summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/00-INDEX2
-rw-r--r--Documentation/ABI/stable/sysfs-firmware-opal-dump41
-rw-r--r--Documentation/ABI/stable/sysfs-firmware-opal-elog60
-rw-r--r--Documentation/ABI/testing/sysfs-bus-event_source-devices-events517
-rw-r--r--Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x723
-rw-r--r--Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_gpci43
-rw-r--r--Documentation/ABI/testing/sysfs-class-scsi_host16
-rw-r--r--Documentation/ABI/testing/sysfs-devices-power27
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-ofw28
-rw-r--r--Documentation/ABI/testing/sysfs-power5
-rw-r--r--Documentation/ABI/testing/sysfs-tty3
-rw-r--r--Documentation/DocBook/Makefile2
-rw-r--r--Documentation/DocBook/w1.tmpl101
-rw-r--r--Documentation/DocBook/writing-an-alsa-driver.tmpl72
-rw-r--r--Documentation/PCI/MSI-HOWTO.txt119
-rw-r--r--Documentation/PCI/pci-iov-howto.txt4
-rw-r--r--Documentation/RCU/RTFP.txt149
-rw-r--r--Documentation/RCU/checklist.txt18
-rw-r--r--Documentation/arm64/memory.txt16
-rw-r--r--Documentation/blockdev/drbd/data-structure-v9.txt38
-rw-r--r--Documentation/connector/cn_test.c2
-rw-r--r--Documentation/cpu-freq/core.txt4
-rw-r--r--Documentation/cpu-freq/cpu-drivers.txt8
-rw-r--r--Documentation/device-mapper/cache.txt11
-rw-r--r--Documentation/device-mapper/thin-provisioning.txt34
-rw-r--r--Documentation/devices.txt2
-rw-r--r--Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt8
-rw-r--r--Documentation/devicetree/bindings/arm/atmel-adc.txt5
-rw-r--r--Documentation/devicetree/bindings/arm/marvell,dove.txt22
-rw-r--r--Documentation/devicetree/bindings/arm/omap/omap.txt2
-rw-r--r--Documentation/devicetree/bindings/ata/ahci-platform.txt22
-rw-r--r--Documentation/devicetree/bindings/ata/apm-xgene.txt76
-rw-r--r--Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt4
-rw-r--r--Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt16
-rw-r--r--Documentation/devicetree/bindings/graph.txt129
-rw-r--r--Documentation/devicetree/bindings/i2c/trivial-devices.txt1
-rw-r--r--Documentation/devicetree/bindings/iio/adc/vf610-adc.txt22
-rw-r--r--Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt113
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt4
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt27
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/fsl/ifc.txt (renamed from Documentation/devicetree/bindings/powerpc/fsl/ifc.txt)0
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt210
-rw-r--r--Documentation/devicetree/bindings/mfd/s2mpa01.txt90
-rw-r--r--Documentation/devicetree/bindings/mfd/s2mps11.txt12
-rw-r--r--Documentation/devicetree/bindings/mfd/tps65910.txt2
-rw-r--r--Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt4
-rw-r--r--Documentation/devicetree/bindings/misc/atmel-ssc.txt8
-rw-r--r--Documentation/devicetree/bindings/misc/sram.txt35
-rw-r--r--Documentation/devicetree/bindings/net/micrel-ks8851.txt1
-rw-r--r--Documentation/devicetree/bindings/net/opencores-ethoc.txt22
-rw-r--r--Documentation/devicetree/bindings/net/sti-dwmac.txt58
-rw-r--r--Documentation/devicetree/bindings/phy/apm-xgene-phy.txt79
-rw-r--r--Documentation/devicetree/bindings/phy/samsung-phy.txt54
-rw-r--r--Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt26
-rw-r--r--Documentation/devicetree/bindings/phy/ti-phy.txt86
-rw-r--r--Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt (renamed from Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt)8
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt1
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt82
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt80
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt1
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt1
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt1
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt2
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt7
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt73
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt14
-rw-r--r--Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt1
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/l2cache.txt23
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt27
-rw-r--r--Documentation/devicetree/bindings/regulator/gpio-regulator.txt4
-rw-r--r--Documentation/devicetree/bindings/regulator/pfuze100.txt96
-rw-r--r--Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt13
-rw-r--r--Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt6
-rw-r--r--Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt133
-rw-r--r--Documentation/devicetree/bindings/serial/efm32-uart.txt4
-rw-r--r--Documentation/devicetree/bindings/serial/fsl-lpuart.txt21
-rw-r--r--Documentation/devicetree/bindings/serial/maxim,max310x.txt36
-rw-r--r--Documentation/devicetree/bindings/serial/renesas,sci-serial.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/armada-370db-audio.txt27
-rw-r--r--Documentation/devicetree/bindings/sound/cs42xx8.txt28
-rw-r--r--Documentation/devicetree/bindings/sound/da9055.txt22
-rw-r--r--Documentation/devicetree/bindings/sound/davinci-evm-audio.txt9
-rw-r--r--Documentation/devicetree/bindings/sound/eukrea-tlv320.txt21
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,esai.txt5
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,spdif.txt5
-rw-r--r--Documentation/devicetree/bindings/sound/mvebu-audio.txt1
-rw-r--r--Documentation/devicetree/bindings/sound/pcm512x.txt30
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rsnd.txt105
-rw-r--r--Documentation/devicetree/bindings/sound/simple-card.txt65
-rw-r--r--Documentation/devicetree/bindings/sound/sirf-audio-codec.txt17
-rw-r--r--Documentation/devicetree/bindings/sound/sirf-audio-port.txt20
-rw-r--r--Documentation/devicetree/bindings/sound/sirf-audio.txt41
-rw-r--r--Documentation/devicetree/bindings/sound/tdm-slot.txt20
-rw-r--r--Documentation/devicetree/bindings/sound/tlv320aic31xx.txt61
-rw-r--r--Documentation/devicetree/bindings/sound/tlv320aic32x4.txt30
-rw-r--r--Documentation/devicetree/bindings/sound/tlv320aic3x.txt1
-rw-r--r--Documentation/devicetree/bindings/sound/widgets.txt20
-rw-r--r--Documentation/devicetree/bindings/spi/efm32-spi.txt8
-rw-r--r--Documentation/devicetree/bindings/spi/qcom,spi-qup.txt85
-rw-r--r--Documentation/devicetree/bindings/spi/sh-hspi.txt28
-rw-r--r--Documentation/devicetree/bindings/spi/sh-msiof.txt42
-rw-r--r--Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt2
-rw-r--r--Documentation/devicetree/bindings/spi/spi-rspi.txt61
-rw-r--r--Documentation/devicetree/bindings/spi/spi-sun4i.txt24
-rw-r--r--Documentation/devicetree/bindings/spi/spi-sun6i.txt24
-rw-r--r--Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt9
-rw-r--r--Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt61
-rw-r--r--Documentation/devicetree/bindings/spmi/spmi.txt41
-rw-r--r--Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt48
-rw-r--r--Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt58
-rw-r--r--Documentation/devicetree/bindings/staging/imx-drm/ldb.txt20
-rw-r--r--Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt4
-rw-r--r--Documentation/devicetree/bindings/timer/ti,keystone-timer.txt29
-rw-r--r--Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt2
-rw-r--r--Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt17
-rw-r--r--Documentation/devicetree/bindings/usb/dwc3.txt6
-rw-r--r--Documentation/devicetree/bindings/usb/fsl-usb.txt4
-rw-r--r--Documentation/devicetree/bindings/usb/mxs-phy.txt8
-rw-r--r--Documentation/devicetree/bindings/usb/omap-usb.txt24
-rw-r--r--Documentation/devicetree/bindings/usb/usb-ehci.txt27
-rw-r--r--Documentation/devicetree/bindings/usb/usb-ohci.txt25
-rw-r--r--Documentation/devicetree/bindings/usb/usb-phy.txt48
-rw-r--r--Documentation/devicetree/bindings/usb/usb-uhci.txt (renamed from Documentation/devicetree/bindings/usb/platform-uhci.txt)4
-rw-r--r--Documentation/devicetree/bindings/usb/usb-xhci.txt4
-rw-r--r--Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt15
-rw-r--r--Documentation/devicetree/bindings/usb/vt8500-ehci.txt12
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt17
-rw-r--r--Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt23
-rw-r--r--Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt6
-rw-r--r--Documentation/fmc/fmc-write-eeprom.txt77
-rw-r--r--Documentation/hwmon/adc128d81847
-rw-r--r--Documentation/hwmon/lm952458
-rw-r--r--Documentation/hwmon/ltc294584
-rw-r--r--Documentation/hwmon/ltc297817
-rw-r--r--Documentation/hwmon/ltc426056
-rw-r--r--Documentation/kernel-parameters.txt51
-rw-r--r--Documentation/kernel-per-CPU-kthreads.txt13
-rw-r--r--Documentation/memory-barriers.txt137
-rw-r--r--Documentation/networking/3c505.txt45
-rw-r--r--Documentation/networking/can.txt6
-rw-r--r--Documentation/networking/netlink_mmap.txt4
-rw-r--r--Documentation/networking/packet_mmap.txt2
-rw-r--r--Documentation/networking/timestamping.txt52
-rw-r--r--Documentation/phy/samsung-usb2.txt135
-rw-r--r--Documentation/power/pm_qos_interface.txt82
-rw-r--r--Documentation/power/runtime_pm.txt29
-rw-r--r--Documentation/scsi/ChangeLog.megaraid_sas13
-rw-r--r--Documentation/sgi-visws.txt13
-rw-r--r--Documentation/sound/oss/vwsnd293
-rw-r--r--Documentation/spi/spidev6
-rw-r--r--Documentation/spi/spidev_fdx.c8
-rw-r--r--Documentation/spi/spidev_test.c45
-rw-r--r--Documentation/sysctl/kernel.txt15
-rw-r--r--Documentation/trace/events-power.txt2
-rw-r--r--Documentation/virtual/kvm/api.txt47
-rw-r--r--Documentation/virtual/kvm/devices/s390_flic.txt91
-rw-r--r--Documentation/w1/masters/ds24902
-rw-r--r--Documentation/w1/w1.netlink8
-rw-r--r--Documentation/watchdog/watchdog-parameters.txt7
-rw-r--r--Documentation/x86/boot.txt4
-rw-r--r--MAINTAINERS259
-rw-r--r--Makefile17
-rw-r--r--arch/alpha/include/asm/Kbuild8
-rw-r--r--arch/alpha/include/asm/cputime.h6
-rw-r--r--arch/alpha/kernel/pci.c6
-rw-r--r--arch/arc/include/asm/Kbuild7
-rw-r--r--arch/arc/mm/cache_arc700.c4
-rw-r--r--arch/arm/Kconfig7
-rw-r--r--arch/arm/Makefile7
-rw-r--r--arch/arm/boot/compressed/.gitignore1
-rw-r--r--arch/arm/boot/dts/Makefile7
-rw-r--r--arch/arm/boot/dts/am335x-evmsk.dts11
-rw-r--r--arch/arm/boot/dts/armada-xp-mv78260.dtsi3
-rw-r--r--arch/arm/boot/dts/atlas6.dtsi17
-rw-r--r--arch/arm/boot/dts/bcm11351.dtsi2
-rw-r--r--arch/arm/boot/dts/dove.dtsi11
-rw-r--r--arch/arm/boot/dts/imx51-apf51dev.dts11
-rw-r--r--arch/arm/boot/dts/imx51-babbage.dts26
-rw-r--r--arch/arm/boot/dts/imx51.dtsi22
-rw-r--r--arch/arm/boot/dts/imx53-m53evk.dts13
-rw-r--r--arch/arm/boot/dts/imx53-mba53.dts13
-rw-r--r--arch/arm/boot/dts/imx53-qsb.dts13
-rw-r--r--arch/arm/boot/dts/imx53.dtsi64
-rw-r--r--arch/arm/boot/dts/imx6dl-hummingboard.dts10
-rw-r--r--arch/arm/boot/dts/imx6dl.dtsi17
-rw-r--r--arch/arm/boot/dts/imx6q.dtsi123
-rw-r--r--arch/arm/boot/dts/imx6qdl-cubox-i.dtsi10
-rw-r--r--arch/arm/boot/dts/imx6qdl.dtsi137
-rw-r--r--arch/arm/boot/dts/keystone-clocks.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-gta04.dts8
-rw-r--r--arch/arm/boot/dts/omap3-igep0020.dts2
-rw-r--r--arch/arm/boot/dts/omap3-igep0030.dts2
-rw-r--r--arch/arm/boot/dts/omap3-n9.dts2
-rw-r--r--arch/arm/boot/dts/omap3-n900.dts4
-rw-r--r--arch/arm/boot/dts/omap3-n950.dts2
-rw-r--r--arch/arm/boot/dts/omap3-overo-storm-tobi.dts22
-rw-r--r--arch/arm/boot/dts/omap3-overo-tobi-common.dtsi (renamed from arch/arm/boot/dts/omap3-tobi.dts)3
-rw-r--r--arch/arm/boot/dts/omap3-overo-tobi.dts22
-rw-r--r--arch/arm/boot/dts/omap3-overo.dtsi3
-rw-r--r--arch/arm/boot/dts/prima2.dtsi20
-rw-r--r--arch/arm/boot/dts/r8a7791.dtsi2
-rw-r--r--arch/arm/boot/dts/sama5d36.dtsi2
-rw-r--r--arch/arm/boot/dts/sun4i-a10.dtsi8
-rw-r--r--arch/arm/boot/dts/sun5i-a10s.dtsi8
-rw-r--r--arch/arm/boot/dts/sun5i-a13.dtsi8
-rw-r--r--arch/arm/boot/dts/sun6i-a31.dtsi10
-rw-r--r--arch/arm/boot/dts/sun7i-a20.dtsi22
-rw-r--r--arch/arm/boot/dts/tegra114.dtsi4
-rw-r--r--arch/arm/boot/dts/tegra20.dtsi4
-rw-r--r--arch/arm/boot/dts/tegra30-cardhu.dtsi2
-rw-r--r--arch/arm/boot/dts/tegra30.dtsi4
-rw-r--r--arch/arm/boot/dts/testcases/tests.dtsi2
-rw-r--r--arch/arm/boot/dts/versatile-pb.dts4
-rw-r--r--arch/arm/boot/dts/zynq-7000.dtsi6
-rw-r--r--arch/arm/configs/tegra_defconfig3
-rw-r--r--arch/arm/include/asm/Kbuild5
-rw-r--r--arch/arm/include/asm/cacheflush.h1
-rw-r--r--arch/arm/include/asm/dma-iommu.h12
-rw-r--r--arch/arm/include/asm/kvm_arm.h4
-rw-r--r--arch/arm/include/asm/kvm_asm.h4
-rw-r--r--arch/arm/include/asm/kvm_host.h9
-rw-r--r--arch/arm/include/asm/kvm_mmu.h30
-rw-r--r--arch/arm/include/asm/memory.h9
-rw-r--r--arch/arm/include/asm/pgtable-3level.h15
-rw-r--r--arch/arm/include/asm/spinlock.h15
-rw-r--r--arch/arm/include/asm/topology.h3
-rw-r--r--arch/arm/kernel/asm-offsets.c1
-rw-r--r--arch/arm/kernel/bios32.c9
-rw-r--r--arch/arm/kernel/head-common.S12
-rw-r--r--arch/arm/kernel/head.S2
-rw-r--r--arch/arm/kernel/process.c16
-rw-r--r--arch/arm/kernel/setup.c2
-rw-r--r--arch/arm/kernel/smp.c3
-rw-r--r--arch/arm/kernel/smp_twd.c2
-rw-r--r--arch/arm/kvm/arm.c3
-rw-r--r--arch/arm/kvm/coproc.c84
-rw-r--r--arch/arm/kvm/coproc.h14
-rw-r--r--arch/arm/kvm/coproc_a15.c2
-rw-r--r--arch/arm/kvm/coproc_a7.c2
-rw-r--r--arch/arm/kvm/guest.c1
-rw-r--r--arch/arm/kvm/interrupts.S11
-rw-r--r--arch/arm/kvm/interrupts_head.S21
-rw-r--r--arch/arm/kvm/mmu.c110
-rw-r--r--arch/arm/mach-davinci/da850.c2
-rw-r--r--arch/arm/mach-davinci/devices-da8xx.c99
-rw-r--r--arch/arm/mach-exynos/Kconfig1
-rw-r--r--arch/arm/mach-imx/Makefile2
-rw-r--r--arch/arm/mach-imx/common.h4
-rw-r--r--arch/arm/mach-imx/mach-mx31moboard.c21
-rw-r--r--arch/arm/mach-imx/pm-imx6q.c7
-rw-r--r--arch/arm/mach-mmp/pm-mmp2.c16
-rw-r--r--arch/arm/mach-mmp/pm-pxa910.c20
-rw-r--r--arch/arm/mach-mvebu/Kconfig1
-rw-r--r--arch/arm/mach-omap1/ams-delta-fiq.c7
-rw-r--r--arch/arm/mach-omap1/board-nokia770.c1
-rw-r--r--arch/arm/mach-omap2/Kconfig11
-rw-r--r--arch/arm/mach-omap2/cclock3xxx_data.c2
-rw-r--r--arch/arm/mach-omap2/cpuidle44xx.c8
-rw-r--r--arch/arm/mach-omap2/dpll3xxx.c92
-rw-r--r--arch/arm/mach-omap2/gpmc.c4
-rw-r--r--arch/arm/mach-omap2/io.c9
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c20
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_7xx_data.c9
-rw-r--r--arch/arm/mach-omap2/pdata-quirks.c21
-rw-r--r--arch/arm/mach-omap2/prminst44xx.c4
-rw-r--r--arch/arm/mach-pxa/mioa701.c9
-rw-r--r--arch/arm/mach-pxa/viper.c3
-rw-r--r--arch/arm/mach-sa1100/include/mach/collie.h2
-rw-r--r--arch/arm/mach-shmobile/Kconfig40
-rw-r--r--arch/arm/mach-shmobile/board-armadillo800eva.c4
-rw-r--r--arch/arm/mach-shmobile/board-bockw.c16
-rw-r--r--arch/arm/mach-shmobile/board-kzm9g.c4
-rw-r--r--arch/arm/mach-shmobile/board-mackerel.c6
-rw-r--r--arch/arm/mach-spear/spear1310.c1
-rw-r--r--arch/arm/mach-spear/spear1340.c1
-rw-r--r--arch/arm/mach-tegra/Kconfig1
-rw-r--r--arch/arm/mach-tegra/pm.c1
-rw-r--r--arch/arm/mach-tegra/tegra.c10
-rw-r--r--arch/arm/mach-u300/Makefile2
-rw-r--r--arch/arm/mach-zynq/Kconfig4
-rw-r--r--arch/arm/mach-zynq/common.c3
-rw-r--r--arch/arm/mm/dma-mapping.c146
-rw-r--r--arch/arm/mm/dump.c3
-rw-r--r--arch/arm/mm/init.c2
-rw-r--r--arch/arm/mm/mm.h1
-rw-r--r--arch/arm/mm/mmu.c7
-rw-r--r--arch/arm/mm/proc-v6.S3
-rw-r--r--arch/arm/mm/proc-v7.S2
-rw-r--r--arch/arm64/Kconfig29
-rw-r--r--arch/arm64/boot/dts/apm-storm.dtsi152
-rw-r--r--arch/arm64/include/asm/Kbuild8
-rw-r--r--arch/arm64/include/asm/barrier.h1
-rw-r--r--arch/arm64/include/asm/cacheflush.h7
-rw-r--r--arch/arm64/include/asm/compat.h2
-rw-r--r--arch/arm64/include/asm/cpufeature.h29
-rw-r--r--arch/arm64/include/asm/debug-monitors.h64
-rw-r--r--arch/arm64/include/asm/dma-mapping.h7
-rw-r--r--arch/arm64/include/asm/hwcap.h9
-rw-r--r--arch/arm64/include/asm/io.h2
-rw-r--r--arch/arm64/include/asm/irqflags.h23
-rw-r--r--arch/arm64/include/asm/kgdb.h84
-rw-r--r--arch/arm64/include/asm/kvm_arm.h18
-rw-r--r--arch/arm64/include/asm/kvm_asm.h3
-rw-r--r--arch/arm64/include/asm/kvm_mmu.h22
-rw-r--r--arch/arm64/include/asm/percpu.h8
-rw-r--r--arch/arm64/include/asm/pgtable-hwdef.h5
-rw-r--r--arch/arm64/include/asm/pgtable.h70
-rw-r--r--arch/arm64/include/asm/psci.h2
-rw-r--r--arch/arm64/include/asm/ptrace.h5
-rw-r--r--arch/arm64/include/asm/tlb.h136
-rw-r--r--arch/arm64/include/asm/topology.h39
-rw-r--r--arch/arm64/include/asm/uaccess.h4
-rw-r--r--arch/arm64/include/asm/unistd.h1
-rw-r--r--arch/arm64/include/uapi/asm/Kbuild1
-rw-r--r--arch/arm64/include/uapi/asm/perf_regs.h40
-rw-r--r--arch/arm64/kernel/Makefile6
-rw-r--r--arch/arm64/kernel/debug-monitors.c10
-rw-r--r--arch/arm64/kernel/head.S20
-rw-r--r--arch/arm64/kernel/kgdb.c336
-rw-r--r--arch/arm64/kernel/perf_event.c75
-rw-r--r--arch/arm64/kernel/perf_regs.c44
-rw-r--r--arch/arm64/kernel/process.c18
-rw-r--r--arch/arm64/kernel/psci.c13
-rw-r--r--arch/arm64/kernel/setup.c33
-rw-r--r--arch/arm64/kernel/smp.c12
-rw-r--r--arch/arm64/kernel/smp_spin_table.c2
-rw-r--r--arch/arm64/kernel/stacktrace.c6
-rw-r--r--arch/arm64/kernel/topology.c95
-rw-r--r--arch/arm64/kernel/vdso.c42
-rw-r--r--arch/arm64/kvm/hyp-init.S6
-rw-r--r--arch/arm64/kvm/hyp.S27
-rw-r--r--arch/arm64/kvm/sys_regs.c99
-rw-r--r--arch/arm64/kvm/sys_regs.h2
-rw-r--r--arch/arm64/mm/cache.S80
-rw-r--r--arch/arm64/mm/dma-mapping.c246
-rw-r--r--arch/arm64/mm/init.c34
-rw-r--r--arch/arm64/mm/proc.S14
-rw-r--r--arch/avr32/Makefile2
-rw-r--r--arch/avr32/boards/mimc200/Makefile2
-rw-r--r--arch/avr32/boards/mimc200/fram.c81
-rw-r--r--arch/avr32/include/asm/Kbuild42
-rw-r--r--arch/avr32/include/asm/bugs.h2
-rw-r--r--arch/avr32/include/asm/io.h2
-rw-r--r--arch/avr32/include/asm/processor.h7
-rw-r--r--arch/avr32/kernel/cpu.c48
-rw-r--r--arch/avr32/mm/cache.c1
-rw-r--r--arch/blackfin/include/asm/Kbuild7
-rw-r--r--arch/blackfin/include/asm/irq.h9
-rw-r--r--arch/c6x/include/asm/Kbuild5
-rw-r--r--arch/c6x/include/asm/cache.h1
-rw-r--r--arch/cris/include/asm/Kbuild4
-rw-r--r--arch/cris/include/asm/bitops.h2
-rw-r--r--arch/cris/include/asm/cputime.h6
-rw-r--r--arch/frv/include/asm/Kbuild6
-rw-r--r--arch/frv/include/asm/cputime.h6
-rw-r--r--arch/frv/mb93090-mb00/pci-frv.c2
-rw-r--r--arch/hexagon/include/asm/Kbuild7
-rw-r--r--arch/ia64/configs/generic_defconfig5
-rw-r--r--arch/ia64/configs/tiger_defconfig1
-rw-r--r--arch/ia64/configs/zx1_defconfig1
-rw-r--r--arch/ia64/hp/common/sba_iommu.c38
-rw-r--r--arch/ia64/include/asm/Kbuild5
-rw-r--r--arch/ia64/include/asm/pci.h2
-rw-r--r--arch/ia64/include/asm/topology.h1
-rw-r--r--arch/ia64/kernel/acpi.c32
-rw-r--r--arch/ia64/kernel/efi.c7
-rw-r--r--arch/ia64/kernel/irq_ia64.c14
-rw-r--r--arch/ia64/kernel/mca.c10
-rw-r--r--arch/ia64/kernel/msi_ia64.c10
-rw-r--r--arch/ia64/kernel/perfmon.c1
-rw-r--r--arch/ia64/kernel/time.c2
-rw-r--r--arch/ia64/kernel/uncached.c2
-rw-r--r--arch/ia64/kvm/kvm-ia64.c1
-rw-r--r--arch/ia64/pci/fixup.c25
-rw-r--r--arch/ia64/pci/pci.c10
-rw-r--r--arch/ia64/sn/kernel/irq.c4
-rw-r--r--arch/ia64/sn/kernel/msi_sn.c2
-rw-r--r--arch/m32r/include/asm/Kbuild6
-rw-r--r--arch/m32r/include/asm/cputime.h6
-rw-r--r--arch/m68k/Kconfig1
-rw-r--r--arch/m68k/amiga/cia.c1
-rw-r--r--arch/m68k/atari/ataints.c1
-rw-r--r--arch/m68k/configs/amiga_defconfig10
-rw-r--r--arch/m68k/configs/apollo_defconfig10
-rw-r--r--arch/m68k/configs/atari_defconfig10
-rw-r--r--arch/m68k/configs/bvme6000_defconfig10
-rw-r--r--arch/m68k/configs/hp300_defconfig10
-rw-r--r--arch/m68k/configs/mac_defconfig10
-rw-r--r--arch/m68k/configs/multi_defconfig10
-rw-r--r--arch/m68k/configs/mvme147_defconfig10
-rw-r--r--arch/m68k/configs/mvme16x_defconfig10
-rw-r--r--arch/m68k/configs/q40_defconfig10
-rw-r--r--arch/m68k/configs/sun3_defconfig10
-rw-r--r--arch/m68k/configs/sun3x_defconfig10
-rw-r--r--arch/m68k/include/asm/Kbuild9
-rw-r--r--arch/m68k/include/asm/barrier.h8
-rw-r--r--arch/m68k/include/asm/unistd.h2
-rw-r--r--arch/m68k/include/uapi/asm/unistd.h2
-rw-r--r--arch/m68k/kernel/head.S70
-rw-r--r--arch/m68k/kernel/ints.c2
-rw-r--r--arch/m68k/kernel/syscalltable.S2
-rw-r--r--arch/metag/Kconfig2
-rw-r--r--arch/metag/include/asm/Kbuild5
-rw-r--r--arch/metag/include/asm/topology.h27
-rw-r--r--arch/metag/kernel/irq.c22
-rw-r--r--arch/metag/kernel/signal.c48
-rw-r--r--arch/microblaze/include/asm/Kbuild6
-rw-r--r--arch/microblaze/include/asm/cputime.h1
-rw-r--r--arch/microblaze/pci/pci-common.c5
-rw-r--r--arch/mips/Kconfig166
-rw-r--r--arch/mips/Kconfig.debug10
-rw-r--r--arch/mips/Makefile5
-rw-r--r--arch/mips/alchemy/Kconfig24
-rw-r--r--arch/mips/alchemy/Platform16
-rw-r--r--arch/mips/alchemy/board-gpr.c4
-rw-r--r--arch/mips/alchemy/board-mtx1.c4
-rw-r--r--arch/mips/alchemy/common/setup.c10
-rw-r--r--arch/mips/alchemy/common/sleeper.S6
-rw-r--r--arch/mips/alchemy/devboards/Makefile4
-rw-r--r--arch/mips/alchemy/devboards/db1000.c47
-rw-r--r--arch/mips/alchemy/devboards/db1200.c78
-rw-r--r--arch/mips/alchemy/devboards/db1300.c40
-rw-r--r--arch/mips/alchemy/devboards/db1550.c10
-rw-r--r--arch/mips/alchemy/devboards/db1xxx.c (renamed from arch/mips/alchemy/devboards/db1235.c)41
-rw-r--r--arch/mips/ar7/time.c1
-rw-r--r--arch/mips/ath79/Kconfig8
-rw-r--r--arch/mips/bcm47xx/Makefile2
-rw-r--r--arch/mips/bcm47xx/bcm47xx_private.h3
-rw-r--r--arch/mips/bcm47xx/board.c26
-rw-r--r--arch/mips/bcm47xx/buttons.c31
-rw-r--r--arch/mips/bcm47xx/leds.c49
-rw-r--r--arch/mips/bcm47xx/nvram.c2
-rw-r--r--arch/mips/bcm47xx/setup.c3
-rw-r--r--arch/mips/bcm47xx/workarounds.c31
-rw-r--r--arch/mips/bcm63xx/cpu.c3
-rw-r--r--arch/mips/cavium-octeon/octeon-irq.c22
-rw-r--r--arch/mips/configs/db1000_defconfig359
-rw-r--r--arch/mips/configs/db1235_defconfig434
-rw-r--r--arch/mips/configs/db1xxx_defconfig245
-rw-r--r--arch/mips/configs/loongson3_defconfig362
-rw-r--r--arch/mips/configs/malta_defconfig9
-rw-r--r--arch/mips/configs/malta_kvm_defconfig10
-rw-r--r--arch/mips/configs/malta_kvm_guest_defconfig7
-rw-r--r--arch/mips/configs/maltaaprp_defconfig3
-rw-r--r--arch/mips/configs/maltasmtc_defconfig4
-rw-r--r--arch/mips/configs/maltasmvp_defconfig5
-rw-r--r--arch/mips/configs/maltasmvp_eva_defconfig200
-rw-r--r--arch/mips/configs/maltaup_defconfig3
-rw-r--r--arch/mips/include/asm/Kbuild5
-rw-r--r--arch/mips/include/asm/asm-eva.h135
-rw-r--r--arch/mips/include/asm/asm.h13
-rw-r--r--arch/mips/include/asm/asmmacro-32.h128
-rw-r--r--arch/mips/include/asm/asmmacro.h345
-rw-r--r--arch/mips/include/asm/atomic.h40
-rw-r--r--arch/mips/include/asm/bitops.h28
-rw-r--r--arch/mips/include/asm/bootinfo.h26
-rw-r--r--arch/mips/include/asm/checksum.h44
-rw-r--r--arch/mips/include/asm/cmpxchg.h20
-rw-r--r--arch/mips/include/asm/cpu-features.h10
-rw-r--r--arch/mips/include/asm/cpu-info.h28
-rw-r--r--arch/mips/include/asm/cpu-type.h6
-rw-r--r--arch/mips/include/asm/cpu.h15
-rw-r--r--arch/mips/include/asm/dma-mapping.h5
-rw-r--r--arch/mips/include/asm/fpu.h4
-rw-r--r--arch/mips/include/asm/ftrace.h20
-rw-r--r--arch/mips/include/asm/futex.h25
-rw-r--r--arch/mips/include/asm/fw/fw.h2
-rw-r--r--arch/mips/include/asm/gcmpregs.h125
-rw-r--r--arch/mips/include/asm/gic.h3
-rw-r--r--arch/mips/include/asm/io.h8
-rw-r--r--arch/mips/include/asm/kvm_host.h417
-rw-r--r--arch/mips/include/asm/local.h8
-rw-r--r--arch/mips/include/asm/mach-au1x00/au1000.h12
-rw-r--r--arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h8
-rw-r--r--arch/mips/include/asm/mach-db1x00/db1200.h91
-rw-r--r--arch/mips/include/asm/mach-db1x00/db1300.h40
-rw-r--r--arch/mips/include/asm/mach-loongson/boot_param.h163
-rw-r--r--arch/mips/include/asm/mach-loongson/dma-coherence.h22
-rw-r--r--arch/mips/include/asm/mach-loongson/irq.h44
-rw-r--r--arch/mips/include/asm/mach-loongson/loongson.h28
-rw-r--r--arch/mips/include/asm/mach-loongson/machine.h6
-rw-r--r--arch/mips/include/asm/mach-loongson/pci.h5
-rw-r--r--arch/mips/include/asm/mach-loongson/spaces.h9
-rw-r--r--arch/mips/include/asm/mach-malta/kernel-entry-init.h115
-rw-r--r--arch/mips/include/asm/mach-malta/spaces.h46
-rw-r--r--arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h12
-rw-r--r--arch/mips/include/asm/mips-boards/malta.h5
-rw-r--r--arch/mips/include/asm/mips-boards/piix4.h5
-rw-r--r--arch/mips/include/asm/mips-cm.h322
-rw-r--r--arch/mips/include/asm/mips-cpc.h150
-rw-r--r--arch/mips/include/asm/mips_mt.h5
-rw-r--r--arch/mips/include/asm/mipsmtregs.h11
-rw-r--r--arch/mips/include/asm/mipsregs.h22
-rw-r--r--arch/mips/include/asm/module.h2
-rw-r--r--arch/mips/include/asm/msa.h203
-rw-r--r--arch/mips/include/asm/page.h2
-rw-r--r--arch/mips/include/asm/pgtable-bits.h9
-rw-r--r--arch/mips/include/asm/processor.h45
-rw-r--r--arch/mips/include/asm/ptrace.h2
-rw-r--r--arch/mips/include/asm/r4kcache.h175
-rw-r--r--arch/mips/include/asm/sigcontext.h2
-rw-r--r--arch/mips/include/asm/smp-cps.h33
-rw-r--r--arch/mips/include/asm/smp-ops.h17
-rw-r--r--arch/mips/include/asm/smp.h1
-rw-r--r--arch/mips/include/asm/stackframe.h2
-rw-r--r--arch/mips/include/asm/switch_to.h22
-rw-r--r--arch/mips/include/asm/syscall.h42
-rw-r--r--arch/mips/include/asm/thread_info.h7
-rw-r--r--arch/mips/include/asm/topology.h4
-rw-r--r--arch/mips/include/asm/uaccess.h559
-rw-r--r--arch/mips/include/asm/unistd.h1
-rw-r--r--arch/mips/include/uapi/asm/inst.h29
-rw-r--r--arch/mips/include/uapi/asm/sigcontext.h8
-rw-r--r--arch/mips/kernel/Makefile5
-rw-r--r--arch/mips/kernel/asm-offsets.c82
-rw-r--r--arch/mips/kernel/bmips_vec.S2
-rw-r--r--arch/mips/kernel/cps-vec.S191
-rw-r--r--arch/mips/kernel/cpu-probe.c74
-rw-r--r--arch/mips/kernel/ftrace.c9
-rw-r--r--arch/mips/kernel/genex.S8
-rw-r--r--arch/mips/kernel/head.S2
-rw-r--r--arch/mips/kernel/idle.c9
-rw-r--r--arch/mips/kernel/irq-gic.c1
-rw-r--r--arch/mips/kernel/kgdb.c18
-rw-r--r--arch/mips/kernel/mips-cm.c121
-rw-r--r--arch/mips/kernel/mips-cpc.c52
-rw-r--r--arch/mips/kernel/mips_ksyms.c24
-rw-r--r--arch/mips/kernel/perf_event_mipsxx.c80
-rw-r--r--arch/mips/kernel/proc.c25
-rw-r--r--arch/mips/kernel/process.c23
-rw-r--r--arch/mips/kernel/ptrace.c161
-rw-r--r--arch/mips/kernel/ptrace32.c67
-rw-r--r--arch/mips/kernel/r4k_fpu.S231
-rw-r--r--arch/mips/kernel/r4k_switch.S60
-rw-r--r--arch/mips/kernel/rtlx-cmp.c3
-rw-r--r--arch/mips/kernel/rtlx-mt.c3
-rw-r--r--arch/mips/kernel/scall32-o32.S24
-rw-r--r--arch/mips/kernel/scall64-64.S5
-rw-r--r--arch/mips/kernel/scall64-n32.S5
-rw-r--r--arch/mips/kernel/scall64-o32.S17
-rw-r--r--arch/mips/kernel/signal.c170
-rw-r--r--arch/mips/kernel/signal32.c137
-rw-r--r--arch/mips/kernel/smp-cmp.c55
-rw-r--r--arch/mips/kernel/smp-cps.c335
-rw-r--r--arch/mips/kernel/smp-gic.c53
-rw-r--r--arch/mips/kernel/smp-mt.c45
-rw-r--r--arch/mips/kernel/smtc-proc.c23
-rw-r--r--arch/mips/kernel/smtc.c2
-rw-r--r--arch/mips/kernel/spram.c5
-rw-r--r--arch/mips/kernel/syscall.c4
-rw-r--r--arch/mips/kernel/traps.c144
-rw-r--r--arch/mips/kernel/unaligned.c135
-rw-r--r--arch/mips/kvm/kvm_mips_emul.c40
-rw-r--r--arch/mips/lasat/picvue_proc.c2
-rw-r--r--arch/mips/lib/csum_partial.S282
-rw-r--r--arch/mips/lib/memcpy.S416
-rw-r--r--arch/mips/lib/memset.S146
-rw-r--r--arch/mips/lib/strlen_user.S36
-rw-r--r--arch/mips/lib/strncpy_user.S40
-rw-r--r--arch/mips/lib/strnlen_user.S36
-rw-r--r--arch/mips/loongson/Kconfig47
-rw-r--r--arch/mips/loongson/Makefile6
-rw-r--r--arch/mips/loongson/Platform1
-rw-r--r--arch/mips/loongson/common/Makefile5
-rw-r--r--arch/mips/loongson/common/dma-swiotlb.c136
-rw-r--r--arch/mips/loongson/common/env.c67
-rw-r--r--arch/mips/loongson/common/init.c11
-rw-r--r--arch/mips/loongson/common/machtype.c4
-rw-r--r--arch/mips/loongson/common/mem.c42
-rw-r--r--arch/mips/loongson/common/pci.c6
-rw-r--r--arch/mips/loongson/common/reset.c21
-rw-r--r--arch/mips/loongson/common/serial.c26
-rw-r--r--arch/mips/loongson/common/setup.c8
-rw-r--r--arch/mips/loongson/common/uart_base.c9
-rw-r--r--arch/mips/loongson/loongson-3/Makefile6
-rw-r--r--arch/mips/loongson/loongson-3/irq.c126
-rw-r--r--arch/mips/loongson/loongson-3/smp.c443
-rw-r--r--arch/mips/loongson/loongson-3/smp.h29
-rw-r--r--arch/mips/math-emu/cp1emu.c64
-rw-r--r--arch/mips/math-emu/kernel_linkage.c76
-rw-r--r--arch/mips/mm/c-r4k.c147
-rw-r--r--arch/mips/mm/cache.c4
-rw-r--r--arch/mips/mm/init.c12
-rw-r--r--arch/mips/mm/sc-mips.c2
-rw-r--r--arch/mips/mm/tlb-r4k.c5
-rw-r--r--arch/mips/mm/tlbex.c6
-rw-r--r--arch/mips/mti-malta/malta-amon.c2
-rw-r--r--arch/mips/mti-malta/malta-init.c30
-rw-r--r--arch/mips/mti-malta/malta-int.c93
-rw-r--r--arch/mips/mti-malta/malta-memory.c58
-rw-r--r--arch/mips/mti-malta/malta-setup.c30
-rw-r--r--arch/mips/mti-sead3/sead3-mtd.c3
-rw-r--r--arch/mips/oprofile/common.c3
-rw-r--r--arch/mips/oprofile/op_model_mipsxx.c9
-rw-r--r--arch/mips/pci/Makefile1
-rw-r--r--arch/mips/pci/fixup-loongson3.c66
-rw-r--r--arch/mips/pci/fixup-malta.c13
-rw-r--r--arch/mips/pci/msi-octeon.c1
-rw-r--r--arch/mips/pci/ops-loongson3.c101
-rw-r--r--arch/mips/pci/pci-alchemy.c5
-rw-r--r--arch/mips/pci/pci-malta.c22
-rw-r--r--arch/mips/pmcs-msp71xx/msp_setup.c2
-rw-r--r--arch/mips/power/hibernate.S1
-rw-r--r--arch/mips/ralink/Kconfig6
-rw-r--r--arch/mips/sgi-ip22/ip22-int.c2
-rw-r--r--arch/mips/sgi-ip22/ip22-time.c2
-rw-r--r--arch/mips/sibyte/bcm1480/irq.c2
-rw-r--r--arch/mips/sibyte/bcm1480/smp.c2
-rw-r--r--arch/mips/sibyte/sb1250/irq.c2
-rw-r--r--arch/mips/sibyte/sb1250/smp.c2
-rw-r--r--arch/mn10300/include/asm/Kbuild4
-rw-r--r--arch/mn10300/include/asm/cputime.h1
-rw-r--r--arch/mn10300/kernel/cevt-mn10300.c2
-rw-r--r--arch/mn10300/kernel/mn10300-serial.c6
-rw-r--r--arch/mn10300/kernel/mn10300-watchdog.c2
-rw-r--r--arch/mn10300/kernel/smp.c2
-rw-r--r--arch/mn10300/unit-asb2364/irq-fpga.c2
-rw-r--r--arch/openrisc/include/asm/Kbuild11
-rw-r--r--arch/parisc/include/asm/Kbuild32
-rw-r--r--arch/parisc/include/asm/page.h11
-rw-r--r--arch/parisc/include/asm/spinlock.h4
-rw-r--r--arch/parisc/include/uapi/asm/unistd.h4
-rw-r--r--arch/parisc/kernel/cache.c64
-rw-r--r--arch/parisc/kernel/irq.c2
-rw-r--r--arch/parisc/kernel/syscall_table.S1
-rw-r--r--arch/powerpc/Kconfig16
-rw-r--r--arch/powerpc/boot/Makefile5
-rw-r--r--arch/powerpc/boot/dts/fsl/b4420si-post.dtsi36
-rw-r--r--arch/powerpc/boot/dts/fsl/b4420si-pre.dtsi2
-rw-r--r--arch/powerpc/boot/dts/fsl/b4860si-post.dtsi36
-rw-r--r--arch/powerpc/boot/dts/fsl/b4860si-pre.dtsi4
-rw-r--r--arch/powerpc/boot/dts/fsl/p2041si-post.dtsi60
-rw-r--r--arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi4
-rw-r--r--arch/powerpc/boot/dts/fsl/p3041si-post.dtsi61
-rw-r--r--arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi4
-rw-r--r--arch/powerpc/boot/dts/fsl/p4080si-post.dtsi113
-rw-r--r--arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi8
-rw-r--r--arch/powerpc/boot/dts/fsl/p5020si-post.dtsi43
-rw-r--r--arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi2
-rw-r--r--arch/powerpc/boot/dts/fsl/p5040si-post.dtsi61
-rw-r--r--arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi4
-rw-r--r--arch/powerpc/boot/dts/fsl/t4240si-post.dtsi86
-rw-r--r--arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi12
-rw-r--r--arch/powerpc/boot/dts/t4240qds.dts42
-rw-r--r--arch/powerpc/configs/40x/acadia_defconfig1
-rw-r--r--arch/powerpc/configs/40x/ep405_defconfig1
-rw-r--r--arch/powerpc/configs/40x/kilauea_defconfig1
-rw-r--r--arch/powerpc/configs/40x/makalu_defconfig1
-rw-r--r--arch/powerpc/configs/40x/walnut_defconfig1
-rw-r--r--arch/powerpc/configs/44x/arches_defconfig1
-rw-r--r--arch/powerpc/configs/44x/bluestone_defconfig1
-rw-r--r--arch/powerpc/configs/44x/canyonlands_defconfig1
-rw-r--r--arch/powerpc/configs/44x/ebony_defconfig1
-rw-r--r--arch/powerpc/configs/44x/eiger_defconfig1
-rw-r--r--arch/powerpc/configs/44x/icon_defconfig1
-rw-r--r--arch/powerpc/configs/44x/iss476-smp_defconfig1
-rw-r--r--arch/powerpc/configs/44x/katmai_defconfig1
-rw-r--r--arch/powerpc/configs/44x/rainier_defconfig1
-rw-r--r--arch/powerpc/configs/44x/redwood_defconfig1
-rw-r--r--arch/powerpc/configs/44x/sequoia_defconfig1
-rw-r--r--arch/powerpc/configs/44x/taishan_defconfig1
-rw-r--r--arch/powerpc/configs/44x/warp_defconfig1
-rw-r--r--arch/powerpc/configs/52xx/cm5200_defconfig1
-rw-r--r--arch/powerpc/configs/52xx/motionpro_defconfig1
-rw-r--r--arch/powerpc/configs/52xx/pcm030_defconfig1
-rw-r--r--arch/powerpc/configs/52xx/tqm5200_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/asp8347_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc8313_rdb_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc8315_rdb_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc836x_mds_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc836x_rdk_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/sbc834x_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/ksi8560_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/ppa8548_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/socrates_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/tqm8540_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/tqm8541_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/tqm8548_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/tqm8555_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/tqm8560_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/xes_mpc85xx_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/gef_ppc9a_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/gef_sbc310_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/gef_sbc610_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/sbc8641d_defconfig1
-rw-r--r--arch/powerpc/configs/c2k_defconfig1
-rw-r--r--arch/powerpc/configs/corenet64_smp_defconfig2
-rw-r--r--arch/powerpc/configs/linkstation_defconfig1
-rw-r--r--arch/powerpc/configs/mpc85xx_defconfig2
-rw-r--r--arch/powerpc/configs/mpc85xx_smp_defconfig2
-rw-r--r--arch/powerpc/configs/ppc40x_defconfig1
-rw-r--r--arch/powerpc/configs/ppc44x_defconfig1
-rw-r--r--arch/powerpc/configs/ppc64_defconfig70
-rw-r--r--arch/powerpc/configs/ppc64e_defconfig70
-rw-r--r--arch/powerpc/configs/prpmc2800_defconfig108
-rw-r--r--arch/powerpc/configs/pseries_defconfig55
-rw-r--r--arch/powerpc/configs/pseries_le_defconfig53
-rw-r--r--arch/powerpc/configs/storcenter_defconfig1
-rw-r--r--arch/powerpc/configs/tqm8xx_defconfig1
-rw-r--r--arch/powerpc/include/asm/Kbuild5
-rw-r--r--arch/powerpc/include/asm/compat.h9
-rw-r--r--arch/powerpc/include/asm/cputable.h6
-rw-r--r--arch/powerpc/include/asm/eeh.h21
-rw-r--r--arch/powerpc/include/asm/exception-64e.h15
-rw-r--r--arch/powerpc/include/asm/exception-64s.h8
-rw-r--r--arch/powerpc/include/asm/hugetlb.h2
-rw-r--r--arch/powerpc/include/asm/hvcall.h5
-rw-r--r--arch/powerpc/include/asm/kvm_book3s.h5
-rw-r--r--arch/powerpc/include/asm/kvm_book3s_64.h12
-rw-r--r--arch/powerpc/include/asm/kvm_book3s_asm.h2
-rw-r--r--arch/powerpc/include/asm/kvm_booke_hv_asm.h17
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h2
-rw-r--r--arch/powerpc/include/asm/machdep.h7
-rw-r--r--arch/powerpc/include/asm/mce.h3
-rw-r--r--arch/powerpc/include/asm/mmu-book3e.h9
-rw-r--r--arch/powerpc/include/asm/opal.h66
-rw-r--r--arch/powerpc/include/asm/paca.h9
-rw-r--r--arch/powerpc/include/asm/perf_event_server.h1
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc64.h26
-rw-r--r--arch/powerpc/include/asm/pgtable.h22
-rw-r--r--arch/powerpc/include/asm/processor.h1
-rw-r--r--arch/powerpc/include/asm/ptrace.h16
-rw-r--r--arch/powerpc/include/asm/reg.h19
-rw-r--r--arch/powerpc/include/asm/rtas.h1
-rw-r--r--arch/powerpc/include/asm/smp.h2
-rw-r--r--arch/powerpc/include/asm/time.h1
-rw-r--r--arch/powerpc/include/asm/tm.h4
-rw-r--r--arch/powerpc/include/asm/topology.h1
-rw-r--r--arch/powerpc/include/asm/vdso.h6
-rw-r--r--arch/powerpc/kernel/asm-offsets.c2
-rw-r--r--arch/powerpc/kernel/cacheinfo.c7
-rw-r--r--arch/powerpc/kernel/cputable.c2
-rw-r--r--arch/powerpc/kernel/crash_dump.c8
-rw-r--r--arch/powerpc/kernel/eeh.c32
-rw-r--r--arch/powerpc/kernel/eeh_driver.c25
-rw-r--r--arch/powerpc/kernel/exceptions-64e.S435
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S15
-rw-r--r--arch/powerpc/kernel/ftrace.c1
-rw-r--r--arch/powerpc/kernel/idle_power7.S90
-rw-r--r--arch/powerpc/kernel/irq.c8
-rw-r--r--arch/powerpc/kernel/mce.c4
-rw-r--r--arch/powerpc/kernel/mce_power.c37
-rw-r--r--arch/powerpc/kernel/misc_32.S5
-rw-r--r--arch/powerpc/kernel/pci_64.c4
-rw-r--r--arch/powerpc/kernel/process.c9
-rw-r--r--arch/powerpc/kernel/prom.c8
-rw-r--r--arch/powerpc/kernel/reloc_64.S1
-rw-r--r--arch/powerpc/kernel/rtas.c22
-rw-r--r--arch/powerpc/kernel/setup_64.c20
-rw-r--r--arch/powerpc/kernel/signal_64.c4
-rw-r--r--arch/powerpc/kernel/smp.c25
-rw-r--r--arch/powerpc/kernel/time.c90
-rw-r--r--arch/powerpc/kernel/traps.c5
-rw-r--r--arch/powerpc/kernel/vdso.c8
-rw-r--r--arch/powerpc/kernel/vdso32/getcpu.S2
-rw-r--r--arch/powerpc/kernel/vdso32/vdso32_wrapper.S2
-rw-r--r--arch/powerpc/kernel/vdso64/getcpu.S2
-rw-r--r--arch/powerpc/kernel/vdso64/vdso64_wrapper.S2
-rw-r--r--arch/powerpc/kernel/vio.c3
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_hv.c9
-rw-r--r--arch/powerpc/kvm/book3s_64_vio_hv.c28
-rw-r--r--arch/powerpc/kvm/book3s_hv.c159
-rw-r--r--arch/powerpc/kvm/book3s_hv_interrupts.S22
-rw-r--r--arch/powerpc/kvm/book3s_hv_rm_mmu.c6
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S262
-rw-r--r--arch/powerpc/kvm/book3s_interrupts.S4
-rw-r--r--arch/powerpc/kvm/book3s_rtas.c7
-rw-r--r--arch/powerpc/kvm/bookehv_interrupts.S21
-rw-r--r--arch/powerpc/lib/memcpy_64.S2
-rw-r--r--arch/powerpc/mm/mem.c7
-rw-r--r--arch/powerpc/mm/pgtable_64.c17
-rw-r--r--arch/powerpc/mm/subpage-prot.c2
-rw-r--r--arch/powerpc/mm/tlb_low_64e.S66
-rw-r--r--arch/powerpc/mm/tlb_nohash.c11
-rw-r--r--arch/powerpc/oprofile/op_model_cell.c3
-rw-r--r--arch/powerpc/perf/Makefile2
-rw-r--r--arch/powerpc/perf/core-book3s.c172
-rw-r--r--arch/powerpc/perf/hv-24x7-catalog.h33
-rw-r--r--arch/powerpc/perf/hv-24x7.c510
-rw-r--r--arch/powerpc/perf/hv-24x7.h109
-rw-r--r--arch/powerpc/perf/hv-common.c39
-rw-r--r--arch/powerpc/perf/hv-common.h36
-rw-r--r--arch/powerpc/perf/hv-gpci.c294
-rw-r--r--arch/powerpc/perf/hv-gpci.h73
-rw-r--r--arch/powerpc/perf/power7-events-list.h10
-rw-r--r--arch/powerpc/perf/power8-pmu.c78
-rw-r--r--arch/powerpc/platforms/44x/Kconfig1
-rw-r--r--arch/powerpc/platforms/85xx/c293pcie.c1
-rw-r--r--arch/powerpc/platforms/85xx/common.c6
-rw-r--r--arch/powerpc/platforms/85xx/corenet_generic.c17
-rw-r--r--arch/powerpc/platforms/85xx/ge_imp3a.c1
-rw-r--r--arch/powerpc/platforms/85xx/mpc8536_ds.c1
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx.h2
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_cds.c1
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ds.c3
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_mds.c4
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_rdb.c16
-rw-r--r--arch/powerpc/platforms/85xx/p1010rdb.c1
-rw-r--r--arch/powerpc/platforms/85xx/p1022_ds.c1
-rw-r--r--arch/powerpc/platforms/85xx/p1022_rdk.c1
-rw-r--r--arch/powerpc/platforms/85xx/p1023_rds.c2
-rw-r--r--arch/powerpc/platforms/85xx/qemu_e500.c1
-rw-r--r--arch/powerpc/platforms/85xx/sbc8548.c1
-rw-r--r--arch/powerpc/platforms/85xx/twr_p102x.c1
-rw-r--r--arch/powerpc/platforms/85xx/xes_mpc85xx.c3
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c2
-rw-r--r--arch/powerpc/platforms/cell/ras.c3
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c1
-rw-r--r--arch/powerpc/platforms/embedded6xx/Kconfig10
-rw-r--r--arch/powerpc/platforms/embedded6xx/Makefile1
-rw-r--r--arch/powerpc/platforms/embedded6xx/prpmc2800.c156
-rw-r--r--arch/powerpc/platforms/powernv/Makefile4
-rw-r--r--arch/powerpc/platforms/powernv/eeh-ioda.c128
-rw-r--r--arch/powerpc/platforms/powernv/eeh-powernv.c2
-rw-r--r--arch/powerpc/platforms/powernv/opal-async.c203
-rw-r--r--arch/powerpc/platforms/powernv/opal-dump.c525
-rw-r--r--arch/powerpc/platforms/powernv/opal-elog.c313
-rw-r--r--arch/powerpc/platforms/powernv/opal-sensor.c64
-rw-r--r--arch/powerpc/platforms/powernv/opal-sysparam.c290
-rw-r--r--arch/powerpc/platforms/powernv/opal-wrappers.S15
-rw-r--r--arch/powerpc/platforms/powernv/opal-xscom.c21
-rw-r--r--arch/powerpc/platforms/powernv/opal.c106
-rw-r--r--arch/powerpc/platforms/powernv/pci.c220
-rw-r--r--arch/powerpc/platforms/powernv/setup.c14
-rw-r--r--arch/powerpc/platforms/ps3/Kconfig2
-rw-r--r--arch/powerpc/platforms/ps3/smp.c2
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig12
-rw-r--r--arch/powerpc/platforms/pseries/dlpar.c2
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pseries.c2
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-cpu.c24
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-memory.c83
-rw-r--r--arch/powerpc/platforms/pseries/mobility.c26
-rw-r--r--arch/powerpc/platforms/pseries/pci.c22
-rw-r--r--arch/powerpc/platforms/pseries/pci_dlpar.c6
-rw-r--r--arch/powerpc/platforms/pseries/reconfig.c2
-rw-r--r--arch/powerpc/platforms/pseries/setup.c34
-rw-r--r--arch/powerpc/platforms/pseries/suspend.c44
-rw-r--r--arch/powerpc/sysdev/Makefile1
-rw-r--r--arch/powerpc/sysdev/ehv_pic.c10
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c178
-rw-r--r--arch/powerpc/sysdev/fsl_pci.h8
-rw-r--r--arch/powerpc/sysdev/msi_bitmap.c2
-rw-r--r--arch/powerpc/xmon/xmon.c4
-rw-r--r--arch/s390/Kconfig6
-rw-r--r--arch/s390/appldata/appldata_os.c2
-rw-r--r--arch/s390/configs/default_defconfig46
-rw-r--r--arch/s390/configs/gcov_defconfig33
-rw-r--r--arch/s390/configs/performance_defconfig33
-rw-r--r--arch/s390/configs/zfcpdump_defconfig1
-rw-r--r--arch/s390/defconfig10
-rw-r--r--arch/s390/hypfs/hypfs_vm.c9
-rw-r--r--arch/s390/include/asm/Kbuild5
-rw-r--r--arch/s390/include/asm/airq.h14
-rw-r--r--arch/s390/include/asm/bitops.h8
-rw-r--r--arch/s390/include/asm/ccwdev.h4
-rw-r--r--arch/s390/include/asm/ccwgroup.h1
-rw-r--r--arch/s390/include/asm/checksum.h11
-rw-r--r--arch/s390/include/asm/compat.h6
-rw-r--r--arch/s390/include/asm/futex.h13
-rw-r--r--arch/s390/include/asm/irq.h1
-rw-r--r--arch/s390/include/asm/kvm_host.h101
-rw-r--r--arch/s390/include/asm/mmu_context.h39
-rw-r--r--arch/s390/include/asm/pgalloc.h18
-rw-r--r--arch/s390/include/asm/pgtable.h107
-rw-r--r--arch/s390/include/asm/processor.h1
-rw-r--r--arch/s390/include/asm/ptrace.h1
-rw-r--r--arch/s390/include/asm/sclp.h1
-rw-r--r--arch/s390/include/asm/setup.h3
-rw-r--r--arch/s390/include/asm/thread_info.h3
-rw-r--r--arch/s390/include/asm/uaccess.h171
-rw-r--r--arch/s390/include/uapi/asm/kvm.h43
-rw-r--r--arch/s390/include/uapi/asm/ptrace.h6
-rw-r--r--arch/s390/kernel/Makefile5
-rw-r--r--arch/s390/kernel/compat_exec_domain.c29
-rw-r--r--arch/s390/kernel/compat_linux.c116
-rw-r--r--arch/s390/kernel/compat_linux.h81
-rw-r--r--arch/s390/kernel/compat_signal.c4
-rw-r--r--arch/s390/kernel/compat_wrapper.S1425
-rw-r--r--arch/s390/kernel/compat_wrapper.c215
-rw-r--r--arch/s390/kernel/early.c2
-rw-r--r--arch/s390/kernel/entry.S9
-rw-r--r--arch/s390/kernel/entry.h6
-rw-r--r--arch/s390/kernel/entry64.S9
-rw-r--r--arch/s390/kernel/irq.c2
-rw-r--r--arch/s390/kernel/perf_event.c2
-rw-r--r--arch/s390/kernel/ptrace.c13
-rw-r--r--arch/s390/kernel/setup.c17
-rw-r--r--arch/s390/kernel/smp.c8
-rw-r--r--arch/s390/kernel/syscalls.S504
-rw-r--r--arch/s390/kernel/topology.c1
-rw-r--r--arch/s390/kvm/Kconfig4
-rw-r--r--arch/s390/kvm/Makefile2
-rw-r--r--arch/s390/kvm/diag.c87
-rw-r--r--arch/s390/kvm/interrupt.c704
-rw-r--r--arch/s390/kvm/irq.h22
-rw-r--r--arch/s390/kvm/kvm-s390.c237
-rw-r--r--arch/s390/kvm/kvm-s390.h9
-rw-r--r--arch/s390/kvm/priv.c48
-rw-r--r--arch/s390/kvm/sigp.c157
-rw-r--r--arch/s390/kvm/trace.h46
-rw-r--r--arch/s390/lib/Makefile3
-rw-r--r--arch/s390/lib/find.c2
-rw-r--r--arch/s390/lib/uaccess.h8
-rw-r--r--arch/s390/lib/uaccess_mvcos.c116
-rw-r--r--arch/s390/lib/uaccess_pt.c69
-rw-r--r--arch/s390/mm/fault.c26
-rw-r--r--arch/s390/mm/maccess.c28
-rw-r--r--arch/s390/mm/pgtable.c158
-rw-r--r--arch/s390/pci/pci.c16
-rw-r--r--arch/s390/pci/pci_debug.c2
-rw-r--r--arch/s390/pci/pci_dma.c8
-rw-r--r--arch/s390/pci/pci_sysfs.c18
-rw-r--r--arch/score/include/asm/Kbuild6
-rw-r--r--arch/score/include/asm/cputime.h6
-rw-r--r--arch/sh/Kconfig85
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c4
-rw-r--r--arch/sh/boards/mach-se/7724/setup.c4
-rw-r--r--arch/sh/drivers/pci/pci.c5
-rw-r--r--arch/sh/include/asm/Kbuild9
-rw-r--r--arch/sh/include/cpu-sh2/cpu/cache.h2
-rw-r--r--arch/sh/include/cpu-sh2a/cpu/cache.h4
-rw-r--r--arch/sh/include/cpu-sh3/cpu/cache.h2
-rw-r--r--arch/sh/include/cpu-sh4/cpu/cache.h2
-rw-r--r--arch/sh/kernel/cpu/init.c4
-rw-r--r--arch/sh/kernel/idle.c4
-rw-r--r--arch/sh/kernel/irq.c18
-rw-r--r--arch/sh/mm/cache-debugfs.c2
-rw-r--r--arch/sh/mm/cache-sh2.c4
-rw-r--r--arch/sh/mm/cache-sh2a.c6
-rw-r--r--arch/sh/mm/cache-sh4.c4
-rw-r--r--arch/sh/mm/cache-shx3.c4
-rw-r--r--arch/sh/mm/cache.c4
-rw-r--r--arch/sparc/Kconfig2
-rw-r--r--arch/sparc/include/asm/Kbuild11
-rw-r--r--arch/sparc/include/asm/smp_64.h1
-rw-r--r--arch/sparc/include/asm/topology_64.h2
-rw-r--r--arch/sparc/kernel/leon_pci.c5
-rw-r--r--arch/sparc/kernel/mdesc.c4
-rw-r--r--arch/sparc/kernel/process_64.c4
-rw-r--r--arch/sparc/kernel/prom_64.c3
-rw-r--r--arch/sparc/kernel/smp_64.c2
-rw-r--r--arch/sparc/kernel/syscalls.S4
-rw-r--r--arch/sparc/kernel/time_64.c5
-rw-r--r--arch/sparc/mm/srmmu.c2
-rw-r--r--arch/sparc/mm/tsb.c2
-rw-r--r--arch/tile/include/asm/Kbuild5
-rw-r--r--arch/tile/kernel/pci_gx.c12
-rw-r--r--arch/um/include/asm/Kbuild34
-rw-r--r--arch/unicore32/include/asm/Kbuild5
-rw-r--r--arch/x86/Kconfig130
-rw-r--r--arch/x86/Kconfig.cpu6
-rw-r--r--arch/x86/Kconfig.debug9
-rw-r--r--arch/x86/Makefile5
-rw-r--r--arch/x86/boot/Makefile2
-rw-r--r--arch/x86/boot/boot.h13
-rw-r--r--arch/x86/boot/compressed/aslr.c9
-rw-r--r--arch/x86/boot/compressed/eboot.c1017
-rw-r--r--arch/x86/boot/compressed/eboot.h60
-rw-r--r--arch/x86/boot/compressed/efi_stub_64.S29
-rw-r--r--arch/x86/boot/compressed/head_32.S52
-rw-r--r--arch/x86/boot/compressed/head_64.S111
-rw-r--r--arch/x86/boot/compressed/misc.c51
-rw-r--r--arch/x86/boot/compressed/string.c46
-rw-r--r--arch/x86/boot/cpucheck.c21
-rw-r--r--arch/x86/boot/edd.c1
-rw-r--r--arch/x86/boot/header.S25
-rw-r--r--arch/x86/boot/main.c1
-rw-r--r--arch/x86/boot/regs.c1
-rw-r--r--arch/x86/boot/string.c14
-rw-r--r--arch/x86/boot/string.h21
-rw-r--r--arch/x86/boot/tools/build.c77
-rw-r--r--arch/x86/boot/video-vesa.c1
-rw-r--r--arch/x86/configs/i386_defconfig1
-rw-r--r--arch/x86/configs/x86_64_defconfig1
-rw-r--r--arch/x86/include/asm/Kbuild2
-rw-r--r--arch/x86/include/asm/apic.h14
-rw-r--r--arch/x86/include/asm/barrier.h8
-rw-r--r--arch/x86/include/asm/clocksource.h4
-rw-r--r--arch/x86/include/asm/cpufeature.h16
-rw-r--r--arch/x86/include/asm/cputime.h1
-rw-r--r--arch/x86/include/asm/efi.h44
-rw-r--r--arch/x86/include/asm/elf.h4
-rw-r--r--arch/x86/include/asm/fixmap.h14
-rw-r--r--arch/x86/include/asm/floppy.h4
-rw-r--r--arch/x86/include/asm/hardirq.h3
-rw-r--r--arch/x86/include/asm/hw_irq.h1
-rw-r--r--arch/x86/include/asm/io.h2
-rw-r--r--arch/x86/include/asm/kvm_host.h18
-rw-r--r--arch/x86/include/asm/mmzone_32.h3
-rw-r--r--arch/x86/include/asm/mpspec.h6
-rw-r--r--arch/x86/include/asm/mshyperv.h4
-rw-r--r--arch/x86/include/asm/msr.h2
-rw-r--r--arch/x86/include/asm/nmi.h3
-rw-r--r--arch/x86/include/asm/numaq.h171
-rw-r--r--arch/x86/include/asm/pci.h7
-rw-r--r--arch/x86/include/asm/pgtable.h17
-rw-r--r--arch/x86/include/asm/pgtable_types.h11
-rw-r--r--arch/x86/include/asm/processor.h9
-rw-r--r--arch/x86/include/asm/setup.h6
-rw-r--r--arch/x86/include/asm/special_insns.h8
-rw-r--r--arch/x86/include/asm/spinlock.h5
-rw-r--r--arch/x86/include/asm/thread_info.h53
-rw-r--r--arch/x86/include/asm/topology.h23
-rw-r--r--arch/x86/include/asm/tsc.h2
-rw-r--r--arch/x86/include/asm/unistd.h3
-rw-r--r--arch/x86/include/asm/vdso.h52
-rw-r--r--arch/x86/include/asm/vdso32.h11
-rw-r--r--arch/x86/include/asm/vgtod.h71
-rw-r--r--arch/x86/include/asm/visws/cobalt.h127
-rw-r--r--arch/x86/include/asm/visws/lithium.h53
-rw-r--r--arch/x86/include/asm/visws/piix4.h107
-rw-r--r--arch/x86/include/asm/visws/sgivw.h5
-rw-r--r--arch/x86/include/asm/vmx.h4
-rw-r--r--arch/x86/include/asm/vvar.h29
-rw-r--r--arch/x86/include/asm/xsave.h18
-rw-r--r--arch/x86/include/uapi/asm/msr-index.h76
-rw-r--r--arch/x86/kernel/Makefile2
-rw-r--r--arch/x86/kernel/acpi/boot.c24
-rw-r--r--arch/x86/kernel/amd_nb.c2
-rw-r--r--arch/x86/kernel/aperture_64.c20
-rw-r--r--arch/x86/kernel/apic/Makefile3
-rw-r--r--arch/x86/kernel/apic/apic.c14
-rw-r--r--arch/x86/kernel/apic/apic_flat_64.c4
-rw-r--r--arch/x86/kernel/apic/apic_noop.c3
-rw-r--r--arch/x86/kernel/apic/apic_numachip.c2
-rw-r--r--arch/x86/kernel/apic/bigsmp_32.c3
-rw-r--r--arch/x86/kernel/apic/es7000_32.c746
-rw-r--r--arch/x86/kernel/apic/numaq_32.c525
-rw-r--r--arch/x86/kernel/apic/probe_32.c3
-rw-r--r--arch/x86/kernel/apic/summit_32.c551
-rw-r--r--arch/x86/kernel/apic/x2apic_cluster.c2
-rw-r--r--arch/x86/kernel/apic/x2apic_phys.c2
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c2
-rw-r--r--arch/x86/kernel/cpu/amd.c50
-rw-r--r--arch/x86/kernel/cpu/centaur.c272
-rw-r--r--arch/x86/kernel/cpu/common.c11
-rw-r--r--arch/x86/kernel/cpu/intel.c57
-rw-r--r--arch/x86/kernel/cpu/match.c42
-rw-r--r--arch/x86/kernel/cpu/mshyperv.c84
-rw-r--r--arch/x86/kernel/cpu/perf_event.c54
-rw-r--r--arch/x86/kernel/cpu/perf_event.h9
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c11
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore.c557
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore.h5
-rw-r--r--arch/x86/kernel/cpu/perf_event_p4.c34
-rw-r--r--arch/x86/kernel/cpu/perf_event_p6.c48
-rw-r--r--arch/x86/kernel/crash.c2
-rw-r--r--arch/x86/kernel/dumpstack_32.c46
-rw-r--r--arch/x86/kernel/dumpstack_64.c118
-rw-r--r--arch/x86/kernel/early-quirks.c15
-rw-r--r--arch/x86/kernel/head_32.S7
-rw-r--r--arch/x86/kernel/head_64.S6
-rw-r--r--arch/x86/kernel/hpet.c6
-rw-r--r--arch/x86/kernel/i387.c15
-rw-r--r--arch/x86/kernel/irq.c6
-rw-r--r--arch/x86/kernel/irq_32.c83
-rw-r--r--arch/x86/kernel/kvm.c1
-rw-r--r--arch/x86/kernel/kvmclock.c2
-rw-r--r--arch/x86/kernel/machine_kexec_64.c2
-rw-r--r--arch/x86/kernel/module.c46
-rw-r--r--arch/x86/kernel/nmi.c37
-rw-r--r--arch/x86/kernel/pci-dma.c4
-rw-r--r--arch/x86/kernel/process.c5
-rw-r--r--arch/x86/kernel/process_32.c4
-rw-r--r--arch/x86/kernel/ptrace.c8
-rw-r--r--arch/x86/kernel/quirks.c2
-rw-r--r--arch/x86/kernel/reboot.c15
-rw-r--r--arch/x86/kernel/setup.c17
-rw-r--r--arch/x86/kernel/smpboot.c20
-rw-r--r--arch/x86/kernel/time.c4
-rw-r--r--arch/x86/kernel/tsc.c12
-rw-r--r--arch/x86/kernel/tsc_msr.c30
-rw-r--r--arch/x86/kernel/vmlinux.lds.S8
-rw-r--r--arch/x86/kernel/vsyscall_64.c45
-rw-r--r--arch/x86/kernel/vsyscall_gtod.c69
-rw-r--r--arch/x86/kvm/cpuid.c39
-rw-r--r--arch/x86/kvm/emulate.c8
-rw-r--r--arch/x86/kvm/mmu.c3
-rw-r--r--arch/x86/kvm/paging_tmpl.h7
-rw-r--r--arch/x86/kvm/svm.c90
-rw-r--r--arch/x86/kvm/vmx.c336
-rw-r--r--arch/x86/kvm/x86.c147
-rw-r--r--arch/x86/kvm/x86.h5
-rw-r--r--arch/x86/lib/hash.c22
-rw-r--r--arch/x86/lib/memcpy_32.c6
-rw-r--r--arch/x86/lib/msr.c89
-rw-r--r--arch/x86/mm/dump_pagetables.c84
-rw-r--r--arch/x86/mm/fault.c54
-rw-r--r--arch/x86/mm/numa.c4
-rw-r--r--arch/x86/mm/pageattr.c70
-rw-r--r--arch/x86/mm/srat.c12
-rw-r--r--arch/x86/net/bpf_jit.S2
-rw-r--r--arch/x86/pci/Makefile3
-rw-r--r--arch/x86/pci/acpi.c59
-rw-r--r--arch/x86/pci/amd_bus.c10
-rw-r--r--arch/x86/pci/bus_numa.c13
-rw-r--r--arch/x86/pci/common.c133
-rw-r--r--arch/x86/pci/fixup.c24
-rw-r--r--arch/x86/pci/irq.c6
-rw-r--r--arch/x86/pci/legacy.c4
-rw-r--r--arch/x86/pci/numaq_32.c165
-rw-r--r--arch/x86/pci/visws.c87
-rw-r--r--arch/x86/platform/Makefile1
-rw-r--r--arch/x86/platform/efi/Makefile1
-rw-r--r--arch/x86/platform/efi/efi.c431
-rw-r--r--arch/x86/platform/efi/efi_32.c7
-rw-r--r--arch/x86/platform/efi/efi_64.c368
-rw-r--r--arch/x86/platform/efi/efi_stub_64.S166
-rw-r--r--arch/x86/platform/efi/efi_thunk_64.S65
-rw-r--r--arch/x86/platform/ts5500/ts5500.c2
-rw-r--r--arch/x86/platform/visws/Makefile1
-rw-r--r--arch/x86/platform/visws/visws_quirks.c608
-rw-r--r--arch/x86/tools/relocs.c2
-rw-r--r--arch/x86/um/asm/barrier.h4
-rw-r--r--arch/x86/vdso/Makefile26
-rw-r--r--arch/x86/vdso/vclock_gettime.c256
-rw-r--r--arch/x86/vdso/vdso-layout.lds.S29
-rw-r--r--arch/x86/vdso/vdso.S22
-rw-r--r--arch/x86/vdso/vdso32-setup.c301
-rw-r--r--arch/x86/vdso/vdso32.S21
-rw-r--r--arch/x86/vdso/vdso32/vclock_gettime.c30
-rw-r--r--arch/x86/vdso/vdso32/vdso32.lds.S15
-rw-r--r--arch/x86/vdso/vdsox32.S22
-rw-r--r--arch/x86/vdso/vma.c20
-rw-r--r--arch/x86/xen/Kconfig2
-rw-r--r--arch/x86/xen/mmu.c5
-rw-r--r--arch/x86/xen/spinlock.c2
-rw-r--r--arch/xtensa/Kconfig3
-rw-r--r--arch/xtensa/boot/dts/xtfpga.dtsi12
-rw-r--r--arch/xtensa/include/asm/Kbuild5
-rw-r--r--arch/xtensa/include/asm/io.h2
-rw-r--r--arch/xtensa/include/asm/traps.h44
-rw-r--r--arch/xtensa/include/asm/vectors.h2
-rw-r--r--arch/xtensa/include/uapi/asm/unistd.h7
-rw-r--r--arch/xtensa/kernel/entry.S449
-rw-r--r--arch/xtensa/kernel/irq.c22
-rw-r--r--arch/xtensa/kernel/setup.c2
-rw-r--r--arch/xtensa/kernel/time.c1
-rw-r--r--arch/xtensa/kernel/vectors.S2
-rw-r--r--arch/xtensa/kernel/xtensa_ksyms.c2
-rw-r--r--arch/xtensa/mm/init.c13
-rw-r--r--arch/xtensa/mm/mmu.c2
-rw-r--r--arch/xtensa/platforms/xtfpga/setup.c7
-rw-r--r--arch/xtensa/variants/fsf/include/variant/tie.h9
-rw-r--r--block/blk-cgroup.c2
-rw-r--r--block/blk-core.c27
-rw-r--r--block/blk-exec.c2
-rw-r--r--block/blk-flush.c15
-rw-r--r--block/blk-ioc.c2
-rw-r--r--block/blk-iopoll.c3
-rw-r--r--block/blk-mq-cpu.c14
-rw-r--r--block/blk-mq-cpumap.c10
-rw-r--r--block/blk-mq-sysfs.c31
-rw-r--r--block/blk-mq.c172
-rw-r--r--block/blk-mq.h3
-rw-r--r--block/blk-softirq.c19
-rw-r--r--block/cfq-iosched.c8
-rw-r--r--block/deadline-iosched.c8
-rw-r--r--block/partitions/atari.h4
-rw-r--r--block/partitions/efi.h9
-rw-r--r--block/partitions/karma.c3
-rw-r--r--drivers/Kconfig4
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acpi/Kconfig28
-rw-r--r--drivers/acpi/ac.c27
-rw-r--r--drivers/acpi/acpi_cmos_rtc.c2
-rw-r--r--drivers/acpi/acpi_lpss.c82
-rw-r--r--drivers/acpi/acpi_pad.c24
-rw-r--r--drivers/acpi/acpica/Makefile4
-rw-r--r--drivers/acpi/acpica/accommon.h2
-rw-r--r--drivers/acpi/acpica/acdebug.h4
-rw-r--r--drivers/acpi/acpica/acdispat.h15
-rw-r--r--drivers/acpi/acpica/acevents.h2
-rw-r--r--drivers/acpi/acpica/acglobal.h364
-rw-r--r--drivers/acpi/acpica/achware.h2
-rw-r--r--drivers/acpi/acpica/acinterp.h10
-rw-r--r--drivers/acpi/acpica/aclocal.h2
-rw-r--r--drivers/acpi/acpica/acmacros.h16
-rw-r--r--drivers/acpi/acpica/acnamesp.h2
-rw-r--r--drivers/acpi/acpica/acobject.h5
-rw-r--r--drivers/acpi/acpica/acopcode.h2
-rw-r--r--drivers/acpi/acpica/acparser.h2
-rw-r--r--drivers/acpi/acpica/acpredef.h16
-rw-r--r--drivers/acpi/acpica/acresrc.h2
-rw-r--r--drivers/acpi/acpica/acstruct.h5
-rw-r--r--drivers/acpi/acpica/actables.h2
-rw-r--r--drivers/acpi/acpica/acutils.h4
-rw-r--r--drivers/acpi/acpica/amlcode.h2
-rw-r--r--drivers/acpi/acpica/amlresrc.h2
-rw-r--r--drivers/acpi/acpica/dsargs.c2
-rw-r--r--drivers/acpi/acpica/dscontrol.c2
-rw-r--r--drivers/acpi/acpica/dsfield.c2
-rw-r--r--drivers/acpi/acpica/dsinit.c61
-rw-r--r--drivers/acpi/acpica/dsmethod.c158
-rw-r--r--drivers/acpi/acpica/dsmthdat.c2
-rw-r--r--drivers/acpi/acpica/dsobject.c2
-rw-r--r--drivers/acpi/acpica/dsopcode.c2
-rw-r--r--drivers/acpi/acpica/dsutils.c2
-rw-r--r--drivers/acpi/acpica/dswexec.c2
-rw-r--r--drivers/acpi/acpica/dswload.c18
-rw-r--r--drivers/acpi/acpica/dswload2.c2
-rw-r--r--drivers/acpi/acpica/dswscope.c2
-rw-r--r--drivers/acpi/acpica/dswstate.c2
-rw-r--r--drivers/acpi/acpica/evevent.c2
-rw-r--r--drivers/acpi/acpica/evglock.c2
-rw-r--r--drivers/acpi/acpica/evgpe.c2
-rw-r--r--drivers/acpi/acpica/evgpeblk.c2
-rw-r--r--drivers/acpi/acpica/evgpeinit.c2
-rw-r--r--drivers/acpi/acpica/evgpeutil.c2
-rw-r--r--drivers/acpi/acpica/evhandler.c2
-rw-r--r--drivers/acpi/acpica/evmisc.c2
-rw-r--r--drivers/acpi/acpica/evregion.c13
-rw-r--r--drivers/acpi/acpica/evrgnini.c2
-rw-r--r--drivers/acpi/acpica/evsci.c2
-rw-r--r--drivers/acpi/acpica/evxface.c2
-rw-r--r--drivers/acpi/acpica/evxfevnt.c2
-rw-r--r--drivers/acpi/acpica/evxfgpe.c21
-rw-r--r--drivers/acpi/acpica/evxfregn.c2
-rw-r--r--drivers/acpi/acpica/exconfig.c2
-rw-r--r--drivers/acpi/acpica/exconvrt.c2
-rw-r--r--drivers/acpi/acpica/excreate.c2
-rw-r--r--drivers/acpi/acpica/exdebug.c2
-rw-r--r--drivers/acpi/acpica/exdump.c231
-rw-r--r--drivers/acpi/acpica/exfield.c2
-rw-r--r--drivers/acpi/acpica/exfldio.c2
-rw-r--r--drivers/acpi/acpica/exmisc.c2
-rw-r--r--drivers/acpi/acpica/exmutex.c2
-rw-r--r--drivers/acpi/acpica/exnames.c2
-rw-r--r--drivers/acpi/acpica/exoparg1.c2
-rw-r--r--drivers/acpi/acpica/exoparg2.c2
-rw-r--r--drivers/acpi/acpica/exoparg3.c2
-rw-r--r--drivers/acpi/acpica/exoparg6.c2
-rw-r--r--drivers/acpi/acpica/exprep.c2
-rw-r--r--drivers/acpi/acpica/exregion.c2
-rw-r--r--drivers/acpi/acpica/exresnte.c2
-rw-r--r--drivers/acpi/acpica/exresolv.c2
-rw-r--r--drivers/acpi/acpica/exresop.c2
-rw-r--r--drivers/acpi/acpica/exstore.c2
-rw-r--r--drivers/acpi/acpica/exstoren.c2
-rw-r--r--drivers/acpi/acpica/exstorob.c2
-rw-r--r--drivers/acpi/acpica/exsystem.c14
-rw-r--r--drivers/acpi/acpica/exutils.c82
-rw-r--r--drivers/acpi/acpica/hwacpi.c2
-rw-r--r--drivers/acpi/acpica/hwesleep.c2
-rw-r--r--drivers/acpi/acpica/hwgpe.c2
-rw-r--r--drivers/acpi/acpica/hwpci.c2
-rw-r--r--drivers/acpi/acpica/hwregs.c2
-rw-r--r--drivers/acpi/acpica/hwsleep.c2
-rw-r--r--drivers/acpi/acpica/hwtimer.c2
-rw-r--r--drivers/acpi/acpica/hwvalid.c2
-rw-r--r--drivers/acpi/acpica/hwxface.c2
-rw-r--r--drivers/acpi/acpica/hwxfsleep.c2
-rw-r--r--drivers/acpi/acpica/nsaccess.c2
-rw-r--r--drivers/acpi/acpica/nsalloc.c2
-rw-r--r--drivers/acpi/acpica/nsarguments.c2
-rw-r--r--drivers/acpi/acpica/nsconvert.c2
-rw-r--r--drivers/acpi/acpica/nsdump.c2
-rw-r--r--drivers/acpi/acpica/nsdumpdv.c2
-rw-r--r--drivers/acpi/acpica/nseval.c2
-rw-r--r--drivers/acpi/acpica/nsinit.c7
-rw-r--r--drivers/acpi/acpica/nsload.c6
-rw-r--r--drivers/acpi/acpica/nsnames.c2
-rw-r--r--drivers/acpi/acpica/nsobject.c12
-rw-r--r--drivers/acpi/acpica/nsparse.c2
-rw-r--r--drivers/acpi/acpica/nspredef.c2
-rw-r--r--drivers/acpi/acpica/nsprepkg.c42
-rw-r--r--drivers/acpi/acpica/nsrepair.c31
-rw-r--r--drivers/acpi/acpica/nsrepair2.c39
-rw-r--r--drivers/acpi/acpica/nssearch.c2
-rw-r--r--drivers/acpi/acpica/nsutils.c2
-rw-r--r--drivers/acpi/acpica/nswalk.c2
-rw-r--r--drivers/acpi/acpica/nsxfeval.c35
-rw-r--r--drivers/acpi/acpica/nsxfname.c2
-rw-r--r--drivers/acpi/acpica/nsxfobj.c2
-rw-r--r--drivers/acpi/acpica/psargs.c2
-rw-r--r--drivers/acpi/acpica/psloop.c6
-rw-r--r--drivers/acpi/acpica/psobject.c9
-rw-r--r--drivers/acpi/acpica/psopcode.c2
-rw-r--r--drivers/acpi/acpica/psopinfo.c2
-rw-r--r--drivers/acpi/acpica/psparse.c2
-rw-r--r--drivers/acpi/acpica/psscope.c2
-rw-r--r--drivers/acpi/acpica/pstree.c2
-rw-r--r--drivers/acpi/acpica/psutils.c2
-rw-r--r--drivers/acpi/acpica/pswalk.c2
-rw-r--r--drivers/acpi/acpica/psxface.c2
-rw-r--r--drivers/acpi/acpica/rsaddr.c2
-rw-r--r--drivers/acpi/acpica/rscalc.c4
-rw-r--r--drivers/acpi/acpica/rscreate.c12
-rw-r--r--drivers/acpi/acpica/rsdump.c5
-rw-r--r--drivers/acpi/acpica/rsdumpinfo.c4
-rw-r--r--drivers/acpi/acpica/rsinfo.c6
-rw-r--r--drivers/acpi/acpica/rsio.c2
-rw-r--r--drivers/acpi/acpica/rsirq.c2
-rw-r--r--drivers/acpi/acpica/rslist.c2
-rw-r--r--drivers/acpi/acpica/rsmemory.c2
-rw-r--r--drivers/acpi/acpica/rsmisc.c2
-rw-r--r--drivers/acpi/acpica/rsserial.c2
-rw-r--r--drivers/acpi/acpica/rsutils.c2
-rw-r--r--drivers/acpi/acpica/rsxface.c2
-rw-r--r--drivers/acpi/acpica/tbfadt.c2
-rw-r--r--drivers/acpi/acpica/tbfind.c2
-rw-r--r--drivers/acpi/acpica/tbinstal.c17
-rw-r--r--drivers/acpi/acpica/tbprint.c22
-rw-r--r--drivers/acpi/acpica/tbutils.c2
-rw-r--r--drivers/acpi/acpica/tbxface.c2
-rw-r--r--drivers/acpi/acpica/tbxfload.c2
-rw-r--r--drivers/acpi/acpica/tbxfroot.c2
-rw-r--r--drivers/acpi/acpica/utaddress.c2
-rw-r--r--drivers/acpi/acpica/utalloc.c2
-rw-r--r--drivers/acpi/acpica/utbuffer.c2
-rw-r--r--drivers/acpi/acpica/utcache.c2
-rw-r--r--drivers/acpi/acpica/utcopy.c8
-rw-r--r--drivers/acpi/acpica/utdebug.c2
-rw-r--r--drivers/acpi/acpica/utdecode.c2
-rw-r--r--drivers/acpi/acpica/utdelete.c17
-rw-r--r--drivers/acpi/acpica/uterror.c2
-rw-r--r--drivers/acpi/acpica/uteval.c2
-rw-r--r--drivers/acpi/acpica/utexcep.c2
-rw-r--r--drivers/acpi/acpica/utglobal.c39
-rw-r--r--drivers/acpi/acpica/utids.c2
-rw-r--r--drivers/acpi/acpica/utinit.c2
-rw-r--r--drivers/acpi/acpica/utlock.c2
-rw-r--r--drivers/acpi/acpica/utmath.c2
-rw-r--r--drivers/acpi/acpica/utmisc.c2
-rw-r--r--drivers/acpi/acpica/utmutex.c2
-rw-r--r--drivers/acpi/acpica/utobject.c2
-rw-r--r--drivers/acpi/acpica/utosi.c28
-rw-r--r--drivers/acpi/acpica/utownerid.c2
-rw-r--r--drivers/acpi/acpica/utpredef.c2
-rw-r--r--drivers/acpi/acpica/utresrc.c5
-rw-r--r--drivers/acpi/acpica/utstate.c2
-rw-r--r--drivers/acpi/acpica/utstring.c2
-rw-r--r--drivers/acpi/acpica/uttrack.c5
-rw-r--r--drivers/acpi/acpica/utxface.c2
-rw-r--r--drivers/acpi/acpica/utxferror.c2
-rw-r--r--drivers/acpi/acpica/utxfinit.c2
-rw-r--r--drivers/acpi/acpica/utxfmutex.c2
-rw-r--r--drivers/acpi/apei/Kconfig2
-rw-r--r--drivers/acpi/battery.c9
-rw-r--r--drivers/acpi/battery.h10
-rw-r--r--drivers/acpi/blacklist.c58
-rw-r--r--drivers/acpi/bus.c63
-rw-r--r--drivers/acpi/button.c6
-rw-r--r--drivers/acpi/container.c5
-rw-r--r--drivers/acpi/device_pm.c41
-rw-r--r--drivers/acpi/dock.c462
-rw-r--r--drivers/acpi/ec.c64
-rw-r--r--drivers/acpi/fan.c12
-rw-r--r--drivers/acpi/glue.c12
-rw-r--r--drivers/acpi/internal.h13
-rw-r--r--drivers/acpi/numa.c16
-rw-r--r--drivers/acpi/osl.c43
-rw-r--r--drivers/acpi/pci_irq.c37
-rw-r--r--drivers/acpi/pci_link.c2
-rw-r--r--drivers/acpi/pci_root.c4
-rw-r--r--drivers/acpi/power.c2
-rw-r--r--drivers/acpi/processor_core.c52
-rw-r--r--drivers/acpi/processor_driver.c2
-rw-r--r--drivers/acpi/processor_perflib.c14
-rw-r--r--drivers/acpi/processor_throttling.c69
-rw-r--r--drivers/acpi/resource.c10
-rw-r--r--drivers/acpi/sbs.c6
-rw-r--r--drivers/acpi/scan.c261
-rw-r--r--drivers/acpi/sleep.c32
-rw-r--r--drivers/acpi/sysfs.c2
-rw-r--r--drivers/acpi/tables.c128
-rw-r--r--drivers/acpi/thermal.c39
-rw-r--r--drivers/acpi/utils.c16
-rw-r--r--drivers/acpi/video.c149
-rw-r--r--drivers/acpi/video_detect.c18
-rw-r--r--drivers/ata/Kconfig57
-rw-r--r--drivers/ata/Makefile8
-rw-r--r--drivers/ata/acard-ahci.c1
-rw-r--r--drivers/ata/ahci.c39
-rw-r--r--drivers/ata/ahci.h14
-rw-r--r--drivers/ata/ahci_da850.c114
-rw-r--r--drivers/ata/ahci_imx.c333
-rw-r--r--drivers/ata/ahci_platform.c291
-rw-r--r--drivers/ata/ahci_st.c245
-rw-r--r--drivers/ata/ahci_sunxi.c249
-rw-r--r--drivers/ata/ahci_xgene.c486
-rw-r--r--drivers/ata/ata_generic.c1
-rw-r--r--drivers/ata/libahci.c38
-rw-r--r--drivers/ata/libahci_platform.c541
-rw-r--r--drivers/ata/libata-acpi.c73
-rw-r--r--drivers/ata/libata-core.c138
-rw-r--r--drivers/ata/libata-eh.c18
-rw-r--r--drivers/ata/libata-pmp.c7
-rw-r--r--drivers/ata/libata-zpodd.c21
-rw-r--r--drivers/ata/pata_acpi.c1
-rw-r--r--drivers/ata/pata_amd.c1
-rw-r--r--drivers/ata/pata_arasan_cf.c2
-rw-r--r--drivers/ata/pata_artop.c1
-rw-r--r--drivers/ata/pata_at91.c1
-rw-r--r--drivers/ata/pata_atiixp.c1
-rw-r--r--drivers/ata/pata_atp867x.c1
-rw-r--r--drivers/ata/pata_cmd640.c1
-rw-r--r--drivers/ata/pata_cmd64x.c1
-rw-r--r--drivers/ata/pata_cs5520.c1
-rw-r--r--drivers/ata/pata_cs5530.c1
-rw-r--r--drivers/ata/pata_cs5535.c1
-rw-r--r--drivers/ata/pata_cs5536.c1
-rw-r--r--drivers/ata/pata_cypress.c1
-rw-r--r--drivers/ata/pata_efar.c1
-rw-r--r--drivers/ata/pata_ep93xx.c1
-rw-r--r--drivers/ata/pata_hpt366.c1
-rw-r--r--drivers/ata/pata_hpt37x.c1
-rw-r--r--drivers/ata/pata_hpt3x2n.c1
-rw-r--r--drivers/ata/pata_hpt3x3.c1
-rw-r--r--drivers/ata/pata_imx.c26
-rw-r--r--drivers/ata/pata_it8213.c1
-rw-r--r--drivers/ata/pata_it821x.c1
-rw-r--r--drivers/ata/pata_jmicron.c1
-rw-r--r--drivers/ata/pata_legacy.c1
-rw-r--r--drivers/ata/pata_marvell.c1
-rw-r--r--drivers/ata/pata_mpiix.c1
-rw-r--r--drivers/ata/pata_netcell.c1
-rw-r--r--drivers/ata/pata_ninja32.c1
-rw-r--r--drivers/ata/pata_ns87410.c1
-rw-r--r--drivers/ata/pata_ns87415.c1
-rw-r--r--drivers/ata/pata_oldpiix.c1
-rw-r--r--drivers/ata/pata_opti.c1
-rw-r--r--drivers/ata/pata_optidma.c1
-rw-r--r--drivers/ata/pata_pcmcia.c1
-rw-r--r--drivers/ata/pata_pdc2027x.c1
-rw-r--r--drivers/ata/pata_pdc202xx_old.c1
-rw-r--r--drivers/ata/pata_piccolo.c1
-rw-r--r--drivers/ata/pata_platform.c1
-rw-r--r--drivers/ata/pata_pxa.c1
-rw-r--r--drivers/ata/pata_radisys.c1
-rw-r--r--drivers/ata/pata_rdc.c1
-rw-r--r--drivers/ata/pata_rz1000.c1
-rw-r--r--drivers/ata/pata_sc1200.c1
-rw-r--r--drivers/ata/pata_scc.c1
-rw-r--r--drivers/ata/pata_sch.c1
-rw-r--r--drivers/ata/pata_serverworks.c1
-rw-r--r--drivers/ata/pata_sil680.c1
-rw-r--r--drivers/ata/pata_sis.c1
-rw-r--r--drivers/ata/pata_sl82c105.c1
-rw-r--r--drivers/ata/pata_triflex.c1
-rw-r--r--drivers/ata/pata_via.c1
-rw-r--r--drivers/ata/pdc_adma.c1
-rw-r--r--drivers/ata/sata_dwc_460ex.c4
-rw-r--r--drivers/ata/sata_highbank.c6
-rw-r--r--drivers/ata/sata_mv.c12
-rw-r--r--drivers/ata/sata_nv.c1
-rw-r--r--drivers/ata/sata_promise.c1
-rw-r--r--drivers/ata/sata_qstor.c1
-rw-r--r--drivers/ata/sata_sil.c2
-rw-r--r--drivers/ata/sata_sis.c1
-rw-r--r--drivers/ata/sata_svw.c1
-rw-r--r--drivers/ata/sata_sx4.c10
-rw-r--r--drivers/ata/sata_uli.c1
-rw-r--r--drivers/ata/sata_via.c1
-rw-r--r--drivers/ata/sata_vsc.c1
-rw-r--r--drivers/base/Kconfig3
-rw-r--r--drivers/base/attribute_container.c1
-rw-r--r--drivers/base/core.c19
-rw-r--r--drivers/base/cpu.c46
-rw-r--r--drivers/base/devres.c26
-rw-r--r--drivers/base/dma-buf.c43
-rw-r--r--drivers/base/firmware_class.c14
-rw-r--r--drivers/base/node.c4
-rw-r--r--drivers/base/platform.c11
-rw-r--r--drivers/base/power/Makefile3
-rw-r--r--drivers/base/power/clock_ops.c1
-rw-r--r--drivers/base/power/common.c1
-rw-r--r--drivers/base/power/domain.c3
-rw-r--r--drivers/base/power/domain_governor.c1
-rw-r--r--drivers/base/power/generic_ops.c2
-rw-r--r--drivers/base/power/main.c280
-rw-r--r--drivers/base/power/opp.c1
-rw-r--r--drivers/base/power/power.h4
-rw-r--r--drivers/base/power/qos.c220
-rw-r--r--drivers/base/power/runtime.c164
-rw-r--r--drivers/base/power/sysfs.c97
-rw-r--r--drivers/base/regmap/internal.h2
-rw-r--r--drivers/base/regmap/regcache.c13
-rw-r--r--drivers/base/regmap/regmap-debugfs.c2
-rw-r--r--drivers/base/regmap/regmap-i2c.c1
-rw-r--r--drivers/base/regmap/regmap-irq.c6
-rw-r--r--drivers/base/regmap/regmap-mmio.c57
-rw-r--r--drivers/base/regmap/regmap-spi.c1
-rw-r--r--drivers/base/regmap/regmap-spmi.c228
-rw-r--r--drivers/base/regmap/regmap.c353
-rw-r--r--drivers/base/topology.c1
-rw-r--r--drivers/block/DAC960.c34
-rw-r--r--drivers/block/aoe/aoecmd.c4
-rw-r--r--drivers/block/ataflop.c16
-rw-r--r--drivers/block/cciss.c2
-rw-r--r--drivers/block/drbd/drbd_actlog.c629
-rw-r--r--drivers/block/drbd/drbd_bitmap.c368
-rw-r--r--drivers/block/drbd/drbd_int.h1130
-rw-r--r--drivers/block/drbd/drbd_main.c2009
-rw-r--r--drivers/block/drbd/drbd_nl.c1653
-rw-r--r--drivers/block/drbd/drbd_proc.c140
-rw-r--r--drivers/block/drbd/drbd_protocol.h295
-rw-r--r--drivers/block/drbd/drbd_receiver.c2532
-rw-r--r--drivers/block/drbd/drbd_req.c464
-rw-r--r--drivers/block/drbd/drbd_req.h20
-rw-r--r--drivers/block/drbd/drbd_state.c859
-rw-r--r--drivers/block/drbd/drbd_state.h40
-rw-r--r--drivers/block/drbd/drbd_strings.c1
-rw-r--r--drivers/block/drbd/drbd_strings.h9
-rw-r--r--drivers/block/drbd/drbd_worker.c944
-rw-r--r--drivers/block/drbd/drbd_wrappers.h14
-rw-r--r--drivers/block/floppy.c42
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c94
-rw-r--r--drivers/block/mtip32xx/mtip32xx.h4
-rw-r--r--drivers/block/nvme-core.c51
-rw-r--r--drivers/block/rbd.c1
-rw-r--r--drivers/block/skd_main.c67
-rw-r--r--drivers/block/swim3.c18
-rw-r--r--drivers/block/virtio_blk.c23
-rw-r--r--drivers/block/zram/zram_drv.c2
-rw-r--r--drivers/bus/mvebu-mbus.c4
-rw-r--r--drivers/char/agp/frontend.c1
-rw-r--r--drivers/char/agp/generic.c1
-rw-r--r--drivers/char/agp/intel-gtt.c1
-rw-r--r--drivers/char/agp/sgi-agp.c1
-rw-r--r--drivers/char/hw_random/bcm2835-rng.c1
-rw-r--r--drivers/char/hw_random/core.c1
-rw-r--r--drivers/char/hw_random/exynos-rng.c1
-rw-r--r--drivers/char/hw_random/n2-drv.c1
-rw-r--r--drivers/char/hw_random/nomadik-rng.c1
-rw-r--r--drivers/char/hw_random/octeon-rng.c1
-rw-r--r--drivers/char/hw_random/virtio-rng.c3
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c1
-rw-r--r--drivers/char/mem.c6
-rw-r--r--drivers/char/mwave/3780i.c1
-rw-r--r--drivers/char/tile-srom.c1
-rw-r--r--drivers/char/tpm/tpm_i2c_infineon.c1
-rw-r--r--drivers/char/tpm/tpm_i2c_stm_st33.c1
-rw-r--r--drivers/clk/at91/clk-master.c2
-rw-r--r--drivers/clk/clk-nomadik.c3
-rw-r--r--drivers/clk/clk.c13
-rw-r--r--drivers/clk/keystone/gate.c1
-rw-r--r--drivers/clk/mvebu/armada-370.c21
-rw-r--r--drivers/clk/mvebu/armada-xp.c20
-rw-r--r--drivers/clk/mvebu/dove.c19
-rw-r--r--drivers/clk/mvebu/kirkwood.c34
-rw-r--r--drivers/clk/shmobile/clk-rcar-gen2.c48
-rw-r--r--drivers/clk/tegra/clk-divider.c2
-rw-r--r--drivers/clk/tegra/clk-id.h4
-rw-r--r--drivers/clk/tegra/clk-tegra-periph.c10
-rw-r--r--drivers/clk/tegra/clk-tegra-super-gen4.c2
-rw-r--r--drivers/clk/tegra/clk-tegra114.c8
-rw-r--r--drivers/clk/tegra/clk-tegra124.c48
-rw-r--r--drivers/clk/tegra/clk-tegra20.c2
-rw-r--r--drivers/clocksource/Kconfig48
-rw-r--r--drivers/clocksource/Makefile3
-rw-r--r--drivers/clocksource/arm_arch_timer.c1
-rw-r--r--drivers/clocksource/cadence_ttc_timer.c121
-rw-r--r--drivers/clocksource/cyclone.c113
-rw-r--r--drivers/clocksource/exynos_mct.c2
-rw-r--r--drivers/clocksource/sun4i_timer.c2
-rw-r--r--drivers/clocksource/time-armada-370-xp.c12
-rw-r--r--drivers/clocksource/time-orion.c28
-rw-r--r--drivers/clocksource/timer-keystone.c241
-rw-r--r--drivers/clocksource/timer-u300.c (renamed from arch/arm/mach-u300/timer.c)4
-rw-r--r--drivers/clocksource/vf_pit_timer.c2
-rw-r--r--drivers/connector/cn_proc.c18
-rw-r--r--drivers/connector/connector.c20
-rw-r--r--drivers/cpufreq/Kconfig2
-rw-r--r--drivers/cpufreq/Kconfig.arm17
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c1
-rw-r--r--drivers/cpufreq/arm_big_little.c6
-rw-r--r--drivers/cpufreq/blackfin-cpufreq.c1
-rw-r--r--drivers/cpufreq/cpufreq-cpu0.c1
-rw-r--r--drivers/cpufreq/cpufreq-nforce2.c4
-rw-r--r--drivers/cpufreq/cpufreq.c553
-rw-r--r--drivers/cpufreq/cpufreq_stats.c40
-rw-r--r--drivers/cpufreq/cris-artpec3-cpufreq.c1
-rw-r--r--drivers/cpufreq/cris-etraxfs-cpufreq.c1
-rw-r--r--drivers/cpufreq/davinci-cpufreq.c1
-rw-r--r--drivers/cpufreq/e_powersaver.c1
-rw-r--r--drivers/cpufreq/elanfreq.c1
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c97
-rw-r--r--drivers/cpufreq/exynos5440-cpufreq.c5
-rw-r--r--drivers/cpufreq/freq_table.c46
-rw-r--r--drivers/cpufreq/gx-suspmod.c4
-rw-r--r--drivers/cpufreq/ia64-acpi-cpufreq.c1
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c1
-rw-r--r--drivers/cpufreq/integrator-cpufreq.c4
-rw-r--r--drivers/cpufreq/intel_pstate.c90
-rw-r--r--drivers/cpufreq/kirkwood-cpufreq.c1
-rw-r--r--drivers/cpufreq/longhaul.c5
-rw-r--r--drivers/cpufreq/loongson2_cpufreq.c1
-rw-r--r--drivers/cpufreq/omap-cpufreq.c1
-rw-r--r--drivers/cpufreq/p4-clockmod.c1
-rw-r--r--drivers/cpufreq/pasemi-cpufreq.c1
-rw-r--r--drivers/cpufreq/pcc-cpufreq.c4
-rw-r--r--drivers/cpufreq/powernow-k6.c5
-rw-r--r--drivers/cpufreq/powernow-k7.c6
-rw-r--r--drivers/cpufreq/powernow-k8.c16
-rw-r--r--drivers/cpufreq/ppc-corenet-cpufreq.c5
-rw-r--r--drivers/cpufreq/ppc_cbe_cpufreq.c1
-rw-r--r--drivers/cpufreq/pxa2xx-cpufreq.c1
-rw-r--r--drivers/cpufreq/pxa3xx-cpufreq.c1
-rw-r--r--drivers/cpufreq/s3c24xx-cpufreq.c4
-rw-r--r--drivers/cpufreq/s5pv210-cpufreq.c49
-rw-r--r--drivers/cpufreq/sc520_freq.c1
-rw-r--r--drivers/cpufreq/sh-cpufreq.c5
-rw-r--r--drivers/cpufreq/sparc-us2e-cpufreq.c4
-rw-r--r--drivers/cpufreq/sparc-us3-cpufreq.c4
-rw-r--r--drivers/cpufreq/spear-cpufreq.c14
-rw-r--r--drivers/cpufreq/speedstep-centrino.c2
-rw-r--r--drivers/cpufreq/speedstep-ich.c1
-rw-r--r--drivers/cpufreq/speedstep-smi.c1
-rw-r--r--drivers/cpufreq/tegra-cpufreq.c47
-rw-r--r--drivers/cpufreq/unicore2-cpufreq.c4
-rw-r--r--drivers/cpuidle/coupled.c2
-rw-r--r--drivers/cpuidle/cpuidle-powernv.c107
-rw-r--r--drivers/cpuidle/cpuidle-pseries.c6
-rw-r--r--drivers/cpuidle/cpuidle.c108
-rw-r--r--drivers/cpuidle/driver.c2
-rw-r--r--drivers/cpuidle/governors/menu.c75
-rw-r--r--drivers/devfreq/devfreq.c31
-rw-r--r--drivers/dma/imx-sdma.c1
-rw-r--r--drivers/dma/ioat/dma.c52
-rw-r--r--drivers/dma/ioat/dma.h1
-rw-r--r--drivers/dma/ioat/dma_v2.c11
-rw-r--r--drivers/dma/ioat/dma_v3.c3
-rw-r--r--drivers/dma/ste_dma40.c4
-rw-r--r--drivers/edac/amd64_edac.c38
-rw-r--r--drivers/edac/amd64_edac.h3
-rw-r--r--drivers/edac/amd8111_edac.c44
-rw-r--r--drivers/edac/e752x_edac.c30
-rw-r--r--drivers/edac/i3200_edac.c2
-rw-r--r--drivers/edac/i5100_edac.c17
-rw-r--r--drivers/edac/i5400_edac.c2
-rw-r--r--drivers/edac/i7300_edac.c38
-rw-r--r--drivers/edac/i7core_edac.c19
-rw-r--r--drivers/edac/i82875p_edac.c2
-rw-r--r--drivers/edac/mce_amd.c65
-rw-r--r--drivers/edac/mpc85xx_edac.c6
-rw-r--r--drivers/edac/octeon_edac-lmc.c179
-rw-r--r--drivers/edac/sb_edac.c2
-rw-r--r--drivers/extcon/Kconfig4
-rw-r--r--drivers/extcon/Makefile2
-rw-r--r--drivers/extcon/extcon-arizona.c12
-rw-r--r--drivers/extcon/extcon-class.c42
-rw-r--r--drivers/extcon/extcon-gpio.c4
-rw-r--r--drivers/extcon/extcon-palmas.c5
-rw-r--r--drivers/extcon/of_extcon.c64
-rw-r--r--drivers/firewire/core-device.c22
-rw-r--r--drivers/firewire/net.c6
-rw-r--r--drivers/firewire/ohci.c15
-rw-r--r--drivers/firewire/sbp2.c17
-rw-r--r--drivers/firmware/dcdbas.c2
-rw-r--r--drivers/firmware/efi/efi-stub-helper.c136
-rw-r--r--drivers/firmware/efi/efi.c5
-rw-r--r--drivers/firmware/efi/efivars.c2
-rw-r--r--drivers/firmware/google/gsmi.c7
-rw-r--r--drivers/firmware/google/memconsole.c47
-rw-r--r--drivers/fmc/fmc-core.c22
-rw-r--r--drivers/fmc/fmc-sdb.c41
-rw-r--r--drivers/fmc/fmc-write-eeprom.c2
-rw-r--r--drivers/gpio/gpio-vr41xx.c20
-rw-r--r--drivers/gpu/drm/armada/armada_drv.c10
-rw-r--r--drivers/gpu/drm/bochs/Kconfig1
-rw-r--r--drivers/gpu/drm/drm_cache.c10
-rw-r--r--drivers/gpu/drm/drm_fops.c3
-rw-r--r--drivers/gpu/drm/drm_ioctl.c12
-rw-r--r--drivers/gpu/drm/drm_pci.c2
-rw-r--r--drivers/gpu/drm/drm_prime.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dmabuf.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c10
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu.h1
-rw-r--r--drivers/gpu/drm/gma500/Kconfig1
-rw-r--r--drivers/gpu/drm/gma500/mmu.c2
-rw-r--r--drivers/gpu/drm/i2c/tda998x_drv.c4
-rw-r--r--drivers/gpu/drm/i915/Kconfig1
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c23
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gem_stolen.c26
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c71
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c1
-rw-r--r--drivers/gpu/drm/i915/intel_display.c22
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c31
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c6
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c4
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c6
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c21
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h1
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig3
-rw-r--r--drivers/gpu/drm/nouveau/Makefile1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv40.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv50.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/mc.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/base.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c45
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c26
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c17
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_vga.c4
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c31
-rw-r--r--drivers/gpu/drm/radeon/atombios_encoders.c9
-rw-r--r--drivers/gpu/drm/radeon/cik.c10
-rw-r--r--drivers/gpu/drm/radeon/cik_sdma.c14
-rw-r--r--drivers/gpu/drm/radeon/dce6_afmt.c15
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c7
-rw-r--r--drivers/gpu/drm/radeon/evergreen_hdmi.c26
-rw-r--r--drivers/gpu/drm/radeon/evergreen_smc.h2
-rw-r--r--drivers/gpu/drm/radeon/ni.c3
-rw-r--r--drivers/gpu/drm/radeon/ni_dpm.c2
-rw-r--r--drivers/gpu/drm/radeon/r100.c2
-rw-r--r--drivers/gpu/drm/radeon/r300.c2
-rw-r--r--drivers/gpu/drm/radeon/r420.c2
-rw-r--r--drivers/gpu/drm/radeon/r520.c2
-rw-r--r--drivers/gpu/drm/radeon/r600.c3
-rw-r--r--drivers/gpu/drm/radeon/r600_audio.c14
-rw-r--r--drivers/gpu/drm/radeon/r600_hdmi.c15
-rw-r--r--drivers/gpu/drm/radeon/radeon.h10
-rw-r--r--drivers/gpu/drm/radeon/radeon_atpx_handler.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c17
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_semaphore.c19
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_uvd.c2
-rw-r--r--drivers/gpu/drm/radeon/rs400.c2
-rw-r--r--drivers/gpu/drm/radeon/rs600.c2
-rw-r--r--drivers/gpu/drm/radeon/rs690.c2
-rw-r--r--drivers/gpu/drm/radeon/rv515.c2
-rw-r--r--drivers/gpu/drm/radeon/rv770.c5
-rw-r--r--drivers/gpu/drm/radeon/rv770_dpm.c9
-rw-r--r--drivers/gpu/drm/radeon/si.c3
-rw-r--r--drivers/gpu/drm/radeon/si_dpm.c2
-rw-r--r--drivers/gpu/drm/tegra/drm.c2
-rw-r--r--drivers/gpu/drm/tegra/rgb.c11
-rw-r--r--drivers/gpu/drm/ttm/ttm_agp_backend.c1
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c8
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c12
-rw-r--r--drivers/gpu/drm/udl/udl_gem.c11
-rw-r--r--drivers/gpu/drm/vmwgfx/svga3d_reg.h129
-rw-r--r--drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h11
-rw-r--r--drivers/gpu/drm/vmwgfx/svga_reg.h9
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_context.c9
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c9
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_mob.c35
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_shader.c16
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_surface.c18
-rw-r--r--drivers/gpu/host1x/job.c2
-rw-r--r--drivers/hid/hid-apple.c3
-rw-r--r--drivers/hid/hid-core.c4
-rw-r--r--drivers/hid/hid-hyperv.c11
-rw-r--r--drivers/hid/hid-ids.h11
-rw-r--r--drivers/hid/hid-input.c2
-rw-r--r--drivers/hid/hid-lg4ff.c2
-rw-r--r--drivers/hid/hid-microsoft.c4
-rw-r--r--drivers/hid/hid-multitouch.c5
-rw-r--r--drivers/hid/hid-prodikeys.c5
-rw-r--r--drivers/hid/hid-sensor-hub.c3
-rw-r--r--drivers/hid/hid-sony.c27
-rw-r--r--drivers/hid/hidraw.c4
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c2
-rw-r--r--drivers/hid/usbhid/hid-quirks.c1
-rw-r--r--drivers/hv/Makefile2
-rw-r--r--drivers/hv/channel.c42
-rw-r--r--drivers/hv/hv_balloon.c3
-rw-r--r--drivers/hv/hv_fcopy.c414
-rw-r--r--drivers/hv/hv_kvp.c4
-rw-r--r--drivers/hv/hv_snapshot.c2
-rw-r--r--drivers/hv/hv_util.c11
-rw-r--r--drivers/hv/hyperv_vmbus.h8
-rw-r--r--drivers/hv/ring_buffer.c17
-rw-r--r--drivers/hv/vmbus_drv.c108
-rw-r--r--drivers/hwmon/Kconfig608
-rw-r--r--drivers/hwmon/Makefile5
-rw-r--r--drivers/hwmon/adc128d818.c491
-rw-r--r--drivers/hwmon/coretemp.c71
-rw-r--r--drivers/hwmon/emc2103.c2
-rw-r--r--drivers/hwmon/hwmon.c5
-rw-r--r--drivers/hwmon/ibmpowernv.c529
-rw-r--r--drivers/hwmon/iio_hwmon.c37
-rw-r--r--drivers/hwmon/jz4740-hwmon.c25
-rw-r--r--drivers/hwmon/lm95241.c93
-rw-r--r--drivers/hwmon/lm95245.c112
-rw-r--r--drivers/hwmon/ltc2945.c519
-rw-r--r--drivers/hwmon/ltc4215.c51
-rw-r--r--drivers/hwmon/ltc4222.c237
-rw-r--r--drivers/hwmon/ltc4245.c30
-rw-r--r--drivers/hwmon/ltc4260.c200
-rw-r--r--drivers/hwmon/max1668.c81
-rw-r--r--drivers/hwmon/max6639.c91
-rw-r--r--drivers/hwmon/max6650.c257
-rw-r--r--drivers/hwmon/pmbus/ltc2978.c25
-rw-r--r--drivers/hwmon/smm665.c2
-rw-r--r--drivers/i2c/busses/Kconfig2
-rw-r--r--drivers/i2c/busses/i2c-cpm.c2
-rw-r--r--drivers/iio/accel/bma180.c4
-rw-r--r--drivers/iio/adc/Kconfig33
-rw-r--r--drivers/iio/adc/Makefile4
-rw-r--r--drivers/iio/adc/max1363.c16
-rw-r--r--drivers/iio/adc/men_z188_adc.c172
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c1
-rw-r--r--drivers/iio/adc/twl6030-gpadc.c1
-rw-r--r--drivers/iio/adc/vf610_adc.c711
-rw-r--r--drivers/iio/adc/viperboard_adc.c2
-rw-r--r--drivers/iio/adc/xilinx-xadc-core.c1333
-rw-r--r--drivers/iio/adc/xilinx-xadc-events.c254
-rw-r--r--drivers/iio/adc/xilinx-xadc.h209
-rw-r--r--drivers/iio/buffer_cb.c7
-rw-r--r--drivers/iio/dac/ad7303.c2
-rw-r--r--drivers/iio/dac/max517.c1
-rw-r--r--drivers/iio/dac/mcp4725.c1
-rw-r--r--drivers/iio/gyro/Kconfig2
-rw-r--r--drivers/iio/gyro/st_gyro.h1
-rw-r--r--drivers/iio/gyro/st_gyro_core.c9
-rw-r--r--drivers/iio/gyro/st_gyro_i2c.c1
-rw-r--r--drivers/iio/gyro/st_gyro_spi.c1
-rw-r--r--drivers/iio/humidity/Kconfig10
-rw-r--r--drivers/iio/humidity/Makefile1
-rw-r--r--drivers/iio/humidity/si7005.c189
-rw-r--r--drivers/iio/imu/Kconfig4
-rw-r--r--drivers/iio/imu/adis16400_core.c2
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c3
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h38
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c1
-rw-r--r--drivers/iio/industrialio-buffer.c16
-rw-r--r--drivers/iio/industrialio-core.c51
-rw-r--r--drivers/iio/industrialio-event.c100
-rw-r--r--drivers/iio/industrialio-trigger.c11
-rw-r--r--drivers/iio/light/Kconfig26
-rw-r--r--drivers/iio/light/Makefile2
-rw-r--r--drivers/iio/light/adjd_s311.c3
-rw-r--r--drivers/iio/light/cm32181.c16
-rw-r--r--drivers/iio/light/cm36651.c45
-rw-r--r--drivers/iio/light/hid-sensor-prox.c375
-rw-r--r--drivers/iio/light/ltr501.c445
-rw-r--r--drivers/iio/light/tcs3472.c2
-rw-r--r--drivers/iio/magnetometer/ak8975.c1
-rw-r--r--drivers/iio/magnetometer/mag3110.c17
-rw-r--r--drivers/iio/pressure/Kconfig16
-rw-r--r--drivers/iio/pressure/Makefile1
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c376
-rw-r--r--drivers/iio/pressure/mpl3115.c2
-rw-r--r--drivers/iio/pressure/st_pressure.h1
-rw-r--r--drivers/iio/pressure/st_pressure_core.c87
-rw-r--r--drivers/iio/pressure/st_pressure_i2c.c1
-rw-r--r--drivers/iio/pressure/st_pressure_spi.c1
-rw-r--r--drivers/infiniband/hw/mlx4/main.c4
-rw-r--r--drivers/infiniband/hw/mlx5/main.c4
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c180
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.h7
-rw-r--r--drivers/input/evdev.c4
-rw-r--r--drivers/input/keyboard/adp5588-keys.c12
-rw-r--r--drivers/input/misc/arizona-haptics.c19
-rw-r--r--drivers/input/misc/da9052_onkey.c29
-rw-r--r--drivers/input/mouse/cypress_ps2.c1
-rw-r--r--drivers/input/mouse/synaptics.c55
-rw-r--r--drivers/input/mousedev.c73
-rw-r--r--drivers/input/touchscreen/st1232.c3
-rw-r--r--drivers/iommu/amd_iommu_types.h1
-rw-r--r--drivers/iommu/arm-smmu.c105
-rw-r--r--drivers/iommu/omap-iommu-debug.c4
-rw-r--r--drivers/iommu/shmobile-iommu.c2
-rw-r--r--drivers/irqchip/Makefile1
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c98
-rw-r--r--drivers/irqchip/irq-bcm2835.c4
-rw-r--r--drivers/irqchip/irq-gic.c11
-rw-r--r--drivers/irqchip/irq-metag-ext.c2
-rw-r--r--drivers/irqchip/irq-metag.c2
-rw-r--r--drivers/irqchip/irq-mmp.c6
-rw-r--r--drivers/irqchip/irq-moxart.c2
-rw-r--r--drivers/irqchip/irq-orion.c24
-rw-r--r--drivers/irqchip/irq-sirfsoc.c2
-rw-r--r--drivers/irqchip/irq-sun4i.c42
-rw-r--r--drivers/irqchip/irq-sunxi-nmi.c208
-rw-r--r--drivers/irqchip/irq-vic.c2
-rw-r--r--drivers/irqchip/irq-vt8500.c3
-rw-r--r--drivers/irqchip/irq-xtensa-mx.c2
-rw-r--r--drivers/irqchip/irq-zevio.c2
-rw-r--r--drivers/irqchip/irqchip.c3
-rw-r--r--drivers/isdn/capi/Kconfig18
-rw-r--r--drivers/macintosh/adb.c57
-rw-r--r--drivers/mcb/Kconfig31
-rw-r--r--drivers/mcb/Makefile7
-rw-r--r--drivers/mcb/mcb-core.c414
-rw-r--r--drivers/mcb/mcb-internal.h118
-rw-r--r--drivers/mcb/mcb-parse.c159
-rw-r--r--drivers/mcb/mcb-pci.c114
-rw-r--r--drivers/md/Kconfig10
-rw-r--r--drivers/md/bcache/Kconfig8
-rw-r--r--drivers/md/bcache/alloc.c173
-rw-r--r--drivers/md/bcache/bcache.h56
-rw-r--r--drivers/md/bcache/bset.c4
-rw-r--r--drivers/md/bcache/bset.h6
-rw-r--r--drivers/md/bcache/btree.c592
-rw-r--r--drivers/md/bcache/btree.h12
-rw-r--r--drivers/md/bcache/extents.c36
-rw-r--r--drivers/md/bcache/journal.c46
-rw-r--r--drivers/md/bcache/journal.h1
-rw-r--r--drivers/md/bcache/movinggc.c18
-rw-r--r--drivers/md/bcache/request.c201
-rw-r--r--drivers/md/bcache/request.h19
-rw-r--r--drivers/md/bcache/stats.c3
-rw-r--r--drivers/md/bcache/super.c64
-rw-r--r--drivers/md/bcache/sysfs.c155
-rw-r--r--drivers/md/bcache/trace.c2
-rw-r--r--drivers/md/dm-cache-policy-mq.c4
-rw-r--r--drivers/md/dm-cache-target.c24
-rw-r--r--drivers/md/dm-io.c23
-rw-r--r--drivers/md/dm-log-userspace-transfer.c2
-rw-r--r--drivers/md/dm-mpath.c7
-rw-r--r--drivers/md/dm-raid1.c3
-rw-r--r--drivers/md/dm-snap-persistent.c3
-rw-r--r--drivers/md/dm-thin-metadata.c58
-rw-r--r--drivers/md/dm-thin-metadata.h21
-rw-r--r--drivers/md/dm-thin.c343
-rw-r--r--drivers/md/persistent-data/Kconfig10
-rw-r--r--drivers/md/persistent-data/dm-space-map-metadata.c115
-rw-r--r--drivers/md/persistent-data/dm-space-map-metadata.h11
-rw-r--r--drivers/media/i2c/adv7343.c4
-rw-r--r--drivers/media/i2c/mt9p031.c4
-rw-r--r--drivers/media/i2c/s5k5baf.c3
-rw-r--r--drivers/media/i2c/tvp514x.c3
-rw-r--r--drivers/media/i2c/tvp7002.c3
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-main.c9
-rw-r--r--drivers/media/pci/cx23885/cx23885-alsa.c5
-rw-r--r--drivers/media/pci/cx25821/cx25821-alsa.c7
-rw-r--r--drivers/media/pci/cx88/cx88-alsa.c6
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-main.c9
-rw-r--r--drivers/media/pci/saa7134/saa7134-alsa.c6
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.c6
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c13
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c5
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-audio.c5
-rw-r--r--drivers/media/usb/em28xx/em28xx-audio.c5
-rw-r--r--drivers/media/usb/stk1160/stk1160-ac97.c6
-rw-r--r--drivers/media/usb/tlg2300/pd-alsa.c3
-rw-r--r--drivers/media/usb/tm6000/tm6000-alsa.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c2
-rw-r--r--drivers/media/v4l2-core/v4l2-of.c133
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-contig.c2
-rw-r--r--drivers/memory/Kconfig15
-rw-r--r--drivers/memory/Makefile2
-rw-r--r--drivers/memory/fsl_ifc.c (renamed from arch/powerpc/sysdev/fsl_ifc.c)8
-rw-r--r--drivers/memory/ti-aemif.c427
-rw-r--r--drivers/message/i2o/iop.c85
-rw-r--r--drivers/mfd/arizona-core.c4
-rw-r--r--drivers/mfd/da9055-i2c.c12
-rw-r--r--drivers/mfd/max14577.c2
-rw-r--r--drivers/mfd/max8997.c6
-rw-r--r--drivers/mfd/max8998.c6
-rw-r--r--drivers/mfd/sec-core.c114
-rw-r--r--drivers/mfd/sec-irq.c97
-rw-r--r--drivers/mfd/tps65217.c4
-rw-r--r--drivers/mfd/wm5102-tables.c21
-rw-r--r--drivers/mfd/wm8994-core.c2
-rw-r--r--drivers/misc/Kconfig3
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/ad525x_dpot.c1
-rw-r--r--drivers/misc/apds9802als.c1
-rw-r--r--drivers/misc/atmel-ssc.c6
-rw-r--r--drivers/misc/bmp085.c1
-rw-r--r--drivers/misc/carma/carma-fpga.c1
-rw-r--r--drivers/misc/ds1682.c1
-rw-r--r--drivers/misc/echo/Kconfig (renamed from drivers/staging/echo/Kconfig)0
-rw-r--r--drivers/misc/echo/Makefile (renamed from drivers/staging/echo/Makefile)0
-rw-r--r--drivers/misc/echo/echo.c (renamed from drivers/staging/echo/echo.c)0
-rw-r--r--drivers/misc/echo/echo.h (renamed from drivers/staging/echo/echo.h)0
-rw-r--r--drivers/misc/echo/fir.h (renamed from drivers/staging/echo/fir.h)0
-rw-r--r--drivers/misc/echo/oslec.h (renamed from drivers/staging/echo/oslec.h)0
-rw-r--r--drivers/misc/eeprom/at25.c1
-rw-r--r--drivers/misc/eeprom/eeprom.c1
-rw-r--r--drivers/misc/eeprom/eeprom_93xx46.c1
-rw-r--r--drivers/misc/eeprom/max6875.c1
-rw-r--r--drivers/misc/eeprom/sunxi_sid.c3
-rw-r--r--drivers/misc/genwqe/card_debugfs.c1
-rw-r--r--drivers/misc/hmc6352.c1
-rw-r--r--drivers/misc/isl29003.c1
-rw-r--r--drivers/misc/isl29020.c1
-rw-r--r--drivers/misc/lattice-ecp3-config.c1
-rw-r--r--drivers/misc/lis3lv02d/lis3lv02d.c1
-rw-r--r--drivers/misc/lis3lv02d/lis3lv02d_i2c.c1
-rw-r--r--drivers/misc/lis3lv02d/lis3lv02d_spi.c1
-rw-r--r--drivers/misc/lkdtm.c74
-rw-r--r--drivers/misc/mei/Kconfig9
-rw-r--r--drivers/misc/mei/Makefile6
-rw-r--r--drivers/misc/mei/amthif.c72
-rw-r--r--drivers/misc/mei/bus.c21
-rw-r--r--drivers/misc/mei/client.c304
-rw-r--r--drivers/misc/mei/client.h30
-rw-r--r--drivers/misc/mei/debugfs.c54
-rw-r--r--drivers/misc/mei/hbm.c281
-rw-r--r--drivers/misc/mei/hbm.h1
-rw-r--r--drivers/misc/mei/hw-me.c30
-rw-r--r--drivers/misc/mei/hw-me.h1
-rw-r--r--drivers/misc/mei/hw-txe-regs.h294
-rw-r--r--drivers/misc/mei/hw-txe.c1107
-rw-r--r--drivers/misc/mei/hw-txe.h74
-rw-r--r--drivers/misc/mei/hw.h20
-rw-r--r--drivers/misc/mei/init.c43
-rw-r--r--drivers/misc/mei/interrupt.c159
-rw-r--r--drivers/misc/mei/main.c23
-rw-r--r--drivers/misc/mei/mei_dev.h54
-rw-r--r--drivers/misc/mei/nfc.c14
-rw-r--r--drivers/misc/mei/pci-me.c14
-rw-r--r--drivers/misc/mei/pci-txe.c293
-rw-r--r--drivers/misc/mei/wd.c136
-rw-r--r--drivers/misc/mic/card/mic_device.h1
-rw-r--r--drivers/misc/mic/host/mic_device.h1
-rw-r--r--drivers/misc/mic/host/mic_intr.c2
-rw-r--r--drivers/misc/pch_phub.c5
-rw-r--r--drivers/misc/sgi-xp/xpc_uv.c2
-rw-r--r--drivers/misc/sram.c127
-rw-r--r--drivers/misc/ti-st/st_core.c1
-rw-r--r--drivers/misc/ti_dac7512.c1
-rw-r--r--drivers/misc/tsl2550.c1
-rw-r--r--drivers/misc/vmw_vmci/vmci_guest.c7
-rw-r--r--drivers/mmc/card/queue.c2
-rw-r--r--drivers/mmc/host/dw_mmc.c2
-rw-r--r--drivers/mtd/nand/Kconfig1
-rw-r--r--drivers/mtd/nand/fsl_ifc_nand.c2
-rw-r--r--drivers/mtd/nand/nand_base.c2
-rw-r--r--drivers/mtd/nand/omap2.c61
-rw-r--r--drivers/mtd/nand/sh_flctl.c2
-rw-r--r--drivers/mtd/ubi/fastmap.c8
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/bonding/bond_3ad.c22
-rw-r--r--drivers/net/bonding/bond_3ad.h1
-rw-r--r--drivers/net/bonding/bond_alb.c2
-rw-r--r--drivers/net/bonding/bond_main.c133
-rw-r--r--drivers/net/bonding/bond_options.c3
-rw-r--r--drivers/net/bonding/bonding.h47
-rw-r--r--drivers/net/can/flexcan.c172
-rw-r--r--drivers/net/can/usb/kvaser_usb.c2
-rw-r--r--drivers/net/ethernet/atheros/alx/main.c14
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_main.c4
-rw-r--r--drivers/net/ethernet/broadcom/b44.c14
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c37
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.h5
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c13
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h2
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c111
-rw-r--r--drivers/net/ethernet/broadcom/cnic.h2
-rw-r--r--drivers/net/ethernet/broadcom/cnic_defs.h2
-rw-r--r--drivers/net/ethernet/broadcom/cnic_if.h16
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c8
-rw-r--r--drivers/net/ethernet/broadcom/tg3.h6
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.c2
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c40
-rw-r--r--drivers/net/ethernet/cadence/macb.c16
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c1
-rw-r--r--drivers/net/ethernet/dec/tulip/tulip_core.c1
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h4
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c84
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c31
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c25
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c6
-rw-r--r--drivers/net/ethernet/lantiq_etop.c2
-rw-r--r--drivers/net/ethernet/marvell/Kconfig6
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c60
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.c11
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c20
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c4
-rw-r--r--drivers/net/ethernet/micrel/ks8851.c30
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c5
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c9
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_main.c4
-rw-r--r--drivers/net/ethernet/realtek/r8169.c4
-rw-r--r--drivers/net/ethernet/sfc/ptp.c7
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/chain_mode.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h20
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c330
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/ring_mode.c9
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c93
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c5
-rw-r--r--drivers/net/ethernet/ti/cpsw.c21
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.c4
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c53
-rw-r--r--drivers/net/ethernet/tile/tilegx.c2
-rw-r--r--drivers/net/ethernet/via/via-rhine.c8
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c13
-rw-r--r--drivers/net/hyperv/netvsc_drv.c53
-rw-r--r--drivers/net/hyperv/rndis_filter.c21
-rw-r--r--drivers/net/ieee802154/at86rf230.c11
-rw-r--r--drivers/net/ifb.c3
-rw-r--r--drivers/net/irda/irtty-sir.c1
-rw-r--r--drivers/net/macvlan.c12
-rw-r--r--drivers/net/phy/dp83640.c13
-rw-r--r--drivers/net/phy/phy.c11
-rw-r--r--drivers/net/phy/phy_device.c19
-rw-r--r--drivers/net/team/team.c2
-rw-r--r--drivers/net/tun.c6
-rw-r--r--drivers/net/usb/Kconfig1
-rw-r--r--drivers/net/usb/Makefile2
-rw-r--r--drivers/net/usb/asix_devices.c3
-rw-r--r--drivers/net/usb/ax88179_178a.c46
-rw-r--r--drivers/net/usb/cdc_ether.c7
-rw-r--r--drivers/net/usb/cdc_ncm.c48
-rw-r--r--drivers/net/usb/gl620a.c4
-rw-r--r--drivers/net/usb/mcs7830.c5
-rw-r--r--drivers/net/usb/net1080.c4
-rw-r--r--drivers/net/usb/qmi_wwan.c9
-rw-r--r--drivers/net/usb/r8152.c15
-rw-r--r--drivers/net/usb/r815x.c248
-rw-r--r--drivers/net/usb/rndis_host.c4
-rw-r--r--drivers/net/usb/smsc75xx.c4
-rw-r--r--drivers/net/usb/smsc95xx.c4
-rw-r--r--drivers/net/usb/sr9800.c6
-rw-r--r--drivers/net/usb/usbnet.c58
-rw-r--r--drivers/net/veth.c6
-rw-r--r--drivers/net/virtio_net.c11
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c19
-rw-r--r--drivers/net/vxlan.c130
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c7
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c70
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c15
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c18
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_proc.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c22
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/sta.c1
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tx.c14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-modparams.h11
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/bt-coex.c7
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c22
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c18
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c5
-rw-r--r--drivers/net/wireless/libertas/cfg.c2
-rw-r--r--drivers/net/wireless/mwifiex/11ac.c3
-rw-r--r--drivers/net/wireless/mwifiex/11n.c3
-rw-r--r--drivers/net/wireless/mwifiex/main.c2
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c34
-rw-r--r--drivers/net/wireless/mwifiex/scan.c8
-rw-r--r--drivers/net/wireless/mwifiex/usb.c12
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c3
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/rtl8187.h10
-rw-r--r--drivers/net/wireless/rtlwifi/ps.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/hw.c18
-rw-r--r--drivers/net/wireless/ti/wl1251/rx.c2
-rw-r--r--drivers/net/xen-netback/interface.c3
-rw-r--r--drivers/net/xen-netback/netback.c39
-rw-r--r--drivers/net/xen-netfront.c1
-rw-r--r--drivers/of/Kconfig18
-rw-r--r--drivers/of/Makefile1
-rw-r--r--drivers/of/address.c8
-rw-r--r--drivers/of/base.c607
-rw-r--r--drivers/of/fdt.c145
-rw-r--r--drivers/of/of_mdio.c22
-rw-r--r--drivers/of/of_net.c11
-rw-r--r--drivers/of/of_reserved_mem.c217
-rw-r--r--drivers/of/pdt.c3
-rw-r--r--drivers/of/selftest.c129
-rw-r--r--drivers/of/testcase-data/testcases.dtsi3
-rw-r--r--drivers/of/testcase-data/tests-interrupts.dtsi (renamed from arch/arm/boot/dts/testcases/tests-interrupts.dtsi)0
-rw-r--r--drivers/of/testcase-data/tests-match.dtsi19
-rw-r--r--drivers/of/testcase-data/tests-phandle.dtsi (renamed from arch/arm/boot/dts/testcases/tests-phandle.dtsi)3
-rw-r--r--drivers/parport/share.c3
-rw-r--r--drivers/pci/Makefile23
-rw-r--r--drivers/pci/bus.c8
-rw-r--r--drivers/pci/host-bridge.c8
-rw-r--r--drivers/pci/host/Kconfig2
-rw-r--r--drivers/pci/host/pci-imx6.c47
-rw-r--r--drivers/pci/host/pci-mvebu.c37
-rw-r--r--drivers/pci/host/pci-rcar-gen2.c180
-rw-r--r--drivers/pci/host/pcie-designware.c6
-rw-r--r--drivers/pci/hotplug/acpiphp.h16
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c529
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c4
-rw-r--r--drivers/pci/hotplug/pciehp.h5
-rw-r--r--drivers/pci/hotplug/pciehp_acpi.c1
-rw-r--r--drivers/pci/hotplug/pciehp_core.c8
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c173
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c75
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c2
-rw-r--r--drivers/pci/iov.c119
-rw-r--r--drivers/pci/msi.c10
-rw-r--r--drivers/pci/pci-driver.c33
-rw-r--r--drivers/pci/pci-sysfs.c17
-rw-r--r--drivers/pci/pci.c131
-rw-r--r--drivers/pci/pci.h4
-rw-r--r--drivers/pci/probe.c93
-rw-r--r--drivers/pci/quirks.c190
-rw-r--r--drivers/pci/rom.c2
-rw-r--r--drivers/pci/search.c10
-rw-r--r--drivers/pci/setup-res.c37
-rw-r--r--drivers/pcmcia/sa11xx_base.c3
-rw-r--r--drivers/pcmcia/yenta_socket.c18
-rw-r--r--drivers/phy/Kconfig110
-rw-r--r--drivers/phy/Makefile9
-rw-r--r--drivers/phy/phy-bcm-kona-usb2.c4
-rw-r--r--drivers/phy/phy-core.c90
-rw-r--r--drivers/phy/phy-exynos-dp-video.c8
-rw-r--r--drivers/phy/phy-exynos-mipi-video.c10
-rw-r--r--drivers/phy/phy-exynos4210-usb2.c261
-rw-r--r--drivers/phy/phy-exynos4x12-usb2.c328
-rw-r--r--drivers/phy/phy-exynos5250-sata.c251
-rw-r--r--drivers/phy/phy-exynos5250-usb2.c404
-rw-r--r--drivers/phy/phy-mvebu-sata.c10
-rw-r--r--drivers/phy/phy-omap-control.c (renamed from drivers/usb/phy/phy-omap-control.c)169
-rw-r--r--drivers/phy/phy-omap-usb2.c139
-rw-r--r--drivers/phy/phy-samsung-usb2.c228
-rw-r--r--drivers/phy/phy-samsung-usb2.h67
-rw-r--r--drivers/phy/phy-sun4i-usb.c331
-rw-r--r--drivers/phy/phy-ti-pipe3.c470
-rw-r--r--drivers/phy/phy-twl4030-usb.c16
-rw-r--r--drivers/phy/phy-xgene.c1750
-rw-r--r--drivers/pinctrl/Kconfig4
-rw-r--r--drivers/pinctrl/devicetree.c4
-rw-r--r--drivers/pinctrl/mvebu/Kconfig9
-rw-r--r--drivers/pinctrl/mvebu/Makefile2
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-370.c20
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-375.c459
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-38x.c462
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-xp.c24
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-dove.c404
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-kirkwood.c25
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.c122
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.h55
-rw-r--r--drivers/pinctrl/pinctrl-adi2-bf54x.c138
-rw-r--r--drivers/pinctrl/pinctrl-adi2-bf60x.c128
-rw-r--r--drivers/pinctrl/pinctrl-adi2.c31
-rw-r--r--drivers/pinctrl/pinctrl-adi2.h8
-rw-r--r--drivers/pinctrl/pinctrl-at91.c39
-rw-r--r--drivers/pinctrl/pinctrl-baytrail.c42
-rw-r--r--drivers/pinctrl/pinctrl-capri.c2
-rw-r--r--drivers/pinctrl/pinctrl-exynos.c82
-rw-r--r--drivers/pinctrl/pinctrl-imx.c2
-rw-r--r--drivers/pinctrl/pinctrl-msm.c113
-rw-r--r--drivers/pinctrl/pinctrl-msm.h5
-rw-r--r--drivers/pinctrl/pinctrl-msm8x74.c14
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.c19
-rw-r--r--drivers/pinctrl/pinctrl-samsung.c2
-rw-r--r--drivers/pinctrl/pinctrl-samsung.h1
-rw-r--r--drivers/pinctrl/pinctrl-single.c3
-rw-r--r--drivers/pinctrl/pinctrl-st.c462
-rw-r--r--drivers/pinctrl/pinctrl-sunxi-pins.h12
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.c6
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.h6
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c38
-rw-r--r--drivers/pinctrl/pinctrl-tegra.h4
-rw-r--r--drivers/pinctrl/pinctrl-tegra114.c1100
-rw-r--r--drivers/pinctrl/pinctrl-tegra124.c1243
-rw-r--r--drivers/pinctrl/pinctrl-tegra20.c640
-rw-r--r--drivers/pinctrl/pinctrl-tegra30.c1287
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7790.c171
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7791.c602
-rw-r--r--drivers/pinctrl/sirf/pinctrl-atlas6.c46
-rw-r--r--drivers/pinctrl/sirf/pinctrl-prima2.c3
-rw-r--r--drivers/pinctrl/sirf/pinctrl-sirf.c7
-rw-r--r--drivers/platform/x86/Kconfig2
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c1
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c6
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c15
-rw-r--r--drivers/pnp/pnpbios/bioscalls.c9
-rw-r--r--drivers/pnp/resource.c2
-rw-r--r--drivers/powercap/intel_rapl.c17
-rw-r--r--drivers/ps3/ps3-vuart.c4
-rw-r--r--drivers/pwm/pwm-lp3943.c4
-rw-r--r--drivers/rapidio/devices/tsi721.h1
-rw-r--r--drivers/rapidio/devices/tsi721_dma.c27
-rw-r--r--drivers/regulator/88pm800.c4
-rw-r--r--drivers/regulator/88pm8607.c8
-rw-r--r--drivers/regulator/Kconfig45
-rw-r--r--drivers/regulator/Makefile4
-rw-r--r--drivers/regulator/aat2870-regulator.c1
-rw-r--r--drivers/regulator/act8865-regulator.c21
-rw-r--r--drivers/regulator/anatop-regulator.c124
-rw-r--r--drivers/regulator/arizona-ldo1.c11
-rw-r--r--drivers/regulator/arizona-micsupp.c4
-rw-r--r--drivers/regulator/as3711-regulator.c15
-rw-r--r--drivers/regulator/as3722-regulator.c1
-rw-r--r--drivers/regulator/bcm590xx-regulator.c403
-rw-r--r--drivers/regulator/core.c64
-rw-r--r--drivers/regulator/da9052-regulator.c29
-rw-r--r--drivers/regulator/da9055-regulator.c69
-rw-r--r--drivers/regulator/da9063-regulator.c17
-rw-r--r--drivers/regulator/da9210-regulator.c5
-rw-r--r--drivers/regulator/db8500-prcmu.c2
-rw-r--r--drivers/regulator/dbx500-prcmu.c16
-rw-r--r--drivers/regulator/dummy.c6
-rw-r--r--drivers/regulator/fan53555.c13
-rw-r--r--drivers/regulator/fixed.c46
-rw-r--r--drivers/regulator/gpio-regulator.c34
-rw-r--r--drivers/regulator/helpers.c48
-rw-r--r--drivers/regulator/lp3971.c2
-rw-r--r--drivers/regulator/lp872x.c4
-rw-r--r--drivers/regulator/max14577.c13
-rw-r--r--drivers/regulator/max1586.c15
-rw-r--r--drivers/regulator/max77686.c15
-rw-r--r--drivers/regulator/max77693.c44
-rw-r--r--drivers/regulator/max8649.c8
-rw-r--r--drivers/regulator/max8660.c35
-rw-r--r--drivers/regulator/max8907-regulator.c16
-rw-r--r--drivers/regulator/max8925-regulator.c8
-rw-r--r--drivers/regulator/max8952.c26
-rw-r--r--drivers/regulator/max8973-regulator.c6
-rw-r--r--drivers/regulator/max8997.c22
-rw-r--r--drivers/regulator/max8998.c27
-rw-r--r--drivers/regulator/mc13xxx-regulator-core.c12
-rw-r--r--drivers/regulator/pfuze100-regulator.c204
-rw-r--r--drivers/regulator/rc5t583-regulator.c13
-rw-r--r--drivers/regulator/s2mpa01.c481
-rw-r--r--drivers/regulator/s2mps11.c364
-rw-r--r--drivers/regulator/s5m8767.c175
-rw-r--r--drivers/regulator/st-pwm.c190
-rw-r--r--drivers/regulator/ti-abb-regulator.c140
-rw-r--r--drivers/regulator/tps51632-regulator.c8
-rw-r--r--drivers/regulator/tps62360-regulator.c9
-rw-r--r--drivers/regulator/tps6507x-regulator.c29
-rw-r--r--drivers/regulator/tps65090-regulator.c13
-rw-r--r--drivers/regulator/tps65217-regulator.c17
-rw-r--r--drivers/regulator/tps65218-regulator.c285
-rw-r--r--drivers/regulator/tps6524x-regulator.c5
-rw-r--r--drivers/regulator/tps6586x-regulator.c20
-rw-r--r--drivers/regulator/tps65910-regulator.c21
-rw-r--r--drivers/regulator/tps80031-regulator.c6
-rw-r--r--drivers/regulator/wm831x-dcdc.c16
-rw-r--r--drivers/regulator/wm831x-isink.c4
-rw-r--r--drivers/regulator/wm831x-ldo.c12
-rw-r--r--drivers/regulator/wm8350-regulator.c4
-rw-r--r--drivers/regulator/wm8994-regulator.c4
-rw-r--r--drivers/rtc/rtc-s3c.c17
-rw-r--r--drivers/s390/block/dcssblk.c14
-rw-r--r--drivers/s390/char/con3215.c8
-rw-r--r--drivers/s390/char/con3270.c13
-rw-r--r--drivers/s390/char/raw3270.c26
-rw-r--r--drivers/s390/char/raw3270.h3
-rw-r--r--drivers/s390/char/sclp_early.c31
-rw-r--r--drivers/s390/cio/airq.c66
-rw-r--r--drivers/s390/cio/ccwgroup.c26
-rw-r--r--drivers/s390/cio/chsc.c1
-rw-r--r--drivers/s390/cio/chsc_sch.c3
-rw-r--r--drivers/s390/cio/cio.c12
-rw-r--r--drivers/s390/cio/device.c52
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.c24
-rw-r--r--drivers/s390/kvm/virtio_ccw.c323
-rw-r--r--drivers/s390/net/qeth_core_main.c9
-rw-r--r--drivers/s390/net/qeth_l2_main.c3
-rw-r--r--drivers/s390/net/qeth_l3_main.c3
-rw-r--r--drivers/sbus/char/jsflash.c1
-rw-r--r--drivers/scsi/NCR5380.c2
-rw-r--r--drivers/scsi/aacraid/aacraid.h2
-rw-r--r--drivers/scsi/aacraid/rx.c9
-rw-r--r--drivers/scsi/aacraid/sa.c3
-rw-r--r--drivers/scsi/aacraid/src.c4
-rw-r--r--drivers/scsi/aha152x.c4
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h1
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c7
-rw-r--r--drivers/scsi/arm/acornscsi.c2
-rw-r--r--drivers/scsi/arm/cumana_1.c2
-rw-r--r--drivers/scsi/arm/cumana_2.c2
-rw-r--r--drivers/scsi/arm/powertec.c2
-rw-r--r--drivers/scsi/atari_scsi.c12
-rw-r--r--drivers/scsi/be2iscsi/be.h11
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c121
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h10
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c13
-rw-r--r--drivers/scsi/be2iscsi/be_main.c313
-rw-r--r--drivers/scsi/be2iscsi/be_main.h23
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c22
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c11
-rw-r--r--drivers/scsi/bfa/bfad_bsg.c4
-rw-r--r--drivers/scsi/bfa/bfad_im.c7
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc.h3
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c8
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c35
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_tgt.c39
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c98
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c31
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c59
-rw-r--r--drivers/scsi/dtc.c2
-rw-r--r--drivers/scsi/eata.c2
-rw-r--r--drivers/scsi/eata_pio.c4
-rw-r--r--drivers/scsi/esas2r/esas2r_init.c2
-rw-r--r--drivers/scsi/esas2r/esas2r_log.c8
-rw-r--r--drivers/scsi/g_NCR5380.c2
-rw-r--r--drivers/scsi/gdth.c6
-rw-r--r--drivers/scsi/hosts.c2
-rw-r--r--drivers/scsi/hpsa.c2618
-rw-r--r--drivers/scsi/hpsa.h171
-rw-r--r--drivers/scsi/hpsa_cmd.h270
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c2
-rw-r--r--drivers/scsi/in2000.c2
-rw-r--r--drivers/scsi/initio.c2
-rw-r--r--drivers/scsi/ipr.c382
-rw-r--r--drivers/scsi/ipr.h22
-rw-r--r--drivers/scsi/isci/host.h5
-rw-r--r--drivers/scsi/isci/init.c2
-rw-r--r--drivers/scsi/isci/port_config.c7
-rw-r--r--drivers/scsi/isci/request.c8
-rw-r--r--drivers/scsi/isci/task.c2
-rw-r--r--drivers/scsi/iscsi_boot_sysfs.c1
-rw-r--r--drivers/scsi/iscsi_tcp.c25
-rw-r--r--drivers/scsi/libiscsi.c232
-rw-r--r--drivers/scsi/libiscsi_tcp.c71
-rw-r--r--drivers/scsi/libsas/sas_ata.c35
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c2
-rw-r--r--drivers/scsi/lpfc/lpfc.h22
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c628
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c3
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h24
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c108
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c200
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c39
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c277
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c47
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c56
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c552
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.h18
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c267
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h21
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/megaraid.c120
-rw-r--r--drivers/scsi/megaraid.h3
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h114
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c815
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c11
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c272
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h3
-rw-r--r--drivers/scsi/pas16.c2
-rw-r--r--drivers/scsi/pm8001/pm8001_ctl.c38
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c105
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c12
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c3
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h12
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c97
-rw-r--r--drivers/scsi/qla1280.c7
-rw-r--r--drivers/scsi/qla2xxx/Makefile2
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c193
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c12
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c134
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h7
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h68
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h12
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c11
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c426
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c44
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c139
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c50
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.c252
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.h57
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c21
-rw-r--r--drivers/scsi/qla2xxx/qla_nx2.c22
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c171
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c65
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c42
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_tmpl.c909
-rw-r--r--drivers/scsi/qla2xxx/qla_tmpl.h205
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h4
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c158
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.h7
-rw-r--r--drivers/scsi/qla4xxx/ql4_83xx.c36
-rw-r--r--drivers/scsi/qla4xxx/ql4_bsg.c4
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h17
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h31
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c7
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c69
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c25
-rw-r--r--drivers/scsi/qla4xxx/ql4_nx.c89
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c232
-rw-r--r--drivers/scsi/qla4xxx/ql4_version.h2
-rw-r--r--drivers/scsi/scsi.c373
-rw-r--r--drivers/scsi/scsi_debug.c141
-rw-r--r--drivers/scsi/scsi_error.c6
-rw-r--r--drivers/scsi/scsi_lib.c114
-rw-r--r--drivers/scsi/scsi_scan.c115
-rw-r--r--drivers/scsi/scsi_sysfs.c257
-rw-r--r--drivers/scsi/scsi_tgt_lib.c3
-rw-r--r--drivers/scsi/scsi_transport_fc.c1
-rw-r--r--drivers/scsi/sd.c42
-rw-r--r--drivers/scsi/sd.h6
-rw-r--r--drivers/scsi/ses.c38
-rw-r--r--drivers/scsi/st.c11
-rw-r--r--drivers/scsi/storvsc_drv.c3
-rw-r--r--drivers/scsi/t128.c2
-rw-r--r--drivers/scsi/u14-34f.c2
-rw-r--r--drivers/scsi/vmw_pvscsi.c242
-rw-r--r--drivers/scsi/vmw_pvscsi.h19
-rw-r--r--drivers/scsi/wd7000.c2
-rw-r--r--drivers/spi/Kconfig55
-rw-r--r--drivers/spi/Makefile5
-rw-r--r--drivers/spi/spi-altera.c7
-rw-r--r--drivers/spi/spi-ath79.c5
-rw-r--r--drivers/spi/spi-atmel.c51
-rw-r--r--drivers/spi/spi-au1550.c39
-rw-r--r--drivers/spi/spi-bcm2835.c1
-rw-r--r--drivers/spi/spi-bcm63xx-hsspi.c8
-rw-r--r--drivers/spi/spi-bcm63xx.c6
-rw-r--r--drivers/spi/spi-bfin-sport.c1
-rw-r--r--drivers/spi/spi-bfin-v3.c3
-rw-r--r--drivers/spi/spi-bfin5xx.c8
-rw-r--r--drivers/spi/spi-bitbang.c5
-rw-r--r--drivers/spi/spi-butterfly.c3
-rw-r--r--drivers/spi/spi-clps711x.c227
-rw-r--r--drivers/spi/spi-coldfire-qspi.c118
-rw-r--r--drivers/spi/spi-davinci.c14
-rw-r--r--drivers/spi/spi-dw-mmio.c2
-rw-r--r--drivers/spi/spi-dw.c17
-rw-r--r--drivers/spi/spi-efm32.c46
-rw-r--r--drivers/spi/spi-ep93xx.c21
-rw-r--r--drivers/spi/spi-falcon.c5
-rw-r--r--drivers/spi/spi-fsl-dspi.c100
-rw-r--r--drivers/spi/spi-fsl-espi.c5
-rw-r--r--drivers/spi/spi-fsl-lib.c14
-rw-r--r--drivers/spi/spi-fsl-spi.c30
-rw-r--r--drivers/spi/spi-gpio.c8
-rw-r--r--drivers/spi/spi-imx.c11
-rw-r--r--drivers/spi/spi-mpc512x-psc.c17
-rw-r--r--drivers/spi/spi-mpc52xx-psc.c1
-rw-r--r--drivers/spi/spi-mpc52xx.c17
-rw-r--r--drivers/spi/spi-mxs.c7
-rw-r--r--drivers/spi/spi-nuc900.c28
-rw-r--r--drivers/spi/spi-oc-tiny.c3
-rw-r--r--drivers/spi/spi-octeon.c80
-rw-r--r--drivers/spi/spi-omap-100k.c52
-rw-r--r--drivers/spi/spi-omap-uwire.c34
-rw-r--r--drivers/spi/spi-omap2-mcspi.c65
-rw-r--r--drivers/spi/spi-orion.c80
-rw-r--r--drivers/spi/spi-pl022.c80
-rw-r--r--drivers/spi/spi-ppc4xx.c1
-rw-r--r--drivers/spi/spi-pxa2xx-dma.c1
-rw-r--r--drivers/spi/spi-pxa2xx-pxadma.c1
-rw-r--r--drivers/spi/spi-pxa2xx.c3
-rw-r--r--drivers/spi/spi-qup.c779
-rw-r--r--drivers/spi/spi-rspi.c842
-rw-r--r--drivers/spi/spi-s3c24xx.c19
-rw-r--r--drivers/spi/spi-s3c64xx.c424
-rw-r--r--drivers/spi/spi-sc18is602.c29
-rw-r--r--drivers/spi/spi-sh-hspi.c43
-rw-r--r--drivers/spi/spi-sh-msiof.c385
-rw-r--r--drivers/spi/spi-sh-sci.c8
-rw-r--r--drivers/spi/spi-sirf.c116
-rw-r--r--drivers/spi/spi-sun4i.c478
-rw-r--r--drivers/spi/spi-sun6i.c484
-rw-r--r--drivers/spi/spi-tegra114.c27
-rw-r--r--drivers/spi/spi-tegra20-sflash.c26
-rw-r--r--drivers/spi/spi-tegra20-slink.c20
-rw-r--r--drivers/spi/spi-ti-qspi.c5
-rw-r--r--drivers/spi/spi-ti-ssp.c378
-rw-r--r--drivers/spi/spi-topcliff-pch.c62
-rw-r--r--drivers/spi/spi-txx9.c25
-rw-r--r--drivers/spi/spi-xcomm.c13
-rw-r--r--drivers/spi/spi-xilinx.c27
-rw-r--r--drivers/spi/spi-xtensa-xtfpga.c170
-rw-r--r--drivers/spi/spi.c247
-rw-r--r--drivers/spi/spidev.c23
-rw-r--r--drivers/spmi/Kconfig27
-rw-r--r--drivers/spmi/Makefile6
-rw-r--r--drivers/spmi/spmi-pmic-arb.c778
-rw-r--r--drivers/spmi/spmi.c574
-rw-r--r--drivers/staging/Kconfig12
-rw-r--r--drivers/staging/Makefile6
-rw-r--r--drivers/staging/android/Kconfig13
-rw-r--r--drivers/staging/android/android_alarm.h44
-rw-r--r--drivers/staging/android/ashmem.h30
-rw-r--r--drivers/staging/android/binder.c271
-rw-r--r--drivers/staging/android/binder.h308
-rw-r--r--drivers/staging/android/binder_trace.h14
-rw-r--r--drivers/staging/android/ion/ion.c156
-rw-r--r--drivers/staging/android/ion/ion_cma_heap.c2
-rw-r--r--drivers/staging/android/ion/ion_dummy_driver.c12
-rw-r--r--drivers/staging/android/ion/ion_heap.c67
-rw-r--r--drivers/staging/android/ion/ion_page_pool.c8
-rw-r--r--drivers/staging/android/ion/ion_priv.h89
-rw-r--r--drivers/staging/android/ion/ion_system_heap.c84
-rw-r--r--drivers/staging/android/ion/tegra/tegra_ion.c10
-rw-r--r--drivers/staging/android/lowmemorykiller.c5
-rw-r--r--drivers/staging/android/sw_sync.h20
-rw-r--r--drivers/staging/android/sync.h88
-rw-r--r--drivers/staging/android/timed_gpio.c8
-rw-r--r--drivers/staging/android/timed_output.h4
-rw-r--r--drivers/staging/android/uapi/android_alarm.h62
-rw-r--r--drivers/staging/android/uapi/ashmem.h47
-rw-r--r--drivers/staging/android/uapi/binder.h351
-rw-r--r--drivers/staging/android/uapi/sw_sync.h32
-rw-r--r--drivers/staging/android/uapi/sync.h97
-rw-r--r--drivers/staging/bcm/Adapter.h6
-rw-r--r--drivers/staging/bcm/Bcmchar.c3439
-rw-r--r--drivers/staging/bcm/Bcmnet.c2
-rw-r--r--drivers/staging/bcm/CmHost.c61
-rw-r--r--drivers/staging/bcm/DDRInit.c32
-rw-r--r--drivers/staging/bcm/InterfaceInit.c416
-rw-r--r--drivers/staging/bcm/InterfaceIsr.c223
-rw-r--r--drivers/staging/bcm/Qos.c35
-rw-r--r--drivers/staging/bcm/Typedefs.h22
-rw-r--r--drivers/staging/bcm/headers.h2
-rw-r--r--drivers/staging/bcm/hostmibs.c8
-rw-r--r--drivers/staging/bcm/nvm.c30
-rw-r--r--drivers/staging/ced1401/ced_ioc.c163
-rw-r--r--drivers/staging/ced1401/ced_ioctl.h31
-rw-r--r--drivers/staging/ced1401/usb1401.c195
-rw-r--r--drivers/staging/ced1401/usb1401.h6
-rw-r--r--drivers/staging/ced1401/use14_ioc.h5
-rw-r--r--drivers/staging/ced1401/userspace/use1401.c10
-rw-r--r--drivers/staging/comedi/Kconfig24
-rw-r--r--drivers/staging/comedi/comedi_fops.c191
-rw-r--r--drivers/staging/comedi/comedidev.h56
-rw-r--r--drivers/staging/comedi/drivers.c30
-rw-r--r--drivers/staging/comedi/drivers/8255_pci.c37
-rw-r--r--drivers/staging/comedi/drivers/Makefile2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c597
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c1187
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c857
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c106
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c73
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c24
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_035.c14
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1500.c24
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1564.c16
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3120.c26
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3200.c36
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3501.c6
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3xxx.c57
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c22
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7x3x.c3
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c73
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c92
-rw-r--r--drivers/staging/comedi/drivers/adq12b.c31
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c67
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c2
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c10
-rw-r--r--drivers/staging/comedi/drivers/aio_aio12_8.c31
-rw-r--r--drivers/staging/comedi/drivers/aio_iiro_16.c2
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_common.c2
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236.c35
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc263.c2
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c29
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c42
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci263.c2
-rw-r--r--drivers/staging/comedi/drivers/c6xdigio.c491
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c150
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c51
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c59
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c41
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c4
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c5
-rw-r--r--drivers/staging/comedi/drivers/comedi_fc.c99
-rw-r--r--drivers/staging/comedi/drivers/comedi_fc.h84
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c7
-rw-r--r--drivers/staging/comedi/drivers/contec_pci_dio.c2
-rw-r--r--drivers/staging/comedi/drivers/dac02.c172
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c85
-rw-r--r--drivers/staging/comedi/drivers/das08.c35
-rw-r--r--drivers/staging/comedi/drivers/das16.c19
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c38
-rw-r--r--drivers/staging/comedi/drivers/das1800.c10
-rw-r--r--drivers/staging/comedi/drivers/das6402.c672
-rw-r--r--drivers/staging/comedi/drivers/das800.c43
-rw-r--r--drivers/staging/comedi/drivers/dmm32at.c83
-rw-r--r--drivers/staging/comedi/drivers/dt2811.c23
-rw-r--r--drivers/staging/comedi/drivers/dt2814.c29
-rw-r--r--drivers/staging/comedi/drivers/dt2815.c39
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c73
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c8
-rw-r--r--drivers/staging/comedi/drivers/dyna_pci10xx.c40
-rw-r--r--drivers/staging/comedi/drivers/fl512.c207
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c1099
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c109
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c20
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c891
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.h6
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c209
-rw-r--r--drivers/staging/comedi/drivers/me4000.c3
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c36
-rw-r--r--drivers/staging/comedi/drivers/mf6x4.c23
-rw-r--r--drivers/staging/comedi/drivers/mite.c11
-rw-r--r--drivers/staging/comedi/drivers/mite.h6
-rw-r--r--drivers/staging/comedi/drivers/mpc624.c30
-rw-r--r--drivers/staging/comedi/drivers/multiq3.c38
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c11
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c3
-rw-r--r--drivers/staging/comedi/drivers/ni_at_a2150.c55
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio16d.c61
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c56
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c4
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c33
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c78
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c16
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.h8
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c26
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c1484
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c1045
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c1523
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c6
-rw-r--r--drivers/staging/comedi/drivers/pcmad.c21
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c42
-rw-r--r--drivers/staging/comedi/drivers/plx9080.h8
-rw-r--r--drivers/staging/comedi/drivers/poc.c157
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c5
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c86
-rw-r--r--drivers/staging/comedi/drivers/rti800.c29
-rw-r--r--drivers/staging/comedi/drivers/rti802.c127
-rw-r--r--drivers/staging/comedi/drivers/s526.c34
-rw-r--r--drivers/staging/comedi/drivers/s626.c174
-rw-r--r--drivers/staging/comedi/drivers/skel.c43
-rw-r--r--drivers/staging/comedi/drivers/ssv_dnp.c3
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c51
-rw-r--r--drivers/staging/comedi/kcomedilib/kcomedilib_main.c3
-rw-r--r--drivers/staging/comedi/proc.c48
-rw-r--r--drivers/staging/comedi/range.c37
-rw-r--r--drivers/staging/crystalhd/bcm_70012_regs.h3
-rw-r--r--drivers/staging/crystalhd/crystalhd_hw.c8
-rw-r--r--drivers/staging/crystalhd/crystalhd_lnx.c21
-rw-r--r--drivers/staging/crystalhd/crystalhd_lnx.h4
-rw-r--r--drivers/staging/crystalhd/crystalhd_misc.c2
-rw-r--r--drivers/staging/crystalhd/crystalhd_misc.h2
-rw-r--r--drivers/staging/cxt1e1/Makefile1
-rw-r--r--drivers/staging/cxt1e1/comet.c44
-rw-r--r--drivers/staging/cxt1e1/comet_tables.c1
-rw-r--r--drivers/staging/cxt1e1/functions.c373
-rw-r--r--drivers/staging/cxt1e1/hwprobe.c598
-rw-r--r--drivers/staging/cxt1e1/libsbew.h56
-rw-r--r--drivers/staging/cxt1e1/linux.c1641
-rw-r--r--drivers/staging/cxt1e1/musycc.c43
-rw-r--r--drivers/staging/cxt1e1/ossiRelease.c29
-rw-r--r--drivers/staging/cxt1e1/pmc93x6_eeprom.c6
-rw-r--r--drivers/staging/cxt1e1/pmcc4.h1
-rw-r--r--drivers/staging/cxt1e1/pmcc4_drv.c116
-rw-r--r--drivers/staging/cxt1e1/pmcc4_private.h1
-rw-r--r--drivers/staging/cxt1e1/pmcc4_sysdep.h1
-rw-r--r--drivers/staging/cxt1e1/sbeproc.c4
-rw-r--r--drivers/staging/dgap/Makefile6
-rw-r--r--drivers/staging/dgap/dgap.c7675
-rw-r--r--drivers/staging/dgap/dgap.h1322
-rw-r--r--drivers/staging/dgap/dgap_conf.h290
-rw-r--r--drivers/staging/dgap/dgap_downld.h69
-rw-r--r--drivers/staging/dgap/dgap_driver.c1030
-rw-r--r--drivers/staging/dgap/dgap_driver.h620
-rw-r--r--drivers/staging/dgap/dgap_fep5.c1938
-rw-r--r--drivers/staging/dgap/dgap_fep5.h253
-rw-r--r--drivers/staging/dgap/dgap_kcompat.h64
-rw-r--r--drivers/staging/dgap/dgap_parse.c1374
-rw-r--r--drivers/staging/dgap/dgap_parse.h35
-rw-r--r--drivers/staging/dgap/dgap_pci.h92
-rw-r--r--drivers/staging/dgap/dgap_sysfs.c793
-rw-r--r--drivers/staging/dgap/dgap_sysfs.h48
-rw-r--r--drivers/staging/dgap/dgap_trace.c186
-rw-r--r--drivers/staging/dgap/dgap_trace.h36
-rw-r--r--drivers/staging/dgap/dgap_tty.c3580
-rw-r--r--drivers/staging/dgap/dgap_tty.h39
-rw-r--r--drivers/staging/dgap/dgap_types.h36
-rw-r--r--drivers/staging/dgap/digi.h376
-rw-r--r--drivers/staging/dgap/downld.c798
-rw-r--r--drivers/staging/dgnc/dgnc_cls.c11
-rw-r--r--drivers/staging/dgnc/dgnc_driver.c4
-rw-r--r--drivers/staging/dgnc/dgnc_mgmt.c27
-rw-r--r--drivers/staging/dgnc/dgnc_neo.c3
-rw-r--r--drivers/staging/dgnc/dgnc_tty.c53
-rw-r--r--drivers/staging/dgrp/dgrp_sysfs.c4
-rw-r--r--drivers/staging/dgrp/dgrp_tty.c22
-rw-r--r--drivers/staging/echo/TODO5
-rw-r--r--drivers/staging/et131x/et131x.c23
-rw-r--r--drivers/staging/frontier/alphatrack.c11
-rw-r--r--drivers/staging/frontier/tranzport.c12
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_hw.c2
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h8
-rw-r--r--drivers/staging/ft1000/ft1000.h156
-rw-r--r--drivers/staging/fwserial/fwserial.c13
-rw-r--r--drivers/staging/fwserial/fwserial.h1
-rw-r--r--drivers/staging/gdm724x/gdm_lte.c187
-rw-r--r--drivers/staging/gdm724x/gdm_lte.h2
-rw-r--r--drivers/staging/gdm724x/gdm_mux.c26
-rw-r--r--drivers/staging/gdm724x/gdm_usb.c56
-rw-r--r--drivers/staging/gdm724x/netlink_k.c3
-rw-r--r--drivers/staging/gdm72xx/TODO2
-rw-r--r--drivers/staging/gdm72xx/gdm_sdio.c50
-rw-r--r--drivers/staging/gdm72xx/gdm_usb.c37
-rw-r--r--drivers/staging/gdm72xx/gdm_wimax.c77
-rw-r--r--drivers/staging/gdm72xx/gdm_wimax.h20
-rw-r--r--drivers/staging/gs_fpgaboot/Kconfig8
-rw-r--r--drivers/staging/gs_fpgaboot/Makefile4
-rw-r--r--drivers/staging/gs_fpgaboot/README71
-rw-r--r--drivers/staging/gs_fpgaboot/TODO7
-rw-r--r--drivers/staging/gs_fpgaboot/gs_fpgaboot.c422
-rw-r--r--drivers/staging/gs_fpgaboot/gs_fpgaboot.h56
-rw-r--r--drivers/staging/gs_fpgaboot/io.c294
-rw-r--r--drivers/staging/gs_fpgaboot/io.h90
-rw-r--r--drivers/staging/iio/Documentation/iio_utils.h22
-rw-r--r--drivers/staging/iio/Documentation/lsiio.c157
-rw-r--r--drivers/staging/iio/accel/sca3000.h26
-rw-r--r--drivers/staging/iio/accel/sca3000_core.c172
-rw-r--r--drivers/staging/iio/accel/sca3000_ring.c2
-rw-r--r--drivers/staging/iio/adc/ad799x.h10
-rw-r--r--drivers/staging/iio/adc/ad799x_core.c56
-rw-r--r--drivers/staging/iio/adc/mxs-lradc.c16
-rw-r--r--drivers/staging/iio/addac/adt7316.c21
-rw-r--r--drivers/staging/iio/addac/adt7316.h8
-rw-r--r--drivers/staging/iio/light/tsl2583.c6
-rw-r--r--drivers/staging/iio/light/tsl2x7x_core.c8
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c4
-rw-r--r--drivers/staging/imx-drm/Kconfig1
-rw-r--r--drivers/staging/imx-drm/Makefile3
-rw-r--r--drivers/staging/imx-drm/TODO5
-rw-r--r--drivers/staging/imx-drm/imx-drm-core.c859
-rw-r--r--drivers/staging/imx-drm/imx-drm.h44
-rw-r--r--drivers/staging/imx-drm/imx-fb.c47
-rw-r--r--drivers/staging/imx-drm/imx-fbdev.c74
-rw-r--r--drivers/staging/imx-drm/imx-hdmi.c695
-rw-r--r--drivers/staging/imx-drm/imx-ldb.c150
-rw-r--r--drivers/staging/imx-drm/imx-tve.c137
-rw-r--r--drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h2
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dc.c2
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-di.c317
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c3
-rw-r--r--drivers/staging/imx-drm/ipuv3-crtc.c93
-rw-r--r--drivers/staging/imx-drm/ipuv3-plane.c4
-rw-r--r--drivers/staging/imx-drm/parallel-display.c127
-rw-r--r--drivers/staging/keucr/common.h8
-rw-r--r--drivers/staging/keucr/init.c16
-rw-r--r--drivers/staging/keucr/init.h6
-rw-r--r--drivers/staging/keucr/smil.h112
-rw-r--r--drivers/staging/keucr/smilecc.c58
-rw-r--r--drivers/staging/keucr/smilmain.c82
-rw-r--r--drivers/staging/keucr/smilsub.c170
-rw-r--r--drivers/staging/keucr/smscsi.c28
-rw-r--r--drivers/staging/keucr/transport.c8
-rw-r--r--drivers/staging/keucr/transport.h6
-rw-r--r--drivers/staging/keucr/usb.c6
-rw-r--r--drivers/staging/keucr/usb.h86
-rw-r--r--drivers/staging/line6/audio.c5
-rw-r--r--drivers/staging/line6/capture.c1
-rw-r--r--drivers/staging/line6/driver.c56
-rw-r--r--drivers/staging/line6/driver.h2
-rw-r--r--drivers/staging/line6/midi.c7
-rw-r--r--drivers/staging/line6/pcm.c2
-rw-r--r--drivers/staging/line6/usbdefs.h8
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/curproc.h9
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h8
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h9
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_string.h30
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lib-lnet.h2
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lib-types.h16
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c132
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c10
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c6
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c15
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c3
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c6
-rw-r--r--drivers/staging/lustre/lnet/lnet/acceptor.c3
-rw-r--r--drivers/staging/lustre/lnet/lnet/api-ni.c5
-rw-r--r--drivers/staging/lustre/lnet/lnet/config.c12
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-eq.c7
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-ptl.c2
-rw-r--r--drivers/staging/lustre/lnet/lnet/peer.c3
-rw-r--r--drivers/staging/lustre/lnet/lnet/router.c12
-rw-r--r--drivers/staging/lustre/lnet/lnet/router_proc.c4
-rw-r--r--drivers/staging/lustre/lnet/selftest/conrpc.c3
-rw-r--r--drivers/staging/lustre/lnet/selftest/console.c24
-rw-r--r--drivers/staging/lustre/lnet/selftest/rpc.c3
-rw-r--r--drivers/staging/lustre/lnet/selftest/selftest.h6
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_request.c34
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_cache.c6
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_internal.h2
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_request.c15
-rw-r--r--drivers/staging/lustre/lustre/include/cl_object.h14
-rw-r--r--drivers/staging/lustre/lustre/include/ioctl.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lclient.h4
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_acl.h2
-rw-r--r--drivers/staging/lustre/lustre/include/linux/obd.h3
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_idl.h85
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_user.h22
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_cfg.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_disk.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_dlm.h4
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_dlm_flags.h18
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_export.h21
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_fid.h12
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_import.h21
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_lib.h8
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_linkea.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_mdc.h11
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_net.h26
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_quota.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_sec.h4
-rw-r--r--drivers/staging/lustre/lustre/include/md_object.h2
-rw-r--r--drivers/staging/lustre/lustre/include/obd.h11
-rw-r--r--drivers/staging/lustre/lustre/include/obd_class.h15
-rw-r--r--drivers/staging/lustre/lustre/include/obd_support.h2
-rw-r--r--drivers/staging/lustre/lustre/lclient/lcommon_cl.c4
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_flock.c41
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lock.c2
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c5
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_request.c2
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_resource.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/debug.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/fail.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c102
-rw-r--r--drivers/staging/lustre/lustre/libcfs/libcfs_string.c54
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c19
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c65
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-module.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c38
-rw-r--r--drivers/staging/lustre/lustre/libcfs/nidstrings.c7
-rw-r--r--drivers/staging/lustre/lustre/libcfs/tracefile.c5
-rw-r--r--drivers/staging/lustre/lustre/libcfs/upcall_cache.c5
-rw-r--r--drivers/staging/lustre/lustre/libcfs/workitem.c10
-rw-r--r--drivers/staging/lustre/lustre/llite/dcache.c328
-rw-r--r--drivers/staging/lustre/lustre/llite/dir.c35
-rw-r--r--drivers/staging/lustre/lustre/llite/file.c105
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_close.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_internal.h42
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_lib.c30
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_mmap.c4
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_nfs.c6
-rw-r--r--drivers/staging/lustre/lustre/llite/lloop.c6
-rw-r--r--drivers/staging/lustre/lustre/llite/namei.c124
-rw-r--r--drivers/staging/lustre/lustre/llite/rw.c10
-rw-r--r--drivers/staging/lustre/lustre/llite/statahead.c14
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_io.c37
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr.c31
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr_cache.c125
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_intent.c1
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_obd.c5
-rw-r--r--drivers/staging/lustre/lustre/lmv/lproc_lmv.c5
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_ea.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_io.c1
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_obd.c6
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_object.c16
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_pack.c3
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_request.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lovsub_dev.c4
-rw-r--r--drivers/staging/lustre/lustre/lvfs/lvfs_linux.c2
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_internal.h4
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_lib.c2
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_locks.c117
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_reint.c3
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_request.c74
-rw-r--r--drivers/staging/lustre/lustre/mgc/mgc_request.c92
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_io.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_lock.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_object.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/genops.c12
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linux/linux-module.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_cat.c6
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_lvfs.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_osd.c6
-rw-r--r--drivers/staging/lustre/lustre/obdclass/local_storage.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lprocfs_status.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lu_object.c10
-rw-r--r--drivers/staging/lustre/lustre/obdclass/md_attrs.c6
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_config.c54
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_mount.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obdo.c6
-rw-r--r--drivers/staging/lustre/lustre/obdecho/echo.c3
-rw-r--r--drivers/staging/lustre/lustre/obdecho/echo_client.c20
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_cache.c12
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_io.c16
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_page.c2
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_quota.c20
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/client.c187
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/events.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_generic_token.c36
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c4
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c4
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c8
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c14
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/import.c37
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/layout.c5
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c4
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/niobuf.c8
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/nrs.c4
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/pack_generic.c14
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c4
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/recover.c57
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec.c18
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c6
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_config.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/service.c12
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/wiretest.c2
-rw-r--r--drivers/staging/media/as102/as10x_handle.h14
-rw-r--r--drivers/staging/media/cxd2099/cxd2099.c12
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.h2
-rw-r--r--drivers/staging/media/dt3155v4l/dt3155v4l.c2
-rw-r--r--drivers/staging/media/go7007/go7007-loader.c2
-rw-r--r--drivers/staging/media/go7007/go7007-v4l2.c20
-rw-r--r--drivers/staging/media/go7007/snd-go7007.c5
-rw-r--r--drivers/staging/media/lirc/lirc_igorplugusb.c2
-rw-r--r--drivers/staging/media/lirc/lirc_imon.c4
-rw-r--r--drivers/staging/media/lirc/lirc_parallel.c26
-rw-r--r--drivers/staging/media/lirc/lirc_sasem.c13
-rw-r--r--drivers/staging/media/msi3101/sdr-msi3101.c2
-rw-r--r--drivers/staging/media/omap24xx/tcm825x.c8
-rw-r--r--drivers/staging/media/omap24xx/tcm825x.h2
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_core.c85
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_hv7131d.c15
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_hv7131r.c15
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_ov7630.c24
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_ov7660.c24
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_pas106b.c18
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_pas202bcb.c15
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-core.c2
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-g723.c6
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-tw28.c2
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c44
-rw-r--r--drivers/staging/netlogic/xlr_net.c5
-rw-r--r--drivers/staging/nokia_h4p/Kconfig9
-rw-r--r--drivers/staging/nokia_h4p/Makefile6
-rw-r--r--drivers/staging/nokia_h4p/TODO132
-rw-r--r--drivers/staging/nokia_h4p/hci_h4p.h222
-rw-r--r--drivers/staging/nokia_h4p/nokia_core.c1206
-rw-r--r--drivers/staging/nokia_h4p/nokia_fw-bcm.c148
-rw-r--r--drivers/staging/nokia_h4p/nokia_fw-csr.c149
-rw-r--r--drivers/staging/nokia_h4p/nokia_fw-ti1273.c110
-rw-r--r--drivers/staging/nokia_h4p/nokia_fw.c208
-rw-r--r--drivers/staging/nokia_h4p/nokia_uart.c199
-rw-r--r--drivers/staging/nvec/nvec.c3
-rw-r--r--drivers/staging/nvec/nvec_ps2.c2
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.c752
-rw-r--r--drivers/staging/octeon/ethernet-defines.h4
-rw-r--r--drivers/staging/octeon/ethernet-mdio.c20
-rw-r--r--drivers/staging/octeon/ethernet-mem.c11
-rw-r--r--drivers/staging/octeon/ethernet-rgmii.c23
-rw-r--r--drivers/staging/octeon/ethernet-tx.c2
-rw-r--r--drivers/staging/octeon/ethernet.c10
-rw-r--r--drivers/staging/octeon/octeon-ethernet.h2
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.h2
-rw-r--r--drivers/staging/ozwpan/ozcdev.c4
-rw-r--r--drivers/staging/ozwpan/ozhcd.c8
-rw-r--r--drivers/staging/ozwpan/ozpd.c31
-rw-r--r--drivers/staging/ozwpan/ozpd.h5
-rw-r--r--drivers/staging/ozwpan/ozproto.c57
-rw-r--r--drivers/staging/ozwpan/ozproto.h2
-rw-r--r--drivers/staging/ozwpan/ozprotocol.h6
-rw-r--r--drivers/staging/ozwpan/ozusbif.h2
-rw-r--r--drivers/staging/ozwpan/ozusbsvc1.c2
-rw-r--r--drivers/staging/panel/panel.c41
-rw-r--r--drivers/staging/rtl8187se/Module.symvers0
-rw-r--r--drivers/staging/rtl8187se/ieee80211/dot11d.h11
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211.h12
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c14
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c15
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c1203
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c151
-rw-r--r--drivers/staging/rtl8187se/r8180.h750
-rw-r--r--drivers/staging/rtl8187se/r8180_core.c894
-rw-r--r--drivers/staging/rtl8187se/r8180_dm.c6
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8225.h21
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8225z2.c59
-rw-r--r--drivers/staging/rtl8187se/r8180_wx.c10
-rw-r--r--drivers/staging/rtl8187se/r8185b_init.c62
-rw-r--r--drivers/staging/rtl8188eu/Kconfig4
-rw-r--r--drivers/staging/rtl8188eu/Makefile1
-rw-r--r--drivers/staging/rtl8188eu/TODO5
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ap.c81
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_br_ext.c13
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_cmd.c220
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_debug.c12
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_efuse.c59
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ieee80211.c58
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_io.c28
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ioctl_set.c52
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_led.c4
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme.c303
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c302
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mp.c16
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mp_ioctl.c78
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_p2p.c50
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_pwrctrl.c27
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_recv.c502
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_security.c93
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_sta_mgt.c87
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_wlan_util.c46
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_xmit.c129
-rw-r--r--drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c13
-rw-r--r--drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c37
-rw-r--r--drivers/staging/rtl8188eu/hal/hal_intf.c4
-rw-r--r--drivers/staging/rtl8188eu/hal/odm.c15
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_RegConfig8188E.c4
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_interface.c101
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c12
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_dm.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c87
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_mp.c10
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c37
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c3
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c6
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_halinit.c10
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_ops_linux.c63
-rw-r--r--drivers/staging/rtl8188eu/include/drv_types.h6
-rw-r--r--drivers/staging/rtl8188eu/include/ethernet.h42
-rw-r--r--drivers/staging/rtl8188eu/include/h2clbk.h35
-rw-r--r--drivers/staging/rtl8188eu/include/if_ether.h111
-rw-r--r--drivers/staging/rtl8188eu/include/ioctl_cfg80211.h107
-rw-r--r--drivers/staging/rtl8188eu/include/ip.h126
-rw-r--r--drivers/staging/rtl8188eu/include/nic_spec.h44
-rw-r--r--drivers/staging/rtl8188eu/include/odm_interface.h23
-rw-r--r--drivers/staging/rtl8188eu/include/osdep_service.h34
-rw-r--r--drivers/staging/rtl8188eu/include/recv_osdep.h10
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_hal.h11
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_recv.h7
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_debug.h24
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_io.h44
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_ioctl.h2
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme.h32
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme_ext.h49
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_pwrctrl.h4
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_recv.h139
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_xmit.h5
-rw-r--r--drivers/staging/rtl8188eu/include/wifi.h2
-rw-r--r--drivers/staging/rtl8188eu/os_dep/ioctl_linux.c242
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mlme_linux.c9
-rw-r--r--drivers/staging/rtl8188eu/os_dep/os_intfs.c12
-rw-r--r--drivers/staging/rtl8188eu/os_dep/osdep_service.c35
-rw-r--r--drivers/staging/rtl8188eu/os_dep/recv_linux.c44
-rw-r--r--drivers/staging/rtl8188eu/os_dep/rtw_android.c1
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_intf.c20
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c5
-rw-r--r--drivers/staging/rtl8188eu/os_dep/xmit_linux.c17
-rw-r--r--drivers/staging/rtl8192e/dot11d.c9
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pci.h52
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_wx.c2
-rw-r--r--drivers/staging/rtl8192e/rtllib_tx.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/EndianFree.h194
-rw-r--r--drivers/staging/rtl8192u/ieee80211/aes.c468
-rw-r--r--drivers/staging/rtl8192u/ieee80211/arc4.c103
-rw-r--r--drivers/staging/rtl8192u/ieee80211/autoload.c40
-rw-r--r--drivers/staging/rtl8192u/ieee80211/cipher.c298
-rw-r--r--drivers/staging/rtl8192u/ieee80211/compress.c64
-rw-r--r--drivers/staging/rtl8192u/ieee80211/crypto_compat.h58
-rw-r--r--drivers/staging/rtl8192u/ieee80211/digest.c108
-rw-r--r--drivers/staging/rtl8192u/ieee80211/dot11d.c173
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211.h2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c22
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c107
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c5
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/internal.h81
-rw-r--r--drivers/staging/rtl8192u/ieee80211/michael_mic.c194
-rw-r--r--drivers/staging/rtl8192u/ieee80211/proc.c112
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c12
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c70
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c39
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl_crypto.h398
-rw-r--r--drivers/staging/rtl8192u/ieee80211/scatterwalk.c117
-rw-r--r--drivers/staging/rtl8192u/ieee80211/scatterwalk.h51
-rw-r--r--drivers/staging/rtl8192u/r8180_93cx6.c10
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c138
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.c99
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.h40
-rw-r--r--drivers/staging/rtl8192u/r819xU_HTGen.h12
-rw-r--r--drivers/staging/rtl8192u/r819xU_HTType.h379
-rw-r--r--drivers/staging/rtl8192u/r819xU_cmdpkt.c2
-rw-r--r--drivers/staging/rtl8192u/r819xU_firmware.c50
-rw-r--r--drivers/staging/rtl8192u/r819xU_firmware_img.c1
-rw-r--r--drivers/staging/rtl8192u/r819xU_phy.c29
-rw-r--r--drivers/staging/rtl8712/drv_types.h2
-rw-r--r--drivers/staging/rtl8712/ieee80211.c6
-rw-r--r--drivers/staging/rtl8712/os_intfs.c2
-rw-r--r--drivers/staging/rtl8712/osdep_service.h5
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.c2
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.c11
-rw-r--r--drivers/staging/rtl8712/rtl871x_security.c13
-rw-r--r--drivers/staging/rtl8821ae/base.c199
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.c2
-rw-r--r--drivers/staging/rtl8821ae/btcoexist/halbtcoutsrc.c12
-rw-r--r--drivers/staging/rtl8821ae/core.c12
-rw-r--r--drivers/staging/rtl8821ae/core.h8
-rw-r--r--drivers/staging/rtl8821ae/debug.c10
-rw-r--r--drivers/staging/rtl8821ae/debug.h12
-rw-r--r--drivers/staging/rtl8821ae/efuse.c26
-rw-r--r--drivers/staging/rtl8821ae/pci.c274
-rw-r--r--drivers/staging/rtl8821ae/pci.h8
-rw-r--r--drivers/staging/rtl8821ae/ps.c2
-rw-r--r--drivers/staging/rtl8821ae/regd.c4
-rw-r--r--drivers/staging/rtl8821ae/regd.h4
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/dm.c24
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/fw.c8
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.h2
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/hal_btc.c6
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/hw.c13
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/phy.c8
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/phy.h2
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/pwrseq.h10
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.c2
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/reg.h28
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/sw.c4
-rw-r--r--drivers/staging/rtl8821ae/rtl8821ae/trx.c10
-rw-r--r--drivers/staging/rtl8821ae/wifi.h486
-rw-r--r--drivers/staging/rts5139/ms.c21
-rw-r--r--drivers/staging/rts5139/ms_mg.c1
-rw-r--r--drivers/staging/rts5139/rts51x.c6
-rw-r--r--drivers/staging/rts5139/rts51x_fop.c10
-rw-r--r--drivers/staging/rts5139/rts51x_fop.h4
-rw-r--r--drivers/staging/rts5139/rts51x_scsi.c4
-rw-r--r--drivers/staging/rts5139/rts51x_transport.c4
-rw-r--r--drivers/staging/rts5139/sd.c4
-rw-r--r--drivers/staging/rts5139/sd_cprm.c1
-rw-r--r--drivers/staging/rts5139/xd.c18
-rw-r--r--drivers/staging/rts5208/ms.c2
-rw-r--r--drivers/staging/rts5208/rtsx.c6
-rw-r--r--drivers/staging/rts5208/rtsx_card.c71
-rw-r--r--drivers/staging/rts5208/rtsx_scsi.c8
-rw-r--r--drivers/staging/rts5208/rtsx_transport.c4
-rw-r--r--drivers/staging/sb105x/Kconfig9
-rw-r--r--drivers/staging/sb105x/Makefile3
-rw-r--r--drivers/staging/sb105x/sb_mp_register.h295
-rw-r--r--drivers/staging/sb105x/sb_pci_mp.c3189
-rw-r--r--drivers/staging/sb105x/sb_pci_mp.h291
-rw-r--r--drivers/staging/sb105x/sb_ser_core.h368
-rw-r--r--drivers/staging/sbe-2t3e3/2t3e3.h21
-rw-r--r--drivers/staging/sbe-2t3e3/ctrl.c17
-rw-r--r--drivers/staging/sbe-2t3e3/ctrl.h16
-rw-r--r--drivers/staging/sbe-2t3e3/dc.c7
-rw-r--r--drivers/staging/sbe-2t3e3/intr.c4
-rw-r--r--drivers/staging/sbe-2t3e3/maps.c9
-rw-r--r--drivers/staging/sbe-2t3e3/module.c2
-rw-r--r--drivers/staging/sbe-2t3e3/netdev.c6
-rw-r--r--drivers/staging/sep/sep_crypto.c2
-rw-r--r--drivers/staging/sep/sep_main.c94
-rw-r--r--drivers/staging/serqt_usb2/serqt_usb2.c18
-rw-r--r--drivers/staging/silicom/bp_mod.h25
-rw-r--r--drivers/staging/silicom/bpctl_mod.c629
-rw-r--r--drivers/staging/silicom/bypasslib/bp_ioctl.h8
-rw-r--r--drivers/staging/silicom/bypasslib/libbp_sd.h313
-rw-r--r--drivers/staging/slicoss/README40
-rw-r--r--drivers/staging/slicoss/TODO38
-rw-r--r--drivers/staging/slicoss/slic.h9
-rw-r--r--drivers/staging/slicoss/slicoss.c73
-rw-r--r--drivers/staging/sm7xxfb/Kconfig13
-rw-r--r--drivers/staging/sm7xxfb/Makefile1
-rw-r--r--drivers/staging/sm7xxfb/TODO9
-rw-r--r--drivers/staging/sm7xxfb/sm7xx.h779
-rw-r--r--drivers/staging/sm7xxfb/sm7xxfb.c1028
-rw-r--r--drivers/staging/speakup/serialio.c4
-rw-r--r--drivers/staging/speakup/speakup_dectlk.c6
-rw-r--r--drivers/staging/tidspbridge/Kconfig2
-rw-r--r--drivers/staging/tidspbridge/core/io_sm.c2
-rw-r--r--drivers/staging/tidspbridge/core/tiomap3430.c23
-rw-r--r--drivers/staging/tidspbridge/core/tiomap3430_pwr.c15
-rw-r--r--drivers/staging/tidspbridge/dynload/tramp.c2
-rw-r--r--drivers/staging/tidspbridge/rmgr/dbdcd.c4
-rw-r--r--drivers/staging/tidspbridge/rmgr/drv.c2
-rw-r--r--drivers/staging/tidspbridge/rmgr/mgr.c8
-rw-r--r--drivers/staging/tidspbridge/rmgr/nldr.c5
-rw-r--r--drivers/staging/tidspbridge/rmgr/node.c20
-rw-r--r--drivers/staging/unisys/Documentation/overview.txt174
-rw-r--r--drivers/staging/unisys/Documentation/proc-entries.txt93
-rw-r--r--drivers/staging/unisys/Kconfig20
-rw-r--r--drivers/staging/unisys/MAINTAINERS6
-rw-r--r--drivers/staging/unisys/Makefile10
-rw-r--r--drivers/staging/unisys/TODO21
-rw-r--r--drivers/staging/unisys/channels/Kconfig10
-rw-r--r--drivers/staging/unisys/channels/Makefile13
-rw-r--r--drivers/staging/unisys/channels/channel.c219
-rw-r--r--drivers/staging/unisys/channels/chanstub.c70
-rw-r--r--drivers/staging/unisys/channels/chanstub.h23
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/channel.h661
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/channel_guid.h64
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/controlframework.h77
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h619
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/diagchannel.h427
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/iochannel.h933
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/vbuschannel.h135
-rw-r--r--drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h92
-rw-r--r--drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h310
-rw-r--r--drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h53
-rw-r--r--drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h209
-rw-r--r--drivers/staging/unisys/common-spar/include/version.h46
-rw-r--r--drivers/staging/unisys/common-spar/include/vmcallinterface.h167
-rw-r--r--drivers/staging/unisys/include/commontypes.h170
-rw-r--r--drivers/staging/unisys/include/guestlinuxdebug.h182
-rw-r--r--drivers/staging/unisys/include/guidutils.h203
-rw-r--r--drivers/staging/unisys/include/periodic_work.h40
-rw-r--r--drivers/staging/unisys/include/procobjecttree.h48
-rw-r--r--drivers/staging/unisys/include/sparstop.h30
-rw-r--r--drivers/staging/unisys/include/timskmod.h324
-rw-r--r--drivers/staging/unisys/include/timskmodutils.h75
-rw-r--r--drivers/staging/unisys/include/uisqueue.h440
-rw-r--r--drivers/staging/unisys/include/uisthread.h46
-rw-r--r--drivers/staging/unisys/include/uisutils.h348
-rw-r--r--drivers/staging/unisys/include/uniklog.h193
-rw-r--r--drivers/staging/unisys/include/vbushelper.h47
-rw-r--r--drivers/staging/unisys/uislib/Kconfig10
-rw-r--r--drivers/staging/unisys/uislib/Makefile17
-rw-r--r--drivers/staging/unisys/uislib/uislib.c2421
-rw-r--r--drivers/staging/unisys/uislib/uisqueue.c160
-rw-r--r--drivers/staging/unisys/uislib/uisthread.c85
-rw-r--r--drivers/staging/unisys/uislib/uisutils.c350
-rw-r--r--drivers/staging/unisys/virthba/Kconfig10
-rw-r--r--drivers/staging/unisys/virthba/Makefile16
-rw-r--r--drivers/staging/unisys/virthba/virthba.c1823
-rw-r--r--drivers/staging/unisys/virthba/virthba.h31
-rw-r--r--drivers/staging/unisys/virtpci/Kconfig10
-rw-r--r--drivers/staging/unisys/virtpci/Makefile13
-rw-r--r--drivers/staging/unisys/virtpci/virtpci.c1771
-rw-r--r--drivers/staging/unisys/virtpci/virtpci.h104
-rw-r--r--drivers/staging/unisys/visorchannel/Kconfig10
-rw-r--r--drivers/staging/unisys/visorchannel/Makefile14
-rw-r--r--drivers/staging/unisys/visorchannel/globals.h29
-rw-r--r--drivers/staging/unisys/visorchannel/visorchannel.h106
-rw-r--r--drivers/staging/unisys/visorchannel/visorchannel_funcs.c674
-rw-r--r--drivers/staging/unisys/visorchannel/visorchannel_main.c49
-rw-r--r--drivers/staging/unisys/visorchipset/Kconfig10
-rw-r--r--drivers/staging/unisys/visorchipset/Makefile18
-rw-r--r--drivers/staging/unisys/visorchipset/controlvm.h27
-rw-r--r--drivers/staging/unisys/visorchipset/controlvm_direct.c62
-rw-r--r--drivers/staging/unisys/visorchipset/file.c226
-rw-r--r--drivers/staging/unisys/visorchipset/file.h26
-rw-r--r--drivers/staging/unisys/visorchipset/filexfer.c506
-rw-r--r--drivers/staging/unisys/visorchipset/filexfer.h147
-rw-r--r--drivers/staging/unisys/visorchipset/globals.h45
-rw-r--r--drivers/staging/unisys/visorchipset/parser.c474
-rw-r--r--drivers/staging/unisys/visorchipset/parser.h45
-rw-r--r--drivers/staging/unisys/visorchipset/testing.h41
-rw-r--r--drivers/staging/unisys/visorchipset/visorchipset.h307
-rw-r--r--drivers/staging/unisys/visorchipset/visorchipset_main.c2945
-rw-r--r--drivers/staging/unisys/visorchipset/visorchipset_umode.h37
-rw-r--r--drivers/staging/unisys/visorutil/Kconfig10
-rw-r--r--drivers/staging/unisys/visorutil/Makefile11
-rw-r--r--drivers/staging/unisys/visorutil/charqueue.c141
-rw-r--r--drivers/staging/unisys/visorutil/charqueue.h37
-rw-r--r--drivers/staging/unisys/visorutil/easyproc.c371
-rw-r--r--drivers/staging/unisys/visorutil/easyproc.h92
-rw-r--r--drivers/staging/unisys/visorutil/memregion.h43
-rw-r--r--drivers/staging/unisys/visorutil/memregion_direct.c223
-rw-r--r--drivers/staging/unisys/visorutil/periodic_work.c236
-rw-r--r--drivers/staging/unisys/visorutil/procobjecttree.c348
-rw-r--r--drivers/staging/unisys/visorutil/visorkmodutils.c71
-rw-r--r--drivers/staging/usbip/stub.h3
-rw-r--r--drivers/staging/usbip/stub_dev.c164
-rw-r--r--drivers/staging/usbip/stub_main.c45
-rw-r--r--drivers/staging/usbip/stub_rx.c28
-rw-r--r--drivers/staging/usbip/stub_tx.c16
-rw-r--r--drivers/staging/usbip/uapi/usbip.h26
-rw-r--r--drivers/staging/usbip/usbip_common.c35
-rw-r--r--drivers/staging/usbip/usbip_common.h19
-rw-r--r--drivers/staging/usbip/userspace/README8
-rw-r--r--drivers/staging/usbip/userspace/configure.ac12
-rw-r--r--drivers/staging/usbip/userspace/libsrc/Makefile.am3
-rw-r--r--drivers/staging/usbip/userspace/libsrc/list.h136
-rw-r--r--drivers/staging/usbip/userspace/libsrc/sysfs_utils.c31
-rw-r--r--drivers/staging/usbip/userspace/libsrc/sysfs_utils.h8
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip_common.c93
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip_common.h41
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c303
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h7
-rw-r--r--drivers/staging/usbip/userspace/libsrc/vhci_driver.c397
-rw-r--r--drivers/staging/usbip/userspace/libsrc/vhci_driver.h14
-rw-r--r--drivers/staging/usbip/userspace/src/Makefile.am1
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_attach.c1
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_bind.c195
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_detach.c2
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_list.c146
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_network.h1
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_unbind.c129
-rw-r--r--drivers/staging/usbip/userspace/src/usbipd.c21
-rw-r--r--drivers/staging/usbip/userspace/src/utils.c48
-rw-r--r--drivers/staging/usbip/vhci_hcd.c44
-rw-r--r--drivers/staging/usbip/vhci_sysfs.c15
-rw-r--r--drivers/staging/vt6655/80211mgr.c331
-rw-r--r--drivers/staging/vt6655/aes_ccmp.c36
-rw-r--r--drivers/staging/vt6655/desc.h15
-rw-r--r--drivers/staging/vt6655/dpc.c36
-rw-r--r--drivers/staging/vt6655/key.c8
-rw-r--r--drivers/staging/vt6655/mac.c10
-rw-r--r--drivers/staging/vt6655/mac.h2
-rw-r--r--drivers/staging/vt6655/michael.c14
-rw-r--r--drivers/staging/vt6655/michael.h6
-rw-r--r--drivers/staging/vt6655/rxtx.c62
-rw-r--r--drivers/staging/vt6655/wmgr.c30
-rw-r--r--drivers/staging/vt6656/80211hdr.h2
-rw-r--r--drivers/staging/vt6656/aes_ccmp.c6
-rw-r--r--drivers/staging/vt6656/card.h7
-rw-r--r--drivers/staging/vt6656/device.h85
-rw-r--r--drivers/staging/vt6656/dpc.c92
-rw-r--r--drivers/staging/vt6656/int.c150
-rw-r--r--drivers/staging/vt6656/int.h45
-rw-r--r--drivers/staging/vt6656/iwctl.c10
-rw-r--r--drivers/staging/vt6656/mac.c16
-rw-r--r--drivers/staging/vt6656/mac.h2
-rw-r--r--drivers/staging/vt6656/main_usb.c350
-rw-r--r--drivers/staging/vt6656/power.c50
-rw-r--r--drivers/staging/vt6656/rxtx.c185
-rw-r--r--drivers/staging/vt6656/rxtx.h92
-rw-r--r--drivers/staging/vt6656/usbpipe.c451
-rw-r--r--drivers/staging/vt6656/wcmd.c77
-rw-r--r--drivers/staging/vt6656/wcmd.h4
-rw-r--r--drivers/staging/vt6656/wmgr.c8
-rw-r--r--drivers/staging/winbond/localpara.h84
-rw-r--r--drivers/staging/winbond/wb35reg.c140
-rw-r--r--drivers/staging/winbond/wb35rx.c27
-rw-r--r--drivers/staging/wlags49_h2/dhf.c10
-rw-r--r--drivers/staging/wlags49_h2/hcf.c16
-rw-r--r--drivers/staging/wlags49_h2/sta_h2.c2
-rw-r--r--drivers/staging/wlags49_h2/wl_main.c311
-rw-r--r--drivers/staging/wlags49_h2/wl_netdev.c1992
-rw-r--r--drivers/staging/wlags49_h2/wl_util.c37
-rw-r--r--drivers/staging/wlags49_h2/wl_wext.c6
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c11
-rw-r--r--drivers/staging/wlan-ng/hfa384x.h4
-rw-r--r--drivers/staging/wlan-ng/p80211mgmt.h172
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c4
-rw-r--r--drivers/staging/wlan-ng/prism2fw.c2
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c100
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c15
-rw-r--r--drivers/staging/xillybus/Kconfig3
-rw-r--r--drivers/staging/xillybus/xillybus_core.c6
-rw-r--r--drivers/target/iscsi/iscsi_target.c10
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.c16
-rw-r--r--drivers/target/iscsi/iscsi_target_tpg.c2
-rw-r--r--drivers/target/target_core_sbc.c47
-rw-r--r--drivers/target/target_core_transport.c3
-rw-r--r--drivers/thermal/Kconfig13
-rw-r--r--drivers/thermal/thermal_core.c27
-rw-r--r--drivers/thermal/x86_pkg_temp_thermal.c11
-rw-r--r--drivers/tty/hvc/hvc_console.c6
-rw-r--r--drivers/tty/ipwireless/tty.c3
-rw-r--r--drivers/tty/n_tty.c11
-rw-r--r--drivers/tty/serial/8250/8250_core.c19
-rw-r--r--drivers/tty/serial/8250/8250_pci.c43
-rw-r--r--drivers/tty/serial/Kconfig4
-rw-r--r--drivers/tty/serial/amba-pl011.c21
-rw-r--r--drivers/tty/serial/atmel_serial.c28
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c16
-rw-r--r--drivers/tty/serial/clps711x.c21
-rw-r--r--drivers/tty/serial/crisv10.c112
-rw-r--r--drivers/tty/serial/efm32-uart.c5
-rw-r--r--drivers/tty/serial/fsl_lpuart.c430
-rw-r--r--drivers/tty/serial/imx.c82
-rw-r--r--drivers/tty/serial/max310x.c417
-rw-r--r--drivers/tty/serial/msm_serial.c140
-rw-r--r--drivers/tty/serial/msm_serial.h9
-rw-r--r--drivers/tty/serial/omap-serial.c11
-rw-r--r--drivers/tty/serial/pch_uart.c2
-rw-r--r--drivers/tty/serial/samsung.c40
-rw-r--r--drivers/tty/serial/serial_core.c20
-rw-r--r--drivers/tty/serial/sh-sci.c89
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c195
-rw-r--r--drivers/tty/serial/sirfsoc_uart.h5
-rw-r--r--drivers/tty/serial/sunhv.c22
-rw-r--r--drivers/tty/serial/sunsab.c14
-rw-r--r--drivers/tty/serial/sunsu.c14
-rw-r--r--drivers/tty/serial/sunzilog.c14
-rw-r--r--drivers/tty/synclink.c1
-rw-r--r--drivers/tty/synclinkmp.c1
-rw-r--r--drivers/tty/tty_buffer.c20
-rw-r--r--drivers/tty/tty_io.c20
-rw-r--r--drivers/tty/tty_ldsem.c15
-rw-r--r--drivers/tty/vt/vt.c20
-rw-r--r--drivers/usb/Kconfig10
-rw-r--r--drivers/usb/chipidea/Makefile1
-rw-r--r--drivers/usb/chipidea/bits.h2
-rw-r--r--drivers/usb/chipidea/ci.h2
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c2
-rw-r--r--drivers/usb/chipidea/ci_hdrc_zevio.c72
-rw-r--r--drivers/usb/chipidea/core.c87
-rw-r--r--drivers/usb/chipidea/udc.c328
-rw-r--r--drivers/usb/core/config.c5
-rw-r--r--drivers/usb/core/devio.c286
-rw-r--r--drivers/usb/core/driver.c121
-rw-r--r--drivers/usb/core/generic.c1
-rw-r--r--drivers/usb/core/hcd.c37
-rw-r--r--drivers/usb/core/hub.c115
-rw-r--r--drivers/usb/core/hub.h2
-rw-r--r--drivers/usb/core/message.c8
-rw-r--r--drivers/usb/core/quirks.c4
-rw-r--r--drivers/usb/core/usb.h10
-rw-r--r--drivers/usb/dwc2/core_intr.c25
-rw-r--r--drivers/usb/dwc2/hcd_intr.c14
-rw-r--r--drivers/usb/dwc3/core.c251
-rw-r--r--drivers/usb/dwc3/core.h105
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c8
-rw-r--r--drivers/usb/dwc3/gadget.c183
-rw-r--r--drivers/usb/dwc3/gadget.h12
-rw-r--r--drivers/usb/gadget/Kconfig3
-rw-r--r--drivers/usb/gadget/at91_udc.c14
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c16
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.h2
-rw-r--r--drivers/usb/gadget/bcm63xx_udc.c58
-rw-r--r--drivers/usb/gadget/composite.c2
-rw-r--r--drivers/usb/gadget/f_fs.c623
-rw-r--r--drivers/usb/gadget/f_midi.c7
-rw-r--r--drivers/usb/gadget/f_subset.c2
-rw-r--r--drivers/usb/gadget/f_uac2.c4
-rw-r--r--drivers/usb/gadget/gr_udc.c10
-rw-r--r--drivers/usb/gadget/inode.c9
-rw-r--r--drivers/usb/gadget/lpc32xx_udc.c4
-rw-r--r--drivers/usb/gadget/printer.c10
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c143
-rw-r--r--drivers/usb/gadget/s3c-hsudc.c1
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c2
-rw-r--r--drivers/usb/gadget/tcm_usb_gadget.c2
-rw-r--r--drivers/usb/gadget/u_ether.c101
-rw-r--r--drivers/usb/gadget/u_fs.h30
-rw-r--r--drivers/usb/gadget/u_serial.c4
-rw-r--r--drivers/usb/host/Kconfig1
-rw-r--r--drivers/usb/host/ehci-hcd.c13
-rw-r--r--drivers/usb/host/ehci-hub.c26
-rw-r--r--drivers/usb/host/ehci-platform.c182
-rw-r--r--drivers/usb/host/ehci-tegra.c4
-rw-r--r--drivers/usb/host/hwa-hc.c42
-rw-r--r--drivers/usb/host/ohci-platform.c199
-rw-r--r--drivers/usb/host/uhci-platform.c1
-rw-r--r--drivers/usb/host/xhci-hub.c8
-rw-r--r--drivers/usb/host/xhci-mem.c212
-rw-r--r--drivers/usb/host/xhci-pci.c18
-rw-r--r--drivers/usb/host/xhci-plat.c4
-rw-r--r--drivers/usb/host/xhci-ring.c146
-rw-r--r--drivers/usb/host/xhci.c47
-rw-r--r--drivers/usb/host/xhci.h5
-rw-r--r--drivers/usb/misc/Kconfig1
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c10
-rw-r--r--drivers/usb/misc/usbled.c34
-rw-r--r--drivers/usb/musb/Kconfig2
-rw-r--r--drivers/usb/musb/musb_core.c20
-rw-r--r--drivers/usb/musb/musb_cppi41.c69
-rw-r--r--drivers/usb/musb/musb_dsps.c58
-rw-r--r--drivers/usb/musb/musb_host.c33
-rw-r--r--drivers/usb/musb/musb_virthub.c26
-rw-r--r--drivers/usb/musb/omap2430.c4
-rw-r--r--drivers/usb/phy/Kconfig21
-rw-r--r--drivers/usb/phy/Makefile2
-rw-r--r--drivers/usb/phy/phy-fsm-usb.c9
-rw-r--r--drivers/usb/phy/phy-msm-usb.c60
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c310
-rw-r--r--drivers/usb/phy/phy-omap-usb3.c361
-rw-r--r--drivers/usb/phy/phy-rcar-gen2-usb.c6
-rw-r--r--drivers/usb/phy/phy-twl6030-usb.c2
-rw-r--r--drivers/usb/phy/phy-ulpi.c2
-rw-r--r--drivers/usb/serial/ch341.c6
-rw-r--r--drivers/usb/serial/cyberjack.c2
-rw-r--r--drivers/usb/serial/cypress_m8.c21
-rw-r--r--drivers/usb/serial/ftdi_sio.c2
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h6
-rw-r--r--drivers/usb/serial/generic.c61
-rw-r--r--drivers/usb/serial/iuu_phoenix.c2
-rw-r--r--drivers/usb/serial/keyspan.c30
-rw-r--r--drivers/usb/serial/keyspan_pda.c2
-rw-r--r--drivers/usb/serial/kl5kusb105.c4
-rw-r--r--drivers/usb/serial/kobil_sct.c3
-rw-r--r--drivers/usb/serial/mos7720.c12
-rw-r--r--drivers/usb/serial/mos7840.c4
-rw-r--r--drivers/usb/serial/option.c3
-rw-r--r--drivers/usb/serial/quatech2.c2
-rw-r--r--drivers/usb/serial/spcp8x5.c7
-rw-r--r--drivers/usb/serial/symbolserial.c4
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c4
-rw-r--r--drivers/usb/serial/usb-serial.c17
-rw-r--r--drivers/usb/storage/Kconfig2
-rw-r--r--drivers/usb/storage/uas-detect.h96
-rw-r--r--drivers/usb/storage/uas.c687
-rw-r--r--drivers/usb/storage/unusual_devs.h5
-rw-r--r--drivers/usb/storage/unusual_uas.h52
-rw-r--r--drivers/usb/storage/usb.c26
-rw-r--r--drivers/usb/storage/usb.h3
-rw-r--r--drivers/usb/wusbcore/devconnect.c4
-rw-r--r--drivers/usb/wusbcore/wa-hc.c2
-rw-r--r--drivers/usb/wusbcore/wa-hc.h26
-rw-r--r--drivers/usb/wusbcore/wa-rpipe.c2
-rw-r--r--drivers/usb/wusbcore/wa-xfer.c583
-rw-r--r--drivers/vfio/pci/vfio_pci_intrs.c12
-rw-r--r--drivers/vfio/vfio_iommu_type1.c4
-rw-r--r--drivers/vhost/net.c67
-rw-r--r--drivers/vhost/scsi.c6
-rw-r--r--drivers/video/Kconfig17
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/gbefb.c4
-rw-r--r--drivers/video/hyperv_fb.c88
-rw-r--r--drivers/video/logo/Kconfig2
-rw-r--r--drivers/video/logo/logo.c2
-rw-r--r--drivers/video/output.c133
-rw-r--r--drivers/video/sgivwfb.c889
-rw-r--r--drivers/video/uvesafb.c4
-rw-r--r--drivers/virtio/virtio_balloon.c14
-rw-r--r--drivers/virtio/virtio_pci.c6
-rw-r--r--drivers/virtio/virtio_ring.c12
-rw-r--r--drivers/vme/bridges/vme_ca91cx42.c29
-rw-r--r--drivers/vme/bridges/vme_tsi148.c18
-rw-r--r--drivers/w1/masters/Kconfig3
-rw-r--r--drivers/w1/masters/ds2490.c155
-rw-r--r--drivers/w1/masters/mxc_w1.c43
-rw-r--r--drivers/w1/masters/w1-gpio.c19
-rw-r--r--drivers/w1/slaves/Kconfig5
-rw-r--r--drivers/w1/slaves/w1_therm.c21
-rw-r--r--drivers/w1/w1.c269
-rw-r--r--drivers/w1/w1.h186
-rw-r--r--drivers/w1/w1_family.c8
-rw-r--r--drivers/w1/w1_family.h13
-rw-r--r--drivers/w1/w1_int.c25
-rw-r--r--drivers/w1/w1_io.c102
-rw-r--r--drivers/w1/w1_netlink.c359
-rw-r--r--drivers/w1/w1_netlink.h33
-rw-r--r--drivers/watchdog/Kconfig38
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/acquirewdt.c21
-rw-r--r--drivers/watchdog/advantechwdt.c21
-rw-r--r--drivers/watchdog/ar7_wdt.c1
-rw-r--r--drivers/watchdog/at32ap700x_wdt.c4
-rw-r--r--drivers/watchdog/ath79_wdt.c1
-rw-r--r--drivers/watchdog/bcm2835_wdt.c4
-rw-r--r--drivers/watchdog/bcm47xx_wdt.c1
-rw-r--r--drivers/watchdog/bcm63xx_wdt.c2
-rw-r--r--drivers/watchdog/booke_wdt.c8
-rw-r--r--drivers/watchdog/cpu5wdt.c1
-rw-r--r--drivers/watchdog/cpwd.c1
-rw-r--r--drivers/watchdog/da9052_wdt.c1
-rw-r--r--drivers/watchdog/da9055_wdt.c4
-rw-r--r--drivers/watchdog/davinci_wdt.c1
-rw-r--r--drivers/watchdog/ep93xx_wdt.c19
-rw-r--r--drivers/watchdog/geodewdt.c17
-rw-r--r--drivers/watchdog/hpwdt.c1
-rw-r--r--drivers/watchdog/i6300esb.c1
-rw-r--r--drivers/watchdog/iTCO_wdt.c8
-rw-r--r--drivers/watchdog/ib700wdt.c21
-rw-r--r--drivers/watchdog/ibmasr.c2
-rw-r--r--drivers/watchdog/indydog.c13
-rw-r--r--drivers/watchdog/intel_scu_watchdog.c4
-rw-r--r--drivers/watchdog/it87_wdt.c41
-rw-r--r--drivers/watchdog/jz4740_wdt.c1
-rw-r--r--drivers/watchdog/max63xx_wdt.c1
-rw-r--r--drivers/watchdog/mpc8xxx_wdt.c1
-rw-r--r--drivers/watchdog/mtx-1_wdt.c1
-rw-r--r--drivers/watchdog/nuc900_wdt.c1
-rw-r--r--drivers/watchdog/of_xilinx_wdt.c390
-rw-r--r--drivers/watchdog/omap_wdt.c23
-rw-r--r--drivers/watchdog/orion_wdt.c1
-rw-r--r--drivers/watchdog/pc87413_wdt.c7
-rw-r--r--drivers/watchdog/pcwd_usb.c4
-rw-r--r--drivers/watchdog/pnx4008_wdt.c1
-rw-r--r--drivers/watchdog/rdc321x_wdt.c1
-rw-r--r--drivers/watchdog/retu_wdt.c1
-rw-r--r--drivers/watchdog/riowd.c1
-rw-r--r--drivers/watchdog/s3c2410_wdt.c9
-rw-r--r--drivers/watchdog/sc520_wdt.c3
-rw-r--r--drivers/watchdog/shwdt.c2
-rw-r--r--drivers/watchdog/softdog.c2
-rw-r--r--drivers/watchdog/sp805_wdt.c19
-rw-r--r--drivers/watchdog/stmp3xxx_rtc_wdt.c1
-rw-r--r--drivers/watchdog/sunxi_wdt.c2
-rw-r--r--drivers/watchdog/tegra_wdt.c302
-rw-r--r--drivers/watchdog/ts72xx_wdt.c6
-rw-r--r--drivers/watchdog/w83697hf_wdt.c6
-rw-r--r--drivers/watchdog/wdt285.c3
-rw-r--r--drivers/watchdog/wdt_pci.c1
-rw-r--r--drivers/watchdog/wm831x_wdt.c1
-rw-r--r--drivers/xen/balloon.c24
-rw-r--r--drivers/xen/events/events_2l.c15
-rw-r--r--drivers/xen/events/events_base.c25
-rw-r--r--drivers/xen/events/events_fifo.c8
-rw-r--r--drivers/xen/xen-acpi-cpuhotplug.c2
-rw-r--r--drivers/xen/xen-acpi-memhotplug.c2
-rw-r--r--drivers/xen/xen-acpi-pad.c26
-rw-r--r--fs/Kconfig1
-rw-r--r--fs/Makefile3
-rw-r--r--fs/afs/internal.h1
-rw-r--r--fs/afs/rxrpc.c12
-rw-r--r--fs/anon_inodes.c34
-rw-r--r--fs/bio-integrity.c87
-rw-r--r--fs/bio.c1
-rw-r--r--fs/ceph/acl.c11
-rw-r--r--fs/ceph/dir.c23
-rw-r--r--fs/ceph/file.c1
-rw-r--r--fs/ceph/super.c32
-rw-r--r--fs/ceph/super.h7
-rw-r--r--fs/ceph/xattr.c54
-rw-r--r--fs/cifs/cifsacl.c33
-rw-r--r--fs/cifs/cifsglob.h4
-rw-r--r--fs/cifs/cifsproto.h6
-rw-r--r--fs/cifs/dir.c2
-rw-r--r--fs/cifs/file.c63
-rw-r--r--fs/cifs/inode.c2
-rw-r--r--fs/cifs/smb1ops.c1
-rw-r--r--fs/cifs/smb2glob.h3
-rw-r--r--fs/cifs/smb2ops.c14
-rw-r--r--fs/cifs/smb2pdu.c4
-rw-r--r--fs/cifs/transport.c29
-rw-r--r--fs/compat.c127
-rw-r--r--fs/compat_binfmt_elf.c5
-rw-r--r--fs/compat_ioctl.c5
-rw-r--r--fs/dcache.c4
-rw-r--r--fs/efivarfs/file.c13
-rw-r--r--fs/exec.c6
-rw-r--r--fs/ext4/ext4.h2
-rw-r--r--fs/ext4/extents.c1
-rw-r--r--fs/ext4/inode.c15
-rw-r--r--fs/ext4/ioctl.c3
-rw-r--r--fs/ext4/resize.c34
-rw-r--r--fs/ext4/super.c20
-rw-r--r--fs/file.c47
-rw-r--r--fs/file_table.c1
-rw-r--r--fs/fs-writeback.c33
-rw-r--r--fs/fscache/object-list.c5
-rw-r--r--fs/fscache/object.c3
-rw-r--r--fs/hfsplus/catalog.c41
-rw-r--r--fs/hfsplus/hfsplus_fs.h1
-rw-r--r--fs/hfsplus/hfsplus_raw.h6
-rw-r--r--fs/hfsplus/inode.c9
-rw-r--r--fs/hfsplus/options.c2
-rw-r--r--fs/jbd2/transaction.c6
-rw-r--r--fs/jfs/acl.c2
-rw-r--r--fs/kernfs/Kconfig7
-rw-r--r--fs/kernfs/dir.c752
-rw-r--r--fs/kernfs/file.c22
-rw-r--r--fs/kernfs/kernfs-internal.h15
-rw-r--r--fs/kernfs/mount.c47
-rw-r--r--fs/kernfs/symlink.c6
-rw-r--r--fs/mount.h4
-rw-r--r--fs/namei.c31
-rw-r--r--fs/namespace.c177
-rw-r--r--fs/nfs/delegation.c11
-rw-r--r--fs/nfs/inode.c14
-rw-r--r--fs/nfs/internal.h12
-rw-r--r--fs/nfs/nfs3proc.c1
-rw-r--r--fs/nfs/nfs4client.c7
-rw-r--r--fs/nfs/nfs4filelayout.c10
-rw-r--r--fs/nfs/nfs4namespace.c12
-rw-r--r--fs/nfs/nfs4proc.c24
-rw-r--r--fs/nfs/nfs4state.c19
-rw-r--r--fs/nfsd/vfs.c1
-rw-r--r--fs/notify/dnotify/dnotify.c2
-rw-r--r--fs/notify/fanotify/fanotify.c8
-rw-r--r--fs/notify/fanotify/fanotify_user.c13
-rw-r--r--fs/notify/fsnotify.c2
-rw-r--r--fs/notify/group.c8
-rw-r--r--fs/notify/inotify/inotify.h2
-rw-r--r--fs/notify/inotify/inotify_fsnotify.c3
-rw-r--r--fs/notify/inotify/inotify_user.c14
-rw-r--r--fs/notify/notification.c20
-rw-r--r--fs/ocfs2/file.c8
-rw-r--r--fs/ocfs2/quota_global.c27
-rw-r--r--fs/ocfs2/quota_local.c4
-rw-r--r--fs/ocfs2/stackglue.c4
-rw-r--r--fs/open.c4
-rw-r--r--fs/pnode.c26
-rw-r--r--fs/pnode.h4
-rw-r--r--fs/proc/Makefile1
-rw-r--r--fs/proc/base.c1
-rw-r--r--fs/proc/internal.h7
-rw-r--r--fs/proc/page.c5
-rw-r--r--fs/proc/proc_devtree.c241
-rw-r--r--fs/proc/root.c3
-rw-r--r--fs/proc/stat.c2
-rw-r--r--fs/proc/uptime.c2
-rw-r--r--fs/quota/dquot.c14
-rw-r--r--fs/read_write.c80
-rw-r--r--fs/reiserfs/do_balan.c895
-rw-r--r--fs/sync.c15
-rw-r--r--fs/sysfs/Kconfig1
-rw-r--r--fs/sysfs/dir.c44
-rw-r--r--fs/sysfs/file.c23
-rw-r--r--fs/sysfs/group.c7
-rw-r--r--fs/sysfs/mount.c7
-rw-r--r--fs/timerfd.c1
-rw-r--r--fs/udf/file.c14
-rw-r--r--fs/udf/inode.c1
-rw-r--r--fs/xfs/xfs_iops.c16
-rw-r--r--fs/xfs/xfs_log_cil.c19
-rw-r--r--fs/xfs/xfs_mount.c24
-rw-r--r--fs/xfs/xfs_sb.c10
-rw-r--r--fs/xfs/xfs_super.c2
-rw-r--r--include/acpi/acbuffer.h2
-rw-r--r--include/acpi/acconfig.h2
-rw-r--r--include/acpi/acexcep.h2
-rw-r--r--include/acpi/acnames.h2
-rw-r--r--include/acpi/acoutput.h2
-rw-r--r--include/acpi/acpi.h5
-rw-r--r--include/acpi/acpi_bus.h49
-rw-r--r--include/acpi/acpi_drivers.h26
-rw-r--r--include/acpi/acpi_numa.h1
-rw-r--r--include/acpi/acpiosxf.h2
-rw-r--r--include/acpi/acpixf.h10
-rw-r--r--include/acpi/acrestyp.h2
-rw-r--r--include/acpi/actbl.h2
-rw-r--r--include/acpi/actbl1.h2
-rw-r--r--include/acpi/actbl2.h2
-rw-r--r--include/acpi/actbl3.h2
-rw-r--r--include/acpi/actypes.h66
-rw-r--r--include/acpi/platform/acenv.h2
-rw-r--r--include/acpi/platform/acgcc.h2
-rw-r--r--include/acpi/platform/aclinux.h20
-rw-r--r--include/asm-generic/bitops/const_hweight.h17
-rw-r--r--include/asm-generic/cputime_jiffies.h4
-rw-r--r--include/asm-generic/cputime_nsecs.h5
-rw-r--r--include/asm-generic/mcs_spinlock.h13
-rw-r--r--include/asm-generic/pgtable.h52
-rw-r--r--include/asm-generic/rwsem.h10
-rw-r--r--include/asm-generic/vmlinux.lds.h11
-rw-r--r--include/drm/drm_crtc.h3
-rw-r--r--include/drm/ttm/ttm_page_alloc.h2
-rw-r--r--include/dt-bindings/clock/tegra124-car.h4
-rw-r--r--include/dt-bindings/sound/tlv320aic31xx-micbias.h8
-rw-r--r--include/dt-bindings/spmi/spmi.h18
-rw-r--r--include/kvm/arm_vgic.h5
-rw-r--r--include/linux/acpi.h13
-rw-r--r--include/linux/ahci_platform.h28
-rw-r--r--include/linux/atmel-ssc.h1
-rw-r--r--include/linux/audit.h3
-rw-r--r--include/linux/bitops.h15
-rw-r--r--include/linux/blk-iopoll.h2
-rw-r--r--include/linux/blk-mq.h16
-rw-r--r--include/linux/blkdev.h1
-rw-r--r--include/linux/ceph/ceph_fs.h5
-rw-r--r--include/linux/cgroup.h2
-rw-r--r--include/linux/clk/ti.h4
-rw-r--r--include/linux/clockchips.h16
-rw-r--r--include/linux/compat.h86
-rw-r--r--include/linux/connector.h2
-rw-r--r--include/linux/cpu.h7
-rw-r--r--include/linux/cpufeature.h60
-rw-r--r--include/linux/cpufreq.h37
-rw-r--r--include/linux/cpuidle.h23
-rw-r--r--include/linux/cputime.h16
-rw-r--r--include/linux/device.h3
-rw-r--r--include/linux/dma-buf.h2
-rw-r--r--include/linux/drbd.h8
-rw-r--r--include/linux/drbd_genl.h6
-rw-r--r--include/linux/efi.h268
-rw-r--r--include/linux/elevator.h11
-rw-r--r--include/linux/extcon.h12
-rw-r--r--include/linux/extcon/of_extcon.h31
-rw-r--r--include/linux/file.h27
-rw-r--r--include/linux/firewire.h1
-rw-r--r--include/linux/fmc-sdb.h2
-rw-r--r--include/linux/fs.h8
-rw-r--r--include/linux/fsl_ifc.h (renamed from arch/powerpc/include/asm/fsl_ifc.h)0
-rw-r--r--include/linux/fsnotify_backend.h4
-rw-r--r--include/linux/ftrace_event.h4
-rw-r--r--include/linux/futex.h4
-rw-r--r--include/linux/gfp.h4
-rw-r--r--include/linux/hardirq.h1
-rw-r--r--include/linux/hid-sensor-ids.h10
-rw-r--r--include/linux/hrtimer.h4
-rw-r--r--include/linux/huge_mm.h41
-rw-r--r--include/linux/hyperv.h353
-rw-r--r--include/linux/idr.h1
-rw-r--r--include/linux/iio/iio.h16
-rw-r--r--include/linux/init.h20
-rw-r--r--include/linux/interrupt.h1
-rw-r--r--include/linux/io.h2
-rw-r--r--include/linux/ioport.h12
-rw-r--r--include/linux/ipc_namespace.h2
-rw-r--r--include/linux/irq.h9
-rw-r--r--include/linux/irq_work.h4
-rw-r--r--include/linux/kernel.h2
-rw-r--r--include/linux/kernel_stat.h10
-rw-r--r--include/linux/kernfs.h118
-rw-r--r--include/linux/kexec.h6
-rw-r--r--include/linux/kvm_host.h20
-rw-r--r--include/linux/libata.h11
-rw-r--r--include/linux/linkage.h4
-rw-r--r--include/linux/lockdep.h29
-rw-r--r--include/linux/mcb.h119
-rw-r--r--include/linux/mfd/arizona/registers.h6
-rw-r--r--include/linux/mfd/max8997-private.h2
-rw-r--r--include/linux/mfd/max8998-private.h2
-rw-r--r--include/linux/mfd/samsung/core.h22
-rw-r--r--include/linux/mfd/samsung/irq.h81
-rw-r--r--include/linux/mfd/samsung/rtc.h57
-rw-r--r--include/linux/mfd/samsung/s2mpa01.h192
-rw-r--r--include/linux/mfd/samsung/s2mps14.h154
-rw-r--r--include/linux/mfd/samsung/s5m8767.h7
-rw-r--r--include/linux/mfd/tps65217.h4
-rw-r--r--include/linux/miscdevice.h16
-rw-r--r--include/linux/mm.h33
-rw-r--r--include/linux/mmzone.h4
-rw-r--r--include/linux/mod_devicetable.h22
-rw-r--r--include/linux/mutex.h5
-rw-r--r--include/linux/netdev_features.h7
-rw-r--r--include/linux/netdevice.h38
-rw-r--r--include/linux/nfs_xdr.h5
-rw-r--r--include/linux/nvme.h1
-rw-r--r--include/linux/of.h137
-rw-r--r--include/linux/of_fdt.h4
-rw-r--r--include/linux/of_graph.h66
-rw-r--r--include/linux/of_reserved_mem.h53
-rw-r--r--include/linux/pci-acpi.h4
-rw-r--r--include/linux/pci.h31
-rw-r--r--include/linux/pci_ids.h6
-rw-r--r--include/linux/phy/omap_control_phy.h (renamed from include/linux/usb/omap_control_usb.h)36
-rw-r--r--include/linux/phy/omap_usb.h (renamed from include/linux/usb/omap_usb.h)14
-rw-r--r--include/linux/phy/phy.h15
-rw-r--r--include/linux/platform_data/adau1977.h45
-rw-r--r--include/linux/platform_data/asoc-s3c.h3
-rw-r--r--include/linux/platform_data/asoc-s3c24xx_simtec.h3
-rw-r--r--include/linux/platform_data/bt-nokia-h4p.h38
-rw-r--r--include/linux/platform_data/davinci_asp.h4
-rw-r--r--include/linux/platform_data/max310x.h64
-rw-r--r--include/linux/platform_data/serial-imx.h2
-rw-r--r--include/linux/platform_data/spi-s3c64xx.h9
-rw-r--r--include/linux/pm.h71
-rw-r--r--include/linux/pm_qos.h34
-rw-r--r--include/linux/pm_runtime.h4
-rw-r--r--include/linux/rculist.h17
-rw-r--r--include/linux/rcupdate.h96
-rw-r--r--include/linux/rcutiny.h20
-rw-r--r--include/linux/rcutree.h8
-rw-r--r--include/linux/regmap.h32
-rw-r--r--include/linux/regulator/driver.h8
-rw-r--r--include/linux/regulator/pfuze100.h14
-rw-r--r--include/linux/rmap.h3
-rw-r--r--include/linux/sched.h52
-rw-r--r--include/linux/sched/prio.h44
-rw-r--r--include/linux/sched/rt.h26
-rw-r--r--include/linux/security.h10
-rw-r--r--include/linux/serial_bcm63xx.h2
-rw-r--r--include/linux/serial_sci.h93
-rw-r--r--include/linux/skbuff.h26
-rw-r--r--include/linux/slab.h2
-rw-r--r--include/linux/smp.h8
-rw-r--r--include/linux/spi/spi.h31
-rw-r--r--include/linux/spi/spi_bitbang.h2
-rw-r--r--include/linux/spmi.h191
-rw-r--r--include/linux/srcu.h4
-rw-r--r--include/linux/syscalls.h8
-rw-r--r--include/linux/sysfs.h16
-rw-r--r--include/linux/torture.h100
-rw-r--r--include/linux/tracepoint.h6
-rw-r--r--include/linux/tty.h2
-rw-r--r--include/linux/tty_ldisc.h1
-rw-r--r--include/linux/usb.h15
-rw-r--r--include/linux/usb/cdc_ncm.h1
-rw-r--r--include/linux/usb/chipidea.h1
-rw-r--r--include/linux/usb/hcd.h1
-rw-r--r--include/linux/usb/phy.h16
-rw-r--r--include/linux/usb/serial.h3
-rw-r--r--include/linux/usb/uas.h14
-rw-r--r--include/linux/usb/usbnet.h2
-rw-r--r--include/linux/usb_usual.h6
-rw-r--r--include/linux/video_output.h57
-rw-r--r--include/linux/workqueue.h45
-rw-r--r--include/linux/writeback.h2
-rw-r--r--include/media/v4l2-of.h33
-rw-r--r--include/net/if_inet6.h4
-rw-r--r--include/net/ip_tunnels.h1
-rw-r--r--include/net/sctp/structs.h14
-rw-r--r--include/net/sock.h6
-rw-r--r--include/net/tcp.h14
-rw-r--r--include/net/xfrm.h11
-rw-r--r--include/scsi/libiscsi.h17
-rw-r--r--include/scsi/libiscsi_tcp.h2
-rw-r--r--include/scsi/libsas.h1
-rw-r--r--include/scsi/scsi_cmnd.h6
-rw-r--r--include/scsi/scsi_device.h22
-rw-r--r--include/scsi/scsi_host.h7
-rw-r--r--include/scsi/scsi_transport_fc.h1
-rw-r--r--include/sound/core.h113
-rw-r--r--include/sound/emu10k1.h2
-rw-r--r--include/sound/hwdep.h3
-rw-r--r--include/sound/pcm.h8
-rw-r--r--include/sound/rawmidi.h2
-rw-r--r--include/sound/rcar_snd.h36
-rw-r--r--include/sound/simple_card.h6
-rw-r--r--include/sound/soc-dai.h3
-rw-r--r--include/sound/soc-dapm.h48
-rw-r--r--include/sound/soc.h152
-rw-r--r--include/target/iscsi/iscsi_transport.h1
-rw-r--r--include/trace/events/bcache.h52
-rw-r--r--include/trace/events/block.h33
-rw-r--r--include/trace/events/hswadsp.h384
-rw-r--r--include/trace/events/intel-sst.h148
-rw-r--r--include/trace/events/power.h4
-rw-r--r--include/trace/events/sunrpc.h4
-rw-r--r--include/trace/events/writeback.h6
-rw-r--r--include/trace/ftrace.h7
-rw-r--r--include/uapi/asm-generic/unistd.h7
-rw-r--r--include/uapi/drm/drm.h2
-rw-r--r--include/uapi/drm/vmwgfx_drm.h1
-rw-r--r--include/uapi/linux/Kbuild1
-rw-r--r--include/uapi/linux/hyperv.h390
-rw-r--r--include/uapi/linux/kvm.h83
-rw-r--r--include/uapi/linux/spi/spidev.h14
-rw-r--r--include/uapi/linux/usb/functionfs.h44
-rw-r--r--include/uapi/linux/usbdevice_fs.h12
-rw-r--r--include/video/sgivw.h681
-rw-r--r--init/Kconfig7
-rw-r--r--init/main.c2
-rw-r--r--ipc/compat.c25
-rw-r--r--ipc/compat_mq.c51
-rw-r--r--ipc/mq_sysctl.c18
-rw-r--r--ipc/mqueue.c6
-rw-r--r--ipc/msg.c2
-rw-r--r--kernel/Makefile5
-rw-r--r--kernel/audit.c43
-rw-r--r--kernel/audit.h2
-rw-r--r--kernel/audit_tree.c2
-rw-r--r--kernel/audit_watch.c2
-rw-r--r--kernel/auditfilter.c10
-rw-r--r--kernel/cgroup.c71
-rw-r--r--kernel/compat.c212
-rw-r--r--kernel/cpu/Makefile1
-rw-r--r--kernel/cpu/idle.c144
-rw-r--r--kernel/cpuset.c10
-rw-r--r--kernel/debug/debug_core.c2
-rw-r--r--kernel/events/core.c51
-rw-r--r--kernel/extable.c2
-rw-r--r--kernel/fork.c1
-rw-r--r--kernel/futex.c90
-rw-r--r--kernel/futex_compat.c2
-rw-r--r--kernel/hrtimer.c15
-rw-r--r--kernel/irq/chip.c48
-rw-r--r--kernel/irq/handle.c5
-rw-r--r--kernel/irq/internals.h9
-rw-r--r--kernel/irq/irqdesc.c5
-rw-r--r--kernel/irq/irqdomain.c1
-rw-r--r--kernel/irq/manage.c132
-rw-r--r--kernel/irq/proc.c8
-rw-r--r--kernel/irq_work.c6
-rw-r--r--kernel/kexec.c8
-rw-r--r--kernel/ksysfs.c2
-rw-r--r--kernel/locking/Makefile3
-rw-r--r--kernel/locking/lockdep.c23
-rw-r--r--kernel/locking/locktorture.c452
-rw-r--r--kernel/locking/mcs_spinlock.c178
-rw-r--r--kernel/locking/mcs_spinlock.h129
-rw-r--r--kernel/locking/mutex-debug.c6
-rw-r--r--kernel/locking/mutex.c104
-rw-r--r--kernel/locking/rtmutex.c12
-rw-r--r--kernel/locking/rwsem-xadd.c4
-rw-r--r--kernel/module.c6
-rw-r--r--kernel/notifier.c2
-rw-r--r--kernel/panic.c4
-rw-r--r--kernel/pid_namespace.c4
-rw-r--r--kernel/power/console.c1
-rw-r--r--kernel/power/hibernate.c22
-rw-r--r--kernel/power/main.c4
-rw-r--r--kernel/power/power.h2
-rw-r--r--kernel/power/qos.c18
-rw-r--r--kernel/power/snapshot.c2
-rw-r--r--kernel/power/suspend.c2
-rw-r--r--kernel/power/wakelock.c2
-rw-r--r--kernel/printk/printk.c2
-rw-r--r--kernel/profile.c4
-rw-r--r--kernel/ptrace.c4
-rw-r--r--kernel/rcu/Makefile2
-rw-r--r--kernel/rcu/rcu.h7
-rw-r--r--kernel/rcu/rcutorture.c (renamed from kernel/rcu/torture.c)1004
-rw-r--r--kernel/rcu/srcu.c11
-rw-r--r--kernel/rcu/tiny.c8
-rw-r--r--kernel/rcu/tiny_plugin.h4
-rw-r--r--kernel/rcu/tree.c80
-rw-r--r--kernel/rcu/tree.h4
-rw-r--r--kernel/rcu/tree_plugin.h19
-rw-r--r--kernel/rcu/tree_trace.c6
-rw-r--r--kernel/rcu/update.c5
-rw-r--r--kernel/resource.c12
-rw-r--r--kernel/sched/Makefile2
-rw-r--r--kernel/sched/auto_group.c2
-rw-r--r--kernel/sched/clock.c4
-rw-r--r--kernel/sched/core.c261
-rw-r--r--kernel/sched/cpudeadline.c6
-rw-r--r--kernel/sched/cputime.c20
-rw-r--r--kernel/sched/deadline.c76
-rw-r--r--kernel/sched/debug.c7
-rw-r--r--kernel/sched/fair.c610
-rw-r--r--kernel/sched/idle.c265
-rw-r--r--kernel/sched/idle_task.c25
-rw-r--r--kernel/sched/rt.c110
-rw-r--r--kernel/sched/sched.h76
-rw-r--r--kernel/sched/stop_task.c15
-rw-r--r--kernel/smp.c139
-rw-r--r--kernel/softirq.c1
-rw-r--r--kernel/stop_machine.c2
-rw-r--r--kernel/sys.c8
-rw-r--r--kernel/sysctl.c19
-rw-r--r--kernel/time/Kconfig2
-rw-r--r--kernel/time/Makefile5
-rw-r--r--kernel/time/clockevents.c40
-rw-r--r--kernel/time/ntp.c5
-rw-r--r--kernel/time/sched_clock.c46
-rw-r--r--kernel/time/tick-broadcast-hrtimer.c106
-rw-r--r--kernel/time/tick-broadcast.c85
-rw-r--r--kernel/time/tick-common.c16
-rw-r--r--kernel/time/tick-internal.h11
-rw-r--r--kernel/time/timekeeping.c3
-rw-r--r--kernel/time/timekeeping_debug.c2
-rw-r--r--kernel/timer.c59
-rw-r--r--kernel/torture.c719
-rw-r--r--kernel/trace/blktrace.c20
-rw-r--r--kernel/trace/ring_buffer_benchmark.c6
-rw-r--r--kernel/trace/trace.c27
-rw-r--r--kernel/trace/trace_event_perf.c22
-rw-r--r--kernel/trace/trace_events.c16
-rw-r--r--kernel/trace/trace_export.c7
-rw-r--r--kernel/trace/trace_irqsoff.c4
-rw-r--r--kernel/tracepoint.c7
-rw-r--r--kernel/up.c6
-rw-r--r--kernel/watchdog.c3
-rw-r--r--kernel/workqueue.c16
-rw-r--r--lib/Kconfig.debug20
-rw-r--r--lib/dma-debug.c131
-rw-r--r--lib/fonts/Kconfig6
-rw-r--r--lib/idr.c10
-rw-r--r--lib/kobject.c2
-rw-r--r--lib/radix-tree.c4
-rw-r--r--lib/random32.c13
-rw-r--r--lib/string.c2
-rw-r--r--lib/vsprintf.c13
-rw-r--r--mm/Kconfig4
-rw-r--r--mm/compaction.c20
-rw-r--r--mm/fremap.c28
-rw-r--r--mm/huge_memory.c20
-rw-r--r--mm/ksm.c2
-rw-r--r--mm/memcontrol.c20
-rw-r--r--mm/memory-failure.c2
-rw-r--r--mm/memory.c15
-rw-r--r--mm/mempolicy.c92
-rw-r--r--mm/migrate.c43
-rw-r--r--mm/mmap.c20
-rw-r--r--mm/mmu_context.c3
-rw-r--r--mm/mprotect.c25
-rw-r--r--mm/page_alloc.c30
-rw-r--r--mm/percpu.c208
-rw-r--r--mm/process_vm_access.c26
-rw-r--r--mm/rmap.c15
-rw-r--r--mm/swap.c4
-rw-r--r--mm/vmpressure.c1
-rw-r--r--net/8021q/vlan.c4
-rw-r--r--net/8021q/vlan_dev.c9
-rw-r--r--net/batman-adv/bat_iv_ogm.c30
-rw-r--r--net/batman-adv/hard-interface.c22
-rw-r--r--net/batman-adv/originator.c36
-rw-r--r--net/batman-adv/originator.h4
-rw-r--r--net/batman-adv/routing.c4
-rw-r--r--net/batman-adv/send.c9
-rw-r--r--net/batman-adv/translation-table.c23
-rw-r--r--net/bluetooth/hidp/core.c16
-rw-r--r--net/bluetooth/hidp/hidp.h4
-rw-r--r--net/bridge/br_device.c6
-rw-r--r--net/bridge/br_input.c11
-rw-r--r--net/bridge/br_multicast.c33
-rw-r--r--net/bridge/br_vlan.c44
-rw-r--r--net/can/raw.c26
-rw-r--r--net/compat.c32
-rw-r--r--net/core/dev.c39
-rw-r--r--net/core/flow_dissector.c20
-rw-r--r--net/core/neighbour.c8
-rw-r--r--net/core/netpoll.c2
-rw-r--r--net/core/rtnetlink.c29
-rw-r--r--net/core/skbuff.c131
-rw-r--r--net/core/sock.c5
-rw-r--r--net/dccp/ccids/lib/tfrc.c2
-rw-r--r--net/dccp/ccids/lib/tfrc.h1
-rw-r--r--net/hsr/hsr_framereg.c2
-rw-r--r--net/ipv4/af_inet.c7
-rw-r--r--net/ipv4/gre_demux.c8
-rw-r--r--net/ipv4/inet_fragment.c5
-rw-r--r--net/ipv4/ip_forward.c71
-rw-r--r--net/ipv4/ip_output.c3
-rw-r--r--net/ipv4/ip_tunnel.c56
-rw-r--r--net/ipv4/ip_tunnel_core.c46
-rw-r--r--net/ipv4/ipconfig.c2
-rw-r--r--net/ipv4/ipmr.c13
-rw-r--r--net/ipv4/netfilter/nf_nat_snmp_basic.c4
-rw-r--r--net/ipv4/route.c13
-rw-r--r--net/ipv4/tcp.c8
-rw-r--r--net/ipv4/tcp_cong.c3
-rw-r--r--net/ipv4/tcp_input.c3
-rw-r--r--net/ipv4/tcp_ipv4.c2
-rw-r--r--net/ipv4/tcp_output.c33
-rw-r--r--net/ipv6/Kconfig1
-rw-r--r--net/ipv6/addrconf.c200
-rw-r--r--net/ipv6/exthdrs_core.c2
-rw-r--r--net/ipv6/exthdrs_offload.c4
-rw-r--r--net/ipv6/ip6_offload.c20
-rw-r--r--net/ipv6/ip6_output.c34
-rw-r--r--net/ipv6/ip6mr.c13
-rw-r--r--net/ipv6/ping.c1
-rw-r--r--net/ipv6/route.c2
-rw-r--r--net/ipv6/sit.c19
-rw-r--r--net/ipv6/udp_offload.c2
-rw-r--r--net/key/af_key.c19
-rw-r--r--net/l2tp/l2tp_core.c6
-rw-r--r--net/l2tp/l2tp_core.h1
-rw-r--r--net/l2tp/l2tp_netlink.c4
-rw-r--r--net/l2tp/l2tp_ppp.c13
-rw-r--r--net/mac80211/chan.c6
-rw-r--r--net/mac80211/ieee80211_i.h10
-rw-r--r--net/mac80211/iface.c6
-rw-r--r--net/mac80211/mesh_ps.c1
-rw-r--r--net/mac80211/mlme.c24
-rw-r--r--net/mac80211/rx.c7
-rw-r--r--net/mac80211/sta_info.c67
-rw-r--r--net/mac80211/sta_info.h7
-rw-r--r--net/mac80211/tx.c15
-rw-r--r--net/mac80211/util.c48
-rw-r--r--net/mac80211/wme.c5
-rw-r--r--net/netfilter/nf_conntrack_netlink.c35
-rw-r--r--net/netfilter/nf_nat_core.c56
-rw-r--r--net/netfilter/nfnetlink_queue_core.c9
-rw-r--r--net/netfilter/nft_meta.c4
-rw-r--r--net/netfilter/nft_payload.c3
-rw-r--r--net/netfilter/nft_reject_inet.c4
-rw-r--r--net/netlink/af_netlink.c4
-rw-r--r--net/nfc/nci/core.c2
-rw-r--r--net/openvswitch/datapath.c15
-rw-r--r--net/openvswitch/flow.c29
-rw-r--r--net/packet/af_packet.c26
-rw-r--r--net/sched/sch_api.c7
-rw-r--r--net/sched/sch_fq.c21
-rw-r--r--net/sched/sch_pie.c21
-rw-r--r--net/sched/sch_tbf.c24
-rw-r--r--net/sctp/associola.c211
-rw-r--r--net/sctp/sm_make_chunk.c4
-rw-r--r--net/sctp/sm_sideeffect.c7
-rw-r--r--net/sctp/sm_statefuns.c12
-rw-r--r--net/sctp/socket.c47
-rw-r--r--net/sctp/sysctl.c18
-rw-r--r--net/sctp/ulpevent.c8
-rw-r--r--net/socket.c17
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c19
-rw-r--r--net/sunrpc/backchannel_rqst.c6
-rw-r--r--net/sunrpc/xprtsock.c6
-rw-r--r--net/tipc/bearer.c7
-rw-r--r--net/tipc/config.c11
-rw-r--r--net/tipc/core.c109
-rw-r--r--net/tipc/core.h2
-rw-r--r--net/tipc/handler.c1
-rw-r--r--net/tipc/link.c7
-rw-r--r--net/tipc/name_table.c40
-rw-r--r--net/tipc/netlink.c8
-rw-r--r--net/tipc/ref.c3
-rw-r--r--net/tipc/server.c19
-rw-r--r--net/tipc/server.h2
-rw-r--r--net/tipc/socket.c12
-rw-r--r--net/tipc/subscr.c48
-rw-r--r--net/unix/af_unix.c20
-rw-r--r--net/wireless/core.c2
-rw-r--r--net/wireless/reg.c12
-rw-r--r--net/xfrm/xfrm_policy.c2
-rw-r--r--net/xfrm/xfrm_state.c23
-rw-r--r--net/xfrm/xfrm_user.c11
-rw-r--r--scripts/Kbuild.include9
-rw-r--r--scripts/Makefile.build2
-rw-r--r--scripts/Makefile.lib13
-rw-r--r--scripts/dtc/dtc-parser.tab.c_shipped469
-rw-r--r--scripts/dtc/dtc-parser.tab.h_shipped36
-rw-r--r--scripts/dtc/dtc.c119
-rw-r--r--scripts/dtc/dtc.h1
-rw-r--r--scripts/dtc/srcpos.c6
-rwxr-xr-xscripts/dtc/update-dtc-source.sh54
-rw-r--r--scripts/dtc/util.c141
-rw-r--r--scripts/dtc/util.h107
-rw-r--r--scripts/dtc/version_gen.h2
-rw-r--r--scripts/gcc-ld29
-rw-r--r--scripts/gen_initramfs_list.sh2
-rwxr-xr-xscripts/ld-version.sh8
-rw-r--r--scripts/mod/devicetable-offsets.c3
-rw-r--r--scripts/mod/file2alias.c20
-rw-r--r--scripts/mod/modpost.c38
-rw-r--r--scripts/mod/modpost.h2
-rw-r--r--security/capability.c3
-rw-r--r--security/keys/compat.c4
-rw-r--r--security/keys/keyring.c6
-rw-r--r--security/security.c6
-rw-r--r--security/selinux/hooks.c13
-rw-r--r--security/selinux/include/security.h2
-rw-r--r--security/selinux/include/xfrm.h3
-rw-r--r--security/selinux/selinuxfs.c28
-rw-r--r--security/selinux/ss/policydb.c8
-rw-r--r--security/selinux/ss/services.c6
-rw-r--r--security/selinux/xfrm.c14
-rw-r--r--sound/aoa/aoa.h2
-rw-r--r--sound/aoa/codecs/onyx.c2
-rw-r--r--sound/aoa/codecs/tas.c2
-rw-r--r--sound/aoa/codecs/toonie.c2
-rw-r--r--sound/aoa/core/alsa.c7
-rw-r--r--sound/arm/aaci.c6
-rw-r--r--sound/arm/pxa2xx-ac97.c6
-rw-r--r--sound/atmel/abdac.c13
-rw-r--r--sound/atmel/ac97c.c10
-rw-r--r--sound/core/compress_offload.c2
-rw-r--r--sound/core/control.c17
-rw-r--r--sound/core/control_compat.c2
-rw-r--r--sound/core/device.c175
-rw-r--r--sound/core/hrtimer.c3
-rw-r--r--sound/core/hwdep.c53
-rw-r--r--sound/core/info.c15
-rw-r--r--sound/core/init.c186
-rw-r--r--sound/core/isadma.c2
-rw-r--r--sound/core/memalloc.c4
-rw-r--r--sound/core/oss/mixer_oss.c20
-rw-r--r--sound/core/oss/pcm_oss.c103
-rw-r--r--sound/core/pcm.c52
-rw-r--r--sound/core/pcm_lib.c28
-rw-r--r--sound/core/pcm_native.c51
-rw-r--r--sound/core/pcm_timer.c4
-rw-r--r--sound/core/rawmidi.c90
-rw-r--r--sound/core/rtctimer.c7
-rw-r--r--sound/core/seq/oss/seq_oss.c22
-rw-r--r--sound/core/seq/oss/seq_oss_device.h13
-rw-r--r--sound/core/seq/oss/seq_oss_init.c29
-rw-r--r--sound/core/seq/oss/seq_oss_ioctl.c18
-rw-r--r--sound/core/seq/oss/seq_oss_midi.c7
-rw-r--r--sound/core/seq/oss/seq_oss_readq.c4
-rw-r--r--sound/core/seq/oss/seq_oss_synth.c11
-rw-r--r--sound/core/seq/oss/seq_oss_timer.c7
-rw-r--r--sound/core/seq/seq_clientmgr.c16
-rw-r--r--sound/core/seq/seq_device.c18
-rw-r--r--sound/core/seq/seq_dummy.c2
-rw-r--r--sound/core/seq/seq_fifo.c2
-rw-r--r--sound/core/seq/seq_lock.c4
-rw-r--r--sound/core/seq/seq_memory.c8
-rw-r--r--sound/core/seq/seq_midi.c8
-rw-r--r--sound/core/seq/seq_midi_emul.c6
-rw-r--r--sound/core/seq/seq_ports.c4
-rw-r--r--sound/core/seq/seq_prioq.c14
-rw-r--r--sound/core/seq/seq_queue.c2
-rw-r--r--sound/core/seq/seq_timer.c10
-rw-r--r--sound/core/seq/seq_virmidi.c2
-rw-r--r--sound/core/sound.c29
-rw-r--r--sound/core/sound_oss.c7
-rw-r--r--sound/core/timer.c17
-rw-r--r--sound/core/vmaster.c2
-rw-r--r--sound/drivers/aloop.c4
-rw-r--r--sound/drivers/dummy.c6
-rw-r--r--sound/drivers/ml403-ac97cr.c5
-rw-r--r--sound/drivers/mpu401/mpu401.c12
-rw-r--r--sound/drivers/mtpav.c4
-rw-r--r--sound/drivers/mts64.c5
-rw-r--r--sound/drivers/opl3/opl3_lib.c4
-rw-r--r--sound/drivers/opl3/opl3_synth.c2
-rw-r--r--sound/drivers/pcsp/pcsp.c4
-rw-r--r--sound/drivers/pcsp/pcsp_input.c1
-rw-r--r--sound/drivers/portman2x4.c5
-rw-r--r--sound/drivers/serial-u16550.c5
-rw-r--r--sound/drivers/virmidi.c6
-rw-r--r--sound/firewire/dice.c4
-rw-r--r--sound/firewire/isight.c4
-rw-r--r--sound/firewire/scs1x.c4
-rw-r--r--sound/firewire/speakers.c4
-rw-r--r--sound/i2c/other/ak4113.c2
-rw-r--r--sound/i2c/other/ak4114.c2
-rw-r--r--sound/i2c/other/ak4117.c2
-rw-r--r--sound/isa/ad1816a/ad1816a.c6
-rw-r--r--sound/isa/ad1848/ad1848.c4
-rw-r--r--sound/isa/adlib.c4
-rw-r--r--sound/isa/als100.c6
-rw-r--r--sound/isa/azt2320.c6
-rw-r--r--sound/isa/cmi8328.c5
-rw-r--r--sound/isa/cmi8330.c13
-rw-r--r--sound/isa/cs423x/cs4231.c4
-rw-r--r--sound/isa/cs423x/cs4236.c16
-rw-r--r--sound/isa/es1688/es1688.c12
-rw-r--r--sound/isa/es18xx.c16
-rw-r--r--sound/isa/galaxy/galaxy.c6
-rw-r--r--sound/isa/gus/gusclassic.c4
-rw-r--r--sound/isa/gus/gusextreme.c6
-rw-r--r--sound/isa/gus/gusmax.c6
-rw-r--r--sound/isa/gus/interwave.c13
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c11
-rw-r--r--sound/isa/opl3sa2.c16
-rw-r--r--sound/isa/opti9xx/miro.c11
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c12
-rw-r--r--sound/isa/sb/jazz16.c6
-rw-r--r--sound/isa/sb/sb16.c13
-rw-r--r--sound/isa/sb/sb8.c6
-rw-r--r--sound/isa/sc6000.c6
-rw-r--r--sound/isa/sscape.c11
-rw-r--r--sound/isa/wavefront/wavefront.c13
-rw-r--r--sound/mips/au1x00.c241
-rw-r--r--sound/mips/hal2.c3
-rw-r--r--sound/mips/sgio2audio.c3
-rw-r--r--sound/oss/Kconfig9
-rw-r--r--sound/oss/Makefile1
-rw-r--r--sound/oss/pas2.h3
-rw-r--r--sound/oss/pas2_card.c2
-rw-r--r--sound/oss/vwsnd.c3506
-rw-r--r--sound/parisc/harmony.c4
-rw-r--r--sound/pci/Kconfig9
-rw-r--r--sound/pci/ac97/ac97_codec.c45
-rw-r--r--sound/pci/ac97/ac97_patch.c3
-rw-r--r--sound/pci/ac97/ac97_pcm.c15
-rw-r--r--sound/pci/ad1889.c37
-rw-r--r--sound/pci/ali5451/ali5451.c152
-rw-r--r--sound/pci/als300.c57
-rw-r--r--sound/pci/als4000.c22
-rw-r--r--sound/pci/asihpi/asihpi.c25
-rw-r--r--sound/pci/atiixp.c33
-rw-r--r--sound/pci/atiixp_modem.c28
-rw-r--r--sound/pci/au88x0/au88x0.c5
-rw-r--r--sound/pci/aw2/aw2-alsa.c46
-rw-r--r--sound/pci/aw2/aw2-saa7146.c6
-rw-r--r--sound/pci/azt3328.c351
-rw-r--r--sound/pci/bt87x.c41
-rw-r--r--sound/pci/ca0106/ca0106_main.c89
-rw-r--r--sound/pci/ca0106/ca_midi.c4
-rw-r--r--sound/pci/cmipci.c41
-rw-r--r--sound/pci/cs4281.c49
-rw-r--r--sound/pci/cs46xx/cs46xx.c3
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c145
-rw-r--r--sound/pci/cs46xx/dsp_spos.c126
-rw-r--r--sound/pci/cs46xx/dsp_spos_scb_lib.c57
-rw-r--r--sound/pci/cs5530.c27
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c31
-rw-r--r--sound/pci/cs5535audio/cs5535audio_olpc.c7
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pcm.c6
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pm.c7
-rw-r--r--sound/pci/ctxfi/ctatc.c2
-rw-r--r--sound/pci/ctxfi/xfi.c3
-rw-r--r--sound/pci/echoaudio/echoaudio.c26
-rw-r--r--sound/pci/echoaudio/echoaudio_dsp.c9
-rw-r--r--sound/pci/echoaudio/midi.c3
-rw-r--r--sound/pci/emu10k1/emu10k1.c9
-rw-r--r--sound/pci/emu10k1/emu10k1_callback.c4
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c74
-rw-r--r--sound/pci/emu10k1/emu10k1_patch.c6
-rw-r--r--sound/pci/emu10k1/emu10k1x.c32
-rw-r--r--sound/pci/emu10k1/emufx.c12
-rw-r--r--sound/pci/emu10k1/emumixer.c6
-rw-r--r--sound/pci/emu10k1/emumpu401.c7
-rw-r--r--sound/pci/emu10k1/emupcm.c22
-rw-r--r--sound/pci/emu10k1/io.c13
-rw-r--r--sound/pci/emu10k1/irq.c21
-rw-r--r--sound/pci/emu10k1/memory.c12
-rw-r--r--sound/pci/emu10k1/p16v.c45
-rw-r--r--sound/pci/emu10k1/voice.c6
-rw-r--r--sound/pci/ens1370.c44
-rw-r--r--sound/pci/es1938.c79
-rw-r--r--sound/pci/es1968.c54
-rw-r--r--sound/pci/fm801.c31
-rw-r--r--sound/pci/hda/Kconfig45
-rw-r--r--sound/pci/hda/Makefile8
-rw-r--r--sound/pci/hda/hda_auto_parser.c65
-rw-r--r--sound/pci/hda/hda_beep.c36
-rw-r--r--sound/pci/hda/hda_beep.h6
-rw-r--r--sound/pci/hda/hda_codec.c238
-rw-r--r--sound/pci/hda/hda_codec.h8
-rw-r--r--sound/pci/hda/hda_controller.c2031
-rw-r--r--sound/pci/hda/hda_controller.h53
-rw-r--r--sound/pci/hda/hda_eld.c17
-rw-r--r--sound/pci/hda/hda_generic.c49
-rw-r--r--sound/pci/hda/hda_generic.h1
-rw-r--r--sound/pci/hda/hda_hwdep.c769
-rw-r--r--sound/pci/hda/hda_i915.c6
-rw-r--r--sound/pci/hda/hda_intel.c2710
-rw-r--r--sound/pci/hda/hda_local.h26
-rw-r--r--sound/pci/hda/hda_priv.h463
-rw-r--r--sound/pci/hda/hda_sysfs.c780
-rw-r--r--sound/pci/hda/patch_analog.c5
-rw-r--r--sound/pci/hda/patch_ca0110.c1
-rw-r--r--sound/pci/hda/patch_ca0132.c277
-rw-r--r--sound/pci/hda/patch_cirrus.c1
-rw-r--r--sound/pci/hda/patch_cmedia.c34
-rw-r--r--sound/pci/hda/patch_conexant.c847
-rw-r--r--sound/pci/hda/patch_hdmi.c109
-rw-r--r--sound/pci/hda/patch_realtek.c514
-rw-r--r--sound/pci/hda/patch_si3054.c5
-rw-r--r--sound/pci/hda/patch_sigmatel.c48
-rw-r--r--sound/pci/hda/patch_via.c8
-rw-r--r--sound/pci/hda/thinkpad_helper.c6
-rw-r--r--sound/pci/ice1712/aureon.c7
-rw-r--r--sound/pci/ice1712/delta.c35
-rw-r--r--sound/pci/ice1712/ews.c12
-rw-r--r--sound/pci/ice1712/ice1712.c123
-rw-r--r--sound/pci/ice1712/ice1724.c50
-rw-r--r--sound/pci/ice1712/juli.c14
-rw-r--r--sound/pci/ice1712/prodigy192.c13
-rw-r--r--sound/pci/ice1712/quartet.c6
-rw-r--r--sound/pci/intel8x0.c90
-rw-r--r--sound/pci/intel8x0m.c50
-rw-r--r--sound/pci/korg1212/korg1212.c5
-rw-r--r--sound/pci/lola/lola.c46
-rw-r--r--sound/pci/lola/lola_clock.c14
-rw-r--r--sound/pci/lola/lola_mixer.c22
-rw-r--r--sound/pci/lola/lola_pcm.c26
-rw-r--r--sound/pci/lx6464es/lx6464es.c162
-rw-r--r--sound/pci/lx6464es/lx_core.c173
-rw-r--r--sound/pci/maestro3.c42
-rw-r--r--sound/pci/mixart/mixart.c123
-rw-r--r--sound/pci/mixart/mixart_core.c49
-rw-r--r--sound/pci/mixart/mixart_hwdep.c65
-rw-r--r--sound/pci/mixart/mixart_mixer.c16
-rw-r--r--sound/pci/nm256/nm256.c79
-rw-r--r--sound/pci/oxygen/oxygen_io.c8
-rw-r--r--sound/pci/oxygen/oxygen_lib.c14
-rw-r--r--sound/pci/oxygen/xonar_dg.c30
-rw-r--r--sound/pci/oxygen/xonar_hdmi.c2
-rw-r--r--sound/pci/oxygen/xonar_lib.c4
-rw-r--r--sound/pci/pcxhr/pcxhr.c58
-rw-r--r--sound/pci/pcxhr/pcxhr_core.c108
-rw-r--r--sound/pci/pcxhr/pcxhr_hwdep.c31
-rw-r--r--sound/pci/pcxhr/pcxhr_mix22.c23
-rw-r--r--sound/pci/pcxhr/pcxhr_mixer.c13
-rw-r--r--sound/pci/riptide/riptide.c5
-rw-r--r--sound/pci/rme32.c10
-rw-r--r--sound/pci/rme96.c51
-rw-r--r--sound/pci/rme9652/hdsp.c133
-rw-r--r--sound/pci/rme9652/hdspm.c131
-rw-r--r--sound/pci/rme9652/rme9652.c24
-rw-r--r--sound/pci/sis7019.c5
-rw-r--r--sound/pci/sonicvibes.c240
-rw-r--r--sound/pci/trident/trident.c3
-rw-r--r--sound/pci/trident/trident_main.c90
-rw-r--r--sound/pci/via82xx.c73
-rw-r--r--sound/pci/via82xx_modem.c49
-rw-r--r--sound/pci/vx222/vx222.c12
-rw-r--r--sound/pci/vx222/vx222_ops.c19
-rw-r--r--sound/pci/ymfpci/ymfpci.c25
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c28
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.c5
-rw-r--r--sound/pcmcia/vx/vxpocket.c4
-rw-r--r--sound/ppc/powermac.c4
-rw-r--r--sound/ppc/snd_ps3.c4
-rw-r--r--sound/sh/aica.c5
-rw-r--r--sound/sh/sh_dac_audio.c2
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/atmel/Kconfig2
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c13
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c20
-rw-r--r--sound/soc/blackfin/Kconfig20
-rw-r--r--sound/soc/cirrus/Kconfig4
-rw-r--r--sound/soc/cirrus/snappercl15.c18
-rw-r--r--sound/soc/codecs/88pm860x-codec.c120
-rw-r--r--sound/soc/codecs/Kconfig195
-rw-r--r--sound/soc/codecs/Makefile39
-rw-r--r--sound/soc/codecs/ad1836.c4
-rw-r--r--sound/soc/codecs/ad193x-i2c.c54
-rw-r--r--sound/soc/codecs/ad193x-spi.c48
-rw-r--r--sound/soc/codecs/ad193x.c154
-rw-r--r--sound/soc/codecs/ad193x.h7
-rw-r--r--sound/soc/codecs/ad1980.c4
-rw-r--r--sound/soc/codecs/adau1373.c39
-rw-r--r--sound/soc/codecs/adau1977-i2c.c59
-rw-r--r--sound/soc/codecs/adau1977-spi.c76
-rw-r--r--sound/soc/codecs/adau1977.c1018
-rw-r--r--sound/soc/codecs/adau1977.h37
-rw-r--r--sound/soc/codecs/adav801.c53
-rw-r--r--sound/soc/codecs/adav803.c50
-rw-r--r--sound/soc/codecs/adav80x.c159
-rw-r--r--sound/soc/codecs/adav80x.h7
-rw-r--r--sound/soc/codecs/ak4104.c2
-rw-r--r--sound/soc/codecs/ak4535.c9
-rw-r--r--sound/soc/codecs/ak4641.c24
-rw-r--r--sound/soc/codecs/ak4642.c8
-rw-r--r--sound/soc/codecs/ak4671.c250
-rw-r--r--sound/soc/codecs/ak4671.h2
-rw-r--r--sound/soc/codecs/alc5623.c120
-rw-r--r--sound/soc/codecs/alc5632.c48
-rw-r--r--sound/soc/codecs/arizona.c325
-rw-r--r--sound/soc/codecs/cq93vc.c3
-rw-r--r--sound/soc/codecs/cs4270.c9
-rw-r--r--sound/soc/codecs/cs4271.c63
-rw-r--r--sound/soc/codecs/cs42l51.c99
-rw-r--r--sound/soc/codecs/cs42l52.c109
-rw-r--r--sound/soc/codecs/cs42l73.c72
-rw-r--r--sound/soc/codecs/cs42xx8-i2c.c64
-rw-r--r--sound/soc/codecs/cs42xx8.c602
-rw-r--r--sound/soc/codecs/cs42xx8.h238
-rw-r--r--sound/soc/codecs/da7210.c28
-rw-r--r--sound/soc/codecs/da7213.c159
-rw-r--r--sound/soc/codecs/da732x.c208
-rw-r--r--sound/soc/codecs/da732x.h3
-rw-r--r--sound/soc/codecs/da9055.c111
-rw-r--r--sound/soc/codecs/isabelle.c71
-rw-r--r--sound/soc/codecs/lm4857.c3
-rw-r--r--sound/soc/codecs/lm49453.c47
-rw-r--r--sound/soc/codecs/max9768.c5
-rw-r--r--sound/soc/codecs/max98088.c47
-rw-r--r--sound/soc/codecs/max98090.c202
-rw-r--r--sound/soc/codecs/max98090.h1
-rw-r--r--sound/soc/codecs/max98095.c60
-rw-r--r--sound/soc/codecs/max9850.c8
-rw-r--r--sound/soc/codecs/mc13783.c30
-rw-r--r--sound/soc/codecs/ml26124.c22
-rw-r--r--sound/soc/codecs/pcm1681.c15
-rw-r--r--sound/soc/codecs/pcm1792a.c33
-rw-r--r--sound/soc/codecs/pcm512x-i2c.c71
-rw-r--r--sound/soc/codecs/pcm512x-spi.c69
-rw-r--r--sound/soc/codecs/pcm512x.c589
-rw-r--r--sound/soc/codecs/pcm512x.h171
-rw-r--r--sound/soc/codecs/rt5631.c84
-rw-r--r--sound/soc/codecs/rt5640.c87
-rw-r--r--sound/soc/codecs/sgtl5000.c18
-rw-r--r--sound/soc/codecs/si476x.c6
-rw-r--r--sound/soc/codecs/sirf-audio-codec.c524
-rw-r--r--sound/soc/codecs/sirf-audio-codec.h75
-rw-r--r--sound/soc/codecs/sn95031.c46
-rw-r--r--sound/soc/codecs/ssm2518.c24
-rw-r--r--sound/soc/codecs/ssm2602-i2c.c57
-rw-r--r--sound/soc/codecs/ssm2602-spi.c41
-rw-r--r--sound/soc/codecs/ssm2602.c180
-rw-r--r--sound/soc/codecs/ssm2602.h14
-rw-r--r--sound/soc/codecs/sta32x.c90
-rw-r--r--sound/soc/codecs/sta529.c15
-rw-r--r--sound/soc/codecs/stac9766.c38
-rw-r--r--sound/soc/codecs/tlv320aic23-i2c.c59
-rw-r--r--sound/soc/codecs/tlv320aic23-spi.c56
-rw-r--r--sound/soc/codecs/tlv320aic23.c79
-rw-r--r--sound/soc/codecs/tlv320aic23.h6
-rw-r--r--sound/soc/codecs/tlv320aic26.c7
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c1280
-rw-r--r--sound/soc/codecs/tlv320aic31xx.h258
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c234
-rw-r--r--sound/soc/codecs/tlv320aic3x.c6
-rw-r--r--sound/soc/codecs/tlv320dac33.c35
-rw-r--r--sound/soc/codecs/twl4030.c101
-rw-r--r--sound/soc/codecs/twl6040.c17
-rw-r--r--sound/soc/codecs/uda134x.c3
-rw-r--r--sound/soc/codecs/uda1380.c43
-rw-r--r--sound/soc/codecs/wl1273.c9
-rw-r--r--sound/soc/codecs/wm2000.c2
-rw-r--r--sound/soc/codecs/wm2200.c25
-rw-r--r--sound/soc/codecs/wm5100.c43
-rw-r--r--sound/soc/codecs/wm5102.c32
-rw-r--r--sound/soc/codecs/wm5110.c22
-rw-r--r--sound/soc/codecs/wm8350.c4
-rw-r--r--sound/soc/codecs/wm8400.c37
-rw-r--r--sound/soc/codecs/wm8510.c10
-rw-r--r--sound/soc/codecs/wm8523.c11
-rw-r--r--sound/soc/codecs/wm8580.c9
-rw-r--r--sound/soc/codecs/wm8711.c8
-rw-r--r--sound/soc/codecs/wm8728.c11
-rw-r--r--sound/soc/codecs/wm8731.c11
-rw-r--r--sound/soc/codecs/wm8737.c56
-rw-r--r--sound/soc/codecs/wm8741.c40
-rw-r--r--sound/soc/codecs/wm8750.c6
-rw-r--r--sound/soc/codecs/wm8753.c12
-rw-r--r--sound/soc/codecs/wm8770.c10
-rw-r--r--sound/soc/codecs/wm8776.c6
-rw-r--r--sound/soc/codecs/wm8804.c10
-rw-r--r--sound/soc/codecs/wm8900.c52
-rw-r--r--sound/soc/codecs/wm8903.c118
-rw-r--r--sound/soc/codecs/wm8904.c86
-rw-r--r--sound/soc/codecs/wm8940.c26
-rw-r--r--sound/soc/codecs/wm8955.c19
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c10
-rw-r--r--sound/soc/codecs/wm8960.c6
-rw-r--r--sound/soc/codecs/wm8961.c23
-rw-r--r--sound/soc/codecs/wm8962.c87
-rw-r--r--sound/soc/codecs/wm8971.c6
-rw-r--r--sound/soc/codecs/wm8974.c10
-rw-r--r--sound/soc/codecs/wm8978.c38
-rw-r--r--sound/soc/codecs/wm8983.c51
-rw-r--r--sound/soc/codecs/wm8985.c46
-rw-r--r--sound/soc/codecs/wm8988.c70
-rw-r--r--sound/soc/codecs/wm8990.c49
-rw-r--r--sound/soc/codecs/wm8991.c52
-rw-r--r--sound/soc/codecs/wm8993.c74
-rw-r--r--sound/soc/codecs/wm8994.c186
-rw-r--r--sound/soc/codecs/wm8995.c50
-rw-r--r--sound/soc/codecs/wm8996.c87
-rw-r--r--sound/soc/codecs/wm8997.c29
-rw-r--r--sound/soc/codecs/wm9081.c34
-rw-r--r--sound/soc/codecs/wm9090.c10
-rw-r--r--sound/soc/codecs/wm9705.c12
-rw-r--r--sound/soc/codecs/wm_adsp.c50
-rw-r--r--sound/soc/codecs/wm_hubs.c16
-rw-r--r--sound/soc/davinci/davinci-evm.c81
-rw-r--r--sound/soc/davinci/davinci-mcasp.c294
-rw-r--r--sound/soc/davinci/edma-pcm.c57
-rw-r--r--sound/soc/davinci/edma-pcm.h25
-rw-r--r--sound/soc/fsl/Kconfig14
-rw-r--r--sound/soc/fsl/eukrea-tlv320.c108
-rw-r--r--sound/soc/fsl/fsl_esai.c38
-rw-r--r--sound/soc/fsl/fsl_esai.h2
-rw-r--r--sound/soc/fsl/fsl_sai.c332
-rw-r--r--sound/soc/fsl/fsl_sai.h48
-rw-r--r--sound/soc/fsl/fsl_spdif.c9
-rw-r--r--sound/soc/fsl/fsl_utils.c27
-rw-r--r--sound/soc/fsl/fsl_utils.h4
-rw-r--r--sound/soc/fsl/imx-mc13783.c1
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c7
-rw-r--r--sound/soc/fsl/imx-sgtl5000.c10
-rw-r--r--sound/soc/fsl/imx-ssi.c2
-rw-r--r--sound/soc/fsl/imx-wm8962.c11
-rw-r--r--sound/soc/fsl/wm1133-ev1.c11
-rw-r--r--sound/soc/generic/simple-card.c385
-rw-r--r--sound/soc/intel/Kconfig42
-rw-r--r--sound/soc/intel/Makefile27
-rw-r--r--sound/soc/intel/byt-rt5640.c187
-rw-r--r--sound/soc/intel/haswell.c235
-rw-r--r--sound/soc/intel/mfld_machine.c108
-rw-r--r--sound/soc/intel/sst-acpi.c284
-rw-r--r--sound/soc/intel/sst-baytrail-dsp.c372
-rw-r--r--sound/soc/intel/sst-baytrail-ipc.c867
-rw-r--r--sound/soc/intel/sst-baytrail-ipc.h69
-rw-r--r--sound/soc/intel/sst-baytrail-pcm.c422
-rw-r--r--sound/soc/intel/sst-dsp-priv.h309
-rw-r--r--sound/soc/intel/sst-dsp.c385
-rw-r--r--sound/soc/intel/sst-dsp.h233
-rw-r--r--sound/soc/intel/sst-firmware.c587
-rw-r--r--sound/soc/intel/sst-haswell-dsp.c517
-rw-r--r--sound/soc/intel/sst-haswell-ipc.c1785
-rw-r--r--sound/soc/intel/sst-haswell-ipc.h488
-rw-r--r--sound/soc/intel/sst-haswell-pcm.c872
-rw-r--r--sound/soc/intel/sst-mfld-dsp.h (renamed from sound/soc/intel/sst_dsp.h)8
-rw-r--r--sound/soc/intel/sst-mfld-platform.c (renamed from sound/soc/intel/sst_platform.c)8
-rw-r--r--sound/soc/intel/sst-mfld-platform.h (renamed from sound/soc/intel/sst_platform.h)4
-rw-r--r--sound/soc/kirkwood/Kconfig11
-rw-r--r--sound/soc/kirkwood/Makefile2
-rw-r--r--sound/soc/kirkwood/armada-370-db.c148
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c1
-rw-r--r--sound/soc/omap/Kconfig4
-rw-r--r--sound/soc/omap/ams-delta.c55
-rw-r--r--sound/soc/omap/n810.c26
-rw-r--r--sound/soc/omap/omap-abe-twl6040.c3
-rw-r--r--sound/soc/omap/rx51.c22
-rw-r--r--sound/soc/pxa/corgi.c49
-rw-r--r--sound/soc/pxa/e740_wm9705.c10
-rw-r--r--sound/soc/pxa/e750_wm9705.c10
-rw-r--r--sound/soc/pxa/e800_wm9712.c19
-rw-r--r--sound/soc/pxa/magician.c60
-rw-r--r--sound/soc/pxa/mioa701_wm9713.c19
-rw-r--r--sound/soc/pxa/poodle.c7
-rw-r--r--sound/soc/pxa/spitz.c58
-rw-r--r--sound/soc/pxa/tosa.c67
-rw-r--r--sound/soc/pxa/zylonite.c17
-rw-r--r--sound/soc/s6000/s6105-ipcam.c28
-rw-r--r--sound/soc/samsung/Kconfig8
-rw-r--r--sound/soc/samsung/h1940_uda1380.c7
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c168
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c5
-rw-r--r--sound/soc/samsung/smdk_wm8994.c2
-rw-r--r--sound/soc/samsung/tobermory.c2
-rw-r--r--sound/soc/sh/fsi.c2
-rw-r--r--sound/soc/sh/migor.c19
-rw-r--r--sound/soc/sh/rcar/Makefile2
-rw-r--r--sound/soc/sh/rcar/adg.c229
-rw-r--r--sound/soc/sh/rcar/core.c426
-rw-r--r--sound/soc/sh/rcar/gen.c113
-rw-r--r--sound/soc/sh/rcar/rsnd.h206
-rw-r--r--sound/soc/sh/rcar/scu.c384
-rw-r--r--sound/soc/sh/rcar/src.c727
-rw-r--r--sound/soc/sh/rcar/ssi.c388
-rw-r--r--sound/soc/sirf/Kconfig14
-rw-r--r--sound/soc/sirf/Makefile5
-rw-r--r--sound/soc/sirf/sirf-audio-port.c194
-rw-r--r--sound/soc/sirf/sirf-audio-port.h62
-rw-r--r--sound/soc/sirf/sirf-audio.c156
-rw-r--r--sound/soc/soc-cache.c13
-rw-r--r--sound/soc/soc-compress.c65
-rw-r--r--sound/soc/soc-core.c606
-rw-r--r--sound/soc/soc-dapm.c604
-rw-r--r--sound/soc/soc-io.c99
-rw-r--r--sound/soc/soc-jack.c5
-rw-r--r--sound/soc/soc-pcm.c109
-rw-r--r--sound/soc/spear/spdif_out.c10
-rw-r--r--sound/soc/tegra/Kconfig2
-rw-r--r--sound/soc/tegra/tegra20_ac97.c17
-rw-r--r--sound/soc/tegra/tegra20_ac97.h1
-rw-r--r--sound/soc/tegra/tegra20_das.c2
-rw-r--r--sound/soc/tegra/tegra20_i2s.c2
-rw-r--r--sound/soc/tegra/tegra20_spdif.c2
-rw-r--r--sound/soc/tegra/tegra30_ahub.c4
-rw-r--r--sound/soc/tegra/tegra30_i2s.c2
-rw-r--r--sound/soc/tegra/tegra_wm9712.c17
-rw-r--r--sound/soc/txx9/txx9aclc-ac97.c8
-rw-r--r--sound/sparc/amd7930.c4
-rw-r--r--sound/sparc/cs4231.c11
-rw-r--r--sound/sparc/dbri.c4
-rw-r--r--sound/spi/at73c213.c6
-rw-r--r--sound/usb/6fire/chip.c13
-rw-r--r--sound/usb/6fire/comm.c4
-rw-r--r--sound/usb/6fire/control.c18
-rw-r--r--sound/usb/6fire/firmware.c70
-rw-r--r--sound/usb/6fire/midi.c12
-rw-r--r--sound/usb/6fire/pcm.c46
-rw-r--r--sound/usb/caiaq/device.c6
-rw-r--r--sound/usb/card.c69
-rw-r--r--sound/usb/clock.c65
-rw-r--r--sound/usb/endpoint.c32
-rw-r--r--sound/usb/format.c68
-rw-r--r--sound/usb/hiface/chip.c10
-rw-r--r--sound/usb/midi.c45
-rw-r--r--sound/usb/misc/ua101.c7
-rw-r--r--sound/usb/mixer.c226
-rw-r--r--sound/usb/mixer.h7
-rw-r--r--sound/usb/mixer_maps.c9
-rw-r--r--sound/usb/mixer_quirks.c10
-rw-r--r--sound/usb/pcm.c83
-rw-r--r--sound/usb/quirks.c52
-rw-r--r--sound/usb/stream.c50
-rw-r--r--sound/usb/usbaudio.h9
-rw-r--r--sound/usb/usx2y/us122l.c11
-rw-r--r--sound/usb/usx2y/usbusx2y.c13
-rw-r--r--sound/usb/usx2y/usbusx2y.h2
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c60
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c76
-rw-r--r--tools/Makefile11
-rw-r--r--tools/hv/Makefile13
-rw-r--r--tools/hv/hv_fcopy_daemon.c195
-rw-r--r--tools/hv/hv_vss_daemon.c2
-rw-r--r--tools/include/linux/hash.h5
-rw-r--r--tools/lib/api/Makefile2
-rw-r--r--tools/lib/api/fs/fs.c (renamed from tools/perf/util/fs.c)11
-rw-r--r--tools/lib/api/fs/fs.h (renamed from tools/perf/util/include/linux/magic.h)12
-rw-r--r--tools/lib/lockdep/Makefile6
-rw-r--r--tools/lib/lockdep/preload.c2
-rwxr-xr-x[-rw-r--r--]tools/lib/lockdep/run_tests.sh0
-rw-r--r--tools/lib/lockdep/uinclude/asm/hash.h6
-rw-r--r--tools/lib/lockdep/uinclude/linux/rcu.h5
-rw-r--r--tools/net/Makefile2
-rw-r--r--tools/perf/Documentation/perf-mem.txt4
-rw-r--r--tools/perf/Documentation/perf-probe.txt2
-rw-r--r--tools/perf/MANIFEST1
-rw-r--r--tools/perf/Makefile.perf42
-rw-r--r--tools/perf/arch/arm/Makefile2
-rw-r--r--tools/perf/arch/arm/util/unwind-libunwind.c (renamed from tools/perf/arch/arm/util/unwind.c)2
-rw-r--r--tools/perf/arch/x86/Makefile9
-rw-r--r--tools/perf/arch/x86/include/perf_regs.h6
-rw-r--r--tools/perf/arch/x86/tests/dwarf-unwind.c59
-rw-r--r--tools/perf/arch/x86/tests/regs_load.S92
-rw-r--r--tools/perf/arch/x86/util/unwind-libdw.c51
-rw-r--r--tools/perf/arch/x86/util/unwind-libunwind.c (renamed from tools/perf/arch/x86/util/unwind.c)4
-rw-r--r--tools/perf/bench/bench.h3
-rw-r--r--tools/perf/bench/futex-hash.c212
-rw-r--r--tools/perf/bench/futex-requeue.c211
-rw-r--r--tools/perf/bench/futex-wake.c201
-rw-r--r--tools/perf/bench/futex.h71
-rw-r--r--tools/perf/bench/numa.c1
-rw-r--r--tools/perf/builtin-bench.c14
-rw-r--r--tools/perf/builtin-diff.c7
-rw-r--r--tools/perf/builtin-inject.c1
-rw-r--r--tools/perf/builtin-kvm.c12
-rw-r--r--tools/perf/builtin-probe.c12
-rw-r--r--tools/perf/builtin-record.c30
-rw-r--r--tools/perf/builtin-report.c68
-rw-r--r--tools/perf/builtin-sched.c10
-rw-r--r--tools/perf/builtin-timechart.c4
-rw-r--r--tools/perf/builtin-top.c18
-rw-r--r--tools/perf/builtin-trace.c32
-rw-r--r--tools/perf/config/Makefile234
-rw-r--r--tools/perf/config/feature-checks/Makefile8
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c13
-rw-r--r--tools/perf/design.txt12
-rw-r--r--tools/perf/perf-completion.sh2
-rw-r--r--tools/perf/perf.h10
-rw-r--r--tools/perf/tests/builtin-test.c8
-rw-r--r--tools/perf/tests/dwarf-unwind.c144
-rw-r--r--tools/perf/tests/hists_link.c1
-rw-r--r--tools/perf/tests/make25
-rw-r--r--tools/perf/tests/parse-events.c2
-rw-r--r--tools/perf/tests/sample-parsing.c17
-rw-r--r--tools/perf/tests/tests.h9
-rw-r--r--tools/perf/ui/browsers/hists.c122
-rw-r--r--tools/perf/ui/gtk/hists.c78
-rw-r--r--tools/perf/ui/hist.c138
-rw-r--r--tools/perf/ui/stdio/hist.c11
-rw-r--r--tools/perf/util/annotate.c23
-rw-r--r--tools/perf/util/annotate.h2
-rw-r--r--tools/perf/util/cpumap.c2
-rw-r--r--tools/perf/util/dso.c4
-rw-r--r--tools/perf/util/dso.h10
-rw-r--r--tools/perf/util/event.c188
-rw-r--r--tools/perf/util/event.h5
-rw-r--r--tools/perf/util/evsel.c60
-rw-r--r--tools/perf/util/evsel.h18
-rw-r--r--tools/perf/util/fs.h7
-rw-r--r--tools/perf/util/hist.c13
-rw-r--r--tools/perf/util/hist.h29
-rw-r--r--tools/perf/util/include/linux/bitops.h4
-rw-r--r--tools/perf/util/include/linux/hash.h5
-rw-r--r--tools/perf/util/include/linux/kernel.h6
-rw-r--r--tools/perf/util/include/linux/list.h1
-rw-r--r--tools/perf/util/include/linux/prefetch.h6
-rw-r--r--tools/perf/util/machine.c79
-rw-r--r--tools/perf/util/machine.h13
-rw-r--r--tools/perf/util/map.h10
-rw-r--r--tools/perf/util/parse-events.c17
-rw-r--r--tools/perf/util/parse-options.c37
-rw-r--r--tools/perf/util/parse-options.h8
-rw-r--r--tools/perf/util/perf_regs.c19
-rw-r--r--tools/perf/util/perf_regs.h13
-rw-r--r--tools/perf/util/pmu.c2
-rw-r--r--tools/perf/util/probe-event.c865
-rw-r--r--tools/perf/util/probe-event.h12
-rw-r--r--tools/perf/util/probe-finder.c198
-rw-r--r--tools/perf/util/probe-finder.h5
-rw-r--r--tools/perf/util/python-ext-sources2
-rw-r--r--tools/perf/util/record.c2
-rw-r--r--tools/perf/util/session.c13
-rw-r--r--tools/perf/util/symbol-elf.c8
-rw-r--r--tools/perf/util/symbol.c65
-rw-r--r--tools/perf/util/symbol.h14
-rw-r--r--tools/perf/util/thread.c21
-rw-r--r--tools/perf/util/thread.h11
-rw-r--r--tools/perf/util/trace-event-parse.c1
-rw-r--r--tools/perf/util/unwind-libdw.c210
-rw-r--r--tools/perf/util/unwind-libdw.h21
-rw-r--r--tools/perf/util/unwind-libunwind.c (renamed from tools/perf/util/unwind.c)50
-rw-r--r--tools/perf/util/unwind.h11
-rw-r--r--tools/perf/util/util.c2
-rw-r--r--tools/testing/selftests/ipc/msgque.c1
-rw-r--r--tools/testing/selftests/powerpc/Makefile2
-rw-r--r--tools/testing/selftests/powerpc/copyloops/Makefile29
-rw-r--r--tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h86
-rw-r--r--tools/testing/selftests/powerpc/copyloops/asm/processor.h0
l---------tools/testing/selftests/powerpc/copyloops/copyuser_64.S1
l---------tools/testing/selftests/powerpc/copyloops/copyuser_power7.S1
l---------tools/testing/selftests/powerpc/copyloops/memcpy_64.S1
l---------tools/testing/selftests/powerpc/copyloops/memcpy_power7.S1
-rw-r--r--tools/testing/selftests/powerpc/copyloops/validate.c99
-rw-r--r--tools/testing/selftests/powerpc/utils.h3
-rw-r--r--tools/testing/selftests/rcutorture/bin/functions.sh1
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh51
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh51
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck.sh13
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh (renamed from tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh)53
-rw-r--r--tools/testing/selftests/rcutorture/bin/kvm.sh276
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/BUSTED6
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/BUSTED.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/CFLIST1
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/CFcommon2
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK016
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh43
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/BUSTED7
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/BUSTED.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/CFLIST (renamed from tools/testing/selftests/rcutorture/configs/CFLIST)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/CFcommon2
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-N (renamed from tools/testing/selftests/rcutorture/configs/SRCU-N)3
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-N.boot (renamed from tools/testing/selftests/rcutorture/configs/SRCU-N.boot)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-P (renamed from tools/testing/selftests/rcutorture/configs/SRCU-P)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-P.boot (renamed from tools/testing/selftests/rcutorture/configs/SRCU-P.boot)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TINY01 (renamed from tools/testing/selftests/rcutorture/configs/TINY01)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TINY02 (renamed from tools/testing/selftests/rcutorture/configs/TINY02)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE01 (renamed from tools/testing/selftests/rcutorture/configs/TREE01)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot (renamed from tools/testing/selftests/rcutorture/configs/TREE01.boot)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE02 (renamed from tools/testing/selftests/rcutorture/configs/TREE02)3
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE03 (renamed from tools/testing/selftests/rcutorture/configs/TREE03)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE04 (renamed from tools/testing/selftests/rcutorture/configs/TREE04)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot (renamed from tools/testing/selftests/rcutorture/configs/TREE04.boot)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE05 (renamed from tools/testing/selftests/rcutorture/configs/TREE05)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot (renamed from tools/testing/selftests/rcutorture/configs/TREE05.boot)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE06 (renamed from tools/testing/selftests/rcutorture/configs/TREE06)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE07 (renamed from tools/testing/selftests/rcutorture/configs/TREE07)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE08 (renamed from tools/testing/selftests/rcutorture/configs/TREE08)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE08-T (renamed from tools/testing/selftests/rcutorture/configs/TREE08-T)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE09 (renamed from tools/testing/selftests/rcutorture/configs/TREE09)1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/CFLIST (renamed from tools/testing/selftests/rcutorture/configs/v0.0/CFLIST)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v0.0/N1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v0.0/N2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v0.0/N3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v0.0/N4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v0.0/N5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v0.0/NT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT3-NH (renamed from tools/testing/selftests/rcutorture/configs/v0.0/NT3-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v0.0/P1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v0.0/P2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v0.0/P3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v0.0/P4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v0.0/P5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v0.0/PT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT2-NH (renamed from tools/testing/selftests/rcutorture/configs/v0.0/PT2-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/ver_functions.sh (renamed from tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh)22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/CFLIST (renamed from tools/testing/selftests/rcutorture/configs/v3.12/CFLIST)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N6---t-nh-SD-smp-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N7-4-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/N8-2-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v3.12/NT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT3-NH (renamed from tools/testing/selftests/rcutorture/configs/v3.12/NT3-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P6---t-nh-SD-smp-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-all)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-none)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v3.12/PT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT2-NH (renamed from tools/testing/selftests/rcutorture/configs/v3.12/PT2-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/CFLIST (renamed from tools/testing/selftests/rcutorture/configs/v3.3/CFLIST)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.3/N1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.3/N2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.3/N3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.3/N4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.3/N5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v3.3/NT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT3-NH (renamed from tools/testing/selftests/rcutorture/configs/v3.3/NT3-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.3/P1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.3/P2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.3/P3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.3/P4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.3/P5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v3.3/PT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT2-NH (renamed from tools/testing/selftests/rcutorture/configs/v3.3/PT2-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/ver_functions.sh (renamed from tools/testing/selftests/rcutorture/configs/ver_functions.sh)28
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/CFLIST (renamed from tools/testing/selftests/rcutorture/configs/v3.5/CFLIST)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.5/N1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.5/N2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.5/N3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.5/N4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.5/N5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v3.5/NT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT3-NH (renamed from tools/testing/selftests/rcutorture/configs/v3.5/NT3-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.5/P1-S-T-NH-SD-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.5/P2-2-t-nh-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.5/P3-3-T-nh-SD-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP (renamed from tools/testing/selftests/rcutorture/configs/v3.5/P4-A-t-NH-sd-SMP-HP)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp (renamed from tools/testing/selftests/rcutorture/configs/v3.5/P5-U-T-NH-sd-SMP-hp)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT1-nh (renamed from tools/testing/selftests/rcutorture/configs/v3.5/PT1-nh)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT2-NH (renamed from tools/testing/selftests/rcutorture/configs/v3.5/PT2-NH)0
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/ver_functions.sh (renamed from tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh)23
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh (renamed from tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh)26
-rw-r--r--tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt (renamed from tools/testing/selftests/rcutorture/doc/TREE_RCU-Kconfig.txt)0
-rw-r--r--tools/virtio/linux/kmemleak.h3
-rw-r--r--tools/virtio/linux/virtio.h4
-rw-r--r--tools/virtio/virtio_test.c2
-rw-r--r--virt/kvm/Kconfig4
-rw-r--r--virt/kvm/async_pf.c27
-rw-r--r--virt/kvm/eventfd.c8
-rw-r--r--virt/kvm/ioapic.c108
-rw-r--r--virt/kvm/kvm_main.c14
5049 files changed, 197138 insertions, 119302 deletions
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 07de7e19b4ce..27e67a98b7be 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -413,8 +413,6 @@ serial-console.txt
- how to set up Linux with a serial line console as the default.
sgi-ioc4.txt
- description of the SGI IOC4 PCI (multi function) device.
-sgi-visws.txt
- - short blurb on the SGI Visual Workstations.
sh/
- directory with info on porting Linux to a new architecture.
smsc_ece1099.txt
diff --git a/Documentation/ABI/stable/sysfs-firmware-opal-dump b/Documentation/ABI/stable/sysfs-firmware-opal-dump
new file mode 100644
index 000000000000..32fe7f5c4880
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-firmware-opal-dump
@@ -0,0 +1,41 @@
+What: /sys/firmware/opal/dump
+Date: Feb 2014
+Contact: Stewart Smith <stewart@linux.vnet.ibm.com>
+Description:
+ This directory exposes interfaces for interacting with
+ the FSP and platform dumps through OPAL firmware interface.
+
+ This is only for the powerpc/powernv platform.
+
+ initiate_dump: When '1' is written to it,
+ we will initiate a dump.
+ Read this file for supported commands.
+
+ 0xXX-0xYYYY: A directory for dump of type 0xXX and
+ id 0xYYYY (in hex). The name of this
+ directory should not be relied upon to
+ be in this format, only that it's unique
+ among all dumps. For determining the type
+ and ID of the dump, use the id and type files.
+ Do not rely on any particular size of dump
+ type or dump id.
+
+ Each dump has the following files:
+ id: An ASCII representation of the dump ID
+ in hex (e.g. '0x01')
+ type: An ASCII representation of the type of
+ dump in the format "0x%x %s" with the ID
+ in hex and a description of the dump type
+ (or 'unknown').
+ Type '0xffffffff unknown' is used when
+ we could not get the type from firmware.
+ e.g. '0x02 System/Platform Dump'
+ dump: A binary file containing the dump.
+ The size of the dump is the size of this file.
+ acknowledge: When 'ack' is written to this, we will
+ acknowledge that we've retrieved the
+ dump to the service processor. It will
+ then remove it, making the dump
+ inaccessible.
+ Reading this file will get a list of
+ supported actions.
diff --git a/Documentation/ABI/stable/sysfs-firmware-opal-elog b/Documentation/ABI/stable/sysfs-firmware-opal-elog
new file mode 100644
index 000000000000..e1f3058f5954
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-firmware-opal-elog
@@ -0,0 +1,60 @@
+What: /sys/firmware/opal/elog
+Date: Feb 2014
+Contact: Stewart Smith <stewart@linux.vnet.ibm.com>
+Description:
+ This directory exposes error log entries retrieved
+ through the OPAL firmware interface.
+
+ Each error log is identified by a unique ID and will
+ exist until explicitly acknowledged to firmware.
+
+ Each log entry has a directory in /sys/firmware/opal/elog.
+
+ Log entries may be purged by the service processor
+ before retrieved by firmware or retrieved/acknowledged by
+ Linux if there is no room for more log entries.
+
+ In the event that Linux has retrieved the log entries
+ but not explicitly acknowledged them to firmware and
+ the service processor needs more room for log entries,
+ the only remaining copy of a log message may be in
+ Linux.
+
+ Typically, a user space daemon will monitor for new
+ entries, read them out and acknowledge them.
+
+ The service processor may be able to store more log
+ entries than firmware can, so after you acknowledge
+ an event from Linux you may instantly get another one
+ from the queue that was generated some time in the past.
+
+ The raw log format is a binary format. We currently
+ do not parse this at all in kernel, leaving it up to
+ user space to solve the problem. In future, we may
+ do more parsing in kernel and add more files to make
+ it easier for simple user space processes to extract
+ more information.
+
+ For each log entry (directory), there are the following
+ files:
+
+ id: An ASCII representation of the ID of the
+ error log, in hex - e.g. "0x01".
+
+ type: An ASCII representation of the type id and
+ description of the type of error log.
+ Currently just "0x00 PEL" - platform error log.
+ In the future there may be additional types.
+
+ raw: A read-only binary file that can be read
+ to get the raw log entry. These are
+ <16kb, often just hundreds of bytes and
+ "average" 2kb.
+
+ acknowledge: Writing 'ack' to this file will acknowledge
+ the error log to firmware (and in turn
+ the service processor, if applicable).
+ Shortly after acknowledging it, the log
+ entry will be removed from sysfs.
+ Reading this file will list the supported
+ operations (curently just acknowledge). \ No newline at end of file
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-events b/Documentation/ABI/testing/sysfs-bus-event_source-devices-events
index 3c1cc24361bd..7b40a3cbc26a 100644
--- a/Documentation/ABI/testing/sysfs-bus-event_source-devices-events
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-events
@@ -57,6 +57,523 @@ What: /sys/devices/cpu/events/PM_1PLUS_PPC_CMPL
/sys/devices/cpu/events/PM_LD_REF_L1
/sys/devices/cpu/events/PM_RUN_CYC
/sys/devices/cpu/events/PM_RUN_INST_CMPL
+ /sys/devices/cpu/events/PM_IC_DEMAND_L2_BR_ALL
+ /sys/devices/cpu/events/PM_GCT_UTIL_7_TO_10_SLOTS
+ /sys/devices/cpu/events/PM_PMC2_SAVED
+ /sys/devices/cpu/events/PM_VSU0_16FLOP
+ /sys/devices/cpu/events/PM_MRK_LSU_DERAT_MISS
+ /sys/devices/cpu/events/PM_MRK_ST_CMPL
+ /sys/devices/cpu/events/PM_NEST_PAIR3_ADD
+ /sys/devices/cpu/events/PM_L2_ST_DISP
+ /sys/devices/cpu/events/PM_L2_CASTOUT_MOD
+ /sys/devices/cpu/events/PM_ISEG
+ /sys/devices/cpu/events/PM_MRK_INST_TIMEO
+ /sys/devices/cpu/events/PM_L2_RCST_DISP_FAIL_ADDR
+ /sys/devices/cpu/events/PM_LSU1_DC_PREF_STREAM_CONFIRM
+ /sys/devices/cpu/events/PM_IERAT_WR_64K
+ /sys/devices/cpu/events/PM_MRK_DTLB_MISS_16M
+ /sys/devices/cpu/events/PM_IERAT_MISS
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_LMEM
+ /sys/devices/cpu/events/PM_FLOP
+ /sys/devices/cpu/events/PM_THRD_PRIO_4_5_CYC
+ /sys/devices/cpu/events/PM_BR_PRED_TA
+ /sys/devices/cpu/events/PM_EXT_INT
+ /sys/devices/cpu/events/PM_VSU_FSQRT_FDIV
+ /sys/devices/cpu/events/PM_MRK_LD_MISS_EXPOSED_CYC
+ /sys/devices/cpu/events/PM_LSU1_LDF
+ /sys/devices/cpu/events/PM_IC_WRITE_ALL
+ /sys/devices/cpu/events/PM_LSU0_SRQ_STFWD
+ /sys/devices/cpu/events/PM_PTEG_FROM_RL2L3_MOD
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_DATA_FROM_L21_MOD
+ /sys/devices/cpu/events/PM_VSU1_SCAL_DOUBLE_ISSUED
+ /sys/devices/cpu/events/PM_VSU0_8FLOP
+ /sys/devices/cpu/events/PM_POWER_EVENT1
+ /sys/devices/cpu/events/PM_DISP_CLB_HELD_BAL
+ /sys/devices/cpu/events/PM_VSU1_2FLOP
+ /sys/devices/cpu/events/PM_LWSYNC_HELD
+ /sys/devices/cpu/events/PM_PTEG_FROM_DL2L3_SHR
+ /sys/devices/cpu/events/PM_INST_FROM_L21_MOD
+ /sys/devices/cpu/events/PM_IERAT_XLATE_WR_16MPLUS
+ /sys/devices/cpu/events/PM_IC_REQ_ALL
+ /sys/devices/cpu/events/PM_DSLB_MISS
+ /sys/devices/cpu/events/PM_L3_MISS
+ /sys/devices/cpu/events/PM_LSU0_L1_PREF
+ /sys/devices/cpu/events/PM_VSU_SCALAR_SINGLE_ISSUED
+ /sys/devices/cpu/events/PM_LSU1_DC_PREF_STREAM_CONFIRM_STRIDE
+ /sys/devices/cpu/events/PM_L2_INST
+ /sys/devices/cpu/events/PM_VSU0_FRSP
+ /sys/devices/cpu/events/PM_FLUSH_DISP
+ /sys/devices/cpu/events/PM_PTEG_FROM_L2MISS
+ /sys/devices/cpu/events/PM_VSU1_DQ_ISSUED
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_DMEM
+ /sys/devices/cpu/events/PM_LSU_FLUSH_ULD
+ /sys/devices/cpu/events/PM_PTEG_FROM_LMEM
+ /sys/devices/cpu/events/PM_MRK_DERAT_MISS_16M
+ /sys/devices/cpu/events/PM_THRD_ALL_RUN_CYC
+ /sys/devices/cpu/events/PM_MEM0_PREFETCH_DISP
+ /sys/devices/cpu/events/PM_MRK_STALL_CMPLU_CYC_COUNT
+ /sys/devices/cpu/events/PM_DATA_FROM_DL2L3_MOD
+ /sys/devices/cpu/events/PM_VSU_FRSP
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L21_MOD
+ /sys/devices/cpu/events/PM_PMC1_OVERFLOW
+ /sys/devices/cpu/events/PM_VSU0_SINGLE
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L3MISS
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_VSU0_VECTOR_SP_ISSUED
+ /sys/devices/cpu/events/PM_VSU1_FEST
+ /sys/devices/cpu/events/PM_MRK_INST_DISP
+ /sys/devices/cpu/events/PM_VSU0_COMPLEX_ISSUED
+ /sys/devices/cpu/events/PM_LSU1_FLUSH_UST
+ /sys/devices/cpu/events/PM_FXU_IDLE
+ /sys/devices/cpu/events/PM_LSU0_FLUSH_ULD
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_DL2L3_MOD
+ /sys/devices/cpu/events/PM_LSU_LMQ_SRQ_EMPTY_ALL_CYC
+ /sys/devices/cpu/events/PM_LSU1_REJECT_LMQ_FULL
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L21_MOD
+ /sys/devices/cpu/events/PM_INST_FROM_RL2L3_MOD
+ /sys/devices/cpu/events/PM_SHL_CREATED
+ /sys/devices/cpu/events/PM_L2_ST_HIT
+ /sys/devices/cpu/events/PM_DATA_FROM_DMEM
+ /sys/devices/cpu/events/PM_L3_LD_MISS
+ /sys/devices/cpu/events/PM_FXU1_BUSY_FXU0_IDLE
+ /sys/devices/cpu/events/PM_DISP_CLB_HELD_RES
+ /sys/devices/cpu/events/PM_L2_SN_SX_I_DONE
+ /sys/devices/cpu/events/PM_STCX_CMPL
+ /sys/devices/cpu/events/PM_VSU0_2FLOP
+ /sys/devices/cpu/events/PM_L3_PREF_MISS
+ /sys/devices/cpu/events/PM_LSU_SRQ_SYNC_CYC
+ /sys/devices/cpu/events/PM_LSU_REJECT_ERAT_MISS
+ /sys/devices/cpu/events/PM_L1_ICACHE_MISS
+ /sys/devices/cpu/events/PM_LSU1_FLUSH_SRQ
+ /sys/devices/cpu/events/PM_LD_REF_L1_LSU0
+ /sys/devices/cpu/events/PM_VSU0_FEST
+ /sys/devices/cpu/events/PM_VSU_VECTOR_SINGLE_ISSUED
+ /sys/devices/cpu/events/PM_FREQ_UP
+ /sys/devices/cpu/events/PM_DATA_FROM_LMEM
+ /sys/devices/cpu/events/PM_LSU1_LDX
+ /sys/devices/cpu/events/PM_PMC3_OVERFLOW
+ /sys/devices/cpu/events/PM_MRK_BR_MPRED
+ /sys/devices/cpu/events/PM_SHL_MATCH
+ /sys/devices/cpu/events/PM_MRK_BR_TAKEN
+ /sys/devices/cpu/events/PM_ISLB_MISS
+ /sys/devices/cpu/events/PM_DISP_HELD_THERMAL
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_RL2L3_SHR
+ /sys/devices/cpu/events/PM_LSU1_SRQ_STFWD
+ /sys/devices/cpu/events/PM_PTEG_FROM_DMEM
+ /sys/devices/cpu/events/PM_VSU_2FLOP
+ /sys/devices/cpu/events/PM_GCT_FULL_CYC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L3_CYC
+ /sys/devices/cpu/events/PM_LSU_SRQ_S0_ALLOC
+ /sys/devices/cpu/events/PM_MRK_DERAT_MISS_4K
+ /sys/devices/cpu/events/PM_BR_MPRED_TA
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L2MISS
+ /sys/devices/cpu/events/PM_DPU_HELD_POWER
+ /sys/devices/cpu/events/PM_MRK_VSU_FIN
+ /sys/devices/cpu/events/PM_LSU_SRQ_S0_VALID
+ /sys/devices/cpu/events/PM_GCT_EMPTY_CYC
+ /sys/devices/cpu/events/PM_IOPS_DISP
+ /sys/devices/cpu/events/PM_RUN_SPURR
+ /sys/devices/cpu/events/PM_PTEG_FROM_L21_MOD
+ /sys/devices/cpu/events/PM_VSU0_1FLOP
+ /sys/devices/cpu/events/PM_SNOOP_TLBIE
+ /sys/devices/cpu/events/PM_DATA_FROM_L3MISS
+ /sys/devices/cpu/events/PM_VSU_SINGLE
+ /sys/devices/cpu/events/PM_DTLB_MISS_16G
+ /sys/devices/cpu/events/PM_FLUSH
+ /sys/devices/cpu/events/PM_L2_LD_HIT
+ /sys/devices/cpu/events/PM_NEST_PAIR2_AND
+ /sys/devices/cpu/events/PM_VSU1_1FLOP
+ /sys/devices/cpu/events/PM_IC_PREF_REQ
+ /sys/devices/cpu/events/PM_L3_LD_HIT
+ /sys/devices/cpu/events/PM_DISP_HELD
+ /sys/devices/cpu/events/PM_L2_LD
+ /sys/devices/cpu/events/PM_LSU_FLUSH_SRQ
+ /sys/devices/cpu/events/PM_BC_PLUS_8_CONV
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L31_MOD_CYC
+ /sys/devices/cpu/events/PM_L2_RCST_BUSY_RC_FULL
+ /sys/devices/cpu/events/PM_TB_BIT_TRANS
+ /sys/devices/cpu/events/PM_THERMAL_MAX
+ /sys/devices/cpu/events/PM_LSU1_FLUSH_ULD
+ /sys/devices/cpu/events/PM_LSU1_REJECT_LHS
+ /sys/devices/cpu/events/PM_LSU_LRQ_S0_ALLOC
+ /sys/devices/cpu/events/PM_L3_CO_L31
+ /sys/devices/cpu/events/PM_POWER_EVENT4
+ /sys/devices/cpu/events/PM_DATA_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_BR_UNCOND
+ /sys/devices/cpu/events/PM_LSU1_DC_PREF_STREAM_ALLOC
+ /sys/devices/cpu/events/PM_PMC4_REWIND
+ /sys/devices/cpu/events/PM_L2_RCLD_DISP
+ /sys/devices/cpu/events/PM_THRD_PRIO_2_3_CYC
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L2MISS
+ /sys/devices/cpu/events/PM_IC_DEMAND_L2_BHT_REDIRECT
+ /sys/devices/cpu/events/PM_DATA_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_IC_PREF_CANCEL_L2
+ /sys/devices/cpu/events/PM_MRK_FIN_STALL_CYC_COUNT
+ /sys/devices/cpu/events/PM_BR_PRED_CCACHE
+ /sys/devices/cpu/events/PM_GCT_UTIL_1_TO_2_SLOTS
+ /sys/devices/cpu/events/PM_MRK_ST_CMPL_INT
+ /sys/devices/cpu/events/PM_LSU_TWO_TABLEWALK_CYC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L3MISS
+ /sys/devices/cpu/events/PM_LSU_SET_MPRED
+ /sys/devices/cpu/events/PM_FLUSH_DISP_TLBIE
+ /sys/devices/cpu/events/PM_VSU1_FCONV
+ /sys/devices/cpu/events/PM_DERAT_MISS_16G
+ /sys/devices/cpu/events/PM_INST_FROM_LMEM
+ /sys/devices/cpu/events/PM_IC_DEMAND_L2_BR_REDIRECT
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L2
+ /sys/devices/cpu/events/PM_PTEG_FROM_L2
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L21_SHR_CYC
+ /sys/devices/cpu/events/PM_MRK_DTLB_MISS_4K
+ /sys/devices/cpu/events/PM_VSU0_FPSCR
+ /sys/devices/cpu/events/PM_VSU1_VECT_DOUBLE_ISSUED
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_RL2L3_MOD
+ /sys/devices/cpu/events/PM_MEM0_RQ_DISP
+ /sys/devices/cpu/events/PM_L2_LD_MISS
+ /sys/devices/cpu/events/PM_VMX_RESULT_SAT_1
+ /sys/devices/cpu/events/PM_L1_PREF
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_LMEM_CYC
+ /sys/devices/cpu/events/PM_GRP_IC_MISS_NONSPEC
+ /sys/devices/cpu/events/PM_PB_NODE_PUMP
+ /sys/devices/cpu/events/PM_SHL_MERGED
+ /sys/devices/cpu/events/PM_NEST_PAIR1_ADD
+ /sys/devices/cpu/events/PM_DATA_FROM_L3
+ /sys/devices/cpu/events/PM_LSU_FLUSH
+ /sys/devices/cpu/events/PM_LSU_SRQ_SYNC_COUNT
+ /sys/devices/cpu/events/PM_PMC2_OVERFLOW
+ /sys/devices/cpu/events/PM_LSU_LDF
+ /sys/devices/cpu/events/PM_POWER_EVENT3
+ /sys/devices/cpu/events/PM_DISP_WT
+ /sys/devices/cpu/events/PM_IC_BANK_CONFLICT
+ /sys/devices/cpu/events/PM_BR_MPRED_CR_TA
+ /sys/devices/cpu/events/PM_L2_INST_MISS
+ /sys/devices/cpu/events/PM_NEST_PAIR2_ADD
+ /sys/devices/cpu/events/PM_MRK_LSU_FLUSH
+ /sys/devices/cpu/events/PM_L2_LDST
+ /sys/devices/cpu/events/PM_INST_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_VSU0_FIN
+ /sys/devices/cpu/events/PM_VSU1_FCONV
+ /sys/devices/cpu/events/PM_INST_FROM_RMEM
+ /sys/devices/cpu/events/PM_DISP_CLB_HELD_TLBIE
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_DMEM_CYC
+ /sys/devices/cpu/events/PM_BR_PRED_CR
+ /sys/devices/cpu/events/PM_LSU_REJECT
+ /sys/devices/cpu/events/PM_GCT_UTIL_3_TO_6_SLOTS
+ /sys/devices/cpu/events/PM_CMPLU_STALL_END_GCT_NOSLOT
+ /sys/devices/cpu/events/PM_LSU0_REJECT_LMQ_FULL
+ /sys/devices/cpu/events/PM_VSU_FEST
+ /sys/devices/cpu/events/PM_NEST_PAIR0_AND
+ /sys/devices/cpu/events/PM_PTEG_FROM_L3
+ /sys/devices/cpu/events/PM_POWER_EVENT2
+ /sys/devices/cpu/events/PM_IC_PREF_CANCEL_PAGE
+ /sys/devices/cpu/events/PM_VSU0_FSQRT_FDIV
+ /sys/devices/cpu/events/PM_MRK_GRP_CMPL
+ /sys/devices/cpu/events/PM_VSU0_SCAL_DOUBLE_ISSUED
+ /sys/devices/cpu/events/PM_GRP_DISP
+ /sys/devices/cpu/events/PM_LSU0_LDX
+ /sys/devices/cpu/events/PM_DATA_FROM_L2
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_RL2L3_MOD
+ /sys/devices/cpu/events/PM_VSU0_VECT_DOUBLE_ISSUED
+ /sys/devices/cpu/events/PM_VSU1_2FLOP_DOUBLE
+ /sys/devices/cpu/events/PM_THRD_PRIO_6_7_CYC
+ /sys/devices/cpu/events/PM_BC_PLUS_8_RSLV_TAKEN
+ /sys/devices/cpu/events/PM_BR_MPRED_CR
+ /sys/devices/cpu/events/PM_L3_CO_MEM
+ /sys/devices/cpu/events/PM_DATA_FROM_RL2L3_MOD
+ /sys/devices/cpu/events/PM_LSU_SRQ_FULL_CYC
+ /sys/devices/cpu/events/PM_TABLEWALK_CYC
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_RMEM
+ /sys/devices/cpu/events/PM_LSU_SRQ_STFWD
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_RMEM
+ /sys/devices/cpu/events/PM_FXU0_FIN
+ /sys/devices/cpu/events/PM_LSU1_L1_SW_PREF
+ /sys/devices/cpu/events/PM_PTEG_FROM_L31_MOD
+ /sys/devices/cpu/events/PM_PMC5_OVERFLOW
+ /sys/devices/cpu/events/PM_LD_REF_L1_LSU1
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L21_SHR
+ /sys/devices/cpu/events/PM_DATA_FROM_RMEM
+ /sys/devices/cpu/events/PM_VSU0_SCAL_SINGLE_ISSUED
+ /sys/devices/cpu/events/PM_BR_MPRED_LSTACK
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_RL2L3_MOD_CYC
+ /sys/devices/cpu/events/PM_LSU0_FLUSH_UST
+ /sys/devices/cpu/events/PM_LSU_NCST
+ /sys/devices/cpu/events/PM_BR_TAKEN
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_LMEM
+ /sys/devices/cpu/events/PM_DTLB_MISS_4K
+ /sys/devices/cpu/events/PM_PMC4_SAVED
+ /sys/devices/cpu/events/PM_VSU1_PERMUTE_ISSUED
+ /sys/devices/cpu/events/PM_SLB_MISS
+ /sys/devices/cpu/events/PM_LSU1_FLUSH_LRQ
+ /sys/devices/cpu/events/PM_DTLB_MISS
+ /sys/devices/cpu/events/PM_VSU1_FRSP
+ /sys/devices/cpu/events/PM_VSU_VECTOR_DOUBLE_ISSUED
+ /sys/devices/cpu/events/PM_L2_CASTOUT_SHR
+ /sys/devices/cpu/events/PM_DATA_FROM_DL2L3_SHR
+ /sys/devices/cpu/events/PM_VSU1_STF
+ /sys/devices/cpu/events/PM_ST_FIN
+ /sys/devices/cpu/events/PM_PTEG_FROM_L21_SHR
+ /sys/devices/cpu/events/PM_L2_LOC_GUESS_WRONG
+ /sys/devices/cpu/events/PM_MRK_STCX_FAIL
+ /sys/devices/cpu/events/PM_LSU0_REJECT_LHS
+ /sys/devices/cpu/events/PM_IC_PREF_CANCEL_HIT
+ /sys/devices/cpu/events/PM_L3_PREF_BUSY
+ /sys/devices/cpu/events/PM_MRK_BRU_FIN
+ /sys/devices/cpu/events/PM_LSU1_NCLD
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L31_MOD
+ /sys/devices/cpu/events/PM_LSU_NCLD
+ /sys/devices/cpu/events/PM_LSU_LDX
+ /sys/devices/cpu/events/PM_L2_LOC_GUESS_CORRECT
+ /sys/devices/cpu/events/PM_THRESH_TIMEO
+ /sys/devices/cpu/events/PM_L3_PREF_ST
+ /sys/devices/cpu/events/PM_DISP_CLB_HELD_SYNC
+ /sys/devices/cpu/events/PM_VSU_SIMPLE_ISSUED
+ /sys/devices/cpu/events/PM_VSU1_SINGLE
+ /sys/devices/cpu/events/PM_DATA_TABLEWALK_CYC
+ /sys/devices/cpu/events/PM_L2_RC_ST_DONE
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L21_MOD
+ /sys/devices/cpu/events/PM_LARX_LSU1
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_RMEM
+ /sys/devices/cpu/events/PM_DISP_CLB_HELD
+ /sys/devices/cpu/events/PM_DERAT_MISS_4K
+ /sys/devices/cpu/events/PM_L2_RCLD_DISP_FAIL_ADDR
+ /sys/devices/cpu/events/PM_SEG_EXCEPTION
+ /sys/devices/cpu/events/PM_FLUSH_DISP_SB
+ /sys/devices/cpu/events/PM_L2_DC_INV
+ /sys/devices/cpu/events/PM_PTEG_FROM_DL2L3_MOD
+ /sys/devices/cpu/events/PM_DSEG
+ /sys/devices/cpu/events/PM_BR_PRED_LSTACK
+ /sys/devices/cpu/events/PM_VSU0_STF
+ /sys/devices/cpu/events/PM_LSU_FX_FIN
+ /sys/devices/cpu/events/PM_DERAT_MISS_16M
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_DL2L3_MOD
+ /sys/devices/cpu/events/PM_GCT_UTIL_11_PLUS_SLOTS
+ /sys/devices/cpu/events/PM_INST_FROM_L3
+ /sys/devices/cpu/events/PM_MRK_IFU_FIN
+ /sys/devices/cpu/events/PM_ITLB_MISS
+ /sys/devices/cpu/events/PM_VSU_STF
+ /sys/devices/cpu/events/PM_LSU_FLUSH_UST
+ /sys/devices/cpu/events/PM_L2_LDST_MISS
+ /sys/devices/cpu/events/PM_FXU1_FIN
+ /sys/devices/cpu/events/PM_SHL_DEALLOCATED
+ /sys/devices/cpu/events/PM_L2_SN_M_WR_DONE
+ /sys/devices/cpu/events/PM_LSU_REJECT_SET_MPRED
+ /sys/devices/cpu/events/PM_L3_PREF_LD
+ /sys/devices/cpu/events/PM_L2_SN_M_RD_DONE
+ /sys/devices/cpu/events/PM_MRK_DERAT_MISS_16G
+ /sys/devices/cpu/events/PM_VSU_FCONV
+ /sys/devices/cpu/events/PM_ANY_THRD_RUN_CYC
+ /sys/devices/cpu/events/PM_LSU_LMQ_FULL_CYC
+ /sys/devices/cpu/events/PM_MRK_LSU_REJECT_LHS
+ /sys/devices/cpu/events/PM_MRK_LD_MISS_L1_CYC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L2_CYC
+ /sys/devices/cpu/events/PM_INST_IMC_MATCH_DISP
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_RMEM_CYC
+ /sys/devices/cpu/events/PM_VSU0_SIMPLE_ISSUED
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_RL2L3_SHR
+ /sys/devices/cpu/events/PM_VSU_FMA_DOUBLE
+ /sys/devices/cpu/events/PM_VSU_4FLOP
+ /sys/devices/cpu/events/PM_VSU1_FIN
+ /sys/devices/cpu/events/PM_NEST_PAIR1_AND
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_RL2L3_MOD
+ /sys/devices/cpu/events/PM_PTEG_FROM_RMEM
+ /sys/devices/cpu/events/PM_LSU_LRQ_S0_VALID
+ /sys/devices/cpu/events/PM_LSU0_LDF
+ /sys/devices/cpu/events/PM_FLUSH_COMPLETION
+ /sys/devices/cpu/events/PM_ST_MISS_L1
+ /sys/devices/cpu/events/PM_L2_NODE_PUMP
+ /sys/devices/cpu/events/PM_INST_FROM_DL2L3_SHR
+ /sys/devices/cpu/events/PM_MRK_STALL_CMPLU_CYC
+ /sys/devices/cpu/events/PM_VSU1_DENORM
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L31_SHR_CYC
+ /sys/devices/cpu/events/PM_NEST_PAIR0_ADD
+ /sys/devices/cpu/events/PM_INST_FROM_L3MISS
+ /sys/devices/cpu/events/PM_EE_OFF_EXT_INT
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_DMEM
+ /sys/devices/cpu/events/PM_INST_FROM_DL2L3_MOD
+ /sys/devices/cpu/events/PM_PMC6_OVERFLOW
+ /sys/devices/cpu/events/PM_VSU_2FLOP_DOUBLE
+ /sys/devices/cpu/events/PM_TLB_MISS
+ /sys/devices/cpu/events/PM_FXU_BUSY
+ /sys/devices/cpu/events/PM_L2_RCLD_DISP_FAIL_OTHER
+ /sys/devices/cpu/events/PM_LSU_REJECT_LMQ_FULL
+ /sys/devices/cpu/events/PM_IC_RELOAD_SHR
+ /sys/devices/cpu/events/PM_GRP_MRK
+ /sys/devices/cpu/events/PM_MRK_ST_NEST
+ /sys/devices/cpu/events/PM_VSU1_FSQRT_FDIV
+ /sys/devices/cpu/events/PM_LSU0_FLUSH_LRQ
+ /sys/devices/cpu/events/PM_LARX_LSU0
+ /sys/devices/cpu/events/PM_IBUF_FULL_CYC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_DL2L3_SHR_CYC
+ /sys/devices/cpu/events/PM_LSU_DC_PREF_STREAM_ALLOC
+ /sys/devices/cpu/events/PM_GRP_MRK_CYC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_RL2L3_SHR_CYC
+ /sys/devices/cpu/events/PM_L2_GLOB_GUESS_CORRECT
+ /sys/devices/cpu/events/PM_LSU_REJECT_LHS
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_LMEM
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L3
+ /sys/devices/cpu/events/PM_FREQ_DOWN
+ /sys/devices/cpu/events/PM_PB_RETRY_NODE_PUMP
+ /sys/devices/cpu/events/PM_INST_FROM_RL2L3_SHR
+ /sys/devices/cpu/events/PM_MRK_INST_ISSUED
+ /sys/devices/cpu/events/PM_PTEG_FROM_L3MISS
+ /sys/devices/cpu/events/PM_RUN_PURR
+ /sys/devices/cpu/events/PM_MRK_GRP_IC_MISS
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L3
+ /sys/devices/cpu/events/PM_PTEG_FROM_RL2L3_SHR
+ /sys/devices/cpu/events/PM_LSU_FLUSH_LRQ
+ /sys/devices/cpu/events/PM_MRK_DERAT_MISS_64K
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_DL2L3_MOD
+ /sys/devices/cpu/events/PM_L2_ST_MISS
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L21_SHR
+ /sys/devices/cpu/events/PM_LWSYNC
+ /sys/devices/cpu/events/PM_LSU0_DC_PREF_STREAM_CONFIRM_STRIDE
+ /sys/devices/cpu/events/PM_MRK_LSU_FLUSH_LRQ
+ /sys/devices/cpu/events/PM_INST_IMC_MATCH_CMPL
+ /sys/devices/cpu/events/PM_NEST_PAIR3_AND
+ /sys/devices/cpu/events/PM_PB_RETRY_SYS_PUMP
+ /sys/devices/cpu/events/PM_MRK_INST_FIN
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_DL2L3_SHR
+ /sys/devices/cpu/events/PM_INST_FROM_L31_MOD
+ /sys/devices/cpu/events/PM_MRK_DTLB_MISS_64K
+ /sys/devices/cpu/events/PM_LSU_FIN
+ /sys/devices/cpu/events/PM_MRK_LSU_REJECT
+ /sys/devices/cpu/events/PM_L2_CO_FAIL_BUSY
+ /sys/devices/cpu/events/PM_MEM0_WQ_DISP
+ /sys/devices/cpu/events/PM_DATA_FROM_L31_MOD
+ /sys/devices/cpu/events/PM_THERMAL_WARN
+ /sys/devices/cpu/events/PM_VSU0_4FLOP
+ /sys/devices/cpu/events/PM_BR_MPRED_CCACHE
+ /sys/devices/cpu/events/PM_L1_DEMAND_WRITE
+ /sys/devices/cpu/events/PM_FLUSH_BR_MPRED
+ /sys/devices/cpu/events/PM_MRK_DTLB_MISS_16G
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_DMEM
+ /sys/devices/cpu/events/PM_L2_RCST_DISP
+ /sys/devices/cpu/events/PM_LSU_PARTIAL_CDF
+ /sys/devices/cpu/events/PM_DISP_CLB_HELD_SB
+ /sys/devices/cpu/events/PM_VSU0_FMA_DOUBLE
+ /sys/devices/cpu/events/PM_FXU0_BUSY_FXU1_IDLE
+ /sys/devices/cpu/events/PM_IC_DEMAND_CYC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L21_SHR
+ /sys/devices/cpu/events/PM_MRK_LSU_FLUSH_UST
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L3MISS
+ /sys/devices/cpu/events/PM_VSU_DENORM
+ /sys/devices/cpu/events/PM_MRK_LSU_PARTIAL_CDF
+ /sys/devices/cpu/events/PM_INST_FROM_L21_SHR
+ /sys/devices/cpu/events/PM_IC_PREF_WRITE
+ /sys/devices/cpu/events/PM_BR_PRED
+ /sys/devices/cpu/events/PM_INST_FROM_DMEM
+ /sys/devices/cpu/events/PM_IC_PREF_CANCEL_ALL
+ /sys/devices/cpu/events/PM_LSU_DC_PREF_STREAM_CONFIRM
+ /sys/devices/cpu/events/PM_MRK_LSU_FLUSH_SRQ
+ /sys/devices/cpu/events/PM_MRK_FIN_STALL_CYC
+ /sys/devices/cpu/events/PM_L2_RCST_DISP_FAIL_OTHER
+ /sys/devices/cpu/events/PM_VSU1_DD_ISSUED
+ /sys/devices/cpu/events/PM_PTEG_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_DATA_FROM_L21_SHR
+ /sys/devices/cpu/events/PM_LSU0_NCLD
+ /sys/devices/cpu/events/PM_VSU1_4FLOP
+ /sys/devices/cpu/events/PM_VSU1_8FLOP
+ /sys/devices/cpu/events/PM_VSU_8FLOP
+ /sys/devices/cpu/events/PM_LSU_LMQ_SRQ_EMPTY_CYC
+ /sys/devices/cpu/events/PM_DTLB_MISS_64K
+ /sys/devices/cpu/events/PM_THRD_CONC_RUN_INST
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L2
+ /sys/devices/cpu/events/PM_PB_SYS_PUMP
+ /sys/devices/cpu/events/PM_VSU_FIN
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L31_MOD
+ /sys/devices/cpu/events/PM_THRD_PRIO_0_1_CYC
+ /sys/devices/cpu/events/PM_DERAT_MISS_64K
+ /sys/devices/cpu/events/PM_PMC2_REWIND
+ /sys/devices/cpu/events/PM_INST_FROM_L2
+ /sys/devices/cpu/events/PM_GRP_BR_MPRED_NONSPEC
+ /sys/devices/cpu/events/PM_INST_DISP
+ /sys/devices/cpu/events/PM_MEM0_RD_CANCEL_TOTAL
+ /sys/devices/cpu/events/PM_LSU0_DC_PREF_STREAM_CONFIRM
+ /sys/devices/cpu/events/PM_L1_DCACHE_RELOAD_VALID
+ /sys/devices/cpu/events/PM_VSU_SCALAR_DOUBLE_ISSUED
+ /sys/devices/cpu/events/PM_L3_PREF_HIT
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L31_MOD
+ /sys/devices/cpu/events/PM_MRK_FXU_FIN
+ /sys/devices/cpu/events/PM_PMC4_OVERFLOW
+ /sys/devices/cpu/events/PM_MRK_PTEG_FROM_L3
+ /sys/devices/cpu/events/PM_LSU0_LMQ_LHR_MERGE
+ /sys/devices/cpu/events/PM_BTAC_HIT
+ /sys/devices/cpu/events/PM_L3_RD_BUSY
+ /sys/devices/cpu/events/PM_LSU0_L1_SW_PREF
+ /sys/devices/cpu/events/PM_INST_FROM_L2MISS
+ /sys/devices/cpu/events/PM_LSU0_DC_PREF_STREAM_ALLOC
+ /sys/devices/cpu/events/PM_L2_ST
+ /sys/devices/cpu/events/PM_VSU0_DENORM
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_DL2L3_SHR
+ /sys/devices/cpu/events/PM_BR_PRED_CR_TA
+ /sys/devices/cpu/events/PM_VSU0_FCONV
+ /sys/devices/cpu/events/PM_MRK_LSU_FLUSH_ULD
+ /sys/devices/cpu/events/PM_BTAC_MISS
+ /sys/devices/cpu/events/PM_MRK_LD_MISS_EXPOSED_CYC_COUNT
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L2
+ /sys/devices/cpu/events/PM_LSU_DCACHE_RELOAD_VALID
+ /sys/devices/cpu/events/PM_VSU_FMA
+ /sys/devices/cpu/events/PM_LSU0_FLUSH_SRQ
+ /sys/devices/cpu/events/PM_LSU1_L1_PREF
+ /sys/devices/cpu/events/PM_IOPS_CMPL
+ /sys/devices/cpu/events/PM_L2_SYS_PUMP
+ /sys/devices/cpu/events/PM_L2_RCLD_BUSY_RC_FULL
+ /sys/devices/cpu/events/PM_LSU_LMQ_S0_ALLOC
+ /sys/devices/cpu/events/PM_FLUSH_DISP_SYNC
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_DL2L3_MOD_CYC
+ /sys/devices/cpu/events/PM_L2_IC_INV
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L21_MOD_CYC
+ /sys/devices/cpu/events/PM_L3_PREF_LDST
+ /sys/devices/cpu/events/PM_LSU_SRQ_EMPTY_CYC
+ /sys/devices/cpu/events/PM_LSU_LMQ_S0_VALID
+ /sys/devices/cpu/events/PM_FLUSH_PARTIAL
+ /sys/devices/cpu/events/PM_VSU1_FMA_DOUBLE
+ /sys/devices/cpu/events/PM_1PLUS_PPC_DISP
+ /sys/devices/cpu/events/PM_DATA_FROM_L2MISS
+ /sys/devices/cpu/events/PM_SUSPENDED
+ /sys/devices/cpu/events/PM_VSU0_FMA
+ /sys/devices/cpu/events/PM_STCX_FAIL
+ /sys/devices/cpu/events/PM_VSU0_FSQRT_FDIV_DOUBLE
+ /sys/devices/cpu/events/PM_DC_PREF_DST
+ /sys/devices/cpu/events/PM_VSU1_SCAL_SINGLE_ISSUED
+ /sys/devices/cpu/events/PM_L3_HIT
+ /sys/devices/cpu/events/PM_L2_GLOB_GUESS_WRONG
+ /sys/devices/cpu/events/PM_MRK_DFU_FIN
+ /sys/devices/cpu/events/PM_INST_FROM_L1
+ /sys/devices/cpu/events/PM_IC_DEMAND_REQ
+ /sys/devices/cpu/events/PM_VSU1_FSQRT_FDIV_DOUBLE
+ /sys/devices/cpu/events/PM_VSU1_FMA
+ /sys/devices/cpu/events/PM_MRK_LD_MISS_L1
+ /sys/devices/cpu/events/PM_VSU0_2FLOP_DOUBLE
+ /sys/devices/cpu/events/PM_LSU_DC_PREF_STRIDED_STREAM_CONFIRM
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_L31_SHR
+ /sys/devices/cpu/events/PM_MRK_LSU_REJECT_ERAT_MISS
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_L2MISS
+ /sys/devices/cpu/events/PM_DATA_FROM_RL2L3_SHR
+ /sys/devices/cpu/events/PM_INST_FROM_PREF
+ /sys/devices/cpu/events/PM_VSU1_SQ
+ /sys/devices/cpu/events/PM_L2_LD_DISP
+ /sys/devices/cpu/events/PM_L2_DISP_ALL
+ /sys/devices/cpu/events/PM_THRD_GRP_CMPL_BOTH_CYC
+ /sys/devices/cpu/events/PM_VSU_FSQRT_FDIV_DOUBLE
+ /sys/devices/cpu/events/PM_INST_PTEG_FROM_DL2L3_SHR
+ /sys/devices/cpu/events/PM_VSU_1FLOP
+ /sys/devices/cpu/events/PM_HV_CYC
+ /sys/devices/cpu/events/PM_MRK_LSU_FIN
+ /sys/devices/cpu/events/PM_MRK_DATA_FROM_RL2L3_SHR
+ /sys/devices/cpu/events/PM_DTLB_MISS_16M
+ /sys/devices/cpu/events/PM_LSU1_LMQ_LHR_MERGE
+ /sys/devices/cpu/events/PM_IFU_FIN
+ /sys/devices/cpu/events/PM_1THRD_CON_RUN_INSTR
+ /sys/devices/cpu/events/PM_CMPLU_STALL_COUNT
+ /sys/devices/cpu/events/PM_MEM0_PB_RD_CL
+ /sys/devices/cpu/events/PM_THRD_1_RUN_CYC
+ /sys/devices/cpu/events/PM_THRD_2_CONC_RUN_INSTR
+ /sys/devices/cpu/events/PM_THRD_2_RUN_CYC
+ /sys/devices/cpu/events/PM_THRD_3_CONC_RUN_INST
+ /sys/devices/cpu/events/PM_THRD_3_RUN_CYC
+ /sys/devices/cpu/events/PM_THRD_4_CONC_RUN_INST
+ /sys/devices/cpu/events/PM_THRD_4_RUN_CYC
Date: 2013/01/08
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7 b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7
new file mode 100644
index 000000000000..e78ee798d7bd
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7
@@ -0,0 +1,23 @@
+What: /sys/bus/event_source/devices/hv_24x7/interface/catalog
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ Provides access to the binary "24x7 catalog" provided by the
+ hypervisor on POWER7 and 8 systems. This catalog lists events
+ avaliable from the powerpc "hv_24x7" pmu. Its format is
+ documented here:
+ https://raw.githubusercontent.com/jmesmon/catalog-24x7/master/hv-24x7-catalog.h
+
+What: /sys/bus/event_source/devices/hv_24x7/interface/catalog_length
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ A number equal to the length in bytes of the catalog. This is
+ also extractable from the provided binary "catalog" sysfs entry.
+
+What: /sys/bus/event_source/devices/hv_24x7/interface/catalog_version
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ Exposes the "version" field of the 24x7 catalog. This is also
+ extractable from the provided binary "catalog" sysfs entry.
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_gpci b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_gpci
new file mode 100644
index 000000000000..3fa58c23f13b
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_gpci
@@ -0,0 +1,43 @@
+What: /sys/bus/event_source/devices/hv_gpci/interface/collect_privileged
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ '0' if the hypervisor is configured to forbid access to event
+ counters being accumulated by other guests and to physical
+ domain event counters.
+ '1' if that access is allowed.
+
+What: /sys/bus/event_source/devices/hv_gpci/interface/ga
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ 0 or 1. Indicates whether we have access to "GA" events (listed
+ in arch/powerpc/perf/hv-gpci.h).
+
+What: /sys/bus/event_source/devices/hv_gpci/interface/expanded
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ 0 or 1. Indicates whether we have access to "EXPANDED" events (listed
+ in arch/powerpc/perf/hv-gpci.h).
+
+What: /sys/bus/event_source/devices/hv_gpci/interface/lab
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ 0 or 1. Indicates whether we have access to "LAB" events (listed
+ in arch/powerpc/perf/hv-gpci.h).
+
+What: /sys/bus/event_source/devices/hv_gpci/interface/version
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ A number indicating the version of the gpci interface that the
+ hypervisor reports supporting.
+
+What: /sys/bus/event_source/devices/hv_gpci/interface/kernel_version
+Date: February 2014
+Contact: Cody P Schafer <cody@linux.vnet.ibm.com>
+Description:
+ A number indicating the latest version of the gpci interface
+ that the kernel is aware of.
diff --git a/Documentation/ABI/testing/sysfs-class-scsi_host b/Documentation/ABI/testing/sysfs-class-scsi_host
index 29a4f892e433..0eb255e7db12 100644
--- a/Documentation/ABI/testing/sysfs-class-scsi_host
+++ b/Documentation/ABI/testing/sysfs-class-scsi_host
@@ -11,3 +11,19 @@ Description:
guaranteed. The 'isci_id' attribute unambiguously identifies
the controller index: '0' for the first controller,
'1' for the second.
+
+What: /sys/class/scsi_host/hostX/acciopath_status
+Date: November 2013
+Contact: Stephen M. Cameron <scameron@beardog.cce.hp.com>
+Description: This file contains the current status of the "SSD Smart Path"
+ feature of HP Smart Array RAID controllers using the hpsa
+ driver. SSD Smart Path, when enabled permits the driver to
+ send i/o requests directly to physical devices that are part
+ of a logical drive, bypassing the controllers firmware RAID
+ stack for a performance advantage when possible. A value of
+ '1' indicates the feature is enabled, and the controller may
+ use the direct i/o path to physical devices. A value of zero
+ means the feature is disabled and the controller may not use
+ the direct i/o path to physical devices. This setting is
+ controller wide, affecting all configured logical drives on the
+ controller. This file is readable and writable.
diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
index efe449bdf811..7dbf96b724ed 100644
--- a/Documentation/ABI/testing/sysfs-devices-power
+++ b/Documentation/ABI/testing/sysfs-devices-power
@@ -187,7 +187,7 @@ Description:
Not all drivers support this attribute. If it isn't supported,
attempts to read or write it will yield I/O errors.
-What: /sys/devices/.../power/pm_qos_latency_us
+What: /sys/devices/.../power/pm_qos_resume_latency_us
Date: March 2012
Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
Description:
@@ -205,6 +205,31 @@ Description:
This attribute has no effect on system-wide suspend/resume and
hibernation.
+What: /sys/devices/.../power/pm_qos_latency_tolerance_us
+Date: January 2014
+Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+ The /sys/devices/.../power/pm_qos_latency_tolerance_us attribute
+ contains the PM QoS active state latency tolerance limit for the
+ given device in microseconds. That is the maximum memory access
+ latency the device can suffer without any visible adverse
+ effects on user space functionality. If that value is the
+ string "any", the latency does not matter to user space at all,
+ but hardware should not be allowed to set the latency tolerance
+ for the device automatically.
+
+ Reading "auto" from this file means that the maximum memory
+ access latency for the device may be determined automatically
+ by the hardware as needed. Writing "auto" to it allows the
+ hardware to be switched to this mode if there are no other
+ latency tolerance requirements from the kernel side.
+
+ This attribute is only present if the feature controlled by it
+ is supported by the hardware.
+
+ This attribute has no effect on runtime suspend and resume of
+ devices and on system-wide suspend/resume and hibernation.
+
What: /sys/devices/.../power/pm_qos_no_power_off
Date: September 2012
Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
diff --git a/Documentation/ABI/testing/sysfs-firmware-ofw b/Documentation/ABI/testing/sysfs-firmware-ofw
new file mode 100644
index 000000000000..f562b188e71d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-ofw
@@ -0,0 +1,28 @@
+What: /sys/firmware/devicetree/*
+Date: November 2013
+Contact: Grant Likely <grant.likely@linaro.org>
+Description:
+ When using OpenFirmware or a Flattened Device Tree to enumerate
+ hardware, the device tree structure will be exposed in this
+ directory.
+
+ It is possible for multiple device-tree directories to exist.
+ Some device drivers use a separate detached device tree which
+ have no attachment to the system tree and will appear in a
+ different subdirectory under /sys/firmware/devicetree.
+
+ Userspace must not use the /sys/firmware/devicetree/base
+ path directly, but instead should follow /proc/device-tree
+ symlink. It is possible that the absolute path will change
+ in the future, but the symlink is the stable ABI.
+
+ The /proc/device-tree symlink replaces the devicetree /proc
+ filesystem support, and has largely the same semantics and
+ should be compatible with existing userspace.
+
+ The contents of /sys/firmware/devicetree/ is a
+ hierarchy of directories, one per device tree node. The
+ directory name is the resolved path component name (node
+ name plus address). Properties are represented as files
+ in the directory. The contents of each file is the exact
+ binary data from the device tree.
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index 205a73878441..64c9276e9421 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -12,8 +12,9 @@ Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
Description:
The /sys/power/state file controls the system power state.
Reading from this file returns what states are supported,
- which is hard-coded to 'standby' (Power-On Suspend), 'mem'
- (Suspend-to-RAM), and 'disk' (Suspend-to-Disk).
+ which is hard-coded to 'freeze' (Low-Power Idle), 'standby'
+ (Power-On Suspend), 'mem' (Suspend-to-RAM), and 'disk'
+ (Suspend-to-Disk).
Writing to this file one of these strings causes the system to
transition into that state. Please see the file
diff --git a/Documentation/ABI/testing/sysfs-tty b/Documentation/ABI/testing/sysfs-tty
index a2ccec35ffce..ad22fb0ee765 100644
--- a/Documentation/ABI/testing/sysfs-tty
+++ b/Documentation/ABI/testing/sysfs-tty
@@ -3,8 +3,7 @@ Date: Nov 2010
Contact: Kay Sievers <kay.sievers@vrfy.org>
Description:
Shows the list of currently configured
- tty devices used for the console,
- like 'tty1 ttyS0'.
+ console devices, like 'tty1 ttyS0'.
The last entry in the file is the active
device connected to /dev/console.
The file supports poll() to detect virtual
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 0f9c6ff41aac..8d96ebf524e9 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -14,7 +14,7 @@ DOCBOOKS := z8530book.xml device-drivers.xml \
genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
80211.xml debugobjects.xml sh.xml regulator.xml \
alsa-driver-api.xml writing-an-alsa-driver.xml \
- tracepoint.xml drm.xml media_api.xml
+ tracepoint.xml drm.xml media_api.xml w1.xml
include $(srctree)/Documentation/DocBook/media/Makefile
diff --git a/Documentation/DocBook/w1.tmpl b/Documentation/DocBook/w1.tmpl
new file mode 100644
index 000000000000..b0228d4c81bb
--- /dev/null
+++ b/Documentation/DocBook/w1.tmpl
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="w1id">
+ <bookinfo>
+ <title>W1: Dallas' 1-wire bus</title>
+
+ <authorgroup>
+ <author>
+ <firstname>David</firstname>
+ <surname>Fries</surname>
+ <affiliation>
+ <address>
+ <email>David@Fries.net</email>
+ </address>
+ </affiliation>
+ </author>
+
+ </authorgroup>
+
+ <copyright>
+ <year>2013</year>
+ <!--
+ <holder></holder>
+ -->
+ </copyright>
+
+ <legalnotice>
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License version 2.
+ </para>
+
+ <para>
+ 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.
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+ <toc></toc>
+
+ <chapter id="w1_internal">
+ <title>W1 API internal to the kernel</title>
+
+ <sect1 id="w1_internal_api">
+ <title>W1 API internal to the kernel</title>
+ <sect2 id="w1.h">
+ <title>drivers/w1/w1.h</title>
+ <para>W1 core functions.</para>
+!Idrivers/w1/w1.h
+ </sect2>
+
+ <sect2 id="w1.c">
+ <title>drivers/w1/w1.c</title>
+ <para>W1 core functions.</para>
+!Idrivers/w1/w1.c
+ </sect2>
+
+ <sect2 id="w1_family.h">
+ <title>drivers/w1/w1_family.h</title>
+ <para>Allows registering device family operations.</para>
+!Idrivers/w1/w1_family.h
+ </sect2>
+
+ <sect2 id="w1_family.c">
+ <title>drivers/w1/w1_family.c</title>
+ <para>Allows registering device family operations.</para>
+!Edrivers/w1/w1_family.c
+ </sect2>
+
+ <sect2 id="w1_int.c">
+ <title>drivers/w1/w1_int.c</title>
+ <para>W1 internal initialization for master devices.</para>
+!Edrivers/w1/w1_int.c
+ </sect2>
+
+ <sect2 id="w1_netlink.h">
+ <title>drivers/w1/w1_netlink.h</title>
+ <para>W1 external netlink API structures and commands.</para>
+!Idrivers/w1/w1_netlink.h
+ </sect2>
+
+ <sect2 id="w1_io.c">
+ <title>drivers/w1/w1_io.c</title>
+ <para>W1 input/output.</para>
+!Edrivers/w1/w1_io.c
+!Idrivers/w1/w1_io.c
+ </sect2>
+
+ </sect1>
+
+
+ </chapter>
+
+</book>
diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl
index 06741e925985..d0056a4e9c53 100644
--- a/Documentation/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl
@@ -468,8 +468,6 @@
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
return 0;
}
@@ -492,7 +490,8 @@
}
/* (2) */
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -591,7 +590,8 @@
struct snd_card *card;
int err;
....
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
]]>
</programlisting>
</informalexample>
@@ -809,28 +809,34 @@
<para>
As mentioned above, to create a card instance, call
- <function>snd_card_create()</function>.
+ <function>snd_card_new()</function>.
<informalexample>
<programlisting>
<![CDATA[
struct snd_card *card;
int err;
- err = snd_card_create(index, id, module, extra_size, &card);
+ err = snd_card_new(&pci->dev, index, id, module, extra_size, &card);
]]>
</programlisting>
</informalexample>
</para>
<para>
- The function takes five arguments, the card-index number, the
- id string, the module pointer (usually
+ The function takes six arguments: the parent device pointer,
+ the card-index number, the id string, the module pointer (usually
<constant>THIS_MODULE</constant>),
the size of extra-data space, and the pointer to return the
card instance. The extra_size argument is used to
allocate card-&gt;private_data for the
chip-specific data. Note that these data
- are allocated by <function>snd_card_create()</function>.
+ are allocated by <function>snd_card_new()</function>.
+ </para>
+
+ <para>
+ The first argument, the pointer of struct
+ <structname>device</structname>, specifies the parent device.
+ For PCI devices, typically &amp;pci-&gt; is passed there.
</para>
</section>
@@ -916,16 +922,16 @@
</para>
<section id="card-management-chip-specific-snd-card-new">
- <title>1. Allocating via <function>snd_card_create()</function>.</title>
+ <title>1. Allocating via <function>snd_card_new()</function>.</title>
<para>
As mentioned above, you can pass the extra-data-length
- to the 4th argument of <function>snd_card_create()</function>, i.e.
+ to the 5th argument of <function>snd_card_new()</function>, i.e.
<informalexample>
<programlisting>
<![CDATA[
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct mychip), &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct mychip), &card);
]]>
</programlisting>
</informalexample>
@@ -954,7 +960,7 @@
<para>
After allocating a card instance via
- <function>snd_card_create()</function> (with
+ <function>snd_card_new()</function> (with
<constant>0</constant> on the 4th arg), call
<function>kzalloc()</function>.
@@ -963,7 +969,8 @@
<![CDATA[
struct snd_card *card;
struct mychip *chip;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
.....
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
]]>
@@ -1170,8 +1177,6 @@
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
return 0;
}
@@ -1526,30 +1531,6 @@
</section>
- <section id="pci-resource-device-struct">
- <title>Registration of Device Struct</title>
- <para>
- At some point, typically after calling <function>snd_device_new()</function>,
- you need to register the struct <structname>device</structname> of the chip
- you're handling for udev and co. ALSA provides a macro for compatibility with
- older kernels. Simply call like the following:
- <informalexample>
- <programlisting>
-<![CDATA[
- snd_card_set_dev(card, &pci->dev);
-]]>
- </programlisting>
- </informalexample>
- so that it stores the PCI's device pointer to the card. This will be
- referred by ALSA core functions later when the devices are registered.
- </para>
- <para>
- In the case of non-PCI, pass the proper device struct pointer of the BUS
- instead. (In the case of legacy ISA without PnP, you don't have to do
- anything.)
- </para>
- </section>
-
<section id="pci-resource-entries">
<title>PCI Entries</title>
<para>
@@ -5740,7 +5721,8 @@ struct _snd_pcm_runtime {
struct mychip *chip;
int err;
....
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
....
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
....
@@ -5752,7 +5734,7 @@ struct _snd_pcm_runtime {
</informalexample>
When you created the chip data with
- <function>snd_card_create()</function>, it's anyway accessible
+ <function>snd_card_new()</function>, it's anyway accessible
via <structfield>private_data</structfield> field.
<informalexample>
@@ -5766,8 +5748,8 @@ struct _snd_pcm_runtime {
struct mychip *chip;
int err;
....
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct mychip), &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct mychip), &card);
....
chip = card->private_data;
....
diff --git a/Documentation/PCI/MSI-HOWTO.txt b/Documentation/PCI/MSI-HOWTO.txt
index a8d01005f480..10a93696e55a 100644
--- a/Documentation/PCI/MSI-HOWTO.txt
+++ b/Documentation/PCI/MSI-HOWTO.txt
@@ -82,7 +82,19 @@ Most of the hard work is done for the driver in the PCI layer. It simply
has to request that the PCI layer set up the MSI capability for this
device.
-4.2.1 pci_enable_msi_range
+4.2.1 pci_enable_msi
+
+int pci_enable_msi(struct pci_dev *dev)
+
+A successful call allocates ONE interrupt to the device, regardless
+of how many MSIs the device supports. The device is switched from
+pin-based interrupt mode to MSI mode. The dev->irq number is changed
+to a new number which represents the message signaled interrupt;
+consequently, this function should be called before the driver calls
+request_irq(), because an MSI is delivered via a vector that is
+different from the vector of a pin-based interrupt.
+
+4.2.2 pci_enable_msi_range
int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
@@ -147,6 +159,11 @@ static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec)
return pci_enable_msi_range(pdev, nvec, nvec);
}
+Note, unlike pci_enable_msi_exact() function, which could be also used to
+enable a particular number of MSI-X interrupts, pci_enable_msi_range()
+returns either a negative errno or 'nvec' (not negative errno or 0 - as
+pci_enable_msi_exact() does).
+
4.2.1.3 Single MSI mode
The most notorious example of the request type described above is
@@ -158,7 +175,27 @@ static int foo_driver_enable_single_msi(struct pci_dev *pdev)
return pci_enable_msi_range(pdev, 1, 1);
}
-4.2.2 pci_disable_msi
+Note, unlike pci_enable_msi() function, which could be also used to
+enable the single MSI mode, pci_enable_msi_range() returns either a
+negative errno or 1 (not negative errno or 0 - as pci_enable_msi()
+does).
+
+4.2.3 pci_enable_msi_exact
+
+int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
+
+This variation on pci_enable_msi_range() call allows a device driver to
+request exactly 'nvec' MSIs.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to request any more MSI interrupts for
+this device.
+
+By contrast with pci_enable_msi_range() function, pci_enable_msi_exact()
+returns zero in case of success, which indicates MSI interrupts have been
+successfully allocated.
+
+4.2.4 pci_disable_msi
void pci_disable_msi(struct pci_dev *dev)
@@ -172,7 +209,7 @@ on any interrupt for which it previously called request_irq().
Failure to do so results in a BUG_ON(), leaving the device with
MSI enabled and thus leaking its vector.
-4.2.3 pci_msi_vec_count
+4.2.4 pci_msi_vec_count
int pci_msi_vec_count(struct pci_dev *dev)
@@ -257,8 +294,8 @@ possible, likely up to the limit returned by pci_msix_vec_count() function:
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
{
- return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
- 1, nvec);
+ return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+ 1, nvec);
}
Note the value of 'minvec' parameter is 1. As 'minvec' is inclusive,
@@ -269,8 +306,8 @@ In this case the function could look like this:
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
{
- return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
- FOO_DRIVER_MINIMUM_NVEC, nvec);
+ return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+ FOO_DRIVER_MINIMUM_NVEC, nvec);
}
4.3.1.2 Exact number of MSI-X interrupts
@@ -282,10 +319,15 @@ parameters:
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
{
- return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
- nvec, nvec);
+ return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+ nvec, nvec);
}
+Note, unlike pci_enable_msix_exact() function, which could be also used to
+enable a particular number of MSI-X interrupts, pci_enable_msix_range()
+returns either a negative errno or 'nvec' (not negative errno or 0 - as
+pci_enable_msix_exact() does).
+
4.3.1.3 Specific requirements to the number of MSI-X interrupts
As noted above, there could be devices that can not operate with just any
@@ -332,7 +374,64 @@ Note how pci_enable_msix_range() return value is analized for a fallback -
any error code other than -ENOSPC indicates a fatal error and should not
be retried.
-4.3.2 pci_disable_msix
+4.3.2 pci_enable_msix_exact
+
+int pci_enable_msix_exact(struct pci_dev *dev,
+ struct msix_entry *entries, int nvec)
+
+This variation on pci_enable_msix_range() call allows a device driver to
+request exactly 'nvec' MSI-Xs.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to allocate any more MSI-X interrupts for
+this device.
+
+By contrast with pci_enable_msix_range() function, pci_enable_msix_exact()
+returns zero in case of success, which indicates MSI-X interrupts have been
+successfully allocated.
+
+Another version of a routine that enables MSI-X mode for a device with
+specific requirements described in chapter 4.3.1.3 might look like this:
+
+/*
+ * Assume 'minvec' and 'maxvec' are non-zero
+ */
+static int foo_driver_enable_msix(struct foo_adapter *adapter,
+ int minvec, int maxvec)
+{
+ int rc;
+
+ minvec = roundup_pow_of_two(minvec);
+ maxvec = rounddown_pow_of_two(maxvec);
+
+ if (minvec > maxvec)
+ return -ERANGE;
+
+retry:
+ rc = pci_enable_msix_exact(adapter->pdev,
+ adapter->msix_entries, maxvec);
+
+ /*
+ * -ENOSPC is the only error code allowed to be analyzed
+ */
+ if (rc == -ENOSPC) {
+ if (maxvec == 1)
+ return -ENOSPC;
+
+ maxvec /= 2;
+
+ if (minvec > maxvec)
+ return -ENOSPC;
+
+ goto retry;
+ } else if (rc < 0) {
+ return rc;
+ }
+
+ return maxvec;
+}
+
+4.3.3 pci_disable_msix
void pci_disable_msix(struct pci_dev *dev)
diff --git a/Documentation/PCI/pci-iov-howto.txt b/Documentation/PCI/pci-iov-howto.txt
index 86551cc72e03..2d91ae251982 100644
--- a/Documentation/PCI/pci-iov-howto.txt
+++ b/Documentation/PCI/pci-iov-howto.txt
@@ -68,10 +68,6 @@ To disable SR-IOV capability:
echo 0 > \
/sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_numvfs
-To notify SR-IOV core of Virtual Function Migration:
-(a) In the driver:
- irqreturn_t pci_sriov_migration(struct pci_dev *dev);
-
3.2 Usage example
Following piece of code illustrates the usage of the SR-IOV API.
diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt
index 273e654d7d08..2f0fcb2112d2 100644
--- a/Documentation/RCU/RTFP.txt
+++ b/Documentation/RCU/RTFP.txt
@@ -31,6 +31,14 @@ has lapsed, so this approach may be used in non-GPL software, if desired.
(In contrast, implementation of RCU is permitted only in software licensed
under either GPL or LGPL. Sorry!!!)
+In 1987, Rashid et al. described lazy TLB-flush [RichardRashid87a].
+At first glance, this has nothing to do with RCU, but nevertheless
+this paper helped inspire the update-side batching used in the later
+RCU implementation in DYNIX/ptx. In 1988, Barbara Liskov published
+a description of Argus that noted that use of out-of-date values can
+be tolerated in some situations. Thus, this paper provides some early
+theoretical justification for use of stale data.
+
In 1990, Pugh [Pugh90] noted that explicitly tracking which threads
were reading a given data structure permitted deferred free to operate
in the presence of non-terminating threads. However, this explicit
@@ -41,11 +49,11 @@ providing a fine-grained locking design, however, it would be interesting
to see how much of the performance advantage reported in 1990 remains
today.
-At about this same time, Adams [Adams91] described ``chaotic relaxation'',
-where the normal barriers between successive iterations of convergent
-numerical algorithms are relaxed, so that iteration $n$ might use
-data from iteration $n-1$ or even $n-2$. This introduces error,
-which typically slows convergence and thus increases the number of
+At about this same time, Andrews [Andrews91textbook] described ``chaotic
+relaxation'', where the normal barriers between successive iterations
+of convergent numerical algorithms are relaxed, so that iteration $n$
+might use data from iteration $n-1$ or even $n-2$. This introduces
+error, which typically slows convergence and thus increases the number of
iterations required. However, this increase is sometimes more than made
up for by a reduction in the number of expensive barrier operations,
which are otherwise required to synchronize the threads at the end
@@ -55,7 +63,8 @@ is thus inapplicable to most data structures in operating-system kernels.
In 1992, Henry (now Alexia) Massalin completed a dissertation advising
parallel programmers to defer processing when feasible to simplify
-synchronization. RCU makes extremely heavy use of this advice.
+synchronization [HMassalinPhD]. RCU makes extremely heavy use of
+this advice.
In 1993, Jacobson [Jacobson93] verbally described what is perhaps the
simplest deferred-free technique: simply waiting a fixed amount of time
@@ -90,27 +99,29 @@ mechanism, which is quite similar to RCU [Gamsa99]. These operating
systems made pervasive use of RCU in place of "existence locks", which
greatly simplifies locking hierarchies and helps avoid deadlocks.
-2001 saw the first RCU presentation involving Linux [McKenney01a]
-at OLS. The resulting abundance of RCU patches was presented the
-following year [McKenney02a], and use of RCU in dcache was first
-described that same year [Linder02a].
+The year 2000 saw an email exchange that would likely have
+led to yet another independent invention of something like RCU
+[RustyRussell2000a,RustyRussell2000b]. Instead, 2001 saw the first
+RCU presentation involving Linux [McKenney01a] at OLS. The resulting
+abundance of RCU patches was presented the following year [McKenney02a],
+and use of RCU in dcache was first described that same year [Linder02a].
Also in 2002, Michael [Michael02b,Michael02a] presented "hazard-pointer"
techniques that defer the destruction of data structures to simplify
non-blocking synchronization (wait-free synchronization, lock-free
synchronization, and obstruction-free synchronization are all examples of
-non-blocking synchronization). In particular, this technique eliminates
-locking, reduces contention, reduces memory latency for readers, and
-parallelizes pipeline stalls and memory latency for writers. However,
-these techniques still impose significant read-side overhead in the
-form of memory barriers. Researchers at Sun worked along similar lines
-in the same timeframe [HerlihyLM02]. These techniques can be thought
-of as inside-out reference counts, where the count is represented by the
-number of hazard pointers referencing a given data structure rather than
-the more conventional counter field within the data structure itself.
-The key advantage of inside-out reference counts is that they can be
-stored in immortal variables, thus allowing races between access and
-deletion to be avoided.
+non-blocking synchronization). The corresponding journal article appeared
+in 2004 [MagedMichael04a]. This technique eliminates locking, reduces
+contention, reduces memory latency for readers, and parallelizes pipeline
+stalls and memory latency for writers. However, these techniques still
+impose significant read-side overhead in the form of memory barriers.
+Researchers at Sun worked along similar lines in the same timeframe
+[HerlihyLM02]. These techniques can be thought of as inside-out reference
+counts, where the count is represented by the number of hazard pointers
+referencing a given data structure rather than the more conventional
+counter field within the data structure itself. The key advantage
+of inside-out reference counts is that they can be stored in immortal
+variables, thus allowing races between access and deletion to be avoided.
By the same token, RCU can be thought of as a "bulk reference count",
where some form of reference counter covers all reference by a given CPU
@@ -123,8 +134,10 @@ can be thought of in other terms as well.
In 2003, the K42 group described how RCU could be used to create
hot-pluggable implementations of operating-system functions [Appavoo03a].
-Later that year saw a paper describing an RCU implementation of System
-V IPC [Arcangeli03], and an introduction to RCU in Linux Journal
+Later that year saw a paper describing an RCU implementation
+of System V IPC [Arcangeli03] (following up on a suggestion by
+Hugh Dickins [Dickins02a] and an implementation by Mingming Cao
+[MingmingCao2002IPCRCU]), and an introduction to RCU in Linux Journal
[McKenney03a].
2004 has seen a Linux-Journal article on use of RCU in dcache
@@ -383,6 +396,21 @@ for Programming Languages and Operating Systems}"
}
}
+@phdthesis{HMassalinPhD
+,author="H. Massalin"
+,title="Synthesis: An Efficient Implementation of Fundamental Operating
+System Services"
+,school="Columbia University"
+,address="New York, NY"
+,year="1992"
+,annotation={
+ Mondo optimizing compiler.
+ Wait-free stuff.
+ Good advice: defer work to avoid synchronization. See page 90
+ (PDF page 106), Section 5.4, fourth bullet point.
+}
+}
+
@unpublished{Jacobson93
,author="Van Jacobson"
,title="Avoid Read-Side Locking Via Delayed Free"
@@ -671,6 +699,20 @@ Orran Krieger and Rusty Russell and Dipankar Sarma and Maneesh Soni"
[Viewed October 18, 2004]"
}
+@conference{Michael02b
+,author="Maged M. Michael"
+,title="High Performance Dynamic Lock-Free Hash Tables and List-Based Sets"
+,Year="2002"
+,Month="August"
+,booktitle="{Proceedings of the 14\textsuperscript{th} Annual ACM
+Symposium on Parallel
+Algorithms and Architecture}"
+,pages="73-82"
+,annotation={
+Like the title says...
+}
+}
+
@Conference{Linder02a
,Author="Hanna Linder and Dipankar Sarma and Maneesh Soni"
,Title="Scalability of the Directory Entry Cache"
@@ -727,6 +769,24 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
}
}
+@conference{Michael02a
+,author="Maged M. Michael"
+,title="Safe Memory Reclamation for Dynamic Lock-Free Objects Using Atomic
+Reads and Writes"
+,Year="2002"
+,Month="August"
+,booktitle="{Proceedings of the 21\textsuperscript{st} Annual ACM
+Symposium on Principles of Distributed Computing}"
+,pages="21-30"
+,annotation={
+ Each thread keeps an array of pointers to items that it is
+ currently referencing. Sort of an inside-out garbage collection
+ mechanism, but one that requires the accessing code to explicitly
+ state its needs. Also requires read-side memory barriers on
+ most architectures.
+}
+}
+
@unpublished{Dickins02a
,author="Hugh Dickins"
,title="Use RCU for System-V IPC"
@@ -735,6 +795,17 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
,note="private communication"
}
+@InProceedings{HerlihyLM02
+,author={Maurice Herlihy and Victor Luchangco and Mark Moir}
+,title="The Repeat Offender Problem: A Mechanism for Supporting Dynamic-Sized,
+Lock-Free Data Structures"
+,booktitle={Proceedings of 16\textsuperscript{th} International
+Symposium on Distributed Computing}
+,year=2002
+,month="October"
+,pages="339-353"
+}
+
@unpublished{Sarma02b
,Author="Dipankar Sarma"
,Title="Some dcache\_rcu benchmark numbers"
@@ -749,6 +820,19 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
}
}
+@unpublished{MingmingCao2002IPCRCU
+,Author="Mingming Cao"
+,Title="[PATCH]updated ipc lock patch"
+,month="October"
+,year="2002"
+,note="Available:
+\url{https://lkml.org/lkml/2002/10/24/262}
+[Viewed February 15, 2014]"
+,annotation={
+ Mingming Cao's patch to introduce RCU to SysV IPC.
+}
+}
+
@unpublished{LinusTorvalds2003a
,Author="Linus Torvalds"
,Title="Re: {[PATCH]} small fixes in brlock.h"
@@ -982,6 +1066,23 @@ Realtime Applications"
}
}
+@article{MagedMichael04a
+,author="Maged M. Michael"
+,title="Hazard Pointers: Safe Memory Reclamation for Lock-Free Objects"
+,Year="2004"
+,Month="June"
+,journal="IEEE Transactions on Parallel and Distributed Systems"
+,volume="15"
+,number="6"
+,pages="491-504"
+,url="Available:
+\url{http://www.research.ibm.com/people/m/michael/ieeetpds-2004.pdf}
+[Viewed March 1, 2005]"
+,annotation={
+ New canonical hazard-pointer citation.
+}
+}
+
@phdthesis{PaulEdwardMcKenneyPhD
,author="Paul E. McKenney"
,title="Exploiting Deferred Destruction:
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index 91266193b8f4..9d10d1db16a5 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -256,10 +256,10 @@ over a rather long period of time, but improvements are always welcome!
variations on this theme.
b. Limiting update rate. For example, if updates occur only
- once per hour, then no explicit rate limiting is required,
- unless your system is already badly broken. The dcache
- subsystem takes this approach -- updates are guarded
- by a global lock, limiting their rate.
+ once per hour, then no explicit rate limiting is
+ required, unless your system is already badly broken.
+ Older versions of the dcache subsystem take this approach,
+ guarding updates with a global lock, limiting their rate.
c. Trusted update -- if updates can only be done manually by
superuser or some other trusted user, then it might not
@@ -268,7 +268,8 @@ over a rather long period of time, but improvements are always welcome!
the machine.
d. Use call_rcu_bh() rather than call_rcu(), in order to take
- advantage of call_rcu_bh()'s faster grace periods.
+ advantage of call_rcu_bh()'s faster grace periods. (This
+ is only a partial solution, though.)
e. Periodically invoke synchronize_rcu(), permitting a limited
number of updates per grace period.
@@ -276,6 +277,13 @@ over a rather long period of time, but improvements are always welcome!
The same cautions apply to call_rcu_bh(), call_rcu_sched(),
call_srcu(), and kfree_rcu().
+ Note that although these primitives do take action to avoid memory
+ exhaustion when any given CPU has too many callbacks, a determined
+ user could still exhaust memory. This is especially the case
+ if a system with a large number of CPUs has been configured to
+ offload all of its RCU callbacks onto a single CPU, or if the
+ system has relatively little free memory.
+
9. All RCU list-traversal primitives, which include
rcu_dereference(), list_for_each_entry_rcu(), and
list_for_each_safe_rcu(), must be either within an RCU read-side
diff --git a/Documentation/arm64/memory.txt b/Documentation/arm64/memory.txt
index 5e054bfe4dde..85e24c4f215c 100644
--- a/Documentation/arm64/memory.txt
+++ b/Documentation/arm64/memory.txt
@@ -35,11 +35,13 @@ ffffffbc00000000 ffffffbdffffffff 8GB vmemmap
ffffffbe00000000 ffffffbffbbfffff ~8GB [guard, future vmmemap]
-ffffffbffbc00000 ffffffbffbdfffff 2MB earlyprintk device
+ffffffbffa000000 ffffffbffaffffff 16MB PCI I/O space
+
+ffffffbffb000000 ffffffbffbbfffff 12MB [guard]
-ffffffbffbe00000 ffffffbffbe0ffff 64KB PCI I/O space
+ffffffbffbc00000 ffffffbffbdfffff 2MB earlyprintk device
-ffffffbffbe10000 ffffffbcffffffff ~2MB [guard]
+ffffffbffbe00000 ffffffbffbffffff 2MB [guard]
ffffffbffc000000 ffffffbfffffffff 64MB modules
@@ -60,11 +62,13 @@ fffffdfc00000000 fffffdfdffffffff 8GB vmemmap
fffffdfe00000000 fffffdfffbbfffff ~8GB [guard, future vmmemap]
-fffffdfffbc00000 fffffdfffbdfffff 2MB earlyprintk device
+fffffdfffa000000 fffffdfffaffffff 16MB PCI I/O space
+
+fffffdfffb000000 fffffdfffbbfffff 12MB [guard]
-fffffdfffbe00000 fffffdfffbe0ffff 64KB PCI I/O space
+fffffdfffbc00000 fffffdfffbdfffff 2MB earlyprintk device
-fffffdfffbe10000 fffffdfffbffffff ~2MB [guard]
+fffffdfffbe00000 fffffdfffbffffff 2MB [guard]
fffffdfffc000000 fffffdffffffffff 64MB modules
diff --git a/Documentation/blockdev/drbd/data-structure-v9.txt b/Documentation/blockdev/drbd/data-structure-v9.txt
new file mode 100644
index 000000000000..1e52a0e32624
--- /dev/null
+++ b/Documentation/blockdev/drbd/data-structure-v9.txt
@@ -0,0 +1,38 @@
+This describes the in kernel data structure for DRBD-9. Starting with
+Linux v3.14 we are reorganizing DRBD to use this data structure.
+
+Basic Data Structure
+====================
+
+A node has a number of DRBD resources. Each such resource has a number of
+devices (aka volumes) and connections to other nodes ("peer nodes"). Each DRBD
+device is represented by a block device locally.
+
+The DRBD objects are interconnected to form a matrix as depicted below; a
+drbd_peer_device object sits at each intersection between a drbd_device and a
+drbd_connection:
+
+ /--------------+---------------+.....+---------------\
+ | resource | device | | device |
+ +--------------+---------------+.....+---------------+
+ | connection | peer_device | | peer_device |
+ +--------------+---------------+.....+---------------+
+ : : : : :
+ : : : : :
+ +--------------+---------------+.....+---------------+
+ | connection | peer_device | | peer_device |
+ \--------------+---------------+.....+---------------/
+
+In this table, horizontally, devices can be accessed from resources by their
+volume number. Likewise, peer_devices can be accessed from connections by
+their volume number. Objects in the vertical direction are connected by double
+linked lists. There are back pointers from peer_devices to their connections a
+devices, and from connections and devices to their resource.
+
+All resources are in the drbd_resources double-linked list. In addition, all
+devices can be accessed by their minor device number via the drbd_devices idr.
+
+The drbd_resource, drbd_connection, and drbd_device objects are reference
+counted. The peer_device objects only serve to establish the links between
+devices and connections; their lifetime is determined by the lifetime of the
+device and connection which they reference.
diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c
index adcca0368d60..d12cc944b696 100644
--- a/Documentation/connector/cn_test.c
+++ b/Documentation/connector/cn_test.c
@@ -145,7 +145,7 @@ static void cn_test_timer_func(unsigned long __data)
memcpy(m + 1, data, m->len);
- cn_netlink_send(m, 0, GFP_ATOMIC);
+ cn_netlink_send(m, 0, 0, GFP_ATOMIC);
kfree(m);
}
diff --git a/Documentation/cpu-freq/core.txt b/Documentation/cpu-freq/core.txt
index ce0666e51036..0060d76b445f 100644
--- a/Documentation/cpu-freq/core.txt
+++ b/Documentation/cpu-freq/core.txt
@@ -92,7 +92,3 @@ values:
cpu - number of the affected CPU
old - old frequency
new - new frequency
-
-If the cpufreq core detects the frequency has changed while the system
-was suspended, these notifiers are called with CPUFREQ_RESUMECHANGE as
-second argument.
diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt
index 8b1a4451422e..48da5fdcb9f1 100644
--- a/Documentation/cpu-freq/cpu-drivers.txt
+++ b/Documentation/cpu-freq/cpu-drivers.txt
@@ -61,7 +61,13 @@ target_index - See below on the differences.
And optionally
-cpufreq_driver.exit - A pointer to a per-CPU cleanup function.
+cpufreq_driver.exit - A pointer to a per-CPU cleanup
+ function called during CPU_POST_DEAD
+ phase of cpu hotplug process.
+
+cpufreq_driver.stop_cpu - A pointer to a per-CPU stop function
+ called during CPU_DOWN_PREPARE phase of
+ cpu hotplug process.
cpufreq_driver.resume - A pointer to a per-CPU resume function
which is called with interrupts disabled
diff --git a/Documentation/device-mapper/cache.txt b/Documentation/device-mapper/cache.txt
index e6b72d355151..68c0f517c60e 100644
--- a/Documentation/device-mapper/cache.txt
+++ b/Documentation/device-mapper/cache.txt
@@ -124,12 +124,11 @@ the default being 204800 sectors (or 100MB).
Updating on-disk metadata
-------------------------
-On-disk metadata is committed every time a REQ_SYNC or REQ_FUA bio is
-written. If no such requests are made then commits will occur every
-second. This means the cache behaves like a physical disk that has a
-write cache (the same is true of the thin-provisioning target). If
-power is lost you may lose some recent writes. The metadata should
-always be consistent in spite of any crash.
+On-disk metadata is committed every time a FLUSH or FUA bio is written.
+If no such requests are made then commits will occur every second. This
+means the cache behaves like a physical disk that has a volatile write
+cache. If power is lost you may lose some recent writes. The metadata
+should always be consistent in spite of any crash.
The 'dirty' state for a cache block changes far too frequently for us
to keep updating it on the fly. So we treat it as a hint. In normal
diff --git a/Documentation/device-mapper/thin-provisioning.txt b/Documentation/device-mapper/thin-provisioning.txt
index 8a7a3d46e0da..05a27e9442bd 100644
--- a/Documentation/device-mapper/thin-provisioning.txt
+++ b/Documentation/device-mapper/thin-provisioning.txt
@@ -116,6 +116,35 @@ Resuming a device with a new table itself triggers an event so the
userspace daemon can use this to detect a situation where a new table
already exceeds the threshold.
+A low water mark for the metadata device is maintained in the kernel and
+will trigger a dm event if free space on the metadata device drops below
+it.
+
+Updating on-disk metadata
+-------------------------
+
+On-disk metadata is committed every time a FLUSH or FUA bio is written.
+If no such requests are made then commits will occur every second. This
+means the thin-provisioning target behaves like a physical disk that has
+a volatile write cache. If power is lost you may lose some recent
+writes. The metadata should always be consistent in spite of any crash.
+
+If data space is exhausted the pool will either error or queue IO
+according to the configuration (see: error_if_no_space). If metadata
+space is exhausted or a metadata operation fails: the pool will error IO
+until the pool is taken offline and repair is performed to 1) fix any
+potential inconsistencies and 2) clear the flag that imposes repair.
+Once the pool's metadata device is repaired it may be resized, which
+will allow the pool to return to normal operation. Note that if a pool
+is flagged as needing repair, the pool's data and metadata devices
+cannot be resized until repair is performed. It should also be noted
+that when the pool's metadata space is exhausted the current metadata
+transaction is aborted. Given that the pool will cache IO whose
+completion may have already been acknowledged to upper IO layers
+(e.g. filesystem) it is strongly suggested that consistency checks
+(e.g. fsck) be performed on those layers when repair of the pool is
+required.
+
Thin provisioning
-----------------
@@ -258,10 +287,9 @@ ii) Status
should register for the event and then check the target's status.
held metadata root:
- The location, in sectors, of the metadata root that has been
+ The location, in blocks, of the metadata root that has been
'held' for userspace read access. '-' indicates there is no
- held root. This feature is not yet implemented so '-' is
- always returned.
+ held root.
discard_passdown|no_discard_passdown
Whether or not discards are actually being passed down to the
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index 10378cc48374..087d2122b204 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -410,6 +410,7 @@ Your cooperation is appreciated.
194 = /dev/zkshim Zero-Knowledge network shim control
195 = /dev/elographics/e2201 Elographics touchscreen E271-2201
196 = /dev/vfio/vfio VFIO userspace driver interface
+ 197 = /dev/pxa3xx-gcu PXA3xx graphics controller unit driver
198 = /dev/sexec Signed executable interface
199 = /dev/scanners/cuecat :CueCat barcode scanner
200 = /dev/net/tun TAP/TUN network device
@@ -451,6 +452,7 @@ Your cooperation is appreciated.
236 = /dev/mapper/control Device-Mapper control device
237 = /dev/loop-control Loopback control device
238 = /dev/vhost-net Host kernel accelerator for virtio net
+ 239 = /dev/uhid User-space I/O driver support for HID subsystem
240-254 Reserved for local use
255 Reserved for MISC_DYNAMIC_MINOR
diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt b/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
index d74091a8a3bf..5fc03134a999 100644
--- a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
+++ b/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt
@@ -1,4 +1,4 @@
-Marvell Armada 370 and Armada XP Interrupt Controller
+Marvell Armada 370, 375, 38x, XP Interrupt Controller
-----------------------------------------------------
Required properties:
@@ -16,7 +16,13 @@ Required properties:
automatically map to the interrupt controller registers of the
current CPU)
+Optional properties:
+- interrupts: If defined, then it indicates that this MPIC is
+ connected as a slave to another interrupt controller. This is
+ typically the case on Armada 375 and Armada 38x, where the MPIC is
+ connected as a slave to the Cortex-A9 GIC. The provided interrupt
+ indicate to which GIC interrupt the MPIC output is connected.
Example:
diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index d1061469f63d..9a1175b46f49 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -5,6 +5,9 @@ Required properties:
<chip> can be "at91sam9260", "at91sam9g45" or "at91sam9x5"
- reg: Should contain ADC registers location and length
- interrupts: Should contain the IRQ line for the ADC
+ - clock-names: tuple listing input clock names.
+ Required elements: "adc_clk", "adc_op_clk".
+ - clocks: phandles to input clocks.
- atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
device
- atmel,adc-startup-time: Startup Time of the ADC in microseconds as
@@ -44,6 +47,8 @@ adc0: adc@fffb0000 {
compatible = "atmel,at91sam9260-adc";
reg = <0xfffb0000 0x100>;
interrupts = <20 4>;
+ clocks = <&adc_clk>, <&adc_op_clk>;
+ clock-names = "adc_clk", "adc_op_clk";
atmel,adc-channel-base = <0x30>;
atmel,adc-channels-used = <0xff>;
atmel,adc-drdy-mask = <0x10000>;
diff --git a/Documentation/devicetree/bindings/arm/marvell,dove.txt b/Documentation/devicetree/bindings/arm/marvell,dove.txt
new file mode 100644
index 000000000000..aaaf64c56e44
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/marvell,dove.txt
@@ -0,0 +1,22 @@
+Marvell Dove Platforms Device Tree Bindings
+-----------------------------------------------
+
+Boards with a Marvell Dove SoC shall have the following properties:
+
+Required root node property:
+- compatible: must contain "marvell,dove";
+
+* Global Configuration registers
+
+Global Configuration registers of Dove SoC are shared by a syscon node.
+
+Required properties:
+- compatible: must contain "marvell,dove-global-config" and "syscon".
+- reg: base address and size of the Global Configuration registers.
+
+Example:
+
+gconf: global-config@e802c {
+ compatible = "marvell,dove-global-config", "syscon";
+ reg = <0xe802c 0x14>;
+};
diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt
index 34dc40cffdfd..af9b4a0d902b 100644
--- a/Documentation/devicetree/bindings/arm/omap/omap.txt
+++ b/Documentation/devicetree/bindings/arm/omap/omap.txt
@@ -91,7 +91,7 @@ Boards:
compatible = "ti,omap3-beagle", "ti,omap3"
- OMAP3 Tobi with Overo : Commercial expansion board with daughter board
- compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3"
+ compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3"
- OMAP4 SDP : Software Development Board
compatible = "ti,omap4-sdp", "ti,omap4430"
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 89de1564950c..48b285ffa3a6 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -4,17 +4,33 @@ SATA nodes are defined to describe on-chip Serial ATA controllers.
Each SATA controller should have its own node.
Required properties:
-- compatible : compatible list, contains "snps,spear-ahci"
+- compatible : compatible list, one of "snps,spear-ahci",
+ "snps,exynos5440-ahci", "ibm,476gtr-ahci",
+ "allwinner,sun4i-a10-ahci", "fsl,imx53-ahci"
+ "fsl,imx6q-ahci" or "snps,dwc-ahci"
- interrupts : <interrupt mapping for SATA IRQ>
- reg : <registers mapping>
Optional properties:
- dma-coherent : Present if dma operations are coherent
+- clocks : a list of phandle + clock specifier pairs
+- target-supply : regulator for SATA target power
-Example:
+"fsl,imx53-ahci", "fsl,imx6q-ahci" required properties:
+- clocks : must contain the sata, sata_ref and ahb clocks
+- clock-names : must contain "ahb" for the ahb clock
+
+Examples:
sata@ffe08000 {
compatible = "snps,spear-ahci";
reg = <0xffe08000 0x1000>;
interrupts = <115>;
-
};
+
+ ahci: sata@01c18000 {
+ compatible = "allwinner,sun4i-a10-ahci";
+ reg = <0x01c18000 0x1000>;
+ interrupts = <56>;
+ clocks = <&pll6 0>, <&ahb_gates 25>;
+ target-supply = <&reg_ahci_5v>;
+ };
diff --git a/Documentation/devicetree/bindings/ata/apm-xgene.txt b/Documentation/devicetree/bindings/ata/apm-xgene.txt
new file mode 100644
index 000000000000..7bcfbf59810e
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/apm-xgene.txt
@@ -0,0 +1,76 @@
+* APM X-Gene 6.0 Gb/s SATA host controller nodes
+
+SATA host controller nodes are defined to describe on-chip Serial ATA
+controllers. Each SATA controller (pair of ports) have its own node.
+
+Required properties:
+- compatible : Shall contain:
+ * "apm,xgene-ahci"
+- reg : First memory resource shall be the AHCI memory
+ resource.
+ Second memory resource shall be the host controller
+ core memory resource.
+ Third memory resource shall be the host controller
+ diagnostic memory resource.
+ 4th memory resource shall be the host controller
+ AXI memory resource.
+ 5th optional memory resource shall be the host
+ controller MUX memory resource if required.
+- interrupts : Interrupt-specifier for SATA host controller IRQ.
+- clocks : Reference to the clock entry.
+- phys : A list of phandles + phy-specifiers, one for each
+ entry in phy-names.
+- phy-names : Should contain:
+ * "sata-phy" for the SATA 6.0Gbps PHY
+
+Optional properties:
+- status : Shall be "ok" if enabled or "disabled" if disabled.
+ Default is "ok".
+
+Example:
+ sataclk: sataclk {
+ compatible = "fixed-clock";
+ #clock-cells = <1>;
+ clock-frequency = <100000000>;
+ clock-output-names = "sataclk";
+ };
+
+ phy2: phy@1f22a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f22a000 0x0 0x100>;
+ #phy-cells = <1>;
+ };
+
+ phy3: phy@1f23a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f23a000 0x0 0x100>;
+ #phy-cells = <1>;
+ };
+
+ sata2: sata@1a400000 {
+ compatible = "apm,xgene-ahci";
+ reg = <0x0 0x1a400000 0x0 0x1000>,
+ <0x0 0x1f220000 0x0 0x1000>,
+ <0x0 0x1f22d000 0x0 0x1000>,
+ <0x0 0x1f22e000 0x0 0x1000>,
+ <0x0 0x1f227000 0x0 0x1000>;
+ interrupts = <0x0 0x87 0x4>;
+ status = "ok";
+ clocks = <&sataclk 0>;
+ phys = <&phy2 0>;
+ phy-names = "sata-phy";
+ };
+
+ sata3: sata@1a800000 {
+ compatible = "apm,xgene-ahci-pcie";
+ reg = <0x0 0x1a800000 0x0 0x1000>,
+ <0x0 0x1f230000 0x0 0x1000>,
+ <0x0 0x1f23d000 0x0 0x1000>,
+ <0x0 0x1f23e000 0x0 0x1000>,
+ <0x0 0x1f237000 0x0 0x1000>;
+ interrupts = <0x0 0x88 0x4>;
+ status = "ok";
+ clocks = <&sataclk 0>;
+ phys = <&phy3 0>;
+ phy-names = "sata-phy";
+ };
diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
index a6a352c2771e..5992dceec7af 100644
--- a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
@@ -21,9 +21,9 @@ Required Properties:
must appear in the same order as the output clocks.
- #clock-cells: Must be 1
- clock-output-names: The name of the clocks as free-form strings
- - renesas,indices: Indices of the gate clocks into the group (0 to 31)
+ - renesas,clock-indices: Indices of the gate clocks into the group (0 to 31)
-The clocks, clock-output-names and renesas,indices properties contain one
+The clocks, clock-output-names and renesas,clock-indices properties contain one
entry per gate clock. The MSTP groups are sparsely populated. Unimplemented
gate clocks must not be declared.
diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
index 68b83ecc3850..ee9be9961524 100644
--- a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
+++ b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
@@ -1,12 +1,16 @@
* Freescale Smart Direct Memory Access (SDMA) Controller for i.MX
Required properties:
-- compatible : Should be "fsl,imx31-sdma", "fsl,imx31-to1-sdma",
- "fsl,imx31-to2-sdma", "fsl,imx35-sdma", "fsl,imx35-to1-sdma",
- "fsl,imx35-to2-sdma", "fsl,imx51-sdma", "fsl,imx53-sdma" or
- "fsl,imx6q-sdma". The -to variants should be preferred since they
- allow to determnine the correct ROM script addresses needed for
- the driver to work without additional firmware.
+- compatible : Should be one of
+ "fsl,imx25-sdma"
+ "fsl,imx31-sdma", "fsl,imx31-to1-sdma", "fsl,imx31-to2-sdma"
+ "fsl,imx35-sdma", "fsl,imx35-to1-sdma", "fsl,imx35-to2-sdma"
+ "fsl,imx51-sdma"
+ "fsl,imx53-sdma"
+ "fsl,imx6q-sdma"
+ The -to variants should be preferred since they allow to determnine the
+ correct ROM script addresses needed for the driver to work without additional
+ firmware.
- reg : Should contain SDMA registers location and length
- interrupts : Should contain SDMA interrupt
- #dma-cells : Must be <3>.
diff --git a/Documentation/devicetree/bindings/graph.txt b/Documentation/devicetree/bindings/graph.txt
new file mode 100644
index 000000000000..1a69c078adf2
--- /dev/null
+++ b/Documentation/devicetree/bindings/graph.txt
@@ -0,0 +1,129 @@
+Common bindings for device graphs
+
+General concept
+---------------
+
+The hierarchical organisation of the device tree is well suited to describe
+control flow to devices, but there can be more complex connections between
+devices that work together to form a logical compound device, following an
+arbitrarily complex graph.
+There already is a simple directed graph between devices tree nodes using
+phandle properties pointing to other nodes to describe connections that
+can not be inferred from device tree parent-child relationships. The device
+tree graph bindings described herein abstract more complex devices that can
+have multiple specifiable ports, each of which can be linked to one or more
+ports of other devices.
+
+These common bindings do not contain any information about the direction or
+type of the connections, they just map their existence. Specific properties
+may be described by specialized bindings depending on the type of connection.
+
+To see how this binding applies to video pipelines, for example, see
+Documentation/device-tree/bindings/media/video-interfaces.txt.
+Here the ports describe data interfaces, and the links between them are
+the connecting data buses. A single port with multiple connections can
+correspond to multiple devices being connected to the same physical bus.
+
+Organisation of ports and endpoints
+-----------------------------------
+
+Ports are described by child 'port' nodes contained in the device node.
+Each port node contains an 'endpoint' subnode for each remote device port
+connected to this port. If a single port is connected to more than one
+remote device, an 'endpoint' child node must be provided for each link.
+If more than one port is present in a device node or there is more than one
+endpoint at a port, or a port node needs to be associated with a selected
+hardware interface, a common scheme using '#address-cells', '#size-cells'
+and 'reg' properties is used number the nodes.
+
+device {
+ ...
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ endpoint@0 {
+ reg = <0>;
+ ...
+ };
+ endpoint@1 {
+ reg = <1>;
+ ...
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ endpoint { ... };
+ };
+};
+
+All 'port' nodes can be grouped under an optional 'ports' node, which
+allows to specify #address-cells, #size-cells properties for the 'port'
+nodes independently from any other child device nodes a device might
+have.
+
+device {
+ ...
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ ...
+ endpoint@0 { ... };
+ endpoint@1 { ... };
+ };
+
+ port@1 { ... };
+ };
+};
+
+Links between endpoints
+-----------------------
+
+Each endpoint should contain a 'remote-endpoint' phandle property that points
+to the corresponding endpoint in the port of the remote device. In turn, the
+remote endpoint should contain a 'remote-endpoint' property. If it has one,
+it must not point to another than the local endpoint. Two endpoints with their
+'remote-endpoint' phandles pointing at each other form a link between the
+containing ports.
+
+device-1 {
+ port {
+ device_1_output: endpoint {
+ remote-endpoint = <&device_2_input>;
+ };
+ };
+};
+
+device-2 {
+ port {
+ device_2_input: endpoint {
+ remote-endpoint = <&device_1_output>;
+ };
+ };
+};
+
+
+Required properties
+-------------------
+
+If there is more than one 'port' or more than one 'endpoint' node or 'reg'
+property is present in port and/or endpoint nodes the following properties
+are required in a relevant parent node:
+
+ - #address-cells : number of cells required to define port/endpoint
+ identifier, should be 1.
+ - #size-cells : should be zero.
+
+Optional endpoint properties
+----------------------------
+
+- remote-endpoint: phandle to an 'endpoint' subnode of a remote device node.
+
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
index 1a1ac2e560e9..f47e56bcf78d 100644
--- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt
+++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
@@ -18,6 +18,7 @@ atmel,24c02 i2c serial eeprom (24cxx)
atmel,at97sc3204t i2c trusted platform module (TPM)
capella,cm32181 CM32181: Ambient Light Sensor
catalyst,24c32 i2c serial eeprom
+cirrus,cs42l51 Cirrus Logic CS42L51 audio codec
dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock
dallas,ds1338 I2C RTC with 56-Byte NV RAM
dallas,ds1339 I2C Serial Real-Time Clock
diff --git a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
new file mode 100644
index 000000000000..dcebff1928e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
@@ -0,0 +1,22 @@
+Freescale vf610 Analog to Digital Converter bindings
+
+The devicetree bindings are for the new ADC driver written for
+vf610/i.MX6slx and upward SoCs from Freescale.
+
+Required properties:
+- compatible: Should contain "fsl,vf610-adc"
+- reg: Offset and length of the register set for the device
+- interrupts: Should contain the interrupt for the device
+- clocks: The clock is needed by the ADC controller, ADC clock source is ipg clock.
+- clock-names: Must contain "adc", matching entry in the clocks property.
+- vref-supply: The regulator supply ADC refrence voltage.
+
+Example:
+adc0: adc@4003b000 {
+ compatible = "fsl,vf610-adc";
+ reg = <0x4003b000 0x1000>;
+ interrupts = <0 53 0x04>;
+ clocks = <&clks VF610_CLK_ADC0>;
+ clock-names = "adc";
+ vref-supply = <&reg_vcc_3v3_mcu>;
+};
diff --git a/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt b/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt
new file mode 100644
index 000000000000..d9ee909d2b78
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt
@@ -0,0 +1,113 @@
+Xilinx XADC device driver
+
+This binding document describes the bindings for both of them since the
+bindings are very similar. The Xilinx XADC is a ADC that can be found in the
+series 7 FPGAs from Xilinx. The XADC has a DRP interface for communication.
+Currently two different frontends for the DRP interface exist. One that is only
+available on the ZYNQ family as a hardmacro in the SoC portion of the ZYNQ. The
+other one is available on all series 7 platforms and is a softmacro with a AXI
+interface. This binding document describes the bindings for both of them since
+the bindings are very similar.
+
+Required properties:
+ - compatible: Should be one of
+ * "xlnx,zynq-xadc-1.00.a": When using the ZYNQ device
+ configuration interface to interface to the XADC hardmacro.
+ * "xlnx,axi-xadc-1.00.a": When using the axi-xadc pcore to
+ interface to the XADC hardmacro.
+ - reg: Address and length of the register set for the device
+ - interrupts: Interrupt for the XADC control interface.
+ - clocks: When using the ZYNQ this must be the ZYNQ PCAP clock,
+ when using the AXI-XADC pcore this must be the clock that provides the
+ clock to the AXI bus interface of the core.
+
+Optional properties:
+ - interrupt-parent: phandle to the parent interrupt controller
+ - xlnx,external-mux:
+ * "none": No external multiplexer is used, this is the default
+ if the property is omitted.
+ * "single": External multiplexer mode is used with one
+ multiplexer.
+ * "dual": External multiplexer mode is used with two
+ multiplexers for simultaneous sampling.
+ - xlnx,external-mux-channel: Configures which pair of pins is used to
+ sample data in external mux mode.
+ Valid values for single external multiplexer mode are:
+ 0: VP/VN
+ 1: VAUXP[0]/VAUXN[0]
+ 2: VAUXP[1]/VAUXN[1]
+ ...
+ 16: VAUXP[15]/VAUXN[15]
+ Valid values for dual external multiplexer mode are:
+ 1: VAUXP[0]/VAUXN[0] - VAUXP[8]/VAUXN[8]
+ 2: VAUXP[1]/VAUXN[1] - VAUXP[9]/VAUXN[9]
+ ...
+ 8: VAUXP[7]/VAUXN[7] - VAUXP[15]/VAUXN[15]
+
+ This property needs to be present if the device is configured for
+ external multiplexer mode (either single or dual). If the device is
+ not using external multiplexer mode the property is ignored.
+ - xnlx,channels: List of external channels that are connected to the ADC
+ Required properties:
+ * #address-cells: Should be 1.
+ * #size-cells: Should be 0.
+
+ The child nodes of this node represent the external channels which are
+ connected to the ADC. If the property is no present no external
+ channels will be assumed to be connected.
+
+ Each child node represents one channel and has the following
+ properties:
+ Required properties:
+ * reg: Pair of pins the the channel is connected to.
+ 0: VP/VN
+ 1: VAUXP[0]/VAUXN[0]
+ 2: VAUXP[1]/VAUXN[1]
+ ...
+ 16: VAUXP[15]/VAUXN[15]
+ Note each channel number should only be used at most
+ once.
+ Optional properties:
+ * xlnx,bipolar: If set the channel is used in bipolar
+ mode.
+
+
+Examples:
+ xadc@f8007100 {
+ compatible = "xlnx,zynq-xadc-1.00.a";
+ reg = <0xf8007100 0x20>;
+ interrupts = <0 7 4>;
+ interrupt-parent = <&gic>;
+ clocks = <&pcap_clk>;
+
+ xlnx,channels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ channel@0 {
+ reg = <0>;
+ };
+ channel@1 {
+ reg = <1>;
+ };
+ channel@8 {
+ reg = <8>;
+ };
+ };
+ };
+
+ xadc@43200000 {
+ compatible = "xlnx,axi-xadc-1.00.a";
+ reg = <0x43200000 0x1000>;
+ interrupts = <0 53 4>;
+ interrupt-parent = <&gic>;
+ clocks = <&fpga1_clk>;
+
+ xlnx,channels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ channel@0 {
+ reg = <0>;
+ xlnx,bipolar;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt
index 32cec4b26cd0..b290ca150d30 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt
@@ -2,7 +2,7 @@ Allwinner Sunxi Interrupt Controller
Required properties:
-- compatible : should be "allwinner,sun4i-ic"
+- compatible : should be "allwinner,sun4i-a10-ic"
- reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
@@ -11,7 +11,7 @@ Required properties:
Example:
intc: interrupt-controller {
- compatible = "allwinner,sun4i-ic";
+ compatible = "allwinner,sun4i-a10-ic";
reg = <0x01c20400 0x400>;
interrupt-controller;
#interrupt-cells = <1>;
diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt
new file mode 100644
index 000000000000..d1c5cdabc3e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt
@@ -0,0 +1,27 @@
+Allwinner Sunxi NMI Controller
+==============================
+
+Required properties:
+
+- compatible : should be "allwinner,sun7i-a20-sc-nmi" or
+ "allwinner,sun6i-a31-sc-nmi"
+- reg : Specifies base physical address and size of the registers.
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+ interrupt source. The value shall be 2. The first cell is the IRQ number, the
+ second cell the trigger type as defined in interrupt.txt in this directory.
+- interrupt-parent: Specifies the parent interrupt controller.
+- interrupts: Specifies the interrupt line (NMI) which is handled by
+ the interrupt controller in the parent controller's notation. This value
+ shall be the NMI.
+
+Example:
+
+sc-nmi-intc@01c00030 {
+ compatible = "allwinner,sun7i-a20-sc-nmi";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x01c00030 0x0c>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 0 4>;
+};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt b/Documentation/devicetree/bindings/memory-controllers/fsl/ifc.txt
index d5e370450ac0..d5e370450ac0 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/fsl/ifc.txt
diff --git a/Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt b/Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt
new file mode 100644
index 000000000000..9592717f483f
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt
@@ -0,0 +1,210 @@
+* Device tree bindings for Texas instruments AEMIF controller
+
+The Async External Memory Interface (EMIF16/AEMIF) controller is intended to
+provide a glue-less interface to a variety of asynchronous memory devices like
+ASRA M, NOR and NAND memory. A total of 256M bytes of any of these memories
+can be accessed at any given time via four chip selects with 64M byte access
+per chip select. Synchronous memories such as DDR1 SD RAM, SDR SDRAM
+and Mobile SDR are not supported.
+
+Documentation:
+Davinci DM646x - http://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf
+OMAP-L138 (DA850) - http://www.ti.com/lit/ug/spruh77a/spruh77a.pdf
+Kestone - http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf
+
+Required properties:
+
+- compatible: "ti,davinci-aemif"
+ "ti,keystone-aemif"
+ "ti,da850-aemif"
+
+- reg: contains offset/length value for AEMIF control registers
+ space.
+
+- #address-cells: Must be 2. The partition number has to be encoded in the
+ first address cell and it may accept values 0..N-1
+ (N - total number of partitions). It's recommended to
+ assign N-1 number for the control partition. The second
+ cell is the offset into the partition.
+
+- #size-cells: Must be set to 1.
+
+- ranges: Contains memory regions. There are two types of
+ ranges/partitions:
+ - CS-specific partition/range. If continuous, must be
+ set up to reflect the memory layout for 4 chipselects,
+ if not then additional range/partition can be added and
+ child device can select the proper one.
+ - control partition which is common for all CS
+ interfaces.
+
+- clocks: the clock feeding the controller clock. Required only
+ if clock tree data present in device tree.
+ See clock-bindings.txt
+
+- clock-names: clock name. It has to be "aemif". Required only if clock
+ tree data present in device tree, in another case don't
+ use it.
+ See clock-bindings.txt
+
+- clock-ranges: Empty property indicating that child nodes can inherit
+ named clocks. Required only if clock tree data present
+ in device tree.
+ See clock-bindings.txt
+
+
+Child chip-select (cs) nodes contain the memory devices nodes connected to
+such as NOR (e.g. cfi-flash) and NAND (ti,davinci-nand, see davinci-nand.txt).
+There might be board specific devices like FPGAs.
+
+Required child cs node properties:
+
+- #address-cells: Must be 2.
+
+- #size-cells: Must be 1.
+
+- ranges: Empty property indicating that child nodes can inherit
+ memory layout.
+
+- clock-ranges: Empty property indicating that child nodes can inherit
+ named clocks. Required only if clock tree data present
+ in device tree.
+
+- ti,cs-chipselect: number of chipselect. Indicates on the aemif driver
+ which chipselect is used for accessing the memory. For
+ compatibles "ti,davinci-aemif" and "ti,keystone-aemif"
+ it can be in range [0-3]. For compatible
+ "ti,da850-aemif" range is [2-5].
+
+Optional child cs node properties:
+
+- ti,cs-bus-width: width of the asynchronous device's data bus
+ 8 or 16 if not preset 8
+
+- ti,cs-select-strobe-mode: enable/disable select strobe mode
+ In select strobe mode chip select behaves as
+ the strobe and is active only during the strobe
+ period. If present then enable.
+
+- ti,cs-extended-wait-mode: enable/disable extended wait mode
+ if set, the controller monitors the EMIFWAIT pin
+ mapped to that chip select to determine if the
+ device wants to extend the strobe period. If
+ present then enable.
+
+- ti,cs-min-turnaround-ns: minimum turn around time, ns
+ Time between the end of one asynchronous memory
+ access and the start of another asynchronous
+ memory access. This delay is not incurred
+ between a read followed by read or a write
+ followed by a write to same chip select.
+
+- ti,cs-read-setup-ns: read setup width, ns
+ Time between the beginning of a memory cycle
+ and the activation of read strobe.
+ Minimum value is 1 (0 treated as 1).
+
+- ti,cs-read-strobe-ns: read strobe width, ns
+ Time between the activation and deactivation of
+ the read strobe.
+ Minimum value is 1 (0 treated as 1).
+
+- ti,cs-read-hold-ns: read hold width, ns
+ Time between the deactivation of the read
+ strobe and the end of the cycle (which may be
+ either an address change or the deactivation of
+ the chip select signal.
+ Minimum value is 1 (0 treated as 1).
+
+- ti,cs-write-setup-ns: write setup width, ns
+ Time between the beginning of a memory cycle
+ and the activation of write strobe.
+ Minimum value is 1 (0 treated as 1).
+
+- ti,cs-write-strobe-ns: write strobe width, ns
+ Time between the activation and deactivation of
+ the write strobe.
+ Minimum value is 1 (0 treated as 1).
+
+- ti,cs-write-hold-ns: write hold width, ns
+ Time between the deactivation of the write
+ strobe and the end of the cycle (which may be
+ either an address change or the deactivation of
+ the chip select signal.
+ Minimum value is 1 (0 treated as 1).
+
+If any of the above parameters are absent, current parameter value will be taken
+from the corresponding HW reg.
+
+Example for aemif, davinci nand and nor flash chip select shown below.
+
+memory-controller@21000A00 {
+ compatible = "ti,davinci-aemif";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clocks = <&clkaemif 0>;
+ clock-names = "aemif";
+ clock-ranges;
+ reg = <0x21000A00 0x00000100>;
+ ranges = <0 0 0x70000000 0x10000000
+ 1 0 0x21000A00 0x00000100>;
+ /*
+ * Partition0: CS-specific memory range which is
+ * implemented as continuous physical memory region
+ * Partition1: control memory range
+ */
+
+ nand:cs2 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-ranges;
+ ranges;
+
+ ti,cs-chipselect = <2>;
+ /* all timings in nanoseconds */
+ ti,cs-min-turnaround-ns = <0>;
+ ti,cs-read-hold-ns = <7>;
+ ti,cs-read-strobe-ns = <42>;
+ ti,cs-read-setup-ns = <14>;
+ ti,cs-write-hold-ns = <7>;
+ ti,cs-write-strobe-ns = <42>;
+ ti,cs-write-setup-ns = <14>;
+
+ nand@0,0x8000000 {
+ compatible = "ti,davinci-nand";
+ reg = <0 0x8000000 0x4000000
+ 1 0x0000000 0x0000100>;
+ /*
+ * Partition0, offset 0x8000000, size 0x4000000
+ * Partition1, offset 0x0000000, size 0x0000100
+ */
+
+ .. see davinci-nand.txt
+ };
+ };
+
+ nor:cs0 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-ranges;
+ ranges;
+
+ ti,cs-chipselect = <0>;
+ /* all timings in nanoseconds */
+ ti,cs-min-turnaround-ns = <0>;
+ ti,cs-read-hold-ns = <8>;
+ ti,cs-read-strobe-ns = <40>;
+ ti,cs-read-setup-ns = <14>;
+ ti,cs-write-hold-ns = <7>;
+ ti,cs-write-strobe-ns = <40>;
+ ti,cs-write-setup-ns = <14>;
+ ti,cs-bus-width = <16>;
+
+ flash@0,0x0000000 {
+ compatible = "cfi-flash";
+ reg = <0 0x0000000 0x4000000>;
+
+ ...
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/mfd/s2mpa01.txt b/Documentation/devicetree/bindings/mfd/s2mpa01.txt
new file mode 100644
index 000000000000..c13d3d8c3947
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/s2mpa01.txt
@@ -0,0 +1,90 @@
+
+* Samsung S2MPA01 Voltage and Current Regulator
+
+The Samsung S2MPA01 is a multi-function device which includes high
+efficiency buck converters including Dual-Phase buck converter, various LDOs,
+and an RTC. It is interfaced to the host controller using an I2C interface.
+Each sub-block is addressed by the host system using different I2C slave
+addresses.
+
+Required properties:
+- compatible: Should be "samsung,s2mpa01-pmic".
+- reg: Specifies the I2C slave address of the PMIC block. It should be 0x66.
+
+Optional properties:
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+ the interrupts from s2mpa01 are delivered to.
+- interrupts: An interrupt specifier for the sole interrupt generated by the
+ device.
+
+Optional nodes:
+- regulators: The regulators of s2mpa01 that have to be instantiated should be
+ included in a sub-node named 'regulators'. Regulator nodes and constraints
+ included in this sub-node use the standard regulator bindings which are
+ documented elsewhere.
+
+Properties for BUCK regulator nodes:
+- regulator-ramp-delay: ramp delay in uV/us. May be 6250, 12500
+ (default), 25000, or 50000. May be 0 for disabling the ramp delay on
+ BUCK{1,2,3,4}.
+
+ In the absence of the regulator-ramp-delay property, the default ramp
+ delay will be used.
+
+ NOTE: Some BUCKs share the ramp rate setting i.e. same ramp value will be set
+ for a particular group of BUCKs. So provide same regulator-ramp-delay=<value>.
+
+ The following BUCKs share ramp settings:
+ * 1 and 6
+ * 2 and 4
+ * 8, 9, and 10
+
+The following are the names of the regulators that the s2mpa01 PMIC block
+supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
+as per the datasheet of s2mpa01.
+
+ - LDOn
+ - valid values for n are 1 to 26
+ - Example: LDO1, LD02, LDO26
+ - BUCKn
+ - valid values for n are 1 to 10.
+ - Example: BUCK1, BUCK2, BUCK9
+
+Example:
+
+ s2mpa01_pmic@66 {
+ compatible = "samsung,s2mpa01-pmic";
+ reg = <0x66>;
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "VDD_ALIVE";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "VDDQ_MMC2";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-ramp-delay = <50000>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mfd/s2mps11.txt b/Documentation/devicetree/bindings/mfd/s2mps11.txt
index 15ee89c3cc7b..f69bec294f02 100644
--- a/Documentation/devicetree/bindings/mfd/s2mps11.txt
+++ b/Documentation/devicetree/bindings/mfd/s2mps11.txt
@@ -1,5 +1,5 @@
-* Samsung S2MPS11 Voltage and Current Regulator
+* Samsung S2MPS11 and S2MPS14 Voltage and Current Regulator
The Samsung S2MPS11 is a multi-function device which includes voltage and
current regulators, RTC, charger controller and other sub-blocks. It is
@@ -7,7 +7,7 @@ interfaced to the host controller using an I2C interface. Each sub-block is
addressed by the host system using different I2C slave addresses.
Required properties:
-- compatible: Should be "samsung,s2mps11-pmic".
+- compatible: Should be "samsung,s2mps11-pmic" or "samsung,s2mps14-pmic".
- reg: Specifies the I2C slave address of the pmic block. It should be 0x66.
Optional properties:
@@ -59,10 +59,14 @@ supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
as per the datasheet of s2mps11.
- LDOn
- - valid values for n are 1 to 38
+ - valid values for n are:
+ - S2MPS11: 1 to 38
+ - S2MPS14: 1 to 25
- Example: LDO1, LD02, LDO28
- BUCKn
- - valid values for n are 1 to 10.
+ - valid values for n are:
+ - S2MPS11: 1 to 10
+ - S2MPS14: 1 to 5
- Example: BUCK1, BUCK2, BUCK9
Example:
diff --git a/Documentation/devicetree/bindings/mfd/tps65910.txt b/Documentation/devicetree/bindings/mfd/tps65910.txt
index b4bd98af1cc7..38833e63a59f 100644
--- a/Documentation/devicetree/bindings/mfd/tps65910.txt
+++ b/Documentation/devicetree/bindings/mfd/tps65910.txt
@@ -11,7 +11,7 @@ Required properties:
- #interrupt-cells: the number of cells to describe an IRQ, this should be 2.
The first cell is the IRQ number.
The second cell is the flags, encoded as the trigger masks from
- Documentation/devicetree/bindings/interrupts.txt
+ Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- regulators: This is the list of child nodes that specify the regulator
initialization data for defined regulators. Not all regulators for the given
device need to be present. The definition for each of these nodes is defined
diff --git a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
index 68ba37295565..fabdf64a5737 100644
--- a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
+++ b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
@@ -1,12 +1,12 @@
Allwinner sunxi-sid
Required properties:
-- compatible: "allwinner,sun4i-sid" or "allwinner,sun7i-a20-sid".
+- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
- reg: Should contain registers location and length
Example for sun4i:
sid@01c23800 {
- compatible = "allwinner,sun4i-sid";
+ compatible = "allwinner,sun4i-a10-sid";
reg = <0x01c23800 0x10>
};
diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt
index 60960b2755f4..efc98ea1f23d 100644
--- a/Documentation/devicetree/bindings/misc/atmel-ssc.txt
+++ b/Documentation/devicetree/bindings/misc/atmel-ssc.txt
@@ -17,6 +17,14 @@ Required properties for devices compatible with "atmel,at91sam9g45-ssc":
See Documentation/devicetree/bindings/dma/atmel-dma.txt for details.
- dma-names: Must be "tx", "rx".
+Optional properties:
+ - atmel,clk-from-rk-pin: bool property.
+ - When SSC works in slave mode, according to the hardware design, the
+ clock can get from TK pin, and also can get from RK pin. So, add
+ this parameter to choose where the clock from.
+ - By default the clock is from TK pin, if the clock from RK pin, this
+ property is needed.
+
Examples:
- PDC transfer:
ssc0: ssc@fffbc000 {
diff --git a/Documentation/devicetree/bindings/misc/sram.txt b/Documentation/devicetree/bindings/misc/sram.txt
index 4d0a00e453a8..36cbe5aea990 100644
--- a/Documentation/devicetree/bindings/misc/sram.txt
+++ b/Documentation/devicetree/bindings/misc/sram.txt
@@ -8,9 +8,44 @@ Required properties:
- reg : SRAM iomem address range
+Reserving sram areas:
+---------------------
+
+Each child of the sram node specifies a region of reserved memory. Each
+child node should use a 'reg' property to specify a specific range of
+reserved memory.
+
+Following the generic-names recommended practice, node names should
+reflect the purpose of the node. Unit address (@<address>) should be
+appended to the name.
+
+Required properties in the sram node:
+
+- #address-cells, #size-cells : should use the same values as the root node
+- ranges : standard definition, should translate from local addresses
+ within the sram to bus addresses
+
+Required properties in the area nodes:
+
+- reg : iomem address range, relative to the SRAM range
+
+Optional properties in the area nodes:
+
+- compatible : standard definition, should contain a vendor specific string
+ in the form <vendor>,[<device>-]<usage>
+
Example:
sram: sram@5c000000 {
compatible = "mmio-sram";
reg = <0x5c000000 0x40000>; /* 256 KiB SRAM at address 0x5c000000 */
+
+ #adress-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x5c000000 0x40000>;
+
+ smp-sram@100 {
+ compatible = "socvendor,smp-sram";
+ reg = <0x100 0x50>;
+ };
};
diff --git a/Documentation/devicetree/bindings/net/micrel-ks8851.txt b/Documentation/devicetree/bindings/net/micrel-ks8851.txt
index 11ace3c3d805..4fc392763611 100644
--- a/Documentation/devicetree/bindings/net/micrel-ks8851.txt
+++ b/Documentation/devicetree/bindings/net/micrel-ks8851.txt
@@ -7,3 +7,4 @@ Required properties:
Optional properties:
- local-mac-address : Ethernet mac address to use
+- vdd-supply: supply for Ethernet mac
diff --git a/Documentation/devicetree/bindings/net/opencores-ethoc.txt b/Documentation/devicetree/bindings/net/opencores-ethoc.txt
new file mode 100644
index 000000000000..2dc127c30d9b
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/opencores-ethoc.txt
@@ -0,0 +1,22 @@
+* OpenCores MAC 10/100 Mbps
+
+Required properties:
+- compatible: Should be "opencores,ethoc".
+- reg: two memory regions (address and length),
+ first region is for the device registers and descriptor rings,
+ second is for the device packet memory.
+- interrupts: interrupt for the device.
+
+Optional properties:
+- clocks: phandle to refer to the clk used as per
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Examples:
+
+ enet0: ethoc@fd030000 {
+ compatible = "opencores,ethoc";
+ reg = <0xfd030000 0x4000 0xfd800000 0x4000>;
+ interrupts = <1>;
+ local-mac-address = [00 50 c2 13 6f 00];
+ clocks = <&osc>;
+ };
diff --git a/Documentation/devicetree/bindings/net/sti-dwmac.txt b/Documentation/devicetree/bindings/net/sti-dwmac.txt
new file mode 100644
index 000000000000..3dd3d0bf112f
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/sti-dwmac.txt
@@ -0,0 +1,58 @@
+STMicroelectronics SoC DWMAC glue layer controller
+
+The device node has following properties.
+
+Required properties:
+ - compatible : Can be "st,stih415-dwmac", "st,stih416-dwmac" or
+ "st,stid127-dwmac".
+ - reg : Offset of the glue configuration register map in system
+ configuration regmap pointed by st,syscon property and size.
+
+ - reg-names : Should be "sti-ethconf".
+
+ - st,syscon : Should be phandle to system configuration node which
+ encompases this glue registers.
+
+ - st,tx-retime-src: On STi Parts for Giga bit speeds, 125Mhz clocks can be
+ wired up in from different sources. One via TXCLK pin and other via CLK_125
+ pin. This wiring is totally board dependent. However the retiming glue
+ logic should be configured accordingly. Possible values for this property
+
+ "txclk" - if 125Mhz clock is wired up via txclk line.
+ "clk_125" - if 125Mhz clock is wired up via clk_125 line.
+
+ This property is only valid for Giga bit setup( GMII, RGMII), and it is
+ un-used for non-giga bit (MII and RMII) setups. Also note that internal
+ clockgen can not generate stable 125Mhz clock.
+
+ - st,ext-phyclk: This boolean property indicates who is generating the clock
+ for tx and rx. This property is only valid for RMII case where the clock can
+ be generated from the MAC or PHY.
+
+ - clock-names: should be "sti-ethclk".
+ - clocks: Should point to ethernet clockgen which can generate phyclk.
+
+
+Example:
+
+ethernet0: dwmac@fe810000 {
+ device_type = "network";
+ compatible = "st,stih416-dwmac", "snps,dwmac", "snps,dwmac-3.710";
+ reg = <0xfe810000 0x8000>, <0x8bc 0x4>;
+ reg-names = "stmmaceth", "sti-ethconf";
+ interrupts = <0 133 0>, <0 134 0>, <0 135 0>;
+ interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
+ phy-mode = "mii";
+
+ st,syscon = <&syscfg_rear>;
+
+ snps,pbl = <32>;
+ snps,mixed-burst;
+
+ resets = <&softreset STIH416_ETH0_SOFTRESET>;
+ reset-names = "stmmaceth";
+ pinctrl-0 = <&pinctrl_mii0>;
+ pinctrl-names = "default";
+ clocks = <&CLK_S_GMAC0_PHY>;
+ clock-names = "stmmaceth";
+};
diff --git a/Documentation/devicetree/bindings/phy/apm-xgene-phy.txt b/Documentation/devicetree/bindings/phy/apm-xgene-phy.txt
new file mode 100644
index 000000000000..5f3a65a9dd88
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/apm-xgene-phy.txt
@@ -0,0 +1,79 @@
+* APM X-Gene 15Gbps Multi-purpose PHY nodes
+
+PHY nodes are defined to describe on-chip 15Gbps Multi-purpose PHY. Each
+PHY (pair of lanes) has its own node.
+
+Required properties:
+- compatible : Shall be "apm,xgene-phy".
+- reg : PHY memory resource is the SDS PHY access resource.
+- #phy-cells : Shall be 1 as it expects one argument for setting
+ the mode of the PHY. Possible values are 0 (SATA),
+ 1 (SGMII), 2 (PCIe), 3 (USB), and 4 (XFI).
+
+Optional properties:
+- status : Shall be "ok" if enabled or "disabled" if disabled.
+ Default is "ok".
+- clocks : Reference to the clock entry.
+- apm,tx-eye-tuning : Manual control to fine tune the capture of the serial
+ bit lines from the automatic calibrated position.
+ Two set of 3-tuple setting for each (up to 3)
+ supported link speed on the host. Range from 0 to
+ 127 in unit of one bit period. Default is 10.
+- apm,tx-eye-direction : Eye tuning manual control direction. 0 means sample
+ data earlier than the nominal sampling point. 1 means
+ sample data later than the nominal sampling point.
+ Two set of 3-tuple setting for each (up to 3)
+ supported link speed on the host. Default is 0.
+- apm,tx-boost-gain : Frequency boost AC (LSB 3-bit) and DC (2-bit)
+ gain control. Two set of 3-tuple setting for each
+ (up to 3) supported link speed on the host. Range is
+ between 0 to 31 in unit of dB. Default is 3.
+- apm,tx-amplitude : Amplitude control. Two set of 3-tuple setting for
+ each (up to 3) supported link speed on the host.
+ Range is between 0 to 199500 in unit of uV.
+ Default is 199500 uV.
+- apm,tx-pre-cursor1 : 1st pre-cursor emphasis taps control. Two set of
+ 3-tuple setting for each (up to 3) supported link
+ speed on the host. Range is 0 to 273000 in unit of
+ uV. Default is 0.
+- apm,tx-pre-cursor2 : 2st pre-cursor emphasis taps control. Two set of
+ 3-tuple setting for each (up to 3) supported link
+ speed on the host. Range is 0 to 127400 in unit uV.
+ Default is 0x0.
+- apm,tx-post-cursor : Post-cursor emphasis taps control. Two set of
+ 3-tuple setting for Gen1, Gen2, and Gen3. Range is
+ between 0 to 0x1f in unit of 18.2mV. Default is 0xf.
+- apm,tx-speed : Tx operating speed. One set of 3-tuple for each
+ supported link speed on the host.
+ 0 = 1-2Gbps
+ 1 = 2-4Gbps (1st tuple default)
+ 2 = 4-8Gbps
+ 3 = 8-15Gbps (2nd tuple default)
+ 4 = 2.5-4Gbps
+ 5 = 4-5Gbps
+ 6 = 5-6Gbps
+ 7 = 6-16Gbps (3rd tuple default)
+
+NOTE: PHY override parameters are board specific setting.
+
+Example:
+ phy1: phy@1f21a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f21a000 0x0 0x100>;
+ #phy-cells = <1>;
+ status = "disabled";
+ };
+
+ phy2: phy@1f22a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f22a000 0x0 0x100>;
+ #phy-cells = <1>;
+ status = "ok";
+ };
+
+ phy3: phy@1f23a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f23a000 0x0 0x100>;
+ #phy-cells = <1>;
+ status = "ok";
+ };
diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt
index c0fccaa1671e..28f9edb8f19c 100644
--- a/Documentation/devicetree/bindings/phy/samsung-phy.txt
+++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt
@@ -20,3 +20,57 @@ Required properties:
- compatible : should be "samsung,exynos5250-dp-video-phy";
- reg : offset and length of the Display Port PHY register set;
- #phy-cells : from the generic PHY bindings, must be 0;
+
+Samsung S5P/EXYNOS SoC series USB PHY
+-------------------------------------------------
+
+Required properties:
+- compatible : should be one of the listed compatibles:
+ - "samsung,exynos4210-usb2-phy"
+ - "samsung,exynos4x12-usb2-phy"
+ - "samsung,exynos5250-usb2-phy"
+- reg : a list of registers used by phy driver
+ - first and obligatory is the location of phy modules registers
+- samsung,sysreg-phandle - handle to syscon used to control the system registers
+- samsung,pmureg-phandle - handle to syscon used to control PMU registers
+- #phy-cells : from the generic phy bindings, must be 1;
+- clocks and clock-names:
+ - the "phy" clock is required by the phy module, used as a gate
+ - the "ref" clock is used to get the rate of the clock provided to the
+ PHY module
+
+The first phandle argument in the PHY specifier identifies the PHY, its
+meaning is compatible dependent. For the currently supported SoCs (Exynos 4210
+and Exynos 4212) it is as follows:
+ 0 - USB device ("device"),
+ 1 - USB host ("host"),
+ 2 - HSIC0 ("hsic0"),
+ 3 - HSIC1 ("hsic1"),
+
+Exynos 4210 and Exynos 4212 use mode switching and require that mode switch
+register is supplied.
+
+Example:
+
+For Exynos 4412 (compatible with Exynos 4212):
+
+usbphy: phy@125b0000 {
+ compatible = "samsung,exynos4x12-usb2-phy";
+ reg = <0x125b0000 0x100>;
+ clocks = <&clock 305>, <&clock 2>;
+ clock-names = "phy", "ref";
+ status = "okay";
+ #phy-cells = <1>;
+ samsung,sysreg-phandle = <&sys_reg>;
+ samsung,pmureg-phandle = <&pmu_reg>;
+};
+
+Then the PHY can be used in other nodes such as:
+
+phy-consumer@12340000 {
+ phys = <&usbphy 2>;
+ phy-names = "phy";
+};
+
+Refer to DT bindings documentation of particular PHY consumer devices for more
+information about required PHYs and the way of specification.
diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
new file mode 100644
index 000000000000..a82361b62015
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
@@ -0,0 +1,26 @@
+Allwinner sun4i USB PHY
+-----------------------
+
+Required properties:
+- compatible : should be one of "allwinner,sun4i-a10-usb-phy",
+ "allwinner,sun5i-a13-usb-phy" or "allwinner,sun7i-a20-usb-phy"
+- reg : a list of offset + length pairs
+- reg-names : "phy_ctrl", "pmu1" and for sun4i or sun7i "pmu2"
+- #phy-cells : from the generic phy bindings, must be 1
+- clocks : phandle + clock specifier for the phy clock
+- clock-names : "usb_phy"
+- resets : a list of phandle + reset specifier pairs
+- reset-names : "usb0_reset", "usb1_reset" and for sun4i or sun7i "usb2_reset"
+
+Example:
+ usbphy: phy@0x01c13400 {
+ #phy-cells = <1>;
+ compatible = "allwinner,sun4i-a10-usb-phy";
+ /* phy base regs, phy1 pmu reg, phy2 pmu reg */
+ reg = <0x01c13400 0x10 0x01c14800 0x4 0x01c1c800 0x4>;
+ reg-names = "phy_ctrl", "pmu1", "pmu2";
+ clocks = <&usb_clk 8>;
+ clock-names = "usb_phy";
+ resets = <&usb_clk 1>, <&usb_clk 2>;
+ reset-names = "usb1_reset", "usb2_reset";
+ };
diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt
new file mode 100644
index 000000000000..788fb0fa3762
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
@@ -0,0 +1,86 @@
+TI PHY: DT DOCUMENTATION FOR PHYs in TI PLATFORMs
+
+OMAP CONTROL PHY
+
+Required properties:
+ - compatible: Should be one of
+ "ti,control-phy-otghs" - if it has otghs_control mailbox register as on OMAP4.
+ "ti,control-phy-usb2" - if it has Power down bit in control_dev_conf register
+ e.g. USB2_PHY on OMAP5.
+ "ti,control-phy-pipe3" - if it has DPLL and individual Rx & Tx power control
+ e.g. USB3 PHY and SATA PHY on OMAP5.
+ "ti,control-phy-usb2-dra7" - if it has power down register like USB2 PHY on
+ DRA7 platform.
+ "ti,control-phy-usb2-am437" - if it has power down register like USB2 PHY on
+ AM437 platform.
+ - reg : Address and length of the register set for the device. It contains
+ the address of "otghs_control" for control-phy-otghs or "power" register
+ for other types.
+ - reg-names: should be "otghs_control" control-phy-otghs and "power" for
+ other types.
+
+omap_control_usb: omap-control-usb@4a002300 {
+ compatible = "ti,control-phy-otghs";
+ reg = <0x4a00233c 0x4>;
+ reg-names = "otghs_control";
+};
+
+OMAP USB2 PHY
+
+Required properties:
+ - compatible: Should be "ti,omap-usb2"
+ - reg : Address and length of the register set for the device.
+ - #phy-cells: determine the number of cells that should be given in the
+ phandle while referencing this phy.
+
+Optional properties:
+ - ctrl-module : phandle of the control module used by PHY driver to power on
+ the PHY.
+
+This is usually a subnode of ocp2scp to which it is connected.
+
+usb2phy@4a0ad080 {
+ compatible = "ti,omap-usb2";
+ reg = <0x4a0ad080 0x58>;
+ ctrl-module = <&omap_control_usb>;
+ #phy-cells = <0>;
+};
+
+TI PIPE3 PHY
+
+Required properties:
+ - compatible: Should be "ti,phy-usb3" or "ti,phy-pipe3-sata".
+ "ti,omap-usb3" is deprecated.
+ - reg : Address and length of the register set for the device.
+ - reg-names: The names of the register addresses corresponding to the registers
+ filled in "reg".
+ - #phy-cells: determine the number of cells that should be given in the
+ phandle while referencing this phy.
+ - clocks: a list of phandles and clock-specifier pairs, one for each entry in
+ clock-names.
+ - clock-names: should include:
+ * "wkupclk" - wakeup clock.
+ * "sysclk" - system clock.
+ * "refclk" - reference clock.
+
+Optional properties:
+ - ctrl-module : phandle of the control module used by PHY driver to power on
+ the PHY.
+
+This is usually a subnode of ocp2scp to which it is connected.
+
+usb3phy@4a084400 {
+ compatible = "ti,phy-usb3";
+ reg = <0x4a084400 0x80>,
+ <0x4a084800 0x64>,
+ <0x4a084c00 0x40>;
+ reg-names = "phy_rx", "phy_tx", "pll_ctrl";
+ ctrl-module = <&omap_control_usb>;
+ #phy-cells = <0>;
+ clocks = <&usb_phy_cm_clk32k>,
+ <&sys_clkin>,
+ <&usb_otg_ss_refclk960m>;
+ clock-names = "wkupclk",
+ "sysclk",
+ "refclk";
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt
index 9e9e9ef9f852..c119debe6bab 100644
--- a/Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt
@@ -1,4 +1,4 @@
-Broadcom Capri Pin Controller
+Broadcom BCM281xx Pin Controller
This is a pin controller for the Broadcom BCM281xx SoC family, which includes
BCM11130, BCM11140, BCM11351, BCM28145, and BCM28155 SoCs.
@@ -7,14 +7,14 @@ BCM11130, BCM11140, BCM11351, BCM28145, and BCM28155 SoCs.
Required Properties:
-- compatible: Must be "brcm,capri-pinctrl".
+- compatible: Must be "brcm,bcm11351-pinctrl"
- reg: Base address of the PAD Controller register block and the size
of the block.
For example, the following is the bare minimum node:
pinctrl@35004800 {
- compatible = "brcm,capri-pinctrl";
+ compatible = "brcm,bcm11351-pinctrl";
reg = <0x35004800 0x430>;
};
@@ -119,7 +119,7 @@ Optional Properties (for HDMI pins):
Example:
// pin controller node
pinctrl@35004800 {
- compatible = "brcm,capri-pinctrl";
+ compatible = "brcmbcm11351-pinctrl";
reg = <0x35004800 0x430>;
// pin configuration node
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt
index 01ef408e205f..adda2a8d1d52 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt
@@ -5,6 +5,7 @@ part and usage.
Required properties:
- compatible: "marvell,88f6710-pinctrl"
+- reg: register specifier of MPP registers
Available mpp pins/groups and functions:
Note: brackets (x) are not part of the mpp name for marvell,function and given
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt
new file mode 100644
index 000000000000..7de0cda4a379
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt
@@ -0,0 +1,82 @@
+* Marvell Armada 375 SoC pinctrl driver for mpp
+
+Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
+part and usage.
+
+Required properties:
+- compatible: "marvell,88f6720-pinctrl"
+- reg: register specifier of MPP registers
+
+Available mpp pins/groups and functions:
+Note: brackets (x) are not part of the mpp name for marvell,function and given
+only for more detailed description in this document.
+
+name pins functions
+================================================================================
+mpp0 0 gpio, dev(ad2), spi0(cs1), spi1(cs1)
+mpp1 1 gpio, dev(ad3), spi0(mosi), spi1(mosi)
+mpp2 2 gpio, dev(ad4), ptp(eventreq), led(c0), audio(sdi)
+mpp3 3 gpio, dev(ad5), ptp(triggen), led(p3), audio(mclk)
+mpp4 4 gpio, dev(ad6), spi0(miso), spi1(miso)
+mpp5 5 gpio, dev(ad7), spi0(cs2), spi1(cs2)
+mpp6 6 gpio, dev(ad0), led(p1), audio(rclk)
+mpp7 7 gpio, dev(ad1), ptp(clk), led(p2), audio(extclk)
+mpp8 8 gpio, dev (bootcs), spi0(cs0), spi1(cs0)
+mpp9 9 gpio, nf(wen), spi0(sck), spi1(sck)
+mpp10 10 gpio, nf(ren), dram(vttctrl), led(c1)
+mpp11 11 gpio, dev(a0), led(c2), audio(sdo)
+mpp12 12 gpio, dev(a1), audio(bclk)
+mpp13 13 gpio, dev(readyn), pcie0(rstoutn), pcie1(rstoutn)
+mpp14 14 gpio, i2c0(sda), uart1(txd)
+mpp15 15 gpio, i2c0(sck), uart1(rxd)
+mpp16 16 gpio, uart0(txd)
+mpp17 17 gpio, uart0(rxd)
+mpp18 18 gpio, tdm(intn)
+mpp19 19 gpio, tdm(rstn)
+mpp20 20 gpio, tdm(pclk)
+mpp21 21 gpio, tdm(fsync)
+mpp22 22 gpio, tdm(drx)
+mpp23 23 gpio, tdm(dtx)
+mpp24 24 gpio, led(p0), ge1(rxd0), sd(cmd), uart0(rts)
+mpp25 25 gpio, led(p2), ge1(rxd1), sd(d0), uart0(cts)
+mpp26 26 gpio, pcie0(clkreq), ge1(rxd2), sd(d2), uart1(rts)
+mpp27 27 gpio, pcie1(clkreq), ge1(rxd3), sd(d1), uart1(cts)
+mpp28 28 gpio, led(p3), ge1(txctl), sd(clk)
+mpp29 29 gpio, pcie1(clkreq), ge1(rxclk), sd(d3)
+mpp30 30 gpio, ge1(txd0), spi1(cs0)
+mpp31 31 gpio, ge1(txd1), spi1(mosi)
+mpp32 32 gpio, ge1(txd2), spi1(sck), ptp(triggen)
+mpp33 33 gpio, ge1(txd3), spi1(miso)
+mpp34 34 gpio, ge1(txclkout), spi1(sck)
+mpp35 35 gpio, ge1(rxctl), spi1(cs1), spi0(cs2)
+mpp36 36 gpio, pcie0(clkreq)
+mpp37 37 gpio, pcie0(clkreq), tdm(intn), ge(mdc)
+mpp38 38 gpio, pcie1(clkreq), ge(mdio)
+mpp39 39 gpio, ref(clkout)
+mpp40 40 gpio, uart1(txd)
+mpp41 41 gpio, uart1(rxd)
+mpp42 42 gpio, spi1(cs2), led(c0)
+mpp43 43 gpio, sata0(prsnt), dram(vttctrl)
+mpp44 44 gpio, sata0(prsnt)
+mpp45 45 gpio, spi0(cs2), pcie0(rstoutn)
+mpp46 46 gpio, led(p0), ge0(txd0), ge1(txd0)
+mpp47 47 gpio, led(p1), ge0(txd1), ge1(txd1)
+mpp48 48 gpio, led(p2), ge0(txd2), ge1(txd2)
+mpp49 49 gpio, led(p3), ge0(txd3), ge1(txd3)
+mpp50 50 gpio, led(c0), ge0(rxd0), ge1(rxd0)
+mpp51 51 gpio, led(c1), ge0(rxd1), ge1(rxd1)
+mpp52 52 gpio, led(c2), ge0(rxd2), ge1(rxd2)
+mpp53 53 gpio, pcie1(rstoutn), ge0(rxd3), ge1(rxd3)
+mpp54 54 gpio, pcie0(rstoutn), ge0(rxctl), ge1(rxctl)
+mpp55 55 gpio, ge0(rxclk), ge1(rxclk)
+mpp56 56 gpio, ge0(txclkout), ge1(txclkout)
+mpp57 57 gpio, ge0(txctl), ge1(txctl)
+mpp58 58 gpio, led(c0)
+mpp59 59 gpio, led(c1)
+mpp60 60 gpio, uart1(txd), led(c2)
+mpp61 61 gpio, i2c1(sda), uart1(rxd), spi1(cs2), led(p0)
+mpp62 62 gpio, i2c1(sck), led(p1)
+mpp63 63 gpio, ptp(triggen), led(p2)
+mpp64 64 gpio, dram(vttctrl), led(p3)
+mpp65 65 gpio, sata1(prsnt)
+mpp66 66 gpio, ptp(eventreq), spi1(cs3)
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt
new file mode 100644
index 000000000000..b17c96849fc9
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt
@@ -0,0 +1,80 @@
+* Marvell Armada 380/385 SoC pinctrl driver for mpp
+
+Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
+part and usage.
+
+Required properties:
+- compatible: "marvell,88f6810-pinctrl", "marvell,88f6820-pinctrl" or
+ "marvell,88f6828-pinctrl" depending on the specific variant of the
+ SoC being used.
+- reg: register specifier of MPP registers
+
+Available mpp pins/groups and functions:
+Note: brackets (x) are not part of the mpp name for marvell,function and given
+only for more detailed description in this document.
+
+name pins functions
+================================================================================
+mpp0 0 gpio, ua0(rxd)
+mpp1 1 gpio, ua0(txd)
+mpp2 2 gpio, i2c0(sck)
+mpp3 3 gpio, i2c0(sda)
+mpp4 4 gpio, ge(mdc), ua1(txd), ua0(rts)
+mpp5 5 gpio, ge(mdio), ua1(rxd), ua0(cts)
+mpp6 6 gpio, ge0(txclkout), ge0(crs), dev(cs3)
+mpp7 7 gpio, ge0(txd0), dev(ad9)
+mpp8 8 gpio, ge0(txd1), dev(ad10)
+mpp9 9 gpio, ge0(txd2), dev(ad11)
+mpp10 10 gpio, ge0(txd3), dev(ad12)
+mpp11 11 gpio, ge0(txctl), dev(ad13)
+mpp12 12 gpio, ge0(rxd0), pcie0(rstout), pcie1(rstout) [1], spi0(cs1), dev(ad14)
+mpp13 13 gpio, ge0(rxd1), pcie0(clkreq), pcie1(clkreq) [1], spi0(cs2), dev(ad15)
+mpp14 14 gpio, ge0(rxd2), ptp(clk), m(vtt_ctrl), spi0(cs3), dev(wen1)
+mpp15 15 gpio, ge0(rxd3), ge(mdc slave), pcie0(rstout), spi0(mosi), pcie1(rstout) [1]
+mpp16 16 gpio, ge0(rxctl), ge(mdio slave), m(decc_err), spi0(miso), pcie0(clkreq)
+mpp17 17 gpio, ge0(rxclk), ptp(clk), ua1(rxd), spi0(sck), sata1(prsnt)
+mpp18 18 gpio, ge0(rxerr), ptp(trig_gen), ua1(txd), spi0(cs0), pcie1(rstout) [1]
+mpp19 19 gpio, ge0(col), ptp(event_req), pcie0(clkreq), sata1(prsnt), ua0(cts)
+mpp20 20 gpio, ge0(txclk), ptp(clk), pcie1(rstout) [1], sata0(prsnt), ua0(rts)
+mpp21 21 gpio, spi0(cs1), ge1(rxd0), sata0(prsnt), sd0(cmd), dev(bootcs)
+mpp22 22 gpio, spi0(mosi), dev(ad0)
+mpp23 23 gpio, spi0(sck), dev(ad2)
+mpp24 24 gpio, spi0(miso), ua0(cts), ua1(rxd), sd0(d4), dev(ready)
+mpp25 25 gpio, spi0(cs0), ua0(rts), ua1(txd), sd0(d5), dev(cs0)
+mpp26 26 gpio, spi0(cs2), i2c1(sck), sd0(d6), dev(cs1)
+mpp27 27 gpio, spi0(cs3), ge1(txclkout), i2c1(sda), sd0(d7), dev(cs2)
+mpp28 28 gpio, ge1(txd0), sd0(clk), dev(ad5)
+mpp29 29 gpio, ge1(txd1), dev(ale0)
+mpp30 30 gpio, ge1(txd2), dev(oen)
+mpp31 31 gpio, ge1(txd3), dev(ale1)
+mpp32 32 gpio, ge1(txctl), dev(wen0)
+mpp33 33 gpio, m(decc_err), dev(ad3)
+mpp34 34 gpio, dev(ad1)
+mpp35 35 gpio, ref(clk_out1), dev(a1)
+mpp36 36 gpio, ptp(trig_gen), dev(a0)
+mpp37 37 gpio, ptp(clk), ge1(rxclk), sd0(d3), dev(ad8)
+mpp38 38 gpio, ptp(event_req), ge1(rxd1), ref(clk_out0), sd0(d0), dev(ad4)
+mpp39 39 gpio, i2c1(sck), ge1(rxd2), ua0(cts), sd0(d1), dev(a2)
+mpp40 40 gpio, i2c1(sda), ge1(rxd3), ua0(rts), sd0(d2), dev(ad6)
+mpp41 41 gpio, ua1(rxd), ge1(rxctl), ua0(cts), spi1(cs3), dev(burst/last)
+mpp42 42 gpio, ua1(txd), ua0(rts), dev(ad7)
+mpp43 43 gpio, pcie0(clkreq), m(vtt_ctrl), m(decc_err), pcie0(rstout), dev(clkout)
+mpp44 44 gpio, sata0(prsnt), sata1(prsnt), sata2(prsnt) [2], sata3(prsnt) [3], pcie0(rstout)
+mpp45 45 gpio, ref(clk_out0), pcie0(rstout), pcie1(rstout) [1], pcie2(rstout), pcie3(rstout)
+mpp46 46 gpio, ref(clk_out1), pcie0(rstout), pcie1(rstout) [1], pcie2(rstout), pcie3(rstout)
+mpp47 47 gpio, sata0(prsnt), sata1(prsnt), sata2(prsnt) [2], spi1(cs2), sata3(prsnt) [2]
+mpp48 48 gpio, sata0(prsnt), m(vtt_ctrl), tdm2c(pclk), audio(mclk), sd0(d4)
+mpp49 49 gpio, sata2(prsnt) [2], sata3(prsnt) [2], tdm2c(fsync), audio(lrclk), sd0(d5)
+mpp50 50 gpio, pcie0(rstout), pcie1(rstout) [1], tdm2c(drx), audio(extclk), sd0(cmd)
+mpp51 51 gpio, tdm2c(dtx), audio(sdo), m(decc_err)
+mpp52 52 gpio, pcie0(rstout), pcie1(rstout) [1], tdm2c(intn), audio(sdi), sd0(d6)
+mpp53 53 gpio, sata1(prsnt), sata0(prsnt), tdm2c(rstn), audio(bclk), sd0(d7)
+mpp54 54 gpio, sata0(prsnt), sata1(prsnt), pcie0(rstout), pcie1(rstout) [1], sd0(d3)
+mpp55 55 gpio, ua1(cts), ge(mdio), pcie1(clkreq) [1], spi1(cs1), sd0(d0)
+mpp56 56 gpio, ua1(rts), ge(mdc), m(decc_err), spi1(mosi)
+mpp57 57 gpio, spi1(sck), sd0(clk)
+mpp58 58 gpio, pcie1(clkreq) [1], i2c1(sck), pcie2(clkreq), spi1(miso), sd0(d1)
+mpp59 59 gpio, pcie0(rstout), i2c1(sda), pcie1(rstout) [1], spi1(cs0), sd0(d2)
+
+[1]: only available on 88F6820 and 88F6828
+[2]: only available on 88F6828
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt
index bfa0a2e5e0cb..373dbccd7ab0 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt
@@ -6,6 +6,7 @@ part and usage.
Required properties:
- compatible: "marvell,mv78230-pinctrl", "marvell,mv78260-pinctrl",
"marvell,mv78460-pinctrl"
+- reg: register specifier of MPP registers
This driver supports all Armada XP variants, i.e. mv78230, mv78260, and mv78460.
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
index 50ec3512a292..cf52477cc7ee 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
@@ -6,6 +6,7 @@ part and usage.
Required properties:
- compatible: "marvell,dove-pinctrl"
- clocks: (optional) phandle of pdma clock
+- reg: register specifiers of MPP, MPP4, and PMU MPP registers
Available mpp pins/groups and functions:
Note: brackets (x) are not part of the mpp name for marvell,function and given
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt
index 95daf6335c37..730444a9a4de 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt
@@ -8,6 +8,7 @@ Required properties:
"marvell,88f6190-pinctrl", "marvell,88f6192-pinctrl",
"marvell,88f6281-pinctrl", "marvell,88f6282-pinctrl"
"marvell,98dx4122-pinctrl"
+- reg: register specifier of MPP registers
This driver supports all kirkwood variants, i.e. 88f6180, 88f619x, and 88f628x.
It also support the 88f6281-based variant in the 98dx412x Bobcat SoCs.
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt
index 0a26c3aa4e6d..0c09f4eb2af0 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt
@@ -37,7 +37,7 @@ uart1: serial@12100 {
pinctrl: pinctrl@d0200 {
compatible = "marvell,dove-pinctrl";
- reg = <0xd0200 0x20>;
+ reg = <0xd0200 0x14>, <0xd0440 0x04>, <0xd802c 0x08>;
pmx_uart1_sw: pmx-uart1-sw {
marvell,pins = "mpp_uart1";
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
index bc0dfdfdb148..66dcaa9efd74 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
@@ -63,6 +63,13 @@ Optional properties:
/* input, enable bits, disable bits, mask */
pinctrl-single,input-schmitt-enable = <0x30 0x40 0 0x70>;
+- pinctrl-single,low-power-mode : array of value that are used to configure
+ low power mode of this pin. For some silicons, the low power mode will
+ control the output of the pin when the pad including the pin enter low
+ power mode.
+ /* low power mode value, mask */
+ pinctrl-single,low-power-mode = <0x288 0x388>;
+
- pinctrl-single,gpio-range : list of value that are used to configure a GPIO
range. They're value of subnode phandle, pin base in pinctrl device, pin
number in this range, GPIO function value of this GPIO range.
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
index 05bf82a07dfd..4bd5be0e5e7d 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
@@ -11,18 +11,68 @@ Pull Up (PU) are driven by the related PIO block.
ST pinctrl driver controls PIO multiplexing block and also interacts with
gpio driver to configure a pin.
-Required properties: (PIO multiplexing block)
+GPIO bank can have one of the two possible types of interrupt-wirings.
+
+First type is via irqmux, single interrupt is used by multiple gpio banks. This
+reduces number of overall interrupts numbers required. All these banks belong to
+a single pincontroller.
+ _________
+ | |----> [gpio-bank (n) ]
+ | |----> [gpio-bank (n + 1)]
+ [irqN]-- | irq-mux |----> [gpio-bank (n + 2)]
+ | |----> [gpio-bank (... )]
+ |_________|----> [gpio-bank (n + 7)]
+
+Second type has a dedicated interrupt per gpio bank.
+
+ [irqN]----> [gpio-bank (n)]
+
+
+Pin controller node:
+Required properties:
- compatible : should be "st,<SOC>-<pio-block>-pinctrl"
like st,stih415-sbc-pinctrl, st,stih415-front-pinctrl and so on.
-- gpio-controller : Indicates this device is a GPIO controller
-- #gpio-cells : Should be one. The first cell is the pin number.
+- st,syscfg : Should be a phandle of the syscfg node.
- st,retime-pin-mask : Should be mask to specify which pins can be retimed.
If the property is not present, it is assumed that all the pins in the
bank are capable of retiming. Retiming is mainly used to improve the
IO timing margins of external synchronous interfaces.
-- st,bank-name : Should be a name string for this bank as
- specified in datasheet.
-- st,syscfg : Should be a phandle of the syscfg node.
+- ranges : defines mapping between pin controller node (parent) to gpio-bank
+ node (children).
+
+Optional properties:
+- interrupts : Interrupt number of the irqmux. If the interrupt is shared
+ with other gpio banks via irqmux.
+ a irqline and gpio banks.
+- reg : irqmux memory resource. If irqmux is present.
+- reg-names : irqmux resource should be named as "irqmux".
+
+GPIO controller/bank node.
+Required properties:
+- gpio-controller : Indicates this device is a GPIO controller
+- #gpio-cells : Should be one. The first cell is the pin number.
+- st,bank-name : Should be a name string for this bank as specified in
+ datasheet.
+
+Optional properties:
+- interrupts : Interrupt number for this gpio bank. If there is a dedicated
+ interrupt wired up for this gpio bank.
+
+- interrupt-controller : Indicates this device is a interrupt controller. GPIO
+ bank can be an interrupt controller iff one of the interrupt type either via
+irqmux or a dedicated interrupt per bank is specified.
+
+- #interrupt-cells: the value of this property should be 2.
+ - First Cell: represents the external gpio interrupt number local to the
+ gpio interrupt space of the controller.
+ - Second Cell: flags to identify the type of the interrupt
+ - 1 = rising edge triggered
+ - 2 = falling edge triggered
+ - 3 = rising and falling edge triggered
+ - 4 = high level triggered
+ - 8 = low level triggered
+for related macros look in:
+include/dt-bindings/interrupt-controller/irq.h
Example:
pin-controller-sbc {
@@ -30,10 +80,17 @@ Example:
#size-cells = <1>;
compatible = "st,stih415-sbc-pinctrl";
st,syscfg = <&syscfg_sbc>;
+ reg = <0xfe61f080 0x4>;
+ reg-names = "irqmux";
+ interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts-names = "irqmux";
ranges = <0 0xfe610000 0x5000>;
+
PIO0: gpio@fe610000 {
gpio-controller;
#gpio-cells = <1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
reg = <0 0x100>;
st,bank-name = "PIO0";
};
@@ -105,6 +162,10 @@ pin-controller {
sdhci0:sdhci@fe810000{
...
+ interrupt-parent = <&PIO3>;
+ #interrupt-cells = <2>;
+ interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; /* Interrupt line via PIO3-3 */
+ interrupts-names = "card-detect";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mmc>;
};
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt
index 4c352be5dd61..9fb89e3f61ea 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt
@@ -1,7 +1,7 @@
Qualcomm MSM8974 TLMM block
Required properties:
-- compatible: "qcom,msm8x74-pinctrl"
+- compatible: "qcom,msm8974-pinctrl"
- reg: Should be the base address and length of the TLMM block.
- interrupts: Should be the parent IRQ of the TLMM block.
- interrupt-controller: Marks the device node as an interrupt controller.
@@ -42,14 +42,14 @@ Non-empty subnodes must specify the 'pins' property.
Note that not all properties are valid for all pins.
-Valid values for qcom,pins are:
+Valid values for pins are:
gpio0-gpio145
Supports mux, bias and drive-strength
sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk, sdc2_cmd, sdc2_data
Supports bias and drive-strength
-Valid values for qcom,function are:
+Valid values for function are:
blsp_i2c2, blsp_i2c6, blsp_i2c11, blsp_spi1, blsp_uart2, blsp_uart8, slimbus
(Note that this is not yet the complete list of functions)
@@ -73,18 +73,18 @@ Example:
uart2_default: uart2_default {
mux {
- qcom,pins = "gpio4", "gpio5";
- qcom,function = "blsp_uart2";
+ pins = "gpio4", "gpio5";
+ function = "blsp_uart2";
};
tx {
- qcom,pins = "gpio4";
+ pins = "gpio4";
drive-strength = <4>;
bias-disable;
};
rx {
- qcom,pins = "gpio5";
+ pins = "gpio5";
drive-strength = <2>;
bias-pull-up;
};
diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
index 257677de3e6b..2b32783ba821 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
@@ -16,6 +16,7 @@ Required Properties:
- "samsung,exynos4210-pinctrl": for Exynos4210 compatible pin-controller.
- "samsung,exynos4x12-pinctrl": for Exynos4x12 compatible pin-controller.
- "samsung,exynos5250-pinctrl": for Exynos5250 compatible pin-controller.
+ - "samsung,exynos5260-pinctrl": for Exynos5260 compatible pin-controller.
- "samsung,exynos5420-pinctrl": for Exynos5420 compatible pin-controller.
- reg: Base address of the pin controller hardware module and length of
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/l2cache.txt b/Documentation/devicetree/bindings/powerpc/fsl/l2cache.txt
new file mode 100644
index 000000000000..c41b2187eaa8
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/l2cache.txt
@@ -0,0 +1,23 @@
+Freescale L2 Cache Controller
+
+L2 cache is present in Freescale's QorIQ and QorIQ Qonverge platforms.
+The cache bindings explained below are ePAPR compliant
+
+Required Properties:
+
+- compatible : Should include "fsl,chip-l2-cache-controller" and "cache"
+ where chip is the processor (bsc9132, npc8572 etc.)
+- reg : Address and size of L2 cache controller registers
+- cache-size : Size of the entire L2 cache
+- interrupts : Error interrupt of L2 controller
+- cache-line-size : Size of L2 cache lines
+
+Example:
+
+ L2: l2-cache-controller@20000 {
+ compatible = "fsl,bsc9132-l2-cache-controller", "cache";
+ reg = <0x20000 0x1000>;
+ cache-line-size = <32>; // 32 bytes
+ cache-size = <0x40000>; // L2,256K
+ interrupts = <16 2 1 0>;
+ };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt b/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt
new file mode 100644
index 000000000000..f87856faf1ab
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt
@@ -0,0 +1,27 @@
+Freescale DDR memory controller
+
+Properties:
+
+- compatible : Should include "fsl,chip-memory-controller" where
+ chip is the processor (bsc9132, mpc8572 etc.), or
+ "fsl,qoriq-memory-controller".
+- reg : Address and size of DDR controller registers
+- interrupts : Error interrupt of DDR controller
+
+Example 1:
+
+ memory-controller@2000 {
+ compatible = "fsl,bsc9132-memory-controller";
+ reg = <0x2000 0x1000>;
+ interrupts = <16 2 1 8>;
+ };
+
+
+Example 2:
+
+ ddr1: memory-controller@8000 {
+ compatible = "fsl,qoriq-memory-controller-v4.7",
+ "fsl,qoriq-memory-controller";
+ reg = <0x8000 0x1000>;
+ interrupts = <16 2 1 23>;
+ };
diff --git a/Documentation/devicetree/bindings/regulator/gpio-regulator.txt b/Documentation/devicetree/bindings/regulator/gpio-regulator.txt
index 63c659800c03..e5cac1e0ca8a 100644
--- a/Documentation/devicetree/bindings/regulator/gpio-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gpio-regulator.txt
@@ -8,8 +8,12 @@ Required properties:
Optional properties:
- enable-gpio : GPIO to use to enable/disable the regulator.
- gpios : GPIO group used to control voltage.
+- gpios-states : gpios pin's initial states array. 0: LOW, 1: HIGH.
+ defualt is LOW if nothing is specified.
- startup-delay-us : Startup time in microseconds.
- enable-active-high : Polarity of GPIO is active high (default is low).
+- regulator-type : Specifies what is being regulated, must be either
+ "voltage" or "current", defaults to current.
Any property defined as part of the core regulator binding defined in
regulator.txt can also be used.
diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.txt b/Documentation/devicetree/bindings/regulator/pfuze100.txt
index fc989b2e8057..34ef5d16d0f1 100644
--- a/Documentation/devicetree/bindings/regulator/pfuze100.txt
+++ b/Documentation/devicetree/bindings/regulator/pfuze100.txt
@@ -1,7 +1,7 @@
PFUZE100 family of regulators
Required properties:
-- compatible: "fsl,pfuze100"
+- compatible: "fsl,pfuze100" or "fsl,pfuze200"
- reg: I2C slave address
Required child node:
@@ -10,11 +10,14 @@ Required child node:
Documentation/devicetree/bindings/regulator/regulator.txt.
The valid names for regulators are:
+ --PFUZE100
sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6
+ --PFUZE200
+ sw1ab,sw2,sw3a,sw3b,swbst,vsnvs,vrefddr,vgen1~vgen6
Each regulator is defined using the standard binding for regulators.
-Example:
+Example 1: PFUZE100
pmic: pfuze100@08 {
compatible = "fsl,pfuze100";
@@ -113,3 +116,92 @@ Example:
};
};
};
+
+
+Example 2: PFUZE200
+
+ pmic: pfuze200@08 {
+ compatible = "fsl,pfuze200";
+ reg = <0x08>;
+
+ regulators {
+ sw1a_reg: sw1ab {
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <1875000>;
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-ramp-delay = <6250>;
+ };
+
+ sw2_reg: sw2 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw3a_reg: sw3a {
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1975000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ sw3b_reg: sw3b {
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1975000>;
+ 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: vgen1 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1550000>;
+ };
+
+ vgen2_reg: vgen2 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1550000>;
+ };
+
+ vgen3_reg: vgen3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vgen4_reg: vgen4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen5_reg: vgen5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vgen6_reg: vgen6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
index fc6b38f035bd..d290988ed975 100644
--- a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
@@ -69,13 +69,16 @@ sub-node should be of the format as listed below.
};
};
The above regulator entries are defined in regulator bindings documentation
-except op_mode description.
+except these properties:
- op_mode: describes the different operating modes of the LDO's with
power mode change in SOC. The different possible values are,
0 - always off mode
1 - on in normal mode
2 - low power mode
3 - suspend mode
+ - s5m8767,pmic-ext-control-gpios: (optional) GPIO specifier for one
+ GPIO controlling this regulator (enable/disable); This is
+ valid only for buck9.
The following are the names of the regulators that the s5m8767 pmic block
supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
@@ -148,5 +151,13 @@ Example:
regulator-always-on;
regulator-boot-on;
};
+
+ vemmc_reg: BUCK9 {
+ regulator-name = "VMEM_VDD_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ op_mode = <3>; /* Standby Mode */
+ s5m8767,pmic-ext-control-gpios = <&gpk0 2 0>;
+ };
};
};
diff --git a/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt b/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt
index 2e57a33e9029..c58db75f959e 100644
--- a/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt
@@ -4,10 +4,14 @@ Required Properties:
- compatible: Should be one of:
- "ti,abb-v1" for older SoCs like OMAP3
- "ti,abb-v2" for newer SoCs like OMAP4, OMAP5
+ - "ti,abb-v3" for a generic definition where setup and control registers are
+ provided (example: DRA7)
- reg: Address and length of the register set for the device. It contains
the information of registers in the same order as described by reg-names
- reg-names: Should contain the reg names
- - "base-address" - contains base address of ABB module
+ - "base-address" - contains base address of ABB module (ti,abb-v1,ti,abb-v2)
+ - "control-address" - contains control register address of ABB module (ti,abb-v3)
+ - "setup-address" - contains setup register address of ABB module (ti,abb-v3)
- "int-address" - contains address of interrupt register for ABB module
(also see Optional properties)
- #address-cell: should be 0
diff --git a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
new file mode 100644
index 000000000000..3da0ebdba8d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
@@ -0,0 +1,133 @@
+*** Reserved memory regions ***
+
+Reserved memory is specified as a node under the /reserved-memory node.
+The operating system shall exclude reserved memory from normal usage
+one can create child nodes describing particular reserved (excluded from
+normal use) memory regions. Such memory regions are usually designed for
+the special usage by various device drivers.
+
+Parameters for each memory region can be encoded into the device tree
+with the following nodes:
+
+/reserved-memory node
+---------------------
+#address-cells, #size-cells (required) - standard definition
+ - Should use the same values as the root node
+ranges (required) - standard definition
+ - Should be empty
+
+/reserved-memory/ child nodes
+-----------------------------
+Each child of the reserved-memory node specifies one or more regions of
+reserved memory. Each child node may either use a 'reg' property to
+specify a specific range of reserved memory, or a 'size' property with
+optional constraints to request a dynamically allocated block of memory.
+
+Following the generic-names recommended practice, node names should
+reflect the purpose of the node (ie. "framebuffer" or "dma-pool"). Unit
+address (@<address>) should be appended to the name if the node is a
+static allocation.
+
+Properties:
+Requires either a) or b) below.
+a) static allocation
+ reg (required) - standard definition
+b) dynamic allocation
+ size (required) - length based on parent's #size-cells
+ - Size in bytes of memory to reserve.
+ alignment (optional) - length based on parent's #size-cells
+ - Address boundary for alignment of allocation.
+ alloc-ranges (optional) - prop-encoded-array (address, length pairs).
+ - Specifies regions of memory that are
+ acceptable to allocate from.
+
+If both reg and size are present, then the reg property takes precedence
+and size is ignored.
+
+Additional properties:
+compatible (optional) - standard definition
+ - may contain the following strings:
+ - shared-dma-pool: This indicates a region of memory meant to be
+ used as a shared pool of DMA buffers for a set of devices. It can
+ be used by an operating system to instanciate the necessary pool
+ management subsystem if necessary.
+ - vendor specific string in the form <vendor>,[<device>-]<usage>
+no-map (optional) - empty property
+ - Indicates the operating system must not create a virtual mapping
+ of the region as part of its standard mapping of system memory,
+ nor permit speculative access to it under any circumstances other
+ than under the control of the device driver using the region.
+reusable (optional) - empty property
+ - The operating system can use the memory in this region with the
+ limitation that the device driver(s) owning the region need to be
+ able to reclaim it back. Typically that means that the operating
+ system can use that region to store volatile or cached data that
+ can be otherwise regenerated or migrated elsewhere.
+
+Linux implementation note:
+- If a "linux,cma-default" property is present, then Linux will use the
+ region for the default pool of the contiguous memory allocator.
+
+Device node references to reserved memory
+-----------------------------------------
+Regions in the /reserved-memory node may be referenced by other device
+nodes by adding a memory-region property to the device node.
+
+memory-region (optional) - phandle, specifier pairs to children of /reserved-memory
+
+Example
+-------
+This example defines 3 contiguous regions are defined for Linux kernel:
+one default of all device drivers (named linux,cma@72000000 and 64MiB in size),
+one dedicated to the framebuffer device (named framebuffer@78000000, 8MiB), and
+one for multimedia processing (named multimedia-memory@77000000, 64MiB).
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ memory {
+ reg = <0x40000000 0x40000000>;
+ };
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ /* global autoconfigured region for contiguous allocations */
+ linux,cma {
+ compatible = "shared-dma-pool";
+ reusable;
+ size = <0x4000000>;
+ alignment = <0x2000>;
+ linux,cma-default;
+ };
+
+ display_reserved: framebuffer@78000000 {
+ reg = <0x78000000 0x800000>;
+ };
+
+ multimedia_reserved: multimedia@77000000 {
+ compatible = "acme,multimedia-memory";
+ reg = <0x77000000 0x4000000>;
+ };
+ };
+
+ /* ... */
+
+ fb0: video@12300000 {
+ memory-region = <&display_reserved>;
+ /* ... */
+ };
+
+ scaler: scaler@12500000 {
+ memory-region = <&multimedia_reserved>;
+ /* ... */
+ };
+
+ codec: codec@12600000 {
+ memory-region = <&multimedia_reserved>;
+ /* ... */
+ };
+};
diff --git a/Documentation/devicetree/bindings/serial/efm32-uart.txt b/Documentation/devicetree/bindings/serial/efm32-uart.txt
index 8e080b893b49..1984bdfbd545 100644
--- a/Documentation/devicetree/bindings/serial/efm32-uart.txt
+++ b/Documentation/devicetree/bindings/serial/efm32-uart.txt
@@ -6,7 +6,7 @@ Required properties:
- interrupts : Should contain uart interrupt
Optional properties:
-- location : Decides the location of the USART I/O pins.
+- efm32,location : Decides the location of the USART I/O pins.
Allowed range : [0 .. 5]
Default: 0
@@ -16,5 +16,5 @@ uart@0x4000c400 {
compatible = "efm32,uart";
reg = <0x4000c400 0x400>;
interrupts = <15>;
- location = <0>;
+ efm32,location = <0>;
};
diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
index 6fd1dd1638dd..a1d1205d8185 100644
--- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
+++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
@@ -4,11 +4,24 @@ Required properties:
- compatible : Should be "fsl,<soc>-lpuart"
- reg : Address and length of the register set for the device
- interrupts : Should contain uart interrupt
+- clocks : phandle + clock specifier pairs, one for each entry in clock-names
+- clock-names : should contain: "ipg" - the uart clock
+
+Optional properties:
+- dmas: A list of two dma specifiers, one for each entry in dma-names.
+- dma-names: should contain "tx" and "rx".
+
+Note: Optional properties for DMA support. Write them both or both not.
Example:
uart0: serial@40027000 {
- compatible = "fsl,vf610-lpuart";
- reg = <0x40027000 0x1000>;
- interrupts = <0 61 0x00>;
- };
+ compatible = "fsl,vf610-lpuart";
+ reg = <0x40027000 0x1000>;
+ interrupts = <0 61 0x00>;
+ clocks = <&clks VF610_CLK_UART0>;
+ clock-names = "ipg";
+ dmas = <&edma0 0 2>,
+ <&edma0 0 3>;
+ dma-names = "rx","tx";
+ };
diff --git a/Documentation/devicetree/bindings/serial/maxim,max310x.txt b/Documentation/devicetree/bindings/serial/maxim,max310x.txt
new file mode 100644
index 000000000000..83a919c241b0
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/maxim,max310x.txt
@@ -0,0 +1,36 @@
+* Maxim MAX310X advanced Universal Asynchronous Receiver-Transmitter (UART)
+
+Required properties:
+- compatible: Should be one of the following:
+ - "maxim,max3107" for Maxim MAX3107,
+ - "maxim,max3108" for Maxim MAX3108,
+ - "maxim,max3109" for Maxim MAX3109,
+ - "maxim,max14830" for Maxim MAX14830.
+- reg: SPI chip select number.
+- interrupt-parent: The phandle for the interrupt controller that
+ services interrupts for this IC.
+- interrupts: Specifies the interrupt source of the parent interrupt
+ controller. The format of the interrupt specifier depends on the
+ parent interrupt controller.
+- clocks: phandle to the IC source clock.
+- clock-names: Should be "xtal" if clock is an external crystal or
+ "osc" if an external clock source is used.
+
+Optional properties:
+- gpio-controller: Marks the device node as a GPIO controller.
+- #gpio-cells: Should be two. The first cell is the GPIO number and
+ the second cell is used to specify the GPIO polarity:
+ 0 = active high,
+ 1 = active low.
+
+Example:
+ max14830: max14830@0 {
+ compatible = "maxim,max14830";
+ reg = <0>;
+ clocks = <&clk20m>;
+ clock-names = "osc";
+ interrupt-parent = <&gpio3>;
+ interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
index f372cf29068d..53e6c175db6c 100644
--- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
+++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
@@ -37,7 +37,7 @@ Example:
};
scifa0: serial@e6c40000 {
- compatible = "renesas,scifa-r8a7790", "renesas,scifa-generic";
+ compatible = "renesas,scifa-r8a7790", "renesas,scifa";
reg = <0 0xe6c40000 0 64>;
interrupt-parent = <&gic>;
interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/Documentation/devicetree/bindings/sound/armada-370db-audio.txt b/Documentation/devicetree/bindings/sound/armada-370db-audio.txt
new file mode 100644
index 000000000000..bf984d238620
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/armada-370db-audio.txt
@@ -0,0 +1,27 @@
+Device Tree bindings for the Armada 370 DB audio
+================================================
+
+These Device Tree bindings are used to describe the audio complex
+found on the Armada 370 DB platform.
+
+Mandatory properties:
+
+ * compatible: must be "marvell,a370db-audio"
+
+ * marvell,audio-controller: a phandle that points to the audio
+ controller of the Armada 370 SoC.
+
+ * marvell,audio-codec: a set of three phandles that points to:
+
+ 1/ the analog audio codec connected to the Armada 370 SoC
+ 2/ the S/PDIF transceiver
+ 3/ the S/PDIF receiver
+
+Example:
+
+ sound {
+ compatible = "marvell,a370db-audio";
+ marvell,audio-controller = <&audio_controller>;
+ marvell,audio-codec = <&audio_codec &spdif_out &spdif_in>;
+ status = "okay";
+ };
diff --git a/Documentation/devicetree/bindings/sound/cs42xx8.txt b/Documentation/devicetree/bindings/sound/cs42xx8.txt
new file mode 100644
index 000000000000..f631fbca6284
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cs42xx8.txt
@@ -0,0 +1,28 @@
+CS42448/CS42888 audio CODEC
+
+Required properties:
+
+ - compatible : must contain one of "cirrus,cs42448" and "cirrus,cs42888"
+
+ - reg : the I2C address of the device for I2C
+
+ - clocks : a list of phandles + clock-specifiers, one for each entry in
+ clock-names
+
+ - clock-names : must contain "mclk"
+
+ - VA-supply, VD-supply, VLS-supply, VLC-supply: power supplies for the device,
+ as covered in Documentation/devicetree/bindings/regulator/regulator.txt
+
+Example:
+
+codec: cs42888@48 {
+ compatible = "cirrus,cs42888";
+ reg = <0x48>;
+ clocks = <&codec_mclk 0>;
+ clock-names = "mclk";
+ VA-supply = <&reg_audio>;
+ VD-supply = <&reg_audio>;
+ VLS-supply = <&reg_audio>;
+ VLC-supply = <&reg_audio>;
+};
diff --git a/Documentation/devicetree/bindings/sound/da9055.txt b/Documentation/devicetree/bindings/sound/da9055.txt
new file mode 100644
index 000000000000..ed1b7cc6f249
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/da9055.txt
@@ -0,0 +1,22 @@
+* Dialog DA9055 Audio CODEC
+
+DA9055 provides Audio CODEC support (I2C only).
+
+The Audio CODEC device in DA9055 has it's own I2C address which is configurable,
+so the device is instantiated separately from the PMIC (MFD) device.
+
+For details on accompanying PMIC I2C device, see the following:
+Documentation/devicetree/bindings/mfd/da9055.txt
+
+Required properties:
+
+ - compatible: "dlg,da9055-codec"
+ - reg: Specifies the I2C slave address
+
+
+Example:
+
+ codec: da9055-codec@1a {
+ compatible = "dlg,da9055-codec";
+ reg = <0x1a>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
index 865178d5cdf3..963e100514c2 100644
--- a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
+++ b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
@@ -5,12 +5,19 @@ Required properties:
- ti,model : The user-visible name of this sound complex.
- ti,audio-codec : The phandle of the TLV320AIC3x audio codec
- ti,mcasp-controller : The phandle of the McASP controller
-- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec
- ti,audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source. Valid names for sources and
sinks are the codec's pins, and the jacks on the board:
+Optional properties:
+- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec.
+- clocks : Reference to the master clock
+- clock-names : The clock should be named "mclk"
+- Either codec-clock-rate or the codec-clock reference has to be defined. If
+ the both are defined the driver attempts to set referenced clock to the
+ defined rate and takes the rate from the clock reference.
+
Board connectors:
* Headphone Jack
diff --git a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt
new file mode 100644
index 000000000000..0d7985c864af
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt
@@ -0,0 +1,21 @@
+Audio complex for Eukrea boards with tlv320aic23 codec.
+
+Required properties:
+- compatible : "eukrea,asoc-tlv320"
+- eukrea,model : The user-visible name of this sound complex.
+- ssi-controller : The phandle of the SSI controller.
+- fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX).
+- fsl,mux-ext-port : The external port of the i.MX audio muxer.
+
+Note: The AUDMUX port numbering should start at 1, which is consistent with
+hardware manual.
+
+Example:
+
+ sound {
+ compatible = "eukrea,asoc-tlv320";
+ eukrea,model = "imx51-eukrea-tlv320aic23";
+ ssi-controller = <&ssi2>;
+ fsl,mux-int-port = <2>;
+ fsl,mux-ext-port = <3>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt
index d7b99fa637b5..aeb8c4a0b88d 100644
--- a/Documentation/devicetree/bindings/sound/fsl,esai.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt
@@ -34,6 +34,10 @@ Required properties:
that ESAI would work in the synchronous mode, which means all the settings
for Receiving would be duplicated from Transmition related registers.
+ - big-endian : If this property is absent, the native endian mode will
+ be in use as default, or the big endian mode will be in use for all the
+ device registers.
+
Example:
esai: esai@02024000 {
@@ -46,5 +50,6 @@ esai: esai@02024000 {
dma-names = "rx", "tx";
fsl,fifo-depth = <128>;
fsl,esai-synchronous;
+ big-endian;
status = "disabled";
};
diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
index f2ae335670f5..3e9e82c8eab3 100644
--- a/Documentation/devicetree/bindings/sound/fsl,spdif.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
@@ -29,6 +29,10 @@ Required properties:
can also be referred to TxClk_Source
bit of register SPDIF_STC.
+ - big-endian : If this property is absent, the native endian mode will
+ be in use as default, or the big endian mode will be in use for all the
+ device registers.
+
Example:
spdif: spdif@02004000 {
@@ -50,5 +54,6 @@ spdif: spdif@02004000 {
"rxtx5", "rxtx6",
"rxtx7";
+ big-endian;
status = "okay";
};
diff --git a/Documentation/devicetree/bindings/sound/mvebu-audio.txt b/Documentation/devicetree/bindings/sound/mvebu-audio.txt
index f0062c5871b4..cb8c07c81ce4 100644
--- a/Documentation/devicetree/bindings/sound/mvebu-audio.txt
+++ b/Documentation/devicetree/bindings/sound/mvebu-audio.txt
@@ -5,6 +5,7 @@ Required properties:
- compatible:
"marvell,kirkwood-audio" for Kirkwood platforms
"marvell,dove-audio" for Dove platforms
+ "marvell,armada370-audio" for Armada 370 platforms
- reg: physical base address of the controller and length of memory mapped
region.
diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt b/Documentation/devicetree/bindings/sound/pcm512x.txt
new file mode 100644
index 000000000000..faff75e64573
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/pcm512x.txt
@@ -0,0 +1,30 @@
+PCM512x audio CODECs
+
+These devices support both I2C and SPI (configured with pin strapping
+on the board).
+
+Required properties:
+
+ - compatible : One of "ti,pcm5121" or "ti,pcm5122"
+
+ - reg : the I2C address of the device for I2C, the chip select
+ number for SPI.
+
+ - AVDD-supply, DVDD-supply, and CPVDD-supply : power supplies for the
+ device, as covered in bindings/regulator/regulator.txt
+
+Optional properties:
+
+ - clocks : A clock specifier for the clock connected as SCLK. If this
+ is absent the device will be configured to clock from BCLK.
+
+Example:
+
+ pcm5122: pcm5122@4c {
+ compatible = "ti,pcm5122";
+ reg = <0x4c>;
+
+ AVDD-supply = <&reg_3v3_analog>;
+ DVDD-supply = <&reg_1v8>;
+ CPVDD-supply = <&reg_3v3>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
new file mode 100644
index 000000000000..a44e9179faf5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -0,0 +1,105 @@
+Renesas R-Car sound
+
+Required properties:
+- compatible : "renesas,rcar_sound-gen1" if generation1
+ "renesas,rcar_sound-gen2" if generation2
+- reg : Should contain the register physical address.
+ required register is
+ SRU/ADG/SSI if generation1
+ SRU/ADG/SSIU/SSI if generation2
+- rcar_sound,ssi : Should contain SSI feature.
+ The number of SSI subnode should be same as HW.
+ see below for detail.
+- rcar_sound,src : Should contain SRC feature.
+ The number of SRC subnode should be same as HW.
+ see below for detail.
+- rcar_sound,dai : DAI contents.
+ The number of DAI subnode should be same as HW.
+ see below for detail.
+
+SSI subnode properties:
+- interrupts : Should contain SSI interrupt for PIO transfer
+- shared-pin : if shared clock pin
+
+SRC subnode properties:
+no properties at this point
+
+DAI subnode properties:
+- playback : list of playback modules
+- capture : list of capture modules
+
+Example:
+
+rcar_sound: rcar_sound@0xffd90000 {
+ #sound-dai-cells = <1>;
+ compatible = "renesas,rcar_sound-gen2";
+ reg = <0 0xec500000 0 0x1000>, /* SCU */
+ <0 0xec5a0000 0 0x100>, /* ADG */
+ <0 0xec540000 0 0x1000>, /* SSIU */
+ <0 0xec541000 0 0x1280>; /* SSI */
+
+ rcar_sound,src {
+ src0: src@0 { };
+ src1: src@1 { };
+ src2: src@2 { };
+ src3: src@3 { };
+ src4: src@4 { };
+ src5: src@5 { };
+ src6: src@6 { };
+ src7: src@7 { };
+ src8: src@8 { };
+ src9: src@9 { };
+ };
+
+ rcar_sound,ssi {
+ ssi0: ssi@0 {
+ interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi1: ssi@1 {
+ interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi2: ssi@2 {
+ interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi3: ssi@3 {
+ interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi4: ssi@4 {
+ interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi5: ssi@5 {
+ interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi6: ssi@6 {
+ interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi7: ssi@7 {
+ interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi8: ssi@8 {
+ interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ ssi9: ssi@9 {
+ interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+
+ rcar_sound,dai {
+ dai0 {
+ playback = <&ssi5 &src5>;
+ capture = <&ssi6>;
+ };
+ dai1 {
+ playback = <&ssi3>;
+ };
+ dai2 {
+ capture = <&ssi4>;
+ };
+ dai3 {
+ playback = <&ssi7>;
+ };
+ dai4 {
+ capture = <&ssi8>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
index 19c84df5fffa..131aa2ad7f1a 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-card.txt
@@ -8,16 +8,26 @@ Required properties:
Optional properties:
+- simple-audio-card,name : User specified audio sound card name, one string
+ property.
- simple-audio-card,format : CPU/CODEC common audio format.
"i2s", "right_j", "left_j" , "dsp_a"
"dsp_b", "ac97", "pdm", "msb", "lsb"
+- simple-audio-card,widgets : Please refer to widgets.txt.
- simple-audio-card,routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the
connection's sink, the second being the connection's
source.
+- dai-tdm-slot-num : Please refer to tdm-slot.txt.
+- dai-tdm-slot-width : Please refer to tdm-slot.txt.
Required subnodes:
+- simple-audio-card,dai-link : container for the CPU and CODEC sub-nodes
+ This container may be omitted when the
+ card has only one DAI link.
+ See the examples.
+
- simple-audio-card,cpu : CPU sub-node
- simple-audio-card,codec : CODEC sub-node
@@ -38,15 +48,29 @@ Optional CPU/CODEC subnodes properties:
clock node (= common clock), or "system-clock-frequency"
(if system doens't support common clock)
-Example:
+Note:
+ * For 'format', 'frame-master', 'bitclock-master', 'bitclock-inversion' and
+ 'frame-inversion', the simple card will use the settings of CODEC for both
+ CPU and CODEC sides as we need to keep the settings identical for both ends
+ of the link.
+
+Example 1 - single DAI link:
sound {
compatible = "simple-audio-card";
+ simple-audio-card,name = "VF610-Tower-Sound-Card";
simple-audio-card,format = "left_j";
+ simple-audio-card,widgets =
+ "Microphone", "Microphone Jack",
+ "Headphone", "Headphone Jack",
+ "Speaker", "External Speaker";
simple-audio-card,routing =
- "MIC_IN", "Mic Jack",
+ "MIC_IN", "Microphone Jack",
"Headphone Jack", "HP_OUT",
- "Ext Spk", "LINE_OUT";
+ "External Speaker", "LINE_OUT";
+
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <8>;
simple-audio-card,cpu {
sound-dai = <&sh_fsi2 0>;
@@ -75,3 +99,38 @@ sh_fsi2: sh_fsi2@ec230000 {
interrupt-parent = <&gic>;
interrupts = <0 146 0x4>;
};
+
+Example 2 - many DAI links:
+
+sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "Cubox Audio";
+ simple-audio-card,format = "i2s";
+
+ simple-audio-card,dai-link@0 { /* I2S - HDMI */
+ simple-audio-card,cpu {
+ sound-dai = <&audio1 0>;
+ };
+ simple-audio-card,codec {
+ sound-dai = <&tda998x 0>;
+ };
+ };
+
+ simple-audio-card,dai-link@1 { /* S/PDIF - HDMI */
+ simple-audio-card,cpu {
+ sound-dai = <&audio1 1>;
+ };
+ simple-audio-card,codec {
+ sound-dai = <&tda998x 1>;
+ };
+ };
+
+ simple-audio-card,dai-link@2 { /* S/PDIF - S/PDIF */
+ simple-audio-card,cpu {
+ sound-dai = <&audio1 1>;
+ };
+ simple-audio-card,codec {
+ sound-dai = <&spdif_codec>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt b/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt
new file mode 100644
index 000000000000..062f5ec36f9b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt
@@ -0,0 +1,17 @@
+SiRF internal audio CODEC
+
+Required properties:
+
+ - compatible : "sirf,atlas6-audio-codec" or "sirf,prima2-audio-codec"
+
+ - reg : the register address of the device.
+
+ - clocks: the clock of SiRF internal audio codec
+
+Example:
+
+audiocodec: audiocodec@b0040000 {
+ compatible = "sirf,atlas6-audio-codec";
+ reg = <0xb0040000 0x10000>;
+ clocks = <&clks 27>;
+};
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio-port.txt b/Documentation/devicetree/bindings/sound/sirf-audio-port.txt
new file mode 100644
index 000000000000..1f66de3c8f00
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sirf-audio-port.txt
@@ -0,0 +1,20 @@
+* SiRF SoC audio port
+
+Required properties:
+- compatible: "sirf,audio-port"
+- reg: Base address and size entries:
+- dmas: List of DMA controller phandle and DMA request line ordered pairs.
+- dma-names: Identifier string for each DMA request line in the dmas property.
+ These strings correspond 1:1 with the ordered pairs in dmas.
+
+ One of the DMA channels will be responsible for transmission (should be
+ named "tx") and one for reception (should be named "rx").
+
+Example:
+
+audioport: audioport@b0040000 {
+ compatible = "sirf,audio-port";
+ reg = <0xb0040000 0x10000>;
+ dmas = <&dmac1 3>, <&dmac1 8>;
+ dma-names = "rx", "tx";
+};
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio.txt b/Documentation/devicetree/bindings/sound/sirf-audio.txt
new file mode 100644
index 000000000000..c88882ca3704
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sirf-audio.txt
@@ -0,0 +1,41 @@
+* SiRF atlas6 and prima2 internal audio codec and port based audio setups
+
+Required properties:
+- compatible: "sirf,sirf-audio-card"
+- sirf,audio-platform: phandle for the platform node
+- sirf,audio-codec: phandle for the SiRF internal codec node
+
+Optional properties:
+- hp-pa-gpios: Need to be present if the board need control external
+ headphone amplifier.
+- spk-pa-gpios: Need to be present if the board need control external
+ speaker amplifier.
+- hp-switch-gpios: Need to be present if the board capable to detect jack
+ insertion, removal.
+
+Available audio endpoints for the audio-routing table:
+
+Board connectors:
+ * Headset Stereophone
+ * Ext Spk
+ * Line In
+ * Mic
+
+SiRF internal audio codec pins:
+ * HPOUTL
+ * HPOUTR
+ * SPKOUT
+ * Ext Mic
+ * Mic Bias
+
+Example:
+
+sound {
+ compatible = "sirf,sirf-audio-card";
+ sirf,audio-codec = <&audiocodec>;
+ sirf,audio-platform = <&audioport>;
+ hp-pa-gpios = <&gpio 44 0>;
+ spk-pa-gpios = <&gpio 46 0>;
+ hp-switch-gpios = <&gpio 45 0>;
+};
+
diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.txt b/Documentation/devicetree/bindings/sound/tdm-slot.txt
new file mode 100644
index 000000000000..6a2c84247f91
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tdm-slot.txt
@@ -0,0 +1,20 @@
+TDM slot:
+
+This specifies audio DAI's TDM slot.
+
+TDM slot properties:
+dai-tdm-slot-num : Number of slots in use.
+dai-tdm-slot-width : Width in bits for each slot.
+
+For instance:
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <8>;
+
+And for each spcified driver, there could be one .of_xlate_tdm_slot_mask()
+to specify a explicit mapping of the channels and the slots. If it's absent
+the default snd_soc_of_xlate_tdm_slot_mask() will be used to generating the
+tx and rx masks.
+
+For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit
+for an active slot as default, and the default active bits are at the LSB of
+the masks.
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
new file mode 100644
index 000000000000..74c66dee3e14
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
@@ -0,0 +1,61 @@
+Texas Instruments - tlv320aic31xx Codec module
+
+The tlv320aic31xx serial control bus communicates through I2C protocols
+
+Required properties:
+
+- compatible - "string" - One of:
+ "ti,tlv320aic310x" - Generic TLV320AIC31xx with mono speaker amp
+ "ti,tlv320aic311x" - Generic TLV320AIC31xx with stereo speaker amp
+ "ti,tlv320aic3100" - TLV320AIC3100 (mono speaker amp, no MiniDSP)
+ "ti,tlv320aic3110" - TLV320AIC3110 (stereo speaker amp, no MiniDSP)
+ "ti,tlv320aic3120" - TLV320AIC3120 (mono speaker amp, MiniDSP)
+ "ti,tlv320aic3111" - TLV320AIC3111 (stereo speaker amp, MiniDSP)
+
+- reg - <int> - I2C slave address
+
+
+Optional properties:
+
+- gpio-reset - gpio pin number used for codec reset
+- ai31xx-micbias-vg - MicBias Voltage setting
+ 1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V
+ 2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V
+ 3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD
+ If this node is not mentioned or if the value is unknown, then
+ micbias is set to 2.0V.
+- HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply,
+ DVDD-supply : power supplies for the device as covered in
+ Documentation/devicetree/bindings/regulator/regulator.txt
+
+CODEC output pins:
+ * HPL
+ * HPR
+ * SPL, devices with stereo speaker amp
+ * SPR, devices with stereo speaker amp
+ * SPK, devices with mono speaker amp
+ * MICBIAS
+
+CODEC input pins:
+ * MIC1LP
+ * MIC1RP
+ * MIC1LM
+
+The pins can be used in referring sound node's audio-routing property.
+
+Example:
+#include <dt-bindings/sound/tlv320aic31xx-micbias.h>
+
+tlv320aic31xx: tlv320aic31xx@18 {
+ compatible = "ti,tlv320aic311x";
+ reg = <0x18>;
+
+ ai31xx-micbias-vg = <MICBIAS_OFF>;
+
+ HPVDD-supply = <&regulator>;
+ SPRVDD-supply = <&regulator>;
+ SPLVDD-supply = <&regulator>;
+ AVDD-supply = <&regulator>;
+ IOVDD-supply = <&regulator>;
+ DVDD-supply = <&regulator>;
+};
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt
new file mode 100644
index 000000000000..5e2741af27be
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt
@@ -0,0 +1,30 @@
+Texas Instruments - tlv320aic32x4 Codec module
+
+The tlv320aic32x4 serial control bus communicates through I2C protocols
+
+Required properties:
+ - compatible: Should be "ti,tlv320aic32x4"
+ - reg: I2C slave address
+ - supply-*: Required supply regulators are:
+ "iov" - digital IO power supply
+ "ldoin" - LDO power supply
+ "dv" - Digital core power supply
+ "av" - Analog core power supply
+ If you supply ldoin, dv and av are optional. Otherwise they are required
+ See regulator/regulator.txt for more information about the detailed binding
+ format.
+
+Optional properties:
+ - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt
+ - clocks/clock-names: Clock named 'mclk' for the master clock of the codec.
+ See clock/clock-bindings.txt for information about the detailed format.
+
+
+Example:
+
+codec: tlv320aic32x4@18 {
+ compatible = "ti,tlv320aic32x4";
+ reg = <0x18>;
+ clocks = <&clks 201>;
+ clock-names = "mclk";
+};
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
index 9d8ea14db490..5e6040c2c2e9 100644
--- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
+++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
@@ -6,7 +6,6 @@ Required properties:
- compatible - "string" - One of:
"ti,tlv320aic3x" - Generic TLV320AIC3x device
- "ti,tlv320aic32x4" - TLV320AIC32x4
"ti,tlv320aic33" - TLV320AIC33
"ti,tlv320aic3007" - TLV320AIC3007
"ti,tlv320aic3106" - TLV320AIC3106
diff --git a/Documentation/devicetree/bindings/sound/widgets.txt b/Documentation/devicetree/bindings/sound/widgets.txt
new file mode 100644
index 000000000000..b6de5ba3b2de
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/widgets.txt
@@ -0,0 +1,20 @@
+Widgets:
+
+This mainly specifies audio off-codec DAPM widgets.
+
+Each entry is a pair of strings in DT:
+
+ "template-wname", "user-supplied-wname"
+
+The "template-wname" being the template widget name and currently includes:
+"Microphone", "Line", "Headphone" and "Speaker".
+
+The "user-supplied-wname" being the user specified widget name.
+
+For instance:
+ simple-audio-widgets =
+ "Microphone", "Microphone Jack",
+ "Line", "Line In Jack",
+ "Line", "Line Out Jack",
+ "Headphone", "Headphone Jack",
+ "Speaker", "Speaker External";
diff --git a/Documentation/devicetree/bindings/spi/efm32-spi.txt b/Documentation/devicetree/bindings/spi/efm32-spi.txt
index a590ca51be75..8f081c96a4fa 100644
--- a/Documentation/devicetree/bindings/spi/efm32-spi.txt
+++ b/Documentation/devicetree/bindings/spi/efm32-spi.txt
@@ -3,24 +3,24 @@
Required properties:
- #address-cells: see spi-bus.txt
- #size-cells: see spi-bus.txt
-- compatible: should be "efm32,spi"
+- compatible: should be "energymicro,efm32-spi"
- reg: Offset and length of the register set for the controller
- interrupts: pair specifying rx and tx irq
- clocks: phandle to the spi clock
- cs-gpios: see spi-bus.txt
-- location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values.
+- efm32,location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values.
Example:
spi1: spi@0x4000c400 { /* USART1 */
#address-cells = <1>;
#size-cells = <0>;
- compatible = "efm32,spi";
+ compatible = "energymicro,efm32-spi";
reg = <0x4000c400 0x400>;
interrupts = <15 16>;
clocks = <&cmu 20>;
cs-gpios = <&gpio 51 1>; // D3
- location = <1>;
+ efm32,location = <1>;
status = "ok";
ks8851@0 {
diff --git a/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
new file mode 100644
index 000000000000..b82a268f1bd4
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
@@ -0,0 +1,85 @@
+Qualcomm Universal Peripheral (QUP) Serial Peripheral Interface (SPI)
+
+The QUP core is an AHB slave that provides a common data path (an output FIFO
+and an input FIFO) for serial peripheral interface (SPI) mini-core.
+
+SPI in master mode supports up to 50MHz, up to four chip selects, programmable
+data path from 4 bits to 32 bits and numerous protocol variants.
+
+Required properties:
+- compatible: Should contain "qcom,spi-qup-v2.1.1" or "qcom,spi-qup-v2.2.1"
+- reg: Should contain base register location and length
+- interrupts: Interrupt number used by this controller
+
+- clocks: Should contain the core clock and the AHB clock.
+- clock-names: Should be "core" for the core clock and "iface" for the
+ AHB clock.
+
+- #address-cells: Number of cells required to define a chip select
+ address on the SPI bus. Should be set to 1.
+- #size-cells: Should be zero.
+
+Optional properties:
+- spi-max-frequency: Specifies maximum SPI clock frequency,
+ Units - Hz. Definition as per
+ Documentation/devicetree/bindings/spi/spi-bus.txt
+
+SPI slave nodes must be children of the SPI master node and can contain
+properties described in Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Example:
+
+ spi_8: spi@f9964000 { /* BLSP2 QUP2 */
+
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xf9964000 0x1000>;
+ interrupts = <0 102 0>;
+ spi-max-frequency = <19200000>;
+
+ clocks = <&gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
+ clock-names = "core", "iface";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi8_default>;
+
+ device@0 {
+ compatible = "arm,pl022-dummy";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <19200000>;
+ spi-cpol;
+ };
+
+ device@1 {
+ compatible = "arm,pl022-dummy";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <1>; /* Chip select 1 */
+ spi-max-frequency = <9600000>;
+ spi-cpha;
+ };
+
+ device@2 {
+ compatible = "arm,pl022-dummy";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <2>; /* Chip select 2 */
+ spi-max-frequency = <19200000>;
+ spi-cpol;
+ spi-cpha;
+ };
+
+ device@3 {
+ compatible = "arm,pl022-dummy";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <3>; /* Chip select 3 */
+ spi-max-frequency = <19200000>;
+ spi-cpol;
+ spi-cpha;
+ spi-cs-high;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/spi/sh-hspi.txt b/Documentation/devicetree/bindings/spi/sh-hspi.txt
index 30b57b1c8a13..319bad4af875 100644
--- a/Documentation/devicetree/bindings/spi/sh-hspi.txt
+++ b/Documentation/devicetree/bindings/spi/sh-hspi.txt
@@ -1,7 +1,29 @@
Renesas HSPI.
Required properties:
-- compatible : "renesas,hspi"
-- reg : Offset and length of the register set for the device
-- interrupts : interrupt line used by HSPI
+- compatible : "renesas,hspi-<soctype>", "renesas,hspi" as fallback.
+ Examples with soctypes are:
+ - "renesas,hspi-r8a7778" (R-Car M1)
+ - "renesas,hspi-r8a7779" (R-Car H1)
+- reg : Offset and length of the register set for the device
+- interrupt-parent : The phandle for the interrupt controller that
+ services interrupts for this device
+- interrupts : Interrupt specifier
+- #address-cells : Must be <1>
+- #size-cells : Must be <0>
+
+Pinctrl properties might be needed, too. See
+Documentation/devicetree/bindings/pinctrl/renesas,*.
+
+Example:
+
+ hspi0: spi@fffc7000 {
+ compatible = "renesas,hspi-r8a7778", "renesas,hspi";
+ reg = <0xfffc7000 0x18>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt
index e6222106ca36..f24baf3b6cc1 100644
--- a/Documentation/devicetree/bindings/spi/sh-msiof.txt
+++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt
@@ -1,12 +1,40 @@
Renesas MSIOF spi controller
Required properties:
-- compatible : "renesas,sh-msiof" for SuperH or
- "renesas,sh-mobile-msiof" for SH Mobile series
-- reg : Offset and length of the register set for the device
-- interrupts : interrupt line used by MSIOF
+- compatible : "renesas,msiof-<soctype>" for SoCs,
+ "renesas,sh-msiof" for SuperH, or
+ "renesas,sh-mobile-msiof" for SH Mobile series.
+ Examples with soctypes are:
+ "renesas,msiof-r8a7790" (R-Car H2)
+ "renesas,msiof-r8a7791" (R-Car M2)
+- reg : Offset and length of the register set for the device
+- interrupt-parent : The phandle for the interrupt controller that
+ services interrupts for this device
+- interrupts : Interrupt specifier
+- #address-cells : Must be <1>
+- #size-cells : Must be <0>
Optional properties:
-- num-cs : total number of chip-selects
-- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
-- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
+- clocks : Must contain a reference to the functional clock.
+- num-cs : Total number of chip-selects (default is 1)
+
+Optional properties, deprecated for soctype-specific bindings:
+- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
+ (default is 64)
+- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
+ (default is 64, or 256 on R-Car H2 and M2)
+
+Pinctrl properties might be needed, too. See
+Documentation/devicetree/bindings/pinctrl/renesas,*.
+
+Example:
+
+ msiof0: spi@e6e20000 {
+ compatible = "renesas,msiof-r8a7791";
+ reg = <0 0xe6e20000 0 0x0064>;
+ interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
index a1fb3035a42b..5376de40f10b 100644
--- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
+++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
@@ -10,6 +10,7 @@ Required properties:
- pinctrl-names: must contain a "default" entry.
- spi-num-chipselects : the number of the chipselect signals.
- bus-num : the slave chip chipselect signal number.
+- big-endian : if DSPI modudle is big endian, the bool will be set in node.
Example:
dspi0@4002c000 {
@@ -24,6 +25,7 @@ dspi0@4002c000 {
bus-num = <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_dspi0_1>;
+ big-endian;
status = "okay";
sflash: at26df081a@0 {
diff --git a/Documentation/devicetree/bindings/spi/spi-rspi.txt b/Documentation/devicetree/bindings/spi/spi-rspi.txt
new file mode 100644
index 000000000000..d57d82a74054
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-rspi.txt
@@ -0,0 +1,61 @@
+Device tree configuration for Renesas RSPI/QSPI driver
+
+Required properties:
+- compatible : For Renesas Serial Peripheral Interface on legacy SH:
+ "renesas,rspi-<soctype>", "renesas,rspi" as fallback.
+ For Renesas Serial Peripheral Interface on RZ/A1H:
+ "renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback.
+ For Quad Serial Peripheral Interface on R-Car Gen2:
+ "renesas,qspi-<soctype>", "renesas,qspi" as fallback.
+ Examples with soctypes are:
+ - "renesas,rspi-sh7757" (SH)
+ - "renesas,rspi-r7s72100" (RZ/A1H)
+ - "renesas,qspi-r8a7790" (R-Car H2)
+ - "renesas,qspi-r8a7791" (R-Car M2)
+- reg : Address start and address range size of the device
+- interrupts : A list of interrupt-specifiers, one for each entry in
+ interrupt-names.
+ If interrupt-names is not present, an interrupt specifier
+ for a single muxed interrupt.
+- interrupt-names : A list of interrupt names. Should contain (if present):
+ - "error" for SPEI,
+ - "rx" for SPRI,
+ - "tx" to SPTI,
+ - "mux" for a single muxed interrupt.
+- interrupt-parent : The phandle for the interrupt controller that
+ services interrupts for this device.
+- num-cs : Number of chip selects. Some RSPI cores have more than 1.
+- #address-cells : Must be <1>
+- #size-cells : Must be <0>
+
+Optional properties:
+- clocks : Must contain a reference to the functional clock.
+
+Pinctrl properties might be needed, too. See
+Documentation/devicetree/bindings/pinctrl/renesas,*.
+
+Examples:
+
+ spi0: spi@e800c800 {
+ compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
+ reg = <0xe800c800 0x24>;
+ interrupts = <0 238 IRQ_TYPE_LEVEL_HIGH>,
+ <0 239 IRQ_TYPE_LEVEL_HIGH>,
+ <0 240 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error", "rx", "tx";
+ interrupt-parent = <&gic>;
+ num-cs = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ spi: spi@e6b10000 {
+ compatible = "renesas,qspi-r8a7791", "renesas,qspi";
+ reg = <0 0xe6b10000 0 0x2c>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7791_CLK_QSPI_MOD>;
+ num-cs = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/spi/spi-sun4i.txt b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
new file mode 100644
index 000000000000..de827f5a301e
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
@@ -0,0 +1,24 @@
+Allwinner A10 SPI controller
+
+Required properties:
+- compatible: Should be "allwinner,sun4-a10-spi".
+- reg: Should contain register location and length.
+- interrupts: Should contain interrupt.
+- clocks: phandle to the clocks feeding the SPI controller. Two are
+ needed:
+ - "ahb": the gated AHB parent clock
+ - "mod": the parent module clock
+- clock-names: Must contain the clock names described just above
+
+Example:
+
+spi1: spi@01c06000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c06000 0x1000>;
+ interrupts = <11>;
+ clocks = <&ahb_gates 21>, <&spi1_clk>;
+ clock-names = "ahb", "mod";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/spi/spi-sun6i.txt b/Documentation/devicetree/bindings/spi/spi-sun6i.txt
new file mode 100644
index 000000000000..21de73db6a05
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-sun6i.txt
@@ -0,0 +1,24 @@
+Allwinner A31 SPI controller
+
+Required properties:
+- compatible: Should be "allwinner,sun6i-a31-spi".
+- reg: Should contain register location and length.
+- interrupts: Should contain interrupt.
+- clocks: phandle to the clocks feeding the SPI controller. Two are
+ needed:
+ - "ahb": the gated AHB parent clock
+ - "mod": the parent module clock
+- clock-names: Must contain the clock names described just above
+- resets: phandle to the reset controller asserting this device in
+ reset
+
+Example:
+
+spi1: spi@01c69000 {
+ compatible = "allwinner,sun6i-a31-spi";
+ reg = <0x01c69000 0x1000>;
+ interrupts = <0 66 4>;
+ clocks = <&ahb1_gates 21>, <&spi1_clk>;
+ clock-names = "ahb", "mod";
+ resets = <&ahb1_rst 21>;
+};
diff --git a/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt b/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt
new file mode 100644
index 000000000000..b6ebe2bc7041
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt
@@ -0,0 +1,9 @@
+Cadence Xtensa XTFPGA platform SPI controller.
+
+This simple SPI master controller is built into xtfpga bitstreams and is used
+to control daughterboard audio codec.
+
+Required properties:
+- compatible: should be "cdns,xtfpga-spi".
+- reg: physical base address of the controller and length of memory mapped
+ region.
diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
new file mode 100644
index 000000000000..715d0998af8e
--- /dev/null
+++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
@@ -0,0 +1,61 @@
+Qualcomm SPMI Controller (PMIC Arbiter)
+
+The SPMI PMIC Arbiter is found on the Snapdragon 800 Series. It is an SPMI
+controller with wrapping arbitration logic to allow for multiple on-chip
+devices to control a single SPMI master.
+
+The PMIC Arbiter can also act as an interrupt controller, providing interrupts
+to slave devices.
+
+See spmi.txt for the generic SPMI controller binding requirements for child
+nodes.
+
+See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for
+generic interrupt controller binding documentation.
+
+Required properties:
+- compatible : should be "qcom,spmi-pmic-arb".
+- reg-names : must contain:
+ "core" - core registers
+ "intr" - interrupt controller registers
+ "cnfg" - configuration registers
+- reg : address + size pairs describing the PMIC arb register sets; order must
+ correspond with the order of entries in reg-names
+- #address-cells : must be set to 2
+- #size-cells : must be set to 0
+- qcom,ee : indicates the active Execution Environment identifier (0-5)
+- qcom,channel : which of the PMIC Arb provided channels to use for accesses (0-5)
+- interrupts : interrupt list for the PMIC Arb controller, must contain a
+ single interrupt entry for the peripheral interrupt
+- interrupt-names : corresponding interrupt names for the interrupts
+ listed in the 'interrupts' property, must contain:
+ "periph_irq" - summary interrupt for PMIC peripherals
+- interrupt-controller : boolean indicator that the PMIC arbiter is an interrupt controller
+- #interrupt-cells : must be set to 4. Interrupts are specified as a 4-tuple:
+ cell 1: slave ID for the requested interrupt (0-15)
+ cell 2: peripheral ID for requested interrupt (0-255)
+ cell 3: the requested peripheral interrupt (0-7)
+ cell 4: interrupt flags indicating level-sense information, as defined in
+ dt-bindings/interrupt-controller/irq.h
+
+Example:
+
+ spmi {
+ compatible = "qcom,spmi-pmic-arb";
+ reg-names = "core", "intr", "cnfg";
+ reg = <0xfc4cf000 0x1000>,
+ <0xfc4cb000 0x1000>,
+ <0xfc4ca000 0x1000>;
+
+ interrupt-names = "periph_irq";
+ interrupts = <0 190 0>;
+
+ qcom,ee = <0>;
+ qcom,channel = <0>;
+
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ interrupt-controller;
+ #interrupt-cells = <4>;
+ };
diff --git a/Documentation/devicetree/bindings/spmi/spmi.txt b/Documentation/devicetree/bindings/spmi/spmi.txt
new file mode 100644
index 000000000000..462a42fb3a1e
--- /dev/null
+++ b/Documentation/devicetree/bindings/spmi/spmi.txt
@@ -0,0 +1,41 @@
+System Power Management Interface (SPMI) Controller
+
+This document defines a generic set of bindings for use by SPMI controllers. A
+controller is modelled in device tree as a node with zero or more child nodes,
+each representing a unique slave on the bus.
+
+Required properties:
+- #address-cells : must be set to 2
+- #size-cells : must be set to 0
+
+Child nodes:
+
+An SPMI controller node can contain zero or more child nodes representing slave
+devices on the bus. Child 'reg' properties are specified as an address, type
+pair. The address must be in the range 0-15 (4 bits). The type must be one of
+SPMI_USID (0) or SPMI_GSID (1) for Unique Slave ID or Group Slave ID respectively.
+These are the identifiers "statically assigned by the system integrator", as
+per the SPMI spec.
+
+Each child node must have one and only one 'reg' entry of type SPMI_USID.
+
+#include <dt-bindings/spmi/spmi.h>
+
+ spmi@.. {
+ compatible = "...";
+ reg = <...>;
+
+ #address-cells = <2>;
+ #size-cells <0>;
+
+ child@0 {
+ compatible = "...";
+ reg = <0 SPMI_USID>;
+ };
+
+ child@7 {
+ compatible = "...";
+ reg = <7 SPMI_USID
+ 3 SPMI_GSID>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
index b876d4925a57..3be5ce7a9654 100644
--- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
+++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
@@ -1,3 +1,22 @@
+Freescale i.MX DRM master device
+================================
+
+The freescale i.MX DRM master device is a virtual device needed to list all
+IPU or other display interface nodes that comprise the graphics subsystem.
+
+Required properties:
+- compatible: Should be "fsl,imx-display-subsystem"
+- ports: Should contain a list of phandles pointing to display interface ports
+ of IPU devices
+
+example:
+
+display-subsystem {
+ compatible = "fsl,display-subsystem";
+ ports = <&ipu_di0>;
+};
+
+
Freescale i.MX IPUv3
====================
@@ -7,18 +26,31 @@ Required properties:
datasheet
- interrupts: Should contain sync interrupt and error interrupt,
in this order.
-- #crtc-cells: 1, See below
- resets: phandle pointing to the system reset controller and
reset line index, see reset/fsl,imx-src.txt for details
+Optional properties:
+- port@[0-3]: Port nodes with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt.
+ Ports 0 and 1 should correspond to CSI0 and CSI1,
+ ports 2 and 3 should correspond to DI0 and DI1, respectively.
example:
ipu: ipu@18000000 {
- #crtc-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
compatible = "fsl,imx53-ipu";
reg = <0x18000000 0x080000000>;
interrupts = <11 10>;
resets = <&src 2>;
+
+ ipu_di0: port@2 {
+ reg = <2>;
+
+ ipu_di0_disp0: endpoint {
+ remote-endpoint = <&display_in>;
+ };
+ };
};
Parallel display support
@@ -26,19 +58,25 @@ Parallel display support
Required properties:
- compatible: Should be "fsl,imx-parallel-display"
-- crtc: the crtc this display is connected to, see below
Optional properties:
- interface_pix_fmt: How this display is connected to the
- crtc. Currently supported types: "rgb24", "rgb565", "bgr666"
+ display interface. Currently supported types: "rgb24", "rgb565", "bgr666"
- edid: verbatim EDID data block describing attached display.
- ddc: phandle describing the i2c bus handling the display data
channel
+- port: A port node with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt.
example:
display@di0 {
compatible = "fsl,imx-parallel-display";
edid = [edid-data];
- crtc = <&ipu 0>;
interface-pix-fmt = "rgb24";
+
+ port {
+ display_in: endpoint {
+ remote-endpoint = <&ipu_di0_disp0>;
+ };
+ };
};
diff --git a/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt b/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt
new file mode 100644
index 000000000000..1b756cf9afb0
--- /dev/null
+++ b/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt
@@ -0,0 +1,58 @@
+Device-Tree bindings for HDMI Transmitter
+
+HDMI Transmitter
+================
+
+The HDMI Transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
+with accompanying PHY IP.
+
+Required properties:
+ - #address-cells : should be <1>
+ - #size-cells : should be <0>
+ - compatible : should be "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
+ - gpr : should be <&gpr>.
+ The phandle points to the iomuxc-gpr region containing the HDMI
+ multiplexer control register.
+ - clocks, clock-names : phandles to the HDMI iahb and isrf clocks, as described
+ in Documentation/devicetree/bindings/clock/clock-bindings.txt and
+ Documentation/devicetree/bindings/clock/imx6q-clock.txt.
+ - port@[0-4]: Up to four port nodes with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt,
+ corresponding to the four inputs to the HDMI multiplexer.
+
+Optional properties:
+ - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+
+example:
+
+ gpr: iomuxc-gpr@020e0000 {
+ /* ... */
+ };
+
+ hdmi: hdmi@0120000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx6q-hdmi";
+ reg = <0x00120000 0x9000>;
+ interrupts = <0 115 0x04>;
+ gpr = <&gpr>;
+ clocks = <&clks 123>, <&clks 124>;
+ clock-names = "iahb", "isfr";
+ ddc-i2c-bus = <&i2c2>;
+
+ port@0 {
+ reg = <0>;
+
+ hdmi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_hdmi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ hdmi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_hdmi>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt b/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt
index ed9377811ee2..578a1fca366e 100644
--- a/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt
+++ b/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt
@@ -50,12 +50,14 @@ have a look at Documentation/devicetree/bindings/video/display-timing.txt.
Required properties:
- reg : should be <0> or <1>
- - crtcs : a list of phandles with index pointing to the IPU display interfaces
- that can be used as video source for this channel.
- fsl,data-mapping : should be "spwg" or "jeida"
This describes how the color bits are laid out in the
serialized LVDS signal.
- fsl,data-width : should be <18> or <24>
+ - port: A port node with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt.
+ On i.MX6, there should be four ports (port@[0-3]) that correspond
+ to the four LVDS multiplexer inputs.
example:
@@ -77,23 +79,33 @@ ldb: ldb@53fa8008 {
lvds-channel@0 {
reg = <0>;
- crtcs = <&ipu 0>;
fsl,data-mapping = "spwg";
fsl,data-width = <24>;
display-timings {
/* ... */
};
+
+ port {
+ lvds0_in: endpoint {
+ remote-endpoint = <&ipu_di0_lvds0>;
+ };
+ };
};
lvds-channel@1 {
reg = <1>;
- crtcs = <&ipu 1>;
fsl,data-mapping = "spwg";
fsl,data-width = <24>;
display-timings {
/* ... */
};
+
+ port {
+ lvds1_in: endpoint {
+ remote-endpoint = <&ipu_di1_lvds1>;
+ };
+ };
};
};
diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt b/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt
index 48aeb7884ed3..5c2e23574ca0 100644
--- a/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt
+++ b/Documentation/devicetree/bindings/timer/allwinner,sun4i-timer.txt
@@ -2,7 +2,7 @@ Allwinner A1X SoCs Timer Controller
Required properties:
-- compatible : should be "allwinner,sun4i-timer"
+- compatible : should be "allwinner,sun4i-a10-timer"
- reg : Specifies base physical address and size of the registers.
- interrupts : The interrupt of the first timer
- clocks: phandle to the source clock (usually a 24 MHz fixed clock)
@@ -10,7 +10,7 @@ Required properties:
Example:
timer {
- compatible = "allwinner,sun4i-timer";
+ compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0x400>;
interrupts = <22>;
clocks = <&osc>;
diff --git a/Documentation/devicetree/bindings/timer/ti,keystone-timer.txt b/Documentation/devicetree/bindings/timer/ti,keystone-timer.txt
new file mode 100644
index 000000000000..5fbe361252b4
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/ti,keystone-timer.txt
@@ -0,0 +1,29 @@
+* Device tree bindings for Texas instruments Keystone timer
+
+This document provides bindings for the 64-bit timer in the KeyStone
+architecture devices. The timer can be configured as a general-purpose 64-bit
+timer, dual general-purpose 32-bit timers. When configured as dual 32-bit
+timers, each half can operate in conjunction (chain mode) or independently
+(unchained mode) of each other.
+
+It is global timer is a free running up-counter and can generate interrupt
+when the counter reaches preset counter values.
+
+Documentation:
+http://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf
+
+Required properties:
+
+- compatible : should be "ti,keystone-timer".
+- reg : specifies base physical address and count of the registers.
+- interrupts : interrupt generated by the timer.
+- clocks : the clock feeding the timer clock.
+
+Example:
+
+timer@22f0000 {
+ compatible = "ti,keystone-timer";
+ reg = <0x022f0000 0x80>;
+ interrupts = <GIC_SPI 110 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clktimer15>;
+};
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt
index b4b5b7906c88..a6a32cb7f777 100644
--- a/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt
+++ b/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt
@@ -18,6 +18,7 @@ Optional properties:
- vbus-supply: regulator for vbus
- disable-over-current: disable over current detect
- external-vbus-divider: enables off-chip resistor divider for Vbus
+- maximum-speed: limit the maximum connection speed to "full-speed".
Examples:
usb@02184000 { /* USB OTG */
@@ -28,4 +29,5 @@ usb@02184000 { /* USB OTG */
fsl,usbmisc = <&usbmisc 0>;
disable-over-current;
external-vbus-divider;
+ maximum-speed = "full-speed";
};
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt
new file mode 100644
index 000000000000..abbcb2aea38c
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt
@@ -0,0 +1,17 @@
+* LSI Zevio USB OTG Controller
+
+Required properties:
+- compatible: Should be "lsi,zevio-usb"
+- reg: Should contain registers location and length
+- interrupts: Should contain controller interrupt
+
+Optional properties:
+- vbus-supply: regulator for vbus
+
+Examples:
+ usb0: usb@b0000000 {
+ reg = <0xb0000000 0x1000>;
+ compatible = "lsi,zevio-usb";
+ interrupts = <8>;
+ vbus-supply = <&vbus_reg>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index e807635f9e1c..471366d6a129 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -6,11 +6,13 @@ Required properties:
- compatible: must be "snps,dwc3"
- reg : Address and length of the register set for the device
- interrupts: Interrupts used by the dwc3 controller.
+
+Optional properties:
- usb-phy : array of phandle for the PHY device. The first element
in the array is expected to be a handle to the USB2/HS PHY and
the second element is expected to be a handle to the USB3/SS PHY
-
-Optional properties:
+ - phys: from the *Generic PHY* bindings
+ - phy-names: from the *Generic PHY* bindings
- tx-fifo-resize: determines if the FIFO *has* to be reallocated.
This is usually a subnode to DWC3 glue to which it is connected.
diff --git a/Documentation/devicetree/bindings/usb/fsl-usb.txt b/Documentation/devicetree/bindings/usb/fsl-usb.txt
index bd5723f0b67e..4779c029b675 100644
--- a/Documentation/devicetree/bindings/usb/fsl-usb.txt
+++ b/Documentation/devicetree/bindings/usb/fsl-usb.txt
@@ -8,7 +8,9 @@ and additions :
Required properties :
- compatible : Should be "fsl-usb2-mph" for multi port host USB
controllers, or "fsl-usb2-dr" for dual role USB controllers
- or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121
+ or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121.
+ Wherever applicable, the IP version of the USB controller should
+ also be mentioned (for eg. fsl-usb2-dr-v2.2 for bsc9132).
- phy_type : For multi port host USB controllers, should be one of
"ulpi", or "serial". For dual role USB controllers, should be
one of "ulpi", "utmi", "utmi_wide", or "serial".
diff --git a/Documentation/devicetree/bindings/usb/mxs-phy.txt b/Documentation/devicetree/bindings/usb/mxs-phy.txt
index 5835b27146ea..cef181a9d8bd 100644
--- a/Documentation/devicetree/bindings/usb/mxs-phy.txt
+++ b/Documentation/devicetree/bindings/usb/mxs-phy.txt
@@ -1,13 +1,19 @@
* Freescale MXS USB Phy Device
Required properties:
-- compatible: Should be "fsl,imx23-usbphy"
+- compatible: should contain:
+ * "fsl,imx23-usbphy" for imx23 and imx28
+ * "fsl,imx6q-usbphy" for imx6dq and imx6dl
+ * "fsl,imx6sl-usbphy" for imx6sl
+ "fsl,imx23-usbphy" is still a fallback for other strings
- reg: Should contain registers location and length
- interrupts: Should contain phy interrupt
+- fsl,anatop: phandle for anatop register, it is only for imx6 SoC series
Example:
usbphy1: usbphy@020c9000 {
compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
reg = <0x020c9000 0x1000>;
interrupts = <0 44 0x04>;
+ fsl,anatop = <&anatop>;
};
diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt
index c495135115cb..38b2faec4199 100644
--- a/Documentation/devicetree/bindings/usb/omap-usb.txt
+++ b/Documentation/devicetree/bindings/usb/omap-usb.txt
@@ -76,27 +76,3 @@ omap_dwc3 {
ranges;
};
-OMAP CONTROL USB
-
-Required properties:
- - compatible: Should be one of
- "ti,control-phy-otghs" - if it has otghs_control mailbox register as on OMAP4.
- "ti,control-phy-usb2" - if it has Power down bit in control_dev_conf register
- e.g. USB2_PHY on OMAP5.
- "ti,control-phy-pipe3" - if it has DPLL and individual Rx & Tx power control
- e.g. USB3 PHY and SATA PHY on OMAP5.
- "ti,control-phy-dra7usb2" - if it has power down register like USB2 PHY on
- DRA7 platform.
- "ti,control-phy-am437usb2" - if it has power down register like USB2 PHY on
- AM437 platform.
- - reg : Address and length of the register set for the device. It contains
- the address of "otghs_control" for control-phy-otghs or "power" register
- for other types.
- - reg-names: should be "otghs_control" control-phy-otghs and "power" for
- other types.
-
-omap_control_usb: omap-control-usb@4a002300 {
- compatible = "ti,control-phy-otghs";
- reg = <0x4a00233c 0x4>;
- reg-names = "otghs_control";
-};
diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
index fa18612f757b..ff151ec084c4 100644
--- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
@@ -1,19 +1,20 @@
USB EHCI controllers
Required properties:
- - compatible : should be "usb-ehci".
+ - compatible : should be "generic-ehci".
- reg : should contain at least address and length of the standard EHCI
register set for the device. Optional platform-dependent registers
(debug-port or other) can be also specified here, but only after
definition of standard EHCI registers.
- interrupts : one EHCI interrupt should be described here.
-If device registers are implemented in big endian mode, the device
-node should have "big-endian-regs" property.
-If controller implementation operates with big endian descriptors,
-"big-endian-desc" property should be specified.
-If both big endian registers and descriptors are used by the controller
-implementation, "big-endian" property can be specified instead of having
-both "big-endian-regs" and "big-endian-desc".
+
+Optional properties:
+ - big-endian-regs : boolean, set this for hcds with big-endian registers
+ - big-endian-desc : boolean, set this for hcds with big-endian descriptors
+ - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
+ - clocks : a list of phandle + clock specifier pairs
+ - phys : phandle + phy specifier pair
+ - phy-names : "usb"
Example (Sequoia 440EPx):
ehci@e0000300 {
@@ -23,3 +24,13 @@ Example (Sequoia 440EPx):
reg = <0 e0000300 90 0 e0000390 70>;
big-endian;
};
+
+Example (Allwinner sun4i A10 SoC):
+ ehci0: usb@01c14000 {
+ compatible = "allwinner,sun4i-a10-ehci", "generic-ehci";
+ reg = <0x01c14000 0x100>;
+ interrupts = <39>;
+ clocks = <&ahb_gates 1>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ };
diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt
new file mode 100644
index 000000000000..45f67d91e888
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt
@@ -0,0 +1,25 @@
+USB OHCI controllers
+
+Required properties:
+- compatible : "generic-ohci"
+- reg : ohci controller register range (address and length)
+- interrupts : ohci controller interrupt
+
+Optional properties:
+- big-endian-regs : boolean, set this for hcds with big-endian registers
+- big-endian-desc : boolean, set this for hcds with big-endian descriptors
+- big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
+- clocks : a list of phandle + clock specifier pairs
+- phys : phandle + phy specifier pair
+- phy-names : "usb"
+
+Example:
+
+ ohci0: usb@01c14400 {
+ compatible = "allwinner,sun4i-a10-ohci", "generic-ohci";
+ reg = <0x01c14400 0x100>;
+ interrupts = <64>;
+ clocks = <&usb_clk 6>, <&ahb_gates 2>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ };
diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt
deleted file mode 100644
index c0245c888982..000000000000
--- a/Documentation/devicetree/bindings/usb/usb-phy.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-USB PHY
-
-OMAP USB2 PHY
-
-Required properties:
- - compatible: Should be "ti,omap-usb2"
- - reg : Address and length of the register set for the device.
- - #phy-cells: determine the number of cells that should be given in the
- phandle while referencing this phy.
-
-Optional properties:
- - ctrl-module : phandle of the control module used by PHY driver to power on
- the PHY.
-
-This is usually a subnode of ocp2scp to which it is connected.
-
-usb2phy@4a0ad080 {
- compatible = "ti,omap-usb2";
- reg = <0x4a0ad080 0x58>;
- ctrl-module = <&omap_control_usb>;
- #phy-cells = <0>;
-};
-
-OMAP USB3 PHY
-
-Required properties:
- - compatible: Should be "ti,omap-usb3"
- - reg : Address and length of the register set for the device.
- - reg-names: The names of the register addresses corresponding to the registers
- filled in "reg".
- - #phy-cells: determine the number of cells that should be given in the
- phandle while referencing this phy.
-
-Optional properties:
- - ctrl-module : phandle of the control module used by PHY driver to power on
- the PHY.
-
-This is usually a subnode of ocp2scp to which it is connected.
-
-usb3phy@4a084400 {
- compatible = "ti,omap-usb3";
- reg = <0x4a084400 0x80>,
- <0x4a084800 0x64>,
- <0x4a084c00 0x40>;
- reg-names = "phy_rx", "phy_tx", "pll_ctrl";
- ctrl-module = <&omap_control_usb>;
- #phy-cells = <0>;
-};
diff --git a/Documentation/devicetree/bindings/usb/platform-uhci.txt b/Documentation/devicetree/bindings/usb/usb-uhci.txt
index a4fb0719d157..298133416c97 100644
--- a/Documentation/devicetree/bindings/usb/platform-uhci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-uhci.txt
@@ -2,14 +2,14 @@ Generic Platform UHCI Controller
-----------------------------------------------------
Required properties:
-- compatible : "platform-uhci"
+- compatible : "generic-uhci" (deprecated: "platform-uhci")
- reg : Should contain 1 register ranges(address and length)
- interrupts : UHCI controller interrupt
Example:
uhci@d8007b00 {
- compatible = "platform-uhci";
+ compatible = "generic-uhci";
reg = <0xd8007b00 0x200>;
interrupts = <43>;
};
diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt
index 5752df0e17a2..90f8f607d125 100644
--- a/Documentation/devicetree/bindings/usb/usb-xhci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt
@@ -1,14 +1,14 @@
USB xHCI controllers
Required properties:
- - compatible: should be "xhci-platform".
+ - compatible: should be "generic-xhci" (deprecated: "xhci-platform").
- reg: should contain address and length of the standard XHCI
register set for the device.
- interrupts: one XHCI interrupt should be described here.
Example:
usb@f0931000 {
- compatible = "xhci-platform";
+ compatible = "generic-xhci";
reg = <0xf0931000 0x8c8>;
interrupts = <0x0 0x4e 0x0>;
};
diff --git a/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
deleted file mode 100644
index 17b3ad1d97e7..000000000000
--- a/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-VIA/Wondermedia VT8500 EHCI Controller
------------------------------------------------------
-
-Required properties:
-- compatible : "via,vt8500-ehci"
-- reg : Should contain 1 register ranges(address and length)
-- interrupts : ehci controller interrupt
-
-Example:
-
- ehci@d8007900 {
- compatible = "via,vt8500-ehci";
- reg = <0xd8007900 0x200>;
- interrupts = <43>;
- };
diff --git a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
deleted file mode 100644
index 5fb8fd6e250c..000000000000
--- a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-VIA VT8500 and Wondermedia WM8xxx SoC USB controllers.
-
-Required properties:
- - compatible: Should be "via,vt8500-ehci" or "wm,prizm-ehci".
- - reg: Address range of the ehci registers. size should be 0x200
- - interrupts: Should contain the ehci interrupt.
-
-usb: ehci@D8007100 {
- compatible = "wm,prizm-ehci", "usb-ehci";
- reg = <0xD8007100 0x200>;
- interrupts = <1>;
-};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 40ce2df0e0e9..95465d57eb31 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -3,6 +3,7 @@ Device tree binding vendor prefix registry. Keep list in alphabetical order.
This isn't an exhaustive list, but you should add new prefixes to it before
using them to avoid name-space collisions.
+abilis Abilis Systems
active-semi Active-Semi International Inc
ad Avionic Design GmbH
adi Analog Devices, Inc.
@@ -11,14 +12,17 @@ ak Asahi Kasei Corp.
allwinner Allwinner Technology Co., Ltd.
altr Altera Corp.
amcc Applied Micro Circuits Corporation (APM, formally AMCC)
+amd Advanced Micro Devices (AMD), Inc.
amstaos AMS-Taos Inc.
apm Applied Micro Circuits Corporation (APM)
arm ARM Ltd.
+armadeus ARMadeus Systems SARL
atmel Atmel Corporation
auo AU Optronics Corporation
avago Avago Technologies
bosch Bosch Sensortec GmbH
brcm Broadcom Corporation
+calxeda Calxeda
capella Capella Microsystems, Inc
cavium Cavium, Inc.
cdns Cadence Design Systems Inc.
@@ -26,8 +30,10 @@ chrp Common Hardware Reference Platform
chunghwa Chunghwa Picture Tubes Ltd.
cirrus Cirrus Logic, Inc.
cortina Cortina Systems, Inc.
+crystalfontz Crystalfontz America, Inc.
dallas Maxim Integrated Products (formerly Dallas Semiconductor)
davicom DAVICOM Semiconductor, Inc.
+dlink D-Link Systems, Inc.
denx Denx Software Engineering
edt Emerging Display Technologies
emmicro EM Microelectronic
@@ -37,7 +43,9 @@ est ESTeem Wireless Modems
fsl Freescale Semiconductor
GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+globalscale Globalscale Technologies, Inc.
gmt Global Mixed-mode Technology, Inc.
+google Google, Inc.
gumstix Gumstix, Inc.
haoyu Haoyu Microelectronic Co. Ltd.
hisilicon Hisilicon Limited.
@@ -46,9 +54,12 @@ hp Hewlett Packard
ibm International Business Machines (IBM)
idt Integrated Device Technologies, Inc.
img Imagination Technologies Ltd.
+intel Intel Corporation
intercontrol Inter Control Group
isl Intersil
karo Ka-Ro electronics GmbH
+lacie LaCie
+lantiq Lantiq Semiconductor
lg LG Corporation
linux Linux-specific binding
lsi LSI Corp. (LSI Logic)
@@ -56,12 +67,16 @@ marvell Marvell Technology Group Ltd.
maxim Maxim Integrated Products
microchip Microchip Technology Inc.
mosaixtech Mosaix Technologies, Inc.
+moxa Moxa
national National Semiconductor
neonode Neonode Inc.
+netgear NETGEAR
nintendo Nintendo
+nokia Nokia
nvidia NVIDIA
nxp NXP Semiconductors
onnn ON Semiconductor Corp.
+opencores OpenCores.org
panasonic Panasonic Corporation
phytec PHYTEC Messtechnik GmbH
picochip Picochip Ltd
@@ -80,6 +95,7 @@ sil Silicon Image
silabs Silicon Laboratories
simtek
sirf SiRF Technology, Inc.
+smsc Standard Microsystems Corporation
snps Synopsys, Inc.
spansion Spansion Inc.
st STMicroelectronics
@@ -94,4 +110,5 @@ via VIA Technologies, Inc.
winbond Winbond Electronics corp.
wlf Wolfson Microelectronics
wm Wondermedia Technologies, Inc.
+xes Extreme Engineering Solutions (X-ES)
xlnx Xilinx
diff --git a/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt b/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt
new file mode 100644
index 000000000000..6d63782a7378
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt
@@ -0,0 +1,23 @@
+Xilinx AXI/PLB soft-core watchdog Device Tree Bindings
+---------------------------------------------------------
+
+Required properties:
+- compatible : Should be "xlnx,xps-timebase-wdt-1.00.a" or
+ "xlnx,xps-timebase-wdt-1.01.a".
+- reg : Physical base address and size
+
+Optional properties:
+- clock-frequency : Frequency of clock in Hz
+- xlnx,wdt-enable-once : 0 - Watchdog can be restarted
+ 1 - Watchdog can be enabled just once
+- xlnx,wdt-interval : Watchdog timeout interval in 2^<val> clock cycles,
+ <val> is integer from 8 to 31.
+
+Example:
+axi-timebase-wdt@40100000 {
+ clock-frequency = <50000000>;
+ compatible = "xlnx,xps-timebase-wdt-1.00.a";
+ reg = <0x40100000 0x10000>;
+ xlnx,wdt-enable-once = <0x0>;
+ xlnx,wdt-interval = <0x1b>;
+} ;
diff --git a/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt b/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt
index e39cb266c8f4..b8f75c51453a 100644
--- a/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt
@@ -2,13 +2,13 @@ Allwinner SoCs Watchdog timer
Required properties:
-- compatible : should be "allwinner,<soc-family>-wdt", the currently supported
- SoC families being sun4i and sun6i
+- compatible : should be either "allwinner,sun4i-a10-wdt" or
+ "allwinner,sun6i-a31-wdt"
- reg : Specifies base physical address and size of the registers.
Example:
wdt: watchdog@01c20c90 {
- compatible = "allwinner,sun4i-wdt";
+ compatible = "allwinner,sun4i-a10-wdt";
reg = <0x01c20c90 0x10>;
};
diff --git a/Documentation/fmc/fmc-write-eeprom.txt b/Documentation/fmc/fmc-write-eeprom.txt
index 44a3bc678bf0..e0a9712156aa 100644
--- a/Documentation/fmc/fmc-write-eeprom.txt
+++ b/Documentation/fmc/fmc-write-eeprom.txt
@@ -9,7 +9,12 @@ Overwriting the EEPROM is not something you should do daily, and it is
expected to only happen during manufacturing. For this reason, the
module makes it unlikely for the random user to change a working EEPROM.
-The module takes the following measures:
+However, since the EEPROM may include application-specific information
+other than the identification, later versions of this packages added
+write-support through sysfs. See *note Accessing the EEPROM::.
+
+To avoid damaging the EEPROM content, the module takes the following
+measures:
* It accepts a `file=' argument (within /lib/firmware) and if no
such argument is received, it doesn't write anything to EEPROM
@@ -70,56 +75,24 @@ first time.
[ 132.899872] fake-fmc: Product name: FmcDelay1ns4cha
-Writing to the EEPROM
+Accessing the EEPROM
=====================
-Once you have created a binary file for your EEPROM, you can write it
-to the storage medium using the fmc-write-eeprom (See *note
-fmc-write-eeprom::, while relying on a carrier driver. The procedure
-here shown here uses the SPEC driver
-(`http://www.ohwr.org/projects/spec-sw').
-
-The example assumes no driver is already loaded (actually, I unloaded
-them by hand as everything loads automatically at boot time after you
-installed the modules), and shows kernel messages together with
-commands. Here the prompt is spusa.root# and two SPEC cards are plugged
-in the system.
-
- spusa.root# insmod fmc.ko
- spusa.root# insmod spec.ko
- [13972.382818] spec 0000:02:00.0: probe for device 0002:0000
- [13972.392773] spec 0000:02:00.0: got file "fmc/spec-init.bin", 1484404 (0x16a674) bytes
- [13972.591388] spec 0000:02:00.0: FPGA programming successful
- [13972.883011] spec 0000:02:00.0: EEPROM has no FRU information
- [13972.888719] spec 0000:02:00.0: No device_id filled, using index
- [13972.894676] spec 0000:02:00.0: No mezzanine_name found
- [13972.899863] /home/rubini/wip/spec-sw/kernel/spec-gpio.c - spec_gpio_init
- [13972.906578] spec 0000:04:00.0: probe for device 0004:0000
- [13972.916509] spec 0000:04:00.0: got file "fmc/spec-init.bin", 1484404 (0x16a674) bytes
- [13973.115096] spec 0000:04:00.0: FPGA programming successful
- [13973.401798] spec 0000:04:00.0: EEPROM has no FRU information
- [13973.407474] spec 0000:04:00.0: No device_id filled, using index
- [13973.413417] spec 0000:04:00.0: No mezzanine_name found
- [13973.418600] /home/rubini/wip/spec-sw/kernel/spec-gpio.c - spec_gpio_init
- spusa.root# ls /sys/bus/fmc/devices
- fmc-0000 fmc-0001
- spusa.root# insmod fmc-write-eeprom.ko busid=0x0200 file=fdelay-eeprom.bin
- [14103.966259] spec 0000:02:00.0: Matching an generic driver (no ID)
- [14103.975519] spec 0000:02:00.0: programming 6155 bytes
- [14126.373762] spec 0000:02:00.0: write_eeprom: success
- [14126.378770] spec 0000:04:00.0: Matching an generic driver (no ID)
- [14126.384903] spec 0000:04:00.0: fmc_write_eeprom: no filename given: not programming
- [14126.392600] fmc_write_eeprom: probe of fmc-0001 failed with error -2
-
-Reading back the EEPROM
-=======================
-
-In order to read back the binary content of the EEPROM of your
-mezzanine device, the bus creates a read-only sysfs file called eeprom
-for each mezzanine it knows about:
-
- spusa.root# cd /sys/bus/fmc/devices; ls -l */eeprom
- -r--r--r-- 1 root root 8192 Apr 9 16:53 FmcDelay1ns4cha-f001/eeprom
- -r--r--r-- 1 root root 8192 Apr 9 17:19 fake-design-for-testing-f002/eeprom
- -r--r--r-- 1 root root 8192 Apr 9 17:19 fake-design-for-testing-f003/eeprom
- -r--r--r-- 1 root root 8192 Apr 9 17:19 fmc-f004/eeprom
+The bus creates a sysfs binary file called eeprom for each mezzanine it
+knows about:
+
+ spusa.root# cd /sys/bus/fmc/devices; ls -l */eeprom
+ -r--r--r-- 1 root root 8192 Feb 21 12:30 FmcAdc100m14b4cha-0800/eeprom
+ -r--r--r-- 1 root root 8192 Feb 21 12:30 FmcDelay1ns4cha-0200/eeprom
+ -r--r--r-- 1 root root 8192 Feb 21 12:30 FmcDio5cha-0400/eeprom
+
+Everybody can read the files and the superuser can also modify it, but
+the operation may on the carrier driver, if the carrier is unable to
+access the I2C bus. For example, the spec driver can access the bus
+only with its golden gateware: after a mezzanine driver reprogrammed
+the FPGA with a custom circuit, the carrier is unable to access the
+EEPROM and returns ENOTSUPP.
+
+An alternative way to write the EEPROM is the mezzanine driver
+fmc-write-eeprom (See *note fmc-write-eeprom::), but the procedure is
+more complex.
diff --git a/Documentation/hwmon/adc128d818 b/Documentation/hwmon/adc128d818
new file mode 100644
index 000000000000..39c95004dabc
--- /dev/null
+++ b/Documentation/hwmon/adc128d818
@@ -0,0 +1,47 @@
+Kernel driver adc128d818
+========================
+
+Supported chips:
+ * Texas Instruments ADC818D818
+ Prefix: 'adc818d818'
+ Addresses scanned: I2C 0x1d, 0x1e, 0x1f, 0x2d, 0x2e, 0x2f
+ Datasheet: Publicly available at the TI website
+ http://www.ti.com/
+
+Author: Guenter Roeck
+
+Description
+-----------
+
+This driver implements support for the Texas Instruments ADC128D818.
+It is described as 'ADC System Monitor with Temperature Sensor'.
+
+The ADC128D818 implements one temperature sensor and seven voltage sensors.
+
+Temperatures are measured in degrees Celsius. There is one set of limits.
+When the HOT Temperature Limit is crossed, this will cause an alarm that will
+be reasserted until the temperature drops below the HOT Hysteresis.
+Measurements are guaranteed between -55 and +125 degrees. The temperature
+measurement has a resolution of 0.5 degrees; the limits have a resolution
+of 1 degree.
+
+Voltage sensors (also known as IN sensors) report their values in volts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit. Note that minimum in this case always means 'closest to
+zero'; this is important for negative voltage measurements. All voltage
+inputs can measure voltages between 0 and 2.55 volts, with a resolution
+of 0.625 mV.
+
+If an alarm triggers, it will remain triggered until the hardware register
+is read at least once. This means that the cause for the alarm may
+already have disappeared by the time the alarm is read. The driver
+caches the alarm status for each sensor until it is at least reported
+once, to ensure that alarms are reported to user space.
+
+The ADC128D818 only updates its values approximately once per second;
+reading it more often will do no harm, but will return 'old' values.
+
+In addition to the scanned address list, the chip can also be configured for
+addresses 0x35 to 0x37. Those addresses are not scanned. You have to instantiate
+the driver explicitly if the chip is configured for any of those addresses in
+your system.
diff --git a/Documentation/hwmon/lm95245 b/Documentation/hwmon/lm95245
index cbd8aeab7124..77eaf2812d25 100644
--- a/Documentation/hwmon/lm95245
+++ b/Documentation/hwmon/lm95245
@@ -24,8 +24,12 @@ is given within a range of -127 to +127.875 degrees. Remote temperatures are
given within a range of -127 to +255 degrees. Resolution depends on
temperature input and range.
-Each sensor has its own critical limit, but the hysteresis is common to all
-two channels.
+Each sensor has its own critical limit. Additionally, there is a relative
+hysteresis value common to both critical limits. To make life easier to
+user-space applications, two absolute values are exported, one for each
+channel, but these values are of course linked. Only the local hysteresis
+can be set from user-space, and the same delta applies to the remote
+hysteresis.
The lm95245 driver can change its update interval to a fixed set of values.
It will round up to the next selectable interval. See the datasheet for exact
diff --git a/Documentation/hwmon/ltc2945 b/Documentation/hwmon/ltc2945
new file mode 100644
index 000000000000..f8d0f7f19adb
--- /dev/null
+++ b/Documentation/hwmon/ltc2945
@@ -0,0 +1,84 @@
+Kernel driver ltc2945
+=====================
+
+Supported chips:
+ * Linear Technology LTC2945
+ Prefix: 'ltc2945'
+ Addresses scanned: -
+ Datasheet:
+ http://cds.linear.com/docs/en/datasheet/2945fa.pdf
+
+Author: Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+The LTC2945 is a rail-to-rail system monitor that measures current, voltage,
+and power consumption.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for LTC2945 devices, since there is no register
+which can be safely used to identify the chip. You will have to instantiate
+the devices explicitly.
+
+Example: the following will load the driver for an LTC2945 at address 0x10
+on I2C bus #1:
+$ modprobe ltc2945
+$ echo ltc2945 0x10 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs entries
+-------------
+
+Voltage readings provided by this driver are reported as obtained from the ADC
+registers. If a set of voltage divider resistors is installed, calculate the
+real voltage by multiplying the reported value with (R1+R2)/R2, where R1 is the
+value of the divider resistor against the measured voltage and R2 is the value
+of the divider resistor against Ground.
+
+Current reading provided by this driver is reported as obtained from the ADC
+Current Sense register. The reported value assumes that a 1 mOhm sense resistor
+is installed. If a different sense resistor is installed, calculate the real
+current by dividing the reported value by the sense resistor value in mOhm.
+
+in1_input VIN voltage (mV). Voltage is measured either at
+ SENSE+ or VDD pin depending on chip configuration.
+in1_min Undervoltage threshold
+in1_max Overvoltage threshold
+in1_lowest Lowest measured voltage
+in1_highest Highest measured voltage
+in1_reset_history Write 1 to reset in1 history
+in1_min_alarm Undervoltage alarm
+in1_max_alarm Overvoltage alarm
+
+in2_input ADIN voltage (mV)
+in2_min Undervoltage threshold
+in2_max Overvoltage threshold
+in2_lowest Lowest measured voltage
+in2_highest Highest measured voltage
+in2_reset_history Write 1 to reset in2 history
+in2_min_alarm Undervoltage alarm
+in2_max_alarm Overvoltage alarm
+
+curr1_input SENSE current (mA)
+curr1_min Undercurrent threshold
+curr1_max Overcurrent threshold
+curr1_lowest Lowest measured current
+curr1_highest Highest measured current
+curr1_reset_history Write 1 to reset curr1 history
+curr1_min_alarm Undercurrent alarm
+curr1_max_alarm Overcurrent alarm
+
+power1_input Power (in uW). Power is calculated based on SENSE+/VDD
+ voltage or ADIN voltage depending on chip configuration.
+power1_min Low lower threshold
+power1_max High power threshold
+power1_input_lowest Historical minimum power use
+power1_input_highest Historical maximum power use
+power1_reset_history Write 1 to reset power1 history
+power1_min_alarm Low power alarm
+power1_max_alarm High power alarm
diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978
index a0546fc42273..686c078bb0e0 100644
--- a/Documentation/hwmon/ltc2978
+++ b/Documentation/hwmon/ltc2978
@@ -23,6 +23,10 @@ Supported chips:
Prefix: 'ltc3883'
Addresses scanned: -
Datasheet: http://www.linear.com/product/ltc3883
+ * Linear Technology LTM4676
+ Prefix: 'ltm4676'
+ Addresses scanned: -
+ Datasheet: http://www.linear.com/product/ltm4676
Author: Guenter Roeck <linux@roeck-us.net>
@@ -33,7 +37,8 @@ Description
LTC2974 is a quad digital power supply manager. LTC2978 is an octal power supply
monitor. LTC2977 is a pin compatible replacement for LTC2978. LTC3880 is a dual
output poly-phase step-down DC/DC controller. LTC3883 is a single phase
-step-down DC/DC controller.
+step-down DC/DC controller. LTM4676 is a dual 13A or single 26A uModule
+regulator.
Usage Notes
@@ -75,7 +80,7 @@ in[N]_label "vout[1-8]".
LTC2974: N=2-5
LTC2977: N=2-9
LTC2978: N=2-9
- LTC3880: N=2-3
+ LTC3880, LTM4676: N=2-3
LTC3883: N=2
in[N]_input Measured output voltage.
in[N]_min Minimum output voltage.
@@ -95,7 +100,7 @@ temp[N]_input Measured temperature.
and temp5 reports the chip temperature.
On LTC2977 and LTC2978, only one temperature measurement
is supported and reports the chip temperature.
- On LTC3880, temp1 and temp2 report external
+ On LTC3880 and LTM4676, temp1 and temp2 report external
temperatures, and temp3 reports the chip temperature.
On LTC3883, temp1 reports an external temperature,
and temp2 reports the chip temperature.
@@ -123,11 +128,11 @@ power[N]_label "pout[1-4]".
LTC2974: N=1-4
LTC2977: Not supported
LTC2978: Not supported
- LTC3880: N=1-2
+ LTC3880, LTM4676: N=1-2
LTC3883: N=2
power[N]_input Measured output power.
-curr1_label "iin". LTC3880 and LTC3883 only.
+curr1_label "iin". LTC3880, LTC3883, and LTM4676 only.
curr1_input Measured input current.
curr1_max Maximum input current.
curr1_max_alarm Input current high alarm.
@@ -138,7 +143,7 @@ curr[N]_label "iout[1-4]".
LTC2974: N=1-4
LTC2977: not supported
LTC2978: not supported
- LTC3880: N=2-3
+ LTC3880, LTM4676: N=2-3
LTC3883: N=2
curr[N]_input Measured output current.
curr[N]_max Maximum output current.
diff --git a/Documentation/hwmon/ltc4260 b/Documentation/hwmon/ltc4260
new file mode 100644
index 000000000000..c4ff4ad998b2
--- /dev/null
+++ b/Documentation/hwmon/ltc4260
@@ -0,0 +1,56 @@
+Kernel driver ltc4260
+=====================
+
+Supported chips:
+ * Linear Technology LTC4260
+ Prefix: 'ltc4260'
+ Addresses scanned: -
+ Datasheet:
+ http://cds.linear.com/docs/en/datasheet/4260fc.pdf
+
+Author: Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+The LTC4260 Hot Swap controller allows a board to be safely inserted
+and removed from a live backplane.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for LTC4260 devices, since there is no register
+which can be safely used to identify the chip. You will have to instantiate
+the devices explicitly.
+
+Example: the following will load the driver for an LTC4260 at address 0x10
+on I2C bus #1:
+$ modprobe ltc4260
+$ echo ltc4260 0x10 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs entries
+-------------
+
+Voltage readings provided by this driver are reported as obtained from the ADC
+registers. If a set of voltage divider resistors is installed, calculate the
+real voltage by multiplying the reported value with (R1+R2)/R2, where R1 is the
+value of the divider resistor against the measured voltage and R2 is the value
+of the divider resistor against Ground.
+
+Current reading provided by this driver is reported as obtained from the ADC
+Current Sense register. The reported value assumes that a 1 mOhm sense resistor
+is installed. If a different sense resistor is installed, calculate the real
+current by dividing the reported value by the sense resistor value in mOhm.
+
+in1_input SOURCE voltage (mV)
+in1_min_alarm Undervoltage alarm
+in1_max_alarm Overvoltage alarm
+
+in2_input ADIN voltage (mV)
+in2_alarm Power bad alarm
+
+curr1_input SENSE current (mA)
+curr1_alarm SENSE overcurrent alarm
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 7116fda7077f..bc3478581f67 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -229,8 +229,24 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
use by PCI
Format: <irq>,<irq>...
+ acpi_no_auto_serialize [HW,ACPI]
+ Disable auto-serialization of AML methods
+ AML control methods that contain the opcodes to create
+ named objects will be marked as "Serialized" by the
+ auto-serialization feature.
+ This feature is enabled by default.
+ This option allows to turn off the feature.
+
acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT
+ acpica_no_return_repair [HW, ACPI]
+ Disable AML predefined validation mechanism
+ This mechanism can repair the evaluation result to make
+ the return objects more ACPI specification compliant.
+ This option is useful for developers to identify the
+ root cause of an AML interpreter issue when the issue
+ has something to do with the repair mechanism.
+
acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS
Format: To spoof as Windows 98: ="Microsoft Windows"
@@ -298,8 +314,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode
Format: { level | edge | high | low }
- acpi_serialize [HW,ACPI] force serialization of AML methods
-
acpi_skip_timer_override [HW,ACPI]
Recognize and ignore IRQ0/pin2 Interrupt Override.
For broken nForce2 BIOS resulting in XT-PIC timer.
@@ -1011,6 +1025,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
parameter will force ia64_sal_cache_flush to call
ia64_pal_cache_flush instead of SAL_CACHE_FLUSH.
+ forcepae [X86-32]
+ Forcefully enable Physical Address Extension (PAE).
+ Many Pentium M systems disable PAE but may have a
+ functionally usable PAE implementation.
+ Warning: use of this parameter will taint the kernel
+ and may cause unknown problems.
+
ftrace=[tracer]
[FTRACE] will set and start the specified tracer
as early as possible in order to facilitate early
@@ -2053,8 +2074,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
IOAPICs that may be present in the system.
nokaslr [X86]
- Disable kernel base offset ASLR (Address Space
- Layout Randomization) if built into the kernel.
+ Disable kernel and module base offset ASLR (Address
+ Space Layout Randomization) if built into the kernel.
noautogroup Disable scheduler automatic task group creation.
@@ -3409,14 +3430,24 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
of CONFIG_HIGHPTE.
vdso= [X86,SH]
- vdso=2: enable compat VDSO (default with COMPAT_VDSO)
- vdso=1: enable VDSO (default)
+ On X86_32, this is an alias for vdso32=. Otherwise:
+
+ vdso=1: enable VDSO (the default)
vdso=0: disable VDSO mapping
- vdso32= [X86]
- vdso32=2: enable compat VDSO (default with COMPAT_VDSO)
- vdso32=1: enable 32-bit VDSO (default)
- vdso32=0: disable 32-bit VDSO mapping
+ vdso32= [X86] Control the 32-bit vDSO
+ vdso32=1: enable 32-bit VDSO
+ vdso32=0 or vdso32=2: disable 32-bit VDSO
+
+ See the help text for CONFIG_COMPAT_VDSO for more
+ details. If CONFIG_COMPAT_VDSO is set, the default is
+ vdso32=0; otherwise, the default is vdso32=1.
+
+ For compatibility with older kernels, vdso32=2 is an
+ alias for vdso32=0.
+
+ Try vdso32=0 if you encounter an error that says:
+ dl_main: Assertion `(void *) ph->p_vaddr == _rtld_local._dl_sysinfo_dso' failed!
vector= [IA-64,SMP]
vector=percpu: enable percpu vector domain
diff --git a/Documentation/kernel-per-CPU-kthreads.txt b/Documentation/kernel-per-CPU-kthreads.txt
index 827104fb9364..f3cd299fcc41 100644
--- a/Documentation/kernel-per-CPU-kthreads.txt
+++ b/Documentation/kernel-per-CPU-kthreads.txt
@@ -162,7 +162,18 @@ Purpose: Execute workqueue requests
To reduce its OS jitter, do any of the following:
1. Run your workload at a real-time priority, which will allow
preempting the kworker daemons.
-2. Do any of the following needed to avoid jitter that your
+2. A given workqueue can be made visible in the sysfs filesystem
+ by passing the WQ_SYSFS to that workqueue's alloc_workqueue().
+ Such a workqueue can be confined to a given subset of the
+ CPUs using the /sys/devices/virtual/workqueue/*/cpumask sysfs
+ files. The set of WQ_SYSFS workqueues can be displayed using
+ "ls sys/devices/virtual/workqueue". That said, the workqueues
+ maintainer would like to caution people against indiscriminately
+ sprinkling WQ_SYSFS across all the workqueues. The reason for
+ caution is that it is easy to add WQ_SYSFS, but because sysfs is
+ part of the formal user/kernel API, it can be nearly impossible
+ to remove it, even if its addition was a mistake.
+3. Do any of the following needed to avoid jitter that your
application cannot tolerate:
a. Build your kernel with CONFIG_SLUB=y rather than
CONFIG_SLAB=y, thus avoiding the slab allocator's periodic
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index ddd2e0d1febc..556f951f8626 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -608,26 +608,30 @@ as follows:
b = p; /* BUG: Compiler can reorder!!! */
do_something();
-The solution is again ACCESS_ONCE(), which preserves the ordering between
-the load from variable 'a' and the store to variable 'b':
+The solution is again ACCESS_ONCE() and barrier(), which preserves the
+ordering between the load from variable 'a' and the store to variable 'b':
q = ACCESS_ONCE(a);
if (q) {
+ barrier();
ACCESS_ONCE(b) = p;
do_something();
} else {
+ barrier();
ACCESS_ONCE(b) = p;
do_something_else();
}
-You could also use barrier() to prevent the compiler from moving
-the stores to variable 'b', but barrier() would not prevent the
-compiler from proving to itself that a==1 always, so ACCESS_ONCE()
-is also needed.
+The initial ACCESS_ONCE() is required to prevent the compiler from
+proving the value of 'a', and the pair of barrier() invocations are
+required to prevent the compiler from pulling the two identical stores
+to 'b' out from the legs of the "if" statement.
It is important to note that control dependencies absolutely require a
a conditional. For example, the following "optimized" version of
-the above example breaks ordering:
+the above example breaks ordering, which is why the barrier() invocations
+are absolutely required if you have identical stores in both legs of
+the "if" statement:
q = ACCESS_ONCE(a);
ACCESS_ONCE(b) = p; /* BUG: No ordering vs. load from a!!! */
@@ -643,9 +647,11 @@ It is of course legal for the prior load to be part of the conditional,
for example, as follows:
if (ACCESS_ONCE(a) > 0) {
+ barrier();
ACCESS_ONCE(b) = q / 2;
do_something();
} else {
+ barrier();
ACCESS_ONCE(b) = q / 3;
do_something_else();
}
@@ -659,9 +665,11 @@ the needed conditional. For example:
q = ACCESS_ONCE(a);
if (q % MAX) {
+ barrier();
ACCESS_ONCE(b) = p;
do_something();
} else {
+ barrier();
ACCESS_ONCE(b) = p;
do_something_else();
}
@@ -723,8 +731,13 @@ In summary:
use smb_rmb(), smp_wmb(), or, in the case of prior stores and
later loads, smp_mb().
+ (*) If both legs of the "if" statement begin with identical stores
+ to the same variable, a barrier() statement is required at the
+ beginning of each leg of the "if" statement.
+
(*) Control dependencies require at least one run-time conditional
- between the prior load and the subsequent store. If the compiler
+ between the prior load and the subsequent store, and this
+ conditional must involve the prior load. If the compiler
is able to optimize the conditional away, it will have also
optimized away the ordering. Careful use of ACCESS_ONCE() can
help to preserve the needed conditional.
@@ -1249,6 +1262,23 @@ The ACCESS_ONCE() function can prevent any number of optimizations that,
while perfectly safe in single-threaded code, can be fatal in concurrent
code. Here are some examples of these sorts of optimizations:
+ (*) The compiler is within its rights to reorder loads and stores
+ to the same variable, and in some cases, the CPU is within its
+ rights to reorder loads to the same variable. This means that
+ the following code:
+
+ a[0] = x;
+ a[1] = x;
+
+ Might result in an older value of x stored in a[1] than in a[0].
+ Prevent both the compiler and the CPU from doing this as follows:
+
+ a[0] = ACCESS_ONCE(x);
+ a[1] = ACCESS_ONCE(x);
+
+ In short, ACCESS_ONCE() provides cache coherence for accesses from
+ multiple CPUs to a single variable.
+
(*) The compiler is within its rights to merge successive loads from
the same variable. Such merging can cause the compiler to "optimize"
the following code:
@@ -1644,12 +1674,12 @@ for each construct. These operations all imply certain barriers:
Memory operations issued after the ACQUIRE will be completed after the
ACQUIRE operation has completed.
- Memory operations issued before the ACQUIRE may be completed after the
- ACQUIRE operation has completed. An smp_mb__before_spinlock(), combined
- with a following ACQUIRE, orders prior loads against subsequent stores and
- stores and prior stores against subsequent stores. Note that this is
- weaker than smp_mb()! The smp_mb__before_spinlock() primitive is free on
- many architectures.
+ Memory operations issued before the ACQUIRE may be completed after
+ the ACQUIRE operation has completed. An smp_mb__before_spinlock(),
+ combined with a following ACQUIRE, orders prior loads against
+ subsequent loads and stores and also orders prior stores against
+ subsequent stores. Note that this is weaker than smp_mb()! The
+ smp_mb__before_spinlock() primitive is free on many architectures.
(2) RELEASE operation implication:
@@ -1694,24 +1724,21 @@ may occur as:
ACQUIRE M, STORE *B, STORE *A, RELEASE M
-This same reordering can of course occur if the lock's ACQUIRE and RELEASE are
-to the same lock variable, but only from the perspective of another CPU not
-holding that lock.
-
-In short, a RELEASE followed by an ACQUIRE may -not- be assumed to be a full
-memory barrier because it is possible for a preceding RELEASE to pass a
-later ACQUIRE from the viewpoint of the CPU, but not from the viewpoint
-of the compiler. Note that deadlocks cannot be introduced by this
-interchange because if such a deadlock threatened, the RELEASE would
-simply complete.
-
-If it is necessary for a RELEASE-ACQUIRE pair to produce a full barrier, the
-ACQUIRE can be followed by an smp_mb__after_unlock_lock() invocation. This
-will produce a full barrier if either (a) the RELEASE and the ACQUIRE are
-executed by the same CPU or task, or (b) the RELEASE and ACQUIRE act on the
-same variable. The smp_mb__after_unlock_lock() primitive is free on many
-architectures. Without smp_mb__after_unlock_lock(), the critical sections
-corresponding to the RELEASE and the ACQUIRE can cross:
+When the ACQUIRE and RELEASE are a lock acquisition and release,
+respectively, this same reordering can occur if the lock's ACQUIRE and
+RELEASE are to the same lock variable, but only from the perspective of
+another CPU not holding that lock. In short, a ACQUIRE followed by an
+RELEASE may -not- be assumed to be a full memory barrier.
+
+Similarly, the reverse case of a RELEASE followed by an ACQUIRE does not
+imply a full memory barrier. If it is necessary for a RELEASE-ACQUIRE
+pair to produce a full barrier, the ACQUIRE can be followed by an
+smp_mb__after_unlock_lock() invocation. This will produce a full barrier
+if either (a) the RELEASE and the ACQUIRE are executed by the same
+CPU or task, or (b) the RELEASE and ACQUIRE act on the same variable.
+The smp_mb__after_unlock_lock() primitive is free on many architectures.
+Without smp_mb__after_unlock_lock(), the CPU's execution of the critical
+sections corresponding to the RELEASE and the ACQUIRE can cross, so that:
*A = a;
RELEASE M
@@ -1722,7 +1749,36 @@ could occur as:
ACQUIRE N, STORE *B, STORE *A, RELEASE M
-With smp_mb__after_unlock_lock(), they cannot, so that:
+It might appear that this reordering could introduce a deadlock.
+However, this cannot happen because if such a deadlock threatened,
+the RELEASE would simply complete, thereby avoiding the deadlock.
+
+ Why does this work?
+
+ One key point is that we are only talking about the CPU doing
+ the reordering, not the compiler. If the compiler (or, for
+ that matter, the developer) switched the operations, deadlock
+ -could- occur.
+
+ But suppose the CPU reordered the operations. In this case,
+ the unlock precedes the lock in the assembly code. The CPU
+ simply elected to try executing the later lock operation first.
+ If there is a deadlock, this lock operation will simply spin (or
+ try to sleep, but more on that later). The CPU will eventually
+ execute the unlock operation (which preceded the lock operation
+ in the assembly code), which will unravel the potential deadlock,
+ allowing the lock operation to succeed.
+
+ But what if the lock is a sleeplock? In that case, the code will
+ try to enter the scheduler, where it will eventually encounter
+ a memory barrier, which will force the earlier unlock operation
+ to complete, again unraveling the deadlock. There might be
+ a sleep-unlock race, but the locking primitive needs to resolve
+ such races properly in any case.
+
+With smp_mb__after_unlock_lock(), the two critical sections cannot overlap.
+For example, with the following code, the store to *A will always be
+seen by other CPUs before the store to *B:
*A = a;
RELEASE M
@@ -1730,13 +1786,18 @@ With smp_mb__after_unlock_lock(), they cannot, so that:
smp_mb__after_unlock_lock();
*B = b;
-will always occur as either of the following:
+The operations will always occur in one of the following orders:
- STORE *A, RELEASE, ACQUIRE, STORE *B
- STORE *A, ACQUIRE, RELEASE, STORE *B
+ STORE *A, RELEASE, ACQUIRE, smp_mb__after_unlock_lock(), STORE *B
+ STORE *A, ACQUIRE, RELEASE, smp_mb__after_unlock_lock(), STORE *B
+ ACQUIRE, STORE *A, RELEASE, smp_mb__after_unlock_lock(), STORE *B
If the RELEASE and ACQUIRE were instead both operating on the same lock
-variable, only the first of these two alternatives can occur.
+variable, only the first of these alternatives can occur. In addition,
+the more strongly ordered systems may rule out some of the above orders.
+But in any case, as noted earlier, the smp_mb__after_unlock_lock()
+ensures that the store to *A will always be seen as happening before
+the store to *B.
Locks and semaphores may not provide any guarantee of ordering on UP compiled
systems, and so cannot be counted on in such a situation to actually achieve
@@ -2757,7 +2818,7 @@ in that order, but, without intervention, the sequence may have almost any
combination of elements combined or discarded, provided the program's view of
the world remains consistent. Note that ACCESS_ONCE() is -not- optional
in the above example, as there are architectures where a given CPU might
-interchange successive loads to the same location. On such architectures,
+reorder successive loads to the same location. On such architectures,
ACCESS_ONCE() does whatever is necessary to prevent this, for example, on
Itanium the volatile casts used by ACCESS_ONCE() cause GCC to emit the
special ld.acq and st.rel instructions that prevent such reordering.
diff --git a/Documentation/networking/3c505.txt b/Documentation/networking/3c505.txt
deleted file mode 100644
index 72f38b13101d..000000000000
--- a/Documentation/networking/3c505.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-The 3Com Etherlink Plus (3c505) driver.
-
-This driver now uses DMA. There is currently no support for PIO operation.
-The default DMA channel is 6; this is _not_ autoprobed, so you must
-make sure you configure it correctly. If loading the driver as a
-module, you can do this with "modprobe 3c505 dma=n". If the driver is
-linked statically into the kernel, you must either use an "ether="
-statement on the command line, or change the definition of ELP_DMA in 3c505.h.
-
-The driver will warn you if it has to fall back on the compiled in
-default DMA channel.
-
-If no base address is given at boot time, the driver will autoprobe
-ports 0x300, 0x280 and 0x310 (in that order). If no IRQ is given, the driver
-will try to probe for it.
-
-The driver can be used as a loadable module.
-
-Theoretically, one instance of the driver can now run multiple cards,
-in the standard way (when loading a module, say "modprobe 3c505
-io=0x300,0x340 irq=10,11 dma=6,7" or whatever). I have not tested
-this, though.
-
-The driver may now support revision 2 hardware; the dependency on
-being able to read the host control register has been removed. This
-is also untested, since I don't have a suitable card.
-
-Known problems:
- I still see "DMA upload timed out" messages from time to time. These
-seem to be fairly non-fatal though.
- The card is old and slow.
-
-To do:
- Improve probe/setup code
- Test multicast and promiscuous operation
-
-Authors:
- The driver is mainly written by Craig Southeren, email
- <craigs@ineluki.apana.org.au>.
- Parts of the driver (adapting the driver to 1.1.4+ kernels,
- IRQ/address detection, some changes) and this README by
- Juha Laiho <jlaiho@ichaos.nullnet.fi>.
- DMA mode, more fixes, etc, by Philip Blundell <pjb27@cam.ac.uk>
- Multicard support, Software configurable DMA, etc., by
- Christopher Collins <ccollins@pcug.org.au>
diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt
index f3089d423515..0cbe6ec22d6f 100644
--- a/Documentation/networking/can.txt
+++ b/Documentation/networking/can.txt
@@ -554,12 +554,6 @@ solution for a couple of reasons:
not specified in the struct can_frame and therefore it is only valid in
CANFD_MTU sized CAN FD frames.
- As long as the payload length is <=8 the received CAN frames from CAN FD
- capable CAN devices can be received and read by legacy sockets too. When
- user-generated CAN FD frames have a payload length <=8 these can be send
- by legacy CAN network interfaces too. Sending CAN FD frames with payload
- length > 8 to a legacy CAN network interface returns an -EMSGSIZE error.
-
Implementation hint for new CAN applications:
To build a CAN FD aware application use struct canfd_frame as basic CAN
diff --git a/Documentation/networking/netlink_mmap.txt b/Documentation/networking/netlink_mmap.txt
index b26122973525..c6af4bac5aa8 100644
--- a/Documentation/networking/netlink_mmap.txt
+++ b/Documentation/networking/netlink_mmap.txt
@@ -226,9 +226,9 @@ Ring setup:
void *rx_ring, *tx_ring;
/* Configure ring parameters */
- if (setsockopt(fd, NETLINK_RX_RING, &req, sizeof(req)) < 0)
+ if (setsockopt(fd, SOL_NETLINK, NETLINK_RX_RING, &req, sizeof(req)) < 0)
exit(1);
- if (setsockopt(fd, NETLINK_TX_RING, &req, sizeof(req)) < 0)
+ if (setsockopt(fd, SOL_NETLINK, NETLINK_TX_RING, &req, sizeof(req)) < 0)
exit(1)
/* Calculate size of each individual ring */
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
index 1404674c0a02..6fea79efb4cb 100644
--- a/Documentation/networking/packet_mmap.txt
+++ b/Documentation/networking/packet_mmap.txt
@@ -453,7 +453,7 @@ TP_STATUS_COPY : This flag indicates that the frame (and associated
enabled previously with setsockopt() and
the PACKET_COPY_THRESH option.
- The number of frames than can be buffered to
+ The number of frames that can be buffered to
be read with recvfrom is limited like a normal socket.
See the SO_RCVBUF option in the socket (7) man page.
diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt
index 661d3c316a17..048c92b487f6 100644
--- a/Documentation/networking/timestamping.txt
+++ b/Documentation/networking/timestamping.txt
@@ -21,26 +21,38 @@ has such a feature).
SO_TIMESTAMPING:
-Instructs the socket layer which kind of information is wanted. The
-parameter is an integer with some of the following bits set. Setting
-other bits is an error and doesn't change the current state.
-
-SOF_TIMESTAMPING_TX_HARDWARE: try to obtain send time stamp in hardware
-SOF_TIMESTAMPING_TX_SOFTWARE: if SOF_TIMESTAMPING_TX_HARDWARE is off or
- fails, then do it in software
-SOF_TIMESTAMPING_RX_HARDWARE: return the original, unmodified time stamp
- as generated by the hardware
-SOF_TIMESTAMPING_RX_SOFTWARE: if SOF_TIMESTAMPING_RX_HARDWARE is off or
- fails, then do it in software
-SOF_TIMESTAMPING_RAW_HARDWARE: return original raw hardware time stamp
-SOF_TIMESTAMPING_SYS_HARDWARE: return hardware time stamp transformed to
- the system time base
-SOF_TIMESTAMPING_SOFTWARE: return system time stamp generated in
- software
-
-SOF_TIMESTAMPING_TX/RX determine how time stamps are generated.
-SOF_TIMESTAMPING_RAW/SYS determine how they are reported in the
-following control message:
+Instructs the socket layer which kind of information should be collected
+and/or reported. The parameter is an integer with some of the following
+bits set. Setting other bits is an error and doesn't change the current
+state.
+
+Four of the bits are requests to the stack to try to generate
+timestamps. Any combination of them is valid.
+
+SOF_TIMESTAMPING_TX_HARDWARE: try to obtain send time stamps in hardware
+SOF_TIMESTAMPING_TX_SOFTWARE: try to obtain send time stamps in software
+SOF_TIMESTAMPING_RX_HARDWARE: try to obtain receive time stamps in hardware
+SOF_TIMESTAMPING_RX_SOFTWARE: try to obtain receive time stamps in software
+
+The other three bits control which timestamps will be reported in a
+generated control message. If none of these bits are set or if none of
+the set bits correspond to data that is available, then the control
+message will not be generated:
+
+SOF_TIMESTAMPING_SOFTWARE: report systime if available
+SOF_TIMESTAMPING_SYS_HARDWARE: report hwtimetrans if available
+SOF_TIMESTAMPING_RAW_HARDWARE: report hwtimeraw if available
+
+It is worth noting that timestamps may be collected for reasons other
+than being requested by a particular socket with
+SOF_TIMESTAMPING_[TR]X_(HARD|SOFT)WARE. For example, most drivers that
+can generate hardware receive timestamps ignore
+SOF_TIMESTAMPING_RX_HARDWARE. It is still a good idea to set that flag
+in case future drivers pay attention.
+
+If timestamps are reported, they will appear in a control message with
+cmsg_level==SOL_SOCKET, cmsg_type==SO_TIMESTAMPING, and a payload like
+this:
struct scm_timestamping {
struct timespec systime;
diff --git a/Documentation/phy/samsung-usb2.txt b/Documentation/phy/samsung-usb2.txt
new file mode 100644
index 000000000000..ed12d437189d
--- /dev/null
+++ b/Documentation/phy/samsung-usb2.txt
@@ -0,0 +1,135 @@
+.------------------------------------------------------------------------------+
+| Samsung USB 2.0 PHY adaptation layer |
++-----------------------------------------------------------------------------+'
+
+| 1. Description
++----------------
+
+The architecture of the USB 2.0 PHY module in Samsung SoCs is similar
+among many SoCs. In spite of the similarities it proved difficult to
+create a one driver that would fit all these PHY controllers. Often
+the differences were minor and were found in particular bits of the
+registers of the PHY. In some rare cases the order of register writes or
+the PHY powering up process had to be altered. This adaptation layer is
+a compromise between having separate drivers and having a single driver
+with added support for many special cases.
+
+| 2. Files description
++----------------------
+
+- phy-samsung-usb2.c
+ This is the main file of the adaptation layer. This file contains
+ the probe function and provides two callbacks to the Generic PHY
+ Framework. This two callbacks are used to power on and power off the
+ phy. They carry out the common work that has to be done on all version
+ of the PHY module. Depending on which SoC was chosen they execute SoC
+ specific callbacks. The specific SoC version is selected by choosing
+ the appropriate compatible string. In addition, this file contains
+ struct of_device_id definitions for particular SoCs.
+
+- phy-samsung-usb2.h
+ This is the include file. It declares the structures used by this
+ driver. In addition it should contain extern declarations for
+ structures that describe particular SoCs.
+
+| 3. Supporting SoCs
++--------------------
+
+To support a new SoC a new file should be added to the drivers/phy
+directory. Each SoC's configuration is stored in an instance of the
+struct samsung_usb2_phy_config.
+
+struct samsung_usb2_phy_config {
+ const struct samsung_usb2_common_phy *phys;
+ int (*rate_to_clk)(unsigned long, u32 *);
+ unsigned int num_phys;
+ bool has_mode_switch;
+};
+
+The num_phys is the number of phys handled by the driver. *phys is an
+array that contains the configuration for each phy. The has_mode_switch
+property is a boolean flag that determines whether the SoC has USB host
+and device on a single pair of pins. If so, a special register has to
+be modified to change the internal routing of these pins between a USB
+device or host module.
+
+For example the configuration for Exynos 4210 is following:
+
+const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
+ .has_mode_switch = 0,
+ .num_phys = EXYNOS4210_NUM_PHYS,
+ .phys = exynos4210_phys,
+ .rate_to_clk = exynos4210_rate_to_clk,
+}
+
+- int (*rate_to_clk)(unsigned long, u32 *)
+ The rate_to_clk callback is to convert the rate of the clock
+ used as the reference clock for the PHY module to the value
+ that should be written in the hardware register.
+
+The exynos4210_phys configuration array is as follows:
+
+static const struct samsung_usb2_common_phy exynos4210_phys[] = {
+ {
+ .label = "device",
+ .id = EXYNOS4210_DEVICE,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {
+ .label = "host",
+ .id = EXYNOS4210_HOST,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {
+ .label = "hsic0",
+ .id = EXYNOS4210_HSIC0,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {
+ .label = "hsic1",
+ .id = EXYNOS4210_HSIC1,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {},
+};
+
+- int (*power_on)(struct samsung_usb2_phy_instance *);
+- int (*power_off)(struct samsung_usb2_phy_instance *);
+ These two callbacks are used to power on and power off the phy
+ by modifying appropriate registers.
+
+Final change to the driver is adding appropriate compatible value to the
+phy-samsung-usb2.c file. In case of Exynos 4210 the following lines were
+added to the struct of_device_id samsung_usb2_phy_of_match[] array:
+
+#ifdef CONFIG_PHY_EXYNOS4210_USB2
+ {
+ .compatible = "samsung,exynos4210-usb2-phy",
+ .data = &exynos4210_usb2_phy_config,
+ },
+#endif
+
+To add further flexibility to the driver the Kconfig file enables to
+include support for selected SoCs in the compiled driver. The Kconfig
+entry for Exynos 4210 is following:
+
+config PHY_EXYNOS4210_USB2
+ bool "Support for Exynos 4210"
+ depends on PHY_SAMSUNG_USB2
+ depends on CPU_EXYNOS4210
+ help
+ Enable USB PHY support for Exynos 4210. This option requires that
+ Samsung USB 2.0 PHY driver is enabled and means that support for this
+ particular SoC is compiled in the driver. In case of Exynos 4210 four
+ phys are available - device, host, HSCI0 and HSCI1.
+
+The newly created file that supports the new SoC has to be also added to the
+Makefile. In case of Exynos 4210 the added line is following:
+
+obj-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o
+
+After completing these steps the support for the new SoC should be ready.
diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt
index 483632087788..a5da5c7e7128 100644
--- a/Documentation/power/pm_qos_interface.txt
+++ b/Documentation/power/pm_qos_interface.txt
@@ -88,17 +88,19 @@ node.
2. PM QoS per-device latency and flags framework
-For each device, there are two lists of PM QoS requests. One is maintained
-along with the aggregated target of latency value and the other is for PM QoS
-flags. Values are updated in response to changes of the request list.
+For each device, there are three lists of PM QoS requests. Two of them are
+maintained along with the aggregated targets of resume latency and active
+state latency tolerance (in microseconds) and the third one is for PM QoS flags.
+Values are updated in response to changes of the request list.
-Target latency value is simply the minimum of the request values held in the
-parameter list elements. The PM QoS flags aggregate value is a gather (bitwise
-OR) of all list elements' values. Two device PM QoS flags are defined currently:
-PM_QOS_FLAG_NO_POWER_OFF and PM_QOS_FLAG_REMOTE_WAKEUP.
+The target values of resume latency and active state latency tolerance are
+simply the minimum of the request values held in the parameter list elements.
+The PM QoS flags aggregate value is a gather (bitwise OR) of all list elements'
+values. Two device PM QoS flags are defined currently: PM_QOS_FLAG_NO_POWER_OFF
+and PM_QOS_FLAG_REMOTE_WAKEUP.
-Note: the aggregated target value is implemented as an atomic variable so that
-reading the aggregated value does not require any locking mechanism.
+Note: The aggregated target values are implemented in such a way that reading
+the aggregated value does not require any locking mechanism.
From kernel mode the use of this interface is the following:
@@ -132,19 +134,21 @@ The meaning of the return values is as follows:
PM_QOS_FLAGS_UNDEFINED: The device's PM QoS structure has not been
initialized or the list of requests is empty.
-int dev_pm_qos_add_ancestor_request(dev, handle, value)
+int dev_pm_qos_add_ancestor_request(dev, handle, type, value)
Add a PM QoS request for the first direct ancestor of the given device whose
-power.ignore_children flag is unset.
+power.ignore_children flag is unset (for DEV_PM_QOS_RESUME_LATENCY requests)
+or whose power.set_latency_tolerance callback pointer is not NULL (for
+DEV_PM_QOS_LATENCY_TOLERANCE requests).
int dev_pm_qos_expose_latency_limit(device, value)
-Add a request to the device's PM QoS list of latency constraints and create
-a sysfs attribute pm_qos_resume_latency_us under the device's power directory
-allowing user space to manipulate that request.
+Add a request to the device's PM QoS list of resume latency constraints and
+create a sysfs attribute pm_qos_resume_latency_us under the device's power
+directory allowing user space to manipulate that request.
void dev_pm_qos_hide_latency_limit(device)
Drop the request added by dev_pm_qos_expose_latency_limit() from the device's
-PM QoS list of latency constraints and remove sysfs attribute pm_qos_resume_latency_us
-from the device's power directory.
+PM QoS list of resume latency constraints and remove sysfs attribute
+pm_qos_resume_latency_us from the device's power directory.
int dev_pm_qos_expose_flags(device, value)
Add a request to the device's PM QoS list of flags and create sysfs attributes
@@ -163,7 +167,7 @@ a per-device notification tree and a global notification tree.
int dev_pm_qos_add_notifier(device, notifier):
Adds a notification callback function for the device.
The callback is called when the aggregated value of the device constraints list
-is changed.
+is changed (for resume latency device PM QoS only).
int dev_pm_qos_remove_notifier(device, notifier):
Removes the notification callback function for the device.
@@ -171,14 +175,48 @@ Removes the notification callback function for the device.
int dev_pm_qos_add_global_notifier(notifier):
Adds a notification callback function in the global notification tree of the
framework.
-The callback is called when the aggregated value for any device is changed.
+The callback is called when the aggregated value for any device is changed
+(for resume latency device PM QoS only).
int dev_pm_qos_remove_global_notifier(notifier):
Removes the notification callback function from the global notification tree
of the framework.
-From user mode:
-No API for user space access to the per-device latency constraints is provided
-yet - still under discussion.
-
+Active state latency tolerance
+
+This device PM QoS type is used to support systems in which hardware may switch
+to energy-saving operation modes on the fly. In those systems, if the operation
+mode chosen by the hardware attempts to save energy in an overly aggressive way,
+it may cause excess latencies to be visible to software, causing it to miss
+certain protocol requirements or target frame or sample rates etc.
+
+If there is a latency tolerance control mechanism for a given device available
+to software, the .set_latency_tolerance callback in that device's dev_pm_info
+structure should be populated. The routine pointed to by it is should implement
+whatever is necessary to transfer the effective requirement value to the
+hardware.
+
+Whenever the effective latency tolerance changes for the device, its
+.set_latency_tolerance() callback will be executed and the effective value will
+be passed to it. If that value is negative, which means that the list of
+latency tolerance requirements for the device is empty, the callback is expected
+to switch the underlying hardware latency tolerance control mechanism to an
+autonomous mode if available. If that value is PM_QOS_LATENCY_ANY, in turn, and
+the hardware supports a special "no requirement" setting, the callback is
+expected to use it. That allows software to prevent the hardware from
+automatically updating the device's latency tolerance in response to its power
+state changes (e.g. during transitions from D3cold to D0), which generally may
+be done in the autonomous latency tolerance control mode.
+
+If .set_latency_tolerance() is present for the device, sysfs attribute
+pm_qos_latency_tolerance_us will be present in the devivce's power directory.
+Then, user space can use that attribute to specify its latency tolerance
+requirement for the device, if any. Writing "any" to it means "no requirement,
+but do not let the hardware control latency tolerance" and writing "auto" to it
+allows the hardware to be switched to the autonomous mode if there are no other
+requirements from the kernel side in the device's list.
+
+Kernel code can use the functions described above along with the
+DEV_PM_QOS_LATENCY_TOLERANCE device PM QoS type to add, remove and update
+latency tolerance requirements for devices.
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index b6ce00b2be9a..5f96daf8566a 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -232,7 +232,7 @@ defined in include/linux/pm.h:
equal to zero); the initial value of it is 1 (i.e. runtime PM is
initially disabled for all devices)
- unsigned int runtime_error;
+ int runtime_error;
- if set, there was a fatal error (one of the callbacks returned error code
as described in Section 2), so the helper funtions will not work until
this flag is cleared; this is the error code returned by the failing
@@ -401,11 +401,11 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
int pm_runtime_disable(struct device *dev);
- increment the device's 'power.disable_depth' field (if the value of that
field was previously zero, this prevents subsystem-level runtime PM
- callbacks from being run for the device), make sure that all of the pending
- runtime PM operations on the device are either completed or canceled;
- returns 1 if there was a resume request pending and it was necessary to
- execute the subsystem-level resume callback for the device to satisfy that
- request, otherwise 0 is returned
+ callbacks from being run for the device), make sure that all of the
+ pending runtime PM operations on the device are either completed or
+ canceled; returns 1 if there was a resume request pending and it was
+ necessary to execute the subsystem-level resume callback for the device
+ to satisfy that request, otherwise 0 is returned
int pm_runtime_barrier(struct device *dev);
- check if there's a resume request pending for the device and resume it
@@ -667,11 +667,11 @@ driver/base/power/generic_ops.c:
int pm_generic_runtime_suspend(struct device *dev);
- invoke the ->runtime_suspend() callback provided by the driver of this
- device and return its result, or return -EINVAL if not defined
+ device and return its result, or return 0 if not defined
int pm_generic_runtime_resume(struct device *dev);
- invoke the ->runtime_resume() callback provided by the driver of this
- device and return its result, or return -EINVAL if not defined
+ device and return its result, or return 0 if not defined
int pm_generic_suspend(struct device *dev);
- if the device has not been suspended at run time, invoke the ->suspend()
@@ -727,15 +727,12 @@ driver/base/power/generic_ops.c:
int pm_generic_restore_noirq(struct device *dev);
- invoke the ->restore_noirq() callback provided by the device's driver
-These functions can be assigned to the ->runtime_idle(), ->runtime_suspend(),
+These functions are the defaults used by the PM core, if a subsystem doesn't
+provide its own callbacks for ->runtime_idle(), ->runtime_suspend(),
->runtime_resume(), ->suspend(), ->suspend_noirq(), ->resume(),
->resume_noirq(), ->freeze(), ->freeze_noirq(), ->thaw(), ->thaw_noirq(),
-->poweroff(), ->poweroff_noirq(), ->restore(), ->restore_noirq() callback
-pointers in the subsystem-level dev_pm_ops structures.
-
-If a subsystem wishes to use all of them at the same time, it can simply assign
-the GENERIC_SUBSYS_PM_OPS macro, defined in include/linux/pm.h, to its
-dev_pm_ops structure pointer.
+->poweroff(), ->poweroff_noirq(), ->restore(), ->restore_noirq() in the
+subsystem-level dev_pm_ops structure.
Device drivers that wish to use the same function as a system suspend, freeze,
poweroff and runtime suspend callback, and similarly for system resume, thaw,
@@ -873,7 +870,7 @@ Here is a schematic pseudo-code example:
foo->is_suspended = 0;
pm_runtime_mark_last_busy(&foo->dev);
if (foo->num_pending_requests > 0)
- foo_process_requests(foo);
+ foo_process_next_request(foo);
unlock(&foo->private_lock);
return 0;
}
diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
index 6edaa65b0818..91ba58ef02d7 100644
--- a/Documentation/scsi/ChangeLog.megaraid_sas
+++ b/Documentation/scsi/ChangeLog.megaraid_sas
@@ -1,3 +1,16 @@
+Release Date : Mon. Mar 10, 2014 17:00:00 PST 2014 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Adam Radford
+ Kashyap Desai
+ Sumit Saxena
+Current Version : 06.803.01.00-rc1
+Old Version : 06.700.06.00-rc1
+ 1. Load correct raid context timeout value for multipathing & clustering.
+ 2. Fix megasas_ioc_init_fusion to use local stack variable.
+ 3. Return leaked MPT frames to MPT command pool.
+ 4. Add Dell PowerEdge VRTX SR-IOV VF device support.
+ 5. Version and Changelog update.
+-------------------------------------------------------------------------------
Release Date : Sat. Aug 31, 2013 17:00:00 PST 2013 -
(emaild-id:megaraidlinux@lsi.com)
Adam Radford
diff --git a/Documentation/sgi-visws.txt b/Documentation/sgi-visws.txt
deleted file mode 100644
index 7ff0811ca2ba..000000000000
--- a/Documentation/sgi-visws.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-
-The SGI Visual Workstations (models 320 and 540) are based around
-the Cobalt, Lithium, and Arsenic ASICs. The Cobalt ASIC is the
-main system ASIC which interfaces the 1-4 IA32 cpus, the memory
-system, and the I/O system in the Lithium ASIC. The Cobalt ASIC
-also contains the 3D gfx rendering engine which renders to main
-system memory -- part of which is used as the frame buffer which
-is DMA'ed to a video connector using the Arsenic ASIC. A PIIX4
-chip and NS87307 are used to provide legacy device support (IDE,
-serial, floppy, and parallel).
-
-The Visual Workstation chipset largely conforms to the PC architecture
-with some notable exceptions such as interrupt handling.
diff --git a/Documentation/sound/oss/vwsnd b/Documentation/sound/oss/vwsnd
deleted file mode 100644
index 4c6cbdb3c548..000000000000
--- a/Documentation/sound/oss/vwsnd
+++ /dev/null
@@ -1,293 +0,0 @@
-vwsnd - Sound driver for the Silicon Graphics 320 and 540 Visual
-Workstations' onboard audio.
-
-Copyright 1999 Silicon Graphics, Inc. All rights reserved.
-
-
-At the time of this writing, March 1999, there are two models of
-Visual Workstation, the 320 and the 540. This document only describes
-those models. Future Visual Workstation models may have different
-sound capabilities, and this driver will probably not work on those
-boxes.
-
-The Visual Workstation has an Analog Devices AD1843 "SoundComm" audio
-codec chip. The AD1843 is accessed through the Cobalt I/O ASIC, also
-known as Lithium. This driver programs both chips.
-
-==============================================================================
-QUICK CONFIGURATION
-
- # insmod soundcore
- # insmod vwsnd
-
-==============================================================================
-I/O CONNECTIONS
-
-On the Visual Workstation, only three of the AD1843 inputs are hooked
-up. The analog line in jacks are connected to the AD1843's AUX1
-input. The CD audio lines are connected to the AD1843's AUX2 input.
-The microphone jack is connected to the AD1843's MIC input. The mic
-jack is mono, but the signal is delivered to both the left and right
-MIC inputs. You can record in stereo from the mic input, but you will
-get the same signal on both channels (within the limits of A/D
-accuracy). Full scale on the Line input is +/- 2.0 V. Full scale on
-the MIC input is 20 dB less, or +/- 0.2 V.
-
-The AD1843's LOUT1 outputs are connected to the Line Out jacks. The
-AD1843's HPOUT outputs are connected to the speaker/headphone jack.
-LOUT2 is not connected. Line out's maximum level is +/- 2.0 V peak to
-peak. The speaker/headphone out's maximum is +/- 4.0 V peak to peak.
-
-The AD1843's PCM input channel and one of its output channels (DAC1)
-are connected to Lithium. The other output channel (DAC2) is not
-connected.
-
-==============================================================================
-CAPABILITIES
-
-The AD1843 has PCM input and output (Pulse Code Modulation, also known
-as wavetable). PCM input and output can be mono or stereo in any of
-four formats. The formats are 16 bit signed and 8 bit unsigned,
-u-Law, and A-Law format. Any sample rate from 4 KHz to 49 KHz is
-available, in 1 Hz increments.
-
-The AD1843 includes an analog mixer that can mix all three input
-signals (line, mic and CD) into the analog outputs. The mixer has a
-separate gain control and mute switch for each input.
-
-There are two outputs, line out and speaker/headphone out. They
-always produce the same signal, and the speaker always has 3 dB more
-gain than the line out. The speaker/headphone output can be muted,
-but this driver does not export that function.
-
-The hardware can sync audio to the video clock, but this driver does
-not have a way to specify syncing to video.
-
-==============================================================================
-PROGRAMMING
-
-This section explains the API supported by the driver. Also see the
-Open Sound Programming Guide at http://www.opensound.com/pguide/ .
-This section assumes familiarity with that document.
-
-The driver has two interfaces, an I/O interface and a mixer interface.
-There is no MIDI or sequencer capability.
-
-==============================================================================
-PROGRAMMING PCM I/O
-
-The I/O interface is usually accessed as /dev/audio or /dev/dsp.
-Using the standard Open Sound System (OSS) ioctl calls, the sample
-rate, number of channels, and sample format may be set within the
-limitations described above. The driver supports triggering. It also
-supports getting the input and output pointers with one-sample
-accuracy.
-
-The SNDCTL_DSP_GETCAP ioctl returns these capabilities.
-
- DSP_CAP_DUPLEX - driver supports full duplex.
-
- DSP_CAP_TRIGGER - driver supports triggering.
-
- DSP_CAP_REALTIME - values returned by SNDCTL_DSP_GETIPTR
- and SNDCTL_DSP_GETOPTR are accurate to a few samples.
-
-Memory mapping (mmap) is not implemented.
-
-The driver permits subdivided fragment sizes from 64 to 4096 bytes.
-The number of fragments can be anything from 3 fragments to however
-many fragments fit into 124 kilobytes. It is up to the user to
-determine how few/small fragments can be used without introducing
-glitches with a given workload. Linux is not realtime, so we can't
-promise anything. (sigh...)
-
-When this driver is switched into or out of mu-Law or A-Law mode on
-output, it may produce an audible click. This is unavoidable. To
-prevent clicking, use signed 16-bit mode instead, and convert from
-mu-Law or A-Law format in software.
-
-==============================================================================
-PROGRAMMING THE MIXER INTERFACE
-
-The mixer interface is usually accessed as /dev/mixer. It is accessed
-through ioctls. The mixer allows the application to control gain or
-mute several audio signal paths, and also allows selection of the
-recording source.
-
-Each of the constants described here can be read using the
-MIXER_READ(SOUND_MIXER_xxx) ioctl. Those that are not read-only can
-also be written using the MIXER_WRITE(SOUND_MIXER_xxx) ioctl. In most
-cases, <sys/soundcard.h> defines constants SOUND_MIXER_READ_xxx and
-SOUND_MIXER_WRITE_xxx which work just as well.
-
-SOUND_MIXER_CAPS Read-only
-
-This is a mask of optional driver capabilities that are implemented.
-This driver's only capability is SOUND_CAP_EXCL_INPUT, which means
-that only one recording source can be active at a time.
-
-SOUND_MIXER_DEVMASK Read-only
-
-This is a mask of the sound channels. This driver's channels are PCM,
-LINE, MIC, CD, and RECLEV.
-
-SOUND_MIXER_STEREODEVS Read-only
-
-This is a mask of which sound channels are capable of stereo. All
-channels are capable of stereo. (But see caveat on MIC input in I/O
-CONNECTIONS section above).
-
-SOUND_MIXER_OUTMASK Read-only
-
-This is a mask of channels that route inputs through to outputs.
-Those are LINE, MIC, and CD.
-
-SOUND_MIXER_RECMASK Read-only
-
-This is a mask of channels that can be recording sources. Those are
-PCM, LINE, MIC, CD.
-
-SOUND_MIXER_PCM Default: 0x5757 (0 dB)
-
-This is the gain control for PCM output. The left and right channel
-gain are controlled independently. This gain control has 64 levels,
-which range from -82.5 dB to +12.0 dB in 1.5 dB steps. Those 64
-levels are mapped onto 100 levels at the ioctl, see below.
-
-SOUND_MIXER_LINE Default: 0x4a4a (0 dB)
-
-This is the gain control for mixing the Line In source into the
-outputs. The left and right channel gain are controlled
-independently. This gain control has 32 levels, which range from
--34.5 dB to +12.0 dB in 1.5 dB steps. Those 32 levels are mapped onto
-100 levels at the ioctl, see below.
-
-SOUND_MIXER_MIC Default: 0x4a4a (0 dB)
-
-This is the gain control for mixing the MIC source into the outputs.
-The left and right channel gain are controlled independently. This
-gain control has 32 levels, which range from -34.5 dB to +12.0 dB in
-1.5 dB steps. Those 32 levels are mapped onto 100 levels at the
-ioctl, see below.
-
-SOUND_MIXER_CD Default: 0x4a4a (0 dB)
-
-This is the gain control for mixing the CD audio source into the
-outputs. The left and right channel gain are controlled
-independently. This gain control has 32 levels, which range from
--34.5 dB to +12.0 dB in 1.5 dB steps. Those 32 levels are mapped onto
-100 levels at the ioctl, see below.
-
-SOUND_MIXER_RECLEV Default: 0 (0 dB)
-
-This is the gain control for PCM input (RECording LEVel). The left
-and right channel gain are controlled independently. This gain
-control has 16 levels, which range from 0 dB to +22.5 dB in 1.5 dB
-steps. Those 16 levels are mapped onto 100 levels at the ioctl, see
-below.
-
-SOUND_MIXER_RECSRC Default: SOUND_MASK_LINE
-
-This is a mask of currently selected PCM input sources (RECording
-SouRCes). Because the AD1843 can only have a single recording source
-at a time, only one bit at a time can be set in this mask. The
-allowable values are SOUND_MASK_PCM, SOUND_MASK_LINE, SOUND_MASK_MIC,
-or SOUND_MASK_CD. Selecting SOUND_MASK_PCM sets up internal
-resampling which is useful for loopback testing and for hardware
-sample rate conversion. But software sample rate conversion is
-probably faster, so I don't know how useful that is.
-
-SOUND_MIXER_OUTSRC DEFAULT: SOUND_MASK_LINE|SOUND_MASK_MIC|SOUND_MASK_CD
-
-This is a mask of sources that are currently passed through to the
-outputs. Those sources whose bits are not set are muted.
-
-==============================================================================
-GAIN CONTROL
-
-There are five gain controls listed above. Each has 16, 32, or 64
-steps. Each control has 1.5 dB of gain per step. Each control is
-stereo.
-
-The OSS defines the argument to a channel gain ioctl as having two
-components, left and right, each of which ranges from 0 to 100. The
-two components are packed into the same word, with the left side gain
-in the least significant byte, and the right side gain in the second
-least significant byte. In C, we would say this.
-
- #include <assert.h>
-
- ...
-
- assert(leftgain >= 0 && leftgain <= 100);
- assert(rightgain >= 0 && rightgain <= 100);
- arg = leftgain | rightgain << 8;
-
-So each OSS gain control has 101 steps. But the hardware has 16, 32,
-or 64 steps. The hardware steps are spread across the 101 OSS steps
-nearly evenly. The conversion formulas are like this, given N equals
-16, 32, or 64.
-
- int round = N/2 - 1;
- OSS_gain_steps = (hw_gain_steps * 100 + round) / (N - 1);
- hw_gain_steps = (OSS_gain_steps * (N - 1) + round) / 100;
-
-Here is a snippet of C code that will return the left and right gain
-of any channel in dB. Pass it one of the predefined gain_desc_t
-structures to access any of the five channels' gains.
-
- typedef struct gain_desc {
- float min_gain;
- float gain_step;
- int nbits;
- int chan;
- } gain_desc_t;
-
- const gain_desc_t gain_pcm = { -82.5, 1.5, 6, SOUND_MIXER_PCM };
- const gain_desc_t gain_line = { -34.5, 1.5, 5, SOUND_MIXER_LINE };
- const gain_desc_t gain_mic = { -34.5, 1.5, 5, SOUND_MIXER_MIC };
- const gain_desc_t gain_cd = { -34.5, 1.5, 5, SOUND_MIXER_CD };
- const gain_desc_t gain_reclev = { 0.0, 1.5, 4, SOUND_MIXER_RECLEV };
-
- int get_gain_dB(int fd, const gain_desc_t *gp,
- float *left, float *right)
- {
- int word;
- int lg, rg;
- int mask = (1 << gp->nbits) - 1;
-
- if (ioctl(fd, MIXER_READ(gp->chan), &word) != 0)
- return -1; /* fail */
- lg = word & 0xFF;
- rg = word >> 8 & 0xFF;
- lg = (lg * mask + mask / 2) / 100;
- rg = (rg * mask + mask / 2) / 100;
- *left = gp->min_gain + gp->gain_step * lg;
- *right = gp->min_gain + gp->gain_step * rg;
- return 0;
- }
-
-And here is the corresponding routine to set a channel's gain in dB.
-
- int set_gain_dB(int fd, const gain_desc_t *gp, float left, float right)
- {
- float max_gain =
- gp->min_gain + (1 << gp->nbits) * gp->gain_step;
- float round = gp->gain_step / 2;
- int mask = (1 << gp->nbits) - 1;
- int word;
- int lg, rg;
-
- if (left < gp->min_gain || right < gp->min_gain)
- return EINVAL;
- lg = (left - gp->min_gain + round) / gp->gain_step;
- rg = (right - gp->min_gain + round) / gp->gain_step;
- if (lg >= (1 << gp->nbits) || rg >= (1 << gp->nbits))
- return EINVAL;
- lg = (100 * lg + mask / 2) / mask;
- rg = (100 * rg + mask / 2) / mask;
- word = lg | rg << 8;
-
- return ioctl(fd, MIXER_WRITE(gp->chan), &word);
- }
-
diff --git a/Documentation/spi/spidev b/Documentation/spi/spidev
index ed2da5e5b28a..3d14035b1766 100644
--- a/Documentation/spi/spidev
+++ b/Documentation/spi/spidev
@@ -85,6 +85,12 @@ settings for data transfer parameters:
SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL
(clock polarity, idle high iff this is set) or SPI_CPHA (clock phase,
sample on trailing edge iff this is set) flags.
+ Note that this request is limited to SPI mode flags that fit in a
+ single byte.
+
+ SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32 ... pass a pointer to a uin32_t
+ which will return (RD) or assign (WR) the full SPI transfer mode,
+ not limited to the bits that fit in one byte.
SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte
which will return (RD) or assign (WR) the bit justification used to
diff --git a/Documentation/spi/spidev_fdx.c b/Documentation/spi/spidev_fdx.c
index 36ec0774ca0b..0ea3e51292fc 100644
--- a/Documentation/spi/spidev_fdx.c
+++ b/Documentation/spi/spidev_fdx.c
@@ -78,10 +78,10 @@ static void do_msg(int fd, int len)
static void dumpstat(const char *name, int fd)
{
- __u8 mode, lsb, bits;
- __u32 speed;
+ __u8 lsb, bits;
+ __u32 mode, speed;
- if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) {
+ if (ioctl(fd, SPI_IOC_RD_MODE32, &mode) < 0) {
perror("SPI rd_mode");
return;
}
@@ -98,7 +98,7 @@ static void dumpstat(const char *name, int fd)
return;
}
- printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n",
+ printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n",
name, mode, bits, lsb ? "(lsb first) " : "", speed);
}
diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c
index 16feda901469..3a2f9d59edab 100644
--- a/Documentation/spi/spidev_test.c
+++ b/Documentation/spi/spidev_test.c
@@ -30,7 +30,7 @@ static void pabort(const char *s)
}
static const char *device = "/dev/spidev1.1";
-static uint8_t mode;
+static uint32_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
@@ -57,6 +57,21 @@ static void transfer(int fd)
.bits_per_word = bits,
};
+ if (mode & SPI_TX_QUAD)
+ tr.tx_nbits = 4;
+ else if (mode & SPI_TX_DUAL)
+ tr.tx_nbits = 2;
+ if (mode & SPI_RX_QUAD)
+ tr.rx_nbits = 4;
+ else if (mode & SPI_RX_DUAL)
+ tr.rx_nbits = 2;
+ if (!(mode & SPI_LOOP)) {
+ if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
+ tr.rx_buf = 0;
+ else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
+ tr.tx_buf = 0;
+ }
+
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
@@ -81,7 +96,11 @@ static void print_usage(const char *prog)
" -O --cpol clock polarity\n"
" -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n"
- " -3 --3wire SI/SO signals shared\n");
+ " -3 --3wire SI/SO signals shared\n"
+ " -N --no-cs no chip select\n"
+ " -R --ready slave pulls low to pause\n"
+ " -2 --dual dual transfer\n"
+ " -4 --quad quad transfer\n");
exit(1);
}
@@ -101,11 +120,13 @@ static void parse_opts(int argc, char *argv[])
{ "3wire", 0, 0, '3' },
{ "no-cs", 0, 0, 'N' },
{ "ready", 0, 0, 'R' },
+ { "dual", 0, 0, '2' },
+ { "quad", 0, 0, '4' },
{ NULL, 0, 0, 0 },
};
int c;
- c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);
+ c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24", lopts, NULL);
if (c == -1)
break;
@@ -147,11 +168,23 @@ static void parse_opts(int argc, char *argv[])
case 'R':
mode |= SPI_READY;
break;
+ case '2':
+ mode |= SPI_TX_DUAL;
+ break;
+ case '4':
+ mode |= SPI_TX_QUAD;
+ break;
default:
print_usage(argv[0]);
break;
}
}
+ if (mode & SPI_LOOP) {
+ if (mode & SPI_TX_DUAL)
+ mode |= SPI_RX_DUAL;
+ if (mode & SPI_TX_QUAD)
+ mode |= SPI_RX_QUAD;
+ }
}
int main(int argc, char *argv[])
@@ -168,11 +201,11 @@ int main(int argc, char *argv[])
/*
* spi mode
*/
- ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
+ ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
pabort("can't set spi mode");
- ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
+ ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
if (ret == -1)
pabort("can't get spi mode");
@@ -198,7 +231,7 @@ int main(int argc, char *argv[])
if (ret == -1)
pabort("can't get max speed hz");
- printf("spi mode: %d\n", mode);
+ printf("spi mode: 0x%x\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index e55124e7c40c..ec8be46bf48d 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -320,10 +320,11 @@ This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
==============================================================
-hung_task_warning:
+hung_task_warnings:
The maximum number of warnings to report. During a check interval
-When this value is reached, no more the warnings will be reported.
+if a hung task is detected, this value is decreased by 1.
+When this value reaches 0, no more warnings will be reported.
This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
-1: report an infinite number of warnings.
@@ -441,8 +442,7 @@ feature should be disabled. Otherwise, if the system overhead from the
feature is too high then the rate the kernel samples for NUMA hinting
faults may be controlled by the numa_balancing_scan_period_min_ms,
numa_balancing_scan_delay_ms, numa_balancing_scan_period_max_ms,
-numa_balancing_scan_size_mb, numa_balancing_settle_count sysctls and
-numa_balancing_migrate_deferred.
+numa_balancing_scan_size_mb, and numa_balancing_settle_count sysctls.
==============================================================
@@ -483,13 +483,6 @@ rate for each task.
numa_balancing_scan_size_mb is how many megabytes worth of pages are
scanned for a given scan.
-numa_balancing_migrate_deferred is how many page migrations get skipped
-unconditionally, after a page migration is skipped because a page is shared
-with other tasks. This reduces page migration overhead, and determines
-how much stronger the "move task near its memory" policy scheduler becomes,
-versus the "move memory near its task" memory management policy, for workloads
-with shared memory.
-
==============================================================
osrelease, ostype & version:
diff --git a/Documentation/trace/events-power.txt b/Documentation/trace/events-power.txt
index 3bd33b8dc7c4..21d514ced212 100644
--- a/Documentation/trace/events-power.txt
+++ b/Documentation/trace/events-power.txt
@@ -92,5 +92,5 @@ dev_pm_qos_remove_request "device=%s type=%s new_value=%d"
The first parameter gives the device name which tries to add/update/remove
QoS requests.
-The second parameter gives the request type (e.g. "DEV_PM_QOS_LATENCY").
+The second parameter gives the request type (e.g. "DEV_PM_QOS_RESUME_LATENCY").
The third parameter is value to be added/updated/removed.
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index dce3d05b4823..a9380ba54c8e 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -586,8 +586,8 @@ struct kvm_fpu {
4.24 KVM_CREATE_IRQCHIP
-Capability: KVM_CAP_IRQCHIP
-Architectures: x86, ia64, ARM, arm64
+Capability: KVM_CAP_IRQCHIP, KVM_CAP_S390_IRQCHIP (s390)
+Architectures: x86, ia64, ARM, arm64, s390
Type: vm ioctl
Parameters: none
Returns: 0 on success, -1 on error
@@ -596,7 +596,10 @@ Creates an interrupt controller model in the kernel. On x86, creates a virtual
ioapic, a virtual PIC (two PICs, nested), and sets up future vcpus to have a
local APIC. IRQ routing for GSIs 0-15 is set to both PIC and IOAPIC; GSI 16-23
only go to the IOAPIC. On ia64, a IOSAPIC is created. On ARM/arm64, a GIC is
-created.
+created. On s390, a dummy irq routing table is created.
+
+Note that on s390 the KVM_CAP_S390_IRQCHIP vm capability needs to be enabled
+before KVM_CREATE_IRQCHIP can be used.
4.25 KVM_IRQ_LINE
@@ -612,6 +615,20 @@ On some architectures it is required that an interrupt controller model has
been previously created with KVM_CREATE_IRQCHIP. Note that edge-triggered
interrupts require the level to be set to 1 and then back to 0.
+On real hardware, interrupt pins can be active-low or active-high. This
+does not matter for the level field of struct kvm_irq_level: 1 always
+means active (asserted), 0 means inactive (deasserted).
+
+x86 allows the operating system to program the interrupt polarity
+(active-low/active-high) for level-triggered interrupts, and KVM used
+to consider the polarity. However, due to bitrot in the handling of
+active-low interrupts, the above convention is now valid on x86 too.
+This is signaled by KVM_CAP_X86_IOAPIC_POLARITY_IGNORED. Userspace
+should not present interrupts to the guest as active-low unless this
+capability is present (or unless it is not using the in-kernel irqchip,
+of course).
+
+
ARM/arm64 can signal an interrupt either at the CPU level, or at the
in-kernel irqchip (GIC), and for in-kernel irqchip can tell the GIC to
use PPIs designated for specific cpus. The irq field is interpreted
@@ -628,7 +645,7 @@ The irq_type field has the following values:
(The irq_id field thus corresponds nicely to the IRQ ID in the ARM GIC specs)
-In both cases, level is used to raise/lower the line.
+In both cases, level is used to assert/deassert the line.
struct kvm_irq_level {
union {
@@ -918,9 +935,9 @@ documentation when it pops into existence).
4.37 KVM_ENABLE_CAP
-Capability: KVM_CAP_ENABLE_CAP
+Capability: KVM_CAP_ENABLE_CAP, KVM_CAP_ENABLE_CAP_VM
Architectures: ppc, s390
-Type: vcpu ioctl
+Type: vcpu ioctl, vm ioctl (with KVM_CAP_ENABLE_CAP_VM)
Parameters: struct kvm_enable_cap (in)
Returns: 0 on success; -1 on error
@@ -951,6 +968,8 @@ function properly, this is the place to put them.
__u8 pad[64];
};
+The vcpu ioctl should be used for vcpu-specific capabilities, the vm ioctl
+for vm-wide capabilities.
4.38 KVM_GET_MP_STATE
@@ -1320,7 +1339,7 @@ KVM_ASSIGN_DEV_IRQ. Partial deassignment of host or guest IRQ is allowed.
4.52 KVM_SET_GSI_ROUTING
Capability: KVM_CAP_IRQ_ROUTING
-Architectures: x86 ia64
+Architectures: x86 ia64 s390
Type: vm ioctl
Parameters: struct kvm_irq_routing (in)
Returns: 0 on success, -1 on error
@@ -1343,6 +1362,7 @@ struct kvm_irq_routing_entry {
union {
struct kvm_irq_routing_irqchip irqchip;
struct kvm_irq_routing_msi msi;
+ struct kvm_irq_routing_s390_adapter adapter;
__u32 pad[8];
} u;
};
@@ -1350,6 +1370,7 @@ struct kvm_irq_routing_entry {
/* gsi routing entry types */
#define KVM_IRQ_ROUTING_IRQCHIP 1
#define KVM_IRQ_ROUTING_MSI 2
+#define KVM_IRQ_ROUTING_S390_ADAPTER 3
No flags are specified so far, the corresponding field must be set to zero.
@@ -1365,6 +1386,14 @@ struct kvm_irq_routing_msi {
__u32 pad;
};
+struct kvm_irq_routing_s390_adapter {
+ __u64 ind_addr;
+ __u64 summary_addr;
+ __u64 ind_offset;
+ __u32 summary_offset;
+ __u32 adapter_id;
+};
+
4.53 KVM_ASSIGN_SET_MSIX_NR
@@ -2566,6 +2595,10 @@ executed a memory-mapped I/O instruction which could not be satisfied
by kvm. The 'data' member contains the written data if 'is_write' is
true, and should be filled by application code otherwise.
+The 'data' member contains, in its first 'len' bytes, the value as it would
+appear if the VCPU performed a load or store of the appropriate width directly
+to the byte array.
+
NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO, KVM_EXIT_OSI, KVM_EXIT_DCR,
KVM_EXIT_PAPR and KVM_EXIT_EPR the corresponding
operations are complete (and guest state is consistent) only after userspace
diff --git a/Documentation/virtual/kvm/devices/s390_flic.txt b/Documentation/virtual/kvm/devices/s390_flic.txt
new file mode 100644
index 000000000000..4ceef53164b0
--- /dev/null
+++ b/Documentation/virtual/kvm/devices/s390_flic.txt
@@ -0,0 +1,91 @@
+FLIC (floating interrupt controller)
+====================================
+
+FLIC handles floating (non per-cpu) interrupts, i.e. I/O, service and some
+machine check interruptions. All interrupts are stored in a per-vm list of
+pending interrupts. FLIC performs operations on this list.
+
+Only one FLIC instance may be instantiated.
+
+FLIC provides support to
+- add interrupts (KVM_DEV_FLIC_ENQUEUE)
+- inspect currently pending interrupts (KVM_FLIC_GET_ALL_IRQS)
+- purge all pending floating interrupts (KVM_DEV_FLIC_CLEAR_IRQS)
+- enable/disable for the guest transparent async page faults
+- register and modify adapter interrupt sources (KVM_DEV_FLIC_ADAPTER_*)
+
+Groups:
+ KVM_DEV_FLIC_ENQUEUE
+ Passes a buffer and length into the kernel which are then injected into
+ the list of pending interrupts.
+ attr->addr contains the pointer to the buffer and attr->attr contains
+ the length of the buffer.
+ The format of the data structure kvm_s390_irq as it is copied from userspace
+ is defined in usr/include/linux/kvm.h.
+
+ KVM_DEV_FLIC_GET_ALL_IRQS
+ Copies all floating interrupts into a buffer provided by userspace.
+ When the buffer is too small it returns -ENOMEM, which is the indication
+ for userspace to try again with a bigger buffer.
+ All interrupts remain pending, i.e. are not deleted from the list of
+ currently pending interrupts.
+ attr->addr contains the userspace address of the buffer into which all
+ interrupt data will be copied.
+ attr->attr contains the size of the buffer in bytes.
+
+ KVM_DEV_FLIC_CLEAR_IRQS
+ Simply deletes all elements from the list of currently pending floating
+ interrupts. No interrupts are injected into the guest.
+
+ KVM_DEV_FLIC_APF_ENABLE
+ Enables async page faults for the guest. So in case of a major page fault
+ the host is allowed to handle this async and continues the guest.
+
+ KVM_DEV_FLIC_APF_DISABLE_WAIT
+ Disables async page faults for the guest and waits until already pending
+ async page faults are done. This is necessary to trigger a completion interrupt
+ for every init interrupt before migrating the interrupt list.
+
+ KVM_DEV_FLIC_ADAPTER_REGISTER
+ Register an I/O adapter interrupt source. Takes a kvm_s390_io_adapter
+ describing the adapter to register:
+
+struct kvm_s390_io_adapter {
+ __u32 id;
+ __u8 isc;
+ __u8 maskable;
+ __u8 swap;
+ __u8 pad;
+};
+
+ id contains the unique id for the adapter, isc the I/O interruption subclass
+ to use, maskable whether this adapter may be masked (interrupts turned off)
+ and swap whether the indicators need to be byte swapped.
+
+
+ KVM_DEV_FLIC_ADAPTER_MODIFY
+ Modifies attributes of an existing I/O adapter interrupt source. Takes
+ a kvm_s390_io_adapter_req specifiying the adapter and the operation:
+
+struct kvm_s390_io_adapter_req {
+ __u32 id;
+ __u8 type;
+ __u8 mask;
+ __u16 pad0;
+ __u64 addr;
+};
+
+ id specifies the adapter and type the operation. The supported operations
+ are:
+
+ KVM_S390_IO_ADAPTER_MASK
+ mask or unmask the adapter, as specified in mask
+
+ KVM_S390_IO_ADAPTER_MAP
+ perform a gmap translation for the guest address provided in addr,
+ pin a userspace page for the translated address and add it to the
+ list of mappings
+
+ KVM_S390_IO_ADAPTER_UNMAP
+ release a userspace page for the translated address specified in addr
+ from the list of mappings
diff --git a/Documentation/w1/masters/ds2490 b/Documentation/w1/masters/ds2490
index 28176def3d6f..3e091151dd80 100644
--- a/Documentation/w1/masters/ds2490
+++ b/Documentation/w1/masters/ds2490
@@ -21,8 +21,6 @@ Notes and limitations.
- The weak pullup current is a minimum of 0.9mA and maximum of 6.0mA.
- The 5V strong pullup is supported with a minimum of 5.9mA and a
maximum of 30.4 mA. (From DS2490.pdf)
-- While the ds2490 supports a hardware search the code doesn't take
- advantage of it (in tested case it only returned first device).
- The hardware will detect when devices are attached to the bus on the
next bus (reset?) operation, however only a message is printed as
the core w1 code doesn't make use of the information. Connecting
diff --git a/Documentation/w1/w1.netlink b/Documentation/w1/w1.netlink
index f59a31965d50..927a52cc0519 100644
--- a/Documentation/w1/w1.netlink
+++ b/Documentation/w1/w1.netlink
@@ -5,8 +5,8 @@ Message types.
=============
There are three types of messages between w1 core and userspace:
-1. Events. They are generated each time new master or slave device
- found either due to automatic or requested search.
+1. Events. They are generated each time a new master or slave device
+ is found either due to automatic or requested search.
2. Userspace commands.
3. Replies to userspace commands.
@@ -131,7 +131,7 @@ of the w1_netlink_cmd structure and cn_msg.len will be equal to the sum
of the sizeof(struct w1_netlink_msg) and sizeof(struct w1_netlink_cmd).
If reply is generated for master or root command (which do not have
w1_netlink_cmd attached), reply will contain only cn_msg and w1_netlink_msg
-structires.
+structures.
w1_netlink_msg.status field will carry positive error value
(EINVAL for example) or zero in case of success.
@@ -160,7 +160,7 @@ procedure is started to select given device.
Then all requested in w1_netlink_msg operations are performed one by one.
If command requires reply (like read command) it is sent on command completion.
-When all commands (w1_netlink_cmd) are processed muster device is unlocked
+When all commands (w1_netlink_cmd) are processed master device is unlocked
and next w1_netlink_msg header processing started.
diff --git a/Documentation/watchdog/watchdog-parameters.txt b/Documentation/watchdog/watchdog-parameters.txt
index f9492fed4104..692791cc674c 100644
--- a/Documentation/watchdog/watchdog-parameters.txt
+++ b/Documentation/watchdog/watchdog-parameters.txt
@@ -150,6 +150,8 @@ nowayout: Disable watchdog shutdown on close
-------------------------------------------------
it87_wdt:
nogameport: Forbid the activation of game port, default=0
+nocir: Forbid the use of CIR (workaround for some buggy setups); set to 1 if
+system resets despite watchdog daemon running, default=0
exclusive: Watchdog exclusive device open, default=1
timeout: Watchdog timeout in seconds, default=60
testmode: Watchdog test mode (1 = no reboot), default=0
@@ -325,6 +327,11 @@ soft_noboot: Softdog action, set to 1 to ignore reboots, 0 to reboot
stmp3xxx_wdt:
heartbeat: Watchdog heartbeat period in seconds from 1 to 4194304, default 19
-------------------------------------------------
+tegra_wdt:
+heartbeat: Watchdog heartbeats in seconds. (default = 120)
+nowayout: Watchdog cannot be stopped once started
+ (default=kernel config parameter)
+-------------------------------------------------
ts72xx_wdt:
timeout: Watchdog timeout in seconds. (1 <= timeout <= 8, default=8)
nowayout: Disable watchdog shutdown on close
diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt
index cb81741d3b0b..a75e3adaa39d 100644
--- a/Documentation/x86/boot.txt
+++ b/Documentation/x86/boot.txt
@@ -182,7 +182,7 @@ Offset Proto Name Meaning
0226/1 2.02+(3 ext_loader_ver Extended boot loader version
0227/1 2.02+(3 ext_loader_type Extended boot loader ID
0228/4 2.02+ cmd_line_ptr 32-bit pointer to the kernel command line
-022C/4 2.03+ ramdisk_max Highest legal initrd address
+022C/4 2.03+ initrd_addr_max Highest legal initrd address
0230/4 2.05+ kernel_alignment Physical addr alignment required for kernel
0234/1 2.05+ relocatable_kernel Whether kernel is relocatable or not
0235/1 2.10+ min_alignment Minimum alignment, as a power of two
@@ -534,7 +534,7 @@ Protocol: 2.02+
zero, the kernel will assume that your boot loader does not support
the 2.02+ protocol.
-Field name: ramdisk_max
+Field name: initrd_addr_max
Type: read
Offset/size: 0x22c/4
Protocol: 2.03+
diff --git a/MAINTAINERS b/MAINTAINERS
index fb08dcececf1..ee175ff17256 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -73,7 +73,8 @@ Descriptions of section entries:
L: Mailing list that is relevant to this area
W: Web-page with status/info
Q: Patchwork web based patch tracking system site
- T: SCM tree type and location. Type is one of: git, hg, quilt, stgit, topgit.
+ T: SCM tree type and location.
+ Type is one of: git, hg, quilt, stgit, topgit
S: Status, one of the following:
Supported: Someone is actually paid to look after this.
Maintained: Someone actually looks after it.
@@ -241,8 +242,8 @@ S: Maintained
F: drivers/platform/x86/acer-wmi.c
ACPI
-M: Len Brown <lenb@kernel.org>
M: Rafael J. Wysocki <rjw@rjwysocki.net>
+M: Len Brown <lenb@kernel.org>
L: linux-acpi@vger.kernel.org
W: https://01.org/linux-acpi
Q: https://patchwork.kernel.org/project/linux-acpi/list/
@@ -473,7 +474,7 @@ F: net/rxrpc/af_rxrpc.c
AGPGART DRIVER
M: David Airlie <airlied@linux.ie>
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
+T: git git://people.freedesktop.org/~airlied/linux (part of drm maint)
S: Maintained
F: drivers/char/agp/
F: include/linux/agp*
@@ -538,7 +539,7 @@ F: arch/alpha/
ALTERA UART/JTAG UART SERIAL DRIVERS
M: Tobias Klauser <tklauser@distanz.ch>
L: linux-serial@vger.kernel.org
-L: nios2-dev@sopc.et.ntust.edu.tw (moderated for non-subscribers)
+L: nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
S: Maintained
F: drivers/tty/serial/altera_uart.c
F: drivers/tty/serial/altera_jtaguart.c
@@ -910,11 +911,11 @@ F: arch/arm/include/asm/hardware/dec21285.h
F: arch/arm/mach-footbridge/
ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
-M: Shawn Guo <shawn.guo@linaro.org>
+M: Shawn Guo <shawn.guo@freescale.com>
M: Sascha Hauer <kernel@pengutronix.de>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
-T: git git://git.linaro.org/people/shawnguo/linux-2.6.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
F: arch/arm/mach-imx/
F: arch/arm/boot/dts/imx*
F: arch/arm/configs/imx*_defconfig
@@ -1319,6 +1320,7 @@ M: Linus Walleij <linus.walleij@linaro.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Supported
F: arch/arm/mach-u300/
+F: drivers/clocksource/timer-u300.c
F: drivers/i2c/busses/i2c-stu300.c
F: drivers/rtc/rtc-coh901331.c
F: drivers/watchdog/coh901327_wdt.c
@@ -1612,11 +1614,11 @@ S: Maintained
F: drivers/net/wireless/atmel*
ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER
-M: Bradley Grove <linuxdrivers@attotech.com>
-L: linux-scsi@vger.kernel.org
-W: http://www.attotech.com
-S: Supported
-F: drivers/scsi/esas2r
+M: Bradley Grove <linuxdrivers@attotech.com>
+L: linux-scsi@vger.kernel.org
+W: http://www.attotech.com
+S: Supported
+F: drivers/scsi/esas2r
AUDIT SUBSYSTEM
M: Eric Paris <eparis@redhat.com>
@@ -1737,6 +1739,7 @@ F: include/uapi/linux/bfs_fs.h
BLACKFIN ARCHITECTURE
M: Steven Miao <realmz6@gmail.com>
L: adi-buildroot-devel@lists.sourceforge.net
+T: git git://git.code.sf.net/p/adi-linux/code
W: http://blackfin.uclinux.org
S: Supported
F: arch/blackfin/
@@ -1830,8 +1833,8 @@ F: net/bluetooth/
F: include/net/bluetooth/
BONDING DRIVER
-M: Jay Vosburgh <fubar@us.ibm.com>
-M: Veaceslav Falico <vfalico@redhat.com>
+M: Jay Vosburgh <j.vosburgh@gmail.com>
+M: Veaceslav Falico <vfalico@gmail.com>
M: Andy Gospodarek <andy@greyhouse.net>
L: netdev@vger.kernel.org
W: http://sourceforge.net/projects/bonding/
@@ -1860,6 +1863,7 @@ F: drivers/net/ethernet/broadcom/bnx2x/
BROADCOM BCM281XX/BCM11XXX ARM ARCHITECTURE
M: Christian Daudt <bcm@fixthebug.org>
+M: Matt Porter <mporter@linaro.org>
L: bcm-kernel-feedback-list@broadcom.com
T: git git://git.github.com/broadcom/bcm11351
S: Maintained
@@ -1917,8 +1921,8 @@ F: drivers/bcma/
F: include/linux/bcma/
BROCADE BFA FC SCSI DRIVER
-M: Anil Gurumurthy <agurumur@brocade.com>
-M: Vijaya Mohan Guvva <vmohan@brocade.com>
+M: Anil Gurumurthy <anil.gurumurthy@qlogic.com>
+M: Sudarsana Kalluru <sudarsana.kalluru@qlogic.com>
L: linux-scsi@vger.kernel.org
S: Supported
F: drivers/scsi/bfa/
@@ -2158,7 +2162,7 @@ F: Documentation/zh_CN/
CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
M: Peter Chen <Peter.Chen@freescale.com>
-T: git://github.com/hzpeterchen/linux-usb.git
+T: git git://github.com/hzpeterchen/linux-usb.git
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/chipidea/
@@ -2178,9 +2182,9 @@ S: Supported
F: drivers/net/ethernet/cisco/enic/
CISCO VIC LOW LATENCY NIC DRIVER
-M: Upinder Malhi <umalhi@cisco.com>
-S: Supported
-F: drivers/infiniband/hw/usnic
+M: Upinder Malhi <umalhi@cisco.com>
+S: Supported
+F: drivers/infiniband/hw/usnic
CIRRUS LOGIC EP93XX ETHERNET DRIVER
M: Hartley Sweeten <hsweeten@visionengravers.com>
@@ -2200,6 +2204,13 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Odd Fixes
F: sound/soc/codecs/cs4270*
+CIRRUS LOGIC AUDIO CODEC DRIVERS
+M: Brian Austin <brian.austin@cirrus.com>
+M: Paul Handrigan <Paul.Handrigan@cirrus.com>
+L: alsa-devel@alsa-project.org (moderated for non-subscribers)
+S: Maintained
+F: sound/soc/codecs/cs*
+
CLEANCACHE API
M: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
L: linux-kernel@vger.kernel.org
@@ -2377,20 +2388,20 @@ F: drivers/cpufreq/arm_big_little.c
F: drivers/cpufreq/arm_big_little_dt.c
CPUIDLE DRIVER - ARM BIG LITTLE
-M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
-M: Daniel Lezcano <daniel.lezcano@linaro.org>
-L: linux-pm@vger.kernel.org
-L: linux-arm-kernel@lists.infradead.org
-T: git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
-S: Maintained
-F: drivers/cpuidle/cpuidle-big_little.c
+M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+M: Daniel Lezcano <daniel.lezcano@linaro.org>
+L: linux-pm@vger.kernel.org
+L: linux-arm-kernel@lists.infradead.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+S: Maintained
+F: drivers/cpuidle/cpuidle-big_little.c
CPUIDLE DRIVERS
M: Rafael J. Wysocki <rjw@rjwysocki.net>
M: Daniel Lezcano <daniel.lezcano@linaro.org>
L: linux-pm@vger.kernel.org
S: Maintained
-T: git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
F: drivers/cpuidle/*
F: include/linux/cpuidle.h
@@ -2408,8 +2419,10 @@ F: tools/power/cpupower/
CPUSETS
M: Li Zefan <lizefan@huawei.com>
+L: cgroups@vger.kernel.org
W: http://www.bullopensource.org/cpuset/
W: http://oss.sgi.com/projects/cpusets/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
S: Maintained
F: Documentation/cgroups/cpusets.txt
F: include/linux/cpuset.h
@@ -2455,9 +2468,9 @@ S: Maintained
F: sound/pci/cs5535audio/
CW1200 WLAN driver
-M: Solomon Peachy <pizza@shaftnet.org>
-S: Maintained
-F: drivers/net/wireless/cw1200/
+M: Solomon Peachy <pizza@shaftnet.org>
+S: Maintained
+F: drivers/net/wireless/cw1200/
CX18 VIDEO4LINUX DRIVER
M: Andy Walls <awalls@md.metrocast.net>
@@ -2608,9 +2621,9 @@ DC395x SCSI driver
M: Oliver Neukum <oliver@neukum.org>
M: Ali Akcaagac <aliakc@web.de>
M: Jamie Lenehan <lenehan@twibble.org>
-W: http://twibble.org/dist/dc395x/
L: dc395x@twibble.org
-L: http://lists.twibble.org/mailman/listinfo/dc395x/
+W: http://twibble.org/dist/dc395x/
+W: http://lists.twibble.org/mailman/listinfo/dc395x/
S: Maintained
F: Documentation/scsi/dc395x.txt
F: drivers/scsi/dc395x.*
@@ -2796,9 +2809,9 @@ S: Supported
F: drivers/acpi/dock.c
DOCUMENTATION
-M: Rob Landley <rob@landley.net>
+M: Randy Dunlap <rdunlap@infradead.org>
L: linux-doc@vger.kernel.org
-T: TBD
+T: quilt http://www.infradead.org/~rdunlap/Doc/patches/
S: Maintained
F: Documentation/
@@ -2845,12 +2858,22 @@ F: lib/kobj*
DRM DRIVERS
M: David Airlie <airlied@linux.ie>
L: dri-devel@lists.freedesktop.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
+T: git git://people.freedesktop.org/~airlied/linux
S: Maintained
F: drivers/gpu/drm/
F: include/drm/
F: include/uapi/drm/
+RADEON DRM DRIVERS
+M: Alex Deucher <alexander.deucher@amd.com>
+M: Christian König <christian.koenig@amd.com>
+L: dri-devel@lists.freedesktop.org
+T: git git://people.freedesktop.org/~agd5f/linux
+S: Supported
+F: drivers/gpu/drm/radeon/
+F: include/drm/radeon*
+F: include/uapi/drm/radeon*
+
INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
M: Daniel Vetter <daniel.vetter@ffwll.ch>
M: Jani Nikula <jani.nikula@linux.intel.com>
@@ -3082,6 +3105,8 @@ F: fs/ecryptfs/
EDAC-CORE
M: Doug Thompson <dougthompson@xmission.com>
+M: Borislav Petkov <bp@alien8.de>
+M: Mauro Carvalho Chehab <m.chehab@samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Supported
@@ -3324,6 +3349,17 @@ S: Maintained
F: include/linux/netfilter_bridge/
F: net/bridge/
+ETHERNET PHY LIBRARY
+M: Florian Fainelli <f.fainelli@gmail.com>
+L: netdev@vger.kernel.org
+S: Maintained
+F: include/linux/phy.h
+F: include/linux/phy_fixed.h
+F: drivers/net/phy/
+F: Documentation/networking/phy.txt
+F: drivers/of/of_mdio.c
+F: drivers/of/of_net.c
+
EXT2 FILE SYSTEM
M: Jan Kara <jack@suse.cz>
L: linux-ext4@vger.kernel.org
@@ -3629,8 +3665,8 @@ S: Maintained
F: fs/freevxfs/
FREEZER
-M: Pavel Machek <pavel@ucw.cz>
M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
+M: Pavel Machek <pavel@ucw.cz>
L: linux-pm@vger.kernel.org
S: Supported
F: Documentation/power/freezing-of-tasks.txt
@@ -3994,8 +4030,8 @@ S: Maintained
F: drivers/video/hgafb.c
HIBERNATION (aka Software Suspend, aka swsusp)
-M: Pavel Machek <pavel@ucw.cz>
M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
+M: Pavel Machek <pavel@ucw.cz>
L: linux-pm@vger.kernel.org
S: Supported
F: arch/x86/power/
@@ -4517,6 +4553,7 @@ M: Greg Rose <gregory.v.rose@intel.com>
M: Alex Duyck <alexander.h.duyck@intel.com>
M: John Ronciak <john.ronciak@intel.com>
M: Mitch Williams <mitch.a.williams@intel.com>
+M: Linux NICS <linux.nics@intel.com>
L: e1000-devel@lists.sourceforge.net
W: http://www.intel.com/support/feedback.htm
W: http://e1000.sourceforge.net/
@@ -4534,6 +4571,7 @@ F: Documentation/networking/ixgbevf.txt
F: Documentation/networking/i40e.txt
F: Documentation/networking/i40evf.txt
F: drivers/net/ethernet/intel/
+F: drivers/net/ethernet/intel/*/
INTEL-MID GPIO DRIVER
M: David Cohen <david.a.cohen@linux.intel.com>
@@ -4890,7 +4928,7 @@ F: drivers/staging/ktap/
KCONFIG
M: "Yann E. MORIN" <yann.morin.1998@free.fr>
L: linux-kbuild@vger.kernel.org
-T: git://gitorious.org/linux-kconfig/linux-kconfig
+T: git git://gitorious.org/linux-kconfig/linux-kconfig
S: Maintained
F: Documentation/kbuild/kconfig-language.txt
F: scripts/kconfig/
@@ -5216,11 +5254,10 @@ F: arch/powerpc/platforms/512x/
F: arch/powerpc/platforms/52xx/
LINUX FOR POWERPC EMBEDDED PPC4XX
-M: Josh Boyer <jwboyer@gmail.com>
+M: Alistair Popple <alistair@popple.id.au>
M: Matt Porter <mporter@kernel.crashing.org>
W: http://www.penguinppc.org/
L: linuxppc-dev@lists.ozlabs.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git
S: Maintained
F: arch/powerpc/platforms/40x/
F: arch/powerpc/platforms/44x/
@@ -5447,11 +5484,11 @@ S: Maintained
F: drivers/media/tuners/m88ts2022*
MA901 MASTERKIT USB FM RADIO DRIVER
-M: Alexey Klimov <klimov.linux@gmail.com>
-L: linux-media@vger.kernel.org
-T: git git://linuxtv.org/media_tree.git
-S: Maintained
-F: drivers/media/radio/radio-ma901.c
+M: Alexey Klimov <klimov.linux@gmail.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/radio/radio-ma901.c
MAC80211
M: Johannes Berg <johannes@sipsolutions.net>
@@ -5487,6 +5524,11 @@ W: http://www.kernel.org/doc/man-pages
L: linux-man@vger.kernel.org
S: Maintained
+MARVELL ARMADA DRM SUPPORT
+M: Russell King <rmk+kernel@arm.linux.org.uk>
+S: Maintained
+F: drivers/gpu/drm/armada/
+
MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
M: Mirko Lindner <mlindner@marvell.com>
M: Stephen Hemminger <stephen@networkplumber.org>
@@ -5607,7 +5649,7 @@ F: drivers/scsi/megaraid/
MELLANOX ETHERNET DRIVER (mlx4_en)
M: Amir Vadai <amirv@mellanox.com>
-L: netdev@vger.kernel.org
+L: netdev@vger.kernel.org
S: Supported
W: http://www.mellanox.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
@@ -5648,11 +5690,17 @@ F: include/linux/mtd/
F: include/uapi/mtd/
MEN A21 WATCHDOG DRIVER
-M: Johannes Thumshirn <johannes.thumshirn@men.de>
+M: Johannes Thumshirn <johannes.thumshirn@men.de>
L: linux-watchdog@vger.kernel.org
S: Supported
F: drivers/watchdog/mena21_wdt.c
+MEN CHAMELEON BUS (mcb)
+M: Johannes Thumshirn <johannes.thumshirn@men.de>
+S: Supported
+F: drivers/mcb/
+F: include/linux/mcb.h
+
METAG ARCHITECTURE
M: James Hogan <james.hogan@imgtec.com>
L: linux-metag@vger.kernel.org
@@ -5704,20 +5752,20 @@ L: linux-rdma@vger.kernel.org
W: http://www.mellanox.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
Q: http://patchwork.kernel.org/project/linux-rdma/list/
-T: git://openfabrics.org/~eli/connect-ib.git
+T: git git://openfabrics.org/~eli/connect-ib.git
S: Supported
F: drivers/net/ethernet/mellanox/mlx5/core/
F: include/linux/mlx5/
Mellanox MLX5 IB driver
-M: Eli Cohen <eli@mellanox.com>
-L: linux-rdma@vger.kernel.org
-W: http://www.mellanox.com
-Q: http://patchwork.kernel.org/project/linux-rdma/list/
-T: git://openfabrics.org/~eli/connect-ib.git
-S: Supported
-F: include/linux/mlx5/
-F: drivers/infiniband/hw/mlx5/
+M: Eli Cohen <eli@mellanox.com>
+L: linux-rdma@vger.kernel.org
+W: http://www.mellanox.com
+Q: http://patchwork.kernel.org/project/linux-rdma/list/
+T: git git://openfabrics.org/~eli/connect-ib.git
+S: Supported
+F: include/linux/mlx5/
+F: drivers/infiniband/hw/mlx5/
MODULE SUPPORT
M: Rusty Russell <rusty@rustcorp.com.au>
@@ -5969,6 +6017,9 @@ F: include/linux/netdevice.h
F: include/uapi/linux/in.h
F: include/uapi/linux/net.h
F: include/uapi/linux/netdevice.h
+F: tools/net/
+F: tools/testing/selftests/net/
+F: lib/random32.c
NETWORKING [IPv4/IPv6]
M: "David S. Miller" <davem@davemloft.net>
@@ -6142,6 +6193,12 @@ S: Supported
F: drivers/block/nvme*
F: include/linux/nvme.h
+NXP TDA998X DRM DRIVER
+M: Russell King <rmk+kernel@arm.linux.org.uk>
+S: Supported
+F: drivers/gpu/drm/i2c/tda998x_drv.c
+F: include/drm/i2c/tda998x.h
+
OMAP SUPPORT
M: Tony Lindgren <tony@atomide.com>
L: linux-omap@vger.kernel.org
@@ -7361,10 +7418,26 @@ W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported
F: arch/s390/
F: drivers/s390/
-F: block/partitions/ibm.c
F: Documentation/s390/
F: Documentation/DocBook/s390*
+S390 COMMON I/O LAYER
+M: Sebastian Ott <sebott@linux.vnet.ibm.com>
+M: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+L: linux-s390@vger.kernel.org
+W: http://www.ibm.com/developerworks/linux/linux390/
+S: Supported
+F: drivers/s390/cio/
+
+S390 DASD DRIVER
+M: Stefan Weinhuber <wein@de.ibm.com>
+M: Stefan Haberland <stefan.haberland@de.ibm.com>
+L: linux-s390@vger.kernel.org
+W: http://www.ibm.com/developerworks/linux/linux390/
+S: Supported
+F: drivers/s390/block/dasd*
+F: block/partitions/ibm.c
+
S390 NETWORK DRIVERS
M: Ursula Braun <ursula.braun@de.ibm.com>
M: Frank Blaschka <blaschka@linux.vnet.ibm.com>
@@ -7374,6 +7447,15 @@ W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported
F: drivers/s390/net/
+S390 PCI SUBSYSTEM
+M: Sebastian Ott <sebott@linux.vnet.ibm.com>
+M: Gerald Schaefer <gerald.schaefer@de.ibm.com>
+L: linux-s390@vger.kernel.org
+W: http://www.ibm.com/developerworks/linux/linux390/
+S: Supported
+F: arch/s390/pci/
+F: drivers/pci/hotplug/s390_pci_hpc.c
+
S390 ZCRYPT DRIVER
M: Ingo Tuchscherer <ingo.tuchscherer@de.ibm.com>
M: linux390@de.ibm.com
@@ -7757,13 +7839,6 @@ F: Documentation/ia64/serial.txt
F: drivers/tty/serial/ioc?_serial.c
F: include/linux/ioc?.h
-SGI VISUAL WORKSTATION 320 AND 540
-M: Andrey Panin <pazke@donpac.ru>
-L: linux-visws-devel@lists.sf.net
-W: http://linux-visws.sf.net
-S: Maintained for 2.6.
-F: Documentation/sgi-visws.txt
-
SGI XP/XPC/XPNET DRIVER
M: Cliff Whickman <cpw@sgi.com>
M: Robin Holt <robinmholt@gmail.com>
@@ -8311,6 +8386,12 @@ M: Teddy Wang <teddy.wang@siliconmotion.com.cn>
S: Odd Fixes
F: drivers/staging/sm7xxfb/
+STAGING - SLICOSS
+M: Lior Dotan <liodot@gmail.com>
+M: Christopher Harrer <charrer@alacritech.com>
+S: Odd Fixes
+F: drivers/staging/slicoss/
+
STAGING - SOFTLOGIC 6x10 MPEG CODEC
M: Ismael Luceno <ismael.luceno@corp.bluecherry.net>
S: Supported
@@ -8383,9 +8464,9 @@ F: arch/sh/
F: drivers/sh/
SUSPEND TO RAM
+M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
M: Len Brown <len.brown@intel.com>
M: Pavel Machek <pavel@ucw.cz>
-M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
L: linux-pm@vger.kernel.org
S: Supported
F: Documentation/power/
@@ -8429,8 +8510,8 @@ TARGET SUBSYSTEM
M: Nicholas A. Bellinger <nab@linux-iscsi.org>
L: linux-scsi@vger.kernel.org
L: target-devel@vger.kernel.org
-L: http://groups.google.com/group/linux-iscsi-target-dev
W: http://www.linux-iscsi.org
+W: http://groups.google.com/group/linux-iscsi-target-dev
T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master
S: Supported
F: drivers/target/
@@ -8671,17 +8752,17 @@ S: Maintained
F: drivers/media/radio/radio-raremono.c
THERMAL
-M: Zhang Rui <rui.zhang@intel.com>
-M: Eduardo Valentin <eduardo.valentin@ti.com>
-L: linux-pm@vger.kernel.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git
-Q: https://patchwork.kernel.org/project/linux-pm/list/
-S: Supported
-F: drivers/thermal/
-F: include/linux/thermal.h
-F: include/linux/cpu_cooling.h
-F: Documentation/devicetree/bindings/thermal/
+M: Zhang Rui <rui.zhang@intel.com>
+M: Eduardo Valentin <eduardo.valentin@ti.com>
+L: linux-pm@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git
+Q: https://patchwork.kernel.org/project/linux-pm/list/
+S: Supported
+F: drivers/thermal/
+F: include/linux/thermal.h
+F: include/linux/cpu_cooling.h
+F: Documentation/devicetree/bindings/thermal/
THINGM BLINK(1) USB RGB LED DRIVER
M: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
@@ -8996,6 +9077,13 @@ F: drivers/cdrom/cdrom.c
F: include/linux/cdrom.h
F: include/uapi/linux/cdrom.h
+UNISYS S-PAR DRIVERS
+M: Benjamin Romer <benjamin.romer@unisys.com>
+M: David Kershner <david.kershner@unisys.com>
+L: sparmaintainer@unisys.com (Unisys internal)
+S: Supported
+F: drivers/staging/unisys/
+
UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER
M: Vinayak Holikatti <vinholikatti@gmail.com>
M: Santosh Y <santoshsy@gmail.com>
@@ -9034,8 +9122,7 @@ S: Maintained
F: drivers/net/wireless/ath/ar5523/
USB ATTACHED SCSI
-M: Matthew Wilcox <willy@linux.intel.com>
-M: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+M: Hans de Goede <hdegoede@redhat.com>
M: Gerd Hoffmann <kraxel@redhat.com>
L: linux-usb@vger.kernel.org
L: linux-scsi@vger.kernel.org
@@ -9261,7 +9348,7 @@ S: Maintained
F: drivers/net/wireless/rndis_wlan.c
USB XHCI DRIVER
-M: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+M: Mathias Nyman <mathias.nyman@intel.com>
L: linux-usb@vger.kernel.org
S: Supported
F: drivers/usb/host/xhci*
@@ -9345,7 +9432,6 @@ F: include/media/videobuf2-*
VIRTIO CONSOLE DRIVER
M: Amit Shah <amit.shah@redhat.com>
-L: virtio-dev@lists.oasis-open.org
L: virtualization@lists.linux-foundation.org
S: Maintained
F: drivers/char/virtio_console.c
@@ -9355,7 +9441,6 @@ F: include/uapi/linux/virtio_console.h
VIRTIO CORE, NET AND BLOCK DRIVERS
M: Rusty Russell <rusty@rustcorp.com.au>
M: "Michael S. Tsirkin" <mst@redhat.com>
-L: virtio-dev@lists.oasis-open.org
L: virtualization@lists.linux-foundation.org
S: Maintained
F: drivers/virtio/
@@ -9368,7 +9453,6 @@ F: include/uapi/linux/virtio_*.h
VIRTIO HOST (VHOST)
M: "Michael S. Tsirkin" <mst@redhat.com>
L: kvm@vger.kernel.org
-L: virtio-dev@lists.oasis-open.org
L: virtualization@lists.linux-foundation.org
L: netdev@vger.kernel.org
S: Maintained
@@ -9715,7 +9799,6 @@ F: drivers/xen/*swiotlb*
XFS FILESYSTEM
P: Silicon Graphics Inc
M: Dave Chinner <david@fromorbit.com>
-M: Ben Myers <bpm@sgi.com>
M: xfs@oss.sgi.com
L: xfs@oss.sgi.com
W: http://oss.sgi.com/projects/xfs
@@ -9740,6 +9823,12 @@ L: linux-serial@vger.kernel.org
S: Maintained
F: drivers/tty/serial/uartlite.c
+XTENSA XTFPGA PLATFORM SUPPORT
+M: Max Filippov <jcmvbkbc@gmail.com>
+L: linux-xtensa@linux-xtensa.org
+S: Maintained
+F: drivers/spi/spi-xtensa-xtfpga.c
+
YAM DRIVER FOR AX.25
M: Jean-Paul Roubelat <jpr@f6fbb.org>
L: linux-hams@vger.kernel.org
@@ -9784,7 +9873,7 @@ ZR36067 VIDEO FOR LINUX DRIVER
L: mjpeg-users@lists.sourceforge.net
L: linux-media@vger.kernel.org
W: http://mjpeg.sourceforge.net/driver-zoran/
-T: Mercurial http://linuxtv.org/hg/v4l-dvb
+T: hg http://linuxtv.org/hg/v4l-dvb
S: Odd Fixes
F: drivers/media/pci/zoran/
diff --git a/Makefile b/Makefile
index 893d6f0e875b..00a933bb1f41 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 14
SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION =
NAME = Shuffling Zombie Juror
# *DOCUMENTATION*
@@ -605,10 +605,11 @@ endif
ifdef CONFIG_CC_STACKPROTECTOR_REGULAR
stackp-flag := -fstack-protector
ifeq ($(call cc-option, $(stackp-flag)),)
- $(warning Cannot use CONFIG_CC_STACKPROTECTOR: \
- -fstack-protector not supported by compiler))
+ $(warning Cannot use CONFIG_CC_STACKPROTECTOR_REGULAR: \
+ -fstack-protector not supported by compiler)
endif
-else ifdef CONFIG_CC_STACKPROTECTOR_STRONG
+else
+ifdef CONFIG_CC_STACKPROTECTOR_STRONG
stackp-flag := -fstack-protector-strong
ifeq ($(call cc-option, $(stackp-flag)),)
$(warning Cannot use CONFIG_CC_STACKPROTECTOR_STRONG: \
@@ -618,6 +619,7 @@ else
# Force off for distro compilers that enable stack protector by default.
stackp-flag := $(call cc-option, -fno-stack-protector)
endif
+endif
KBUILD_CFLAGS += $(stackp-flag)
# This warning generated too much noise in a regular build.
@@ -727,6 +729,13 @@ export KBUILD_IMAGE ?= vmlinux
export INSTALL_PATH ?= /boot
#
+# INSTALL_DTBS_PATH specifies a prefix for relocations required by build roots.
+# Like INSTALL_MOD_PATH, it isn't defined in the Makefile, but can be passed as
+# an argument if needed. Otherwise it defaults to the kernel install path
+#
+export INSTALL_DTBS_PATH ?= $(INSTALL_PATH)/dtbs/$(KERNELRELEASE)
+
+#
# INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
# relocations required by build roots. This is not defined in the
# makefile but the argument can be passed to make if needed.
diff --git a/arch/alpha/include/asm/Kbuild b/arch/alpha/include/asm/Kbuild
index a73a8e208a4a..96e54bed5088 100644
--- a/arch/alpha/include/asm/Kbuild
+++ b/arch/alpha/include/asm/Kbuild
@@ -1,7 +1,9 @@
-generic-y += clkdev.h
+generic-y += clkdev.h
+generic-y += cputime.h
generic-y += exec.h
-generic-y += trace_clock.h
-generic-y += preempt.h
generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
+generic-y += trace_clock.h
diff --git a/arch/alpha/include/asm/cputime.h b/arch/alpha/include/asm/cputime.h
deleted file mode 100644
index 19577fd93230..000000000000
--- a/arch/alpha/include/asm/cputime.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ALPHA_CPUTIME_H
-#define __ALPHA_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __ALPHA_CPUTIME_H */
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index edb4e0097b75..076c35cd6cde 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -254,12 +254,6 @@ void pcibios_fixup_bus(struct pci_bus *bus)
}
}
-int
-pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- return pci_enable_resources(dev, mask);
-}
-
/*
* If we set up a device for bus mastering, we need to check the latency
* timer as certain firmware forgets to set it properly, as seen
diff --git a/arch/arc/include/asm/Kbuild b/arch/arc/include/asm/Kbuild
index 0d3362991c31..e76fd79f32b0 100644
--- a/arch/arc/include/asm/Kbuild
+++ b/arch/arc/include/asm/Kbuild
@@ -1,15 +1,15 @@
generic-y += auxvec.h
generic-y += barrier.h
-generic-y += bugs.h
generic-y += bitsperlong.h
+generic-y += bugs.h
generic-y += clkdev.h
generic-y += cputime.h
generic-y += device.h
generic-y += div64.h
generic-y += emergency-restart.h
generic-y += errno.h
-generic-y += fcntl.h
generic-y += fb.h
+generic-y += fcntl.h
generic-y += ftrace.h
generic-y += hardirq.h
generic-y += hash.h
@@ -22,6 +22,7 @@ generic-y += kmap_types.h
generic-y += kvm_para.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += msgbuf.h
generic-y += param.h
@@ -30,6 +31,7 @@ generic-y += pci.h
generic-y += percpu.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sembuf.h
@@ -48,4 +50,3 @@ generic-y += ucontext.h
generic-y += user.h
generic-y += vga.h
generic-y += xor.h
-generic-y += preempt.h
diff --git a/arch/arc/mm/cache_arc700.c b/arch/arc/mm/cache_arc700.c
index 6b58c1de7577..400c663b21c2 100644
--- a/arch/arc/mm/cache_arc700.c
+++ b/arch/arc/mm/cache_arc700.c
@@ -282,7 +282,7 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr,
#else
/* if V-P const for loop, PTAG can be written once outside loop */
if (full_page_op)
- write_aux_reg(ARC_REG_DC_PTAG, paddr);
+ write_aux_reg(aux_tag, paddr);
#endif
while (num_lines-- > 0) {
@@ -296,7 +296,7 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr,
write_aux_reg(aux_cmd, vaddr);
vaddr += L1_CACHE_BYTES;
#else
- write_aux_reg(aux, paddr);
+ write_aux_reg(aux_cmd, paddr);
paddr += L1_CACHE_BYTES;
#endif
}
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e25419817791..503da0a2a8ea 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -534,7 +534,6 @@ config ARCH_DOVE
select PINCTRL
select PINCTRL_DOVE
select PLAT_ORION_LEGACY
- select USB_ARCH_HAS_EHCI
help
Support for the Marvell Dove SoC 88AP510
@@ -633,7 +632,6 @@ config ARCH_LPC32XX
select GENERIC_CLOCKEVENTS
select HAVE_IDE
select HAVE_PWM
- select USB_ARCH_HAS_OHCI
select USE_OF
help
Support for the NXP LPC32XX family of processors
@@ -770,7 +768,6 @@ config ARCH_S3C64XX
select SAMSUNG_ATAGS
select SAMSUNG_WAKEMASK
select SAMSUNG_WDT_RESET
- select USB_ARCH_HAS_OHCI
help
Samsung S3C64XX series based systems
@@ -1578,6 +1575,7 @@ config BL_SWITCHER_DUMMY_IF
choice
prompt "Memory split"
+ depends on MMU
default VMSPLIT_3G
help
Select the desired split between kernel and user memory.
@@ -1595,6 +1593,7 @@ endchoice
config PAGE_OFFSET
hex
+ default PHYS_OFFSET if !MMU
default 0x40000000 if VMSPLIT_1G
default 0x80000000 if VMSPLIT_2G
default 0xC0000000
@@ -1903,6 +1902,7 @@ config XEN
depends on ARM && AEABI && OF
depends on CPU_V7 && !CPU_V6
depends on !GENERIC_ATOMIC64
+ depends on MMU
select ARM_PSCI
select SWIOTLB_XEN
select ARCH_DMA_ADDR_T_64BIT
@@ -1918,6 +1918,7 @@ config USE_OF
select IRQ_DOMAIN
select OF
select OF_EARLY_FLATTREE
+ select OF_RESERVED_MEM
help
Include support for flattened device tree machine descriptions.
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 08a9ef58d9c3..fddf4beaee45 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -310,9 +310,9 @@ $(INSTALL_TARGETS):
%.dtb: | scripts
$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $(boot)/dts/$@
-PHONY += dtbs
-dtbs: scripts
- $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) dtbs
+PHONY += dtbs dtbs_install
+dtbs dtbs_install: prepare scripts
+ $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $@
# We use MRPROPER_FILES and CLEAN_FILES now
archclean:
@@ -331,6 +331,7 @@ define archhelp
echo ' bootpImage - Combined zImage and initial RAM disk'
echo ' (supply initrd image via make variable INITRD=<path>)'
echo '* dtbs - Build device tree blobs for enabled boards'
+ echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)'
echo ' install - Install uncompressed kernel'
echo ' zinstall - Install compressed kernel'
echo ' uinstall - Install U-Boot wrapped compressed kernel'
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore
index 47279aa96a6a..0714e0334e33 100644
--- a/arch/arm/boot/compressed/.gitignore
+++ b/arch/arm/boot/compressed/.gitignore
@@ -1,4 +1,5 @@
ashldi3.S
+bswapsdi2.S
font.c
lib1funcs.S
hyp-stub.S
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 6d1e43d46187..d3cb0126a102 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -209,7 +209,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
omap3-n900.dtb \
omap3-n9.dtb \
omap3-n950.dtb \
- omap3-tobi.dtb \
+ omap3-overo-tobi.dtb \
+ omap3-overo-storm-tobi.dtb \
omap3-gta04.dtb \
omap3-igep0020.dtb \
omap3-igep0030.dtb \
@@ -322,7 +323,7 @@ dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb \
zynq-zc706.dtb \
zynq-zed.dtb
-targets += dtbs
+targets += dtbs dtbs_install
targets += $(dtb-y)
endif
@@ -332,3 +333,5 @@ dtbs: $(addprefix $(obj)/, $(dtb-y))
$(Q)rm -f $(obj)/../*.dtb
clean-files := *.dtb
+
+dtbs_install: $(addsuffix _dtbinst_, $(dtb-y))
diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 4718ec4a4dbf..486880b74831 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -121,7 +121,7 @@
ti,model = "AM335x-EVMSK";
ti,audio-codec = <&tlv320aic3106>;
ti,mcasp-controller = <&mcasp1>;
- ti,codec-clock-rate = <24576000>;
+ ti,codec-clock-rate = <24000000>;
ti,audio-routing =
"Headphone Jack", "HPLOUT",
"Headphone Jack", "HPROUT";
@@ -256,6 +256,12 @@
>;
};
+ mmc1_pins: pinmux_mmc1_pins {
+ pinctrl-single,pins = <
+ 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+ >;
+ };
+
mcasp1_pins: mcasp1_pins {
pinctrl-single,pins = <
0x10c (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
@@ -456,6 +462,9 @@
status = "okay";
vmmc-supply = <&vmmc_reg>;
bus-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
};
&sham {
diff --git a/arch/arm/boot/dts/armada-xp-mv78260.dtsi b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
index 66609684d41b..9480cf891f8c 100644
--- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
@@ -23,6 +23,7 @@
gpio0 = &gpio0;
gpio1 = &gpio1;
gpio2 = &gpio2;
+ eth3 = &eth3;
};
cpus {
@@ -291,7 +292,7 @@
interrupts = <91>;
};
- ethernet@34000 {
+ eth3: ethernet@34000 {
compatible = "marvell,armada-370-neta";
reg = <0x34000 0x4000>;
interrupts = <14>;
diff --git a/arch/arm/boot/dts/atlas6.dtsi b/arch/arm/boot/dts/atlas6.dtsi
index f8674bcc4489..0c81dc945aed 100644
--- a/arch/arm/boot/dts/atlas6.dtsi
+++ b/arch/arm/boot/dts/atlas6.dtsi
@@ -217,8 +217,8 @@
interrupts = <17>;
fifosize = <128>;
clocks = <&clks 13>;
- sirf,uart-dma-rx-channel = <21>;
- sirf,uart-dma-tx-channel = <2>;
+ dmas = <&dmac1 5>, <&dmac0 2>;
+ dma-names = "rx", "tx";
};
uart1: uart@b0060000 {
@@ -228,6 +228,7 @@
interrupts = <18>;
fifosize = <32>;
clocks = <&clks 14>;
+ dma-names = "no-rx", "no-tx";
};
uart2: uart@b0070000 {
@@ -237,8 +238,8 @@
interrupts = <19>;
fifosize = <128>;
clocks = <&clks 15>;
- sirf,uart-dma-rx-channel = <6>;
- sirf,uart-dma-tx-channel = <7>;
+ dmas = <&dmac0 6>, <&dmac0 7>;
+ dma-names = "rx", "tx";
};
usp0: usp@b0080000 {
@@ -248,8 +249,8 @@
interrupts = <20>;
fifosize = <128>;
clocks = <&clks 28>;
- sirf,usp-dma-rx-channel = <17>;
- sirf,usp-dma-tx-channel = <18>;
+ dmas = <&dmac1 1>, <&dmac1 2>;
+ dma-names = "rx", "tx";
};
usp1: usp@b0090000 {
@@ -259,8 +260,8 @@
interrupts = <21>;
fifosize = <128>;
clocks = <&clks 29>;
- sirf,usp-dma-rx-channel = <14>;
- sirf,usp-dma-tx-channel = <15>;
+ dmas = <&dmac0 14>, <&dmac0 15>;
+ dma-names = "rx", "tx";
};
dmac0: dma-controller@b00b0000 {
diff --git a/arch/arm/boot/dts/bcm11351.dtsi b/arch/arm/boot/dts/bcm11351.dtsi
index e491b82f8d67..792fde1b7f75 100644
--- a/arch/arm/boot/dts/bcm11351.dtsi
+++ b/arch/arm/boot/dts/bcm11351.dtsi
@@ -147,7 +147,7 @@
};
pinctrl@35004800 {
- compatible = "brcm,capri-pinctrl";
+ compatible = "brcm,bcm11351-pinctrl";
reg = <0x35004800 0x430>;
};
diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi
index 2b76524f4aa7..187fd46b7b5e 100644
--- a/arch/arm/boot/dts/dove.dtsi
+++ b/arch/arm/boot/dts/dove.dtsi
@@ -379,15 +379,6 @@
#clock-cells = <1>;
};
- pmu_intc: pmu-interrupt-ctrl@d0050 {
- compatible = "marvell,dove-pmu-intc";
- interrupt-controller;
- #interrupt-cells = <1>;
- reg = <0xd0050 0x8>;
- interrupts = <33>;
- marvell,#interrupts = <7>;
- };
-
pinctrl: pin-ctrl@d0200 {
compatible = "marvell,dove-pinctrl";
reg = <0xd0200 0x10>;
@@ -610,8 +601,6 @@
rtc: real-time-clock@d8500 {
compatible = "marvell,orion-rtc";
reg = <0xd8500 0x20>;
- interrupt-parent = <&pmu_intc>;
- interrupts = <5>;
};
gpio2: gpio-ctrl@e8400 {
diff --git a/arch/arm/boot/dts/imx51-apf51dev.dts b/arch/arm/boot/dts/imx51-apf51dev.dts
index 5a7f552786a1..d3f98141462c 100644
--- a/arch/arm/boot/dts/imx51-apf51dev.dts
+++ b/arch/arm/boot/dts/imx51-apf51dev.dts
@@ -18,7 +18,6 @@
display@di1 {
compatible = "fsl,imx-parallel-display";
- crtcs = <&ipu 0>;
interface-pix-fmt = "bgr666";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu_disp1_1>;
@@ -41,6 +40,12 @@
pixelclk-active = <0>;
};
};
+
+ port {
+ display_in: endpoint {
+ remote-endpoint = <&ipu_di0_disp0>;
+ };
+ };
};
gpio-keys {
@@ -122,3 +127,7 @@
};
};
};
+
+&ipu_di0_disp0 {
+ remote-endpoint = <&display_in>;
+};
diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts
index be1407cf5abd..671927145632 100644
--- a/arch/arm/boot/dts/imx51-babbage.dts
+++ b/arch/arm/boot/dts/imx51-babbage.dts
@@ -21,9 +21,8 @@
reg = <0x90000000 0x20000000>;
};
- display@di0 {
+ display0: display@di0 {
compatible = "fsl,imx-parallel-display";
- crtcs = <&ipu 0>;
interface-pix-fmt = "rgb24";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu_disp1_1>;
@@ -41,11 +40,16 @@
vsync-len = <10>;
};
};
+
+ port {
+ display0_in: endpoint {
+ remote-endpoint = <&ipu_di0_disp0>;
+ };
+ };
};
- display@di1 {
+ display1: display@di1 {
compatible = "fsl,imx-parallel-display";
- crtcs = <&ipu 1>;
interface-pix-fmt = "rgb565";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu_disp2_1>;
@@ -68,6 +72,12 @@
pixelclk-active = <0>;
};
};
+
+ port {
+ display1_in: endpoint {
+ remote-endpoint = <&ipu_di1_disp1>;
+ };
+ };
};
gpio-keys {
@@ -258,6 +268,14 @@
};
};
+&ipu_di0_disp0 {
+ remote-endpoint = <&display0_in>;
+};
+
+&ipu_di1_disp1 {
+ remote-endpoint = <&display1_in>;
+};
+
&ssi2 {
fsl,mode = "i2s-slave";
status = "okay";
diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi
index 4bcdd3ad15e5..28c96aada80b 100644
--- a/arch/arm/boot/dts/imx51.dtsi
+++ b/arch/arm/boot/dts/imx51.dtsi
@@ -79,6 +79,11 @@
};
};
+ display-subsystem {
+ compatible = "fsl,imx-display-subsystem";
+ ports = <&ipu_di0>, <&ipu_di1>;
+ };
+
soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -92,13 +97,28 @@
};
ipu: ipu@40000000 {
- #crtc-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
compatible = "fsl,imx51-ipu";
reg = <0x40000000 0x20000000>;
interrupts = <11 10>;
clocks = <&clks 59>, <&clks 110>, <&clks 61>;
clock-names = "bus", "di0", "di1";
resets = <&src 2>;
+
+ ipu_di0: port@2 {
+ reg = <2>;
+
+ ipu_di0_disp0: endpoint {
+ };
+ };
+
+ ipu_di1: port@3 {
+ reg = <3>;
+
+ ipu_di1_disp1: endpoint {
+ };
+ };
};
aips@70000000 { /* AIPS1 */
diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts
index 7d304d02ed38..0298adc73bb7 100644
--- a/arch/arm/boot/dts/imx53-m53evk.dts
+++ b/arch/arm/boot/dts/imx53-m53evk.dts
@@ -21,9 +21,8 @@
};
soc {
- display@di1 {
+ display1: display@di1 {
compatible = "fsl,imx-parallel-display";
- crtcs = <&ipu 1>;
interface-pix-fmt = "bgr666";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu_disp2_1>;
@@ -44,6 +43,12 @@
};
};
};
+
+ port {
+ display1_in: endpoint {
+ remote-endpoint = <&ipu_di1_disp1>;
+ };
+ };
};
backlight {
@@ -221,6 +226,10 @@
};
};
+&ipu_di1_disp1 {
+ remote-endpoint = <&display1_in>;
+};
+
&nfc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_nand_1>;
diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts
index a63090267941..a5b55c603591 100644
--- a/arch/arm/boot/dts/imx53-mba53.dts
+++ b/arch/arm/boot/dts/imx53-mba53.dts
@@ -38,9 +38,14 @@
compatible = "fsl,imx-parallel-display";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_disp1_1>;
- crtcs = <&ipu 1>;
interface-pix-fmt = "rgb24";
status = "disabled";
+
+ port {
+ display1_in: endpoint {
+ remote-endpoint = <&ipu_di1_disp1>;
+ };
+ };
};
reg_3p2v: 3p2v {
@@ -141,6 +146,10 @@
};
};
+&ipu_di1_disp1 {
+ remote-endpoint = <&display1_in>;
+};
+
&cspi {
status = "okay";
};
@@ -228,7 +237,7 @@
&tve {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_vga_sync_1>;
- ddc = <&i2c3>;
+ i2c-ddc-bus = <&i2c3>;
fsl,tve-mode = "vga";
fsl,hsync-pin = <4>;
fsl,vsync-pin = <6>;
diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts
index 91a5935a4aac..8b254289344f 100644
--- a/arch/arm/boot/dts/imx53-qsb.dts
+++ b/arch/arm/boot/dts/imx53-qsb.dts
@@ -21,9 +21,8 @@
reg = <0x70000000 0x40000000>;
};
- display@di0 {
+ display0: display@di0 {
compatible = "fsl,imx-parallel-display";
- crtcs = <&ipu 0>;
interface-pix-fmt = "rgb565";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu_disp0_1>;
@@ -46,6 +45,12 @@
pixelclk-active = <0>;
};
};
+
+ port {
+ display0_in: endpoint {
+ remote-endpoint = <&ipu_di0_disp0>;
+ };
+ };
};
gpio-keys {
@@ -126,6 +131,10 @@
status = "okay";
};
+&ipu_di0_disp0 {
+ remote-endpoint = <&display0_in>;
+};
+
&ssi2 {
fsl,mode = "i2s-slave";
status = "okay";
diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index 4307e80b2d2e..04d3127edfe1 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -45,6 +45,11 @@
};
};
+ display-subsystem {
+ compatible = "fsl,imx-display-subsystem";
+ ports = <&ipu_di0>, <&ipu_di1>;
+ };
+
tzic: tz-interrupt-controller@0fffc000 {
compatible = "fsl,imx53-tzic", "fsl,tzic";
interrupt-controller;
@@ -85,13 +90,49 @@
ranges;
ipu: ipu@18000000 {
- #crtc-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
compatible = "fsl,imx53-ipu";
reg = <0x18000000 0x080000000>;
interrupts = <11 10>;
clocks = <&clks 59>, <&clks 110>, <&clks 61>;
clock-names = "bus", "di0", "di1";
resets = <&src 2>;
+
+ ipu_di0: port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ ipu_di0_disp0: endpoint@0 {
+ reg = <0>;
+ };
+
+ ipu_di0_lvds0: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&lvds0_in>;
+ };
+ };
+
+ ipu_di1: port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ ipu_di1_disp1: endpoint@0 {
+ reg = <0>;
+ };
+
+ ipu_di1_lvds1: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&lvds1_in>;
+ };
+
+ ipu_di1_tve: endpoint@2 {
+ reg = <2>;
+ remote-endpoint = <&tve_in>;
+ };
+ };
};
aips@50000000 { /* AIPS1 */
@@ -838,14 +879,24 @@
lvds-channel@0 {
reg = <0>;
- crtcs = <&ipu 0>;
status = "disabled";
+
+ port {
+ lvds0_in: endpoint {
+ remote-endpoint = <&ipu_di0_lvds0>;
+ };
+ };
};
lvds-channel@1 {
reg = <1>;
- crtcs = <&ipu 1>;
status = "disabled";
+
+ port {
+ lvds1_in: endpoint {
+ remote-endpoint = <&ipu_di0_lvds0>;
+ };
+ };
};
};
@@ -1103,8 +1154,13 @@
interrupts = <92>;
clocks = <&clks 69>, <&clks 116>;
clock-names = "tve", "di_sel";
- crtcs = <&ipu 1>;
status = "disabled";
+
+ port {
+ tve_in: endpoint {
+ remote-endpoint = <&ipu_di1_tve>;
+ };
+ };
};
vpu: vpu@63ff4000 {
diff --git a/arch/arm/boot/dts/imx6dl-hummingboard.dts b/arch/arm/boot/dts/imx6dl-hummingboard.dts
index fd8fc7cd53f3..5bfae54fb780 100644
--- a/arch/arm/boot/dts/imx6dl-hummingboard.dts
+++ b/arch/arm/boot/dts/imx6dl-hummingboard.dts
@@ -52,12 +52,6 @@
};
};
- codec: spdif-transmitter {
- compatible = "linux,spdif-dit";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_hummingboard_spdif>;
- };
-
sound-spdif {
compatible = "fsl,imx-audio-spdif";
model = "imx-spdif";
@@ -111,7 +105,7 @@
};
pinctrl_hummingboard_spdif: hummingboard-spdif {
- fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0>;
+ fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
};
pinctrl_hummingboard_usbh1_vbus: hummingboard-usbh1-vbus {
@@ -142,6 +136,8 @@
};
&spdif {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_hummingboard_spdif>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 9e8ae118fdd4..25bbdd6f214b 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -70,6 +70,15 @@
};
};
};
+
+ display-subsystem {
+ compatible = "fsl,imx-display-subsystem";
+ ports = <&ipu1_di0>, <&ipu1_di1>;
+ };
+};
+
+&hdmi {
+ compatible = "fsl,imx6dl-hdmi";
};
&ldb {
@@ -79,12 +88,4 @@
clock-names = "di0_pll", "di1_pll",
"di0_sel", "di1_sel",
"di0", "di1";
-
- lvds-channel@0 {
- crtcs = <&ipu1 0>, <&ipu1 1>;
- };
-
- lvds-channel@1 {
- crtcs = <&ipu1 0>, <&ipu1 1>;
- };
};
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index f024ef28b34b..2a8d9de666c9 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -132,13 +132,84 @@
};
ipu2: ipu@02800000 {
- #crtc-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
compatible = "fsl,imx6q-ipu";
reg = <0x02800000 0x400000>;
interrupts = <0 8 0x4 0 7 0x4>;
clocks = <&clks 133>, <&clks 134>, <&clks 137>;
clock-names = "bus", "di0", "di1";
resets = <&src 4>;
+
+ ipu2_di0: port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ ipu2_di0_disp0: endpoint@0 {
+ };
+
+ ipu2_di0_hdmi: endpoint@1 {
+ remote-endpoint = <&hdmi_mux_2>;
+ };
+
+ ipu2_di0_mipi: endpoint@2 {
+ };
+
+ ipu2_di0_lvds0: endpoint@3 {
+ remote-endpoint = <&lvds0_mux_2>;
+ };
+
+ ipu2_di0_lvds1: endpoint@4 {
+ remote-endpoint = <&lvds1_mux_2>;
+ };
+ };
+
+ ipu2_di1: port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ ipu2_di1_hdmi: endpoint@1 {
+ remote-endpoint = <&hdmi_mux_3>;
+ };
+
+ ipu2_di1_mipi: endpoint@2 {
+ };
+
+ ipu2_di1_lvds0: endpoint@3 {
+ remote-endpoint = <&lvds0_mux_3>;
+ };
+
+ ipu2_di1_lvds1: endpoint@4 {
+ remote-endpoint = <&lvds1_mux_3>;
+ };
+ };
+ };
+ };
+
+ display-subsystem {
+ compatible = "fsl,imx-display-subsystem";
+ ports = <&ipu1_di0>, <&ipu1_di1>, <&ipu2_di0>, <&ipu2_di1>;
+ };
+};
+
+&hdmi {
+ compatible = "fsl,imx6q-hdmi";
+
+ port@2 {
+ reg = <2>;
+
+ hdmi_mux_2: endpoint {
+ remote-endpoint = <&ipu2_di0_hdmi>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+
+ hdmi_mux_3: endpoint {
+ remote-endpoint = <&ipu2_di1_hdmi>;
};
};
};
@@ -152,10 +223,56 @@
"di0", "di1";
lvds-channel@0 {
- crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+ port@2 {
+ reg = <2>;
+
+ lvds0_mux_2: endpoint {
+ remote-endpoint = <&ipu2_di0_lvds0>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+
+ lvds0_mux_3: endpoint {
+ remote-endpoint = <&ipu2_di1_lvds0>;
+ };
+ };
};
lvds-channel@1 {
- crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+ port@2 {
+ reg = <2>;
+
+ lvds1_mux_2: endpoint {
+ remote-endpoint = <&ipu2_di0_lvds1>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+
+ lvds1_mux_3: endpoint {
+ remote-endpoint = <&ipu2_di1_lvds1>;
+ };
+ };
+ };
+};
+
+&mipi_dsi {
+ port@2 {
+ reg = <2>;
+
+ mipi_mux_2: endpoint {
+ remote-endpoint = <&ipu2_di0_mipi>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+
+ mipi_mux_3: endpoint {
+ remote-endpoint = <&ipu2_di1_mipi>;
+ };
};
};
diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
index 64daa3b311f6..c2a24888a276 100644
--- a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
@@ -46,12 +46,6 @@
};
};
- codec: spdif-transmitter {
- compatible = "linux,spdif-dit";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_cubox_i_spdif>;
- };
-
sound-spdif {
compatible = "fsl,imx-audio-spdif";
model = "imx-spdif";
@@ -89,7 +83,7 @@
};
pinctrl_cubox_i_spdif: cubox-i-spdif {
- fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0>;
+ fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
};
pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbus {
@@ -121,6 +115,8 @@
};
&spdif {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_cubox_i_spdif>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index fb28b2ecb1db..64a8cbe9480f 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1358,13 +1358,76 @@
status = "disabled";
lvds-channel@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
reg = <0>;
status = "disabled";
+
+ port@0 {
+ reg = <0>;
+
+ lvds0_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_lvds0>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ lvds0_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_lvds0>;
+ };
+ };
};
lvds-channel@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
reg = <1>;
status = "disabled";
+
+ port@0 {
+ reg = <0>;
+
+ lvds1_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_lvds1>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ lvds1_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_lvds1>;
+ };
+ };
+ };
+ };
+
+ hdmi: hdmi@0120000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x00120000 0x9000>;
+ interrupts = <0 115 0x04>;
+ gpr = <&gpr>;
+ clocks = <&clks 123>, <&clks 124>;
+ clock-names = "iahb", "isfr";
+ status = "disabled";
+
+ port@0 {
+ reg = <0>;
+
+ hdmi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_hdmi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ hdmi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_hdmi>;
+ };
};
};
@@ -1579,8 +1642,27 @@
reg = <0x021dc000 0x4000>;
};
- mipi@021e0000 { /* MIPI-DSI */
+ mipi_dsi: mipi@021e0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
reg = <0x021e0000 0x4000>;
+ status = "disabled";
+
+ port@0 {
+ reg = <0>;
+
+ mipi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_mipi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ mipi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_mipi>;
+ };
+ };
};
vdoa@021e4000 {
@@ -1634,13 +1716,64 @@
};
ipu1: ipu@02400000 {
- #crtc-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
compatible = "fsl,imx6q-ipu";
reg = <0x02400000 0x400000>;
interrupts = <0 6 0x4 0 5 0x4>;
clocks = <&clks 130>, <&clks 131>, <&clks 132>;
clock-names = "bus", "di0", "di1";
resets = <&src 2>;
+
+ ipu1_di0: port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ ipu1_di0_disp0: endpoint@0 {
+ };
+
+ ipu1_di0_hdmi: endpoint@1 {
+ remote-endpoint = <&hdmi_mux_0>;
+ };
+
+ ipu1_di0_mipi: endpoint@2 {
+ remote-endpoint = <&mipi_mux_0>;
+ };
+
+ ipu1_di0_lvds0: endpoint@3 {
+ remote-endpoint = <&lvds0_mux_0>;
+ };
+
+ ipu1_di0_lvds1: endpoint@4 {
+ remote-endpoint = <&lvds1_mux_0>;
+ };
+ };
+
+ ipu1_di1: port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ ipu1_di0_disp1: endpoint@0 {
+ };
+
+ ipu1_di1_hdmi: endpoint@1 {
+ remote-endpoint = <&hdmi_mux_1>;
+ };
+
+ ipu1_di1_mipi: endpoint@2 {
+ remote-endpoint = <&mipi_mux_1>;
+ };
+
+ ipu1_di1_lvds0: endpoint@3 {
+ remote-endpoint = <&lvds0_mux_1>;
+ };
+
+ ipu1_di1_lvds1: endpoint@4 {
+ remote-endpoint = <&lvds1_mux_1>;
+ };
+ };
};
};
};
diff --git a/arch/arm/boot/dts/keystone-clocks.dtsi b/arch/arm/boot/dts/keystone-clocks.dtsi
index 2363593e1050..ef58d1c24313 100644
--- a/arch/arm/boot/dts/keystone-clocks.dtsi
+++ b/arch/arm/boot/dts/keystone-clocks.dtsi
@@ -612,7 +612,7 @@ clocks {
compatible = "ti,keystone,psc-clock";
clocks = <&chipclk13>;
clock-output-names = "vcp-3";
- reg = <0x0235000a8 0xb00>, <0x02350060 0x400>;
+ reg = <0x023500a8 0xb00>, <0x02350060 0x400>;
reg-names = "control", "domain";
domain-id = <24>;
};
diff --git a/arch/arm/boot/dts/omap3-gta04.dts b/arch/arm/boot/dts/omap3-gta04.dts
index b9b55c95a566..d3b253bbc885 100644
--- a/arch/arm/boot/dts/omap3-gta04.dts
+++ b/arch/arm/boot/dts/omap3-gta04.dts
@@ -13,7 +13,7 @@
/ {
model = "OMAP3 GTA04";
- compatible = "ti,omap3-gta04", "ti,omap3";
+ compatible = "ti,omap3-gta04", "ti,omap36xx", "ti,omap3";
cpus {
cpu@0 {
@@ -32,7 +32,7 @@
aux-button {
label = "aux";
linux,code = <169>;
- gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
+ gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
gpio-key,wakeup;
};
};
@@ -92,6 +92,8 @@
bmp085@77 {
compatible = "bosch,bmp085";
reg = <0x77>;
+ interrupt-parent = <&gpio4>;
+ interrupts = <17 IRQ_TYPE_EDGE_RISING>;
};
/* leds */
@@ -141,8 +143,8 @@
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins>;
vmmc-supply = <&vmmc1>;
- vmmc_aux-supply = <&vsim>;
bus-width = <4>;
+ ti,non-removable;
};
&mmc2 {
diff --git a/arch/arm/boot/dts/omap3-igep0020.dts b/arch/arm/boot/dts/omap3-igep0020.dts
index 25a2b5f652fd..f2779ac75872 100644
--- a/arch/arm/boot/dts/omap3-igep0020.dts
+++ b/arch/arm/boot/dts/omap3-igep0020.dts
@@ -14,7 +14,7 @@
/ {
model = "IGEPv2 (TI OMAP AM/DM37x)";
- compatible = "isee,omap3-igep0020", "ti,omap3";
+ compatible = "isee,omap3-igep0020", "ti,omap36xx", "ti,omap3";
leds {
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/omap3-igep0030.dts b/arch/arm/boot/dts/omap3-igep0030.dts
index 145c58cfc8ac..2793749eb1ba 100644
--- a/arch/arm/boot/dts/omap3-igep0030.dts
+++ b/arch/arm/boot/dts/omap3-igep0030.dts
@@ -13,7 +13,7 @@
/ {
model = "IGEP COM MODULE (TI OMAP AM/DM37x)";
- compatible = "isee,omap3-igep0030", "ti,omap3";
+ compatible = "isee,omap3-igep0030", "ti,omap36xx", "ti,omap3";
leds {
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/omap3-n9.dts b/arch/arm/boot/dts/omap3-n9.dts
index 39828ce464ee..9938b5dc1909 100644
--- a/arch/arm/boot/dts/omap3-n9.dts
+++ b/arch/arm/boot/dts/omap3-n9.dts
@@ -14,5 +14,5 @@
/ {
model = "Nokia N9";
- compatible = "nokia,omap3-n9", "ti,omap3";
+ compatible = "nokia,omap3-n9", "ti,omap36xx", "ti,omap3";
};
diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index 6fc85f963530..0bf40c90faba 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2013 Pavel Machek <pavel@ucw.cz>
- * Copyright 2013 Aaro Koskinen <aaro.koskinen@iki.fi>
+ * Copyright (C) 2013-2014 Aaro Koskinen <aaro.koskinen@iki.fi>
*
* 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
@@ -13,7 +13,7 @@
/ {
model = "Nokia N900";
- compatible = "nokia,omap3-n900", "ti,omap3";
+ compatible = "nokia,omap3-n900", "ti,omap3430", "ti,omap3";
cpus {
cpu@0 {
diff --git a/arch/arm/boot/dts/omap3-n950.dts b/arch/arm/boot/dts/omap3-n950.dts
index b076a526b999..261c5589bfa3 100644
--- a/arch/arm/boot/dts/omap3-n950.dts
+++ b/arch/arm/boot/dts/omap3-n950.dts
@@ -14,5 +14,5 @@
/ {
model = "Nokia N950";
- compatible = "nokia,omap3-n950", "ti,omap3";
+ compatible = "nokia,omap3-n950", "ti,omap36xx", "ti,omap3";
};
diff --git a/arch/arm/boot/dts/omap3-overo-storm-tobi.dts b/arch/arm/boot/dts/omap3-overo-storm-tobi.dts
new file mode 100644
index 000000000000..966b5c9cd96a
--- /dev/null
+++ b/arch/arm/boot/dts/omap3-overo-storm-tobi.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
+ *
+ * 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.
+ */
+
+/*
+ * Tobi expansion board is manufactured by Gumstix Inc.
+ */
+
+/dts-v1/;
+
+#include "omap36xx.dtsi"
+#include "omap3-overo-tobi-common.dtsi"
+
+/ {
+ model = "OMAP36xx/AM37xx/DM37xx Gumstix Overo on Tobi";
+ compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap36xx", "ti,omap3";
+};
+
diff --git a/arch/arm/boot/dts/omap3-tobi.dts b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi
index 7e4ad2aec37a..4edc013a91c1 100644
--- a/arch/arm/boot/dts/omap3-tobi.dts
+++ b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi
@@ -13,9 +13,6 @@
#include "omap3-overo.dtsi"
/ {
- model = "TI OMAP3 Gumstix Overo on Tobi";
- compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3";
-
leds {
compatible = "gpio-leds";
heartbeat {
diff --git a/arch/arm/boot/dts/omap3-overo-tobi.dts b/arch/arm/boot/dts/omap3-overo-tobi.dts
new file mode 100644
index 000000000000..de5653e1b5ca
--- /dev/null
+++ b/arch/arm/boot/dts/omap3-overo-tobi.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
+ *
+ * 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.
+ */
+
+/*
+ * Tobi expansion board is manufactured by Gumstix Inc.
+ */
+
+/dts-v1/;
+
+#include "omap34xx.dtsi"
+#include "omap3-overo-tobi-common.dtsi"
+
+/ {
+ model = "OMAP35xx Gumstix Overo on Tobi";
+ compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3430", "ti,omap3";
+};
+
diff --git a/arch/arm/boot/dts/omap3-overo.dtsi b/arch/arm/boot/dts/omap3-overo.dtsi
index a461d2fd1fb0..597099907f8e 100644
--- a/arch/arm/boot/dts/omap3-overo.dtsi
+++ b/arch/arm/boot/dts/omap3-overo.dtsi
@@ -9,9 +9,6 @@
/*
* The Gumstix Overo must be combined with an expansion board.
*/
-/dts-v1/;
-
-#include "omap34xx.dtsi"
/ {
pwmleds {
diff --git a/arch/arm/boot/dts/prima2.dtsi b/arch/arm/boot/dts/prima2.dtsi
index 0e219932d7cc..8582ae41a583 100644
--- a/arch/arm/boot/dts/prima2.dtsi
+++ b/arch/arm/boot/dts/prima2.dtsi
@@ -223,8 +223,8 @@
interrupts = <17>;
fifosize = <128>;
clocks = <&clks 13>;
- sirf,uart-dma-rx-channel = <21>;
- sirf,uart-dma-tx-channel = <2>;
+ dmas = <&dmac1 5>, <&dmac0 2>;
+ dma-names = "rx", "tx";
};
uart1: uart@b0060000 {
@@ -243,8 +243,8 @@
interrupts = <19>;
fifosize = <128>;
clocks = <&clks 15>;
- sirf,uart-dma-rx-channel = <6>;
- sirf,uart-dma-tx-channel = <7>;
+ dmas = <&dmac0 6>, <&dmac0 7>;
+ dma-names = "rx", "tx";
};
usp0: usp@b0080000 {
@@ -254,8 +254,8 @@
interrupts = <20>;
fifosize = <128>;
clocks = <&clks 28>;
- sirf,usp-dma-rx-channel = <17>;
- sirf,usp-dma-tx-channel = <18>;
+ dmas = <&dmac1 1>, <&dmac1 2>;
+ dma-names = "rx", "tx";
};
usp1: usp@b0090000 {
@@ -265,8 +265,8 @@
interrupts = <21>;
fifosize = <128>;
clocks = <&clks 29>;
- sirf,usp-dma-rx-channel = <14>;
- sirf,usp-dma-tx-channel = <15>;
+ dmas = <&dmac0 14>, <&dmac0 15>;
+ dma-names = "rx", "tx";
};
usp2: usp@b00a0000 {
@@ -276,8 +276,8 @@
interrupts = <22>;
fifosize = <128>;
clocks = <&clks 30>;
- sirf,usp-dma-rx-channel = <10>;
- sirf,usp-dma-tx-channel = <11>;
+ dmas = <&dmac0 10>, <&dmac0 11>;
+ dma-names = "rx", "tx";
};
dmac0: dma-controller@b00b0000 {
diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index 19c65509a22d..3b075dd19b51 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -429,7 +429,7 @@
R8A7791_CLK_MSIOF1 R8A7791_CLK_SCIFB2
>;
clock-output-names =
- "scifa2", "scifa1", "scifa0", "misof2", "scifb0",
+ "scifa2", "scifa1", "scifa0", "msiof2", "scifb0",
"scifb1", "msiof1", "scifb2";
};
mstp3_clks: mstp3_clks@e615013c {
diff --git a/arch/arm/boot/dts/sama5d36.dtsi b/arch/arm/boot/dts/sama5d36.dtsi
index 6c31c26e6cc0..db58cad6acd3 100644
--- a/arch/arm/boot/dts/sama5d36.dtsi
+++ b/arch/arm/boot/dts/sama5d36.dtsi
@@ -8,8 +8,8 @@
*/
#include "sama5d3.dtsi"
#include "sama5d3_can.dtsi"
-#include "sama5d3_emac.dtsi"
#include "sama5d3_gmac.dtsi"
+#include "sama5d3_emac.dtsi"
#include "sama5d3_lcd.dtsi"
#include "sama5d3_mci2.dtsi"
#include "sama5d3_tcb1.dtsi"
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 10666ca8aee1..7753be0c86d7 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -331,7 +331,7 @@
};
intc: interrupt-controller@01c20400 {
- compatible = "allwinner,sun4i-ic";
+ compatible = "allwinner,sun4i-a10-ic";
reg = <0x01c20400 0x400>;
interrupt-controller;
#interrupt-cells = <1>;
@@ -403,7 +403,7 @@
};
timer@01c20c00 {
- compatible = "allwinner,sun4i-timer";
+ compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0x90>;
interrupts = <22>;
clocks = <&osc24M>;
@@ -421,12 +421,12 @@
};
sid: eeprom@01c23800 {
- compatible = "allwinner,sun4i-sid";
+ compatible = "allwinner,sun4i-a10-sid";
reg = <0x01c23800 0x10>;
};
rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-ts";
+ compatible = "allwinner,sun4i-a10-ts";
reg = <0x01c25000 0x100>;
interrupts = <29>;
};
diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index 64961595e8d6..ee17b1c379e3 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -294,7 +294,7 @@
};
intc: interrupt-controller@01c20400 {
- compatible = "allwinner,sun4i-ic";
+ compatible = "allwinner,sun4i-a10-ic";
reg = <0x01c20400 0x400>;
interrupt-controller;
#interrupt-cells = <1>;
@@ -366,7 +366,7 @@
};
timer@01c20c00 {
- compatible = "allwinner,sun4i-timer";
+ compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0x90>;
interrupts = <22>;
clocks = <&osc24M>;
@@ -378,12 +378,12 @@
};
sid: eeprom@01c23800 {
- compatible = "allwinner,sun4i-sid";
+ compatible = "allwinner,sun4i-a10-sid";
reg = <0x01c23800 0x10>;
};
rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-ts";
+ compatible = "allwinner,sun4i-a10-ts";
reg = <0x01c25000 0x100>;
interrupts = <29>;
};
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index 320335abfccd..3490ef9ec603 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -275,7 +275,7 @@
ranges;
intc: interrupt-controller@01c20400 {
- compatible = "allwinner,sun4i-ic";
+ compatible = "allwinner,sun4i-a10-ic";
reg = <0x01c20400 0x400>;
interrupt-controller;
#interrupt-cells = <1>;
@@ -329,7 +329,7 @@
};
timer@01c20c00 {
- compatible = "allwinner,sun4i-timer";
+ compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0x90>;
interrupts = <22>;
clocks = <&osc24M>;
@@ -341,12 +341,12 @@
};
sid: eeprom@01c23800 {
- compatible = "allwinner,sun4i-sid";
+ compatible = "allwinner,sun4i-a10-sid";
reg = <0x01c23800 0x10>;
};
rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-ts";
+ compatible = "allwinner,sun4i-a10-ts";
reg = <0x01c25000 0x100>;
interrupts = <29>;
};
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 5256ad9be52c..38d43febda4c 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -190,6 +190,14 @@
#size-cells = <1>;
ranges;
+ nmi_intc: interrupt-controller@01f00c0c {
+ compatible = "allwinner,sun6i-a31-sc-nmi";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x01f00c0c 0x38>;
+ interrupts = <0 32 4>;
+ };
+
pio: pinctrl@01c20800 {
compatible = "allwinner,sun6i-a31-pinctrl";
reg = <0x01c20800 0x400>;
@@ -231,7 +239,7 @@
};
timer@01c20c00 {
- compatible = "allwinner,sun4i-timer";
+ compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0xa0>;
interrupts = <0 18 4>,
<0 19 4>,
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 9ff09484847b..cadcf2f9881d 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -339,6 +339,14 @@
#size-cells = <1>;
ranges;
+ nmi_intc: interrupt-controller@01c00030 {
+ compatible = "allwinner,sun7i-a20-sc-nmi";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x01c00030 0x0c>;
+ interrupts = <0 0 4>;
+ };
+
emac: ethernet@01c0b000 {
compatible = "allwinner,sun4i-a10-emac";
reg = <0x01c0b000 0x1000>;
@@ -435,7 +443,7 @@
};
timer@01c20c00 {
- compatible = "allwinner,sun4i-timer";
+ compatible = "allwinner,sun4i-a10-timer";
reg = <0x01c20c00 0x90>;
interrupts = <0 22 4>,
<0 23 4>,
@@ -454,7 +462,7 @@
rtc: rtc@01c20d00 {
compatible = "allwinner,sun7i-a20-rtc";
reg = <0x01c20d00 0x20>;
- interrupts = <0 24 1>;
+ interrupts = <0 24 4>;
};
sid: eeprom@01c23800 {
@@ -463,7 +471,7 @@
};
rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-ts";
+ compatible = "allwinner,sun4i-a10-ts";
reg = <0x01c25000 0x100>;
interrupts = <0 29 4>;
};
@@ -596,10 +604,10 @@
hstimer@01c60000 {
compatible = "allwinner,sun7i-a20-hstimer";
reg = <0x01c60000 0x1000>;
- interrupts = <0 81 1>,
- <0 82 1>,
- <0 83 1>,
- <0 84 1>;
+ interrupts = <0 81 4>,
+ <0 82 4>,
+ <0 83 4>,
+ <0 84 4>;
clocks = <&ahb_gates 28>;
};
diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
index 389e987ec281..44ec401ec366 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -57,6 +57,8 @@
resets = <&tegra_car 27>;
reset-names = "dc";
+ nvidia,head = <0>;
+
rgb {
status = "disabled";
};
@@ -72,6 +74,8 @@
resets = <&tegra_car 26>;
reset-names = "dc";
+ nvidia,head = <1>;
+
rgb {
status = "disabled";
};
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 480ecda3416b..48d2a7f4d0c0 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -94,6 +94,8 @@
resets = <&tegra_car 27>;
reset-names = "dc";
+ nvidia,head = <0>;
+
rgb {
status = "disabled";
};
@@ -109,6 +111,8 @@
resets = <&tegra_car 26>;
reset-names = "dc";
+ nvidia,head = <1>;
+
rgb {
status = "disabled";
};
diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi
index 9104224124ee..1e156d9d0506 100644
--- a/arch/arm/boot/dts/tegra30-cardhu.dtsi
+++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi
@@ -28,7 +28,7 @@
compatible = "nvidia,cardhu", "nvidia,tegra30";
aliases {
- rtc0 = "/i2c@7000d000/tps6586x@34";
+ rtc0 = "/i2c@7000d000/tps65911@2d";
rtc1 = "/rtc@7000e000";
};
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index ed8e7700b46d..19a84e933f4e 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -170,6 +170,8 @@
resets = <&tegra_car 27>;
reset-names = "dc";
+ nvidia,head = <0>;
+
rgb {
status = "disabled";
};
@@ -185,6 +187,8 @@
resets = <&tegra_car 26>;
reset-names = "dc";
+ nvidia,head = <1>;
+
rgb {
status = "disabled";
};
diff --git a/arch/arm/boot/dts/testcases/tests.dtsi b/arch/arm/boot/dts/testcases/tests.dtsi
deleted file mode 100644
index 3f123ecc9dd7..000000000000
--- a/arch/arm/boot/dts/testcases/tests.dtsi
+++ /dev/null
@@ -1,2 +0,0 @@
-/include/ "tests-phandle.dtsi"
-/include/ "tests-interrupts.dtsi"
diff --git a/arch/arm/boot/dts/versatile-pb.dts b/arch/arm/boot/dts/versatile-pb.dts
index f43907c40c93..65f657711323 100644
--- a/arch/arm/boot/dts/versatile-pb.dts
+++ b/arch/arm/boot/dts/versatile-pb.dts
@@ -1,4 +1,4 @@
-/include/ "versatile-ab.dts"
+#include <versatile-ab.dts>
/ {
model = "ARM Versatile PB";
@@ -47,4 +47,4 @@
};
};
-/include/ "testcases/tests.dtsi"
+#include <testcases.dtsi>
diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi
index 8b67b19392ec..789d0bacc110 100644
--- a/arch/arm/boot/dts/zynq-7000.dtsi
+++ b/arch/arm/boot/dts/zynq-7000.dtsi
@@ -24,6 +24,12 @@
device_type = "cpu";
reg = <0>;
clocks = <&clkc 3>;
+ operating-points = <
+ /* kHz uV */
+ 666667 1000000
+ 333334 1000000
+ 222223 1000000
+ >;
};
cpu@1 {
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index 00fe9e9710fd..27d69b558c5d 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -204,7 +204,10 @@ CONFIG_MMC_BLOCK_MINORS=16
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_ONESHOT=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild
index 3278afe2c3ab..23e728ecf8ab 100644
--- a/arch/arm/include/asm/Kbuild
+++ b/arch/arm/include/asm/Kbuild
@@ -7,16 +7,19 @@ generic-y += current.h
generic-y += emergency-restart.h
generic-y += errno.h
generic-y += exec.h
+generic-y += hash.h
generic-y += ioctl.h
generic-y += ipcbuf.h
generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += msgbuf.h
generic-y += param.h
generic-y += parport.h
generic-y += poll.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += sections.h
generic-y += segment.h
@@ -33,5 +36,3 @@ generic-y += termios.h
generic-y += timex.h
generic-y += trace_clock.h
generic-y += unaligned.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index e9a49fe0284e..8b8b61685a34 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -212,6 +212,7 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,
static inline void __flush_icache_all(void)
{
__flush_icache_preferred();
+ dsb();
}
/*
diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h
index a8c56acc8c98..eec0a12c5c1d 100644
--- a/arch/arm/include/asm/dma-iommu.h
+++ b/arch/arm/include/asm/dma-iommu.h
@@ -13,9 +13,12 @@ struct dma_iommu_mapping {
/* iommu specific data */
struct iommu_domain *domain;
- void *bitmap;
- size_t bits;
- unsigned int order;
+ unsigned long **bitmaps; /* array of bitmaps */
+ unsigned int nr_bitmaps; /* nr of elements in array */
+ unsigned int extensions;
+ size_t bitmap_size; /* size of a single bitmap */
+ size_t bits; /* per bitmap */
+ unsigned int size; /* per bitmap */
dma_addr_t base;
spinlock_t lock;
@@ -23,8 +26,7 @@ struct dma_iommu_mapping {
};
struct dma_iommu_mapping *
-arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size,
- int order);
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size);
void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
index 1d3153c7eb41..816db0bf2dd8 100644
--- a/arch/arm/include/asm/kvm_arm.h
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -55,6 +55,7 @@
* The bits we set in HCR:
* TAC: Trap ACTLR
* TSC: Trap SMC
+ * TVM: Trap VM ops (until MMU and caches are on)
* TSW: Trap cache operations by set/way
* TWI: Trap WFI
* TWE: Trap WFE
@@ -68,8 +69,7 @@
*/
#define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
- HCR_TWE | HCR_SWIO | HCR_TIDCP)
-#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
+ HCR_TVM | HCR_TWE | HCR_SWIO | HCR_TIDCP)
/* System Control Register (SCTLR) bits */
#define SCTLR_TE (1 << 30)
diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 661da11f76f4..53b3c4a50d5c 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -48,7 +48,9 @@
#define c13_TID_URO 26 /* Thread ID, User R/O */
#define c13_TID_PRIV 27 /* Thread ID, Privileged */
#define c14_CNTKCTL 28 /* Timer Control Register (PL1) */
-#define NR_CP15_REGS 29 /* Number of regs (incl. invalid) */
+#define c10_AMAIR0 29 /* Auxilary Memory Attribute Indirection Reg0 */
+#define c10_AMAIR1 30 /* Auxilary Memory Attribute Indirection Reg1 */
+#define NR_CP15_REGS 31 /* Number of regs (incl. invalid) */
#define ARM_EXCEPTION_RESET 0
#define ARM_EXCEPTION_UNDEFINED 1
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 098f7dd6d564..09af14999c9b 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -101,6 +101,12 @@ struct kvm_vcpu_arch {
/* The CPU type we expose to the VM */
u32 midr;
+ /* HYP trapping configuration */
+ u32 hcr;
+
+ /* Interrupt related fields */
+ u32 irq_lines; /* IRQ and FIQ levels */
+
/* Exception Information */
struct kvm_vcpu_fault_info fault;
@@ -128,9 +134,6 @@ struct kvm_vcpu_arch {
/* IO related fields */
struct kvm_decode mmio_decode;
- /* Interrupt related fields */
- u32 irq_lines; /* IRQ and FIQ levels */
-
/* Cache some mmu pages needed inside spinlock regions */
struct kvm_mmu_memory_cache mmu_page_cache;
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 2d122adcdb22..5c7aa3c1519f 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -114,11 +114,34 @@ static inline void kvm_set_s2pmd_writable(pmd_t *pmd)
pmd_val(*pmd) |= L_PMD_S2_RDWR;
}
+/* Open coded p*d_addr_end that can deal with 64bit addresses */
+#define kvm_pgd_addr_end(addr, end) \
+({ u64 __boundary = ((addr) + PGDIR_SIZE) & PGDIR_MASK; \
+ (__boundary - 1 < (end) - 1)? __boundary: (end); \
+})
+
+#define kvm_pud_addr_end(addr,end) (end)
+
+#define kvm_pmd_addr_end(addr, end) \
+({ u64 __boundary = ((addr) + PMD_SIZE) & PMD_MASK; \
+ (__boundary - 1 < (end) - 1)? __boundary: (end); \
+})
+
struct kvm;
-static inline void coherent_icache_guest_page(struct kvm *kvm, hva_t hva,
- unsigned long size)
+#define kvm_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l))
+
+static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
{
+ return (vcpu->arch.cp15[c1_SCTLR] & 0b101) == 0b101;
+}
+
+static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva,
+ unsigned long size)
+{
+ if (!vcpu_has_cache_enabled(vcpu))
+ kvm_flush_dcache_to_poc((void *)hva, size);
+
/*
* If we are going to insert an instruction page and the icache is
* either VIPT or PIPT, there is a potential problem where the host
@@ -139,9 +162,10 @@ static inline void coherent_icache_guest_page(struct kvm *kvm, hva_t hva,
}
}
-#define kvm_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l))
#define kvm_virt_to_phys(x) virt_to_idmap((unsigned long)(x))
+void stage2_flush_vm(struct kvm *kvm);
+
#endif /* !__ASSEMBLY__ */
#endif /* __ARM_KVM_MMU_H__ */
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 8756e4bcdba0..4afb376d9c7c 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -30,14 +30,15 @@
*/
#define UL(x) _AC(x, UL)
+/* PAGE_OFFSET - the virtual address of the start of the kernel image */
+#define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET)
+
#ifdef CONFIG_MMU
/*
- * PAGE_OFFSET - the virtual address of the start of the kernel image
* TASK_SIZE - the maximum size of a user space task.
* TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
*/
-#define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET)
#define TASK_SIZE (UL(CONFIG_PAGE_OFFSET) - UL(SZ_16M))
#define TASK_UNMAPPED_BASE ALIGN(TASK_SIZE / 3, SZ_16M)
@@ -104,10 +105,6 @@
#define END_MEM (UL(CONFIG_DRAM_BASE) + CONFIG_DRAM_SIZE)
#endif
-#ifndef PAGE_OFFSET
-#define PAGE_OFFSET PLAT_PHYS_OFFSET
-#endif
-
/*
* The module can be at any place in ram in nommu mode.
*/
diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h
index 03243f7eeddf..85c60adc8b60 100644
--- a/arch/arm/include/asm/pgtable-3level.h
+++ b/arch/arm/include/asm/pgtable-3level.h
@@ -120,13 +120,16 @@
/*
* 2nd stage PTE definitions for LPAE.
*/
-#define L_PTE_S2_MT_UNCACHED (_AT(pteval_t, 0x5) << 2) /* MemAttr[3:0] */
-#define L_PTE_S2_MT_WRITETHROUGH (_AT(pteval_t, 0xa) << 2) /* MemAttr[3:0] */
-#define L_PTE_S2_MT_WRITEBACK (_AT(pteval_t, 0xf) << 2) /* MemAttr[3:0] */
-#define L_PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[1] */
-#define L_PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */
+#define L_PTE_S2_MT_UNCACHED (_AT(pteval_t, 0x0) << 2) /* strongly ordered */
+#define L_PTE_S2_MT_WRITETHROUGH (_AT(pteval_t, 0xa) << 2) /* normal inner write-through */
+#define L_PTE_S2_MT_WRITEBACK (_AT(pteval_t, 0xf) << 2) /* normal inner write-back */
+#define L_PTE_S2_MT_DEV_SHARED (_AT(pteval_t, 0x1) << 2) /* device */
+#define L_PTE_S2_MT_MASK (_AT(pteval_t, 0xf) << 2)
-#define L_PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */
+#define L_PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[1] */
+#define L_PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */
+
+#define L_PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */
/*
* Hyp-mode PL2 PTE definitions for LPAE.
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index ef3c6072aa45..ac4bfae26702 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -37,18 +37,9 @@
static inline void dsb_sev(void)
{
-#if __LINUX_ARM_ARCH__ >= 7
- __asm__ __volatile__ (
- "dsb ishst\n"
- SEV
- );
-#else
- __asm__ __volatile__ (
- "mcr p15, 0, %0, c7, c10, 4\n"
- SEV
- : : "r" (0)
- );
-#endif
+
+ dsb(ishst);
+ __asm__(SEV);
}
/*
diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
index 58b8b84adcd2..2fe85fff5cca 100644
--- a/arch/arm/include/asm/topology.h
+++ b/arch/arm/include/asm/topology.h
@@ -20,9 +20,6 @@ extern struct cputopo_arm cpu_topology[NR_CPUS];
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
#define topology_thread_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
-#define mc_capable() (cpu_topology[0].socket_id != -1)
-#define smt_capable() (cpu_topology[0].thread_id != -1)
-
void init_cpu_topology(void);
void store_cpu_topology(unsigned int cpuid);
const struct cpumask *cpu_coregroup_mask(int cpu);
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index ded041711beb..85598b5d1efd 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -174,6 +174,7 @@ int main(void)
DEFINE(VCPU_FIQ_REGS, offsetof(struct kvm_vcpu, arch.regs.fiq_regs));
DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.regs.usr_regs.ARM_pc));
DEFINE(VCPU_CPSR, offsetof(struct kvm_vcpu, arch.regs.usr_regs.ARM_cpsr));
+ DEFINE(VCPU_HCR, offsetof(struct kvm_vcpu, arch.hcr));
DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines));
DEFINE(VCPU_HSR, offsetof(struct kvm_vcpu, arch.fault.hsr));
DEFINE(VCPU_HxFAR, offsetof(struct kvm_vcpu, arch.fault.hxfar));
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 317da88ae65b..d0d46786892c 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -19,7 +19,7 @@
static int debug_pci;
/*
- * We can't use pci_find_device() here since we are
+ * We can't use pci_get_device() here since we are
* called from interrupt context.
*/
static void pcibios_bus_report_status(struct pci_bus *bus, u_int status_mask, int warn)
@@ -57,13 +57,10 @@ static void pcibios_bus_report_status(struct pci_bus *bus, u_int status_mask, in
void pcibios_report_status(u_int status_mask, int warn)
{
- struct list_head *l;
-
- list_for_each(l, &pci_root_buses) {
- struct pci_bus *bus = pci_bus_b(l);
+ struct pci_bus *bus;
+ list_for_each_entry(bus, &pci_root_buses, node)
pcibios_bus_report_status(bus, status_mask, warn);
- }
}
/*
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S
index 47cd974e57ea..c96ecacb2021 100644
--- a/arch/arm/kernel/head-common.S
+++ b/arch/arm/kernel/head-common.S
@@ -177,6 +177,18 @@ __lookup_processor_type_data:
.long __proc_info_end
.size __lookup_processor_type_data, . - __lookup_processor_type_data
+__error_lpae:
+#ifdef CONFIG_DEBUG_LL
+ adr r0, str_lpae
+ bl printascii
+ b __error
+str_lpae: .asciz "\nError: Kernel with LPAE support, but CPU does not support LPAE.\n"
+#else
+ b __error
+#endif
+ .align
+ENDPROC(__error_lpae)
+
__error_p:
#ifdef CONFIG_DEBUG_LL
adr r0, str_p1
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 914616e0bdcd..f5f381d91556 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -102,7 +102,7 @@ ENTRY(stext)
and r3, r3, #0xf @ extract VMSA support
cmp r3, #5 @ long-descriptor translation table format?
THUMB( it lo ) @ force fixup-able long branch encoding
- blo __error_p @ only classic page table format
+ blo __error_lpae @ only classic page table format
#endif
#ifndef CONFIG_XIP_KERNEL
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 92f7b15dd221..adabeababeb0 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -30,7 +30,6 @@
#include <linux/uaccess.h>
#include <linux/random.h>
#include <linux/hw_breakpoint.h>
-#include <linux/cpuidle.h>
#include <linux/leds.h>
#include <linux/reboot.h>
@@ -133,7 +132,11 @@ EXPORT_SYMBOL_GPL(arm_pm_restart);
void (*arm_pm_idle)(void);
-static void default_idle(void)
+/*
+ * Called from the core idle loop.
+ */
+
+void arch_cpu_idle(void)
{
if (arm_pm_idle)
arm_pm_idle();
@@ -168,15 +171,6 @@ void arch_cpu_idle_dead(void)
#endif
/*
- * Called from the core idle loop.
- */
-void arch_cpu_idle(void)
-{
- if (cpuidle_idle_call())
- default_idle();
-}
-
-/*
* Called by kexec, immediately prior to machine_kexec().
*
* This must completely disable all secondary CPUs; simply causing those CPUs
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index b0df9761de6d..1e8b030dbefd 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -731,7 +731,7 @@ static void __init request_standard_resources(const struct machine_desc *mdesc)
kernel_data.end = virt_to_phys(_end - 1);
for_each_memblock(memory, region) {
- res = memblock_virt_alloc_low(sizeof(*res), 0);
+ res = memblock_virt_alloc(sizeof(*res), 0);
res->name = "System RAM";
res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index b7b4c86e338b..7c4fada440f0 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -674,8 +674,7 @@ static int cpufreq_callback(struct notifier_block *nb,
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
- (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
- (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
+ (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
global_l_p_j_ref_freq,
freq->new);
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 6591e26fc13f..dfc32130bc44 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -166,7 +166,7 @@ static int twd_cpufreq_transition(struct notifier_block *nb,
* frequency. The timer is local to a cpu, so cross-call to the
* changing cpu.
*/
- if (state == CPUFREQ_POSTCHANGE || state == CPUFREQ_RESUMECHANGE)
+ if (state == CPUFREQ_POSTCHANGE)
smp_call_function_single(freqs->cpu, twd_update_frequency,
NULL, 1);
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 1d8248ea5669..bd18bb8b2770 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -878,7 +878,8 @@ static int hyp_init_cpu_pm_notifier(struct notifier_block *self,
unsigned long cmd,
void *v)
{
- if (cmd == CPU_PM_EXIT) {
+ if (cmd == CPU_PM_EXIT &&
+ __hyp_get_vectors() == hyp_default_vectors) {
cpu_init_hyp_mode(NULL);
return NOTIFY_OK;
}
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 78c0885d6501..c58a35116f63 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -23,6 +23,7 @@
#include <asm/kvm_host.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_coproc.h>
+#include <asm/kvm_mmu.h>
#include <asm/cacheflush.h>
#include <asm/cputype.h>
#include <trace/events/kvm.h>
@@ -205,6 +206,44 @@ done:
}
/*
+ * Generic accessor for VM registers. Only called as long as HCR_TVM
+ * is set.
+ */
+static bool access_vm_reg(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p,
+ const struct coproc_reg *r)
+{
+ BUG_ON(!p->is_write);
+
+ vcpu->arch.cp15[r->reg] = *vcpu_reg(vcpu, p->Rt1);
+ if (p->is_64bit)
+ vcpu->arch.cp15[r->reg + 1] = *vcpu_reg(vcpu, p->Rt2);
+
+ return true;
+}
+
+/*
+ * SCTLR accessor. Only called as long as HCR_TVM is set. If the
+ * guest enables the MMU, we stop trapping the VM sys_regs and leave
+ * it in complete control of the caches.
+ *
+ * Used by the cpu-specific code.
+ */
+bool access_sctlr(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p,
+ const struct coproc_reg *r)
+{
+ access_vm_reg(vcpu, p, r);
+
+ if (vcpu_has_cache_enabled(vcpu)) { /* MMU+Caches enabled? */
+ vcpu->arch.hcr &= ~HCR_TVM;
+ stage2_flush_vm(vcpu->kvm);
+ }
+
+ return true;
+}
+
+/*
* We could trap ID_DFR0 and tell the guest we don't support performance
* monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was
* NAKed, so it will read the PMCR anyway.
@@ -261,33 +300,36 @@ static const struct coproc_reg cp15_regs[] = {
{ CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32,
NULL, reset_val, c1_CPACR, 0x00000000 },
- /* TTBR0/TTBR1: swapped by interrupt.S. */
- { CRm64( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 },
- { CRm64( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 },
-
- /* TTBCR: swapped by interrupt.S. */
+ /* TTBR0/TTBR1/TTBCR: swapped by interrupt.S. */
+ { CRm64( 2), Op1( 0), is64, access_vm_reg, reset_unknown64, c2_TTBR0 },
+ { CRn(2), CRm( 0), Op1( 0), Op2( 0), is32,
+ access_vm_reg, reset_unknown, c2_TTBR0 },
+ { CRn(2), CRm( 0), Op1( 0), Op2( 1), is32,
+ access_vm_reg, reset_unknown, c2_TTBR1 },
{ CRn( 2), CRm( 0), Op1( 0), Op2( 2), is32,
- NULL, reset_val, c2_TTBCR, 0x00000000 },
+ access_vm_reg, reset_val, c2_TTBCR, 0x00000000 },
+ { CRm64( 2), Op1( 1), is64, access_vm_reg, reset_unknown64, c2_TTBR1 },
+
/* DACR: swapped by interrupt.S. */
{ CRn( 3), CRm( 0), Op1( 0), Op2( 0), is32,
- NULL, reset_unknown, c3_DACR },
+ access_vm_reg, reset_unknown, c3_DACR },
/* DFSR/IFSR/ADFSR/AIFSR: swapped by interrupt.S. */
{ CRn( 5), CRm( 0), Op1( 0), Op2( 0), is32,
- NULL, reset_unknown, c5_DFSR },
+ access_vm_reg, reset_unknown, c5_DFSR },
{ CRn( 5), CRm( 0), Op1( 0), Op2( 1), is32,
- NULL, reset_unknown, c5_IFSR },
+ access_vm_reg, reset_unknown, c5_IFSR },
{ CRn( 5), CRm( 1), Op1( 0), Op2( 0), is32,
- NULL, reset_unknown, c5_ADFSR },
+ access_vm_reg, reset_unknown, c5_ADFSR },
{ CRn( 5), CRm( 1), Op1( 0), Op2( 1), is32,
- NULL, reset_unknown, c5_AIFSR },
+ access_vm_reg, reset_unknown, c5_AIFSR },
/* DFAR/IFAR: swapped by interrupt.S. */
{ CRn( 6), CRm( 0), Op1( 0), Op2( 0), is32,
- NULL, reset_unknown, c6_DFAR },
+ access_vm_reg, reset_unknown, c6_DFAR },
{ CRn( 6), CRm( 0), Op1( 0), Op2( 2), is32,
- NULL, reset_unknown, c6_IFAR },
+ access_vm_reg, reset_unknown, c6_IFAR },
/* PAR swapped by interrupt.S */
{ CRm64( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR },
@@ -324,9 +366,15 @@ static const struct coproc_reg cp15_regs[] = {
/* PRRR/NMRR (aka MAIR0/MAIR1): swapped by interrupt.S. */
{ CRn(10), CRm( 2), Op1( 0), Op2( 0), is32,
- NULL, reset_unknown, c10_PRRR},
+ access_vm_reg, reset_unknown, c10_PRRR},
{ CRn(10), CRm( 2), Op1( 0), Op2( 1), is32,
- NULL, reset_unknown, c10_NMRR},
+ access_vm_reg, reset_unknown, c10_NMRR},
+
+ /* AMAIR0/AMAIR1: swapped by interrupt.S. */
+ { CRn(10), CRm( 3), Op1( 0), Op2( 0), is32,
+ access_vm_reg, reset_unknown, c10_AMAIR0},
+ { CRn(10), CRm( 3), Op1( 0), Op2( 1), is32,
+ access_vm_reg, reset_unknown, c10_AMAIR1},
/* VBAR: swapped by interrupt.S. */
{ CRn(12), CRm( 0), Op1( 0), Op2( 0), is32,
@@ -334,7 +382,7 @@ static const struct coproc_reg cp15_regs[] = {
/* CONTEXTIDR/TPIDRURW/TPIDRURO/TPIDRPRW: swapped by interrupt.S. */
{ CRn(13), CRm( 0), Op1( 0), Op2( 1), is32,
- NULL, reset_val, c13_CID, 0x00000000 },
+ access_vm_reg, reset_val, c13_CID, 0x00000000 },
{ CRn(13), CRm( 0), Op1( 0), Op2( 2), is32,
NULL, reset_unknown, c13_TID_URW },
{ CRn(13), CRm( 0), Op1( 0), Op2( 3), is32,
@@ -443,7 +491,7 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
struct coproc_params params;
- params.CRm = (kvm_vcpu_get_hsr(vcpu) >> 1) & 0xf;
+ params.CRn = (kvm_vcpu_get_hsr(vcpu) >> 1) & 0xf;
params.Rt1 = (kvm_vcpu_get_hsr(vcpu) >> 5) & 0xf;
params.is_write = ((kvm_vcpu_get_hsr(vcpu) & 1) == 0);
params.is_64bit = true;
@@ -451,7 +499,7 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
params.Op1 = (kvm_vcpu_get_hsr(vcpu) >> 16) & 0xf;
params.Op2 = 0;
params.Rt2 = (kvm_vcpu_get_hsr(vcpu) >> 10) & 0xf;
- params.CRn = 0;
+ params.CRm = 0;
return emulate_cp15(vcpu, &params);
}
diff --git a/arch/arm/kvm/coproc.h b/arch/arm/kvm/coproc.h
index 0461d5c8d3de..1a44bbe39643 100644
--- a/arch/arm/kvm/coproc.h
+++ b/arch/arm/kvm/coproc.h
@@ -58,8 +58,8 @@ static inline void print_cp_instr(const struct coproc_params *p)
{
/* Look, we even formatted it for you to paste into the table! */
if (p->is_64bit) {
- kvm_pr_unimpl(" { CRm(%2lu), Op1(%2lu), is64, func_%s },\n",
- p->CRm, p->Op1, p->is_write ? "write" : "read");
+ kvm_pr_unimpl(" { CRm64(%2lu), Op1(%2lu), is64, func_%s },\n",
+ p->CRn, p->Op1, p->is_write ? "write" : "read");
} else {
kvm_pr_unimpl(" { CRn(%2lu), CRm(%2lu), Op1(%2lu), Op2(%2lu), is32,"
" func_%s },\n",
@@ -135,13 +135,13 @@ static inline int cmp_reg(const struct coproc_reg *i1,
return -1;
if (i1->CRn != i2->CRn)
return i1->CRn - i2->CRn;
- if (i1->is_64 != i2->is_64)
- return i2->is_64 - i1->is_64;
if (i1->CRm != i2->CRm)
return i1->CRm - i2->CRm;
if (i1->Op1 != i2->Op1)
return i1->Op1 - i2->Op1;
- return i1->Op2 - i2->Op2;
+ if (i1->Op2 != i2->Op2)
+ return i1->Op2 - i2->Op2;
+ return i2->is_64 - i1->is_64;
}
@@ -153,4 +153,8 @@ static inline int cmp_reg(const struct coproc_reg *i1,
#define is64 .is_64 = true
#define is32 .is_64 = false
+bool access_sctlr(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p,
+ const struct coproc_reg *r);
+
#endif /* __ARM_KVM_COPROC_LOCAL_H__ */
diff --git a/arch/arm/kvm/coproc_a15.c b/arch/arm/kvm/coproc_a15.c
index bb0cac1410cc..e6f4ae48bda9 100644
--- a/arch/arm/kvm/coproc_a15.c
+++ b/arch/arm/kvm/coproc_a15.c
@@ -34,7 +34,7 @@
static const struct coproc_reg a15_regs[] = {
/* SCTLR: swapped by interrupt.S. */
{ CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
- NULL, reset_val, c1_SCTLR, 0x00C50078 },
+ access_sctlr, reset_val, c1_SCTLR, 0x00C50078 },
};
static struct kvm_coproc_target_table a15_target_table = {
diff --git a/arch/arm/kvm/coproc_a7.c b/arch/arm/kvm/coproc_a7.c
index 1df767331588..17fc7cd479d3 100644
--- a/arch/arm/kvm/coproc_a7.c
+++ b/arch/arm/kvm/coproc_a7.c
@@ -37,7 +37,7 @@
static const struct coproc_reg a7_regs[] = {
/* SCTLR: swapped by interrupt.S. */
{ CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
- NULL, reset_val, c1_SCTLR, 0x00C50878 },
+ access_sctlr, reset_val, c1_SCTLR, 0x00C50878 },
};
static struct kvm_coproc_target_table a7_target_table = {
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 2786eae10c0d..b23a59c1c522 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -38,6 +38,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
+ vcpu->arch.hcr = HCR_GUEST_MASK;
return 0;
}
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
index ddc15539bad2..0d68d4073068 100644
--- a/arch/arm/kvm/interrupts.S
+++ b/arch/arm/kvm/interrupts.S
@@ -220,6 +220,10 @@ after_vfp_restore:
* in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c). Return values are
* passed in r0 and r1.
*
+ * A function pointer with a value of 0xffffffff has a special meaning,
+ * and is used to implement __hyp_get_vectors in the same way as in
+ * arch/arm/kernel/hyp_stub.S.
+ *
* The calling convention follows the standard AAPCS:
* r0 - r3: caller save
* r12: caller save
@@ -363,6 +367,11 @@ hyp_hvc:
host_switch_to_hyp:
pop {r0, r1, r2}
+ /* Check for __hyp_get_vectors */
+ cmp r0, #-1
+ mrceq p15, 4, r0, c12, c0, 0 @ get HVBAR
+ beq 1f
+
push {lr}
mrs lr, SPSR
push {lr}
@@ -378,7 +387,7 @@ THUMB( orr lr, #1)
pop {lr}
msr SPSR_csxf, lr
pop {lr}
- eret
+1: eret
guest_trap:
load_vcpu @ Load VCPU pointer to r0
diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
index 6f18695a09cb..76af93025574 100644
--- a/arch/arm/kvm/interrupts_head.S
+++ b/arch/arm/kvm/interrupts_head.S
@@ -303,13 +303,17 @@ vcpu .req r0 @ vcpu pointer always in r0
mrc p15, 0, r2, c14, c1, 0 @ CNTKCTL
mrrc p15, 0, r4, r5, c7 @ PAR
+ mrc p15, 0, r6, c10, c3, 0 @ AMAIR0
+ mrc p15, 0, r7, c10, c3, 1 @ AMAIR1
.if \store_to_vcpu == 0
- push {r2,r4-r5}
+ push {r2,r4-r7}
.else
str r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
add r12, vcpu, #CP15_OFFSET(c7_PAR)
strd r4, r5, [r12]
+ str r6, [vcpu, #CP15_OFFSET(c10_AMAIR0)]
+ str r7, [vcpu, #CP15_OFFSET(c10_AMAIR1)]
.endif
.endm
@@ -322,15 +326,19 @@ vcpu .req r0 @ vcpu pointer always in r0
*/
.macro write_cp15_state read_from_vcpu
.if \read_from_vcpu == 0
- pop {r2,r4-r5}
+ pop {r2,r4-r7}
.else
ldr r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
add r12, vcpu, #CP15_OFFSET(c7_PAR)
ldrd r4, r5, [r12]
+ ldr r6, [vcpu, #CP15_OFFSET(c10_AMAIR0)]
+ ldr r7, [vcpu, #CP15_OFFSET(c10_AMAIR1)]
.endif
mcr p15, 0, r2, c14, c1, 0 @ CNTKCTL
mcrr p15, 0, r4, r5, c7 @ PAR
+ mcr p15, 0, r6, c10, c3, 0 @ AMAIR0
+ mcr p15, 0, r7, c10, c3, 1 @ AMAIR1
.if \read_from_vcpu == 0
pop {r2-r12}
@@ -597,17 +605,14 @@ vcpu .req r0 @ vcpu pointer always in r0
/* Enable/Disable: stage-2 trans., trap interrupts, trap wfi, trap smc */
.macro configure_hyp_role operation
- mrc p15, 4, r2, c1, c1, 0 @ HCR
- bic r2, r2, #HCR_VIRT_EXCP_MASK
- ldr r3, =HCR_GUEST_MASK
.if \operation == vmentry
- orr r2, r2, r3
+ ldr r2, [vcpu, #VCPU_HCR]
ldr r3, [vcpu, #VCPU_IRQ_LINES]
orr r2, r2, r3
.else
- bic r2, r2, r3
+ mov r2, #0
.endif
- mcr p15, 4, r2, c1, c1, 0
+ mcr p15, 4, r2, c1, c1, 0 @ HCR
.endm
.macro load_vcpu
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 7789857d1470..80bb1e6c2c29 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -144,8 +144,9 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
while (addr < end) {
pgd = pgdp + pgd_index(addr);
pud = pud_offset(pgd, addr);
+ pte = NULL;
if (pud_none(*pud)) {
- addr = pud_addr_end(addr, end);
+ addr = kvm_pud_addr_end(addr, end);
continue;
}
@@ -155,13 +156,13 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
* move on.
*/
clear_pud_entry(kvm, pud, addr);
- addr = pud_addr_end(addr, end);
+ addr = kvm_pud_addr_end(addr, end);
continue;
}
pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd)) {
- addr = pmd_addr_end(addr, end);
+ addr = kvm_pmd_addr_end(addr, end);
continue;
}
@@ -174,12 +175,12 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
/*
* If the pmd entry is to be cleared, walk back up the ladder
*/
- if (kvm_pmd_huge(*pmd) || page_empty(pte)) {
+ if (kvm_pmd_huge(*pmd) || (pte && page_empty(pte))) {
clear_pmd_entry(kvm, pmd, addr);
- next = pmd_addr_end(addr, end);
+ next = kvm_pmd_addr_end(addr, end);
if (page_empty(pmd) && !page_empty(pud)) {
clear_pud_entry(kvm, pud, addr);
- next = pud_addr_end(addr, end);
+ next = kvm_pud_addr_end(addr, end);
}
}
@@ -187,6 +188,99 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
}
}
+static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd,
+ phys_addr_t addr, phys_addr_t end)
+{
+ pte_t *pte;
+
+ pte = pte_offset_kernel(pmd, addr);
+ do {
+ if (!pte_none(*pte)) {
+ hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT);
+ kvm_flush_dcache_to_poc((void*)hva, PAGE_SIZE);
+ }
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+}
+
+static void stage2_flush_pmds(struct kvm *kvm, pud_t *pud,
+ phys_addr_t addr, phys_addr_t end)
+{
+ pmd_t *pmd;
+ phys_addr_t next;
+
+ pmd = pmd_offset(pud, addr);
+ do {
+ next = kvm_pmd_addr_end(addr, end);
+ if (!pmd_none(*pmd)) {
+ if (kvm_pmd_huge(*pmd)) {
+ hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT);
+ kvm_flush_dcache_to_poc((void*)hva, PMD_SIZE);
+ } else {
+ stage2_flush_ptes(kvm, pmd, addr, next);
+ }
+ }
+ } while (pmd++, addr = next, addr != end);
+}
+
+static void stage2_flush_puds(struct kvm *kvm, pgd_t *pgd,
+ phys_addr_t addr, phys_addr_t end)
+{
+ pud_t *pud;
+ phys_addr_t next;
+
+ pud = pud_offset(pgd, addr);
+ do {
+ next = kvm_pud_addr_end(addr, end);
+ if (!pud_none(*pud)) {
+ if (pud_huge(*pud)) {
+ hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT);
+ kvm_flush_dcache_to_poc((void*)hva, PUD_SIZE);
+ } else {
+ stage2_flush_pmds(kvm, pud, addr, next);
+ }
+ }
+ } while (pud++, addr = next, addr != end);
+}
+
+static void stage2_flush_memslot(struct kvm *kvm,
+ struct kvm_memory_slot *memslot)
+{
+ phys_addr_t addr = memslot->base_gfn << PAGE_SHIFT;
+ phys_addr_t end = addr + PAGE_SIZE * memslot->npages;
+ phys_addr_t next;
+ pgd_t *pgd;
+
+ pgd = kvm->arch.pgd + pgd_index(addr);
+ do {
+ next = kvm_pgd_addr_end(addr, end);
+ stage2_flush_puds(kvm, pgd, addr, next);
+ } while (pgd++, addr = next, addr != end);
+}
+
+/**
+ * stage2_flush_vm - Invalidate cache for pages mapped in stage 2
+ * @kvm: The struct kvm pointer
+ *
+ * Go through the stage 2 page tables and invalidate any cache lines
+ * backing memory already mapped to the VM.
+ */
+void stage2_flush_vm(struct kvm *kvm)
+{
+ struct kvm_memslots *slots;
+ struct kvm_memory_slot *memslot;
+ int idx;
+
+ idx = srcu_read_lock(&kvm->srcu);
+ spin_lock(&kvm->mmu_lock);
+
+ slots = kvm_memslots(kvm);
+ kvm_for_each_memslot(memslot, slots)
+ stage2_flush_memslot(kvm, memslot);
+
+ spin_unlock(&kvm->mmu_lock);
+ srcu_read_unlock(&kvm->srcu, idx);
+}
+
/**
* free_boot_hyp_pgd - free HYP boot page tables
*
@@ -715,7 +809,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
kvm_set_s2pmd_writable(&new_pmd);
kvm_set_pfn_dirty(pfn);
}
- coherent_icache_guest_page(kvm, hva & PMD_MASK, PMD_SIZE);
+ coherent_cache_guest_page(vcpu, hva & PMD_MASK, PMD_SIZE);
ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd);
} else {
pte_t new_pte = pfn_pte(pfn, PAGE_S2);
@@ -723,7 +817,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
kvm_set_s2pte_writable(&new_pte);
kvm_set_pfn_dirty(pfn);
}
- coherent_icache_guest_page(kvm, hva, PAGE_SIZE);
+ coherent_cache_guest_page(vcpu, hva, PAGE_SIZE);
ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte, false);
}
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 2ab00434b2eb..85399c98f84a 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -472,7 +472,7 @@ static struct clk_lookup da850_clks[] = {
CLK("spi_davinci.0", NULL, &spi0_clk),
CLK("spi_davinci.1", NULL, &spi1_clk),
CLK("vpif", NULL, &vpif_clk),
- CLK("ahci", NULL, &sata_clk),
+ CLK("ahci_da850", NULL, &sata_clk),
CLK("davinci-rproc.0", NULL, &dsp_clk),
CLK("ehrpwm", "fck", &ehrpwm_clk),
CLK("ehrpwm", "tbclk", &ehrpwm_tbclk),
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 0486cdf28c8d..56ea41d5f849 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -1020,7 +1020,6 @@ int __init da8xx_register_spi_bus(int instance, unsigned num_chipselect)
}
#ifdef CONFIG_ARCH_DAVINCI_DA850
-
static struct resource da850_sata_resources[] = {
{
.start = DA850_SATA_BASE,
@@ -1028,103 +1027,22 @@ static struct resource da850_sata_resources[] = {
.flags = IORESOURCE_MEM,
},
{
+ .start = DA8XX_SYSCFG1_BASE + DA8XX_PWRDN_REG,
+ .end = DA8XX_SYSCFG1_BASE + DA8XX_PWRDN_REG + 0x3,
+ .flags = IORESOURCE_MEM,
+ },
+ {
.start = IRQ_DA850_SATAINT,
.flags = IORESOURCE_IRQ,
},
};
-/* SATA PHY Control Register offset from AHCI base */
-#define SATA_P0PHYCR_REG 0x178
-
-#define SATA_PHY_MPY(x) ((x) << 0)
-#define SATA_PHY_LOS(x) ((x) << 6)
-#define SATA_PHY_RXCDR(x) ((x) << 10)
-#define SATA_PHY_RXEQ(x) ((x) << 13)
-#define SATA_PHY_TXSWING(x) ((x) << 19)
-#define SATA_PHY_ENPLL(x) ((x) << 31)
-
-static struct clk *da850_sata_clk;
-static unsigned long da850_sata_refclkpn;
-
-/* Supported DA850 SATA crystal frequencies */
-#define KHZ_TO_HZ(freq) ((freq) * 1000)
-static unsigned long da850_sata_xtal[] = {
- KHZ_TO_HZ(300000),
- KHZ_TO_HZ(250000),
- 0, /* Reserved */
- KHZ_TO_HZ(187500),
- KHZ_TO_HZ(150000),
- KHZ_TO_HZ(125000),
- KHZ_TO_HZ(120000),
- KHZ_TO_HZ(100000),
- KHZ_TO_HZ(75000),
- KHZ_TO_HZ(60000),
-};
-
-static int da850_sata_init(struct device *dev, void __iomem *addr)
-{
- int i, ret;
- unsigned int val;
-
- da850_sata_clk = clk_get(dev, NULL);
- if (IS_ERR(da850_sata_clk))
- return PTR_ERR(da850_sata_clk);
-
- ret = clk_prepare_enable(da850_sata_clk);
- if (ret)
- goto err0;
-
- /* Enable SATA clock receiver */
- val = __raw_readl(DA8XX_SYSCFG1_VIRT(DA8XX_PWRDN_REG));
- val &= ~BIT(0);
- __raw_writel(val, DA8XX_SYSCFG1_VIRT(DA8XX_PWRDN_REG));
-
- /* Get the multiplier needed for 1.5GHz PLL output */
- for (i = 0; i < ARRAY_SIZE(da850_sata_xtal); i++)
- if (da850_sata_xtal[i] == da850_sata_refclkpn)
- break;
-
- if (i == ARRAY_SIZE(da850_sata_xtal)) {
- ret = -EINVAL;
- goto err1;
- }
-
- val = SATA_PHY_MPY(i + 1) |
- SATA_PHY_LOS(1) |
- SATA_PHY_RXCDR(4) |
- SATA_PHY_RXEQ(1) |
- SATA_PHY_TXSWING(3) |
- SATA_PHY_ENPLL(1);
-
- __raw_writel(val, addr + SATA_P0PHYCR_REG);
-
- return 0;
-
-err1:
- clk_disable_unprepare(da850_sata_clk);
-err0:
- clk_put(da850_sata_clk);
- return ret;
-}
-
-static void da850_sata_exit(struct device *dev)
-{
- clk_disable_unprepare(da850_sata_clk);
- clk_put(da850_sata_clk);
-}
-
-static struct ahci_platform_data da850_sata_pdata = {
- .init = da850_sata_init,
- .exit = da850_sata_exit,
-};
-
static u64 da850_sata_dmamask = DMA_BIT_MASK(32);
static struct platform_device da850_sata_device = {
- .name = "ahci",
+ .name = "ahci_da850",
.id = -1,
.dev = {
- .platform_data = &da850_sata_pdata,
.dma_mask = &da850_sata_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
@@ -1134,9 +1052,8 @@ static struct platform_device da850_sata_device = {
int __init da850_register_sata(unsigned long refclkpn)
{
- da850_sata_refclkpn = refclkpn;
- if (!da850_sata_refclkpn)
- return -EINVAL;
+ /* please see comment in drivers/ata/ahci_da850.c */
+ BUG_ON(refclkpn != 100 * 1000 * 1000);
return platform_device_register(&da850_sata_device);
}
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 4c414af75ef0..8d197dcdd2c0 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -36,7 +36,6 @@ config ARCH_EXYNOS5
select HAVE_ARM_SCU if SMP
select HAVE_SMP
select PINCTRL
- select USB_ARCH_HAS_XHCI
help
Samsung EXYNOS5 (Cortex-A15) SoC based systems
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index befcaf5d0574..ec419649320f 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -101,11 +101,9 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o
obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o
-ifeq ($(CONFIG_PM),y)
obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o
# i.MX6SL reuses i.MX6Q code
obj-$(CONFIG_SOC_IMX6SL) += pm-imx6q.o headsmp.o
-endif
# i.MX5 based machines
obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 59c3b9b26bb4..baf439dc22d8 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -144,13 +144,11 @@ void imx6q_set_chicken_bit(void);
void imx_cpu_die(unsigned int cpu);
int imx_cpu_kill(unsigned int cpu);
-#ifdef CONFIG_PM
void imx6q_pm_init(void);
void imx6q_pm_set_ccm_base(void __iomem *base);
+#ifdef CONFIG_PM
void imx5_pm_init(void);
#else
-static inline void imx6q_pm_init(void) {}
-static inline void imx6q_pm_set_ccm_base(void __iomem *base) {}
static inline void imx5_pm_init(void) {}
#endif
diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c
index b3738e616f19..8f45afe785f8 100644
--- a/arch/arm/mach-imx/mach-mx31moboard.c
+++ b/arch/arm/mach-imx/mach-mx31moboard.c
@@ -128,27 +128,15 @@ static struct platform_device mx31moboard_flash = {
.num_resources = 1,
};
-static int moboard_uart0_init(struct platform_device *pdev)
+static void __init moboard_uart0_init(void)
{
- int ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack");
- if (ret)
- return ret;
-
- ret = gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0);
- if (ret)
+ if (!gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack")) {
+ gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0);
gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1));
-
- return ret;
-}
-
-static void moboard_uart0_exit(struct platform_device *pdev)
-{
- gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1));
+ }
}
static const struct imxuart_platform_data uart0_pdata __initconst = {
- .init = moboard_uart0_init,
- .exit = moboard_uart0_exit,
};
static const struct imxuart_platform_data uart4_pdata __initconst = {
@@ -543,6 +531,7 @@ static void __init mx31moboard_init(void)
imx31_add_imx2_wdt();
+ moboard_uart0_init();
imx31_add_imx_uart0(&uart0_pdata);
imx31_add_imx_uart4(&uart4_pdata);
diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c
index 7a9b98589db7..29e3fe6a6669 100644
--- a/arch/arm/mach-imx/pm-imx6q.c
+++ b/arch/arm/mach-imx/pm-imx6q.c
@@ -120,7 +120,7 @@ static void imx6q_enable_wb(bool enable)
int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
{
- struct irq_desc *iomuxc_irq_desc;
+ struct irq_data *iomuxc_irq_data = irq_get_irq_data(32);
u32 val = readl_relaxed(ccm_base + CLPCR);
val &= ~BM_CLPCR_LPM;
@@ -167,10 +167,9 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
* 3) Software should mask IRQ #32 right after CCM Low-Power mode
* is set (set bits 0-1 of CCM_CLPCR).
*/
- iomuxc_irq_desc = irq_to_desc(32);
- imx_gpc_irq_unmask(&iomuxc_irq_desc->irq_data);
+ imx_gpc_irq_unmask(iomuxc_irq_data);
writel_relaxed(val, ccm_base + CLPCR);
- imx_gpc_irq_mask(&iomuxc_irq_desc->irq_data);
+ imx_gpc_irq_mask(iomuxc_irq_data);
return 0;
}
diff --git a/arch/arm/mach-mmp/pm-mmp2.c b/arch/arm/mach-mmp/pm-mmp2.c
index 461a191a32d2..43b1a516957f 100644
--- a/arch/arm/mach-mmp/pm-mmp2.c
+++ b/arch/arm/mach-mmp/pm-mmp2.c
@@ -27,22 +27,8 @@
int mmp2_set_wake(struct irq_data *d, unsigned int on)
{
- int irq = d->irq;
- struct irq_desc *desc = irq_to_desc(irq);
unsigned long data = 0;
-
- if (unlikely(irq >= nr_irqs)) {
- pr_err("IRQ nubmers are out of boundary!\n");
- return -EINVAL;
- }
-
- if (on) {
- if (desc->action)
- desc->action->flags |= IRQF_NO_SUSPEND;
- } else {
- if (desc->action)
- desc->action->flags &= ~IRQF_NO_SUSPEND;
- }
+ int irq = d->irq;
/* enable wakeup sources */
switch (irq) {
diff --git a/arch/arm/mach-mmp/pm-pxa910.c b/arch/arm/mach-mmp/pm-pxa910.c
index 48981ca801a5..04c9daf9f8d7 100644
--- a/arch/arm/mach-mmp/pm-pxa910.c
+++ b/arch/arm/mach-mmp/pm-pxa910.c
@@ -27,22 +27,8 @@
int pxa910_set_wake(struct irq_data *data, unsigned int on)
{
- int irq = data->irq;
- struct irq_desc *desc = irq_to_desc(data->irq);
uint32_t awucrm = 0, apcr = 0;
-
- if (unlikely(irq >= nr_irqs)) {
- pr_err("IRQ nubmers are out of boundary!\n");
- return -EINVAL;
- }
-
- if (on) {
- if (desc->action)
- desc->action->flags |= IRQF_NO_SUSPEND;
- } else {
- if (desc->action)
- desc->action->flags &= ~IRQF_NO_SUSPEND;
- }
+ int irq = data->irq;
/* setting wakeup sources */
switch (irq) {
@@ -115,9 +101,11 @@ int pxa910_set_wake(struct irq_data *data, unsigned int on)
if (irq >= IRQ_GPIO_START && irq < IRQ_BOARD_START) {
awucrm = MPMU_AWUCRM_WAKEUP(2);
apcr |= MPMU_APCR_SLPWP2;
- } else
+ } else {
+ /* FIXME: This should return a proper error code ! */
printk(KERN_ERR "Error: no defined wake up source irq: %d\n",
irq);
+ }
}
if (on) {
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index 5e269d7263ce..df9e7d270810 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -16,6 +16,7 @@ config ARCH_MVEBU
select ARCH_REQUIRE_GPIOLIB
select MIGHT_HAVE_PCI
select PCI_QUIRKS if PCI
+ select OF_ADDRESS_PCI
if ARCH_MVEBU
diff --git a/arch/arm/mach-omap1/ams-delta-fiq.c b/arch/arm/mach-omap1/ams-delta-fiq.c
index f12a12af3523..d1f12095f315 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq.c
+++ b/arch/arm/mach-omap1/ams-delta-fiq.c
@@ -44,13 +44,10 @@ static unsigned int irq_counter[16];
static irqreturn_t deferred_fiq(int irq, void *dev_id)
{
- struct irq_desc *irq_desc;
- struct irq_chip *irq_chip = NULL;
int gpio, irq_num, fiq_count;
+ struct irq_chip *irq_chip;
- irq_desc = irq_to_desc(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK));
- if (irq_desc)
- irq_chip = irq_desc->irq_data.chip;
+ irq_chip = irq_get_chip(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK));
/*
* For each handled GPIO interrupt, keep calling its interrupt handler
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index 91449c5cb70f..85089d821982 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -156,6 +156,7 @@ static struct omap_usb_config nokia770_usb_config __initdata = {
.register_dev = 1,
.hmc_mode = 16,
.pins[0] = 6,
+ .extcon = "tahvo-usb",
};
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index e2ce4f8366a7..ac4882511749 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -21,7 +21,6 @@ config ARCH_OMAP3
select PM_OPP if PM
select PM_RUNTIME if CPU_IDLE
select SOC_HAS_OMAP2_SDRC
- select USB_ARCH_HAS_EHCI if USB_SUPPORT
config ARCH_OMAP4
bool "TI OMAP4"
@@ -42,7 +41,6 @@ config ARCH_OMAP4
select PL310_ERRATA_727915
select PM_OPP if PM
select PM_RUNTIME if CPU_IDLE
- select USB_ARCH_HAS_EHCI if USB_SUPPORT
select ARM_ERRATA_754322
select ARM_ERRATA_775420
@@ -50,6 +48,7 @@ config SOC_OMAP5
bool "TI OMAP5"
depends on ARCH_MULTI_V7
select ARCH_OMAP2PLUS
+ select ARCH_HAS_OPP
select ARM_CPU_SUSPEND if PM
select ARM_GIC
select CPU_V7
@@ -63,6 +62,7 @@ config SOC_AM33XX
bool "TI AM33XX"
depends on ARCH_MULTI_V7
select ARCH_OMAP2PLUS
+ select ARCH_HAS_OPP
select ARM_CPU_SUSPEND if PM
select CPU_V7
select MULTI_IRQ_HANDLER
@@ -72,6 +72,7 @@ config SOC_AM43XX
depends on ARCH_MULTI_V7
select CPU_V7
select ARCH_OMAP2PLUS
+ select ARCH_HAS_OPP
select MULTI_IRQ_HANDLER
select ARM_GIC
select MACH_OMAP_GENERIC
@@ -80,6 +81,7 @@ config SOC_DRA7XX
bool "TI DRA7XX"
depends on ARCH_MULTI_V7
select ARCH_OMAP2PLUS
+ select ARCH_HAS_OPP
select ARM_CPU_SUSPEND if PM
select ARM_GIC
select CPU_V7
@@ -100,7 +102,6 @@ config ARCH_OMAP2PLUS
select MACH_OMAP_GENERIC
select OMAP_DM_TIMER
select PINCTRL
- select PROC_DEVICETREE if PROC_FS
select SOC_BUS
select SPARSE_IRQ
select TI_PRIV_EDMA
@@ -268,9 +269,6 @@ config MACH_OMAP_3430SDP
default y
select OMAP_PACKAGE_CBB
-config MACH_NOKIA_N800
- bool
-
config MACH_NOKIA_N810
bool
@@ -281,7 +279,6 @@ config MACH_NOKIA_N8X0
bool "Nokia N800/N810"
depends on SOC_OMAP2420
default y
- select MACH_NOKIA_N800
select MACH_NOKIA_N810
select MACH_NOKIA_N810_WIMAX
select OMAP_PACKAGE_ZAC
diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c
index 3b05aea56d1f..11ed9152e665 100644
--- a/arch/arm/mach-omap2/cclock3xxx_data.c
+++ b/arch/arm/mach-omap2/cclock3xxx_data.c
@@ -433,7 +433,9 @@ static const struct clk_ops dpll4_m5x2_ck_ops = {
.enable = &omap2_dflt_clk_enable,
.disable = &omap2_dflt_clk_disable,
.is_enabled = &omap2_dflt_clk_is_enabled,
+ .set_rate = &omap3_clkoutx2_set_rate,
.recalc_rate = &omap3_clkoutx2_recalc,
+ .round_rate = &omap3_clkoutx2_round_rate,
};
static const struct clk_ops dpll4_m5x2_ck_3630_ops = {
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c
index 4c158c838d40..01fc710c8181 100644
--- a/arch/arm/mach-omap2/cpuidle44xx.c
+++ b/arch/arm/mach-omap2/cpuidle44xx.c
@@ -23,6 +23,8 @@
#include "prm.h"
#include "clockdomain.h"
+#define MAX_CPUS 2
+
/* Machine specific information */
struct idle_statedata {
u32 cpu_state;
@@ -48,11 +50,11 @@ static struct idle_statedata omap4_idle_data[] = {
},
};
-static struct powerdomain *mpu_pd, *cpu_pd[NR_CPUS];
-static struct clockdomain *cpu_clkdm[NR_CPUS];
+static struct powerdomain *mpu_pd, *cpu_pd[MAX_CPUS];
+static struct clockdomain *cpu_clkdm[MAX_CPUS];
static atomic_t abort_barrier;
-static bool cpu_done[NR_CPUS];
+static bool cpu_done[MAX_CPUS];
static struct idle_statedata *state_ptr = &omap4_idle_data[0];
/* Private functions */
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index 3185ced807c9..3c418ea54bbe 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -623,6 +623,32 @@ void omap3_dpll_deny_idle(struct clk_hw_omap *clk)
/* Clock control for DPLL outputs */
+/* Find the parent DPLL for the given clkoutx2 clock */
+static struct clk_hw_omap *omap3_find_clkoutx2_dpll(struct clk_hw *hw)
+{
+ struct clk_hw_omap *pclk = NULL;
+ struct clk *parent;
+
+ /* Walk up the parents of clk, looking for a DPLL */
+ do {
+ do {
+ parent = __clk_get_parent(hw->clk);
+ hw = __clk_get_hw(parent);
+ } while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC));
+ if (!hw)
+ break;
+ pclk = to_clk_hw_omap(hw);
+ } while (pclk && !pclk->dpll_data);
+
+ /* clk does not have a DPLL as a parent? error in the clock data */
+ if (!pclk) {
+ WARN_ON(1);
+ return NULL;
+ }
+
+ return pclk;
+}
+
/**
* omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
* @clk: DPLL output struct clk
@@ -637,27 +663,14 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
unsigned long rate;
u32 v;
struct clk_hw_omap *pclk = NULL;
- struct clk *parent;
if (!parent_rate)
return 0;
- /* Walk up the parents of clk, looking for a DPLL */
- do {
- do {
- parent = __clk_get_parent(hw->clk);
- hw = __clk_get_hw(parent);
- } while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC));
- if (!hw)
- break;
- pclk = to_clk_hw_omap(hw);
- } while (pclk && !pclk->dpll_data);
+ pclk = omap3_find_clkoutx2_dpll(hw);
- /* clk does not have a DPLL as a parent? error in the clock data */
- if (!pclk) {
- WARN_ON(1);
+ if (!pclk)
return 0;
- }
dd = pclk->dpll_data;
@@ -672,6 +685,55 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
return rate;
}
+int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ return 0;
+}
+
+long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ const struct dpll_data *dd;
+ u32 v;
+ struct clk_hw_omap *pclk = NULL;
+
+ if (!*prate)
+ return 0;
+
+ pclk = omap3_find_clkoutx2_dpll(hw);
+
+ if (!pclk)
+ return 0;
+
+ dd = pclk->dpll_data;
+
+ /* TYPE J does not have a clkoutx2 */
+ if (dd->flags & DPLL_J_TYPE) {
+ *prate = __clk_round_rate(__clk_get_parent(pclk->hw.clk), rate);
+ return *prate;
+ }
+
+ WARN_ON(!dd->enable_mask);
+
+ v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask;
+ v >>= __ffs(dd->enable_mask);
+
+ /* If in bypass, the rate is fixed to the bypass rate*/
+ if (v != OMAP3XXX_EN_DPLL_LOCKED)
+ return *prate;
+
+ if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+ unsigned long best_parent;
+
+ best_parent = (rate / 2);
+ *prate = __clk_round_rate(__clk_get_parent(hw->clk),
+ best_parent);
+ }
+
+ return *prate * 2;
+}
+
/* OMAP3/4 non-CORE DPLL clkops */
const struct clk_hw_omap_ops clkhwops_omap3_dpll = {
.allow_idle = omap3_dpll_allow_idle,
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index d24926e6340f..ab43755364f5 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1339,7 +1339,7 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
of_property_read_bool(np, "gpmc,time-para-granularity");
}
-#ifdef CONFIG_MTD_NAND
+#if IS_ENABLED(CONFIG_MTD_NAND)
static const char * const nand_xfer_types[] = {
[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
@@ -1429,7 +1429,7 @@ static int gpmc_probe_nand_child(struct platform_device *pdev,
}
#endif
-#ifdef CONFIG_MTD_ONENAND
+#if IS_ENABLED(CONFIG_MTD_ONENAND)
static int gpmc_probe_onenand_child(struct platform_device *pdev,
struct device_node *child)
{
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index d408b15b4fbf..af432b191255 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -179,15 +179,6 @@ static struct map_desc omap34xx_io_desc[] __initdata = {
.length = L4_EMU_34XX_SIZE,
.type = MT_DEVICE
},
-#if defined(CONFIG_DEBUG_LL) && \
- (defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3))
- {
- .virtual = ZOOM_UART_VIRT,
- .pfn = __phys_to_pfn(ZOOM_UART_BASE),
- .length = SZ_1M,
- .type = MT_DEVICE
- },
-#endif
};
#endif
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 42d81885c700..1f33f5db10d5 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1947,29 +1947,31 @@ static int _ocp_softreset(struct omap_hwmod *oh)
goto dis_opt_clks;
_write_sysconfig(v, oh);
- ret = _clear_softreset(oh, &v);
- if (ret)
- goto dis_opt_clks;
-
- _write_sysconfig(v, oh);
if (oh->class->sysc->srst_udelay)
udelay(oh->class->sysc->srst_udelay);
c = _wait_softreset_complete(oh);
- if (c == MAX_MODULE_SOFTRESET_WAIT)
+ if (c == MAX_MODULE_SOFTRESET_WAIT) {
pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n",
oh->name, MAX_MODULE_SOFTRESET_WAIT);
- else
+ ret = -ETIMEDOUT;
+ goto dis_opt_clks;
+ } else {
pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c);
+ }
+
+ ret = _clear_softreset(oh, &v);
+ if (ret)
+ goto dis_opt_clks;
+
+ _write_sysconfig(v, oh);
/*
* XXX add _HWMOD_STATE_WEDGED for modules that don't come back from
* _wait_target_ready() or _reset()
*/
- ret = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
-
dis_opt_clks:
if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
_disable_optional_clocks(oh);
diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
index 18f333c440db..810c205d668b 100644
--- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
@@ -1365,11 +1365,10 @@ static struct omap_hwmod_class_sysconfig dra7xx_spinlock_sysc = {
.rev_offs = 0x0000,
.sysc_offs = 0x0010,
.syss_offs = 0x0014,
- .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
- SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
- SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
- .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
- SIDLE_SMART_WKUP),
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+ SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index 3d5b24dcd9a4..c33e07e2f0d4 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -22,6 +22,8 @@
#include "common-board-devices.h"
#include "dss-common.h"
#include "control.h"
+#include "omap-secure.h"
+#include "soc.h"
struct pdata_init {
const char *compatible;
@@ -169,6 +171,22 @@ static void __init am3517_evm_legacy_init(void)
omap_ctrl_writel(v, AM35XX_CONTROL_IP_SW_RESET);
omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); /* OCP barrier */
}
+
+static void __init nokia_n900_legacy_init(void)
+{
+ hsmmc2_internal_input_clk();
+
+ if (omap_type() == OMAP2_DEVICE_TYPE_SEC) {
+ if (IS_ENABLED(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);
+ } else {
+ pr_warning("RX-51: Not enabling ARM errata 430973 workaround\n");
+ pr_warning("Thumb binaries may crash randomly without this workaround\n");
+ }
+ }
+}
#endif /* CONFIG_ARCH_OMAP3 */
#ifdef CONFIG_ARCH_OMAP4
@@ -239,6 +257,7 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
#endif
#ifdef CONFIG_ARCH_OMAP3
OF_DEV_AUXDATA("ti,omap3-padconf", 0x48002030, "48002030.pinmux", &pcs_pdata),
+ OF_DEV_AUXDATA("ti,omap3-padconf", 0x480025a0, "480025a0.pinmux", &pcs_pdata),
OF_DEV_AUXDATA("ti,omap3-padconf", 0x48002a00, "48002a00.pinmux", &pcs_pdata),
/* Only on am3517 */
OF_DEV_AUXDATA("ti,davinci_mdio", 0x5c030000, "davinci_mdio.0", NULL),
@@ -259,7 +278,7 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
static struct pdata_init pdata_quirks[] __initdata = {
#ifdef CONFIG_ARCH_OMAP3
{ "compulab,omap3-sbc-t3730", omap3_sbc_t3730_legacy_init, },
- { "nokia,omap3-n900", hsmmc2_internal_input_clk, },
+ { "nokia,omap3-n900", nokia_n900_legacy_init, },
{ "nokia,omap3-n9", hsmmc2_internal_input_clk, },
{ "nokia,omap3-n950", hsmmc2_internal_input_clk, },
{ "isee,omap3-igep0020", omap3_igep0020_legacy_init, },
diff --git a/arch/arm/mach-omap2/prminst44xx.c b/arch/arm/mach-omap2/prminst44xx.c
index 6334b96b4097..280f3c58abe5 100644
--- a/arch/arm/mach-omap2/prminst44xx.c
+++ b/arch/arm/mach-omap2/prminst44xx.c
@@ -183,11 +183,11 @@ void omap4_prminst_global_warm_sw_reset(void)
OMAP4_PRM_RSTCTRL_OFFSET);
v |= OMAP4430_RST_GLOBAL_WARM_SW_MASK;
omap4_prminst_write_inst_reg(v, OMAP4430_PRM_PARTITION,
- OMAP4430_PRM_DEVICE_INST,
+ dev_inst,
OMAP4_PRM_RSTCTRL_OFFSET);
/* OCP barrier */
v = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
- OMAP4430_PRM_DEVICE_INST,
+ dev_inst,
OMAP4_PRM_RSTCTRL_OFFSET);
}
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index f70583fee59f..29997bde277d 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -38,6 +38,7 @@
#include <linux/mtd/physmap.h>
#include <linux/usb/gpio_vbus.h>
#include <linux/reboot.h>
+#include <linux/regulator/fixed.h>
#include <linux/regulator/max1586.h>
#include <linux/slab.h>
#include <linux/i2c/pxa-i2c.h>
@@ -714,6 +715,10 @@ static struct gpio global_gpios[] = {
{ GPIO56_MT9M111_nOE, GPIOF_OUT_INIT_LOW, "Camera nOE" },
};
+static struct regulator_consumer_supply fixed_5v0_consumers[] = {
+ REGULATOR_SUPPLY("power", "pwm-backlight"),
+};
+
static void __init mioa701_machine_init(void)
{
int rc;
@@ -753,6 +758,10 @@ static void __init mioa701_machine_init(void)
pxa_set_i2c_info(&i2c_pdata);
pxa27x_set_i2c_power_info(NULL);
pxa_set_camera_info(&mioa701_pxacamera_platform_data);
+
+ regulator_register_always_on(0, "fixed-5.0V", fixed_5v0_consumers,
+ ARRAY_SIZE(fixed_5v0_consumers),
+ 5000000);
}
static void mioa701_machine_exit(void)
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
index 29905b127ad9..41f27f667ca8 100644
--- a/arch/arm/mach-pxa/viper.c
+++ b/arch/arm/mach-pxa/viper.c
@@ -885,9 +885,6 @@ static int viper_cpufreq_notifier(struct notifier_block *nb,
viper_set_core_cpu_voltage(freq->new, 0);
}
break;
- case CPUFREQ_RESUMECHANGE:
- viper_set_core_cpu_voltage(freq->new, 0);
- break;
default:
/* ignore */
break;
diff --git a/arch/arm/mach-sa1100/include/mach/collie.h b/arch/arm/mach-sa1100/include/mach/collie.h
index f33679d2d3ee..50e1d850ee2e 100644
--- a/arch/arm/mach-sa1100/include/mach/collie.h
+++ b/arch/arm/mach-sa1100/include/mach/collie.h
@@ -13,6 +13,8 @@
#ifndef __ASM_ARCH_COLLIE_H
#define __ASM_ARCH_COLLIE_H
+#include "hardware.h" /* Gives GPIO_MAX */
+
extern void locomolcd_power(int on);
#define COLLIE_SCOOP_GPIO_BASE (GPIO_MAX + 1)
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 05fa505df585..3b8c87461d67 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -24,17 +24,21 @@ comment "Renesas ARM SoCs System Type"
config ARCH_EMEV2
bool "Emma Mobile EV2"
+ select SYS_SUPPORTS_EM_STI
config ARCH_R7S72100
bool "RZ/A1H (R7S72100)"
+ select SYS_SUPPORTS_SH_MTU2
config ARCH_R8A7790
bool "R-Car H2 (R8A77900)"
select RENESAS_IRQC
+ select SYS_SUPPORTS_SH_CMT
config ARCH_R8A7791
bool "R-Car M2 (R8A77910)"
select RENESAS_IRQC
+ select SYS_SUPPORTS_SH_CMT
comment "Renesas ARM SoCs Board Type"
@@ -68,6 +72,8 @@ config ARCH_SH7372
select ARM_CPU_SUSPEND if PM || CPU_IDLE
select CPU_V7
select SH_CLK_CPG
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_TMU
config ARCH_SH73A0
bool "SH-Mobile AG5 (R8A73A00)"
@@ -77,6 +83,8 @@ config ARCH_SH73A0
select I2C
select SH_CLK_CPG
select RENESAS_INTC_IRQPIN
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_TMU
config ARCH_R8A73A4
bool "R-Mobile APE6 (R8A73A40)"
@@ -87,6 +95,8 @@ config ARCH_R8A73A4
select RENESAS_IRQC
select ARCH_HAS_CPUFREQ
select ARCH_HAS_OPP
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_TMU
config ARCH_R8A7740
bool "R-Mobile A1 (R8A77400)"
@@ -95,6 +105,8 @@ config ARCH_R8A7740
select CPU_V7
select SH_CLK_CPG
select RENESAS_INTC_IRQPIN
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_TMU
config ARCH_R8A7778
bool "R-Car M1A (R8A77781)"
@@ -102,8 +114,7 @@ config ARCH_R8A7778
select CPU_V7
select SH_CLK_CPG
select ARM_GIC
- select USB_ARCH_HAS_EHCI
- select USB_ARCH_HAS_OHCI
+ select SYS_SUPPORTS_SH_TMU
config ARCH_R8A7779
bool "R-Car H1 (R8A77790)"
@@ -111,9 +122,8 @@ config ARCH_R8A7779
select ARM_GIC
select CPU_V7
select SH_CLK_CPG
- select USB_ARCH_HAS_EHCI
- select USB_ARCH_HAS_OHCI
select RENESAS_INTC_IRQPIN
+ select SYS_SUPPORTS_SH_TMU
config ARCH_R8A7790
bool "R-Car H2 (R8A77900)"
@@ -123,6 +133,7 @@ config ARCH_R8A7790
select MIGHT_HAVE_PCI
select SH_CLK_CPG
select RENESAS_IRQC
+ select SYS_SUPPORTS_SH_CMT
config ARCH_R8A7791
bool "R-Car M2 (R8A77910)"
@@ -132,6 +143,7 @@ config ARCH_R8A7791
select MIGHT_HAVE_PCI
select SH_CLK_CPG
select RENESAS_IRQC
+ select SYS_SUPPORTS_SH_CMT
config ARCH_EMEV2
bool "Emma Mobile EV2"
@@ -141,6 +153,7 @@ config ARCH_EMEV2
select MIGHT_HAVE_PCI
select USE_OF
select AUTO_ZRELADDR
+ select SYS_SUPPORTS_EM_STI
config ARCH_R7S72100
bool "RZ/A1H (R7S72100)"
@@ -148,6 +161,7 @@ config ARCH_R7S72100
select ARM_GIC
select CPU_V7
select SH_CLK_CPG
+ select SYS_SUPPORTS_SH_MTU2
comment "Renesas ARM SoCs Board Type"
@@ -321,24 +335,6 @@ config SHMOBILE_TIMER_HZ
want to select a HZ value such as 128 that can evenly divide RCLK.
A HZ value that does not divide evenly may cause timer drift.
-config SH_TIMER_CMT
- bool "CMT timer driver"
- default y
- help
- This enables build of the CMT timer driver.
-
-config SH_TIMER_TMU
- bool "TMU timer driver"
- default y
- help
- This enables build of the TMU timer driver.
-
-config EM_TIMER_STI
- bool "STI timer driver"
- default y
- help
- This enables build of the STI timer driver.
-
endmenu
endif
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index 93533e2710a8..9323854242ca 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -988,14 +988,12 @@ static struct asoc_simple_card_info fsi_wm8978_info = {
.card = "FSI2A-WM8978",
.codec = "wm8978.0-001a",
.platform = "sh_fsi2",
- .daifmt = SND_SOC_DAIFMT_I2S,
+ .daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
.cpu_dai = {
.name = "fsia-dai",
- .fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
},
.codec_dai = {
.name = "wm8978-hifi",
- .fmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF,
.sysclk = 12288000,
},
};
diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c
index c475220545f2..74c27d9d6900 100644
--- a/arch/arm/mach-shmobile/board-bockw.c
+++ b/arch/arm/mach-shmobile/board-bockw.c
@@ -429,14 +429,12 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
.card = "SSI56-AK4643",
.codec = "ak4642-codec.0-0012",
.platform = "rcar_sound",
- .daifmt = SND_SOC_DAIFMT_LEFT_J,
+ .daifmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
.cpu_dai = {
.name = "rsnd-dai.0",
- .fmt = SND_SOC_DAIFMT_CBS_CFS,
},
.codec_dai = {
.name = "ak4642-hifi",
- .fmt = SND_SOC_DAIFMT_CBM_CFM,
.sysclk = 11289600,
},
},
@@ -446,10 +444,9 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
.card = "SSI3-AK4554(playback)",
.codec = "ak4554-adc-dac.0",
.platform = "rcar_sound",
+ .daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_RIGHT_J,
.cpu_dai = {
.name = "rsnd-dai.1",
- .fmt = SND_SOC_DAIFMT_CBM_CFM |
- SND_SOC_DAIFMT_RIGHT_J,
},
.codec_dai = {
.name = "ak4554-hifi",
@@ -461,10 +458,9 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
.card = "SSI4-AK4554(capture)",
.codec = "ak4554-adc-dac.0",
.platform = "rcar_sound",
+ .daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_LEFT_J,
.cpu_dai = {
.name = "rsnd-dai.2",
- .fmt = SND_SOC_DAIFMT_CBM_CFM |
- SND_SOC_DAIFMT_LEFT_J,
},
.codec_dai = {
.name = "ak4554-hifi",
@@ -476,10 +472,9 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
.card = "SSI7-AK4554(playback)",
.codec = "ak4554-adc-dac.1",
.platform = "rcar_sound",
+ .daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_RIGHT_J,
.cpu_dai = {
.name = "rsnd-dai.3",
- .fmt = SND_SOC_DAIFMT_CBM_CFM |
- SND_SOC_DAIFMT_RIGHT_J,
},
.codec_dai = {
.name = "ak4554-hifi",
@@ -491,10 +486,9 @@ static struct asoc_simple_card_info rsnd_card_info[] = {
.card = "SSI8-AK4554(capture)",
.codec = "ak4554-adc-dac.1",
.platform = "rcar_sound",
+ .daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_LEFT_J,
.cpu_dai = {
.name = "rsnd-dai.4",
- .fmt = SND_SOC_DAIFMT_CBM_CFM |
- SND_SOC_DAIFMT_LEFT_J,
},
.codec_dai = {
.name = "ak4554-hifi",
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
index bc40b853ffd3..03dc3ac84502 100644
--- a/arch/arm/mach-shmobile/board-kzm9g.c
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -589,14 +589,12 @@ static struct asoc_simple_card_info fsi2_ak4648_info = {
.card = "FSI2A-AK4648",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi2",
- .daifmt = SND_SOC_DAIFMT_LEFT_J,
+ .daifmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
.cpu_dai = {
.name = "fsia-dai",
- .fmt = SND_SOC_DAIFMT_CBS_CFS,
},
.codec_dai = {
.name = "ak4642-hifi",
- .fmt = SND_SOC_DAIFMT_CBM_CFM,
.sysclk = 11289600,
},
};
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 3aba0372f630..0ff4d8e45cf7 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -509,9 +509,9 @@ static struct asoc_simple_card_info fsi2_hdmi_info = {
.card = "FSI2B-HDMI",
.codec = "sh-mobile-hdmi",
.platform = "sh_fsi2",
+ .daifmt = SND_SOC_DAIFMT_CBS_CFS,
.cpu_dai = {
.name = "fsib-dai",
- .fmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF,
},
.codec_dai = {
.name = "sh_mobile_hdmi-hifi",
@@ -905,14 +905,12 @@ static struct asoc_simple_card_info fsi2_ak4643_info = {
.card = "FSI2A-AK4643",
.codec = "ak4642-codec.0-0013",
.platform = "sh_fsi2",
- .daifmt = SND_SOC_DAIFMT_LEFT_J,
+ .daifmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
.cpu_dai = {
.name = "fsia-dai",
- .fmt = SND_SOC_DAIFMT_CBS_CFS,
},
.codec_dai = {
.name = "ak4642-hifi",
- .fmt = SND_SOC_DAIFMT_CBM_CFM,
.sysclk = 11289600,
},
};
diff --git a/arch/arm/mach-spear/spear1310.c b/arch/arm/mach-spear/spear1310.c
index 7ad003001ab7..824b12a56a42 100644
--- a/arch/arm/mach-spear/spear1310.c
+++ b/arch/arm/mach-spear/spear1310.c
@@ -28,6 +28,7 @@
static void __init spear1310_dt_init(void)
{
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ platform_device_register_simple("spear-cpufreq", -1, NULL, 0);
}
static const char * const spear1310_dt_board_compat[] = {
diff --git a/arch/arm/mach-spear/spear1340.c b/arch/arm/mach-spear/spear1340.c
index 3fb683424729..7b6bff7154e1 100644
--- a/arch/arm/mach-spear/spear1340.c
+++ b/arch/arm/mach-spear/spear1340.c
@@ -143,6 +143,7 @@ static void __init spear1340_dt_init(void)
{
of_platform_populate(NULL, of_default_bus_match_table,
spear1340_auxdata_lookup, NULL);
+ platform_device_register_simple("spear-cpufreq", -1, NULL, 0);
}
static const char * const spear1340_dt_board_compat[] = {
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index b1232d8be6f5..4926bd11f190 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -19,7 +19,6 @@ config ARCH_TEGRA
select RESET_CONTROLLER
select SOC_BUS
select SPARSE_IRQ
- select USB_ARCH_HAS_EHCI if USB_SUPPORT
select USB_ULPI if USB_PHY
select USB_ULPI_VIEWPORT if USB_PHY
select USE_OF
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index 4ae0286b468d..f55b05a29b55 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -24,6 +24,7 @@
#include <linux/cpu_pm.h>
#include <linux/suspend.h>
#include <linux/err.h>
+#include <linux/slab.h>
#include <linux/clk/tegra.h>
#include <asm/smp_plat.h>
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index 303a285d80fd..6191603379e1 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -73,10 +73,20 @@ u32 tegra_uart_config[3] = {
static void __init tegra_init_cache(void)
{
#ifdef CONFIG_CACHE_L2X0
+ static const struct of_device_id pl310_ids[] __initconst = {
+ { .compatible = "arm,pl310-cache", },
+ {}
+ };
+
+ struct device_node *np;
int ret;
void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
u32 aux_ctrl, cache_type;
+ np = of_find_matching_node(NULL, pl310_ids);
+ if (!np)
+ return;
+
cache_type = readl(p + L2X0_CACHE_TYPE);
aux_ctrl = (cache_type & 0x700) << (17-8);
aux_ctrl |= 0x7C400001;
diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile
index 0f362b64fb87..3ec74ac95bc1 100644
--- a/arch/arm/mach-u300/Makefile
+++ b/arch/arm/mach-u300/Makefile
@@ -2,7 +2,7 @@
# Makefile for the linux kernel, U300 machine.
#
-obj-y := core.o timer.o
+obj-y := core.o
obj-m :=
obj-n :=
obj- :=
diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig
index 6b04260aa142..f03e75bd0b2b 100644
--- a/arch/arm/mach-zynq/Kconfig
+++ b/arch/arm/mach-zynq/Kconfig
@@ -2,6 +2,8 @@ config ARCH_ZYNQ
bool "Xilinx Zynq ARM Cortex A9 Platform" if ARCH_MULTI_V7
select ARM_AMBA
select ARM_GIC
+ select ARCH_HAS_CPUFREQ
+ select ARCH_HAS_OPP
select COMMON_CLK
select CPU_V7
select GENERIC_CLOCKEVENTS
@@ -13,6 +15,6 @@ config ARCH_ZYNQ
select HAVE_SMP
select SPARSE_IRQ
select CADENCE_TTC_TIMER
- select ARM_GLOBAL_TIMER
+ select ARM_GLOBAL_TIMER if !CPU_FREQ
help
Support for Xilinx Zynq ARM Cortex A9 Platform
diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c
index 8c09a8393fb6..a39be8e80856 100644
--- a/arch/arm/mach-zynq/common.c
+++ b/arch/arm/mach-zynq/common.c
@@ -64,6 +64,8 @@ static struct platform_device zynq_cpuidle_device = {
*/
static void __init zynq_init_machine(void)
{
+ struct platform_device_info devinfo = { .name = "cpufreq-cpu0", };
+
/*
* 64KB way size, 8-way associativity, parity disabled
*/
@@ -72,6 +74,7 @@ static void __init zynq_init_machine(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
platform_device_register(&zynq_cpuidle_device);
+ platform_device_register_full(&devinfo);
}
static void __init zynq_timer_init(void)
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 1a77450e728a..4fe42ce720d2 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -1069,6 +1069,8 @@ fs_initcall(dma_debug_do_init);
/* IOMMU */
+static int extend_iommu_mapping(struct dma_iommu_mapping *mapping);
+
static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
size_t size)
{
@@ -1076,41 +1078,87 @@ static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
unsigned int align = 0;
unsigned int count, start;
unsigned long flags;
+ dma_addr_t iova;
+ int i;
if (order > CONFIG_ARM_DMA_IOMMU_ALIGNMENT)
order = CONFIG_ARM_DMA_IOMMU_ALIGNMENT;
- count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
- (1 << mapping->order) - 1) >> mapping->order;
-
- if (order > mapping->order)
- align = (1 << (order - mapping->order)) - 1;
+ count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ align = (1 << order) - 1;
spin_lock_irqsave(&mapping->lock, flags);
- start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0,
- count, align);
- if (start > mapping->bits) {
- spin_unlock_irqrestore(&mapping->lock, flags);
- return DMA_ERROR_CODE;
+ for (i = 0; i < mapping->nr_bitmaps; i++) {
+ start = bitmap_find_next_zero_area(mapping->bitmaps[i],
+ mapping->bits, 0, count, align);
+
+ if (start > mapping->bits)
+ continue;
+
+ bitmap_set(mapping->bitmaps[i], start, count);
+ break;
}
- bitmap_set(mapping->bitmap, start, count);
+ /*
+ * No unused range found. Try to extend the existing mapping
+ * and perform a second attempt to reserve an IO virtual
+ * address range of size bytes.
+ */
+ if (i == mapping->nr_bitmaps) {
+ if (extend_iommu_mapping(mapping)) {
+ spin_unlock_irqrestore(&mapping->lock, flags);
+ return DMA_ERROR_CODE;
+ }
+
+ start = bitmap_find_next_zero_area(mapping->bitmaps[i],
+ mapping->bits, 0, count, align);
+
+ if (start > mapping->bits) {
+ spin_unlock_irqrestore(&mapping->lock, flags);
+ return DMA_ERROR_CODE;
+ }
+
+ bitmap_set(mapping->bitmaps[i], start, count);
+ }
spin_unlock_irqrestore(&mapping->lock, flags);
- return mapping->base + (start << (mapping->order + PAGE_SHIFT));
+ iova = mapping->base + (mapping->size * i);
+ iova += start << PAGE_SHIFT;
+
+ return iova;
}
static inline void __free_iova(struct dma_iommu_mapping *mapping,
dma_addr_t addr, size_t size)
{
- unsigned int start = (addr - mapping->base) >>
- (mapping->order + PAGE_SHIFT);
- unsigned int count = ((size >> PAGE_SHIFT) +
- (1 << mapping->order) - 1) >> mapping->order;
+ unsigned int start, count;
unsigned long flags;
+ dma_addr_t bitmap_base;
+ u32 bitmap_index;
+
+ if (!size)
+ return;
+
+ bitmap_index = (u32) (addr - mapping->base) / (u32) mapping->size;
+ BUG_ON(addr < mapping->base || bitmap_index > mapping->extensions);
+
+ bitmap_base = mapping->base + mapping->size * bitmap_index;
+
+ start = (addr - bitmap_base) >> PAGE_SHIFT;
+
+ if (addr + size > bitmap_base + mapping->size) {
+ /*
+ * The address range to be freed reaches into the iova
+ * range of the next bitmap. This should not happen as
+ * we don't allow this in __alloc_iova (at the
+ * moment).
+ */
+ BUG();
+ } else
+ count = size >> PAGE_SHIFT;
spin_lock_irqsave(&mapping->lock, flags);
- bitmap_clear(mapping->bitmap, start, count);
+ bitmap_clear(mapping->bitmaps[bitmap_index], start, count);
spin_unlock_irqrestore(&mapping->lock, flags);
}
@@ -1358,7 +1406,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
*handle = DMA_ERROR_CODE;
size = PAGE_ALIGN(size);
- if (gfp & GFP_ATOMIC)
+ if (!(gfp & __GFP_WAIT))
return __iommu_alloc_atomic(dev, size, handle);
/*
@@ -1875,8 +1923,7 @@ struct dma_map_ops iommu_coherent_ops = {
* arm_iommu_create_mapping
* @bus: pointer to the bus holding the client device (for IOMMU calls)
* @base: start address of the valid IO address space
- * @size: size of the valid IO address space
- * @order: accuracy of the IO addresses allocations
+ * @size: maximum size of the valid IO address space
*
* Creates a mapping structure which holds information about used/unused
* IO address ranges, which is required to perform memory allocation and
@@ -1886,38 +1933,54 @@ struct dma_map_ops iommu_coherent_ops = {
* arm_iommu_attach_device function.
*/
struct dma_iommu_mapping *
-arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size,
- int order)
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
{
- unsigned int count = size >> (PAGE_SHIFT + order);
- unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
+ unsigned int bits = size >> PAGE_SHIFT;
+ unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long);
struct dma_iommu_mapping *mapping;
+ int extensions = 1;
int err = -ENOMEM;
- if (!count)
+ if (!bitmap_size)
return ERR_PTR(-EINVAL);
+ if (bitmap_size > PAGE_SIZE) {
+ extensions = bitmap_size / PAGE_SIZE;
+ bitmap_size = PAGE_SIZE;
+ }
+
mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL);
if (!mapping)
goto err;
- mapping->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
- if (!mapping->bitmap)
+ mapping->bitmap_size = bitmap_size;
+ mapping->bitmaps = kzalloc(extensions * sizeof(unsigned long *),
+ GFP_KERNEL);
+ if (!mapping->bitmaps)
goto err2;
+ mapping->bitmaps[0] = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!mapping->bitmaps[0])
+ goto err3;
+
+ mapping->nr_bitmaps = 1;
+ mapping->extensions = extensions;
mapping->base = base;
+ mapping->size = bitmap_size << PAGE_SHIFT;
mapping->bits = BITS_PER_BYTE * bitmap_size;
- mapping->order = order;
+
spin_lock_init(&mapping->lock);
mapping->domain = iommu_domain_alloc(bus);
if (!mapping->domain)
- goto err3;
+ goto err4;
kref_init(&mapping->kref);
return mapping;
+err4:
+ kfree(mapping->bitmaps[0]);
err3:
- kfree(mapping->bitmap);
+ kfree(mapping->bitmaps);
err2:
kfree(mapping);
err:
@@ -1927,14 +1990,35 @@ EXPORT_SYMBOL_GPL(arm_iommu_create_mapping);
static void release_iommu_mapping(struct kref *kref)
{
+ int i;
struct dma_iommu_mapping *mapping =
container_of(kref, struct dma_iommu_mapping, kref);
iommu_domain_free(mapping->domain);
- kfree(mapping->bitmap);
+ for (i = 0; i < mapping->nr_bitmaps; i++)
+ kfree(mapping->bitmaps[i]);
+ kfree(mapping->bitmaps);
kfree(mapping);
}
+static int extend_iommu_mapping(struct dma_iommu_mapping *mapping)
+{
+ int next_bitmap;
+
+ if (mapping->nr_bitmaps > mapping->extensions)
+ return -EINVAL;
+
+ next_bitmap = mapping->nr_bitmaps;
+ mapping->bitmaps[next_bitmap] = kzalloc(mapping->bitmap_size,
+ GFP_ATOMIC);
+ if (!mapping->bitmaps[next_bitmap])
+ return -ENOMEM;
+
+ mapping->nr_bitmaps++;
+
+ return 0;
+}
+
void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
{
if (mapping)
diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c
index 2b3a56414271..ef69152f9b52 100644
--- a/arch/arm/mm/dump.c
+++ b/arch/arm/mm/dump.c
@@ -264,6 +264,9 @@ static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
note_page(st, addr, 3, pmd_val(*pmd));
else
walk_pte(st, pmd, addr);
+
+ if (SECTION_SIZE < PMD_SIZE && pmd_large(pmd[1]))
+ note_page(st, addr + SECTION_SIZE, 3, pmd_val(pmd[1]));
}
}
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 804d61566a53..2a77ba8796ae 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -323,6 +323,8 @@ void __init arm_memblock_init(struct meminfo *mi,
if (mdesc->reserve)
mdesc->reserve();
+ early_init_fdt_scan_reserved_mem();
+
/*
* reserve memory for DMA contigouos allocations,
* must come from DMA area inside low memory
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index d5a982d15a88..7ea641b7aa7d 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -38,6 +38,7 @@ static inline pmd_t *pmd_off_k(unsigned long virt)
struct mem_type {
pteval_t prot_pte;
+ pteval_t prot_pte_s2;
pmdval_t prot_l1;
pmdval_t prot_sect;
unsigned int domain;
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 4f08c133cc25..a623cb3ad012 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -232,12 +232,16 @@ __setup("noalign", noalign_setup);
#endif /* ifdef CONFIG_CPU_CP15 / else */
#define PROT_PTE_DEVICE L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_XN
+#define PROT_PTE_S2_DEVICE PROT_PTE_DEVICE
#define PROT_SECT_DEVICE PMD_TYPE_SECT|PMD_SECT_AP_WRITE
static struct mem_type mem_types[] = {
[MT_DEVICE] = { /* Strongly ordered / ARMv6 shared device */
.prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED |
L_PTE_SHARED,
+ .prot_pte_s2 = s2_policy(PROT_PTE_S2_DEVICE) |
+ s2_policy(L_PTE_S2_MT_DEV_SHARED) |
+ L_PTE_SHARED,
.prot_l1 = PMD_TYPE_TABLE,
.prot_sect = PROT_SECT_DEVICE | PMD_SECT_S,
.domain = DOMAIN_IO,
@@ -508,7 +512,8 @@ static void __init build_mem_type_table(void)
cp = &cache_policies[cachepolicy];
vecs_pgprot = kern_pgprot = user_pgprot = cp->pte;
s2_pgprot = cp->pte_s2;
- hyp_device_pgprot = s2_device_pgprot = mem_types[MT_DEVICE].prot_pte;
+ hyp_device_pgprot = mem_types[MT_DEVICE].prot_pte;
+ s2_device_pgprot = mem_types[MT_DEVICE].prot_pte_s2;
/*
* ARMv6 and above have extended page tables.
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 45dc29f85d56..32b3558321c4 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -208,7 +208,6 @@ __v6_setup:
mcr p15, 0, r0, c7, c14, 0 @ clean+invalidate D cache
mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
mcr p15, 0, r0, c7, c15, 0 @ clean+invalidate cache
- mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs
mcr p15, 0, r0, c2, c0, 2 @ TTB control register
@@ -218,6 +217,8 @@ __v6_setup:
ALT_UP(orr r8, r8, #TTB_FLAGS_UP)
mcr p15, 0, r8, c2, c0, 1 @ load TTB1
#endif /* CONFIG_MMU */
+ mcr p15, 0, r0, c7, c10, 4 @ drain write buffer and
+ @ complete invalidations
adr r5, v6_crval
ldmia r5, {r5, r6}
ARM_BE8(orr r6, r6, #1 << 25) @ big-endian page tables
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index bd1781979a39..74f6033e76dd 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -351,7 +351,6 @@ __v7_setup:
4: mov r10, #0
mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate
- dsb
#ifdef CONFIG_MMU
mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs
v7_ttb_setup r10, r4, r8, r5 @ TTBCR, TTBRx setup
@@ -360,6 +359,7 @@ __v7_setup:
mcr p15, 0, r5, c10, c2, 0 @ write PRRR
mcr p15, 0, r6, c10, c2, 1 @ write NMRR
#endif
+ dsb @ Complete invalidations
#ifndef CONFIG_ARM_THUMBEE
mrc p15, 0, r0, c0, c1, 0 @ read ID_PFR0 for ThumbEE
and r0, r0, #(0xf << 12) @ ThumbEE enabled field
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 27bbcfc7202a..9711a5fd948d 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -16,6 +16,7 @@ config ARM64
select DCACHE_WORD_ACCESS
select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+ select GENERIC_CPU_AUTOPROBE
select GENERIC_IOMAP
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
@@ -26,6 +27,7 @@ config ARM64
select GENERIC_TIME_VSYSCALL
select HARDIRQS_SW_RESEND
select HAVE_ARCH_JUMP_LABEL
+ select HAVE_ARCH_KGDB
select HAVE_ARCH_TRACEHOOK
select HAVE_DEBUG_BUGVERBOSE
select HAVE_DEBUG_KMEMLEAK
@@ -38,11 +40,14 @@ config ARM64
select HAVE_MEMBLOCK
select HAVE_PATA_PLATFORM
select HAVE_PERF_EVENTS
+ select HAVE_PERF_REGS
+ select HAVE_PERF_USER_STACK_DUMP
select IRQ_DOMAIN
select MODULES_USE_ELF_RELA
select NO_BOOTMEM
select OF
select OF_EARLY_FLATTREE
+ select OF_RESERVED_MEM
select PERF_USE_VMALLOC
select POWER_RESET
select POWER_SUPPLY
@@ -73,7 +78,7 @@ config LOCKDEP_SUPPORT
config TRACE_IRQFLAGS_SUPPORT
def_bool y
-config RWSEM_GENERIC_SPINLOCK
+config RWSEM_XCHGADD_ALGORITHM
def_bool y
config GENERIC_HWEIGHT
@@ -85,7 +90,7 @@ config GENERIC_CSUM
config GENERIC_CALIBRATE_DELAY
def_bool y
-config ZONE_DMA32
+config ZONE_DMA
def_bool y
config ARCH_DMA_ADDR_T_64BIT
@@ -164,6 +169,22 @@ config SMP
If you don't know what to do here, say N.
+config SCHED_MC
+ bool "Multi-core scheduler support"
+ depends on SMP
+ help
+ Multi-core scheduler support improves the CPU scheduler's decision
+ making when dealing with multi-core CPU chips at a cost of slightly
+ increased overhead in some places. If unsure say N here.
+
+config SCHED_SMT
+ bool "SMT scheduler support"
+ depends on SMP
+ help
+ Improves the CPU scheduler's decision making when dealing with
+ MultiThreading at a cost of slightly increased overhead in some
+ places. If unsure say N here.
+
config NR_CPUS
int "Maximum number of CPUs (2-32)"
range 2 32
@@ -301,6 +322,10 @@ menu "CPU Power Management"
source "drivers/cpuidle/Kconfig"
+source "kernel/power/Kconfig"
+
+source "drivers/cpufreq/Kconfig"
+
endmenu
source "net/Kconfig"
diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi
index d37d7369e260..93f4b2dd9248 100644
--- a/arch/arm64/boot/dts/apm-storm.dtsi
+++ b/arch/arm64/boot/dts/apm-storm.dtsi
@@ -176,6 +176,87 @@
reg-names = "csr-reg";
clock-output-names = "eth8clk";
};
+
+ sataphy1clk: sataphy1clk@1f21c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f21c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sataphy1clk";
+ status = "disabled";
+ csr-offset = <0x4>;
+ csr-mask = <0x00>;
+ enable-offset = <0x0>;
+ enable-mask = <0x06>;
+ };
+
+ sataphy2clk: sataphy1clk@1f22c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f22c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sataphy2clk";
+ status = "ok";
+ csr-offset = <0x4>;
+ csr-mask = <0x3a>;
+ enable-offset = <0x0>;
+ enable-mask = <0x06>;
+ };
+
+ sataphy3clk: sataphy1clk@1f23c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f23c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sataphy3clk";
+ status = "ok";
+ csr-offset = <0x4>;
+ csr-mask = <0x3a>;
+ enable-offset = <0x0>;
+ enable-mask = <0x06>;
+ };
+
+ sata01clk: sata01clk@1f21c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f21c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sata01clk";
+ csr-offset = <0x4>;
+ csr-mask = <0x05>;
+ enable-offset = <0x0>;
+ enable-mask = <0x39>;
+ };
+
+ sata23clk: sata23clk@1f22c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f22c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sata23clk";
+ csr-offset = <0x4>;
+ csr-mask = <0x05>;
+ enable-offset = <0x0>;
+ enable-mask = <0x39>;
+ };
+
+ sata45clk: sata45clk@1f23c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f23c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sata45clk";
+ csr-offset = <0x4>;
+ csr-mask = <0x05>;
+ enable-offset = <0x0>;
+ enable-mask = <0x39>;
+ };
};
serial0: serial@1c020000 {
@@ -187,5 +268,76 @@
interrupt-parent = <&gic>;
interrupts = <0x0 0x4c 0x4>;
};
+
+ phy1: phy@1f21a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f21a000 0x0 0x100>;
+ #phy-cells = <1>;
+ clocks = <&sataphy1clk 0>;
+ status = "disabled";
+ apm,tx-boost-gain = <30 30 30 30 30 30>;
+ apm,tx-eye-tuning = <2 10 10 2 10 10>;
+ };
+
+ phy2: phy@1f22a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f22a000 0x0 0x100>;
+ #phy-cells = <1>;
+ clocks = <&sataphy2clk 0>;
+ status = "ok";
+ apm,tx-boost-gain = <30 30 30 30 30 30>;
+ apm,tx-eye-tuning = <1 10 10 2 10 10>;
+ };
+
+ phy3: phy@1f23a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f23a000 0x0 0x100>;
+ #phy-cells = <1>;
+ clocks = <&sataphy3clk 0>;
+ status = "ok";
+ apm,tx-boost-gain = <31 31 31 31 31 31>;
+ apm,tx-eye-tuning = <2 10 10 2 10 10>;
+ };
+
+ sata1: sata@1a000000 {
+ compatible = "apm,xgene-ahci";
+ reg = <0x0 0x1a000000 0x0 0x1000>,
+ <0x0 0x1f210000 0x0 0x1000>,
+ <0x0 0x1f21d000 0x0 0x1000>,
+ <0x0 0x1f21e000 0x0 0x1000>,
+ <0x0 0x1f217000 0x0 0x1000>;
+ interrupts = <0x0 0x86 0x4>;
+ status = "disabled";
+ clocks = <&sata01clk 0>;
+ phys = <&phy1 0>;
+ phy-names = "sata-phy";
+ };
+
+ sata2: sata@1a400000 {
+ compatible = "apm,xgene-ahci";
+ reg = <0x0 0x1a400000 0x0 0x1000>,
+ <0x0 0x1f220000 0x0 0x1000>,
+ <0x0 0x1f22d000 0x0 0x1000>,
+ <0x0 0x1f22e000 0x0 0x1000>,
+ <0x0 0x1f227000 0x0 0x1000>;
+ interrupts = <0x0 0x87 0x4>;
+ status = "ok";
+ clocks = <&sata23clk 0>;
+ phys = <&phy2 0>;
+ phy-names = "sata-phy";
+ };
+
+ sata3: sata@1a800000 {
+ compatible = "apm,xgene-ahci";
+ reg = <0x0 0x1a800000 0x0 0x1000>,
+ <0x0 0x1f230000 0x0 0x1000>,
+ <0x0 0x1f23d000 0x0 0x1000>,
+ <0x0 0x1f23e000 0x0 0x1000>;
+ interrupts = <0x0 0x88 0x4>;
+ status = "ok";
+ clocks = <&sata45clk 0>;
+ phys = <&phy3 0>;
+ phy-names = "sata-phy";
+ };
};
};
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
index 71c53ecfcc3a..4bca4923fc0b 100644
--- a/arch/arm64/include/asm/Kbuild
+++ b/arch/arm64/include/asm/Kbuild
@@ -12,6 +12,7 @@ generic-y += dma.h
generic-y += emergency-restart.h
generic-y += errno.h
generic-y += ftrace.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
@@ -22,13 +23,16 @@ generic-y += kmap_types.h
generic-y += kvm_para.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += msgbuf.h
generic-y += mutex.h
generic-y += pci.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
+generic-y += rwsem.h
generic-y += scatterlist.h
generic-y += sections.h
generic-y += segment.h
@@ -38,8 +42,8 @@ generic-y += shmbuf.h
generic-y += sizes.h
generic-y += socket.h
generic-y += sockios.h
-generic-y += switch_to.h
generic-y += swab.h
+generic-y += switch_to.h
generic-y += termbits.h
generic-y += termios.h
generic-y += topology.h
@@ -49,5 +53,3 @@ generic-y += unaligned.h
generic-y += user.h
generic-y += vga.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 409ca370cfe2..66eb7648043b 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -25,6 +25,7 @@
#define wfi() asm volatile("wfi" : : : "memory")
#define isb() asm volatile("isb" : : : "memory")
+#define dmb(opt) asm volatile("dmb sy" : : : "memory")
#define dsb(opt) asm volatile("dsb sy" : : : "memory")
#define mb() dsb()
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index 889324981aa4..4c60e64a801c 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -85,6 +85,13 @@ static inline void flush_cache_page(struct vm_area_struct *vma,
}
/*
+ * Cache maintenance functions used by the DMA API. No to be used directly.
+ */
+extern void __dma_map_area(const void *, size_t, int);
+extern void __dma_unmap_area(const void *, size_t, int);
+extern void __dma_flush_range(const void *, const void *);
+
+/*
* Copy user data from/to a page which is mapped into a different
* processes address space. Really, we want to allow our "user
* space" model to handle this.
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index fda2704b3f9f..e71f81fe127a 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -228,7 +228,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
return (u32)(unsigned long)uptr;
}
-#define compat_user_stack_pointer() (current_pt_regs()->compat_sp)
+#define compat_user_stack_pointer() (user_stack_pointer(current_pt_regs()))
static inline void __user *arch_compat_alloc_user_space(long len)
{
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
new file mode 100644
index 000000000000..cd4ac0516488
--- /dev/null
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@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.
+ */
+
+#ifndef __ASM_CPUFEATURE_H
+#define __ASM_CPUFEATURE_H
+
+#include <asm/hwcap.h>
+
+/*
+ * In the arm64 world (as in the ARM world), elf_hwcap is used both internally
+ * in the kernel and for user space to keep track of which optional features
+ * are supported by the current system. So let's map feature 'x' to HWCAP_x.
+ * Note that HWCAP_x constants are bit fields so we need to take the log.
+ */
+
+#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap))
+#define cpu_feature(x) ilog2(HWCAP_ ## x)
+
+static inline bool cpu_have_feature(unsigned int num)
+{
+ return elf_hwcap & (1UL << num);
+}
+
+#endif
diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
index 62314791570c..6e9b5b36921c 100644
--- a/arch/arm64/include/asm/debug-monitors.h
+++ b/arch/arm64/include/asm/debug-monitors.h
@@ -26,6 +26,53 @@
#define DBG_ESR_EVT_HWWP 0x2
#define DBG_ESR_EVT_BRK 0x6
+/*
+ * Break point instruction encoding
+ */
+#define BREAK_INSTR_SIZE 4
+
+/*
+ * ESR values expected for dynamic and compile time BRK instruction
+ */
+#define DBG_ESR_VAL_BRK(x) (0xf2000000 | ((x) & 0xfffff))
+
+/*
+ * #imm16 values used for BRK instruction generation
+ * Allowed values for kgbd are 0x400 - 0x7ff
+ * 0x400: for dynamic BRK instruction
+ * 0x401: for compile time BRK instruction
+ */
+#define KGDB_DYN_DGB_BRK_IMM 0x400
+#define KDBG_COMPILED_DBG_BRK_IMM 0x401
+
+/*
+ * BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+#define AARCH64_BREAK_MON 0xd4200000
+
+/*
+ * Extract byte from BRK instruction
+ */
+#define KGDB_DYN_DGB_BRK_INS_BYTE(x) \
+ ((((AARCH64_BREAK_MON) & 0xffe0001f) >> (x * 8)) & 0xff)
+
+/*
+ * Extract byte from BRK #imm16
+ */
+#define KGBD_DYN_DGB_BRK_IMM_BYTE(x) \
+ (((((KGDB_DYN_DGB_BRK_IMM) & 0xffff) << 5) >> (x * 8)) & 0xff)
+
+#define KGDB_DYN_DGB_BRK_BYTE(x) \
+ (KGDB_DYN_DGB_BRK_INS_BYTE(x) | KGBD_DYN_DGB_BRK_IMM_BYTE(x))
+
+#define KGDB_DYN_BRK_INS_BYTE0 KGDB_DYN_DGB_BRK_BYTE(0)
+#define KGDB_DYN_BRK_INS_BYTE1 KGDB_DYN_DGB_BRK_BYTE(1)
+#define KGDB_DYN_BRK_INS_BYTE2 KGDB_DYN_DGB_BRK_BYTE(2)
+#define KGDB_DYN_BRK_INS_BYTE3 KGDB_DYN_DGB_BRK_BYTE(3)
+
+#define CACHE_FLUSH_IS_SAFE 1
+
enum debug_el {
DBG_ACTIVE_EL0 = 0,
DBG_ACTIVE_EL1,
@@ -43,23 +90,6 @@ enum debug_el {
#ifndef __ASSEMBLY__
struct task_struct;
-#define local_dbg_save(flags) \
- do { \
- typecheck(unsigned long, flags); \
- asm volatile( \
- "mrs %0, daif // local_dbg_save\n" \
- "msr daifset, #8" \
- : "=r" (flags) : : "memory"); \
- } while (0)
-
-#define local_dbg_restore(flags) \
- do { \
- typecheck(unsigned long, flags); \
- asm volatile( \
- "msr daif, %0 // local_dbg_restore\n" \
- : : "r" (flags) : "memory"); \
- } while (0)
-
#define DBG_ARCH_ID_RESERVED 0 /* In case of ptrace ABI updates. */
#define DBG_HOOK_HANDLED 0
diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h
index fd0c0c0e447a..3a4572ec3273 100644
--- a/arch/arm64/include/asm/dma-mapping.h
+++ b/arch/arm64/include/asm/dma-mapping.h
@@ -30,6 +30,8 @@
#define DMA_ERROR_CODE (~(dma_addr_t)0)
extern struct dma_map_ops *dma_ops;
+extern struct dma_map_ops coherent_swiotlb_dma_ops;
+extern struct dma_map_ops noncoherent_swiotlb_dma_ops;
static inline struct dma_map_ops *__generic_dma_ops(struct device *dev)
{
@@ -47,6 +49,11 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
return __generic_dma_ops(dev);
}
+static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
+{
+ dev->archdata.dma_ops = ops;
+}
+
#include <asm-generic/dma-mapping-common.h>
static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 6cddbb0c9f54..024c46183c3c 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -32,6 +32,12 @@
#define COMPAT_HWCAP_IDIV (COMPAT_HWCAP_IDIVA|COMPAT_HWCAP_IDIVT)
#define COMPAT_HWCAP_EVTSTRM (1 << 21)
+#define COMPAT_HWCAP2_AES (1 << 0)
+#define COMPAT_HWCAP2_PMULL (1 << 1)
+#define COMPAT_HWCAP2_SHA1 (1 << 2)
+#define COMPAT_HWCAP2_SHA2 (1 << 3)
+#define COMPAT_HWCAP2_CRC32 (1 << 4)
+
#ifndef __ASSEMBLY__
/*
* This yields a mask that user programs can use to figure out what
@@ -41,7 +47,8 @@
#ifdef CONFIG_COMPAT
#define COMPAT_ELF_HWCAP (compat_elf_hwcap)
-extern unsigned int compat_elf_hwcap;
+#define COMPAT_ELF_HWCAP2 (compat_elf_hwcap2)
+extern unsigned int compat_elf_hwcap, compat_elf_hwcap2;
#endif
extern unsigned long elf_hwcap;
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 4cc813eddacb..7846a6bb0833 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -121,7 +121,7 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
* I/O port access primitives.
*/
#define IO_SPACE_LIMIT 0xffff
-#define PCI_IOBASE ((void __iomem *)(MODULES_VADDR - SZ_2M))
+#define PCI_IOBASE ((void __iomem *)(MODULES_VADDR - SZ_32M))
static inline u8 inb(unsigned long addr)
{
diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h
index b2fcfbc51ecc..11cc941bd107 100644
--- a/arch/arm64/include/asm/irqflags.h
+++ b/arch/arm64/include/asm/irqflags.h
@@ -90,5 +90,28 @@ static inline int arch_irqs_disabled_flags(unsigned long flags)
return flags & PSR_I_BIT;
}
+/*
+ * save and restore debug state
+ */
+#define local_dbg_save(flags) \
+ do { \
+ typecheck(unsigned long, flags); \
+ asm volatile( \
+ "mrs %0, daif // local_dbg_save\n" \
+ "msr daifset, #8" \
+ : "=r" (flags) : : "memory"); \
+ } while (0)
+
+#define local_dbg_restore(flags) \
+ do { \
+ typecheck(unsigned long, flags); \
+ asm volatile( \
+ "msr daif, %0 // local_dbg_restore\n" \
+ : : "r" (flags) : "memory"); \
+ } while (0)
+
+#define local_dbg_enable() asm("msr daifclr, #8" : : : "memory")
+#define local_dbg_disable() asm("msr daifset, #8" : : : "memory")
+
#endif
#endif
diff --git a/arch/arm64/include/asm/kgdb.h b/arch/arm64/include/asm/kgdb.h
new file mode 100644
index 000000000000..3c8aafc1082f
--- /dev/null
+++ b/arch/arm64/include/asm/kgdb.h
@@ -0,0 +1,84 @@
+/*
+ * AArch64 KGDB support
+ *
+ * Based on arch/arm/include/kgdb.h
+ *
+ * Copyright (C) 2013 Cavium Inc.
+ * Author: Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM_KGDB_H
+#define __ARM_KGDB_H
+
+#include <linux/ptrace.h>
+#include <asm/debug-monitors.h>
+
+#ifndef __ASSEMBLY__
+
+static inline void arch_kgdb_breakpoint(void)
+{
+ asm ("brk %0" : : "I" (KDBG_COMPILED_DBG_BRK_IMM));
+}
+
+extern void kgdb_handle_bus_error(void);
+extern int kgdb_fault_expected;
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * gdb is expecting the following registers layout.
+ *
+ * General purpose regs:
+ * r0-r30: 64 bit
+ * sp,pc : 64 bit
+ * pstate : 64 bit
+ * Total: 34
+ * FPU regs:
+ * f0-f31: 128 bit
+ * Total: 32
+ * Extra regs
+ * fpsr & fpcr: 32 bit
+ * Total: 2
+ *
+ */
+
+#define _GP_REGS 34
+#define _FP_REGS 32
+#define _EXTRA_REGS 2
+/*
+ * general purpose registers size in bytes.
+ * pstate is only 4 bytes. subtract 4 bytes
+ */
+#define GP_REG_BYTES (_GP_REGS * 8)
+#define DBG_MAX_REG_NUM (_GP_REGS + _FP_REGS + _EXTRA_REGS)
+
+/*
+ * Size of I/O buffer for gdb packet.
+ * considering to hold all register contents, size is set
+ */
+
+#define BUFMAX 2048
+
+/*
+ * Number of bytes required for gdb_regs buffer.
+ * _GP_REGS: 8 bytes, _FP_REGS: 16 bytes and _EXTRA_REGS: 4 bytes each
+ * GDB fails to connect for size beyond this with error
+ * "'g' packet reply is too long"
+ */
+
+#define NUMREGBYTES ((_GP_REGS * 8) + (_FP_REGS * 16) + \
+ (_EXTRA_REGS * 4))
+
+#endif /* __ASM_KGDB_H */
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 0eb398655378..3d6903006a8a 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -62,6 +62,7 @@
* RW: 64bit by default, can be overriden for 32bit VMs
* TAC: Trap ACTLR
* TSC: Trap SMC
+ * TVM: Trap VM ops (until M+C set in SCTLR_EL1)
* TSW: Trap cache operations by set/way
* TWE: Trap WFE
* TWI: Trap WFI
@@ -74,7 +75,7 @@
* SWIO: Turn set/way invalidates into set/way clean+invalidate
*/
#define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
- HCR_BSU_IS | HCR_FB | HCR_TAC | \
+ HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \
HCR_AMO | HCR_IMO | HCR_FMO | \
HCR_SWIO | HCR_TIDCP | HCR_RW)
#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
@@ -106,7 +107,6 @@
/* VTCR_EL2 Registers bits */
#define VTCR_EL2_PS_MASK (7 << 16)
-#define VTCR_EL2_PS_40B (2 << 16)
#define VTCR_EL2_TG0_MASK (1 << 14)
#define VTCR_EL2_TG0_4K (0 << 14)
#define VTCR_EL2_TG0_64K (1 << 14)
@@ -129,10 +129,9 @@
* 64kB pages (TG0 = 1)
* 2 level page tables (SL = 1)
*/
-#define VTCR_EL2_FLAGS (VTCR_EL2_PS_40B | VTCR_EL2_TG0_64K | \
- VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \
- VTCR_EL2_IRGN0_WBWA | VTCR_EL2_SL0_LVL1 | \
- VTCR_EL2_T0SZ_40B)
+#define VTCR_EL2_FLAGS (VTCR_EL2_TG0_64K | VTCR_EL2_SH0_INNER | \
+ VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \
+ VTCR_EL2_SL0_LVL1 | VTCR_EL2_T0SZ_40B)
#define VTTBR_X (38 - VTCR_EL2_T0SZ_40B)
#else
/*
@@ -142,10 +141,9 @@
* 4kB pages (TG0 = 0)
* 3 level page tables (SL = 1)
*/
-#define VTCR_EL2_FLAGS (VTCR_EL2_PS_40B | VTCR_EL2_TG0_4K | \
- VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \
- VTCR_EL2_IRGN0_WBWA | VTCR_EL2_SL0_LVL1 | \
- VTCR_EL2_T0SZ_40B)
+#define VTCR_EL2_FLAGS (VTCR_EL2_TG0_4K | VTCR_EL2_SH0_INNER | \
+ VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \
+ VTCR_EL2_SL0_LVL1 | VTCR_EL2_T0SZ_40B)
#define VTTBR_X (37 - VTCR_EL2_T0SZ_40B)
#endif
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index b25763bc0ec4..9fcd54b1e16d 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -79,7 +79,8 @@
#define c13_TID_URW (TPIDR_EL0 * 2) /* Thread ID, User R/W */
#define c13_TID_URO (TPIDRRO_EL0 * 2)/* Thread ID, User R/O */
#define c13_TID_PRIV (TPIDR_EL1 * 2) /* Thread ID, Privileged */
-#define c10_AMAIR (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
+#define c10_AMAIR0 (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
+#define c10_AMAIR1 (c10_AMAIR0 + 1)/* Aux Memory Attr Indirection Reg */
#define c14_CNTKCTL (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */
#define NR_CP15_REGS (NR_SYS_REGS * 2)
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 7f1f9408ff66..7d29847a893b 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -106,7 +106,6 @@ static inline bool kvm_is_write_fault(unsigned long esr)
return true;
}
-static inline void kvm_clean_dcache_area(void *addr, size_t size) {}
static inline void kvm_clean_pgd(pgd_t *pgd) {}
static inline void kvm_clean_pmd_entry(pmd_t *pmd) {}
static inline void kvm_clean_pte(pte_t *pte) {}
@@ -122,11 +121,25 @@ static inline void kvm_set_s2pmd_writable(pmd_t *pmd)
pmd_val(*pmd) |= PMD_S2_RDWR;
}
+#define kvm_pgd_addr_end(addr, end) pgd_addr_end(addr, end)
+#define kvm_pud_addr_end(addr, end) pud_addr_end(addr, end)
+#define kvm_pmd_addr_end(addr, end) pmd_addr_end(addr, end)
+
struct kvm;
-static inline void coherent_icache_guest_page(struct kvm *kvm, hva_t hva,
- unsigned long size)
+#define kvm_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l))
+
+static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
{
+ return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
+}
+
+static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva,
+ unsigned long size)
+{
+ if (!vcpu_has_cache_enabled(vcpu))
+ kvm_flush_dcache_to_poc((void *)hva, size);
+
if (!icache_is_aliasing()) { /* PIPT */
flush_icache_range(hva, hva + size);
} else if (!icache_is_aivivt()) { /* non ASID-tagged VIVT */
@@ -135,8 +148,9 @@ static inline void coherent_icache_guest_page(struct kvm *kvm, hva_t hva,
}
}
-#define kvm_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l))
#define kvm_virt_to_phys(x) __virt_to_phys((unsigned long)(x))
+void stage2_flush_vm(struct kvm *kvm);
+
#endif /* __ASSEMBLY__ */
#endif /* __ARM64_KVM_MMU_H__ */
diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h
index 13fb0b3efc5f..453a179469a3 100644
--- a/arch/arm64/include/asm/percpu.h
+++ b/arch/arm64/include/asm/percpu.h
@@ -16,6 +16,8 @@
#ifndef __ASM_PERCPU_H
#define __ASM_PERCPU_H
+#ifdef CONFIG_SMP
+
static inline void set_my_cpu_offset(unsigned long off)
{
asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory");
@@ -36,6 +38,12 @@ static inline unsigned long __my_cpu_offset(void)
}
#define __my_cpu_offset __my_cpu_offset()
+#else /* !CONFIG_SMP */
+
+#define set_my_cpu_offset(x) do { } while (0)
+
+#endif /* CONFIG_SMP */
+
#include <asm-generic/percpu.h>
#endif /* __ASM_PERCPU_H */
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index b1d2e26c3c88..f7af66b54cb2 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -100,9 +100,9 @@
#define PTE_HYP PTE_USER
/*
- * 40-bit physical address supported.
+ * Highest possible physical address supported.
*/
-#define PHYS_MASK_SHIFT (40)
+#define PHYS_MASK_SHIFT (48)
#define PHYS_MASK ((UL(1) << PHYS_MASK_SHIFT) - 1)
/*
@@ -122,7 +122,6 @@
#define TCR_SHARED ((UL(3) << 12) | (UL(3) << 28))
#define TCR_TG0_64K (UL(1) << 14)
#define TCR_TG1_64K (UL(1) << 30)
-#define TCR_IPS_40BIT (UL(2) << 32)
#define TCR_ASID16 (UL(1) << 36)
#define TCR_TBI0 (UL(1) << 37)
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index b524dcd17243..90c811f05a2e 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -136,11 +136,11 @@ extern struct page *empty_zero_page;
/*
* The following only work if pte_present(). Undefined behaviour otherwise.
*/
-#define pte_present(pte) (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE))
-#define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY)
-#define pte_young(pte) (pte_val(pte) & PTE_AF)
-#define pte_special(pte) (pte_val(pte) & PTE_SPECIAL)
-#define pte_write(pte) (pte_val(pte) & PTE_WRITE)
+#define pte_present(pte) (!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)))
+#define pte_dirty(pte) (!!(pte_val(pte) & PTE_DIRTY))
+#define pte_young(pte) (!!(pte_val(pte) & PTE_AF))
+#define pte_special(pte) (!!(pte_val(pte) & PTE_SPECIAL))
+#define pte_write(pte) (!!(pte_val(pte) & PTE_WRITE))
#define pte_exec(pte) (!(pte_val(pte) & PTE_UXN))
#define pte_valid_user(pte) \
@@ -199,7 +199,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte)
{
if (pte_valid_user(pte)) {
- if (pte_exec(pte))
+ if (!pte_special(pte) && pte_exec(pte))
__sync_icache_dcache(pte, addr);
if (pte_dirty(pte) && pte_write(pte))
pte_val(pte) &= ~PTE_RDONLY;
@@ -227,36 +227,36 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
#define __HAVE_ARCH_PTE_SPECIAL
-/*
- * Software PMD bits for THP
- */
+static inline pte_t pmd_pte(pmd_t pmd)
+{
+ return __pte(pmd_val(pmd));
+}
-#define PMD_SECT_DIRTY (_AT(pmdval_t, 1) << 55)
-#define PMD_SECT_SPLITTING (_AT(pmdval_t, 1) << 57)
+static inline pmd_t pte_pmd(pte_t pte)
+{
+ return __pmd(pte_val(pte));
+}
/*
* THP definitions.
*/
-#define pmd_young(pmd) (pmd_val(pmd) & PMD_SECT_AF)
-
-#define __HAVE_ARCH_PMD_WRITE
-#define pmd_write(pmd) (!(pmd_val(pmd) & PMD_SECT_RDONLY))
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define pmd_trans_huge(pmd) (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
-#define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING)
+#define pmd_trans_splitting(pmd) pte_special(pmd_pte(pmd))
#endif
-#define PMD_BIT_FUNC(fn,op) \
-static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
+#define pmd_young(pmd) pte_young(pmd_pte(pmd))
+#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
+#define pmd_mksplitting(pmd) pte_pmd(pte_mkspecial(pmd_pte(pmd)))
+#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))
+#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd)))
+#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
+#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
+#define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) &= ~PMD_TYPE_MASK))
-PMD_BIT_FUNC(wrprotect, |= PMD_SECT_RDONLY);
-PMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF);
-PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING);
-PMD_BIT_FUNC(mkwrite, &= ~PMD_SECT_RDONLY);
-PMD_BIT_FUNC(mkdirty, |= PMD_SECT_DIRTY);
-PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF);
-PMD_BIT_FUNC(mknotpresent, &= ~PMD_TYPE_MASK);
+#define __HAVE_ARCH_PMD_WRITE
+#define pmd_write(pmd) pte_write(pmd_pte(pmd))
#define pmd_mkhuge(pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
@@ -266,15 +266,6 @@ PMD_BIT_FUNC(mknotpresent, &= ~PMD_TYPE_MASK);
#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
-static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
-{
- const pmdval_t mask = PMD_SECT_USER | PMD_SECT_PXN | PMD_SECT_UXN |
- PMD_SECT_RDONLY | PMD_SECT_PROT_NONE |
- PMD_SECT_VALID;
- pmd_val(pmd) = (pmd_val(pmd) & ~mask) | (pgprot_val(newprot) & mask);
- return pmd;
-}
-
#define set_pmd_at(mm, addr, pmdp, pmd) set_pmd(pmdp, pmd)
static inline int has_transparent_hugepage(void)
@@ -286,11 +277,9 @@ static inline int has_transparent_hugepage(void)
* Mark the prot value as uncacheable and unbufferable.
*/
#define pgprot_noncached(prot) \
- __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE))
+ __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN)
#define pgprot_writecombine(prot) \
- __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC))
-#define pgprot_dmacoherent(prot) \
- __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC))
+ __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
#define __HAVE_PHYS_MEM_ACCESS_PROT
struct file;
extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
@@ -383,6 +372,11 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
return pte;
}
+static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
+{
+ return pte_pmd(pte_modify(pmd_pte(pmd), newprot));
+}
+
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h
index e5312ea0ec1a..d15ab8b46336 100644
--- a/arch/arm64/include/asm/psci.h
+++ b/arch/arm64/include/asm/psci.h
@@ -14,6 +14,6 @@
#ifndef __ASM_PSCI_H
#define __ASM_PSCI_H
-int psci_init(void);
+void psci_init(void);
#endif /* __ASM_PSCI_H */
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 0e7fa4963735..c7ba261dd4b3 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -68,6 +68,7 @@
/* Architecturally defined mapping between AArch32 and AArch64 registers */
#define compat_usr(x) regs[(x)]
+#define compat_fp regs[11]
#define compat_sp regs[13]
#define compat_lr regs[14]
#define compat_sp_hyp regs[15]
@@ -132,7 +133,7 @@ struct pt_regs {
(!((regs)->pstate & PSR_F_BIT))
#define user_stack_pointer(regs) \
- ((regs)->sp)
+ (!compat_user_mode(regs)) ? ((regs)->sp) : ((regs)->compat_sp)
/*
* Are the current registers suitable for user mode? (used to maintain
@@ -164,7 +165,7 @@ static inline int valid_user_regs(struct user_pt_regs *regs)
return 0;
}
-#define instruction_pointer(regs) (regs)->pc
+#define instruction_pointer(regs) ((unsigned long)(regs)->pc)
#ifdef CONFIG_SMP
extern unsigned long profile_pc(struct pt_regs *regs);
diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
index 717031a762c2..72cadf52ca80 100644
--- a/arch/arm64/include/asm/tlb.h
+++ b/arch/arm64/include/asm/tlb.h
@@ -19,115 +19,44 @@
#ifndef __ASM_TLB_H
#define __ASM_TLB_H
-#include <linux/pagemap.h>
-#include <linux/swap.h>
-#include <asm/pgalloc.h>
-#include <asm/tlbflush.h>
-
-#define MMU_GATHER_BUNDLE 8
-
-/*
- * TLB handling. This allows us to remove pages from the page
- * tables, and efficiently handle the TLB issues.
- */
-struct mmu_gather {
- struct mm_struct *mm;
- unsigned int fullmm;
- struct vm_area_struct *vma;
- unsigned long start, end;
- unsigned long range_start;
- unsigned long range_end;
- unsigned int nr;
- unsigned int max;
- struct page **pages;
- struct page *local[MMU_GATHER_BUNDLE];
-};
+#include <asm-generic/tlb.h>
/*
- * This is unnecessarily complex. There's three ways the TLB shootdown
- * code is used:
+ * There's three ways the TLB shootdown code is used:
* 1. Unmapping a range of vmas. See zap_page_range(), unmap_region().
* tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called.
- * tlb->vma will be non-NULL.
* 2. Unmapping all vmas. See exit_mmap().
* tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called.
- * tlb->vma will be non-NULL. Additionally, page tables will be freed.
+ * Page tables will be freed.
* 3. Unmapping argument pages. See shift_arg_pages().
* tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called.
- * tlb->vma will be NULL.
*/
static inline void tlb_flush(struct mmu_gather *tlb)
{
- if (tlb->fullmm || !tlb->vma)
+ if (tlb->fullmm) {
flush_tlb_mm(tlb->mm);
- else if (tlb->range_end > 0) {
- flush_tlb_range(tlb->vma, tlb->range_start, tlb->range_end);
- tlb->range_start = TASK_SIZE;
- tlb->range_end = 0;
+ } else if (tlb->end > 0) {
+ struct vm_area_struct vma = { .vm_mm = tlb->mm, };
+ flush_tlb_range(&vma, tlb->start, tlb->end);
+ tlb->start = TASK_SIZE;
+ tlb->end = 0;
}
}
static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr)
{
if (!tlb->fullmm) {
- if (addr < tlb->range_start)
- tlb->range_start = addr;
- if (addr + PAGE_SIZE > tlb->range_end)
- tlb->range_end = addr + PAGE_SIZE;
- }
-}
-
-static inline void __tlb_alloc_page(struct mmu_gather *tlb)
-{
- unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
-
- if (addr) {
- tlb->pages = (void *)addr;
- tlb->max = PAGE_SIZE / sizeof(struct page *);
+ tlb->start = min(tlb->start, addr);
+ tlb->end = max(tlb->end, addr + PAGE_SIZE);
}
}
-static inline void tlb_flush_mmu(struct mmu_gather *tlb)
-{
- tlb_flush(tlb);
- free_pages_and_swap_cache(tlb->pages, tlb->nr);
- tlb->nr = 0;
- if (tlb->pages == tlb->local)
- __tlb_alloc_page(tlb);
-}
-
-static inline void
-tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end)
-{
- tlb->mm = mm;
- tlb->fullmm = !(start | (end+1));
- tlb->start = start;
- tlb->end = end;
- tlb->vma = NULL;
- tlb->max = ARRAY_SIZE(tlb->local);
- tlb->pages = tlb->local;
- tlb->nr = 0;
- __tlb_alloc_page(tlb);
-}
-
-static inline void
-tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
-{
- tlb_flush_mmu(tlb);
-
- /* keep the page table cache within bounds */
- check_pgt_cache();
-
- if (tlb->pages != tlb->local)
- free_pages((unsigned long)tlb->pages, 0);
-}
-
/*
* Memorize the range for the TLB flush.
*/
-static inline void
-tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr)
+static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
+ unsigned long addr)
{
tlb_add_flush(tlb, addr);
}
@@ -137,38 +66,24 @@ tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr)
* case where we're doing a full MM flush. When we're doing a munmap,
* the vmas are adjusted to only cover the region to be torn down.
*/
-static inline void
-tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
+static inline void tlb_start_vma(struct mmu_gather *tlb,
+ struct vm_area_struct *vma)
{
if (!tlb->fullmm) {
- tlb->vma = vma;
- tlb->range_start = TASK_SIZE;
- tlb->range_end = 0;
+ tlb->start = TASK_SIZE;
+ tlb->end = 0;
}
}
-static inline void
-tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
+static inline void tlb_end_vma(struct mmu_gather *tlb,
+ struct vm_area_struct *vma)
{
if (!tlb->fullmm)
tlb_flush(tlb);
}
-static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
-{
- tlb->pages[tlb->nr++] = page;
- VM_BUG_ON(tlb->nr > tlb->max);
- return tlb->max - tlb->nr;
-}
-
-static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
-{
- if (!__tlb_remove_page(tlb, page))
- tlb_flush_mmu(tlb);
-}
-
static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
- unsigned long addr)
+ unsigned long addr)
{
pgtable_page_dtor(pte);
tlb_add_flush(tlb, addr);
@@ -184,16 +99,5 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
}
#endif
-#define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr)
-#define pmd_free_tlb(tlb, pmdp, addr) __pmd_free_tlb(tlb, pmdp, addr)
-#define pud_free_tlb(tlb, pudp, addr) pud_free((tlb)->mm, pudp)
-
-#define tlb_migrate_finish(mm) do { } while (0)
-
-static inline void
-tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, unsigned long addr)
-{
- tlb_add_flush(tlb, addr);
-}
#endif
diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
new file mode 100644
index 000000000000..0172e6d76bf3
--- /dev/null
+++ b/arch/arm64/include/asm/topology.h
@@ -0,0 +1,39 @@
+#ifndef __ASM_TOPOLOGY_H
+#define __ASM_TOPOLOGY_H
+
+#ifdef CONFIG_SMP
+
+#include <linux/cpumask.h>
+
+struct cpu_topology {
+ int thread_id;
+ int core_id;
+ int cluster_id;
+ cpumask_t thread_sibling;
+ cpumask_t core_sibling;
+};
+
+extern struct cpu_topology cpu_topology[NR_CPUS];
+
+#define topology_physical_package_id(cpu) (cpu_topology[cpu].cluster_id)
+#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
+#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
+#define topology_thread_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
+
+#define mc_capable() (cpu_topology[0].cluster_id != -1)
+#define smt_capable() (cpu_topology[0].thread_id != -1)
+
+void init_cpu_topology(void);
+void store_cpu_topology(unsigned int cpuid);
+const struct cpumask *cpu_coregroup_mask(int cpu);
+
+#else
+
+static inline void init_cpu_topology(void) { }
+static inline void store_cpu_topology(unsigned int cpuid) { }
+
+#endif
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_ARM_TOPOLOGY_H */
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 6c0f684aca81..3bf8f4e99a51 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -83,7 +83,7 @@ static inline void set_fs(mm_segment_t fs)
* Returns 1 if the range is valid, 0 otherwise.
*
* This is equivalent to the following test:
- * (u65)addr + (u65)size < (u65)current->addr_limit
+ * (u65)addr + (u65)size <= current->addr_limit
*
* This needs 65-bit arithmetic.
*/
@@ -91,7 +91,7 @@ static inline void set_fs(mm_segment_t fs)
({ \
unsigned long flag, roksum; \
__chk_user_ptr(addr); \
- asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, cc" \
+ asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls" \
: "=&r" (flag), "=&r" (roksum) \
: "1" (addr), "Ir" (size), \
"r" (current_thread_info()->addr_limit) \
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 82ce217e94cf..a4654c656a1e 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -14,6 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef CONFIG_COMPAT
+#define __ARCH_WANT_COMPAT_SYS_GETDENTS64
#define __ARCH_WANT_COMPAT_STAT64
#define __ARCH_WANT_SYS_GETHOSTNAME
#define __ARCH_WANT_SYS_PAUSE
diff --git a/arch/arm64/include/uapi/asm/Kbuild b/arch/arm64/include/uapi/asm/Kbuild
index e4b78bdca19e..942376d37d22 100644
--- a/arch/arm64/include/uapi/asm/Kbuild
+++ b/arch/arm64/include/uapi/asm/Kbuild
@@ -9,6 +9,7 @@ header-y += byteorder.h
header-y += fcntl.h
header-y += hwcap.h
header-y += kvm_para.h
+header-y += perf_regs.h
header-y += param.h
header-y += ptrace.h
header-y += setup.h
diff --git a/arch/arm64/include/uapi/asm/perf_regs.h b/arch/arm64/include/uapi/asm/perf_regs.h
new file mode 100644
index 000000000000..172b8317ee49
--- /dev/null
+++ b/arch/arm64/include/uapi/asm/perf_regs.h
@@ -0,0 +1,40 @@
+#ifndef _ASM_ARM64_PERF_REGS_H
+#define _ASM_ARM64_PERF_REGS_H
+
+enum perf_event_arm_regs {
+ PERF_REG_ARM64_X0,
+ PERF_REG_ARM64_X1,
+ PERF_REG_ARM64_X2,
+ PERF_REG_ARM64_X3,
+ PERF_REG_ARM64_X4,
+ PERF_REG_ARM64_X5,
+ PERF_REG_ARM64_X6,
+ PERF_REG_ARM64_X7,
+ PERF_REG_ARM64_X8,
+ PERF_REG_ARM64_X9,
+ PERF_REG_ARM64_X10,
+ PERF_REG_ARM64_X11,
+ PERF_REG_ARM64_X12,
+ PERF_REG_ARM64_X13,
+ PERF_REG_ARM64_X14,
+ PERF_REG_ARM64_X15,
+ PERF_REG_ARM64_X16,
+ PERF_REG_ARM64_X17,
+ PERF_REG_ARM64_X18,
+ PERF_REG_ARM64_X19,
+ PERF_REG_ARM64_X20,
+ PERF_REG_ARM64_X21,
+ PERF_REG_ARM64_X22,
+ PERF_REG_ARM64_X23,
+ PERF_REG_ARM64_X24,
+ PERF_REG_ARM64_X25,
+ PERF_REG_ARM64_X26,
+ PERF_REG_ARM64_X27,
+ PERF_REG_ARM64_X28,
+ PERF_REG_ARM64_X29,
+ PERF_REG_ARM64_LR,
+ PERF_REG_ARM64_SP,
+ PERF_REG_ARM64_PC,
+ PERF_REG_ARM64_MAX,
+};
+#endif /* _ASM_ARM64_PERF_REGS_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 2d4554b13410..7d811d9522bc 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -14,12 +14,14 @@ arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
-arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o
+arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o
+arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
-arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
+arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+arm64-obj-$(CONFIG_KGDB) += kgdb.o
obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index 636ba8b6240b..14ba23c61153 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -137,7 +137,6 @@ void disable_debug_monitors(enum debug_el el)
static void clear_os_lock(void *unused)
{
asm volatile("msr oslar_el1, %0" : : "r" (0));
- isb();
}
static int os_lock_notify(struct notifier_block *self,
@@ -156,8 +155,9 @@ static struct notifier_block os_lock_nb = {
static int debug_monitors_init(void)
{
/* Clear the OS lock. */
- smp_call_function(clear_os_lock, NULL, 1);
- clear_os_lock(NULL);
+ on_each_cpu(clear_os_lock, NULL, 1);
+ isb();
+ local_dbg_enable();
/* Register hotplug handler. */
register_cpu_notifier(&os_lock_nb);
@@ -189,7 +189,7 @@ static void clear_regs_spsr_ss(struct pt_regs *regs)
/* EL1 Single Step Handler hooks */
static LIST_HEAD(step_hook);
-DEFINE_RWLOCK(step_hook_lock);
+static DEFINE_RWLOCK(step_hook_lock);
void register_step_hook(struct step_hook *hook)
{
@@ -276,7 +276,7 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
* Use reader/writer locks instead of plain spinlock.
*/
static LIST_HEAD(break_hook);
-DEFINE_RWLOCK(break_hook_lock);
+static DEFINE_RWLOCK(break_hook_lock);
void register_break_hook(struct break_hook *hook)
{
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 0b281fffda51..61035d6814cb 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -384,26 +384,18 @@ ENDPROC(__calc_phys_offset)
* Preserves: tbl, flags
* Corrupts: phys, start, end, pstate
*/
- .macro create_block_map, tbl, flags, phys, start, end, idmap=0
+ .macro create_block_map, tbl, flags, phys, start, end
lsr \phys, \phys, #BLOCK_SHIFT
- .if \idmap
- and \start, \phys, #PTRS_PER_PTE - 1 // table index
- .else
lsr \start, \start, #BLOCK_SHIFT
and \start, \start, #PTRS_PER_PTE - 1 // table index
- .endif
orr \phys, \flags, \phys, lsl #BLOCK_SHIFT // table entry
- .ifnc \start,\end
lsr \end, \end, #BLOCK_SHIFT
and \end, \end, #PTRS_PER_PTE - 1 // table end index
- .endif
9999: str \phys, [\tbl, \start, lsl #3] // store the entry
- .ifnc \start,\end
add \start, \start, #1 // next entry
add \phys, \phys, #BLOCK_SIZE // next block
cmp \start, \end
b.ls 9999b
- .endif
.endm
/*
@@ -435,9 +427,13 @@ __create_page_tables:
* Create the identity mapping.
*/
add x0, x25, #PAGE_SIZE // section table address
- adr x3, __turn_mmu_on // virtual/physical address
+ ldr x3, =KERNEL_START
+ add x3, x3, x28 // __pa(KERNEL_START)
create_pgd_entry x25, x0, x3, x5, x6
- create_block_map x0, x7, x3, x5, x5, idmap=1
+ ldr x6, =KERNEL_END
+ mov x5, x3 // __pa(KERNEL_START)
+ add x6, x6, x28 // __pa(KERNEL_END)
+ create_block_map x0, x7, x3, x5, x6
/*
* Map the kernel image (starting with PHYS_OFFSET).
@@ -445,7 +441,7 @@ __create_page_tables:
add x0, x26, #PAGE_SIZE // section table address
mov x5, #PAGE_OFFSET
create_pgd_entry x26, x0, x5, x3, x6
- ldr x6, =KERNEL_END - 1
+ ldr x6, =KERNEL_END
mov x3, x24 // phys offset
create_block_map x0, x7, x3, x5, x6
diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
new file mode 100644
index 000000000000..75c9cf1aafee
--- /dev/null
+++ b/arch/arm64/kernel/kgdb.c
@@ -0,0 +1,336 @@
+/*
+ * AArch64 KGDB support
+ *
+ * Based on arch/arm/kernel/kgdb.c
+ *
+ * Copyright (C) 2013 Cavium Inc.
+ * Author: Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/irq.h>
+#include <linux/kdebug.h>
+#include <linux/kgdb.h>
+#include <asm/traps.h>
+
+struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
+ { "x0", 8, offsetof(struct pt_regs, regs[0])},
+ { "x1", 8, offsetof(struct pt_regs, regs[1])},
+ { "x2", 8, offsetof(struct pt_regs, regs[2])},
+ { "x3", 8, offsetof(struct pt_regs, regs[3])},
+ { "x4", 8, offsetof(struct pt_regs, regs[4])},
+ { "x5", 8, offsetof(struct pt_regs, regs[5])},
+ { "x6", 8, offsetof(struct pt_regs, regs[6])},
+ { "x7", 8, offsetof(struct pt_regs, regs[7])},
+ { "x8", 8, offsetof(struct pt_regs, regs[8])},
+ { "x9", 8, offsetof(struct pt_regs, regs[9])},
+ { "x10", 8, offsetof(struct pt_regs, regs[10])},
+ { "x11", 8, offsetof(struct pt_regs, regs[11])},
+ { "x12", 8, offsetof(struct pt_regs, regs[12])},
+ { "x13", 8, offsetof(struct pt_regs, regs[13])},
+ { "x14", 8, offsetof(struct pt_regs, regs[14])},
+ { "x15", 8, offsetof(struct pt_regs, regs[15])},
+ { "x16", 8, offsetof(struct pt_regs, regs[16])},
+ { "x17", 8, offsetof(struct pt_regs, regs[17])},
+ { "x18", 8, offsetof(struct pt_regs, regs[18])},
+ { "x19", 8, offsetof(struct pt_regs, regs[19])},
+ { "x20", 8, offsetof(struct pt_regs, regs[20])},
+ { "x21", 8, offsetof(struct pt_regs, regs[21])},
+ { "x22", 8, offsetof(struct pt_regs, regs[22])},
+ { "x23", 8, offsetof(struct pt_regs, regs[23])},
+ { "x24", 8, offsetof(struct pt_regs, regs[24])},
+ { "x25", 8, offsetof(struct pt_regs, regs[25])},
+ { "x26", 8, offsetof(struct pt_regs, regs[26])},
+ { "x27", 8, offsetof(struct pt_regs, regs[27])},
+ { "x28", 8, offsetof(struct pt_regs, regs[28])},
+ { "x29", 8, offsetof(struct pt_regs, regs[29])},
+ { "x30", 8, offsetof(struct pt_regs, regs[30])},
+ { "sp", 8, offsetof(struct pt_regs, sp)},
+ { "pc", 8, offsetof(struct pt_regs, pc)},
+ { "pstate", 8, offsetof(struct pt_regs, pstate)},
+ { "v0", 16, -1 },
+ { "v1", 16, -1 },
+ { "v2", 16, -1 },
+ { "v3", 16, -1 },
+ { "v4", 16, -1 },
+ { "v5", 16, -1 },
+ { "v6", 16, -1 },
+ { "v7", 16, -1 },
+ { "v8", 16, -1 },
+ { "v9", 16, -1 },
+ { "v10", 16, -1 },
+ { "v11", 16, -1 },
+ { "v12", 16, -1 },
+ { "v13", 16, -1 },
+ { "v14", 16, -1 },
+ { "v15", 16, -1 },
+ { "v16", 16, -1 },
+ { "v17", 16, -1 },
+ { "v18", 16, -1 },
+ { "v19", 16, -1 },
+ { "v20", 16, -1 },
+ { "v21", 16, -1 },
+ { "v22", 16, -1 },
+ { "v23", 16, -1 },
+ { "v24", 16, -1 },
+ { "v25", 16, -1 },
+ { "v26", 16, -1 },
+ { "v27", 16, -1 },
+ { "v28", 16, -1 },
+ { "v29", 16, -1 },
+ { "v30", 16, -1 },
+ { "v31", 16, -1 },
+ { "fpsr", 4, -1 },
+ { "fpcr", 4, -1 },
+};
+
+char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
+{
+ if (regno >= DBG_MAX_REG_NUM || regno < 0)
+ return NULL;
+
+ if (dbg_reg_def[regno].offset != -1)
+ memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
+ dbg_reg_def[regno].size);
+ else
+ memset(mem, 0, dbg_reg_def[regno].size);
+ return dbg_reg_def[regno].name;
+}
+
+int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
+{
+ if (regno >= DBG_MAX_REG_NUM || regno < 0)
+ return -EINVAL;
+
+ if (dbg_reg_def[regno].offset != -1)
+ memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
+ dbg_reg_def[regno].size);
+ return 0;
+}
+
+void
+sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
+{
+ struct pt_regs *thread_regs;
+
+ /* Initialize to zero */
+ memset((char *)gdb_regs, 0, NUMREGBYTES);
+ thread_regs = task_pt_regs(task);
+ memcpy((void *)gdb_regs, (void *)thread_regs->regs, GP_REG_BYTES);
+}
+
+void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
+{
+ regs->pc = pc;
+}
+
+static int compiled_break;
+
+static void kgdb_arch_update_addr(struct pt_regs *regs,
+ char *remcom_in_buffer)
+{
+ unsigned long addr;
+ char *ptr;
+
+ ptr = &remcom_in_buffer[1];
+ if (kgdb_hex2long(&ptr, &addr))
+ kgdb_arch_set_pc(regs, addr);
+ else if (compiled_break == 1)
+ kgdb_arch_set_pc(regs, regs->pc + 4);
+
+ compiled_break = 0;
+}
+
+int kgdb_arch_handle_exception(int exception_vector, int signo,
+ int err_code, char *remcom_in_buffer,
+ char *remcom_out_buffer,
+ struct pt_regs *linux_regs)
+{
+ int err;
+
+ switch (remcom_in_buffer[0]) {
+ case 'D':
+ case 'k':
+ /*
+ * Packet D (Detach), k (kill). No special handling
+ * is required here. Handle same as c packet.
+ */
+ case 'c':
+ /*
+ * Packet c (Continue) to continue executing.
+ * Set pc to required address.
+ * Try to read optional parameter and set pc.
+ * If this was a compiled breakpoint, we need to move
+ * to the next instruction else we will just breakpoint
+ * over and over again.
+ */
+ kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
+ atomic_set(&kgdb_cpu_doing_single_step, -1);
+ kgdb_single_step = 0;
+
+ /*
+ * Received continue command, disable single step
+ */
+ if (kernel_active_single_step())
+ kernel_disable_single_step();
+
+ err = 0;
+ break;
+ case 's':
+ /*
+ * Update step address value with address passed
+ * with step packet.
+ * On debug exception return PC is copied to ELR
+ * So just update PC.
+ * If no step address is passed, resume from the address
+ * pointed by PC. Do not update PC
+ */
+ kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
+ atomic_set(&kgdb_cpu_doing_single_step, raw_smp_processor_id());
+ kgdb_single_step = 1;
+
+ /*
+ * Enable single step handling
+ */
+ if (!kernel_active_single_step())
+ kernel_enable_single_step(linux_regs);
+ err = 0;
+ break;
+ default:
+ err = -1;
+ }
+ return err;
+}
+
+static int kgdb_brk_fn(struct pt_regs *regs, unsigned int esr)
+{
+ kgdb_handle_exception(1, SIGTRAP, 0, regs);
+ return 0;
+}
+
+static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int esr)
+{
+ compiled_break = 1;
+ kgdb_handle_exception(1, SIGTRAP, 0, regs);
+
+ return 0;
+}
+
+static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
+{
+ kgdb_handle_exception(1, SIGTRAP, 0, regs);
+ return 0;
+}
+
+static struct break_hook kgdb_brkpt_hook = {
+ .esr_mask = 0xffffffff,
+ .esr_val = DBG_ESR_VAL_BRK(KGDB_DYN_DGB_BRK_IMM),
+ .fn = kgdb_brk_fn
+};
+
+static struct break_hook kgdb_compiled_brkpt_hook = {
+ .esr_mask = 0xffffffff,
+ .esr_val = DBG_ESR_VAL_BRK(KDBG_COMPILED_DBG_BRK_IMM),
+ .fn = kgdb_compiled_brk_fn
+};
+
+static struct step_hook kgdb_step_hook = {
+ .fn = kgdb_step_brk_fn
+};
+
+static void kgdb_call_nmi_hook(void *ignored)
+{
+ kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+ local_irq_enable();
+ smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+ local_irq_disable();
+}
+
+static int __kgdb_notify(struct die_args *args, unsigned long cmd)
+{
+ struct pt_regs *regs = args->regs;
+
+ if (kgdb_handle_exception(1, args->signr, cmd, regs))
+ return NOTIFY_DONE;
+ return NOTIFY_STOP;
+}
+
+static int
+kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
+{
+ unsigned long flags;
+ int ret;
+
+ local_irq_save(flags);
+ ret = __kgdb_notify(ptr, cmd);
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static struct notifier_block kgdb_notifier = {
+ .notifier_call = kgdb_notify,
+ /*
+ * Want to be lowest priority
+ */
+ .priority = -INT_MAX,
+};
+
+/*
+ * kgdb_arch_init - Perform any architecture specific initalization.
+ * This function will handle the initalization of any architecture
+ * specific callbacks.
+ */
+int kgdb_arch_init(void)
+{
+ int ret = register_die_notifier(&kgdb_notifier);
+
+ if (ret != 0)
+ return ret;
+
+ register_break_hook(&kgdb_brkpt_hook);
+ register_break_hook(&kgdb_compiled_brkpt_hook);
+ register_step_hook(&kgdb_step_hook);
+ return 0;
+}
+
+/*
+ * kgdb_arch_exit - Perform any architecture specific uninitalization.
+ * This function will handle the uninitalization of any architecture
+ * specific callbacks, for dynamic registration and unregistration.
+ */
+void kgdb_arch_exit(void)
+{
+ unregister_break_hook(&kgdb_brkpt_hook);
+ unregister_break_hook(&kgdb_compiled_brkpt_hook);
+ unregister_step_hook(&kgdb_step_hook);
+ unregister_die_notifier(&kgdb_notifier);
+}
+
+/*
+ * ARM instructions are always in LE.
+ * Break instruction is encoded in LE format
+ */
+struct kgdb_arch arch_kgdb_ops = {
+ .gdb_bpt_instr = {
+ KGDB_DYN_BRK_INS_BYTE0,
+ KGDB_DYN_BRK_INS_BYTE1,
+ KGDB_DYN_BRK_INS_BYTE2,
+ KGDB_DYN_BRK_INS_BYTE3,
+ }
+};
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 5b1cd792274a..e868c72a7938 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -1348,8 +1348,8 @@ early_initcall(init_hw_perf_events);
* Callchain handling code.
*/
struct frame_tail {
- struct frame_tail __user *fp;
- unsigned long lr;
+ struct frame_tail __user *fp;
+ unsigned long lr;
} __attribute__((packed));
/*
@@ -1386,22 +1386,80 @@ user_backtrace(struct frame_tail __user *tail,
return buftail.fp;
}
+/*
+ * The registers we're interested in are at the end of the variable
+ * length saved register structure. The fp points at the end of this
+ * structure so the address of this struct is:
+ * (struct compat_frame_tail *)(xxx->fp)-1
+ *
+ * This code has been adapted from the ARM OProfile support.
+ */
+struct compat_frame_tail {
+ compat_uptr_t fp; /* a (struct compat_frame_tail *) in compat mode */
+ u32 sp;
+ u32 lr;
+} __attribute__((packed));
+
+static struct compat_frame_tail __user *
+compat_user_backtrace(struct compat_frame_tail __user *tail,
+ struct perf_callchain_entry *entry)
+{
+ struct compat_frame_tail buftail;
+ unsigned long err;
+
+ /* Also check accessibility of one struct frame_tail beyond */
+ if (!access_ok(VERIFY_READ, tail, sizeof(buftail)))
+ return NULL;
+
+ pagefault_disable();
+ err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
+ pagefault_enable();
+
+ if (err)
+ return NULL;
+
+ perf_callchain_store(entry, buftail.lr);
+
+ /*
+ * Frame pointers should strictly progress back up the stack
+ * (towards higher addresses).
+ */
+ if (tail + 1 >= (struct compat_frame_tail __user *)
+ compat_ptr(buftail.fp))
+ return NULL;
+
+ return (struct compat_frame_tail __user *)compat_ptr(buftail.fp) - 1;
+}
+
void perf_callchain_user(struct perf_callchain_entry *entry,
struct pt_regs *regs)
{
- struct frame_tail __user *tail;
-
if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
/* We don't support guest os callchain now */
return;
}
perf_callchain_store(entry, regs->pc);
- tail = (struct frame_tail __user *)regs->regs[29];
- while (entry->nr < PERF_MAX_STACK_DEPTH &&
- tail && !((unsigned long)tail & 0xf))
- tail = user_backtrace(tail, entry);
+ if (!compat_user_mode(regs)) {
+ /* AARCH64 mode */
+ struct frame_tail __user *tail;
+
+ tail = (struct frame_tail __user *)regs->regs[29];
+
+ while (entry->nr < PERF_MAX_STACK_DEPTH &&
+ tail && !((unsigned long)tail & 0xf))
+ tail = user_backtrace(tail, entry);
+ } else {
+ /* AARCH32 compat mode */
+ struct compat_frame_tail __user *tail;
+
+ tail = (struct compat_frame_tail __user *)regs->compat_fp - 1;
+
+ while ((entry->nr < PERF_MAX_STACK_DEPTH) &&
+ tail && !((unsigned long)tail & 0x3))
+ tail = compat_user_backtrace(tail, entry);
+ }
}
/*
@@ -1429,6 +1487,7 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
frame.fp = regs->regs[29];
frame.sp = regs->sp;
frame.pc = regs->pc;
+
walk_stackframe(&frame, callchain_trace, entry);
}
diff --git a/arch/arm64/kernel/perf_regs.c b/arch/arm64/kernel/perf_regs.c
new file mode 100644
index 000000000000..f2d6f0a36d63
--- /dev/null
+++ b/arch/arm64/kernel/perf_regs.c
@@ -0,0 +1,44 @@
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/bug.h>
+#include <asm/perf_regs.h>
+#include <asm/ptrace.h>
+
+u64 perf_reg_value(struct pt_regs *regs, int idx)
+{
+ if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM64_MAX))
+ return 0;
+
+ /*
+ * Compat (i.e. 32 bit) mode:
+ * - PC has been set in the pt_regs struct in kernel_entry,
+ * - Handle SP and LR here.
+ */
+ if (compat_user_mode(regs)) {
+ if ((u32)idx == PERF_REG_ARM64_SP)
+ return regs->compat_sp;
+ if ((u32)idx == PERF_REG_ARM64_LR)
+ return regs->compat_lr;
+ }
+
+ return regs->regs[idx];
+}
+
+#define REG_RESERVED (~((1ULL << PERF_REG_ARM64_MAX) - 1))
+
+int perf_reg_validate(u64 mask)
+{
+ if (!mask || mask & REG_RESERVED)
+ return -EINVAL;
+
+ return 0;
+}
+
+u64 perf_reg_abi(struct task_struct *task)
+{
+ if (is_compat_thread(task_thread_info(task)))
+ return PERF_SAMPLE_REGS_ABI_32;
+ else
+ return PERF_SAMPLE_REGS_ABI_64;
+}
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 1c0a9be2ffa8..6391485f342d 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -33,7 +33,6 @@
#include <linux/kallsyms.h>
#include <linux/init.h>
#include <linux/cpu.h>
-#include <linux/cpuidle.h>
#include <linux/elfcore.h>
#include <linux/pm.h>
#include <linux/tick.h>
@@ -72,8 +71,17 @@ static void setup_restart(void)
void soft_restart(unsigned long addr)
{
+ typedef void (*phys_reset_t)(unsigned long);
+ phys_reset_t phys_reset;
+
setup_restart();
- cpu_reset(addr);
+
+ /* Switch to the identity mapping */
+ phys_reset = (phys_reset_t)virt_to_phys(cpu_reset);
+ phys_reset(addr);
+
+ /* Should never get here */
+ BUG();
}
/*
@@ -94,10 +102,8 @@ void arch_cpu_idle(void)
* This should do all the clock switching and wait for interrupt
* tricks
*/
- if (cpuidle_idle_call()) {
- cpu_do_idle();
- local_irq_enable();
- }
+ cpu_do_idle();
+ local_irq_enable();
}
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index 4f97db3d7363..ea4828a4aa96 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -176,22 +176,20 @@ static const struct of_device_id psci_of_match[] __initconst = {
{},
};
-int __init psci_init(void)
+void __init psci_init(void)
{
struct device_node *np;
const char *method;
u32 id;
- int err = 0;
np = of_find_matching_node(NULL, psci_of_match);
if (!np)
- return -ENODEV;
+ return;
pr_info("probing function IDs from device-tree\n");
if (of_property_read_string(np, "method", &method)) {
pr_warning("missing \"method\" property\n");
- err = -ENXIO;
goto out_put_node;
}
@@ -201,7 +199,6 @@ int __init psci_init(void)
invoke_psci_fn = __invoke_psci_fn_smc;
} else {
pr_warning("invalid \"method\" property: %s\n", method);
- err = -EINVAL;
goto out_put_node;
}
@@ -227,7 +224,7 @@ int __init psci_init(void)
out_put_node:
of_node_put(np);
- return err;
+ return;
}
#ifdef CONFIG_SMP
@@ -251,7 +248,7 @@ static int cpu_psci_cpu_boot(unsigned int cpu)
{
int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_entry));
if (err)
- pr_err("psci: failed to boot CPU%d (%d)\n", cpu, err);
+ pr_err("failed to boot CPU%d (%d)\n", cpu, err);
return err;
}
@@ -278,7 +275,7 @@ static void cpu_psci_cpu_die(unsigned int cpu)
ret = psci_ops.cpu_off(state);
- pr_crit("psci: unable to power off CPU%u (%d)\n", cpu, ret);
+ pr_crit("unable to power off CPU%u (%d)\n", cpu, ret);
}
#endif
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index c8e9effe52e1..67da30741a1b 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -69,6 +69,7 @@ EXPORT_SYMBOL_GPL(elf_hwcap);
COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV)
unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT;
+unsigned int compat_elf_hwcap2 __read_mostly;
#endif
static const char *cpu_name;
@@ -242,6 +243,38 @@ static void __init setup_processor(void)
block = (features >> 16) & 0xf;
if (block && !(block & 0x8))
elf_hwcap |= HWCAP_CRC32;
+
+#ifdef CONFIG_COMPAT
+ /*
+ * ID_ISAR5_EL1 carries similar information as above, but pertaining to
+ * the Aarch32 32-bit execution state.
+ */
+ features = read_cpuid(ID_ISAR5_EL1);
+ block = (features >> 4) & 0xf;
+ if (!(block & 0x8)) {
+ switch (block) {
+ default:
+ case 2:
+ compat_elf_hwcap2 |= COMPAT_HWCAP2_PMULL;
+ case 1:
+ compat_elf_hwcap2 |= COMPAT_HWCAP2_AES;
+ case 0:
+ break;
+ }
+ }
+
+ block = (features >> 8) & 0xf;
+ if (block && !(block & 0x8))
+ compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA1;
+
+ block = (features >> 12) & 0xf;
+ if (block && !(block & 0x8))
+ compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA2;
+
+ block = (features >> 16) & 0xf;
+ if (block && !(block & 0x8))
+ compat_elf_hwcap2 |= COMPAT_HWCAP2_CRC32;
+#endif
}
static void __init setup_machine_fdt(phys_addr_t dt_phys)
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 7cfb92a4ab66..f0a141dd5655 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -114,6 +114,11 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
return ret;
}
+static void smp_store_cpu_info(unsigned int cpuid)
+{
+ store_cpu_topology(cpuid);
+}
+
/*
* This is the secondary CPU boot entry. We're using this CPUs
* idle thread stack, but a set of temporary page tables.
@@ -152,6 +157,8 @@ asmlinkage void secondary_start_kernel(void)
*/
notify_cpu_starting(cpu);
+ smp_store_cpu_info(cpu);
+
/*
* OK, now it's safe to let the boot CPU continue. Wait for
* the CPU migration code to notice that the CPU is online
@@ -160,6 +167,7 @@ asmlinkage void secondary_start_kernel(void)
set_cpu_online(cpu, true);
complete(&cpu_running);
+ local_dbg_enable();
local_irq_enable();
local_async_enable();
@@ -390,6 +398,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
int err;
unsigned int cpu, ncores = num_possible_cpus();
+ init_cpu_topology();
+
+ smp_store_cpu_info(smp_processor_id());
+
/*
* are we trying to boot more cores than exist?
*/
diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c
index 44c22805d2e2..7a530d2cc807 100644
--- a/arch/arm64/kernel/smp_spin_table.c
+++ b/arch/arm64/kernel/smp_spin_table.c
@@ -128,7 +128,7 @@ static int smp_spin_table_cpu_boot(unsigned int cpu)
return secondary_holding_pen_release != INVALID_HWID ? -ENOSYS : 0;
}
-void smp_spin_table_cpu_postboot(void)
+static void smp_spin_table_cpu_postboot(void)
{
/*
* Let the primary processor know we're out of the pen.
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index c3b6c63ea5fb..38f0558f0c0a 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -48,7 +48,11 @@ int unwind_frame(struct stackframe *frame)
frame->sp = fp + 0x10;
frame->fp = *(unsigned long *)(fp);
- frame->pc = *(unsigned long *)(fp + 8);
+ /*
+ * -4 here because we care about the PC at time of bl,
+ * not where the return will go.
+ */
+ frame->pc = *(unsigned long *)(fp + 8) - 4;
return 0;
}
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
new file mode 100644
index 000000000000..3e06b0be4ec8
--- /dev/null
+++ b/arch/arm64/kernel/topology.c
@@ -0,0 +1,95 @@
+/*
+ * arch/arm64/kernel/topology.c
+ *
+ * Copyright (C) 2011,2013,2014 Linaro Limited.
+ *
+ * Based on the arm32 version written by Vincent Guittot in turn based on
+ * arch/sh/kernel/topology.c
+ *
+ * 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.
+ */
+
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/percpu.h>
+#include <linux/node.h>
+#include <linux/nodemask.h>
+#include <linux/sched.h>
+
+#include <asm/topology.h>
+
+/*
+ * cpu topology table
+ */
+struct cpu_topology cpu_topology[NR_CPUS];
+EXPORT_SYMBOL_GPL(cpu_topology);
+
+const struct cpumask *cpu_coregroup_mask(int cpu)
+{
+ return &cpu_topology[cpu].core_sibling;
+}
+
+static void update_siblings_masks(unsigned int cpuid)
+{
+ struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
+ int cpu;
+
+ if (cpuid_topo->cluster_id == -1) {
+ /*
+ * DT does not contain topology information for this cpu
+ * reset it to default behaviour
+ */
+ pr_debug("CPU%u: No topology information configured\n", cpuid);
+ cpuid_topo->core_id = 0;
+ cpumask_set_cpu(cpuid, &cpuid_topo->core_sibling);
+ cpumask_set_cpu(cpuid, &cpuid_topo->thread_sibling);
+ return;
+ }
+
+ /* update core and thread sibling masks */
+ for_each_possible_cpu(cpu) {
+ cpu_topo = &cpu_topology[cpu];
+
+ if (cpuid_topo->cluster_id != cpu_topo->cluster_id)
+ continue;
+
+ cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
+ if (cpu != cpuid)
+ cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
+
+ if (cpuid_topo->core_id != cpu_topo->core_id)
+ continue;
+
+ cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
+ if (cpu != cpuid)
+ cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
+ }
+}
+
+void store_cpu_topology(unsigned int cpuid)
+{
+ update_siblings_masks(cpuid);
+}
+
+/*
+ * init_cpu_topology is called at boot when only one cpu is running
+ * which prevent simultaneous write access to cpu_topology array
+ */
+void __init init_cpu_topology(void)
+{
+ unsigned int cpu;
+
+ /* init core mask and power*/
+ for_each_possible_cpu(cpu) {
+ struct cpu_topology *cpu_topo = &cpu_topology[cpu];
+
+ cpu_topo->thread_id = -1;
+ cpu_topo->core_id = -1;
+ cpu_topo->cluster_id = -1;
+ cpumask_clear(&cpu_topo->core_sibling);
+ cpumask_clear(&cpu_topo->thread_sibling);
+ }
+}
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index a7149cae1615..50384fec56c4 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -106,49 +106,31 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
static int __init vdso_init(void)
{
- struct page *pg;
- char *vbase;
- int i, ret = 0;
+ int i;
+
+ if (memcmp(&vdso_start, "\177ELF", 4)) {
+ pr_err("vDSO is not a valid ELF object!\n");
+ return -EINVAL;
+ }
vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
pr_info("vdso: %ld pages (%ld code, %ld data) at base %p\n",
vdso_pages + 1, vdso_pages, 1L, &vdso_start);
/* Allocate the vDSO pagelist, plus a page for the data. */
- vdso_pagelist = kzalloc(sizeof(struct page *) * (vdso_pages + 1),
+ vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *),
GFP_KERNEL);
- if (vdso_pagelist == NULL) {
- pr_err("Failed to allocate vDSO pagelist!\n");
+ if (vdso_pagelist == NULL)
return -ENOMEM;
- }
/* Grab the vDSO code pages. */
- for (i = 0; i < vdso_pages; i++) {
- pg = virt_to_page(&vdso_start + i*PAGE_SIZE);
- ClearPageReserved(pg);
- get_page(pg);
- vdso_pagelist[i] = pg;
- }
-
- /* Sanity check the shared object header. */
- vbase = vmap(vdso_pagelist, 1, 0, PAGE_KERNEL);
- if (vbase == NULL) {
- pr_err("Failed to map vDSO pagelist!\n");
- return -ENOMEM;
- } else if (memcmp(vbase, "\177ELF", 4)) {
- pr_err("vDSO is not a valid ELF object!\n");
- ret = -EINVAL;
- goto unmap;
- }
+ for (i = 0; i < vdso_pages; i++)
+ vdso_pagelist[i] = virt_to_page(&vdso_start + i * PAGE_SIZE);
/* Grab the vDSO data page. */
- pg = virt_to_page(vdso_data);
- get_page(pg);
- vdso_pagelist[i] = pg;
+ vdso_pagelist[i] = virt_to_page(vdso_data);
-unmap:
- vunmap(vbase);
- return ret;
+ return 0;
}
arch_initcall(vdso_init);
diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S
index 2b0244d65c16..d968796f4b2d 100644
--- a/arch/arm64/kvm/hyp-init.S
+++ b/arch/arm64/kvm/hyp-init.S
@@ -68,6 +68,12 @@ __do_hyp_init:
msr tcr_el2, x4
ldr x4, =VTCR_EL2_FLAGS
+ /*
+ * Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS bits in
+ * VTCR_EL2.
+ */
+ mrs x5, ID_AA64MMFR0_EL1
+ bfi x4, x5, #16, #3
msr vtcr_el2, x4
mrs x4, mair_el1
diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
index 3b47c36e10ff..2c56012cb2d2 100644
--- a/arch/arm64/kvm/hyp.S
+++ b/arch/arm64/kvm/hyp.S
@@ -694,6 +694,24 @@ __hyp_panic_str:
.align 2
+/*
+ * u64 kvm_call_hyp(void *hypfn, ...);
+ *
+ * This is not really a variadic function in the classic C-way and care must
+ * be taken when calling this to ensure parameters are passed in registers
+ * only, since the stack will change between the caller and the callee.
+ *
+ * Call the function with the first argument containing a pointer to the
+ * function you wish to call in Hyp mode, and subsequent arguments will be
+ * passed as x0, x1, and x2 (a maximum of 3 arguments in addition to the
+ * function pointer can be passed). The function being called must be mapped
+ * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c). Return values are
+ * passed in r0 and r1.
+ *
+ * A function pointer with a value of 0 has a special meaning, and is
+ * used to implement __hyp_get_vectors in the same way as in
+ * arch/arm64/kernel/hyp_stub.S.
+ */
ENTRY(kvm_call_hyp)
hvc #0
ret
@@ -737,7 +755,12 @@ el1_sync: // Guest trapped into EL2
pop x2, x3
pop x0, x1
- push lr, xzr
+ /* Check for __hyp_get_vectors */
+ cbnz x0, 1f
+ mrs x0, vbar_el2
+ b 2f
+
+1: push lr, xzr
/*
* Compute the function address in EL2, and shuffle the parameters.
@@ -750,7 +773,7 @@ el1_sync: // Guest trapped into EL2
blr lr
pop lr, xzr
- eret
+2: eret
el1_trap:
/*
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 02e9d09e1d80..03244582bc55 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -27,6 +27,7 @@
#include <asm/kvm_host.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_coproc.h>
+#include <asm/kvm_mmu.h>
#include <asm/cacheflush.h>
#include <asm/cputype.h>
#include <trace/events/kvm.h>
@@ -121,6 +122,48 @@ done:
}
/*
+ * Generic accessor for VM registers. Only called as long as HCR_TVM
+ * is set.
+ */
+static bool access_vm_reg(struct kvm_vcpu *vcpu,
+ const struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ unsigned long val;
+
+ BUG_ON(!p->is_write);
+
+ val = *vcpu_reg(vcpu, p->Rt);
+ if (!p->is_aarch32) {
+ vcpu_sys_reg(vcpu, r->reg) = val;
+ } else {
+ vcpu_cp15(vcpu, r->reg) = val & 0xffffffffUL;
+ if (!p->is_32bit)
+ vcpu_cp15(vcpu, r->reg + 1) = val >> 32;
+ }
+ return true;
+}
+
+/*
+ * SCTLR_EL1 accessor. Only called as long as HCR_TVM is set. If the
+ * guest enables the MMU, we stop trapping the VM sys_regs and leave
+ * it in complete control of the caches.
+ */
+static bool access_sctlr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ access_vm_reg(vcpu, p, r);
+
+ if (vcpu_has_cache_enabled(vcpu)) { /* MMU+Caches enabled? */
+ vcpu->arch.hcr_el2 &= ~HCR_TVM;
+ stage2_flush_vm(vcpu->kvm);
+ }
+
+ return true;
+}
+
+/*
* We could trap ID_DFR0 and tell the guest we don't support performance
* monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was
* NAKed, so it will read the PMCR anyway.
@@ -185,32 +228,32 @@ static const struct sys_reg_desc sys_reg_descs[] = {
NULL, reset_mpidr, MPIDR_EL1 },
/* SCTLR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b000),
- NULL, reset_val, SCTLR_EL1, 0x00C50078 },
+ access_sctlr, reset_val, SCTLR_EL1, 0x00C50078 },
/* CPACR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b010),
NULL, reset_val, CPACR_EL1, 0 },
/* TTBR0_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b000),
- NULL, reset_unknown, TTBR0_EL1 },
+ access_vm_reg, reset_unknown, TTBR0_EL1 },
/* TTBR1_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b001),
- NULL, reset_unknown, TTBR1_EL1 },
+ access_vm_reg, reset_unknown, TTBR1_EL1 },
/* TCR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b010),
- NULL, reset_val, TCR_EL1, 0 },
+ access_vm_reg, reset_val, TCR_EL1, 0 },
/* AFSR0_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b000),
- NULL, reset_unknown, AFSR0_EL1 },
+ access_vm_reg, reset_unknown, AFSR0_EL1 },
/* AFSR1_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b001),
- NULL, reset_unknown, AFSR1_EL1 },
+ access_vm_reg, reset_unknown, AFSR1_EL1 },
/* ESR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0010), Op2(0b000),
- NULL, reset_unknown, ESR_EL1 },
+ access_vm_reg, reset_unknown, ESR_EL1 },
/* FAR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0110), CRm(0b0000), Op2(0b000),
- NULL, reset_unknown, FAR_EL1 },
+ access_vm_reg, reset_unknown, FAR_EL1 },
/* PAR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0111), CRm(0b0100), Op2(0b000),
NULL, reset_unknown, PAR_EL1 },
@@ -224,17 +267,17 @@ static const struct sys_reg_desc sys_reg_descs[] = {
/* MAIR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
- NULL, reset_unknown, MAIR_EL1 },
+ access_vm_reg, reset_unknown, MAIR_EL1 },
/* AMAIR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0011), Op2(0b000),
- NULL, reset_amair_el1, AMAIR_EL1 },
+ access_vm_reg, reset_amair_el1, AMAIR_EL1 },
/* VBAR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000),
NULL, reset_val, VBAR_EL1, 0 },
/* CONTEXTIDR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001),
- NULL, reset_val, CONTEXTIDR_EL1, 0 },
+ access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 },
/* TPIDR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b100),
NULL, reset_unknown, TPIDR_EL1 },
@@ -305,14 +348,32 @@ static const struct sys_reg_desc sys_reg_descs[] = {
NULL, reset_val, FPEXC32_EL2, 0x70 },
};
-/* Trapped cp15 registers */
+/*
+ * Trapped cp15 registers. TTBR0/TTBR1 get a double encoding,
+ * depending on the way they are accessed (as a 32bit or a 64bit
+ * register).
+ */
static const struct sys_reg_desc cp15_regs[] = {
+ { Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
+ { Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_sctlr, NULL, c1_SCTLR },
+ { Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
+ { Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, c2_TTBR1 },
+ { Op1( 0), CRn( 2), CRm( 0), Op2( 2), access_vm_reg, NULL, c2_TTBCR },
+ { Op1( 0), CRn( 3), CRm( 0), Op2( 0), access_vm_reg, NULL, c3_DACR },
+ { Op1( 0), CRn( 5), CRm( 0), Op2( 0), access_vm_reg, NULL, c5_DFSR },
+ { Op1( 0), CRn( 5), CRm( 0), Op2( 1), access_vm_reg, NULL, c5_IFSR },
+ { Op1( 0), CRn( 5), CRm( 1), Op2( 0), access_vm_reg, NULL, c5_ADFSR },
+ { Op1( 0), CRn( 5), CRm( 1), Op2( 1), access_vm_reg, NULL, c5_AIFSR },
+ { Op1( 0), CRn( 6), CRm( 0), Op2( 0), access_vm_reg, NULL, c6_DFAR },
+ { Op1( 0), CRn( 6), CRm( 0), Op2( 2), access_vm_reg, NULL, c6_IFAR },
+
/*
* DC{C,I,CI}SW operations:
*/
{ Op1( 0), CRn( 7), CRm( 6), Op2( 2), access_dcsw },
{ Op1( 0), CRn( 7), CRm(10), Op2( 2), access_dcsw },
{ Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw },
+
{ Op1( 0), CRn( 9), CRm(12), Op2( 0), pm_fake },
{ Op1( 0), CRn( 9), CRm(12), Op2( 1), pm_fake },
{ Op1( 0), CRn( 9), CRm(12), Op2( 2), pm_fake },
@@ -326,6 +387,14 @@ static const struct sys_reg_desc cp15_regs[] = {
{ Op1( 0), CRn( 9), CRm(14), Op2( 0), pm_fake },
{ Op1( 0), CRn( 9), CRm(14), Op2( 1), pm_fake },
{ Op1( 0), CRn( 9), CRm(14), Op2( 2), pm_fake },
+
+ { Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
+ { Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
+ { Op1( 0), CRn(10), CRm( 3), Op2( 0), access_vm_reg, NULL, c10_AMAIR0 },
+ { Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, c10_AMAIR1 },
+ { Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
+
+ { Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR1 },
};
/* Target specific emulation tables */
@@ -437,6 +506,8 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
u32 hsr = kvm_vcpu_get_hsr(vcpu);
int Rt2 = (hsr >> 10) & 0xf;
+ params.is_aarch32 = true;
+ params.is_32bit = false;
params.CRm = (hsr >> 1) & 0xf;
params.Rt = (hsr >> 5) & 0xf;
params.is_write = ((hsr & 1) == 0);
@@ -480,6 +551,8 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
struct sys_reg_params params;
u32 hsr = kvm_vcpu_get_hsr(vcpu);
+ params.is_aarch32 = true;
+ params.is_32bit = true;
params.CRm = (hsr >> 1) & 0xf;
params.Rt = (hsr >> 5) & 0xf;
params.is_write = ((hsr & 1) == 0);
@@ -549,6 +622,8 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run)
struct sys_reg_params params;
unsigned long esr = kvm_vcpu_get_hsr(vcpu);
+ params.is_aarch32 = false;
+ params.is_32bit = false;
params.Op0 = (esr >> 20) & 3;
params.Op1 = (esr >> 14) & 0x7;
params.CRn = (esr >> 10) & 0xf;
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index d50d3722998e..d411e251412c 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -30,6 +30,8 @@ struct sys_reg_params {
u8 Op2;
u8 Rt;
bool is_write;
+ bool is_aarch32;
+ bool is_32bit; /* Only valid if is_aarch32 is true */
};
struct sys_reg_desc {
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 1ea9f26d1b70..c46f48b33c14 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -30,7 +30,7 @@
*
* Corrupted registers: x0-x7, x9-x11
*/
-ENTRY(__flush_dcache_all)
+__flush_dcache_all:
dsb sy // ensure ordering with previous memory accesses
mrs x0, clidr_el1 // read clidr
and x3, x0, #0x7000000 // extract loc from clidr
@@ -166,3 +166,81 @@ ENTRY(__flush_dcache_area)
dsb sy
ret
ENDPROC(__flush_dcache_area)
+
+/*
+ * __dma_inv_range(start, end)
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+__dma_inv_range:
+ dcache_line_size x2, x3
+ sub x3, x2, #1
+ bic x0, x0, x3
+ bic x1, x1, x3
+1: dc ivac, x0 // invalidate D / U line
+ add x0, x0, x2
+ cmp x0, x1
+ b.lo 1b
+ dsb sy
+ ret
+ENDPROC(__dma_inv_range)
+
+/*
+ * __dma_clean_range(start, end)
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+__dma_clean_range:
+ dcache_line_size x2, x3
+ sub x3, x2, #1
+ bic x0, x0, x3
+1: dc cvac, x0 // clean D / U line
+ add x0, x0, x2
+ cmp x0, x1
+ b.lo 1b
+ dsb sy
+ ret
+ENDPROC(__dma_clean_range)
+
+/*
+ * __dma_flush_range(start, end)
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+ENTRY(__dma_flush_range)
+ dcache_line_size x2, x3
+ sub x3, x2, #1
+ bic x0, x0, x3
+1: dc civac, x0 // clean & invalidate D / U line
+ add x0, x0, x2
+ cmp x0, x1
+ b.lo 1b
+ dsb sy
+ ret
+ENDPROC(__dma_flush_range)
+
+/*
+ * __dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(__dma_map_area)
+ add x1, x1, x0
+ cmp w2, #DMA_FROM_DEVICE
+ b.eq __dma_inv_range
+ b __dma_clean_range
+ENDPROC(__dma_map_area)
+
+/*
+ * __dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(__dma_unmap_area)
+ add x1, x1, x0
+ cmp w2, #DMA_TO_DEVICE
+ b.ne __dma_inv_range
+ ret
+ENDPROC(__dma_unmap_area)
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index fbd76785c5db..0ba347e59f06 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -30,18 +30,26 @@
struct dma_map_ops *dma_ops;
EXPORT_SYMBOL(dma_ops);
-static void *arm64_swiotlb_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flags,
- struct dma_attrs *attrs)
+static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
+ bool coherent)
+{
+ if (!coherent || dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
+ return pgprot_writecombine(prot);
+ return prot;
+}
+
+static void *__dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flags,
+ struct dma_attrs *attrs)
{
if (dev == NULL) {
WARN_ONCE(1, "Use an actual device structure for DMA allocation\n");
return NULL;
}
- if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
+ if (IS_ENABLED(CONFIG_ZONE_DMA) &&
dev->coherent_dma_mask <= DMA_BIT_MASK(32))
- flags |= GFP_DMA32;
+ flags |= GFP_DMA;
if (IS_ENABLED(CONFIG_DMA_CMA)) {
struct page *page;
@@ -58,9 +66,9 @@ static void *arm64_swiotlb_alloc_coherent(struct device *dev, size_t size,
}
}
-static void arm64_swiotlb_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle,
- struct dma_attrs *attrs)
+static void __dma_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
{
if (dev == NULL) {
WARN_ONCE(1, "Use an actual device structure for DMA allocation\n");
@@ -78,9 +86,212 @@ static void arm64_swiotlb_free_coherent(struct device *dev, size_t size,
}
}
-static struct dma_map_ops arm64_swiotlb_dma_ops = {
- .alloc = arm64_swiotlb_alloc_coherent,
- .free = arm64_swiotlb_free_coherent,
+static void *__dma_alloc_noncoherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flags,
+ struct dma_attrs *attrs)
+{
+ struct page *page, **map;
+ void *ptr, *coherent_ptr;
+ int order, i;
+
+ size = PAGE_ALIGN(size);
+ order = get_order(size);
+
+ ptr = __dma_alloc_coherent(dev, size, dma_handle, flags, attrs);
+ if (!ptr)
+ goto no_mem;
+ map = kmalloc(sizeof(struct page *) << order, flags & ~GFP_DMA);
+ if (!map)
+ goto no_map;
+
+ /* remove any dirty cache lines on the kernel alias */
+ __dma_flush_range(ptr, ptr + size);
+
+ /* create a coherent mapping */
+ page = virt_to_page(ptr);
+ for (i = 0; i < (size >> PAGE_SHIFT); i++)
+ map[i] = page + i;
+ coherent_ptr = vmap(map, size >> PAGE_SHIFT, VM_MAP,
+ __get_dma_pgprot(attrs, pgprot_default, false));
+ kfree(map);
+ if (!coherent_ptr)
+ goto no_map;
+
+ return coherent_ptr;
+
+no_map:
+ __dma_free_coherent(dev, size, ptr, *dma_handle, attrs);
+no_mem:
+ *dma_handle = ~0;
+ return NULL;
+}
+
+static void __dma_free_noncoherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
+{
+ void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle));
+
+ vunmap(vaddr);
+ __dma_free_coherent(dev, size, swiotlb_addr, dma_handle, attrs);
+}
+
+static dma_addr_t __swiotlb_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ dma_addr_t dev_addr;
+
+ dev_addr = swiotlb_map_page(dev, page, offset, size, dir, attrs);
+ __dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
+
+ return dev_addr;
+}
+
+
+static void __swiotlb_unmap_page(struct device *dev, dma_addr_t dev_addr,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
+ swiotlb_unmap_page(dev, dev_addr, size, dir, attrs);
+}
+
+static int __swiotlb_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
+ int nelems, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct scatterlist *sg;
+ int i, ret;
+
+ ret = swiotlb_map_sg_attrs(dev, sgl, nelems, dir, attrs);
+ for_each_sg(sgl, sg, ret, i)
+ __dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
+ sg->length, dir);
+
+ return ret;
+}
+
+static void __swiotlb_unmap_sg_attrs(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(sgl, sg, nelems, i)
+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
+ sg->length, dir);
+ swiotlb_unmap_sg_attrs(dev, sgl, nelems, dir, attrs);
+}
+
+static void __swiotlb_sync_single_for_cpu(struct device *dev,
+ dma_addr_t dev_addr, size_t size,
+ enum dma_data_direction dir)
+{
+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
+ swiotlb_sync_single_for_cpu(dev, dev_addr, size, dir);
+}
+
+static void __swiotlb_sync_single_for_device(struct device *dev,
+ dma_addr_t dev_addr, size_t size,
+ enum dma_data_direction dir)
+{
+ swiotlb_sync_single_for_device(dev, dev_addr, size, dir);
+ __dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
+}
+
+static void __swiotlb_sync_sg_for_cpu(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir)
+{
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(sgl, sg, nelems, i)
+ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
+ sg->length, dir);
+ swiotlb_sync_sg_for_cpu(dev, sgl, nelems, dir);
+}
+
+static void __swiotlb_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir)
+{
+ struct scatterlist *sg;
+ int i;
+
+ swiotlb_sync_sg_for_device(dev, sgl, nelems, dir);
+ for_each_sg(sgl, sg, nelems, i)
+ __dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
+ sg->length, dir);
+}
+
+/* vma->vm_page_prot must be set appropriately before calling this function */
+static int __dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+ int ret = -ENXIO;
+ unsigned long nr_vma_pages = (vma->vm_end - vma->vm_start) >>
+ PAGE_SHIFT;
+ unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ unsigned long pfn = dma_to_phys(dev, dma_addr) >> PAGE_SHIFT;
+ unsigned long off = vma->vm_pgoff;
+
+ if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+ return ret;
+
+ if (off < nr_pages && nr_vma_pages <= (nr_pages - off)) {
+ ret = remap_pfn_range(vma, vma->vm_start,
+ pfn + off,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+ }
+
+ return ret;
+}
+
+static int __swiotlb_mmap_noncoherent(struct device *dev,
+ struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs)
+{
+ vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot, false);
+ return __dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+
+static int __swiotlb_mmap_coherent(struct device *dev,
+ struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs)
+{
+ /* Just use whatever page_prot attributes were specified */
+ return __dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+
+struct dma_map_ops noncoherent_swiotlb_dma_ops = {
+ .alloc = __dma_alloc_noncoherent,
+ .free = __dma_free_noncoherent,
+ .mmap = __swiotlb_mmap_noncoherent,
+ .map_page = __swiotlb_map_page,
+ .unmap_page = __swiotlb_unmap_page,
+ .map_sg = __swiotlb_map_sg_attrs,
+ .unmap_sg = __swiotlb_unmap_sg_attrs,
+ .sync_single_for_cpu = __swiotlb_sync_single_for_cpu,
+ .sync_single_for_device = __swiotlb_sync_single_for_device,
+ .sync_sg_for_cpu = __swiotlb_sync_sg_for_cpu,
+ .sync_sg_for_device = __swiotlb_sync_sg_for_device,
+ .dma_supported = swiotlb_dma_supported,
+ .mapping_error = swiotlb_dma_mapping_error,
+};
+EXPORT_SYMBOL(noncoherent_swiotlb_dma_ops);
+
+struct dma_map_ops coherent_swiotlb_dma_ops = {
+ .alloc = __dma_alloc_coherent,
+ .free = __dma_free_coherent,
+ .mmap = __swiotlb_mmap_coherent,
.map_page = swiotlb_map_page,
.unmap_page = swiotlb_unmap_page,
.map_sg = swiotlb_map_sg_attrs,
@@ -92,12 +303,19 @@ static struct dma_map_ops arm64_swiotlb_dma_ops = {
.dma_supported = swiotlb_dma_supported,
.mapping_error = swiotlb_dma_mapping_error,
};
+EXPORT_SYMBOL(coherent_swiotlb_dma_ops);
+
+extern int swiotlb_late_init_with_default_size(size_t default_size);
-void __init arm64_swiotlb_init(void)
+static int __init swiotlb_late_init(void)
{
- dma_ops = &arm64_swiotlb_dma_ops;
- swiotlb_init(1);
+ size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT);
+
+ dma_ops = &coherent_swiotlb_dma_ops;
+
+ return swiotlb_late_init_with_default_size(swiotlb_size);
}
+subsys_initcall(swiotlb_late_init);
#define PREALLOC_DMA_DEBUG_ENTRIES 4096
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index d0b4c2efda90..51d5352e6ad5 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -30,6 +30,7 @@
#include <linux/memblock.h>
#include <linux/sort.h>
#include <linux/of_fdt.h>
+#include <linux/dma-mapping.h>
#include <linux/dma-contiguous.h>
#include <asm/sections.h>
@@ -59,22 +60,22 @@ static int __init early_initrd(char *p)
early_param("initrd", early_initrd);
#endif
-#define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT)
-
static void __init zone_sizes_init(unsigned long min, unsigned long max)
{
struct memblock_region *reg;
unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
- unsigned long max_dma32 = min;
+ unsigned long max_dma = min;
memset(zone_size, 0, sizeof(zone_size));
-#ifdef CONFIG_ZONE_DMA32
/* 4GB maximum for 32-bit only capable devices */
- max_dma32 = max(min, min(max, MAX_DMA32_PFN));
- zone_size[ZONE_DMA32] = max_dma32 - min;
-#endif
- zone_size[ZONE_NORMAL] = max - max_dma32;
+ if (IS_ENABLED(CONFIG_ZONE_DMA)) {
+ unsigned long max_dma_phys =
+ (unsigned long)dma_to_phys(NULL, DMA_BIT_MASK(32) + 1);
+ max_dma = max(min, min(max, max_dma_phys >> PAGE_SHIFT));
+ zone_size[ZONE_DMA] = max_dma - min;
+ }
+ zone_size[ZONE_NORMAL] = max - max_dma;
memcpy(zhole_size, zone_size, sizeof(zhole_size));
@@ -84,15 +85,15 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
if (start >= max)
continue;
-#ifdef CONFIG_ZONE_DMA32
- if (start < max_dma32) {
- unsigned long dma_end = min(end, max_dma32);
- zhole_size[ZONE_DMA32] -= dma_end - start;
+
+ if (IS_ENABLED(CONFIG_ZONE_DMA) && start < max_dma) {
+ unsigned long dma_end = min(end, max_dma);
+ zhole_size[ZONE_DMA] -= dma_end - start;
}
-#endif
- if (end > max_dma32) {
+
+ if (end > max_dma) {
unsigned long normal_end = min(end, max);
- unsigned long normal_start = max(start, max_dma32);
+ unsigned long normal_start = max(start, max_dma);
zhole_size[ZONE_NORMAL] -= normal_end - normal_start;
}
}
@@ -160,6 +161,7 @@ void __init arm64_memblock_init(void)
memblock_reserve(base, size);
}
+ early_init_fdt_scan_reserved_mem();
dma_contiguous_reserve(0);
memblock_allow_resize();
@@ -261,8 +263,6 @@ static void __init free_unused_memmap(void)
*/
void __init mem_init(void)
{
- arm64_swiotlb_init();
-
max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
#ifndef CONFIG_SPARSEMEM_VMEMMAP
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 1333e6f9a8e5..e085ee6ef4e2 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -173,12 +173,6 @@ ENDPROC(cpu_do_switch_mm)
* value of the SCTLR_EL1 register.
*/
ENTRY(__cpu_setup)
- /*
- * Preserve the link register across the function call.
- */
- mov x28, lr
- bl __flush_dcache_all
- mov lr, x28
ic iallu // I+BTB cache invalidate
tlbi vmalle1is // invalidate I + D TLBs
dsb sy
@@ -215,8 +209,14 @@ ENTRY(__cpu_setup)
* Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for
* both user and kernel.
*/
- ldr x10, =TCR_TxSZ(VA_BITS) | TCR_FLAGS | TCR_IPS_40BIT | \
+ ldr x10, =TCR_TxSZ(VA_BITS) | TCR_FLAGS | \
TCR_ASID16 | TCR_TBI0 | (1 << 31)
+ /*
+ * Read the PARange bits from ID_AA64MMFR0_EL1 and set the IPS bits in
+ * TCR_EL1.
+ */
+ mrs x9, ID_AA64MMFR0_EL1
+ bfi x10, x9, #32, #3
#ifdef CONFIG_ARM64_64K_PAGES
orr x10, x10, TCR_TG0_64K
orr x10, x10, TCR_TG1_64K
diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile
index 22fb66590dcd..dba48a5d5bb9 100644
--- a/arch/avr32/Makefile
+++ b/arch/avr32/Makefile
@@ -11,7 +11,7 @@ all: uImage vmlinux.elf
KBUILD_DEFCONFIG := atstk1002_defconfig
-KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic
+KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic -D__linux__
KBUILD_AFLAGS += -mrelax -mno-pic
KBUILD_CFLAGS_MODULE += -mno-relax
LDFLAGS_vmlinux += --relax
diff --git a/arch/avr32/boards/mimc200/Makefile b/arch/avr32/boards/mimc200/Makefile
index 79c076e168a8..c740aa116755 100644
--- a/arch/avr32/boards/mimc200/Makefile
+++ b/arch/avr32/boards/mimc200/Makefile
@@ -1 +1 @@
-obj-y += setup.o flash.o fram.o
+obj-y += setup.o flash.o
diff --git a/arch/avr32/boards/mimc200/fram.c b/arch/avr32/boards/mimc200/fram.c
deleted file mode 100644
index 9764a1a1073e..000000000000
--- a/arch/avr32/boards/mimc200/fram.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * FRAM driver for MIMC200 board
- *
- * Copyright 2008 Mark Jackson <mpfj@mimc.co.uk>
- *
- * This module adds *very* simply support for the system's FRAM device.
- * At the moment, this is hard-coded to the MIMC200 platform, and only
- * supports mmap().
- */
-
-#define FRAM_VERSION "1.0"
-
-#include <linux/miscdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/mm.h>
-#include <linux/io.h>
-
-#define FRAM_BASE 0xac000000
-#define FRAM_SIZE 0x20000
-
-/*
- * The are the file operation function for user access to /dev/fram
- */
-
-static int fram_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- int ret;
-
- ret = remap_pfn_range(vma,
- vma->vm_start,
- virt_to_phys((void *)((unsigned long)FRAM_BASE)) >> PAGE_SHIFT,
- vma->vm_end-vma->vm_start,
- PAGE_SHARED);
-
- if (ret != 0)
- return -EAGAIN;
-
- return 0;
-}
-
-static const struct file_operations fram_fops = {
- .owner = THIS_MODULE,
- .mmap = fram_mmap,
- .llseek = noop_llseek,
-};
-
-#define FRAM_MINOR 0
-
-static struct miscdevice fram_dev = {
- FRAM_MINOR,
- "fram",
- &fram_fops
-};
-
-static int __init
-fram_init(void)
-{
- int ret;
-
- ret = misc_register(&fram_dev);
- if (ret) {
- printk(KERN_ERR "fram: can't misc_register on minor=%d\n",
- FRAM_MINOR);
- return ret;
- }
- printk(KERN_INFO "FRAM memory driver v" FRAM_VERSION "\n");
- return 0;
-}
-
-static void __exit
-fram_cleanup_module(void)
-{
- misc_deregister(&fram_dev);
-}
-
-module_init(fram_init);
-module_exit(fram_cleanup_module);
-
-MODULE_LICENSE("GPL");
-
-MODULE_ALIAS_MISCDEV(FRAM_MINOR);
diff --git a/arch/avr32/include/asm/Kbuild b/arch/avr32/include/asm/Kbuild
index cfb9fe1b8df9..00a0f3ccd6eb 100644
--- a/arch/avr32/include/asm/Kbuild
+++ b/arch/avr32/include/asm/Kbuild
@@ -1,21 +1,23 @@
-generic-y += clkdev.h
-generic-y += cputime.h
-generic-y += delay.h
-generic-y += device.h
-generic-y += div64.h
-generic-y += emergency-restart.h
-generic-y += exec.h
-generic-y += futex.h
-generic-y += preempt.h
-generic-y += irq_regs.h
-generic-y += param.h
-generic-y += local.h
-generic-y += local64.h
-generic-y += percpu.h
-generic-y += scatterlist.h
-generic-y += sections.h
-generic-y += topology.h
-generic-y += trace_clock.h
-generic-y += xor.h
-generic-y += hash.h
+generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += delay.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += emergency-restart.h
+generic-y += exec.h
+generic-y += futex.h
+generic-y += hash.h
+generic-y += irq_regs.h
+generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
+generic-y += param.h
+generic-y += percpu.h
+generic-y += preempt.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += topology.h
+generic-y += trace_clock.h
+generic-y += vga.h
+generic-y += xor.h
diff --git a/arch/avr32/include/asm/bugs.h b/arch/avr32/include/asm/bugs.h
index 7635e770622e..278661bbd1b0 100644
--- a/arch/avr32/include/asm/bugs.h
+++ b/arch/avr32/include/asm/bugs.h
@@ -9,7 +9,7 @@
static void __init check_bugs(void)
{
- cpu_data->loops_per_jiffy = loops_per_jiffy;
+ boot_cpu_data.loops_per_jiffy = loops_per_jiffy;
}
#endif /* __ASM_AVR32_BUGS_H */
diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h
index fc6483f83ccc..4f5ec2bb7172 100644
--- a/arch/avr32/include/asm/io.h
+++ b/arch/avr32/include/asm/io.h
@@ -295,6 +295,8 @@ extern void __iounmap(void __iomem *addr);
#define iounmap(addr) \
__iounmap(addr)
+#define ioremap_wc ioremap_nocache
+
#define cached(addr) P1SEGADDR(addr)
#define uncached(addr) P2SEGADDR(addr)
diff --git a/arch/avr32/include/asm/processor.h b/arch/avr32/include/asm/processor.h
index 48d71c5c898a..972adcc1e8f4 100644
--- a/arch/avr32/include/asm/processor.h
+++ b/arch/avr32/include/asm/processor.h
@@ -83,13 +83,8 @@ static inline unsigned int avr32_get_chip_revision(struct avr32_cpuinfo *cpu)
extern struct avr32_cpuinfo boot_cpu_data;
-#ifdef CONFIG_SMP
-extern struct avr32_cpuinfo cpu_data[];
-#define current_cpu_data cpu_data[smp_processor_id()]
-#else
-#define cpu_data (&boot_cpu_data)
+/* No SMP support so far */
#define current_cpu_data boot_cpu_data
-#endif
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's
diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c
index 2233be71e2e8..0341ae27c9ec 100644
--- a/arch/avr32/kernel/cpu.c
+++ b/arch/avr32/kernel/cpu.c
@@ -39,10 +39,12 @@ static ssize_t store_pc0event(struct device *dev,
size_t count)
{
unsigned long val;
- char *endp;
+ int ret;
- val = simple_strtoul(buf, &endp, 0);
- if (endp == buf || val > 0x3f)
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
+ if (val > 0x3f)
return -EINVAL;
val = (val << 12) | (sysreg_read(PCCR) & 0xfffc0fff);
sysreg_write(PCCR, val);
@@ -61,11 +63,11 @@ static ssize_t store_pc0count(struct device *dev,
const char *buf, size_t count)
{
unsigned long val;
- char *endp;
+ int ret;
- val = simple_strtoul(buf, &endp, 0);
- if (endp == buf)
- return -EINVAL;
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
sysreg_write(PCNT0, val);
return count;
@@ -84,10 +86,12 @@ static ssize_t store_pc1event(struct device *dev,
size_t count)
{
unsigned long val;
- char *endp;
+ int ret;
- val = simple_strtoul(buf, &endp, 0);
- if (endp == buf || val > 0x3f)
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
+ if (val > 0x3f)
return -EINVAL;
val = (val << 18) | (sysreg_read(PCCR) & 0xff03ffff);
sysreg_write(PCCR, val);
@@ -106,11 +110,11 @@ static ssize_t store_pc1count(struct device *dev,
size_t count)
{
unsigned long val;
- char *endp;
+ int ret;
- val = simple_strtoul(buf, &endp, 0);
- if (endp == buf)
- return -EINVAL;
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
sysreg_write(PCNT1, val);
return count;
@@ -129,11 +133,11 @@ static ssize_t store_pccycles(struct device *dev,
size_t count)
{
unsigned long val;
- char *endp;
+ int ret;
- val = simple_strtoul(buf, &endp, 0);
- if (endp == buf)
- return -EINVAL;
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
sysreg_write(PCCNT, val);
return count;
@@ -152,11 +156,11 @@ static ssize_t store_pcenable(struct device *dev,
size_t count)
{
unsigned long pccr, val;
- char *endp;
+ int ret;
- val = simple_strtoul(buf, &endp, 0);
- if (endp == buf)
- return -EINVAL;
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
if (val)
val = 1;
diff --git a/arch/avr32/mm/cache.c b/arch/avr32/mm/cache.c
index 6a46ecd56cfd..85d635cd7b28 100644
--- a/arch/avr32/mm/cache.c
+++ b/arch/avr32/mm/cache.c
@@ -111,6 +111,7 @@ void flush_icache_range(unsigned long start, unsigned long end)
__flush_icache_range(start & ~(linesz - 1),
(end + linesz - 1) & ~(linesz - 1));
}
+EXPORT_SYMBOL(flush_icache_range);
/*
* This one is called from __do_fault() and do_swap_page().
diff --git a/arch/blackfin/include/asm/Kbuild b/arch/blackfin/include/asm/Kbuild
index 359d36fdc247..0d93b9a79ca9 100644
--- a/arch/blackfin/include/asm/Kbuild
+++ b/arch/blackfin/include/asm/Kbuild
@@ -10,6 +10,7 @@ generic-y += emergency-restart.h
generic-y += errno.h
generic-y += fb.h
generic-y += futex.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ipcbuf.h
@@ -17,14 +18,16 @@ generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += kvm_para.h
-generic-y += local64.h
generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += msgbuf.h
generic-y += mutex.h
generic-y += param.h
generic-y += percpu.h
generic-y += pgalloc.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sembuf.h
@@ -44,5 +47,3 @@ generic-y += ucontext.h
generic-y += unaligned.h
generic-y += user.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/blackfin/include/asm/irq.h b/arch/blackfin/include/asm/irq.h
index 2fd04f10cc26..89de539ed010 100644
--- a/arch/blackfin/include/asm/irq.h
+++ b/arch/blackfin/include/asm/irq.h
@@ -20,15 +20,6 @@
/* SYS_IRQS and NR_IRQS are defined in <mach-bf5xx/irq.h> */
#include <mach/irq.h>
-/*
- * pm save bfin pint registers
- */
-struct adi_pm_pint_save {
- u32 assign;
- u32 edge_set;
- u32 invert_set;
-};
-
#if ANOMALY_05000244 && defined(CONFIG_BFIN_ICACHE)
# define NOP_PAD_ANOMALY_05000244 "nop; nop;"
#else
diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild
index d73bb85ccdd3..8dbdce8421b0 100644
--- a/arch/c6x/include/asm/Kbuild
+++ b/arch/c6x/include/asm/Kbuild
@@ -15,6 +15,7 @@ generic-y += exec.h
generic-y += fb.h
generic-y += fcntl.h
generic-y += futex.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += io.h
generic-y += ioctl.h
@@ -24,6 +25,7 @@ generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += local.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += mmu.h
generic-y += mmu_context.h
@@ -34,6 +36,7 @@ generic-y += percpu.h
generic-y += pgalloc.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += segment.h
@@ -56,5 +59,3 @@ generic-y += ucontext.h
generic-y += user.h
generic-y += vga.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/c6x/include/asm/cache.h b/arch/c6x/include/asm/cache.h
index 09c5a0f5f4d1..86648c083bb4 100644
--- a/arch/c6x/include/asm/cache.h
+++ b/arch/c6x/include/asm/cache.h
@@ -12,6 +12,7 @@
#define _ASM_C6X_CACHE_H
#include <linux/irqflags.h>
+#include <linux/init.h>
/*
* Cache line size
diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild
index f3fd8768f095..afff5105909d 100644
--- a/arch/cris/include/asm/Kbuild
+++ b/arch/cris/include/asm/Kbuild
@@ -5,12 +5,14 @@ header-y += arch-v32/
generic-y += barrier.h
generic-y += clkdev.h
+generic-y += cputime.h
generic-y += exec.h
generic-y += hash.h
generic-y += kvm_para.h
generic-y += linkage.h
+generic-y += mcs_spinlock.h
generic-y += module.h
+generic-y += preempt.h
generic-y += trace_clock.h
generic-y += vga.h
generic-y += xor.h
-generic-y += preempt.h
diff --git a/arch/cris/include/asm/bitops.h b/arch/cris/include/asm/bitops.h
index 184066ceb1f6..053c17b36559 100644
--- a/arch/cris/include/asm/bitops.h
+++ b/arch/cris/include/asm/bitops.h
@@ -144,7 +144,7 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
* definition, which doesn't have the same semantics. We don't want to
* use -fno-builtin, so just hide the name ffs.
*/
-#define ffs kernel_ffs
+#define ffs(x) kernel_ffs(x)
#include <asm-generic/bitops/fls.h>
#include <asm-generic/bitops/__fls.h>
diff --git a/arch/cris/include/asm/cputime.h b/arch/cris/include/asm/cputime.h
deleted file mode 100644
index 4446a65656fa..000000000000
--- a/arch/cris/include/asm/cputime.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __CRIS_CPUTIME_H
-#define __CRIS_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __CRIS_CPUTIME_H */
diff --git a/arch/frv/include/asm/Kbuild b/arch/frv/include/asm/Kbuild
index bc42f14c9c2e..87b95eb8aee5 100644
--- a/arch/frv/include/asm/Kbuild
+++ b/arch/frv/include/asm/Kbuild
@@ -1,6 +1,8 @@
generic-y += clkdev.h
+generic-y += cputime.h
generic-y += exec.h
-generic-y += trace_clock.h
-generic-y += preempt.h
generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
+generic-y += trace_clock.h
diff --git a/arch/frv/include/asm/cputime.h b/arch/frv/include/asm/cputime.h
deleted file mode 100644
index f6c373ad2b80..000000000000
--- a/arch/frv/include/asm/cputime.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_CPUTIME_H
-#define _ASM_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* _ASM_CPUTIME_H */
diff --git a/arch/frv/mb93090-mb00/pci-frv.c b/arch/frv/mb93090-mb00/pci-frv.c
index c28121765448..67b1d1685759 100644
--- a/arch/frv/mb93090-mb00/pci-frv.c
+++ b/arch/frv/mb93090-mb00/pci-frv.c
@@ -88,7 +88,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
/* Depth-First Search on bus tree */
for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
- bus = pci_bus_b(ln);
+ bus = list_entry(ln, struct pci_bus, node);
if ((dev = bus->self)) {
for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
r = &dev->resource[idx];
diff --git a/arch/hexagon/include/asm/Kbuild b/arch/hexagon/include/asm/Kbuild
index 38ca45d3df1e..eadcc118f950 100644
--- a/arch/hexagon/include/asm/Kbuild
+++ b/arch/hexagon/include/asm/Kbuild
@@ -25,14 +25,16 @@ generic-y += ipcbuf.h
generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += kmap_types.h
-generic-y += local64.h
generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += msgbuf.h
generic-y += pci.h
generic-y += percpu.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += rwsem.h
generic-y += scatterlist.h
@@ -45,8 +47,8 @@ generic-y += siginfo.h
generic-y += sizes.h
generic-y += socket.h
generic-y += sockios.h
-generic-y += statfs.h
generic-y += stat.h
+generic-y += statfs.h
generic-y += termbits.h
generic-y += termios.h
generic-y += topology.h
@@ -55,4 +57,3 @@ generic-y += types.h
generic-y += ucontext.h
generic-y += unaligned.h
generic-y += xor.h
-generic-y += preempt.h
diff --git a/arch/ia64/configs/generic_defconfig b/arch/ia64/configs/generic_defconfig
index efbd2929aeb7..b4efaf2bc13e 100644
--- a/arch/ia64/configs/generic_defconfig
+++ b/arch/ia64/configs/generic_defconfig
@@ -25,14 +25,13 @@ CONFIG_KEXEC=y
CONFIG_CRASH_DUMP=y
CONFIG_EFI_VARS=y
CONFIG_BINFMT_MISC=m
-CONFIG_ACPI_PROCFS=y
CONFIG_ACPI_BUTTON=m
CONFIG_ACPI_FAN=m
CONFIG_ACPI_DOCK=y
CONFIG_ACPI_PROCESSOR=m
-CONFIG_ACPI_CONTAINER=m
+CONFIG_ACPI_CONTAINER=y
CONFIG_HOTPLUG_PCI=y
-CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI_ACPI=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig
index 0f4e9e41f130..0fed9ae5a42a 100644
--- a/arch/ia64/configs/tiger_defconfig
+++ b/arch/ia64/configs/tiger_defconfig
@@ -26,7 +26,6 @@ CONFIG_IA64_PALINFO=y
CONFIG_KEXEC=y
CONFIG_EFI_VARS=y
CONFIG_BINFMT_MISC=m
-CONFIG_ACPI_PROCFS=y
CONFIG_ACPI_BUTTON=m
CONFIG_ACPI_FAN=m
CONFIG_ACPI_PROCESSOR=m
diff --git a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig
index fc7aba07c2b4..54bc72eda30d 100644
--- a/arch/ia64/configs/zx1_defconfig
+++ b/arch/ia64/configs/zx1_defconfig
@@ -16,7 +16,6 @@ CONFIG_IA64_PALINFO=y
CONFIG_CRASH_DUMP=y
CONFIG_EFI_VARS=y
CONFIG_BINFMT_MISC=y
-CONFIG_ACPI_PROCFS=y
CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_ACPI=y
CONFIG_PACKET=y
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index 8e858b593e4f..1a871b78e570 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -1140,11 +1140,13 @@ sba_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
#ifdef CONFIG_NUMA
{
+ int node = ioc->node;
struct page *page;
- page = alloc_pages_exact_node(ioc->node == MAX_NUMNODES ?
- numa_node_id() : ioc->node, flags,
- get_order(size));
+ if (node == NUMA_NO_NODE)
+ node = numa_node_id();
+
+ page = alloc_pages_exact_node(node, flags, get_order(size));
if (unlikely(!page))
return NULL;
@@ -1596,7 +1598,7 @@ static void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
*
***************************************************************/
-static void __init
+static void
ioc_iova_init(struct ioc *ioc)
{
int tcnfg;
@@ -1807,7 +1809,7 @@ static struct ioc_iommu ioc_iommu_info[] __initdata = {
{ SX2000_IOC_ID, "sx2000", NULL },
};
-static struct ioc * __init
+static struct ioc *
ioc_init(unsigned long hpa, void *handle)
{
struct ioc *ioc;
@@ -1914,7 +1916,7 @@ ioc_show(struct seq_file *s, void *v)
seq_printf(s, "Hewlett Packard %s IOC rev %d.%d\n",
ioc->name, ((ioc->rev >> 4) & 0xF), (ioc->rev & 0xF));
#ifdef CONFIG_NUMA
- if (ioc->node != MAX_NUMNODES)
+ if (ioc->node != NUMA_NO_NODE)
seq_printf(s, "NUMA node : %d\n", ioc->node);
#endif
seq_printf(s, "IOVA size : %ld MB\n", ((ioc->pdir_size >> 3) * iovp_size)/(1024*1024));
@@ -2015,33 +2017,21 @@ sba_connect_bus(struct pci_bus *bus)
printk(KERN_WARNING "No IOC for PCI Bus %04x:%02x in ACPI\n", pci_domain_nr(bus), bus->number);
}
-#ifdef CONFIG_NUMA
static void __init
sba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle)
{
+#ifdef CONFIG_NUMA
unsigned int node;
- int pxm;
-
- ioc->node = MAX_NUMNODES;
-
- pxm = acpi_get_pxm(handle);
-
- if (pxm < 0)
- return;
-
- node = pxm_to_node(pxm);
- if (node >= MAX_NUMNODES || !node_online(node))
- return;
+ node = acpi_get_node(handle);
+ if (node != NUMA_NO_NODE && !node_online(node))
+ node = NUMA_NO_NODE;
ioc->node = node;
- return;
-}
-#else
-#define sba_map_ioc_to_node(ioc, handle)
#endif
+}
-static int __init
+static int
acpi_sba_ioc_add(struct acpi_device *device,
const struct acpi_device_id *not_used)
{
diff --git a/arch/ia64/include/asm/Kbuild b/arch/ia64/include/asm/Kbuild
index 283a83154b5e..0da4aa2602ae 100644
--- a/arch/ia64/include/asm/Kbuild
+++ b/arch/ia64/include/asm/Kbuild
@@ -1,8 +1,9 @@
generic-y += clkdev.h
generic-y += exec.h
+generic-y += hash.h
generic-y += kvm_para.h
-generic-y += trace_clock.h
+generic-y += mcs_spinlock.h
generic-y += preempt.h
+generic-y += trace_clock.h
generic-y += vtime.h
-generic-y += hash.h
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index 71fbaaa495cc..7d41cc089822 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -98,7 +98,7 @@ struct pci_controller {
struct acpi_device *companion;
void *iommu;
int segment;
- int node; /* nearest node with memory or -1 for global allocation */
+ int node; /* nearest node with memory or NUMA_NO_NODE for global allocation */
void *platform_data;
};
diff --git a/arch/ia64/include/asm/topology.h b/arch/ia64/include/asm/topology.h
index a2496e449b75..5cb55a1e606b 100644
--- a/arch/ia64/include/asm/topology.h
+++ b/arch/ia64/include/asm/topology.h
@@ -77,7 +77,6 @@ void build_cpu_to_node_map(void);
#define topology_core_id(cpu) (cpu_data(cpu)->core_id)
#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
#define topology_thread_cpumask(cpu) (&per_cpu(cpu_sibling_map, cpu))
-#define smt_capable() (smp_num_siblings > 1)
#endif
extern void arch_fix_phys_package_id(int num, u32 slot);
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 07d209c9507f..0d407b300762 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -54,10 +54,6 @@
#include <asm/sal.h>
#include <asm/cyclone.h>
-#define BAD_MADT_ENTRY(entry, end) ( \
- (!entry) || (unsigned long)entry + sizeof(*entry) > end || \
- ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
-
#define PREFIX "ACPI: "
unsigned int acpi_cpei_override;
@@ -803,14 +799,9 @@ int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi)
* ACPI based hotplug CPU support
*/
#ifdef CONFIG_ACPI_HOTPLUG_CPU
-static
-int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
+static int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
{
#ifdef CONFIG_ACPI_NUMA
- int pxm_id;
- int nid;
-
- pxm_id = acpi_get_pxm(handle);
/*
* We don't have cpu-only-node hotadd. But if the system equips
* SRAT table, pxm is already found and node is ready.
@@ -818,11 +809,10 @@ int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
* This code here is for the system which doesn't have full SRAT
* table for possible cpus.
*/
- nid = acpi_map_pxm_to_node(pxm_id);
node_cpuid[cpu].phys_id = physid;
- node_cpuid[cpu].nid = nid;
+ node_cpuid[cpu].nid = acpi_get_node(handle);
#endif
- return (0);
+ return 0;
}
int additional_cpus __initdata = -1;
@@ -929,7 +919,7 @@ static acpi_status acpi_map_iosapic(acpi_handle handle, u32 depth,
union acpi_object *obj;
struct acpi_madt_io_sapic *iosapic;
unsigned int gsi_base;
- int pxm, node;
+ int node;
/* Only care about objects w/ a method that returns the MADT */
if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
@@ -956,17 +946,9 @@ static acpi_status acpi_map_iosapic(acpi_handle handle, u32 depth,
kfree(buffer.pointer);
- /*
- * OK, it's an IOSAPIC MADT entry, look for a _PXM value to tell
- * us which node to associate this with.
- */
- pxm = acpi_get_pxm(handle);
- if (pxm < 0)
- return AE_OK;
-
- node = pxm_to_node(pxm);
-
- if (node >= MAX_NUMNODES || !node_online(node) ||
+ /* OK, it's an IOSAPIC MADT entry; associate it with a node */
+ node = acpi_get_node(handle);
+ if (node == NUMA_NO_NODE || !node_online(node) ||
cpumask_empty(cpumask_of_node(node)))
return AE_OK;
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index da5b462e6de6..741b99c1a0b1 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -477,6 +477,9 @@ efi_init (void)
char *cp, vendor[100] = "unknown";
int i;
+ set_bit(EFI_BOOT, &efi.flags);
+ set_bit(EFI_64BIT, &efi.flags);
+
/*
* It's too early to be able to use the standard kernel command line
* support...
@@ -529,6 +532,8 @@ efi_init (void)
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff, vendor);
+ set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+
palo_phys = EFI_INVALID_TABLE_ADDR;
if (efi_config_init(arch_tables) != 0)
@@ -657,6 +662,8 @@ efi_enter_virtual_mode (void)
return;
}
+ set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+
/*
* Now that EFI is in virtual mode, we call the EFI functions more
* efficiently:
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index 1034884b77da..0884f5ecbcc3 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -364,7 +364,6 @@ static irqreturn_t smp_irq_move_cleanup_interrupt(int irq, void *dev_id)
static struct irqaction irq_move_irqaction = {
.handler = smp_irq_move_cleanup_interrupt,
- .flags = IRQF_DISABLED,
.name = "irq_move"
};
@@ -489,14 +488,13 @@ ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
ia64_srlz_d();
while (vector != IA64_SPURIOUS_INT_VECTOR) {
int irq = local_vector_to_irq(vector);
- struct irq_desc *desc = irq_to_desc(irq);
if (unlikely(IS_LOCAL_TLB_FLUSH(vector))) {
smp_local_flush_tlb();
- kstat_incr_irqs_this_cpu(irq, desc);
+ kstat_incr_irq_this_cpu(irq);
} else if (unlikely(IS_RESCHEDULE(vector))) {
scheduler_ipi();
- kstat_incr_irqs_this_cpu(irq, desc);
+ kstat_incr_irq_this_cpu(irq);
} else {
ia64_setreg(_IA64_REG_CR_TPR, vector);
ia64_srlz_d();
@@ -549,13 +547,12 @@ void ia64_process_pending_intr(void)
*/
while (vector != IA64_SPURIOUS_INT_VECTOR) {
int irq = local_vector_to_irq(vector);
- struct irq_desc *desc = irq_to_desc(irq);
if (unlikely(IS_LOCAL_TLB_FLUSH(vector))) {
smp_local_flush_tlb();
- kstat_incr_irqs_this_cpu(irq, desc);
+ kstat_incr_irq_this_cpu(irq);
} else if (unlikely(IS_RESCHEDULE(vector))) {
- kstat_incr_irqs_this_cpu(irq, desc);
+ kstat_incr_irq_this_cpu(irq);
} else {
struct pt_regs *old_regs = set_irq_regs(NULL);
@@ -602,7 +599,6 @@ static irqreturn_t dummy_handler (int irq, void *dev_id)
static struct irqaction ipi_irqaction = {
.handler = handle_IPI,
- .flags = IRQF_DISABLED,
.name = "IPI"
};
@@ -611,13 +607,11 @@ static struct irqaction ipi_irqaction = {
*/
static struct irqaction resched_irqaction = {
.handler = dummy_handler,
- .flags = IRQF_DISABLED,
.name = "resched"
};
static struct irqaction tlb_irqaction = {
.handler = dummy_handler,
- .flags = IRQF_DISABLED,
.name = "tlb_flush"
};
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index b8edfa75a83f..db7b36bb068b 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -217,7 +217,7 @@ void ia64_mca_printk(const char *fmt, ...)
/* Copy the output into mlogbuf */
if (oops_in_progress) {
/* mlogbuf was abandoned, use printk directly instead. */
- printk(temp_buf);
+ printk("%s", temp_buf);
} else {
spin_lock(&mlogbuf_wlock);
for (p = temp_buf; *p; p++) {
@@ -268,7 +268,7 @@ void ia64_mlogbuf_dump(void)
}
*p = '\0';
if (temp_buf[0])
- printk(temp_buf);
+ printk("%s", temp_buf);
mlogbuf_start = index;
mlogbuf_timestamp = 0;
@@ -1772,38 +1772,32 @@ __setup("disable_cpe_poll", ia64_mca_disable_cpe_polling);
static struct irqaction cmci_irqaction = {
.handler = ia64_mca_cmc_int_handler,
- .flags = IRQF_DISABLED,
.name = "cmc_hndlr"
};
static struct irqaction cmcp_irqaction = {
.handler = ia64_mca_cmc_int_caller,
- .flags = IRQF_DISABLED,
.name = "cmc_poll"
};
static struct irqaction mca_rdzv_irqaction = {
.handler = ia64_mca_rendez_int_handler,
- .flags = IRQF_DISABLED,
.name = "mca_rdzv"
};
static struct irqaction mca_wkup_irqaction = {
.handler = ia64_mca_wakeup_int_handler,
- .flags = IRQF_DISABLED,
.name = "mca_wkup"
};
#ifdef CONFIG_ACPI
static struct irqaction mca_cpe_irqaction = {
.handler = ia64_mca_cpe_int_handler,
- .flags = IRQF_DISABLED,
.name = "cpe_hndlr"
};
static struct irqaction mca_cpep_irqaction = {
.handler = ia64_mca_cpe_int_caller,
- .flags = IRQF_DISABLED,
.name = "cpe_poll"
};
#endif /* CONFIG_ACPI */
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
index fb2f1e622877..c430f9198d1b 100644
--- a/arch/ia64/kernel/msi_ia64.c
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -17,12 +17,9 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata,
{
struct msi_msg msg;
u32 addr, data;
- int cpu = first_cpu(*cpu_mask);
+ int cpu = cpumask_first_and(cpu_mask, cpu_online_mask);
unsigned int irq = idata->irq;
- if (!cpu_online(cpu))
- return -1;
-
if (irq_prepare_move(irq, cpu))
return -1;
@@ -139,10 +136,7 @@ static int dmar_msi_set_affinity(struct irq_data *data,
unsigned int irq = data->irq;
struct irq_cfg *cfg = irq_cfg + irq;
struct msi_msg msg;
- int cpu = cpumask_first(mask);
-
- if (!cpu_online(cpu))
- return -1;
+ int cpu = cpumask_first_and(mask, cpu_online_mask);
if (irq_prepare_move(irq, cpu))
return -1;
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index cb592773c78b..d841c4bd6864 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -6387,7 +6387,6 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
static struct irqaction perfmon_irqaction = {
.handler = pfm_interrupt_handler,
- .flags = IRQF_DISABLED,
.name = "perfmon"
};
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index fbaac1afb844..71c52bc7c28d 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -380,7 +380,7 @@ static cycle_t itc_get_cycles(struct clocksource *cs)
static struct irqaction timer_irqaction = {
.handler = timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_IRQPOLL,
+ .flags = IRQF_IRQPOLL,
.name = "timer"
};
diff --git a/arch/ia64/kernel/uncached.c b/arch/ia64/kernel/uncached.c
index a96bcf83a735..20e8a9b21d75 100644
--- a/arch/ia64/kernel/uncached.c
+++ b/arch/ia64/kernel/uncached.c
@@ -98,7 +98,7 @@ static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid)
/* attempt to allocate a granule's worth of cached memory pages */
page = alloc_pages_exact_node(nid,
- GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+ GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
IA64_GRANULE_SHIFT-PAGE_SHIFT);
if (!page) {
mutex_unlock(&uc_pool->add_chunk_mutex);
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 53f44bee9ebb..6a4309bb821a 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -199,6 +199,7 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_IRQCHIP:
case KVM_CAP_MP_STATE:
case KVM_CAP_IRQ_INJECT_STATUS:
+ case KVM_CAP_IOAPIC_POLARITY_IGNORED:
r = 1;
break;
case KVM_CAP_COALESCED_MMIO:
diff --git a/arch/ia64/pci/fixup.c b/arch/ia64/pci/fixup.c
index 5dc969dd4ac0..eee069a0b539 100644
--- a/arch/ia64/pci/fixup.c
+++ b/arch/ia64/pci/fixup.c
@@ -5,6 +5,7 @@
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/vgaarb.h>
#include <asm/machvec.h>
@@ -19,9 +20,10 @@
* IORESOURCE_ROM_SHADOW is used to associate the boot video
* card with this copy. On laptops this copy has to be used since
* the main ROM may be compressed or combined with another image.
- * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW
- * is marked here since the boot video device will be the only enabled
- * video device at this point.
+ * See pci_map_rom() for use of this flag. Before marking the device
+ * with IORESOURCE_ROM_SHADOW check if a vga_default_device is already set
+ * by either arch cde or vga-arbitration, if so only apply the fixup to this
+ * already determined primary video card.
*/
static void pci_fixup_video(struct pci_dev *pdev)
@@ -35,9 +37,6 @@ static void pci_fixup_video(struct pci_dev *pdev)
return;
/* Maybe, this machine supports legacy memory map. */
- if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
- return;
-
/* Is VGA routed to us? */
bus = pdev->bus;
while (bus) {
@@ -60,10 +59,14 @@ static void pci_fixup_video(struct pci_dev *pdev)
}
bus = bus->parent;
}
- pci_read_config_word(pdev, PCI_COMMAND, &config);
- if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
- pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
- dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
+ if (!vga_default_device() || pdev == vga_default_device()) {
+ pci_read_config_word(pdev, PCI_COMMAND, &config);
+ if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+ pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+ dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
+ vga_set_default_device(pdev);
+ }
}
}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 9e4938d8ca4d..291a582777cf 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -126,7 +126,6 @@ static struct pci_controller *alloc_pci_controller(int seg)
return NULL;
controller->segment = seg;
- controller->node = -1;
return controller;
}
@@ -430,19 +429,14 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
struct pci_root_info *info = NULL;
int busnum = root->secondary.start;
struct pci_bus *pbus;
- int pxm, ret;
+ int ret;
controller = alloc_pci_controller(domain);
if (!controller)
return NULL;
controller->companion = device;
-
- pxm = acpi_get_pxm(device->handle);
-#ifdef CONFIG_NUMA
- if (pxm >= 0)
- controller->node = pxm_to_node(pxm);
-#endif
+ controller->node = acpi_get_node(device->handle);
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
index 62cf4dde6a04..85d095154902 100644
--- a/arch/ia64/sn/kernel/irq.c
+++ b/arch/ia64/sn/kernel/irq.c
@@ -209,8 +209,8 @@ static int sn_set_affinity_irq(struct irq_data *data,
nasid_t nasid;
int slice;
- nasid = cpuid_to_nasid(cpumask_first(mask));
- slice = cpuid_to_slice(cpumask_first(mask));
+ nasid = cpuid_to_nasid(cpumask_first_and(mask, cpu_online_mask));
+ slice = cpuid_to_slice(cpumask_first_and(mask, cpu_online_mask));
list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
sn_irq_lh[irq], list)
diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c
index 2b98b9e088de..afc58d2799ad 100644
--- a/arch/ia64/sn/kernel/msi_sn.c
+++ b/arch/ia64/sn/kernel/msi_sn.c
@@ -166,7 +166,7 @@ static int sn_set_msi_irq_affinity(struct irq_data *data,
struct sn_pcibus_provider *provider;
unsigned int cpu, irq = data->irq;
- cpu = cpumask_first(cpu_mask);
+ cpu = cpumask_first_and(cpu_mask, cpu_online_mask);
sn_irq_info = sn_msi_info[irq].sn_irq_info;
if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
return -1;
diff --git a/arch/m32r/include/asm/Kbuild b/arch/m32r/include/asm/Kbuild
index 932435ac4e5c..67779a74b62d 100644
--- a/arch/m32r/include/asm/Kbuild
+++ b/arch/m32r/include/asm/Kbuild
@@ -1,7 +1,9 @@
generic-y += clkdev.h
+generic-y += cputime.h
generic-y += exec.h
+generic-y += hash.h
+generic-y += mcs_spinlock.h
generic-y += module.h
-generic-y += trace_clock.h
generic-y += preempt.h
-generic-y += hash.h
+generic-y += trace_clock.h
diff --git a/arch/m32r/include/asm/cputime.h b/arch/m32r/include/asm/cputime.h
deleted file mode 100644
index 0a47550df2b7..000000000000
--- a/arch/m32r/include/asm/cputime.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __M32R_CPUTIME_H
-#define __M32R_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __M32R_CPUTIME_H */
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index dbdd2231c75d..b2e322939256 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -17,6 +17,7 @@ config M68K
select FPU if MMU
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
+ select HAVE_FUTEX_CMPXCHG if MMU && FUTEX
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_REL
select MODULES_USE_ELF_RELA
diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
index 18c0e29976e3..2081b8cd5591 100644
--- a/arch/m68k/amiga/cia.c
+++ b/arch/m68k/amiga/cia.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index 3e73a63c066f..3d2b63bedf05 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -41,6 +41,7 @@
#include <linux/init.h>
#include <linux/seq_file.h>
#include <linux/module.h>
+#include <linux/irq.h>
#include <asm/traps.h>
diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig
index 559ff3af8ff7..96da4963d14b 100644
--- a/arch/m68k/configs/amiga_defconfig
+++ b/arch/m68k/configs/amiga_defconfig
@@ -24,6 +24,8 @@ CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68020=y
CONFIG_M68030=y
CONFIG_M68040=y
@@ -85,6 +87,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -94,6 +97,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -126,6 +131,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -163,8 +169,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -190,7 +194,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -512,7 +515,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig
index cb1f55df69b6..1b8739f50cbf 100644
--- a/arch/m68k/configs/apollo_defconfig
+++ b/arch/m68k/configs/apollo_defconfig
@@ -25,6 +25,8 @@ CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68020=y
CONFIG_M68030=y
CONFIG_M68040=y
@@ -83,6 +85,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -92,6 +95,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -124,6 +129,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -161,8 +167,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -188,7 +192,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -470,7 +473,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig
index e880cfbb62d9..6ea4e91f0caa 100644
--- a/arch/m68k/configs/atari_defconfig
+++ b/arch/m68k/configs/atari_defconfig
@@ -24,6 +24,8 @@ CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68020=y
CONFIG_M68030=y
CONFIG_M68040=y
@@ -82,6 +84,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -91,6 +94,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -123,6 +128,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -160,8 +166,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -187,7 +191,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -487,7 +490,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig
index 4aa4f45e52a8..e5a12739ff2d 100644
--- a/arch/m68k/configs/bvme6000_defconfig
+++ b/arch/m68k/configs/bvme6000_defconfig
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68040=y
CONFIG_M68060=y
CONFIG_VME=y
@@ -81,6 +83,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -90,6 +93,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -122,6 +127,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -159,8 +165,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -186,7 +190,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -463,7 +466,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig
index 7cd9d9f456fb..8936d7fb0f0f 100644
--- a/arch/m68k/configs/hp300_defconfig
+++ b/arch/m68k/configs/hp300_defconfig
@@ -25,6 +25,8 @@ CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68020=y
CONFIG_M68030=y
CONFIG_M68040=y
@@ -83,6 +85,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -92,6 +95,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -124,6 +129,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -161,8 +167,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -188,7 +192,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -472,7 +475,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig
index 31f5bd061d14..be5342cca25b 100644
--- a/arch/m68k/configs/mac_defconfig
+++ b/arch/m68k/configs/mac_defconfig
@@ -24,6 +24,8 @@ CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68020=y
CONFIG_M68030=y
CONFIG_M68040=y
@@ -82,6 +84,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -91,6 +94,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -123,6 +128,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -160,8 +166,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -187,7 +191,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -495,7 +498,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig
index 4e5adff326ee..f27194ade167 100644
--- a/arch/m68k/configs/multi_defconfig
+++ b/arch/m68k/configs/multi_defconfig
@@ -20,6 +20,8 @@ CONFIG_SOLARIS_X86_PARTITION=y
CONFIG_UNIXWARE_DISKLABEL=y
# CONFIG_EFI_PARTITION is not set
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68020=y
CONFIG_M68040=y
CONFIG_M68060=y
@@ -91,6 +93,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -100,6 +103,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -132,6 +137,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -169,8 +175,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -196,7 +200,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -571,7 +574,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig
index 02cdbac5565e..c3887603c1db 100644
--- a/arch/m68k/configs/mvme147_defconfig
+++ b/arch/m68k/configs/mvme147_defconfig
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68030=y
CONFIG_VME=y
CONFIG_MVME147=y
@@ -80,6 +82,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -89,6 +92,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -121,6 +126,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -158,8 +164,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -185,7 +189,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -463,7 +466,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig
index 05a990a9dbd4..f7ff784d05ac 100644
--- a/arch/m68k/configs/mvme16x_defconfig
+++ b/arch/m68k/configs/mvme16x_defconfig
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68040=y
CONFIG_M68060=y
CONFIG_VME=y
@@ -81,6 +83,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -90,6 +93,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -122,6 +127,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -159,8 +165,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -186,7 +190,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -464,7 +467,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig
index 568e2a98f976..f0c72ab037be 100644
--- a/arch/m68k/configs/q40_defconfig
+++ b/arch/m68k/configs/q40_defconfig
@@ -25,6 +25,8 @@ CONFIG_SUN_PARTITION=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_M68040=y
CONFIG_M68060=y
CONFIG_Q40=y
@@ -81,6 +83,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -90,6 +93,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -122,6 +127,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -159,8 +165,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -186,7 +190,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -485,7 +488,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig
index 60b0aeac5742..7bca0f464521 100644
--- a/arch/m68k/configs/sun3_defconfig
+++ b/arch/m68k/configs/sun3_defconfig
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_SUN3=y
# CONFIG_COMPACTION is not set
CONFIG_CLEANCACHE=y
@@ -78,6 +80,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -87,6 +90,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -119,6 +124,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -156,8 +162,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -183,7 +187,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -464,7 +467,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig
index 21bda331eebb..317f3e1fec95 100644
--- a/arch/m68k/configs/sun3x_defconfig
+++ b/arch/m68k/configs/sun3x_defconfig
@@ -24,6 +24,8 @@ CONFIG_UNIXWARE_DISKLABEL=y
# CONFIG_EFI_PARTITION is not set
CONFIG_SYSV68_PARTITION=y
CONFIG_IOSCHED_DEADLINE=m
+CONFIG_KEXEC=y
+CONFIG_BOOTINFO_PROC=y
CONFIG_SUN3X=y
# CONFIG_COMPACTION is not set
CONFIG_CLEANCACHE=y
@@ -78,6 +80,7 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
@@ -87,6 +90,8 @@ CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -119,6 +124,7 @@ CONFIG_NETFILTER_XT_MATCH_DSCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -156,8 +162,6 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_TABLES_IPV4=m
-CONFIG_NFT_REJECT_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NF_TABLES_ARP=m
@@ -183,7 +187,6 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_NF_TABLES_IPV6=m
CONFIG_NFT_CHAIN_ROUTE_IPV6=m
CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
@@ -464,7 +467,6 @@ CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_T10DIF=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_IA64=y
diff --git a/arch/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild
index 7cc8c364924d..c67c94a2d672 100644
--- a/arch/m68k/include/asm/Kbuild
+++ b/arch/m68k/include/asm/Kbuild
@@ -1,4 +1,4 @@
-
+generic-y += barrier.h
generic-y += bitsperlong.h
generic-y += clkdev.h
generic-y += cputime.h
@@ -6,6 +6,7 @@ generic-y += device.h
generic-y += emergency-restart.h
generic-y += errno.h
generic-y += exec.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ipcbuf.h
@@ -13,11 +14,13 @@ generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += kvm_para.h
-generic-y += local64.h
generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += mutex.h
generic-y += percpu.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sections.h
@@ -31,5 +34,3 @@ generic-y += trace_clock.h
generic-y += types.h
generic-y += word-at-a-time.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/m68k/include/asm/barrier.h b/arch/m68k/include/asm/barrier.h
deleted file mode 100644
index 15c5f77c1614..000000000000
--- a/arch/m68k/include/asm/barrier.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _M68K_BARRIER_H
-#define _M68K_BARRIER_H
-
-#define nop() do { asm volatile ("nop"); barrier(); } while (0)
-
-#include <asm-generic/barrier.h>
-
-#endif /* _M68K_BARRIER_H */
diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h
index 014f288fc813..9d38b73989eb 100644
--- a/arch/m68k/include/asm/unistd.h
+++ b/arch/m68k/include/asm/unistd.h
@@ -4,7 +4,7 @@
#include <uapi/asm/unistd.h>
-#define NR_syscalls 349
+#define NR_syscalls 351
#define __ARCH_WANT_OLD_READDIR
#define __ARCH_WANT_OLD_STAT
diff --git a/arch/m68k/include/uapi/asm/unistd.h b/arch/m68k/include/uapi/asm/unistd.h
index 625f321001dc..b932dd470041 100644
--- a/arch/m68k/include/uapi/asm/unistd.h
+++ b/arch/m68k/include/uapi/asm/unistd.h
@@ -354,5 +354,7 @@
#define __NR_process_vm_writev 346
#define __NR_kcmp 347
#define __NR_finit_module 348
+#define __NR_sched_setattr 349
+#define __NR_sched_getattr 350
#endif /* _UAPI_ASM_M68K_UNISTD_H_ */
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index 4c99bab7e664..3ab329b88521 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -275,7 +275,6 @@
#ifdef CONFIG_FRAMEBUFFER_CONSOLE
#define CONSOLE
-#define CONSOLE_PENGUIN
#endif
#ifdef CONFIG_EARLY_PRINTK
@@ -658,27 +657,6 @@ ENTRY(__start)
movel %a0@,%a1@
#endif
-#if 0
- /*
- * Clear the screen
- */
- lea %pc@(L(mac_videobase)),%a0
- movel %a0@,%a1
- lea %pc@(L(mac_dimensions)),%a0
- movel %a0@,%d1
- swap %d1 /* #rows is high bytes */
- andl #0xFFFF,%d1 /* rows */
- subl #10,%d1
- lea %pc@(L(mac_rowbytes)),%a0
-loopy2:
- movel %a0@,%d0
- subql #1,%d0
-loopx2:
- moveb #0x55, %a1@+
- dbra %d0,loopx2
- dbra %d1,loopy2
-#endif
-
L(test_notmac):
#endif /* CONFIG_MAC */
@@ -907,15 +885,15 @@ L(nothp):
*/
#ifdef CONFIG_MAC
is_not_mac(L(nocon))
-#ifdef CONSOLE
+# ifdef CONSOLE
console_init
-#ifdef CONSOLE_PENGUIN
+# ifdef CONFIG_LOGO
console_put_penguin
-#endif /* CONSOLE_PENGUIN */
+# endif /* CONFIG_LOGO */
console_put_stats
-#endif /* CONSOLE */
+# endif /* CONSOLE */
L(nocon):
-#endif /* CONFIG_MAC */
+#endif /* CONFIG_MAC */
putc '\n'
@@ -3324,14 +3302,13 @@ func_return set_leds
#define Lconsole_struct_num_columns 8
#define Lconsole_struct_num_rows 12
#define Lconsole_struct_left_edge 16
-#define Lconsole_struct_penguin_putc 20
func_start console_init,%a0-%a4/%d0-%d7
/*
* Some of the register usage that follows
* a0 = pointer to boot_info
* a1 = pointer to screen
- * a2 = pointer to Lconsole_globals
+ * a2 = pointer to console_globals
* d3 = pixel width of screen
* d4 = pixel height of screen
* (d3,d4) ~= (x,y) of a point just below
@@ -3456,7 +3433,7 @@ func_start console_put_stats,%a0/%d7
func_return console_put_stats
-#ifdef CONSOLE_PENGUIN
+#ifdef CONFIG_LOGO
func_start console_put_penguin,%a0-%a1/%d0-%d7
/*
* Get 'that_penguin' onto the screen in the upper right corner
@@ -3799,38 +3776,6 @@ L(console_plot_pixel_exit):
func_return console_plot_pixel
#endif /* CONSOLE */
-#if 0
-/*
- * This is some old code lying around. I don't believe
- * it's used or important anymore. My guess is it contributed
- * to getting to this point, but it's done for now.
- * It was still in the 2.1.77 head.S, so it's still here.
- * (And still not used!)
- */
-L(showtest):
- moveml %a0/%d7,%sp@-
- puts "A="
- putn %a1
-
- .long 0xf0119f15 | ptestr #5,%a1@,#7,%a0
-
- puts "DA="
- putn %a0
-
- puts "D="
- putn %a0@
-
- puts "S="
- lea %pc@(L(mmu)),%a0
- .long 0xf0106200 | pmove %psr,%a0@
- clrl %d7
- movew %a0@,%d7
- putn %d7
-
- putc '\n'
- moveml %sp@+,%a0/%d7
- rts
-#endif /* 0 */
__INITDATA
.align 4
@@ -3849,7 +3794,6 @@ L(console_globals):
.long 0 /* max num columns */
.long 0 /* max num rows */
.long 0 /* left edge */
- .long 0 /* mac putc */
L(console_font):
.long 0 /* pointer to console font (struct font_desc) */
L(console_font_data):
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index 077d3a70fed1..5b8d66fbf383 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -10,9 +10,9 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/irq.h>
#include <asm/setup.h>
#include <asm/irq.h>
diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S
index 3f04ea0ab802..b6223dc41d82 100644
--- a/arch/m68k/kernel/syscalltable.S
+++ b/arch/m68k/kernel/syscalltable.S
@@ -369,4 +369,6 @@ ENTRY(sys_call_table)
.long sys_process_vm_writev
.long sys_kcmp
.long sys_finit_module
+ .long sys_sched_setattr
+ .long sys_sched_getattr /* 350 */
diff --git a/arch/metag/Kconfig b/arch/metag/Kconfig
index e56abd2c1b4f..b1d3c9c0eff8 100644
--- a/arch/metag/Kconfig
+++ b/arch/metag/Kconfig
@@ -9,6 +9,7 @@ config METAG
select HAVE_ARCH_TRACEHOOK
select HAVE_C_RECORDMCOUNT
select HAVE_DEBUG_KMEMLEAK
+ select HAVE_DEBUG_STACKOVERFLOW
select HAVE_DYNAMIC_FTRACE
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_FUNCTION_TRACER
@@ -29,7 +30,6 @@ config METAG
select OF
select OF_EARLY_FLATTREE
select SPARSE_IRQ
- select HAVE_DEBUG_STACKOVERFLOW
config STACKTRACE_SUPPORT
def_bool y
diff --git a/arch/metag/include/asm/Kbuild b/arch/metag/include/asm/Kbuild
index b716d807c2ec..c29ead89a317 100644
--- a/arch/metag/include/asm/Kbuild
+++ b/arch/metag/include/asm/Kbuild
@@ -13,6 +13,7 @@ generic-y += fb.h
generic-y += fcntl.h
generic-y += futex.h
generic-y += hardirq.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
@@ -23,6 +24,7 @@ generic-y += kmap_types.h
generic-y += kvm_para.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += msgbuf.h
generic-y += mutex.h
generic-y += param.h
@@ -30,6 +32,7 @@ generic-y += pci.h
generic-y += percpu.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += scatterlist.h
generic-y += sections.h
generic-y += sembuf.h
@@ -52,5 +55,3 @@ generic-y += unaligned.h
generic-y += user.h
generic-y += vga.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/metag/include/asm/topology.h b/arch/metag/include/asm/topology.h
index 8e9c0b3b9691..e95f874ded1b 100644
--- a/arch/metag/include/asm/topology.h
+++ b/arch/metag/include/asm/topology.h
@@ -3,33 +3,6 @@
#ifdef CONFIG_NUMA
-/* sched_domains SD_NODE_INIT for Meta machines */
-#define SD_NODE_INIT (struct sched_domain) { \
- .parent = NULL, \
- .child = NULL, \
- .groups = NULL, \
- .min_interval = 8, \
- .max_interval = 32, \
- .busy_factor = 32, \
- .imbalance_pct = 125, \
- .cache_nice_tries = 2, \
- .busy_idx = 3, \
- .idle_idx = 2, \
- .newidle_idx = 0, \
- .wake_idx = 0, \
- .forkexec_idx = 0, \
- .flags = SD_LOAD_BALANCE \
- | SD_BALANCE_FORK \
- | SD_BALANCE_EXEC \
- | SD_BALANCE_NEWIDLE \
- | SD_SERIALIZE, \
- .last_balance = jiffies, \
- .balance_interval = 1, \
- .nr_balance_failed = 0, \
- .max_newidle_lb_cost = 0, \
- .next_decay_max_lb_cost = jiffies, \
-}
-
#define cpu_to_node(cpu) ((void)(cpu), 0)
#define parent_node(node) ((void)(node), 0)
diff --git a/arch/metag/kernel/irq.c b/arch/metag/kernel/irq.c
index 3b4b7f6c0950..5385dd1216b7 100644
--- a/arch/metag/kernel/irq.c
+++ b/arch/metag/kernel/irq.c
@@ -261,18 +261,6 @@ int __init arch_probe_nr_irqs(void)
}
#ifdef CONFIG_HOTPLUG_CPU
-static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
-{
- struct irq_desc *desc = irq_to_desc(irq);
- struct irq_chip *chip = irq_data_get_irq_chip(data);
- unsigned long flags;
-
- raw_spin_lock_irqsave(&desc->lock, flags);
- if (chip->irq_set_affinity)
- chip->irq_set_affinity(data, cpumask_of(cpu), false);
- raw_spin_unlock_irqrestore(&desc->lock, flags);
-}
-
/*
* The CPU has been marked offline. Migrate IRQs off this CPU. If
* the affinity settings do not allow other CPUs, force them onto any
@@ -281,10 +269,9 @@ static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
void migrate_irqs(void)
{
unsigned int i, cpu = smp_processor_id();
- struct irq_desc *desc;
- for_each_irq_desc(i, desc) {
- struct irq_data *data = irq_desc_get_irq_data(desc);
+ for_each_active_irq(i) {
+ struct irq_data *data = irq_get_irq_data(i);
unsigned int newcpu;
if (irqd_is_per_cpu(data))
@@ -300,11 +287,8 @@ void migrate_irqs(void)
i, cpu);
cpumask_setall(data->affinity);
- newcpu = cpumask_any_and(data->affinity,
- cpu_online_mask);
}
-
- route_irq(data, i, newcpu);
+ irq_set_affinity(i, data->affinity);
}
}
#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/metag/kernel/signal.c b/arch/metag/kernel/signal.c
index 3be61cf0b147..b9e4a82d2bd4 100644
--- a/arch/metag/kernel/signal.c
+++ b/arch/metag/kernel/signal.c
@@ -152,18 +152,18 @@ static void __user *get_sigframe(struct k_sigaction *ka, unsigned long sp,
return (void __user *)sp;
}
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs *regs)
+static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
+ struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
- int err = -EFAULT;
+ int err;
unsigned long code;
- frame = get_sigframe(ka, regs->REG_SP, sizeof(*frame));
+ frame = get_sigframe(&ksig->ka, regs->REG_SP, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto out;
+ return -EFAULT;
- err = copy_siginfo_to_user(&frame->info, info);
+ err = copy_siginfo_to_user(&frame->info, &ksig->info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
@@ -174,7 +174,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
- goto out;
+ return -EFAULT;
/* Set up to return from userspace. */
@@ -187,15 +187,15 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(code, (unsigned long __user *)(&frame->retcode[1]));
if (err)
- goto out;
+ return -EFAULT;
/* Set up registers for signal handler */
regs->REG_RTP = (unsigned long) frame->retcode;
regs->REG_SP = (unsigned long) frame + sizeof(*frame);
- regs->REG_ARG1 = sig;
+ regs->REG_ARG1 = ksig->sig;
regs->REG_ARG2 = (unsigned long) &frame->info;
regs->REG_ARG3 = (unsigned long) &frame->uc;
- regs->REG_PC = (unsigned long) ka->sa.sa_handler;
+ regs->REG_PC = (unsigned long) ksig->ka.sa.sa_handler;
pr_debug("SIG deliver (%s:%d): sp=%p pc=%08x pr=%08x\n",
current->comm, current->pid, frame, regs->REG_PC,
@@ -205,24 +205,19 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
* effective cache flush - directed rather than 'full flush'.
*/
flush_cache_sigtramp(regs->REG_RTP, sizeof(frame->retcode));
-out:
- if (err) {
- force_sigsegv(sig, current);
- return -EFAULT;
- }
+
return 0;
}
-static void handle_signal(unsigned long sig, siginfo_t *info,
- struct k_sigaction *ka, struct pt_regs *regs)
+static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
sigset_t *oldset = sigmask_to_save();
+ int ret;
/* Set up the stack frame */
- if (setup_rt_frame(sig, ka, info, oldset, regs))
- return;
+ ret = setup_rt_frame(ksig, oldset, regs);
- signal_delivered(sig, info, ka, regs, test_thread_flag(TIF_SINGLESTEP));
+ signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
}
/*
@@ -235,10 +230,8 @@ static void handle_signal(unsigned long sig, siginfo_t *info,
static int do_signal(struct pt_regs *regs, int syscall)
{
unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
- struct k_sigaction ka;
- siginfo_t info;
- int signr;
int restart = 0;
+ struct ksignal ksig;
/*
* By the end of rt_sigreturn the context describes the point that the
@@ -275,7 +268,8 @@ static int do_signal(struct pt_regs *regs, int syscall)
* Get the signal to deliver. When running under ptrace, at this point
* the debugger may change all our registers ...
*/
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+ get_signal(&ksig);
+
/*
* Depending on the signal settings we may need to revert the decision
* to restart the system call. But skip this if a debugger has chosen to
@@ -283,19 +277,19 @@ static int do_signal(struct pt_regs *regs, int syscall)
*/
if (regs->REG_PC != restart_addr)
restart = 0;
- if (signr > 0) {
+ if (ksig.sig > 0) {
if (unlikely(restart)) {
if (retval == -ERESTARTNOHAND
|| retval == -ERESTART_RESTARTBLOCK
|| (retval == -ERESTARTSYS
- && !(ka.sa.sa_flags & SA_RESTART))) {
+ && !(ksig.ka.sa.sa_flags & SA_RESTART))) {
regs->REG_RETVAL = -EINTR;
regs->REG_PC = continue_addr;
}
}
/* Whee! Actually deliver the signal. */
- handle_signal(signr, &info, &ka, regs);
+ handle_signal(&ksig, regs);
return 0;
}
diff --git a/arch/microblaze/include/asm/Kbuild b/arch/microblaze/include/asm/Kbuild
index 2b98bc73642a..c98ed95c0541 100644
--- a/arch/microblaze/include/asm/Kbuild
+++ b/arch/microblaze/include/asm/Kbuild
@@ -1,8 +1,10 @@
generic-y += barrier.h
generic-y += clkdev.h
+generic-y += cputime.h
generic-y += exec.h
generic-y += hash.h
-generic-y += trace_clock.h
-generic-y += syscalls.h
+generic-y += mcs_spinlock.h
generic-y += preempt.h
+generic-y += syscalls.h
+generic-y += trace_clock.h
diff --git a/arch/microblaze/include/asm/cputime.h b/arch/microblaze/include/asm/cputime.h
deleted file mode 100644
index 6d68ad7e0ea3..000000000000
--- a/arch/microblaze/include/asm/cputime.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/cputime.h>
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 66804adcacf0..70996cc66aa2 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -1294,11 +1294,6 @@ void pcibios_finish_adding_to_bus(struct pci_bus *bus)
}
EXPORT_SYMBOL_GPL(pcibios_finish_adding_to_bus);
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- return pci_enable_resources(dev, mask);
-}
-
static void pcibios_setup_phb_resources(struct pci_controller *hose,
struct list_head *resources)
{
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index dcae3a7035db..16d5ab1615b1 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -10,6 +10,7 @@ config MIPS
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
select HAVE_ARCH_KGDB
+ select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
select ARCH_HAVE_CUSTOM_GPIO_H
select HAVE_FUNCTION_TRACER
@@ -62,13 +63,12 @@ config MIPS_ALCHEMY
select CEVT_R4K
select CSRC_R4K
select IRQ_CPU
+ select DMA_MAYBE_COHERENT # Au1000,1500,1100 aren't, rest is
select SYS_HAS_CPU_MIPS32_R1
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_APM_EMULATION
select ARCH_REQUIRE_GPIOLIB
select SYS_SUPPORTS_ZBOOT
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
config AR7
bool "Texas Instruments AR7"
@@ -123,7 +123,7 @@ config BCM47XX
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_HAS_EARLY_PRINTK
- select EARLY_PRINTK_8250 if EARLY_PRINTK
+ select USE_GENERIC_EARLY_PRINTK_8250
help
Support for BCM47XX based boards
@@ -150,7 +150,6 @@ config MIPS_COBALT
select CSRC_R4K
select CEVT_GT641XX
select DMA_NONCOHERENT
- select EARLY_PRINTK_8250 if EARLY_PRINTK
select HW_HAS_PCI
select I8253
select I8259
@@ -163,6 +162,7 @@ config MIPS_COBALT
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_64BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
+ select USE_GENERIC_EARLY_PRINTK_8250
config MACH_DECSTATION
bool "DECstations"
@@ -235,7 +235,6 @@ config MACH_JZ4740
select IRQ_CPU
select ARCH_REQUIRE_GPIOLIB
select SYS_HAS_EARLY_PRINTK
- select HAVE_PWM
select HAVE_CLK
select GENERIC_IRQ_CHIP
@@ -320,6 +319,7 @@ config MIPS_MALTA
select SWAP_IO_SPACE
select SYS_HAS_CPU_MIPS32_R1
select SYS_HAS_CPU_MIPS32_R2
+ select SYS_HAS_CPU_MIPS32_R3_5
select SYS_HAS_CPU_MIPS64_R1
select SYS_HAS_CPU_MIPS64_R2
select SYS_HAS_CPU_NEVADA
@@ -329,6 +329,7 @@ config MIPS_MALTA
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_MIPS_CMP
+ select SYS_SUPPORTS_MIPS_CPS
select SYS_SUPPORTS_MULTITHREADING
select SYS_SUPPORTS_SMARTMIPS
select SYS_SUPPORTS_ZBOOT
@@ -360,7 +361,6 @@ config MIPS_SEAD3
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_SMARTMIPS
select SYS_SUPPORTS_MICROMIPS
- select USB_ARCH_HAS_EHCI
select USB_EHCI_BIG_ENDIAN_DESC
select USB_EHCI_BIG_ENDIAN_MMIO
select USE_OF
@@ -674,6 +674,7 @@ config SNI_RM
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_HIGHMEM
select SYS_SUPPORTS_LITTLE_ENDIAN
+ select USE_GENERIC_EARLY_PRINTK_8250
help
The SNI RM200/300/400 are MIPS-based machines manufactured by
Siemens Nixdorf Informationssysteme (SNI), parent company of Pyramid
@@ -718,8 +719,6 @@ config CAVIUM_OCTEON_SOC
select SWAP_IO_SPACE
select HW_HAS_PCI
select ZONE_DMA32
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
select HOLES_IN_ZONE
select ARCH_REQUIRE_GPIOLIB
help
@@ -756,8 +755,6 @@ config NLM_XLR_BOARD
select ZONE_DMA32 if 64BIT
select SYNC_R4K
select SYS_HAS_EARLY_PRINTK
- select USB_ARCH_HAS_OHCI if USB_SUPPORT
- select USB_ARCH_HAS_EHCI if USB_SUPPORT
select SYS_SUPPORTS_ZBOOT
select SYS_SUPPORTS_ZBOOT_UART16550
help
@@ -782,7 +779,6 @@ config NLM_XLP_BOARD
select CEVT_R4K
select CSRC_R4K
select IRQ_CPU
- select ARCH_SUPPORTS_MSI
select ZONE_DMA32 if 64BIT
select SYNC_R4K
select SYS_HAS_EARLY_PRINTK
@@ -868,6 +864,7 @@ config CEVT_R4K
bool
config CEVT_GIC
+ select MIPS_CM
bool
config CEVT_SB1250
@@ -886,6 +883,7 @@ config CSRC_R4K
bool
config CSRC_GIC
+ select MIPS_CM
bool
config CSRC_SB1250
@@ -1030,6 +1028,7 @@ config IRQ_GT641XX
bool
config IRQ_GIC
+ select MIPS_CM
bool
config PCI_GT64XXX_PCI0
@@ -1148,6 +1147,18 @@ choice
prompt "CPU type"
default CPU_R4X00
+config CPU_LOONGSON3
+ bool "Loongson 3 CPU"
+ depends on SYS_HAS_CPU_LOONGSON3
+ select CPU_SUPPORTS_64BIT_KERNEL
+ select CPU_SUPPORTS_HIGHMEM
+ select CPU_SUPPORTS_HUGEPAGES
+ select WEAK_ORDERING
+ select WEAK_REORDERING_BEYOND_LLSC
+ help
+ The Loongson 3 processor implements the MIPS64R2 instruction
+ set with many extensions.
+
config CPU_LOONGSON2E
bool "Loongson 2E"
depends on SYS_HAS_CPU_LOONGSON2E
@@ -1203,6 +1214,7 @@ config CPU_MIPS32_R2
select CPU_HAS_PREFETCH
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
+ select CPU_SUPPORTS_MSA
select HAVE_KVM
help
Choose this option to build a kernel for release 2 or later of the
@@ -1238,6 +1250,7 @@ config CPU_MIPS64_R2
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
select CPU_SUPPORTS_HUGEPAGES
+ select CPU_SUPPORTS_MSA
help
Choose this option to build a kernel for release 2 or later of the
MIPS64 architecture. Many modern embedded systems with a 64-bit
@@ -1396,7 +1409,6 @@ config CPU_CAVIUM_OCTEON
select LIBFDT
select USE_OF
select USB_EHCI_BIG_ENDIAN_MMIO
- select SYS_HAS_DMA_OPS
select MIPS_L1_CACHE_SHIFT_7
help
The Cavium Octeon processor is a highly integrated chip containing
@@ -1448,6 +1460,26 @@ config CPU_XLP
Netlogic Microsystems XLP processors.
endchoice
+config CPU_MIPS32_3_5_FEATURES
+ bool "MIPS32 Release 3.5 Features"
+ depends on SYS_HAS_CPU_MIPS32_R3_5
+ depends on CPU_MIPS32_R2
+ help
+ Choose this option to build a kernel for release 2 or later of the
+ MIPS32 architecture including features from the 3.5 release such as
+ support for Enhanced Virtual Addressing (EVA).
+
+config CPU_MIPS32_3_5_EVA
+ bool "Enhanced Virtual Addressing (EVA)"
+ depends on CPU_MIPS32_3_5_FEATURES
+ select EVA
+ default y
+ help
+ Choose this option if you want to enable the Enhanced Virtual
+ Addressing (EVA) on your MIPS32 core (such as proAptiv).
+ One of its primary benefits is an increase in the maximum size
+ of lowmem (up to 3GB). If unsure, say 'N' here.
+
if CPU_LOONGSON2F
config CPU_NOP_WORKAROUNDS
bool
@@ -1523,6 +1555,10 @@ config CPU_BMIPS5000
select SYS_SUPPORTS_SMP
select SYS_SUPPORTS_HOTPLUG_CPU
+config SYS_HAS_CPU_LOONGSON3
+ bool
+ select CPU_SUPPORTS_CPUFREQ
+
config SYS_HAS_CPU_LOONGSON2E
bool
@@ -1541,6 +1577,9 @@ config SYS_HAS_CPU_MIPS32_R1
config SYS_HAS_CPU_MIPS32_R2
bool
+config SYS_HAS_CPU_MIPS32_R3_5
+ bool
+
config SYS_HAS_CPU_MIPS64_R1
bool
@@ -1657,6 +1696,9 @@ config CPU_MIPSR2
bool
default y if CPU_MIPS32_R2 || CPU_MIPS64_R2 || CPU_CAVIUM_OCTEON
+config EVA
+ bool
+
config SYS_SUPPORTS_32BIT_KERNEL
bool
config SYS_SUPPORTS_64BIT_KERNEL
@@ -1729,7 +1771,7 @@ choice
config PAGE_SIZE_4KB
bool "4kB"
- depends on !CPU_LOONGSON2
+ depends on !CPU_LOONGSON2 && !CPU_LOONGSON3
help
This option select the standard 4kB Linux page size. On some
R3000-family processors this is the only available page size. Using
@@ -1776,12 +1818,12 @@ endchoice
config FORCE_MAX_ZONEORDER
int "Maximum zone order"
- range 14 64 if HUGETLB_PAGE && PAGE_SIZE_64KB
- default "14" if HUGETLB_PAGE && PAGE_SIZE_64KB
- range 13 64 if HUGETLB_PAGE && PAGE_SIZE_32KB
- default "13" if HUGETLB_PAGE && PAGE_SIZE_32KB
- range 12 64 if HUGETLB_PAGE && PAGE_SIZE_16KB
- default "12" if HUGETLB_PAGE && PAGE_SIZE_16KB
+ range 14 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_64KB
+ default "14" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_64KB
+ range 13 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_32KB
+ default "13" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_32KB
+ range 12 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_16KB
+ default "12" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_16KB
range 11 64
default "11"
help
@@ -1870,6 +1912,7 @@ config MIPS_MT_SMP
select CPU_MIPSR2_IRQ_VI
select CPU_MIPSR2_IRQ_EI
select SYNC_R4K
+ select MIPS_GIC_IPI
select MIPS_MT
select SMP
select SMP_UP
@@ -1887,6 +1930,7 @@ config MIPS_MT_SMTC
bool "Use all TCs on all VPEs for SMP (DEPRECATED)"
depends on CPU_MIPS32_R2
depends on SYS_SUPPORTS_MULTITHREADING
+ depends on !MIPS_CPS
select CPU_MIPSR2_IRQ_VI
select CPU_MIPSR2_IRQ_EI
select MIPS_MT
@@ -1994,13 +2038,45 @@ config MIPS_VPE_APSP_API_MT
depends on MIPS_VPE_APSP_API && !MIPS_CMP
config MIPS_CMP
- bool "MIPS CMP support"
- depends on SYS_SUPPORTS_MIPS_CMP && MIPS_MT_SMP
+ bool "MIPS CMP framework support (DEPRECATED)"
+ depends on SYS_SUPPORTS_MIPS_CMP && !MIPS_MT_SMTC
+ select MIPS_GIC_IPI
select SYNC_R4K
select WEAK_ORDERING
default n
help
- Enable Coherency Manager processor (CMP) support.
+ Select this if you are using a bootloader which implements the "CMP
+ framework" protocol (ie. YAMON) and want your kernel to make use of
+ its ability to start secondary CPUs.
+
+ Unless you have a specific need, you should use CONFIG_MIPS_CPS
+ instead of this.
+
+config MIPS_CPS
+ bool "MIPS Coherent Processing System support"
+ depends on SYS_SUPPORTS_MIPS_CPS
+ select MIPS_CM
+ select MIPS_CPC
+ select MIPS_GIC_IPI
+ select SMP
+ select SYNC_R4K if (CEVT_R4K || CSRC_R4K)
+ select SYS_SUPPORTS_SMP
+ select WEAK_ORDERING
+ help
+ Select this if you wish to run an SMP kernel across multiple cores
+ within a MIPS Coherent Processing System. When this option is
+ enabled the kernel will probe for other cores and boot them with
+ no external assistance. It is safe to enable this when hardware
+ support is unavailable.
+
+config MIPS_GIC_IPI
+ bool
+
+config MIPS_CM
+ bool
+
+config MIPS_CPC
+ bool
config SB1_PASS_1_WORKAROUNDS
bool
@@ -2043,6 +2119,21 @@ config CPU_MICROMIPS
When this option is enabled the kernel will be built using the
microMIPS ISA
+config CPU_HAS_MSA
+ bool "Support for the MIPS SIMD Architecture"
+ depends on CPU_SUPPORTS_MSA
+ default y
+ help
+ MIPS SIMD Architecture (MSA) introduces 128 bit wide vector registers
+ and a set of SIMD instructions to operate on them. When this option
+ is enabled the kernel will support allocating & switching MSA
+ vector register contexts. If you know that your kernel will only be
+ running on CPUs which do not support MSA or that your userland will
+ not be making use of it then you may wish to say N here to reduce
+ the size & complexity of your kernel.
+
+ If unsure, say Y.
+
config CPU_HAS_WB
bool
@@ -2094,7 +2185,7 @@ config CPU_R4400_WORKAROUNDS
#
config HIGHMEM
bool "High Memory Support"
- depends on 32BIT && CPU_SUPPORTS_HIGHMEM && SYS_SUPPORTS_HIGHMEM
+ depends on 32BIT && CPU_SUPPORTS_HIGHMEM && SYS_SUPPORTS_HIGHMEM && !CPU_MIPS32_3_5_EVA
config CPU_SUPPORTS_HIGHMEM
bool
@@ -2108,6 +2199,9 @@ config SYS_SUPPORTS_SMARTMIPS
config SYS_SUPPORTS_MICROMIPS
bool
+config CPU_SUPPORTS_MSA
+ bool
+
config ARCH_FLATMEM_ENABLE
def_bool y
depends on !NUMA && !CPU_LOONGSON2
@@ -2181,6 +2275,9 @@ config SMP_UP
config SYS_SUPPORTS_MIPS_CMP
bool
+config SYS_SUPPORTS_MIPS_CPS
+ bool
+
config SYS_SUPPORTS_SMP
bool
@@ -2353,9 +2450,8 @@ config SECCOMP
If unsure, say Y. Only embedded should say N here.
config MIPS_O32_FP64_SUPPORT
- bool "Support for O32 binaries using 64-bit FP"
+ bool "Support for O32 binaries using 64-bit FP (EXPERIMENTAL)"
depends on 32BIT || MIPS32_O32
- default y
help
When this is enabled, the kernel will support use of 64-bit floating
point registers with binaries using the O32 ABI along with the
@@ -2367,7 +2463,14 @@ config MIPS_O32_FP64_SUPPORT
of your kernel & potentially improve FP emulation performance by
saying N here.
- If unsure, say Y.
+ Although binutils currently supports use of this flag the details
+ concerning its effect upon the O32 ABI in userland are still being
+ worked on. In order to avoid userland becoming dependant upon current
+ behaviour before the details have been finalised, this option should
+ be considered experimental and only enabled by those working upon
+ said details.
+
+ If unsure, say N.
config USE_OF
bool
@@ -2407,6 +2510,17 @@ config PCI
your box. Other bus systems are ISA, EISA, or VESA. If you have PCI,
say Y, otherwise N.
+config HT_PCI
+ bool "Support for HT-linked PCI"
+ default y
+ depends on CPU_LOONGSON3
+ select PCI
+ select PCI_DOMAINS
+ help
+ Loongson family machines use Hyper-Transport bus for inter-core
+ connection and device connection. The PCI bus is a subordinate
+ linked at HT. Choose Y for Loongson-3 based machines.
+
config PCI_DOMAINS
bool
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index b147e7038ff0..25de29211d76 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -21,13 +21,17 @@ config EARLY_PRINTK
unless you want to debug such a crash.
config EARLY_PRINTK_8250
- bool "8250/16550 and compatible serial early printk driver"
- depends on EARLY_PRINTK
- default n
+ bool
+ depends on EARLY_PRINTK && USE_GENERIC_EARLY_PRINTK_8250
+ default y
help
+ "8250/16550 and compatible serial early printk driver"
If you say Y here, it will be possible to use a 8250/16550 serial
port as the boot console.
+config USE_GENERIC_EARLY_PRINTK_8250
+ bool
+
config CMDLINE_BOOL
bool "Built-in kernel command line"
default n
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 9b8556de9993..1a5b4032cb66 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -119,6 +119,11 @@ cflags-$(CONFIG_CPU_MICROMIPS) += $(call cc-option,-mmicromips)
cflags-$(CONFIG_SB1XXX_CORELIS) += $(call cc-option,-mno-sched-prolog) \
-fno-omit-frame-pointer
+ifeq ($(CONFIG_CPU_HAS_MSA),y)
+toolchain-msa := $(call cc-option-yn,-mhard-float -mfp64 -mmsa)
+cflags-$(toolchain-msa) += -DTOOLCHAIN_SUPPORTS_MSA
+endif
+
#
# CPU-dependent compiler/assembler options for optimization.
#
diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig
index 7032ac7ecd1b..b9628983d620 100644
--- a/arch/mips/alchemy/Kconfig
+++ b/arch/mips/alchemy/Kconfig
@@ -16,36 +16,29 @@ config ALCHEMY_GPIO_INDIRECT
choice
prompt "Machine type"
depends on MIPS_ALCHEMY
- default MIPS_DB1000
+ default MIPS_DB1XXX
config MIPS_MTX1
bool "4G Systems MTX-1 board"
- select DMA_NONCOHERENT
select HW_HAS_PCI
select ALCHEMY_GPIOINT_AU1000
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_HAS_EARLY_PRINTK
-config MIPS_DB1000
- bool "Alchemy DB1000/DB1500/DB1100 PB1500/1100 boards"
- select ALCHEMY_GPIOINT_AU1000
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select SYS_SUPPORTS_BIG_ENDIAN
- select SYS_SUPPORTS_LITTLE_ENDIAN
- select SYS_HAS_EARLY_PRINTK
-
-config MIPS_DB1235
- bool "Alchemy DB1200/PB1200/DB1300/DB1550/PB1550 boards"
+config MIPS_DB1XXX
+ bool "Alchemy DB1XXX / PB1XXX boards"
select ARCH_REQUIRE_GPIOLIB
select HW_HAS_PCI
- select DMA_COHERENT
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_HAS_EARLY_PRINTK
+ help
+ Select this option if you have one of the following Alchemy
+ development boards: DB1000 DB1500 DB1100 DB1550 DB1200 DB1300
+ PB1500 PB1100 PB1550 PB1200
+ Board type is autodetected during boot.
config MIPS_XXS1500
bool "MyCable XXS1500 board"
- select DMA_NONCOHERENT
select ALCHEMY_GPIOINT_AU1000
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_HAS_EARLY_PRINTK
@@ -54,7 +47,6 @@ config MIPS_GPR
bool "Trapeze ITS GPR board"
select ALCHEMY_GPIOINT_AU1000
select HW_HAS_PCI
- select DMA_NONCOHERENT
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_HAS_EARLY_PRINTK
diff --git a/arch/mips/alchemy/Platform b/arch/mips/alchemy/Platform
index b3afcdd8d77a..33c9da3b077b 100644
--- a/arch/mips/alchemy/Platform
+++ b/arch/mips/alchemy/Platform
@@ -5,18 +5,12 @@ platform-$(CONFIG_MIPS_ALCHEMY) += alchemy/common/
#
-# AMD Alchemy Db1000/Db1500/Pb1500/Db1100/Pb1100 eval boards
+# AMD Alchemy Db1000/Db1500/Pb1500/Db1100/Pb1100
+# Db1550/Pb1550/Db1200/Pb1200/Db1300
#
-platform-$(CONFIG_MIPS_DB1000) += alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1000) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1000) += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1200/Pb1200/Db1550/Pb1550/Db1300 eval boards
-#
-platform-$(CONFIG_MIPS_DB1235) += alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1235) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1235) += 0xffffffff80100000
+platform-$(CONFIG_MIPS_DB1XXX) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1XXX) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1XXX) += 0xffffffff80100000
#
# 4G-Systems MTX-1 "MeshCube" wireless router
diff --git a/arch/mips/alchemy/board-gpr.c b/arch/mips/alchemy/board-gpr.c
index 9edc35ff8cf1..acf9a2a37f5a 100644
--- a/arch/mips/alchemy/board-gpr.c
+++ b/arch/mips/alchemy/board-gpr.c
@@ -53,10 +53,8 @@ void __init prom_init(void)
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
- if (!memsize_str)
+ if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
memsize = 0x04000000;
- else
- strict_strtoul(memsize_str, 0, &memsize);
add_memory_region(0, memsize, BOOT_MEM_RAM);
}
diff --git a/arch/mips/alchemy/board-mtx1.c b/arch/mips/alchemy/board-mtx1.c
index 9969dbab19e3..25a59a23547e 100644
--- a/arch/mips/alchemy/board-mtx1.c
+++ b/arch/mips/alchemy/board-mtx1.c
@@ -52,10 +52,8 @@ void __init prom_init(void)
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
- if (!memsize_str)
+ if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
memsize = 0x04000000;
- else
- strict_strtoul(memsize_str, 0, &memsize);
add_memory_region(0, memsize, BOOT_MEM_RAM);
}
diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c
index 62b4e7bbeab9..566a1743f685 100644
--- a/arch/mips/alchemy/common/setup.c
+++ b/arch/mips/alchemy/common/setup.c
@@ -30,6 +30,7 @@
#include <linux/jiffies.h>
#include <linux/module.h>
+#include <asm/dma-coherence.h>
#include <asm/mipsregs.h>
#include <asm/time.h>
@@ -59,6 +60,15 @@ void __init plat_mem_setup(void)
/* Clear to obtain best system bus performance */
clear_c0_config(1 << 19); /* Clear Config[OD] */
+ hw_coherentio = 0;
+ coherentio = 1;
+ switch (alchemy_get_cputype()) {
+ case ALCHEMY_CPU_AU1000:
+ case ALCHEMY_CPU_AU1500:
+ case ALCHEMY_CPU_AU1100:
+ coherentio = 0;
+ }
+
board_setup(); /* board specific setup */
/* IO/MEM resources. */
diff --git a/arch/mips/alchemy/common/sleeper.S b/arch/mips/alchemy/common/sleeper.S
index 706d933e0085..c73d81270b42 100644
--- a/arch/mips/alchemy/common/sleeper.S
+++ b/arch/mips/alchemy/common/sleeper.S
@@ -95,7 +95,7 @@ LEAF(alchemy_sleep_au1000)
/* cache following instructions, as memory gets put to sleep */
la t0, 1f
- .set mips3
+ .set arch=r4000
cache 0x14, 0(t0)
cache 0x14, 32(t0)
cache 0x14, 64(t0)
@@ -121,7 +121,7 @@ LEAF(alchemy_sleep_au1550)
/* cache following instructions, as memory gets put to sleep */
la t0, 1f
- .set mips3
+ .set arch=r4000
cache 0x14, 0(t0)
cache 0x14, 32(t0)
cache 0x14, 64(t0)
@@ -163,7 +163,7 @@ LEAF(alchemy_sleep_au1300)
la t1, 4f
subu t2, t1, t0
- .set mips3
+ .set arch=r4000
1: cache 0x14, 0(t0)
subu t2, t2, 32
diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile
index 15bf7306648b..9da3659a9d1c 100644
--- a/arch/mips/alchemy/devboards/Makefile
+++ b/arch/mips/alchemy/devboards/Makefile
@@ -2,7 +2,5 @@
# Alchemy Develboards
#
-obj-y += bcsr.o platform.o
+obj-y += bcsr.o platform.o db1000.o db1200.o db1300.o db1550.o db1xxx.o
obj-$(CONFIG_PM) += pm.o
-obj-$(CONFIG_MIPS_DB1000) += db1000.o
-obj-$(CONFIG_MIPS_DB1235) += db1235.o db1200.o db1300.o db1550.o
diff --git a/arch/mips/alchemy/devboards/db1000.c b/arch/mips/alchemy/devboards/db1000.c
index 5483906e0f86..92dd929d4057 100644
--- a/arch/mips/alchemy/devboards/db1000.c
+++ b/arch/mips/alchemy/devboards/db1000.c
@@ -41,42 +41,27 @@
#define F_SWAPPED (bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT)
-struct pci_dev;
+const char *get_system_type(void);
-static const char *board_type_str(void)
+int __init db1000_board_setup(void)
{
+ /* initialize board register space */
+ bcsr_init(DB1000_BCSR_PHYS_ADDR,
+ DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS);
+
switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
case BCSR_WHOAMI_DB1000:
- return "DB1000";
case BCSR_WHOAMI_DB1500:
- return "DB1500";
case BCSR_WHOAMI_DB1100:
- return "DB1100";
case BCSR_WHOAMI_PB1500:
case BCSR_WHOAMI_PB1500R2:
- return "PB1500";
case BCSR_WHOAMI_PB1100:
- return "PB1100";
- default:
- return "(unknown)";
+ pr_info("AMD Alchemy %s Board\n", get_system_type());
+ return 0;
}
+ return -ENODEV;
}
-const char *get_system_type(void)
-{
- return board_type_str();
-}
-
-void __init board_setup(void)
-{
- /* initialize board register space */
- bcsr_init(DB1000_BCSR_PHYS_ADDR,
- DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS);
-
- printk(KERN_INFO "AMD Alchemy %s Board\n", board_type_str());
-}
-
-
static int db1500_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
{
if ((slot < 12) || (slot > 13) || pin == 0)
@@ -114,17 +99,10 @@ static struct platform_device db1500_pci_host_dev = {
.resource = alchemy_pci_host_res,
};
-static int __init db1500_pci_init(void)
+int __init db1500_pci_setup(void)
{
- int id = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
- if ((id == BCSR_WHOAMI_DB1500) || (id == BCSR_WHOAMI_PB1500) ||
- (id == BCSR_WHOAMI_PB1500R2))
- return platform_device_register(&db1500_pci_host_dev);
- return 0;
+ return platform_device_register(&db1500_pci_host_dev);
}
-/* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */
-arch_initcall(db1500_pci_init);
-
static struct resource au1100_lcd_resources[] = {
[0] = {
@@ -513,7 +491,7 @@ static struct platform_device *db1100_devs[] = {
&db1000_irda_dev,
};
-static int __init db1000_dev_init(void)
+int __init db1000_dev_setup(void)
{
int board = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
int c0, c1, d0, d1, s0, s1, flashsize = 32, twosocks = 1;
@@ -623,4 +601,3 @@ static int __init db1000_dev_init(void)
db1x_register_norflash(flashsize << 20, 4 /* 32bit */, F_SWAPPED);
return 0;
}
-device_initcall(db1000_dev_init);
diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c
index a84d98b8f96e..9e46667f2597 100644
--- a/arch/mips/alchemy/devboards/db1200.c
+++ b/arch/mips/alchemy/devboards/db1200.c
@@ -35,16 +35,63 @@
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/smc91x.h>
+#include <linux/ata_platform.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1100_mmc.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
#include <asm/mach-au1x00/au1200fb.h>
#include <asm/mach-au1x00/au1550_spi.h>
#include <asm/mach-db1x00/bcsr.h>
-#include <asm/mach-db1x00/db1200.h>
#include "platform.h"
+#define BCSR_INT_IDE 0x0001
+#define BCSR_INT_ETH 0x0002
+#define BCSR_INT_PC0 0x0004
+#define BCSR_INT_PC0STSCHG 0x0008
+#define BCSR_INT_PC1 0x0010
+#define BCSR_INT_PC1STSCHG 0x0020
+#define BCSR_INT_DC 0x0040
+#define BCSR_INT_FLASHBUSY 0x0080
+#define BCSR_INT_PC0INSERT 0x0100
+#define BCSR_INT_PC0EJECT 0x0200
+#define BCSR_INT_PC1INSERT 0x0400
+#define BCSR_INT_PC1EJECT 0x0800
+#define BCSR_INT_SD0INSERT 0x1000
+#define BCSR_INT_SD0EJECT 0x2000
+#define BCSR_INT_SD1INSERT 0x4000
+#define BCSR_INT_SD1EJECT 0x8000
+
+#define DB1200_IDE_PHYS_ADDR 0x18800000
+#define DB1200_IDE_REG_SHIFT 5
+#define DB1200_IDE_PHYS_LEN (16 << DB1200_IDE_REG_SHIFT)
+#define DB1200_ETH_PHYS_ADDR 0x19000300
+#define DB1200_NAND_PHYS_ADDR 0x20000000
+
+#define PB1200_IDE_PHYS_ADDR 0x0C800000
+#define PB1200_ETH_PHYS_ADDR 0x0D000300
+#define PB1200_NAND_PHYS_ADDR 0x1C000000
+
+#define DB1200_INT_BEGIN (AU1000_MAX_INTR + 1)
+#define DB1200_IDE_INT (DB1200_INT_BEGIN + 0)
+#define DB1200_ETH_INT (DB1200_INT_BEGIN + 1)
+#define DB1200_PC0_INT (DB1200_INT_BEGIN + 2)
+#define DB1200_PC0_STSCHG_INT (DB1200_INT_BEGIN + 3)
+#define DB1200_PC1_INT (DB1200_INT_BEGIN + 4)
+#define DB1200_PC1_STSCHG_INT (DB1200_INT_BEGIN + 5)
+#define DB1200_DC_INT (DB1200_INT_BEGIN + 6)
+#define DB1200_FLASHBUSY_INT (DB1200_INT_BEGIN + 7)
+#define DB1200_PC0_INSERT_INT (DB1200_INT_BEGIN + 8)
+#define DB1200_PC0_EJECT_INT (DB1200_INT_BEGIN + 9)
+#define DB1200_PC1_INSERT_INT (DB1200_INT_BEGIN + 10)
+#define DB1200_PC1_EJECT_INT (DB1200_INT_BEGIN + 11)
+#define DB1200_SD0_INSERT_INT (DB1200_INT_BEGIN + 12)
+#define DB1200_SD0_EJECT_INT (DB1200_INT_BEGIN + 13)
+#define PB1200_SD1_INSERT_INT (DB1200_INT_BEGIN + 14)
+#define PB1200_SD1_EJECT_INT (DB1200_INT_BEGIN + 15)
+#define DB1200_INT_END (DB1200_INT_BEGIN + 15)
+
const char *get_system_type(void);
static int __init db1200_detect_board(void)
@@ -89,6 +136,15 @@ int __init db1200_board_setup(void)
return -ENODEV;
whoami = bcsr_read(BCSR_WHOAMI);
+ switch (BCSR_WHOAMI_BOARD(whoami)) {
+ case BCSR_WHOAMI_PB1200_DDR1:
+ case BCSR_WHOAMI_PB1200_DDR2:
+ case BCSR_WHOAMI_DB1200:
+ break;
+ default:
+ return -ENODEV;
+ }
+
printk(KERN_INFO "Alchemy/AMD/RMI %s Board, CPLD Rev %d"
" Board-ID %d Daughtercard ID %d\n", get_system_type(),
(whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf);
@@ -275,32 +331,38 @@ static struct platform_device db1200_eth_dev = {
/**********************************************************************/
+static struct pata_platform_info db1200_ide_info = {
+ .ioport_shift = DB1200_IDE_REG_SHIFT,
+};
+
+#define IDE_ALT_START (14 << DB1200_IDE_REG_SHIFT)
static struct resource db1200_ide_res[] = {
[0] = {
.start = DB1200_IDE_PHYS_ADDR,
- .end = DB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1,
+ .end = DB1200_IDE_PHYS_ADDR + IDE_ALT_START - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
+ .start = DB1200_IDE_PHYS_ADDR + IDE_ALT_START,
+ .end = DB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
.start = DB1200_IDE_INT,
.end = DB1200_IDE_INT,
.flags = IORESOURCE_IRQ,
},
- [2] = {
- .start = AU1200_DSCR_CMD0_DMA_REQ1,
- .end = AU1200_DSCR_CMD0_DMA_REQ1,
- .flags = IORESOURCE_DMA,
- },
};
static u64 au1200_ide_dmamask = DMA_BIT_MASK(32);
static struct platform_device db1200_ide_dev = {
- .name = "au1200-ide",
+ .name = "pata_platform",
.id = 0,
.dev = {
.dma_mask = &au1200_ide_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &db1200_ide_info,
},
.num_resources = ARRAY_SIZE(db1200_ide_res),
.resource = db1200_ide_res,
diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c
index 6167e73eef9c..1aed6be4de10 100644
--- a/arch/mips/alchemy/devboards/db1300.c
+++ b/arch/mips/alchemy/devboards/db1300.c
@@ -26,12 +26,44 @@
#include <asm/mach-au1x00/au1200fb.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/mach-au1x00/au1xxx_psc.h>
-#include <asm/mach-db1x00/db1300.h>
#include <asm/mach-db1x00/bcsr.h>
#include <asm/mach-au1x00/prom.h>
#include "platform.h"
+/* FPGA (external mux) interrupt sources */
+#define DB1300_FIRST_INT (ALCHEMY_GPIC_INT_LAST + 1)
+#define DB1300_IDE_INT (DB1300_FIRST_INT + 0)
+#define DB1300_ETH_INT (DB1300_FIRST_INT + 1)
+#define DB1300_CF_INT (DB1300_FIRST_INT + 2)
+#define DB1300_VIDEO_INT (DB1300_FIRST_INT + 4)
+#define DB1300_HDMI_INT (DB1300_FIRST_INT + 5)
+#define DB1300_DC_INT (DB1300_FIRST_INT + 6)
+#define DB1300_FLASH_INT (DB1300_FIRST_INT + 7)
+#define DB1300_CF_INSERT_INT (DB1300_FIRST_INT + 8)
+#define DB1300_CF_EJECT_INT (DB1300_FIRST_INT + 9)
+#define DB1300_AC97_INT (DB1300_FIRST_INT + 10)
+#define DB1300_AC97_PEN_INT (DB1300_FIRST_INT + 11)
+#define DB1300_SD1_INSERT_INT (DB1300_FIRST_INT + 12)
+#define DB1300_SD1_EJECT_INT (DB1300_FIRST_INT + 13)
+#define DB1300_OTG_VBUS_OC_INT (DB1300_FIRST_INT + 14)
+#define DB1300_HOST_VBUS_OC_INT (DB1300_FIRST_INT + 15)
+#define DB1300_LAST_INT (DB1300_FIRST_INT + 15)
+
+/* SMSC9210 CS */
+#define DB1300_ETH_PHYS_ADDR 0x19000000
+#define DB1300_ETH_PHYS_END 0x197fffff
+
+/* ATA CS */
+#define DB1300_IDE_PHYS_ADDR 0x18800000
+#define DB1300_IDE_REG_SHIFT 5
+#define DB1300_IDE_PHYS_LEN (16 << DB1300_IDE_REG_SHIFT)
+
+/* NAND CS */
+#define DB1300_NAND_PHYS_ADDR 0x20000000
+#define DB1300_NAND_PHYS_END 0x20000fff
+
+
static struct i2c_board_info db1300_i2c_devs[] __initdata = {
{ I2C_BOARD_INFO("wm8731", 0x1b), }, /* I2S audio codec */
{ I2C_BOARD_INFO("ne1619", 0x2d), }, /* adm1025-compat hwmon */
@@ -759,11 +791,15 @@ int __init db1300_board_setup(void)
{
unsigned short whoami;
- db1300_gpio_config();
bcsr_init(DB1300_BCSR_PHYS_ADDR,
DB1300_BCSR_PHYS_ADDR + DB1300_BCSR_HEXLED_OFS);
whoami = bcsr_read(BCSR_WHOAMI);
+ if (BCSR_WHOAMI_BOARD(whoami) != BCSR_WHOAMI_DB1300)
+ return -ENODEV;
+
+ db1300_gpio_config();
+
printk(KERN_INFO "NetLogic DBAu1300 Development Platform.\n\t"
"BoardID %d CPLD Rev %d DaughtercardID %d\n",
BCSR_WHOAMI_BOARD(whoami), BCSR_WHOAMI_CPLD(whoami),
diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c
index 016cddacd7ea..bbd8d9884702 100644
--- a/arch/mips/alchemy/devboards/db1550.c
+++ b/arch/mips/alchemy/devboards/db1550.c
@@ -62,10 +62,16 @@ int __init db1550_board_setup(void)
DB1550_BCSR_PHYS_ADDR + DB1550_BCSR_HEXLED_OFS);
whoami = bcsr_read(BCSR_WHOAMI); /* PB1550 hexled offset differs */
- if ((BCSR_WHOAMI_BOARD(whoami) == BCSR_WHOAMI_PB1550_SDR) ||
- (BCSR_WHOAMI_BOARD(whoami) == BCSR_WHOAMI_PB1550_DDR))
+ switch (BCSR_WHOAMI_BOARD(whoami)) {
+ case BCSR_WHOAMI_PB1550_SDR:
+ case BCSR_WHOAMI_PB1550_DDR:
bcsr_init(PB1550_BCSR_PHYS_ADDR,
PB1550_BCSR_PHYS_ADDR + PB1550_BCSR_HEXLED_OFS);
+ case BCSR_WHOAMI_DB1550:
+ break;
+ default:
+ return -ENODEV;
+ }
pr_info("Alchemy/AMD %s Board, CPLD Rev %d Board-ID %d " \
"Daughtercard ID %d\n", get_system_type(),
diff --git a/arch/mips/alchemy/devboards/db1235.c b/arch/mips/alchemy/devboards/db1xxx.c
index bac19dc43d1d..2d47f951121a 100644
--- a/arch/mips/alchemy/devboards/db1235.c
+++ b/arch/mips/alchemy/devboards/db1xxx.c
@@ -1,12 +1,13 @@
/*
- * DB1200/PB1200 / DB1550 / DB1300 board support.
- *
- * These 4 boards can reliably be supported in a single kernel image.
+ * Alchemy DB/PB1xxx board support.
*/
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-db1x00/bcsr.h>
+int __init db1000_board_setup(void);
+int __init db1000_dev_setup(void);
+int __init db1500_pci_setup(void);
int __init db1200_board_setup(void);
int __init db1200_dev_setup(void);
int __init db1300_board_setup(void);
@@ -18,6 +19,17 @@ int __init db1550_pci_setup(int);
static const char *board_type_str(void)
{
switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
+ case BCSR_WHOAMI_DB1000:
+ return "DB1000";
+ case BCSR_WHOAMI_DB1500:
+ return "DB1500";
+ case BCSR_WHOAMI_DB1100:
+ return "DB1100";
+ case BCSR_WHOAMI_PB1500:
+ case BCSR_WHOAMI_PB1500R2:
+ return "PB1500";
+ case BCSR_WHOAMI_PB1100:
+ return "PB1100";
case BCSR_WHOAMI_PB1200_DDR1:
case BCSR_WHOAMI_PB1200_DDR2:
return "PB1200";
@@ -45,6 +57,11 @@ void __init board_setup(void)
int ret;
switch (alchemy_get_cputype()) {
+ case ALCHEMY_CPU_AU1000:
+ case ALCHEMY_CPU_AU1500:
+ case ALCHEMY_CPU_AU1100:
+ ret = db1000_board_setup();
+ break;
case ALCHEMY_CPU_AU1550:
ret = db1550_board_setup();
break;
@@ -62,7 +79,7 @@ void __init board_setup(void)
panic("cannot initialize board support");
}
-int __init db1235_arch_init(void)
+static int __init db1xxx_arch_init(void)
{
int id = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
if (id == BCSR_WHOAMI_DB1550)
@@ -70,14 +87,24 @@ int __init db1235_arch_init(void)
else if ((id == BCSR_WHOAMI_PB1550_SDR) ||
(id == BCSR_WHOAMI_PB1550_DDR))
return db1550_pci_setup(1);
+ else if ((id == BCSR_WHOAMI_DB1500) || (id == BCSR_WHOAMI_PB1500) ||
+ (id == BCSR_WHOAMI_PB1500R2))
+ return db1500_pci_setup();
return 0;
}
-arch_initcall(db1235_arch_init);
+arch_initcall(db1xxx_arch_init);
-int __init db1235_dev_init(void)
+static int __init db1xxx_dev_init(void)
{
switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
+ case BCSR_WHOAMI_DB1000:
+ case BCSR_WHOAMI_DB1500:
+ case BCSR_WHOAMI_DB1100:
+ case BCSR_WHOAMI_PB1500:
+ case BCSR_WHOAMI_PB1500R2:
+ case BCSR_WHOAMI_PB1100:
+ return db1000_dev_setup();
case BCSR_WHOAMI_PB1200_DDR1:
case BCSR_WHOAMI_PB1200_DDR2:
case BCSR_WHOAMI_DB1200:
@@ -91,4 +118,4 @@ int __init db1235_dev_init(void)
}
return 0;
}
-device_initcall(db1235_dev_init);
+device_initcall(db1xxx_dev_init);
diff --git a/arch/mips/ar7/time.c b/arch/mips/ar7/time.c
index 1dc6c3b37f91..22c93213b233 100644
--- a/arch/mips/ar7/time.c
+++ b/arch/mips/ar7/time.c
@@ -18,6 +18,7 @@
* Setting up the clock on the MIPS boards.
*/
+#include <linux/init.h>
#include <linux/time.h>
#include <linux/err.h>
#include <linux/clk.h>
diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig
index 3995e31a73e2..dfc60209dc63 100644
--- a/arch/mips/ath79/Kconfig
+++ b/arch/mips/ath79/Kconfig
@@ -74,34 +74,26 @@ config ATH79_MACH_UBNT_XM
endmenu
config SOC_AR71XX
- select USB_ARCH_HAS_EHCI
- select USB_ARCH_HAS_OHCI
select HW_HAS_PCI
def_bool n
config SOC_AR724X
- select USB_ARCH_HAS_EHCI
- select USB_ARCH_HAS_OHCI
select HW_HAS_PCI
select PCI_AR724X if PCI
def_bool n
config SOC_AR913X
- select USB_ARCH_HAS_EHCI
def_bool n
config SOC_AR933X
- select USB_ARCH_HAS_EHCI
def_bool n
config SOC_AR934X
- select USB_ARCH_HAS_EHCI
select HW_HAS_PCI
select PCI_AR724X if PCI
def_bool n
config SOC_QCA955X
- select USB_ARCH_HAS_EHCI
select HW_HAS_PCI
select PCI_AR724X if PCI
def_bool n
diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile
index 4688b6a6211b..d58c51b5e501 100644
--- a/arch/mips/bcm47xx/Makefile
+++ b/arch/mips/bcm47xx/Makefile
@@ -4,4 +4,4 @@
#
obj-y += irq.o nvram.o prom.o serial.o setup.o time.o sprom.o
-obj-y += board.o buttons.o leds.o
+obj-y += board.o buttons.o leds.o workarounds.o
diff --git a/arch/mips/bcm47xx/bcm47xx_private.h b/arch/mips/bcm47xx/bcm47xx_private.h
index 5c94acebf76a..0194c3b9a729 100644
--- a/arch/mips/bcm47xx/bcm47xx_private.h
+++ b/arch/mips/bcm47xx/bcm47xx_private.h
@@ -9,4 +9,7 @@ int __init bcm47xx_buttons_register(void);
/* leds.c */
void __init bcm47xx_leds_register(void);
+/* workarounds.c */
+void __init bcm47xx_workarounds(void);
+
#endif
diff --git a/arch/mips/bcm47xx/board.c b/arch/mips/bcm47xx/board.c
index 6d612e2b949b..44ab1be68c3c 100644
--- a/arch/mips/bcm47xx/board.c
+++ b/arch/mips/bcm47xx/board.c
@@ -1,3 +1,4 @@
+#include <linux/errno.h>
#include <linux/export.h>
#include <linux/string.h>
#include <bcm47xx_board.h>
@@ -71,7 +72,11 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_hardware_version[] __initcons
{{BCM47XX_BOARD_ASUS_WL500W, "Asus WL500W"}, "WL500gW-"},
{{BCM47XX_BOARD_ASUS_WL520GC, "Asus WL520GC"}, "WL520GC-"},
{{BCM47XX_BOARD_ASUS_WL520GU, "Asus WL520GU"}, "WL520GU-"},
+ {{BCM47XX_BOARD_BELKIN_F7D3301, "Belkin F7D3301"}, "F7D3301"},
+ {{BCM47XX_BOARD_BELKIN_F7D3302, "Belkin F7D3302"}, "F7D3302"},
{{BCM47XX_BOARD_BELKIN_F7D4301, "Belkin F7D4301"}, "F7D4301"},
+ {{BCM47XX_BOARD_BELKIN_F7D4302, "Belkin F7D4302"}, "F7D4302"},
+ {{BCM47XX_BOARD_BELKIN_F7D4401, "Belkin F7D4401"}, "F7D4401"},
{ {0}, NULL},
};
@@ -175,7 +180,16 @@ struct bcm47xx_board_type_list3 bcm47xx_board_list_board[] __initconst = {
{{BCM47XX_BOARD_PHICOMM_M1, "Phicomm M1"}, "0x0590", "80", "0x1104"},
{{BCM47XX_BOARD_ZTE_H218N, "ZTE H218N"}, "0x053d", "1234", "0x1305"},
{{BCM47XX_BOARD_NETGEAR_WNR3500L, "Netgear WNR3500L"}, "0x04CF", "3500", "02"},
- {{BCM47XX_BOARD_LINKSYS_WRT54GSV1, "Linksys WRT54GS V1"}, "0x0101", "42", "0x10"},
+ {{BCM47XX_BOARD_LINKSYS_WRT54G, "Linksys WRT54G/GS/GL"}, "0x0101", "42", "0x10"},
+ {{BCM47XX_BOARD_LINKSYS_WRT54G, "Linksys WRT54G/GS/GL"}, "0x0467", "42", "0x10"},
+ {{BCM47XX_BOARD_LINKSYS_WRT54G, "Linksys WRT54G/GS/GL"}, "0x0708", "42", "0x10"},
+ { {0}, NULL},
+};
+
+/* boardtype, boardrev */
+static const
+struct bcm47xx_board_type_list2 bcm47xx_board_list_board_type_rev[] __initconst = {
+ {{BCM47XX_BOARD_SIEMENS_SE505V2, "Siemens SE505 V2"}, "0x0101", "0x10"},
{ {0}, NULL},
};
@@ -272,6 +286,16 @@ static __init const struct bcm47xx_board_type *bcm47xx_board_get_nvram(void)
return &e3->board;
}
}
+
+ if (bcm47xx_nvram_getenv("boardtype", buf1, sizeof(buf1)) >= 0 &&
+ bcm47xx_nvram_getenv("boardrev", buf2, sizeof(buf2)) >= 0 &&
+ bcm47xx_nvram_getenv("boardnum", buf3, sizeof(buf3)) == -ENOENT) {
+ for (e2 = bcm47xx_board_list_board_type_rev; e2->value1; e2++) {
+ if (!strcmp(buf1, e2->value1) &&
+ !strcmp(buf2, e2->value2))
+ return &e2->board;
+ }
+ }
return bcm47xx_board_unknown;
}
diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c
index 872c62e93e0e..49a1ce06844b 100644
--- a/arch/mips/bcm47xx/buttons.c
+++ b/arch/mips/bcm47xx/buttons.c
@@ -259,6 +259,18 @@ bcm47xx_buttons_linksys_wrt310nv1[] __initconst = {
};
static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt54g3gv2[] __initconst = {
+ BCM47XX_GPIO_KEY(5, KEY_WIMAX),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt54gsv1[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
bcm47xx_buttons_linksys_wrt610nv1[] __initconst = {
BCM47XX_GPIO_KEY(6, KEY_RESTART),
BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON),
@@ -270,6 +282,12 @@ bcm47xx_buttons_linksys_wrt610nv2[] __initconst = {
BCM47XX_GPIO_KEY(6, KEY_RESTART),
};
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrtsl54gs[] __initconst = {
+ BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
/* Motorola */
static const struct gpio_keys_button
@@ -402,7 +420,11 @@ int __init bcm47xx_buttons_register(void)
err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wlhdd);
break;
+ case BCM47XX_BOARD_BELKIN_F7D3301:
+ case BCM47XX_BOARD_BELKIN_F7D3302:
case BCM47XX_BOARD_BELKIN_F7D4301:
+ case BCM47XX_BOARD_BELKIN_F7D4302:
+ case BCM47XX_BOARD_BELKIN_F7D4401:
err = bcm47xx_copy_bdata(bcm47xx_buttons_belkin_f7d4301);
break;
@@ -479,12 +501,21 @@ int __init bcm47xx_buttons_register(void)
case BCM47XX_BOARD_LINKSYS_WRT310NV1:
err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt310nv1);
break;
+ case BCM47XX_BOARD_LINKSYS_WRT54G:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt54gsv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT54G3GV2:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt54g3gv2);
+ break;
case BCM47XX_BOARD_LINKSYS_WRT610NV1:
err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt610nv1);
break;
case BCM47XX_BOARD_LINKSYS_WRT610NV2:
err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt610nv2);
break;
+ case BCM47XX_BOARD_LINKSYS_WRTSL54GS:
+ err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrtsl54gs);
+ break;
case BCM47XX_BOARD_MOTOROLA_WE800G:
err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_we800g);
diff --git a/arch/mips/bcm47xx/leds.c b/arch/mips/bcm47xx/leds.c
index 647d15527066..adcb547a91c3 100644
--- a/arch/mips/bcm47xx/leds.c
+++ b/arch/mips/bcm47xx/leds.c
@@ -292,6 +292,21 @@ bcm47xx_leds_linksys_wrt310nv1[] __initconst = {
};
static const struct gpio_led
+bcm47xx_leds_linksys_wrt54gsv1[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(5, "white", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "orange", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt54g3gv2[] __initconst = {
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(2, "green", "3g", 0, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "blue", "3g", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
bcm47xx_leds_linksys_wrt610nv1[] __initconst = {
BCM47XX_GPIO_LED(0, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF),
BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_OFF),
@@ -308,6 +323,15 @@ bcm47xx_leds_linksys_wrt610nv2[] __initconst = {
BCM47XX_GPIO_LED(7, "unk", "usb", 0, LEDS_GPIO_DEFSTATE_OFF),
};
+static const struct gpio_led
+bcm47xx_leds_linksys_wrtsl54gs[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+ BCM47XX_GPIO_LED(2, "white", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "orange", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(7, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
/* Motorola */
static const struct gpio_led
@@ -359,6 +383,14 @@ bcm47xx_leds_netgear_wnr834bv2[] __initconst = {
BCM47XX_GPIO_LED(7, "unk", "connected", 0, LEDS_GPIO_DEFSTATE_OFF),
};
+/* Siemens */
+static const struct gpio_led
+bcm47xx_leds_siemens_se505v2[] __initconst = {
+ BCM47XX_GPIO_LED(0, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(3, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+ BCM47XX_GPIO_LED(5, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
/* SimpleTech */
static const struct gpio_led
@@ -425,7 +457,11 @@ void __init bcm47xx_leds_register(void)
bcm47xx_set_pdata(bcm47xx_leds_asus_wlhdd);
break;
+ case BCM47XX_BOARD_BELKIN_F7D3301:
+ case BCM47XX_BOARD_BELKIN_F7D3302:
case BCM47XX_BOARD_BELKIN_F7D4301:
+ case BCM47XX_BOARD_BELKIN_F7D4302:
+ case BCM47XX_BOARD_BELKIN_F7D4401:
bcm47xx_set_pdata(bcm47xx_leds_belkin_f7d4301);
break;
@@ -502,12 +538,21 @@ void __init bcm47xx_leds_register(void)
case BCM47XX_BOARD_LINKSYS_WRT310NV1:
bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt310nv1);
break;
+ case BCM47XX_BOARD_LINKSYS_WRT54G:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt54gsv1);
+ break;
+ case BCM47XX_BOARD_LINKSYS_WRT54G3GV2:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt54g3gv2);
+ break;
case BCM47XX_BOARD_LINKSYS_WRT610NV1:
bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt610nv1);
break;
case BCM47XX_BOARD_LINKSYS_WRT610NV2:
bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt610nv2);
break;
+ case BCM47XX_BOARD_LINKSYS_WRTSL54GS:
+ bcm47xx_set_pdata(bcm47xx_leds_linksys_wrtsl54gs);
+ break;
case BCM47XX_BOARD_MOTOROLA_WE800G:
bcm47xx_set_pdata(bcm47xx_leds_motorola_we800g);
@@ -529,6 +574,10 @@ void __init bcm47xx_leds_register(void)
bcm47xx_set_pdata(bcm47xx_leds_netgear_wnr834bv2);
break;
+ case BCM47XX_BOARD_SIEMENS_SE505V2:
+ bcm47xx_set_pdata(bcm47xx_leds_siemens_se505v2);
+ break;
+
case BCM47XX_BOARD_SIMPLETECH_SIMPLESHARE:
bcm47xx_set_pdata(bcm47xx_leds_simpletech_simpleshare);
break;
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index 6decb27cf48b..2bed73a684ae 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -196,7 +196,7 @@ int bcm47xx_nvram_gpio_pin(const char *name)
char nvram_var[10];
char buf[30];
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < 32; i++) {
err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
if (err <= 0)
continue;
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 025be218ea15..63a4b0e915dc 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -212,7 +212,7 @@ void __init plat_mem_setup(void)
{
struct cpuinfo_mips *c = &current_cpu_data;
- if (c->cputype == CPU_74K) {
+ if ((c->cputype == CPU_74K) || (c->cputype == CPU_1074K)) {
printk(KERN_INFO "bcm47xx: using bcma bus\n");
#ifdef CONFIG_BCM47XX_BCMA
bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA;
@@ -282,6 +282,7 @@ static int __init bcm47xx_register_bus_complete(void)
}
bcm47xx_buttons_register();
bcm47xx_leds_register();
+ bcm47xx_workarounds();
fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status);
return 0;
diff --git a/arch/mips/bcm47xx/workarounds.c b/arch/mips/bcm47xx/workarounds.c
new file mode 100644
index 000000000000..e81ce4623070
--- /dev/null
+++ b/arch/mips/bcm47xx/workarounds.c
@@ -0,0 +1,31 @@
+#include "bcm47xx_private.h"
+
+#include <linux/gpio.h>
+#include <bcm47xx_board.h>
+#include <bcm47xx.h>
+
+static void __init bcm47xx_workarounds_netgear_wnr3500l(void)
+{
+ const int usb_power = 12;
+ int err;
+
+ err = gpio_request_one(usb_power, GPIOF_OUT_INIT_HIGH, "usb_power");
+ if (err)
+ pr_err("Failed to request USB power gpio: %d\n", err);
+ else
+ gpio_free(usb_power);
+}
+
+void __init bcm47xx_workarounds(void)
+{
+ enum bcm47xx_board board = bcm47xx_board_get();
+
+ switch (board) {
+ case BCM47XX_BOARD_NETGEAR_WNR3500L:
+ bcm47xx_workarounds_netgear_wnr3500l();
+ break;
+ default:
+ /* No workaround(s) needed */
+ break;
+ }
+}
diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c
index 1b1b8a89959b..fd4e76c00a42 100644
--- a/arch/mips/bcm63xx/cpu.c
+++ b/arch/mips/bcm63xx/cpu.c
@@ -299,14 +299,13 @@ static unsigned int detect_memory_size(void)
void __init bcm63xx_cpu_init(void)
{
unsigned int tmp;
- struct cpuinfo_mips *c = &current_cpu_data;
unsigned int cpu = smp_processor_id();
u32 chipid_reg;
/* soc registers location depends on cpu type */
chipid_reg = 0;
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_BMIPS3300:
if ((read_c0_prid() & PRID_IMP_MASK) != PRID_IMP_BMIPS3300_ALT)
__cpu_name[cpu] = "Broadcom BCM6338";
diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index 25fbfae06c1f..c2bb4f896ce7 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -975,10 +975,6 @@ static int octeon_irq_ciu_xlat(struct irq_domain *d,
if (ciu > 1 || bit > 63)
return -EINVAL;
- /* These are the GPIO lines */
- if (ciu == 0 && bit >= 16 && bit < 32)
- return -EINVAL;
-
*out_hwirq = (ciu << 6) | bit;
*out_type = 0;
@@ -1007,6 +1003,10 @@ static int octeon_irq_ciu_map(struct irq_domain *d,
if (!octeon_irq_virq_in_range(virq))
return -EINVAL;
+ /* Don't map irq if it is reserved for GPIO. */
+ if (line == 0 && bit >= 16 && bit <32)
+ return 0;
+
if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0)
return -EINVAL;
@@ -1525,10 +1525,6 @@ static int octeon_irq_ciu2_xlat(struct irq_domain *d,
ciu = intspec[0];
bit = intspec[1];
- /* Line 7 are the GPIO lines */
- if (ciu > 6 || bit > 63)
- return -EINVAL;
-
*out_hwirq = (ciu << 6) | bit;
*out_type = 0;
@@ -1570,8 +1566,14 @@ static int octeon_irq_ciu2_map(struct irq_domain *d,
if (!octeon_irq_virq_in_range(virq))
return -EINVAL;
- /* Line 7 are the GPIO lines */
- if (line > 6 || octeon_irq_ciu_to_irq[line][bit] != 0)
+ /*
+ * Don't map irq if it is reserved for GPIO.
+ * (Line 7 are the GPIO lines.)
+ */
+ if (line == 7)
+ return 0;
+
+ if (line > 7 || octeon_irq_ciu_to_irq[line][bit] != 0)
return -EINVAL;
if (octeon_irq_ciu2_is_edge(line, bit))
diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig
deleted file mode 100644
index bac26b971c5e..000000000000
--- a/arch/mips/configs/db1000_defconfig
+++ /dev/null
@@ -1,359 +0,0 @@
-CONFIG_MIPS=y
-CONFIG_MIPS_ALCHEMY=y
-CONFIG_MIPS_DB1000=y
-CONFIG_SCHED_OMIT_FRAME_POINTER=y
-CONFIG_TICK_ONESHOT=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_HZ_100=y
-CONFIG_HZ=100
-CONFIG_PREEMPT_NONE=y
-CONFIG_EXPERIMENTAL=y
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-CONFIG_CROSS_COMPILE=""
-CONFIG_LOCALVERSION="-db1x00"
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_KERNEL_LZMA=y
-CONFIG_DEFAULT_HOSTNAME="db1x00"
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-CONFIG_FHANDLE=y
-CONFIG_AUDIT=y
-CONFIG_TINY_RCU=y
-CONFIG_LOG_BUF_SHIFT=18
-CONFIG_NAMESPACES=y
-CONFIG_UTS_NS=y
-CONFIG_IPC_NS=y
-CONFIG_USER_NS=y
-CONFIG_PID_NS=y
-CONFIG_NET_NS=y
-CONFIG_SYSCTL=y
-CONFIG_EXPERT=y
-CONFIG_KALLSYMS=y
-CONFIG_KALLSYMS_ALL=y
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_AIO=y
-CONFIG_EMBEDDED=y
-CONFIG_HAVE_PERF_EVENTS=y
-CONFIG_PERF_USE_VMALLOC=y
-CONFIG_PCI_QUIRKS=y
-CONFIG_SLAB=y
-CONFIG_SLABINFO=y
-CONFIG_BLOCK=y
-CONFIG_LBDAF=y
-CONFIG_BLK_DEV_BSG=y
-CONFIG_BLK_DEV_BSGLIB=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_DEFAULT_NOOP=y
-CONFIG_DEFAULT_IOSCHED="noop"
-CONFIG_FREEZER=y
-CONFIG_PCI=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA=y
-CONFIG_PCMCIA_LOAD_CIS=y
-CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
-CONFIG_BINFMT_ELF=y
-CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
-CONFIG_SUSPEND=y
-CONFIG_SUSPEND_FREEZER=y
-CONFIG_PM_SLEEP=y
-CONFIG_PM_RUNTIME=y
-CONFIG_PM=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-CONFIG_NET_IPIP=y
-CONFIG_INET_TUNNEL=y
-CONFIG_INET_LRO=y
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-CONFIG_IPV6=y
-CONFIG_INET6_XFRM_MODE_TRANSPORT=y
-CONFIG_INET6_XFRM_MODE_TUNNEL=y
-CONFIG_INET6_XFRM_MODE_BEET=y
-CONFIG_IPV6_SIT=y
-CONFIG_IPV6_NDISC_NODETYPE=y
-CONFIG_STP=y
-CONFIG_GARP=y
-CONFIG_BRIDGE=y
-CONFIG_BRIDGE_IGMP_SNOOPING=y
-CONFIG_VLAN_8021Q=y
-CONFIG_VLAN_8021Q_GVRP=y
-CONFIG_LLC=y
-CONFIG_LLC2=y
-CONFIG_DNS_RESOLVER=y
-CONFIG_BT=y
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIBTUSB=y
-CONFIG_UEVENT_HELPER_PATH=""
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLKDEVS=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_GEN_PROBE=y
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-CONFIG_MTD_CFI_NOSWAP=y
-CONFIG_MTD_CFI_GEOMETRY=y
-CONFIG_MTD_MAP_BANK_WIDTH_1=y
-CONFIG_MTD_MAP_BANK_WIDTH_2=y
-CONFIG_MTD_MAP_BANK_WIDTH_4=y
-CONFIG_MTD_CFI_I1=y
-CONFIG_MTD_CFI_I2=y
-CONFIG_MTD_CFI_I4=y
-CONFIG_MTD_CFI_I8=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_CFI_UTIL=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_SCSI_MOD=y
-CONFIG_SCSI=y
-CONFIG_SCSI_DMA=y
-CONFIG_SCSI_PROC_FS=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_ATA=y
-CONFIG_ATA_VERBOSE_ERROR=y
-CONFIG_ATA_SFF=y
-CONFIG_ATA_BMDMA=y
-CONFIG_PATA_HPT37X=y
-CONFIG_PATA_PCMCIA=y
-CONFIG_MD=y
-CONFIG_BLK_DEV_DM=y
-CONFIG_FIREWIRE=y
-CONFIG_FIREWIRE_OHCI=y
-CONFIG_FIREWIRE_OHCI_DEBUG=y
-CONFIG_FIREWIRE_NET=y
-CONFIG_NETDEVICES=y
-CONFIG_MII=y
-CONFIG_PHYLIB=y
-CONFIG_NET_ETHERNET=y
-CONFIG_MIPS_AU1X00_ENET=y
-CONFIG_NET_PCMCIA=y
-CONFIG_PCMCIA_3C589=y
-CONFIG_PCMCIA_PCNET=y
-CONFIG_PPP=y
-CONFIG_PPP_MULTILINK=y
-CONFIG_PPP_FILTER=y
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_SYNC_TTY=y
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=y
-CONFIG_PPP_MPPE=y
-CONFIG_PPPOE=y
-CONFIG_INPUT=y
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_VT=y
-CONFIG_CONSOLE_TRANSLATIONS=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
-CONFIG_DEVKMEM=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_TTY_PRINTK=y
-CONFIG_DEVPORT=y
-CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-CONFIG_FB=y
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_FB_CFB_COPYAREA=y
-CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_AU1100=y
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x16=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_TIMER=y
-CONFIG_SND_PCM=y
-CONFIG_SND_JACK=y
-CONFIG_SND_SEQUENCER=y
-CONFIG_SND_HRTIMER=y
-CONFIG_SND_SEQ_HRTIMER_DEFAULT=y
-CONFIG_SND_DYNAMIC_MINORS=y
-CONFIG_SND_VMASTER=y
-CONFIG_SND_AC97_CODEC=y
-CONFIG_SND_SOC=y
-CONFIG_SND_SOC_AC97_BUS=y
-CONFIG_SND_SOC_AU1XAUDIO=y
-CONFIG_SND_SOC_AU1XAC97C=y
-CONFIG_SND_SOC_DB1000=y
-CONFIG_SND_SOC_AC97_CODEC=y
-CONFIG_AC97_BUS=y
-CONFIG_HID_SUPPORT=y
-CONFIG_HID=y
-CONFIG_HIDRAW=y
-CONFIG_USB_HID=y
-CONFIG_USB_SUPPORT=y
-CONFIG_USB=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-CONFIG_USB_EHCI_TT_NEWSCHED=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PLATFORM=y
-CONFIG_USB_UHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_RTC_LIB=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-CONFIG_RTC_INTF_SYSFS=y
-CONFIG_RTC_INTF_PROC=y
-CONFIG_RTC_INTF_DEV=y
-CONFIG_RTC_DRV_AU1XXX=y
-CONFIG_EXT4_FS=y
-CONFIG_EXT4_USE_FOR_EXT23=y
-CONFIG_EXT4_FS_XATTR=y
-CONFIG_EXT4_FS_POSIX_ACL=y
-CONFIG_EXT4_FS_SECURITY=y
-CONFIG_JBD2=y
-CONFIG_FS_MBCACHE=y
-CONFIG_FS_POSIX_ACL=y
-CONFIG_EXPORTFS=y
-CONFIG_FILE_LOCKING=y
-CONFIG_FSNOTIFY=y
-CONFIG_DNOTIFY=y
-CONFIG_INOTIFY_USER=y
-CONFIG_GENERIC_ACL=y
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_TMPFS_XATTR=y
-CONFIG_MISC_FILESYSTEMS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=0
-CONFIG_JFFS2_FS_WRITEBUFFER=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_FS_XATTR=y
-CONFIG_JFFS2_FS_POSIX_ACL=y
-CONFIG_JFFS2_FS_SECURITY=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_ZLIB=y
-CONFIG_JFFS2_LZO=y
-CONFIG_JFFS2_RTIME=y
-CONFIG_JFFS2_RUBIN=y
-CONFIG_JFFS2_CMODE_PRIORITY=y
-CONFIG_SQUASHFS=y
-CONFIG_SQUASHFS_ZLIB=y
-CONFIG_SQUASHFS_LZO=y
-CONFIG_SQUASHFS_XZ=y
-CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
-CONFIG_NETWORK_FILESYSTEMS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
-CONFIG_NFS_V4_1=y
-CONFIG_PNFS_FILE_LAYOUT=y
-CONFIG_PNFS_BLOCK=y
-CONFIG_ROOT_NFS=y
-CONFIG_NFS_USE_KERNEL_DNS=y
-CONFIG_NFS_USE_NEW_IDMAPPER=y
-CONFIG_NFSD=y
-CONFIG_NFSD_V2_ACL=y
-CONFIG_NFSD_V3=y
-CONFIG_NFSD_V3_ACL=y
-CONFIG_NFSD_V4=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_ACL_SUPPORT=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-CONFIG_SUNRPC_BACKCHANNEL=y
-CONFIG_MSDOS_PARTITION=y
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_CODEPAGE_1250=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_ISO8859_15=y
-CONFIG_NLS_UTF8=y
-CONFIG_HAVE_ARCH_KGDB=y
-CONFIG_EARLY_PRINTK=y
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="noirqdebug rootwait root=/dev/sda1 rootfstype=ext4 console=ttyS0,115200 video=au1100fb:panel:CRT_800x600_16"
-CONFIG_DEBUG_ZBOOT=y
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
-CONFIG_SECURITYFS=y
-CONFIG_DEFAULT_SECURITY_DAC=y
-CONFIG_DEFAULT_SECURITY=""
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_ALGAPI2=y
-CONFIG_CRYPTO_AEAD2=y
-CONFIG_CRYPTO_BLKCIPHER=y
-CONFIG_CRYPTO_BLKCIPHER2=y
-CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_HASH2=y
-CONFIG_CRYPTO_RNG=y
-CONFIG_CRYPTO_RNG2=y
-CONFIG_CRYPTO_PCOMP2=y
-CONFIG_CRYPTO_MANAGER=y
-CONFIG_CRYPTO_MANAGER2=y
-CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
-CONFIG_CRYPTO_WORKQUEUE=y
-CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_SHA1=y
-CONFIG_CRYPTO_AES=y
-CONFIG_CRYPTO_ANSI_CPRNG=y
-CONFIG_BITREVERSE=y
-CONFIG_CRC_CCITT=y
-CONFIG_CRC16=y
-CONFIG_CRC_ITU_T=y
-CONFIG_CRC32=y
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
-CONFIG_LZO_COMPRESS=y
-CONFIG_LZO_DECOMPRESS=y
-CONFIG_XZ_DEC=y
diff --git a/arch/mips/configs/db1235_defconfig b/arch/mips/configs/db1235_defconfig
deleted file mode 100644
index 28e49f226dc0..000000000000
--- a/arch/mips/configs/db1235_defconfig
+++ /dev/null
@@ -1,434 +0,0 @@
-CONFIG_MIPS_ALCHEMY=y
-CONFIG_MIPS_DB1235=y
-CONFIG_COMPACTION=y
-CONFIG_KSM=y
-CONFIG_HZ_100=y
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-db1235"
-CONFIG_KERNEL_LZMA=y
-CONFIG_DEFAULT_HOSTNAME="db1235"
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_BSD_PROCESS_ACCT_V3=y
-CONFIG_FHANDLE=y
-CONFIG_TASKSTATS=y
-CONFIG_TASK_DELAY_ACCT=y
-CONFIG_AUDIT=y
-CONFIG_AUDIT_LOGINUID_IMMUTABLE=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_LOG_BUF_SHIFT=16
-CONFIG_NAMESPACES=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_JUMP_LABEL=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_LDM_PARTITION=y
-CONFIG_EFI_PARTITION=y
-CONFIG_PCI=y
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_UNIX_DIAG=y
-CONFIG_XFRM_USER=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_MULTIPATH=y
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-CONFIG_NET_IPIP=y
-CONFIG_NET_IPGRE_DEMUX=y
-CONFIG_NET_IPGRE=y
-CONFIG_NET_IPGRE_BROADCAST=y
-CONFIG_IP_MROUTE=y
-CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
-CONFIG_IP_PIMSM_V1=y
-CONFIG_IP_PIMSM_V2=y
-CONFIG_ARPD=y
-CONFIG_SYN_COOKIES=y
-CONFIG_NET_IPVTI=y
-CONFIG_INET_AH=y
-CONFIG_INET_ESP=y
-CONFIG_INET_IPCOMP=y
-CONFIG_INET_UDP_DIAG=y
-CONFIG_TCP_CONG_ADVANCED=y
-CONFIG_TCP_CONG_HSTCP=y
-CONFIG_TCP_CONG_HYBLA=y
-CONFIG_TCP_CONG_SCALABLE=y
-CONFIG_TCP_CONG_LP=y
-CONFIG_TCP_CONG_VENO=y
-CONFIG_TCP_CONG_YEAH=y
-CONFIG_TCP_CONG_ILLINOIS=y
-CONFIG_DEFAULT_HYBLA=y
-CONFIG_TCP_MD5SIG=y
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
-CONFIG_IPV6_OPTIMISTIC_DAD=y
-CONFIG_INET6_AH=y
-CONFIG_INET6_ESP=y
-CONFIG_INET6_IPCOMP=y
-CONFIG_IPV6_MIP6=y
-CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=y
-CONFIG_IPV6_SIT_6RD=y
-CONFIG_IPV6_TUNNEL=y
-CONFIG_IPV6_MULTIPLE_TABLES=y
-CONFIG_IPV6_SUBTREES=y
-CONFIG_IPV6_MROUTE=y
-CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
-CONFIG_IPV6_PIMSM_V2=y
-CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=y
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CONNTRACK_TIMEOUT=y
-CONFIG_NF_CONNTRACK_TIMESTAMP=y
-CONFIG_NF_CT_PROTO_DCCP=y
-CONFIG_NF_CT_PROTO_SCTP=y
-CONFIG_NF_CT_PROTO_UDPLITE=y
-CONFIG_NF_CONNTRACK_AMANDA=y
-CONFIG_NF_CONNTRACK_FTP=y
-CONFIG_NF_CONNTRACK_H323=y
-CONFIG_NF_CONNTRACK_IRC=y
-CONFIG_NF_CONNTRACK_NETBIOS_NS=y
-CONFIG_NF_CONNTRACK_SNMP=y
-CONFIG_NF_CONNTRACK_PPTP=y
-CONFIG_NF_CONNTRACK_SANE=y
-CONFIG_NF_CONNTRACK_SIP=y
-CONFIG_NF_CONNTRACK_TFTP=y
-CONFIG_NF_CT_NETLINK=y
-CONFIG_NF_CT_NETLINK_TIMEOUT=y
-CONFIG_NF_CT_NETLINK_HELPER=y
-CONFIG_NETFILTER_NETLINK_QUEUE_CT=y
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
-CONFIG_NETFILTER_XT_TARGET_HMARK=y
-CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
-CONFIG_NETFILTER_XT_TARGET_LED=y
-CONFIG_NETFILTER_XT_TARGET_LOG=y
-CONFIG_NETFILTER_XT_TARGET_MARK=y
-CONFIG_NETFILTER_XT_TARGET_NFLOG=y
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
-CONFIG_NETFILTER_XT_TARGET_TEE=y
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
-CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
-CONFIG_NETFILTER_XT_MATCH_CLUSTER=y
-CONFIG_NETFILTER_XT_MATCH_COMMENT=y
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
-CONFIG_NETFILTER_XT_MATCH_CPU=y
-CONFIG_NETFILTER_XT_MATCH_DCCP=y
-CONFIG_NETFILTER_XT_MATCH_DEVGROUP=y
-CONFIG_NETFILTER_XT_MATCH_DSCP=y
-CONFIG_NETFILTER_XT_MATCH_ESP=y
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_HELPER=y
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
-CONFIG_NETFILTER_XT_MATCH_LENGTH=y
-CONFIG_NETFILTER_XT_MATCH_LIMIT=y
-CONFIG_NETFILTER_XT_MATCH_MAC=y
-CONFIG_NETFILTER_XT_MATCH_MARK=y
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
-CONFIG_NETFILTER_XT_MATCH_NFACCT=y
-CONFIG_NETFILTER_XT_MATCH_OSF=y
-CONFIG_NETFILTER_XT_MATCH_OWNER=y
-CONFIG_NETFILTER_XT_MATCH_POLICY=y
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=y
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA=y
-CONFIG_NETFILTER_XT_MATCH_RATEEST=y
-CONFIG_NETFILTER_XT_MATCH_REALM=y
-CONFIG_NETFILTER_XT_MATCH_RECENT=y
-CONFIG_NETFILTER_XT_MATCH_SCTP=y
-CONFIG_NETFILTER_XT_MATCH_STATE=y
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
-CONFIG_NETFILTER_XT_MATCH_STRING=y
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
-CONFIG_NETFILTER_XT_MATCH_TIME=y
-CONFIG_NETFILTER_XT_MATCH_U32=y
-CONFIG_NF_CONNTRACK_IPV4=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_AH=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_RPFILTER=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_TARGET_ULOG=y
-CONFIG_NF_NAT=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_MANGLE=y
-CONFIG_IP_NF_TARGET_CLUSTERIP=y
-CONFIG_IP_NF_TARGET_ECN=y
-CONFIG_IP_NF_TARGET_TTL=y
-CONFIG_IP_NF_RAW=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_NF_CONNTRACK_IPV6=y
-CONFIG_IP6_NF_IPTABLES=y
-CONFIG_IP6_NF_MATCH_AH=y
-CONFIG_IP6_NF_MATCH_EUI64=y
-CONFIG_IP6_NF_MATCH_FRAG=y
-CONFIG_IP6_NF_MATCH_OPTS=y
-CONFIG_IP6_NF_MATCH_HL=y
-CONFIG_IP6_NF_MATCH_IPV6HEADER=y
-CONFIG_IP6_NF_MATCH_MH=y
-CONFIG_IP6_NF_MATCH_RPFILTER=y
-CONFIG_IP6_NF_MATCH_RT=y
-CONFIG_IP6_NF_TARGET_HL=y
-CONFIG_IP6_NF_FILTER=y
-CONFIG_IP6_NF_TARGET_REJECT=y
-CONFIG_IP6_NF_MANGLE=y
-CONFIG_IP6_NF_RAW=y
-CONFIG_BRIDGE_NF_EBTABLES=y
-CONFIG_BRIDGE_EBT_BROUTE=y
-CONFIG_BRIDGE_EBT_T_FILTER=y
-CONFIG_BRIDGE_EBT_T_NAT=y
-CONFIG_BRIDGE_EBT_802_3=y
-CONFIG_BRIDGE_EBT_AMONG=y
-CONFIG_BRIDGE_EBT_ARP=y
-CONFIG_BRIDGE_EBT_IP=y
-CONFIG_BRIDGE_EBT_IP6=y
-CONFIG_BRIDGE_EBT_LIMIT=y
-CONFIG_BRIDGE_EBT_MARK=y
-CONFIG_BRIDGE_EBT_PKTTYPE=y
-CONFIG_BRIDGE_EBT_STP=y
-CONFIG_BRIDGE_EBT_VLAN=y
-CONFIG_BRIDGE_EBT_ARPREPLY=y
-CONFIG_BRIDGE_EBT_DNAT=y
-CONFIG_BRIDGE_EBT_MARK_T=y
-CONFIG_BRIDGE_EBT_REDIRECT=y
-CONFIG_BRIDGE_EBT_SNAT=y
-CONFIG_BRIDGE_EBT_LOG=y
-CONFIG_BRIDGE_EBT_NFLOG=y
-CONFIG_L2TP=y
-CONFIG_L2TP_V3=y
-CONFIG_L2TP_IP=y
-CONFIG_L2TP_ETH=y
-CONFIG_BRIDGE=y
-CONFIG_VLAN_8021Q=y
-CONFIG_VLAN_8021Q_GVRP=y
-CONFIG_LLC2=y
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_CBQ=y
-CONFIG_NET_SCH_HTB=y
-CONFIG_NET_SCH_HFSC=y
-CONFIG_NET_SCH_PRIO=y
-CONFIG_NET_SCH_MULTIQ=y
-CONFIG_NET_SCH_RED=y
-CONFIG_NET_SCH_SFB=y
-CONFIG_NET_SCH_SFQ=y
-CONFIG_NET_SCH_TEQL=y
-CONFIG_NET_SCH_TBF=y
-CONFIG_NET_SCH_GRED=y
-CONFIG_NET_SCH_DSMARK=y
-CONFIG_NET_SCH_NETEM=y
-CONFIG_NET_SCH_DRR=y
-CONFIG_NET_SCH_MQPRIO=y
-CONFIG_NET_SCH_CHOKE=y
-CONFIG_NET_SCH_QFQ=y
-CONFIG_NET_SCH_CODEL=y
-CONFIG_NET_SCH_FQ_CODEL=y
-CONFIG_NET_SCH_INGRESS=y
-CONFIG_NET_SCH_PLUG=y
-CONFIG_NET_CLS_BASIC=y
-CONFIG_NET_CLS_TCINDEX=y
-CONFIG_NET_CLS_ROUTE4=y
-CONFIG_NET_CLS_FW=y
-CONFIG_NET_CLS_U32=y
-CONFIG_CLS_U32_PERF=y
-CONFIG_CLS_U32_MARK=y
-CONFIG_NET_CLS_RSVP=y
-CONFIG_NET_CLS_RSVP6=y
-CONFIG_NET_CLS_FLOW=y
-CONFIG_NET_EMATCH=y
-CONFIG_NET_EMATCH_CMP=y
-CONFIG_NET_EMATCH_NBYTE=y
-CONFIG_NET_EMATCH_U32=y
-CONFIG_NET_EMATCH_META=y
-CONFIG_NET_EMATCH_TEXT=y
-CONFIG_NET_CLS_ACT=y
-CONFIG_NET_ACT_POLICE=y
-CONFIG_NET_ACT_GACT=y
-CONFIG_GACT_PROB=y
-CONFIG_NET_ACT_MIRRED=y
-CONFIG_NET_ACT_NAT=y
-CONFIG_NET_ACT_PEDIT=y
-CONFIG_NET_ACT_SIMP=y
-CONFIG_NET_ACT_SKBEDIT=y
-CONFIG_NET_ACT_CSUM=y
-CONFIG_NET_CLS_IND=y
-CONFIG_BT=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIBTUSB=y
-CONFIG_CFG80211=y
-CONFIG_CFG80211_CERTIFICATION_ONUS=y
-CONFIG_CFG80211_WEXT=y
-CONFIG_MAC80211=y
-CONFIG_MAC80211_LEDS=y
-CONFIG_RFKILL=y
-CONFIG_RFKILL_INPUT=y
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_M25P80=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_PLATFORM=y
-CONFIG_EEPROM_AT24=y
-CONFIG_EEPROM_AT25=y
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE_AU1XXX=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_ATA=y
-CONFIG_PATA_HPT37X=y
-CONFIG_PATA_PCMCIA=y
-CONFIG_PATA_PLATFORM=y
-CONFIG_NETDEVICES=y
-CONFIG_MIPS_AU1X00_ENET=y
-CONFIG_SMC91X=y
-CONFIG_SMSC911X=y
-CONFIG_AMD_PHY=y
-CONFIG_SMSC_PHY=y
-CONFIG_RT2X00=y
-CONFIG_RT73USB=y
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_WM97XX=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_TTY_PRINTK=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_AU1550=y
-CONFIG_SPI=y
-CONFIG_SPI_AU1550=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_SENSORS_ADM1025=y
-CONFIG_SENSORS_LM70=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_HRTIMER=y
-CONFIG_SND_DYNAMIC_MINORS=y
-CONFIG_SND_SOC=y
-CONFIG_SND_SOC_AU1XPSC=y
-CONFIG_SND_SOC_DB1200=y
-CONFIG_HIDRAW=y
-CONFIG_UHID=y
-CONFIG_USB_HIDDEV=y
-CONFIG_USB=y
-CONFIG_USB_DYNAMIC_MINORS=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_HCD_PLATFORM=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PLATFORM=y
-CONFIG_USB_STORAGE=y
-CONFIG_MMC=y
-CONFIG_MMC_AU1X=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AU1XXX=y
-CONFIG_EXT4_FS=y
-CONFIG_EXT4_FS_POSIX_ACL=y
-CONFIG_EXT4_FS_SECURITY=y
-CONFIG_XFS_FS=y
-CONFIG_XFS_POSIX_ACL=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_CONFIGFS_FS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_FS_XATTR=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_LZO=y
-CONFIG_JFFS2_CMODE_FAVOURLZO=y
-CONFIG_SQUASHFS=y
-CONFIG_SQUASHFS_LZO=y
-CONFIG_SQUASHFS_XZ=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFS_V4_1=y
-CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org"
-CONFIG_ROOT_NFS=y
-CONFIG_NFSD=y
-CONFIG_NFSD_V3_ACL=y
-CONFIG_NFSD_V4=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_CODEPAGE_852=y
-CONFIG_NLS_CODEPAGE_1250=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_ISO8859_2=y
-CONFIG_NLS_ISO8859_15=y
-CONFIG_NLS_UTF8=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_STRIP_ASM_SYMS=y
-CONFIG_SECURITYFS=y
-CONFIG_CRYPTO_USER=y
-CONFIG_CRYPTO_NULL=y
-CONFIG_CRYPTO_CRYPTD=y
-CONFIG_CRYPTO_CCM=y
-CONFIG_CRYPTO_GCM=y
-CONFIG_CRYPTO_CTS=y
-CONFIG_CRYPTO_LRW=y
-CONFIG_CRYPTO_PCBC=y
-CONFIG_CRYPTO_XTS=y
-CONFIG_CRYPTO_XCBC=y
-CONFIG_CRYPTO_VMAC=y
-CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_MICHAEL_MIC=y
-CONFIG_CRYPTO_RMD128=y
-CONFIG_CRYPTO_RMD160=y
-CONFIG_CRYPTO_RMD256=y
-CONFIG_CRYPTO_RMD320=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_SHA512=y
-CONFIG_CRYPTO_TGR192=y
-CONFIG_CRYPTO_WP512=y
-CONFIG_CRYPTO_ANUBIS=y
-CONFIG_CRYPTO_BLOWFISH=y
-CONFIG_CRYPTO_CAMELLIA=y
-CONFIG_CRYPTO_CAST5=y
-CONFIG_CRYPTO_CAST6=y
-CONFIG_CRYPTO_FCRYPT=y
-CONFIG_CRYPTO_KHAZAD=y
-CONFIG_CRYPTO_SALSA20=y
-CONFIG_CRYPTO_SEED=y
-CONFIG_CRYPTO_SERPENT=y
-CONFIG_CRYPTO_TEA=y
-CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRYPTO_ZLIB=y
-CONFIG_CRYPTO_LZO=y
-CONFIG_CRYPTO_USER_API_HASH=y
-CONFIG_CRYPTO_USER_API_SKCIPHER=y
diff --git a/arch/mips/configs/db1xxx_defconfig b/arch/mips/configs/db1xxx_defconfig
new file mode 100644
index 000000000000..c99b6eeda90b
--- /dev/null
+++ b/arch/mips/configs/db1xxx_defconfig
@@ -0,0 +1,245 @@
+CONFIG_MIPS_ALCHEMY=y
+CONFIG_MIPS_DB1XXX=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUG=y
+CONFIG_HZ_100=y
+CONFIG_LOCALVERSION="-db1xxx"
+CONFIG_KERNEL_XZ=y
+CONFIG_DEFAULT_HOSTNAME="db1xxx"
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_FHANDLE=y
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_MEMCG_KMEM=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_BLK_DEV_BSGLIB=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_DEFAULT_NOOP=y
+CONFIG_PCI=y
+CONFIG_PCI_REALLOC_ENABLE_AUTO=y
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_PACKET_DIAG=y
+CONFIG_UNIX=y
+CONFIG_UNIX_DIAG=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_FIB_TRIE_STATS=y
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE_DEMUX=y
+CONFIG_NET_IPGRE=y
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_UDP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_VENO=y
+CONFIG_DEFAULT_VENO=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=y
+CONFIG_IPV6_VTI=y
+CONFIG_IPV6_SIT_6RD=y
+CONFIG_IPV6_GRE=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_BRIDGE=y
+CONFIG_NETLINK_MMAP=y
+CONFIG_NETLINK_DIAG=y
+CONFIG_IRDA=y
+CONFIG_IRLAN=y
+CONFIG_IRCOMM=y
+CONFIG_IRDA_ULTRA=y
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_AU1000_FIR=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIBTUSB=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=y
+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_ADV_OPTIONS=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_SST25L=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ECC_BCH=y
+CONFIG_MTD_NAND_AU1550=y
+CONFIG_MTD_NAND_PLATFORM=y
+CONFIG_EEPROM_AT24=y
+CONFIG_EEPROM_AT25=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_ATA=y
+CONFIG_PATA_HPT37X=y
+CONFIG_PATA_HPT3X2N=y
+CONFIG_PATA_PCMCIA=y
+CONFIG_PATA_PLATFORM=y
+CONFIG_NETDEVICES=y
+CONFIG_NLMON=y
+CONFIG_PCMCIA_3C589=y
+CONFIG_MIPS_AU1X00_ENET=y
+CONFIG_SMC91X=y
+CONFIG_SMSC911X=y
+CONFIG_AMD_PHY=y
+CONFIG_SMSC_PHY=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+CONFIG_TOUCHSCREEN_WM97XX=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_TTY_PRINTK=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_AU1550=y
+CONFIG_SPI=y
+CONFIG_SPI_AU1550=y
+CONFIG_SPI_GPIO=y
+CONFIG_SENSORS_ADM1025=y
+CONFIG_SENSORS_LM70=y
+CONFIG_FB=y
+CONFIG_FB_AU1100=y
+CONFIG_FB_AU1200=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SEQUENCER=y
+CONFIG_SND_HRTIMER=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_AC97_POWER_SAVE=y
+CONFIG_SND_AC97_POWER_SAVE_DEFAULT=1
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_AU1XPSC=y
+CONFIG_SND_SOC_AU1XAUDIO=y
+CONFIG_SND_SOC_DB1000=y
+CONFIG_SND_SOC_DB1200=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_LOGITECH_DJ=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_OTG=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_MMC=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_SDIO_UART=y
+CONFIG_MMC_AU1X=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_AU1XXX=y
+CONFIG_FIRMWARE_MEMMAP=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_XFS_FS=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_FANOTIFY=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_FILE_DIRECT=y
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="local"
+CONFIG_NFS_V4_1_MIGRATION=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_UTF8=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_SECURITYFS=y
+CONFIG_CRYPTO_USER=y
+CONFIG_CRYPTO_CRYPTD=y
+CONFIG_CRYPTO_USER_API_HASH=y
+CONFIG_CRYPTO_USER_API_SKCIPHER=y
+CONFIG_CRC32_SLICEBY4=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
diff --git a/arch/mips/configs/loongson3_defconfig b/arch/mips/configs/loongson3_defconfig
new file mode 100644
index 000000000000..ea1761f0f917
--- /dev/null
+++ b/arch/mips/configs/loongson3_defconfig
@@ -0,0 +1,362 @@
+CONFIG_MACH_LOONGSON=y
+CONFIG_SWIOTLB=y
+CONFIG_LEMOTE_MACH3A=y
+CONFIG_CPU_LOONGSON3=y
+CONFIG_64BIT=y
+CONFIG_PAGE_SIZE_16KB=y
+CONFIG_KSM=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HZ_256=y
+CONFIG_PREEMPT=y
+CONFIG_KEXEC=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CPUSETS=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_BLK_CGROUP=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_IOSCHED_DEADLINE=m
+CONFIG_CFQ_GROUP_IOSCHED=y
+CONFIG_PCI=y
+CONFIG_HT_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_HOTPLUG_PCI_PCIE=y
+# CONFIG_PCIEAER is not set
+CONFIG_PCIEASPM_PERFORMANCE=y
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_SHPC=m
+CONFIG_BINFMT_MISC=m
+CONFIG_MIPS32_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_IP_VS=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_SCTP=m
+CONFIG_L2TP=m
+CONFIG_BRIDGE=m
+CONFIG_CFG80211=m
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=m
+CONFIG_RFKILL=m
+CONFIG_RFKILL_INPUT=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_MTD=m
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_ISCSI_TCP=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_MM=y
+CONFIG_MEGARAID_MAILBOX=y
+CONFIG_MEGARAID_LEGACY=y
+CONFIG_MEGARAID_SAS=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI=y
+CONFIG_PATA_ATIIXP=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_TARGET_CORE=m
+CONFIG_TCM_IBLOCK=m
+CONFIG_TCM_FILEIO=m
+CONFIG_TCM_PSCSI=m
+CONFIG_LOOPBACK_TARGET=m
+CONFIG_ISCSI_TARGET=m
+CONFIG_NETDEVICES=y
+CONFIG_TUN=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_HP is not set
+CONFIG_E1000=y
+CONFIG_E1000E=y
+CONFIG_IGB=y
+CONFIG_IXGB=y
+CONFIG_IXGBE=y
+# CONFIG_NET_VENDOR_I825XX is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+CONFIG_R8169=y
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_TOSHIBA is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_ATH_CARDS=m
+CONFIG_ATH9K=m
+CONFIG_HOSTAP=m
+CONFIG_INPUT_POLLDEV=m
+CONFIG_INPUT_SPARSEKMAP=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_XTKBD=m
+CONFIG_MOUSE_PS2_SENTELIC=y
+CONFIG_MOUSE_SERIAL=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_RAW=m
+CONFIG_LEGACY_PTY_COUNT=16
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=16
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_HW_RANDOM=y
+CONFIG_RAW_DRIVER=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PIIX4=y
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM93=m
+CONFIG_SENSORS_W83627HF=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_DRM=y
+CONFIG_DRM_RADEON=y
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB_RADEON=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=m
+CONFIG_BACKLIGHT_GENERIC=m
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+# CONFIG_SND_ISA is not set
+CONFIG_SND_HDA_INTEL=m
+CONFIG_SND_HDA_PATCH_LOADER=y
+CONFIG_SND_HDA_CODEC_REALTEK=m
+CONFIG_SND_HDA_CODEC_CONEXANT=m
+# CONFIG_SND_USB is not set
+CONFIG_HID_A4TECH=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_USB=y
+CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=m
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_CMOS=y
+CONFIG_DMADEVICES=y
+CONFIG_PM_DEVFREQ=y
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
+CONFIG_DEVFREQ_GOV_PERFORMANCE=y
+CONFIG_DEVFREQ_GOV_POWERSAVE=y
+CONFIG_DEVFREQ_GOV_USERSPACE=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_QUOTA=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=936
+CONFIG_FAT_DEFAULT_IOCHARSET="gb2312"
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=m
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_FRAME_WARN=1024
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_RCU_CPU_STALL_VERBOSE is not set
+# CONFIG_FTRACE is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_PATH=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_DEFLATE=m
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig
index ce1d3eeeb737..b745b6a9f322 100644
--- a/arch/mips/configs/malta_defconfig
+++ b/arch/mips/configs/malta_defconfig
@@ -1,7 +1,9 @@
CONFIG_MIPS_MALTA=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y
+CONFIG_PAGE_SIZE_16KB=y
CONFIG_MIPS_MT_SMP=y
+CONFIG_NR_CPUS=8
CONFIG_HZ_100=y
CONFIG_SYSVIPC=y
CONFIG_NO_HZ=y
@@ -42,7 +44,6 @@ CONFIG_INET_IPCOMP=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
CONFIG_TCP_MD5SIG=y
-CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
@@ -68,7 +69,6 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_TPROXY=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
@@ -125,7 +125,6 @@ CONFIG_IP_VS_SH=m
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
@@ -185,7 +184,6 @@ CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
CONFIG_PHONET=m
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
@@ -226,9 +224,9 @@ CONFIG_MAC80211_RC_DEFAULT_PID=y
CONFIG_MAC80211_MESH=y
CONFIG_RFKILL=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
CONFIG_CONNECTOR=m
CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_OOPS=m
CONFIG_MTD_CFI=y
@@ -328,7 +326,6 @@ CONFIG_LIBERTAS=m
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO_I8042 is not set
-CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_HWMON is not set
diff --git a/arch/mips/configs/malta_kvm_defconfig b/arch/mips/configs/malta_kvm_defconfig
index 341bb47204d6..4f7d952d8517 100644
--- a/arch/mips/configs/malta_kvm_defconfig
+++ b/arch/mips/configs/malta_kvm_defconfig
@@ -3,6 +3,7 @@ CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y
CONFIG_PAGE_SIZE_16KB=y
CONFIG_MIPS_MT_SMP=y
+CONFIG_NR_CPUS=8
CONFIG_HZ_100=y
CONFIG_SYSVIPC=y
CONFIG_NO_HZ=y
@@ -44,7 +45,6 @@ CONFIG_INET_IPCOMP=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
CONFIG_TCP_MD5SIG=y
-CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
@@ -70,7 +70,6 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_TPROXY=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
@@ -127,7 +126,6 @@ CONFIG_IP_VS_SH=m
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
@@ -187,7 +185,6 @@ CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
CONFIG_PHONET=m
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
@@ -228,9 +225,9 @@ CONFIG_MAC80211_RC_DEFAULT_PID=y
CONFIG_MAC80211_MESH=y
CONFIG_RFKILL=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
CONFIG_CONNECTOR=m
CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_OOPS=m
CONFIG_MTD_CFI=y
@@ -300,6 +297,7 @@ CONFIG_IFB=m
CONFIG_MACVLAN=m
CONFIG_TUN=m
CONFIG_VETH=m
+CONFIG_VHOST_NET=m
CONFIG_PCNET32=y
CONFIG_CHELSIO_T3=m
CONFIG_AX88796=m
@@ -329,7 +327,6 @@ CONFIG_LIBERTAS=m
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO_I8042 is not set
-CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_HWMON is not set
@@ -453,4 +450,3 @@ CONFIG_VIRTUALIZATION=y
CONFIG_KVM=m
CONFIG_KVM_MIPS_DYN_TRANS=y
CONFIG_KVM_MIPS_DEBUG_COP0_COUNTERS=y
-CONFIG_VHOST_NET=m
diff --git a/arch/mips/configs/malta_kvm_guest_defconfig b/arch/mips/configs/malta_kvm_guest_defconfig
index 2b8558b71080..e36681c24ddc 100644
--- a/arch/mips/configs/malta_kvm_guest_defconfig
+++ b/arch/mips/configs/malta_kvm_guest_defconfig
@@ -44,7 +44,6 @@ CONFIG_INET_IPCOMP=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
CONFIG_TCP_MD5SIG=y
-CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
@@ -70,7 +69,6 @@ CONFIG_NF_CONNTRACK_SANE=m
CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_TPROXY=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
@@ -127,7 +125,6 @@ CONFIG_IP_VS_SH=m
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
@@ -187,7 +184,6 @@ CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
CONFIG_PHONET=m
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
@@ -228,9 +224,9 @@ CONFIG_MAC80211_RC_DEFAULT_PID=y
CONFIG_MAC80211_MESH=y
CONFIG_RFKILL=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
CONFIG_CONNECTOR=m
CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_OOPS=m
CONFIG_MTD_CFI=y
@@ -331,7 +327,6 @@ CONFIG_LIBERTAS=m
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO_I8042 is not set
-CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_HWMON is not set
diff --git a/arch/mips/configs/maltaaprp_defconfig b/arch/mips/configs/maltaaprp_defconfig
index 93057a760dfa..fb042ce86b4b 100644
--- a/arch/mips/configs/maltaaprp_defconfig
+++ b/arch/mips/configs/maltaaprp_defconfig
@@ -44,7 +44,6 @@ CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_INET_LRO is not set
-CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
@@ -55,7 +54,6 @@ CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
@@ -80,6 +78,7 @@ CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_CLS_IND=y
# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_IDE=y
diff --git a/arch/mips/configs/maltasmtc_defconfig b/arch/mips/configs/maltasmtc_defconfig
index 4e54b75d89be..eb316447588c 100644
--- a/arch/mips/configs/maltasmtc_defconfig
+++ b/arch/mips/configs/maltasmtc_defconfig
@@ -1,6 +1,7 @@
CONFIG_MIPS_MALTA=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y
+CONFIG_PAGE_SIZE_16KB=y
CONFIG_MIPS_MT_SMTC=y
# CONFIG_MIPS_MT_FPAFF is not set
CONFIG_NR_CPUS=9
@@ -45,7 +46,6 @@ CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_INET_LRO is not set
-CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
@@ -56,7 +56,6 @@ CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
@@ -81,6 +80,7 @@ CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_CLS_IND=y
# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_IDE=y
diff --git a/arch/mips/configs/maltasmvp_defconfig b/arch/mips/configs/maltasmvp_defconfig
index d75931850392..10ef3bed5f43 100644
--- a/arch/mips/configs/maltasmvp_defconfig
+++ b/arch/mips/configs/maltasmvp_defconfig
@@ -1,10 +1,11 @@
CONFIG_MIPS_MALTA=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R2=y
+CONFIG_PAGE_SIZE_16KB=y
CONFIG_MIPS_MT_SMP=y
CONFIG_SCHED_SMT=y
CONFIG_MIPS_CMP=y
-CONFIG_NR_CPUS=2
+CONFIG_NR_CPUS=8
CONFIG_HZ_100=y
CONFIG_LOCALVERSION="cmp"
CONFIG_SYSVIPC=y
@@ -47,7 +48,6 @@ CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_INET_LRO is not set
-CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
@@ -82,6 +82,7 @@ CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_CLS_IND=y
# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_IDE=y
diff --git a/arch/mips/configs/maltasmvp_eva_defconfig b/arch/mips/configs/maltasmvp_eva_defconfig
new file mode 100644
index 000000000000..2d3002cba102
--- /dev/null
+++ b/arch/mips/configs/maltasmvp_eva_defconfig
@@ -0,0 +1,200 @@
+CONFIG_MIPS_MALTA=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPS32_3_5_FEATURES=y
+CONFIG_PAGE_SIZE_16KB=y
+CONFIG_MIPS_MT_SMP=y
+CONFIG_SCHED_SMT=y
+CONFIG_MIPS_CMP=y
+CONFIG_NR_CPUS=8
+CONFIG_HZ_100=y
+CONFIG_LOCALVERSION="cmp"
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PCI=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_NET_IPIP=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+# CONFIG_INET_LRO is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_CLS_IND=y
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_IDE=y
+# CONFIG_IDE_PROC_FS is not set
+# CONFIG_IDEPCI_PCIBUS_ORDER is not set
+CONFIG_BLK_DEV_GENERIC=y
+CONFIG_BLK_DEV_PIIX=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+CONFIG_PCNET32=y
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_HP is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_TOSHIBA is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_WLAN is not set
+# CONFIG_VT is not set
+CONFIG_LEGACY_PTY_COUNT=4
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_HW_RANDOM=y
+# CONFIG_HWMON is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_G=y
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_IDE_DISK=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_CMOS=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_XFS_FS=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V2=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_CIFS=m
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_FTRACE is not set
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
diff --git a/arch/mips/configs/maltaup_defconfig b/arch/mips/configs/maltaup_defconfig
index 9868fc9c1133..62344648eb7a 100644
--- a/arch/mips/configs/maltaup_defconfig
+++ b/arch/mips/configs/maltaup_defconfig
@@ -43,7 +43,6 @@ CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_INET_LRO is not set
-CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
@@ -54,7 +53,6 @@ CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
@@ -79,6 +77,7 @@ CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_CLS_IND=y
# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_IDE=y
diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild
index 2d7f65052c1f..05439187891d 100644
--- a/arch/mips/include/asm/Kbuild
+++ b/arch/mips/include/asm/Kbuild
@@ -2,16 +2,17 @@
generic-y += cputime.h
generic-y += current.h
generic-y += emergency-restart.h
+generic-y += hash.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += mutex.h
generic-y += parport.h
generic-y += percpu.h
+generic-y += preempt.h
generic-y += scatterlist.h
generic-y += sections.h
generic-y += segment.h
generic-y += serial.h
generic-y += trace_clock.h
-generic-y += preempt.h
generic-y += ucontext.h
generic-y += xor.h
-generic-y += hash.h
diff --git a/arch/mips/include/asm/asm-eva.h b/arch/mips/include/asm/asm-eva.h
new file mode 100644
index 000000000000..e41c56e375b1
--- /dev/null
+++ b/arch/mips/include/asm/asm-eva.h
@@ -0,0 +1,135 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2014 Imagination Technologies Ltd.
+ *
+ */
+
+#ifndef __ASM_ASM_EVA_H
+#define __ASM_ASM_EVA_H
+
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_EVA
+
+#define __BUILD_EVA_INSN(insn, reg, addr) \
+ " .set push\n" \
+ " .set mips0\n" \
+ " .set eva\n" \
+ " "insn" "reg", "addr "\n" \
+ " .set pop\n"
+
+#define user_cache(op, base) __BUILD_EVA_INSN("cachee", op, base)
+#define user_ll(reg, addr) __BUILD_EVA_INSN("lle", reg, addr)
+#define user_sc(reg, addr) __BUILD_EVA_INSN("sce", reg, addr)
+#define user_lw(reg, addr) __BUILD_EVA_INSN("lwe", reg, addr)
+#define user_lwl(reg, addr) __BUILD_EVA_INSN("lwle", reg, addr)
+#define user_lwr(reg, addr) __BUILD_EVA_INSN("lwre", reg, addr)
+#define user_lh(reg, addr) __BUILD_EVA_INSN("lhe", reg, addr)
+#define user_lb(reg, addr) __BUILD_EVA_INSN("lbe", reg, addr)
+#define user_lbu(reg, addr) __BUILD_EVA_INSN("lbue", reg, addr)
+/* No 64-bit EVA instruction for loading double words */
+#define user_ld(reg, addr) user_lw(reg, addr)
+#define user_sw(reg, addr) __BUILD_EVA_INSN("swe", reg, addr)
+#define user_swl(reg, addr) __BUILD_EVA_INSN("swle", reg, addr)
+#define user_swr(reg, addr) __BUILD_EVA_INSN("swre", reg, addr)
+#define user_sh(reg, addr) __BUILD_EVA_INSN("she", reg, addr)
+#define user_sb(reg, addr) __BUILD_EVA_INSN("sbe", reg, addr)
+/* No 64-bit EVA instruction for storing double words */
+#define user_sd(reg, addr) user_sw(reg, addr)
+
+#else
+
+#define user_cache(op, base) "cache " op ", " base "\n"
+#define user_ll(reg, addr) "ll " reg ", " addr "\n"
+#define user_sc(reg, addr) "sc " reg ", " addr "\n"
+#define user_lw(reg, addr) "lw " reg ", " addr "\n"
+#define user_lwl(reg, addr) "lwl " reg ", " addr "\n"
+#define user_lwr(reg, addr) "lwr " reg ", " addr "\n"
+#define user_lh(reg, addr) "lh " reg ", " addr "\n"
+#define user_lb(reg, addr) "lb " reg ", " addr "\n"
+#define user_lbu(reg, addr) "lbu " reg ", " addr "\n"
+#define user_sw(reg, addr) "sw " reg ", " addr "\n"
+#define user_swl(reg, addr) "swl " reg ", " addr "\n"
+#define user_swr(reg, addr) "swr " reg ", " addr "\n"
+#define user_sh(reg, addr) "sh " reg ", " addr "\n"
+#define user_sb(reg, addr) "sb " reg ", " addr "\n"
+
+#ifdef CONFIG_32BIT
+/*
+ * No 'sd' or 'ld' instructions in 32-bit but the code will
+ * do the correct thing
+ */
+#define user_sd(reg, addr) user_sw(reg, addr)
+#define user_ld(reg, addr) user_lw(reg, addr)
+#else
+#define user_sd(reg, addr) "sd " reg", " addr "\n"
+#define user_ld(reg, addr) "ld " reg", " addr "\n"
+#endif /* CONFIG_32BIT */
+
+#endif /* CONFIG_EVA */
+
+#else /* __ASSEMBLY__ */
+
+#ifdef CONFIG_EVA
+
+#define __BUILD_EVA_INSN(insn, reg, addr) \
+ .set push; \
+ .set mips0; \
+ .set eva; \
+ insn reg, addr; \
+ .set pop;
+
+#define user_cache(op, base) __BUILD_EVA_INSN(cachee, op, base)
+#define user_ll(reg, addr) __BUILD_EVA_INSN(lle, reg, addr)
+#define user_sc(reg, addr) __BUILD_EVA_INSN(sce, reg, addr)
+#define user_lw(reg, addr) __BUILD_EVA_INSN(lwe, reg, addr)
+#define user_lwl(reg, addr) __BUILD_EVA_INSN(lwle, reg, addr)
+#define user_lwr(reg, addr) __BUILD_EVA_INSN(lwre, reg, addr)
+#define user_lh(reg, addr) __BUILD_EVA_INSN(lhe, reg, addr)
+#define user_lb(reg, addr) __BUILD_EVA_INSN(lbe, reg, addr)
+#define user_lbu(reg, addr) __BUILD_EVA_INSN(lbue, reg, addr)
+/* No 64-bit EVA instruction for loading double words */
+#define user_ld(reg, addr) user_lw(reg, addr)
+#define user_sw(reg, addr) __BUILD_EVA_INSN(swe, reg, addr)
+#define user_swl(reg, addr) __BUILD_EVA_INSN(swle, reg, addr)
+#define user_swr(reg, addr) __BUILD_EVA_INSN(swre, reg, addr)
+#define user_sh(reg, addr) __BUILD_EVA_INSN(she, reg, addr)
+#define user_sb(reg, addr) __BUILD_EVA_INSN(sbe, reg, addr)
+/* No 64-bit EVA instruction for loading double words */
+#define user_sd(reg, addr) user_sw(reg, addr)
+#else
+
+#define user_cache(op, base) cache op, base
+#define user_ll(reg, addr) ll reg, addr
+#define user_sc(reg, addr) sc reg, addr
+#define user_lw(reg, addr) lw reg, addr
+#define user_lwl(reg, addr) lwl reg, addr
+#define user_lwr(reg, addr) lwr reg, addr
+#define user_lh(reg, addr) lh reg, addr
+#define user_lb(reg, addr) lb reg, addr
+#define user_lbu(reg, addr) lbu reg, addr
+#define user_sw(reg, addr) sw reg, addr
+#define user_swl(reg, addr) swl reg, addr
+#define user_swr(reg, addr) swr reg, addr
+#define user_sh(reg, addr) sh reg, addr
+#define user_sb(reg, addr) sb reg, addr
+
+#ifdef CONFIG_32BIT
+/*
+ * No 'sd' or 'ld' instructions in 32-bit but the code will
+ * do the correct thing
+ */
+#define user_sd(reg, addr) user_sw(reg, addr)
+#define user_ld(reg, addr) user_lw(reg, addr)
+#else
+#define user_sd(reg, addr) sd reg, addr
+#define user_ld(reg, addr) ld reg, addr
+#endif /* CONFIG_32BIT */
+
+#endif /* CONFIG_EVA */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_ASM_EVA_H */
diff --git a/arch/mips/include/asm/asm.h b/arch/mips/include/asm/asm.h
index 879691d194af..7c26b28bf252 100644
--- a/arch/mips/include/asm/asm.h
+++ b/arch/mips/include/asm/asm.h
@@ -18,6 +18,7 @@
#define __ASM_ASM_H
#include <asm/sgidefs.h>
+#include <asm/asm-eva.h>
#ifndef CAT
#ifdef __STDC__
@@ -145,19 +146,27 @@ symbol = value
#define PREF(hint,addr) \
.set push; \
- .set mips4; \
+ .set arch=r5000; \
pref hint, addr; \
.set pop
+#define PREFE(hint, addr) \
+ .set push; \
+ .set mips0; \
+ .set eva; \
+ prefe hint, addr; \
+ .set pop
+
#define PREFX(hint,addr) \
.set push; \
- .set mips4; \
+ .set arch=r5000; \
prefx hint, addr; \
.set pop
#else /* !CONFIG_CPU_HAS_PREFETCH */
#define PREF(hint, addr)
+#define PREFE(hint, addr)
#define PREFX(hint, addr)
#endif /* !CONFIG_CPU_HAS_PREFETCH */
diff --git a/arch/mips/include/asm/asmmacro-32.h b/arch/mips/include/asm/asmmacro-32.h
index 70e1f176f123..e38c2811d4e2 100644
--- a/arch/mips/include/asm/asmmacro-32.h
+++ b/arch/mips/include/asm/asmmacro-32.h
@@ -14,75 +14,75 @@
.macro fpu_save_single thread tmp=t0
cfc1 \tmp, fcr31
- swc1 $f0, THREAD_FPR0(\thread)
- swc1 $f1, THREAD_FPR1(\thread)
- swc1 $f2, THREAD_FPR2(\thread)
- swc1 $f3, THREAD_FPR3(\thread)
- swc1 $f4, THREAD_FPR4(\thread)
- swc1 $f5, THREAD_FPR5(\thread)
- swc1 $f6, THREAD_FPR6(\thread)
- swc1 $f7, THREAD_FPR7(\thread)
- swc1 $f8, THREAD_FPR8(\thread)
- swc1 $f9, THREAD_FPR9(\thread)
- swc1 $f10, THREAD_FPR10(\thread)
- swc1 $f11, THREAD_FPR11(\thread)
- swc1 $f12, THREAD_FPR12(\thread)
- swc1 $f13, THREAD_FPR13(\thread)
- swc1 $f14, THREAD_FPR14(\thread)
- swc1 $f15, THREAD_FPR15(\thread)
- swc1 $f16, THREAD_FPR16(\thread)
- swc1 $f17, THREAD_FPR17(\thread)
- swc1 $f18, THREAD_FPR18(\thread)
- swc1 $f19, THREAD_FPR19(\thread)
- swc1 $f20, THREAD_FPR20(\thread)
- swc1 $f21, THREAD_FPR21(\thread)
- swc1 $f22, THREAD_FPR22(\thread)
- swc1 $f23, THREAD_FPR23(\thread)
- swc1 $f24, THREAD_FPR24(\thread)
- swc1 $f25, THREAD_FPR25(\thread)
- swc1 $f26, THREAD_FPR26(\thread)
- swc1 $f27, THREAD_FPR27(\thread)
- swc1 $f28, THREAD_FPR28(\thread)
- swc1 $f29, THREAD_FPR29(\thread)
- swc1 $f30, THREAD_FPR30(\thread)
- swc1 $f31, THREAD_FPR31(\thread)
+ swc1 $f0, THREAD_FPR0_LS64(\thread)
+ swc1 $f1, THREAD_FPR1_LS64(\thread)
+ swc1 $f2, THREAD_FPR2_LS64(\thread)
+ swc1 $f3, THREAD_FPR3_LS64(\thread)
+ swc1 $f4, THREAD_FPR4_LS64(\thread)
+ swc1 $f5, THREAD_FPR5_LS64(\thread)
+ swc1 $f6, THREAD_FPR6_LS64(\thread)
+ swc1 $f7, THREAD_FPR7_LS64(\thread)
+ swc1 $f8, THREAD_FPR8_LS64(\thread)
+ swc1 $f9, THREAD_FPR9_LS64(\thread)
+ swc1 $f10, THREAD_FPR10_LS64(\thread)
+ swc1 $f11, THREAD_FPR11_LS64(\thread)
+ swc1 $f12, THREAD_FPR12_LS64(\thread)
+ swc1 $f13, THREAD_FPR13_LS64(\thread)
+ swc1 $f14, THREAD_FPR14_LS64(\thread)
+ swc1 $f15, THREAD_FPR15_LS64(\thread)
+ swc1 $f16, THREAD_FPR16_LS64(\thread)
+ swc1 $f17, THREAD_FPR17_LS64(\thread)
+ swc1 $f18, THREAD_FPR18_LS64(\thread)
+ swc1 $f19, THREAD_FPR19_LS64(\thread)
+ swc1 $f20, THREAD_FPR20_LS64(\thread)
+ swc1 $f21, THREAD_FPR21_LS64(\thread)
+ swc1 $f22, THREAD_FPR22_LS64(\thread)
+ swc1 $f23, THREAD_FPR23_LS64(\thread)
+ swc1 $f24, THREAD_FPR24_LS64(\thread)
+ swc1 $f25, THREAD_FPR25_LS64(\thread)
+ swc1 $f26, THREAD_FPR26_LS64(\thread)
+ swc1 $f27, THREAD_FPR27_LS64(\thread)
+ swc1 $f28, THREAD_FPR28_LS64(\thread)
+ swc1 $f29, THREAD_FPR29_LS64(\thread)
+ swc1 $f30, THREAD_FPR30_LS64(\thread)
+ swc1 $f31, THREAD_FPR31_LS64(\thread)
sw \tmp, THREAD_FCR31(\thread)
.endm
.macro fpu_restore_single thread tmp=t0
lw \tmp, THREAD_FCR31(\thread)
- lwc1 $f0, THREAD_FPR0(\thread)
- lwc1 $f1, THREAD_FPR1(\thread)
- lwc1 $f2, THREAD_FPR2(\thread)
- lwc1 $f3, THREAD_FPR3(\thread)
- lwc1 $f4, THREAD_FPR4(\thread)
- lwc1 $f5, THREAD_FPR5(\thread)
- lwc1 $f6, THREAD_FPR6(\thread)
- lwc1 $f7, THREAD_FPR7(\thread)
- lwc1 $f8, THREAD_FPR8(\thread)
- lwc1 $f9, THREAD_FPR9(\thread)
- lwc1 $f10, THREAD_FPR10(\thread)
- lwc1 $f11, THREAD_FPR11(\thread)
- lwc1 $f12, THREAD_FPR12(\thread)
- lwc1 $f13, THREAD_FPR13(\thread)
- lwc1 $f14, THREAD_FPR14(\thread)
- lwc1 $f15, THREAD_FPR15(\thread)
- lwc1 $f16, THREAD_FPR16(\thread)
- lwc1 $f17, THREAD_FPR17(\thread)
- lwc1 $f18, THREAD_FPR18(\thread)
- lwc1 $f19, THREAD_FPR19(\thread)
- lwc1 $f20, THREAD_FPR20(\thread)
- lwc1 $f21, THREAD_FPR21(\thread)
- lwc1 $f22, THREAD_FPR22(\thread)
- lwc1 $f23, THREAD_FPR23(\thread)
- lwc1 $f24, THREAD_FPR24(\thread)
- lwc1 $f25, THREAD_FPR25(\thread)
- lwc1 $f26, THREAD_FPR26(\thread)
- lwc1 $f27, THREAD_FPR27(\thread)
- lwc1 $f28, THREAD_FPR28(\thread)
- lwc1 $f29, THREAD_FPR29(\thread)
- lwc1 $f30, THREAD_FPR30(\thread)
- lwc1 $f31, THREAD_FPR31(\thread)
+ lwc1 $f0, THREAD_FPR0_LS64(\thread)
+ lwc1 $f1, THREAD_FPR1_LS64(\thread)
+ lwc1 $f2, THREAD_FPR2_LS64(\thread)
+ lwc1 $f3, THREAD_FPR3_LS64(\thread)
+ lwc1 $f4, THREAD_FPR4_LS64(\thread)
+ lwc1 $f5, THREAD_FPR5_LS64(\thread)
+ lwc1 $f6, THREAD_FPR6_LS64(\thread)
+ lwc1 $f7, THREAD_FPR7_LS64(\thread)
+ lwc1 $f8, THREAD_FPR8_LS64(\thread)
+ lwc1 $f9, THREAD_FPR9_LS64(\thread)
+ lwc1 $f10, THREAD_FPR10_LS64(\thread)
+ lwc1 $f11, THREAD_FPR11_LS64(\thread)
+ lwc1 $f12, THREAD_FPR12_LS64(\thread)
+ lwc1 $f13, THREAD_FPR13_LS64(\thread)
+ lwc1 $f14, THREAD_FPR14_LS64(\thread)
+ lwc1 $f15, THREAD_FPR15_LS64(\thread)
+ lwc1 $f16, THREAD_FPR16_LS64(\thread)
+ lwc1 $f17, THREAD_FPR17_LS64(\thread)
+ lwc1 $f18, THREAD_FPR18_LS64(\thread)
+ lwc1 $f19, THREAD_FPR19_LS64(\thread)
+ lwc1 $f20, THREAD_FPR20_LS64(\thread)
+ lwc1 $f21, THREAD_FPR21_LS64(\thread)
+ lwc1 $f22, THREAD_FPR22_LS64(\thread)
+ lwc1 $f23, THREAD_FPR23_LS64(\thread)
+ lwc1 $f24, THREAD_FPR24_LS64(\thread)
+ lwc1 $f25, THREAD_FPR25_LS64(\thread)
+ lwc1 $f26, THREAD_FPR26_LS64(\thread)
+ lwc1 $f27, THREAD_FPR27_LS64(\thread)
+ lwc1 $f28, THREAD_FPR28_LS64(\thread)
+ lwc1 $f29, THREAD_FPR29_LS64(\thread)
+ lwc1 $f30, THREAD_FPR30_LS64(\thread)
+ lwc1 $f31, THREAD_FPR31_LS64(\thread)
ctc1 \tmp, fcr31
.endm
diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h
index 3220c93ea981..b464b8b1147a 100644
--- a/arch/mips/include/asm/asmmacro.h
+++ b/arch/mips/include/asm/asmmacro.h
@@ -9,6 +9,7 @@
#define _ASM_ASMMACRO_H
#include <asm/hazards.h>
+#include <asm/asm-offsets.h>
#ifdef CONFIG_32BIT
#include <asm/asmmacro-32.h>
@@ -54,59 +55,69 @@
.endm
.macro local_irq_disable reg=t0
+#ifdef CONFIG_PREEMPT
+ lw \reg, TI_PRE_COUNT($28)
+ addi \reg, \reg, 1
+ sw \reg, TI_PRE_COUNT($28)
+#endif
mfc0 \reg, CP0_STATUS
ori \reg, \reg, 1
xori \reg, \reg, 1
mtc0 \reg, CP0_STATUS
irq_disable_hazard
+#ifdef CONFIG_PREEMPT
+ lw \reg, TI_PRE_COUNT($28)
+ addi \reg, \reg, -1
+ sw \reg, TI_PRE_COUNT($28)
+#endif
.endm
#endif /* CONFIG_MIPS_MT_SMTC */
.macro fpu_save_16even thread tmp=t0
cfc1 \tmp, fcr31
- sdc1 $f0, THREAD_FPR0(\thread)
- sdc1 $f2, THREAD_FPR2(\thread)
- sdc1 $f4, THREAD_FPR4(\thread)
- sdc1 $f6, THREAD_FPR6(\thread)
- sdc1 $f8, THREAD_FPR8(\thread)
- sdc1 $f10, THREAD_FPR10(\thread)
- sdc1 $f12, THREAD_FPR12(\thread)
- sdc1 $f14, THREAD_FPR14(\thread)
- sdc1 $f16, THREAD_FPR16(\thread)
- sdc1 $f18, THREAD_FPR18(\thread)
- sdc1 $f20, THREAD_FPR20(\thread)
- sdc1 $f22, THREAD_FPR22(\thread)
- sdc1 $f24, THREAD_FPR24(\thread)
- sdc1 $f26, THREAD_FPR26(\thread)
- sdc1 $f28, THREAD_FPR28(\thread)
- sdc1 $f30, THREAD_FPR30(\thread)
+ sdc1 $f0, THREAD_FPR0_LS64(\thread)
+ sdc1 $f2, THREAD_FPR2_LS64(\thread)
+ sdc1 $f4, THREAD_FPR4_LS64(\thread)
+ sdc1 $f6, THREAD_FPR6_LS64(\thread)
+ sdc1 $f8, THREAD_FPR8_LS64(\thread)
+ sdc1 $f10, THREAD_FPR10_LS64(\thread)
+ sdc1 $f12, THREAD_FPR12_LS64(\thread)
+ sdc1 $f14, THREAD_FPR14_LS64(\thread)
+ sdc1 $f16, THREAD_FPR16_LS64(\thread)
+ sdc1 $f18, THREAD_FPR18_LS64(\thread)
+ sdc1 $f20, THREAD_FPR20_LS64(\thread)
+ sdc1 $f22, THREAD_FPR22_LS64(\thread)
+ sdc1 $f24, THREAD_FPR24_LS64(\thread)
+ sdc1 $f26, THREAD_FPR26_LS64(\thread)
+ sdc1 $f28, THREAD_FPR28_LS64(\thread)
+ sdc1 $f30, THREAD_FPR30_LS64(\thread)
sw \tmp, THREAD_FCR31(\thread)
.endm
.macro fpu_save_16odd thread
.set push
.set mips64r2
- sdc1 $f1, THREAD_FPR1(\thread)
- sdc1 $f3, THREAD_FPR3(\thread)
- sdc1 $f5, THREAD_FPR5(\thread)
- sdc1 $f7, THREAD_FPR7(\thread)
- sdc1 $f9, THREAD_FPR9(\thread)
- sdc1 $f11, THREAD_FPR11(\thread)
- sdc1 $f13, THREAD_FPR13(\thread)
- sdc1 $f15, THREAD_FPR15(\thread)
- sdc1 $f17, THREAD_FPR17(\thread)
- sdc1 $f19, THREAD_FPR19(\thread)
- sdc1 $f21, THREAD_FPR21(\thread)
- sdc1 $f23, THREAD_FPR23(\thread)
- sdc1 $f25, THREAD_FPR25(\thread)
- sdc1 $f27, THREAD_FPR27(\thread)
- sdc1 $f29, THREAD_FPR29(\thread)
- sdc1 $f31, THREAD_FPR31(\thread)
+ sdc1 $f1, THREAD_FPR1_LS64(\thread)
+ sdc1 $f3, THREAD_FPR3_LS64(\thread)
+ sdc1 $f5, THREAD_FPR5_LS64(\thread)
+ sdc1 $f7, THREAD_FPR7_LS64(\thread)
+ sdc1 $f9, THREAD_FPR9_LS64(\thread)
+ sdc1 $f11, THREAD_FPR11_LS64(\thread)
+ sdc1 $f13, THREAD_FPR13_LS64(\thread)
+ sdc1 $f15, THREAD_FPR15_LS64(\thread)
+ sdc1 $f17, THREAD_FPR17_LS64(\thread)
+ sdc1 $f19, THREAD_FPR19_LS64(\thread)
+ sdc1 $f21, THREAD_FPR21_LS64(\thread)
+ sdc1 $f23, THREAD_FPR23_LS64(\thread)
+ sdc1 $f25, THREAD_FPR25_LS64(\thread)
+ sdc1 $f27, THREAD_FPR27_LS64(\thread)
+ sdc1 $f29, THREAD_FPR29_LS64(\thread)
+ sdc1 $f31, THREAD_FPR31_LS64(\thread)
.set pop
.endm
.macro fpu_save_double thread status tmp
-#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
sll \tmp, \status, 5
bgez \tmp, 10f
fpu_save_16odd \thread
@@ -117,49 +128,49 @@
.macro fpu_restore_16even thread tmp=t0
lw \tmp, THREAD_FCR31(\thread)
- ldc1 $f0, THREAD_FPR0(\thread)
- ldc1 $f2, THREAD_FPR2(\thread)
- ldc1 $f4, THREAD_FPR4(\thread)
- ldc1 $f6, THREAD_FPR6(\thread)
- ldc1 $f8, THREAD_FPR8(\thread)
- ldc1 $f10, THREAD_FPR10(\thread)
- ldc1 $f12, THREAD_FPR12(\thread)
- ldc1 $f14, THREAD_FPR14(\thread)
- ldc1 $f16, THREAD_FPR16(\thread)
- ldc1 $f18, THREAD_FPR18(\thread)
- ldc1 $f20, THREAD_FPR20(\thread)
- ldc1 $f22, THREAD_FPR22(\thread)
- ldc1 $f24, THREAD_FPR24(\thread)
- ldc1 $f26, THREAD_FPR26(\thread)
- ldc1 $f28, THREAD_FPR28(\thread)
- ldc1 $f30, THREAD_FPR30(\thread)
+ ldc1 $f0, THREAD_FPR0_LS64(\thread)
+ ldc1 $f2, THREAD_FPR2_LS64(\thread)
+ ldc1 $f4, THREAD_FPR4_LS64(\thread)
+ ldc1 $f6, THREAD_FPR6_LS64(\thread)
+ ldc1 $f8, THREAD_FPR8_LS64(\thread)
+ ldc1 $f10, THREAD_FPR10_LS64(\thread)
+ ldc1 $f12, THREAD_FPR12_LS64(\thread)
+ ldc1 $f14, THREAD_FPR14_LS64(\thread)
+ ldc1 $f16, THREAD_FPR16_LS64(\thread)
+ ldc1 $f18, THREAD_FPR18_LS64(\thread)
+ ldc1 $f20, THREAD_FPR20_LS64(\thread)
+ ldc1 $f22, THREAD_FPR22_LS64(\thread)
+ ldc1 $f24, THREAD_FPR24_LS64(\thread)
+ ldc1 $f26, THREAD_FPR26_LS64(\thread)
+ ldc1 $f28, THREAD_FPR28_LS64(\thread)
+ ldc1 $f30, THREAD_FPR30_LS64(\thread)
ctc1 \tmp, fcr31
.endm
.macro fpu_restore_16odd thread
.set push
.set mips64r2
- ldc1 $f1, THREAD_FPR1(\thread)
- ldc1 $f3, THREAD_FPR3(\thread)
- ldc1 $f5, THREAD_FPR5(\thread)
- ldc1 $f7, THREAD_FPR7(\thread)
- ldc1 $f9, THREAD_FPR9(\thread)
- ldc1 $f11, THREAD_FPR11(\thread)
- ldc1 $f13, THREAD_FPR13(\thread)
- ldc1 $f15, THREAD_FPR15(\thread)
- ldc1 $f17, THREAD_FPR17(\thread)
- ldc1 $f19, THREAD_FPR19(\thread)
- ldc1 $f21, THREAD_FPR21(\thread)
- ldc1 $f23, THREAD_FPR23(\thread)
- ldc1 $f25, THREAD_FPR25(\thread)
- ldc1 $f27, THREAD_FPR27(\thread)
- ldc1 $f29, THREAD_FPR29(\thread)
- ldc1 $f31, THREAD_FPR31(\thread)
+ ldc1 $f1, THREAD_FPR1_LS64(\thread)
+ ldc1 $f3, THREAD_FPR3_LS64(\thread)
+ ldc1 $f5, THREAD_FPR5_LS64(\thread)
+ ldc1 $f7, THREAD_FPR7_LS64(\thread)
+ ldc1 $f9, THREAD_FPR9_LS64(\thread)
+ ldc1 $f11, THREAD_FPR11_LS64(\thread)
+ ldc1 $f13, THREAD_FPR13_LS64(\thread)
+ ldc1 $f15, THREAD_FPR15_LS64(\thread)
+ ldc1 $f17, THREAD_FPR17_LS64(\thread)
+ ldc1 $f19, THREAD_FPR19_LS64(\thread)
+ ldc1 $f21, THREAD_FPR21_LS64(\thread)
+ ldc1 $f23, THREAD_FPR23_LS64(\thread)
+ ldc1 $f25, THREAD_FPR25_LS64(\thread)
+ ldc1 $f27, THREAD_FPR27_LS64(\thread)
+ ldc1 $f29, THREAD_FPR29_LS64(\thread)
+ ldc1 $f31, THREAD_FPR31_LS64(\thread)
.set pop
.endm
.macro fpu_restore_double thread status tmp
-#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
sll \tmp, \status, 5
bgez \tmp, 10f # 16 register mode?
@@ -169,6 +180,17 @@
fpu_restore_16even \thread \tmp
.endm
+#ifdef CONFIG_CPU_MIPSR2
+ .macro _EXT rd, rs, p, s
+ ext \rd, \rs, \p, \s
+ .endm
+#else /* !CONFIG_CPU_MIPSR2 */
+ .macro _EXT rd, rs, p, s
+ srl \rd, \rs, \p
+ andi \rd, \rd, (1 << \s) - 1
+ .endm
+#endif /* !CONFIG_CPU_MIPSR2 */
+
/*
* Temporary until all gas have MT ASE support
*/
@@ -196,4 +218,195 @@
.word 0x41800000 | (\rt << 16) | (\rd << 11) | (\u << 5) | (\sel)
.endm
+#ifdef TOOLCHAIN_SUPPORTS_MSA
+ .macro ld_d wd, off, base
+ .set push
+ .set mips32r2
+ .set msa
+ ld.d $w\wd, \off(\base)
+ .set pop
+ .endm
+
+ .macro st_d wd, off, base
+ .set push
+ .set mips32r2
+ .set msa
+ st.d $w\wd, \off(\base)
+ .set pop
+ .endm
+
+ .macro copy_u_w rd, ws, n
+ .set push
+ .set mips32r2
+ .set msa
+ copy_u.w \rd, $w\ws[\n]
+ .set pop
+ .endm
+
+ .macro copy_u_d rd, ws, n
+ .set push
+ .set mips64r2
+ .set msa
+ copy_u.d \rd, $w\ws[\n]
+ .set pop
+ .endm
+
+ .macro insert_w wd, n, rs
+ .set push
+ .set mips32r2
+ .set msa
+ insert.w $w\wd[\n], \rs
+ .set pop
+ .endm
+
+ .macro insert_d wd, n, rs
+ .set push
+ .set mips64r2
+ .set msa
+ insert.d $w\wd[\n], \rs
+ .set pop
+ .endm
+#else
+ /*
+ * Temporary until all toolchains in use include MSA support.
+ */
+ .macro cfcmsa rd, cs
+ .set push
+ .set noat
+ .word 0x787e0059 | (\cs << 11)
+ move \rd, $1
+ .set pop
+ .endm
+
+ .macro ctcmsa cd, rs
+ .set push
+ .set noat
+ move $1, \rs
+ .word 0x783e0819 | (\cd << 6)
+ .set pop
+ .endm
+
+ .macro ld_d wd, off, base
+ .set push
+ .set noat
+ add $1, \base, \off
+ .word 0x78000823 | (\wd << 6)
+ .set pop
+ .endm
+
+ .macro st_d wd, off, base
+ .set push
+ .set noat
+ add $1, \base, \off
+ .word 0x78000827 | (\wd << 6)
+ .set pop
+ .endm
+
+ .macro copy_u_w rd, ws, n
+ .set push
+ .set noat
+ .word 0x78f00059 | (\n << 16) | (\ws << 11)
+ /* move triggers an assembler bug... */
+ or \rd, $1, zero
+ .set pop
+ .endm
+
+ .macro copy_u_d rd, ws, n
+ .set push
+ .set noat
+ .word 0x78f80059 | (\n << 16) | (\ws << 11)
+ /* move triggers an assembler bug... */
+ or \rd, $1, zero
+ .set pop
+ .endm
+
+ .macro insert_w wd, n, rs
+ .set push
+ .set noat
+ /* move triggers an assembler bug... */
+ or $1, \rs, zero
+ .word 0x79300819 | (\n << 16) | (\wd << 6)
+ .set pop
+ .endm
+
+ .macro insert_d wd, n, rs
+ .set push
+ .set noat
+ /* move triggers an assembler bug... */
+ or $1, \rs, zero
+ .word 0x79380819 | (\n << 16) | (\wd << 6)
+ .set pop
+ .endm
+#endif
+
+ .macro msa_save_all thread
+ st_d 0, THREAD_FPR0, \thread
+ st_d 1, THREAD_FPR1, \thread
+ st_d 2, THREAD_FPR2, \thread
+ st_d 3, THREAD_FPR3, \thread
+ st_d 4, THREAD_FPR4, \thread
+ st_d 5, THREAD_FPR5, \thread
+ st_d 6, THREAD_FPR6, \thread
+ st_d 7, THREAD_FPR7, \thread
+ st_d 8, THREAD_FPR8, \thread
+ st_d 9, THREAD_FPR9, \thread
+ st_d 10, THREAD_FPR10, \thread
+ st_d 11, THREAD_FPR11, \thread
+ st_d 12, THREAD_FPR12, \thread
+ st_d 13, THREAD_FPR13, \thread
+ st_d 14, THREAD_FPR14, \thread
+ st_d 15, THREAD_FPR15, \thread
+ st_d 16, THREAD_FPR16, \thread
+ st_d 17, THREAD_FPR17, \thread
+ st_d 18, THREAD_FPR18, \thread
+ st_d 19, THREAD_FPR19, \thread
+ st_d 20, THREAD_FPR20, \thread
+ st_d 21, THREAD_FPR21, \thread
+ st_d 22, THREAD_FPR22, \thread
+ st_d 23, THREAD_FPR23, \thread
+ st_d 24, THREAD_FPR24, \thread
+ st_d 25, THREAD_FPR25, \thread
+ st_d 26, THREAD_FPR26, \thread
+ st_d 27, THREAD_FPR27, \thread
+ st_d 28, THREAD_FPR28, \thread
+ st_d 29, THREAD_FPR29, \thread
+ st_d 30, THREAD_FPR30, \thread
+ st_d 31, THREAD_FPR31, \thread
+ .endm
+
+ .macro msa_restore_all thread
+ ld_d 0, THREAD_FPR0, \thread
+ ld_d 1, THREAD_FPR1, \thread
+ ld_d 2, THREAD_FPR2, \thread
+ ld_d 3, THREAD_FPR3, \thread
+ ld_d 4, THREAD_FPR4, \thread
+ ld_d 5, THREAD_FPR5, \thread
+ ld_d 6, THREAD_FPR6, \thread
+ ld_d 7, THREAD_FPR7, \thread
+ ld_d 8, THREAD_FPR8, \thread
+ ld_d 9, THREAD_FPR9, \thread
+ ld_d 10, THREAD_FPR10, \thread
+ ld_d 11, THREAD_FPR11, \thread
+ ld_d 12, THREAD_FPR12, \thread
+ ld_d 13, THREAD_FPR13, \thread
+ ld_d 14, THREAD_FPR14, \thread
+ ld_d 15, THREAD_FPR15, \thread
+ ld_d 16, THREAD_FPR16, \thread
+ ld_d 17, THREAD_FPR17, \thread
+ ld_d 18, THREAD_FPR18, \thread
+ ld_d 19, THREAD_FPR19, \thread
+ ld_d 20, THREAD_FPR20, \thread
+ ld_d 21, THREAD_FPR21, \thread
+ ld_d 22, THREAD_FPR22, \thread
+ ld_d 23, THREAD_FPR23, \thread
+ ld_d 24, THREAD_FPR24, \thread
+ ld_d 25, THREAD_FPR25, \thread
+ ld_d 26, THREAD_FPR26, \thread
+ ld_d 27, THREAD_FPR27, \thread
+ ld_d 28, THREAD_FPR28, \thread
+ ld_d 29, THREAD_FPR29, \thread
+ ld_d 30, THREAD_FPR30, \thread
+ ld_d 31, THREAD_FPR31, \thread
+ .endm
+
#endif /* _ASM_ASMMACRO_H */
diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h
index 7eed2f261710..e8eb3d53a241 100644
--- a/arch/mips/include/asm/atomic.h
+++ b/arch/mips/include/asm/atomic.h
@@ -53,7 +53,7 @@ static __inline__ void atomic_add(int i, atomic_t * v)
int temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %1 # atomic_add \n"
" addu %0, %2 \n"
" sc %0, %1 \n"
@@ -66,7 +66,7 @@ static __inline__ void atomic_add(int i, atomic_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" ll %0, %1 # atomic_add \n"
" addu %0, %2 \n"
" sc %0, %1 \n"
@@ -96,7 +96,7 @@ static __inline__ void atomic_sub(int i, atomic_t * v)
int temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %1 # atomic_sub \n"
" subu %0, %2 \n"
" sc %0, %1 \n"
@@ -109,7 +109,7 @@ static __inline__ void atomic_sub(int i, atomic_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" ll %0, %1 # atomic_sub \n"
" subu %0, %2 \n"
" sc %0, %1 \n"
@@ -139,7 +139,7 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
int temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %1, %2 # atomic_add_return \n"
" addu %0, %1, %3 \n"
" sc %0, %2 \n"
@@ -153,7 +153,7 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" ll %1, %2 # atomic_add_return \n"
" addu %0, %1, %3 \n"
" sc %0, %2 \n"
@@ -188,7 +188,7 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
int temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %1, %2 # atomic_sub_return \n"
" subu %0, %1, %3 \n"
" sc %0, %2 \n"
@@ -205,7 +205,7 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" ll %1, %2 # atomic_sub_return \n"
" subu %0, %1, %3 \n"
" sc %0, %2 \n"
@@ -248,7 +248,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
int temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %1, %2 # atomic_sub_if_positive\n"
" subu %0, %1, %3 \n"
" bltz %0, 1f \n"
@@ -266,7 +266,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
int temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %1, %2 # atomic_sub_if_positive\n"
" subu %0, %1, %3 \n"
" bltz %0, 1f \n"
@@ -420,7 +420,7 @@ static __inline__ void atomic64_add(long i, atomic64_t * v)
long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %0, %1 # atomic64_add \n"
" daddu %0, %2 \n"
" scd %0, %1 \n"
@@ -433,7 +433,7 @@ static __inline__ void atomic64_add(long i, atomic64_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" lld %0, %1 # atomic64_add \n"
" daddu %0, %2 \n"
" scd %0, %1 \n"
@@ -463,7 +463,7 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v)
long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %0, %1 # atomic64_sub \n"
" dsubu %0, %2 \n"
" scd %0, %1 \n"
@@ -476,7 +476,7 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" lld %0, %1 # atomic64_sub \n"
" dsubu %0, %2 \n"
" scd %0, %1 \n"
@@ -506,7 +506,7 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %1, %2 # atomic64_add_return \n"
" daddu %0, %1, %3 \n"
" scd %0, %2 \n"
@@ -520,7 +520,7 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" lld %1, %2 # atomic64_add_return \n"
" daddu %0, %1, %3 \n"
" scd %0, %2 \n"
@@ -556,7 +556,7 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %1, %2 # atomic64_sub_return \n"
" dsubu %0, %1, %3 \n"
" scd %0, %2 \n"
@@ -571,7 +571,7 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" lld %1, %2 # atomic64_sub_return \n"
" dsubu %0, %1, %3 \n"
" scd %0, %2 \n"
@@ -615,7 +615,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %1, %2 # atomic64_sub_if_positive\n"
" dsubu %0, %1, %3 \n"
" bltz %0, 1f \n"
@@ -633,7 +633,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %1, %2 # atomic64_sub_if_positive\n"
" dsubu %0, %1, %3 \n"
" bltz %0, 1f \n"
diff --git a/arch/mips/include/asm/bitops.h b/arch/mips/include/asm/bitops.h
index 71305a8b3d78..6a65d49e2c0d 100644
--- a/arch/mips/include/asm/bitops.h
+++ b/arch/mips/include/asm/bitops.h
@@ -79,7 +79,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
if (kernel_uses_llsc && R10000_LLSC_WAR) {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # set_bit \n"
" or %0, %2 \n"
" " __SC "%0, %1 \n"
@@ -101,7 +101,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
} else if (kernel_uses_llsc) {
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # set_bit \n"
" or %0, %2 \n"
" " __SC "%0, %1 \n"
@@ -131,7 +131,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
if (kernel_uses_llsc && R10000_LLSC_WAR) {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # clear_bit \n"
" and %0, %2 \n"
" " __SC "%0, %1 \n"
@@ -153,7 +153,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
} else if (kernel_uses_llsc) {
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # clear_bit \n"
" and %0, %2 \n"
" " __SC "%0, %1 \n"
@@ -197,7 +197,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # change_bit \n"
" xor %0, %2 \n"
" " __SC "%0, %1 \n"
@@ -211,7 +211,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # change_bit \n"
" xor %0, %2 \n"
" " __SC "%0, %1 \n"
@@ -244,7 +244,7 @@ static inline int test_and_set_bit(unsigned long nr,
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # test_and_set_bit \n"
" or %2, %0, %3 \n"
" " __SC "%2, %1 \n"
@@ -260,7 +260,7 @@ static inline int test_and_set_bit(unsigned long nr,
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # test_and_set_bit \n"
" or %2, %0, %3 \n"
" " __SC "%2, %1 \n"
@@ -298,7 +298,7 @@ static inline int test_and_set_bit_lock(unsigned long nr,
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # test_and_set_bit \n"
" or %2, %0, %3 \n"
" " __SC "%2, %1 \n"
@@ -314,7 +314,7 @@ static inline int test_and_set_bit_lock(unsigned long nr,
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # test_and_set_bit \n"
" or %2, %0, %3 \n"
" " __SC "%2, %1 \n"
@@ -353,7 +353,7 @@ static inline int test_and_clear_bit(unsigned long nr,
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # test_and_clear_bit \n"
" or %2, %0, %3 \n"
" xor %2, %3 \n"
@@ -386,7 +386,7 @@ static inline int test_and_clear_bit(unsigned long nr,
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # test_and_clear_bit \n"
" or %2, %0, %3 \n"
" xor %2, %3 \n"
@@ -427,7 +427,7 @@ static inline int test_and_change_bit(unsigned long nr,
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: " __LL "%0, %1 # test_and_change_bit \n"
" xor %2, %0, %3 \n"
" " __SC "%2, %1 \n"
@@ -443,7 +443,7 @@ static inline int test_and_change_bit(unsigned long nr,
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" " __LL "%0, %1 # test_and_change_bit \n"
" xor %2, %0, %3 \n"
" " __SC "\t%2, %1 \n"
diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h
index 4d2cdea5aa37..1f7ca8b00404 100644
--- a/arch/mips/include/asm/bootinfo.h
+++ b/arch/mips/include/asm/bootinfo.h
@@ -61,15 +61,21 @@
/*
* Valid machtype for Loongson family
*/
-#define MACH_LOONGSON_UNKNOWN 0
-#define MACH_LEMOTE_FL2E 1
-#define MACH_LEMOTE_FL2F 2
-#define MACH_LEMOTE_ML2F7 3
-#define MACH_LEMOTE_YL2F89 4
-#define MACH_DEXXON_GDIUM2F10 5
-#define MACH_LEMOTE_NAS 6
-#define MACH_LEMOTE_LL2F 7
-#define MACH_LOONGSON_END 8
+enum loongson_machine_type {
+ MACH_LOONGSON_UNKNOWN,
+ MACH_LEMOTE_FL2E,
+ MACH_LEMOTE_FL2F,
+ MACH_LEMOTE_ML2F7,
+ MACH_LEMOTE_YL2F89,
+ MACH_DEXXON_GDIUM2F10,
+ MACH_LEMOTE_NAS,
+ MACH_LEMOTE_LL2F,
+ MACH_LEMOTE_A1004,
+ MACH_LEMOTE_A1101,
+ MACH_LEMOTE_A1201,
+ MACH_LEMOTE_A1205,
+ MACH_LOONGSON_END
+};
/*
* Valid machtype for group INGENIC
@@ -112,6 +118,8 @@ extern void prom_free_prom_memory(void);
extern void free_init_pages(const char *what,
unsigned long begin, unsigned long end);
+extern void (*free_init_pages_eva)(void *begin, void *end);
+
/*
* Initial kernel command line, usually setup by prom_init()
*/
diff --git a/arch/mips/include/asm/checksum.h b/arch/mips/include/asm/checksum.h
index ac3d2b8a20d4..3418c51e1151 100644
--- a/arch/mips/include/asm/checksum.h
+++ b/arch/mips/include/asm/checksum.h
@@ -7,6 +7,7 @@
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 2001 Thiemo Seufer.
* Copyright (C) 2002 Maciej W. Rozycki
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*/
#ifndef _ASM_CHECKSUM_H
#define _ASM_CHECKSUM_H
@@ -29,9 +30,13 @@
*/
__wsum csum_partial(const void *buff, int len, __wsum sum);
-__wsum __csum_partial_copy_user(const void *src, void *dst,
- int len, __wsum sum, int *err_ptr);
+__wsum __csum_partial_copy_kernel(const void *src, void *dst,
+ int len, __wsum sum, int *err_ptr);
+__wsum __csum_partial_copy_from_user(const void *src, void *dst,
+ int len, __wsum sum, int *err_ptr);
+__wsum __csum_partial_copy_to_user(const void *src, void *dst,
+ int len, __wsum sum, int *err_ptr);
/*
* this is a new version of the above that records errors it finds in *errp,
* but continues and zeros the rest of the buffer.
@@ -41,8 +46,26 @@ __wsum csum_partial_copy_from_user(const void __user *src, void *dst, int len,
__wsum sum, int *err_ptr)
{
might_fault();
- return __csum_partial_copy_user((__force void *)src, dst,
- len, sum, err_ptr);
+ if (segment_eq(get_fs(), get_ds()))
+ return __csum_partial_copy_kernel((__force void *)src, dst,
+ len, sum, err_ptr);
+ else
+ return __csum_partial_copy_from_user((__force void *)src, dst,
+ len, sum, err_ptr);
+}
+
+#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
+static inline
+__wsum csum_and_copy_from_user(const void __user *src, void *dst,
+ int len, __wsum sum, int *err_ptr)
+{
+ if (access_ok(VERIFY_READ, src, len))
+ return csum_partial_copy_from_user(src, dst, len, sum,
+ err_ptr);
+ if (len)
+ *err_ptr = -EFAULT;
+
+ return sum;
}
/*
@@ -54,9 +77,16 @@ __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len,
__wsum sum, int *err_ptr)
{
might_fault();
- if (access_ok(VERIFY_WRITE, dst, len))
- return __csum_partial_copy_user(src, (__force void *)dst,
- len, sum, err_ptr);
+ if (access_ok(VERIFY_WRITE, dst, len)) {
+ if (segment_eq(get_fs(), get_ds()))
+ return __csum_partial_copy_kernel(src,
+ (__force void *)dst,
+ len, sum, err_ptr);
+ else
+ return __csum_partial_copy_to_user(src,
+ (__force void *)dst,
+ len, sum, err_ptr);
+ }
if (len)
*err_ptr = -EFAULT;
diff --git a/arch/mips/include/asm/cmpxchg.h b/arch/mips/include/asm/cmpxchg.h
index 466069bd8465..eefcaa363a87 100644
--- a/arch/mips/include/asm/cmpxchg.h
+++ b/arch/mips/include/asm/cmpxchg.h
@@ -22,11 +22,11 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
unsigned long dummy;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %3 # xchg_u32 \n"
" .set mips0 \n"
" move %2, %z4 \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" sc %2, %1 \n"
" beqzl %2, 1b \n"
" .set mips0 \n"
@@ -38,11 +38,11 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" ll %0, %3 # xchg_u32 \n"
" .set mips0 \n"
" move %2, %z4 \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" sc %2, %1 \n"
" .set mips0 \n"
: "=&r" (retval), "=m" (*m), "=&r" (dummy)
@@ -74,7 +74,7 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
unsigned long dummy;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: lld %0, %3 # xchg_u64 \n"
" move %2, %z4 \n"
" scd %2, %1 \n"
@@ -88,7 +88,7 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
do {
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" lld %0, %3 # xchg_u64 \n"
" move %2, %z4 \n"
" scd %2, %1 \n"
@@ -145,12 +145,12 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
__asm__ __volatile__( \
" .set push \n" \
" .set noat \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
"1: " ld " %0, %2 # __cmpxchg_asm \n" \
" bne %0, %z3, 2f \n" \
" .set mips0 \n" \
" move $1, %z4 \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
" " st " $1, %1 \n" \
" beqzl $1, 1b \n" \
"2: \n" \
@@ -162,12 +162,12 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
__asm__ __volatile__( \
" .set push \n" \
" .set noat \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
"1: " ld " %0, %2 # __cmpxchg_asm \n" \
" bne %0, %z3, 2f \n" \
" .set mips0 \n" \
" move $1, %z4 \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
" " st " $1, %1 \n" \
" beqz $1, 1b \n" \
" .set pop \n" \
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index 6e70b03b6aab..f56cc975b92f 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -26,7 +26,9 @@
#ifndef cpu_has_segments
#define cpu_has_segments (cpu_data[0].options & MIPS_CPU_SEGMENTS)
#endif
-
+#ifndef cpu_has_eva
+#define cpu_has_eva (cpu_data[0].options & MIPS_CPU_EVA)
+#endif
/*
* For the moment we don't consider R6000 and R8000 so we can assume that
@@ -299,4 +301,10 @@
#define cpu_has_vz (cpu_data[0].ases & MIPS_ASE_VZ)
#endif
+#if defined(CONFIG_CPU_HAS_MSA) && !defined(cpu_has_msa)
+# define cpu_has_msa (cpu_data[0].ases & MIPS_ASE_MSA)
+#elif !defined(cpu_has_msa)
+# define cpu_has_msa 0
+#endif
+
#endif /* __ASM_CPU_FEATURES_H */
diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h
index 8f7adf0ac1e3..dc2135be2a3a 100644
--- a/arch/mips/include/asm/cpu-info.h
+++ b/arch/mips/include/asm/cpu-info.h
@@ -49,6 +49,7 @@ struct cpuinfo_mips {
unsigned long ases;
unsigned int processor_id;
unsigned int fpu_id;
+ unsigned int msa_id;
unsigned int cputype;
int isa_level;
int tlbsize;
@@ -95,4 +96,31 @@ extern void cpu_report(void);
extern const char *__cpu_name[];
#define cpu_name_string() __cpu_name[smp_processor_id()]
+struct seq_file;
+struct notifier_block;
+
+extern int register_proc_cpuinfo_notifier(struct notifier_block *nb);
+extern int proc_cpuinfo_notifier_call_chain(unsigned long val, void *v);
+
+#define proc_cpuinfo_notifier(fn, pri) \
+({ \
+ static struct notifier_block fn##_nb = { \
+ .notifier_call = fn, \
+ .priority = pri \
+ }; \
+ \
+ register_proc_cpuinfo_notifier(&fn##_nb); \
+})
+
+struct proc_cpuinfo_notifier_args {
+ struct seq_file *m;
+ unsigned long n;
+};
+
+#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
+# define cpu_vpe_id(cpuinfo) ((cpuinfo)->vpe_id)
+#else
+# define cpu_vpe_id(cpuinfo) 0
+#endif
+
#endif /* __ASM_CPU_INFO_H */
diff --git a/arch/mips/include/asm/cpu-type.h b/arch/mips/include/asm/cpu-type.h
index 02f591bd95ca..721906130a57 100644
--- a/arch/mips/include/asm/cpu-type.h
+++ b/arch/mips/include/asm/cpu-type.h
@@ -20,6 +20,10 @@ static inline int __pure __get_cpu_type(const int cpu_type)
case CPU_LOONGSON2:
#endif
+#ifdef CONFIG_SYS_HAS_CPU_LOONGSON3
+ case CPU_LOONGSON3:
+#endif
+
#ifdef CONFIG_SYS_HAS_CPU_LOONGSON1B
case CPU_LOONGSON1:
#endif
@@ -46,6 +50,8 @@ static inline int __pure __get_cpu_type(const int cpu_type)
case CPU_M14KEC:
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
+ case CPU_P5600:
+ case CPU_M5150:
#endif
#ifdef CONFIG_SYS_HAS_CPU_MIPS64_R1
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index 76411df3d971..530eb8b3a68e 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -82,10 +82,10 @@
#define PRID_IMP_RM7000 0x2700
#define PRID_IMP_NEVADA 0x2800 /* RM5260 ??? */
#define PRID_IMP_RM9000 0x3400
-#define PRID_IMP_LOONGSON1 0x4200
+#define PRID_IMP_LOONGSON_32 0x4200 /* Loongson-1 */
#define PRID_IMP_R5432 0x5400
#define PRID_IMP_R5500 0x5500
-#define PRID_IMP_LOONGSON2 0x6300
+#define PRID_IMP_LOONGSON_64 0x6300 /* Loongson-2/3 */
#define PRID_IMP_UNKNOWN 0xff00
@@ -115,6 +115,8 @@
#define PRID_IMP_INTERAPTIV_MP 0xa100
#define PRID_IMP_PROAPTIV_UP 0xa200
#define PRID_IMP_PROAPTIV_MP 0xa300
+#define PRID_IMP_M5150 0xa700
+#define PRID_IMP_P5600 0xa800
/*
* These are the PRID's for when 23:16 == PRID_COMP_SIBYTE
@@ -229,6 +231,7 @@
#define PRID_REV_LOONGSON1B 0x0020
#define PRID_REV_LOONGSON2E 0x0002
#define PRID_REV_LOONGSON2F 0x0003
+#define PRID_REV_LOONGSON3A 0x0005
/*
* Older processors used to encode processor version and revision in two
@@ -296,14 +299,14 @@ enum cpu_type_enum {
CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K,
CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350,
CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC,
- CPU_M14KEC, CPU_INTERAPTIV, CPU_PROAPTIV,
+ CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K, CPU_M5150,
/*
* MIPS64 class processors
*/
CPU_5KC, CPU_5KE, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
- CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS, CPU_CAVIUM_OCTEON2,
- CPU_CAVIUM_OCTEON3, CPU_XLR, CPU_XLP,
+ CPU_LOONGSON3, CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS,
+ CPU_CAVIUM_OCTEON2, CPU_CAVIUM_OCTEON3, CPU_XLR, CPU_XLP,
CPU_LAST
};
@@ -358,6 +361,7 @@ enum cpu_type_enum {
#define MIPS_CPU_MICROMIPS 0x01000000 /* CPU has microMIPS capability */
#define MIPS_CPU_TLBINV 0x02000000 /* CPU supports TLBINV/F */
#define MIPS_CPU_SEGMENTS 0x04000000 /* CPU supports Segmentation Control registers */
+#define MIPS_CPU_EVA 0x80000000 /* CPU supports Enhanced Virtual Addressing */
/*
* CPU ASE encodings
@@ -370,5 +374,6 @@ enum cpu_type_enum {
#define MIPS_ASE_MIPSMT 0x00000020 /* CPU supports MIPS MT */
#define MIPS_ASE_DSP2P 0x00000040 /* Signal Processing ASE Rev 2 */
#define MIPS_ASE_VZ 0x00000080 /* Virtualization ASE */
+#define MIPS_ASE_MSA 0x00000100 /* MIPS SIMD Architecture */
#endif /* _ASM_CPU_H */
diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h
index 84238c574d5e..06412aa9e3fb 100644
--- a/arch/mips/include/asm/dma-mapping.h
+++ b/arch/mips/include/asm/dma-mapping.h
@@ -49,9 +49,14 @@ static inline int dma_mapping_error(struct device *dev, u64 mask)
static inline int
dma_set_mask(struct device *dev, u64 mask)
{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
if(!dev->dma_mask || !dma_supported(dev, mask))
return -EIO;
+ if (ops->set_dma_mask)
+ return ops->set_dma_mask(dev, mask);
+
*dev->dma_mask = mask;
return 0;
diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h
index 6b9749540edf..4d86b72750c7 100644
--- a/arch/mips/include/asm/fpu.h
+++ b/arch/mips/include/asm/fpu.h
@@ -57,7 +57,7 @@ static inline int __enable_fpu(enum fpu_mode mode)
return 0;
case FPU_64BIT:
-#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_MIPS64))
+#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_64BIT))
/* we only have a 32-bit FPU */
return SIGFPE;
#endif
@@ -180,7 +180,7 @@ static inline void restore_fp(struct task_struct *tsk)
_restore_fp(tsk);
}
-static inline fpureg_t *get_fpu_regs(struct task_struct *tsk)
+static inline union fpureg *get_fpu_regs(struct task_struct *tsk)
{
if (tsk == current) {
preempt_disable();
diff --git a/arch/mips/include/asm/ftrace.h b/arch/mips/include/asm/ftrace.h
index ce35c9af0c28..992aaba603b5 100644
--- a/arch/mips/include/asm/ftrace.h
+++ b/arch/mips/include/asm/ftrace.h
@@ -22,12 +22,12 @@ extern void _mcount(void);
#define safe_load(load, src, dst, error) \
do { \
asm volatile ( \
- "1: " load " %[" STR(dst) "], 0(%[" STR(src) "])\n"\
- " li %[" STR(error) "], 0\n" \
+ "1: " load " %[tmp_dst], 0(%[tmp_src])\n" \
+ " li %[tmp_err], 0\n" \
"2:\n" \
\
".section .fixup, \"ax\"\n" \
- "3: li %[" STR(error) "], 1\n" \
+ "3: li %[tmp_err], 1\n" \
" j 2b\n" \
".previous\n" \
\
@@ -35,8 +35,8 @@ do { \
STR(PTR) "\t1b, 3b\n\t" \
".previous\n" \
\
- : [dst] "=&r" (dst), [error] "=r" (error)\
- : [src] "r" (src) \
+ : [tmp_dst] "=&r" (dst), [tmp_err] "=r" (error)\
+ : [tmp_src] "r" (src) \
: "memory" \
); \
} while (0)
@@ -44,12 +44,12 @@ do { \
#define safe_store(store, src, dst, error) \
do { \
asm volatile ( \
- "1: " store " %[" STR(src) "], 0(%[" STR(dst) "])\n"\
- " li %[" STR(error) "], 0\n" \
+ "1: " store " %[tmp_src], 0(%[tmp_dst])\n"\
+ " li %[tmp_err], 0\n" \
"2:\n" \
\
".section .fixup, \"ax\"\n" \
- "3: li %[" STR(error) "], 1\n" \
+ "3: li %[tmp_err], 1\n" \
" j 2b\n" \
".previous\n" \
\
@@ -57,8 +57,8 @@ do { \
STR(PTR) "\t1b, 3b\n\t" \
".previous\n" \
\
- : [error] "=r" (error) \
- : [dst] "r" (dst), [src] "r" (src)\
+ : [tmp_err] "=r" (error) \
+ : [tmp_dst] "r" (dst), [tmp_src] "r" (src)\
: "memory" \
); \
} while (0)
diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h
index 6ea15815d3ee..194cda0396a3 100644
--- a/arch/mips/include/asm/futex.h
+++ b/arch/mips/include/asm/futex.h
@@ -12,6 +12,7 @@
#include <linux/futex.h>
#include <linux/uaccess.h>
+#include <asm/asm-eva.h>
#include <asm/barrier.h>
#include <asm/errno.h>
#include <asm/war.h>
@@ -22,11 +23,11 @@
__asm__ __volatile__( \
" .set push \n" \
" .set noat \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
"1: ll %1, %4 # __futex_atomic_op \n" \
" .set mips0 \n" \
" " insn " \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
"2: sc $1, %2 \n" \
" beqzl $1, 1b \n" \
__WEAK_LLSC_MB \
@@ -48,12 +49,12 @@
__asm__ __volatile__( \
" .set push \n" \
" .set noat \n" \
- " .set mips3 \n" \
- "1: ll %1, %4 # __futex_atomic_op \n" \
+ " .set arch=r4000 \n" \
+ "1: "user_ll("%1", "%4")" # __futex_atomic_op\n" \
" .set mips0 \n" \
" " insn " \n" \
- " .set mips3 \n" \
- "2: sc $1, %2 \n" \
+ " .set arch=r4000 \n" \
+ "2: "user_sc("$1", "%2")" \n" \
" beqz $1, 1b \n" \
__WEAK_LLSC_MB \
"3: \n" \
@@ -146,12 +147,12 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
"# futex_atomic_cmpxchg_inatomic \n"
" .set push \n"
" .set noat \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %1, %3 \n"
" bne %1, %z4, 3f \n"
" .set mips0 \n"
" move $1, %z5 \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"2: sc $1, %2 \n"
" beqzl $1, 1b \n"
__WEAK_LLSC_MB
@@ -173,13 +174,13 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
"# futex_atomic_cmpxchg_inatomic \n"
" .set push \n"
" .set noat \n"
- " .set mips3 \n"
- "1: ll %1, %3 \n"
+ " .set arch=r4000 \n"
+ "1: "user_ll("%1", "%3")" \n"
" bne %1, %z4, 3f \n"
" .set mips0 \n"
" move $1, %z5 \n"
- " .set mips3 \n"
- "2: sc $1, %2 \n"
+ " .set arch=r4000 \n"
+ "2: "user_sc("$1", "%2")" \n"
" beqz $1, 1b \n"
__WEAK_LLSC_MB
"3: \n"
diff --git a/arch/mips/include/asm/fw/fw.h b/arch/mips/include/asm/fw/fw.h
index d6c50a7e9ede..f3e6978aad70 100644
--- a/arch/mips/include/asm/fw/fw.h
+++ b/arch/mips/include/asm/fw/fw.h
@@ -38,7 +38,7 @@ extern int *_fw_envp;
extern void fw_init_cmdline(void);
extern char *fw_getcmdline(void);
-extern fw_memblock_t *fw_getmdesc(void);
+extern fw_memblock_t *fw_getmdesc(int);
extern void fw_meminit(void);
extern char *fw_getenv(char *name);
extern unsigned long fw_getenvl(char *name);
diff --git a/arch/mips/include/asm/gcmpregs.h b/arch/mips/include/asm/gcmpregs.h
deleted file mode 100644
index a7359f77a48e..000000000000
--- a/arch/mips/include/asm/gcmpregs.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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) 2000, 07 MIPS Technologies, Inc.
- *
- * Multiprocessor Subsystem Register Definitions
- *
- */
-#ifndef _ASM_GCMPREGS_H
-#define _ASM_GCMPREGS_H
-
-
-/* Offsets to major blocks within GCMP from GCMP base */
-#define GCMP_GCB_OFS 0x0000 /* Global Control Block */
-#define GCMP_CLCB_OFS 0x2000 /* Core Local Control Block */
-#define GCMP_COCB_OFS 0x4000 /* Core Other Control Block */
-#define GCMP_GDB_OFS 0x8000 /* Global Debug Block */
-
-/* Offsets to individual GCMP registers from GCMP base */
-#define GCMPOFS(block, tag, reg) \
- (GCMP_##block##_OFS + GCMP_##tag##_##reg##_OFS)
-#define GCMPOFSn(block, tag, reg, n) \
- (GCMP_##block##_OFS + GCMP_##tag##_##reg##_OFS(n))
-
-#define GCMPGCBOFS(reg) GCMPOFS(GCB, GCB, reg)
-#define GCMPGCBOFSn(reg, n) GCMPOFSn(GCB, GCB, reg, n)
-#define GCMPCLCBOFS(reg) GCMPOFS(CLCB, CCB, reg)
-#define GCMPCOCBOFS(reg) GCMPOFS(COCB, CCB, reg)
-#define GCMPGDBOFS(reg) GCMPOFS(GDB, GDB, reg)
-
-/* GCMP register access */
-#define GCMPGCB(reg) REGP(_gcmp_base, GCMPGCBOFS(reg))
-#define GCMPGCBn(reg, n) REGP(_gcmp_base, GCMPGCBOFSn(reg, n))
-#define GCMPCLCB(reg) REGP(_gcmp_base, GCMPCLCBOFS(reg))
-#define GCMPCOCB(reg) REGP(_gcmp_base, GCMPCOCBOFS(reg))
-#define GCMPGDB(reg) REGP(_gcmp_base, GCMPGDBOFS(reg))
-
-/* Mask generation */
-#define GCMPMSK(block, reg, bits) (MSK(bits)<<GCMP_##block##_##reg##_SHF)
-#define GCMPGCBMSK(reg, bits) GCMPMSK(GCB, reg, bits)
-#define GCMPCCBMSK(reg, bits) GCMPMSK(CCB, reg, bits)
-#define GCMPGDBMSK(reg, bits) GCMPMSK(GDB, reg, bits)
-
-/* GCB registers */
-#define GCMP_GCB_GC_OFS 0x0000 /* Global Config Register */
-#define GCMP_GCB_GC_NUMIOCU_SHF 8
-#define GCMP_GCB_GC_NUMIOCU_MSK GCMPGCBMSK(GC_NUMIOCU, 4)
-#define GCMP_GCB_GC_NUMCORES_SHF 0
-#define GCMP_GCB_GC_NUMCORES_MSK GCMPGCBMSK(GC_NUMCORES, 8)
-#define GCMP_GCB_GCMPB_OFS 0x0008 /* Global GCMP Base */
-#define GCMP_GCB_GCMPB_GCMPBASE_SHF 15
-#define GCMP_GCB_GCMPB_GCMPBASE_MSK GCMPGCBMSK(GCMPB_GCMPBASE, 17)
-#define GCMP_GCB_GCMPB_CMDEFTGT_SHF 0
-#define GCMP_GCB_GCMPB_CMDEFTGT_MSK GCMPGCBMSK(GCMPB_CMDEFTGT, 2)
-#define GCMP_GCB_GCMPB_CMDEFTGT_DISABLED 0
-#define GCMP_GCB_GCMPB_CMDEFTGT_MEM 1
-#define GCMP_GCB_GCMPB_CMDEFTGT_IOCU1 2
-#define GCMP_GCB_GCMPB_CMDEFTGT_IOCU2 3
-#define GCMP_GCB_CCMC_OFS 0x0010 /* Global CM Control */
-#define GCMP_GCB_GCSRAP_OFS 0x0020 /* Global CSR Access Privilege */
-#define GCMP_GCB_GCSRAP_CMACCESS_SHF 0
-#define GCMP_GCB_GCSRAP_CMACCESS_MSK GCMPGCBMSK(GCSRAP_CMACCESS, 8)
-#define GCMP_GCB_GCMPREV_OFS 0x0030 /* GCMP Revision Register */
-#define GCMP_GCB_GCMEM_OFS 0x0040 /* Global CM Error Mask */
-#define GCMP_GCB_GCMEC_OFS 0x0048 /* Global CM Error Cause */
-#define GCMP_GCB_GMEC_ERROR_TYPE_SHF 27
-#define GCMP_GCB_GMEC_ERROR_TYPE_MSK GCMPGCBMSK(GMEC_ERROR_TYPE, 5)
-#define GCMP_GCB_GMEC_ERROR_INFO_SHF 0
-#define GCMP_GCB_GMEC_ERROR_INFO_MSK GCMPGCBMSK(GMEC_ERROR_INFO, 27)
-#define GCMP_GCB_GCMEA_OFS 0x0050 /* Global CM Error Address */
-#define GCMP_GCB_GCMEO_OFS 0x0058 /* Global CM Error Multiple */
-#define GCMP_GCB_GMEO_ERROR_2ND_SHF 0
-#define GCMP_GCB_GMEO_ERROR_2ND_MSK GCMPGCBMSK(GMEO_ERROR_2ND, 5)
-#define GCMP_GCB_GICBA_OFS 0x0080 /* Global Interrupt Controller Base Address */
-#define GCMP_GCB_GICBA_BASE_SHF 17
-#define GCMP_GCB_GICBA_BASE_MSK GCMPGCBMSK(GICBA_BASE, 15)
-#define GCMP_GCB_GICBA_EN_SHF 0
-#define GCMP_GCB_GICBA_EN_MSK GCMPGCBMSK(GICBA_EN, 1)
-
-/* GCB Regions */
-#define GCMP_GCB_CMxBASE_OFS(n) (0x0090+16*(n)) /* Global Region[0-3] Base Address */
-#define GCMP_GCB_CMxBASE_BASE_SHF 16
-#define GCMP_GCB_CMxBASE_BASE_MSK GCMPGCBMSK(CMxBASE_BASE, 16)
-#define GCMP_GCB_CMxMASK_OFS(n) (0x0098+16*(n)) /* Global Region[0-3] Address Mask */
-#define GCMP_GCB_CMxMASK_MASK_SHF 16
-#define GCMP_GCB_CMxMASK_MASK_MSK GCMPGCBMSK(CMxMASK_MASK, 16)
-#define GCMP_GCB_CMxMASK_CMREGTGT_SHF 0
-#define GCMP_GCB_CMxMASK_CMREGTGT_MSK GCMPGCBMSK(CMxMASK_CMREGTGT, 2)
-#define GCMP_GCB_CMxMASK_CMREGTGT_MEM 0
-#define GCMP_GCB_CMxMASK_CMREGTGT_MEM1 1
-#define GCMP_GCB_CMxMASK_CMREGTGT_IOCU1 2
-#define GCMP_GCB_CMxMASK_CMREGTGT_IOCU2 3
-
-
-/* Core local/Core other control block registers */
-#define GCMP_CCB_RESETR_OFS 0x0000 /* Reset Release */
-#define GCMP_CCB_RESETR_INRESET_SHF 0
-#define GCMP_CCB_RESETR_INRESET_MSK GCMPCCBMSK(RESETR_INRESET, 16)
-#define GCMP_CCB_COHCTL_OFS 0x0008 /* Coherence Control */
-#define GCMP_CCB_COHCTL_DOMAIN_SHF 0
-#define GCMP_CCB_COHCTL_DOMAIN_MSK GCMPCCBMSK(COHCTL_DOMAIN, 8)
-#define GCMP_CCB_CFG_OFS 0x0010 /* Config */
-#define GCMP_CCB_CFG_IOCUTYPE_SHF 10
-#define GCMP_CCB_CFG_IOCUTYPE_MSK GCMPCCBMSK(CFG_IOCUTYPE, 2)
-#define GCMP_CCB_CFG_IOCUTYPE_CPU 0
-#define GCMP_CCB_CFG_IOCUTYPE_NCIOCU 1
-#define GCMP_CCB_CFG_IOCUTYPE_CIOCU 2
-#define GCMP_CCB_CFG_NUMVPE_SHF 0
-#define GCMP_CCB_CFG_NUMVPE_MSK GCMPCCBMSK(CFG_NUMVPE, 10)
-#define GCMP_CCB_OTHER_OFS 0x0018 /* Other Address */
-#define GCMP_CCB_OTHER_CORENUM_SHF 16
-#define GCMP_CCB_OTHER_CORENUM_MSK GCMPCCBMSK(OTHER_CORENUM, 16)
-#define GCMP_CCB_RESETBASE_OFS 0x0020 /* Reset Exception Base */
-#define GCMP_CCB_RESETBASE_BEV_SHF 12
-#define GCMP_CCB_RESETBASE_BEV_MSK GCMPCCBMSK(RESETBASE_BEV, 20)
-#define GCMP_CCB_ID_OFS 0x0028 /* Identification */
-#define GCMP_CCB_DINTGROUP_OFS 0x0030 /* DINT Group Participate */
-#define GCMP_CCB_DBGGROUP_OFS 0x0100 /* DebugBreak Group */
-
-extern int __init gcmp_probe(unsigned long, unsigned long);
-extern int __init gcmp_niocu(void);
-extern void __init gcmp_setregion(int, unsigned long, unsigned long, int);
-#endif /* _ASM_GCMPREGS_H */
diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index b2e3e93dd7d8..082716690589 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -11,6 +11,9 @@
#ifndef _ASM_GICREGS_H
#define _ASM_GICREGS_H
+#include <linux/bitmap.h>
+#include <linux/threads.h>
+
#undef GICISBYTELITTLEENDIAN
/* Constants */
diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h
index 3321dd5a8872..933b50e125a0 100644
--- a/arch/mips/include/asm/io.h
+++ b/arch/mips/include/asm/io.h
@@ -331,7 +331,7 @@ static inline void pfx##write##bwlq(type val, \
if (irq) \
local_irq_save(__flags); \
__asm__ __volatile__( \
- ".set mips3" "\t\t# __writeq""\n\t" \
+ ".set arch=r4000" "\t\t# __writeq""\n\t" \
"dsll32 %L0, %L0, 0" "\n\t" \
"dsrl32 %L0, %L0, 0" "\n\t" \
"dsll32 %M0, %M0, 0" "\n\t" \
@@ -361,7 +361,7 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem) \
if (irq) \
local_irq_save(__flags); \
__asm__ __volatile__( \
- ".set mips3" "\t\t# __readq" "\n\t" \
+ ".set arch=r4000" "\t\t# __readq" "\n\t" \
"ld %L0, %1" "\n\t" \
"dsra32 %M0, %L0, 0" "\n\t" \
"sll %L0, %L0, 0" "\n\t" \
@@ -584,7 +584,7 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int
*
* This API used to be exported; it now is for arch code internal use only.
*/
-#ifdef CONFIG_DMA_NONCOHERENT
+#if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT)
extern void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size);
extern void (*_dma_cache_wback)(unsigned long start, unsigned long size);
@@ -603,7 +603,7 @@ extern void (*_dma_cache_inv)(unsigned long start, unsigned long size);
#define dma_cache_inv(start,size) \
do { (void) (start); (void) (size); } while (0)
-#endif /* CONFIG_DMA_NONCOHERENT */
+#endif /* CONFIG_DMA_NONCOHERENT || CONFIG_DMA_MAYBE_COHERENT */
/*
* Read a 32-bit register that requires a 64-bit read cycle on the bus.
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index a995fce87791..060aaa6348d7 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -30,16 +30,16 @@
/* Special address that contains the comm page, used for reducing # of traps */
-#define KVM_GUEST_COMMPAGE_ADDR 0x0
+#define KVM_GUEST_COMMPAGE_ADDR 0x0
#define KVM_GUEST_KERNEL_MODE(vcpu) ((kvm_read_c0_guest_status(vcpu->arch.cop0) & (ST0_EXL | ST0_ERL)) || \
((kvm_read_c0_guest_status(vcpu->arch.cop0) & KSU_USER) == 0))
-#define KVM_GUEST_KUSEG 0x00000000UL
-#define KVM_GUEST_KSEG0 0x40000000UL
-#define KVM_GUEST_KSEG23 0x60000000UL
-#define KVM_GUEST_KSEGX(a) ((_ACAST32_(a)) & 0x60000000)
-#define KVM_GUEST_CPHYSADDR(a) ((_ACAST32_(a)) & 0x1fffffff)
+#define KVM_GUEST_KUSEG 0x00000000UL
+#define KVM_GUEST_KSEG0 0x40000000UL
+#define KVM_GUEST_KSEG23 0x60000000UL
+#define KVM_GUEST_KSEGX(a) ((_ACAST32_(a)) & 0x60000000)
+#define KVM_GUEST_CPHYSADDR(a) ((_ACAST32_(a)) & 0x1fffffff)
#define KVM_GUEST_CKSEG0ADDR(a) (KVM_GUEST_CPHYSADDR(a) | KVM_GUEST_KSEG0)
#define KVM_GUEST_CKSEG1ADDR(a) (KVM_GUEST_CPHYSADDR(a) | KVM_GUEST_KSEG1)
@@ -52,17 +52,17 @@
#define KVM_GUEST_KSEG1ADDR(a) (KVM_GUEST_CPHYSADDR(a) | KVM_GUEST_KSEG1)
#define KVM_GUEST_KSEG23ADDR(a) (KVM_GUEST_CPHYSADDR(a) | KVM_GUEST_KSEG23)
-#define KVM_INVALID_PAGE 0xdeadbeef
-#define KVM_INVALID_INST 0xdeadbeef
-#define KVM_INVALID_ADDR 0xdeadbeef
+#define KVM_INVALID_PAGE 0xdeadbeef
+#define KVM_INVALID_INST 0xdeadbeef
+#define KVM_INVALID_ADDR 0xdeadbeef
-#define KVM_MALTA_GUEST_RTC_ADDR 0xb8000070UL
+#define KVM_MALTA_GUEST_RTC_ADDR 0xb8000070UL
-#define GUEST_TICKS_PER_JIFFY (40000000/HZ)
-#define MS_TO_NS(x) (x * 1E6L)
+#define GUEST_TICKS_PER_JIFFY (40000000/HZ)
+#define MS_TO_NS(x) (x * 1E6L)
-#define CAUSEB_DC 27
-#define CAUSEF_DC (_ULCAST_(1) << 27)
+#define CAUSEB_DC 27
+#define CAUSEF_DC (_ULCAST_(1) << 27)
struct kvm;
struct kvm_run;
@@ -126,8 +126,8 @@ struct kvm_arch {
int commpage_tlb;
};
-#define N_MIPS_COPROC_REGS 32
-#define N_MIPS_COPROC_SEL 8
+#define N_MIPS_COPROC_REGS 32
+#define N_MIPS_COPROC_SEL 8
struct mips_coproc {
unsigned long reg[N_MIPS_COPROC_REGS][N_MIPS_COPROC_SEL];
@@ -139,124 +139,124 @@ struct mips_coproc {
/*
* Coprocessor 0 register names
*/
-#define MIPS_CP0_TLB_INDEX 0
-#define MIPS_CP0_TLB_RANDOM 1
-#define MIPS_CP0_TLB_LOW 2
-#define MIPS_CP0_TLB_LO0 2
-#define MIPS_CP0_TLB_LO1 3
-#define MIPS_CP0_TLB_CONTEXT 4
-#define MIPS_CP0_TLB_PG_MASK 5
-#define MIPS_CP0_TLB_WIRED 6
-#define MIPS_CP0_HWRENA 7
-#define MIPS_CP0_BAD_VADDR 8
-#define MIPS_CP0_COUNT 9
-#define MIPS_CP0_TLB_HI 10
-#define MIPS_CP0_COMPARE 11
-#define MIPS_CP0_STATUS 12
-#define MIPS_CP0_CAUSE 13
-#define MIPS_CP0_EXC_PC 14
-#define MIPS_CP0_PRID 15
-#define MIPS_CP0_CONFIG 16
-#define MIPS_CP0_LLADDR 17
-#define MIPS_CP0_WATCH_LO 18
-#define MIPS_CP0_WATCH_HI 19
-#define MIPS_CP0_TLB_XCONTEXT 20
-#define MIPS_CP0_ECC 26
-#define MIPS_CP0_CACHE_ERR 27
-#define MIPS_CP0_TAG_LO 28
-#define MIPS_CP0_TAG_HI 29
-#define MIPS_CP0_ERROR_PC 30
-#define MIPS_CP0_DEBUG 23
-#define MIPS_CP0_DEPC 24
-#define MIPS_CP0_PERFCNT 25
-#define MIPS_CP0_ERRCTL 26
-#define MIPS_CP0_DATA_LO 28
-#define MIPS_CP0_DATA_HI 29
-#define MIPS_CP0_DESAVE 31
-
-#define MIPS_CP0_CONFIG_SEL 0
-#define MIPS_CP0_CONFIG1_SEL 1
-#define MIPS_CP0_CONFIG2_SEL 2
-#define MIPS_CP0_CONFIG3_SEL 3
+#define MIPS_CP0_TLB_INDEX 0
+#define MIPS_CP0_TLB_RANDOM 1
+#define MIPS_CP0_TLB_LOW 2
+#define MIPS_CP0_TLB_LO0 2
+#define MIPS_CP0_TLB_LO1 3
+#define MIPS_CP0_TLB_CONTEXT 4
+#define MIPS_CP0_TLB_PG_MASK 5
+#define MIPS_CP0_TLB_WIRED 6
+#define MIPS_CP0_HWRENA 7
+#define MIPS_CP0_BAD_VADDR 8
+#define MIPS_CP0_COUNT 9
+#define MIPS_CP0_TLB_HI 10
+#define MIPS_CP0_COMPARE 11
+#define MIPS_CP0_STATUS 12
+#define MIPS_CP0_CAUSE 13
+#define MIPS_CP0_EXC_PC 14
+#define MIPS_CP0_PRID 15
+#define MIPS_CP0_CONFIG 16
+#define MIPS_CP0_LLADDR 17
+#define MIPS_CP0_WATCH_LO 18
+#define MIPS_CP0_WATCH_HI 19
+#define MIPS_CP0_TLB_XCONTEXT 20
+#define MIPS_CP0_ECC 26
+#define MIPS_CP0_CACHE_ERR 27
+#define MIPS_CP0_TAG_LO 28
+#define MIPS_CP0_TAG_HI 29
+#define MIPS_CP0_ERROR_PC 30
+#define MIPS_CP0_DEBUG 23
+#define MIPS_CP0_DEPC 24
+#define MIPS_CP0_PERFCNT 25
+#define MIPS_CP0_ERRCTL 26
+#define MIPS_CP0_DATA_LO 28
+#define MIPS_CP0_DATA_HI 29
+#define MIPS_CP0_DESAVE 31
+
+#define MIPS_CP0_CONFIG_SEL 0
+#define MIPS_CP0_CONFIG1_SEL 1
+#define MIPS_CP0_CONFIG2_SEL 2
+#define MIPS_CP0_CONFIG3_SEL 3
/* Config0 register bits */
-#define CP0C0_M 31
-#define CP0C0_K23 28
-#define CP0C0_KU 25
-#define CP0C0_MDU 20
-#define CP0C0_MM 17
-#define CP0C0_BM 16
-#define CP0C0_BE 15
-#define CP0C0_AT 13
-#define CP0C0_AR 10
-#define CP0C0_MT 7
-#define CP0C0_VI 3
-#define CP0C0_K0 0
+#define CP0C0_M 31
+#define CP0C0_K23 28
+#define CP0C0_KU 25
+#define CP0C0_MDU 20
+#define CP0C0_MM 17
+#define CP0C0_BM 16
+#define CP0C0_BE 15
+#define CP0C0_AT 13
+#define CP0C0_AR 10
+#define CP0C0_MT 7
+#define CP0C0_VI 3
+#define CP0C0_K0 0
/* Config1 register bits */
-#define CP0C1_M 31
-#define CP0C1_MMU 25
-#define CP0C1_IS 22
-#define CP0C1_IL 19
-#define CP0C1_IA 16
-#define CP0C1_DS 13
-#define CP0C1_DL 10
-#define CP0C1_DA 7
-#define CP0C1_C2 6
-#define CP0C1_MD 5
-#define CP0C1_PC 4
-#define CP0C1_WR 3
-#define CP0C1_CA 2
-#define CP0C1_EP 1
-#define CP0C1_FP 0
+#define CP0C1_M 31
+#define CP0C1_MMU 25
+#define CP0C1_IS 22
+#define CP0C1_IL 19
+#define CP0C1_IA 16
+#define CP0C1_DS 13
+#define CP0C1_DL 10
+#define CP0C1_DA 7
+#define CP0C1_C2 6
+#define CP0C1_MD 5
+#define CP0C1_PC 4
+#define CP0C1_WR 3
+#define CP0C1_CA 2
+#define CP0C1_EP 1
+#define CP0C1_FP 0
/* Config2 Register bits */
-#define CP0C2_M 31
-#define CP0C2_TU 28
-#define CP0C2_TS 24
-#define CP0C2_TL 20
-#define CP0C2_TA 16
-#define CP0C2_SU 12
-#define CP0C2_SS 8
-#define CP0C2_SL 4
-#define CP0C2_SA 0
+#define CP0C2_M 31
+#define CP0C2_TU 28
+#define CP0C2_TS 24
+#define CP0C2_TL 20
+#define CP0C2_TA 16
+#define CP0C2_SU 12
+#define CP0C2_SS 8
+#define CP0C2_SL 4
+#define CP0C2_SA 0
/* Config3 Register bits */
-#define CP0C3_M 31
-#define CP0C3_ISA_ON_EXC 16
-#define CP0C3_ULRI 13
-#define CP0C3_DSPP 10
-#define CP0C3_LPA 7
-#define CP0C3_VEIC 6
-#define CP0C3_VInt 5
-#define CP0C3_SP 4
-#define CP0C3_MT 2
-#define CP0C3_SM 1
-#define CP0C3_TL 0
+#define CP0C3_M 31
+#define CP0C3_ISA_ON_EXC 16
+#define CP0C3_ULRI 13
+#define CP0C3_DSPP 10
+#define CP0C3_LPA 7
+#define CP0C3_VEIC 6
+#define CP0C3_VInt 5
+#define CP0C3_SP 4
+#define CP0C3_MT 2
+#define CP0C3_SM 1
+#define CP0C3_TL 0
/* Have config1, Cacheable, noncoherent, write-back, write allocate*/
-#define MIPS_CONFIG0 \
+#define MIPS_CONFIG0 \
((1 << CP0C0_M) | (0x3 << CP0C0_K0))
/* Have config2, no coprocessor2 attached, no MDMX support attached,
no performance counters, watch registers present,
no code compression, EJTAG present, no FPU, no watch registers */
-#define MIPS_CONFIG1 \
-((1 << CP0C1_M) | \
- (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \
- (0 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP) | \
+#define MIPS_CONFIG1 \
+((1 << CP0C1_M) | \
+ (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \
+ (0 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP) | \
(0 << CP0C1_FP))
/* Have config3, no tertiary/secondary caches implemented */
-#define MIPS_CONFIG2 \
+#define MIPS_CONFIG2 \
((1 << CP0C2_M))
/* No config4, no DSP ASE, no large physaddr (PABITS),
no external interrupt controller, no vectored interrupts,
no 1kb pages, no SmartMIPS ASE, no trace logic */
-#define MIPS_CONFIG3 \
-((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \
- (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \
+#define MIPS_CONFIG3 \
+((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \
+ (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \
(0 << CP0C3_SM) | (0 << CP0C3_TL))
/* MMU types, the first four entries have the same layout as the
@@ -274,36 +274,36 @@ enum mips_mmu_types {
/*
* Trap codes
*/
-#define T_INT 0 /* Interrupt pending */
-#define T_TLB_MOD 1 /* TLB modified fault */
-#define T_TLB_LD_MISS 2 /* TLB miss on load or ifetch */
-#define T_TLB_ST_MISS 3 /* TLB miss on a store */
-#define T_ADDR_ERR_LD 4 /* Address error on a load or ifetch */
-#define T_ADDR_ERR_ST 5 /* Address error on a store */
-#define T_BUS_ERR_IFETCH 6 /* Bus error on an ifetch */
-#define T_BUS_ERR_LD_ST 7 /* Bus error on a load or store */
-#define T_SYSCALL 8 /* System call */
-#define T_BREAK 9 /* Breakpoint */
-#define T_RES_INST 10 /* Reserved instruction exception */
-#define T_COP_UNUSABLE 11 /* Coprocessor unusable */
-#define T_OVFLOW 12 /* Arithmetic overflow */
+#define T_INT 0 /* Interrupt pending */
+#define T_TLB_MOD 1 /* TLB modified fault */
+#define T_TLB_LD_MISS 2 /* TLB miss on load or ifetch */
+#define T_TLB_ST_MISS 3 /* TLB miss on a store */
+#define T_ADDR_ERR_LD 4 /* Address error on a load or ifetch */
+#define T_ADDR_ERR_ST 5 /* Address error on a store */
+#define T_BUS_ERR_IFETCH 6 /* Bus error on an ifetch */
+#define T_BUS_ERR_LD_ST 7 /* Bus error on a load or store */
+#define T_SYSCALL 8 /* System call */
+#define T_BREAK 9 /* Breakpoint */
+#define T_RES_INST 10 /* Reserved instruction exception */
+#define T_COP_UNUSABLE 11 /* Coprocessor unusable */
+#define T_OVFLOW 12 /* Arithmetic overflow */
/*
* Trap definitions added for r4000 port.
*/
-#define T_TRAP 13 /* Trap instruction */
-#define T_VCEI 14 /* Virtual coherency exception */
-#define T_FPE 15 /* Floating point exception */
-#define T_WATCH 23 /* Watch address reference */
-#define T_VCED 31 /* Virtual coherency data */
+#define T_TRAP 13 /* Trap instruction */
+#define T_VCEI 14 /* Virtual coherency exception */
+#define T_FPE 15 /* Floating point exception */
+#define T_WATCH 23 /* Watch address reference */
+#define T_VCED 31 /* Virtual coherency data */
/* Resume Flags */
-#define RESUME_FLAG_DR (1<<0) /* Reload guest nonvolatile state? */
-#define RESUME_FLAG_HOST (1<<1) /* Resume host? */
+#define RESUME_FLAG_DR (1<<0) /* Reload guest nonvolatile state? */
+#define RESUME_FLAG_HOST (1<<1) /* Resume host? */
-#define RESUME_GUEST 0
-#define RESUME_GUEST_DR RESUME_FLAG_DR
-#define RESUME_HOST RESUME_FLAG_HOST
+#define RESUME_GUEST 0
+#define RESUME_GUEST_DR RESUME_FLAG_DR
+#define RESUME_HOST RESUME_FLAG_HOST
enum emulation_result {
EMULATE_DONE, /* no further processing */
@@ -313,24 +313,27 @@ enum emulation_result {
EMULATE_PRIV_FAIL,
};
-#define MIPS3_PG_G 0x00000001 /* Global; ignore ASID if in lo0 & lo1 */
-#define MIPS3_PG_V 0x00000002 /* Valid */
-#define MIPS3_PG_NV 0x00000000
-#define MIPS3_PG_D 0x00000004 /* Dirty */
+#define MIPS3_PG_G 0x00000001 /* Global; ignore ASID if in lo0 & lo1 */
+#define MIPS3_PG_V 0x00000002 /* Valid */
+#define MIPS3_PG_NV 0x00000000
+#define MIPS3_PG_D 0x00000004 /* Dirty */
#define mips3_paddr_to_tlbpfn(x) \
- (((unsigned long)(x) >> MIPS3_PG_SHIFT) & MIPS3_PG_FRAME)
+ (((unsigned long)(x) >> MIPS3_PG_SHIFT) & MIPS3_PG_FRAME)
#define mips3_tlbpfn_to_paddr(x) \
- ((unsigned long)((x) & MIPS3_PG_FRAME) << MIPS3_PG_SHIFT)
+ ((unsigned long)((x) & MIPS3_PG_FRAME) << MIPS3_PG_SHIFT)
-#define MIPS3_PG_SHIFT 6
-#define MIPS3_PG_FRAME 0x3fffffc0
+#define MIPS3_PG_SHIFT 6
+#define MIPS3_PG_FRAME 0x3fffffc0
-#define VPN2_MASK 0xffffe000
-#define TLB_IS_GLOBAL(x) (((x).tlb_lo0 & MIPS3_PG_G) && ((x).tlb_lo1 & MIPS3_PG_G))
-#define TLB_VPN2(x) ((x).tlb_hi & VPN2_MASK)
-#define TLB_ASID(x) ((x).tlb_hi & ASID_MASK)
-#define TLB_IS_VALID(x, va) (((va) & (1 << PAGE_SHIFT)) ? ((x).tlb_lo1 & MIPS3_PG_V) : ((x).tlb_lo0 & MIPS3_PG_V))
+#define VPN2_MASK 0xffffe000
+#define TLB_IS_GLOBAL(x) (((x).tlb_lo0 & MIPS3_PG_G) && \
+ ((x).tlb_lo1 & MIPS3_PG_G))
+#define TLB_VPN2(x) ((x).tlb_hi & VPN2_MASK)
+#define TLB_ASID(x) ((x).tlb_hi & ASID_MASK)
+#define TLB_IS_VALID(x, va) (((va) & (1 << PAGE_SHIFT)) \
+ ? ((x).tlb_lo1 & MIPS3_PG_V) \
+ : ((x).tlb_lo0 & MIPS3_PG_V))
struct kvm_mips_tlb {
long tlb_mask;
@@ -339,7 +342,7 @@ struct kvm_mips_tlb {
long tlb_lo1;
};
-#define KVM_MIPS_GUEST_TLB_SIZE 64
+#define KVM_MIPS_GUEST_TLB_SIZE 64
struct kvm_vcpu_arch {
void *host_ebase, *guest_ebase;
unsigned long host_stack;
@@ -400,65 +403,67 @@ struct kvm_vcpu_arch {
};
-#define kvm_read_c0_guest_index(cop0) (cop0->reg[MIPS_CP0_TLB_INDEX][0])
-#define kvm_write_c0_guest_index(cop0, val) (cop0->reg[MIPS_CP0_TLB_INDEX][0] = val)
-#define kvm_read_c0_guest_entrylo0(cop0) (cop0->reg[MIPS_CP0_TLB_LO0][0])
-#define kvm_read_c0_guest_entrylo1(cop0) (cop0->reg[MIPS_CP0_TLB_LO1][0])
-#define kvm_read_c0_guest_context(cop0) (cop0->reg[MIPS_CP0_TLB_CONTEXT][0])
-#define kvm_write_c0_guest_context(cop0, val) (cop0->reg[MIPS_CP0_TLB_CONTEXT][0] = (val))
-#define kvm_read_c0_guest_userlocal(cop0) (cop0->reg[MIPS_CP0_TLB_CONTEXT][2])
-#define kvm_read_c0_guest_pagemask(cop0) (cop0->reg[MIPS_CP0_TLB_PG_MASK][0])
-#define kvm_write_c0_guest_pagemask(cop0, val) (cop0->reg[MIPS_CP0_TLB_PG_MASK][0] = (val))
-#define kvm_read_c0_guest_wired(cop0) (cop0->reg[MIPS_CP0_TLB_WIRED][0])
-#define kvm_write_c0_guest_wired(cop0, val) (cop0->reg[MIPS_CP0_TLB_WIRED][0] = (val))
-#define kvm_read_c0_guest_badvaddr(cop0) (cop0->reg[MIPS_CP0_BAD_VADDR][0])
-#define kvm_write_c0_guest_badvaddr(cop0, val) (cop0->reg[MIPS_CP0_BAD_VADDR][0] = (val))
-#define kvm_read_c0_guest_count(cop0) (cop0->reg[MIPS_CP0_COUNT][0])
-#define kvm_write_c0_guest_count(cop0, val) (cop0->reg[MIPS_CP0_COUNT][0] = (val))
-#define kvm_read_c0_guest_entryhi(cop0) (cop0->reg[MIPS_CP0_TLB_HI][0])
-#define kvm_write_c0_guest_entryhi(cop0, val) (cop0->reg[MIPS_CP0_TLB_HI][0] = (val))
-#define kvm_read_c0_guest_compare(cop0) (cop0->reg[MIPS_CP0_COMPARE][0])
-#define kvm_write_c0_guest_compare(cop0, val) (cop0->reg[MIPS_CP0_COMPARE][0] = (val))
-#define kvm_read_c0_guest_status(cop0) (cop0->reg[MIPS_CP0_STATUS][0])
-#define kvm_write_c0_guest_status(cop0, val) (cop0->reg[MIPS_CP0_STATUS][0] = (val))
-#define kvm_read_c0_guest_intctl(cop0) (cop0->reg[MIPS_CP0_STATUS][1])
-#define kvm_write_c0_guest_intctl(cop0, val) (cop0->reg[MIPS_CP0_STATUS][1] = (val))
-#define kvm_read_c0_guest_cause(cop0) (cop0->reg[MIPS_CP0_CAUSE][0])
-#define kvm_write_c0_guest_cause(cop0, val) (cop0->reg[MIPS_CP0_CAUSE][0] = (val))
-#define kvm_read_c0_guest_epc(cop0) (cop0->reg[MIPS_CP0_EXC_PC][0])
-#define kvm_write_c0_guest_epc(cop0, val) (cop0->reg[MIPS_CP0_EXC_PC][0] = (val))
-#define kvm_read_c0_guest_prid(cop0) (cop0->reg[MIPS_CP0_PRID][0])
-#define kvm_write_c0_guest_prid(cop0, val) (cop0->reg[MIPS_CP0_PRID][0] = (val))
-#define kvm_read_c0_guest_ebase(cop0) (cop0->reg[MIPS_CP0_PRID][1])
-#define kvm_write_c0_guest_ebase(cop0, val) (cop0->reg[MIPS_CP0_PRID][1] = (val))
-#define kvm_read_c0_guest_config(cop0) (cop0->reg[MIPS_CP0_CONFIG][0])
-#define kvm_read_c0_guest_config1(cop0) (cop0->reg[MIPS_CP0_CONFIG][1])
-#define kvm_read_c0_guest_config2(cop0) (cop0->reg[MIPS_CP0_CONFIG][2])
-#define kvm_read_c0_guest_config3(cop0) (cop0->reg[MIPS_CP0_CONFIG][3])
-#define kvm_read_c0_guest_config7(cop0) (cop0->reg[MIPS_CP0_CONFIG][7])
-#define kvm_write_c0_guest_config(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][0] = (val))
-#define kvm_write_c0_guest_config1(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][1] = (val))
-#define kvm_write_c0_guest_config2(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][2] = (val))
-#define kvm_write_c0_guest_config3(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][3] = (val))
-#define kvm_write_c0_guest_config7(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][7] = (val))
-#define kvm_read_c0_guest_errorepc(cop0) (cop0->reg[MIPS_CP0_ERROR_PC][0])
-#define kvm_write_c0_guest_errorepc(cop0, val) (cop0->reg[MIPS_CP0_ERROR_PC][0] = (val))
-
-#define kvm_set_c0_guest_status(cop0, val) (cop0->reg[MIPS_CP0_STATUS][0] |= (val))
-#define kvm_clear_c0_guest_status(cop0, val) (cop0->reg[MIPS_CP0_STATUS][0] &= ~(val))
-#define kvm_set_c0_guest_cause(cop0, val) (cop0->reg[MIPS_CP0_CAUSE][0] |= (val))
-#define kvm_clear_c0_guest_cause(cop0, val) (cop0->reg[MIPS_CP0_CAUSE][0] &= ~(val))
-#define kvm_change_c0_guest_cause(cop0, change, val) \
-{ \
- kvm_clear_c0_guest_cause(cop0, change); \
- kvm_set_c0_guest_cause(cop0, ((val) & (change))); \
+#define kvm_read_c0_guest_index(cop0) (cop0->reg[MIPS_CP0_TLB_INDEX][0])
+#define kvm_write_c0_guest_index(cop0, val) (cop0->reg[MIPS_CP0_TLB_INDEX][0] = val)
+#define kvm_read_c0_guest_entrylo0(cop0) (cop0->reg[MIPS_CP0_TLB_LO0][0])
+#define kvm_read_c0_guest_entrylo1(cop0) (cop0->reg[MIPS_CP0_TLB_LO1][0])
+#define kvm_read_c0_guest_context(cop0) (cop0->reg[MIPS_CP0_TLB_CONTEXT][0])
+#define kvm_write_c0_guest_context(cop0, val) (cop0->reg[MIPS_CP0_TLB_CONTEXT][0] = (val))
+#define kvm_read_c0_guest_userlocal(cop0) (cop0->reg[MIPS_CP0_TLB_CONTEXT][2])
+#define kvm_read_c0_guest_pagemask(cop0) (cop0->reg[MIPS_CP0_TLB_PG_MASK][0])
+#define kvm_write_c0_guest_pagemask(cop0, val) (cop0->reg[MIPS_CP0_TLB_PG_MASK][0] = (val))
+#define kvm_read_c0_guest_wired(cop0) (cop0->reg[MIPS_CP0_TLB_WIRED][0])
+#define kvm_write_c0_guest_wired(cop0, val) (cop0->reg[MIPS_CP0_TLB_WIRED][0] = (val))
+#define kvm_read_c0_guest_hwrena(cop0) (cop0->reg[MIPS_CP0_HWRENA][0])
+#define kvm_write_c0_guest_hwrena(cop0, val) (cop0->reg[MIPS_CP0_HWRENA][0] = (val))
+#define kvm_read_c0_guest_badvaddr(cop0) (cop0->reg[MIPS_CP0_BAD_VADDR][0])
+#define kvm_write_c0_guest_badvaddr(cop0, val) (cop0->reg[MIPS_CP0_BAD_VADDR][0] = (val))
+#define kvm_read_c0_guest_count(cop0) (cop0->reg[MIPS_CP0_COUNT][0])
+#define kvm_write_c0_guest_count(cop0, val) (cop0->reg[MIPS_CP0_COUNT][0] = (val))
+#define kvm_read_c0_guest_entryhi(cop0) (cop0->reg[MIPS_CP0_TLB_HI][0])
+#define kvm_write_c0_guest_entryhi(cop0, val) (cop0->reg[MIPS_CP0_TLB_HI][0] = (val))
+#define kvm_read_c0_guest_compare(cop0) (cop0->reg[MIPS_CP0_COMPARE][0])
+#define kvm_write_c0_guest_compare(cop0, val) (cop0->reg[MIPS_CP0_COMPARE][0] = (val))
+#define kvm_read_c0_guest_status(cop0) (cop0->reg[MIPS_CP0_STATUS][0])
+#define kvm_write_c0_guest_status(cop0, val) (cop0->reg[MIPS_CP0_STATUS][0] = (val))
+#define kvm_read_c0_guest_intctl(cop0) (cop0->reg[MIPS_CP0_STATUS][1])
+#define kvm_write_c0_guest_intctl(cop0, val) (cop0->reg[MIPS_CP0_STATUS][1] = (val))
+#define kvm_read_c0_guest_cause(cop0) (cop0->reg[MIPS_CP0_CAUSE][0])
+#define kvm_write_c0_guest_cause(cop0, val) (cop0->reg[MIPS_CP0_CAUSE][0] = (val))
+#define kvm_read_c0_guest_epc(cop0) (cop0->reg[MIPS_CP0_EXC_PC][0])
+#define kvm_write_c0_guest_epc(cop0, val) (cop0->reg[MIPS_CP0_EXC_PC][0] = (val))
+#define kvm_read_c0_guest_prid(cop0) (cop0->reg[MIPS_CP0_PRID][0])
+#define kvm_write_c0_guest_prid(cop0, val) (cop0->reg[MIPS_CP0_PRID][0] = (val))
+#define kvm_read_c0_guest_ebase(cop0) (cop0->reg[MIPS_CP0_PRID][1])
+#define kvm_write_c0_guest_ebase(cop0, val) (cop0->reg[MIPS_CP0_PRID][1] = (val))
+#define kvm_read_c0_guest_config(cop0) (cop0->reg[MIPS_CP0_CONFIG][0])
+#define kvm_read_c0_guest_config1(cop0) (cop0->reg[MIPS_CP0_CONFIG][1])
+#define kvm_read_c0_guest_config2(cop0) (cop0->reg[MIPS_CP0_CONFIG][2])
+#define kvm_read_c0_guest_config3(cop0) (cop0->reg[MIPS_CP0_CONFIG][3])
+#define kvm_read_c0_guest_config7(cop0) (cop0->reg[MIPS_CP0_CONFIG][7])
+#define kvm_write_c0_guest_config(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][0] = (val))
+#define kvm_write_c0_guest_config1(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][1] = (val))
+#define kvm_write_c0_guest_config2(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][2] = (val))
+#define kvm_write_c0_guest_config3(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][3] = (val))
+#define kvm_write_c0_guest_config7(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][7] = (val))
+#define kvm_read_c0_guest_errorepc(cop0) (cop0->reg[MIPS_CP0_ERROR_PC][0])
+#define kvm_write_c0_guest_errorepc(cop0, val) (cop0->reg[MIPS_CP0_ERROR_PC][0] = (val))
+
+#define kvm_set_c0_guest_status(cop0, val) (cop0->reg[MIPS_CP0_STATUS][0] |= (val))
+#define kvm_clear_c0_guest_status(cop0, val) (cop0->reg[MIPS_CP0_STATUS][0] &= ~(val))
+#define kvm_set_c0_guest_cause(cop0, val) (cop0->reg[MIPS_CP0_CAUSE][0] |= (val))
+#define kvm_clear_c0_guest_cause(cop0, val) (cop0->reg[MIPS_CP0_CAUSE][0] &= ~(val))
+#define kvm_change_c0_guest_cause(cop0, change, val) \
+{ \
+ kvm_clear_c0_guest_cause(cop0, change); \
+ kvm_set_c0_guest_cause(cop0, ((val) & (change))); \
}
-#define kvm_set_c0_guest_ebase(cop0, val) (cop0->reg[MIPS_CP0_PRID][1] |= (val))
-#define kvm_clear_c0_guest_ebase(cop0, val) (cop0->reg[MIPS_CP0_PRID][1] &= ~(val))
-#define kvm_change_c0_guest_ebase(cop0, change, val) \
-{ \
- kvm_clear_c0_guest_ebase(cop0, change); \
- kvm_set_c0_guest_ebase(cop0, ((val) & (change))); \
+#define kvm_set_c0_guest_ebase(cop0, val) (cop0->reg[MIPS_CP0_PRID][1] |= (val))
+#define kvm_clear_c0_guest_ebase(cop0, val) (cop0->reg[MIPS_CP0_PRID][1] &= ~(val))
+#define kvm_change_c0_guest_ebase(cop0, change, val) \
+{ \
+ kvm_clear_c0_guest_ebase(cop0, change); \
+ kvm_set_c0_guest_ebase(cop0, ((val) & (change))); \
}
diff --git a/arch/mips/include/asm/local.h b/arch/mips/include/asm/local.h
index d44622cd74be..46dfc3c1fd49 100644
--- a/arch/mips/include/asm/local.h
+++ b/arch/mips/include/asm/local.h
@@ -33,7 +33,7 @@ static __inline__ long local_add_return(long i, local_t * l)
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1:" __LL "%1, %2 # local_add_return \n"
" addu %0, %1, %3 \n"
__SC "%0, %2 \n"
@@ -47,7 +47,7 @@ static __inline__ long local_add_return(long i, local_t * l)
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1:" __LL "%1, %2 # local_add_return \n"
" addu %0, %1, %3 \n"
__SC "%0, %2 \n"
@@ -78,7 +78,7 @@ static __inline__ long local_sub_return(long i, local_t * l)
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1:" __LL "%1, %2 # local_sub_return \n"
" subu %0, %1, %3 \n"
__SC "%0, %2 \n"
@@ -92,7 +92,7 @@ static __inline__ long local_sub_return(long i, local_t * l)
unsigned long temp;
__asm__ __volatile__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1:" __LL "%1, %2 # local_sub_return \n"
" subu %0, %1, %3 \n"
__SC "%0, %2 \n"
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index 54f9e84db8ac..b4c3ecb17d48 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -1161,18 +1161,6 @@ enum soc_au1200_ints {
#define MAC_RX_BUFF3_STATUS 0x30
#define MAC_RX_BUFF3_ADDR 0x34
-#define UART_RX 0 /* Receive buffer */
-#define UART_TX 4 /* Transmit buffer */
-#define UART_IER 8 /* Interrupt Enable Register */
-#define UART_IIR 0xC /* Interrupt ID Register */
-#define UART_FCR 0x10 /* FIFO Control Register */
-#define UART_LCR 0x14 /* Line Control Register */
-#define UART_MCR 0x18 /* Modem Control Register */
-#define UART_LSR 0x1C /* Line Status Register */
-#define UART_MSR 0x20 /* Modem Status Register */
-#define UART_CLK 0x28 /* Baud Rate Clock Divider */
-#define UART_MOD_CNTRL 0x100 /* Module Control */
-
/* SSIO */
#define SSI0_STATUS 0xB1600000
# define SSI_STATUS_BF (1 << 4)
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h
index 40005fb39618..bba7399a49a3 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h
@@ -27,7 +27,11 @@ enum bcm47xx_board {
BCM47XX_BOARD_ASUS_WL700GE,
BCM47XX_BOARD_ASUS_WLHDD,
+ BCM47XX_BOARD_BELKIN_F7D3301,
+ BCM47XX_BOARD_BELKIN_F7D3302,
BCM47XX_BOARD_BELKIN_F7D4301,
+ BCM47XX_BOARD_BELKIN_F7D4302,
+ BCM47XX_BOARD_BELKIN_F7D4401,
BCM47XX_BOARD_BUFFALO_WBR2_G54,
BCM47XX_BOARD_BUFFALO_WHR2_A54G54,
@@ -66,7 +70,7 @@ enum bcm47xx_board {
BCM47XX_BOARD_LINKSYS_WRT310NV1,
BCM47XX_BOARD_LINKSYS_WRT310NV2,
BCM47XX_BOARD_LINKSYS_WRT54G3GV2,
- BCM47XX_BOARD_LINKSYS_WRT54GSV1,
+ BCM47XX_BOARD_LINKSYS_WRT54G,
BCM47XX_BOARD_LINKSYS_WRT610NV1,
BCM47XX_BOARD_LINKSYS_WRT610NV2,
BCM47XX_BOARD_LINKSYS_WRTSL54GS,
@@ -94,6 +98,8 @@ enum bcm47xx_board {
BCM47XX_BOARD_PHICOMM_M1,
+ BCM47XX_BOARD_SIEMENS_SE505V2,
+
BCM47XX_BOARD_SIMPLETECH_SIMPLESHARE,
BCM47XX_BOARD_ZTE_H218N,
diff --git a/arch/mips/include/asm/mach-db1x00/db1200.h b/arch/mips/include/asm/mach-db1x00/db1200.h
deleted file mode 100644
index d3cce7326dd4..000000000000
--- a/arch/mips/include/asm/mach-db1x00/db1200.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * AMD Alchemy DBAu1200 Reference Board
- * Board register defines.
- *
- * ########################################################################
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- *
- */
-#ifndef __ASM_DB1200_H
-#define __ASM_DB1200_H
-
-#include <linux/types.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1xxx_psc.h>
-
-/* Bit positions for the different interrupt sources */
-#define BCSR_INT_IDE 0x0001
-#define BCSR_INT_ETH 0x0002
-#define BCSR_INT_PC0 0x0004
-#define BCSR_INT_PC0STSCHG 0x0008
-#define BCSR_INT_PC1 0x0010
-#define BCSR_INT_PC1STSCHG 0x0020
-#define BCSR_INT_DC 0x0040
-#define BCSR_INT_FLASHBUSY 0x0080
-#define BCSR_INT_PC0INSERT 0x0100
-#define BCSR_INT_PC0EJECT 0x0200
-#define BCSR_INT_PC1INSERT 0x0400
-#define BCSR_INT_PC1EJECT 0x0800
-#define BCSR_INT_SD0INSERT 0x1000
-#define BCSR_INT_SD0EJECT 0x2000
-#define BCSR_INT_SD1INSERT 0x4000
-#define BCSR_INT_SD1EJECT 0x8000
-
-#define IDE_REG_SHIFT 5
-
-#define DB1200_IDE_PHYS_ADDR 0x18800000
-#define DB1200_IDE_PHYS_LEN (16 << IDE_REG_SHIFT)
-#define DB1200_ETH_PHYS_ADDR 0x19000300
-#define DB1200_NAND_PHYS_ADDR 0x20000000
-
-#define PB1200_IDE_PHYS_ADDR 0x0C800000
-#define PB1200_ETH_PHYS_ADDR 0x0D000300
-#define PB1200_NAND_PHYS_ADDR 0x1C000000
-
-/*
- * External Interrupts for DBAu1200 as of 8/6/2004.
- * Bit positions in the CPLD registers can be calculated by taking
- * the interrupt define and subtracting the DB1200_INT_BEGIN value.
- *
- * Example: IDE bis pos is = 64 - 64
- * ETH bit pos is = 65 - 64
- */
-enum external_db1200_ints {
- DB1200_INT_BEGIN = AU1000_MAX_INTR + 1,
-
- DB1200_IDE_INT = DB1200_INT_BEGIN,
- DB1200_ETH_INT,
- DB1200_PC0_INT,
- DB1200_PC0_STSCHG_INT,
- DB1200_PC1_INT,
- DB1200_PC1_STSCHG_INT,
- DB1200_DC_INT,
- DB1200_FLASHBUSY_INT,
- DB1200_PC0_INSERT_INT,
- DB1200_PC0_EJECT_INT,
- DB1200_PC1_INSERT_INT,
- DB1200_PC1_EJECT_INT,
- DB1200_SD0_INSERT_INT,
- DB1200_SD0_EJECT_INT,
- PB1200_SD1_INSERT_INT,
- PB1200_SD1_EJECT_INT,
-
- DB1200_INT_END = DB1200_INT_BEGIN + 15,
-};
-
-#endif /* __ASM_DB1200_H */
diff --git a/arch/mips/include/asm/mach-db1x00/db1300.h b/arch/mips/include/asm/mach-db1x00/db1300.h
deleted file mode 100644
index 3d1ede46f059..000000000000
--- a/arch/mips/include/asm/mach-db1x00/db1300.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * NetLogic DB1300 board constants
- */
-
-#ifndef _DB1300_H_
-#define _DB1300_H_
-
-/* FPGA (external mux) interrupt sources */
-#define DB1300_FIRST_INT (ALCHEMY_GPIC_INT_LAST + 1)
-#define DB1300_IDE_INT (DB1300_FIRST_INT + 0)
-#define DB1300_ETH_INT (DB1300_FIRST_INT + 1)
-#define DB1300_CF_INT (DB1300_FIRST_INT + 2)
-#define DB1300_VIDEO_INT (DB1300_FIRST_INT + 4)
-#define DB1300_HDMI_INT (DB1300_FIRST_INT + 5)
-#define DB1300_DC_INT (DB1300_FIRST_INT + 6)
-#define DB1300_FLASH_INT (DB1300_FIRST_INT + 7)
-#define DB1300_CF_INSERT_INT (DB1300_FIRST_INT + 8)
-#define DB1300_CF_EJECT_INT (DB1300_FIRST_INT + 9)
-#define DB1300_AC97_INT (DB1300_FIRST_INT + 10)
-#define DB1300_AC97_PEN_INT (DB1300_FIRST_INT + 11)
-#define DB1300_SD1_INSERT_INT (DB1300_FIRST_INT + 12)
-#define DB1300_SD1_EJECT_INT (DB1300_FIRST_INT + 13)
-#define DB1300_OTG_VBUS_OC_INT (DB1300_FIRST_INT + 14)
-#define DB1300_HOST_VBUS_OC_INT (DB1300_FIRST_INT + 15)
-#define DB1300_LAST_INT (DB1300_FIRST_INT + 15)
-
-/* SMSC9210 CS */
-#define DB1300_ETH_PHYS_ADDR 0x19000000
-#define DB1300_ETH_PHYS_END 0x197fffff
-
-/* ATA CS */
-#define DB1300_IDE_PHYS_ADDR 0x18800000
-#define DB1300_IDE_REG_SHIFT 5
-#define DB1300_IDE_PHYS_LEN (16 << DB1300_IDE_REG_SHIFT)
-
-/* NAND CS */
-#define DB1300_NAND_PHYS_ADDR 0x20000000
-#define DB1300_NAND_PHYS_END 0x20000fff
-
-#endif /* _DB1300_H_ */
diff --git a/arch/mips/include/asm/mach-loongson/boot_param.h b/arch/mips/include/asm/mach-loongson/boot_param.h
new file mode 100644
index 000000000000..829a7ec185fb
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson/boot_param.h
@@ -0,0 +1,163 @@
+#ifndef __ASM_MACH_LOONGSON_BOOT_PARAM_H_
+#define __ASM_MACH_LOONGSON_BOOT_PARAM_H_
+
+#define SYSTEM_RAM_LOW 1
+#define SYSTEM_RAM_HIGH 2
+#define MEM_RESERVED 3
+#define PCI_IO 4
+#define PCI_MEM 5
+#define LOONGSON_CFG_REG 6
+#define VIDEO_ROM 7
+#define ADAPTER_ROM 8
+#define ACPI_TABLE 9
+#define MAX_MEMORY_TYPE 10
+
+#define LOONGSON3_BOOT_MEM_MAP_MAX 128
+struct efi_memory_map_loongson {
+ u16 vers; /* version of efi_memory_map */
+ u32 nr_map; /* number of memory_maps */
+ u32 mem_freq; /* memory frequence */
+ struct mem_map {
+ u32 node_id; /* node_id which memory attached to */
+ u32 mem_type; /* system memory, pci memory, pci io, etc. */
+ u64 mem_start; /* memory map start address */
+ u32 mem_size; /* each memory_map size, not the total size */
+ } map[LOONGSON3_BOOT_MEM_MAP_MAX];
+} __packed;
+
+enum loongson_cpu_type {
+ Loongson_2E = 0,
+ Loongson_2F = 1,
+ Loongson_3A = 2,
+ Loongson_3B = 3,
+ Loongson_1A = 4,
+ Loongson_1B = 5
+};
+
+/*
+ * Capability and feature descriptor structure for MIPS CPU
+ */
+struct efi_cpuinfo_loongson {
+ u16 vers; /* version of efi_cpuinfo_loongson */
+ u32 processor_id; /* PRID, e.g. 6305, 6306 */
+ u32 cputype; /* Loongson_3A/3B, etc. */
+ u32 total_node; /* num of total numa nodes */
+ u32 cpu_startup_core_id; /* Core id */
+ u32 cpu_clock_freq; /* cpu_clock */
+ u32 nr_cpus;
+} __packed;
+
+struct system_loongson {
+ u16 vers; /* version of system_loongson */
+ u32 ccnuma_smp; /* 0: no numa; 1: has numa */
+ u32 sing_double_channel; /* 1:single; 2:double */
+} __packed;
+
+struct irq_source_routing_table {
+ u16 vers;
+ u16 size;
+ u16 rtr_bus;
+ u16 rtr_devfn;
+ u32 vendor;
+ u32 device;
+ u32 PIC_type; /* conform use HT or PCI to route to CPU-PIC */
+ u64 ht_int_bit; /* 3A: 1<<24; 3B: 1<<16 */
+ u64 ht_enable; /* irqs used in this PIC */
+ u32 node_id; /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */
+ u64 pci_mem_start_addr;
+ u64 pci_mem_end_addr;
+ u64 pci_io_start_addr;
+ u64 pci_io_end_addr;
+ u64 pci_config_addr;
+ u32 dma_mask_bits;
+} __packed;
+
+struct interface_info {
+ u16 vers; /* version of the specificition */
+ u16 size;
+ u8 flag;
+ char description[64];
+} __packed;
+
+#define MAX_RESOURCE_NUMBER 128
+struct resource_loongson {
+ u64 start; /* resource start address */
+ u64 end; /* resource end address */
+ char name[64];
+ u32 flags;
+};
+
+struct archdev_data {}; /* arch specific additions */
+
+struct board_devices {
+ char name[64]; /* hold the device name */
+ u32 num_resources; /* number of device_resource */
+ /* for each device's resource */
+ struct resource_loongson resource[MAX_RESOURCE_NUMBER];
+ /* arch specific additions */
+ struct archdev_data archdata;
+};
+
+struct loongson_special_attribute {
+ u16 vers; /* version of this special */
+ char special_name[64]; /* special_atribute_name */
+ u32 loongson_special_type; /* type of special device */
+ /* for each device's resource */
+ struct resource_loongson resource[MAX_RESOURCE_NUMBER];
+};
+
+struct loongson_params {
+ u64 memory_offset; /* efi_memory_map_loongson struct offset */
+ u64 cpu_offset; /* efi_cpuinfo_loongson struct offset */
+ u64 system_offset; /* system_loongson struct offset */
+ u64 irq_offset; /* irq_source_routing_table struct offset */
+ u64 interface_offset; /* interface_info struct offset */
+ u64 special_offset; /* loongson_special_attribute struct offset */
+ u64 boarddev_table_offset; /* board_devices offset */
+};
+
+struct smbios_tables {
+ u16 vers; /* version of smbios */
+ u64 vga_bios; /* vga_bios address */
+ struct loongson_params lp;
+};
+
+struct efi_reset_system_t {
+ u64 ResetCold;
+ u64 ResetWarm;
+ u64 ResetType;
+ u64 Shutdown;
+ u64 DoSuspend; /* NULL if not support */
+};
+
+struct efi_loongson {
+ u64 mps; /* MPS table */
+ u64 acpi; /* ACPI table (IA64 ext 0.71) */
+ u64 acpi20; /* ACPI table (ACPI 2.0) */
+ struct smbios_tables smbios; /* SM BIOS table */
+ u64 sal_systab; /* SAL system table */
+ u64 boot_info; /* boot info table */
+};
+
+struct boot_params {
+ struct efi_loongson efi;
+ struct efi_reset_system_t reset_system;
+};
+
+struct loongson_system_configuration {
+ u32 nr_cpus;
+ enum loongson_cpu_type cputype;
+ u64 ht_control_base;
+ u64 pci_mem_start_addr;
+ u64 pci_mem_end_addr;
+ u64 pci_io_base;
+ u64 restart_addr;
+ u64 poweroff_addr;
+ u64 suspend_addr;
+ u64 vgabios_addr;
+ u32 dma_mask_bits;
+};
+
+extern struct efi_memory_map_loongson *loongson_memmap;
+extern struct loongson_system_configuration loongson_sysconf;
+#endif
diff --git a/arch/mips/include/asm/mach-loongson/dma-coherence.h b/arch/mips/include/asm/mach-loongson/dma-coherence.h
index aeb2c05d6145..6a902751cc7f 100644
--- a/arch/mips/include/asm/mach-loongson/dma-coherence.h
+++ b/arch/mips/include/asm/mach-loongson/dma-coherence.h
@@ -11,24 +11,40 @@
#ifndef __ASM_MACH_LOONGSON_DMA_COHERENCE_H
#define __ASM_MACH_LOONGSON_DMA_COHERENCE_H
+#ifdef CONFIG_SWIOTLB
+#include <linux/swiotlb.h>
+#endif
+
struct device;
+extern dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr);
+extern phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr);
static inline dma_addr_t plat_map_dma_mem(struct device *dev, void *addr,
size_t size)
{
+#ifdef CONFIG_CPU_LOONGSON3
+ return virt_to_phys(addr);
+#else
return virt_to_phys(addr) | 0x80000000;
+#endif
}
static inline dma_addr_t plat_map_dma_mem_page(struct device *dev,
struct page *page)
{
+#ifdef CONFIG_CPU_LOONGSON3
+ return page_to_phys(page);
+#else
return page_to_phys(page) | 0x80000000;
+#endif
}
static inline unsigned long plat_dma_addr_to_phys(struct device *dev,
dma_addr_t dma_addr)
{
-#if defined(CONFIG_CPU_LOONGSON2F) && defined(CONFIG_64BIT)
+#if defined(CONFIG_CPU_LOONGSON3) && defined(CONFIG_64BIT)
+ return dma_addr;
+#elif defined(CONFIG_CPU_LOONGSON2F) && defined(CONFIG_64BIT)
return (dma_addr > 0x8fffffff) ? dma_addr : (dma_addr & 0x0fffffff);
#else
return dma_addr & 0x7fffffff;
@@ -55,7 +71,11 @@ static inline int plat_dma_supported(struct device *dev, u64 mask)
static inline int plat_device_is_coherent(struct device *dev)
{
+#ifdef CONFIG_DMA_NONCOHERENT
return 0;
+#else
+ return 1;
+#endif /* CONFIG_DMA_NONCOHERENT */
}
#endif /* __ASM_MACH_LOONGSON_DMA_COHERENCE_H */
diff --git a/arch/mips/include/asm/mach-loongson/irq.h b/arch/mips/include/asm/mach-loongson/irq.h
new file mode 100644
index 000000000000..34560bda6626
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson/irq.h
@@ -0,0 +1,44 @@
+#ifndef __ASM_MACH_LOONGSON_IRQ_H_
+#define __ASM_MACH_LOONGSON_IRQ_H_
+
+#include <boot_param.h>
+
+#ifdef CONFIG_CPU_LOONGSON3
+
+/* cpu core interrupt numbers */
+#define MIPS_CPU_IRQ_BASE 56
+
+#define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 2) /* UART */
+#define LOONGSON_HT1_IRQ (MIPS_CPU_IRQ_BASE + 3) /* HT1 */
+#define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* CPU Timer */
+
+#define LOONGSON_HT1_CFG_BASE loongson_sysconf.ht_control_base
+#define LOONGSON_HT1_INT_VECTOR_BASE (LOONGSON_HT1_CFG_BASE + 0x80)
+#define LOONGSON_HT1_INT_EN_BASE (LOONGSON_HT1_CFG_BASE + 0xa0)
+#define LOONGSON_HT1_INT_VECTOR(n) \
+ LOONGSON3_REG32(LOONGSON_HT1_INT_VECTOR_BASE, 4 * (n))
+#define LOONGSON_HT1_INTN_EN(n) \
+ LOONGSON3_REG32(LOONGSON_HT1_INT_EN_BASE, 4 * (n))
+
+#define LOONGSON_INT_ROUTER_OFFSET 0x1400
+#define LOONGSON_INT_ROUTER_INTEN \
+ LOONGSON3_REG32(LOONGSON3_REG_BASE, LOONGSON_INT_ROUTER_OFFSET + 0x24)
+#define LOONGSON_INT_ROUTER_INTENSET \
+ LOONGSON3_REG32(LOONGSON3_REG_BASE, LOONGSON_INT_ROUTER_OFFSET + 0x28)
+#define LOONGSON_INT_ROUTER_INTENCLR \
+ LOONGSON3_REG32(LOONGSON3_REG_BASE, LOONGSON_INT_ROUTER_OFFSET + 0x2c)
+#define LOONGSON_INT_ROUTER_ENTRY(n) \
+ LOONGSON3_REG8(LOONGSON3_REG_BASE, LOONGSON_INT_ROUTER_OFFSET + n)
+#define LOONGSON_INT_ROUTER_LPC LOONGSON_INT_ROUTER_ENTRY(0x0a)
+#define LOONGSON_INT_ROUTER_HT1(n) LOONGSON_INT_ROUTER_ENTRY(n + 0x18)
+
+#define LOONGSON_INT_CORE0_INT0 0x11 /* route to int 0 of core 0 */
+#define LOONGSON_INT_CORE0_INT1 0x21 /* route to int 1 of core 0 */
+
+#endif
+
+extern void fixup_irqs(void);
+extern void loongson3_ipi_interrupt(struct pt_regs *regs);
+
+#include_next <irq.h>
+#endif /* __ASM_MACH_LOONGSON_IRQ_H_ */
diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
index b286534fef08..f3fd1eb8e3dd 100644
--- a/arch/mips/include/asm/mach-loongson/loongson.h
+++ b/arch/mips/include/asm/mach-loongson/loongson.h
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/kconfig.h>
+#include <boot_param.h>
/* loongson internal northbridge initialization */
extern void bonito_irq_init(void);
@@ -24,8 +25,9 @@ extern void mach_prepare_reboot(void);
extern void mach_prepare_shutdown(void);
/* environment arguments from bootloader */
-extern unsigned long cpu_clock_freq;
-extern unsigned long memsize, highmemsize;
+extern u32 cpu_clock_freq;
+extern u32 memsize, highmemsize;
+extern struct plat_smp_ops loongson3_smp_ops;
/* loongson-specific command line, env and memory initialization */
extern void __init prom_init_memory(void);
@@ -61,6 +63,12 @@ extern int mach_i8259_irq(void);
#define LOONGSON_REG(x) \
(*(volatile u32 *)((char *)CKSEG1ADDR(LOONGSON_REG_BASE) + (x)))
+#define LOONGSON3_REG8(base, x) \
+ (*(volatile u8 *)((char *)TO_UNCAC(base) + (x)))
+
+#define LOONGSON3_REG32(base, x) \
+ (*(volatile u32 *)((char *)TO_UNCAC(base) + (x)))
+
#define LOONGSON_IRQ_BASE 32
#define LOONGSON2_PERFCNT_IRQ (MIPS_CPU_IRQ_BASE + 6) /* cpu perf counter */
@@ -86,6 +94,10 @@ static inline void do_perfcnt_IRQ(void)
#define LOONGSON_REG_BASE 0x1fe00000
#define LOONGSON_REG_SIZE 0x00100000 /* 256Bytes + 256Bytes + ??? */
#define LOONGSON_REG_TOP (LOONGSON_REG_BASE+LOONGSON_REG_SIZE-1)
+/* Loongson-3 specific registers */
+#define LOONGSON3_REG_BASE 0x3ff00000
+#define LOONGSON3_REG_SIZE 0x00100000 /* 256Bytes + 256Bytes + ??? */
+#define LOONGSON3_REG_TOP (LOONGSON3_REG_BASE+LOONGSON3_REG_SIZE-1)
#define LOONGSON_LIO1_BASE 0x1ff00000
#define LOONGSON_LIO1_SIZE 0x00100000 /* 1M */
@@ -101,7 +113,13 @@ static inline void do_perfcnt_IRQ(void)
#define LOONGSON_PCICFG_BASE 0x1fe80000
#define LOONGSON_PCICFG_SIZE 0x00000800 /* 2K */
#define LOONGSON_PCICFG_TOP (LOONGSON_PCICFG_BASE+LOONGSON_PCICFG_SIZE-1)
+
+#if defined(CONFIG_HT_PCI)
+#define LOONGSON_PCIIO_BASE loongson_sysconf.pci_io_base
+#else
#define LOONGSON_PCIIO_BASE 0x1fd00000
+#endif
+
#define LOONGSON_PCIIO_SIZE 0x00100000 /* 1M */
#define LOONGSON_PCIIO_TOP (LOONGSON_PCIIO_BASE+LOONGSON_PCIIO_SIZE-1)
@@ -231,6 +249,9 @@ static inline void do_perfcnt_IRQ(void)
#define LOONGSON_PXARB_CFG LOONGSON_REG(LOONGSON_REGBASE + 0x68)
#define LOONGSON_PXARB_STATUS LOONGSON_REG(LOONGSON_REGBASE + 0x6c)
+/* Chip Config */
+#define LOONGSON_CHIPCFG0 LOONGSON_REG(LOONGSON_REGBASE + 0x80)
+
/* pcimap */
#define LOONGSON_PCIMAP_PCIMAP_LO0 0x0000003f
@@ -246,9 +267,6 @@ static inline void do_perfcnt_IRQ(void)
#ifdef CONFIG_CPU_SUPPORTS_CPUFREQ
#include <linux/cpufreq.h>
extern struct cpufreq_frequency_table loongson2_clockmod_table[];
-
-/* Chip Config */
-#define LOONGSON_CHIPCFG0 LOONGSON_REG(LOONGSON_REGBASE + 0x80)
#endif
/*
diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h
index 3810d5ca84ac..1b1f592fa2be 100644
--- a/arch/mips/include/asm/mach-loongson/machine.h
+++ b/arch/mips/include/asm/mach-loongson/machine.h
@@ -24,4 +24,10 @@
#endif
+#ifdef CONFIG_LEMOTE_MACH3A
+
+#define LOONGSON_MACHTYPE MACH_LEMOTE_A1101
+
+#endif /* CONFIG_LEMOTE_MACH3A */
+
#endif /* __ASM_MACH_LOONGSON_MACHINE_H */
diff --git a/arch/mips/include/asm/mach-loongson/pci.h b/arch/mips/include/asm/mach-loongson/pci.h
index bc99dab4ef63..1212774f66ef 100644
--- a/arch/mips/include/asm/mach-loongson/pci.h
+++ b/arch/mips/include/asm/mach-loongson/pci.h
@@ -40,8 +40,13 @@ extern struct pci_ops loongson_pci_ops;
#else /* loongson2f/32bit & loongson2e */
/* this pci memory space is mapped by pcimap in pci.c */
+#ifdef CONFIG_CPU_LOONGSON3
+#define LOONGSON_PCI_MEM_START 0x40000000UL
+#define LOONGSON_PCI_MEM_END 0x7effffffUL
+#else
#define LOONGSON_PCI_MEM_START LOONGSON_PCILO1_BASE
#define LOONGSON_PCI_MEM_END (LOONGSON_PCILO1_BASE + 0x04000000 * 2)
+#endif
/* this is an offset from mips_io_port_base */
#define LOONGSON_PCI_IO_START 0x00004000UL
diff --git a/arch/mips/include/asm/mach-loongson/spaces.h b/arch/mips/include/asm/mach-loongson/spaces.h
new file mode 100644
index 000000000000..e2506ee90044
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson/spaces.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_MACH_LOONGSON_SPACES_H_
+#define __ASM_MACH_LOONGSON_SPACES_H_
+
+#if defined(CONFIG_64BIT)
+#define CAC_BASE _AC(0x9800000000000000, UL)
+#endif /* CONFIG_64BIT */
+
+#include <asm/mach-generic/spaces.h>
+#endif
diff --git a/arch/mips/include/asm/mach-malta/kernel-entry-init.h b/arch/mips/include/asm/mach-malta/kernel-entry-init.h
index 0b793e7bf67e..7c5e17a17849 100644
--- a/arch/mips/include/asm/mach-malta/kernel-entry-init.h
+++ b/arch/mips/include/asm/mach-malta/kernel-entry-init.h
@@ -5,10 +5,80 @@
*
* Chris Dearman (chris@mips.com)
* Copyright (C) 2007 Mips Technologies, Inc.
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*/
#ifndef __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H
#define __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H
+ /*
+ * Prepare segments for EVA boot:
+ *
+ * This is in case the processor boots in legacy configuration
+ * (SI_EVAReset is de-asserted and CONFIG5.K == 0)
+ *
+ * On entry, t1 is loaded with CP0_CONFIG
+ *
+ * ========================= Mappings =============================
+ * Virtual memory Physical memory Mapping
+ * 0x00000000 - 0x7fffffff 0x80000000 - 0xfffffffff MUSUK (kuseg)
+ * Flat 2GB physical memory
+ *
+ * 0x80000000 - 0x9fffffff 0x00000000 - 0x1ffffffff MUSUK (kseg0)
+ * 0xa0000000 - 0xbf000000 0x00000000 - 0x1ffffffff MUSUK (kseg1)
+ * 0xc0000000 - 0xdfffffff - MK (kseg2)
+ * 0xe0000000 - 0xffffffff - MK (kseg3)
+ *
+ *
+ * Lowmem is expanded to 2GB
+ */
+ .macro eva_entry
+ /*
+ * Get Config.K0 value and use it to program
+ * the segmentation registers
+ */
+ andi t1, 0x7 /* CCA */
+ move t2, t1
+ ins t2, t1, 16, 3
+ /* SegCtl0 */
+ li t0, ((MIPS_SEGCFG_MK << MIPS_SEGCFG_AM_SHIFT) | \
+ (0 << MIPS_SEGCFG_PA_SHIFT) | \
+ (1 << MIPS_SEGCFG_EU_SHIFT)) | \
+ (((MIPS_SEGCFG_MK << MIPS_SEGCFG_AM_SHIFT) | \
+ (0 << MIPS_SEGCFG_PA_SHIFT) | \
+ (1 << MIPS_SEGCFG_EU_SHIFT)) << 16)
+ or t0, t2
+ mtc0 t0, $5, 2
+
+ /* SegCtl1 */
+ li t0, ((MIPS_SEGCFG_MUSUK << MIPS_SEGCFG_AM_SHIFT) | \
+ (0 << MIPS_SEGCFG_PA_SHIFT) | \
+ (2 << MIPS_SEGCFG_C_SHIFT) | \
+ (1 << MIPS_SEGCFG_EU_SHIFT)) | \
+ (((MIPS_SEGCFG_MUSUK << MIPS_SEGCFG_AM_SHIFT) | \
+ (0 << MIPS_SEGCFG_PA_SHIFT) | \
+ (1 << MIPS_SEGCFG_EU_SHIFT)) << 16)
+ ins t0, t1, 16, 3
+ mtc0 t0, $5, 3
+
+ /* SegCtl2 */
+ li t0, ((MIPS_SEGCFG_MUSUK << MIPS_SEGCFG_AM_SHIFT) | \
+ (6 << MIPS_SEGCFG_PA_SHIFT) | \
+ (1 << MIPS_SEGCFG_EU_SHIFT)) | \
+ (((MIPS_SEGCFG_MUSUK << MIPS_SEGCFG_AM_SHIFT) | \
+ (4 << MIPS_SEGCFG_PA_SHIFT) | \
+ (1 << MIPS_SEGCFG_EU_SHIFT)) << 16)
+ or t0, t2
+ mtc0 t0, $5, 4
+
+ jal mips_ihb
+ mfc0 t0, $16, 5
+ li t2, 0x40000000 /* K bit */
+ or t0, t0, t2
+ mtc0 t0, $16, 5
+ sync
+ jal mips_ihb
+ .endm
+
.macro kernel_entry_setup
#ifdef CONFIG_MIPS_MT_SMTC
mfc0 t0, CP0_CONFIG
@@ -39,14 +109,57 @@
nonmt_processor:
.asciz "SMTC kernel requires the MT ASE to run\n"
__FINIT
-0:
#endif
+
+#ifdef CONFIG_EVA
+ sync
+ ehb
+
+ mfc0 t1, CP0_CONFIG
+ bgez t1, 9f
+ mfc0 t0, CP0_CONFIG, 1
+ bgez t0, 9f
+ mfc0 t0, CP0_CONFIG, 2
+ bgez t0, 9f
+ mfc0 t0, CP0_CONFIG, 3
+ sll t0, t0, 6 /* SC bit */
+ bgez t0, 9f
+
+ eva_entry
+ b 0f
+9:
+ /* Assume we came from YAMON... */
+ PTR_LA v0, 0x9fc00534 /* YAMON print */
+ lw v0, (v0)
+ move a0, zero
+ PTR_LA a1, nonsc_processor
+ jal v0
+
+ PTR_LA v0, 0x9fc00520 /* YAMON exit */
+ lw v0, (v0)
+ li a0, 1
+ jal v0
+
+1: b 1b
+ nop
+ __INITDATA
+nonsc_processor:
+ .asciz "EVA kernel requires a MIPS core with Segment Control implemented\n"
+ __FINIT
+#endif /* CONFIG_EVA */
+0:
.endm
/*
* Do SMP slave processor setup necessary before we can safely execute C code.
*/
.macro smp_slave_setup
+#ifdef CONFIG_EVA
+ sync
+ ehb
+ mfc0 t1, CP0_CONFIG
+ eva_entry
+#endif
.endm
#endif /* __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H */
diff --git a/arch/mips/include/asm/mach-malta/spaces.h b/arch/mips/include/asm/mach-malta/spaces.h
new file mode 100644
index 000000000000..d7e54971ec66
--- /dev/null
+++ b/arch/mips/include/asm/mach-malta/spaces.h
@@ -0,0 +1,46 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2014 Imagination Technologies Ltd.
+ */
+
+#ifndef _ASM_MALTA_SPACES_H
+#define _ASM_MALTA_SPACES_H
+
+#ifdef CONFIG_EVA
+
+/*
+ * Traditional Malta Board Memory Map for EVA
+ *
+ * 0x00000000 - 0x0fffffff: 1st RAM region, 256MB
+ * 0x10000000 - 0x1bffffff: GIC and CPC Control Registers
+ * 0x1c000000 - 0x1fffffff: I/O And Flash
+ * 0x20000000 - 0x7fffffff: 2nd RAM region, 1.5GB
+ * 0x80000000 - 0xffffffff: Physical memory aliases to 0x0 (2GB)
+ *
+ * The kernel is still located in 0x80000000(kseg0). However,
+ * the physical mask has been shifted to 0x80000000 which exploits the alias
+ * on the Malta board. As a result of which, we override the __pa_symbol
+ * to peform direct mapping from virtual to physical addresses. In other
+ * words, the 0x80000000 virtual address maps to 0x80000000 physical address
+ * which in turn aliases to 0x0. We do this in order to be able to use a flat
+ * 2GB of memory (0x80000000 - 0xffffffff) so we can avoid the I/O hole in
+ * 0x10000000 - 0x1fffffff.
+ * The last 64KB of physical memory are reserved for correct HIGHMEM
+ * macros arithmetics.
+ *
+ */
+
+#define PAGE_OFFSET _AC(0x0, UL)
+#define PHYS_OFFSET _AC(0x80000000, UL)
+#define HIGHMEM_START _AC(0xffff0000, UL)
+
+#define __pa_symbol(x) (RELOC_HIDE((unsigned long)(x), 0))
+
+#endif /* CONFIG_EVA */
+
+#include <asm/mach-generic/spaces.h>
+
+#endif /* _ASM_MALTA_SPACES_H */
diff --git a/arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h b/arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h
index 2dbc7a8cec1a..fc946c835995 100644
--- a/arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h
+++ b/arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h
@@ -76,7 +76,7 @@ static inline void set_value_reg32(volatile u32 *const addr,
__asm__ __volatile__(
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %1 # set_value_reg32 \n"
" and %0, %2 \n"
" or %0, %3 \n"
@@ -98,7 +98,7 @@ static inline void set_reg32(volatile u32 *const addr,
__asm__ __volatile__(
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %1 # set_reg32 \n"
" or %0, %2 \n"
" sc %0, %1 \n"
@@ -119,7 +119,7 @@ static inline void clear_reg32(volatile u32 *const addr,
__asm__ __volatile__(
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %1 # clear_reg32 \n"
" and %0, %2 \n"
" sc %0, %1 \n"
@@ -140,7 +140,7 @@ static inline void toggle_reg32(volatile u32 *const addr,
__asm__ __volatile__(
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
"1: ll %0, %1 # toggle_reg32 \n"
" xor %0, %2 \n"
" sc %0, %1 \n"
@@ -216,7 +216,7 @@ static inline u32 blocking_read_reg32(volatile u32 *const addr)
#define custom_read_reg32(address, tmp) \
__asm__ __volatile__( \
" .set push \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
"1: ll %0, %1 #custom_read_reg32 \n" \
" .set pop \n" \
: "=r" (tmp), "=m" (*address) \
@@ -225,7 +225,7 @@ static inline u32 blocking_read_reg32(volatile u32 *const addr)
#define custom_write_reg32(address, tmp) \
__asm__ __volatile__( \
" .set push \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
" sc %0, %1 #custom_write_reg32 \n" \
" "__beqz"%0, 1b \n" \
" nop \n" \
diff --git a/arch/mips/include/asm/mips-boards/malta.h b/arch/mips/include/asm/mips-boards/malta.h
index 722bc889eab5..fd9774269a5e 100644
--- a/arch/mips/include/asm/mips-boards/malta.h
+++ b/arch/mips/include/asm/mips-boards/malta.h
@@ -64,6 +64,11 @@ static inline unsigned long get_msc_port_base(unsigned long reg)
#define GIC_ADDRSPACE_SZ (128 * 1024)
/*
+ * CPC Specific definitions
+ */
+#define CPC_BASE_ADDR 0x1bde0000
+
+/*
* MSC01 BIU Specific definitions
* FIXME : These should be elsewhere ?
*/
diff --git a/arch/mips/include/asm/mips-boards/piix4.h b/arch/mips/include/asm/mips-boards/piix4.h
index 836e2ede24de..9cf54041d416 100644
--- a/arch/mips/include/asm/mips-boards/piix4.h
+++ b/arch/mips/include/asm/mips-boards/piix4.h
@@ -50,4 +50,9 @@
#define PIIX4_FUNC1_IDETIM_SECONDARY_HI 0x43
#define PIIX4_FUNC1_IDETIM_SECONDARY_HI_IDE_DECODE_EN (1 << 7)
+/* Power Management Configuration Space */
+#define PIIX4_FUNC3_PMBA 0x40
+#define PIIX4_FUNC3_PMREGMISC 0x80
+#define PIIX4_FUNC3_PMREGMISC_EN (1 << 0)
+
#endif /* __ASM_MIPS_BOARDS_PIIX4_H */
diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h
new file mode 100644
index 000000000000..6a9d2dd005ca
--- /dev/null
+++ b/arch/mips/include/asm/mips-cm.h
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __MIPS_ASM_MIPS_CM_H__
+#define __MIPS_ASM_MIPS_CM_H__
+
+#include <linux/io.h>
+#include <linux/types.h>
+
+/* The base address of the CM GCR block */
+extern void __iomem *mips_cm_base;
+
+/* The base address of the CM L2-only sync region */
+extern void __iomem *mips_cm_l2sync_base;
+
+/**
+ * __mips_cm_phys_base - retrieve the physical base address of the CM
+ *
+ * This function returns the physical base address of the Coherence Manager
+ * global control block, or 0 if no Coherence Manager is present. It provides
+ * a default implementation which reads the CMGCRBase register where available,
+ * and may be overriden by platforms which determine this address in a
+ * different way by defining a function with the same prototype except for the
+ * name mips_cm_phys_base (without underscores).
+ */
+extern phys_t __mips_cm_phys_base(void);
+
+/**
+ * mips_cm_probe - probe for a Coherence Manager
+ *
+ * Attempt to detect the presence of a Coherence Manager. Returns 0 if a CM
+ * is successfully detected, else -errno.
+ */
+#ifdef CONFIG_MIPS_CM
+extern int mips_cm_probe(void);
+#else
+static inline int mips_cm_probe(void)
+{
+ return -ENODEV;
+}
+#endif
+
+/**
+ * mips_cm_present - determine whether a Coherence Manager is present
+ *
+ * Returns true if a CM is present in the system, else false.
+ */
+static inline bool mips_cm_present(void)
+{
+#ifdef CONFIG_MIPS_CM
+ return mips_cm_base != NULL;
+#else
+ return false;
+#endif
+}
+
+/**
+ * mips_cm_has_l2sync - determine whether an L2-only sync region is present
+ *
+ * Returns true if the system implements an L2-only sync region, else false.
+ */
+static inline bool mips_cm_has_l2sync(void)
+{
+#ifdef CONFIG_MIPS_CM
+ return mips_cm_l2sync_base != NULL;
+#else
+ return false;
+#endif
+}
+
+/* Offsets to register blocks from the CM base address */
+#define MIPS_CM_GCB_OFS 0x0000 /* Global Control Block */
+#define MIPS_CM_CLCB_OFS 0x2000 /* Core Local Control Block */
+#define MIPS_CM_COCB_OFS 0x4000 /* Core Other Control Block */
+#define MIPS_CM_GDB_OFS 0x6000 /* Global Debug Block */
+
+/* Total size of the CM memory mapped registers */
+#define MIPS_CM_GCR_SIZE 0x8000
+
+/* Size of the L2-only sync region */
+#define MIPS_CM_L2SYNC_SIZE 0x1000
+
+/* Macros to ease the creation of register access functions */
+#define BUILD_CM_R_(name, off) \
+static inline u32 *addr_gcr_##name(void) \
+{ \
+ return (u32 *)(mips_cm_base + (off)); \
+} \
+ \
+static inline u32 read_gcr_##name(void) \
+{ \
+ return __raw_readl(addr_gcr_##name()); \
+}
+
+#define BUILD_CM__W(name, off) \
+static inline void write_gcr_##name(u32 value) \
+{ \
+ __raw_writel(value, addr_gcr_##name()); \
+}
+
+#define BUILD_CM_RW(name, off) \
+ BUILD_CM_R_(name, off) \
+ BUILD_CM__W(name, off)
+
+#define BUILD_CM_Cx_R_(name, off) \
+ BUILD_CM_R_(cl_##name, MIPS_CM_CLCB_OFS + (off)) \
+ BUILD_CM_R_(co_##name, MIPS_CM_COCB_OFS + (off))
+
+#define BUILD_CM_Cx__W(name, off) \
+ BUILD_CM__W(cl_##name, MIPS_CM_CLCB_OFS + (off)) \
+ BUILD_CM__W(co_##name, MIPS_CM_COCB_OFS + (off))
+
+#define BUILD_CM_Cx_RW(name, off) \
+ BUILD_CM_Cx_R_(name, off) \
+ BUILD_CM_Cx__W(name, off)
+
+/* GCB register accessor functions */
+BUILD_CM_R_(config, MIPS_CM_GCB_OFS + 0x00)
+BUILD_CM_RW(base, MIPS_CM_GCB_OFS + 0x08)
+BUILD_CM_RW(access, MIPS_CM_GCB_OFS + 0x20)
+BUILD_CM_R_(rev, MIPS_CM_GCB_OFS + 0x30)
+BUILD_CM_RW(error_mask, MIPS_CM_GCB_OFS + 0x40)
+BUILD_CM_RW(error_cause, MIPS_CM_GCB_OFS + 0x48)
+BUILD_CM_RW(error_addr, MIPS_CM_GCB_OFS + 0x50)
+BUILD_CM_RW(error_mult, MIPS_CM_GCB_OFS + 0x58)
+BUILD_CM_RW(l2_only_sync_base, MIPS_CM_GCB_OFS + 0x70)
+BUILD_CM_RW(gic_base, MIPS_CM_GCB_OFS + 0x80)
+BUILD_CM_RW(cpc_base, MIPS_CM_GCB_OFS + 0x88)
+BUILD_CM_RW(reg0_base, MIPS_CM_GCB_OFS + 0x90)
+BUILD_CM_RW(reg0_mask, MIPS_CM_GCB_OFS + 0x98)
+BUILD_CM_RW(reg1_base, MIPS_CM_GCB_OFS + 0xa0)
+BUILD_CM_RW(reg1_mask, MIPS_CM_GCB_OFS + 0xa8)
+BUILD_CM_RW(reg2_base, MIPS_CM_GCB_OFS + 0xb0)
+BUILD_CM_RW(reg2_mask, MIPS_CM_GCB_OFS + 0xb8)
+BUILD_CM_RW(reg3_base, MIPS_CM_GCB_OFS + 0xc0)
+BUILD_CM_RW(reg3_mask, MIPS_CM_GCB_OFS + 0xc8)
+BUILD_CM_R_(gic_status, MIPS_CM_GCB_OFS + 0xd0)
+BUILD_CM_R_(cpc_status, MIPS_CM_GCB_OFS + 0xf0)
+
+/* Core Local & Core Other register accessor functions */
+BUILD_CM_Cx_RW(reset_release, 0x00)
+BUILD_CM_Cx_RW(coherence, 0x08)
+BUILD_CM_Cx_R_(config, 0x10)
+BUILD_CM_Cx_RW(other, 0x18)
+BUILD_CM_Cx_RW(reset_base, 0x20)
+BUILD_CM_Cx_R_(id, 0x28)
+BUILD_CM_Cx_RW(reset_ext_base, 0x30)
+BUILD_CM_Cx_R_(tcid_0_priority, 0x40)
+BUILD_CM_Cx_R_(tcid_1_priority, 0x48)
+BUILD_CM_Cx_R_(tcid_2_priority, 0x50)
+BUILD_CM_Cx_R_(tcid_3_priority, 0x58)
+BUILD_CM_Cx_R_(tcid_4_priority, 0x60)
+BUILD_CM_Cx_R_(tcid_5_priority, 0x68)
+BUILD_CM_Cx_R_(tcid_6_priority, 0x70)
+BUILD_CM_Cx_R_(tcid_7_priority, 0x78)
+BUILD_CM_Cx_R_(tcid_8_priority, 0x80)
+
+/* GCR_CONFIG register fields */
+#define CM_GCR_CONFIG_NUMIOCU_SHF 8
+#define CM_GCR_CONFIG_NUMIOCU_MSK (_ULCAST_(0xf) << 8)
+#define CM_GCR_CONFIG_PCORES_SHF 0
+#define CM_GCR_CONFIG_PCORES_MSK (_ULCAST_(0xff) << 0)
+
+/* GCR_BASE register fields */
+#define CM_GCR_BASE_GCRBASE_SHF 15
+#define CM_GCR_BASE_GCRBASE_MSK (_ULCAST_(0x1ffff) << 15)
+#define CM_GCR_BASE_CMDEFTGT_SHF 0
+#define CM_GCR_BASE_CMDEFTGT_MSK (_ULCAST_(0x3) << 0)
+#define CM_GCR_BASE_CMDEFTGT_DISABLED 0
+#define CM_GCR_BASE_CMDEFTGT_MEM 1
+#define CM_GCR_BASE_CMDEFTGT_IOCU0 2
+#define CM_GCR_BASE_CMDEFTGT_IOCU1 3
+
+/* GCR_ACCESS register fields */
+#define CM_GCR_ACCESS_ACCESSEN_SHF 0
+#define CM_GCR_ACCESS_ACCESSEN_MSK (_ULCAST_(0xff) << 0)
+
+/* GCR_REV register fields */
+#define CM_GCR_REV_MAJOR_SHF 8
+#define CM_GCR_REV_MAJOR_MSK (_ULCAST_(0xff) << 8)
+#define CM_GCR_REV_MINOR_SHF 0
+#define CM_GCR_REV_MINOR_MSK (_ULCAST_(0xff) << 0)
+
+/* GCR_ERROR_CAUSE register fields */
+#define CM_GCR_ERROR_CAUSE_ERRTYPE_SHF 27
+#define CM_GCR_ERROR_CAUSE_ERRTYPE_MSK (_ULCAST_(0x1f) << 27)
+#define CM_GCR_ERROR_CAUSE_ERRINFO_SHF 0
+#define CM_GCR_ERROR_CAUSE_ERRINGO_MSK (_ULCAST_(0x7ffffff) << 0)
+
+/* GCR_ERROR_MULT register fields */
+#define CM_GCR_ERROR_MULT_ERR2ND_SHF 0
+#define CM_GCR_ERROR_MULT_ERR2ND_MSK (_ULCAST_(0x1f) << 0)
+
+/* GCR_L2_ONLY_SYNC_BASE register fields */
+#define CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE_SHF 12
+#define CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE_MSK (_ULCAST_(0xfffff) << 12)
+#define CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN_SHF 0
+#define CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN_MSK (_ULCAST_(0x1) << 0)
+
+/* GCR_GIC_BASE register fields */
+#define CM_GCR_GIC_BASE_GICBASE_SHF 17
+#define CM_GCR_GIC_BASE_GICBASE_MSK (_ULCAST_(0x7fff) << 17)
+#define CM_GCR_GIC_BASE_GICEN_SHF 0
+#define CM_GCR_GIC_BASE_GICEN_MSK (_ULCAST_(0x1) << 0)
+
+/* GCR_CPC_BASE register fields */
+#define CM_GCR_CPC_BASE_CPCBASE_SHF 17
+#define CM_GCR_CPC_BASE_CPCBASE_MSK (_ULCAST_(0x7fff) << 17)
+#define CM_GCR_CPC_BASE_CPCEN_SHF 0
+#define CM_GCR_CPC_BASE_CPCEN_MSK (_ULCAST_(0x1) << 0)
+
+/* GCR_REGn_BASE register fields */
+#define CM_GCR_REGn_BASE_BASEADDR_SHF 16
+#define CM_GCR_REGn_BASE_BASEADDR_MSK (_ULCAST_(0xffff) << 16)
+
+/* GCR_REGn_MASK register fields */
+#define CM_GCR_REGn_MASK_ADDRMASK_SHF 16
+#define CM_GCR_REGn_MASK_ADDRMASK_MSK (_ULCAST_(0xffff) << 16)
+#define CM_GCR_REGn_MASK_CCAOVR_SHF 5
+#define CM_GCR_REGn_MASK_CCAOVR_MSK (_ULCAST_(0x3) << 5)
+#define CM_GCR_REGn_MASK_CCAOVREN_SHF 4
+#define CM_GCR_REGn_MASK_CCAOVREN_MSK (_ULCAST_(0x1) << 4)
+#define CM_GCR_REGn_MASK_DROPL2_SHF 2
+#define CM_GCR_REGn_MASK_DROPL2_MSK (_ULCAST_(0x1) << 2)
+#define CM_GCR_REGn_MASK_CMTGT_SHF 0
+#define CM_GCR_REGn_MASK_CMTGT_MSK (_ULCAST_(0x3) << 0)
+#define CM_GCR_REGn_MASK_CMTGT_DISABLED (_ULCAST_(0x0) << 0)
+#define CM_GCR_REGn_MASK_CMTGT_MEM (_ULCAST_(0x1) << 0)
+#define CM_GCR_REGn_MASK_CMTGT_IOCU0 (_ULCAST_(0x2) << 0)
+#define CM_GCR_REGn_MASK_CMTGT_IOCU1 (_ULCAST_(0x3) << 0)
+
+/* GCR_GIC_STATUS register fields */
+#define CM_GCR_GIC_STATUS_EX_SHF 0
+#define CM_GCR_GIC_STATUS_EX_MSK (_ULCAST_(0x1) << 0)
+
+/* GCR_CPC_STATUS register fields */
+#define CM_GCR_CPC_STATUS_EX_SHF 0
+#define CM_GCR_CPC_STATUS_EX_MSK (_ULCAST_(0x1) << 0)
+
+/* GCR_Cx_COHERENCE register fields */
+#define CM_GCR_Cx_COHERENCE_COHDOMAINEN_SHF 0
+#define CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK (_ULCAST_(0xff) << 0)
+
+/* GCR_Cx_CONFIG register fields */
+#define CM_GCR_Cx_CONFIG_IOCUTYPE_SHF 10
+#define CM_GCR_Cx_CONFIG_IOCUTYPE_MSK (_ULCAST_(0x3) << 10)
+#define CM_GCR_Cx_CONFIG_PVPE_SHF 0
+#define CM_GCR_Cx_CONFIG_PVPE_MSK (_ULCAST_(0x1ff) << 0)
+
+/* GCR_Cx_OTHER register fields */
+#define CM_GCR_Cx_OTHER_CORENUM_SHF 16
+#define CM_GCR_Cx_OTHER_CORENUM_MSK (_ULCAST_(0xffff) << 16)
+
+/* GCR_Cx_RESET_BASE register fields */
+#define CM_GCR_Cx_RESET_BASE_BEVEXCBASE_SHF 12
+#define CM_GCR_Cx_RESET_BASE_BEVEXCBASE_MSK (_ULCAST_(0xfffff) << 12)
+
+/* GCR_Cx_RESET_EXT_BASE register fields */
+#define CM_GCR_Cx_RESET_EXT_BASE_EVARESET_SHF 31
+#define CM_GCR_Cx_RESET_EXT_BASE_EVARESET_MSK (_ULCAST_(0x1) << 31)
+#define CM_GCR_Cx_RESET_EXT_BASE_UEB_SHF 30
+#define CM_GCR_Cx_RESET_EXT_BASE_UEB_MSK (_ULCAST_(0x1) << 30)
+#define CM_GCR_Cx_RESET_EXT_BASE_BEVEXCMASK_SHF 20
+#define CM_GCR_Cx_RESET_EXT_BASE_BEVEXCMASK_MSK (_ULCAST_(0xff) << 20)
+#define CM_GCR_Cx_RESET_EXT_BASE_BEVEXCPA_SHF 1
+#define CM_GCR_Cx_RESET_EXT_BASE_BEVEXCPA_MSK (_ULCAST_(0x7f) << 1)
+#define CM_GCR_Cx_RESET_EXT_BASE_PRESENT_SHF 0
+#define CM_GCR_Cx_RESET_EXT_BASE_PRESENT_MSK (_ULCAST_(0x1) << 0)
+
+/**
+ * mips_cm_numcores - return the number of cores present in the system
+ *
+ * Returns the value of the PCORES field of the GCR_CONFIG register plus 1, or
+ * zero if no Coherence Manager is present.
+ */
+static inline unsigned mips_cm_numcores(void)
+{
+ if (!mips_cm_present())
+ return 0;
+
+ return ((read_gcr_config() & CM_GCR_CONFIG_PCORES_MSK)
+ >> CM_GCR_CONFIG_PCORES_SHF) + 1;
+}
+
+/**
+ * mips_cm_numiocu - return the number of IOCUs present in the system
+ *
+ * Returns the value of the NUMIOCU field of the GCR_CONFIG register, or zero
+ * if no Coherence Manager is present.
+ */
+static inline unsigned mips_cm_numiocu(void)
+{
+ if (!mips_cm_present())
+ return 0;
+
+ return (read_gcr_config() & CM_GCR_CONFIG_NUMIOCU_MSK)
+ >> CM_GCR_CONFIG_NUMIOCU_SHF;
+}
+
+/**
+ * mips_cm_l2sync - perform an L2-only sync operation
+ *
+ * If an L2-only sync region is present in the system then this function
+ * performs and L2-only sync and returns zero. Otherwise it returns -ENODEV.
+ */
+static inline int mips_cm_l2sync(void)
+{
+ if (!mips_cm_has_l2sync())
+ return -ENODEV;
+
+ writel(0, mips_cm_l2sync_base);
+ return 0;
+}
+
+#endif /* __MIPS_ASM_MIPS_CM_H__ */
diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h
new file mode 100644
index 000000000000..988507e46d42
--- /dev/null
+++ b/arch/mips/include/asm/mips-cpc.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __MIPS_ASM_MIPS_CPC_H__
+#define __MIPS_ASM_MIPS_CPC_H__
+
+#include <linux/io.h>
+#include <linux/types.h>
+
+/* The base address of the CPC registers */
+extern void __iomem *mips_cpc_base;
+
+/**
+ * mips_cpc_default_phys_base - retrieve the default physical base address of
+ * the CPC
+ *
+ * Returns the default physical base address of the Cluster Power Controller
+ * memory mapped registers. This is platform dependant & must therefore be
+ * implemented per-platform.
+ */
+extern phys_t mips_cpc_default_phys_base(void);
+
+/**
+ * mips_cpc_phys_base - retrieve the physical base address of the CPC
+ *
+ * This function returns the physical base address of the Cluster Power
+ * Controller memory mapped registers, or 0 if no Cluster Power Controller
+ * is present. It may be overriden by individual platforms which determine
+ * this address in a different way.
+ */
+extern phys_t __weak mips_cpc_phys_base(void);
+
+/**
+ * mips_cpc_probe - probe for a Cluster Power Controller
+ *
+ * Attempt to detect the presence of a Cluster Power Controller. Returns 0 if
+ * a CPC is successfully detected, else -errno.
+ */
+#ifdef CONFIG_MIPS_CPC
+extern int mips_cpc_probe(void);
+#else
+static inline int mips_cpc_probe(void)
+{
+ return -ENODEV;
+}
+#endif
+
+/**
+ * mips_cpc_present - determine whether a Cluster Power Controller is present
+ *
+ * Returns true if a CPC is present in the system, else false.
+ */
+static inline bool mips_cpc_present(void)
+{
+#ifdef CONFIG_MIPS_CPC
+ return mips_cpc_base != NULL;
+#else
+ return false;
+#endif
+}
+
+/* Offsets from the CPC base address to various control blocks */
+#define MIPS_CPC_GCB_OFS 0x0000
+#define MIPS_CPC_CLCB_OFS 0x2000
+#define MIPS_CPC_COCB_OFS 0x4000
+
+/* Macros to ease the creation of register access functions */
+#define BUILD_CPC_R_(name, off) \
+static inline u32 read_cpc_##name(void) \
+{ \
+ return __raw_readl(mips_cpc_base + (off)); \
+}
+
+#define BUILD_CPC__W(name, off) \
+static inline void write_cpc_##name(u32 value) \
+{ \
+ __raw_writel(value, mips_cpc_base + (off)); \
+}
+
+#define BUILD_CPC_RW(name, off) \
+ BUILD_CPC_R_(name, off) \
+ BUILD_CPC__W(name, off)
+
+#define BUILD_CPC_Cx_R_(name, off) \
+ BUILD_CPC_R_(cl_##name, MIPS_CPC_CLCB_OFS + (off)) \
+ BUILD_CPC_R_(co_##name, MIPS_CPC_COCB_OFS + (off))
+
+#define BUILD_CPC_Cx__W(name, off) \
+ BUILD_CPC__W(cl_##name, MIPS_CPC_CLCB_OFS + (off)) \
+ BUILD_CPC__W(co_##name, MIPS_CPC_COCB_OFS + (off))
+
+#define BUILD_CPC_Cx_RW(name, off) \
+ BUILD_CPC_Cx_R_(name, off) \
+ BUILD_CPC_Cx__W(name, off)
+
+/* GCB register accessor functions */
+BUILD_CPC_RW(access, MIPS_CPC_GCB_OFS + 0x00)
+BUILD_CPC_RW(seqdel, MIPS_CPC_GCB_OFS + 0x08)
+BUILD_CPC_RW(rail, MIPS_CPC_GCB_OFS + 0x10)
+BUILD_CPC_RW(resetlen, MIPS_CPC_GCB_OFS + 0x18)
+BUILD_CPC_R_(revision, MIPS_CPC_GCB_OFS + 0x20)
+
+/* Core Local & Core Other accessor functions */
+BUILD_CPC_Cx_RW(cmd, 0x00)
+BUILD_CPC_Cx_RW(stat_conf, 0x08)
+BUILD_CPC_Cx_RW(other, 0x10)
+
+/* CPC_Cx_CMD register fields */
+#define CPC_Cx_CMD_SHF 0
+#define CPC_Cx_CMD_MSK (_ULCAST_(0xf) << 0)
+#define CPC_Cx_CMD_CLOCKOFF (_ULCAST_(0x1) << 0)
+#define CPC_Cx_CMD_PWRDOWN (_ULCAST_(0x2) << 0)
+#define CPC_Cx_CMD_PWRUP (_ULCAST_(0x3) << 0)
+#define CPC_Cx_CMD_RESET (_ULCAST_(0x4) << 0)
+
+/* CPC_Cx_STAT_CONF register fields */
+#define CPC_Cx_STAT_CONF_PWRUPE_SHF 23
+#define CPC_Cx_STAT_CONF_PWRUPE_MSK (_ULCAST_(0x1) << 23)
+#define CPC_Cx_STAT_CONF_SEQSTATE_SHF 19
+#define CPC_Cx_STAT_CONF_SEQSTATE_MSK (_ULCAST_(0xf) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_D0 (_ULCAST_(0x0) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U0 (_ULCAST_(0x1) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U1 (_ULCAST_(0x2) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U2 (_ULCAST_(0x3) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U3 (_ULCAST_(0x4) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U4 (_ULCAST_(0x5) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U5 (_ULCAST_(0x6) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_U6 (_ULCAST_(0x7) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_D1 (_ULCAST_(0x8) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_D3 (_ULCAST_(0x9) << 19)
+#define CPC_Cx_STAT_CONF_SEQSTATE_D2 (_ULCAST_(0xa) << 19)
+#define CPC_Cx_STAT_CONF_CLKGAT_IMPL_SHF 17
+#define CPC_Cx_STAT_CONF_CLKGAT_IMPL_MSK (_ULCAST_(0x1) << 17)
+#define CPC_Cx_STAT_CONF_PWRDN_IMPL_SHF 16
+#define CPC_Cx_STAT_CONF_PWRDN_IMPL_MSK (_ULCAST_(0x1) << 16)
+#define CPC_Cx_STAT_CONF_EJTAG_PROBE_SHF 15
+#define CPC_Cx_STAT_CONF_EJTAG_PROBE_MSK (_ULCAST_(0x1) << 15)
+
+/* CPC_Cx_OTHER register fields */
+#define CPC_Cx_OTHER_CORENUM_SHF 16
+#define CPC_Cx_OTHER_CORENUM_MSK (_ULCAST_(0xff) << 16)
+
+#endif /* __MIPS_ASM_MIPS_CPC_H__ */
diff --git a/arch/mips/include/asm/mips_mt.h b/arch/mips/include/asm/mips_mt.h
index ac7935203f89..a3df0c3faa0e 100644
--- a/arch/mips/include/asm/mips_mt.h
+++ b/arch/mips/include/asm/mips_mt.h
@@ -18,7 +18,12 @@ extern cpumask_t mt_fpu_cpumask;
extern unsigned long mt_fpemul_threshold;
extern void mips_mt_regdump(unsigned long previous_mvpcontrol_value);
+
+#ifdef CONFIG_MIPS_MT
extern void mips_mt_set_cpuoptions(void);
+#else
+static inline void mips_mt_set_cpuoptions(void) { }
+#endif
struct class;
extern struct class *mt_class;
diff --git a/arch/mips/include/asm/mipsmtregs.h b/arch/mips/include/asm/mipsmtregs.h
index 38b7704ee376..6efa79a27b6a 100644
--- a/arch/mips/include/asm/mipsmtregs.h
+++ b/arch/mips/include/asm/mipsmtregs.h
@@ -176,6 +176,17 @@
#ifndef __ASSEMBLY__
+static inline unsigned core_nvpes(void)
+{
+ unsigned conf0;
+
+ if (!cpu_has_mipsmt)
+ return 1;
+
+ conf0 = read_c0_mvpconf0();
+ return ((conf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
+}
+
static inline unsigned int dvpe(void)
{
int res = 0;
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index bbc3dd4294bc..3e025b5311db 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -568,11 +568,23 @@
#define MIPS_CONF1_PC (_ULCAST_(1) << 4)
#define MIPS_CONF1_MD (_ULCAST_(1) << 5)
#define MIPS_CONF1_C2 (_ULCAST_(1) << 6)
+#define MIPS_CONF1_DA_SHF 7
+#define MIPS_CONF1_DA_SZ 3
#define MIPS_CONF1_DA (_ULCAST_(7) << 7)
+#define MIPS_CONF1_DL_SHF 10
+#define MIPS_CONF1_DL_SZ 3
#define MIPS_CONF1_DL (_ULCAST_(7) << 10)
+#define MIPS_CONF1_DS_SHF 13
+#define MIPS_CONF1_DS_SZ 3
#define MIPS_CONF1_DS (_ULCAST_(7) << 13)
+#define MIPS_CONF1_IA_SHF 16
+#define MIPS_CONF1_IA_SZ 3
#define MIPS_CONF1_IA (_ULCAST_(7) << 16)
+#define MIPS_CONF1_IL_SHF 19
+#define MIPS_CONF1_IL_SZ 3
#define MIPS_CONF1_IL (_ULCAST_(7) << 19)
+#define MIPS_CONF1_IS_SHF 22
+#define MIPS_CONF1_IS_SZ 3
#define MIPS_CONF1_IS (_ULCAST_(7) << 22)
#define MIPS_CONF1_TLBS_SHIFT (25)
#define MIPS_CONF1_TLBS_SIZE (6)
@@ -653,9 +665,16 @@
#define MIPS_CONF7_RPS (_ULCAST_(1) << 2)
+#define MIPS_CONF7_IAR (_ULCAST_(1) << 10)
+#define MIPS_CONF7_AR (_ULCAST_(1) << 16)
+
/* EntryHI bit definition */
#define MIPS_ENTRYHI_EHINV (_ULCAST_(1) << 10)
+/* CMGCRBase bit definitions */
+#define MIPS_CMGCRB_BASE 11
+#define MIPS_CMGCRF_BASE (~_ULCAST_((1 << MIPS_CMGCRB_BASE) - 1))
+
/*
* Bits in the MIPS32/64 coprocessor 1 (FPU) revision register.
*/
@@ -1010,6 +1029,8 @@ do { \
#define read_c0_prid() __read_32bit_c0_register($15, 0)
+#define read_c0_cmgcrbase() __read_ulong_c0_register($15, 3)
+
#define read_c0_config() __read_32bit_c0_register($16, 0)
#define read_c0_config1() __read_32bit_c0_register($16, 1)
#define read_c0_config2() __read_32bit_c0_register($16, 2)
@@ -1883,6 +1904,7 @@ change_c0_##name(unsigned int change, unsigned int newbits) \
__BUILD_SET_C0(status)
__BUILD_SET_C0(cause)
__BUILD_SET_C0(config)
+__BUILD_SET_C0(config5)
__BUILD_SET_C0(intcontrol)
__BUILD_SET_C0(intctl)
__BUILD_SET_C0(srsmap)
diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h
index 44b705d08262..c2edae382d5d 100644
--- a/arch/mips/include/asm/module.h
+++ b/arch/mips/include/asm/module.h
@@ -126,6 +126,8 @@ search_module_dbetables(unsigned long addr)
#define MODULE_PROC_FAMILY "LOONGSON1 "
#elif defined CONFIG_CPU_LOONGSON2
#define MODULE_PROC_FAMILY "LOONGSON2 "
+#elif defined CONFIG_CPU_LOONGSON3
+#define MODULE_PROC_FAMILY "LOONGSON3 "
#elif defined CONFIG_CPU_CAVIUM_OCTEON
#define MODULE_PROC_FAMILY "OCTEON "
#elif defined CONFIG_CPU_XLR
diff --git a/arch/mips/include/asm/msa.h b/arch/mips/include/asm/msa.h
new file mode 100644
index 000000000000..a2aba6c3ec05
--- /dev/null
+++ b/arch/mips/include/asm/msa.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#ifndef _ASM_MSA_H
+#define _ASM_MSA_H
+
+#include <asm/mipsregs.h>
+
+extern void _save_msa(struct task_struct *);
+extern void _restore_msa(struct task_struct *);
+
+static inline void enable_msa(void)
+{
+ if (cpu_has_msa) {
+ set_c0_config5(MIPS_CONF5_MSAEN);
+ enable_fpu_hazard();
+ }
+}
+
+static inline void disable_msa(void)
+{
+ if (cpu_has_msa) {
+ clear_c0_config5(MIPS_CONF5_MSAEN);
+ disable_fpu_hazard();
+ }
+}
+
+static inline int is_msa_enabled(void)
+{
+ if (!cpu_has_msa)
+ return 0;
+
+ return read_c0_config5() & MIPS_CONF5_MSAEN;
+}
+
+static inline int thread_msa_context_live(void)
+{
+ /*
+ * Check cpu_has_msa only if it's a constant. This will allow the
+ * compiler to optimise out code for CPUs without MSA without adding
+ * an extra redundant check for CPUs with MSA.
+ */
+ if (__builtin_constant_p(cpu_has_msa) && !cpu_has_msa)
+ return 0;
+
+ return test_thread_flag(TIF_MSA_CTX_LIVE);
+}
+
+static inline void save_msa(struct task_struct *t)
+{
+ if (cpu_has_msa)
+ _save_msa(t);
+}
+
+static inline void restore_msa(struct task_struct *t)
+{
+ if (cpu_has_msa)
+ _restore_msa(t);
+}
+
+#ifdef TOOLCHAIN_SUPPORTS_MSA
+
+#define __BUILD_MSA_CTL_REG(name, cs) \
+static inline unsigned int read_msa_##name(void) \
+{ \
+ unsigned int reg; \
+ __asm__ __volatile__( \
+ " .set push\n" \
+ " .set msa\n" \
+ " cfcmsa %0, $" #cs "\n" \
+ " .set pop\n" \
+ : "=r"(reg)); \
+ return reg; \
+} \
+ \
+static inline void write_msa_##name(unsigned int val) \
+{ \
+ __asm__ __volatile__( \
+ " .set push\n" \
+ " .set msa\n" \
+ " cfcmsa $" #cs ", %0\n" \
+ " .set pop\n" \
+ : : "r"(val)); \
+}
+
+#else /* !TOOLCHAIN_SUPPORTS_MSA */
+
+/*
+ * Define functions using .word for the c[ft]cmsa instructions in order to
+ * allow compilation with toolchains that do not support MSA. Once all
+ * toolchains in use support MSA these can be removed.
+ */
+
+#define __BUILD_MSA_CTL_REG(name, cs) \
+static inline unsigned int read_msa_##name(void) \
+{ \
+ unsigned int reg; \
+ __asm__ __volatile__( \
+ " .set push\n" \
+ " .set noat\n" \
+ " .word 0x787e0059 | (" #cs " << 11)\n" \
+ " move %0, $1\n" \
+ " .set pop\n" \
+ : "=r"(reg)); \
+ return reg; \
+} \
+ \
+static inline void write_msa_##name(unsigned int val) \
+{ \
+ __asm__ __volatile__( \
+ " .set push\n" \
+ " .set noat\n" \
+ " move $1, %0\n" \
+ " .word 0x783e0819 | (" #cs " << 6)\n" \
+ " .set pop\n" \
+ : : "r"(val)); \
+}
+
+#endif /* !TOOLCHAIN_SUPPORTS_MSA */
+
+#define MSA_IR 0
+#define MSA_CSR 1
+#define MSA_ACCESS 2
+#define MSA_SAVE 3
+#define MSA_MODIFY 4
+#define MSA_REQUEST 5
+#define MSA_MAP 6
+#define MSA_UNMAP 7
+
+__BUILD_MSA_CTL_REG(ir, 0)
+__BUILD_MSA_CTL_REG(csr, 1)
+__BUILD_MSA_CTL_REG(access, 2)
+__BUILD_MSA_CTL_REG(save, 3)
+__BUILD_MSA_CTL_REG(modify, 4)
+__BUILD_MSA_CTL_REG(request, 5)
+__BUILD_MSA_CTL_REG(map, 6)
+__BUILD_MSA_CTL_REG(unmap, 7)
+
+/* MSA Implementation Register (MSAIR) */
+#define MSA_IR_REVB 0
+#define MSA_IR_REVF (_ULCAST_(0xff) << MSA_IR_REVB)
+#define MSA_IR_PROCB 8
+#define MSA_IR_PROCF (_ULCAST_(0xff) << MSA_IR_PROCB)
+#define MSA_IR_WRPB 16
+#define MSA_IR_WRPF (_ULCAST_(0x1) << MSA_IR_WRPB)
+
+/* MSA Control & Status Register (MSACSR) */
+#define MSA_CSR_RMB 0
+#define MSA_CSR_RMF (_ULCAST_(0x3) << MSA_CSR_RMB)
+#define MSA_CSR_RM_NEAREST 0
+#define MSA_CSR_RM_TO_ZERO 1
+#define MSA_CSR_RM_TO_POS 2
+#define MSA_CSR_RM_TO_NEG 3
+#define MSA_CSR_FLAGSB 2
+#define MSA_CSR_FLAGSF (_ULCAST_(0x1f) << MSA_CSR_FLAGSB)
+#define MSA_CSR_FLAGS_IB 2
+#define MSA_CSR_FLAGS_IF (_ULCAST_(0x1) << MSA_CSR_FLAGS_IB)
+#define MSA_CSR_FLAGS_UB 3
+#define MSA_CSR_FLAGS_UF (_ULCAST_(0x1) << MSA_CSR_FLAGS_UB)
+#define MSA_CSR_FLAGS_OB 4
+#define MSA_CSR_FLAGS_OF (_ULCAST_(0x1) << MSA_CSR_FLAGS_OB)
+#define MSA_CSR_FLAGS_ZB 5
+#define MSA_CSR_FLAGS_ZF (_ULCAST_(0x1) << MSA_CSR_FLAGS_ZB)
+#define MSA_CSR_FLAGS_VB 6
+#define MSA_CSR_FLAGS_VF (_ULCAST_(0x1) << MSA_CSR_FLAGS_VB)
+#define MSA_CSR_ENABLESB 7
+#define MSA_CSR_ENABLESF (_ULCAST_(0x1f) << MSA_CSR_ENABLESB)
+#define MSA_CSR_ENABLES_IB 7
+#define MSA_CSR_ENABLES_IF (_ULCAST_(0x1) << MSA_CSR_ENABLES_IB)
+#define MSA_CSR_ENABLES_UB 8
+#define MSA_CSR_ENABLES_UF (_ULCAST_(0x1) << MSA_CSR_ENABLES_UB)
+#define MSA_CSR_ENABLES_OB 9
+#define MSA_CSR_ENABLES_OF (_ULCAST_(0x1) << MSA_CSR_ENABLES_OB)
+#define MSA_CSR_ENABLES_ZB 10
+#define MSA_CSR_ENABLES_ZF (_ULCAST_(0x1) << MSA_CSR_ENABLES_ZB)
+#define MSA_CSR_ENABLES_VB 11
+#define MSA_CSR_ENABLES_VF (_ULCAST_(0x1) << MSA_CSR_ENABLES_VB)
+#define MSA_CSR_CAUSEB 12
+#define MSA_CSR_CAUSEF (_ULCAST_(0x3f) << MSA_CSR_CAUSEB)
+#define MSA_CSR_CAUSE_IB 12
+#define MSA_CSR_CAUSE_IF (_ULCAST_(0x1) << MSA_CSR_CAUSE_IB)
+#define MSA_CSR_CAUSE_UB 13
+#define MSA_CSR_CAUSE_UF (_ULCAST_(0x1) << MSA_CSR_CAUSE_UB)
+#define MSA_CSR_CAUSE_OB 14
+#define MSA_CSR_CAUSE_OF (_ULCAST_(0x1) << MSA_CSR_CAUSE_OB)
+#define MSA_CSR_CAUSE_ZB 15
+#define MSA_CSR_CAUSE_ZF (_ULCAST_(0x1) << MSA_CSR_CAUSE_ZB)
+#define MSA_CSR_CAUSE_VB 16
+#define MSA_CSR_CAUSE_VF (_ULCAST_(0x1) << MSA_CSR_CAUSE_VB)
+#define MSA_CSR_CAUSE_EB 17
+#define MSA_CSR_CAUSE_EF (_ULCAST_(0x1) << MSA_CSR_CAUSE_EB)
+#define MSA_CSR_NXB 18
+#define MSA_CSR_NXF (_ULCAST_(0x1) << MSA_CSR_NXB)
+#define MSA_CSR_FSB 24
+#define MSA_CSR_FSF (_ULCAST_(0x1) << MSA_CSR_FSB)
+
+#endif /* _ASM_MSA_H */
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index 5e08bcc74897..5699ec3a71af 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -190,7 +190,9 @@ typedef struct { unsigned long pgprot; } pgprot_t;
* https://patchwork.linux-mips.org/patch/1541/
*/
+#ifndef __pa_symbol
#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0))
+#endif
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h
index 32aea4852fb0..e592f3687d6f 100644
--- a/arch/mips/include/asm/pgtable-bits.h
+++ b/arch/mips/include/asm/pgtable-bits.h
@@ -235,6 +235,15 @@ static inline uint64_t pte_to_entrylo(unsigned long pte_val)
#define _CACHE_CACHABLE_NONCOHERENT (5<<_CACHE_SHIFT)
#define _CACHE_UNCACHED_ACCELERATED (7<<_CACHE_SHIFT)
+#elif defined(CONFIG_CPU_LOONGSON3)
+
+/* Using COHERENT flag for NONCOHERENT doesn't hurt. */
+
+#define _CACHE_UNCACHED (2<<_CACHE_SHIFT) /* LOONGSON */
+#define _CACHE_CACHABLE_NONCOHERENT (3<<_CACHE_SHIFT) /* LOONGSON */
+#define _CACHE_CACHABLE_COHERENT (3<<_CACHE_SHIFT) /* LOONGSON-3 */
+#define _CACHE_UNCACHED_ACCELERATED (7<<_CACHE_SHIFT) /* LOONGSON */
+
#else
#define _CACHE_CACHABLE_NO_WA (0<<_CACHE_SHIFT) /* R4600 only */
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index 3605b844ad87..ad70cba8daff 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -97,18 +97,48 @@ extern unsigned int vced_count, vcei_count;
#define NUM_FPU_REGS 32
-typedef __u64 fpureg_t;
+#ifdef CONFIG_CPU_HAS_MSA
+# define FPU_REG_WIDTH 128
+#else
+# define FPU_REG_WIDTH 64
+#endif
+
+union fpureg {
+ __u32 val32[FPU_REG_WIDTH / 32];
+ __u64 val64[FPU_REG_WIDTH / 64];
+};
+
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+# define FPR_IDX(width, idx) (idx)
+#else
+# define FPR_IDX(width, idx) ((FPU_REG_WIDTH / (width)) - 1 - (idx))
+#endif
+
+#define BUILD_FPR_ACCESS(width) \
+static inline u##width get_fpr##width(union fpureg *fpr, unsigned idx) \
+{ \
+ return fpr->val##width[FPR_IDX(width, idx)]; \
+} \
+ \
+static inline void set_fpr##width(union fpureg *fpr, unsigned idx, \
+ u##width val) \
+{ \
+ fpr->val##width[FPR_IDX(width, idx)] = val; \
+}
+
+BUILD_FPR_ACCESS(32)
+BUILD_FPR_ACCESS(64)
/*
- * It would be nice to add some more fields for emulator statistics, but there
- * are a number of fixed offsets in offset.h and elsewhere that would have to
- * be recalculated by hand. So the additional information will be private to
- * the FPU emulator for now. See asm-mips/fpu_emulator.h.
+ * It would be nice to add some more fields for emulator statistics,
+ * the additional information is private to the FPU emulator for now.
+ * See arch/mips/include/asm/fpu_emulator.h.
*/
struct mips_fpu_struct {
- fpureg_t fpr[NUM_FPU_REGS];
+ union fpureg fpr[NUM_FPU_REGS];
unsigned int fcr31;
+ unsigned int msacsr;
};
#define NUM_DSP_REGS 6
@@ -284,8 +314,9 @@ struct thread_struct {
* Saved FPU/FPU emulator stuff \
*/ \
.fpu = { \
- .fpr = {0,}, \
+ .fpr = {{{0,},},}, \
.fcr31 = 0, \
+ .msacsr = 0, \
}, \
/* \
* FPU affinity state (null if not FPAFF) \
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
index 7bba9da110af..bf1ac8d35783 100644
--- a/arch/mips/include/asm/ptrace.h
+++ b/arch/mips/include/asm/ptrace.h
@@ -82,7 +82,7 @@ static inline long regs_return_value(struct pt_regs *regs)
#define instruction_pointer(regs) ((regs)->cp0_epc)
#define profile_pc(regs) instruction_pointer(regs)
-extern asmlinkage void syscall_trace_enter(struct pt_regs *regs);
+extern asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall);
extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
extern void die(const char *, struct pt_regs *) __noreturn;
diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h
index c84caddb8bde..ca64cbe44493 100644
--- a/arch/mips/include/asm/r4kcache.h
+++ b/arch/mips/include/asm/r4kcache.h
@@ -17,6 +17,7 @@
#include <asm/cpu-features.h>
#include <asm/cpu-type.h>
#include <asm/mipsmtregs.h>
+#include <asm/uaccess.h> /* for segment_eq() */
/*
* This macro return a properly sign-extended address suitable as base address
@@ -35,7 +36,7 @@
__asm__ __volatile__( \
" .set push \n" \
" .set noreorder \n" \
- " .set mips3\n\t \n" \
+ " .set arch=r4000 \n" \
" cache %0, %1 \n" \
" .set pop \n" \
: \
@@ -203,7 +204,7 @@ static inline void flush_scache_line(unsigned long addr)
__asm__ __volatile__( \
" .set push \n" \
" .set noreorder \n" \
- " .set mips3 \n" \
+ " .set arch=r4000 \n" \
"1: cache %0, (%1) \n" \
"2: .set pop \n" \
" .section __ex_table,\"a\" \n" \
@@ -212,6 +213,20 @@ static inline void flush_scache_line(unsigned long addr)
: \
: "i" (op), "r" (addr))
+#define protected_cachee_op(op,addr) \
+ __asm__ __volatile__( \
+ " .set push \n" \
+ " .set noreorder \n" \
+ " .set mips0 \n" \
+ " .set eva \n" \
+ "1: cachee %0, (%1) \n" \
+ "2: .set pop \n" \
+ " .section __ex_table,\"a\" \n" \
+ " "STR(PTR)" 1b, 2b \n" \
+ " .previous" \
+ : \
+ : "i" (op), "r" (addr))
+
/*
* The next two are for badland addresses like signal trampolines.
*/
@@ -223,7 +238,11 @@ static inline void protected_flush_icache_line(unsigned long addr)
break;
default:
+#ifdef CONFIG_EVA
+ protected_cachee_op(Hit_Invalidate_I, addr);
+#else
protected_cache_op(Hit_Invalidate_I, addr);
+#endif
break;
}
}
@@ -356,6 +375,91 @@ static inline void invalidate_tcache_page(unsigned long addr)
: "r" (base), \
"i" (op));
+/*
+ * Perform the cache operation specified by op using a user mode virtual
+ * address while in kernel mode.
+ */
+#define cache16_unroll32_user(base,op) \
+ __asm__ __volatile__( \
+ " .set push \n" \
+ " .set noreorder \n" \
+ " .set mips0 \n" \
+ " .set eva \n" \
+ " cachee %1, 0x000(%0); cachee %1, 0x010(%0) \n" \
+ " cachee %1, 0x020(%0); cachee %1, 0x030(%0) \n" \
+ " cachee %1, 0x040(%0); cachee %1, 0x050(%0) \n" \
+ " cachee %1, 0x060(%0); cachee %1, 0x070(%0) \n" \
+ " cachee %1, 0x080(%0); cachee %1, 0x090(%0) \n" \
+ " cachee %1, 0x0a0(%0); cachee %1, 0x0b0(%0) \n" \
+ " cachee %1, 0x0c0(%0); cachee %1, 0x0d0(%0) \n" \
+ " cachee %1, 0x0e0(%0); cachee %1, 0x0f0(%0) \n" \
+ " cachee %1, 0x100(%0); cachee %1, 0x110(%0) \n" \
+ " cachee %1, 0x120(%0); cachee %1, 0x130(%0) \n" \
+ " cachee %1, 0x140(%0); cachee %1, 0x150(%0) \n" \
+ " cachee %1, 0x160(%0); cachee %1, 0x170(%0) \n" \
+ " cachee %1, 0x180(%0); cachee %1, 0x190(%0) \n" \
+ " cachee %1, 0x1a0(%0); cachee %1, 0x1b0(%0) \n" \
+ " cachee %1, 0x1c0(%0); cachee %1, 0x1d0(%0) \n" \
+ " cachee %1, 0x1e0(%0); cachee %1, 0x1f0(%0) \n" \
+ " .set pop \n" \
+ : \
+ : "r" (base), \
+ "i" (op));
+
+#define cache32_unroll32_user(base, op) \
+ __asm__ __volatile__( \
+ " .set push \n" \
+ " .set noreorder \n" \
+ " .set mips0 \n" \
+ " .set eva \n" \
+ " cachee %1, 0x000(%0); cachee %1, 0x020(%0) \n" \
+ " cachee %1, 0x040(%0); cachee %1, 0x060(%0) \n" \
+ " cachee %1, 0x080(%0); cachee %1, 0x0a0(%0) \n" \
+ " cachee %1, 0x0c0(%0); cachee %1, 0x0e0(%0) \n" \
+ " cachee %1, 0x100(%0); cachee %1, 0x120(%0) \n" \
+ " cachee %1, 0x140(%0); cachee %1, 0x160(%0) \n" \
+ " cachee %1, 0x180(%0); cachee %1, 0x1a0(%0) \n" \
+ " cachee %1, 0x1c0(%0); cachee %1, 0x1e0(%0) \n" \
+ " cachee %1, 0x200(%0); cachee %1, 0x220(%0) \n" \
+ " cachee %1, 0x240(%0); cachee %1, 0x260(%0) \n" \
+ " cachee %1, 0x280(%0); cachee %1, 0x2a0(%0) \n" \
+ " cachee %1, 0x2c0(%0); cachee %1, 0x2e0(%0) \n" \
+ " cachee %1, 0x300(%0); cachee %1, 0x320(%0) \n" \
+ " cachee %1, 0x340(%0); cachee %1, 0x360(%0) \n" \
+ " cachee %1, 0x380(%0); cachee %1, 0x3a0(%0) \n" \
+ " cachee %1, 0x3c0(%0); cachee %1, 0x3e0(%0) \n" \
+ " .set pop \n" \
+ : \
+ : "r" (base), \
+ "i" (op));
+
+#define cache64_unroll32_user(base, op) \
+ __asm__ __volatile__( \
+ " .set push \n" \
+ " .set noreorder \n" \
+ " .set mips0 \n" \
+ " .set eva \n" \
+ " cachee %1, 0x000(%0); cachee %1, 0x040(%0) \n" \
+ " cachee %1, 0x080(%0); cachee %1, 0x0c0(%0) \n" \
+ " cachee %1, 0x100(%0); cachee %1, 0x140(%0) \n" \
+ " cachee %1, 0x180(%0); cachee %1, 0x1c0(%0) \n" \
+ " cachee %1, 0x200(%0); cachee %1, 0x240(%0) \n" \
+ " cachee %1, 0x280(%0); cachee %1, 0x2c0(%0) \n" \
+ " cachee %1, 0x300(%0); cachee %1, 0x340(%0) \n" \
+ " cachee %1, 0x380(%0); cachee %1, 0x3c0(%0) \n" \
+ " cachee %1, 0x400(%0); cachee %1, 0x440(%0) \n" \
+ " cachee %1, 0x480(%0); cachee %1, 0x4c0(%0) \n" \
+ " cachee %1, 0x500(%0); cachee %1, 0x540(%0) \n" \
+ " cachee %1, 0x580(%0); cachee %1, 0x5c0(%0) \n" \
+ " cachee %1, 0x600(%0); cachee %1, 0x640(%0) \n" \
+ " cachee %1, 0x680(%0); cachee %1, 0x6c0(%0) \n" \
+ " cachee %1, 0x700(%0); cachee %1, 0x740(%0) \n" \
+ " cachee %1, 0x780(%0); cachee %1, 0x7c0(%0) \n" \
+ " .set pop \n" \
+ : \
+ : "r" (base), \
+ "i" (op));
+
/* build blast_xxx, blast_xxx_page, blast_xxx_page_indexed */
#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize, extra) \
static inline void extra##blast_##pfx##cache##lsize(void) \
@@ -429,6 +533,32 @@ __BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64, )
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128, )
+#define __BUILD_BLAST_USER_CACHE(pfx, desc, indexop, hitop, lsize) \
+static inline void blast_##pfx##cache##lsize##_user_page(unsigned long page) \
+{ \
+ unsigned long start = page; \
+ unsigned long end = page + PAGE_SIZE; \
+ \
+ __##pfx##flush_prologue \
+ \
+ do { \
+ cache##lsize##_unroll32_user(start, hitop); \
+ start += lsize * 32; \
+ } while (start < end); \
+ \
+ __##pfx##flush_epilogue \
+}
+
+__BUILD_BLAST_USER_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D,
+ 16)
+__BUILD_BLAST_USER_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16)
+__BUILD_BLAST_USER_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D,
+ 32)
+__BUILD_BLAST_USER_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32)
+__BUILD_BLAST_USER_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D,
+ 64)
+__BUILD_BLAST_USER_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
+
/* build blast_xxx_range, protected_blast_xxx_range */
#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot, extra) \
static inline void prot##extra##blast_##pfx##cache##_range(unsigned long start, \
@@ -450,12 +580,51 @@ static inline void prot##extra##blast_##pfx##cache##_range(unsigned long start,
__##pfx##flush_epilogue \
}
+#ifndef CONFIG_EVA
+
__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_, )
-__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_, )
__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_, )
+
+#else
+
+#define __BUILD_PROT_BLAST_CACHE_RANGE(pfx, desc, hitop) \
+static inline void protected_blast_##pfx##cache##_range(unsigned long start,\
+ unsigned long end) \
+{ \
+ unsigned long lsize = cpu_##desc##_line_size(); \
+ unsigned long addr = start & ~(lsize - 1); \
+ unsigned long aend = (end - 1) & ~(lsize - 1); \
+ \
+ __##pfx##flush_prologue \
+ \
+ if (segment_eq(get_fs(), USER_DS)) { \
+ while (1) { \
+ protected_cachee_op(hitop, addr); \
+ if (addr == aend) \
+ break; \
+ addr += lsize; \
+ } \
+ } else { \
+ while (1) { \
+ protected_cache_op(hitop, addr); \
+ if (addr == aend) \
+ break; \
+ addr += lsize; \
+ } \
+ \
+ } \
+ __##pfx##flush_epilogue \
+}
+
+__BUILD_PROT_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D)
+__BUILD_PROT_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I)
+
+#endif
+__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_, )
__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I_Loongson2, \
protected_, loongson2_)
__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, , )
+__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, , )
__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, , )
/* blast_inv_dcache_range */
__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, , )
diff --git a/arch/mips/include/asm/sigcontext.h b/arch/mips/include/asm/sigcontext.h
index eeeb0f48c767..f54bdbe85c0d 100644
--- a/arch/mips/include/asm/sigcontext.h
+++ b/arch/mips/include/asm/sigcontext.h
@@ -32,6 +32,8 @@ struct sigcontext32 {
__u32 sc_lo2;
__u32 sc_hi3;
__u32 sc_lo3;
+ __u64 sc_msaregs[32]; /* Most significant 64 bits */
+ __u32 sc_msa_csr;
};
#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 */
#endif /* _ASM_SIGCONTEXT_H */
diff --git a/arch/mips/include/asm/smp-cps.h b/arch/mips/include/asm/smp-cps.h
new file mode 100644
index 000000000000..d60d1a2180d1
--- /dev/null
+++ b/arch/mips/include/asm/smp-cps.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __MIPS_ASM_SMP_CPS_H__
+#define __MIPS_ASM_SMP_CPS_H__
+
+#ifndef __ASSEMBLY__
+
+struct boot_config {
+ unsigned int core;
+ unsigned int vpe;
+ unsigned long pc;
+ unsigned long sp;
+ unsigned long gp;
+};
+
+extern struct boot_config mips_cps_bootcfg;
+
+extern void mips_cps_core_entry(void);
+
+#else /* __ASSEMBLY__ */
+
+.extern mips_cps_bootcfg;
+
+#endif /* __ASSEMBLY__ */
+#endif /* __MIPS_ASM_SMP_CPS_H__ */
diff --git a/arch/mips/include/asm/smp-ops.h b/arch/mips/include/asm/smp-ops.h
index ef2a8041e78b..73d35b18fb64 100644
--- a/arch/mips/include/asm/smp-ops.h
+++ b/arch/mips/include/asm/smp-ops.h
@@ -13,6 +13,8 @@
#include <linux/errno.h>
+#include <asm/mips-cm.h>
+
#ifdef CONFIG_SMP
#include <linux/cpumask.h>
@@ -43,6 +45,9 @@ static inline void plat_smp_setup(void)
mp_ops->smp_setup();
}
+extern void gic_send_ipi_single(int cpu, unsigned int action);
+extern void gic_send_ipi_mask(const struct cpumask *mask, unsigned int action);
+
#else /* !CONFIG_SMP */
struct plat_smp_ops;
@@ -76,6 +81,9 @@ static inline int register_cmp_smp_ops(void)
#ifdef CONFIG_MIPS_CMP
extern struct plat_smp_ops cmp_smp_ops;
+ if (!mips_cm_present())
+ return -ENODEV;
+
register_smp_ops(&cmp_smp_ops);
return 0;
@@ -97,4 +105,13 @@ static inline int register_vsmp_smp_ops(void)
#endif
}
+#ifdef CONFIG_MIPS_CPS
+extern int register_cps_smp_ops(void);
+#else
+static inline int register_cps_smp_ops(void)
+{
+ return -ENODEV;
+}
+#endif
+
#endif /* __ASM_SMP_OPS_H */
diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h
index eb6008758484..efa02acd3dd5 100644
--- a/arch/mips/include/asm/smp.h
+++ b/arch/mips/include/asm/smp.h
@@ -42,6 +42,7 @@ extern int __cpu_logical_map[NR_CPUS];
#define SMP_ICACHE_FLUSH 0x4
/* Used by kexec crashdump to save all cpu's state */
#define SMP_DUMP 0x8
+#define SMP_ASK_C0COUNT 0x10
extern volatile cpumask_t cpu_callin_map;
diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h
index 4857e2c8df5a..d301e108d5b8 100644
--- a/arch/mips/include/asm/stackframe.h
+++ b/arch/mips/include/asm/stackframe.h
@@ -435,7 +435,7 @@
.macro RESTORE_SP_AND_RET
LONG_L sp, PT_R29(sp)
- .set mips3
+ .set arch=r4000
eret
.set mips0
.endm
diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h
index 278d45a09728..495c1041a2cc 100644
--- a/arch/mips/include/asm/switch_to.h
+++ b/arch/mips/include/asm/switch_to.h
@@ -16,22 +16,29 @@
#include <asm/watch.h>
#include <asm/dsp.h>
#include <asm/cop2.h>
+#include <asm/msa.h>
struct task_struct;
+enum {
+ FP_SAVE_NONE = 0,
+ FP_SAVE_VECTOR = -1,
+ FP_SAVE_SCALAR = 1,
+};
+
/**
* resume - resume execution of a task
* @prev: The task previously executed.
* @next: The task to begin executing.
* @next_ti: task_thread_info(next).
- * @usedfpu: Non-zero if prev's FP context should be saved.
+ * @fp_save: Which, if any, FP context to save for prev.
*
* This function is used whilst scheduling to save the context of prev & load
* the context of next. Returns prev.
*/
extern asmlinkage struct task_struct *resume(struct task_struct *prev,
struct task_struct *next, struct thread_info *next_ti,
- u32 usedfpu);
+ s32 fp_save);
extern unsigned int ll_bit;
extern struct task_struct *ll_task;
@@ -75,7 +82,8 @@ do { \
#define switch_to(prev, next, last) \
do { \
- u32 __usedfpu, __c0_stat; \
+ u32 __c0_stat; \
+ s32 __fpsave = FP_SAVE_NONE; \
__mips_mt_fpaff_switch_to(prev); \
if (cpu_has_dsp) \
__save_dsp(prev); \
@@ -88,8 +96,12 @@ do { \
write_c0_status(__c0_stat & ~ST0_CU2); \
} \
__clear_software_ll_bit(); \
- __usedfpu = test_and_clear_tsk_thread_flag(prev, TIF_USEDFPU); \
- (last) = resume(prev, next, task_thread_info(next), __usedfpu); \
+ if (test_and_clear_tsk_thread_flag(prev, TIF_USEDFPU)) \
+ __fpsave = FP_SAVE_SCALAR; \
+ if (test_and_clear_tsk_thread_flag(prev, TIF_USEDMSA)) \
+ __fpsave = FP_SAVE_VECTOR; \
+ (last) = resume(prev, next, task_thread_info(next), __fpsave); \
+ disable_msa(); \
} while (0)
#define finish_arch_switch(prev) \
diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
index 33e8dbfc1b63..6c488c85d791 100644
--- a/arch/mips/include/asm/syscall.h
+++ b/arch/mips/include/asm/syscall.h
@@ -13,17 +13,29 @@
#ifndef __ASM_MIPS_SYSCALL_H
#define __ASM_MIPS_SYSCALL_H
+#include <linux/compiler.h>
#include <linux/audit.h>
#include <linux/elf-em.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <asm/ptrace.h>
+#include <asm/unistd.h>
+
+#ifndef __NR_syscall /* Only defined if _MIPS_SIM == _MIPS_SIM_ABI32 */
+#define __NR_syscall 4000
+#endif
static inline long syscall_get_nr(struct task_struct *task,
struct pt_regs *regs)
{
- return regs->regs[2];
+ /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
+ if ((config_enabled(CONFIG_32BIT) ||
+ test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
+ (regs->regs[2] == __NR_syscall))
+ return regs->regs[4];
+ else
+ return regs->regs[2];
}
static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
@@ -39,14 +51,14 @@ static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
#ifdef CONFIG_32BIT
case 4: case 5: case 6: case 7:
- return get_user(*arg, (int *)usp + 4 * n);
+ return get_user(*arg, (int *)usp + n);
#endif
#ifdef CONFIG_64BIT
case 4: case 5: case 6: case 7:
#ifdef CONFIG_MIPS32_O32
if (test_thread_flag(TIF_32BIT_REGS))
- return get_user(*arg, (int *)usp + 4 * n);
+ return get_user(*arg, (int *)usp + n);
else
#endif
*arg = regs->regs[4 + n];
@@ -57,6 +69,8 @@ static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
default:
BUG();
}
+
+ unreachable();
}
static inline long syscall_get_return_value(struct task_struct *task,
@@ -65,6 +79,12 @@ static inline long syscall_get_return_value(struct task_struct *task,
return regs->regs[2];
}
+static inline void syscall_rollback(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ /* Do nothing */
+}
+
static inline void syscall_set_return_value(struct task_struct *task,
struct pt_regs *regs,
int error, long val)
@@ -83,11 +103,17 @@ static inline void syscall_get_arguments(struct task_struct *task,
unsigned int i, unsigned int n,
unsigned long *args)
{
- unsigned long arg;
int ret;
+ /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
+ if ((config_enabled(CONFIG_32BIT) ||
+ test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
+ (regs->regs[2] == __NR_syscall)) {
+ i++;
+ n++;
+ }
while (n--)
- ret |= mips_get_syscall_arg(&arg, task, regs, i++);
+ ret |= mips_get_syscall_arg(args++, task, regs, i++);
/*
* No way to communicate an error because this is a void function.
@@ -101,11 +127,13 @@ extern const unsigned long sys_call_table[];
extern const unsigned long sys32_call_table[];
extern const unsigned long sysn32_call_table[];
-static inline int __syscall_get_arch(void)
+static inline int syscall_get_arch(struct task_struct *task,
+ struct pt_regs *regs)
{
int arch = EM_MIPS;
#ifdef CONFIG_64BIT
- arch |= __AUDIT_ARCH_64BIT;
+ if (!test_tsk_thread_flag(task, TIF_32BIT_REGS))
+ arch |= __AUDIT_ARCH_64BIT;
#endif
#if defined(__LITTLE_ENDIAN)
arch |= __AUDIT_ARCH_LE;
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index 24846f9053fe..d2d961d6cb86 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -116,6 +116,8 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_LOAD_WATCH 25 /* If set, load watch registers */
#define TIF_SYSCALL_TRACEPOINT 26 /* syscall tracepoint instrumentation */
#define TIF_32BIT_FPREGS 27 /* 32-bit floating point registers */
+#define TIF_USEDMSA 29 /* MSA has been used this quantum */
+#define TIF_MSA_CTX_LIVE 30 /* MSA context must be preserved */
#define TIF_SYSCALL_TRACE 31 /* syscall trace active */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -133,10 +135,13 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_FPUBOUND (1<<TIF_FPUBOUND)
#define _TIF_LOAD_WATCH (1<<TIF_LOAD_WATCH)
#define _TIF_32BIT_FPREGS (1<<TIF_32BIT_FPREGS)
+#define _TIF_USEDMSA (1<<TIF_USEDMSA)
+#define _TIF_MSA_CTX_LIVE (1<<TIF_MSA_CTX_LIVE)
#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)
#define _TIF_WORK_SYSCALL_ENTRY (_TIF_NOHZ | _TIF_SYSCALL_TRACE | \
- _TIF_SYSCALL_AUDIT | _TIF_SYSCALL_TRACEPOINT)
+ _TIF_SYSCALL_AUDIT | \
+ _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP)
/* work to do in syscall_trace_leave() */
#define _TIF_WORK_SYSCALL_EXIT (_TIF_NOHZ | _TIF_SYSCALL_TRACE | \
diff --git a/arch/mips/include/asm/topology.h b/arch/mips/include/asm/topology.h
index 12609a17dc8b..20ea4859c822 100644
--- a/arch/mips/include/asm/topology.h
+++ b/arch/mips/include/asm/topology.h
@@ -10,8 +10,4 @@
#include <topology.h>
-#ifdef CONFIG_SMP
-#define smt_capable() (smp_num_siblings > 1)
-#endif
-
#endif /* __ASM_TOPOLOGY_H */
diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
index f3fa3750f577..a10951090234 100644
--- a/arch/mips/include/asm/uaccess.h
+++ b/arch/mips/include/asm/uaccess.h
@@ -6,6 +6,7 @@
* Copyright (C) 1996, 1997, 1998, 1999, 2000, 03, 04 by Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 2007 Maciej W. Rozycki
+ * Copyright (C) 2014, Imagination Technologies Ltd.
*/
#ifndef _ASM_UACCESS_H
#define _ASM_UACCESS_H
@@ -13,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/thread_info.h>
+#include <asm/asm-eva.h>
/*
* The fs value determines whether argument validity checking should be
@@ -222,11 +224,44 @@ struct __large_struct { unsigned long buf[100]; };
* Yuck. We need two variants, one for 64bit operation and one
* for 32 bit mode and old iron.
*/
+#ifndef CONFIG_EVA
+#define __get_kernel_common(val, size, ptr) __get_user_common(val, size, ptr)
+#else
+/*
+ * Kernel specific functions for EVA. We need to use normal load instructions
+ * to read data from kernel when operating in EVA mode. We use these macros to
+ * avoid redefining __get_user_asm for EVA.
+ */
+#undef _loadd
+#undef _loadw
+#undef _loadh
+#undef _loadb
#ifdef CONFIG_32BIT
-#define __GET_USER_DW(val, ptr) __get_user_asm_ll32(val, ptr)
+#define _loadd _loadw
+#else
+#define _loadd(reg, addr) "ld " reg ", " addr
+#endif
+#define _loadw(reg, addr) "lw " reg ", " addr
+#define _loadh(reg, addr) "lh " reg ", " addr
+#define _loadb(reg, addr) "lb " reg ", " addr
+
+#define __get_kernel_common(val, size, ptr) \
+do { \
+ switch (size) { \
+ case 1: __get_data_asm(val, _loadb, ptr); break; \
+ case 2: __get_data_asm(val, _loadh, ptr); break; \
+ case 4: __get_data_asm(val, _loadw, ptr); break; \
+ case 8: __GET_DW(val, _loadd, ptr); break; \
+ default: __get_user_unknown(); break; \
+ } \
+} while (0)
+#endif
+
+#ifdef CONFIG_32BIT
+#define __GET_DW(val, insn, ptr) __get_data_asm_ll32(val, insn, ptr)
#endif
#ifdef CONFIG_64BIT
-#define __GET_USER_DW(val, ptr) __get_user_asm(val, "ld", ptr)
+#define __GET_DW(val, insn, ptr) __get_data_asm(val, insn, ptr)
#endif
extern void __get_user_unknown(void);
@@ -234,10 +269,10 @@ extern void __get_user_unknown(void);
#define __get_user_common(val, size, ptr) \
do { \
switch (size) { \
- case 1: __get_user_asm(val, "lb", ptr); break; \
- case 2: __get_user_asm(val, "lh", ptr); break; \
- case 4: __get_user_asm(val, "lw", ptr); break; \
- case 8: __GET_USER_DW(val, ptr); break; \
+ case 1: __get_data_asm(val, user_lb, ptr); break; \
+ case 2: __get_data_asm(val, user_lh, ptr); break; \
+ case 4: __get_data_asm(val, user_lw, ptr); break; \
+ case 8: __GET_DW(val, user_ld, ptr); break; \
default: __get_user_unknown(); break; \
} \
} while (0)
@@ -246,8 +281,12 @@ do { \
({ \
int __gu_err; \
\
- __chk_user_ptr(ptr); \
- __get_user_common((x), size, ptr); \
+ if (segment_eq(get_fs(), get_ds())) { \
+ __get_kernel_common((x), size, ptr); \
+ } else { \
+ __chk_user_ptr(ptr); \
+ __get_user_common((x), size, ptr); \
+ } \
__gu_err; \
})
@@ -257,18 +296,22 @@ do { \
const __typeof__(*(ptr)) __user * __gu_ptr = (ptr); \
\
might_fault(); \
- if (likely(access_ok(VERIFY_READ, __gu_ptr, size))) \
- __get_user_common((x), size, __gu_ptr); \
+ if (likely(access_ok(VERIFY_READ, __gu_ptr, size))) { \
+ if (segment_eq(get_fs(), get_ds())) \
+ __get_kernel_common((x), size, __gu_ptr); \
+ else \
+ __get_user_common((x), size, __gu_ptr); \
+ } \
\
__gu_err; \
})
-#define __get_user_asm(val, insn, addr) \
+#define __get_data_asm(val, insn, addr) \
{ \
long __gu_tmp; \
\
__asm__ __volatile__( \
- "1: " insn " %1, %3 \n" \
+ "1: "insn("%1", "%3")" \n" \
"2: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \
@@ -287,7 +330,7 @@ do { \
/*
* Get a long long 64 using 32 bit registers.
*/
-#define __get_user_asm_ll32(val, addr) \
+#define __get_data_asm_ll32(val, insn, addr) \
{ \
union { \
unsigned long long l; \
@@ -295,8 +338,8 @@ do { \
} __gu_tmp; \
\
__asm__ __volatile__( \
- "1: lw %1, (%3) \n" \
- "2: lw %D1, 4(%3) \n" \
+ "1: " insn("%1", "(%3)")" \n" \
+ "2: " insn("%D1", "4(%3)")" \n" \
"3: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \
@@ -315,30 +358,73 @@ do { \
(val) = __gu_tmp.t; \
}
+#ifndef CONFIG_EVA
+#define __put_kernel_common(ptr, size) __put_user_common(ptr, size)
+#else
+/*
+ * Kernel specific functions for EVA. We need to use normal load instructions
+ * to read data from kernel when operating in EVA mode. We use these macros to
+ * avoid redefining __get_data_asm for EVA.
+ */
+#undef _stored
+#undef _storew
+#undef _storeh
+#undef _storeb
+#ifdef CONFIG_32BIT
+#define _stored _storew
+#else
+#define _stored(reg, addr) "ld " reg ", " addr
+#endif
+
+#define _storew(reg, addr) "sw " reg ", " addr
+#define _storeh(reg, addr) "sh " reg ", " addr
+#define _storeb(reg, addr) "sb " reg ", " addr
+
+#define __put_kernel_common(ptr, size) \
+do { \
+ switch (size) { \
+ case 1: __put_data_asm(_storeb, ptr); break; \
+ case 2: __put_data_asm(_storeh, ptr); break; \
+ case 4: __put_data_asm(_storew, ptr); break; \
+ case 8: __PUT_DW(_stored, ptr); break; \
+ default: __put_user_unknown(); break; \
+ } \
+} while(0)
+#endif
+
/*
* Yuck. We need two variants, one for 64bit operation and one
* for 32 bit mode and old iron.
*/
#ifdef CONFIG_32BIT
-#define __PUT_USER_DW(ptr) __put_user_asm_ll32(ptr)
+#define __PUT_DW(insn, ptr) __put_data_asm_ll32(insn, ptr)
#endif
#ifdef CONFIG_64BIT
-#define __PUT_USER_DW(ptr) __put_user_asm("sd", ptr)
+#define __PUT_DW(insn, ptr) __put_data_asm(insn, ptr)
#endif
+#define __put_user_common(ptr, size) \
+do { \
+ switch (size) { \
+ case 1: __put_data_asm(user_sb, ptr); break; \
+ case 2: __put_data_asm(user_sh, ptr); break; \
+ case 4: __put_data_asm(user_sw, ptr); break; \
+ case 8: __PUT_DW(user_sd, ptr); break; \
+ default: __put_user_unknown(); break; \
+ } \
+} while (0)
+
#define __put_user_nocheck(x, ptr, size) \
({ \
__typeof__(*(ptr)) __pu_val; \
int __pu_err = 0; \
\
- __chk_user_ptr(ptr); \
__pu_val = (x); \
- switch (size) { \
- case 1: __put_user_asm("sb", ptr); break; \
- case 2: __put_user_asm("sh", ptr); break; \
- case 4: __put_user_asm("sw", ptr); break; \
- case 8: __PUT_USER_DW(ptr); break; \
- default: __put_user_unknown(); break; \
+ if (segment_eq(get_fs(), get_ds())) { \
+ __put_kernel_common(ptr, size); \
+ } else { \
+ __chk_user_ptr(ptr); \
+ __put_user_common(ptr, size); \
} \
__pu_err; \
})
@@ -351,21 +437,19 @@ do { \
\
might_fault(); \
if (likely(access_ok(VERIFY_WRITE, __pu_addr, size))) { \
- switch (size) { \
- case 1: __put_user_asm("sb", __pu_addr); break; \
- case 2: __put_user_asm("sh", __pu_addr); break; \
- case 4: __put_user_asm("sw", __pu_addr); break; \
- case 8: __PUT_USER_DW(__pu_addr); break; \
- default: __put_user_unknown(); break; \
- } \
+ if (segment_eq(get_fs(), get_ds())) \
+ __put_kernel_common(__pu_addr, size); \
+ else \
+ __put_user_common(__pu_addr, size); \
} \
+ \
__pu_err; \
})
-#define __put_user_asm(insn, ptr) \
+#define __put_data_asm(insn, ptr) \
{ \
__asm__ __volatile__( \
- "1: " insn " %z2, %3 # __put_user_asm\n" \
+ "1: "insn("%z2", "%3")" # __put_data_asm \n" \
"2: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \
@@ -380,11 +464,11 @@ do { \
"i" (-EFAULT)); \
}
-#define __put_user_asm_ll32(ptr) \
+#define __put_data_asm_ll32(insn, ptr) \
{ \
__asm__ __volatile__( \
- "1: sw %2, (%3) # __put_user_asm_ll32 \n" \
- "2: sw %D2, 4(%3) \n" \
+ "1: "insn("%2", "(%3)")" # __put_data_asm_ll32 \n" \
+ "2: "insn("%D2", "4(%3)")" \n" \
"3: \n" \
" .insn \n" \
" .section .fixup,\"ax\" \n" \
@@ -403,6 +487,11 @@ do { \
extern void __put_user_unknown(void);
/*
+ * ul{b,h,w} are macros and there are no equivalent macros for EVA.
+ * EVA unaligned access is handled in the ADE exception handler.
+ */
+#ifndef CONFIG_EVA
+/*
* put_user_unaligned: - Write a simple value into user space.
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
@@ -504,7 +593,7 @@ extern void __get_user_unaligned_unknown(void);
#define __get_user_unaligned_common(val, size, ptr) \
do { \
switch (size) { \
- case 1: __get_user_asm(val, "lb", ptr); break; \
+ case 1: __get_data_asm(val, "lb", ptr); break; \
case 2: __get_user_unaligned_asm(val, "ulh", ptr); break; \
case 4: __get_user_unaligned_asm(val, "ulw", ptr); break; \
case 8: __GET_USER_UNALIGNED_DW(val, ptr); break; \
@@ -531,7 +620,7 @@ do { \
__gu_err; \
})
-#define __get_user_unaligned_asm(val, insn, addr) \
+#define __get_data_unaligned_asm(val, insn, addr) \
{ \
long __gu_tmp; \
\
@@ -594,19 +683,23 @@ do { \
#define __PUT_USER_UNALIGNED_DW(ptr) __put_user_unaligned_asm("usd", ptr)
#endif
+#define __put_user_unaligned_common(ptr, size) \
+do { \
+ switch (size) { \
+ case 1: __put_data_asm("sb", ptr); break; \
+ case 2: __put_user_unaligned_asm("ush", ptr); break; \
+ case 4: __put_user_unaligned_asm("usw", ptr); break; \
+ case 8: __PUT_USER_UNALIGNED_DW(ptr); break; \
+ default: __put_user_unaligned_unknown(); break; \
+} while (0)
+
#define __put_user_unaligned_nocheck(x,ptr,size) \
({ \
__typeof__(*(ptr)) __pu_val; \
int __pu_err = 0; \
\
__pu_val = (x); \
- switch (size) { \
- case 1: __put_user_asm("sb", ptr); break; \
- case 2: __put_user_unaligned_asm("ush", ptr); break; \
- case 4: __put_user_unaligned_asm("usw", ptr); break; \
- case 8: __PUT_USER_UNALIGNED_DW(ptr); break; \
- default: __put_user_unaligned_unknown(); break; \
- } \
+ __put_user_unaligned_common(ptr, size); \
__pu_err; \
})
@@ -616,15 +709,9 @@ do { \
__typeof__(*(ptr)) __pu_val = (x); \
int __pu_err = -EFAULT; \
\
- if (likely(access_ok(VERIFY_WRITE, __pu_addr, size))) { \
- switch (size) { \
- case 1: __put_user_asm("sb", __pu_addr); break; \
- case 2: __put_user_unaligned_asm("ush", __pu_addr); break; \
- case 4: __put_user_unaligned_asm("usw", __pu_addr); break; \
- case 8: __PUT_USER_UNALGINED_DW(__pu_addr); break; \
- default: __put_user_unaligned_unknown(); break; \
- } \
- } \
+ if (likely(access_ok(VERIFY_WRITE, __pu_addr, size))) \
+ __put_user_unaligned_common(__pu_addr, size); \
+ \
__pu_err; \
})
@@ -669,6 +756,7 @@ do { \
}
extern void __put_user_unaligned_unknown(void);
+#endif
/*
* We're generating jump to subroutines which will be outside the range of
@@ -693,6 +781,7 @@ extern void __put_user_unaligned_unknown(void);
extern size_t __copy_user(void *__to, const void *__from, size_t __n);
+#ifndef CONFIG_EVA
#define __invoke_copy_to_user(to, from, n) \
({ \
register void __user *__cu_to_r __asm__("$4"); \
@@ -711,6 +800,11 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n);
__cu_len_r; \
})
+#define __invoke_copy_to_kernel(to, from, n) \
+ __invoke_copy_to_user(to, from, n)
+
+#endif
+
/*
* __copy_to_user: - Copy a block of data into user space, with less checking.
* @to: Destination address, in user space.
@@ -735,7 +829,12 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n);
__cu_from = (from); \
__cu_len = (n); \
might_fault(); \
- __cu_len = __invoke_copy_to_user(__cu_to, __cu_from, __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) \
+ __cu_len = __invoke_copy_to_kernel(__cu_to, __cu_from, \
+ __cu_len); \
+ else \
+ __cu_len = __invoke_copy_to_user(__cu_to, __cu_from, \
+ __cu_len); \
__cu_len; \
})
@@ -750,7 +849,12 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_to = (to); \
__cu_from = (from); \
__cu_len = (n); \
- __cu_len = __invoke_copy_to_user(__cu_to, __cu_from, __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) \
+ __cu_len = __invoke_copy_to_kernel(__cu_to, __cu_from, \
+ __cu_len); \
+ else \
+ __cu_len = __invoke_copy_to_user(__cu_to, __cu_from, \
+ __cu_len); \
__cu_len; \
})
@@ -763,8 +867,14 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_to = (to); \
__cu_from = (from); \
__cu_len = (n); \
- __cu_len = __invoke_copy_from_user_inatomic(__cu_to, __cu_from, \
- __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) \
+ __cu_len = __invoke_copy_from_kernel_inatomic(__cu_to, \
+ __cu_from,\
+ __cu_len);\
+ else \
+ __cu_len = __invoke_copy_from_user_inatomic(__cu_to, \
+ __cu_from, \
+ __cu_len); \
__cu_len; \
})
@@ -790,14 +900,23 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_to = (to); \
__cu_from = (from); \
__cu_len = (n); \
- if (access_ok(VERIFY_WRITE, __cu_to, __cu_len)) { \
- might_fault(); \
- __cu_len = __invoke_copy_to_user(__cu_to, __cu_from, \
- __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) { \
+ __cu_len = __invoke_copy_to_kernel(__cu_to, \
+ __cu_from, \
+ __cu_len); \
+ } else { \
+ if (access_ok(VERIFY_WRITE, __cu_to, __cu_len)) { \
+ might_fault(); \
+ __cu_len = __invoke_copy_to_user(__cu_to, \
+ __cu_from, \
+ __cu_len); \
+ } \
} \
__cu_len; \
})
+#ifndef CONFIG_EVA
+
#define __invoke_copy_from_user(to, from, n) \
({ \
register void *__cu_to_r __asm__("$4"); \
@@ -821,6 +940,17 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_len_r; \
})
+#define __invoke_copy_from_kernel(to, from, n) \
+ __invoke_copy_from_user(to, from, n)
+
+/* For userland <-> userland operations */
+#define ___invoke_copy_in_user(to, from, n) \
+ __invoke_copy_from_user(to, from, n)
+
+/* For kernel <-> kernel operations */
+#define ___invoke_copy_in_kernel(to, from, n) \
+ __invoke_copy_from_user(to, from, n)
+
#define __invoke_copy_from_user_inatomic(to, from, n) \
({ \
register void *__cu_to_r __asm__("$4"); \
@@ -844,6 +974,97 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_len_r; \
})
+#define __invoke_copy_from_kernel_inatomic(to, from, n) \
+ __invoke_copy_from_user_inatomic(to, from, n) \
+
+#else
+
+/* EVA specific functions */
+
+extern size_t __copy_user_inatomic_eva(void *__to, const void *__from,
+ size_t __n);
+extern size_t __copy_from_user_eva(void *__to, const void *__from,
+ size_t __n);
+extern size_t __copy_to_user_eva(void *__to, const void *__from,
+ size_t __n);
+extern size_t __copy_in_user_eva(void *__to, const void *__from, size_t __n);
+
+#define __invoke_copy_from_user_eva_generic(to, from, n, func_ptr) \
+({ \
+ register void *__cu_to_r __asm__("$4"); \
+ register const void __user *__cu_from_r __asm__("$5"); \
+ register long __cu_len_r __asm__("$6"); \
+ \
+ __cu_to_r = (to); \
+ __cu_from_r = (from); \
+ __cu_len_r = (n); \
+ __asm__ __volatile__( \
+ ".set\tnoreorder\n\t" \
+ __MODULE_JAL(func_ptr) \
+ ".set\tnoat\n\t" \
+ __UA_ADDU "\t$1, %1, %2\n\t" \
+ ".set\tat\n\t" \
+ ".set\treorder" \
+ : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r) \
+ : \
+ : "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31", \
+ DADDI_SCRATCH, "memory"); \
+ __cu_len_r; \
+})
+
+#define __invoke_copy_to_user_eva_generic(to, from, n, func_ptr) \
+({ \
+ register void *__cu_to_r __asm__("$4"); \
+ register const void __user *__cu_from_r __asm__("$5"); \
+ register long __cu_len_r __asm__("$6"); \
+ \
+ __cu_to_r = (to); \
+ __cu_from_r = (from); \
+ __cu_len_r = (n); \
+ __asm__ __volatile__( \
+ __MODULE_JAL(func_ptr) \
+ : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r) \
+ : \
+ : "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31", \
+ DADDI_SCRATCH, "memory"); \
+ __cu_len_r; \
+})
+
+/*
+ * Source or destination address is in userland. We need to go through
+ * the TLB
+ */
+#define __invoke_copy_from_user(to, from, n) \
+ __invoke_copy_from_user_eva_generic(to, from, n, __copy_from_user_eva)
+
+#define __invoke_copy_from_user_inatomic(to, from, n) \
+ __invoke_copy_from_user_eva_generic(to, from, n, \
+ __copy_user_inatomic_eva)
+
+#define __invoke_copy_to_user(to, from, n) \
+ __invoke_copy_to_user_eva_generic(to, from, n, __copy_to_user_eva)
+
+#define ___invoke_copy_in_user(to, from, n) \
+ __invoke_copy_from_user_eva_generic(to, from, n, __copy_in_user_eva)
+
+/*
+ * Source or destination address in the kernel. We are not going through
+ * the TLB
+ */
+#define __invoke_copy_from_kernel(to, from, n) \
+ __invoke_copy_from_user_eva_generic(to, from, n, __copy_user)
+
+#define __invoke_copy_from_kernel_inatomic(to, from, n) \
+ __invoke_copy_from_user_eva_generic(to, from, n, __copy_user_inatomic)
+
+#define __invoke_copy_to_kernel(to, from, n) \
+ __invoke_copy_to_user_eva_generic(to, from, n, __copy_user)
+
+#define ___invoke_copy_in_kernel(to, from, n) \
+ __invoke_copy_from_user_eva_generic(to, from, n, __copy_user)
+
+#endif /* CONFIG_EVA */
+
/*
* __copy_from_user: - Copy a block of data from user space, with less checking.
* @to: Destination address, in kernel space.
@@ -901,10 +1122,17 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_to = (to); \
__cu_from = (from); \
__cu_len = (n); \
- if (access_ok(VERIFY_READ, __cu_from, __cu_len)) { \
- might_fault(); \
- __cu_len = __invoke_copy_from_user(__cu_to, __cu_from, \
- __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) { \
+ __cu_len = __invoke_copy_from_kernel(__cu_to, \
+ __cu_from, \
+ __cu_len); \
+ } else { \
+ if (access_ok(VERIFY_READ, __cu_from, __cu_len)) { \
+ might_fault(); \
+ __cu_len = __invoke_copy_from_user(__cu_to, \
+ __cu_from, \
+ __cu_len); \
+ } \
} \
__cu_len; \
})
@@ -918,9 +1146,14 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_to = (to); \
__cu_from = (from); \
__cu_len = (n); \
- might_fault(); \
- __cu_len = __invoke_copy_from_user(__cu_to, __cu_from, \
- __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) { \
+ __cu_len = ___invoke_copy_in_kernel(__cu_to, __cu_from, \
+ __cu_len); \
+ } else { \
+ might_fault(); \
+ __cu_len = ___invoke_copy_in_user(__cu_to, __cu_from, \
+ __cu_len); \
+ } \
__cu_len; \
})
@@ -933,11 +1166,17 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
__cu_to = (to); \
__cu_from = (from); \
__cu_len = (n); \
- if (likely(access_ok(VERIFY_READ, __cu_from, __cu_len) && \
- access_ok(VERIFY_WRITE, __cu_to, __cu_len))) { \
- might_fault(); \
- __cu_len = __invoke_copy_from_user(__cu_to, __cu_from, \
- __cu_len); \
+ if (segment_eq(get_fs(), get_ds())) { \
+ __cu_len = ___invoke_copy_in_kernel(__cu_to,__cu_from, \
+ __cu_len); \
+ } else { \
+ if (likely(access_ok(VERIFY_READ, __cu_from, __cu_len) &&\
+ access_ok(VERIFY_WRITE, __cu_to, __cu_len))) {\
+ might_fault(); \
+ __cu_len = ___invoke_copy_in_user(__cu_to, \
+ __cu_from, \
+ __cu_len); \
+ } \
} \
__cu_len; \
})
@@ -1007,16 +1246,28 @@ __strncpy_from_user(char *__to, const char __user *__from, long __len)
{
long res;
- might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, %2\n\t"
- "move\t$6, %3\n\t"
- __MODULE_JAL(__strncpy_from_user_nocheck_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (__to), "r" (__from), "r" (__len)
- : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+ if (segment_eq(get_fs(), get_ds())) {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ "move\t$6, %3\n\t"
+ __MODULE_JAL(__strncpy_from_kernel_nocheck_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (__to), "r" (__from), "r" (__len)
+ : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+ } else {
+ might_fault();
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ "move\t$6, %3\n\t"
+ __MODULE_JAL(__strncpy_from_user_nocheck_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (__to), "r" (__from), "r" (__len)
+ : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+ }
return res;
}
@@ -1044,16 +1295,28 @@ strncpy_from_user(char *__to, const char __user *__from, long __len)
{
long res;
- might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, %2\n\t"
- "move\t$6, %3\n\t"
- __MODULE_JAL(__strncpy_from_user_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (__to), "r" (__from), "r" (__len)
- : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+ if (segment_eq(get_fs(), get_ds())) {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ "move\t$6, %3\n\t"
+ __MODULE_JAL(__strncpy_from_kernel_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (__to), "r" (__from), "r" (__len)
+ : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+ } else {
+ might_fault();
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ "move\t$6, %3\n\t"
+ __MODULE_JAL(__strncpy_from_user_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (__to), "r" (__from), "r" (__len)
+ : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
+ }
return res;
}
@@ -1063,14 +1326,24 @@ static inline long __strlen_user(const char __user *s)
{
long res;
- might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- __MODULE_JAL(__strlen_user_nocheck_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (s)
- : "$2", "$4", __UA_t0, "$31");
+ if (segment_eq(get_fs(), get_ds())) {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ __MODULE_JAL(__strlen_kernel_nocheck_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s)
+ : "$2", "$4", __UA_t0, "$31");
+ } else {
+ might_fault();
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ __MODULE_JAL(__strlen_user_nocheck_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s)
+ : "$2", "$4", __UA_t0, "$31");
+ }
return res;
}
@@ -1093,14 +1366,24 @@ static inline long strlen_user(const char __user *s)
{
long res;
- might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- __MODULE_JAL(__strlen_user_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (s)
- : "$2", "$4", __UA_t0, "$31");
+ if (segment_eq(get_fs(), get_ds())) {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ __MODULE_JAL(__strlen_kernel_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s)
+ : "$2", "$4", __UA_t0, "$31");
+ } else {
+ might_fault();
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ __MODULE_JAL(__strlen_kernel_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s)
+ : "$2", "$4", __UA_t0, "$31");
+ }
return res;
}
@@ -1110,15 +1393,26 @@ static inline long __strnlen_user(const char __user *s, long n)
{
long res;
- might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, %2\n\t"
- __MODULE_JAL(__strnlen_user_nocheck_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (s), "r" (n)
- : "$2", "$4", "$5", __UA_t0, "$31");
+ if (segment_eq(get_fs(), get_ds())) {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ __MODULE_JAL(__strnlen_kernel_nocheck_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s), "r" (n)
+ : "$2", "$4", "$5", __UA_t0, "$31");
+ } else {
+ might_fault();
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ __MODULE_JAL(__strnlen_user_nocheck_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s), "r" (n)
+ : "$2", "$4", "$5", __UA_t0, "$31");
+ }
return res;
}
@@ -1142,14 +1436,25 @@ static inline long strnlen_user(const char __user *s, long n)
long res;
might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, %2\n\t"
- __MODULE_JAL(__strnlen_user_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (s), "r" (n)
- : "$2", "$4", "$5", __UA_t0, "$31");
+ if (segment_eq(get_fs(), get_ds())) {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ __MODULE_JAL(__strnlen_kernel_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s), "r" (n)
+ : "$2", "$4", "$5", __UA_t0, "$31");
+ } else {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ __MODULE_JAL(__strnlen_user_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s), "r" (n)
+ : "$2", "$4", "$5", __UA_t0, "$31");
+ }
return res;
}
diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h
index 4d3b92886665..413d6c612bec 100644
--- a/arch/mips/include/asm/unistd.h
+++ b/arch/mips/include/asm/unistd.h
@@ -24,7 +24,6 @@
#ifndef __ASSEMBLY__
-#define __ARCH_OMIT_COMPAT_SYS_GETDENTS64
#define __ARCH_WANT_OLD_READDIR
#define __ARCH_WANT_SYS_ALARM
#define __ARCH_WANT_SYS_GETHOSTNAME
diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h
index b39ba25b41cc..df6e775f3fef 100644
--- a/arch/mips/include/uapi/asm/inst.h
+++ b/arch/mips/include/uapi/asm/inst.h
@@ -8,6 +8,7 @@
* Copyright (C) 1996, 2000 by Ralf Baechle
* Copyright (C) 2006 by Thiemo Seufer
* Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*/
#ifndef _UAPI_ASM_INST_H
#define _UAPI_ASM_INST_H
@@ -73,10 +74,16 @@ enum spec2_op {
enum spec3_op {
ext_op, dextm_op, dextu_op, dext_op,
ins_op, dinsm_op, dinsu_op, dins_op,
- lx_op = 0x0a,
- bshfl_op = 0x20,
- dbshfl_op = 0x24,
- rdhwr_op = 0x3b
+ lx_op = 0x0a, lwle_op = 0x19,
+ lwre_op = 0x1a, cachee_op = 0x1b,
+ sbe_op = 0x1c, she_op = 0x1d,
+ sce_op = 0x1e, swe_op = 0x1f,
+ bshfl_op = 0x20, swle_op = 0x21,
+ swre_op = 0x22, prefe_op = 0x23,
+ dbshfl_op = 0x24, lbue_op = 0x28,
+ lhue_op = 0x29, lbe_op = 0x2c,
+ lhe_op = 0x2d, lle_op = 0x2e,
+ lwe_op = 0x2f, rdhwr_op = 0x3b
};
/*
@@ -163,8 +170,8 @@ enum cop1_sdw_func {
*/
enum cop1x_func {
lwxc1_op = 0x00, ldxc1_op = 0x01,
- pfetch_op = 0x07, swxc1_op = 0x08,
- sdxc1_op = 0x09, madd_s_op = 0x20,
+ swxc1_op = 0x08, sdxc1_op = 0x09,
+ pfetch_op = 0x0f, madd_s_op = 0x20,
madd_d_op = 0x21, madd_e_op = 0x22,
msub_s_op = 0x28, msub_d_op = 0x29,
msub_e_op = 0x2a, nmadd_s_op = 0x30,
@@ -592,6 +599,15 @@ struct v_format { /* MDMX vector format */
;)))))))
};
+struct spec3_format { /* SPEC3 */
+ BITFIELD_FIELD(unsigned int opcode:6,
+ BITFIELD_FIELD(unsigned int rs:5,
+ BITFIELD_FIELD(unsigned int rt:5,
+ BITFIELD_FIELD(signed int simmediate:9,
+ BITFIELD_FIELD(unsigned int func:7,
+ ;)))))
+};
+
/*
* microMIPS instruction formats (32-bit length)
*
@@ -863,6 +879,7 @@ union mips_instruction {
struct b_format b_format;
struct ps_format ps_format;
struct v_format v_format;
+ struct spec3_format spec3_format;
struct fb_format fb_format;
struct fp0_format fp0_format;
struct mm_fp0_format mm_fp0_format;
diff --git a/arch/mips/include/uapi/asm/sigcontext.h b/arch/mips/include/uapi/asm/sigcontext.h
index 6c9906f59c6e..681c17603a48 100644
--- a/arch/mips/include/uapi/asm/sigcontext.h
+++ b/arch/mips/include/uapi/asm/sigcontext.h
@@ -12,6 +12,10 @@
#include <linux/types.h>
#include <asm/sgidefs.h>
+/* Bits which may be set in sc_used_math */
+#define USEDMATH_FP (1 << 0)
+#define USEDMATH_MSA (1 << 1)
+
#if _MIPS_SIM == _MIPS_SIM_ABI32
/*
@@ -37,6 +41,8 @@ struct sigcontext {
unsigned long sc_lo2;
unsigned long sc_hi3;
unsigned long sc_lo3;
+ unsigned long long sc_msaregs[32]; /* Most significant 64 bits */
+ unsigned long sc_msa_csr;
};
#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
@@ -70,6 +76,8 @@ struct sigcontext {
__u32 sc_used_math;
__u32 sc_dsp;
__u32 sc_reserved;
+ __u64 sc_msaregs[32];
+ __u32 sc_msa_csr;
};
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 26c6175e1379..277dab301cea 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -53,6 +53,8 @@ obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o
obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o
obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o
obj-$(CONFIG_MIPS_CMP) += smp-cmp.o
+obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o
+obj-$(CONFIG_MIPS_GIC_IPI) += smp-gic.o
obj-$(CONFIG_CPU_MIPSR2) += spram.o
obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o
@@ -102,6 +104,9 @@ obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+obj-$(CONFIG_MIPS_CM) += mips-cm.o
+obj-$(CONFIG_MIPS_CPC) += mips-cpc.o
+
#
# DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is not
# safe to unconditionnaly use the assembler -mdsp / -mdspr2 switches
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index 0c2e853c3db4..0ea75c244b48 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -16,6 +16,7 @@
#include <linux/suspend.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
+#include <asm/smp-cps.h>
#include <linux/kvm_host.h>
@@ -168,6 +169,72 @@ void output_thread_fpu_defines(void)
OFFSET(THREAD_FPR30, task_struct, thread.fpu.fpr[30]);
OFFSET(THREAD_FPR31, task_struct, thread.fpu.fpr[31]);
+ /* the least significant 64 bits of each FP register */
+ OFFSET(THREAD_FPR0_LS64, task_struct,
+ thread.fpu.fpr[0].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR1_LS64, task_struct,
+ thread.fpu.fpr[1].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR2_LS64, task_struct,
+ thread.fpu.fpr[2].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR3_LS64, task_struct,
+ thread.fpu.fpr[3].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR4_LS64, task_struct,
+ thread.fpu.fpr[4].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR5_LS64, task_struct,
+ thread.fpu.fpr[5].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR6_LS64, task_struct,
+ thread.fpu.fpr[6].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR7_LS64, task_struct,
+ thread.fpu.fpr[7].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR8_LS64, task_struct,
+ thread.fpu.fpr[8].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR9_LS64, task_struct,
+ thread.fpu.fpr[9].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR10_LS64, task_struct,
+ thread.fpu.fpr[10].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR11_LS64, task_struct,
+ thread.fpu.fpr[11].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR12_LS64, task_struct,
+ thread.fpu.fpr[12].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR13_LS64, task_struct,
+ thread.fpu.fpr[13].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR14_LS64, task_struct,
+ thread.fpu.fpr[14].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR15_LS64, task_struct,
+ thread.fpu.fpr[15].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR16_LS64, task_struct,
+ thread.fpu.fpr[16].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR17_LS64, task_struct,
+ thread.fpu.fpr[17].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR18_LS64, task_struct,
+ thread.fpu.fpr[18].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR19_LS64, task_struct,
+ thread.fpu.fpr[19].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR20_LS64, task_struct,
+ thread.fpu.fpr[20].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR21_LS64, task_struct,
+ thread.fpu.fpr[21].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR22_LS64, task_struct,
+ thread.fpu.fpr[22].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR23_LS64, task_struct,
+ thread.fpu.fpr[23].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR24_LS64, task_struct,
+ thread.fpu.fpr[24].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR25_LS64, task_struct,
+ thread.fpu.fpr[25].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR26_LS64, task_struct,
+ thread.fpu.fpr[26].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR27_LS64, task_struct,
+ thread.fpu.fpr[27].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR28_LS64, task_struct,
+ thread.fpu.fpr[28].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR29_LS64, task_struct,
+ thread.fpu.fpr[29].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR30_LS64, task_struct,
+ thread.fpu.fpr[30].val64[FPR_IDX(64, 0)]);
+ OFFSET(THREAD_FPR31_LS64, task_struct,
+ thread.fpu.fpr[31].val64[FPR_IDX(64, 0)]);
+
OFFSET(THREAD_FCR31, task_struct, thread.fpu.fcr31);
BLANK();
}
@@ -228,6 +295,7 @@ void output_sc_defines(void)
OFFSET(SC_LO2, sigcontext, sc_lo2);
OFFSET(SC_HI3, sigcontext, sc_hi3);
OFFSET(SC_LO3, sigcontext, sc_lo3);
+ OFFSET(SC_MSAREGS, sigcontext, sc_msaregs);
BLANK();
}
#endif
@@ -242,6 +310,7 @@ void output_sc_defines(void)
OFFSET(SC_MDLO, sigcontext, sc_mdlo);
OFFSET(SC_PC, sigcontext, sc_pc);
OFFSET(SC_FPC_CSR, sigcontext, sc_fpc_csr);
+ OFFSET(SC_MSAREGS, sigcontext, sc_msaregs);
BLANK();
}
#endif
@@ -253,6 +322,7 @@ void output_sc32_defines(void)
OFFSET(SC32_FPREGS, sigcontext32, sc_fpregs);
OFFSET(SC32_FPC_CSR, sigcontext32, sc_fpc_csr);
OFFSET(SC32_FPC_EIR, sigcontext32, sc_fpc_eir);
+ OFFSET(SC32_MSAREGS, sigcontext32, sc_msaregs);
BLANK();
}
#endif
@@ -397,3 +467,15 @@ void output_kvm_defines(void)
OFFSET(COP0_STATUS, mips_coproc, reg[MIPS_CP0_STATUS][0]);
BLANK();
}
+
+#ifdef CONFIG_MIPS_CPS
+void output_cps_defines(void)
+{
+ COMMENT(" MIPS CPS offsets. ");
+ OFFSET(BOOTCFG_CORE, boot_config, core);
+ OFFSET(BOOTCFG_VPE, boot_config, vpe);
+ OFFSET(BOOTCFG_PC, boot_config, pc);
+ OFFSET(BOOTCFG_SP, boot_config, sp);
+ OFFSET(BOOTCFG_GP, boot_config, gp);
+}
+#endif
diff --git a/arch/mips/kernel/bmips_vec.S b/arch/mips/kernel/bmips_vec.S
index a5bf73d22fcc..290c23b51678 100644
--- a/arch/mips/kernel/bmips_vec.S
+++ b/arch/mips/kernel/bmips_vec.S
@@ -122,7 +122,7 @@ NESTED(bmips_reset_nmi_vec, PT_SIZE, sp)
jr k0
RESTORE_ALL
- .set mips3
+ .set arch=r4000
eret
/***********************************************************************
diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S
new file mode 100644
index 000000000000..f7a46db4b161
--- /dev/null
+++ b/arch/mips/kernel/cps-vec.S
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <asm/addrspace.h>
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/asmmacro.h>
+#include <asm/cacheops.h>
+#include <asm/mipsregs.h>
+
+#define GCR_CL_COHERENCE_OFS 0x2008
+
+.section .text.cps-vec
+.balign 0x1000
+.set noreorder
+
+LEAF(mips_cps_core_entry)
+ /*
+ * These first 8 bytes will be patched by cps_smp_setup to load the
+ * base address of the CM GCRs into register v1.
+ */
+ .quad 0
+
+ /* Check whether we're here due to an NMI */
+ mfc0 k0, CP0_STATUS
+ and k0, k0, ST0_NMI
+ beqz k0, not_nmi
+ nop
+
+ /* This is an NMI */
+ la k0, nmi_handler
+ jr k0
+ nop
+
+not_nmi:
+ /* Setup Cause */
+ li t0, CAUSEF_IV
+ mtc0 t0, CP0_CAUSE
+
+ /* Setup Status */
+ li t0, ST0_CU1 | ST0_CU0
+ mtc0 t0, CP0_STATUS
+
+ /*
+ * Clear the bits used to index the caches. Note that the architecture
+ * dictates that writing to any of TagLo or TagHi selects 0 or 2 should
+ * be valid for all MIPS32 CPUs, even those for which said writes are
+ * unnecessary.
+ */
+ mtc0 zero, CP0_TAGLO, 0
+ mtc0 zero, CP0_TAGHI, 0
+ mtc0 zero, CP0_TAGLO, 2
+ mtc0 zero, CP0_TAGHI, 2
+ ehb
+
+ /* Primary cache configuration is indicated by Config1 */
+ mfc0 v0, CP0_CONFIG, 1
+
+ /* Detect I-cache line size */
+ _EXT t0, v0, MIPS_CONF1_IL_SHF, MIPS_CONF1_IL_SZ
+ beqz t0, icache_done
+ li t1, 2
+ sllv t0, t1, t0
+
+ /* Detect I-cache size */
+ _EXT t1, v0, MIPS_CONF1_IS_SHF, MIPS_CONF1_IS_SZ
+ xori t2, t1, 0x7
+ beqz t2, 1f
+ li t3, 32
+ addi t1, t1, 1
+ sllv t1, t3, t1
+1: /* At this point t1 == I-cache sets per way */
+ _EXT t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ
+ addi t2, t2, 1
+ mul t1, t1, t0
+ mul t1, t1, t2
+
+ li a0, KSEG0
+ add a1, a0, t1
+1: cache Index_Store_Tag_I, 0(a0)
+ add a0, a0, t0
+ bne a0, a1, 1b
+ nop
+icache_done:
+
+ /* Detect D-cache line size */
+ _EXT t0, v0, MIPS_CONF1_DL_SHF, MIPS_CONF1_DL_SZ
+ beqz t0, dcache_done
+ li t1, 2
+ sllv t0, t1, t0
+
+ /* Detect D-cache size */
+ _EXT t1, v0, MIPS_CONF1_DS_SHF, MIPS_CONF1_DS_SZ
+ xori t2, t1, 0x7
+ beqz t2, 1f
+ li t3, 32
+ addi t1, t1, 1
+ sllv t1, t3, t1
+1: /* At this point t1 == D-cache sets per way */
+ _EXT t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ
+ addi t2, t2, 1
+ mul t1, t1, t0
+ mul t1, t1, t2
+
+ li a0, KSEG0
+ addu a1, a0, t1
+ subu a1, a1, t0
+1: cache Index_Store_Tag_D, 0(a0)
+ bne a0, a1, 1b
+ add a0, a0, t0
+dcache_done:
+
+ /* Set Kseg0 cacheable, coherent, write-back, write-allocate */
+ mfc0 t0, CP0_CONFIG
+ ori t0, 0x7
+ xori t0, 0x2
+ mtc0 t0, CP0_CONFIG
+ ehb
+
+ /* Enter the coherent domain */
+ li t0, 0xff
+ sw t0, GCR_CL_COHERENCE_OFS(v1)
+ ehb
+
+ /* Jump to kseg0 */
+ la t0, 1f
+ jr t0
+ nop
+
+1: /* We're up, cached & coherent */
+
+ /*
+ * TODO: We should check the VPE number we intended to boot here, and
+ * if non-zero we should start that VPE and stop this one. For
+ * the moment this doesn't matter since CPUs are brought up
+ * sequentially and in order, but once hotplug is implemented
+ * this will need revisiting.
+ */
+
+ /* Off we go! */
+ la t0, mips_cps_bootcfg
+ lw t1, BOOTCFG_PC(t0)
+ lw gp, BOOTCFG_GP(t0)
+ lw sp, BOOTCFG_SP(t0)
+ jr t1
+ nop
+ END(mips_cps_core_entry)
+
+.org 0x200
+LEAF(excep_tlbfill)
+ b .
+ nop
+ END(excep_tlbfill)
+
+.org 0x280
+LEAF(excep_xtlbfill)
+ b .
+ nop
+ END(excep_xtlbfill)
+
+.org 0x300
+LEAF(excep_cache)
+ b .
+ nop
+ END(excep_cache)
+
+.org 0x380
+LEAF(excep_genex)
+ b .
+ nop
+ END(excep_genex)
+
+.org 0x400
+LEAF(excep_intex)
+ b .
+ nop
+ END(excep_intex)
+
+.org 0x480
+LEAF(excep_ejtag)
+ la k0, ejtag_debug_handler
+ jr k0
+ nop
+ END(excep_ejtag)
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 530f832de02c..6e8fb85ce7c3 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -23,6 +23,8 @@
#include <asm/cpu-type.h>
#include <asm/fpu.h>
#include <asm/mipsregs.h>
+#include <asm/mipsmtregs.h>
+#include <asm/msa.h>
#include <asm/watch.h>
#include <asm/elf.h>
#include <asm/spram.h>
@@ -126,6 +128,20 @@ static inline int __cpu_has_fpu(void)
return ((cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE);
}
+static inline unsigned long cpu_get_msa_id(void)
+{
+ unsigned long status, conf5, msa_id;
+
+ status = read_c0_status();
+ __enable_fpu(FPU_64BIT);
+ conf5 = read_c0_config5();
+ enable_msa();
+ msa_id = read_msa_ir();
+ write_c0_config5(conf5);
+ write_c0_status(status);
+ return msa_id;
+}
+
static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
{
#ifdef __NEED_VMBITS_PROBE
@@ -166,11 +182,12 @@ static char unknown_isa[] = KERN_ERR \
static void set_ftlb_enable(struct cpuinfo_mips *c, int enable)
{
unsigned int config6;
- /*
- * Config6 is implementation dependent and it's currently only
- * used by proAptiv
- */
- if (c->cputype == CPU_PROAPTIV) {
+
+ /* It's implementation dependent how the FTLB can be enabled */
+ switch (c->cputype) {
+ case CPU_PROAPTIV:
+ case CPU_P5600:
+ /* proAptiv & related cores use Config6 to enable the FTLB */
config6 = read_c0_config6();
if (enable)
/* Enable FTLB */
@@ -179,6 +196,7 @@ static void set_ftlb_enable(struct cpuinfo_mips *c, int enable)
/* Disable FTLB */
write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN);
back_to_back_c0_hazard();
+ break;
}
}
@@ -301,6 +319,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
c->ases |= MIPS_ASE_VZ;
if (config3 & MIPS_CONF3_SC)
c->options |= MIPS_CPU_SEGMENTS;
+ if (config3 & MIPS_CONF3_MSA)
+ c->ases |= MIPS_ASE_MSA;
return config3 & MIPS_CONF_M;
}
@@ -367,6 +387,9 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c)
config5 &= ~MIPS_CONF5_UFR;
write_c0_config5(config5);
+ if (config5 & MIPS_CONF5_EVA)
+ c->options |= MIPS_CPU_EVA;
+
return config5 & MIPS_CONF_M;
}
@@ -398,8 +421,13 @@ static void decode_configs(struct cpuinfo_mips *c)
mips_probe_watch_registers(c);
- if (cpu_has_mips_r2)
+#ifndef CONFIG_MIPS_CPS
+ if (cpu_has_mips_r2) {
c->core = read_c0_ebase() & 0x3ff;
+ if (cpu_has_mipsmt)
+ c->core >>= fls(core_nvpes()) - 1;
+ }
+#endif
}
#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \
@@ -710,17 +738,23 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
MIPS_CPU_LLSC;
c->tlbsize = 64;
break;
- case PRID_IMP_LOONGSON2:
- c->cputype = CPU_LOONGSON2;
- __cpu_name[cpu] = "ICT Loongson-2";
-
+ case PRID_IMP_LOONGSON_64: /* Loongson-2/3 */
switch (c->processor_id & PRID_REV_MASK) {
case PRID_REV_LOONGSON2E:
+ c->cputype = CPU_LOONGSON2;
+ __cpu_name[cpu] = "ICT Loongson-2";
set_elf_platform(cpu, "loongson2e");
break;
case PRID_REV_LOONGSON2F:
+ c->cputype = CPU_LOONGSON2;
+ __cpu_name[cpu] = "ICT Loongson-2";
set_elf_platform(cpu, "loongson2f");
break;
+ case PRID_REV_LOONGSON3A:
+ c->cputype = CPU_LOONGSON3;
+ __cpu_name[cpu] = "ICT Loongson-3";
+ set_elf_platform(cpu, "loongson3a");
+ break;
}
set_isa(c, MIPS_CPU_ISA_III);
@@ -729,7 +763,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
MIPS_CPU_32FPR;
c->tlbsize = 64;
break;
- case PRID_IMP_LOONGSON1:
+ case PRID_IMP_LOONGSON_32: /* Loongson-1 */
decode_configs(c);
c->cputype = CPU_LOONGSON1;
@@ -806,7 +840,7 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
__cpu_name[cpu] = "MIPS 1004Kc";
break;
case PRID_IMP_1074K:
- c->cputype = CPU_74K;
+ c->cputype = CPU_1074K;
__cpu_name[cpu] = "MIPS 1074Kc";
break;
case PRID_IMP_INTERAPTIV_UP:
@@ -825,6 +859,14 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
c->cputype = CPU_PROAPTIV;
__cpu_name[cpu] = "MIPS proAptiv (multi)";
break;
+ case PRID_IMP_P5600:
+ c->cputype = CPU_P5600;
+ __cpu_name[cpu] = "MIPS P5600";
+ break;
+ case PRID_IMP_M5150:
+ c->cputype = CPU_M5150;
+ __cpu_name[cpu] = "MIPS M5150";
+ break;
}
decode_configs(c);
@@ -1176,6 +1218,12 @@ void cpu_probe(void)
else
c->srsets = 1;
+ if (cpu_has_msa) {
+ c->msa_id = cpu_get_msa_id();
+ WARN(c->msa_id & MSA_IR_WRPF,
+ "Vector register partitioning unimplemented!");
+ }
+
cpu_probe_vmbits(c);
#ifdef CONFIG_64BIT
@@ -1192,4 +1240,6 @@ void cpu_report(void)
smp_processor_id(), c->processor_id, cpu_name_string());
if (c->options & MIPS_CPU_FPU)
printk(KERN_INFO "FPU revision is: %08x\n", c->fpu_id);
+ if (cpu_has_msa)
+ pr_info("MSA revision is: %08x\n", c->msa_id);
}
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
index 185ba258361b..74fe73506d8f 100644
--- a/arch/mips/kernel/ftrace.c
+++ b/arch/mips/kernel/ftrace.c
@@ -90,6 +90,7 @@ static inline void ftrace_dyn_arch_init_insns(void)
static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
{
int faulted;
+ mm_segment_t old_fs;
/* *(unsigned int *)ip = new_code; */
safe_store_code(new_code, ip, faulted);
@@ -97,7 +98,10 @@ static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
if (unlikely(faulted))
return -EFAULT;
+ old_fs = get_fs();
+ set_fs(get_ds());
flush_icache_range(ip, ip + 8);
+ set_fs(old_fs);
return 0;
}
@@ -111,11 +115,10 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1,
safe_store_code(new_code1, ip, faulted);
if (unlikely(faulted))
return -EFAULT;
- ip += 4;
- safe_store_code(new_code2, ip, faulted);
+ safe_store_code(new_code2, ip + 4, faulted);
if (unlikely(faulted))
return -EFAULT;
- flush_icache_range(ip, ip + 8); /* original ip + 12 */
+ flush_icache_range(ip, ip + 8);
return 0;
}
#endif
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index d84f6a509502..a9ce3408be25 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -67,7 +67,7 @@ NESTED(except_vec3_generic, 0, sp)
*/
NESTED(except_vec3_r4000, 0, sp)
.set push
- .set mips3
+ .set arch=r4000
.set noat
mfc0 k1, CP0_CAUSE
li k0, 31<<2
@@ -139,7 +139,7 @@ LEAF(__r4k_wait)
nop
nop
#endif
- .set mips3
+ .set arch=r4000
wait
/* end of rollback region (the region size must be power of two) */
1:
@@ -475,8 +475,10 @@ NESTED(nmi_handler, PT_SIZE, sp)
BUILD_HANDLER cpu cpu sti silent /* #11 */
BUILD_HANDLER ov ov sti silent /* #12 */
BUILD_HANDLER tr tr sti silent /* #13 */
+ BUILD_HANDLER msa_fpe msa_fpe sti silent /* #14 */
BUILD_HANDLER fpe fpe fpe silent /* #15 */
BUILD_HANDLER ftlb ftlb none silent /* #16 */
+ BUILD_HANDLER msa msa sti silent /* #21 */
BUILD_HANDLER mdmx mdmx sti silent /* #22 */
#ifdef CONFIG_HARDWARE_WATCHPOINTS
/*
@@ -575,7 +577,7 @@ isrdhwr:
ori k1, _THREAD_MASK
xori k1, _THREAD_MASK
LONG_L v1, TI_TP_VALUE(k1)
- .set mips3
+ .set arch=r4000
eret
.set mips0
#endif
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index 7b6a5b3e3acf..e712dcf18b2d 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -175,8 +175,8 @@ NESTED(smp_bootstrap, 16, sp)
DMT 10 # dmt t2 /* t0, t1 are used by CLI and setup_c0_status() */
jal mips_ihb
#endif /* CONFIG_MIPS_MT_SMTC */
- setup_c0_status_sec
smp_slave_setup
+ setup_c0_status_sec
#ifdef CONFIG_MIPS_MT_SMTC
andi t2, t2, VPECONTROL_TE
beqz t2, 2f
diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c
index 3553243bf9d6..837ff27950bc 100644
--- a/arch/mips/kernel/idle.c
+++ b/arch/mips/kernel/idle.c
@@ -64,7 +64,7 @@ void r4k_wait_irqoff(void)
if (!need_resched())
__asm__(
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" wait \n"
" .set pop \n");
local_irq_enable();
@@ -82,7 +82,7 @@ static void rm7k_wait_irqoff(void)
if (!need_resched())
__asm__(
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" .set noat \n"
" mfc0 $1, $12 \n"
" sync \n"
@@ -103,7 +103,7 @@ static void au1k_wait(void)
unsigned long c0status = read_c0_status() | 1; /* irqs on */
__asm__(
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" cache 0x14, 0(%0) \n"
" cache 0x14, 32(%0) \n"
" sync \n"
@@ -184,8 +184,11 @@ void __init check_wait(void)
case CPU_24K:
case CPU_34K:
case CPU_1004K:
+ case CPU_1074K:
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
+ case CPU_P5600:
+ case CPU_M5150:
cpu_wait = r4k_wait;
if (read_c0_config7() & MIPS_CONF7_WII)
cpu_wait = r4k_wait_irqoff;
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c
index 5b5ddb231f26..8520dad6d4e3 100644
--- a/arch/mips/kernel/irq-gic.c
+++ b/arch/mips/kernel/irq-gic.c
@@ -16,7 +16,6 @@
#include <asm/gic.h>
#include <asm/setup.h>
#include <asm/traps.h>
-#include <asm/gcmpregs.h>
#include <linux/hardirq.h>
#include <asm-generic/bitops/find.h>
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c
index fcaac2f132f0..7afcc2f22c0d 100644
--- a/arch/mips/kernel/kgdb.c
+++ b/arch/mips/kernel/kgdb.c
@@ -32,6 +32,7 @@
#include <asm/cacheflush.h>
#include <asm/processor.h>
#include <asm/sigcontext.h>
+#include <asm/uaccess.h>
static struct hard_trap_info {
unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */
@@ -208,7 +209,14 @@ void arch_kgdb_breakpoint(void)
static void kgdb_call_nmi_hook(void *ignored)
{
+ mm_segment_t old_fs;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+
kgdb_nmicallback(raw_smp_processor_id(), NULL);
+
+ set_fs(old_fs);
}
void kgdb_roundup_cpus(unsigned long flags)
@@ -282,6 +290,7 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
struct die_args *args = (struct die_args *)ptr;
struct pt_regs *regs = args->regs;
int trap = (regs->cp0_cause & 0x7c) >> 2;
+ mm_segment_t old_fs;
#ifdef CONFIG_KPROBES
/*
@@ -296,11 +305,17 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
if (user_mode(regs))
return NOTIFY_DONE;
+ /* Kernel mode. Set correct address limit */
+ old_fs = get_fs();
+ set_fs(get_ds());
+
if (atomic_read(&kgdb_active) != -1)
kgdb_nmicallback(smp_processor_id(), regs);
- if (kgdb_handle_exception(trap, compute_signal(trap), cmd, regs))
+ if (kgdb_handle_exception(trap, compute_signal(trap), cmd, regs)) {
+ set_fs(old_fs);
return NOTIFY_DONE;
+ }
if (atomic_read(&kgdb_setting_breakpoint))
if ((trap == 9) && (regs->cp0_epc == (unsigned long)breakinst))
@@ -310,6 +325,7 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
local_irq_enable();
__flush_cache_all();
+ set_fs(old_fs);
return NOTIFY_STOP;
}
diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c
new file mode 100644
index 000000000000..f76f7a08412d
--- /dev/null
+++ b/arch/mips/kernel/mips-cm.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/errno.h>
+
+#include <asm/mips-cm.h>
+#include <asm/mipsregs.h>
+
+void __iomem *mips_cm_base;
+void __iomem *mips_cm_l2sync_base;
+
+phys_t __mips_cm_phys_base(void)
+{
+ u32 config3 = read_c0_config3();
+ u32 cmgcr;
+
+ /* Check the CMGCRBase register is implemented */
+ if (!(config3 & MIPS_CONF3_CMGCR))
+ return 0;
+
+ /* Read the address from CMGCRBase */
+ cmgcr = read_c0_cmgcrbase();
+ return (cmgcr & MIPS_CMGCRF_BASE) << (36 - 32);
+}
+
+phys_t mips_cm_phys_base(void)
+ __attribute__((weak, alias("__mips_cm_phys_base")));
+
+phys_t __mips_cm_l2sync_phys_base(void)
+{
+ u32 base_reg;
+
+ /*
+ * If the L2-only sync region is already enabled then leave it at it's
+ * current location.
+ */
+ base_reg = read_gcr_l2_only_sync_base();
+ if (base_reg & CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN_MSK)
+ return base_reg & CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE_MSK;
+
+ /* Default to following the CM */
+ return mips_cm_phys_base() + MIPS_CM_GCR_SIZE;
+}
+
+phys_t mips_cm_l2sync_phys_base(void)
+ __attribute__((weak, alias("__mips_cm_l2sync_phys_base")));
+
+static void mips_cm_probe_l2sync(void)
+{
+ unsigned major_rev;
+ phys_t addr;
+
+ /* L2-only sync was introduced with CM major revision 6 */
+ major_rev = (read_gcr_rev() & CM_GCR_REV_MAJOR_MSK) >>
+ CM_GCR_REV_MAJOR_SHF;
+ if (major_rev < 6)
+ return;
+
+ /* Find a location for the L2 sync region */
+ addr = mips_cm_l2sync_phys_base();
+ BUG_ON((addr & CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE_MSK) != addr);
+ if (!addr)
+ return;
+
+ /* Set the region base address & enable it */
+ write_gcr_l2_only_sync_base(addr | CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN_MSK);
+
+ /* Map the region */
+ mips_cm_l2sync_base = ioremap_nocache(addr, MIPS_CM_L2SYNC_SIZE);
+}
+
+int mips_cm_probe(void)
+{
+ phys_t addr;
+ u32 base_reg;
+
+ addr = mips_cm_phys_base();
+ BUG_ON((addr & CM_GCR_BASE_GCRBASE_MSK) != addr);
+ if (!addr)
+ return -ENODEV;
+
+ mips_cm_base = ioremap_nocache(addr, MIPS_CM_GCR_SIZE);
+ if (!mips_cm_base)
+ return -ENXIO;
+
+ /* sanity check that we're looking at a CM */
+ base_reg = read_gcr_base();
+ if ((base_reg & CM_GCR_BASE_GCRBASE_MSK) != addr) {
+ pr_err("GCRs appear to have been moved (expected them at 0x%08lx)!\n",
+ (unsigned long)addr);
+ mips_cm_base = NULL;
+ return -ENODEV;
+ }
+
+ /* set default target to memory */
+ base_reg &= ~CM_GCR_BASE_CMDEFTGT_MSK;
+ base_reg |= CM_GCR_BASE_CMDEFTGT_MEM;
+ write_gcr_base(base_reg);
+
+ /* disable CM regions */
+ write_gcr_reg0_base(CM_GCR_REGn_BASE_BASEADDR_MSK);
+ write_gcr_reg0_mask(CM_GCR_REGn_MASK_ADDRMASK_MSK);
+ write_gcr_reg1_base(CM_GCR_REGn_BASE_BASEADDR_MSK);
+ write_gcr_reg1_mask(CM_GCR_REGn_MASK_ADDRMASK_MSK);
+ write_gcr_reg2_base(CM_GCR_REGn_BASE_BASEADDR_MSK);
+ write_gcr_reg2_mask(CM_GCR_REGn_MASK_ADDRMASK_MSK);
+ write_gcr_reg3_base(CM_GCR_REGn_BASE_BASEADDR_MSK);
+ write_gcr_reg3_mask(CM_GCR_REGn_MASK_ADDRMASK_MSK);
+
+ /* probe for an L2-only sync region */
+ mips_cm_probe_l2sync();
+
+ return 0;
+}
diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c
new file mode 100644
index 000000000000..c9dc67402969
--- /dev/null
+++ b/arch/mips/kernel/mips-cpc.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/errno.h>
+
+#include <asm/mips-cm.h>
+#include <asm/mips-cpc.h>
+
+void __iomem *mips_cpc_base;
+
+phys_t __weak mips_cpc_phys_base(void)
+{
+ u32 cpc_base;
+
+ if (!mips_cm_present())
+ return 0;
+
+ if (!(read_gcr_cpc_status() & CM_GCR_CPC_STATUS_EX_MSK))
+ return 0;
+
+ /* If the CPC is already enabled, leave it so */
+ cpc_base = read_gcr_cpc_base();
+ if (cpc_base & CM_GCR_CPC_BASE_CPCEN_MSK)
+ return cpc_base & CM_GCR_CPC_BASE_CPCBASE_MSK;
+
+ /* Otherwise, give it the default address & enable it */
+ cpc_base = mips_cpc_default_phys_base();
+ write_gcr_cpc_base(cpc_base | CM_GCR_CPC_BASE_CPCEN_MSK);
+ return cpc_base;
+}
+
+int mips_cpc_probe(void)
+{
+ phys_t addr;
+
+ addr = mips_cpc_phys_base();
+ if (!addr)
+ return -ENODEV;
+
+ mips_cpc_base = ioremap_nocache(addr, 0x8000);
+ if (!mips_cpc_base)
+ return -ENXIO;
+
+ return 0;
+}
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index 6e58e97fcd39..2607c3a4ff7e 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -16,12 +16,20 @@
#include <asm/ftrace.h>
extern void *__bzero(void *__s, size_t __count);
+extern long __strncpy_from_kernel_nocheck_asm(char *__to,
+ const char *__from, long __len);
+extern long __strncpy_from_kernel_asm(char *__to, const char *__from,
+ long __len);
extern long __strncpy_from_user_nocheck_asm(char *__to,
const char *__from, long __len);
extern long __strncpy_from_user_asm(char *__to, const char *__from,
long __len);
+extern long __strlen_kernel_nocheck_asm(const char *s);
+extern long __strlen_kernel_asm(const char *s);
extern long __strlen_user_nocheck_asm(const char *s);
extern long __strlen_user_asm(const char *s);
+extern long __strnlen_kernel_nocheck_asm(const char *s);
+extern long __strnlen_kernel_asm(const char *s);
extern long __strnlen_user_nocheck_asm(const char *s);
extern long __strnlen_user_asm(const char *s);
@@ -43,17 +51,31 @@ EXPORT_SYMBOL(copy_page);
*/
EXPORT_SYMBOL(__copy_user);
EXPORT_SYMBOL(__copy_user_inatomic);
+#ifdef CONFIG_EVA
+EXPORT_SYMBOL(__copy_from_user_eva);
+EXPORT_SYMBOL(__copy_in_user_eva);
+EXPORT_SYMBOL(__copy_to_user_eva);
+EXPORT_SYMBOL(__copy_user_inatomic_eva);
+#endif
EXPORT_SYMBOL(__bzero);
+EXPORT_SYMBOL(__strncpy_from_kernel_nocheck_asm);
+EXPORT_SYMBOL(__strncpy_from_kernel_asm);
EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm);
EXPORT_SYMBOL(__strncpy_from_user_asm);
+EXPORT_SYMBOL(__strlen_kernel_nocheck_asm);
+EXPORT_SYMBOL(__strlen_kernel_asm);
EXPORT_SYMBOL(__strlen_user_nocheck_asm);
EXPORT_SYMBOL(__strlen_user_asm);
+EXPORT_SYMBOL(__strnlen_kernel_nocheck_asm);
+EXPORT_SYMBOL(__strnlen_kernel_asm);
EXPORT_SYMBOL(__strnlen_user_nocheck_asm);
EXPORT_SYMBOL(__strnlen_user_asm);
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_nocheck);
-EXPORT_SYMBOL(__csum_partial_copy_user);
+EXPORT_SYMBOL(__csum_partial_copy_kernel);
+EXPORT_SYMBOL(__csum_partial_copy_to_user);
+EXPORT_SYMBOL(__csum_partial_copy_from_user);
EXPORT_SYMBOL(invalid_pte_table);
#ifdef CONFIG_FUNCTION_TRACER
diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c
index 24cdf64789c3..4f2d9dece7ab 100644
--- a/arch/mips/kernel/perf_event_mipsxx.c
+++ b/arch/mips/kernel/perf_event_mipsxx.c
@@ -805,7 +805,7 @@ static void reset_counters(void *arg)
}
}
-/* 24K/34K/1004K cores can share the same event map. */
+/* 24K/34K/1004K/interAptiv/loongson1 cores share the same event map. */
static const struct mips_perf_event mipsxxcore_event_map
[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, P },
@@ -814,8 +814,8 @@ static const struct mips_perf_event mipsxxcore_event_map
[PERF_COUNT_HW_BRANCH_MISSES] = { 0x02, CNTR_ODD, T },
};
-/* 74K core has different branch event code. */
-static const struct mips_perf_event mipsxx74Kcore_event_map
+/* 74K/proAptiv core has different branch event code. */
+static const struct mips_perf_event mipsxxcore_event_map2
[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, P },
[PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD, T },
@@ -849,7 +849,7 @@ static const struct mips_perf_event xlp_event_map[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_BRANCH_MISSES] = { 0x1c, CNTR_ALL }, /* PAPI_BR_MSP */
};
-/* 24K/34K/1004K cores can share the same cache event map. */
+/* 24K/34K/1004K/interAptiv/loongson1 cores share the same cache event map. */
static const struct mips_perf_event mipsxxcore_cache_map
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
@@ -930,8 +930,8 @@ static const struct mips_perf_event mipsxxcore_cache_map
},
};
-/* 74K core has completely different cache event map. */
-static const struct mips_perf_event mipsxx74Kcore_cache_map
+/* 74K/proAptiv core has completely different cache event map. */
+static const struct mips_perf_event mipsxxcore_cache_map2
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
@@ -978,6 +978,11 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map
[C(RESULT_MISS)] = { 0x1d, CNTR_EVEN, P },
},
},
+/*
+ * 74K core does not have specific DTLB events. proAptiv core has
+ * "speculative" DTLB events which are numbered 0x63 (even/odd) and
+ * not included here. One can use raw events if really needed.
+ */
[C(ITLB)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = { 0x04, CNTR_EVEN, T },
@@ -1378,6 +1383,10 @@ static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev)
#define IS_BOTH_COUNTERS_74K_EVENT(b) \
((b) == 0 || (b) == 1)
+/* proAptiv */
+#define IS_BOTH_COUNTERS_PROAPTIV_EVENT(b) \
+ ((b) == 0 || (b) == 1)
+
/* 1004K */
#define IS_BOTH_COUNTERS_1004K_EVENT(b) \
((b) == 0 || (b) == 1 || (b) == 11)
@@ -1391,6 +1400,20 @@ static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev)
#define IS_RANGE_V_1004K_EVENT(r) ((r) == 47)
#endif
+/* interAptiv */
+#define IS_BOTH_COUNTERS_INTERAPTIV_EVENT(b) \
+ ((b) == 0 || (b) == 1 || (b) == 11)
+#ifdef CONFIG_MIPS_MT_SMP
+/* The P/V/T info is not provided for "(b) == 38" in SUM, assume P. */
+#define IS_RANGE_P_INTERAPTIV_EVENT(r, b) \
+ ((b) == 0 || (r) == 18 || (b) == 21 || (b) == 22 || \
+ (b) == 25 || (b) == 36 || (b) == 38 || (b) == 39 || \
+ (r) == 44 || (r) == 174 || (r) == 176 || ((b) >= 50 && \
+ (b) <= 59) || (r) == 188 || (b) == 61 || (b) == 62 || \
+ ((b) >= 64 && (b) <= 67))
+#define IS_RANGE_V_INTERAPTIV_EVENT(r) ((r) == 47 || (r) == 175)
+#endif
+
/* BMIPS5000 */
#define IS_BOTH_COUNTERS_BMIPS5000_EVENT(b) \
((b) == 0 || (b) == 1)
@@ -1442,6 +1465,7 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
#endif
break;
case CPU_74K:
+ case CPU_1074K:
if (IS_BOTH_COUNTERS_74K_EVENT(base_id))
raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
else
@@ -1451,6 +1475,16 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
raw_event.range = P;
#endif
break;
+ case CPU_PROAPTIV:
+ if (IS_BOTH_COUNTERS_PROAPTIV_EVENT(base_id))
+ raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
+ else
+ raw_event.cntr_mask =
+ raw_id > 127 ? CNTR_ODD : CNTR_EVEN;
+#ifdef CONFIG_MIPS_MT_SMP
+ raw_event.range = P;
+#endif
+ break;
case CPU_1004K:
if (IS_BOTH_COUNTERS_1004K_EVENT(base_id))
raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
@@ -1466,6 +1500,21 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
raw_event.range = T;
#endif
break;
+ case CPU_INTERAPTIV:
+ if (IS_BOTH_COUNTERS_INTERAPTIV_EVENT(base_id))
+ raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
+ else
+ raw_event.cntr_mask =
+ raw_id > 127 ? CNTR_ODD : CNTR_EVEN;
+#ifdef CONFIG_MIPS_MT_SMP
+ if (IS_RANGE_P_INTERAPTIV_EVENT(raw_id, base_id))
+ raw_event.range = P;
+ else if (unlikely(IS_RANGE_V_INTERAPTIV_EVENT(raw_id)))
+ raw_event.range = V;
+ else
+ raw_event.range = T;
+#endif
+ break;
case CPU_BMIPS5000:
if (IS_BOTH_COUNTERS_BMIPS5000_EVENT(base_id))
raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
@@ -1576,14 +1625,29 @@ init_hw_perf_events(void)
break;
case CPU_74K:
mipspmu.name = "mips/74K";
- mipspmu.general_event_map = &mipsxx74Kcore_event_map;
- mipspmu.cache_event_map = &mipsxx74Kcore_cache_map;
+ mipspmu.general_event_map = &mipsxxcore_event_map2;
+ mipspmu.cache_event_map = &mipsxxcore_cache_map2;
+ break;
+ case CPU_PROAPTIV:
+ mipspmu.name = "mips/proAptiv";
+ mipspmu.general_event_map = &mipsxxcore_event_map2;
+ mipspmu.cache_event_map = &mipsxxcore_cache_map2;
break;
case CPU_1004K:
mipspmu.name = "mips/1004K";
mipspmu.general_event_map = &mipsxxcore_event_map;
mipspmu.cache_event_map = &mipsxxcore_cache_map;
break;
+ case CPU_1074K:
+ mipspmu.name = "mips/1074K";
+ mipspmu.general_event_map = &mipsxxcore_event_map;
+ mipspmu.cache_event_map = &mipsxxcore_cache_map;
+ break;
+ case CPU_INTERAPTIV:
+ mipspmu.name = "mips/interAptiv";
+ mipspmu.general_event_map = &mipsxxcore_event_map;
+ mipspmu.cache_event_map = &mipsxxcore_cache_map;
+ break;
case CPU_LOONGSON1:
mipspmu.name = "mips/loongson1";
mipspmu.general_event_map = &mipsxxcore_event_map;
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index 00d20974b3e7..e40971b51d2f 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -17,8 +17,24 @@
unsigned int vced_count, vcei_count;
+/*
+ * * No lock; only written during early bootup by CPU 0.
+ * */
+static RAW_NOTIFIER_HEAD(proc_cpuinfo_chain);
+
+int __ref register_proc_cpuinfo_notifier(struct notifier_block *nb)
+{
+ return raw_notifier_chain_register(&proc_cpuinfo_chain, nb);
+}
+
+int proc_cpuinfo_notifier_call_chain(unsigned long val, void *v)
+{
+ return raw_notifier_call_chain(&proc_cpuinfo_chain, val, v);
+}
+
static int show_cpuinfo(struct seq_file *m, void *v)
{
+ struct proc_cpuinfo_notifier_args proc_cpuinfo_notifier_args;
unsigned long n = (unsigned long) v - 1;
unsigned int version = cpu_data[n].processor_id;
unsigned int fp_vers = cpu_data[n].fpu_id;
@@ -95,6 +111,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
if (cpu_has_mipsmt) seq_printf(m, "%s", " mt");
if (cpu_has_mmips) seq_printf(m, "%s", " micromips");
if (cpu_has_vz) seq_printf(m, "%s", " vz");
+ if (cpu_has_msa) seq_printf(m, "%s", " msa");
+ if (cpu_has_eva) seq_printf(m, "%s", " eva");
seq_printf(m, "\n");
if (cpu_has_mmips) {
@@ -118,6 +136,13 @@ static int show_cpuinfo(struct seq_file *m, void *v)
cpu_has_vce ? "%u" : "not available");
seq_printf(m, fmt, 'D', vced_count);
seq_printf(m, fmt, 'I', vcei_count);
+
+ proc_cpuinfo_notifier_args.m = m;
+ proc_cpuinfo_notifier_args.n = n;
+
+ raw_notifier_call_chain(&proc_cpuinfo_chain, 0,
+ &proc_cpuinfo_notifier_args);
+
seq_printf(m, "\n");
return 0;
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 6ae540e133b2..60e39dc7f1eb 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -32,6 +32,7 @@
#include <asm/cpu.h>
#include <asm/dsp.h>
#include <asm/fpu.h>
+#include <asm/msa.h>
#include <asm/pgtable.h>
#include <asm/mipsregs.h>
#include <asm/processor.h>
@@ -65,6 +66,8 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
clear_used_math();
clear_fpu_owner();
init_dsp();
+ clear_thread_flag(TIF_MSA_CTX_LIVE);
+ disable_msa();
regs->cp0_epc = pc;
regs->regs[29] = sp;
}
@@ -89,7 +92,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
preempt_disable();
- if (is_fpu_owner())
+ if (is_msa_enabled())
+ save_msa(p);
+ else if (is_fpu_owner())
save_fp(p);
if (cpu_has_dsp)
@@ -157,7 +162,13 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
/* Fill in the fpu structure for a core dump.. */
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
{
- memcpy(r, &current->thread.fpu, sizeof(current->thread.fpu));
+ int i;
+
+ for (i = 0; i < NUM_FPU_REGS; i++)
+ memcpy(&r[i], &current->thread.fpu.fpr[i], sizeof(*r));
+
+ memcpy(&r[NUM_FPU_REGS], &current->thread.fpu.fcr31,
+ sizeof(current->thread.fpu.fcr31));
return 1;
}
@@ -192,7 +203,13 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpr)
{
- memcpy(fpr, &t->thread.fpu, sizeof(current->thread.fpu));
+ int i;
+
+ for (i = 0; i < NUM_FPU_REGS; i++)
+ memcpy(&fpr[i], &t->thread.fpu.fpr[i], sizeof(*fpr));
+
+ memcpy(&fpr[NUM_FPU_REGS], &t->thread.fpu.fcr31,
+ sizeof(t->thread.fpu.fcr31));
return 1;
}
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 7da9b76db4d9..7271e5a83081 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -114,51 +114,30 @@ int ptrace_setregs(struct task_struct *child, __s64 __user *data)
int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
{
int i;
- unsigned int tmp;
if (!access_ok(VERIFY_WRITE, data, 33 * 8))
return -EIO;
if (tsk_used_math(child)) {
- fpureg_t *fregs = get_fpu_regs(child);
+ union fpureg *fregs = get_fpu_regs(child);
for (i = 0; i < 32; i++)
- __put_user(fregs[i], i + (__u64 __user *) data);
+ __put_user(get_fpr64(&fregs[i], 0),
+ i + (__u64 __user *)data);
} else {
for (i = 0; i < 32; i++)
__put_user((__u64) -1, i + (__u64 __user *) data);
}
__put_user(child->thread.fpu.fcr31, data + 64);
-
- preempt_disable();
- if (cpu_has_fpu) {
- unsigned int flags;
-
- if (cpu_has_mipsmt) {
- unsigned int vpflags = dvpe();
- flags = read_c0_status();
- __enable_fpu(FPU_AS_IS);
- __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
- write_c0_status(flags);
- evpe(vpflags);
- } else {
- flags = read_c0_status();
- __enable_fpu(FPU_AS_IS);
- __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
- write_c0_status(flags);
- }
- } else {
- tmp = 0;
- }
- preempt_enable();
- __put_user(tmp, data + 65);
+ __put_user(current_cpu_data.fpu_id, data + 65);
return 0;
}
int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
{
- fpureg_t *fregs;
+ union fpureg *fregs;
+ u64 fpr_val;
int i;
if (!access_ok(VERIFY_READ, data, 33 * 8))
@@ -166,8 +145,10 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
fregs = get_fpu_regs(child);
- for (i = 0; i < 32; i++)
- __get_user(fregs[i], i + (__u64 __user *) data);
+ for (i = 0; i < 32; i++) {
+ __get_user(fpr_val, i + (__u64 __user *)data);
+ set_fpr64(&fregs[i], 0, fpr_val);
+ }
__get_user(child->thread.fpu.fcr31, data + 64);
@@ -300,10 +281,27 @@ static int fpr_get(struct task_struct *target,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
- return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- &target->thread.fpu,
- 0, sizeof(elf_fpregset_t));
+ unsigned i;
+ int err;
+ u64 fpr_val;
+
/* XXX fcr31 */
+
+ if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &target->thread.fpu,
+ 0, sizeof(elf_fpregset_t));
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0);
+ err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &fpr_val, i * sizeof(elf_fpreg_t),
+ (i + 1) * sizeof(elf_fpreg_t));
+ if (err)
+ return err;
+ }
+
+ return 0;
}
static int fpr_set(struct task_struct *target,
@@ -311,10 +309,27 @@ static int fpr_set(struct task_struct *target,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
- return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.fpu,
- 0, sizeof(elf_fpregset_t));
+ unsigned i;
+ int err;
+ u64 fpr_val;
+
/* XXX fcr31 */
+
+ if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
+ return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.fpu,
+ 0, sizeof(elf_fpregset_t));
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &fpr_val, i * sizeof(elf_fpreg_t),
+ (i + 1) * sizeof(elf_fpreg_t));
+ if (err)
+ return err;
+ set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val);
+ }
+
+ return 0;
}
enum mips_regset {
@@ -408,7 +423,7 @@ long arch_ptrace(struct task_struct *child, long request,
/* Read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
struct pt_regs *regs;
- fpureg_t *fregs;
+ union fpureg *fregs;
unsigned long tmp = 0;
regs = task_pt_regs(child);
@@ -433,14 +448,12 @@ long arch_ptrace(struct task_struct *child, long request,
* order bits of the values stored in the even
* registers - unless we're using r2k_switch.S.
*/
- if (addr & 1)
- tmp = fregs[(addr & ~1) - 32] >> 32;
- else
- tmp = fregs[addr - 32];
+ tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
+ addr & 1);
break;
}
#endif
- tmp = fregs[addr - FPR_BASE];
+ tmp = get_fpr32(&fregs[addr - FPR_BASE], 0);
break;
case PC:
tmp = regs->cp0_epc;
@@ -465,44 +478,10 @@ long arch_ptrace(struct task_struct *child, long request,
case FPC_CSR:
tmp = child->thread.fpu.fcr31;
break;
- case FPC_EIR: { /* implementation / version register */
- unsigned int flags;
-#ifdef CONFIG_MIPS_MT_SMTC
- unsigned long irqflags;
- unsigned int mtflags;
-#endif /* CONFIG_MIPS_MT_SMTC */
-
- preempt_disable();
- if (!cpu_has_fpu) {
- preempt_enable();
- break;
- }
-
-#ifdef CONFIG_MIPS_MT_SMTC
- /* Read-modify-write of Status must be atomic */
- local_irq_save(irqflags);
- mtflags = dmt();
-#endif /* CONFIG_MIPS_MT_SMTC */
- if (cpu_has_mipsmt) {
- unsigned int vpflags = dvpe();
- flags = read_c0_status();
- __enable_fpu(FPU_AS_IS);
- __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
- write_c0_status(flags);
- evpe(vpflags);
- } else {
- flags = read_c0_status();
- __enable_fpu(FPU_AS_IS);
- __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
- write_c0_status(flags);
- }
-#ifdef CONFIG_MIPS_MT_SMTC
- emt(mtflags);
- local_irq_restore(irqflags);
-#endif /* CONFIG_MIPS_MT_SMTC */
- preempt_enable();
+ case FPC_EIR:
+ /* implementation / version register */
+ tmp = current_cpu_data.fpu_id;
break;
- }
case DSP_BASE ... DSP_BASE + 5: {
dspreg_t *dregs;
@@ -548,7 +527,7 @@ long arch_ptrace(struct task_struct *child, long request,
regs->regs[addr] = data;
break;
case FPR_BASE ... FPR_BASE + 31: {
- fpureg_t *fregs = get_fpu_regs(child);
+ union fpureg *fregs = get_fpu_regs(child);
if (!tsk_used_math(child)) {
/* FP not yet used */
@@ -563,19 +542,12 @@ long arch_ptrace(struct task_struct *child, long request,
* order bits of the values stored in the even
* registers - unless we're using r2k_switch.S.
*/
- if (addr & 1) {
- fregs[(addr & ~1) - FPR_BASE] &=
- 0xffffffff;
- fregs[(addr & ~1) - FPR_BASE] |=
- ((u64)data) << 32;
- } else {
- fregs[addr - FPR_BASE] &= ~0xffffffffLL;
- fregs[addr - FPR_BASE] |= data;
- }
+ set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
+ addr & 1, data);
break;
}
#endif
- fregs[addr - FPR_BASE] = data;
+ set_fpr64(&fregs[addr - FPR_BASE], 0, data);
break;
}
case PC:
@@ -662,13 +634,13 @@ long arch_ptrace(struct task_struct *child, long request,
* Notification of system call entry/exit
* - triggered by current->work.syscall_trace
*/
-asmlinkage void syscall_trace_enter(struct pt_regs *regs)
+asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)
{
long ret = 0;
user_exit();
- /* do the secure computing check first */
- secure_computing_strict(regs->regs[2]);
+ if (secure_computing(syscall) == -1)
+ return -1;
if (test_thread_flag(TIF_SYSCALL_TRACE) &&
tracehook_report_syscall_entry(regs))
@@ -677,10 +649,11 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs)
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_enter(regs, regs->regs[2]);
- audit_syscall_entry(__syscall_get_arch(),
- regs->regs[2],
+ audit_syscall_entry(syscall_get_arch(current, regs),
+ syscall,
regs->regs[4], regs->regs[5],
regs->regs[6], regs->regs[7]);
+ return syscall;
}
/*
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
index b8aa2dd5b00b..b40c3ca60ee5 100644
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -80,7 +80,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
/* Read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
struct pt_regs *regs;
- fpureg_t *fregs;
+ union fpureg *fregs;
unsigned int tmp;
regs = task_pt_regs(child);
@@ -103,13 +103,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
* order bits of the values stored in the even
* registers - unless we're using r2k_switch.S.
*/
- if (addr & 1)
- tmp = fregs[(addr & ~1) - 32] >> 32;
- else
- tmp = fregs[addr - 32];
+ tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
+ addr & 1);
break;
}
- tmp = fregs[addr - FPR_BASE];
+ tmp = get_fpr32(&fregs[addr - FPR_BASE], 0);
break;
case PC:
tmp = regs->cp0_epc;
@@ -129,46 +127,10 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
case FPC_CSR:
tmp = child->thread.fpu.fcr31;
break;
- case FPC_EIR: { /* implementation / version register */
- unsigned int flags;
-#ifdef CONFIG_MIPS_MT_SMTC
- unsigned int irqflags;
- unsigned int mtflags;
-#endif /* CONFIG_MIPS_MT_SMTC */
-
- preempt_disable();
- if (!cpu_has_fpu) {
- preempt_enable();
- tmp = 0;
- break;
- }
-
-#ifdef CONFIG_MIPS_MT_SMTC
- /* Read-modify-write of Status must be atomic */
- local_irq_save(irqflags);
- mtflags = dmt();
-#endif /* CONFIG_MIPS_MT_SMTC */
-
- if (cpu_has_mipsmt) {
- unsigned int vpflags = dvpe();
- flags = read_c0_status();
- __enable_fpu(FPU_AS_IS);
- __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
- write_c0_status(flags);
- evpe(vpflags);
- } else {
- flags = read_c0_status();
- __enable_fpu(FPU_AS_IS);
- __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
- write_c0_status(flags);
- }
-#ifdef CONFIG_MIPS_MT_SMTC
- emt(mtflags);
- local_irq_restore(irqflags);
-#endif /* CONFIG_MIPS_MT_SMTC */
- preempt_enable();
+ case FPC_EIR:
+ /* implementation / version register */
+ tmp = current_cpu_data.fpu_id;
break;
- }
case DSP_BASE ... DSP_BASE + 5: {
dspreg_t *dregs;
@@ -233,7 +195,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
regs->regs[addr] = data;
break;
case FPR_BASE ... FPR_BASE + 31: {
- fpureg_t *fregs = get_fpu_regs(child);
+ union fpureg *fregs = get_fpu_regs(child);
if (!tsk_used_math(child)) {
/* FP not yet used */
@@ -247,18 +209,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
* order bits of the values stored in the even
* registers - unless we're using r2k_switch.S.
*/
- if (addr & 1) {
- fregs[(addr & ~1) - FPR_BASE] &=
- 0xffffffff;
- fregs[(addr & ~1) - FPR_BASE] |=
- ((u64)data) << 32;
- } else {
- fregs[addr - FPR_BASE] &= ~0xffffffffLL;
- fregs[addr - FPR_BASE] |= data;
- }
+ set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
+ addr & 1, data);
break;
}
- fregs[addr - FPR_BASE] = data;
+ set_fpr64(&fregs[addr - FPR_BASE], 0, data);
break;
}
case PC:
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S
index 253b2fb52026..71814272d148 100644
--- a/arch/mips/kernel/r4k_fpu.S
+++ b/arch/mips/kernel/r4k_fpu.S
@@ -13,6 +13,7 @@
* Copyright (C) 1999, 2001 Silicon Graphics, Inc.
*/
#include <asm/asm.h>
+#include <asm/asmmacro.h>
#include <asm/errno.h>
#include <asm/fpregdef.h>
#include <asm/mipsregs.h>
@@ -30,14 +31,14 @@
.endm
.set noreorder
- .set mips3
+ .set arch=r4000
LEAF(_save_fp_context)
cfc1 t1, fcr31
-#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
.set push
-#ifdef CONFIG_MIPS32_R2
+#ifdef CONFIG_CPU_MIPS32_R2
.set mips64r2
mfc0 t0, CP0_STATUS
sll t0, t0, 5
@@ -146,11 +147,11 @@ LEAF(_save_fp_context32)
* - cp1 status/control register
*/
LEAF(_restore_fp_context)
- EX lw t0, SC_FPC_CSR(a0)
+ EX lw t1, SC_FPC_CSR(a0)
-#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
.set push
-#ifdef CONFIG_MIPS32_R2
+#ifdef CONFIG_CPU_MIPS32_R2
.set mips64r2
mfc0 t0, CP0_STATUS
sll t0, t0, 5
@@ -191,7 +192,7 @@ LEAF(_restore_fp_context)
EX ldc1 $f26, SC_FPREGS+208(a0)
EX ldc1 $f28, SC_FPREGS+224(a0)
EX ldc1 $f30, SC_FPREGS+240(a0)
- ctc1 t0, fcr31
+ ctc1 t1, fcr31
jr ra
li v0, 0 # success
END(_restore_fp_context)
@@ -199,7 +200,7 @@ LEAF(_restore_fp_context)
#ifdef CONFIG_MIPS32_COMPAT
LEAF(_restore_fp_context32)
/* Restore an o32 sigcontext. */
- EX lw t0, SC32_FPC_CSR(a0)
+ EX lw t1, SC32_FPC_CSR(a0)
mfc0 t0, CP0_STATUS
sll t0, t0, 5
@@ -239,12 +240,224 @@ LEAF(_restore_fp_context32)
EX ldc1 $f26, SC32_FPREGS+208(a0)
EX ldc1 $f28, SC32_FPREGS+224(a0)
EX ldc1 $f30, SC32_FPREGS+240(a0)
- ctc1 t0, fcr31
+ ctc1 t1, fcr31
jr ra
li v0, 0 # success
END(_restore_fp_context32)
#endif
+#ifdef CONFIG_CPU_HAS_MSA
+
+ .macro save_sc_msareg wr, off, sc, tmp
+#ifdef CONFIG_64BIT
+ copy_u_d \tmp, \wr, 1
+ EX sd \tmp, (\off+(\wr*8))(\sc)
+#elif defined(CONFIG_CPU_LITTLE_ENDIAN)
+ copy_u_w \tmp, \wr, 2
+ EX sw \tmp, (\off+(\wr*8)+0)(\sc)
+ copy_u_w \tmp, \wr, 3
+ EX sw \tmp, (\off+(\wr*8)+4)(\sc)
+#else /* CONFIG_CPU_BIG_ENDIAN */
+ copy_u_w \tmp, \wr, 2
+ EX sw \tmp, (\off+(\wr*8)+4)(\sc)
+ copy_u_w \tmp, \wr, 3
+ EX sw \tmp, (\off+(\wr*8)+0)(\sc)
+#endif
+ .endm
+
+/*
+ * int _save_msa_context(struct sigcontext *sc)
+ *
+ * Save the upper 64 bits of each vector register along with the MSA_CSR
+ * register into sc. Returns zero on success, else non-zero.
+ */
+LEAF(_save_msa_context)
+ save_sc_msareg 0, SC_MSAREGS, a0, t0
+ save_sc_msareg 1, SC_MSAREGS, a0, t0
+ save_sc_msareg 2, SC_MSAREGS, a0, t0
+ save_sc_msareg 3, SC_MSAREGS, a0, t0
+ save_sc_msareg 4, SC_MSAREGS, a0, t0
+ save_sc_msareg 5, SC_MSAREGS, a0, t0
+ save_sc_msareg 6, SC_MSAREGS, a0, t0
+ save_sc_msareg 7, SC_MSAREGS, a0, t0
+ save_sc_msareg 8, SC_MSAREGS, a0, t0
+ save_sc_msareg 9, SC_MSAREGS, a0, t0
+ save_sc_msareg 10, SC_MSAREGS, a0, t0
+ save_sc_msareg 11, SC_MSAREGS, a0, t0
+ save_sc_msareg 12, SC_MSAREGS, a0, t0
+ save_sc_msareg 13, SC_MSAREGS, a0, t0
+ save_sc_msareg 14, SC_MSAREGS, a0, t0
+ save_sc_msareg 15, SC_MSAREGS, a0, t0
+ save_sc_msareg 16, SC_MSAREGS, a0, t0
+ save_sc_msareg 17, SC_MSAREGS, a0, t0
+ save_sc_msareg 18, SC_MSAREGS, a0, t0
+ save_sc_msareg 19, SC_MSAREGS, a0, t0
+ save_sc_msareg 20, SC_MSAREGS, a0, t0
+ save_sc_msareg 21, SC_MSAREGS, a0, t0
+ save_sc_msareg 22, SC_MSAREGS, a0, t0
+ save_sc_msareg 23, SC_MSAREGS, a0, t0
+ save_sc_msareg 24, SC_MSAREGS, a0, t0
+ save_sc_msareg 25, SC_MSAREGS, a0, t0
+ save_sc_msareg 26, SC_MSAREGS, a0, t0
+ save_sc_msareg 27, SC_MSAREGS, a0, t0
+ save_sc_msareg 28, SC_MSAREGS, a0, t0
+ save_sc_msareg 29, SC_MSAREGS, a0, t0
+ save_sc_msareg 30, SC_MSAREGS, a0, t0
+ save_sc_msareg 31, SC_MSAREGS, a0, t0
+ jr ra
+ li v0, 0
+ END(_save_msa_context)
+
+#ifdef CONFIG_MIPS32_COMPAT
+
+/*
+ * int _save_msa_context32(struct sigcontext32 *sc)
+ *
+ * Save the upper 64 bits of each vector register along with the MSA_CSR
+ * register into sc. Returns zero on success, else non-zero.
+ */
+LEAF(_save_msa_context32)
+ save_sc_msareg 0, SC32_MSAREGS, a0, t0
+ save_sc_msareg 1, SC32_MSAREGS, a0, t0
+ save_sc_msareg 2, SC32_MSAREGS, a0, t0
+ save_sc_msareg 3, SC32_MSAREGS, a0, t0
+ save_sc_msareg 4, SC32_MSAREGS, a0, t0
+ save_sc_msareg 5, SC32_MSAREGS, a0, t0
+ save_sc_msareg 6, SC32_MSAREGS, a0, t0
+ save_sc_msareg 7, SC32_MSAREGS, a0, t0
+ save_sc_msareg 8, SC32_MSAREGS, a0, t0
+ save_sc_msareg 9, SC32_MSAREGS, a0, t0
+ save_sc_msareg 10, SC32_MSAREGS, a0, t0
+ save_sc_msareg 11, SC32_MSAREGS, a0, t0
+ save_sc_msareg 12, SC32_MSAREGS, a0, t0
+ save_sc_msareg 13, SC32_MSAREGS, a0, t0
+ save_sc_msareg 14, SC32_MSAREGS, a0, t0
+ save_sc_msareg 15, SC32_MSAREGS, a0, t0
+ save_sc_msareg 16, SC32_MSAREGS, a0, t0
+ save_sc_msareg 17, SC32_MSAREGS, a0, t0
+ save_sc_msareg 18, SC32_MSAREGS, a0, t0
+ save_sc_msareg 19, SC32_MSAREGS, a0, t0
+ save_sc_msareg 20, SC32_MSAREGS, a0, t0
+ save_sc_msareg 21, SC32_MSAREGS, a0, t0
+ save_sc_msareg 22, SC32_MSAREGS, a0, t0
+ save_sc_msareg 23, SC32_MSAREGS, a0, t0
+ save_sc_msareg 24, SC32_MSAREGS, a0, t0
+ save_sc_msareg 25, SC32_MSAREGS, a0, t0
+ save_sc_msareg 26, SC32_MSAREGS, a0, t0
+ save_sc_msareg 27, SC32_MSAREGS, a0, t0
+ save_sc_msareg 28, SC32_MSAREGS, a0, t0
+ save_sc_msareg 29, SC32_MSAREGS, a0, t0
+ save_sc_msareg 30, SC32_MSAREGS, a0, t0
+ save_sc_msareg 31, SC32_MSAREGS, a0, t0
+ jr ra
+ li v0, 0
+ END(_save_msa_context32)
+
+#endif /* CONFIG_MIPS32_COMPAT */
+
+ .macro restore_sc_msareg wr, off, sc, tmp
+#ifdef CONFIG_64BIT
+ EX ld \tmp, (\off+(\wr*8))(\sc)
+ insert_d \wr, 1, \tmp
+#elif defined(CONFIG_CPU_LITTLE_ENDIAN)
+ EX lw \tmp, (\off+(\wr*8)+0)(\sc)
+ insert_w \wr, 2, \tmp
+ EX lw \tmp, (\off+(\wr*8)+4)(\sc)
+ insert_w \wr, 3, \tmp
+#else /* CONFIG_CPU_BIG_ENDIAN */
+ EX lw \tmp, (\off+(\wr*8)+4)(\sc)
+ insert_w \wr, 2, \tmp
+ EX lw \tmp, (\off+(\wr*8)+0)(\sc)
+ insert_w \wr, 3, \tmp
+#endif
+ .endm
+
+/*
+ * int _restore_msa_context(struct sigcontext *sc)
+ */
+LEAF(_restore_msa_context)
+ restore_sc_msareg 0, SC_MSAREGS, a0, t0
+ restore_sc_msareg 1, SC_MSAREGS, a0, t0
+ restore_sc_msareg 2, SC_MSAREGS, a0, t0
+ restore_sc_msareg 3, SC_MSAREGS, a0, t0
+ restore_sc_msareg 4, SC_MSAREGS, a0, t0
+ restore_sc_msareg 5, SC_MSAREGS, a0, t0
+ restore_sc_msareg 6, SC_MSAREGS, a0, t0
+ restore_sc_msareg 7, SC_MSAREGS, a0, t0
+ restore_sc_msareg 8, SC_MSAREGS, a0, t0
+ restore_sc_msareg 9, SC_MSAREGS, a0, t0
+ restore_sc_msareg 10, SC_MSAREGS, a0, t0
+ restore_sc_msareg 11, SC_MSAREGS, a0, t0
+ restore_sc_msareg 12, SC_MSAREGS, a0, t0
+ restore_sc_msareg 13, SC_MSAREGS, a0, t0
+ restore_sc_msareg 14, SC_MSAREGS, a0, t0
+ restore_sc_msareg 15, SC_MSAREGS, a0, t0
+ restore_sc_msareg 16, SC_MSAREGS, a0, t0
+ restore_sc_msareg 17, SC_MSAREGS, a0, t0
+ restore_sc_msareg 18, SC_MSAREGS, a0, t0
+ restore_sc_msareg 19, SC_MSAREGS, a0, t0
+ restore_sc_msareg 20, SC_MSAREGS, a0, t0
+ restore_sc_msareg 21, SC_MSAREGS, a0, t0
+ restore_sc_msareg 22, SC_MSAREGS, a0, t0
+ restore_sc_msareg 23, SC_MSAREGS, a0, t0
+ restore_sc_msareg 24, SC_MSAREGS, a0, t0
+ restore_sc_msareg 25, SC_MSAREGS, a0, t0
+ restore_sc_msareg 26, SC_MSAREGS, a0, t0
+ restore_sc_msareg 27, SC_MSAREGS, a0, t0
+ restore_sc_msareg 28, SC_MSAREGS, a0, t0
+ restore_sc_msareg 29, SC_MSAREGS, a0, t0
+ restore_sc_msareg 30, SC_MSAREGS, a0, t0
+ restore_sc_msareg 31, SC_MSAREGS, a0, t0
+ jr ra
+ li v0, 0
+ END(_restore_msa_context)
+
+#ifdef CONFIG_MIPS32_COMPAT
+
+/*
+ * int _restore_msa_context32(struct sigcontext32 *sc)
+ */
+LEAF(_restore_msa_context32)
+ restore_sc_msareg 0, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 1, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 2, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 3, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 4, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 5, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 6, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 7, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 8, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 9, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 10, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 11, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 12, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 13, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 14, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 15, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 16, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 17, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 18, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 19, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 20, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 21, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 22, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 23, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 24, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 25, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 26, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 27, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 28, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 29, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 30, SC32_MSAREGS, a0, t0
+ restore_sc_msareg 31, SC32_MSAREGS, a0, t0
+ jr ra
+ li v0, 0
+ END(_restore_msa_context32)
+
+#endif /* CONFIG_MIPS32_COMPAT */
+
+#endif /* CONFIG_CPU_HAS_MSA */
+
.set reorder
.type fault@function
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index cc78dd9a17c7..abacac7c33ef 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -29,18 +29,8 @@
#define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS)
/*
- * FPU context is saved iff the process has used it's FPU in the current
- * time slice as indicated by _TIF_USEDFPU. In any case, the CU1 bit for user
- * space STATUS register should be 0, so that a process *always* starts its
- * userland with FPU disabled after each context switch.
- *
- * FPU will be enabled as soon as the process accesses FPU again, through
- * do_cpu() trap.
- */
-
-/*
* task_struct *resume(task_struct *prev, task_struct *next,
- * struct thread_info *next_ti, int usedfpu)
+ * struct thread_info *next_ti, s32 fp_save)
*/
.align 5
LEAF(resume)
@@ -50,23 +40,37 @@
LONG_S ra, THREAD_REG31(a0)
/*
- * check if we need to save FPU registers
+ * Check whether we need to save any FP context. FP context is saved
+ * iff the process has used the context with the scalar FPU or the MSA
+ * ASE in the current time slice, as indicated by _TIF_USEDFPU and
+ * _TIF_USEDMSA respectively. switch_to will have set fp_save
+ * accordingly to an FP_SAVE_ enum value.
*/
+ beqz a3, 2f
- beqz a3, 1f
-
- PTR_L t3, TASK_THREAD_INFO(a0)
/*
- * clear saved user stack CU1 bit
+ * We do. Clear the saved CU1 bit for prev, such that next time it is
+ * scheduled it will start in userland with the FPU disabled. If the
+ * task uses the FPU then it will be enabled again via the do_cpu trap.
+ * This allows us to lazily restore the FP context.
*/
+ PTR_L t3, TASK_THREAD_INFO(a0)
LONG_L t0, ST_OFF(t3)
li t1, ~ST0_CU1
and t0, t0, t1
LONG_S t0, ST_OFF(t3)
+ /* Check whether we're saving scalar or vector context. */
+ bgtz a3, 1f
+
+ /* Save 128b MSA vector context. */
+ msa_save_all a0
+ b 2f
+
+1: /* Save 32b/64b scalar FP context. */
fpu_save_double a0 t0 t1 # c0_status passed in t0
# clobbers t1
-1:
+2:
#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
PTR_LA t8, __stack_chk_guard
@@ -141,6 +145,26 @@ LEAF(_restore_fp)
jr ra
END(_restore_fp)
+#ifdef CONFIG_CPU_HAS_MSA
+
+/*
+ * Save a thread's MSA vector context.
+ */
+LEAF(_save_msa)
+ msa_save_all a0
+ jr ra
+ END(_save_msa)
+
+/*
+ * Restore a thread's MSA vector context.
+ */
+LEAF(_restore_msa)
+ msa_restore_all a0
+ jr ra
+ END(_restore_msa)
+
+#endif
+
/*
* Load the FPU with signalling NANS. This bit pattern we're using has
* the property that no matter whether considered as single or as double
@@ -270,7 +294,7 @@ LEAF(_init_fpu)
1: .set pop
#endif /* CONFIG_CPU_MIPS32_R2 */
#else
- .set mips3
+ .set arch=r4000
dmtc1 t1, $f0
dmtc1 t1, $f2
dmtc1 t1, $f4
diff --git a/arch/mips/kernel/rtlx-cmp.c b/arch/mips/kernel/rtlx-cmp.c
index 56dc69635153..758fb3cd2326 100644
--- a/arch/mips/kernel/rtlx-cmp.c
+++ b/arch/mips/kernel/rtlx-cmp.c
@@ -112,5 +112,8 @@ void __exit rtlx_module_exit(void)
for (i = 0; i < RTLX_CHANNELS; i++)
device_destroy(mt_class, MKDEV(major, i));
+
unregister_chrdev(major, RTLX_MODULE_NAME);
+
+ aprp_hook = NULL;
}
diff --git a/arch/mips/kernel/rtlx-mt.c b/arch/mips/kernel/rtlx-mt.c
index 91d61ba422b4..9c1aca00fd54 100644
--- a/arch/mips/kernel/rtlx-mt.c
+++ b/arch/mips/kernel/rtlx-mt.c
@@ -144,5 +144,8 @@ void __exit rtlx_module_exit(void)
for (i = 0; i < RTLX_CHANNELS; i++)
device_destroy(mt_class, MKDEV(major, i));
+
unregister_chrdev(major, RTLX_MODULE_NAME);
+
+ aprp_hook = NULL;
}
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index a5b14f48e1af..fdc70b400442 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -6,6 +6,7 @@
* Copyright (C) 1995-99, 2000- 02, 06 Ralf Baechle <ralf@linux-mips.org>
* Copyright (C) 2001 MIPS Technologies, Inc.
* Copyright (C) 2004 Thiemo Seufer
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*/
#include <linux/errno.h>
#include <asm/asm.h>
@@ -74,10 +75,10 @@ NESTED(handle_sys, PT_SIZE, sp)
.set noreorder
.set nomacro
-1: lw t5, 16(t0) # argument #5 from usp
-4: lw t6, 20(t0) # argument #6 from usp
-3: lw t7, 24(t0) # argument #7 from usp
-2: lw t8, 28(t0) # argument #8 from usp
+1: user_lw(t5, 16(t0)) # argument #5 from usp
+4: user_lw(t6, 20(t0)) # argument #6 from usp
+3: user_lw(t7, 24(t0)) # argument #7 from usp
+2: user_lw(t8, 28(t0)) # argument #8 from usp
sw t5, 16(sp) # argument #5 to ksp
sw t6, 20(sp) # argument #6 to ksp
@@ -118,7 +119,18 @@ syscall_trace_entry:
SAVE_STATIC
move s0, t2
move a0, sp
- jal syscall_trace_enter
+
+ /*
+ * syscall number is in v0 unless we called syscall(__NR_###)
+ * where the real syscall number is in a0
+ */
+ addiu a1, v0, __NR_O32_Linux
+ bnez v0, 1f /* __NR_syscall at offset 0 */
+ lw a1, PT_R4(sp)
+
+1: jal syscall_trace_enter
+
+ bltz v0, 2f # seccomp failed? Skip syscall
move t0, s0
RESTORE_STATIC
@@ -138,7 +150,7 @@ syscall_trace_entry:
sw t1, PT_R0(sp) # save it for syscall restarting
1: sw v0, PT_R2(sp) # result
- j syscall_exit
+2: j syscall_exit
/* ------------------------------------------------------------------------ */
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index b56e254beb15..dd99c3285aea 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -80,8 +80,11 @@ syscall_trace_entry:
SAVE_STATIC
move s0, t2
move a0, sp
+ daddiu a1, v0, __NR_64_Linux
jal syscall_trace_enter
+ bltz v0, 2f # seccomp failed? Skip syscall
+
move t0, s0
RESTORE_STATIC
ld a0, PT_R4(sp) # Restore argument registers
@@ -102,7 +105,7 @@ syscall_trace_entry:
sd t1, PT_R0(sp) # save it for syscall restarting
1: sd v0, PT_R2(sp) # result
- j syscall_exit
+2: j syscall_exit
illegal_syscall:
/* This also isn't a 64-bit syscall, throw an error. */
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index f7e5b72cf481..f68d2f4f0090 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -72,8 +72,11 @@ n32_syscall_trace_entry:
SAVE_STATIC
move s0, t2
move a0, sp
+ daddiu a1, v0, __NR_N32_Linux
jal syscall_trace_enter
+ bltz v0, 2f # seccomp failed? Skip syscall
+
move t0, s0
RESTORE_STATIC
ld a0, PT_R4(sp) # Restore argument registers
@@ -94,7 +97,7 @@ n32_syscall_trace_entry:
sd t1, PT_R0(sp) # save it for syscall restarting
1: sd v0, PT_R2(sp) # result
- j syscall_exit
+2: j syscall_exit
not_n32_scall:
/* This is not an n32 compatibility syscall, pass it on to
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 6788727d91af..70f6acecd928 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -112,7 +112,20 @@ trace_a_syscall:
move s0, t2 # Save syscall pointer
move a0, sp
- jal syscall_trace_enter
+ /*
+ * syscall number is in v0 unless we called syscall(__NR_###)
+ * where the real syscall number is in a0
+ * note: NR_syscall is the first O32 syscall but the macro is
+ * only defined when compiling with -mabi=32 (CONFIG_32BIT)
+ * therefore __NR_O32_Linux is used (4000)
+ */
+ addiu a1, v0, __NR_O32_Linux
+ bnez v0, 1f /* __NR_syscall at offset 0 */
+ lw a1, PT_R4(sp)
+
+1: jal syscall_trace_enter
+
+ bltz v0, 2f # seccomp failed? Skip syscall
move t0, s0
RESTORE_STATIC
@@ -136,7 +149,7 @@ trace_a_syscall:
sd t1, PT_R0(sp) # save it for syscall restarting
1: sd v0, PT_R2(sp) # result
- j syscall_exit
+2: j syscall_exit
/* ------------------------------------------------------------------------ */
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 5199563c4403..33133d3df3e5 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -6,6 +6,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1994 - 2000 Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2014, Imagination Technologies Ltd.
*/
#include <linux/cache.h>
#include <linux/context_tracking.h>
@@ -30,6 +31,7 @@
#include <linux/bitops.h>
#include <asm/cacheflush.h>
#include <asm/fpu.h>
+#include <asm/msa.h>
#include <asm/sim.h>
#include <asm/ucontext.h>
#include <asm/cpu-features.h>
@@ -46,8 +48,8 @@ static int (*restore_fp_context)(struct sigcontext __user *sc);
extern asmlinkage int _save_fp_context(struct sigcontext __user *sc);
extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc);
-extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc);
-extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc);
+extern asmlinkage int _save_msa_context(struct sigcontext __user *sc);
+extern asmlinkage int _restore_msa_context(struct sigcontext __user *sc);
struct sigframe {
u32 sf_ass[4]; /* argument save space for o32 */
@@ -64,17 +66,95 @@ struct rt_sigframe {
};
/*
+ * Thread saved context copy to/from a signal context presumed to be on the
+ * user stack, and therefore accessed with appropriate macros from uaccess.h.
+ */
+static int copy_fp_to_sigcontext(struct sigcontext __user *sc)
+{
+ int i;
+ int err = 0;
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err |=
+ __put_user(get_fpr64(&current->thread.fpu.fpr[i], 0),
+ &sc->sc_fpregs[i]);
+ }
+ err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
+
+ return err;
+}
+
+static int copy_fp_from_sigcontext(struct sigcontext __user *sc)
+{
+ int i;
+ int err = 0;
+ u64 fpr_val;
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err |= __get_user(fpr_val, &sc->sc_fpregs[i]);
+ set_fpr64(&current->thread.fpu.fpr[i], 0, fpr_val);
+ }
+ err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
+
+ return err;
+}
+
+/*
+ * These functions will save only the upper 64 bits of the vector registers,
+ * since the lower 64 bits have already been saved as the scalar FP context.
+ */
+static int copy_msa_to_sigcontext(struct sigcontext __user *sc)
+{
+ int i;
+ int err = 0;
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err |=
+ __put_user(get_fpr64(&current->thread.fpu.fpr[i], 1),
+ &sc->sc_msaregs[i]);
+ }
+ err |= __put_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
+
+ return err;
+}
+
+static int copy_msa_from_sigcontext(struct sigcontext __user *sc)
+{
+ int i;
+ int err = 0;
+ u64 val;
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err |= __get_user(val, &sc->sc_msaregs[i]);
+ set_fpr64(&current->thread.fpu.fpr[i], 1, val);
+ }
+ err |= __get_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
+
+ return err;
+}
+
+/*
* Helper routines
*/
-static int protected_save_fp_context(struct sigcontext __user *sc)
+static int protected_save_fp_context(struct sigcontext __user *sc,
+ unsigned used_math)
{
int err;
+ bool save_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
+#ifndef CONFIG_EVA
while (1) {
lock_fpu_owner();
- err = own_fpu_inatomic(1);
- if (!err)
- err = save_fp_context(sc); /* this might fail */
- unlock_fpu_owner();
+ if (is_fpu_owner()) {
+ err = save_fp_context(sc);
+ if (save_msa && !err)
+ err = _save_msa_context(sc);
+ unlock_fpu_owner();
+ } else {
+ unlock_fpu_owner();
+ err = copy_fp_to_sigcontext(sc);
+ if (save_msa && !err)
+ err = copy_msa_to_sigcontext(sc);
+ }
if (likely(!err))
break;
/* touch the sigcontext and try again */
@@ -84,18 +164,44 @@ static int protected_save_fp_context(struct sigcontext __user *sc)
if (err)
break; /* really bad sigcontext */
}
+#else
+ /*
+ * EVA does not have FPU EVA instructions so saving fpu context directly
+ * does not work.
+ */
+ disable_msa();
+ lose_fpu(1);
+ err = save_fp_context(sc); /* this might fail */
+ if (save_msa && !err)
+ err = copy_msa_to_sigcontext(sc);
+#endif
return err;
}
-static int protected_restore_fp_context(struct sigcontext __user *sc)
+static int protected_restore_fp_context(struct sigcontext __user *sc,
+ unsigned used_math)
{
int err, tmp __maybe_unused;
+ bool restore_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
+#ifndef CONFIG_EVA
while (1) {
lock_fpu_owner();
- err = own_fpu_inatomic(0);
- if (!err)
- err = restore_fp_context(sc); /* this might fail */
- unlock_fpu_owner();
+ if (is_fpu_owner()) {
+ err = restore_fp_context(sc);
+ if (restore_msa && !err) {
+ enable_msa();
+ err = _restore_msa_context(sc);
+ } else {
+ /* signal handler may have used MSA */
+ disable_msa();
+ }
+ unlock_fpu_owner();
+ } else {
+ unlock_fpu_owner();
+ err = copy_fp_from_sigcontext(sc);
+ if (!err && (used_math & USEDMATH_MSA))
+ err = copy_msa_from_sigcontext(sc);
+ }
if (likely(!err))
break;
/* touch the sigcontext and try again */
@@ -105,6 +211,17 @@ static int protected_restore_fp_context(struct sigcontext __user *sc)
if (err)
break; /* really bad sigcontext */
}
+#else
+ /*
+ * EVA does not have FPU EVA instructions so restoring fpu context
+ * directly does not work.
+ */
+ enable_msa();
+ lose_fpu(0);
+ err = restore_fp_context(sc); /* this might fail */
+ if (restore_msa && !err)
+ err = copy_msa_from_sigcontext(sc);
+#endif
return err;
}
@@ -135,7 +252,8 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
}
- used_math = !!used_math();
+ used_math = used_math() ? USEDMATH_FP : 0;
+ used_math |= thread_msa_context_live() ? USEDMATH_MSA : 0;
err |= __put_user(used_math, &sc->sc_used_math);
if (used_math) {
@@ -143,7 +261,7 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
* Save FPU state to signal context. Signal handler
* will "inherit" current FPU state.
*/
- err |= protected_save_fp_context(sc);
+ err |= protected_save_fp_context(sc, used_math);
}
return err;
}
@@ -168,14 +286,14 @@ int fpcsr_pending(unsigned int __user *fpcsr)
}
static int
-check_and_restore_fp_context(struct sigcontext __user *sc)
+check_and_restore_fp_context(struct sigcontext __user *sc, unsigned used_math)
{
int err, sig;
err = sig = fpcsr_pending(&sc->sc_fpc_csr);
if (err > 0)
err = 0;
- err |= protected_restore_fp_context(sc);
+ err |= protected_restore_fp_context(sc, used_math);
return err ?: sig;
}
@@ -215,9 +333,10 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
if (used_math) {
/* restore fpu context if we have used it before */
if (!err)
- err = check_and_restore_fp_context(sc);
+ err = check_and_restore_fp_context(sc, used_math);
} else {
- /* signal handler may have used FPU. Give it up. */
+ /* signal handler may have used FPU or MSA. Disable them. */
+ disable_msa();
lose_fpu(0);
}
@@ -591,23 +710,26 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
}
#ifdef CONFIG_SMP
+#ifndef CONFIG_EVA
static int smp_save_fp_context(struct sigcontext __user *sc)
{
return raw_cpu_has_fpu
? _save_fp_context(sc)
- : fpu_emulator_save_context(sc);
+ : copy_fp_to_sigcontext(sc);
}
static int smp_restore_fp_context(struct sigcontext __user *sc)
{
return raw_cpu_has_fpu
? _restore_fp_context(sc)
- : fpu_emulator_restore_context(sc);
+ : copy_fp_from_sigcontext(sc);
}
+#endif /* CONFIG_EVA */
#endif
static int signal_setup(void)
{
+#ifndef CONFIG_EVA
#ifdef CONFIG_SMP
/* For now just do the cpu_has_fpu check when the functions are invoked */
save_fp_context = smp_save_fp_context;
@@ -617,9 +739,13 @@ static int signal_setup(void)
save_fp_context = _save_fp_context;
restore_fp_context = _restore_fp_context;
} else {
- save_fp_context = fpu_emulator_save_context;
- restore_fp_context = fpu_emulator_restore_context;
+ save_fp_context = copy_fp_from_sigcontext;
+ restore_fp_context = copy_fp_to_sigcontext;
}
+#endif /* CONFIG_SMP */
+#else
+ save_fp_context = copy_fp_from_sigcontext;;
+ restore_fp_context = copy_fp_to_sigcontext;
#endif
return 0;
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 3d60f7750fa8..299f956e4db3 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -30,6 +30,7 @@
#include <asm/sim.h>
#include <asm/ucontext.h>
#include <asm/fpu.h>
+#include <asm/msa.h>
#include <asm/war.h>
#include <asm/vdso.h>
#include <asm/dsp.h>
@@ -42,8 +43,8 @@ static int (*restore_fp_context32)(struct sigcontext32 __user *sc);
extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc);
extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc);
-extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc);
-extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc);
+extern asmlinkage int _save_msa_context32(struct sigcontext32 __user *sc);
+extern asmlinkage int _restore_msa_context32(struct sigcontext32 __user *sc);
/*
* Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
@@ -78,17 +79,96 @@ struct rt_sigframe32 {
};
/*
+ * Thread saved context copy to/from a signal context presumed to be on the
+ * user stack, and therefore accessed with appropriate macros from uaccess.h.
+ */
+static int copy_fp_to_sigcontext32(struct sigcontext32 __user *sc)
+{
+ int i;
+ int err = 0;
+ int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
+
+ for (i = 0; i < NUM_FPU_REGS; i += inc) {
+ err |=
+ __put_user(get_fpr64(&current->thread.fpu.fpr[i], 0),
+ &sc->sc_fpregs[i]);
+ }
+ err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
+
+ return err;
+}
+
+static int copy_fp_from_sigcontext32(struct sigcontext32 __user *sc)
+{
+ int i;
+ int err = 0;
+ int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
+ u64 fpr_val;
+
+ for (i = 0; i < NUM_FPU_REGS; i += inc) {
+ err |= __get_user(fpr_val, &sc->sc_fpregs[i]);
+ set_fpr64(&current->thread.fpu.fpr[i], 0, fpr_val);
+ }
+ err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
+
+ return err;
+}
+
+/*
+ * These functions will save only the upper 64 bits of the vector registers,
+ * since the lower 64 bits have already been saved as the scalar FP context.
+ */
+static int copy_msa_to_sigcontext32(struct sigcontext32 __user *sc)
+{
+ int i;
+ int err = 0;
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err |=
+ __put_user(get_fpr64(&current->thread.fpu.fpr[i], 1),
+ &sc->sc_msaregs[i]);
+ }
+ err |= __put_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
+
+ return err;
+}
+
+static int copy_msa_from_sigcontext32(struct sigcontext32 __user *sc)
+{
+ int i;
+ int err = 0;
+ u64 val;
+
+ for (i = 0; i < NUM_FPU_REGS; i++) {
+ err |= __get_user(val, &sc->sc_msaregs[i]);
+ set_fpr64(&current->thread.fpu.fpr[i], 1, val);
+ }
+ err |= __get_user(current->thread.fpu.msacsr, &sc->sc_msa_csr);
+
+ return err;
+}
+
+/*
* sigcontext handlers
*/
-static int protected_save_fp_context32(struct sigcontext32 __user *sc)
+static int protected_save_fp_context32(struct sigcontext32 __user *sc,
+ unsigned used_math)
{
int err;
+ bool save_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
while (1) {
lock_fpu_owner();
- err = own_fpu_inatomic(1);
- if (!err)
- err = save_fp_context32(sc); /* this might fail */
- unlock_fpu_owner();
+ if (is_fpu_owner()) {
+ err = save_fp_context32(sc);
+ if (save_msa && !err)
+ err = _save_msa_context32(sc);
+ unlock_fpu_owner();
+ } else {
+ unlock_fpu_owner();
+ err = copy_fp_to_sigcontext32(sc);
+ if (save_msa && !err)
+ err = copy_msa_to_sigcontext32(sc);
+ }
if (likely(!err))
break;
/* touch the sigcontext and try again */
@@ -101,15 +181,29 @@ static int protected_save_fp_context32(struct sigcontext32 __user *sc)
return err;
}
-static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
+static int protected_restore_fp_context32(struct sigcontext32 __user *sc,
+ unsigned used_math)
{
int err, tmp __maybe_unused;
+ bool restore_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
while (1) {
lock_fpu_owner();
- err = own_fpu_inatomic(0);
- if (!err)
- err = restore_fp_context32(sc); /* this might fail */
- unlock_fpu_owner();
+ if (is_fpu_owner()) {
+ err = restore_fp_context32(sc);
+ if (restore_msa && !err) {
+ enable_msa();
+ err = _restore_msa_context32(sc);
+ } else {
+ /* signal handler may have used MSA */
+ disable_msa();
+ }
+ unlock_fpu_owner();
+ } else {
+ unlock_fpu_owner();
+ err = copy_fp_from_sigcontext32(sc);
+ if (restore_msa && !err)
+ err = copy_msa_from_sigcontext32(sc);
+ }
if (likely(!err))
break;
/* touch the sigcontext and try again */
@@ -147,7 +241,8 @@ static int setup_sigcontext32(struct pt_regs *regs,
err |= __put_user(mflo3(), &sc->sc_lo3);
}
- used_math = !!used_math();
+ used_math = used_math() ? USEDMATH_FP : 0;
+ used_math |= thread_msa_context_live() ? USEDMATH_MSA : 0;
err |= __put_user(used_math, &sc->sc_used_math);
if (used_math) {
@@ -155,20 +250,21 @@ static int setup_sigcontext32(struct pt_regs *regs,
* Save FPU state to signal context. Signal handler
* will "inherit" current FPU state.
*/
- err |= protected_save_fp_context32(sc);
+ err |= protected_save_fp_context32(sc, used_math);
}
return err;
}
static int
-check_and_restore_fp_context32(struct sigcontext32 __user *sc)
+check_and_restore_fp_context32(struct sigcontext32 __user *sc,
+ unsigned used_math)
{
int err, sig;
err = sig = fpcsr_pending(&sc->sc_fpc_csr);
if (err > 0)
err = 0;
- err |= protected_restore_fp_context32(sc);
+ err |= protected_restore_fp_context32(sc, used_math);
return err ?: sig;
}
@@ -205,9 +301,10 @@ static int restore_sigcontext32(struct pt_regs *regs,
if (used_math) {
/* restore fpu context if we have used it before */
if (!err)
- err = check_and_restore_fp_context32(sc);
+ err = check_and_restore_fp_context32(sc, used_math);
} else {
- /* signal handler may have used FPU. Give it up. */
+ /* signal handler may have used FPU or MSA. Disable them. */
+ disable_msa();
lose_fpu(0);
}
@@ -566,8 +663,8 @@ static int signal32_init(void)
save_fp_context32 = _save_fp_context32;
restore_fp_context32 = _restore_fp_context32;
} else {
- save_fp_context32 = fpu_emulator_save_context32;
- restore_fp_context32 = fpu_emulator_restore_context32;
+ save_fp_context32 = copy_fp_to_sigcontext32;
+ restore_fp_context32 = copy_fp_from_sigcontext32;
}
return 0;
diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c
index 1b925d8a610c..3ef55fb7ac03 100644
--- a/arch/mips/kernel/smp-cmp.c
+++ b/arch/mips/kernel/smp-cmp.c
@@ -39,57 +39,9 @@
#include <asm/amon.h>
#include <asm/gic.h>
-static void ipi_call_function(unsigned int cpu)
-{
- pr_debug("CPU%d: %s cpu %d status %08x\n",
- smp_processor_id(), __func__, cpu, read_c0_status());
-
- gic_send_ipi(plat_ipi_call_int_xlate(cpu));
-}
-
-
-static void ipi_resched(unsigned int cpu)
-{
- pr_debug("CPU%d: %s cpu %d status %08x\n",
- smp_processor_id(), __func__, cpu, read_c0_status());
-
- gic_send_ipi(plat_ipi_resched_int_xlate(cpu));
-}
-
-/*
- * FIXME: This isn't restricted to CMP
- * The SMVP kernel could use GIC interrupts if available
- */
-void cmp_send_ipi_single(int cpu, unsigned int action)
-{
- unsigned long flags;
-
- local_irq_save(flags);
-
- switch (action) {
- case SMP_CALL_FUNCTION:
- ipi_call_function(cpu);
- break;
-
- case SMP_RESCHEDULE_YOURSELF:
- ipi_resched(cpu);
- break;
- }
-
- local_irq_restore(flags);
-}
-
-static void cmp_send_ipi_mask(const struct cpumask *mask, unsigned int action)
-{
- unsigned int i;
-
- for_each_cpu(i, mask)
- cmp_send_ipi_single(i, action);
-}
-
static void cmp_init_secondary(void)
{
- struct cpuinfo_mips *c = &current_cpu_data;
+ struct cpuinfo_mips *c __maybe_unused = &current_cpu_data;
/* Assume GIC is present */
change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP6 |
@@ -97,7 +49,6 @@ static void cmp_init_secondary(void)
/* Enable per-cpu interrupts: platform specific */
- c->core = (read_c0_ebase() >> 1) & 0x1ff;
#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
if (cpu_has_mipsmt)
c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) &
@@ -210,8 +161,8 @@ void __init cmp_prepare_cpus(unsigned int max_cpus)
}
struct plat_smp_ops cmp_smp_ops = {
- .send_ipi_single = cmp_send_ipi_single,
- .send_ipi_mask = cmp_send_ipi_mask,
+ .send_ipi_single = gic_send_ipi_single,
+ .send_ipi_mask = gic_send_ipi_mask,
.init_secondary = cmp_init_secondary,
.smp_finish = cmp_smp_finish,
.cpus_done = cmp_cpus_done,
diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c
new file mode 100644
index 000000000000..536eec0d21b6
--- /dev/null
+++ b/arch/mips/kernel/smp-cps.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+
+#include <asm/cacheflush.h>
+#include <asm/gic.h>
+#include <asm/mips-cm.h>
+#include <asm/mips-cpc.h>
+#include <asm/mips_mt.h>
+#include <asm/mipsregs.h>
+#include <asm/smp-cps.h>
+#include <asm/time.h>
+#include <asm/uasm.h>
+
+static DECLARE_BITMAP(core_power, NR_CPUS);
+
+struct boot_config mips_cps_bootcfg;
+
+static void init_core(void)
+{
+ unsigned int nvpes, t;
+ u32 mvpconf0, vpeconf0, vpecontrol, tcstatus, tcbind, status;
+
+ if (!cpu_has_mipsmt)
+ return;
+
+ /* Enter VPE configuration state */
+ dvpe();
+ set_c0_mvpcontrol(MVPCONTROL_VPC);
+
+ /* Retrieve the count of VPEs in this core */
+ mvpconf0 = read_c0_mvpconf0();
+ nvpes = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
+ smp_num_siblings = nvpes;
+
+ for (t = 1; t < nvpes; t++) {
+ /* Use a 1:1 mapping of TC index to VPE index */
+ settc(t);
+
+ /* Bind 1 TC to this VPE */
+ tcbind = read_tc_c0_tcbind();
+ tcbind &= ~TCBIND_CURVPE;
+ tcbind |= t << TCBIND_CURVPE_SHIFT;
+ write_tc_c0_tcbind(tcbind);
+
+ /* Set exclusive TC, non-active, master */
+ vpeconf0 = read_vpe_c0_vpeconf0();
+ vpeconf0 &= ~(VPECONF0_XTC | VPECONF0_VPA);
+ vpeconf0 |= t << VPECONF0_XTC_SHIFT;
+ vpeconf0 |= VPECONF0_MVP;
+ write_vpe_c0_vpeconf0(vpeconf0);
+
+ /* Declare TC non-active, non-allocatable & interrupt exempt */
+ tcstatus = read_tc_c0_tcstatus();
+ tcstatus &= ~(TCSTATUS_A | TCSTATUS_DA);
+ tcstatus |= TCSTATUS_IXMT;
+ write_tc_c0_tcstatus(tcstatus);
+
+ /* Halt the TC */
+ write_tc_c0_tchalt(TCHALT_H);
+
+ /* Allow only 1 TC to execute */
+ vpecontrol = read_vpe_c0_vpecontrol();
+ vpecontrol &= ~VPECONTROL_TE;
+ write_vpe_c0_vpecontrol(vpecontrol);
+
+ /* Copy (most of) Status from VPE 0 */
+ status = read_c0_status();
+ status &= ~(ST0_IM | ST0_IE | ST0_KSU);
+ status |= ST0_CU0;
+ write_vpe_c0_status(status);
+
+ /* Copy Config from VPE 0 */
+ write_vpe_c0_config(read_c0_config());
+ write_vpe_c0_config7(read_c0_config7());
+
+ /* Ensure no software interrupts are pending */
+ write_vpe_c0_cause(0);
+
+ /* Sync Count */
+ write_vpe_c0_count(read_c0_count());
+ }
+
+ /* Leave VPE configuration state */
+ clear_c0_mvpcontrol(MVPCONTROL_VPC);
+}
+
+static void __init cps_smp_setup(void)
+{
+ unsigned int ncores, nvpes, core_vpes;
+ int c, v;
+ u32 core_cfg, *entry_code;
+
+ /* Detect & record VPE topology */
+ ncores = mips_cm_numcores();
+ pr_info("VPE topology ");
+ for (c = nvpes = 0; c < ncores; c++) {
+ if (cpu_has_mipsmt && config_enabled(CONFIG_MIPS_MT_SMP)) {
+ write_gcr_cl_other(c << CM_GCR_Cx_OTHER_CORENUM_SHF);
+ core_cfg = read_gcr_co_config();
+ core_vpes = ((core_cfg & CM_GCR_Cx_CONFIG_PVPE_MSK) >>
+ CM_GCR_Cx_CONFIG_PVPE_SHF) + 1;
+ } else {
+ core_vpes = 1;
+ }
+
+ pr_cont("%c%u", c ? ',' : '{', core_vpes);
+
+ for (v = 0; v < min_t(int, core_vpes, NR_CPUS - nvpes); v++) {
+ cpu_data[nvpes + v].core = c;
+#ifdef CONFIG_MIPS_MT_SMP
+ cpu_data[nvpes + v].vpe_id = v;
+#endif
+ }
+
+ nvpes += core_vpes;
+ }
+ pr_cont("} total %u\n", nvpes);
+
+ /* Indicate present CPUs (CPU being synonymous with VPE) */
+ for (v = 0; v < min_t(unsigned, nvpes, NR_CPUS); v++) {
+ set_cpu_possible(v, true);
+ set_cpu_present(v, true);
+ __cpu_number_map[v] = v;
+ __cpu_logical_map[v] = v;
+ }
+
+ /* Core 0 is powered up (we're running on it) */
+ bitmap_set(core_power, 0, 1);
+
+ /* Disable MT - we only want to run 1 TC per VPE */
+ if (cpu_has_mipsmt)
+ dmt();
+
+ /* Initialise core 0 */
+ init_core();
+
+ /* Patch the start of mips_cps_core_entry to provide the CM base */
+ entry_code = (u32 *)&mips_cps_core_entry;
+ UASM_i_LA(&entry_code, 3, (long)mips_cm_base);
+
+ /* Make core 0 coherent with everything */
+ write_gcr_cl_coherence(0xff);
+}
+
+static void __init cps_prepare_cpus(unsigned int max_cpus)
+{
+ mips_mt_set_cpuoptions();
+}
+
+static void boot_core(struct boot_config *cfg)
+{
+ u32 access;
+
+ /* Select the appropriate core */
+ write_gcr_cl_other(cfg->core << CM_GCR_Cx_OTHER_CORENUM_SHF);
+
+ /* Set its reset vector */
+ write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry));
+
+ /* Ensure its coherency is disabled */
+ write_gcr_co_coherence(0);
+
+ /* Ensure the core can access the GCRs */
+ access = read_gcr_access();
+ access |= 1 << (CM_GCR_ACCESS_ACCESSEN_SHF + cfg->core);
+ write_gcr_access(access);
+
+ /* Copy cfg */
+ mips_cps_bootcfg = *cfg;
+
+ if (mips_cpc_present()) {
+ /* Select the appropriate core */
+ write_cpc_cl_other(cfg->core << CPC_Cx_OTHER_CORENUM_SHF);
+
+ /* Reset the core */
+ write_cpc_co_cmd(CPC_Cx_CMD_RESET);
+ } else {
+ /* Take the core out of reset */
+ write_gcr_co_reset_release(0);
+ }
+
+ /* The core is now powered up */
+ bitmap_set(core_power, cfg->core, 1);
+}
+
+static void boot_vpe(void *info)
+{
+ struct boot_config *cfg = info;
+ u32 tcstatus, vpeconf0;
+
+ /* Enter VPE configuration state */
+ dvpe();
+ set_c0_mvpcontrol(MVPCONTROL_VPC);
+
+ settc(cfg->vpe);
+
+ /* Set the TC restart PC */
+ write_tc_c0_tcrestart((unsigned long)&smp_bootstrap);
+
+ /* Activate the TC, allow interrupts */
+ tcstatus = read_tc_c0_tcstatus();
+ tcstatus &= ~TCSTATUS_IXMT;
+ tcstatus |= TCSTATUS_A;
+ write_tc_c0_tcstatus(tcstatus);
+
+ /* Clear the TC halt bit */
+ write_tc_c0_tchalt(0);
+
+ /* Activate the VPE */
+ vpeconf0 = read_vpe_c0_vpeconf0();
+ vpeconf0 |= VPECONF0_VPA;
+ write_vpe_c0_vpeconf0(vpeconf0);
+
+ /* Set the stack & global pointer registers */
+ write_tc_gpr_sp(cfg->sp);
+ write_tc_gpr_gp(cfg->gp);
+
+ /* Leave VPE configuration state */
+ clear_c0_mvpcontrol(MVPCONTROL_VPC);
+
+ /* Enable other VPEs to execute */
+ evpe(EVPE_ENABLE);
+}
+
+static void cps_boot_secondary(int cpu, struct task_struct *idle)
+{
+ struct boot_config cfg;
+ unsigned int remote;
+ int err;
+
+ cfg.core = cpu_data[cpu].core;
+ cfg.vpe = cpu_vpe_id(&cpu_data[cpu]);
+ cfg.pc = (unsigned long)&smp_bootstrap;
+ cfg.sp = __KSTK_TOS(idle);
+ cfg.gp = (unsigned long)task_thread_info(idle);
+
+ if (!test_bit(cfg.core, core_power)) {
+ /* Boot a VPE on a powered down core */
+ boot_core(&cfg);
+ return;
+ }
+
+ if (cfg.core != current_cpu_data.core) {
+ /* Boot a VPE on another powered up core */
+ for (remote = 0; remote < NR_CPUS; remote++) {
+ if (cpu_data[remote].core != cfg.core)
+ continue;
+ if (cpu_online(remote))
+ break;
+ }
+ BUG_ON(remote >= NR_CPUS);
+
+ err = smp_call_function_single(remote, boot_vpe, &cfg, 1);
+ if (err)
+ panic("Failed to call remote CPU\n");
+ return;
+ }
+
+ BUG_ON(!cpu_has_mipsmt);
+
+ /* Boot a VPE on this core */
+ boot_vpe(&cfg);
+}
+
+static void cps_init_secondary(void)
+{
+ /* Disable MT - we only want to run 1 TC per VPE */
+ if (cpu_has_mipsmt)
+ dmt();
+
+ /* TODO: revisit this assumption once hotplug is implemented */
+ if (cpu_vpe_id(&current_cpu_data) == 0)
+ init_core();
+
+ change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 |
+ STATUSF_IP6 | STATUSF_IP7);
+}
+
+static void cps_smp_finish(void)
+{
+ write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency / HZ));
+
+#ifdef CONFIG_MIPS_MT_FPAFF
+ /* If we have an FPU, enroll ourselves in the FPU-full mask */
+ if (cpu_has_fpu)
+ cpu_set(smp_processor_id(), mt_fpu_cpumask);
+#endif /* CONFIG_MIPS_MT_FPAFF */
+
+ local_irq_enable();
+}
+
+static void cps_cpus_done(void)
+{
+}
+
+static struct plat_smp_ops cps_smp_ops = {
+ .smp_setup = cps_smp_setup,
+ .prepare_cpus = cps_prepare_cpus,
+ .boot_secondary = cps_boot_secondary,
+ .init_secondary = cps_init_secondary,
+ .smp_finish = cps_smp_finish,
+ .send_ipi_single = gic_send_ipi_single,
+ .send_ipi_mask = gic_send_ipi_mask,
+ .cpus_done = cps_cpus_done,
+};
+
+int register_cps_smp_ops(void)
+{
+ if (!mips_cm_present()) {
+ pr_warn("MIPS CPS SMP unable to proceed without a CM\n");
+ return -ENODEV;
+ }
+
+ /* check we have a GIC - we need one for IPIs */
+ if (!(read_gcr_gic_status() & CM_GCR_GIC_STATUS_EX_MSK)) {
+ pr_warn("MIPS CPS SMP unable to proceed without a GIC\n");
+ return -ENODEV;
+ }
+
+ register_smp_ops(&cps_smp_ops);
+ return 0;
+}
diff --git a/arch/mips/kernel/smp-gic.c b/arch/mips/kernel/smp-gic.c
new file mode 100644
index 000000000000..3bb1f92ab525
--- /dev/null
+++ b/arch/mips/kernel/smp-gic.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * Based on smp-cmp.c:
+ * Copyright (C) 2007 MIPS Technologies, Inc.
+ * Author: Chris Dearman (chris@mips.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/printk.h>
+
+#include <asm/gic.h>
+#include <asm/smp-ops.h>
+
+void gic_send_ipi_single(int cpu, unsigned int action)
+{
+ unsigned long flags;
+ unsigned int intr;
+
+ pr_debug("CPU%d: %s cpu %d action %u status %08x\n",
+ smp_processor_id(), __func__, cpu, action, read_c0_status());
+
+ local_irq_save(flags);
+
+ switch (action) {
+ case SMP_CALL_FUNCTION:
+ intr = plat_ipi_call_int_xlate(cpu);
+ break;
+
+ case SMP_RESCHEDULE_YOURSELF:
+ intr = plat_ipi_resched_int_xlate(cpu);
+ break;
+
+ default:
+ BUG();
+ }
+
+ gic_send_ipi(intr);
+ local_irq_restore(flags);
+}
+
+void gic_send_ipi_mask(const struct cpumask *mask, unsigned int action)
+{
+ unsigned int i;
+
+ for_each_cpu(i, mask)
+ gic_send_ipi_single(i, action);
+}
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
index 0fb8cefc9114..f8e13149604d 100644
--- a/arch/mips/kernel/smp-mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -113,27 +113,6 @@ static void __init smvp_tc_init(unsigned int tc, unsigned int mvpconf0)
write_tc_c0_tchalt(TCHALT_H);
}
-#ifdef CONFIG_IRQ_GIC
-static void mp_send_ipi_single(int cpu, unsigned int action)
-{
- unsigned long flags;
-
- local_irq_save(flags);
-
- switch (action) {
- case SMP_CALL_FUNCTION:
- gic_send_ipi(plat_ipi_call_int_xlate(cpu));
- break;
-
- case SMP_RESCHEDULE_YOURSELF:
- gic_send_ipi(plat_ipi_resched_int_xlate(cpu));
- break;
- }
-
- local_irq_restore(flags);
-}
-#endif
-
static void vsmp_send_ipi_single(int cpu, unsigned int action)
{
int i;
@@ -142,7 +121,7 @@ static void vsmp_send_ipi_single(int cpu, unsigned int action)
#ifdef CONFIG_IRQ_GIC
if (gic_present) {
- mp_send_ipi_single(cpu, action);
+ gic_send_ipi_single(cpu, action);
return;
}
#endif
@@ -313,3 +292,25 @@ struct plat_smp_ops vsmp_smp_ops = {
.smp_setup = vsmp_smp_setup,
.prepare_cpus = vsmp_prepare_cpus,
};
+
+static int proc_cpuinfo_chain_call(struct notifier_block *nfb,
+ unsigned long action_unused, void *data)
+{
+ struct proc_cpuinfo_notifier_args *pcn = data;
+ struct seq_file *m = pcn->m;
+ unsigned long n = pcn->n;
+
+ if (!cpu_has_mipsmt)
+ return NOTIFY_OK;
+
+ seq_printf(m, "VPE\t\t\t: %d\n", cpu_data[n].vpe_id);
+
+ return NOTIFY_OK;
+}
+
+static int __init proc_cpuinfo_notifier_init(void)
+{
+ return proc_cpuinfo_notifier(proc_cpuinfo_chain_call, 0);
+}
+
+subsys_initcall(proc_cpuinfo_notifier_init);
diff --git a/arch/mips/kernel/smtc-proc.c b/arch/mips/kernel/smtc-proc.c
index c10aa84c9fa9..38635a996cbf 100644
--- a/arch/mips/kernel/smtc-proc.c
+++ b/arch/mips/kernel/smtc-proc.c
@@ -77,3 +77,26 @@ void init_smtc_stats(void)
proc_create("smtc", 0444, NULL, &smtc_proc_fops);
}
+
+static int proc_cpuinfo_chain_call(struct notifier_block *nfb,
+ unsigned long action_unused, void *data)
+{
+ struct proc_cpuinfo_notifier_args *pcn = data;
+ struct seq_file *m = pcn->m;
+ unsigned long n = pcn->n;
+
+ if (!cpu_has_mipsmt)
+ return NOTIFY_OK;
+
+ seq_printf(m, "VPE\t\t\t: %d\n", cpu_data[n].vpe_id);
+ seq_printf(m, "TC\t\t\t: %d\n", cpu_data[n].tc_id);
+
+ return NOTIFY_OK;
+}
+
+static int __init proc_cpuinfo_notifier_init(void)
+{
+ return proc_cpuinfo_notifier(proc_cpuinfo_chain_call, 0);
+}
+
+subsys_initcall(proc_cpuinfo_notifier_init);
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index dfc1b911be04..c1681d65dd5c 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -1007,7 +1007,7 @@ static void __irq_entry smtc_clock_tick_interrupt(void)
int irq = MIPS_CPU_IRQ_BASE + 1;
irq_enter();
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
cd = &per_cpu(mips_clockevent_device, cpu);
cd->event_handler(cd);
irq_exit();
diff --git a/arch/mips/kernel/spram.c b/arch/mips/kernel/spram.c
index b242e2c10ea0..67f2495def1c 100644
--- a/arch/mips/kernel/spram.c
+++ b/arch/mips/kernel/spram.c
@@ -197,16 +197,17 @@ static void probe_spram(char *type,
}
void spram_config(void)
{
- struct cpuinfo_mips *c = &current_cpu_data;
unsigned int config0;
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_24K:
case CPU_34K:
case CPU_74K:
case CPU_1004K:
+ case CPU_1074K:
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
+ case CPU_P5600:
config0 = read_c0_config();
/* FIXME: addresses are Malta specific */
if (config0 & (1<<24)) {
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index b79d13f95bf0..4a4f9dda5658 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -110,7 +110,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
if (cpu_has_llsc && R10000_LLSC_WAR) {
__asm__ __volatile__ (
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" li %[err], 0 \n"
"1: ll %[old], (%[addr]) \n"
" move %[tmp], %[new] \n"
@@ -135,7 +135,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
: "memory");
} else if (cpu_has_llsc) {
__asm__ __volatile__ (
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" li %[err], 0 \n"
"1: ll %[old], (%[addr]) \n"
" move %[tmp], %[new] \n"
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index e0b499694d18..074e857ced28 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -10,6 +10,7 @@
* Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki
* Copyright (C) 2000, 2001, 2012 MIPS Technologies, Inc. All rights reserved.
+ * Copyright (C) 2014, Imagination Technologies Ltd.
*/
#include <linux/bug.h>
#include <linux/compiler.h>
@@ -47,6 +48,7 @@
#include <asm/mipsregs.h>
#include <asm/mipsmtregs.h>
#include <asm/module.h>
+#include <asm/msa.h>
#include <asm/pgtable.h>
#include <asm/ptrace.h>
#include <asm/sections.h>
@@ -77,8 +79,10 @@ extern asmlinkage void handle_ri_rdhwr(void);
extern asmlinkage void handle_cpu(void);
extern asmlinkage void handle_ov(void);
extern asmlinkage void handle_tr(void);
+extern asmlinkage void handle_msa_fpe(void);
extern asmlinkage void handle_fpe(void);
extern asmlinkage void handle_ftlb(void);
+extern asmlinkage void handle_msa(void);
extern asmlinkage void handle_mdmx(void);
extern asmlinkage void handle_watch(void);
extern asmlinkage void handle_mt(void);
@@ -861,6 +865,11 @@ asmlinkage void do_bp(struct pt_regs *regs)
enum ctx_state prev_state;
unsigned long epc;
u16 instr[2];
+ mm_segment_t seg;
+
+ seg = get_fs();
+ if (!user_mode(regs))
+ set_fs(KERNEL_DS);
prev_state = exception_enter();
if (get_isa16_mode(regs->cp0_epc)) {
@@ -870,17 +879,19 @@ asmlinkage void do_bp(struct pt_regs *regs)
if ((__get_user(instr[0], (u16 __user *)msk_isa16_mode(epc)) ||
(__get_user(instr[1], (u16 __user *)msk_isa16_mode(epc + 2)))))
goto out_sigsegv;
- opcode = (instr[0] << 16) | instr[1];
+ opcode = (instr[0] << 16) | instr[1];
} else {
- /* MIPS16e mode */
- if (__get_user(instr[0], (u16 __user *)msk_isa16_mode(epc)))
+ /* MIPS16e mode */
+ if (__get_user(instr[0],
+ (u16 __user *)msk_isa16_mode(epc)))
goto out_sigsegv;
- bcode = (instr[0] >> 6) & 0x3f;
- do_trap_or_bp(regs, bcode, "Break");
- goto out;
+ bcode = (instr[0] >> 6) & 0x3f;
+ do_trap_or_bp(regs, bcode, "Break");
+ goto out;
}
} else {
- if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
+ if (__get_user(opcode,
+ (unsigned int __user *) exception_epc(regs)))
goto out_sigsegv;
}
@@ -918,6 +929,7 @@ asmlinkage void do_bp(struct pt_regs *regs)
do_trap_or_bp(regs, bcode, "Break");
out:
+ set_fs(seg);
exception_exit(prev_state);
return;
@@ -931,8 +943,13 @@ asmlinkage void do_tr(struct pt_regs *regs)
u32 opcode, tcode = 0;
enum ctx_state prev_state;
u16 instr[2];
+ mm_segment_t seg;
unsigned long epc = msk_isa16_mode(exception_epc(regs));
+ seg = get_fs();
+ if (!user_mode(regs))
+ set_fs(get_ds());
+
prev_state = exception_enter();
if (get_isa16_mode(regs->cp0_epc)) {
if (__get_user(instr[0], (u16 __user *)(epc + 0)) ||
@@ -953,6 +970,7 @@ asmlinkage void do_tr(struct pt_regs *regs)
do_trap_or_bp(regs, tcode, "Trap");
out:
+ set_fs(seg);
exception_exit(prev_state);
return;
@@ -1074,6 +1092,76 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
return NOTIFY_OK;
}
+static int enable_restore_fp_context(int msa)
+{
+ int err, was_fpu_owner;
+
+ if (!used_math()) {
+ /* First time FP context user. */
+ err = init_fpu();
+ if (msa && !err)
+ enable_msa();
+ if (!err)
+ set_used_math();
+ return err;
+ }
+
+ /*
+ * This task has formerly used the FP context.
+ *
+ * If this thread has no live MSA vector context then we can simply
+ * restore the scalar FP context. If it has live MSA vector context
+ * (that is, it has or may have used MSA since last performing a
+ * function call) then we'll need to restore the vector context. This
+ * applies even if we're currently only executing a scalar FP
+ * instruction. This is because if we were to later execute an MSA
+ * instruction then we'd either have to:
+ *
+ * - Restore the vector context & clobber any registers modified by
+ * scalar FP instructions between now & then.
+ *
+ * or
+ *
+ * - Not restore the vector context & lose the most significant bits
+ * of all vector registers.
+ *
+ * Neither of those options is acceptable. We cannot restore the least
+ * significant bits of the registers now & only restore the most
+ * significant bits later because the most significant bits of any
+ * vector registers whose aliased FP register is modified now will have
+ * been zeroed. We'd have no way to know that when restoring the vector
+ * context & thus may load an outdated value for the most significant
+ * bits of a vector register.
+ */
+ if (!msa && !thread_msa_context_live())
+ return own_fpu(1);
+
+ /*
+ * This task is using or has previously used MSA. Thus we require
+ * that Status.FR == 1.
+ */
+ was_fpu_owner = is_fpu_owner();
+ err = own_fpu(0);
+ if (err)
+ return err;
+
+ enable_msa();
+ write_msa_csr(current->thread.fpu.msacsr);
+ set_thread_flag(TIF_USEDMSA);
+
+ /*
+ * If this is the first time that the task is using MSA and it has
+ * previously used scalar FP in this time slice then we already nave
+ * FP context which we shouldn't clobber.
+ */
+ if (!test_and_set_thread_flag(TIF_MSA_CTX_LIVE) && was_fpu_owner)
+ return 0;
+
+ /* We need to restore the vector context. */
+ restore_msa(current);
+ return 0;
+}
+
asmlinkage void do_cpu(struct pt_regs *regs)
{
enum ctx_state prev_state;
@@ -1153,12 +1241,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
/* Fall through. */
case 1:
- if (used_math()) /* Using the FPU again. */
- err = own_fpu(1);
- else { /* First time FPU user. */
- err = init_fpu();
- set_used_math();
- }
+ err = enable_restore_fp_context(0);
if (!raw_cpu_has_fpu || err) {
int sig;
@@ -1183,6 +1266,37 @@ out:
exception_exit(prev_state);
}
+asmlinkage void do_msa_fpe(struct pt_regs *regs)
+{
+ enum ctx_state prev_state;
+
+ prev_state = exception_enter();
+ die_if_kernel("do_msa_fpe invoked from kernel context!", regs);
+ force_sig(SIGFPE, current);
+ exception_exit(prev_state);
+}
+
+asmlinkage void do_msa(struct pt_regs *regs)
+{
+ enum ctx_state prev_state;
+ int err;
+
+ prev_state = exception_enter();
+
+ if (!cpu_has_msa || test_thread_flag(TIF_32BIT_FPREGS)) {
+ force_sig(SIGILL, current);
+ goto out;
+ }
+
+ die_if_kernel("do_msa invoked from kernel context!", regs);
+
+ err = enable_restore_fp_context(1);
+ if (err)
+ force_sig(SIGILL, current);
+out:
+ exception_exit(prev_state);
+}
+
asmlinkage void do_mdmx(struct pt_regs *regs)
{
enum ctx_state prev_state;
@@ -1337,8 +1451,10 @@ static inline void parity_protection_init(void)
case CPU_34K:
case CPU_74K:
case CPU_1004K:
+ case CPU_1074K:
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
+ case CPU_P5600:
{
#define ERRCTL_PE 0x80000000
#define ERRCTL_L2P 0x00800000
@@ -2017,6 +2133,7 @@ void __init trap_init(void)
set_except_vector(11, handle_cpu);
set_except_vector(12, handle_ov);
set_except_vector(13, handle_tr);
+ set_except_vector(14, handle_msa_fpe);
if (current_cpu_type() == CPU_R6000 ||
current_cpu_type() == CPU_R6000A) {
@@ -2040,6 +2157,7 @@ void __init trap_init(void)
set_except_vector(15, handle_fpe);
set_except_vector(16, handle_ftlb);
+ set_except_vector(21, handle_msa);
set_except_vector(22, handle_mdmx);
if (cpu_has_mcheck)
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index c369a5d35527..2b3517214d6d 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -7,6 +7,7 @@
*
* Copyright (C) 1996, 1998, 1999, 2002 by Ralf Baechle
* Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*
* This file contains exception handler for address error exception with the
* special capability to execute faulting instructions in software. The
@@ -110,8 +111,8 @@ extern void show_registers(struct pt_regs *regs);
#ifdef __BIG_ENDIAN
#define LoadHW(addr, value, res) \
__asm__ __volatile__ (".set\tnoat\n" \
- "1:\tlb\t%0, 0(%2)\n" \
- "2:\tlbu\t$1, 1(%2)\n\t" \
+ "1:\t"user_lb("%0", "0(%2)")"\n" \
+ "2:\t"user_lbu("$1", "1(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
@@ -130,8 +131,8 @@ extern void show_registers(struct pt_regs *regs);
#define LoadW(addr, value, res) \
__asm__ __volatile__ ( \
- "1:\tlwl\t%0, (%2)\n" \
- "2:\tlwr\t%0, 3(%2)\n\t" \
+ "1:\t"user_lwl("%0", "(%2)")"\n" \
+ "2:\t"user_lwr("%0", "3(%2)")"\n\t" \
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
@@ -149,8 +150,8 @@ extern void show_registers(struct pt_regs *regs);
#define LoadHWU(addr, value, res) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
- "1:\tlbu\t%0, 0(%2)\n" \
- "2:\tlbu\t$1, 1(%2)\n\t" \
+ "1:\t"user_lbu("%0", "0(%2)")"\n" \
+ "2:\t"user_lbu("$1", "1(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
@@ -170,8 +171,8 @@ extern void show_registers(struct pt_regs *regs);
#define LoadWU(addr, value, res) \
__asm__ __volatile__ ( \
- "1:\tlwl\t%0, (%2)\n" \
- "2:\tlwr\t%0, 3(%2)\n\t" \
+ "1:\t"user_lwl("%0", "(%2)")"\n" \
+ "2:\t"user_lwr("%0", "3(%2)")"\n\t" \
"dsll\t%0, %0, 32\n\t" \
"dsrl\t%0, %0, 32\n\t" \
"li\t%1, 0\n" \
@@ -209,9 +210,9 @@ extern void show_registers(struct pt_regs *regs);
#define StoreHW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
- "1:\tsb\t%1, 1(%2)\n\t" \
+ "1:\t"user_sb("%1", "1(%2)")"\n" \
"srl\t$1, %1, 0x8\n" \
- "2:\tsb\t$1, 0(%2)\n\t" \
+ "2:\t"user_sb("$1", "0(%2)")"\n" \
".set\tat\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
@@ -229,8 +230,8 @@ extern void show_registers(struct pt_regs *regs);
#define StoreW(addr, value, res) \
__asm__ __volatile__ ( \
- "1:\tswl\t%1,(%2)\n" \
- "2:\tswr\t%1, 3(%2)\n\t" \
+ "1:\t"user_swl("%1", "(%2)")"\n" \
+ "2:\t"user_swr("%1", "3(%2)")"\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
".insn\n\t" \
@@ -267,8 +268,8 @@ extern void show_registers(struct pt_regs *regs);
#ifdef __LITTLE_ENDIAN
#define LoadHW(addr, value, res) \
__asm__ __volatile__ (".set\tnoat\n" \
- "1:\tlb\t%0, 1(%2)\n" \
- "2:\tlbu\t$1, 0(%2)\n\t" \
+ "1:\t"user_lb("%0", "1(%2)")"\n" \
+ "2:\t"user_lbu("$1", "0(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
@@ -287,8 +288,8 @@ extern void show_registers(struct pt_regs *regs);
#define LoadW(addr, value, res) \
__asm__ __volatile__ ( \
- "1:\tlwl\t%0, 3(%2)\n" \
- "2:\tlwr\t%0, (%2)\n\t" \
+ "1:\t"user_lwl("%0", "3(%2)")"\n" \
+ "2:\t"user_lwr("%0", "(%2)")"\n\t" \
"li\t%1, 0\n" \
"3:\n\t" \
".insn\n\t" \
@@ -306,8 +307,8 @@ extern void show_registers(struct pt_regs *regs);
#define LoadHWU(addr, value, res) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
- "1:\tlbu\t%0, 1(%2)\n" \
- "2:\tlbu\t$1, 0(%2)\n\t" \
+ "1:\t"user_lbu("%0", "1(%2)")"\n" \
+ "2:\t"user_lbu("$1", "0(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
@@ -327,8 +328,8 @@ extern void show_registers(struct pt_regs *regs);
#define LoadWU(addr, value, res) \
__asm__ __volatile__ ( \
- "1:\tlwl\t%0, 3(%2)\n" \
- "2:\tlwr\t%0, (%2)\n\t" \
+ "1:\t"user_lwl("%0", "3(%2)")"\n" \
+ "2:\t"user_lwr("%0", "(%2)")"\n\t" \
"dsll\t%0, %0, 32\n\t" \
"dsrl\t%0, %0, 32\n\t" \
"li\t%1, 0\n" \
@@ -366,9 +367,9 @@ extern void show_registers(struct pt_regs *regs);
#define StoreHW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tnoat\n" \
- "1:\tsb\t%1, 0(%2)\n\t" \
+ "1:\t"user_sb("%1", "0(%2)")"\n" \
"srl\t$1,%1, 0x8\n" \
- "2:\tsb\t$1, 1(%2)\n\t" \
+ "2:\t"user_sb("$1", "1(%2)")"\n" \
".set\tat\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
@@ -386,8 +387,8 @@ extern void show_registers(struct pt_regs *regs);
#define StoreW(addr, value, res) \
__asm__ __volatile__ ( \
- "1:\tswl\t%1, 3(%2)\n" \
- "2:\tswr\t%1, (%2)\n\t" \
+ "1:\t"user_swl("%1", "3(%2)")"\n" \
+ "2:\t"user_swr("%1", "(%2)")"\n\t" \
"li\t%0, 0\n" \
"3:\n\t" \
".insn\n\t" \
@@ -430,7 +431,9 @@ static void emulate_load_store_insn(struct pt_regs *regs,
unsigned long origpc;
unsigned long orig31;
void __user *fault_addr = NULL;
-
+#ifdef CONFIG_EVA
+ mm_segment_t seg;
+#endif
origpc = (unsigned long)pc;
orig31 = regs->regs[31];
@@ -475,6 +478,88 @@ static void emulate_load_store_insn(struct pt_regs *regs,
* The remaining opcodes are the ones that are really of
* interest.
*/
+#ifdef CONFIG_EVA
+ case spec3_op:
+ /*
+ * we can land here only from kernel accessing user memory,
+ * so we need to "switch" the address limit to user space, so
+ * address check can work properly.
+ */
+ seg = get_fs();
+ set_fs(USER_DS);
+ switch (insn.spec3_format.func) {
+ case lhe_op:
+ if (!access_ok(VERIFY_READ, addr, 2)) {
+ set_fs(seg);
+ goto sigbus;
+ }
+ LoadHW(addr, value, res);
+ if (res) {
+ set_fs(seg);
+ goto fault;
+ }
+ compute_return_epc(regs);
+ regs->regs[insn.spec3_format.rt] = value;
+ break;
+ case lwe_op:
+ if (!access_ok(VERIFY_READ, addr, 4)) {
+ set_fs(seg);
+ goto sigbus;
+ }
+ LoadW(addr, value, res);
+ if (res) {
+ set_fs(seg);
+ goto fault;
+ }
+ compute_return_epc(regs);
+ regs->regs[insn.spec3_format.rt] = value;
+ break;
+ case lhue_op:
+ if (!access_ok(VERIFY_READ, addr, 2)) {
+ set_fs(seg);
+ goto sigbus;
+ }
+ LoadHWU(addr, value, res);
+ if (res) {
+ set_fs(seg);
+ goto fault;
+ }
+ compute_return_epc(regs);
+ regs->regs[insn.spec3_format.rt] = value;
+ break;
+ case she_op:
+ if (!access_ok(VERIFY_WRITE, addr, 2)) {
+ set_fs(seg);
+ goto sigbus;
+ }
+ compute_return_epc(regs);
+ value = regs->regs[insn.spec3_format.rt];
+ StoreHW(addr, value, res);
+ if (res) {
+ set_fs(seg);
+ goto fault;
+ }
+ break;
+ case swe_op:
+ if (!access_ok(VERIFY_WRITE, addr, 4)) {
+ set_fs(seg);
+ goto sigbus;
+ }
+ compute_return_epc(regs);
+ value = regs->regs[insn.spec3_format.rt];
+ StoreW(addr, value, res);
+ if (res) {
+ set_fs(seg);
+ goto fault;
+ }
+ break;
+ default:
+ set_fs(seg);
+ goto sigill;
+ }
+ set_fs(seg);
+ break;
+#endif
case lh_op:
if (!access_ok(VERIFY_READ, addr, 2))
goto sigbus;
diff --git a/arch/mips/kvm/kvm_mips_emul.c b/arch/mips/kvm/kvm_mips_emul.c
index 4b6274b47f33..e3fec99941a7 100644
--- a/arch/mips/kvm/kvm_mips_emul.c
+++ b/arch/mips/kvm/kvm_mips_emul.c
@@ -436,13 +436,6 @@ kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, uint32_t cause,
sel = inst & 0x7;
co_bit = (inst >> 25) & 1;
- /* Verify that the register is valid */
- if (rd > MIPS_CP0_DESAVE) {
- printk("Invalid rd: %d\n", rd);
- er = EMULATE_FAIL;
- goto done;
- }
-
if (co_bit) {
op = (inst) & 0xff;
@@ -1542,8 +1535,15 @@ kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
}
if ((inst & OPCODE) == SPEC3 && (inst & FUNC) == RDHWR) {
+ int usermode = !KVM_GUEST_KERNEL_MODE(vcpu);
int rd = (inst & RD) >> 11;
int rt = (inst & RT) >> 16;
+ /* If usermode, check RDHWR rd is allowed by guest HWREna */
+ if (usermode && !(kvm_read_c0_guest_hwrena(cop0) & BIT(rd))) {
+ kvm_debug("RDHWR %#x disallowed by HWREna @ %p\n",
+ rd, opc);
+ goto emulate_ri;
+ }
switch (rd) {
case 0: /* CPU number */
arch->gprs[rt] = 0;
@@ -1567,31 +1567,27 @@ kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
}
break;
case 29:
-#if 1
arch->gprs[rt] = kvm_read_c0_guest_userlocal(cop0);
-#else
- /* UserLocal not implemented */
- er = kvm_mips_emulate_ri_exc(cause, opc, run, vcpu);
-#endif
break;
default:
- printk("RDHWR not supported\n");
- er = EMULATE_FAIL;
- break;
+ kvm_debug("RDHWR %#x not supported @ %p\n", rd, opc);
+ goto emulate_ri;
}
} else {
- printk("Emulate RI not supported @ %p: %#x\n", opc, inst);
- er = EMULATE_FAIL;
+ kvm_debug("Emulate RI not supported @ %p: %#x\n", opc, inst);
+ goto emulate_ri;
}
+ return EMULATE_DONE;
+
+emulate_ri:
/*
- * Rollback PC only if emulation was unsuccessful
+ * Rollback PC (if in branch delay slot then the PC already points to
+ * branch target), and pass the RI exception to the guest OS.
*/
- if (er == EMULATE_FAIL) {
- vcpu->arch.pc = curr_pc;
- }
- return er;
+ vcpu->arch.pc = curr_pc;
+ return kvm_mips_emulate_ri_exc(cause, opc, run, vcpu);
}
enum emulation_result
diff --git a/arch/mips/lasat/picvue_proc.c b/arch/mips/lasat/picvue_proc.c
index 638c5db122c9..2bcd8391bc93 100644
--- a/arch/mips/lasat/picvue_proc.c
+++ b/arch/mips/lasat/picvue_proc.c
@@ -175,7 +175,7 @@ static void pvc_proc_cleanup(void)
remove_proc_entry("scroll", pvc_display_dir);
remove_proc_entry(DISPLAY_DIR_NAME, NULL);
- del_timer(&timer);
+ del_timer_sync(&timer);
}
static int __init pvc_proc_init(void)
diff --git a/arch/mips/lib/csum_partial.S b/arch/mips/lib/csum_partial.S
index a6adffbb4e5f..2e4825e48388 100644
--- a/arch/mips/lib/csum_partial.S
+++ b/arch/mips/lib/csum_partial.S
@@ -8,6 +8,7 @@
* Copyright (C) 1998, 1999 Ralf Baechle
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 2007 Maciej W. Rozycki
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*/
#include <linux/errno.h>
#include <asm/asm.h>
@@ -296,7 +297,7 @@ LEAF(csum_partial)
* checksum and copy routines based on memcpy.S
*
* csum_partial_copy_nocheck(src, dst, len, sum)
- * __csum_partial_copy_user(src, dst, len, sum, errp)
+ * __csum_partial_copy_kernel(src, dst, len, sum, errp)
*
* See "Spec" in memcpy.S for details. Unlike __copy_user, all
* function in this file use the standard calling convention.
@@ -327,20 +328,58 @@ LEAF(csum_partial)
* These handlers do not need to overwrite any data.
*/
-#define EXC(inst_reg,addr,handler) \
-9: inst_reg, addr; \
- .section __ex_table,"a"; \
- PTR 9b, handler; \
- .previous
+/* Instruction type */
+#define LD_INSN 1
+#define ST_INSN 2
+#define LEGACY_MODE 1
+#define EVA_MODE 2
+#define USEROP 1
+#define KERNELOP 2
+
+/*
+ * Wrapper to add an entry in the exception table
+ * in case the insn causes a memory exception.
+ * Arguments:
+ * insn : Load/store instruction
+ * type : Instruction type
+ * reg : Register
+ * addr : Address
+ * handler : Exception handler
+ */
+#define EXC(insn, type, reg, addr, handler) \
+ .if \mode == LEGACY_MODE; \
+9: insn reg, addr; \
+ .section __ex_table,"a"; \
+ PTR 9b, handler; \
+ .previous; \
+ /* This is enabled in EVA mode */ \
+ .else; \
+ /* If loading from user or storing to user */ \
+ .if ((\from == USEROP) && (type == LD_INSN)) || \
+ ((\to == USEROP) && (type == ST_INSN)); \
+9: __BUILD_EVA_INSN(insn##e, reg, addr); \
+ .section __ex_table,"a"; \
+ PTR 9b, handler; \
+ .previous; \
+ .else; \
+ /* EVA without exception */ \
+ insn reg, addr; \
+ .endif; \
+ .endif
+
+#undef LOAD
#ifdef USE_DOUBLE
-#define LOAD ld
-#define LOADL ldl
-#define LOADR ldr
-#define STOREL sdl
-#define STORER sdr
-#define STORE sd
+#define LOADK ld /* No exception */
+#define LOAD(reg, addr, handler) EXC(ld, LD_INSN, reg, addr, handler)
+#define LOADBU(reg, addr, handler) EXC(lbu, LD_INSN, reg, addr, handler)
+#define LOADL(reg, addr, handler) EXC(ldl, LD_INSN, reg, addr, handler)
+#define LOADR(reg, addr, handler) EXC(ldr, LD_INSN, reg, addr, handler)
+#define STOREB(reg, addr, handler) EXC(sb, ST_INSN, reg, addr, handler)
+#define STOREL(reg, addr, handler) EXC(sdl, ST_INSN, reg, addr, handler)
+#define STORER(reg, addr, handler) EXC(sdr, ST_INSN, reg, addr, handler)
+#define STORE(reg, addr, handler) EXC(sd, ST_INSN, reg, addr, handler)
#define ADD daddu
#define SUB dsubu
#define SRL dsrl
@@ -352,12 +391,15 @@ LEAF(csum_partial)
#else
-#define LOAD lw
-#define LOADL lwl
-#define LOADR lwr
-#define STOREL swl
-#define STORER swr
-#define STORE sw
+#define LOADK lw /* No exception */
+#define LOAD(reg, addr, handler) EXC(lw, LD_INSN, reg, addr, handler)
+#define LOADBU(reg, addr, handler) EXC(lbu, LD_INSN, reg, addr, handler)
+#define LOADL(reg, addr, handler) EXC(lwl, LD_INSN, reg, addr, handler)
+#define LOADR(reg, addr, handler) EXC(lwr, LD_INSN, reg, addr, handler)
+#define STOREB(reg, addr, handler) EXC(sb, ST_INSN, reg, addr, handler)
+#define STOREL(reg, addr, handler) EXC(swl, ST_INSN, reg, addr, handler)
+#define STORER(reg, addr, handler) EXC(swr, ST_INSN, reg, addr, handler)
+#define STORE(reg, addr, handler) EXC(sw, ST_INSN, reg, addr, handler)
#define ADD addu
#define SUB subu
#define SRL srl
@@ -396,14 +438,20 @@ LEAF(csum_partial)
.set at=v1
#endif
-LEAF(__csum_partial_copy_user)
+ .macro __BUILD_CSUM_PARTIAL_COPY_USER mode, from, to, __nocheck
+
PTR_ADDU AT, src, len /* See (1) above. */
+ /* initialize __nocheck if this the first time we execute this
+ * macro
+ */
#ifdef CONFIG_64BIT
move errptr, a4
#else
lw errptr, 16(sp)
#endif
-FEXPORT(csum_partial_copy_nocheck)
+ .if \__nocheck == 1
+ FEXPORT(csum_partial_copy_nocheck)
+ .endif
move sum, zero
move odd, zero
/*
@@ -419,48 +467,48 @@ FEXPORT(csum_partial_copy_nocheck)
*/
sltu t2, len, NBYTES
and t1, dst, ADDRMASK
- bnez t2, .Lcopy_bytes_checklen
+ bnez t2, .Lcopy_bytes_checklen\@
and t0, src, ADDRMASK
andi odd, dst, 0x1 /* odd buffer? */
- bnez t1, .Ldst_unaligned
+ bnez t1, .Ldst_unaligned\@
nop
- bnez t0, .Lsrc_unaligned_dst_aligned
+ bnez t0, .Lsrc_unaligned_dst_aligned\@
/*
* use delay slot for fall-through
* src and dst are aligned; need to compute rem
*/
-.Lboth_aligned:
+.Lboth_aligned\@:
SRL t0, len, LOG_NBYTES+3 # +3 for 8 units/iter
- beqz t0, .Lcleanup_both_aligned # len < 8*NBYTES
+ beqz t0, .Lcleanup_both_aligned\@ # len < 8*NBYTES
nop
SUB len, 8*NBYTES # subtract here for bgez loop
.align 4
1:
-EXC( LOAD t0, UNIT(0)(src), .Ll_exc)
-EXC( LOAD t1, UNIT(1)(src), .Ll_exc_copy)
-EXC( LOAD t2, UNIT(2)(src), .Ll_exc_copy)
-EXC( LOAD t3, UNIT(3)(src), .Ll_exc_copy)
-EXC( LOAD t4, UNIT(4)(src), .Ll_exc_copy)
-EXC( LOAD t5, UNIT(5)(src), .Ll_exc_copy)
-EXC( LOAD t6, UNIT(6)(src), .Ll_exc_copy)
-EXC( LOAD t7, UNIT(7)(src), .Ll_exc_copy)
+ LOAD(t0, UNIT(0)(src), .Ll_exc\@)
+ LOAD(t1, UNIT(1)(src), .Ll_exc_copy\@)
+ LOAD(t2, UNIT(2)(src), .Ll_exc_copy\@)
+ LOAD(t3, UNIT(3)(src), .Ll_exc_copy\@)
+ LOAD(t4, UNIT(4)(src), .Ll_exc_copy\@)
+ LOAD(t5, UNIT(5)(src), .Ll_exc_copy\@)
+ LOAD(t6, UNIT(6)(src), .Ll_exc_copy\@)
+ LOAD(t7, UNIT(7)(src), .Ll_exc_copy\@)
SUB len, len, 8*NBYTES
ADD src, src, 8*NBYTES
-EXC( STORE t0, UNIT(0)(dst), .Ls_exc)
+ STORE(t0, UNIT(0)(dst), .Ls_exc\@)
ADDC(sum, t0)
-EXC( STORE t1, UNIT(1)(dst), .Ls_exc)
+ STORE(t1, UNIT(1)(dst), .Ls_exc\@)
ADDC(sum, t1)
-EXC( STORE t2, UNIT(2)(dst), .Ls_exc)
+ STORE(t2, UNIT(2)(dst), .Ls_exc\@)
ADDC(sum, t2)
-EXC( STORE t3, UNIT(3)(dst), .Ls_exc)
+ STORE(t3, UNIT(3)(dst), .Ls_exc\@)
ADDC(sum, t3)
-EXC( STORE t4, UNIT(4)(dst), .Ls_exc)
+ STORE(t4, UNIT(4)(dst), .Ls_exc\@)
ADDC(sum, t4)
-EXC( STORE t5, UNIT(5)(dst), .Ls_exc)
+ STORE(t5, UNIT(5)(dst), .Ls_exc\@)
ADDC(sum, t5)
-EXC( STORE t6, UNIT(6)(dst), .Ls_exc)
+ STORE(t6, UNIT(6)(dst), .Ls_exc\@)
ADDC(sum, t6)
-EXC( STORE t7, UNIT(7)(dst), .Ls_exc)
+ STORE(t7, UNIT(7)(dst), .Ls_exc\@)
ADDC(sum, t7)
.set reorder /* DADDI_WAR */
ADD dst, dst, 8*NBYTES
@@ -471,44 +519,44 @@ EXC( STORE t7, UNIT(7)(dst), .Ls_exc)
/*
* len == the number of bytes left to copy < 8*NBYTES
*/
-.Lcleanup_both_aligned:
+.Lcleanup_both_aligned\@:
#define rem t7
- beqz len, .Ldone
+ beqz len, .Ldone\@
sltu t0, len, 4*NBYTES
- bnez t0, .Lless_than_4units
+ bnez t0, .Lless_than_4units\@
and rem, len, (NBYTES-1) # rem = len % NBYTES
/*
* len >= 4*NBYTES
*/
-EXC( LOAD t0, UNIT(0)(src), .Ll_exc)
-EXC( LOAD t1, UNIT(1)(src), .Ll_exc_copy)
-EXC( LOAD t2, UNIT(2)(src), .Ll_exc_copy)
-EXC( LOAD t3, UNIT(3)(src), .Ll_exc_copy)
+ LOAD(t0, UNIT(0)(src), .Ll_exc\@)
+ LOAD(t1, UNIT(1)(src), .Ll_exc_copy\@)
+ LOAD(t2, UNIT(2)(src), .Ll_exc_copy\@)
+ LOAD(t3, UNIT(3)(src), .Ll_exc_copy\@)
SUB len, len, 4*NBYTES
ADD src, src, 4*NBYTES
-EXC( STORE t0, UNIT(0)(dst), .Ls_exc)
+ STORE(t0, UNIT(0)(dst), .Ls_exc\@)
ADDC(sum, t0)
-EXC( STORE t1, UNIT(1)(dst), .Ls_exc)
+ STORE(t1, UNIT(1)(dst), .Ls_exc\@)
ADDC(sum, t1)
-EXC( STORE t2, UNIT(2)(dst), .Ls_exc)
+ STORE(t2, UNIT(2)(dst), .Ls_exc\@)
ADDC(sum, t2)
-EXC( STORE t3, UNIT(3)(dst), .Ls_exc)
+ STORE(t3, UNIT(3)(dst), .Ls_exc\@)
ADDC(sum, t3)
.set reorder /* DADDI_WAR */
ADD dst, dst, 4*NBYTES
- beqz len, .Ldone
+ beqz len, .Ldone\@
.set noreorder
-.Lless_than_4units:
+.Lless_than_4units\@:
/*
* rem = len % NBYTES
*/
- beq rem, len, .Lcopy_bytes
+ beq rem, len, .Lcopy_bytes\@
nop
1:
-EXC( LOAD t0, 0(src), .Ll_exc)
+ LOAD(t0, 0(src), .Ll_exc\@)
ADD src, src, NBYTES
SUB len, len, NBYTES
-EXC( STORE t0, 0(dst), .Ls_exc)
+ STORE(t0, 0(dst), .Ls_exc\@)
ADDC(sum, t0)
.set reorder /* DADDI_WAR */
ADD dst, dst, NBYTES
@@ -527,20 +575,20 @@ EXC( STORE t0, 0(dst), .Ls_exc)
* more instruction-level parallelism.
*/
#define bits t2
- beqz len, .Ldone
+ beqz len, .Ldone\@
ADD t1, dst, len # t1 is just past last byte of dst
li bits, 8*NBYTES
SLL rem, len, 3 # rem = number of bits to keep
-EXC( LOAD t0, 0(src), .Ll_exc)
+ LOAD(t0, 0(src), .Ll_exc\@)
SUB bits, bits, rem # bits = number of bits to discard
SHIFT_DISCARD t0, t0, bits
-EXC( STREST t0, -1(t1), .Ls_exc)
+ STREST(t0, -1(t1), .Ls_exc\@)
SHIFT_DISCARD_REVERT t0, t0, bits
.set reorder
ADDC(sum, t0)
- b .Ldone
+ b .Ldone\@
.set noreorder
-.Ldst_unaligned:
+.Ldst_unaligned\@:
/*
* dst is unaligned
* t0 = src & ADDRMASK
@@ -551,25 +599,25 @@ EXC( STREST t0, -1(t1), .Ls_exc)
* Set match = (src and dst have same alignment)
*/
#define match rem
-EXC( LDFIRST t3, FIRST(0)(src), .Ll_exc)
+ LDFIRST(t3, FIRST(0)(src), .Ll_exc\@)
ADD t2, zero, NBYTES
-EXC( LDREST t3, REST(0)(src), .Ll_exc_copy)
+ LDREST(t3, REST(0)(src), .Ll_exc_copy\@)
SUB t2, t2, t1 # t2 = number of bytes copied
xor match, t0, t1
-EXC( STFIRST t3, FIRST(0)(dst), .Ls_exc)
+ STFIRST(t3, FIRST(0)(dst), .Ls_exc\@)
SLL t4, t1, 3 # t4 = number of bits to discard
SHIFT_DISCARD t3, t3, t4
/* no SHIFT_DISCARD_REVERT to handle odd buffer properly */
ADDC(sum, t3)
- beq len, t2, .Ldone
+ beq len, t2, .Ldone\@
SUB len, len, t2
ADD dst, dst, t2
- beqz match, .Lboth_aligned
+ beqz match, .Lboth_aligned\@
ADD src, src, t2
-.Lsrc_unaligned_dst_aligned:
+.Lsrc_unaligned_dst_aligned\@:
SRL t0, len, LOG_NBYTES+2 # +2 for 4 units/iter
- beqz t0, .Lcleanup_src_unaligned
+ beqz t0, .Lcleanup_src_unaligned\@
and rem, len, (4*NBYTES-1) # rem = len % 4*NBYTES
1:
/*
@@ -578,53 +626,53 @@ EXC( STFIRST t3, FIRST(0)(dst), .Ls_exc)
* It's OK to load FIRST(N+1) before REST(N) because the two addresses
* are to the same unit (unless src is aligned, but it's not).
*/
-EXC( LDFIRST t0, FIRST(0)(src), .Ll_exc)
-EXC( LDFIRST t1, FIRST(1)(src), .Ll_exc_copy)
+ LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
+ LDFIRST(t1, FIRST(1)(src), .Ll_exc_copy\@)
SUB len, len, 4*NBYTES
-EXC( LDREST t0, REST(0)(src), .Ll_exc_copy)
-EXC( LDREST t1, REST(1)(src), .Ll_exc_copy)
-EXC( LDFIRST t2, FIRST(2)(src), .Ll_exc_copy)
-EXC( LDFIRST t3, FIRST(3)(src), .Ll_exc_copy)
-EXC( LDREST t2, REST(2)(src), .Ll_exc_copy)
-EXC( LDREST t3, REST(3)(src), .Ll_exc_copy)
+ LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
+ LDREST(t1, REST(1)(src), .Ll_exc_copy\@)
+ LDFIRST(t2, FIRST(2)(src), .Ll_exc_copy\@)
+ LDFIRST(t3, FIRST(3)(src), .Ll_exc_copy\@)
+ LDREST(t2, REST(2)(src), .Ll_exc_copy\@)
+ LDREST(t3, REST(3)(src), .Ll_exc_copy\@)
ADD src, src, 4*NBYTES
#ifdef CONFIG_CPU_SB1
nop # improves slotting
#endif
-EXC( STORE t0, UNIT(0)(dst), .Ls_exc)
+ STORE(t0, UNIT(0)(dst), .Ls_exc\@)
ADDC(sum, t0)
-EXC( STORE t1, UNIT(1)(dst), .Ls_exc)
+ STORE(t1, UNIT(1)(dst), .Ls_exc\@)
ADDC(sum, t1)
-EXC( STORE t2, UNIT(2)(dst), .Ls_exc)
+ STORE(t2, UNIT(2)(dst), .Ls_exc\@)
ADDC(sum, t2)
-EXC( STORE t3, UNIT(3)(dst), .Ls_exc)
+ STORE(t3, UNIT(3)(dst), .Ls_exc\@)
ADDC(sum, t3)
.set reorder /* DADDI_WAR */
ADD dst, dst, 4*NBYTES
bne len, rem, 1b
.set noreorder
-.Lcleanup_src_unaligned:
- beqz len, .Ldone
+.Lcleanup_src_unaligned\@:
+ beqz len, .Ldone\@
and rem, len, NBYTES-1 # rem = len % NBYTES
- beq rem, len, .Lcopy_bytes
+ beq rem, len, .Lcopy_bytes\@
nop
1:
-EXC( LDFIRST t0, FIRST(0)(src), .Ll_exc)
-EXC( LDREST t0, REST(0)(src), .Ll_exc_copy)
+ LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
+ LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
ADD src, src, NBYTES
SUB len, len, NBYTES
-EXC( STORE t0, 0(dst), .Ls_exc)
+ STORE(t0, 0(dst), .Ls_exc\@)
ADDC(sum, t0)
.set reorder /* DADDI_WAR */
ADD dst, dst, NBYTES
bne len, rem, 1b
.set noreorder
-.Lcopy_bytes_checklen:
- beqz len, .Ldone
+.Lcopy_bytes_checklen\@:
+ beqz len, .Ldone\@
nop
-.Lcopy_bytes:
+.Lcopy_bytes\@:
/* 0 < len < NBYTES */
#ifdef CONFIG_CPU_LITTLE_ENDIAN
#define SHIFT_START 0
@@ -637,12 +685,12 @@ EXC( STORE t0, 0(dst), .Ls_exc)
li t3, SHIFT_START # shift
/* use .Ll_exc_copy here to return correct sum on fault */
#define COPY_BYTE(N) \
-EXC( lbu t0, N(src), .Ll_exc_copy); \
+ LOADBU(t0, N(src), .Ll_exc_copy\@); \
SUB len, len, 1; \
-EXC( sb t0, N(dst), .Ls_exc); \
+ STOREB(t0, N(dst), .Ls_exc\@); \
SLLV t0, t0, t3; \
addu t3, SHIFT_INC; \
- beqz len, .Lcopy_bytes_done; \
+ beqz len, .Lcopy_bytes_done\@; \
or t2, t0
COPY_BYTE(0)
@@ -653,14 +701,14 @@ EXC( sb t0, N(dst), .Ls_exc); \
COPY_BYTE(4)
COPY_BYTE(5)
#endif
-EXC( lbu t0, NBYTES-2(src), .Ll_exc_copy)
+ LOADBU(t0, NBYTES-2(src), .Ll_exc_copy\@)
SUB len, len, 1
-EXC( sb t0, NBYTES-2(dst), .Ls_exc)
+ STOREB(t0, NBYTES-2(dst), .Ls_exc\@)
SLLV t0, t0, t3
or t2, t0
-.Lcopy_bytes_done:
+.Lcopy_bytes_done\@:
ADDC(sum, t2)
-.Ldone:
+.Ldone\@:
/* fold checksum */
#ifdef USE_DOUBLE
dsll32 v1, sum, 0
@@ -689,7 +737,7 @@ EXC( sb t0, NBYTES-2(dst), .Ls_exc)
jr ra
.set noreorder
-.Ll_exc_copy:
+.Ll_exc_copy\@:
/*
* Copy bytes from src until faulting load address (or until a
* lb faults)
@@ -700,11 +748,11 @@ EXC( sb t0, NBYTES-2(dst), .Ls_exc)
*
* Assumes src < THREAD_BUADDR($28)
*/
- LOAD t0, TI_TASK($28)
+ LOADK t0, TI_TASK($28)
li t2, SHIFT_START
- LOAD t0, THREAD_BUADDR(t0)
+ LOADK t0, THREAD_BUADDR(t0)
1:
-EXC( lbu t1, 0(src), .Ll_exc)
+ LOADBU(t1, 0(src), .Ll_exc\@)
ADD src, src, 1
sb t1, 0(dst) # can't fault -- we're copy_from_user
SLLV t1, t1, t2
@@ -714,10 +762,10 @@ EXC( lbu t1, 0(src), .Ll_exc)
ADD dst, dst, 1
bne src, t0, 1b
.set noreorder
-.Ll_exc:
- LOAD t0, TI_TASK($28)
+.Ll_exc\@:
+ LOADK t0, TI_TASK($28)
nop
- LOAD t0, THREAD_BUADDR(t0) # t0 is just past last good address
+ LOADK t0, THREAD_BUADDR(t0) # t0 is just past last good address
nop
SUB len, AT, t0 # len number of uncopied bytes
/*
@@ -733,7 +781,7 @@ EXC( lbu t1, 0(src), .Ll_exc)
*/
.set reorder /* DADDI_WAR */
SUB src, len, 1
- beqz len, .Ldone
+ beqz len, .Ldone\@
.set noreorder
1: sb zero, 0(dst)
ADD dst, dst, 1
@@ -748,13 +796,31 @@ EXC( lbu t1, 0(src), .Ll_exc)
SUB src, src, v1
#endif
li v1, -EFAULT
- b .Ldone
+ b .Ldone\@
sw v1, (errptr)
-.Ls_exc:
+.Ls_exc\@:
li v0, -1 /* invalid checksum */
li v1, -EFAULT
jr ra
sw v1, (errptr)
.set pop
- END(__csum_partial_copy_user)
+ .endm
+
+LEAF(__csum_partial_copy_kernel)
+#ifndef CONFIG_EVA
+FEXPORT(__csum_partial_copy_to_user)
+FEXPORT(__csum_partial_copy_from_user)
+#endif
+__BUILD_CSUM_PARTIAL_COPY_USER LEGACY_MODE USEROP USEROP 1
+END(__csum_partial_copy_kernel)
+
+#ifdef CONFIG_EVA
+LEAF(__csum_partial_copy_to_user)
+__BUILD_CSUM_PARTIAL_COPY_USER EVA_MODE KERNELOP USEROP 0
+END(__csum_partial_copy_to_user)
+
+LEAF(__csum_partial_copy_from_user)
+__BUILD_CSUM_PARTIAL_COPY_USER EVA_MODE USEROP KERNELOP 0
+END(__csum_partial_copy_from_user)
+#endif
diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S
index c5c40dad0bbf..c17ef80cf65a 100644
--- a/arch/mips/lib/memcpy.S
+++ b/arch/mips/lib/memcpy.S
@@ -10,6 +10,7 @@
* Copyright (C) 2002 Broadcom, Inc.
* memcpy/copy_user author: Mark Vandevoorde
* Copyright (C) 2007 Maciej W. Rozycki
+ * Copyright (C) 2014 Imagination Technologies Ltd.
*
* Mnemonic names for arguments to memcpy/__copy_user
*/
@@ -85,11 +86,51 @@
* they're not protected.
*/
-#define EXC(inst_reg,addr,handler) \
-9: inst_reg, addr; \
- .section __ex_table,"a"; \
- PTR 9b, handler; \
- .previous
+/* Instruction type */
+#define LD_INSN 1
+#define ST_INSN 2
+/* Pretech type */
+#define SRC_PREFETCH 1
+#define DST_PREFETCH 2
+#define LEGACY_MODE 1
+#define EVA_MODE 2
+#define USEROP 1
+#define KERNELOP 2
+
+/*
+ * Wrapper to add an entry in the exception table
+ * in case the insn causes a memory exception.
+ * Arguments:
+ * insn : Load/store instruction
+ * type : Instruction type
+ * reg : Register
+ * addr : Address
+ * handler : Exception handler
+ */
+
+#define EXC(insn, type, reg, addr, handler) \
+ .if \mode == LEGACY_MODE; \
+9: insn reg, addr; \
+ .section __ex_table,"a"; \
+ PTR 9b, handler; \
+ .previous; \
+ /* This is assembled in EVA mode */ \
+ .else; \
+ /* If loading from user or storing to user */ \
+ .if ((\from == USEROP) && (type == LD_INSN)) || \
+ ((\to == USEROP) && (type == ST_INSN)); \
+9: __BUILD_EVA_INSN(insn##e, reg, addr); \
+ .section __ex_table,"a"; \
+ PTR 9b, handler; \
+ .previous; \
+ .else; \
+ /* \
+ * Still in EVA, but no need for \
+ * exception handler or EVA insn \
+ */ \
+ insn reg, addr; \
+ .endif; \
+ .endif
/*
* Only on the 64-bit kernel we can made use of 64-bit registers.
@@ -100,12 +141,13 @@
#ifdef USE_DOUBLE
-#define LOAD ld
-#define LOADL ldl
-#define LOADR ldr
-#define STOREL sdl
-#define STORER sdr
-#define STORE sd
+#define LOADK ld /* No exception */
+#define LOAD(reg, addr, handler) EXC(ld, LD_INSN, reg, addr, handler)
+#define LOADL(reg, addr, handler) EXC(ldl, LD_INSN, reg, addr, handler)
+#define LOADR(reg, addr, handler) EXC(ldr, LD_INSN, reg, addr, handler)
+#define STOREL(reg, addr, handler) EXC(sdl, ST_INSN, reg, addr, handler)
+#define STORER(reg, addr, handler) EXC(sdr, ST_INSN, reg, addr, handler)
+#define STORE(reg, addr, handler) EXC(sd, ST_INSN, reg, addr, handler)
#define ADD daddu
#define SUB dsubu
#define SRL dsrl
@@ -136,12 +178,13 @@
#else
-#define LOAD lw
-#define LOADL lwl
-#define LOADR lwr
-#define STOREL swl
-#define STORER swr
-#define STORE sw
+#define LOADK lw /* No exception */
+#define LOAD(reg, addr, handler) EXC(lw, LD_INSN, reg, addr, handler)
+#define LOADL(reg, addr, handler) EXC(lwl, LD_INSN, reg, addr, handler)
+#define LOADR(reg, addr, handler) EXC(lwr, LD_INSN, reg, addr, handler)
+#define STOREL(reg, addr, handler) EXC(swl, ST_INSN, reg, addr, handler)
+#define STORER(reg, addr, handler) EXC(swr, ST_INSN, reg, addr, handler)
+#define STORE(reg, addr, handler) EXC(sw, ST_INSN, reg, addr, handler)
#define ADD addu
#define SUB subu
#define SRL srl
@@ -154,6 +197,33 @@
#endif /* USE_DOUBLE */
+#define LOADB(reg, addr, handler) EXC(lb, LD_INSN, reg, addr, handler)
+#define STOREB(reg, addr, handler) EXC(sb, ST_INSN, reg, addr, handler)
+
+#define _PREF(hint, addr, type) \
+ .if \mode == LEGACY_MODE; \
+ PREF(hint, addr); \
+ .else; \
+ .if ((\from == USEROP) && (type == SRC_PREFETCH)) || \
+ ((\to == USEROP) && (type == DST_PREFETCH)); \
+ /* \
+ * PREFE has only 9 bits for the offset \
+ * compared to PREF which has 16, so it may \
+ * need to use the $at register but this \
+ * register should remain intact because it's \
+ * used later on. Therefore use $v1. \
+ */ \
+ .set at=v1; \
+ PREFE(hint, addr); \
+ .set noat; \
+ .else; \
+ PREF(hint, addr); \
+ .endif; \
+ .endif
+
+#define PREFS(hint, addr) _PREF(hint, addr, SRC_PREFETCH)
+#define PREFD(hint, addr) _PREF(hint, addr, DST_PREFETCH)
+
#ifdef CONFIG_CPU_LITTLE_ENDIAN
#define LDFIRST LOADR
#define LDREST LOADL
@@ -182,27 +252,23 @@
.set at=v1
#endif
-/*
- * t6 is used as a flag to note inatomic mode.
- */
-LEAF(__copy_user_inatomic)
- b __copy_user_common
- li t6, 1
- END(__copy_user_inatomic)
-
-/*
- * A combined memcpy/__copy_user
- * __copy_user sets len to 0 for success; else to an upper bound of
- * the number of uncopied bytes.
- * memcpy sets v0 to dst.
- */
.align 5
-LEAF(memcpy) /* a0=dst a1=src a2=len */
- move v0, dst /* return value */
-.L__memcpy:
-FEXPORT(__copy_user)
- li t6, 0 /* not inatomic */
-__copy_user_common:
+
+ /*
+ * Macro to build the __copy_user common code
+ * Arguements:
+ * mode : LEGACY_MODE or EVA_MODE
+ * from : Source operand. USEROP or KERNELOP
+ * to : Destination operand. USEROP or KERNELOP
+ */
+ .macro __BUILD_COPY_USER mode, from, to
+
+ /* initialize __memcpy if this the first time we execute this macro */
+ .ifnotdef __memcpy
+ .set __memcpy, 1
+ .hidden __memcpy /* make sure it does not leak */
+ .endif
+
/*
* Note: dst & src may be unaligned, len may be 0
* Temps
@@ -217,94 +283,94 @@ __copy_user_common:
*
* If len < NBYTES use byte operations.
*/
- PREF( 0, 0(src) )
- PREF( 1, 0(dst) )
+ PREFS( 0, 0(src) )
+ PREFD( 1, 0(dst) )
sltu t2, len, NBYTES
and t1, dst, ADDRMASK
- PREF( 0, 1*32(src) )
- PREF( 1, 1*32(dst) )
- bnez t2, .Lcopy_bytes_checklen
+ PREFS( 0, 1*32(src) )
+ PREFD( 1, 1*32(dst) )
+ bnez t2, .Lcopy_bytes_checklen\@
and t0, src, ADDRMASK
- PREF( 0, 2*32(src) )
- PREF( 1, 2*32(dst) )
- bnez t1, .Ldst_unaligned
+ PREFS( 0, 2*32(src) )
+ PREFD( 1, 2*32(dst) )
+ bnez t1, .Ldst_unaligned\@
nop
- bnez t0, .Lsrc_unaligned_dst_aligned
+ bnez t0, .Lsrc_unaligned_dst_aligned\@
/*
* use delay slot for fall-through
* src and dst are aligned; need to compute rem
*/
-.Lboth_aligned:
+.Lboth_aligned\@:
SRL t0, len, LOG_NBYTES+3 # +3 for 8 units/iter
- beqz t0, .Lcleanup_both_aligned # len < 8*NBYTES
+ beqz t0, .Lcleanup_both_aligned\@ # len < 8*NBYTES
and rem, len, (8*NBYTES-1) # rem = len % (8*NBYTES)
- PREF( 0, 3*32(src) )
- PREF( 1, 3*32(dst) )
+ PREFS( 0, 3*32(src) )
+ PREFD( 1, 3*32(dst) )
.align 4
1:
R10KCBARRIER(0(ra))
-EXC( LOAD t0, UNIT(0)(src), .Ll_exc)
-EXC( LOAD t1, UNIT(1)(src), .Ll_exc_copy)
-EXC( LOAD t2, UNIT(2)(src), .Ll_exc_copy)
-EXC( LOAD t3, UNIT(3)(src), .Ll_exc_copy)
+ LOAD(t0, UNIT(0)(src), .Ll_exc\@)
+ LOAD(t1, UNIT(1)(src), .Ll_exc_copy\@)
+ LOAD(t2, UNIT(2)(src), .Ll_exc_copy\@)
+ LOAD(t3, UNIT(3)(src), .Ll_exc_copy\@)
SUB len, len, 8*NBYTES
-EXC( LOAD t4, UNIT(4)(src), .Ll_exc_copy)
-EXC( LOAD t7, UNIT(5)(src), .Ll_exc_copy)
-EXC( STORE t0, UNIT(0)(dst), .Ls_exc_p8u)
-EXC( STORE t1, UNIT(1)(dst), .Ls_exc_p7u)
-EXC( LOAD t0, UNIT(6)(src), .Ll_exc_copy)
-EXC( LOAD t1, UNIT(7)(src), .Ll_exc_copy)
+ LOAD(t4, UNIT(4)(src), .Ll_exc_copy\@)
+ LOAD(t7, UNIT(5)(src), .Ll_exc_copy\@)
+ STORE(t0, UNIT(0)(dst), .Ls_exc_p8u\@)
+ STORE(t1, UNIT(1)(dst), .Ls_exc_p7u\@)
+ LOAD(t0, UNIT(6)(src), .Ll_exc_copy\@)
+ LOAD(t1, UNIT(7)(src), .Ll_exc_copy\@)
ADD src, src, 8*NBYTES
ADD dst, dst, 8*NBYTES
-EXC( STORE t2, UNIT(-6)(dst), .Ls_exc_p6u)
-EXC( STORE t3, UNIT(-5)(dst), .Ls_exc_p5u)
-EXC( STORE t4, UNIT(-4)(dst), .Ls_exc_p4u)
-EXC( STORE t7, UNIT(-3)(dst), .Ls_exc_p3u)
-EXC( STORE t0, UNIT(-2)(dst), .Ls_exc_p2u)
-EXC( STORE t1, UNIT(-1)(dst), .Ls_exc_p1u)
- PREF( 0, 8*32(src) )
- PREF( 1, 8*32(dst) )
+ STORE(t2, UNIT(-6)(dst), .Ls_exc_p6u\@)
+ STORE(t3, UNIT(-5)(dst), .Ls_exc_p5u\@)
+ STORE(t4, UNIT(-4)(dst), .Ls_exc_p4u\@)
+ STORE(t7, UNIT(-3)(dst), .Ls_exc_p3u\@)
+ STORE(t0, UNIT(-2)(dst), .Ls_exc_p2u\@)
+ STORE(t1, UNIT(-1)(dst), .Ls_exc_p1u\@)
+ PREFS( 0, 8*32(src) )
+ PREFD( 1, 8*32(dst) )
bne len, rem, 1b
nop
/*
* len == rem == the number of bytes left to copy < 8*NBYTES
*/
-.Lcleanup_both_aligned:
- beqz len, .Ldone
+.Lcleanup_both_aligned\@:
+ beqz len, .Ldone\@
sltu t0, len, 4*NBYTES
- bnez t0, .Lless_than_4units
+ bnez t0, .Lless_than_4units\@
and rem, len, (NBYTES-1) # rem = len % NBYTES
/*
* len >= 4*NBYTES
*/
-EXC( LOAD t0, UNIT(0)(src), .Ll_exc)
-EXC( LOAD t1, UNIT(1)(src), .Ll_exc_copy)
-EXC( LOAD t2, UNIT(2)(src), .Ll_exc_copy)
-EXC( LOAD t3, UNIT(3)(src), .Ll_exc_copy)
+ LOAD( t0, UNIT(0)(src), .Ll_exc\@)
+ LOAD( t1, UNIT(1)(src), .Ll_exc_copy\@)
+ LOAD( t2, UNIT(2)(src), .Ll_exc_copy\@)
+ LOAD( t3, UNIT(3)(src), .Ll_exc_copy\@)
SUB len, len, 4*NBYTES
ADD src, src, 4*NBYTES
R10KCBARRIER(0(ra))
-EXC( STORE t0, UNIT(0)(dst), .Ls_exc_p4u)
-EXC( STORE t1, UNIT(1)(dst), .Ls_exc_p3u)
-EXC( STORE t2, UNIT(2)(dst), .Ls_exc_p2u)
-EXC( STORE t3, UNIT(3)(dst), .Ls_exc_p1u)
+ STORE(t0, UNIT(0)(dst), .Ls_exc_p4u\@)
+ STORE(t1, UNIT(1)(dst), .Ls_exc_p3u\@)
+ STORE(t2, UNIT(2)(dst), .Ls_exc_p2u\@)
+ STORE(t3, UNIT(3)(dst), .Ls_exc_p1u\@)
.set reorder /* DADDI_WAR */
ADD dst, dst, 4*NBYTES
- beqz len, .Ldone
+ beqz len, .Ldone\@
.set noreorder
-.Lless_than_4units:
+.Lless_than_4units\@:
/*
* rem = len % NBYTES
*/
- beq rem, len, .Lcopy_bytes
+ beq rem, len, .Lcopy_bytes\@
nop
1:
R10KCBARRIER(0(ra))
-EXC( LOAD t0, 0(src), .Ll_exc)
+ LOAD(t0, 0(src), .Ll_exc\@)
ADD src, src, NBYTES
SUB len, len, NBYTES
-EXC( STORE t0, 0(dst), .Ls_exc_p1u)
+ STORE(t0, 0(dst), .Ls_exc_p1u\@)
.set reorder /* DADDI_WAR */
ADD dst, dst, NBYTES
bne rem, len, 1b
@@ -322,17 +388,17 @@ EXC( STORE t0, 0(dst), .Ls_exc_p1u)
* more instruction-level parallelism.
*/
#define bits t2
- beqz len, .Ldone
+ beqz len, .Ldone\@
ADD t1, dst, len # t1 is just past last byte of dst
li bits, 8*NBYTES
SLL rem, len, 3 # rem = number of bits to keep
-EXC( LOAD t0, 0(src), .Ll_exc)
+ LOAD(t0, 0(src), .Ll_exc\@)
SUB bits, bits, rem # bits = number of bits to discard
SHIFT_DISCARD t0, t0, bits
-EXC( STREST t0, -1(t1), .Ls_exc)
+ STREST(t0, -1(t1), .Ls_exc\@)
jr ra
move len, zero
-.Ldst_unaligned:
+.Ldst_unaligned\@:
/*
* dst is unaligned
* t0 = src & ADDRMASK
@@ -343,25 +409,25 @@ EXC( STREST t0, -1(t1), .Ls_exc)
* Set match = (src and dst have same alignment)
*/
#define match rem
-EXC( LDFIRST t3, FIRST(0)(src), .Ll_exc)
+ LDFIRST(t3, FIRST(0)(src), .Ll_exc\@)
ADD t2, zero, NBYTES
-EXC( LDREST t3, REST(0)(src), .Ll_exc_copy)
+ LDREST(t3, REST(0)(src), .Ll_exc_copy\@)
SUB t2, t2, t1 # t2 = number of bytes copied
xor match, t0, t1
R10KCBARRIER(0(ra))
-EXC( STFIRST t3, FIRST(0)(dst), .Ls_exc)
- beq len, t2, .Ldone
+ STFIRST(t3, FIRST(0)(dst), .Ls_exc\@)
+ beq len, t2, .Ldone\@
SUB len, len, t2
ADD dst, dst, t2
- beqz match, .Lboth_aligned
+ beqz match, .Lboth_aligned\@
ADD src, src, t2
-.Lsrc_unaligned_dst_aligned:
+.Lsrc_unaligned_dst_aligned\@:
SRL t0, len, LOG_NBYTES+2 # +2 for 4 units/iter
- PREF( 0, 3*32(src) )
- beqz t0, .Lcleanup_src_unaligned
+ PREFS( 0, 3*32(src) )
+ beqz t0, .Lcleanup_src_unaligned\@
and rem, len, (4*NBYTES-1) # rem = len % 4*NBYTES
- PREF( 1, 3*32(dst) )
+ PREFD( 1, 3*32(dst) )
1:
/*
* Avoid consecutive LD*'s to the same register since some mips
@@ -370,58 +436,58 @@ EXC( STFIRST t3, FIRST(0)(dst), .Ls_exc)
* are to the same unit (unless src is aligned, but it's not).
*/
R10KCBARRIER(0(ra))
-EXC( LDFIRST t0, FIRST(0)(src), .Ll_exc)
-EXC( LDFIRST t1, FIRST(1)(src), .Ll_exc_copy)
+ LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
+ LDFIRST(t1, FIRST(1)(src), .Ll_exc_copy\@)
SUB len, len, 4*NBYTES
-EXC( LDREST t0, REST(0)(src), .Ll_exc_copy)
-EXC( LDREST t1, REST(1)(src), .Ll_exc_copy)
-EXC( LDFIRST t2, FIRST(2)(src), .Ll_exc_copy)
-EXC( LDFIRST t3, FIRST(3)(src), .Ll_exc_copy)
-EXC( LDREST t2, REST(2)(src), .Ll_exc_copy)
-EXC( LDREST t3, REST(3)(src), .Ll_exc_copy)
- PREF( 0, 9*32(src) ) # 0 is PREF_LOAD (not streamed)
+ LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
+ LDREST(t1, REST(1)(src), .Ll_exc_copy\@)
+ LDFIRST(t2, FIRST(2)(src), .Ll_exc_copy\@)
+ LDFIRST(t3, FIRST(3)(src), .Ll_exc_copy\@)
+ LDREST(t2, REST(2)(src), .Ll_exc_copy\@)
+ LDREST(t3, REST(3)(src), .Ll_exc_copy\@)
+ PREFS( 0, 9*32(src) ) # 0 is PREF_LOAD (not streamed)
ADD src, src, 4*NBYTES
#ifdef CONFIG_CPU_SB1
nop # improves slotting
#endif
-EXC( STORE t0, UNIT(0)(dst), .Ls_exc_p4u)
-EXC( STORE t1, UNIT(1)(dst), .Ls_exc_p3u)
-EXC( STORE t2, UNIT(2)(dst), .Ls_exc_p2u)
-EXC( STORE t3, UNIT(3)(dst), .Ls_exc_p1u)
- PREF( 1, 9*32(dst) ) # 1 is PREF_STORE (not streamed)
+ STORE(t0, UNIT(0)(dst), .Ls_exc_p4u\@)
+ STORE(t1, UNIT(1)(dst), .Ls_exc_p3u\@)
+ STORE(t2, UNIT(2)(dst), .Ls_exc_p2u\@)
+ STORE(t3, UNIT(3)(dst), .Ls_exc_p1u\@)
+ PREFD( 1, 9*32(dst) ) # 1 is PREF_STORE (not streamed)
.set reorder /* DADDI_WAR */
ADD dst, dst, 4*NBYTES
bne len, rem, 1b
.set noreorder
-.Lcleanup_src_unaligned:
- beqz len, .Ldone
+.Lcleanup_src_unaligned\@:
+ beqz len, .Ldone\@
and rem, len, NBYTES-1 # rem = len % NBYTES
- beq rem, len, .Lcopy_bytes
+ beq rem, len, .Lcopy_bytes\@
nop
1:
R10KCBARRIER(0(ra))
-EXC( LDFIRST t0, FIRST(0)(src), .Ll_exc)
-EXC( LDREST t0, REST(0)(src), .Ll_exc_copy)
+ LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
+ LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
ADD src, src, NBYTES
SUB len, len, NBYTES
-EXC( STORE t0, 0(dst), .Ls_exc_p1u)
+ STORE(t0, 0(dst), .Ls_exc_p1u\@)
.set reorder /* DADDI_WAR */
ADD dst, dst, NBYTES
bne len, rem, 1b
.set noreorder
-.Lcopy_bytes_checklen:
- beqz len, .Ldone
+.Lcopy_bytes_checklen\@:
+ beqz len, .Ldone\@
nop
-.Lcopy_bytes:
+.Lcopy_bytes\@:
/* 0 < len < NBYTES */
R10KCBARRIER(0(ra))
#define COPY_BYTE(N) \
-EXC( lb t0, N(src), .Ll_exc); \
+ LOADB(t0, N(src), .Ll_exc\@); \
SUB len, len, 1; \
- beqz len, .Ldone; \
-EXC( sb t0, N(dst), .Ls_exc_p1)
+ beqz len, .Ldone\@; \
+ STOREB(t0, N(dst), .Ls_exc_p1\@)
COPY_BYTE(0)
COPY_BYTE(1)
@@ -431,16 +497,19 @@ EXC( sb t0, N(dst), .Ls_exc_p1)
COPY_BYTE(4)
COPY_BYTE(5)
#endif
-EXC( lb t0, NBYTES-2(src), .Ll_exc)
+ LOADB(t0, NBYTES-2(src), .Ll_exc\@)
SUB len, len, 1
jr ra
-EXC( sb t0, NBYTES-2(dst), .Ls_exc_p1)
-.Ldone:
+ STOREB(t0, NBYTES-2(dst), .Ls_exc_p1\@)
+.Ldone\@:
jr ra
- nop
+ .if __memcpy == 1
END(memcpy)
+ .set __memcpy, 0
+ .hidden __memcpy
+ .endif
-.Ll_exc_copy:
+.Ll_exc_copy\@:
/*
* Copy bytes from src until faulting load address (or until a
* lb faults)
@@ -451,24 +520,24 @@ EXC( sb t0, NBYTES-2(dst), .Ls_exc_p1)
*
* Assumes src < THREAD_BUADDR($28)
*/
- LOAD t0, TI_TASK($28)
+ LOADK t0, TI_TASK($28)
nop
- LOAD t0, THREAD_BUADDR(t0)
+ LOADK t0, THREAD_BUADDR(t0)
1:
-EXC( lb t1, 0(src), .Ll_exc)
+ LOADB(t1, 0(src), .Ll_exc\@)
ADD src, src, 1
sb t1, 0(dst) # can't fault -- we're copy_from_user
.set reorder /* DADDI_WAR */
ADD dst, dst, 1
bne src, t0, 1b
.set noreorder
-.Ll_exc:
- LOAD t0, TI_TASK($28)
+.Ll_exc\@:
+ LOADK t0, TI_TASK($28)
nop
- LOAD t0, THREAD_BUADDR(t0) # t0 is just past last good address
+ LOADK t0, THREAD_BUADDR(t0) # t0 is just past last good address
nop
SUB len, AT, t0 # len number of uncopied bytes
- bnez t6, .Ldone /* Skip the zeroing part if inatomic */
+ bnez t6, .Ldone\@ /* Skip the zeroing part if inatomic */
/*
* Here's where we rely on src and dst being incremented in tandem,
* See (3) above.
@@ -482,7 +551,7 @@ EXC( lb t1, 0(src), .Ll_exc)
*/
.set reorder /* DADDI_WAR */
SUB src, len, 1
- beqz len, .Ldone
+ beqz len, .Ldone\@
.set noreorder
1: sb zero, 0(dst)
ADD dst, dst, 1
@@ -503,7 +572,7 @@ EXC( lb t1, 0(src), .Ll_exc)
#define SEXC(n) \
.set reorder; /* DADDI_WAR */ \
-.Ls_exc_p ## n ## u: \
+.Ls_exc_p ## n ## u\@: \
ADD len, len, n*NBYTES; \
jr ra; \
.set noreorder
@@ -517,14 +586,15 @@ SEXC(3)
SEXC(2)
SEXC(1)
-.Ls_exc_p1:
+.Ls_exc_p1\@:
.set reorder /* DADDI_WAR */
ADD len, len, 1
jr ra
.set noreorder
-.Ls_exc:
+.Ls_exc\@:
jr ra
nop
+ .endm
.align 5
LEAF(memmove)
@@ -575,3 +645,71 @@ LEAF(__rmemcpy) /* a0=dst a1=src a2=len */
jr ra
move a2, zero
END(__rmemcpy)
+
+/*
+ * t6 is used as a flag to note inatomic mode.
+ */
+LEAF(__copy_user_inatomic)
+ b __copy_user_common
+ li t6, 1
+ END(__copy_user_inatomic)
+
+/*
+ * A combined memcpy/__copy_user
+ * __copy_user sets len to 0 for success; else to an upper bound of
+ * the number of uncopied bytes.
+ * memcpy sets v0 to dst.
+ */
+ .align 5
+LEAF(memcpy) /* a0=dst a1=src a2=len */
+ move v0, dst /* return value */
+.L__memcpy:
+FEXPORT(__copy_user)
+ li t6, 0 /* not inatomic */
+__copy_user_common:
+ /* Legacy Mode, user <-> user */
+ __BUILD_COPY_USER LEGACY_MODE USEROP USEROP
+
+#ifdef CONFIG_EVA
+
+/*
+ * For EVA we need distinct symbols for reading and writing to user space.
+ * This is because we need to use specific EVA instructions to perform the
+ * virtual <-> physical translation when a virtual address is actually in user
+ * space
+ */
+
+LEAF(__copy_user_inatomic_eva)
+ b __copy_from_user_common
+ li t6, 1
+ END(__copy_user_inatomic_eva)
+
+/*
+ * __copy_from_user (EVA)
+ */
+
+LEAF(__copy_from_user_eva)
+ li t6, 0 /* not inatomic */
+__copy_from_user_common:
+ __BUILD_COPY_USER EVA_MODE USEROP KERNELOP
+END(__copy_from_user_eva)
+
+
+
+/*
+ * __copy_to_user (EVA)
+ */
+
+LEAF(__copy_to_user_eva)
+__BUILD_COPY_USER EVA_MODE KERNELOP USEROP
+END(__copy_to_user_eva)
+
+/*
+ * __copy_in_user (EVA)
+ */
+
+LEAF(__copy_in_user_eva)
+__BUILD_COPY_USER EVA_MODE USEROP USEROP
+END(__copy_in_user_eva)
+
+#endif
diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S
index 0580194e7402..7b0e5462ca51 100644
--- a/arch/mips/lib/memset.S
+++ b/arch/mips/lib/memset.S
@@ -34,13 +34,27 @@
#define FILLPTRG t0
#endif
+#define LEGACY_MODE 1
+#define EVA_MODE 2
+
+/*
+ * No need to protect it with EVA #ifdefery. The generated block of code
+ * will never be assembled if EVA is not enabled.
+ */
+#define __EVAFY(insn, reg, addr) __BUILD_EVA_INSN(insn##e, reg, addr)
+#define ___BUILD_EVA_INSN(insn, reg, addr) __EVAFY(insn, reg, addr)
+
#define EX(insn,reg,addr,handler) \
-9: insn reg, addr; \
+ .if \mode == LEGACY_MODE; \
+9: insn reg, addr; \
+ .else; \
+9: ___BUILD_EVA_INSN(insn, reg, addr); \
+ .endif; \
.section __ex_table,"a"; \
PTR 9b, handler; \
.previous
- .macro f_fill64 dst, offset, val, fixup
+ .macro f_fill64 dst, offset, val, fixup, mode
EX(LONG_S, \val, (\offset + 0 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 1 * STORSIZE)(\dst), \fixup)
EX(LONG_S, \val, (\offset + 2 * STORSIZE)(\dst), \fixup)
@@ -63,34 +77,24 @@
#endif
.endm
-/*
- * memset(void *s, int c, size_t n)
- *
- * a0: start of area to clear
- * a1: char to fill with
- * a2: size of area to clear
- */
.set noreorder
.align 5
-LEAF(memset)
- beqz a1, 1f
- move v0, a0 /* result */
- andi a1, 0xff /* spread fillword */
- LONG_SLL t1, a1, 8
- or a1, t1
- LONG_SLL t1, a1, 16
-#if LONGSIZE == 8
- or a1, t1
- LONG_SLL t1, a1, 32
-#endif
- or a1, t1
-1:
+ /*
+ * Macro to generate the __bzero{,_user} symbol
+ * Arguments:
+ * mode: LEGACY_MODE or EVA_MODE
+ */
+ .macro __BUILD_BZERO mode
+ /* Initialize __memset if this is the first time we call this macro */
+ .ifnotdef __memset
+ .set __memset, 1
+ .hidden __memset /* Make sure it does not leak */
+ .endif
-FEXPORT(__bzero)
sltiu t0, a2, STORSIZE /* very small region? */
- bnez t0, .Lsmall_memset
- andi t0, a0, STORMASK /* aligned? */
+ bnez t0, .Lsmall_memset\@
+ andi t0, a0, STORMASK /* aligned? */
#ifdef CONFIG_CPU_MICROMIPS
move t8, a1 /* used by 'swp' instruction */
@@ -98,39 +102,39 @@ FEXPORT(__bzero)
#endif
#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
beqz t0, 1f
- PTR_SUBU t0, STORSIZE /* alignment in bytes */
+ PTR_SUBU t0, STORSIZE /* alignment in bytes */
#else
.set noat
li AT, STORSIZE
beqz t0, 1f
- PTR_SUBU t0, AT /* alignment in bytes */
+ PTR_SUBU t0, AT /* alignment in bytes */
.set at
#endif
R10KCBARRIER(0(ra))
#ifdef __MIPSEB__
- EX(LONG_S_L, a1, (a0), .Lfirst_fixup) /* make word/dword aligned */
+ EX(LONG_S_L, a1, (a0), .Lfirst_fixup\@) /* make word/dword aligned */
#endif
#ifdef __MIPSEL__
- EX(LONG_S_R, a1, (a0), .Lfirst_fixup) /* make word/dword aligned */
+ EX(LONG_S_R, a1, (a0), .Lfirst_fixup\@) /* make word/dword aligned */
#endif
PTR_SUBU a0, t0 /* long align ptr */
PTR_ADDU a2, t0 /* correct size */
1: ori t1, a2, 0x3f /* # of full blocks */
xori t1, 0x3f
- beqz t1, .Lmemset_partial /* no block to fill */
- andi t0, a2, 0x40-STORSIZE
+ beqz t1, .Lmemset_partial\@ /* no block to fill */
+ andi t0, a2, 0x40-STORSIZE
PTR_ADDU t1, a0 /* end address */
.set reorder
1: PTR_ADDIU a0, 64
R10KCBARRIER(0(ra))
- f_fill64 a0, -64, FILL64RG, .Lfwd_fixup
+ f_fill64 a0, -64, FILL64RG, .Lfwd_fixup\@, \mode
bne t1, a0, 1b
.set noreorder
-.Lmemset_partial:
+.Lmemset_partial\@:
R10KCBARRIER(0(ra))
PTR_LA t1, 2f /* where to start */
#ifdef CONFIG_CPU_MICROMIPS
@@ -145,60 +149,100 @@ FEXPORT(__bzero)
.set at
#endif
jr t1
- PTR_ADDU a0, t0 /* dest ptr */
+ PTR_ADDU a0, t0 /* dest ptr */
.set push
.set noreorder
.set nomacro
- f_fill64 a0, -64, FILL64RG, .Lpartial_fixup /* ... but first do longs ... */
+ /* ... but first do longs ... */
+ f_fill64 a0, -64, FILL64RG, .Lpartial_fixup\@, \mode
2: .set pop
andi a2, STORMASK /* At most one long to go */
beqz a2, 1f
- PTR_ADDU a0, a2 /* What's left */
+ PTR_ADDU a0, a2 /* What's left */
R10KCBARRIER(0(ra))
#ifdef __MIPSEB__
- EX(LONG_S_R, a1, -1(a0), .Llast_fixup)
+ EX(LONG_S_R, a1, -1(a0), .Llast_fixup\@)
#endif
#ifdef __MIPSEL__
- EX(LONG_S_L, a1, -1(a0), .Llast_fixup)
+ EX(LONG_S_L, a1, -1(a0), .Llast_fixup\@)
#endif
1: jr ra
- move a2, zero
+ move a2, zero
-.Lsmall_memset:
+.Lsmall_memset\@:
beqz a2, 2f
- PTR_ADDU t1, a0, a2
+ PTR_ADDU t1, a0, a2
1: PTR_ADDIU a0, 1 /* fill bytewise */
R10KCBARRIER(0(ra))
bne t1, a0, 1b
- sb a1, -1(a0)
+ sb a1, -1(a0)
2: jr ra /* done */
- move a2, zero
+ move a2, zero
+ .if __memset == 1
END(memset)
+ .set __memset, 0
+ .hidden __memset
+ .endif
-.Lfirst_fixup:
+.Lfirst_fixup\@:
jr ra
- nop
+ nop
-.Lfwd_fixup:
+.Lfwd_fixup\@:
PTR_L t0, TI_TASK($28)
andi a2, 0x3f
LONG_L t0, THREAD_BUADDR(t0)
LONG_ADDU a2, t1
jr ra
- LONG_SUBU a2, t0
+ LONG_SUBU a2, t0
-.Lpartial_fixup:
+.Lpartial_fixup\@:
PTR_L t0, TI_TASK($28)
andi a2, STORMASK
LONG_L t0, THREAD_BUADDR(t0)
LONG_ADDU a2, t1
jr ra
- LONG_SUBU a2, t0
+ LONG_SUBU a2, t0
-.Llast_fixup:
+.Llast_fixup\@:
jr ra
- andi v1, a2, STORMASK
+ andi v1, a2, STORMASK
+
+ .endm
+
+/*
+ * memset(void *s, int c, size_t n)
+ *
+ * a0: start of area to clear
+ * a1: char to fill with
+ * a2: size of area to clear
+ */
+
+LEAF(memset)
+ beqz a1, 1f
+ move v0, a0 /* result */
+
+ andi a1, 0xff /* spread fillword */
+ LONG_SLL t1, a1, 8
+ or a1, t1
+ LONG_SLL t1, a1, 16
+#if LONGSIZE == 8
+ or a1, t1
+ LONG_SLL t1, a1, 32
+#endif
+ or a1, t1
+1:
+#ifndef CONFIG_EVA
+FEXPORT(__bzero)
+#endif
+ __BUILD_BZERO LEGACY_MODE
+
+#ifdef CONFIG_EVA
+LEAF(__bzero)
+ __BUILD_BZERO EVA_MODE
+END(__bzero)
+#endif
diff --git a/arch/mips/lib/strlen_user.S b/arch/mips/lib/strlen_user.S
index e362dcdc69d1..bef65c98df59 100644
--- a/arch/mips/lib/strlen_user.S
+++ b/arch/mips/lib/strlen_user.S
@@ -22,19 +22,43 @@
*
* Return 0 for error
*/
-LEAF(__strlen_user_asm)
+ .macro __BUILD_STRLEN_ASM func
+LEAF(__strlen_\func\()_asm)
LONG_L v0, TI_ADDR_LIMIT($28) # pointer ok?
and v0, a0
- bnez v0, .Lfault
+ bnez v0, .Lfault\@
-FEXPORT(__strlen_user_nocheck_asm)
+FEXPORT(__strlen_\func\()_nocheck_asm)
move v0, a0
-1: EX(lbu, v1, (v0), .Lfault)
+.ifeqs "\func", "kernel"
+1: EX(lbu, v1, (v0), .Lfault\@)
+.else
+1: EX(lbue, v1, (v0), .Lfault\@)
+.endif
PTR_ADDIU v0, 1
bnez v1, 1b
PTR_SUBU v0, a0
jr ra
- END(__strlen_user_asm)
+ END(__strlen_\func\()_asm)
-.Lfault: move v0, zero
+.Lfault\@: move v0, zero
jr ra
+ .endm
+
+#ifndef CONFIG_EVA
+ /* Set aliases */
+ .global __strlen_user_asm
+ .global __strlen_user_nocheck_asm
+ .set __strlen_user_asm, __strlen_kernel_asm
+ .set __strlen_user_nocheck_asm, __strlen_kernel_nocheck_asm
+#endif
+
+__BUILD_STRLEN_ASM kernel
+
+#ifdef CONFIG_EVA
+
+ .set push
+ .set eva
+__BUILD_STRLEN_ASM user
+ .set pop
+#endif
diff --git a/arch/mips/lib/strncpy_user.S b/arch/mips/lib/strncpy_user.S
index 92870b6b53ea..d3301cd1e9a5 100644
--- a/arch/mips/lib/strncpy_user.S
+++ b/arch/mips/lib/strncpy_user.S
@@ -28,16 +28,21 @@
* it happens at most some bytes of the exceptions handlers will be copied.
*/
-LEAF(__strncpy_from_user_asm)
+ .macro __BUILD_STRNCPY_ASM func
+LEAF(__strncpy_from_\func\()_asm)
LONG_L v0, TI_ADDR_LIMIT($28) # pointer ok?
and v0, a1
- bnez v0, .Lfault
+ bnez v0, .Lfault\@
-FEXPORT(__strncpy_from_user_nocheck_asm)
+FEXPORT(__strncpy_from_\func\()_nocheck_asm)
.set noreorder
move t0, zero
move v1, a1
-1: EX(lbu, v0, (v1), .Lfault)
+.ifeqs "\func","kernel"
+1: EX(lbu, v0, (v1), .Lfault\@)
+.else
+1: EX(lbue, v0, (v1), .Lfault\@)
+.endif
PTR_ADDIU v1, 1
R10KCBARRIER(0(ra))
beqz v0, 2f
@@ -47,15 +52,34 @@ FEXPORT(__strncpy_from_user_nocheck_asm)
PTR_ADDIU a0, 1
2: PTR_ADDU v0, a1, t0
xor v0, a1
- bltz v0, .Lfault
+ bltz v0, .Lfault\@
nop
jr ra # return n
move v0, t0
- END(__strncpy_from_user_asm)
+ END(__strncpy_from_\func\()_asm)
-.Lfault: jr ra
+.Lfault\@: jr ra
li v0, -EFAULT
.section __ex_table,"a"
- PTR 1b, .Lfault
+ PTR 1b, .Lfault\@
.previous
+
+ .endm
+
+#ifndef CONFIG_EVA
+ /* Set aliases */
+ .global __strncpy_from_user_asm
+ .global __strncpy_from_user_nocheck_asm
+ .set __strncpy_from_user_asm, __strncpy_from_kernel_asm
+ .set __strncpy_from_user_nocheck_asm, __strncpy_from_kernel_nocheck_asm
+#endif
+
+__BUILD_STRNCPY_ASM kernel
+
+#ifdef CONFIG_EVA
+ .set push
+ .set eva
+__BUILD_STRNCPY_ASM user
+ .set pop
+#endif
diff --git a/arch/mips/lib/strnlen_user.S b/arch/mips/lib/strnlen_user.S
index fcacea5e61f1..f3af6995e2a6 100644
--- a/arch/mips/lib/strnlen_user.S
+++ b/arch/mips/lib/strnlen_user.S
@@ -25,22 +25,46 @@
* bytes. There's nothing secret there. On 64-bit accessing beyond
* the maximum is a tad hairier ...
*/
-LEAF(__strnlen_user_asm)
+ .macro __BUILD_STRNLEN_ASM func
+LEAF(__strnlen_\func\()_asm)
LONG_L v0, TI_ADDR_LIMIT($28) # pointer ok?
and v0, a0
- bnez v0, .Lfault
+ bnez v0, .Lfault\@
-FEXPORT(__strnlen_user_nocheck_asm)
+FEXPORT(__strnlen_\func\()_nocheck_asm)
move v0, a0
PTR_ADDU a1, a0 # stop pointer
1: beq v0, a1, 1f # limit reached?
- EX(lb, t0, (v0), .Lfault)
+.ifeqs "\func", "kernel"
+ EX(lb, t0, (v0), .Lfault\@)
+.else
+ EX(lbe, t0, (v0), .Lfault\@)
+.endif
PTR_ADDIU v0, 1
bnez t0, 1b
1: PTR_SUBU v0, a0
jr ra
- END(__strnlen_user_asm)
+ END(__strnlen_\func\()_asm)
-.Lfault:
+.Lfault\@:
move v0, zero
jr ra
+ .endm
+
+#ifndef CONFIG_EVA
+ /* Set aliases */
+ .global __strnlen_user_asm
+ .global __strnlen_user_nocheck_asm
+ .set __strnlen_user_asm, __strnlen_kernel_asm
+ .set __strnlen_user_nocheck_asm, __strnlen_kernel_nocheck_asm
+#endif
+
+__BUILD_STRNLEN_ASM kernel
+
+#ifdef CONFIG_EVA
+
+ .set push
+ .set eva
+__BUILD_STRNLEN_ASM user
+ .set pop
+#endif
diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig
index 263beb9322a8..7397be226a06 100644
--- a/arch/mips/loongson/Kconfig
+++ b/arch/mips/loongson/Kconfig
@@ -59,6 +59,36 @@ config LEMOTE_MACH2F
These family machines include fuloong2f mini PC, yeeloong2f notebook,
LingLoong allinone PC and so forth.
+
+config LEMOTE_MACH3A
+ bool "Lemote Loongson 3A family machines"
+ select ARCH_SPARSEMEM_ENABLE
+ select GENERIC_ISA_DMA_SUPPORT_BROKEN
+ select GENERIC_HARDIRQS_NO__DO_IRQ
+ select BOOT_ELF32
+ select BOARD_SCACHE
+ select CSRC_R4K
+ select CEVT_R4K
+ select CPU_HAS_WB
+ select HW_HAS_PCI
+ select ISA
+ select HT_PCI
+ select I8259
+ select IRQ_CPU
+ select NR_CPUS_DEFAULT_4
+ select SYS_HAS_CPU_LOONGSON3
+ select SYS_HAS_EARLY_PRINTK
+ select SYS_SUPPORTS_SMP
+ select SYS_SUPPORTS_HOTPLUG_CPU
+ select SYS_SUPPORTS_64BIT_KERNEL
+ select SYS_SUPPORTS_HIGHMEM
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select LOONGSON_MC146818
+ select ZONE_DMA32
+ select LEFI_FIRMWARE_INTERFACE
+ help
+ Lemote Loongson 3A family machines utilize the 3A revision of
+ Loongson processor and RS780/SBX00 chipset.
endchoice
config CS5536
@@ -86,8 +116,25 @@ config LOONGSON_UART_BASE
default y
depends on EARLY_PRINTK || SERIAL_8250
+config IOMMU_HELPER
+ bool
+
+config NEED_SG_DMA_LENGTH
+ bool
+
+config SWIOTLB
+ bool "Soft IOMMU Support for All-Memory DMA"
+ default y
+ depends on CPU_LOONGSON3
+ select IOMMU_HELPER
+ select NEED_SG_DMA_LENGTH
+ select NEED_DMA_MAP_STATE
+
config LOONGSON_MC146818
bool
default n
+config LEFI_FIRMWARE_INTERFACE
+ bool
+
endif # MACH_LOONGSON
diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile
index 0dc0055754cd..7429994e7604 100644
--- a/arch/mips/loongson/Makefile
+++ b/arch/mips/loongson/Makefile
@@ -15,3 +15,9 @@ obj-$(CONFIG_LEMOTE_FULOONG2E) += fuloong-2e/
#
obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/
+
+#
+# All Loongson-3 family machines
+#
+
+obj-$(CONFIG_CPU_LOONGSON3) += loongson-3/
diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform
index 29692e5433b1..6205372b6c2d 100644
--- a/arch/mips/loongson/Platform
+++ b/arch/mips/loongson/Platform
@@ -30,3 +30,4 @@ platform-$(CONFIG_MACH_LOONGSON) += loongson/
cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely
load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000
load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000
+load-$(CONFIG_CPU_LOONGSON3) += 0xffffffff80200000
diff --git a/arch/mips/loongson/common/Makefile b/arch/mips/loongson/common/Makefile
index 9e4484ccbb03..0bb9cc9dc621 100644
--- a/arch/mips/loongson/common/Makefile
+++ b/arch/mips/loongson/common/Makefile
@@ -26,3 +26,8 @@ obj-$(CONFIG_CS5536) += cs5536/
#
obj-$(CONFIG_LOONGSON_SUSPEND) += pm.o
+
+#
+# Big Memory (SWIOTLB) Support
+#
+obj-$(CONFIG_SWIOTLB) += dma-swiotlb.o
diff --git a/arch/mips/loongson/common/dma-swiotlb.c b/arch/mips/loongson/common/dma-swiotlb.c
new file mode 100644
index 000000000000..c2be01f91575
--- /dev/null
+++ b/arch/mips/loongson/common/dma-swiotlb.c
@@ -0,0 +1,136 @@
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/swiotlb.h>
+#include <linux/bootmem.h>
+
+#include <asm/bootinfo.h>
+#include <boot_param.h>
+#include <dma-coherence.h>
+
+static void *loongson_dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
+{
+ void *ret;
+
+ if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
+ return ret;
+
+ /* ignore region specifiers */
+ gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);
+
+#ifdef CONFIG_ISA
+ if (dev == NULL)
+ gfp |= __GFP_DMA;
+ else
+#endif
+#ifdef CONFIG_ZONE_DMA
+ if (dev->coherent_dma_mask < DMA_BIT_MASK(32))
+ gfp |= __GFP_DMA;
+ else
+#endif
+#ifdef CONFIG_ZONE_DMA32
+ if (dev->coherent_dma_mask < DMA_BIT_MASK(40))
+ gfp |= __GFP_DMA32;
+ else
+#endif
+ ;
+ gfp |= __GFP_NORETRY;
+
+ ret = swiotlb_alloc_coherent(dev, size, dma_handle, gfp);
+ mb();
+ return ret;
+}
+
+static void loongson_dma_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs)
+{
+ int order = get_order(size);
+
+ if (dma_release_from_coherent(dev, order, vaddr))
+ return;
+
+ swiotlb_free_coherent(dev, size, vaddr, dma_handle);
+}
+
+static dma_addr_t loongson_dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ dma_addr_t daddr = swiotlb_map_page(dev, page, offset, size,
+ dir, attrs);
+ mb();
+ return daddr;
+}
+
+static int loongson_dma_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ int r = swiotlb_map_sg_attrs(dev, sg, nents, dir, NULL);
+ mb();
+
+ return r;
+}
+
+static void loongson_dma_sync_single_for_device(struct device *dev,
+ dma_addr_t dma_handle, size_t size,
+ enum dma_data_direction dir)
+{
+ swiotlb_sync_single_for_device(dev, dma_handle, size, dir);
+ mb();
+}
+
+static void loongson_dma_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction dir)
+{
+ swiotlb_sync_sg_for_device(dev, sg, nents, dir);
+ mb();
+}
+
+static int loongson_dma_set_mask(struct device *dev, u64 mask)
+{
+ if (mask > DMA_BIT_MASK(loongson_sysconf.dma_mask_bits)) {
+ *dev->dma_mask = DMA_BIT_MASK(loongson_sysconf.dma_mask_bits);
+ return -EIO;
+ }
+
+ *dev->dma_mask = mask;
+
+ return 0;
+}
+
+dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+ return paddr;
+}
+
+phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+ return daddr;
+}
+
+static struct dma_map_ops loongson_dma_map_ops = {
+ .alloc = loongson_dma_alloc_coherent,
+ .free = loongson_dma_free_coherent,
+ .map_page = loongson_dma_map_page,
+ .unmap_page = swiotlb_unmap_page,
+ .map_sg = loongson_dma_map_sg,
+ .unmap_sg = swiotlb_unmap_sg_attrs,
+ .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
+ .sync_single_for_device = loongson_dma_sync_single_for_device,
+ .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+ .sync_sg_for_device = loongson_dma_sync_sg_for_device,
+ .mapping_error = swiotlb_dma_mapping_error,
+ .dma_supported = swiotlb_dma_supported,
+ .set_dma_mask = loongson_dma_set_mask
+};
+
+void __init plat_swiotlb_setup(void)
+{
+ swiotlb_init(1);
+ mips_dma_map_ops = &loongson_dma_map_ops;
+}
diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c
index 0a18fcf2d372..0c543eae49bf 100644
--- a/arch/mips/loongson/common/env.c
+++ b/arch/mips/loongson/common/env.c
@@ -18,29 +18,30 @@
* option) any later version.
*/
#include <linux/module.h>
-
#include <asm/bootinfo.h>
-
#include <loongson.h>
+#include <boot_param.h>
-unsigned long cpu_clock_freq;
+u32 cpu_clock_freq;
EXPORT_SYMBOL(cpu_clock_freq);
-unsigned long memsize, highmemsize;
+struct efi_memory_map_loongson *loongson_memmap;
+struct loongson_system_configuration loongson_sysconf;
#define parse_even_earlier(res, option, p) \
do { \
unsigned int tmp __maybe_unused; \
\
if (strncmp(option, (char *)p, strlen(option)) == 0) \
- tmp = strict_strtol((char *)p + strlen(option"="), 10, &res); \
+ tmp = kstrtou32((char *)p + strlen(option"="), 10, &res); \
} while (0)
void __init prom_init_env(void)
{
/* pmon passes arguments in 32bit pointers */
- int *_prom_envp;
- unsigned long bus_clock;
unsigned int processor_id;
+
+#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
+ int *_prom_envp;
long l;
/* firmware arguments are initialized in head.S */
@@ -48,7 +49,6 @@ void __init prom_init_env(void)
l = (long)*_prom_envp;
while (l != 0) {
- parse_even_earlier(bus_clock, "busclock", l);
parse_even_earlier(cpu_clock_freq, "cpuclock", l);
parse_even_earlier(memsize, "memsize", l);
parse_even_earlier(highmemsize, "highmemsize", l);
@@ -57,8 +57,48 @@ void __init prom_init_env(void)
}
if (memsize == 0)
memsize = 256;
- if (bus_clock == 0)
- bus_clock = 66000000;
+ pr_info("memsize=%u, highmemsize=%u\n", memsize, highmemsize);
+#else
+ struct boot_params *boot_p;
+ struct loongson_params *loongson_p;
+ struct efi_cpuinfo_loongson *ecpu;
+ struct irq_source_routing_table *eirq_source;
+
+ /* firmware arguments are initialized in head.S */
+ boot_p = (struct boot_params *)fw_arg2;
+ loongson_p = &(boot_p->efi.smbios.lp);
+
+ ecpu = (struct efi_cpuinfo_loongson *)
+ ((u64)loongson_p + loongson_p->cpu_offset);
+ eirq_source = (struct irq_source_routing_table *)
+ ((u64)loongson_p + loongson_p->irq_offset);
+ loongson_memmap = (struct efi_memory_map_loongson *)
+ ((u64)loongson_p + loongson_p->memory_offset);
+
+ cpu_clock_freq = ecpu->cpu_clock_freq;
+ loongson_sysconf.cputype = ecpu->cputype;
+ loongson_sysconf.nr_cpus = ecpu->nr_cpus;
+ if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0)
+ loongson_sysconf.nr_cpus = NR_CPUS;
+
+ loongson_sysconf.pci_mem_start_addr = eirq_source->pci_mem_start_addr;
+ loongson_sysconf.pci_mem_end_addr = eirq_source->pci_mem_end_addr;
+ loongson_sysconf.pci_io_base = eirq_source->pci_io_start_addr;
+ loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits;
+ if (loongson_sysconf.dma_mask_bits < 32 ||
+ loongson_sysconf.dma_mask_bits > 64)
+ loongson_sysconf.dma_mask_bits = 32;
+
+ loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm;
+ loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown;
+ loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend;
+
+ loongson_sysconf.ht_control_base = 0x90000EFDFB000000;
+ loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios;
+ pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n",
+ loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr,
+ loongson_sysconf.vgabios_addr);
+#endif
if (cpu_clock_freq == 0) {
processor_id = (&current_cpu_data)->processor_id;
switch (processor_id & PRID_REV_MASK) {
@@ -68,12 +108,13 @@ void __init prom_init_env(void)
case PRID_REV_LOONGSON2F:
cpu_clock_freq = 797000000;
break;
+ case PRID_REV_LOONGSON3A:
+ cpu_clock_freq = 900000000;
+ break;
default:
cpu_clock_freq = 100000000;
break;
}
}
-
- pr_info("busclock=%ld, cpuclock=%ld, memsize=%ld, highmemsize=%ld\n",
- bus_clock, cpu_clock_freq, memsize, highmemsize);
+ pr_info("CpuClock = %u\n", cpu_clock_freq);
}
diff --git a/arch/mips/loongson/common/init.c b/arch/mips/loongson/common/init.c
index ae7af1fd5d59..f37fe5413b73 100644
--- a/arch/mips/loongson/common/init.c
+++ b/arch/mips/loongson/common/init.c
@@ -9,6 +9,7 @@
*/
#include <linux/bootmem.h>
+#include <asm/smp-ops.h>
#include <loongson.h>
@@ -17,10 +18,6 @@ unsigned long __maybe_unused _loongson_addrwincfg_base;
void __init prom_init(void)
{
- /* init base address of io space */
- set_io_port_base((unsigned long)
- ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE));
-
#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
_loongson_addrwincfg_base = (unsigned long)
ioremap(LOONGSON_ADDRWINCFG_BASE, LOONGSON_ADDRWINCFG_SIZE);
@@ -28,10 +25,16 @@ void __init prom_init(void)
prom_init_cmdline();
prom_init_env();
+
+ /* init base address of io space */
+ set_io_port_base((unsigned long)
+ ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE));
+
prom_init_memory();
/*init the uart base address */
prom_init_uart_base();
+ register_smp_ops(&loongson3_smp_ops);
}
void __init prom_free_prom_memory(void)
diff --git a/arch/mips/loongson/common/machtype.c b/arch/mips/loongson/common/machtype.c
index 4becd4f9ef2e..1a4797984b8d 100644
--- a/arch/mips/loongson/common/machtype.c
+++ b/arch/mips/loongson/common/machtype.c
@@ -27,6 +27,10 @@ static const char *system_types[] = {
[MACH_DEXXON_GDIUM2F10] "dexxon-gdium-2f",
[MACH_LEMOTE_NAS] "lemote-nas-2f",
[MACH_LEMOTE_LL2F] "lemote-lynloong-2f",
+ [MACH_LEMOTE_A1004] "lemote-3a-notebook-a1004",
+ [MACH_LEMOTE_A1101] "lemote-3a-itx-a1101",
+ [MACH_LEMOTE_A1201] "lemote-2gq-notebook-a1201",
+ [MACH_LEMOTE_A1205] "lemote-2gq-aio-a1205",
[MACH_LOONGSON_END] NULL,
};
diff --git a/arch/mips/loongson/common/mem.c b/arch/mips/loongson/common/mem.c
index 8626a42f5b94..b01d52473da8 100644
--- a/arch/mips/loongson/common/mem.c
+++ b/arch/mips/loongson/common/mem.c
@@ -11,9 +11,14 @@
#include <asm/bootinfo.h>
#include <loongson.h>
+#include <boot_param.h>
#include <mem.h>
#include <pci.h>
+#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
+
+u32 memsize, highmemsize;
+
void __init prom_init_memory(void)
{
add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM);
@@ -49,6 +54,43 @@ void __init prom_init_memory(void)
#endif /* !CONFIG_64BIT */
}
+#else /* CONFIG_LEFI_FIRMWARE_INTERFACE */
+
+void __init prom_init_memory(void)
+{
+ int i;
+ u32 node_id;
+ u32 mem_type;
+
+ /* parse memory information */
+ for (i = 0; i < loongson_memmap->nr_map; i++) {
+ node_id = loongson_memmap->map[i].node_id;
+ mem_type = loongson_memmap->map[i].mem_type;
+
+ if (node_id == 0) {
+ switch (mem_type) {
+ case SYSTEM_RAM_LOW:
+ add_memory_region(loongson_memmap->map[i].mem_start,
+ (u64)loongson_memmap->map[i].mem_size << 20,
+ BOOT_MEM_RAM);
+ break;
+ case SYSTEM_RAM_HIGH:
+ add_memory_region(loongson_memmap->map[i].mem_start,
+ (u64)loongson_memmap->map[i].mem_size << 20,
+ BOOT_MEM_RAM);
+ break;
+ case MEM_RESERVED:
+ add_memory_region(loongson_memmap->map[i].mem_start,
+ (u64)loongson_memmap->map[i].mem_size << 20,
+ BOOT_MEM_RESERVED);
+ break;
+ }
+ }
+ }
+}
+
+#endif /* CONFIG_LEFI_FIRMWARE_INTERFACE */
+
/* override of arch/mips/mm/cache.c: __uncached_access */
int __uncached_access(struct file *file, unsigned long addr)
{
diff --git a/arch/mips/loongson/common/pci.c b/arch/mips/loongson/common/pci.c
index fa7784459721..003ab4e618b3 100644
--- a/arch/mips/loongson/common/pci.c
+++ b/arch/mips/loongson/common/pci.c
@@ -11,6 +11,7 @@
#include <pci.h>
#include <loongson.h>
+#include <boot_param.h>
static struct resource loongson_pci_mem_resource = {
.name = "pci memory space",
@@ -82,7 +83,10 @@ static int __init pcibios_init(void)
setup_pcimap();
loongson_pci_controller.io_map_base = mips_io_port_base;
-
+#ifdef CONFIG_LEFI_FIRMWARE_INTERFACE
+ loongson_pci_mem_resource.start = loongson_sysconf.pci_mem_start_addr;
+ loongson_pci_mem_resource.end = loongson_sysconf.pci_mem_end_addr;
+#endif
register_pci_controller(&loongson_pci_controller);
return 0;
diff --git a/arch/mips/loongson/common/reset.c b/arch/mips/loongson/common/reset.c
index 65bfbb5d06f4..a60715e11306 100644
--- a/arch/mips/loongson/common/reset.c
+++ b/arch/mips/loongson/common/reset.c
@@ -16,6 +16,7 @@
#include <asm/reboot.h>
#include <loongson.h>
+#include <boot_param.h>
static inline void loongson_reboot(void)
{
@@ -37,17 +38,37 @@ static inline void loongson_reboot(void)
static void loongson_restart(char *command)
{
+#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
/* do preparation for reboot */
mach_prepare_reboot();
/* reboot via jumping to boot base address */
loongson_reboot();
+#else
+ void (*fw_restart)(void) = (void *)loongson_sysconf.restart_addr;
+
+ fw_restart();
+ while (1) {
+ if (cpu_wait)
+ cpu_wait();
+ }
+#endif
}
static void loongson_poweroff(void)
{
+#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
mach_prepare_shutdown();
unreachable();
+#else
+ void (*fw_poweroff)(void) = (void *)loongson_sysconf.poweroff_addr;
+
+ fw_poweroff();
+ while (1) {
+ if (cpu_wait)
+ cpu_wait();
+ }
+#endif
}
static void loongson_halt(void)
diff --git a/arch/mips/loongson/common/serial.c b/arch/mips/loongson/common/serial.c
index 5f2b78ae97cc..bd2b7095b6dc 100644
--- a/arch/mips/loongson/common/serial.c
+++ b/arch/mips/loongson/common/serial.c
@@ -19,19 +19,19 @@
#include <loongson.h>
#include <machine.h>
-#define PORT(int) \
+#define PORT(int, clk) \
{ \
.irq = int, \
- .uartclk = 1843200, \
+ .uartclk = clk, \
.iotype = UPIO_PORT, \
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
.regshift = 0, \
}
-#define PORT_M(int) \
+#define PORT_M(int, clk) \
{ \
.irq = MIPS_CPU_IRQ_BASE + (int), \
- .uartclk = 3686400, \
+ .uartclk = clk, \
.iotype = UPIO_MEM, \
.membase = (void __iomem *)NULL, \
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
@@ -40,13 +40,17 @@
static struct plat_serial8250_port uart8250_data[][2] = {
[MACH_LOONGSON_UNKNOWN] {},
- [MACH_LEMOTE_FL2E] {PORT(4), {} },
- [MACH_LEMOTE_FL2F] {PORT(3), {} },
- [MACH_LEMOTE_ML2F7] {PORT_M(3), {} },
- [MACH_LEMOTE_YL2F89] {PORT_M(3), {} },
- [MACH_DEXXON_GDIUM2F10] {PORT_M(3), {} },
- [MACH_LEMOTE_NAS] {PORT_M(3), {} },
- [MACH_LEMOTE_LL2F] {PORT(3), {} },
+ [MACH_LEMOTE_FL2E] {PORT(4, 1843200), {} },
+ [MACH_LEMOTE_FL2F] {PORT(3, 1843200), {} },
+ [MACH_LEMOTE_ML2F7] {PORT_M(3, 3686400), {} },
+ [MACH_LEMOTE_YL2F89] {PORT_M(3, 3686400), {} },
+ [MACH_DEXXON_GDIUM2F10] {PORT_M(3, 3686400), {} },
+ [MACH_LEMOTE_NAS] {PORT_M(3, 3686400), {} },
+ [MACH_LEMOTE_LL2F] {PORT(3, 1843200), {} },
+ [MACH_LEMOTE_A1004] {PORT_M(2, 33177600), {} },
+ [MACH_LEMOTE_A1101] {PORT_M(2, 25000000), {} },
+ [MACH_LEMOTE_A1201] {PORT_M(2, 25000000), {} },
+ [MACH_LEMOTE_A1205] {PORT_M(2, 25000000), {} },
[MACH_LOONGSON_END] {},
};
diff --git a/arch/mips/loongson/common/setup.c b/arch/mips/loongson/common/setup.c
index 8223f8acfd59..bb4ac922e47a 100644
--- a/arch/mips/loongson/common/setup.c
+++ b/arch/mips/loongson/common/setup.c
@@ -18,9 +18,6 @@
#include <linux/screen_info.h>
#endif
-void (*__wbflush)(void);
-EXPORT_SYMBOL(__wbflush);
-
static void wbflush_loongson(void)
{
asm(".set\tpush\n\t"
@@ -32,10 +29,11 @@ static void wbflush_loongson(void)
".set mips0\n\t");
}
+void (*__wbflush)(void) = wbflush_loongson;
+EXPORT_SYMBOL(__wbflush);
+
void __init plat_mem_setup(void)
{
- __wbflush = wbflush_loongson;
-
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
conswitchp = &vga_con;
diff --git a/arch/mips/loongson/common/uart_base.c b/arch/mips/loongson/common/uart_base.c
index e192ad021edc..1e1eeea73fde 100644
--- a/arch/mips/loongson/common/uart_base.c
+++ b/arch/mips/loongson/common/uart_base.c
@@ -35,9 +35,16 @@ void prom_init_loongson_uart_base(void)
case MACH_DEXXON_GDIUM2F10:
case MACH_LEMOTE_NAS:
default:
- /* The CPU provided serial port */
+ /* The CPU provided serial port (LPC) */
loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8;
break;
+ case MACH_LEMOTE_A1004:
+ case MACH_LEMOTE_A1101:
+ case MACH_LEMOTE_A1201:
+ case MACH_LEMOTE_A1205:
+ /* The CPU provided serial port (CPU) */
+ loongson_uart_base = LOONGSON_REG_BASE + 0x1e0;
+ break;
}
_loongson_uart_base =
diff --git a/arch/mips/loongson/loongson-3/Makefile b/arch/mips/loongson/loongson-3/Makefile
new file mode 100644
index 000000000000..70152b252ddc
--- /dev/null
+++ b/arch/mips/loongson/loongson-3/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for Loongson-3 family machines
+#
+obj-y += irq.o
+
+obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/mips/loongson/loongson-3/irq.c b/arch/mips/loongson/loongson-3/irq.c
new file mode 100644
index 000000000000..f240828181ff
--- /dev/null
+++ b/arch/mips/loongson/loongson-3/irq.c
@@ -0,0 +1,126 @@
+#include <loongson.h>
+#include <irq.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/i8259.h>
+#include <asm/mipsregs.h>
+
+unsigned int ht_irq[] = {1, 3, 4, 5, 6, 7, 8, 12, 14, 15};
+
+static void ht_irqdispatch(void)
+{
+ unsigned int i, irq;
+
+ irq = LOONGSON_HT1_INT_VECTOR(0);
+ LOONGSON_HT1_INT_VECTOR(0) = irq; /* Acknowledge the IRQs */
+
+ for (i = 0; i < ARRAY_SIZE(ht_irq); i++) {
+ if (irq & (0x1 << ht_irq[i]))
+ do_IRQ(ht_irq[i]);
+ }
+}
+
+void mach_irq_dispatch(unsigned int pending)
+{
+ if (pending & CAUSEF_IP7)
+ do_IRQ(LOONGSON_TIMER_IRQ);
+#if defined(CONFIG_SMP)
+ else if (pending & CAUSEF_IP6)
+ loongson3_ipi_interrupt(NULL);
+#endif
+ else if (pending & CAUSEF_IP3)
+ ht_irqdispatch();
+ else if (pending & CAUSEF_IP2)
+ do_IRQ(LOONGSON_UART_IRQ);
+ else {
+ pr_err("%s : spurious interrupt\n", __func__);
+ spurious_interrupt();
+ }
+}
+
+static struct irqaction cascade_irqaction = {
+ .handler = no_action,
+ .name = "cascade",
+};
+
+static inline void mask_loongson_irq(struct irq_data *d)
+{
+ clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
+ irq_disable_hazard();
+
+ /* Workaround: UART IRQ may deliver to any core */
+ if (d->irq == LOONGSON_UART_IRQ) {
+ int cpu = smp_processor_id();
+
+ LOONGSON_INT_ROUTER_INTENCLR = 1 << 10;
+ LOONGSON_INT_ROUTER_LPC = 0x10 + (1<<cpu);
+ }
+}
+
+static inline void unmask_loongson_irq(struct irq_data *d)
+{
+ /* Workaround: UART IRQ may deliver to any core */
+ if (d->irq == LOONGSON_UART_IRQ) {
+ int cpu = smp_processor_id();
+
+ LOONGSON_INT_ROUTER_INTENSET = 1 << 10;
+ LOONGSON_INT_ROUTER_LPC = 0x10 + (1<<cpu);
+ }
+
+ set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
+ irq_enable_hazard();
+}
+
+ /* For MIPS IRQs which shared by all cores */
+static struct irq_chip loongson_irq_chip = {
+ .name = "Loongson",
+ .irq_ack = mask_loongson_irq,
+ .irq_mask = mask_loongson_irq,
+ .irq_mask_ack = mask_loongson_irq,
+ .irq_unmask = unmask_loongson_irq,
+ .irq_eoi = unmask_loongson_irq,
+};
+
+void irq_router_init(void)
+{
+ int i;
+
+ /* route LPC int to cpu core0 int 0 */
+ LOONGSON_INT_ROUTER_LPC = LOONGSON_INT_CORE0_INT0;
+ /* route HT1 int0 ~ int7 to cpu core0 INT1*/
+ for (i = 0; i < 8; i++)
+ LOONGSON_INT_ROUTER_HT1(i) = LOONGSON_INT_CORE0_INT1;
+ /* enable HT1 interrupt */
+ LOONGSON_HT1_INTN_EN(0) = 0xffffffff;
+ /* enable router interrupt intenset */
+ LOONGSON_INT_ROUTER_INTENSET =
+ LOONGSON_INT_ROUTER_INTEN | (0xffff << 16) | 0x1 << 10;
+}
+
+void __init mach_init_irq(void)
+{
+ clear_c0_status(ST0_IM | ST0_BEV);
+
+ irq_router_init();
+ mips_cpu_irq_init();
+ init_i8259_irqs();
+ irq_set_chip_and_handler(LOONGSON_UART_IRQ,
+ &loongson_irq_chip, handle_level_irq);
+
+ /* setup HT1 irq */
+ setup_irq(LOONGSON_HT1_IRQ, &cascade_irqaction);
+
+ set_c0_status(STATUSF_IP2 | STATUSF_IP6);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+void fixup_irqs(void)
+{
+ irq_cpu_offline();
+ clear_c0_status(ST0_IM);
+}
+
+#endif
diff --git a/arch/mips/loongson/loongson-3/smp.c b/arch/mips/loongson/loongson-3/smp.c
new file mode 100644
index 000000000000..c665fe16d4c9
--- /dev/null
+++ b/arch/mips/loongson/loongson-3/smp.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2010, 2011, 2012, Lemote, Inc.
+ * Author: Chen Huacai, chenhc@lemote.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/init.h>
+#include <linux/cpu.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/cpufreq.h>
+#include <asm/processor.h>
+#include <asm/time.h>
+#include <asm/clock.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <loongson.h>
+
+#include "smp.h"
+
+DEFINE_PER_CPU(int, cpu_state);
+DEFINE_PER_CPU(uint32_t, core0_c0count);
+
+/* read a 32bit value from ipi register */
+#define loongson3_ipi_read32(addr) readl(addr)
+/* read a 64bit value from ipi register */
+#define loongson3_ipi_read64(addr) readq(addr)
+/* write a 32bit value to ipi register */
+#define loongson3_ipi_write32(action, addr) \
+ do { \
+ writel(action, addr); \
+ __wbflush(); \
+ } while (0)
+/* write a 64bit value to ipi register */
+#define loongson3_ipi_write64(action, addr) \
+ do { \
+ writeq(action, addr); \
+ __wbflush(); \
+ } while (0)
+
+static void *ipi_set0_regs[] = {
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + SET0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + SET0),
+};
+
+static void *ipi_clear0_regs[] = {
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + CLEAR0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + CLEAR0),
+};
+
+static void *ipi_status0_regs[] = {
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + STATUS0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + STATUS0),
+};
+
+static void *ipi_en0_regs[] = {
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + EN0),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + EN0),
+};
+
+static void *ipi_mailbox_buf[] = {
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + BUF),
+ (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + BUF),
+};
+
+/*
+ * Simple enough, just poke the appropriate ipi register
+ */
+static void loongson3_send_ipi_single(int cpu, unsigned int action)
+{
+ loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu]);
+}
+
+static void
+loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action)
+{
+ unsigned int i;
+
+ for_each_cpu(i, mask)
+ loongson3_ipi_write32((u32)action, ipi_set0_regs[i]);
+}
+
+void loongson3_ipi_interrupt(struct pt_regs *regs)
+{
+ int i, cpu = smp_processor_id();
+ unsigned int action, c0count;
+
+ /* Load the ipi register to figure out what we're supposed to do */
+ action = loongson3_ipi_read32(ipi_status0_regs[cpu]);
+
+ /* Clear the ipi register to clear the interrupt */
+ loongson3_ipi_write32((u32)action, ipi_clear0_regs[cpu]);
+
+ if (action & SMP_RESCHEDULE_YOURSELF)
+ scheduler_ipi();
+
+ if (action & SMP_CALL_FUNCTION)
+ smp_call_function_interrupt();
+
+ if (action & SMP_ASK_C0COUNT) {
+ BUG_ON(cpu != 0);
+ c0count = read_c0_count();
+ for (i = 1; i < loongson_sysconf.nr_cpus; i++)
+ per_cpu(core0_c0count, i) = c0count;
+ }
+}
+
+#define MAX_LOOPS 1111
+/*
+ * SMP init and finish on secondary CPUs
+ */
+static void loongson3_init_secondary(void)
+{
+ int i;
+ uint32_t initcount;
+ unsigned int cpu = smp_processor_id();
+ unsigned int imask = STATUSF_IP7 | STATUSF_IP6 |
+ STATUSF_IP3 | STATUSF_IP2;
+
+ /* Set interrupt mask, but don't enable */
+ change_c0_status(ST0_IM, imask);
+
+ for (i = 0; i < loongson_sysconf.nr_cpus; i++)
+ loongson3_ipi_write32(0xffffffff, ipi_en0_regs[i]);
+
+ per_cpu(cpu_state, cpu) = CPU_ONLINE;
+
+ i = 0;
+ __get_cpu_var(core0_c0count) = 0;
+ loongson3_send_ipi_single(0, SMP_ASK_C0COUNT);
+ while (!__get_cpu_var(core0_c0count)) {
+ i++;
+ cpu_relax();
+ }
+
+ if (i > MAX_LOOPS)
+ i = MAX_LOOPS;
+ initcount = __get_cpu_var(core0_c0count) + i;
+ write_c0_count(initcount);
+}
+
+static void loongson3_smp_finish(void)
+{
+ write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ);
+ local_irq_enable();
+ loongson3_ipi_write64(0,
+ (void *)(ipi_mailbox_buf[smp_processor_id()]+0x0));
+ pr_info("CPU#%d finished, CP0_ST=%x\n",
+ smp_processor_id(), read_c0_status());
+}
+
+static void __init loongson3_smp_setup(void)
+{
+ int i, num;
+
+ init_cpu_possible(cpu_none_mask);
+ set_cpu_possible(0, true);
+
+ __cpu_number_map[0] = 0;
+ __cpu_logical_map[0] = 0;
+
+ /* For unified kernel, NR_CPUS is the maximum possible value,
+ * loongson_sysconf.nr_cpus is the really present value */
+ for (i = 1, num = 0; i < loongson_sysconf.nr_cpus; i++) {
+ set_cpu_possible(i, true);
+ __cpu_number_map[i] = ++num;
+ __cpu_logical_map[num] = i;
+ }
+ pr_info("Detected %i available secondary CPU(s)\n", num);
+}
+
+static void __init loongson3_prepare_cpus(unsigned int max_cpus)
+{
+ init_cpu_present(cpu_possible_mask);
+ per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+}
+
+/*
+ * Setup the PC, SP, and GP of a secondary processor and start it runing!
+ */
+static void loongson3_boot_secondary(int cpu, struct task_struct *idle)
+{
+ unsigned long startargs[4];
+
+ pr_info("Booting CPU#%d...\n", cpu);
+
+ /* startargs[] are initial PC, SP and GP for secondary CPU */
+ startargs[0] = (unsigned long)&smp_bootstrap;
+ startargs[1] = (unsigned long)__KSTK_TOS(idle);
+ startargs[2] = (unsigned long)task_thread_info(idle);
+ startargs[3] = 0;
+
+ pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n",
+ cpu, startargs[0], startargs[1], startargs[2]);
+
+ loongson3_ipi_write64(startargs[3], (void *)(ipi_mailbox_buf[cpu]+0x18));
+ loongson3_ipi_write64(startargs[2], (void *)(ipi_mailbox_buf[cpu]+0x10));
+ loongson3_ipi_write64(startargs[1], (void *)(ipi_mailbox_buf[cpu]+0x8));
+ loongson3_ipi_write64(startargs[0], (void *)(ipi_mailbox_buf[cpu]+0x0));
+}
+
+/*
+ * Final cleanup after all secondaries booted
+ */
+static void __init loongson3_cpus_done(void)
+{
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+static int loongson3_cpu_disable(void)
+{
+ unsigned long flags;
+ unsigned int cpu = smp_processor_id();
+
+ if (cpu == 0)
+ return -EBUSY;
+
+ set_cpu_online(cpu, false);
+ cpu_clear(cpu, cpu_callin_map);
+ local_irq_save(flags);
+ fixup_irqs();
+ local_irq_restore(flags);
+ flush_cache_all();
+ local_flush_tlb_all();
+
+ return 0;
+}
+
+
+static void loongson3_cpu_die(unsigned int cpu)
+{
+ while (per_cpu(cpu_state, cpu) != CPU_DEAD)
+ cpu_relax();
+
+ mb();
+}
+
+/* To shutdown a core in Loongson 3, the target core should go to CKSEG1 and
+ * flush all L1 entries at first. Then, another core (usually Core 0) can
+ * safely disable the clock of the target core. loongson3_play_dead() is
+ * called via CKSEG1 (uncached and unmmaped) */
+static void loongson3_play_dead(int *state_addr)
+{
+ register int val;
+ register long cpuid, core, node, count;
+ register void *addr, *base, *initfunc;
+
+ __asm__ __volatile__(
+ " .set push \n"
+ " .set noreorder \n"
+ " li %[addr], 0x80000000 \n" /* KSEG0 */
+ "1: cache 0, 0(%[addr]) \n" /* flush L1 ICache */
+ " cache 0, 1(%[addr]) \n"
+ " cache 0, 2(%[addr]) \n"
+ " cache 0, 3(%[addr]) \n"
+ " cache 1, 0(%[addr]) \n" /* flush L1 DCache */
+ " cache 1, 1(%[addr]) \n"
+ " cache 1, 2(%[addr]) \n"
+ " cache 1, 3(%[addr]) \n"
+ " addiu %[sets], %[sets], -1 \n"
+ " bnez %[sets], 1b \n"
+ " addiu %[addr], %[addr], 0x20 \n"
+ " li %[val], 0x7 \n" /* *state_addr = CPU_DEAD; */
+ " sw %[val], (%[state_addr]) \n"
+ " sync \n"
+ " cache 21, (%[state_addr]) \n" /* flush entry of *state_addr */
+ " .set pop \n"
+ : [addr] "=&r" (addr), [val] "=&r" (val)
+ : [state_addr] "r" (state_addr),
+ [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
+
+ __asm__ __volatile__(
+ " .set push \n"
+ " .set noreorder \n"
+ " .set mips64 \n"
+ " mfc0 %[cpuid], $15, 1 \n"
+ " andi %[cpuid], 0x3ff \n"
+ " dli %[base], 0x900000003ff01000 \n"
+ " andi %[core], %[cpuid], 0x3 \n"
+ " sll %[core], 8 \n" /* get core id */
+ " or %[base], %[base], %[core] \n"
+ " andi %[node], %[cpuid], 0xc \n"
+ " dsll %[node], 42 \n" /* get node id */
+ " or %[base], %[base], %[node] \n"
+ "1: li %[count], 0x100 \n" /* wait for init loop */
+ "2: bnez %[count], 2b \n" /* limit mailbox access */
+ " addiu %[count], -1 \n"
+ " ld %[initfunc], 0x20(%[base]) \n" /* get PC via mailbox */
+ " beqz %[initfunc], 1b \n"
+ " nop \n"
+ " ld $sp, 0x28(%[base]) \n" /* get SP via mailbox */
+ " ld $gp, 0x30(%[base]) \n" /* get GP via mailbox */
+ " ld $a1, 0x38(%[base]) \n"
+ " jr %[initfunc] \n" /* jump to initial PC */
+ " nop \n"
+ " .set pop \n"
+ : [core] "=&r" (core), [node] "=&r" (node),
+ [base] "=&r" (base), [cpuid] "=&r" (cpuid),
+ [count] "=&r" (count), [initfunc] "=&r" (initfunc)
+ : /* No Input */
+ : "a1");
+}
+
+void play_dead(void)
+{
+ int *state_addr;
+ unsigned int cpu = smp_processor_id();
+ void (*play_dead_at_ckseg1)(int *);
+
+ idle_task_exit();
+ play_dead_at_ckseg1 =
+ (void *)CKSEG1ADDR((unsigned long)loongson3_play_dead);
+ state_addr = &per_cpu(cpu_state, cpu);
+ mb();
+ play_dead_at_ckseg1(state_addr);
+}
+
+#define CPU_POST_DEAD_FROZEN (CPU_POST_DEAD | CPU_TASKS_FROZEN)
+static int loongson3_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+
+ switch (action) {
+ case CPU_POST_DEAD:
+ case CPU_POST_DEAD_FROZEN:
+ pr_info("Disable clock for CPU#%d\n", cpu);
+ LOONGSON_CHIPCFG0 &= ~(1 << (12 + cpu));
+ break;
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ pr_info("Enable clock for CPU#%d\n", cpu);
+ LOONGSON_CHIPCFG0 |= 1 << (12 + cpu);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static int register_loongson3_notifier(void)
+{
+ hotcpu_notifier(loongson3_cpu_callback, 0);
+ return 0;
+}
+early_initcall(register_loongson3_notifier);
+
+#endif
+
+struct plat_smp_ops loongson3_smp_ops = {
+ .send_ipi_single = loongson3_send_ipi_single,
+ .send_ipi_mask = loongson3_send_ipi_mask,
+ .init_secondary = loongson3_init_secondary,
+ .smp_finish = loongson3_smp_finish,
+ .cpus_done = loongson3_cpus_done,
+ .boot_secondary = loongson3_boot_secondary,
+ .smp_setup = loongson3_smp_setup,
+ .prepare_cpus = loongson3_prepare_cpus,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_disable = loongson3_cpu_disable,
+ .cpu_die = loongson3_cpu_die,
+#endif
+};
diff --git a/arch/mips/loongson/loongson-3/smp.h b/arch/mips/loongson/loongson-3/smp.h
new file mode 100644
index 000000000000..3453e8c4f2f0
--- /dev/null
+++ b/arch/mips/loongson/loongson-3/smp.h
@@ -0,0 +1,29 @@
+#ifndef __LOONGSON_SMP_H_
+#define __LOONGSON_SMP_H_
+
+/* for Loongson-3A smp support */
+
+/* 4 groups(nodes) in maximum in numa case */
+#define SMP_CORE_GROUP0_BASE 0x900000003ff01000
+#define SMP_CORE_GROUP1_BASE 0x900010003ff01000
+#define SMP_CORE_GROUP2_BASE 0x900020003ff01000
+#define SMP_CORE_GROUP3_BASE 0x900030003ff01000
+
+/* 4 cores in each group(node) */
+#define SMP_CORE0_OFFSET 0x000
+#define SMP_CORE1_OFFSET 0x100
+#define SMP_CORE2_OFFSET 0x200
+#define SMP_CORE3_OFFSET 0x300
+
+/* ipi registers offsets */
+#define STATUS0 0x00
+#define EN0 0x04
+#define SET0 0x08
+#define CLEAR0 0x0c
+#define STATUS1 0x10
+#define MASK1 0x14
+#define SET1 0x18
+#define CLEAR1 0x1c
+#define BUF 0x20
+
+#endif
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index 506925b2c3f3..7b3c9acae689 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -876,20 +876,43 @@ static inline int cop1_64bit(struct pt_regs *xcp)
#endif
}
-#define SIFROMREG(si, x) ((si) = cop1_64bit(xcp) || !(x & 1) ? \
- (int)ctx->fpr[x] : (int)(ctx->fpr[x & ~1] >> 32))
-
-#define SITOREG(si, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = \
- cop1_64bit(xcp) || !(x & 1) ? \
- ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \
- ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32)
-
-#define SIFROMHREG(si, x) ((si) = (int)(ctx->fpr[x] >> 32))
-#define SITOHREG(si, x) (ctx->fpr[x] = \
- ctx->fpr[x] << 32 >> 32 | (u64)(si) << 32)
-
-#define DIFROMREG(di, x) ((di) = ctx->fpr[x & ~(cop1_64bit(xcp) == 0)])
-#define DITOREG(di, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = (di))
+#define SIFROMREG(si, x) do { \
+ if (cop1_64bit(xcp)) \
+ (si) = get_fpr32(&ctx->fpr[x], 0); \
+ else \
+ (si) = get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \
+} while (0)
+
+#define SITOREG(si, x) do { \
+ if (cop1_64bit(xcp)) { \
+ unsigned i; \
+ set_fpr32(&ctx->fpr[x], 0, si); \
+ for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \
+ set_fpr32(&ctx->fpr[x], i, 0); \
+ } else { \
+ set_fpr32(&ctx->fpr[(x) & ~1], (x) & 1, si); \
+ } \
+} while (0)
+
+#define SIFROMHREG(si, x) ((si) = get_fpr32(&ctx->fpr[x], 1))
+
+#define SITOHREG(si, x) do { \
+ unsigned i; \
+ set_fpr32(&ctx->fpr[x], 1, si); \
+ for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \
+ set_fpr32(&ctx->fpr[x], i, 0); \
+} while (0)
+
+#define DIFROMREG(di, x) \
+ ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0))
+
+#define DITOREG(di, x) do { \
+ unsigned fpr, i; \
+ fpr = (x) & ~(cop1_64bit(xcp) == 0); \
+ set_fpr64(&ctx->fpr[fpr], 0, di); \
+ for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val64); i++) \
+ set_fpr64(&ctx->fpr[fpr], i, 0); \
+} while (0)
#define SPFROMREG(sp, x) SIFROMREG((sp).bits, x)
#define SPTOREG(sp, x) SITOREG((sp).bits, x)
@@ -1538,10 +1561,10 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
break;
}
- case 0x7: /* 7 */
- if (MIPSInst_FUNC(ir) != pfetch_op) {
+ case 0x3:
+ if (MIPSInst_FUNC(ir) != pfetch_op)
return SIGILL;
- }
+
/* ignore prefx operation */
break;
@@ -1960,15 +1983,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
#if defined(__mips64)
case l_fmt:{
+ u64 bits;
+ DIFROMREG(bits, MIPSInst_FS(ir));
+
switch (MIPSInst_FUNC(ir)) {
case fcvts_op:
/* convert long to single precision real */
- rv.s = ieee754sp_flong(ctx->fpr[MIPSInst_FS(ir)]);
+ rv.s = ieee754sp_flong(bits);
rfmt = s_fmt;
goto copcsr;
case fcvtd_op:
/* convert long to double precision real */
- rv.d = ieee754dp_flong(ctx->fpr[MIPSInst_FS(ir)]);
+ rv.d = ieee754dp_flong(bits);
rfmt = d_fmt;
goto copcsr;
default:
diff --git a/arch/mips/math-emu/kernel_linkage.c b/arch/mips/math-emu/kernel_linkage.c
index 3aeae07ed5b8..eb58a85b3157 100644
--- a/arch/mips/math-emu/kernel_linkage.c
+++ b/arch/mips/math-emu/kernel_linkage.c
@@ -40,78 +40,6 @@ void fpu_emulator_init_fpu(void)
}
current->thread.fpu.fcr31 = 0;
- for (i = 0; i < 32; i++) {
- current->thread.fpu.fpr[i] = SIGNALLING_NAN;
- }
-}
-
-
-/*
- * Emulator context save/restore to/from a signal context
- * presumed to be on the user stack, and therefore accessed
- * with appropriate macros from uaccess.h
- */
-
-int fpu_emulator_save_context(struct sigcontext __user *sc)
-{
- int i;
- int err = 0;
-
- for (i = 0; i < 32; i++) {
- err |=
- __put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
- }
- err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
-
- return err;
-}
-
-int fpu_emulator_restore_context(struct sigcontext __user *sc)
-{
- int i;
- int err = 0;
-
- for (i = 0; i < 32; i++) {
- err |=
- __get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
- }
- err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
-
- return err;
-}
-
-#ifdef CONFIG_64BIT
-/*
- * This is the o32 version
- */
-
-int fpu_emulator_save_context32(struct sigcontext32 __user *sc)
-{
- int i;
- int err = 0;
- int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
-
- for (i = 0; i < 32; i += inc) {
- err |=
- __put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
- }
- err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
-
- return err;
-}
-
-int fpu_emulator_restore_context32(struct sigcontext32 __user *sc)
-{
- int i;
- int err = 0;
- int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
-
- for (i = 0; i < 32; i += inc) {
- err |=
- __get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
- }
- err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr);
-
- return err;
+ for (i = 0; i < 32; i++)
+ set_fpr64(&current->thread.fpu.fpr[i], 0, SIGNALLING_NAN);
}
-#endif
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index c14259edd53f..1c74a6ad072a 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -57,7 +57,7 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info)
preempt_enable();
}
-#if defined(CONFIG_MIPS_CMP)
+#if defined(CONFIG_MIPS_CMP) || defined(CONFIG_MIPS_CPS)
#define cpu_has_safe_index_cacheops 0
#else
#define cpu_has_safe_index_cacheops 1
@@ -123,6 +123,28 @@ static void r4k_blast_dcache_page_setup(void)
r4k_blast_dcache_page = r4k_blast_dcache_page_dc64;
}
+#ifndef CONFIG_EVA
+#define r4k_blast_dcache_user_page r4k_blast_dcache_page
+#else
+
+static void (*r4k_blast_dcache_user_page)(unsigned long addr);
+
+static void r4k_blast_dcache_user_page_setup(void)
+{
+ unsigned long dc_lsize = cpu_dcache_line_size();
+
+ if (dc_lsize == 0)
+ r4k_blast_dcache_user_page = (void *)cache_noop;
+ else if (dc_lsize == 16)
+ r4k_blast_dcache_user_page = blast_dcache16_user_page;
+ else if (dc_lsize == 32)
+ r4k_blast_dcache_user_page = blast_dcache32_user_page;
+ else if (dc_lsize == 64)
+ r4k_blast_dcache_user_page = blast_dcache64_user_page;
+}
+
+#endif
+
static void (* r4k_blast_dcache_page_indexed)(unsigned long addr);
static void r4k_blast_dcache_page_indexed_setup(void)
@@ -245,6 +267,27 @@ static void r4k_blast_icache_page_setup(void)
r4k_blast_icache_page = blast_icache64_page;
}
+#ifndef CONFIG_EVA
+#define r4k_blast_icache_user_page r4k_blast_icache_page
+#else
+
+static void (*r4k_blast_icache_user_page)(unsigned long addr);
+
+static void __cpuinit r4k_blast_icache_user_page_setup(void)
+{
+ unsigned long ic_lsize = cpu_icache_line_size();
+
+ if (ic_lsize == 0)
+ r4k_blast_icache_user_page = (void *)cache_noop;
+ else if (ic_lsize == 16)
+ r4k_blast_icache_user_page = blast_icache16_user_page;
+ else if (ic_lsize == 32)
+ r4k_blast_icache_user_page = blast_icache32_user_page;
+ else if (ic_lsize == 64)
+ r4k_blast_icache_user_page = blast_icache64_user_page;
+}
+
+#endif
static void (* r4k_blast_icache_page_indexed)(unsigned long addr);
@@ -355,6 +398,7 @@ static inline void local_r4k___flush_cache_all(void * args)
{
switch (current_cpu_type()) {
case CPU_LOONGSON2:
+ case CPU_LOONGSON3:
case CPU_R4000SC:
case CPU_R4000MC:
case CPU_R4400SC:
@@ -519,7 +563,8 @@ static inline void local_r4k_flush_cache_page(void *args)
}
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
- r4k_blast_dcache_page(addr);
+ vaddr ? r4k_blast_dcache_page(addr) :
+ r4k_blast_dcache_user_page(addr);
if (exec && !cpu_icache_snoops_remote_store)
r4k_blast_scache_page(addr);
}
@@ -530,7 +575,8 @@ static inline void local_r4k_flush_cache_page(void *args)
if (cpu_context(cpu, mm) != 0)
drop_mmu_context(mm, cpu);
} else
- r4k_blast_icache_page(addr);
+ vaddr ? r4k_blast_icache_page(addr) :
+ r4k_blast_icache_user_page(addr);
}
if (vaddr) {
@@ -595,6 +641,17 @@ static inline void local_r4k_flush_icache_range(unsigned long start, unsigned lo
break;
}
}
+#ifdef CONFIG_EVA
+ /*
+ * Due to all possible segment mappings, there might cache aliases
+ * caused by the bootloader being in non-EVA mode, and the CPU switching
+ * to EVA during early kernel init. It's best to flush the scache
+ * to avoid having secondary cores fetching stale data and lead to
+ * kernel crashes.
+ */
+ bc_wback_inv(start, (end - start));
+ __sync();
+#endif
}
static inline void local_r4k_flush_icache_range_ipi(void *args)
@@ -617,7 +674,7 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end)
instruction_hazard();
}
-#ifdef CONFIG_DMA_NONCOHERENT
+#if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT)
static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
{
@@ -688,7 +745,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
bc_inv(addr, size);
__sync();
}
-#endif /* CONFIG_DMA_NONCOHERENT */
+#endif /* CONFIG_DMA_NONCOHERENT || CONFIG_DMA_MAYBE_COHERENT */
/*
* While we're protected against bad userland addresses we don't care
@@ -1010,6 +1067,33 @@ static void probe_pcache(void)
c->dcache.waybit = 0;
break;
+ case CPU_LOONGSON3:
+ config1 = read_c0_config1();
+ lsize = (config1 >> 19) & 7;
+ if (lsize)
+ c->icache.linesz = 2 << lsize;
+ else
+ c->icache.linesz = 0;
+ c->icache.sets = 64 << ((config1 >> 22) & 7);
+ c->icache.ways = 1 + ((config1 >> 16) & 7);
+ icache_size = c->icache.sets *
+ c->icache.ways *
+ c->icache.linesz;
+ c->icache.waybit = 0;
+
+ lsize = (config1 >> 10) & 7;
+ if (lsize)
+ c->dcache.linesz = 2 << lsize;
+ else
+ c->dcache.linesz = 0;
+ c->dcache.sets = 64 << ((config1 >> 13) & 7);
+ c->dcache.ways = 1 + ((config1 >> 7) & 7);
+ dcache_size = c->dcache.sets *
+ c->dcache.ways *
+ c->dcache.linesz;
+ c->dcache.waybit = 0;
+ break;
+
default:
if (!(config & MIPS_CONF_M))
panic("Don't know how to probe P-caches on this cpu.");
@@ -1113,13 +1197,21 @@ static void probe_pcache(void)
case CPU_34K:
case CPU_74K:
case CPU_1004K:
+ case CPU_1074K:
case CPU_INTERAPTIV:
+ case CPU_P5600:
case CPU_PROAPTIV:
- if (current_cpu_type() == CPU_74K)
+ case CPU_M5150:
+ if ((c->cputype == CPU_74K) || (c->cputype == CPU_1074K))
alias_74k_erratum(c);
- if ((read_c0_config7() & (1 << 16))) {
- /* effectively physically indexed dcache,
- thus no virtual aliases. */
+ if (!(read_c0_config7() & MIPS_CONF7_IAR) &&
+ (c->icache.waysize > PAGE_SIZE))
+ c->icache.flags |= MIPS_CACHE_ALIASES;
+ if (read_c0_config7() & MIPS_CONF7_AR) {
+ /*
+ * Effectively physically indexed dcache,
+ * thus no virtual aliases.
+ */
c->dcache.flags |= MIPS_CACHE_PINDEX;
break;
}
@@ -1239,6 +1331,33 @@ static void __init loongson2_sc_init(void)
c->options |= MIPS_CPU_INCLUSIVE_CACHES;
}
+static void __init loongson3_sc_init(void)
+{
+ struct cpuinfo_mips *c = &current_cpu_data;
+ unsigned int config2, lsize;
+
+ config2 = read_c0_config2();
+ lsize = (config2 >> 4) & 15;
+ if (lsize)
+ c->scache.linesz = 2 << lsize;
+ else
+ c->scache.linesz = 0;
+ c->scache.sets = 64 << ((config2 >> 8) & 15);
+ c->scache.ways = 1 + (config2 & 15);
+
+ scache_size = c->scache.sets *
+ c->scache.ways *
+ c->scache.linesz;
+ /* Loongson-3 has 4 cores, 1MB scache for each. scaches are shared */
+ scache_size *= 4;
+ c->scache.waybit = 0;
+ pr_info("Unified secondary cache %ldkB %s, linesize %d bytes.\n",
+ scache_size >> 10, way_string[c->scache.ways], c->scache.linesz);
+ if (scache_size)
+ c->options |= MIPS_CPU_INCLUSIVE_CACHES;
+ return;
+}
+
extern int r5k_sc_init(void);
extern int rm7k_sc_init(void);
extern int mips_sc_init(void);
@@ -1291,6 +1410,10 @@ static void setup_scache(void)
loongson2_sc_init();
return;
+ case CPU_LOONGSON3:
+ loongson3_sc_init();
+ return;
+
case CPU_XLP:
/* don't need to worry about L2, fully coherent */
return;
@@ -1461,6 +1584,10 @@ void r4k_cache_init(void)
r4k_blast_scache_page_setup();
r4k_blast_scache_page_indexed_setup();
r4k_blast_scache_setup();
+#ifdef CONFIG_EVA
+ r4k_blast_dcache_user_page_setup();
+ r4k_blast_icache_user_page_setup();
+#endif
/*
* Some MIPS32 and MIPS64 processors have physically indexed caches.
@@ -1492,7 +1619,7 @@ void r4k_cache_init(void)
flush_icache_range = r4k_flush_icache_range;
local_flush_icache_range = local_r4k_flush_icache_range;
-#if defined(CONFIG_DMA_NONCOHERENT)
+#if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT)
if (coherentio) {
_dma_cache_wback_inv = (void *)cache_noop;
_dma_cache_wback = (void *)cache_noop;
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index fde7e56d13fe..e422b38d3113 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -49,7 +49,7 @@ EXPORT_SYMBOL_GPL(local_flush_data_cache_page);
EXPORT_SYMBOL(flush_data_cache_page);
EXPORT_SYMBOL(flush_icache_all);
-#ifdef CONFIG_DMA_NONCOHERENT
+#if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT)
/* DMA cache operations. */
void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size);
@@ -58,7 +58,7 @@ void (*_dma_cache_inv)(unsigned long start, unsigned long size);
EXPORT_SYMBOL(_dma_cache_wback_inv);
-#endif /* CONFIG_DMA_NONCOHERENT */
+#endif /* CONFIG_DMA_NONCOHERENT || CONFIG_DMA_MAYBE_COHERENT */
/*
* We could optimize the case where the cache argument is not BCACHE but
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 6b59617760c1..4fc74c78265a 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -422,10 +422,20 @@ void free_initrd_mem(unsigned long start, unsigned long end)
}
#endif
+void (*free_init_pages_eva)(void *begin, void *end) = NULL;
+
void __init_refok free_initmem(void)
{
prom_free_prom_memory();
- free_initmem_default(POISON_FREE_INITMEM);
+ /*
+ * Let the platform define a specific function to free the
+ * init section since EVA may have used any possible mapping
+ * between virtual and physical addresses.
+ */
+ if (free_init_pages_eva)
+ free_init_pages_eva((void *)&__init_begin, (void *)&__init_end);
+ else
+ free_initmem_default(POISON_FREE_INITMEM);
}
#ifndef CONFIG_MIPS_PGD_C0_CONTEXT
diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index 7a56aee5fce7..99eb8fabab60 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -76,8 +76,10 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c)
case CPU_34K:
case CPU_74K:
case CPU_1004K:
+ case CPU_1074K:
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
+ case CPU_P5600:
case CPU_BMIPS5000:
if (config2 & (1 << 12))
return 0;
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index ae4ca2450707..eeaf50f5df2b 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -48,13 +48,14 @@ extern void build_tlb_refill_handler(void);
#endif /* CONFIG_MIPS_MT_SMTC */
/*
- * LOONGSON2 has a 4 entry itlb which is a subset of dtlb,
- * unfortrunately, itlb is not totally transparent to software.
+ * LOONGSON2/3 has a 4 entry itlb which is a subset of dtlb,
+ * unfortunately, itlb is not totally transparent to software.
*/
static inline void flush_itlb(void)
{
switch (current_cpu_type()) {
case CPU_LOONGSON2:
+ case CPU_LOONGSON3:
write_c0_diag(4);
break;
default:
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index b234b1b5ccad..ee88367ab3ad 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -509,7 +509,10 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l,
switch (current_cpu_type()) {
case CPU_M14KC:
case CPU_74K:
+ case CPU_1074K:
case CPU_PROAPTIV:
+ case CPU_P5600:
+ case CPU_M5150:
break;
default:
@@ -579,6 +582,7 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l,
case CPU_BMIPS4380:
case CPU_BMIPS5000:
case CPU_LOONGSON2:
+ case CPU_LOONGSON3:
case CPU_R5500:
if (m4kc_tlbp_war())
uasm_i_nop(p);
@@ -621,7 +625,7 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l,
default:
panic("No TLB refill handler yet (CPU type: %d)",
- current_cpu_data.cputype);
+ current_cpu_type());
break;
}
}
diff --git a/arch/mips/mti-malta/malta-amon.c b/arch/mips/mti-malta/malta-amon.c
index 592ac0427426..84ac523b0ce0 100644
--- a/arch/mips/mti-malta/malta-amon.c
+++ b/arch/mips/mti-malta/malta-amon.c
@@ -72,7 +72,7 @@ int amon_cpu_start(int cpu,
return 0;
}
-#ifdef CONFIG_MIPS_VPE_LOADER
+#ifdef CONFIG_MIPS_VPE_LOADER_CMP
int vpe_run(struct vpe *v)
{
struct vpe_notifications *n;
diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c
index fcebfced26d0..4f9e44d358b7 100644
--- a/arch/mips/mti-malta/malta-init.c
+++ b/arch/mips/mti-malta/malta-init.c
@@ -20,7 +20,8 @@
#include <asm/smp-ops.h>
#include <asm/traps.h>
#include <asm/fw/fw.h>
-#include <asm/gcmpregs.h>
+#include <asm/mips-cm.h>
+#include <asm/mips-cpc.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/malta.h>
@@ -110,6 +111,11 @@ static void __init mips_ejtag_setup(void)
flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
}
+phys_t mips_cpc_default_phys_base(void)
+{
+ return CPC_BASE_ADDR;
+}
+
extern struct plat_smp_ops msmtc_smp_ops;
void __init prom_init(void)
@@ -238,10 +244,23 @@ mips_pci_controller:
MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_MEM_SHF |
MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_BAR0_SHF);
#endif
+#ifndef CONFIG_EVA
/* Fix up target memory mapping. */
MSC_READ(MSC01_PCI_BAR0, mask);
MSC_WRITE(MSC01_PCI_P2SCMSKL, mask & MSC01_PCI_BAR0_SIZE_MSK);
+#else
+ /*
+ * Setup the Malta max (2GB) memory for PCI DMA in host bridge
+ * in transparent addressing mode, starting from 0x80000000.
+ */
+ mask = PHYS_OFFSET | (1<<3);
+ MSC_WRITE(MSC01_PCI_BAR0, mask);
+ mask = PHYS_OFFSET;
+ MSC_WRITE(MSC01_PCI_HEAD4, mask);
+ MSC_WRITE(MSC01_PCI_P2SCMSKL, mask);
+ MSC_WRITE(MSC01_PCI_P2SCMAPL, mask);
+#endif
/* Don't handle target retries indefinitely. */
if ((data & MSC01_PCI_CFG_MAXRTRY_MSK) ==
MSC01_PCI_CFG_MAXRTRY_MSK)
@@ -276,10 +295,13 @@ mips_pci_controller:
console_config();
#endif
/* Early detection of CMP support */
- if (gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ))
- if (!register_cmp_smp_ops())
- return;
+ mips_cm_probe();
+ mips_cpc_probe();
+ if (!register_cps_smp_ops())
+ return;
+ if (!register_cmp_smp_ops())
+ return;
if (!register_vsmp_smp_ops())
return;
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index ca3e3a46a42f..b71ee809191a 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -26,6 +26,7 @@
#include <asm/i8259.h>
#include <asm/irq_cpu.h>
#include <asm/irq_regs.h>
+#include <asm/mips-cm.h>
#include <asm/mips-boards/malta.h>
#include <asm/mips-boards/maltaint.h>
#include <asm/gt64120.h>
@@ -33,13 +34,10 @@
#include <asm/mips-boards/msc01_pci.h>
#include <asm/msc01_ic.h>
#include <asm/gic.h>
-#include <asm/gcmpregs.h>
#include <asm/setup.h>
#include <asm/rtlx.h>
-int gcmp_present = -1;
static unsigned long _msc01_biu_base;
-static unsigned long _gcmp_base;
static unsigned int ipi_map[NR_CPUS];
static DEFINE_RAW_SPINLOCK(mips_irq_lock);
@@ -119,7 +117,7 @@ static void malta_hw0_irqdispatch(void)
do_IRQ(MALTA_INT_BASE + irq);
-#ifdef MIPS_VPE_APSP_API
+#ifdef CONFIG_MIPS_VPE_APSP_API_MT
if (aprp_hook)
aprp_hook();
#endif
@@ -288,10 +286,6 @@ asmlinkage void plat_irq_dispatch(void)
#ifdef CONFIG_MIPS_MT_SMP
-
-#define GIC_MIPS_CPU_IPI_RESCHED_IRQ 3
-#define GIC_MIPS_CPU_IPI_CALL_IRQ 4
-
#define MIPS_CPU_IPI_RESCHED_IRQ 0 /* SW int 0 for resched */
#define C_RESCHED C_SW0
#define MIPS_CPU_IPI_CALL_IRQ 1 /* SW int 1 for resched */
@@ -308,9 +302,16 @@ static void ipi_call_dispatch(void)
do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
}
+#endif /* CONFIG_MIPS_MT_SMP */
+
+#ifdef CONFIG_MIPS_GIC_IPI
+
+#define GIC_MIPS_CPU_IPI_RESCHED_IRQ 3
+#define GIC_MIPS_CPU_IPI_CALL_IRQ 4
+
static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
{
-#ifdef MIPS_VPE_APSP_API
+#ifdef CONFIG_MIPS_VPE_APSP_API_CMP
if (aprp_hook)
aprp_hook();
#endif
@@ -338,7 +339,7 @@ static struct irqaction irq_call = {
.flags = IRQF_PERCPU,
.name = "IPI_call"
};
-#endif /* CONFIG_MIPS_MT_SMP */
+#endif /* CONFIG_MIPS_GIC_IPI */
static int gic_resched_int_base;
static int gic_call_int_base;
@@ -418,49 +419,7 @@ static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = {
};
#undef X
-/*
- * GCMP needs to be detected before any SMP initialisation
- */
-int __init gcmp_probe(unsigned long addr, unsigned long size)
-{
- if ((mips_revision_sconid != MIPS_REVISION_SCON_ROCIT) &&
- (mips_revision_sconid != MIPS_REVISION_SCON_GT64120)) {
- gcmp_present = 0;
- pr_debug("GCMP NOT present\n");
- return gcmp_present;
- }
-
- if (gcmp_present >= 0)
- return gcmp_present;
-
- _gcmp_base = (unsigned long) ioremap_nocache(GCMP_BASE_ADDR,
- GCMP_ADDRSPACE_SZ);
- _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE,
- MSC01_BIU_ADDRSPACE_SZ);
- gcmp_present = ((GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) ==
- GCMP_BASE_ADDR);
-
- if (gcmp_present)
- pr_debug("GCMP present\n");
- return gcmp_present;
-}
-
-/* Return the number of IOCU's present */
-int __init gcmp_niocu(void)
-{
- return gcmp_present ? ((GCMPGCB(GC) & GCMP_GCB_GC_NUMIOCU_MSK) >>
- GCMP_GCB_GC_NUMIOCU_SHF) : 0;
-}
-
-/* Set GCMP region attributes */
-void __init gcmp_setregion(int region, unsigned long base,
- unsigned long mask, int type)
-{
- GCMPGCBn(CMxBASE, region) = base;
- GCMPGCBn(CMxMASK, region) = mask | type;
-}
-
-#if defined(CONFIG_MIPS_MT_SMP)
+#ifdef CONFIG_MIPS_GIC_IPI
static void __init fill_ipi_map1(int baseintr, int cpu, int cpupin)
{
int intr = baseintr + cpu;
@@ -496,8 +455,8 @@ void __init arch_init_irq(void)
if (!cpu_has_veic)
mips_cpu_irq_init();
- if (gcmp_present) {
- GCMPGCB(GICBA) = GIC_BASE_ADDR | GCMP_GCB_GICBA_EN_MSK;
+ if (mips_cm_present()) {
+ write_gcr_gic_base(GIC_BASE_ADDR | CM_GCR_GIC_BASE_GICEN_MSK);
gic_present = 1;
} else {
if (mips_revision_sconid == MIPS_REVISION_SCON_ROCIT) {
@@ -576,7 +535,7 @@ void __init arch_init_irq(void)
if (gic_present) {
/* FIXME */
int i;
-#if defined(CONFIG_MIPS_MT_SMP)
+#if defined(CONFIG_MIPS_GIC_IPI)
gic_call_int_base = GIC_NUM_INTRS -
(NR_CPUS - nr_cpu_ids) * 2 - nr_cpu_ids;
gic_resched_int_base = gic_call_int_base - nr_cpu_ids;
@@ -584,14 +543,14 @@ void __init arch_init_irq(void)
#endif
gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map,
ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
- if (!gcmp_present) {
+ if (!mips_cm_present()) {
/* Enable the GIC */
i = REG(_msc01_biu_base, MSC01_SC_CFG);
REG(_msc01_biu_base, MSC01_SC_CFG) =
(i | (0x1 << MSC01_SC_CFG_GICENA_SHF));
pr_debug("GIC Enabled\n");
}
-#if defined(CONFIG_MIPS_MT_SMP)
+#if defined(CONFIG_MIPS_GIC_IPI)
/* set up ipi interrupts */
if (cpu_has_vint) {
set_vi_handler(MIPSCPU_INT_IPI0, malta_ipi_irqdispatch);
@@ -708,16 +667,16 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
/* This duplicates the handling in do_be which seems wrong */
int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
- if (gcmp_present) {
- unsigned long cm_error = GCMPGCB(GCMEC);
- unsigned long cm_addr = GCMPGCB(GCMEA);
- unsigned long cm_other = GCMPGCB(GCMEO);
+ if (mips_cm_present()) {
+ unsigned long cm_error = read_gcr_error_cause();
+ unsigned long cm_addr = read_gcr_error_addr();
+ unsigned long cm_other = read_gcr_error_mult();
unsigned long cause, ocause;
char buf[256];
- cause = (cm_error & GCMP_GCB_GMEC_ERROR_TYPE_MSK);
+ cause = cm_error & CM_GCR_ERROR_CAUSE_ERRTYPE_MSK;
if (cause != 0) {
- cause >>= GCMP_GCB_GMEC_ERROR_TYPE_SHF;
+ cause >>= CM_GCR_ERROR_CAUSE_ERRTYPE_SHF;
if (cause < 16) {
unsigned long cca_bits = (cm_error >> 15) & 7;
unsigned long tr_bits = (cm_error >> 12) & 7;
@@ -748,8 +707,8 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
mcmd[cmd_bits], sport_bits);
}
- ocause = (cm_other & GCMP_GCB_GMEO_ERROR_2ND_MSK) >>
- GCMP_GCB_GMEO_ERROR_2ND_SHF;
+ ocause = (cm_other & CM_GCR_ERROR_MULT_ERR2ND_MSK) >>
+ CM_GCR_ERROR_MULT_ERR2ND_SHF;
pr_err("CM_ERROR=%08lx %s <%s>\n", cm_error,
causes[cause], buf);
@@ -757,7 +716,7 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
pr_err("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]);
/* reprime cause register */
- GCMPGCB(GCMEC) = 0;
+ write_gcr_error_cause(0);
}
}
diff --git a/arch/mips/mti-malta/malta-memory.c b/arch/mips/mti-malta/malta-memory.c
index 1f73d63e92a7..6d0f4ab3632d 100644
--- a/arch/mips/mti-malta/malta-memory.c
+++ b/arch/mips/mti-malta/malta-memory.c
@@ -24,22 +24,30 @@ static fw_memblock_t mdesc[FW_MAX_MEMBLOCKS];
/* determined physical memory size, not overridden by command line args */
unsigned long physical_memsize = 0L;
-fw_memblock_t * __init fw_getmdesc(void)
+fw_memblock_t * __init fw_getmdesc(int eva)
{
- char *memsize_str, *ptr;
- unsigned int memsize;
+ char *memsize_str, *ememsize_str __maybe_unused = NULL, *ptr;
+ unsigned long memsize, ememsize __maybe_unused = 0;
static char cmdline[COMMAND_LINE_SIZE] __initdata;
- long val;
int tmp;
/* otherwise look in the environment */
+
memsize_str = fw_getenv("memsize");
- if (!memsize_str) {
+ if (memsize_str)
+ tmp = kstrtol(memsize_str, 0, &memsize);
+ if (eva) {
+ /* Look for ememsize for EVA */
+ ememsize_str = fw_getenv("ememsize");
+ if (ememsize_str)
+ tmp = kstrtol(ememsize_str, 0, &ememsize);
+ }
+ if (!memsize && !ememsize) {
pr_warn("memsize not set in YAMON, set to default (32Mb)\n");
physical_memsize = 0x02000000;
} else {
- tmp = kstrtol(memsize_str, 0, &val);
- physical_memsize = (unsigned long)val;
+ /* If ememsize is set, then set physical_memsize to that */
+ physical_memsize = ememsize ? : memsize;
}
#ifdef CONFIG_CPU_BIG_ENDIAN
@@ -54,20 +62,30 @@ fw_memblock_t * __init fw_getmdesc(void)
ptr = strstr(cmdline, "memsize=");
if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' '))
ptr = strstr(ptr, " memsize=");
+ /* And now look for ememsize */
+ if (eva) {
+ ptr = strstr(cmdline, "ememsize=");
+ if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' '))
+ ptr = strstr(ptr, " ememsize=");
+ }
if (ptr)
- memsize = memparse(ptr + 8, &ptr);
+ memsize = memparse(ptr + 8 + (eva ? 1 : 0), &ptr);
else
memsize = physical_memsize;
+ /* Last 64K for HIGHMEM arithmetics */
+ if (memsize > 0x7fff0000)
+ memsize = 0x7fff0000;
+
memset(mdesc, 0, sizeof(mdesc));
mdesc[0].type = fw_dontuse;
- mdesc[0].base = 0x00000000;
+ mdesc[0].base = PHYS_OFFSET;
mdesc[0].size = 0x00001000;
mdesc[1].type = fw_code;
- mdesc[1].base = 0x00001000;
+ mdesc[1].base = mdesc[0].base + 0x00001000UL;
mdesc[1].size = 0x000ef000;
/*
@@ -78,21 +96,27 @@ fw_memblock_t * __init fw_getmdesc(void)
* devices.
*/
mdesc[2].type = fw_dontuse;
- mdesc[2].base = 0x000f0000;
+ mdesc[2].base = mdesc[0].base + 0x000f0000UL;
mdesc[2].size = 0x00010000;
mdesc[3].type = fw_dontuse;
- mdesc[3].base = 0x00100000;
+ mdesc[3].base = mdesc[0].base + 0x00100000UL;
mdesc[3].size = CPHYSADDR(PFN_ALIGN((unsigned long)&_end)) -
- mdesc[3].base;
+ 0x00100000UL;
mdesc[4].type = fw_free;
- mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end));
- mdesc[4].size = memsize - mdesc[4].base;
+ mdesc[4].base = mdesc[0].base + CPHYSADDR(PFN_ALIGN(&_end));
+ mdesc[4].size = memsize - CPHYSADDR(mdesc[4].base);
return &mdesc[0];
}
+static void free_init_pages_eva_malta(void *begin, void *end)
+{
+ free_init_pages("unused kernel", __pa_symbol((unsigned long *)begin),
+ __pa_symbol((unsigned long *)end));
+}
+
static int __init fw_memtype_classify(unsigned int type)
{
switch (type) {
@@ -109,7 +133,9 @@ void __init fw_meminit(void)
{
fw_memblock_t *p;
- p = fw_getmdesc();
+ p = fw_getmdesc(config_enabled(CONFIG_EVA));
+ free_init_pages_eva = (config_enabled(CONFIG_EVA) ?
+ free_init_pages_eva_malta : NULL);
while (p->size) {
long type;
diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c
index c72a06936781..bf621516afff 100644
--- a/arch/mips/mti-malta/malta-setup.c
+++ b/arch/mips/mti-malta/malta-setup.c
@@ -26,12 +26,12 @@
#include <linux/time.h>
#include <asm/fw/fw.h>
+#include <asm/mips-cm.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/malta.h>
#include <asm/mips-boards/maltaint.h>
#include <asm/dma.h>
#include <asm/traps.h>
-#include <asm/gcmpregs.h>
#ifdef CONFIG_VT
#include <linux/console.h>
#endif
@@ -127,7 +127,7 @@ static int __init plat_enable_iocoherency(void)
BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
pr_info("Enabled Bonito IOBC coherency\n");
}
- } else if (gcmp_niocu() != 0) {
+ } else if (mips_cm_numiocu() != 0) {
/* Nothing special needs to be done to enable coherency */
pr_info("CMP IOCU detected\n");
if ((*(unsigned int *)0xbf403000 & 0x81) != 0x81) {
@@ -165,7 +165,6 @@ static void __init plat_setup_iocoherency(void)
#endif
}
-#ifdef CONFIG_BLK_DEV_IDE
static void __init pci_clock_check(void)
{
unsigned int __iomem *jmpr_p =
@@ -175,18 +174,25 @@ static void __init pci_clock_check(void)
33, 20, 25, 30, 12, 16, 37, 10
};
int pciclock = pciclocks[jmpr];
- char *argptr = fw_getcmdline();
+ char *optptr, *argptr = fw_getcmdline();
- if (pciclock != 33 && !strstr(argptr, "idebus=")) {
- pr_warn("WARNING: PCI clock is %dMHz, setting idebus\n",
+ /*
+ * If user passed a pci_clock= option, don't tack on another one
+ */
+ optptr = strstr(argptr, "pci_clock=");
+ if (optptr && (optptr == argptr || optptr[-1] == ' '))
+ return;
+
+ if (pciclock != 33) {
+ pr_warn("WARNING: PCI clock is %dMHz, setting pci_clock\n",
pciclock);
argptr += strlen(argptr);
- sprintf(argptr, " idebus=%d", pciclock);
+ sprintf(argptr, " pci_clock=%d", pciclock);
if (pciclock < 20 || pciclock > 66)
- pr_warn("WARNING: IDE timing calculations will be incorrect\n");
+ pr_warn("WARNING: IDE timing calculations will be "
+ "incorrect\n");
}
}
-#endif
#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
static void __init screen_info_setup(void)
@@ -247,6 +253,10 @@ void __init plat_mem_setup(void)
{
unsigned int i;
+ if (config_enabled(CONFIG_EVA))
+ /* EVA has already been configured in mach-malta/kernel-init.h */
+ pr_info("Enhanced Virtual Addressing (EVA) activated\n");
+
mips_pcibios_init();
/* Request I/O space for devices used on the Malta board. */
@@ -268,9 +278,7 @@ void __init plat_mem_setup(void)
plat_setup_iocoherency();
-#ifdef CONFIG_BLK_DEV_IDE
pci_clock_check();
-#endif
#ifdef CONFIG_BLK_DEV_FD
fd_activate();
diff --git a/arch/mips/mti-sead3/sead3-mtd.c b/arch/mips/mti-sead3/sead3-mtd.c
index ffa35f509789..f9c890d72677 100644
--- a/arch/mips/mti-sead3/sead3-mtd.c
+++ b/arch/mips/mti-sead3/sead3-mtd.c
@@ -50,5 +50,4 @@ static int __init sead3_mtd_init(void)
return 0;
}
-
-module_init(sead3_mtd_init)
+device_initcall(sead3_mtd_init);
diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c
index 2a86e38872a7..e74732449478 100644
--- a/arch/mips/oprofile/common.c
+++ b/arch/mips/oprofile/common.c
@@ -86,8 +86,11 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
case CPU_34K:
case CPU_1004K:
case CPU_74K:
+ case CPU_1074K:
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
+ case CPU_P5600:
+ case CPU_M5150:
case CPU_LOONGSON1:
case CPU_SB1:
case CPU_SB1A:
diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c
index 4d94d75ec6f9..42821ae2d77e 100644
--- a/arch/mips/oprofile/op_model_mipsxx.c
+++ b/arch/mips/oprofile/op_model_mipsxx.c
@@ -372,6 +372,7 @@ static int __init mipsxx_init(void)
op_model_mipsxx_ops.cpu_type = "mips/34K";
break;
+ case CPU_1074K:
case CPU_74K:
op_model_mipsxx_ops.cpu_type = "mips/74K";
break;
@@ -384,6 +385,14 @@ static int __init mipsxx_init(void)
op_model_mipsxx_ops.cpu_type = "mips/proAptiv";
break;
+ case CPU_P5600:
+ op_model_mipsxx_ops.cpu_type = "mips/P5600";
+ break;
+
+ case CPU_M5150:
+ op_model_mipsxx_ops.cpu_type = "mips/M5150";
+ break;
+
case CPU_5KC:
op_model_mipsxx_ops.cpu_type = "mips/5K";
break;
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index 137f2a6feb25..d61138a177cc 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o
obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o
obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o
obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o
+obj-$(CONFIG_LEMOTE_MACH3A) += fixup-loongson3.o ops-loongson3.o
obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o
obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o
obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o
diff --git a/arch/mips/pci/fixup-loongson3.c b/arch/mips/pci/fixup-loongson3.c
new file mode 100644
index 000000000000..d708ae46d325
--- /dev/null
+++ b/arch/mips/pci/fixup-loongson3.c
@@ -0,0 +1,66 @@
+/*
+ * fixup-loongson3.c
+ *
+ * Copyright (C) 2012 Lemote, Inc.
+ * Author: Xiang Yu, xiangy@lemote.com
+ * Chen Huacai, chenhc@lemote.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 SOFTWARE IS PROVIDED ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <linux/pci.h>
+#include <boot_param.h>
+
+static void print_fixup_info(const struct pci_dev *pdev)
+{
+ dev_info(&pdev->dev, "Device %x:%x, irq %d\n",
+ pdev->vendor, pdev->device, pdev->irq);
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ print_fixup_info(dev);
+ return dev->irq;
+}
+
+static void pci_fixup_radeon(struct pci_dev *pdev)
+{
+ if (pdev->resource[PCI_ROM_RESOURCE].start)
+ return;
+
+ if (!loongson_sysconf.vgabios_addr)
+ return;
+
+ pdev->resource[PCI_ROM_RESOURCE].start =
+ loongson_sysconf.vgabios_addr;
+ pdev->resource[PCI_ROM_RESOURCE].end =
+ loongson_sysconf.vgabios_addr + 256*1024 - 1;
+ pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_COPY;
+
+ dev_info(&pdev->dev, "BAR %d: assigned %pR for Radeon ROM\n",
+ PCI_ROM_RESOURCE, &pdev->resource[PCI_ROM_RESOURCE]);
+}
+
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
+ PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_radeon);
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c
index 7a0eda782e35..2f9e52a1a750 100644
--- a/arch/mips/pci/fixup-malta.c
+++ b/arch/mips/pci/fixup-malta.c
@@ -51,6 +51,19 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
return 0;
}
+static void malta_piix_func3_base_fixup(struct pci_dev *dev)
+{
+ /* Set a sane PM I/O base address */
+ pci_write_config_word(dev, PIIX4_FUNC3_PMBA, 0x1000);
+
+ /* Enable access to the PM I/O region */
+ pci_write_config_byte(dev, PIIX4_FUNC3_PMREGMISC,
+ PIIX4_FUNC3_PMREGMISC_EN);
+}
+
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+ malta_piix_func3_base_fixup);
+
static void malta_piix_func0_fixup(struct pci_dev *pdev)
{
unsigned char reg_val;
diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c
index d37be36dc659..2b91b0e61566 100644
--- a/arch/mips/pci/msi-octeon.c
+++ b/arch/mips/pci/msi-octeon.c
@@ -150,6 +150,7 @@ msi_irq_allocated:
msg.address_lo =
((128ul << 20) + CVMX_PCI_MSI_RCV) & 0xffffffff;
msg.address_hi = ((128ul << 20) + CVMX_PCI_MSI_RCV) >> 32;
+ break;
case OCTEON_DMA_BAR_TYPE_BIG:
/* When using big bar, Bar 0 is based at 0 */
msg.address_lo = (0 + CVMX_PCI_MSI_RCV) & 0xffffffff;
diff --git a/arch/mips/pci/ops-loongson3.c b/arch/mips/pci/ops-loongson3.c
new file mode 100644
index 000000000000..46ed541a3ec7
--- /dev/null
+++ b/arch/mips/pci/ops-loongson3.c
@@ -0,0 +1,101 @@
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+
+#include <asm/mips-boards/bonito64.h>
+
+#include <loongson.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+#define HT1LO_PCICFG_BASE 0x1a000000
+#define HT1LO_PCICFG_BASE_TP1 0x1b000000
+
+static int loongson3_pci_config_access(unsigned char access_type,
+ struct pci_bus *bus, unsigned int devfn,
+ int where, u32 *data)
+{
+ unsigned char busnum = bus->number;
+ u_int64_t addr, type;
+ void *addrp;
+ int device = PCI_SLOT(devfn);
+ int function = PCI_FUNC(devfn);
+ int reg = where & ~3;
+
+ addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
+ if (busnum == 0) {
+ if (device > 31)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ addrp = (void *)(TO_UNCAC(HT1LO_PCICFG_BASE) | (addr & 0xffff));
+ type = 0;
+
+ } else {
+ addrp = (void *)(TO_UNCAC(HT1LO_PCICFG_BASE_TP1) | (addr));
+ type = 0x10000;
+ }
+
+ if (access_type == PCI_ACCESS_WRITE)
+ writel(*data, addrp);
+ else {
+ *data = readl(addrp);
+ if (*data == 0xffffffff) {
+ *data = -1;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int loongson3_pci_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ u32 data = 0;
+ int ret = loongson3_pci_config_access(PCI_ACCESS_READ,
+ bus, devfn, where, &data);
+
+ if (ret != PCIBIOS_SUCCESSFUL)
+ return ret;
+
+ if (size == 1)
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ else if (size == 2)
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ else
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int loongson3_pci_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 data = 0;
+ int ret;
+
+ if (size == 4)
+ data = val;
+ else {
+ ret = loongson3_pci_config_access(PCI_ACCESS_READ,
+ bus, devfn, where, &data);
+ if (ret != PCIBIOS_SUCCESSFUL)
+ return ret;
+
+ if (size == 1)
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else if (size == 2)
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ }
+
+ ret = loongson3_pci_config_access(PCI_ACCESS_WRITE,
+ bus, devfn, where, &data);
+
+ return ret;
+}
+
+struct pci_ops loongson_pci_ops = {
+ .read = loongson3_pci_pcibios_read,
+ .write = loongson3_pci_pcibios_write
+};
diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c
index d1faece21b6a..563d1f61d6ee 100644
--- a/arch/mips/pci/pci-alchemy.c
+++ b/arch/mips/pci/pci-alchemy.c
@@ -16,6 +16,7 @@
#include <linux/syscore_ops.h>
#include <linux/vmalloc.h>
+#include <asm/dma-coherence.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/tlbmisc.h>
@@ -411,17 +412,15 @@ static int alchemy_pci_probe(struct platform_device *pdev)
}
ctx->alchemy_pci_ctrl.io_map_base = (unsigned long)virt_io;
-#ifdef CONFIG_DMA_NONCOHERENT
/* Au1500 revisions older than AD have borked coherent PCI */
if ((alchemy_get_cputype() == ALCHEMY_CPU_AU1500) &&
- (read_c0_prid() < 0x01030202)) {
+ (read_c0_prid() < 0x01030202) && !coherentio) {
val = __raw_readl(ctx->regs + PCI_REG_CONFIG);
val |= PCI_CONFIG_NC;
__raw_writel(val, ctx->regs + PCI_REG_CONFIG);
wmb();
dev_info(&pdev->dev, "non-coherent PCI on Au1500 AA/AB/AC\n");
}
-#endif
if (pd->board_map_irq)
ctx->board_map_irq = pd->board_map_irq;
diff --git a/arch/mips/pci/pci-malta.c b/arch/mips/pci/pci-malta.c
index f1a73890dd4f..cfbbc3e3e914 100644
--- a/arch/mips/pci/pci-malta.c
+++ b/arch/mips/pci/pci-malta.c
@@ -27,7 +27,7 @@
#include <linux/init.h>
#include <asm/gt64120.h>
-#include <asm/gcmpregs.h>
+#include <asm/mips-cm.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/bonito64.h>
#include <asm/mips-boards/msc01_pci.h>
@@ -201,11 +201,11 @@ void __init mips_pcibios_init(void)
msc_mem_resource.start = start & mask;
msc_mem_resource.end = (start & mask) | ~mask;
msc_controller.mem_offset = (start & mask) - (map & mask);
-#ifdef CONFIG_MIPS_CMP
- if (gcmp_niocu())
- gcmp_setregion(0, start, mask,
- GCMP_GCB_GCMPB_CMDEFTGT_IOCU1);
-#endif
+ if (mips_cm_numiocu()) {
+ write_gcr_reg0_base(start);
+ write_gcr_reg0_mask(mask |
+ CM_GCR_REGn_MASK_CMTGT_IOCU0);
+ }
MSC_READ(MSC01_PCI_SC2PIOBASL, start);
MSC_READ(MSC01_PCI_SC2PIOMSKL, mask);
MSC_READ(MSC01_PCI_SC2PIOMAPL, map);
@@ -213,11 +213,11 @@ void __init mips_pcibios_init(void)
msc_io_resource.end = (map & mask) | ~mask;
msc_controller.io_offset = 0;
ioport_resource.end = ~mask;
-#ifdef CONFIG_MIPS_CMP
- if (gcmp_niocu())
- gcmp_setregion(1, start, mask,
- GCMP_GCB_GCMPB_CMDEFTGT_IOCU1);
-#endif
+ if (mips_cm_numiocu()) {
+ write_gcr_reg1_base(start);
+ write_gcr_reg1_mask(mask |
+ CM_GCR_REGn_MASK_CMTGT_IOCU0);
+ }
/* If ranges overlap I/O takes precedence. */
start = start & mask;
end = start | ~mask;
diff --git a/arch/mips/pmcs-msp71xx/msp_setup.c b/arch/mips/pmcs-msp71xx/msp_setup.c
index 396b2967ad85..7e980767679c 100644
--- a/arch/mips/pmcs-msp71xx/msp_setup.c
+++ b/arch/mips/pmcs-msp71xx/msp_setup.c
@@ -49,7 +49,7 @@ void msp7120_reset(void)
/* Cache the reset code of this function */
__asm__ __volatile__ (
" .set push \n"
- " .set mips3 \n"
+ " .set arch=r4000 \n"
" la %0,startpoint \n"
" la %1,endpoint \n"
" .set pop \n"
diff --git a/arch/mips/power/hibernate.S b/arch/mips/power/hibernate.S
index 7e0277a1048f..32a7c828f073 100644
--- a/arch/mips/power/hibernate.S
+++ b/arch/mips/power/hibernate.S
@@ -43,6 +43,7 @@ LEAF(swsusp_arch_resume)
bne t1, t3, 1b
PTR_L t0, PBE_NEXT(t0)
bnez t0, 0b
+ jal local_flush_tlb_all /* Avoid TLB mismatch after kernel resume */
PTR_LA t0, saved_regs
PTR_L ra, PT_R31(t0)
PTR_L sp, PT_R29(t0)
diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig
index 1bfd1c17b3c2..4a296655f446 100644
--- a/arch/mips/ralink/Kconfig
+++ b/arch/mips/ralink/Kconfig
@@ -20,19 +20,13 @@ choice
config SOC_RT305X
bool "RT305x"
select USB_ARCH_HAS_HCD
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
config SOC_RT3883
bool "RT3883"
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
select HW_HAS_PCI
config SOC_MT7620
bool "MT7620"
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
endchoice
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
index 3db64d51798d..58b40ae59335 100644
--- a/arch/mips/sgi-ip22/ip22-int.c
+++ b/arch/mips/sgi-ip22/ip22-int.c
@@ -148,7 +148,7 @@ static void __irq_entry indy_buserror_irq(void)
int irq = SGI_BUSERR_IRQ;
irq_enter();
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
ip22_be_interrupt(irq);
irq_exit();
}
diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c
index 607192449335..045aa89f28d8 100644
--- a/arch/mips/sgi-ip22/ip22-time.c
+++ b/arch/mips/sgi-ip22/ip22-time.c
@@ -123,7 +123,7 @@ void __irq_entry indy_8254timer_irq(void)
char c;
irq_enter();
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
printk(KERN_ALERT "Oops, got 8254 interrupt.\n");
ArcRead(0, &c, 1, &cnt);
ArcEnterInteractiveMode();
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c
index 09d6e16a70f1..59cfe2659771 100644
--- a/arch/mips/sibyte/bcm1480/irq.c
+++ b/arch/mips/sibyte/bcm1480/irq.c
@@ -95,7 +95,7 @@ static int bcm1480_set_affinity(struct irq_data *d, const struct cpumask *mask,
u64 cur_ints;
unsigned long flags;
- i = cpumask_first(mask);
+ i = cpumask_first_and(mask, cpu_online_mask);
/* Convert logical CPU to physical CPU */
cpu = cpu_logical_map(i);
diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c
index 54e2c4de15c1..70d9182b26f1 100644
--- a/arch/mips/sibyte/bcm1480/smp.c
+++ b/arch/mips/sibyte/bcm1480/smp.c
@@ -182,7 +182,7 @@ void bcm1480_mailbox_interrupt(void)
int irq = K_BCM1480_INT_MBOX_0_0;
unsigned int action;
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
/* Load the mailbox register to figure out what we're supposed to do */
action = (__raw_readq(mailbox_0_regs[cpu]) >> 48) & 0xffff;
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
index fca0cdb99509..6d8dba5cf348 100644
--- a/arch/mips/sibyte/sb1250/irq.c
+++ b/arch/mips/sibyte/sb1250/irq.c
@@ -88,7 +88,7 @@ static int sb1250_set_affinity(struct irq_data *d, const struct cpumask *mask,
u64 cur_ints;
unsigned long flags;
- i = cpumask_first(mask);
+ i = cpumask_first_and(mask, cpu_online_mask);
/* Convert logical CPU to physical CPU */
cpu = cpu_logical_map(i);
diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c
index d7b942db0ea5..db976117dd4d 100644
--- a/arch/mips/sibyte/sb1250/smp.c
+++ b/arch/mips/sibyte/sb1250/smp.c
@@ -170,7 +170,7 @@ void sb1250_mailbox_interrupt(void)
int irq = K_INT_MBOX_0;
unsigned int action;
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
/* Load the mailbox register to figure out what we're supposed to do */
action = (____raw_readq(mailbox_regs[cpu]) >> 48) & 0xffff;
diff --git a/arch/mn10300/include/asm/Kbuild b/arch/mn10300/include/asm/Kbuild
index 992e989ab785..654d5ba6e310 100644
--- a/arch/mn10300/include/asm/Kbuild
+++ b/arch/mn10300/include/asm/Kbuild
@@ -1,7 +1,9 @@
generic-y += barrier.h
generic-y += clkdev.h
+generic-y += cputime.h
generic-y += exec.h
generic-y += hash.h
-generic-y += trace_clock.h
+generic-y += mcs_spinlock.h
generic-y += preempt.h
+generic-y += trace_clock.h
diff --git a/arch/mn10300/include/asm/cputime.h b/arch/mn10300/include/asm/cputime.h
deleted file mode 100644
index 6d68ad7e0ea3..000000000000
--- a/arch/mn10300/include/asm/cputime.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/cputime.h>
diff --git a/arch/mn10300/kernel/cevt-mn10300.c b/arch/mn10300/kernel/cevt-mn10300.c
index ccce35e3e179..60f64ca1752a 100644
--- a/arch/mn10300/kernel/cevt-mn10300.c
+++ b/arch/mn10300/kernel/cevt-mn10300.c
@@ -113,7 +113,7 @@ int __init init_clockevents(void)
cd->set_next_event = next_event;
iact = &per_cpu(timer_irq, cpu);
- iact->flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER;
+ iact->flags = IRQF_SHARED | IRQF_TIMER;
iact->handler = timer_interrupt;
clockevents_register_device(cd);
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c
index bf6e949a2f87..7ecf69879e2d 100644
--- a/arch/mn10300/kernel/mn10300-serial.c
+++ b/arch/mn10300/kernel/mn10300-serial.c
@@ -985,17 +985,17 @@ static int mn10300_serial_startup(struct uart_port *_port)
irq_set_chip(port->tm_irq, &mn10300_serial_pic);
if (request_irq(port->rx_irq, mn10300_serial_interrupt,
- IRQF_DISABLED | IRQF_NOBALANCING,
+ IRQF_NOBALANCING,
port->rx_name, port) < 0)
goto error;
if (request_irq(port->tx_irq, mn10300_serial_interrupt,
- IRQF_DISABLED | IRQF_NOBALANCING,
+ IRQF_NOBALANCING,
port->tx_name, port) < 0)
goto error2;
if (request_irq(port->tm_irq, mn10300_serial_interrupt,
- IRQF_DISABLED | IRQF_NOBALANCING,
+ IRQF_NOBALANCING,
port->tm_name, port) < 0)
goto error3;
mn10300_serial_mask_ack(port->tm_irq);
diff --git a/arch/mn10300/kernel/mn10300-watchdog.c b/arch/mn10300/kernel/mn10300-watchdog.c
index db64a7166c09..a2d8e6938d67 100644
--- a/arch/mn10300/kernel/mn10300-watchdog.c
+++ b/arch/mn10300/kernel/mn10300-watchdog.c
@@ -142,7 +142,7 @@ void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep)
NMICR = NMICR_WDIF;
nmi_count(smp_processor_id())++;
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
for_each_online_cpu(cpu) {
diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c
index a17f9c9c14c9..f984193718b1 100644
--- a/arch/mn10300/kernel/smp.c
+++ b/arch/mn10300/kernel/smp.c
@@ -143,7 +143,7 @@ static struct irqaction call_function_ipi = {
static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id);
static struct irqaction local_timer_ipi = {
.handler = smp_ipi_timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_NOBALANCING,
+ .flags = IRQF_NOBALANCING,
.name = "smp local timer IPI"
};
#endif
diff --git a/arch/mn10300/unit-asb2364/irq-fpga.c b/arch/mn10300/unit-asb2364/irq-fpga.c
index e16c216f31dc..073e2ccc4a44 100644
--- a/arch/mn10300/unit-asb2364/irq-fpga.c
+++ b/arch/mn10300/unit-asb2364/irq-fpga.c
@@ -76,7 +76,7 @@ static irqreturn_t fpga_interrupt(int irq, void *_mask)
static struct irqaction fpga_irq[] = {
[0] = {
.handler = fpga_interrupt,
- .flags = IRQF_DISABLED | IRQF_SHARED,
+ .flags = IRQF_SHARED,
.name = "fpga",
},
};
diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild
index 2e40f1ca8667..480af0d9c2f5 100644
--- a/arch/openrisc/include/asm/Kbuild
+++ b/arch/openrisc/include/asm/Kbuild
@@ -10,8 +10,8 @@ generic-y += bugs.h
generic-y += cacheflush.h
generic-y += checksum.h
generic-y += clkdev.h
-generic-y += cmpxchg.h
generic-y += cmpxchg-local.h
+generic-y += cmpxchg.h
generic-y += cputime.h
generic-y += current.h
generic-y += device.h
@@ -25,6 +25,7 @@ generic-y += fcntl.h
generic-y += ftrace.h
generic-y += futex.h
generic-y += hardirq.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
@@ -34,6 +35,7 @@ generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += kvm_para.h
generic-y += local.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += module.h
generic-y += msgbuf.h
@@ -41,6 +43,7 @@ generic-y += pci.h
generic-y += percpu.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sections.h
@@ -53,11 +56,11 @@ generic-y += siginfo.h
generic-y += signal.h
generic-y += socket.h
generic-y += sockios.h
-generic-y += statfs.h
generic-y += stat.h
+generic-y += statfs.h
generic-y += string.h
-generic-y += switch_to.h
generic-y += swab.h
+generic-y += switch_to.h
generic-y += termbits.h
generic-y += termios.h
generic-y += topology.h
@@ -68,5 +71,3 @@ generic-y += user.h
generic-y += vga.h
generic-y += word-at-a-time.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/parisc/include/asm/Kbuild b/arch/parisc/include/asm/Kbuild
index 752c981bc3c7..ecf25e6678ad 100644
--- a/arch/parisc/include/asm/Kbuild
+++ b/arch/parisc/include/asm/Kbuild
@@ -1,9 +1,29 @@
+generic-y += auxvec.h
generic-y += barrier.h
-generic-y += word-at-a-time.h auxvec.h user.h cputime.h emergency-restart.h \
- segment.h topology.h vga.h device.h percpu.h hw_irq.h mutex.h \
- div64.h irq_regs.h kdebug.h kvm_para.h local64.h local.h param.h \
- poll.h xor.h clkdev.h exec.h
-generic-y += trace_clock.h
-generic-y += preempt.h
+generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += emergency-restart.h
+generic-y += exec.h
generic-y += hash.h
+generic-y += hw_irq.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += kvm_para.h
+generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
+generic-y += mutex.h
+generic-y += param.h
+generic-y += percpu.h
+generic-y += poll.h
+generic-y += preempt.h
+generic-y += segment.h
+generic-y += topology.h
+generic-y += trace_clock.h
+generic-y += user.h
+generic-y += vga.h
+generic-y += word-at-a-time.h
+generic-y += xor.h
diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
index 637fe031aa84..60d5d174dfe4 100644
--- a/arch/parisc/include/asm/page.h
+++ b/arch/parisc/include/asm/page.h
@@ -32,17 +32,6 @@ void copy_page_asm(void *to, void *from);
void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
struct page *pg);
-/* #define CONFIG_PARISC_TMPALIAS */
-
-#ifdef CONFIG_PARISC_TMPALIAS
-void clear_user_highpage(struct page *page, unsigned long vaddr);
-#define clear_user_highpage clear_user_highpage
-struct vm_area_struct;
-void copy_user_highpage(struct page *to, struct page *from,
- unsigned long vaddr, struct vm_area_struct *vma);
-#define __HAVE_ARCH_COPY_USER_HIGHPAGE
-#endif
-
/*
* These are used to make use of C type-checking..
*/
diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h
index 3516e0b27044..64f2992e439f 100644
--- a/arch/parisc/include/asm/spinlock.h
+++ b/arch/parisc/include/asm/spinlock.h
@@ -191,8 +191,4 @@ static __inline__ int arch_write_can_lock(arch_rwlock_t *rw)
#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-#define arch_spin_relax(lock) cpu_relax()
-#define arch_read_relax(lock) cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
#endif /* __ASM_SPINLOCK_H */
diff --git a/arch/parisc/include/uapi/asm/unistd.h b/arch/parisc/include/uapi/asm/unistd.h
index 42706794a36f..265ae5190b0a 100644
--- a/arch/parisc/include/uapi/asm/unistd.h
+++ b/arch/parisc/include/uapi/asm/unistd.h
@@ -828,13 +828,13 @@
#define __NR_finit_module (__NR_Linux + 333)
#define __NR_sched_setattr (__NR_Linux + 334)
#define __NR_sched_getattr (__NR_Linux + 335)
+#define __NR_utimes (__NR_Linux + 336)
-#define __NR_Linux_syscalls (__NR_sched_getattr + 1)
+#define __NR_Linux_syscalls (__NR_utimes + 1)
#define __IGNORE_select /* newselect */
#define __IGNORE_fadvise64 /* fadvise64_64 */
-#define __IGNORE_utimes /* utime */
#define HPUX_GATEWAY_ADDR 0xC0000004
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index ac87a40502e6..a6ffc775a9f8 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -581,67 +581,3 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
__flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
}
}
-
-#ifdef CONFIG_PARISC_TMPALIAS
-
-void clear_user_highpage(struct page *page, unsigned long vaddr)
-{
- void *vto;
- unsigned long flags;
-
- /* Clear using TMPALIAS region. The page doesn't need to
- be flushed but the kernel mapping needs to be purged. */
-
- vto = kmap_atomic(page);
-
- /* The PA-RISC 2.0 Architecture book states on page F-6:
- "Before a write-capable translation is enabled, *all*
- non-equivalently-aliased translations must be removed
- from the page table and purged from the TLB. (Note
- that the caches are not required to be flushed at this
- time.) Before any non-equivalent aliased translation
- is re-enabled, the virtual address range for the writeable
- page (the entire page) must be flushed from the cache,
- and the write-capable translation removed from the page
- table and purged from the TLB." */
-
- purge_kernel_dcache_page_asm((unsigned long)vto);
- purge_tlb_start(flags);
- pdtlb_kernel(vto);
- purge_tlb_end(flags);
- preempt_disable();
- clear_user_page_asm(vto, vaddr);
- preempt_enable();
-
- pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */
-}
-
-void copy_user_highpage(struct page *to, struct page *from,
- unsigned long vaddr, struct vm_area_struct *vma)
-{
- void *vfrom, *vto;
- unsigned long flags;
-
- /* Copy using TMPALIAS region. This has the advantage
- that the `from' page doesn't need to be flushed. However,
- the `to' page must be flushed in copy_user_page_asm since
- it can be used to bring in executable code. */
-
- vfrom = kmap_atomic(from);
- vto = kmap_atomic(to);
-
- purge_kernel_dcache_page_asm((unsigned long)vto);
- purge_tlb_start(flags);
- pdtlb_kernel(vto);
- pdtlb_kernel(vfrom);
- purge_tlb_end(flags);
- preempt_disable();
- copy_user_page_asm(vto, vfrom, vaddr);
- flush_dcache_page_asm(__pa(vto), vaddr);
- preempt_enable();
-
- pagefault_enable(); /* kunmap_atomic(addr, KM_USER1); */
- pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */
-}
-
-#endif /* CONFIG_PARISC_TMPALIAS */
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index 8ceac4785609..cfe056fe7f5c 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -117,7 +117,7 @@ int cpu_check_affinity(struct irq_data *d, const struct cpumask *dest)
return -EINVAL;
/* whatever mask they set, we just allow one CPU */
- cpu_dest = first_cpu(*dest);
+ cpu_dest = cpumask_first_and(dest, cpu_online_mask);
return cpu_dest;
}
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 8fa3fbb3e4d3..80e5dd248934 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -431,6 +431,7 @@
ENTRY_SAME(finit_module)
ENTRY_SAME(sched_setattr)
ENTRY_SAME(sched_getattr) /* 335 */
+ ENTRY_COMP(utimes)
/* Nothing yet */
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 957bf344c0f5..6c03a94991ad 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -90,6 +90,7 @@ config PPC
select BINFMT_ELF
select OF
select OF_EARLY_FLATTREE
+ select OF_RESERVED_MEM
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_DYNAMIC_FTRACE
select HAVE_FUNCTION_TRACER
@@ -130,6 +131,8 @@ config PPC
select GENERIC_CMOS_UPDATE
select GENERIC_TIME_VSYSCALL_OLD
select GENERIC_CLOCKEVENTS
+ select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+ select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select HAVE_MOD_ARCH_SPECIFIC
@@ -618,6 +621,15 @@ config CMDLINE
some command-line options at build time by entering them here. In
most cases you will need to specify the root device here.
+config CMDLINE_FORCE
+ bool "Always use the default kernel command string"
+ depends on CMDLINE_BOOL
+ help
+ Always use the default kernel command string, even if the boot
+ loader passes other arguments to the kernel.
+ This is useful if you cannot or don't want to change the
+ command-line options your boot loader passes to the kernel.
+
config EXTRA_TARGETS
string "Additional default image types"
help
@@ -736,10 +748,6 @@ config FSL_LBC
controller. Also contains some common code used by
drivers for specific local bus peripherals.
-config FSL_IFC
- bool
- depends on FSL_SOC
-
config FSL_GTM
bool
depends on PPC_83xx || QUICC_ENGINE || CPM2
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 90e9d9548660..a1f8c7f1ec60 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -54,7 +54,7 @@ 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)/,$(zlib) cuboot-c2k.o gunzip_util.o main.o prpmc2800.o): \
+$(addprefix $(obj)/,$(zlib) cuboot-c2k.o gunzip_util.o main.o): \
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
@@ -95,7 +95,7 @@ src-plat-$(CONFIG_FSL_SOC_BOOKE) += cuboot-85xx.c cuboot-85xx-cpm2.c
src-plat-$(CONFIG_EMBEDDED6xx) += cuboot-pq2.c cuboot-mpc7448hpc2.c \
cuboot-c2k.c gamecube-head.S \
gamecube.c wii-head.S wii.c holly.c \
- prpmc2800.c fixed-head.S mvme5100.c
+ fixed-head.S mvme5100.c
src-plat-$(CONFIG_AMIGAONE) += cuboot-amigaone.c
src-plat-$(CONFIG_PPC_PS3) += ps3-head.S ps3-hvcall.S ps3.c
src-plat-$(CONFIG_EPAPR_BOOT) += epapr.c epapr-wrapper.c
@@ -204,7 +204,6 @@ image-$(CONFIG_PPC_CHRP) += zImage.chrp
image-$(CONFIG_PPC_EFIKA) += zImage.chrp
image-$(CONFIG_PPC_PMAC) += zImage.pmac
image-$(CONFIG_PPC_HOLLY) += dtbImage.holly
-image-$(CONFIG_PPC_PRPMC2800) += dtbImage.prpmc2800
image-$(CONFIG_DEFAULT_UIMAGE) += uImage
image-$(CONFIG_EPAPR_BOOT) += zImage.epapr
diff --git a/arch/powerpc/boot/dts/fsl/b4420si-post.dtsi b/arch/powerpc/boot/dts/fsl/b4420si-post.dtsi
index 5a6615d0ade2..60566f9927be 100644
--- a/arch/powerpc/boot/dts/fsl/b4420si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4420si-post.dtsi
@@ -86,6 +86,42 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,b4420-clockgen", "fsl,qoriq-clockgen-2.0";
+ ranges = <0x0 0xe1000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-2.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2", "pll0-div4";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2", "pll1-div4";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-2.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0", "pll0-div2", "pll0-div4",
+ "pll1", "pll1-div2", "pll1-div4";
+ clock-output-names = "cmux0";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/b4420si-pre.dtsi b/arch/powerpc/boot/dts/fsl/b4420si-pre.dtsi
index c6e451affb05..2419731c2c54 100644
--- a/arch/powerpc/boot/dts/fsl/b4420si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4420si-pre.dtsi
@@ -64,11 +64,13 @@
cpu0: PowerPC,e6500@0 {
device_type = "cpu";
reg = <0 1>;
+ clocks = <&mux0>;
next-level-cache = <&L2>;
};
cpu1: PowerPC,e6500@2 {
device_type = "cpu";
reg = <2 3>;
+ clocks = <&mux0>;
next-level-cache = <&L2>;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/b4860si-post.dtsi b/arch/powerpc/boot/dts/fsl/b4860si-post.dtsi
index 981397518fc6..cbc354b05117 100644
--- a/arch/powerpc/boot/dts/fsl/b4860si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4860si-post.dtsi
@@ -130,6 +130,42 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,b4860-clockgen", "fsl,qoriq-clockgen-2.0";
+ ranges = <0x0 0xe1000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-2.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2", "pll0-div4";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2", "pll1-div4";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-2.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0", "pll0-div2", "pll0-div4",
+ "pll1", "pll1-div2", "pll1-div4";
+ clock-output-names = "cmux0";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/b4860si-pre.dtsi b/arch/powerpc/boot/dts/fsl/b4860si-pre.dtsi
index 9bc26b147900..142ac862cacf 100644
--- a/arch/powerpc/boot/dts/fsl/b4860si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4860si-pre.dtsi
@@ -64,21 +64,25 @@
cpu0: PowerPC,e6500@0 {
device_type = "cpu";
reg = <0 1>;
+ clocks = <&mux0>;
next-level-cache = <&L2>;
};
cpu1: PowerPC,e6500@2 {
device_type = "cpu";
reg = <2 3>;
+ clocks = <&mux0>;
next-level-cache = <&L2>;
};
cpu2: PowerPC,e6500@4 {
device_type = "cpu";
reg = <4 5>;
+ clocks = <&mux0>;
next-level-cache = <&L2>;
};
cpu3: PowerPC,e6500@6 {
device_type = "cpu";
reg = <6 7>;
+ clocks = <&mux0>;
next-level-cache = <&L2>;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
index dc6cc5afd189..e2987a33083c 100644
--- a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
@@ -306,8 +306,68 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,p2041-clockgen", "fsl,qoriq-clockgen-1.0";
+ ranges = <0x0 0xe1000 0x1000>;
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-1.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux0";
+ };
+
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux1";
+ };
+
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ };
+
+ mux3: mux3@60 {
+ #clock-cells = <0>;
+ reg = <0x60 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux3";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
index 7a2697d04549..22f3b14517de 100644
--- a/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
@@ -81,6 +81,7 @@
cpu0: PowerPC,e500mc@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -89,6 +90,7 @@
cpu1: PowerPC,e500mc@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
@@ -97,6 +99,7 @@
cpu2: PowerPC,e500mc@2 {
device_type = "cpu";
reg = <2>;
+ clocks = <&mux2>;
next-level-cache = <&L2_2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
@@ -105,6 +108,7 @@
cpu3: PowerPC,e500mc@3 {
device_type = "cpu";
reg = <3>;
+ clocks = <&mux3>;
next-level-cache = <&L2_3>;
L2_3: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
index 3fa1e22d544a..7af6d45fd998 100644
--- a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
@@ -333,8 +333,69 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,p3041-clockgen", "fsl,qoriq-clockgen-1.0";
+ ranges = <0x0 0xe1000 0x1000>;
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-1.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux0";
+ };
+
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux1";
+ };
+
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux2";
+ };
+
+ mux3: mux3@60 {
+ #clock-cells = <0>;
+ reg = <0x60 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux3";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
index c9ca2c305cfe..468e8be8ac6f 100644
--- a/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
@@ -82,6 +82,7 @@
cpu0: PowerPC,e500mc@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -90,6 +91,7 @@
cpu1: PowerPC,e500mc@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
@@ -98,6 +100,7 @@
cpu2: PowerPC,e500mc@2 {
device_type = "cpu";
reg = <2>;
+ clocks = <&mux2>;
next-level-cache = <&L2_2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
@@ -106,6 +109,7 @@
cpu3: PowerPC,e500mc@3 {
device_type = "cpu";
reg = <3>;
+ clocks = <&mux3>;
next-level-cache = <&L2_3>;
L2_3: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
index 34769a7eafea..2415e1f1d3fa 100644
--- a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
@@ -353,8 +353,121 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,p4080-clockgen", "fsl,qoriq-clockgen-1.0";
+ ranges = <0x0 0xe1000 0x1000>;
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-1.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2";
+ };
+
+ pll2: pll2@840 {
+ #clock-cells = <1>;
+ reg = <0x840 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll2", "pll2-div2";
+ };
+
+ pll3: pll3@860 {
+ #clock-cells = <1>;
+ reg = <0x860 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll3", "pll3-div2";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux0";
+ };
+
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux1";
+ };
+
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux2";
+ };
+
+ mux3: mux3@60 {
+ #clock-cells = <0>;
+ reg = <0x60 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux3";
+ };
+
+ mux4: mux4@80 {
+ #clock-cells = <0>;
+ reg = <0x80 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+ clock-names = "pll2", "pll2-div2", "pll3", "pll3-div2";
+ clock-output-names = "cmux4";
+ };
+
+ mux5: mux5@a0 {
+ #clock-cells = <0>;
+ reg = <0xa0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+ clock-names = "pll2", "pll2-div2", "pll3", "pll3-div2";
+ clock-output-names = "cmux5";
+ };
+
+ mux6: mux6@c0 {
+ #clock-cells = <0>;
+ reg = <0xc0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+ clock-names = "pll2", "pll2-div2", "pll3", "pll3-div2";
+ clock-output-names = "cmux6";
+ };
+
+ mux7: mux7@e0 {
+ #clock-cells = <0>;
+ reg = <0xe0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+ clock-names = "pll2", "pll2-div2", "pll3", "pll3-div2";
+ clock-output-names = "cmux7";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
index 493d9a056b5c..0040b5a5379e 100644
--- a/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
@@ -81,6 +81,7 @@
cpu0: PowerPC,e500mc@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -89,6 +90,7 @@
cpu1: PowerPC,e500mc@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
@@ -97,6 +99,7 @@
cpu2: PowerPC,e500mc@2 {
device_type = "cpu";
reg = <2>;
+ clocks = <&mux2>;
next-level-cache = <&L2_2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
@@ -105,6 +108,7 @@
cpu3: PowerPC,e500mc@3 {
device_type = "cpu";
reg = <3>;
+ clocks = <&mux3>;
next-level-cache = <&L2_3>;
L2_3: l2-cache {
next-level-cache = <&cpc>;
@@ -113,6 +117,7 @@
cpu4: PowerPC,e500mc@4 {
device_type = "cpu";
reg = <4>;
+ clocks = <&mux4>;
next-level-cache = <&L2_4>;
L2_4: l2-cache {
next-level-cache = <&cpc>;
@@ -121,6 +126,7 @@
cpu5: PowerPC,e500mc@5 {
device_type = "cpu";
reg = <5>;
+ clocks = <&mux5>;
next-level-cache = <&L2_5>;
L2_5: l2-cache {
next-level-cache = <&cpc>;
@@ -129,6 +135,7 @@
cpu6: PowerPC,e500mc@6 {
device_type = "cpu";
reg = <6>;
+ clocks = <&mux6>;
next-level-cache = <&L2_6>;
L2_6: l2-cache {
next-level-cache = <&cpc>;
@@ -137,6 +144,7 @@
cpu7: PowerPC,e500mc@7 {
device_type = "cpu";
reg = <7>;
+ clocks = <&mux7>;
next-level-cache = <&L2_7>;
L2_7: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
index bc3ae5a2252f..2985de4ad6be 100644
--- a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
@@ -338,8 +338,51 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,p5020-clockgen", "fsl,qoriq-clockgen-1.0";
+ ranges = <0x0 0xe1000 0x1000>;
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-1.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux0";
+ };
+
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux1";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
index 8df47fc45ab5..fe1a2e6613b4 100644
--- a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
@@ -88,6 +88,7 @@
cpu0: PowerPC,e5500@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -96,6 +97,7 @@
cpu1: PowerPC,e5500@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
index a91897f6af09..546a899efe20 100644
--- a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
@@ -298,8 +298,69 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,p5040-clockgen", "fsl,qoriq-clockgen-1.0";
+ ranges = <0x0 0xe1000 0x1000>;
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-1.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-1.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux0";
+ };
+
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux1";
+ };
+
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux2";
+ };
+
+ mux3: mux3@60 {
+ #clock-cells = <0>;
+ reg = <0x60 0x4>;
+ compatible = "fsl,qoriq-core-mux-1.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+ clock-output-names = "cmux3";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
index 40ca943f5d1c..3674686687cb 100644
--- a/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
@@ -81,6 +81,7 @@
cpu0: PowerPC,e5500@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -89,6 +90,7 @@
cpu1: PowerPC,e5500@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
@@ -97,6 +99,7 @@
cpu2: PowerPC,e5500@2 {
device_type = "cpu";
reg = <2>;
+ clocks = <&mux2>;
next-level-cache = <&L2_2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
@@ -105,6 +108,7 @@
cpu3: PowerPC,e5500@3 {
device_type = "cpu";
reg = <3>;
+ clocks = <&mux3>;
next-level-cache = <&L2_3>;
L2_3: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi b/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
index 4143a9733cd0..f99d74ff11b4 100644
--- a/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
@@ -369,7 +369,93 @@
clockgen: global-utilities@e1000 {
compatible = "fsl,t4240-clockgen", "fsl,qoriq-clockgen-2.0";
+ ranges = <0x0 0xe1000 0x1000>;
reg = <0xe1000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysclk: sysclk {
+ #clock-cells = <0>;
+ compatible = "fsl,qoriq-sysclk-2.0";
+ clock-output-names = "sysclk";
+ };
+
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll0", "pll0-div2", "pll0-div4";
+ };
+
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll1", "pll1-div2", "pll1-div4";
+ };
+
+ pll2: pll2@840 {
+ #clock-cells = <1>;
+ reg = <0x840 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll2", "pll2-div2", "pll2-div4";
+ };
+
+ pll3: pll3@860 {
+ #clock-cells = <1>;
+ reg = <0x860 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll3", "pll3-div2", "pll3-div4";
+ };
+
+ pll4: pll4@880 {
+ #clock-cells = <1>;
+ reg = <0x880 0x4>;
+ compatible = "fsl,qoriq-core-pll-2.0";
+ clocks = <&sysclk>;
+ clock-output-names = "pll4", "pll4-div2", "pll4-div4";
+ };
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-2.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>,
+ <&pll2 0>, <&pll2 1>, <&pll2 2>;
+ clock-names = "pll0", "pll0-div2", "pll0-div4",
+ "pll1", "pll1-div2", "pll1-div4",
+ "pll2", "pll2-div2", "pll2-div4";
+ clock-output-names = "cmux0";
+ };
+
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20 0x4>;
+ compatible = "fsl,qoriq-core-mux-2.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>,
+ <&pll2 0>, <&pll2 1>, <&pll2 2>;
+ clock-names = "pll0", "pll0-div2", "pll0-div4",
+ "pll1", "pll1-div2", "pll1-div4",
+ "pll2", "pll2-div2", "pll2-div4";
+ clock-output-names = "cmux1";
+ };
+
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40 0x4>;
+ compatible = "fsl,qoriq-core-mux-2.0";
+ clocks = <&pll3 0>, <&pll3 1>, <&pll3 2>,
+ <&pll4 0>, <&pll4 1>, <&pll4 2>;
+ clock-names = "pll3", "pll3-div2", "pll3-div4",
+ "pll4", "pll4-div2", "pll4-div4";
+ clock-output-names = "cmux2";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi b/arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi
index a93c55a88560..0b8ccc5b4a46 100644
--- a/arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi
@@ -67,61 +67,73 @@
cpu0: PowerPC,e6500@0 {
device_type = "cpu";
reg = <0 1>;
+ clocks = <&mux0>;
next-level-cache = <&L2_1>;
};
cpu1: PowerPC,e6500@2 {
device_type = "cpu";
reg = <2 3>;
+ clocks = <&mux0>;
next-level-cache = <&L2_1>;
};
cpu2: PowerPC,e6500@4 {
device_type = "cpu";
reg = <4 5>;
+ clocks = <&mux0>;
next-level-cache = <&L2_1>;
};
cpu3: PowerPC,e6500@6 {
device_type = "cpu";
reg = <6 7>;
+ clocks = <&mux0>;
next-level-cache = <&L2_1>;
};
cpu4: PowerPC,e6500@8 {
device_type = "cpu";
reg = <8 9>;
+ clocks = <&mux1>;
next-level-cache = <&L2_2>;
};
cpu5: PowerPC,e6500@10 {
device_type = "cpu";
reg = <10 11>;
+ clocks = <&mux1>;
next-level-cache = <&L2_2>;
};
cpu6: PowerPC,e6500@12 {
device_type = "cpu";
reg = <12 13>;
+ clocks = <&mux1>;
next-level-cache = <&L2_2>;
};
cpu7: PowerPC,e6500@14 {
device_type = "cpu";
reg = <14 15>;
+ clocks = <&mux1>;
next-level-cache = <&L2_2>;
};
cpu8: PowerPC,e6500@16 {
device_type = "cpu";
reg = <16 17>;
+ clocks = <&mux2>;
next-level-cache = <&L2_3>;
};
cpu9: PowerPC,e6500@18 {
device_type = "cpu";
reg = <18 19>;
+ clocks = <&mux2>;
next-level-cache = <&L2_3>;
};
cpu10: PowerPC,e6500@20 {
device_type = "cpu";
reg = <20 21>;
+ clocks = <&mux2>;
next-level-cache = <&L2_3>;
};
cpu11: PowerPC,e6500@22 {
device_type = "cpu";
reg = <22 23>;
+ clocks = <&mux2>;
next-level-cache = <&L2_3>;
};
};
diff --git a/arch/powerpc/boot/dts/t4240qds.dts b/arch/powerpc/boot/dts/t4240qds.dts
index 63e81b010804..97683f6a2936 100644
--- a/arch/powerpc/boot/dts/t4240qds.dts
+++ b/arch/powerpc/boot/dts/t4240qds.dts
@@ -159,6 +159,48 @@
interrupts = <0x1 0x1 0 0>;
};
};
+
+ i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x2>;
+
+ ina220@40 {
+ compatible = "ti,ina220";
+ reg = <0x40>;
+ shunt-resistor = <1000>;
+ };
+
+ ina220@41 {
+ compatible = "ti,ina220";
+ reg = <0x41>;
+ shunt-resistor = <1000>;
+ };
+
+ ina220@44 {
+ compatible = "ti,ina220";
+ reg = <0x44>;
+ shunt-resistor = <1000>;
+ };
+
+ ina220@45 {
+ compatible = "ti,ina220";
+ reg = <0x45>;
+ shunt-resistor = <1000>;
+ };
+
+ ina220@46 {
+ compatible = "ti,ina220";
+ reg = <0x46>;
+ shunt-resistor = <1000>;
+ };
+
+ ina220@47 {
+ compatible = "ti,ina220";
+ reg = <0x47>;
+ shunt-resistor = <1000>;
+ };
+ };
};
};
diff --git a/arch/powerpc/configs/40x/acadia_defconfig b/arch/powerpc/configs/40x/acadia_defconfig
index ed3bab72a834..69e06eeae6a6 100644
--- a/arch/powerpc/configs/40x/acadia_defconfig
+++ b/arch/powerpc/configs/40x/acadia_defconfig
@@ -30,7 +30,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/40x/ep405_defconfig b/arch/powerpc/configs/40x/ep405_defconfig
index 17582a3420fb..cf06d42f2c03 100644
--- a/arch/powerpc/configs/40x/ep405_defconfig
+++ b/arch/powerpc/configs/40x/ep405_defconfig
@@ -29,7 +29,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/40x/kilauea_defconfig b/arch/powerpc/configs/40x/kilauea_defconfig
index f2d4be936e08..5ff338f6443f 100644
--- a/arch/powerpc/configs/40x/kilauea_defconfig
+++ b/arch/powerpc/configs/40x/kilauea_defconfig
@@ -32,7 +32,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/40x/makalu_defconfig b/arch/powerpc/configs/40x/makalu_defconfig
index 42b979355f9b..84505e3aa0fb 100644
--- a/arch/powerpc/configs/40x/makalu_defconfig
+++ b/arch/powerpc/configs/40x/makalu_defconfig
@@ -29,7 +29,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/40x/walnut_defconfig b/arch/powerpc/configs/40x/walnut_defconfig
index aa1a4cac3708..0a19f4386ee9 100644
--- a/arch/powerpc/configs/40x/walnut_defconfig
+++ b/arch/powerpc/configs/40x/walnut_defconfig
@@ -27,7 +27,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/arches_defconfig b/arch/powerpc/configs/44x/arches_defconfig
index 329f9a3b892e..44355c53cd30 100644
--- a/arch/powerpc/configs/44x/arches_defconfig
+++ b/arch/powerpc/configs/44x/arches_defconfig
@@ -31,7 +31,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/bluestone_defconfig b/arch/powerpc/configs/44x/bluestone_defconfig
index 20c8d26d7fc0..ca7f1f32f2b2 100644
--- a/arch/powerpc/configs/44x/bluestone_defconfig
+++ b/arch/powerpc/configs/44x/bluestone_defconfig
@@ -26,7 +26,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/canyonlands_defconfig b/arch/powerpc/configs/44x/canyonlands_defconfig
index d5be93e6e92d..7b8abd1b88b0 100644
--- a/arch/powerpc/configs/44x/canyonlands_defconfig
+++ b/arch/powerpc/configs/44x/canyonlands_defconfig
@@ -31,7 +31,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/ebony_defconfig b/arch/powerpc/configs/44x/ebony_defconfig
index f9269fc4ffcc..31b58b0d52e2 100644
--- a/arch/powerpc/configs/44x/ebony_defconfig
+++ b/arch/powerpc/configs/44x/ebony_defconfig
@@ -28,7 +28,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/44x/eiger_defconfig b/arch/powerpc/configs/44x/eiger_defconfig
index 9be089038fd7..faccaf65f394 100644
--- a/arch/powerpc/configs/44x/eiger_defconfig
+++ b/arch/powerpc/configs/44x/eiger_defconfig
@@ -34,7 +34,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/icon_defconfig b/arch/powerpc/configs/44x/icon_defconfig
index 82f73035a7ce..05782c145141 100644
--- a/arch/powerpc/configs/44x/icon_defconfig
+++ b/arch/powerpc/configs/44x/icon_defconfig
@@ -33,7 +33,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/iss476-smp_defconfig b/arch/powerpc/configs/44x/iss476-smp_defconfig
index ca00cf750d3e..49a1518a4e69 100644
--- a/arch/powerpc/configs/44x/iss476-smp_defconfig
+++ b/arch/powerpc/configs/44x/iss476-smp_defconfig
@@ -42,7 +42,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/44x/katmai_defconfig b/arch/powerpc/configs/44x/katmai_defconfig
index 109562c3c6be..f1137972ed41 100644
--- a/arch/powerpc/configs/44x/katmai_defconfig
+++ b/arch/powerpc/configs/44x/katmai_defconfig
@@ -29,7 +29,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/rainier_defconfig b/arch/powerpc/configs/44x/rainier_defconfig
index 21c33faf61a2..4b91a44c4c32 100644
--- a/arch/powerpc/configs/44x/rainier_defconfig
+++ b/arch/powerpc/configs/44x/rainier_defconfig
@@ -30,7 +30,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/redwood_defconfig b/arch/powerpc/configs/44x/redwood_defconfig
index 48802811da76..b7113e114a14 100644
--- a/arch/powerpc/configs/44x/redwood_defconfig
+++ b/arch/powerpc/configs/44x/redwood_defconfig
@@ -34,7 +34,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/sequoia_defconfig b/arch/powerpc/configs/44x/sequoia_defconfig
index b7a653b626db..9642d99b47f1 100644
--- a/arch/powerpc/configs/44x/sequoia_defconfig
+++ b/arch/powerpc/configs/44x/sequoia_defconfig
@@ -31,7 +31,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/44x/taishan_defconfig b/arch/powerpc/configs/44x/taishan_defconfig
index 30de97f158a4..09e3075030bf 100644
--- a/arch/powerpc/configs/44x/taishan_defconfig
+++ b/arch/powerpc/configs/44x/taishan_defconfig
@@ -29,7 +29,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_CFI=y
diff --git a/arch/powerpc/configs/44x/warp_defconfig b/arch/powerpc/configs/44x/warp_defconfig
index 105bc56f4b2b..551e50a0be5e 100644
--- a/arch/powerpc/configs/44x/warp_defconfig
+++ b/arch/powerpc/configs/44x/warp_defconfig
@@ -34,7 +34,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_STANDALONE is not set
# CONFIG_FIRMWARE_IN_KERNEL is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/52xx/cm5200_defconfig b/arch/powerpc/configs/52xx/cm5200_defconfig
index 0b88c7b30bb9..4f84a0b2fbf3 100644
--- a/arch/powerpc/configs/52xx/cm5200_defconfig
+++ b/arch/powerpc/configs/52xx/cm5200_defconfig
@@ -30,7 +30,6 @@ CONFIG_SYN_COOKIES=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/52xx/motionpro_defconfig b/arch/powerpc/configs/52xx/motionpro_defconfig
index 0d13ad7e4478..c05310a913be 100644
--- a/arch/powerpc/configs/52xx/motionpro_defconfig
+++ b/arch/powerpc/configs/52xx/motionpro_defconfig
@@ -31,7 +31,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/52xx/pcm030_defconfig b/arch/powerpc/configs/52xx/pcm030_defconfig
index 430aa182fa1c..2401e2554329 100644
--- a/arch/powerpc/configs/52xx/pcm030_defconfig
+++ b/arch/powerpc/configs/52xx/pcm030_defconfig
@@ -44,7 +44,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/52xx/tqm5200_defconfig b/arch/powerpc/configs/52xx/tqm5200_defconfig
index 7af4c5bb7c63..21c841e0f482 100644
--- a/arch/powerpc/configs/52xx/tqm5200_defconfig
+++ b/arch/powerpc/configs/52xx/tqm5200_defconfig
@@ -35,7 +35,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/83xx/asp8347_defconfig b/arch/powerpc/configs/83xx/asp8347_defconfig
index d2762d9dcb8e..985f95c7280a 100644
--- a/arch/powerpc/configs/83xx/asp8347_defconfig
+++ b/arch/powerpc/configs/83xx/asp8347_defconfig
@@ -32,7 +32,6 @@ CONFIG_SYN_COOKIES=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_REDBOOT_PARTS=y
CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
CONFIG_MTD_OF_PARTS=y
diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
index e4ad2e27551a..0b73b7f9d112 100644
--- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
@@ -30,7 +30,6 @@ CONFIG_SYN_COOKIES=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
index 34ff5686be08..97ac3b993cb6 100644
--- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
@@ -30,7 +30,6 @@ CONFIG_SYN_COOKIES=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
diff --git a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
index 10b5c4cd0e72..05710bbfd2ef 100644
--- a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
@@ -31,7 +31,6 @@ CONFIG_SYN_COOKIES=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
index 45925d701d2a..0540d673a052 100644
--- a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
+++ b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
@@ -29,7 +29,6 @@ CONFIG_SYN_COOKIES=y
# CONFIG_IPV6 is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/83xx/sbc834x_defconfig b/arch/powerpc/configs/83xx/sbc834x_defconfig
index 6d6463fe06fc..a3bcda67d2d9 100644
--- a/arch/powerpc/configs/83xx/sbc834x_defconfig
+++ b/arch/powerpc/configs/83xx/sbc834x_defconfig
@@ -31,7 +31,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/85xx/ksi8560_defconfig b/arch/powerpc/configs/85xx/ksi8560_defconfig
index 8f7c1061891a..aee0d17a9551 100644
--- a/arch/powerpc/configs/85xx/ksi8560_defconfig
+++ b/arch/powerpc/configs/85xx/ksi8560_defconfig
@@ -28,7 +28,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
diff --git a/arch/powerpc/configs/85xx/ppa8548_defconfig b/arch/powerpc/configs/85xx/ppa8548_defconfig
index a11337de8aa2..e80bb9b21eac 100644
--- a/arch/powerpc/configs/85xx/ppa8548_defconfig
+++ b/arch/powerpc/configs/85xx/ppa8548_defconfig
@@ -44,7 +44,6 @@ CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_PHYSMAP_OF=y
CONFIG_I2C=y
diff --git a/arch/powerpc/configs/85xx/socrates_defconfig b/arch/powerpc/configs/85xx/socrates_defconfig
index 77506b5d5a41..e5147488c000 100644
--- a/arch/powerpc/configs/85xx/socrates_defconfig
+++ b/arch/powerpc/configs/85xx/socrates_defconfig
@@ -32,7 +32,6 @@ CONFIG_CAN_RAW=y
CONFIG_CAN_BCM=y
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/85xx/tqm8540_defconfig b/arch/powerpc/configs/85xx/tqm8540_defconfig
index ddcb9f37fa1f..5a800e6e38e3 100644
--- a/arch/powerpc/configs/85xx/tqm8540_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8540_defconfig
@@ -26,7 +26,6 @@ CONFIG_SYN_COOKIES=y
# CONFIG_IPV6 is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/85xx/tqm8541_defconfig b/arch/powerpc/configs/85xx/tqm8541_defconfig
index 981abd6d4b57..2d936697d69e 100644
--- a/arch/powerpc/configs/85xx/tqm8541_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8541_defconfig
@@ -26,7 +26,6 @@ CONFIG_SYN_COOKIES=y
# CONFIG_IPV6 is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/85xx/tqm8548_defconfig b/arch/powerpc/configs/85xx/tqm8548_defconfig
index 37b3d7227cdd..ce8a67e89473 100644
--- a/arch/powerpc/configs/85xx/tqm8548_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8548_defconfig
@@ -34,7 +34,6 @@ CONFIG_SYN_COOKIES=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLKDEVS=y
diff --git a/arch/powerpc/configs/85xx/tqm8555_defconfig b/arch/powerpc/configs/85xx/tqm8555_defconfig
index 3593b320c97c..a4e12971ccac 100644
--- a/arch/powerpc/configs/85xx/tqm8555_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8555_defconfig
@@ -26,7 +26,6 @@ CONFIG_SYN_COOKIES=y
# CONFIG_IPV6 is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/85xx/tqm8560_defconfig b/arch/powerpc/configs/85xx/tqm8560_defconfig
index de413acc34d6..341abe18a74d 100644
--- a/arch/powerpc/configs/85xx/tqm8560_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8560_defconfig
@@ -26,7 +26,6 @@ CONFIG_SYN_COOKIES=y
# CONFIG_IPV6 is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
index 1cd6fcb368e9..07bb81df27e0 100644
--- a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
+++ b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
@@ -65,7 +65,6 @@ CONFIG_ARPD=y
CONFIG_IPV6=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_REDBOOT_PARTS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
diff --git a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
index f2f6734d5f76..e5a648115ada 100644
--- a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
+++ b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
@@ -70,7 +70,6 @@ CONFIG_NET_PKTGEN=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/arch/powerpc/configs/86xx/gef_sbc310_defconfig
index be73219212b7..8317b6010ba6 100644
--- a/arch/powerpc/configs/86xx/gef_sbc310_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc310_defconfig
@@ -70,7 +70,6 @@ CONFIG_NET_PKTGEN=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
index b3e2b1058f27..124d66f0282c 100644
--- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
@@ -123,7 +123,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
index c09598b31de1..bcbe74716689 100644
--- a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
+++ b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
@@ -41,7 +41,6 @@ CONFIG_IP_PNP_RARP=y
CONFIG_IPV6=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/86xx/sbc8641d_defconfig b/arch/powerpc/configs/86xx/sbc8641d_defconfig
index 1a62baf855e9..1e151594c691 100644
--- a/arch/powerpc/configs/86xx/sbc8641d_defconfig
+++ b/arch/powerpc/configs/86xx/sbc8641d_defconfig
@@ -120,7 +120,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
diff --git a/arch/powerpc/configs/c2k_defconfig b/arch/powerpc/configs/c2k_defconfig
index 671a8f960afa..c69f61620908 100644
--- a/arch/powerpc/configs/c2k_defconfig
+++ b/arch/powerpc/configs/c2k_defconfig
@@ -149,7 +149,6 @@ CONFIG_BT_HCIVHCI=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_CONCAT=m
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=m
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/corenet64_smp_defconfig b/arch/powerpc/configs/corenet64_smp_defconfig
index 63508ddee11c..5c7fa19ae4ef 100644
--- a/arch/powerpc/configs/corenet64_smp_defconfig
+++ b/arch/powerpc/configs/corenet64_smp_defconfig
@@ -26,7 +26,6 @@ CONFIG_CORENET_GENERIC=y
CONFIG_BINFMT_MISC=m
CONFIG_MATH_EMULATION=y
CONFIG_MATH_EMULATION_HW_UNIMPLEMENTED=y
-CONFIG_FSL_IFC=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCI_MSI=y
CONFIG_RAPIDIO=y
@@ -60,7 +59,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/linkstation_defconfig b/arch/powerpc/configs/linkstation_defconfig
index 8a874b999867..353435256f4c 100644
--- a/arch/powerpc/configs/linkstation_defconfig
+++ b/arch/powerpc/configs/linkstation_defconfig
@@ -59,7 +59,6 @@ CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index 83d3550fdb54..19f0fbe5ba4b 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -49,7 +49,6 @@ CONFIG_HIGHMEM=y
CONFIG_BINFMT_MISC=m
CONFIG_MATH_EMULATION=y
CONFIG_FORCE_MAX_ZONEORDER=12
-CONFIG_FSL_IFC=y
CONFIG_PCI=y
CONFIG_PCI_MSI=y
CONFIG_RAPIDIO=y
@@ -82,7 +81,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index 4b686294feb4..062312e1fe1a 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -52,7 +52,6 @@ CONFIG_HIGHMEM=y
CONFIG_BINFMT_MISC=m
CONFIG_MATH_EMULATION=y
CONFIG_FORCE_MAX_ZONEORDER=12
-CONFIG_FSL_IFC=y
CONFIG_PCI=y
CONFIG_PCI_MSI=y
CONFIG_RAPIDIO=y
@@ -85,7 +84,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/ppc40x_defconfig b/arch/powerpc/configs/ppc40x_defconfig
index 1eb19ac45d09..52908c7897d9 100644
--- a/arch/powerpc/configs/ppc40x_defconfig
+++ b/arch/powerpc/configs/ppc40x_defconfig
@@ -33,7 +33,6 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/ppc44x_defconfig b/arch/powerpc/configs/ppc44x_defconfig
index 3b98d7354341..ccf66b9060a6 100644
--- a/arch/powerpc/configs/ppc44x_defconfig
+++ b/arch/powerpc/configs/ppc44x_defconfig
@@ -44,7 +44,6 @@ CONFIG_BRIDGE=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index e015896b7e5c..f26b267eb71f 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -73,74 +73,8 @@ CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_SCTP=m
-CONFIG_NF_CONNTRACK_AMANDA=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_H323=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_NETBIOS_NS=m
-CONFIG_NF_CONNTRACK_PPTP=m
-CONFIG_NF_CONNTRACK_SIP=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_DSCP=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TPROXY=m
-CONFIG_NETFILTER_XT_TARGET_TRACE=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DCCP=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_SOCKET=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_BRIDGE=m
CONFIG_BPF_JIT=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
diff --git a/arch/powerpc/configs/ppc64e_defconfig b/arch/powerpc/configs/ppc64e_defconfig
index f627fda08953..438e813dc9cb 100644
--- a/arch/powerpc/configs/ppc64e_defconfig
+++ b/arch/powerpc/configs/ppc64e_defconfig
@@ -48,74 +48,8 @@ CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_SCTP=m
-CONFIG_NF_CONNTRACK_AMANDA=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_H323=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_NETBIOS_NS=m
-CONFIG_NF_CONNTRACK_PPTP=m
-CONFIG_NF_CONNTRACK_SIP=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_DSCP=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TPROXY=m
-CONFIG_NETFILTER_XT_TARGET_TRACE=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DCCP=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_SOCKET=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_BRIDGE=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
diff --git a/arch/powerpc/configs/prpmc2800_defconfig b/arch/powerpc/configs/prpmc2800_defconfig
deleted file mode 100644
index cd80fb615d34..000000000000
--- a/arch/powerpc/configs/prpmc2800_defconfig
+++ /dev/null
@@ -1,108 +0,0 @@
-CONFIG_ALTIVEC=y
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-# CONFIG_PPC_CHRP is not set
-# CONFIG_PPC_PMAC is not set
-CONFIG_EMBEDDED6xx=y
-CONFIG_PPC_PRPMC2800=y
-CONFIG_HIGHMEM=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_BINFMT_MISC=y
-CONFIG_SPARSE_IRQ=y
-# CONFIG_SECCOMP is not set
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_XFRM_USER=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_SYN_COOKIES=y
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_PROC_DEVICETREE=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=131072
-CONFIG_IDE=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PDC202XX_NEW=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_ATA=y
-CONFIG_SATA_MV=y
-CONFIG_MACINTOSH_DRIVERS=y
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
-CONFIG_E100=y
-CONFIG_8139TOO=y
-# CONFIG_8139TOO_PIO is not set
-CONFIG_E1000=y
-CONFIG_MV643XX_ETH=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_MPSC=y
-CONFIG_SERIAL_MPSC_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_MV64XXX=y
-CONFIG_VIDEO_OUTPUT_CONTROL=y
-CONFIG_HID_DRAGONRISE=y
-CONFIG_HID_GYRATION=y
-CONFIG_HID_TWINHAN=y
-CONFIG_HID_NTRIG=y
-CONFIG_HID_ORTEK=y
-CONFIG_HID_PANTHERLORD=y
-CONFIG_HID_PETALYNX=y
-CONFIG_HID_SAMSUNG=y
-CONFIG_HID_SONY=y
-CONFIG_HID_SUNPLUS=y
-CONFIG_HID_GREENASIA=y
-CONFIG_HID_SMARTJOYPLUS=y
-CONFIG_HID_TOPSEED=y
-CONFIG_HID_THRUSTMASTER=y
-CONFIG_THRUSTMASTER_FF=y
-CONFIG_HID_ZEROPLUS=y
-CONFIG_ZEROPLUS_FF=y
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_MON=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_MAX6900=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_INOTIFY=y
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_CRC_T10DIF=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index e9a8b4e0a0f6..9ea8342bd219 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -65,57 +65,8 @@ CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_UDPLITE=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DCCP=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_TIME=m
-CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_BRIDGE=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
@@ -353,3 +304,5 @@ CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
CONFIG_VIRTUALIZATION=y
CONFIG_KVM_BOOK3S_64=m
CONFIG_KVM_BOOK3S_64_HV=y
+CONFIG_TRANSPARENT_HUGEPAGE=y
+CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
diff --git a/arch/powerpc/configs/pseries_le_defconfig b/arch/powerpc/configs/pseries_le_defconfig
index 62771e0adb7c..3c84f9d87980 100644
--- a/arch/powerpc/configs/pseries_le_defconfig
+++ b/arch/powerpc/configs/pseries_le_defconfig
@@ -67,57 +67,8 @@ CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_UDPLITE=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DCCP=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_TIME=m
-CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_ULOG=m
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_BRIDGE=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
diff --git a/arch/powerpc/configs/storcenter_defconfig b/arch/powerpc/configs/storcenter_defconfig
index ebb2a66c99d3..ba39c785445d 100644
--- a/arch/powerpc/configs/storcenter_defconfig
+++ b/arch/powerpc/configs/storcenter_defconfig
@@ -31,7 +31,6 @@ CONFIG_IP_PNP_DHCP=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/configs/tqm8xx_defconfig b/arch/powerpc/configs/tqm8xx_defconfig
index 4b6f8bf104e0..7fe277a7b422 100644
--- a/arch/powerpc/configs/tqm8xx_defconfig
+++ b/arch/powerpc/configs/tqm8xx_defconfig
@@ -41,7 +41,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild
index 6c0a955a1b06..3fb1bc432f4f 100644
--- a/arch/powerpc/include/asm/Kbuild
+++ b/arch/powerpc/include/asm/Kbuild
@@ -1,7 +1,8 @@
generic-y += clkdev.h
+generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
generic-y += rwsem.h
generic-y += trace_clock.h
-generic-y += preempt.h
generic-y += vtime.h
-generic-y += hash.h
diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h
index 84fdf6857c31..b142b8e0ed9e 100644
--- a/arch/powerpc/include/asm/compat.h
+++ b/arch/powerpc/include/asm/compat.h
@@ -8,7 +8,11 @@
#include <linux/sched.h>
#define COMPAT_USER_HZ 100
+#ifdef __BIG_ENDIAN__
#define COMPAT_UTS_MACHINE "ppc\0\0"
+#else
+#define COMPAT_UTS_MACHINE "ppcle\0\0"
+#endif
typedef u32 compat_size_t;
typedef s32 compat_ssize_t;
@@ -200,10 +204,11 @@ static inline void __user *arch_compat_alloc_user_space(long len)
/*
* We can't access below the stack pointer in the 32bit ABI and
- * can access 288 bytes in the 64bit ABI
+ * can access 288 bytes in the 64bit big-endian ABI,
+ * or 512 bytes with the new ELFv2 little-endian ABI.
*/
if (!is_32bit_task())
- usp -= 288;
+ usp -= USER_REDZONE_SIZE;
return (void __user *) (usp - len);
}
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 617cc767c076..bc2347774f0a 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -189,6 +189,7 @@ extern const char *powerpc_base_platform;
#define CPU_FTR_HAS_PPR LONG_ASM_CONST(0x0200000000000000)
#define CPU_FTR_DAWR LONG_ASM_CONST(0x0400000000000000)
#define CPU_FTR_DABRX LONG_ASM_CONST(0x0800000000000000)
+#define CPU_FTR_PMAO_BUG LONG_ASM_CONST(0x1000000000000000)
#ifndef __ASSEMBLY__
@@ -445,6 +446,7 @@ extern const char *powerpc_base_platform;
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)
+#define CPU_FTRS_POWER8E (CPU_FTRS_POWER8 | CPU_FTR_PMAO_BUG)
#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 | \
@@ -466,8 +468,8 @@ extern const char *powerpc_base_platform;
#define CPU_FTRS_POSSIBLE \
(CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \
CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 | \
- CPU_FTRS_POWER7 | CPU_FTRS_POWER8 | CPU_FTRS_CELL | \
- CPU_FTRS_PA6T | CPU_FTR_VSX)
+ CPU_FTRS_POWER7 | CPU_FTRS_POWER8E | CPU_FTRS_POWER8 | \
+ CPU_FTRS_CELL | CPU_FTRS_PA6T | CPU_FTR_VSX)
#endif
#else
enum {
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 9e39ceb1d19f..d4dd41fb951b 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -172,10 +172,20 @@ struct eeh_ops {
};
extern struct eeh_ops *eeh_ops;
-extern int eeh_subsystem_enabled;
+extern bool eeh_subsystem_enabled;
extern raw_spinlock_t confirm_error_lock;
extern int eeh_probe_mode;
+static inline bool eeh_enabled(void)
+{
+ return eeh_subsystem_enabled;
+}
+
+static inline void eeh_set_enable(bool mode)
+{
+ eeh_subsystem_enabled = mode;
+}
+
#define EEH_PROBE_MODE_DEV (1<<0) /* From PCI device */
#define EEH_PROBE_MODE_DEVTREE (1<<1) /* From device tree */
@@ -246,7 +256,7 @@ void eeh_remove_device(struct pci_dev *);
* If this macro yields TRUE, the caller relays to eeh_check_failure()
* which does further tests out of line.
*/
-#define EEH_POSSIBLE_ERROR(val, type) ((val) == (type)~0 && eeh_subsystem_enabled)
+#define EEH_POSSIBLE_ERROR(val, type) ((val) == (type)~0 && eeh_enabled())
/*
* Reads from a device which has been isolated by EEH will return
@@ -257,6 +267,13 @@ void eeh_remove_device(struct pci_dev *);
#else /* !CONFIG_EEH */
+static inline bool eeh_enabled(void)
+{
+ return false;
+}
+
+static inline void eeh_set_enable(bool mode) { }
+
static inline int eeh_init(void)
{
return 0;
diff --git a/arch/powerpc/include/asm/exception-64e.h b/arch/powerpc/include/asm/exception-64e.h
index 51fa43e536b9..a563d9afd179 100644
--- a/arch/powerpc/include/asm/exception-64e.h
+++ b/arch/powerpc/include/asm/exception-64e.h
@@ -46,9 +46,8 @@
#define EX_CR (1 * 8)
#define EX_R10 (2 * 8)
#define EX_R11 (3 * 8)
-#define EX_R13 (4 * 8)
-#define EX_R14 (5 * 8)
-#define EX_R15 (6 * 8)
+#define EX_R14 (4 * 8)
+#define EX_R15 (5 * 8)
/*
* The TLB miss exception uses different slots.
@@ -173,16 +172,6 @@ exc_##label##_book3e:
ld r9,EX_TLB_R9(r12); \
ld r8,EX_TLB_R8(r12); \
mtlr r16;
-#define TLB_MISS_PROLOG_STATS_BOLTED \
- mflr r10; \
- std r8,PACA_EXTLB+EX_TLB_R8(r13); \
- std r9,PACA_EXTLB+EX_TLB_R9(r13); \
- std r10,PACA_EXTLB+EX_TLB_LR(r13);
-#define TLB_MISS_RESTORE_STATS_BOLTED \
- ld r16,PACA_EXTLB+EX_TLB_LR(r13); \
- ld r9,PACA_EXTLB+EX_TLB_R9(r13); \
- ld r8,PACA_EXTLB+EX_TLB_R8(r13); \
- mtlr r16;
#define TLB_MISS_STATS_D(name) \
addi r9,r13,MMSTAT_DSTATS+name; \
bl .tlb_stat_inc;
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 66830618cc19..aeaa56cd9b54 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -147,6 +147,14 @@ BEGIN_FTR_SECTION_NESTED(943) \
END_FTR_SECTION_NESTED(ftr,ftr,943)
/*
+ * Set an SPR from a register if the CPU has the given feature
+ */
+#define OPT_SET_SPR(ra, spr, ftr) \
+BEGIN_FTR_SECTION_NESTED(943) \
+ mtspr spr,ra; \
+END_FTR_SECTION_NESTED(ftr,ftr,943)
+
+/*
* Save a register to the PACA if the CPU has the given feature
*/
#define OPT_SAVE_REG_TO_PACA(offset, ra, ftr) \
diff --git a/arch/powerpc/include/asm/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h
index d750336b171d..623f2971ce0e 100644
--- a/arch/powerpc/include/asm/hugetlb.h
+++ b/arch/powerpc/include/asm/hugetlb.h
@@ -127,7 +127,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
{
#ifdef CONFIG_PPC64
- return __pte(pte_update(mm, addr, ptep, ~0UL, 1));
+ return __pte(pte_update(mm, addr, ptep, ~0UL, 0, 1));
#else
return __pte(pte_update(ptep, ~0UL, 0));
#endif
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index d8b600b3f058..5dbbb29f5c3e 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -274,6 +274,11 @@
/* Platform specific hcalls, used by KVM */
#define H_RTAS 0xf000
+/* "Platform specific hcalls", provided by PHYP */
+#define H_GET_24X7_CATALOG_PAGE 0xF078
+#define H_GET_24X7_DATA 0xF07C
+#define H_GET_PERF_COUNTER_INFO 0xF080
+
#ifndef __ASSEMBLY__
/**
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index 83851aabfdc8..bb1e38a23ac7 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -304,6 +304,11 @@ static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
return vcpu->arch.fault_dar;
}
+static inline bool is_kvmppc_resume_guest(int r)
+{
+ return (r == RESUME_GUEST || r == RESUME_GUEST_NV);
+}
+
/* Magic register values loaded into r3 and r4 before the 'sc' assembly
* instruction for the OSI hypercalls */
#define OSI_SC_MAGIC_R3 0x113724FA
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index bf0fa8b0a883..51388befeddb 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -289,6 +289,18 @@ static inline void note_hpte_modification(struct kvm *kvm,
if (atomic_read(&kvm->arch.hpte_mod_interest))
rev->guest_rpte |= HPTE_GR_MODIFIED;
}
+
+/*
+ * Like kvm_memslots(), but for use in real mode when we can't do
+ * any RCU stuff (since the secondary threads are offline from the
+ * kernel's point of view), and we can't print anything.
+ * Thus we use rcu_dereference_raw() rather than rcu_dereference_check().
+ */
+static inline struct kvm_memslots *kvm_memslots_raw(struct kvm *kvm)
+{
+ return rcu_dereference_raw_notrace(kvm->memslots);
+}
+
#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
#endif /* __ASM_KVM_BOOK3S_64_H__ */
diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h b/arch/powerpc/include/asm/kvm_book3s_asm.h
index f3a91dc02c98..821725c1bf46 100644
--- a/arch/powerpc/include/asm/kvm_book3s_asm.h
+++ b/arch/powerpc/include/asm/kvm_book3s_asm.h
@@ -94,7 +94,7 @@ struct kvmppc_host_state {
unsigned long xics_phys;
u32 saved_xirr;
u64 dabr;
- u64 host_mmcr[3];
+ u64 host_mmcr[7]; /* MMCR 0,1,A, SIAR, SDAR, MMCR2, SIER */
u32 host_pmc[8];
u64 host_purr;
u64 host_spurr;
diff --git a/arch/powerpc/include/asm/kvm_booke_hv_asm.h b/arch/powerpc/include/asm/kvm_booke_hv_asm.h
index 3a79f5325712..e5f048bbcb7c 100644
--- a/arch/powerpc/include/asm/kvm_booke_hv_asm.h
+++ b/arch/powerpc/include/asm/kvm_booke_hv_asm.h
@@ -36,26 +36,21 @@
* *(r8 + GPR11) = saved r11
*
* 64-bit host
- * Expected inputs (GEN/GDBELL/DBG/MC exception types):
+ * Expected inputs (GEN/GDBELL/DBG/CRIT/MC exception types):
* r10 = saved CR
* r13 = PACA_POINTER
* *(r13 + PACA_EX##type + EX_R10) = saved r10
* *(r13 + PACA_EX##type + EX_R11) = saved r11
* SPRN_SPRG_##type##_SCRATCH = saved r13
*
- * Expected inputs (CRIT exception type):
- * r10 = saved CR
- * r13 = PACA_POINTER
- * *(r13 + PACA_EX##type + EX_R10) = saved r10
- * *(r13 + PACA_EX##type + EX_R11) = saved r11
- * *(r13 + PACA_EX##type + EX_R13) = saved r13
- *
* Expected inputs (TLB exception type):
* r10 = saved CR
+ * r12 = extlb pointer
* r13 = PACA_POINTER
- * *(r13 + PACA_EX##type + EX_TLB_R10) = saved r10
- * *(r13 + PACA_EX##type + EX_TLB_R11) = saved r11
- * SPRN_SPRG_GEN_SCRATCH = saved r13
+ * *(r12 + EX_TLB_R10) = saved r10
+ * *(r12 + EX_TLB_R11) = saved r11
+ * *(r12 + EX_TLB_R13) = saved r13
+ * SPRN_SPRG_GEN_SCRATCH = saved r12
*
* Only the bolted version of TLB miss exception handlers is supported now.
*/
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index fcd53f0d34ba..4096f16502a9 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -129,6 +129,8 @@ extern long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
struct kvm_create_spapr_tce *args);
extern long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
unsigned long ioba, unsigned long tce);
+extern long kvmppc_h_get_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
+ unsigned long ioba);
extern struct kvm_rma_info *kvm_alloc_rma(void);
extern void kvm_release_rma(struct kvm_rma_info *ri);
extern struct page *kvm_alloc_hpt(unsigned long nr_pages);
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index ad3025d0880b..5b6c03f1058f 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -170,6 +170,9 @@ struct machdep_calls {
int (*system_reset_exception)(struct pt_regs *regs);
int (*machine_check_exception)(struct pt_regs *regs);
+ /* Called during machine check exception to retrive fixup address. */
+ bool (*mce_check_early_recovery)(struct pt_regs *regs);
+
/* Motherboard/chipset features. This is a kind of general purpose
* hook used to control some machine specific features (like reset
* lines, chip power control, etc...).
@@ -279,6 +282,10 @@ struct machdep_calls {
#ifdef CONFIG_ARCH_RANDOM
int (*get_random_long)(unsigned long *v);
#endif
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+ int (*remove_memory)(u64, u64);
+#endif
};
extern void e500_idle(void);
diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h
index 8e99edf6d966..f97d8cb6bdf6 100644
--- a/arch/powerpc/include/asm/mce.h
+++ b/arch/powerpc/include/asm/mce.h
@@ -187,7 +187,8 @@ struct mce_error_info {
#define MCE_EVENT_DONTRELEASE false
extern void save_mce_event(struct pt_regs *regs, long handled,
- struct mce_error_info *mce_err, uint64_t addr);
+ struct mce_error_info *mce_err, uint64_t nip,
+ uint64_t addr);
extern int get_mce_event(struct machine_check_event *mce, bool release);
extern void release_mce_event(void);
extern void machine_check_queue_event(void);
diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
index 89b785d16846..901dac6b6cb7 100644
--- a/arch/powerpc/include/asm/mmu-book3e.h
+++ b/arch/powerpc/include/asm/mmu-book3e.h
@@ -287,11 +287,14 @@ extern int mmu_linear_psize;
extern int mmu_vmemmap_psize;
struct tlb_core_data {
+ /*
+ * Per-core spinlock for e6500 TLB handlers (no tlbsrx.)
+ * Must be the first struct element.
+ */
+ u8 lock;
+
/* For software way selection, as on Freescale TLB1 */
u8 esel_next, esel_max, esel_first;
-
- /* Per-core spinlock for e6500 TLB handlers (no tlbsrx.) */
- u8 lock;
};
#ifdef CONFIG_PPC64
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 40157e2ca691..fe2aa0b48d2b 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -83,6 +83,8 @@ extern int opal_enter_rtas(struct rtas_args *args,
#define OPAL_INTERNAL_ERROR -11
#define OPAL_BUSY_EVENT -12
#define OPAL_HARDWARE_FROZEN -13
+#define OPAL_WRONG_STATE -14
+#define OPAL_ASYNC_COMPLETION -15
/* API Tokens (in r0) */
#define OPAL_CONSOLE_WRITE 1
@@ -151,12 +153,27 @@ extern int opal_enter_rtas(struct rtas_args *args,
#define OPAL_LPC_READ 67
#define OPAL_LPC_WRITE 68
#define OPAL_RETURN_CPU 69
+#define OPAL_ELOG_READ 71
+#define OPAL_ELOG_WRITE 72
+#define OPAL_ELOG_ACK 73
+#define OPAL_ELOG_RESEND 74
+#define OPAL_ELOG_SIZE 75
#define OPAL_FLASH_VALIDATE 76
#define OPAL_FLASH_MANAGE 77
#define OPAL_FLASH_UPDATE 78
+#define OPAL_RESYNC_TIMEBASE 79
+#define OPAL_DUMP_INIT 81
+#define OPAL_DUMP_INFO 82
+#define OPAL_DUMP_READ 83
+#define OPAL_DUMP_ACK 84
#define OPAL_GET_MSG 85
#define OPAL_CHECK_ASYNC_COMPLETION 86
#define OPAL_SYNC_HOST_REBOOT 87
+#define OPAL_SENSOR_READ 88
+#define OPAL_GET_PARAM 89
+#define OPAL_SET_PARAM 90
+#define OPAL_DUMP_RESEND 91
+#define OPAL_DUMP_INFO2 94
#ifndef __ASSEMBLY__
@@ -237,11 +254,14 @@ enum OpalPendingState {
OPAL_EVENT_EPOW = 0x80,
OPAL_EVENT_LED_STATUS = 0x100,
OPAL_EVENT_PCI_ERROR = 0x200,
+ OPAL_EVENT_DUMP_AVAIL = 0x400,
OPAL_EVENT_MSG_PENDING = 0x800,
};
enum OpalMessageType {
- OPAL_MSG_ASYNC_COMP = 0,
+ OPAL_MSG_ASYNC_COMP = 0, /* params[0] = token, params[1] = rc,
+ * additional params function-specific
+ */
OPAL_MSG_MEM_ERR,
OPAL_MSG_EPOW,
OPAL_MSG_SHUTDOWN,
@@ -394,6 +414,13 @@ enum OpalLPCAddressType {
OPAL_LPC_FW = 2,
};
+/* System parameter permission */
+enum OpalSysparamPerm {
+ OPAL_SYSPARAM_READ = 0x1,
+ OPAL_SYSPARAM_WRITE = 0x2,
+ OPAL_SYSPARAM_RW = (OPAL_SYSPARAM_READ | OPAL_SYSPARAM_WRITE),
+};
+
struct opal_msg {
uint32_t msg_type;
uint32_t reserved;
@@ -816,23 +843,44 @@ int64_t opal_pci_next_error(uint64_t phb_id, uint64_t *first_frozen_pe,
int64_t opal_pci_poll(uint64_t phb_id);
int64_t opal_return_cpu(void);
-int64_t opal_xscom_read(uint32_t gcid, uint32_t pcb_addr, __be64 *val);
-int64_t opal_xscom_write(uint32_t gcid, uint32_t pcb_addr, uint64_t val);
+int64_t opal_xscom_read(uint32_t gcid, uint64_t pcb_addr, __be64 *val);
+int64_t opal_xscom_write(uint32_t gcid, uint64_t pcb_addr, uint64_t val);
int64_t opal_lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_type,
uint32_t addr, uint32_t data, uint32_t sz);
int64_t opal_lpc_read(uint32_t chip_id, enum OpalLPCAddressType addr_type,
uint32_t addr, __be32 *data, uint32_t sz);
+
+int64_t opal_read_elog(uint64_t buffer, size_t size, uint64_t log_id);
+int64_t opal_get_elog_size(uint64_t *log_id, size_t *size, uint64_t *elog_type);
+int64_t opal_write_elog(uint64_t buffer, uint64_t size, uint64_t offset);
+int64_t opal_send_ack_elog(uint64_t log_id);
+void opal_resend_pending_logs(void);
+
int64_t opal_validate_flash(uint64_t buffer, uint32_t *size, uint32_t *result);
int64_t opal_manage_flash(uint8_t op);
int64_t opal_update_flash(uint64_t blk_list);
+int64_t opal_dump_init(uint8_t dump_type);
+int64_t opal_dump_info(uint32_t *dump_id, uint32_t *dump_size);
+int64_t opal_dump_info2(uint32_t *dump_id, uint32_t *dump_size, uint32_t *dump_type);
+int64_t opal_dump_read(uint32_t dump_id, uint64_t buffer);
+int64_t opal_dump_ack(uint32_t dump_id);
+int64_t opal_dump_resend_notification(void);
int64_t opal_get_msg(uint64_t buffer, size_t size);
int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token);
int64_t opal_sync_host_reboot(void);
+int64_t opal_get_param(uint64_t token, uint32_t param_id, uint64_t buffer,
+ size_t length);
+int64_t opal_set_param(uint64_t token, uint32_t param_id, uint64_t buffer,
+ size_t length);
+int64_t opal_sensor_read(uint32_t sensor_hndl, int token,
+ uint32_t *sensor_data);
/* Internal functions */
extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data);
+extern int early_init_dt_scan_recoverable_ranges(unsigned long node,
+ const char *uname, int depth, void *data);
extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
@@ -853,6 +901,13 @@ extern void opal_notifier_update_evt(uint64_t evt_mask, uint64_t evt_val);
extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
+extern int __opal_async_get_token(void);
+extern int opal_async_get_token_interruptible(void);
+extern int __opal_async_release_token(int token);
+extern int opal_async_release_token(int token);
+extern int opal_async_wait_response(uint64_t token, struct opal_msg *msg);
+extern int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data);
+
extern void hvc_opal_init_early(void);
struct rtc_time;
@@ -861,10 +916,15 @@ extern void opal_get_rtc_time(struct rtc_time *tm);
extern unsigned long opal_get_boot_time(void);
extern void opal_nvram_init(void);
extern void opal_flash_init(void);
+extern int opal_elog_init(void);
+extern void opal_platform_dump_init(void);
+extern void opal_sys_param_init(void);
extern int opal_machine_check(struct pt_regs *regs);
+extern bool opal_mce_check_early_recovery(struct pt_regs *regs);
extern void opal_shutdown(void);
+extern int opal_resync_timebase(void);
extern void opal_lpc_init(void);
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 9c5dbc3833fb..8e956a0b6e85 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -116,8 +116,11 @@ struct paca_struct {
/* Shared by all threads of a core -- points to tcd of first thread */
struct tlb_core_data *tcd_ptr;
- /* We can have up to 3 levels of reentrancy in the TLB miss handler */
- u64 extlb[3][EX_TLB_SIZE / sizeof(u64)];
+ /*
+ * We can have up to 3 levels of reentrancy in the TLB miss handler,
+ * in each of four exception levels (normal, crit, mcheck, debug).
+ */
+ u64 extlb[12][EX_TLB_SIZE / sizeof(u64)];
u64 exmc[8]; /* used for machine checks */
u64 excrit[8]; /* used for crit interrupts */
u64 exdbg[8]; /* used for debug interrupts */
@@ -146,7 +149,7 @@ struct paca_struct {
u8 io_sync; /* writel() needs spin_unlock sync */
u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */
u8 nap_state_lost; /* NV GPR values lost in power7_idle */
- u64 sprg3; /* Saved user-visible sprg */
+ u64 sprg_vdso; /* Saved user-visible sprg */
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
u64 tm_scratch; /* TM scratch area for reclaim */
#endif
diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h
index 3fd2f1b6f906..9ed737146dbb 100644
--- a/arch/powerpc/include/asm/perf_event_server.h
+++ b/arch/powerpc/include/asm/perf_event_server.h
@@ -14,6 +14,7 @@
#include <linux/device.h>
#include <uapi/asm/perf_event.h>
+/* Update perf_event_print_debug() if this changes */
#define MAX_HWEVENTS 8
#define MAX_EVENT_ALTERNATIVES 8
#define MAX_LIMITED_HWCOUNTERS 2
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
index bc141c950b1e..eb9261024f51 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -195,6 +195,7 @@ extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
static inline unsigned long pte_update(struct mm_struct *mm,
unsigned long addr,
pte_t *ptep, unsigned long clr,
+ unsigned long set,
int huge)
{
#ifdef PTE_ATOMIC_UPDATES
@@ -205,14 +206,15 @@ static inline unsigned long pte_update(struct mm_struct *mm,
andi. %1,%0,%6\n\
bne- 1b \n\
andc %1,%0,%4 \n\
+ or %1,%1,%7\n\
stdcx. %1,0,%3 \n\
bne- 1b"
: "=&r" (old), "=&r" (tmp), "=m" (*ptep)
- : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY)
+ : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY), "r" (set)
: "cc" );
#else
unsigned long old = pte_val(*ptep);
- *ptep = __pte(old & ~clr);
+ *ptep = __pte((old & ~clr) | set);
#endif
/* huge pages use the old page table lock */
if (!huge)
@@ -231,9 +233,9 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
{
unsigned long old;
- if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
+ if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
return 0;
- old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0);
+ old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
return (old & _PAGE_ACCESSED) != 0;
}
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
@@ -252,7 +254,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
if ((pte_val(*ptep) & _PAGE_RW) == 0)
return;
- pte_update(mm, addr, ptep, _PAGE_RW, 0);
+ pte_update(mm, addr, ptep, _PAGE_RW, 0, 0);
}
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
@@ -261,7 +263,7 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
if ((pte_val(*ptep) & _PAGE_RW) == 0)
return;
- pte_update(mm, addr, ptep, _PAGE_RW, 1);
+ pte_update(mm, addr, ptep, _PAGE_RW, 0, 1);
}
/*
@@ -284,14 +286,14 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
{
- unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0);
+ unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0, 0);
return __pte(old);
}
static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
pte_t * ptep)
{
- pte_update(mm, addr, ptep, ~0UL, 0);
+ pte_update(mm, addr, ptep, ~0UL, 0, 0);
}
@@ -506,7 +508,9 @@ extern int pmdp_set_access_flags(struct vm_area_struct *vma,
extern unsigned long pmd_hugepage_update(struct mm_struct *mm,
unsigned long addr,
- pmd_t *pmdp, unsigned long clr);
+ pmd_t *pmdp,
+ unsigned long clr,
+ unsigned long set);
static inline int __pmdp_test_and_clear_young(struct mm_struct *mm,
unsigned long addr, pmd_t *pmdp)
@@ -515,7 +519,7 @@ static inline int __pmdp_test_and_clear_young(struct mm_struct *mm,
if ((pmd_val(*pmdp) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
return 0;
- old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED);
+ old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED, 0);
return ((old & _PAGE_ACCESSED) != 0);
}
@@ -542,7 +546,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr,
if ((pmd_val(*pmdp) & _PAGE_RW) == 0)
return;
- pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW);
+ pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW, 0);
}
#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index f83b6f3e1b39..3ebb188c3ff5 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -75,12 +75,34 @@ static inline pte_t pte_mknuma(pte_t pte)
return pte;
}
+#define ptep_set_numa ptep_set_numa
+static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ if ((pte_val(*ptep) & _PAGE_PRESENT) == 0)
+ VM_BUG_ON(1);
+
+ pte_update(mm, addr, ptep, _PAGE_PRESENT, _PAGE_NUMA, 0);
+ return;
+}
+
#define pmd_numa pmd_numa
static inline int pmd_numa(pmd_t pmd)
{
return pte_numa(pmd_pte(pmd));
}
+#define pmdp_set_numa pmdp_set_numa
+static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp)
+{
+ if ((pmd_val(*pmdp) & _PAGE_PRESENT) == 0)
+ VM_BUG_ON(1);
+
+ pmd_hugepage_update(mm, addr, pmdp, _PAGE_PRESENT, _PAGE_NUMA);
+ return;
+}
+
#define pmd_mknonnuma pmd_mknonnuma
static inline pmd_t pmd_mknonnuma(pmd_t pmd)
{
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index b62de43ae5f3..d660dc36831a 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -450,6 +450,7 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
extern int powersave_nap; /* set if nap mode can be used in idle loop */
extern void power7_nap(void);
+extern void power7_sleep(void);
extern void flush_instruction_cache(void);
extern void hard_reset_now(void);
extern void poweroff_now(void);
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index becc08e6a65c..279b80f3bb29 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -28,11 +28,23 @@
#ifdef __powerpc64__
+/*
+ * Size of redzone that userspace is allowed to use below the stack
+ * pointer. This is 288 in the 64-bit big-endian ELF ABI, and 512 in
+ * the new ELFv2 little-endian ABI, so we allow the larger amount.
+ *
+ * For kernel code we allow a 288-byte redzone, in order to conserve
+ * kernel stack space; gcc currently only uses 288 bytes, and will
+ * hopefully allow explicit control of the redzone size in future.
+ */
+#define USER_REDZONE_SIZE 512
+#define KERNEL_REDZONE_SIZE 288
+
#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */
#define STACK_FRAME_LR_SAVE 2 /* Location of LR in stack frame */
#define STACK_FRAME_REGS_MARKER ASM_CONST(0x7265677368657265)
#define STACK_INT_FRAME_SIZE (sizeof(struct pt_regs) + \
- STACK_FRAME_OVERHEAD + 288)
+ STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE)
#define STACK_FRAME_MARKER 12
/* Size of dummy stack frame allocated when calling signal handler. */
@@ -41,6 +53,8 @@
#else /* __powerpc64__ */
+#define USER_REDZONE_SIZE 0
+#define KERNEL_REDZONE_SIZE 0
#define STACK_FRAME_OVERHEAD 16 /* size of minimum stack frame */
#define STACK_FRAME_LR_SAVE 1 /* Location of LR in stack frame */
#define STACK_FRAME_REGS_MARKER ASM_CONST(0x72656773)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 90c06ec6eff5..0dcc48af25a3 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -213,6 +213,7 @@
#define SPRN_ACOP 0x1F /* Available Coprocessor Register */
#define SPRN_TFIAR 0x81 /* Transaction Failure Inst Addr */
#define SPRN_TEXASR 0x82 /* Transaction EXception & Summary */
+#define TEXASR_FS __MASK(63-36) /* Transaction Failure Summary */
#define SPRN_TEXASRU 0x83 /* '' '' '' Upper 32 */
#define SPRN_TFHAR 0x80 /* Transaction Failure Handler Addr */
#define SPRN_CTRLF 0x088
@@ -577,9 +578,13 @@
#define SPRN_SPRG3 0x113 /* Special Purpose Register General 3 */
#define SPRN_USPRG3 0x103 /* SPRG3 userspace read */
#define SPRN_SPRG4 0x114 /* Special Purpose Register General 4 */
+#define SPRN_USPRG4 0x104 /* SPRG4 userspace read */
#define SPRN_SPRG5 0x115 /* Special Purpose Register General 5 */
+#define SPRN_USPRG5 0x105 /* SPRG5 userspace read */
#define SPRN_SPRG6 0x116 /* Special Purpose Register General 6 */
+#define SPRN_USPRG6 0x106 /* SPRG6 userspace read */
#define SPRN_SPRG7 0x117 /* Special Purpose Register General 7 */
+#define SPRN_USPRG7 0x107 /* SPRG7 userspace read */
#define SPRN_SRR0 0x01A /* Save/Restore Register 0 */
#define SPRN_SRR1 0x01B /* Save/Restore Register 1 */
#define SRR1_ISI_NOPT 0x40000000 /* ISI: Not found in hash */
@@ -664,12 +669,14 @@
#define MMCR0_PMXE 0x04000000UL /* performance monitor exception enable */
#define MMCR0_FCECE 0x02000000UL /* freeze ctrs on enabled cond or event */
#define MMCR0_TBEE 0x00400000UL /* time base exception enable */
+#define MMCR0_BHRBA 0x00200000UL /* BHRB Access allowed in userspace */
#define MMCR0_EBE 0x00100000UL /* Event based branch enable */
#define MMCR0_PMCC 0x000c0000UL /* PMC control */
#define MMCR0_PMCC_U6 0x00080000UL /* PMC1-6 are R/W by user (PR) */
#define MMCR0_PMC1CE 0x00008000UL /* PMC1 count enable*/
#define MMCR0_PMCjCE 0x00004000UL /* PMCj count enable*/
#define MMCR0_TRIGGER 0x00002000UL /* TRIGGER enable */
+#define MMCR0_PMAO_SYNC 0x00000800UL /* PMU interrupt is synchronous */
#define MMCR0_PMAO 0x00000080UL /* performance monitor alert has occurred, set to 0 after handling exception */
#define MMCR0_SHRFC 0x00000040UL /* SHRre freeze conditions between threads */
#define MMCR0_FC56 0x00000010UL /* freeze counters 5 and 6 */
@@ -703,6 +710,7 @@
#define SPRN_EBBHR 804 /* Event based branch handler register */
#define SPRN_EBBRR 805 /* Event based branch return register */
#define SPRN_BESCR 806 /* Branch event status and control register */
+#define BESCR_GE 0x8000000000000000ULL /* Global Enable */
#define SPRN_WORT 895 /* Workload optimization register - thread */
#define SPRN_PMC1 787
@@ -879,11 +887,10 @@
* 64-bit embedded
* - SPRG0 generic exception scratch
* - SPRG2 TLB exception stack
- * - SPRG3 critical exception scratch and
- * CPU and NUMA node for VDSO getcpu (user visible)
+ * - SPRG3 critical exception scratch (user visible, sorry!)
* - SPRG4 unused (user visible)
* - SPRG6 TLB miss scratch (user visible, sorry !)
- * - SPRG7 critical exception scratch
+ * - SPRG7 CPU and NUMA node for VDSO getcpu (user visible)
* - SPRG8 machine check exception scratch
* - SPRG9 debug exception scratch
*
@@ -940,6 +947,8 @@
#define SPRN_SPRG_SCRATCH0 SPRN_SPRG2
#define SPRN_SPRG_HPACA SPRN_HSPRG0
#define SPRN_SPRG_HSCRATCH0 SPRN_HSPRG1
+#define SPRN_SPRG_VDSO_READ SPRN_USPRG3
+#define SPRN_SPRG_VDSO_WRITE SPRN_SPRG3
#define GET_PACA(rX) \
BEGIN_FTR_SECTION_NESTED(66); \
@@ -983,6 +992,8 @@
#define SPRN_SPRG_TLB_SCRATCH SPRN_SPRG6
#define SPRN_SPRG_GEN_SCRATCH SPRN_SPRG0
#define SPRN_SPRG_GDBELL_SCRATCH SPRN_SPRG_GEN_SCRATCH
+#define SPRN_SPRG_VDSO_READ SPRN_USPRG7
+#define SPRN_SPRG_VDSO_WRITE SPRN_SPRG7
#define SET_PACA(rX) mtspr SPRN_SPRG_PACA,rX
#define GET_PACA(rX) mfspr rX,SPRN_SPRG_PACA
@@ -1102,6 +1113,8 @@
#define PVR_8560 0x80200000
#define PVR_VER_E500V1 0x8020
#define PVR_VER_E500V2 0x8021
+#define PVR_VER_E500MC 0x8023
+#define PVR_VER_E5500 0x8024
#define PVR_VER_E6500 0x8040
/*
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 9bd52c65e66f..a0e1add01ef5 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -283,6 +283,7 @@ extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal);
#ifdef CONFIG_PPC_PSERIES
extern int pseries_devicetree_update(s32 scope);
+extern void post_mobility_fixup(void);
#endif
#ifdef CONFIG_PPC_RTAS_DAEMON
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index 084e0807db98..ff51046b6466 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -120,7 +120,7 @@ extern int cpu_to_core_id(int cpu);
* in /proc/interrupts will be wrong!!! --Troy */
#define PPC_MSG_CALL_FUNCTION 0
#define PPC_MSG_RESCHEDULE 1
-#define PPC_MSG_CALL_FUNC_SINGLE 2
+#define PPC_MSG_TICK_BROADCAST 2
#define PPC_MSG_DEBUGGER_BREAK 3
/* for irq controllers that have dedicated ipis per message (4) */
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h
index c1f267694acb..1d428e6007ca 100644
--- a/arch/powerpc/include/asm/time.h
+++ b/arch/powerpc/include/asm/time.h
@@ -28,6 +28,7 @@ extern struct clock_event_device decrementer_clockevent;
struct rtc_time;
extern void to_tm(int tim, struct rtc_time * tm);
extern void GregorianDay(struct rtc_time *tm);
+extern void tick_broadcast_ipi_handler(void);
extern void generic_calibrate_decr(void);
diff --git a/arch/powerpc/include/asm/tm.h b/arch/powerpc/include/asm/tm.h
index 0c9f8b74dd97..c22d704b6d41 100644
--- a/arch/powerpc/include/asm/tm.h
+++ b/arch/powerpc/include/asm/tm.h
@@ -7,6 +7,8 @@
#include <uapi/asm/tm.h>
+#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);
@@ -21,3 +23,5 @@ extern void tm_recheckpoint(struct thread_struct *thread,
extern void tm_abort(uint8_t cause);
extern void tm_save_sprs(struct thread_struct *thread);
extern void tm_restore_sprs(struct thread_struct *thread);
+
+#endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index d0b5fca6b077..c9202151079f 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -99,7 +99,6 @@ static inline int prrn_is_enabled(void)
#ifdef CONFIG_SMP
#include <asm/cputable.h>
-#define smt_capable() (cpu_has_feature(CPU_FTR_SMT))
#ifdef CONFIG_PPC64
#include <asm/smp.h>
diff --git a/arch/powerpc/include/asm/vdso.h b/arch/powerpc/include/asm/vdso.h
index 0d9cecddf8a4..c53f5f6d1761 100644
--- a/arch/powerpc/include/asm/vdso.h
+++ b/arch/powerpc/include/asm/vdso.h
@@ -4,11 +4,11 @@
#ifdef __KERNEL__
/* Default link addresses for the vDSOs */
-#define VDSO32_LBASE 0x100000
-#define VDSO64_LBASE 0x100000
+#define VDSO32_LBASE 0x0
+#define VDSO64_LBASE 0x0
/* Default map addresses for 32bit vDSO */
-#define VDSO32_MBASE VDSO32_LBASE
+#define VDSO32_MBASE 0x100000
#define VDSO_VERSION_STRING LINUX_2.6.15
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index b5aacf72ae6f..dba8140ebc20 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -253,7 +253,7 @@ int main(void)
DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
DEFINE(PACA_NAPSTATELOST, offsetof(struct paca_struct, nap_state_lost));
- DEFINE(PACA_SPRG3, offsetof(struct paca_struct, sprg3));
+ DEFINE(PACA_SPRG_VDSO, offsetof(struct paca_struct, sprg_vdso));
#endif /* CONFIG_PPC64 */
/* RTAS */
diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c
index 2912b8787aa4..40198d50b4c2 100644
--- a/arch/powerpc/kernel/cacheinfo.c
+++ b/arch/powerpc/kernel/cacheinfo.c
@@ -756,7 +756,10 @@ void cacheinfo_cpu_online(unsigned int cpu_id)
cacheinfo_sysfs_populate(cpu_id, cache);
}
-#ifdef CONFIG_HOTPLUG_CPU /* functions needed for cpu offline */
+/* functions needed to remove cache entry for cpu offline or suspend/resume */
+
+#if (defined(CONFIG_PPC_PSERIES) && defined(CONFIG_SUSPEND)) || \
+ defined(CONFIG_HOTPLUG_CPU)
static struct cache *cache_lookup_by_cpu(unsigned int cpu_id)
{
@@ -843,4 +846,4 @@ void cacheinfo_cpu_offline(unsigned int cpu_id)
if (cache)
cache_cpu_clear(cache, cpu_id);
}
-#endif /* CONFIG_HOTPLUG_CPU */
+#endif /* (CONFIG_PPC_PSERIES && CONFIG_SUSPEND) || CONFIG_HOTPLUG_CPU */
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 6c8dd5da4de5..c1faade6506d 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -510,7 +510,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.pvr_mask = 0xffff0000,
.pvr_value = 0x004b0000,
.cpu_name = "POWER8E (raw)",
- .cpu_features = CPU_FTRS_POWER8,
+ .cpu_features = CPU_FTRS_POWER8E,
.cpu_user_features = COMMON_USER_POWER8,
.cpu_user_features2 = COMMON_USER2_POWER8,
.mmu_features = MMU_FTRS_POWER8,
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
index 11c1d069d920..7a13f378ca2c 100644
--- a/arch/powerpc/kernel/crash_dump.c
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -98,17 +98,19 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
size_t csize, unsigned long offset, int userbuf)
{
void *vaddr;
+ phys_addr_t paddr;
if (!csize)
return 0;
csize = min_t(size_t, csize, PAGE_SIZE);
+ paddr = pfn << PAGE_SHIFT;
- if ((min_low_pfn < pfn) && (pfn < max_pfn)) {
- vaddr = __va(pfn << PAGE_SHIFT);
+ if (memblock_is_region_memory(paddr, csize)) {
+ vaddr = __va(paddr);
csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf);
} else {
- vaddr = __ioremap(pfn << PAGE_SHIFT, PAGE_SIZE, 0);
+ vaddr = __ioremap(paddr, PAGE_SIZE, 0);
csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf);
iounmap(vaddr);
}
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 148db72a8c43..e7b76a6bf150 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -28,6 +28,7 @@
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/rbtree.h>
+#include <linux/reboot.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/export.h>
@@ -89,7 +90,7 @@
/* Platform dependent EEH operations */
struct eeh_ops *eeh_ops = NULL;
-int eeh_subsystem_enabled;
+bool eeh_subsystem_enabled = false;
EXPORT_SYMBOL(eeh_subsystem_enabled);
/*
@@ -364,7 +365,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
eeh_stats.total_mmio_ffs++;
- if (!eeh_subsystem_enabled)
+ if (!eeh_enabled())
return 0;
if (!edev) {
@@ -747,6 +748,17 @@ int __exit eeh_ops_unregister(const char *name)
return -EEXIST;
}
+static int eeh_reboot_notifier(struct notifier_block *nb,
+ unsigned long action, void *unused)
+{
+ eeh_set_enable(false);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block eeh_reboot_nb = {
+ .notifier_call = eeh_reboot_notifier,
+};
+
/**
* eeh_init - EEH initialization
*
@@ -778,6 +790,14 @@ int eeh_init(void)
if (machine_is(powernv) && cnt++ <= 0)
return ret;
+ /* Register reboot notifier */
+ ret = register_reboot_notifier(&eeh_reboot_nb);
+ if (ret) {
+ pr_warn("%s: Failed to register notifier (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
/* call platform initialization function */
if (!eeh_ops) {
pr_warning("%s: Platform EEH operation not found\n",
@@ -822,7 +842,7 @@ int eeh_init(void)
return ret;
}
- if (eeh_subsystem_enabled)
+ if (eeh_enabled())
pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n");
else
pr_warning("EEH: No capable adapters found\n");
@@ -897,7 +917,7 @@ void eeh_add_device_late(struct pci_dev *dev)
struct device_node *dn;
struct eeh_dev *edev;
- if (!dev || !eeh_subsystem_enabled)
+ if (!dev || !eeh_enabled())
return;
pr_debug("EEH: Adding device %s\n", pci_name(dev));
@@ -1005,7 +1025,7 @@ void eeh_remove_device(struct pci_dev *dev)
{
struct eeh_dev *edev;
- if (!dev || !eeh_subsystem_enabled)
+ if (!dev || !eeh_enabled())
return;
edev = pci_dev_to_eeh_dev(dev);
@@ -1045,7 +1065,7 @@ void eeh_remove_device(struct pci_dev *dev)
static int proc_eeh_show(struct seq_file *m, void *v)
{
- if (0 == eeh_subsystem_enabled) {
+ if (!eeh_enabled()) {
seq_printf(m, "EEH Subsystem is globally disabled\n");
seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs);
} else {
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index fdc679d309ec..bb61ca58ca6d 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -143,13 +143,30 @@ static void eeh_disable_irq(struct pci_dev *dev)
static void eeh_enable_irq(struct pci_dev *dev)
{
struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
- struct irq_desc *desc;
if ((edev->mode) & EEH_DEV_IRQ_DISABLED) {
edev->mode &= ~EEH_DEV_IRQ_DISABLED;
-
- desc = irq_to_desc(dev->irq);
- if (desc && desc->depth > 0)
+ /*
+ * FIXME !!!!!
+ *
+ * This is just ass backwards. This maze has
+ * unbalanced irq_enable/disable calls. So instead of
+ * finding the root cause it works around the warning
+ * in the irq_enable code by conditionally calling
+ * into it.
+ *
+ * That's just wrong.The warning in the core code is
+ * there to tell people to fix their assymetries in
+ * their own code, not by abusing the core information
+ * to avoid it.
+ *
+ * I so wish that the assymetry would be the other way
+ * round and a few more irq_disable calls render that
+ * shit unusable forever.
+ *
+ * tglx
+ */
+ if (irqd_irq_disabled(irq_get_irq_data(dev->irq)))
enable_irq(dev->irq);
}
}
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
index 063b65dd4f27..c1bee3ce9d1f 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -34,7 +34,250 @@
* special interrupts from within a non-standard level will probably
* blow you up
*/
-#define SPECIAL_EXC_FRAME_SIZE INT_FRAME_SIZE
+#define SPECIAL_EXC_SRR0 0
+#define SPECIAL_EXC_SRR1 1
+#define SPECIAL_EXC_SPRG_GEN 2
+#define SPECIAL_EXC_SPRG_TLB 3
+#define SPECIAL_EXC_MAS0 4
+#define SPECIAL_EXC_MAS1 5
+#define SPECIAL_EXC_MAS2 6
+#define SPECIAL_EXC_MAS3 7
+#define SPECIAL_EXC_MAS6 8
+#define SPECIAL_EXC_MAS7 9
+#define SPECIAL_EXC_MAS5 10 /* E.HV only */
+#define SPECIAL_EXC_MAS8 11 /* E.HV only */
+#define SPECIAL_EXC_IRQHAPPENED 12
+#define SPECIAL_EXC_DEAR 13
+#define SPECIAL_EXC_ESR 14
+#define SPECIAL_EXC_SOFTE 15
+#define SPECIAL_EXC_CSRR0 16
+#define SPECIAL_EXC_CSRR1 17
+/* must be even to keep 16-byte stack alignment */
+#define SPECIAL_EXC_END 18
+
+#define SPECIAL_EXC_FRAME_SIZE (INT_FRAME_SIZE + SPECIAL_EXC_END * 8)
+#define SPECIAL_EXC_FRAME_OFFS (INT_FRAME_SIZE - 288)
+
+#define SPECIAL_EXC_STORE(reg, name) \
+ std reg, (SPECIAL_EXC_##name * 8 + SPECIAL_EXC_FRAME_OFFS)(r1)
+
+#define SPECIAL_EXC_LOAD(reg, name) \
+ ld reg, (SPECIAL_EXC_##name * 8 + SPECIAL_EXC_FRAME_OFFS)(r1)
+
+special_reg_save:
+ lbz r9,PACAIRQHAPPENED(r13)
+ RECONCILE_IRQ_STATE(r3,r4)
+
+ /*
+ * We only need (or have stack space) to save this stuff if
+ * we interrupted the kernel.
+ */
+ ld r3,_MSR(r1)
+ andi. r3,r3,MSR_PR
+ bnelr
+
+ /* Copy info into temporary exception thread info */
+ ld r11,PACAKSAVE(r13)
+ CURRENT_THREAD_INFO(r11, r11)
+ CURRENT_THREAD_INFO(r12, r1)
+ ld r10,TI_FLAGS(r11)
+ std r10,TI_FLAGS(r12)
+ ld r10,TI_PREEMPT(r11)
+ std r10,TI_PREEMPT(r12)
+ ld r10,TI_TASK(r11)
+ std r10,TI_TASK(r12)
+
+ /*
+ * Advance to the next TLB exception frame for handler
+ * types that don't do it automatically.
+ */
+ LOAD_REG_ADDR(r11,extlb_level_exc)
+ lwz r12,0(r11)
+ mfspr r10,SPRN_SPRG_TLB_EXFRAME
+ add r10,r10,r12
+ mtspr SPRN_SPRG_TLB_EXFRAME,r10
+
+ /*
+ * Save registers needed to allow nesting of certain exceptions
+ * (such as TLB misses) inside special exception levels
+ */
+ mfspr r10,SPRN_SRR0
+ SPECIAL_EXC_STORE(r10,SRR0)
+ mfspr r10,SPRN_SRR1
+ SPECIAL_EXC_STORE(r10,SRR1)
+ mfspr r10,SPRN_SPRG_GEN_SCRATCH
+ SPECIAL_EXC_STORE(r10,SPRG_GEN)
+ mfspr r10,SPRN_SPRG_TLB_SCRATCH
+ SPECIAL_EXC_STORE(r10,SPRG_TLB)
+ mfspr r10,SPRN_MAS0
+ SPECIAL_EXC_STORE(r10,MAS0)
+ mfspr r10,SPRN_MAS1
+ SPECIAL_EXC_STORE(r10,MAS1)
+ mfspr r10,SPRN_MAS2
+ SPECIAL_EXC_STORE(r10,MAS2)
+ mfspr r10,SPRN_MAS3
+ SPECIAL_EXC_STORE(r10,MAS3)
+ mfspr r10,SPRN_MAS6
+ SPECIAL_EXC_STORE(r10,MAS6)
+ mfspr r10,SPRN_MAS7
+ SPECIAL_EXC_STORE(r10,MAS7)
+BEGIN_FTR_SECTION
+ mfspr r10,SPRN_MAS5
+ SPECIAL_EXC_STORE(r10,MAS5)
+ mfspr r10,SPRN_MAS8
+ SPECIAL_EXC_STORE(r10,MAS8)
+
+ /* MAS5/8 could have inappropriate values if we interrupted KVM code */
+ li r10,0
+ mtspr SPRN_MAS5,r10
+ mtspr SPRN_MAS8,r10
+END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV)
+ SPECIAL_EXC_STORE(r9,IRQHAPPENED)
+
+ mfspr r10,SPRN_DEAR
+ SPECIAL_EXC_STORE(r10,DEAR)
+ mfspr r10,SPRN_ESR
+ SPECIAL_EXC_STORE(r10,ESR)
+
+ lbz r10,PACASOFTIRQEN(r13)
+ SPECIAL_EXC_STORE(r10,SOFTE)
+ ld r10,_NIP(r1)
+ SPECIAL_EXC_STORE(r10,CSRR0)
+ ld r10,_MSR(r1)
+ SPECIAL_EXC_STORE(r10,CSRR1)
+
+ blr
+
+ret_from_level_except:
+ ld r3,_MSR(r1)
+ andi. r3,r3,MSR_PR
+ beq 1f
+ b ret_from_except
+1:
+
+ LOAD_REG_ADDR(r11,extlb_level_exc)
+ lwz r12,0(r11)
+ mfspr r10,SPRN_SPRG_TLB_EXFRAME
+ sub r10,r10,r12
+ mtspr SPRN_SPRG_TLB_EXFRAME,r10
+
+ /*
+ * It's possible that the special level exception interrupted a
+ * TLB miss handler, and inserted the same entry that the
+ * interrupted handler was about to insert. On CPUs without TLB
+ * write conditional, this can result in a duplicate TLB entry.
+ * Wipe all non-bolted entries to be safe.
+ *
+ * Note that this doesn't protect against any TLB misses
+ * we may take accessing the stack from here to the end of
+ * the special level exception. It's not clear how we can
+ * reasonably protect against that, but only CPUs with
+ * neither TLB write conditional nor bolted kernel memory
+ * are affected. Do any such CPUs even exist?
+ */
+ PPC_TLBILX_ALL(0,R0)
+
+ REST_NVGPRS(r1)
+
+ SPECIAL_EXC_LOAD(r10,SRR0)
+ mtspr SPRN_SRR0,r10
+ SPECIAL_EXC_LOAD(r10,SRR1)
+ mtspr SPRN_SRR1,r10
+ SPECIAL_EXC_LOAD(r10,SPRG_GEN)
+ mtspr SPRN_SPRG_GEN_SCRATCH,r10
+ SPECIAL_EXC_LOAD(r10,SPRG_TLB)
+ mtspr SPRN_SPRG_TLB_SCRATCH,r10
+ SPECIAL_EXC_LOAD(r10,MAS0)
+ mtspr SPRN_MAS0,r10
+ SPECIAL_EXC_LOAD(r10,MAS1)
+ mtspr SPRN_MAS1,r10
+ SPECIAL_EXC_LOAD(r10,MAS2)
+ mtspr SPRN_MAS2,r10
+ SPECIAL_EXC_LOAD(r10,MAS3)
+ mtspr SPRN_MAS3,r10
+ SPECIAL_EXC_LOAD(r10,MAS6)
+ mtspr SPRN_MAS6,r10
+ SPECIAL_EXC_LOAD(r10,MAS7)
+ mtspr SPRN_MAS7,r10
+BEGIN_FTR_SECTION
+ SPECIAL_EXC_LOAD(r10,MAS5)
+ mtspr SPRN_MAS5,r10
+ SPECIAL_EXC_LOAD(r10,MAS8)
+ mtspr SPRN_MAS8,r10
+END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV)
+
+ lbz r6,PACASOFTIRQEN(r13)
+ ld r5,SOFTE(r1)
+
+ /* Interrupts had better not already be enabled... */
+ twnei r6,0
+
+ cmpwi cr0,r5,0
+ beq 1f
+
+ TRACE_ENABLE_INTS
+ stb r5,PACASOFTIRQEN(r13)
+1:
+ /*
+ * Restore PACAIRQHAPPENED rather than setting it based on
+ * the return MSR[EE], since we could have interrupted
+ * __check_irq_replay() or other inconsistent transitory
+ * states that must remain that way.
+ */
+ SPECIAL_EXC_LOAD(r10,IRQHAPPENED)
+ stb r10,PACAIRQHAPPENED(r13)
+
+ SPECIAL_EXC_LOAD(r10,DEAR)
+ mtspr SPRN_DEAR,r10
+ SPECIAL_EXC_LOAD(r10,ESR)
+ mtspr SPRN_ESR,r10
+
+ stdcx. r0,0,r1 /* to clear the reservation */
+
+ REST_4GPRS(2, r1)
+ REST_4GPRS(6, r1)
+
+ ld r10,_CTR(r1)
+ ld r11,_XER(r1)
+ mtctr r10
+ mtxer r11
+
+ blr
+
+.macro ret_from_level srr0 srr1 paca_ex scratch
+ bl ret_from_level_except
+
+ ld r10,_LINK(r1)
+ ld r11,_CCR(r1)
+ ld r0,GPR13(r1)
+ mtlr r10
+ mtcr r11
+
+ ld r10,GPR10(r1)
+ ld r11,GPR11(r1)
+ ld r12,GPR12(r1)
+ mtspr \scratch,r0
+
+ std r10,\paca_ex+EX_R10(r13);
+ std r11,\paca_ex+EX_R11(r13);
+ ld r10,_NIP(r1)
+ ld r11,_MSR(r1)
+ ld r0,GPR0(r1)
+ ld r1,GPR1(r1)
+ mtspr \srr0,r10
+ mtspr \srr1,r11
+ ld r10,\paca_ex+EX_R10(r13)
+ ld r11,\paca_ex+EX_R11(r13)
+ mfspr r13,\scratch
+.endm
+
+ret_from_crit_except:
+ ret_from_level SPRN_CSRR0 SPRN_CSRR1 PACA_EXCRIT SPRN_SPRG_CRIT_SCRATCH
+ rfci
+
+ret_from_mc_except:
+ ret_from_level SPRN_MCSRR0 SPRN_MCSRR1 PACA_EXMC SPRN_SPRG_MC_SCRATCH
+ rfmci
/* Exception prolog code for all exceptions */
#define EXCEPTION_PROLOG(n, intnum, type, addition) \
@@ -42,7 +285,6 @@
mfspr r13,SPRN_SPRG_PACA; /* get PACA */ \
std r10,PACA_EX##type+EX_R10(r13); \
std r11,PACA_EX##type+EX_R11(r13); \
- PROLOG_STORE_RESTORE_SCRATCH_##type; \
mfcr r10; /* save CR */ \
mfspr r11,SPRN_##type##_SRR1;/* what are we coming from */ \
DO_KVM intnum,SPRN_##type##_SRR1; /* KVM hook */ \
@@ -69,19 +311,19 @@
#define CRIT_SET_KSTACK \
ld r1,PACA_CRIT_STACK(r13); \
- subi r1,r1,SPECIAL_EXC_FRAME_SIZE;
+ subi r1,r1,SPECIAL_EXC_FRAME_SIZE
#define SPRN_CRIT_SRR0 SPRN_CSRR0
#define SPRN_CRIT_SRR1 SPRN_CSRR1
#define DBG_SET_KSTACK \
ld r1,PACA_DBG_STACK(r13); \
- subi r1,r1,SPECIAL_EXC_FRAME_SIZE;
+ subi r1,r1,SPECIAL_EXC_FRAME_SIZE
#define SPRN_DBG_SRR0 SPRN_DSRR0
#define SPRN_DBG_SRR1 SPRN_DSRR1
#define MC_SET_KSTACK \
ld r1,PACA_MC_STACK(r13); \
- subi r1,r1,SPECIAL_EXC_FRAME_SIZE;
+ subi r1,r1,SPECIAL_EXC_FRAME_SIZE
#define SPRN_MC_SRR0 SPRN_MCSRR0
#define SPRN_MC_SRR1 SPRN_MCSRR1
@@ -100,20 +342,6 @@
#define GDBELL_EXCEPTION_PROLOG(n, intnum, addition) \
EXCEPTION_PROLOG(n, intnum, GDBELL, addition##_GDBELL(n))
-/*
- * Store user-visible scratch in PACA exception slots and restore proper value
- */
-#define PROLOG_STORE_RESTORE_SCRATCH_GEN
-#define PROLOG_STORE_RESTORE_SCRATCH_GDBELL
-#define PROLOG_STORE_RESTORE_SCRATCH_DBG
-#define PROLOG_STORE_RESTORE_SCRATCH_MC
-
-#define PROLOG_STORE_RESTORE_SCRATCH_CRIT \
- mfspr r10,SPRN_SPRG_CRIT_SCRATCH; /* get r13 */ \
- std r10,PACA_EXCRIT+EX_R13(r13); \
- ld r11,PACA_SPRG3(r13); \
- mtspr SPRN_SPRG_CRIT_SCRATCH,r11;
-
/* Variants of the "addition" argument for the prolog
*/
#define PROLOG_ADDITION_NONE_GEN(n)
@@ -147,10 +375,8 @@
std r15,PACA_EXMC+EX_R15(r13)
-/* Core exception code for all exceptions except TLB misses.
- * XXX: Needs to make SPRN_SPRG_GEN depend on exception type
- */
-#define EXCEPTION_COMMON(n, excf, ints) \
+/* Core exception code for all exceptions except TLB misses. */
+#define EXCEPTION_COMMON_LVL(n, scratch, excf) \
exc_##n##_common: \
std r0,GPR0(r1); /* save r0 in stackframe */ \
std r2,GPR2(r1); /* save r2 in stackframe */ \
@@ -163,7 +389,7 @@ exc_##n##_common: \
ACCOUNT_CPU_USER_ENTRY(r10,r11);/* accounting (uses cr0+eq) */ \
2: ld r3,excf+EX_R10(r13); /* get back r10 */ \
ld r4,excf+EX_R11(r13); /* get back r11 */ \
- mfspr r5,SPRN_SPRG_GEN_SCRATCH;/* get back r13 */ \
+ mfspr r5,scratch; /* get back r13 */ \
std r12,GPR12(r1); /* save r12 in stackframe */ \
ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \
mflr r6; /* save LR in stackframe */ \
@@ -187,24 +413,29 @@ exc_##n##_common: \
std r11,SOFTE(r1); /* and save it to stackframe */ \
std r12,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ \
std r3,_TRAP(r1); /* set trap number */ \
- std r0,RESULT(r1); /* clear regs->result */ \
- ints;
+ std r0,RESULT(r1); /* clear regs->result */
-/* Variants for the "ints" argument. This one does nothing when we want
- * to keep interrupts in their original state
- */
-#define INTS_KEEP
+#define EXCEPTION_COMMON(n) \
+ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_GEN_SCRATCH, PACA_EXGEN)
+#define EXCEPTION_COMMON_CRIT(n) \
+ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_CRIT_SCRATCH, PACA_EXCRIT)
+#define EXCEPTION_COMMON_MC(n) \
+ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_MC_SCRATCH, PACA_EXMC)
+#define EXCEPTION_COMMON_DBG(n) \
+ EXCEPTION_COMMON_LVL(n, SPRN_SPRG_DBG_SCRATCH, PACA_EXDBG)
-/* This second version is meant for exceptions that don't immediately
- * hard-enable. We set a bit in paca->irq_happened to ensure that
- * a subsequent call to arch_local_irq_restore() will properly
- * hard-enable and avoid the fast-path, and then reconcile irq state.
+/*
+ * This is meant for exceptions that don't immediately hard-enable. We
+ * set a bit in paca->irq_happened to ensure that a subsequent call to
+ * arch_local_irq_restore() will properly hard-enable and avoid the
+ * fast-path, and then reconcile irq state.
*/
#define INTS_DISABLE RECONCILE_IRQ_STATE(r3,r4)
-/* This is called by exceptions that used INTS_KEEP (that did not touch
- * irq indicators in the PACA). This will restore MSR:EE to it's previous
- * value
+/*
+ * This is called by exceptions that don't use INTS_DISABLE (that did not
+ * touch irq indicators in the PACA). This will restore MSR:EE to it's
+ * previous value
*
* XXX In the long run, we may want to open-code it in order to separate the
* load from the wrtee, thus limiting the latency caused by the dependency
@@ -262,7 +493,8 @@ exc_##n##_bad_stack: \
#define MASKABLE_EXCEPTION(trapnum, intnum, label, hdlr, ack) \
START_EXCEPTION(label); \
NORMAL_EXCEPTION_PROLOG(trapnum, intnum, PROLOG_ADDITION_MASKABLE)\
- EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE) \
+ EXCEPTION_COMMON(trapnum) \
+ INTS_DISABLE; \
ack(r8); \
CHECK_NAPPING(); \
addi r3,r1,STACK_FRAME_OVERHEAD; \
@@ -283,8 +515,8 @@ exception_marker:
.balign 0x1000
.globl interrupt_base_book3e
interrupt_base_book3e: /* fake trap */
- EXCEPTION_STUB(0x000, machine_check) /* 0x0200 */
- EXCEPTION_STUB(0x020, critical_input) /* 0x0580 */
+ EXCEPTION_STUB(0x000, machine_check)
+ EXCEPTION_STUB(0x020, critical_input) /* 0x0100 */
EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */
EXCEPTION_STUB(0x060, data_storage) /* 0x0300 */
EXCEPTION_STUB(0x080, instruction_storage) /* 0x0400 */
@@ -299,8 +531,8 @@ interrupt_base_book3e: /* fake trap */
EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */
EXCEPTION_STUB(0x1c0, data_tlb_miss)
EXCEPTION_STUB(0x1e0, instruction_tlb_miss)
- EXCEPTION_STUB(0x200, altivec_unavailable) /* 0x0f20 */
- EXCEPTION_STUB(0x220, altivec_assist) /* 0x1700 */
+ EXCEPTION_STUB(0x200, altivec_unavailable)
+ EXCEPTION_STUB(0x220, altivec_assist)
EXCEPTION_STUB(0x260, perfmon)
EXCEPTION_STUB(0x280, doorbell)
EXCEPTION_STUB(0x2a0, doorbell_crit)
@@ -317,25 +549,25 @@ interrupt_end_book3e:
START_EXCEPTION(critical_input);
CRIT_EXCEPTION_PROLOG(0x100, BOOKE_INTERRUPT_CRITICAL,
PROLOG_ADDITION_NONE)
-// EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE)
-// bl special_reg_save_crit
-// CHECK_NAPPING();
-// addi r3,r1,STACK_FRAME_OVERHEAD
-// bl .critical_exception
-// b ret_from_crit_except
- b .
+ EXCEPTION_COMMON_CRIT(0x100)
+ bl .save_nvgprs
+ bl special_reg_save
+ CHECK_NAPPING();
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .unknown_exception
+ b ret_from_crit_except
/* Machine Check Interrupt */
START_EXCEPTION(machine_check);
- MC_EXCEPTION_PROLOG(0x200, BOOKE_INTERRUPT_MACHINE_CHECK,
+ MC_EXCEPTION_PROLOG(0x000, BOOKE_INTERRUPT_MACHINE_CHECK,
PROLOG_ADDITION_NONE)
-// EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE)
-// bl special_reg_save_mc
-// addi r3,r1,STACK_FRAME_OVERHEAD
-// CHECK_NAPPING();
-// bl .machine_check_exception
-// b ret_from_mc_except
- b .
+ EXCEPTION_COMMON_MC(0x000)
+ bl .save_nvgprs
+ bl special_reg_save
+ CHECK_NAPPING();
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .machine_check_exception
+ b ret_from_mc_except
/* Data Storage Interrupt */
START_EXCEPTION(data_storage)
@@ -343,7 +575,8 @@ interrupt_end_book3e:
PROLOG_ADDITION_2REGS)
mfspr r14,SPRN_DEAR
mfspr r15,SPRN_ESR
- EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_DISABLE)
+ EXCEPTION_COMMON(0x300)
+ INTS_DISABLE
b storage_fault_common
/* Instruction Storage Interrupt */
@@ -352,7 +585,8 @@ interrupt_end_book3e:
PROLOG_ADDITION_2REGS)
li r15,0
mr r14,r10
- EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_DISABLE)
+ EXCEPTION_COMMON(0x400)
+ INTS_DISABLE
b storage_fault_common
/* External Input Interrupt */
@@ -365,7 +599,7 @@ interrupt_end_book3e:
PROLOG_ADDITION_2REGS)
mfspr r14,SPRN_DEAR
mfspr r15,SPRN_ESR
- EXCEPTION_COMMON(0x600, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x600)
b alignment_more /* no room, go out of line */
/* Program Interrupt */
@@ -373,7 +607,8 @@ interrupt_end_book3e:
NORMAL_EXCEPTION_PROLOG(0x700, BOOKE_INTERRUPT_PROGRAM,
PROLOG_ADDITION_1REG)
mfspr r14,SPRN_ESR
- EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE)
+ EXCEPTION_COMMON(0x700)
+ INTS_DISABLE
std r14,_DSISR(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
ld r14,PACA_EXGEN+EX_R14(r13)
@@ -386,7 +621,7 @@ interrupt_end_book3e:
NORMAL_EXCEPTION_PROLOG(0x800, BOOKE_INTERRUPT_FP_UNAVAIL,
PROLOG_ADDITION_NONE)
/* we can probably do a shorter exception entry for that one... */
- EXCEPTION_COMMON(0x800, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x800)
ld r12,_MSR(r1)
andi. r0,r12,MSR_PR;
beq- 1f
@@ -403,7 +638,7 @@ interrupt_end_book3e:
NORMAL_EXCEPTION_PROLOG(0x200, BOOKE_INTERRUPT_SPE_ALTIVEC_UNAVAIL,
PROLOG_ADDITION_NONE)
/* we can probably do a shorter exception entry for that one... */
- EXCEPTION_COMMON(0x200, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x200)
#ifdef CONFIG_ALTIVEC
BEGIN_FTR_SECTION
ld r12,_MSR(r1)
@@ -425,7 +660,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
NORMAL_EXCEPTION_PROLOG(0x220,
BOOKE_INTERRUPT_SPE_FP_DATA_ALTIVEC_ASSIST,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0x220, PACA_EXGEN, INTS_DISABLE)
+ EXCEPTION_COMMON(0x220)
+ INTS_DISABLE
bl .save_nvgprs
addi r3,r1,STACK_FRAME_OVERHEAD
#ifdef CONFIG_ALTIVEC
@@ -450,13 +686,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
START_EXCEPTION(watchdog);
CRIT_EXCEPTION_PROLOG(0x9f0, BOOKE_INTERRUPT_WATCHDOG,
PROLOG_ADDITION_NONE)
-// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE)
-// bl special_reg_save_crit
-// CHECK_NAPPING();
-// addi r3,r1,STACK_FRAME_OVERHEAD
-// bl .unknown_exception
-// b ret_from_crit_except
- b .
+ EXCEPTION_COMMON_CRIT(0x9f0)
+ bl .save_nvgprs
+ bl special_reg_save
+ CHECK_NAPPING();
+ addi r3,r1,STACK_FRAME_OVERHEAD
+#ifdef CONFIG_BOOKE_WDT
+ bl .WatchdogException
+#else
+ bl .unknown_exception
+#endif
+ b ret_from_crit_except
/* System Call Interrupt */
START_EXCEPTION(system_call)
@@ -470,7 +710,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
START_EXCEPTION(ap_unavailable);
NORMAL_EXCEPTION_PROLOG(0xf20, BOOKE_INTERRUPT_AP_UNAVAIL,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_DISABLE)
+ EXCEPTION_COMMON(0xf20)
+ INTS_DISABLE
bl .save_nvgprs
addi r3,r1,STACK_FRAME_OVERHEAD
bl .unknown_exception
@@ -513,7 +754,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
mtcr r10
ld r10,PACA_EXCRIT+EX_R10(r13) /* restore registers */
ld r11,PACA_EXCRIT+EX_R11(r13)
- ld r13,PACA_EXCRIT+EX_R13(r13)
+ mfspr r13,SPRN_SPRG_CRIT_SCRATCH
rfci
/* Normal debug exception */
@@ -526,10 +767,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
/* Now we mash up things to make it look like we are coming on a
* normal exception
*/
- ld r15,PACA_EXCRIT+EX_R13(r13)
- mtspr SPRN_SPRG_GEN_SCRATCH,r15
mfspr r14,SPRN_DBSR
- EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE)
+ EXCEPTION_COMMON_CRIT(0xd00)
std r14,_DSISR(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
mr r4,r14
@@ -592,10 +831,9 @@ kernel_dbg_exc:
/* Now we mash up things to make it look like we are coming on a
* normal exception
*/
- mfspr r15,SPRN_SPRG_DBG_SCRATCH
- mtspr SPRN_SPRG_GEN_SCRATCH,r15
mfspr r14,SPRN_DBSR
- EXCEPTION_COMMON(0xd08, PACA_EXDBG, INTS_DISABLE)
+ EXCEPTION_COMMON_DBG(0xd08)
+ INTS_DISABLE
std r14,_DSISR(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
mr r4,r14
@@ -608,7 +846,8 @@ kernel_dbg_exc:
START_EXCEPTION(perfmon);
NORMAL_EXCEPTION_PROLOG(0x260, BOOKE_INTERRUPT_PERFORMANCE_MONITOR,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0x260, PACA_EXGEN, INTS_DISABLE)
+ EXCEPTION_COMMON(0x260)
+ INTS_DISABLE
CHECK_NAPPING()
addi r3,r1,STACK_FRAME_OVERHEAD
bl .performance_monitor_exception
@@ -622,13 +861,13 @@ kernel_dbg_exc:
START_EXCEPTION(doorbell_crit);
CRIT_EXCEPTION_PROLOG(0x2a0, BOOKE_INTERRUPT_DOORBELL_CRITICAL,
PROLOG_ADDITION_NONE)
-// EXCEPTION_COMMON(0x2a0, PACA_EXCRIT, INTS_DISABLE)
-// bl special_reg_save_crit
-// CHECK_NAPPING();
-// addi r3,r1,STACK_FRAME_OVERHEAD
-// bl .doorbell_critical_exception
-// b ret_from_crit_except
- b .
+ EXCEPTION_COMMON_CRIT(0x2a0)
+ bl .save_nvgprs
+ bl special_reg_save
+ CHECK_NAPPING();
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .unknown_exception
+ b ret_from_crit_except
/*
* Guest doorbell interrupt
@@ -637,7 +876,7 @@ kernel_dbg_exc:
START_EXCEPTION(guest_doorbell);
GDBELL_EXCEPTION_PROLOG(0x2c0, BOOKE_INTERRUPT_GUEST_DBELL,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0x2c0, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x2c0)
addi r3,r1,STACK_FRAME_OVERHEAD
bl .save_nvgprs
INTS_RESTORE_HARD
@@ -648,19 +887,19 @@ kernel_dbg_exc:
START_EXCEPTION(guest_doorbell_crit);
CRIT_EXCEPTION_PROLOG(0x2e0, BOOKE_INTERRUPT_GUEST_DBELL_CRIT,
PROLOG_ADDITION_NONE)
-// EXCEPTION_COMMON(0x2e0, PACA_EXCRIT, INTS_DISABLE)
-// bl special_reg_save_crit
-// CHECK_NAPPING();
-// addi r3,r1,STACK_FRAME_OVERHEAD
-// bl .guest_doorbell_critical_exception
-// b ret_from_crit_except
- b .
+ EXCEPTION_COMMON_CRIT(0x2e0)
+ bl .save_nvgprs
+ bl special_reg_save
+ CHECK_NAPPING();
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .unknown_exception
+ b ret_from_crit_except
/* Hypervisor call */
START_EXCEPTION(hypercall);
NORMAL_EXCEPTION_PROLOG(0x310, BOOKE_INTERRUPT_HV_SYSCALL,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0x310, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x310)
addi r3,r1,STACK_FRAME_OVERHEAD
bl .save_nvgprs
INTS_RESTORE_HARD
@@ -671,7 +910,7 @@ kernel_dbg_exc:
START_EXCEPTION(ehpriv);
NORMAL_EXCEPTION_PROLOG(0x320, BOOKE_INTERRUPT_HV_PRIV,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0x320, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x320)
addi r3,r1,STACK_FRAME_OVERHEAD
bl .save_nvgprs
INTS_RESTORE_HARD
@@ -682,7 +921,7 @@ kernel_dbg_exc:
START_EXCEPTION(lrat_error);
NORMAL_EXCEPTION_PROLOG(0x340, BOOKE_INTERRUPT_LRAT_ERROR,
PROLOG_ADDITION_NONE)
- EXCEPTION_COMMON(0x340, PACA_EXGEN, INTS_KEEP)
+ EXCEPTION_COMMON(0x340)
addi r3,r1,STACK_FRAME_OVERHEAD
bl .save_nvgprs
INTS_RESTORE_HARD
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 38d507306a11..d9c650ec7dac 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -121,9 +121,10 @@ BEGIN_FTR_SECTION
cmpwi cr1,r13,2
/* Total loss of HV state is fatal, we could try to use the
* PIR to locate a PACA, then use an emergency stack etc...
- * but for now, let's just stay stuck here
+ * OPAL v3 based powernv platforms have new idle states
+ * which fall in this catagory.
*/
- bgt cr1,.
+ bgt cr1,8f
GET_PACA(r13)
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
@@ -141,6 +142,11 @@ BEGIN_FTR_SECTION
beq cr1,2f
b .power7_wakeup_noloss
2: b .power7_wakeup_loss
+
+ /* Fast Sleep wakeup on PowerNV */
+8: GET_PACA(r13)
+ b .power7_wakeup_tb_loss
+
9:
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
#endif /* CONFIG_PPC_P7_NAP */
@@ -164,13 +170,18 @@ BEGIN_FTR_SECTION
*/
mfspr r13,SPRN_SRR1
rlwinm. r13,r13,47-31,30,31
+ OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
beq 9f
+ mfspr r13,SPRN_SRR1
+ rlwinm. r13,r13,47-31,30,31
/* waking up from powersave (nap) state */
cmpwi cr1,r13,2
/* Total loss of HV state is fatal. let's just stay stuck here */
+ OPT_GET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
bgt cr1,.
9:
+ OPT_SET_SPR(r13, SPRN_CFAR, CPU_FTR_CFAR)
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
#endif /* CONFIG_PPC_P7_NAP */
EXCEPTION_PROLOG_0(PACA_EXMC)
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index 9b27b293a922..b0ded97ee4e1 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -74,6 +74,7 @@ ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new)
*/
static int test_24bit_addr(unsigned long ip, unsigned long addr)
{
+ addr = ppc_function_entry((void *)addr);
/* use the create_branch to verify that this offset can be branched */
return create_branch((unsigned int *)ip, addr, 0);
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
index 3fdef0f0c67f..c3ab86975614 100644
--- a/arch/powerpc/kernel/idle_power7.S
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -17,20 +17,31 @@
#include <asm/ppc-opcode.h>
#include <asm/hw_irq.h>
#include <asm/kvm_book3s_asm.h>
+#include <asm/opal.h>
#undef DEBUG
- .text
+/* Idle state entry routines */
-_GLOBAL(power7_idle)
- /* Now check if user or arch enabled NAP mode */
- LOAD_REG_ADDRBASE(r3,powersave_nap)
- lwz r4,ADDROFF(powersave_nap)(r3)
- cmpwi 0,r4,0
- beqlr
- /* fall through */
+#define IDLE_STATE_ENTER_SEQ(IDLE_INST) \
+ /* Magic NAP/SLEEP/WINKLE mode enter sequence */ \
+ std r0,0(r1); \
+ ptesync; \
+ ld r0,0(r1); \
+1: cmp cr0,r0,r0; \
+ bne 1b; \
+ IDLE_INST; \
+ b .
-_GLOBAL(power7_nap)
+ .text
+
+/*
+ * Pass requested state in r3:
+ * 0 - nap
+ * 1 - sleep
+ */
+_GLOBAL(power7_powersave_common)
+ /* Use r3 to pass state nap/sleep/winkle */
/* NAP is a state loss, we create a regs frame on the
* stack, fill it up with the state we care about and
* stick a pointer to it in PACAR1. We really only
@@ -79,8 +90,8 @@ _GLOBAL(power7_nap)
/* Continue saving state */
SAVE_GPR(2, r1)
SAVE_NVGPRS(r1)
- mfcr r3
- std r3,_CCR(r1)
+ mfcr r4
+ std r4,_CCR(r1)
std r9,_MSR(r1)
std r1,PACAR1(r13)
@@ -90,15 +101,56 @@ _GLOBAL(power7_enter_nap_mode)
li r4,KVM_HWTHREAD_IN_NAP
stb r4,HSTATE_HWTHREAD_STATE(r13)
#endif
+ cmpwi cr0,r3,1
+ beq 2f
+ IDLE_STATE_ENTER_SEQ(PPC_NAP)
+ /* No return */
+2: IDLE_STATE_ENTER_SEQ(PPC_SLEEP)
+ /* No return */
- /* Magic NAP mode enter sequence */
- std r0,0(r1)
- ptesync
- ld r0,0(r1)
-1: cmp cr0,r0,r0
- bne 1b
- PPC_NAP
- b .
+_GLOBAL(power7_idle)
+ /* Now check if user or arch enabled NAP mode */
+ LOAD_REG_ADDRBASE(r3,powersave_nap)
+ lwz r4,ADDROFF(powersave_nap)(r3)
+ cmpwi 0,r4,0
+ beqlr
+ /* fall through */
+
+_GLOBAL(power7_nap)
+ li r3,0
+ b power7_powersave_common
+ /* No return */
+
+_GLOBAL(power7_sleep)
+ li r3,1
+ b power7_powersave_common
+ /* No return */
+
+_GLOBAL(power7_wakeup_tb_loss)
+ ld r2,PACATOC(r13);
+ ld r1,PACAR1(r13)
+
+ /* Time base re-sync */
+ li r0,OPAL_RESYNC_TIMEBASE
+ LOAD_REG_ADDR(r11,opal);
+ ld r12,8(r11);
+ ld r2,0(r11);
+ mtctr r12
+ bctrl
+
+ /* TODO: Check r3 for failure */
+
+ REST_NVGPRS(r1)
+ REST_GPR(2, r1)
+ ld r3,_CCR(r1)
+ ld r4,_MSR(r1)
+ ld r5,_NIP(r1)
+ addi r1,r1,INT_FRAME_SIZE
+ mtcr r3
+ mfspr r3,SPRN_SRR1 /* Return SRR1 */
+ mtspr SPRN_SRR1,r4
+ mtspr SPRN_SRR0,r5
+ rfid
_GLOBAL(power7_wakeup_loss)
ld r1,PACAR1(r13)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 1d0848bba049..ca1cd7459c4a 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -465,7 +465,6 @@ static inline void check_stack_overflow(void)
void __do_irq(struct pt_regs *regs)
{
- struct irq_desc *desc;
unsigned int irq;
irq_enter();
@@ -487,11 +486,8 @@ void __do_irq(struct pt_regs *regs)
/* And finally process it */
if (unlikely(irq == NO_IRQ))
__get_cpu_var(irq_stat).spurious_irqs++;
- else {
- desc = irq_to_desc(irq);
- if (likely(desc))
- desc->handle_irq(irq, desc);
- }
+ else
+ generic_handle_irq(irq);
trace_irq_exit(regs);
diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c
index cadef7e64e42..a7fd4cb78b78 100644
--- a/arch/powerpc/kernel/mce.c
+++ b/arch/powerpc/kernel/mce.c
@@ -70,7 +70,7 @@ static void mce_set_error_info(struct machine_check_event *mce,
*/
void save_mce_event(struct pt_regs *regs, long handled,
struct mce_error_info *mce_err,
- uint64_t addr)
+ uint64_t nip, uint64_t addr)
{
uint64_t srr1;
int index = __get_cpu_var(mce_nest_count)++;
@@ -86,7 +86,7 @@ void save_mce_event(struct pt_regs *regs, long handled,
/* Populate generic machine check info */
mce->version = MCE_V1;
- mce->srr0 = regs->nip;
+ mce->srr0 = nip;
mce->srr1 = regs->msr;
mce->gpr3 = regs->gpr[3];
mce->in_use = 1;
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c
index 27c93f41166f..aa9aff3d6ad3 100644
--- a/arch/powerpc/kernel/mce_power.c
+++ b/arch/powerpc/kernel/mce_power.c
@@ -26,6 +26,7 @@
#include <linux/ptrace.h>
#include <asm/mmu.h>
#include <asm/mce.h>
+#include <asm/machdep.h>
/* flush SLBs and reload */
static void flush_and_reload_slb(void)
@@ -197,13 +198,32 @@ static void mce_get_derror_p7(struct mce_error_info *mce_err, uint64_t dsisr)
}
}
+static long mce_handle_ue_error(struct pt_regs *regs)
+{
+ long handled = 0;
+
+ /*
+ * On specific SCOM read via MMIO we may get a machine check
+ * exception with SRR0 pointing inside opal. If that is the
+ * case OPAL may have recovery address to re-read SCOM data in
+ * different way and hence we can recover from this MC.
+ */
+
+ if (ppc_md.mce_check_early_recovery) {
+ if (ppc_md.mce_check_early_recovery(regs))
+ handled = 1;
+ }
+ return handled;
+}
+
long __machine_check_early_realmode_p7(struct pt_regs *regs)
{
- uint64_t srr1, addr;
+ uint64_t srr1, nip, addr;
long handled = 1;
struct mce_error_info mce_error_info = { 0 };
srr1 = regs->msr;
+ nip = regs->nip;
/*
* Handle memory errors depending whether this was a load/store or
@@ -221,7 +241,11 @@ long __machine_check_early_realmode_p7(struct pt_regs *regs)
addr = regs->nip;
}
- save_mce_event(regs, handled, &mce_error_info, addr);
+ /* Handle UE error. */
+ if (mce_error_info.error_type == MCE_ERROR_TYPE_UE)
+ handled = mce_handle_ue_error(regs);
+
+ save_mce_event(regs, handled, &mce_error_info, nip, addr);
return handled;
}
@@ -263,11 +287,12 @@ static long mce_handle_derror_p8(uint64_t dsisr)
long __machine_check_early_realmode_p8(struct pt_regs *regs)
{
- uint64_t srr1, addr;
+ uint64_t srr1, nip, addr;
long handled = 1;
struct mce_error_info mce_error_info = { 0 };
srr1 = regs->msr;
+ nip = regs->nip;
if (P7_SRR1_MC_LOADSTORE(srr1)) {
handled = mce_handle_derror_p8(regs->dsisr);
@@ -279,6 +304,10 @@ long __machine_check_early_realmode_p8(struct pt_regs *regs)
addr = regs->nip;
}
- save_mce_event(regs, handled, &mce_error_info, addr);
+ /* Handle UE error. */
+ if (mce_error_info.error_type == MCE_ERROR_TYPE_UE)
+ handled = mce_handle_ue_error(regs);
+
+ save_mce_event(regs, handled, &mce_error_info, nip, addr);
return handled;
}
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 879f09620f83..7c6bb4b17b49 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -57,11 +57,14 @@ _GLOBAL(call_do_softirq)
mtlr r0
blr
+/*
+ * void call_do_irq(struct pt_regs *regs, struct thread_info *irqtp);
+ */
_GLOBAL(call_do_irq)
mflr r0
stw r0,4(r1)
lwz r10,THREAD+KSP_LIMIT(r2)
- addi r11,r3,THREAD_INFO_GAP
+ addi r11,r4,THREAD_INFO_GAP
stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4)
mr r1,r4
stw r10,8(r1)
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index a9e311f7a9dd..2a4779091a58 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -208,7 +208,6 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
unsigned long in_devfn)
{
struct pci_controller* hose;
- struct list_head *ln;
struct pci_bus *bus = NULL;
struct device_node *hose_node;
@@ -230,8 +229,7 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
* used on pre-domains setup. We return the first match
*/
- for (ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) {
- bus = pci_bus_b(ln);
+ list_for_each_entry(bus, &pci_root_buses, node) {
if (in_bus >= bus->number && in_bus <= bus->busn_res.end)
break;
bus = NULL;
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 8d4c247f1738..af064d28b365 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1048,6 +1048,15 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
flush_altivec_to_thread(src);
flush_vsx_to_thread(src);
flush_spe_to_thread(src);
+ /*
+ * Flush TM state out so we can copy it. __switch_to_tm() does this
+ * flush but it removes the checkpointed state from the current CPU and
+ * 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.
+ */
+ __switch_to_tm(src);
+ tm_recheckpoint_new_task(src);
*dst = *src;
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index f58c0d3aaeb4..dd72bebd708a 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -33,6 +33,7 @@
#include <linux/irq.h>
#include <linux/memblock.h>
#include <linux/of.h>
+#include <linux/of_fdt.h>
#include <asm/prom.h>
#include <asm/rtas.h>
@@ -588,6 +589,8 @@ static void __init early_reserve_mem_dt(void)
memblock_reserve(base, size);
}
}
+
+ early_init_fdt_scan_reserved_mem();
}
static void __init early_reserve_mem(void)
@@ -752,6 +755,11 @@ void __init early_init_devtree(void *params)
spinning_secondaries = boot_cpu_count - 1;
#endif
+#ifdef CONFIG_PPC_POWERNV
+ /* Scan and build the list of machine check recoverable ranges */
+ of_scan_flat_dt(early_init_dt_scan_recoverable_ranges, NULL);
+#endif
+
DBG(" <- early_init_devtree()\n");
}
diff --git a/arch/powerpc/kernel/reloc_64.S b/arch/powerpc/kernel/reloc_64.S
index 1482327cfeba..d88736fbece6 100644
--- a/arch/powerpc/kernel/reloc_64.S
+++ b/arch/powerpc/kernel/reloc_64.S
@@ -81,6 +81,7 @@ _GLOBAL(relocate)
6: blr
+.balign 8
p_dyn: .llong __dynamic_start - 0b
p_rela: .llong __rela_dyn_start - 0b
p_st: .llong _stext - 0b
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 4cf674d7d5ae..f386296ff378 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -1013,12 +1013,13 @@ struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
return NULL;
}
+/* We assume to be passed big endian arguments */
asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
{
struct rtas_args args;
unsigned long flags;
char *buff_copy, *errbuf = NULL;
- int nargs;
+ int nargs, nret, token;
int rc;
if (!capable(CAP_SYS_ADMIN))
@@ -1027,10 +1028,13 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0)
return -EFAULT;
- nargs = args.nargs;
+ nargs = be32_to_cpu(args.nargs);
+ nret = be32_to_cpu(args.nret);
+ token = be32_to_cpu(args.token);
+
if (nargs > ARRAY_SIZE(args.args)
- || args.nret > ARRAY_SIZE(args.args)
- || nargs + args.nret > ARRAY_SIZE(args.args))
+ || nret > ARRAY_SIZE(args.args)
+ || nargs + nret > ARRAY_SIZE(args.args))
return -EINVAL;
/* Copy in args. */
@@ -1038,14 +1042,14 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
nargs * sizeof(rtas_arg_t)) != 0)
return -EFAULT;
- if (args.token == RTAS_UNKNOWN_SERVICE)
+ if (token == RTAS_UNKNOWN_SERVICE)
return -EINVAL;
args.rets = &args.args[nargs];
- memset(args.rets, 0, args.nret * sizeof(rtas_arg_t));
+ memset(args.rets, 0, nret * sizeof(rtas_arg_t));
/* Need to handle ibm,suspend_me call specially */
- if (args.token == ibm_suspend_me_token) {
+ if (token == ibm_suspend_me_token) {
rc = rtas_ibm_suspend_me(&args);
if (rc)
return rc;
@@ -1062,7 +1066,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
/* A -1 return code indicates that the last command couldn't
be completed due to a hardware error. */
- if (args.rets[0] == -1)
+ if (be32_to_cpu(args.rets[0]) == -1)
errbuf = __fetch_rtas_last_error(buff_copy);
unlock_rtas(flags);
@@ -1077,7 +1081,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
/* Copy out args. */
if (copy_to_user(uargs->args + nargs,
args.args + nargs,
- args.nret * sizeof(rtas_arg_t)) != 0)
+ nret * sizeof(rtas_arg_t)) != 0)
return -EFAULT;
return 0;
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index f5f11a7d30e5..4933909cc5c0 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -102,6 +102,8 @@ static void setup_tlb_core_data(void)
{
int cpu;
+ BUILD_BUG_ON(offsetof(struct tlb_core_data, lock) != 0);
+
for_each_possible_cpu(cpu) {
int first = cpu_first_thread_sibling(cpu);
@@ -552,14 +554,20 @@ static void __init irqstack_early_init(void)
static void __init exc_lvl_early_init(void)
{
unsigned int i;
+ unsigned long sp;
for_each_possible_cpu(i) {
- critirq_ctx[i] = (struct thread_info *)
- __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
- dbgirq_ctx[i] = (struct thread_info *)
- __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
- mcheckirq_ctx[i] = (struct thread_info *)
- __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
+ sp = memblock_alloc(THREAD_SIZE, THREAD_SIZE);
+ critirq_ctx[i] = (struct thread_info *)__va(sp);
+ paca[i].crit_kstack = __va(sp + THREAD_SIZE);
+
+ sp = memblock_alloc(THREAD_SIZE, THREAD_SIZE);
+ dbgirq_ctx[i] = (struct thread_info *)__va(sp);
+ paca[i].dbg_kstack = __va(sp + THREAD_SIZE);
+
+ sp = memblock_alloc(THREAD_SIZE, THREAD_SIZE);
+ mcheckirq_ctx[i] = (struct thread_info *)__va(sp);
+ paca[i].mc_kstack = __va(sp + THREAD_SIZE);
}
if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC))
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index e35bf773df7a..8d253c29649b 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -65,8 +65,8 @@ struct rt_sigframe {
struct siginfo __user *pinfo;
void __user *puc;
struct siginfo info;
- /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
- char abigap[288];
+ /* New 64 bit little-endian ABI allows redzone of 512 bytes below sp */
+ char abigap[USER_REDZONE_SIZE];
} __attribute__ ((aligned (16)));
static const char fmt32[] = KERN_INFO \
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index ac2621af3154..e2a4232c5871 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -35,6 +35,7 @@
#include <asm/ptrace.h>
#include <linux/atomic.h>
#include <asm/irq.h>
+#include <asm/hw_irq.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
@@ -145,9 +146,9 @@ static irqreturn_t reschedule_action(int irq, void *data)
return IRQ_HANDLED;
}
-static irqreturn_t call_function_single_action(int irq, void *data)
+static irqreturn_t tick_broadcast_ipi_action(int irq, void *data)
{
- generic_smp_call_function_single_interrupt();
+ tick_broadcast_ipi_handler();
return IRQ_HANDLED;
}
@@ -168,14 +169,14 @@ static irqreturn_t debug_ipi_action(int irq, void *data)
static irq_handler_t smp_ipi_action[] = {
[PPC_MSG_CALL_FUNCTION] = call_function_action,
[PPC_MSG_RESCHEDULE] = reschedule_action,
- [PPC_MSG_CALL_FUNC_SINGLE] = call_function_single_action,
+ [PPC_MSG_TICK_BROADCAST] = tick_broadcast_ipi_action,
[PPC_MSG_DEBUGGER_BREAK] = debug_ipi_action,
};
const char *smp_ipi_name[] = {
[PPC_MSG_CALL_FUNCTION] = "ipi call function",
[PPC_MSG_RESCHEDULE] = "ipi reschedule",
- [PPC_MSG_CALL_FUNC_SINGLE] = "ipi call function single",
+ [PPC_MSG_TICK_BROADCAST] = "ipi tick-broadcast",
[PPC_MSG_DEBUGGER_BREAK] = "ipi debugger",
};
@@ -251,8 +252,8 @@ irqreturn_t smp_ipi_demux(void)
generic_smp_call_function_interrupt();
if (all & IPI_MESSAGE(PPC_MSG_RESCHEDULE))
scheduler_ipi();
- if (all & IPI_MESSAGE(PPC_MSG_CALL_FUNC_SINGLE))
- generic_smp_call_function_single_interrupt();
+ if (all & IPI_MESSAGE(PPC_MSG_TICK_BROADCAST))
+ tick_broadcast_ipi_handler();
if (all & IPI_MESSAGE(PPC_MSG_DEBUGGER_BREAK))
debug_ipi_action(0, NULL);
} while (info->messages);
@@ -280,7 +281,7 @@ EXPORT_SYMBOL_GPL(smp_send_reschedule);
void arch_send_call_function_single_ipi(int cpu)
{
- do_message_pass(cpu, PPC_MSG_CALL_FUNC_SINGLE);
+ do_message_pass(cpu, PPC_MSG_CALL_FUNCTION);
}
void arch_send_call_function_ipi_mask(const struct cpumask *mask)
@@ -291,6 +292,16 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
do_message_pass(cpu, PPC_MSG_CALL_FUNCTION);
}
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+void tick_broadcast(const struct cpumask *mask)
+{
+ unsigned int cpu;
+
+ for_each_cpu(cpu, mask)
+ do_message_pass(cpu, PPC_MSG_TICK_BROADCAST);
+}
+#endif
+
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
void smp_send_debugger_break(void)
{
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index b3dab20acf34..122a580f7322 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -42,6 +42,7 @@
#include <linux/timex.h>
#include <linux/kernel_stat.h>
#include <linux/time.h>
+#include <linux/clockchips.h>
#include <linux/init.h>
#include <linux/profile.h>
#include <linux/cpu.h>
@@ -106,7 +107,7 @@ struct clock_event_device decrementer_clockevent = {
.irq = 0,
.set_next_event = decrementer_set_next_event,
.set_mode = decrementer_set_mode,
- .features = CLOCK_EVT_FEAT_ONESHOT,
+ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP,
};
EXPORT_SYMBOL(decrementer_clockevent);
@@ -478,6 +479,47 @@ void arch_irq_work_raise(void)
#endif /* CONFIG_IRQ_WORK */
+void __timer_interrupt(void)
+{
+ struct pt_regs *regs = get_irq_regs();
+ u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
+ struct clock_event_device *evt = &__get_cpu_var(decrementers);
+ u64 now;
+
+ trace_timer_interrupt_entry(regs);
+
+ if (test_irq_work_pending()) {
+ clear_irq_work_pending();
+ irq_work_run();
+ }
+
+ now = get_tb_or_rtc();
+ if (now >= *next_tb) {
+ *next_tb = ~(u64)0;
+ if (evt->event_handler)
+ evt->event_handler(evt);
+ __get_cpu_var(irq_stat).timer_irqs_event++;
+ } else {
+ now = *next_tb - now;
+ if (now <= DECREMENTER_MAX)
+ set_dec((int)now);
+ /* We may have raced with new irq work */
+ if (test_irq_work_pending())
+ set_dec(1);
+ __get_cpu_var(irq_stat).timer_irqs_others++;
+ }
+
+#ifdef CONFIG_PPC64
+ /* collect purr register values often, for accurate calculations */
+ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+ struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
+ cu->current_tb = mfspr(SPRN_PURR);
+ }
+#endif
+
+ trace_timer_interrupt_exit(regs);
+}
+
/*
* timer_interrupt - gets called when the decrementer overflows,
* with interrupts disabled.
@@ -486,8 +528,6 @@ void timer_interrupt(struct pt_regs * regs)
{
struct pt_regs *old_regs;
u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
- struct clock_event_device *evt = &__get_cpu_var(decrementers);
- u64 now;
/* Ensure a positive value is written to the decrementer, or else
* some CPUs will continue to take decrementer exceptions.
@@ -519,39 +559,7 @@ void timer_interrupt(struct pt_regs * regs)
old_regs = set_irq_regs(regs);
irq_enter();
- trace_timer_interrupt_entry(regs);
-
- if (test_irq_work_pending()) {
- clear_irq_work_pending();
- irq_work_run();
- }
-
- now = get_tb_or_rtc();
- if (now >= *next_tb) {
- *next_tb = ~(u64)0;
- if (evt->event_handler)
- evt->event_handler(evt);
- __get_cpu_var(irq_stat).timer_irqs_event++;
- } else {
- now = *next_tb - now;
- if (now <= DECREMENTER_MAX)
- set_dec((int)now);
- /* We may have raced with new irq work */
- if (test_irq_work_pending())
- set_dec(1);
- __get_cpu_var(irq_stat).timer_irqs_others++;
- }
-
-#ifdef CONFIG_PPC64
- /* collect purr register values often, for accurate calculations */
- if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
- struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
- cu->current_tb = mfspr(SPRN_PURR);
- }
-#endif
-
- trace_timer_interrupt_exit(regs);
-
+ __timer_interrupt();
irq_exit();
set_irq_regs(old_regs);
}
@@ -825,6 +833,15 @@ static void decrementer_set_mode(enum clock_event_mode mode,
decrementer_set_next_event(DECREMENTER_MAX, dev);
}
+/* Interrupt handler for the timer broadcast IPI */
+void tick_broadcast_ipi_handler(void)
+{
+ u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
+
+ *next_tb = get_tb_or_rtc();
+ __timer_interrupt();
+}
+
static void register_decrementer_clockevent(int cpu)
{
struct clock_event_device *dec = &per_cpu(decrementers, cpu);
@@ -928,6 +945,7 @@ void __init time_init(void)
clocksource_init();
init_decrementer_clockevent();
+ tick_setup_hrtimer_broadcast();
}
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 33cd7a0b8e73..df86f0ce2d36 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1379,8 +1379,9 @@ void facility_unavailable_exception(struct pt_regs *regs)
if (!arch_irq_disabled_regs(regs))
local_irq_enable();
- pr_err("%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n",
- hv ? "Hypervisor " : "", facility, regs->nip, regs->msr);
+ pr_err_ratelimited(
+ "%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n",
+ hv ? "Hypervisor " : "", facility, regs->nip, regs->msr);
if (user_mode(regs)) {
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 094e45c16a17..ce74c335a6a4 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -715,8 +715,8 @@ int vdso_getcpu_init(void)
unsigned long cpu, node, val;
/*
- * SPRG3 contains the CPU in the bottom 16 bits and the NUMA node in
- * the next 16 bits. The VDSO uses this to implement getcpu().
+ * SPRG_VDSO contains the CPU in the bottom 16 bits and the NUMA node
+ * in the next 16 bits. The VDSO uses this to implement getcpu().
*/
cpu = get_cpu();
WARN_ON_ONCE(cpu > 0xffff);
@@ -725,8 +725,8 @@ int vdso_getcpu_init(void)
WARN_ON_ONCE(node > 0xffff);
val = (cpu & 0xfff) | ((node & 0xffff) << 16);
- mtspr(SPRN_SPRG3, val);
- get_paca()->sprg3 = val;
+ mtspr(SPRN_SPRG_VDSO_WRITE, val);
+ get_paca()->sprg_vdso = val;
put_cpu();
diff --git a/arch/powerpc/kernel/vdso32/getcpu.S b/arch/powerpc/kernel/vdso32/getcpu.S
index 47afd08c90f7..23eb9a9441bd 100644
--- a/arch/powerpc/kernel/vdso32/getcpu.S
+++ b/arch/powerpc/kernel/vdso32/getcpu.S
@@ -29,7 +29,7 @@
*/
V_FUNCTION_BEGIN(__kernel_getcpu)
.cfi_startproc
- mfspr r5,SPRN_USPRG3
+ mfspr r5,SPRN_SPRG_VDSO_READ
cmpdi cr0,r3,0
cmpdi cr1,r4,0
clrlwi r6,r5,16
diff --git a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
index 79683d0393f5..6ac107ac402a 100644
--- a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
+++ b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
@@ -6,7 +6,7 @@
.globl vdso32_start, vdso32_end
.balign PAGE_SIZE
vdso32_start:
- .incbin "arch/powerpc/kernel/vdso32/vdso32.so"
+ .incbin "arch/powerpc/kernel/vdso32/vdso32.so.dbg"
.balign PAGE_SIZE
vdso32_end:
diff --git a/arch/powerpc/kernel/vdso64/getcpu.S b/arch/powerpc/kernel/vdso64/getcpu.S
index 47afd08c90f7..23eb9a9441bd 100644
--- a/arch/powerpc/kernel/vdso64/getcpu.S
+++ b/arch/powerpc/kernel/vdso64/getcpu.S
@@ -29,7 +29,7 @@
*/
V_FUNCTION_BEGIN(__kernel_getcpu)
.cfi_startproc
- mfspr r5,SPRN_USPRG3
+ mfspr r5,SPRN_SPRG_VDSO_READ
cmpdi cr0,r3,0
cmpdi cr1,r4,0
clrlwi r6,r5,16
diff --git a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
index 8df9e2463007..df60fca6a13d 100644
--- a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
+++ b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
@@ -6,7 +6,7 @@
.globl vdso64_start, vdso64_end
.balign PAGE_SIZE
vdso64_start:
- .incbin "arch/powerpc/kernel/vdso64/vdso64.so"
+ .incbin "arch/powerpc/kernel/vdso64/vdso64.so.dbg"
.balign PAGE_SIZE
vdso64_end:
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 826d8bd9e522..904c66128fae 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -1432,7 +1432,8 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node)
/* needed to ensure proper operation of coherent allocations
* later, in case driver doesn't set it explicitly */
- dma_coerce_mask_and_coherent(&viodev->dev, DMA_BIT_MASK(64));
+ viodev->dev.coherent_dma_mask = DMA_BIT_MASK(64);
+ viodev->dev.dma_mask = &viodev->dev.coherent_dma_mask;
}
/* register with generic device framework */
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 303ece75b8e4..fb25ebc0af0c 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -262,7 +262,14 @@ int kvmppc_mmu_hv_init(void)
static void kvmppc_mmu_book3s_64_hv_reset_msr(struct kvm_vcpu *vcpu)
{
- kvmppc_set_msr(vcpu, vcpu->arch.intr_msr);
+ unsigned long msr = vcpu->arch.intr_msr;
+
+ /* If transactional, change to suspend mode on IRQ delivery */
+ if (MSR_TM_TRANSACTIONAL(vcpu->arch.shregs.msr))
+ msr |= MSR_TS_S;
+ else
+ msr |= vcpu->arch.shregs.msr & MSR_TS_MASK;
+ kvmppc_set_msr(vcpu, msr);
}
/*
diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c
index 2c25f5412bdb..89e96b3e0039 100644
--- a/arch/powerpc/kvm/book3s_64_vio_hv.c
+++ b/arch/powerpc/kvm/book3s_64_vio_hv.c
@@ -75,3 +75,31 @@ long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
return H_TOO_HARD;
}
EXPORT_SYMBOL_GPL(kvmppc_h_put_tce);
+
+long kvmppc_h_get_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
+ unsigned long ioba)
+{
+ struct kvm *kvm = vcpu->kvm;
+ struct kvmppc_spapr_tce_table *stt;
+
+ list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) {
+ if (stt->liobn == liobn) {
+ unsigned long idx = ioba >> SPAPR_TCE_SHIFT;
+ struct page *page;
+ u64 *tbl;
+
+ if (ioba >= stt->window_size)
+ return H_PARAMETER;
+
+ page = stt->pages[idx / TCES_PER_PAGE];
+ tbl = (u64 *)page_address(page);
+
+ vcpu->arch.gpr[4] = tbl[idx % TCES_PER_PAGE];
+ return H_SUCCESS;
+ }
+ }
+
+ /* Didn't find the liobn, punt it to userspace */
+ return H_TOO_HARD;
+}
+EXPORT_SYMBOL_GPL(kvmppc_h_get_tce);
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 17fc9496b6ac..8227dba5af0f 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -86,7 +86,7 @@ static void kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu)
/* CPU points to the first thread of the core */
if (cpu != me && cpu >= 0 && cpu < nr_cpu_ids) {
-#ifdef CONFIG_KVM_XICS
+#ifdef CONFIG_PPC_ICP_NATIVE
int real_cpu = cpu + vcpu->arch.ptid;
if (paca[real_cpu].kvm_hstate.xics_phys)
xics_wake_cpu(real_cpu);
@@ -879,17 +879,6 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
case KVM_REG_PPC_IAMR:
*val = get_reg_val(id, vcpu->arch.iamr);
break;
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- case KVM_REG_PPC_TFHAR:
- *val = get_reg_val(id, vcpu->arch.tfhar);
- break;
- case KVM_REG_PPC_TFIAR:
- *val = get_reg_val(id, vcpu->arch.tfiar);
- break;
- case KVM_REG_PPC_TEXASR:
- *val = get_reg_val(id, vcpu->arch.texasr);
- break;
-#endif
case KVM_REG_PPC_FSCR:
*val = get_reg_val(id, vcpu->arch.fscr);
break;
@@ -970,6 +959,69 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
case KVM_REG_PPC_PPR:
*val = get_reg_val(id, vcpu->arch.ppr);
break;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ case KVM_REG_PPC_TFHAR:
+ *val = get_reg_val(id, vcpu->arch.tfhar);
+ break;
+ case KVM_REG_PPC_TFIAR:
+ *val = get_reg_val(id, vcpu->arch.tfiar);
+ break;
+ case KVM_REG_PPC_TEXASR:
+ *val = get_reg_val(id, vcpu->arch.texasr);
+ break;
+ case KVM_REG_PPC_TM_GPR0 ... KVM_REG_PPC_TM_GPR31:
+ i = id - KVM_REG_PPC_TM_GPR0;
+ *val = get_reg_val(id, vcpu->arch.gpr_tm[i]);
+ break;
+ case KVM_REG_PPC_TM_VSR0 ... KVM_REG_PPC_TM_VSR63:
+ {
+ int j;
+ i = id - KVM_REG_PPC_TM_VSR0;
+ if (i < 32)
+ for (j = 0; j < TS_FPRWIDTH; j++)
+ val->vsxval[j] = vcpu->arch.fp_tm.fpr[i][j];
+ else {
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ val->vval = vcpu->arch.vr_tm.vr[i-32];
+ else
+ r = -ENXIO;
+ }
+ break;
+ }
+ case KVM_REG_PPC_TM_CR:
+ *val = get_reg_val(id, vcpu->arch.cr_tm);
+ break;
+ case KVM_REG_PPC_TM_LR:
+ *val = get_reg_val(id, vcpu->arch.lr_tm);
+ break;
+ case KVM_REG_PPC_TM_CTR:
+ *val = get_reg_val(id, vcpu->arch.ctr_tm);
+ break;
+ case KVM_REG_PPC_TM_FPSCR:
+ *val = get_reg_val(id, vcpu->arch.fp_tm.fpscr);
+ break;
+ case KVM_REG_PPC_TM_AMR:
+ *val = get_reg_val(id, vcpu->arch.amr_tm);
+ break;
+ case KVM_REG_PPC_TM_PPR:
+ *val = get_reg_val(id, vcpu->arch.ppr_tm);
+ break;
+ case KVM_REG_PPC_TM_VRSAVE:
+ *val = get_reg_val(id, vcpu->arch.vrsave_tm);
+ break;
+ case KVM_REG_PPC_TM_VSCR:
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ *val = get_reg_val(id, vcpu->arch.vr_tm.vscr.u[3]);
+ else
+ r = -ENXIO;
+ break;
+ case KVM_REG_PPC_TM_DSCR:
+ *val = get_reg_val(id, vcpu->arch.dscr_tm);
+ break;
+ case KVM_REG_PPC_TM_TAR:
+ *val = get_reg_val(id, vcpu->arch.tar_tm);
+ break;
+#endif
case KVM_REG_PPC_ARCH_COMPAT:
*val = get_reg_val(id, vcpu->arch.vcore->arch_compat);
break;
@@ -1039,17 +1091,6 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
case KVM_REG_PPC_IAMR:
vcpu->arch.iamr = set_reg_val(id, *val);
break;
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- case KVM_REG_PPC_TFHAR:
- vcpu->arch.tfhar = set_reg_val(id, *val);
- break;
- case KVM_REG_PPC_TFIAR:
- vcpu->arch.tfiar = set_reg_val(id, *val);
- break;
- case KVM_REG_PPC_TEXASR:
- vcpu->arch.texasr = set_reg_val(id, *val);
- break;
-#endif
case KVM_REG_PPC_FSCR:
vcpu->arch.fscr = set_reg_val(id, *val);
break;
@@ -1144,6 +1185,68 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
case KVM_REG_PPC_PPR:
vcpu->arch.ppr = set_reg_val(id, *val);
break;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ case KVM_REG_PPC_TFHAR:
+ vcpu->arch.tfhar = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TFIAR:
+ vcpu->arch.tfiar = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TEXASR:
+ vcpu->arch.texasr = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_GPR0 ... KVM_REG_PPC_TM_GPR31:
+ i = id - KVM_REG_PPC_TM_GPR0;
+ vcpu->arch.gpr_tm[i] = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_VSR0 ... KVM_REG_PPC_TM_VSR63:
+ {
+ int j;
+ i = id - KVM_REG_PPC_TM_VSR0;
+ if (i < 32)
+ for (j = 0; j < TS_FPRWIDTH; j++)
+ vcpu->arch.fp_tm.fpr[i][j] = val->vsxval[j];
+ else
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ vcpu->arch.vr_tm.vr[i-32] = val->vval;
+ else
+ r = -ENXIO;
+ break;
+ }
+ case KVM_REG_PPC_TM_CR:
+ vcpu->arch.cr_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_LR:
+ vcpu->arch.lr_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_CTR:
+ vcpu->arch.ctr_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_FPSCR:
+ vcpu->arch.fp_tm.fpscr = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_AMR:
+ vcpu->arch.amr_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_PPR:
+ vcpu->arch.ppr_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_VRSAVE:
+ vcpu->arch.vrsave_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_VSCR:
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ vcpu->arch.vr.vscr.u[3] = set_reg_val(id, *val);
+ else
+ r = - ENXIO;
+ break;
+ case KVM_REG_PPC_TM_DSCR:
+ vcpu->arch.dscr_tm = set_reg_val(id, *val);
+ break;
+ case KVM_REG_PPC_TM_TAR:
+ vcpu->arch.tar_tm = set_reg_val(id, *val);
+ break;
+#endif
case KVM_REG_PPC_ARCH_COMPAT:
r = kvmppc_set_arch_compat(vcpu, set_reg_val(id, *val));
break;
@@ -1360,9 +1463,7 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu)
smp_wmb();
#if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP)
if (cpu != smp_processor_id()) {
-#ifdef CONFIG_KVM_XICS
xics_wake_cpu(cpu);
-#endif
if (vcpu->arch.ptid)
++vc->n_woken;
}
@@ -1530,7 +1631,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
vcpu->arch.trap = 0;
if (vcpu->arch.ceded) {
- if (ret != RESUME_GUEST)
+ if (!is_kvmppc_resume_guest(ret))
kvmppc_end_cede(vcpu);
else
kvmppc_set_timer(vcpu);
@@ -1541,7 +1642,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
vc->vcore_state = VCORE_INACTIVE;
list_for_each_entry_safe(vcpu, vnext, &vc->runnable_threads,
arch.run_list) {
- if (vcpu->arch.ret != RESUME_GUEST) {
+ if (!is_kvmppc_resume_guest(vcpu->arch.ret)) {
kvmppc_remove_runnable(vc, vcpu);
wake_up(&vcpu->arch.cpu_run);
}
@@ -1731,7 +1832,7 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx);
}
- } while (r == RESUME_GUEST);
+ } while (is_kvmppc_resume_guest(r));
out:
vcpu->arch.state = KVMPPC_VCPU_NOTREADY;
@@ -2366,7 +2467,7 @@ static int kvmppc_book3s_init_hv(void)
*/
r = kvmppc_core_check_processor_compat_hv();
if (r < 0)
- return r;
+ return -ENODEV;
kvm_ops_hv.owner = THIS_MODULE;
kvmppc_hv_ops = &kvm_ops_hv;
diff --git a/arch/powerpc/kvm/book3s_hv_interrupts.S b/arch/powerpc/kvm/book3s_hv_interrupts.S
index e873796b1a29..e18e3cfc32de 100644
--- a/arch/powerpc/kvm/book3s_hv_interrupts.S
+++ b/arch/powerpc/kvm/book3s_hv_interrupts.S
@@ -71,6 +71,14 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
mtmsrd r10,1
/* Save host PMU registers */
+BEGIN_FTR_SECTION
+ /* Work around P8 PMAE bug */
+ li r3, -1
+ clrrdi r3, r3, 10
+ mfspr r8, SPRN_MMCR2
+ mtspr SPRN_MMCR2, r3 /* freeze all counters using MMCR2 */
+ isync
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
li r3, 1
sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */
mfspr r7, SPRN_MMCR0 /* save MMCR0 */
@@ -87,9 +95,18 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
cmpwi r5, 0
beq 31f /* skip if not */
mfspr r5, SPRN_MMCR1
+ mfspr r9, SPRN_SIAR
+ mfspr r10, SPRN_SDAR
std r7, HSTATE_MMCR(r13)
std r5, HSTATE_MMCR + 8(r13)
std r6, HSTATE_MMCR + 16(r13)
+ std r9, HSTATE_MMCR + 24(r13)
+ std r10, HSTATE_MMCR + 32(r13)
+BEGIN_FTR_SECTION
+ mfspr r9, SPRN_SIER
+ std r8, HSTATE_MMCR + 40(r13)
+ std r9, HSTATE_MMCR + 48(r13)
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
mfspr r3, SPRN_PMC1
mfspr r5, SPRN_PMC2
mfspr r6, SPRN_PMC3
@@ -110,6 +127,11 @@ BEGIN_FTR_SECTION
stw r10, HSTATE_PMC + 24(r13)
stw r11, HSTATE_PMC + 28(r13)
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
+BEGIN_FTR_SECTION
+ mfspr r9, SPRN_SIER
+ std r8, HSTATE_MMCR + 40(r13)
+ std r9, HSTATE_MMCR + 48(r13)
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
31:
/*
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index 37fb3caa4c80..1d6c56ad5b60 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -111,7 +111,7 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index,
rcbits = hpte_r & (HPTE_R_R | HPTE_R_C);
ptel = rev->guest_rpte |= rcbits;
gfn = hpte_rpn(ptel, hpte_page_size(hpte_v, ptel));
- memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
+ memslot = __gfn_to_memslot(kvm_memslots_raw(kvm), gfn);
if (!memslot)
return;
@@ -192,7 +192,7 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
/* Find the memslot (if any) for this address */
gpa = (ptel & HPTE_R_RPN) & ~(psize - 1);
gfn = gpa >> PAGE_SHIFT;
- memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
+ memslot = __gfn_to_memslot(kvm_memslots_raw(kvm), gfn);
pa = 0;
is_io = ~0ul;
rmap = NULL;
@@ -670,7 +670,7 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
psize = hpte_page_size(v, r);
gfn = ((r & HPTE_R_RPN) & ~(psize - 1)) >> PAGE_SHIFT;
- memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
+ memslot = __gfn_to_memslot(kvm_memslots_raw(kvm), gfn);
if (memslot) {
hva = __gfn_to_hva_memslot(memslot, gfn);
pte = lookup_linux_pte_and_update(pgdir, hva,
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index e66d4ec04d95..ffbb871c2bd8 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -28,6 +28,9 @@
#include <asm/exception-64s.h>
#include <asm/kvm_book3s_asm.h>
#include <asm/mmu-hash64.h>
+#include <asm/tm.h>
+
+#define VCPU_GPRS_TM(reg) (((reg) * ULONG_SIZE) + VCPU_GPR_TM)
#ifdef __LITTLE_ENDIAN__
#error Need to fix lppaca and SLB shadow accesses in little endian mode
@@ -75,8 +78,8 @@ BEGIN_FTR_SECTION
END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
/* Restore SPRG3 */
- ld r3,PACA_SPRG3(r13)
- mtspr SPRN_SPRG3,r3
+ ld r3,PACA_SPRG_VDSO(r13)
+ mtspr SPRN_SPRG_VDSO_WRITE,r3
/* Reload the host's PMU registers */
ld r3, PACALPPACAPTR(r13) /* is the host using the PMU? */
@@ -106,8 +109,18 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
ld r3, HSTATE_MMCR(r13)
ld r4, HSTATE_MMCR + 8(r13)
ld r5, HSTATE_MMCR + 16(r13)
+ ld r6, HSTATE_MMCR + 24(r13)
+ ld r7, HSTATE_MMCR + 32(r13)
mtspr SPRN_MMCR1, r4
mtspr SPRN_MMCRA, r5
+ mtspr SPRN_SIAR, r6
+ mtspr SPRN_SDAR, r7
+BEGIN_FTR_SECTION
+ ld r8, HSTATE_MMCR + 40(r13)
+ ld r9, HSTATE_MMCR + 48(r13)
+ mtspr SPRN_MMCR2, r8
+ mtspr SPRN_SIER, r9
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
mtspr SPRN_MMCR0, r3
isync
23:
@@ -597,6 +610,116 @@ BEGIN_FTR_SECTION
END_FTR_SECTION_NESTED(CPU_FTR_ARCH_206, CPU_FTR_ARCH_206, 89)
END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+ b skip_tm
+END_FTR_SECTION_IFCLR(CPU_FTR_TM)
+
+ /* Turn on TM/FP/VSX/VMX so we can restore them. */
+ mfmsr r5
+ li r6, MSR_TM >> 32
+ sldi r6, r6, 32
+ or r5, r5, r6
+ ori r5, r5, MSR_FP
+ oris r5, r5, (MSR_VEC | MSR_VSX)@h
+ mtmsrd r5
+
+ /*
+ * The user may change these outside of a transaction, so they must
+ * always be context switched.
+ */
+ ld r5, VCPU_TFHAR(r4)
+ ld r6, VCPU_TFIAR(r4)
+ ld r7, VCPU_TEXASR(r4)
+ mtspr SPRN_TFHAR, r5
+ mtspr SPRN_TFIAR, r6
+ mtspr SPRN_TEXASR, r7
+
+ ld r5, VCPU_MSR(r4)
+ rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
+ beq skip_tm /* TM not active in guest */
+
+ /* Make sure the failure summary is set, otherwise we'll program check
+ * when we trechkpt. It's possible that this might have been not set
+ * on a kvmppc_set_one_reg() call but we shouldn't let this crash the
+ * host.
+ */
+ oris r7, r7, (TEXASR_FS)@h
+ mtspr SPRN_TEXASR, r7
+
+ /*
+ * We need to load up the checkpointed state for the guest.
+ * We need to do this early as it will blow away any GPRs, VSRs and
+ * some SPRs.
+ */
+
+ mr r31, r4
+ addi r3, r31, VCPU_FPRS_TM
+ bl .load_fp_state
+ addi r3, r31, VCPU_VRS_TM
+ bl .load_vr_state
+ mr r4, r31
+ lwz r7, VCPU_VRSAVE_TM(r4)
+ mtspr SPRN_VRSAVE, r7
+
+ ld r5, VCPU_LR_TM(r4)
+ lwz r6, VCPU_CR_TM(r4)
+ ld r7, VCPU_CTR_TM(r4)
+ ld r8, VCPU_AMR_TM(r4)
+ ld r9, VCPU_TAR_TM(r4)
+ mtlr r5
+ mtcr r6
+ mtctr r7
+ mtspr SPRN_AMR, r8
+ mtspr SPRN_TAR, r9
+
+ /*
+ * Load up PPR and DSCR values but don't put them in the actual SPRs
+ * till the last moment to avoid running with userspace PPR and DSCR for
+ * too long.
+ */
+ ld r29, VCPU_DSCR_TM(r4)
+ ld r30, VCPU_PPR_TM(r4)
+
+ std r2, PACATMSCRATCH(r13) /* Save TOC */
+
+ /* Clear the MSR RI since r1, r13 are all going to be foobar. */
+ li r5, 0
+ mtmsrd r5, 1
+
+ /* Load GPRs r0-r28 */
+ reg = 0
+ .rept 29
+ ld reg, VCPU_GPRS_TM(reg)(r31)
+ reg = reg + 1
+ .endr
+
+ mtspr SPRN_DSCR, r29
+ mtspr SPRN_PPR, r30
+
+ /* Load final GPRs */
+ ld 29, VCPU_GPRS_TM(29)(r31)
+ ld 30, VCPU_GPRS_TM(30)(r31)
+ ld 31, VCPU_GPRS_TM(31)(r31)
+
+ /* TM checkpointed state is now setup. All GPRs are now volatile. */
+ TRECHKPT
+
+ /* Now let's get back the state we need. */
+ HMT_MEDIUM
+ GET_PACA(r13)
+ ld r29, HSTATE_DSCR(r13)
+ mtspr SPRN_DSCR, r29
+ ld r4, HSTATE_KVM_VCPU(r13)
+ ld r1, HSTATE_HOST_R1(r13)
+ ld r2, PACATMSCRATCH(r13)
+
+ /* Set the MSR RI since we have our registers back. */
+ li r5, MSR_RI
+ mtmsrd r5, 1
+skip_tm:
+#endif
+
/* Load guest PMU registers */
/* R4 is live here (vcpu pointer) */
li r3, 1
@@ -704,14 +827,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
ld r6, VCPU_VTB(r4)
mtspr SPRN_IC, r5
mtspr SPRN_VTB, r6
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- ld r5, VCPU_TFHAR(r4)
- ld r6, VCPU_TFIAR(r4)
- ld r7, VCPU_TEXASR(r4)
- mtspr SPRN_TFHAR, r5
- mtspr SPRN_TFIAR, r6
- mtspr SPRN_TEXASR, r7
-#endif
ld r8, VCPU_EBBHR(r4)
mtspr SPRN_EBBHR, r8
ld r5, VCPU_EBBRR(r4)
@@ -736,6 +851,10 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
* Set the decrementer to the guest decrementer.
*/
ld r8,VCPU_DEC_EXPIRES(r4)
+ /* r8 is a host timebase value here, convert to guest TB */
+ ld r5,HSTATE_KVM_VCORE(r13)
+ ld r6,VCORE_TB_OFFSET(r5)
+ add r8,r8,r6
mftb r7
subf r3,r7,r8
mtspr SPRN_DEC,r3
@@ -817,7 +936,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
12: mtspr SPRN_SRR0, r10
mr r10,r0
mtspr SPRN_SRR1, r11
- ld r11, VCPU_INTR_MSR(r4)
+ mr r9, r4
+ bl kvmppc_msr_interrupt
5:
/*
@@ -1098,17 +1218,15 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_201)
mftb r6
extsw r5,r5
add r5,r5,r6
+ /* r5 is a guest timebase value here, convert to host TB */
+ ld r3,HSTATE_KVM_VCORE(r13)
+ ld r4,VCORE_TB_OFFSET(r3)
+ subf r5,r4,r5
std r5,VCPU_DEC_EXPIRES(r9)
BEGIN_FTR_SECTION
b 8f
END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
- /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
- mfmsr r8
- li r0, 1
- rldimi r8, r0, MSR_TM_LG, 63-MSR_TM_LG
- mtmsrd r8
-
/* Save POWER8-specific registers */
mfspr r5, SPRN_IAMR
mfspr r6, SPRN_PSPB
@@ -1122,14 +1240,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
std r5, VCPU_IC(r9)
std r6, VCPU_VTB(r9)
std r7, VCPU_TAR(r9)
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- mfspr r5, SPRN_TFHAR
- mfspr r6, SPRN_TFIAR
- mfspr r7, SPRN_TEXASR
- std r5, VCPU_TFHAR(r9)
- std r6, VCPU_TFIAR(r9)
- std r7, VCPU_TEXASR(r9)
-#endif
mfspr r8, SPRN_EBBHR
std r8, VCPU_EBBHR(r9)
mfspr r5, SPRN_EBBRR
@@ -1387,7 +1497,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
ld r8,VCORE_TB_OFFSET(r5)
cmpdi r8,0
beq 17f
- mftb r6 /* current host timebase */
+ mftb r6 /* current guest timebase */
subf r8,r8,r6
mtspr SPRN_TBU40,r8 /* update upper 40 bits */
mftb r7 /* check if lower 24 bits overflowed */
@@ -1504,73 +1614,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
1: addi r8,r8,16
.endr
- /* Save DEC */
- mfspr r5,SPRN_DEC
- mftb r6
- extsw r5,r5
- add r5,r5,r6
- std r5,VCPU_DEC_EXPIRES(r9)
-
-BEGIN_FTR_SECTION
- b 8f
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
- /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
- mfmsr r8
- li r0, 1
- rldimi r8, r0, MSR_TM_LG, 63-MSR_TM_LG
- mtmsrd r8
-
- /* Save POWER8-specific registers */
- mfspr r5, SPRN_IAMR
- mfspr r6, SPRN_PSPB
- mfspr r7, SPRN_FSCR
- std r5, VCPU_IAMR(r9)
- stw r6, VCPU_PSPB(r9)
- std r7, VCPU_FSCR(r9)
- mfspr r5, SPRN_IC
- mfspr r6, SPRN_VTB
- mfspr r7, SPRN_TAR
- std r5, VCPU_IC(r9)
- std r6, VCPU_VTB(r9)
- std r7, VCPU_TAR(r9)
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
- mfspr r5, SPRN_TFHAR
- mfspr r6, SPRN_TFIAR
- mfspr r7, SPRN_TEXASR
- std r5, VCPU_TFHAR(r9)
- std r6, VCPU_TFIAR(r9)
- std r7, VCPU_TEXASR(r9)
-#endif
- mfspr r8, SPRN_EBBHR
- std r8, VCPU_EBBHR(r9)
- mfspr r5, SPRN_EBBRR
- mfspr r6, SPRN_BESCR
- mfspr r7, SPRN_CSIGR
- mfspr r8, SPRN_TACR
- std r5, VCPU_EBBRR(r9)
- std r6, VCPU_BESCR(r9)
- std r7, VCPU_CSIGR(r9)
- std r8, VCPU_TACR(r9)
- mfspr r5, SPRN_TCSCR
- mfspr r6, SPRN_ACOP
- mfspr r7, SPRN_PID
- mfspr r8, SPRN_WORT
- std r5, VCPU_TCSCR(r9)
- std r6, VCPU_ACOP(r9)
- stw r7, VCPU_GUEST_PID(r9)
- std r8, VCPU_WORT(r9)
-8:
-
- /* Save and reset AMR and UAMOR before turning on the MMU */
-BEGIN_FTR_SECTION
- mfspr r5,SPRN_AMR
- mfspr r6,SPRN_UAMOR
- std r5,VCPU_AMR(r9)
- std r6,VCPU_UAMOR(r9)
- li r6,0
- mtspr SPRN_AMR,r6
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-
/* Unset guest mode */
li r0, KVM_GUEST_MODE_NONE
stb r0, HSTATE_IN_GUEST(r13)
@@ -1624,7 +1667,7 @@ kvmppc_hdsi:
mtspr SPRN_SRR0, r10
mtspr SPRN_SRR1, r11
li r10, BOOK3S_INTERRUPT_DATA_STORAGE
- ld r11, VCPU_INTR_MSR(r9)
+ bl kvmppc_msr_interrupt
fast_interrupt_c_return:
6: ld r7, VCPU_CTR(r9)
lwz r8, VCPU_XER(r9)
@@ -1693,7 +1736,7 @@ kvmppc_hisi:
1: mtspr SPRN_SRR0, r10
mtspr SPRN_SRR1, r11
li r10, BOOK3S_INTERRUPT_INST_STORAGE
- ld r11, VCPU_INTR_MSR(r9)
+ bl kvmppc_msr_interrupt
b fast_interrupt_c_return
3: ld r6, VCPU_KVM(r9) /* not relocated, use VRMA */
@@ -1736,7 +1779,7 @@ sc_1_fast_return:
mtspr SPRN_SRR0,r10
mtspr SPRN_SRR1,r11
li r10, BOOK3S_INTERRUPT_SYSCALL
- ld r11, VCPU_INTR_MSR(r9)
+ bl kvmppc_msr_interrupt
mr r4,r9
b fast_guest_return
@@ -1758,7 +1801,7 @@ hcall_real_table:
.long 0 /* 0x10 - H_CLEAR_MOD */
.long 0 /* 0x14 - H_CLEAR_REF */
.long .kvmppc_h_protect - hcall_real_table
- .long 0 /* 0x1c - H_GET_TCE */
+ .long .kvmppc_h_get_tce - hcall_real_table
.long .kvmppc_h_put_tce - hcall_real_table
.long 0 /* 0x24 - H_SET_SPRG0 */
.long .kvmppc_h_set_dabr - hcall_real_table
@@ -2064,7 +2107,7 @@ machine_check_realmode:
beq mc_cont
/* If not, deliver a machine check. SRR0/1 are already set */
li r10, BOOK3S_INTERRUPT_MACHINE_CHECK
- ld r11, VCPU_INTR_MSR(r9)
+ bl kvmppc_msr_interrupt
b fast_interrupt_c_return
/*
@@ -2203,10 +2246,8 @@ BEGIN_FTR_SECTION
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
#endif
mfspr r6,SPRN_VRSAVE
- stw r6,VCPU_VRSAVE(r3)
+ stw r6,VCPU_VRSAVE(r31)
mtlr r30
- mtmsrd r5
- isync
blr
/*
@@ -2240,7 +2281,7 @@ BEGIN_FTR_SECTION
bl .load_vr_state
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
#endif
- lwz r7,VCPU_VRSAVE(r4)
+ lwz r7,VCPU_VRSAVE(r31)
mtspr SPRN_VRSAVE,r7
mtlr r30
mr r4,r31
@@ -2253,3 +2294,20 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
*/
kvmppc_bad_host_intr:
b .
+
+/*
+ * This mimics the MSR transition on IRQ delivery. The new guest MSR is taken
+ * from VCPU_INTR_MSR and is modified based on the required TM state changes.
+ * r11 has the guest MSR value (in/out)
+ * r9 has a vcpu pointer (in)
+ * r0 is used as a scratch register
+ */
+kvmppc_msr_interrupt:
+ rldicl r0, r11, 64 - MSR_TS_S_LG, 62
+ cmpwi r0, 2 /* Check if we are in transactional state.. */
+ ld r11, VCPU_INTR_MSR(r9)
+ bne 1f
+ /* ... if transactional, change to suspended */
+ li r0, 1
+1: rldimi r11, r0, MSR_TS_S_LG, 63 - MSR_TS_T_LG
+ blr
diff --git a/arch/powerpc/kvm/book3s_interrupts.S b/arch/powerpc/kvm/book3s_interrupts.S
index f779450cb07c..3533c999194a 100644
--- a/arch/powerpc/kvm/book3s_interrupts.S
+++ b/arch/powerpc/kvm/book3s_interrupts.S
@@ -153,8 +153,8 @@ kvm_start_lightweight:
* Reload kernel SPRG3 value.
* No need to save guest value as usermode can't modify SPRG3.
*/
- ld r3, PACA_SPRG3(r13)
- mtspr SPRN_SPRG3, r3
+ ld r3, PACA_SPRG_VDSO(r13)
+ mtspr SPRN_SPRG_VDSO_WRITE, r3
#endif /* CONFIG_PPC_BOOK3S_64 */
/* R7 = vcpu */
diff --git a/arch/powerpc/kvm/book3s_rtas.c b/arch/powerpc/kvm/book3s_rtas.c
index cf95cdef73c9..7a053157483b 100644
--- a/arch/powerpc/kvm/book3s_rtas.c
+++ b/arch/powerpc/kvm/book3s_rtas.c
@@ -213,8 +213,11 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
gpa_t args_phys;
int rc;
- /* r4 contains the guest physical address of the RTAS args */
- args_phys = kvmppc_get_gpr(vcpu, 4);
+ /*
+ * r4 contains the guest physical address of the RTAS args
+ * Mask off the top 4 bits since this is a guest real address
+ */
+ args_phys = kvmppc_get_gpr(vcpu, 4) & KVM_PAM;
rc = kvm_read_guest(vcpu->kvm, args_phys, &args, sizeof(args));
if (rc)
diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S
index e4185f6b3309..a1712b818a5f 100644
--- a/arch/powerpc/kvm/bookehv_interrupts.S
+++ b/arch/powerpc/kvm/bookehv_interrupts.S
@@ -229,17 +229,20 @@
stw r10, VCPU_CR(r4)
PPC_STL r11, VCPU_GPR(R4)(r4)
PPC_STL r5, VCPU_GPR(R5)(r4)
- .if \type == EX_CRIT
- PPC_LL r5, (\paca_ex + EX_R13)(r13)
- .else
- mfspr r5, \scratch
- .endif
PPC_STL r6, VCPU_GPR(R6)(r4)
PPC_STL r8, VCPU_GPR(R8)(r4)
PPC_STL r9, VCPU_GPR(R9)(r4)
- PPC_STL r5, VCPU_GPR(R13)(r4)
+ .if \type == EX_TLB
+ PPC_LL r5, EX_TLB_R13(r12)
+ PPC_LL r6, EX_TLB_R10(r12)
+ PPC_LL r8, EX_TLB_R11(r12)
+ mfspr r12, \scratch
+ .else
+ mfspr r5, \scratch
PPC_LL r6, (\paca_ex + \ex_r10)(r13)
PPC_LL r8, (\paca_ex + \ex_r11)(r13)
+ .endif
+ PPC_STL r5, VCPU_GPR(R13)(r4)
PPC_STL r3, VCPU_GPR(R3)(r4)
PPC_STL r7, VCPU_GPR(R7)(r4)
PPC_STL r12, VCPU_GPR(R12)(r4)
@@ -435,10 +438,16 @@ _GLOBAL(kvmppc_resume_host)
PPC_STL r5, VCPU_LR(r4)
mfspr r7, SPRN_SPRG5
stw r3, VCPU_VRSAVE(r4)
+#ifdef CONFIG_64BIT
+ PPC_LL r3, PACA_SPRG_VDSO(r13)
+#endif
PPC_STD(r6, VCPU_SHARED_SPRG4, r11)
mfspr r8, SPRN_SPRG6
PPC_STD(r7, VCPU_SHARED_SPRG5, r11)
mfspr r9, SPRN_SPRG7
+#ifdef CONFIG_64BIT
+ mtspr SPRN_SPRG_VDSO_WRITE, r3
+#endif
PPC_STD(r8, VCPU_SHARED_SPRG6, r11)
mfxer r3
PPC_STD(r9, VCPU_SHARED_SPRG7, r11)
diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S
index d2bbbc8d7dc0..72ad055168a3 100644
--- a/arch/powerpc/lib/memcpy_64.S
+++ b/arch/powerpc/lib/memcpy_64.S
@@ -14,7 +14,9 @@ _GLOBAL(memcpy)
BEGIN_FTR_SECTION
std r3,48(r1) /* save destination pointer for return value */
FTR_SECTION_ELSE
+#ifndef SELFTEST
b memcpy_power7
+#endif
ALT_FTR_SECTION_END_IFCLR(CPU_FTR_VMX_COPY)
PPC_MTOCRF(0x01,r5)
cmpldi cr1,r5,16
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 4b5cd5c2594d..2c8e90f5789e 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -139,9 +139,14 @@ int arch_remove_memory(u64 start, u64 size)
unsigned long start_pfn = start >> PAGE_SHIFT;
unsigned long nr_pages = size >> PAGE_SHIFT;
struct zone *zone;
+ int ret;
zone = page_zone(pfn_to_page(start_pfn));
- return __remove_pages(zone, start_pfn, nr_pages);
+ ret = __remove_pages(zone, start_pfn, nr_pages);
+ if (!ret && (ppc_md.remove_memory))
+ ret = ppc_md.remove_memory(start, size);
+
+ return ret;
}
#endif
#endif /* CONFIG_MEMORY_HOTPLUG */
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 65b7b65e8708..f6ce1f111f5b 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -510,7 +510,8 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, unsigned long address,
}
unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr,
- pmd_t *pmdp, unsigned long clr)
+ pmd_t *pmdp, unsigned long clr,
+ unsigned long set)
{
unsigned long old, tmp;
@@ -526,14 +527,15 @@ unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr,
andi. %1,%0,%6\n\
bne- 1b \n\
andc %1,%0,%4 \n\
+ or %1,%1,%7\n\
stdcx. %1,0,%3 \n\
bne- 1b"
: "=&r" (old), "=&r" (tmp), "=m" (*pmdp)
- : "r" (pmdp), "r" (clr), "m" (*pmdp), "i" (_PAGE_BUSY)
+ : "r" (pmdp), "r" (clr), "m" (*pmdp), "i" (_PAGE_BUSY), "r" (set)
: "cc" );
#else
old = pmd_val(*pmdp);
- *pmdp = __pmd(old & ~clr);
+ *pmdp = __pmd((old & ~clr) | set);
#endif
if (old & _PAGE_HASHPTE)
hpte_do_hugepage_flush(mm, addr, pmdp);
@@ -645,6 +647,11 @@ void pmdp_splitting_flush(struct vm_area_struct *vma,
if (old & _PAGE_HASHPTE)
hpte_do_hugepage_flush(vma->vm_mm, address, pmdp);
}
+ /*
+ * This ensures that generic code that rely on IRQ disabling
+ * to prevent a parallel THP split work as expected.
+ */
+ kick_all_cpus_sync();
}
/*
@@ -708,7 +715,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
pmd_t *pmdp)
{
- pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT);
+ pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, 0);
}
/*
@@ -835,7 +842,7 @@ pmd_t pmdp_get_and_clear(struct mm_struct *mm,
unsigned long old;
pgtable_t *pgtable_slot;
- old = pmd_hugepage_update(mm, addr, pmdp, ~0UL);
+ old = pmd_hugepage_update(mm, addr, pmdp, ~0UL, 0);
old_pmd = __pmd(old);
/*
* We have pmd == none and we are holding page_table_lock.
diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c
index a770df2dae70..6c0b1f5f8d2c 100644
--- a/arch/powerpc/mm/subpage-prot.c
+++ b/arch/powerpc/mm/subpage-prot.c
@@ -78,7 +78,7 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr,
pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
arch_enter_lazy_mmu_mode();
for (; npages > 0; --npages) {
- pte_update(mm, addr, pte, 0, 0);
+ pte_update(mm, addr, pte, 0, 0, 0);
addr += PAGE_SIZE;
++pte;
}
diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S
index c95eb323e9ae..356e8b41fb09 100644
--- a/arch/powerpc/mm/tlb_low_64e.S
+++ b/arch/powerpc/mm/tlb_low_64e.S
@@ -39,37 +39,49 @@
* *
**********************************************************************/
+/*
+ * Note that, unlike non-bolted handlers, TLB_EXFRAME is not
+ * modified by the TLB miss handlers themselves, since the TLB miss
+ * handler code will not itself cause a recursive TLB miss.
+ *
+ * TLB_EXFRAME will be modified when crit/mc/debug exceptions are
+ * entered/exited.
+ */
.macro tlb_prolog_bolted intnum addr
- mtspr SPRN_SPRG_GEN_SCRATCH,r13
+ mtspr SPRN_SPRG_GEN_SCRATCH,r12
+ mfspr r12,SPRN_SPRG_TLB_EXFRAME
+ std r13,EX_TLB_R13(r12)
+ std r10,EX_TLB_R10(r12)
mfspr r13,SPRN_SPRG_PACA
- std r10,PACA_EXTLB+EX_TLB_R10(r13)
+
mfcr r10
- std r11,PACA_EXTLB+EX_TLB_R11(r13)
+ std r11,EX_TLB_R11(r12)
#ifdef CONFIG_KVM_BOOKE_HV
BEGIN_FTR_SECTION
mfspr r11, SPRN_SRR1
END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV)
#endif
DO_KVM \intnum, SPRN_SRR1
- std r16,PACA_EXTLB+EX_TLB_R16(r13)
+ std r16,EX_TLB_R16(r12)
mfspr r16,\addr /* get faulting address */
- std r14,PACA_EXTLB+EX_TLB_R14(r13)
+ std r14,EX_TLB_R14(r12)
ld r14,PACAPGD(r13)
- std r15,PACA_EXTLB+EX_TLB_R15(r13)
- std r10,PACA_EXTLB+EX_TLB_CR(r13)
- TLB_MISS_PROLOG_STATS_BOLTED
+ std r15,EX_TLB_R15(r12)
+ std r10,EX_TLB_CR(r12)
+ TLB_MISS_PROLOG_STATS
.endm
.macro tlb_epilog_bolted
- ld r14,PACA_EXTLB+EX_TLB_CR(r13)
- ld r10,PACA_EXTLB+EX_TLB_R10(r13)
- ld r11,PACA_EXTLB+EX_TLB_R11(r13)
+ ld r14,EX_TLB_CR(r12)
+ ld r10,EX_TLB_R10(r12)
+ ld r11,EX_TLB_R11(r12)
+ ld r13,EX_TLB_R13(r12)
mtcr r14
- ld r14,PACA_EXTLB+EX_TLB_R14(r13)
- ld r15,PACA_EXTLB+EX_TLB_R15(r13)
- TLB_MISS_RESTORE_STATS_BOLTED
- ld r16,PACA_EXTLB+EX_TLB_R16(r13)
- mfspr r13,SPRN_SPRG_GEN_SCRATCH
+ ld r14,EX_TLB_R14(r12)
+ ld r15,EX_TLB_R15(r12)
+ TLB_MISS_RESTORE_STATS
+ ld r16,EX_TLB_R16(r12)
+ mfspr r12,SPRN_SPRG_GEN_SCRATCH
.endm
/* Data TLB miss */
@@ -284,7 +296,7 @@ itlb_miss_fault_bolted:
* r14 = page table base
* r13 = PACA
* r11 = tlb_per_core ptr
- * r10 = crap (free to use)
+ * r10 = cpu number
*/
tlb_miss_common_e6500:
/*
@@ -293,15 +305,18 @@ tlb_miss_common_e6500:
*
* MAS6:IND should be already set based on MAS4
*/
- addi r10,r11,TCD_LOCK
-1: lbarx r15,0,r10
+1: lbarx r15,0,r11
+ lhz r10,PACAPACAINDEX(r13)
cmpdi r15,0
+ cmpdi cr1,r15,1 /* set cr1.eq = 0 for non-recursive */
bne 2f
- li r15,1
- stbcx. r15,0,r10
+ stbcx. r10,0,r11
bne 1b
+3:
.subsection 1
-2: lbz r15,0(r10)
+2: cmpd cr1,r15,r10 /* recursive lock due to mcheck/crit/etc? */
+ beq cr1,3b /* unlock will happen if cr1.eq = 0 */
+ lbz r15,0(r11)
cmpdi r15,0
bne 2b
b 1b
@@ -379,9 +394,11 @@ tlb_miss_common_e6500:
tlb_miss_done_e6500:
.macro tlb_unlock_e6500
+ beq cr1,1f /* no unlock if lock was recursively grabbed */
li r15,0
isync
- stb r15,TCD_LOCK(r11)
+ stb r15,0(r11)
+1:
.endm
tlb_unlock_e6500
@@ -1091,7 +1108,8 @@ tlb_load_linear:
ld r11,PACATOC(r13)
ld r11,linear_map_top@got(r11)
ld r10,0(r11)
- cmpld cr0,r10,r16
+ tovirt(10,10)
+ cmpld cr0,r16,r10
bge tlb_load_linear_fault
/* MAS1 need whole new setup. */
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index b37a58e1c92d..ae3d5b799b90 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -144,6 +144,15 @@ int mmu_vmemmap_psize; /* Page size used for the virtual mem map */
int book3e_htw_mode; /* HW tablewalk? Value is PPC_HTW_* */
unsigned long linear_map_top; /* Top of linear mapping */
+
+/*
+ * Number of bytes to add to SPRN_SPRG_TLB_EXFRAME on crit/mcheck/debug
+ * exceptions. This is used for bolted and e6500 TLB miss handlers which
+ * do not modify this SPRG in the TLB miss code; for other TLB miss handlers,
+ * this is set to zero.
+ */
+int extlb_level_exc;
+
#endif /* CONFIG_PPC64 */
#ifdef CONFIG_PPC_FSL_BOOK3E
@@ -559,6 +568,7 @@ static void setup_mmu_htw(void)
break;
#ifdef CONFIG_PPC_FSL_BOOK3E
case PPC_HTW_E6500:
+ extlb_level_exc = EX_TLB_SIZE;
patch_exception(0x1c0, exc_data_tlb_miss_e6500_book3e);
patch_exception(0x1e0, exc_instruction_tlb_miss_e6500_book3e);
break;
@@ -652,6 +662,7 @@ static void __early_init_mmu(int boot_cpu)
memblock_enforce_memory_limit(linear_map_top);
if (book3e_htw_mode == PPC_HTW_NONE) {
+ extlb_level_exc = EX_TLB_SIZE;
patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e);
patch_exception(0x1e0,
exc_instruction_tlb_miss_bolted_book3e);
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index 1f0ebdeea5f7..863d89386f60 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -1121,8 +1121,7 @@ oprof_cpufreq_notify(struct notifier_block *nb, unsigned long val, void *data)
int ret = 0;
struct cpufreq_freqs *frq = data;
if ((val == CPUFREQ_PRECHANGE && frq->old < frq->new) ||
- (val == CPUFREQ_POSTCHANGE && frq->old > frq->new) ||
- (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE))
+ (val == CPUFREQ_POSTCHANGE && frq->old > frq->new))
set_spu_profiling_frequency(frq->new, spu_cycle_reset);
return ret;
}
diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile
index 60d71eea919c..f9c083a5652a 100644
--- a/arch/powerpc/perf/Makefile
+++ b/arch/powerpc/perf/Makefile
@@ -11,5 +11,7 @@ obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450-pmu.o
obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o
obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o e6500-pmu.o
+obj-$(CONFIG_HV_PERF_CTRS) += hv-24x7.o hv-gpci.o hv-common.o
+
obj-$(CONFIG_PPC64) += $(obj64-y)
obj-$(CONFIG_PPC32) += $(obj32-y)
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 67cf22083f4c..4520c9356b54 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -78,6 +78,7 @@ static unsigned int freeze_events_kernel = MMCR0_FCS;
#define MMCR0_FC56 0
#define MMCR0_PMAO 0
#define MMCR0_EBE 0
+#define MMCR0_BHRBA 0
#define MMCR0_PMCC 0
#define MMCR0_PMCC_U6 0
@@ -120,6 +121,7 @@ static inline void power_pmu_bhrb_enable(struct perf_event *event) {}
static inline void power_pmu_bhrb_disable(struct perf_event *event) {}
void power_pmu_flush_branch_stack(void) {}
static inline void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) {}
+static void pmao_restore_workaround(bool ebb) { }
#endif /* CONFIG_PPC32 */
static bool regs_use_siar(struct pt_regs *regs)
@@ -502,8 +504,11 @@ static int ebb_event_check(struct perf_event *event)
if (!leader->attr.pinned || !leader->attr.exclusive)
return -EINVAL;
- if (event->attr.inherit || event->attr.sample_period ||
- event->attr.enable_on_exec || event->attr.freq)
+ if (event->attr.freq ||
+ event->attr.inherit ||
+ event->attr.sample_type ||
+ event->attr.sample_period ||
+ event->attr.enable_on_exec)
return -EINVAL;
}
@@ -542,13 +547,21 @@ static unsigned long ebb_switch_in(bool ebb, unsigned long mmcr0)
if (!ebb)
goto out;
- /* Enable EBB and read/write to all 6 PMCs for userspace */
- mmcr0 |= MMCR0_EBE | MMCR0_PMCC_U6;
+ /* Enable EBB and read/write to all 6 PMCs and BHRB for userspace */
+ mmcr0 |= MMCR0_EBE | MMCR0_BHRBA | MMCR0_PMCC_U6;
- /* Add any bits from the user reg, FC or PMAO */
+ /*
+ * Add any bits from the user MMCR0, FC or PMAO. This is compatible
+ * with pmao_restore_workaround() because we may add PMAO but we never
+ * clear it here.
+ */
mmcr0 |= current->thread.mmcr0;
- /* Be careful not to set PMXE if userspace had it cleared */
+ /*
+ * Be careful not to set PMXE if userspace had it cleared. This is also
+ * compatible with pmao_restore_workaround() because it has already
+ * cleared PMXE and we leave PMAO alone.
+ */
if (!(current->thread.mmcr0 & MMCR0_PMXE))
mmcr0 &= ~MMCR0_PMXE;
@@ -559,13 +572,94 @@ static unsigned long ebb_switch_in(bool ebb, unsigned long mmcr0)
out:
return mmcr0;
}
-#endif /* CONFIG_PPC64 */
-
-static void perf_event_interrupt(struct pt_regs *regs);
-void perf_event_print_debug(void)
+static void pmao_restore_workaround(bool ebb)
{
+ unsigned pmcs[6];
+
+ if (!cpu_has_feature(CPU_FTR_PMAO_BUG))
+ return;
+
+ /*
+ * On POWER8E there is a hardware defect which affects the PMU context
+ * switch logic, ie. power_pmu_disable/enable().
+ *
+ * When a counter overflows PMXE is cleared and FC/PMAO is set in MMCR0
+ * by the hardware. Sometime later the actual PMU exception is
+ * delivered.
+ *
+ * If we context switch, or simply disable/enable, the PMU prior to the
+ * exception arriving, the exception will be lost when we clear PMAO.
+ *
+ * When we reenable the PMU, we will write the saved MMCR0 with PMAO
+ * set, and this _should_ generate an exception. However because of the
+ * defect no exception is generated when we write PMAO, and we get
+ * stuck with no counters counting but no exception delivered.
+ *
+ * The workaround is to detect this case and tweak the hardware to
+ * create another pending PMU exception.
+ *
+ * We do that by setting up PMC6 (cycles) for an imminent overflow and
+ * enabling the PMU. That causes a new exception to be generated in the
+ * chip, but we don't take it yet because we have interrupts hard
+ * disabled. We then write back the PMU state as we want it to be seen
+ * by the exception handler. When we reenable interrupts the exception
+ * handler will be called and see the correct state.
+ *
+ * The logic is the same for EBB, except that the exception is gated by
+ * us having interrupts hard disabled as well as the fact that we are
+ * not in userspace. The exception is finally delivered when we return
+ * to userspace.
+ */
+
+ /* Only if PMAO is set and PMAO_SYNC is clear */
+ if ((current->thread.mmcr0 & (MMCR0_PMAO | MMCR0_PMAO_SYNC)) != MMCR0_PMAO)
+ return;
+
+ /* If we're doing EBB, only if BESCR[GE] is set */
+ if (ebb && !(current->thread.bescr & BESCR_GE))
+ return;
+
+ /*
+ * We are already soft-disabled in power_pmu_enable(). We need to hard
+ * enable to actually prevent the PMU exception from firing.
+ */
+ hard_irq_disable();
+
+ /*
+ * This is a bit gross, but we know we're on POWER8E and have 6 PMCs.
+ * Using read/write_pmc() in a for loop adds 12 function calls and
+ * almost doubles our code size.
+ */
+ pmcs[0] = mfspr(SPRN_PMC1);
+ pmcs[1] = mfspr(SPRN_PMC2);
+ pmcs[2] = mfspr(SPRN_PMC3);
+ pmcs[3] = mfspr(SPRN_PMC4);
+ pmcs[4] = mfspr(SPRN_PMC5);
+ pmcs[5] = mfspr(SPRN_PMC6);
+
+ /* Ensure all freeze bits are unset */
+ mtspr(SPRN_MMCR2, 0);
+
+ /* Set up PMC6 to overflow in one cycle */
+ mtspr(SPRN_PMC6, 0x7FFFFFFE);
+
+ /* Enable exceptions and unfreeze PMC6 */
+ mtspr(SPRN_MMCR0, MMCR0_PMXE | MMCR0_PMCjCE | MMCR0_PMAO);
+
+ /* Now we need to refreeze and restore the PMCs */
+ mtspr(SPRN_MMCR0, MMCR0_FC | MMCR0_PMAO);
+
+ mtspr(SPRN_PMC1, pmcs[0]);
+ mtspr(SPRN_PMC2, pmcs[1]);
+ mtspr(SPRN_PMC3, pmcs[2]);
+ mtspr(SPRN_PMC4, pmcs[3]);
+ mtspr(SPRN_PMC5, pmcs[4]);
+ mtspr(SPRN_PMC6, pmcs[5]);
}
+#endif /* CONFIG_PPC64 */
+
+static void perf_event_interrupt(struct pt_regs *regs);
/*
* Read one performance monitor counter (PMC).
@@ -645,6 +739,57 @@ static void write_pmc(int idx, unsigned long val)
}
}
+/* Called from sysrq_handle_showregs() */
+void perf_event_print_debug(void)
+{
+ unsigned long sdar, sier, flags;
+ u32 pmcs[MAX_HWEVENTS];
+ int i;
+
+ if (!ppmu->n_counter)
+ return;
+
+ local_irq_save(flags);
+
+ pr_info("CPU: %d PMU registers, ppmu = %s n_counters = %d",
+ smp_processor_id(), ppmu->name, ppmu->n_counter);
+
+ for (i = 0; i < ppmu->n_counter; i++)
+ pmcs[i] = read_pmc(i + 1);
+
+ for (; i < MAX_HWEVENTS; i++)
+ pmcs[i] = 0xdeadbeef;
+
+ pr_info("PMC1: %08x PMC2: %08x PMC3: %08x PMC4: %08x\n",
+ pmcs[0], pmcs[1], pmcs[2], pmcs[3]);
+
+ if (ppmu->n_counter > 4)
+ pr_info("PMC5: %08x PMC6: %08x PMC7: %08x PMC8: %08x\n",
+ pmcs[4], pmcs[5], pmcs[6], pmcs[7]);
+
+ pr_info("MMCR0: %016lx MMCR1: %016lx MMCRA: %016lx\n",
+ mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCRA));
+
+ sdar = sier = 0;
+#ifdef CONFIG_PPC64
+ sdar = mfspr(SPRN_SDAR);
+
+ if (ppmu->flags & PPMU_HAS_SIER)
+ sier = mfspr(SPRN_SIER);
+
+ if (ppmu->flags & PPMU_EBB) {
+ pr_info("MMCR2: %016lx EBBHR: %016lx\n",
+ mfspr(SPRN_MMCR2), mfspr(SPRN_EBBHR));
+ pr_info("EBBRR: %016lx BESCR: %016lx\n",
+ mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
+ }
+#endif
+ pr_info("SIAR: %016lx SDAR: %016lx SIER: %016lx\n",
+ mfspr(SPRN_SIAR), sdar, sier);
+
+ local_irq_restore(flags);
+}
+
/*
* Check if a set of events can all go on the PMU at once.
* If they can't, this will look at alternative codes for the events
@@ -973,11 +1118,12 @@ static void power_pmu_disable(struct pmu *pmu)
}
/*
- * Set the 'freeze counters' bit, clear EBE/PMCC/PMAO/FC56.
+ * Set the 'freeze counters' bit, clear EBE/BHRBA/PMCC/PMAO/FC56
*/
val = mmcr0 = mfspr(SPRN_MMCR0);
val |= MMCR0_FC;
- val &= ~(MMCR0_EBE | MMCR0_PMCC | MMCR0_PMAO | MMCR0_FC56);
+ val &= ~(MMCR0_EBE | MMCR0_BHRBA | MMCR0_PMCC | MMCR0_PMAO |
+ MMCR0_FC56);
/*
* The barrier is to make sure the mtspr has been
@@ -1144,6 +1290,8 @@ static void power_pmu_enable(struct pmu *pmu)
cpuhw->mmcr[0] |= MMCR0_PMXE | MMCR0_FCECE;
out_enable:
+ pmao_restore_workaround(ebb);
+
mmcr0 = ebb_switch_in(ebb, cpuhw->mmcr[0]);
mb();
diff --git a/arch/powerpc/perf/hv-24x7-catalog.h b/arch/powerpc/perf/hv-24x7-catalog.h
new file mode 100644
index 000000000000..21b19dd86d9c
--- /dev/null
+++ b/arch/powerpc/perf/hv-24x7-catalog.h
@@ -0,0 +1,33 @@
+#ifndef LINUX_POWERPC_PERF_HV_24X7_CATALOG_H_
+#define LINUX_POWERPC_PERF_HV_24X7_CATALOG_H_
+
+#include <linux/types.h>
+
+/* From document "24x7 Event and Group Catalog Formats Proposal" v0.15 */
+
+struct hv_24x7_catalog_page_0 {
+#define HV_24X7_CATALOG_MAGIC 0x32347837 /* "24x7" in ASCII */
+ __be32 magic;
+ __be32 length; /* In 4096 byte pages */
+ __be64 version; /* XXX: arbitrary? what's the meaning/useage/purpose? */
+ __u8 build_time_stamp[16]; /* "YYYYMMDDHHMMSS\0\0" */
+ __u8 reserved2[32];
+ __be16 schema_data_offs; /* in 4096 byte pages */
+ __be16 schema_data_len; /* in 4096 byte pages */
+ __be16 schema_entry_count;
+ __u8 reserved3[2];
+ __be16 event_data_offs;
+ __be16 event_data_len;
+ __be16 event_entry_count;
+ __u8 reserved4[2];
+ __be16 group_data_offs; /* in 4096 byte pages */
+ __be16 group_data_len; /* in 4096 byte pages */
+ __be16 group_entry_count;
+ __u8 reserved5[2];
+ __be16 formula_data_offs; /* in 4096 byte pages */
+ __be16 formula_data_len; /* in 4096 byte pages */
+ __be16 formula_entry_count;
+ __u8 reserved6[2];
+} __packed;
+
+#endif
diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c
new file mode 100644
index 000000000000..297c91051413
--- /dev/null
+++ b/arch/powerpc/perf/hv-24x7.c
@@ -0,0 +1,510 @@
+/*
+ * Hypervisor supplied "24x7" performance counter support
+ *
+ * Author: Cody P Schafer <cody@linux.vnet.ibm.com>
+ * Copyright 2014 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "hv-24x7: " fmt
+
+#include <linux/perf_event.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/firmware.h>
+#include <asm/hvcall.h>
+#include <asm/io.h>
+
+#include "hv-24x7.h"
+#include "hv-24x7-catalog.h"
+#include "hv-common.h"
+
+/*
+ * TODO: Merging events:
+ * - Think of the hcall as an interface to a 4d array of counters:
+ * - x = domains
+ * - y = indexes in the domain (core, chip, vcpu, node, etc)
+ * - z = offset into the counter space
+ * - w = lpars (guest vms, "logical partitions")
+ * - A single request is: x,y,y_last,z,z_last,w,w_last
+ * - this means we can retrieve a rectangle of counters in y,z for a single x.
+ *
+ * - Things to consider (ignoring w):
+ * - input cost_per_request = 16
+ * - output cost_per_result(ys,zs) = 8 + 8 * ys + ys * zs
+ * - limited number of requests per hcall (must fit into 4K bytes)
+ * - 4k = 16 [buffer header] - 16 [request size] * request_count
+ * - 255 requests per hcall
+ * - sometimes it will be more efficient to read extra data and discard
+ */
+
+/*
+ * Example usage:
+ * perf stat -e 'hv_24x7/domain=2,offset=8,starting_index=0,lpar=0xffffffff/'
+ */
+
+/* u3 0-6, one of HV_24X7_PERF_DOMAIN */
+EVENT_DEFINE_RANGE_FORMAT(domain, config, 0, 3);
+/* u16 */
+EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 16, 31);
+/* u32, see "data_offset" */
+EVENT_DEFINE_RANGE_FORMAT(offset, config, 32, 63);
+/* u16 */
+EVENT_DEFINE_RANGE_FORMAT(lpar, config1, 0, 15);
+
+EVENT_DEFINE_RANGE(reserved1, config, 4, 15);
+EVENT_DEFINE_RANGE(reserved2, config1, 16, 63);
+EVENT_DEFINE_RANGE(reserved3, config2, 0, 63);
+
+static struct attribute *format_attrs[] = {
+ &format_attr_domain.attr,
+ &format_attr_offset.attr,
+ &format_attr_starting_index.attr,
+ &format_attr_lpar.attr,
+ NULL,
+};
+
+static struct attribute_group format_group = {
+ .name = "format",
+ .attrs = format_attrs,
+};
+
+static struct kmem_cache *hv_page_cache;
+
+/*
+ * read_offset_data - copy data from one buffer to another while treating the
+ * source buffer as a small view on the total avaliable
+ * source data.
+ *
+ * @dest: buffer to copy into
+ * @dest_len: length of @dest in bytes
+ * @requested_offset: the offset within the source data we want. Must be > 0
+ * @src: buffer to copy data from
+ * @src_len: length of @src in bytes
+ * @source_offset: the offset in the sorce data that (src,src_len) refers to.
+ * Must be > 0
+ *
+ * returns the number of bytes copied.
+ *
+ * The following ascii art shows the various buffer possitioning we need to
+ * handle, assigns some arbitrary varibles to points on the buffer, and then
+ * shows how we fiddle with those values to get things we care about (copy
+ * start in src and copy len)
+ *
+ * s = @src buffer
+ * d = @dest buffer
+ * '.' areas in d are written to.
+ *
+ * u
+ * x w v z
+ * d |.........|
+ * s |----------------------|
+ *
+ * u
+ * x w z v
+ * d |........------|
+ * s |------------------|
+ *
+ * x w u,z,v
+ * d |........|
+ * s |------------------|
+ *
+ * x,w u,v,z
+ * d |..................|
+ * s |------------------|
+ *
+ * x u
+ * w v z
+ * d |........|
+ * s |------------------|
+ *
+ * x z w v
+ * d |------|
+ * s |------|
+ *
+ * x = source_offset
+ * w = requested_offset
+ * z = source_offset + src_len
+ * v = requested_offset + dest_len
+ *
+ * w_offset_in_s = w - x = requested_offset - source_offset
+ * z_offset_in_s = z - x = src_len
+ * v_offset_in_s = v - x = request_offset + dest_len - src_len
+ */
+static ssize_t read_offset_data(void *dest, size_t dest_len,
+ loff_t requested_offset, void *src,
+ size_t src_len, loff_t source_offset)
+{
+ size_t w_offset_in_s = requested_offset - source_offset;
+ size_t z_offset_in_s = src_len;
+ size_t v_offset_in_s = requested_offset + dest_len - src_len;
+ size_t u_offset_in_s = min(z_offset_in_s, v_offset_in_s);
+ size_t copy_len = u_offset_in_s - w_offset_in_s;
+
+ if (requested_offset < 0 || source_offset < 0)
+ return -EINVAL;
+
+ if (z_offset_in_s <= w_offset_in_s)
+ return 0;
+
+ memcpy(dest, src + w_offset_in_s, copy_len);
+ return copy_len;
+}
+
+static unsigned long h_get_24x7_catalog_page(char page[static 4096],
+ u32 version, u32 index)
+{
+ WARN_ON(!IS_ALIGNED((unsigned long)page, 4096));
+ return plpar_hcall_norets(H_GET_24X7_CATALOG_PAGE,
+ virt_to_phys(page),
+ version,
+ index);
+}
+
+static ssize_t catalog_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t offset, size_t count)
+{
+ unsigned long hret;
+ ssize_t ret = 0;
+ size_t catalog_len = 0, catalog_page_len = 0, page_count = 0;
+ loff_t page_offset = 0;
+ uint32_t catalog_version_num = 0;
+ void *page = kmem_cache_alloc(hv_page_cache, GFP_USER);
+ struct hv_24x7_catalog_page_0 *page_0 = page;
+ if (!page)
+ return -ENOMEM;
+
+ hret = h_get_24x7_catalog_page(page, 0, 0);
+ if (hret) {
+ ret = -EIO;
+ goto e_free;
+ }
+
+ catalog_version_num = be32_to_cpu(page_0->version);
+ catalog_page_len = be32_to_cpu(page_0->length);
+ catalog_len = catalog_page_len * 4096;
+
+ page_offset = offset / 4096;
+ page_count = count / 4096;
+
+ if (page_offset >= catalog_page_len)
+ goto e_free;
+
+ if (page_offset != 0) {
+ hret = h_get_24x7_catalog_page(page, catalog_version_num,
+ page_offset);
+ if (hret) {
+ ret = -EIO;
+ goto e_free;
+ }
+ }
+
+ ret = read_offset_data(buf, count, offset,
+ page, 4096, page_offset * 4096);
+e_free:
+ if (hret)
+ pr_err("h_get_24x7_catalog_page(ver=%d, page=%lld) failed: rc=%ld\n",
+ catalog_version_num, page_offset, hret);
+ kfree(page);
+
+ pr_devel("catalog_read: offset=%lld(%lld) count=%zu(%zu) catalog_len=%zu(%zu) => %zd\n",
+ offset, page_offset, count, page_count, catalog_len,
+ catalog_page_len, ret);
+
+ return ret;
+}
+
+#define PAGE_0_ATTR(_name, _fmt, _expr) \
+static ssize_t _name##_show(struct device *dev, \
+ struct device_attribute *dev_attr, \
+ char *buf) \
+{ \
+ unsigned long hret; \
+ ssize_t ret = 0; \
+ void *page = kmem_cache_alloc(hv_page_cache, GFP_USER); \
+ struct hv_24x7_catalog_page_0 *page_0 = page; \
+ if (!page) \
+ return -ENOMEM; \
+ hret = h_get_24x7_catalog_page(page, 0, 0); \
+ if (hret) { \
+ ret = -EIO; \
+ goto e_free; \
+ } \
+ ret = sprintf(buf, _fmt, _expr); \
+e_free: \
+ kfree(page); \
+ return ret; \
+} \
+static DEVICE_ATTR_RO(_name)
+
+PAGE_0_ATTR(catalog_version, "%lld\n",
+ (unsigned long long)be32_to_cpu(page_0->version));
+PAGE_0_ATTR(catalog_len, "%lld\n",
+ (unsigned long long)be32_to_cpu(page_0->length) * 4096);
+static BIN_ATTR_RO(catalog, 0/* real length varies */);
+
+static struct bin_attribute *if_bin_attrs[] = {
+ &bin_attr_catalog,
+ NULL,
+};
+
+static struct attribute *if_attrs[] = {
+ &dev_attr_catalog_len.attr,
+ &dev_attr_catalog_version.attr,
+ NULL,
+};
+
+static struct attribute_group if_group = {
+ .name = "interface",
+ .bin_attrs = if_bin_attrs,
+ .attrs = if_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+ &format_group,
+ &if_group,
+ NULL,
+};
+
+static bool is_physical_domain(int domain)
+{
+ return domain == HV_24X7_PERF_DOMAIN_PHYSICAL_CHIP ||
+ domain == HV_24X7_PERF_DOMAIN_PHYSICAL_CORE;
+}
+
+static unsigned long single_24x7_request(u8 domain, u32 offset, u16 ix,
+ u16 lpar, u64 *res,
+ bool success_expected)
+{
+ unsigned long ret;
+
+ /*
+ * request_buffer and result_buffer are not required to be 4k aligned,
+ * but are not allowed to cross any 4k boundary. Aligning them to 4k is
+ * the simplest way to ensure that.
+ */
+ struct reqb {
+ struct hv_24x7_request_buffer buf;
+ struct hv_24x7_request req;
+ } __packed __aligned(4096) request_buffer = {
+ .buf = {
+ .interface_version = HV_24X7_IF_VERSION_CURRENT,
+ .num_requests = 1,
+ },
+ .req = {
+ .performance_domain = domain,
+ .data_size = cpu_to_be16(8),
+ .data_offset = cpu_to_be32(offset),
+ .starting_lpar_ix = cpu_to_be16(lpar),
+ .max_num_lpars = cpu_to_be16(1),
+ .starting_ix = cpu_to_be16(ix),
+ .max_ix = cpu_to_be16(1),
+ }
+ };
+
+ struct resb {
+ struct hv_24x7_data_result_buffer buf;
+ struct hv_24x7_result res;
+ struct hv_24x7_result_element elem;
+ __be64 result;
+ } __packed __aligned(4096) result_buffer = {};
+
+ ret = plpar_hcall_norets(H_GET_24X7_DATA,
+ virt_to_phys(&request_buffer), sizeof(request_buffer),
+ virt_to_phys(&result_buffer), sizeof(result_buffer));
+
+ if (ret) {
+ if (success_expected)
+ pr_err_ratelimited("hcall failed: %d %#x %#x %d => 0x%lx (%ld) detail=0x%x failing ix=%x\n",
+ domain, offset, ix, lpar,
+ ret, ret,
+ result_buffer.buf.detailed_rc,
+ result_buffer.buf.failing_request_ix);
+ return ret;
+ }
+
+ *res = be64_to_cpu(result_buffer.result);
+ return ret;
+}
+
+static unsigned long event_24x7_request(struct perf_event *event, u64 *res,
+ bool success_expected)
+{
+ return single_24x7_request(event_get_domain(event),
+ event_get_offset(event),
+ event_get_starting_index(event),
+ event_get_lpar(event),
+ res,
+ success_expected);
+}
+
+static int h_24x7_event_init(struct perf_event *event)
+{
+ struct hv_perf_caps caps;
+ unsigned domain;
+ unsigned long hret;
+ u64 ct;
+
+ /* Not our event */
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ /* Unused areas must be 0 */
+ if (event_get_reserved1(event) ||
+ event_get_reserved2(event) ||
+ event_get_reserved3(event)) {
+ pr_devel("reserved set when forbidden 0x%llx(0x%llx) 0x%llx(0x%llx) 0x%llx(0x%llx)\n",
+ event->attr.config,
+ event_get_reserved1(event),
+ event->attr.config1,
+ event_get_reserved2(event),
+ event->attr.config2,
+ event_get_reserved3(event));
+ return -EINVAL;
+ }
+
+ /* unsupported modes and filters */
+ if (event->attr.exclude_user ||
+ event->attr.exclude_kernel ||
+ event->attr.exclude_hv ||
+ event->attr.exclude_idle ||
+ event->attr.exclude_host ||
+ event->attr.exclude_guest ||
+ is_sampling_event(event)) /* no sampling */
+ return -EINVAL;
+
+ /* no branch sampling */
+ if (has_branch_stack(event))
+ return -EOPNOTSUPP;
+
+ /* offset must be 8 byte aligned */
+ if (event_get_offset(event) % 8) {
+ pr_devel("bad alignment\n");
+ return -EINVAL;
+ }
+
+ /* Domains above 6 are invalid */
+ domain = event_get_domain(event);
+ if (domain > 6) {
+ pr_devel("invalid domain %d\n", domain);
+ return -EINVAL;
+ }
+
+ hret = hv_perf_caps_get(&caps);
+ if (hret) {
+ pr_devel("could not get capabilities: rc=%ld\n", hret);
+ return -EIO;
+ }
+
+ /* PHYSICAL domains & other lpars require extra capabilities */
+ if (!caps.collect_privileged && (is_physical_domain(domain) ||
+ (event_get_lpar(event) != event_get_lpar_max()))) {
+ pr_devel("hv permisions disallow: is_physical_domain:%d, lpar=0x%llx\n",
+ is_physical_domain(domain),
+ event_get_lpar(event));
+ return -EACCES;
+ }
+
+ /* see if the event complains */
+ if (event_24x7_request(event, &ct, false)) {
+ pr_devel("test hcall failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static u64 h_24x7_get_value(struct perf_event *event)
+{
+ unsigned long ret;
+ u64 ct;
+ ret = event_24x7_request(event, &ct, true);
+ if (ret)
+ /* We checked this in event init, shouldn't fail here... */
+ return 0;
+
+ return ct;
+}
+
+static void h_24x7_event_update(struct perf_event *event)
+{
+ s64 prev;
+ u64 now;
+ now = h_24x7_get_value(event);
+ prev = local64_xchg(&event->hw.prev_count, now);
+ local64_add(now - prev, &event->count);
+}
+
+static void h_24x7_event_start(struct perf_event *event, int flags)
+{
+ if (flags & PERF_EF_RELOAD)
+ local64_set(&event->hw.prev_count, h_24x7_get_value(event));
+}
+
+static void h_24x7_event_stop(struct perf_event *event, int flags)
+{
+ h_24x7_event_update(event);
+}
+
+static int h_24x7_event_add(struct perf_event *event, int flags)
+{
+ if (flags & PERF_EF_START)
+ h_24x7_event_start(event, flags);
+
+ return 0;
+}
+
+static int h_24x7_event_idx(struct perf_event *event)
+{
+ return 0;
+}
+
+static struct pmu h_24x7_pmu = {
+ .task_ctx_nr = perf_invalid_context,
+
+ .name = "hv_24x7",
+ .attr_groups = attr_groups,
+ .event_init = h_24x7_event_init,
+ .add = h_24x7_event_add,
+ .del = h_24x7_event_stop,
+ .start = h_24x7_event_start,
+ .stop = h_24x7_event_stop,
+ .read = h_24x7_event_update,
+ .event_idx = h_24x7_event_idx,
+};
+
+static int hv_24x7_init(void)
+{
+ int r;
+ unsigned long hret;
+ struct hv_perf_caps caps;
+
+ if (!firmware_has_feature(FW_FEATURE_LPAR)) {
+ pr_info("not a virtualized system, not enabling\n");
+ return -ENODEV;
+ }
+
+ hret = hv_perf_caps_get(&caps);
+ if (hret) {
+ pr_info("could not obtain capabilities, error 0x%80lx, not enabling\n",
+ hret);
+ return -ENODEV;
+ }
+
+ hv_page_cache = kmem_cache_create("hv-page-4096", 4096, 4096, 0, NULL);
+ if (!hv_page_cache)
+ return -ENOMEM;
+
+ r = perf_pmu_register(&h_24x7_pmu, h_24x7_pmu.name, -1);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+device_initcall(hv_24x7_init);
diff --git a/arch/powerpc/perf/hv-24x7.h b/arch/powerpc/perf/hv-24x7.h
new file mode 100644
index 000000000000..720ebce4b435
--- /dev/null
+++ b/arch/powerpc/perf/hv-24x7.h
@@ -0,0 +1,109 @@
+#ifndef LINUX_POWERPC_PERF_HV_24X7_H_
+#define LINUX_POWERPC_PERF_HV_24X7_H_
+
+#include <linux/types.h>
+
+struct hv_24x7_request {
+ /* PHYSICAL domains require enabling via phyp/hmc. */
+#define HV_24X7_PERF_DOMAIN_PHYSICAL_CHIP 0x01
+#define HV_24X7_PERF_DOMAIN_PHYSICAL_CORE 0x02
+#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_HOME_CORE 0x03
+#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_HOME_CHIP 0x04
+#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_HOME_NODE 0x05
+#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_REMOTE_NODE 0x06
+ __u8 performance_domain;
+ __u8 reserved[0x1];
+
+ /* bytes to read starting at @data_offset. must be a multiple of 8 */
+ __be16 data_size;
+
+ /*
+ * byte offset within the perf domain to read from. must be 8 byte
+ * aligned
+ */
+ __be32 data_offset;
+
+ /*
+ * only valid for VIRTUAL_PROCESSOR domains, ignored for others.
+ * -1 means "current partition only"
+ * Enabling via phyp/hmc required for non-"-1" values. 0 forbidden
+ * unless requestor is 0.
+ */
+ __be16 starting_lpar_ix;
+
+ /*
+ * Ignored when @starting_lpar_ix == -1
+ * Ignored when @performance_domain is not VIRTUAL_PROCESSOR_*
+ * -1 means "infinite" or all
+ */
+ __be16 max_num_lpars;
+
+ /* chip, core, or virtual processor based on @performance_domain */
+ __be16 starting_ix;
+ __be16 max_ix;
+} __packed;
+
+struct hv_24x7_request_buffer {
+ /* 0 - ? */
+ /* 1 - ? */
+#define HV_24X7_IF_VERSION_CURRENT 0x01
+ __u8 interface_version;
+ __u8 num_requests;
+ __u8 reserved[0xE];
+ struct hv_24x7_request requests[];
+} __packed;
+
+struct hv_24x7_result_element {
+ __be16 lpar_ix;
+
+ /*
+ * represents the core, chip, or virtual processor based on the
+ * request's @performance_domain
+ */
+ __be16 domain_ix;
+
+ /* -1 if @performance_domain does not refer to a virtual processor */
+ __be32 lpar_cfg_instance_id;
+
+ /* size = @result_element_data_size of cointaining result. */
+ __u8 element_data[];
+} __packed;
+
+struct hv_24x7_result {
+ __u8 result_ix;
+
+ /*
+ * 0 = not all result elements fit into the buffer, additional requests
+ * required
+ * 1 = all result elements were returned
+ */
+ __u8 results_complete;
+ __be16 num_elements_returned;
+
+ /* This is a copy of @data_size from the coresponding hv_24x7_request */
+ __be16 result_element_data_size;
+ __u8 reserved[0x2];
+
+ /* WARNING: only valid for first result element due to variable sizes
+ * of result elements */
+ /* struct hv_24x7_result_element[@num_elements_returned] */
+ struct hv_24x7_result_element elements[];
+} __packed;
+
+struct hv_24x7_data_result_buffer {
+ /* See versioning for request buffer */
+ __u8 interface_version;
+
+ __u8 num_results;
+ __u8 reserved[0x1];
+ __u8 failing_request_ix;
+ __be32 detailed_rc;
+ __be64 cec_cfg_instance_id;
+ __be64 catalog_version_num;
+ __u8 reserved2[0x8];
+ /* WARNING: only valid for the first result due to variable sizes of
+ * results */
+ struct hv_24x7_result results[]; /* [@num_results] */
+} __packed;
+
+#endif
diff --git a/arch/powerpc/perf/hv-common.c b/arch/powerpc/perf/hv-common.c
new file mode 100644
index 000000000000..47e02b366f58
--- /dev/null
+++ b/arch/powerpc/perf/hv-common.c
@@ -0,0 +1,39 @@
+#include <asm/io.h>
+#include <asm/hvcall.h>
+
+#include "hv-gpci.h"
+#include "hv-common.h"
+
+unsigned long hv_perf_caps_get(struct hv_perf_caps *caps)
+{
+ unsigned long r;
+ struct p {
+ struct hv_get_perf_counter_info_params params;
+ struct cv_system_performance_capabilities caps;
+ } __packed __aligned(sizeof(uint64_t));
+
+ struct p arg = {
+ .params = {
+ .counter_request = cpu_to_be32(
+ CIR_SYSTEM_PERFORMANCE_CAPABILITIES),
+ .starting_index = cpu_to_be32(-1),
+ .counter_info_version_in = 0,
+ }
+ };
+
+ r = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO,
+ virt_to_phys(&arg), sizeof(arg));
+
+ if (r)
+ return r;
+
+ pr_devel("capability_mask: 0x%x\n", arg.caps.capability_mask);
+
+ caps->version = arg.params.counter_info_version_out;
+ caps->collect_privileged = !!arg.caps.perf_collect_privileged;
+ caps->ga = !!(arg.caps.capability_mask & CV_CM_GA);
+ caps->expanded = !!(arg.caps.capability_mask & CV_CM_EXPANDED);
+ caps->lab = !!(arg.caps.capability_mask & CV_CM_LAB);
+
+ return r;
+}
diff --git a/arch/powerpc/perf/hv-common.h b/arch/powerpc/perf/hv-common.h
new file mode 100644
index 000000000000..5d79cecbd73d
--- /dev/null
+++ b/arch/powerpc/perf/hv-common.h
@@ -0,0 +1,36 @@
+#ifndef LINUX_POWERPC_PERF_HV_COMMON_H_
+#define LINUX_POWERPC_PERF_HV_COMMON_H_
+
+#include <linux/perf_event.h>
+#include <linux/types.h>
+
+struct hv_perf_caps {
+ u16 version;
+ u16 collect_privileged:1,
+ ga:1,
+ expanded:1,
+ lab:1,
+ unused:12;
+};
+
+unsigned long hv_perf_caps_get(struct hv_perf_caps *caps);
+
+
+#define EVENT_DEFINE_RANGE_FORMAT(name, attr_var, bit_start, bit_end) \
+PMU_FORMAT_ATTR(name, #attr_var ":" #bit_start "-" #bit_end); \
+EVENT_DEFINE_RANGE(name, attr_var, bit_start, bit_end)
+
+#define EVENT_DEFINE_RANGE(name, attr_var, bit_start, bit_end) \
+static u64 event_get_##name##_max(void) \
+{ \
+ BUILD_BUG_ON((bit_start > bit_end) \
+ || (bit_end >= (sizeof(1ull) * 8))); \
+ return (((1ull << (bit_end - bit_start)) - 1) << 1) + 1; \
+} \
+static u64 event_get_##name(struct perf_event *event) \
+{ \
+ return (event->attr.attr_var >> (bit_start)) & \
+ event_get_##name##_max(); \
+}
+
+#endif
diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c
new file mode 100644
index 000000000000..278ba7b9c2b5
--- /dev/null
+++ b/arch/powerpc/perf/hv-gpci.c
@@ -0,0 +1,294 @@
+/*
+ * Hypervisor supplied "gpci" ("get performance counter info") performance
+ * counter support
+ *
+ * Author: Cody P Schafer <cody@linux.vnet.ibm.com>
+ * Copyright 2014 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "hv-gpci: " fmt
+
+#include <linux/init.h>
+#include <linux/perf_event.h>
+#include <asm/firmware.h>
+#include <asm/hvcall.h>
+#include <asm/io.h>
+
+#include "hv-gpci.h"
+#include "hv-common.h"
+
+/*
+ * Example usage:
+ * perf stat -e 'hv_gpci/counter_info_version=3,offset=0,length=8,
+ * secondary_index=0,starting_index=0xffffffff,request=0x10/' ...
+ */
+
+/* u32 */
+EVENT_DEFINE_RANGE_FORMAT(request, config, 0, 31);
+/* u32 */
+EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 32, 63);
+/* u16 */
+EVENT_DEFINE_RANGE_FORMAT(secondary_index, config1, 0, 15);
+/* u8 */
+EVENT_DEFINE_RANGE_FORMAT(counter_info_version, config1, 16, 23);
+/* u8, bytes of data (1-8) */
+EVENT_DEFINE_RANGE_FORMAT(length, config1, 24, 31);
+/* u32, byte offset */
+EVENT_DEFINE_RANGE_FORMAT(offset, config1, 32, 63);
+
+static struct attribute *format_attrs[] = {
+ &format_attr_request.attr,
+ &format_attr_starting_index.attr,
+ &format_attr_secondary_index.attr,
+ &format_attr_counter_info_version.attr,
+
+ &format_attr_offset.attr,
+ &format_attr_length.attr,
+ NULL,
+};
+
+static struct attribute_group format_group = {
+ .name = "format",
+ .attrs = format_attrs,
+};
+
+#define HV_CAPS_ATTR(_name, _format) \
+static ssize_t _name##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *page) \
+{ \
+ struct hv_perf_caps caps; \
+ unsigned long hret = hv_perf_caps_get(&caps); \
+ if (hret) \
+ return -EIO; \
+ \
+ return sprintf(page, _format, caps._name); \
+} \
+static struct device_attribute hv_caps_attr_##_name = __ATTR_RO(_name)
+
+static ssize_t kernel_version_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ return sprintf(page, "0x%x\n", COUNTER_INFO_VERSION_CURRENT);
+}
+
+DEVICE_ATTR_RO(kernel_version);
+HV_CAPS_ATTR(version, "0x%x\n");
+HV_CAPS_ATTR(ga, "%d\n");
+HV_CAPS_ATTR(expanded, "%d\n");
+HV_CAPS_ATTR(lab, "%d\n");
+HV_CAPS_ATTR(collect_privileged, "%d\n");
+
+static struct attribute *interface_attrs[] = {
+ &dev_attr_kernel_version.attr,
+ &hv_caps_attr_version.attr,
+ &hv_caps_attr_ga.attr,
+ &hv_caps_attr_expanded.attr,
+ &hv_caps_attr_lab.attr,
+ &hv_caps_attr_collect_privileged.attr,
+ NULL,
+};
+
+static struct attribute_group interface_group = {
+ .name = "interface",
+ .attrs = interface_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+ &format_group,
+ &interface_group,
+ NULL,
+};
+
+#define GPCI_MAX_DATA_BYTES \
+ (1024 - sizeof(struct hv_get_perf_counter_info_params))
+
+static unsigned long single_gpci_request(u32 req, u32 starting_index,
+ u16 secondary_index, u8 version_in, u32 offset, u8 length,
+ u64 *value)
+{
+ unsigned long ret;
+ size_t i;
+ u64 count;
+
+ struct {
+ struct hv_get_perf_counter_info_params params;
+ uint8_t bytes[GPCI_MAX_DATA_BYTES];
+ } __packed __aligned(sizeof(uint64_t)) arg = {
+ .params = {
+ .counter_request = cpu_to_be32(req),
+ .starting_index = cpu_to_be32(starting_index),
+ .secondary_index = cpu_to_be16(secondary_index),
+ .counter_info_version_in = version_in,
+ }
+ };
+
+ ret = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO,
+ virt_to_phys(&arg), sizeof(arg));
+ if (ret) {
+ pr_devel("hcall failed: 0x%lx\n", ret);
+ return ret;
+ }
+
+ /*
+ * we verify offset and length are within the zeroed buffer at event
+ * init.
+ */
+ count = 0;
+ for (i = offset; i < offset + length; i++)
+ count |= arg.bytes[i] << (i - offset);
+
+ *value = count;
+ return ret;
+}
+
+static u64 h_gpci_get_value(struct perf_event *event)
+{
+ u64 count;
+ unsigned long ret = single_gpci_request(event_get_request(event),
+ event_get_starting_index(event),
+ event_get_secondary_index(event),
+ event_get_counter_info_version(event),
+ event_get_offset(event),
+ event_get_length(event),
+ &count);
+ if (ret)
+ return 0;
+ return count;
+}
+
+static void h_gpci_event_update(struct perf_event *event)
+{
+ s64 prev;
+ u64 now = h_gpci_get_value(event);
+ prev = local64_xchg(&event->hw.prev_count, now);
+ local64_add(now - prev, &event->count);
+}
+
+static void h_gpci_event_start(struct perf_event *event, int flags)
+{
+ local64_set(&event->hw.prev_count, h_gpci_get_value(event));
+}
+
+static void h_gpci_event_stop(struct perf_event *event, int flags)
+{
+ h_gpci_event_update(event);
+}
+
+static int h_gpci_event_add(struct perf_event *event, int flags)
+{
+ if (flags & PERF_EF_START)
+ h_gpci_event_start(event, flags);
+
+ return 0;
+}
+
+static int h_gpci_event_init(struct perf_event *event)
+{
+ u64 count;
+ u8 length;
+
+ /* Not our event */
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ /* config2 is unused */
+ if (event->attr.config2) {
+ pr_devel("config2 set when reserved\n");
+ return -EINVAL;
+ }
+
+ /* unsupported modes and filters */
+ if (event->attr.exclude_user ||
+ event->attr.exclude_kernel ||
+ event->attr.exclude_hv ||
+ event->attr.exclude_idle ||
+ event->attr.exclude_host ||
+ event->attr.exclude_guest ||
+ is_sampling_event(event)) /* no sampling */
+ return -EINVAL;
+
+ /* no branch sampling */
+ if (has_branch_stack(event))
+ return -EOPNOTSUPP;
+
+ length = event_get_length(event);
+ if (length < 1 || length > 8) {
+ pr_devel("length invalid\n");
+ return -EINVAL;
+ }
+
+ /* last byte within the buffer? */
+ if ((event_get_offset(event) + length) > GPCI_MAX_DATA_BYTES) {
+ pr_devel("request outside of buffer: %zu > %zu\n",
+ (size_t)event_get_offset(event) + length,
+ GPCI_MAX_DATA_BYTES);
+ return -EINVAL;
+ }
+
+ /* check if the request works... */
+ if (single_gpci_request(event_get_request(event),
+ event_get_starting_index(event),
+ event_get_secondary_index(event),
+ event_get_counter_info_version(event),
+ event_get_offset(event),
+ length,
+ &count)) {
+ pr_devel("gpci hcall failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int h_gpci_event_idx(struct perf_event *event)
+{
+ return 0;
+}
+
+static struct pmu h_gpci_pmu = {
+ .task_ctx_nr = perf_invalid_context,
+
+ .name = "hv_gpci",
+ .attr_groups = attr_groups,
+ .event_init = h_gpci_event_init,
+ .add = h_gpci_event_add,
+ .del = h_gpci_event_stop,
+ .start = h_gpci_event_start,
+ .stop = h_gpci_event_stop,
+ .read = h_gpci_event_update,
+ .event_idx = h_gpci_event_idx,
+};
+
+static int hv_gpci_init(void)
+{
+ int r;
+ unsigned long hret;
+ struct hv_perf_caps caps;
+
+ if (!firmware_has_feature(FW_FEATURE_LPAR)) {
+ pr_info("not a virtualized system, not enabling\n");
+ return -ENODEV;
+ }
+
+ hret = hv_perf_caps_get(&caps);
+ if (hret) {
+ pr_info("could not obtain capabilities, error 0x%80lx, not enabling\n",
+ hret);
+ return -ENODEV;
+ }
+
+ r = perf_pmu_register(&h_gpci_pmu, h_gpci_pmu.name, -1);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+device_initcall(hv_gpci_init);
diff --git a/arch/powerpc/perf/hv-gpci.h b/arch/powerpc/perf/hv-gpci.h
new file mode 100644
index 000000000000..b25f460c9cce
--- /dev/null
+++ b/arch/powerpc/perf/hv-gpci.h
@@ -0,0 +1,73 @@
+#ifndef LINUX_POWERPC_PERF_HV_GPCI_H_
+#define LINUX_POWERPC_PERF_HV_GPCI_H_
+
+#include <linux/types.h>
+
+/* From the document "H_GetPerformanceCounterInfo Interface" v1.07 */
+
+/* H_GET_PERF_COUNTER_INFO argument */
+struct hv_get_perf_counter_info_params {
+ __be32 counter_request; /* I */
+ __be32 starting_index; /* IO */
+ __be16 secondary_index; /* IO */
+ __be16 returned_values; /* O */
+ __be32 detail_rc; /* O, only needed when called via *_norets() */
+
+ /*
+ * O, size each of counter_value element in bytes, only set for version
+ * >= 0x3
+ */
+ __be16 cv_element_size;
+
+ /* I, 0 (zero) for versions < 0x3 */
+ __u8 counter_info_version_in;
+
+ /* O, 0 (zero) if version < 0x3. Must be set to 0 when making hcall */
+ __u8 counter_info_version_out;
+ __u8 reserved[0xC];
+ __u8 counter_value[];
+} __packed;
+
+/*
+ * counter info version => fw version/reference (spec version)
+ *
+ * 8 => power8 (1.07)
+ * [7 is skipped by spec 1.07]
+ * 6 => TLBIE (1.07)
+ * 5 => v7r7m0.phyp (1.05)
+ * [4 skipped]
+ * 3 => v7r6m0.phyp (?)
+ * [1,2 skipped]
+ * 0 => v7r{2,3,4}m0.phyp (?)
+ */
+#define COUNTER_INFO_VERSION_CURRENT 0x8
+
+/*
+ * These determine the counter_value[] layout and the meaning of starting_index
+ * and secondary_index.
+ *
+ * Unless otherwise noted, @secondary_index is unused and ignored.
+ */
+enum counter_info_requests {
+
+ /* GENERAL */
+
+ /* @starting_index: must be -1 (to refer to the current partition)
+ */
+ CIR_SYSTEM_PERFORMANCE_CAPABILITIES = 0X40,
+};
+
+struct cv_system_performance_capabilities {
+ /* If != 0, allowed to collect data from other partitions */
+ __u8 perf_collect_privileged;
+
+ /* These following are only valid if counter_info_version >= 0x3 */
+#define CV_CM_GA (1 << 7)
+#define CV_CM_EXPANDED (1 << 6)
+#define CV_CM_LAB (1 << 5)
+ /* remaining bits are reserved */
+ __u8 capability_mask;
+ __u8 reserved[0xE];
+} __packed;
+
+#endif
diff --git a/arch/powerpc/perf/power7-events-list.h b/arch/powerpc/perf/power7-events-list.h
index 687790a2c0b8..64f13d9260a6 100644
--- a/arch/powerpc/perf/power7-events-list.h
+++ b/arch/powerpc/perf/power7-events-list.h
@@ -546,3 +546,13 @@ EVENT(PM_MRK_DATA_FROM_RL2L3_SHR, 0x1d04c)
EVENT(PM_DTLB_MISS_16M, 0x4c05e)
EVENT(PM_LSU1_LMQ_LHR_MERGE, 0x0d09a)
EVENT(PM_IFU_FIN, 0x40066)
+EVENT(PM_1THRD_CON_RUN_INSTR, 0x30062)
+EVENT(PM_CMPLU_STALL_COUNT, 0x4000B)
+EVENT(PM_MEM0_PB_RD_CL, 0x30083)
+EVENT(PM_THRD_1_RUN_CYC, 0x10060)
+EVENT(PM_THRD_2_CONC_RUN_INSTR, 0x40062)
+EVENT(PM_THRD_2_RUN_CYC, 0x20060)
+EVENT(PM_THRD_3_CONC_RUN_INST, 0x10062)
+EVENT(PM_THRD_3_RUN_CYC, 0x30060)
+EVENT(PM_THRD_4_CONC_RUN_INST, 0x20062)
+EVENT(PM_THRD_4_RUN_CYC, 0x40060)
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index 96cee20dcd34..fe2763b6e039 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -10,6 +10,8 @@
* 2 of the License, or (at your option) any later version.
*/
+#define pr_fmt(fmt) "power8-pmu: " fmt
+
#include <linux/kernel.h>
#include <linux/perf_event.h>
#include <asm/firmware.h>
@@ -62,9 +64,11 @@
*
* 60 56 52 48 44 40 36 32
* | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
- * | [ thresh_cmp ] [ thresh_ctl ]
- * | |
- * *- EBB (Linux) thresh start/stop OR FAB match -*
+ * | | [ ] [ thresh_cmp ] [ thresh_ctl ]
+ * | | | |
+ * | | *- IFM (Linux) thresh start/stop OR FAB match -*
+ * | *- BHRB (Linux)
+ * *- EBB (Linux)
*
* 28 24 20 16 12 8 4 0
* | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
@@ -114,9 +118,18 @@
* MMCRA[57:59] = sample[0:2] (RAND_SAMP_ELIG)
 * MMCRA[61:62] = sample[3:4] (RAND_SAMP_MODE)
*
+ * if EBB and BHRB:
+ * MMCRA[32:33] = IFM
+ *
*/
#define EVENT_EBB_MASK 1ull
+#define EVENT_EBB_SHIFT PERF_EVENT_CONFIG_EBB_SHIFT
+#define EVENT_BHRB_MASK 1ull
+#define EVENT_BHRB_SHIFT 62
+#define EVENT_WANTS_BHRB (EVENT_BHRB_MASK << EVENT_BHRB_SHIFT)
+#define EVENT_IFM_MASK 3ull
+#define EVENT_IFM_SHIFT 60
#define EVENT_THR_CMP_SHIFT 40 /* Threshold CMP value */
#define EVENT_THR_CMP_MASK 0x3ff
#define EVENT_THR_CTL_SHIFT 32 /* Threshold control value (start/stop) */
@@ -141,6 +154,12 @@
#define EVENT_IS_MARKED (EVENT_MARKED_MASK << EVENT_MARKED_SHIFT)
#define EVENT_PSEL_MASK 0xff /* PMCxSEL value */
+/* Bits defined by Linux */
+#define EVENT_LINUX_MASK \
+ ((EVENT_EBB_MASK << EVENT_EBB_SHIFT) | \
+ (EVENT_BHRB_MASK << EVENT_BHRB_SHIFT) | \
+ (EVENT_IFM_MASK << EVENT_IFM_SHIFT))
+
#define EVENT_VALID_MASK \
((EVENT_THRESH_MASK << EVENT_THRESH_SHIFT) | \
(EVENT_SAMPLE_MASK << EVENT_SAMPLE_SHIFT) | \
@@ -149,7 +168,7 @@
(EVENT_UNIT_MASK << EVENT_UNIT_SHIFT) | \
(EVENT_COMBINE_MASK << EVENT_COMBINE_SHIFT) | \
(EVENT_MARKED_MASK << EVENT_MARKED_SHIFT) | \
- (EVENT_EBB_MASK << PERF_EVENT_CONFIG_EBB_SHIFT) | \
+ EVENT_LINUX_MASK | \
EVENT_PSEL_MASK)
/* MMCRA IFM bits - POWER8 */
@@ -173,10 +192,11 @@
*
* 28 24 20 16 12 8 4 0
* | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
- * | [ ] [ sample ] [ ] [6] [5] [4] [3] [2] [1]
- * EBB -* | |
- * | | Count of events for each PMC.
- * L1 I/D qualifier -* | p1, p2, p3, p4, p5, p6.
+ * [ ] | [ ] [ sample ] [ ] [6] [5] [4] [3] [2] [1]
+ * | | | |
+ * BHRB IFM -* | | | Count of events for each PMC.
+ * EBB -* | | p1, p2, p3, p4, p5, p6.
+ * L1 I/D qualifier -* |
* nc - number of counters -*
*
* The PMC fields P1..P6, and NC, are adder fields. As we accumulate constraints
@@ -195,6 +215,9 @@
#define CNST_EBB_VAL(v) (((v) & EVENT_EBB_MASK) << 24)
#define CNST_EBB_MASK CNST_EBB_VAL(EVENT_EBB_MASK)
+#define CNST_IFM_VAL(v) (((v) & EVENT_IFM_MASK) << 25)
+#define CNST_IFM_MASK CNST_IFM_VAL(EVENT_IFM_MASK)
+
#define CNST_L1_QUAL_VAL(v) (((v) & 3) << 22)
#define CNST_L1_QUAL_MASK CNST_L1_QUAL_VAL(3)
@@ -241,6 +264,7 @@
#define MMCRA_THR_SEL_SHIFT 16
#define MMCRA_THR_CMP_SHIFT 32
#define MMCRA_SDAR_MODE_TLB (1ull << 42)
+#define MMCRA_IFM_SHIFT 30
static inline bool event_is_fab_match(u64 event)
@@ -265,20 +289,22 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long
pmc = (event >> EVENT_PMC_SHIFT) & EVENT_PMC_MASK;
unit = (event >> EVENT_UNIT_SHIFT) & EVENT_UNIT_MASK;
cache = (event >> EVENT_CACHE_SEL_SHIFT) & EVENT_CACHE_SEL_MASK;
- ebb = (event >> PERF_EVENT_CONFIG_EBB_SHIFT) & EVENT_EBB_MASK;
-
- /* Clear the EBB bit in the event, so event checks work below */
- event &= ~(EVENT_EBB_MASK << PERF_EVENT_CONFIG_EBB_SHIFT);
+ ebb = (event >> EVENT_EBB_SHIFT) & EVENT_EBB_MASK;
if (pmc) {
+ u64 base_event;
+
if (pmc > 6)
return -1;
- mask |= CNST_PMC_MASK(pmc);
- value |= CNST_PMC_VAL(pmc);
+ /* Ignore Linux defined bits when checking event below */
+ base_event = event & ~EVENT_LINUX_MASK;
- if (pmc >= 5 && event != 0x500fa && event != 0x600f4)
+ if (pmc >= 5 && base_event != 0x500fa && base_event != 0x600f4)
return -1;
+
+ mask |= CNST_PMC_MASK(pmc);
+ value |= CNST_PMC_VAL(pmc);
}
if (pmc <= 4) {
@@ -299,9 +325,10 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long
* HV writable, and there is no API for guest kernels to modify
* it. The solution is for the hypervisor to initialise the
* field to zeroes, and for us to only ever allow events that
- * have a cache selector of zero.
+ * have a cache selector of zero. The bank selector (bit 3) is
+ * irrelevant, as long as the rest of the value is 0.
*/
- if (cache)
+ if (cache & 0x7)
return -1;
} else if (event & EVENT_IS_L1) {
@@ -342,6 +369,15 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long
/* EBB events must specify the PMC */
return -1;
+ if (event & EVENT_WANTS_BHRB) {
+ if (!ebb)
+ /* Only EBB events can request BHRB */
+ return -1;
+
+ mask |= CNST_IFM_MASK;
+ value |= CNST_IFM_VAL(event >> EVENT_IFM_SHIFT);
+ }
+
/*
* All events must agree on EBB, either all request it or none.
* EBB events are pinned & exclusive, so this should never actually
@@ -431,6 +467,11 @@ static int power8_compute_mmcr(u64 event[], int n_ev,
mmcra |= val << MMCRA_THR_CMP_SHIFT;
}
+ if (event[i] & EVENT_WANTS_BHRB) {
+ val = (event[i] >> EVENT_IFM_SHIFT) & EVENT_IFM_MASK;
+ mmcra |= val << MMCRA_IFM_SHIFT;
+ }
+
hwc[i] = pmc - 1;
}
@@ -774,6 +815,9 @@ static int __init init_power8_pmu(void)
/* Tell userspace that EBB is supported */
cur_cpu_spec->cpu_user_features2 |= PPC_FEATURE2_EBB;
+ if (cpu_has_feature(CPU_FTR_PMAO_BUG))
+ pr_info("PMAO restore workaround active.\n");
+
return 0;
}
early_initcall(init_power8_pmu);
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index d6c7506ec7d9..dc1a264ec6e6 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -265,7 +265,6 @@ config 440EP
select PPC_FPU
select IBM440EP_ERR42
select IBM_EMAC_ZMII
- select USB_ARCH_HAS_OHCI
config 440EPX
bool
diff --git a/arch/powerpc/platforms/85xx/c293pcie.c b/arch/powerpc/platforms/85xx/c293pcie.c
index 213d5b815827..84476b646005 100644
--- a/arch/powerpc/platforms/85xx/c293pcie.c
+++ b/arch/powerpc/platforms/85xx/c293pcie.c
@@ -68,6 +68,7 @@ define_machine(c293_pcie) {
.init_IRQ = c293_pcie_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c
index 3b085c7ee539..b564b5e23f7c 100644
--- a/arch/powerpc/platforms/85xx/common.c
+++ b/arch/powerpc/platforms/85xx/common.c
@@ -107,6 +107,12 @@ void __init mpc85xx_qe_init(void)
qe_reset();
of_node_put(np);
+}
+
+void __init mpc85xx_qe_par_io_init(void)
+{
+ struct device_node *np;
+
np = of_find_node_by_name(NULL, "par_io");
if (np) {
struct device_node *ucc;
diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
index fbd871e69754..8e4b1e1a4911 100644
--- a/arch/powerpc/platforms/85xx/corenet_generic.c
+++ b/arch/powerpc/platforms/85xx/corenet_generic.c
@@ -26,11 +26,13 @@
#include <asm/udbg.h>
#include <asm/mpic.h>
#include <asm/ehv_pic.h>
+#include <asm/qe_ic.h>
#include <linux/of_platform.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#include "smp.h"
+#include "mpc85xx.h"
void __init corenet_gen_pic_init(void)
{
@@ -38,6 +40,8 @@ void __init corenet_gen_pic_init(void)
unsigned int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU |
MPIC_NO_RESET;
+ struct device_node *np;
+
if (ppc_md.get_irq == mpic_get_coreint_irq)
flags |= MPIC_ENABLE_COREINT;
@@ -45,6 +49,13 @@ void __init corenet_gen_pic_init(void)
BUG_ON(mpic == NULL);
mpic_init(mpic);
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
+ if (np) {
+ qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
+ qe_ic_cascade_high_mpic);
+ of_node_put(np);
+ }
}
/*
@@ -57,6 +68,8 @@ void __init corenet_gen_setup_arch(void)
swiotlb_detect_4g();
pr_info("%s board from Freescale Semiconductor\n", ppc_md.name);
+
+ mpc85xx_qe_init();
}
static const struct of_device_id of_device_ids[] = {
@@ -81,6 +94,9 @@ static const struct of_device_id of_device_ids[] = {
{
.compatible = "fsl,qoriq-pcie-v3.0",
},
+ {
+ .compatible = "fsl,qe",
+ },
/* The following two are for the Freescale hypervisor */
{
.name = "hypervisor",
@@ -163,6 +179,7 @@ define_machine(corenet_generic) {
.init_IRQ = corenet_gen_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_coreint_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/ge_imp3a.c b/arch/powerpc/platforms/85xx/ge_imp3a.c
index e6285ae6f423..11790e074c8a 100644
--- a/arch/powerpc/platforms/85xx/ge_imp3a.c
+++ b/arch/powerpc/platforms/85xx/ge_imp3a.c
@@ -215,6 +215,7 @@ define_machine(ge_imp3a) {
.show_cpuinfo = ge_imp3a_show_cpuinfo,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c
index 15ce4b55f117..a378ba3519e9 100644
--- a/arch/powerpc/platforms/85xx/mpc8536_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c
@@ -76,6 +76,7 @@ define_machine(mpc8536_ds) {
.init_IRQ = mpc8536_ds_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h
index fc51dd4092e5..39056f6befeb 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx.h
+++ b/arch/powerpc/platforms/85xx/mpc85xx.h
@@ -10,8 +10,10 @@ static inline void __init mpc85xx_cpm2_pic_init(void) {}
#ifdef CONFIG_QUICC_ENGINE
extern void mpc85xx_qe_init(void);
+extern void mpc85xx_qe_par_io_init(void);
#else
static inline void __init mpc85xx_qe_init(void) {}
+static inline void __init mpc85xx_qe_par_io_init(void) {}
#endif
#endif
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index 7a31a0e1df29..b0753e222086 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -385,6 +385,7 @@ define_machine(mpc85xx_cds) {
#ifdef CONFIG_PCI
.restart = mpc85xx_cds_restart,
.pcibios_fixup_bus = mpc85xx_cds_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#else
.restart = fsl_rstcr_restart,
#endif
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
index 9ebb91ed96a3..ffdf02121a7c 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
@@ -209,6 +209,7 @@ define_machine(mpc8544_ds) {
.init_IRQ = mpc85xx_ds_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -223,6 +224,7 @@ define_machine(mpc8572_ds) {
.init_IRQ = mpc85xx_ds_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -237,6 +239,7 @@ define_machine(p2020_ds) {
.init_IRQ = mpc85xx_ds_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 34f3c5eb3bee..a392e94a07fa 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -239,6 +239,7 @@ static void __init mpc85xx_mds_qe_init(void)
struct device_node *np;
mpc85xx_qe_init();
+ mpc85xx_qe_par_io_init();
mpc85xx_mds_reset_ucc_phys();
if (machine_is(p1021_mds)) {
@@ -391,6 +392,7 @@ define_machine(mpc8568_mds) {
.progress = udbg_progress,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
};
@@ -412,6 +414,7 @@ define_machine(mpc8569_mds) {
.progress = udbg_progress,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
};
@@ -434,6 +437,7 @@ define_machine(p1021_mds) {
.progress = udbg_progress,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
};
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
index e15bdd18fdb2..e358bed66d01 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
@@ -86,10 +86,6 @@ void __init mpc85xx_rdb_pic_init(void)
*/
static void __init mpc85xx_rdb_setup_arch(void)
{
-#ifdef CONFIG_QUICC_ENGINE
- struct device_node *np;
-#endif
-
if (ppc_md.progress)
ppc_md.progress("mpc85xx_rdb_setup_arch()", 0);
@@ -99,8 +95,10 @@ static void __init mpc85xx_rdb_setup_arch(void)
#ifdef CONFIG_QUICC_ENGINE
mpc85xx_qe_init();
+ mpc85xx_qe_par_io_init();
#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE)
if (machine_is(p1025_rdb)) {
+ struct device_node *np;
struct ccsr_guts __iomem *guts;
@@ -233,6 +231,7 @@ define_machine(p2020_rdb) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -247,6 +246,7 @@ define_machine(p1020_rdb) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -261,6 +261,7 @@ define_machine(p1021_rdb_pc) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -275,6 +276,7 @@ define_machine(p2020_rdb_pc) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -289,6 +291,7 @@ define_machine(p1025_rdb) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -303,6 +306,7 @@ define_machine(p1020_mbg_pc) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -317,6 +321,7 @@ define_machine(p1020_utm_pc) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -331,6 +336,7 @@ define_machine(p1020_rdb_pc) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -345,6 +351,7 @@ define_machine(p1020_rdb_pd) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -359,6 +366,7 @@ define_machine(p1024_rdb) {
.init_IRQ = mpc85xx_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/p1010rdb.c b/arch/powerpc/platforms/85xx/p1010rdb.c
index d6a3dd311494..ad1a3d438a9e 100644
--- a/arch/powerpc/platforms/85xx/p1010rdb.c
+++ b/arch/powerpc/platforms/85xx/p1010rdb.c
@@ -78,6 +78,7 @@ define_machine(p1010_rdb) {
.init_IRQ = p1010_rdb_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c
index e611e79f23ce..6ac986d3f8a3 100644
--- a/arch/powerpc/platforms/85xx/p1022_ds.c
+++ b/arch/powerpc/platforms/85xx/p1022_ds.c
@@ -567,6 +567,7 @@ define_machine(p1022_ds) {
.init_IRQ = p1022_ds_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/p1022_rdk.c b/arch/powerpc/platforms/85xx/p1022_rdk.c
index 8c9297112b30..7a180f0308d5 100644
--- a/arch/powerpc/platforms/85xx/p1022_rdk.c
+++ b/arch/powerpc/platforms/85xx/p1022_rdk.c
@@ -147,6 +147,7 @@ define_machine(p1022_rdk) {
.init_IRQ = p1022_rdk_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/p1023_rds.c b/arch/powerpc/platforms/85xx/p1023_rds.c
index 2ae9d490c3d9..0e614007acfb 100644
--- a/arch/powerpc/platforms/85xx/p1023_rds.c
+++ b/arch/powerpc/platforms/85xx/p1023_rds.c
@@ -126,6 +126,7 @@ define_machine(p1023_rds) {
.progress = udbg_progress,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
};
@@ -140,5 +141,6 @@ define_machine(p1023_rdb) {
.progress = udbg_progress,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
};
diff --git a/arch/powerpc/platforms/85xx/qemu_e500.c b/arch/powerpc/platforms/85xx/qemu_e500.c
index 5cefc5a9a144..7f2673293549 100644
--- a/arch/powerpc/platforms/85xx/qemu_e500.c
+++ b/arch/powerpc/platforms/85xx/qemu_e500.c
@@ -66,6 +66,7 @@ define_machine(qemu_e500) {
.init_IRQ = qemu_e500_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_coreint_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/85xx/sbc8548.c b/arch/powerpc/platforms/85xx/sbc8548.c
index f62121825914..b07214666d65 100644
--- a/arch/powerpc/platforms/85xx/sbc8548.c
+++ b/arch/powerpc/platforms/85xx/sbc8548.c
@@ -135,6 +135,7 @@ define_machine(sbc8548) {
.restart = fsl_rstcr_restart,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
diff --git a/arch/powerpc/platforms/85xx/twr_p102x.c b/arch/powerpc/platforms/85xx/twr_p102x.c
index c25ff10f05ee..1eadb6d0dc64 100644
--- a/arch/powerpc/platforms/85xx/twr_p102x.c
+++ b/arch/powerpc/platforms/85xx/twr_p102x.c
@@ -77,6 +77,7 @@ static void __init twr_p1025_setup_arch(void)
#ifdef CONFIG_QUICC_ENGINE
mpc85xx_qe_init();
+ mpc85xx_qe_par_io_init();
#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE)
if (machine_is(twr_p1025)) {
diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c
index dcbf7e42dce7..1a9c1085855f 100644
--- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c
+++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c
@@ -170,6 +170,7 @@ define_machine(xes_mpc8572) {
.init_IRQ = xes_mpc85xx_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -184,6 +185,7 @@ define_machine(xes_mpc8548) {
.init_IRQ = xes_mpc85xx_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
@@ -198,6 +200,7 @@ define_machine(xes_mpc8540) {
.init_IRQ = xes_mpc85xx_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+ .pcibios_fixup_phb = fsl_pcibios_fixup_phb,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 2d42f3bb66d6..8a106b4172e0 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -215,7 +215,7 @@ void iic_request_IPIs(void)
{
iic_request_ipi(PPC_MSG_CALL_FUNCTION);
iic_request_ipi(PPC_MSG_RESCHEDULE);
- iic_request_ipi(PPC_MSG_CALL_FUNC_SINGLE);
+ iic_request_ipi(PPC_MSG_TICK_BROADCAST);
iic_request_ipi(PPC_MSG_DEBUGGER_BREAK);
}
diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c
index 5ec1e47a0d77..e865d748179b 100644
--- a/arch/powerpc/platforms/cell/ras.c
+++ b/arch/powerpc/platforms/cell/ras.c
@@ -123,7 +123,8 @@ static int __init cbe_ptcal_enable_on_node(int nid, int order)
area->nid = nid;
area->order = order;
- area->pages = alloc_pages_exact_node(area->nid, GFP_KERNEL|GFP_THISNODE,
+ area->pages = alloc_pages_exact_node(area->nid,
+ GFP_KERNEL|__GFP_THISNODE,
area->order);
if (!area->pages) {
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 49318385d4fa..4a0a64fe25df 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -83,7 +83,6 @@ static struct timer_list spuloadavg_timer;
#define MIN_SPU_TIMESLICE max(5 * HZ / (1000 * SPUSCHED_TICK), 1)
#define DEF_SPU_TIMESLICE (100 * HZ / (1000 * SPUSCHED_TICK))
-#define MAX_USER_PRIO (MAX_PRIO - MAX_RT_PRIO)
#define SCALE_PRIO(x, prio) \
max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_SPU_TIMESLICE)
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index 6d3c7a9fd047..2a7024d8d8b1 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -34,7 +34,6 @@ config MPC7448HPC2
select TSI108_BRIDGE
select DEFAULT_UIMAGE
select PPC_UDBG_16550
- select TSI108_BRIDGE
help
Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga)
platform
@@ -44,19 +43,10 @@ config PPC_HOLLY
depends on EMBEDDED6xx
select TSI108_BRIDGE
select PPC_UDBG_16550
- select TSI108_BRIDGE
help
Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval
Board with TSI108/9 bridge (Hickory/Holly)
-config PPC_PRPMC2800
- bool "Motorola-PrPMC2800"
- depends on EMBEDDED6xx
- select MV64X60
- select NOT_COHERENT_CACHE
- help
- This option enables support for the Motorola PrPMC2800 board
-
config PPC_C2K
bool "SBS/GEFanuc C2K board"
depends on EMBEDDED6xx
diff --git a/arch/powerpc/platforms/embedded6xx/Makefile b/arch/powerpc/platforms/embedded6xx/Makefile
index cdd48d402b93..f126a2a09981 100644
--- a/arch/powerpc/platforms/embedded6xx/Makefile
+++ b/arch/powerpc/platforms/embedded6xx/Makefile
@@ -5,7 +5,6 @@ obj-$(CONFIG_MPC7448HPC2) += mpc7448_hpc2.o
obj-$(CONFIG_LINKSTATION) += linkstation.o ls_uart.o
obj-$(CONFIG_STORCENTER) += storcenter.o
obj-$(CONFIG_PPC_HOLLY) += holly.o
-obj-$(CONFIG_PPC_PRPMC2800) += prpmc2800.o
obj-$(CONFIG_PPC_C2K) += c2k.o
obj-$(CONFIG_USBGECKO_UDBG) += usbgecko_udbg.o
obj-$(CONFIG_GAMECUBE_COMMON) += flipper-pic.o
diff --git a/arch/powerpc/platforms/embedded6xx/prpmc2800.c b/arch/powerpc/platforms/embedded6xx/prpmc2800.c
deleted file mode 100644
index d455f08bea53..000000000000
--- a/arch/powerpc/platforms/embedded6xx/prpmc2800.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Board setup routines for the Motorola PrPMC2800
- *
- * Author: Dale Farnsworth <dale@farnsworth.org>
- *
- * 2007 (c) MontaVista, Software, 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.
- */
-
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/seq_file.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/time.h>
-
-#include <mm/mmu_decl.h>
-
-#include <sysdev/mv64x60.h>
-
-#define MV64x60_MPP_CNTL_0 0x0000
-#define MV64x60_MPP_CNTL_2 0x0008
-
-#define MV64x60_GPP_IO_CNTL 0x0000
-#define MV64x60_GPP_LEVEL_CNTL 0x0010
-#define MV64x60_GPP_VALUE_SET 0x0018
-
-#define PLATFORM_NAME_MAX 32
-
-static char prpmc2800_platform_name[PLATFORM_NAME_MAX];
-
-static void __iomem *mv64x60_mpp_reg_base;
-static void __iomem *mv64x60_gpp_reg_base;
-
-static void __init prpmc2800_setup_arch(void)
-{
- struct device_node *np;
- phys_addr_t paddr;
- const unsigned int *reg;
-
- /*
- * ioremap mpp and gpp registers in case they are later
- * needed by prpmc2800_reset_board().
- */
- np = of_find_compatible_node(NULL, NULL, "marvell,mv64360-mpp");
- reg = of_get_property(np, "reg", NULL);
- paddr = of_translate_address(np, reg);
- of_node_put(np);
- mv64x60_mpp_reg_base = ioremap(paddr, reg[1]);
-
- np = of_find_compatible_node(NULL, NULL, "marvell,mv64360-gpp");
- reg = of_get_property(np, "reg", NULL);
- paddr = of_translate_address(np, reg);
- of_node_put(np);
- mv64x60_gpp_reg_base = ioremap(paddr, reg[1]);
-
-#ifdef CONFIG_PCI
- mv64x60_pci_init();
-#endif
-
- printk("Motorola %s\n", prpmc2800_platform_name);
-}
-
-static void prpmc2800_reset_board(void)
-{
- u32 temp;
-
- local_irq_disable();
-
- temp = in_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_0);
- temp &= 0xFFFF0FFF;
- out_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_0, temp);
-
- temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL);
- temp |= 0x00000004;
- out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL, temp);
-
- temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL);
- temp |= 0x00000004;
- out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL, temp);
-
- temp = in_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_2);
- temp &= 0xFFFF0FFF;
- out_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_2, temp);
-
- temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL);
- temp |= 0x00080000;
- out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL, temp);
-
- temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL);
- temp |= 0x00080000;
- out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL, temp);
-
- out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_VALUE_SET, 0x00080004);
-}
-
-static void prpmc2800_restart(char *cmd)
-{
- volatile ulong i = 10000000;
-
- prpmc2800_reset_board();
-
- while (i-- > 0);
- panic("restart failed\n");
-}
-
-#ifdef CONFIG_NOT_COHERENT_CACHE
-#define PPRPM2800_COHERENCY_SETTING "off"
-#else
-#define PPRPM2800_COHERENCY_SETTING "on"
-#endif
-
-void prpmc2800_show_cpuinfo(struct seq_file *m)
-{
- seq_printf(m, "Vendor\t\t: Motorola\n");
- seq_printf(m, "coherency\t: %s\n", PPRPM2800_COHERENCY_SETTING);
-}
-
-/*
- * Called very early, device-tree isn't unflattened
- */
-static int __init prpmc2800_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
- unsigned long len = PLATFORM_NAME_MAX;
- void *m;
-
- if (!of_flat_dt_is_compatible(root, "motorola,PrPMC2800"))
- return 0;
-
- /* Update ppc_md.name with name from dt */
- m = of_get_flat_dt_prop(root, "model", &len);
- if (m)
- strncpy(prpmc2800_platform_name, m,
- min((int)len, PLATFORM_NAME_MAX - 1));
-
- _set_L2CR(_get_L2CR() | L2CR_L2E);
- return 1;
-}
-
-define_machine(prpmc2800){
- .name = prpmc2800_platform_name,
- .probe = prpmc2800_probe,
- .setup_arch = prpmc2800_setup_arch,
- .init_early = mv64x60_init_early,
- .show_cpuinfo = prpmc2800_show_cpuinfo,
- .init_IRQ = mv64x60_init_irq,
- .get_irq = mv64x60_get_irq,
- .restart = prpmc2800_restart,
- .calibrate_decr = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index 8d767fde5a6a..f324ea099503 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -1,6 +1,6 @@
-obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o
+obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o opal-async.o
obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
-obj-y += rng.o
+obj-y += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index e1e71618b70c..253fefe3d1a0 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -44,7 +44,8 @@ static int ioda_eeh_event(struct notifier_block *nb,
/* We simply send special EEH event */
if ((changed_evts & OPAL_EVENT_PCI_ERROR) &&
- (events & OPAL_EVENT_PCI_ERROR))
+ (events & OPAL_EVENT_PCI_ERROR) &&
+ eeh_enabled())
eeh_send_failure_event(NULL);
return 0;
@@ -113,6 +114,7 @@ DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_inbB_dbgfs_ops, ioda_eeh_inbB_dbgfs_get,
ioda_eeh_inbB_dbgfs_set, "0x%llx\n");
#endif /* CONFIG_DEBUG_FS */
+
/**
* ioda_eeh_post_init - Chip dependent post initialization
* @hose: PCI controller
@@ -220,6 +222,22 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
return ret;
}
+static void ioda_eeh_phb_diag(struct pci_controller *hose)
+{
+ struct pnv_phb *phb = hose->private_data;
+ long rc;
+
+ rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
+ PNV_PCI_DIAG_BUF_SIZE);
+ if (rc != OPAL_SUCCESS) {
+ pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n",
+ __func__, hose->global_number, rc);
+ return;
+ }
+
+ pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
+}
+
/**
* ioda_eeh_get_state - Retrieve the state of PE
* @pe: EEH PE
@@ -271,6 +289,9 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
result |= EEH_STATE_DMA_ACTIVE;
result |= EEH_STATE_MMIO_ENABLED;
result |= EEH_STATE_DMA_ENABLED;
+ } else if (!(pe->state & EEH_PE_ISOLATED)) {
+ eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
+ ioda_eeh_phb_diag(hose);
}
return result;
@@ -314,6 +335,15 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
__func__, fstate, hose->global_number, pe_no);
}
+ /* Dump PHB diag-data for frozen PE */
+ if (result != EEH_STATE_NOT_SUPPORT &&
+ (result & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) !=
+ (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE) &&
+ !(pe->state & EEH_PE_ISOLATED)) {
+ eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
+ ioda_eeh_phb_diag(hose);
+ }
+
return result;
}
@@ -489,8 +519,7 @@ static int ioda_eeh_bridge_reset(struct pci_controller *hose,
static int ioda_eeh_reset(struct eeh_pe *pe, int option)
{
struct pci_controller *hose = pe->phb;
- struct eeh_dev *edev;
- struct pci_dev *dev;
+ struct pci_bus *bus;
int ret;
/*
@@ -519,73 +548,17 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option)
if (pe->type & EEH_PE_PHB) {
ret = ioda_eeh_phb_reset(hose, option);
} else {
- if (pe->type & EEH_PE_DEVICE) {
- /*
- * If it's device PE, we didn't refer to the parent
- * PCI bus yet. So we have to figure it out indirectly.
- */
- edev = list_first_entry(&pe->edevs,
- struct eeh_dev, list);
- dev = eeh_dev_to_pci_dev(edev);
- dev = dev->bus->self;
- } else {
- /*
- * If it's bus PE, the parent PCI bus is already there
- * and just pick it up.
- */
- dev = pe->bus->self;
- }
-
- /*
- * Do reset based on the fact that the direct upstream bridge
- * is root bridge (port) or not.
- */
- if (dev->bus->number == 0)
+ bus = eeh_pe_bus_get(pe);
+ if (pci_is_root_bus(bus))
ret = ioda_eeh_root_reset(hose, option);
else
- ret = ioda_eeh_bridge_reset(hose, dev, option);
+ ret = ioda_eeh_bridge_reset(hose, bus->self, option);
}
return ret;
}
/**
- * ioda_eeh_get_log - Retrieve error log
- * @pe: EEH PE
- * @severity: Severity level of the log
- * @drv_log: buffer to store the log
- * @len: space of the log buffer
- *
- * The function is used to retrieve error log from P7IOC.
- */
-static int ioda_eeh_get_log(struct eeh_pe *pe, int severity,
- char *drv_log, unsigned long len)
-{
- s64 ret;
- unsigned long flags;
- struct pci_controller *hose = pe->phb;
- struct pnv_phb *phb = hose->private_data;
-
- spin_lock_irqsave(&phb->lock, flags);
-
- ret = opal_pci_get_phb_diag_data2(phb->opal_id,
- phb->diag.blob, PNV_PCI_DIAG_BUF_SIZE);
- if (ret) {
- spin_unlock_irqrestore(&phb->lock, flags);
- pr_warning("%s: Can't get log for PHB#%x-PE#%x (%lld)\n",
- __func__, hose->global_number, pe->addr, ret);
- return -EIO;
- }
-
- /* The PHB diag-data is always indicative */
- pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
-
- spin_unlock_irqrestore(&phb->lock, flags);
-
- return 0;
-}
-
-/**
* ioda_eeh_configure_bridge - Configure the PCI bridges for the indicated PE
* @pe: EEH PE
*
@@ -666,22 +639,6 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose)
}
}
-static void ioda_eeh_phb_diag(struct pci_controller *hose)
-{
- struct pnv_phb *phb = hose->private_data;
- long rc;
-
- rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
- PNV_PCI_DIAG_BUF_SIZE);
- if (rc != OPAL_SUCCESS) {
- pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n",
- __func__, hose->global_number, rc);
- return;
- }
-
- pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
-}
-
static int ioda_eeh_get_phb_pe(struct pci_controller *hose,
struct eeh_pe **pe)
{
@@ -855,6 +812,20 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
}
/*
+ * EEH core will try recover from fenced PHB or
+ * frozen PE. In the time for frozen PE, EEH core
+ * enable IO path for that before collecting logs,
+ * but it ruins the site. So we have to dump the
+ * log in advance here.
+ */
+ if ((ret == EEH_NEXT_ERR_FROZEN_PE ||
+ ret == EEH_NEXT_ERR_FENCED_PHB) &&
+ !((*pe)->state & EEH_PE_ISOLATED)) {
+ eeh_pe_state_mark(*pe, EEH_PE_ISOLATED);
+ ioda_eeh_phb_diag(hose);
+ }
+
+ /*
* If we have no errors on the specific PHB or only
* informative error there, we continue poking it.
* Otherwise, we need actions to be taken by upper
@@ -872,7 +843,6 @@ struct pnv_eeh_ops ioda_eeh_ops = {
.set_option = ioda_eeh_set_option,
.get_state = ioda_eeh_get_state,
.reset = ioda_eeh_reset,
- .get_log = ioda_eeh_get_log,
.configure_bridge = ioda_eeh_configure_bridge,
.next_error = ioda_eeh_next_error
};
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
index a79fddc5e74e..a59788e83b8b 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -145,7 +145,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
* Enable EEH explicitly so that we will do EEH check
* while accessing I/O stuff
*/
- eeh_subsystem_enabled = 1;
+ eeh_set_enable(true);
/* Save memory bars */
eeh_save_bars(edev);
diff --git a/arch/powerpc/platforms/powernv/opal-async.c b/arch/powerpc/platforms/powernv/opal-async.c
new file mode 100644
index 000000000000..cd0c1354d404
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-async.c
@@ -0,0 +1,203 @@
+/*
+ * PowerNV OPAL asynchronous completion interfaces
+ *
+ * Copyright 2013 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.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/gfp.h>
+#include <linux/of.h>
+#include <asm/opal.h>
+
+#define N_ASYNC_COMPLETIONS 64
+
+static DECLARE_BITMAP(opal_async_complete_map, N_ASYNC_COMPLETIONS) = {~0UL};
+static DECLARE_BITMAP(opal_async_token_map, N_ASYNC_COMPLETIONS);
+static DECLARE_WAIT_QUEUE_HEAD(opal_async_wait);
+static DEFINE_SPINLOCK(opal_async_comp_lock);
+static struct semaphore opal_async_sem;
+static struct opal_msg *opal_async_responses;
+static unsigned int opal_max_async_tokens;
+
+int __opal_async_get_token(void)
+{
+ unsigned long flags;
+ int token;
+
+ spin_lock_irqsave(&opal_async_comp_lock, flags);
+ token = find_first_bit(opal_async_complete_map, opal_max_async_tokens);
+ if (token >= opal_max_async_tokens) {
+ token = -EBUSY;
+ goto out;
+ }
+
+ if (__test_and_set_bit(token, opal_async_token_map)) {
+ token = -EBUSY;
+ goto out;
+ }
+
+ __clear_bit(token, opal_async_complete_map);
+
+out:
+ spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+ return token;
+}
+
+int opal_async_get_token_interruptible(void)
+{
+ int token;
+
+ /* Wait until a token is available */
+ if (down_interruptible(&opal_async_sem))
+ return -ERESTARTSYS;
+
+ token = __opal_async_get_token();
+ if (token < 0)
+ up(&opal_async_sem);
+
+ return token;
+}
+
+int __opal_async_release_token(int token)
+{
+ unsigned long flags;
+
+ if (token < 0 || token >= opal_max_async_tokens) {
+ pr_err("%s: Passed token is out of range, token %d\n",
+ __func__, token);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&opal_async_comp_lock, flags);
+ __set_bit(token, opal_async_complete_map);
+ __clear_bit(token, opal_async_token_map);
+ spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+
+ return 0;
+}
+
+int opal_async_release_token(int token)
+{
+ int ret;
+
+ ret = __opal_async_release_token(token);
+ if (ret)
+ return ret;
+
+ up(&opal_async_sem);
+
+ return 0;
+}
+
+int opal_async_wait_response(uint64_t token, struct opal_msg *msg)
+{
+ if (token >= opal_max_async_tokens) {
+ pr_err("%s: Invalid token passed\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!msg) {
+ pr_err("%s: Invalid message pointer passed\n", __func__);
+ return -EINVAL;
+ }
+
+ wait_event(opal_async_wait, test_bit(token, opal_async_complete_map));
+ memcpy(msg, &opal_async_responses[token], sizeof(*msg));
+
+ return 0;
+}
+
+static int opal_async_comp_event(struct notifier_block *nb,
+ unsigned long msg_type, void *msg)
+{
+ struct opal_msg *comp_msg = msg;
+ unsigned long flags;
+
+ if (msg_type != OPAL_MSG_ASYNC_COMP)
+ return 0;
+
+ memcpy(&opal_async_responses[comp_msg->params[0]], comp_msg,
+ sizeof(*comp_msg));
+ spin_lock_irqsave(&opal_async_comp_lock, flags);
+ __set_bit(comp_msg->params[0], opal_async_complete_map);
+ spin_unlock_irqrestore(&opal_async_comp_lock, flags);
+
+ wake_up(&opal_async_wait);
+
+ return 0;
+}
+
+static struct notifier_block opal_async_comp_nb = {
+ .notifier_call = opal_async_comp_event,
+ .next = NULL,
+ .priority = 0,
+};
+
+static int __init opal_async_comp_init(void)
+{
+ struct device_node *opal_node;
+ const __be32 *async;
+ int err;
+
+ opal_node = of_find_node_by_path("/ibm,opal");
+ if (!opal_node) {
+ pr_err("%s: Opal node not found\n", __func__);
+ err = -ENOENT;
+ goto out;
+ }
+
+ async = of_get_property(opal_node, "opal-msg-async-num", NULL);
+ if (!async) {
+ pr_err("%s: %s has no opal-msg-async-num\n",
+ __func__, opal_node->full_name);
+ err = -ENOENT;
+ goto out_opal_node;
+ }
+
+ opal_max_async_tokens = be32_to_cpup(async);
+ if (opal_max_async_tokens > N_ASYNC_COMPLETIONS)
+ opal_max_async_tokens = N_ASYNC_COMPLETIONS;
+
+ err = opal_message_notifier_register(OPAL_MSG_ASYNC_COMP,
+ &opal_async_comp_nb);
+ if (err) {
+ pr_err("%s: Can't register OPAL event notifier (%d)\n",
+ __func__, err);
+ goto out_opal_node;
+ }
+
+ opal_async_responses = kzalloc(
+ sizeof(*opal_async_responses) * opal_max_async_tokens,
+ GFP_KERNEL);
+ if (!opal_async_responses) {
+ pr_err("%s: Out of memory, failed to do asynchronous "
+ "completion init\n", __func__);
+ err = -ENOMEM;
+ goto out_opal_node;
+ }
+
+ /* Initialize to 1 less than the maximum tokens available, as we may
+ * require to pop one during emergency through synchronous call to
+ * __opal_async_get_token()
+ */
+ sema_init(&opal_async_sem, opal_max_async_tokens - 1);
+
+out_opal_node:
+ of_node_put(opal_node);
+out:
+ return err;
+}
+subsys_initcall(opal_async_comp_init);
diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c
new file mode 100644
index 000000000000..0c767c561dc9
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-dump.c
@@ -0,0 +1,525 @@
+/*
+ * PowerNV OPAL Dump Interface
+ *
+ * Copyright 2013,2014 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 <linux/kobject.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/delay.h>
+
+#include <asm/opal.h>
+
+#define DUMP_TYPE_FSP 0x01
+
+struct dump_obj {
+ struct kobject kobj;
+ struct bin_attribute dump_attr;
+ uint32_t id; /* becomes object name */
+ uint32_t type;
+ uint32_t size;
+ char *buffer;
+};
+#define to_dump_obj(x) container_of(x, struct dump_obj, kobj)
+
+struct dump_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct dump_obj *dump, struct dump_attribute *attr,
+ char *buf);
+ ssize_t (*store)(struct dump_obj *dump, struct dump_attribute *attr,
+ const char *buf, size_t count);
+};
+#define to_dump_attr(x) container_of(x, struct dump_attribute, attr)
+
+static ssize_t dump_id_show(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "0x%x\n", dump_obj->id);
+}
+
+static const char* dump_type_to_string(uint32_t type)
+{
+ switch (type) {
+ case 0x01: return "SP Dump";
+ case 0x02: return "System/Platform Dump";
+ case 0x03: return "SMA Dump";
+ default: return "unknown";
+ }
+}
+
+static ssize_t dump_type_show(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ char *buf)
+{
+
+ return sprintf(buf, "0x%x %s\n", dump_obj->type,
+ dump_type_to_string(dump_obj->type));
+}
+
+static ssize_t dump_ack_show(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "ack - acknowledge dump\n");
+}
+
+/*
+ * Send acknowledgement to OPAL
+ */
+static int64_t dump_send_ack(uint32_t dump_id)
+{
+ int rc;
+
+ rc = opal_dump_ack(dump_id);
+ if (rc)
+ pr_warn("%s: Failed to send ack to Dump ID 0x%x (%d)\n",
+ __func__, dump_id, rc);
+ return rc;
+}
+
+static void delay_release_kobj(void *kobj)
+{
+ kobject_put((struct kobject *)kobj);
+}
+
+static ssize_t dump_ack_store(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ dump_send_ack(dump_obj->id);
+ sysfs_schedule_callback(&dump_obj->kobj, delay_release_kobj,
+ &dump_obj->kobj, THIS_MODULE);
+ return count;
+}
+
+/* Attributes of a dump
+ * The binary attribute of the dump itself is dynamic
+ * due to the dynamic size of the dump
+ */
+static struct dump_attribute id_attribute =
+ __ATTR(id, 0666, dump_id_show, NULL);
+static struct dump_attribute type_attribute =
+ __ATTR(type, 0666, dump_type_show, NULL);
+static struct dump_attribute ack_attribute =
+ __ATTR(acknowledge, 0660, dump_ack_show, dump_ack_store);
+
+static ssize_t init_dump_show(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "1 - initiate dump\n");
+}
+
+static int64_t dump_fips_init(uint8_t type)
+{
+ int rc;
+
+ rc = opal_dump_init(type);
+ if (rc)
+ pr_warn("%s: Failed to initiate FipS dump (%d)\n",
+ __func__, rc);
+ return rc;
+}
+
+static ssize_t init_dump_store(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ dump_fips_init(DUMP_TYPE_FSP);
+ pr_info("%s: Initiated FSP dump\n", __func__);
+ return count;
+}
+
+static struct dump_attribute initiate_attribute =
+ __ATTR(initiate_dump, 0600, init_dump_show, init_dump_store);
+
+static struct attribute *initiate_attrs[] = {
+ &initiate_attribute.attr,
+ NULL,
+};
+
+static struct attribute_group initiate_attr_group = {
+ .attrs = initiate_attrs,
+};
+
+static struct kset *dump_kset;
+
+static ssize_t dump_attr_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buf)
+{
+ struct dump_attribute *attribute;
+ struct dump_obj *dump;
+
+ attribute = to_dump_attr(attr);
+ dump = to_dump_obj(kobj);
+
+ if (!attribute->show)
+ return -EIO;
+
+ return attribute->show(dump, attribute, buf);
+}
+
+static ssize_t dump_attr_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buf, size_t len)
+{
+ struct dump_attribute *attribute;
+ struct dump_obj *dump;
+
+ attribute = to_dump_attr(attr);
+ dump = to_dump_obj(kobj);
+
+ if (!attribute->store)
+ return -EIO;
+
+ return attribute->store(dump, attribute, buf, len);
+}
+
+static const struct sysfs_ops dump_sysfs_ops = {
+ .show = dump_attr_show,
+ .store = dump_attr_store,
+};
+
+static void dump_release(struct kobject *kobj)
+{
+ struct dump_obj *dump;
+
+ dump = to_dump_obj(kobj);
+ vfree(dump->buffer);
+ kfree(dump);
+}
+
+static struct attribute *dump_default_attrs[] = {
+ &id_attribute.attr,
+ &type_attribute.attr,
+ &ack_attribute.attr,
+ NULL,
+};
+
+static struct kobj_type dump_ktype = {
+ .sysfs_ops = &dump_sysfs_ops,
+ .release = &dump_release,
+ .default_attrs = dump_default_attrs,
+};
+
+static void free_dump_sg_list(struct opal_sg_list *list)
+{
+ struct opal_sg_list *sg1;
+ while (list) {
+ sg1 = list->next;
+ kfree(list);
+ list = sg1;
+ }
+ list = NULL;
+}
+
+static struct opal_sg_list *dump_data_to_sglist(struct dump_obj *dump)
+{
+ struct opal_sg_list *sg1, *list = NULL;
+ void *addr;
+ int64_t size;
+
+ addr = dump->buffer;
+ size = dump->size;
+
+ sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!sg1)
+ goto nomem;
+
+ list = sg1;
+ sg1->num_entries = 0;
+ while (size > 0) {
+ /* Translate virtual address to physical address */
+ sg1->entry[sg1->num_entries].data =
+ (void *)(vmalloc_to_pfn(addr) << PAGE_SHIFT);
+
+ if (size > PAGE_SIZE)
+ sg1->entry[sg1->num_entries].length = PAGE_SIZE;
+ else
+ sg1->entry[sg1->num_entries].length = size;
+
+ sg1->num_entries++;
+ if (sg1->num_entries >= SG_ENTRIES_PER_NODE) {
+ sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!sg1->next)
+ goto nomem;
+
+ sg1 = sg1->next;
+ sg1->num_entries = 0;
+ }
+ addr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ return list;
+
+nomem:
+ pr_err("%s : Failed to allocate memory\n", __func__);
+ free_dump_sg_list(list);
+ return NULL;
+}
+
+static void sglist_to_phy_addr(struct opal_sg_list *list)
+{
+ struct opal_sg_list *sg, *next;
+
+ for (sg = list; sg; sg = next) {
+ next = sg->next;
+ /* Don't translate NULL pointer for last entry */
+ if (sg->next)
+ sg->next = (struct opal_sg_list *)__pa(sg->next);
+ else
+ sg->next = NULL;
+
+ /* Convert num_entries to length */
+ sg->num_entries =
+ sg->num_entries * sizeof(struct opal_sg_entry) + 16;
+ }
+}
+
+static int64_t dump_read_info(uint32_t *id, uint32_t *size, uint32_t *type)
+{
+ int rc;
+ *type = 0xffffffff;
+
+ rc = opal_dump_info2(id, size, type);
+
+ if (rc == OPAL_PARAMETER)
+ rc = opal_dump_info(id, size);
+
+ if (rc)
+ pr_warn("%s: Failed to get dump info (%d)\n",
+ __func__, rc);
+ return rc;
+}
+
+static int64_t dump_read_data(struct dump_obj *dump)
+{
+ struct opal_sg_list *list;
+ uint64_t addr;
+ int64_t rc;
+
+ /* Allocate memory */
+ dump->buffer = vzalloc(PAGE_ALIGN(dump->size));
+ if (!dump->buffer) {
+ pr_err("%s : Failed to allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Generate SG list */
+ list = dump_data_to_sglist(dump);
+ if (!list) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Translate sg list addr to real address */
+ sglist_to_phy_addr(list);
+
+ /* First entry address */
+ addr = __pa(list);
+
+ /* Fetch data */
+ rc = OPAL_BUSY_EVENT;
+ while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
+ rc = opal_dump_read(dump->id, addr);
+ if (rc == OPAL_BUSY_EVENT) {
+ opal_poll_events(NULL);
+ msleep(20);
+ }
+ }
+
+ if (rc != OPAL_SUCCESS && rc != OPAL_PARTIAL)
+ pr_warn("%s: Extract dump failed for ID 0x%x\n",
+ __func__, dump->id);
+
+ /* Free SG list */
+ free_dump_sg_list(list);
+
+out:
+ return rc;
+}
+
+static ssize_t dump_attr_read(struct file *filep, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
+{
+ ssize_t rc;
+
+ struct dump_obj *dump = to_dump_obj(kobj);
+
+ if (!dump->buffer) {
+ rc = dump_read_data(dump);
+
+ if (rc != OPAL_SUCCESS && rc != OPAL_PARTIAL) {
+ vfree(dump->buffer);
+ dump->buffer = NULL;
+
+ return -EIO;
+ }
+ if (rc == OPAL_PARTIAL) {
+ /* On a partial read, we just return EIO
+ * and rely on userspace to ask us to try
+ * again.
+ */
+ pr_info("%s: Platform dump partially read.ID = 0x%x\n",
+ __func__, dump->id);
+ return -EIO;
+ }
+ }
+
+ memcpy(buffer, dump->buffer + pos, count);
+
+ /* You may think we could free the dump buffer now and retrieve
+ * it again later if needed, but due to current firmware limitation,
+ * that's not the case. So, once read into userspace once,
+ * we keep the dump around until it's acknowledged by userspace.
+ */
+
+ return count;
+}
+
+static struct dump_obj *create_dump_obj(uint32_t id, size_t size,
+ uint32_t type)
+{
+ struct dump_obj *dump;
+ int rc;
+
+ dump = kzalloc(sizeof(*dump), GFP_KERNEL);
+ if (!dump)
+ return NULL;
+
+ dump->kobj.kset = dump_kset;
+
+ kobject_init(&dump->kobj, &dump_ktype);
+
+ sysfs_bin_attr_init(&dump->dump_attr);
+
+ dump->dump_attr.attr.name = "dump";
+ dump->dump_attr.attr.mode = 0400;
+ dump->dump_attr.size = size;
+ dump->dump_attr.read = dump_attr_read;
+
+ dump->id = id;
+ dump->size = size;
+ dump->type = type;
+
+ rc = kobject_add(&dump->kobj, NULL, "0x%x-0x%x", type, id);
+ if (rc) {
+ kobject_put(&dump->kobj);
+ return NULL;
+ }
+
+ rc = sysfs_create_bin_file(&dump->kobj, &dump->dump_attr);
+ if (rc) {
+ kobject_put(&dump->kobj);
+ return NULL;
+ }
+
+ pr_info("%s: New platform dump. ID = 0x%x Size %u\n",
+ __func__, dump->id, dump->size);
+
+ kobject_uevent(&dump->kobj, KOBJ_ADD);
+
+ return dump;
+}
+
+static int process_dump(void)
+{
+ int rc;
+ uint32_t dump_id, dump_size, dump_type;
+ struct dump_obj *dump;
+ char name[22];
+
+ rc = dump_read_info(&dump_id, &dump_size, &dump_type);
+ if (rc != OPAL_SUCCESS)
+ return rc;
+
+ sprintf(name, "0x%x-0x%x", dump_type, dump_id);
+
+ /* we may get notified twice, let's handle
+ * that gracefully and not create two conflicting
+ * entries.
+ */
+ if (kset_find_obj(dump_kset, name))
+ return 0;
+
+ dump = create_dump_obj(dump_id, dump_size, dump_type);
+ if (!dump)
+ return -1;
+
+ return 0;
+}
+
+static void dump_work_fn(struct work_struct *work)
+{
+ process_dump();
+}
+
+static DECLARE_WORK(dump_work, dump_work_fn);
+
+static void schedule_process_dump(void)
+{
+ schedule_work(&dump_work);
+}
+
+/*
+ * New dump available notification
+ *
+ * Once we get notification, we add sysfs entries for it.
+ * We only fetch the dump on demand, and create sysfs asynchronously.
+ */
+static int dump_event(struct notifier_block *nb,
+ unsigned long events, void *change)
+{
+ if (events & OPAL_EVENT_DUMP_AVAIL)
+ schedule_process_dump();
+
+ return 0;
+}
+
+static struct notifier_block dump_nb = {
+ .notifier_call = dump_event,
+ .next = NULL,
+ .priority = 0
+};
+
+void __init opal_platform_dump_init(void)
+{
+ int rc;
+
+ dump_kset = kset_create_and_add("dump", NULL, opal_kobj);
+ if (!dump_kset) {
+ pr_warn("%s: Failed to create dump kset\n", __func__);
+ return;
+ }
+
+ rc = sysfs_create_group(&dump_kset->kobj, &initiate_attr_group);
+ if (rc) {
+ pr_warn("%s: Failed to create initiate dump attr group\n",
+ __func__);
+ kobject_put(&dump_kset->kobj);
+ return;
+ }
+
+ rc = opal_notifier_register(&dump_nb);
+ if (rc) {
+ pr_warn("%s: Can't register OPAL event notifier (%d)\n",
+ __func__, rc);
+ return;
+ }
+
+ opal_dump_resend_notification();
+}
diff --git a/arch/powerpc/platforms/powernv/opal-elog.c b/arch/powerpc/platforms/powernv/opal-elog.c
new file mode 100644
index 000000000000..1d7355bc9db0
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-elog.c
@@ -0,0 +1,313 @@
+/*
+ * Error log support on PowerNV.
+ *
+ * Copyright 2013,2014 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/fcntl.h>
+#include <linux/kobject.h>
+#include <asm/uaccess.h>
+#include <asm/opal.h>
+
+struct elog_obj {
+ struct kobject kobj;
+ struct bin_attribute raw_attr;
+ uint64_t id;
+ uint64_t type;
+ size_t size;
+ char *buffer;
+};
+#define to_elog_obj(x) container_of(x, struct elog_obj, kobj)
+
+struct elog_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct elog_obj *elog, struct elog_attribute *attr,
+ char *buf);
+ ssize_t (*store)(struct elog_obj *elog, struct elog_attribute *attr,
+ const char *buf, size_t count);
+};
+#define to_elog_attr(x) container_of(x, struct elog_attribute, attr)
+
+static ssize_t elog_id_show(struct elog_obj *elog_obj,
+ struct elog_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "0x%llx\n", elog_obj->id);
+}
+
+static const char *elog_type_to_string(uint64_t type)
+{
+ switch (type) {
+ case 0: return "PEL";
+ default: return "unknown";
+ }
+}
+
+static ssize_t elog_type_show(struct elog_obj *elog_obj,
+ struct elog_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "0x%llx %s\n",
+ elog_obj->type,
+ elog_type_to_string(elog_obj->type));
+}
+
+static ssize_t elog_ack_show(struct elog_obj *elog_obj,
+ struct elog_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "ack - acknowledge log message\n");
+}
+
+static void delay_release_kobj(void *kobj)
+{
+ kobject_put((struct kobject *)kobj);
+}
+
+static ssize_t elog_ack_store(struct elog_obj *elog_obj,
+ struct elog_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ opal_send_ack_elog(elog_obj->id);
+ sysfs_schedule_callback(&elog_obj->kobj, delay_release_kobj,
+ &elog_obj->kobj, THIS_MODULE);
+ return count;
+}
+
+static struct elog_attribute id_attribute =
+ __ATTR(id, 0666, elog_id_show, NULL);
+static struct elog_attribute type_attribute =
+ __ATTR(type, 0666, elog_type_show, NULL);
+static struct elog_attribute ack_attribute =
+ __ATTR(acknowledge, 0660, elog_ack_show, elog_ack_store);
+
+static struct kset *elog_kset;
+
+static ssize_t elog_attr_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buf)
+{
+ struct elog_attribute *attribute;
+ struct elog_obj *elog;
+
+ attribute = to_elog_attr(attr);
+ elog = to_elog_obj(kobj);
+
+ if (!attribute->show)
+ return -EIO;
+
+ return attribute->show(elog, attribute, buf);
+}
+
+static ssize_t elog_attr_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buf, size_t len)
+{
+ struct elog_attribute *attribute;
+ struct elog_obj *elog;
+
+ attribute = to_elog_attr(attr);
+ elog = to_elog_obj(kobj);
+
+ if (!attribute->store)
+ return -EIO;
+
+ return attribute->store(elog, attribute, buf, len);
+}
+
+static const struct sysfs_ops elog_sysfs_ops = {
+ .show = elog_attr_show,
+ .store = elog_attr_store,
+};
+
+static void elog_release(struct kobject *kobj)
+{
+ struct elog_obj *elog;
+
+ elog = to_elog_obj(kobj);
+ kfree(elog->buffer);
+ kfree(elog);
+}
+
+static struct attribute *elog_default_attrs[] = {
+ &id_attribute.attr,
+ &type_attribute.attr,
+ &ack_attribute.attr,
+ NULL,
+};
+
+static struct kobj_type elog_ktype = {
+ .sysfs_ops = &elog_sysfs_ops,
+ .release = &elog_release,
+ .default_attrs = elog_default_attrs,
+};
+
+/* Maximum size of a single log on FSP is 16KB */
+#define OPAL_MAX_ERRLOG_SIZE 16384
+
+static ssize_t raw_attr_read(struct file *filep, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
+{
+ int opal_rc;
+
+ struct elog_obj *elog = to_elog_obj(kobj);
+
+ /* We may have had an error reading before, so let's retry */
+ if (!elog->buffer) {
+ elog->buffer = kzalloc(elog->size, GFP_KERNEL);
+ if (!elog->buffer)
+ return -EIO;
+
+ opal_rc = opal_read_elog(__pa(elog->buffer),
+ elog->size, elog->id);
+ if (opal_rc != OPAL_SUCCESS) {
+ pr_err("ELOG: log read failed for log-id=%llx\n",
+ elog->id);
+ kfree(elog->buffer);
+ elog->buffer = NULL;
+ return -EIO;
+ }
+ }
+
+ memcpy(buffer, elog->buffer + pos, count);
+
+ return count;
+}
+
+static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type)
+{
+ struct elog_obj *elog;
+ int rc;
+
+ elog = kzalloc(sizeof(*elog), GFP_KERNEL);
+ if (!elog)
+ return NULL;
+
+ elog->kobj.kset = elog_kset;
+
+ kobject_init(&elog->kobj, &elog_ktype);
+
+ sysfs_bin_attr_init(&elog->raw_attr);
+
+ elog->raw_attr.attr.name = "raw";
+ elog->raw_attr.attr.mode = 0400;
+ elog->raw_attr.size = size;
+ elog->raw_attr.read = raw_attr_read;
+
+ elog->id = id;
+ elog->size = size;
+ elog->type = type;
+
+ elog->buffer = kzalloc(elog->size, GFP_KERNEL);
+
+ if (elog->buffer) {
+ rc = opal_read_elog(__pa(elog->buffer),
+ elog->size, elog->id);
+ if (rc != OPAL_SUCCESS) {
+ pr_err("ELOG: log read failed for log-id=%llx\n",
+ elog->id);
+ kfree(elog->buffer);
+ elog->buffer = NULL;
+ }
+ }
+
+ rc = kobject_add(&elog->kobj, NULL, "0x%llx", id);
+ if (rc) {
+ kobject_put(&elog->kobj);
+ return NULL;
+ }
+
+ rc = sysfs_create_bin_file(&elog->kobj, &elog->raw_attr);
+ if (rc) {
+ kobject_put(&elog->kobj);
+ return NULL;
+ }
+
+ kobject_uevent(&elog->kobj, KOBJ_ADD);
+
+ return elog;
+}
+
+static void elog_work_fn(struct work_struct *work)
+{
+ size_t elog_size;
+ uint64_t log_id;
+ uint64_t elog_type;
+ int rc;
+ char name[2+16+1];
+
+ rc = opal_get_elog_size(&log_id, &elog_size, &elog_type);
+ if (rc != OPAL_SUCCESS) {
+ pr_err("ELOG: Opal log read failed\n");
+ return;
+ }
+
+ BUG_ON(elog_size > OPAL_MAX_ERRLOG_SIZE);
+
+ if (elog_size >= OPAL_MAX_ERRLOG_SIZE)
+ elog_size = OPAL_MAX_ERRLOG_SIZE;
+
+ sprintf(name, "0x%llx", log_id);
+
+ /* we may get notified twice, let's handle
+ * that gracefully and not create two conflicting
+ * entries.
+ */
+ if (kset_find_obj(elog_kset, name))
+ return;
+
+ create_elog_obj(log_id, elog_size, elog_type);
+}
+
+static DECLARE_WORK(elog_work, elog_work_fn);
+
+static int elog_event(struct notifier_block *nb,
+ unsigned long events, void *change)
+{
+ /* check for error log event */
+ if (events & OPAL_EVENT_ERROR_LOG_AVAIL)
+ schedule_work(&elog_work);
+ return 0;
+}
+
+static struct notifier_block elog_nb = {
+ .notifier_call = elog_event,
+ .next = NULL,
+ .priority = 0
+};
+
+int __init opal_elog_init(void)
+{
+ int rc = 0;
+
+ elog_kset = kset_create_and_add("elog", NULL, opal_kobj);
+ if (!elog_kset) {
+ pr_warn("%s: failed to create elog kset\n", __func__);
+ return -1;
+ }
+
+ rc = opal_notifier_register(&elog_nb);
+ if (rc) {
+ pr_err("%s: Can't register OPAL event notifier (%d)\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* We are now ready to pull error logs from opal. */
+ opal_resend_pending_logs();
+
+ return 0;
+}
diff --git a/arch/powerpc/platforms/powernv/opal-sensor.c b/arch/powerpc/platforms/powernv/opal-sensor.c
new file mode 100644
index 000000000000..663cc9c65613
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-sensor.c
@@ -0,0 +1,64 @@
+/*
+ * PowerNV sensor code
+ *
+ * Copyright (C) 2013 IBM
+ *
+ * This program is free software; 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/delay.h>
+#include <linux/mutex.h>
+#include <asm/opal.h>
+
+static DEFINE_MUTEX(opal_sensor_mutex);
+
+/*
+ * This will return sensor information to driver based on the requested sensor
+ * handle. A handle is an opaque id for the powernv, read by the driver from the
+ * device tree..
+ */
+int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data)
+{
+ int ret, token;
+ struct opal_msg msg;
+
+ token = opal_async_get_token_interruptible();
+ if (token < 0) {
+ pr_err("%s: Couldn't get the token, returning\n", __func__);
+ ret = token;
+ goto out;
+ }
+
+ mutex_lock(&opal_sensor_mutex);
+ ret = opal_sensor_read(sensor_hndl, token, sensor_data);
+ if (ret != OPAL_ASYNC_COMPLETION)
+ goto out_token;
+
+ ret = opal_async_wait_response(token, &msg);
+ if (ret) {
+ pr_err("%s: Failed to wait for the async response, %d\n",
+ __func__, ret);
+ goto out_token;
+ }
+
+ ret = msg.params[1];
+
+out_token:
+ mutex_unlock(&opal_sensor_mutex);
+ opal_async_release_token(token);
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(opal_get_sensor_data);
diff --git a/arch/powerpc/platforms/powernv/opal-sysparam.c b/arch/powerpc/platforms/powernv/opal-sysparam.c
new file mode 100644
index 000000000000..0bd249a26f30
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-sysparam.c
@@ -0,0 +1,290 @@
+/*
+ * PowerNV system parameter code
+ *
+ * Copyright (C) 2013 IBM
+ *
+ * This program is free software; 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/kobject.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/gfp.h>
+#include <linux/stat.h>
+#include <asm/opal.h>
+
+#define MAX_PARAM_DATA_LEN 64
+
+static DEFINE_MUTEX(opal_sysparam_mutex);
+static struct kobject *sysparam_kobj;
+static void *param_data_buf;
+
+struct param_attr {
+ struct list_head list;
+ u32 param_id;
+ u32 param_size;
+ struct kobj_attribute kobj_attr;
+};
+
+static int opal_get_sys_param(u32 param_id, u32 length, void *buffer)
+{
+ struct opal_msg msg;
+ int ret, token;
+
+ token = opal_async_get_token_interruptible();
+ if (token < 0) {
+ if (token != -ERESTARTSYS)
+ pr_err("%s: Couldn't get the token, returning\n",
+ __func__);
+ ret = token;
+ goto out;
+ }
+
+ ret = opal_get_param(token, param_id, (u64)buffer, length);
+ if (ret != OPAL_ASYNC_COMPLETION)
+ goto out_token;
+
+ ret = opal_async_wait_response(token, &msg);
+ if (ret) {
+ pr_err("%s: Failed to wait for the async response, %d\n",
+ __func__, ret);
+ goto out_token;
+ }
+
+ ret = msg.params[1];
+
+out_token:
+ opal_async_release_token(token);
+out:
+ return ret;
+}
+
+static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
+{
+ struct opal_msg msg;
+ int ret, token;
+
+ token = opal_async_get_token_interruptible();
+ if (token < 0) {
+ if (token != -ERESTARTSYS)
+ pr_err("%s: Couldn't get the token, returning\n",
+ __func__);
+ ret = token;
+ goto out;
+ }
+
+ ret = opal_set_param(token, param_id, (u64)buffer, length);
+
+ if (ret != OPAL_ASYNC_COMPLETION)
+ goto out_token;
+
+ ret = opal_async_wait_response(token, &msg);
+ if (ret) {
+ pr_err("%s: Failed to wait for the async response, %d\n",
+ __func__, ret);
+ goto out_token;
+ }
+
+ ret = msg.params[1];
+
+out_token:
+ opal_async_release_token(token);
+out:
+ return ret;
+}
+
+static ssize_t sys_param_show(struct kobject *kobj,
+ struct kobj_attribute *kobj_attr, char *buf)
+{
+ struct param_attr *attr = container_of(kobj_attr, struct param_attr,
+ kobj_attr);
+ int ret;
+
+ mutex_lock(&opal_sysparam_mutex);
+ ret = opal_get_sys_param(attr->param_id, attr->param_size,
+ param_data_buf);
+ if (ret)
+ goto out;
+
+ memcpy(buf, param_data_buf, attr->param_size);
+
+out:
+ mutex_unlock(&opal_sysparam_mutex);
+ return ret ? ret : attr->param_size;
+}
+
+static ssize_t sys_param_store(struct kobject *kobj,
+ struct kobj_attribute *kobj_attr, const char *buf, size_t count)
+{
+ struct param_attr *attr = container_of(kobj_attr, struct param_attr,
+ kobj_attr);
+ int ret;
+
+ mutex_lock(&opal_sysparam_mutex);
+ memcpy(param_data_buf, buf, count);
+ ret = opal_set_sys_param(attr->param_id, attr->param_size,
+ param_data_buf);
+ mutex_unlock(&opal_sysparam_mutex);
+ return ret ? ret : count;
+}
+
+void __init opal_sys_param_init(void)
+{
+ struct device_node *sysparam;
+ struct param_attr *attr;
+ u32 *id, *size;
+ int count, i;
+ u8 *perm;
+
+ if (!opal_kobj) {
+ pr_warn("SYSPARAM: opal kobject is not available\n");
+ goto out;
+ }
+
+ sysparam_kobj = kobject_create_and_add("sysparams", opal_kobj);
+ if (!sysparam_kobj) {
+ pr_err("SYSPARAM: Failed to create sysparam kobject\n");
+ goto out;
+ }
+
+ /* Allocate big enough buffer for any get/set transactions */
+ param_data_buf = kzalloc(MAX_PARAM_DATA_LEN, GFP_KERNEL);
+ if (!param_data_buf) {
+ pr_err("SYSPARAM: Failed to allocate memory for param data "
+ "buf\n");
+ goto out_kobj_put;
+ }
+
+ sysparam = of_find_node_by_path("/ibm,opal/sysparams");
+ if (!sysparam) {
+ pr_err("SYSPARAM: Opal sysparam node not found\n");
+ goto out_param_buf;
+ }
+
+ if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {
+ pr_err("SYSPARAM: Opal sysparam node not compatible\n");
+ goto out_node_put;
+ }
+
+ /* Number of parameters exposed through DT */
+ count = of_property_count_strings(sysparam, "param-name");
+ if (count < 0) {
+ pr_err("SYSPARAM: No string found of property param-name in "
+ "the node %s\n", sysparam->name);
+ goto out_node_put;
+ }
+
+ id = kzalloc(sizeof(*id) * count, GFP_KERNEL);
+ if (!id) {
+ pr_err("SYSPARAM: Failed to allocate memory to read parameter "
+ "id\n");
+ goto out_node_put;
+ }
+
+ size = kzalloc(sizeof(*size) * count, GFP_KERNEL);
+ if (!size) {
+ pr_err("SYSPARAM: Failed to allocate memory to read parameter "
+ "size\n");
+ goto out_free_id;
+ }
+
+ perm = kzalloc(sizeof(*perm) * count, GFP_KERNEL);
+ if (!perm) {
+ pr_err("SYSPARAM: Failed to allocate memory to read supported "
+ "action on the parameter");
+ goto out_free_size;
+ }
+
+ if (of_property_read_u32_array(sysparam, "param-id", id, count)) {
+ pr_err("SYSPARAM: Missing property param-id in the DT\n");
+ goto out_free_perm;
+ }
+
+ if (of_property_read_u32_array(sysparam, "param-len", size, count)) {
+ pr_err("SYSPARAM: Missing propery param-len in the DT\n");
+ goto out_free_perm;
+ }
+
+
+ if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {
+ pr_err("SYSPARAM: Missing propery param-perm in the DT\n");
+ goto out_free_perm;
+ }
+
+ attr = kzalloc(sizeof(*attr) * count, GFP_KERNEL);
+ if (!attr) {
+ pr_err("SYSPARAM: Failed to allocate memory for parameter "
+ "attributes\n");
+ goto out_free_perm;
+ }
+
+ /* For each of the parameters, populate the parameter attributes */
+ for (i = 0; i < count; i++) {
+ sysfs_attr_init(&attr[i].kobj_attr.attr);
+ attr[i].param_id = id[i];
+ attr[i].param_size = size[i];
+ if (of_property_read_string_index(sysparam, "param-name", i,
+ &attr[i].kobj_attr.attr.name))
+ continue;
+
+ /* If the parameter is read-only or read-write */
+ switch (perm[i] & 3) {
+ case OPAL_SYSPARAM_READ:
+ attr[i].kobj_attr.attr.mode = S_IRUGO;
+ break;
+ case OPAL_SYSPARAM_WRITE:
+ attr[i].kobj_attr.attr.mode = S_IWUGO;
+ break;
+ case OPAL_SYSPARAM_RW:
+ attr[i].kobj_attr.attr.mode = S_IRUGO | S_IWUGO;
+ break;
+ default:
+ break;
+ }
+
+ attr[i].kobj_attr.show = sys_param_show;
+ attr[i].kobj_attr.store = sys_param_store;
+
+ if (sysfs_create_file(sysparam_kobj, &attr[i].kobj_attr.attr)) {
+ pr_err("SYSPARAM: Failed to create sysfs file %s\n",
+ attr[i].kobj_attr.attr.name);
+ goto out_free_attr;
+ }
+ }
+
+ kfree(perm);
+ kfree(size);
+ kfree(id);
+ of_node_put(sysparam);
+ return;
+
+out_free_attr:
+ kfree(attr);
+out_free_perm:
+ kfree(perm);
+out_free_size:
+ kfree(size);
+out_free_id:
+ kfree(id);
+out_node_put:
+ of_node_put(sysparam);
+out_param_buf:
+ kfree(param_data_buf);
+out_kobj_put:
+ kobject_put(sysparam_kobj);
+out:
+ return;
+}
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 3e8829c40fbb..bb90f9a4e027 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -123,9 +123,24 @@ OPAL_CALL(opal_xscom_write, OPAL_XSCOM_WRITE);
OPAL_CALL(opal_lpc_read, OPAL_LPC_READ);
OPAL_CALL(opal_lpc_write, OPAL_LPC_WRITE);
OPAL_CALL(opal_return_cpu, OPAL_RETURN_CPU);
+OPAL_CALL(opal_read_elog, OPAL_ELOG_READ);
+OPAL_CALL(opal_send_ack_elog, OPAL_ELOG_ACK);
+OPAL_CALL(opal_get_elog_size, OPAL_ELOG_SIZE);
+OPAL_CALL(opal_resend_pending_logs, OPAL_ELOG_RESEND);
+OPAL_CALL(opal_write_elog, OPAL_ELOG_WRITE);
OPAL_CALL(opal_validate_flash, OPAL_FLASH_VALIDATE);
OPAL_CALL(opal_manage_flash, OPAL_FLASH_MANAGE);
OPAL_CALL(opal_update_flash, OPAL_FLASH_UPDATE);
+OPAL_CALL(opal_resync_timebase, OPAL_RESYNC_TIMEBASE);
+OPAL_CALL(opal_dump_init, OPAL_DUMP_INIT);
+OPAL_CALL(opal_dump_info, OPAL_DUMP_INFO);
+OPAL_CALL(opal_dump_info2, OPAL_DUMP_INFO2);
+OPAL_CALL(opal_dump_read, OPAL_DUMP_READ);
+OPAL_CALL(opal_dump_ack, OPAL_DUMP_ACK);
OPAL_CALL(opal_get_msg, OPAL_GET_MSG);
OPAL_CALL(opal_check_completion, OPAL_CHECK_ASYNC_COMPLETION);
+OPAL_CALL(opal_dump_resend_notification, OPAL_DUMP_RESEND);
OPAL_CALL(opal_sync_host_reboot, OPAL_SYNC_HOST_REBOOT);
+OPAL_CALL(opal_sensor_read, OPAL_SENSOR_READ);
+OPAL_CALL(opal_get_param, OPAL_GET_PARAM);
+OPAL_CALL(opal_set_param, OPAL_SET_PARAM);
diff --git a/arch/powerpc/platforms/powernv/opal-xscom.c b/arch/powerpc/platforms/powernv/opal-xscom.c
index 4fbf276ac99e..4cd2ea6c0dbe 100644
--- a/arch/powerpc/platforms/powernv/opal-xscom.c
+++ b/arch/powerpc/platforms/powernv/opal-xscom.c
@@ -71,11 +71,11 @@ static int opal_xscom_err_xlate(int64_t rc)
}
}
-static u64 opal_scom_unmangle(u64 reg)
+static u64 opal_scom_unmangle(u64 addr)
{
/*
* XSCOM indirect addresses have the top bit set. Additionally
- * the reset of the top 3 nibbles is always 0.
+ * the rest of the top 3 nibbles is always 0.
*
* Because the debugfs interface uses signed offsets and shifts
* the address left by 3, we basically cannot use the top 4 bits
@@ -86,10 +86,13 @@ static u64 opal_scom_unmangle(u64 reg)
* conversion here. To leave room for further xscom address
* expansion, we only clear out the top byte
*
+ * For in-kernel use, we also support the real indirect bit, so
+ * we test for any of the top 5 bits
+ *
*/
- if (reg & (1ull << 59))
- reg = (reg & ~(0xffull << 56)) | (1ull << 63);
- return reg;
+ if (addr & (0x1full << 59))
+ addr = (addr & ~(0xffull << 56)) | (1ull << 63);
+ return addr;
}
static int opal_scom_read(scom_map_t map, u64 reg, u64 *value)
@@ -98,8 +101,8 @@ static int opal_scom_read(scom_map_t map, u64 reg, u64 *value)
int64_t rc;
__be64 v;
- reg = opal_scom_unmangle(reg);
- rc = opal_xscom_read(m->chip, m->addr + reg, (__be64 *)__pa(&v));
+ reg = opal_scom_unmangle(m->addr + reg);
+ rc = opal_xscom_read(m->chip, reg, (__be64 *)__pa(&v));
*value = be64_to_cpu(v);
return opal_xscom_err_xlate(rc);
}
@@ -109,8 +112,8 @@ static int opal_scom_write(scom_map_t map, u64 reg, u64 value)
struct opal_scom_map *m = map;
int64_t rc;
- reg = opal_scom_unmangle(reg);
- rc = opal_xscom_write(m->chip, m->addr + reg, value);
+ reg = opal_scom_unmangle(m->addr + reg);
+ rc = opal_xscom_write(m->chip, reg, value);
return opal_xscom_err_xlate(rc);
}
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 65499adaecff..e92f2f67640f 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -21,6 +21,7 @@
#include <linux/sched.h>
#include <linux/kobject.h>
#include <linux/delay.h>
+#include <linux/memblock.h>
#include <asm/opal.h>
#include <asm/firmware.h>
#include <asm/mce.h>
@@ -33,8 +34,18 @@ struct kobject *opal_kobj;
struct opal {
u64 base;
u64 entry;
+ u64 size;
} opal;
+struct mcheck_recoverable_range {
+ u64 start_addr;
+ u64 end_addr;
+ u64 recover_addr;
+};
+
+static struct mcheck_recoverable_range *mc_recoverable_range;
+static int mc_recoverable_range_len;
+
static struct device_node *opal_node;
static DEFINE_SPINLOCK(opal_write_lock);
extern u64 opal_mc_secondary_handler[];
@@ -49,25 +60,29 @@ static atomic_t opal_notifier_hold = ATOMIC_INIT(0);
int __init early_init_dt_scan_opal(unsigned long node,
const char *uname, int depth, void *data)
{
- const void *basep, *entryp;
- unsigned long basesz, entrysz;
+ const void *basep, *entryp, *sizep;
+ unsigned long basesz, entrysz, runtimesz;
if (depth != 1 || strcmp(uname, "ibm,opal") != 0)
return 0;
basep = of_get_flat_dt_prop(node, "opal-base-address", &basesz);
entryp = of_get_flat_dt_prop(node, "opal-entry-address", &entrysz);
+ sizep = of_get_flat_dt_prop(node, "opal-runtime-size", &runtimesz);
- if (!basep || !entryp)
+ if (!basep || !entryp || !sizep)
return 1;
opal.base = of_read_number(basep, basesz/4);
opal.entry = of_read_number(entryp, entrysz/4);
+ opal.size = of_read_number(sizep, runtimesz/4);
pr_debug("OPAL Base = 0x%llx (basep=%p basesz=%ld)\n",
opal.base, basep, basesz);
pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%ld)\n",
opal.entry, entryp, entrysz);
+ pr_debug("OPAL Entry = 0x%llx (sizep=%p runtimesz=%ld)\n",
+ opal.size, sizep, runtimesz);
powerpc_firmware_features |= FW_FEATURE_OPAL;
if (of_flat_dt_is_compatible(node, "ibm,opal-v3")) {
@@ -84,6 +99,53 @@ int __init early_init_dt_scan_opal(unsigned long node,
return 1;
}
+int __init early_init_dt_scan_recoverable_ranges(unsigned long node,
+ const char *uname, int depth, void *data)
+{
+ unsigned long i, size;
+ const __be32 *prop;
+
+ if (depth != 1 || strcmp(uname, "ibm,opal") != 0)
+ return 0;
+
+ prop = of_get_flat_dt_prop(node, "mcheck-recoverable-ranges", &size);
+
+ if (!prop)
+ return 1;
+
+ pr_debug("Found machine check recoverable ranges.\n");
+
+ /*
+ * Allocate a buffer to hold the MC recoverable ranges. We would be
+ * accessing them in real mode, hence it needs to be within
+ * RMO region.
+ */
+ mc_recoverable_range =__va(memblock_alloc_base(size, __alignof__(u64),
+ ppc64_rma_size));
+ memset(mc_recoverable_range, 0, size);
+
+ /*
+ * Each recoverable address entry is an (start address,len,
+ * recover address) pair, * 2 cells each, totalling 4 cells per entry.
+ */
+ for (i = 0; i < size / (sizeof(*prop) * 5); i++) {
+ mc_recoverable_range[i].start_addr =
+ of_read_number(prop + (i * 5) + 0, 2);
+ mc_recoverable_range[i].end_addr =
+ mc_recoverable_range[i].start_addr +
+ of_read_number(prop + (i * 5) + 2, 1);
+ mc_recoverable_range[i].recover_addr =
+ of_read_number(prop + (i * 5) + 3, 2);
+
+ pr_debug("Machine check recoverable range: %llx..%llx: %llx\n",
+ mc_recoverable_range[i].start_addr,
+ mc_recoverable_range[i].end_addr,
+ mc_recoverable_range[i].recover_addr);
+ }
+ mc_recoverable_range_len = i;
+ return 1;
+}
+
static int __init opal_register_exception_handlers(void)
{
#ifdef __BIG_ENDIAN__
@@ -401,6 +463,38 @@ int opal_machine_check(struct pt_regs *regs)
return 0;
}
+static uint64_t find_recovery_address(uint64_t nip)
+{
+ int i;
+
+ for (i = 0; i < mc_recoverable_range_len; i++)
+ if ((nip >= mc_recoverable_range[i].start_addr) &&
+ (nip < mc_recoverable_range[i].end_addr))
+ return mc_recoverable_range[i].recover_addr;
+ return 0;
+}
+
+bool opal_mce_check_early_recovery(struct pt_regs *regs)
+{
+ uint64_t recover_addr = 0;
+
+ if (!opal.base || !opal.size)
+ goto out;
+
+ if ((regs->nip >= opal.base) &&
+ (regs->nip <= (opal.base + opal.size)))
+ recover_addr = find_recovery_address(regs->nip);
+
+ /*
+ * Setup regs->nip to rfi into fixup address.
+ */
+ if (recover_addr)
+ regs->nip = recover_addr;
+
+out:
+ return !!recover_addr;
+}
+
static irqreturn_t opal_interrupt(int irq, void *data)
{
__be64 events;
@@ -472,8 +566,14 @@ static int __init opal_init(void)
/* Create "opal" kobject under /sys/firmware */
rc = opal_sysfs_init();
if (rc == 0) {
+ /* Setup error log interface */
+ rc = opal_elog_init();
/* Setup code update interface */
opal_flash_init();
+ /* Setup platform dump extract interface */
+ opal_platform_dump_init();
+ /* Setup system parameters interface */
+ opal_sys_param_init();
}
return 0;
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 95633d79ef5d..8518817dcdfd 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -134,57 +134,72 @@ static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose,
pr_info("P7IOC PHB#%d Diag-data (Version: %d)\n\n",
hose->global_number, common->version);
- pr_info(" brdgCtl: %08x\n", data->brdgCtl);
-
- pr_info(" portStatusReg: %08x\n", data->portStatusReg);
- pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus);
- pr_info(" busAgentStatus: %08x\n", data->busAgentStatus);
-
- pr_info(" deviceStatus: %08x\n", data->deviceStatus);
- pr_info(" slotStatus: %08x\n", data->slotStatus);
- pr_info(" linkStatus: %08x\n", data->linkStatus);
- pr_info(" devCmdStatus: %08x\n", data->devCmdStatus);
- pr_info(" devSecStatus: %08x\n", data->devSecStatus);
-
- pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus);
- pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus);
- pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus);
- pr_info(" tlpHdr1: %08x\n", data->tlpHdr1);
- pr_info(" tlpHdr2: %08x\n", data->tlpHdr2);
- pr_info(" tlpHdr3: %08x\n", data->tlpHdr3);
- pr_info(" tlpHdr4: %08x\n", data->tlpHdr4);
- pr_info(" sourceId: %08x\n", data->sourceId);
- pr_info(" errorClass: %016llx\n", data->errorClass);
- pr_info(" correlator: %016llx\n", data->correlator);
- pr_info(" p7iocPlssr: %016llx\n", data->p7iocPlssr);
- pr_info(" p7iocCsr: %016llx\n", data->p7iocCsr);
- pr_info(" lemFir: %016llx\n", data->lemFir);
- pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask);
- pr_info(" lemWOF: %016llx\n", data->lemWOF);
- pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus);
- pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus);
- pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0);
- pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1);
- pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus);
- pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus);
- pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0);
- pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1);
- pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus);
- pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus);
- pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0);
- pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1);
- pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus);
- pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus);
- pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0);
- pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1);
+ if (data->brdgCtl)
+ pr_info(" brdgCtl: %08x\n",
+ data->brdgCtl);
+ if (data->portStatusReg || data->rootCmplxStatus ||
+ data->busAgentStatus)
+ pr_info(" UtlSts: %08x %08x %08x\n",
+ data->portStatusReg, data->rootCmplxStatus,
+ data->busAgentStatus);
+ if (data->deviceStatus || data->slotStatus ||
+ data->linkStatus || data->devCmdStatus ||
+ data->devSecStatus)
+ pr_info(" RootSts: %08x %08x %08x %08x %08x\n",
+ data->deviceStatus, data->slotStatus,
+ data->linkStatus, data->devCmdStatus,
+ data->devSecStatus);
+ if (data->rootErrorStatus || data->uncorrErrorStatus ||
+ data->corrErrorStatus)
+ pr_info(" RootErrSts: %08x %08x %08x\n",
+ data->rootErrorStatus, data->uncorrErrorStatus,
+ data->corrErrorStatus);
+ if (data->tlpHdr1 || data->tlpHdr2 ||
+ data->tlpHdr3 || data->tlpHdr4)
+ pr_info(" RootErrLog: %08x %08x %08x %08x\n",
+ data->tlpHdr1, data->tlpHdr2,
+ data->tlpHdr3, data->tlpHdr4);
+ if (data->sourceId || data->errorClass ||
+ data->correlator)
+ pr_info(" RootErrLog1: %08x %016llx %016llx\n",
+ data->sourceId, data->errorClass,
+ data->correlator);
+ if (data->p7iocPlssr || data->p7iocCsr)
+ pr_info(" PhbSts: %016llx %016llx\n",
+ data->p7iocPlssr, data->p7iocCsr);
+ if (data->lemFir || data->lemErrorMask ||
+ data->lemWOF)
+ pr_info(" Lem: %016llx %016llx %016llx\n",
+ data->lemFir, data->lemErrorMask,
+ data->lemWOF);
+ if (data->phbErrorStatus || data->phbFirstErrorStatus ||
+ data->phbErrorLog0 || data->phbErrorLog1)
+ pr_info(" PhbErr: %016llx %016llx %016llx %016llx\n",
+ data->phbErrorStatus, data->phbFirstErrorStatus,
+ data->phbErrorLog0, data->phbErrorLog1);
+ if (data->mmioErrorStatus || data->mmioFirstErrorStatus ||
+ data->mmioErrorLog0 || data->mmioErrorLog1)
+ pr_info(" OutErr: %016llx %016llx %016llx %016llx\n",
+ data->mmioErrorStatus, data->mmioFirstErrorStatus,
+ data->mmioErrorLog0, data->mmioErrorLog1);
+ if (data->dma0ErrorStatus || data->dma0FirstErrorStatus ||
+ data->dma0ErrorLog0 || data->dma0ErrorLog1)
+ pr_info(" InAErr: %016llx %016llx %016llx %016llx\n",
+ data->dma0ErrorStatus, data->dma0FirstErrorStatus,
+ data->dma0ErrorLog0, data->dma0ErrorLog1);
+ if (data->dma1ErrorStatus || data->dma1FirstErrorStatus ||
+ data->dma1ErrorLog0 || data->dma1ErrorLog1)
+ pr_info(" InBErr: %016llx %016llx %016llx %016llx\n",
+ data->dma1ErrorStatus, data->dma1FirstErrorStatus,
+ data->dma1ErrorLog0, data->dma1ErrorLog1);
for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) {
if ((data->pestA[i] >> 63) == 0 &&
(data->pestB[i] >> 63) == 0)
continue;
- pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]);
- pr_info(" PESTB: %016llx\n", data->pestB[i]);
+ pr_info(" PE[%3d] A/B: %016llx %016llx\n",
+ i, data->pestA[i], data->pestB[i]);
}
}
@@ -197,62 +212,77 @@ static void pnv_pci_dump_phb3_diag_data(struct pci_controller *hose,
data = (struct OpalIoPhb3ErrorData*)common;
pr_info("PHB3 PHB#%d Diag-data (Version: %d)\n\n",
hose->global_number, common->version);
-
- pr_info(" brdgCtl: %08x\n", data->brdgCtl);
-
- pr_info(" portStatusReg: %08x\n", data->portStatusReg);
- pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus);
- pr_info(" busAgentStatus: %08x\n", data->busAgentStatus);
-
- pr_info(" deviceStatus: %08x\n", data->deviceStatus);
- pr_info(" slotStatus: %08x\n", data->slotStatus);
- pr_info(" linkStatus: %08x\n", data->linkStatus);
- pr_info(" devCmdStatus: %08x\n", data->devCmdStatus);
- pr_info(" devSecStatus: %08x\n", data->devSecStatus);
-
- pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus);
- pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus);
- pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus);
- pr_info(" tlpHdr1: %08x\n", data->tlpHdr1);
- pr_info(" tlpHdr2: %08x\n", data->tlpHdr2);
- pr_info(" tlpHdr3: %08x\n", data->tlpHdr3);
- pr_info(" tlpHdr4: %08x\n", data->tlpHdr4);
- pr_info(" sourceId: %08x\n", data->sourceId);
- pr_info(" errorClass: %016llx\n", data->errorClass);
- pr_info(" correlator: %016llx\n", data->correlator);
-
- pr_info(" nFir: %016llx\n", data->nFir);
- pr_info(" nFirMask: %016llx\n", data->nFirMask);
- pr_info(" nFirWOF: %016llx\n", data->nFirWOF);
- pr_info(" PhbPlssr: %016llx\n", data->phbPlssr);
- pr_info(" PhbCsr: %016llx\n", data->phbCsr);
- pr_info(" lemFir: %016llx\n", data->lemFir);
- pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask);
- pr_info(" lemWOF: %016llx\n", data->lemWOF);
- pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus);
- pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus);
- pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0);
- pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1);
- pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus);
- pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus);
- pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0);
- pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1);
- pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus);
- pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus);
- pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0);
- pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1);
- pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus);
- pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus);
- pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0);
- pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1);
+ if (data->brdgCtl)
+ pr_info(" brdgCtl: %08x\n",
+ data->brdgCtl);
+ if (data->portStatusReg || data->rootCmplxStatus ||
+ data->busAgentStatus)
+ pr_info(" UtlSts: %08x %08x %08x\n",
+ data->portStatusReg, data->rootCmplxStatus,
+ data->busAgentStatus);
+ if (data->deviceStatus || data->slotStatus ||
+ data->linkStatus || data->devCmdStatus ||
+ data->devSecStatus)
+ pr_info(" RootSts: %08x %08x %08x %08x %08x\n",
+ data->deviceStatus, data->slotStatus,
+ data->linkStatus, data->devCmdStatus,
+ data->devSecStatus);
+ if (data->rootErrorStatus || data->uncorrErrorStatus ||
+ data->corrErrorStatus)
+ pr_info(" RootErrSts: %08x %08x %08x\n",
+ data->rootErrorStatus, data->uncorrErrorStatus,
+ data->corrErrorStatus);
+ if (data->tlpHdr1 || data->tlpHdr2 ||
+ data->tlpHdr3 || data->tlpHdr4)
+ pr_info(" RootErrLog: %08x %08x %08x %08x\n",
+ data->tlpHdr1, data->tlpHdr2,
+ data->tlpHdr3, data->tlpHdr4);
+ if (data->sourceId || data->errorClass ||
+ data->correlator)
+ pr_info(" RootErrLog1: %08x %016llx %016llx\n",
+ data->sourceId, data->errorClass,
+ data->correlator);
+ if (data->nFir || data->nFirMask ||
+ data->nFirWOF)
+ pr_info(" nFir: %016llx %016llx %016llx\n",
+ data->nFir, data->nFirMask,
+ data->nFirWOF);
+ if (data->phbPlssr || data->phbCsr)
+ pr_info(" PhbSts: %016llx %016llx\n",
+ data->phbPlssr, data->phbCsr);
+ if (data->lemFir || data->lemErrorMask ||
+ data->lemWOF)
+ pr_info(" Lem: %016llx %016llx %016llx\n",
+ data->lemFir, data->lemErrorMask,
+ data->lemWOF);
+ if (data->phbErrorStatus || data->phbFirstErrorStatus ||
+ data->phbErrorLog0 || data->phbErrorLog1)
+ pr_info(" PhbErr: %016llx %016llx %016llx %016llx\n",
+ data->phbErrorStatus, data->phbFirstErrorStatus,
+ data->phbErrorLog0, data->phbErrorLog1);
+ if (data->mmioErrorStatus || data->mmioFirstErrorStatus ||
+ data->mmioErrorLog0 || data->mmioErrorLog1)
+ pr_info(" OutErr: %016llx %016llx %016llx %016llx\n",
+ data->mmioErrorStatus, data->mmioFirstErrorStatus,
+ data->mmioErrorLog0, data->mmioErrorLog1);
+ if (data->dma0ErrorStatus || data->dma0FirstErrorStatus ||
+ data->dma0ErrorLog0 || data->dma0ErrorLog1)
+ pr_info(" InAErr: %016llx %016llx %016llx %016llx\n",
+ data->dma0ErrorStatus, data->dma0FirstErrorStatus,
+ data->dma0ErrorLog0, data->dma0ErrorLog1);
+ if (data->dma1ErrorStatus || data->dma1FirstErrorStatus ||
+ data->dma1ErrorLog0 || data->dma1ErrorLog1)
+ pr_info(" InBErr: %016llx %016llx %016llx %016llx\n",
+ data->dma1ErrorStatus, data->dma1FirstErrorStatus,
+ data->dma1ErrorLog0, data->dma1ErrorLog1);
for (i = 0; i < OPAL_PHB3_NUM_PEST_REGS; i++) {
if ((data->pestA[i] >> 63) == 0 &&
(data->pestB[i] >> 63) == 0)
continue;
- pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]);
- pr_info(" PESTB: %016llx\n", data->pestB[i]);
+ pr_info(" PE[%3d] A/B: %016llx %016llx\n",
+ i, data->pestA[i], data->pestB[i]);
}
}
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index 110f4fbd319f..61cf8fa9c61b 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -26,7 +26,6 @@
#include <linux/of_fdt.h>
#include <linux/interrupt.h>
#include <linux/bug.h>
-#include <linux/cpuidle.h>
#include <linux/pci.h>
#include <asm/machdep.h>
@@ -188,6 +187,7 @@ static void __init pnv_setup_machdep_opal(void)
ppc_md.power_off = pnv_power_off;
ppc_md.halt = pnv_halt;
ppc_md.machine_check_exception = opal_machine_check;
+ ppc_md.mce_check_early_recovery = opal_mce_check_early_recovery;
}
#ifdef CONFIG_PPC_POWERNV_RTAS
@@ -225,16 +225,6 @@ static int __init pnv_probe(void)
return 1;
}
-void powernv_idle(void)
-{
- /* Hook to cpuidle framework if available, else
- * call on default platform idle code
- */
- if (cpuidle_idle_call()) {
- power7_idle();
- }
-}
-
define_machine(powernv) {
.name = "PowerNV",
.probe = pnv_probe,
@@ -244,7 +234,7 @@ define_machine(powernv) {
.show_cpuinfo = pnv_show_cpuinfo,
.progress = pnv_progress,
.machine_shutdown = pnv_shutdown,
- .power_save = powernv_idle,
+ .power_save = power7_idle,
.calibrate_decr = generic_calibrate_decr,
.dma_set_mask = pnv_dma_set_mask,
#ifdef CONFIG_KEXEC
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index e87c19473973..56f274064d6c 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -2,10 +2,8 @@ config PPC_PS3
bool "Sony PS3"
depends on PPC64 && PPC_BOOK3S
select PPC_CELL
- select USB_ARCH_HAS_OHCI
select USB_OHCI_LITTLE_ENDIAN
select USB_OHCI_BIG_ENDIAN_MMIO
- select USB_ARCH_HAS_EHCI
select USB_EHCI_BIG_ENDIAN_MMIO
select PPC_PCI_CHOICE
help
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 4b35166229fe..b358bec6c8cb 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -76,7 +76,7 @@ static int __init ps3_smp_probe(void)
BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION != 0);
BUILD_BUG_ON(PPC_MSG_RESCHEDULE != 1);
- BUILD_BUG_ON(PPC_MSG_CALL_FUNC_SINGLE != 2);
+ BUILD_BUG_ON(PPC_MSG_TICK_BROADCAST != 2);
BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3);
for (i = 0; i < MSG_COUNT; i++) {
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 80b1d57c306a..2cb8b776c84a 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -111,6 +111,18 @@ config CMM
will be reused for other LPARs. The interface allows firmware to
balance memory across many LPARs.
+config HV_PERF_CTRS
+ bool "Hypervisor supplied PMU events (24x7 & GPCI)"
+ default y
+ depends on PERF_EVENTS && PPC_PSERIES
+ help
+ Enable access to hypervisor supplied counters in perf. Currently,
+ this enables code that uses the hcall GetPerfCounterInfo and 24x7
+ interfaces to retrieve counters. GPCI exists on Power 6 and later
+ systems. 24x7 is available on Power 8 systems.
+
+ If unsure, select Y.
+
config DTL
bool "Dispatch Trace Log"
depends on PPC_SPLPAR && DEBUG_FS
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index a8fe5aa3d34f..022b38e6a80b 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -11,7 +11,6 @@
*/
#include <linux/kernel.h>
-#include <linux/kref.h>
#include <linux/notifier.h>
#include <linux/spinlock.h>
#include <linux/cpu.h>
@@ -87,7 +86,6 @@ static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa,
}
of_node_set_flag(dn, OF_DYNAMIC);
- kref_init(&dn->kref);
return dn;
}
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 9ef3cc8ebc11..8a8f0472d98f 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -265,7 +265,7 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
enable = 1;
if (enable) {
- eeh_subsystem_enabled = 1;
+ eeh_set_enable(true);
eeh_add_to_parent_pe(edev);
pr_debug("%s: EEH enabled on %s PHB#%d-PE#%x, config addr#%x\n",
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 82789e79e539..9b8e05078a63 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -35,12 +35,7 @@
#include "offline_states.h"
/* This version can't take the spinlock, because it never returns */
-static struct rtas_args rtas_stop_self_args = {
- .token = RTAS_UNKNOWN_SERVICE,
- .nargs = 0,
- .nret = 1,
- .rets = &rtas_stop_self_args.args[0],
-};
+static int rtas_stop_self_token = RTAS_UNKNOWN_SERVICE;
static DEFINE_PER_CPU(enum cpu_state_vals, preferred_offline_state) =
CPU_STATE_OFFLINE;
@@ -93,15 +88,20 @@ void set_default_offline_state(int cpu)
static void rtas_stop_self(void)
{
- struct rtas_args *args = &rtas_stop_self_args;
+ struct rtas_args args = {
+ .token = cpu_to_be32(rtas_stop_self_token),
+ .nargs = 0,
+ .nret = 1,
+ .rets = &args.args[0],
+ };
local_irq_disable();
- BUG_ON(args->token == RTAS_UNKNOWN_SERVICE);
+ BUG_ON(rtas_stop_self_token == RTAS_UNKNOWN_SERVICE);
printk("cpu %u (hwid %u) Ready to die...\n",
smp_processor_id(), hard_smp_processor_id());
- enter_rtas(__pa(args));
+ enter_rtas(__pa(&args));
panic("Alas, I survived.\n");
}
@@ -392,10 +392,10 @@ static int __init pseries_cpu_hotplug_init(void)
}
}
- rtas_stop_self_args.token = rtas_token("stop-self");
+ rtas_stop_self_token = rtas_token("stop-self");
qcss_tok = rtas_token("query-cpu-stopped-state");
- if (rtas_stop_self_args.token == RTAS_UNKNOWN_SERVICE ||
+ if (rtas_stop_self_token == RTAS_UNKNOWN_SERVICE ||
qcss_tok == RTAS_UNKNOWN_SERVICE) {
printk(KERN_INFO "CPU Hotplug not supported by firmware "
"- disabling.\n");
@@ -420,4 +420,4 @@ static int __init pseries_cpu_hotplug_init(void)
return 0;
}
-arch_initcall(pseries_cpu_hotplug_init);
+machine_arch_initcall(pseries, pseries_cpu_hotplug_init);
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 9590dbb756f2..573b488fc48b 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -14,6 +14,7 @@
#include <linux/memblock.h>
#include <linux/vmalloc.h>
#include <linux/memory.h>
+#include <linux/memory_hotplug.h>
#include <asm/firmware.h>
#include <asm/machdep.h>
@@ -75,13 +76,27 @@ unsigned long memory_block_size_bytes(void)
}
#ifdef CONFIG_MEMORY_HOTREMOVE
-static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
+static int pseries_remove_memory(u64 start, u64 size)
{
- unsigned long start, start_pfn;
- struct zone *zone;
int ret;
- unsigned long section;
- unsigned long sections_to_remove;
+
+ /* Remove htab bolted mappings for this section of memory */
+ start = (unsigned long)__va(start);
+ ret = remove_section_mapping(start, start + size);
+
+ /* Ensure all vmalloc mappings are flushed in case they also
+ * hit that section of memory
+ */
+ vm_unmap_aliases();
+
+ return ret;
+}
+
+static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
+{
+ unsigned long block_sz, start_pfn;
+ int sections_per_block;
+ int i, nid;
start_pfn = base >> PAGE_SHIFT;
@@ -90,45 +105,21 @@ static int pseries_remove_memblock(unsigned long base, unsigned int memblock_siz
return 0;
}
- zone = page_zone(pfn_to_page(start_pfn));
+ block_sz = memory_block_size_bytes();
+ sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
+ nid = memory_add_physaddr_to_nid(base);
- /*
- * Remove section mappings and sysfs entries for the
- * section of the memory we are removing.
- *
- * NOTE: Ideally, this should be done in generic code like
- * remove_memory(). But remove_memory() gets called by writing
- * to sysfs "state" file and we can't remove sysfs entries
- * while writing to it. So we have to defer it to here.
- */
- sections_to_remove = (memblock_size >> PAGE_SHIFT) / PAGES_PER_SECTION;
- for (section = 0; section < sections_to_remove; section++) {
- unsigned long pfn = start_pfn + section * PAGES_PER_SECTION;
- ret = __remove_pages(zone, pfn, PAGES_PER_SECTION);
- if (ret)
- return ret;
+ for (i = 0; i < sections_per_block; i++) {
+ remove_memory(nid, base, MIN_MEMORY_BLOCK_SIZE);
+ base += MIN_MEMORY_BLOCK_SIZE;
}
- /*
- * Update memory regions for memory remove
- */
+ /* Update memory regions for memory remove */
memblock_remove(base, memblock_size);
-
- /*
- * Remove htab bolted mappings for this section of memory
- */
- start = (unsigned long)__va(base);
- ret = remove_section_mapping(start, start + memblock_size);
-
- /* Ensure all vmalloc mappings are flushed in case they also
- * hit that section of memory
- */
- vm_unmap_aliases();
-
- return ret;
+ return 0;
}
-static int pseries_remove_memory(struct device_node *np)
+static int pseries_remove_mem_node(struct device_node *np)
{
const char *type;
const unsigned int *regs;
@@ -153,8 +144,8 @@ static int pseries_remove_memory(struct device_node *np)
base = *(unsigned long *)regs;
lmb_size = regs[3];
- ret = pseries_remove_memblock(base, lmb_size);
- return ret;
+ pseries_remove_memblock(base, lmb_size);
+ return 0;
}
#else
static inline int pseries_remove_memblock(unsigned long base,
@@ -162,13 +153,13 @@ static inline int pseries_remove_memblock(unsigned long base,
{
return -EOPNOTSUPP;
}
-static inline int pseries_remove_memory(struct device_node *np)
+static inline int pseries_remove_mem_node(struct device_node *np)
{
return -EOPNOTSUPP;
}
#endif /* CONFIG_MEMORY_HOTREMOVE */
-static int pseries_add_memory(struct device_node *np)
+static int pseries_add_mem_node(struct device_node *np)
{
const char *type;
const unsigned int *regs;
@@ -254,10 +245,10 @@ static int pseries_memory_notifier(struct notifier_block *nb,
switch (action) {
case OF_RECONFIG_ATTACH_NODE:
- err = pseries_add_memory(node);
+ err = pseries_add_mem_node(node);
break;
case OF_RECONFIG_DETACH_NODE:
- err = pseries_remove_memory(node);
+ err = pseries_remove_mem_node(node);
break;
case OF_RECONFIG_UPDATE_PROPERTY:
pr = (struct of_prop_reconfig *)node;
@@ -277,6 +268,10 @@ static int __init pseries_memory_hotplug_init(void)
if (firmware_has_feature(FW_FEATURE_LPAR))
of_reconfig_notifier_register(&pseries_mem_nb);
+#ifdef CONFIG_MEMORY_HOTREMOVE
+ ppc_md.remove_memory = pseries_remove_memory;
+#endif
+
return 0;
}
machine_device_initcall(pseries, pseries_memory_hotplug_init);
diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
index cde4e0a095ae..bde7ebad3949 100644
--- a/arch/powerpc/platforms/pseries/mobility.c
+++ b/arch/powerpc/platforms/pseries/mobility.c
@@ -290,13 +290,6 @@ void post_mobility_fixup(void)
int rc;
int activate_fw_token;
- rc = pseries_devicetree_update(MIGRATION_SCOPE);
- if (rc) {
- printk(KERN_ERR "Initial post-mobility device tree update "
- "failed: %d\n", rc);
- return;
- }
-
activate_fw_token = rtas_token("ibm,activate-firmware");
if (activate_fw_token == RTAS_UNKNOWN_SERVICE) {
printk(KERN_ERR "Could not make post-mobility "
@@ -304,16 +297,17 @@ void post_mobility_fixup(void)
return;
}
- rc = rtas_call(activate_fw_token, 0, 1, NULL);
- if (!rc) {
- rc = pseries_devicetree_update(MIGRATION_SCOPE);
- if (rc)
- printk(KERN_ERR "Secondary post-mobility device tree "
- "update failed: %d\n", rc);
- } else {
+ do {
+ rc = rtas_call(activate_fw_token, 0, 1, NULL);
+ } while (rtas_busy_delay(rc));
+
+ if (rc)
printk(KERN_ERR "Post-mobility activate-fw failed: %d\n", rc);
- return;
- }
+
+ rc = pseries_devicetree_update(MIGRATION_SCOPE);
+ if (rc)
+ printk(KERN_ERR "Post-mobility device tree update "
+ "failed: %d\n", rc);
return;
}
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index 70670a2d9cf2..c413ec158ff5 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -113,7 +113,8 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
{
struct device_node *dn, *pdn;
struct pci_bus *bus;
- const __be32 *pcie_link_speed_stats;
+ u32 pcie_link_speed_stats[2];
+ int rc;
bus = bridge->bus;
@@ -122,38 +123,45 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
return 0;
for (pdn = dn; pdn != NULL; pdn = of_get_next_parent(pdn)) {
- pcie_link_speed_stats = of_get_property(pdn,
- "ibm,pcie-link-speed-stats", NULL);
- if (pcie_link_speed_stats)
+ rc = of_property_read_u32_array(pdn,
+ "ibm,pcie-link-speed-stats",
+ &pcie_link_speed_stats[0], 2);
+ if (!rc)
break;
}
of_node_put(pdn);
- if (!pcie_link_speed_stats) {
+ if (rc) {
pr_err("no ibm,pcie-link-speed-stats property\n");
return 0;
}
- switch (be32_to_cpup(pcie_link_speed_stats)) {
+ switch (pcie_link_speed_stats[0]) {
case 0x01:
bus->max_bus_speed = PCIE_SPEED_2_5GT;
break;
case 0x02:
bus->max_bus_speed = PCIE_SPEED_5_0GT;
break;
+ case 0x04:
+ bus->max_bus_speed = PCIE_SPEED_8_0GT;
+ break;
default:
bus->max_bus_speed = PCI_SPEED_UNKNOWN;
break;
}
- switch (be32_to_cpup(pcie_link_speed_stats)) {
+ switch (pcie_link_speed_stats[1]) {
case 0x01:
bus->cur_bus_speed = PCIE_SPEED_2_5GT;
break;
case 0x02:
bus->cur_bus_speed = PCIE_SPEED_5_0GT;
break;
+ case 0x04:
+ bus->cur_bus_speed = PCIE_SPEED_8_0GT;
+ break;
default:
bus->cur_bus_speed = PCI_SPEED_UNKNOWN;
break;
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index efe61374f6ea..203cbf0dc101 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -37,15 +37,15 @@ find_bus_among_children(struct pci_bus *bus,
struct device_node *dn)
{
struct pci_bus *child = NULL;
- struct list_head *tmp;
+ struct pci_bus *tmp;
struct device_node *busdn;
busdn = pci_bus_to_OF_node(bus);
if (busdn == dn)
return bus;
- list_for_each(tmp, &bus->children) {
- child = find_bus_among_children(pci_bus_b(tmp), dn);
+ list_for_each_entry(tmp, &bus->children, node) {
+ child = find_bus_among_children(tmp, dn);
if (child)
break;
};
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index f93cdf55628c..0435bb65d0aa 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -12,7 +12,6 @@
*/
#include <linux/kernel.h>
-#include <linux/kref.h>
#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
@@ -70,7 +69,6 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist
np->properties = proplist;
of_node_set_flag(np, OF_DYNAMIC);
- kref_init(&np->kref);
np->parent = derive_parent(path);
if (IS_ERR(np->parent)) {
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 972df0ffd4dc..2db8cc691bf4 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -39,7 +39,6 @@
#include <linux/irq.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
-#include <linux/cpuidle.h>
#include <linux/of.h>
#include <linux/kexec.h>
@@ -356,29 +355,24 @@ early_initcall(alloc_dispatch_log_kmem_cache);
static void pseries_lpar_idle(void)
{
- /* This would call on the cpuidle framework, and the back-end pseries
- * driver to go to idle states
+ /*
+ * Default handler to go into low thread priority and possibly
+ * low power mode by cedeing processor to hypervisor
*/
- if (cpuidle_idle_call()) {
- /* On error, execute default handler
- * to go into low thread priority and possibly
- * low power mode by cedeing processor to hypervisor
- */
- /* Indicate to hypervisor that we are idle. */
- get_lppaca()->idle = 1;
+ /* Indicate to hypervisor that we are idle. */
+ get_lppaca()->idle = 1;
- /*
- * Yield the processor to the hypervisor. We return if
- * an external interrupt occurs (which are driven prior
- * to returning here) or if a prod occurs from another
- * processor. When returning here, external interrupts
- * are enabled.
- */
- cede_processor();
+ /*
+ * Yield the processor to the hypervisor. We return if
+ * an external interrupt occurs (which are driven prior
+ * to returning here) or if a prod occurs from another
+ * processor. When returning here, external interrupts
+ * are enabled.
+ */
+ cede_processor();
- get_lppaca()->idle = 0;
- }
+ get_lppaca()->idle = 0;
}
/*
diff --git a/arch/powerpc/platforms/pseries/suspend.c b/arch/powerpc/platforms/pseries/suspend.c
index 16a255255d30..b87b97849d4c 100644
--- a/arch/powerpc/platforms/pseries/suspend.c
+++ b/arch/powerpc/platforms/pseries/suspend.c
@@ -26,6 +26,7 @@
#include <asm/mmu.h>
#include <asm/rtas.h>
#include <asm/topology.h>
+#include "../../kernel/cacheinfo.h"
static u64 stream_id;
static struct device suspend_dev;
@@ -79,6 +80,23 @@ static int pseries_suspend_cpu(void)
}
/**
+ * pseries_suspend_enable_irqs
+ *
+ * Post suspend configuration updates
+ *
+ **/
+static void pseries_suspend_enable_irqs(void)
+{
+ /*
+ * Update configuration which can be modified based on device tree
+ * changes during resume.
+ */
+ cacheinfo_cpu_offline(smp_processor_id());
+ post_mobility_fixup();
+ cacheinfo_cpu_online(smp_processor_id());
+}
+
+/**
* pseries_suspend_enter - Final phase of hibernation
*
* Return value:
@@ -174,7 +192,30 @@ out:
return rc;
}
-static DEVICE_ATTR(hibernate, S_IWUSR, NULL, store_hibernate);
+#define USER_DT_UPDATE 0
+#define KERN_DT_UPDATE 1
+
+/**
+ * show_hibernate - Report device tree update responsibilty
+ * @dev: subsys root device
+ * @attr: device attribute struct
+ * @buf: buffer
+ *
+ * Report whether a device tree update is performed by the kernel after a
+ * resume, or if drmgr must coordinate the update from user space.
+ *
+ * Return value:
+ * 0 if drmgr is to initiate update, and 1 otherwise
+ **/
+static ssize_t show_hibernate(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", KERN_DT_UPDATE);
+}
+
+static DEVICE_ATTR(hibernate, S_IWUSR | S_IRUGO,
+ show_hibernate, store_hibernate);
static struct bus_type suspend_subsys = {
.name = "power",
@@ -235,6 +276,7 @@ static int __init pseries_suspend_init(void)
return rc;
ppc_md.suspend_disable_cpu = pseries_suspend_cpu;
+ ppc_md.suspend_enable_irqs = pseries_suspend_enable_irqs;
suspend_set_ops(&pseries_suspend_ops);
return 0;
}
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index f67ac900d870..afbcc37aa094 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -21,7 +21,6 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o fsl_mpic_err.o
obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y)
obj-$(CONFIG_FSL_PMC) += fsl_pmc.o
obj-$(CONFIG_FSL_LBC) += fsl_lbc.o
-obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_FSL_GTM) += fsl_gtm.o
obj-$(CONFIG_FSL_85XX_CACHE_SRAM) += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o
diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c
index b74085cea1af..2d20f10a4203 100644
--- a/arch/powerpc/sysdev/ehv_pic.c
+++ b/arch/powerpc/sysdev/ehv_pic.c
@@ -28,8 +28,6 @@
#include <asm/ehv_pic.h>
#include <asm/fsl_hcalls.h>
-#include "../../../kernel/irq/settings.h"
-
static struct ehv_pic *global_ehv_pic;
static DEFINE_SPINLOCK(ehv_pic_lock);
@@ -113,17 +111,13 @@ static unsigned int ehv_pic_type_to_vecpri(unsigned int type)
int ehv_pic_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
unsigned int src = virq_to_hw(d->irq);
- struct irq_desc *desc = irq_to_desc(d->irq);
unsigned int vecpri, vold, vnew, prio, cpu_dest;
unsigned long flags;
if (flow_type == IRQ_TYPE_NONE)
flow_type = IRQ_TYPE_LEVEL_LOW;
- irq_settings_clr_level(desc);
- irq_settings_set_trigger_mask(desc, flow_type);
- if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
- irq_settings_set_level(desc);
+ irqd_set_trigger_type(d, flow_type);
vecpri = ehv_pic_type_to_vecpri(flow_type);
@@ -144,7 +138,7 @@ int ehv_pic_set_irq_type(struct irq_data *d, unsigned int flow_type)
ev_int_set_config(src, vecpri, prio, cpu_dest);
spin_unlock_irqrestore(&ehv_pic_lock, flags);
- return 0;
+ return IRQ_SET_MASK_OK_NOCOPY;
}
static struct irq_chip ehv_pic_irq_chip = {
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index a625dcf26b2b..3f415e252ea5 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -22,10 +22,13 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/bootmem.h>
#include <linux/memblock.h>
#include <linux/log2.h>
#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/syscore_ops.h>
#include <linux/uaccess.h>
#include <asm/io.h>
@@ -868,6 +871,14 @@ u64 fsl_pci_immrbar_base(struct pci_controller *hose)
pci_bus_read_config_dword(hose->bus,
PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base);
+
+ /*
+ * For PEXCSRBAR, bit 3-0 indicate prefetchable and
+ * address type. So when getting base address, these
+ * bits should be masked
+ */
+ base &= PCI_BASE_ADDRESS_MEM_MASK;
+
return base;
}
#endif
@@ -1086,55 +1097,171 @@ void fsl_pci_assign_primary(void)
}
}
-static int fsl_pci_probe(struct platform_device *pdev)
+#ifdef CONFIG_PM_SLEEP
+static irqreturn_t fsl_pci_pme_handle(int irq, void *dev_id)
{
- int ret;
- struct device_node *node;
+ struct pci_controller *hose = dev_id;
+ struct ccsr_pci __iomem *pci = hose->private_data;
+ u32 dr;
- node = pdev->dev.of_node;
- ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
+ dr = in_be32(&pci->pex_pme_mes_dr);
+ if (!dr)
+ return IRQ_NONE;
- mpc85xx_pci_err_probe(pdev);
+ out_be32(&pci->pex_pme_mes_dr, dr);
- return 0;
+ return IRQ_HANDLED;
}
-#ifdef CONFIG_PM
-static int fsl_pci_resume(struct device *dev)
+static int fsl_pci_pme_probe(struct pci_controller *hose)
{
- struct pci_controller *hose;
- struct resource pci_rsrc;
+ struct ccsr_pci __iomem *pci;
+ struct pci_dev *dev;
+ int pme_irq;
+ int res;
+ u16 pms;
- hose = pci_find_hose_for_OF_device(dev->of_node);
- if (!hose)
- return -ENODEV;
+ /* Get hose's pci_dev */
+ dev = list_first_entry(&hose->bus->devices, typeof(*dev), bus_list);
+
+ /* PME Disable */
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pms);
+ pms &= ~PCI_PM_CTRL_PME_ENABLE;
+ pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pms);
+
+ pme_irq = irq_of_parse_and_map(hose->dn, 0);
+ if (!pme_irq) {
+ dev_err(&dev->dev, "Failed to map PME interrupt.\n");
+
+ return -ENXIO;
+ }
+
+ res = devm_request_irq(hose->parent, pme_irq,
+ fsl_pci_pme_handle,
+ IRQF_SHARED,
+ "[PCI] PME", hose);
+ if (res < 0) {
+ dev_err(&dev->dev, "Unable to requiest irq %d for PME\n", pme_irq);
+ irq_dispose_mapping(pme_irq);
- if (of_address_to_resource(dev->of_node, 0, &pci_rsrc)) {
- dev_err(dev, "Get pci register base failed.");
return -ENODEV;
}
- setup_pci_atmu(hose);
+ pci = hose->private_data;
+
+ /* Enable PTOD, ENL23D & EXL23D */
+ out_be32(&pci->pex_pme_mes_disr, 0);
+ setbits32(&pci->pex_pme_mes_disr,
+ PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D);
+
+ out_be32(&pci->pex_pme_mes_ier, 0);
+ setbits32(&pci->pex_pme_mes_ier,
+ PME_DISR_EN_PTOD | PME_DISR_EN_ENL23D | PME_DISR_EN_EXL23D);
+
+ /* PME Enable */
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pms);
+ pms |= PCI_PM_CTRL_PME_ENABLE;
+ pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pms);
return 0;
}
-static const struct dev_pm_ops pci_pm_ops = {
- .resume = fsl_pci_resume,
-};
+static void send_pme_turnoff_message(struct pci_controller *hose)
+{
+ struct ccsr_pci __iomem *pci = hose->private_data;
+ u32 dr;
+ int i;
-#define PCI_PM_OPS (&pci_pm_ops)
+ /* Send PME_Turn_Off Message Request */
+ setbits32(&pci->pex_pmcr, PEX_PMCR_PTOMR);
-#else
+ /* Wait trun off done */
+ for (i = 0; i < 150; i++) {
+ dr = in_be32(&pci->pex_pme_mes_dr);
+ if (dr) {
+ out_be32(&pci->pex_pme_mes_dr, dr);
+ break;
+ }
+
+ udelay(1000);
+ }
+}
+
+static void fsl_pci_syscore_do_suspend(struct pci_controller *hose)
+{
+ send_pme_turnoff_message(hose);
+}
+
+static int fsl_pci_syscore_suspend(void)
+{
+ struct pci_controller *hose, *tmp;
-#define PCI_PM_OPS NULL
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+ fsl_pci_syscore_do_suspend(hose);
+ return 0;
+}
+
+static void fsl_pci_syscore_do_resume(struct pci_controller *hose)
+{
+ struct ccsr_pci __iomem *pci = hose->private_data;
+ u32 dr;
+ int i;
+
+ /* Send Exit L2 State Message */
+ setbits32(&pci->pex_pmcr, PEX_PMCR_EXL2S);
+
+ /* Wait exit done */
+ for (i = 0; i < 150; i++) {
+ dr = in_be32(&pci->pex_pme_mes_dr);
+ if (dr) {
+ out_be32(&pci->pex_pme_mes_dr, dr);
+ break;
+ }
+
+ udelay(1000);
+ }
+
+ setup_pci_atmu(hose);
+}
+
+static void fsl_pci_syscore_resume(void)
+{
+ struct pci_controller *hose, *tmp;
+
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+ fsl_pci_syscore_do_resume(hose);
+}
+
+static struct syscore_ops pci_syscore_pm_ops = {
+ .suspend = fsl_pci_syscore_suspend,
+ .resume = fsl_pci_syscore_resume,
+};
#endif
+void fsl_pcibios_fixup_phb(struct pci_controller *phb)
+{
+#ifdef CONFIG_PM_SLEEP
+ fsl_pci_pme_probe(phb);
+#endif
+}
+
+static int fsl_pci_probe(struct platform_device *pdev)
+{
+ struct device_node *node;
+ int ret;
+
+ node = pdev->dev.of_node;
+ ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
+
+ mpc85xx_pci_err_probe(pdev);
+
+ return 0;
+}
+
static struct platform_driver fsl_pci_driver = {
.driver = {
.name = "fsl-pci",
- .pm = PCI_PM_OPS,
.of_match_table = pci_ids,
},
.probe = fsl_pci_probe,
@@ -1142,6 +1269,9 @@ static struct platform_driver fsl_pci_driver = {
static int __init fsl_pci_init(void)
{
+#ifdef CONFIG_PM_SLEEP
+ register_syscore_ops(&pci_syscore_pm_ops);
+#endif
return platform_driver_register(&fsl_pci_driver);
}
arch_initcall(fsl_pci_init);
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index 8d455df58471..c1cec771d5ea 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -32,6 +32,13 @@ struct platform_device;
#define PIWAR_WRITE_SNOOP 0x00005000
#define PIWAR_SZ_MASK 0x0000003f
+#define PEX_PMCR_PTOMR 0x1
+#define PEX_PMCR_EXL2S 0x2
+
+#define PME_DISR_EN_PTOD 0x00008000
+#define PME_DISR_EN_ENL23D 0x00002000
+#define PME_DISR_EN_EXL23D 0x00001000
+
/* PCI/PCI Express outbound window reg */
struct pci_outbound_window_regs {
__be32 potar; /* 0x.0 - Outbound translation address register */
@@ -111,6 +118,7 @@ struct ccsr_pci {
extern int fsl_add_bridge(struct platform_device *pdev, int is_primary);
extern void fsl_pcibios_fixup_bus(struct pci_bus *bus);
+extern void fsl_pcibios_fixup_phb(struct pci_controller *phb);
extern int mpc83xx_add_bridge(struct device_node *dev);
u64 fsl_pci_immrbar_base(struct pci_controller *hose);
diff --git a/arch/powerpc/sysdev/msi_bitmap.c b/arch/powerpc/sysdev/msi_bitmap.c
index 0968b66b4cf9..8ba60424be95 100644
--- a/arch/powerpc/sysdev/msi_bitmap.c
+++ b/arch/powerpc/sysdev/msi_bitmap.c
@@ -202,7 +202,7 @@ void __init test_of_node(void)
/* There should really be a struct device_node allocator */
memset(&of_node, 0, sizeof(of_node));
- kref_init(&of_node.kref);
+ kref_init(&of_node.kobj.kref);
of_node.full_name = node_name;
check(0 == msi_bitmap_alloc(&bmp, size, &of_node));
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index b07909850f77..08504e75b2c7 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -171,7 +171,11 @@ extern void xmon_leave(void);
#define REG "%.8lx"
#endif
+#ifdef __LITTLE_ENDIAN__
+#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
+#else
#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
+#endif
#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
|| ('a' <= (c) && (c) <= 'f') \
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 65a07750f4f9..953f17c8d17c 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -117,6 +117,7 @@ config S390
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+ select HAVE_FUTEX_CMPXCHG if FUTEX
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZ4
@@ -140,6 +141,7 @@ config S390
select OLD_SIGACTION
select OLD_SIGSUSPEND3
select SYSCTL_EXCEPTION_TRACE
+ select TTY
select VIRT_CPU_ACCOUNTING
select VIRT_TO_BUS
@@ -415,6 +417,10 @@ config ARCH_ENABLE_MEMORY_HOTPLUG
config ARCH_ENABLE_MEMORY_HOTREMOVE
def_bool y
+config ARCH_ENABLE_SPLIT_PMD_PTLOCK
+ def_bool y
+ depends on 64BIT
+
config FORCE_MAX_ZONEORDER
int
default "9"
diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c
index de8e2b3b0180..69b23b25ac34 100644
--- a/arch/s390/appldata/appldata_os.c
+++ b/arch/s390/appldata/appldata_os.c
@@ -171,7 +171,7 @@ static int __init appldata_os_init(void)
int rc, max_size;
max_size = sizeof(struct appldata_os_data) +
- (NR_CPUS * sizeof(struct appldata_os_per_cpu));
+ (num_possible_cpus() * sizeof(struct appldata_os_per_cpu));
if (max_size > APPLDATA_MAX_REC_SIZE) {
pr_err("Maximum OS record size %i exceeds the maximum "
"record size %i\n", max_size, APPLDATA_MAX_REC_SIZE);
diff --git a/arch/s390/configs/default_defconfig b/arch/s390/configs/default_defconfig
index e0af2ee58751..ddaae2f5c913 100644
--- a/arch/s390/configs/default_defconfig
+++ b/arch/s390/configs/default_defconfig
@@ -46,6 +46,7 @@ CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_CFQ_GROUP_IOSCHED=y
CONFIG_DEFAULT_DEADLINE=y
CONFIG_MARCH_Z9_109=y
+CONFIG_NR_CPUS=256
CONFIG_PREEMPT=y
CONFIG_HZ_100=y
CONFIG_MEMORY_HOTPLUG=y
@@ -58,7 +59,6 @@ CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_S390=y
CONFIG_CHSC_SCH=y
CONFIG_CRASH_DUMP=y
-CONFIG_ZFCPDUMP=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=m
CONFIG_HIBERNATION=y
@@ -101,7 +101,6 @@ CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
@@ -111,6 +110,7 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
CONFIG_INET6_XFRM_MODE_BEET=m
CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_VTI=m
CONFIG_IPV6_SIT=m
CONFIG_IPV6_GRE=m
CONFIG_IPV6_MULTIPLE_TABLES=y
@@ -135,7 +135,17 @@ CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
CONFIG_NF_CT_NETLINK_TIMEOUT=m
-CONFIG_NETFILTER_TPROXY=m
+CONFIG_NF_TABLES=m
+CONFIG_NFT_EXTHDR=m
+CONFIG_NFT_META=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_RBTREE=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_AUDIT=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -204,7 +214,9 @@ CONFIG_IP_SET_HASH_IP=m
CONFIG_IP_SET_HASH_IPPORT=m
CONFIG_IP_SET_HASH_IPPORTIP=m
CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
@@ -227,6 +239,11 @@ CONFIG_IP_VS_FTP=m
CONFIG_IP_VS_PE_SIP=m
CONFIG_NF_CONNTRACK_IPV4=m
# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_NF_TABLES_IPV4=m
+CONFIG_NFT_REJECT_IPV4=m
+CONFIG_NFT_CHAIN_ROUTE_IPV4=m
+CONFIG_NFT_CHAIN_NAT_IPV4=m
+CONFIG_NF_TABLES_ARP=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
@@ -249,6 +266,9 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_NF_TABLES_IPV6=m
+CONFIG_NFT_CHAIN_ROUTE_IPV6=m
+CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m
@@ -268,6 +288,7 @@ CONFIG_IP6_NF_SECURITY=m
CONFIG_NF_NAT_IPV6=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
CONFIG_NET_SCTPPROBE=m
CONFIG_RDS=m
CONFIG_RDS_RDMA=m
@@ -314,6 +335,7 @@ CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_FLOW=m
CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_CLS_BPF=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=m
CONFIG_NET_ACT_GACT=m
@@ -381,8 +403,8 @@ CONFIG_BLK_DEV_DM=m
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
-CONFIG_DM_RAID=m
CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_MULTIPATH_QL=m
@@ -434,7 +456,6 @@ CONFIG_TN3270_FS=y
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
CONFIG_SOFT_WATCHDOG=m
-CONFIG_ZVM_WATCHDOG=m
# CONFIG_HID is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_INFINIBAND=m
@@ -534,13 +555,23 @@ CONFIG_UNUSED_SYMBOLS=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_SELFTEST=y
+CONFIG_DEBUG_OBJECTS_FREE=y
+CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_OBJECTS_WORK=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
CONFIG_SLUB_DEBUG_ON=y
CONFIG_SLUB_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_VM=y
CONFIG_DEBUG_VM_RB=y
CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
CONFIG_DEBUG_PER_CPU_MAPS=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_HUNG_TASK=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_RT_MUTEX_TESTER=y
@@ -573,9 +604,11 @@ CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
CONFIG_BLK_DEV_IO_TRACE=y
# CONFIG_KPROBE_EVENT is not set
CONFIG_LKDTM=m
+CONFIG_TEST_LIST_SORT=y
CONFIG_KPROBES_SANITY_TEST=y
-CONFIG_RBTREE_TEST=m
+CONFIG_RBTREE_TEST=y
CONFIG_INTERVAL_TREE_TEST=m
+CONFIG_PERCPU_TEST=m
CONFIG_ATOMIC64_SELFTEST=y
CONFIG_DMA_API_DEBUG=y
# CONFIG_STRICT_DEVMEM is not set
@@ -638,7 +671,6 @@ CONFIG_CRYPTO_AES_S390=m
CONFIG_CRYPTO_GHASH_S390=m
CONFIG_ASYMMETRIC_KEY_TYPE=m
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m
-CONFIG_PUBLIC_KEY_ALGO_RSA=m
CONFIG_X509_CERTIFICATE_PARSER=m
CONFIG_CRC7=m
CONFIG_CRC8=m
diff --git a/arch/s390/configs/gcov_defconfig b/arch/s390/configs/gcov_defconfig
index b9f6b4cab927..c81a74e3e25a 100644
--- a/arch/s390/configs/gcov_defconfig
+++ b/arch/s390/configs/gcov_defconfig
@@ -46,6 +46,7 @@ CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_CFQ_GROUP_IOSCHED=y
CONFIG_DEFAULT_DEADLINE=y
CONFIG_MARCH_Z9_109=y
+CONFIG_NR_CPUS=256
CONFIG_HZ_100=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTREMOVE=y
@@ -56,7 +57,6 @@ CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_S390=y
CONFIG_CHSC_SCH=y
CONFIG_CRASH_DUMP=y
-CONFIG_ZFCPDUMP=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=m
CONFIG_HIBERNATION=y
@@ -99,7 +99,6 @@ CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
@@ -109,6 +108,7 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
CONFIG_INET6_XFRM_MODE_BEET=m
CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_VTI=m
CONFIG_IPV6_SIT=m
CONFIG_IPV6_GRE=m
CONFIG_IPV6_MULTIPLE_TABLES=y
@@ -133,7 +133,17 @@ CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
CONFIG_NF_CT_NETLINK_TIMEOUT=m
-CONFIG_NETFILTER_TPROXY=m
+CONFIG_NF_TABLES=m
+CONFIG_NFT_EXTHDR=m
+CONFIG_NFT_META=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_RBTREE=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_AUDIT=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -202,7 +212,9 @@ CONFIG_IP_SET_HASH_IP=m
CONFIG_IP_SET_HASH_IPPORT=m
CONFIG_IP_SET_HASH_IPPORTIP=m
CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
@@ -225,6 +237,11 @@ CONFIG_IP_VS_FTP=m
CONFIG_IP_VS_PE_SIP=m
CONFIG_NF_CONNTRACK_IPV4=m
# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_NF_TABLES_IPV4=m
+CONFIG_NFT_REJECT_IPV4=m
+CONFIG_NFT_CHAIN_ROUTE_IPV4=m
+CONFIG_NFT_CHAIN_NAT_IPV4=m
+CONFIG_NF_TABLES_ARP=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
@@ -247,6 +264,9 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_NF_TABLES_IPV6=m
+CONFIG_NFT_CHAIN_ROUTE_IPV6=m
+CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m
@@ -266,6 +286,7 @@ CONFIG_IP6_NF_SECURITY=m
CONFIG_NF_NAT_IPV6=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
CONFIG_NET_SCTPPROBE=m
CONFIG_RDS=m
CONFIG_RDS_RDMA=m
@@ -311,6 +332,7 @@ CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_FLOW=m
CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_CLS_BPF=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=m
CONFIG_NET_ACT_GACT=m
@@ -378,8 +400,8 @@ CONFIG_BLK_DEV_DM=m
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
-CONFIG_DM_RAID=m
CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_MULTIPATH_QL=m
@@ -431,7 +453,6 @@ CONFIG_TN3270_FS=y
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
CONFIG_SOFT_WATCHDOG=m
-CONFIG_ZVM_WATCHDOG=m
# CONFIG_HID is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_INFINIBAND=m
@@ -540,6 +561,7 @@ CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_LKDTM=m
CONFIG_RBTREE_TEST=m
CONFIG_INTERVAL_TREE_TEST=m
+CONFIG_PERCPU_TEST=m
CONFIG_ATOMIC64_SELFTEST=y
# CONFIG_STRICT_DEVMEM is not set
CONFIG_S390_PTDUMP=y
@@ -601,7 +623,6 @@ CONFIG_CRYPTO_AES_S390=m
CONFIG_CRYPTO_GHASH_S390=m
CONFIG_ASYMMETRIC_KEY_TYPE=m
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m
-CONFIG_PUBLIC_KEY_ALGO_RSA=m
CONFIG_X509_CERTIFICATE_PARSER=m
CONFIG_CRC7=m
CONFIG_CRC8=m
diff --git a/arch/s390/configs/performance_defconfig b/arch/s390/configs/performance_defconfig
index 91087b43e8fa..b5ba8fe1cc64 100644
--- a/arch/s390/configs/performance_defconfig
+++ b/arch/s390/configs/performance_defconfig
@@ -44,6 +44,7 @@ CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_CFQ_GROUP_IOSCHED=y
CONFIG_DEFAULT_DEADLINE=y
CONFIG_MARCH_Z9_109=y
+CONFIG_NR_CPUS=256
CONFIG_HZ_100=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTREMOVE=y
@@ -54,7 +55,6 @@ CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_S390=y
CONFIG_CHSC_SCH=y
CONFIG_CRASH_DUMP=y
-CONFIG_ZFCPDUMP=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=m
CONFIG_HIBERNATION=y
@@ -97,7 +97,6 @@ CONFIG_TCP_CONG_VENO=m
CONFIG_TCP_CONG_YEAH=m
CONFIG_TCP_CONG_ILLINOIS=m
CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
@@ -107,6 +106,7 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
CONFIG_INET6_XFRM_MODE_BEET=m
CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_VTI=m
CONFIG_IPV6_SIT=m
CONFIG_IPV6_GRE=m
CONFIG_IPV6_MULTIPLE_TABLES=y
@@ -131,7 +131,17 @@ CONFIG_NF_CONNTRACK_SIP=m
CONFIG_NF_CONNTRACK_TFTP=m
CONFIG_NF_CT_NETLINK=m
CONFIG_NF_CT_NETLINK_TIMEOUT=m
-CONFIG_NETFILTER_TPROXY=m
+CONFIG_NF_TABLES=m
+CONFIG_NFT_EXTHDR=m
+CONFIG_NFT_META=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_RBTREE=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_COUNTER=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_COMPAT=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_AUDIT=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
@@ -200,7 +210,9 @@ CONFIG_IP_SET_HASH_IP=m
CONFIG_IP_SET_HASH_IPPORT=m
CONFIG_IP_SET_HASH_IPPORTIP=m
CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
@@ -223,6 +235,11 @@ CONFIG_IP_VS_FTP=m
CONFIG_IP_VS_PE_SIP=m
CONFIG_NF_CONNTRACK_IPV4=m
# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_NF_TABLES_IPV4=m
+CONFIG_NFT_REJECT_IPV4=m
+CONFIG_NFT_CHAIN_ROUTE_IPV4=m
+CONFIG_NFT_CHAIN_NAT_IPV4=m
+CONFIG_NF_TABLES_ARP=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
@@ -245,6 +262,9 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_NF_TABLES_IPV6=m
+CONFIG_NFT_CHAIN_ROUTE_IPV6=m
+CONFIG_NFT_CHAIN_NAT_IPV6=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m
@@ -264,6 +284,7 @@ CONFIG_IP6_NF_SECURITY=m
CONFIG_NF_NAT_IPV6=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_IP6_NF_TARGET_NPT=m
+CONFIG_NF_TABLES_BRIDGE=m
CONFIG_NET_SCTPPROBE=m
CONFIG_RDS=m
CONFIG_RDS_RDMA=m
@@ -309,6 +330,7 @@ CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_FLOW=m
CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_CLS_BPF=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=m
CONFIG_NET_ACT_GACT=m
@@ -376,8 +398,8 @@ CONFIG_BLK_DEV_DM=m
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
-CONFIG_DM_RAID=m
CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_MULTIPATH_QL=m
@@ -429,7 +451,6 @@ CONFIG_TN3270_FS=y
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
CONFIG_SOFT_WATCHDOG=m
-CONFIG_ZVM_WATCHDOG=m
# CONFIG_HID is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_INFINIBAND=m
@@ -532,6 +553,7 @@ CONFIG_LATENCYTOP=y
CONFIG_BLK_DEV_IO_TRACE=y
# CONFIG_KPROBE_EVENT is not set
CONFIG_LKDTM=m
+CONFIG_PERCPU_TEST=m
CONFIG_ATOMIC64_SELFTEST=y
# CONFIG_STRICT_DEVMEM is not set
CONFIG_S390_PTDUMP=y
@@ -593,7 +615,6 @@ CONFIG_CRYPTO_AES_S390=m
CONFIG_CRYPTO_GHASH_S390=m
CONFIG_ASYMMETRIC_KEY_TYPE=m
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m
-CONFIG_PUBLIC_KEY_ALGO_RSA=m
CONFIG_X509_CERTIFICATE_PARSER=m
CONFIG_CRC7=m
CONFIG_CRC8=m
diff --git a/arch/s390/configs/zfcpdump_defconfig b/arch/s390/configs/zfcpdump_defconfig
index d725c4d956e4..cef073ca1f07 100644
--- a/arch/s390/configs/zfcpdump_defconfig
+++ b/arch/s390/configs/zfcpdump_defconfig
@@ -19,7 +19,6 @@ CONFIG_HZ_100=y
# CONFIG_CHSC_SCH is not set
# CONFIG_SCM_BUS is not set
CONFIG_CRASH_DUMP=y
-CONFIG_ZFCPDUMP=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_SECCOMP is not set
# CONFIG_IUCV is not set
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 33f57514f424..4557cb7ffddf 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -40,6 +40,7 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_IBM_PARTITION=y
CONFIG_DEFAULT_DEADLINE=y
CONFIG_MARCH_Z196=y
+CONFIG_NR_CPUS=256
CONFIG_HZ_100=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTREMOVE=y
@@ -122,22 +123,31 @@ CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_HUGETLBFS=y
# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DETECT_HUNG_TASK=y
CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_PROVE_LOCKING=y
CONFIG_LOCK_STAT=y
CONFIG_DEBUG_LOCKDEP=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_WRITECOUNT=y
CONFIG_DEBUG_LIST=y
+CONFIG_DEBUG_SG=y
CONFIG_DEBUG_NOTIFIERS=y
CONFIG_PROVE_RCU=y
CONFIG_RCU_CPU_STALL_TIMEOUT=60
CONFIG_RCU_TRACE=y
CONFIG_LATENCYTOP=y
+CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_KPROBES_SANITY_TEST=y
# CONFIG_STRICT_DEVMEM is not set
+CONFIG_S390_PTDUMP=y
CONFIG_CRYPTO_CRYPTD=m
CONFIG_CRYPTO_AUTHENC=m
CONFIG_CRYPTO_TEST=m
diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c
index 24908ce149f1..32040ace00ea 100644
--- a/arch/s390/hypfs/hypfs_vm.c
+++ b/arch/s390/hypfs/hypfs_vm.c
@@ -32,7 +32,7 @@ struct diag2fc_data {
__u32 pcpus;
__u32 lcpus;
__u32 vcpus;
- __u32 cpu_min;
+ __u32 ocpus;
__u32 cpu_max;
__u32 cpu_shares;
__u32 cpu_use_samp;
@@ -142,7 +142,12 @@ static int hpyfs_vm_create_guest(struct dentry *systems_dir,
ATTRIBUTE(cpus_dir, "capped", capped_value);
ATTRIBUTE(cpus_dir, "dedicated", dedicated_flag);
ATTRIBUTE(cpus_dir, "count", data->vcpus);
- ATTRIBUTE(cpus_dir, "weight_min", data->cpu_min);
+ /*
+ * Note: The "weight_min" attribute got the wrong name.
+ * The value represents the number of non-stopped (operating)
+ * CPUS.
+ */
+ ATTRIBUTE(cpus_dir, "weight_min", data->ocpus);
ATTRIBUTE(cpus_dir, "weight_max", data->cpu_max);
ATTRIBUTE(cpus_dir, "weight_cur", data->cpu_shares);
diff --git a/arch/s390/include/asm/Kbuild b/arch/s390/include/asm/Kbuild
index 8386a4a1f19a..57892a8a9055 100644
--- a/arch/s390/include/asm/Kbuild
+++ b/arch/s390/include/asm/Kbuild
@@ -1,6 +1,7 @@
generic-y += clkdev.h
-generic-y += trace_clock.h
-generic-y += preempt.h
generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
+generic-y += trace_clock.h
diff --git a/arch/s390/include/asm/airq.h b/arch/s390/include/asm/airq.h
index 4bbb5957ed1b..bd93ff6661b8 100644
--- a/arch/s390/include/asm/airq.h
+++ b/arch/s390/include/asm/airq.h
@@ -44,11 +44,21 @@ struct airq_iv {
struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags);
void airq_iv_release(struct airq_iv *iv);
-unsigned long airq_iv_alloc_bit(struct airq_iv *iv);
-void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit);
+unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num);
+void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num);
unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start,
unsigned long end);
+static inline unsigned long airq_iv_alloc_bit(struct airq_iv *iv)
+{
+ return airq_iv_alloc(iv, 1);
+}
+
+static inline void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit)
+{
+ airq_iv_free(iv, bit, 1);
+}
+
static inline unsigned long airq_iv_end(struct airq_iv *iv)
{
return iv->end;
diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h
index 6e6ad0680829..ec5ef891db6b 100644
--- a/arch/s390/include/asm/bitops.h
+++ b/arch/s390/include/asm/bitops.h
@@ -13,9 +13,9 @@
*
* The bitop functions are defined to work on unsigned longs, so for an
* s390x system the bits end up numbered:
- * |63..............0|127............64|191...........128|255...........196|
+ * |63..............0|127............64|191...........128|255...........192|
* and on s390:
- * |31.....0|63....31|95....64|127...96|159..128|191..160|223..192|255..224|
+ * |31.....0|63....32|95....64|127...96|159..128|191..160|223..192|255..224|
*
* There are a few little-endian macros used mostly for filesystem
* bitmaps, these work on similar bit arrays layouts, but
@@ -30,7 +30,7 @@
* on an s390x system the bits are numbered:
* |0..............63|64............127|128...........191|192...........255|
* and on s390:
- * |0.....31|31....63|64....95|96...127|128..159|160..191|192..223|224..255|
+ * |0.....31|32....63|64....95|96...127|128..159|160..191|192..223|224..255|
*
* The main difference is that bit 0-63 (64b) or 0-31 (32b) in the bit
* number field needs to be reversed compared to the LSB0 encoded bit
@@ -304,7 +304,7 @@ static inline int test_bit(unsigned long nr, const volatile unsigned long *ptr)
* On an s390x system the bits are numbered:
* |0..............63|64............127|128...........191|192...........255|
* and on s390:
- * |0.....31|31....63|64....95|96...127|128..159|160..191|192..223|224..255|
+ * |0.....31|32....63|64....95|96...127|128..159|160..191|192..223|224..255|
*/
unsigned long find_first_bit_inv(const unsigned long *addr, unsigned long size);
unsigned long find_next_bit_inv(const unsigned long *addr, unsigned long size,
diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h
index f201af8be580..a9c2c0686177 100644
--- a/arch/s390/include/asm/ccwdev.h
+++ b/arch/s390/include/asm/ccwdev.h
@@ -219,7 +219,9 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
#define to_ccwdev(n) container_of(n, struct ccw_device, dev)
#define to_ccwdrv(n) container_of(n, struct ccw_driver, driver)
-extern struct ccw_device *ccw_device_probe_console(void);
+extern struct ccw_device *ccw_device_create_console(struct ccw_driver *);
+extern void ccw_device_destroy_console(struct ccw_device *);
+extern int ccw_device_enable_console(struct ccw_device *);
extern void ccw_device_wait_idle(struct ccw_device *);
extern int ccw_device_force_console(struct ccw_device *);
diff --git a/arch/s390/include/asm/ccwgroup.h b/arch/s390/include/asm/ccwgroup.h
index 23723ce5ca7a..6e670f88d125 100644
--- a/arch/s390/include/asm/ccwgroup.h
+++ b/arch/s390/include/asm/ccwgroup.h
@@ -23,6 +23,7 @@ struct ccwgroup_device {
unsigned int count;
struct device dev;
struct ccw_device *cdev[0];
+ struct work_struct ungroup_work;
};
/**
diff --git a/arch/s390/include/asm/checksum.h b/arch/s390/include/asm/checksum.h
index 4f57a4f3909a..740364856355 100644
--- a/arch/s390/include/asm/checksum.h
+++ b/arch/s390/include/asm/checksum.h
@@ -44,22 +44,15 @@ csum_partial(const void *buff, int len, __wsum sum)
* here even more important to align src and dst on a 32-bit (or even
* better 64-bit) boundary
*
- * Copy from userspace and compute checksum. If we catch an exception
- * then zero the rest of the buffer.
+ * Copy from userspace and compute checksum.
*/
static inline __wsum
csum_partial_copy_from_user(const void __user *src, void *dst,
int len, __wsum sum,
int *err_ptr)
{
- int missing;
-
- missing = copy_from_user(dst, src, len);
- if (missing) {
- memset(dst + len - missing, 0, missing);
+ if (unlikely(copy_from_user(dst, src, len)))
*err_ptr = -EFAULT;
- }
-
return csum_partial(dst, len, sum);
}
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index 5d7e8cf83bd6..d350ed9d0fbb 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -8,7 +8,11 @@
#include <linux/thread_info.h>
#define __TYPE_IS_PTR(t) (!__builtin_types_compatible_p(typeof(0?(t)0:0ULL), u64))
-#define __SC_DELOUSE(t,v) (t)(__TYPE_IS_PTR(t) ? ((v) & 0x7fffffff) : (v))
+
+#define __SC_DELOUSE(t,v) ({ \
+ BUILD_BUG_ON(sizeof(t) > 4 && !__TYPE_IS_PTR(t)); \
+ (t)(__TYPE_IS_PTR(t) ? ((v) & 0x7fffffff) : (v)); \
+})
#define PSW32_MASK_PER 0x40000000UL
#define PSW32_MASK_DAT 0x04000000UL
diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
index 51bcaa0fdeef..fda46bd38c99 100644
--- a/arch/s390/include/asm/futex.h
+++ b/arch/s390/include/asm/futex.h
@@ -5,7 +5,10 @@
#include <linux/uaccess.h>
#include <asm/errno.h>
-static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval);
+int __futex_atomic_op_inuser(int op, u32 __user *uaddr, int oparg, int *old);
+
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
@@ -17,7 +20,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
oparg = 1 << oparg;
pagefault_disable();
- ret = uaccess.futex_atomic_op(op, uaddr, oparg, &oldval);
+ ret = __futex_atomic_op_inuser(op, uaddr, oparg, &oldval);
pagefault_enable();
if (!ret) {
@@ -34,10 +37,4 @@ static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
return ret;
}
-static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
- u32 oldval, u32 newval)
-{
- return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
-}
-
#endif /* _ASM_S390_FUTEX_H */
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h
index 5f8bcc5fe423..35f0faab5361 100644
--- a/arch/s390/include/asm/irq.h
+++ b/arch/s390/include/asm/irq.h
@@ -53,6 +53,7 @@ enum interruption_class {
IRQIO_PCI,
IRQIO_MSI,
IRQIO_VIR,
+ IRQIO_VAI,
NMI_NMI,
CPU_RST,
NR_ARCH_IRQS
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index eef3dd3fd9a9..154b60089be9 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -16,12 +16,22 @@
#include <linux/hrtimer.h>
#include <linux/interrupt.h>
#include <linux/kvm_host.h>
+#include <linux/kvm.h>
#include <asm/debug.h>
#include <asm/cpu.h>
+#include <asm/isc.h>
#define KVM_MAX_VCPUS 64
#define KVM_USER_MEM_SLOTS 32
+/*
+ * These seem to be used for allocating ->chip in the routing table,
+ * which we don't use. 4096 is an out-of-thin-air value. If we need
+ * to look at ->chip later on, we'll need to revisit this.
+ */
+#define KVM_NR_IRQCHIPS 1
+#define KVM_IRQCHIP_NUM_PINS 4096
+
struct sca_entry {
atomic_t scn;
__u32 reserved;
@@ -106,7 +116,11 @@ struct kvm_s390_sie_block {
__u64 gbea; /* 0x0180 */
__u8 reserved188[24]; /* 0x0188 */
__u32 fac; /* 0x01a0 */
- __u8 reserved1a4[68]; /* 0x01a4 */
+ __u8 reserved1a4[20]; /* 0x01a4 */
+ __u64 cbrlo; /* 0x01b8 */
+ __u8 reserved1c0[30]; /* 0x01c0 */
+ __u64 pp; /* 0x01de */
+ __u8 reserved1e6[2]; /* 0x01e6 */
__u64 itdba; /* 0x01e8 */
__u8 reserved1f0[16]; /* 0x01f0 */
} __attribute__((packed));
@@ -155,6 +169,7 @@ struct kvm_vcpu_stat {
u32 instruction_stsi;
u32 instruction_stfl;
u32 instruction_tprot;
+ u32 instruction_essa;
u32 instruction_sigp_sense;
u32 instruction_sigp_sense_running;
u32 instruction_sigp_external_call;
@@ -168,18 +183,6 @@ struct kvm_vcpu_stat {
u32 diagnose_9c;
};
-struct kvm_s390_io_info {
- __u16 subchannel_id; /* 0x0b8 */
- __u16 subchannel_nr; /* 0x0ba */
- __u32 io_int_parm; /* 0x0bc */
- __u32 io_int_word; /* 0x0c0 */
-};
-
-struct kvm_s390_ext_info {
- __u32 ext_params;
- __u64 ext_params2;
-};
-
#define PGM_OPERATION 0x01
#define PGM_PRIVILEGED_OP 0x02
#define PGM_EXECUTE 0x03
@@ -188,27 +191,6 @@ struct kvm_s390_ext_info {
#define PGM_SPECIFICATION 0x06
#define PGM_DATA 0x07
-struct kvm_s390_pgm_info {
- __u16 code;
-};
-
-struct kvm_s390_prefix_info {
- __u32 address;
-};
-
-struct kvm_s390_extcall_info {
- __u16 code;
-};
-
-struct kvm_s390_emerg_info {
- __u16 code;
-};
-
-struct kvm_s390_mchk_info {
- __u64 cr14;
- __u64 mcic;
-};
-
struct kvm_s390_interrupt_info {
struct list_head list;
u64 type;
@@ -243,9 +225,8 @@ struct kvm_s390_float_interrupt {
struct list_head list;
atomic_t active;
int next_rr_cpu;
- unsigned long idle_mask[(KVM_MAX_VCPUS + sizeof(long) - 1)
- / sizeof(long)];
- struct kvm_s390_local_interrupt *local_int[KVM_MAX_VCPUS];
+ unsigned long idle_mask[BITS_TO_LONGS(KVM_MAX_VCPUS)];
+ unsigned int irq_count;
};
@@ -262,6 +243,10 @@ struct kvm_vcpu_arch {
u64 stidp_data;
};
struct gmap *gmap;
+#define KVM_S390_PFAULT_TOKEN_INVALID (-1UL)
+ unsigned long pfault_token;
+ unsigned long pfault_select;
+ unsigned long pfault_compare;
};
struct kvm_vm_stat {
@@ -271,12 +256,36 @@ struct kvm_vm_stat {
struct kvm_arch_memory_slot {
};
+struct s390_map_info {
+ struct list_head list;
+ __u64 guest_addr;
+ __u64 addr;
+ struct page *page;
+};
+
+struct s390_io_adapter {
+ unsigned int id;
+ int isc;
+ bool maskable;
+ bool masked;
+ bool swap;
+ struct rw_semaphore maps_lock;
+ struct list_head maps;
+ atomic_t nr_maps;
+};
+
+#define MAX_S390_IO_ADAPTERS ((MAX_ISC + 1) * 8)
+#define MAX_S390_ADAPTER_MAPS 256
+
struct kvm_arch{
struct sca_block *sca;
debug_info_t *dbf;
struct kvm_s390_float_interrupt float_int;
+ struct kvm_device *flic;
struct gmap *gmap;
int css_support;
+ int use_irqchip;
+ struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
};
#define KVM_HVA_ERR_BAD (-1UL)
@@ -287,6 +296,24 @@ static inline bool kvm_is_error_hva(unsigned long addr)
return IS_ERR_VALUE(addr);
}
+#define ASYNC_PF_PER_VCPU 64
+struct kvm_vcpu;
+struct kvm_async_pf;
+struct kvm_arch_async_pf {
+ unsigned long pfault_token;
+};
+
+bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu);
+
+void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work);
+
+void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work);
+
+void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work);
+
extern int sie64a(struct kvm_s390_sie_block *, u64 *);
extern char sie_exit;
#endif
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h
index 5d1f950704dc..38149b63dc44 100644
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -48,13 +48,42 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
- cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
- update_mm(next, tsk);
+ int cpu = smp_processor_id();
+
+ if (prev == next)
+ return;
+ if (atomic_inc_return(&next->context.attach_count) >> 16) {
+ /* Delay update_mm until all TLB flushes are done. */
+ set_tsk_thread_flag(tsk, TIF_TLB_WAIT);
+ } else {
+ cpumask_set_cpu(cpu, mm_cpumask(next));
+ update_mm(next, tsk);
+ if (next->context.flush_mm)
+ /* Flush pending TLBs */
+ __tlb_flush_mm(next);
+ }
atomic_dec(&prev->context.attach_count);
WARN_ON(atomic_read(&prev->context.attach_count) < 0);
- atomic_inc(&next->context.attach_count);
- /* Check for TLBs not flushed yet */
- __tlb_flush_mm_lazy(next);
+}
+
+#define finish_arch_post_lock_switch finish_arch_post_lock_switch
+static inline void finish_arch_post_lock_switch(void)
+{
+ struct task_struct *tsk = current;
+ struct mm_struct *mm = tsk->mm;
+
+ if (!test_tsk_thread_flag(tsk, TIF_TLB_WAIT))
+ return;
+ preempt_disable();
+ clear_tsk_thread_flag(tsk, TIF_TLB_WAIT);
+ while (atomic_read(&mm->context.attach_count) >> 16)
+ cpu_relax();
+
+ cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
+ update_mm(mm, tsk);
+ if (mm->context.flush_mm)
+ __tlb_flush_mm(mm);
+ preempt_enable();
}
#define enter_lazy_tlb(mm,tsk) do { } while (0)
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h
index e1408ddb94f8..884017cbfa9f 100644
--- a/arch/s390/include/asm/pgalloc.h
+++ b/arch/s390/include/asm/pgalloc.h
@@ -22,6 +22,7 @@ unsigned long *page_table_alloc(struct mm_struct *, unsigned long);
void page_table_free(struct mm_struct *, unsigned long *);
void page_table_free_rcu(struct mmu_gather *, unsigned long *);
+void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long);
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned long key, bool nq);
@@ -91,11 +92,22 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
{
unsigned long *table = crst_table_alloc(mm);
- if (table)
- crst_table_init(table, _SEGMENT_ENTRY_EMPTY);
+
+ if (!table)
+ return NULL;
+ crst_table_init(table, _SEGMENT_ENTRY_EMPTY);
+ if (!pgtable_pmd_page_ctor(virt_to_page(table))) {
+ crst_table_free(mm, table);
+ return NULL;
+ }
return (pmd_t *) table;
}
-#define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd)
+
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
+{
+ pgtable_pmd_page_dtor(virt_to_page(pmd));
+ crst_table_free(mm, (unsigned long *) pmd);
+}
static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
{
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 2204400d0bd5..50a75d96f939 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -229,6 +229,7 @@ extern unsigned long MODULES_END;
#define _PAGE_READ 0x010 /* SW pte read bit */
#define _PAGE_WRITE 0x020 /* SW pte write bit */
#define _PAGE_SPECIAL 0x040 /* SW associated with special page */
+#define _PAGE_UNUSED 0x080 /* SW bit for pgste usage state */
#define __HAVE_ARCH_PTE_SPECIAL
/* Set of bits not changed in pte_modify */
@@ -394,6 +395,12 @@ extern unsigned long MODULES_END;
#endif /* CONFIG_64BIT */
+/* Guest Page State used for virtualization */
+#define _PGSTE_GPS_ZERO 0x0000000080000000UL
+#define _PGSTE_GPS_USAGE_MASK 0x0000000003000000UL
+#define _PGSTE_GPS_USAGE_STABLE 0x0000000000000000UL
+#define _PGSTE_GPS_USAGE_UNUSED 0x0000000001000000UL
+
/*
* A user page table pointer has the space-switch-event bit, the
* private-space-control bit and the storage-alteration-event-control
@@ -617,6 +624,14 @@ static inline int pte_none(pte_t pte)
return pte_val(pte) == _PAGE_INVALID;
}
+static inline int pte_swap(pte_t pte)
+{
+ /* Bit pattern: (pte & 0x603) == 0x402 */
+ return (pte_val(pte) & (_PAGE_INVALID | _PAGE_PROTECT |
+ _PAGE_TYPE | _PAGE_PRESENT))
+ == (_PAGE_INVALID | _PAGE_TYPE);
+}
+
static inline int pte_file(pte_t pte)
{
/* Bit pattern: (pte & 0x601) == 0x600 */
@@ -767,6 +782,7 @@ static inline void pgste_set_pte(pte_t *ptep, pte_t entry)
* @table: pointer to the page directory
* @asce: address space control element for gmap page table
* @crst_list: list of all crst tables used in the guest address space
+ * @pfault_enabled: defines if pfaults are applicable for the guest
*/
struct gmap {
struct list_head list;
@@ -775,6 +791,7 @@ struct gmap {
unsigned long asce;
void *private;
struct list_head crst_list;
+ bool pfault_enabled;
};
/**
@@ -821,20 +838,20 @@ unsigned long gmap_translate(unsigned long address, struct gmap *);
unsigned long __gmap_fault(unsigned long address, struct gmap *);
unsigned long gmap_fault(unsigned long address, struct gmap *);
void gmap_discard(unsigned long from, unsigned long to, struct gmap *);
+void __gmap_zap(unsigned long address, struct gmap *);
void gmap_register_ipte_notifier(struct gmap_notifier *);
void gmap_unregister_ipte_notifier(struct gmap_notifier *);
int gmap_ipte_notify(struct gmap *, unsigned long start, unsigned long len);
-void gmap_do_ipte_notify(struct mm_struct *, unsigned long addr, pte_t *);
+void gmap_do_ipte_notify(struct mm_struct *, pte_t *);
static inline pgste_t pgste_ipte_notify(struct mm_struct *mm,
- unsigned long addr,
pte_t *ptep, pgste_t pgste)
{
#ifdef CONFIG_PGSTE
if (pgste_val(pgste) & PGSTE_IN_BIT) {
pgste_val(pgste) &= ~PGSTE_IN_BIT;
- gmap_do_ipte_notify(mm, addr, ptep);
+ gmap_do_ipte_notify(mm, ptep);
}
#endif
return pgste;
@@ -852,6 +869,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
+ pgste_val(pgste) &= ~_PGSTE_GPS_ZERO;
pgste_set_key(ptep, pgste, entry);
pgste_set_pte(ptep, entry);
pgste_set_unlock(ptep, pgste);
@@ -881,6 +899,12 @@ static inline int pte_young(pte_t pte)
return (pte_val(pte) & _PAGE_YOUNG) != 0;
}
+#define __HAVE_ARCH_PTE_UNUSED
+static inline int pte_unused(pte_t pte)
+{
+ return pte_val(pte) & _PAGE_UNUSED;
+}
+
/*
* pgd/pmd/pte modification functions
*/
@@ -1034,30 +1058,41 @@ static inline int ptep_test_and_clear_user_young(struct mm_struct *mm,
static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
{
- if (!(pte_val(*ptep) & _PAGE_INVALID)) {
+ unsigned long pto = (unsigned long) ptep;
+
#ifndef CONFIG_64BIT
- /* pto must point to the start of the segment table */
- pte_t *pto = (pte_t *) (((unsigned long) ptep) & 0x7ffffc00);
-#else
- /* ipte in zarch mode can do the math */
- pte_t *pto = ptep;
+ /* pto in ESA mode must point to the start of the segment table */
+ pto &= 0x7ffffc00;
#endif
- asm volatile(
- " ipte %2,%3"
- : "=m" (*ptep) : "m" (*ptep),
- "a" (pto), "a" (address));
- }
+ /* Invalidation + global TLB flush for the pte */
+ asm volatile(
+ " ipte %2,%3"
+ : "=m" (*ptep) : "m" (*ptep), "a" (pto), "a" (address));
+}
+
+static inline void ptep_flush_direct(struct mm_struct *mm,
+ unsigned long address, pte_t *ptep)
+{
+ if (pte_val(*ptep) & _PAGE_INVALID)
+ return;
+ __ptep_ipte(address, ptep);
}
static inline void ptep_flush_lazy(struct mm_struct *mm,
unsigned long address, pte_t *ptep)
{
- int active = (mm == current->active_mm) ? 1 : 0;
+ int active, count;
- if (atomic_read(&mm->context.attach_count) > active)
- __ptep_ipte(address, ptep);
- else
+ if (pte_val(*ptep) & _PAGE_INVALID)
+ return;
+ active = (mm == current->active_mm) ? 1 : 0;
+ count = atomic_add_return(0x10000, &mm->context.attach_count);
+ if ((count & 0xffff) <= active) {
+ pte_val(*ptep) |= _PAGE_INVALID;
mm->context.flush_mm = 1;
+ } else
+ __ptep_ipte(address, ptep);
+ atomic_sub(0x10000, &mm->context.attach_count);
}
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
@@ -1070,11 +1105,11 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
if (mm_has_pgste(vma->vm_mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_ipte_notify(vma->vm_mm, addr, ptep, pgste);
+ pgste = pgste_ipte_notify(vma->vm_mm, ptep, pgste);
}
pte = *ptep;
- __ptep_ipte(addr, ptep);
+ ptep_flush_direct(vma->vm_mm, addr, ptep);
young = pte_young(pte);
pte = pte_mkold(pte);
@@ -1116,7 +1151,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_ipte_notify(mm, address, ptep, pgste);
+ pgste = pgste_ipte_notify(mm, ptep, pgste);
}
pte = *ptep;
@@ -1140,12 +1175,11 @@ static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
- pgste_ipte_notify(mm, address, ptep, pgste);
+ pgste_ipte_notify(mm, ptep, pgste);
}
pte = *ptep;
ptep_flush_lazy(mm, address, ptep);
- pte_val(*ptep) |= _PAGE_INVALID;
if (mm_has_pgste(mm)) {
pgste = pgste_update_all(&pte, pgste);
@@ -1178,14 +1212,17 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
if (mm_has_pgste(vma->vm_mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste);
+ pgste = pgste_ipte_notify(vma->vm_mm, ptep, pgste);
}
pte = *ptep;
- __ptep_ipte(address, ptep);
+ ptep_flush_direct(vma->vm_mm, address, ptep);
pte_val(*ptep) = _PAGE_INVALID;
if (mm_has_pgste(vma->vm_mm)) {
+ if ((pgste_val(pgste) & _PGSTE_GPS_USAGE_MASK) ==
+ _PGSTE_GPS_USAGE_UNUSED)
+ pte_val(pte) |= _PAGE_UNUSED;
pgste = pgste_update_all(&pte, pgste);
pgste_set_unlock(ptep, pgste);
}
@@ -1209,7 +1246,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
if (!full && mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_ipte_notify(mm, address, ptep, pgste);
+ pgste = pgste_ipte_notify(mm, ptep, pgste);
}
pte = *ptep;
@@ -1234,7 +1271,7 @@ static inline pte_t ptep_set_wrprotect(struct mm_struct *mm,
if (pte_write(pte)) {
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_ipte_notify(mm, address, ptep, pgste);
+ pgste = pgste_ipte_notify(mm, ptep, pgste);
}
ptep_flush_lazy(mm, address, ptep);
@@ -1260,10 +1297,10 @@ static inline int ptep_set_access_flags(struct vm_area_struct *vma,
return 0;
if (mm_has_pgste(vma->vm_mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste);
+ pgste = pgste_ipte_notify(vma->vm_mm, ptep, pgste);
}
- __ptep_ipte(address, ptep);
+ ptep_flush_direct(vma->vm_mm, address, ptep);
if (mm_has_pgste(vma->vm_mm)) {
pgste_set_pte(ptep, entry);
@@ -1447,12 +1484,16 @@ static inline pmd_t pmd_mkwrite(pmd_t pmd)
static inline void pmdp_flush_lazy(struct mm_struct *mm,
unsigned long address, pmd_t *pmdp)
{
- int active = (mm == current->active_mm) ? 1 : 0;
+ int active, count;
- if ((atomic_read(&mm->context.attach_count) & 0xffff) > active)
- __pmd_idte(address, pmdp);
- else
+ active = (mm == current->active_mm) ? 1 : 0;
+ count = atomic_add_return(0x10000, &mm->context.attach_count);
+ if ((count & 0xffff) <= active) {
+ pmd_val(*pmdp) |= _SEGMENT_ENTRY_INVALID;
mm->context.flush_mm = 1;
+ } else
+ __pmd_idte(address, pmdp);
+ atomic_sub(0x10000, &mm->context.attach_count);
}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 0a876bc543d3..dc5fc4f90e52 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -79,6 +79,7 @@ struct thread_struct {
unsigned long ksp; /* kernel stack pointer */
mm_segment_t mm_segment;
unsigned long gmap_addr; /* address of last gmap fault. */
+ unsigned int gmap_pfault; /* signal of a pending guest pfault */
struct per_regs per_user; /* User specified PER registers */
struct per_event per_event; /* Cause of the last PER trap */
unsigned long per_flags; /* Flags to control debug behavior */
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index 9c82cebddabd..f4783c0b7b43 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -83,6 +83,7 @@ struct per_struct_kernel {
* These are defined as per linux/ptrace.h, which see.
*/
#define arch_has_single_step() (1)
+#define arch_has_block_step() (1)
#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
#define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h
index abaca2275c7a..2f5e9932b4de 100644
--- a/arch/s390/include/asm/sclp.h
+++ b/arch/s390/include/asm/sclp.h
@@ -46,6 +46,7 @@ int sclp_cpu_configure(u8 cpu);
int sclp_cpu_deconfigure(u8 cpu);
unsigned long long sclp_get_rnmax(void);
unsigned long long sclp_get_rzm(void);
+unsigned int sclp_get_max_cpu(void);
int sclp_sdias_blk_count(void);
int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
int sclp_chp_configure(struct chp_id chpid);
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index 94cfbe442f12..406f3a1e63ef 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -59,7 +59,6 @@ void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
#define MACHINE_FLAG_DIAG44 (1UL << 4)
#define MACHINE_FLAG_IDTE (1UL << 5)
#define MACHINE_FLAG_DIAG9C (1UL << 6)
-#define MACHINE_FLAG_MVCOS (1UL << 7)
#define MACHINE_FLAG_KVM (1UL << 8)
#define MACHINE_FLAG_ESOP (1UL << 9)
#define MACHINE_FLAG_EDAT1 (1UL << 10)
@@ -85,7 +84,6 @@ void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
#define MACHINE_HAS_IDTE (0)
#define MACHINE_HAS_DIAG44 (1)
#define MACHINE_HAS_MVPG (S390_lowcore.machine_flags & MACHINE_FLAG_MVPG)
-#define MACHINE_HAS_MVCOS (0)
#define MACHINE_HAS_EDAT1 (0)
#define MACHINE_HAS_EDAT2 (0)
#define MACHINE_HAS_LPP (0)
@@ -98,7 +96,6 @@ void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
#define MACHINE_HAS_IDTE (S390_lowcore.machine_flags & MACHINE_FLAG_IDTE)
#define MACHINE_HAS_DIAG44 (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG44)
#define MACHINE_HAS_MVPG (1)
-#define MACHINE_HAS_MVCOS (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS)
#define MACHINE_HAS_EDAT1 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1)
#define MACHINE_HAS_EDAT2 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT2)
#define MACHINE_HAS_LPP (S390_lowcore.machine_flags & MACHINE_FLAG_LPP)
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index 10e0fcd3633d..3ccd71b90345 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -81,6 +81,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+#define TIF_TLB_WAIT 4 /* wait for TLB flush completion */
#define TIF_PER_TRAP 6 /* deliver sigtrap on return to user */
#define TIF_MCCK_PENDING 7 /* machine check handling is pending */
#define TIF_SYSCALL_TRACE 8 /* syscall trace active */
@@ -91,11 +92,13 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 19 /* restore signal mask in do_signal() */
#define TIF_SINGLE_STEP 20 /* This task is single stepped */
+#define TIF_BLOCK_STEP 21 /* This task is block stepped */
#define _TIF_SYSCALL (1<<TIF_SYSCALL)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+#define _TIF_TLB_WAIT (1<<TIF_TLB_WAIT)
#define _TIF_PER_TRAP (1<<TIF_PER_TRAP)
#define _TIF_MCCK_PENDING (1<<TIF_MCCK_PENDING)
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index 79330af9a5f8..4133b3f72fb0 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -92,33 +92,58 @@ static inline unsigned long extable_fixup(const struct exception_table_entry *x)
#define ARCH_HAS_SORT_EXTABLE
#define ARCH_HAS_SEARCH_EXTABLE
-struct uaccess_ops {
- size_t (*copy_from_user)(size_t, const void __user *, void *);
- size_t (*copy_to_user)(size_t, void __user *, const void *);
- size_t (*copy_in_user)(size_t, void __user *, const void __user *);
- size_t (*clear_user)(size_t, void __user *);
- size_t (*strnlen_user)(size_t, const char __user *);
- size_t (*strncpy_from_user)(size_t, const char __user *, char *);
- int (*futex_atomic_op)(int op, u32 __user *, int oparg, int *old);
- int (*futex_atomic_cmpxchg)(u32 *, u32 __user *, u32 old, u32 new);
-};
+int __handle_fault(unsigned long, unsigned long, int);
-extern struct uaccess_ops uaccess;
-extern struct uaccess_ops uaccess_mvcos;
-extern struct uaccess_ops uaccess_pt;
+/**
+ * __copy_from_user: - Copy a block of data from user space, with less checking.
+ * @to: Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from user space to kernel space. Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
+unsigned long __must_check __copy_from_user(void *to, const void __user *from,
+ unsigned long n);
+
+/**
+ * __copy_to_user: - Copy a block of data into user space, with less checking.
+ * @to: Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from kernel space to user space. Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+unsigned long __must_check __copy_to_user(void __user *to, const void *from,
+ unsigned long n);
-extern int __handle_fault(unsigned long, unsigned long, int);
+#define __copy_to_user_inatomic __copy_to_user
+#define __copy_from_user_inatomic __copy_from_user
-static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
+static inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)
{
- size = uaccess.copy_to_user(size, ptr, x);
- return size ? -EFAULT : size;
+ size = __copy_to_user(ptr, x, size);
+ return size ? -EFAULT : 0;
}
-static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
+static inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size)
{
- size = uaccess.copy_from_user(size, ptr, x);
- return size ? -EFAULT : size;
+ size = __copy_from_user(x, ptr, size);
+ return size ? -EFAULT : 0;
}
/*
@@ -135,8 +160,8 @@ static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
case 2: \
case 4: \
case 8: \
- __pu_err = __put_user_fn(sizeof (*(ptr)), \
- ptr, &__x); \
+ __pu_err = __put_user_fn(&__x, ptr, \
+ sizeof(*(ptr))); \
break; \
default: \
__put_user_bad(); \
@@ -152,7 +177,7 @@ static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
})
-extern int __put_user_bad(void) __attribute__((noreturn));
+int __put_user_bad(void) __attribute__((noreturn));
#define __get_user(x, ptr) \
({ \
@@ -161,29 +186,29 @@ extern int __put_user_bad(void) __attribute__((noreturn));
switch (sizeof(*(ptr))) { \
case 1: { \
unsigned char __x; \
- __gu_err = __get_user_fn(sizeof (*(ptr)), \
- ptr, &__x); \
+ __gu_err = __get_user_fn(&__x, ptr, \
+ sizeof(*(ptr))); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \
break; \
}; \
case 2: { \
unsigned short __x; \
- __gu_err = __get_user_fn(sizeof (*(ptr)), \
- ptr, &__x); \
+ __gu_err = __get_user_fn(&__x, ptr, \
+ sizeof(*(ptr))); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \
break; \
}; \
case 4: { \
unsigned int __x; \
- __gu_err = __get_user_fn(sizeof (*(ptr)), \
- ptr, &__x); \
+ __gu_err = __get_user_fn(&__x, ptr, \
+ sizeof(*(ptr))); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \
break; \
}; \
case 8: { \
unsigned long long __x; \
- __gu_err = __get_user_fn(sizeof (*(ptr)), \
- ptr, &__x); \
+ __gu_err = __get_user_fn(&__x, ptr, \
+ sizeof(*(ptr))); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \
break; \
}; \
@@ -200,35 +225,12 @@ extern int __put_user_bad(void) __attribute__((noreturn));
__get_user(x, ptr); \
})
-extern int __get_user_bad(void) __attribute__((noreturn));
+int __get_user_bad(void) __attribute__((noreturn));
#define __put_user_unaligned __put_user
#define __get_user_unaligned __get_user
/**
- * __copy_to_user: - Copy a block of data into user space, with less checking.
- * @to: Destination address, in user space.
- * @from: Source address, in kernel space.
- * @n: Number of bytes to copy.
- *
- * Context: User context only. This function may sleep.
- *
- * Copy data from kernel space to user space. Caller must check
- * the specified block with access_ok() before calling this function.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- */
-static inline unsigned long __must_check
-__copy_to_user(void __user *to, const void *from, unsigned long n)
-{
- return uaccess.copy_to_user(n, to, from);
-}
-
-#define __copy_to_user_inatomic __copy_to_user
-#define __copy_from_user_inatomic __copy_from_user
-
-/**
* copy_to_user: - Copy a block of data into user space.
* @to: Destination address, in user space.
* @from: Source address, in kernel space.
@@ -248,30 +250,7 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
return __copy_to_user(to, from, n);
}
-/**
- * __copy_from_user: - Copy a block of data from user space, with less checking.
- * @to: Destination address, in kernel space.
- * @from: Source address, in user space.
- * @n: Number of bytes to copy.
- *
- * Context: User context only. This function may sleep.
- *
- * Copy data from user space to kernel space. Caller must check
- * the specified block with access_ok() before calling this function.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- *
- * If some data could not be copied, this function will pad the copied
- * data to the requested size using zero bytes.
- */
-static inline unsigned long __must_check
-__copy_from_user(void *to, const void __user *from, unsigned long n)
-{
- return uaccess.copy_from_user(n, from, to);
-}
-
-extern void copy_from_user_overflow(void)
+void copy_from_user_overflow(void)
#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS
__compiletime_warning("copy_from_user() buffer size is not provably correct")
#endif
@@ -306,11 +285,8 @@ copy_from_user(void *to, const void __user *from, unsigned long n)
return __copy_from_user(to, from, n);
}
-static inline unsigned long __must_check
-__copy_in_user(void __user *to, const void __user *from, unsigned long n)
-{
- return uaccess.copy_in_user(n, to, from);
-}
+unsigned long __must_check
+__copy_in_user(void __user *to, const void __user *from, unsigned long n);
static inline unsigned long __must_check
copy_in_user(void __user *to, const void __user *from, unsigned long n)
@@ -322,18 +298,22 @@ copy_in_user(void __user *to, const void __user *from, unsigned long n)
/*
* Copy a null terminated string from userspace.
*/
+
+long __strncpy_from_user(char *dst, const char __user *src, long count);
+
static inline long __must_check
strncpy_from_user(char *dst, const char __user *src, long count)
{
might_fault();
- return uaccess.strncpy_from_user(count, src, dst);
+ return __strncpy_from_user(dst, src, count);
}
-static inline unsigned long
-strnlen_user(const char __user * src, unsigned long n)
+unsigned long __must_check __strnlen_user(const char __user *src, unsigned long count);
+
+static inline unsigned long strnlen_user(const char __user *src, unsigned long n)
{
might_fault();
- return uaccess.strnlen_user(n, src);
+ return __strnlen_user(src, n);
}
/**
@@ -355,21 +335,14 @@ strnlen_user(const char __user * src, unsigned long n)
/*
* Zero Userspace
*/
+unsigned long __must_check __clear_user(void __user *to, unsigned long size);
-static inline unsigned long __must_check
-__clear_user(void __user *to, unsigned long n)
-{
- return uaccess.clear_user(n, to);
-}
-
-static inline unsigned long __must_check
-clear_user(void __user *to, unsigned long n)
+static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
{
might_fault();
- return uaccess.clear_user(n, to);
+ return __clear_user(to, n);
}
-extern int copy_to_user_real(void __user *dest, void *src, size_t count);
-extern int copy_from_user_real(void *dest, void __user *src, size_t count);
+int copy_to_user_real(void __user *dest, void *src, unsigned long count);
#endif /* __S390_UACCESS_H */
diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h
index d25da598ec62..c003c6a73b1e 100644
--- a/arch/s390/include/uapi/asm/kvm.h
+++ b/arch/s390/include/uapi/asm/kvm.h
@@ -16,6 +16,44 @@
#define __KVM_S390
+/* Device control API: s390-specific devices */
+#define KVM_DEV_FLIC_GET_ALL_IRQS 1
+#define KVM_DEV_FLIC_ENQUEUE 2
+#define KVM_DEV_FLIC_CLEAR_IRQS 3
+#define KVM_DEV_FLIC_APF_ENABLE 4
+#define KVM_DEV_FLIC_APF_DISABLE_WAIT 5
+#define KVM_DEV_FLIC_ADAPTER_REGISTER 6
+#define KVM_DEV_FLIC_ADAPTER_MODIFY 7
+/*
+ * We can have up to 4*64k pending subchannels + 8 adapter interrupts,
+ * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts.
+ * There are also sclp and machine checks. This gives us
+ * sizeof(kvm_s390_irq)*(4*65536+8+64*64+1+1) = 72 * 266250 = 19170000
+ * Lets round up to 8192 pages.
+ */
+#define KVM_S390_MAX_FLOAT_IRQS 266250
+#define KVM_S390_FLIC_MAX_BUFFER 0x2000000
+
+struct kvm_s390_io_adapter {
+ __u32 id;
+ __u8 isc;
+ __u8 maskable;
+ __u8 swap;
+ __u8 pad;
+};
+
+#define KVM_S390_IO_ADAPTER_MASK 1
+#define KVM_S390_IO_ADAPTER_MAP 2
+#define KVM_S390_IO_ADAPTER_UNMAP 3
+
+struct kvm_s390_io_adapter_req {
+ __u32 id;
+ __u8 type;
+ __u8 mask;
+ __u16 pad0;
+ __u64 addr;
+};
+
/* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs {
/* general purpose regs for s390 */
@@ -57,4 +95,9 @@ struct kvm_sync_regs {
#define KVM_REG_S390_EPOCHDIFF (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x2)
#define KVM_REG_S390_CPU_TIMER (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x3)
#define KVM_REG_S390_CLOCK_COMP (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x4)
+#define KVM_REG_S390_PFTOKEN (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x5)
+#define KVM_REG_S390_PFCOMPARE (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x6)
+#define KVM_REG_S390_PFSELECT (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x7)
+#define KVM_REG_S390_PP (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x8)
+#define KVM_REG_S390_GBEA (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x9)
#endif
diff --git a/arch/s390/include/uapi/asm/ptrace.h b/arch/s390/include/uapi/asm/ptrace.h
index 7e0b498a2c2b..a150f4fabe43 100644
--- a/arch/s390/include/uapi/asm/ptrace.h
+++ b/arch/s390/include/uapi/asm/ptrace.h
@@ -403,6 +403,12 @@ typedef struct
#define PTRACE_TE_ABORT_RAND 0x5011
/*
+ * The numbers chosen here are somewhat arbitrary but absolutely MUST
+ * not overlap with any of the number assigned in <linux/ptrace.h>.
+ */
+#define PTRACE_SINGLEBLOCK 12 /* resume execution until next branch */
+
+/*
* PT_PROT definition is loosely based on hppa bsd definition in
* gdb/hppab-nat.c
*/
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 1b3ac09c11b6..a95c4ca99617 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -47,9 +47,8 @@ obj-$(CONFIG_SCHED_BOOK) += topology.o
obj-$(CONFIG_HIBERNATION) += suspend.o swsusp_asm64.o
obj-$(CONFIG_AUDIT) += audit.o
compat-obj-$(CONFIG_AUDIT) += compat_audit.o
-obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \
- compat_wrapper.o compat_exec_domain.o \
- $(compat-obj-y)
+obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o
+obj-$(CONFIG_COMPAT) += compat_wrapper.o $(compat-obj-y)
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_KPROBES) += kprobes.o
diff --git a/arch/s390/kernel/compat_exec_domain.c b/arch/s390/kernel/compat_exec_domain.c
deleted file mode 100644
index 765fabdada9f..000000000000
--- a/arch/s390/kernel/compat_exec_domain.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Support for 32-bit Linux for S390 personality.
- *
- * Copyright IBM Corp. 2000
- * Author(s): Gerhard Tonn (ton@de.ibm.com)
- *
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/personality.h>
-#include <linux/sched.h>
-
-static struct exec_domain s390_exec_domain;
-
-static int __init s390_init (void)
-{
- s390_exec_domain.name = "Linux/s390";
- s390_exec_domain.handler = NULL;
- s390_exec_domain.pers_low = PER_LINUX32;
- s390_exec_domain.pers_high = PER_LINUX32;
- s390_exec_domain.signal_map = default_exec_domain.signal_map;
- s390_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
- register_exec_domain(&s390_exec_domain);
- return 0;
-}
-
-__initcall(s390_init);
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index db02052bd137..ca38139423ae 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -86,48 +86,51 @@
#define SET_STAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)
#define SET_STAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)
-asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group)
+COMPAT_SYSCALL_DEFINE3(s390_chown16, const char __user *, filename,
+ u16, user, u16, group)
{
return sys_chown(filename, low2highuid(user), low2highgid(group));
}
-asmlinkage long sys32_lchown16(const char __user * filename, u16 user, u16 group)
+COMPAT_SYSCALL_DEFINE3(s390_lchown16, const char __user *,
+ filename, u16, user, u16, group)
{
return sys_lchown(filename, low2highuid(user), low2highgid(group));
}
-asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group)
+COMPAT_SYSCALL_DEFINE3(s390_fchown16, unsigned int, fd, u16, user, u16, group)
{
return sys_fchown(fd, low2highuid(user), low2highgid(group));
}
-asmlinkage long sys32_setregid16(u16 rgid, u16 egid)
+COMPAT_SYSCALL_DEFINE2(s390_setregid16, u16, rgid, u16, egid)
{
return sys_setregid(low2highgid(rgid), low2highgid(egid));
}
-asmlinkage long sys32_setgid16(u16 gid)
+COMPAT_SYSCALL_DEFINE1(s390_setgid16, u16, gid)
{
return sys_setgid((gid_t)gid);
}
-asmlinkage long sys32_setreuid16(u16 ruid, u16 euid)
+COMPAT_SYSCALL_DEFINE2(s390_setreuid16, u16, ruid, u16, euid)
{
return sys_setreuid(low2highuid(ruid), low2highuid(euid));
}
-asmlinkage long sys32_setuid16(u16 uid)
+COMPAT_SYSCALL_DEFINE1(s390_setuid16, u16, uid)
{
return sys_setuid((uid_t)uid);
}
-asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid)
+COMPAT_SYSCALL_DEFINE3(s390_setresuid16, u16, ruid, u16, euid, u16, suid)
{
return sys_setresuid(low2highuid(ruid), low2highuid(euid),
- low2highuid(suid));
+ low2highuid(suid));
}
-asmlinkage long sys32_getresuid16(u16 __user *ruidp, u16 __user *euidp, u16 __user *suidp)
+COMPAT_SYSCALL_DEFINE3(s390_getresuid16, u16 __user *, ruidp,
+ u16 __user *, euidp, u16 __user *, suidp)
{
const struct cred *cred = current_cred();
int retval;
@@ -144,13 +147,14 @@ asmlinkage long sys32_getresuid16(u16 __user *ruidp, u16 __user *euidp, u16 __us
return retval;
}
-asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid)
+COMPAT_SYSCALL_DEFINE3(s390_setresgid16, u16, rgid, u16, egid, u16, sgid)
{
return sys_setresgid(low2highgid(rgid), low2highgid(egid),
- low2highgid(sgid));
+ low2highgid(sgid));
}
-asmlinkage long sys32_getresgid16(u16 __user *rgidp, u16 __user *egidp, u16 __user *sgidp)
+COMPAT_SYSCALL_DEFINE3(s390_getresgid16, u16 __user *, rgidp,
+ u16 __user *, egidp, u16 __user *, sgidp)
{
const struct cred *cred = current_cred();
int retval;
@@ -167,12 +171,12 @@ asmlinkage long sys32_getresgid16(u16 __user *rgidp, u16 __user *egidp, u16 __us
return retval;
}
-asmlinkage long sys32_setfsuid16(u16 uid)
+COMPAT_SYSCALL_DEFINE1(s390_setfsuid16, u16, uid)
{
return sys_setfsuid((uid_t)uid);
}
-asmlinkage long sys32_setfsgid16(u16 gid)
+COMPAT_SYSCALL_DEFINE1(s390_setfsgid16, u16, gid)
{
return sys_setfsgid((gid_t)gid);
}
@@ -215,7 +219,7 @@ static int groups16_from_user(struct group_info *group_info, u16 __user *groupli
return 0;
}
-asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist)
+COMPAT_SYSCALL_DEFINE2(s390_getgroups16, int, gidsetsize, u16 __user *, grouplist)
{
const struct cred *cred = current_cred();
int i;
@@ -240,7 +244,7 @@ out:
return i;
}
-asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)
+COMPAT_SYSCALL_DEFINE2(s390_setgroups16, int, gidsetsize, u16 __user *, grouplist)
{
struct group_info *group_info;
int retval;
@@ -265,22 +269,22 @@ asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)
return retval;
}
-asmlinkage long sys32_getuid16(void)
+COMPAT_SYSCALL_DEFINE0(s390_getuid16)
{
return high2lowuid(from_kuid_munged(current_user_ns(), current_uid()));
}
-asmlinkage long sys32_geteuid16(void)
+COMPAT_SYSCALL_DEFINE0(s390_geteuid16)
{
return high2lowuid(from_kuid_munged(current_user_ns(), current_euid()));
}
-asmlinkage long sys32_getgid16(void)
+COMPAT_SYSCALL_DEFINE0(s390_getgid16)
{
return high2lowgid(from_kgid_munged(current_user_ns(), current_gid()));
}
-asmlinkage long sys32_getegid16(void)
+COMPAT_SYSCALL_DEFINE0(s390_getegid16)
{
return high2lowgid(from_kgid_munged(current_user_ns(), current_egid()));
}
@@ -295,41 +299,35 @@ COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, compat_ulong_t, second,
}
#endif
-asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)
+COMPAT_SYSCALL_DEFINE3(s390_truncate64, const char __user *, path, u32, high, u32, low)
{
- if ((int)high < 0)
- return -EINVAL;
- else
- return sys_truncate(path, (high << 32) | low);
+ return sys_truncate(path, (unsigned long)high << 32 | low);
}
-asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
+COMPAT_SYSCALL_DEFINE3(s390_ftruncate64, unsigned int, fd, u32, high, u32, low)
{
- if ((int)high < 0)
- return -EINVAL;
- else
- return sys_ftruncate(fd, (high << 32) | low);
+ return sys_ftruncate(fd, (unsigned long)high << 32 | low);
}
-asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
- size_t count, u32 poshi, u32 poslo)
+COMPAT_SYSCALL_DEFINE5(s390_pread64, unsigned int, fd, char __user *, ubuf,
+ compat_size_t, count, u32, high, u32, low)
{
if ((compat_ssize_t) count < 0)
return -EINVAL;
- return sys_pread64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+ return sys_pread64(fd, ubuf, count, (unsigned long)high << 32 | low);
}
-asmlinkage long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
- size_t count, u32 poshi, u32 poslo)
+COMPAT_SYSCALL_DEFINE5(s390_pwrite64, unsigned int, fd, const char __user *, ubuf,
+ compat_size_t, count, u32, high, u32, low)
{
if ((compat_ssize_t) count < 0)
return -EINVAL;
- return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+ return sys_pwrite64(fd, ubuf, count, (unsigned long)high << 32 | low);
}
-asmlinkage compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count)
+COMPAT_SYSCALL_DEFINE4(s390_readahead, int, fd, u32, high, u32, low, s32, count)
{
- return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
+ return sys_readahead(fd, (unsigned long)high << 32 | low, count);
}
struct stat64_emu31 {
@@ -381,7 +379,7 @@ static int cp_stat64(struct stat64_emu31 __user *ubuf, struct kstat *stat)
return copy_to_user(ubuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
}
-asmlinkage long sys32_stat64(const char __user * filename, struct stat64_emu31 __user * statbuf)
+COMPAT_SYSCALL_DEFINE2(s390_stat64, const char __user *, filename, struct stat64_emu31 __user *, statbuf)
{
struct kstat stat;
int ret = vfs_stat(filename, &stat);
@@ -390,7 +388,7 @@ asmlinkage long sys32_stat64(const char __user * filename, struct stat64_emu31 _
return ret;
}
-asmlinkage long sys32_lstat64(const char __user * filename, struct stat64_emu31 __user * statbuf)
+COMPAT_SYSCALL_DEFINE2(s390_lstat64, const char __user *, filename, struct stat64_emu31 __user *, statbuf)
{
struct kstat stat;
int ret = vfs_lstat(filename, &stat);
@@ -399,7 +397,7 @@ asmlinkage long sys32_lstat64(const char __user * filename, struct stat64_emu31
return ret;
}
-asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 __user * statbuf)
+COMPAT_SYSCALL_DEFINE2(s390_fstat64, unsigned int, fd, struct stat64_emu31 __user *, statbuf)
{
struct kstat stat;
int ret = vfs_fstat(fd, &stat);
@@ -408,8 +406,8 @@ asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 __user * sta
return ret;
}
-asmlinkage long sys32_fstatat64(unsigned int dfd, const char __user *filename,
- struct stat64_emu31 __user* statbuf, int flag)
+COMPAT_SYSCALL_DEFINE4(s390_fstatat64, unsigned int, dfd, const char __user *, filename,
+ struct stat64_emu31 __user *, statbuf, int, flag)
{
struct kstat stat;
int error;
@@ -435,7 +433,7 @@ struct mmap_arg_struct_emu31 {
compat_ulong_t offset;
};
-asmlinkage unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
+COMPAT_SYSCALL_DEFINE1(s390_old_mmap, struct mmap_arg_struct_emu31 __user *, arg)
{
struct mmap_arg_struct_emu31 a;
@@ -447,7 +445,7 @@ asmlinkage unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
a.offset >> PAGE_SHIFT);
}
-asmlinkage long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg)
+COMPAT_SYSCALL_DEFINE1(s390_mmap2, struct mmap_arg_struct_emu31 __user *, arg)
{
struct mmap_arg_struct_emu31 a;
@@ -456,7 +454,7 @@ asmlinkage long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg)
return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
}
-asmlinkage long sys32_read(unsigned int fd, char __user * buf, size_t count)
+COMPAT_SYSCALL_DEFINE3(s390_read, unsigned int, fd, char __user *, buf, compat_size_t, count)
{
if ((compat_ssize_t) count < 0)
return -EINVAL;
@@ -464,7 +462,7 @@ asmlinkage long sys32_read(unsigned int fd, char __user * buf, size_t count)
return sys_read(fd, buf, count);
}
-asmlinkage long sys32_write(unsigned int fd, const char __user * buf, size_t count)
+COMPAT_SYSCALL_DEFINE3(s390_write, unsigned int, fd, const char __user *, buf, compat_size_t, count)
{
if ((compat_ssize_t) count < 0)
return -EINVAL;
@@ -478,14 +476,13 @@ asmlinkage long sys32_write(unsigned int fd, const char __user * buf, size_t cou
* because the 31 bit values differ from the 64 bit values.
*/
-asmlinkage long
-sys32_fadvise64(int fd, loff_t offset, size_t len, int advise)
+COMPAT_SYSCALL_DEFINE5(s390_fadvise64, int, fd, u32, high, u32, low, compat_size_t, len, int, advise)
{
if (advise == 4)
advise = POSIX_FADV_DONTNEED;
else if (advise == 5)
advise = POSIX_FADV_NOREUSE;
- return sys_fadvise64(fd, offset, len, advise);
+ return sys_fadvise64(fd, (unsigned long)high << 32 | low, len, advise);
}
struct fadvise64_64_args {
@@ -495,8 +492,7 @@ struct fadvise64_64_args {
int advice;
};
-asmlinkage long
-sys32_fadvise64_64(struct fadvise64_64_args __user *args)
+COMPAT_SYSCALL_DEFINE1(s390_fadvise64_64, struct fadvise64_64_args __user *, args)
{
struct fadvise64_64_args a;
@@ -508,3 +504,17 @@ sys32_fadvise64_64(struct fadvise64_64_args __user *args)
a.advice = POSIX_FADV_NOREUSE;
return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice);
}
+
+COMPAT_SYSCALL_DEFINE6(s390_sync_file_range, int, fd, u32, offhigh, u32, offlow,
+ u32, nhigh, u32, nlow, unsigned int, flags)
+{
+ return sys_sync_file_range(fd, ((loff_t)offhigh << 32) + offlow,
+ ((u64)nhigh << 32) + nlow, flags);
+}
+
+COMPAT_SYSCALL_DEFINE6(s390_fallocate, int, fd, int, mode, u32, offhigh, u32, offlow,
+ u32, lenhigh, u32, lenlow)
+{
+ return sys_fallocate(fd, mode, ((loff_t)offhigh << 32) + offlow,
+ ((u64)lenhigh << 32) + lenlow);
+}
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index 1bfda3eca379..39ddfdb40ae8 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -76,46 +76,43 @@ struct stat64_emu31;
struct mmap_arg_struct_emu31;
struct fadvise64_64_args;
-long sys32_chown16(const char __user * filename, u16 user, u16 group);
-long sys32_lchown16(const char __user * filename, u16 user, u16 group);
-long sys32_fchown16(unsigned int fd, u16 user, u16 group);
-long sys32_setregid16(u16 rgid, u16 egid);
-long sys32_setgid16(u16 gid);
-long sys32_setreuid16(u16 ruid, u16 euid);
-long sys32_setuid16(u16 uid);
-long sys32_setresuid16(u16 ruid, u16 euid, u16 suid);
-long sys32_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user *suid);
-long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid);
-long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user *sgid);
-long sys32_setfsuid16(u16 uid);
-long sys32_setfsgid16(u16 gid);
-long sys32_getgroups16(int gidsetsize, u16 __user *grouplist);
-long sys32_setgroups16(int gidsetsize, u16 __user *grouplist);
-long sys32_getuid16(void);
-long sys32_geteuid16(void);
-long sys32_getgid16(void);
-long sys32_getegid16(void);
-long sys32_truncate64(const char __user * path, unsigned long high,
- unsigned long low);
-long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low);
-long sys32_init_module(void __user *umod, unsigned long len,
- const char __user *uargs);
-long sys32_delete_module(const char __user *name_user, unsigned int flags);
-long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count,
- u32 poshi, u32 poslo);
-long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
- size_t count, u32 poshi, u32 poslo);
-compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count);
-long sys32_stat64(const char __user * filename, struct stat64_emu31 __user * statbuf);
-long sys32_lstat64(const char __user * filename,
- struct stat64_emu31 __user * statbuf);
-long sys32_fstat64(unsigned long fd, struct stat64_emu31 __user * statbuf);
-long sys32_fstatat64(unsigned int dfd, const char __user *filename,
- struct stat64_emu31 __user* statbuf, int flag);
-unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg);
-long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg);
-long sys32_read(unsigned int fd, char __user * buf, size_t count);
-long sys32_write(unsigned int fd, const char __user * buf, size_t count);
-long sys32_fadvise64(int fd, loff_t offset, size_t len, int advise);
-long sys32_fadvise64_64(struct fadvise64_64_args __user *args);
+long compat_sys_s390_chown16(const char __user *filename, u16 user, u16 group);
+long compat_sys_s390_lchown16(const char __user *filename, u16 user, u16 group);
+long compat_sys_s390_fchown16(unsigned int fd, u16 user, u16 group);
+long compat_sys_s390_setregid16(u16 rgid, u16 egid);
+long compat_sys_s390_setgid16(u16 gid);
+long compat_sys_s390_setreuid16(u16 ruid, u16 euid);
+long compat_sys_s390_setuid16(u16 uid);
+long compat_sys_s390_setresuid16(u16 ruid, u16 euid, u16 suid);
+long compat_sys_s390_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user *suid);
+long compat_sys_s390_setresgid16(u16 rgid, u16 egid, u16 sgid);
+long compat_sys_s390_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user *sgid);
+long compat_sys_s390_setfsuid16(u16 uid);
+long compat_sys_s390_setfsgid16(u16 gid);
+long compat_sys_s390_getgroups16(int gidsetsize, u16 __user *grouplist);
+long compat_sys_s390_setgroups16(int gidsetsize, u16 __user *grouplist);
+long compat_sys_s390_getuid16(void);
+long compat_sys_s390_geteuid16(void);
+long compat_sys_s390_getgid16(void);
+long compat_sys_s390_getegid16(void);
+long compat_sys_s390_truncate64(const char __user *path, u32 high, u32 low);
+long compat_sys_s390_ftruncate64(unsigned int fd, u32 high, u32 low);
+long compat_sys_s390_pread64(unsigned int fd, char __user *ubuf, compat_size_t count, u32 high, u32 low);
+long compat_sys_s390_pwrite64(unsigned int fd, const char __user *ubuf, compat_size_t count, u32 high, u32 low);
+long compat_sys_s390_readahead(int fd, u32 high, u32 low, s32 count);
+long compat_sys_s390_stat64(const char __user *filename, struct stat64_emu31 __user *statbuf);
+long compat_sys_s390_lstat64(const char __user *filename, struct stat64_emu31 __user *statbuf);
+long compat_sys_s390_fstat64(unsigned int fd, struct stat64_emu31 __user *statbuf);
+long compat_sys_s390_fstatat64(unsigned int dfd, const char __user *filename, struct stat64_emu31 __user *statbuf, int flag);
+long compat_sys_s390_old_mmap(struct mmap_arg_struct_emu31 __user *arg);
+long compat_sys_s390_mmap2(struct mmap_arg_struct_emu31 __user *arg);
+long compat_sys_s390_read(unsigned int fd, char __user * buf, compat_size_t count);
+long compat_sys_s390_write(unsigned int fd, const char __user * buf, compat_size_t count);
+long compat_sys_s390_fadvise64(int fd, u32 high, u32 low, compat_size_t len, int advise);
+long compat_sys_s390_fadvise64_64(struct fadvise64_64_args __user *args);
+long compat_sys_s390_sync_file_range(int fd, u32 offhigh, u32 offlow, u32 nhigh, u32 nlow, unsigned int flags);
+long compat_sys_s390_fallocate(int fd, int mode, u32 offhigh, u32 offlow, u32 lenhigh, u32 lenlow);
+long compat_sys_sigreturn(void);
+long compat_sys_rt_sigreturn(void);
+
#endif /* _ASM_S390X_S390_H */
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index 8b84bc373e94..7df5ed9f44d7 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -241,7 +241,7 @@ static int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
return 0;
}
-asmlinkage long sys32_sigreturn(void)
+COMPAT_SYSCALL_DEFINE0(sigreturn)
{
struct pt_regs *regs = task_pt_regs(current);
sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
@@ -260,7 +260,7 @@ badframe:
return 0;
}
-asmlinkage long sys32_rt_sigreturn(void)
+COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
{
struct pt_regs *regs = task_pt_regs(current);
rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
deleted file mode 100644
index 59c8efce1b99..000000000000
--- a/arch/s390/kernel/compat_wrapper.S
+++ /dev/null
@@ -1,1425 +0,0 @@
-/*
-* wrapper for 31 bit compatible system calls.
-*
-* Copyright IBM Corp. 2000, 2006
-* Author(s): Gerhard Tonn (ton@de.ibm.com),
-* Thomas Spatzier (tspat@de.ibm.com)
-*/
-
-#include <linux/linkage.h>
-
-ENTRY(sys32_exit_wrapper)
- lgfr %r2,%r2 # int
- jg sys_exit # branch to sys_exit
-
-ENTRY(sys32_read_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # char *
- llgfr %r4,%r4 # size_t
- jg sys32_read # branch to sys_read
-
-ENTRY(sys32_write_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # size_t
- jg sys32_write # branch to system call
-
-ENTRY(sys32_close_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_close # branch to system call
-
-ENTRY(sys32_creat_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- jg sys_creat # branch to system call
-
-ENTRY(sys32_link_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # const char *
- jg sys_link # branch to system call
-
-ENTRY(sys32_unlink_wrapper)
- llgtr %r2,%r2 # const char *
- jg sys_unlink # branch to system call
-
-ENTRY(sys32_chdir_wrapper)
- llgtr %r2,%r2 # const char *
- jg sys_chdir # branch to system call
-
-ENTRY(sys32_time_wrapper)
- llgtr %r2,%r2 # int *
- jg compat_sys_time # branch to system call
-
-ENTRY(sys32_mknod_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- llgfr %r4,%r4 # dev
- jg sys_mknod # branch to system call
-
-ENTRY(sys32_chmod_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # mode_t
- jg sys_chmod # branch to system call
-
-ENTRY(sys32_lchown16_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
- llgfr %r4,%r4 # __kernel_old_uid_emu31_t
- jg sys32_lchown16 # branch to system call
-
-#sys32_getpid_wrapper # void
-
-ENTRY(sys32_mount_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # char *
- llgfr %r5,%r5 # unsigned long
- llgtr %r6,%r6 # void *
- jg compat_sys_mount # branch to system call
-
-ENTRY(sys32_oldumount_wrapper)
- llgtr %r2,%r2 # char *
- jg sys_oldumount # branch to system call
-
-ENTRY(sys32_setuid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
- jg sys32_setuid16 # branch to system call
-
-#sys32_getuid16_wrapper # void
-
-ENTRY(sys32_ptrace_wrapper)
- lgfr %r2,%r2 # long
- lgfr %r3,%r3 # long
- llgtr %r4,%r4 # long
- llgfr %r5,%r5 # long
- jg compat_sys_ptrace # branch to system call
-
-ENTRY(sys32_alarm_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_alarm # branch to system call
-
-ENTRY(compat_sys_utime_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct compat_utimbuf *
- jg compat_sys_utime # branch to system call
-
-ENTRY(sys32_access_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- jg sys_access # branch to system call
-
-ENTRY(sys32_nice_wrapper)
- lgfr %r2,%r2 # int
- jg sys_nice # branch to system call
-
-#sys32_sync_wrapper # void
-
-ENTRY(sys32_kill_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- jg sys_kill # branch to system call
-
-ENTRY(sys32_rename_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # const char *
- jg sys_rename # branch to system call
-
-ENTRY(sys32_mkdir_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- jg sys_mkdir # branch to system call
-
-ENTRY(sys32_rmdir_wrapper)
- llgtr %r2,%r2 # const char *
- jg sys_rmdir # branch to system call
-
-ENTRY(sys32_dup_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_dup # branch to system call
-
-ENTRY(sys32_pipe_wrapper)
- llgtr %r2,%r2 # u32 *
- jg sys_pipe # branch to system call
-
-ENTRY(compat_sys_times_wrapper)
- llgtr %r2,%r2 # struct compat_tms *
- jg compat_sys_times # branch to system call
-
-ENTRY(sys32_brk_wrapper)
- llgtr %r2,%r2 # unsigned long
- jg sys_brk # branch to system call
-
-ENTRY(sys32_setgid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
- jg sys32_setgid16 # branch to system call
-
-#sys32_getgid16_wrapper # void
-
-ENTRY(sys32_signal_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # __sighandler_t
- jg sys_signal
-
-#sys32_geteuid16_wrapper # void
-
-#sys32_getegid16_wrapper # void
-
-ENTRY(sys32_acct_wrapper)
- llgtr %r2,%r2 # char *
- jg sys_acct # branch to system call
-
-ENTRY(sys32_umount_wrapper)
- llgtr %r2,%r2 # char *
- lgfr %r3,%r3 # int
- jg sys_umount # branch to system call
-
-ENTRY(compat_sys_ioctl_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- llgfr %r4,%r4 # unsigned int
- jg compat_sys_ioctl # branch to system call
-
-ENTRY(compat_sys_fcntl_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- llgfr %r4,%r4 # unsigned long
- jg compat_sys_fcntl # branch to system call
-
-ENTRY(sys32_setpgid_wrapper)
- lgfr %r2,%r2 # pid_t
- lgfr %r3,%r3 # pid_t
- jg sys_setpgid # branch to system call
-
-ENTRY(sys32_umask_wrapper)
- lgfr %r2,%r2 # int
- jg sys_umask # branch to system call
-
-ENTRY(sys32_chroot_wrapper)
- llgtr %r2,%r2 # char *
- jg sys_chroot # branch to system call
-
-ENTRY(sys32_ustat_wrapper)
- llgfr %r2,%r2 # dev_t
- llgtr %r3,%r3 # struct ustat *
- jg compat_sys_ustat
-
-ENTRY(sys32_dup2_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- jg sys_dup2 # branch to system call
-
-#sys32_getppid_wrapper # void
-
-#sys32_getpgrp_wrapper # void
-
-#sys32_setsid_wrapper # void
-
-ENTRY(sys32_setreuid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
- jg sys32_setreuid16 # branch to system call
-
-ENTRY(sys32_setregid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
- llgfr %r3,%r3 # __kernel_old_gid_emu31_t
- jg sys32_setregid16 # branch to system call
-
-ENTRY(sys_sigsuspend_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- llgfr %r4,%r4 # old_sigset_t
- jg sys_sigsuspend
-
-ENTRY(compat_sys_sigpending_wrapper)
- llgtr %r2,%r2 # compat_old_sigset_t *
- jg compat_sys_sigpending # branch to system call
-
-ENTRY(sys32_sethostname_wrapper)
- llgtr %r2,%r2 # char *
- lgfr %r3,%r3 # int
- jg sys_sethostname # branch to system call
-
-ENTRY(compat_sys_setrlimit_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # struct rlimit_emu31 *
- jg compat_sys_setrlimit # branch to system call
-
-ENTRY(compat_sys_old_getrlimit_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # struct rlimit_emu31 *
- jg compat_sys_old_getrlimit # branch to system call
-
-ENTRY(compat_sys_getrlimit_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # struct rlimit_emu31 *
- jg compat_sys_getrlimit # branch to system call
-
-ENTRY(sys32_mmap2_wrapper)
- llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
- jg sys32_mmap2 # branch to system call
-
-ENTRY(compat_sys_gettimeofday_wrapper)
- llgtr %r2,%r2 # struct timeval_emu31 *
- llgtr %r3,%r3 # struct timezone *
- jg compat_sys_gettimeofday # branch to system call
-
-ENTRY(compat_sys_settimeofday_wrapper)
- llgtr %r2,%r2 # struct timeval_emu31 *
- llgtr %r3,%r3 # struct timezone *
- jg compat_sys_settimeofday # branch to system call
-
-ENTRY(sys32_getgroups16_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
- jg sys32_getgroups16 # branch to system call
-
-ENTRY(sys32_setgroups16_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
- jg sys32_setgroups16 # branch to system call
-
-ENTRY(sys32_symlink_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # const char *
- jg sys_symlink # branch to system call
-
-ENTRY(sys32_readlink_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # char *
- lgfr %r4,%r4 # int
- jg sys_readlink # branch to system call
-
-ENTRY(sys32_uselib_wrapper)
- llgtr %r2,%r2 # const char *
- jg sys_uselib # branch to system call
-
-ENTRY(sys32_swapon_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- jg sys_swapon # branch to system call
-
-ENTRY(sys32_reboot_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- llgfr %r4,%r4 # unsigned int
- llgtr %r5,%r5 # void *
- jg sys_reboot # branch to system call
-
-ENTRY(old32_readdir_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # void *
- llgfr %r4,%r4 # unsigned int
- jg compat_sys_old_readdir # branch to system call
-
-ENTRY(old32_mmap_wrapper)
- llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
- jg old32_mmap # branch to system call
-
-ENTRY(sys32_munmap_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # size_t
- jg sys_munmap # branch to system call
-
-ENTRY(sys32_fchmod_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # mode_t
- jg sys_fchmod # branch to system call
-
-ENTRY(sys32_fchown16_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # compat_uid_t
- llgfr %r4,%r4 # compat_uid_t
- jg sys32_fchown16 # branch to system call
-
-ENTRY(sys32_getpriority_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- jg sys_getpriority # branch to system call
-
-ENTRY(sys32_setpriority_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- lgfr %r4,%r4 # int
- jg sys_setpriority # branch to system call
-
-ENTRY(compat_sys_statfs_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct compat_statfs *
- jg compat_sys_statfs # branch to system call
-
-ENTRY(compat_sys_fstatfs_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # struct compat_statfs *
- jg compat_sys_fstatfs # branch to system call
-
-ENTRY(compat_sys_socketcall_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # u32 *
- jg compat_sys_socketcall # branch to system call
-
-ENTRY(sys32_syslog_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # char *
- lgfr %r4,%r4 # int
- jg sys_syslog # branch to system call
-
-ENTRY(compat_sys_newstat_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct stat_emu31 *
- jg compat_sys_newstat # branch to system call
-
-ENTRY(compat_sys_newlstat_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct stat_emu31 *
- jg compat_sys_newlstat # branch to system call
-
-ENTRY(compat_sys_newfstat_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # struct stat_emu31 *
- jg compat_sys_newfstat # branch to system call
-
-#sys32_vhangup_wrapper # void
-
-ENTRY(sys32_swapoff_wrapper)
- llgtr %r2,%r2 # const char *
- jg sys_swapoff # branch to system call
-
-ENTRY(compat_sys_sysinfo_wrapper)
- llgtr %r2,%r2 # struct sysinfo_emu31 *
- jg compat_sys_sysinfo # branch to system call
-
-ENTRY(sys32_fsync_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_fsync # branch to system call
-
-#sys32_sigreturn_wrapper # done in sigreturn_glue
-
-#sys32_clone_wrapper # done in clone_glue
-
-ENTRY(sys32_setdomainname_wrapper)
- llgtr %r2,%r2 # char *
- lgfr %r3,%r3 # int
- jg sys_setdomainname # branch to system call
-
-ENTRY(sys32_newuname_wrapper)
- llgtr %r2,%r2 # struct new_utsname *
- jg sys_newuname # branch to system call
-
-ENTRY(compat_sys_adjtimex_wrapper)
- llgtr %r2,%r2 # struct compat_timex *
- jg compat_sys_adjtimex # branch to system call
-
-ENTRY(sys32_mprotect_wrapper)
- llgtr %r2,%r2 # unsigned long (actually pointer
- llgfr %r3,%r3 # size_t
- llgfr %r4,%r4 # unsigned long
- jg sys_mprotect # branch to system call
-
-ENTRY(sys_init_module_wrapper)
- llgtr %r2,%r2 # void *
- llgfr %r3,%r3 # unsigned long
- llgtr %r4,%r4 # char *
- jg sys_init_module # branch to system call
-
-ENTRY(sys_delete_module_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # unsigned int
- jg sys_delete_module # branch to system call
-
-ENTRY(sys32_quotactl_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # qid_t
- llgtr %r5,%r5 # caddr_t
- jg sys_quotactl # branch to system call
-
-ENTRY(sys32_getpgid_wrapper)
- lgfr %r2,%r2 # pid_t
- jg sys_getpgid # branch to system call
-
-ENTRY(sys32_fchdir_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_fchdir # branch to system call
-
-ENTRY(sys32_bdflush_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # long
- jg sys_bdflush # branch to system call
-
-ENTRY(sys32_sysfs_wrapper)
- lgfr %r2,%r2 # int
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- jg sys_sysfs # branch to system call
-
-ENTRY(sys32_personality_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_s390_personality # branch to system call
-
-ENTRY(sys32_setfsuid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
- jg sys32_setfsuid16 # branch to system call
-
-ENTRY(sys32_setfsgid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
- jg sys32_setfsgid16 # branch to system call
-
-ENTRY(sys32_llseek_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- llgtr %r5,%r5 # loff_t *
- llgfr %r6,%r6 # unsigned int
- jg sys_llseek # branch to system call
-
-ENTRY(sys32_getdents_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # void *
- llgfr %r4,%r4 # unsigned int
- jg compat_sys_getdents # branch to system call
-
-ENTRY(compat_sys_select_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # compat_fd_set *
- llgtr %r4,%r4 # compat_fd_set *
- llgtr %r5,%r5 # compat_fd_set *
- llgtr %r6,%r6 # struct compat_timeval *
- jg compat_sys_select # branch to system call
-
-ENTRY(sys32_flock_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- jg sys_flock # branch to system call
-
-ENTRY(sys32_msync_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # size_t
- lgfr %r4,%r4 # int
- jg sys_msync # branch to system call
-
-ENTRY(compat_sys_readv_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const struct compat_iovec *
- llgfr %r4,%r4 # unsigned long
- jg compat_sys_readv # branch to system call
-
-ENTRY(compat_sys_writev_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const struct compat_iovec *
- llgfr %r4,%r4 # unsigned long
- jg compat_sys_writev # branch to system call
-
-ENTRY(sys32_getsid_wrapper)
- lgfr %r2,%r2 # pid_t
- jg sys_getsid # branch to system call
-
-ENTRY(sys32_fdatasync_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_fdatasync # branch to system call
-
-ENTRY(sys32_mlock_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # size_t
- jg sys_mlock # branch to system call
-
-ENTRY(sys32_munlock_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # size_t
- jg sys_munlock # branch to system call
-
-ENTRY(sys32_mlockall_wrapper)
- lgfr %r2,%r2 # int
- jg sys_mlockall # branch to system call
-
-#sys32_munlockall_wrapper # void
-
-ENTRY(sys32_sched_setparam_wrapper)
- lgfr %r2,%r2 # pid_t
- llgtr %r3,%r3 # struct sched_param *
- jg sys_sched_setparam # branch to system call
-
-ENTRY(sys32_sched_getparam_wrapper)
- lgfr %r2,%r2 # pid_t
- llgtr %r3,%r3 # struct sched_param *
- jg sys_sched_getparam # branch to system call
-
-ENTRY(sys32_sched_setscheduler_wrapper)
- lgfr %r2,%r2 # pid_t
- lgfr %r3,%r3 # int
- llgtr %r4,%r4 # struct sched_param *
- jg sys_sched_setscheduler # branch to system call
-
-ENTRY(sys32_sched_getscheduler_wrapper)
- lgfr %r2,%r2 # pid_t
- jg sys_sched_getscheduler # branch to system call
-
-#sys32_sched_yield_wrapper # void
-
-ENTRY(sys32_sched_get_priority_max_wrapper)
- lgfr %r2,%r2 # int
- jg sys_sched_get_priority_max # branch to system call
-
-ENTRY(sys32_sched_get_priority_min_wrapper)
- lgfr %r2,%r2 # int
- jg sys_sched_get_priority_min # branch to system call
-
-ENTRY(compat_sys_nanosleep_wrapper)
- llgtr %r2,%r2 # struct compat_timespec *
- llgtr %r3,%r3 # struct compat_timespec *
- jg compat_sys_nanosleep # branch to system call
-
-ENTRY(sys32_mremap_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- llgfr %r5,%r5 # unsigned long
- llgfr %r6,%r6 # unsigned long
- jg sys_mremap # branch to system call
-
-ENTRY(sys32_setresuid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
- llgfr %r4,%r4 # __kernel_old_uid_emu31_t
- jg sys32_setresuid16 # branch to system call
-
-ENTRY(sys32_getresuid16_wrapper)
- llgtr %r2,%r2 # __kernel_old_uid_emu31_t *
- llgtr %r3,%r3 # __kernel_old_uid_emu31_t *
- llgtr %r4,%r4 # __kernel_old_uid_emu31_t *
- jg sys32_getresuid16 # branch to system call
-
-ENTRY(sys32_poll_wrapper)
- llgtr %r2,%r2 # struct pollfd *
- llgfr %r3,%r3 # unsigned int
- lgfr %r4,%r4 # int
- jg sys_poll # branch to system call
-
-ENTRY(sys32_setresgid16_wrapper)
- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
- llgfr %r3,%r3 # __kernel_old_gid_emu31_t
- llgfr %r4,%r4 # __kernel_old_gid_emu31_t
- jg sys32_setresgid16 # branch to system call
-
-ENTRY(sys32_getresgid16_wrapper)
- llgtr %r2,%r2 # __kernel_old_gid_emu31_t *
- llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
- llgtr %r4,%r4 # __kernel_old_gid_emu31_t *
- jg sys32_getresgid16 # branch to system call
-
-ENTRY(sys32_prctl_wrapper)
- lgfr %r2,%r2 # int
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- llgfr %r5,%r5 # unsigned long
- llgfr %r6,%r6 # unsigned long
- jg sys_prctl # branch to system call
-
-#sys32_rt_sigreturn_wrapper # done in rt_sigreturn_glue
-
-ENTRY(sys32_pread64_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # char *
- llgfr %r4,%r4 # size_t
- llgfr %r5,%r5 # u32
- llgfr %r6,%r6 # u32
- jg sys32_pread64 # branch to system call
-
-ENTRY(sys32_pwrite64_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # size_t
- llgfr %r5,%r5 # u32
- llgfr %r6,%r6 # u32
- jg sys32_pwrite64 # branch to system call
-
-ENTRY(sys32_chown16_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
- llgfr %r4,%r4 # __kernel_old_gid_emu31_t
- jg sys32_chown16 # branch to system call
-
-ENTRY(sys32_getcwd_wrapper)
- llgtr %r2,%r2 # char *
- llgfr %r3,%r3 # unsigned long
- jg sys_getcwd # branch to system call
-
-ENTRY(sys32_capget_wrapper)
- llgtr %r2,%r2 # cap_user_header_t
- llgtr %r3,%r3 # cap_user_data_t
- jg sys_capget # branch to system call
-
-ENTRY(sys32_capset_wrapper)
- llgtr %r2,%r2 # cap_user_header_t
- llgtr %r3,%r3 # const cap_user_data_t
- jg sys_capset # branch to system call
-
-#sys32_vfork_wrapper # done in vfork_glue
-
-ENTRY(sys32_truncate64_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- jg sys32_truncate64 # branch to system call
-
-ENTRY(sys32_ftruncate64_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- jg sys32_ftruncate64 # branch to system call
-
-ENTRY(sys32_lchown_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # uid_t
- llgfr %r4,%r4 # gid_t
- jg sys_lchown # branch to system call
-
-#sys32_getuid_wrapper # void
-#sys32_getgid_wrapper # void
-#sys32_geteuid_wrapper # void
-#sys32_getegid_wrapper # void
-
-ENTRY(sys32_setreuid_wrapper)
- llgfr %r2,%r2 # uid_t
- llgfr %r3,%r3 # uid_t
- jg sys_setreuid # branch to system call
-
-ENTRY(sys32_setregid_wrapper)
- llgfr %r2,%r2 # gid_t
- llgfr %r3,%r3 # gid_t
- jg sys_setregid # branch to system call
-
-ENTRY(sys32_getgroups_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # gid_t *
- jg sys_getgroups # branch to system call
-
-ENTRY(sys32_setgroups_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # gid_t *
- jg sys_setgroups # branch to system call
-
-ENTRY(sys32_fchown_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # uid_t
- llgfr %r4,%r4 # gid_t
- jg sys_fchown # branch to system call
-
-ENTRY(sys32_setresuid_wrapper)
- llgfr %r2,%r2 # uid_t
- llgfr %r3,%r3 # uid_t
- llgfr %r4,%r4 # uid_t
- jg sys_setresuid # branch to system call
-
-ENTRY(sys32_getresuid_wrapper)
- llgtr %r2,%r2 # uid_t *
- llgtr %r3,%r3 # uid_t *
- llgtr %r4,%r4 # uid_t *
- jg sys_getresuid # branch to system call
-
-ENTRY(sys32_setresgid_wrapper)
- llgfr %r2,%r2 # gid_t
- llgfr %r3,%r3 # gid_t
- llgfr %r4,%r4 # gid_t
- jg sys_setresgid # branch to system call
-
-ENTRY(sys32_getresgid_wrapper)
- llgtr %r2,%r2 # gid_t *
- llgtr %r3,%r3 # gid_t *
- llgtr %r4,%r4 # gid_t *
- jg sys_getresgid # branch to system call
-
-ENTRY(sys32_chown_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # uid_t
- llgfr %r4,%r4 # gid_t
- jg sys_chown # branch to system call
-
-ENTRY(sys32_setuid_wrapper)
- llgfr %r2,%r2 # uid_t
- jg sys_setuid # branch to system call
-
-ENTRY(sys32_setgid_wrapper)
- llgfr %r2,%r2 # gid_t
- jg sys_setgid # branch to system call
-
-ENTRY(sys32_setfsuid_wrapper)
- llgfr %r2,%r2 # uid_t
- jg sys_setfsuid # branch to system call
-
-ENTRY(sys32_setfsgid_wrapper)
- llgfr %r2,%r2 # gid_t
- jg sys_setfsgid # branch to system call
-
-ENTRY(sys32_pivot_root_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # const char *
- jg sys_pivot_root # branch to system call
-
-ENTRY(sys32_mincore_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # size_t
- llgtr %r4,%r4 # unsigned char *
- jg sys_mincore # branch to system call
-
-ENTRY(sys32_madvise_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # size_t
- lgfr %r4,%r4 # int
- jg sys_madvise # branch to system call
-
-ENTRY(sys32_getdents64_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # void *
- llgfr %r4,%r4 # unsigned int
- jg sys_getdents64 # branch to system call
-
-ENTRY(compat_sys_fcntl64_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- llgfr %r4,%r4 # unsigned long
- jg compat_sys_fcntl64 # branch to system call
-
-ENTRY(sys32_stat64_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct stat64 *
- jg sys32_stat64 # branch to system call
-
-ENTRY(sys32_lstat64_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct stat64 *
- jg sys32_lstat64 # branch to system call
-
-ENTRY(sys32_stime_wrapper)
- llgtr %r2,%r2 # long *
- jg compat_sys_stime # branch to system call
-
-ENTRY(sys32_fstat64_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgtr %r3,%r3 # struct stat64 *
- jg sys32_fstat64 # branch to system call
-
-ENTRY(sys32_setxattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # void *
- llgfr %r5,%r5 # size_t
- lgfr %r6,%r6 # int
- jg sys_setxattr
-
-ENTRY(sys32_lsetxattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # void *
- llgfr %r5,%r5 # size_t
- lgfr %r6,%r6 # int
- jg sys_lsetxattr
-
-ENTRY(sys32_fsetxattr_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # void *
- llgfr %r5,%r5 # size_t
- lgfr %r6,%r6 # int
- jg sys_fsetxattr
-
-ENTRY(sys32_getxattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # void *
- llgfr %r5,%r5 # size_t
- jg sys_getxattr
-
-ENTRY(sys32_lgetxattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # void *
- llgfr %r5,%r5 # size_t
- jg sys_lgetxattr
-
-ENTRY(sys32_fgetxattr_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # void *
- llgfr %r5,%r5 # size_t
- jg sys_fgetxattr
-
-ENTRY(sys32_listxattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgfr %r4,%r4 # size_t
- jg sys_listxattr
-
-ENTRY(sys32_llistxattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- llgfr %r4,%r4 # size_t
- jg sys_llistxattr
-
-ENTRY(sys32_flistxattr_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # char *
- llgfr %r4,%r4 # size_t
- jg sys_flistxattr
-
-ENTRY(sys32_removexattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- jg sys_removexattr
-
-ENTRY(sys32_lremovexattr_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # char *
- jg sys_lremovexattr
-
-ENTRY(sys32_fremovexattr_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # char *
- jg sys_fremovexattr
-
-ENTRY(sys32_sched_setaffinity_wrapper)
- lgfr %r2,%r2 # int
- llgfr %r3,%r3 # unsigned int
- llgtr %r4,%r4 # unsigned long *
- jg compat_sys_sched_setaffinity
-
-ENTRY(sys32_sched_getaffinity_wrapper)
- lgfr %r2,%r2 # int
- llgfr %r3,%r3 # unsigned int
- llgtr %r4,%r4 # unsigned long *
- jg compat_sys_sched_getaffinity
-
-ENTRY(sys32_exit_group_wrapper)
- lgfr %r2,%r2 # int
- jg sys_exit_group # branch to system call
-
-ENTRY(sys32_set_tid_address_wrapper)
- llgtr %r2,%r2 # int *
- jg sys_set_tid_address # branch to system call
-
-ENTRY(sys_epoll_create_wrapper)
- lgfr %r2,%r2 # int
- jg sys_epoll_create # branch to system call
-
-ENTRY(sys_epoll_ctl_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- lgfr %r4,%r4 # int
- llgtr %r5,%r5 # struct epoll_event *
- jg sys_epoll_ctl # branch to system call
-
-ENTRY(sys_epoll_wait_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # struct epoll_event *
- lgfr %r4,%r4 # int
- lgfr %r5,%r5 # int
- jg sys_epoll_wait # branch to system call
-
-ENTRY(sys32_fadvise64_wrapper)
- lgfr %r2,%r2 # int
- sllg %r3,%r3,32 # get high word of 64bit loff_t
- or %r3,%r4 # get low word of 64bit loff_t
- llgfr %r4,%r5 # size_t (unsigned long)
- lgfr %r5,%r6 # int
- jg sys32_fadvise64
-
-ENTRY(sys32_fadvise64_64_wrapper)
- llgtr %r2,%r2 # struct fadvise64_64_args *
- jg sys32_fadvise64_64
-
-ENTRY(sys32_clock_settime_wrapper)
- lgfr %r2,%r2 # clockid_t (int)
- llgtr %r3,%r3 # struct compat_timespec *
- jg compat_sys_clock_settime
-
-ENTRY(sys32_clock_gettime_wrapper)
- lgfr %r2,%r2 # clockid_t (int)
- llgtr %r3,%r3 # struct compat_timespec *
- jg compat_sys_clock_gettime
-
-ENTRY(sys32_clock_getres_wrapper)
- lgfr %r2,%r2 # clockid_t (int)
- llgtr %r3,%r3 # struct compat_timespec *
- jg compat_sys_clock_getres
-
-ENTRY(sys32_clock_nanosleep_wrapper)
- lgfr %r2,%r2 # clockid_t (int)
- lgfr %r3,%r3 # int
- llgtr %r4,%r4 # struct compat_timespec *
- llgtr %r5,%r5 # struct compat_timespec *
- jg compat_sys_clock_nanosleep
-
-ENTRY(sys32_timer_create_wrapper)
- lgfr %r2,%r2 # timer_t (int)
- llgtr %r3,%r3 # struct compat_sigevent *
- llgtr %r4,%r4 # timer_t *
- jg compat_sys_timer_create
-
-ENTRY(sys32_timer_settime_wrapper)
- lgfr %r2,%r2 # timer_t (int)
- lgfr %r3,%r3 # int
- llgtr %r4,%r4 # struct compat_itimerspec *
- llgtr %r5,%r5 # struct compat_itimerspec *
- jg compat_sys_timer_settime
-
-ENTRY(sys32_timer_gettime_wrapper)
- lgfr %r2,%r2 # timer_t (int)
- llgtr %r3,%r3 # struct compat_itimerspec *
- jg compat_sys_timer_gettime
-
-ENTRY(sys32_timer_getoverrun_wrapper)
- lgfr %r2,%r2 # timer_t (int)
- jg sys_timer_getoverrun
-
-ENTRY(sys32_timer_delete_wrapper)
- lgfr %r2,%r2 # timer_t (int)
- jg sys_timer_delete
-
-ENTRY(sys32_io_setup_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # u32 *
- jg compat_sys_io_setup
-
-ENTRY(sys32_io_destroy_wrapper)
- llgfr %r2,%r2 # (aio_context_t) u32
- jg sys_io_destroy
-
-ENTRY(sys32_io_getevents_wrapper)
- llgfr %r2,%r2 # (aio_context_t) u32
- lgfr %r3,%r3 # long
- lgfr %r4,%r4 # long
- llgtr %r5,%r5 # struct io_event *
- llgtr %r6,%r6 # struct compat_timespec *
- jg compat_sys_io_getevents
-
-ENTRY(sys32_io_submit_wrapper)
- llgfr %r2,%r2 # (aio_context_t) u32
- lgfr %r3,%r3 # long
- llgtr %r4,%r4 # struct iocb **
- jg compat_sys_io_submit
-
-ENTRY(sys32_io_cancel_wrapper)
- llgfr %r2,%r2 # (aio_context_t) u32
- llgtr %r3,%r3 # struct iocb *
- llgtr %r4,%r4 # struct io_event *
- jg sys_io_cancel
-
-ENTRY(compat_sys_statfs64_wrapper)
- llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # compat_size_t
- llgtr %r4,%r4 # struct compat_statfs64 *
- jg compat_sys_statfs64
-
-ENTRY(compat_sys_fstatfs64_wrapper)
- llgfr %r2,%r2 # unsigned int fd
- llgfr %r3,%r3 # compat_size_t
- llgtr %r4,%r4 # struct compat_statfs64 *
- jg compat_sys_fstatfs64
-
-ENTRY(compat_sys_mq_open_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- llgfr %r4,%r4 # mode_t
- llgtr %r5,%r5 # struct compat_mq_attr *
- jg compat_sys_mq_open
-
-ENTRY(sys32_mq_unlink_wrapper)
- llgtr %r2,%r2 # const char *
- jg sys_mq_unlink
-
-ENTRY(compat_sys_mq_timedsend_wrapper)
- lgfr %r2,%r2 # mqd_t
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # size_t
- llgfr %r5,%r5 # unsigned int
- llgtr %r6,%r6 # const struct compat_timespec *
- jg compat_sys_mq_timedsend
-
-ENTRY(compat_sys_mq_timedreceive_wrapper)
- lgfr %r2,%r2 # mqd_t
- llgtr %r3,%r3 # char *
- llgfr %r4,%r4 # size_t
- llgtr %r5,%r5 # unsigned int *
- llgtr %r6,%r6 # const struct compat_timespec *
- jg compat_sys_mq_timedreceive
-
-ENTRY(compat_sys_mq_notify_wrapper)
- lgfr %r2,%r2 # mqd_t
- llgtr %r3,%r3 # struct compat_sigevent *
- jg compat_sys_mq_notify
-
-ENTRY(compat_sys_mq_getsetattr_wrapper)
- lgfr %r2,%r2 # mqd_t
- llgtr %r3,%r3 # struct compat_mq_attr *
- llgtr %r4,%r4 # struct compat_mq_attr *
- jg compat_sys_mq_getsetattr
-
-ENTRY(compat_sys_add_key_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # const char *
- llgtr %r4,%r4 # const void *
- llgfr %r5,%r5 # size_t
- llgfr %r6,%r6 # (key_serial_t) u32
- jg sys_add_key
-
-ENTRY(compat_sys_request_key_wrapper)
- llgtr %r2,%r2 # const char *
- llgtr %r3,%r3 # const char *
- llgtr %r4,%r4 # const void *
- llgfr %r5,%r5 # (key_serial_t) u32
- jg sys_request_key
-
-ENTRY(sys32_remap_file_pages_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # unsigned long
- llgfr %r4,%r4 # unsigned long
- llgfr %r5,%r5 # unsigned long
- llgfr %r6,%r6 # unsigned long
- jg sys_remap_file_pages
-
-ENTRY(compat_sys_kexec_load_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # unsigned long
- llgtr %r4,%r4 # struct kexec_segment *
- llgfr %r5,%r5 # unsigned long
- jg compat_sys_kexec_load
-
-ENTRY(sys_ioprio_set_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- lgfr %r4,%r4 # int
- jg sys_ioprio_set
-
-ENTRY(sys_ioprio_get_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- jg sys_ioprio_get
-
-ENTRY(sys_inotify_add_watch_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # u32
- jg sys_inotify_add_watch
-
-ENTRY(sys_inotify_rm_watch_wrapper)
- lgfr %r2,%r2 # int
- llgfr %r3,%r3 # u32
- jg sys_inotify_rm_watch
-
-ENTRY(sys_mkdirat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- lgfr %r4,%r4 # int
- jg sys_mkdirat
-
-ENTRY(sys_mknodat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- lgfr %r4,%r4 # int
- llgfr %r5,%r5 # unsigned int
- jg sys_mknodat
-
-ENTRY(sys_fchownat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # uid_t
- llgfr %r5,%r5 # gid_t
- lgfr %r6,%r6 # int
- jg sys_fchownat
-
-ENTRY(compat_sys_futimesat_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # struct timeval *
- jg compat_sys_futimesat
-
-ENTRY(sys32_fstatat64_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # struct stat64 *
- lgfr %r5,%r5 # int
- jg sys32_fstatat64
-
-ENTRY(sys_unlinkat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- lgfr %r4,%r4 # int
- jg sys_unlinkat
-
-ENTRY(sys_renameat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- lgfr %r4,%r4 # int
- llgtr %r5,%r5 # const char *
- jg sys_renameat
-
-ENTRY(sys_linkat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- lgfr %r4,%r4 # int
- llgtr %r5,%r5 # const char *
- lgfr %r6,%r6 # int
- jg sys_linkat
-
-ENTRY(sys_symlinkat_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- llgtr %r4,%r4 # const char *
- jg sys_symlinkat
-
-ENTRY(sys_readlinkat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- llgtr %r4,%r4 # char *
- lgfr %r5,%r5 # int
- jg sys_readlinkat
-
-ENTRY(sys_fchmodat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- llgfr %r4,%r4 # mode_t
- jg sys_fchmodat
-
-ENTRY(sys_faccessat_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char *
- lgfr %r4,%r4 # int
- jg sys_faccessat
-
-ENTRY(compat_sys_pselect6_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # fd_set *
- llgtr %r4,%r4 # fd_set *
- llgtr %r5,%r5 # fd_set *
- llgtr %r6,%r6 # struct timespec *
- llgt %r0,164(%r15) # void *
- stg %r0,160(%r15)
- jg compat_sys_pselect6
-
-ENTRY(compat_sys_ppoll_wrapper)
- llgtr %r2,%r2 # struct pollfd *
- llgfr %r3,%r3 # unsigned int
- llgtr %r4,%r4 # struct timespec *
- llgtr %r5,%r5 # const sigset_t *
- llgfr %r6,%r6 # size_t
- jg compat_sys_ppoll
-
-ENTRY(sys_unshare_wrapper)
- llgfr %r2,%r2 # unsigned long
- jg sys_unshare
-
-ENTRY(sys_splice_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # loff_t *
- lgfr %r4,%r4 # int
- llgtr %r5,%r5 # loff_t *
- llgfr %r6,%r6 # size_t
- llgf %r0,164(%r15) # unsigned int
- stg %r0,160(%r15)
- jg sys_splice
-
-ENTRY(sys_sync_file_range_wrapper)
- lgfr %r2,%r2 # int
- sllg %r3,%r3,32 # get high word of 64bit loff_t
- or %r3,%r4 # get low word of 64bit loff_t
- sllg %r4,%r5,32 # get high word of 64bit loff_t
- or %r4,%r6 # get low word of 64bit loff_t
- llgf %r5,164(%r15) # unsigned int
- jg sys_sync_file_range
-
-ENTRY(sys_tee_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- llgfr %r4,%r4 # size_t
- llgfr %r5,%r5 # unsigned int
- jg sys_tee
-
-ENTRY(sys_getcpu_wrapper)
- llgtr %r2,%r2 # unsigned *
- llgtr %r3,%r3 # unsigned *
- llgtr %r4,%r4 # struct getcpu_cache *
- jg sys_getcpu
-
-ENTRY(compat_sys_utimes_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # struct compat_timeval *
- jg compat_sys_utimes
-
-ENTRY(compat_sys_utimensat_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # char *
- llgtr %r4,%r4 # struct compat_timespec *
- lgfr %r5,%r5 # int
- jg compat_sys_utimensat
-
-ENTRY(sys_eventfd_wrapper)
- llgfr %r2,%r2 # unsigned int
- jg sys_eventfd
-
-ENTRY(sys_fallocate_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- sllg %r4,%r4,32 # get high word of 64bit loff_t
- lr %r4,%r5 # get low word of 64bit loff_t
- sllg %r5,%r6,32 # get high word of 64bit loff_t
- l %r5,164(%r15) # get low word of 64bit loff_t
- jg sys_fallocate
-
-ENTRY(sys_timerfd_create_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- jg sys_timerfd_create
-
-ENTRY(sys_eventfd2_wrapper)
- llgfr %r2,%r2 # unsigned int
- lgfr %r3,%r3 # int
- jg sys_eventfd2
-
-ENTRY(sys_inotify_init1_wrapper)
- lgfr %r2,%r2 # int
- jg sys_inotify_init1
-
-ENTRY(sys_pipe2_wrapper)
- llgtr %r2,%r2 # u32 *
- lgfr %r3,%r3 # int
- jg sys_pipe2 # branch to system call
-
-ENTRY(sys_dup3_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- lgfr %r4,%r4 # int
- jg sys_dup3 # branch to system call
-
-ENTRY(sys_epoll_create1_wrapper)
- lgfr %r2,%r2 # int
- jg sys_epoll_create1 # branch to system call
-
-ENTRY(sys32_readahead_wrapper)
- lgfr %r2,%r2 # int
- llgfr %r3,%r3 # u32
- llgfr %r4,%r4 # u32
- lgfr %r5,%r5 # s32
- jg sys32_readahead # branch to system call
-
-ENTRY(sys_tkill_wrapper)
- lgfr %r2,%r2 # pid_t
- lgfr %r3,%r3 # int
- jg sys_tkill # branch to system call
-
-ENTRY(sys_tgkill_wrapper)
- lgfr %r2,%r2 # pid_t
- lgfr %r3,%r3 # pid_t
- lgfr %r4,%r4 # int
- jg sys_tgkill # branch to system call
-
-ENTRY(compat_sys_keyctl_wrapper)
- llgfr %r2,%r2 # u32
- llgfr %r3,%r3 # u32
- llgfr %r4,%r4 # u32
- llgfr %r5,%r5 # u32
- llgfr %r6,%r6 # u32
- jg compat_sys_keyctl # branch to system call
-
-ENTRY(sys_perf_event_open_wrapper)
- llgtr %r2,%r2 # const struct perf_event_attr *
- lgfr %r3,%r3 # pid_t
- lgfr %r4,%r4 # int
- lgfr %r5,%r5 # int
- llgfr %r6,%r6 # unsigned long
- jg sys_perf_event_open # branch to system call
-
-ENTRY(sys_clone_wrapper)
- llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # unsigned long
- llgtr %r4,%r4 # int *
- llgtr %r5,%r5 # int *
- jg sys_clone # branch to system call
-
-ENTRY(sys32_execve_wrapper)
- llgtr %r2,%r2 # char *
- llgtr %r3,%r3 # compat_uptr_t *
- llgtr %r4,%r4 # compat_uptr_t *
- jg compat_sys_execve # branch to system call
-
-ENTRY(sys_fanotify_init_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
- jg sys_fanotify_init # branch to system call
-
-ENTRY(sys_prlimit64_wrapper)
- lgfr %r2,%r2 # pid_t
- llgfr %r3,%r3 # unsigned int
- llgtr %r4,%r4 # const struct rlimit64 __user *
- llgtr %r5,%r5 # struct rlimit64 __user *
- jg sys_prlimit64 # branch to system call
-
-ENTRY(sys_name_to_handle_at_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char __user *
- llgtr %r4,%r4 # struct file_handle __user *
- llgtr %r5,%r5 # int __user *
- lgfr %r6,%r6 # int
- jg sys_name_to_handle_at
-
-ENTRY(compat_sys_clock_adjtime_wrapper)
- lgfr %r2,%r2 # clockid_t (int)
- llgtr %r3,%r3 # struct compat_timex __user *
- jg compat_sys_clock_adjtime
-
-ENTRY(sys_syncfs_wrapper)
- lgfr %r2,%r2 # int
- jg sys_syncfs
-
-ENTRY(sys_setns_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- jg sys_setns
-
-ENTRY(compat_sys_process_vm_readv_wrapper)
- lgfr %r2,%r2 # compat_pid_t
- llgtr %r3,%r3 # struct compat_iovec __user *
- llgfr %r4,%r4 # unsigned long
- llgtr %r5,%r5 # struct compat_iovec __user *
- llgfr %r6,%r6 # unsigned long
- llgf %r0,164(%r15) # unsigned long
- stg %r0,160(%r15)
- jg compat_sys_process_vm_readv
-
-ENTRY(compat_sys_process_vm_writev_wrapper)
- lgfr %r2,%r2 # compat_pid_t
- llgtr %r3,%r3 # struct compat_iovec __user *
- llgfr %r4,%r4 # unsigned long
- llgtr %r5,%r5 # struct compat_iovec __user *
- llgfr %r6,%r6 # unsigned long
- llgf %r0,164(%r15) # unsigned long
- stg %r0,160(%r15)
- jg compat_sys_process_vm_writev
-
-ENTRY(sys_s390_runtime_instr_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- jg sys_s390_runtime_instr
-
-ENTRY(sys_kcmp_wrapper)
- lgfr %r2,%r2 # pid_t
- lgfr %r3,%r3 # pid_t
- lgfr %r4,%r4 # int
- llgfr %r5,%r5 # unsigned long
- llgfr %r6,%r6 # unsigned long
- jg sys_kcmp
-
-ENTRY(sys_finit_module_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const char __user *
- lgfr %r4,%r4 # int
- jg sys_finit_module
-
-ENTRY(sys_sched_setattr_wrapper)
- lgfr %r2,%r2 # pid_t
- llgtr %r3,%r3 # struct sched_attr __user *
- jg sys_sched_setattr
-
-ENTRY(sys_sched_getattr_wrapper)
- lgfr %r2,%r2 # pid_t
- llgtr %r3,%r3 # const char __user *
- llgfr %r3,%r3 # unsigned int
- jg sys_sched_getattr
diff --git a/arch/s390/kernel/compat_wrapper.c b/arch/s390/kernel/compat_wrapper.c
new file mode 100644
index 000000000000..824c39dfddfc
--- /dev/null
+++ b/arch/s390/kernel/compat_wrapper.c
@@ -0,0 +1,215 @@
+/*
+ * Compat sytem call wrappers.
+ *
+ * Copyright IBM Corp. 2014
+ */
+
+#include <linux/syscalls.h>
+#include <linux/compat.h>
+#include "entry.h"
+
+#define COMPAT_SYSCALL_WRAP1(name, ...) \
+ COMPAT_SYSCALL_WRAPx(1, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP2(name, ...) \
+ COMPAT_SYSCALL_WRAPx(2, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP3(name, ...) \
+ COMPAT_SYSCALL_WRAPx(3, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP4(name, ...) \
+ COMPAT_SYSCALL_WRAPx(4, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP5(name, ...) \
+ COMPAT_SYSCALL_WRAPx(5, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_WRAP6(name, ...) \
+ COMPAT_SYSCALL_WRAPx(6, _##name, __VA_ARGS__)
+
+#define __SC_COMPAT_TYPE(t, a) \
+ __typeof(__builtin_choose_expr(sizeof(t) > 4, 0L, (t)0)) a
+
+#define __SC_COMPAT_CAST(t, a) \
+({ \
+ long __ReS = a; \
+ \
+ BUILD_BUG_ON((sizeof(t) > 4) && !__TYPE_IS_L(t) && \
+ !__TYPE_IS_UL(t) && !__TYPE_IS_PTR(t)); \
+ if (__TYPE_IS_L(t)) \
+ __ReS = (s32)a; \
+ if (__TYPE_IS_UL(t)) \
+ __ReS = (u32)a; \
+ if (__TYPE_IS_PTR(t)) \
+ __ReS = a & 0x7fffffff; \
+ (t)__ReS; \
+})
+
+/*
+ * The COMPAT_SYSCALL_WRAP macro generates system call wrappers to be used by
+ * compat tasks. These wrappers will only be used for system calls where only
+ * the system call arguments need sign or zero extension or zeroing of the upper
+ * 33 bits of pointers.
+ * Note: since the wrapper function will afterwards call a system call which
+ * again performs zero and sign extension for all system call arguments with
+ * a size of less than eight bytes, these compat wrappers only touch those
+ * system call arguments with a size of eight bytes ((unsigned) long and
+ * pointers). Zero and sign extension for e.g. int parameters will be done by
+ * the regular system call wrappers.
+ */
+#define COMPAT_SYSCALL_WRAPx(x, name, ...) \
+ asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
+ asmlinkage long compat_sys##name(__MAP(x,__SC_COMPAT_TYPE,__VA_ARGS__));\
+ asmlinkage long compat_sys##name(__MAP(x,__SC_COMPAT_TYPE,__VA_ARGS__)) \
+ { \
+ return sys##name(__MAP(x,__SC_COMPAT_CAST,__VA_ARGS__)); \
+ }
+
+COMPAT_SYSCALL_WRAP1(exit, int, error_code);
+COMPAT_SYSCALL_WRAP1(close, unsigned int, fd);
+COMPAT_SYSCALL_WRAP2(creat, const char __user *, pathname, umode_t, mode);
+COMPAT_SYSCALL_WRAP2(link, const char __user *, oldname, const char __user *, newname);
+COMPAT_SYSCALL_WRAP1(unlink, const char __user *, pathname);
+COMPAT_SYSCALL_WRAP1(chdir, const char __user *, filename);
+COMPAT_SYSCALL_WRAP3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev);
+COMPAT_SYSCALL_WRAP2(chmod, const char __user *, filename, umode_t, mode);
+COMPAT_SYSCALL_WRAP1(oldumount, char __user *, name);
+COMPAT_SYSCALL_WRAP1(alarm, unsigned int, seconds);
+COMPAT_SYSCALL_WRAP2(access, const char __user *, filename, int, mode);
+COMPAT_SYSCALL_WRAP1(nice, int, increment);
+COMPAT_SYSCALL_WRAP2(kill, int, pid, int, sig);
+COMPAT_SYSCALL_WRAP2(rename, const char __user *, oldname, const char __user *, newname);
+COMPAT_SYSCALL_WRAP2(mkdir, const char __user *, pathname, umode_t, mode);
+COMPAT_SYSCALL_WRAP1(rmdir, const char __user *, pathname);
+COMPAT_SYSCALL_WRAP1(dup, unsigned int, fildes);
+COMPAT_SYSCALL_WRAP1(pipe, int __user *, fildes);
+COMPAT_SYSCALL_WRAP1(brk, unsigned long, brk);
+COMPAT_SYSCALL_WRAP2(signal, int, sig, __sighandler_t, handler);
+COMPAT_SYSCALL_WRAP1(acct, const char __user *, name);
+COMPAT_SYSCALL_WRAP2(umount, char __user *, name, int, flags);
+COMPAT_SYSCALL_WRAP2(setpgid, pid_t, pid, pid_t, pgid);
+COMPAT_SYSCALL_WRAP1(umask, int, mask);
+COMPAT_SYSCALL_WRAP1(chroot, const char __user *, filename);
+COMPAT_SYSCALL_WRAP2(dup2, unsigned int, oldfd, unsigned int, newfd);
+COMPAT_SYSCALL_WRAP3(sigsuspend, int, unused1, int, unused2, old_sigset_t, mask);
+COMPAT_SYSCALL_WRAP2(sethostname, char __user *, name, int, len);
+COMPAT_SYSCALL_WRAP2(symlink, const char __user *, old, const char __user *, new);
+COMPAT_SYSCALL_WRAP3(readlink, const char __user *, path, char __user *, buf, int, bufsiz);
+COMPAT_SYSCALL_WRAP1(uselib, const char __user *, library);
+COMPAT_SYSCALL_WRAP2(swapon, const char __user *, specialfile, int, swap_flags);
+COMPAT_SYSCALL_WRAP4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg);
+COMPAT_SYSCALL_WRAP2(munmap, unsigned long, addr, size_t, len);
+COMPAT_SYSCALL_WRAP2(fchmod, unsigned int, fd, umode_t, mode);
+COMPAT_SYSCALL_WRAP2(getpriority, int, which, int, who);
+COMPAT_SYSCALL_WRAP3(setpriority, int, which, int, who, int, niceval);
+COMPAT_SYSCALL_WRAP3(syslog, int, type, char __user *, buf, int, len);
+COMPAT_SYSCALL_WRAP1(swapoff, const char __user *, specialfile);
+COMPAT_SYSCALL_WRAP1(fsync, unsigned int, fd);
+COMPAT_SYSCALL_WRAP2(setdomainname, char __user *, name, int, len);
+COMPAT_SYSCALL_WRAP1(newuname, struct new_utsname __user *, name);
+COMPAT_SYSCALL_WRAP3(mprotect, unsigned long, start, size_t, len, unsigned long, prot);
+COMPAT_SYSCALL_WRAP3(init_module, void __user *, umod, unsigned long, len, const char __user *, uargs);
+COMPAT_SYSCALL_WRAP2(delete_module, const char __user *, name_user, unsigned int, flags);
+COMPAT_SYSCALL_WRAP4(quotactl, unsigned int, cmd, const char __user *, special, qid_t, id, void __user *, addr);
+COMPAT_SYSCALL_WRAP1(getpgid, pid_t, pid);
+COMPAT_SYSCALL_WRAP1(fchdir, unsigned int, fd);
+COMPAT_SYSCALL_WRAP2(bdflush, int, func, long, data);
+COMPAT_SYSCALL_WRAP3(sysfs, int, option, unsigned long, arg1, unsigned long, arg2);
+COMPAT_SYSCALL_WRAP1(s390_personality, unsigned int, personality);
+COMPAT_SYSCALL_WRAP5(llseek, unsigned int, fd, unsigned long, high, unsigned long, low, loff_t __user *, result, unsigned int, whence);
+COMPAT_SYSCALL_WRAP2(flock, unsigned int, fd, unsigned int, cmd);
+COMPAT_SYSCALL_WRAP3(msync, unsigned long, start, size_t, len, int, flags);
+COMPAT_SYSCALL_WRAP1(getsid, pid_t, pid);
+COMPAT_SYSCALL_WRAP1(fdatasync, unsigned int, fd);
+COMPAT_SYSCALL_WRAP2(mlock, unsigned long, start, size_t, len);
+COMPAT_SYSCALL_WRAP2(munlock, unsigned long, start, size_t, len);
+COMPAT_SYSCALL_WRAP1(mlockall, int, flags);
+COMPAT_SYSCALL_WRAP2(sched_setparam, pid_t, pid, struct sched_param __user *, param);
+COMPAT_SYSCALL_WRAP2(sched_getparam, pid_t, pid, struct sched_param __user *, param);
+COMPAT_SYSCALL_WRAP3(sched_setscheduler, pid_t, pid, int, policy, struct sched_param __user *, param);
+COMPAT_SYSCALL_WRAP1(sched_getscheduler, pid_t, pid);
+COMPAT_SYSCALL_WRAP1(sched_get_priority_max, int, policy);
+COMPAT_SYSCALL_WRAP1(sched_get_priority_min, int, policy);
+COMPAT_SYSCALL_WRAP5(mremap, unsigned long, addr, unsigned long, old_len, unsigned long, new_len, unsigned long, flags, unsigned long, new_addr);
+COMPAT_SYSCALL_WRAP3(poll, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout);
+COMPAT_SYSCALL_WRAP5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, unsigned long, arg4, unsigned long, arg5);
+COMPAT_SYSCALL_WRAP2(getcwd, char __user *, buf, unsigned long, size);
+COMPAT_SYSCALL_WRAP2(capget, cap_user_header_t, header, cap_user_data_t, dataptr);
+COMPAT_SYSCALL_WRAP2(capset, cap_user_header_t, header, const cap_user_data_t, data);
+COMPAT_SYSCALL_WRAP3(lchown, const char __user *, filename, uid_t, user, gid_t, group);
+COMPAT_SYSCALL_WRAP2(setreuid, uid_t, ruid, uid_t, euid);
+COMPAT_SYSCALL_WRAP2(setregid, gid_t, rgid, gid_t, egid);
+COMPAT_SYSCALL_WRAP2(getgroups, int, gidsetsize, gid_t __user *, grouplist);
+COMPAT_SYSCALL_WRAP2(setgroups, int, gidsetsize, gid_t __user *, grouplist);
+COMPAT_SYSCALL_WRAP3(fchown, unsigned int, fd, uid_t, user, gid_t, group);
+COMPAT_SYSCALL_WRAP3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid);
+COMPAT_SYSCALL_WRAP3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __user *, suid);
+COMPAT_SYSCALL_WRAP3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid);
+COMPAT_SYSCALL_WRAP3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, sgid);
+COMPAT_SYSCALL_WRAP3(chown, const char __user *, filename, uid_t, user, gid_t, group);
+COMPAT_SYSCALL_WRAP1(setuid, uid_t, uid);
+COMPAT_SYSCALL_WRAP1(setgid, gid_t, gid);
+COMPAT_SYSCALL_WRAP1(setfsuid, uid_t, uid);
+COMPAT_SYSCALL_WRAP1(setfsgid, gid_t, gid);
+COMPAT_SYSCALL_WRAP2(pivot_root, const char __user *, new_root, const char __user *, put_old);
+COMPAT_SYSCALL_WRAP3(mincore, unsigned long, start, size_t, len, unsigned char __user *, vec);
+COMPAT_SYSCALL_WRAP3(madvise, unsigned long, start, size_t, len, int, behavior);
+COMPAT_SYSCALL_WRAP5(setxattr, const char __user *, path, const char __user *, name, const void __user *, value, size_t, size, int, flags);
+COMPAT_SYSCALL_WRAP5(lsetxattr, const char __user *, path, const char __user *, name, const void __user *, value, size_t, size, int, flags);
+COMPAT_SYSCALL_WRAP5(fsetxattr, int, fd, const char __user *, name, const void __user *, value, size_t, size, int, flags);
+COMPAT_SYSCALL_WRAP3(getdents64, unsigned int, fd, struct linux_dirent64 __user *, dirent, unsigned int, count);
+COMPAT_SYSCALL_WRAP4(getxattr, const char __user *, path, const char __user *, name, void __user *, value, size_t, size);
+COMPAT_SYSCALL_WRAP4(lgetxattr, const char __user *, path, const char __user *, name, void __user *, value, size_t, size);
+COMPAT_SYSCALL_WRAP4(fgetxattr, int, fd, const char __user *, name, void __user *, value, size_t, size);
+COMPAT_SYSCALL_WRAP3(listxattr, const char __user *, path, char __user *, list, size_t, size);
+COMPAT_SYSCALL_WRAP3(llistxattr, const char __user *, path, char __user *, list, size_t, size);
+COMPAT_SYSCALL_WRAP3(flistxattr, int, fd, char __user *, list, size_t, size);
+COMPAT_SYSCALL_WRAP2(removexattr, const char __user *, path, const char __user *, name);
+COMPAT_SYSCALL_WRAP2(lremovexattr, const char __user *, path, const char __user *, name);
+COMPAT_SYSCALL_WRAP2(fremovexattr, int, fd, const char __user *, name);
+COMPAT_SYSCALL_WRAP1(exit_group, int, error_code);
+COMPAT_SYSCALL_WRAP1(set_tid_address, int __user *, tidptr);
+COMPAT_SYSCALL_WRAP1(epoll_create, int, size);
+COMPAT_SYSCALL_WRAP4(epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event __user *, event);
+COMPAT_SYSCALL_WRAP4(epoll_wait, int, epfd, struct epoll_event __user *, events, int, maxevents, int, timeout);
+COMPAT_SYSCALL_WRAP1(timer_getoverrun, timer_t, timer_id);
+COMPAT_SYSCALL_WRAP1(timer_delete, compat_timer_t, compat_timer_id);
+COMPAT_SYSCALL_WRAP1(io_destroy, aio_context_t, ctx);
+COMPAT_SYSCALL_WRAP3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb, struct io_event __user *, result);
+COMPAT_SYSCALL_WRAP1(mq_unlink, const char __user *, name);
+COMPAT_SYSCALL_WRAP5(add_key, const char __user *, tp, const char __user *, dsc, const void __user *, pld, size_t, len, key_serial_t, id);
+COMPAT_SYSCALL_WRAP4(request_key, const char __user *, tp, const char __user *, dsc, const char __user *, info, key_serial_t, id);
+COMPAT_SYSCALL_WRAP5(remap_file_pages, unsigned long, start, unsigned long, size, unsigned long, prot, unsigned long, pgoff, unsigned long, flags);
+COMPAT_SYSCALL_WRAP3(ioprio_set, int, which, int, who, int, ioprio);
+COMPAT_SYSCALL_WRAP2(ioprio_get, int, which, int, who);
+COMPAT_SYSCALL_WRAP3(inotify_add_watch, int, fd, const char __user *, path, u32, mask);
+COMPAT_SYSCALL_WRAP2(inotify_rm_watch, int, fd, __s32, wd);
+COMPAT_SYSCALL_WRAP3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode);
+COMPAT_SYSCALL_WRAP4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, unsigned, dev);
+COMPAT_SYSCALL_WRAP5(fchownat, int, dfd, const char __user *, filename, uid_t, user, gid_t, group, int, flag);
+COMPAT_SYSCALL_WRAP3(unlinkat, int, dfd, const char __user *, pathname, int, flag);
+COMPAT_SYSCALL_WRAP4(renameat, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname);
+COMPAT_SYSCALL_WRAP5(linkat, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname, int, flags);
+COMPAT_SYSCALL_WRAP3(symlinkat, const char __user *, oldname, int, newdfd, const char __user *, newname);
+COMPAT_SYSCALL_WRAP4(readlinkat, int, dfd, const char __user *, path, char __user *, buf, int, bufsiz);
+COMPAT_SYSCALL_WRAP3(fchmodat, int, dfd, const char __user *, filename, umode_t, mode);
+COMPAT_SYSCALL_WRAP3(faccessat, int, dfd, const char __user *, filename, int, mode);
+COMPAT_SYSCALL_WRAP1(unshare, unsigned long, unshare_flags);
+COMPAT_SYSCALL_WRAP6(splice, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags);
+COMPAT_SYSCALL_WRAP4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags);
+COMPAT_SYSCALL_WRAP3(getcpu, unsigned __user *, cpu, unsigned __user *, node, struct getcpu_cache __user *, cache);
+COMPAT_SYSCALL_WRAP1(eventfd, unsigned int, count);
+COMPAT_SYSCALL_WRAP2(timerfd_create, int, clockid, int, flags);
+COMPAT_SYSCALL_WRAP2(eventfd2, unsigned int, count, int, flags);
+COMPAT_SYSCALL_WRAP1(inotify_init1, int, flags);
+COMPAT_SYSCALL_WRAP2(pipe2, int __user *, fildes, int, flags);
+COMPAT_SYSCALL_WRAP3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags);
+COMPAT_SYSCALL_WRAP1(epoll_create1, int, flags);
+COMPAT_SYSCALL_WRAP2(tkill, int, pid, int, sig);
+COMPAT_SYSCALL_WRAP3(tgkill, int, tgid, int, pid, int, sig);
+COMPAT_SYSCALL_WRAP5(perf_event_open, struct perf_event_attr __user *, attr_uptr, pid_t, pid, int, cpu, int, group_fd, unsigned long, flags);
+COMPAT_SYSCALL_WRAP5(clone, unsigned long, newsp, unsigned long, clone_flags, int __user *, parent_tidptr, int __user *, child_tidptr, int, tls_val);
+COMPAT_SYSCALL_WRAP2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags);
+COMPAT_SYSCALL_WRAP4(prlimit64, pid_t, pid, unsigned int, resource, const struct rlimit64 __user *, new_rlim, struct rlimit64 __user *, old_rlim);
+COMPAT_SYSCALL_WRAP5(name_to_handle_at, int, dfd, const char __user *, name, struct file_handle __user *, handle, int __user *, mnt_id, int, flag);
+COMPAT_SYSCALL_WRAP1(syncfs, int, fd);
+COMPAT_SYSCALL_WRAP2(setns, int, fd, int, nstype);
+COMPAT_SYSCALL_WRAP2(s390_runtime_instr, int, command, int, signum);
+COMPAT_SYSCALL_WRAP5(kcmp, pid_t, pid1, pid_t, pid2, int, type, unsigned long, idx1, unsigned long, idx2);
+COMPAT_SYSCALL_WRAP3(finit_module, int, fd, const char __user *, uargs, int, flags);
+COMPAT_SYSCALL_WRAP3(sched_setattr, pid_t, pid, struct sched_attr __user *, attr, unsigned int, flags);
+COMPAT_SYSCALL_WRAP4(sched_getattr, pid_t, pid, struct sched_attr __user *, attr, unsigned int, size, unsigned int, flags);
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index fca20b5fe79e..6b594439cca5 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -380,8 +380,6 @@ static __init void detect_machine_facilities(void)
S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT2;
if (test_facility(3))
S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
- if (test_facility(27))
- S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
if (test_facility(40))
S390_lowcore.machine_flags |= MACHINE_FLAG_LPP;
if (test_facility(50) && test_facility(73))
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 0dc2b6d0a1ec..526d3735ed29 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -43,6 +43,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING)
_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
_TIF_SYSCALL_TRACEPOINT)
+_TIF_TRANSFER = (_TIF_MCCK_PENDING | _TIF_TLB_WAIT)
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE = 1 << STACK_SHIFT
@@ -159,10 +160,12 @@ ENTRY(__switch_to)
lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
l %r15,__THREAD_ksp(%r3) # load kernel stack of next
- tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending?
+ lhi %r6,_TIF_TRANSFER # transfer TIF bits
+ n %r6,__TI_flags(%r4) # isolate TIF bits
jz 0f
- ni __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
- oi __TI_flags+3(%r5),_TIF_MCCK_PENDING # set it in next
+ o %r6,__TI_flags(%r5) # set TIF bits of next
+ st %r6,__TI_flags(%r5)
+ ni __TI_flags+3(%r4),255-_TIF_TRANSFER # clear TIF bits of prev
0: lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task
br %r14
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index cb533f78c09e..6ac78192455f 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -67,9 +67,7 @@ struct s390_mmap_arg_struct;
struct fadvise64_64_args;
struct old_sigaction;
-long sys_sigreturn(void);
-long sys_rt_sigreturn(void);
-long sys32_sigreturn(void);
-long sys32_rt_sigreturn(void);
+long sys_s390_personality(unsigned int personality);
+long sys_s390_runtime_instr(int command, int signum);
#endif /* _ENTRY_H */
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 384e609b4711..e09dbe5f2901 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -48,6 +48,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING)
_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
_TIF_SYSCALL_TRACEPOINT)
+_TIF_TRANSFER = (_TIF_MCCK_PENDING | _TIF_TLB_WAIT)
#define BASED(name) name-system_call(%r13)
@@ -189,10 +190,12 @@ ENTRY(__switch_to)
lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
mvc __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
lg %r15,__THREAD_ksp(%r3) # load kernel stack of next
- tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending?
+ llill %r6,_TIF_TRANSFER # transfer TIF bits
+ ng %r6,__TI_flags(%r4) # isolate TIF bits
jz 0f
- ni __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
- oi __TI_flags+7(%r5),_TIF_MCCK_PENDING # set it in next
+ og %r6,__TI_flags(%r5) # set TIF bits of next
+ stg %r6,__TI_flags(%r5)
+ ni __TI_flags+7(%r4),255-_TIF_TRANSFER # clear TIF bits of prev
0: lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task
br %r14
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index bb27a262c44a..d42b14cc72a4 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -18,6 +18,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/cpu.h>
+#include <linux/irq.h>
#include <asm/irq_regs.h>
#include <asm/cputime.h>
#include <asm/lowcore.h>
@@ -84,6 +85,7 @@ static const struct irq_class irqclass_sub_desc[NR_ARCH_IRQS] = {
[IRQIO_PCI] = {.name = "PCI", .desc = "[I/O] PCI Interrupt" },
[IRQIO_MSI] = {.name = "MSI", .desc = "[I/O] MSI Interrupt" },
[IRQIO_VIR] = {.name = "VIR", .desc = "[I/O] Virtual I/O Devices"},
+ [IRQIO_VAI] = {.name = "VAI", .desc = "[I/O] Virtual I/O Devices AI"},
[NMI_NMI] = {.name = "NMI", .desc = "[NMI] Machine Check"},
[CPU_RST] = {.name = "RST", .desc = "[CPU] CPU Restart"},
};
diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c
index 5d2dfa31c4ef..61595c1f0a0f 100644
--- a/arch/s390/kernel/perf_event.c
+++ b/arch/s390/kernel/perf_event.c
@@ -121,7 +121,7 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
: PERF_RECORD_MISC_KERNEL;
}
-void print_debug_cf(void)
+static void print_debug_cf(void)
{
struct cpumf_ctr_info cf_info;
int cpu = smp_processor_id();
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index f6be6087a0e9..4ac8fafec95f 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -85,7 +85,10 @@ void update_cr_regs(struct task_struct *task)
/* merge TIF_SINGLE_STEP into user specified PER registers. */
if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) {
- new.control |= PER_EVENT_IFETCH;
+ if (test_tsk_thread_flag(task, TIF_BLOCK_STEP))
+ new.control |= PER_EVENT_BRANCH;
+ else
+ new.control |= PER_EVENT_IFETCH;
#ifdef CONFIG_64BIT
new.control |= PER_CONTROL_SUSPENSION;
new.control |= PER_EVENT_TRANSACTION_END;
@@ -107,14 +110,22 @@ void update_cr_regs(struct task_struct *task)
void user_enable_single_step(struct task_struct *task)
{
+ clear_tsk_thread_flag(task, TIF_BLOCK_STEP);
set_tsk_thread_flag(task, TIF_SINGLE_STEP);
}
void user_disable_single_step(struct task_struct *task)
{
+ clear_tsk_thread_flag(task, TIF_BLOCK_STEP);
clear_tsk_thread_flag(task, TIF_SINGLE_STEP);
}
+void user_enable_block_step(struct task_struct *task)
+{
+ set_tsk_thread_flag(task, TIF_SINGLE_STEP);
+ set_tsk_thread_flag(task, TIF_BLOCK_STEP);
+}
+
/*
* Called by kernel/ptrace.c when detaching..
*
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 09e2f468f48b..f70f2489fa5f 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -47,7 +47,6 @@
#include <linux/compat.h>
#include <asm/ipl.h>
-#include <asm/uaccess.h>
#include <asm/facility.h>
#include <asm/smp.h>
#include <asm/mmu_context.h>
@@ -65,12 +64,6 @@
#include "entry.h"
/*
- * User copy operations.
- */
-struct uaccess_ops uaccess;
-EXPORT_SYMBOL(uaccess);
-
-/*
* Machine setup..
*/
unsigned int console_mode = 0;
@@ -294,14 +287,6 @@ static int __init parse_vmalloc(char *arg)
}
early_param("vmalloc", parse_vmalloc);
-static int __init early_parse_user_mode(char *p)
-{
- if (!p || strcmp(p, "primary") == 0)
- return 0;
- return 1;
-}
-early_param("user_mode", early_parse_user_mode);
-
void *restart_stack __attribute__((__section__(".data")));
static void __init setup_lowcore(void)
@@ -1009,8 +994,6 @@ void __init setup_arch(char **cmdline_p)
init_mm.end_data = (unsigned long) &_edata;
init_mm.brk = (unsigned long) &_end;
- uaccess = MACHINE_HAS_MVCOS ? uaccess_mvcos : uaccess_pt;
-
parse_early_param();
detect_memory_layout(memory_chunk, memory_end);
os_info_init();
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index a7125b62a9a6..8827883310dd 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -773,11 +773,11 @@ void __noreturn cpu_die(void)
void __init smp_fill_possible_mask(void)
{
- unsigned int possible, cpu;
+ unsigned int possible, sclp, cpu;
- possible = setup_possible_cpus;
- if (!possible)
- possible = MACHINE_IS_VM ? 64 : nr_cpu_ids;
+ sclp = sclp_get_max_cpu() ?: nr_cpu_ids;
+ possible = setup_possible_cpus ?: nr_cpu_ids;
+ possible = min(possible, sclp);
for (cpu = 0; cpu < possible && cpu < nr_cpu_ids; cpu++)
set_cpu_possible(cpu, true);
}
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 143992152ec9..542ef488bac1 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -9,349 +9,349 @@
#define NI_SYSCALL SYSCALL(sys_ni_syscall,sys_ni_syscall,sys_ni_syscall)
NI_SYSCALL /* 0 */
-SYSCALL(sys_exit,sys_exit,sys32_exit_wrapper)
+SYSCALL(sys_exit,sys_exit,compat_sys_exit)
SYSCALL(sys_fork,sys_fork,sys_fork)
-SYSCALL(sys_read,sys_read,sys32_read_wrapper)
-SYSCALL(sys_write,sys_write,sys32_write_wrapper)
+SYSCALL(sys_read,sys_read,compat_sys_s390_read)
+SYSCALL(sys_write,sys_write,compat_sys_s390_write)
SYSCALL(sys_open,sys_open,compat_sys_open) /* 5 */
-SYSCALL(sys_close,sys_close,sys32_close_wrapper)
+SYSCALL(sys_close,sys_close,compat_sys_close)
SYSCALL(sys_restart_syscall,sys_restart_syscall,sys_restart_syscall)
-SYSCALL(sys_creat,sys_creat,sys32_creat_wrapper)
-SYSCALL(sys_link,sys_link,sys32_link_wrapper)
-SYSCALL(sys_unlink,sys_unlink,sys32_unlink_wrapper) /* 10 */
-SYSCALL(sys_execve,sys_execve,sys32_execve_wrapper)
-SYSCALL(sys_chdir,sys_chdir,sys32_chdir_wrapper)
-SYSCALL(sys_time,sys_ni_syscall,sys32_time_wrapper) /* old time syscall */
-SYSCALL(sys_mknod,sys_mknod,sys32_mknod_wrapper)
-SYSCALL(sys_chmod,sys_chmod,sys32_chmod_wrapper) /* 15 */
-SYSCALL(sys_lchown16,sys_ni_syscall,sys32_lchown16_wrapper) /* old lchown16 syscall*/
+SYSCALL(sys_creat,sys_creat,compat_sys_creat)
+SYSCALL(sys_link,sys_link,compat_sys_link)
+SYSCALL(sys_unlink,sys_unlink,compat_sys_unlink) /* 10 */
+SYSCALL(sys_execve,sys_execve,compat_sys_execve)
+SYSCALL(sys_chdir,sys_chdir,compat_sys_chdir)
+SYSCALL(sys_time,sys_ni_syscall,compat_sys_time) /* old time syscall */
+SYSCALL(sys_mknod,sys_mknod,compat_sys_mknod)
+SYSCALL(sys_chmod,sys_chmod,compat_sys_chmod) /* 15 */
+SYSCALL(sys_lchown16,sys_ni_syscall,compat_sys_s390_lchown16) /* old lchown16 syscall*/
NI_SYSCALL /* old break syscall holder */
NI_SYSCALL /* old stat syscall holder */
SYSCALL(sys_lseek,sys_lseek,compat_sys_lseek)
SYSCALL(sys_getpid,sys_getpid,sys_getpid) /* 20 */
-SYSCALL(sys_mount,sys_mount,sys32_mount_wrapper)
-SYSCALL(sys_oldumount,sys_oldumount,sys32_oldumount_wrapper)
-SYSCALL(sys_setuid16,sys_ni_syscall,sys32_setuid16_wrapper) /* old setuid16 syscall*/
-SYSCALL(sys_getuid16,sys_ni_syscall,sys32_getuid16) /* old getuid16 syscall*/
-SYSCALL(sys_stime,sys_ni_syscall,sys32_stime_wrapper) /* 25 old stime syscall */
-SYSCALL(sys_ptrace,sys_ptrace,sys32_ptrace_wrapper)
-SYSCALL(sys_alarm,sys_alarm,sys32_alarm_wrapper)
+SYSCALL(sys_mount,sys_mount,compat_sys_mount)
+SYSCALL(sys_oldumount,sys_oldumount,compat_sys_oldumount)
+SYSCALL(sys_setuid16,sys_ni_syscall,compat_sys_s390_setuid16) /* old setuid16 syscall*/
+SYSCALL(sys_getuid16,sys_ni_syscall,compat_sys_s390_getuid16) /* old getuid16 syscall*/
+SYSCALL(sys_stime,sys_ni_syscall,compat_sys_stime) /* 25 old stime syscall */
+SYSCALL(sys_ptrace,sys_ptrace,compat_sys_ptrace)
+SYSCALL(sys_alarm,sys_alarm,compat_sys_alarm)
NI_SYSCALL /* old fstat syscall */
SYSCALL(sys_pause,sys_pause,sys_pause)
-SYSCALL(sys_utime,sys_utime,compat_sys_utime_wrapper) /* 30 */
+SYSCALL(sys_utime,sys_utime,compat_sys_utime) /* 30 */
NI_SYSCALL /* old stty syscall */
NI_SYSCALL /* old gtty syscall */
-SYSCALL(sys_access,sys_access,sys32_access_wrapper)
-SYSCALL(sys_nice,sys_nice,sys32_nice_wrapper)
+SYSCALL(sys_access,sys_access,compat_sys_access)
+SYSCALL(sys_nice,sys_nice,compat_sys_nice)
NI_SYSCALL /* 35 old ftime syscall */
SYSCALL(sys_sync,sys_sync,sys_sync)
-SYSCALL(sys_kill,sys_kill,sys32_kill_wrapper)
-SYSCALL(sys_rename,sys_rename,sys32_rename_wrapper)
-SYSCALL(sys_mkdir,sys_mkdir,sys32_mkdir_wrapper)
-SYSCALL(sys_rmdir,sys_rmdir,sys32_rmdir_wrapper) /* 40 */
-SYSCALL(sys_dup,sys_dup,sys32_dup_wrapper)
-SYSCALL(sys_pipe,sys_pipe,sys32_pipe_wrapper)
-SYSCALL(sys_times,sys_times,compat_sys_times_wrapper)
+SYSCALL(sys_kill,sys_kill,compat_sys_kill)
+SYSCALL(sys_rename,sys_rename,compat_sys_rename)
+SYSCALL(sys_mkdir,sys_mkdir,compat_sys_mkdir)
+SYSCALL(sys_rmdir,sys_rmdir,compat_sys_rmdir) /* 40 */
+SYSCALL(sys_dup,sys_dup,compat_sys_dup)
+SYSCALL(sys_pipe,sys_pipe,compat_sys_pipe)
+SYSCALL(sys_times,sys_times,compat_sys_times)
NI_SYSCALL /* old prof syscall */
-SYSCALL(sys_brk,sys_brk,sys32_brk_wrapper) /* 45 */
-SYSCALL(sys_setgid16,sys_ni_syscall,sys32_setgid16_wrapper) /* old setgid16 syscall*/
-SYSCALL(sys_getgid16,sys_ni_syscall,sys32_getgid16) /* old getgid16 syscall*/
-SYSCALL(sys_signal,sys_signal,sys32_signal_wrapper)
-SYSCALL(sys_geteuid16,sys_ni_syscall,sys32_geteuid16) /* old geteuid16 syscall */
-SYSCALL(sys_getegid16,sys_ni_syscall,sys32_getegid16) /* 50 old getegid16 syscall */
-SYSCALL(sys_acct,sys_acct,sys32_acct_wrapper)
-SYSCALL(sys_umount,sys_umount,sys32_umount_wrapper)
+SYSCALL(sys_brk,sys_brk,compat_sys_brk) /* 45 */
+SYSCALL(sys_setgid16,sys_ni_syscall,compat_sys_s390_setgid16) /* old setgid16 syscall*/
+SYSCALL(sys_getgid16,sys_ni_syscall,compat_sys_s390_getgid16) /* old getgid16 syscall*/
+SYSCALL(sys_signal,sys_signal,compat_sys_signal)
+SYSCALL(sys_geteuid16,sys_ni_syscall,compat_sys_s390_geteuid16) /* old geteuid16 syscall */
+SYSCALL(sys_getegid16,sys_ni_syscall,compat_sys_s390_getegid16) /* 50 old getegid16 syscall */
+SYSCALL(sys_acct,sys_acct,compat_sys_acct)
+SYSCALL(sys_umount,sys_umount,compat_sys_umount)
NI_SYSCALL /* old lock syscall */
-SYSCALL(sys_ioctl,sys_ioctl,compat_sys_ioctl_wrapper)
-SYSCALL(sys_fcntl,sys_fcntl,compat_sys_fcntl_wrapper) /* 55 */
+SYSCALL(sys_ioctl,sys_ioctl,compat_sys_ioctl)
+SYSCALL(sys_fcntl,sys_fcntl,compat_sys_fcntl) /* 55 */
NI_SYSCALL /* intel mpx syscall */
-SYSCALL(sys_setpgid,sys_setpgid,sys32_setpgid_wrapper)
+SYSCALL(sys_setpgid,sys_setpgid,compat_sys_setpgid)
NI_SYSCALL /* old ulimit syscall */
NI_SYSCALL /* old uname syscall */
-SYSCALL(sys_umask,sys_umask,sys32_umask_wrapper) /* 60 */
-SYSCALL(sys_chroot,sys_chroot,sys32_chroot_wrapper)
-SYSCALL(sys_ustat,sys_ustat,sys32_ustat_wrapper)
-SYSCALL(sys_dup2,sys_dup2,sys32_dup2_wrapper)
+SYSCALL(sys_umask,sys_umask,compat_sys_umask) /* 60 */
+SYSCALL(sys_chroot,sys_chroot,compat_sys_chroot)
+SYSCALL(sys_ustat,sys_ustat,compat_sys_ustat)
+SYSCALL(sys_dup2,sys_dup2,compat_sys_dup2)
SYSCALL(sys_getppid,sys_getppid,sys_getppid)
SYSCALL(sys_getpgrp,sys_getpgrp,sys_getpgrp) /* 65 */
SYSCALL(sys_setsid,sys_setsid,sys_setsid)
SYSCALL(sys_sigaction,sys_sigaction,compat_sys_sigaction)
NI_SYSCALL /* old sgetmask syscall*/
NI_SYSCALL /* old ssetmask syscall*/
-SYSCALL(sys_setreuid16,sys_ni_syscall,sys32_setreuid16_wrapper) /* old setreuid16 syscall */
-SYSCALL(sys_setregid16,sys_ni_syscall,sys32_setregid16_wrapper) /* old setregid16 syscall */
-SYSCALL(sys_sigsuspend,sys_sigsuspend,sys_sigsuspend_wrapper)
-SYSCALL(sys_sigpending,sys_sigpending,compat_sys_sigpending_wrapper)
-SYSCALL(sys_sethostname,sys_sethostname,sys32_sethostname_wrapper)
-SYSCALL(sys_setrlimit,sys_setrlimit,compat_sys_setrlimit_wrapper) /* 75 */
-SYSCALL(sys_old_getrlimit,sys_getrlimit,compat_sys_old_getrlimit_wrapper)
+SYSCALL(sys_setreuid16,sys_ni_syscall,compat_sys_s390_setreuid16) /* old setreuid16 syscall */
+SYSCALL(sys_setregid16,sys_ni_syscall,compat_sys_s390_setregid16) /* old setregid16 syscall */
+SYSCALL(sys_sigsuspend,sys_sigsuspend,compat_sys_sigsuspend)
+SYSCALL(sys_sigpending,sys_sigpending,compat_sys_sigpending)
+SYSCALL(sys_sethostname,sys_sethostname,compat_sys_sethostname)
+SYSCALL(sys_setrlimit,sys_setrlimit,compat_sys_setrlimit) /* 75 */
+SYSCALL(sys_old_getrlimit,sys_getrlimit,compat_sys_old_getrlimit)
SYSCALL(sys_getrusage,sys_getrusage,compat_sys_getrusage)
-SYSCALL(sys_gettimeofday,sys_gettimeofday,compat_sys_gettimeofday_wrapper)
-SYSCALL(sys_settimeofday,sys_settimeofday,compat_sys_settimeofday_wrapper)
-SYSCALL(sys_getgroups16,sys_ni_syscall,sys32_getgroups16_wrapper) /* 80 old getgroups16 syscall */
-SYSCALL(sys_setgroups16,sys_ni_syscall,sys32_setgroups16_wrapper) /* old setgroups16 syscall */
+SYSCALL(sys_gettimeofday,sys_gettimeofday,compat_sys_gettimeofday)
+SYSCALL(sys_settimeofday,sys_settimeofday,compat_sys_settimeofday)
+SYSCALL(sys_getgroups16,sys_ni_syscall,compat_sys_s390_getgroups16) /* 80 old getgroups16 syscall */
+SYSCALL(sys_setgroups16,sys_ni_syscall,compat_sys_s390_setgroups16) /* old setgroups16 syscall */
NI_SYSCALL /* old select syscall */
-SYSCALL(sys_symlink,sys_symlink,sys32_symlink_wrapper)
+SYSCALL(sys_symlink,sys_symlink,compat_sys_symlink)
NI_SYSCALL /* old lstat syscall */
-SYSCALL(sys_readlink,sys_readlink,sys32_readlink_wrapper) /* 85 */
-SYSCALL(sys_uselib,sys_uselib,sys32_uselib_wrapper)
-SYSCALL(sys_swapon,sys_swapon,sys32_swapon_wrapper)
-SYSCALL(sys_reboot,sys_reboot,sys32_reboot_wrapper)
-SYSCALL(sys_ni_syscall,sys_ni_syscall,old32_readdir_wrapper) /* old readdir syscall */
-SYSCALL(sys_old_mmap,sys_old_mmap,old32_mmap_wrapper) /* 90 */
-SYSCALL(sys_munmap,sys_munmap,sys32_munmap_wrapper)
+SYSCALL(sys_readlink,sys_readlink,compat_sys_readlink) /* 85 */
+SYSCALL(sys_uselib,sys_uselib,compat_sys_uselib)
+SYSCALL(sys_swapon,sys_swapon,compat_sys_swapon)
+SYSCALL(sys_reboot,sys_reboot,compat_sys_reboot)
+SYSCALL(sys_ni_syscall,sys_ni_syscall,compat_sys_old_readdir) /* old readdir syscall */
+SYSCALL(sys_old_mmap,sys_old_mmap,compat_sys_s390_old_mmap) /* 90 */
+SYSCALL(sys_munmap,sys_munmap,compat_sys_munmap)
SYSCALL(sys_truncate,sys_truncate,compat_sys_truncate)
SYSCALL(sys_ftruncate,sys_ftruncate,compat_sys_ftruncate)
-SYSCALL(sys_fchmod,sys_fchmod,sys32_fchmod_wrapper)
-SYSCALL(sys_fchown16,sys_ni_syscall,sys32_fchown16_wrapper) /* 95 old fchown16 syscall*/
-SYSCALL(sys_getpriority,sys_getpriority,sys32_getpriority_wrapper)
-SYSCALL(sys_setpriority,sys_setpriority,sys32_setpriority_wrapper)
+SYSCALL(sys_fchmod,sys_fchmod,compat_sys_fchmod)
+SYSCALL(sys_fchown16,sys_ni_syscall,compat_sys_s390_fchown16) /* 95 old fchown16 syscall*/
+SYSCALL(sys_getpriority,sys_getpriority,compat_sys_getpriority)
+SYSCALL(sys_setpriority,sys_setpriority,compat_sys_setpriority)
NI_SYSCALL /* old profil syscall */
-SYSCALL(sys_statfs,sys_statfs,compat_sys_statfs_wrapper)
-SYSCALL(sys_fstatfs,sys_fstatfs,compat_sys_fstatfs_wrapper) /* 100 */
+SYSCALL(sys_statfs,sys_statfs,compat_sys_statfs)
+SYSCALL(sys_fstatfs,sys_fstatfs,compat_sys_fstatfs) /* 100 */
NI_SYSCALL /* ioperm for i386 */
-SYSCALL(sys_socketcall,sys_socketcall,compat_sys_socketcall_wrapper)
-SYSCALL(sys_syslog,sys_syslog,sys32_syslog_wrapper)
+SYSCALL(sys_socketcall,sys_socketcall,compat_sys_socketcall)
+SYSCALL(sys_syslog,sys_syslog,compat_sys_syslog)
SYSCALL(sys_setitimer,sys_setitimer,compat_sys_setitimer)
SYSCALL(sys_getitimer,sys_getitimer,compat_sys_getitimer) /* 105 */
-SYSCALL(sys_newstat,sys_newstat,compat_sys_newstat_wrapper)
-SYSCALL(sys_newlstat,sys_newlstat,compat_sys_newlstat_wrapper)
-SYSCALL(sys_newfstat,sys_newfstat,compat_sys_newfstat_wrapper)
+SYSCALL(sys_newstat,sys_newstat,compat_sys_newstat)
+SYSCALL(sys_newlstat,sys_newlstat,compat_sys_newlstat)
+SYSCALL(sys_newfstat,sys_newfstat,compat_sys_newfstat)
NI_SYSCALL /* old uname syscall */
SYSCALL(sys_lookup_dcookie,sys_lookup_dcookie,compat_sys_lookup_dcookie) /* 110 */
SYSCALL(sys_vhangup,sys_vhangup,sys_vhangup)
NI_SYSCALL /* old "idle" system call */
NI_SYSCALL /* vm86old for i386 */
SYSCALL(sys_wait4,sys_wait4,compat_sys_wait4)
-SYSCALL(sys_swapoff,sys_swapoff,sys32_swapoff_wrapper) /* 115 */
-SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper)
+SYSCALL(sys_swapoff,sys_swapoff,compat_sys_swapoff) /* 115 */
+SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo)
SYSCALL(sys_s390_ipc,sys_s390_ipc,compat_sys_s390_ipc)
-SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper)
-SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn)
-SYSCALL(sys_clone,sys_clone,sys_clone_wrapper) /* 120 */
-SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper)
-SYSCALL(sys_newuname,sys_newuname,sys32_newuname_wrapper)
+SYSCALL(sys_fsync,sys_fsync,compat_sys_fsync)
+SYSCALL(sys_sigreturn,sys_sigreturn,compat_sys_sigreturn)
+SYSCALL(sys_clone,sys_clone,compat_sys_clone) /* 120 */
+SYSCALL(sys_setdomainname,sys_setdomainname,compat_sys_setdomainname)
+SYSCALL(sys_newuname,sys_newuname,compat_sys_newuname)
NI_SYSCALL /* modify_ldt for i386 */
-SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex_wrapper)
-SYSCALL(sys_mprotect,sys_mprotect,sys32_mprotect_wrapper) /* 125 */
+SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex)
+SYSCALL(sys_mprotect,sys_mprotect,compat_sys_mprotect) /* 125 */
SYSCALL(sys_sigprocmask,sys_sigprocmask,compat_sys_sigprocmask)
NI_SYSCALL /* old "create module" */
-SYSCALL(sys_init_module,sys_init_module,sys_init_module_wrapper)
-SYSCALL(sys_delete_module,sys_delete_module,sys_delete_module_wrapper)
+SYSCALL(sys_init_module,sys_init_module,compat_sys_init_module)
+SYSCALL(sys_delete_module,sys_delete_module,compat_sys_delete_module)
NI_SYSCALL /* 130: old get_kernel_syms */
-SYSCALL(sys_quotactl,sys_quotactl,sys32_quotactl_wrapper)
-SYSCALL(sys_getpgid,sys_getpgid,sys32_getpgid_wrapper)
-SYSCALL(sys_fchdir,sys_fchdir,sys32_fchdir_wrapper)
-SYSCALL(sys_bdflush,sys_bdflush,sys32_bdflush_wrapper)
-SYSCALL(sys_sysfs,sys_sysfs,sys32_sysfs_wrapper) /* 135 */
-SYSCALL(sys_personality,sys_s390_personality,sys32_personality_wrapper)
+SYSCALL(sys_quotactl,sys_quotactl,compat_sys_quotactl)
+SYSCALL(sys_getpgid,sys_getpgid,compat_sys_getpgid)
+SYSCALL(sys_fchdir,sys_fchdir,compat_sys_fchdir)
+SYSCALL(sys_bdflush,sys_bdflush,compat_sys_bdflush)
+SYSCALL(sys_sysfs,sys_sysfs,compat_sys_sysfs) /* 135 */
+SYSCALL(sys_personality,sys_s390_personality,compat_sys_s390_personality)
NI_SYSCALL /* for afs_syscall */
-SYSCALL(sys_setfsuid16,sys_ni_syscall,sys32_setfsuid16_wrapper) /* old setfsuid16 syscall */
-SYSCALL(sys_setfsgid16,sys_ni_syscall,sys32_setfsgid16_wrapper) /* old setfsgid16 syscall */
-SYSCALL(sys_llseek,sys_llseek,sys32_llseek_wrapper) /* 140 */
-SYSCALL(sys_getdents,sys_getdents,sys32_getdents_wrapper)
-SYSCALL(sys_select,sys_select,compat_sys_select_wrapper)
-SYSCALL(sys_flock,sys_flock,sys32_flock_wrapper)
-SYSCALL(sys_msync,sys_msync,sys32_msync_wrapper)
-SYSCALL(sys_readv,sys_readv,compat_sys_readv_wrapper) /* 145 */
-SYSCALL(sys_writev,sys_writev,compat_sys_writev_wrapper)
-SYSCALL(sys_getsid,sys_getsid,sys32_getsid_wrapper)
-SYSCALL(sys_fdatasync,sys_fdatasync,sys32_fdatasync_wrapper)
+SYSCALL(sys_setfsuid16,sys_ni_syscall,compat_sys_s390_setfsuid16) /* old setfsuid16 syscall */
+SYSCALL(sys_setfsgid16,sys_ni_syscall,compat_sys_s390_setfsgid16) /* old setfsgid16 syscall */
+SYSCALL(sys_llseek,sys_llseek,compat_sys_llseek) /* 140 */
+SYSCALL(sys_getdents,sys_getdents,compat_sys_getdents)
+SYSCALL(sys_select,sys_select,compat_sys_select)
+SYSCALL(sys_flock,sys_flock,compat_sys_flock)
+SYSCALL(sys_msync,sys_msync,compat_sys_msync)
+SYSCALL(sys_readv,sys_readv,compat_sys_readv) /* 145 */
+SYSCALL(sys_writev,sys_writev,compat_sys_writev)
+SYSCALL(sys_getsid,sys_getsid,compat_sys_getsid)
+SYSCALL(sys_fdatasync,sys_fdatasync,compat_sys_fdatasync)
SYSCALL(sys_sysctl,sys_sysctl,compat_sys_sysctl)
-SYSCALL(sys_mlock,sys_mlock,sys32_mlock_wrapper) /* 150 */
-SYSCALL(sys_munlock,sys_munlock,sys32_munlock_wrapper)
-SYSCALL(sys_mlockall,sys_mlockall,sys32_mlockall_wrapper)
+SYSCALL(sys_mlock,sys_mlock,compat_sys_mlock) /* 150 */
+SYSCALL(sys_munlock,sys_munlock,compat_sys_munlock)
+SYSCALL(sys_mlockall,sys_mlockall,compat_sys_mlockall)
SYSCALL(sys_munlockall,sys_munlockall,sys_munlockall)
-SYSCALL(sys_sched_setparam,sys_sched_setparam,sys32_sched_setparam_wrapper)
-SYSCALL(sys_sched_getparam,sys_sched_getparam,sys32_sched_getparam_wrapper) /* 155 */
-SYSCALL(sys_sched_setscheduler,sys_sched_setscheduler,sys32_sched_setscheduler_wrapper)
-SYSCALL(sys_sched_getscheduler,sys_sched_getscheduler,sys32_sched_getscheduler_wrapper)
+SYSCALL(sys_sched_setparam,sys_sched_setparam,compat_sys_sched_setparam)
+SYSCALL(sys_sched_getparam,sys_sched_getparam,compat_sys_sched_getparam) /* 155 */
+SYSCALL(sys_sched_setscheduler,sys_sched_setscheduler,compat_sys_sched_setscheduler)
+SYSCALL(sys_sched_getscheduler,sys_sched_getscheduler,compat_sys_sched_getscheduler)
SYSCALL(sys_sched_yield,sys_sched_yield,sys_sched_yield)
-SYSCALL(sys_sched_get_priority_max,sys_sched_get_priority_max,sys32_sched_get_priority_max_wrapper)
-SYSCALL(sys_sched_get_priority_min,sys_sched_get_priority_min,sys32_sched_get_priority_min_wrapper) /* 160 */
+SYSCALL(sys_sched_get_priority_max,sys_sched_get_priority_max,compat_sys_sched_get_priority_max)
+SYSCALL(sys_sched_get_priority_min,sys_sched_get_priority_min,compat_sys_sched_get_priority_min) /* 160 */
SYSCALL(sys_sched_rr_get_interval,sys_sched_rr_get_interval,compat_sys_sched_rr_get_interval)
-SYSCALL(sys_nanosleep,sys_nanosleep,compat_sys_nanosleep_wrapper)
-SYSCALL(sys_mremap,sys_mremap,sys32_mremap_wrapper)
-SYSCALL(sys_setresuid16,sys_ni_syscall,sys32_setresuid16_wrapper) /* old setresuid16 syscall */
-SYSCALL(sys_getresuid16,sys_ni_syscall,sys32_getresuid16_wrapper) /* 165 old getresuid16 syscall */
+SYSCALL(sys_nanosleep,sys_nanosleep,compat_sys_nanosleep)
+SYSCALL(sys_mremap,sys_mremap,compat_sys_mremap)
+SYSCALL(sys_setresuid16,sys_ni_syscall,compat_sys_s390_setresuid16) /* old setresuid16 syscall */
+SYSCALL(sys_getresuid16,sys_ni_syscall,compat_sys_s390_getresuid16) /* 165 old getresuid16 syscall */
NI_SYSCALL /* for vm86 */
NI_SYSCALL /* old sys_query_module */
-SYSCALL(sys_poll,sys_poll,sys32_poll_wrapper)
+SYSCALL(sys_poll,sys_poll,compat_sys_poll)
NI_SYSCALL /* old nfsservctl */
-SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper) /* 170 old setresgid16 syscall */
-SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper) /* old getresgid16 syscall */
-SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper)
-SYSCALL(sys_rt_sigreturn,sys_rt_sigreturn,sys32_rt_sigreturn)
+SYSCALL(sys_setresgid16,sys_ni_syscall,compat_sys_s390_setresgid16) /* 170 old setresgid16 syscall */
+SYSCALL(sys_getresgid16,sys_ni_syscall,compat_sys_s390_getresgid16) /* old getresgid16 syscall */
+SYSCALL(sys_prctl,sys_prctl,compat_sys_prctl)
+SYSCALL(sys_rt_sigreturn,sys_rt_sigreturn,compat_sys_rt_sigreturn)
SYSCALL(sys_rt_sigaction,sys_rt_sigaction,compat_sys_rt_sigaction)
SYSCALL(sys_rt_sigprocmask,sys_rt_sigprocmask,compat_sys_rt_sigprocmask) /* 175 */
SYSCALL(sys_rt_sigpending,sys_rt_sigpending,compat_sys_rt_sigpending)
SYSCALL(sys_rt_sigtimedwait,sys_rt_sigtimedwait,compat_sys_rt_sigtimedwait)
SYSCALL(sys_rt_sigqueueinfo,sys_rt_sigqueueinfo,compat_sys_rt_sigqueueinfo)
SYSCALL(sys_rt_sigsuspend,sys_rt_sigsuspend,compat_sys_rt_sigsuspend)
-SYSCALL(sys_pread64,sys_pread64,sys32_pread64_wrapper) /* 180 */
-SYSCALL(sys_pwrite64,sys_pwrite64,sys32_pwrite64_wrapper)
-SYSCALL(sys_chown16,sys_ni_syscall,sys32_chown16_wrapper) /* old chown16 syscall */
-SYSCALL(sys_getcwd,sys_getcwd,sys32_getcwd_wrapper)
-SYSCALL(sys_capget,sys_capget,sys32_capget_wrapper)
-SYSCALL(sys_capset,sys_capset,sys32_capset_wrapper) /* 185 */
+SYSCALL(sys_pread64,sys_pread64,compat_sys_s390_pread64) /* 180 */
+SYSCALL(sys_pwrite64,sys_pwrite64,compat_sys_s390_pwrite64)
+SYSCALL(sys_chown16,sys_ni_syscall,compat_sys_s390_chown16) /* old chown16 syscall */
+SYSCALL(sys_getcwd,sys_getcwd,compat_sys_getcwd)
+SYSCALL(sys_capget,sys_capget,compat_sys_capget)
+SYSCALL(sys_capset,sys_capset,compat_sys_capset) /* 185 */
SYSCALL(sys_sigaltstack,sys_sigaltstack,compat_sys_sigaltstack)
SYSCALL(sys_sendfile,sys_sendfile64,compat_sys_sendfile)
NI_SYSCALL /* streams1 */
NI_SYSCALL /* streams2 */
SYSCALL(sys_vfork,sys_vfork,sys_vfork) /* 190 */
-SYSCALL(sys_getrlimit,sys_getrlimit,compat_sys_getrlimit_wrapper)
-SYSCALL(sys_mmap2,sys_mmap2,sys32_mmap2_wrapper)
-SYSCALL(sys_truncate64,sys_ni_syscall,sys32_truncate64_wrapper)
-SYSCALL(sys_ftruncate64,sys_ni_syscall,sys32_ftruncate64_wrapper)
-SYSCALL(sys_stat64,sys_ni_syscall,sys32_stat64_wrapper) /* 195 */
-SYSCALL(sys_lstat64,sys_ni_syscall,sys32_lstat64_wrapper)
-SYSCALL(sys_fstat64,sys_ni_syscall,sys32_fstat64_wrapper)
-SYSCALL(sys_lchown,sys_lchown,sys32_lchown_wrapper)
+SYSCALL(sys_getrlimit,sys_getrlimit,compat_sys_getrlimit)
+SYSCALL(sys_mmap2,sys_mmap2,compat_sys_s390_mmap2)
+SYSCALL(sys_truncate64,sys_ni_syscall,compat_sys_s390_truncate64)
+SYSCALL(sys_ftruncate64,sys_ni_syscall,compat_sys_s390_ftruncate64)
+SYSCALL(sys_stat64,sys_ni_syscall,compat_sys_s390_stat64) /* 195 */
+SYSCALL(sys_lstat64,sys_ni_syscall,compat_sys_s390_lstat64)
+SYSCALL(sys_fstat64,sys_ni_syscall,compat_sys_s390_fstat64)
+SYSCALL(sys_lchown,sys_lchown,compat_sys_lchown)
SYSCALL(sys_getuid,sys_getuid,sys_getuid)
SYSCALL(sys_getgid,sys_getgid,sys_getgid) /* 200 */
SYSCALL(sys_geteuid,sys_geteuid,sys_geteuid)
SYSCALL(sys_getegid,sys_getegid,sys_getegid)
-SYSCALL(sys_setreuid,sys_setreuid,sys32_setreuid_wrapper)
-SYSCALL(sys_setregid,sys_setregid,sys32_setregid_wrapper)
-SYSCALL(sys_getgroups,sys_getgroups,sys32_getgroups_wrapper) /* 205 */
-SYSCALL(sys_setgroups,sys_setgroups,sys32_setgroups_wrapper)
-SYSCALL(sys_fchown,sys_fchown,sys32_fchown_wrapper)
-SYSCALL(sys_setresuid,sys_setresuid,sys32_setresuid_wrapper)
-SYSCALL(sys_getresuid,sys_getresuid,sys32_getresuid_wrapper)
-SYSCALL(sys_setresgid,sys_setresgid,sys32_setresgid_wrapper) /* 210 */
-SYSCALL(sys_getresgid,sys_getresgid,sys32_getresgid_wrapper)
-SYSCALL(sys_chown,sys_chown,sys32_chown_wrapper)
-SYSCALL(sys_setuid,sys_setuid,sys32_setuid_wrapper)
-SYSCALL(sys_setgid,sys_setgid,sys32_setgid_wrapper)
-SYSCALL(sys_setfsuid,sys_setfsuid,sys32_setfsuid_wrapper) /* 215 */
-SYSCALL(sys_setfsgid,sys_setfsgid,sys32_setfsgid_wrapper)
-SYSCALL(sys_pivot_root,sys_pivot_root,sys32_pivot_root_wrapper)
-SYSCALL(sys_mincore,sys_mincore,sys32_mincore_wrapper)
-SYSCALL(sys_madvise,sys_madvise,sys32_madvise_wrapper)
-SYSCALL(sys_getdents64,sys_getdents64,sys32_getdents64_wrapper) /* 220 */
-SYSCALL(sys_fcntl64,sys_ni_syscall,compat_sys_fcntl64_wrapper)
-SYSCALL(sys_readahead,sys_readahead,sys32_readahead_wrapper)
+SYSCALL(sys_setreuid,sys_setreuid,compat_sys_setreuid)
+SYSCALL(sys_setregid,sys_setregid,compat_sys_setregid)
+SYSCALL(sys_getgroups,sys_getgroups,compat_sys_getgroups) /* 205 */
+SYSCALL(sys_setgroups,sys_setgroups,compat_sys_setgroups)
+SYSCALL(sys_fchown,sys_fchown,compat_sys_fchown)
+SYSCALL(sys_setresuid,sys_setresuid,compat_sys_setresuid)
+SYSCALL(sys_getresuid,sys_getresuid,compat_sys_getresuid)
+SYSCALL(sys_setresgid,sys_setresgid,compat_sys_setresgid) /* 210 */
+SYSCALL(sys_getresgid,sys_getresgid,compat_sys_getresgid)
+SYSCALL(sys_chown,sys_chown,compat_sys_chown)
+SYSCALL(sys_setuid,sys_setuid,compat_sys_setuid)
+SYSCALL(sys_setgid,sys_setgid,compat_sys_setgid)
+SYSCALL(sys_setfsuid,sys_setfsuid,compat_sys_setfsuid) /* 215 */
+SYSCALL(sys_setfsgid,sys_setfsgid,compat_sys_setfsgid)
+SYSCALL(sys_pivot_root,sys_pivot_root,compat_sys_pivot_root)
+SYSCALL(sys_mincore,sys_mincore,compat_sys_mincore)
+SYSCALL(sys_madvise,sys_madvise,compat_sys_madvise)
+SYSCALL(sys_getdents64,sys_getdents64,compat_sys_getdents64) /* 220 */
+SYSCALL(sys_fcntl64,sys_ni_syscall,compat_sys_fcntl64)
+SYSCALL(sys_readahead,sys_readahead,compat_sys_s390_readahead)
SYSCALL(sys_sendfile64,sys_ni_syscall,compat_sys_sendfile64)
-SYSCALL(sys_setxattr,sys_setxattr,sys32_setxattr_wrapper)
-SYSCALL(sys_lsetxattr,sys_lsetxattr,sys32_lsetxattr_wrapper) /* 225 */
-SYSCALL(sys_fsetxattr,sys_fsetxattr,sys32_fsetxattr_wrapper)
-SYSCALL(sys_getxattr,sys_getxattr,sys32_getxattr_wrapper)
-SYSCALL(sys_lgetxattr,sys_lgetxattr,sys32_lgetxattr_wrapper)
-SYSCALL(sys_fgetxattr,sys_fgetxattr,sys32_fgetxattr_wrapper)
-SYSCALL(sys_listxattr,sys_listxattr,sys32_listxattr_wrapper) /* 230 */
-SYSCALL(sys_llistxattr,sys_llistxattr,sys32_llistxattr_wrapper)
-SYSCALL(sys_flistxattr,sys_flistxattr,sys32_flistxattr_wrapper)
-SYSCALL(sys_removexattr,sys_removexattr,sys32_removexattr_wrapper)
-SYSCALL(sys_lremovexattr,sys_lremovexattr,sys32_lremovexattr_wrapper)
-SYSCALL(sys_fremovexattr,sys_fremovexattr,sys32_fremovexattr_wrapper) /* 235 */
+SYSCALL(sys_setxattr,sys_setxattr,compat_sys_setxattr)
+SYSCALL(sys_lsetxattr,sys_lsetxattr,compat_sys_lsetxattr) /* 225 */
+SYSCALL(sys_fsetxattr,sys_fsetxattr,compat_sys_fsetxattr)
+SYSCALL(sys_getxattr,sys_getxattr,compat_sys_getxattr)
+SYSCALL(sys_lgetxattr,sys_lgetxattr,compat_sys_lgetxattr)
+SYSCALL(sys_fgetxattr,sys_fgetxattr,compat_sys_fgetxattr)
+SYSCALL(sys_listxattr,sys_listxattr,compat_sys_listxattr) /* 230 */
+SYSCALL(sys_llistxattr,sys_llistxattr,compat_sys_llistxattr)
+SYSCALL(sys_flistxattr,sys_flistxattr,compat_sys_flistxattr)
+SYSCALL(sys_removexattr,sys_removexattr,compat_sys_removexattr)
+SYSCALL(sys_lremovexattr,sys_lremovexattr,compat_sys_lremovexattr)
+SYSCALL(sys_fremovexattr,sys_fremovexattr,compat_sys_fremovexattr) /* 235 */
SYSCALL(sys_gettid,sys_gettid,sys_gettid)
-SYSCALL(sys_tkill,sys_tkill,sys_tkill_wrapper)
+SYSCALL(sys_tkill,sys_tkill,compat_sys_tkill)
SYSCALL(sys_futex,sys_futex,compat_sys_futex)
-SYSCALL(sys_sched_setaffinity,sys_sched_setaffinity,sys32_sched_setaffinity_wrapper)
-SYSCALL(sys_sched_getaffinity,sys_sched_getaffinity,sys32_sched_getaffinity_wrapper) /* 240 */
-SYSCALL(sys_tgkill,sys_tgkill,sys_tgkill_wrapper)
+SYSCALL(sys_sched_setaffinity,sys_sched_setaffinity,compat_sys_sched_setaffinity)
+SYSCALL(sys_sched_getaffinity,sys_sched_getaffinity,compat_sys_sched_getaffinity) /* 240 */
+SYSCALL(sys_tgkill,sys_tgkill,compat_sys_tgkill)
NI_SYSCALL /* reserved for TUX */
-SYSCALL(sys_io_setup,sys_io_setup,sys32_io_setup_wrapper)
-SYSCALL(sys_io_destroy,sys_io_destroy,sys32_io_destroy_wrapper)
-SYSCALL(sys_io_getevents,sys_io_getevents,sys32_io_getevents_wrapper) /* 245 */
-SYSCALL(sys_io_submit,sys_io_submit,sys32_io_submit_wrapper)
-SYSCALL(sys_io_cancel,sys_io_cancel,sys32_io_cancel_wrapper)
-SYSCALL(sys_exit_group,sys_exit_group,sys32_exit_group_wrapper)
-SYSCALL(sys_epoll_create,sys_epoll_create,sys_epoll_create_wrapper)
-SYSCALL(sys_epoll_ctl,sys_epoll_ctl,sys_epoll_ctl_wrapper) /* 250 */
-SYSCALL(sys_epoll_wait,sys_epoll_wait,sys_epoll_wait_wrapper)
-SYSCALL(sys_set_tid_address,sys_set_tid_address,sys32_set_tid_address_wrapper)
-SYSCALL(sys_s390_fadvise64,sys_fadvise64_64,sys32_fadvise64_wrapper)
-SYSCALL(sys_timer_create,sys_timer_create,sys32_timer_create_wrapper)
-SYSCALL(sys_timer_settime,sys_timer_settime,sys32_timer_settime_wrapper) /* 255 */
-SYSCALL(sys_timer_gettime,sys_timer_gettime,sys32_timer_gettime_wrapper)
-SYSCALL(sys_timer_getoverrun,sys_timer_getoverrun,sys32_timer_getoverrun_wrapper)
-SYSCALL(sys_timer_delete,sys_timer_delete,sys32_timer_delete_wrapper)
-SYSCALL(sys_clock_settime,sys_clock_settime,sys32_clock_settime_wrapper)
-SYSCALL(sys_clock_gettime,sys_clock_gettime,sys32_clock_gettime_wrapper) /* 260 */
-SYSCALL(sys_clock_getres,sys_clock_getres,sys32_clock_getres_wrapper)
-SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,sys32_clock_nanosleep_wrapper)
+SYSCALL(sys_io_setup,sys_io_setup,compat_sys_io_setup)
+SYSCALL(sys_io_destroy,sys_io_destroy,compat_sys_io_destroy)
+SYSCALL(sys_io_getevents,sys_io_getevents,compat_sys_io_getevents) /* 245 */
+SYSCALL(sys_io_submit,sys_io_submit,compat_sys_io_submit)
+SYSCALL(sys_io_cancel,sys_io_cancel,compat_sys_io_cancel)
+SYSCALL(sys_exit_group,sys_exit_group,compat_sys_exit_group)
+SYSCALL(sys_epoll_create,sys_epoll_create,compat_sys_epoll_create)
+SYSCALL(sys_epoll_ctl,sys_epoll_ctl,compat_sys_epoll_ctl) /* 250 */
+SYSCALL(sys_epoll_wait,sys_epoll_wait,compat_sys_epoll_wait)
+SYSCALL(sys_set_tid_address,sys_set_tid_address,compat_sys_set_tid_address)
+SYSCALL(sys_s390_fadvise64,sys_fadvise64_64,compat_sys_s390_fadvise64)
+SYSCALL(sys_timer_create,sys_timer_create,compat_sys_timer_create)
+SYSCALL(sys_timer_settime,sys_timer_settime,compat_sys_timer_settime) /* 255 */
+SYSCALL(sys_timer_gettime,sys_timer_gettime,compat_sys_timer_gettime)
+SYSCALL(sys_timer_getoverrun,sys_timer_getoverrun,compat_sys_timer_getoverrun)
+SYSCALL(sys_timer_delete,sys_timer_delete,compat_sys_timer_delete)
+SYSCALL(sys_clock_settime,sys_clock_settime,compat_sys_clock_settime)
+SYSCALL(sys_clock_gettime,sys_clock_gettime,compat_sys_clock_gettime) /* 260 */
+SYSCALL(sys_clock_getres,sys_clock_getres,compat_sys_clock_getres)
+SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,compat_sys_clock_nanosleep)
NI_SYSCALL /* reserved for vserver */
-SYSCALL(sys_s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper)
-SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64_wrapper)
-SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64_wrapper)
-SYSCALL(sys_remap_file_pages,sys_remap_file_pages,sys32_remap_file_pages_wrapper)
+SYSCALL(sys_s390_fadvise64_64,sys_ni_syscall,compat_sys_s390_fadvise64_64)
+SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64)
+SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64)
+SYSCALL(sys_remap_file_pages,sys_remap_file_pages,compat_sys_remap_file_pages)
NI_SYSCALL /* 268 sys_mbind */
NI_SYSCALL /* 269 sys_get_mempolicy */
NI_SYSCALL /* 270 sys_set_mempolicy */
-SYSCALL(sys_mq_open,sys_mq_open,compat_sys_mq_open_wrapper)
-SYSCALL(sys_mq_unlink,sys_mq_unlink,sys32_mq_unlink_wrapper)
-SYSCALL(sys_mq_timedsend,sys_mq_timedsend,compat_sys_mq_timedsend_wrapper)
-SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive_wrapper)
-SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify_wrapper) /* 275 */
-SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr_wrapper)
-SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load_wrapper)
-SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper)
-SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper)
-SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl_wrapper) /* 280 */
+SYSCALL(sys_mq_open,sys_mq_open,compat_sys_mq_open)
+SYSCALL(sys_mq_unlink,sys_mq_unlink,compat_sys_mq_unlink)
+SYSCALL(sys_mq_timedsend,sys_mq_timedsend,compat_sys_mq_timedsend)
+SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive)
+SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify) /* 275 */
+SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr)
+SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load)
+SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key)
+SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key)
+SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl) /* 280 */
SYSCALL(sys_waitid,sys_waitid,compat_sys_waitid)
-SYSCALL(sys_ioprio_set,sys_ioprio_set,sys_ioprio_set_wrapper)
-SYSCALL(sys_ioprio_get,sys_ioprio_get,sys_ioprio_get_wrapper)
+SYSCALL(sys_ioprio_set,sys_ioprio_set,compat_sys_ioprio_set)
+SYSCALL(sys_ioprio_get,sys_ioprio_get,compat_sys_ioprio_get)
SYSCALL(sys_inotify_init,sys_inotify_init,sys_inotify_init)
-SYSCALL(sys_inotify_add_watch,sys_inotify_add_watch,sys_inotify_add_watch_wrapper) /* 285 */
-SYSCALL(sys_inotify_rm_watch,sys_inotify_rm_watch,sys_inotify_rm_watch_wrapper)
+SYSCALL(sys_inotify_add_watch,sys_inotify_add_watch,compat_sys_inotify_add_watch) /* 285 */
+SYSCALL(sys_inotify_rm_watch,sys_inotify_rm_watch,compat_sys_inotify_rm_watch)
NI_SYSCALL /* 287 sys_migrate_pages */
SYSCALL(sys_openat,sys_openat,compat_sys_openat)
-SYSCALL(sys_mkdirat,sys_mkdirat,sys_mkdirat_wrapper)
-SYSCALL(sys_mknodat,sys_mknodat,sys_mknodat_wrapper) /* 290 */
-SYSCALL(sys_fchownat,sys_fchownat,sys_fchownat_wrapper)
-SYSCALL(sys_futimesat,sys_futimesat,compat_sys_futimesat_wrapper)
-SYSCALL(sys_fstatat64,sys_newfstatat,sys32_fstatat64_wrapper)
-SYSCALL(sys_unlinkat,sys_unlinkat,sys_unlinkat_wrapper)
-SYSCALL(sys_renameat,sys_renameat,sys_renameat_wrapper) /* 295 */
-SYSCALL(sys_linkat,sys_linkat,sys_linkat_wrapper)
-SYSCALL(sys_symlinkat,sys_symlinkat,sys_symlinkat_wrapper)
-SYSCALL(sys_readlinkat,sys_readlinkat,sys_readlinkat_wrapper)
-SYSCALL(sys_fchmodat,sys_fchmodat,sys_fchmodat_wrapper)
-SYSCALL(sys_faccessat,sys_faccessat,sys_faccessat_wrapper) /* 300 */
-SYSCALL(sys_pselect6,sys_pselect6,compat_sys_pselect6_wrapper)
-SYSCALL(sys_ppoll,sys_ppoll,compat_sys_ppoll_wrapper)
-SYSCALL(sys_unshare,sys_unshare,sys_unshare_wrapper)
+SYSCALL(sys_mkdirat,sys_mkdirat,compat_sys_mkdirat)
+SYSCALL(sys_mknodat,sys_mknodat,compat_sys_mknodat) /* 290 */
+SYSCALL(sys_fchownat,sys_fchownat,compat_sys_fchownat)
+SYSCALL(sys_futimesat,sys_futimesat,compat_sys_futimesat)
+SYSCALL(sys_fstatat64,sys_newfstatat,compat_sys_s390_fstatat64)
+SYSCALL(sys_unlinkat,sys_unlinkat,compat_sys_unlinkat)
+SYSCALL(sys_renameat,sys_renameat,compat_sys_renameat) /* 295 */
+SYSCALL(sys_linkat,sys_linkat,compat_sys_linkat)
+SYSCALL(sys_symlinkat,sys_symlinkat,compat_sys_symlinkat)
+SYSCALL(sys_readlinkat,sys_readlinkat,compat_sys_readlinkat)
+SYSCALL(sys_fchmodat,sys_fchmodat,compat_sys_fchmodat)
+SYSCALL(sys_faccessat,sys_faccessat,compat_sys_faccessat) /* 300 */
+SYSCALL(sys_pselect6,sys_pselect6,compat_sys_pselect6)
+SYSCALL(sys_ppoll,sys_ppoll,compat_sys_ppoll)
+SYSCALL(sys_unshare,sys_unshare,compat_sys_unshare)
SYSCALL(sys_set_robust_list,sys_set_robust_list,compat_sys_set_robust_list)
SYSCALL(sys_get_robust_list,sys_get_robust_list,compat_sys_get_robust_list)
-SYSCALL(sys_splice,sys_splice,sys_splice_wrapper)
-SYSCALL(sys_sync_file_range,sys_sync_file_range,sys_sync_file_range_wrapper)
-SYSCALL(sys_tee,sys_tee,sys_tee_wrapper)
+SYSCALL(sys_splice,sys_splice,compat_sys_splice)
+SYSCALL(sys_sync_file_range,sys_sync_file_range,compat_sys_s390_sync_file_range)
+SYSCALL(sys_tee,sys_tee,compat_sys_tee)
SYSCALL(sys_vmsplice,sys_vmsplice,compat_sys_vmsplice)
NI_SYSCALL /* 310 sys_move_pages */
-SYSCALL(sys_getcpu,sys_getcpu,sys_getcpu_wrapper)
+SYSCALL(sys_getcpu,sys_getcpu,compat_sys_getcpu)
SYSCALL(sys_epoll_pwait,sys_epoll_pwait,compat_sys_epoll_pwait)
-SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes_wrapper)
-SYSCALL(sys_s390_fallocate,sys_fallocate,sys_fallocate_wrapper)
-SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper) /* 315 */
+SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes)
+SYSCALL(sys_s390_fallocate,sys_fallocate,compat_sys_s390_fallocate)
+SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat) /* 315 */
SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd)
NI_SYSCALL /* 317 old sys_timer_fd */
-SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper)
-SYSCALL(sys_timerfd_create,sys_timerfd_create,sys_timerfd_create_wrapper)
+SYSCALL(sys_eventfd,sys_eventfd,compat_sys_eventfd)
+SYSCALL(sys_timerfd_create,sys_timerfd_create,compat_sys_timerfd_create)
SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime) /* 320 */
SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime)
SYSCALL(sys_signalfd4,sys_signalfd4,compat_sys_signalfd4)
-SYSCALL(sys_eventfd2,sys_eventfd2,sys_eventfd2_wrapper)
-SYSCALL(sys_inotify_init1,sys_inotify_init1,sys_inotify_init1_wrapper)
-SYSCALL(sys_pipe2,sys_pipe2,sys_pipe2_wrapper) /* 325 */
-SYSCALL(sys_dup3,sys_dup3,sys_dup3_wrapper)
-SYSCALL(sys_epoll_create1,sys_epoll_create1,sys_epoll_create1_wrapper)
+SYSCALL(sys_eventfd2,sys_eventfd2,compat_sys_eventfd2)
+SYSCALL(sys_inotify_init1,sys_inotify_init1,compat_sys_inotify_init1)
+SYSCALL(sys_pipe2,sys_pipe2,compat_sys_pipe2) /* 325 */
+SYSCALL(sys_dup3,sys_dup3,compat_sys_dup3)
+SYSCALL(sys_epoll_create1,sys_epoll_create1,compat_sys_epoll_create1)
SYSCALL(sys_preadv,sys_preadv,compat_sys_preadv)
SYSCALL(sys_pwritev,sys_pwritev,compat_sys_pwritev)
SYSCALL(sys_rt_tgsigqueueinfo,sys_rt_tgsigqueueinfo,compat_sys_rt_tgsigqueueinfo) /* 330 */
-SYSCALL(sys_perf_event_open,sys_perf_event_open,sys_perf_event_open_wrapper)
-SYSCALL(sys_fanotify_init,sys_fanotify_init,sys_fanotify_init_wrapper)
+SYSCALL(sys_perf_event_open,sys_perf_event_open,compat_sys_perf_event_open)
+SYSCALL(sys_fanotify_init,sys_fanotify_init,compat_sys_fanotify_init)
SYSCALL(sys_fanotify_mark,sys_fanotify_mark,compat_sys_fanotify_mark)
-SYSCALL(sys_prlimit64,sys_prlimit64,sys_prlimit64_wrapper)
-SYSCALL(sys_name_to_handle_at,sys_name_to_handle_at,sys_name_to_handle_at_wrapper) /* 335 */
+SYSCALL(sys_prlimit64,sys_prlimit64,compat_sys_prlimit64)
+SYSCALL(sys_name_to_handle_at,sys_name_to_handle_at,compat_sys_name_to_handle_at) /* 335 */
SYSCALL(sys_open_by_handle_at,sys_open_by_handle_at,compat_sys_open_by_handle_at)
-SYSCALL(sys_clock_adjtime,sys_clock_adjtime,compat_sys_clock_adjtime_wrapper)
-SYSCALL(sys_syncfs,sys_syncfs,sys_syncfs_wrapper)
-SYSCALL(sys_setns,sys_setns,sys_setns_wrapper)
-SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv_wrapper) /* 340 */
-SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev_wrapper)
-SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,sys_s390_runtime_instr_wrapper)
-SYSCALL(sys_kcmp,sys_kcmp,sys_kcmp_wrapper)
-SYSCALL(sys_finit_module,sys_finit_module,sys_finit_module_wrapper)
-SYSCALL(sys_sched_setattr,sys_sched_setattr,sys_sched_setattr_wrapper) /* 345 */
-SYSCALL(sys_sched_getattr,sys_sched_getattr,sys_sched_getattr_wrapper)
+SYSCALL(sys_clock_adjtime,sys_clock_adjtime,compat_sys_clock_adjtime)
+SYSCALL(sys_syncfs,sys_syncfs,compat_sys_syncfs)
+SYSCALL(sys_setns,sys_setns,compat_sys_setns)
+SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv) /* 340 */
+SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev)
+SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,compat_sys_s390_runtime_instr)
+SYSCALL(sys_kcmp,sys_kcmp,compat_sys_kcmp)
+SYSCALL(sys_finit_module,sys_finit_module,compat_sys_finit_module)
+SYSCALL(sys_sched_setattr,sys_sched_setattr,compat_sys_sched_setattr) /* 345 */
+SYSCALL(sys_sched_getattr,sys_sched_getattr,compat_sys_sched_getattr)
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
index 4b2e3e317004..6298fed11ced 100644
--- a/arch/s390/kernel/topology.c
+++ b/arch/s390/kernel/topology.c
@@ -451,7 +451,6 @@ static int __init topology_init(void)
}
set_topology_timer();
out:
- update_cpu_masks();
return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching);
}
device_initcall(topology_init);
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index 70b46eacf8e1..10d529ac9821 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -23,6 +23,10 @@ config KVM
select ANON_INODES
select HAVE_KVM_CPU_RELAX_INTERCEPT
select HAVE_KVM_EVENTFD
+ select KVM_ASYNC_PF
+ select KVM_ASYNC_PF_SYNC
+ select HAVE_KVM_IRQCHIP
+ select HAVE_KVM_IRQ_ROUTING
---help---
Support hosting paravirtualized guest machines using the SIE
virtualization capability on the mainframe. This should work
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile
index 40b4c6470f88..d3adb37e93a4 100644
--- a/arch/s390/kvm/Makefile
+++ b/arch/s390/kvm/Makefile
@@ -7,7 +7,7 @@
# as published by the Free Software Foundation.
KVM := ../../../virt/kvm
-common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o
+common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/async_pf.o $(KVM)/irqchip.o
ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c
index 8216c0e0b2e2..03a05ffb662f 100644
--- a/arch/s390/kvm/diag.c
+++ b/arch/s390/kvm/diag.c
@@ -13,10 +13,12 @@
#include <linux/kvm.h>
#include <linux/kvm_host.h>
+#include <asm/pgalloc.h>
#include <asm/virtio-ccw.h>
#include "kvm-s390.h"
#include "trace.h"
#include "trace-s390.h"
+#include "gaccess.h"
static int diag_release_pages(struct kvm_vcpu *vcpu)
{
@@ -46,6 +48,87 @@ static int diag_release_pages(struct kvm_vcpu *vcpu)
return 0;
}
+static int __diag_page_ref_service(struct kvm_vcpu *vcpu)
+{
+ struct prs_parm {
+ u16 code;
+ u16 subcode;
+ u16 parm_len;
+ u16 parm_version;
+ u64 token_addr;
+ u64 select_mask;
+ u64 compare_mask;
+ u64 zarch;
+ };
+ struct prs_parm parm;
+ int rc;
+ u16 rx = (vcpu->arch.sie_block->ipa & 0xf0) >> 4;
+ u16 ry = (vcpu->arch.sie_block->ipa & 0x0f);
+ unsigned long hva_token = KVM_HVA_ERR_BAD;
+
+ if (vcpu->run->s.regs.gprs[rx] & 7)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ if (copy_from_guest(vcpu, &parm, vcpu->run->s.regs.gprs[rx], sizeof(parm)))
+ return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ if (parm.parm_version != 2 || parm.parm_len < 5 || parm.code != 0x258)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ switch (parm.subcode) {
+ case 0: /* TOKEN */
+ if (vcpu->arch.pfault_token != KVM_S390_PFAULT_TOKEN_INVALID) {
+ /*
+ * If the pagefault handshake is already activated,
+ * the token must not be changed. We have to return
+ * decimal 8 instead, as mandated in SC24-6084.
+ */
+ vcpu->run->s.regs.gprs[ry] = 8;
+ return 0;
+ }
+
+ if ((parm.compare_mask & parm.select_mask) != parm.compare_mask ||
+ parm.token_addr & 7 || parm.zarch != 0x8000000000000000ULL)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ hva_token = gfn_to_hva(vcpu->kvm, gpa_to_gfn(parm.token_addr));
+ if (kvm_is_error_hva(hva_token))
+ return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+
+ vcpu->arch.pfault_token = parm.token_addr;
+ vcpu->arch.pfault_select = parm.select_mask;
+ vcpu->arch.pfault_compare = parm.compare_mask;
+ vcpu->run->s.regs.gprs[ry] = 0;
+ rc = 0;
+ break;
+ case 1: /*
+ * CANCEL
+ * Specification allows to let already pending tokens survive
+ * the cancel, therefore to reduce code complexity, we assume
+ * all outstanding tokens are already pending.
+ */
+ if (parm.token_addr || parm.select_mask ||
+ parm.compare_mask || parm.zarch)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ vcpu->run->s.regs.gprs[ry] = 0;
+ /*
+ * If the pfault handling was not established or is already
+ * canceled SC24-6084 requests to return decimal 4.
+ */
+ if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID)
+ vcpu->run->s.regs.gprs[ry] = 4;
+ else
+ vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
+
+ rc = 0;
+ break;
+ default:
+ rc = -EOPNOTSUPP;
+ break;
+ }
+
+ return rc;
+}
+
static int __diag_time_slice_end(struct kvm_vcpu *vcpu)
{
VCPU_EVENT(vcpu, 5, "%s", "diag time slice end");
@@ -86,9 +169,11 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
switch (subcode) {
case 3:
vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR;
+ page_table_reset_pgste(current->mm, 0, TASK_SIZE);
break;
case 4:
vcpu->run->s390_reset_flags = 0;
+ page_table_reset_pgste(current->mm, 0, TASK_SIZE);
break;
default:
return -EOPNOTSUPP;
@@ -150,6 +235,8 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu)
return __diag_time_slice_end(vcpu);
case 0x9c:
return __diag_time_slice_end_directed(vcpu);
+ case 0x258:
+ return __diag_page_ref_service(vcpu);
case 0x308:
return __diag_ipl_functions(vcpu);
case 0x500:
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 5f79d2d79ca7..200a8f9390b6 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -1,7 +1,7 @@
/*
* handling kvm guest interrupts
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008,2014
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
@@ -13,6 +13,7 @@
#include <linux/interrupt.h>
#include <linux/kvm_host.h>
#include <linux/hrtimer.h>
+#include <linux/mmu_context.h>
#include <linux/signal.h>
#include <linux/slab.h>
#include <asm/asm-offsets.h>
@@ -31,7 +32,7 @@ static int is_ioint(u64 type)
return ((type & 0xfffe0000u) != 0xfffe0000u);
}
-static int psw_extint_disabled(struct kvm_vcpu *vcpu)
+int psw_extint_disabled(struct kvm_vcpu *vcpu)
{
return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT);
}
@@ -78,11 +79,8 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
return 1;
return 0;
case KVM_S390_INT_SERVICE:
- if (psw_extint_disabled(vcpu))
- return 0;
- if (vcpu->arch.sie_block->gcr[0] & 0x200ul)
- return 1;
- return 0;
+ case KVM_S390_INT_PFAULT_INIT:
+ case KVM_S390_INT_PFAULT_DONE:
case KVM_S390_INT_VIRTIO:
if (psw_extint_disabled(vcpu))
return 0;
@@ -117,14 +115,12 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
static void __set_cpu_idle(struct kvm_vcpu *vcpu)
{
- BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1);
atomic_set_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
set_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask);
}
static void __unset_cpu_idle(struct kvm_vcpu *vcpu)
{
- BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1);
atomic_clear_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
clear_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask);
}
@@ -150,6 +146,8 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
case KVM_S390_INT_EXTERNAL_CALL:
case KVM_S390_INT_EMERGENCY:
case KVM_S390_INT_SERVICE:
+ case KVM_S390_INT_PFAULT_INIT:
+ case KVM_S390_INT_PFAULT_DONE:
case KVM_S390_INT_VIRTIO:
if (psw_extint_disabled(vcpu))
__set_cpuflag(vcpu, CPUSTAT_EXT_INT);
@@ -223,6 +221,30 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
rc |= put_guest(vcpu, inti->ext.ext_params,
(u32 __user *)__LC_EXT_PARAMS);
break;
+ case KVM_S390_INT_PFAULT_INIT:
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, 0,
+ inti->ext.ext_params2);
+ rc = put_guest(vcpu, 0x2603, (u16 __user *) __LC_EXT_INT_CODE);
+ rc |= put_guest(vcpu, 0x0600, (u16 __user *) __LC_EXT_CPU_ADDR);
+ rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
+ __LC_EXT_NEW_PSW, sizeof(psw_t));
+ rc |= put_guest(vcpu, inti->ext.ext_params2,
+ (u64 __user *) __LC_EXT_PARAMS2);
+ break;
+ case KVM_S390_INT_PFAULT_DONE:
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, 0,
+ inti->ext.ext_params2);
+ rc = put_guest(vcpu, 0x2603, (u16 __user *) __LC_EXT_INT_CODE);
+ rc |= put_guest(vcpu, 0x0680, (u16 __user *) __LC_EXT_CPU_ADDR);
+ rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
+ __LC_EXT_NEW_PSW, sizeof(psw_t));
+ rc |= put_guest(vcpu, inti->ext.ext_params2,
+ (u64 __user *) __LC_EXT_PARAMS2);
+ break;
case KVM_S390_INT_VIRTIO:
VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx",
inti->ext.ext_params, inti->ext.ext_params2);
@@ -357,7 +379,7 @@ static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu)
return 1;
}
-static int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
+int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int;
@@ -482,11 +504,26 @@ enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer)
struct kvm_vcpu *vcpu;
vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer);
+ vcpu->preempted = true;
tasklet_schedule(&vcpu->arch.tasklet);
return HRTIMER_NORESTART;
}
+void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ struct kvm_s390_interrupt_info *n, *inti = NULL;
+
+ spin_lock_bh(&li->lock);
+ list_for_each_entry_safe(inti, n, &li->list, list) {
+ list_del(&inti->list);
+ kfree(inti);
+ }
+ atomic_set(&li->active, 0);
+ spin_unlock_bh(&li->lock);
+}
+
void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
@@ -528,6 +565,7 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
list_for_each_entry_safe(inti, n, &fi->list, list) {
if (__interrupt_is_deliverable(vcpu, inti)) {
list_del(&inti->list);
+ fi->irq_count--;
deliver = 1;
break;
}
@@ -583,6 +621,7 @@ void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu)
if ((inti->type == KVM_S390_MCHK) &&
__interrupt_is_deliverable(vcpu, inti)) {
list_del(&inti->list);
+ fi->irq_count--;
deliver = 1;
break;
}
@@ -650,8 +689,10 @@ struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
inti = iter;
break;
}
- if (inti)
+ if (inti) {
list_del_init(&inti->list);
+ fi->irq_count--;
+ }
if (list_empty(&fi->list))
atomic_set(&fi->active, 0);
spin_unlock(&fi->lock);
@@ -659,53 +700,101 @@ struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
return inti;
}
-int kvm_s390_inject_vm(struct kvm *kvm,
- struct kvm_s390_interrupt *s390int)
+static int __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
{
struct kvm_s390_local_interrupt *li;
struct kvm_s390_float_interrupt *fi;
- struct kvm_s390_interrupt_info *inti, *iter;
+ struct kvm_s390_interrupt_info *iter;
+ struct kvm_vcpu *dst_vcpu = NULL;
int sigcpu;
+ int rc = 0;
+
+ mutex_lock(&kvm->lock);
+ fi = &kvm->arch.float_int;
+ spin_lock(&fi->lock);
+ if (fi->irq_count >= KVM_S390_MAX_FLOAT_IRQS) {
+ rc = -EINVAL;
+ goto unlock_fi;
+ }
+ fi->irq_count++;
+ if (!is_ioint(inti->type)) {
+ list_add_tail(&inti->list, &fi->list);
+ } else {
+ u64 isc_bits = int_word_to_isc_bits(inti->io.io_int_word);
+
+ /* Keep I/O interrupts sorted in isc order. */
+ list_for_each_entry(iter, &fi->list, list) {
+ if (!is_ioint(iter->type))
+ continue;
+ if (int_word_to_isc_bits(iter->io.io_int_word)
+ <= isc_bits)
+ continue;
+ break;
+ }
+ list_add_tail(&inti->list, &iter->list);
+ }
+ atomic_set(&fi->active, 1);
+ sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS);
+ if (sigcpu == KVM_MAX_VCPUS) {
+ do {
+ sigcpu = fi->next_rr_cpu++;
+ if (sigcpu == KVM_MAX_VCPUS)
+ sigcpu = fi->next_rr_cpu = 0;
+ } while (kvm_get_vcpu(kvm, sigcpu) == NULL);
+ }
+ dst_vcpu = kvm_get_vcpu(kvm, sigcpu);
+ li = &dst_vcpu->arch.local_int;
+ spin_lock_bh(&li->lock);
+ atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+ if (waitqueue_active(li->wq))
+ wake_up_interruptible(li->wq);
+ kvm_get_vcpu(kvm, sigcpu)->preempted = true;
+ spin_unlock_bh(&li->lock);
+unlock_fi:
+ spin_unlock(&fi->lock);
+ mutex_unlock(&kvm->lock);
+ return rc;
+}
+
+int kvm_s390_inject_vm(struct kvm *kvm,
+ struct kvm_s390_interrupt *s390int)
+{
+ struct kvm_s390_interrupt_info *inti;
inti = kzalloc(sizeof(*inti), GFP_KERNEL);
if (!inti)
return -ENOMEM;
- switch (s390int->type) {
+ inti->type = s390int->type;
+ switch (inti->type) {
case KVM_S390_INT_VIRTIO:
VM_EVENT(kvm, 5, "inject: virtio parm:%x,parm64:%llx",
s390int->parm, s390int->parm64);
- inti->type = s390int->type;
inti->ext.ext_params = s390int->parm;
inti->ext.ext_params2 = s390int->parm64;
break;
case KVM_S390_INT_SERVICE:
VM_EVENT(kvm, 5, "inject: sclp parm:%x", s390int->parm);
- inti->type = s390int->type;
inti->ext.ext_params = s390int->parm;
break;
- case KVM_S390_PROGRAM_INT:
- case KVM_S390_SIGP_STOP:
- case KVM_S390_INT_EXTERNAL_CALL:
- case KVM_S390_INT_EMERGENCY:
- kfree(inti);
- return -EINVAL;
+ case KVM_S390_INT_PFAULT_DONE:
+ inti->type = s390int->type;
+ inti->ext.ext_params2 = s390int->parm64;
+ break;
case KVM_S390_MCHK:
VM_EVENT(kvm, 5, "inject: machine check parm64:%llx",
s390int->parm64);
- inti->type = s390int->type;
inti->mchk.cr14 = s390int->parm; /* upper bits are not used */
inti->mchk.mcic = s390int->parm64;
break;
case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
- if (s390int->type & IOINT_AI_MASK)
+ if (inti->type & IOINT_AI_MASK)
VM_EVENT(kvm, 5, "%s", "inject: I/O (AI)");
else
VM_EVENT(kvm, 5, "inject: I/O css %x ss %x schid %04x",
s390int->type & IOINT_CSSID_MASK,
s390int->type & IOINT_SSID_MASK,
s390int->type & IOINT_SCHID_MASK);
- inti->type = s390int->type;
inti->io.subchannel_id = s390int->parm >> 16;
inti->io.subchannel_nr = s390int->parm & 0x0000ffffu;
inti->io.io_int_parm = s390int->parm64 >> 32;
@@ -718,43 +807,7 @@ int kvm_s390_inject_vm(struct kvm *kvm,
trace_kvm_s390_inject_vm(s390int->type, s390int->parm, s390int->parm64,
2);
- mutex_lock(&kvm->lock);
- fi = &kvm->arch.float_int;
- spin_lock(&fi->lock);
- if (!is_ioint(inti->type))
- list_add_tail(&inti->list, &fi->list);
- else {
- u64 isc_bits = int_word_to_isc_bits(inti->io.io_int_word);
-
- /* Keep I/O interrupts sorted in isc order. */
- list_for_each_entry(iter, &fi->list, list) {
- if (!is_ioint(iter->type))
- continue;
- if (int_word_to_isc_bits(iter->io.io_int_word)
- <= isc_bits)
- continue;
- break;
- }
- list_add_tail(&inti->list, &iter->list);
- }
- atomic_set(&fi->active, 1);
- sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS);
- if (sigcpu == KVM_MAX_VCPUS) {
- do {
- sigcpu = fi->next_rr_cpu++;
- if (sigcpu == KVM_MAX_VCPUS)
- sigcpu = fi->next_rr_cpu = 0;
- } while (fi->local_int[sigcpu] == NULL);
- }
- li = fi->local_int[sigcpu];
- spin_lock_bh(&li->lock);
- atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
- if (waitqueue_active(li->wq))
- wake_up_interruptible(li->wq);
- spin_unlock_bh(&li->lock);
- spin_unlock(&fi->lock);
- mutex_unlock(&kvm->lock);
- return 0;
+ return __inject_vm(kvm, inti);
}
int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
@@ -814,6 +867,10 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
inti->type = s390int->type;
inti->mchk.mcic = s390int->parm64;
break;
+ case KVM_S390_INT_PFAULT_INIT:
+ inti->type = s390int->type;
+ inti->ext.ext_params2 = s390int->parm64;
+ break;
case KVM_S390_INT_VIRTIO:
case KVM_S390_INT_SERVICE:
case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
@@ -837,7 +894,528 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
if (waitqueue_active(&vcpu->wq))
wake_up_interruptible(&vcpu->wq);
+ vcpu->preempted = true;
spin_unlock_bh(&li->lock);
mutex_unlock(&vcpu->kvm->lock);
return 0;
}
+
+static void clear_floating_interrupts(struct kvm *kvm)
+{
+ struct kvm_s390_float_interrupt *fi;
+ struct kvm_s390_interrupt_info *n, *inti = NULL;
+
+ mutex_lock(&kvm->lock);
+ fi = &kvm->arch.float_int;
+ spin_lock(&fi->lock);
+ list_for_each_entry_safe(inti, n, &fi->list, list) {
+ list_del(&inti->list);
+ kfree(inti);
+ }
+ fi->irq_count = 0;
+ atomic_set(&fi->active, 0);
+ spin_unlock(&fi->lock);
+ mutex_unlock(&kvm->lock);
+}
+
+static inline int copy_irq_to_user(struct kvm_s390_interrupt_info *inti,
+ u8 *addr)
+{
+ struct kvm_s390_irq __user *uptr = (struct kvm_s390_irq __user *) addr;
+ struct kvm_s390_irq irq = {0};
+
+ irq.type = inti->type;
+ switch (inti->type) {
+ case KVM_S390_INT_PFAULT_INIT:
+ case KVM_S390_INT_PFAULT_DONE:
+ case KVM_S390_INT_VIRTIO:
+ case KVM_S390_INT_SERVICE:
+ irq.u.ext = inti->ext;
+ break;
+ case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
+ irq.u.io = inti->io;
+ break;
+ case KVM_S390_MCHK:
+ irq.u.mchk = inti->mchk;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (copy_to_user(uptr, &irq, sizeof(irq)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int get_all_floating_irqs(struct kvm *kvm, __u8 *buf, __u64 len)
+{
+ struct kvm_s390_interrupt_info *inti;
+ struct kvm_s390_float_interrupt *fi;
+ int ret = 0;
+ int n = 0;
+
+ mutex_lock(&kvm->lock);
+ fi = &kvm->arch.float_int;
+ spin_lock(&fi->lock);
+
+ list_for_each_entry(inti, &fi->list, list) {
+ if (len < sizeof(struct kvm_s390_irq)) {
+ /* signal userspace to try again */
+ ret = -ENOMEM;
+ break;
+ }
+ ret = copy_irq_to_user(inti, buf);
+ if (ret)
+ break;
+ buf += sizeof(struct kvm_s390_irq);
+ len -= sizeof(struct kvm_s390_irq);
+ n++;
+ }
+
+ spin_unlock(&fi->lock);
+ mutex_unlock(&kvm->lock);
+
+ return ret < 0 ? ret : n;
+}
+
+static int flic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+ int r;
+
+ switch (attr->group) {
+ case KVM_DEV_FLIC_GET_ALL_IRQS:
+ r = get_all_floating_irqs(dev->kvm, (u8 *) attr->addr,
+ attr->attr);
+ break;
+ default:
+ r = -EINVAL;
+ }
+
+ return r;
+}
+
+static inline int copy_irq_from_user(struct kvm_s390_interrupt_info *inti,
+ u64 addr)
+{
+ struct kvm_s390_irq __user *uptr = (struct kvm_s390_irq __user *) addr;
+ void *target = NULL;
+ void __user *source;
+ u64 size;
+
+ if (get_user(inti->type, (u64 __user *)addr))
+ return -EFAULT;
+
+ switch (inti->type) {
+ case KVM_S390_INT_PFAULT_INIT:
+ case KVM_S390_INT_PFAULT_DONE:
+ case KVM_S390_INT_VIRTIO:
+ case KVM_S390_INT_SERVICE:
+ target = (void *) &inti->ext;
+ source = &uptr->u.ext;
+ size = sizeof(inti->ext);
+ break;
+ case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
+ target = (void *) &inti->io;
+ source = &uptr->u.io;
+ size = sizeof(inti->io);
+ break;
+ case KVM_S390_MCHK:
+ target = (void *) &inti->mchk;
+ source = &uptr->u.mchk;
+ size = sizeof(inti->mchk);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (copy_from_user(target, source, size))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int enqueue_floating_irq(struct kvm_device *dev,
+ struct kvm_device_attr *attr)
+{
+ struct kvm_s390_interrupt_info *inti = NULL;
+ int r = 0;
+ int len = attr->attr;
+
+ if (len % sizeof(struct kvm_s390_irq) != 0)
+ return -EINVAL;
+ else if (len > KVM_S390_FLIC_MAX_BUFFER)
+ return -EINVAL;
+
+ while (len >= sizeof(struct kvm_s390_irq)) {
+ inti = kzalloc(sizeof(*inti), GFP_KERNEL);
+ if (!inti)
+ return -ENOMEM;
+
+ r = copy_irq_from_user(inti, attr->addr);
+ if (r) {
+ kfree(inti);
+ return r;
+ }
+ r = __inject_vm(dev->kvm, inti);
+ if (r) {
+ kfree(inti);
+ return r;
+ }
+ len -= sizeof(struct kvm_s390_irq);
+ attr->addr += sizeof(struct kvm_s390_irq);
+ }
+
+ return r;
+}
+
+static struct s390_io_adapter *get_io_adapter(struct kvm *kvm, unsigned int id)
+{
+ if (id >= MAX_S390_IO_ADAPTERS)
+ return NULL;
+ return kvm->arch.adapters[id];
+}
+
+static int register_io_adapter(struct kvm_device *dev,
+ struct kvm_device_attr *attr)
+{
+ struct s390_io_adapter *adapter;
+ struct kvm_s390_io_adapter adapter_info;
+
+ if (copy_from_user(&adapter_info,
+ (void __user *)attr->addr, sizeof(adapter_info)))
+ return -EFAULT;
+
+ if ((adapter_info.id >= MAX_S390_IO_ADAPTERS) ||
+ (dev->kvm->arch.adapters[adapter_info.id] != NULL))
+ return -EINVAL;
+
+ adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ if (!adapter)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&adapter->maps);
+ init_rwsem(&adapter->maps_lock);
+ atomic_set(&adapter->nr_maps, 0);
+ adapter->id = adapter_info.id;
+ adapter->isc = adapter_info.isc;
+ adapter->maskable = adapter_info.maskable;
+ adapter->masked = false;
+ adapter->swap = adapter_info.swap;
+ dev->kvm->arch.adapters[adapter->id] = adapter;
+
+ return 0;
+}
+
+int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked)
+{
+ int ret;
+ struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
+
+ if (!adapter || !adapter->maskable)
+ return -EINVAL;
+ ret = adapter->masked;
+ adapter->masked = masked;
+ return ret;
+}
+
+static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr)
+{
+ struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
+ struct s390_map_info *map;
+ int ret;
+
+ if (!adapter || !addr)
+ return -EINVAL;
+
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (!map) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ INIT_LIST_HEAD(&map->list);
+ map->guest_addr = addr;
+ map->addr = gmap_translate(addr, kvm->arch.gmap);
+ if (map->addr == -EFAULT) {
+ ret = -EFAULT;
+ goto out;
+ }
+ ret = get_user_pages_fast(map->addr, 1, 1, &map->page);
+ if (ret < 0)
+ goto out;
+ BUG_ON(ret != 1);
+ down_write(&adapter->maps_lock);
+ if (atomic_inc_return(&adapter->nr_maps) < MAX_S390_ADAPTER_MAPS) {
+ list_add_tail(&map->list, &adapter->maps);
+ ret = 0;
+ } else {
+ put_page(map->page);
+ ret = -EINVAL;
+ }
+ up_write(&adapter->maps_lock);
+out:
+ if (ret)
+ kfree(map);
+ return ret;
+}
+
+static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
+{
+ struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
+ struct s390_map_info *map, *tmp;
+ int found = 0;
+
+ if (!adapter || !addr)
+ return -EINVAL;
+
+ down_write(&adapter->maps_lock);
+ list_for_each_entry_safe(map, tmp, &adapter->maps, list) {
+ if (map->guest_addr == addr) {
+ found = 1;
+ atomic_dec(&adapter->nr_maps);
+ list_del(&map->list);
+ put_page(map->page);
+ kfree(map);
+ break;
+ }
+ }
+ up_write(&adapter->maps_lock);
+
+ return found ? 0 : -EINVAL;
+}
+
+void kvm_s390_destroy_adapters(struct kvm *kvm)
+{
+ int i;
+ struct s390_map_info *map, *tmp;
+
+ for (i = 0; i < MAX_S390_IO_ADAPTERS; i++) {
+ if (!kvm->arch.adapters[i])
+ continue;
+ list_for_each_entry_safe(map, tmp,
+ &kvm->arch.adapters[i]->maps, list) {
+ list_del(&map->list);
+ put_page(map->page);
+ kfree(map);
+ }
+ kfree(kvm->arch.adapters[i]);
+ }
+}
+
+static int modify_io_adapter(struct kvm_device *dev,
+ struct kvm_device_attr *attr)
+{
+ struct kvm_s390_io_adapter_req req;
+ struct s390_io_adapter *adapter;
+ int ret;
+
+ if (copy_from_user(&req, (void __user *)attr->addr, sizeof(req)))
+ return -EFAULT;
+
+ adapter = get_io_adapter(dev->kvm, req.id);
+ if (!adapter)
+ return -EINVAL;
+ switch (req.type) {
+ case KVM_S390_IO_ADAPTER_MASK:
+ ret = kvm_s390_mask_adapter(dev->kvm, req.id, req.mask);
+ if (ret > 0)
+ ret = 0;
+ break;
+ case KVM_S390_IO_ADAPTER_MAP:
+ ret = kvm_s390_adapter_map(dev->kvm, req.id, req.addr);
+ break;
+ case KVM_S390_IO_ADAPTER_UNMAP:
+ ret = kvm_s390_adapter_unmap(dev->kvm, req.id, req.addr);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+ int r = 0;
+ unsigned int i;
+ struct kvm_vcpu *vcpu;
+
+ switch (attr->group) {
+ case KVM_DEV_FLIC_ENQUEUE:
+ r = enqueue_floating_irq(dev, attr);
+ break;
+ case KVM_DEV_FLIC_CLEAR_IRQS:
+ r = 0;
+ clear_floating_interrupts(dev->kvm);
+ break;
+ case KVM_DEV_FLIC_APF_ENABLE:
+ dev->kvm->arch.gmap->pfault_enabled = 1;
+ break;
+ case KVM_DEV_FLIC_APF_DISABLE_WAIT:
+ dev->kvm->arch.gmap->pfault_enabled = 0;
+ /*
+ * Make sure no async faults are in transition when
+ * clearing the queues. So we don't need to worry
+ * about late coming workers.
+ */
+ synchronize_srcu(&dev->kvm->srcu);
+ kvm_for_each_vcpu(i, vcpu, dev->kvm)
+ kvm_clear_async_pf_completion_queue(vcpu);
+ break;
+ case KVM_DEV_FLIC_ADAPTER_REGISTER:
+ r = register_io_adapter(dev, attr);
+ break;
+ case KVM_DEV_FLIC_ADAPTER_MODIFY:
+ r = modify_io_adapter(dev, attr);
+ break;
+ default:
+ r = -EINVAL;
+ }
+
+ return r;
+}
+
+static int flic_create(struct kvm_device *dev, u32 type)
+{
+ if (!dev)
+ return -EINVAL;
+ if (dev->kvm->arch.flic)
+ return -EINVAL;
+ dev->kvm->arch.flic = dev;
+ return 0;
+}
+
+static void flic_destroy(struct kvm_device *dev)
+{
+ dev->kvm->arch.flic = NULL;
+ kfree(dev);
+}
+
+/* s390 floating irq controller (flic) */
+struct kvm_device_ops kvm_flic_ops = {
+ .name = "kvm-flic",
+ .get_attr = flic_get_attr,
+ .set_attr = flic_set_attr,
+ .create = flic_create,
+ .destroy = flic_destroy,
+};
+
+static unsigned long get_ind_bit(__u64 addr, unsigned long bit_nr, bool swap)
+{
+ unsigned long bit;
+
+ bit = bit_nr + (addr % PAGE_SIZE) * 8;
+
+ return swap ? (bit ^ (BITS_PER_LONG - 1)) : bit;
+}
+
+static struct s390_map_info *get_map_info(struct s390_io_adapter *adapter,
+ u64 addr)
+{
+ struct s390_map_info *map;
+
+ if (!adapter)
+ return NULL;
+
+ list_for_each_entry(map, &adapter->maps, list) {
+ if (map->guest_addr == addr)
+ return map;
+ }
+ return NULL;
+}
+
+static int adapter_indicators_set(struct kvm *kvm,
+ struct s390_io_adapter *adapter,
+ struct kvm_s390_adapter_int *adapter_int)
+{
+ unsigned long bit;
+ int summary_set, idx;
+ struct s390_map_info *info;
+ void *map;
+
+ info = get_map_info(adapter, adapter_int->ind_addr);
+ if (!info)
+ return -1;
+ map = page_address(info->page);
+ bit = get_ind_bit(info->addr, adapter_int->ind_offset, adapter->swap);
+ set_bit(bit, map);
+ idx = srcu_read_lock(&kvm->srcu);
+ mark_page_dirty(kvm, info->guest_addr >> PAGE_SHIFT);
+ set_page_dirty_lock(info->page);
+ info = get_map_info(adapter, adapter_int->summary_addr);
+ if (!info) {
+ srcu_read_unlock(&kvm->srcu, idx);
+ return -1;
+ }
+ map = page_address(info->page);
+ bit = get_ind_bit(info->addr, adapter_int->summary_offset,
+ adapter->swap);
+ summary_set = test_and_set_bit(bit, map);
+ mark_page_dirty(kvm, info->guest_addr >> PAGE_SHIFT);
+ set_page_dirty_lock(info->page);
+ srcu_read_unlock(&kvm->srcu, idx);
+ return summary_set ? 0 : 1;
+}
+
+/*
+ * < 0 - not injected due to error
+ * = 0 - coalesced, summary indicator already active
+ * > 0 - injected interrupt
+ */
+static int set_adapter_int(struct kvm_kernel_irq_routing_entry *e,
+ struct kvm *kvm, int irq_source_id, int level,
+ bool line_status)
+{
+ int ret;
+ struct s390_io_adapter *adapter;
+
+ /* We're only interested in the 0->1 transition. */
+ if (!level)
+ return 0;
+ adapter = get_io_adapter(kvm, e->adapter.adapter_id);
+ if (!adapter)
+ return -1;
+ down_read(&adapter->maps_lock);
+ ret = adapter_indicators_set(kvm, adapter, &e->adapter);
+ up_read(&adapter->maps_lock);
+ if ((ret > 0) && !adapter->masked) {
+ struct kvm_s390_interrupt s390int = {
+ .type = KVM_S390_INT_IO(1, 0, 0, 0),
+ .parm = 0,
+ .parm64 = (adapter->isc << 27) | 0x80000000,
+ };
+ ret = kvm_s390_inject_vm(kvm, &s390int);
+ if (ret == 0)
+ ret = 1;
+ }
+ return ret;
+}
+
+int kvm_set_routing_entry(struct kvm_irq_routing_table *rt,
+ struct kvm_kernel_irq_routing_entry *e,
+ const struct kvm_irq_routing_entry *ue)
+{
+ int ret;
+
+ switch (ue->type) {
+ case KVM_IRQ_ROUTING_S390_ADAPTER:
+ e->set = set_adapter_int;
+ e->adapter.summary_addr = ue->u.adapter.summary_addr;
+ e->adapter.ind_addr = ue->u.adapter.ind_addr;
+ e->adapter.summary_offset = ue->u.adapter.summary_offset;
+ e->adapter.ind_offset = ue->u.adapter.ind_offset;
+ e->adapter.adapter_id = ue->u.adapter.adapter_id;
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,
+ int irq_source_id, int level, bool line_status)
+{
+ return -EINVAL;
+}
diff --git a/arch/s390/kvm/irq.h b/arch/s390/kvm/irq.h
new file mode 100644
index 000000000000..d98e4159643d
--- /dev/null
+++ b/arch/s390/kvm/irq.h
@@ -0,0 +1,22 @@
+/*
+ * s390 irqchip routines
+ *
+ * Copyright IBM Corp. 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ */
+#ifndef __KVM_IRQ_H
+#define __KVM_IRQ_H
+
+#include <linux/kvm_host.h>
+
+static inline int irqchip_in_kernel(struct kvm *kvm)
+{
+ return 1;
+}
+
+#endif
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index e0676f390d57..b3ecb8f5b6ce 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -68,6 +68,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
{ "instruction_storage_key", VCPU_STAT(instruction_storage_key) },
{ "instruction_stsch", VCPU_STAT(instruction_stsch) },
{ "instruction_chsc", VCPU_STAT(instruction_chsc) },
+ { "instruction_essa", VCPU_STAT(instruction_essa) },
{ "instruction_stsi", VCPU_STAT(instruction_stsi) },
{ "instruction_stfl", VCPU_STAT(instruction_stfl) },
{ "instruction_tprot", VCPU_STAT(instruction_tprot) },
@@ -152,11 +153,14 @@ int kvm_dev_ioctl_check_extension(long ext)
#ifdef CONFIG_KVM_S390_UCONTROL
case KVM_CAP_S390_UCONTROL:
#endif
+ case KVM_CAP_ASYNC_PF:
case KVM_CAP_SYNC_REGS:
case KVM_CAP_ONE_REG:
case KVM_CAP_ENABLE_CAP:
case KVM_CAP_S390_CSS_SUPPORT:
case KVM_CAP_IOEVENTFD:
+ case KVM_CAP_DEVICE_CTRL:
+ case KVM_CAP_ENABLE_CAP_VM:
r = 1;
break;
case KVM_CAP_NR_VCPUS:
@@ -185,6 +189,25 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
return 0;
}
+static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
+{
+ int r;
+
+ if (cap->flags)
+ return -EINVAL;
+
+ switch (cap->cap) {
+ case KVM_CAP_S390_IRQCHIP:
+ kvm->arch.use_irqchip = 1;
+ r = 0;
+ break;
+ default:
+ r = -EINVAL;
+ break;
+ }
+ return r;
+}
+
long kvm_arch_vm_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -202,6 +225,26 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = kvm_s390_inject_vm(kvm, &s390int);
break;
}
+ case KVM_ENABLE_CAP: {
+ struct kvm_enable_cap cap;
+ r = -EFAULT;
+ if (copy_from_user(&cap, argp, sizeof(cap)))
+ break;
+ r = kvm_vm_ioctl_enable_cap(kvm, &cap);
+ break;
+ }
+ case KVM_CREATE_IRQCHIP: {
+ struct kvm_irq_routing_entry routing;
+
+ r = -EINVAL;
+ if (kvm->arch.use_irqchip) {
+ /* Set up dummy routing. */
+ memset(&routing, 0, sizeof(routing));
+ kvm_set_irq_routing(kvm, &routing, 0, 0);
+ r = 0;
+ }
+ break;
+ }
default:
r = -ENOTTY;
}
@@ -213,6 +256,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
{
int rc;
char debug_name[16];
+ static unsigned long sca_offset;
rc = -EINVAL;
#ifdef CONFIG_KVM_S390_UCONTROL
@@ -234,6 +278,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL);
if (!kvm->arch.sca)
goto out_err;
+ spin_lock(&kvm_lock);
+ sca_offset = (sca_offset + 16) & 0x7f0;
+ kvm->arch.sca = (struct sca_block *) ((char *) kvm->arch.sca + sca_offset);
+ spin_unlock(&kvm_lock);
sprintf(debug_name, "kvm-%u", current->pid);
@@ -254,9 +302,11 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
if (!kvm->arch.gmap)
goto out_nogmap;
kvm->arch.gmap->private = kvm;
+ kvm->arch.gmap->pfault_enabled = 0;
}
kvm->arch.css_support = 0;
+ kvm->arch.use_irqchip = 0;
return 0;
out_nogmap:
@@ -271,6 +321,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
{
VCPU_EVENT(vcpu, 3, "%s", "free cpu");
trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id);
+ kvm_clear_async_pf_completion_queue(vcpu);
if (!kvm_is_ucontrol(vcpu->kvm)) {
clear_bit(63 - vcpu->vcpu_id,
(unsigned long *) &vcpu->kvm->arch.sca->mcn);
@@ -283,7 +334,11 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
if (kvm_is_ucontrol(vcpu->kvm))
gmap_free(vcpu->arch.gmap);
+ if (vcpu->arch.sie_block->cbrlo)
+ __free_page(__pfn_to_page(
+ vcpu->arch.sie_block->cbrlo >> PAGE_SHIFT));
free_page((unsigned long)(vcpu->arch.sie_block));
+
kvm_vcpu_uninit(vcpu);
kmem_cache_free(kvm_vcpu_cache, vcpu);
}
@@ -315,11 +370,14 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
debug_unregister(kvm->arch.dbf);
if (!kvm_is_ucontrol(kvm))
gmap_free(kvm->arch.gmap);
+ kvm_s390_destroy_adapters(kvm);
}
/* Section: vcpu related */
int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
{
+ vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
+ kvm_clear_async_pf_completion_queue(vcpu);
if (kvm_is_ucontrol(vcpu->kvm)) {
vcpu->arch.gmap = gmap_alloc(current->mm);
if (!vcpu->arch.gmap)
@@ -380,7 +438,11 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
vcpu->arch.guest_fpregs.fpc = 0;
asm volatile("lfpc %0" : : "Q" (vcpu->arch.guest_fpregs.fpc));
vcpu->arch.sie_block->gbea = 1;
+ vcpu->arch.sie_block->pp = 0;
+ vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
+ kvm_clear_async_pf_completion_queue(vcpu);
atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
+ kvm_s390_clear_local_irqs(vcpu);
}
int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
@@ -390,6 +452,8 @@ int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
+ struct page *cbrl;
+
atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH |
CPUSTAT_SM |
CPUSTAT_STOPPED |
@@ -401,6 +465,14 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
vcpu->arch.sie_block->ecb2 = 8;
vcpu->arch.sie_block->eca = 0xC1002001U;
vcpu->arch.sie_block->fac = (int) (long) vfacilities;
+ if (kvm_enabled_cmma()) {
+ cbrl = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (cbrl) {
+ vcpu->arch.sie_block->ecb2 |= 0x80;
+ vcpu->arch.sie_block->ecb2 &= ~0x08;
+ vcpu->arch.sie_block->cbrlo = page_to_phys(cbrl);
+ }
+ }
hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet,
(unsigned long) vcpu);
@@ -451,11 +523,8 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
spin_lock_init(&vcpu->arch.local_int.lock);
INIT_LIST_HEAD(&vcpu->arch.local_int.list);
vcpu->arch.local_int.float_int = &kvm->arch.float_int;
- spin_lock(&kvm->arch.float_int.lock);
- kvm->arch.float_int.local_int[id] = &vcpu->arch.local_int;
vcpu->arch.local_int.wq = &vcpu->wq;
vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags;
- spin_unlock(&kvm->arch.float_int.lock);
rc = kvm_vcpu_init(vcpu, kvm, id);
if (rc)
@@ -475,9 +544,7 @@ out:
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
{
- /* kvm common code refers to this, but never calls it */
- BUG();
- return 0;
+ return kvm_cpu_has_interrupt(vcpu);
}
void s390_vcpu_block(struct kvm_vcpu *vcpu)
@@ -553,6 +620,26 @@ static int kvm_arch_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu,
r = put_user(vcpu->arch.sie_block->ckc,
(u64 __user *)reg->addr);
break;
+ case KVM_REG_S390_PFTOKEN:
+ r = put_user(vcpu->arch.pfault_token,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_PFCOMPARE:
+ r = put_user(vcpu->arch.pfault_compare,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_PFSELECT:
+ r = put_user(vcpu->arch.pfault_select,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_PP:
+ r = put_user(vcpu->arch.sie_block->pp,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_GBEA:
+ r = put_user(vcpu->arch.sie_block->gbea,
+ (u64 __user *)reg->addr);
+ break;
default:
break;
}
@@ -582,6 +669,26 @@ static int kvm_arch_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu,
r = get_user(vcpu->arch.sie_block->ckc,
(u64 __user *)reg->addr);
break;
+ case KVM_REG_S390_PFTOKEN:
+ r = get_user(vcpu->arch.pfault_token,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_PFCOMPARE:
+ r = get_user(vcpu->arch.pfault_compare,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_PFSELECT:
+ r = get_user(vcpu->arch.pfault_select,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_PP:
+ r = get_user(vcpu->arch.sie_block->pp,
+ (u64 __user *)reg->addr);
+ break;
+ case KVM_REG_S390_GBEA:
+ r = get_user(vcpu->arch.sie_block->gbea,
+ (u64 __user *)reg->addr);
+ break;
default:
break;
}
@@ -700,10 +807,100 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
return 0;
}
+static long kvm_arch_fault_in_sync(struct kvm_vcpu *vcpu)
+{
+ long rc;
+ hva_t fault = gmap_fault(current->thread.gmap_addr, vcpu->arch.gmap);
+ struct mm_struct *mm = current->mm;
+ down_read(&mm->mmap_sem);
+ rc = get_user_pages(current, mm, fault, 1, 1, 0, NULL, NULL);
+ up_read(&mm->mmap_sem);
+ return rc;
+}
+
+static void __kvm_inject_pfault_token(struct kvm_vcpu *vcpu, bool start_token,
+ unsigned long token)
+{
+ struct kvm_s390_interrupt inti;
+ inti.parm64 = token;
+
+ if (start_token) {
+ inti.type = KVM_S390_INT_PFAULT_INIT;
+ WARN_ON_ONCE(kvm_s390_inject_vcpu(vcpu, &inti));
+ } else {
+ inti.type = KVM_S390_INT_PFAULT_DONE;
+ WARN_ON_ONCE(kvm_s390_inject_vm(vcpu->kvm, &inti));
+ }
+}
+
+void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+ trace_kvm_s390_pfault_init(vcpu, work->arch.pfault_token);
+ __kvm_inject_pfault_token(vcpu, true, work->arch.pfault_token);
+}
+
+void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+ trace_kvm_s390_pfault_done(vcpu, work->arch.pfault_token);
+ __kvm_inject_pfault_token(vcpu, false, work->arch.pfault_token);
+}
+
+void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+ /* s390 will always inject the page directly */
+}
+
+bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu)
+{
+ /*
+ * s390 will always inject the page directly,
+ * but we still want check_async_completion to cleanup
+ */
+ return true;
+}
+
+static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu)
+{
+ hva_t hva;
+ struct kvm_arch_async_pf arch;
+ int rc;
+
+ if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID)
+ return 0;
+ if ((vcpu->arch.sie_block->gpsw.mask & vcpu->arch.pfault_select) !=
+ vcpu->arch.pfault_compare)
+ return 0;
+ if (psw_extint_disabled(vcpu))
+ return 0;
+ if (kvm_cpu_has_interrupt(vcpu))
+ return 0;
+ if (!(vcpu->arch.sie_block->gcr[0] & 0x200ul))
+ return 0;
+ if (!vcpu->arch.gmap->pfault_enabled)
+ return 0;
+
+ hva = gmap_fault(current->thread.gmap_addr, vcpu->arch.gmap);
+ if (copy_from_guest(vcpu, &arch.pfault_token, vcpu->arch.pfault_token, 8))
+ return 0;
+
+ rc = kvm_setup_async_pf(vcpu, current->thread.gmap_addr, hva, &arch);
+ return rc;
+}
+
static int vcpu_pre_run(struct kvm_vcpu *vcpu)
{
int rc, cpuflags;
+ /*
+ * On s390 notifications for arriving pages will be delivered directly
+ * to the guest but the house keeping for completed pfaults is
+ * handled outside the worker.
+ */
+ kvm_check_async_pf_completion(vcpu);
+
memcpy(&vcpu->arch.sie_block->gg14, &vcpu->run->s.regs.gprs[14], 16);
if (need_resched())
@@ -729,7 +926,7 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu)
static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
{
- int rc;
+ int rc = -1;
VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
vcpu->arch.sie_block->icptcode);
@@ -743,7 +940,16 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
current->thread.gmap_addr;
vcpu->run->s390_ucontrol.pgm_code = 0x10;
rc = -EREMOTE;
- } else {
+
+ } else if (current->thread.gmap_pfault) {
+ trace_kvm_s390_major_guest_pfault(vcpu);
+ current->thread.gmap_pfault = 0;
+ if (kvm_arch_setup_async_pf(vcpu) ||
+ (kvm_arch_fault_in_sync(vcpu) >= 0))
+ rc = 0;
+ }
+
+ if (rc == -1) {
VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
trace_kvm_s390_sie_fault(vcpu);
rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
@@ -753,7 +959,8 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
if (rc == 0) {
if (kvm_is_ucontrol(vcpu->kvm))
- rc = -EOPNOTSUPP;
+ /* Don't exit for host interrupts. */
+ rc = vcpu->arch.sie_block->icptcode ? -EOPNOTSUPP : 0;
else
rc = kvm_handle_sie_intercept(vcpu);
}
@@ -761,6 +968,16 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
return rc;
}
+bool kvm_enabled_cmma(void)
+{
+ if (!MACHINE_IS_LPAR)
+ return false;
+ /* only enable for z10 and later */
+ if (!MACHINE_HAS_EDAT1)
+ return false;
+ return true;
+}
+
static int __vcpu_run(struct kvm_vcpu *vcpu)
{
int rc, exit_reason;
@@ -806,8 +1023,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
- BUG_ON(vcpu->kvm->arch.float_int.local_int[vcpu->vcpu_id] == NULL);
-
switch (kvm_run->exit_reason) {
case KVM_EXIT_S390_SIEIC:
case KVM_EXIT_UNKNOWN:
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index f9559b0bd620..3c1e2274d9ea 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -129,6 +129,7 @@ enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
void kvm_s390_tasklet(unsigned long parm);
void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu);
void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu);
+void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu);
int __must_check kvm_s390_inject_vm(struct kvm *kvm,
struct kvm_s390_interrupt *s390int);
int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
@@ -136,6 +137,7 @@ int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
u64 cr6, u64 schid);
+int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked);
/* implemented in priv.c */
int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
@@ -156,7 +158,14 @@ void s390_vcpu_block(struct kvm_vcpu *vcpu);
void s390_vcpu_unblock(struct kvm_vcpu *vcpu);
void exit_sie(struct kvm_vcpu *vcpu);
void exit_sie_sync(struct kvm_vcpu *vcpu);
+/* are we going to support cmma? */
+bool kvm_enabled_cmma(void);
/* implemented in diag.c */
int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
+/* implemented in interrupt.c */
+int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
+int psw_extint_disabled(struct kvm_vcpu *vcpu);
+void kvm_s390_destroy_adapters(struct kvm *kvm);
+
#endif
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 75beea632a10..476e9e218f43 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -396,15 +396,10 @@ static int handle_stidp(struct kvm_vcpu *vcpu)
static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
int cpus = 0;
int n;
- spin_lock(&fi->lock);
- for (n = 0; n < KVM_MAX_VCPUS; n++)
- if (fi->local_int[n])
- cpus++;
- spin_unlock(&fi->lock);
+ cpus = atomic_read(&vcpu->kvm->online_vcpus);
/* deal with other level 3 hypervisors */
if (stsi(mem, 3, 2, 2))
@@ -636,8 +631,49 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
return 0;
}
+static int handle_essa(struct kvm_vcpu *vcpu)
+{
+ /* entries expected to be 1FF */
+ int entries = (vcpu->arch.sie_block->cbrlo & ~PAGE_MASK) >> 3;
+ unsigned long *cbrlo, cbrle;
+ struct gmap *gmap;
+ int i;
+
+ VCPU_EVENT(vcpu, 5, "cmma release %d pages", entries);
+ gmap = vcpu->arch.gmap;
+ vcpu->stat.instruction_essa++;
+ if (!kvm_enabled_cmma() || !vcpu->arch.sie_block->cbrlo)
+ return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
+
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+ if (((vcpu->arch.sie_block->ipb & 0xf0000000) >> 28) > 6)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ /* Rewind PSW to repeat the ESSA instruction */
+ vcpu->arch.sie_block->gpsw.addr =
+ __rewind_psw(vcpu->arch.sie_block->gpsw, 4);
+ vcpu->arch.sie_block->cbrlo &= PAGE_MASK; /* reset nceo */
+ cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo);
+ down_read(&gmap->mm->mmap_sem);
+ for (i = 0; i < entries; ++i) {
+ cbrle = cbrlo[i];
+ if (unlikely(cbrle & ~PAGE_MASK || cbrle < 2 * PAGE_SIZE))
+ /* invalid entry */
+ break;
+ /* try to free backing */
+ __gmap_zap(cbrle, gmap);
+ }
+ up_read(&gmap->mm->mmap_sem);
+ if (i < entries)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ return 0;
+}
+
static const intercept_handler_t b9_handlers[256] = {
[0x8d] = handle_epsw,
+ [0xab] = handle_essa,
[0xaf] = handle_pfmf,
};
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index 87c2b3a3bd3e..26caeb530a78 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -23,29 +23,30 @@
static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
u64 *reg)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
+ struct kvm_s390_local_interrupt *li;
+ struct kvm_vcpu *dst_vcpu = NULL;
+ int cpuflags;
int rc;
if (cpu_addr >= KVM_MAX_VCPUS)
return SIGP_CC_NOT_OPERATIONAL;
- spin_lock(&fi->lock);
- if (fi->local_int[cpu_addr] == NULL)
- rc = SIGP_CC_NOT_OPERATIONAL;
- else if (!(atomic_read(fi->local_int[cpu_addr]->cpuflags)
- & (CPUSTAT_ECALL_PEND | CPUSTAT_STOPPED)))
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
+ return SIGP_CC_NOT_OPERATIONAL;
+ li = &dst_vcpu->arch.local_int;
+
+ cpuflags = atomic_read(li->cpuflags);
+ if (!(cpuflags & (CPUSTAT_ECALL_PEND | CPUSTAT_STOPPED)))
rc = SIGP_CC_ORDER_CODE_ACCEPTED;
else {
*reg &= 0xffffffff00000000UL;
- if (atomic_read(fi->local_int[cpu_addr]->cpuflags)
- & CPUSTAT_ECALL_PEND)
+ if (cpuflags & CPUSTAT_ECALL_PEND)
*reg |= SIGP_STATUS_EXT_CALL_PENDING;
- if (atomic_read(fi->local_int[cpu_addr]->cpuflags)
- & CPUSTAT_STOPPED)
+ if (cpuflags & CPUSTAT_STOPPED)
*reg |= SIGP_STATUS_STOPPED;
rc = SIGP_CC_STATUS_STORED;
}
- spin_unlock(&fi->lock);
VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", cpu_addr, rc);
return rc;
@@ -53,12 +54,13 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
struct kvm_s390_local_interrupt *li;
struct kvm_s390_interrupt_info *inti;
- int rc;
+ struct kvm_vcpu *dst_vcpu = NULL;
- if (cpu_addr >= KVM_MAX_VCPUS)
+ if (cpu_addr < KVM_MAX_VCPUS)
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
return SIGP_CC_NOT_OPERATIONAL;
inti = kzalloc(sizeof(*inti), GFP_KERNEL);
@@ -68,13 +70,7 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
inti->type = KVM_S390_INT_EMERGENCY;
inti->emerg.code = vcpu->vcpu_id;
- spin_lock(&fi->lock);
- li = fi->local_int[cpu_addr];
- if (li == NULL) {
- rc = SIGP_CC_NOT_OPERATIONAL;
- kfree(inti);
- goto unlock;
- }
+ li = &dst_vcpu->arch.local_int;
spin_lock_bh(&li->lock);
list_add_tail(&inti->list, &li->list);
atomic_set(&li->active, 1);
@@ -82,11 +78,9 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
if (waitqueue_active(li->wq))
wake_up_interruptible(li->wq);
spin_unlock_bh(&li->lock);
- rc = SIGP_CC_ORDER_CODE_ACCEPTED;
VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr);
-unlock:
- spin_unlock(&fi->lock);
- return rc;
+
+ return SIGP_CC_ORDER_CODE_ACCEPTED;
}
static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr,
@@ -122,12 +116,13 @@ static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr,
static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
struct kvm_s390_local_interrupt *li;
struct kvm_s390_interrupt_info *inti;
- int rc;
+ struct kvm_vcpu *dst_vcpu = NULL;
- if (cpu_addr >= KVM_MAX_VCPUS)
+ if (cpu_addr < KVM_MAX_VCPUS)
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
return SIGP_CC_NOT_OPERATIONAL;
inti = kzalloc(sizeof(*inti), GFP_KERNEL);
@@ -137,13 +132,7 @@ static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
inti->type = KVM_S390_INT_EXTERNAL_CALL;
inti->extcall.code = vcpu->vcpu_id;
- spin_lock(&fi->lock);
- li = fi->local_int[cpu_addr];
- if (li == NULL) {
- rc = SIGP_CC_NOT_OPERATIONAL;
- kfree(inti);
- goto unlock;
- }
+ li = &dst_vcpu->arch.local_int;
spin_lock_bh(&li->lock);
list_add_tail(&inti->list, &li->list);
atomic_set(&li->active, 1);
@@ -151,11 +140,9 @@ static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
if (waitqueue_active(li->wq))
wake_up_interruptible(li->wq);
spin_unlock_bh(&li->lock);
- rc = SIGP_CC_ORDER_CODE_ACCEPTED;
VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", cpu_addr);
-unlock:
- spin_unlock(&fi->lock);
- return rc;
+
+ return SIGP_CC_ORDER_CODE_ACCEPTED;
}
static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
@@ -189,31 +176,26 @@ out:
static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int action)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
struct kvm_s390_local_interrupt *li;
+ struct kvm_vcpu *dst_vcpu = NULL;
int rc;
if (cpu_addr >= KVM_MAX_VCPUS)
return SIGP_CC_NOT_OPERATIONAL;
- spin_lock(&fi->lock);
- li = fi->local_int[cpu_addr];
- if (li == NULL) {
- rc = SIGP_CC_NOT_OPERATIONAL;
- goto unlock;
- }
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
+ return SIGP_CC_NOT_OPERATIONAL;
+ li = &dst_vcpu->arch.local_int;
rc = __inject_sigp_stop(li, action);
-unlock:
- spin_unlock(&fi->lock);
VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr);
if ((action & ACTION_STORE_ON_STOP) != 0 && rc == -ESHUTDOWN) {
/* If the CPU has already been stopped, we still have
* to save the status when doing stop-and-store. This
* has to be done after unlocking all spinlocks. */
- struct kvm_vcpu *dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
rc = kvm_s390_store_status_unloaded(dst_vcpu,
KVM_S390_STORE_STATUS_NOADDR);
}
@@ -224,6 +206,8 @@ unlock:
static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
{
int rc;
+ unsigned int i;
+ struct kvm_vcpu *v;
switch (parameter & 0xff) {
case 0:
@@ -231,6 +215,11 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
break;
case 1:
case 2:
+ kvm_for_each_vcpu(i, v, vcpu->kvm) {
+ v->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
+ kvm_clear_async_pf_completion_queue(v);
+ }
+
rc = SIGP_CC_ORDER_CODE_ACCEPTED;
break;
default:
@@ -242,12 +231,18 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
u64 *reg)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
- struct kvm_s390_local_interrupt *li = NULL;
+ struct kvm_s390_local_interrupt *li;
+ struct kvm_vcpu *dst_vcpu = NULL;
struct kvm_s390_interrupt_info *inti;
int rc;
u8 tmp;
+ if (cpu_addr < KVM_MAX_VCPUS)
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
+ return SIGP_CC_NOT_OPERATIONAL;
+ li = &dst_vcpu->arch.local_int;
+
/* make sure that the new value is valid memory */
address = address & 0x7fffe000u;
if (copy_from_guest_absolute(vcpu, &tmp, address, 1) ||
@@ -261,18 +256,6 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
if (!inti)
return SIGP_CC_BUSY;
- spin_lock(&fi->lock);
- if (cpu_addr < KVM_MAX_VCPUS)
- li = fi->local_int[cpu_addr];
-
- if (li == NULL) {
- *reg &= 0xffffffff00000000UL;
- *reg |= SIGP_STATUS_INCORRECT_STATE;
- rc = SIGP_CC_STATUS_STORED;
- kfree(inti);
- goto out_fi;
- }
-
spin_lock_bh(&li->lock);
/* cpu must be in stopped state */
if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
@@ -295,8 +278,6 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address);
out_li:
spin_unlock_bh(&li->lock);
-out_fi:
- spin_unlock(&fi->lock);
return rc;
}
@@ -334,28 +315,26 @@ static int __sigp_store_status_at_addr(struct kvm_vcpu *vcpu, u16 cpu_id,
static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
u64 *reg)
{
+ struct kvm_s390_local_interrupt *li;
+ struct kvm_vcpu *dst_vcpu = NULL;
int rc;
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
if (cpu_addr >= KVM_MAX_VCPUS)
return SIGP_CC_NOT_OPERATIONAL;
- spin_lock(&fi->lock);
- if (fi->local_int[cpu_addr] == NULL)
- rc = SIGP_CC_NOT_OPERATIONAL;
- else {
- if (atomic_read(fi->local_int[cpu_addr]->cpuflags)
- & CPUSTAT_RUNNING) {
- /* running */
- rc = SIGP_CC_ORDER_CODE_ACCEPTED;
- } else {
- /* not running */
- *reg &= 0xffffffff00000000UL;
- *reg |= SIGP_STATUS_NOT_RUNNING;
- rc = SIGP_CC_STATUS_STORED;
- }
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
+ return SIGP_CC_NOT_OPERATIONAL;
+ li = &dst_vcpu->arch.local_int;
+ if (atomic_read(li->cpuflags) & CPUSTAT_RUNNING) {
+ /* running */
+ rc = SIGP_CC_ORDER_CODE_ACCEPTED;
+ } else {
+ /* not running */
+ *reg &= 0xffffffff00000000UL;
+ *reg |= SIGP_STATUS_NOT_RUNNING;
+ rc = SIGP_CC_STATUS_STORED;
}
- spin_unlock(&fi->lock);
VCPU_EVENT(vcpu, 4, "sensed running status of cpu %x rc %x", cpu_addr,
rc);
@@ -366,26 +345,22 @@ static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
/* Test whether the destination CPU is available and not busy */
static int sigp_check_callable(struct kvm_vcpu *vcpu, u16 cpu_addr)
{
- struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
struct kvm_s390_local_interrupt *li;
int rc = SIGP_CC_ORDER_CODE_ACCEPTED;
+ struct kvm_vcpu *dst_vcpu = NULL;
if (cpu_addr >= KVM_MAX_VCPUS)
return SIGP_CC_NOT_OPERATIONAL;
- spin_lock(&fi->lock);
- li = fi->local_int[cpu_addr];
- if (li == NULL) {
- rc = SIGP_CC_NOT_OPERATIONAL;
- goto out;
- }
-
+ dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ if (!dst_vcpu)
+ return SIGP_CC_NOT_OPERATIONAL;
+ li = &dst_vcpu->arch.local_int;
spin_lock_bh(&li->lock);
if (li->action_bits & ACTION_STOP_ON_STOP)
rc = SIGP_CC_BUSY;
spin_unlock_bh(&li->lock);
-out:
- spin_unlock(&fi->lock);
+
return rc;
}
diff --git a/arch/s390/kvm/trace.h b/arch/s390/kvm/trace.h
index 3db76b2daed7..e8e7213d4cc5 100644
--- a/arch/s390/kvm/trace.h
+++ b/arch/s390/kvm/trace.h
@@ -30,6 +30,52 @@
TP_printk("%02d[%016lx-%016lx]: " p_str, __entry->id, \
__entry->pswmask, __entry->pswaddr, p_args)
+TRACE_EVENT(kvm_s390_major_guest_pfault,
+ TP_PROTO(VCPU_PROTO_COMMON),
+ TP_ARGS(VCPU_ARGS_COMMON),
+
+ TP_STRUCT__entry(
+ VCPU_FIELD_COMMON
+ ),
+
+ TP_fast_assign(
+ VCPU_ASSIGN_COMMON
+ ),
+ VCPU_TP_PRINTK("%s", "major fault, maybe applicable for pfault")
+ );
+
+TRACE_EVENT(kvm_s390_pfault_init,
+ TP_PROTO(VCPU_PROTO_COMMON, long pfault_token),
+ TP_ARGS(VCPU_ARGS_COMMON, pfault_token),
+
+ TP_STRUCT__entry(
+ VCPU_FIELD_COMMON
+ __field(long, pfault_token)
+ ),
+
+ TP_fast_assign(
+ VCPU_ASSIGN_COMMON
+ __entry->pfault_token = pfault_token;
+ ),
+ VCPU_TP_PRINTK("init pfault token %ld", __entry->pfault_token)
+ );
+
+TRACE_EVENT(kvm_s390_pfault_done,
+ TP_PROTO(VCPU_PROTO_COMMON, long pfault_token),
+ TP_ARGS(VCPU_ARGS_COMMON, pfault_token),
+
+ TP_STRUCT__entry(
+ VCPU_FIELD_COMMON
+ __field(long, pfault_token)
+ ),
+
+ TP_fast_assign(
+ VCPU_ASSIGN_COMMON
+ __entry->pfault_token = pfault_token;
+ ),
+ VCPU_TP_PRINTK("done pfault token %ld", __entry->pfault_token)
+ );
+
/*
* Tracepoints for SIE entry and exit.
*/
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index b068729e50ac..e3fffe1dff51 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -2,8 +2,7 @@
# Makefile for s390-specific library files..
#
-lib-y += delay.o string.o uaccess_pt.o find.o
+lib-y += delay.o string.o uaccess_pt.o uaccess_mvcos.o find.o
obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o
obj-$(CONFIG_64BIT) += mem64.o
-lib-$(CONFIG_64BIT) += uaccess_mvcos.o
lib-$(CONFIG_SMP) += spinlock.o
diff --git a/arch/s390/lib/find.c b/arch/s390/lib/find.c
index 620d34d6487e..922003c1b90d 100644
--- a/arch/s390/lib/find.c
+++ b/arch/s390/lib/find.c
@@ -4,7 +4,7 @@
* On s390x the bits are numbered:
* |0..............63|64............127|128...........191|192...........255|
* and on s390:
- * |0.....31|31....63|64....95|96...127|128..159|160..191|192..223|224..255|
+ * |0.....31|32....63|64....95|96...127|128..159|160..191|192..223|224..255|
*
* The reason for this bit numbering is the fact that the hardware sets bits
* in a bitmap starting at bit 0 (MSB) and we don't want to scan the bitmap
diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
index b1a22173d027..c7e0e81f4b4e 100644
--- a/arch/s390/lib/uaccess.h
+++ b/arch/s390/lib/uaccess.h
@@ -6,7 +6,11 @@
#ifndef __ARCH_S390_LIB_UACCESS_H
#define __ARCH_S390_LIB_UACCESS_H
-extern int futex_atomic_op_pt(int, u32 __user *, int, int *);
-extern int futex_atomic_cmpxchg_pt(u32 *, u32 __user *, u32, u32);
+unsigned long copy_from_user_pt(void *to, const void __user *from, unsigned long n);
+unsigned long copy_to_user_pt(void __user *to, const void *from, unsigned long n);
+unsigned long copy_in_user_pt(void __user *to, const void __user *from, unsigned long n);
+unsigned long clear_user_pt(void __user *to, unsigned long n);
+unsigned long strnlen_user_pt(const char __user *src, unsigned long count);
+long strncpy_from_user_pt(char *dst, const char __user *src, long count);
#endif /* __ARCH_S390_LIB_UACCESS_H */
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
index 4b7993bf69b9..ae97b8df11aa 100644
--- a/arch/s390/lib/uaccess_mvcos.c
+++ b/arch/s390/lib/uaccess_mvcos.c
@@ -6,8 +6,11 @@
* Gerald Schaefer (gerald.schaefer@de.ibm.com)
*/
+#include <linux/jump_label.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/mm.h>
+#include <asm/facility.h>
#include <asm/uaccess.h>
#include <asm/futex.h>
#include "uaccess.h"
@@ -26,7 +29,10 @@
#define SLR "slgr"
#endif
-static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
+static struct static_key have_mvcos = STATIC_KEY_INIT_TRUE;
+
+static inline unsigned long copy_from_user_mvcos(void *x, const void __user *ptr,
+ unsigned long size)
{
register unsigned long reg0 asm("0") = 0x81UL;
unsigned long tmp1, tmp2;
@@ -65,7 +71,16 @@ static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
return size;
}
-static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
+unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+ if (static_key_true(&have_mvcos))
+ return copy_from_user_mvcos(to, from, n);
+ return copy_from_user_pt(to, from, n);
+}
+EXPORT_SYMBOL(__copy_from_user);
+
+static inline unsigned long copy_to_user_mvcos(void __user *ptr, const void *x,
+ unsigned long size)
{
register unsigned long reg0 asm("0") = 0x810000UL;
unsigned long tmp1, tmp2;
@@ -94,8 +109,16 @@ static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
return size;
}
-static size_t copy_in_user_mvcos(size_t size, void __user *to,
- const void __user *from)
+unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+ if (static_key_true(&have_mvcos))
+ return copy_to_user_mvcos(to, from, n);
+ return copy_to_user_pt(to, from, n);
+}
+EXPORT_SYMBOL(__copy_to_user);
+
+static inline unsigned long copy_in_user_mvcos(void __user *to, const void __user *from,
+ unsigned long size)
{
register unsigned long reg0 asm("0") = 0x810081UL;
unsigned long tmp1, tmp2;
@@ -117,7 +140,15 @@ static size_t copy_in_user_mvcos(size_t size, void __user *to,
return size;
}
-static size_t clear_user_mvcos(size_t size, void __user *to)
+unsigned long __copy_in_user(void __user *to, const void __user *from, unsigned long n)
+{
+ if (static_key_true(&have_mvcos))
+ return copy_in_user_mvcos(to, from, n);
+ return copy_in_user_pt(to, from, n);
+}
+EXPORT_SYMBOL(__copy_in_user);
+
+static inline unsigned long clear_user_mvcos(void __user *to, unsigned long size)
{
register unsigned long reg0 asm("0") = 0x810000UL;
unsigned long tmp1, tmp2;
@@ -145,17 +176,26 @@ static size_t clear_user_mvcos(size_t size, void __user *to)
return size;
}
-static size_t strnlen_user_mvcos(size_t count, const char __user *src)
+unsigned long __clear_user(void __user *to, unsigned long size)
{
- size_t done, len, offset, len_str;
+ if (static_key_true(&have_mvcos))
+ return clear_user_mvcos(to, size);
+ return clear_user_pt(to, size);
+}
+EXPORT_SYMBOL(__clear_user);
+
+static inline unsigned long strnlen_user_mvcos(const char __user *src,
+ unsigned long count)
+{
+ unsigned long done, len, offset, len_str;
char buf[256];
done = 0;
do {
- offset = (size_t)src & ~PAGE_MASK;
+ offset = (unsigned long)src & ~PAGE_MASK;
len = min(256UL, PAGE_SIZE - offset);
len = min(count - done, len);
- if (copy_from_user_mvcos(len, src, buf))
+ if (copy_from_user_mvcos(buf, src, len))
return 0;
len_str = strnlen(buf, len);
done += len_str;
@@ -164,18 +204,26 @@ static size_t strnlen_user_mvcos(size_t count, const char __user *src)
return done + 1;
}
-static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
- char *dst)
+unsigned long __strnlen_user(const char __user *src, unsigned long count)
{
- size_t done, len, offset, len_str;
+ if (static_key_true(&have_mvcos))
+ return strnlen_user_mvcos(src, count);
+ return strnlen_user_pt(src, count);
+}
+EXPORT_SYMBOL(__strnlen_user);
- if (unlikely(!count))
+static inline long strncpy_from_user_mvcos(char *dst, const char __user *src,
+ long count)
+{
+ unsigned long done, len, offset, len_str;
+
+ if (unlikely(count <= 0))
return 0;
done = 0;
do {
- offset = (size_t)src & ~PAGE_MASK;
+ offset = (unsigned long)src & ~PAGE_MASK;
len = min(count - done, PAGE_SIZE - offset);
- if (copy_from_user_mvcos(len, src, dst))
+ if (copy_from_user_mvcos(dst, src, len))
return -EFAULT;
len_str = strnlen(dst, len);
done += len_str;
@@ -185,13 +233,31 @@ static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
return done;
}
-struct uaccess_ops uaccess_mvcos = {
- .copy_from_user = copy_from_user_mvcos,
- .copy_to_user = copy_to_user_mvcos,
- .copy_in_user = copy_in_user_mvcos,
- .clear_user = clear_user_mvcos,
- .strnlen_user = strnlen_user_mvcos,
- .strncpy_from_user = strncpy_from_user_mvcos,
- .futex_atomic_op = futex_atomic_op_pt,
- .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
-};
+long __strncpy_from_user(char *dst, const char __user *src, long count)
+{
+ if (static_key_true(&have_mvcos))
+ return strncpy_from_user_mvcos(dst, src, count);
+ return strncpy_from_user_pt(dst, src, count);
+}
+EXPORT_SYMBOL(__strncpy_from_user);
+
+/*
+ * The uaccess page tabe walk variant can be enforced with the "uaccesspt"
+ * kernel parameter. This is mainly for debugging purposes.
+ */
+static int force_uaccess_pt __initdata;
+
+static int __init parse_uaccess_pt(char *__unused)
+{
+ force_uaccess_pt = 1;
+ return 0;
+}
+early_param("uaccesspt", parse_uaccess_pt);
+
+static int __init uaccess_init(void)
+{
+ if (IS_ENABLED(CONFIG_32BIT) || force_uaccess_pt || !test_facility(27))
+ static_key_slow_dec(&have_mvcos);
+ return 0;
+}
+early_initcall(uaccess_init);
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 61ebcc9ccb34..8d39760bae68 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -22,7 +22,7 @@
#define SLR "slgr"
#endif
-static size_t strnlen_kernel(size_t count, const char __user *src)
+static unsigned long strnlen_kernel(const char __user *src, unsigned long count)
{
register unsigned long reg0 asm("0") = 0UL;
unsigned long tmp1, tmp2;
@@ -42,8 +42,8 @@ static size_t strnlen_kernel(size_t count, const char __user *src)
return count;
}
-static size_t copy_in_kernel(size_t count, void __user *to,
- const void __user *from)
+static unsigned long copy_in_kernel(void __user *to, const void __user *from,
+ unsigned long count)
{
unsigned long tmp1;
@@ -146,8 +146,8 @@ static unsigned long follow_table(struct mm_struct *mm,
#endif /* CONFIG_64BIT */
-static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
- size_t n, int write_user)
+static inline unsigned long __user_copy_pt(unsigned long uaddr, void *kptr,
+ unsigned long n, int write_user)
{
struct mm_struct *mm = current->mm;
unsigned long offset, done, size, kaddr;
@@ -189,8 +189,7 @@ fault:
* Do DAT for user address by page table walk, return kernel address.
* This function needs to be called with current->mm->page_table_lock held.
*/
-static __always_inline unsigned long __dat_user_addr(unsigned long uaddr,
- int write)
+static inline unsigned long __dat_user_addr(unsigned long uaddr, int write)
{
struct mm_struct *mm = current->mm;
unsigned long kaddr;
@@ -211,29 +210,29 @@ fault:
return 0;
}
-static size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
+unsigned long copy_from_user_pt(void *to, const void __user *from, unsigned long n)
{
- size_t rc;
+ unsigned long rc;
if (segment_eq(get_fs(), KERNEL_DS))
- return copy_in_kernel(n, (void __user *) to, from);
+ return copy_in_kernel((void __user *) to, from, n);
rc = __user_copy_pt((unsigned long) from, to, n, 0);
if (unlikely(rc))
memset(to + n - rc, 0, rc);
return rc;
}
-static size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
+unsigned long copy_to_user_pt(void __user *to, const void *from, unsigned long n)
{
if (segment_eq(get_fs(), KERNEL_DS))
- return copy_in_kernel(n, to, (void __user *) from);
+ return copy_in_kernel(to, (void __user *) from, n);
return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
}
-static size_t clear_user_pt(size_t n, void __user *to)
+unsigned long clear_user_pt(void __user *to, unsigned long n)
{
void *zpage = (void *) empty_zero_page;
- long done, size, ret;
+ unsigned long done, size, ret;
done = 0;
do {
@@ -242,7 +241,7 @@ static size_t clear_user_pt(size_t n, void __user *to)
else
size = n - done;
if (segment_eq(get_fs(), KERNEL_DS))
- ret = copy_in_kernel(n, to, (void __user *) zpage);
+ ret = copy_in_kernel(to, (void __user *) zpage, n);
else
ret = __user_copy_pt((unsigned long) to, zpage, size, 1);
done += size;
@@ -253,17 +252,17 @@ static size_t clear_user_pt(size_t n, void __user *to)
return 0;
}
-static size_t strnlen_user_pt(size_t count, const char __user *src)
+unsigned long strnlen_user_pt(const char __user *src, unsigned long count)
{
unsigned long uaddr = (unsigned long) src;
struct mm_struct *mm = current->mm;
unsigned long offset, done, len, kaddr;
- size_t len_str;
+ unsigned long len_str;
if (unlikely(!count))
return 0;
if (segment_eq(get_fs(), KERNEL_DS))
- return strnlen_kernel(count, src);
+ return strnlen_kernel(src, count);
if (!mm)
return 0;
done = 0;
@@ -289,19 +288,18 @@ fault:
goto retry;
}
-static size_t strncpy_from_user_pt(size_t count, const char __user *src,
- char *dst)
+long strncpy_from_user_pt(char *dst, const char __user *src, long count)
{
- size_t done, len, offset, len_str;
+ unsigned long done, len, offset, len_str;
- if (unlikely(!count))
+ if (unlikely(count <= 0))
return 0;
done = 0;
do {
- offset = (size_t)src & ~PAGE_MASK;
+ offset = (unsigned long)src & ~PAGE_MASK;
len = min(count - done, PAGE_SIZE - offset);
if (segment_eq(get_fs(), KERNEL_DS)) {
- if (copy_in_kernel(len, (void __user *) dst, src))
+ if (copy_in_kernel((void __user *) dst, src, len))
return -EFAULT;
} else {
if (__user_copy_pt((unsigned long) src, dst, len, 0))
@@ -315,8 +313,8 @@ static size_t strncpy_from_user_pt(size_t count, const char __user *src,
return done;
}
-static size_t copy_in_user_pt(size_t n, void __user *to,
- const void __user *from)
+unsigned long copy_in_user_pt(void __user *to, const void __user *from,
+ unsigned long n)
{
struct mm_struct *mm = current->mm;
unsigned long offset_max, uaddr, done, size, error_code;
@@ -326,7 +324,7 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
int write_user;
if (segment_eq(get_fs(), KERNEL_DS))
- return copy_in_kernel(n, to, from);
+ return copy_in_kernel(to, from, n);
if (!mm)
return n;
done = 0;
@@ -411,7 +409,7 @@ static int __futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
return ret;
}
-int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
+int __futex_atomic_op_inuser(int op, u32 __user *uaddr, int oparg, int *old)
{
int ret;
@@ -449,8 +447,8 @@ static int __futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
return ret;
}
-int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
- u32 oldval, u32 newval)
+int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
{
int ret;
@@ -471,14 +469,3 @@ int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
put_page(virt_to_page(uaddr));
return ret;
}
-
-struct uaccess_ops uaccess_pt = {
- .copy_from_user = copy_from_user_pt,
- .copy_to_user = copy_to_user_pt,
- .copy_in_user = copy_in_user_pt,
- .clear_user = clear_user_pt,
- .strnlen_user = strnlen_user_pt,
- .strncpy_from_user = strncpy_from_user_pt,
- .futex_atomic_op = futex_atomic_op_pt,
- .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
-};
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index d95265b2719f..88cef505453b 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -50,6 +50,7 @@
#define VM_FAULT_BADMAP 0x020000
#define VM_FAULT_BADACCESS 0x040000
#define VM_FAULT_SIGNAL 0x080000
+#define VM_FAULT_PFAULT 0x100000
static unsigned long store_indication __read_mostly;
@@ -227,6 +228,7 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault)
return;
}
case VM_FAULT_BADCONTEXT:
+ case VM_FAULT_PFAULT:
do_no_context(regs);
break;
case VM_FAULT_SIGNAL:
@@ -264,6 +266,9 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault)
*/
static inline int do_exception(struct pt_regs *regs, int access)
{
+#ifdef CONFIG_PGSTE
+ struct gmap *gmap;
+#endif
struct task_struct *tsk;
struct mm_struct *mm;
struct vm_area_struct *vma;
@@ -304,9 +309,10 @@ static inline int do_exception(struct pt_regs *regs, int access)
down_read(&mm->mmap_sem);
#ifdef CONFIG_PGSTE
- if ((current->flags & PF_VCPU) && S390_lowcore.gmap) {
- address = __gmap_fault(address,
- (struct gmap *) S390_lowcore.gmap);
+ gmap = (struct gmap *)
+ ((current->flags & PF_VCPU) ? S390_lowcore.gmap : 0);
+ if (gmap) {
+ address = __gmap_fault(address, gmap);
if (address == -EFAULT) {
fault = VM_FAULT_BADMAP;
goto out_up;
@@ -315,6 +321,8 @@ static inline int do_exception(struct pt_regs *regs, int access)
fault = VM_FAULT_OOM;
goto out_up;
}
+ if (gmap->pfault_enabled)
+ flags |= FAULT_FLAG_RETRY_NOWAIT;
}
#endif
@@ -371,9 +379,19 @@ retry:
regs, address);
}
if (fault & VM_FAULT_RETRY) {
+#ifdef CONFIG_PGSTE
+ if (gmap && (flags & FAULT_FLAG_RETRY_NOWAIT)) {
+ /* FAULT_FLAG_RETRY_NOWAIT has been set,
+ * mmap_sem has not been released */
+ current->thread.gmap_pfault = 1;
+ fault = VM_FAULT_PFAULT;
+ goto out_up;
+ }
+#endif
/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
* of starvation. */
- flags &= ~FAULT_FLAG_ALLOW_RETRY;
+ flags &= ~(FAULT_FLAG_ALLOW_RETRY |
+ FAULT_FLAG_RETRY_NOWAIT);
flags |= FAULT_FLAG_TRIED;
down_read(&mm->mmap_sem);
goto retry;
diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c
index d1e0e0c7a7e2..2a2e35416d2f 100644
--- a/arch/s390/mm/maccess.c
+++ b/arch/s390/mm/maccess.c
@@ -128,7 +128,7 @@ void memcpy_absolute(void *dest, void *src, size_t count)
/*
* Copy memory from kernel (real) to user (virtual)
*/
-int copy_to_user_real(void __user *dest, void *src, size_t count)
+int copy_to_user_real(void __user *dest, void *src, unsigned long count)
{
int offs = 0, size, rc;
char *buf;
@@ -152,32 +152,6 @@ out:
}
/*
- * Copy memory from user (virtual) to kernel (real)
- */
-int copy_from_user_real(void *dest, void __user *src, size_t count)
-{
- int offs = 0, size, rc;
- char *buf;
-
- buf = (char *) __get_free_page(GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- rc = -EFAULT;
- while (offs < count) {
- size = min(PAGE_SIZE, count - offs);
- if (copy_from_user(buf, src + offs, size))
- goto out;
- if (memcpy_real(dest + offs, buf, size))
- goto out;
- offs += size;
- }
- rc = 0;
-out:
- free_page((unsigned long) buf);
- return rc;
-}
-
-/*
* Check if physical address is within prefix or zero page
*/
static int is_swapped(unsigned long addr)
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 3584ed9b20a1..796c9320c709 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -17,6 +17,7 @@
#include <linux/quicklist.h>
#include <linux/rcupdate.h>
#include <linux/slab.h>
+#include <linux/swapops.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -594,6 +595,82 @@ unsigned long gmap_fault(unsigned long address, struct gmap *gmap)
}
EXPORT_SYMBOL_GPL(gmap_fault);
+static void gmap_zap_swap_entry(swp_entry_t entry, struct mm_struct *mm)
+{
+ if (!non_swap_entry(entry))
+ dec_mm_counter(mm, MM_SWAPENTS);
+ else if (is_migration_entry(entry)) {
+ struct page *page = migration_entry_to_page(entry);
+
+ if (PageAnon(page))
+ dec_mm_counter(mm, MM_ANONPAGES);
+ else
+ dec_mm_counter(mm, MM_FILEPAGES);
+ }
+ free_swap_and_cache(entry);
+}
+
+/**
+ * The mm->mmap_sem lock must be held
+ */
+static void gmap_zap_unused(struct mm_struct *mm, unsigned long address)
+{
+ unsigned long ptev, pgstev;
+ spinlock_t *ptl;
+ pgste_t pgste;
+ pte_t *ptep, pte;
+
+ ptep = get_locked_pte(mm, address, &ptl);
+ if (unlikely(!ptep))
+ return;
+ pte = *ptep;
+ if (!pte_swap(pte))
+ goto out_pte;
+ /* Zap unused and logically-zero pages */
+ pgste = pgste_get_lock(ptep);
+ pgstev = pgste_val(pgste);
+ ptev = pte_val(pte);
+ if (((pgstev & _PGSTE_GPS_USAGE_MASK) == _PGSTE_GPS_USAGE_UNUSED) ||
+ ((pgstev & _PGSTE_GPS_ZERO) && (ptev & _PAGE_INVALID))) {
+ gmap_zap_swap_entry(pte_to_swp_entry(pte), mm);
+ pte_clear(mm, address, ptep);
+ }
+ pgste_set_unlock(ptep, pgste);
+out_pte:
+ pte_unmap_unlock(*ptep, ptl);
+}
+
+/*
+ * this function is assumed to be called with mmap_sem held
+ */
+void __gmap_zap(unsigned long address, struct gmap *gmap)
+{
+ unsigned long *table, *segment_ptr;
+ unsigned long segment, pgstev, ptev;
+ struct gmap_pgtable *mp;
+ struct page *page;
+
+ segment_ptr = gmap_table_walk(address, gmap);
+ if (IS_ERR(segment_ptr))
+ return;
+ segment = *segment_ptr;
+ if (segment & _SEGMENT_ENTRY_INVALID)
+ return;
+ page = pfn_to_page(segment >> PAGE_SHIFT);
+ mp = (struct gmap_pgtable *) page->index;
+ address = mp->vmaddr | (address & ~PMD_MASK);
+ /* Page table is present */
+ table = (unsigned long *)(segment & _SEGMENT_ENTRY_ORIGIN);
+ table = table + ((address >> 12) & 0xff);
+ pgstev = table[PTRS_PER_PTE];
+ ptev = table[0];
+ /* quick check, checked again with locks held */
+ if (((pgstev & _PGSTE_GPS_USAGE_MASK) == _PGSTE_GPS_USAGE_UNUSED) ||
+ ((pgstev & _PGSTE_GPS_ZERO) && (ptev & _PAGE_INVALID)))
+ gmap_zap_unused(gmap->mm, address);
+}
+EXPORT_SYMBOL_GPL(__gmap_zap);
+
void gmap_discard(unsigned long from, unsigned long to, struct gmap *gmap)
{
@@ -671,7 +748,7 @@ EXPORT_SYMBOL_GPL(gmap_unregister_ipte_notifier);
/**
* gmap_ipte_notify - mark a range of ptes for invalidation notification
* @gmap: pointer to guest mapping meta data structure
- * @address: virtual address in the guest address space
+ * @start: virtual address in the guest address space
* @len: size of area
*
* Returns 0 if for each page in the given range a gmap mapping exists and
@@ -725,13 +802,12 @@ EXPORT_SYMBOL_GPL(gmap_ipte_notify);
/**
* gmap_do_ipte_notify - call all invalidation callbacks for a specific pte.
* @mm: pointer to the process mm_struct
- * @addr: virtual address in the process address space
* @pte: pointer to the page table entry
*
* This function is assumed to be called with the page table lock held
* for the pte to notify.
*/
-void gmap_do_ipte_notify(struct mm_struct *mm, unsigned long addr, pte_t *pte)
+void gmap_do_ipte_notify(struct mm_struct *mm, pte_t *pte)
{
unsigned long segment_offset;
struct gmap_notifier *nb;
@@ -802,6 +878,78 @@ static inline void page_table_free_pgste(unsigned long *table)
__free_page(page);
}
+static inline unsigned long page_table_reset_pte(struct mm_struct *mm,
+ pmd_t *pmd, unsigned long addr, unsigned long end)
+{
+ pte_t *start_pte, *pte;
+ spinlock_t *ptl;
+ pgste_t pgste;
+
+ start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+ pte = start_pte;
+ do {
+ pgste = pgste_get_lock(pte);
+ pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK;
+ pgste_set_unlock(pte, pgste);
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+ pte_unmap_unlock(start_pte, ptl);
+
+ return addr;
+}
+
+static inline unsigned long page_table_reset_pmd(struct mm_struct *mm,
+ pud_t *pud, unsigned long addr, unsigned long end)
+{
+ unsigned long next;
+ pmd_t *pmd;
+
+ pmd = pmd_offset(pud, addr);
+ do {
+ next = pmd_addr_end(addr, end);
+ if (pmd_none_or_clear_bad(pmd))
+ continue;
+ next = page_table_reset_pte(mm, pmd, addr, next);
+ } while (pmd++, addr = next, addr != end);
+
+ return addr;
+}
+
+static inline unsigned long page_table_reset_pud(struct mm_struct *mm,
+ pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+ unsigned long next;
+ pud_t *pud;
+
+ pud = pud_offset(pgd, addr);
+ do {
+ next = pud_addr_end(addr, end);
+ if (pud_none_or_clear_bad(pud))
+ continue;
+ next = page_table_reset_pmd(mm, pud, addr, next);
+ } while (pud++, addr = next, addr != end);
+
+ return addr;
+}
+
+void page_table_reset_pgste(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ unsigned long addr, next;
+ pgd_t *pgd;
+
+ addr = start;
+ down_read(&mm->mmap_sem);
+ pgd = pgd_offset(mm, addr);
+ do {
+ next = pgd_addr_end(addr, end);
+ if (pgd_none_or_clear_bad(pgd))
+ continue;
+ next = page_table_reset_pud(mm, pgd, addr, next);
+ } while (pgd++, addr = next, addr != end);
+ up_read(&mm->mmap_sem);
+}
+EXPORT_SYMBOL(page_table_reset_pgste);
+
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned long key, bool nq)
{
@@ -1248,7 +1396,7 @@ void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
{
struct list_head *lh = (struct list_head *) pgtable;
- assert_spin_locked(&mm->page_table_lock);
+ assert_spin_locked(pmd_lockptr(mm, pmdp));
/* FIFO */
if (!pmd_huge_pte(mm, pmdp))
@@ -1264,7 +1412,7 @@ pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp)
pgtable_t pgtable;
pte_t *ptep;
- assert_spin_locked(&mm->page_table_lock);
+ assert_spin_locked(pmd_lockptr(mm, pmdp));
/* FIFO */
pgtable = pmd_huge_pte(mm, pmdp);
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 66670ff262a0..1df1d29ac81d 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -686,27 +686,13 @@ int pcibios_add_device(struct pci_dev *pdev)
int pcibios_enable_device(struct pci_dev *pdev, int mask)
{
struct zpci_dev *zdev = get_zdev(pdev);
- struct resource *res;
- u16 cmd;
- int i;
zdev->pdev = pdev;
zpci_debug_init_device(zdev);
zpci_fmb_enable_device(zdev);
zpci_map_resources(zdev);
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- for (i = 0; i < PCI_BAR_COUNT; i++) {
- res = &pdev->resource[i];
-
- if (res->flags & IORESOURCE_IO)
- return -EINVAL;
-
- if (res->flags & IORESOURCE_MEM)
- cmd |= PCI_COMMAND_MEMORY;
- }
- pci_write_config_word(pdev, PCI_COMMAND, cmd);
- return 0;
+ return pci_enable_resources(pdev, mask);
}
void pcibios_disable_device(struct pci_dev *pdev)
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c
index 75c69b402e05..c5c66840ac00 100644
--- a/arch/s390/pci/pci_debug.c
+++ b/arch/s390/pci/pci_debug.c
@@ -139,7 +139,7 @@ void zpci_debug_exit_device(struct zpci_dev *zdev)
int __init zpci_debug_init(void)
{
/* event trace buffer */
- pci_debug_msg_id = debug_register("pci_msg", 16, 1, 16 * sizeof(long));
+ pci_debug_msg_id = debug_register("pci_msg", 8, 1, 8 * sizeof(long));
if (!pci_debug_msg_id)
return -EINVAL;
debug_register_view(pci_debug_msg_id, &debug_sprintf_view);
diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c
index 60c11a629d96..f91c03119804 100644
--- a/arch/s390/pci/pci_dma.c
+++ b/arch/s390/pci/pci_dma.c
@@ -206,11 +206,13 @@ static void dma_cleanup_tables(struct zpci_dev *zdev)
zdev->dma_table = NULL;
}
-static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev, unsigned long start,
- int size)
+static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev,
+ unsigned long start, int size)
{
- unsigned long boundary_size = 0x1000000;
+ unsigned long boundary_size;
+ boundary_size = ALIGN(dma_get_seg_boundary(&zdev->pdev->dev) + 1,
+ PAGE_SIZE) >> PAGE_SHIFT;
return iommu_area_alloc(zdev->iommu_bitmap, zdev->iommu_pages,
start, size, 0, boundary_size, 0);
}
diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c
index cf8a12ff733b..ab4a91393005 100644
--- a/arch/s390/pci/pci_sysfs.c
+++ b/arch/s390/pci/pci_sysfs.c
@@ -48,29 +48,27 @@ static ssize_t show_pfgid(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR(pfgid, S_IRUGO, show_pfgid, NULL);
-static void recover_callback(struct device *dev)
+static ssize_t store_recover(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct zpci_dev *zdev = get_zdev(pdev);
int ret;
+ if (!device_remove_file_self(dev, attr))
+ return count;
+
pci_stop_and_remove_bus_device(pdev);
ret = zpci_disable_device(zdev);
if (ret)
- return;
+ return ret;
ret = zpci_enable_device(zdev);
if (ret)
- return;
+ return ret;
pci_rescan_bus(zdev->bus);
-}
-
-static ssize_t store_recover(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int rc = device_schedule_callback(dev, recover_callback);
- return rc ? rc : count;
+ return count;
}
static DEVICE_ATTR(recover, S_IWUSR, NULL, store_recover);
diff --git a/arch/score/include/asm/Kbuild b/arch/score/include/asm/Kbuild
index 146b9d5e89f8..2f947aba4bd4 100644
--- a/arch/score/include/asm/Kbuild
+++ b/arch/score/include/asm/Kbuild
@@ -1,10 +1,12 @@
header-y +=
+
generic-y += barrier.h
generic-y += clkdev.h
+generic-y += cputime.h
generic-y += hash.h
+generic-y += mcs_spinlock.h
+generic-y += preempt.h
generic-y += trace_clock.h
generic-y += xor.h
-generic-y += preempt.h
-
diff --git a/arch/score/include/asm/cputime.h b/arch/score/include/asm/cputime.h
deleted file mode 100644
index 1fced99f0d67..000000000000
--- a/arch/score/include/asm/cputime.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_SCORE_CPUTIME_H
-#define _ASM_SCORE_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* _ASM_SCORE_CPUTIME_H */
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 6357710753d5..1399383315a3 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -123,15 +123,6 @@ config SYS_SUPPORTS_NUMA
config SYS_SUPPORTS_PCI
bool
-config SYS_SUPPORTS_CMT
- bool
-
-config SYS_SUPPORTS_MTU2
- bool
-
-config SYS_SUPPORTS_TMU
- bool
-
config STACKTRACE_SUPPORT
def_bool y
@@ -191,14 +182,14 @@ config CPU_SH3
bool
select CPU_HAS_INTEVT
select CPU_HAS_SR_RB
- select SYS_SUPPORTS_TMU
+ select SYS_SUPPORTS_SH_TMU
config CPU_SH4
bool
select CPU_HAS_INTEVT
select CPU_HAS_SR_RB
select CPU_HAS_FPU if !CPU_SH4AL_DSP
- select SYS_SUPPORTS_TMU
+ select SYS_SUPPORTS_SH_TMU
select SYS_SUPPORTS_HUGETLBFS if MMU
config CPU_SH4A
@@ -213,7 +204,7 @@ config CPU_SH4AL_DSP
config CPU_SH5
bool
select CPU_HAS_FPU
- select SYS_SUPPORTS_TMU
+ select SYS_SUPPORTS_SH_TMU
select SYS_SUPPORTS_HUGETLBFS if MMU
config CPU_SHX2
@@ -250,7 +241,7 @@ choice
config CPU_SUBTYPE_SH7619
bool "Support SH7619 processor"
select CPU_SH2
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
# SH-2A Processor Support
@@ -258,50 +249,50 @@ config CPU_SUBTYPE_SH7201
bool "Support SH7201 processor"
select CPU_SH2A
select CPU_HAS_FPU
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_MTU2
config CPU_SUBTYPE_SH7203
bool "Support SH7203 processor"
select CPU_SH2A
select CPU_HAS_FPU
- select SYS_SUPPORTS_CMT
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_MTU2
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL
config CPU_SUBTYPE_SH7206
bool "Support SH7206 processor"
select CPU_SH2A
- select SYS_SUPPORTS_CMT
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_MTU2
config CPU_SUBTYPE_SH7263
bool "Support SH7263 processor"
select CPU_SH2A
select CPU_HAS_FPU
- select SYS_SUPPORTS_CMT
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_MTU2
config CPU_SUBTYPE_SH7264
bool "Support SH7264 processor"
select CPU_SH2A
select CPU_HAS_FPU
- select SYS_SUPPORTS_CMT
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_MTU2
select PINCTRL
config CPU_SUBTYPE_SH7269
bool "Support SH7269 processor"
select CPU_SH2A
select CPU_HAS_FPU
- select SYS_SUPPORTS_CMT
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_MTU2
select PINCTRL
config CPU_SUBTYPE_MXG
bool "Support MX-G processor"
select CPU_SH2A
- select SYS_SUPPORTS_MTU2
+ select SYS_SUPPORTS_SH_MTU2
help
Select MX-G if running on an R8A03022BG part.
@@ -354,9 +345,8 @@ config CPU_SUBTYPE_SH7720
bool "Support SH7720 processor"
select CPU_SH3
select CPU_HAS_DSP
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
- select USB_ARCH_HAS_OHCI
select USB_OHCI_SH if USB_OHCI_HCD
select PINCTRL
help
@@ -366,8 +356,7 @@ config CPU_SUBTYPE_SH7721
bool "Support SH7721 processor"
select CPU_SH3
select CPU_HAS_DSP
- select SYS_SUPPORTS_CMT
- select USB_ARCH_HAS_OHCI
+ select SYS_SUPPORTS_SH_CMT
select USB_OHCI_SH if USB_OHCI_HCD
help
Select SH7721 if you have a SH3-DSP SH7721 CPU.
@@ -422,7 +411,7 @@ config CPU_SUBTYPE_SH7723
select CPU_SHX2
select ARCH_SHMOBILE
select ARCH_SPARSEMEM_ENABLE
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL
help
@@ -434,7 +423,7 @@ config CPU_SUBTYPE_SH7724
select CPU_SHX2
select ARCH_SHMOBILE
select ARCH_SPARSEMEM_ENABLE
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL
help
@@ -445,8 +434,6 @@ config CPU_SUBTYPE_SH7734
select CPU_SH4A
select CPU_SHX2
select ARCH_WANT_OPTIONAL_GPIOLIB
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
select PINCTRL
help
Select SH7734 if you have a SH4A SH7734 CPU.
@@ -456,8 +443,6 @@ config CPU_SUBTYPE_SH7757
select CPU_SH4A
select CPU_SHX2
select ARCH_WANT_OPTIONAL_GPIOLIB
- select USB_ARCH_HAS_OHCI
- select USB_ARCH_HAS_EHCI
select PINCTRL
help
Select SH7757 if you have a SH4A SH7757 CPU.
@@ -465,7 +450,6 @@ config CPU_SUBTYPE_SH7757
config CPU_SUBTYPE_SH7763
bool "Support SH7763 processor"
select CPU_SH4A
- select USB_ARCH_HAS_OHCI
select USB_OHCI_SH if USB_OHCI_HCD
help
Select SH7763 if you have a SH4A SH7763(R5S77631) CPU.
@@ -494,9 +478,7 @@ config CPU_SUBTYPE_SH7786
select CPU_HAS_PTEAEX
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select ARCH_WANT_OPTIONAL_GPIOLIB
- select USB_ARCH_HAS_OHCI
select USB_OHCI_SH if USB_OHCI_HCD
- select USB_ARCH_HAS_EHCI
select USB_EHCI_SH if USB_EHCI_HCD
select PINCTRL
@@ -514,7 +496,7 @@ config CPU_SUBTYPE_SH7343
bool "Support SH7343 processor"
select CPU_SH4AL_DSP
select ARCH_SHMOBILE
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
config CPU_SUBTYPE_SH7722
bool "Support SH7722 processor"
@@ -523,7 +505,7 @@ config CPU_SUBTYPE_SH7722
select ARCH_SHMOBILE
select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_NUMA
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
select PINCTRL
@@ -534,7 +516,7 @@ config CPU_SUBTYPE_SH7366
select ARCH_SHMOBILE
select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_NUMA
- select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_SH_CMT
endchoice
@@ -567,27 +549,6 @@ source "arch/sh/boards/Kconfig"
menu "Timer and clock configuration"
-config SH_TIMER_TMU
- bool "TMU timer driver"
- depends on SYS_SUPPORTS_TMU
- default y
- help
- This enables the build of the TMU timer driver.
-
-config SH_TIMER_CMT
- bool "CMT timer driver"
- depends on SYS_SUPPORTS_CMT
- default y
- help
- This enables build of the CMT timer driver.
-
-config SH_TIMER_MTU2
- bool "MTU2 timer driver"
- depends on SYS_SUPPORTS_MTU2
- default y
- help
- This enables build of the MTU2 timer driver.
-
config SH_PCLK_FREQ
int "Peripheral clock frequency (in Hz)"
depends on SH_CLK_CPG_LEGACY
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 5bc3a15465c7..85d5255d259f 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -861,14 +861,12 @@ static struct asoc_simple_card_info fsi_da7210_info = {
.card = "FSIB-DA7210",
.codec = "da7210.0-001a",
.platform = "sh_fsi.0",
- .daifmt = SND_SOC_DAIFMT_I2S,
+ .daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
.cpu_dai = {
.name = "fsib-dai",
- .fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
},
.codec_dai = {
.name = "da7210-hifi",
- .fmt = SND_SOC_DAIFMT_CBM_CFM,
},
};
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 21e4230659a5..1162bc6945a3 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -304,14 +304,12 @@ static struct asoc_simple_card_info fsi_ak4642_info = {
.card = "FSIA-AK4642",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi.0",
- .daifmt = SND_SOC_DAIFMT_LEFT_J,
+ .daifmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
.cpu_dai = {
.name = "fsia-dai",
- .fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
},
.codec_dai = {
.name = "ak4642-hifi",
- .fmt = SND_SOC_DAIFMT_CBM_CFM,
.sysclk = 11289600,
},
};
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 60ed3e1c4b75..1bc09ee7948f 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -186,11 +186,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
return start;
}
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- return pci_enable_resources(dev, mask);
-}
-
static void __init
pcibios_bus_report_status_early(struct pci_channel *hose,
int top_bus, int current_bus,
diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild
index 0cd7198a4524..c19e47dacb31 100644
--- a/arch/sh/include/asm/Kbuild
+++ b/arch/sh/include/asm/Kbuild
@@ -8,18 +8,21 @@ generic-y += emergency-restart.h
generic-y += errno.h
generic-y += exec.h
generic-y += fcntl.h
+generic-y += hash.h
generic-y += ioctl.h
generic-y += ipcbuf.h
generic-y += irq_regs.h
generic-y += kvm_para.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
+generic-y += mman.h
+generic-y += msgbuf.h
generic-y += param.h
generic-y += parport.h
generic-y += percpu.h
generic-y += poll.h
-generic-y += mman.h
-generic-y += msgbuf.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sembuf.h
@@ -34,5 +37,3 @@ generic-y += termios.h
generic-y += trace_clock.h
generic-y += ucontext.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/sh/include/cpu-sh2/cpu/cache.h b/arch/sh/include/cpu-sh2/cpu/cache.h
index 673515bc4135..aa1b2b9088a7 100644
--- a/arch/sh/include/cpu-sh2/cpu/cache.h
+++ b/arch/sh/include/cpu-sh2/cpu/cache.h
@@ -18,7 +18,7 @@
#define SH_CACHE_ASSOC 8
#if defined(CONFIG_CPU_SUBTYPE_SH7619)
-#define CCR 0xffffffec
+#define SH_CCR 0xffffffec
#define CCR_CACHE_CE 0x01 /* Cache enable */
#define CCR_CACHE_WT 0x02 /* CCR[bit1=1,bit2=1] */
diff --git a/arch/sh/include/cpu-sh2a/cpu/cache.h b/arch/sh/include/cpu-sh2a/cpu/cache.h
index defb0baa5a06..b27ce92cb600 100644
--- a/arch/sh/include/cpu-sh2a/cpu/cache.h
+++ b/arch/sh/include/cpu-sh2a/cpu/cache.h
@@ -17,8 +17,8 @@
#define SH_CACHE_COMBINED 4
#define SH_CACHE_ASSOC 8
-#define CCR 0xfffc1000 /* CCR1 */
-#define CCR2 0xfffc1004
+#define SH_CCR 0xfffc1000 /* CCR1 */
+#define SH_CCR2 0xfffc1004
/*
* Most of the SH-2A CCR1 definitions resemble the SH-4 ones. All others not
diff --git a/arch/sh/include/cpu-sh3/cpu/cache.h b/arch/sh/include/cpu-sh3/cpu/cache.h
index bee2d81c56bf..29700fd88c75 100644
--- a/arch/sh/include/cpu-sh3/cpu/cache.h
+++ b/arch/sh/include/cpu-sh3/cpu/cache.h
@@ -17,7 +17,7 @@
#define SH_CACHE_COMBINED 4
#define SH_CACHE_ASSOC 8
-#define CCR 0xffffffec /* Address of Cache Control Register */
+#define SH_CCR 0xffffffec /* Address of Cache Control Register */
#define CCR_CACHE_CE 0x01 /* Cache Enable */
#define CCR_CACHE_WT 0x02 /* Write-Through (for P0,U0,P3) (else writeback) */
diff --git a/arch/sh/include/cpu-sh4/cpu/cache.h b/arch/sh/include/cpu-sh4/cpu/cache.h
index 7bfb9e8b069c..92c4cd119b66 100644
--- a/arch/sh/include/cpu-sh4/cpu/cache.h
+++ b/arch/sh/include/cpu-sh4/cpu/cache.h
@@ -17,7 +17,7 @@
#define SH_CACHE_COMBINED 4
#define SH_CACHE_ASSOC 8
-#define CCR 0xff00001c /* Address of Cache Control Register */
+#define SH_CCR 0xff00001c /* Address of Cache Control Register */
#define CCR_CACHE_OCE 0x0001 /* Operand Cache Enable */
#define CCR_CACHE_WT 0x0002 /* Write-Through (for P0,U0,P3) (else writeback)*/
#define CCR_CACHE_CB 0x0004 /* Copy-Back (for P1) (else writethrough) */
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index ecf83cd158dc..0d7360d549c1 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -112,7 +112,7 @@ static void cache_init(void)
unsigned long ccr, flags;
jump_to_uncached();
- ccr = __raw_readl(CCR);
+ ccr = __raw_readl(SH_CCR);
/*
* At this point we don't know whether the cache is enabled or not - a
@@ -189,7 +189,7 @@ static void cache_init(void)
l2_cache_init();
- __raw_writel(flags, CCR);
+ __raw_writel(flags, SH_CCR);
back_to_cached();
}
#else
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c
index 2ea4483fd722..be616ee0cf87 100644
--- a/arch/sh/kernel/idle.c
+++ b/arch/sh/kernel/idle.c
@@ -16,7 +16,6 @@
#include <linux/thread_info.h>
#include <linux/irqflags.h>
#include <linux/smp.h>
-#include <linux/cpuidle.h>
#include <linux/atomic.h>
#include <asm/pgalloc.h>
#include <asm/smp.h>
@@ -40,8 +39,7 @@ void arch_cpu_idle_dead(void)
void arch_cpu_idle(void)
{
- if (cpuidle_idle_call())
- sh_idle();
+ sh_idle();
}
void __init select_idle_routine(void)
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 0833736afa32..65a1ecd77f96 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -217,19 +217,6 @@ void __init init_IRQ(void)
}
#ifdef CONFIG_HOTPLUG_CPU
-static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
-{
- struct irq_desc *desc = irq_to_desc(irq);
- struct irq_chip *chip = irq_data_get_irq_chip(data);
-
- printk(KERN_INFO "IRQ%u: moving from cpu%u to cpu%u\n",
- irq, data->node, cpu);
-
- raw_spin_lock_irq(&desc->lock);
- chip->irq_set_affinity(data, cpumask_of(cpu), false);
- raw_spin_unlock_irq(&desc->lock);
-}
-
/*
* The CPU has been marked offline. Migrate IRQs off this CPU. If
* the affinity settings do not allow other CPUs, force them onto any
@@ -250,11 +237,8 @@ void migrate_irqs(void)
irq, cpu);
cpumask_setall(data->affinity);
- newcpu = cpumask_any_and(data->affinity,
- cpu_online_mask);
}
-
- route_irq(data, irq, newcpu);
+ irq_set_affinity(irq, data->affinity);
}
}
}
diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c
index 115725198038..777e50f33c00 100644
--- a/arch/sh/mm/cache-debugfs.c
+++ b/arch/sh/mm/cache-debugfs.c
@@ -36,7 +36,7 @@ static int cache_seq_show(struct seq_file *file, void *iter)
*/
jump_to_uncached();
- ccr = __raw_readl(CCR);
+ ccr = __raw_readl(SH_CCR);
if ((ccr & CCR_CACHE_ENABLE) == 0) {
back_to_cached();
diff --git a/arch/sh/mm/cache-sh2.c b/arch/sh/mm/cache-sh2.c
index defcf719f2e8..a74259f2f981 100644
--- a/arch/sh/mm/cache-sh2.c
+++ b/arch/sh/mm/cache-sh2.c
@@ -63,9 +63,9 @@ static void sh2__flush_invalidate_region(void *start, int size)
local_irq_save(flags);
jump_to_uncached();
- ccr = __raw_readl(CCR);
+ ccr = __raw_readl(SH_CCR);
ccr |= CCR_CACHE_INVALIDATE;
- __raw_writel(ccr, CCR);
+ __raw_writel(ccr, SH_CCR);
back_to_cached();
local_irq_restore(flags);
diff --git a/arch/sh/mm/cache-sh2a.c b/arch/sh/mm/cache-sh2a.c
index 949e2d3138a0..ee87d081259b 100644
--- a/arch/sh/mm/cache-sh2a.c
+++ b/arch/sh/mm/cache-sh2a.c
@@ -134,7 +134,8 @@ static void sh2a__flush_invalidate_region(void *start, int size)
/* If there are too many pages then just blow the cache */
if (((end - begin) >> PAGE_SHIFT) >= MAX_OCACHE_PAGES) {
- __raw_writel(__raw_readl(CCR) | CCR_OCACHE_INVALIDATE, CCR);
+ __raw_writel(__raw_readl(SH_CCR) | CCR_OCACHE_INVALIDATE,
+ SH_CCR);
} else {
for (v = begin; v < end; v += L1_CACHE_BYTES)
sh2a_invalidate_line(CACHE_OC_ADDRESS_ARRAY, v);
@@ -167,7 +168,8 @@ static void sh2a_flush_icache_range(void *args)
/* I-Cache invalidate */
/* If there are too many pages then just blow the cache */
if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) {
- __raw_writel(__raw_readl(CCR) | CCR_ICACHE_INVALIDATE, CCR);
+ __raw_writel(__raw_readl(SH_CCR) | CCR_ICACHE_INVALIDATE,
+ SH_CCR);
} else {
for (v = start; v < end; v += L1_CACHE_BYTES)
sh2a_invalidate_line(CACHE_IC_ADDRESS_ARRAY, v);
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
index 0e529285b28d..51d8f7f31d1d 100644
--- a/arch/sh/mm/cache-sh4.c
+++ b/arch/sh/mm/cache-sh4.c
@@ -133,9 +133,9 @@ static void flush_icache_all(void)
jump_to_uncached();
/* Flush I-cache */
- ccr = __raw_readl(CCR);
+ ccr = __raw_readl(SH_CCR);
ccr |= CCR_CACHE_ICI;
- __raw_writel(ccr, CCR);
+ __raw_writel(ccr, SH_CCR);
/*
* back_to_cached() will take care of the barrier for us, don't add
diff --git a/arch/sh/mm/cache-shx3.c b/arch/sh/mm/cache-shx3.c
index c0adbee97b5f..24c58b7dc022 100644
--- a/arch/sh/mm/cache-shx3.c
+++ b/arch/sh/mm/cache-shx3.c
@@ -19,7 +19,7 @@ void __init shx3_cache_init(void)
{
unsigned int ccr;
- ccr = __raw_readl(CCR);
+ ccr = __raw_readl(SH_CCR);
/*
* If we've got cache aliases, resolve them in hardware.
@@ -40,5 +40,5 @@ void __init shx3_cache_init(void)
ccr |= CCR_CACHE_IBE;
#endif
- writel_uncached(ccr, CCR);
+ writel_uncached(ccr, SH_CCR);
}
diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c
index 616966a96cba..097c2cdd117f 100644
--- a/arch/sh/mm/cache.c
+++ b/arch/sh/mm/cache.c
@@ -285,8 +285,8 @@ void __init cpu_cache_init(void)
{
unsigned int cache_disabled = 0;
-#ifdef CCR
- cache_disabled = !(__raw_readl(CCR) & CCR_CACHE_ENABLE);
+#ifdef SH_CCR
+ cache_disabled = !(__raw_readl(SH_CCR) & CCR_CACHE_ENABLE);
#endif
compute_alias(&boot_cpu_data.icache);
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index c51efdcd07a2..7d8b7e94b93b 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -27,7 +27,7 @@ config SPARC
select RTC_DRV_M48T59
select HAVE_DMA_ATTRS
select HAVE_DMA_API_DEBUG
- select HAVE_ARCH_JUMP_LABEL
+ select HAVE_ARCH_JUMP_LABEL if SPARC64
select GENERIC_IRQ_SHOW
select ARCH_WANT_IPC_PARSE_VERSION
select GENERIC_PCI_IOMAP
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index 4b60a0c325ec..a45821818003 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -6,15 +6,16 @@ generic-y += cputime.h
generic-y += div64.h
generic-y += emergency-restart.h
generic-y += exec.h
-generic-y += linkage.h
-generic-y += local64.h
-generic-y += mutex.h
+generic-y += hash.h
generic-y += irq_regs.h
+generic-y += linkage.h
generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += module.h
+generic-y += mutex.h
+generic-y += preempt.h
generic-y += serial.h
generic-y += trace_clock.h
generic-y += types.h
generic-y += word-at-a-time.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/sparc/include/asm/smp_64.h b/arch/sparc/include/asm/smp_64.h
index dd3bef4b9896..05710393959f 100644
--- a/arch/sparc/include/asm/smp_64.h
+++ b/arch/sparc/include/asm/smp_64.h
@@ -32,7 +32,6 @@
DECLARE_PER_CPU(cpumask_t, cpu_sibling_map);
extern cpumask_t cpu_core_map[NR_CPUS];
-extern int sparc64_multi_core;
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
diff --git a/arch/sparc/include/asm/topology_64.h b/arch/sparc/include/asm/topology_64.h
index 1754390a426f..a2d10fc64faf 100644
--- a/arch/sparc/include/asm/topology_64.h
+++ b/arch/sparc/include/asm/topology_64.h
@@ -42,8 +42,6 @@ static inline int pcibus_to_node(struct pci_bus *pbus)
#define topology_core_id(cpu) (cpu_data(cpu).core_id)
#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
#define topology_thread_cpumask(cpu) (&per_cpu(cpu_sibling_map, cpu))
-#define mc_capable() (sparc64_multi_core)
-#define smt_capable() (sparc64_multi_core)
#endif /* CONFIG_SMP */
extern cpumask_t cpu_core_map[NR_CPUS];
diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c
index 88aaaa57bb64..e16c4157e1ae 100644
--- a/arch/sparc/kernel/leon_pci.c
+++ b/arch/sparc/kernel/leon_pci.c
@@ -99,11 +99,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
return res->start;
}
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- return pci_enable_resources(dev, mask);
-}
-
/* in/out routines taken from pcic.c
*
* This probably belongs here rather than ioport.c because
diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c
index b90bf23e3aab..a1a4400d4025 100644
--- a/arch/sparc/kernel/mdesc.c
+++ b/arch/sparc/kernel/mdesc.c
@@ -896,10 +896,6 @@ void mdesc_fill_in_cpu_data(cpumask_t *mask)
mdesc_iterate_over_cpus(fill_in_one_cpu, NULL, mask);
-#ifdef CONFIG_SMP
- sparc64_multi_core = 1;
-#endif
-
hp = mdesc_grab();
set_core_ids(hp);
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index 32a280ec38c1..d7b4967f8fa6 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -58,9 +58,12 @@ void arch_cpu_idle(void)
{
if (tlb_type != hypervisor) {
touch_nmi_watchdog();
+ local_irq_enable();
} else {
unsigned long pstate;
+ local_irq_enable();
+
/* The sun4v sleeping code requires that we have PSTATE.IE cleared over
* the cpu sleep hypervisor call.
*/
@@ -82,7 +85,6 @@ void arch_cpu_idle(void)
: "=&r" (pstate)
: "i" (PSTATE_IE));
}
- local_irq_enable();
}
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c
index 6b39125eb927..9a690d39c01b 100644
--- a/arch/sparc/kernel/prom_64.c
+++ b/arch/sparc/kernel/prom_64.c
@@ -555,9 +555,6 @@ static void *fill_in_one_cpu(struct device_node *dp, int cpuid, int arg)
cpu_data(cpuid).core_id = portid + 1;
cpu_data(cpuid).proc_id = portid;
-#ifdef CONFIG_SMP
- sparc64_multi_core = 1;
-#endif
} else {
cpu_data(cpuid).dcache_size =
of_getintprop_default(dp, "dcache-size", 16 * 1024);
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index b085311dcd0e..9781048161ab 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -53,8 +53,6 @@
#include "cpumap.h"
-int sparc64_multi_core __read_mostly;
-
DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE;
cpumask_t cpu_core_map[NR_CPUS] __read_mostly =
{ [0 ... NR_CPUS-1] = CPU_MASK_NONE };
diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S
index 87729fff13b9..33a17e7b3ccd 100644
--- a/arch/sparc/kernel/syscalls.S
+++ b/arch/sparc/kernel/syscalls.S
@@ -189,7 +189,8 @@ linux_sparc_syscall32:
mov %i0, %l5 ! IEU1
5: call %l7 ! CTI Group brk forced
srl %i5, 0, %o5 ! IEU1
- ba,a,pt %xcc, 3f
+ ba,pt %xcc, 3f
+ sra %o0, 0, %o0
/* Linux native system calls enter here... */
.align 32
@@ -217,7 +218,6 @@ linux_sparc_syscall:
3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0]
ret_sys_call:
ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
- sra %o0, 0, %o0
mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
sllx %g2, 32, %g2
diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c
index c3d82b5f54ca..3fddf64c7fc6 100644
--- a/arch/sparc/kernel/time_64.c
+++ b/arch/sparc/kernel/time_64.c
@@ -659,8 +659,7 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val
ft->clock_tick_ref = cpu_data(cpu).clock_tick;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
- (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
- (val == CPUFREQ_RESUMECHANGE)) {
+ (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
cpu_data(cpu).clock_tick =
cpufreq_scale(ft->clock_tick_ref,
ft->ref_freq,
@@ -733,7 +732,7 @@ void __irq_entry timer_interrupt(int irq, struct pt_regs *regs)
irq_enter();
local_cpu_data().irq0_irqs++;
- kstat_incr_irqs_this_cpu(0, irq_to_desc(0));
+ kstat_incr_irq_this_cpu(0);
if (unlikely(!evt->event_handler)) {
printk(KERN_WARNING
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 869023abe5a4..cfbe53c17b0d 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -14,6 +14,7 @@
#include <linux/pagemap.h>
#include <linux/vmalloc.h>
#include <linux/kdebug.h>
+#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/log2.h>
@@ -62,6 +63,7 @@ extern unsigned long last_valid_pfn;
static pgd_t *srmmu_swapper_pg_dir;
const struct sparc32_cachetlb_ops *sparc32_cachetlb_ops;
+EXPORT_SYMBOL(sparc32_cachetlb_ops);
#ifdef CONFIG_SMP
const struct sparc32_cachetlb_ops *local_ops;
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c
index 3b3a360b429a..f5d506fdddad 100644
--- a/arch/sparc/mm/tsb.c
+++ b/arch/sparc/mm/tsb.c
@@ -273,7 +273,7 @@ void __init pgtable_cache_init(void)
prom_halt();
}
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < ARRAY_SIZE(tsb_cache_names); i++) {
unsigned long size = 8192 << i;
const char *name = tsb_cache_names[i];
diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild
index 3793c75e45d9..0aa5675e7025 100644
--- a/arch/tile/include/asm/Kbuild
+++ b/arch/tile/include/asm/Kbuild
@@ -11,6 +11,7 @@ generic-y += errno.h
generic-y += exec.h
generic-y += fb.h
generic-y += fcntl.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
@@ -18,12 +19,14 @@ generic-y += ipcbuf.h
generic-y += irq_regs.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += msgbuf.h
generic-y += mutex.h
generic-y += param.h
generic-y += parport.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sembuf.h
@@ -38,5 +41,3 @@ generic-y += termios.h
generic-y += trace_clock.h
generic-y += types.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c
index a97a6452b812..077b7bc437e5 100644
--- a/arch/tile/kernel/pci_gx.c
+++ b/arch/tile/kernel/pci_gx.c
@@ -1065,18 +1065,6 @@ char *__init pcibios_setup(char *str)
}
/*
- * Enable memory address decoding, as appropriate, for the
- * device described by the 'dev' struct.
- *
- * This is called from the generic PCI layer, and can be called
- * for bridges or endpoints.
- */
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- return pci_enable_resources(dev, mask);
-}
-
-/*
* Called for each device after PCI setup is done.
* We initialize the PCI device capabilities conservatively, assuming that
* all devices can only address the 32-bit DMA space. The exception here is
diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild
index 88a330dcdede..a5e4b6068213 100644
--- a/arch/um/include/asm/Kbuild
+++ b/arch/um/include/asm/Kbuild
@@ -1,8 +1,28 @@
-generic-y += bug.h cputime.h device.h emergency-restart.h futex.h hardirq.h
-generic-y += hw_irq.h irq_regs.h kdebug.h percpu.h sections.h topology.h xor.h
-generic-y += ftrace.h pci.h io.h param.h delay.h mutex.h current.h exec.h
-generic-y += switch_to.h clkdev.h
-generic-y += trace_clock.h
-generic-y += preempt.h
-generic-y += hash.h
generic-y += barrier.h
+generic-y += bug.h
+generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += current.h
+generic-y += delay.h
+generic-y += device.h
+generic-y += emergency-restart.h
+generic-y += exec.h
+generic-y += ftrace.h
+generic-y += futex.h
+generic-y += hardirq.h
+generic-y += hash.h
+generic-y += hw_irq.h
+generic-y += io.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += mcs_spinlock.h
+generic-y += mutex.h
+generic-y += param.h
+generic-y += pci.h
+generic-y += percpu.h
+generic-y += preempt.h
+generic-y += sections.h
+generic-y += switch_to.h
+generic-y += topology.h
+generic-y += trace_clock.h
+generic-y += xor.h
diff --git a/arch/unicore32/include/asm/Kbuild b/arch/unicore32/include/asm/Kbuild
index 3ef4f9d9bf5d..1e5fb872a4aa 100644
--- a/arch/unicore32/include/asm/Kbuild
+++ b/arch/unicore32/include/asm/Kbuild
@@ -16,6 +16,7 @@ generic-y += fcntl.h
generic-y += ftrace.h
generic-y += futex.h
generic-y += hardirq.h
+generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
@@ -24,6 +25,7 @@ generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += local.h
+generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += module.h
generic-y += msgbuf.h
@@ -32,6 +34,7 @@ generic-y += parport.h
generic-y += percpu.h
generic-y += poll.h
generic-y += posix_types.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sections.h
@@ -60,5 +63,3 @@ generic-y += unaligned.h
generic-y += user.h
generic-y += vga.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 0af5250d914f..f73071742975 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -107,9 +107,9 @@ config X86
select HAVE_ARCH_SOFT_DIRTY
select CLOCKSOURCE_WATCHDOG
select GENERIC_CLOCKEVENTS
- select ARCH_CLOCKSOURCE_DATA if X86_64
+ select ARCH_CLOCKSOURCE_DATA
select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC)
- select GENERIC_TIME_VSYSCALL if X86_64
+ select GENERIC_TIME_VSYSCALL
select KTIME_SCALAR if X86_32
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
@@ -127,6 +127,7 @@ config X86
select HAVE_DEBUG_STACKOVERFLOW
select HAVE_IRQ_EXIT_ON_IRQ_STACK if X86_64
select HAVE_CC_STACKPROTECTOR
+ select GENERIC_CPU_AUTOPROBE
config INSTRUCTION_DECODER
def_bool y
@@ -195,9 +196,6 @@ config ARCH_HAS_CPU_RELAX
config ARCH_HAS_CACHE_LINE_SIZE
def_bool y
-config ARCH_HAS_CPU_AUTOPROBE
- def_bool y
-
config HAVE_SETUP_PER_CPU_AREA
def_bool y
@@ -346,12 +344,9 @@ config X86_EXTENDED_PLATFORM
for the following (non-PC) 32 bit x86 platforms:
Goldfish (Android emulator)
AMD Elan
- NUMAQ (IBM/Sequent)
RDC R-321x SoC
SGI 320/540 (Visual Workstation)
STA2X11-based (e.g. Northville)
- Summit/EXA (IBM x440)
- Unisys ES7000 IA32 series
Moorestown MID devices
If you have one of these systems, or if you want to build a
@@ -489,49 +484,22 @@ config X86_32_NON_STANDARD
depends on X86_32 && SMP
depends on X86_EXTENDED_PLATFORM
---help---
- This option compiles in the NUMAQ, Summit, bigsmp, ES7000,
- STA2X11, default subarchitectures. It is intended for a generic
- binary kernel. If you select them all, kernel will probe it
- one by one and will fallback to default.
+ This option compiles in the bigsmp and STA2X11 default
+ subarchitectures. It is intended for a generic binary
+ kernel. If you select them all, kernel will probe it one by
+ one and will fallback to default.
# Alphabetically sorted list of Non standard 32 bit platforms
-config X86_NUMAQ
- bool "NUMAQ (IBM/Sequent)"
- depends on X86_32_NON_STANDARD
- depends on PCI
- select NUMA
- select X86_MPPARSE
- ---help---
- This option is used for getting Linux to run on a NUMAQ (IBM/Sequent)
- NUMA multiquad box. This changes the way that processors are
- bootstrapped, and uses Clustered Logical APIC addressing mode instead
- of Flat Logical. You will need a new lynxer.elf file to flash your
- firmware with - send email to <Martin.Bligh@us.ibm.com>.
-
config X86_SUPPORTS_MEMORY_FAILURE
def_bool y
# MCE code calls memory_failure():
depends on X86_MCE
# On 32-bit this adds too big of NODES_SHIFT and we run out of page flags:
- depends on !X86_NUMAQ
# On 32-bit SPARSEMEM adds too big of SECTIONS_WIDTH:
depends on X86_64 || !SPARSEMEM
select ARCH_SUPPORTS_MEMORY_FAILURE
-config X86_VISWS
- bool "SGI 320/540 (Visual Workstation)"
- depends on X86_32 && PCI && X86_MPPARSE && PCI_GODIRECT
- depends on X86_32_NON_STANDARD
- ---help---
- The SGI Visual Workstation series is an IA32-based workstation
- based on SGI systems chips with some legacy PC hardware attached.
-
- Say Y here to create a kernel to run on the SGI 320 or 540.
-
- A kernel compiled for the Visual Workstation will run on general
- PCs as well. See <file:Documentation/sgi-visws.txt> for details.
-
config STA2X11
bool "STA2X11 Companion Chip Support"
depends on X86_32_NON_STANDARD && PCI
@@ -548,20 +516,6 @@ config STA2X11
option is selected the kernel will still be able to boot on
standard PC machines.
-config X86_SUMMIT
- bool "Summit/EXA (IBM x440)"
- depends on X86_32_NON_STANDARD
- ---help---
- This option is needed for IBM systems that use the Summit/EXA chipset.
- In particular, it is needed for the x440.
-
-config X86_ES7000
- bool "Unisys ES7000 IA32 series"
- depends on X86_32_NON_STANDARD && X86_BIGSMP
- ---help---
- Support for Unisys ES7000 systems. Say 'Y' here if this kernel is
- supposed to run on an IA32-based Unisys ES7000 system.
-
config X86_32_IRIS
tristate "Eurobraille/Iris poweroff module"
depends on X86_32
@@ -684,14 +638,6 @@ config MEMTEST
memtest=4, mean do 4 test patterns.
If you are unsure how to answer this question, answer N.
-config X86_SUMMIT_NUMA
- def_bool y
- depends on X86_32 && NUMA && X86_32_NON_STANDARD
-
-config X86_CYCLONE_TIMER
- def_bool y
- depends on X86_SUMMIT
-
source "arch/x86/Kconfig.cpu"
config HPET_TIMER
@@ -820,7 +766,7 @@ config NR_CPUS
range 2 8192 if SMP && !MAXSMP && CPUMASK_OFFSTACK && X86_64
default "1" if !SMP
default "8192" if MAXSMP
- default "32" if SMP && (X86_NUMAQ || X86_SUMMIT || X86_BIGSMP || X86_ES7000)
+ default "32" if SMP && X86_BIGSMP
default "8" if SMP
---help---
This allows you to specify the maximum number of CPUs which this
@@ -884,10 +830,6 @@ config X86_IO_APIC
def_bool y
depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC || PCI_MSI
-config X86_VISWS_APIC
- def_bool y
- depends on X86_32 && X86_VISWS
-
config X86_REROUTE_FOR_BROKEN_BOOT_IRQS
bool "Reroute for broken boot IRQs"
depends on X86_IO_APIC
@@ -1105,13 +1047,11 @@ config X86_CPUID
choice
prompt "High Memory Support"
- default HIGHMEM64G if X86_NUMAQ
default HIGHMEM4G
depends on X86_32
config NOHIGHMEM
bool "off"
- depends on !X86_NUMAQ
---help---
Linux can use up to 64 Gigabytes of physical memory on x86 systems.
However, the address space of 32-bit x86 processors is only 4
@@ -1148,7 +1088,6 @@ config NOHIGHMEM
config HIGHMEM4G
bool "4GB"
- depends on !X86_NUMAQ
---help---
Select this if you have a 32-bit processor and between 1 and 4
gigabytes of physical RAM.
@@ -1240,8 +1179,8 @@ config DIRECT_GBPAGES
config NUMA
bool "Numa Memory Allocation and Scheduler Support"
depends on SMP
- depends on X86_64 || (X86_32 && HIGHMEM64G && (X86_NUMAQ || X86_BIGSMP || X86_SUMMIT && ACPI))
- default y if (X86_NUMAQ || X86_SUMMIT || X86_BIGSMP)
+ depends on X86_64 || (X86_32 && HIGHMEM64G && X86_BIGSMP)
+ default y if X86_BIGSMP
---help---
Enable NUMA (Non Uniform Memory Access) support.
@@ -1252,15 +1191,11 @@ config NUMA
For 64-bit this is recommended if the system is Intel Core i7
(or later), AMD Opteron, or EM64T NUMA.
- For 32-bit this is only needed on (rare) 32-bit-only platforms
- that support NUMA topologies, such as NUMAQ / Summit, or if you
- boot a 32-bit kernel on a 64-bit NUMA platform.
+ For 32-bit this is only needed if you boot a 32-bit
+ kernel on a 64-bit NUMA platform.
Otherwise, you should say N.
-comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI"
- depends on X86_32 && X86_SUMMIT && (!HIGHMEM64G || !ACPI)
-
config AMD_NUMA
def_bool y
prompt "Old style AMD Opteron NUMA detection"
@@ -1302,7 +1237,6 @@ config NODES_SHIFT
range 1 10
default "10" if MAXSMP
default "6" if X86_64
- default "4" if X86_NUMAQ
default "3"
depends on NEED_MULTIPLE_NODES
---help---
@@ -1585,6 +1519,20 @@ config EFI_STUB
See Documentation/efi-stub.txt for more information.
+config EFI_MIXED
+ bool "EFI mixed-mode support"
+ depends on EFI_STUB && X86_64
+ ---help---
+ Enabling this feature allows a 64-bit kernel to be booted
+ on a 32-bit firmware, provided that your CPU supports 64-bit
+ mode.
+
+ Note that it is not possible to boot a mixed-mode enabled
+ kernel via the EFI boot stub - a bootloader that supports
+ the EFI handover protocol must be used.
+
+ If unsure, say N.
+
config SECCOMP
def_bool y
prompt "Enable seccomp to safely compute untrusted bytecode"
@@ -1836,17 +1784,29 @@ config DEBUG_HOTPLUG_CPU0
If unsure, say N.
config COMPAT_VDSO
- def_bool y
- prompt "Compat VDSO support"
+ def_bool n
+ prompt "Disable the 32-bit vDSO (needed for glibc 2.3.3)"
depends on X86_32 || IA32_EMULATION
---help---
- Map the 32-bit VDSO to the predictable old-style address too.
+ Certain buggy versions of glibc will crash if they are
+ presented with a 32-bit vDSO that is not mapped at the address
+ indicated in its segment table.
- Say N here if you are running a sufficiently recent glibc
- version (2.3.3 or later), to remove the high-mapped
- VDSO mapping and to exclusively use the randomized VDSO.
+ The bug was introduced by f866314b89d56845f55e6f365e18b31ec978ec3a
+ and fixed by 3b3ddb4f7db98ec9e912ccdf54d35df4aa30e04a and
+ 49ad572a70b8aeb91e57483a11dd1b77e31c4468. Glibc 2.3.3 is
+ the only released version with the bug, but OpenSUSE 9
+ contains a buggy "glibc 2.3.2".
- If unsure, say Y.
+ The symptom of the bug is that everything crashes on startup, saying:
+ dl_main: Assertion `(void *) ph->p_vaddr == _rtld_local._dl_sysinfo_dso' failed!
+
+ Saying Y here changes the default value of the vdso32 boot
+ option from 1 to 0, which turns off the 32-bit vDSO entirely.
+ This works around the glibc bug but hurts performance.
+
+ If unsure, say N: if you are compiling your own kernel, you
+ are unlikely to be using a buggy version of glibc.
config CMDLINE_BOOL
bool "Built-in kernel command line"
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index c026cca5602c..6983314c8b37 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -341,10 +341,6 @@ config X86_USE_3DNOW
def_bool y
depends on (MCYRIXIII || MK7 || MGEODE_LX) && !UML
-config X86_OOSTORE
- def_bool y
- depends on (MWINCHIP3D || MWINCHIPC6) && MTRR
-
#
# P6_NOPs are a relatively minor optimization that require a family >=
# 6 processor, except that it is broken on certain VIA chips.
@@ -363,7 +359,7 @@ config X86_P6_NOP
config X86_TSC
def_bool y
- depends on ((MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) && !X86_NUMAQ) || X86_64
+ depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) || X86_64
config X86_CMPXCHG64
def_bool y
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 321a52ccf63a..61bd2ad94281 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -81,6 +81,15 @@ config X86_PTDUMP
kernel.
If in doubt, say "N"
+config EFI_PGT_DUMP
+ bool "Dump the EFI pagetable"
+ depends on EFI && X86_PTDUMP
+ ---help---
+ Enable this if you want to dump the EFI page table before
+ enabling virtual mode. This can be used to debug miscellaneous
+ issues with the mapping of the EFI runtime regions into that
+ table.
+
config DEBUG_RODATA
bool "Write protect kernel read-only data structures"
default y
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index eeda43abed6e..3b9348a0c1a4 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -82,8 +82,8 @@ else
KBUILD_AFLAGS += -m64
KBUILD_CFLAGS += -m64
- # Don't autogenerate MMX or SSE instructions
- KBUILD_CFLAGS += -mno-mmx -mno-sse
+ # Don't autogenerate traditional x87, MMX or SSE instructions
+ KBUILD_CFLAGS += -mno-mmx -mno-sse -mno-80387 -mno-fp-ret-in-387
# Use -mpreferred-stack-boundary=3 if supported.
KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=3)
@@ -152,6 +152,7 @@ cfi-sections := $(call as-instr,.cfi_sections .debug_frame,-DCONFIG_AS_CFI_SECTI
# does binutils support specific instructions?
asinstr := $(call as-instr,fxsaveq (%rax),-DCONFIG_AS_FXSAVEQ=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)
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 878df7e88cd4..abb9eba61b50 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -80,7 +80,7 @@ targets += voffset.h
$(obj)/voffset.h: vmlinux FORCE
$(call if_changed,voffset)
-sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|startup_64\|efi_pe_entry\|efi_stub_entry\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p'
+sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p'
quiet_cmd_zoffset = ZOFFSET $@
cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
index 50f8c5e0f37e..bd49ec61255c 100644
--- a/arch/x86/boot/boot.h
+++ b/arch/x86/boot/boot.h
@@ -177,14 +177,6 @@ static inline void wrgs32(u32 v, addr_t addr)
}
/* Note: these only return true/false, not a signed return value! */
-static inline int memcmp(const void *s1, const void *s2, size_t len)
-{
- u8 diff;
- asm("repe; cmpsb; setnz %0"
- : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
- return diff;
-}
-
static inline int memcmp_fs(const void *s1, addr_t s2, size_t len)
{
u8 diff;
@@ -228,11 +220,6 @@ void copy_to_fs(addr_t dst, void *src, size_t len);
void *copy_from_fs(void *dst, addr_t src, size_t len);
void copy_to_gs(addr_t dst, void *src, size_t len);
void *copy_from_gs(void *dst, addr_t src, size_t len);
-void *memcpy(void *dst, void *src, size_t len);
-void *memset(void *dst, int c, size_t len);
-
-#define memcpy(d,s,l) __builtin_memcpy(d,s,l)
-#define memset(d,c,l) __builtin_memset(d,c,l)
/* a20.c */
int enable_a20(void);
diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index 90a21f430117..4dbf967da50d 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -111,7 +111,7 @@ struct mem_vector {
};
#define MEM_AVOID_MAX 5
-struct mem_vector mem_avoid[MEM_AVOID_MAX];
+static struct mem_vector mem_avoid[MEM_AVOID_MAX];
static bool mem_contains(struct mem_vector *region, struct mem_vector *item)
{
@@ -180,7 +180,7 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
}
/* Does this memory vector overlap a known avoided area? */
-bool mem_avoid_overlap(struct mem_vector *img)
+static bool mem_avoid_overlap(struct mem_vector *img)
{
int i;
@@ -192,8 +192,9 @@ bool mem_avoid_overlap(struct mem_vector *img)
return false;
}
-unsigned long slots[CONFIG_RANDOMIZE_BASE_MAX_OFFSET / CONFIG_PHYSICAL_ALIGN];
-unsigned long slot_max = 0;
+static unsigned long slots[CONFIG_RANDOMIZE_BASE_MAX_OFFSET /
+ CONFIG_PHYSICAL_ALIGN];
+static unsigned long slot_max;
static void slots_append(unsigned long addr)
{
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index a7677babf946..1e6146137f8e 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -19,10 +19,272 @@
static efi_system_table_t *sys_table;
+static struct efi_config *efi_early;
+
+#define efi_call_early(f, ...) \
+ efi_early->call(efi_early->f, __VA_ARGS__);
+
+#define BOOT_SERVICES(bits) \
+static void setup_boot_services##bits(struct efi_config *c) \
+{ \
+ efi_system_table_##bits##_t *table; \
+ efi_boot_services_##bits##_t *bt; \
+ \
+ table = (typeof(table))sys_table; \
+ \
+ c->text_output = table->con_out; \
+ \
+ bt = (typeof(bt))(unsigned long)(table->boottime); \
+ \
+ c->allocate_pool = bt->allocate_pool; \
+ c->allocate_pages = bt->allocate_pages; \
+ c->get_memory_map = bt->get_memory_map; \
+ c->free_pool = bt->free_pool; \
+ c->free_pages = bt->free_pages; \
+ c->locate_handle = bt->locate_handle; \
+ c->handle_protocol = bt->handle_protocol; \
+ c->exit_boot_services = bt->exit_boot_services; \
+}
+BOOT_SERVICES(32);
+BOOT_SERVICES(64);
-#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
+static void efi_printk(efi_system_table_t *, char *);
+static void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
+
+static efi_status_t
+__file_size32(void *__fh, efi_char16_t *filename_16,
+ void **handle, u64 *file_sz)
+{
+ efi_file_handle_32_t *h, *fh = __fh;
+ efi_file_info_t *info;
+ efi_status_t status;
+ efi_guid_t info_guid = EFI_FILE_INFO_ID;
+ u32 info_sz;
+
+ status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16,
+ EFI_FILE_MODE_READ, (u64)0);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, "Failed to open file: ");
+ efi_char16_printk(sys_table, filename_16);
+ efi_printk(sys_table, "\n");
+ return status;
+ }
+
+ *handle = h;
+
+ info_sz = 0;
+ status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
+ &info_sz, NULL);
+ if (status != EFI_BUFFER_TOO_SMALL) {
+ efi_printk(sys_table, "Failed to get file info size\n");
+ return status;
+ }
+
+grow:
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ info_sz, (void **)&info);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, "Failed to alloc mem for file info\n");
+ return status;
+ }
+
+ status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
+ &info_sz, info);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ efi_call_early(free_pool, info);
+ goto grow;
+ }
+
+ *file_sz = info->file_size;
+ efi_call_early(free_pool, info);
+
+ if (status != EFI_SUCCESS)
+ efi_printk(sys_table, "Failed to get initrd info\n");
+
+ return status;
+}
+
+static efi_status_t
+__file_size64(void *__fh, efi_char16_t *filename_16,
+ void **handle, u64 *file_sz)
+{
+ efi_file_handle_64_t *h, *fh = __fh;
+ efi_file_info_t *info;
+ efi_status_t status;
+ efi_guid_t info_guid = EFI_FILE_INFO_ID;
+ u32 info_sz;
+ status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16,
+ EFI_FILE_MODE_READ, (u64)0);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, "Failed to open file: ");
+ efi_char16_printk(sys_table, filename_16);
+ efi_printk(sys_table, "\n");
+ return status;
+ }
+ *handle = h;
+
+ info_sz = 0;
+ status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
+ &info_sz, NULL);
+ if (status != EFI_BUFFER_TOO_SMALL) {
+ efi_printk(sys_table, "Failed to get file info size\n");
+ return status;
+ }
+
+grow:
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ info_sz, (void **)&info);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, "Failed to alloc mem for file info\n");
+ return status;
+ }
+
+ status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
+ &info_sz, info);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ efi_call_early(free_pool, info);
+ goto grow;
+ }
+
+ *file_sz = info->file_size;
+ efi_call_early(free_pool, info);
+
+ if (status != EFI_SUCCESS)
+ efi_printk(sys_table, "Failed to get initrd info\n");
+
+ return status;
+}
+static efi_status_t
+efi_file_size(efi_system_table_t *sys_table, void *__fh,
+ efi_char16_t *filename_16, void **handle, u64 *file_sz)
+{
+ if (efi_early->is64)
+ return __file_size64(__fh, filename_16, handle, file_sz);
+
+ return __file_size32(__fh, filename_16, handle, file_sz);
+}
+
+static inline efi_status_t
+efi_file_read(void *__fh, void *handle, unsigned long *size, void *addr)
+{
+ unsigned long func;
+
+ if (efi_early->is64) {
+ efi_file_handle_64_t *fh = __fh;
+
+ func = (unsigned long)fh->read;
+ return efi_early->call(func, handle, size, addr);
+ } else {
+ efi_file_handle_32_t *fh = __fh;
+
+ func = (unsigned long)fh->read;
+ return efi_early->call(func, handle, size, addr);
+ }
+}
+
+static inline efi_status_t efi_file_close(void *__fh, void *handle)
+{
+ if (efi_early->is64) {
+ efi_file_handle_64_t *fh = __fh;
+
+ return efi_early->call((unsigned long)fh->close, handle);
+ } else {
+ efi_file_handle_32_t *fh = __fh;
+
+ return efi_early->call((unsigned long)fh->close, handle);
+ }
+}
+
+static inline efi_status_t __open_volume32(void *__image, void **__fh)
+{
+ efi_file_io_interface_t *io;
+ efi_loaded_image_32_t *image = __image;
+ efi_file_handle_32_t *fh;
+ efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
+ efi_status_t status;
+ void *handle = (void *)(unsigned long)image->device_handle;
+ unsigned long func;
+
+ status = efi_call_early(handle_protocol, handle,
+ &fs_proto, (void **)&io);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, "Failed to handle fs_proto\n");
+ return status;
+ }
+
+ func = (unsigned long)io->open_volume;
+ status = efi_early->call(func, io, &fh);
+ if (status != EFI_SUCCESS)
+ efi_printk(sys_table, "Failed to open volume\n");
+
+ *__fh = fh;
+ return status;
+}
+
+static inline efi_status_t __open_volume64(void *__image, void **__fh)
+{
+ efi_file_io_interface_t *io;
+ efi_loaded_image_64_t *image = __image;
+ efi_file_handle_64_t *fh;
+ efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
+ efi_status_t status;
+ void *handle = (void *)(unsigned long)image->device_handle;
+ unsigned long func;
+
+ status = efi_call_early(handle_protocol, handle,
+ &fs_proto, (void **)&io);
+ if (status != EFI_SUCCESS) {
+ efi_printk(sys_table, "Failed to handle fs_proto\n");
+ return status;
+ }
+
+ func = (unsigned long)io->open_volume;
+ status = efi_early->call(func, io, &fh);
+ if (status != EFI_SUCCESS)
+ efi_printk(sys_table, "Failed to open volume\n");
+
+ *__fh = fh;
+ return status;
+}
+
+static inline efi_status_t
+efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh)
+{
+ if (efi_early->is64)
+ return __open_volume64(__image, __fh);
+
+ return __open_volume32(__image, __fh);
+}
+
+static void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
+{
+ unsigned long output_string;
+ size_t offset;
+
+ if (efi_early->is64) {
+ struct efi_simple_text_output_protocol_64 *out;
+ u64 *func;
+
+ offset = offsetof(typeof(*out), output_string);
+ output_string = efi_early->text_output + offset;
+ func = (u64 *)output_string;
+
+ efi_early->call(*func, efi_early->text_output, str);
+ } else {
+ struct efi_simple_text_output_protocol_32 *out;
+ u32 *func;
+
+ offset = offsetof(typeof(*out), output_string);
+ output_string = efi_early->text_output + offset;
+ func = (u32 *)output_string;
+
+ efi_early->call(*func, efi_early->text_output, str);
+ }
+}
+
+#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
static void find_bits(unsigned long mask, u8 *pos, u8 *size)
{
@@ -47,105 +309,97 @@ static void find_bits(unsigned long mask, u8 *pos, u8 *size)
*size = len;
}
-static efi_status_t setup_efi_pci(struct boot_params *params)
+static efi_status_t
+__setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom)
{
- efi_pci_io_protocol *pci;
+ struct pci_setup_rom *rom = NULL;
efi_status_t status;
- void **pci_handle;
- efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
- unsigned long nr_pci, size = 0;
- int i;
- struct setup_data *data;
+ unsigned long size;
+ uint64_t attributes;
- data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+ status = efi_early->call(pci->attributes, pci,
+ EfiPciIoAttributeOperationGet, 0, 0,
+ &attributes);
+ if (status != EFI_SUCCESS)
+ return status;
- while (data && data->next)
- data = (struct setup_data *)(unsigned long)data->next;
+ if (!pci->romimage || !pci->romsize)
+ return EFI_INVALID_PARAMETER;
- status = efi_call_phys5(sys_table->boottime->locate_handle,
- EFI_LOCATE_BY_PROTOCOL, &pci_proto,
- NULL, &size, pci_handle);
+ size = pci->romsize + sizeof(*rom);
- if (status == EFI_BUFFER_TOO_SMALL) {
- status = efi_call_phys3(sys_table->boottime->allocate_pool,
- EFI_LOADER_DATA, size, &pci_handle);
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
+ if (status != EFI_SUCCESS)
+ return status;
- if (status != EFI_SUCCESS)
- return status;
+ memset(rom, 0, sizeof(*rom));
- status = efi_call_phys5(sys_table->boottime->locate_handle,
- EFI_LOCATE_BY_PROTOCOL, &pci_proto,
- NULL, &size, pci_handle);
- }
+ rom->data.type = SETUP_PCI;
+ rom->data.len = size - sizeof(struct setup_data);
+ rom->data.next = 0;
+ rom->pcilen = pci->romsize;
+ *__rom = rom;
- if (status != EFI_SUCCESS)
- goto free_handle;
-
- nr_pci = size / sizeof(void *);
- for (i = 0; i < nr_pci; i++) {
- void *h = pci_handle[i];
- uint64_t attributes;
- struct pci_setup_rom *rom;
+ status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
+ PCI_VENDOR_ID, 1, &(rom->vendor));
- status = efi_call_phys3(sys_table->boottime->handle_protocol,
- h, &pci_proto, &pci);
+ if (status != EFI_SUCCESS)
+ goto free_struct;
- if (status != EFI_SUCCESS)
- continue;
+ status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
+ PCI_DEVICE_ID, 1, &(rom->devid));
- if (!pci)
- continue;
+ if (status != EFI_SUCCESS)
+ goto free_struct;
-#ifdef CONFIG_X86_64
- status = efi_call_phys4(pci->attributes, pci,
- EfiPciIoAttributeOperationGet, 0,
- &attributes);
-#else
- status = efi_call_phys5(pci->attributes, pci,
- EfiPciIoAttributeOperationGet, 0, 0,
- &attributes);
-#endif
- if (status != EFI_SUCCESS)
- continue;
+ status = efi_early->call(pci->get_location, pci, &(rom->segment),
+ &(rom->bus), &(rom->device), &(rom->function));
- if (!pci->romimage || !pci->romsize)
- continue;
+ if (status != EFI_SUCCESS)
+ goto free_struct;
- size = pci->romsize + sizeof(*rom);
+ memcpy(rom->romdata, pci->romimage, pci->romsize);
+ return status;
- status = efi_call_phys3(sys_table->boottime->allocate_pool,
- EFI_LOADER_DATA, size, &rom);
+free_struct:
+ efi_call_early(free_pool, rom);
+ return status;
+}
- if (status != EFI_SUCCESS)
- continue;
+static efi_status_t
+setup_efi_pci32(struct boot_params *params, void **pci_handle,
+ unsigned long size)
+{
+ efi_pci_io_protocol_32 *pci = NULL;
+ efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
+ u32 *handles = (u32 *)(unsigned long)pci_handle;
+ efi_status_t status;
+ unsigned long nr_pci;
+ struct setup_data *data;
+ int i;
- rom->data.type = SETUP_PCI;
- rom->data.len = size - sizeof(struct setup_data);
- rom->data.next = 0;
- rom->pcilen = pci->romsize;
+ data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
- status = efi_call_phys5(pci->pci.read, pci,
- EfiPciIoWidthUint16, PCI_VENDOR_ID,
- 1, &(rom->vendor));
+ while (data && data->next)
+ data = (struct setup_data *)(unsigned long)data->next;
- if (status != EFI_SUCCESS)
- goto free_struct;
+ nr_pci = size / sizeof(u32);
+ for (i = 0; i < nr_pci; i++) {
+ struct pci_setup_rom *rom = NULL;
+ u32 h = handles[i];
- status = efi_call_phys5(pci->pci.read, pci,
- EfiPciIoWidthUint16, PCI_DEVICE_ID,
- 1, &(rom->devid));
+ status = efi_call_early(handle_protocol, h,
+ &pci_proto, (void **)&pci);
if (status != EFI_SUCCESS)
- goto free_struct;
+ continue;
- status = efi_call_phys5(pci->get_location, pci,
- &(rom->segment), &(rom->bus),
- &(rom->device), &(rom->function));
+ if (!pci)
+ continue;
+ status = __setup_efi_pci32(pci, &rom);
if (status != EFI_SUCCESS)
- goto free_struct;
-
- memcpy(rom->romdata, pci->romimage, pci->romsize);
+ continue;
if (data)
data->next = (unsigned long)rom;
@@ -154,105 +408,155 @@ static efi_status_t setup_efi_pci(struct boot_params *params)
data = (struct setup_data *)rom;
- continue;
- free_struct:
- efi_call_phys1(sys_table->boottime->free_pool, rom);
}
-free_handle:
- efi_call_phys1(sys_table->boottime->free_pool, pci_handle);
return status;
}
-/*
- * See if we have Graphics Output Protocol
- */
-static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
- unsigned long size)
+static efi_status_t
+__setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom)
{
- struct efi_graphics_output_protocol *gop, *first_gop;
- struct efi_pixel_bitmask pixel_info;
- unsigned long nr_gops;
+ struct pci_setup_rom *rom;
efi_status_t status;
- void **gop_handle;
- u16 width, height;
- u32 fb_base, fb_size;
- u32 pixels_per_scan_line;
- int pixel_format;
- int i;
+ unsigned long size;
+ uint64_t attributes;
- status = efi_call_phys3(sys_table->boottime->allocate_pool,
- EFI_LOADER_DATA, size, &gop_handle);
+ status = efi_early->call(pci->attributes, pci,
+ EfiPciIoAttributeOperationGet, 0,
+ &attributes);
if (status != EFI_SUCCESS)
return status;
- status = efi_call_phys5(sys_table->boottime->locate_handle,
- EFI_LOCATE_BY_PROTOCOL, proto,
- NULL, &size, gop_handle);
+ if (!pci->romimage || !pci->romsize)
+ return EFI_INVALID_PARAMETER;
+
+ size = pci->romsize + sizeof(*rom);
+
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
if (status != EFI_SUCCESS)
- goto free_handle;
+ return status;
- first_gop = NULL;
+ rom->data.type = SETUP_PCI;
+ rom->data.len = size - sizeof(struct setup_data);
+ rom->data.next = 0;
+ rom->pcilen = pci->romsize;
+ *__rom = rom;
- nr_gops = size / sizeof(void *);
- for (i = 0; i < nr_gops; i++) {
- struct efi_graphics_output_mode_info *info;
- efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
- bool conout_found = false;
- void *dummy;
- void *h = gop_handle[i];
+ status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
+ PCI_VENDOR_ID, 1, &(rom->vendor));
+
+ if (status != EFI_SUCCESS)
+ goto free_struct;
+
+ status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
+ PCI_DEVICE_ID, 1, &(rom->devid));
+
+ if (status != EFI_SUCCESS)
+ goto free_struct;
+
+ status = efi_early->call(pci->get_location, pci, &(rom->segment),
+ &(rom->bus), &(rom->device), &(rom->function));
+
+ if (status != EFI_SUCCESS)
+ goto free_struct;
+
+ memcpy(rom->romdata, pci->romimage, pci->romsize);
+ return status;
+
+free_struct:
+ efi_call_early(free_pool, rom);
+ return status;
+
+}
+
+static efi_status_t
+setup_efi_pci64(struct boot_params *params, void **pci_handle,
+ unsigned long size)
+{
+ efi_pci_io_protocol_64 *pci = NULL;
+ efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
+ u64 *handles = (u64 *)(unsigned long)pci_handle;
+ efi_status_t status;
+ unsigned long nr_pci;
+ struct setup_data *data;
+ int i;
+
+ data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+
+ while (data && data->next)
+ data = (struct setup_data *)(unsigned long)data->next;
+
+ nr_pci = size / sizeof(u64);
+ for (i = 0; i < nr_pci; i++) {
+ struct pci_setup_rom *rom = NULL;
+ u64 h = handles[i];
+
+ status = efi_call_early(handle_protocol, h,
+ &pci_proto, (void **)&pci);
- status = efi_call_phys3(sys_table->boottime->handle_protocol,
- h, proto, &gop);
if (status != EFI_SUCCESS)
continue;
- status = efi_call_phys3(sys_table->boottime->handle_protocol,
- h, &conout_proto, &dummy);
+ if (!pci)
+ continue;
- if (status == EFI_SUCCESS)
- conout_found = true;
+ status = __setup_efi_pci64(pci, &rom);
+ if (status != EFI_SUCCESS)
+ continue;
- status = efi_call_phys4(gop->query_mode, gop,
- gop->mode->mode, &size, &info);
- if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
- /*
- * Systems that use the UEFI Console Splitter may
- * provide multiple GOP devices, not all of which are
- * backed by real hardware. The workaround is to search
- * for a GOP implementing the ConOut protocol, and if
- * one isn't found, to just fall back to the first GOP.
- */
- width = info->horizontal_resolution;
- height = info->vertical_resolution;
- fb_base = gop->mode->frame_buffer_base;
- fb_size = gop->mode->frame_buffer_size;
- pixel_format = info->pixel_format;
- pixel_info = info->pixel_information;
- pixels_per_scan_line = info->pixels_per_scan_line;
+ if (data)
+ data->next = (unsigned long)rom;
+ else
+ params->hdr.setup_data = (unsigned long)rom;
+
+ data = (struct setup_data *)rom;
- /*
- * Once we've found a GOP supporting ConOut,
- * don't bother looking any further.
- */
- first_gop = gop;
- if (conout_found)
- break;
- }
}
- /* Did we find any GOPs? */
- if (!first_gop)
+ return status;
+}
+
+static efi_status_t setup_efi_pci(struct boot_params *params)
+{
+ efi_status_t status;
+ void **pci_handle = NULL;
+ efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
+ unsigned long size = 0;
+
+ status = efi_call_early(locate_handle,
+ EFI_LOCATE_BY_PROTOCOL,
+ &pci_proto, NULL, &size, pci_handle);
+
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ status = efi_call_early(allocate_pool,
+ EFI_LOADER_DATA,
+ size, (void **)&pci_handle);
+
+ if (status != EFI_SUCCESS)
+ return status;
+
+ status = efi_call_early(locate_handle,
+ EFI_LOCATE_BY_PROTOCOL, &pci_proto,
+ NULL, &size, pci_handle);
+ }
+
+ if (status != EFI_SUCCESS)
goto free_handle;
- /* EFI framebuffer */
- si->orig_video_isVGA = VIDEO_TYPE_EFI;
+ if (efi_early->is64)
+ status = setup_efi_pci64(params, pci_handle, size);
+ else
+ status = setup_efi_pci32(params, pci_handle, size);
- si->lfb_width = width;
- si->lfb_height = height;
- si->lfb_base = fb_base;
- si->pages = 1;
+free_handle:
+ efi_call_early(free_pool, pci_handle);
+ return status;
+}
+static void
+setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
+ struct efi_pixel_bitmask pixel_info, int pixel_format)
+{
if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
si->lfb_depth = 32;
si->lfb_linelength = pixels_per_scan_line * 4;
@@ -297,62 +601,319 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
si->rsvd_size = 0;
si->rsvd_pos = 0;
}
+}
+
+static efi_status_t
+__gop_query32(struct efi_graphics_output_protocol_32 *gop32,
+ struct efi_graphics_output_mode_info **info,
+ unsigned long *size, u32 *fb_base)
+{
+ struct efi_graphics_output_protocol_mode_32 *mode;
+ efi_status_t status;
+ unsigned long m;
+
+ m = gop32->mode;
+ mode = (struct efi_graphics_output_protocol_mode_32 *)m;
+
+ status = efi_early->call(gop32->query_mode, gop32,
+ mode->mode, size, info);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ *fb_base = mode->frame_buffer_base;
+ return status;
+}
+
+static efi_status_t
+setup_gop32(struct screen_info *si, efi_guid_t *proto,
+ unsigned long size, void **gop_handle)
+{
+ struct efi_graphics_output_protocol_32 *gop32, *first_gop;
+ unsigned long nr_gops;
+ u16 width, height;
+ u32 pixels_per_scan_line;
+ u32 fb_base;
+ struct efi_pixel_bitmask pixel_info;
+ int pixel_format;
+ efi_status_t status;
+ u32 *handles = (u32 *)(unsigned long)gop_handle;
+ int i;
+
+ first_gop = NULL;
+ gop32 = NULL;
+
+ nr_gops = size / sizeof(u32);
+ for (i = 0; i < nr_gops; i++) {
+ struct efi_graphics_output_mode_info *info = NULL;
+ efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
+ bool conout_found = false;
+ void *dummy = NULL;
+ u32 h = handles[i];
+
+ status = efi_call_early(handle_protocol, h,
+ proto, (void **)&gop32);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ status = efi_call_early(handle_protocol, h,
+ &conout_proto, &dummy);
+ if (status == EFI_SUCCESS)
+ conout_found = true;
+
+ status = __gop_query32(gop32, &info, &size, &fb_base);
+ if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
+ /*
+ * Systems that use the UEFI Console Splitter may
+ * provide multiple GOP devices, not all of which are
+ * backed by real hardware. The workaround is to search
+ * for a GOP implementing the ConOut protocol, and if
+ * one isn't found, to just fall back to the first GOP.
+ */
+ width = info->horizontal_resolution;
+ height = info->vertical_resolution;
+ pixel_format = info->pixel_format;
+ pixel_info = info->pixel_information;
+ pixels_per_scan_line = info->pixels_per_scan_line;
+
+ /*
+ * Once we've found a GOP supporting ConOut,
+ * don't bother looking any further.
+ */
+ first_gop = gop32;
+ if (conout_found)
+ break;
+ }
+ }
+
+ /* Did we find any GOPs? */
+ if (!first_gop)
+ goto out;
+
+ /* EFI framebuffer */
+ si->orig_video_isVGA = VIDEO_TYPE_EFI;
+
+ si->lfb_width = width;
+ si->lfb_height = height;
+ si->lfb_base = fb_base;
+ si->pages = 1;
+
+ setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
si->lfb_size = si->lfb_linelength * si->lfb_height;
si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
+out:
+ return status;
+}
-free_handle:
- efi_call_phys1(sys_table->boottime->free_pool, gop_handle);
+static efi_status_t
+__gop_query64(struct efi_graphics_output_protocol_64 *gop64,
+ struct efi_graphics_output_mode_info **info,
+ unsigned long *size, u32 *fb_base)
+{
+ struct efi_graphics_output_protocol_mode_64 *mode;
+ efi_status_t status;
+ unsigned long m;
+
+ m = gop64->mode;
+ mode = (struct efi_graphics_output_protocol_mode_64 *)m;
+
+ status = efi_early->call(gop64->query_mode, gop64,
+ mode->mode, size, info);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ *fb_base = mode->frame_buffer_base;
+ return status;
+}
+
+static efi_status_t
+setup_gop64(struct screen_info *si, efi_guid_t *proto,
+ unsigned long size, void **gop_handle)
+{
+ struct efi_graphics_output_protocol_64 *gop64, *first_gop;
+ unsigned long nr_gops;
+ u16 width, height;
+ u32 pixels_per_scan_line;
+ u32 fb_base;
+ struct efi_pixel_bitmask pixel_info;
+ int pixel_format;
+ efi_status_t status;
+ u64 *handles = (u64 *)(unsigned long)gop_handle;
+ int i;
+
+ first_gop = NULL;
+ gop64 = NULL;
+
+ nr_gops = size / sizeof(u64);
+ for (i = 0; i < nr_gops; i++) {
+ struct efi_graphics_output_mode_info *info = NULL;
+ efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
+ bool conout_found = false;
+ void *dummy = NULL;
+ u64 h = handles[i];
+
+ status = efi_call_early(handle_protocol, h,
+ proto, (void **)&gop64);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ status = efi_call_early(handle_protocol, h,
+ &conout_proto, &dummy);
+ if (status == EFI_SUCCESS)
+ conout_found = true;
+
+ status = __gop_query64(gop64, &info, &size, &fb_base);
+ if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
+ /*
+ * Systems that use the UEFI Console Splitter may
+ * provide multiple GOP devices, not all of which are
+ * backed by real hardware. The workaround is to search
+ * for a GOP implementing the ConOut protocol, and if
+ * one isn't found, to just fall back to the first GOP.
+ */
+ width = info->horizontal_resolution;
+ height = info->vertical_resolution;
+ pixel_format = info->pixel_format;
+ pixel_info = info->pixel_information;
+ pixels_per_scan_line = info->pixels_per_scan_line;
+
+ /*
+ * Once we've found a GOP supporting ConOut,
+ * don't bother looking any further.
+ */
+ first_gop = gop64;
+ if (conout_found)
+ break;
+ }
+ }
+
+ /* Did we find any GOPs? */
+ if (!first_gop)
+ goto out;
+
+ /* EFI framebuffer */
+ si->orig_video_isVGA = VIDEO_TYPE_EFI;
+
+ si->lfb_width = width;
+ si->lfb_height = height;
+ si->lfb_base = fb_base;
+ si->pages = 1;
+
+ setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
+
+ si->lfb_size = si->lfb_linelength * si->lfb_height;
+
+ si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
+out:
return status;
}
/*
- * See if we have Universal Graphics Adapter (UGA) protocol
+ * See if we have Graphics Output Protocol
*/
-static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
+static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
unsigned long size)
{
- struct efi_uga_draw_protocol *uga, *first_uga;
- unsigned long nr_ugas;
efi_status_t status;
- u32 width, height;
- void **uga_handle = NULL;
- int i;
+ void **gop_handle = NULL;
- status = efi_call_phys3(sys_table->boottime->allocate_pool,
- EFI_LOADER_DATA, size, &uga_handle);
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ size, (void **)&gop_handle);
if (status != EFI_SUCCESS)
return status;
- status = efi_call_phys5(sys_table->boottime->locate_handle,
- EFI_LOCATE_BY_PROTOCOL, uga_proto,
- NULL, &size, uga_handle);
+ status = efi_call_early(locate_handle,
+ EFI_LOCATE_BY_PROTOCOL,
+ proto, NULL, &size, gop_handle);
if (status != EFI_SUCCESS)
goto free_handle;
+ if (efi_early->is64)
+ status = setup_gop64(si, proto, size, gop_handle);
+ else
+ status = setup_gop32(si, proto, size, gop_handle);
+
+free_handle:
+ efi_call_early(free_pool, gop_handle);
+ return status;
+}
+
+static efi_status_t
+setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
+{
+ struct efi_uga_draw_protocol *uga = NULL, *first_uga;
+ efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
+ unsigned long nr_ugas;
+ u32 *handles = (u32 *)uga_handle;;
+ efi_status_t status;
+ int i;
+
first_uga = NULL;
+ nr_ugas = size / sizeof(u32);
+ for (i = 0; i < nr_ugas; i++) {
+ efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
+ u32 w, h, depth, refresh;
+ void *pciio;
+ u32 handle = handles[i];
+
+ status = efi_call_early(handle_protocol, handle,
+ &uga_proto, (void **)&uga);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
+
+ status = efi_early->call((unsigned long)uga->get_mode, uga,
+ &w, &h, &depth, &refresh);
+ if (status == EFI_SUCCESS && (!first_uga || pciio)) {
+ *width = w;
+ *height = h;
+
+ /*
+ * Once we've found a UGA supporting PCIIO,
+ * don't bother looking any further.
+ */
+ if (pciio)
+ break;
- nr_ugas = size / sizeof(void *);
+ first_uga = uga;
+ }
+ }
+
+ return status;
+}
+
+static efi_status_t
+setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height)
+{
+ struct efi_uga_draw_protocol *uga = NULL, *first_uga;
+ efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
+ unsigned long nr_ugas;
+ u64 *handles = (u64 *)uga_handle;;
+ efi_status_t status;
+ int i;
+
+ first_uga = NULL;
+ nr_ugas = size / sizeof(u64);
for (i = 0; i < nr_ugas; i++) {
efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
- void *handle = uga_handle[i];
u32 w, h, depth, refresh;
void *pciio;
+ u64 handle = handles[i];
- status = efi_call_phys3(sys_table->boottime->handle_protocol,
- handle, uga_proto, &uga);
+ status = efi_call_early(handle_protocol, handle,
+ &uga_proto, (void **)&uga);
if (status != EFI_SUCCESS)
continue;
- efi_call_phys3(sys_table->boottime->handle_protocol,
- handle, &pciio_proto, &pciio);
+ efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
- status = efi_call_phys5(uga->get_mode, uga, &w, &h,
- &depth, &refresh);
+ status = efi_early->call((unsigned long)uga->get_mode, uga,
+ &w, &h, &depth, &refresh);
if (status == EFI_SUCCESS && (!first_uga || pciio)) {
- width = w;
- height = h;
+ *width = w;
+ *height = h;
/*
* Once we've found a UGA supporting PCIIO,
@@ -365,7 +926,39 @@ static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
}
}
- if (!first_uga)
+ return status;
+}
+
+/*
+ * See if we have Universal Graphics Adapter (UGA) protocol
+ */
+static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
+ unsigned long size)
+{
+ efi_status_t status;
+ u32 width, height;
+ void **uga_handle = NULL;
+
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ size, (void **)&uga_handle);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ status = efi_call_early(locate_handle,
+ EFI_LOCATE_BY_PROTOCOL,
+ uga_proto, NULL, &size, uga_handle);
+ if (status != EFI_SUCCESS)
+ goto free_handle;
+
+ height = 0;
+ width = 0;
+
+ if (efi_early->is64)
+ status = setup_uga64(uga_handle, size, &width, &height);
+ else
+ status = setup_uga32(uga_handle, size, &width, &height);
+
+ if (!width && !height)
goto free_handle;
/* EFI framebuffer */
@@ -384,9 +977,8 @@ static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
si->rsvd_size = 8;
si->rsvd_pos = 24;
-
free_handle:
- efi_call_phys1(sys_table->boottime->free_pool, uga_handle);
+ efi_call_early(free_pool, uga_handle);
return status;
}
@@ -404,29 +996,28 @@ void setup_graphics(struct boot_params *boot_params)
memset(si, 0, sizeof(*si));
size = 0;
- status = efi_call_phys5(sys_table->boottime->locate_handle,
- EFI_LOCATE_BY_PROTOCOL, &graphics_proto,
- NULL, &size, gop_handle);
+ status = efi_call_early(locate_handle,
+ EFI_LOCATE_BY_PROTOCOL,
+ &graphics_proto, NULL, &size, gop_handle);
if (status == EFI_BUFFER_TOO_SMALL)
status = setup_gop(si, &graphics_proto, size);
if (status != EFI_SUCCESS) {
size = 0;
- status = efi_call_phys5(sys_table->boottime->locate_handle,
- EFI_LOCATE_BY_PROTOCOL, &uga_proto,
- NULL, &size, uga_handle);
+ status = efi_call_early(locate_handle,
+ EFI_LOCATE_BY_PROTOCOL,
+ &uga_proto, NULL, &size, uga_handle);
if (status == EFI_BUFFER_TOO_SMALL)
setup_uga(si, &uga_proto, size);
}
}
-
/*
* Because the x86 boot code expects to be passed a boot_params we
* need to create one ourselves (usually the bootloader would create
* one for us).
*/
-struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
+struct boot_params *make_boot_params(struct efi_config *c)
{
struct boot_params *boot_params;
struct sys_desc_table *sdt;
@@ -434,7 +1025,7 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
struct setup_header *hdr;
struct efi_info *efi;
efi_loaded_image_t *image;
- void *options;
+ void *options, *handle;
efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
int options_size = 0;
efi_status_t status;
@@ -445,14 +1036,21 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
unsigned long ramdisk_addr;
unsigned long ramdisk_size;
- sys_table = _table;
+ efi_early = c;
+ sys_table = (efi_system_table_t *)(unsigned long)efi_early->table;
+ handle = (void *)(unsigned long)efi_early->image_handle;
/* Check if we were booted by the EFI firmware */
if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
return NULL;
- status = efi_call_phys3(sys_table->boottime->handle_protocol,
- handle, &proto, (void *)&image);
+ if (efi_early->is64)
+ setup_boot_services64(efi_early);
+ else
+ setup_boot_services32(efi_early);
+
+ status = efi_call_early(handle_protocol, handle,
+ &proto, (void *)&image);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
return NULL;
@@ -641,14 +1239,13 @@ static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
sizeof(struct e820entry) * nr_desc;
if (*e820ext) {
- efi_call_phys1(sys_table->boottime->free_pool, *e820ext);
+ efi_call_early(free_pool, *e820ext);
*e820ext = NULL;
*e820ext_size = 0;
}
- status = efi_call_phys3(sys_table->boottime->allocate_pool,
- EFI_LOADER_DATA, size, e820ext);
-
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ size, (void **)e820ext);
if (status == EFI_SUCCESS)
*e820ext_size = size;
@@ -656,12 +1253,13 @@ static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
}
static efi_status_t exit_boot(struct boot_params *boot_params,
- void *handle)
+ void *handle, bool is64)
{
struct efi_info *efi = &boot_params->efi_info;
unsigned long map_sz, key, desc_size;
efi_memory_desc_t *mem_map;
struct setup_data *e820ext;
+ const char *signature;
__u32 e820ext_size;
__u32 nr_desc, prev_nr_desc;
efi_status_t status;
@@ -691,11 +1289,13 @@ get_map:
if (status != EFI_SUCCESS)
goto free_mem_map;
- efi_call_phys1(sys_table->boottime->free_pool, mem_map);
+ efi_call_early(free_pool, mem_map);
goto get_map; /* Allocated memory, get map again */
}
- memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32));
+ signature = is64 ? EFI64_LOADER_SIGNATURE : EFI32_LOADER_SIGNATURE;
+ memcpy(&efi->efi_loader_signature, signature, sizeof(__u32));
+
efi->efi_systab = (unsigned long)sys_table;
efi->efi_memdesc_size = desc_size;
efi->efi_memdesc_version = desc_version;
@@ -708,8 +1308,7 @@ get_map:
#endif
/* Might as well exit boot services now */
- status = efi_call_phys2(sys_table->boottime->exit_boot_services,
- handle, key);
+ status = efi_call_early(exit_boot_services, handle, key);
if (status != EFI_SUCCESS) {
/*
* ExitBootServices() will fail if any of the event
@@ -722,7 +1321,7 @@ get_map:
goto free_mem_map;
called_exit = true;
- efi_call_phys1(sys_table->boottime->free_pool, mem_map);
+ efi_call_early(free_pool, mem_map);
goto get_map;
}
@@ -736,23 +1335,31 @@ get_map:
return EFI_SUCCESS;
free_mem_map:
- efi_call_phys1(sys_table->boottime->free_pool, mem_map);
+ efi_call_early(free_pool, mem_map);
return status;
}
-
/*
* On success we return a pointer to a boot_params structure, and NULL
* on failure.
*/
-struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
+struct boot_params *efi_main(struct efi_config *c,
struct boot_params *boot_params)
{
- struct desc_ptr *gdt;
+ struct desc_ptr *gdt = NULL;
efi_loaded_image_t *image;
struct setup_header *hdr = &boot_params->hdr;
efi_status_t status;
struct desc_struct *desc;
+ void *handle;
+ efi_system_table_t *_table;
+ bool is64;
+
+ efi_early = c;
+
+ _table = (efi_system_table_t *)(unsigned long)efi_early->table;
+ handle = (void *)(unsigned long)efi_early->image_handle;
+ is64 = efi_early->is64;
sys_table = _table;
@@ -760,13 +1367,17 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
goto fail;
+ if (is64)
+ setup_boot_services64(efi_early);
+ else
+ setup_boot_services32(efi_early);
+
setup_graphics(boot_params);
setup_efi_pci(boot_params);
- status = efi_call_phys3(sys_table->boottime->allocate_pool,
- EFI_LOADER_DATA, sizeof(*gdt),
- (void **)&gdt);
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ sizeof(*gdt), (void **)&gdt);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");
goto fail;
@@ -797,7 +1408,7 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
hdr->code32_start = bzimage_addr;
}
- status = exit_boot(boot_params, handle);
+ status = exit_boot(boot_params, handle, is64);
if (status != EFI_SUCCESS)
goto fail;
diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
index 81b6b652b46a..c88c31ecad12 100644
--- a/arch/x86/boot/compressed/eboot.h
+++ b/arch/x86/boot/compressed/eboot.h
@@ -37,6 +37,24 @@ struct efi_graphics_output_mode_info {
u32 pixels_per_scan_line;
} __packed;
+struct efi_graphics_output_protocol_mode_32 {
+ u32 max_mode;
+ u32 mode;
+ u32 info;
+ u32 size_of_info;
+ u64 frame_buffer_base;
+ u32 frame_buffer_size;
+} __packed;
+
+struct efi_graphics_output_protocol_mode_64 {
+ u32 max_mode;
+ u32 mode;
+ u64 info;
+ u64 size_of_info;
+ u64 frame_buffer_base;
+ u64 frame_buffer_size;
+} __packed;
+
struct efi_graphics_output_protocol_mode {
u32 max_mode;
u32 mode;
@@ -46,6 +64,20 @@ struct efi_graphics_output_protocol_mode {
unsigned long frame_buffer_size;
} __packed;
+struct efi_graphics_output_protocol_32 {
+ u32 query_mode;
+ u32 set_mode;
+ u32 blt;
+ u32 mode;
+};
+
+struct efi_graphics_output_protocol_64 {
+ u64 query_mode;
+ u64 set_mode;
+ u64 blt;
+ u64 mode;
+};
+
struct efi_graphics_output_protocol {
void *query_mode;
unsigned long set_mode;
@@ -53,10 +85,38 @@ struct efi_graphics_output_protocol {
struct efi_graphics_output_protocol_mode *mode;
};
+struct efi_uga_draw_protocol_32 {
+ u32 get_mode;
+ u32 set_mode;
+ u32 blt;
+};
+
+struct efi_uga_draw_protocol_64 {
+ u64 get_mode;
+ u64 set_mode;
+ u64 blt;
+};
+
struct efi_uga_draw_protocol {
void *get_mode;
void *set_mode;
void *blt;
};
+struct efi_config {
+ u64 image_handle;
+ u64 table;
+ u64 allocate_pool;
+ u64 allocate_pages;
+ u64 get_memory_map;
+ u64 free_pool;
+ u64 free_pages;
+ u64 locate_handle;
+ u64 handle_protocol;
+ u64 exit_boot_services;
+ u64 text_output;
+ efi_status_t (*call)(unsigned long, ...);
+ bool is64;
+} __packed;
+
#endif /* BOOT_COMPRESSED_EBOOT_H */
diff --git a/arch/x86/boot/compressed/efi_stub_64.S b/arch/x86/boot/compressed/efi_stub_64.S
index cedc60de86eb..7ff3632806b1 100644
--- a/arch/x86/boot/compressed/efi_stub_64.S
+++ b/arch/x86/boot/compressed/efi_stub_64.S
@@ -1 +1,30 @@
+#include <asm/segment.h>
+#include <asm/msr.h>
+#include <asm/processor-flags.h>
+
#include "../../platform/efi/efi_stub_64.S"
+
+#ifdef CONFIG_EFI_MIXED
+ .code64
+ .text
+ENTRY(efi64_thunk)
+ push %rbp
+ push %rbx
+
+ subq $16, %rsp
+ leaq efi_exit32(%rip), %rax
+ movl %eax, 8(%rsp)
+ leaq efi_gdt64(%rip), %rax
+ movl %eax, 4(%rsp)
+ movl %eax, 2(%rax) /* Fixup the gdt base address */
+ leaq efi32_boot_gdt(%rip), %rax
+ movl %eax, (%rsp)
+
+ call __efi64_thunk
+
+ addq $16, %rsp
+ pop %rbx
+ pop %rbp
+ ret
+ENDPROC(efi64_thunk)
+#endif /* CONFIG_EFI_MIXED */
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
index 9116aac232c7..de9d4200d305 100644
--- a/arch/x86/boot/compressed/head_32.S
+++ b/arch/x86/boot/compressed/head_32.S
@@ -42,26 +42,53 @@ ENTRY(startup_32)
ENTRY(efi_pe_entry)
add $0x4, %esp
+ call 1f
+1: popl %esi
+ subl $1b, %esi
+
+ popl %ecx
+ movl %ecx, efi32_config(%esi) /* Handle */
+ popl %ecx
+ movl %ecx, efi32_config+8(%esi) /* EFI System table pointer */
+
+ /* Relocate efi_config->call() */
+ leal efi32_config(%esi), %eax
+ add %esi, 88(%eax)
+ pushl %eax
+
call make_boot_params
cmpl $0, %eax
- je 1f
- movl 0x4(%esp), %esi
- movl (%esp), %ecx
+ je fail
+ popl %ecx
pushl %eax
- pushl %esi
pushl %ecx
- sub $0x4, %esp
+ jmp 2f /* Skip efi_config initialization */
-ENTRY(efi_stub_entry)
+ENTRY(efi32_stub_entry)
add $0x4, %esp
+ popl %ecx
+ popl %edx
+
+ call 1f
+1: popl %esi
+ subl $1b, %esi
+
+ movl %ecx, efi32_config(%esi) /* Handle */
+ movl %edx, efi32_config+8(%esi) /* EFI System table pointer */
+
+ /* Relocate efi_config->call() */
+ leal efi32_config(%esi), %eax
+ add %esi, 88(%eax)
+ pushl %eax
+2:
call efi_main
cmpl $0, %eax
movl %eax, %esi
jne 2f
-1:
+fail:
/* EFI init failed, so hang. */
hlt
- jmp 1b
+ jmp fail
2:
call 3f
3:
@@ -202,6 +229,15 @@ relocated:
xorl %ebx, %ebx
jmp *%eax
+#ifdef CONFIG_EFI_STUB
+ .data
+efi32_config:
+ .fill 11,8,0
+ .long efi_call_phys
+ .long 0
+ .byte 0
+#endif
+
/*
* Stack and heap for uncompression
*/
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index c5c1ae0997e7..57e58a5fa210 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -113,7 +113,8 @@ ENTRY(startup_32)
lgdt gdt(%ebp)
/* Enable PAE mode */
- movl $(X86_CR4_PAE), %eax
+ movl %cr4, %eax
+ orl $X86_CR4_PAE, %eax
movl %eax, %cr4
/*
@@ -178,6 +179,13 @@ ENTRY(startup_32)
*/
pushl $__KERNEL_CS
leal startup_64(%ebp), %eax
+#ifdef CONFIG_EFI_MIXED
+ movl efi32_config(%ebp), %ebx
+ cmp $0, %ebx
+ jz 1f
+ leal handover_entry(%ebp), %eax
+1:
+#endif
pushl %eax
/* Enter paged protected Mode, activating Long Mode */
@@ -188,6 +196,30 @@ ENTRY(startup_32)
lret
ENDPROC(startup_32)
+#ifdef CONFIG_EFI_MIXED
+ .org 0x190
+ENTRY(efi32_stub_entry)
+ add $0x4, %esp /* Discard return address */
+ popl %ecx
+ popl %edx
+ popl %esi
+
+ leal (BP_scratch+4)(%esi), %esp
+ call 1f
+1: pop %ebp
+ subl $1b, %ebp
+
+ movl %ecx, efi32_config(%ebp)
+ movl %edx, efi32_config+8(%ebp)
+ sgdtl efi32_boot_gdt(%ebp)
+
+ leal efi32_config(%ebp), %eax
+ movl %eax, efi_config(%ebp)
+
+ jmp startup_32
+ENDPROC(efi32_stub_entry)
+#endif
+
.code64
.org 0x200
ENTRY(startup_64)
@@ -209,26 +241,48 @@ ENTRY(startup_64)
jmp preferred_addr
ENTRY(efi_pe_entry)
- mov %rcx, %rdi
- mov %rdx, %rsi
- pushq %rdi
- pushq %rsi
+ movq %rcx, efi64_config(%rip) /* Handle */
+ movq %rdx, efi64_config+8(%rip) /* EFI System table pointer */
+
+ leaq efi64_config(%rip), %rax
+ movq %rax, efi_config(%rip)
+
+ call 1f
+1: popq %rbp
+ subq $1b, %rbp
+
+ /*
+ * Relocate efi_config->call().
+ */
+ addq %rbp, efi64_config+88(%rip)
+
+ movq %rax, %rdi
call make_boot_params
cmpq $0,%rax
- je 1f
- mov %rax, %rdx
- popq %rsi
- popq %rdi
+ je fail
+ mov %rax, %rsi
+ jmp 2f /* Skip the relocation */
-ENTRY(efi_stub_entry)
+handover_entry:
+ call 1f
+1: popq %rbp
+ subq $1b, %rbp
+
+ /*
+ * Relocate efi_config->call().
+ */
+ movq efi_config(%rip), %rax
+ addq %rbp, 88(%rax)
+2:
+ movq efi_config(%rip), %rdi
call efi_main
movq %rax,%rsi
cmpq $0,%rax
jne 2f
-1:
+fail:
/* EFI init failed, so hang. */
hlt
- jmp 1b
+ jmp fail
2:
call 3f
3:
@@ -307,6 +361,20 @@ preferred_addr:
leaq relocated(%rbx), %rax
jmp *%rax
+#ifdef CONFIG_EFI_STUB
+ .org 0x390
+ENTRY(efi64_stub_entry)
+ movq %rdi, efi64_config(%rip) /* Handle */
+ movq %rsi, efi64_config+8(%rip) /* EFI System table pointer */
+
+ leaq efi64_config(%rip), %rax
+ movq %rax, efi_config(%rip)
+
+ movq %rdx, %rsi
+ jmp handover_entry
+ENDPROC(efi64_stub_entry)
+#endif
+
.text
relocated:
@@ -372,6 +440,25 @@ gdt:
.quad 0x0000000000000000 /* TS continued */
gdt_end:
+#ifdef CONFIG_EFI_STUB
+efi_config:
+ .quad 0
+
+#ifdef CONFIG_EFI_MIXED
+ .global efi32_config
+efi32_config:
+ .fill 11,8,0
+ .quad efi64_thunk
+ .byte 0
+#endif
+
+ .global efi64_config
+efi64_config:
+ .fill 11,8,0
+ .quad efi_call6
+ .byte 1
+#endif /* CONFIG_EFI_STUB */
+
/*
* Stack and heap for uncompression
*/
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 196eaf373a06..17684615374b 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -10,6 +10,7 @@
*/
#include "misc.h"
+#include "../string.h"
/* WARNING!!
* This code is compiled with -fPIC and it is relocated dynamically
@@ -97,8 +98,14 @@
*/
#define STATIC static
-#undef memset
#undef memcpy
+
+/*
+ * Use a normal definition of memset() from string.c. There are already
+ * included header files which expect a definition of memset() and by
+ * the time we define memset macro, it is too late.
+ */
+#undef memset
#define memzero(s, n) memset((s), 0, (n))
@@ -109,9 +116,6 @@ static void error(char *m);
*/
struct boot_params *real_mode; /* Pointer to real-mode data */
-void *memset(void *s, int c, size_t n);
-void *memcpy(void *dest, const void *src, size_t n);
-
memptr free_mem_ptr;
memptr free_mem_end_ptr;
@@ -216,45 +220,6 @@ void __putstr(const char *s)
outb(0xff & (pos >> 1), vidport+1);
}
-void *memset(void *s, int c, size_t n)
-{
- int i;
- char *ss = s;
-
- for (i = 0; i < n; i++)
- ss[i] = c;
- return s;
-}
-#ifdef CONFIG_X86_32
-void *memcpy(void *dest, const void *src, size_t n)
-{
- int d0, d1, d2;
- asm volatile(
- "rep ; movsl\n\t"
- "movl %4,%%ecx\n\t"
- "rep ; movsb\n\t"
- : "=&c" (d0), "=&D" (d1), "=&S" (d2)
- : "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src)
- : "memory");
-
- return dest;
-}
-#else
-void *memcpy(void *dest, const void *src, size_t n)
-{
- long d0, d1, d2;
- asm volatile(
- "rep ; movsq\n\t"
- "movq %4,%%rcx\n\t"
- "rep ; movsb\n\t"
- : "=&c" (d0), "=&D" (d1), "=&S" (d2)
- : "0" (n >> 3), "g" (n & 7), "1" (dest), "2" (src)
- : "memory");
-
- return dest;
-}
-#endif
-
static void error(char *x)
{
error_putstr("\n\n");
diff --git a/arch/x86/boot/compressed/string.c b/arch/x86/boot/compressed/string.c
index ffb9c5c9d748..f3c57e341402 100644
--- a/arch/x86/boot/compressed/string.c
+++ b/arch/x86/boot/compressed/string.c
@@ -1,11 +1,45 @@
#include "misc.h"
+#include "../string.c"
+
+/* misc.h might pull in string_32.h which has a macro for memcpy. undef that */
+#undef memcpy
-int memcmp(const void *s1, const void *s2, size_t len)
+#ifdef CONFIG_X86_32
+void *memcpy(void *dest, const void *src, size_t n)
{
- u8 diff;
- asm("repe; cmpsb; setnz %0"
- : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
- return diff;
+ int d0, d1, d2;
+ asm volatile(
+ "rep ; movsl\n\t"
+ "movl %4,%%ecx\n\t"
+ "rep ; movsb\n\t"
+ : "=&c" (d0), "=&D" (d1), "=&S" (d2)
+ : "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src)
+ : "memory");
+
+ return dest;
}
+#else
+void *memcpy(void *dest, const void *src, size_t n)
+{
+ long d0, d1, d2;
+ asm volatile(
+ "rep ; movsq\n\t"
+ "movq %4,%%rcx\n\t"
+ "rep ; movsb\n\t"
+ : "=&c" (d0), "=&D" (d1), "=&S" (d2)
+ : "0" (n >> 3), "g" (n & 7), "1" (dest), "2" (src)
+ : "memory");
-#include "../string.c"
+ return dest;
+}
+#endif
+
+void *memset(void *s, int c, size_t n)
+{
+ int i;
+ char *ss = s;
+
+ for (i = 0; i < n; i++)
+ ss[i] = c;
+ return s;
+}
diff --git a/arch/x86/boot/cpucheck.c b/arch/x86/boot/cpucheck.c
index 100a9a10076a..1fd7d575092e 100644
--- a/arch/x86/boot/cpucheck.c
+++ b/arch/x86/boot/cpucheck.c
@@ -27,6 +27,7 @@
#include <asm/processor-flags.h>
#include <asm/required-features.h>
#include <asm/msr-index.h>
+#include "string.h"
static u32 err_flags[NCAPINTS];
@@ -67,6 +68,13 @@ static int is_transmeta(void)
cpu_vendor[2] == A32('M', 'x', '8', '6');
}
+static int is_intel(void)
+{
+ return cpu_vendor[0] == A32('G', 'e', 'n', 'u') &&
+ cpu_vendor[1] == A32('i', 'n', 'e', 'I') &&
+ cpu_vendor[2] == A32('n', 't', 'e', 'l');
+}
+
/* Returns a bitmask of which words we have error bits in */
static int check_cpuflags(void)
{
@@ -153,6 +161,19 @@ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr)
asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx));
err = check_cpuflags();
+ } else if (err == 0x01 &&
+ !(err_flags[0] & ~(1 << X86_FEATURE_PAE)) &&
+ is_intel() && cpu.level == 6 &&
+ (cpu.model == 9 || cpu.model == 13)) {
+ /* PAE is disabled on this Pentium M but can be forced */
+ if (cmdline_find_option_bool("forcepae")) {
+ puts("WARNING: Forcing PAE in CPU flags\n");
+ set_bit(X86_FEATURE_PAE, cpu.flags);
+ err = check_cpuflags();
+ }
+ else {
+ puts("WARNING: PAE disabled. Use parameter 'forcepae' to enable at your own risk!\n");
+ }
}
if (err_flags_ptr)
diff --git a/arch/x86/boot/edd.c b/arch/x86/boot/edd.c
index c501a5b466f8..223e42527077 100644
--- a/arch/x86/boot/edd.c
+++ b/arch/x86/boot/edd.c
@@ -15,6 +15,7 @@
#include "boot.h"
#include <linux/edd.h>
+#include "string.h"
#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index ec3b8ba68096..0ca9a5c362bc 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -283,7 +283,7 @@ _start:
# Part 2 of the header, from the old setup.S
.ascii "HdrS" # header signature
- .word 0x020c # header version number (>= 0x0105)
+ .word 0x020d # header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
.globl realmode_swtch
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
@@ -350,7 +350,7 @@ cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
# can be located anywhere in
# low memory 0x10000 or higher.
-ramdisk_max: .long 0x7fffffff
+initrd_addr_max: .long 0x7fffffff
# (Header version 0x0203 or later)
# The highest safe address for
# the contents of an initrd
@@ -375,7 +375,8 @@ xloadflags:
# define XLF0 0
#endif
-#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64)
+#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64) && \
+ !defined(CONFIG_EFI_MIXED)
/* kernel/boot_param/ramdisk could be loaded above 4g */
# define XLF1 XLF_CAN_BE_LOADED_ABOVE_4G
#else
@@ -383,10 +384,14 @@ xloadflags:
#endif
#ifdef CONFIG_EFI_STUB
-# ifdef CONFIG_X86_64
-# define XLF23 XLF_EFI_HANDOVER_64 /* 64-bit EFI handover ok */
+# ifdef CONFIG_EFI_MIXED
+# define XLF23 (XLF_EFI_HANDOVER_32|XLF_EFI_HANDOVER_64)
# else
-# define XLF23 XLF_EFI_HANDOVER_32 /* 32-bit EFI handover ok */
+# ifdef CONFIG_X86_64
+# define XLF23 XLF_EFI_HANDOVER_64 /* 64-bit EFI handover ok */
+# else
+# define XLF23 XLF_EFI_HANDOVER_32 /* 32-bit EFI handover ok */
+# endif
# endif
#else
# define XLF23 0
@@ -426,13 +431,7 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr
#define INIT_SIZE VO_INIT_SIZE
#endif
init_size: .long INIT_SIZE # kernel initialization size
-handover_offset:
-#ifdef CONFIG_EFI_STUB
- .long 0x30 # offset to the handover
- # protocol entry point
-#else
- .long 0
-#endif
+handover_offset: .long 0 # Filled in by build.c
# End of setup header #####################################################
diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c
index cf6083d444f4..fd6c9f236996 100644
--- a/arch/x86/boot/main.c
+++ b/arch/x86/boot/main.c
@@ -14,6 +14,7 @@
*/
#include "boot.h"
+#include "string.h"
struct boot_params boot_params __attribute__((aligned(16)));
diff --git a/arch/x86/boot/regs.c b/arch/x86/boot/regs.c
index 958019b1cfa5..c0fb356a3092 100644
--- a/arch/x86/boot/regs.c
+++ b/arch/x86/boot/regs.c
@@ -17,6 +17,7 @@
*/
#include "boot.h"
+#include "string.h"
void initregs(struct biosregs *reg)
{
diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c
index 574dedfe2890..5339040ef86e 100644
--- a/arch/x86/boot/string.c
+++ b/arch/x86/boot/string.c
@@ -14,6 +14,20 @@
#include "boot.h"
+/*
+ * This file gets included in compressed/string.c which might pull in
+ * string_32.h and which in turn maps memcmp to __builtin_memcmp(). Undo
+ * that first.
+ */
+#undef memcmp
+int memcmp(const void *s1, const void *s2, size_t len)
+{
+ u8 diff;
+ asm("repe; cmpsb; setnz %0"
+ : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
+ return diff;
+}
+
int strcmp(const char *str1, const char *str2)
{
const unsigned char *s1 = (const unsigned char *)str1;
diff --git a/arch/x86/boot/string.h b/arch/x86/boot/string.h
new file mode 100644
index 000000000000..725e820602b1
--- /dev/null
+++ b/arch/x86/boot/string.h
@@ -0,0 +1,21 @@
+#ifndef BOOT_STRING_H
+#define BOOT_STRING_H
+
+/* Undef any of these macros coming from string_32.h. */
+#undef memcpy
+#undef memset
+#undef memcmp
+
+void *memcpy(void *dst, const void *src, size_t len);
+void *memset(void *dst, int c, size_t len);
+int memcmp(const void *s1, const void *s2, size_t len);
+
+/*
+ * Access builtin version by default. If one needs to use optimized version,
+ * do "undef memcpy" in .c file and link against right string.c
+ */
+#define memcpy(d,s,l) __builtin_memcpy(d,s,l)
+#define memset(d,c,l) __builtin_memset(d,c,l)
+#define memcmp __builtin_memcmp
+
+#endif /* BOOT_STRING_H */
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index 8e15b22391fc..1a2f2121cada 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -53,7 +53,8 @@ int is_big_kernel;
#define PECOFF_RELOC_RESERVE 0x20
-unsigned long efi_stub_entry;
+unsigned long efi32_stub_entry;
+unsigned long efi64_stub_entry;
unsigned long efi_pe_entry;
unsigned long startup_64;
@@ -219,6 +220,52 @@ static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
update_pecoff_section_header(".text", text_start, text_sz);
}
+static int reserve_pecoff_reloc_section(int c)
+{
+ /* Reserve 0x20 bytes for .reloc section */
+ memset(buf+c, 0, PECOFF_RELOC_RESERVE);
+ return PECOFF_RELOC_RESERVE;
+}
+
+static void efi_stub_defaults(void)
+{
+ /* Defaults for old kernel */
+#ifdef CONFIG_X86_32
+ efi_pe_entry = 0x10;
+#else
+ efi_pe_entry = 0x210;
+ startup_64 = 0x200;
+#endif
+}
+
+static void efi_stub_entry_update(void)
+{
+ unsigned long addr = efi32_stub_entry;
+
+#ifdef CONFIG_X86_64
+ /* Yes, this is really how we defined it :( */
+ addr = efi64_stub_entry - 0x200;
+#endif
+
+#ifdef CONFIG_EFI_MIXED
+ if (efi32_stub_entry != addr)
+ die("32-bit and 64-bit EFI entry points do not match\n");
+#endif
+ put_unaligned_le32(addr, &buf[0x264]);
+}
+
+#else
+
+static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
+static inline void update_pecoff_text(unsigned int text_start,
+ unsigned int file_sz) {}
+static inline void efi_stub_defaults(void) {}
+static inline void efi_stub_entry_update(void) {}
+
+static inline int reserve_pecoff_reloc_section(int c)
+{
+ return 0;
+}
#endif /* CONFIG_EFI_STUB */
@@ -250,7 +297,8 @@ static void parse_zoffset(char *fname)
p = (char *)buf;
while (p && *p) {
- PARSE_ZOFS(p, efi_stub_entry);
+ PARSE_ZOFS(p, efi32_stub_entry);
+ PARSE_ZOFS(p, efi64_stub_entry);
PARSE_ZOFS(p, efi_pe_entry);
PARSE_ZOFS(p, startup_64);
@@ -271,15 +319,7 @@ int main(int argc, char ** argv)
void *kernel;
u32 crc = 0xffffffffUL;
- /* Defaults for old kernel */
-#ifdef CONFIG_X86_32
- efi_pe_entry = 0x10;
- efi_stub_entry = 0x30;
-#else
- efi_pe_entry = 0x210;
- efi_stub_entry = 0x230;
- startup_64 = 0x200;
-#endif
+ efi_stub_defaults();
if (argc != 5)
usage();
@@ -302,11 +342,7 @@ int main(int argc, char ** argv)
die("Boot block hasn't got boot flag (0xAA55)");
fclose(file);
-#ifdef CONFIG_EFI_STUB
- /* Reserve 0x20 bytes for .reloc section */
- memset(buf+c, 0, PECOFF_RELOC_RESERVE);
- c += PECOFF_RELOC_RESERVE;
-#endif
+ c += reserve_pecoff_reloc_section(c);
/* Pad unused space with zeros */
setup_sectors = (c + 511) / 512;
@@ -315,9 +351,7 @@ int main(int argc, char ** argv)
i = setup_sectors*512;
memset(buf+c, 0, i-c);
-#ifdef CONFIG_EFI_STUB
update_pecoff_setup_and_reloc(i);
-#endif
/* Set the default root device */
put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
@@ -342,14 +376,9 @@ int main(int argc, char ** argv)
buf[0x1f1] = setup_sectors-1;
put_unaligned_le32(sys_size, &buf[0x1f4]);
-#ifdef CONFIG_EFI_STUB
update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz));
-#ifdef CONFIG_X86_64 /* Yes, this is really how we defined it :( */
- efi_stub_entry -= 0x200;
-#endif
- put_unaligned_le32(efi_stub_entry, &buf[0x264]);
-#endif
+ efi_stub_entry_update();
crc = partial_crc32(buf, i, crc);
if (fwrite(buf, 1, i, dest) != i)
diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c
index 11e8c6eb80a1..ba3e100654db 100644
--- a/arch/x86/boot/video-vesa.c
+++ b/arch/x86/boot/video-vesa.c
@@ -16,6 +16,7 @@
#include "boot.h"
#include "video.h"
#include "vesa.h"
+#include "string.h"
/* VESA information */
static struct vesa_general_info vginfo;
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index a7fef2621cc9..619e7f7426c6 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -60,7 +60,6 @@ CONFIG_CRASH_DUMP=y
CONFIG_HIBERNATION=y
CONFIG_PM_DEBUG=y
CONFIG_PM_TRACE_RTC=y
-CONFIG_ACPI_PROCFS=y
CONFIG_ACPI_DOCK=y
CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index c1119d4c1281..6181c69b786b 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -58,7 +58,6 @@ CONFIG_CRASH_DUMP=y
CONFIG_HIBERNATION=y
CONFIG_PM_DEBUG=y
CONFIG_PM_TRACE_RTC=y
-CONFIG_ACPI_PROCFS=y
CONFIG_ACPI_DOCK=y
CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
diff --git a/arch/x86/include/asm/Kbuild b/arch/x86/include/asm/Kbuild
index 7f669853317a..4acddc43ee0c 100644
--- a/arch/x86/include/asm/Kbuild
+++ b/arch/x86/include/asm/Kbuild
@@ -5,3 +5,5 @@ genhdr-y += unistd_64.h
genhdr-y += unistd_x32.h
generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += mcs_spinlock.h
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 1d2091a226bc..19b0ebafcd3e 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -93,9 +93,6 @@ static inline int is_vsmp_box(void)
return 0;
}
#endif
-extern void xapic_wait_icr_idle(void);
-extern u32 safe_xapic_wait_icr_idle(void);
-extern void xapic_icr_write(u32, u32);
extern int setup_profiling_timer(unsigned int);
static inline void native_apic_mem_write(u32 reg, u32 v)
@@ -184,7 +181,6 @@ extern int x2apic_phys;
extern int x2apic_preenabled;
extern void check_x2apic(void);
extern void enable_x2apic(void);
-extern void x2apic_icr_write(u32 low, u32 id);
static inline int x2apic_enabled(void)
{
u64 msr;
@@ -221,7 +217,6 @@ static inline void x2apic_force_phys(void)
{
}
-#define nox2apic 0
#define x2apic_preenabled 0
#define x2apic_supported() 0
#endif
@@ -351,7 +346,7 @@ struct apic {
int trampoline_phys_low;
int trampoline_phys_high;
- void (*wait_for_init_deassert)(atomic_t *deassert);
+ bool wait_for_init_deassert;
void (*smp_callin_clear_local_apic)(void);
void (*inquire_remote_apic)(int apicid);
@@ -517,13 +512,6 @@ extern int default_cpu_present_to_apicid(int mps_cpu);
extern int default_check_phys_apicid_present(int phys_apicid);
#endif
-static inline void default_wait_for_init_deassert(atomic_t *deassert)
-{
- while (!atomic_read(deassert))
- cpu_relax();
- return;
-}
-
extern void generic_bigsmp_probe(void);
diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h
index 04a48903b2eb..69bbb4845020 100644
--- a/arch/x86/include/asm/barrier.h
+++ b/arch/x86/include/asm/barrier.h
@@ -85,11 +85,7 @@
#else
# define smp_rmb() barrier()
#endif
-#ifdef CONFIG_X86_OOSTORE
-# define smp_wmb() wmb()
-#else
-# define smp_wmb() barrier()
-#endif
+#define smp_wmb() barrier()
#define smp_read_barrier_depends() read_barrier_depends()
#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
#else /* !SMP */
@@ -100,7 +96,7 @@
#define set_mb(var, value) do { var = value; barrier(); } while (0)
#endif /* SMP */
-#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
+#if defined(CONFIG_X86_PPRO_FENCE)
/*
* For either of these options x86 doesn't have a strong TSO memory
diff --git a/arch/x86/include/asm/clocksource.h b/arch/x86/include/asm/clocksource.h
index 16a57f4ed64d..eda81dc0f4ae 100644
--- a/arch/x86/include/asm/clocksource.h
+++ b/arch/x86/include/asm/clocksource.h
@@ -3,8 +3,6 @@
#ifndef _ASM_X86_CLOCKSOURCE_H
#define _ASM_X86_CLOCKSOURCE_H
-#ifdef CONFIG_X86_64
-
#define VCLOCK_NONE 0 /* No vDSO clock available. */
#define VCLOCK_TSC 1 /* vDSO should use vread_tsc. */
#define VCLOCK_HPET 2 /* vDSO should use vread_hpet. */
@@ -14,6 +12,4 @@ struct arch_clocksource_data {
int vclock_mode;
};
-#endif /* CONFIG_X86_64 */
-
#endif /* _ASM_X86_CLOCKSOURCE_H */
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index e099f9502ace..e265ff95d16d 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -37,7 +37,7 @@
#define X86_FEATURE_PAT (0*32+16) /* Page Attribute Table */
#define X86_FEATURE_PSE36 (0*32+17) /* 36-bit PSEs */
#define X86_FEATURE_PN (0*32+18) /* Processor serial number */
-#define X86_FEATURE_CLFLSH (0*32+19) /* "clflush" CLFLUSH instruction */
+#define X86_FEATURE_CLFLUSH (0*32+19) /* CLFLUSH instruction */
#define X86_FEATURE_DS (0*32+21) /* "dts" Debug Store */
#define X86_FEATURE_ACPI (0*32+22) /* ACPI via MSR */
#define X86_FEATURE_MMX (0*32+23) /* Multimedia Extensions */
@@ -217,9 +217,14 @@
#define X86_FEATURE_INVPCID (9*32+10) /* Invalidate Processor Context ID */
#define X86_FEATURE_RTM (9*32+11) /* Restricted Transactional Memory */
#define X86_FEATURE_MPX (9*32+14) /* Memory Protection Extension */
+#define X86_FEATURE_AVX512F (9*32+16) /* AVX-512 Foundation */
#define X86_FEATURE_RDSEED (9*32+18) /* The RDSEED instruction */
#define X86_FEATURE_ADX (9*32+19) /* The ADCX and ADOX instructions */
#define X86_FEATURE_SMAP (9*32+20) /* Supervisor Mode Access Prevention */
+#define X86_FEATURE_CLFLUSHOPT (9*32+23) /* CLFLUSHOPT instruction */
+#define X86_FEATURE_AVX512PF (9*32+26) /* AVX-512 Prefetch */
+#define X86_FEATURE_AVX512ER (9*32+27) /* AVX-512 Exponential and Reciprocal */
+#define X86_FEATURE_AVX512CD (9*32+28) /* AVX-512 Conflict Detection */
/*
* BUG word(s)
@@ -313,7 +318,7 @@ extern const char * const x86_power_flags[32];
#define cpu_has_pmm_enabled boot_cpu_has(X86_FEATURE_PMM_EN)
#define cpu_has_ds boot_cpu_has(X86_FEATURE_DS)
#define cpu_has_pebs boot_cpu_has(X86_FEATURE_PEBS)
-#define cpu_has_clflush boot_cpu_has(X86_FEATURE_CLFLSH)
+#define cpu_has_clflush boot_cpu_has(X86_FEATURE_CLFLUSH)
#define cpu_has_bts boot_cpu_has(X86_FEATURE_BTS)
#define cpu_has_gbpages boot_cpu_has(X86_FEATURE_GBPAGES)
#define cpu_has_arch_perfmon boot_cpu_has(X86_FEATURE_ARCH_PERFMON)
@@ -541,6 +546,13 @@ static __always_inline __pure bool _static_cpu_has_safe(u16 bit)
#define static_cpu_has_bug(bit) static_cpu_has((bit))
#define boot_cpu_has_bug(bit) cpu_has_bug(&boot_cpu_data, (bit))
+#define MAX_CPU_FEATURES (NCAPINTS * 32)
+#define cpu_have_feature boot_cpu_has
+
+#define CPU_FEATURE_TYPEFMT "x86,ven%04Xfam%04Xmod%04X"
+#define CPU_FEATURE_TYPEVAL boot_cpu_data.x86_vendor, boot_cpu_data.x86, \
+ boot_cpu_data.x86_model
+
#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
#endif /* _ASM_X86_CPUFEATURE_H */
diff --git a/arch/x86/include/asm/cputime.h b/arch/x86/include/asm/cputime.h
deleted file mode 100644
index 6d68ad7e0ea3..000000000000
--- a/arch/x86/include/asm/cputime.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/cputime.h>
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 3d6b9f81cc68..0869434eaf72 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -19,9 +19,11 @@
*/
#define EFI_OLD_MEMMAP EFI_ARCH_1
+#define EFI32_LOADER_SIGNATURE "EL32"
+#define EFI64_LOADER_SIGNATURE "EL64"
+
#ifdef CONFIG_X86_32
-#define EFI_LOADER_SIGNATURE "EL32"
extern unsigned long asmlinkage efi_call_phys(void *, ...);
@@ -57,8 +59,6 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...);
#else /* !CONFIG_X86_32 */
-#define EFI_LOADER_SIGNATURE "EL64"
-
extern u64 efi_call0(void *fp);
extern u64 efi_call1(void *fp, u64 arg1);
extern u64 efi_call2(void *fp, u64 arg1, u64 arg2);
@@ -119,7 +119,6 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
#endif /* CONFIG_X86_32 */
extern int add_efi_memmap;
-extern unsigned long x86_efi_facility;
extern struct efi_scratch efi_scratch;
extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
extern int efi_memblock_x86_reserve_range(void);
@@ -130,10 +129,13 @@ extern void efi_memory_uc(u64 addr, unsigned long size);
extern void __init efi_map_region(efi_memory_desc_t *md);
extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
extern void efi_sync_low_kernel_mappings(void);
-extern void efi_setup_page_tables(void);
+extern int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages);
+extern void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages);
extern void __init old_map_region(efi_memory_desc_t *md);
extern void __init runtime_code_page_mkexec(void);
extern void __init efi_runtime_mkexec(void);
+extern void __init efi_dump_pagetable(void);
+extern void __init efi_apply_memmap_quirks(void);
struct efi_setup_data {
u64 fw_vendor;
@@ -152,8 +154,40 @@ static inline bool efi_is_native(void)
return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT);
}
+static inline bool efi_runtime_supported(void)
+{
+ if (efi_is_native())
+ return true;
+
+ if (IS_ENABLED(CONFIG_EFI_MIXED) && !efi_enabled(EFI_OLD_MEMMAP))
+ return true;
+
+ return false;
+}
+
extern struct console early_efi_console;
extern void parse_efi_setup(u64 phys_addr, u32 data_len);
+
+#ifdef CONFIG_EFI_MIXED
+extern void efi_thunk_runtime_setup(void);
+extern efi_status_t efi_thunk_set_virtual_address_map(
+ void *phys_set_virtual_address_map,
+ unsigned long memory_map_size,
+ unsigned long descriptor_size,
+ u32 descriptor_version,
+ efi_memory_desc_t *virtual_map);
+#else
+static inline void efi_thunk_runtime_setup(void) {}
+static inline efi_status_t efi_thunk_set_virtual_address_map(
+ void *phys_set_virtual_address_map,
+ unsigned long memory_map_size,
+ unsigned long descriptor_size,
+ u32 descriptor_version,
+ efi_memory_desc_t *virtual_map)
+{
+ return EFI_SUCCESS;
+}
+#endif /* CONFIG_EFI_MIXED */
#else
/*
* IF EFI is not configured, have the EFI calls return -ENOSYS.
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index 9c999c1674fa..2c71182d30ef 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -281,16 +281,12 @@ do { \
#define STACK_RND_MASK (0x7ff)
-#define VDSO_HIGH_BASE (__fix_to_virt(FIX_VDSO))
-
#define ARCH_DLINFO ARCH_DLINFO_IA32(vdso_enabled)
/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
#else /* CONFIG_X86_32 */
-#define VDSO_HIGH_BASE 0xffffe000U /* CONFIG_COMPAT_VDSO address */
-
/* 1GB for 64bit, 8MB for 32bit */
#define STACK_RND_MASK (test_thread_flag(TIF_ADDR32) ? 0x7ff : 0x3fffff)
diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h
index 7252cd339175..8dcd35c4c787 100644
--- a/arch/x86/include/asm/fixmap.h
+++ b/arch/x86/include/asm/fixmap.h
@@ -40,15 +40,8 @@
*/
extern unsigned long __FIXADDR_TOP;
#define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP)
-
-#define FIXADDR_USER_START __fix_to_virt(FIX_VDSO)
-#define FIXADDR_USER_END __fix_to_virt(FIX_VDSO - 1)
#else
#define FIXADDR_TOP (VSYSCALL_END-PAGE_SIZE)
-
-/* Only covers 32bit vsyscalls currently. Need another set for 64bit. */
-#define FIXADDR_USER_START ((unsigned long)VSYSCALL32_VSYSCALL)
-#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE)
#endif
@@ -74,7 +67,6 @@ extern unsigned long __FIXADDR_TOP;
enum fixed_addresses {
#ifdef CONFIG_X86_32
FIX_HOLE,
- FIX_VDSO,
#else
VSYSCALL_LAST_PAGE,
VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE
@@ -98,12 +90,6 @@ enum fixed_addresses {
FIX_IO_APIC_BASE_0,
FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS - 1,
#endif
-#ifdef CONFIG_X86_VISWS_APIC
- FIX_CO_CPU, /* Cobalt timer */
- FIX_CO_APIC, /* Cobalt APIC Redirection Table */
- FIX_LI_PCIA, /* Lithium PCI Bridge A */
- FIX_LI_PCIB, /* Lithium PCI Bridge B */
-#endif
FIX_RO_IDT, /* Virtual mapping for read-only IDT */
#ifdef CONFIG_X86_32
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
diff --git a/arch/x86/include/asm/floppy.h b/arch/x86/include/asm/floppy.h
index d3d74698dce9..1c7eefe32502 100644
--- a/arch/x86/include/asm/floppy.h
+++ b/arch/x86/include/asm/floppy.h
@@ -145,10 +145,10 @@ static int fd_request_irq(void)
{
if (can_use_virtual_dma)
return request_irq(FLOPPY_IRQ, floppy_hardint,
- IRQF_DISABLED, "floppy", NULL);
+ 0, "floppy", NULL);
else
return request_irq(FLOPPY_IRQ, floppy_interrupt,
- IRQF_DISABLED, "floppy", NULL);
+ 0, "floppy", NULL);
}
static unsigned long dma_mem_alloc(unsigned long size)
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index ab0ae1aa6d0a..230853da4ec0 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -33,6 +33,9 @@ typedef struct {
#ifdef CONFIG_X86_MCE_THRESHOLD
unsigned int irq_threshold_count;
#endif
+#if IS_ENABLED(CONFIG_HYPERV) || defined(CONFIG_XEN)
+ unsigned int irq_hv_callback_count;
+#endif
} ____cacheline_aligned irq_cpustat_t;
DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index 67d69b8e2d20..a307b7530e54 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -98,7 +98,6 @@ extern void trace_call_function_single_interrupt(void);
#define IO_APIC_IRQ(x) (((x) >= NR_IRQS_LEGACY) || ((1<<(x)) & io_apic_irqs))
extern unsigned long io_apic_irqs;
-extern void init_VISWS_APIC_irqs(void);
extern void setup_IO_APIC(void);
extern void disable_IO_APIC(void);
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index 34f69cb9350a..91d9c69a629e 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -237,7 +237,7 @@ memcpy_toio(volatile void __iomem *dst, const void *src, size_t count)
static inline void flush_write_buffers(void)
{
-#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
+#if defined(CONFIG_X86_PPRO_FENCE)
asm volatile("lock; addl $0,0(%%esp)": : :"memory");
#endif
}
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index fdf83afbb7d9..fcaf9c961265 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -337,6 +337,11 @@ struct kvm_pmu {
u64 reprogram_pmi;
};
+enum {
+ KVM_DEBUGREG_BP_ENABLED = 1,
+ KVM_DEBUGREG_WONT_EXIT = 2,
+};
+
struct kvm_vcpu_arch {
/*
* rip and regs accesses must go through
@@ -444,7 +449,6 @@ struct kvm_vcpu_arch {
} st;
u64 last_guest_tsc;
- u64 last_kernel_ns;
u64 last_host_tsc;
u64 tsc_offset_adjustment;
u64 this_tsc_nsec;
@@ -464,7 +468,7 @@ struct kvm_vcpu_arch {
struct mtrr_state_type mtrr_state;
u32 pat;
- int switch_db_regs;
+ unsigned switch_db_regs;
unsigned long db[KVM_NR_DB_REGS];
unsigned long dr6;
unsigned long dr7;
@@ -599,6 +603,8 @@ struct kvm_arch {
bool use_master_clock;
u64 master_kernel_ns;
cycle_t master_cycle_now;
+ struct delayed_work kvmclock_update_work;
+ struct delayed_work kvmclock_sync_work;
struct kvm_xen_hvm_config xen_hvm_config;
@@ -702,6 +708,7 @@ struct kvm_x86_ops {
void (*set_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
u64 (*get_dr6)(struct kvm_vcpu *vcpu);
void (*set_dr6)(struct kvm_vcpu *vcpu, unsigned long value);
+ void (*sync_dirty_debug_regs)(struct kvm_vcpu *vcpu);
void (*set_dr7)(struct kvm_vcpu *vcpu, unsigned long value);
void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg);
unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
@@ -728,8 +735,8 @@ struct kvm_x86_ops {
int (*nmi_allowed)(struct kvm_vcpu *vcpu);
bool (*get_nmi_mask)(struct kvm_vcpu *vcpu);
void (*set_nmi_mask)(struct kvm_vcpu *vcpu, bool masked);
- int (*enable_nmi_window)(struct kvm_vcpu *vcpu);
- int (*enable_irq_window)(struct kvm_vcpu *vcpu);
+ void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
+ void (*enable_irq_window)(struct kvm_vcpu *vcpu);
void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
int (*vm_has_apicv)(struct kvm *kvm);
void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
@@ -765,6 +772,9 @@ struct kvm_x86_ops {
struct x86_instruction_info *info,
enum x86_intercept_stage stage);
void (*handle_external_intr)(struct kvm_vcpu *vcpu);
+ bool (*mpx_supported)(void);
+
+ int (*check_nested_events)(struct kvm_vcpu *vcpu, bool external_intr);
};
struct kvm_arch_async_pf {
diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h
index 8a9b3e288cb4..1ec990bd7dc0 100644
--- a/arch/x86/include/asm/mmzone_32.h
+++ b/arch/x86/include/asm/mmzone_32.h
@@ -11,9 +11,6 @@
#ifdef CONFIG_NUMA
extern struct pglist_data *node_data[];
#define NODE_DATA(nid) (node_data[nid])
-
-#include <asm/numaq.h>
-
#endif /* CONFIG_NUMA */
#ifdef CONFIG_DISCONTIGMEM
diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h
index 3e6b4920ef5d..f5a617956735 100644
--- a/arch/x86/include/asm/mpspec.h
+++ b/arch/x86/include/asm/mpspec.h
@@ -25,12 +25,6 @@ extern int pic_mode;
extern unsigned int def_to_bigsmp;
-#ifdef CONFIG_X86_NUMAQ
-extern int mp_bus_id_to_node[MAX_MP_BUSSES];
-extern int mp_bus_id_to_local[MAX_MP_BUSSES];
-extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
-#endif
-
#else /* CONFIG_X86_64: */
#define MAX_MP_BUSSES 256
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
index cd9c41938b8a..c163215abb9a 100644
--- a/arch/x86/include/asm/mshyperv.h
+++ b/arch/x86/include/asm/mshyperv.h
@@ -2,6 +2,7 @@
#define _ASM_X86_MSHYPER_H
#include <linux/types.h>
+#include <linux/interrupt.h>
#include <asm/hyperv.h>
struct ms_hyperv_info {
@@ -16,6 +17,7 @@ void hyperv_callback_vector(void);
#define trace_hyperv_callback_vector hyperv_callback_vector
#endif
void hyperv_vector_handler(struct pt_regs *regs);
-void hv_register_vmbus_handler(int irq, irq_handler_t handler);
+void hv_setup_vmbus_irq(void (*handler)(void));
+void hv_remove_vmbus_irq(void);
#endif
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index e139b13f2a33..de36f22eb0b9 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -214,6 +214,8 @@ do { \
struct msr *msrs_alloc(void);
void msrs_free(struct msr *msrs);
+int msr_set_bit(u32 msr, u8 bit);
+int msr_clear_bit(u32 msr, u8 bit);
#ifdef CONFIG_SMP
int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h
index 86f9301903c8..5f2fc4441b11 100644
--- a/arch/x86/include/asm/nmi.h
+++ b/arch/x86/include/asm/nmi.h
@@ -1,6 +1,7 @@
#ifndef _ASM_X86_NMI_H
#define _ASM_X86_NMI_H
+#include <linux/irq_work.h>
#include <linux/pm.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -38,6 +39,8 @@ typedef int (*nmi_handler_t)(unsigned int, struct pt_regs *);
struct nmiaction {
struct list_head list;
nmi_handler_t handler;
+ u64 max_duration;
+ struct irq_work irq_work;
unsigned long flags;
const char *name;
};
diff --git a/arch/x86/include/asm/numaq.h b/arch/x86/include/asm/numaq.h
deleted file mode 100644
index c3b3c322fd87..000000000000
--- a/arch/x86/include/asm/numaq.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Written by: Patricia Gaughen, IBM Corporation
- *
- * Copyright (C) 2002, IBM Corp.
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to <gone@us.ibm.com>
- */
-
-#ifndef _ASM_X86_NUMAQ_H
-#define _ASM_X86_NUMAQ_H
-
-#ifdef CONFIG_X86_NUMAQ
-
-extern int found_numaq;
-extern int numaq_numa_init(void);
-extern int pci_numaq_init(void);
-
-extern void *xquad_portio;
-
-#define XQUAD_PORTIO_BASE 0xfe400000
-#define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */
-#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)
-
-/*
- * SYS_CFG_DATA_PRIV_ADDR, struct eachquadmem, and struct sys_cfg_data are the
- */
-#define SYS_CFG_DATA_PRIV_ADDR 0x0009d000 /* place for scd in private
- quad space */
-
-/*
- * Communication area for each processor on lynxer-processor tests.
- *
- * NOTE: If you change the size of this eachproc structure you need
- * to change the definition for EACH_QUAD_SIZE.
- */
-struct eachquadmem {
- unsigned int priv_mem_start; /* Starting address of this */
- /* quad's private memory. */
- /* This is always 0. */
- /* In MB. */
- unsigned int priv_mem_size; /* Size of this quad's */
- /* private memory. */
- /* In MB. */
- unsigned int low_shrd_mem_strp_start;/* Starting address of this */
- /* quad's low shared block */
- /* (untranslated). */
- /* In MB. */
- unsigned int low_shrd_mem_start; /* Starting address of this */
- /* quad's low shared memory */
- /* (untranslated). */
- /* In MB. */
- unsigned int low_shrd_mem_size; /* Size of this quad's low */
- /* shared memory. */
- /* In MB. */
- unsigned int lmmio_copb_start; /* Starting address of this */
- /* quad's local memory */
- /* mapped I/O in the */
- /* compatibility OPB. */
- /* In MB. */
- unsigned int lmmio_copb_size; /* Size of this quad's local */
- /* memory mapped I/O in the */
- /* compatibility OPB. */
- /* In MB. */
- unsigned int lmmio_nopb_start; /* Starting address of this */
- /* quad's local memory */
- /* mapped I/O in the */
- /* non-compatibility OPB. */
- /* In MB. */
- unsigned int lmmio_nopb_size; /* Size of this quad's local */
- /* memory mapped I/O in the */
- /* non-compatibility OPB. */
- /* In MB. */
- unsigned int io_apic_0_start; /* Starting address of I/O */
- /* APIC 0. */
- unsigned int io_apic_0_sz; /* Size I/O APIC 0. */
- unsigned int io_apic_1_start; /* Starting address of I/O */
- /* APIC 1. */
- unsigned int io_apic_1_sz; /* Size I/O APIC 1. */
- unsigned int hi_shrd_mem_start; /* Starting address of this */
- /* quad's high shared memory.*/
- /* In MB. */
- unsigned int hi_shrd_mem_size; /* Size of this quad's high */
- /* shared memory. */
- /* In MB. */
- unsigned int mps_table_addr; /* Address of this quad's */
- /* MPS tables from BIOS, */
- /* in system space.*/
- unsigned int lcl_MDC_pio_addr; /* Port-I/O address for */
- /* local access of MDC. */
- unsigned int rmt_MDC_mmpio_addr; /* MM-Port-I/O address for */
- /* remote access of MDC. */
- unsigned int mm_port_io_start; /* Starting address of this */
- /* quad's memory mapped Port */
- /* I/O space. */
- unsigned int mm_port_io_size; /* Size of this quad's memory*/
- /* mapped Port I/O space. */
- unsigned int mm_rmt_io_apic_start; /* Starting address of this */
- /* quad's memory mapped */
- /* remote I/O APIC space. */
- unsigned int mm_rmt_io_apic_size; /* Size of this quad's memory*/
- /* mapped remote I/O APIC */
- /* space. */
- unsigned int mm_isa_start; /* Starting address of this */
- /* quad's memory mapped ISA */
- /* space (contains MDC */
- /* memory space). */
- unsigned int mm_isa_size; /* Size of this quad's memory*/
- /* mapped ISA space (contains*/
- /* MDC memory space). */
- unsigned int rmt_qmi_addr; /* Remote addr to access QMI.*/
- unsigned int lcl_qmi_addr; /* Local addr to access QMI. */
-};
-
-/*
- * Note: This structure must be NOT be changed unless the multiproc and
- * OS are changed to reflect the new structure.
- */
-struct sys_cfg_data {
- unsigned int quad_id;
- unsigned int bsp_proc_id; /* Boot Strap Processor in this quad. */
- unsigned int scd_version; /* Version number of this table. */
- unsigned int first_quad_id;
- unsigned int quads_present31_0; /* 1 bit for each quad */
- unsigned int quads_present63_32; /* 1 bit for each quad */
- unsigned int config_flags;
- unsigned int boot_flags;
- unsigned int csr_start_addr; /* Absolute value (not in MB) */
- unsigned int csr_size; /* Absolute value (not in MB) */
- unsigned int lcl_apic_start_addr; /* Absolute value (not in MB) */
- unsigned int lcl_apic_size; /* Absolute value (not in MB) */
- unsigned int low_shrd_mem_base; /* 0 or 512MB or 1GB */
- unsigned int low_shrd_mem_quad_offset; /* 0,128M,256M,512M,1G */
- /* may not be totally populated */
- unsigned int split_mem_enbl; /* 0 for no low shared memory */
- unsigned int mmio_sz; /* Size of total system memory mapped I/O */
- /* (in MB). */
- unsigned int quad_spin_lock; /* Spare location used for quad */
- /* bringup. */
- unsigned int nonzero55; /* For checksumming. */
- unsigned int nonzeroaa; /* For checksumming. */
- unsigned int scd_magic_number;
- unsigned int system_type;
- unsigned int checksum;
- /*
- * memory configuration area for each quad
- */
- struct eachquadmem eq[MAX_NUMNODES]; /* indexed by quad id */
-};
-
-void numaq_tsc_disable(void);
-
-#endif /* CONFIG_X86_NUMAQ */
-#endif /* _ASM_X86_NUMAQ_H */
-
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 1ac6114c9ea5..96ae4f4040bb 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -26,11 +26,6 @@ extern int pci_routeirq;
extern int noioapicquirk;
extern int noioapicreroute;
-/* scan a bus after allocating a pci_sysdata for it */
-extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops,
- int node);
-extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
-
#ifdef CONFIG_PCI
#ifdef CONFIG_PCI_DOMAINS
@@ -70,7 +65,7 @@ extern unsigned long pci_mem_start;
extern int pcibios_enabled;
void pcibios_config_init(void);
-struct pci_bus *pcibios_scan_root(int bus);
+void pcibios_scan_root(int bus);
void pcibios_set_master(struct pci_dev *dev);
void pcibios_penalize_isa_irq(int irq, int active);
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 5ad38ad07890..b459ddf27d64 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -15,9 +15,10 @@
: (prot))
#ifndef __ASSEMBLY__
-
#include <asm/x86_init.h>
+void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd);
+
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
@@ -445,20 +446,10 @@ static inline int pte_same(pte_t a, pte_t b)
return a.pte == b.pte;
}
-static inline int pteval_present(pteval_t pteval)
-{
- /*
- * Yes Linus, _PAGE_PROTNONE == _PAGE_NUMA. Expressing it this
- * way clearly states that the intent is that protnone and numa
- * hinting ptes are considered present for the purposes of
- * pagetable operations like zapping, protection changes, gup etc.
- */
- return pteval & (_PAGE_PRESENT | _PAGE_PROTNONE | _PAGE_NUMA);
-}
-
static inline int pte_present(pte_t a)
{
- return pteval_present(pte_flags(a));
+ return pte_flags(a) & (_PAGE_PRESENT | _PAGE_PROTNONE |
+ _PAGE_NUMA);
}
#define pte_accessible pte_accessible
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index 1aa9ccd43223..eb3d44945133 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -214,13 +214,8 @@
#ifdef CONFIG_X86_64
#define __PAGE_KERNEL_IDENT_LARGE_EXEC __PAGE_KERNEL_LARGE_EXEC
#else
-/*
- * For PDE_IDENT_ATTR include USER bit. As the PDE and PTE protection
- * bits are combined, this will alow user to access the high address mapped
- * VDSO in the presence of CONFIG_COMPAT_VDSO
- */
#define PTE_IDENT_ATTR 0x003 /* PRESENT+RW */
-#define PDE_IDENT_ATTR 0x067 /* PRESENT+RW+USER+DIRTY+ACCESSED */
+#define PDE_IDENT_ATTR 0x063 /* PRESENT+RW+DIRTY+ACCESSED */
#define PGD_IDENT_ATTR 0x001 /* PRESENT (no other attributes) */
#endif
@@ -382,9 +377,13 @@ static inline void update_page_count(int level, unsigned long pages) { }
* as a pte too.
*/
extern pte_t *lookup_address(unsigned long address, unsigned int *level);
+extern pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
+ unsigned int *level);
extern phys_addr_t slow_virt_to_phys(void *__address);
extern int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
unsigned numpages, unsigned long page_flags);
+void kernel_unmap_pages_in_pgd(pgd_t *root, unsigned long address,
+ unsigned numpages);
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_X86_PGTABLE_DEFS_H */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index fdedd38fd0fc..a4ea02351f4d 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -449,6 +449,15 @@ struct stack_canary {
};
DECLARE_PER_CPU_ALIGNED(struct stack_canary, stack_canary);
#endif
+/*
+ * per-CPU IRQ handling stacks
+ */
+struct irq_stack {
+ u32 stack[THREAD_SIZE/sizeof(u32)];
+} __aligned(THREAD_SIZE);
+
+DECLARE_PER_CPU(struct irq_stack *, hardirq_stack);
+DECLARE_PER_CPU(struct irq_stack *, softirq_stack);
#endif /* X86_64 */
extern unsigned int xstate_size;
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
index d62c9f809bc5..9264f04a4c55 100644
--- a/arch/x86/include/asm/setup.h
+++ b/arch/x86/include/asm/setup.h
@@ -39,12 +39,6 @@ static inline void vsmp_init(void) { }
void setup_bios_corruption_check(void);
-#ifdef CONFIG_X86_VISWS
-extern void visws_early_detect(void);
-#else
-static inline void visws_early_detect(void) { }
-#endif
-
extern unsigned long saved_video_mode;
extern void reserve_standard_io_resources(void);
diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h
index 645cad2c95ff..e820c080a4e9 100644
--- a/arch/x86/include/asm/special_insns.h
+++ b/arch/x86/include/asm/special_insns.h
@@ -191,6 +191,14 @@ static inline void clflush(volatile void *__p)
asm volatile("clflush %0" : "+m" (*(volatile char __force *)__p));
}
+static inline void clflushopt(volatile void *__p)
+{
+ alternative_io(".byte " __stringify(NOP_DS_PREFIX) "; clflush %P0",
+ ".byte 0x66; clflush %P0",
+ X86_FEATURE_CLFLUSHOPT,
+ "+m" (*(volatile char __force *)__p));
+}
+
#define nop() asm volatile ("nop")
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index bf156ded74b5..0f62f5482d91 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -26,10 +26,9 @@
# define LOCK_PTR_REG "D"
#endif
-#if defined(CONFIG_X86_32) && \
- (defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE))
+#if defined(CONFIG_X86_32) && (defined(CONFIG_X86_PPRO_FENCE))
/*
- * On PPro SMP or if we are using OOSTORE, we use a locked operation to unlock
+ * On PPro SMP, we use a locked operation to unlock
* (PPro errata 66, 92)
*/
# define UNLOCK_LOCK_PREFIX LOCK_PREFIX
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index e1940c06ed02..47e5de25ba79 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -9,6 +9,7 @@
#include <linux/compiler.h>
#include <asm/page.h>
+#include <asm/percpu.h>
#include <asm/types.h>
/*
@@ -32,12 +33,6 @@ struct thread_info {
mm_segment_t addr_limit;
struct restart_block restart_block;
void __user *sysenter_return;
-#ifdef CONFIG_X86_32
- unsigned long previous_esp; /* ESP of the previous stack in
- case of nested (IRQ) stacks
- */
- __u8 supervisor_stack[0];
-#endif
unsigned int sig_on_uaccess_error:1;
unsigned int uaccess_err:1; /* uaccess failed */
};
@@ -153,9 +148,9 @@ struct thread_info {
#define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY)
#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW)
-#ifdef CONFIG_X86_32
+#define STACK_WARN (THREAD_SIZE/8)
+#define KERNEL_STACK_OFFSET (5*(BITS_PER_LONG/8))
-#define STACK_WARN (THREAD_SIZE/8)
/*
* macros/functions for gaining access to the thread information structure
*
@@ -163,42 +158,6 @@ struct thread_info {
*/
#ifndef __ASSEMBLY__
-#define current_stack_pointer ({ \
- unsigned long sp; \
- asm("mov %%esp,%0" : "=g" (sp)); \
- sp; \
-})
-
-/* how to get the thread information struct from C */
-static inline struct thread_info *current_thread_info(void)
-{
- return (struct thread_info *)
- (current_stack_pointer & ~(THREAD_SIZE - 1));
-}
-
-#else /* !__ASSEMBLY__ */
-
-/* how to get the thread information struct from ASM */
-#define GET_THREAD_INFO(reg) \
- movl $-THREAD_SIZE, reg; \
- andl %esp, reg
-
-/* use this one if reg already contains %esp */
-#define GET_THREAD_INFO_WITH_ESP(reg) \
- andl $-THREAD_SIZE, reg
-
-#endif
-
-#else /* X86_32 */
-
-#include <asm/percpu.h>
-#define KERNEL_STACK_OFFSET (5*8)
-
-/*
- * macros/functions for gaining access to the thread information structure
- * preempt_count needs to be 1 initially, until the scheduler is functional.
- */
-#ifndef __ASSEMBLY__
DECLARE_PER_CPU(unsigned long, kernel_stack);
static inline struct thread_info *current_thread_info(void)
@@ -213,8 +172,8 @@ static inline struct thread_info *current_thread_info(void)
/* how to get the thread information struct from ASM */
#define GET_THREAD_INFO(reg) \
- movq PER_CPU_VAR(kernel_stack),reg ; \
- subq $(THREAD_SIZE-KERNEL_STACK_OFFSET),reg
+ _ASM_MOV PER_CPU_VAR(kernel_stack),reg ; \
+ _ASM_SUB $(THREAD_SIZE-KERNEL_STACK_OFFSET),reg ;
/*
* Same if PER_CPU_VAR(kernel_stack) is, perhaps with some offset, already in
@@ -224,8 +183,6 @@ static inline struct thread_info *current_thread_info(void)
#endif
-#endif /* !X86_32 */
-
/*
* Thread-synchronous status.
*
diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index d35f24e231cd..0e8f04f2c26f 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -119,9 +119,10 @@ static inline void setup_node_to_cpumask_map(void) { }
extern const struct cpumask *cpu_coregroup_mask(int cpu);
-#ifdef ENABLE_TOPO_DEFINES
#define topology_physical_package_id(cpu) (cpu_data(cpu).phys_proc_id)
#define topology_core_id(cpu) (cpu_data(cpu).cpu_core_id)
+
+#ifdef ENABLE_TOPO_DEFINES
#define topology_core_cpumask(cpu) (per_cpu(cpu_core_map, cpu))
#define topology_thread_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu))
#endif
@@ -131,25 +132,7 @@ static inline void arch_fix_phys_package_id(int num, u32 slot)
}
struct pci_bus;
+int x86_pci_root_bus_node(int bus);
void x86_pci_root_bus_resources(int bus, struct list_head *resources);
-#ifdef CONFIG_SMP
-#define mc_capable() ((boot_cpu_data.x86_max_cores > 1) && \
- (cpumask_weight(cpu_core_mask(0)) != nr_cpu_ids))
-#define smt_capable() (smp_num_siblings > 1)
-#endif
-
-#ifdef CONFIG_NUMA
-extern int get_mp_bus_to_node(int busnum);
-extern void set_mp_bus_to_node(int busnum, int node);
-#else
-static inline int get_mp_bus_to_node(int busnum)
-{
- return 0;
-}
-static inline void set_mp_bus_to_node(int busnum, int node)
-{
-}
-#endif
-
#endif /* _ASM_X86_TOPOLOGY_H */
diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index 57ae63cd6ee2..94605c0e9cee 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -66,6 +66,6 @@ extern void tsc_save_sched_clock_state(void);
extern void tsc_restore_sched_clock_state(void);
/* MSR based TSC calibration for Intel Atom SoC platforms */
-int try_msr_calibrate_tsc(unsigned long *fast_calibrate);
+unsigned long try_msr_calibrate_tsc(void);
#endif /* _ASM_X86_TSC_H */
diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h
index c2a48139c340..3f556c6a0157 100644
--- a/arch/x86/include/asm/unistd.h
+++ b/arch/x86/include/asm/unistd.h
@@ -23,6 +23,9 @@
# include <asm/unistd_64.h>
# include <asm/unistd_64_x32.h>
# define __ARCH_WANT_COMPAT_SYS_TIME
+# define __ARCH_WANT_COMPAT_SYS_GETDENTS64
+# define __ARCH_WANT_COMPAT_SYS_PREADV64
+# define __ARCH_WANT_COMPAT_SYS_PWRITEV64
# endif
diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h
index fddb53d63915..d1dc55404ff1 100644
--- a/arch/x86/include/asm/vdso.h
+++ b/arch/x86/include/asm/vdso.h
@@ -1,8 +1,45 @@
#ifndef _ASM_X86_VDSO_H
#define _ASM_X86_VDSO_H
+#include <asm/page_types.h>
+#include <linux/linkage.h>
+
+#ifdef __ASSEMBLER__
+
+#define DEFINE_VDSO_IMAGE(symname, filename) \
+__PAGE_ALIGNED_DATA ; \
+ .globl symname##_start, symname##_end ; \
+ .align PAGE_SIZE ; \
+ symname##_start: ; \
+ .incbin filename ; \
+ symname##_end: ; \
+ .align PAGE_SIZE /* extra data here leaks to userspace. */ ; \
+ \
+.previous ; \
+ \
+ .globl symname##_pages ; \
+ .bss ; \
+ .align 8 ; \
+ .type symname##_pages, @object ; \
+ symname##_pages: ; \
+ .zero (symname##_end - symname##_start + PAGE_SIZE - 1) / PAGE_SIZE * (BITS_PER_LONG / 8) ; \
+ .size symname##_pages, .-symname##_pages
+
+#else
+
+#define DECLARE_VDSO_IMAGE(symname) \
+ extern char symname##_start[], symname##_end[]; \
+ extern struct page *symname##_pages[]
+
#if defined CONFIG_X86_32 || defined CONFIG_COMPAT
-extern const char VDSO32_PRELINK[];
+
+#include <asm/vdso32.h>
+
+DECLARE_VDSO_IMAGE(vdso32_int80);
+#ifdef CONFIG_COMPAT
+DECLARE_VDSO_IMAGE(vdso32_syscall);
+#endif
+DECLARE_VDSO_IMAGE(vdso32_sysenter);
/*
* Given a pointer to the vDSO image, find the pointer to VDSO32_name
@@ -11,8 +48,7 @@ extern const char VDSO32_PRELINK[];
#define VDSO32_SYMBOL(base, name) \
({ \
extern const char VDSO32_##name[]; \
- (void __user *)(VDSO32_##name - VDSO32_PRELINK + \
- (unsigned long)(base)); \
+ (void __user *)(VDSO32_##name + (unsigned long)(base)); \
})
#endif
@@ -23,12 +59,8 @@ extern const char VDSO32_PRELINK[];
extern void __user __kernel_sigreturn;
extern void __user __kernel_rt_sigreturn;
-/*
- * These symbols are defined by vdso32.S to mark the bounds
- * of the ELF DSO images included therein.
- */
-extern const char vdso32_int80_start, vdso32_int80_end;
-extern const char vdso32_syscall_start, vdso32_syscall_end;
-extern const char vdso32_sysenter_start, vdso32_sysenter_end;
+void __init patch_vdso32(void *vdso, size_t len);
+
+#endif /* __ASSEMBLER__ */
#endif /* _ASM_X86_VDSO_H */
diff --git a/arch/x86/include/asm/vdso32.h b/arch/x86/include/asm/vdso32.h
new file mode 100644
index 000000000000..7efb7018406e
--- /dev/null
+++ b/arch/x86/include/asm/vdso32.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_X86_VDSO32_H
+#define _ASM_X86_VDSO32_H
+
+#define VDSO_BASE_PAGE 0
+#define VDSO_VVAR_PAGE 1
+#define VDSO_HPET_PAGE 2
+#define VDSO_PAGES 3
+#define VDSO_PREV_PAGES 2
+#define VDSO_OFFSET(x) ((x) * PAGE_SIZE)
+
+#endif
diff --git a/arch/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h
index 46e24d36b7da..3c3366c2e37f 100644
--- a/arch/x86/include/asm/vgtod.h
+++ b/arch/x86/include/asm/vgtod.h
@@ -1,30 +1,73 @@
#ifndef _ASM_X86_VGTOD_H
#define _ASM_X86_VGTOD_H
-#include <asm/vsyscall.h>
+#include <linux/compiler.h>
#include <linux/clocksource.h>
+#ifdef BUILD_VDSO32_64
+typedef u64 gtod_long_t;
+#else
+typedef unsigned long gtod_long_t;
+#endif
+/*
+ * vsyscall_gtod_data will be accessed by 32 and 64 bit code at the same time
+ * so be carefull by modifying this structure.
+ */
struct vsyscall_gtod_data {
- seqcount_t seq;
+ unsigned seq;
- struct { /* extract of a clocksource struct */
- int vclock_mode;
- cycle_t cycle_last;
- cycle_t mask;
- u32 mult;
- u32 shift;
- } clock;
+ int vclock_mode;
+ cycle_t cycle_last;
+ cycle_t mask;
+ u32 mult;
+ u32 shift;
/* open coded 'struct timespec' */
- time_t wall_time_sec;
u64 wall_time_snsec;
+ gtod_long_t wall_time_sec;
+ gtod_long_t monotonic_time_sec;
u64 monotonic_time_snsec;
- time_t monotonic_time_sec;
+ gtod_long_t wall_time_coarse_sec;
+ gtod_long_t wall_time_coarse_nsec;
+ gtod_long_t monotonic_time_coarse_sec;
+ gtod_long_t monotonic_time_coarse_nsec;
- struct timezone sys_tz;
- struct timespec wall_time_coarse;
- struct timespec monotonic_time_coarse;
+ int tz_minuteswest;
+ int tz_dsttime;
};
extern struct vsyscall_gtod_data vsyscall_gtod_data;
+static inline unsigned gtod_read_begin(const struct vsyscall_gtod_data *s)
+{
+ unsigned ret;
+
+repeat:
+ ret = ACCESS_ONCE(s->seq);
+ if (unlikely(ret & 1)) {
+ cpu_relax();
+ goto repeat;
+ }
+ smp_rmb();
+ return ret;
+}
+
+static inline int gtod_read_retry(const struct vsyscall_gtod_data *s,
+ unsigned start)
+{
+ smp_rmb();
+ return unlikely(s->seq != start);
+}
+
+static inline void gtod_write_begin(struct vsyscall_gtod_data *s)
+{
+ ++s->seq;
+ smp_wmb();
+}
+
+static inline void gtod_write_end(struct vsyscall_gtod_data *s)
+{
+ smp_wmb();
+ ++s->seq;
+}
+
#endif /* _ASM_X86_VGTOD_H */
diff --git a/arch/x86/include/asm/visws/cobalt.h b/arch/x86/include/asm/visws/cobalt.h
deleted file mode 100644
index 2edb37637ead..000000000000
--- a/arch/x86/include/asm/visws/cobalt.h
+++ /dev/null
@@ -1,127 +0,0 @@
-#ifndef _ASM_X86_VISWS_COBALT_H
-#define _ASM_X86_VISWS_COBALT_H
-
-#include <asm/fixmap.h>
-
-/*
- * Cobalt SGI Visual Workstation system ASIC
- */
-
-#define CO_CPU_NUM_PHYS 0x1e00
-#define CO_CPU_TAB_PHYS (CO_CPU_NUM_PHYS + 2)
-
-#define CO_CPU_MAX 4
-
-#define CO_CPU_PHYS 0xc2000000
-#define CO_APIC_PHYS 0xc4000000
-
-/* see set_fixmap() and asm/fixmap.h */
-#define CO_CPU_VADDR (fix_to_virt(FIX_CO_CPU))
-#define CO_APIC_VADDR (fix_to_virt(FIX_CO_APIC))
-
-/* Cobalt CPU registers -- relative to CO_CPU_VADDR, use co_cpu_*() */
-#define CO_CPU_REV 0x08
-#define CO_CPU_CTRL 0x10
-#define CO_CPU_STAT 0x20
-#define CO_CPU_TIMEVAL 0x30
-
-/* CO_CPU_CTRL bits */
-#define CO_CTRL_TIMERUN 0x04 /* 0 == disabled */
-#define CO_CTRL_TIMEMASK 0x08 /* 0 == unmasked */
-
-/* CO_CPU_STATUS bits */
-#define CO_STAT_TIMEINTR 0x02 /* (r) 1 == int pend, (w) 0 == clear */
-
-/* CO_CPU_TIMEVAL value */
-#define CO_TIME_HZ 100000000 /* Cobalt core rate */
-
-/* Cobalt APIC registers -- relative to CO_APIC_VADDR, use co_apic_*() */
-#define CO_APIC_HI(n) (((n) * 0x10) + 4)
-#define CO_APIC_LO(n) ((n) * 0x10)
-#define CO_APIC_ID 0x0ffc
-
-/* CO_APIC_ID bits */
-#define CO_APIC_ENABLE 0x00000100
-
-/* CO_APIC_LO bits */
-#define CO_APIC_MASK 0x00010000 /* 0 = enabled */
-#define CO_APIC_LEVEL 0x00008000 /* 0 = edge */
-
-/*
- * Where things are physically wired to Cobalt
- * #defines with no board _<type>_<rev>_ are common to all (thus far)
- */
-#define CO_APIC_IDE0 4
-#define CO_APIC_IDE1 2 /* Only on 320 */
-
-#define CO_APIC_8259 12 /* serial, floppy, par-l-l */
-
-/* Lithium PCI Bridge A -- "the one with 82557 Ethernet" */
-#define CO_APIC_PCIA_BASE0 0 /* and 1 */ /* slot 0, line 0 */
-#define CO_APIC_PCIA_BASE123 5 /* and 6 */ /* slot 0, line 1 */
-
-#define CO_APIC_PIIX4_USB 7 /* this one is weird */
-
-/* Lithium PCI Bridge B -- "the one with PIIX4" */
-#define CO_APIC_PCIB_BASE0 8 /* and 9-12 *//* slot 0, line 0 */
-#define CO_APIC_PCIB_BASE123 13 /* 14.15 */ /* slot 0, line 1 */
-
-#define CO_APIC_VIDOUT0 16
-#define CO_APIC_VIDOUT1 17
-#define CO_APIC_VIDIN0 18
-#define CO_APIC_VIDIN1 19
-
-#define CO_APIC_LI_AUDIO 22
-
-#define CO_APIC_AS 24
-#define CO_APIC_RE 25
-
-#define CO_APIC_CPU 28 /* Timer and Cache interrupt */
-#define CO_APIC_NMI 29
-#define CO_APIC_LAST CO_APIC_NMI
-
-/*
- * This is how irqs are assigned on the Visual Workstation.
- * Legacy devices get irq's 1-15 (system clock is 0 and is CO_APIC_CPU).
- * All other devices (including PCI) go to Cobalt and are irq's 16 on up.
- */
-#define CO_IRQ_APIC0 16 /* irq of apic entry 0 */
-#define IS_CO_APIC(irq) ((irq) >= CO_IRQ_APIC0)
-#define CO_IRQ(apic) (CO_IRQ_APIC0 + (apic)) /* apic ent to irq */
-#define CO_APIC(irq) ((irq) - CO_IRQ_APIC0) /* irq to apic ent */
-#define CO_IRQ_IDE0 14 /* knowledge of... */
-#define CO_IRQ_IDE1 15 /* ... ide driver defaults! */
-#define CO_IRQ_8259 CO_IRQ(CO_APIC_8259)
-
-#ifdef CONFIG_X86_VISWS_APIC
-static inline void co_cpu_write(unsigned long reg, unsigned long v)
-{
- *((volatile unsigned long *)(CO_CPU_VADDR+reg))=v;
-}
-
-static inline unsigned long co_cpu_read(unsigned long reg)
-{
- return *((volatile unsigned long *)(CO_CPU_VADDR+reg));
-}
-
-static inline void co_apic_write(unsigned long reg, unsigned long v)
-{
- *((volatile unsigned long *)(CO_APIC_VADDR+reg))=v;
-}
-
-static inline unsigned long co_apic_read(unsigned long reg)
-{
- return *((volatile unsigned long *)(CO_APIC_VADDR+reg));
-}
-#endif
-
-extern char visws_board_type;
-
-#define VISWS_320 0
-#define VISWS_540 1
-
-extern char visws_board_rev;
-
-extern int pci_visws_init(void);
-
-#endif /* _ASM_X86_VISWS_COBALT_H */
diff --git a/arch/x86/include/asm/visws/lithium.h b/arch/x86/include/asm/visws/lithium.h
deleted file mode 100644
index a10d89bc1270..000000000000
--- a/arch/x86/include/asm/visws/lithium.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef _ASM_X86_VISWS_LITHIUM_H
-#define _ASM_X86_VISWS_LITHIUM_H
-
-#include <asm/fixmap.h>
-
-/*
- * Lithium is the SGI Visual Workstation I/O ASIC
- */
-
-#define LI_PCI_A_PHYS 0xfc000000 /* Enet is dev 3 */
-#define LI_PCI_B_PHYS 0xfd000000 /* PIIX4 is here */
-
-/* see set_fixmap() and asm/fixmap.h */
-#define LI_PCIA_VADDR (fix_to_virt(FIX_LI_PCIA))
-#define LI_PCIB_VADDR (fix_to_virt(FIX_LI_PCIB))
-
-/* Not a standard PCI? (not in linux/pci.h) */
-#define LI_PCI_BUSNUM 0x44 /* lo8: primary, hi8: sub */
-#define LI_PCI_INTEN 0x46
-
-/* LI_PCI_INTENT bits */
-#define LI_INTA_0 0x0001
-#define LI_INTA_1 0x0002
-#define LI_INTA_2 0x0004
-#define LI_INTA_3 0x0008
-#define LI_INTA_4 0x0010
-#define LI_INTB 0x0020
-#define LI_INTC 0x0040
-#define LI_INTD 0x0080
-
-/* More special purpose macros... */
-static inline void li_pcia_write16(unsigned long reg, unsigned short v)
-{
- *((volatile unsigned short *)(LI_PCIA_VADDR+reg))=v;
-}
-
-static inline unsigned short li_pcia_read16(unsigned long reg)
-{
- return *((volatile unsigned short *)(LI_PCIA_VADDR+reg));
-}
-
-static inline void li_pcib_write16(unsigned long reg, unsigned short v)
-{
- *((volatile unsigned short *)(LI_PCIB_VADDR+reg))=v;
-}
-
-static inline unsigned short li_pcib_read16(unsigned long reg)
-{
- return *((volatile unsigned short *)(LI_PCIB_VADDR+reg));
-}
-
-#endif /* _ASM_X86_VISWS_LITHIUM_H */
-
diff --git a/arch/x86/include/asm/visws/piix4.h b/arch/x86/include/asm/visws/piix4.h
deleted file mode 100644
index d0af4d338e7f..000000000000
--- a/arch/x86/include/asm/visws/piix4.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef _ASM_X86_VISWS_PIIX4_H
-#define _ASM_X86_VISWS_PIIX4_H
-
-/*
- * PIIX4 as used on SGI Visual Workstations
- */
-
-#define PIIX_PM_START 0x0F80
-
-#define SIO_GPIO_START 0x0FC0
-
-#define SIO_PM_START 0x0FC8
-
-#define PMBASE PIIX_PM_START
-#define GPIREG0 (PMBASE+0x30)
-#define GPIREG(x) (GPIREG0+((x)/8))
-#define GPIBIT(x) (1 << ((x)%8))
-
-#define PIIX_GPI_BD_ID1 18
-#define PIIX_GPI_BD_ID2 19
-#define PIIX_GPI_BD_ID3 20
-#define PIIX_GPI_BD_ID4 21
-#define PIIX_GPI_BD_REG GPIREG(PIIX_GPI_BD_ID1)
-#define PIIX_GPI_BD_MASK (GPIBIT(PIIX_GPI_BD_ID1) | \
- GPIBIT(PIIX_GPI_BD_ID2) | \
- GPIBIT(PIIX_GPI_BD_ID3) | \
- GPIBIT(PIIX_GPI_BD_ID4) )
-
-#define PIIX_GPI_BD_SHIFT (PIIX_GPI_BD_ID1 % 8)
-
-#define SIO_INDEX 0x2e
-#define SIO_DATA 0x2f
-
-#define SIO_DEV_SEL 0x7
-#define SIO_DEV_ENB 0x30
-#define SIO_DEV_MSB 0x60
-#define SIO_DEV_LSB 0x61
-
-#define SIO_GP_DEV 0x7
-
-#define SIO_GP_BASE SIO_GPIO_START
-#define SIO_GP_MSB (SIO_GP_BASE>>8)
-#define SIO_GP_LSB (SIO_GP_BASE&0xff)
-
-#define SIO_GP_DATA1 (SIO_GP_BASE+0)
-
-#define SIO_PM_DEV 0x8
-
-#define SIO_PM_BASE SIO_PM_START
-#define SIO_PM_MSB (SIO_PM_BASE>>8)
-#define SIO_PM_LSB (SIO_PM_BASE&0xff)
-#define SIO_PM_INDEX (SIO_PM_BASE+0)
-#define SIO_PM_DATA (SIO_PM_BASE+1)
-
-#define SIO_PM_FER2 0x1
-
-#define SIO_PM_GP_EN 0x80
-
-
-
-/*
- * This is the dev/reg where generating a config cycle will
- * result in a PCI special cycle.
- */
-#define SPECIAL_DEV 0xff
-#define SPECIAL_REG 0x00
-
-/*
- * PIIX4 needs to see a special cycle with the following data
- * to be convinced the processor has gone into the stop grant
- * state. PIIX4 insists on seeing this before it will power
- * down a system.
- */
-#define PIIX_SPECIAL_STOP 0x00120002
-
-#define PIIX4_RESET_PORT 0xcf9
-#define PIIX4_RESET_VAL 0x6
-
-#define PMSTS_PORT 0xf80 // 2 bytes PM Status
-#define PMEN_PORT 0xf82 // 2 bytes PM Enable
-#define PMCNTRL_PORT 0xf84 // 2 bytes PM Control
-
-#define PM_SUSPEND_ENABLE 0x2000 // start sequence to suspend state
-
-/*
- * PMSTS and PMEN I/O bit definitions.
- * (Bits are the same in both registers)
- */
-#define PM_STS_RSM (1<<15) // Resume Status
-#define PM_STS_PWRBTNOR (1<<11) // Power Button Override
-#define PM_STS_RTC (1<<10) // RTC status
-#define PM_STS_PWRBTN (1<<8) // Power Button Pressed?
-#define PM_STS_GBL (1<<5) // Global Status
-#define PM_STS_BM (1<<4) // Bus Master Status
-#define PM_STS_TMROF (1<<0) // Timer Overflow Status.
-
-/*
- * Stop clock GPI register
- */
-#define PIIX_GPIREG0 (0xf80 + 0x30)
-
-/*
- * Stop clock GPI bit in GPIREG0
- */
-#define PIIX_GPI_STPCLK 0x4 // STPCLK signal routed back in
-
-#endif /* _ASM_X86_VISWS_PIIX4_H */
diff --git a/arch/x86/include/asm/visws/sgivw.h b/arch/x86/include/asm/visws/sgivw.h
deleted file mode 100644
index 5fbf63e1003c..000000000000
--- a/arch/x86/include/asm/visws/sgivw.h
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
- * Frame buffer position and size:
- */
-extern unsigned long sgivwfb_mem_phys;
-extern unsigned long sgivwfb_mem_size;
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 2067264fb7f5..7004d21e6219 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -85,6 +85,7 @@
#define VM_EXIT_SAVE_IA32_EFER 0x00100000
#define VM_EXIT_LOAD_IA32_EFER 0x00200000
#define VM_EXIT_SAVE_VMX_PREEMPTION_TIMER 0x00400000
+#define VM_EXIT_CLEAR_BNDCFGS 0x00800000
#define VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR 0x00036dff
@@ -95,6 +96,7 @@
#define VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL 0x00002000
#define VM_ENTRY_LOAD_IA32_PAT 0x00004000
#define VM_ENTRY_LOAD_IA32_EFER 0x00008000
+#define VM_ENTRY_LOAD_BNDCFGS 0x00010000
#define VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR 0x000011ff
@@ -174,6 +176,8 @@ enum vmcs_field {
GUEST_PDPTR2_HIGH = 0x0000280f,
GUEST_PDPTR3 = 0x00002810,
GUEST_PDPTR3_HIGH = 0x00002811,
+ GUEST_BNDCFGS = 0x00002812,
+ GUEST_BNDCFGS_HIGH = 0x00002813,
HOST_IA32_PAT = 0x00002c00,
HOST_IA32_PAT_HIGH = 0x00002c01,
HOST_IA32_EFER = 0x00002c02,
diff --git a/arch/x86/include/asm/vvar.h b/arch/x86/include/asm/vvar.h
index d76ac40da206..081d909bc495 100644
--- a/arch/x86/include/asm/vvar.h
+++ b/arch/x86/include/asm/vvar.h
@@ -16,8 +16,8 @@
* you mess up, the linker will catch it.)
*/
-/* Base address of vvars. This is not ABI. */
-#define VVAR_ADDRESS (-10*1024*1024 - 4096)
+#ifndef _ASM_X86_VVAR_H
+#define _ASM_X86_VVAR_H
#if defined(__VVAR_KERNEL_LDS)
@@ -29,16 +29,35 @@
#else
+#ifdef BUILD_VDSO32
+
+#define DECLARE_VVAR(offset, type, name) \
+ extern type vvar_ ## name __attribute__((visibility("hidden")));
+
+#define VVAR(name) (vvar_ ## name)
+
+#else
+
+extern char __vvar_page;
+
+/* Base address of vvars. This is not ABI. */
+#ifdef CONFIG_X86_64
+#define VVAR_ADDRESS (-10*1024*1024 - 4096)
+#else
+#define VVAR_ADDRESS (&__vvar_page)
+#endif
+
#define DECLARE_VVAR(offset, type, name) \
static type const * const vvaraddr_ ## name = \
(void *)(VVAR_ADDRESS + (offset));
+#define VVAR(name) (*vvaraddr_ ## name)
+#endif
+
#define DEFINE_VVAR(type, name) \
type name \
__attribute__((section(".vvar_" #name), aligned(16))) __visible
-#define VVAR(name) (*vvaraddr_ ## name)
-
#endif
/* DECLARE_VVAR(offset, type, name) */
@@ -48,3 +67,5 @@ DECLARE_VVAR(16, int, vgetcpu_mode)
DECLARE_VVAR(128, struct vsyscall_gtod_data, vsyscall_gtod_data)
#undef DECLARE_VVAR
+
+#endif
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
index 554738963b28..d949ef28c48b 100644
--- a/arch/x86/include/asm/xsave.h
+++ b/arch/x86/include/asm/xsave.h
@@ -6,13 +6,18 @@
#define XSTATE_CPUID 0x0000000d
-#define XSTATE_FP 0x1
-#define XSTATE_SSE 0x2
-#define XSTATE_YMM 0x4
-#define XSTATE_BNDREGS 0x8
-#define XSTATE_BNDCSR 0x10
+#define XSTATE_FP 0x1
+#define XSTATE_SSE 0x2
+#define XSTATE_YMM 0x4
+#define XSTATE_BNDREGS 0x8
+#define XSTATE_BNDCSR 0x10
+#define XSTATE_OPMASK 0x20
+#define XSTATE_ZMM_Hi256 0x40
+#define XSTATE_Hi16_ZMM 0x80
#define XSTATE_FPSSE (XSTATE_FP | XSTATE_SSE)
+/* Bit 63 of XCR0 is reserved for future expansion */
+#define XSTATE_EXTEND_MASK (~(XSTATE_FPSSE | (1ULL << 63)))
#define FXSAVE_SIZE 512
@@ -23,7 +28,8 @@
#define XSAVE_YMM_OFFSET (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET)
/* Supported features which support lazy state saving */
-#define XSTATE_LAZY (XSTATE_FP | XSTATE_SSE | XSTATE_YMM)
+#define XSTATE_LAZY (XSTATE_FP | XSTATE_SSE | XSTATE_YMM \
+ | XSTATE_OPMASK | XSTATE_ZMM_Hi256 | XSTATE_Hi16_ZMM)
/* Supported features which require eager state saving */
#define XSTATE_EAGER (XSTATE_BNDREGS | XSTATE_BNDCSR)
diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h
index c19fc60ff062..c827ace3121b 100644
--- a/arch/x86/include/uapi/asm/msr-index.h
+++ b/arch/x86/include/uapi/asm/msr-index.h
@@ -295,6 +295,7 @@
#define MSR_SMI_COUNT 0x00000034
#define MSR_IA32_FEATURE_CONTROL 0x0000003a
#define MSR_IA32_TSC_ADJUST 0x0000003b
+#define MSR_IA32_BNDCFGS 0x00000d90
#define FEATURE_CONTROL_LOCKED (1<<0)
#define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1<<1)
@@ -368,33 +369,58 @@
#define THERM_LOG_THRESHOLD1 (1 << 9)
/* MISC_ENABLE bits: architectural */
-#define MSR_IA32_MISC_ENABLE_FAST_STRING (1ULL << 0)
-#define MSR_IA32_MISC_ENABLE_TCC (1ULL << 1)
-#define MSR_IA32_MISC_ENABLE_EMON (1ULL << 7)
-#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL (1ULL << 11)
-#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1ULL << 12)
-#define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP (1ULL << 16)
-#define MSR_IA32_MISC_ENABLE_MWAIT (1ULL << 18)
-#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID (1ULL << 22)
-#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE (1ULL << 23)
-#define MSR_IA32_MISC_ENABLE_XD_DISABLE (1ULL << 34)
+#define MSR_IA32_MISC_ENABLE_FAST_STRING_BIT 0
+#define MSR_IA32_MISC_ENABLE_FAST_STRING (1ULL << MSR_IA32_MISC_ENABLE_FAST_STRING_BIT)
+#define MSR_IA32_MISC_ENABLE_TCC_BIT 1
+#define MSR_IA32_MISC_ENABLE_TCC (1ULL << MSR_IA32_MISC_ENABLE_TCC_BIT)
+#define MSR_IA32_MISC_ENABLE_EMON_BIT 7
+#define MSR_IA32_MISC_ENABLE_EMON (1ULL << MSR_IA32_MISC_ENABLE_EMON_BIT)
+#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL_BIT 11
+#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL (1ULL << MSR_IA32_MISC_ENABLE_BTS_UNAVAIL_BIT)
+#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL_BIT 12
+#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1ULL << MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL_BIT)
+#define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP_BIT 16
+#define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP (1ULL << MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP_BIT)
+#define MSR_IA32_MISC_ENABLE_MWAIT_BIT 18
+#define MSR_IA32_MISC_ENABLE_MWAIT (1ULL << MSR_IA32_MISC_ENABLE_MWAIT_BIT)
+#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT 22
+#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID (1ULL << MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT);
+#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE_BIT 23
+#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_XTPR_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_XD_DISABLE_BIT 34
+#define MSR_IA32_MISC_ENABLE_XD_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_XD_DISABLE_BIT)
/* MISC_ENABLE bits: model-specific, meaning may vary from core to core */
-#define MSR_IA32_MISC_ENABLE_X87_COMPAT (1ULL << 2)
-#define MSR_IA32_MISC_ENABLE_TM1 (1ULL << 3)
-#define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE (1ULL << 4)
-#define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE (1ULL << 6)
-#define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK (1ULL << 8)
-#define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE (1ULL << 9)
-#define MSR_IA32_MISC_ENABLE_FERR (1ULL << 10)
-#define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX (1ULL << 10)
-#define MSR_IA32_MISC_ENABLE_TM2 (1ULL << 13)
-#define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE (1ULL << 19)
-#define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK (1ULL << 20)
-#define MSR_IA32_MISC_ENABLE_L1D_CONTEXT (1ULL << 24)
-#define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE (1ULL << 37)
-#define MSR_IA32_MISC_ENABLE_TURBO_DISABLE (1ULL << 38)
-#define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE (1ULL << 39)
+#define MSR_IA32_MISC_ENABLE_X87_COMPAT_BIT 2
+#define MSR_IA32_MISC_ENABLE_X87_COMPAT (1ULL << MSR_IA32_MISC_ENABLE_X87_COMPAT_BIT)
+#define MSR_IA32_MISC_ENABLE_TM1_BIT 3
+#define MSR_IA32_MISC_ENABLE_TM1 (1ULL << MSR_IA32_MISC_ENABLE_TM1_BIT)
+#define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE_BIT 4
+#define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE_BIT 6
+#define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK_BIT 8
+#define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK (1ULL << MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK_BIT)
+#define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT 9
+#define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_FERR_BIT 10
+#define MSR_IA32_MISC_ENABLE_FERR (1ULL << MSR_IA32_MISC_ENABLE_FERR_BIT)
+#define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX_BIT 10
+#define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX (1ULL << MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX_BIT)
+#define MSR_IA32_MISC_ENABLE_TM2_BIT 13
+#define MSR_IA32_MISC_ENABLE_TM2 (1ULL << MSR_IA32_MISC_ENABLE_TM2_BIT)
+#define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE_BIT 19
+#define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK_BIT 20
+#define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK (1ULL << MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK_BIT)
+#define MSR_IA32_MISC_ENABLE_L1D_CONTEXT_BIT 24
+#define MSR_IA32_MISC_ENABLE_L1D_CONTEXT (1ULL << MSR_IA32_MISC_ENABLE_L1D_CONTEXT_BIT)
+#define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE_BIT 37
+#define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_TURBO_DISABLE_BIT 38
+#define MSR_IA32_MISC_ENABLE_TURBO_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_TURBO_DISABLE_BIT)
+#define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE_BIT 39
+#define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE_BIT)
#define MSR_IA32_TSC_DEADLINE 0x000006E0
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index cb648c84b327..f4d96000d33a 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -26,7 +26,7 @@ obj-$(CONFIG_IRQ_WORK) += irq_work.o
obj-y += probe_roms.o
obj-$(CONFIG_X86_32) += i386_ksyms_32.o
obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o
-obj-y += syscall_$(BITS).o
+obj-y += syscall_$(BITS).o vsyscall_gtod.o
obj-$(CONFIG_X86_64) += vsyscall_64.o
obj-$(CONFIG_X86_64) += vsyscall_emu_64.o
obj-$(CONFIG_SYSFS) += ksysfs.o
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 1dac94265b59..86281ffb96d6 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -53,10 +53,6 @@ EXPORT_SYMBOL(acpi_disabled);
# include <asm/proto.h>
#endif /* X86 */
-#define BAD_MADT_ENTRY(entry, end) ( \
- (!entry) || (unsigned long)entry + sizeof(*entry) > end || \
- ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
-
#define PREFIX "ACPI: "
int acpi_noirq; /* skip ACPI IRQ initialization */
@@ -613,10 +609,10 @@ static void acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
int nid;
nid = acpi_get_node(handle);
- if (nid == -1 || !node_online(nid))
- return;
- set_apicid_to_node(physid, nid);
- numa_set_node(cpu, nid);
+ if (nid != -1) {
+ set_apicid_to_node(physid, nid);
+ numa_set_node(cpu, nid);
+ }
#endif
}
@@ -907,10 +903,6 @@ static int __init acpi_parse_madt_lapic_entries(void)
#ifdef CONFIG_X86_IO_APIC
#define MP_ISA_BUS 0
-#ifdef CONFIG_X86_ES7000
-extern int es7000_plat;
-#endif
-
void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
{
int ioapic;
@@ -960,14 +952,6 @@ void __init mp_config_acpi_legacy_irqs(void)
set_bit(MP_ISA_BUS, mp_bus_not_pci);
pr_debug("Bus #%d is ISA\n", MP_ISA_BUS);
-#ifdef CONFIG_X86_ES7000
- /*
- * Older generations of ES7000 have no legacy identity mappings
- */
- if (es7000_plat == 1)
- return;
-#endif
-
/*
* Use the default configuration for the IRQs 0-15. Unless
* overridden by (MADT) interrupt source override entries.
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
index dec8de4e1663..f04dbb3069b8 100644
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
@@ -22,6 +22,7 @@ const struct pci_device_id amd_nb_misc_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
{}
};
EXPORT_SYMBOL(amd_nb_misc_ids);
@@ -30,6 +31,7 @@ static const struct pci_device_id amd_nb_link_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
{}
};
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c
index fd972a3e4cbb..9fa8aa051f54 100644
--- a/arch/x86/kernel/aperture_64.c
+++ b/arch/x86/kernel/aperture_64.c
@@ -18,7 +18,6 @@
#include <linux/pci_ids.h>
#include <linux/pci.h>
#include <linux/bitops.h>
-#include <linux/ioport.h>
#include <linux/suspend.h>
#include <asm/e820.h>
#include <asm/io.h>
@@ -54,18 +53,6 @@ int fallback_aper_force __initdata;
int fix_aperture __initdata = 1;
-static struct resource gart_resource = {
- .name = "GART",
- .flags = IORESOURCE_MEM,
-};
-
-static void __init insert_aperture_resource(u32 aper_base, u32 aper_size)
-{
- gart_resource.start = aper_base;
- gart_resource.end = aper_base + aper_size - 1;
- insert_resource(&iomem_resource, &gart_resource);
-}
-
/* This code runs before the PCI subsystem is initialized, so just
access the northbridge directly. */
@@ -96,7 +83,6 @@ static u32 __init allocate_aperture(void)
memblock_reserve(addr, aper_size);
printk(KERN_INFO "Mapping aperture over %d KB of RAM @ %lx\n",
aper_size >> 10, addr);
- insert_aperture_resource((u32)addr, aper_size);
register_nosave_region(addr >> PAGE_SHIFT,
(addr+aper_size) >> PAGE_SHIFT);
@@ -444,12 +430,8 @@ int __init gart_iommu_hole_init(void)
out:
if (!fix && !fallback_aper_force) {
- if (last_aper_base) {
- unsigned long n = (32 * 1024 * 1024) << last_aper_order;
-
- insert_aperture_resource((u32)last_aper_base, n);
+ if (last_aper_base)
return 1;
- }
return 0;
}
diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile
index 0ae0323b1f9c..dcb5b15401ce 100644
--- a/arch/x86/kernel/apic/Makefile
+++ b/arch/x86/kernel/apic/Makefile
@@ -18,10 +18,7 @@ obj-y += apic_flat_64.o
endif
# APIC probe will depend on the listing order here
-obj-$(CONFIG_X86_NUMAQ) += numaq_32.o
-obj-$(CONFIG_X86_SUMMIT) += summit_32.o
obj-$(CONFIG_X86_BIGSMP) += bigsmp_32.o
-obj-$(CONFIG_X86_ES7000) += es7000_32.o
# For 32bit, probe_32 need to be listed last
obj-$(CONFIG_X86_LOCAL_APIC) += probe_$(BITS).o
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 7f26c9a70a9e..481ae38f6a44 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -133,6 +133,10 @@ static inline void imcr_apic_to_pic(void)
* +1=force-enable
*/
static int force_enable_local_apic __initdata;
+
+/* Control whether x2APIC mode is enabled or not */
+static bool nox2apic __initdata;
+
/*
* APIC command line parameters
*/
@@ -162,8 +166,7 @@ int x2apic_mode;
/* x2apic enabled before OS handover */
int x2apic_preenabled;
static int x2apic_disabled;
-static int nox2apic;
-static __init int setup_nox2apic(char *str)
+static int __init setup_nox2apic(char *str)
{
if (x2apic_enabled()) {
int apicid = native_apic_msr_read(APIC_ID);
@@ -178,7 +181,7 @@ static __init int setup_nox2apic(char *str)
} else
setup_clear_cpu_cap(X86_FEATURE_X2APIC);
- nox2apic = 1;
+ nox2apic = true;
return 0;
}
@@ -283,8 +286,12 @@ u32 native_safe_apic_wait_icr_idle(void)
void native_apic_icr_write(u32 low, u32 id)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id));
apic_write(APIC_ICR, low);
+ local_irq_restore(flags);
}
u64 native_apic_icr_read(void)
@@ -2129,7 +2136,6 @@ int generic_processor_info(int apicid, int version)
*
* - arch/x86/kernel/mpparse.c: MP_processor_info()
* - arch/x86/mm/amdtopology.c: amd_numa_init()
- * - arch/x86/platform/visws/visws_quirks.c: MP_processor_info()
*
* This function is executed with the modified
* boot_cpu_physical_apicid. So, disabled_cpu_apicid kernel
diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c
index 2c621a6b901a..7c1b29479513 100644
--- a/arch/x86/kernel/apic/apic_flat_64.c
+++ b/arch/x86/kernel/apic/apic_flat_64.c
@@ -198,7 +198,7 @@ static struct apic apic_flat = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = default_inquire_remote_apic,
@@ -314,7 +314,7 @@ static struct apic apic_physflat = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = default_inquire_remote_apic,
diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c
index 191ce75c0e54..8c7c98249c20 100644
--- a/arch/x86/kernel/apic/apic_noop.c
+++ b/arch/x86/kernel/apic/apic_noop.c
@@ -172,8 +172,7 @@ struct apic apic_noop = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
-
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = NULL,
diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c
index 3e67f9e3d7ef..a5b45df8bc88 100644
--- a/arch/x86/kernel/apic/apic_numachip.c
+++ b/arch/x86/kernel/apic/apic_numachip.c
@@ -248,7 +248,7 @@ static const struct apic apic_numachip __refconst = {
.wakeup_secondary_cpu = numachip_wakeup_secondary,
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = NULL, /* REMRD not supported */
diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c
index d50e3640d5ae..e4840aa7a255 100644
--- a/arch/x86/kernel/apic/bigsmp_32.c
+++ b/arch/x86/kernel/apic/bigsmp_32.c
@@ -199,8 +199,7 @@ static struct apic apic_bigsmp = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = default_wait_for_init_deassert,
-
+ .wait_for_init_deassert = true,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = default_inquire_remote_apic,
diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c
deleted file mode 100644
index c55224731b2d..000000000000
--- a/arch/x86/kernel/apic/es7000_32.c
+++ /dev/null
@@ -1,746 +0,0 @@
-/*
- * Written by: Garry Forsgren, Unisys Corporation
- * Natalie Protasevich, Unisys Corporation
- *
- * This file contains the code to configure and interface
- * with Unisys ES7000 series hardware system manager.
- *
- * Copyright (c) 2003 Unisys Corporation.
- * Copyright (C) 2009, Red Hat, Inc., Ingo Molnar
- *
- * All Rights Reserved.
- *
- * 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 would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Unisys Corporation, Township Line & Union Meeting
- * Roads-A, Unisys Way, Blue Bell, Pennsylvania, 19424, or:
- *
- * http://www.unisys.com
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/notifier.h>
-#include <linux/spinlock.h>
-#include <linux/cpumask.h>
-#include <linux/threads.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/reboot.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/acpi.h>
-#include <linux/init.h>
-#include <linux/gfp.h>
-#include <linux/nmi.h>
-#include <linux/smp.h>
-#include <linux/io.h>
-
-#include <asm/apicdef.h>
-#include <linux/atomic.h>
-#include <asm/fixmap.h>
-#include <asm/mpspec.h>
-#include <asm/setup.h>
-#include <asm/apic.h>
-#include <asm/ipi.h>
-
-/*
- * ES7000 chipsets
- */
-
-#define NON_UNISYS 0
-#define ES7000_CLASSIC 1
-#define ES7000_ZORRO 2
-
-#define MIP_REG 1
-#define MIP_PSAI_REG 4
-
-#define MIP_BUSY 1
-#define MIP_SPIN 0xf0000
-#define MIP_VALID 0x0100000000000000ULL
-#define MIP_SW_APIC 0x1020b
-
-#define MIP_PORT(val) ((val >> 32) & 0xffff)
-
-#define MIP_RD_LO(val) (val & 0xffffffff)
-
-struct mip_reg {
- unsigned long long off_0x00;
- unsigned long long off_0x08;
- unsigned long long off_0x10;
- unsigned long long off_0x18;
- unsigned long long off_0x20;
- unsigned long long off_0x28;
- unsigned long long off_0x30;
- unsigned long long off_0x38;
-};
-
-struct mip_reg_info {
- unsigned long long mip_info;
- unsigned long long delivery_info;
- unsigned long long host_reg;
- unsigned long long mip_reg;
-};
-
-struct psai {
- unsigned long long entry_type;
- unsigned long long addr;
- unsigned long long bep_addr;
-};
-
-#ifdef CONFIG_ACPI
-
-struct es7000_oem_table {
- struct acpi_table_header Header;
- u32 OEMTableAddr;
- u32 OEMTableSize;
-};
-
-static unsigned long oem_addrX;
-static unsigned long oem_size;
-
-#endif
-
-/*
- * ES7000 Globals
- */
-
-static volatile unsigned long *psai;
-static struct mip_reg *mip_reg;
-static struct mip_reg *host_reg;
-static int mip_port;
-static unsigned long mip_addr;
-static unsigned long host_addr;
-
-int es7000_plat;
-
-/*
- * GSI override for ES7000 platforms.
- */
-
-
-static int wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip)
-{
- unsigned long vect = 0, psaival = 0;
-
- if (psai == NULL)
- return -1;
-
- vect = ((unsigned long)__pa(eip)/0x1000) << 16;
- psaival = (0x1000000 | vect | cpu);
-
- while (*psai & 0x1000000)
- ;
-
- *psai = psaival;
-
- return 0;
-}
-
-static int es7000_apic_is_cluster(void)
-{
- /* MPENTIUMIII */
- if (boot_cpu_data.x86 == 6 &&
- (boot_cpu_data.x86_model >= 7 && boot_cpu_data.x86_model <= 11))
- return 1;
-
- return 0;
-}
-
-static void setup_unisys(void)
-{
- /*
- * Determine the generation of the ES7000 currently running.
- *
- * es7000_plat = 1 if the machine is a 5xx ES7000 box
- * es7000_plat = 2 if the machine is a x86_64 ES7000 box
- *
- */
- if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
- es7000_plat = ES7000_ZORRO;
- else
- es7000_plat = ES7000_CLASSIC;
-}
-
-/*
- * Parse the OEM Table:
- */
-static int parse_unisys_oem(char *oemptr)
-{
- int i;
- int success = 0;
- unsigned char type, size;
- unsigned long val;
- char *tp = NULL;
- struct psai *psaip = NULL;
- struct mip_reg_info *mi;
- struct mip_reg *host, *mip;
-
- tp = oemptr;
-
- tp += 8;
-
- for (i = 0; i <= 6; i++) {
- type = *tp++;
- size = *tp++;
- tp -= 2;
- switch (type) {
- case MIP_REG:
- mi = (struct mip_reg_info *)tp;
- val = MIP_RD_LO(mi->host_reg);
- host_addr = val;
- host = (struct mip_reg *)val;
- host_reg = __va(host);
- val = MIP_RD_LO(mi->mip_reg);
- mip_port = MIP_PORT(mi->mip_info);
- mip_addr = val;
- mip = (struct mip_reg *)val;
- mip_reg = __va(mip);
- pr_debug("host_reg = 0x%lx\n",
- (unsigned long)host_reg);
- pr_debug("mip_reg = 0x%lx\n",
- (unsigned long)mip_reg);
- success++;
- break;
- case MIP_PSAI_REG:
- psaip = (struct psai *)tp;
- if (tp != NULL) {
- if (psaip->addr)
- psai = __va(psaip->addr);
- else
- psai = NULL;
- success++;
- }
- break;
- default:
- break;
- }
- tp += size;
- }
-
- if (success < 2)
- es7000_plat = NON_UNISYS;
- else
- setup_unisys();
-
- return es7000_plat;
-}
-
-#ifdef CONFIG_ACPI
-static int __init find_unisys_acpi_oem_table(unsigned long *oem_addr)
-{
- struct acpi_table_header *header = NULL;
- struct es7000_oem_table *table;
- acpi_size tbl_size;
- acpi_status ret;
- int i = 0;
-
- for (;;) {
- ret = acpi_get_table_with_size("OEM1", i++, &header, &tbl_size);
- if (!ACPI_SUCCESS(ret))
- return -1;
-
- if (!memcmp((char *) &header->oem_id, "UNISYS", 6))
- break;
-
- early_acpi_os_unmap_memory(header, tbl_size);
- }
-
- table = (void *)header;
-
- oem_addrX = table->OEMTableAddr;
- oem_size = table->OEMTableSize;
-
- early_acpi_os_unmap_memory(header, tbl_size);
-
- *oem_addr = (unsigned long)__acpi_map_table(oem_addrX, oem_size);
-
- return 0;
-}
-
-static void __init unmap_unisys_acpi_oem_table(unsigned long oem_addr)
-{
- if (!oem_addr)
- return;
-
- __acpi_unmap_table((char *)oem_addr, oem_size);
-}
-
-static int es7000_check_dsdt(void)
-{
- struct acpi_table_header header;
-
- if (ACPI_SUCCESS(acpi_get_table_header(ACPI_SIG_DSDT, 0, &header)) &&
- !strncmp(header.oem_id, "UNISYS", 6))
- return 1;
- return 0;
-}
-
-static int es7000_acpi_ret;
-
-/* Hook from generic ACPI tables.c */
-static int __init es7000_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
- unsigned long oem_addr = 0;
- int check_dsdt;
- int ret = 0;
-
- /* check dsdt at first to avoid clear fix_map for oem_addr */
- check_dsdt = es7000_check_dsdt();
-
- if (!find_unisys_acpi_oem_table(&oem_addr)) {
- if (check_dsdt) {
- ret = parse_unisys_oem((char *)oem_addr);
- } else {
- setup_unisys();
- ret = 1;
- }
- /*
- * we need to unmap it
- */
- unmap_unisys_acpi_oem_table(oem_addr);
- }
-
- es7000_acpi_ret = ret;
-
- return ret && !es7000_apic_is_cluster();
-}
-
-static int es7000_acpi_madt_oem_check_cluster(char *oem_id, char *oem_table_id)
-{
- int ret = es7000_acpi_ret;
-
- return ret && es7000_apic_is_cluster();
-}
-
-#else /* !CONFIG_ACPI: */
-static int es7000_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
- return 0;
-}
-
-static int es7000_acpi_madt_oem_check_cluster(char *oem_id, char *oem_table_id)
-{
- return 0;
-}
-#endif /* !CONFIG_ACPI */
-
-static void es7000_spin(int n)
-{
- int i = 0;
-
- while (i++ < n)
- rep_nop();
-}
-
-static int es7000_mip_write(struct mip_reg *mip_reg)
-{
- int status = 0;
- int spin;
-
- spin = MIP_SPIN;
- while ((host_reg->off_0x38 & MIP_VALID) != 0) {
- if (--spin <= 0) {
- WARN(1, "Timeout waiting for Host Valid Flag\n");
- return -1;
- }
- es7000_spin(MIP_SPIN);
- }
-
- memcpy(host_reg, mip_reg, sizeof(struct mip_reg));
- outb(1, mip_port);
-
- spin = MIP_SPIN;
-
- while ((mip_reg->off_0x38 & MIP_VALID) == 0) {
- if (--spin <= 0) {
- WARN(1, "Timeout waiting for MIP Valid Flag\n");
- return -1;
- }
- es7000_spin(MIP_SPIN);
- }
-
- status = (mip_reg->off_0x00 & 0xffff0000000000ULL) >> 48;
- mip_reg->off_0x38 &= ~MIP_VALID;
-
- return status;
-}
-
-static void es7000_enable_apic_mode(void)
-{
- struct mip_reg es7000_mip_reg;
- int mip_status;
-
- if (!es7000_plat)
- return;
-
- pr_info("Enabling APIC mode.\n");
- memset(&es7000_mip_reg, 0, sizeof(struct mip_reg));
- es7000_mip_reg.off_0x00 = MIP_SW_APIC;
- es7000_mip_reg.off_0x38 = MIP_VALID;
-
- while ((mip_status = es7000_mip_write(&es7000_mip_reg)) != 0)
- WARN(1, "Command failed, status = %x\n", mip_status);
-}
-
-static void es7000_wait_for_init_deassert(atomic_t *deassert)
-{
- while (!atomic_read(deassert))
- cpu_relax();
-}
-
-static unsigned int es7000_get_apic_id(unsigned long x)
-{
- return (x >> 24) & 0xFF;
-}
-
-static void es7000_send_IPI_mask(const struct cpumask *mask, int vector)
-{
- default_send_IPI_mask_sequence_phys(mask, vector);
-}
-
-static void es7000_send_IPI_allbutself(int vector)
-{
- default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
-}
-
-static void es7000_send_IPI_all(int vector)
-{
- es7000_send_IPI_mask(cpu_online_mask, vector);
-}
-
-static int es7000_apic_id_registered(void)
-{
- return 1;
-}
-
-static const struct cpumask *target_cpus_cluster(void)
-{
- return cpu_all_mask;
-}
-
-static const struct cpumask *es7000_target_cpus(void)
-{
- return cpumask_of(smp_processor_id());
-}
-
-static unsigned long es7000_check_apicid_used(physid_mask_t *map, int apicid)
-{
- return 0;
-}
-
-static unsigned long es7000_check_apicid_present(int bit)
-{
- return physid_isset(bit, phys_cpu_present_map);
-}
-
-static int es7000_early_logical_apicid(int cpu)
-{
- /* on es7000, logical apicid is the same as physical */
- return early_per_cpu(x86_bios_cpu_apicid, cpu);
-}
-
-static unsigned long calculate_ldr(int cpu)
-{
- unsigned long id = per_cpu(x86_bios_cpu_apicid, cpu);
-
- return SET_APIC_LOGICAL_ID(id);
-}
-
-/*
- * Set up the logical destination ID.
- *
- * Intel recommends to set DFR, LdR and TPR before enabling
- * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
- * document number 292116). So here it goes...
- */
-static void es7000_init_apic_ldr_cluster(void)
-{
- unsigned long val;
- int cpu = smp_processor_id();
-
- apic_write(APIC_DFR, APIC_DFR_CLUSTER);
- val = calculate_ldr(cpu);
- apic_write(APIC_LDR, val);
-}
-
-static void es7000_init_apic_ldr(void)
-{
- unsigned long val;
- int cpu = smp_processor_id();
-
- apic_write(APIC_DFR, APIC_DFR_FLAT);
- val = calculate_ldr(cpu);
- apic_write(APIC_LDR, val);
-}
-
-static void es7000_setup_apic_routing(void)
-{
- int apic = per_cpu(x86_bios_cpu_apicid, smp_processor_id());
-
- pr_info("Enabling APIC mode: %s. Using %d I/O APICs, target cpus %lx\n",
- (apic_version[apic] == 0x14) ?
- "Physical Cluster" : "Logical Cluster",
- nr_ioapics, cpumask_bits(es7000_target_cpus())[0]);
-}
-
-static int es7000_cpu_present_to_apicid(int mps_cpu)
-{
- if (!mps_cpu)
- return boot_cpu_physical_apicid;
- else if (mps_cpu < nr_cpu_ids)
- return per_cpu(x86_bios_cpu_apicid, mps_cpu);
- else
- return BAD_APICID;
-}
-
-static int cpu_id;
-
-static void es7000_apicid_to_cpu_present(int phys_apicid, physid_mask_t *retmap)
-{
- physid_set_mask_of_physid(cpu_id, retmap);
- ++cpu_id;
-}
-
-static void es7000_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
-{
- /* For clustered we don't have a good way to do this yet - hack */
- physids_promote(0xFFL, retmap);
-}
-
-static int es7000_check_phys_apicid_present(int cpu_physical_apicid)
-{
- boot_cpu_physical_apicid = read_apic_id();
- return 1;
-}
-
-static inline int
-es7000_cpu_mask_to_apicid(const struct cpumask *cpumask, unsigned int *dest_id)
-{
- unsigned int round = 0;
- unsigned int cpu, uninitialized_var(apicid);
-
- /*
- * The cpus in the mask must all be on the apic cluster.
- */
- for_each_cpu_and(cpu, cpumask, cpu_online_mask) {
- int new_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
-
- if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) {
- WARN(1, "Not a valid mask!");
-
- return -EINVAL;
- }
- apicid |= new_apicid;
- round++;
- }
- if (!round)
- return -EINVAL;
- *dest_id = apicid;
- return 0;
-}
-
-static int
-es7000_cpu_mask_to_apicid_and(const struct cpumask *inmask,
- const struct cpumask *andmask,
- unsigned int *apicid)
-{
- cpumask_var_t cpumask;
- *apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
-
- if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC))
- return 0;
-
- cpumask_and(cpumask, inmask, andmask);
- es7000_cpu_mask_to_apicid(cpumask, apicid);
-
- free_cpumask_var(cpumask);
-
- return 0;
-}
-
-static int es7000_phys_pkg_id(int cpuid_apic, int index_msb)
-{
- return cpuid_apic >> index_msb;
-}
-
-static int probe_es7000(void)
-{
- /* probed later in mptable/ACPI hooks */
- return 0;
-}
-
-static int es7000_mps_ret;
-static int es7000_mps_oem_check(struct mpc_table *mpc, char *oem,
- char *productid)
-{
- int ret = 0;
-
- if (mpc->oemptr) {
- struct mpc_oemtable *oem_table =
- (struct mpc_oemtable *)mpc->oemptr;
-
- if (!strncmp(oem, "UNISYS", 6))
- ret = parse_unisys_oem((char *)oem_table);
- }
-
- es7000_mps_ret = ret;
-
- return ret && !es7000_apic_is_cluster();
-}
-
-static int es7000_mps_oem_check_cluster(struct mpc_table *mpc, char *oem,
- char *productid)
-{
- int ret = es7000_mps_ret;
-
- return ret && es7000_apic_is_cluster();
-}
-
-/* We've been warned by a false positive warning.Use __refdata to keep calm. */
-static struct apic __refdata apic_es7000_cluster = {
-
- .name = "es7000",
- .probe = probe_es7000,
- .acpi_madt_oem_check = es7000_acpi_madt_oem_check_cluster,
- .apic_id_valid = default_apic_id_valid,
- .apic_id_registered = es7000_apic_id_registered,
-
- .irq_delivery_mode = dest_LowestPrio,
- /* logical delivery broadcast to all procs: */
- .irq_dest_mode = 1,
-
- .target_cpus = target_cpus_cluster,
- .disable_esr = 1,
- .dest_logical = 0,
- .check_apicid_used = es7000_check_apicid_used,
- .check_apicid_present = es7000_check_apicid_present,
-
- .vector_allocation_domain = flat_vector_allocation_domain,
- .init_apic_ldr = es7000_init_apic_ldr_cluster,
-
- .ioapic_phys_id_map = es7000_ioapic_phys_id_map,
- .setup_apic_routing = es7000_setup_apic_routing,
- .multi_timer_check = NULL,
- .cpu_present_to_apicid = es7000_cpu_present_to_apicid,
- .apicid_to_cpu_present = es7000_apicid_to_cpu_present,
- .setup_portio_remap = NULL,
- .check_phys_apicid_present = es7000_check_phys_apicid_present,
- .enable_apic_mode = es7000_enable_apic_mode,
- .phys_pkg_id = es7000_phys_pkg_id,
- .mps_oem_check = es7000_mps_oem_check_cluster,
-
- .get_apic_id = es7000_get_apic_id,
- .set_apic_id = NULL,
- .apic_id_mask = 0xFF << 24,
-
- .cpu_mask_to_apicid_and = es7000_cpu_mask_to_apicid_and,
-
- .send_IPI_mask = es7000_send_IPI_mask,
- .send_IPI_mask_allbutself = NULL,
- .send_IPI_allbutself = es7000_send_IPI_allbutself,
- .send_IPI_all = es7000_send_IPI_all,
- .send_IPI_self = default_send_IPI_self,
-
- .wakeup_secondary_cpu = wakeup_secondary_cpu_via_mip,
-
- .trampoline_phys_low = 0x467,
- .trampoline_phys_high = 0x469,
-
- .wait_for_init_deassert = NULL,
-
- /* Nothing to do for most platforms, since cleared by the INIT cycle: */
- .smp_callin_clear_local_apic = NULL,
- .inquire_remote_apic = default_inquire_remote_apic,
-
- .read = native_apic_mem_read,
- .write = native_apic_mem_write,
- .eoi_write = native_apic_mem_write,
- .icr_read = native_apic_icr_read,
- .icr_write = native_apic_icr_write,
- .wait_icr_idle = native_apic_wait_icr_idle,
- .safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
-
- .x86_32_early_logical_apicid = es7000_early_logical_apicid,
-};
-
-static struct apic __refdata apic_es7000 = {
-
- .name = "es7000",
- .probe = probe_es7000,
- .acpi_madt_oem_check = es7000_acpi_madt_oem_check,
- .apic_id_valid = default_apic_id_valid,
- .apic_id_registered = es7000_apic_id_registered,
-
- .irq_delivery_mode = dest_Fixed,
- /* phys delivery to target CPUs: */
- .irq_dest_mode = 0,
-
- .target_cpus = es7000_target_cpus,
- .disable_esr = 1,
- .dest_logical = 0,
- .check_apicid_used = es7000_check_apicid_used,
- .check_apicid_present = es7000_check_apicid_present,
-
- .vector_allocation_domain = flat_vector_allocation_domain,
- .init_apic_ldr = es7000_init_apic_ldr,
-
- .ioapic_phys_id_map = es7000_ioapic_phys_id_map,
- .setup_apic_routing = es7000_setup_apic_routing,
- .multi_timer_check = NULL,
- .cpu_present_to_apicid = es7000_cpu_present_to_apicid,
- .apicid_to_cpu_present = es7000_apicid_to_cpu_present,
- .setup_portio_remap = NULL,
- .check_phys_apicid_present = es7000_check_phys_apicid_present,
- .enable_apic_mode = es7000_enable_apic_mode,
- .phys_pkg_id = es7000_phys_pkg_id,
- .mps_oem_check = es7000_mps_oem_check,
-
- .get_apic_id = es7000_get_apic_id,
- .set_apic_id = NULL,
- .apic_id_mask = 0xFF << 24,
-
- .cpu_mask_to_apicid_and = es7000_cpu_mask_to_apicid_and,
-
- .send_IPI_mask = es7000_send_IPI_mask,
- .send_IPI_mask_allbutself = NULL,
- .send_IPI_allbutself = es7000_send_IPI_allbutself,
- .send_IPI_all = es7000_send_IPI_all,
- .send_IPI_self = default_send_IPI_self,
-
- .trampoline_phys_low = 0x467,
- .trampoline_phys_high = 0x469,
-
- .wait_for_init_deassert = es7000_wait_for_init_deassert,
-
- /* Nothing to do for most platforms, since cleared by the INIT cycle: */
- .smp_callin_clear_local_apic = NULL,
- .inquire_remote_apic = default_inquire_remote_apic,
-
- .read = native_apic_mem_read,
- .write = native_apic_mem_write,
- .eoi_write = native_apic_mem_write,
- .icr_read = native_apic_icr_read,
- .icr_write = native_apic_icr_write,
- .wait_icr_idle = native_apic_wait_icr_idle,
- .safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
-
- .x86_32_early_logical_apicid = es7000_early_logical_apicid,
-};
-
-/*
- * Need to check for es7000 followed by es7000_cluster, so this order
- * in apic_drivers is important.
- */
-apic_drivers(apic_es7000, apic_es7000_cluster);
diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c
deleted file mode 100644
index 1e42e8f305ee..000000000000
--- a/arch/x86/kernel/apic/numaq_32.c
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * Written by: Patricia Gaughen, IBM Corporation
- *
- * Copyright (C) 2002, IBM Corp.
- * Copyright (C) 2009, Red Hat, Inc., Ingo Molnar
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to <gone@us.ibm.com>
- */
-#include <linux/nodemask.h>
-#include <linux/topology.h>
-#include <linux/bootmem.h>
-#include <linux/memblock.h>
-#include <linux/threads.h>
-#include <linux/cpumask.h>
-#include <linux/kernel.h>
-#include <linux/mmzone.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/numa.h>
-#include <linux/smp.h>
-#include <linux/io.h>
-#include <linux/mm.h>
-
-#include <asm/processor.h>
-#include <asm/fixmap.h>
-#include <asm/mpspec.h>
-#include <asm/numaq.h>
-#include <asm/setup.h>
-#include <asm/apic.h>
-#include <asm/e820.h>
-#include <asm/ipi.h>
-
-int found_numaq;
-
-/*
- * Have to match translation table entries to main table entries by counter
- * hence the mpc_record variable .... can't see a less disgusting way of
- * doing this ....
- */
-struct mpc_trans {
- unsigned char mpc_type;
- unsigned char trans_len;
- unsigned char trans_type;
- unsigned char trans_quad;
- unsigned char trans_global;
- unsigned char trans_local;
- unsigned short trans_reserved;
-};
-
-static int mpc_record;
-
-static struct mpc_trans *translation_table[MAX_MPC_ENTRY];
-
-int mp_bus_id_to_node[MAX_MP_BUSSES];
-int mp_bus_id_to_local[MAX_MP_BUSSES];
-int quad_local_to_mp_bus_id[NR_CPUS/4][4];
-
-
-static inline void numaq_register_node(int node, struct sys_cfg_data *scd)
-{
- struct eachquadmem *eq = scd->eq + node;
- u64 start = (u64)(eq->hi_shrd_mem_start - eq->priv_mem_size) << 20;
- u64 end = (u64)(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size) << 20;
- int ret;
-
- node_set(node, numa_nodes_parsed);
- ret = numa_add_memblk(node, start, end);
- BUG_ON(ret < 0);
-}
-
-/*
- * Function: smp_dump_qct()
- *
- * Description: gets memory layout from the quad config table. This
- * function also updates numa_nodes_parsed with the nodes (quads) present.
- */
-static void __init smp_dump_qct(void)
-{
- struct sys_cfg_data *scd;
- int node;
-
- scd = (void *)__va(SYS_CFG_DATA_PRIV_ADDR);
-
- for_each_node(node) {
- if (scd->quads_present31_0 & (1 << node))
- numaq_register_node(node, scd);
- }
-}
-
-void numaq_tsc_disable(void)
-{
- if (!found_numaq)
- return;
-
- if (num_online_nodes() > 1) {
- printk(KERN_DEBUG "NUMAQ: disabling TSC\n");
- setup_clear_cpu_cap(X86_FEATURE_TSC);
- }
-}
-
-static void __init numaq_tsc_init(void)
-{
- numaq_tsc_disable();
-}
-
-static inline int generate_logical_apicid(int quad, int phys_apicid)
-{
- return (quad << 4) + (phys_apicid ? phys_apicid << 1 : 1);
-}
-
-/* x86_quirks member */
-static int mpc_apic_id(struct mpc_cpu *m)
-{
- int quad = translation_table[mpc_record]->trans_quad;
- int logical_apicid = generate_logical_apicid(quad, m->apicid);
-
- printk(KERN_DEBUG
- "Processor #%d %u:%u APIC version %d (quad %d, apic %d)\n",
- m->apicid, (m->cpufeature & CPU_FAMILY_MASK) >> 8,
- (m->cpufeature & CPU_MODEL_MASK) >> 4,
- m->apicver, quad, logical_apicid);
-
- return logical_apicid;
-}
-
-/* x86_quirks member */
-static void mpc_oem_bus_info(struct mpc_bus *m, char *name)
-{
- int quad = translation_table[mpc_record]->trans_quad;
- int local = translation_table[mpc_record]->trans_local;
-
- mp_bus_id_to_node[m->busid] = quad;
- mp_bus_id_to_local[m->busid] = local;
-
- printk(KERN_INFO "Bus #%d is %s (node %d)\n", m->busid, name, quad);
-}
-
-/* x86_quirks member */
-static void mpc_oem_pci_bus(struct mpc_bus *m)
-{
- int quad = translation_table[mpc_record]->trans_quad;
- int local = translation_table[mpc_record]->trans_local;
-
- quad_local_to_mp_bus_id[quad][local] = m->busid;
-}
-
-/*
- * Called from mpparse code.
- * mode = 0: prescan
- * mode = 1: one mpc entry scanned
- */
-static void numaq_mpc_record(unsigned int mode)
-{
- if (!mode)
- mpc_record = 0;
- else
- mpc_record++;
-}
-
-static void __init MP_translation_info(struct mpc_trans *m)
-{
- printk(KERN_INFO
- "Translation: record %d, type %d, quad %d, global %d, local %d\n",
- mpc_record, m->trans_type, m->trans_quad, m->trans_global,
- m->trans_local);
-
- if (mpc_record >= MAX_MPC_ENTRY)
- printk(KERN_ERR "MAX_MPC_ENTRY exceeded!\n");
- else
- translation_table[mpc_record] = m; /* stash this for later */
-
- if (m->trans_quad < MAX_NUMNODES && !node_online(m->trans_quad))
- node_set_online(m->trans_quad);
-}
-
-static int __init mpf_checksum(unsigned char *mp, int len)
-{
- int sum = 0;
-
- while (len--)
- sum += *mp++;
-
- return sum & 0xFF;
-}
-
-/*
- * Read/parse the MPC oem tables
- */
-static void __init smp_read_mpc_oem(struct mpc_table *mpc)
-{
- struct mpc_oemtable *oemtable = (void *)(long)mpc->oemptr;
- int count = sizeof(*oemtable); /* the header size */
- unsigned char *oemptr = ((unsigned char *)oemtable) + count;
-
- mpc_record = 0;
- printk(KERN_INFO
- "Found an OEM MPC table at %8p - parsing it...\n", oemtable);
-
- if (memcmp(oemtable->signature, MPC_OEM_SIGNATURE, 4)) {
- printk(KERN_WARNING
- "SMP mpc oemtable: bad signature [%c%c%c%c]!\n",
- oemtable->signature[0], oemtable->signature[1],
- oemtable->signature[2], oemtable->signature[3]);
- return;
- }
-
- if (mpf_checksum((unsigned char *)oemtable, oemtable->length)) {
- printk(KERN_WARNING "SMP oem mptable: checksum error!\n");
- return;
- }
-
- while (count < oemtable->length) {
- switch (*oemptr) {
- case MP_TRANSLATION:
- {
- struct mpc_trans *m = (void *)oemptr;
-
- MP_translation_info(m);
- oemptr += sizeof(*m);
- count += sizeof(*m);
- ++mpc_record;
- break;
- }
- default:
- printk(KERN_WARNING
- "Unrecognised OEM table entry type! - %d\n",
- (int)*oemptr);
- return;
- }
- }
-}
-
-static __init void early_check_numaq(void)
-{
- /*
- * get boot-time SMP configuration:
- */
- if (smp_found_config)
- early_get_smp_config();
-
- if (found_numaq) {
- x86_init.mpparse.mpc_record = numaq_mpc_record;
- x86_init.mpparse.setup_ioapic_ids = x86_init_noop;
- x86_init.mpparse.mpc_apic_id = mpc_apic_id;
- x86_init.mpparse.smp_read_mpc_oem = smp_read_mpc_oem;
- x86_init.mpparse.mpc_oem_pci_bus = mpc_oem_pci_bus;
- x86_init.mpparse.mpc_oem_bus_info = mpc_oem_bus_info;
- x86_init.timers.tsc_pre_init = numaq_tsc_init;
- x86_init.pci.init = pci_numaq_init;
- }
-}
-
-int __init numaq_numa_init(void)
-{
- early_check_numaq();
- if (!found_numaq)
- return -ENOENT;
- smp_dump_qct();
-
- return 0;
-}
-
-#define NUMAQ_APIC_DFR_VALUE (APIC_DFR_CLUSTER)
-
-static inline unsigned int numaq_get_apic_id(unsigned long x)
-{
- return (x >> 24) & 0x0F;
-}
-
-static inline void numaq_send_IPI_mask(const struct cpumask *mask, int vector)
-{
- default_send_IPI_mask_sequence_logical(mask, vector);
-}
-
-static inline void numaq_send_IPI_allbutself(int vector)
-{
- default_send_IPI_mask_allbutself_logical(cpu_online_mask, vector);
-}
-
-static inline void numaq_send_IPI_all(int vector)
-{
- numaq_send_IPI_mask(cpu_online_mask, vector);
-}
-
-#define NUMAQ_TRAMPOLINE_PHYS_LOW (0x8)
-#define NUMAQ_TRAMPOLINE_PHYS_HIGH (0xa)
-
-/*
- * Because we use NMIs rather than the INIT-STARTUP sequence to
- * bootstrap the CPUs, the APIC may be in a weird state. Kick it:
- */
-static inline void numaq_smp_callin_clear_local_apic(void)
-{
- clear_local_APIC();
-}
-
-static inline const struct cpumask *numaq_target_cpus(void)
-{
- return cpu_all_mask;
-}
-
-static unsigned long numaq_check_apicid_used(physid_mask_t *map, int apicid)
-{
- return physid_isset(apicid, *map);
-}
-
-static inline unsigned long numaq_check_apicid_present(int bit)
-{
- return physid_isset(bit, phys_cpu_present_map);
-}
-
-static inline int numaq_apic_id_registered(void)
-{
- return 1;
-}
-
-static inline void numaq_init_apic_ldr(void)
-{
- /* Already done in NUMA-Q firmware */
-}
-
-static inline void numaq_setup_apic_routing(void)
-{
- printk(KERN_INFO
- "Enabling APIC mode: NUMA-Q. Using %d I/O APICs\n",
- nr_ioapics);
-}
-
-/*
- * Skip adding the timer int on secondary nodes, which causes
- * a small but painful rift in the time-space continuum.
- */
-static inline int numaq_multi_timer_check(int apic, int irq)
-{
- return apic != 0 && irq == 0;
-}
-
-static inline void numaq_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
-{
- /* We don't have a good way to do this yet - hack */
- return physids_promote(0xFUL, retmap);
-}
-
-/*
- * Supporting over 60 cpus on NUMA-Q requires a locality-dependent
- * cpu to APIC ID relation to properly interact with the intelligent
- * mode of the cluster controller.
- */
-static inline int numaq_cpu_present_to_apicid(int mps_cpu)
-{
- if (mps_cpu < 60)
- return ((mps_cpu >> 2) << 4) | (1 << (mps_cpu & 0x3));
- else
- return BAD_APICID;
-}
-
-static inline int numaq_apicid_to_node(int logical_apicid)
-{
- return logical_apicid >> 4;
-}
-
-static int numaq_numa_cpu_node(int cpu)
-{
- int logical_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
-
- if (logical_apicid != BAD_APICID)
- return numaq_apicid_to_node(logical_apicid);
- return NUMA_NO_NODE;
-}
-
-static void numaq_apicid_to_cpu_present(int logical_apicid, physid_mask_t *retmap)
-{
- int node = numaq_apicid_to_node(logical_apicid);
- int cpu = __ffs(logical_apicid & 0xf);
-
- physid_set_mask_of_physid(cpu + 4*node, retmap);
-}
-
-/* Where the IO area was mapped on multiquad, always 0 otherwise */
-void *xquad_portio;
-
-static inline int numaq_check_phys_apicid_present(int phys_apicid)
-{
- return 1;
-}
-
-/*
- * We use physical apicids here, not logical, so just return the default
- * physical broadcast to stop people from breaking us
- */
-static int
-numaq_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
- const struct cpumask *andmask,
- unsigned int *apicid)
-{
- *apicid = 0x0F;
- return 0;
-}
-
-/* No NUMA-Q box has a HT CPU, but it can't hurt to use the default code. */
-static inline int numaq_phys_pkg_id(int cpuid_apic, int index_msb)
-{
- return cpuid_apic >> index_msb;
-}
-
-static int
-numaq_mps_oem_check(struct mpc_table *mpc, char *oem, char *productid)
-{
- if (strncmp(oem, "IBM NUMA", 8))
- printk(KERN_ERR "Warning! Not a NUMA-Q system!\n");
- else
- found_numaq = 1;
-
- return found_numaq;
-}
-
-static int probe_numaq(void)
-{
- /* already know from get_memcfg_numaq() */
- return found_numaq;
-}
-
-static void numaq_setup_portio_remap(void)
-{
- int num_quads = num_online_nodes();
-
- if (num_quads <= 1)
- return;
-
- printk(KERN_INFO
- "Remapping cross-quad port I/O for %d quads\n", num_quads);
-
- xquad_portio = ioremap(XQUAD_PORTIO_BASE, num_quads*XQUAD_PORTIO_QUAD);
-
- printk(KERN_INFO
- "xquad_portio vaddr 0x%08lx, len %08lx\n",
- (u_long) xquad_portio, (u_long) num_quads*XQUAD_PORTIO_QUAD);
-}
-
-/* Use __refdata to keep false positive warning calm. */
-static struct apic __refdata apic_numaq = {
-
- .name = "NUMAQ",
- .probe = probe_numaq,
- .acpi_madt_oem_check = NULL,
- .apic_id_valid = default_apic_id_valid,
- .apic_id_registered = numaq_apic_id_registered,
-
- .irq_delivery_mode = dest_LowestPrio,
- /* physical delivery on LOCAL quad: */
- .irq_dest_mode = 0,
-
- .target_cpus = numaq_target_cpus,
- .disable_esr = 1,
- .dest_logical = APIC_DEST_LOGICAL,
- .check_apicid_used = numaq_check_apicid_used,
- .check_apicid_present = numaq_check_apicid_present,
-
- .vector_allocation_domain = flat_vector_allocation_domain,
- .init_apic_ldr = numaq_init_apic_ldr,
-
- .ioapic_phys_id_map = numaq_ioapic_phys_id_map,
- .setup_apic_routing = numaq_setup_apic_routing,
- .multi_timer_check = numaq_multi_timer_check,
- .cpu_present_to_apicid = numaq_cpu_present_to_apicid,
- .apicid_to_cpu_present = numaq_apicid_to_cpu_present,
- .setup_portio_remap = numaq_setup_portio_remap,
- .check_phys_apicid_present = numaq_check_phys_apicid_present,
- .enable_apic_mode = NULL,
- .phys_pkg_id = numaq_phys_pkg_id,
- .mps_oem_check = numaq_mps_oem_check,
-
- .get_apic_id = numaq_get_apic_id,
- .set_apic_id = NULL,
- .apic_id_mask = 0x0F << 24,
-
- .cpu_mask_to_apicid_and = numaq_cpu_mask_to_apicid_and,
-
- .send_IPI_mask = numaq_send_IPI_mask,
- .send_IPI_mask_allbutself = NULL,
- .send_IPI_allbutself = numaq_send_IPI_allbutself,
- .send_IPI_all = numaq_send_IPI_all,
- .send_IPI_self = default_send_IPI_self,
-
- .wakeup_secondary_cpu = wakeup_secondary_cpu_via_nmi,
- .trampoline_phys_low = NUMAQ_TRAMPOLINE_PHYS_LOW,
- .trampoline_phys_high = NUMAQ_TRAMPOLINE_PHYS_HIGH,
-
- /* We don't do anything here because we use NMI's to boot instead */
- .wait_for_init_deassert = NULL,
-
- .smp_callin_clear_local_apic = numaq_smp_callin_clear_local_apic,
- .inquire_remote_apic = NULL,
-
- .read = native_apic_mem_read,
- .write = native_apic_mem_write,
- .eoi_write = native_apic_mem_write,
- .icr_read = native_apic_icr_read,
- .icr_write = native_apic_icr_write,
- .wait_icr_idle = native_apic_wait_icr_idle,
- .safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
-
- .x86_32_early_logical_apicid = noop_x86_32_early_logical_apicid,
- .x86_32_numa_cpu_node = numaq_numa_cpu_node,
-};
-
-apic_driver(apic_numaq);
diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c
index eb35ef9ee63f..cceb352c968c 100644
--- a/arch/x86/kernel/apic/probe_32.c
+++ b/arch/x86/kernel/apic/probe_32.c
@@ -119,8 +119,7 @@ static struct apic apic_default = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = default_wait_for_init_deassert,
-
+ .wait_for_init_deassert = true,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = default_inquire_remote_apic,
diff --git a/arch/x86/kernel/apic/summit_32.c b/arch/x86/kernel/apic/summit_32.c
deleted file mode 100644
index 00146f9b0254..000000000000
--- a/arch/x86/kernel/apic/summit_32.c
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * IBM Summit-Specific Code
- *
- * Written By: Matthew Dobson, IBM Corporation
- *
- * Copyright (c) 2003 IBM Corp.
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to <colpatch@us.ibm.com>
- *
- */
-
-#define pr_fmt(fmt) "summit: %s: " fmt, __func__
-
-#include <linux/mm.h>
-#include <asm/io.h>
-#include <asm/bios_ebda.h>
-
-/*
- * APIC driver for the IBM "Summit" chipset.
- */
-#include <linux/threads.h>
-#include <linux/cpumask.h>
-#include <asm/mpspec.h>
-#include <asm/apic.h>
-#include <asm/smp.h>
-#include <asm/fixmap.h>
-#include <asm/apicdef.h>
-#include <asm/ipi.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/gfp.h>
-#include <linux/smp.h>
-
-static unsigned summit_get_apic_id(unsigned long x)
-{
- return (x >> 24) & 0xFF;
-}
-
-static inline void summit_send_IPI_mask(const struct cpumask *mask, int vector)
-{
- default_send_IPI_mask_sequence_logical(mask, vector);
-}
-
-static void summit_send_IPI_allbutself(int vector)
-{
- default_send_IPI_mask_allbutself_logical(cpu_online_mask, vector);
-}
-
-static void summit_send_IPI_all(int vector)
-{
- summit_send_IPI_mask(cpu_online_mask, vector);
-}
-
-#include <asm/tsc.h>
-
-extern int use_cyclone;
-
-#ifdef CONFIG_X86_SUMMIT_NUMA
-static void setup_summit(void);
-#else
-static inline void setup_summit(void) {}
-#endif
-
-static int summit_mps_oem_check(struct mpc_table *mpc, char *oem,
- char *productid)
-{
- if (!strncmp(oem, "IBM ENSW", 8) &&
- (!strncmp(productid, "VIGIL SMP", 9)
- || !strncmp(productid, "EXA", 3)
- || !strncmp(productid, "RUTHLESS SMP", 12))){
- mark_tsc_unstable("Summit based system");
- use_cyclone = 1; /*enable cyclone-timer*/
- setup_summit();
- return 1;
- }
- return 0;
-}
-
-/* Hook from generic ACPI tables.c */
-static int summit_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
- if (!strncmp(oem_id, "IBM", 3) &&
- (!strncmp(oem_table_id, "SERVIGIL", 8)
- || !strncmp(oem_table_id, "EXA", 3))){
- mark_tsc_unstable("Summit based system");
- use_cyclone = 1; /*enable cyclone-timer*/
- setup_summit();
- return 1;
- }
- return 0;
-}
-
-struct rio_table_hdr {
- unsigned char version; /* Version number of this data structure */
- /* Version 3 adds chassis_num & WP_index */
- unsigned char num_scal_dev; /* # of Scalability devices (Twisters for Vigil) */
- unsigned char num_rio_dev; /* # of RIO I/O devices (Cyclones and Winnipegs) */
-} __attribute__((packed));
-
-struct scal_detail {
- unsigned char node_id; /* Scalability Node ID */
- unsigned long CBAR; /* Address of 1MB register space */
- unsigned char port0node; /* Node ID port connected to: 0xFF=None */
- unsigned char port0port; /* Port num port connected to: 0,1,2, or 0xFF=None */
- unsigned char port1node; /* Node ID port connected to: 0xFF = None */
- unsigned char port1port; /* Port num port connected to: 0,1,2, or 0xFF=None */
- unsigned char port2node; /* Node ID port connected to: 0xFF = None */
- unsigned char port2port; /* Port num port connected to: 0,1,2, or 0xFF=None */
- unsigned char chassis_num; /* 1 based Chassis number (1 = boot node) */
-} __attribute__((packed));
-
-struct rio_detail {
- unsigned char node_id; /* RIO Node ID */
- unsigned long BBAR; /* Address of 1MB register space */
- unsigned char type; /* Type of device */
- unsigned char owner_id; /* For WPEG: Node ID of Cyclone that owns this WPEG*/
- /* For CYC: Node ID of Twister that owns this CYC */
- unsigned char port0node; /* Node ID port connected to: 0xFF=None */
- unsigned char port0port; /* Port num port connected to: 0,1,2, or 0xFF=None */
- unsigned char port1node; /* Node ID port connected to: 0xFF=None */
- unsigned char port1port; /* Port num port connected to: 0,1,2, or 0xFF=None */
- unsigned char first_slot; /* For WPEG: Lowest slot number below this WPEG */
- /* For CYC: 0 */
- unsigned char status; /* For WPEG: Bit 0 = 1 : the XAPIC is used */
- /* = 0 : the XAPIC is not used, ie:*/
- /* ints fwded to another XAPIC */
- /* Bits1:7 Reserved */
- /* For CYC: Bits0:7 Reserved */
- unsigned char WP_index; /* For WPEG: WPEG instance index - lower ones have */
- /* lower slot numbers/PCI bus numbers */
- /* For CYC: No meaning */
- unsigned char chassis_num; /* 1 based Chassis number */
- /* For LookOut WPEGs this field indicates the */
- /* Expansion Chassis #, enumerated from Boot */
- /* Node WPEG external port, then Boot Node CYC */
- /* external port, then Next Vigil chassis WPEG */
- /* external port, etc. */
- /* Shared Lookouts have only 1 chassis number (the */
- /* first one assigned) */
-} __attribute__((packed));
-
-
-typedef enum {
- CompatTwister = 0, /* Compatibility Twister */
- AltTwister = 1, /* Alternate Twister of internal 8-way */
- CompatCyclone = 2, /* Compatibility Cyclone */
- AltCyclone = 3, /* Alternate Cyclone of internal 8-way */
- CompatWPEG = 4, /* Compatibility WPEG */
- AltWPEG = 5, /* Second Planar WPEG */
- LookOutAWPEG = 6, /* LookOut WPEG */
- LookOutBWPEG = 7, /* LookOut WPEG */
-} node_type;
-
-static inline int is_WPEG(struct rio_detail *rio){
- return (rio->type == CompatWPEG || rio->type == AltWPEG ||
- rio->type == LookOutAWPEG || rio->type == LookOutBWPEG);
-}
-
-#define SUMMIT_APIC_DFR_VALUE (APIC_DFR_CLUSTER)
-
-static const struct cpumask *summit_target_cpus(void)
-{
- /* CPU_MASK_ALL (0xff) has undefined behaviour with
- * dest_LowestPrio mode logical clustered apic interrupt routing
- * Just start on cpu 0. IRQ balancing will spread load
- */
- return cpumask_of(0);
-}
-
-static unsigned long summit_check_apicid_used(physid_mask_t *map, int apicid)
-{
- return 0;
-}
-
-/* we don't use the phys_cpu_present_map to indicate apicid presence */
-static unsigned long summit_check_apicid_present(int bit)
-{
- return 1;
-}
-
-static int summit_early_logical_apicid(int cpu)
-{
- int count = 0;
- u8 my_id = early_per_cpu(x86_cpu_to_apicid, cpu);
- u8 my_cluster = APIC_CLUSTER(my_id);
-#ifdef CONFIG_SMP
- u8 lid;
- int i;
-
- /* Create logical APIC IDs by counting CPUs already in cluster. */
- for (count = 0, i = nr_cpu_ids; --i >= 0; ) {
- lid = early_per_cpu(x86_cpu_to_logical_apicid, i);
- if (lid != BAD_APICID && APIC_CLUSTER(lid) == my_cluster)
- ++count;
- }
-#endif
- /* We only have a 4 wide bitmap in cluster mode. If a deranged
- * BIOS puts 5 CPUs in one APIC cluster, we're hosed. */
- BUG_ON(count >= XAPIC_DEST_CPUS_SHIFT);
- return my_cluster | (1UL << count);
-}
-
-static void summit_init_apic_ldr(void)
-{
- int cpu = smp_processor_id();
- unsigned long id = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
- unsigned long val;
-
- apic_write(APIC_DFR, SUMMIT_APIC_DFR_VALUE);
- val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
- val |= SET_APIC_LOGICAL_ID(id);
- apic_write(APIC_LDR, val);
-}
-
-static int summit_apic_id_registered(void)
-{
- return 1;
-}
-
-static void summit_setup_apic_routing(void)
-{
- pr_info("Enabling APIC mode: Summit. Using %d I/O APICs\n",
- nr_ioapics);
-}
-
-static int summit_cpu_present_to_apicid(int mps_cpu)
-{
- if (mps_cpu < nr_cpu_ids)
- return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
- else
- return BAD_APICID;
-}
-
-static void summit_ioapic_phys_id_map(physid_mask_t *phys_id_map, physid_mask_t *retmap)
-{
- /* For clustered we don't have a good way to do this yet - hack */
- physids_promote(0x0FL, retmap);
-}
-
-static void summit_apicid_to_cpu_present(int apicid, physid_mask_t *retmap)
-{
- physid_set_mask_of_physid(0, retmap);
-}
-
-static int summit_check_phys_apicid_present(int physical_apicid)
-{
- return 1;
-}
-
-static inline int
-summit_cpu_mask_to_apicid(const struct cpumask *cpumask, unsigned int *dest_id)
-{
- unsigned int round = 0;
- unsigned int cpu, apicid = 0;
-
- /*
- * The cpus in the mask must all be on the apic cluster.
- */
- for_each_cpu_and(cpu, cpumask, cpu_online_mask) {
- int new_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
-
- if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) {
- pr_err("Not a valid mask!\n");
- return -EINVAL;
- }
- apicid |= new_apicid;
- round++;
- }
- if (!round)
- return -EINVAL;
- *dest_id = apicid;
- return 0;
-}
-
-static int
-summit_cpu_mask_to_apicid_and(const struct cpumask *inmask,
- const struct cpumask *andmask,
- unsigned int *apicid)
-{
- cpumask_var_t cpumask;
- *apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
-
- if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC))
- return 0;
-
- cpumask_and(cpumask, inmask, andmask);
- summit_cpu_mask_to_apicid(cpumask, apicid);
-
- free_cpumask_var(cpumask);
-
- return 0;
-}
-
-/*
- * cpuid returns the value latched in the HW at reset, not the APIC ID
- * register's value. For any box whose BIOS changes APIC IDs, like
- * clustered APIC systems, we must use hard_smp_processor_id.
- *
- * See Intel's IA-32 SW Dev's Manual Vol2 under CPUID.
- */
-static int summit_phys_pkg_id(int cpuid_apic, int index_msb)
-{
- return hard_smp_processor_id() >> index_msb;
-}
-
-static int probe_summit(void)
-{
- /* probed later in mptable/ACPI hooks */
- return 0;
-}
-
-#ifdef CONFIG_X86_SUMMIT_NUMA
-static struct rio_table_hdr *rio_table_hdr;
-static struct scal_detail *scal_devs[MAX_NUMNODES];
-static struct rio_detail *rio_devs[MAX_NUMNODES*4];
-
-#ifndef CONFIG_X86_NUMAQ
-static int mp_bus_id_to_node[MAX_MP_BUSSES];
-#endif
-
-static int setup_pci_node_map_for_wpeg(int wpeg_num, int last_bus)
-{
- int twister = 0, node = 0;
- int i, bus, num_buses;
-
- for (i = 0; i < rio_table_hdr->num_rio_dev; i++) {
- if (rio_devs[i]->node_id == rio_devs[wpeg_num]->owner_id) {
- twister = rio_devs[i]->owner_id;
- break;
- }
- }
- if (i == rio_table_hdr->num_rio_dev) {
- pr_err("Couldn't find owner Cyclone for Winnipeg!\n");
- return last_bus;
- }
-
- for (i = 0; i < rio_table_hdr->num_scal_dev; i++) {
- if (scal_devs[i]->node_id == twister) {
- node = scal_devs[i]->node_id;
- break;
- }
- }
- if (i == rio_table_hdr->num_scal_dev) {
- pr_err("Couldn't find owner Twister for Cyclone!\n");
- return last_bus;
- }
-
- switch (rio_devs[wpeg_num]->type) {
- case CompatWPEG:
- /*
- * The Compatibility Winnipeg controls the 2 legacy buses,
- * the 66MHz PCI bus [2 slots] and the 2 "extra" buses in case
- * a PCI-PCI bridge card is used in either slot: total 5 buses.
- */
- num_buses = 5;
- break;
- case AltWPEG:
- /*
- * The Alternate Winnipeg controls the 2 133MHz buses [1 slot
- * each], their 2 "extra" buses, the 100MHz bus [2 slots] and
- * the "extra" buses for each of those slots: total 7 buses.
- */
- num_buses = 7;
- break;
- case LookOutAWPEG:
- case LookOutBWPEG:
- /*
- * A Lookout Winnipeg controls 3 100MHz buses [2 slots each]
- * & the "extra" buses for each of those slots: total 9 buses.
- */
- num_buses = 9;
- break;
- default:
- pr_info("Unsupported Winnipeg type!\n");
- return last_bus;
- }
-
- for (bus = last_bus; bus < last_bus + num_buses; bus++)
- mp_bus_id_to_node[bus] = node;
- return bus;
-}
-
-static int build_detail_arrays(void)
-{
- unsigned long ptr;
- int i, scal_detail_size, rio_detail_size;
-
- if (rio_table_hdr->num_scal_dev > MAX_NUMNODES) {
- pr_warn("MAX_NUMNODES too low! Defined as %d, but system has %d nodes\n",
- MAX_NUMNODES, rio_table_hdr->num_scal_dev);
- return 0;
- }
-
- switch (rio_table_hdr->version) {
- default:
- pr_warn("Invalid Rio Grande Table Version: %d\n",
- rio_table_hdr->version);
- return 0;
- case 2:
- scal_detail_size = 11;
- rio_detail_size = 13;
- break;
- case 3:
- scal_detail_size = 12;
- rio_detail_size = 15;
- break;
- }
-
- ptr = (unsigned long)rio_table_hdr + 3;
- for (i = 0; i < rio_table_hdr->num_scal_dev; i++, ptr += scal_detail_size)
- scal_devs[i] = (struct scal_detail *)ptr;
-
- for (i = 0; i < rio_table_hdr->num_rio_dev; i++, ptr += rio_detail_size)
- rio_devs[i] = (struct rio_detail *)ptr;
-
- return 1;
-}
-
-void setup_summit(void)
-{
- unsigned long ptr;
- unsigned short offset;
- int i, next_wpeg, next_bus = 0;
-
- /* The pointer to the EBDA is stored in the word @ phys 0x40E(40:0E) */
- ptr = get_bios_ebda();
- ptr = (unsigned long)phys_to_virt(ptr);
-
- rio_table_hdr = NULL;
- offset = 0x180;
- while (offset) {
- /* The block id is stored in the 2nd word */
- if (*((unsigned short *)(ptr + offset + 2)) == 0x4752) {
- /* set the pointer past the offset & block id */
- rio_table_hdr = (struct rio_table_hdr *)(ptr + offset + 4);
- break;
- }
- /* The next offset is stored in the 1st word. 0 means no more */
- offset = *((unsigned short *)(ptr + offset));
- }
- if (!rio_table_hdr) {
- pr_err("Unable to locate Rio Grande Table in EBDA - bailing!\n");
- return;
- }
-
- if (!build_detail_arrays())
- return;
-
- /* The first Winnipeg we're looking for has an index of 0 */
- next_wpeg = 0;
- do {
- for (i = 0; i < rio_table_hdr->num_rio_dev; i++) {
- if (is_WPEG(rio_devs[i]) && rio_devs[i]->WP_index == next_wpeg) {
- /* It's the Winnipeg we're looking for! */
- next_bus = setup_pci_node_map_for_wpeg(i, next_bus);
- next_wpeg++;
- break;
- }
- }
- /*
- * If we go through all Rio devices and don't find one with
- * the next index, it means we've found all the Winnipegs,
- * and thus all the PCI buses.
- */
- if (i == rio_table_hdr->num_rio_dev)
- next_wpeg = 0;
- } while (next_wpeg != 0);
-}
-#endif
-
-static struct apic apic_summit = {
-
- .name = "summit",
- .probe = probe_summit,
- .acpi_madt_oem_check = summit_acpi_madt_oem_check,
- .apic_id_valid = default_apic_id_valid,
- .apic_id_registered = summit_apic_id_registered,
-
- .irq_delivery_mode = dest_LowestPrio,
- /* logical delivery broadcast to all CPUs: */
- .irq_dest_mode = 1,
-
- .target_cpus = summit_target_cpus,
- .disable_esr = 1,
- .dest_logical = APIC_DEST_LOGICAL,
- .check_apicid_used = summit_check_apicid_used,
- .check_apicid_present = summit_check_apicid_present,
-
- .vector_allocation_domain = flat_vector_allocation_domain,
- .init_apic_ldr = summit_init_apic_ldr,
-
- .ioapic_phys_id_map = summit_ioapic_phys_id_map,
- .setup_apic_routing = summit_setup_apic_routing,
- .multi_timer_check = NULL,
- .cpu_present_to_apicid = summit_cpu_present_to_apicid,
- .apicid_to_cpu_present = summit_apicid_to_cpu_present,
- .setup_portio_remap = NULL,
- .check_phys_apicid_present = summit_check_phys_apicid_present,
- .enable_apic_mode = NULL,
- .phys_pkg_id = summit_phys_pkg_id,
- .mps_oem_check = summit_mps_oem_check,
-
- .get_apic_id = summit_get_apic_id,
- .set_apic_id = NULL,
- .apic_id_mask = 0xFF << 24,
-
- .cpu_mask_to_apicid_and = summit_cpu_mask_to_apicid_and,
-
- .send_IPI_mask = summit_send_IPI_mask,
- .send_IPI_mask_allbutself = NULL,
- .send_IPI_allbutself = summit_send_IPI_allbutself,
- .send_IPI_all = summit_send_IPI_all,
- .send_IPI_self = default_send_IPI_self,
-
- .trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
- .trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
-
- .wait_for_init_deassert = default_wait_for_init_deassert,
-
- .smp_callin_clear_local_apic = NULL,
- .inquire_remote_apic = default_inquire_remote_apic,
-
- .read = native_apic_mem_read,
- .write = native_apic_mem_write,
- .eoi_write = native_apic_mem_write,
- .icr_read = native_apic_icr_read,
- .icr_write = native_apic_icr_write,
- .wait_icr_idle = native_apic_wait_icr_idle,
- .safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
-
- .x86_32_early_logical_apicid = summit_early_logical_apicid,
-};
-
-apic_driver(apic_summit);
diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c
index cac85ee6913f..e66766bf1641 100644
--- a/arch/x86/kernel/apic/x2apic_cluster.c
+++ b/arch/x86/kernel/apic/x2apic_cluster.c
@@ -279,7 +279,7 @@ static struct apic apic_x2apic_cluster = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = NULL,
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
index de231e328cae..6d600ebf6c12 100644
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -133,7 +133,7 @@ static struct apic apic_x2apic_phys = {
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = NULL,
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index d263b1307de1..7834389ba5be 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -396,7 +396,7 @@ static struct apic __refdata apic_x2apic_uv_x = {
.wakeup_secondary_cpu = uv_wakeup_secondary,
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
- .wait_for_init_deassert = NULL,
+ .wait_for_init_deassert = false,
.smp_callin_clear_local_apic = NULL,
.inquire_remote_apic = NULL,
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index c67ffa686064..ce8b8ff0e0ef 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -218,7 +218,7 @@ static void amd_k7_smp_check(struct cpuinfo_x86 *c)
*/
WARN_ONCE(1, "WARNING: This combination of AMD"
" processors is not suitable for SMP.\n");
- add_taint(TAINT_UNSAFE_SMP, LOCKDEP_NOW_UNRELIABLE);
+ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_NOW_UNRELIABLE);
}
static void init_amd_k7(struct cpuinfo_x86 *c)
@@ -233,9 +233,7 @@ static void init_amd_k7(struct cpuinfo_x86 *c)
if (c->x86_model >= 6 && c->x86_model <= 10) {
if (!cpu_has(c, X86_FEATURE_XMM)) {
printk(KERN_INFO "Enabling disabled K7/SSE Support.\n");
- rdmsr(MSR_K7_HWCR, l, h);
- l &= ~0x00008000;
- wrmsr(MSR_K7_HWCR, l, h);
+ msr_clear_bit(MSR_K7_HWCR, 15);
set_cpu_cap(c, X86_FEATURE_XMM);
}
}
@@ -509,14 +507,8 @@ static void early_init_amd(struct cpuinfo_x86 *c)
#endif
/* F16h erratum 793, CVE-2013-6885 */
- if (c->x86 == 0x16 && c->x86_model <= 0xf) {
- u64 val;
-
- rdmsrl(MSR_AMD64_LS_CFG, val);
- if (!(val & BIT(15)))
- wrmsrl(MSR_AMD64_LS_CFG, val | BIT(15));
- }
-
+ if (c->x86 == 0x16 && c->x86_model <= 0xf)
+ msr_set_bit(MSR_AMD64_LS_CFG, 15);
}
static const int amd_erratum_383[];
@@ -536,11 +528,8 @@ static void init_amd(struct cpuinfo_x86 *c)
* Errata 63 for SH-B3 steppings
* Errata 122 for all steppings (F+ have it disabled by default)
*/
- if (c->x86 == 0xf) {
- rdmsrl(MSR_K7_HWCR, value);
- value |= 1 << 6;
- wrmsrl(MSR_K7_HWCR, value);
- }
+ if (c->x86 == 0xf)
+ msr_set_bit(MSR_K7_HWCR, 6);
#endif
early_init_amd(c);
@@ -623,14 +612,11 @@ static void init_amd(struct cpuinfo_x86 *c)
(c->x86_model >= 0x10) && (c->x86_model <= 0x1f) &&
!cpu_has(c, X86_FEATURE_TOPOEXT)) {
- if (!rdmsrl_safe(0xc0011005, &value)) {
- value |= 1ULL << 54;
- wrmsrl_safe(0xc0011005, value);
+ if (msr_set_bit(0xc0011005, 54) > 0) {
rdmsrl(0xc0011005, value);
- if (value & (1ULL << 54)) {
+ if (value & BIT_64(54)) {
set_cpu_cap(c, X86_FEATURE_TOPOEXT);
- printk(KERN_INFO FW_INFO "CPU: Re-enabling "
- "disabled Topology Extensions Support\n");
+ pr_info(FW_INFO "CPU: Re-enabling disabled Topology Extensions Support.\n");
}
}
}
@@ -709,19 +695,12 @@ static void init_amd(struct cpuinfo_x86 *c)
* Disable GART TLB Walk Errors on Fam10h. We do this here
* because this is always needed when GART is enabled, even in a
* kernel which has no MCE support built in.
- * BIOS should disable GartTlbWlk Errors themself. If
- * it doesn't do it here as suggested by the BKDG.
+ * BIOS should disable GartTlbWlk Errors already. If
+ * it doesn't, do it here as suggested by the BKDG.
*
* Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=33012
*/
- u64 mask;
- int err;
-
- err = rdmsrl_safe(MSR_AMD64_MCx_MASK(4), &mask);
- if (err == 0) {
- mask |= (1 << 10);
- wrmsrl_safe(MSR_AMD64_MCx_MASK(4), mask);
- }
+ msr_set_bit(MSR_AMD64_MCx_MASK(4), 10);
/*
* On family 10h BIOS may not have properly enabled WC+ support,
@@ -733,10 +712,7 @@ static void init_amd(struct cpuinfo_x86 *c)
* NOTE: we want to use the _safe accessors so as not to #GP kvm
* guests on older kvm hosts.
*/
-
- rdmsrl_safe(MSR_AMD64_BU_CFG2, &value);
- value &= ~(1ULL << 24);
- wrmsrl_safe(MSR_AMD64_BU_CFG2, value);
+ msr_clear_bit(MSR_AMD64_BU_CFG2, 24);
if (cpu_has_amd_erratum(c, amd_erratum_383))
set_cpu_bug(c, X86_BUG_AMD_TLB_MMATCH);
diff --git a/arch/x86/kernel/cpu/centaur.c b/arch/x86/kernel/cpu/centaur.c
index 8779edab684e..d8fba5c15fbd 100644
--- a/arch/x86/kernel/cpu/centaur.c
+++ b/arch/x86/kernel/cpu/centaur.c
@@ -8,236 +8,6 @@
#include "cpu.h"
-#ifdef CONFIG_X86_OOSTORE
-
-static u32 power2(u32 x)
-{
- u32 s = 1;
-
- while (s <= x)
- s <<= 1;
-
- return s >>= 1;
-}
-
-
-/*
- * Set up an actual MCR
- */
-static void centaur_mcr_insert(int reg, u32 base, u32 size, int key)
-{
- u32 lo, hi;
-
- hi = base & ~0xFFF;
- lo = ~(size-1); /* Size is a power of 2 so this makes a mask */
- lo &= ~0xFFF; /* Remove the ctrl value bits */
- lo |= key; /* Attribute we wish to set */
- wrmsr(reg+MSR_IDT_MCR0, lo, hi);
- mtrr_centaur_report_mcr(reg, lo, hi); /* Tell the mtrr driver */
-}
-
-/*
- * Figure what we can cover with MCR's
- *
- * Shortcut: We know you can't put 4Gig of RAM on a winchip
- */
-static u32 ramtop(void)
-{
- u32 clip = 0xFFFFFFFFUL;
- u32 top = 0;
- int i;
-
- for (i = 0; i < e820.nr_map; i++) {
- unsigned long start, end;
-
- if (e820.map[i].addr > 0xFFFFFFFFUL)
- continue;
- /*
- * Don't MCR over reserved space. Ignore the ISA hole
- * we frob around that catastrophe already
- */
- if (e820.map[i].type == E820_RESERVED) {
- if (e820.map[i].addr >= 0x100000UL &&
- e820.map[i].addr < clip)
- clip = e820.map[i].addr;
- continue;
- }
- start = e820.map[i].addr;
- end = e820.map[i].addr + e820.map[i].size;
- if (start >= end)
- continue;
- if (end > top)
- top = end;
- }
- /*
- * Everything below 'top' should be RAM except for the ISA hole.
- * Because of the limited MCR's we want to map NV/ACPI into our
- * MCR range for gunk in RAM
- *
- * Clip might cause us to MCR insufficient RAM but that is an
- * acceptable failure mode and should only bite obscure boxes with
- * a VESA hole at 15Mb
- *
- * The second case Clip sometimes kicks in is when the EBDA is marked
- * as reserved. Again we fail safe with reasonable results
- */
- if (top > clip)
- top = clip;
-
- return top;
-}
-
-/*
- * Compute a set of MCR's to give maximum coverage
- */
-static int centaur_mcr_compute(int nr, int key)
-{
- u32 mem = ramtop();
- u32 root = power2(mem);
- u32 base = root;
- u32 top = root;
- u32 floor = 0;
- int ct = 0;
-
- while (ct < nr) {
- u32 fspace = 0;
- u32 high;
- u32 low;
-
- /*
- * Find the largest block we will fill going upwards
- */
- high = power2(mem-top);
-
- /*
- * Find the largest block we will fill going downwards
- */
- low = base/2;
-
- /*
- * Don't fill below 1Mb going downwards as there
- * is an ISA hole in the way.
- */
- if (base <= 1024*1024)
- low = 0;
-
- /*
- * See how much space we could cover by filling below
- * the ISA hole
- */
-
- if (floor == 0)
- fspace = 512*1024;
- else if (floor == 512*1024)
- fspace = 128*1024;
-
- /* And forget ROM space */
-
- /*
- * Now install the largest coverage we get
- */
- if (fspace > high && fspace > low) {
- centaur_mcr_insert(ct, floor, fspace, key);
- floor += fspace;
- } else if (high > low) {
- centaur_mcr_insert(ct, top, high, key);
- top += high;
- } else if (low > 0) {
- base -= low;
- centaur_mcr_insert(ct, base, low, key);
- } else
- break;
- ct++;
- }
- /*
- * We loaded ct values. We now need to set the mask. The caller
- * must do this bit.
- */
- return ct;
-}
-
-static void centaur_create_optimal_mcr(void)
-{
- int used;
- int i;
-
- /*
- * Allocate up to 6 mcrs to mark as much of ram as possible
- * as write combining and weak write ordered.
- *
- * To experiment with: Linux never uses stack operations for
- * mmio spaces so we could globally enable stack operation wc
- *
- * Load the registers with type 31 - full write combining, all
- * writes weakly ordered.
- */
- used = centaur_mcr_compute(6, 31);
-
- /*
- * Wipe unused MCRs
- */
- for (i = used; i < 8; i++)
- wrmsr(MSR_IDT_MCR0+i, 0, 0);
-}
-
-static void winchip2_create_optimal_mcr(void)
-{
- u32 lo, hi;
- int used;
- int i;
-
- /*
- * Allocate up to 6 mcrs to mark as much of ram as possible
- * as write combining, weak store ordered.
- *
- * Load the registers with type 25
- * 8 - weak write ordering
- * 16 - weak read ordering
- * 1 - write combining
- */
- used = centaur_mcr_compute(6, 25);
-
- /*
- * Mark the registers we are using.
- */
- rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
- for (i = 0; i < used; i++)
- lo |= 1<<(9+i);
- wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-
- /*
- * Wipe unused MCRs
- */
-
- for (i = used; i < 8; i++)
- wrmsr(MSR_IDT_MCR0+i, 0, 0);
-}
-
-/*
- * Handle the MCR key on the Winchip 2.
- */
-static void winchip2_unprotect_mcr(void)
-{
- u32 lo, hi;
- u32 key;
-
- rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
- lo &= ~0x1C0; /* blank bits 8-6 */
- key = (lo>>17) & 7;
- lo |= key<<6; /* replace with unlock key */
- wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}
-
-static void winchip2_protect_mcr(void)
-{
- u32 lo, hi;
-
- rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
- lo &= ~0x1C0; /* blank bits 8-6 */
- wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}
-#endif /* CONFIG_X86_OOSTORE */
-
#define ACE_PRESENT (1 << 6)
#define ACE_ENABLED (1 << 7)
#define ACE_FCR (1 << 28) /* MSR_VIA_FCR */
@@ -362,20 +132,6 @@ static void init_centaur(struct cpuinfo_x86 *c)
fcr_clr = DPDC;
printk(KERN_NOTICE "Disabling bugged TSC.\n");
clear_cpu_cap(c, X86_FEATURE_TSC);
-#ifdef CONFIG_X86_OOSTORE
- centaur_create_optimal_mcr();
- /*
- * Enable:
- * write combining on non-stack, non-string
- * write combining on string, all types
- * weak write ordering
- *
- * The C6 original lacks weak read order
- *
- * Note 0x120 is write only on Winchip 1
- */
- wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0);
-#endif
break;
case 8:
switch (c->x86_mask) {
@@ -392,40 +148,12 @@ static void init_centaur(struct cpuinfo_x86 *c)
fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
E2MMX|EAMD3D;
fcr_clr = DPDC;
-#ifdef CONFIG_X86_OOSTORE
- winchip2_unprotect_mcr();
- winchip2_create_optimal_mcr();
- rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
- /*
- * Enable:
- * write combining on non-stack, non-string
- * write combining on string, all types
- * weak write ordering
- */
- lo |= 31;
- wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
- winchip2_protect_mcr();
-#endif
break;
case 9:
name = "3";
fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
E2MMX|EAMD3D;
fcr_clr = DPDC;
-#ifdef CONFIG_X86_OOSTORE
- winchip2_unprotect_mcr();
- winchip2_create_optimal_mcr();
- rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
- /*
- * Enable:
- * write combining on non-stack, non-string
- * write combining on string, all types
- * weak write ordering
- */
- lo |= 31;
- wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
- winchip2_protect_mcr();
-#endif
break;
default:
name = "??";
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 8e28bf2fc3ef..a135239badb7 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1025,7 +1025,8 @@ __setup("show_msr=", setup_show_msr);
static __init int setup_noclflush(char *arg)
{
- setup_clear_cpu_cap(X86_FEATURE_CLFLSH);
+ setup_clear_cpu_cap(X86_FEATURE_CLFLUSH);
+ setup_clear_cpu_cap(X86_FEATURE_CLFLUSHOPT);
return 1;
}
__setup("noclflush", setup_noclflush);
@@ -1078,6 +1079,10 @@ static __init int setup_disablecpuid(char *arg)
}
__setup("clearcpuid=", setup_disablecpuid);
+DEFINE_PER_CPU(unsigned long, kernel_stack) =
+ (unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE;
+EXPORT_PER_CPU_SYMBOL(kernel_stack);
+
#ifdef CONFIG_X86_64
struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table };
struct desc_ptr debug_idt_descr = { NR_VECTORS * 16 - 1,
@@ -1094,10 +1099,6 @@ DEFINE_PER_CPU(struct task_struct *, current_task) ____cacheline_aligned =
&init_task;
EXPORT_PER_CPU_SYMBOL(current_task);
-DEFINE_PER_CPU(unsigned long, kernel_stack) =
- (unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE;
-EXPORT_PER_CPU_SYMBOL(kernel_stack);
-
DEFINE_PER_CPU(char *, irq_stack_ptr) =
init_per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64;
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 5cd9bfabd645..a80029035bf2 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -31,11 +31,8 @@ static void early_init_intel(struct cpuinfo_x86 *c)
/* Unmask CPUID levels if masked: */
if (c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xd)) {
- rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
-
- if (misc_enable & MSR_IA32_MISC_ENABLE_LIMIT_CPUID) {
- misc_enable &= ~MSR_IA32_MISC_ENABLE_LIMIT_CPUID;
- wrmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
+ if (msr_clear_bit(MSR_IA32_MISC_ENABLE,
+ MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT) > 0) {
c->cpuid_level = cpuid_eax(0);
get_cpu_cap(c);
}
@@ -129,16 +126,10 @@ static void early_init_intel(struct cpuinfo_x86 *c)
* Ingo Molnar reported a Pentium D (model 6) and a Xeon
* (model 2) with the same problem.
*/
- if (c->x86 == 15) {
- rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
-
- if (misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING) {
- printk(KERN_INFO "kmemcheck: Disabling fast string operations\n");
-
- misc_enable &= ~MSR_IA32_MISC_ENABLE_FAST_STRING;
- wrmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
- }
- }
+ if (c->x86 == 15)
+ if (msr_clear_bit(MSR_IA32_MISC_ENABLE,
+ MSR_IA32_MISC_ENABLE_FAST_STRING_BIT) > 0)
+ pr_info("kmemcheck: Disabling fast string operations\n");
#endif
/*
@@ -195,10 +186,16 @@ static void intel_smp_check(struct cpuinfo_x86 *c)
}
}
-static void intel_workarounds(struct cpuinfo_x86 *c)
+static int forcepae;
+static int __init forcepae_setup(char *__unused)
{
- unsigned long lo, hi;
+ forcepae = 1;
+ return 1;
+}
+__setup("forcepae", forcepae_setup);
+static void intel_workarounds(struct cpuinfo_x86 *c)
+{
#ifdef CONFIG_X86_F00F_BUG
/*
* All current models of Pentium and Pentium with MMX technology CPUs
@@ -225,16 +222,26 @@ static void intel_workarounds(struct cpuinfo_x86 *c)
clear_cpu_cap(c, X86_FEATURE_SEP);
/*
+ * PAE CPUID issue: many Pentium M report no PAE but may have a
+ * functionally usable PAE implementation.
+ * Forcefully enable PAE if kernel parameter "forcepae" is present.
+ */
+ if (forcepae) {
+ printk(KERN_WARNING "PAE forced!\n");
+ set_cpu_cap(c, X86_FEATURE_PAE);
+ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_NOW_UNRELIABLE);
+ }
+
+ /*
* P4 Xeon errata 037 workaround.
* Hardware prefetcher may cause stale data to be loaded into the cache.
*/
if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) {
- rdmsr(MSR_IA32_MISC_ENABLE, lo, hi);
- if ((lo & MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE) == 0) {
- printk (KERN_INFO "CPU: C0 stepping P4 Xeon detected.\n");
- printk (KERN_INFO "CPU: Disabling hardware prefetching (Errata 037)\n");
- lo |= MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE;
- wrmsr(MSR_IA32_MISC_ENABLE, lo, hi);
+ if (msr_set_bit(MSR_IA32_MISC_ENABLE,
+ MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT)
+ > 0) {
+ pr_info("CPU: C0 stepping P4 Xeon detected.\n");
+ pr_info("CPU: Disabling hardware prefetching (Errata 037)\n");
}
}
@@ -267,10 +274,6 @@ static void intel_workarounds(struct cpuinfo_x86 *c)
}
#endif
-#ifdef CONFIG_X86_NUMAQ
- numaq_tsc_disable();
-#endif
-
intel_smp_check(c);
}
#else
diff --git a/arch/x86/kernel/cpu/match.c b/arch/x86/kernel/cpu/match.c
index 36565373af87..afa9f0d487ea 100644
--- a/arch/x86/kernel/cpu/match.c
+++ b/arch/x86/kernel/cpu/match.c
@@ -47,45 +47,3 @@ const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match)
return NULL;
}
EXPORT_SYMBOL(x86_match_cpu);
-
-ssize_t arch_print_cpu_modalias(struct device *dev,
- struct device_attribute *attr,
- char *bufptr)
-{
- int size = PAGE_SIZE;
- int i, n;
- char *buf = bufptr;
-
- n = snprintf(buf, size, "x86cpu:vendor:%04X:family:%04X:"
- "model:%04X:feature:",
- boot_cpu_data.x86_vendor,
- boot_cpu_data.x86,
- boot_cpu_data.x86_model);
- size -= n;
- buf += n;
- size -= 1;
- for (i = 0; i < NCAPINTS*32; i++) {
- if (boot_cpu_has(i)) {
- n = snprintf(buf, size, ",%04X", i);
- if (n >= size) {
- WARN(1, "x86 features overflow page\n");
- break;
- }
- size -= n;
- buf += n;
- }
- }
- *buf++ = '\n';
- return buf - bufptr;
-}
-
-int arch_cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
- if (buf) {
- arch_print_cpu_modalias(NULL, NULL, buf);
- add_uevent_var(env, "MODALIAS=%s", buf);
- kfree(buf);
- }
- return 0;
-}
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 9f7ca266864a..76f98fe5b35c 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -17,6 +17,7 @@
#include <linux/hardirq.h>
#include <linux/efi.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <asm/processor.h>
#include <asm/hypervisor.h>
#include <asm/hyperv.h>
@@ -26,10 +27,50 @@
#include <asm/irq_regs.h>
#include <asm/i8259.h>
#include <asm/apic.h>
+#include <asm/timer.h>
struct ms_hyperv_info ms_hyperv;
EXPORT_SYMBOL_GPL(ms_hyperv);
+#if IS_ENABLED(CONFIG_HYPERV)
+static void (*vmbus_handler)(void);
+
+void hyperv_vector_handler(struct pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+
+ irq_enter();
+ exit_idle();
+
+ inc_irq_stat(irq_hv_callback_count);
+ if (vmbus_handler)
+ vmbus_handler();
+
+ irq_exit();
+ set_irq_regs(old_regs);
+}
+
+void hv_setup_vmbus_irq(void (*handler)(void))
+{
+ vmbus_handler = handler;
+ /*
+ * Setup the IDT for hypervisor callback. Prevent reallocation
+ * at module reload.
+ */
+ if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors))
+ alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR,
+ hyperv_callback_vector);
+}
+
+void hv_remove_vmbus_irq(void)
+{
+ /* We have no way to deallocate the interrupt gate */
+ vmbus_handler = NULL;
+}
+EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq);
+EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq);
+#endif
+
static uint32_t __init ms_hyperv_platform(void)
{
u32 eax;
@@ -105,6 +146,11 @@ static void __init ms_hyperv_init_platform(void)
if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
+
+#ifdef CONFIG_X86_IO_APIC
+ no_timer_check = 1;
+#endif
+
}
const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
@@ -113,41 +159,3 @@ const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
.init_platform = ms_hyperv_init_platform,
};
EXPORT_SYMBOL(x86_hyper_ms_hyperv);
-
-#if IS_ENABLED(CONFIG_HYPERV)
-static int vmbus_irq = -1;
-static irq_handler_t vmbus_isr;
-
-void hv_register_vmbus_handler(int irq, irq_handler_t handler)
-{
- /*
- * Setup the IDT for hypervisor callback.
- */
- alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
-
- vmbus_irq = irq;
- vmbus_isr = handler;
-}
-
-void hyperv_vector_handler(struct pt_regs *regs)
-{
- struct pt_regs *old_regs = set_irq_regs(regs);
- struct irq_desc *desc;
-
- irq_enter();
- exit_idle();
-
- desc = irq_to_desc(vmbus_irq);
-
- if (desc)
- generic_handle_irq_desc(vmbus_irq, desc);
-
- irq_exit();
- set_irq_regs(old_regs);
-}
-#else
-void hv_register_vmbus_handler(int irq, irq_handler_t handler)
-{
-}
-#endif
-EXPORT_SYMBOL_GPL(hv_register_vmbus_handler);
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index b88645191fe5..ae407f7226c8 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -892,7 +892,6 @@ static void x86_pmu_enable(struct pmu *pmu)
* hw_perf_group_sched_in() or x86_pmu_enable()
*
* step1: save events moving to new counters
- * step2: reprogram moved events into new counters
*/
for (i = 0; i < n_running; i++) {
event = cpuc->event_list[i];
@@ -918,6 +917,9 @@ static void x86_pmu_enable(struct pmu *pmu)
x86_pmu_stop(event, PERF_EF_UPDATE);
}
+ /*
+ * step2: reprogram moved events into new counters
+ */
for (i = 0; i < cpuc->n_events; i++) {
event = cpuc->event_list[i];
hwc = &event->hw;
@@ -1043,7 +1045,7 @@ static int x86_pmu_add(struct perf_event *event, int flags)
/*
* If group events scheduling transaction was started,
* skip the schedulability test here, it will be performed
- * at commit time (->commit_txn) as a whole
+ * at commit time (->commit_txn) as a whole.
*/
if (cpuc->group_flag & PERF_EVENT_TXN)
goto done_collect;
@@ -1058,6 +1060,10 @@ static int x86_pmu_add(struct perf_event *event, int flags)
memcpy(cpuc->assign, assign, n*sizeof(int));
done_collect:
+ /*
+ * Commit the collect_events() state. See x86_pmu_del() and
+ * x86_pmu_*_txn().
+ */
cpuc->n_events = n;
cpuc->n_added += n - n0;
cpuc->n_txn += n - n0;
@@ -1183,25 +1189,38 @@ static void x86_pmu_del(struct perf_event *event, int flags)
* If we're called during a txn, we don't need to do anything.
* The events never got scheduled and ->cancel_txn will truncate
* the event_list.
+ *
+ * XXX assumes any ->del() called during a TXN will only be on
+ * an event added during that same TXN.
*/
if (cpuc->group_flag & PERF_EVENT_TXN)
return;
+ /*
+ * Not a TXN, therefore cleanup properly.
+ */
x86_pmu_stop(event, PERF_EF_UPDATE);
for (i = 0; i < cpuc->n_events; i++) {
- if (event == cpuc->event_list[i]) {
+ if (event == cpuc->event_list[i])
+ break;
+ }
- if (x86_pmu.put_event_constraints)
- x86_pmu.put_event_constraints(cpuc, event);
+ if (WARN_ON_ONCE(i == cpuc->n_events)) /* called ->del() without ->add() ? */
+ return;
- while (++i < cpuc->n_events)
- cpuc->event_list[i-1] = cpuc->event_list[i];
+ /* If we have a newly added event; make sure to decrease n_added. */
+ if (i >= cpuc->n_events - cpuc->n_added)
+ --cpuc->n_added;
+
+ if (x86_pmu.put_event_constraints)
+ x86_pmu.put_event_constraints(cpuc, event);
+
+ /* Delete the array entry. */
+ while (++i < cpuc->n_events)
+ cpuc->event_list[i-1] = cpuc->event_list[i];
+ --cpuc->n_events;
- --cpuc->n_events;
- break;
- }
- }
perf_event_update_userpage(event);
}
@@ -1521,6 +1540,8 @@ static int __init init_hw_perf_events(void)
pr_cont("%s PMU driver.\n", x86_pmu.name);
+ x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
+
for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next)
quirk->func();
@@ -1534,7 +1555,6 @@ static int __init init_hw_perf_events(void)
__EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1,
0, x86_pmu.num_counters, 0, 0);
- x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
x86_pmu_format_group.attrs = x86_pmu.format_attrs;
if (x86_pmu.event_attrs)
@@ -1594,7 +1614,8 @@ static void x86_pmu_cancel_txn(struct pmu *pmu)
{
__this_cpu_and(cpu_hw_events.group_flag, ~PERF_EVENT_TXN);
/*
- * Truncate the collected events.
+ * Truncate collected array by the number of events added in this
+ * transaction. See x86_pmu_add() and x86_pmu_*_txn().
*/
__this_cpu_sub(cpu_hw_events.n_added, __this_cpu_read(cpu_hw_events.n_txn));
__this_cpu_sub(cpu_hw_events.n_events, __this_cpu_read(cpu_hw_events.n_txn));
@@ -1605,6 +1626,8 @@ static void x86_pmu_cancel_txn(struct pmu *pmu)
* Commit group events scheduling transaction
* Perform the group schedulability test as a whole
* Return 0 if success
+ *
+ * Does not cancel the transaction on failure; expects the caller to do this.
*/
static int x86_pmu_commit_txn(struct pmu *pmu)
{
@@ -1820,9 +1843,12 @@ static ssize_t set_attr_rdpmc(struct device *cdev,
if (ret)
return ret;
+ if (x86_pmu.attr_rdpmc_broken)
+ return -ENOTSUPP;
+
if (!!val != !!x86_pmu.attr_rdpmc) {
x86_pmu.attr_rdpmc = !!val;
- smp_call_function(change_rdpmc, (void *)val, 1);
+ on_each_cpu(change_rdpmc, (void *)val, 1);
}
return count;
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index c1a861829d81..3b2f9bdd974b 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -130,9 +130,11 @@ struct cpu_hw_events {
unsigned long running[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
int enabled;
- int n_events;
- int n_added;
- int n_txn;
+ int n_events; /* the # of events in the below arrays */
+ int n_added; /* the # last events in the below arrays;
+ they've never been enabled yet */
+ int n_txn; /* the # last events in the below arrays;
+ added in the current transaction */
int assign[X86_PMC_IDX_MAX]; /* event to counter assignment */
u64 tags[X86_PMC_IDX_MAX];
struct perf_event *event_list[X86_PMC_IDX_MAX]; /* in enabled order */
@@ -409,6 +411,7 @@ struct x86_pmu {
/*
* sysfs attrs
*/
+ int attr_rdpmc_broken;
int attr_rdpmc;
struct attribute **format_attrs;
struct attribute **event_attrs;
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 0fa4f242f050..aa333d966886 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -1361,10 +1361,8 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
intel_pmu_disable_all();
handled = intel_pmu_drain_bts_buffer();
status = intel_pmu_get_status();
- if (!status) {
- intel_pmu_enable_all(0);
- return handled;
- }
+ if (!status)
+ goto done;
loops = 0;
again:
@@ -2310,10 +2308,7 @@ __init int intel_pmu_init(void)
if (version > 1)
x86_pmu.num_counters_fixed = max((int)edx.split.num_counters_fixed, 3);
- /*
- * v2 and above have a perf capabilities MSR
- */
- if (version > 1) {
+ if (boot_cpu_has(X86_FEATURE_PDCM)) {
u64 capabilities;
rdmsrl(MSR_IA32_PERF_CAPABILITIES, capabilities);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
index 29c248799ced..bd2253d40cff 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -66,6 +66,47 @@ DEFINE_UNCORE_FORMAT_ATTR(mask_vnw, mask_vnw, "config2:3-4");
DEFINE_UNCORE_FORMAT_ATTR(mask0, mask0, "config2:0-31");
DEFINE_UNCORE_FORMAT_ATTR(mask1, mask1, "config2:32-63");
+static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box);
+static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box);
+static void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event);
+static void uncore_pmu_event_read(struct perf_event *event);
+
+static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
+{
+ return container_of(event->pmu, struct intel_uncore_pmu, pmu);
+}
+
+static struct intel_uncore_box *
+uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
+{
+ struct intel_uncore_box *box;
+
+ box = *per_cpu_ptr(pmu->box, cpu);
+ if (box)
+ return box;
+
+ raw_spin_lock(&uncore_box_lock);
+ list_for_each_entry(box, &pmu->box_list, list) {
+ if (box->phys_id == topology_physical_package_id(cpu)) {
+ atomic_inc(&box->refcnt);
+ *per_cpu_ptr(pmu->box, cpu) = box;
+ break;
+ }
+ }
+ raw_spin_unlock(&uncore_box_lock);
+
+ return *per_cpu_ptr(pmu->box, cpu);
+}
+
+static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
+{
+ /*
+ * perf core schedules event on the basis of cpu, uncore events are
+ * collected by one of the cpus inside a physical package.
+ */
+ return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
+}
+
static u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
{
u64 count;
@@ -501,8 +542,11 @@ static struct extra_reg snbep_uncore_cbox_extra_regs[] = {
SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0x6),
SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0x6),
SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0x6),
SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x6),
SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x8),
SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x8),
@@ -1178,10 +1222,15 @@ static struct extra_reg ivt_uncore_cbox_extra_regs[] = {
SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x5134, 0xffff, 0xc),
SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0xc),
SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0xc),
SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
- SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0xc),
SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x10),
SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10),
SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10),
@@ -1631,6 +1680,349 @@ static struct intel_uncore_type *snb_msr_uncores[] = {
&snb_uncore_cbox,
NULL,
};
+
+enum {
+ SNB_PCI_UNCORE_IMC,
+};
+
+static struct uncore_event_desc snb_uncore_imc_events[] = {
+ INTEL_UNCORE_EVENT_DESC(data_reads, "event=0x01"),
+ INTEL_UNCORE_EVENT_DESC(data_reads.scale, "6.103515625e-5"),
+ INTEL_UNCORE_EVENT_DESC(data_reads.unit, "MiB"),
+
+ INTEL_UNCORE_EVENT_DESC(data_writes, "event=0x02"),
+ INTEL_UNCORE_EVENT_DESC(data_writes.scale, "6.103515625e-5"),
+ INTEL_UNCORE_EVENT_DESC(data_writes.unit, "MiB"),
+
+ { /* end: all zeroes */ },
+};
+
+#define SNB_UNCORE_PCI_IMC_EVENT_MASK 0xff
+#define SNB_UNCORE_PCI_IMC_BAR_OFFSET 0x48
+
+/* page size multiple covering all config regs */
+#define SNB_UNCORE_PCI_IMC_MAP_SIZE 0x6000
+
+#define SNB_UNCORE_PCI_IMC_DATA_READS 0x1
+#define SNB_UNCORE_PCI_IMC_DATA_READS_BASE 0x5050
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES 0x2
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE 0x5054
+#define SNB_UNCORE_PCI_IMC_CTR_BASE SNB_UNCORE_PCI_IMC_DATA_READS_BASE
+
+static struct attribute *snb_uncore_imc_formats_attr[] = {
+ &format_attr_event.attr,
+ NULL,
+};
+
+static struct attribute_group snb_uncore_imc_format_group = {
+ .name = "format",
+ .attrs = snb_uncore_imc_formats_attr,
+};
+
+static void snb_uncore_imc_init_box(struct intel_uncore_box *box)
+{
+ struct pci_dev *pdev = box->pci_dev;
+ int where = SNB_UNCORE_PCI_IMC_BAR_OFFSET;
+ resource_size_t addr;
+ u32 pci_dword;
+
+ pci_read_config_dword(pdev, where, &pci_dword);
+ addr = pci_dword;
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+ pci_read_config_dword(pdev, where + 4, &pci_dword);
+ addr |= ((resource_size_t)pci_dword << 32);
+#endif
+
+ addr &= ~(PAGE_SIZE - 1);
+
+ box->io_addr = ioremap(addr, SNB_UNCORE_PCI_IMC_MAP_SIZE);
+ box->hrtimer_duration = UNCORE_SNB_IMC_HRTIMER_INTERVAL;
+}
+
+static void snb_uncore_imc_enable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_disable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static void snb_uncore_imc_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ return (u64)*(unsigned int *)(box->io_addr + hwc->event_base);
+}
+
+/*
+ * custom event_init() function because we define our own fixed, free
+ * running counters, so we do not want to conflict with generic uncore
+ * logic. Also simplifies processing
+ */
+static int snb_uncore_imc_event_init(struct perf_event *event)
+{
+ struct intel_uncore_pmu *pmu;
+ struct intel_uncore_box *box;
+ struct hw_perf_event *hwc = &event->hw;
+ u64 cfg = event->attr.config & SNB_UNCORE_PCI_IMC_EVENT_MASK;
+ int idx, base;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ pmu = uncore_event_to_pmu(event);
+ /* no device found for this pmu */
+ if (pmu->func_id < 0)
+ return -ENOENT;
+
+ /* Sampling not supported yet */
+ if (hwc->sample_period)
+ return -EINVAL;
+
+ /* unsupported modes and filters */
+ if (event->attr.exclude_user ||
+ event->attr.exclude_kernel ||
+ event->attr.exclude_hv ||
+ event->attr.exclude_idle ||
+ event->attr.exclude_host ||
+ event->attr.exclude_guest ||
+ event->attr.sample_period) /* no sampling */
+ return -EINVAL;
+
+ /*
+ * Place all uncore events for a particular physical package
+ * onto a single cpu
+ */
+ if (event->cpu < 0)
+ return -EINVAL;
+
+ /* check only supported bits are set */
+ if (event->attr.config & ~SNB_UNCORE_PCI_IMC_EVENT_MASK)
+ return -EINVAL;
+
+ box = uncore_pmu_to_box(pmu, event->cpu);
+ if (!box || box->cpu < 0)
+ return -EINVAL;
+
+ event->cpu = box->cpu;
+
+ event->hw.idx = -1;
+ event->hw.last_tag = ~0ULL;
+ event->hw.extra_reg.idx = EXTRA_REG_NONE;
+ event->hw.branch_reg.idx = EXTRA_REG_NONE;
+ /*
+ * check event is known (whitelist, determines counter)
+ */
+ switch (cfg) {
+ case SNB_UNCORE_PCI_IMC_DATA_READS:
+ base = SNB_UNCORE_PCI_IMC_DATA_READS_BASE;
+ idx = UNCORE_PMC_IDX_FIXED;
+ break;
+ case SNB_UNCORE_PCI_IMC_DATA_WRITES:
+ base = SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE;
+ idx = UNCORE_PMC_IDX_FIXED + 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* must be done before validate_group */
+ event->hw.event_base = base;
+ event->hw.config = cfg;
+ event->hw.idx = idx;
+
+ /* no group validation needed, we have free running counters */
+
+ return 0;
+}
+
+static int snb_uncore_imc_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+ return 0;
+}
+
+static void snb_uncore_imc_event_start(struct perf_event *event, int flags)
+{
+ struct intel_uncore_box *box = uncore_event_to_box(event);
+ u64 count;
+
+ if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+ return;
+
+ event->hw.state = 0;
+ box->n_active++;
+
+ list_add_tail(&event->active_entry, &box->active_list);
+
+ count = snb_uncore_imc_read_counter(box, event);
+ local64_set(&event->hw.prev_count, count);
+
+ if (box->n_active == 1)
+ uncore_pmu_start_hrtimer(box);
+}
+
+static void snb_uncore_imc_event_stop(struct perf_event *event, int flags)
+{
+ struct intel_uncore_box *box = uncore_event_to_box(event);
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (!(hwc->state & PERF_HES_STOPPED)) {
+ box->n_active--;
+
+ WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+ hwc->state |= PERF_HES_STOPPED;
+
+ list_del(&event->active_entry);
+
+ if (box->n_active == 0)
+ uncore_pmu_cancel_hrtimer(box);
+ }
+
+ if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+ /*
+ * Drain the remaining delta count out of a event
+ * that we are disabling:
+ */
+ uncore_perf_event_update(box, event);
+ hwc->state |= PERF_HES_UPTODATE;
+ }
+}
+
+static int snb_uncore_imc_event_add(struct perf_event *event, int flags)
+{
+ struct intel_uncore_box *box = uncore_event_to_box(event);
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (!box)
+ return -ENODEV;
+
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+ if (!(flags & PERF_EF_START))
+ hwc->state |= PERF_HES_ARCH;
+
+ snb_uncore_imc_event_start(event, 0);
+
+ box->n_events++;
+
+ return 0;
+}
+
+static void snb_uncore_imc_event_del(struct perf_event *event, int flags)
+{
+ struct intel_uncore_box *box = uncore_event_to_box(event);
+ int i;
+
+ snb_uncore_imc_event_stop(event, PERF_EF_UPDATE);
+
+ for (i = 0; i < box->n_events; i++) {
+ if (event == box->event_list[i]) {
+ --box->n_events;
+ break;
+ }
+ }
+}
+
+static int snb_pci2phy_map_init(int devid)
+{
+ struct pci_dev *dev = NULL;
+ int bus;
+
+ dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, dev);
+ if (!dev)
+ return -ENOTTY;
+
+ bus = dev->bus->number;
+
+ pcibus_to_physid[bus] = 0;
+
+ pci_dev_put(dev);
+
+ return 0;
+}
+
+static struct pmu snb_uncore_imc_pmu = {
+ .task_ctx_nr = perf_invalid_context,
+ .event_init = snb_uncore_imc_event_init,
+ .add = snb_uncore_imc_event_add,
+ .del = snb_uncore_imc_event_del,
+ .start = snb_uncore_imc_event_start,
+ .stop = snb_uncore_imc_event_stop,
+ .read = uncore_pmu_event_read,
+};
+
+static struct intel_uncore_ops snb_uncore_imc_ops = {
+ .init_box = snb_uncore_imc_init_box,
+ .enable_box = snb_uncore_imc_enable_box,
+ .disable_box = snb_uncore_imc_disable_box,
+ .disable_event = snb_uncore_imc_disable_event,
+ .enable_event = snb_uncore_imc_enable_event,
+ .hw_config = snb_uncore_imc_hw_config,
+ .read_counter = snb_uncore_imc_read_counter,
+};
+
+static struct intel_uncore_type snb_uncore_imc = {
+ .name = "imc",
+ .num_counters = 2,
+ .num_boxes = 1,
+ .fixed_ctr_bits = 32,
+ .fixed_ctr = SNB_UNCORE_PCI_IMC_CTR_BASE,
+ .event_descs = snb_uncore_imc_events,
+ .format_group = &snb_uncore_imc_format_group,
+ .perf_ctr = SNB_UNCORE_PCI_IMC_DATA_READS_BASE,
+ .event_mask = SNB_UNCORE_PCI_IMC_EVENT_MASK,
+ .ops = &snb_uncore_imc_ops,
+ .pmu = &snb_uncore_imc_pmu,
+};
+
+static struct intel_uncore_type *snb_pci_uncores[] = {
+ [SNB_PCI_UNCORE_IMC] = &snb_uncore_imc,
+ NULL,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(snb_uncore_pci_ids) = {
+ { /* IMC */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SNB_IMC),
+ .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+ },
+ { /* end: all zeroes */ },
+};
+
+static DEFINE_PCI_DEVICE_TABLE(ivb_uncore_pci_ids) = {
+ { /* IMC */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_IMC),
+ .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+ },
+ { /* end: all zeroes */ },
+};
+
+static DEFINE_PCI_DEVICE_TABLE(hsw_uncore_pci_ids) = {
+ { /* IMC */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC),
+ .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+ },
+ { /* end: all zeroes */ },
+};
+
+static struct pci_driver snb_uncore_pci_driver = {
+ .name = "snb_uncore",
+ .id_table = snb_uncore_pci_ids,
+};
+
+static struct pci_driver ivb_uncore_pci_driver = {
+ .name = "ivb_uncore",
+ .id_table = ivb_uncore_pci_ids,
+};
+
+static struct pci_driver hsw_uncore_pci_driver = {
+ .name = "hsw_uncore",
+ .id_table = hsw_uncore_pci_ids,
+};
+
/* end of Sandy Bridge uncore support */
/* Nehalem uncore support */
@@ -2781,6 +3173,7 @@ again:
static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
{
struct intel_uncore_box *box;
+ struct perf_event *event;
unsigned long flags;
int bit;
@@ -2793,19 +3186,27 @@ static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
*/
local_irq_save(flags);
+ /*
+ * handle boxes with an active event list as opposed to active
+ * counters
+ */
+ list_for_each_entry(event, &box->active_list, active_entry) {
+ uncore_perf_event_update(box, event);
+ }
+
for_each_set_bit(bit, box->active_mask, UNCORE_PMC_IDX_MAX)
uncore_perf_event_update(box, box->events[bit]);
local_irq_restore(flags);
- hrtimer_forward_now(hrtimer, ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL));
+ hrtimer_forward_now(hrtimer, ns_to_ktime(box->hrtimer_duration));
return HRTIMER_RESTART;
}
static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box)
{
__hrtimer_start_range_ns(&box->hrtimer,
- ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL), 0,
+ ns_to_ktime(box->hrtimer_duration), 0,
HRTIMER_MODE_REL_PINNED, 0);
}
@@ -2839,43 +3240,12 @@ static struct intel_uncore_box *uncore_alloc_box(struct intel_uncore_type *type,
box->cpu = -1;
box->phys_id = -1;
- return box;
-}
-
-static struct intel_uncore_box *
-uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
-{
- struct intel_uncore_box *box;
-
- box = *per_cpu_ptr(pmu->box, cpu);
- if (box)
- return box;
+ /* set default hrtimer timeout */
+ box->hrtimer_duration = UNCORE_PMU_HRTIMER_INTERVAL;
- raw_spin_lock(&uncore_box_lock);
- list_for_each_entry(box, &pmu->box_list, list) {
- if (box->phys_id == topology_physical_package_id(cpu)) {
- atomic_inc(&box->refcnt);
- *per_cpu_ptr(pmu->box, cpu) = box;
- break;
- }
- }
- raw_spin_unlock(&uncore_box_lock);
+ INIT_LIST_HEAD(&box->active_list);
- return *per_cpu_ptr(pmu->box, cpu);
-}
-
-static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
-{
- return container_of(event->pmu, struct intel_uncore_pmu, pmu);
-}
-
-static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
-{
- /*
- * perf core schedules event on the basis of cpu, uncore events are
- * collected by one of the cpus inside a physical package.
- */
- return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
+ return box;
}
static int
@@ -3271,16 +3641,21 @@ static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
{
int ret;
- pmu->pmu = (struct pmu) {
- .attr_groups = pmu->type->attr_groups,
- .task_ctx_nr = perf_invalid_context,
- .event_init = uncore_pmu_event_init,
- .add = uncore_pmu_event_add,
- .del = uncore_pmu_event_del,
- .start = uncore_pmu_event_start,
- .stop = uncore_pmu_event_stop,
- .read = uncore_pmu_event_read,
- };
+ if (!pmu->type->pmu) {
+ pmu->pmu = (struct pmu) {
+ .attr_groups = pmu->type->attr_groups,
+ .task_ctx_nr = perf_invalid_context,
+ .event_init = uncore_pmu_event_init,
+ .add = uncore_pmu_event_add,
+ .del = uncore_pmu_event_del,
+ .start = uncore_pmu_event_start,
+ .stop = uncore_pmu_event_stop,
+ .read = uncore_pmu_event_read,
+ };
+ } else {
+ pmu->pmu = *pmu->type->pmu;
+ pmu->pmu.attr_groups = pmu->type->attr_groups;
+ }
if (pmu->type->num_boxes == 1) {
if (strlen(pmu->type->name) > 0)
@@ -3326,6 +3701,8 @@ static int __init uncore_type_init(struct intel_uncore_type *type)
if (!pmus)
return -ENOMEM;
+ type->pmus = pmus;
+
type->unconstrainted = (struct event_constraint)
__EVENT_CONSTRAINT(0, (1ULL << type->num_counters) - 1,
0, type->num_counters, 0, 0);
@@ -3361,7 +3738,6 @@ static int __init uncore_type_init(struct intel_uncore_type *type)
}
type->pmu_group = &uncore_pmu_attr_group;
- type->pmus = pmus;
return 0;
fail:
uncore_type_exit(type);
@@ -3493,6 +3869,28 @@ static int __init uncore_pci_init(void)
pci_uncores = ivt_pci_uncores;
uncore_pci_driver = &ivt_uncore_pci_driver;
break;
+ case 42: /* Sandy Bridge */
+ ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_SNB_IMC);
+ if (ret)
+ return ret;
+ pci_uncores = snb_pci_uncores;
+ uncore_pci_driver = &snb_uncore_pci_driver;
+ break;
+ case 58: /* Ivy Bridge */
+ ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_IVB_IMC);
+ if (ret)
+ return ret;
+ pci_uncores = snb_pci_uncores;
+ uncore_pci_driver = &ivb_uncore_pci_driver;
+ break;
+ case 60: /* Haswell */
+ case 69: /* Haswell Celeron */
+ ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_HSW_IMC);
+ if (ret)
+ return ret;
+ pci_uncores = snb_pci_uncores;
+ uncore_pci_driver = &hsw_uncore_pci_driver;
+ break;
default:
return 0;
}
@@ -3764,7 +4162,7 @@ static void __init uncore_cpu_setup(void *dummy)
static int __init uncore_cpu_init(void)
{
- int ret, cpu, max_cores;
+ int ret, max_cores;
max_cores = boot_cpu_data.x86_max_cores;
switch (boot_cpu_data.x86_model) {
@@ -3808,29 +4206,6 @@ static int __init uncore_cpu_init(void)
if (ret)
return ret;
- get_online_cpus();
-
- for_each_online_cpu(cpu) {
- int i, phys_id = topology_physical_package_id(cpu);
-
- for_each_cpu(i, &uncore_cpu_mask) {
- if (phys_id == topology_physical_package_id(i)) {
- phys_id = -1;
- break;
- }
- }
- if (phys_id < 0)
- continue;
-
- uncore_cpu_prepare(cpu, phys_id);
- uncore_event_init_cpu(cpu);
- }
- on_each_cpu(uncore_cpu_setup, NULL, 1);
-
- register_cpu_notifier(&uncore_cpu_nb);
-
- put_online_cpus();
-
return 0;
}
@@ -3859,6 +4234,41 @@ static int __init uncore_pmus_register(void)
return 0;
}
+static void __init uncore_cpumask_init(void)
+{
+ int cpu;
+
+ /*
+ * ony invoke once from msr or pci init code
+ */
+ if (!cpumask_empty(&uncore_cpu_mask))
+ return;
+
+ get_online_cpus();
+
+ for_each_online_cpu(cpu) {
+ int i, phys_id = topology_physical_package_id(cpu);
+
+ for_each_cpu(i, &uncore_cpu_mask) {
+ if (phys_id == topology_physical_package_id(i)) {
+ phys_id = -1;
+ break;
+ }
+ }
+ if (phys_id < 0)
+ continue;
+
+ uncore_cpu_prepare(cpu, phys_id);
+ uncore_event_init_cpu(cpu);
+ }
+ on_each_cpu(uncore_cpu_setup, NULL, 1);
+
+ register_cpu_notifier(&uncore_cpu_nb);
+
+ put_online_cpus();
+}
+
+
static int __init intel_uncore_init(void)
{
int ret;
@@ -3877,6 +4287,7 @@ static int __init intel_uncore_init(void)
uncore_pci_exit();
goto fail;
}
+ uncore_cpumask_init();
uncore_pmus_register();
return 0;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
index a80ab71a883d..90236f0c94a9 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
@@ -6,6 +6,7 @@
#define UNCORE_PMU_NAME_LEN 32
#define UNCORE_PMU_HRTIMER_INTERVAL (60LL * NSEC_PER_SEC)
+#define UNCORE_SNB_IMC_HRTIMER_INTERVAL (5ULL * NSEC_PER_SEC)
#define UNCORE_FIXED_EVENT 0xff
#define UNCORE_PMC_IDX_MAX_GENERIC 8
@@ -440,6 +441,7 @@ struct intel_uncore_type {
struct intel_uncore_ops *ops;
struct uncore_event_desc *event_descs;
const struct attribute_group *attr_groups[4];
+ struct pmu *pmu; /* for custom pmu ops */
};
#define pmu_group attr_groups[0]
@@ -488,8 +490,11 @@ struct intel_uncore_box {
u64 tags[UNCORE_PMC_IDX_MAX];
struct pci_dev *pci_dev;
struct intel_uncore_pmu *pmu;
+ u64 hrtimer_duration; /* hrtimer timeout for this box */
struct hrtimer hrtimer;
struct list_head list;
+ struct list_head active_list;
+ void *io_addr;
struct intel_uncore_extra_reg shared_regs[0];
};
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c
index 3486e6660357..5d466b7d8609 100644
--- a/arch/x86/kernel/cpu/perf_event_p4.c
+++ b/arch/x86/kernel/cpu/perf_event_p4.c
@@ -1257,7 +1257,24 @@ again:
pass++;
goto again;
}
-
+ /*
+ * Perf does test runs to see if a whole group can be assigned
+ * together succesfully. There can be multiple rounds of this.
+ * Unfortunately, p4_pmu_swap_config_ts touches the hwc->config
+ * bits, such that the next round of group assignments will
+ * cause the above p4_should_swap_ts to pass instead of fail.
+ * This leads to counters exclusive to thread0 being used by
+ * thread1.
+ *
+ * Solve this with a cheap hack, reset the idx back to -1 to
+ * force a new lookup (p4_next_cntr) to get the right counter
+ * for the right thread.
+ *
+ * This probably doesn't comply with the general spirit of how
+ * perf wants to work, but P4 is special. :-(
+ */
+ if (p4_should_swap_ts(hwc->config, cpu))
+ hwc->idx = -1;
p4_pmu_swap_config_ts(hwc, cpu);
if (assign)
assign[i] = cntr_idx;
@@ -1322,6 +1339,7 @@ static __initconst const struct x86_pmu p4_pmu = {
__init int p4_pmu_init(void)
{
unsigned int low, high;
+ int i, reg;
/* If we get stripped -- indexing fails */
BUILD_BUG_ON(ARCH_P4_MAX_CCCR > INTEL_PMC_MAX_GENERIC);
@@ -1340,5 +1358,19 @@ __init int p4_pmu_init(void)
x86_pmu = p4_pmu;
+ /*
+ * Even though the counters are configured to interrupt a particular
+ * logical processor when an overflow happens, testing has shown that
+ * on kdump kernels (which uses a single cpu), thread1's counter
+ * continues to run and will report an NMI on thread0. Due to the
+ * overflow bug, this leads to a stream of unknown NMIs.
+ *
+ * Solve this by zero'ing out the registers to mimic a reset.
+ */
+ for (i = 0; i < x86_pmu.num_counters; i++) {
+ reg = x86_pmu_config_addr(i);
+ wrmsrl_safe(reg, 0ULL);
+ }
+
return 0;
}
diff --git a/arch/x86/kernel/cpu/perf_event_p6.c b/arch/x86/kernel/cpu/perf_event_p6.c
index b1e2fe115323..7c1a0c07b607 100644
--- a/arch/x86/kernel/cpu/perf_event_p6.c
+++ b/arch/x86/kernel/cpu/perf_event_p6.c
@@ -231,31 +231,49 @@ static __initconst const struct x86_pmu p6_pmu = {
};
+static __init void p6_pmu_rdpmc_quirk(void)
+{
+ if (boot_cpu_data.x86_mask < 9) {
+ /*
+ * PPro erratum 26; fixed in stepping 9 and above.
+ */
+ pr_warn("Userspace RDPMC support disabled due to a CPU erratum\n");
+ x86_pmu.attr_rdpmc_broken = 1;
+ x86_pmu.attr_rdpmc = 0;
+ }
+}
+
__init int p6_pmu_init(void)
{
+ x86_pmu = p6_pmu;
+
switch (boot_cpu_data.x86_model) {
- case 1:
- case 3: /* Pentium Pro */
- case 5:
- case 6: /* Pentium II */
- case 7:
- case 8:
- case 11: /* Pentium III */
- case 9:
- case 13:
- /* Pentium M */
+ case 1: /* Pentium Pro */
+ x86_add_quirk(p6_pmu_rdpmc_quirk);
+ break;
+
+ case 3: /* Pentium II - Klamath */
+ case 5: /* Pentium II - Deschutes */
+ case 6: /* Pentium II - Mendocino */
break;
+
+ case 7: /* Pentium III - Katmai */
+ case 8: /* Pentium III - Coppermine */
+ case 10: /* Pentium III Xeon */
+ case 11: /* Pentium III - Tualatin */
+ break;
+
+ case 9: /* Pentium M - Banias */
+ case 13: /* Pentium M - Dothan */
+ break;
+
default:
- pr_cont("unsupported p6 CPU model %d ",
- boot_cpu_data.x86_model);
+ pr_cont("unsupported p6 CPU model %d ", boot_cpu_data.x86_model);
return -ENODEV;
}
- x86_pmu = p6_pmu;
-
memcpy(hw_cache_event_ids, p6_hw_cache_event_ids,
sizeof(hw_cache_event_ids));
-
return 0;
}
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index a57902efe2d5..507de8066594 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -57,9 +57,7 @@ static void kdump_nmi_callback(int cpu, struct pt_regs *regs)
{
#ifdef CONFIG_X86_32
struct pt_regs fixed_regs;
-#endif
-#ifdef CONFIG_X86_32
if (!user_mode_vm(regs)) {
crash_fixup_ss_esp(&fixed_regs, regs);
regs = &fixed_regs;
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index f2a1770ca176..5abd4cd4230c 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -16,12 +16,35 @@
#include <asm/stacktrace.h>
+static void *is_irq_stack(void *p, void *irq)
+{
+ if (p < irq || p >= (irq + THREAD_SIZE))
+ return NULL;
+ return irq + THREAD_SIZE;
+}
+
+
+static void *is_hardirq_stack(unsigned long *stack, int cpu)
+{
+ void *irq = per_cpu(hardirq_stack, cpu);
+
+ return is_irq_stack(stack, irq);
+}
+
+static void *is_softirq_stack(unsigned long *stack, int cpu)
+{
+ void *irq = per_cpu(softirq_stack, cpu);
+
+ return is_irq_stack(stack, irq);
+}
void dump_trace(struct task_struct *task, struct pt_regs *regs,
unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data)
{
+ const unsigned cpu = get_cpu();
int graph = 0;
+ u32 *prev_esp;
if (!task)
task = current;
@@ -30,7 +53,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
unsigned long dummy;
stack = &dummy;
- if (task && task != current)
+ if (task != current)
stack = (unsigned long *)task->thread.sp;
}
@@ -39,18 +62,31 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
for (;;) {
struct thread_info *context;
+ void *end_stack;
+
+ end_stack = is_hardirq_stack(stack, cpu);
+ if (!end_stack)
+ end_stack = is_softirq_stack(stack, cpu);
- context = (struct thread_info *)
- ((unsigned long)stack & (~(THREAD_SIZE - 1)));
- bp = ops->walk_stack(context, stack, bp, ops, data, NULL, &graph);
+ context = task_thread_info(task);
+ bp = ops->walk_stack(context, stack, bp, ops, data,
+ end_stack, &graph);
- stack = (unsigned long *)context->previous_esp;
+ /* Stop if not on irq stack */
+ if (!end_stack)
+ break;
+
+ /* The previous esp is saved on the bottom of the stack */
+ prev_esp = (u32 *)(end_stack - THREAD_SIZE);
+ stack = (unsigned long *)*prev_esp;
if (!stack)
break;
+
if (ops->stack(data, "IRQ") < 0)
break;
touch_nmi_watchdog();
}
+ put_cpu();
}
EXPORT_SYMBOL(dump_trace);
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index addb207dab92..1abcb50b48ae 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -104,6 +104,44 @@ in_irq_stack(unsigned long *stack, unsigned long *irq_stack,
return (stack >= irq_stack && stack < irq_stack_end);
}
+static const unsigned long irq_stack_size =
+ (IRQ_STACK_SIZE - 64) / sizeof(unsigned long);
+
+enum stack_type {
+ STACK_IS_UNKNOWN,
+ STACK_IS_NORMAL,
+ STACK_IS_EXCEPTION,
+ STACK_IS_IRQ,
+};
+
+static enum stack_type
+analyze_stack(int cpu, struct task_struct *task, unsigned long *stack,
+ unsigned long **stack_end, unsigned long *irq_stack,
+ unsigned *used, char **id)
+{
+ unsigned long addr;
+
+ addr = ((unsigned long)stack & (~(THREAD_SIZE - 1)));
+ if ((unsigned long)task_stack_page(task) == addr)
+ return STACK_IS_NORMAL;
+
+ *stack_end = in_exception_stack(cpu, (unsigned long)stack,
+ used, id);
+ if (*stack_end)
+ return STACK_IS_EXCEPTION;
+
+ if (!irq_stack)
+ return STACK_IS_NORMAL;
+
+ *stack_end = irq_stack;
+ irq_stack = irq_stack - irq_stack_size;
+
+ if (in_irq_stack(stack, irq_stack, *stack_end))
+ return STACK_IS_IRQ;
+
+ return STACK_IS_UNKNOWN;
+}
+
/*
* x86-64 can have up to three kernel stacks:
* process stack
@@ -116,12 +154,12 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
const struct stacktrace_ops *ops, void *data)
{
const unsigned cpu = get_cpu();
- unsigned long *irq_stack_end =
- (unsigned long *)per_cpu(irq_stack_ptr, cpu);
- unsigned used = 0;
struct thread_info *tinfo;
- int graph = 0;
+ unsigned long *irq_stack = (unsigned long *)per_cpu(irq_stack_ptr, cpu);
unsigned long dummy;
+ unsigned used = 0;
+ int graph = 0;
+ int done = 0;
if (!task)
task = current;
@@ -143,49 +181,61 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
* exceptions
*/
tinfo = task_thread_info(task);
- for (;;) {
+ while (!done) {
+ unsigned long *stack_end;
+ enum stack_type stype;
char *id;
- unsigned long *estack_end;
- estack_end = in_exception_stack(cpu, (unsigned long)stack,
- &used, &id);
- if (estack_end) {
+ stype = analyze_stack(cpu, task, stack, &stack_end,
+ irq_stack, &used, &id);
+
+ /* Default finish unless specified to continue */
+ done = 1;
+
+ switch (stype) {
+
+ /* Break out early if we are on the thread stack */
+ case STACK_IS_NORMAL:
+ break;
+
+ case STACK_IS_EXCEPTION:
+
if (ops->stack(data, id) < 0)
break;
bp = ops->walk_stack(tinfo, stack, bp, ops,
- data, estack_end, &graph);
+ data, stack_end, &graph);
ops->stack(data, "<EOE>");
/*
* We link to the next stack via the
* second-to-last pointer (index -2 to end) in the
* exception stack:
*/
- stack = (unsigned long *) estack_end[-2];
- continue;
- }
- if (irq_stack_end) {
- unsigned long *irq_stack;
- irq_stack = irq_stack_end -
- (IRQ_STACK_SIZE - 64) / sizeof(*irq_stack);
-
- if (in_irq_stack(stack, irq_stack, irq_stack_end)) {
- if (ops->stack(data, "IRQ") < 0)
- break;
- bp = ops->walk_stack(tinfo, stack, bp,
- ops, data, irq_stack_end, &graph);
- /*
- * We link to the next stack (which would be
- * the process stack normally) the last
- * pointer (index -1 to end) in the IRQ stack:
- */
- stack = (unsigned long *) (irq_stack_end[-1]);
- irq_stack_end = NULL;
- ops->stack(data, "EOI");
- continue;
- }
+ stack = (unsigned long *) stack_end[-2];
+ done = 0;
+ break;
+
+ case STACK_IS_IRQ:
+
+ if (ops->stack(data, "IRQ") < 0)
+ break;
+ bp = ops->walk_stack(tinfo, stack, bp,
+ ops, data, stack_end, &graph);
+ /*
+ * We link to the next stack (which would be
+ * the process stack normally) the last
+ * pointer (index -1 to end) in the IRQ stack:
+ */
+ stack = (unsigned long *) (stack_end[-1]);
+ irq_stack = NULL;
+ ops->stack(data, "EOI");
+ done = 0;
+ break;
+
+ case STACK_IS_UNKNOWN:
+ ops->stack(data, "UNK");
+ break;
}
- break;
}
/*
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index bc4a088f9023..6d7d5a1260a6 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -203,18 +203,15 @@ static void __init intel_remapping_check(int num, int slot, int func)
revision = read_pci_config_byte(num, slot, func, PCI_REVISION_ID);
/*
- * Revision 13 of all triggering devices id in this quirk have
- * a problem draining interrupts when irq remapping is enabled,
- * and should be flagged as broken. Additionally revisions 0x12
- * and 0x22 of device id 0x3405 has this problem.
+ * Revision <= 13 of all triggering devices id in this quirk
+ * have a problem draining interrupts when irq remapping is
+ * enabled, and should be flagged as broken. Additionally
+ * revision 0x22 of device id 0x3405 has this problem.
*/
- if (revision == 0x13)
+ if (revision <= 0x13)
set_irq_remapping_broken();
- else if ((device == 0x3405) &&
- ((revision == 0x12) ||
- (revision == 0x22)))
+ else if (device == 0x3405 && revision == 0x22)
set_irq_remapping_broken();
-
}
/*
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 81ba27679f18..f36bd42d6f0c 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -544,6 +544,10 @@ ENDPROC(early_idt_handlers)
/* This is global to keep gas from relaxing the jumps */
ENTRY(early_idt_handler)
cld
+
+ cmpl $2,(%esp) # X86_TRAP_NMI
+ je is_nmi # Ignore NMI
+
cmpl $2,%ss:early_recursion_flag
je hlt_loop
incl %ss:early_recursion_flag
@@ -594,8 +598,9 @@ ex_entry:
pop %edx
pop %ecx
pop %eax
- addl $8,%esp /* drop vector number and error code */
decl %ss:early_recursion_flag
+is_nmi:
+ addl $8,%esp /* drop vector number and error code */
iret
ENDPROC(early_idt_handler)
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index e1aabdb314c8..a468c0a65c42 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -343,6 +343,9 @@ early_idt_handlers:
ENTRY(early_idt_handler)
cld
+ cmpl $2,(%rsp) # X86_TRAP_NMI
+ je is_nmi # Ignore NMI
+
cmpl $2,early_recursion_flag(%rip)
jz 1f
incl early_recursion_flag(%rip)
@@ -405,8 +408,9 @@ ENTRY(early_idt_handler)
popq %rdx
popq %rcx
popq %rax
- addq $16,%rsp # drop vector number and error code
decl early_recursion_flag(%rip)
+is_nmi:
+ addq $16,%rsp # drop vector number and error code
INTERRUPT_RETURN
ENDPROC(early_idt_handler)
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index da85a8e830a1..93eed15a8fd4 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -521,7 +521,7 @@ static int hpet_setup_irq(struct hpet_dev *dev)
{
if (request_irq(dev->irq, hpet_interrupt_handler,
- IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING,
+ IRQF_TIMER | IRQF_NOBALANCING,
dev->name, dev))
return -1;
@@ -699,7 +699,7 @@ static int hpet_cpuhp_notify(struct notifier_block *n,
/* FIXME: add schedule_work_on() */
schedule_delayed_work_on(cpu, &work.work, 0);
wait_for_completion(&work.complete);
- destroy_timer_on_stack(&work.work.timer);
+ destroy_delayed_work_on_stack(&work.work);
break;
case CPU_DEAD:
if (hdev) {
@@ -752,9 +752,7 @@ static struct clocksource clocksource_hpet = {
.mask = HPET_MASK,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
.resume = hpet_resume_counter,
-#ifdef CONFIG_X86_64
.archdata = { .vclock_mode = VCLOCK_HPET },
-#endif
};
static int hpet_clocksource_register(void)
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index e8368c6dd2a2..d5dd80814419 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -86,10 +86,19 @@ EXPORT_SYMBOL(__kernel_fpu_begin);
void __kernel_fpu_end(void)
{
- if (use_eager_fpu())
- math_state_restore();
- else
+ if (use_eager_fpu()) {
+ /*
+ * For eager fpu, most the time, tsk_used_math() is true.
+ * Restore the user math as we are done with the kernel usage.
+ * At few instances during thread exit, signal handling etc,
+ * tsk_used_math() is false. Those few places will take proper
+ * actions, so we don't need to restore the math here.
+ */
+ if (likely(tsk_used_math(current)))
+ math_state_restore();
+ } else {
stts();
+ }
}
EXPORT_SYMBOL(__kernel_fpu_end);
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index d99f31d9a750..42805fac0092 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -125,6 +125,12 @@ int arch_show_interrupts(struct seq_file *p, int prec)
seq_printf(p, "%10u ", per_cpu(mce_poll_count, j));
seq_printf(p, " Machine check polls\n");
#endif
+#if defined(CONFIG_HYPERV) || defined(CONFIG_XEN)
+ seq_printf(p, "%*s: ", prec, "THR");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stats(j)->irq_hv_callback_count);
+ seq_printf(p, " Hypervisor callback interrupts\n");
+#endif
seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
#if defined(CONFIG_X86_IO_APIC)
seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read(&irq_mis_count));
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index d7fcbedc9c43..63ce838e5a54 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -55,16 +55,8 @@ static inline int check_stack_overflow(void) { return 0; }
static inline void print_stack_overflow(void) { }
#endif
-/*
- * per-CPU IRQ handling contexts (thread information and stack)
- */
-union irq_ctx {
- struct thread_info tinfo;
- u32 stack[THREAD_SIZE/sizeof(u32)];
-} __attribute__((aligned(THREAD_SIZE)));
-
-static DEFINE_PER_CPU(union irq_ctx *, hardirq_ctx);
-static DEFINE_PER_CPU(union irq_ctx *, softirq_ctx);
+DEFINE_PER_CPU(struct irq_stack *, hardirq_stack);
+DEFINE_PER_CPU(struct irq_stack *, softirq_stack);
static void call_on_stack(void *func, void *stack)
{
@@ -77,14 +69,26 @@ static void call_on_stack(void *func, void *stack)
: "memory", "cc", "edx", "ecx", "eax");
}
+/* how to get the current stack pointer from C */
+#define current_stack_pointer ({ \
+ unsigned long sp; \
+ asm("mov %%esp,%0" : "=g" (sp)); \
+ sp; \
+})
+
+static inline void *current_stack(void)
+{
+ return (void *)(current_stack_pointer & ~(THREAD_SIZE - 1));
+}
+
static inline int
execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
{
- union irq_ctx *curctx, *irqctx;
- u32 *isp, arg1, arg2;
+ struct irq_stack *curstk, *irqstk;
+ u32 *isp, *prev_esp, arg1, arg2;
- curctx = (union irq_ctx *) current_thread_info();
- irqctx = __this_cpu_read(hardirq_ctx);
+ curstk = (struct irq_stack *) current_stack();
+ irqstk = __this_cpu_read(hardirq_stack);
/*
* this is where we switch to the IRQ stack. However, if we are
@@ -92,13 +96,14 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
* handler) we can't do that and just have to keep using the
* current stack (which is the irq stack already after all)
*/
- if (unlikely(curctx == irqctx))
+ if (unlikely(curstk == irqstk))
return 0;
- /* build the stack frame on the IRQ stack */
- isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
- irqctx->tinfo.task = curctx->tinfo.task;
- irqctx->tinfo.previous_esp = current_stack_pointer;
+ isp = (u32 *) ((char *)irqstk + sizeof(*irqstk));
+
+ /* Save the next esp at the bottom of the stack */
+ prev_esp = (u32 *)irqstk;
+ *prev_esp = current_stack_pointer;
if (unlikely(overflow))
call_on_stack(print_stack_overflow, isp);
@@ -118,46 +123,40 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
*/
void irq_ctx_init(int cpu)
{
- union irq_ctx *irqctx;
+ struct irq_stack *irqstk;
- if (per_cpu(hardirq_ctx, cpu))
+ if (per_cpu(hardirq_stack, cpu))
return;
- irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
+ irqstk = page_address(alloc_pages_node(cpu_to_node(cpu),
THREADINFO_GFP,
THREAD_SIZE_ORDER));
- memset(&irqctx->tinfo, 0, sizeof(struct thread_info));
- irqctx->tinfo.cpu = cpu;
- irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
-
- per_cpu(hardirq_ctx, cpu) = irqctx;
+ per_cpu(hardirq_stack, cpu) = irqstk;
- irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
+ irqstk = page_address(alloc_pages_node(cpu_to_node(cpu),
THREADINFO_GFP,
THREAD_SIZE_ORDER));
- memset(&irqctx->tinfo, 0, sizeof(struct thread_info));
- irqctx->tinfo.cpu = cpu;
- irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
-
- per_cpu(softirq_ctx, cpu) = irqctx;
+ per_cpu(softirq_stack, cpu) = irqstk;
printk(KERN_DEBUG "CPU %u irqstacks, hard=%p soft=%p\n",
- cpu, per_cpu(hardirq_ctx, cpu), per_cpu(softirq_ctx, cpu));
+ cpu, per_cpu(hardirq_stack, cpu), per_cpu(softirq_stack, cpu));
}
void do_softirq_own_stack(void)
{
- struct thread_info *curctx;
- union irq_ctx *irqctx;
- u32 *isp;
+ struct thread_info *curstk;
+ struct irq_stack *irqstk;
+ u32 *isp, *prev_esp;
- curctx = current_thread_info();
- irqctx = __this_cpu_read(softirq_ctx);
- irqctx->tinfo.task = curctx->task;
- irqctx->tinfo.previous_esp = current_stack_pointer;
+ curstk = current_stack();
+ irqstk = __this_cpu_read(softirq_stack);
/* build the stack frame on the softirq stack */
- isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
+ isp = (u32 *) ((char *)irqstk + sizeof(*irqstk));
+
+ /* Push the previous esp onto the stack */
+ prev_esp = (u32 *)irqstk;
+ *prev_esp = current_stack_pointer;
call_on_stack(__do_softirq, isp);
}
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 713f1b3bad52..0331cb389d68 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -417,7 +417,6 @@ void kvm_disable_steal_time(void)
#ifdef CONFIG_SMP
static void __init kvm_smp_prepare_boot_cpu(void)
{
- WARN_ON(kvm_register_clock("primary cpu clock"));
kvm_guest_cpu_init();
native_smp_prepare_boot_cpu();
kvm_spinlock_init();
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index e6041094ff26..d9156ceecdff 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -242,7 +242,7 @@ void __init kvmclock_init(void)
hv_clock = __va(mem);
memset(hv_clock, 0, size);
- if (kvm_register_clock("boot clock")) {
+ if (kvm_register_clock("primary cpu clock")) {
hv_clock = NULL;
memblock_free(mem, size);
return;
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
index 4eabc160696f..679cef0791cd 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -279,5 +279,7 @@ void arch_crash_save_vmcoreinfo(void)
VMCOREINFO_SYMBOL(node_data);
VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
#endif
+ vmcoreinfo_append_str("KERNELOFFSET=%lx\n",
+ (unsigned long)&_text - __START_KERNEL);
}
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
index 18be189368bb..e69f9882bf95 100644
--- a/arch/x86/kernel/module.c
+++ b/arch/x86/kernel/module.c
@@ -28,6 +28,7 @@
#include <linux/mm.h>
#include <linux/gfp.h>
#include <linux/jump_label.h>
+#include <linux/random.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -43,13 +44,52 @@ do { \
} while (0)
#endif
+#ifdef CONFIG_RANDOMIZE_BASE
+static unsigned long module_load_offset;
+static int randomize_modules = 1;
+
+/* Mutex protects the module_load_offset. */
+static DEFINE_MUTEX(module_kaslr_mutex);
+
+static int __init parse_nokaslr(char *p)
+{
+ randomize_modules = 0;
+ return 0;
+}
+early_param("nokaslr", parse_nokaslr);
+
+static unsigned long int get_module_load_offset(void)
+{
+ if (randomize_modules) {
+ mutex_lock(&module_kaslr_mutex);
+ /*
+ * Calculate the module_load_offset the first time this
+ * code is called. Once calculated it stays the same until
+ * reboot.
+ */
+ if (module_load_offset == 0)
+ module_load_offset =
+ (get_random_int() % 1024 + 1) * PAGE_SIZE;
+ mutex_unlock(&module_kaslr_mutex);
+ }
+ return module_load_offset;
+}
+#else
+static unsigned long int get_module_load_offset(void)
+{
+ return 0;
+}
+#endif
+
void *module_alloc(unsigned long size)
{
if (PAGE_ALIGN(size) > MODULES_LEN)
return NULL;
- return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
- GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC,
- NUMA_NO_NODE, __builtin_return_address(0));
+ return __vmalloc_node_range(size, 1,
+ MODULES_VADDR + get_module_load_offset(),
+ MODULES_END, GFP_KERNEL | __GFP_HIGHMEM,
+ PAGE_KERNEL_EXEC, NUMA_NO_NODE,
+ __builtin_return_address(0));
}
#ifdef CONFIG_X86_32
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index 6fcb49ce50a1..b4872b999a71 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -87,6 +87,7 @@ __setup("unknown_nmi_panic", setup_unknown_nmi_panic);
#define nmi_to_desc(type) (&nmi_desc[type])
static u64 nmi_longest_ns = 1 * NSEC_PER_MSEC;
+
static int __init nmi_warning_debugfs(void)
{
debugfs_create_u64("nmi_longest_ns", 0644,
@@ -95,6 +96,20 @@ static int __init nmi_warning_debugfs(void)
}
fs_initcall(nmi_warning_debugfs);
+static void nmi_max_handler(struct irq_work *w)
+{
+ struct nmiaction *a = container_of(w, struct nmiaction, irq_work);
+ int remainder_ns, decimal_msecs;
+ u64 whole_msecs = ACCESS_ONCE(a->max_duration);
+
+ remainder_ns = do_div(whole_msecs, (1000 * 1000));
+ decimal_msecs = remainder_ns / 1000;
+
+ printk_ratelimited(KERN_INFO
+ "INFO: NMI handler (%ps) took too long to run: %lld.%03d msecs\n",
+ a->handler, whole_msecs, decimal_msecs);
+}
+
static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2b)
{
struct nmi_desc *desc = nmi_to_desc(type);
@@ -110,26 +125,20 @@ static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2
* to handle those situations.
*/
list_for_each_entry_rcu(a, &desc->head, list) {
- u64 before, delta, whole_msecs;
- int remainder_ns, decimal_msecs, thishandled;
+ int thishandled;
+ u64 delta;
- before = sched_clock();
+ delta = sched_clock();
thishandled = a->handler(type, regs);
handled += thishandled;
- delta = sched_clock() - before;
+ delta = sched_clock() - delta;
trace_nmi_handler(a->handler, (int)delta, thishandled);
- if (delta < nmi_longest_ns)
+ if (delta < nmi_longest_ns || delta < a->max_duration)
continue;
- nmi_longest_ns = delta;
- whole_msecs = delta;
- remainder_ns = do_div(whole_msecs, (1000 * 1000));
- decimal_msecs = remainder_ns / 1000;
- printk_ratelimited(KERN_INFO
- "INFO: NMI handler (%ps) took too long to run: "
- "%lld.%03d msecs\n", a->handler, whole_msecs,
- decimal_msecs);
+ a->max_duration = delta;
+ irq_work_queue(&a->irq_work);
}
rcu_read_unlock();
@@ -146,6 +155,8 @@ int __register_nmi_handler(unsigned int type, struct nmiaction *action)
if (!action->handler)
return -EINVAL;
+ init_irq_work(&action->irq_work, nmi_max_handler);
+
spin_lock_irqsave(&desc->lock, flags);
/*
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 872079a67e4d..f7d0672481fd 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -100,8 +100,10 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,
flag |= __GFP_ZERO;
again:
page = NULL;
- if (!(flag & GFP_ATOMIC))
+ /* CMA can be used only in the context which permits sleeping */
+ if (flag & __GFP_WAIT)
page = dma_alloc_from_contiguous(dev, count, get_order(size));
+ /* fallback */
if (!page)
page = alloc_pages_node(dev_to_node(dev), flag, get_order(size));
if (!page)
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 3fb8d95ab8b5..4505e2a950d8 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -298,10 +298,7 @@ void arch_cpu_idle_dead(void)
*/
void arch_cpu_idle(void)
{
- if (cpuidle_idle_call())
- x86_idle();
- else
- local_irq_enable();
+ x86_idle();
}
/*
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 0de43e98ce08..7bc86bbe7485 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -314,6 +314,10 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
*/
arch_end_context_switch(next_p);
+ this_cpu_write(kernel_stack,
+ (unsigned long)task_stack_page(next_p) +
+ THREAD_SIZE - KERNEL_STACK_OFFSET);
+
/*
* Restore %gs if needed (which is common)
*/
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 7461f50d5bb1..678c0ada3b3c 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -184,14 +184,14 @@ unsigned long kernel_stack_pointer(struct pt_regs *regs)
{
unsigned long context = (unsigned long)regs & ~(THREAD_SIZE - 1);
unsigned long sp = (unsigned long)&regs->sp;
- struct thread_info *tinfo;
+ u32 *prev_esp;
if (context == (sp & ~(THREAD_SIZE - 1)))
return sp;
- tinfo = (struct thread_info *)context;
- if (tinfo->previous_esp)
- return tinfo->previous_esp;
+ prev_esp = (u32 *)(context);
+ if (prev_esp)
+ return (unsigned long)prev_esp;
return (unsigned long)regs;
}
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
index 7c6acd4b8995..ff898bbf579d 100644
--- a/arch/x86/kernel/quirks.c
+++ b/arch/x86/kernel/quirks.c
@@ -529,7 +529,7 @@ static void quirk_amd_nb_node(struct pci_dev *dev)
return;
pci_read_config_dword(nb_ht, 0x60, &val);
- node = val & 7;
+ node = pcibus_to_node(dev->bus) | (val & 7);
/*
* Some hardware may return an invalid node ID,
* so check it first:
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index c752cb43e52f..654b46574b91 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -464,9 +464,12 @@ void __attribute__((weak)) mach_reboot_fixups(void)
* 2) If still alive, write to the keyboard controller
* 3) If still alive, write to the ACPI reboot register again
* 4) If still alive, write to the keyboard controller again
+ * 5) If still alive, call the EFI runtime service to reboot
+ * 6) If still alive, write to the PCI IO port 0xCF9 to reboot
+ * 7) If still alive, inform BIOS to do a proper reboot
*
* If the machine is still alive at this stage, it gives up. We default to
- * following the same pattern, except that if we're still alive after (4) we'll
+ * following the same pattern, except that if we're still alive after (7) we'll
* try to force a triple fault and then cycle between hitting the keyboard
* controller and doing that
*/
@@ -502,7 +505,7 @@ static void native_machine_emergency_restart(void)
attempt = 1;
reboot_type = BOOT_ACPI;
} else {
- reboot_type = BOOT_TRIPLE;
+ reboot_type = BOOT_EFI;
}
break;
@@ -510,13 +513,15 @@ static void native_machine_emergency_restart(void)
load_idt(&no_idt);
__asm__ __volatile__("int3");
+ /* We're probably dead after this, but... */
reboot_type = BOOT_KBD;
break;
case BOOT_BIOS:
machine_real_restart(MRR_BIOS);
- reboot_type = BOOT_KBD;
+ /* We're probably dead after this, but... */
+ reboot_type = BOOT_TRIPLE;
break;
case BOOT_ACPI:
@@ -530,7 +535,7 @@ static void native_machine_emergency_restart(void)
EFI_RESET_WARM :
EFI_RESET_COLD,
EFI_SUCCESS, 0, NULL);
- reboot_type = BOOT_KBD;
+ reboot_type = BOOT_CF9_COND;
break;
case BOOT_CF9:
@@ -548,7 +553,7 @@ static void native_machine_emergency_restart(void)
outb(cf9|reboot_code, 0xcf9);
udelay(50);
}
- reboot_type = BOOT_KBD;
+ reboot_type = BOOT_BIOS;
break;
}
}
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 06853e670354..09c76d265550 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -869,7 +869,6 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_X86_32
memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
- visws_early_detect();
/*
* copy kernel address range established so far and switch
@@ -926,11 +925,11 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_EFI
if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
"EL32", 4)) {
- set_bit(EFI_BOOT, &x86_efi_facility);
+ set_bit(EFI_BOOT, &efi.flags);
} else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
"EL64", 4)) {
- set_bit(EFI_BOOT, &x86_efi_facility);
- set_bit(EFI_64BIT, &x86_efi_facility);
+ set_bit(EFI_BOOT, &efi.flags);
+ set_bit(EFI_64BIT, &efi.flags);
}
if (efi_enabled(EFI_BOOT))
@@ -1239,14 +1238,8 @@ void __init setup_arch(char **cmdline_p)
register_refined_jiffies(CLOCK_TICK_RATE);
#ifdef CONFIG_EFI
- /* Once setup is done above, unmap the EFI memory map on
- * mismatched firmware/kernel archtectures since there is no
- * support for runtime services.
- */
- if (efi_enabled(EFI_BOOT) && !efi_is_native()) {
- pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
- efi_unmap_memmap();
- }
+ if (efi_enabled(EFI_BOOT))
+ efi_apply_memmap_quirks();
#endif
}
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index a32da804252e..34826934d4a7 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -122,8 +122,9 @@ static void smp_callin(void)
* Since CPU0 is not wakened up by INIT, it doesn't wait for the IPI.
*/
cpuid = smp_processor_id();
- if (apic->wait_for_init_deassert && cpuid != 0)
- apic->wait_for_init_deassert(&init_deasserted);
+ if (apic->wait_for_init_deassert && cpuid)
+ while (!atomic_read(&init_deasserted))
+ cpu_relax();
/*
* (This works even if the APIC is not enabled.)
@@ -701,11 +702,15 @@ wakeup_cpu_via_init_nmi(int cpu, unsigned long start_ip, int apicid,
int id;
int boot_error;
+ preempt_disable();
+
/*
* Wake up AP by INIT, INIT, STARTUP sequence.
*/
- if (cpu)
- return wakeup_secondary_cpu_via_init(apicid, start_ip);
+ if (cpu) {
+ boot_error = wakeup_secondary_cpu_via_init(apicid, start_ip);
+ goto out;
+ }
/*
* Wake up BSP by nmi.
@@ -725,6 +730,9 @@ wakeup_cpu_via_init_nmi(int cpu, unsigned long start_ip, int apicid,
boot_error = wakeup_secondary_cpu_via_nmi(id, start_ip);
}
+out:
+ preempt_enable();
+
return boot_error;
}
@@ -758,10 +766,10 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
#else
clear_tsk_thread_flag(idle, TIF_FORK);
initial_gs = per_cpu_offset(cpu);
+#endif
per_cpu(kernel_stack, cpu) =
(unsigned long)task_stack_page(idle) -
KERNEL_STACK_OFFSET + THREAD_SIZE;
-#endif
early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
initial_code = (unsigned long)start_secondary;
stack_start = idle->thread.sp;
@@ -1379,7 +1387,7 @@ static inline void mwait_play_dead(void)
if (!this_cpu_has(X86_FEATURE_MWAIT))
return;
- if (!this_cpu_has(X86_FEATURE_CLFLSH))
+ if (!this_cpu_has(X86_FEATURE_CLFLUSH))
return;
if (__this_cpu_read(cpu_info.cpuid_level) < CPUID_MWAIT_LEAF)
return;
diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c
index 24d3c91e9812..bf7ef5ce29df 100644
--- a/arch/x86/kernel/time.c
+++ b/arch/x86/kernel/time.c
@@ -23,7 +23,7 @@
#include <asm/time.h>
#ifdef CONFIG_X86_64
-DEFINE_VVAR(volatile unsigned long, jiffies) = INITIAL_JIFFIES;
+__visible DEFINE_VVAR(volatile unsigned long, jiffies) = INITIAL_JIFFIES;
#endif
unsigned long profile_pc(struct pt_regs *regs)
@@ -62,7 +62,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
static struct irqaction irq0 = {
.handler = timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
+ .flags = IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
.name = "timer"
};
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index acb3b606613e..57e5ce126d5a 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -653,13 +653,10 @@ unsigned long native_calibrate_tsc(void)
/* Calibrate TSC using MSR for Intel Atom SoCs */
local_irq_save(flags);
- i = try_msr_calibrate_tsc(&fast_calibrate);
+ fast_calibrate = try_msr_calibrate_tsc();
local_irq_restore(flags);
- if (i >= 0) {
- if (i == 0)
- pr_warn("Fast TSC calibration using MSR failed\n");
+ if (fast_calibrate)
return fast_calibrate;
- }
local_irq_save(flags);
fast_calibrate = quick_pit_calibrate();
@@ -917,8 +914,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
tsc_khz_ref = tsc_khz;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
- (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
- (val == CPUFREQ_RESUMECHANGE)) {
+ (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
*lpj = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
@@ -988,9 +984,7 @@ static struct clocksource clocksource_tsc = {
.mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS |
CLOCK_SOURCE_MUST_VERIFY,
-#ifdef CONFIG_X86_64
.archdata = { .vclock_mode = VCLOCK_TSC },
-#endif
};
void mark_tsc_unstable(char *reason)
diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c
index 8b5434f4389f..92ae6acac8a7 100644
--- a/arch/x86/kernel/tsc_msr.c
+++ b/arch/x86/kernel/tsc_msr.c
@@ -53,7 +53,7 @@ static struct freq_desc freq_desc_tables[] = {
/* TNG */
{ 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } },
/* VLV2 */
- { 6, 0x37, 1, { 0, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } },
+ { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } },
/* ANN */
{ 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 } },
};
@@ -77,21 +77,18 @@ static int match_cpu(u8 family, u8 model)
/*
* Do MSR calibration only for known/supported CPUs.
- * Return values:
- * -1: CPU is unknown/unsupported for MSR based calibration
- * 0: CPU is known/supported, but calibration failed
- * 1: CPU is known/supported, and calibration succeeded
+ *
+ * Returns the calibration value or 0 if MSR calibration failed.
*/
-int try_msr_calibrate_tsc(unsigned long *fast_calibrate)
+unsigned long try_msr_calibrate_tsc(void)
{
- int cpu_index;
u32 lo, hi, ratio, freq_id, freq;
+ unsigned long res;
+ int cpu_index;
cpu_index = match_cpu(boot_cpu_data.x86, boot_cpu_data.x86_model);
if (cpu_index < 0)
- return -1;
-
- *fast_calibrate = 0;
+ return 0;
if (freq_desc_tables[cpu_index].msr_plat) {
rdmsr(MSR_PLATFORM_INFO, lo, hi);
@@ -103,7 +100,7 @@ int try_msr_calibrate_tsc(unsigned long *fast_calibrate)
pr_info("Maximum core-clock to bus-clock ratio: 0x%x\n", ratio);
if (!ratio)
- return 0;
+ goto fail;
/* Get FSB FREQ ID */
rdmsr(MSR_FSB_FREQ, lo, hi);
@@ -112,16 +109,19 @@ int try_msr_calibrate_tsc(unsigned long *fast_calibrate)
pr_info("Resolved frequency ID: %u, frequency: %u KHz\n",
freq_id, freq);
if (!freq)
- return 0;
+ goto fail;
/* TSC frequency = maximum resolved freq * maximum resolved bus ratio */
- *fast_calibrate = freq * ratio;
- pr_info("TSC runs at %lu KHz\n", *fast_calibrate);
+ res = freq * ratio;
+ pr_info("TSC runs at %lu KHz\n", res);
#ifdef CONFIG_X86_LOCAL_APIC
lapic_timer_frequency = (freq * 1000) / HZ;
pr_info("lapic_timer_frequency = %d\n", lapic_timer_frequency);
#endif
+ return res;
- return 1;
+fail:
+ pr_warn("Fast TSC calibration using MSR failed\n");
+ return 0;
}
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index da6b35a98260..49edf2dd3613 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -147,7 +147,6 @@ SECTIONS
_edata = .;
} :data
-#ifdef CONFIG_X86_64
. = ALIGN(PAGE_SIZE);
__vvar_page = .;
@@ -165,12 +164,15 @@ SECTIONS
#undef __VVAR_KERNEL_LDS
#undef EMIT_VVAR
+ /*
+ * Pad the rest of the page with zeros. Otherwise the loader
+ * can leave garbage here.
+ */
+ . = __vvar_beginning_hack + PAGE_SIZE;
} :data
. = ALIGN(__vvar_page + PAGE_SIZE, PAGE_SIZE);
-#endif /* CONFIG_X86_64 */
-
/* Init code and data - will be freed after init */
. = ALIGN(PAGE_SIZE);
.init.begin : AT(ADDR(.init.begin) - LOAD_OFFSET) {
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c
index 1f96f9347ed9..9ea287666c65 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/kernel/vsyscall_64.c
@@ -47,14 +47,12 @@
#include <asm/segment.h>
#include <asm/desc.h>
#include <asm/topology.h>
-#include <asm/vgtod.h>
#include <asm/traps.h>
#define CREATE_TRACE_POINTS
#include "vsyscall_trace.h"
DEFINE_VVAR(int, vgetcpu_mode);
-DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data);
static enum { EMULATE, NATIVE, NONE } vsyscall_mode = EMULATE;
@@ -77,48 +75,6 @@ static int __init vsyscall_setup(char *str)
}
early_param("vsyscall", vsyscall_setup);
-void update_vsyscall_tz(void)
-{
- vsyscall_gtod_data.sys_tz = sys_tz;
-}
-
-void update_vsyscall(struct timekeeper *tk)
-{
- struct vsyscall_gtod_data *vdata = &vsyscall_gtod_data;
-
- write_seqcount_begin(&vdata->seq);
-
- /* copy vsyscall data */
- vdata->clock.vclock_mode = tk->clock->archdata.vclock_mode;
- vdata->clock.cycle_last = tk->clock->cycle_last;
- vdata->clock.mask = tk->clock->mask;
- vdata->clock.mult = tk->mult;
- vdata->clock.shift = tk->shift;
-
- vdata->wall_time_sec = tk->xtime_sec;
- vdata->wall_time_snsec = tk->xtime_nsec;
-
- vdata->monotonic_time_sec = tk->xtime_sec
- + tk->wall_to_monotonic.tv_sec;
- vdata->monotonic_time_snsec = tk->xtime_nsec
- + (tk->wall_to_monotonic.tv_nsec
- << tk->shift);
- while (vdata->monotonic_time_snsec >=
- (((u64)NSEC_PER_SEC) << tk->shift)) {
- vdata->monotonic_time_snsec -=
- ((u64)NSEC_PER_SEC) << tk->shift;
- vdata->monotonic_time_sec++;
- }
-
- vdata->wall_time_coarse.tv_sec = tk->xtime_sec;
- vdata->wall_time_coarse.tv_nsec = (long)(tk->xtime_nsec >> tk->shift);
-
- vdata->monotonic_time_coarse = timespec_add(vdata->wall_time_coarse,
- tk->wall_to_monotonic);
-
- write_seqcount_end(&vdata->seq);
-}
-
static void warn_bad_vsyscall(const char *level, struct pt_regs *regs,
const char *message)
{
@@ -374,7 +330,6 @@ void __init map_vsyscall(void)
{
extern char __vsyscall_page;
unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page);
- extern char __vvar_page;
unsigned long physaddr_vvar_page = __pa_symbol(&__vvar_page);
__set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_vsyscall,
diff --git a/arch/x86/kernel/vsyscall_gtod.c b/arch/x86/kernel/vsyscall_gtod.c
new file mode 100644
index 000000000000..f9c6e56e14b5
--- /dev/null
+++ b/arch/x86/kernel/vsyscall_gtod.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE
+ * Copyright 2003 Andi Kleen, SuSE Labs.
+ *
+ * Modified for x86 32 bit architecture by
+ * Stefani Seibold <stefani@seibold.net>
+ * sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany
+ *
+ * Thanks to hpa@transmeta.com for some useful hint.
+ * Special thanks to Ingo Molnar for his early experience with
+ * a different vsyscall implementation for Linux/IA32 and for the name.
+ *
+ */
+
+#include <linux/timekeeper_internal.h>
+#include <asm/vgtod.h>
+#include <asm/vvar.h>
+
+DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data);
+
+void update_vsyscall_tz(void)
+{
+ vsyscall_gtod_data.tz_minuteswest = sys_tz.tz_minuteswest;
+ vsyscall_gtod_data.tz_dsttime = sys_tz.tz_dsttime;
+}
+
+void update_vsyscall(struct timekeeper *tk)
+{
+ struct vsyscall_gtod_data *vdata = &vsyscall_gtod_data;
+
+ gtod_write_begin(vdata);
+
+ /* copy vsyscall data */
+ vdata->vclock_mode = tk->clock->archdata.vclock_mode;
+ vdata->cycle_last = tk->clock->cycle_last;
+ vdata->mask = tk->clock->mask;
+ vdata->mult = tk->mult;
+ vdata->shift = tk->shift;
+
+ vdata->wall_time_sec = tk->xtime_sec;
+ vdata->wall_time_snsec = tk->xtime_nsec;
+
+ vdata->monotonic_time_sec = tk->xtime_sec
+ + tk->wall_to_monotonic.tv_sec;
+ vdata->monotonic_time_snsec = tk->xtime_nsec
+ + (tk->wall_to_monotonic.tv_nsec
+ << tk->shift);
+ while (vdata->monotonic_time_snsec >=
+ (((u64)NSEC_PER_SEC) << tk->shift)) {
+ vdata->monotonic_time_snsec -=
+ ((u64)NSEC_PER_SEC) << tk->shift;
+ vdata->monotonic_time_sec++;
+ }
+
+ vdata->wall_time_coarse_sec = tk->xtime_sec;
+ vdata->wall_time_coarse_nsec = (long)(tk->xtime_nsec >> tk->shift);
+
+ vdata->monotonic_time_coarse_sec =
+ vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec;
+ vdata->monotonic_time_coarse_nsec =
+ vdata->wall_time_coarse_nsec + tk->wall_to_monotonic.tv_nsec;
+
+ while (vdata->monotonic_time_coarse_nsec >= NSEC_PER_SEC) {
+ vdata->monotonic_time_coarse_nsec -= NSEC_PER_SEC;
+ vdata->monotonic_time_coarse_sec++;
+ }
+
+ gtod_write_end(vdata);
+}
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index c6976257eff5..bea60671ef8a 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -28,7 +28,7 @@ static u32 xstate_required_size(u64 xstate_bv)
int feature_bit = 0;
u32 ret = XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET;
- xstate_bv &= ~XSTATE_FPSSE;
+ xstate_bv &= XSTATE_EXTEND_MASK;
while (xstate_bv) {
if (xstate_bv & 0x1) {
u32 eax, ebx, ecx, edx;
@@ -43,6 +43,16 @@ static u32 xstate_required_size(u64 xstate_bv)
return ret;
}
+u64 kvm_supported_xcr0(void)
+{
+ u64 xcr0 = KVM_SUPPORTED_XCR0 & host_xcr0;
+
+ if (!kvm_x86_ops->mpx_supported())
+ xcr0 &= ~(XSTATE_BNDREGS | XSTATE_BNDCSR);
+
+ return xcr0;
+}
+
void kvm_update_cpuid(struct kvm_vcpu *vcpu)
{
struct kvm_cpuid_entry2 *best;
@@ -73,9 +83,9 @@ void kvm_update_cpuid(struct kvm_vcpu *vcpu)
} else {
vcpu->arch.guest_supported_xcr0 =
(best->eax | ((u64)best->edx << 32)) &
- host_xcr0 & KVM_SUPPORTED_XCR0;
- vcpu->arch.guest_xstate_size =
- xstate_required_size(vcpu->arch.guest_supported_xcr0);
+ kvm_supported_xcr0();
+ vcpu->arch.guest_xstate_size = best->ebx =
+ xstate_required_size(vcpu->arch.xcr0);
}
kvm_pmu_cpuid_update(vcpu);
@@ -210,13 +220,6 @@ static void do_cpuid_1_ent(struct kvm_cpuid_entry2 *entry, u32 function,
entry->flags = 0;
}
-static bool supported_xcr0_bit(unsigned bit)
-{
- u64 mask = ((u64)1 << bit);
-
- return mask & KVM_SUPPORTED_XCR0 & host_xcr0;
-}
-
#define F(x) bit(X86_FEATURE_##x)
static int __do_cpuid_ent_emulated(struct kvm_cpuid_entry2 *entry,
@@ -256,6 +259,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
#endif
unsigned f_rdtscp = kvm_x86_ops->rdtscp_supported() ? F(RDTSCP) : 0;
unsigned f_invpcid = kvm_x86_ops->invpcid_supported() ? F(INVPCID) : 0;
+ unsigned f_mpx = kvm_x86_ops->mpx_supported() ? F(MPX) : 0;
/* cpuid 1.edx */
const u32 kvm_supported_word0_x86_features =
@@ -263,7 +267,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
F(TSC) | F(MSR) | F(PAE) | F(MCE) |
F(CX8) | F(APIC) | 0 /* Reserved */ | F(SEP) |
F(MTRR) | F(PGE) | F(MCA) | F(CMOV) |
- F(PAT) | F(PSE36) | 0 /* PSN */ | F(CLFLSH) |
+ F(PAT) | F(PSE36) | 0 /* PSN */ | F(CLFLUSH) |
0 /* Reserved, DS, ACPI */ | F(MMX) |
F(FXSR) | F(XMM) | F(XMM2) | F(SELFSNOOP) |
0 /* HTT, TM, Reserved, PBE */;
@@ -303,7 +307,8 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
/* cpuid 7.0.ebx */
const u32 kvm_supported_word9_x86_features =
F(FSGSBASE) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
- F(BMI2) | F(ERMS) | f_invpcid | F(RTM);
+ F(BMI2) | F(ERMS) | f_invpcid | F(RTM) | f_mpx | F(RDSEED) |
+ F(ADX);
/* all calls to cpuid_count() should be made on the same cpu */
get_cpu();
@@ -436,16 +441,18 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
}
case 0xd: {
int idx, i;
+ u64 supported = kvm_supported_xcr0();
- entry->eax &= host_xcr0 & KVM_SUPPORTED_XCR0;
- entry->edx &= (host_xcr0 & KVM_SUPPORTED_XCR0) >> 32;
+ entry->eax &= supported;
+ entry->edx &= supported >> 32;
entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
for (idx = 1, i = 1; idx < 64; ++idx) {
+ u64 mask = ((u64)1 << idx);
if (*nent >= maxnent)
goto out;
do_cpuid_1_ent(&entry[i], function, idx);
- if (entry[i].eax == 0 || !supported_xcr0_bit(idx))
+ if (entry[i].eax == 0 || !(supported & mask))
continue;
entry[i].flags |=
KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 07ffca0a89e9..205b17eed93c 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -3668,6 +3668,10 @@ static const struct gprefix pfx_vmovntpx = {
I(0, em_mov), N, N, N,
};
+static const struct gprefix pfx_0f_28_0f_29 = {
+ I(Aligned, em_mov), I(Aligned, em_mov), N, N,
+};
+
static const struct escape escape_d9 = { {
N, N, N, N, N, N, N, I(DstMem, em_fnstcw),
}, {
@@ -3870,7 +3874,9 @@ static const struct opcode twobyte_table[256] = {
IIP(ModRM | SrcMem | Priv | Op3264, em_cr_write, cr_write, check_cr_write),
IIP(ModRM | SrcMem | Priv | Op3264, em_dr_write, dr_write, check_dr_write),
N, N, N, N,
- N, N, N, GP(ModRM | DstMem | SrcReg | Sse | Mov | Aligned, &pfx_vmovntpx),
+ GP(ModRM | DstReg | SrcMem | Mov | Sse, &pfx_0f_28_0f_29),
+ GP(ModRM | DstMem | SrcReg | Mov | Sse, &pfx_0f_28_0f_29),
+ N, GP(ModRM | DstMem | SrcReg | Sse | Mov | Aligned, &pfx_vmovntpx),
N, N, N, N,
/* 0x30 - 0x3F */
II(ImplicitOps | Priv, em_wrmsr, wrmsr),
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index e50425d0f5f7..f5704d9e5ddc 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -2672,6 +2672,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
break;
}
+ drop_large_spte(vcpu, iterator.sptep);
if (!is_shadow_present_pte(*iterator.sptep)) {
u64 base_addr = iterator.addr;
@@ -3328,7 +3329,7 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn)
arch.direct_map = vcpu->arch.mmu.direct_map;
arch.cr3 = vcpu->arch.mmu.get_cr3(vcpu);
- return kvm_setup_async_pf(vcpu, gva, gfn, &arch);
+ return kvm_setup_async_pf(vcpu, gva, gfn_to_hva(vcpu->kvm, gfn), &arch);
}
static bool can_do_async_pf(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index cba218a2f08d..b1e6c1bf68d3 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -913,7 +913,8 @@ static gpa_t FNAME(gva_to_gpa_nested)(struct kvm_vcpu *vcpu, gva_t vaddr,
* and kvm_mmu_notifier_invalidate_range_start detect the mapping page isn't
* used by guest then tlbs are not flushed, so guest is allowed to access the
* freed pages.
- * And we increase kvm->tlbs_dirty to delay tlbs flush in this case.
+ * We set tlbs_dirty to let the notifier know this change and delay the flush
+ * until such a case actually happens.
*/
static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
{
@@ -942,7 +943,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
return -EINVAL;
if (FNAME(prefetch_invalid_gpte)(vcpu, sp, &sp->spt[i], gpte)) {
- vcpu->kvm->tlbs_dirty++;
+ vcpu->kvm->tlbs_dirty = true;
continue;
}
@@ -957,7 +958,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
if (gfn != sp->gfns[i]) {
drop_spte(vcpu->kvm, &sp->spt[i]);
- vcpu->kvm->tlbs_dirty++;
+ vcpu->kvm->tlbs_dirty = true;
continue;
}
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index e81df8fce027..7f4f9c2badae 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -34,6 +34,7 @@
#include <asm/perf_event.h>
#include <asm/tlbflush.h>
#include <asm/desc.h>
+#include <asm/debugreg.h>
#include <asm/kvm_para.h>
#include <asm/virtext.h>
@@ -303,20 +304,35 @@ static inline bool is_cr_intercept(struct vcpu_svm *svm, int bit)
return vmcb->control.intercept_cr & (1U << bit);
}
-static inline void set_dr_intercept(struct vcpu_svm *svm, int bit)
+static inline void set_dr_intercepts(struct vcpu_svm *svm)
{
struct vmcb *vmcb = get_host_vmcb(svm);
- vmcb->control.intercept_dr |= (1U << bit);
+ vmcb->control.intercept_dr = (1 << INTERCEPT_DR0_READ)
+ | (1 << INTERCEPT_DR1_READ)
+ | (1 << INTERCEPT_DR2_READ)
+ | (1 << INTERCEPT_DR3_READ)
+ | (1 << INTERCEPT_DR4_READ)
+ | (1 << INTERCEPT_DR5_READ)
+ | (1 << INTERCEPT_DR6_READ)
+ | (1 << INTERCEPT_DR7_READ)
+ | (1 << INTERCEPT_DR0_WRITE)
+ | (1 << INTERCEPT_DR1_WRITE)
+ | (1 << INTERCEPT_DR2_WRITE)
+ | (1 << INTERCEPT_DR3_WRITE)
+ | (1 << INTERCEPT_DR4_WRITE)
+ | (1 << INTERCEPT_DR5_WRITE)
+ | (1 << INTERCEPT_DR6_WRITE)
+ | (1 << INTERCEPT_DR7_WRITE);
recalc_intercepts(svm);
}
-static inline void clr_dr_intercept(struct vcpu_svm *svm, int bit)
+static inline void clr_dr_intercepts(struct vcpu_svm *svm)
{
struct vmcb *vmcb = get_host_vmcb(svm);
- vmcb->control.intercept_dr &= ~(1U << bit);
+ vmcb->control.intercept_dr = 0;
recalc_intercepts(svm);
}
@@ -1080,23 +1096,7 @@ static void init_vmcb(struct vcpu_svm *svm)
set_cr_intercept(svm, INTERCEPT_CR4_WRITE);
set_cr_intercept(svm, INTERCEPT_CR8_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR0_READ);
- set_dr_intercept(svm, INTERCEPT_DR1_READ);
- set_dr_intercept(svm, INTERCEPT_DR2_READ);
- set_dr_intercept(svm, INTERCEPT_DR3_READ);
- set_dr_intercept(svm, INTERCEPT_DR4_READ);
- set_dr_intercept(svm, INTERCEPT_DR5_READ);
- set_dr_intercept(svm, INTERCEPT_DR6_READ);
- set_dr_intercept(svm, INTERCEPT_DR7_READ);
-
- set_dr_intercept(svm, INTERCEPT_DR0_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR1_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR2_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR3_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR4_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR5_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR6_WRITE);
- set_dr_intercept(svm, INTERCEPT_DR7_WRITE);
+ set_dr_intercepts(svm);
set_exception_intercept(svm, PF_VECTOR);
set_exception_intercept(svm, UD_VECTOR);
@@ -1684,6 +1684,21 @@ static void svm_set_dr6(struct kvm_vcpu *vcpu, unsigned long value)
mark_dirty(svm->vmcb, VMCB_DR);
}
+static void svm_sync_dirty_debug_regs(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ get_debugreg(vcpu->arch.db[0], 0);
+ get_debugreg(vcpu->arch.db[1], 1);
+ get_debugreg(vcpu->arch.db[2], 2);
+ get_debugreg(vcpu->arch.db[3], 3);
+ vcpu->arch.dr6 = svm_get_dr6(vcpu);
+ vcpu->arch.dr7 = svm->vmcb->save.dr7;
+
+ vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_WONT_EXIT;
+ set_dr_intercepts(svm);
+}
+
static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -2842,6 +2857,7 @@ static int iret_interception(struct vcpu_svm *svm)
clr_intercept(svm, INTERCEPT_IRET);
svm->vcpu.arch.hflags |= HF_IRET_MASK;
svm->nmi_iret_rip = kvm_rip_read(&svm->vcpu);
+ kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
return 1;
}
@@ -2974,6 +2990,17 @@ static int dr_interception(struct vcpu_svm *svm)
unsigned long val;
int err;
+ if (svm->vcpu.guest_debug == 0) {
+ /*
+ * No more DR vmexits; force a reload of the debug registers
+ * and reenter on this instruction. The next vmexit will
+ * retrieve the full state of the debug registers.
+ */
+ clr_dr_intercepts(svm);
+ svm->vcpu.arch.switch_db_regs |= KVM_DEBUGREG_WONT_EXIT;
+ return 1;
+ }
+
if (!boot_cpu_has(X86_FEATURE_DECODEASSISTS))
return emulate_on_interception(svm);
@@ -3002,10 +3029,8 @@ static int cr8_write_interception(struct vcpu_svm *svm)
u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
/* instruction emulation calls kvm_set_cr8() */
r = cr_interception(svm);
- if (irqchip_in_kernel(svm->vcpu.kvm)) {
- clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
+ if (irqchip_in_kernel(svm->vcpu.kvm))
return r;
- }
if (cr8_prev <= kvm_get_cr8(&svm->vcpu))
return r;
kvm_run->exit_reason = KVM_EXIT_SET_TPR;
@@ -3567,6 +3592,8 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
if (is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK))
return;
+ clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
+
if (irr == -1)
return;
@@ -3649,7 +3676,7 @@ static int svm_interrupt_allowed(struct kvm_vcpu *vcpu)
return ret;
}
-static int enable_irq_window(struct kvm_vcpu *vcpu)
+static void enable_irq_window(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -3663,16 +3690,15 @@ static int enable_irq_window(struct kvm_vcpu *vcpu)
svm_set_vintr(svm);
svm_inject_irq(svm, 0x0);
}
- return 0;
}
-static int enable_nmi_window(struct kvm_vcpu *vcpu)
+static void enable_nmi_window(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
if ((svm->vcpu.arch.hflags & (HF_NMI_MASK | HF_IRET_MASK))
== HF_NMI_MASK)
- return 0; /* IRET will cause a vm exit */
+ return; /* IRET will cause a vm exit */
/*
* Something prevents NMI from been injected. Single step over possible
@@ -3681,7 +3707,6 @@ static int enable_nmi_window(struct kvm_vcpu *vcpu)
svm->nmi_singlestep = true;
svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF);
update_db_bp_intercept(vcpu);
- return 0;
}
static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr)
@@ -4064,6 +4089,11 @@ static bool svm_invpcid_supported(void)
return false;
}
+static bool svm_mpx_supported(void)
+{
+ return false;
+}
+
static bool svm_has_wbinvd_exit(void)
{
return true;
@@ -4302,6 +4332,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.get_dr6 = svm_get_dr6,
.set_dr6 = svm_set_dr6,
.set_dr7 = svm_set_dr7,
+ .sync_dirty_debug_regs = svm_sync_dirty_debug_regs,
.cache_reg = svm_cache_reg,
.get_rflags = svm_get_rflags,
.set_rflags = svm_set_rflags,
@@ -4345,6 +4376,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.rdtscp_supported = svm_rdtscp_supported,
.invpcid_supported = svm_invpcid_supported,
+ .mpx_supported = svm_mpx_supported,
.set_supported_cpuid = svm_set_supported_cpuid,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index a06f101ef64b..1320e0f8e611 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -31,6 +31,7 @@
#include <linux/ftrace_event.h>
#include <linux/slab.h>
#include <linux/tboot.h>
+#include <linux/hrtimer.h>
#include "kvm_cache_regs.h"
#include "x86.h"
@@ -42,6 +43,7 @@
#include <asm/i387.h>
#include <asm/xcr.h>
#include <asm/perf_event.h>
+#include <asm/debugreg.h>
#include <asm/kexec.h>
#include "trace.h"
@@ -110,6 +112,8 @@ module_param(nested, bool, S_IRUGO);
#define RMODE_GUEST_OWNED_EFLAGS_BITS (~(X86_EFLAGS_IOPL | X86_EFLAGS_VM))
+#define VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE 5
+
/*
* These 2 parameters are used to config the controls for Pause-Loop Exiting:
* ple_gap: upper bound on the amount of time between two successive
@@ -202,6 +206,7 @@ struct __packed vmcs12 {
u64 guest_pdptr1;
u64 guest_pdptr2;
u64 guest_pdptr3;
+ u64 guest_bndcfgs;
u64 host_ia32_pat;
u64 host_ia32_efer;
u64 host_ia32_perf_global_ctrl;
@@ -374,6 +379,9 @@ struct nested_vmx {
*/
struct page *apic_access_page;
u64 msr_ia32_feature_control;
+
+ struct hrtimer preemption_timer;
+ bool preemption_timer_expired;
};
#define POSTED_INTR_ON 0
@@ -441,6 +449,7 @@ struct vcpu_vmx {
#endif
int gs_ldt_reload_needed;
int fs_reload_needed;
+ u64 msr_host_bndcfgs;
} host_state;
struct {
int vm86_active;
@@ -533,6 +542,7 @@ static const unsigned long shadow_read_write_fields[] = {
GUEST_CS_LIMIT,
GUEST_CS_BASE,
GUEST_ES_BASE,
+ GUEST_BNDCFGS,
CR0_GUEST_HOST_MASK,
CR0_READ_SHADOW,
CR4_READ_SHADOW,
@@ -588,6 +598,7 @@ static const unsigned short vmcs_field_to_offset_table[] = {
FIELD64(GUEST_PDPTR1, guest_pdptr1),
FIELD64(GUEST_PDPTR2, guest_pdptr2),
FIELD64(GUEST_PDPTR3, guest_pdptr3),
+ FIELD64(GUEST_BNDCFGS, guest_bndcfgs),
FIELD64(HOST_IA32_PAT, host_ia32_pat),
FIELD64(HOST_IA32_EFER, host_ia32_efer),
FIELD64(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl),
@@ -718,6 +729,7 @@ static unsigned long nested_ept_get_cr3(struct kvm_vcpu *vcpu);
static u64 construct_eptp(unsigned long root_hpa);
static void kvm_cpu_vmxon(u64 addr);
static void kvm_cpu_vmxoff(void);
+static bool vmx_mpx_supported(void);
static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr);
static void vmx_set_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg);
@@ -728,6 +740,7 @@ static u32 vmx_segment_access_rights(struct kvm_segment *var);
static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu);
static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx);
static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx);
+static bool vmx_mpx_supported(void);
static DEFINE_PER_CPU(struct vmcs *, vmxarea);
static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
@@ -1047,6 +1060,12 @@ static inline bool nested_cpu_has_virtual_nmis(struct vmcs12 *vmcs12)
return vmcs12->pin_based_vm_exec_control & PIN_BASED_VIRTUAL_NMIS;
}
+static inline bool nested_cpu_has_preemption_timer(struct vmcs12 *vmcs12)
+{
+ return vmcs12->pin_based_vm_exec_control &
+ PIN_BASED_VMX_PREEMPTION_TIMER;
+}
+
static inline int nested_cpu_has_ept(struct vmcs12 *vmcs12)
{
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_EPT);
@@ -1710,6 +1729,8 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
if (is_long_mode(&vmx->vcpu))
wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
#endif
+ if (boot_cpu_has(X86_FEATURE_MPX))
+ rdmsrl(MSR_IA32_BNDCFGS, vmx->host_state.msr_host_bndcfgs);
for (i = 0; i < vmx->save_nmsrs; ++i)
kvm_set_shared_msr(vmx->guest_msrs[i].index,
vmx->guest_msrs[i].data,
@@ -1747,6 +1768,8 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
#ifdef CONFIG_X86_64
wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
#endif
+ if (vmx->host_state.msr_host_bndcfgs)
+ wrmsrl(MSR_IA32_BNDCFGS, vmx->host_state.msr_host_bndcfgs);
/*
* If the FPU is not active (through the host task or
* the guest vcpu), then restore the cr0.TS bit.
@@ -2248,9 +2271,9 @@ static __init void nested_vmx_setup_ctls_msrs(void)
*/
nested_vmx_pinbased_ctls_low |= PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR;
nested_vmx_pinbased_ctls_high &= PIN_BASED_EXT_INTR_MASK |
- PIN_BASED_NMI_EXITING | PIN_BASED_VIRTUAL_NMIS |
+ PIN_BASED_NMI_EXITING | PIN_BASED_VIRTUAL_NMIS;
+ nested_vmx_pinbased_ctls_high |= PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR |
PIN_BASED_VMX_PREEMPTION_TIMER;
- nested_vmx_pinbased_ctls_high |= PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR;
/*
* Exit controls
@@ -2265,15 +2288,12 @@ static __init void nested_vmx_setup_ctls_msrs(void)
#ifdef CONFIG_X86_64
VM_EXIT_HOST_ADDR_SPACE_SIZE |
#endif
- VM_EXIT_LOAD_IA32_PAT | VM_EXIT_SAVE_IA32_PAT |
+ VM_EXIT_LOAD_IA32_PAT | VM_EXIT_SAVE_IA32_PAT;
+ nested_vmx_exit_ctls_high |= VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR |
+ VM_EXIT_LOAD_IA32_EFER | VM_EXIT_SAVE_IA32_EFER |
VM_EXIT_SAVE_VMX_PREEMPTION_TIMER;
- if (!(nested_vmx_pinbased_ctls_high & PIN_BASED_VMX_PREEMPTION_TIMER) ||
- !(nested_vmx_exit_ctls_high & VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)) {
- nested_vmx_exit_ctls_high &= ~VM_EXIT_SAVE_VMX_PREEMPTION_TIMER;
- nested_vmx_pinbased_ctls_high &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
- }
- nested_vmx_exit_ctls_high |= (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR |
- VM_EXIT_LOAD_IA32_EFER | VM_EXIT_SAVE_IA32_EFER);
+ if (vmx_mpx_supported())
+ nested_vmx_exit_ctls_high |= VM_EXIT_CLEAR_BNDCFGS;
/* entry controls */
rdmsr(MSR_IA32_VMX_ENTRY_CTLS,
@@ -2287,6 +2307,8 @@ static __init void nested_vmx_setup_ctls_msrs(void)
VM_ENTRY_LOAD_IA32_PAT;
nested_vmx_entry_ctls_high |= (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR |
VM_ENTRY_LOAD_IA32_EFER);
+ if (vmx_mpx_supported())
+ nested_vmx_entry_ctls_high |= VM_ENTRY_LOAD_BNDCFGS;
/* cpu-based controls */
rdmsr(MSR_IA32_VMX_PROCBASED_CTLS,
@@ -2342,9 +2364,9 @@ static __init void nested_vmx_setup_ctls_msrs(void)
/* miscellaneous data */
rdmsr(MSR_IA32_VMX_MISC, nested_vmx_misc_low, nested_vmx_misc_high);
- nested_vmx_misc_low &= VMX_MISC_PREEMPTION_TIMER_RATE_MASK |
- VMX_MISC_SAVE_EFER_LMA;
- nested_vmx_misc_low |= VMX_MISC_ACTIVITY_HLT;
+ nested_vmx_misc_low &= VMX_MISC_SAVE_EFER_LMA;
+ nested_vmx_misc_low |= VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE |
+ VMX_MISC_ACTIVITY_HLT;
nested_vmx_misc_high = 0;
}
@@ -2479,6 +2501,11 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
case MSR_IA32_SYSENTER_ESP:
data = vmcs_readl(GUEST_SYSENTER_ESP);
break;
+ case MSR_IA32_BNDCFGS:
+ if (!vmx_mpx_supported())
+ return 1;
+ data = vmcs_read64(GUEST_BNDCFGS);
+ break;
case MSR_IA32_FEATURE_CONTROL:
if (!nested_vmx_allowed(vcpu))
return 1;
@@ -2547,6 +2574,11 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case MSR_IA32_SYSENTER_ESP:
vmcs_writel(GUEST_SYSENTER_ESP, data);
break;
+ case MSR_IA32_BNDCFGS:
+ if (!vmx_mpx_supported())
+ return 1;
+ vmcs_write64(GUEST_BNDCFGS, data);
+ break;
case MSR_IA32_TSC:
kvm_write_tsc(vcpu, msr_info);
break;
@@ -2832,12 +2864,12 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
vmx_capability.ept, vmx_capability.vpid);
}
- min = 0;
+ min = VM_EXIT_SAVE_DEBUG_CONTROLS;
#ifdef CONFIG_X86_64
min |= VM_EXIT_HOST_ADDR_SPACE_SIZE;
#endif
opt = VM_EXIT_SAVE_IA32_PAT | VM_EXIT_LOAD_IA32_PAT |
- VM_EXIT_ACK_INTR_ON_EXIT;
+ VM_EXIT_ACK_INTR_ON_EXIT | VM_EXIT_CLEAR_BNDCFGS;
if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS,
&_vmexit_control) < 0)
return -EIO;
@@ -2853,8 +2885,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
!(_vmexit_control & VM_EXIT_ACK_INTR_ON_EXIT))
_pin_based_exec_control &= ~PIN_BASED_POSTED_INTR;
- min = 0;
- opt = VM_ENTRY_LOAD_IA32_PAT;
+ min = VM_ENTRY_LOAD_DEBUG_CONTROLS;
+ opt = VM_ENTRY_LOAD_IA32_PAT | VM_ENTRY_LOAD_BNDCFGS;
if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS,
&_vmentry_control) < 0)
return -EIO;
@@ -4223,6 +4255,10 @@ static u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx)
static u32 vmx_exec_control(struct vcpu_vmx *vmx)
{
u32 exec_control = vmcs_config.cpu_based_exec_ctrl;
+
+ if (vmx->vcpu.arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)
+ exec_control &= ~CPU_BASED_MOV_DR_EXITING;
+
if (!vm_need_tpr_shadow(vmx->vcpu.kvm)) {
exec_control &= ~CPU_BASED_TPR_SHADOW;
#ifdef CONFIG_X86_64
@@ -4496,39 +4532,28 @@ static bool nested_exit_on_nmi(struct kvm_vcpu *vcpu)
PIN_BASED_NMI_EXITING;
}
-static int enable_irq_window(struct kvm_vcpu *vcpu)
+static void enable_irq_window(struct kvm_vcpu *vcpu)
{
u32 cpu_based_vm_exec_control;
- if (is_guest_mode(vcpu) && nested_exit_on_intr(vcpu))
- /*
- * We get here if vmx_interrupt_allowed() said we can't
- * inject to L1 now because L2 must run. The caller will have
- * to make L2 exit right after entry, so we can inject to L1
- * more promptly.
- */
- return -EBUSY;
-
cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
- return 0;
}
-static int enable_nmi_window(struct kvm_vcpu *vcpu)
+static void enable_nmi_window(struct kvm_vcpu *vcpu)
{
u32 cpu_based_vm_exec_control;
- if (!cpu_has_virtual_nmis())
- return enable_irq_window(vcpu);
-
- if (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_STI)
- return enable_irq_window(vcpu);
+ if (!cpu_has_virtual_nmis() ||
+ vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_STI) {
+ enable_irq_window(vcpu);
+ return;
+ }
cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_NMI_PENDING;
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
- return 0;
}
static void vmx_inject_irq(struct kvm_vcpu *vcpu)
@@ -4620,22 +4645,8 @@ static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
static int vmx_nmi_allowed(struct kvm_vcpu *vcpu)
{
- if (is_guest_mode(vcpu)) {
- if (to_vmx(vcpu)->nested.nested_run_pending)
- return 0;
- if (nested_exit_on_nmi(vcpu)) {
- nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI,
- NMI_VECTOR | INTR_TYPE_NMI_INTR |
- INTR_INFO_VALID_MASK, 0);
- /*
- * The NMI-triggered VM exit counts as injection:
- * clear this one and block further NMIs.
- */
- vcpu->arch.nmi_pending = 0;
- vmx_set_nmi_mask(vcpu, true);
- return 0;
- }
- }
+ if (to_vmx(vcpu)->nested.nested_run_pending)
+ return 0;
if (!cpu_has_virtual_nmis() && to_vmx(vcpu)->soft_vnmi_blocked)
return 0;
@@ -4647,19 +4658,8 @@ static int vmx_nmi_allowed(struct kvm_vcpu *vcpu)
static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu)
{
- if (is_guest_mode(vcpu)) {
- if (to_vmx(vcpu)->nested.nested_run_pending)
- return 0;
- if (nested_exit_on_intr(vcpu)) {
- nested_vmx_vmexit(vcpu, EXIT_REASON_EXTERNAL_INTERRUPT,
- 0, 0);
- /*
- * fall through to normal code, but now in L1, not L2
- */
- }
- }
-
- return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
+ return (!to_vmx(vcpu)->nested.nested_run_pending &&
+ vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
!(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS));
}
@@ -5102,6 +5102,22 @@ static int handle_dr(struct kvm_vcpu *vcpu)
}
}
+ if (vcpu->guest_debug == 0) {
+ u32 cpu_based_vm_exec_control;
+
+ cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ cpu_based_vm_exec_control &= ~CPU_BASED_MOV_DR_EXITING;
+ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+
+ /*
+ * No more DR vmexits; force a reload of the debug registers
+ * and reenter on this instruction. The next vmexit will
+ * retrieve the full state of the debug registers.
+ */
+ vcpu->arch.switch_db_regs |= KVM_DEBUGREG_WONT_EXIT;
+ return 1;
+ }
+
exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
dr = exit_qualification & DEBUG_REG_ACCESS_NUM;
reg = DEBUG_REG_ACCESS_REG(exit_qualification);
@@ -5128,6 +5144,24 @@ static void vmx_set_dr6(struct kvm_vcpu *vcpu, unsigned long val)
{
}
+static void vmx_sync_dirty_debug_regs(struct kvm_vcpu *vcpu)
+{
+ u32 cpu_based_vm_exec_control;
+
+ get_debugreg(vcpu->arch.db[0], 0);
+ get_debugreg(vcpu->arch.db[1], 1);
+ get_debugreg(vcpu->arch.db[2], 2);
+ get_debugreg(vcpu->arch.db[3], 3);
+ get_debugreg(vcpu->arch.dr6, 6);
+ vcpu->arch.dr7 = vmcs_readl(GUEST_DR7);
+
+ vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_WONT_EXIT;
+
+ cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ cpu_based_vm_exec_control |= CPU_BASED_MOV_DR_EXITING;
+ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+}
+
static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val)
{
vmcs_writel(GUEST_DR7, val);
@@ -5727,6 +5761,18 @@ static void nested_vmx_failValid(struct kvm_vcpu *vcpu,
*/
}
+static enum hrtimer_restart vmx_preemption_timer_fn(struct hrtimer *timer)
+{
+ struct vcpu_vmx *vmx =
+ container_of(timer, struct vcpu_vmx, nested.preemption_timer);
+
+ vmx->nested.preemption_timer_expired = true;
+ kvm_make_request(KVM_REQ_EVENT, &vmx->vcpu);
+ kvm_vcpu_kick(&vmx->vcpu);
+
+ return HRTIMER_NORESTART;
+}
+
/*
* Emulate the VMXON instruction.
* Currently, we just remember that VMX is active, and do not save or even
@@ -5791,6 +5837,10 @@ static int handle_vmon(struct kvm_vcpu *vcpu)
INIT_LIST_HEAD(&(vmx->nested.vmcs02_pool));
vmx->nested.vmcs02_num = 0;
+ hrtimer_init(&vmx->nested.preemption_timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ vmx->nested.preemption_timer.function = vmx_preemption_timer_fn;
+
vmx->nested.vmxon = true;
skip_emulated_instruction(vcpu);
@@ -6688,7 +6738,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
else if (is_page_fault(intr_info))
return enable_ept;
else if (is_no_device(intr_info) &&
- !(nested_read_cr0(vmcs12) & X86_CR0_TS))
+ !(vmcs12->guest_cr0 & X86_CR0_TS))
return 0;
return vmcs12->exception_bitmap &
(1u << (intr_info & INTR_INFO_VECTOR_MASK));
@@ -6767,9 +6817,6 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
* table is L0's fault.
*/
return 0;
- case EXIT_REASON_PREEMPTION_TIMER:
- return vmcs12->pin_based_vm_exec_control &
- PIN_BASED_VMX_PREEMPTION_TIMER;
case EXIT_REASON_WBINVD:
return nested_cpu_has2(vmcs12, SECONDARY_EXEC_WBINVD_EXITING);
case EXIT_REASON_XSETBV:
@@ -6785,27 +6832,6 @@ static void vmx_get_exit_info(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2)
*info2 = vmcs_read32(VM_EXIT_INTR_INFO);
}
-static void nested_adjust_preemption_timer(struct kvm_vcpu *vcpu)
-{
- u64 delta_tsc_l1;
- u32 preempt_val_l1, preempt_val_l2, preempt_scale;
-
- if (!(get_vmcs12(vcpu)->pin_based_vm_exec_control &
- PIN_BASED_VMX_PREEMPTION_TIMER))
- return;
- preempt_scale = native_read_msr(MSR_IA32_VMX_MISC) &
- MSR_IA32_VMX_MISC_PREEMPTION_TIMER_SCALE;
- preempt_val_l2 = vmcs_read32(VMX_PREEMPTION_TIMER_VALUE);
- delta_tsc_l1 = vmx_read_l1_tsc(vcpu, native_read_tsc())
- - vcpu->arch.last_guest_tsc;
- preempt_val_l1 = delta_tsc_l1 >> preempt_scale;
- if (preempt_val_l2 <= preempt_val_l1)
- preempt_val_l2 = 0;
- else
- preempt_val_l2 -= preempt_val_l1;
- vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, preempt_val_l2);
-}
-
/*
* The guest has exited. See if we can fix it or if we need userspace
* assistance.
@@ -7052,6 +7078,12 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
local_irq_enable();
}
+static bool vmx_mpx_supported(void)
+{
+ return (vmcs_config.vmexit_ctrl & VM_EXIT_CLEAR_BNDCFGS) &&
+ (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_BNDCFGS);
+}
+
static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
{
u32 exit_intr_info;
@@ -7218,8 +7250,6 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
atomic_switch_perf_msrs(vmx);
debugctlmsr = get_debugctlmsr();
- if (is_guest_mode(vcpu) && !vmx->nested.nested_run_pending)
- nested_adjust_preemption_timer(vcpu);
vmx->__launched = vmx->loaded_vmcs->launched;
asm(
/* Store host registers */
@@ -7616,6 +7646,28 @@ static void vmx_inject_page_fault_nested(struct kvm_vcpu *vcpu,
kvm_inject_page_fault(vcpu, fault);
}
+static void vmx_start_preemption_timer(struct kvm_vcpu *vcpu)
+{
+ u64 preemption_timeout = get_vmcs12(vcpu)->vmx_preemption_timer_value;
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+ if (vcpu->arch.virtual_tsc_khz == 0)
+ return;
+
+ /* Make sure short timeouts reliably trigger an immediate vmexit.
+ * hrtimer_start does not guarantee this. */
+ if (preemption_timeout <= 1) {
+ vmx_preemption_timer_fn(&vmx->nested.preemption_timer);
+ return;
+ }
+
+ preemption_timeout <<= VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE;
+ preemption_timeout *= 1000000;
+ do_div(preemption_timeout, vcpu->arch.virtual_tsc_khz);
+ hrtimer_start(&vmx->nested.preemption_timer,
+ ns_to_ktime(preemption_timeout), HRTIMER_MODE_REL);
+}
+
/*
* prepare_vmcs02 is called when the L1 guest hypervisor runs its nested
* L2 guest. L1 has a vmcs for L2 (vmcs12), and this function "merges" it
@@ -7629,7 +7681,6 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
u32 exec_control;
- u32 exit_control;
vmcs_write16(GUEST_ES_SELECTOR, vmcs12->guest_es_selector);
vmcs_write16(GUEST_CS_SELECTOR, vmcs12->guest_cs_selector);
@@ -7687,13 +7738,14 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
vmcs_write64(VMCS_LINK_POINTER, -1ull);
- vmcs_write32(PIN_BASED_VM_EXEC_CONTROL,
- (vmcs_config.pin_based_exec_ctrl |
- vmcs12->pin_based_vm_exec_control));
+ exec_control = vmcs12->pin_based_vm_exec_control;
+ exec_control |= vmcs_config.pin_based_exec_ctrl;
+ exec_control &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
+ vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, exec_control);
- if (vmcs12->pin_based_vm_exec_control & PIN_BASED_VMX_PREEMPTION_TIMER)
- vmcs_write32(VMX_PREEMPTION_TIMER_VALUE,
- vmcs12->vmx_preemption_timer_value);
+ vmx->nested.preemption_timer_expired = false;
+ if (nested_cpu_has_preemption_timer(vmcs12))
+ vmx_start_preemption_timer(vcpu);
/*
* Whether page-faults are trapped is determined by a combination of
@@ -7721,7 +7773,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
enable_ept ? vmcs12->page_fault_error_code_match : 0);
if (cpu_has_secondary_exec_ctrls()) {
- u32 exec_control = vmx_secondary_exec_control(vmx);
+ exec_control = vmx_secondary_exec_control(vmx);
if (!vmx->rdtscp_enabled)
exec_control &= ~SECONDARY_EXEC_RDTSCP;
/* Take the following fields only from vmcs12 */
@@ -7808,10 +7860,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
* we should use its exit controls. Note that VM_EXIT_LOAD_IA32_EFER
* bits are further modified by vmx_set_efer() below.
*/
- exit_control = vmcs_config.vmexit_ctrl;
- if (vmcs12->pin_based_vm_exec_control & PIN_BASED_VMX_PREEMPTION_TIMER)
- exit_control |= VM_EXIT_SAVE_VMX_PREEMPTION_TIMER;
- vm_exit_controls_init(vmx, exit_control);
+ vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl);
/* vmcs12's VM_ENTRY_LOAD_IA32_EFER and VM_ENTRY_IA32E_MODE are
* emulated by vmx_set_efer(), below.
@@ -7830,6 +7879,9 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
set_cr4_guest_host_mask(vmx);
+ if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS)
+ vmcs_write64(GUEST_BNDCFGS, vmcs12->guest_bndcfgs);
+
if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING)
vmcs_write64(TSC_OFFSET,
vmx->nested.vmcs01_tsc_offset + vmcs12->tsc_offset);
@@ -8155,6 +8207,58 @@ static void vmcs12_save_pending_event(struct kvm_vcpu *vcpu,
}
}
+static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr)
+{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+ if (nested_cpu_has_preemption_timer(get_vmcs12(vcpu)) &&
+ vmx->nested.preemption_timer_expired) {
+ if (vmx->nested.nested_run_pending)
+ return -EBUSY;
+ nested_vmx_vmexit(vcpu, EXIT_REASON_PREEMPTION_TIMER, 0, 0);
+ return 0;
+ }
+
+ if (vcpu->arch.nmi_pending && nested_exit_on_nmi(vcpu)) {
+ if (vmx->nested.nested_run_pending ||
+ vcpu->arch.interrupt.pending)
+ return -EBUSY;
+ nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI,
+ NMI_VECTOR | INTR_TYPE_NMI_INTR |
+ INTR_INFO_VALID_MASK, 0);
+ /*
+ * The NMI-triggered VM exit counts as injection:
+ * clear this one and block further NMIs.
+ */
+ vcpu->arch.nmi_pending = 0;
+ vmx_set_nmi_mask(vcpu, true);
+ return 0;
+ }
+
+ if ((kvm_cpu_has_interrupt(vcpu) || external_intr) &&
+ nested_exit_on_intr(vcpu)) {
+ if (vmx->nested.nested_run_pending)
+ return -EBUSY;
+ nested_vmx_vmexit(vcpu, EXIT_REASON_EXTERNAL_INTERRUPT, 0, 0);
+ }
+
+ return 0;
+}
+
+static u32 vmx_get_preemption_timer_value(struct kvm_vcpu *vcpu)
+{
+ ktime_t remaining =
+ hrtimer_get_remaining(&to_vmx(vcpu)->nested.preemption_timer);
+ u64 value;
+
+ if (ktime_to_ns(remaining) <= 0)
+ return 0;
+
+ value = ktime_to_ns(remaining) * vcpu->arch.virtual_tsc_khz;
+ do_div(value, 1000000);
+ return value >> VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE;
+}
+
/*
* prepare_vmcs12 is part of what we need to do when the nested L2 guest exits
* and we want to prepare to run its L1 parent. L1 keeps a vmcs for L2 (vmcs12),
@@ -8225,10 +8329,13 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
else
vmcs12->guest_activity_state = GUEST_ACTIVITY_ACTIVE;
- if ((vmcs12->pin_based_vm_exec_control & PIN_BASED_VMX_PREEMPTION_TIMER) &&
- (vmcs12->vm_exit_controls & VM_EXIT_SAVE_VMX_PREEMPTION_TIMER))
- vmcs12->vmx_preemption_timer_value =
- vmcs_read32(VMX_PREEMPTION_TIMER_VALUE);
+ if (nested_cpu_has_preemption_timer(vmcs12)) {
+ if (vmcs12->vm_exit_controls &
+ VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)
+ vmcs12->vmx_preemption_timer_value =
+ vmx_get_preemption_timer_value(vcpu);
+ hrtimer_cancel(&to_vmx(vcpu)->nested.preemption_timer);
+ }
/*
* In some cases (usually, nested EPT), L2 is allowed to change its
@@ -8260,6 +8367,8 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
vmcs12->guest_sysenter_cs = vmcs_read32(GUEST_SYSENTER_CS);
vmcs12->guest_sysenter_esp = vmcs_readl(GUEST_SYSENTER_ESP);
vmcs12->guest_sysenter_eip = vmcs_readl(GUEST_SYSENTER_EIP);
+ if (vmx_mpx_supported())
+ vmcs12->guest_bndcfgs = vmcs_read64(GUEST_BNDCFGS);
/* update exit information fields: */
@@ -8369,6 +8478,10 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
vmcs_writel(GUEST_IDTR_BASE, vmcs12->host_idtr_base);
vmcs_writel(GUEST_GDTR_BASE, vmcs12->host_gdtr_base);
+ /* If not VM_EXIT_CLEAR_BNDCFGS, the L2 value propagates to L1. */
+ if (vmcs12->vm_exit_controls & VM_EXIT_CLEAR_BNDCFGS)
+ vmcs_write64(GUEST_BNDCFGS, 0);
+
if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PAT) {
vmcs_write64(GUEST_IA32_PAT, vmcs12->host_ia32_pat);
vcpu->arch.pat = vmcs12->host_ia32_pat;
@@ -8495,6 +8608,9 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
nested_vmx_succeed(vcpu);
if (enable_shadow_vmcs)
vmx->nested.sync_shadow_vmcs = true;
+
+ /* in case we halted in L2 */
+ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
}
/*
@@ -8573,6 +8689,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
.get_dr6 = vmx_get_dr6,
.set_dr6 = vmx_set_dr6,
.set_dr7 = vmx_set_dr7,
+ .sync_dirty_debug_regs = vmx_sync_dirty_debug_regs,
.cache_reg = vmx_cache_reg,
.get_rflags = vmx_get_rflags,
.set_rflags = vmx_set_rflags,
@@ -8634,6 +8751,9 @@ static struct kvm_x86_ops vmx_x86_ops = {
.check_intercept = vmx_check_intercept,
.handle_external_intr = vmx_handle_external_intr,
+ .mpx_supported = vmx_mpx_supported,
+
+ .check_nested_events = vmx_check_nested_events,
};
static int __init vmx_init(void)
@@ -8721,6 +8841,8 @@ static int __init vmx_init(void)
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
+ vmx_disable_intercept_for_msr(MSR_IA32_BNDCFGS, true);
+
memcpy(vmx_msr_bitmap_legacy_x2apic,
vmx_msr_bitmap_legacy, PAGE_SIZE);
memcpy(vmx_msr_bitmap_longmode_x2apic,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 39c28f09dfd5..d1c55f8722c6 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -595,13 +595,13 @@ static void kvm_put_guest_xcr0(struct kvm_vcpu *vcpu)
int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
{
- u64 xcr0;
+ u64 xcr0 = xcr;
+ u64 old_xcr0 = vcpu->arch.xcr0;
u64 valid_bits;
/* Only support XCR_XFEATURE_ENABLED_MASK(xcr0) now */
if (index != XCR_XFEATURE_ENABLED_MASK)
return 1;
- xcr0 = xcr;
if (!(xcr0 & XSTATE_FP))
return 1;
if ((xcr0 & XSTATE_YMM) && !(xcr0 & XSTATE_SSE))
@@ -616,8 +616,14 @@ int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
if (xcr0 & ~valid_bits)
return 1;
+ if ((!(xcr0 & XSTATE_BNDREGS)) != (!(xcr0 & XSTATE_BNDCSR)))
+ return 1;
+
kvm_put_guest_xcr0(vcpu);
vcpu->arch.xcr0 = xcr0;
+
+ if ((xcr0 ^ old_xcr0) & XSTATE_EXTEND_MASK)
+ kvm_update_cpuid(vcpu);
return 0;
}
@@ -753,7 +759,9 @@ static void kvm_update_dr7(struct kvm_vcpu *vcpu)
else
dr7 = vcpu->arch.dr7;
kvm_x86_ops->set_dr7(vcpu, dr7);
- vcpu->arch.switch_db_regs = (dr7 & DR7_BP_EN_MASK);
+ vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_BP_ENABLED;
+ if (dr7 & DR7_BP_EN_MASK)
+ vcpu->arch.switch_db_regs |= KVM_DEBUGREG_BP_ENABLED;
}
static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
@@ -879,7 +887,7 @@ static u32 msrs_to_save[] = {
MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
#endif
MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA,
- MSR_IA32_FEATURE_CONTROL
+ MSR_IA32_FEATURE_CONTROL, MSR_IA32_BNDCFGS
};
static unsigned num_msrs_to_save;
@@ -1581,7 +1589,6 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
/* With all the info we got, fill in the values */
vcpu->hv_clock.tsc_timestamp = tsc_timestamp;
vcpu->hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset;
- vcpu->last_kernel_ns = kernel_ns;
vcpu->last_guest_tsc = tsc_timestamp;
/*
@@ -1623,14 +1630,21 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
* the others.
*
* So in those cases, request a kvmclock update for all vcpus.
- * The worst case for a remote vcpu to update its kvmclock
- * is then bounded by maximum nohz sleep latency.
+ * We need to rate-limit these requests though, as they can
+ * considerably slow guests that have a large number of vcpus.
+ * The time for a remote vcpu to update its kvmclock is bound
+ * by the delay we use to rate-limit the updates.
*/
-static void kvm_gen_kvmclock_update(struct kvm_vcpu *v)
+#define KVMCLOCK_UPDATE_DELAY msecs_to_jiffies(100)
+
+static void kvmclock_update_fn(struct work_struct *work)
{
int i;
- struct kvm *kvm = v->kvm;
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct kvm_arch *ka = container_of(dwork, struct kvm_arch,
+ kvmclock_update_work);
+ struct kvm *kvm = container_of(ka, struct kvm, arch);
struct kvm_vcpu *vcpu;
kvm_for_each_vcpu(i, vcpu, kvm) {
@@ -1639,6 +1653,29 @@ static void kvm_gen_kvmclock_update(struct kvm_vcpu *v)
}
}
+static void kvm_gen_kvmclock_update(struct kvm_vcpu *v)
+{
+ struct kvm *kvm = v->kvm;
+
+ set_bit(KVM_REQ_CLOCK_UPDATE, &v->requests);
+ schedule_delayed_work(&kvm->arch.kvmclock_update_work,
+ KVMCLOCK_UPDATE_DELAY);
+}
+
+#define KVMCLOCK_SYNC_PERIOD (300 * HZ)
+
+static void kvmclock_sync_fn(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct kvm_arch *ka = container_of(dwork, struct kvm_arch,
+ kvmclock_sync_work);
+ struct kvm *kvm = container_of(ka, struct kvm, arch);
+
+ schedule_delayed_work(&kvm->arch.kvmclock_update_work, 0);
+ schedule_delayed_work(&kvm->arch.kvmclock_sync_work,
+ KVMCLOCK_SYNC_PERIOD);
+}
+
static bool msr_mtrr_valid(unsigned msr)
{
switch (msr) {
@@ -2323,9 +2360,12 @@ static int get_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case HV_X64_MSR_VP_INDEX: {
int r;
struct kvm_vcpu *v;
- kvm_for_each_vcpu(r, v, vcpu->kvm)
- if (v == vcpu)
+ kvm_for_each_vcpu(r, v, vcpu->kvm) {
+ if (v == vcpu) {
data = r;
+ break;
+ }
+ }
break;
}
case HV_X64_MSR_EOI:
@@ -2617,6 +2657,7 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_KVMCLOCK_CTRL:
case KVM_CAP_READONLY_MEM:
case KVM_CAP_HYPERV_TIME:
+ case KVM_CAP_IOAPIC_POLARITY_IGNORED:
#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
case KVM_CAP_ASSIGN_DEV_IRQ:
case KVM_CAP_PCI_2_3:
@@ -3043,9 +3084,7 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
* CPUID leaf 0xD, index 0, EDX:EAX. This is for compatibility
* with old userspace.
*/
- if (xstate_bv & ~KVM_SUPPORTED_XCR0)
- return -EINVAL;
- if (xstate_bv & ~host_xcr0)
+ if (xstate_bv & ~kvm_supported_xcr0())
return -EINVAL;
memcpy(&vcpu->arch.guest_fpu.state->xsave,
guest_xsave->region, vcpu->arch.guest_xstate_size);
@@ -3898,6 +3937,23 @@ static void kvm_init_msr_list(void)
for (i = j = KVM_SAVE_MSRS_BEGIN; i < ARRAY_SIZE(msrs_to_save); i++) {
if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0)
continue;
+
+ /*
+ * Even MSRs that are valid in the host may not be exposed
+ * to the guests in some cases. We could work around this
+ * in VMX with the generic MSR save/load machinery, but it
+ * is not really worthwhile since it will really only
+ * happen with nested virtualization.
+ */
+ switch (msrs_to_save[i]) {
+ case MSR_IA32_BNDCFGS:
+ if (!kvm_x86_ops->mpx_supported())
+ continue;
+ break;
+ default:
+ break;
+ }
+
if (j < i)
msrs_to_save[j] = msrs_to_save[i];
j++;
@@ -4394,6 +4450,7 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
if (!exchanged)
return X86EMUL_CMPXCHG_FAILED;
+ mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
kvm_mmu_pte_write(vcpu, gpa, new, bytes);
return X86EMUL_CONTINUE;
@@ -5537,9 +5594,10 @@ int kvm_arch_init(void *opaque)
goto out_free_percpu;
kvm_set_mmio_spte_mask();
- kvm_init_msr_list();
kvm_x86_ops = ops;
+ kvm_init_msr_list();
+
kvm_mmu_set_mask_ptes(PT_USER_MASK, PT_ACCESSED_MASK,
PT_DIRTY_MASK, PT64_NX_MASK, 0);
@@ -5782,8 +5840,10 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr);
}
-static void inject_pending_event(struct kvm_vcpu *vcpu)
+static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
{
+ int r;
+
/* try to reinject previous events if any */
if (vcpu->arch.exception.pending) {
trace_kvm_inj_exception(vcpu->arch.exception.nr,
@@ -5793,17 +5853,23 @@ static void inject_pending_event(struct kvm_vcpu *vcpu)
vcpu->arch.exception.has_error_code,
vcpu->arch.exception.error_code,
vcpu->arch.exception.reinject);
- return;
+ return 0;
}
if (vcpu->arch.nmi_injected) {
kvm_x86_ops->set_nmi(vcpu);
- return;
+ return 0;
}
if (vcpu->arch.interrupt.pending) {
kvm_x86_ops->set_irq(vcpu);
- return;
+ return 0;
+ }
+
+ if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events) {
+ r = kvm_x86_ops->check_nested_events(vcpu, req_int_win);
+ if (r != 0)
+ return r;
}
/* try to inject new event if pending */
@@ -5820,6 +5886,7 @@ static void inject_pending_event(struct kvm_vcpu *vcpu)
kvm_x86_ops->set_irq(vcpu);
}
}
+ return 0;
}
static void process_nmi(struct kvm_vcpu *vcpu)
@@ -5924,15 +5991,13 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
goto out;
}
- inject_pending_event(vcpu);
-
+ if (inject_pending_event(vcpu, req_int_win) != 0)
+ req_immediate_exit = true;
/* enable NMI/IRQ window open exits if needed */
- if (vcpu->arch.nmi_pending)
- req_immediate_exit =
- kvm_x86_ops->enable_nmi_window(vcpu) != 0;
+ else if (vcpu->arch.nmi_pending)
+ kvm_x86_ops->enable_nmi_window(vcpu);
else if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win)
- req_immediate_exit =
- kvm_x86_ops->enable_irq_window(vcpu) != 0;
+ kvm_x86_ops->enable_irq_window(vcpu);
if (kvm_lapic_enabled(vcpu)) {
/*
@@ -5992,12 +6057,28 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
set_debugreg(vcpu->arch.eff_db[1], 1);
set_debugreg(vcpu->arch.eff_db[2], 2);
set_debugreg(vcpu->arch.eff_db[3], 3);
+ set_debugreg(vcpu->arch.dr6, 6);
}
trace_kvm_entry(vcpu->vcpu_id);
kvm_x86_ops->run(vcpu);
/*
+ * Do this here before restoring debug registers on the host. And
+ * since we do this before handling the vmexit, a DR access vmexit
+ * can (a) read the correct value of the debug registers, (b) set
+ * KVM_DEBUGREG_WONT_EXIT again.
+ */
+ if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) {
+ int i;
+
+ WARN_ON(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP);
+ kvm_x86_ops->sync_dirty_debug_regs(vcpu);
+ for (i = 0; i < KVM_NR_DB_REGS; i++)
+ vcpu->arch.eff_db[i] = vcpu->arch.db[i];
+ }
+
+ /*
* If the guest has used debug registers, at least dr7
* will be disabled while returning to the host.
* If we don't have active breakpoints in the host, we don't
@@ -6186,7 +6267,7 @@ static int complete_emulated_mmio(struct kvm_vcpu *vcpu)
frag->len -= len;
}
- if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) {
+ if (vcpu->mmio_cur_fragment >= vcpu->mmio_nr_fragments) {
vcpu->mmio_needed = 0;
/* FIXME: return into emulator if single-stepping. */
@@ -6711,6 +6792,7 @@ int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
{
int r;
struct msr_data msr;
+ struct kvm *kvm = vcpu->kvm;
r = vcpu_load(vcpu);
if (r)
@@ -6721,6 +6803,9 @@ int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
kvm_write_tsc(vcpu, &msr);
vcpu_put(vcpu);
+ schedule_delayed_work(&kvm->arch.kvmclock_sync_work,
+ KVMCLOCK_SYNC_PERIOD);
+
return r;
}
@@ -7013,6 +7098,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
pvclock_update_vm_gtod_copy(kvm);
+ INIT_DELAYED_WORK(&kvm->arch.kvmclock_update_work, kvmclock_update_fn);
+ INIT_DELAYED_WORK(&kvm->arch.kvmclock_sync_work, kvmclock_sync_fn);
+
return 0;
}
@@ -7050,6 +7138,8 @@ static void kvm_free_vcpus(struct kvm *kvm)
void kvm_arch_sync_events(struct kvm *kvm)
{
+ cancel_delayed_work_sync(&kvm->arch.kvmclock_sync_work);
+ cancel_delayed_work_sync(&kvm->arch.kvmclock_update_work);
kvm_free_all_assigned_devices(kvm);
kvm_free_pit(kvm);
}
@@ -7248,6 +7338,9 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
{
+ if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events)
+ kvm_x86_ops->check_nested_events(vcpu, false);
+
return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE &&
!vcpu->arch.apf.halted)
|| !list_empty_careful(&vcpu->async_pf.done)
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 8da5823bcde6..8c97bac9a895 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -122,9 +122,12 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
gva_t addr, void *val, unsigned int bytes,
struct x86_exception *exception);
-#define KVM_SUPPORTED_XCR0 (XSTATE_FP | XSTATE_SSE | XSTATE_YMM)
+#define KVM_SUPPORTED_XCR0 (XSTATE_FP | XSTATE_SSE | XSTATE_YMM \
+ | XSTATE_BNDREGS | XSTATE_BNDCSR)
extern u64 host_xcr0;
+extern u64 kvm_supported_xcr0(void);
+
extern unsigned int min_timer_period_us;
extern struct static_key kvm_no_apic_vcpu;
diff --git a/arch/x86/lib/hash.c b/arch/x86/lib/hash.c
index 3056702e81fb..ff4fa51a5b1f 100644
--- a/arch/x86/lib/hash.c
+++ b/arch/x86/lib/hash.c
@@ -32,6 +32,7 @@
*/
#include <linux/hash.h>
+#include <linux/init.h>
#include <asm/processor.h>
#include <asm/cpufeature.h>
@@ -39,7 +40,11 @@
static inline u32 crc32_u32(u32 crc, u32 val)
{
+#ifdef CONFIG_AS_CRC32
asm ("crc32l %1,%0\n" : "+r" (crc) : "rm" (val));
+#else
+ asm (".byte 0xf2, 0x0f, 0x38, 0xf1, 0xc1" : "+a" (crc) : "c" (val));
+#endif
return crc;
}
@@ -49,19 +54,18 @@ static u32 intel_crc4_2_hash(const void *data, u32 len, u32 seed)
u32 i, tmp = 0;
for (i = 0; i < len / 4; i++)
- seed = crc32_u32(*p32++, seed);
+ seed = crc32_u32(seed, *p32++);
- switch (3 - (len & 0x03)) {
- case 0:
+ switch (len & 3) {
+ case 3:
tmp |= *((const u8 *) p32 + 2) << 16;
/* fallthrough */
- case 1:
+ case 2:
tmp |= *((const u8 *) p32 + 1) << 8;
/* fallthrough */
- case 2:
+ case 1:
tmp |= *((const u8 *) p32);
- seed = crc32_u32(tmp, seed);
- default:
+ seed = crc32_u32(seed, tmp);
break;
}
@@ -74,12 +78,12 @@ static u32 intel_crc4_2_hash2(const u32 *data, u32 len, u32 seed)
u32 i;
for (i = 0; i < len; i++)
- seed = crc32_u32(*p32++, seed);
+ seed = crc32_u32(seed, *p32++);
return seed;
}
-void setup_arch_fast_hash(struct fast_hash_ops *ops)
+void __init setup_arch_fast_hash(struct fast_hash_ops *ops)
{
if (cpu_has_xmm4_2) {
ops->hash = intel_crc4_2_hash;
diff --git a/arch/x86/lib/memcpy_32.c b/arch/x86/lib/memcpy_32.c
index e78761d6b7f8..a404b4b75533 100644
--- a/arch/x86/lib/memcpy_32.c
+++ b/arch/x86/lib/memcpy_32.c
@@ -4,7 +4,7 @@
#undef memcpy
#undef memset
-void *memcpy(void *to, const void *from, size_t n)
+__visible void *memcpy(void *to, const void *from, size_t n)
{
#ifdef CONFIG_X86_USE_3DNOW
return __memcpy3d(to, from, n);
@@ -14,13 +14,13 @@ void *memcpy(void *to, const void *from, size_t n)
}
EXPORT_SYMBOL(memcpy);
-void *memset(void *s, int c, size_t count)
+__visible void *memset(void *s, int c, size_t count)
{
return __memset(s, c, count);
}
EXPORT_SYMBOL(memset);
-void *memmove(void *dest, const void *src, size_t n)
+__visible void *memmove(void *dest, const void *src, size_t n)
{
int d0,d1,d2,d3,d4,d5;
char *ret = dest;
diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c
index 8f8eebdca7d4..db9db446b71a 100644
--- a/arch/x86/lib/msr.c
+++ b/arch/x86/lib/msr.c
@@ -8,7 +8,7 @@ struct msr *msrs_alloc(void)
msrs = alloc_percpu(struct msr);
if (!msrs) {
- pr_warning("%s: error allocating msrs\n", __func__);
+ pr_warn("%s: error allocating msrs\n", __func__);
return NULL;
}
@@ -21,3 +21,90 @@ void msrs_free(struct msr *msrs)
free_percpu(msrs);
}
EXPORT_SYMBOL(msrs_free);
+
+/**
+ * Read an MSR with error handling
+ *
+ * @msr: MSR to read
+ * @m: value to read into
+ *
+ * It returns read data only on success, otherwise it doesn't change the output
+ * argument @m.
+ *
+ */
+int msr_read(u32 msr, struct msr *m)
+{
+ int err;
+ u64 val;
+
+ err = rdmsrl_safe(msr, &val);
+ if (!err)
+ m->q = val;
+
+ return err;
+}
+
+/**
+ * Write an MSR with error handling
+ *
+ * @msr: MSR to write
+ * @m: value to write
+ */
+int msr_write(u32 msr, struct msr *m)
+{
+ return wrmsrl_safe(msr, m->q);
+}
+
+static inline int __flip_bit(u32 msr, u8 bit, bool set)
+{
+ struct msr m, m1;
+ int err = -EINVAL;
+
+ if (bit > 63)
+ return err;
+
+ err = msr_read(msr, &m);
+ if (err)
+ return err;
+
+ m1 = m;
+ if (set)
+ m1.q |= BIT_64(bit);
+ else
+ m1.q &= ~BIT_64(bit);
+
+ if (m1.q == m.q)
+ return 0;
+
+ err = msr_write(msr, &m);
+ if (err)
+ return err;
+
+ return 1;
+}
+
+/**
+ * Set @bit in a MSR @msr.
+ *
+ * Retval:
+ * < 0: An error was encountered.
+ * = 0: Bit was already set.
+ * > 0: Hardware accepted the MSR write.
+ */
+int msr_set_bit(u32 msr, u8 bit)
+{
+ return __flip_bit(msr, bit, true);
+}
+
+/**
+ * Clear @bit in a MSR @msr.
+ *
+ * Retval:
+ * < 0: An error was encountered.
+ * = 0: Bit was already cleared.
+ * > 0: Hardware accepted the MSR write.
+ */
+int msr_clear_bit(u32 msr, u8 bit)
+{
+ return __flip_bit(msr, bit, false);
+}
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index 0002a3a33081..20621d753d5f 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -30,6 +30,7 @@ struct pg_state {
unsigned long start_address;
unsigned long current_address;
const struct addr_marker *marker;
+ bool to_dmesg;
};
struct addr_marker {
@@ -88,10 +89,28 @@ static struct addr_marker address_markers[] = {
#define PUD_LEVEL_MULT (PTRS_PER_PMD * PMD_LEVEL_MULT)
#define PGD_LEVEL_MULT (PTRS_PER_PUD * PUD_LEVEL_MULT)
+#define pt_dump_seq_printf(m, to_dmesg, fmt, args...) \
+({ \
+ if (to_dmesg) \
+ printk(KERN_INFO fmt, ##args); \
+ else \
+ if (m) \
+ seq_printf(m, fmt, ##args); \
+})
+
+#define pt_dump_cont_printf(m, to_dmesg, fmt, args...) \
+({ \
+ if (to_dmesg) \
+ printk(KERN_CONT fmt, ##args); \
+ else \
+ if (m) \
+ seq_printf(m, fmt, ##args); \
+})
+
/*
* Print a readable form of a pgprot_t to the seq_file
*/
-static void printk_prot(struct seq_file *m, pgprot_t prot, int level)
+static void printk_prot(struct seq_file *m, pgprot_t prot, int level, bool dmsg)
{
pgprotval_t pr = pgprot_val(prot);
static const char * const level_name[] =
@@ -99,47 +118,47 @@ static void printk_prot(struct seq_file *m, pgprot_t prot, int level)
if (!pgprot_val(prot)) {
/* Not present */
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
} else {
if (pr & _PAGE_USER)
- seq_printf(m, "USR ");
+ pt_dump_cont_printf(m, dmsg, "USR ");
else
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
if (pr & _PAGE_RW)
- seq_printf(m, "RW ");
+ pt_dump_cont_printf(m, dmsg, "RW ");
else
- seq_printf(m, "ro ");
+ pt_dump_cont_printf(m, dmsg, "ro ");
if (pr & _PAGE_PWT)
- seq_printf(m, "PWT ");
+ pt_dump_cont_printf(m, dmsg, "PWT ");
else
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
if (pr & _PAGE_PCD)
- seq_printf(m, "PCD ");
+ pt_dump_cont_printf(m, dmsg, "PCD ");
else
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
/* Bit 9 has a different meaning on level 3 vs 4 */
if (level <= 3) {
if (pr & _PAGE_PSE)
- seq_printf(m, "PSE ");
+ pt_dump_cont_printf(m, dmsg, "PSE ");
else
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
} else {
if (pr & _PAGE_PAT)
- seq_printf(m, "pat ");
+ pt_dump_cont_printf(m, dmsg, "pat ");
else
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
}
if (pr & _PAGE_GLOBAL)
- seq_printf(m, "GLB ");
+ pt_dump_cont_printf(m, dmsg, "GLB ");
else
- seq_printf(m, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
if (pr & _PAGE_NX)
- seq_printf(m, "NX ");
+ pt_dump_cont_printf(m, dmsg, "NX ");
else
- seq_printf(m, "x ");
+ pt_dump_cont_printf(m, dmsg, "x ");
}
- seq_printf(m, "%s\n", level_name[level]);
+ pt_dump_cont_printf(m, dmsg, "%s\n", level_name[level]);
}
/*
@@ -178,7 +197,8 @@ static void note_page(struct seq_file *m, struct pg_state *st,
st->current_prot = new_prot;
st->level = level;
st->marker = address_markers;
- seq_printf(m, "---[ %s ]---\n", st->marker->name);
+ pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
+ st->marker->name);
} else if (prot != cur || level != st->level ||
st->current_address >= st->marker[1].start_address) {
const char *unit = units;
@@ -188,17 +208,17 @@ static void note_page(struct seq_file *m, struct pg_state *st,
/*
* Now print the actual finished series
*/
- seq_printf(m, "0x%0*lx-0x%0*lx ",
- width, st->start_address,
- width, st->current_address);
+ pt_dump_seq_printf(m, st->to_dmesg, "0x%0*lx-0x%0*lx ",
+ width, st->start_address,
+ width, st->current_address);
delta = (st->current_address - st->start_address) >> 10;
while (!(delta & 1023) && unit[1]) {
delta >>= 10;
unit++;
}
- seq_printf(m, "%9lu%c ", delta, *unit);
- printk_prot(m, st->current_prot, st->level);
+ pt_dump_cont_printf(m, st->to_dmesg, "%9lu%c ", delta, *unit);
+ printk_prot(m, st->current_prot, st->level, st->to_dmesg);
/*
* We print markers for special areas of address space,
@@ -207,7 +227,8 @@ static void note_page(struct seq_file *m, struct pg_state *st,
*/
if (st->current_address >= st->marker[1].start_address) {
st->marker++;
- seq_printf(m, "---[ %s ]---\n", st->marker->name);
+ pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
+ st->marker->name);
}
st->start_address = st->current_address;
@@ -296,7 +317,7 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
#define pgd_none(a) pud_none(__pud(pgd_val(a)))
#endif
-static void walk_pgd_level(struct seq_file *m)
+void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)
{
#ifdef CONFIG_X86_64
pgd_t *start = (pgd_t *) &init_level4_pgt;
@@ -304,9 +325,12 @@ static void walk_pgd_level(struct seq_file *m)
pgd_t *start = swapper_pg_dir;
#endif
int i;
- struct pg_state st;
+ struct pg_state st = {};
- memset(&st, 0, sizeof(st));
+ if (pgd) {
+ start = pgd;
+ st.to_dmesg = true;
+ }
for (i = 0; i < PTRS_PER_PGD; i++) {
st.current_address = normalize_addr(i * PGD_LEVEL_MULT);
@@ -331,7 +355,7 @@ static void walk_pgd_level(struct seq_file *m)
static int ptdump_show(struct seq_file *m, void *v)
{
- walk_pgd_level(m);
+ ptdump_walk_pgd_level(m, NULL);
return 0;
}
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 6dea040cc3a1..8e5722992677 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -584,8 +584,13 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code,
if (error_code & PF_INSTR) {
unsigned int level;
+ pgd_t *pgd;
+ pte_t *pte;
- pte_t *pte = lookup_address(address, &level);
+ pgd = __va(read_cr3() & PHYSICAL_PAGE_MASK);
+ pgd += pgd_index(address);
+
+ pte = lookup_address_in_pgd(pgd, address, &level);
if (pte && pte_present(*pte) && !pte_exec(*pte))
printk(nx_warning, from_kuid(&init_user_ns, current_uid()));
@@ -1020,13 +1025,17 @@ static inline bool smap_violation(int error_code, struct pt_regs *regs)
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
* routines.
+ *
+ * This function must have noinline because both callers
+ * {,trace_}do_page_fault() have notrace on. Having this an actual function
+ * guarantees there's a function trace entry.
*/
-static void __kprobes
-__do_page_fault(struct pt_regs *regs, unsigned long error_code)
+static void __kprobes noinline
+__do_page_fault(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
{
struct vm_area_struct *vma;
struct task_struct *tsk;
- unsigned long address;
struct mm_struct *mm;
int fault;
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
@@ -1034,9 +1043,6 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
tsk = current;
mm = tsk->mm;
- /* Get the faulting address: */
- address = read_cr2();
-
/*
* Detect and handle instructions that would cause a page fault for
* both a tracked kernel page and a userspace page.
@@ -1248,32 +1254,50 @@ good_area:
up_read(&mm->mmap_sem);
}
-dotraplinkage void __kprobes
+dotraplinkage void __kprobes notrace
do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
+ unsigned long address = read_cr2(); /* Get the faulting address */
enum ctx_state prev_state;
+ /*
+ * We must have this function tagged with __kprobes, notrace and call
+ * read_cr2() before calling anything else. To avoid calling any kind
+ * of tracing machinery before we've observed the CR2 value.
+ *
+ * exception_{enter,exit}() contain all sorts of tracepoints.
+ */
+
prev_state = exception_enter();
- __do_page_fault(regs, error_code);
+ __do_page_fault(regs, error_code, address);
exception_exit(prev_state);
}
-static void trace_page_fault_entries(struct pt_regs *regs,
+#ifdef CONFIG_TRACING
+static void trace_page_fault_entries(unsigned long address, struct pt_regs *regs,
unsigned long error_code)
{
if (user_mode(regs))
- trace_page_fault_user(read_cr2(), regs, error_code);
+ trace_page_fault_user(address, regs, error_code);
else
- trace_page_fault_kernel(read_cr2(), regs, error_code);
+ trace_page_fault_kernel(address, regs, error_code);
}
-dotraplinkage void __kprobes
+dotraplinkage void __kprobes notrace
trace_do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
+ /*
+ * The exception_enter and tracepoint processing could
+ * trigger another page faults (user space callchain
+ * reading) and destroy the original cr2 value, so read
+ * the faulting address now.
+ */
+ unsigned long address = read_cr2();
enum ctx_state prev_state;
prev_state = exception_enter();
- trace_page_fault_entries(regs, error_code);
- __do_page_fault(regs, error_code);
+ trace_page_fault_entries(address, regs, error_code);
+ __do_page_fault(regs, error_code, address);
exception_exit(prev_state);
}
+#endif /* CONFIG_TRACING */
diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c
index 27aa0455fab3..1d045f9c390f 100644
--- a/arch/x86/mm/numa.c
+++ b/arch/x86/mm/numa.c
@@ -687,10 +687,6 @@ static int __init dummy_numa_init(void)
void __init x86_numa_init(void)
{
if (!numa_off) {
-#ifdef CONFIG_X86_NUMAQ
- if (!numa_init(numaq_numa_init))
- return;
-#endif
#ifdef CONFIG_ACPI_NUMA
if (!numa_init(x86_acpi_numa_init))
return;
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index b3b19f46c016..ae242a7c11c7 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -126,8 +126,8 @@ within(unsigned long addr, unsigned long start, unsigned long end)
* @vaddr: virtual start address
* @size: number of bytes to flush
*
- * clflush is an unordered instruction which needs fencing with mfence
- * to avoid ordering issues.
+ * clflushopt is an unordered instruction which needs fencing with mfence or
+ * sfence to avoid ordering issues.
*/
void clflush_cache_range(void *vaddr, unsigned int size)
{
@@ -136,11 +136,11 @@ void clflush_cache_range(void *vaddr, unsigned int size)
mb();
for (; vaddr < vend; vaddr += boot_cpu_data.x86_clflush_size)
- clflush(vaddr);
+ clflushopt(vaddr);
/*
* Flush any possible final partial cacheline:
*/
- clflush(vend);
+ clflushopt(vend);
mb();
}
@@ -323,8 +323,12 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
return prot;
}
-static pte_t *__lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
- unsigned int *level)
+/*
+ * Lookup the page table entry for a virtual address in a specific pgd.
+ * Return a pointer to the entry and the level of the mapping.
+ */
+pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
+ unsigned int *level)
{
pud_t *pud;
pmd_t *pmd;
@@ -365,7 +369,7 @@ static pte_t *__lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
*/
pte_t *lookup_address(unsigned long address, unsigned int *level)
{
- return __lookup_address_in_pgd(pgd_offset_k(address), address, level);
+ return lookup_address_in_pgd(pgd_offset_k(address), address, level);
}
EXPORT_SYMBOL_GPL(lookup_address);
@@ -373,7 +377,7 @@ static pte_t *_lookup_address_cpa(struct cpa_data *cpa, unsigned long address,
unsigned int *level)
{
if (cpa->pgd)
- return __lookup_address_in_pgd(cpa->pgd + pgd_index(address),
+ return lookup_address_in_pgd(cpa->pgd + pgd_index(address),
address, level);
return lookup_address(address, level);
@@ -692,6 +696,18 @@ static bool try_to_free_pmd_page(pmd_t *pmd)
return true;
}
+static bool try_to_free_pud_page(pud_t *pud)
+{
+ int i;
+
+ for (i = 0; i < PTRS_PER_PUD; i++)
+ if (!pud_none(pud[i]))
+ return false;
+
+ free_page((unsigned long)pud);
+ return true;
+}
+
static bool unmap_pte_range(pmd_t *pmd, unsigned long start, unsigned long end)
{
pte_t *pte = pte_offset_kernel(pmd, start);
@@ -805,6 +821,16 @@ static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end)
*/
}
+static void unmap_pgd_range(pgd_t *root, unsigned long addr, unsigned long end)
+{
+ pgd_t *pgd_entry = root + pgd_index(addr);
+
+ unmap_pud_range(pgd_entry, addr, end);
+
+ if (try_to_free_pud_page((pud_t *)pgd_page_vaddr(*pgd_entry)))
+ pgd_clear(pgd_entry);
+}
+
static int alloc_pte_page(pmd_t *pmd)
{
pte_t *pte = (pte_t *)get_zeroed_page(GFP_KERNEL | __GFP_NOTRACK);
@@ -999,9 +1025,8 @@ static int populate_pud(struct cpa_data *cpa, unsigned long start, pgd_t *pgd,
static int populate_pgd(struct cpa_data *cpa, unsigned long addr)
{
pgprot_t pgprot = __pgprot(_KERNPG_TABLE);
- bool allocd_pgd = false;
- pgd_t *pgd_entry;
pud_t *pud = NULL; /* shut up gcc */
+ pgd_t *pgd_entry;
int ret;
pgd_entry = cpa->pgd + pgd_index(addr);
@@ -1015,7 +1040,6 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr)
return -1;
set_pgd(pgd_entry, __pgd(__pa(pud) | _KERNPG_TABLE));
- allocd_pgd = true;
}
pgprot_val(pgprot) &= ~pgprot_val(cpa->mask_clr);
@@ -1023,19 +1047,11 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr)
ret = populate_pud(cpa, addr, pgd_entry, pgprot);
if (ret < 0) {
- unmap_pud_range(pgd_entry, addr,
+ unmap_pgd_range(cpa->pgd, addr,
addr + (cpa->numpages << PAGE_SHIFT));
-
- if (allocd_pgd) {
- /*
- * If I allocated this PUD page, I can just as well
- * free it in this error path.
- */
- pgd_clear(pgd_entry);
- free_page((unsigned long)pud);
- }
return ret;
}
+
cpa->numpages = ret;
return 0;
}
@@ -1377,10 +1393,10 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
cache = cache_attr(mask_set);
/*
- * On success we use clflush, when the CPU supports it to
- * avoid the wbindv. If the CPU does not support it and in the
+ * On success we use CLFLUSH, when the CPU supports it to
+ * avoid the WBINVD. If the CPU does not support it and in the
* error case we fall back to cpa_flush_all (which uses
- * wbindv):
+ * WBINVD):
*/
if (!ret && cpu_has_clflush) {
if (cpa.flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) {
@@ -1861,6 +1877,12 @@ out:
return retval;
}
+void kernel_unmap_pages_in_pgd(pgd_t *root, unsigned long address,
+ unsigned numpages)
+{
+ unmap_pgd_range(root, address, address + (numpages << PAGE_SHIFT));
+}
+
/*
* The testcases use internal knowledge of the implementation that shouldn't
* be exposed to the rest of the kernel. Include these directly here.
diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c
index 1953e9c9391a..66338a60aa6e 100644
--- a/arch/x86/mm/srat.c
+++ b/arch/x86/mm/srat.c
@@ -52,12 +52,18 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
int i, j;
for (i = 0; i < slit->locality_count; i++) {
- if (pxm_to_node(i) == NUMA_NO_NODE)
+ const int from_node = pxm_to_node(i);
+
+ if (from_node == NUMA_NO_NODE)
continue;
+
for (j = 0; j < slit->locality_count; j++) {
- if (pxm_to_node(j) == NUMA_NO_NODE)
+ const int to_node = pxm_to_node(j);
+
+ if (to_node == NUMA_NO_NODE)
continue;
- numa_set_distance(pxm_to_node(i), pxm_to_node(j),
+
+ numa_set_distance(from_node, to_node,
slit->entry[slit->locality_count * i + j]);
}
}
diff --git a/arch/x86/net/bpf_jit.S b/arch/x86/net/bpf_jit.S
index 877b9a1b2152..01495755701b 100644
--- a/arch/x86/net/bpf_jit.S
+++ b/arch/x86/net/bpf_jit.S
@@ -140,7 +140,7 @@ bpf_slow_path_byte_msh:
push %r9; \
push SKBDATA; \
/* rsi already has offset */ \
- mov $SIZE,%ecx; /* size */ \
+ mov $SIZE,%edx; /* size */ \
call bpf_internal_load_pointer_neg_helper; \
test %rax,%rax; \
pop SKBDATA; \
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile
index e063eed0f912..5c6fc3577a49 100644
--- a/arch/x86/pci/Makefile
+++ b/arch/x86/pci/Makefile
@@ -13,9 +13,6 @@ obj-y += legacy.o irq.o
obj-$(CONFIG_STA2X11) += sta2x11-fixup.o
-obj-$(CONFIG_X86_VISWS) += visws.o
-
-obj-$(CONFIG_X86_NUMAQ) += numaq_32.o
obj-$(CONFIG_X86_NUMACHIP) += numachip.o
obj-$(CONFIG_X86_INTEL_MID) += intel_mid_pci.o
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 4f25ec077552..01edac6c5e18 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -218,9 +218,8 @@ static void teardown_mcfg_map(struct pci_root_info *info)
}
#endif
-static acpi_status
-resource_to_addr(struct acpi_resource *resource,
- struct acpi_resource_address64 *addr)
+static acpi_status resource_to_addr(struct acpi_resource *resource,
+ struct acpi_resource_address64 *addr)
{
acpi_status status;
struct acpi_resource_memory24 *memory24;
@@ -265,8 +264,7 @@ resource_to_addr(struct acpi_resource *resource,
return AE_ERROR;
}
-static acpi_status
-count_resource(struct acpi_resource *acpi_res, void *data)
+static acpi_status count_resource(struct acpi_resource *acpi_res, void *data)
{
struct pci_root_info *info = data;
struct acpi_resource_address64 addr;
@@ -278,8 +276,7 @@ count_resource(struct acpi_resource *acpi_res, void *data)
return AE_OK;
}
-static acpi_status
-setup_resource(struct acpi_resource *acpi_res, void *data)
+static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data)
{
struct pci_root_info *info = data;
struct resource *res;
@@ -435,9 +432,9 @@ static void release_pci_root_info(struct pci_host_bridge *bridge)
__release_pci_root_info(info);
}
-static void
-probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
- int busnum, int domain)
+static void probe_pci_root_info(struct pci_root_info *info,
+ struct acpi_device *device,
+ int busnum, int domain)
{
size_t size;
@@ -473,16 +470,13 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
{
struct acpi_device *device = root->device;
- struct pci_root_info *info = NULL;
+ struct pci_root_info *info;
int domain = root->segment;
int busnum = root->secondary.start;
LIST_HEAD(resources);
- struct pci_bus *bus = NULL;
+ struct pci_bus *bus;
struct pci_sysdata *sd;
int node;
-#ifdef CONFIG_ACPI_NUMA
- int pxm;
-#endif
if (pci_ignore_seg)
domain = 0;
@@ -494,19 +488,12 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
return NULL;
}
- node = -1;
-#ifdef CONFIG_ACPI_NUMA
- pxm = acpi_get_pxm(device->handle);
- if (pxm >= 0)
- node = pxm_to_node(pxm);
- if (node != -1)
- set_mp_bus_to_node(busnum, node);
- else
-#endif
- node = get_mp_bus_to_node(busnum);
+ node = acpi_get_node(device->handle);
+ if (node == NUMA_NO_NODE)
+ node = x86_pci_root_bus_node(busnum);
- if (node != -1 && !node_online(node))
- node = -1;
+ if (node != NUMA_NO_NODE && !node_online(node))
+ node = NUMA_NO_NODE;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
@@ -519,15 +506,12 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
sd->domain = domain;
sd->node = node;
sd->companion = device;
- /*
- * Maybe the desired pci bus has been already scanned. In such case
- * it is unnecessary to scan the pci bus with the given domain,busnum.
- */
+
bus = pci_find_bus(domain, busnum);
if (bus) {
/*
- * If the desired bus exits, the content of bus->sysdata will
- * be replaced by sd.
+ * If the desired bus has been scanned already, replace
+ * its bus->sysdata.
*/
memcpy(bus->sysdata, sd, sizeof(*sd));
kfree(info);
@@ -572,15 +556,8 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
pcie_bus_configure_settings(child);
}
- if (bus && node != -1) {
-#ifdef CONFIG_ACPI_NUMA
- if (pxm >= 0)
- dev_printk(KERN_DEBUG, &bus->dev,
- "on NUMA node %d (pxm %d)\n", node, pxm);
-#else
+ if (bus && node != NUMA_NO_NODE)
dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
-#endif
- }
return bus;
}
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c
index a48be98e9ded..a313a7fb6b86 100644
--- a/arch/x86/pci/amd_bus.c
+++ b/arch/x86/pci/amd_bus.c
@@ -44,15 +44,6 @@ static struct pci_root_info __init *find_pci_root_info(int node, int link)
return NULL;
}
-static void __init set_mp_bus_range_to_node(int min_bus, int max_bus, int node)
-{
-#ifdef CONFIG_NUMA
- int j;
-
- for (j = min_bus; j <= max_bus; j++)
- set_mp_bus_to_node(j, node);
-#endif
-}
/**
* early_fill_mp_bus_to_node()
* called before pcibios_scan_root and pci_scan_bus
@@ -117,7 +108,6 @@ static int __init early_fill_mp_bus_info(void)
min_bus = (reg >> 16) & 0xff;
max_bus = (reg >> 24) & 0xff;
node = (reg >> 4) & 0x07;
- set_mp_bus_range_to_node(min_bus, max_bus, node);
link = (reg >> 8) & 0x03;
info = alloc_pci_root_info(min_bus, max_bus, node, link);
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c
index c2735feb2508..f3a2cfc14125 100644
--- a/arch/x86/pci/bus_numa.c
+++ b/arch/x86/pci/bus_numa.c
@@ -10,9 +10,6 @@ static struct pci_root_info *x86_find_pci_root_info(int bus)
{
struct pci_root_info *info;
- if (list_empty(&pci_root_infos))
- return NULL;
-
list_for_each_entry(info, &pci_root_infos, list)
if (info->busn.start == bus)
return info;
@@ -20,6 +17,16 @@ static struct pci_root_info *x86_find_pci_root_info(int bus)
return NULL;
}
+int x86_pci_root_bus_node(int bus)
+{
+ struct pci_root_info *info = x86_find_pci_root_info(bus);
+
+ if (!info)
+ return NUMA_NO_NODE;
+
+ return info->node;
+}
+
void x86_pci_root_bus_resources(int bus, struct list_head *resources)
{
struct pci_root_info *info = x86_find_pci_root_info(bus);
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 981c2dbd72cc..059a76c29739 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -456,19 +456,25 @@ void __init dmi_check_pciprobe(void)
dmi_check_system(pciprobe_dmi_table);
}
-struct pci_bus *pcibios_scan_root(int busnum)
+void pcibios_scan_root(int busnum)
{
- struct pci_bus *bus = NULL;
+ struct pci_bus *bus;
+ struct pci_sysdata *sd;
+ LIST_HEAD(resources);
- while ((bus = pci_find_next_bus(bus)) != NULL) {
- if (bus->number == busnum) {
- /* Already scanned */
- return bus;
- }
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+ if (!sd) {
+ printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busnum);
+ return;
+ }
+ sd->node = x86_pci_root_bus_node(busnum);
+ x86_pci_root_bus_resources(busnum, &resources);
+ printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
+ bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources);
+ if (!bus) {
+ pci_free_resource_list(&resources);
+ kfree(sd);
}
-
- return pci_scan_bus_on_node(busnum, &pci_root_ops,
- get_mp_bus_to_node(busnum));
}
void __init pcibios_set_cache_line_size(void)
@@ -561,7 +567,6 @@ char * __init pcibios_setup(char *str)
pci_probe |= PCI_PROBE_NOEARLY;
return NULL;
}
-#ifndef CONFIG_X86_VISWS
else if (!strcmp(str, "usepirqmask")) {
pci_probe |= PCI_USE_PIRQ_MASK;
return NULL;
@@ -571,9 +576,7 @@ char * __init pcibios_setup(char *str)
} else if (!strncmp(str, "lastbus=", 8)) {
pcibios_last_bus = simple_strtol(str+8, NULL, 0);
return NULL;
- }
-#endif
- else if (!strcmp(str, "rom")) {
+ } else if (!strcmp(str, "rom")) {
pci_probe |= PCI_ASSIGN_ROMS;
return NULL;
} else if (!strcmp(str, "norom")) {
@@ -677,105 +680,3 @@ int pci_ext_cfg_avail(void)
else
return 0;
}
-
-struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node)
-{
- LIST_HEAD(resources);
- struct pci_bus *bus = NULL;
- struct pci_sysdata *sd;
-
- /*
- * Allocate per-root-bus (not per bus) arch-specific data.
- * TODO: leak; this memory is never freed.
- * It's arguable whether it's worth the trouble to care.
- */
- sd = kzalloc(sizeof(*sd), GFP_KERNEL);
- if (!sd) {
- printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno);
- return NULL;
- }
- sd->node = node;
- x86_pci_root_bus_resources(busno, &resources);
- printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busno);
- bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources);
- if (!bus) {
- pci_free_resource_list(&resources);
- kfree(sd);
- }
-
- return bus;
-}
-
-struct pci_bus *pci_scan_bus_with_sysdata(int busno)
-{
- return pci_scan_bus_on_node(busno, &pci_root_ops, -1);
-}
-
-/*
- * NUMA info for PCI busses
- *
- * Early arch code is responsible for filling in reasonable values here.
- * A node id of "-1" means "use current node". In other words, if a bus
- * has a -1 node id, it's not tightly coupled to any particular chunk
- * of memory (as is the case on some Nehalem systems).
- */
-#ifdef CONFIG_NUMA
-
-#define BUS_NR 256
-
-#ifdef CONFIG_X86_64
-
-static int mp_bus_to_node[BUS_NR] = {
- [0 ... BUS_NR - 1] = -1
-};
-
-void set_mp_bus_to_node(int busnum, int node)
-{
- if (busnum >= 0 && busnum < BUS_NR)
- mp_bus_to_node[busnum] = node;
-}
-
-int get_mp_bus_to_node(int busnum)
-{
- int node = -1;
-
- if (busnum < 0 || busnum > (BUS_NR - 1))
- return node;
-
- node = mp_bus_to_node[busnum];
-
- /*
- * let numa_node_id to decide it later in dma_alloc_pages
- * if there is no ram on that node
- */
- if (node != -1 && !node_online(node))
- node = -1;
-
- return node;
-}
-
-#else /* CONFIG_X86_32 */
-
-static int mp_bus_to_node[BUS_NR] = {
- [0 ... BUS_NR - 1] = -1
-};
-
-void set_mp_bus_to_node(int busnum, int node)
-{
- if (busnum >= 0 && busnum < BUS_NR)
- mp_bus_to_node[busnum] = (unsigned char) node;
-}
-
-int get_mp_bus_to_node(int busnum)
-{
- int node;
-
- if (busnum < 0 || busnum > (BUS_NR - 1))
- return 0;
- node = mp_bus_to_node[busnum];
- return node;
-}
-
-#endif /* CONFIG_X86_32 */
-
-#endif /* CONFIG_NUMA */
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index bca9e85daaa5..94ae9ae9574f 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -25,9 +25,9 @@ static void pci_fixup_i450nx(struct pci_dev *d)
dev_dbg(&d->dev, "i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno,
suba, subb);
if (busno)
- pci_scan_bus_with_sysdata(busno); /* Bus A */
+ pcibios_scan_root(busno); /* Bus A */
if (suba < subb)
- pci_scan_bus_with_sysdata(suba+1); /* Bus B */
+ pcibios_scan_root(suba+1); /* Bus B */
}
pcibios_last_bus = -1;
}
@@ -42,7 +42,7 @@ static void pci_fixup_i450gx(struct pci_dev *d)
u8 busno;
pci_read_config_byte(d, 0x4a, &busno);
dev_info(&d->dev, "i440KX/GX host bridge; secondary bus %02x\n", busno);
- pci_scan_bus_with_sysdata(busno);
+ pcibios_scan_root(busno);
pcibios_last_bus = -1;
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx);
@@ -313,9 +313,10 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_r
* IORESOURCE_ROM_SHADOW is used to associate the boot video
* card with this copy. On laptops this copy has to be used since
* the main ROM may be compressed or combined with another image.
- * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW
- * is marked here since the boot video device will be the only enabled
- * video device at this point.
+ * See pci_map_rom() for use of this flag. Before marking the device
+ * with IORESOURCE_ROM_SHADOW check if a vga_default_device is already set
+ * by either arch cde or vga-arbitration, if so only apply the fixup to this
+ * already determined primary video card.
*/
static void pci_fixup_video(struct pci_dev *pdev)
@@ -346,12 +347,13 @@ static void pci_fixup_video(struct pci_dev *pdev)
}
bus = bus->parent;
}
- pci_read_config_word(pdev, PCI_COMMAND, &config);
- if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
- pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
- dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
- if (!vga_default_device())
+ if (!vga_default_device() || pdev == vga_default_device()) {
+ pci_read_config_word(pdev, PCI_COMMAND, &config);
+ if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+ pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+ dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
vga_set_default_device(pdev);
+ }
}
}
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index 372e9b8989b3..84112f55dd7a 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -136,13 +136,9 @@ static void __init pirq_peer_trick(void)
busmap[e->bus] = 1;
}
for (i = 1; i < 256; i++) {
- int node;
if (!busmap[i] || pci_find_bus(0, i))
continue;
- node = get_mp_bus_to_node(i);
- if (pci_scan_bus_on_node(i, &pci_root_ops, node))
- printk(KERN_INFO "PCI: Discovered primary peer "
- "bus %02x [IRQ]\n", i);
+ pcibios_scan_root(i);
}
pcibios_last_bus = -1;
}
diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c
index 4db96fb1c232..5b662c0faf8c 100644
--- a/arch/x86/pci/legacy.c
+++ b/arch/x86/pci/legacy.c
@@ -37,19 +37,17 @@ int __init pci_legacy_init(void)
void pcibios_scan_specific_bus(int busn)
{
int devfn;
- long node;
u32 l;
if (pci_find_bus(0, busn))
return;
- node = get_mp_bus_to_node(busn);
for (devfn = 0; devfn < 256; devfn += 8) {
if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) &&
l != 0x0000 && l != 0xffff) {
DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l);
printk(KERN_INFO "PCI: Discovered peer bus %02x\n", busn);
- pci_scan_bus_on_node(busn, &pci_root_ops, node);
+ pcibios_scan_root(busn);
return;
}
}
diff --git a/arch/x86/pci/numaq_32.c b/arch/x86/pci/numaq_32.c
deleted file mode 100644
index 72c229f9ebcf..000000000000
--- a/arch/x86/pci/numaq_32.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * numaq_32.c - Low-level PCI access for NUMA-Q machines
- */
-
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/nodemask.h>
-#include <asm/apic.h>
-#include <asm/mpspec.h>
-#include <asm/pci_x86.h>
-#include <asm/numaq.h>
-
-#define BUS2QUAD(global) (mp_bus_id_to_node[global])
-
-#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
-
-#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
-
-#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \
- (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3))
-
-static void write_cf8(unsigned bus, unsigned devfn, unsigned reg)
-{
- unsigned val = PCI_CONF1_MQ_ADDRESS(bus, devfn, reg);
- if (xquad_portio)
- writel(val, XQUAD_PORT_ADDR(0xcf8, BUS2QUAD(bus)));
- else
- outl(val, 0xCF8);
-}
-
-static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
- unsigned int devfn, int reg, int len, u32 *value)
-{
- unsigned long flags;
- void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
-
- WARN_ON(seg);
- if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
- return -EINVAL;
-
- raw_spin_lock_irqsave(&pci_config_lock, flags);
-
- write_cf8(bus, devfn, reg);
-
- switch (len) {
- case 1:
- if (xquad_portio)
- *value = readb(adr + (reg & 3));
- else
- *value = inb(0xCFC + (reg & 3));
- break;
- case 2:
- if (xquad_portio)
- *value = readw(adr + (reg & 2));
- else
- *value = inw(0xCFC + (reg & 2));
- break;
- case 4:
- if (xquad_portio)
- *value = readl(adr);
- else
- *value = inl(0xCFC);
- break;
- }
-
- raw_spin_unlock_irqrestore(&pci_config_lock, flags);
-
- return 0;
-}
-
-static int pci_conf1_mq_write(unsigned int seg, unsigned int bus,
- unsigned int devfn, int reg, int len, u32 value)
-{
- unsigned long flags;
- void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
-
- WARN_ON(seg);
- if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
- return -EINVAL;
-
- raw_spin_lock_irqsave(&pci_config_lock, flags);
-
- write_cf8(bus, devfn, reg);
-
- switch (len) {
- case 1:
- if (xquad_portio)
- writeb(value, adr + (reg & 3));
- else
- outb((u8)value, 0xCFC + (reg & 3));
- break;
- case 2:
- if (xquad_portio)
- writew(value, adr + (reg & 2));
- else
- outw((u16)value, 0xCFC + (reg & 2));
- break;
- case 4:
- if (xquad_portio)
- writel(value, adr + reg);
- else
- outl((u32)value, 0xCFC);
- break;
- }
-
- raw_spin_unlock_irqrestore(&pci_config_lock, flags);
-
- return 0;
-}
-
-#undef PCI_CONF1_MQ_ADDRESS
-
-static const struct pci_raw_ops pci_direct_conf1_mq = {
- .read = pci_conf1_mq_read,
- .write = pci_conf1_mq_write
-};
-
-
-static void pci_fixup_i450nx(struct pci_dev *d)
-{
- /*
- * i450NX -- Find and scan all secondary buses on all PXB's.
- */
- int pxb, reg;
- u8 busno, suba, subb;
- int quad = BUS2QUAD(d->bus->number);
-
- dev_info(&d->dev, "searching for i450NX host bridges\n");
- reg = 0xd0;
- for(pxb=0; pxb<2; pxb++) {
- pci_read_config_byte(d, reg++, &busno);
- pci_read_config_byte(d, reg++, &suba);
- pci_read_config_byte(d, reg++, &subb);
- dev_dbg(&d->dev, "i450NX PXB %d: %02x/%02x/%02x\n",
- pxb, busno, suba, subb);
- if (busno) {
- /* Bus A */
- pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, busno));
- }
- if (suba < subb) {
- /* Bus B */
- pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, suba+1));
- }
- }
- pcibios_last_bus = -1;
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx);
-
-int __init pci_numaq_init(void)
-{
- int quad;
-
- raw_pci_ops = &pci_direct_conf1_mq;
-
- pcibios_scan_root(0);
- if (num_online_nodes() > 1)
- for_each_online_node(quad) {
- if (quad == 0)
- continue;
- printk("Scanning PCI bus %d for quad %d\n",
- QUADLOCAL2BUS(quad,0), quad);
- pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, 0));
- }
- return 0;
-}
diff --git a/arch/x86/pci/visws.c b/arch/x86/pci/visws.c
deleted file mode 100644
index 3e6d2a6db866..000000000000
--- a/arch/x86/pci/visws.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Low-Level PCI Support for SGI Visual Workstation
- *
- * (c) 1999--2000 Martin Mares <mj@ucw.cz>
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/setup.h>
-#include <asm/pci_x86.h>
-#include <asm/visws/cobalt.h>
-#include <asm/visws/lithium.h>
-
-static int pci_visws_enable_irq(struct pci_dev *dev) { return 0; }
-static void pci_visws_disable_irq(struct pci_dev *dev) { }
-
-/* int (*pcibios_enable_irq)(struct pci_dev *dev) = &pci_visws_enable_irq; */
-/* void (*pcibios_disable_irq)(struct pci_dev *dev) = &pci_visws_disable_irq; */
-
-/* void __init pcibios_penalize_isa_irq(int irq, int active) {} */
-
-
-unsigned int pci_bus0, pci_bus1;
-
-static int __init visws_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
- int irq, bus = dev->bus->number;
-
- pin--;
-
- /* Nothing useful at PIIX4 pin 1 */
- if (bus == pci_bus0 && slot == 4 && pin == 0)
- return -1;
-
- /* PIIX4 USB is on Bus 0, Slot 4, Line 3 */
- if (bus == pci_bus0 && slot == 4 && pin == 3) {
- irq = CO_IRQ(CO_APIC_PIIX4_USB);
- goto out;
- }
-
- /* First pin spread down 1 APIC entry per slot */
- if (pin == 0) {
- irq = CO_IRQ((bus == pci_bus0 ? CO_APIC_PCIB_BASE0 :
- CO_APIC_PCIA_BASE0) + slot);
- goto out;
- }
-
- /* lines 1,2,3 from any slot is shared in this twirly pattern */
- if (bus == pci_bus1) {
- /* lines 1-3 from devices 0 1 rotate over 2 apic entries */
- irq = CO_IRQ(CO_APIC_PCIA_BASE123 + ((slot + (pin - 1)) % 2));
- } else { /* bus == pci_bus0 */
- /* lines 1-3 from devices 0-3 rotate over 3 apic entries */
- if (slot == 0)
- slot = 3; /* same pattern */
- irq = CO_IRQ(CO_APIC_PCIA_BASE123 + ((3 - slot) + (pin - 1) % 3));
- }
-out:
- printk(KERN_DEBUG "PCI: Bus %d Slot %d Line %d -> IRQ %d\n", bus, slot, pin, irq);
- return irq;
-}
-
-int __init pci_visws_init(void)
-{
- pcibios_enable_irq = &pci_visws_enable_irq;
- pcibios_disable_irq = &pci_visws_disable_irq;
-
- /* The VISWS supports configuration access type 1 only */
- pci_probe = (pci_probe | PCI_PROBE_CONF1) &
- ~(PCI_PROBE_BIOS | PCI_PROBE_CONF2);
-
- pci_bus0 = li_pcib_read16(LI_PCI_BUSNUM) & 0xff;
- pci_bus1 = li_pcia_read16(LI_PCI_BUSNUM) & 0xff;
-
- printk(KERN_INFO "PCI: Lithium bridge A bus: %u, "
- "bridge B (PIIX4) bus: %u\n", pci_bus1, pci_bus0);
-
- raw_pci_ops = &pci_direct_conf1;
- pci_scan_bus_with_sysdata(pci_bus0);
- pci_scan_bus_with_sysdata(pci_bus1);
- pci_fixup_irqs(pci_common_swizzle, visws_map_irq);
- pcibios_resource_survey();
- /* Request bus scan */
- return 1;
-}
diff --git a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile
index 20342d4c82ce..85afde1fa3e5 100644
--- a/arch/x86/platform/Makefile
+++ b/arch/x86/platform/Makefile
@@ -9,5 +9,4 @@ obj-y += olpc/
obj-y += scx200/
obj-y += sfi/
obj-y += ts5500/
-obj-y += visws/
obj-y += uv/
diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile
index b7b0b35c1981..d51045afcaaf 100644
--- a/arch/x86/platform/efi/Makefile
+++ b/arch/x86/platform/efi/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o
+obj-$(CONFIG_EFI_MIXED) += efi_thunk_$(BITS).o
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 1a201ac7cef8..3781dd39e8bd 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -52,6 +52,7 @@
#include <asm/tlbflush.h>
#include <asm/x86_init.h>
#include <asm/rtc.h>
+#include <asm/uv/uv.h>
#define EFI_DEBUG
@@ -67,9 +68,7 @@ struct efi_memory_map memmap;
static struct efi efi_phys __initdata;
static efi_system_table_t efi_systab __initdata;
-unsigned long x86_efi_facility;
-
-static __initdata efi_config_table_type_t arch_tables[] = {
+static efi_config_table_type_t arch_tables[] __initdata = {
#ifdef CONFIG_X86_UV
{UV_SYSTEM_TABLE_GUID, "UVsystab", &efi.uv_systab},
#endif
@@ -78,16 +77,7 @@ static __initdata efi_config_table_type_t arch_tables[] = {
u64 efi_setup; /* efi setup_data physical address */
-/*
- * Returns 1 if 'facility' is enabled, 0 otherwise.
- */
-int efi_enabled(int facility)
-{
- return test_bit(facility, &x86_efi_facility) != 0;
-}
-EXPORT_SYMBOL(efi_enabled);
-
-static bool __initdata disable_runtime = false;
+static bool disable_runtime __initdata = false;
static int __init setup_noefi(char *arg)
{
disable_runtime = true;
@@ -256,27 +246,12 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
return status;
}
-static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
- efi_time_cap_t *tc)
-{
- unsigned long flags;
- efi_status_t status;
-
- spin_lock_irqsave(&rtc_lock, flags);
- efi_call_phys_prelog();
- status = efi_call_phys2(efi_phys.get_time, virt_to_phys(tm),
- virt_to_phys(tc));
- efi_call_phys_epilog();
- spin_unlock_irqrestore(&rtc_lock, flags);
- return status;
-}
-
int efi_set_rtc_mmss(const struct timespec *now)
{
unsigned long nowtime = now->tv_sec;
- efi_status_t status;
- efi_time_t eft;
- efi_time_cap_t cap;
+ efi_status_t status;
+ efi_time_t eft;
+ efi_time_cap_t cap;
struct rtc_time tm;
status = efi.get_time(&eft, &cap);
@@ -294,9 +269,8 @@ int efi_set_rtc_mmss(const struct timespec *now)
eft.second = tm.tm_sec;
eft.nanosecond = 0;
} else {
- printk(KERN_ERR
- "%s: Invalid EFI RTC value: write of %lx to EFI RTC failed\n",
- __FUNCTION__, nowtime);
+ pr_err("%s: Invalid EFI RTC value: write of %lx to EFI RTC failed\n",
+ __func__, nowtime);
return -1;
}
@@ -412,8 +386,7 @@ static void __init print_efi_memmap(void)
p < memmap.map_end;
p += memmap.desc_size, i++) {
md = p;
- pr_info("mem%02u: type=%u, attr=0x%llx, "
- "range=[0x%016llx-0x%016llx) (%lluMB)\n",
+ pr_info("mem%02u: type=%u, attr=0x%llx, range=[0x%016llx-0x%016llx) (%lluMB)\n",
i, md->type, md->attribute, md->phys_addr,
md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
(md->num_pages >> (20 - EFI_PAGE_SHIFT)));
@@ -445,9 +418,8 @@ void __init efi_reserve_boot_services(void)
memblock_is_region_reserved(start, size)) {
/* Could not reserve, skip it */
md->num_pages = 0;
- memblock_dbg("Could not reserve boot range "
- "[0x%010llx-0x%010llx]\n",
- start, start+size-1);
+ memblock_dbg("Could not reserve boot range [0x%010llx-0x%010llx]\n",
+ start, start+size-1);
} else
memblock_reserve(start, size);
}
@@ -455,7 +427,7 @@ void __init efi_reserve_boot_services(void)
void __init efi_unmap_memmap(void)
{
- clear_bit(EFI_MEMMAP, &x86_efi_facility);
+ clear_bit(EFI_MEMMAP, &efi.flags);
if (memmap.map) {
early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
memmap.map = NULL;
@@ -466,9 +438,6 @@ void __init efi_free_boot_services(void)
{
void *p;
- if (!efi_is_native())
- return;
-
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
efi_memory_desc_t *md = p;
unsigned long long start = md->phys_addr;
@@ -583,45 +552,82 @@ static int __init efi_systab_init(void *phys)
return -EINVAL;
}
if ((efi.systab->hdr.revision >> 16) == 0)
- pr_err("Warning: System table version "
- "%d.%02d, expected 1.00 or greater!\n",
+ pr_err("Warning: System table version %d.%02d, expected 1.00 or greater!\n",
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff);
+ set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+
return 0;
}
-static int __init efi_runtime_init(void)
+static int __init efi_runtime_init32(void)
{
- efi_runtime_services_t *runtime;
+ efi_runtime_services_32_t *runtime;
+
+ runtime = early_ioremap((unsigned long)efi.systab->runtime,
+ sizeof(efi_runtime_services_32_t));
+ if (!runtime) {
+ pr_err("Could not map the runtime service table!\n");
+ return -ENOMEM;
+ }
/*
- * Check out the runtime services table. We need to map
- * the runtime services table so that we can grab the physical
- * address of several of the EFI runtime functions, needed to
- * set the firmware into virtual mode.
+ * We will only need *early* access to the following two
+ * EFI runtime services before set_virtual_address_map
+ * is invoked.
*/
+ efi_phys.set_virtual_address_map =
+ (efi_set_virtual_address_map_t *)
+ (unsigned long)runtime->set_virtual_address_map;
+ early_iounmap(runtime, sizeof(efi_runtime_services_32_t));
+
+ return 0;
+}
+
+static int __init efi_runtime_init64(void)
+{
+ efi_runtime_services_64_t *runtime;
+
runtime = early_ioremap((unsigned long)efi.systab->runtime,
- sizeof(efi_runtime_services_t));
+ sizeof(efi_runtime_services_64_t));
if (!runtime) {
pr_err("Could not map the runtime service table!\n");
return -ENOMEM;
}
+
/*
- * We will only need *early* access to the following
- * two EFI runtime services before set_virtual_address_map
+ * We will only need *early* access to the following two
+ * EFI runtime services before set_virtual_address_map
* is invoked.
*/
- efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
efi_phys.set_virtual_address_map =
- (efi_set_virtual_address_map_t *)
- runtime->set_virtual_address_map;
+ (efi_set_virtual_address_map_t *)
+ (unsigned long)runtime->set_virtual_address_map;
+ early_iounmap(runtime, sizeof(efi_runtime_services_64_t));
+
+ return 0;
+}
+
+static int __init efi_runtime_init(void)
+{
+ int rv;
+
/*
- * Make efi_get_time can be called before entering
- * virtual mode.
+ * Check out the runtime services table. We need to map
+ * the runtime services table so that we can grab the physical
+ * address of several of the EFI runtime functions, needed to
+ * set the firmware into virtual mode.
*/
- efi.get_time = phys_efi_get_time;
- early_iounmap(runtime, sizeof(efi_runtime_services_t));
+ if (efi_enabled(EFI_64BIT))
+ rv = efi_runtime_init64();
+ else
+ rv = efi_runtime_init32();
+
+ if (rv)
+ return rv;
+
+ set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
return 0;
}
@@ -640,6 +646,8 @@ static int __init efi_memmap_init(void)
if (add_efi_memmap)
do_add_efi_memmap();
+ set_bit(EFI_MEMMAP, &efi.flags);
+
return 0;
}
@@ -722,7 +730,7 @@ void __init efi_init(void)
if (efi_systab_init(efi_phys.systab))
return;
- set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
+ set_bit(EFI_SYSTEM_TABLES, &efi.flags);
efi.config_table = (unsigned long)efi.systab->tables;
efi.fw_vendor = (unsigned long)efi.systab->fw_vendor;
@@ -750,24 +758,21 @@ void __init efi_init(void)
if (efi_config_init(arch_tables))
return;
- set_bit(EFI_CONFIG_TABLES, &x86_efi_facility);
-
/*
* Note: We currently don't support runtime services on an EFI
* that doesn't match the kernel 32/64-bit mode.
*/
- if (!efi_is_native())
+ if (!efi_runtime_supported())
pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
else {
if (disable_runtime || efi_runtime_init())
return;
- set_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility);
}
if (efi_memmap_init())
return;
- set_bit(EFI_MEMMAP, &x86_efi_facility);
+ set_bit(EFI_MEMMAP, &efi.flags);
print_efi_memmap();
}
@@ -844,6 +849,22 @@ void __init old_map_region(efi_memory_desc_t *md)
(unsigned long long)md->phys_addr);
}
+static void native_runtime_setup(void)
+{
+ efi.get_time = virt_efi_get_time;
+ efi.set_time = virt_efi_set_time;
+ efi.get_wakeup_time = virt_efi_get_wakeup_time;
+ efi.set_wakeup_time = virt_efi_set_wakeup_time;
+ efi.get_variable = virt_efi_get_variable;
+ efi.get_next_variable = virt_efi_get_next_variable;
+ efi.set_variable = virt_efi_set_variable;
+ efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
+ efi.reset_system = virt_efi_reset_system;
+ efi.query_variable_info = virt_efi_query_variable_info;
+ efi.update_capsule = virt_efi_update_capsule;
+ efi.query_capsule_caps = virt_efi_query_capsule_caps;
+}
+
/* Merge contiguous regions of the same type and attribute */
static void __init efi_merge_regions(void)
{
@@ -891,8 +912,9 @@ static void __init get_systab_virt_addr(efi_memory_desc_t *md)
}
}
-static int __init save_runtime_map(void)
+static void __init save_runtime_map(void)
{
+#ifdef CONFIG_KEXEC
efi_memory_desc_t *md;
void *tmp, *p, *q = NULL;
int count = 0;
@@ -914,38 +936,44 @@ static int __init save_runtime_map(void)
}
efi_runtime_map_setup(q, count, memmap.desc_size);
+ return;
- return 0;
out:
kfree(q);
- return -ENOMEM;
+ pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
+#endif
}
-/*
- * Map efi regions which were passed via setup_data. The virt_addr is a fixed
- * addr which was used in first kernel of a kexec boot.
- */
-static void __init efi_map_regions_fixed(void)
+static void *realloc_pages(void *old_memmap, int old_shift)
{
- void *p;
- efi_memory_desc_t *md;
+ void *ret;
- for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
- md = p;
- efi_map_region_fixed(md); /* FIXME: add error handling */
- get_systab_virt_addr(md);
- }
+ ret = (void *)__get_free_pages(GFP_KERNEL, old_shift + 1);
+ if (!ret)
+ goto out;
+ /*
+ * A first-time allocation doesn't have anything to copy.
+ */
+ if (!old_memmap)
+ return ret;
+
+ memcpy(ret, old_memmap, PAGE_SIZE << old_shift);
+
+out:
+ free_pages((unsigned long)old_memmap, old_shift);
+ return ret;
}
/*
- * Map efi memory ranges for runtime serivce and update new_memmap with virtual
- * addresses.
+ * Map the efi memory ranges of the runtime services and update new_mmap with
+ * virtual addresses.
*/
-static void * __init efi_map_regions(int *count)
+static void * __init efi_map_regions(int *count, int *pg_shift)
{
+ void *p, *new_memmap = NULL;
+ unsigned long left = 0;
efi_memory_desc_t *md;
- void *p, *tmp, *new_memmap = NULL;
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
md = p;
@@ -960,20 +988,80 @@ static void * __init efi_map_regions(int *count)
efi_map_region(md);
get_systab_virt_addr(md);
- tmp = krealloc(new_memmap, (*count + 1) * memmap.desc_size,
- GFP_KERNEL);
- if (!tmp)
- goto out;
- new_memmap = tmp;
+ if (left < memmap.desc_size) {
+ new_memmap = realloc_pages(new_memmap, *pg_shift);
+ if (!new_memmap)
+ return NULL;
+
+ left += PAGE_SIZE << *pg_shift;
+ (*pg_shift)++;
+ }
+
memcpy(new_memmap + (*count * memmap.desc_size), md,
memmap.desc_size);
+
+ left -= memmap.desc_size;
(*count)++;
}
return new_memmap;
-out:
- kfree(new_memmap);
- return NULL;
+}
+
+static void __init kexec_enter_virtual_mode(void)
+{
+#ifdef CONFIG_KEXEC
+ efi_memory_desc_t *md;
+ void *p;
+
+ efi.systab = NULL;
+
+ /*
+ * We don't do virtual mode, since we don't do runtime services, on
+ * non-native EFI
+ */
+ if (!efi_is_native()) {
+ efi_unmap_memmap();
+ return;
+ }
+
+ /*
+ * Map efi regions which were passed via setup_data. The virt_addr is a
+ * fixed addr which was used in first kernel of a kexec boot.
+ */
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
+ efi_map_region_fixed(md); /* FIXME: add error handling */
+ get_systab_virt_addr(md);
+ }
+
+ save_runtime_map();
+
+ BUG_ON(!efi.systab);
+
+ efi_sync_low_kernel_mappings();
+
+ /*
+ * Now that EFI is in virtual mode, update the function
+ * pointers in the runtime service table to the new virtual addresses.
+ *
+ * Call EFI services through wrapper functions.
+ */
+ efi.runtime_version = efi_systab.hdr.revision;
+
+ native_runtime_setup();
+
+ efi.set_virtual_address_map = NULL;
+
+ if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX))
+ runtime_code_page_mkexec();
+
+ /* clean DUMMY object */
+ efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ 0, NULL);
+#endif
}
/*
@@ -995,57 +1083,53 @@ out:
*
* Specially for kexec boot, efi runtime maps in previous kernel should
* be passed in via setup_data. In that case runtime ranges will be mapped
- * to the same virtual addresses as the first kernel.
+ * to the same virtual addresses as the first kernel, see
+ * kexec_enter_virtual_mode().
*/
-void __init efi_enter_virtual_mode(void)
+static void __init __efi_enter_virtual_mode(void)
{
- efi_status_t status;
+ int count = 0, pg_shift = 0;
void *new_memmap = NULL;
- int err, count = 0;
+ efi_status_t status;
efi.systab = NULL;
- /*
- * We don't do virtual mode, since we don't do runtime services, on
- * non-native EFI
- */
- if (!efi_is_native()) {
- efi_unmap_memmap();
+ efi_merge_regions();
+ new_memmap = efi_map_regions(&count, &pg_shift);
+ if (!new_memmap) {
+ pr_err("Error reallocating memory, EFI runtime non-functional!\n");
return;
}
- if (efi_setup) {
- efi_map_regions_fixed();
- } else {
- efi_merge_regions();
- new_memmap = efi_map_regions(&count);
- if (!new_memmap) {
- pr_err("Error reallocating memory, EFI runtime non-functional!\n");
- return;
- }
- }
-
- err = save_runtime_map();
- if (err)
- pr_err("Error saving runtime map, efi runtime on kexec non-functional!!\n");
+ save_runtime_map();
BUG_ON(!efi.systab);
- efi_setup_page_tables();
+ if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift))
+ return;
+
efi_sync_low_kernel_mappings();
+ efi_dump_pagetable();
- if (!efi_setup) {
+ if (efi_is_native()) {
status = phys_efi_set_virtual_address_map(
- memmap.desc_size * count,
- memmap.desc_size,
- memmap.desc_version,
- (efi_memory_desc_t *)__pa(new_memmap));
-
- if (status != EFI_SUCCESS) {
- pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n",
- status);
- panic("EFI call to SetVirtualAddressMap() failed!");
- }
+ memmap.desc_size * count,
+ memmap.desc_size,
+ memmap.desc_version,
+ (efi_memory_desc_t *)__pa(new_memmap));
+ } else {
+ status = efi_thunk_set_virtual_address_map(
+ efi_phys.set_virtual_address_map,
+ memmap.desc_size * count,
+ memmap.desc_size,
+ memmap.desc_version,
+ (efi_memory_desc_t *)__pa(new_memmap));
+ }
+
+ if (status != EFI_SUCCESS) {
+ pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n",
+ status);
+ panic("EFI call to SetVirtualAddressMap() failed!");
}
/*
@@ -1055,23 +1139,43 @@ void __init efi_enter_virtual_mode(void)
* Call EFI services through wrapper functions.
*/
efi.runtime_version = efi_systab.hdr.revision;
- efi.get_time = virt_efi_get_time;
- efi.set_time = virt_efi_set_time;
- efi.get_wakeup_time = virt_efi_get_wakeup_time;
- efi.set_wakeup_time = virt_efi_set_wakeup_time;
- efi.get_variable = virt_efi_get_variable;
- efi.get_next_variable = virt_efi_get_next_variable;
- efi.set_variable = virt_efi_set_variable;
- efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
- efi.reset_system = virt_efi_reset_system;
+
+ if (efi_is_native())
+ native_runtime_setup();
+ else
+ efi_thunk_runtime_setup();
+
efi.set_virtual_address_map = NULL;
- efi.query_variable_info = virt_efi_query_variable_info;
- efi.update_capsule = virt_efi_update_capsule;
- efi.query_capsule_caps = virt_efi_query_capsule_caps;
efi_runtime_mkexec();
- kfree(new_memmap);
+ /*
+ * We mapped the descriptor array into the EFI pagetable above but we're
+ * not unmapping it here. Here's why:
+ *
+ * We're copying select PGDs from the kernel page table to the EFI page
+ * table and when we do so and make changes to those PGDs like unmapping
+ * stuff from them, those changes appear in the kernel page table and we
+ * go boom.
+ *
+ * From setup_real_mode():
+ *
+ * ...
+ * trampoline_pgd[0] = init_level4_pgt[pgd_index(__PAGE_OFFSET)].pgd;
+ *
+ * In this particular case, our allocation is in PGD 0 of the EFI page
+ * table but we've copied that PGD from PGD[272] of the EFI page table:
+ *
+ * pgd_index(__PAGE_OFFSET = 0xffff880000000000) = 272
+ *
+ * where the direct memory mapping in kernel space is.
+ *
+ * new_memmap's VA comes from that direct mapping and thus clearing it,
+ * it would get cleared in the kernel page table too.
+ *
+ * efi_cleanup_page_tables(__pa(new_memmap), 1 << pg_shift);
+ */
+ free_pages((unsigned long)new_memmap, pg_shift);
/* clean DUMMY object */
efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
@@ -1081,6 +1185,14 @@ void __init efi_enter_virtual_mode(void)
0, NULL);
}
+void __init efi_enter_virtual_mode(void)
+{
+ if (efi_setup)
+ kexec_enter_virtual_mode();
+ else
+ __efi_enter_virtual_mode();
+}
+
/*
* Convenience functions to obtain memory types and attributes
*/
@@ -1118,9 +1230,8 @@ u64 efi_mem_attributes(unsigned long phys_addr)
}
/*
- * Some firmware has serious problems when using more than 50% of the EFI
- * variable store, i.e. it triggers bugs that can brick machines. Ensure that
- * we never use more than this safe limit.
+ * Some firmware implementations refuse to boot if there's insufficient space
+ * in the variable store. Ensure that we never use more than a safe limit.
*
* Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
* store.
@@ -1139,10 +1250,9 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
return status;
/*
- * Some firmware implementations refuse to boot if there's insufficient
- * space in the variable store. We account for that by refusing the
- * write if permitting it would reduce the available space to under
- * 5KB. This figure was provided by Samsung, so should be safe.
+ * We account for that by refusing the write if permitting it would
+ * reduce the available space to under 5KB. This figure was provided by
+ * Samsung, so should be safe.
*/
if ((remaining_size - size < EFI_MIN_RESERVE) &&
!efi_no_storage_paranoia) {
@@ -1205,8 +1315,27 @@ static int __init parse_efi_cmdline(char *str)
str++;
if (!strncmp(str, "old_map", 7))
- set_bit(EFI_OLD_MEMMAP, &x86_efi_facility);
+ set_bit(EFI_OLD_MEMMAP, &efi.flags);
return 0;
}
early_param("efi", parse_efi_cmdline);
+
+void __init efi_apply_memmap_quirks(void)
+{
+ /*
+ * Once setup is done earlier, unmap the EFI memory map on mismatched
+ * firmware/kernel architectures since there is no support for runtime
+ * services.
+ */
+ if (!efi_runtime_supported()) {
+ pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
+ efi_unmap_memmap();
+ }
+
+ /*
+ * UV doesn't support the new EFI pagetable mapping yet.
+ */
+ if (is_uv_system())
+ set_bit(EFI_OLD_MEMMAP, &efi.flags);
+}
diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c
index 0b74cdf7f816..9ee3491e31fb 100644
--- a/arch/x86/platform/efi/efi_32.c
+++ b/arch/x86/platform/efi/efi_32.c
@@ -40,7 +40,12 @@
static unsigned long efi_rt_eflags;
void efi_sync_low_kernel_mappings(void) {}
-void efi_setup_page_tables(void) {}
+void __init efi_dump_pagetable(void) {}
+int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
+{
+ return 0;
+}
+void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) {}
void __init efi_map_region(efi_memory_desc_t *md)
{
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index 0c2a234fef1e..290d397e1dd9 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -39,6 +39,7 @@
#include <asm/cacheflush.h>
#include <asm/fixmap.h>
#include <asm/realmode.h>
+#include <asm/time.h>
static pgd_t *save_pgd __initdata;
static unsigned long efi_flags __initdata;
@@ -58,7 +59,8 @@ struct efi_scratch {
u64 prev_cr3;
pgd_t *efi_pgt;
bool use_pgd;
-};
+ u64 phys_stack;
+} __packed;
static void __init early_code_mapping_set_exec(int executable)
{
@@ -137,12 +139,64 @@ void efi_sync_low_kernel_mappings(void)
sizeof(pgd_t) * num_pgds);
}
-void efi_setup_page_tables(void)
+int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
{
+ unsigned long text;
+ struct page *page;
+ unsigned npages;
+ pgd_t *pgd;
+
+ if (efi_enabled(EFI_OLD_MEMMAP))
+ return 0;
+
efi_scratch.efi_pgt = (pgd_t *)(unsigned long)real_mode_header->trampoline_pgd;
+ pgd = __va(efi_scratch.efi_pgt);
- if (!efi_enabled(EFI_OLD_MEMMAP))
- efi_scratch.use_pgd = true;
+ /*
+ * It can happen that the physical address of new_memmap lands in memory
+ * which is not mapped in the EFI page table. Therefore we need to go
+ * and ident-map those pages containing the map before calling
+ * phys_efi_set_virtual_address_map().
+ */
+ if (kernel_map_pages_in_pgd(pgd, pa_memmap, pa_memmap, num_pages, _PAGE_NX)) {
+ pr_err("Error ident-mapping new memmap (0x%lx)!\n", pa_memmap);
+ return 1;
+ }
+
+ efi_scratch.use_pgd = true;
+
+ /*
+ * When making calls to the firmware everything needs to be 1:1
+ * mapped and addressable with 32-bit pointers. Map the kernel
+ * text and allocate a new stack because we can't rely on the
+ * stack pointer being < 4GB.
+ */
+ if (!IS_ENABLED(CONFIG_EFI_MIXED))
+ return 0;
+
+ page = alloc_page(GFP_KERNEL|__GFP_DMA32);
+ if (!page)
+ panic("Unable to allocate EFI runtime stack < 4GB\n");
+
+ efi_scratch.phys_stack = virt_to_phys(page_address(page));
+ efi_scratch.phys_stack += PAGE_SIZE; /* stack grows down */
+
+ npages = (_end - _text) >> PAGE_SHIFT;
+ text = __pa(_text);
+
+ if (kernel_map_pages_in_pgd(pgd, text >> PAGE_SHIFT, text, npages, 0)) {
+ pr_err("Failed to map kernel text 1:1\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages)
+{
+ pgd_t *pgd = (pgd_t *)__va(real_mode_header->trampoline_pgd);
+
+ kernel_unmap_pages_in_pgd(pgd, pa_memmap, num_pages);
}
static void __init __map_region(efi_memory_desc_t *md, u64 va)
@@ -173,6 +227,16 @@ void __init efi_map_region(efi_memory_desc_t *md)
*/
__map_region(md, md->phys_addr);
+ /*
+ * Enforce the 1:1 mapping as the default virtual address when
+ * booting in EFI mixed mode, because even though we may be
+ * running a 64-bit kernel, the firmware may only be 32-bit.
+ */
+ if (!efi_is_native () && IS_ENABLED(CONFIG_EFI_MIXED)) {
+ md->virt_addr = md->phys_addr;
+ return;
+ }
+
efi_va -= size;
/* Is PA 2M-aligned? */
@@ -242,3 +306,299 @@ void __init efi_runtime_mkexec(void)
if (__supported_pte_mask & _PAGE_NX)
runtime_code_page_mkexec();
}
+
+void __init efi_dump_pagetable(void)
+{
+#ifdef CONFIG_EFI_PGT_DUMP
+ pgd_t *pgd = (pgd_t *)__va(real_mode_header->trampoline_pgd);
+
+ ptdump_walk_pgd_level(NULL, pgd);
+#endif
+}
+
+#ifdef CONFIG_EFI_MIXED
+extern efi_status_t efi64_thunk(u32, ...);
+
+#define runtime_service32(func) \
+({ \
+ u32 table = (u32)(unsigned long)efi.systab; \
+ u32 *rt, *___f; \
+ \
+ rt = (u32 *)(table + offsetof(efi_system_table_32_t, runtime)); \
+ ___f = (u32 *)(*rt + offsetof(efi_runtime_services_32_t, func)); \
+ *___f; \
+})
+
+/*
+ * Switch to the EFI page tables early so that we can access the 1:1
+ * runtime services mappings which are not mapped in any other page
+ * tables. This function must be called before runtime_service32().
+ *
+ * Also, disable interrupts because the IDT points to 64-bit handlers,
+ * which aren't going to function correctly when we switch to 32-bit.
+ */
+#define efi_thunk(f, ...) \
+({ \
+ efi_status_t __s; \
+ unsigned long flags; \
+ u32 func; \
+ \
+ efi_sync_low_kernel_mappings(); \
+ local_irq_save(flags); \
+ \
+ efi_scratch.prev_cr3 = read_cr3(); \
+ write_cr3((unsigned long)efi_scratch.efi_pgt); \
+ __flush_tlb_all(); \
+ \
+ func = runtime_service32(f); \
+ __s = efi64_thunk(func, __VA_ARGS__); \
+ \
+ write_cr3(efi_scratch.prev_cr3); \
+ __flush_tlb_all(); \
+ local_irq_restore(flags); \
+ \
+ __s; \
+})
+
+efi_status_t efi_thunk_set_virtual_address_map(
+ void *phys_set_virtual_address_map,
+ unsigned long memory_map_size,
+ unsigned long descriptor_size,
+ u32 descriptor_version,
+ efi_memory_desc_t *virtual_map)
+{
+ efi_status_t status;
+ unsigned long flags;
+ u32 func;
+
+ efi_sync_low_kernel_mappings();
+ local_irq_save(flags);
+
+ efi_scratch.prev_cr3 = read_cr3();
+ write_cr3((unsigned long)efi_scratch.efi_pgt);
+ __flush_tlb_all();
+
+ func = (u32)(unsigned long)phys_set_virtual_address_map;
+ status = efi64_thunk(func, memory_map_size, descriptor_size,
+ descriptor_version, virtual_map);
+
+ write_cr3(efi_scratch.prev_cr3);
+ __flush_tlb_all();
+ local_irq_restore(flags);
+
+ return status;
+}
+
+static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+{
+ efi_status_t status;
+ u32 phys_tm, phys_tc;
+
+ spin_lock(&rtc_lock);
+
+ phys_tm = virt_to_phys(tm);
+ phys_tc = virt_to_phys(tc);
+
+ status = efi_thunk(get_time, phys_tm, phys_tc);
+
+ spin_unlock(&rtc_lock);
+
+ return status;
+}
+
+static efi_status_t efi_thunk_set_time(efi_time_t *tm)
+{
+ efi_status_t status;
+ u32 phys_tm;
+
+ spin_lock(&rtc_lock);
+
+ phys_tm = virt_to_phys(tm);
+
+ status = efi_thunk(set_time, phys_tm);
+
+ spin_unlock(&rtc_lock);
+
+ return status;
+}
+
+static efi_status_t
+efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
+ efi_time_t *tm)
+{
+ efi_status_t status;
+ u32 phys_enabled, phys_pending, phys_tm;
+
+ spin_lock(&rtc_lock);
+
+ phys_enabled = virt_to_phys(enabled);
+ phys_pending = virt_to_phys(pending);
+ phys_tm = virt_to_phys(tm);
+
+ status = efi_thunk(get_wakeup_time, phys_enabled,
+ phys_pending, phys_tm);
+
+ spin_unlock(&rtc_lock);
+
+ return status;
+}
+
+static efi_status_t
+efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
+{
+ efi_status_t status;
+ u32 phys_tm;
+
+ spin_lock(&rtc_lock);
+
+ phys_tm = virt_to_phys(tm);
+
+ status = efi_thunk(set_wakeup_time, enabled, phys_tm);
+
+ spin_unlock(&rtc_lock);
+
+ return status;
+}
+
+
+static efi_status_t
+efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
+ u32 *attr, unsigned long *data_size, void *data)
+{
+ efi_status_t status;
+ u32 phys_name, phys_vendor, phys_attr;
+ u32 phys_data_size, phys_data;
+
+ phys_data_size = virt_to_phys(data_size);
+ phys_vendor = virt_to_phys(vendor);
+ phys_name = virt_to_phys(name);
+ phys_attr = virt_to_phys(attr);
+ phys_data = virt_to_phys(data);
+
+ status = efi_thunk(get_variable, phys_name, phys_vendor,
+ phys_attr, phys_data_size, phys_data);
+
+ return status;
+}
+
+static efi_status_t
+efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
+ u32 attr, unsigned long data_size, void *data)
+{
+ u32 phys_name, phys_vendor, phys_data;
+ efi_status_t status;
+
+ phys_name = virt_to_phys(name);
+ phys_vendor = virt_to_phys(vendor);
+ phys_data = virt_to_phys(data);
+
+ /* If data_size is > sizeof(u32) we've got problems */
+ status = efi_thunk(set_variable, phys_name, phys_vendor,
+ attr, data_size, phys_data);
+
+ return status;
+}
+
+static efi_status_t
+efi_thunk_get_next_variable(unsigned long *name_size,
+ efi_char16_t *name,
+ efi_guid_t *vendor)
+{
+ efi_status_t status;
+ u32 phys_name_size, phys_name, phys_vendor;
+
+ phys_name_size = virt_to_phys(name_size);
+ phys_vendor = virt_to_phys(vendor);
+ phys_name = virt_to_phys(name);
+
+ status = efi_thunk(get_next_variable, phys_name_size,
+ phys_name, phys_vendor);
+
+ return status;
+}
+
+static efi_status_t
+efi_thunk_get_next_high_mono_count(u32 *count)
+{
+ efi_status_t status;
+ u32 phys_count;
+
+ phys_count = virt_to_phys(count);
+ status = efi_thunk(get_next_high_mono_count, phys_count);
+
+ return status;
+}
+
+static void
+efi_thunk_reset_system(int reset_type, efi_status_t status,
+ unsigned long data_size, efi_char16_t *data)
+{
+ u32 phys_data;
+
+ phys_data = virt_to_phys(data);
+
+ efi_thunk(reset_system, reset_type, status, data_size, phys_data);
+}
+
+static efi_status_t
+efi_thunk_update_capsule(efi_capsule_header_t **capsules,
+ unsigned long count, unsigned long sg_list)
+{
+ /*
+ * To properly support this function we would need to repackage
+ * 'capsules' because the firmware doesn't understand 64-bit
+ * pointers.
+ */
+ return EFI_UNSUPPORTED;
+}
+
+static efi_status_t
+efi_thunk_query_variable_info(u32 attr, u64 *storage_space,
+ u64 *remaining_space,
+ u64 *max_variable_size)
+{
+ efi_status_t status;
+ u32 phys_storage, phys_remaining, phys_max;
+
+ if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
+ return EFI_UNSUPPORTED;
+
+ phys_storage = virt_to_phys(storage_space);
+ phys_remaining = virt_to_phys(remaining_space);
+ phys_max = virt_to_phys(max_variable_size);
+
+ status = efi_thunk(query_variable_info, attr, phys_storage,
+ phys_remaining, phys_max);
+
+ return status;
+}
+
+static efi_status_t
+efi_thunk_query_capsule_caps(efi_capsule_header_t **capsules,
+ unsigned long count, u64 *max_size,
+ int *reset_type)
+{
+ /*
+ * To properly support this function we would need to repackage
+ * 'capsules' because the firmware doesn't understand 64-bit
+ * pointers.
+ */
+ return EFI_UNSUPPORTED;
+}
+
+void efi_thunk_runtime_setup(void)
+{
+ efi.get_time = efi_thunk_get_time;
+ efi.set_time = efi_thunk_set_time;
+ efi.get_wakeup_time = efi_thunk_get_wakeup_time;
+ efi.set_wakeup_time = efi_thunk_set_wakeup_time;
+ efi.get_variable = efi_thunk_get_variable;
+ efi.get_next_variable = efi_thunk_get_next_variable;
+ efi.set_variable = efi_thunk_set_variable;
+ efi.get_next_high_mono_count = efi_thunk_get_next_high_mono_count;
+ efi.reset_system = efi_thunk_reset_system;
+ efi.query_variable_info = efi_thunk_query_variable_info;
+ efi.update_capsule = efi_thunk_update_capsule;
+ efi.query_capsule_caps = efi_thunk_query_capsule_caps;
+}
+#endif /* CONFIG_EFI_MIXED */
diff --git a/arch/x86/platform/efi/efi_stub_64.S b/arch/x86/platform/efi/efi_stub_64.S
index 88073b140298..e0984ef0374b 100644
--- a/arch/x86/platform/efi/efi_stub_64.S
+++ b/arch/x86/platform/efi/efi_stub_64.S
@@ -7,6 +7,10 @@
*/
#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/msr.h>
+#include <asm/processor-flags.h>
+#include <asm/page_types.h>
#define SAVE_XMM \
mov %rsp, %rax; \
@@ -164,7 +168,169 @@ ENTRY(efi_call6)
ret
ENDPROC(efi_call6)
+#ifdef CONFIG_EFI_MIXED
+
+/*
+ * We run this function from the 1:1 mapping.
+ *
+ * This function must be invoked with a 1:1 mapped stack.
+ */
+ENTRY(__efi64_thunk)
+ movl %ds, %eax
+ push %rax
+ movl %es, %eax
+ push %rax
+ movl %ss, %eax
+ push %rax
+
+ subq $32, %rsp
+ movl %esi, 0x0(%rsp)
+ movl %edx, 0x4(%rsp)
+ movl %ecx, 0x8(%rsp)
+ movq %r8, %rsi
+ movl %esi, 0xc(%rsp)
+ movq %r9, %rsi
+ movl %esi, 0x10(%rsp)
+
+ sgdt save_gdt(%rip)
+
+ leaq 1f(%rip), %rbx
+ movq %rbx, func_rt_ptr(%rip)
+
+ /* Switch to gdt with 32-bit segments */
+ movl 64(%rsp), %eax
+ lgdt (%rax)
+
+ leaq efi_enter32(%rip), %rax
+ pushq $__KERNEL_CS
+ pushq %rax
+ lretq
+
+1: addq $32, %rsp
+
+ lgdt save_gdt(%rip)
+
+ pop %rbx
+ movl %ebx, %ss
+ pop %rbx
+ movl %ebx, %es
+ pop %rbx
+ movl %ebx, %ds
+
+ /*
+ * Convert 32-bit status code into 64-bit.
+ */
+ test %rax, %rax
+ jz 1f
+ movl %eax, %ecx
+ andl $0x0fffffff, %ecx
+ andl $0xf0000000, %eax
+ shl $32, %rax
+ or %rcx, %rax
+1:
+ ret
+ENDPROC(__efi64_thunk)
+
+ENTRY(efi_exit32)
+ movq func_rt_ptr(%rip), %rax
+ push %rax
+ mov %rdi, %rax
+ ret
+ENDPROC(efi_exit32)
+
+ .code32
+/*
+ * EFI service pointer must be in %edi.
+ *
+ * The stack should represent the 32-bit calling convention.
+ */
+ENTRY(efi_enter32)
+ movl $__KERNEL_DS, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+
+ /* Reload pgtables */
+ movl %cr3, %eax
+ movl %eax, %cr3
+
+ /* Disable paging */
+ movl %cr0, %eax
+ btrl $X86_CR0_PG_BIT, %eax
+ movl %eax, %cr0
+
+ /* Disable long mode via EFER */
+ movl $MSR_EFER, %ecx
+ rdmsr
+ btrl $_EFER_LME, %eax
+ wrmsr
+
+ call *%edi
+
+ /* We must preserve return value */
+ movl %eax, %edi
+
+ /*
+ * Some firmware will return with interrupts enabled. Be sure to
+ * disable them before we switch GDTs.
+ */
+ cli
+
+ movl 68(%esp), %eax
+ movl %eax, 2(%eax)
+ lgdtl (%eax)
+
+ movl %cr4, %eax
+ btsl $(X86_CR4_PAE_BIT), %eax
+ movl %eax, %cr4
+
+ movl %cr3, %eax
+ movl %eax, %cr3
+
+ movl $MSR_EFER, %ecx
+ rdmsr
+ btsl $_EFER_LME, %eax
+ wrmsr
+
+ xorl %eax, %eax
+ lldt %ax
+
+ movl 72(%esp), %eax
+ pushl $__KERNEL_CS
+ pushl %eax
+
+ /* Enable paging */
+ movl %cr0, %eax
+ btsl $X86_CR0_PG_BIT, %eax
+ movl %eax, %cr0
+ lret
+ENDPROC(efi_enter32)
+
+ .data
+ .balign 8
+ .global efi32_boot_gdt
+efi32_boot_gdt: .word 0
+ .quad 0
+
+save_gdt: .word 0
+ .quad 0
+func_rt_ptr: .quad 0
+
+ .global efi_gdt64
+efi_gdt64:
+ .word efi_gdt64_end - efi_gdt64
+ .long 0 /* Filled out by user */
+ .word 0
+ .quad 0x0000000000000000 /* NULL descriptor */
+ .quad 0x00af9a000000ffff /* __KERNEL_CS */
+ .quad 0x00cf92000000ffff /* __KERNEL_DS */
+ .quad 0x0080890000000000 /* TS descriptor */
+ .quad 0x0000000000000000 /* TS continued */
+efi_gdt64_end:
+#endif /* CONFIG_EFI_MIXED */
+
.data
ENTRY(efi_scratch)
.fill 3,8,0
.byte 0
+ .quad 0
diff --git a/arch/x86/platform/efi/efi_thunk_64.S b/arch/x86/platform/efi/efi_thunk_64.S
new file mode 100644
index 000000000000..8806fa73e6e6
--- /dev/null
+++ b/arch/x86/platform/efi/efi_thunk_64.S
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 Intel Corporation; author Matt Fleming
+ */
+
+#include <linux/linkage.h>
+#include <asm/page_types.h>
+
+ .text
+ .code64
+ENTRY(efi64_thunk)
+ push %rbp
+ push %rbx
+
+ /*
+ * Switch to 1:1 mapped 32-bit stack pointer.
+ */
+ movq %rsp, efi_saved_sp(%rip)
+ movq efi_scratch+25(%rip), %rsp
+
+ /*
+ * Calculate the physical address of the kernel text.
+ */
+ movq $__START_KERNEL_map, %rax
+ subq phys_base(%rip), %rax
+
+ /*
+ * Push some physical addresses onto the stack. This is easier
+ * to do now in a code64 section while the assembler can address
+ * 64-bit values. Note that all the addresses on the stack are
+ * 32-bit.
+ */
+ subq $16, %rsp
+ leaq efi_exit32(%rip), %rbx
+ subq %rax, %rbx
+ movl %ebx, 8(%rsp)
+ leaq efi_gdt64(%rip), %rbx
+ subq %rax, %rbx
+ movl %ebx, 2(%ebx)
+ movl %ebx, 4(%rsp)
+ leaq efi_gdt32(%rip), %rbx
+ subq %rax, %rbx
+ movl %ebx, 2(%ebx)
+ movl %ebx, (%rsp)
+
+ leaq __efi64_thunk(%rip), %rbx
+ subq %rax, %rbx
+ call *%rbx
+
+ movq efi_saved_sp(%rip), %rsp
+ pop %rbx
+ pop %rbp
+ retq
+ENDPROC(efi64_thunk)
+
+ .data
+efi_gdt32:
+ .word efi_gdt32_end - efi_gdt32
+ .long 0 /* Filled out above */
+ .word 0
+ .quad 0x0000000000000000 /* NULL descriptor */
+ .quad 0x00cf9a000000ffff /* __KERNEL_CS */
+ .quad 0x00cf93000000ffff /* __KERNEL_DS */
+efi_gdt32_end:
+
+efi_saved_sp: .quad 0
diff --git a/arch/x86/platform/ts5500/ts5500.c b/arch/x86/platform/ts5500/ts5500.c
index 39febb214e8c..9471b9456f25 100644
--- a/arch/x86/platform/ts5500/ts5500.c
+++ b/arch/x86/platform/ts5500/ts5500.c
@@ -88,7 +88,7 @@ struct ts5500_sbc {
static const struct {
const char * const string;
const ssize_t offset;
-} ts5500_signatures[] __initdata = {
+} ts5500_signatures[] __initconst = {
{ "TS-5x00 AMD Elan", 0xb14 },
};
diff --git a/arch/x86/platform/visws/Makefile b/arch/x86/platform/visws/Makefile
deleted file mode 100644
index 91bc17ab2fd5..000000000000
--- a/arch/x86/platform/visws/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_X86_VISWS) += visws_quirks.o
diff --git a/arch/x86/platform/visws/visws_quirks.c b/arch/x86/platform/visws/visws_quirks.c
deleted file mode 100644
index 94d8a39332ec..000000000000
--- a/arch/x86/platform/visws/visws_quirks.c
+++ /dev/null
@@ -1,608 +0,0 @@
-/*
- * SGI Visual Workstation support and quirks, unmaintained.
- *
- * Split out from setup.c by davej@suse.de
- *
- * Copyright (C) 1999 Bent Hagemark, Ingo Molnar
- *
- * SGI Visual Workstation interrupt controller
- *
- * The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC
- * which serves as the main interrupt controller in the system. Non-legacy
- * hardware in the system uses this controller directly. Legacy devices
- * are connected to the PIIX4 which in turn has its 8259(s) connected to
- * a of the Cobalt APIC entry.
- *
- * 09/02/2000 - Updated for 2.4 by jbarnes@sgi.com
- *
- * 25/11/2002 - Updated for 2.5 by Andrey Panin <pazke@orbita1.ru>
- */
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-
-#include <asm/visws/cobalt.h>
-#include <asm/visws/piix4.h>
-#include <asm/io_apic.h>
-#include <asm/fixmap.h>
-#include <asm/reboot.h>
-#include <asm/setup.h>
-#include <asm/apic.h>
-#include <asm/e820.h>
-#include <asm/time.h>
-#include <asm/io.h>
-
-#include <linux/kernel_stat.h>
-
-#include <asm/i8259.h>
-#include <asm/irq_vectors.h>
-#include <asm/visws/lithium.h>
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
-
-extern int no_broadcast;
-
-char visws_board_type = -1;
-char visws_board_rev = -1;
-
-static void __init visws_time_init(void)
-{
- printk(KERN_INFO "Starting Cobalt Timer system clock\n");
-
- /* Set the countdown value */
- co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
-
- /* Start the timer */
- co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN);
-
- /* Enable (unmask) the timer interrupt */
- co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
-
- setup_default_timer_irq();
-}
-
-/* Replaces the default init_ISA_irqs in the generic setup */
-static void __init visws_pre_intr_init(void);
-
-/* Quirk for machine specific memory setup. */
-
-#define MB (1024 * 1024)
-
-unsigned long sgivwfb_mem_phys;
-unsigned long sgivwfb_mem_size;
-EXPORT_SYMBOL(sgivwfb_mem_phys);
-EXPORT_SYMBOL(sgivwfb_mem_size);
-
-long long mem_size __initdata = 0;
-
-static char * __init visws_memory_setup(void)
-{
- long long gfx_mem_size = 8 * MB;
-
- mem_size = boot_params.alt_mem_k;
-
- if (!mem_size) {
- printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
- mem_size = 128 * MB;
- }
-
- /*
- * this hardcodes the graphics memory to 8 MB
- * it really should be sized dynamically (or at least
- * set as a boot param)
- */
- if (!sgivwfb_mem_size) {
- printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
- sgivwfb_mem_size = 8 * MB;
- }
-
- /*
- * Trim to nearest MB
- */
- sgivwfb_mem_size &= ~((1 << 20) - 1);
- sgivwfb_mem_phys = mem_size - gfx_mem_size;
-
- e820_add_region(0, LOWMEMSIZE(), E820_RAM);
- e820_add_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
- e820_add_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
-
- return "PROM";
-}
-
-static void visws_machine_emergency_restart(void)
-{
- /*
- * Visual Workstations restart after this
- * register is poked on the PIIX4
- */
- outb(PIIX4_RESET_VAL, PIIX4_RESET_PORT);
-}
-
-static void visws_machine_power_off(void)
-{
- unsigned short pm_status;
-/* extern unsigned int pci_bus0; */
-
- while ((pm_status = inw(PMSTS_PORT)) & 0x100)
- outw(pm_status, PMSTS_PORT);
-
- outw(PM_SUSPEND_ENABLE, PMCNTRL_PORT);
-
- mdelay(10);
-
-#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
- (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
-
-/* outl(PCI_CONF1_ADDRESS(pci_bus0, SPECIAL_DEV, SPECIAL_REG), 0xCF8); */
- outl(PIIX_SPECIAL_STOP, 0xCFC);
-}
-
-static void __init visws_get_smp_config(unsigned int early)
-{
-}
-
-/*
- * The Visual Workstation is Intel MP compliant in the hardware
- * sense, but it doesn't have a BIOS(-configuration table).
- * No problem for Linux.
- */
-
-static void __init MP_processor_info(struct mpc_cpu *m)
-{
- int ver, logical_apicid;
- physid_mask_t apic_cpus;
-
- if (!(m->cpuflag & CPU_ENABLED))
- return;
-
- logical_apicid = m->apicid;
- printk(KERN_INFO "%sCPU #%d %u:%u APIC version %d\n",
- m->cpuflag & CPU_BOOTPROCESSOR ? "Bootup " : "",
- m->apicid, (m->cpufeature & CPU_FAMILY_MASK) >> 8,
- (m->cpufeature & CPU_MODEL_MASK) >> 4, m->apicver);
-
- if (m->cpuflag & CPU_BOOTPROCESSOR)
- boot_cpu_physical_apicid = m->apicid;
-
- ver = m->apicver;
- if ((ver >= 0x14 && m->apicid >= 0xff) || m->apicid >= 0xf) {
- printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
- m->apicid, MAX_LOCAL_APIC);
- return;
- }
-
- apic->apicid_to_cpu_present(m->apicid, &apic_cpus);
- physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus);
- /*
- * Validate version
- */
- if (ver == 0x0) {
- printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! "
- "fixing up to 0x10. (tell your hw vendor)\n",
- m->apicid);
- ver = 0x10;
- }
- apic_version[m->apicid] = ver;
-}
-
-static void __init visws_find_smp_config(void)
-{
- struct mpc_cpu *mp = phys_to_virt(CO_CPU_TAB_PHYS);
- unsigned short ncpus = readw(phys_to_virt(CO_CPU_NUM_PHYS));
-
- if (ncpus > CO_CPU_MAX) {
- printk(KERN_WARNING "find_visws_smp: got cpu count of %d at %p\n",
- ncpus, mp);
-
- ncpus = CO_CPU_MAX;
- }
-
- if (ncpus > setup_max_cpus)
- ncpus = setup_max_cpus;
-
-#ifdef CONFIG_X86_LOCAL_APIC
- smp_found_config = 1;
-#endif
- while (ncpus--)
- MP_processor_info(mp++);
-
- mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-}
-
-static void visws_trap_init(void);
-
-void __init visws_early_detect(void)
-{
- int raw;
-
- visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
- >> PIIX_GPI_BD_SHIFT;
-
- if (visws_board_type < 0)
- return;
-
- /*
- * Override the default platform setup functions
- */
- x86_init.resources.memory_setup = visws_memory_setup;
- x86_init.mpparse.get_smp_config = visws_get_smp_config;
- x86_init.mpparse.find_smp_config = visws_find_smp_config;
- x86_init.irqs.pre_vector_init = visws_pre_intr_init;
- x86_init.irqs.trap_init = visws_trap_init;
- x86_init.timers.timer_init = visws_time_init;
- x86_init.pci.init = pci_visws_init;
- x86_init.pci.init_irq = x86_init_noop;
-
- /*
- * Install reboot quirks:
- */
- pm_power_off = visws_machine_power_off;
- machine_ops.emergency_restart = visws_machine_emergency_restart;
-
- /*
- * Do not use broadcast IPIs:
- */
- no_broadcast = 0;
-
-#ifdef CONFIG_X86_IO_APIC
- /*
- * Turn off IO-APIC detection and initialization:
- */
- skip_ioapic_setup = 1;
-#endif
-
- /*
- * Get Board rev.
- * First, we have to initialize the 307 part to allow us access
- * to the GPIO registers. Let's map them at 0x0fc0 which is right
- * after the PIIX4 PM section.
- */
- outb_p(SIO_DEV_SEL, SIO_INDEX);
- outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */
-
- outb_p(SIO_DEV_MSB, SIO_INDEX);
- outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */
-
- outb_p(SIO_DEV_LSB, SIO_INDEX);
- outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */
-
- outb_p(SIO_DEV_ENB, SIO_INDEX);
- outb_p(1, SIO_DATA); /* Enable GPIO registers. */
-
- /*
- * Now, we have to map the power management section to write
- * a bit which enables access to the GPIO registers.
- * What lunatic came up with this shit?
- */
- outb_p(SIO_DEV_SEL, SIO_INDEX);
- outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */
-
- outb_p(SIO_DEV_MSB, SIO_INDEX);
- outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */
-
- outb_p(SIO_DEV_LSB, SIO_INDEX);
- outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */
-
- outb_p(SIO_DEV_ENB, SIO_INDEX);
- outb_p(1, SIO_DATA); /* Enable PM registers. */
-
- /*
- * Now, write the PM register which enables the GPIO registers.
- */
- outb_p(SIO_PM_FER2, SIO_PM_INDEX);
- outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
-
- /*
- * Now, initialize the GPIO registers.
- * We want them all to be inputs which is the
- * power on default, so let's leave them alone.
- * So, let's just read the board rev!
- */
- raw = inb_p(SIO_GP_DATA1);
- raw &= 0x7f; /* 7 bits of valid board revision ID. */
-
- if (visws_board_type == VISWS_320) {
- if (raw < 0x6) {
- visws_board_rev = 4;
- } else if (raw < 0xc) {
- visws_board_rev = 5;
- } else {
- visws_board_rev = 6;
- }
- } else if (visws_board_type == VISWS_540) {
- visws_board_rev = 2;
- } else {
- visws_board_rev = raw;
- }
-
- printk(KERN_INFO "Silicon Graphics Visual Workstation %s (rev %d) detected\n",
- (visws_board_type == VISWS_320 ? "320" :
- (visws_board_type == VISWS_540 ? "540" :
- "unknown")), visws_board_rev);
-}
-
-#define A01234 (LI_INTA_0 | LI_INTA_1 | LI_INTA_2 | LI_INTA_3 | LI_INTA_4)
-#define BCD (LI_INTB | LI_INTC | LI_INTD)
-#define ALLDEVS (A01234 | BCD)
-
-static __init void lithium_init(void)
-{
- set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
- set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
-
- if ((li_pcia_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
- (li_pcia_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
- printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'A');
-/* panic("This machine is not SGI Visual Workstation 320/540"); */
- }
-
- if ((li_pcib_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
- (li_pcib_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
- printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'B');
-/* panic("This machine is not SGI Visual Workstation 320/540"); */
- }
-
- li_pcia_write16(LI_PCI_INTEN, ALLDEVS);
- li_pcib_write16(LI_PCI_INTEN, ALLDEVS);
-}
-
-static __init void cobalt_init(void)
-{
- /*
- * On normal SMP PC this is used only with SMP, but we have to
- * use it and set it up here to start the Cobalt clock
- */
- set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
- setup_local_APIC();
- printk(KERN_INFO "Local APIC Version %#x, ID %#x\n",
- (unsigned int)apic_read(APIC_LVR),
- (unsigned int)apic_read(APIC_ID));
-
- set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
- set_fixmap(FIX_CO_APIC, CO_APIC_PHYS);
- printk(KERN_INFO "Cobalt Revision %#lx, APIC ID %#lx\n",
- co_cpu_read(CO_CPU_REV), co_apic_read(CO_APIC_ID));
-
- /* Enable Cobalt APIC being careful to NOT change the ID! */
- co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID) | CO_APIC_ENABLE);
-
- printk(KERN_INFO "Cobalt APIC enabled: ID reg %#lx\n",
- co_apic_read(CO_APIC_ID));
-}
-
-static void __init visws_trap_init(void)
-{
- lithium_init();
- cobalt_init();
-}
-
-/*
- * IRQ controller / APIC support:
- */
-
-static DEFINE_SPINLOCK(cobalt_lock);
-
-/*
- * Set the given Cobalt APIC Redirection Table entry to point
- * to the given IDT vector/index.
- */
-static inline void co_apic_set(int entry, int irq)
-{
- co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (irq + FIRST_EXTERNAL_VECTOR));
- co_apic_write(CO_APIC_HI(entry), 0);
-}
-
-/*
- * Cobalt (IO)-APIC functions to handle PCI devices.
- */
-static inline int co_apic_ide0_hack(void)
-{
- extern char visws_board_type;
- extern char visws_board_rev;
-
- if (visws_board_type == VISWS_320 && visws_board_rev == 5)
- return 5;
- return CO_APIC_IDE0;
-}
-
-static int is_co_apic(unsigned int irq)
-{
- if (IS_CO_APIC(irq))
- return CO_APIC(irq);
-
- switch (irq) {
- case 0: return CO_APIC_CPU;
- case CO_IRQ_IDE0: return co_apic_ide0_hack();
- case CO_IRQ_IDE1: return CO_APIC_IDE1;
- default: return -1;
- }
-}
-
-
-/*
- * This is the SGI Cobalt (IO-)APIC:
- */
-static void enable_cobalt_irq(struct irq_data *data)
-{
- co_apic_set(is_co_apic(data->irq), data->irq);
-}
-
-static void disable_cobalt_irq(struct irq_data *data)
-{
- int entry = is_co_apic(data->irq);
-
- co_apic_write(CO_APIC_LO(entry), CO_APIC_MASK);
- co_apic_read(CO_APIC_LO(entry));
-}
-
-static void ack_cobalt_irq(struct irq_data *data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cobalt_lock, flags);
- disable_cobalt_irq(data);
- apic_write(APIC_EOI, APIC_EOI_ACK);
- spin_unlock_irqrestore(&cobalt_lock, flags);
-}
-
-static struct irq_chip cobalt_irq_type = {
- .name = "Cobalt-APIC",
- .irq_enable = enable_cobalt_irq,
- .irq_disable = disable_cobalt_irq,
- .irq_ack = ack_cobalt_irq,
-};
-
-
-/*
- * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt
- * -- not the manner expected by the code in i8259.c.
- *
- * there is a 'master' physical interrupt source that gets sent to
- * the CPU. But in the chipset there are various 'virtual' interrupts
- * waiting to be handled. We represent this to Linux through a 'master'
- * interrupt controller type, and through a special virtual interrupt-
- * controller. Device drivers only see the virtual interrupt sources.
- */
-static unsigned int startup_piix4_master_irq(struct irq_data *data)
-{
- legacy_pic->init(0);
- enable_cobalt_irq(data);
- return 0;
-}
-
-static struct irq_chip piix4_master_irq_type = {
- .name = "PIIX4-master",
- .irq_startup = startup_piix4_master_irq,
- .irq_ack = ack_cobalt_irq,
-};
-
-static void pii4_mask(struct irq_data *data) { }
-
-static struct irq_chip piix4_virtual_irq_type = {
- .name = "PIIX4-virtual",
- .irq_mask = pii4_mask,
-};
-
-/*
- * PIIX4-8259 master/virtual functions to handle interrupt requests
- * from legacy devices: floppy, parallel, serial, rtc.
- *
- * None of these get Cobalt APIC entries, neither do they have IDT
- * entries. These interrupts are purely virtual and distributed from
- * the 'master' interrupt source: CO_IRQ_8259.
- *
- * When the 8259 interrupts its handler figures out which of these
- * devices is interrupting and dispatches to its handler.
- *
- * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/
- * enable_irq gets the right irq. This 'master' irq is never directly
- * manipulated by any driver.
- */
-static irqreturn_t piix4_master_intr(int irq, void *dev_id)
-{
- unsigned long flags;
- int realirq;
-
- raw_spin_lock_irqsave(&i8259A_lock, flags);
-
- /* Find out what's interrupting in the PIIX4 master 8259 */
- outb(0x0c, 0x20); /* OCW3 Poll command */
- realirq = inb(0x20);
-
- /*
- * Bit 7 == 0 means invalid/spurious
- */
- if (unlikely(!(realirq & 0x80)))
- goto out_unlock;
-
- realirq &= 7;
-
- if (unlikely(realirq == 2)) {
- outb(0x0c, 0xa0);
- realirq = inb(0xa0);
-
- if (unlikely(!(realirq & 0x80)))
- goto out_unlock;
-
- realirq = (realirq & 7) + 8;
- }
-
- /* mask and ack interrupt */
- cached_irq_mask |= 1 << realirq;
- if (unlikely(realirq > 7)) {
- inb(0xa1);
- outb(cached_slave_mask, 0xa1);
- outb(0x60 + (realirq & 7), 0xa0);
- outb(0x60 + 2, 0x20);
- } else {
- inb(0x21);
- outb(cached_master_mask, 0x21);
- outb(0x60 + realirq, 0x20);
- }
-
- raw_spin_unlock_irqrestore(&i8259A_lock, flags);
-
- /*
- * handle this 'virtual interrupt' as a Cobalt one now.
- */
- generic_handle_irq(realirq);
-
- return IRQ_HANDLED;
-
-out_unlock:
- raw_spin_unlock_irqrestore(&i8259A_lock, flags);
- return IRQ_NONE;
-}
-
-static struct irqaction master_action = {
- .handler = piix4_master_intr,
- .name = "PIIX4-8259",
- .flags = IRQF_NO_THREAD,
-};
-
-static struct irqaction cascade_action = {
- .handler = no_action,
- .name = "cascade",
- .flags = IRQF_NO_THREAD,
-};
-
-static inline void set_piix4_virtual_irq_type(void)
-{
- piix4_virtual_irq_type.irq_enable = i8259A_chip.irq_unmask;
- piix4_virtual_irq_type.irq_disable = i8259A_chip.irq_mask;
- piix4_virtual_irq_type.irq_unmask = i8259A_chip.irq_unmask;
-}
-
-static void __init visws_pre_intr_init(void)
-{
- int i;
-
- set_piix4_virtual_irq_type();
-
- for (i = 0; i < CO_IRQ_APIC0 + CO_APIC_LAST + 1; i++) {
- struct irq_chip *chip = NULL;
-
- if (i == 0)
- chip = &cobalt_irq_type;
- else if (i == CO_IRQ_IDE0)
- chip = &cobalt_irq_type;
- else if (i == CO_IRQ_IDE1)
- chip = &cobalt_irq_type;
- else if (i == CO_IRQ_8259)
- chip = &piix4_master_irq_type;
- else if (i < CO_IRQ_APIC0)
- chip = &piix4_virtual_irq_type;
- else if (IS_CO_APIC(i))
- chip = &cobalt_irq_type;
-
- if (chip)
- irq_set_chip(i, chip);
- }
-
- setup_irq(CO_IRQ_8259, &master_action);
- setup_irq(2, &cascade_action);
-}
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index cfbdbdb4e173..bbb1d2259ecf 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -69,8 +69,8 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
"__per_cpu_load|"
"init_per_cpu__.*|"
"__end_rodata_hpage_align|"
- "__vvar_page|"
#endif
+ "__vvar_page|"
"_end)$"
};
diff --git a/arch/x86/um/asm/barrier.h b/arch/x86/um/asm/barrier.h
index 7d01b8c56c00..cc04e67bfd05 100644
--- a/arch/x86/um/asm/barrier.h
+++ b/arch/x86/um/asm/barrier.h
@@ -40,11 +40,7 @@
#define smp_rmb() barrier()
#endif /* CONFIG_X86_PPRO_FENCE */
-#ifdef CONFIG_X86_OOSTORE
-#define smp_wmb() wmb()
-#else /* CONFIG_X86_OOSTORE */
#define smp_wmb() barrier()
-#endif /* CONFIG_X86_OOSTORE */
#define smp_read_barrier_depends() read_barrier_depends()
#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index fd14be1d1472..c580d1210ffe 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -2,6 +2,8 @@
# Building vDSO images for x86.
#
+KBUILD_CFLAGS += $(DISABLE_LTO)
+
VDSO64-$(CONFIG_X86_64) := y
VDSOX32-$(CONFIG_X86_X32_ABI) := y
VDSO32-$(CONFIG_X86_32) := y
@@ -21,7 +23,8 @@ vobjs-$(VDSOX32-y) += $(vobjx32s-compat)
vobj64s := $(filter-out $(vobjx32s-compat),$(vobjs-y))
# files to link into kernel
-obj-$(VDSO64-y) += vma.o vdso.o
+obj-y += vma.o
+obj-$(VDSO64-y) += vdso.o
obj-$(VDSOX32-y) += vdsox32.o
obj-$(VDSO32-y) += vdso32.o vdso32-setup.o
@@ -35,7 +38,8 @@ export CPPFLAGS_vdso.lds += -P -C
VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \
-Wl,--no-undefined \
- -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
+ -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 \
+ $(DISABLE_LTO)
$(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so
@@ -127,7 +131,7 @@ vdso32.so-$(VDSO32-y) += sysenter
vdso32-images = $(vdso32.so-y:%=vdso32-%.so)
CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds)
-VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-soname=linux-gate.so.1
+VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-m,elf_i386 -Wl,-soname=linux-gate.so.1
# This makes sure the $(obj) subdirectory exists even though vdso32/
# is not a kbuild sub-make subdirectory.
@@ -135,7 +139,7 @@ override obj-dirs = $(dir $(obj)) $(obj)/vdso32/
targets += vdso32/vdso32.lds
targets += $(vdso32-images) $(vdso32-images:=.dbg)
-targets += vdso32/note.o $(vdso32.so-y:%=vdso32/%.o)
+targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o)
extra-y += $(vdso32-images)
@@ -145,8 +149,19 @@ KBUILD_AFLAGS_32 := $(filter-out -m64,$(KBUILD_AFLAGS))
$(vdso32-images:%=$(obj)/%.dbg): KBUILD_AFLAGS = $(KBUILD_AFLAGS_32)
$(vdso32-images:%=$(obj)/%.dbg): asflags-$(CONFIG_X86_64) += -m32
+KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS))
+KBUILD_CFLAGS_32 := $(filter-out -mcmodel=kernel,$(KBUILD_CFLAGS_32))
+KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32))
+KBUILD_CFLAGS_32 := $(filter-out -mfentry,$(KBUILD_CFLAGS_32))
+KBUILD_CFLAGS_32 += -m32 -msoft-float -mregparm=0 -fpic
+KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector)
+KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls)
+KBUILD_CFLAGS_32 += -fno-omit-frame-pointer
+$(vdso32-images:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32)
+
$(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \
$(obj)/vdso32/vdso32.lds \
+ $(obj)/vdso32/vclock_gettime.o \
$(obj)/vdso32/note.o \
$(obj)/vdso32/%.o
$(call if_changed,vdso)
@@ -181,7 +196,8 @@ quiet_cmd_vdso = VDSO $@
-Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \
sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'
-VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \
+ $(LTO_CFLAGS)
GCOV_PROFILE := n
#
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c
index eb5d7a56f8d4..16d686171e9a 100644
--- a/arch/x86/vdso/vclock_gettime.c
+++ b/arch/x86/vdso/vclock_gettime.c
@@ -4,6 +4,9 @@
*
* Fast user context implementation of clock_gettime, gettimeofday, and time.
*
+ * 32 Bit compat layer by Stefani Seibold <stefani@seibold.net>
+ * sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany
+ *
* The code should have no internal unresolved relocations.
* Check with readelf after changing.
*/
@@ -11,56 +14,55 @@
/* Disable profiling for userspace code: */
#define DISABLE_BRANCH_PROFILING
-#include <linux/kernel.h>
-#include <linux/posix-timers.h>
-#include <linux/time.h>
-#include <linux/string.h>
-#include <asm/vsyscall.h>
-#include <asm/fixmap.h>
+#include <uapi/linux/time.h>
#include <asm/vgtod.h>
-#include <asm/timex.h>
#include <asm/hpet.h>
+#include <asm/vvar.h>
#include <asm/unistd.h>
-#include <asm/io.h>
-#include <asm/pvclock.h>
+#include <asm/msr.h>
+#include <linux/math64.h>
+#include <linux/time.h>
#define gtod (&VVAR(vsyscall_gtod_data))
-notrace static cycle_t vread_tsc(void)
+extern int __vdso_clock_gettime(clockid_t clock, struct timespec *ts);
+extern int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz);
+extern time_t __vdso_time(time_t *t);
+
+#ifdef CONFIG_HPET_TIMER
+static inline u32 read_hpet_counter(const volatile void *addr)
{
- cycle_t ret;
- u64 last;
+ return *(const volatile u32 *) (addr + HPET_COUNTER);
+}
+#endif
- /*
- * Empirically, a fence (of type that depends on the CPU)
- * before rdtsc is enough to ensure that rdtsc is ordered
- * with respect to loads. The various CPU manuals are unclear
- * as to whether rdtsc can be reordered with later loads,
- * but no one has ever seen it happen.
- */
- rdtsc_barrier();
- ret = (cycle_t)vget_cycles();
+#ifndef BUILD_VDSO32
- last = VVAR(vsyscall_gtod_data).clock.cycle_last;
+#include <linux/kernel.h>
+#include <asm/vsyscall.h>
+#include <asm/fixmap.h>
+#include <asm/pvclock.h>
- if (likely(ret >= last))
- return ret;
+static notrace cycle_t vread_hpet(void)
+{
+ return read_hpet_counter((const void *)fix_to_virt(VSYSCALL_HPET));
+}
- /*
- * GCC likes to generate cmov here, but this branch is extremely
- * predictable (it's just a funciton of time and the likely is
- * very likely) and there's a data dependence, so force GCC
- * to generate a branch instead. I don't barrier() because
- * we don't actually need a barrier, and if this function
- * ever gets inlined it will generate worse code.
- */
- asm volatile ("");
- return last;
+notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
+{
+ long ret;
+ asm("syscall" : "=a" (ret) :
+ "0" (__NR_clock_gettime), "D" (clock), "S" (ts) : "memory");
+ return ret;
}
-static notrace cycle_t vread_hpet(void)
+notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
{
- return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + HPET_COUNTER);
+ long ret;
+
+ asm("syscall" : "=a" (ret) :
+ "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
+ return ret;
}
#ifdef CONFIG_PARAVIRT_CLOCK
@@ -124,7 +126,7 @@ static notrace cycle_t vread_pvclock(int *mode)
*mode = VCLOCK_NONE;
/* refer to tsc.c read_tsc() comment for rationale */
- last = VVAR(vsyscall_gtod_data).clock.cycle_last;
+ last = gtod->cycle_last;
if (likely(ret >= last))
return ret;
@@ -133,11 +135,30 @@ static notrace cycle_t vread_pvclock(int *mode)
}
#endif
+#else
+
+extern u8 hpet_page
+ __attribute__((visibility("hidden")));
+
+#ifdef CONFIG_HPET_TIMER
+static notrace cycle_t vread_hpet(void)
+{
+ return read_hpet_counter((const void *)(&hpet_page));
+}
+#endif
+
notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
{
long ret;
- asm("syscall" : "=a" (ret) :
- "0" (__NR_clock_gettime),"D" (clock), "S" (ts) : "memory");
+
+ asm(
+ "mov %%ebx, %%edx \n"
+ "mov %2, %%ebx \n"
+ "call VDSO32_vsyscall \n"
+ "mov %%edx, %%ebx \n"
+ : "=a" (ret)
+ : "0" (__NR_clock_gettime), "g" (clock), "c" (ts)
+ : "memory", "edx");
return ret;
}
@@ -145,28 +166,79 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
{
long ret;
- asm("syscall" : "=a" (ret) :
- "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
+ asm(
+ "mov %%ebx, %%edx \n"
+ "mov %2, %%ebx \n"
+ "call VDSO32_vsyscall \n"
+ "mov %%edx, %%ebx \n"
+ : "=a" (ret)
+ : "0" (__NR_gettimeofday), "g" (tv), "c" (tz)
+ : "memory", "edx");
return ret;
}
+#ifdef CONFIG_PARAVIRT_CLOCK
+
+static notrace cycle_t vread_pvclock(int *mode)
+{
+ *mode = VCLOCK_NONE;
+ return 0;
+}
+#endif
+
+#endif
+
+notrace static cycle_t vread_tsc(void)
+{
+ cycle_t ret;
+ u64 last;
+
+ /*
+ * Empirically, a fence (of type that depends on the CPU)
+ * before rdtsc is enough to ensure that rdtsc is ordered
+ * with respect to loads. The various CPU manuals are unclear
+ * as to whether rdtsc can be reordered with later loads,
+ * but no one has ever seen it happen.
+ */
+ rdtsc_barrier();
+ ret = (cycle_t)__native_read_tsc();
+
+ last = gtod->cycle_last;
+
+ if (likely(ret >= last))
+ return ret;
+
+ /*
+ * GCC likes to generate cmov here, but this branch is extremely
+ * predictable (it's just a funciton of time and the likely is
+ * very likely) and there's a data dependence, so force GCC
+ * to generate a branch instead. I don't barrier() because
+ * we don't actually need a barrier, and if this function
+ * ever gets inlined it will generate worse code.
+ */
+ asm volatile ("");
+ return last;
+}
notrace static inline u64 vgetsns(int *mode)
{
- long v;
+ u64 v;
cycles_t cycles;
- if (gtod->clock.vclock_mode == VCLOCK_TSC)
+
+ if (gtod->vclock_mode == VCLOCK_TSC)
cycles = vread_tsc();
- else if (gtod->clock.vclock_mode == VCLOCK_HPET)
+#ifdef CONFIG_HPET_TIMER
+ else if (gtod->vclock_mode == VCLOCK_HPET)
cycles = vread_hpet();
+#endif
#ifdef CONFIG_PARAVIRT_CLOCK
- else if (gtod->clock.vclock_mode == VCLOCK_PVCLOCK)
+ else if (gtod->vclock_mode == VCLOCK_PVCLOCK)
cycles = vread_pvclock(mode);
#endif
else
return 0;
- v = (cycles - gtod->clock.cycle_last) & gtod->clock.mask;
- return v * gtod->clock.mult;
+ v = (cycles - gtod->cycle_last) & gtod->mask;
+ return v * gtod->mult;
}
/* Code size doesn't matter (vdso is 4k anyway) and this is faster. */
@@ -176,106 +248,102 @@ notrace static int __always_inline do_realtime(struct timespec *ts)
u64 ns;
int mode;
- ts->tv_nsec = 0;
do {
- seq = raw_read_seqcount_begin(&gtod->seq);
- mode = gtod->clock.vclock_mode;
+ seq = gtod_read_begin(gtod);
+ mode = gtod->vclock_mode;
ts->tv_sec = gtod->wall_time_sec;
ns = gtod->wall_time_snsec;
ns += vgetsns(&mode);
- ns >>= gtod->clock.shift;
- } while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
+ ns >>= gtod->shift;
+ } while (unlikely(gtod_read_retry(gtod, seq)));
+
+ ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
+ ts->tv_nsec = ns;
- timespec_add_ns(ts, ns);
return mode;
}
-notrace static int do_monotonic(struct timespec *ts)
+notrace static int __always_inline do_monotonic(struct timespec *ts)
{
unsigned long seq;
u64 ns;
int mode;
- ts->tv_nsec = 0;
do {
- seq = raw_read_seqcount_begin(&gtod->seq);
- mode = gtod->clock.vclock_mode;
+ seq = gtod_read_begin(gtod);
+ mode = gtod->vclock_mode;
ts->tv_sec = gtod->monotonic_time_sec;
ns = gtod->monotonic_time_snsec;
ns += vgetsns(&mode);
- ns >>= gtod->clock.shift;
- } while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
- timespec_add_ns(ts, ns);
+ ns >>= gtod->shift;
+ } while (unlikely(gtod_read_retry(gtod, seq)));
+
+ ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
+ ts->tv_nsec = ns;
return mode;
}
-notrace static int do_realtime_coarse(struct timespec *ts)
+notrace static void do_realtime_coarse(struct timespec *ts)
{
unsigned long seq;
do {
- seq = raw_read_seqcount_begin(&gtod->seq);
- ts->tv_sec = gtod->wall_time_coarse.tv_sec;
- ts->tv_nsec = gtod->wall_time_coarse.tv_nsec;
- } while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
- return 0;
+ seq = gtod_read_begin(gtod);
+ ts->tv_sec = gtod->wall_time_coarse_sec;
+ ts->tv_nsec = gtod->wall_time_coarse_nsec;
+ } while (unlikely(gtod_read_retry(gtod, seq)));
}
-notrace static int do_monotonic_coarse(struct timespec *ts)
+notrace static void do_monotonic_coarse(struct timespec *ts)
{
unsigned long seq;
do {
- seq = raw_read_seqcount_begin(&gtod->seq);
- ts->tv_sec = gtod->monotonic_time_coarse.tv_sec;
- ts->tv_nsec = gtod->monotonic_time_coarse.tv_nsec;
- } while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
-
- return 0;
+ seq = gtod_read_begin(gtod);
+ ts->tv_sec = gtod->monotonic_time_coarse_sec;
+ ts->tv_nsec = gtod->monotonic_time_coarse_nsec;
+ } while (unlikely(gtod_read_retry(gtod, seq)));
}
notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
{
- int ret = VCLOCK_NONE;
-
switch (clock) {
case CLOCK_REALTIME:
- ret = do_realtime(ts);
+ if (do_realtime(ts) == VCLOCK_NONE)
+ goto fallback;
break;
case CLOCK_MONOTONIC:
- ret = do_monotonic(ts);
+ if (do_monotonic(ts) == VCLOCK_NONE)
+ goto fallback;
break;
case CLOCK_REALTIME_COARSE:
- return do_realtime_coarse(ts);
+ do_realtime_coarse(ts);
+ break;
case CLOCK_MONOTONIC_COARSE:
- return do_monotonic_coarse(ts);
+ do_monotonic_coarse(ts);
+ break;
+ default:
+ goto fallback;
}
- if (ret == VCLOCK_NONE)
- return vdso_fallback_gettime(clock, ts);
return 0;
+fallback:
+ return vdso_fallback_gettime(clock, ts);
}
int clock_gettime(clockid_t, struct timespec *)
__attribute__((weak, alias("__vdso_clock_gettime")));
notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
{
- long ret = VCLOCK_NONE;
-
if (likely(tv != NULL)) {
- BUILD_BUG_ON(offsetof(struct timeval, tv_usec) !=
- offsetof(struct timespec, tv_nsec) ||
- sizeof(*tv) != sizeof(struct timespec));
- ret = do_realtime((struct timespec *)tv);
+ if (unlikely(do_realtime((struct timespec *)tv) == VCLOCK_NONE))
+ return vdso_fallback_gtod(tv, tz);
tv->tv_usec /= 1000;
}
if (unlikely(tz != NULL)) {
- /* Avoid memcpy. Some old compilers fail to inline it */
- tz->tz_minuteswest = gtod->sys_tz.tz_minuteswest;
- tz->tz_dsttime = gtod->sys_tz.tz_dsttime;
+ tz->tz_minuteswest = gtod->tz_minuteswest;
+ tz->tz_dsttime = gtod->tz_dsttime;
}
- if (ret == VCLOCK_NONE)
- return vdso_fallback_gtod(tv, tz);
return 0;
}
int gettimeofday(struct timeval *, struct timezone *)
@@ -287,8 +355,8 @@ int gettimeofday(struct timeval *, struct timezone *)
*/
notrace time_t __vdso_time(time_t *t)
{
- /* This is atomic on x86_64 so we don't need any locks. */
- time_t result = ACCESS_ONCE(VVAR(vsyscall_gtod_data).wall_time_sec);
+ /* This is atomic on x86 so we don't need any locks. */
+ time_t result = ACCESS_ONCE(gtod->wall_time_sec);
if (t)
*t = result;
diff --git a/arch/x86/vdso/vdso-layout.lds.S b/arch/x86/vdso/vdso-layout.lds.S
index 634a2cf62046..2e263f367b13 100644
--- a/arch/x86/vdso/vdso-layout.lds.S
+++ b/arch/x86/vdso/vdso-layout.lds.S
@@ -6,7 +6,25 @@
SECTIONS
{
- . = VDSO_PRELINK + SIZEOF_HEADERS;
+#ifdef BUILD_VDSO32
+#include <asm/vdso32.h>
+
+ .hpet_sect : {
+ hpet_page = . - VDSO_OFFSET(VDSO_HPET_PAGE);
+ } :text :hpet_sect
+
+ .vvar_sect : {
+ vvar = . - VDSO_OFFSET(VDSO_VVAR_PAGE);
+
+ /* Place all vvars at the offsets in asm/vvar.h. */
+#define EMIT_VVAR(name, offset) vvar_ ## name = vvar + offset;
+#define __VVAR_KERNEL_LDS
+#include <asm/vvar.h>
+#undef __VVAR_KERNEL_LDS
+#undef EMIT_VVAR
+ } :text :vvar_sect
+#endif
+ . = SIZEOF_HEADERS;
.hash : { *(.hash) } :text
.gnu.hash : { *(.gnu.hash) }
@@ -44,6 +62,11 @@ SECTIONS
. = ALIGN(0x100);
.text : { *(.text*) } :text =0x90909090
+
+ /DISCARD/ : {
+ *(.discard)
+ *(.discard.*)
+ }
}
/*
@@ -61,4 +84,8 @@ PHDRS
dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
note PT_NOTE FLAGS(4); /* PF_R */
eh_frame_hdr PT_GNU_EH_FRAME;
+#ifdef BUILD_VDSO32
+ vvar_sect PT_NULL FLAGS(4); /* PF_R */
+ hpet_sect PT_NULL FLAGS(4); /* PF_R */
+#endif
}
diff --git a/arch/x86/vdso/vdso.S b/arch/x86/vdso/vdso.S
index 1e13eb8c9656..be3f23b09af5 100644
--- a/arch/x86/vdso/vdso.S
+++ b/arch/x86/vdso/vdso.S
@@ -1,21 +1,3 @@
-#include <asm/page_types.h>
-#include <linux/linkage.h>
+#include <asm/vdso.h>
-__PAGE_ALIGNED_DATA
-
- .globl vdso_start, vdso_end
- .align PAGE_SIZE
-vdso_start:
- .incbin "arch/x86/vdso/vdso.so"
-vdso_end:
- .align PAGE_SIZE /* extra data here leaks to userspace. */
-
-.previous
-
- .globl vdso_pages
- .bss
- .align 8
- .type vdso_pages, @object
-vdso_pages:
- .zero (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE * 8
- .size vdso_pages, .-vdso_pages
+DEFINE_VDSO_IMAGE(vdso, "arch/x86/vdso/vdso.so")
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index d6bfb876cfb0..00348980a3a6 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/vdso/vdso32-setup.c
@@ -16,6 +16,7 @@
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <asm/cpufeature.h>
#include <asm/msr.h>
@@ -25,17 +26,14 @@
#include <asm/tlbflush.h>
#include <asm/vdso.h>
#include <asm/proto.h>
-
-enum {
- VDSO_DISABLED = 0,
- VDSO_ENABLED = 1,
- VDSO_COMPAT = 2,
-};
+#include <asm/fixmap.h>
+#include <asm/hpet.h>
+#include <asm/vvar.h>
#ifdef CONFIG_COMPAT_VDSO
-#define VDSO_DEFAULT VDSO_COMPAT
+#define VDSO_DEFAULT 0
#else
-#define VDSO_DEFAULT VDSO_ENABLED
+#define VDSO_DEFAULT 1
#endif
#ifdef CONFIG_X86_64
@@ -44,13 +42,6 @@ enum {
#endif
/*
- * This is the difference between the prelinked addresses in the vDSO images
- * and the VDSO_HIGH_BASE address where CONFIG_COMPAT_VDSO places the vDSO
- * in the user address space.
- */
-#define VDSO_ADDR_ADJUST (VDSO_HIGH_BASE - (unsigned long)VDSO32_PRELINK)
-
-/*
* Should the kernel map a VDSO page into processes and pass its
* address down to glibc upon exec()?
*/
@@ -60,6 +51,9 @@ static int __init vdso_setup(char *s)
{
vdso_enabled = simple_strtoul(s, NULL, 0);
+ if (vdso_enabled > 1)
+ pr_warn("vdso32 values other than 0 and 1 are no longer allowed; vdso disabled\n");
+
return 1;
}
@@ -76,124 +70,8 @@ __setup_param("vdso=", vdso32_setup, vdso_setup, 0);
EXPORT_SYMBOL_GPL(vdso_enabled);
#endif
-static __init void reloc_symtab(Elf32_Ehdr *ehdr,
- unsigned offset, unsigned size)
-{
- Elf32_Sym *sym = (void *)ehdr + offset;
- unsigned nsym = size / sizeof(*sym);
- unsigned i;
-
- for(i = 0; i < nsym; i++, sym++) {
- if (sym->st_shndx == SHN_UNDEF ||
- sym->st_shndx == SHN_ABS)
- continue; /* skip */
-
- if (sym->st_shndx > SHN_LORESERVE) {
- printk(KERN_INFO "VDSO: unexpected st_shndx %x\n",
- sym->st_shndx);
- continue;
- }
-
- switch(ELF_ST_TYPE(sym->st_info)) {
- case STT_OBJECT:
- case STT_FUNC:
- case STT_SECTION:
- case STT_FILE:
- sym->st_value += VDSO_ADDR_ADJUST;
- }
- }
-}
-
-static __init void reloc_dyn(Elf32_Ehdr *ehdr, unsigned offset)
-{
- Elf32_Dyn *dyn = (void *)ehdr + offset;
-
- for(; dyn->d_tag != DT_NULL; dyn++)
- switch(dyn->d_tag) {
- case DT_PLTGOT:
- case DT_HASH:
- case DT_STRTAB:
- case DT_SYMTAB:
- case DT_RELA:
- case DT_INIT:
- case DT_FINI:
- case DT_REL:
- case DT_DEBUG:
- case DT_JMPREL:
- case DT_VERSYM:
- case DT_VERDEF:
- case DT_VERNEED:
- case DT_ADDRRNGLO ... DT_ADDRRNGHI:
- /* definitely pointers needing relocation */
- dyn->d_un.d_ptr += VDSO_ADDR_ADJUST;
- break;
-
- case DT_ENCODING ... OLD_DT_LOOS-1:
- case DT_LOOS ... DT_HIOS-1:
- /* Tags above DT_ENCODING are pointers if
- they're even */
- if (dyn->d_tag >= DT_ENCODING &&
- (dyn->d_tag & 1) == 0)
- dyn->d_un.d_ptr += VDSO_ADDR_ADJUST;
- break;
-
- case DT_VERDEFNUM:
- case DT_VERNEEDNUM:
- case DT_FLAGS_1:
- case DT_RELACOUNT:
- case DT_RELCOUNT:
- case DT_VALRNGLO ... DT_VALRNGHI:
- /* definitely not pointers */
- break;
-
- case OLD_DT_LOOS ... DT_LOOS-1:
- case DT_HIOS ... DT_VALRNGLO-1:
- default:
- if (dyn->d_tag > DT_ENCODING)
- printk(KERN_INFO "VDSO: unexpected DT_tag %x\n",
- dyn->d_tag);
- break;
- }
-}
-
-static __init void relocate_vdso(Elf32_Ehdr *ehdr)
-{
- Elf32_Phdr *phdr;
- Elf32_Shdr *shdr;
- int i;
-
- BUG_ON(memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0 ||
- !elf_check_arch_ia32(ehdr) ||
- ehdr->e_type != ET_DYN);
-
- ehdr->e_entry += VDSO_ADDR_ADJUST;
-
- /* rebase phdrs */
- phdr = (void *)ehdr + ehdr->e_phoff;
- for (i = 0; i < ehdr->e_phnum; i++) {
- phdr[i].p_vaddr += VDSO_ADDR_ADJUST;
-
- /* relocate dynamic stuff */
- if (phdr[i].p_type == PT_DYNAMIC)
- reloc_dyn(ehdr, phdr[i].p_offset);
- }
-
- /* rebase sections */
- shdr = (void *)ehdr + ehdr->e_shoff;
- for(i = 0; i < ehdr->e_shnum; i++) {
- if (!(shdr[i].sh_flags & SHF_ALLOC))
- continue;
-
- shdr[i].sh_addr += VDSO_ADDR_ADJUST;
-
- if (shdr[i].sh_type == SHT_SYMTAB ||
- shdr[i].sh_type == SHT_DYNSYM)
- reloc_symtab(ehdr, shdr[i].sh_offset,
- shdr[i].sh_size);
- }
-}
-
-static struct page *vdso32_pages[1];
+static struct page **vdso32_pages;
+static unsigned vdso32_size;
#ifdef CONFIG_X86_64
@@ -212,12 +90,6 @@ void syscall32_cpu_init(void)
wrmsrl(MSR_CSTAR, ia32_cstar_target);
}
-#define compat_uses_vma 1
-
-static inline void map_compat_vdso(int map)
-{
-}
-
#else /* CONFIG_X86_32 */
#define vdso32_sysenter() (boot_cpu_has(X86_FEATURE_SEP))
@@ -241,64 +113,36 @@ void enable_sep_cpu(void)
put_cpu();
}
-static struct vm_area_struct gate_vma;
-
-static int __init gate_vma_init(void)
-{
- gate_vma.vm_mm = NULL;
- gate_vma.vm_start = FIXADDR_USER_START;
- gate_vma.vm_end = FIXADDR_USER_END;
- gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
- gate_vma.vm_page_prot = __P101;
-
- return 0;
-}
-
-#define compat_uses_vma 0
-
-static void map_compat_vdso(int map)
-{
- static int vdso_mapped;
-
- if (map == vdso_mapped)
- return;
-
- vdso_mapped = map;
-
- __set_fixmap(FIX_VDSO, page_to_pfn(vdso32_pages[0]) << PAGE_SHIFT,
- map ? PAGE_READONLY_EXEC : PAGE_NONE);
-
- /* flush stray tlbs */
- flush_tlb_all();
-}
-
#endif /* CONFIG_X86_64 */
int __init sysenter_setup(void)
{
- void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
- const void *vsyscall;
- size_t vsyscall_len;
-
- vdso32_pages[0] = virt_to_page(syscall_page);
-
-#ifdef CONFIG_X86_32
- gate_vma_init();
-#endif
+ char *vdso32_start, *vdso32_end;
+ int npages, i;
+#ifdef CONFIG_COMPAT
if (vdso32_syscall()) {
- vsyscall = &vdso32_syscall_start;
- vsyscall_len = &vdso32_syscall_end - &vdso32_syscall_start;
- } else if (vdso32_sysenter()){
- vsyscall = &vdso32_sysenter_start;
- vsyscall_len = &vdso32_sysenter_end - &vdso32_sysenter_start;
+ vdso32_start = vdso32_syscall_start;
+ vdso32_end = vdso32_syscall_end;
+ vdso32_pages = vdso32_syscall_pages;
+ } else
+#endif
+ if (vdso32_sysenter()) {
+ vdso32_start = vdso32_sysenter_start;
+ vdso32_end = vdso32_sysenter_end;
+ vdso32_pages = vdso32_sysenter_pages;
} else {
- vsyscall = &vdso32_int80_start;
- vsyscall_len = &vdso32_int80_end - &vdso32_int80_start;
+ vdso32_start = vdso32_int80_start;
+ vdso32_end = vdso32_int80_end;
+ vdso32_pages = vdso32_int80_pages;
}
- memcpy(syscall_page, vsyscall, vsyscall_len);
- relocate_vdso(syscall_page);
+ npages = ((vdso32_end - vdso32_start) + PAGE_SIZE - 1) / PAGE_SIZE;
+ vdso32_size = npages << PAGE_SHIFT;
+ for (i = 0; i < npages; i++)
+ vdso32_pages[i] = virt_to_page(vdso32_start + i*PAGE_SIZE);
+
+ patch_vdso32(vdso32_start, vdso32_size);
return 0;
}
@@ -309,48 +153,73 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
struct mm_struct *mm = current->mm;
unsigned long addr;
int ret = 0;
- bool compat;
+ struct vm_area_struct *vma;
#ifdef CONFIG_X86_X32_ABI
if (test_thread_flag(TIF_X32))
return x32_setup_additional_pages(bprm, uses_interp);
#endif
- if (vdso_enabled == VDSO_DISABLED)
+ if (vdso_enabled != 1) /* Other values all mean "disabled" */
return 0;
down_write(&mm->mmap_sem);
- /* Test compat mode once here, in case someone
- changes it via sysctl */
- compat = (vdso_enabled == VDSO_COMPAT);
+ addr = get_unmapped_area(NULL, 0, vdso32_size + VDSO_OFFSET(VDSO_PREV_PAGES), 0, 0);
+ if (IS_ERR_VALUE(addr)) {
+ ret = addr;
+ goto up_fail;
+ }
+
+ addr += VDSO_OFFSET(VDSO_PREV_PAGES);
- map_compat_vdso(compat);
+ current->mm->context.vdso = (void *)addr;
- if (compat)
- addr = VDSO_HIGH_BASE;
- else {
- addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
- if (IS_ERR_VALUE(addr)) {
- ret = addr;
- goto up_fail;
- }
+ /*
+ * MAYWRITE to allow gdb to COW and set breakpoints
+ */
+ ret = install_special_mapping(mm,
+ addr,
+ vdso32_size,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
+ vdso32_pages);
+
+ if (ret)
+ goto up_fail;
+
+ vma = _install_special_mapping(mm,
+ addr - VDSO_OFFSET(VDSO_PREV_PAGES),
+ VDSO_OFFSET(VDSO_PREV_PAGES),
+ VM_READ,
+ NULL);
+
+ if (IS_ERR(vma)) {
+ ret = PTR_ERR(vma);
+ goto up_fail;
}
- current->mm->context.vdso = (void *)addr;
+ ret = remap_pfn_range(vma,
+ addr - VDSO_OFFSET(VDSO_VVAR_PAGE),
+ __pa_symbol(&__vvar_page) >> PAGE_SHIFT,
+ PAGE_SIZE,
+ PAGE_READONLY);
+
+ if (ret)
+ goto up_fail;
- if (compat_uses_vma || !compat) {
- /*
- * MAYWRITE to allow gdb to COW and set breakpoints
- */
- ret = install_special_mapping(mm, addr, PAGE_SIZE,
- VM_READ|VM_EXEC|
- VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
- vdso32_pages);
+#ifdef CONFIG_HPET_TIMER
+ if (hpet_address) {
+ ret = io_remap_pfn_range(vma,
+ addr - VDSO_OFFSET(VDSO_HPET_PAGE),
+ hpet_address >> PAGE_SHIFT,
+ PAGE_SIZE,
+ pgprot_noncached(PAGE_READONLY));
if (ret)
goto up_fail;
}
+#endif
current_thread_info()->sysenter_return =
VDSO32_SYMBOL(addr, SYSENTER_RETURN);
@@ -411,20 +280,12 @@ const char *arch_vma_name(struct vm_area_struct *vma)
struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
{
- /*
- * Check to see if the corresponding task was created in compat vdso
- * mode.
- */
- if (mm && mm->context.vdso == (void *)VDSO_HIGH_BASE)
- return &gate_vma;
return NULL;
}
int in_gate_area(struct mm_struct *mm, unsigned long addr)
{
- const struct vm_area_struct *vma = get_gate_vma(mm);
-
- return vma && addr >= vma->vm_start && addr < vma->vm_end;
+ return 0;
}
int in_gate_area_no_mm(unsigned long addr)
diff --git a/arch/x86/vdso/vdso32.S b/arch/x86/vdso/vdso32.S
index 2ce5f82c333b..018bcd9f97b4 100644
--- a/arch/x86/vdso/vdso32.S
+++ b/arch/x86/vdso/vdso32.S
@@ -1,22 +1,9 @@
-#include <linux/init.h>
+#include <asm/vdso.h>
-__INITDATA
+DEFINE_VDSO_IMAGE(vdso32_int80, "arch/x86/vdso/vdso32-int80.so")
- .globl vdso32_int80_start, vdso32_int80_end
-vdso32_int80_start:
- .incbin "arch/x86/vdso/vdso32-int80.so"
-vdso32_int80_end:
-
- .globl vdso32_syscall_start, vdso32_syscall_end
-vdso32_syscall_start:
#ifdef CONFIG_COMPAT
- .incbin "arch/x86/vdso/vdso32-syscall.so"
+DEFINE_VDSO_IMAGE(vdso32_syscall, "arch/x86/vdso/vdso32-syscall.so")
#endif
-vdso32_syscall_end:
-
- .globl vdso32_sysenter_start, vdso32_sysenter_end
-vdso32_sysenter_start:
- .incbin "arch/x86/vdso/vdso32-sysenter.so"
-vdso32_sysenter_end:
-__FINIT
+DEFINE_VDSO_IMAGE(vdso32_sysenter, "arch/x86/vdso/vdso32-sysenter.so")
diff --git a/arch/x86/vdso/vdso32/vclock_gettime.c b/arch/x86/vdso/vdso32/vclock_gettime.c
new file mode 100644
index 000000000000..175cc72c0f68
--- /dev/null
+++ b/arch/x86/vdso/vdso32/vclock_gettime.c
@@ -0,0 +1,30 @@
+#define BUILD_VDSO32
+
+#ifndef CONFIG_CC_OPTIMIZE_FOR_SIZE
+#undef CONFIG_OPTIMIZE_INLINING
+#endif
+
+#undef CONFIG_X86_PPRO_FENCE
+
+#ifdef CONFIG_X86_64
+
+/*
+ * in case of a 32 bit VDSO for a 64 bit kernel fake a 32 bit kernel
+ * configuration
+ */
+#undef CONFIG_64BIT
+#undef CONFIG_X86_64
+#undef CONFIG_ILLEGAL_POINTER_VALUE
+#undef CONFIG_SPARSEMEM_VMEMMAP
+#undef CONFIG_NR_CPUS
+
+#define CONFIG_X86_32 1
+#define CONFIG_PAGE_OFFSET 0
+#define CONFIG_ILLEGAL_POINTER_VALUE 0
+#define CONFIG_NR_CPUS 1
+
+#define BUILD_VDSO32_64
+
+#endif
+
+#include "../vclock_gettime.c"
diff --git a/arch/x86/vdso/vdso32/vdso32.lds.S b/arch/x86/vdso/vdso32/vdso32.lds.S
index 976124bb5f92..aadb8b9994cd 100644
--- a/arch/x86/vdso/vdso32/vdso32.lds.S
+++ b/arch/x86/vdso/vdso32/vdso32.lds.S
@@ -8,7 +8,11 @@
* values visible using the asm-x86/vdso.h macros from the kernel proper.
*/
+#include <asm/page.h>
+
+#define BUILD_VDSO32
#define VDSO_PRELINK 0
+
#include "../vdso-layout.lds.S"
/* The ELF entry point can be used to set the AT_SYSINFO value. */
@@ -19,6 +23,13 @@ ENTRY(__kernel_vsyscall);
*/
VERSION
{
+ LINUX_2.6 {
+ global:
+ __vdso_clock_gettime;
+ __vdso_gettimeofday;
+ __vdso_time;
+ };
+
LINUX_2.5 {
global:
__kernel_vsyscall;
@@ -31,7 +42,9 @@ VERSION
/*
* Symbols we define here called VDSO* get their values into vdso32-syms.h.
*/
-VDSO32_PRELINK = VDSO_PRELINK;
VDSO32_vsyscall = __kernel_vsyscall;
VDSO32_sigreturn = __kernel_sigreturn;
VDSO32_rt_sigreturn = __kernel_rt_sigreturn;
+VDSO32_clock_gettime = clock_gettime;
+VDSO32_gettimeofday = gettimeofday;
+VDSO32_time = time;
diff --git a/arch/x86/vdso/vdsox32.S b/arch/x86/vdso/vdsox32.S
index 295f1c7543d8..f4aa34e7f370 100644
--- a/arch/x86/vdso/vdsox32.S
+++ b/arch/x86/vdso/vdsox32.S
@@ -1,21 +1,3 @@
-#include <asm/page_types.h>
-#include <linux/linkage.h>
+#include <asm/vdso.h>
-__PAGE_ALIGNED_DATA
-
- .globl vdsox32_start, vdsox32_end
- .align PAGE_SIZE
-vdsox32_start:
- .incbin "arch/x86/vdso/vdsox32.so"
-vdsox32_end:
- .align PAGE_SIZE /* extra data here leaks to userspace. */
-
-.previous
-
- .globl vdsox32_pages
- .bss
- .align 8
- .type vdsox32_pages, @object
-vdsox32_pages:
- .zero (vdsox32_end - vdsox32_start + PAGE_SIZE - 1) / PAGE_SIZE * 8
- .size vdsox32_pages, .-vdsox32_pages
+DEFINE_VDSO_IMAGE(vdsox32, "arch/x86/vdso/vdsox32.so")
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
index 431e87544411..1ad102613127 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/vdso/vma.c
@@ -16,20 +16,22 @@
#include <asm/vdso.h>
#include <asm/page.h>
+#if defined(CONFIG_X86_64)
unsigned int __read_mostly vdso_enabled = 1;
-extern char vdso_start[], vdso_end[];
+DECLARE_VDSO_IMAGE(vdso);
extern unsigned short vdso_sync_cpuid;
-
-extern struct page *vdso_pages[];
static unsigned vdso_size;
#ifdef CONFIG_X86_X32_ABI
-extern char vdsox32_start[], vdsox32_end[];
-extern struct page *vdsox32_pages[];
+DECLARE_VDSO_IMAGE(vdsox32);
static unsigned vdsox32_size;
+#endif
+#endif
-static void __init patch_vdsox32(void *vdso, size_t len)
+#if defined(CONFIG_X86_32) || defined(CONFIG_X86_X32_ABI) || \
+ defined(CONFIG_COMPAT)
+void __init patch_vdso32(void *vdso, size_t len)
{
Elf32_Ehdr *hdr = vdso;
Elf32_Shdr *sechdrs, *alt_sec = 0;
@@ -52,7 +54,7 @@ static void __init patch_vdsox32(void *vdso, size_t len)
}
/* If we get here, it's probably a bug. */
- pr_warning("patch_vdsox32: .altinstructions not found\n");
+ pr_warning("patch_vdso32: .altinstructions not found\n");
return; /* nothing to patch */
found:
@@ -61,6 +63,7 @@ found:
}
#endif
+#if defined(CONFIG_X86_64)
static void __init patch_vdso64(void *vdso, size_t len)
{
Elf64_Ehdr *hdr = vdso;
@@ -104,7 +107,7 @@ static int __init init_vdso(void)
vdso_pages[i] = virt_to_page(vdso_start + i*PAGE_SIZE);
#ifdef CONFIG_X86_X32_ABI
- patch_vdsox32(vdsox32_start, vdsox32_end - vdsox32_start);
+ patch_vdso32(vdsox32_start, vdsox32_end - vdsox32_start);
npages = (vdsox32_end - vdsox32_start + PAGE_SIZE - 1) / PAGE_SIZE;
vdsox32_size = npages << PAGE_SHIFT;
for (i = 0; i < npages; i++)
@@ -204,3 +207,4 @@ static __init int vdso_setup(char *s)
return 0;
}
__setup("vdso=", vdso_setup);
+#endif
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
index 01b90261fa38..9c50cc2e403b 100644
--- a/arch/x86/xen/Kconfig
+++ b/arch/x86/xen/Kconfig
@@ -7,7 +7,7 @@ config XEN
depends on PARAVIRT
select PARAVIRT_CLOCK
select XEN_HAVE_PVMMU
- depends on X86_64 || (X86_32 && X86_PAE && !X86_VISWS)
+ depends on X86_64 || (X86_32 && X86_PAE)
depends on X86_TSC
help
This is the Linux Xen port. Enabling this will allow the
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 256282e7888b..86e02eabb640 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -365,7 +365,7 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
/* Assume pteval_t is equivalent to all the other *val_t types. */
static pteval_t pte_mfn_to_pfn(pteval_t val)
{
- if (pteval_present(val)) {
+ if (val & _PAGE_PRESENT) {
unsigned long mfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
unsigned long pfn = mfn_to_pfn(mfn);
@@ -381,7 +381,7 @@ static pteval_t pte_mfn_to_pfn(pteval_t val)
static pteval_t pte_pfn_to_mfn(pteval_t val)
{
- if (pteval_present(val)) {
+ if (val & _PAGE_PRESENT) {
unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
pteval_t flags = val & PTE_FLAGS_MASK;
unsigned long mfn;
@@ -2058,7 +2058,6 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
case FIX_RO_IDT:
#ifdef CONFIG_X86_32
case FIX_WP_TEST:
- case FIX_VDSO:
# ifdef CONFIG_HIGHMEM
case FIX_KMAP_BEGIN ... FIX_KMAP_END:
# endif
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
index 581521c843a5..4d3acc34a998 100644
--- a/arch/x86/xen/spinlock.c
+++ b/arch/x86/xen/spinlock.c
@@ -183,7 +183,7 @@ __visible void xen_lock_spinning(struct arch_spinlock *lock, __ticket_t want)
local_irq_save(flags);
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ kstat_incr_irq_this_cpu(irq);
out:
cpumask_clear_cpu(cpu, &waiting_cpus);
w->lock = NULL;
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index ba56e11cbf77..c87ae7c6e5f9 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -20,6 +20,7 @@ config XTENSA
select HAVE_FUNCTION_TRACER
select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_PERF_EVENTS
+ select COMMON_CLK
help
Xtensa processors are 32-bit RISC machines designed by Tensilica
primarily for embedded systems. These processors are both
@@ -80,7 +81,6 @@ choice
config XTENSA_VARIANT_FSF
bool "fsf - default (not generic) configuration"
select MMU
- select HAVE_XTENSA_GPIO32
config XTENSA_VARIANT_DC232B
bool "dc232b - Diamond 232L Standard Core Rev.B (LE)"
@@ -135,7 +135,6 @@ config HAVE_SMP
config SMP
bool "Enable Symmetric multi-processing support"
depends on HAVE_SMP
- select USE_GENERIC_SMP_HELPERS
select GENERIC_SMP_IDLE_THREAD
help
Enabled SMP Software; allows more than one CPU/CORE
diff --git a/arch/xtensa/boot/dts/xtfpga.dtsi b/arch/xtensa/boot/dts/xtfpga.dtsi
index 46b4f5eab421..e7370b11348e 100644
--- a/arch/xtensa/boot/dts/xtfpga.dtsi
+++ b/arch/xtensa/boot/dts/xtfpga.dtsi
@@ -35,6 +35,13 @@
interrupt-controller;
};
+ clocks {
+ osc: main-oscillator {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ };
+ };
+
serial0: serial@fd050020 {
device_type = "serial";
compatible = "ns16550a";
@@ -42,9 +49,7 @@
reg = <0xfd050020 0x20>;
reg-shift = <2>;
interrupts = <0 1>; /* external irq 0 */
- /* Filled in by platform_setup from FPGA register
- * clock-frequency = <100000000>;
- */
+ clocks = <&osc>;
};
enet0: ethoc@fd030000 {
@@ -52,5 +57,6 @@
reg = <0xfd030000 0x4000 0xfd800000 0x4000>;
interrupts = <1 1>; /* external irq 1 */
local-mac-address = [00 50 c2 13 6f 00];
+ clocks = <&osc>;
};
};
diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild
index 0a337e4a8370..c3d20ba6eb86 100644
--- a/arch/xtensa/include/asm/Kbuild
+++ b/arch/xtensa/include/asm/Kbuild
@@ -9,6 +9,7 @@ generic-y += errno.h
generic-y += exec.h
generic-y += fcntl.h
generic-y += hardirq.h
+generic-y += hash.h
generic-y += ioctl.h
generic-y += irq_regs.h
generic-y += kdebug.h
@@ -17,7 +18,9 @@ generic-y += kvm_para.h
generic-y += linkage.h
generic-y += local.h
generic-y += local64.h
+generic-y += mcs_spinlock.h
generic-y += percpu.h
+generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sections.h
@@ -27,5 +30,3 @@ generic-y += termios.h
generic-y += topology.h
generic-y += trace_clock.h
generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h
index 2a042d430c25..74944207167e 100644
--- a/arch/xtensa/include/asm/io.h
+++ b/arch/xtensa/include/asm/io.h
@@ -25,7 +25,7 @@
#ifdef CONFIG_MMU
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && CONFIG_OF
+#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF)
extern unsigned long xtensa_kio_paddr;
static inline unsigned long xtensa_get_kio_paddr(void)
diff --git a/arch/xtensa/include/asm/traps.h b/arch/xtensa/include/asm/traps.h
index 8c194f6af45e..677bfcf4ee5d 100644
--- a/arch/xtensa/include/asm/traps.h
+++ b/arch/xtensa/include/asm/traps.h
@@ -23,25 +23,37 @@ void secondary_trap_init(void);
static inline void spill_registers(void)
{
-
+#if XCHAL_NUM_AREGS > 16
__asm__ __volatile__ (
- "movi a14, "__stringify((1 << PS_EXCM_BIT) | LOCKLEVEL)"\n\t"
- "mov a12, a0\n\t"
- "rsr a13, sar\n\t"
- "xsr a14, ps\n\t"
- "movi a0, _spill_registers\n\t"
- "rsync\n\t"
- "callx0 a0\n\t"
- "mov a0, a12\n\t"
- "wsr a13, sar\n\t"
- "wsr a14, ps\n\t"
- : :
-#if defined(CONFIG_FRAME_POINTER)
- : "a2", "a3", "a4", "a11", "a12", "a13", "a14", "a15",
+ " call12 1f\n"
+ " _j 2f\n"
+ " retw\n"
+ " .align 4\n"
+ "1:\n"
+ " _entry a1, 48\n"
+ " addi a12, a0, 3\n"
+#if XCHAL_NUM_AREGS > 32
+ " .rept (" __stringify(XCHAL_NUM_AREGS) " - 32) / 12\n"
+ " _entry a1, 48\n"
+ " mov a12, a0\n"
+ " .endr\n"
+#endif
+ " _entry a1, 48\n"
+#if XCHAL_NUM_AREGS % 12 == 0
+ " mov a8, a8\n"
+#elif XCHAL_NUM_AREGS % 12 == 4
+ " mov a12, a12\n"
+#elif XCHAL_NUM_AREGS % 12 == 8
+ " mov a4, a4\n"
+#endif
+ " retw\n"
+ "2:\n"
+ : : : "a12", "a13", "memory");
#else
- : "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15",
+ __asm__ __volatile__ (
+ " mov a12, a12\n"
+ : : : "memory");
#endif
- "memory");
}
#endif /* _XTENSA_TRAPS_H */
diff --git a/arch/xtensa/include/asm/vectors.h b/arch/xtensa/include/asm/vectors.h
index 5791b45d5a5d..f74ddfbb92ef 100644
--- a/arch/xtensa/include/asm/vectors.h
+++ b/arch/xtensa/include/asm/vectors.h
@@ -25,7 +25,7 @@
#define XCHAL_KIO_DEFAULT_PADDR 0xf0000000
#define XCHAL_KIO_SIZE 0x10000000
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && CONFIG_OF
+#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF)
#define XCHAL_KIO_PADDR xtensa_get_kio_paddr()
#else
#define XCHAL_KIO_PADDR XCHAL_KIO_DEFAULT_PADDR
diff --git a/arch/xtensa/include/uapi/asm/unistd.h b/arch/xtensa/include/uapi/asm/unistd.h
index 51940fec6990..b9395529f02d 100644
--- a/arch/xtensa/include/uapi/asm/unistd.h
+++ b/arch/xtensa/include/uapi/asm/unistd.h
@@ -734,7 +734,12 @@ __SYSCALL(332, sys_finit_module, 3)
#define __NR_accept4 333
__SYSCALL(333, sys_accept4, 4)
-#define __NR_syscall_count 334
+#define __NR_sched_setattr 334
+__SYSCALL(334, sys_sched_setattr, 2)
+#define __NR_sched_getattr 335
+__SYSCALL(335, sys_sched_getattr, 3)
+
+#define __NR_syscall_count 336
/*
* sysxtensa syscall handler
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 21dbe6bdb8ed..ef7f4990722b 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -1081,196 +1081,53 @@ ENTRY(fast_syscall_spill_registers)
rsr a0, sar
s32i a3, a2, PT_AREG3
- s32i a4, a2, PT_AREG4
- s32i a0, a2, PT_AREG5 # store SAR to PT_AREG5
+ s32i a0, a2, PT_SAR
- /* The spill routine might clobber a7, a11, and a15. */
+ /* The spill routine might clobber a4, a7, a8, a11, a12, and a15. */
+ s32i a4, a2, PT_AREG4
s32i a7, a2, PT_AREG7
+ s32i a8, a2, PT_AREG8
s32i a11, a2, PT_AREG11
+ s32i a12, a2, PT_AREG12
s32i a15, a2, PT_AREG15
- call0 _spill_registers # destroys a3, a4, and SAR
-
- /* Advance PC, restore registers and SAR, and return from exception. */
-
- l32i a3, a2, PT_AREG5
- l32i a4, a2, PT_AREG4
- l32i a0, a2, PT_AREG0
- wsr a3, sar
- l32i a3, a2, PT_AREG3
-
- /* Restore clobbered registers. */
-
- l32i a7, a2, PT_AREG7
- l32i a11, a2, PT_AREG11
- l32i a15, a2, PT_AREG15
-
- movi a2, 0
- rfe
-
-ENDPROC(fast_syscall_spill_registers)
-
-/* Fixup handler.
- *
- * We get here if the spill routine causes an exception, e.g. tlb miss.
- * We basically restore WINDOWBASE and WINDOWSTART to the condition when
- * we entered the spill routine and jump to the user exception handler.
- *
- * a0: value of depc, original value in depc
- * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
- * a3: exctable, original value in excsave1
- */
-
-ENTRY(fast_syscall_spill_registers_fixup)
-
- rsr a2, windowbase # get current windowbase (a2 is saved)
- xsr a0, depc # restore depc and a0
- ssl a2 # set shift (32 - WB)
-
- /* We need to make sure the current registers (a0-a3) are preserved.
- * To do this, we simply set the bit for the current window frame
- * in WS, so that the exception handlers save them to the task stack.
- */
-
- xsr a3, excsave1 # get spill-mask
- slli a3, a3, 1 # shift left by one
-
- slli a2, a3, 32-WSBITS
- src a2, a3, a2 # a2 = xxwww1yyxxxwww1yy......
- wsr a2, windowstart # set corrected windowstart
-
- srli a3, a3, 1
- rsr a2, excsave1
- l32i a2, a2, EXC_TABLE_DOUBLE_SAVE # restore a2
- xsr a2, excsave1
- s32i a3, a2, EXC_TABLE_DOUBLE_SAVE # save a3
- l32i a3, a2, EXC_TABLE_PARAM # original WB (in user task)
- xsr a2, excsave1
-
- /* Return to the original (user task) WINDOWBASE.
- * We leave the following frame behind:
- * a0, a1, a2 same
- * a3: trashed (saved in EXC_TABLE_DOUBLE_SAVE)
- * depc: depc (we have to return to that address)
- * excsave_1: exctable
- */
-
- wsr a3, windowbase
- rsync
-
- /* We are now in the original frame when we entered _spill_registers:
- * a0: return address
- * a1: used, stack pointer
- * a2: kernel stack pointer
- * a3: available
- * depc: exception address
- * excsave: exctable
- * Note: This frame might be the same as above.
- */
-
- /* Setup stack pointer. */
-
- addi a2, a2, -PT_USER_SIZE
- s32i a0, a2, PT_AREG0
-
- /* Make sure we return to this fixup handler. */
-
- movi a3, fast_syscall_spill_registers_fixup_return
- s32i a3, a2, PT_DEPC # setup depc
-
- /* Jump to the exception handler. */
-
- rsr a3, excsave1
- rsr a0, exccause
- addx4 a0, a0, a3 # find entry in table
- l32i a0, a0, EXC_TABLE_FAST_USER # load handler
- l32i a3, a3, EXC_TABLE_DOUBLE_SAVE
- jx a0
-
-ENDPROC(fast_syscall_spill_registers_fixup)
-
-ENTRY(fast_syscall_spill_registers_fixup_return)
-
- /* When we return here, all registers have been restored (a2: DEPC) */
-
- wsr a2, depc # exception address
-
- /* Restore fixup handler. */
-
- rsr a2, excsave1
- s32i a3, a2, EXC_TABLE_DOUBLE_SAVE
- movi a3, fast_syscall_spill_registers_fixup
- s32i a3, a2, EXC_TABLE_FIXUP
- rsr a3, windowbase
- s32i a3, a2, EXC_TABLE_PARAM
- l32i a2, a2, EXC_TABLE_KSTK
-
- /* Load WB at the time the exception occurred. */
-
- rsr a3, sar # WB is still in SAR
- neg a3, a3
- wsr a3, windowbase
- rsync
-
- rsr a3, excsave1
- l32i a3, a3, EXC_TABLE_DOUBLE_SAVE
-
- rfde
-
-ENDPROC(fast_syscall_spill_registers_fixup_return)
-
-/*
- * spill all registers.
- *
- * This is not a real function. The following conditions must be met:
- *
- * - must be called with call0.
- * - uses a3, a4 and SAR.
- * - the last 'valid' register of each frame are clobbered.
- * - the caller must have registered a fixup handler
- * (or be inside a critical section)
- * - PS_EXCM must be set (PS_WOE cleared?)
- */
-
-ENTRY(_spill_registers)
-
/*
* Rotate ws so that the current windowbase is at bit 0.
* Assume ws = xxxwww1yy (www1 current window frame).
* Rotate ws right so that a4 = yyxxxwww1.
*/
- rsr a4, windowbase
+ rsr a0, windowbase
rsr a3, windowstart # a3 = xxxwww1yy
- ssr a4 # holds WB
- slli a4, a3, WSBITS
- or a3, a3, a4 # a3 = xxxwww1yyxxxwww1yy
+ ssr a0 # holds WB
+ slli a0, a3, WSBITS
+ or a3, a3, a0 # a3 = xxxwww1yyxxxwww1yy
srl a3, a3 # a3 = 00xxxwww1yyxxxwww1
/* We are done if there are no more than the current register frame. */
extui a3, a3, 1, WSBITS-1 # a3 = 0yyxxxwww
- movi a4, (1 << (WSBITS-1))
+ movi a0, (1 << (WSBITS-1))
_beqz a3, .Lnospill # only one active frame? jump
/* We want 1 at the top, so that we return to the current windowbase */
- or a3, a3, a4 # 1yyxxxwww
+ or a3, a3, a0 # 1yyxxxwww
/* Skip empty frames - get 'oldest' WINDOWSTART-bit. */
wsr a3, windowstart # save shifted windowstart
- neg a4, a3
- and a3, a4, a3 # first bit set from right: 000010000
+ neg a0, a3
+ and a3, a0, a3 # first bit set from right: 000010000
- ffs_ws a4, a3 # a4: shifts to skip empty frames
+ ffs_ws a0, a3 # a0: shifts to skip empty frames
movi a3, WSBITS
- sub a4, a3, a4 # WSBITS-a4:number of 0-bits from right
- ssr a4 # save in SAR for later.
+ sub a0, a3, a0 # WSBITS-a0:number of 0-bits from right
+ ssr a0 # save in SAR for later.
rsr a3, windowbase
- add a3, a3, a4
+ add a3, a3, a0
wsr a3, windowbase
rsync
@@ -1285,22 +1142,6 @@ ENTRY(_spill_registers)
* we have to save 4,8. or 12 registers.
*/
- _bbsi.l a3, 1, .Lc4
- _bbsi.l a3, 2, .Lc8
-
- /* Special case: we have a call12-frame starting at a4. */
-
- _bbci.l a3, 3, .Lc12 # bit 3 shouldn't be zero! (Jump to Lc12 first)
-
- s32e a4, a1, -16 # a1 is valid with an empty spill area
- l32e a4, a5, -12
- s32e a8, a4, -48
- mov a8, a4
- l32e a4, a1, -16
- j .Lc12c
-
-.Lnospill:
- ret
.Lloop: _bbsi.l a3, 1, .Lc4
_bbci.l a3, 2, .Lc12
@@ -1314,20 +1155,10 @@ ENTRY(_spill_registers)
s32e a9, a4, -28
s32e a10, a4, -24
s32e a11, a4, -20
-
srli a11, a3, 2 # shift windowbase by 2
rotw 2
_bnei a3, 1, .Lloop
-
-.Lexit: /* Done. Do the final rotation, set WS, and return. */
-
- rotw 1
- rsr a3, windowbase
- ssl a3
- movi a3, 1
- sll a3, a3
- wsr a3, windowstart
- ret
+ j .Lexit
.Lc4: s32e a4, a9, -16
s32e a5, a9, -12
@@ -1343,11 +1174,11 @@ ENTRY(_spill_registers)
/* 12-register frame (call12) */
- l32e a2, a5, -12
- s32e a8, a2, -48
- mov a8, a2
+ l32e a0, a5, -12
+ s32e a8, a0, -48
+ mov a8, a0
-.Lc12c: s32e a9, a8, -44
+ s32e a9, a8, -44
s32e a10, a8, -40
s32e a11, a8, -36
s32e a12, a8, -32
@@ -1367,30 +1198,54 @@ ENTRY(_spill_registers)
*/
rotw 1
- mov a5, a13
+ mov a4, a13
rotw -1
- s32e a4, a9, -16
- s32e a5, a9, -12
- s32e a6, a9, -8
- s32e a7, a9, -4
+ s32e a4, a8, -16
+ s32e a5, a8, -12
+ s32e a6, a8, -8
+ s32e a7, a8, -4
rotw 3
_beqi a3, 1, .Lexit
j .Lloop
-.Linvalid_mask:
+.Lexit:
- /* We get here because of an unrecoverable error in the window
- * registers. If we are in user space, we kill the application,
- * however, this condition is unrecoverable in kernel space.
- */
+ /* Done. Do the final rotation and set WS */
+
+ rotw 1
+ rsr a3, windowbase
+ ssl a3
+ movi a3, 1
+ sll a3, a3
+ wsr a3, windowstart
+.Lnospill:
+
+ /* Advance PC, restore registers and SAR, and return from exception. */
+
+ l32i a3, a2, PT_SAR
+ l32i a0, a2, PT_AREG0
+ wsr a3, sar
+ l32i a3, a2, PT_AREG3
- rsr a0, ps
- _bbci.l a0, PS_UM_BIT, 1f
+ /* Restore clobbered registers. */
- /* User space: Setup a dummy frame and kill application.
+ l32i a4, a2, PT_AREG4
+ l32i a7, a2, PT_AREG7
+ l32i a8, a2, PT_AREG8
+ l32i a11, a2, PT_AREG11
+ l32i a12, a2, PT_AREG12
+ l32i a15, a2, PT_AREG15
+
+ movi a2, 0
+ rfe
+
+.Linvalid_mask:
+
+ /* We get here because of an unrecoverable error in the window
+ * registers, so set up a dummy frame and kill the user application.
* Note: We assume EXC_TABLE_KSTK contains a valid stack pointer.
*/
@@ -1414,14 +1269,136 @@ ENTRY(_spill_registers)
movi a4, do_exit
callx4 a4
-1: /* Kernel space: PANIC! */
+ /* shouldn't return, so panic */
wsr a0, excsave1
movi a0, unrecoverable_exception
callx0 a0 # should not return
1: j 1b
-ENDPROC(_spill_registers)
+
+ENDPROC(fast_syscall_spill_registers)
+
+/* Fixup handler.
+ *
+ * We get here if the spill routine causes an exception, e.g. tlb miss.
+ * We basically restore WINDOWBASE and WINDOWSTART to the condition when
+ * we entered the spill routine and jump to the user exception handler.
+ *
+ * Note that we only need to restore the bits in windowstart that have not
+ * been spilled yet by the _spill_register routine. Luckily, a3 contains a
+ * rotated windowstart with only those bits set for frames that haven't been
+ * spilled yet. Because a3 is rotated such that bit 0 represents the register
+ * frame for the current windowbase - 1, we need to rotate a3 left by the
+ * value of the current windowbase + 1 and move it to windowstart.
+ *
+ * a0: value of depc, original value in depc
+ * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
+ * a3: exctable, original value in excsave1
+ */
+
+ENTRY(fast_syscall_spill_registers_fixup)
+
+ rsr a2, windowbase # get current windowbase (a2 is saved)
+ xsr a0, depc # restore depc and a0
+ ssl a2 # set shift (32 - WB)
+
+ /* We need to make sure the current registers (a0-a3) are preserved.
+ * To do this, we simply set the bit for the current window frame
+ * in WS, so that the exception handlers save them to the task stack.
+ *
+ * Note: we use a3 to set the windowbase, so we take a special care
+ * of it, saving it in the original _spill_registers frame across
+ * the exception handler call.
+ */
+
+ xsr a3, excsave1 # get spill-mask
+ slli a3, a3, 1 # shift left by one
+ addi a3, a3, 1 # set the bit for the current window frame
+
+ slli a2, a3, 32-WSBITS
+ src a2, a3, a2 # a2 = xxwww1yyxxxwww1yy......
+ wsr a2, windowstart # set corrected windowstart
+
+ srli a3, a3, 1
+ rsr a2, excsave1
+ l32i a2, a2, EXC_TABLE_DOUBLE_SAVE # restore a2
+ xsr a2, excsave1
+ s32i a3, a2, EXC_TABLE_DOUBLE_SAVE # save a3
+ l32i a3, a2, EXC_TABLE_PARAM # original WB (in user task)
+ xsr a2, excsave1
+
+ /* Return to the original (user task) WINDOWBASE.
+ * We leave the following frame behind:
+ * a0, a1, a2 same
+ * a3: trashed (saved in EXC_TABLE_DOUBLE_SAVE)
+ * depc: depc (we have to return to that address)
+ * excsave_1: exctable
+ */
+
+ wsr a3, windowbase
+ rsync
+
+ /* We are now in the original frame when we entered _spill_registers:
+ * a0: return address
+ * a1: used, stack pointer
+ * a2: kernel stack pointer
+ * a3: available
+ * depc: exception address
+ * excsave: exctable
+ * Note: This frame might be the same as above.
+ */
+
+ /* Setup stack pointer. */
+
+ addi a2, a2, -PT_USER_SIZE
+ s32i a0, a2, PT_AREG0
+
+ /* Make sure we return to this fixup handler. */
+
+ movi a3, fast_syscall_spill_registers_fixup_return
+ s32i a3, a2, PT_DEPC # setup depc
+
+ /* Jump to the exception handler. */
+
+ rsr a3, excsave1
+ rsr a0, exccause
+ addx4 a0, a0, a3 # find entry in table
+ l32i a0, a0, EXC_TABLE_FAST_USER # load handler
+ l32i a3, a3, EXC_TABLE_DOUBLE_SAVE
+ jx a0
+
+ENDPROC(fast_syscall_spill_registers_fixup)
+
+ENTRY(fast_syscall_spill_registers_fixup_return)
+
+ /* When we return here, all registers have been restored (a2: DEPC) */
+
+ wsr a2, depc # exception address
+
+ /* Restore fixup handler. */
+
+ rsr a2, excsave1
+ s32i a3, a2, EXC_TABLE_DOUBLE_SAVE
+ movi a3, fast_syscall_spill_registers_fixup
+ s32i a3, a2, EXC_TABLE_FIXUP
+ rsr a3, windowbase
+ s32i a3, a2, EXC_TABLE_PARAM
+ l32i a2, a2, EXC_TABLE_KSTK
+
+ /* Load WB at the time the exception occurred. */
+
+ rsr a3, sar # WB is still in SAR
+ neg a3, a3
+ wsr a3, windowbase
+ rsync
+
+ rsr a3, excsave1
+ l32i a3, a3, EXC_TABLE_DOUBLE_SAVE
+
+ rfde
+
+ENDPROC(fast_syscall_spill_registers_fixup_return)
#ifdef CONFIG_MMU
/*
@@ -1794,6 +1771,43 @@ ENTRY(system_call)
ENDPROC(system_call)
+/*
+ * Spill live registers on the kernel stack macro.
+ *
+ * Entry condition: ps.woe is set, ps.excm is cleared
+ * Exit condition: windowstart has single bit set
+ * May clobber: a12, a13
+ */
+ .macro spill_registers_kernel
+
+#if XCHAL_NUM_AREGS > 16
+ call12 1f
+ _j 2f
+ retw
+ .align 4
+1:
+ _entry a1, 48
+ addi a12, a0, 3
+#if XCHAL_NUM_AREGS > 32
+ .rept (XCHAL_NUM_AREGS - 32) / 12
+ _entry a1, 48
+ mov a12, a0
+ .endr
+#endif
+ _entry a1, 48
+#if XCHAL_NUM_AREGS % 12 == 0
+ mov a8, a8
+#elif XCHAL_NUM_AREGS % 12 == 4
+ mov a12, a12
+#elif XCHAL_NUM_AREGS % 12 == 8
+ mov a4, a4
+#endif
+ retw
+2:
+#else
+ mov a12, a12
+#endif
+ .endm
/*
* Task switch.
@@ -1806,21 +1820,20 @@ ENTRY(_switch_to)
entry a1, 16
- mov a12, a2 # preserve 'prev' (a2)
- mov a13, a3 # and 'next' (a3)
+ mov a10, a2 # preserve 'prev' (a2)
+ mov a11, a3 # and 'next' (a3)
l32i a4, a2, TASK_THREAD_INFO
l32i a5, a3, TASK_THREAD_INFO
- save_xtregs_user a4 a6 a8 a9 a10 a11 THREAD_XTREGS_USER
+ save_xtregs_user a4 a6 a8 a9 a12 a13 THREAD_XTREGS_USER
- s32i a0, a12, THREAD_RA # save return address
- s32i a1, a12, THREAD_SP # save stack pointer
+ s32i a0, a10, THREAD_RA # save return address
+ s32i a1, a10, THREAD_SP # save stack pointer
/* Disable ints while we manipulate the stack pointer. */
- movi a14, (1 << PS_EXCM_BIT) | LOCKLEVEL
- xsr a14, ps
+ rsil a14, LOCKLEVEL
rsr a3, excsave1
rsync
s32i a3, a3, EXC_TABLE_FIXUP /* enter critical section */
@@ -1835,7 +1848,7 @@ ENTRY(_switch_to)
/* Flush register file. */
- call0 _spill_registers # destroys a3, a4, and SAR
+ spill_registers_kernel
/* Set kernel stack (and leave critical section)
* Note: It's save to set it here. The stack will not be overwritten
@@ -1851,13 +1864,13 @@ ENTRY(_switch_to)
/* restore context of the task 'next' */
- l32i a0, a13, THREAD_RA # restore return address
- l32i a1, a13, THREAD_SP # restore stack pointer
+ l32i a0, a11, THREAD_RA # restore return address
+ l32i a1, a11, THREAD_SP # restore stack pointer
- load_xtregs_user a5 a6 a8 a9 a10 a11 THREAD_XTREGS_USER
+ load_xtregs_user a5 a6 a8 a9 a12 a13 THREAD_XTREGS_USER
wsr a14, ps
- mov a2, a12 # return 'prev'
+ mov a2, a10 # return 'prev'
rsync
retw
diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c
index 482868a2de6e..3eee94f621eb 100644
--- a/arch/xtensa/kernel/irq.c
+++ b/arch/xtensa/kernel/irq.c
@@ -155,18 +155,6 @@ void __init init_IRQ(void)
}
#ifdef CONFIG_HOTPLUG_CPU
-static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
-{
- struct irq_desc *desc = irq_to_desc(irq);
- struct irq_chip *chip = irq_data_get_irq_chip(data);
- unsigned long flags;
-
- raw_spin_lock_irqsave(&desc->lock, flags);
- if (chip->irq_set_affinity)
- chip->irq_set_affinity(data, cpumask_of(cpu), false);
- raw_spin_unlock_irqrestore(&desc->lock, flags);
-}
-
/*
* The CPU has been marked offline. Migrate IRQs off this CPU. If
* the affinity settings do not allow other CPUs, force them onto any
@@ -175,10 +163,9 @@ static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
void migrate_irqs(void)
{
unsigned int i, cpu = smp_processor_id();
- struct irq_desc *desc;
- for_each_irq_desc(i, desc) {
- struct irq_data *data = irq_desc_get_irq_data(desc);
+ for_each_active_irq(i) {
+ struct irq_data *data = irq_get_irq_data(i);
unsigned int newcpu;
if (irqd_is_per_cpu(data))
@@ -194,11 +181,8 @@ void migrate_irqs(void)
i, cpu);
cpumask_setall(data->affinity);
- newcpu = cpumask_any_and(data->affinity,
- cpu_online_mask);
}
-
- route_irq(data, i, newcpu);
+ irq_set_affinity(i, data->affinity);
}
}
#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
index 7d12af1317f1..84fe931bb60e 100644
--- a/arch/xtensa/kernel/setup.c
+++ b/arch/xtensa/kernel/setup.c
@@ -22,6 +22,7 @@
#include <linux/bootmem.h>
#include <linux/kernel.h>
#include <linux/percpu.h>
+#include <linux/clk-provider.h>
#include <linux/cpu.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
@@ -276,6 +277,7 @@ void __init early_init_devtree(void *params)
static int __init xtensa_device_probe(void)
{
+ of_clk_init(NULL);
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
return 0;
}
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
index 08b769d3b3a1..2a1823de69cc 100644
--- a/arch/xtensa/kernel/time.c
+++ b/arch/xtensa/kernel/time.c
@@ -30,6 +30,7 @@
#include <asm/platform.h>
unsigned long ccount_freq; /* ccount Hz */
+EXPORT_SYMBOL(ccount_freq);
static cycle_t ccount_read(struct clocksource *cs)
{
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S
index cb8fd44caabc..f9e1ec346e35 100644
--- a/arch/xtensa/kernel/vectors.S
+++ b/arch/xtensa/kernel/vectors.S
@@ -235,7 +235,7 @@ ENTRY(_DoubleExceptionVector)
/* Check for overflow/underflow exception, jump if overflow. */
- _bbci.l a0, 6, _DoubleExceptionVector_WindowOverflow
+ bbci.l a0, 6, _DoubleExceptionVector_WindowOverflow
/*
* Restart window underflow exception.
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c
index 74a60c7e085e..80b33ed51f31 100644
--- a/arch/xtensa/kernel/xtensa_ksyms.c
+++ b/arch/xtensa/kernel/xtensa_ksyms.c
@@ -122,9 +122,7 @@ EXPORT_SYMBOL(insw);
EXPORT_SYMBOL(insl);
extern long common_exception_return;
-extern long _spill_registers;
EXPORT_SYMBOL(common_exception_return);
-EXPORT_SYMBOL(_spill_registers);
#ifdef CONFIG_FUNCTION_TRACER
EXPORT_SYMBOL(_mcount);
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c
index 479d7537a32a..aff108df92d3 100644
--- a/arch/xtensa/mm/init.c
+++ b/arch/xtensa/mm/init.c
@@ -90,7 +90,7 @@ int __init mem_reserve(unsigned long start, unsigned long end, int must_exist)
/*
- * Initialize the bootmem system and give it all the memory we have available.
+ * Initialize the bootmem system and give it all low memory we have available.
*/
void __init bootmem_init(void)
@@ -142,9 +142,14 @@ void __init bootmem_init(void)
/* Add all remaining memory pieces into the bootmem map */
- for (i=0; i<sysmem.nr_banks; i++)
- free_bootmem(sysmem.bank[i].start,
- sysmem.bank[i].end - sysmem.bank[i].start);
+ for (i = 0; i < sysmem.nr_banks; i++) {
+ if (sysmem.bank[i].start >> PAGE_SHIFT < max_low_pfn) {
+ unsigned long end = min(max_low_pfn << PAGE_SHIFT,
+ sysmem.bank[i].end);
+ free_bootmem(sysmem.bank[i].start,
+ end - sysmem.bank[i].start);
+ }
+ }
}
diff --git a/arch/xtensa/mm/mmu.c b/arch/xtensa/mm/mmu.c
index 36ec171698b8..861203e958da 100644
--- a/arch/xtensa/mm/mmu.c
+++ b/arch/xtensa/mm/mmu.c
@@ -39,7 +39,7 @@ void init_mmu(void)
set_itlbcfg_register(0);
set_dtlbcfg_register(0);
#endif
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && CONFIG_OF
+#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF)
/*
* Update the IO area mapping in case xtensa_kio_paddr has changed
*/
diff --git a/arch/xtensa/platforms/xtfpga/setup.c b/arch/xtensa/platforms/xtfpga/setup.c
index 800227862fe8..57fd08b36f51 100644
--- a/arch/xtensa/platforms/xtfpga/setup.c
+++ b/arch/xtensa/platforms/xtfpga/setup.c
@@ -135,11 +135,11 @@ static void __init update_local_mac(struct device_node *node)
static int __init machine_setup(void)
{
- struct device_node *serial;
+ struct device_node *clock;
struct device_node *eth = NULL;
- for_each_compatible_node(serial, NULL, "ns16550a")
- update_clock_frequency(serial);
+ for_each_node_by_name(clock, "main-oscillator")
+ update_clock_frequency(clock);
if ((eth = of_find_compatible_node(eth, NULL, "opencores,ethoc")))
update_local_mac(eth);
@@ -290,6 +290,7 @@ static int __init xtavnet_init(void)
* knows whether they set it correctly on the DIP switches.
*/
pr_info("XTFPGA: Ethernet MAC %pM\n", ethoc_pdata.hwaddr);
+ ethoc_pdata.eth_clkfreq = *(long *)XTFPGA_CLKFRQ_VADDR;
return 0;
}
diff --git a/arch/xtensa/variants/fsf/include/variant/tie.h b/arch/xtensa/variants/fsf/include/variant/tie.h
index bf4020116df5..244cdea4dee5 100644
--- a/arch/xtensa/variants/fsf/include/variant/tie.h
+++ b/arch/xtensa/variants/fsf/include/variant/tie.h
@@ -18,13 +18,6 @@
#define XCHAL_CP_MASK 0x00 /* bitmask of all CPs by ID */
#define XCHAL_CP_PORT_MASK 0x00 /* bitmask of only port CPs */
-/* Basic parameters of each coprocessor: */
-#define XCHAL_CP7_NAME "XTIOP"
-#define XCHAL_CP7_IDENT XTIOP
-#define XCHAL_CP7_SA_SIZE 0 /* size of state save area */
-#define XCHAL_CP7_SA_ALIGN 1 /* min alignment of save area */
-#define XCHAL_CP_ID_XTIOP 7 /* coprocessor ID (0..7) */
-
/* Filler info for unassigned coprocessors, to simplify arrays etc: */
#define XCHAL_NCP_SA_SIZE 0
#define XCHAL_NCP_SA_ALIGN 1
@@ -42,6 +35,8 @@
#define XCHAL_CP5_SA_ALIGN 1
#define XCHAL_CP6_SA_SIZE 0
#define XCHAL_CP6_SA_ALIGN 1
+#define XCHAL_CP7_SA_SIZE 0
+#define XCHAL_CP7_SA_ALIGN 1
/* Save area for non-coprocessor optional and custom (TIE) state: */
#define XCHAL_NCP_SA_SIZE 0
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 4e491d9b5292..b6e95b5e262f 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -336,7 +336,7 @@ static void blkg_destroy(struct blkcg_gq *blkg)
* under queue_lock. If it's not pointing to @blkg now, it never
* will. Hint assignment itself can race safely.
*/
- if (rcu_dereference_raw(blkcg->blkg_hint) == blkg)
+ if (rcu_access_pointer(blkcg->blkg_hint) == blkg)
rcu_assign_pointer(blkcg->blkg_hint, NULL);
/*
diff --git a/block/blk-core.c b/block/blk-core.c
index 4db2b32b70e0..34d7c196338b 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -693,20 +693,11 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
if (!uninit_q)
return NULL;
- uninit_q->flush_rq = kzalloc(sizeof(struct request), GFP_KERNEL);
- if (!uninit_q->flush_rq)
- goto out_cleanup_queue;
-
q = blk_init_allocated_queue(uninit_q, rfn, lock);
if (!q)
- goto out_free_flush_rq;
- return q;
+ blk_cleanup_queue(uninit_q);
-out_free_flush_rq:
- kfree(uninit_q->flush_rq);
-out_cleanup_queue:
- blk_cleanup_queue(uninit_q);
- return NULL;
+ return q;
}
EXPORT_SYMBOL(blk_init_queue_node);
@@ -717,9 +708,13 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
if (!q)
return NULL;
- if (blk_init_rl(&q->root_rl, q, GFP_KERNEL))
+ q->flush_rq = kzalloc(sizeof(struct request), GFP_KERNEL);
+ if (!q->flush_rq)
return NULL;
+ if (blk_init_rl(&q->root_rl, q, GFP_KERNEL))
+ goto fail;
+
q->request_fn = rfn;
q->prep_rq_fn = NULL;
q->unprep_rq_fn = NULL;
@@ -742,12 +737,16 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
/* init elevator */
if (elevator_init(q, NULL)) {
mutex_unlock(&q->sysfs_lock);
- return NULL;
+ goto fail;
}
mutex_unlock(&q->sysfs_lock);
return q;
+
+fail:
+ kfree(q->flush_rq);
+ return NULL;
}
EXPORT_SYMBOL(blk_init_allocated_queue);
@@ -2354,7 +2353,7 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
if (!req->bio)
return false;
- trace_block_rq_complete(req->q, req);
+ trace_block_rq_complete(req->q, req, nr_bytes);
/*
* For fs requests, rq is just carrier of independent bio's
diff --git a/block/blk-exec.c b/block/blk-exec.c
index c68613bb4c79..dbf4502b1d67 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -65,7 +65,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
* be resued after dying flag is set
*/
if (q->mq_ops) {
- blk_mq_insert_request(q, rq, at_head, true);
+ blk_mq_insert_request(rq, at_head, true, false);
return;
}
diff --git a/block/blk-flush.c b/block/blk-flush.c
index 66e2b697f5db..43e6b4755e9a 100644
--- a/block/blk-flush.c
+++ b/block/blk-flush.c
@@ -137,17 +137,20 @@ static void mq_flush_run(struct work_struct *work)
rq = container_of(work, struct request, mq_flush_work);
memset(&rq->csd, 0, sizeof(rq->csd));
- blk_mq_run_request(rq, true, false);
+ blk_mq_insert_request(rq, false, true, false);
}
-static bool blk_flush_queue_rq(struct request *rq)
+static bool blk_flush_queue_rq(struct request *rq, bool add_front)
{
if (rq->q->mq_ops) {
INIT_WORK(&rq->mq_flush_work, mq_flush_run);
kblockd_schedule_work(rq->q, &rq->mq_flush_work);
return false;
} else {
- list_add_tail(&rq->queuelist, &rq->q->queue_head);
+ if (add_front)
+ list_add(&rq->queuelist, &rq->q->queue_head);
+ else
+ list_add_tail(&rq->queuelist, &rq->q->queue_head);
return true;
}
}
@@ -193,7 +196,7 @@ static bool blk_flush_complete_seq(struct request *rq, unsigned int seq,
case REQ_FSEQ_DATA:
list_move_tail(&rq->flush.list, &q->flush_data_in_flight);
- queued = blk_flush_queue_rq(rq);
+ queued = blk_flush_queue_rq(rq, true);
break;
case REQ_FSEQ_DONE:
@@ -326,7 +329,7 @@ static bool blk_kick_flush(struct request_queue *q)
q->flush_rq->rq_disk = first_rq->rq_disk;
q->flush_rq->end_io = flush_end_io;
- return blk_flush_queue_rq(q->flush_rq);
+ return blk_flush_queue_rq(q->flush_rq, false);
}
static void flush_data_end_io(struct request *rq, int error)
@@ -411,7 +414,7 @@ void blk_insert_flush(struct request *rq)
if ((policy & REQ_FSEQ_DATA) &&
!(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) {
if (q->mq_ops) {
- blk_mq_run_request(rq, false, true);
+ blk_mq_insert_request(rq, false, false, true);
} else
list_add_tail(&rq->queuelist, &q->queue_head);
return;
diff --git a/block/blk-ioc.c b/block/blk-ioc.c
index 242df01413f6..1a27f45ec776 100644
--- a/block/blk-ioc.c
+++ b/block/blk-ioc.c
@@ -68,7 +68,7 @@ static void ioc_destroy_icq(struct io_cq *icq)
* under queue_lock. If it's not pointing to @icq now, it never
* will. Hint assignment itself can race safely.
*/
- if (rcu_dereference_raw(ioc->icq_hint) == icq)
+ if (rcu_access_pointer(ioc->icq_hint) == icq)
rcu_assign_pointer(ioc->icq_hint, NULL);
ioc_exit_icq(icq);
diff --git a/block/blk-iopoll.c b/block/blk-iopoll.c
index 1855bf51edb0..c11d24e379e2 100644
--- a/block/blk-iopoll.c
+++ b/block/blk-iopoll.c
@@ -14,9 +14,6 @@
#include "blk.h"
-int blk_iopoll_enabled = 1;
-EXPORT_SYMBOL(blk_iopoll_enabled);
-
static unsigned int blk_iopoll_budget __read_mostly = 256;
static DEFINE_PER_CPU(struct list_head, blk_cpu_iopoll);
diff --git a/block/blk-mq-cpu.c b/block/blk-mq-cpu.c
index 3146befb56aa..136ef8643bba 100644
--- a/block/blk-mq-cpu.c
+++ b/block/blk-mq-cpu.c
@@ -11,7 +11,7 @@
#include "blk-mq.h"
static LIST_HEAD(blk_mq_cpu_notify_list);
-static DEFINE_SPINLOCK(blk_mq_cpu_notify_lock);
+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)
@@ -19,12 +19,12 @@ static int blk_mq_main_cpu_notify(struct notifier_block *self,
unsigned int cpu = (unsigned long) hcpu;
struct blk_mq_cpu_notifier *notify;
- spin_lock(&blk_mq_cpu_notify_lock);
+ raw_spin_lock(&blk_mq_cpu_notify_lock);
list_for_each_entry(notify, &blk_mq_cpu_notify_list, list)
notify->notify(notify->data, action, cpu);
- spin_unlock(&blk_mq_cpu_notify_lock);
+ raw_spin_unlock(&blk_mq_cpu_notify_lock);
return NOTIFY_OK;
}
@@ -32,16 +32,16 @@ void blk_mq_register_cpu_notifier(struct blk_mq_cpu_notifier *notifier)
{
BUG_ON(!notifier->notify);
- spin_lock(&blk_mq_cpu_notify_lock);
+ raw_spin_lock(&blk_mq_cpu_notify_lock);
list_add_tail(&notifier->list, &blk_mq_cpu_notify_list);
- spin_unlock(&blk_mq_cpu_notify_lock);
+ raw_spin_unlock(&blk_mq_cpu_notify_lock);
}
void blk_mq_unregister_cpu_notifier(struct blk_mq_cpu_notifier *notifier)
{
- spin_lock(&blk_mq_cpu_notify_lock);
+ raw_spin_lock(&blk_mq_cpu_notify_lock);
list_del(&notifier->list);
- spin_unlock(&blk_mq_cpu_notify_lock);
+ raw_spin_unlock(&blk_mq_cpu_notify_lock);
}
void blk_mq_init_cpu_notifier(struct blk_mq_cpu_notifier *notifier,
diff --git a/block/blk-mq-cpumap.c b/block/blk-mq-cpumap.c
index f8721278601c..097921329619 100644
--- a/block/blk-mq-cpumap.c
+++ b/block/blk-mq-cpumap.c
@@ -9,15 +9,6 @@
#include "blk.h"
#include "blk-mq.h"
-static void show_map(unsigned int *map, unsigned int nr)
-{
- int i;
-
- pr_info("blk-mq: CPU -> queue map\n");
- for_each_online_cpu(i)
- pr_info(" CPU%2u -> Queue %u\n", i, map[i]);
-}
-
static int cpu_to_queue_index(unsigned int nr_cpus, unsigned int nr_queues,
const int cpu)
{
@@ -85,7 +76,6 @@ int blk_mq_update_queue_map(unsigned int *map, unsigned int nr_queues)
map[i] = map[first_sibling];
}
- show_map(map, nr_cpus);
free_cpumask_var(cpus);
return 0;
}
diff --git a/block/blk-mq-sysfs.c b/block/blk-mq-sysfs.c
index b91ce75bd35d..b0ba264b0522 100644
--- a/block/blk-mq-sysfs.c
+++ b/block/blk-mq-sysfs.c
@@ -244,6 +244,32 @@ static ssize_t blk_mq_hw_sysfs_tags_show(struct blk_mq_hw_ctx *hctx, char *page)
return blk_mq_tag_sysfs_show(hctx->tags, page);
}
+static ssize_t blk_mq_hw_sysfs_cpus_show(struct blk_mq_hw_ctx *hctx, char *page)
+{
+ unsigned int i, queue_num, first = 1;
+ ssize_t ret = 0;
+
+ blk_mq_disable_hotplug();
+
+ for_each_online_cpu(i) {
+ queue_num = hctx->queue->mq_map[i];
+ if (queue_num != hctx->queue_num)
+ continue;
+
+ if (first)
+ ret += sprintf(ret + page, "%u", i);
+ else
+ ret += sprintf(ret + page, ", %u", i);
+
+ first = 0;
+ }
+
+ blk_mq_enable_hotplug();
+
+ ret += sprintf(ret + page, "\n");
+ return ret;
+}
+
static struct blk_mq_ctx_sysfs_entry blk_mq_sysfs_dispatched = {
.attr = {.name = "dispatched", .mode = S_IRUGO },
.show = blk_mq_sysfs_dispatched_show,
@@ -294,6 +320,10 @@ static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_tags = {
.attr = {.name = "tags", .mode = S_IRUGO },
.show = blk_mq_hw_sysfs_tags_show,
};
+static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_cpus = {
+ .attr = {.name = "cpu_list", .mode = S_IRUGO },
+ .show = blk_mq_hw_sysfs_cpus_show,
+};
static struct attribute *default_hw_ctx_attrs[] = {
&blk_mq_hw_sysfs_queued.attr,
@@ -302,6 +332,7 @@ static struct attribute *default_hw_ctx_attrs[] = {
&blk_mq_hw_sysfs_pending.attr,
&blk_mq_hw_sysfs_ipi.attr,
&blk_mq_hw_sysfs_tags.attr,
+ &blk_mq_hw_sysfs_cpus.attr,
NULL,
};
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 1fa9dd153fde..b1bcc619d0ea 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -73,8 +73,8 @@ static void blk_mq_hctx_mark_pending(struct blk_mq_hw_ctx *hctx,
set_bit(ctx->index_hw, hctx->ctx_map);
}
-static struct request *blk_mq_alloc_rq(struct blk_mq_hw_ctx *hctx, gfp_t gfp,
- bool reserved)
+static struct request *__blk_mq_alloc_request(struct blk_mq_hw_ctx *hctx,
+ gfp_t gfp, bool reserved)
{
struct request *rq;
unsigned int tag;
@@ -193,12 +193,6 @@ static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx,
ctx->rq_dispatched[rw_is_sync(rw_flags)]++;
}
-static struct request *__blk_mq_alloc_request(struct blk_mq_hw_ctx *hctx,
- gfp_t gfp, bool reserved)
-{
- return blk_mq_alloc_rq(hctx, gfp, reserved);
-}
-
static struct request *blk_mq_alloc_request_pinned(struct request_queue *q,
int rw, gfp_t gfp,
bool reserved)
@@ -289,38 +283,10 @@ void blk_mq_free_request(struct request *rq)
__blk_mq_free_request(hctx, ctx, rq);
}
-static void blk_mq_bio_endio(struct request *rq, struct bio *bio, int error)
-{
- if (error)
- clear_bit(BIO_UPTODATE, &bio->bi_flags);
- else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
- error = -EIO;
-
- if (unlikely(rq->cmd_flags & REQ_QUIET))
- set_bit(BIO_QUIET, &bio->bi_flags);
-
- /* don't actually finish bio if it's part of flush sequence */
- if (!(rq->cmd_flags & REQ_FLUSH_SEQ))
- bio_endio(bio, error);
-}
-
-void blk_mq_end_io(struct request *rq, int error)
+bool blk_mq_end_io_partial(struct request *rq, int error, unsigned int nr_bytes)
{
- struct bio *bio = rq->bio;
- unsigned int bytes = 0;
-
- trace_block_rq_complete(rq->q, rq);
-
- while (bio) {
- struct bio *next = bio->bi_next;
-
- bio->bi_next = NULL;
- bytes += bio->bi_iter.bi_size;
- blk_mq_bio_endio(rq, bio, error);
- bio = next;
- }
-
- blk_account_io_completion(rq, bytes);
+ if (blk_update_request(rq, error, blk_rq_bytes(rq)))
+ return true;
blk_account_io_done(rq);
@@ -328,8 +294,9 @@ void blk_mq_end_io(struct request *rq, int error)
rq->end_io(rq, error);
else
blk_mq_free_request(rq);
+ return false;
}
-EXPORT_SYMBOL(blk_mq_end_io);
+EXPORT_SYMBOL(blk_mq_end_io_partial);
static void __blk_mq_complete_request_remote(void *data)
{
@@ -353,7 +320,7 @@ void __blk_mq_complete_request(struct request *rq)
rq->csd.func = __blk_mq_complete_request_remote;
rq->csd.info = rq;
rq->csd.flags = 0;
- __smp_call_function_single(ctx->cpu, &rq->csd, 0);
+ smp_call_function_single_async(ctx->cpu, &rq->csd);
} else {
rq->q->softirq_done_fn(rq);
}
@@ -547,7 +514,7 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
LIST_HEAD(rq_list);
int bit, queued;
- if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->flags)))
+ if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state)))
return;
hctx->run++;
@@ -636,7 +603,7 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async)
{
- if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->flags)))
+ if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state)))
return;
if (!async)
@@ -656,7 +623,7 @@ void blk_mq_run_queues(struct request_queue *q, bool async)
queue_for_each_hw_ctx(q, hctx, i) {
if ((!blk_mq_hctx_has_pending(hctx) &&
list_empty_careful(&hctx->dispatch)) ||
- test_bit(BLK_MQ_S_STOPPED, &hctx->flags))
+ test_bit(BLK_MQ_S_STOPPED, &hctx->state))
continue;
blk_mq_run_hw_queue(hctx, async);
@@ -730,60 +697,27 @@ static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx,
blk_mq_add_timer(rq);
}
-void blk_mq_insert_request(struct request_queue *q, struct request *rq,
- bool at_head, bool run_queue)
+void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
+ bool async)
{
+ struct request_queue *q = rq->q;
struct blk_mq_hw_ctx *hctx;
- struct blk_mq_ctx *ctx, *current_ctx;
+ struct blk_mq_ctx *ctx = rq->mq_ctx, *current_ctx;
+
+ current_ctx = blk_mq_get_ctx(q);
+ if (!cpu_online(ctx->cpu))
+ rq->mq_ctx = ctx = current_ctx;
- ctx = rq->mq_ctx;
hctx = q->mq_ops->map_queue(q, ctx->cpu);
- if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
+ if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA) &&
+ !(rq->cmd_flags & (REQ_FLUSH_SEQ))) {
blk_insert_flush(rq);
} else {
- current_ctx = blk_mq_get_ctx(q);
-
- if (!cpu_online(ctx->cpu)) {
- ctx = current_ctx;
- hctx = q->mq_ops->map_queue(q, ctx->cpu);
- rq->mq_ctx = ctx;
- }
spin_lock(&ctx->lock);
__blk_mq_insert_request(hctx, rq, at_head);
spin_unlock(&ctx->lock);
-
- blk_mq_put_ctx(current_ctx);
- }
-
- if (run_queue)
- __blk_mq_run_hw_queue(hctx);
-}
-EXPORT_SYMBOL(blk_mq_insert_request);
-
-/*
- * This is a special version of blk_mq_insert_request to bypass FLUSH request
- * check. Should only be used internally.
- */
-void blk_mq_run_request(struct request *rq, bool run_queue, bool async)
-{
- struct request_queue *q = rq->q;
- struct blk_mq_hw_ctx *hctx;
- struct blk_mq_ctx *ctx, *current_ctx;
-
- current_ctx = blk_mq_get_ctx(q);
-
- ctx = rq->mq_ctx;
- if (!cpu_online(ctx->cpu)) {
- ctx = current_ctx;
- rq->mq_ctx = ctx;
}
- hctx = q->mq_ops->map_queue(q, ctx->cpu);
-
- /* ctx->cpu might be offline */
- spin_lock(&ctx->lock);
- __blk_mq_insert_request(hctx, rq, false);
- spin_unlock(&ctx->lock);
blk_mq_put_ctx(current_ctx);
@@ -926,6 +860,8 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
ctx = blk_mq_get_ctx(q);
hctx = q->mq_ops->map_queue(q, ctx->cpu);
+ if (is_sync)
+ rw |= REQ_SYNC;
trace_block_getrq(q, bio, rw);
rq = __blk_mq_alloc_request(hctx, GFP_ATOMIC, false);
if (likely(rq))
@@ -1058,8 +994,46 @@ static void blk_mq_hctx_notify(void *data, unsigned long action,
blk_mq_put_ctx(ctx);
}
-static void blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx,
- void (*init)(void *, struct blk_mq_hw_ctx *,
+static int blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx,
+ int (*init)(void *, struct blk_mq_hw_ctx *,
+ struct request *, unsigned int),
+ void *data)
+{
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < hctx->queue_depth; i++) {
+ struct request *rq = hctx->rqs[i];
+
+ ret = init(data, hctx, rq, i);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+int blk_mq_init_commands(struct request_queue *q,
+ int (*init)(void *, struct blk_mq_hw_ctx *,
+ struct request *, unsigned int),
+ void *data)
+{
+ struct blk_mq_hw_ctx *hctx;
+ unsigned int i;
+ int ret = 0;
+
+ queue_for_each_hw_ctx(q, hctx, i) {
+ ret = blk_mq_init_hw_commands(hctx, init, data);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(blk_mq_init_commands);
+
+static void blk_mq_free_hw_commands(struct blk_mq_hw_ctx *hctx,
+ void (*free)(void *, struct blk_mq_hw_ctx *,
struct request *, unsigned int),
void *data)
{
@@ -1068,12 +1042,12 @@ static void blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx,
for (i = 0; i < hctx->queue_depth; i++) {
struct request *rq = hctx->rqs[i];
- init(data, hctx, rq, i);
+ free(data, hctx, rq, i);
}
}
-void blk_mq_init_commands(struct request_queue *q,
- void (*init)(void *, struct blk_mq_hw_ctx *,
+void blk_mq_free_commands(struct request_queue *q,
+ void (*free)(void *, struct blk_mq_hw_ctx *,
struct request *, unsigned int),
void *data)
{
@@ -1081,9 +1055,9 @@ void blk_mq_init_commands(struct request_queue *q,
unsigned int i;
queue_for_each_hw_ctx(q, hctx, i)
- blk_mq_init_hw_commands(hctx, init, data);
+ blk_mq_free_hw_commands(hctx, free, data);
}
-EXPORT_SYMBOL(blk_mq_init_commands);
+EXPORT_SYMBOL(blk_mq_free_commands);
static void blk_mq_free_rq_map(struct blk_mq_hw_ctx *hctx)
{
@@ -1494,6 +1468,16 @@ static int blk_mq_queue_reinit_notify(struct notifier_block *nb,
return NOTIFY_OK;
}
+void blk_mq_disable_hotplug(void)
+{
+ mutex_lock(&all_q_mutex);
+}
+
+void blk_mq_enable_hotplug(void)
+{
+ mutex_unlock(&all_q_mutex);
+}
+
static int __init blk_mq_init(void)
{
blk_mq_cpu_init();
diff --git a/block/blk-mq.h b/block/blk-mq.h
index ed0035cd458e..ebbe6bac9d61 100644
--- a/block/blk-mq.h
+++ b/block/blk-mq.h
@@ -23,7 +23,6 @@ struct blk_mq_ctx {
};
void __blk_mq_complete_request(struct request *rq);
-void blk_mq_run_request(struct request *rq, bool run_queue, bool async);
void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);
void blk_mq_init_flush(struct request_queue *q);
void blk_mq_drain_queue(struct request_queue *q);
@@ -40,6 +39,8 @@ void blk_mq_init_cpu_notifier(struct blk_mq_cpu_notifier *notifier,
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
diff --git a/block/blk-softirq.c b/block/blk-softirq.c
index 57790c1a97eb..ebd6b6f1bdeb 100644
--- a/block/blk-softirq.c
+++ b/block/blk-softirq.c
@@ -30,8 +30,8 @@ static void blk_done_softirq(struct softirq_action *h)
while (!list_empty(&local_list)) {
struct request *rq;
- rq = list_entry(local_list.next, struct request, csd.list);
- list_del_init(&rq->csd.list);
+ rq = list_entry(local_list.next, struct request, queuelist);
+ list_del_init(&rq->queuelist);
rq->q->softirq_done_fn(rq);
}
}
@@ -45,9 +45,14 @@ static void trigger_softirq(void *data)
local_irq_save(flags);
list = this_cpu_ptr(&blk_cpu_done);
- list_add_tail(&rq->csd.list, list);
+ /*
+ * We reuse queuelist for a list of requests to process. Since the
+ * queuelist is used by the block layer only for requests waiting to be
+ * submitted to the device it is unused now.
+ */
+ list_add_tail(&rq->queuelist, list);
- if (list->next == &rq->csd.list)
+ if (list->next == &rq->queuelist)
raise_softirq_irqoff(BLOCK_SOFTIRQ);
local_irq_restore(flags);
@@ -65,7 +70,7 @@ static int raise_blk_irq(int cpu, struct request *rq)
data->info = rq;
data->flags = 0;
- __smp_call_function_single(cpu, data, 0);
+ smp_call_function_single_async(cpu, data);
return 0;
}
@@ -136,7 +141,7 @@ void __blk_complete_request(struct request *req)
struct list_head *list;
do_local:
list = this_cpu_ptr(&blk_cpu_done);
- list_add_tail(&req->csd.list, list);
+ list_add_tail(&req->queuelist, list);
/*
* if the list only contains our just added request,
@@ -144,7 +149,7 @@ do_local:
* entries there, someone already raised the irq but it
* hasn't run yet.
*/
- if (list->next == &req->csd.list)
+ if (list->next == &req->queuelist)
raise_softirq_irqoff(BLOCK_SOFTIRQ);
} else if (raise_blk_irq(ccpu, req))
goto do_local;
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 744833b630c6..5873e4ada9eb 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -2367,10 +2367,10 @@ cfq_merged_requests(struct request_queue *q, struct request *rq,
* reposition in fifo if next is older than rq
*/
if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist) &&
- time_before(rq_fifo_time(next), rq_fifo_time(rq)) &&
+ time_before(next->fifo_time, rq->fifo_time) &&
cfqq == RQ_CFQQ(next)) {
list_move(&rq->queuelist, &next->queuelist);
- rq_set_fifo_time(rq, rq_fifo_time(next));
+ rq->fifo_time = next->fifo_time;
}
if (cfqq->next_rq == next)
@@ -2814,7 +2814,7 @@ static struct request *cfq_check_fifo(struct cfq_queue *cfqq)
return NULL;
rq = rq_entry_fifo(cfqq->fifo.next);
- if (time_before(jiffies, rq_fifo_time(rq)))
+ if (time_before(jiffies, rq->fifo_time))
rq = NULL;
cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq);
@@ -3927,7 +3927,7 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
cfq_log_cfqq(cfqd, cfqq, "insert_request");
cfq_init_prio_data(cfqq, RQ_CIC(rq));
- rq_set_fifo_time(rq, jiffies + cfqd->cfq_fifo_expire[rq_is_sync(rq)]);
+ rq->fifo_time = jiffies + cfqd->cfq_fifo_expire[rq_is_sync(rq)];
list_add_tail(&rq->queuelist, &cfqq->fifo);
cfq_add_rq_rb(rq);
cfqg_stats_update_io_add(RQ_CFQG(rq), cfqd->serving_group,
diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c
index 9ef66406c625..a753df2b3fc2 100644
--- a/block/deadline-iosched.c
+++ b/block/deadline-iosched.c
@@ -106,7 +106,7 @@ deadline_add_request(struct request_queue *q, struct request *rq)
/*
* set expire time and add to fifo list
*/
- rq_set_fifo_time(rq, jiffies + dd->fifo_expire[data_dir]);
+ rq->fifo_time = jiffies + dd->fifo_expire[data_dir];
list_add_tail(&rq->queuelist, &dd->fifo_list[data_dir]);
}
@@ -174,9 +174,9 @@ deadline_merged_requests(struct request_queue *q, struct request *req,
* and move into next position (next will be deleted) in fifo
*/
if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) {
- if (time_before(rq_fifo_time(next), rq_fifo_time(req))) {
+ if (time_before(next->fifo_time, req->fifo_time)) {
list_move(&req->queuelist, &next->queuelist);
- rq_set_fifo_time(req, rq_fifo_time(next));
+ req->fifo_time = next->fifo_time;
}
}
@@ -230,7 +230,7 @@ static inline int deadline_check_fifo(struct deadline_data *dd, int ddir)
/*
* rq is expired!
*/
- if (time_after_eq(jiffies, rq_fifo_time(rq)))
+ if (time_after_eq(jiffies, rq->fifo_time))
return 1;
return 0;
diff --git a/block/partitions/atari.h b/block/partitions/atari.h
index fe2d32a89f36..f2ec43bfeec1 100644
--- a/block/partitions/atari.h
+++ b/block/partitions/atari.h
@@ -11,6 +11,8 @@
* by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de)
*/
+#include <linux/compiler.h>
+
struct partition_info
{
u8 flg; /* bit 0: active; bit 7: bootable */
@@ -29,6 +31,6 @@ struct rootsector
u32 bsl_st; /* start of bad sector list */
u32 bsl_cnt; /* length of bad sector list */
u16 checksum; /* checksum for bootable disks */
-} __attribute__((__packed__));
+} __packed;
int atari_partition(struct parsed_partitions *state);
diff --git a/block/partitions/efi.h b/block/partitions/efi.h
index 4efcafba7e64..abd0b19288a6 100644
--- a/block/partitions/efi.h
+++ b/block/partitions/efi.h
@@ -32,6 +32,7 @@
#include <linux/major.h>
#include <linux/string.h>
#include <linux/efi.h>
+#include <linux/compiler.h>
#define MSDOS_MBR_SIGNATURE 0xaa55
#define EFI_PMBR_OSTYPE_EFI 0xEF
@@ -87,13 +88,13 @@ typedef struct _gpt_header {
*
* uint8_t reserved2[ BlockSize - 92 ];
*/
-} __attribute__ ((packed)) gpt_header;
+} __packed gpt_header;
typedef struct _gpt_entry_attributes {
u64 required_to_function:1;
u64 reserved:47;
u64 type_guid_specific:16;
-} __attribute__ ((packed)) gpt_entry_attributes;
+} __packed gpt_entry_attributes;
typedef struct _gpt_entry {
efi_guid_t partition_type_guid;
@@ -102,7 +103,7 @@ typedef struct _gpt_entry {
__le64 ending_lba;
gpt_entry_attributes attributes;
efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
-} __attribute__ ((packed)) gpt_entry;
+} __packed gpt_entry;
typedef struct _gpt_mbr_record {
u8 boot_indicator; /* unused by EFI, set to 0x80 for bootable */
@@ -124,7 +125,7 @@ typedef struct _legacy_mbr {
__le16 unknown;
gpt_mbr_record partition_record[4];
__le16 signature;
-} __attribute__ ((packed)) legacy_mbr;
+} __packed legacy_mbr;
/* Functions */
extern int efi_partition(struct parsed_partitions *state);
diff --git a/block/partitions/karma.c b/block/partitions/karma.c
index 0ea19312706b..9721fa589bb1 100644
--- a/block/partitions/karma.c
+++ b/block/partitions/karma.c
@@ -8,6 +8,7 @@
#include "check.h"
#include "karma.h"
+#include <linux/compiler.h>
int karma_partition(struct parsed_partitions *state)
{
@@ -26,7 +27,7 @@ int karma_partition(struct parsed_partitions *state)
} d_partitions[2];
u8 d_blank[208];
__le16 d_magic;
- } __attribute__((packed)) *label;
+ } __packed *label;
struct d_partition *p;
data = read_part_sector(state, 0, &sect);
diff --git a/drivers/Kconfig b/drivers/Kconfig
index b3138fbb46a4..0a0a90f52d26 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
source "drivers/spi/Kconfig"
+source "drivers/spmi/Kconfig"
+
source "drivers/hsi/Kconfig"
source "drivers/pps/Kconfig"
@@ -170,4 +172,6 @@ source "drivers/phy/Kconfig"
source "drivers/powercap/Kconfig"
+source "drivers/mcb/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 8e3b8b06c0b2..e3ced91b1784 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_ATA) += ata/
obj-$(CONFIG_TARGET_CORE) += target/
obj-$(CONFIG_MTD) += mtd/
obj-$(CONFIG_SPI) += spi/
+obj-$(CONFIG_SPMI) += spmi/
obj-y += hsi/
obj-y += net/
obj-$(CONFIG_ATM) += atm/
@@ -155,3 +156,4 @@ obj-$(CONFIG_IPACK_BUS) += ipack/
obj-$(CONFIG_NTB) += ntb/
obj-$(CONFIG_FMC) += fmc/
obj-$(CONFIG_POWERCAP) += powercap/
+obj-$(CONFIG_MCB) += mcb/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 4770de5707b9..c205653e9644 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -43,19 +43,6 @@ config ACPI_SLEEP
depends on SUSPEND || HIBERNATION
default y
-config ACPI_PROCFS
- bool "Deprecated /proc/acpi files"
- depends on PROC_FS
- help
- For backwards compatibility, this option allows
- deprecated /proc/acpi/ files to exist, even when
- they have been replaced by functions in /sys.
-
- This option has no effect on /proc/acpi/ files
- and functions which do not yet exist in /sys.
-
- Say N to delete /proc/acpi/ files that have moved to /sys/
-
config ACPI_EC_DEBUGFS
tristate "EC read/write access through /sys/kernel/debug/ec"
default n
@@ -115,7 +102,7 @@ config ACPI_BUTTON
config ACPI_VIDEO
tristate "Video"
- depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
+ depends on X86 && BACKLIGHT_CLASS_DEVICE
depends on INPUT
select THERMAL
help
@@ -343,6 +330,19 @@ config ACPI_BGRT
data from the firmware boot splash. It will appear under
/sys/firmware/acpi/bgrt/ .
+config ACPI_REDUCED_HARDWARE_ONLY
+ bool "Hardware-reduced ACPI support only" if EXPERT
+ def_bool n
+ depends on ACPI
+ help
+ This config item changes the way the ACPI code is built. When this
+ option is selected, the kernel will use a specialized version of
+ ACPICA that ONLY supports the ACPI "reduced hardware" mode. The
+ resulting kernel will be smaller but it will also be restricted to
+ running in ACPI reduced hardware mode ONLY.
+
+ If you are unsure what to do, do not enable this option.
+
source "drivers/acpi/apei/Kconfig"
config ACPI_EXTLOG
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index e7515aa43d6b..2c01c1da29ce 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -33,6 +33,7 @@
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/acpi.h>
+#include "battery.h"
#define PREFIX "ACPI: "
@@ -57,6 +58,7 @@ struct acpi_ac {
struct power_supply charger;
struct platform_device *pdev;
unsigned long long state;
+ struct notifier_block battery_nb;
};
#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger)
@@ -152,6 +154,26 @@ static void acpi_ac_notify_handler(acpi_handle handle, u32 event, void *data)
return;
}
+static int acpi_ac_battery_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct acpi_ac *ac = container_of(nb, struct acpi_ac, battery_nb);
+ struct acpi_bus_event *event = (struct acpi_bus_event *)data;
+
+ /*
+ * On HP Pavilion dv6-6179er AC status notifications aren't triggered
+ * when adapter is plugged/unplugged. However, battery status
+ * notifcations are triggered when battery starts charging or
+ * discharging. Re-reading AC status triggers lost AC notifications,
+ * if AC status has changed.
+ */
+ if (strcmp(event->device_class, ACPI_BATTERY_CLASS) == 0 &&
+ event->type == ACPI_BATTERY_NOTIFY_STATUS)
+ acpi_ac_get_state(ac);
+
+ return NOTIFY_OK;
+}
+
static int thinkpad_e530_quirk(const struct dmi_system_id *d)
{
ac_sleep_before_get_state_ms = 1000;
@@ -215,6 +237,8 @@ static int acpi_ac_probe(struct platform_device *pdev)
acpi_device_name(adev), acpi_device_bid(adev),
ac->state ? "on-line" : "off-line");
+ ac->battery_nb.notifier_call = acpi_ac_battery_notify;
+ register_acpi_notifier(&ac->battery_nb);
end:
if (result)
kfree(ac);
@@ -243,6 +267,8 @@ static int acpi_ac_resume(struct device *dev)
kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
return 0;
}
+#else
+#define acpi_ac_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(acpi_ac_pm_ops, NULL, acpi_ac_resume);
@@ -259,6 +285,7 @@ static int acpi_ac_remove(struct platform_device *pdev)
ac = platform_get_drvdata(pdev);
if (ac->charger.dev)
power_supply_unregister(&ac->charger);
+ unregister_acpi_notifier(&ac->battery_nb);
kfree(ac);
diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c
index 84190ed89c04..961b45d18a5d 100644
--- a/drivers/acpi/acpi_cmos_rtc.c
+++ b/drivers/acpi/acpi_cmos_rtc.c
@@ -18,8 +18,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
ACPI_MODULE_NAME("cmos rtc");
static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 6745fe137b9e..69e29f409d4c 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -33,6 +33,13 @@ ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_GENERAL_UART_RTS_OVRD BIT(3)
#define LPSS_SW_LTR 0x10
#define LPSS_AUTO_LTR 0x14
+#define LPSS_LTR_SNOOP_REQ BIT(15)
+#define LPSS_LTR_SNOOP_MASK 0x0000FFFF
+#define LPSS_LTR_SNOOP_LAT_1US 0x800
+#define LPSS_LTR_SNOOP_LAT_32US 0xC00
+#define LPSS_LTR_SNOOP_LAT_SHIFT 5
+#define LPSS_LTR_SNOOP_LAT_CUTOFF 3000
+#define LPSS_LTR_MAX_VAL 0x3FF
#define LPSS_TX_INT 0x20
#define LPSS_TX_INT_MASK BIT(1)
@@ -102,6 +109,16 @@ static struct lpss_device_desc lpt_sdio_dev_desc = {
.ltr_required = true,
};
+static struct lpss_shared_clock pwm_clock = {
+ .name = "pwm_clk",
+ .rate = 25000000,
+};
+
+static struct lpss_device_desc byt_pwm_dev_desc = {
+ .clk_required = true,
+ .shared_clock = &pwm_clock,
+};
+
static struct lpss_shared_clock uart_clock = {
.name = "uart_clk",
.rate = 44236800,
@@ -157,6 +174,7 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
{ "INT33C7", },
/* BayTrail LPSS devices */
+ { "80860F09", (unsigned long)&byt_pwm_dev_desc },
{ "80860F0A", (unsigned long)&byt_uart_dev_desc },
{ "80860F0E", (unsigned long)&byt_spi_dev_desc },
{ "80860F14", (unsigned long)&byt_sdio_dev_desc },
@@ -315,6 +333,17 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
return ret;
}
+static u32 __lpss_reg_read(struct lpss_private_data *pdata, unsigned int reg)
+{
+ return readl(pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
+}
+
+static void __lpss_reg_write(u32 val, struct lpss_private_data *pdata,
+ unsigned int reg)
+{
+ writel(val, pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
+}
+
static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val)
{
struct acpi_device *adev;
@@ -336,7 +365,7 @@ static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val)
ret = -ENODEV;
goto out;
}
- *val = readl(pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
+ *val = __lpss_reg_read(pdata, reg);
out:
spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -389,6 +418,37 @@ static struct attribute_group lpss_attr_group = {
.name = "lpss_ltr",
};
+static void acpi_lpss_set_ltr(struct device *dev, s32 val)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ u32 ltr_mode, ltr_val;
+
+ ltr_mode = __lpss_reg_read(pdata, LPSS_GENERAL);
+ if (val < 0) {
+ if (ltr_mode & LPSS_GENERAL_LTR_MODE_SW) {
+ ltr_mode &= ~LPSS_GENERAL_LTR_MODE_SW;
+ __lpss_reg_write(ltr_mode, pdata, LPSS_GENERAL);
+ }
+ return;
+ }
+ ltr_val = __lpss_reg_read(pdata, LPSS_SW_LTR) & ~LPSS_LTR_SNOOP_MASK;
+ if (val >= LPSS_LTR_SNOOP_LAT_CUTOFF) {
+ ltr_val |= LPSS_LTR_SNOOP_LAT_32US;
+ val = LPSS_LTR_MAX_VAL;
+ } else if (val > LPSS_LTR_MAX_VAL) {
+ ltr_val |= LPSS_LTR_SNOOP_LAT_32US | LPSS_LTR_SNOOP_REQ;
+ val >>= LPSS_LTR_SNOOP_LAT_SHIFT;
+ } else {
+ ltr_val |= LPSS_LTR_SNOOP_LAT_1US | LPSS_LTR_SNOOP_REQ;
+ }
+ ltr_val |= val;
+ __lpss_reg_write(ltr_val, pdata, LPSS_SW_LTR);
+ if (!(ltr_mode & LPSS_GENERAL_LTR_MODE_SW)) {
+ ltr_mode |= LPSS_GENERAL_LTR_MODE_SW;
+ __lpss_reg_write(ltr_mode, pdata, LPSS_GENERAL);
+ }
+}
+
static int acpi_lpss_platform_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
@@ -426,9 +486,29 @@ static struct notifier_block acpi_lpss_nb = {
.notifier_call = acpi_lpss_platform_notify,
};
+static void acpi_lpss_bind(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+
+ if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required)
+ return;
+
+ if (pdata->mmio_size >= pdata->dev_desc->prv_offset + LPSS_LTR_SIZE)
+ dev->power.set_latency_tolerance = acpi_lpss_set_ltr;
+ else
+ dev_err(dev, "MMIO size insufficient to access LTR\n");
+}
+
+static void acpi_lpss_unbind(struct device *dev)
+{
+ dev->power.set_latency_tolerance = NULL;
+}
+
static struct acpi_scan_handler lpss_handler = {
.ids = acpi_lpss_device_ids,
.attach = acpi_lpss_create_device,
+ .bind = acpi_lpss_bind,
+ .unbind = acpi_lpss_unbind,
};
void __init acpi_lpss_init(void)
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index df96a0fe4890..37d73024b82e 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -408,28 +408,14 @@ static int acpi_pad_pur(acpi_handle handle)
return num;
}
-/* Notify firmware how many CPUs are idle */
-static void acpi_pad_ost(acpi_handle handle, int stat,
- uint32_t idle_cpus)
-{
- union acpi_object params[3] = {
- {.type = ACPI_TYPE_INTEGER,},
- {.type = ACPI_TYPE_INTEGER,},
- {.type = ACPI_TYPE_BUFFER,},
- };
- struct acpi_object_list arg_list = {3, params};
-
- params[0].integer.value = ACPI_PROCESSOR_AGGREGATOR_NOTIFY;
- params[1].integer.value = stat;
- params[2].buffer.length = 4;
- params[2].buffer.pointer = (void *)&idle_cpus;
- acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
-}
-
static void acpi_pad_handle_notify(acpi_handle handle)
{
int num_cpus;
uint32_t idle_cpus;
+ struct acpi_buffer param = {
+ .length = 4,
+ .pointer = (void *)&idle_cpus,
+ };
mutex_lock(&isolated_cpus_lock);
num_cpus = acpi_pad_pur(handle);
@@ -439,7 +425,7 @@ static void acpi_pad_handle_notify(acpi_handle handle)
}
acpi_pad_idle_cpus(num_cpus);
idle_cpus = acpi_pad_idle_cpus_num();
- acpi_pad_ost(handle, 0, idle_cpus);
+ acpi_evaluate_ost(handle, ACPI_PROCESSOR_AGGREGATOR_NOTIFY, 0, &param);
mutex_unlock(&isolated_cpus_lock);
}
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index 438304086ff1..b7ed86a20427 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -122,6 +122,8 @@ acpi-y += \
rsaddr.o \
rscalc.o \
rscreate.o \
+ rsdump.o \
+ rsdumpinfo.o \
rsinfo.o \
rsio.o \
rsirq.o \
@@ -132,8 +134,6 @@ acpi-y += \
rsutils.o \
rsxface.o
-acpi-$(ACPI_FUTURE_USAGE) += rsdump.o rsdumpinfo.o
-
acpi-y += \
tbfadt.o \
tbfind.o \
diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h
index 8a6c4a0d22db..6f1c616910ac 100644
--- a/drivers/acpi/acpica/accommon.h
+++ b/drivers/acpi/acpica/accommon.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 2bf3ca2b8a7a..68a91eb0fa48 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -115,6 +115,8 @@ ACPI_HW_DEPENDENT_RETURN_VOID(void
char *block_arg))
ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_generate_sci(void))
+void acpi_db_execute_test(char *type_arg);
+
/*
* dbconvert - miscellaneous conversion routines
*/
diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h
index 427db72a6302..d3e2cc395d7f 100644
--- a/drivers/acpi/acpica/acdispat.h
+++ b/drivers/acpi/acpica/acdispat.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -139,20 +139,21 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
struct acpi_walk_state *walk_state);
/*
- * dsload - Parser/Interpreter interface, pass 1 namespace load callbacks
+ * dsload - Parser/Interpreter interface
*/
acpi_status
acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number);
+/* dsload - pass 1 namespace load callbacks */
+
acpi_status
acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state,
union acpi_parse_object **out_op);
acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state);
-/*
- * dsload - Parser/Interpreter interface, pass 2 namespace load callbacks
- */
+/* dsload - pass 2 namespace load callbacks */
+
acpi_status
acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
union acpi_parse_object **out_op);
@@ -200,7 +201,9 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state);
/*
* dsmethod - Parser/Interpreter interface - control method parsing
*/
-acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node);
+acpi_status
+acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
+ union acpi_operand_object *obj_desc);
acpi_status
acpi_ds_call_control_method(struct acpi_thread_state *thread,
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index 0fb0adf435d6..68ec61fff188 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 4ed1aa384df2..49bbc71fad54 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,11 +51,19 @@
* to simplify maintenance of the code.
*/
#ifdef DEFINE_ACPI_GLOBALS
-#define ACPI_EXTERN
-#define ACPI_INIT_GLOBAL(a,b) a=b
+#define ACPI_GLOBAL(type,name) \
+ extern type name; \
+ type name
+
+#define ACPI_INIT_GLOBAL(type,name,value) \
+ type name=value
+
#else
-#define ACPI_EXTERN extern
-#define ACPI_INIT_GLOBAL(a,b) a
+#define ACPI_GLOBAL(type,name) \
+ extern type name
+
+#define ACPI_INIT_GLOBAL(type,name,value) \
+ extern type name
#endif
#ifdef DEFINE_ACPI_GLOBALS
@@ -82,33 +90,34 @@
* 5) Allow unresolved references (invalid target name) in package objects
* 6) Enable warning messages for behavior that is not ACPI spec compliant
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_interpreter_slack, FALSE);
/*
- * Automatically serialize ALL control methods? Default is FALSE, meaning
- * to use the Serialized/not_serialized method flags on a per method basis.
- * Only change this if the ASL code is poorly written and cannot handle
- * reentrancy even though methods are marked "NotSerialized".
+ * Automatically serialize all methods that create named objects? Default
+ * is TRUE, meaning that all non_serialized methods are scanned once at
+ * table load time to determine those that create named objects. Methods
+ * that create named objects are marked Serialized in order to prevent
+ * possible run-time problems if they are entered by more than one thread.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, TRUE);
/*
* Create the predefined _OSI method in the namespace? Default is TRUE
* because ACPI CA is fully compatible with other ACPI implementations.
* Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_create_osi_method, TRUE);
/*
* Optionally use default values for the ACPI register widths. Set this to
* TRUE to use the defaults, if an FADT contains incorrect widths/lengths.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_use_default_register_widths, TRUE);
/*
* Optionally enable output from the AML Debug Object.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_aml_debug_object, FALSE);
/*
* Optionally copy the entire DSDT to local memory (instead of simply
@@ -116,7 +125,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
* DSDT, creating the need for this option. Default is FALSE, do not copy
* the DSDT.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_copy_dsdt_locally, FALSE);
/*
* Optionally ignore an XSDT if present and use the RSDT instead.
@@ -124,7 +133,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE);
* of the RSDT, the XSDT has been found to be corrupt or ill-formed on
* some machines. Default behavior is to use the XSDT if present.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_do_not_use_xsdt, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE);
/*
* Optionally use 32-bit FADT addresses if and when there is a conflict
@@ -134,7 +143,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_do_not_use_xsdt, FALSE);
* some machines have been found to have a corrupted non-zero 64-bit
* address. Default is FALSE, do not favor the 32-bit addresses.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_use32_bit_fadt_addresses, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, FALSE);
/*
* Optionally truncate I/O addresses to 16 bits. Provides compatibility
@@ -142,47 +151,28 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_use32_bit_fadt_addresses, FALSE);
* this value is set to TRUE if any Windows OSI strings have been
* requested by the BIOS.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_truncate_io_addresses, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_truncate_io_addresses, FALSE);
/*
* Disable runtime checking and repair of values returned by control methods.
* Use only if the repair is causing a problem on a particular machine.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_auto_repair, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_auto_repair, FALSE);
/*
* Optionally do not load any SSDTs from the RSDT/XSDT during initialization.
* This can be useful for debugging ACPI problems on some machines.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_ssdt_table_load, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_load, FALSE);
/*
* We keep track of the latest version of Windows that has been requested by
* the BIOS.
*/
-u8 ACPI_INIT_GLOBAL(acpi_gbl_osi_data, 0);
-
-/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
-
-struct acpi_table_fadt acpi_gbl_FADT;
-u32 acpi_current_gpe_count;
-u32 acpi_gbl_trace_flags;
-acpi_name acpi_gbl_trace_method_name;
-u8 acpi_gbl_system_awake_and_running;
-
-/*
- * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning
- * that the ACPI hardware is no longer required. A flag in the FADT indicates
- * a reduced HW machine, and that flag is duplicated here for convenience.
- */
-u8 acpi_gbl_reduced_hardware;
+ACPI_INIT_GLOBAL(u8, acpi_gbl_osi_data, 0);
#endif /* DEFINE_ACPI_GLOBALS */
-/* Do not disassemble buffers to resource descriptors */
-
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_no_resource_disassembly, FALSE);
-
/*****************************************************************************
*
* ACPI Table globals
@@ -190,37 +180,36 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_no_resource_disassembly, FALSE);
****************************************************************************/
/*
- * acpi_gbl_root_table_list is the master list of ACPI tables that were
- * found in the RSDT/XSDT.
+ * Master list of all ACPI tables that were found in the RSDT/XSDT.
*/
-ACPI_EXTERN struct acpi_table_list acpi_gbl_root_table_list;
+ACPI_GLOBAL(struct acpi_table_list, acpi_gbl_root_table_list);
+
+/* DSDT information. Used to check for DSDT corruption */
+
+ACPI_GLOBAL(struct acpi_table_header *, acpi_gbl_DSDT);
+ACPI_GLOBAL(struct acpi_table_header, acpi_gbl_original_dsdt_header);
#if (!ACPI_REDUCED_HARDWARE)
-ACPI_EXTERN struct acpi_table_facs *acpi_gbl_FACS;
+ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_FACS);
#endif /* !ACPI_REDUCED_HARDWARE */
/* These addresses are calculated from the FADT Event Block addresses */
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_status;
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
-
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_status;
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
+ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1a_status);
+ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1a_enable);
-/* DSDT information. Used to check for DSDT corruption */
-
-ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT;
-ACPI_EXTERN struct acpi_table_header acpi_gbl_original_dsdt_header;
+ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_status);
+ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_enable);
/*
- * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is
+ * Handle both ACPI 1.0 and ACPI 2.0+ Integer widths. The integer width is
* determined by the revision of the DSDT: If the DSDT revision is less than
* 2, use only the lower 32 bits of the internal 64-bit Integer.
*/
-ACPI_EXTERN u8 acpi_gbl_integer_bit_width;
-ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
-ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
+ACPI_GLOBAL(u8, acpi_gbl_integer_bit_width);
+ACPI_GLOBAL(u8, acpi_gbl_integer_byte_width);
+ACPI_GLOBAL(u8, acpi_gbl_integer_nybble_width);
/*****************************************************************************
*
@@ -233,36 +222,36 @@ ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
* actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs.
* (The table maps local handles to the real OS handles)
*/
-ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[ACPI_NUM_MUTEX];
+ACPI_GLOBAL(struct acpi_mutex_info, acpi_gbl_mutex_info[ACPI_NUM_MUTEX]);
/*
* Global lock mutex is an actual AML mutex object
* Global lock semaphore works in conjunction with the actual global lock
* Global lock spinlock is used for "pending" handshake
*/
-ACPI_EXTERN union acpi_operand_object *acpi_gbl_global_lock_mutex;
-ACPI_EXTERN acpi_semaphore acpi_gbl_global_lock_semaphore;
-ACPI_EXTERN acpi_spinlock acpi_gbl_global_lock_pending_lock;
-ACPI_EXTERN u16 acpi_gbl_global_lock_handle;
-ACPI_EXTERN u8 acpi_gbl_global_lock_acquired;
-ACPI_EXTERN u8 acpi_gbl_global_lock_present;
-ACPI_EXTERN u8 acpi_gbl_global_lock_pending;
+ACPI_GLOBAL(union acpi_operand_object *, acpi_gbl_global_lock_mutex);
+ACPI_GLOBAL(acpi_semaphore, acpi_gbl_global_lock_semaphore);
+ACPI_GLOBAL(acpi_spinlock, acpi_gbl_global_lock_pending_lock);
+ACPI_GLOBAL(u16, acpi_gbl_global_lock_handle);
+ACPI_GLOBAL(u8, acpi_gbl_global_lock_acquired);
+ACPI_GLOBAL(u8, acpi_gbl_global_lock_present);
+ACPI_GLOBAL(u8, acpi_gbl_global_lock_pending);
/*
* Spinlocks are used for interfaces that can be possibly called at
* interrupt level
*/
-ACPI_EXTERN acpi_spinlock acpi_gbl_gpe_lock; /* For GPE data structs and registers */
-ACPI_EXTERN acpi_spinlock acpi_gbl_hardware_lock; /* For ACPI H/W except GPE registers */
-ACPI_EXTERN acpi_spinlock acpi_gbl_reference_count_lock;
+ACPI_GLOBAL(acpi_spinlock, acpi_gbl_gpe_lock); /* For GPE data structs and registers */
+ACPI_GLOBAL(acpi_spinlock, acpi_gbl_hardware_lock); /* For ACPI H/W except GPE registers */
+ACPI_GLOBAL(acpi_spinlock, acpi_gbl_reference_count_lock);
/* Mutex for _OSI support */
-ACPI_EXTERN acpi_mutex acpi_gbl_osi_mutex;
+ACPI_GLOBAL(acpi_mutex, acpi_gbl_osi_mutex);
/* Reader/Writer lock is used for namespace walk and dynamic table unload */
-ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
+ACPI_GLOBAL(struct acpi_rw_lock, acpi_gbl_namespace_rw_lock);
/*****************************************************************************
*
@@ -272,70 +261,69 @@ ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
/* Object caches */
-ACPI_EXTERN acpi_cache_t *acpi_gbl_namespace_cache;
-ACPI_EXTERN acpi_cache_t *acpi_gbl_state_cache;
-ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_cache;
-ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_ext_cache;
-ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache;
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_namespace_cache);
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_state_cache);
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_ps_node_cache);
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_ps_node_ext_cache);
+ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_operand_cache);
+
+/* System */
+
+ACPI_INIT_GLOBAL(u32, acpi_gbl_startup_flags, 0);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_shutdown, TRUE);
/* Global handlers */
-ACPI_EXTERN struct acpi_global_notify_handler acpi_gbl_global_notify[2];
-ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
-ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
-ACPI_EXTERN acpi_table_handler acpi_gbl_table_handler;
-ACPI_EXTERN void *acpi_gbl_table_handler_context;
-ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk;
-ACPI_EXTERN acpi_interface_handler acpi_gbl_interface_handler;
-ACPI_EXTERN struct acpi_sci_handler_info *acpi_gbl_sci_handler_list;
+ACPI_GLOBAL(struct acpi_global_notify_handler, acpi_gbl_global_notify[2]);
+ACPI_GLOBAL(acpi_exception_handler, acpi_gbl_exception_handler);
+ACPI_GLOBAL(acpi_init_handler, acpi_gbl_init_handler);
+ACPI_GLOBAL(acpi_table_handler, acpi_gbl_table_handler);
+ACPI_GLOBAL(void *, acpi_gbl_table_handler_context);
+ACPI_GLOBAL(struct acpi_walk_state *, acpi_gbl_breakpoint_walk);
+ACPI_GLOBAL(acpi_interface_handler, acpi_gbl_interface_handler);
+ACPI_GLOBAL(struct acpi_sci_handler_info *, acpi_gbl_sci_handler_list);
/* Owner ID support */
-ACPI_EXTERN u32 acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS];
-ACPI_EXTERN u8 acpi_gbl_last_owner_id_index;
-ACPI_EXTERN u8 acpi_gbl_next_owner_id_offset;
+ACPI_GLOBAL(u32, acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS]);
+ACPI_GLOBAL(u8, acpi_gbl_last_owner_id_index);
+ACPI_GLOBAL(u8, acpi_gbl_next_owner_id_offset);
/* Initialization sequencing */
-ACPI_EXTERN u8 acpi_gbl_reg_methods_executed;
+ACPI_GLOBAL(u8, acpi_gbl_reg_methods_executed);
/* Misc */
-ACPI_EXTERN u32 acpi_gbl_original_mode;
-ACPI_EXTERN u32 acpi_gbl_rsdp_original_location;
-ACPI_EXTERN u32 acpi_gbl_ns_lookup_count;
-ACPI_EXTERN u32 acpi_gbl_ps_find_count;
-ACPI_EXTERN u16 acpi_gbl_pm1_enable_register_save;
-ACPI_EXTERN u8 acpi_gbl_debugger_configuration;
-ACPI_EXTERN u8 acpi_gbl_step_to_next_call;
-ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present;
-ACPI_EXTERN u8 acpi_gbl_events_initialized;
-ACPI_EXTERN struct acpi_interface_info *acpi_gbl_supported_interfaces;
-ACPI_EXTERN struct acpi_address_range
- *acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX];
-
-#ifndef DEFINE_ACPI_GLOBALS
-
-/* Other miscellaneous */
-
-extern u8 acpi_gbl_shutdown;
-extern u32 acpi_gbl_startup_flags;
+ACPI_GLOBAL(u32, acpi_gbl_original_mode);
+ACPI_GLOBAL(u32, acpi_gbl_rsdp_original_location);
+ACPI_GLOBAL(u32, acpi_gbl_ns_lookup_count);
+ACPI_GLOBAL(u32, acpi_gbl_ps_find_count);
+ACPI_GLOBAL(u16, acpi_gbl_pm1_enable_register_save);
+ACPI_GLOBAL(u8, acpi_gbl_debugger_configuration);
+ACPI_GLOBAL(u8, acpi_gbl_step_to_next_call);
+ACPI_GLOBAL(u8, acpi_gbl_acpi_hardware_present);
+ACPI_GLOBAL(u8, acpi_gbl_events_initialized);
+ACPI_GLOBAL(struct acpi_interface_info *, acpi_gbl_supported_interfaces);
+ACPI_GLOBAL(struct acpi_address_range *,
+ acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX]);
+
+/* Other miscellaneous, declared and initialized in utglobal */
+
extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
extern const char *acpi_gbl_lowest_dstate_names[ACPI_NUM_sx_w_METHODS];
extern const char *acpi_gbl_highest_dstate_names[ACPI_NUM_sx_d_METHODS];
-extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
-
-#endif
+extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
-/* Lists for tracking memory allocations */
+/* Lists for tracking memory allocations (debug only) */
-ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list;
-ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list;
-ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats;
-ACPI_EXTERN u8 acpi_gbl_disable_mem_tracking;
+ACPI_GLOBAL(struct acpi_memory_list *, acpi_gbl_global_list);
+ACPI_GLOBAL(struct acpi_memory_list *, acpi_gbl_ns_node_list);
+ACPI_GLOBAL(u8, acpi_gbl_display_final_mem_stats);
+ACPI_GLOBAL(u8, acpi_gbl_disable_mem_tracking);
#endif
/*****************************************************************************
@@ -350,22 +338,23 @@ ACPI_EXTERN u8 acpi_gbl_disable_mem_tracking;
#define NUM_PREDEFINED_NAMES 9
#endif
-ACPI_EXTERN struct acpi_namespace_node acpi_gbl_root_node_struct;
-ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node;
-ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device;
-ACPI_EXTERN union acpi_operand_object *acpi_gbl_module_code_list;
+ACPI_GLOBAL(struct acpi_namespace_node, acpi_gbl_root_node_struct);
+ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_root_node);
+ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_fadt_gpe_device);
+ACPI_GLOBAL(union acpi_operand_object *, acpi_gbl_module_code_list);
extern const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES];
extern const struct acpi_predefined_names
acpi_gbl_pre_defined_names[NUM_PREDEFINED_NAMES];
#ifdef ACPI_DEBUG_OUTPUT
-ACPI_EXTERN u32 acpi_gbl_current_node_count;
-ACPI_EXTERN u32 acpi_gbl_current_node_size;
-ACPI_EXTERN u32 acpi_gbl_max_concurrent_node_count;
-ACPI_EXTERN acpi_size *acpi_gbl_entry_stack_pointer;
-ACPI_EXTERN acpi_size *acpi_gbl_lowest_stack_pointer;
-ACPI_EXTERN u32 acpi_gbl_deepest_nesting;
+ACPI_GLOBAL(u32, acpi_gbl_current_node_count);
+ACPI_GLOBAL(u32, acpi_gbl_current_node_size);
+ACPI_GLOBAL(u32, acpi_gbl_max_concurrent_node_count);
+ACPI_GLOBAL(acpi_size *, acpi_gbl_entry_stack_pointer);
+ACPI_GLOBAL(acpi_size *, acpi_gbl_lowest_stack_pointer);
+ACPI_GLOBAL(u32, acpi_gbl_deepest_nesting);
+ACPI_INIT_GLOBAL(u32, acpi_gbl_nesting_level, 0);
#endif
/*****************************************************************************
@@ -374,11 +363,11 @@ ACPI_EXTERN u32 acpi_gbl_deepest_nesting;
*
****************************************************************************/
-ACPI_EXTERN struct acpi_thread_state *acpi_gbl_current_walk_list;
+ACPI_GLOBAL(struct acpi_thread_state *, acpi_gbl_current_walk_list);
/* Control method single step flag */
-ACPI_EXTERN u8 acpi_gbl_cm_single_step;
+ACPI_GLOBAL(u8, acpi_gbl_cm_single_step);
/*****************************************************************************
*
@@ -388,8 +377,9 @@ ACPI_EXTERN u8 acpi_gbl_cm_single_step;
extern struct acpi_bit_register_info
acpi_gbl_bit_register_info[ACPI_NUM_BITREG];
-ACPI_EXTERN u8 acpi_gbl_sleep_type_a;
-ACPI_EXTERN u8 acpi_gbl_sleep_type_b;
+
+ACPI_GLOBAL(u8, acpi_gbl_sleep_type_a);
+ACPI_GLOBAL(u8, acpi_gbl_sleep_type_b);
/*****************************************************************************
*
@@ -399,14 +389,15 @@ ACPI_EXTERN u8 acpi_gbl_sleep_type_b;
#if (!ACPI_REDUCED_HARDWARE)
-ACPI_EXTERN u8 acpi_gbl_all_gpes_initialized;
-ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
-ACPI_EXTERN struct acpi_gpe_block_info
- *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
-ACPI_EXTERN acpi_gbl_event_handler acpi_gbl_global_event_handler;
-ACPI_EXTERN void *acpi_gbl_global_event_handler_context;
-ACPI_EXTERN struct acpi_fixed_event_handler
- acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS];
+ACPI_GLOBAL(u8, acpi_gbl_all_gpes_initialized);
+ACPI_GLOBAL(struct acpi_gpe_xrupt_info *, acpi_gbl_gpe_xrupt_list_head);
+ACPI_GLOBAL(struct acpi_gpe_block_info *,
+ acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS]);
+ACPI_GLOBAL(acpi_gbl_event_handler, acpi_gbl_global_event_handler);
+ACPI_GLOBAL(void *, acpi_gbl_global_event_handler_context);
+ACPI_GLOBAL(struct acpi_fixed_event_handler,
+ acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS]);
+
extern struct acpi_fixed_event_info
acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS];
@@ -418,23 +409,19 @@ extern struct acpi_fixed_event_info
*
****************************************************************************/
-/* Procedure nesting level for debug output */
-
-extern u32 acpi_gbl_nesting_level;
-
/* Event counters */
-ACPI_EXTERN u32 acpi_method_count;
-ACPI_EXTERN u32 acpi_gpe_count;
-ACPI_EXTERN u32 acpi_sci_count;
-ACPI_EXTERN u32 acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS];
+ACPI_GLOBAL(u32, acpi_method_count);
+ACPI_GLOBAL(u32, acpi_gpe_count);
+ACPI_GLOBAL(u32, acpi_sci_count);
+ACPI_GLOBAL(u32, acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS]);
/* Support for dynamic control method tracing mechanism */
-ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
-ACPI_EXTERN u32 acpi_gbl_original_dbg_layer;
-ACPI_EXTERN u32 acpi_gbl_trace_dbg_level;
-ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
+ACPI_GLOBAL(u32, acpi_gbl_original_dbg_level);
+ACPI_GLOBAL(u32, acpi_gbl_original_dbg_layer);
+ACPI_GLOBAL(u32, acpi_gbl_trace_dbg_level);
+ACPI_GLOBAL(u32, acpi_gbl_trace_dbg_layer);
/*****************************************************************************
*
@@ -442,61 +429,64 @@ ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
*
****************************************************************************/
-ACPI_EXTERN u8 acpi_gbl_db_output_flags;
+ACPI_GLOBAL(u8, acpi_gbl_db_output_flags);
#ifdef ACPI_DISASSEMBLER
-ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_ignore_noop_operator, FALSE);
+/* Do not disassemble buffers to resource descriptors */
+
+ACPI_INIT_GLOBAL(u8, acpi_gbl_no_resource_disassembly, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_ignore_noop_operator, FALSE);
-ACPI_EXTERN u8 acpi_gbl_db_opt_disasm;
-ACPI_EXTERN u8 acpi_gbl_db_opt_verbose;
-ACPI_EXTERN u8 acpi_gbl_num_external_methods;
-ACPI_EXTERN u32 acpi_gbl_resolved_external_methods;
-ACPI_EXTERN struct acpi_external_list *acpi_gbl_external_list;
-ACPI_EXTERN struct acpi_external_file *acpi_gbl_external_file_list;
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_disasm);
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_verbose);
+ACPI_GLOBAL(u8, acpi_gbl_num_external_methods);
+ACPI_GLOBAL(u32, acpi_gbl_resolved_external_methods);
+ACPI_GLOBAL(struct acpi_external_list *, acpi_gbl_external_list);
+ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list);
#endif
#ifdef ACPI_DEBUGGER
-extern u8 acpi_gbl_method_executing;
-extern u8 acpi_gbl_abort_method;
-extern u8 acpi_gbl_db_terminate_threads;
+ACPI_INIT_GLOBAL(u8, acpi_gbl_db_terminate_threads, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE);
-ACPI_EXTERN u8 acpi_gbl_db_opt_tables;
-ACPI_EXTERN u8 acpi_gbl_db_opt_stats;
-ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods;
-ACPI_EXTERN u8 acpi_gbl_db_opt_no_region_support;
-ACPI_EXTERN u8 acpi_gbl_db_output_to_file;
-ACPI_EXTERN char *acpi_gbl_db_buffer;
-ACPI_EXTERN char *acpi_gbl_db_filename;
-ACPI_EXTERN u32 acpi_gbl_db_debug_level;
-ACPI_EXTERN u32 acpi_gbl_db_console_debug_level;
-ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_db_scope_node;
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_tables);
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_stats);
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_ini_methods);
+ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_region_support);
+ACPI_GLOBAL(u8, acpi_gbl_db_output_to_file);
+ACPI_GLOBAL(char *, acpi_gbl_db_buffer);
+ACPI_GLOBAL(char *, acpi_gbl_db_filename);
+ACPI_GLOBAL(u32, acpi_gbl_db_debug_level);
+ACPI_GLOBAL(u32, acpi_gbl_db_console_debug_level);
+ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_db_scope_node);
-ACPI_EXTERN char *acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS];
-ACPI_EXTERN acpi_object_type acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS];
+ACPI_GLOBAL(char *, acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS]);
+ACPI_GLOBAL(acpi_object_type, acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS]);
/* These buffers should all be the same size */
-ACPI_EXTERN char acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE];
-ACPI_EXTERN char acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE];
-ACPI_EXTERN char acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE];
-ACPI_EXTERN char acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE];
+ACPI_GLOBAL(char, acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]);
+ACPI_GLOBAL(char, acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE]);
+ACPI_GLOBAL(char, acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE]);
+ACPI_GLOBAL(char, acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE]);
/*
* Statistic globals
*/
-ACPI_EXTERN u16 acpi_gbl_obj_type_count[ACPI_TYPE_NS_NODE_MAX + 1];
-ACPI_EXTERN u16 acpi_gbl_node_type_count[ACPI_TYPE_NS_NODE_MAX + 1];
-ACPI_EXTERN u16 acpi_gbl_obj_type_count_misc;
-ACPI_EXTERN u16 acpi_gbl_node_type_count_misc;
-ACPI_EXTERN u32 acpi_gbl_num_nodes;
-ACPI_EXTERN u32 acpi_gbl_num_objects;
-
-ACPI_EXTERN u32 acpi_gbl_size_of_parse_tree;
-ACPI_EXTERN u32 acpi_gbl_size_of_method_trees;
-ACPI_EXTERN u32 acpi_gbl_size_of_node_entries;
-ACPI_EXTERN u32 acpi_gbl_size_of_acpi_objects;
+ACPI_GLOBAL(u16, acpi_gbl_obj_type_count[ACPI_TYPE_NS_NODE_MAX + 1]);
+ACPI_GLOBAL(u16, acpi_gbl_node_type_count[ACPI_TYPE_NS_NODE_MAX + 1]);
+ACPI_GLOBAL(u16, acpi_gbl_obj_type_count_misc);
+ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc);
+ACPI_GLOBAL(u32, acpi_gbl_num_nodes);
+ACPI_GLOBAL(u32, acpi_gbl_num_objects);
+
+ACPI_GLOBAL(u32, acpi_gbl_size_of_parse_tree);
+ACPI_GLOBAL(u32, acpi_gbl_size_of_method_trees);
+ACPI_GLOBAL(u32, acpi_gbl_size_of_node_entries);
+ACPI_GLOBAL(u32, acpi_gbl_size_of_acpi_objects);
#endif /* ACPI_DEBUGGER */
@@ -508,7 +498,7 @@ ACPI_EXTERN u32 acpi_gbl_size_of_acpi_objects;
#ifdef ACPI_APPLICATION
-ACPI_FILE ACPI_INIT_GLOBAL(acpi_gbl_debug_file, NULL);
+ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_debug_file, NULL);
#endif /* ACPI_APPLICATION */
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index 6357e932bfd9..2ad2351a9833 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
index 8af8c9bdeb35..b01f71ce0523 100644
--- a/drivers/acpi/acpica/acinterp.h
+++ b/drivers/acpi/acpica/acinterp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -87,6 +87,10 @@ typedef const struct acpi_exdump_info {
#define ACPI_EXD_PACKAGE 11
#define ACPI_EXD_FIELD 12
#define ACPI_EXD_REFERENCE 13
+#define ACPI_EXD_LIST 14 /* Operand object list */
+#define ACPI_EXD_HDLR_LIST 15 /* Address Handler list */
+#define ACPI_EXD_RGN_LIST 16 /* Region list */
+#define ACPI_EXD_NODE 17 /* Namespace Node */
/* restore default alignment */
@@ -454,10 +458,6 @@ void acpi_ex_enter_interpreter(void);
void acpi_ex_exit_interpreter(void);
-void acpi_ex_reacquire_interpreter(void);
-
-void acpi_ex_relinquish_interpreter(void);
-
u8 acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
void acpi_ex_acquire_global_lock(u32 rule);
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index d95ca5449ace..52a21dafb540 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index 2a86c65d873b..4bceb11c7380 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,17 +63,21 @@
#define ACPI_SET64(ptr, val) (*ACPI_CAST64 (ptr) = (u64) (val))
/*
- * printf() format helpers
+ * printf() format helpers. These macros are workarounds for the difficulties
+ * with emitting 64-bit integers and 64-bit pointers with the same code
+ * for both 32-bit and 64-bit hosts.
*/
-
-/* Split 64-bit integer into two 32-bit values. Use with %8.8X%8.8X */
-
#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i), ACPI_LODWORD(i)
#if ACPI_MACHINE_WIDTH == 64
#define ACPI_FORMAT_NATIVE_UINT(i) ACPI_FORMAT_UINT64(i)
+#define ACPI_FORMAT_TO_UINT(i) ACPI_FORMAT_UINT64(i)
+#define ACPI_PRINTF_UINT "0x%8.8X%8.8X"
+
#else
-#define ACPI_FORMAT_NATIVE_UINT(i) 0, (i)
+#define ACPI_FORMAT_NATIVE_UINT(i) 0, (u32) (i)
+#define ACPI_FORMAT_TO_UINT(i) (u32) (i)
+#define ACPI_PRINTF_UINT "0x%8.8X"
#endif
/*
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index e6138ac4a160..ee1c040f321c 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index cc7ab6dd724e..22fb6449d3d6 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -193,7 +193,8 @@ struct acpi_object_method {
#define ACPI_METHOD_INTERNAL_ONLY 0x02 /* Method is implemented internally (_OSI) */
#define ACPI_METHOD_SERIALIZED 0x04 /* Method is serialized */
#define ACPI_METHOD_SERIALIZED_PENDING 0x08 /* Method is to be marked serialized */
-#define ACPI_METHOD_MODIFIED_NAMESPACE 0x10 /* Method modified the namespace */
+#define ACPI_METHOD_IGNORE_SYNC_LEVEL 0x10 /* Method was auto-serialized at table load time */
+#define ACPI_METHOD_MODIFIED_NAMESPACE 0x20 /* Method modified the namespace */
/******************************************************************************
*
diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h
index 3fc9ca7e8aa3..dda0e6affcf1 100644
--- a/drivers/acpi/acpica/acopcode.h
+++ b/drivers/acpi/acpica/acopcode.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h
index aed319318835..6168b85463ed 100644
--- a/drivers/acpi/acpica/acparser.h
+++ b/drivers/acpi/acpica/acparser.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index f600aded7261..a48d713e9599 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,7 @@
*
* Return Package types
*
- * 1) PTYPE1 packages do not contain sub-packages.
+ * 1) PTYPE1 packages do not contain subpackages.
*
* ACPI_PTYPE1_FIXED: Fixed-length length, 1 or 2 object types:
* object type
@@ -63,8 +63,8 @@
* (Used for _PRW)
*
*
- * 2) PTYPE2 packages contain a Variable-length number of sub-packages. Each
- * of the different types describe the contents of each of the sub-packages.
+ * 2) PTYPE2 packages contain a Variable-length number of subpackages. Each
+ * of the different types describe the contents of each of the subpackages.
*
* ACPI_PTYPE2: Each subpackage contains 1 or 2 object types. Zero-length
* parent package is allowed:
@@ -560,7 +560,7 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
/*
* For _HPX, a single package is returned, containing a variable-length number
- * of sub-packages. Each sub-package contains a PCI record setting.
+ * of subpackages. Each subpackage contains a PCI record setting.
* There are several different type of record settings, of different
* lengths, but all elements of all settings are Integers.
*/
@@ -698,6 +698,12 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+ {{"_PRP", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: 1 Str, 1 Int/Str/Pkg */
+ PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_STRING, 1,
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING |
+ ACPI_RTYPE_PACKAGE | ACPI_RTYPE_REFERENCE, 1, 0),
+
{{"_PRS", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h
index ff97430455cb..4b008e8884a1 100644
--- a/drivers/acpi/acpica/acresrc.h
+++ b/drivers/acpi/acpica/acresrc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h
index fc83c0a5ca70..cf7346110bd8 100644
--- a/drivers/acpi/acpica/acstruct.h
+++ b/drivers/acpi/acpica/acstruct.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -133,6 +133,9 @@ struct acpi_init_walk_info {
u32 table_index;
u32 object_count;
u32 method_count;
+ u32 serial_method_count;
+ u32 non_serial_method_count;
+ u32 serialized_method_count;
u32 device_count;
u32 op_region_count;
u32 field_count;
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index c54f42c64fe2..5fa4b2027697 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index be8180c17d7e..ceeec0b7ccb1 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,7 +49,7 @@ extern const u8 acpi_gbl_resource_aml_serial_bus_sizes[];
/* Strings used by the disassembler and debugger resource dump routines */
-#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
extern const char *acpi_gbl_bm_decode[];
extern const char *acpi_gbl_config_decode[];
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h
index 48a3e331b72d..5908ccec6aea 100644
--- a/drivers/acpi/acpica/amlcode.h
+++ b/drivers/acpi/acpica/amlcode.h
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h
index 87c26366d1df..f3f834408441 100644
--- a/drivers/acpi/acpica/amlresrc.h
+++ b/drivers/acpi/acpica/amlresrc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c
index afdc6df17abf..720b1cdda711 100644
--- a/drivers/acpi/acpica/dsargs.c
+++ b/drivers/acpi/acpica/dsargs.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c
index eb56b66444b5..8daf9de82b73 100644
--- a/drivers/acpi/acpica/dscontrol.c
+++ b/drivers/acpi/acpica/dscontrol.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c
index e7a57c554e84..3661c8e90540 100644
--- a/drivers/acpi/acpica/dsfield.c
+++ b/drivers/acpi/acpica/dsfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c
index 14424200d246..aee5e45f6d35 100644
--- a/drivers/acpi/acpica/dsinit.c
+++ b/drivers/acpi/acpica/dsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -83,8 +83,8 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
(struct acpi_init_walk_info *)context;
struct acpi_namespace_node *node =
(struct acpi_namespace_node *)obj_handle;
- acpi_object_type type;
acpi_status status;
+ union acpi_operand_object *obj_desc;
ACPI_FUNCTION_ENTRY();
@@ -100,9 +100,7 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
/* And even then, we are only interested in a few object types */
- type = acpi_ns_get_type(obj_handle);
-
- switch (type) {
+ switch (acpi_ns_get_type(obj_handle)) {
case ACPI_TYPE_REGION:
status = acpi_ds_initialize_region(obj_handle);
@@ -117,8 +115,44 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
break;
case ACPI_TYPE_METHOD:
-
+ /*
+ * Auto-serialization support. We will examine each method that is
+ * not_serialized to determine if it creates any Named objects. If
+ * it does, it will be marked serialized to prevent problems if
+ * the method is entered by two or more threads and an attempt is
+ * made to create the same named object twice -- which results in
+ * an AE_ALREADY_EXISTS exception and method abort.
+ */
info->method_count++;
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+ break;
+ }
+
+ /* Ignore if already serialized */
+
+ if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) {
+ info->serial_method_count++;
+ break;
+ }
+
+ if (acpi_gbl_auto_serialize_methods) {
+
+ /* Parse/scan method and serialize it if necessary */
+
+ acpi_ds_auto_serialize_method(node, obj_desc);
+ if (obj_desc->method.
+ info_flags & ACPI_METHOD_SERIALIZED) {
+
+ /* Method was just converted to Serialized */
+
+ info->serial_method_count++;
+ info->serialized_method_count++;
+ break;
+ }
+ }
+
+ info->non_serial_method_count++;
break;
case ACPI_TYPE_DEVICE:
@@ -170,7 +204,6 @@ acpi_ds_initialize_objects(u32 table_index,
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"**** Starting initialization of namespace objects ****\n"));
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:"));
/* Set all init info to zero */
@@ -205,14 +238,16 @@ acpi_ds_initialize_objects(u32 table_index,
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "\nTable [%4.4s](id %4.4X) - %u Objects with %u Devices %u Methods %u Regions\n",
+ "Table [%4.4s] (id %4.4X) - %4u Objects with %3u Devices, "
+ "%3u Regions, %3u Methods (%u/%u/%u Serial/Non/Cvt)\n",
table->signature, owner_id, info.object_count,
- info.device_count, info.method_count,
- info.op_region_count));
+ info.device_count, info.op_region_count,
+ info.method_count, info.serial_method_count,
+ info.non_serial_method_count,
+ info.serialized_method_count));
- ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "%u Methods, %u Regions\n", info.method_count,
- info.op_region_count));
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "%u Methods, %u Regions\n",
+ info.method_count, info.op_region_count));
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index 81a78ba84311..3c7f7378b94d 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,16 +49,155 @@
#ifdef ACPI_DISASSEMBLER
#include "acdisasm.h"
#endif
+#include "acparser.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsmethod")
/* Local prototypes */
static acpi_status
+acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **out_op);
+
+static acpi_status
acpi_ds_create_method_mutex(union acpi_operand_object *method_desc);
/*******************************************************************************
*
+ * FUNCTION: acpi_ds_auto_serialize_method
+ *
+ * PARAMETERS: node - Namespace Node of the method
+ * obj_desc - Method object attached to node
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse a control method AML to scan for control methods that
+ * need serialization due to the creation of named objects.
+ *
+ * NOTE: It is a bit of overkill to mark all such methods serialized, since
+ * there is only a problem if the method actually blocks during execution.
+ * A blocking operation is, for example, a Sleep() operation, or any access
+ * to an operation region. However, it is probably not possible to easily
+ * detect whether a method will block or not, so we simply mark all suspicious
+ * methods as serialized.
+ *
+ * NOTE2: This code is essentially a generic routine for parsing a single
+ * control method.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
+ union acpi_operand_object *obj_desc)
+{
+ acpi_status status;
+ union acpi_parse_object *op = NULL;
+ struct acpi_walk_state *walk_state;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_auto_serialize_method, node);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+ "Method auto-serialization parse [%4.4s] %p\n",
+ acpi_ut_get_node_name(node), node));
+
+ /* Create/Init a root op for the method parse tree */
+
+ op = acpi_ps_alloc_op(AML_METHOD_OP);
+ if (!op) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ acpi_ps_set_name(op, node->name.integer);
+ op->common.node = node;
+
+ /* Create and initialize a new walk state */
+
+ walk_state =
+ acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL);
+ if (!walk_state) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ status =
+ acpi_ds_init_aml_walk(walk_state, op, node,
+ obj_desc->method.aml_start,
+ obj_desc->method.aml_length, NULL, 0);
+ if (ACPI_FAILURE(status)) {
+ acpi_ds_delete_walk_state(walk_state);
+ return_ACPI_STATUS(status);
+ }
+
+ walk_state->descending_callback = acpi_ds_detect_named_opcodes;
+
+ /* Parse the method, scan for creation of named objects */
+
+ status = acpi_ps_parse_aml(walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ acpi_ps_delete_parse_tree(op);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_detect_named_opcodes
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * out_op - Unused, required for parser interface
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback used during the loading of ACPI tables.
+ * Currently used to detect methods that must be marked serialized
+ * in order to avoid problems with the creation of named objects.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **out_op)
+{
+
+ ACPI_FUNCTION_NAME(acpi_ds_detect_named_opcodes);
+
+ /* We are only interested in opcodes that create a new name */
+
+ if (!
+ (walk_state->op_info->
+ flags & (AML_NAMED | AML_CREATE | AML_FIELD))) {
+ return (AE_OK);
+ }
+
+ /*
+ * At this point, we know we have a Named object opcode.
+ * Mark the method as serialized. Later code will create a mutex for
+ * this method to enforce serialization.
+ *
+ * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the
+ * Sync Level mechanism for this method, even though it is now serialized.
+ * Otherwise, there can be conflicts with existing ASL code that actually
+ * uses sync levels.
+ */
+ walk_state->method_desc->method.sync_level = 0;
+ walk_state->method_desc->method.info_flags |=
+ (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
+ walk_state->method_node->name.ascii,
+ walk_state->method_node, walk_state->op_info->name,
+ walk_state->opcode));
+
+ /* Abort the parse, no need to examine this method any further */
+
+ return (AE_CTRL_TERMINATE);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ds_method_error
*
* PARAMETERS: status - Execution status
@@ -74,7 +213,7 @@ acpi_ds_create_method_mutex(union acpi_operand_object *method_desc);
******************************************************************************/
acpi_status
-acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
+acpi_ds_method_error(acpi_status status, struct acpi_walk_state * walk_state)
{
ACPI_FUNCTION_ENTRY();
@@ -217,13 +356,19 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
/*
* The current_sync_level (per-thread) must be less than or equal to
* the sync level of the method. This mechanism provides some
- * deadlock prevention
+ * deadlock prevention.
+ *
+ * If the method was auto-serialized, we just ignore the sync level
+ * mechanism, because auto-serialization of methods can interfere
+ * with ASL code that actually uses sync levels.
*
* Top-level method invocation has no walk state at this point
*/
if (walk_state &&
- (walk_state->thread->current_sync_level >
- obj_desc->method.mutex->mutex.sync_level)) {
+ (!(obj_desc->method.
+ info_flags & ACPI_METHOD_IGNORE_SYNC_LEVEL))
+ && (walk_state->thread->current_sync_level >
+ obj_desc->method.mutex->mutex.sync_level)) {
ACPI_ERROR((AE_INFO,
"Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)",
acpi_ut_get_node_name(method_node),
@@ -668,7 +813,8 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
method_desc->method.info_flags &=
~ACPI_METHOD_SERIALIZED_PENDING;
method_desc->method.info_flags |=
- ACPI_METHOD_SERIALIZED;
+ (ACPI_METHOD_SERIALIZED |
+ ACPI_METHOD_IGNORE_SYNC_LEVEL);
method_desc->method.sync_level = 0;
}
diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c
index c4b0b3657237..b67522df01ac 100644
--- a/drivers/acpi/acpica/dsmthdat.c
+++ b/drivers/acpi/acpica/dsmthdat.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c
index b1746a68dad1..a1e7e6b6fcf7 100644
--- a/drivers/acpi/acpica/dsobject.c
+++ b/drivers/acpi/acpica/dsobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index 5205edcf2c01..6c0759c0db47 100644
--- a/drivers/acpi/acpica/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index d7f53fb2979a..9f74795e2268 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index 1bbb22fd6fa0..f7f5107e754d 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c
index 2dbe109727c8..15623da26200 100644
--- a/drivers/acpi/acpica/dswload.c
+++ b/drivers/acpi/acpica/dswload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -73,8 +73,20 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
{
switch (pass_number) {
+ case 0:
+
+ /* Parse only - caller will setup callbacks */
+
+ walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
+ ACPI_PARSE_DELETE_TREE | ACPI_PARSE_DISASSEMBLE;
+ walk_state->descending_callback = NULL;
+ walk_state->ascending_callback = NULL;
+ break;
+
case 1:
+ /* Load pass 1 */
+
walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
ACPI_PARSE_DELETE_TREE;
walk_state->descending_callback = acpi_ds_load1_begin_op;
@@ -83,6 +95,8 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
case 2:
+ /* Load pass 2 */
+
walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
ACPI_PARSE_DELETE_TREE;
walk_state->descending_callback = acpi_ds_load2_begin_op;
@@ -91,6 +105,8 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
case 3:
+ /* Execution pass */
+
#ifndef ACPI_NO_METHOD_EXECUTION
walk_state->parse_flags |= ACPI_PARSE_EXECUTE |
ACPI_PARSE_DELETE_TREE;
diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c
index 7f569d573027..2ac28d297305 100644
--- a/drivers/acpi/acpica/dswload2.c
+++ b/drivers/acpi/acpica/dswload2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c
index d67891de1b54..9d6e2c1de1f8 100644
--- a/drivers/acpi/acpica/dswscope.c
+++ b/drivers/acpi/acpica/dswscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c
index ecb12e2137ff..24f7d5ea678a 100644
--- a/drivers/acpi/acpica/dswstate.c
+++ b/drivers/acpi/acpica/dswstate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index 83cd45f4a870..c7bffff9ed32 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c
index 4c67193a9fa7..3393a73ca0d6 100644
--- a/drivers/acpi/acpica/evglock.c
+++ b/drivers/acpi/acpica/evglock.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index a9cb4a1a4bb8..955f83da68a5 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index a31e549e64cc..caaed3c673fd 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index a3e2f38aadf6..ae779c1e871d 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c
index 4d764e847a08..17e4bbfdb096 100644
--- a/drivers/acpi/acpica/evgpeutil.c
+++ b/drivers/acpi/acpica/evgpeutil.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c
index e3157313eb27..78ac29351c9e 100644
--- a/drivers/acpi/acpica/evhandler.c
+++ b/drivers/acpi/acpica/evhandler.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index a5687540e9a6..5d594eb2e5ec 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index 144cbb9b73bc..9957297d1580 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -314,6 +314,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
{
union acpi_operand_object *handler_obj;
union acpi_operand_object *obj_desc;
+ union acpi_operand_object *start_desc;
union acpi_operand_object **last_obj_ptr;
acpi_adr_space_setup region_setup;
void **region_context;
@@ -341,6 +342,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
/* Find this region in the handler's list */
obj_desc = handler_obj->address_space.region_list;
+ start_desc = obj_desc;
last_obj_ptr = &handler_obj->address_space.region_list;
while (obj_desc) {
@@ -438,6 +440,15 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
last_obj_ptr = &obj_desc->region.next;
obj_desc = obj_desc->region.next;
+
+ /* Prevent infinite loop if list is corrupted */
+
+ if (obj_desc == start_desc) {
+ ACPI_ERROR((AE_INFO,
+ "Circular handler list in region object %p",
+ region_obj));
+ return_VOID;
+ }
}
/* If we get here, the region was not in the handler's region list */
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 8354c4f7f10c..1b148a440d67 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c
index 9e9e3454d893..4d8a709c1fc4 100644
--- a/drivers/acpi/acpica/evsci.c
+++ b/drivers/acpi/acpica/evsci.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 23a7fadca412..a734b27da061 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index 39d06af5e347..e286640ad4ff 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index 5713da77c665..20a1392ffe06 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -583,6 +583,18 @@ acpi_install_gpe_block(acpi_handle gpe_device,
goto unlock_and_exit;
}
+ /* Validate the parent device */
+
+ if (node->type != ACPI_TYPE_DEVICE) {
+ status = AE_TYPE;
+ goto unlock_and_exit;
+ }
+
+ if (node->object) {
+ status = AE_ALREADY_EXISTS;
+ goto unlock_and_exit;
+ }
+
/*
* For user-installed GPE Block Devices, the gpe_block_base_number
* is always zero
@@ -666,6 +678,13 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)
goto unlock_and_exit;
}
+ /* Validate the parent device */
+
+ if (node->type != ACPI_TYPE_DEVICE) {
+ status = AE_TYPE;
+ goto unlock_and_exit;
+ }
+
/* Get the device_object attached to the node */
obj_desc = acpi_ns_get_attached_object(node);
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c
index 02ed75ac56cd..2d6f187939c7 100644
--- a/drivers/acpi/acpica/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 06d216c8d43a..8ba1464efd11 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c
index 69e4a8cc9b71..c545386fee96 100644
--- a/drivers/acpi/acpica/exconvrt.c
+++ b/drivers/acpi/acpica/exconvrt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c
index 3c2e6dcdad3e..95d23dabcfbb 100644
--- a/drivers/acpi/acpica/excreate.c
+++ b/drivers/acpi/acpica/excreate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c
index 81c72a4ecd82..4cfc3d3b5c97 100644
--- a/drivers/acpi/acpica/exdebug.c
+++ b/drivers/acpi/acpica/exdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index 4d046faac48c..973fdae00f94 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -94,12 +94,13 @@ static struct acpi_exdump_info acpi_ex_dump_buffer[5] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_buffer), NULL},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(buffer.length), "Length"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.pointer), "Pointer"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.node), "Parent Node"},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(buffer.node), "Parent Node"},
{ACPI_EXD_BUFFER, 0, NULL}
};
-static struct acpi_exdump_info acpi_ex_dump_package[5] = {
+static struct acpi_exdump_info acpi_ex_dump_package[6] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_package), NULL},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(package.node), "Parent Node"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(package.flags), "Flags"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(package.count), "Elements"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(package.elements), "Element List"},
@@ -108,11 +109,11 @@ static struct acpi_exdump_info acpi_ex_dump_package[5] = {
static struct acpi_exdump_info acpi_ex_dump_device[4] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_device), NULL},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.handler), "Handler"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[0]),
"System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[1]),
- "Device Notify"}
+ "Device Notify"},
+ {ACPI_EXD_HDLR_LIST, ACPI_EXD_OFFSET(device.handler), "Handler"}
};
static struct acpi_exdump_info acpi_ex_dump_event[2] = {
@@ -142,17 +143,18 @@ static struct acpi_exdump_info acpi_ex_dump_mutex[5] = {
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"}
};
-static struct acpi_exdump_info acpi_ex_dump_region[7] = {
+static struct acpi_exdump_info acpi_ex_dump_region[8] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_region), NULL},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(region.space_id), "Space Id"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(region.flags), "Flags"},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(region.node), "Parent Node"},
{ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(region.address), "Address"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(region.length), "Length"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(region.handler), "Handler"},
+ {ACPI_EXD_HDLR_LIST, ACPI_EXD_OFFSET(region.handler), "Handler"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(region.next), "Next"}
};
-static struct acpi_exdump_info acpi_ex_dump_power[5] = {
+static struct acpi_exdump_info acpi_ex_dump_power[6] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_power), NULL},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(power_resource.system_level),
"System Level"},
@@ -161,7 +163,8 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = {
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[0]),
"System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[1]),
- "Device Notify"}
+ "Device Notify"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.handler), "Handler"}
};
static struct acpi_exdump_info acpi_ex_dump_processor[7] = {
@@ -225,7 +228,7 @@ static struct acpi_exdump_info acpi_ex_dump_reference[8] = {
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(reference.target_type), "Target Type"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(reference.value), "Value"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.object), "Object Desc"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.node), "Node"},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(reference.node), "Node"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.where), "Where"},
{ACPI_EXD_REFERENCE, 0, NULL}
};
@@ -234,16 +237,16 @@ static struct acpi_exdump_info acpi_ex_dump_address_handler[6] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_address_handler),
NULL},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(address_space.space_id), "Space Id"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.next), "Next"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.region_list),
+ {ACPI_EXD_HDLR_LIST, ACPI_EXD_OFFSET(address_space.next), "Next"},
+ {ACPI_EXD_RGN_LIST, ACPI_EXD_OFFSET(address_space.region_list),
"Region List"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.node), "Node"},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(address_space.node), "Node"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.context), "Context"}
};
static struct acpi_exdump_info acpi_ex_dump_notify[7] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_notify), NULL},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.node), "Node"},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(notify.node), "Node"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(notify.handler_type), "Handler Type"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.handler), "Handler"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.context), "Context"},
@@ -252,14 +255,31 @@ static struct acpi_exdump_info acpi_ex_dump_notify[7] = {
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.next[1]), "Next Device Notify"}
};
+static struct acpi_exdump_info acpi_ex_dump_extra[6] = {
+ {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_extra), NULL},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(extra.method_REG), "_REG Method"},
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(extra.scope_node), "Scope Node"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(extra.region_context),
+ "Region Context"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(extra.aml_start), "Aml Start"},
+ {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(extra.aml_length), "Aml Length"}
+};
+
+static struct acpi_exdump_info acpi_ex_dump_data[3] = {
+ {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_data), NULL},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(data.handler), "Handler"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(data.pointer), "Raw Data"}
+};
+
/* Miscellaneous tables */
-static struct acpi_exdump_info acpi_ex_dump_common[4] = {
+static struct acpi_exdump_info acpi_ex_dump_common[5] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_common), NULL},
{ACPI_EXD_TYPE, 0, NULL},
{ACPI_EXD_UINT16, ACPI_EXD_OFFSET(common.reference_count),
"Reference Count"},
- {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(common.flags), "Flags"}
+ {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(common.flags), "Flags"},
+ {ACPI_EXD_LIST, ACPI_EXD_OFFSET(common.next_object), "Object List"}
};
static struct acpi_exdump_info acpi_ex_dump_field_common[7] = {
@@ -274,15 +294,17 @@ static struct acpi_exdump_info acpi_ex_dump_field_common[7] = {
"Field Bit Offset"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(common_field.base_byte_offset),
"Base Byte Offset"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(common_field.node), "Parent Node"}
+ {ACPI_EXD_NODE, ACPI_EXD_OFFSET(common_field.node), "Parent Node"}
};
-static struct acpi_exdump_info acpi_ex_dump_node[5] = {
+static struct acpi_exdump_info acpi_ex_dump_node[7] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_node), NULL},
{ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(flags), "Flags"},
{ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(owner_id), "Owner Id"},
- {ACPI_EXD_POINTER, ACPI_EXD_NSOFFSET(child), "Child List"},
- {ACPI_EXD_POINTER, ACPI_EXD_NSOFFSET(peer), "Next Peer"}
+ {ACPI_EXD_LIST, ACPI_EXD_NSOFFSET(object), "Object List"},
+ {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(parent), "Parent"},
+ {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(child), "Child"},
+ {ACPI_EXD_NODE, ACPI_EXD_NSOFFSET(peer), "Peer"}
};
/* Dispatch table, indexed by object type */
@@ -315,7 +337,9 @@ static struct acpi_exdump_info *acpi_ex_dump_info[] = {
acpi_ex_dump_address_handler,
NULL,
NULL,
- NULL
+ NULL,
+ acpi_ex_dump_extra,
+ acpi_ex_dump_data
};
/*******************************************************************************
@@ -340,6 +364,10 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
char *name;
const char *reference_name;
u8 count;
+ union acpi_operand_object *start;
+ union acpi_operand_object *data = NULL;
+ union acpi_operand_object *next;
+ struct acpi_namespace_node *node;
if (!info) {
acpi_os_printf
@@ -363,9 +391,9 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
case ACPI_EXD_TYPE:
- acpi_ex_out_string("Type",
- acpi_ut_get_object_type_name
- (obj_desc));
+ acpi_os_printf("%20s : %2.2X [%s]\n", "Type",
+ obj_desc->common.type,
+ acpi_ut_get_object_type_name(obj_desc));
break;
case ACPI_EXD_UINT8:
@@ -433,6 +461,121 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
acpi_ex_dump_reference_obj(obj_desc);
break;
+ case ACPI_EXD_LIST:
+
+ start = *ACPI_CAST_PTR(void *, target);
+ next = start;
+
+ acpi_os_printf("%20s : %p", name, next);
+ if (next) {
+ acpi_os_printf("(%s %2.2X)",
+ acpi_ut_get_object_type_name
+ (next), next->common.type);
+
+ while (next->common.next_object) {
+ if ((next->common.type ==
+ ACPI_TYPE_LOCAL_DATA) && !data) {
+ data = next;
+ }
+
+ next = next->common.next_object;
+ acpi_os_printf("->%p(%s %2.2X)", next,
+ acpi_ut_get_object_type_name
+ (next),
+ next->common.type);
+
+ if ((next == start) || (next == data)) {
+ acpi_os_printf
+ ("\n**** Error: Object list appears to be circular linked");
+ break;
+ }
+ }
+ }
+
+ acpi_os_printf("\n", next);
+ break;
+
+ case ACPI_EXD_HDLR_LIST:
+
+ start = *ACPI_CAST_PTR(void *, target);
+ next = start;
+
+ acpi_os_printf("%20s : %p", name, next);
+ if (next) {
+ acpi_os_printf("(%s %2.2X)",
+ acpi_ut_get_object_type_name
+ (next), next->common.type);
+
+ while (next->address_space.next) {
+ if ((next->common.type ==
+ ACPI_TYPE_LOCAL_DATA) && !data) {
+ data = next;
+ }
+
+ next = next->address_space.next;
+ acpi_os_printf("->%p(%s %2.2X)", next,
+ acpi_ut_get_object_type_name
+ (next),
+ next->common.type);
+
+ if ((next == start) || (next == data)) {
+ acpi_os_printf
+ ("\n**** Error: Handler list appears to be circular linked");
+ break;
+ }
+ }
+ }
+
+ acpi_os_printf("\n", next);
+ break;
+
+ case ACPI_EXD_RGN_LIST:
+
+ start = *ACPI_CAST_PTR(void *, target);
+ next = start;
+
+ acpi_os_printf("%20s : %p", name, next);
+ if (next) {
+ acpi_os_printf("(%s %2.2X)",
+ acpi_ut_get_object_type_name
+ (next), next->common.type);
+
+ while (next->region.next) {
+ if ((next->common.type ==
+ ACPI_TYPE_LOCAL_DATA) && !data) {
+ data = next;
+ }
+
+ next = next->region.next;
+ acpi_os_printf("->%p(%s %2.2X)", next,
+ acpi_ut_get_object_type_name
+ (next),
+ next->common.type);
+
+ if ((next == start) || (next == data)) {
+ acpi_os_printf
+ ("\n**** Error: Region list appears to be circular linked");
+ break;
+ }
+ }
+ }
+
+ acpi_os_printf("\n", next);
+ break;
+
+ case ACPI_EXD_NODE:
+
+ node =
+ *ACPI_CAST_PTR(struct acpi_namespace_node *,
+ target);
+
+ acpi_os_printf("%20s : %p", name, node);
+ if (node) {
+ acpi_os_printf(" [%4.4s]", node->name.ascii);
+ }
+ acpi_os_printf("\n");
+ break;
+
default:
acpi_os_printf("**** Invalid table opcode [%X] ****\n",
@@ -821,10 +964,8 @@ void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags)
}
acpi_os_printf("%20s : %4.4s\n", "Name", acpi_ut_get_node_name(node));
- acpi_ex_out_string("Type", acpi_ut_get_type_name(node->type));
- acpi_ex_out_pointer("Attached Object",
- acpi_ns_get_attached_object(node));
- acpi_ex_out_pointer("Parent", node->parent);
+ acpi_os_printf("%20s : %2.2X [%s]\n", "Type",
+ node->type, acpi_ut_get_type_name(node->type));
acpi_ex_dump_object(ACPI_CAST_PTR(union acpi_operand_object, node),
acpi_ex_dump_node);
@@ -1017,22 +1158,26 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags)
((struct acpi_namespace_node *)obj_desc)->
object);
- acpi_ex_dump_object_descriptor(((struct acpi_namespace_node *)
- obj_desc)->object, flags);
- return_VOID;
+ obj_desc = ((struct acpi_namespace_node *)obj_desc)->object;
+ goto dump_object;
}
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) {
- acpi_os_printf
- ("ExDumpObjectDescriptor: %p is not an ACPI operand object: [%s]\n",
- obj_desc, acpi_ut_get_descriptor_name(obj_desc));
+ acpi_os_printf("%p is not an ACPI operand object: [%s]\n",
+ obj_desc, acpi_ut_get_descriptor_name(obj_desc));
return_VOID;
}
- if (obj_desc->common.type > ACPI_TYPE_NS_NODE_MAX) {
+ /* Validate the object type */
+
+ if (obj_desc->common.type > ACPI_TYPE_LOCAL_MAX) {
+ acpi_os_printf("Not a known object type: %2.2X\n",
+ obj_desc->common.type);
return_VOID;
}
+dump_object:
+
/* Common Fields */
acpi_ex_dump_object(obj_desc, acpi_ex_dump_common);
@@ -1040,6 +1185,22 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags)
/* Object-specific fields */
acpi_ex_dump_object(obj_desc, acpi_ex_dump_info[obj_desc->common.type]);
+
+ if (obj_desc->common.type == ACPI_TYPE_REGION) {
+ obj_desc = obj_desc->common.next_object;
+ if (obj_desc->common.type > ACPI_TYPE_LOCAL_MAX) {
+ acpi_os_printf
+ ("Secondary object is not a known object type: %2.2X\n",
+ obj_desc->common.type);
+
+ return_VOID;
+ }
+
+ acpi_os_printf("\nExtra attached Object (%p):\n", obj_desc);
+ acpi_ex_dump_object(obj_desc,
+ acpi_ex_dump_info[obj_desc->common.type]);
+ }
+
return_VOID;
}
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index cfd875243421..68d97441432c 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index 49fb742d61b9..1d1b27a96c5b 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c
index 65d93607f368..2207e624f538 100644
--- a/drivers/acpi/acpica/exmisc.c
+++ b/drivers/acpi/acpica/exmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c
index 7be0205ad067..b49ea2a95f4f 100644
--- a/drivers/acpi/acpica/exmutex.c
+++ b/drivers/acpi/acpica/exmutex.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c
index 14689dec4960..dbb03b544e8c 100644
--- a/drivers/acpi/acpica/exnames.c
+++ b/drivers/acpi/acpica/exnames.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c
index d74cea416ca0..1b8e94104407 100644
--- a/drivers/acpi/acpica/exoparg1.c
+++ b/drivers/acpi/acpica/exoparg1.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c
index d6fa0fce1fc9..2ede656ee26a 100644
--- a/drivers/acpi/acpica/exoparg2.c
+++ b/drivers/acpi/acpica/exoparg2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c
index bc042adf8804..363767cf01e5 100644
--- a/drivers/acpi/acpica/exoparg3.c
+++ b/drivers/acpi/acpica/exoparg3.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c
index 4459e32c683d..29e9e99f7fe3 100644
--- a/drivers/acpi/acpica/exoparg6.c
+++ b/drivers/acpi/acpica/exoparg6.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index 5a588611ab48..ee3f872870bc 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index 9d28867e60dc..cd5288a257a9 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c
index 7ca6925a87ca..ab060261b43e 100644
--- a/drivers/acpi/acpica/exresnte.c
+++ b/drivers/acpi/acpica/exresnte.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c
index 1606524312e3..3cde553bcbe1 100644
--- a/drivers/acpi/acpica/exresolv.c
+++ b/drivers/acpi/acpica/exresolv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c
index be3f66973ee8..3af8de3fcea4 100644
--- a/drivers/acpi/acpica/exresop.c
+++ b/drivers/acpi/acpica/exresop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c
index f0b09bf9887d..daf49f7ea311 100644
--- a/drivers/acpi/acpica/exstore.c
+++ b/drivers/acpi/acpica/exstore.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c
index 20d809d90c5b..04bd16c08f9e 100644
--- a/drivers/acpi/acpica/exstoren.c
+++ b/drivers/acpi/acpica/exstoren.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c
index 26e371073b1a..fd11018b0168 100644
--- a/drivers/acpi/acpica/exstorob.c
+++ b/drivers/acpi/acpica/exstorob.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c
index 6578dee2e51b..f7da64123ed5 100644
--- a/drivers/acpi/acpica/exsystem.c
+++ b/drivers/acpi/acpica/exsystem.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -77,7 +77,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
/* We must wait, so unlock the interpreter */
- acpi_ex_relinquish_interpreter();
+ acpi_ex_exit_interpreter();
status = acpi_os_wait_semaphore(semaphore, 1, timeout);
@@ -87,7 +87,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
/* Reacquire the interpreter */
- acpi_ex_reacquire_interpreter();
+ acpi_ex_enter_interpreter();
}
return_ACPI_STATUS(status);
@@ -123,7 +123,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
/* We must wait, so unlock the interpreter */
- acpi_ex_relinquish_interpreter();
+ acpi_ex_exit_interpreter();
status = acpi_os_acquire_mutex(mutex, timeout);
@@ -133,7 +133,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
/* Reacquire the interpreter */
- acpi_ex_reacquire_interpreter();
+ acpi_ex_enter_interpreter();
}
return_ACPI_STATUS(status);
@@ -198,7 +198,7 @@ acpi_status acpi_ex_system_do_sleep(u64 how_long)
/* Since this thread will sleep, we must release the interpreter */
- acpi_ex_relinquish_interpreter();
+ acpi_ex_exit_interpreter();
/*
* For compatibility with other ACPI implementations and to prevent
@@ -212,7 +212,7 @@ acpi_status acpi_ex_system_do_sleep(u64 how_long)
/* And now we must get the interpreter again */
- acpi_ex_reacquire_interpreter();
+ acpi_ex_enter_interpreter();
return (AE_OK);
}
diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c
index 99dc7b287d55..d9d72dff2a76 100644
--- a/drivers/acpi/acpica/exutils.c
+++ b/drivers/acpi/acpica/exutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -100,37 +100,6 @@ void acpi_ex_enter_interpreter(void)
/*******************************************************************************
*
- * FUNCTION: acpi_ex_reacquire_interpreter
- *
- * PARAMETERS: None
- *
- * RETURN: None
- *
- * DESCRIPTION: Reacquire the interpreter execution region from within the
- * interpreter code. Failure to enter the interpreter region is a
- * fatal system error. Used in conjunction with
- * relinquish_interpreter
- *
- ******************************************************************************/
-
-void acpi_ex_reacquire_interpreter(void)
-{
- ACPI_FUNCTION_TRACE(ex_reacquire_interpreter);
-
- /*
- * If the global serialized flag is set, do not release the interpreter,
- * since it was not actually released by acpi_ex_relinquish_interpreter.
- * This forces the interpreter to be single threaded.
- */
- if (!acpi_gbl_all_methods_serialized) {
- acpi_ex_enter_interpreter();
- }
-
- return_VOID;
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ex_exit_interpreter
*
* PARAMETERS: None
@@ -139,7 +108,16 @@ void acpi_ex_reacquire_interpreter(void)
*
* DESCRIPTION: Exit the interpreter execution region. This is the top level
* routine used to exit the interpreter when all processing has
- * been completed.
+ * been completed, or when the method blocks.
+ *
+ * Cases where the interpreter is unlocked internally:
+ * 1) Method will be blocked on a Sleep() AML opcode
+ * 2) Method will be blocked on an Acquire() AML opcode
+ * 3) Method will be blocked on a Wait() AML opcode
+ * 4) Method will be blocked to acquire the global lock
+ * 5) Method will be blocked waiting to execute a serialized control
+ * method that is currently executing
+ * 6) About to invoke a user-installed opregion handler
*
******************************************************************************/
@@ -160,44 +138,6 @@ void acpi_ex_exit_interpreter(void)
/*******************************************************************************
*
- * FUNCTION: acpi_ex_relinquish_interpreter
- *
- * PARAMETERS: None
- *
- * RETURN: None
- *
- * DESCRIPTION: Exit the interpreter execution region, from within the
- * interpreter - before attempting an operation that will possibly
- * block the running thread.
- *
- * Cases where the interpreter is unlocked internally
- * 1) Method to be blocked on a Sleep() AML opcode
- * 2) Method to be blocked on an Acquire() AML opcode
- * 3) Method to be blocked on a Wait() AML opcode
- * 4) Method to be blocked to acquire the global lock
- * 5) Method to be blocked waiting to execute a serialized control method
- * that is currently executing
- * 6) About to invoke a user-installed opregion handler
- *
- ******************************************************************************/
-
-void acpi_ex_relinquish_interpreter(void)
-{
- ACPI_FUNCTION_TRACE(ex_relinquish_interpreter);
-
- /*
- * If the global serialized flag is set, do not release the interpreter.
- * This forces the interpreter to be single threaded.
- */
- if (!acpi_gbl_all_methods_serialized) {
- acpi_ex_exit_interpreter();
- }
-
- return_VOID;
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ex_truncate_for32bit_table
*
* PARAMETERS: obj_desc - Object to be truncated
diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c
index 3d36df828f52..1e66d960fc11 100644
--- a/drivers/acpi/acpica/hwacpi.c
+++ b/drivers/acpi/acpica/hwacpi.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c
index 414076818d40..858fdd6be598 100644
--- a/drivers/acpi/acpica/hwesleep.c
+++ b/drivers/acpi/acpica/hwesleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index 96540506058f..2e6caabba07a 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c
index 0889a629505f..e701d8c33dbf 100644
--- a/drivers/acpi/acpica/hwpci.c
+++ b/drivers/acpi/acpica/hwpci.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index 12e6cff54f78..e0fd9b4978cd 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index e3828cc4361b..d590693eb54e 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c
index 3c498dc1636e..76ab5c1a814e 100644
--- a/drivers/acpi/acpica/hwtimer.c
+++ b/drivers/acpi/acpica/hwtimer.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c
index eab70d58852a..6b919127cd9d 100644
--- a/drivers/acpi/acpica/hwvalid.c
+++ b/drivers/acpi/acpica/hwvalid.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c
index b4b47db2dee2..96d007df65ec 100644
--- a/drivers/acpi/acpica/hwxface.c
+++ b/drivers/acpi/acpica/hwxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c
index 15dddc10fc9b..6921c7f3d208 100644
--- a/drivers/acpi/acpica/hwxfsleep.c
+++ b/drivers/acpi/acpica/hwxfsleep.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c
index 14f65f6345b9..f1249e3463be 100644
--- a/drivers/acpi/acpica/nsaccess.c
+++ b/drivers/acpi/acpica/nsaccess.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c
index fd1ff54cda19..607eb9e5150d 100644
--- a/drivers/acpi/acpica/nsalloc.c
+++ b/drivers/acpi/acpica/nsalloc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsarguments.c b/drivers/acpi/acpica/nsarguments.c
index 74b24c82707e..80fcfc8c9c1b 100644
--- a/drivers/acpi/acpica/nsarguments.c
+++ b/drivers/acpi/acpica/nsarguments.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c
index acd2964c2690..b55642c4ee58 100644
--- a/drivers/acpi/acpica/nsconvert.c
+++ b/drivers/acpi/acpica/nsconvert.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c
index 48b9c6f12643..3d88ef4a3e0d 100644
--- a/drivers/acpi/acpica/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c
index 283762511b73..42d37109aa5d 100644
--- a/drivers/acpi/acpica/nsdumpdv.c
+++ b/drivers/acpi/acpica/nsdumpdv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c
index 963ceef063f8..e634a05974db 100644
--- a/drivers/acpi/acpica/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index 3a0423af968c..a3fb7e4c0809 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -111,9 +111,8 @@ acpi_status acpi_ns_initialize_objects(void)
info.object_count));
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "%u Control Methods found\n", info.method_count));
- ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "%u Op Regions found\n", info.op_region_count));
+ "%u Control Methods found\n%u Op Regions found\n",
+ info.method_count, info.op_region_count));
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c
index 89ec645e7730..7c9d0181f341 100644
--- a/drivers/acpi/acpica/nsload.c
+++ b/drivers/acpi/acpica/nsload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -128,12 +128,12 @@ unlock:
* parse trees.
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "**** Begin Table Method Parsing and Object Initialization\n"));
+ "**** Begin Table Object Initialization\n"));
status = acpi_ds_initialize_objects(table_index, node);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "**** Completed Table Method Parsing and Object Initialization\n"));
+ "**** Completed Table Object Initialization\n"));
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c
index 90a0380fb8a0..7eee0a6f02f6 100644
--- a/drivers/acpi/acpica/nsnames.c
+++ b/drivers/acpi/acpica/nsnames.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c
index 7a736f4d1fd8..fe54a8c73b8c 100644
--- a/drivers/acpi/acpica/nsobject.c
+++ b/drivers/acpi/acpica/nsobject.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -222,13 +222,19 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node)
}
}
- /* Clear the entry in all cases */
+ /* Clear the Node entry in all cases */
node->object = NULL;
if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_OPERAND) {
+
+ /* Unlink object from front of possible object list */
+
node->object = obj_desc->common.next_object;
+
+ /* Handle possible 2-descriptor object */
+
if (node->object &&
- ((node->object)->common.type != ACPI_TYPE_LOCAL_DATA)) {
+ (node->object->common.type != ACPI_TYPE_LOCAL_DATA)) {
node->object = node->object->common.next_object;
}
}
diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c
index 177857340271..e83cff31754b 100644
--- a/drivers/acpi/acpica/nsparse.c
+++ b/drivers/acpi/acpica/nsparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index d2855d9857c4..392910ffbed9 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c
index 3d5391f9bcb5..68f725839eb6 100644
--- a/drivers/acpi/acpica/nsprepkg.c
+++ b/drivers/acpi/acpica/nsprepkg.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -132,12 +132,12 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
* Decode the type of the expected package contents
*
* PTYPE1 packages contain no subpackages
- * PTYPE2 packages contain sub-packages
+ * PTYPE2 packages contain subpackages
*/
switch (package->ret_info.type) {
case ACPI_PTYPE1_FIXED:
/*
- * The package count is fixed and there are no sub-packages
+ * The package count is fixed and there are no subpackages
*
* If package is too small, exit.
* If package is larger than expected, issue warning but continue
@@ -169,7 +169,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
case ACPI_PTYPE1_VAR:
/*
- * The package count is variable, there are no sub-packages, and all
+ * The package count is variable, there are no subpackages, and all
* elements must be of the same type
*/
for (i = 0; i < count; i++) {
@@ -185,7 +185,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
case ACPI_PTYPE1_OPTION:
/*
- * The package count is variable, there are no sub-packages. There are
+ * The package count is variable, there are no subpackages. There are
* a fixed number of required elements, and a variable number of
* optional elements.
*
@@ -242,7 +242,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
elements++;
count--;
- /* Examine the sub-packages */
+ /* Examine the subpackages */
status =
acpi_ns_check_package_list(info, package, elements, count);
@@ -250,7 +250,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
case ACPI_PTYPE2_PKG_COUNT:
- /* First element is the (Integer) count of sub-packages to follow */
+ /* First element is the (Integer) count of subpackages to follow */
status = acpi_ns_check_object_type(info, elements,
ACPI_RTYPE_INTEGER, 0);
@@ -270,7 +270,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
count = expected_count;
elements++;
- /* Examine the sub-packages */
+ /* Examine the subpackages */
status =
acpi_ns_check_package_list(info, package, elements, count);
@@ -283,9 +283,9 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
case ACPI_PTYPE2_FIX_VAR:
/*
* These types all return a single Package that consists of a
- * variable number of sub-Packages.
+ * variable number of subpackages.
*
- * First, ensure that the first element is a sub-Package. If not,
+ * First, ensure that the first element is a subpackage. If not,
* the BIOS may have incorrectly returned the object as a single
* package instead of a Package of Packages (a common error if
* there is only one entry). We may be able to repair this by
@@ -310,7 +310,7 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
count = 1;
}
- /* Examine the sub-packages */
+ /* Examine the subpackages */
status =
acpi_ns_check_package_list(info, package, elements, count);
@@ -370,9 +370,9 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
u32 j;
/*
- * Validate each sub-Package in the parent Package
+ * Validate each subpackage in the parent Package
*
- * NOTE: assumes list of sub-packages contains no NULL elements.
+ * NOTE: assumes list of subpackages contains no NULL elements.
* Any NULL elements should have been removed by earlier call
* to acpi_ns_remove_null_elements.
*/
@@ -389,7 +389,7 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
return (status);
}
- /* Examine the different types of expected sub-packages */
+ /* Examine the different types of expected subpackages */
info->parent_package = sub_package;
switch (package->ret_info.type) {
@@ -450,14 +450,14 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
case ACPI_PTYPE2_FIXED:
- /* Each sub-package has a fixed length */
+ /* Each subpackage has a fixed length */
expected_count = package->ret_info2.count;
if (sub_package->package.count < expected_count) {
goto package_too_small;
}
- /* Check the type of each sub-package element */
+ /* Check the type of each subpackage element */
for (j = 0; j < expected_count; j++) {
status =
@@ -475,14 +475,14 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
case ACPI_PTYPE2_MIN:
- /* Each sub-package has a variable but minimum length */
+ /* Each subpackage has a variable but minimum length */
expected_count = package->ret_info.count1;
if (sub_package->package.count < expected_count) {
goto package_too_small;
}
- /* Check the type of each sub-package element */
+ /* Check the type of each subpackage element */
status =
acpi_ns_check_package_elements(info, sub_elements,
@@ -531,7 +531,7 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
(*sub_elements)->integer.value = expected_count;
}
- /* Check the type of each sub-package element */
+ /* Check the type of each subpackage element */
status =
acpi_ns_check_package_elements(info,
@@ -557,10 +557,10 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
package_too_small:
- /* The sub-package count was smaller than required */
+ /* The subpackage count was smaller than required */
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags,
- "Return Sub-Package[%u] is too small - found %u elements, expected %u",
+ "Return SubPackage[%u] is too small - found %u elements, expected %u",
i, sub_package->package.count, expected_count));
return (AE_AML_OPERAND_VALUE);
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
index a05afff50eb9..7e417aa5c91e 100644
--- a/drivers/acpi/acpica/nsrepair.c
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -207,13 +207,30 @@ acpi_ns_simple_repair(struct acpi_evaluate_info *info,
* this predefined name. Either one return value is expected, or none,
* for both methods and other objects.
*
- * Exit now if there is no return object. Warning if one was expected.
+ * Try to fix if there was no return object. Warning if failed to fix.
*/
if (!return_object) {
if (expected_btypes && (!(expected_btypes & ACPI_RTYPE_NONE))) {
- ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
- ACPI_WARN_ALWAYS,
- "Missing expected return value"));
+ if (package_index != ACPI_NOT_PACKAGE_ELEMENT) {
+ ACPI_WARN_PREDEFINED((AE_INFO,
+ info->full_pathname,
+ ACPI_WARN_ALWAYS,
+ "Found unexpected NULL package element"));
+
+ status =
+ acpi_ns_repair_null_element(info,
+ expected_btypes,
+ package_index,
+ return_object_ptr);
+ if (ACPI_SUCCESS(status)) {
+ return (AE_OK); /* Repair was successful */
+ }
+ } else {
+ ACPI_WARN_PREDEFINED((AE_INFO,
+ info->full_pathname,
+ ACPI_WARN_ALWAYS,
+ "Missing expected return value"));
+ }
return (AE_AML_NO_RETURN_VALUE);
}
@@ -448,7 +465,7 @@ acpi_ns_repair_null_element(struct acpi_evaluate_info * info,
* RETURN: None.
*
* DESCRIPTION: Remove all NULL package elements from packages that contain
- * a variable number of sub-packages. For these types of
+ * a variable number of subpackages. For these types of
* packages, NULL elements can be safely removed.
*
*****************************************************************************/
@@ -469,7 +486,7 @@ acpi_ns_remove_null_elements(struct acpi_evaluate_info *info,
/*
* We can safely remove all NULL elements from these package types:
* PTYPE1_VAR packages contain a variable number of simple data types.
- * PTYPE2 packages contain a variable number of sub-packages.
+ * PTYPE2 packages contain a variable number of subpackages.
*/
switch (package_type) {
case ACPI_PTYPE1_VAR:
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index 6a25d320b169..b09e6bef72b8 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -432,8 +432,8 @@ acpi_ns_repair_CID(struct acpi_evaluate_info *info,
* DESCRIPTION: Repair for the _CST object:
* 1. Sort the list ascending by C state type
* 2. Ensure type cannot be zero
- * 3. A sub-package count of zero means _CST is meaningless
- * 4. Count must match the number of C state sub-packages
+ * 3. A subpackage count of zero means _CST is meaningless
+ * 4. Count must match the number of C state subpackages
*
*****************************************************************************/
@@ -611,6 +611,7 @@ acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
union acpi_operand_object **top_object_list;
union acpi_operand_object **sub_object_list;
union acpi_operand_object *obj_desc;
+ union acpi_operand_object *sub_package;
u32 element_count;
u32 index;
@@ -619,8 +620,17 @@ acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
top_object_list = package_object->package.elements;
element_count = package_object->package.count;
- for (index = 0; index < element_count; index++) {
- sub_object_list = (*top_object_list)->package.elements;
+ /* Examine each subpackage */
+
+ for (index = 0; index < element_count; index++, top_object_list++) {
+ sub_package = *top_object_list;
+ sub_object_list = sub_package->package.elements;
+
+ /* Check for minimum required element count */
+
+ if (sub_package->package.count < 4) {
+ continue;
+ }
/*
* If the BIOS has erroneously reversed the _PRT source_name (index 2)
@@ -634,15 +644,12 @@ acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
sub_object_list[2] = obj_desc;
info->return_flags |= ACPI_OBJECT_REPAIRED;
- ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ ACPI_WARN_PREDEFINED((AE_INFO,
+ info->full_pathname,
info->node_flags,
"PRT[%X]: Fixed reversed SourceName and SourceIndex",
index));
}
-
- /* Point to the next union acpi_operand_object in the top level package */
-
- top_object_list++;
}
return (AE_OK);
@@ -679,7 +686,7 @@ acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
u32 i;
/*
- * Entries (sub-packages) in the _PSS Package must be sorted by power
+ * Entries (subpackages) in the _PSS Package must be sorted by power
* dissipation, in descending order. If it appears that the list is
* incorrectly sorted, sort it. We sort by cpu_frequency, since this
* should be proportional to the power.
@@ -767,9 +774,9 @@ acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
*
* PARAMETERS: info - Method execution information block
* return_object - Pointer to the top-level returned object
- * start_index - Index of the first sub-package
- * expected_count - Minimum length of each sub-package
- * sort_index - Sub-package entry to sort on
+ * start_index - Index of the first subpackage
+ * expected_count - Minimum length of each subpackage
+ * sort_index - Subpackage entry to sort on
* sort_direction - Ascending or descending
* sort_key_name - Name of the sort_index field
*
@@ -805,7 +812,7 @@ acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
}
/*
- * NOTE: assumes list of sub-packages contains no NULL elements.
+ * NOTE: assumes list of subpackages contains no NULL elements.
* Any NULL elements should have been removed by earlier call
* to acpi_ns_remove_null_elements.
*/
@@ -832,7 +839,7 @@ acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
return (AE_AML_OPERAND_TYPE);
}
- /* Each sub-package must have the minimum length */
+ /* Each subpackage must have the minimum length */
if ((*outer_elements)->package.count < expected_count) {
return (AE_AML_PACKAGE_LIMIT);
diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c
index 47420faef073..af1cc42a8aa1 100644
--- a/drivers/acpi/acpica/nssearch.c
+++ b/drivers/acpi/acpica/nssearch.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index 4a0665b6bcc1..4a5e3f5c0ff7 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c
index e81f15ef659a..4758a1f2ce22 100644
--- a/drivers/acpi/acpica/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index 1f0c28ba50df..4bd558bf10d2 100644
--- a/drivers/acpi/acpica/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -923,19 +923,22 @@ ACPI_EXPORT_SYMBOL(acpi_detach_data)
/*******************************************************************************
*
- * FUNCTION: acpi_get_data
+ * FUNCTION: acpi_get_data_full
*
* PARAMETERS: obj_handle - Namespace node
* handler - Handler used in call to attach_data
* data - Where the data is returned
+ * callback - function to execute before returning
*
* RETURN: Status
*
- * DESCRIPTION: Retrieve data that was previously attached to a namespace node.
+ * DESCRIPTION: Retrieve data that was previously attached to a namespace node
+ * and execute a callback before returning.
*
******************************************************************************/
acpi_status
-acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
+acpi_get_data_full(acpi_handle obj_handle, acpi_object_handler handler,
+ void **data, void (*callback)(void *))
{
struct acpi_namespace_node *node;
acpi_status status;
@@ -960,10 +963,34 @@ acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
}
status = acpi_ns_get_attached_data(node, handler, data);
+ if (ACPI_SUCCESS(status) && callback) {
+ callback(*data);
+ }
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return (status);
}
+ACPI_EXPORT_SYMBOL(acpi_get_data_full)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_data
+ *
+ * PARAMETERS: obj_handle - Namespace node
+ * handler - Handler used in call to attach_data
+ * data - Where the data is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve data that was previously attached to a namespace node.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
+{
+ return acpi_get_data_full(obj_handle, handler, data, NULL);
+}
+
ACPI_EXPORT_SYMBOL(acpi_get_data)
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c
index 3a4bd3ff49a3..8c6c11ce9760 100644
--- a/drivers/acpi/acpica/nsxfname.c
+++ b/drivers/acpi/acpica/nsxfname.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c
index 0e6d79e462d4..dae9401be7a2 100644
--- a/drivers/acpi/acpica/nsxfobj.c
+++ b/drivers/acpi/acpica/nsxfobj.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 91a5a69db80c..314d314340ae 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c
index 065b44ae538f..b058e2390fdd 100644
--- a/drivers/acpi/acpica/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -480,6 +480,10 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
status = AE_OK;
}
+ if (status == AE_CTRL_TERMINATE) {
+ return_ACPI_STATUS(status);
+ }
+
status =
acpi_ps_complete_op(walk_state, &op,
status);
diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c
index 95dc608a66a8..a6885077d59e 100644
--- a/drivers/acpi/acpica/psobject.c
+++ b/drivers/acpi/acpica/psobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -219,7 +219,10 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
status = walk_state->descending_callback(walk_state, op);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog"));
+ if (status != AE_CTRL_TERMINATE) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "During name lookup/catalog"));
+ }
return_ACPI_STATUS(status);
}
@@ -230,7 +233,7 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
status = acpi_ps_next_parse_state(walk_state, *op, status);
if (ACPI_FAILURE(status)) {
if (status == AE_CTRL_PENDING) {
- return_ACPI_STATUS(AE_CTRL_PARSE_PENDING);
+ status = AE_CTRL_PARSE_PENDING;
}
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c
index 1b659e59710a..1755d2ac5656 100644
--- a/drivers/acpi/acpica/psopcode.c
+++ b/drivers/acpi/acpica/psopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c
index b0c9787dbe61..0d8d37ffd04d 100644
--- a/drivers/acpi/acpica/psopinfo.c
+++ b/drivers/acpi/acpica/psopinfo.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c
index 79d9a28dedef..6d27b597394e 100644
--- a/drivers/acpi/acpica/psparse.c
+++ b/drivers/acpi/acpica/psparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c
index 6a4b6fb39f32..32d250feea21 100644
--- a/drivers/acpi/acpica/psscope.c
+++ b/drivers/acpi/acpica/psscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c
index 877dc0de8df3..0b64181e7720 100644
--- a/drivers/acpi/acpica/pstree.c
+++ b/drivers/acpi/acpica/pstree.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c
index 91fa73a6e55e..3cd48802eede 100644
--- a/drivers/acpi/acpica/psutils.c
+++ b/drivers/acpi/acpica/psutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c
index abd65624754f..9cb07e1e76d9 100644
--- a/drivers/acpi/acpica/pswalk.c
+++ b/drivers/acpi/acpica/pswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c
index fcb7a840e996..e135acaa5e1c 100644
--- a/drivers/acpi/acpica/psxface.c
+++ b/drivers/acpi/acpica/psxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c
index f3a9276ac665..916fd095ff34 100644
--- a/drivers/acpi/acpica/rsaddr.c
+++ b/drivers/acpi/acpica/rsaddr.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c
index b60c9cf82862..689556744b03 100644
--- a/drivers/acpi/acpica/rscalc.c
+++ b/drivers/acpi/acpica/rscalc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -636,7 +636,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
for (index = 0; index < number_of_elements; index++) {
- /* Dereference the sub-package */
+ /* Dereference the subpackage */
package_element = *top_object_list;
diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c
index 3a2ace93e62c..75d369050657 100644
--- a/drivers/acpi/acpica/rscreate.c
+++ b/drivers/acpi/acpica/rscreate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -273,7 +273,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
*/
user_prt->length = (sizeof(struct acpi_pci_routing_table) - 4);
- /* Each sub-package must be of length 4 */
+ /* Each subpackage must be of length 4 */
if ((*top_object_list)->package.count != 4) {
ACPI_ERROR((AE_INFO,
@@ -283,7 +283,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
}
/*
- * Dereference the sub-package.
+ * Dereference the subpackage.
* The sub_object_list will now point to an array of the four IRQ
* elements: [Address, Pin, Source, source_index]
*/
@@ -292,7 +292,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
/* 1) First subobject: Dereference the PRT.Address */
obj_desc = sub_object_list[0];
- if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
+ if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO,
"(PRT[%u].Address) Need Integer, found %s",
index,
@@ -305,7 +305,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
/* 2) Second subobject: Dereference the PRT.Pin */
obj_desc = sub_object_list[1];
- if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
+ if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO,
"(PRT[%u].Pin) Need Integer, found %s",
index,
@@ -394,7 +394,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
/* 4) Fourth subobject: Dereference the PRT.source_index */
obj_desc = sub_object_list[3];
- if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
+ if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO,
"(PRT[%u].SourceIndex) Need Integer, found %s",
index,
diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c
index 8a2d4986b0aa..c3c56b5a9788 100644
--- a/drivers/acpi/acpica/rsdump.c
+++ b/drivers/acpi/acpica/rsdump.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,8 @@
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsdump")
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER)
/* Local prototypes */
static void acpi_rs_out_string(char *title, char *value);
diff --git a/drivers/acpi/acpica/rsdumpinfo.c b/drivers/acpi/acpica/rsdumpinfo.c
index 46192bd53653..2f9332d5c973 100644
--- a/drivers/acpi/acpica/rsdumpinfo.c
+++ b/drivers/acpi/acpica/rsdumpinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,7 @@
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsdumpinfo")
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER)
#define ACPI_RSD_OFFSET(f) (u8) ACPI_OFFSET (union acpi_resource_data,f)
#define ACPI_PRT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_pci_routing_table,f)
#define ACPI_RSD_TABLE_SIZE(name) (sizeof(name) / sizeof (struct acpi_rsdump_info))
diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c
index 41fed78e0de6..9d3f8a9a24bd 100644
--- a/drivers/acpi/acpica/rsinfo.c
+++ b/drivers/acpi/acpica/rsinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -132,8 +132,7 @@ struct acpi_rsconvert_info *acpi_gbl_convert_resource_serial_bus_dispatch[] = {
acpi_rs_convert_uart_serial_bus,
};
-#ifdef ACPI_FUTURE_USAGE
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUGGER)
/* Dispatch table for resource dump functions */
@@ -168,7 +167,6 @@ struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[] = {
};
#endif
-#endif /* ACPI_FUTURE_USAGE */
/*
* Base sizes for external AML resource descriptors, indexed by internal type.
* Includes size of the descriptor header (1 byte for small descriptors,
diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c
index ca183755a6f9..19d64873290a 100644
--- a/drivers/acpi/acpica/rsio.c
+++ b/drivers/acpi/acpica/rsio.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c
index 364decc1028a..3461f7db26df 100644
--- a/drivers/acpi/acpica/rsirq.c
+++ b/drivers/acpi/acpica/rsirq.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c
index 6053aa182093..77291293af64 100644
--- a/drivers/acpi/acpica/rslist.c
+++ b/drivers/acpi/acpica/rslist.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c
index ebc773a1b350..eab4483ff5f8 100644
--- a/drivers/acpi/acpica/rsmemory.c
+++ b/drivers/acpi/acpica/rsmemory.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c
index c99cec9cefde..41eea4bc089c 100644
--- a/drivers/acpi/acpica/rsmisc.c
+++ b/drivers/acpi/acpica/rsmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c
index fe49fc43e10f..9e8407223d95 100644
--- a/drivers/acpi/acpica/rsserial.c
+++ b/drivers/acpi/acpica/rsserial.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c
index 14a7982c9961..897a5ceb0420 100644
--- a/drivers/acpi/acpica/rsutils.c
+++ b/drivers/acpi/acpica/rsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c
index 01e476988aae..877ab9202133 100644
--- a/drivers/acpi/acpica/rsxface.c
+++ b/drivers/acpi/acpica/rsxface.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 8f89263ac47e..ec14588254d4 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c
index e4f4f02d49e7..c12003947bd5 100644
--- a/drivers/acpi/acpica/tbfind.c
+++ b/drivers/acpi/acpica/tbfind.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c
index 634357d51fe9..e3040947e9a0 100644
--- a/drivers/acpi/acpica/tbinstal.c
+++ b/drivers/acpi/acpica/tbinstal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -292,10 +292,11 @@ struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header
new_table = acpi_os_map_memory(new_address, new_table_length);
if (!new_table) {
ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY,
- "%4.4s %p Attempted physical table override failed",
+ "%4.4s " ACPI_PRINTF_UINT
+ " Attempted physical table override failed",
table_header->signature,
- ACPI_CAST_PTR(void,
- table_desc->address)));
+ ACPI_FORMAT_TO_UINT(table_desc->
+ address)));
return (NULL);
}
@@ -308,11 +309,11 @@ struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header
finish_override:
- ACPI_INFO((AE_INFO,
- "%4.4s %p %s table override, new table: %p",
+ ACPI_INFO((AE_INFO, "%4.4s " ACPI_PRINTF_UINT
+ " %s table override, new table: " ACPI_PRINTF_UINT,
table_header->signature,
- ACPI_CAST_PTR(void, table_desc->address),
- override_type, new_table));
+ ACPI_FORMAT_TO_UINT(table_desc->address),
+ override_type, ACPI_FORMAT_TO_UINT(new_table)));
/* We can now unmap/delete the original table (if fully mapped) */
diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c
index 6866e767ba90..df3bb20ea325 100644
--- a/drivers/acpi/acpica/tbprint.c
+++ b/drivers/acpi/acpica/tbprint.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -128,15 +128,17 @@ acpi_tb_print_table_header(acpi_physical_address address,
struct acpi_table_header local_header;
/*
- * The reason that the Address is cast to a void pointer is so that we
- * can use %p which will work properly on both 32-bit and 64-bit hosts.
+ * The reason that we use ACPI_PRINTF_UINT and ACPI_FORMAT_TO_UINT is to
+ * support both 32-bit and 64-bit hosts/addresses in a consistent manner.
+ * The %p specifier does not emit uniform output on all hosts. On some,
+ * leading zeros are not supported.
*/
if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
/* FACS only has signature and length fields */
- ACPI_INFO((AE_INFO, "%4.4s %p %06X",
- header->signature, ACPI_CAST_PTR(void, address),
+ ACPI_INFO((AE_INFO, "%-4.4s " ACPI_PRINTF_UINT " %06X",
+ header->signature, ACPI_FORMAT_TO_UINT(address),
header->length));
} else if (ACPI_VALIDATE_RSDP_SIG(header->signature)) {
@@ -147,8 +149,9 @@ acpi_tb_print_table_header(acpi_physical_address address,
header)->oem_id, ACPI_OEM_ID_SIZE);
acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE);
- ACPI_INFO((AE_INFO, "RSDP %p %06X (v%.2d %6.6s)",
- ACPI_CAST_PTR(void, address),
+ ACPI_INFO((AE_INFO,
+ "RSDP " ACPI_PRINTF_UINT " %06X (v%.2d %-6.6s)",
+ ACPI_FORMAT_TO_UINT(address),
(ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
revision >
0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
@@ -162,8 +165,9 @@ acpi_tb_print_table_header(acpi_physical_address address,
acpi_tb_cleanup_table_header(&local_header, header);
ACPI_INFO((AE_INFO,
- "%4.4s %p %06X (v%.2d %6.6s %8.8s %08X %4.4s %08X)",
- local_header.signature, ACPI_CAST_PTR(void, address),
+ "%-4.4s " ACPI_PRINTF_UINT
+ " %06X (v%.2d %-6.6s %-8.8s %08X %-4.4s %08X)",
+ local_header.signature, ACPI_FORMAT_TO_UINT(address),
local_header.length, local_header.revision,
local_header.oem_id, local_header.oem_table_id,
local_header.oem_revision,
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 6412d3c301cb..a4702eee91a8 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c
index db826eaadd1c..a1593159d9ea 100644
--- a/drivers/acpi/acpica/tbxface.c
+++ b/drivers/acpi/acpica/tbxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c
index 60b5a871833c..0909420fc776 100644
--- a/drivers/acpi/acpica/tbxfload.c
+++ b/drivers/acpi/acpica/tbxfload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c
index e4e1468877c3..65ab8fed3d5e 100644
--- a/drivers/acpi/acpica/tbxfroot.c
+++ b/drivers/acpi/acpica/tbxfroot.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c
index 2c2b6ae5dfc4..a1acec9d2ef3 100644
--- a/drivers/acpi/acpica/utaddress.c
+++ b/drivers/acpi/acpica/utaddress.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c
index 1851762fc5b5..efac83c606dc 100644
--- a/drivers/acpi/acpica/utalloc.c
+++ b/drivers/acpi/acpica/utalloc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c
index 11fde93be120..3c1699740653 100644
--- a/drivers/acpi/acpica/utbuffer.c
+++ b/drivers/acpi/acpica/utbuffer.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c
index cacd2fd9e665..78fde0aac487 100644
--- a/drivers/acpi/acpica/utcache.c
+++ b/drivers/acpi/acpica/utcache.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c
index edff4e653d9a..270c16464dd9 100644
--- a/drivers/acpi/acpica/utcopy.c
+++ b/drivers/acpi/acpica/utcopy.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -535,10 +535,10 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
case ACPI_TYPE_LOCAL_REFERENCE:
- /* TBD: should validate incoming handle */
+ /* An incoming reference is defined to be a namespace node */
- internal_object->reference.class = ACPI_REFCLASS_NAME;
- internal_object->reference.node =
+ internal_object->reference.class = ACPI_REFCLASS_REFOF;
+ internal_object->reference.object =
external_object->reference.handle;
break;
diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c
index d971c8631263..21a20ac5b1e1 100644
--- a/drivers/acpi/acpica/utdebug.c
+++ b/drivers/acpi/acpica/utdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c
index b3f31dd89a45..fbfa9eca011f 100644
--- a/drivers/acpi/acpica/utdecode.c
+++ b/drivers/acpi/acpica/utdecode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index c07d2227ea42..a3516de213fa 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -75,6 +75,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
union acpi_operand_object *handler_desc;
union acpi_operand_object *second_desc;
union acpi_operand_object *next_desc;
+ union acpi_operand_object *start_desc;
union acpi_operand_object **last_obj_ptr;
ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object);
@@ -235,10 +236,11 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
if (handler_desc) {
next_desc =
handler_desc->address_space.region_list;
+ start_desc = next_desc;
last_obj_ptr =
&handler_desc->address_space.region_list;
- /* Remove the region object from the handler's list */
+ /* Remove the region object from the handler list */
while (next_desc) {
if (next_desc == object) {
@@ -247,10 +249,19 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
break;
}
- /* Walk the linked list of handler */
+ /* Walk the linked list of handlers */
last_obj_ptr = &next_desc->region.next;
next_desc = next_desc->region.next;
+
+ /* Prevent infinite loop if list is corrupted */
+
+ if (next_desc == start_desc) {
+ ACPI_ERROR((AE_INFO,
+ "Circular region list in address handler object %p",
+ handler_desc));
+ return_VOID;
+ }
}
if (handler_desc->address_space.handler_flags &
diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c
index 154fdcaa5830..8e544d4688cd 100644
--- a/drivers/acpi/acpica/uterror.c
+++ b/drivers/acpi/acpica/uterror.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c
index 16fb90506db7..8fed1482d228 100644
--- a/drivers/acpi/acpica/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utexcep.c b/drivers/acpi/acpica/utexcep.c
index 3cf7b597edb9..0403dcaabaf2 100644
--- a/drivers/acpi/acpica/utexcep.c
+++ b/drivers/acpi/acpica/utexcep.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index 030cb0dc673c..f3abeae9d2f8 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,31 +55,27 @@ ACPI_MODULE_NAME("utglobal")
* Static global variable initialization.
*
******************************************************************************/
-/*
- * We want the debug switches statically initialized so they
- * are already set when the debugger is entered.
- */
-/* Debug switch - level and trace mask */
+/* Debug output control masks */
u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT;
-/* Debug switch - layer (component) mask */
-
u32 acpi_dbg_layer = 0;
-u32 acpi_gbl_nesting_level = 0;
-/* Debugger globals */
+/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
-u8 acpi_gbl_db_terminate_threads = FALSE;
-u8 acpi_gbl_abort_method = FALSE;
-u8 acpi_gbl_method_executing = FALSE;
+struct acpi_table_fadt acpi_gbl_FADT;
+u32 acpi_gbl_trace_flags;
+acpi_name acpi_gbl_trace_method_name;
+u8 acpi_gbl_system_awake_and_running;
+u32 acpi_current_gpe_count;
-/* System flags */
-
-u32 acpi_gbl_startup_flags = 0;
-
-/* System starts uninitialized */
+/*
+ * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning
+ * that the ACPI hardware is no longer required. A flag in the FADT indicates
+ * a reduced HW machine, and that flag is duplicated here for convenience.
+ */
+u8 acpi_gbl_reduced_hardware;
-u8 acpi_gbl_shutdown = TRUE;
+/* Various state name strings */
const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = {
"\\_S0_",
@@ -335,7 +331,6 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_DSDT = NULL;
acpi_gbl_cm_single_step = FALSE;
- acpi_gbl_db_terminate_threads = FALSE;
acpi_gbl_shutdown = FALSE;
acpi_gbl_ns_lookup_count = 0;
acpi_gbl_ps_find_count = 0;
@@ -382,6 +377,10 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_disable_mem_tracking = FALSE;
#endif
+#ifdef ACPI_DEBUGGER
+ acpi_gbl_db_terminate_threads = FALSE;
+#endif
+
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c
index bfca7b4b6731..4b12880e5b11 100644
--- a/drivers/acpi/acpica/utids.c
+++ b/drivers/acpi/acpica/utids.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index c5d1ac44c07d..5f56fc49021e 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c
index 5c26ad420344..dc6e96547f18 100644
--- a/drivers/acpi/acpica/utlock.c
+++ b/drivers/acpi/acpica/utlock.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c
index 909fe66e1934..d44dee6ee10a 100644
--- a/drivers/acpi/acpica/utmath.c
+++ b/drivers/acpi/acpica/utmath.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c
index 02f9101b65e4..2e2bb14e1099 100644
--- a/drivers/acpi/acpica/utmisc.c
+++ b/drivers/acpi/acpica/utmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index 08c323245584..82717fff9ffc 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c
index 517af700399d..dfa9009bfc87 100644
--- a/drivers/acpi/acpica/utobject.c
+++ b/drivers/acpi/acpica/utobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c
index 8856bd37bc76..685766fc6ca8 100644
--- a/drivers/acpi/acpica/utosi.c
+++ b/drivers/acpi/acpica/utosi.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,6 +47,31 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utosi")
+/******************************************************************************
+ *
+ * ACPICA policy for new _OSI strings:
+ *
+ * It is the stated policy of ACPICA that new _OSI strings will be integrated
+ * into this module as soon as possible after they are defined. It is strongly
+ * recommended that all ACPICA hosts mirror this policy and integrate any
+ * changes to this module as soon as possible. There are several historical
+ * reasons behind this policy:
+ *
+ * 1) New BIOSs tend to test only the case where the host responds TRUE to
+ * the latest version of Windows, which would respond to the latest/newest
+ * _OSI string. Not responding TRUE to the latest version of Windows will
+ * risk executing untested code paths throughout the DSDT and SSDTs.
+ *
+ * 2) If a new _OSI string is recognized only after a significant delay, this
+ * has the potential to cause problems on existing working machines because
+ * of the possibility that a new and different path through the ASL code
+ * will be executed.
+ *
+ * 3) New _OSI strings are tending to come out about once per year. A delay
+ * in recognizing a new string for a significant amount of time risks the
+ * release of another string which only compounds the initial problem.
+ *
+ *****************************************************************************/
/*
* Strings supported by the _OSI predefined control method (which is
* implemented internally within this module.)
@@ -74,6 +99,7 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = {
{"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2}, /* Windows Vista SP2 - Added 09/2010 */
{"Windows 2009", NULL, 0, ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */
{"Windows 2012", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8 and Server 2012 - Added 08/2012 */
+ {"Windows 2013", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */
/* Feature Group Strings */
diff --git a/drivers/acpi/acpica/utownerid.c b/drivers/acpi/acpica/utownerid.c
index eb3aca761369..36bec57ebd23 100644
--- a/drivers/acpi/acpica/utownerid.c
+++ b/drivers/acpi/acpica/utownerid.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utpredef.c b/drivers/acpi/acpica/utpredef.c
index 2b1ce4cd3207..db30caff130a 100644
--- a/drivers/acpi/acpica/utpredef.c
+++ b/drivers/acpi/acpica/utpredef.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c
index 2c2accb9e534..14cb6c0c8be2 100644
--- a/drivers/acpi/acpica/utresrc.c
+++ b/drivers/acpi/acpica/utresrc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,8 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utresrc")
-#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
/*
* Strings used to decode resource descriptors.
* Used by both the disassembler and the debugger resource dump routines
diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c
index 03c4c2febd84..1cc97a752c15 100644
--- a/drivers/acpi/acpica/utstate.c
+++ b/drivers/acpi/acpica/utstate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c
index 45c0eb26b33d..77219336c7e0 100644
--- a/drivers/acpi/acpica/utstring.c
+++ b/drivers/acpi/acpica/utstring.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c
index c0027773cccb..7d0ee969d781 100644
--- a/drivers/acpi/acpica/uttrack.c
+++ b/drivers/acpi/acpica/uttrack.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -276,7 +276,8 @@ acpi_ut_free_and_track(void *allocation,
}
acpi_os_free(debug_block);
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed\n", allocation));
+ ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed (block %p)\n",
+ allocation, debug_block));
return_VOID;
}
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index be322c83643a..502a8492dc83 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c
index f7edb88f6054..edd861102f1b 100644
--- a/drivers/acpi/acpica/utxferror.c
+++ b/drivers/acpi/acpica/utxferror.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c
index 246ef68681f4..13380d818462 100644
--- a/drivers/acpi/acpica/utxfinit.c
+++ b/drivers/acpi/acpica/utxfinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c
index 312299721ba1..2a0f9e04d3a4 100644
--- a/drivers/acpi/acpica/utxfmutex.c
+++ b/drivers/acpi/acpica/utxfmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index 3650b2183227..c4dac7150960 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -12,7 +12,7 @@ config ACPI_APEI
config ACPI_APEI_GHES
bool "APEI Generic Hardware Error Source"
- depends on ACPI_APEI && X86
+ depends on ACPI_APEI
select ACPI_HED
select IRQ_WORK
select GENERIC_ALLOCATOR
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 018a42883706..9a2c63b20050 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -39,15 +39,13 @@
#include <linux/acpi.h>
#include <linux/power_supply.h>
+#include "battery.h"
+
#define PREFIX "ACPI: "
#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
-#define ACPI_BATTERY_CLASS "battery"
#define ACPI_BATTERY_DEVICE_NAME "Battery"
-#define ACPI_BATTERY_NOTIFY_STATUS 0x80
-#define ACPI_BATTERY_NOTIFY_INFO 0x81
-#define ACPI_BATTERY_NOTIFY_THRESHOLD 0x82
/* Battery power unit: 0 means mW, 1 means mA */
#define ACPI_BATTERY_POWER_UNIT_MA 1
@@ -736,6 +734,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event,
acpi_battery_present(battery));
+ acpi_notifier_call_chain(device, event, acpi_battery_present(battery));
/* acpi_battery_update could remove power_supply object */
if (old && battery->bat.dev)
power_supply_changed(&battery->bat);
@@ -841,6 +840,8 @@ static int acpi_battery_resume(struct device *dev)
acpi_battery_update(battery);
return 0;
}
+#else
+#define acpi_battery_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume);
diff --git a/drivers/acpi/battery.h b/drivers/acpi/battery.h
new file mode 100644
index 000000000000..6c084976987d
--- /dev/null
+++ b/drivers/acpi/battery.h
@@ -0,0 +1,10 @@
+#ifndef __ACPI_BATTERY_H
+#define __ACPI_BATTERY_H
+
+#define ACPI_BATTERY_CLASS "battery"
+
+#define ACPI_BATTERY_NOTIFY_STATUS 0x80
+#define ACPI_BATTERY_NOTIFY_INFO 0x81
+#define ACPI_BATTERY_NOTIFY_THRESHOLD 0x82
+
+#endif
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index 10e4964d051a..afec4526c48a 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -260,14 +260,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
},
{
.callback = dmi_disable_osi_win8,
- .ident = "Dell Inspiron 15R SE",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7520"),
- },
- },
- {
- .callback = dmi_disable_osi_win8,
.ident = "ThinkPad Edge E530",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -322,56 +314,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_VERSION, "2349D15"),
},
},
- {
- .callback = dmi_disable_osi_win8,
- .ident = "HP ProBook 2013 models",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "),
- DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
- },
- },
- {
- .callback = dmi_disable_osi_win8,
- .ident = "HP EliteBook 2013 models",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "),
- DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
- },
- },
- {
- .callback = dmi_disable_osi_win8,
- .ident = "HP ZBook 14",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"),
- },
- },
- {
- .callback = dmi_disable_osi_win8,
- .ident = "HP ZBook 15",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"),
- },
- },
- {
- .callback = dmi_disable_osi_win8,
- .ident = "HP ZBook 17",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"),
- },
- },
- {
- .callback = dmi_disable_osi_win8,
- .ident = "HP EliteBook 8780w",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"),
- },
- },
/*
* BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index fcb59c21c68d..e7e5844c87d0 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -311,9 +311,7 @@ static void acpi_bus_osc_support(void)
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PPC_OST_SUPPORT;
#endif
-#ifdef ACPI_HOTPLUG_OST
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT;
-#endif
if (!ghes_disable)
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT;
@@ -340,60 +338,77 @@ static void acpi_bus_osc_support(void)
*/
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
{
- struct acpi_device *device = NULL;
+ struct acpi_device *adev;
struct acpi_driver *driver;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
- type, handle));
+ acpi_status status;
+ u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
switch (type) {
-
case ACPI_NOTIFY_BUS_CHECK:
- /* TBD */
+ acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
break;
case ACPI_NOTIFY_DEVICE_CHECK:
- /* TBD */
+ acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
break;
case ACPI_NOTIFY_DEVICE_WAKE:
- /* TBD */
+ acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n");
break;
case ACPI_NOTIFY_EJECT_REQUEST:
- /* TBD */
+ acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
break;
case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
+ acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n");
/* TBD: Exactly what does 'light' mean? */
break;
case ACPI_NOTIFY_FREQUENCY_MISMATCH:
- /* TBD */
+ acpi_handle_err(handle, "Device cannot be configured due "
+ "to a frequency mismatch\n");
break;
case ACPI_NOTIFY_BUS_MODE_MISMATCH:
- /* TBD */
+ acpi_handle_err(handle, "Device cannot be configured due "
+ "to a bus mode mismatch\n");
break;
case ACPI_NOTIFY_POWER_FAULT:
- /* TBD */
+ acpi_handle_err(handle, "Device has suffered a power fault\n");
break;
default:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Received unknown/unsupported notification [%08x]\n",
- type));
- break;
+ acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
+ ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
+ goto err;
}
- acpi_bus_get_device(handle, &device);
- if (device) {
- driver = device->driver;
- if (driver && driver->ops.notify &&
- (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
- driver->ops.notify(device, type);
+ adev = acpi_bus_get_acpi_device(handle);
+ if (!adev)
+ goto err;
+
+ driver = adev->driver;
+ if (driver && driver->ops.notify &&
+ (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
+ driver->ops.notify(adev, type);
+
+ switch (type) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ status = acpi_hotplug_schedule(adev, type);
+ if (ACPI_SUCCESS(status))
+ return;
+ default:
+ break;
}
+ acpi_bus_put_acpi_device(adev);
+ return;
+
+ err:
+ acpi_evaluate_ost(handle, type, ost_code, NULL);
}
/* --------------------------------------------------------------------------
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 11c11f6b8fa1..db35594d4df7 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -80,6 +80,8 @@ static void acpi_button_notify(struct acpi_device *device, u32 event);
#ifdef CONFIG_PM_SLEEP
static int acpi_button_resume(struct device *dev);
+#else
+#define acpi_button_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(acpi_button_pm, NULL, acpi_button_resume);
@@ -300,6 +302,10 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
input_sync(input);
pm_wakeup_event(&device->dev, 0);
+ acpi_bus_generate_netlink_event(
+ device->pnp.device_class,
+ dev_name(&device->dev),
+ event, ++button->pushed);
}
break;
default:
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 368f9ddb8480..63119d09b354 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -31,8 +31,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define _COMPONENT ACPI_CONTAINER_COMPONENT
ACPI_MODULE_NAME("container");
@@ -68,6 +66,9 @@ static int container_device_attach(struct acpi_device *adev,
struct device *dev;
int ret;
+ if (adev->flags.is_dock_station)
+ return 0;
+
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return -ENOMEM;
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index c14a00d3dca6..d047739f3380 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -901,15 +901,30 @@ EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
int acpi_subsys_prepare(struct device *dev)
{
/*
- * Follow PCI and resume devices suspended at run time before running
- * their system suspend callbacks.
+ * Devices having power.ignore_children set may still be necessary for
+ * suspending their children in the next phase of device suspend.
*/
- pm_runtime_resume(dev);
+ if (dev->power.ignore_children)
+ pm_runtime_resume(dev);
+
return pm_generic_prepare(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
/**
+ * acpi_subsys_suspend - Run the device driver's suspend callback.
+ * @dev: Device to handle.
+ *
+ * Follow PCI and resume devices suspended at run time before running their
+ * system suspend callbacks.
+ */
+int acpi_subsys_suspend(struct device *dev)
+{
+ pm_runtime_resume(dev);
+ return pm_generic_suspend(dev);
+}
+
+/**
* acpi_subsys_suspend_late - Suspend device using ACPI.
* @dev: Device to suspend.
*
@@ -937,6 +952,23 @@ int acpi_subsys_resume_early(struct device *dev)
return ret ? ret : pm_generic_resume_early(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_resume_early);
+
+/**
+ * acpi_subsys_freeze - Run the device driver's freeze callback.
+ * @dev: Device to handle.
+ */
+int acpi_subsys_freeze(struct device *dev)
+{
+ /*
+ * This used to be done in acpi_subsys_prepare() for all devices and
+ * some drivers may depend on it, so do it here. Ideally, however,
+ * runtime-suspended devices should not be touched during freeze/thaw
+ * transitions.
+ */
+ pm_runtime_resume(dev);
+ return pm_generic_freeze(dev);
+}
+
#endif /* CONFIG_PM_SLEEP */
static struct dev_pm_domain acpi_general_pm_domain = {
@@ -947,8 +979,11 @@ static struct dev_pm_domain acpi_general_pm_domain = {
#endif
#ifdef CONFIG_PM_SLEEP
.prepare = acpi_subsys_prepare,
+ .suspend = acpi_subsys_suspend,
.suspend_late = acpi_subsys_suspend_late,
.resume_early = acpi_subsys_resume_early,
+ .freeze = acpi_subsys_freeze,
+ .poweroff = acpi_subsys_suspend,
.poweroff_late = acpi_subsys_suspend_late,
.restore_early = acpi_subsys_resume_early,
#endif
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index e9b3081c4fe9..f0fc6260266b 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -1,7 +1,9 @@
/*
* dock.c - ACPI dock station driver
*
- * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+ * Copyright (C) 2006, 2014, Intel Corp.
+ * Author: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+ * Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -35,8 +37,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver"
ACPI_MODULE_NAME("dock");
@@ -68,15 +68,10 @@ struct dock_station {
};
static LIST_HEAD(dock_stations);
static int dock_station_count;
-static DEFINE_MUTEX(hotplug_lock);
struct dock_dependent_device {
struct list_head list;
- acpi_handle handle;
- const struct acpi_dock_ops *hp_ops;
- void *hp_context;
- unsigned int hp_refcount;
- void (*hp_release)(void *);
+ struct acpi_device *adev;
};
#define DOCK_DOCKING 0x00000001
@@ -98,13 +93,13 @@ enum dock_callback_type {
*****************************************************************************/
/**
* add_dock_dependent_device - associate a device with the dock station
- * @ds: The dock station
- * @handle: handle of the dependent device
+ * @ds: Dock station.
+ * @adev: Dependent ACPI device object.
*
* Add the dependent device to the dock's dependent device list.
*/
-static int __init
-add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
+static int add_dock_dependent_device(struct dock_station *ds,
+ struct acpi_device *adev)
{
struct dock_dependent_device *dd;
@@ -112,180 +107,120 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
if (!dd)
return -ENOMEM;
- dd->handle = handle;
+ dd->adev = adev;
INIT_LIST_HEAD(&dd->list);
list_add_tail(&dd->list, &ds->dependent_devices);
return 0;
}
-static void remove_dock_dependent_devices(struct dock_station *ds)
+static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
+ enum dock_callback_type cb_type)
{
- struct dock_dependent_device *dd, *aux;
+ struct acpi_device *adev = dd->adev;
- list_for_each_entry_safe(dd, aux, &ds->dependent_devices, list) {
- list_del(&dd->list);
- kfree(dd);
- }
-}
+ acpi_lock_hp_context();
-/**
- * dock_init_hotplug - Initialize a hotplug device on a docking station.
- * @dd: Dock-dependent device.
- * @ops: Dock operations to attach to the dependent device.
- * @context: Data to pass to the @ops callbacks and @release.
- * @init: Optional initialization routine to run after setting up context.
- * @release: Optional release routine to run on removal.
- */
-static int dock_init_hotplug(struct dock_dependent_device *dd,
- const struct acpi_dock_ops *ops, void *context,
- void (*init)(void *), void (*release)(void *))
-{
- int ret = 0;
+ if (!adev->hp)
+ goto out;
- mutex_lock(&hotplug_lock);
- if (WARN_ON(dd->hp_context)) {
- ret = -EEXIST;
- } else {
- dd->hp_refcount = 1;
- dd->hp_ops = ops;
- dd->hp_context = context;
- dd->hp_release = release;
- if (init)
- init(context);
- }
- mutex_unlock(&hotplug_lock);
- return ret;
-}
+ if (cb_type == DOCK_CALL_FIXUP) {
+ void (*fixup)(struct acpi_device *);
-/**
- * dock_release_hotplug - Decrement hotplug reference counter of dock device.
- * @dd: Dock-dependent device.
- *
- * Decrement the reference counter of @dd and if 0, detach its hotplug
- * operations from it, reset its context pointer and run the optional release
- * routine if present.
- */
-static void dock_release_hotplug(struct dock_dependent_device *dd)
-{
- mutex_lock(&hotplug_lock);
- if (dd->hp_context && !--dd->hp_refcount) {
- void (*release)(void *) = dd->hp_release;
- void *context = dd->hp_context;
-
- dd->hp_ops = NULL;
- dd->hp_context = NULL;
- dd->hp_release = NULL;
- if (release)
- release(context);
- }
- mutex_unlock(&hotplug_lock);
-}
+ fixup = adev->hp->fixup;
+ if (fixup) {
+ acpi_unlock_hp_context();
+ fixup(adev);
+ return;
+ }
+ } else if (cb_type == DOCK_CALL_UEVENT) {
+ void (*uevent)(struct acpi_device *, u32);
+
+ uevent = adev->hp->uevent;
+ if (uevent) {
+ acpi_unlock_hp_context();
+ uevent(adev, event);
+ return;
+ }
+ } else {
+ int (*notify)(struct acpi_device *, u32);
-static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
- enum dock_callback_type cb_type)
-{
- acpi_notify_handler cb = NULL;
- bool run = false;
-
- mutex_lock(&hotplug_lock);
-
- if (dd->hp_context) {
- run = true;
- dd->hp_refcount++;
- if (dd->hp_ops) {
- switch (cb_type) {
- case DOCK_CALL_FIXUP:
- cb = dd->hp_ops->fixup;
- break;
- case DOCK_CALL_UEVENT:
- cb = dd->hp_ops->uevent;
- break;
- default:
- cb = dd->hp_ops->handler;
- }
+ notify = adev->hp->notify;
+ if (notify) {
+ acpi_unlock_hp_context();
+ notify(adev, event);
+ return;
}
}
- mutex_unlock(&hotplug_lock);
+ out:
+ acpi_unlock_hp_context();
+}
- if (!run)
- return;
+static struct dock_station *find_dock_station(acpi_handle handle)
+{
+ struct dock_station *ds;
- if (cb)
- cb(dd->handle, event, dd->hp_context);
+ list_for_each_entry(ds, &dock_stations, sibling)
+ if (ds->handle == handle)
+ return ds;
- dock_release_hotplug(dd);
+ return NULL;
}
/**
* find_dock_dependent_device - get a device dependent on this dock
* @ds: the dock station
- * @handle: the acpi_handle of the device we want
+ * @adev: ACPI device object to find.
*
* iterate over the dependent device list for this dock. If the
* dependent device matches the handle, return.
*/
static struct dock_dependent_device *
-find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
+find_dock_dependent_device(struct dock_station *ds, struct acpi_device *adev)
{
struct dock_dependent_device *dd;
list_for_each_entry(dd, &ds->dependent_devices, list)
- if (handle == dd->handle)
+ if (adev == dd->adev)
return dd;
return NULL;
}
-/*****************************************************************************
- * Dock functions *
- *****************************************************************************/
-static int __init is_battery(acpi_handle handle)
+void register_dock_dependent_device(struct acpi_device *adev,
+ acpi_handle dshandle)
{
- struct acpi_device_info *info;
- int ret = 1;
+ struct dock_station *ds = find_dock_station(dshandle);
- if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info)))
- return 0;
- if (!(info->valid & ACPI_VALID_HID))
- ret = 0;
- else
- ret = !strcmp("PNP0C0A", info->hardware_id.string);
-
- kfree(info);
- return ret;
+ if (ds && !find_dock_dependent_device(ds, adev))
+ add_dock_dependent_device(ds, adev);
}
-/* Check whether ACPI object is an ejectable battery or disk bay */
-static bool __init is_ejectable_bay(acpi_handle handle)
-{
- if (acpi_has_method(handle, "_EJ0") && is_battery(handle))
- return true;
-
- return acpi_bay_match(handle);
-}
+/*****************************************************************************
+ * Dock functions *
+ *****************************************************************************/
/**
* is_dock_device - see if a device is on a dock station
- * @handle: acpi handle of the device
+ * @adev: ACPI device object to check.
*
* If this device is either the dock station itself,
* or is a device dependent on the dock station, then it
* is a dock device
*/
-int is_dock_device(acpi_handle handle)
+int is_dock_device(struct acpi_device *adev)
{
struct dock_station *dock_station;
if (!dock_station_count)
return 0;
- if (acpi_dock_match(handle))
+ if (acpi_dock_match(adev->handle))
return 1;
list_for_each_entry(dock_station, &dock_stations, sibling)
- if (find_dock_dependent_device(dock_station, handle))
+ if (find_dock_dependent_device(dock_station, adev))
return 1;
return 0;
@@ -313,43 +248,6 @@ static int dock_present(struct dock_station *ds)
}
/**
- * dock_create_acpi_device - add new devices to acpi
- * @handle - handle of the device to add
- *
- * This function will create a new acpi_device for the given
- * handle if one does not exist already. This should cause
- * acpi to scan for drivers for the given devices, and call
- * matching driver's add routine.
- */
-static void dock_create_acpi_device(acpi_handle handle)
-{
- struct acpi_device *device = NULL;
- int ret;
-
- acpi_bus_get_device(handle, &device);
- if (!acpi_device_enumerated(device)) {
- ret = acpi_bus_scan(handle);
- if (ret)
- pr_debug("error adding bus, %x\n", -ret);
- }
-}
-
-/**
- * dock_remove_acpi_device - remove the acpi_device struct from acpi
- * @handle - the handle of the device to remove
- *
- * Tell acpi to remove the acpi_device. This should cause any loaded
- * driver to have it's remove routine called.
- */
-static void dock_remove_acpi_device(acpi_handle handle)
-{
- struct acpi_device *device;
-
- if (!acpi_bus_get_device(handle, &device))
- acpi_bus_trim(device);
-}
-
-/**
* hot_remove_dock_devices - Remove dock station devices.
* @ds: Dock station.
*/
@@ -366,7 +264,7 @@ static void hot_remove_dock_devices(struct dock_station *ds)
dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST, false);
list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
- dock_remove_acpi_device(dd->handle);
+ acpi_bus_trim(dd->adev);
}
/**
@@ -392,12 +290,20 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
dock_hotplug_event(dd, event, DOCK_CALL_HANDLER);
/*
- * Now make sure that an acpi_device is created for each dependent
- * device. That will cause scan handlers to be attached to device
- * objects or acpi_drivers to be stopped/started if they are present.
+ * Check if all devices have been enumerated already. If not, run
+ * acpi_bus_scan() for them and that will cause scan handlers to be
+ * attached to device objects or acpi_drivers to be stopped/started if
+ * they are present.
*/
- list_for_each_entry(dd, &ds->dependent_devices, list)
- dock_create_acpi_device(dd->handle);
+ list_for_each_entry(dd, &ds->dependent_devices, list) {
+ struct acpi_device *adev = dd->adev;
+
+ if (!acpi_device_enumerated(adev)) {
+ int ret = acpi_bus_scan(adev->handle);
+ if (ret)
+ dev_dbg(&adev->dev, "scan error %d\n", -ret);
+ }
+ }
}
static void dock_event(struct dock_station *ds, u32 event, int num)
@@ -501,71 +407,6 @@ static int dock_in_progress(struct dock_station *ds)
}
/**
- * register_hotplug_dock_device - register a hotplug function
- * @handle: the handle of the device
- * @ops: handlers to call after docking
- * @context: device specific data
- * @init: Optional initialization routine to run after registration
- * @release: Optional release routine to run on unregistration
- *
- * If a driver would like to perform a hotplug operation after a dock
- * event, they can register an acpi_notifiy_handler to be called by
- * the dock driver after _DCK is executed.
- */
-int register_hotplug_dock_device(acpi_handle handle,
- const struct acpi_dock_ops *ops, void *context,
- void (*init)(void *), void (*release)(void *))
-{
- struct dock_dependent_device *dd;
- struct dock_station *dock_station;
- int ret = -EINVAL;
-
- if (WARN_ON(!context))
- return -EINVAL;
-
- if (!dock_station_count)
- return -ENODEV;
-
- /*
- * make sure this handle is for a device dependent on the dock,
- * this would include the dock station itself
- */
- list_for_each_entry(dock_station, &dock_stations, sibling) {
- /*
- * An ATA bay can be in a dock and itself can be ejected
- * separately, so there are two 'dock stations' which need the
- * ops
- */
- dd = find_dock_dependent_device(dock_station, handle);
- if (dd && !dock_init_hotplug(dd, ops, context, init, release))
- ret = 0;
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
-
-/**
- * unregister_hotplug_dock_device - remove yourself from the hotplug list
- * @handle: the acpi handle of the device
- */
-void unregister_hotplug_dock_device(acpi_handle handle)
-{
- struct dock_dependent_device *dd;
- struct dock_station *dock_station;
-
- if (!dock_station_count)
- return;
-
- list_for_each_entry(dock_station, &dock_stations, sibling) {
- dd = find_dock_dependent_device(dock_station, handle);
- if (dd)
- dock_release_hotplug(dd);
- }
-}
-EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
-
-/**
* handle_eject_request - handle an undock request checking for error conditions
*
* Check to make sure the dock device is still present, then undock and
@@ -598,20 +439,23 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
}
/**
- * dock_notify - act upon an acpi dock notification
- * @ds: dock station
- * @event: the acpi event
+ * dock_notify - Handle ACPI dock notification.
+ * @adev: Dock station's ACPI device object.
+ * @event: Event code.
*
* If we are notified to dock, then check to see if the dock is
* present and then dock. Notify all drivers of the dock event,
* and then hotplug and devices that may need hotplugging.
*/
-static void dock_notify(struct dock_station *ds, u32 event)
+int dock_notify(struct acpi_device *adev, u32 event)
{
- acpi_handle handle = ds->handle;
- struct acpi_device *adev = NULL;
+ acpi_handle handle = adev->handle;
+ struct dock_station *ds = find_dock_station(handle);
int surprise_removal = 0;
+ if (!ds)
+ return -ENODEV;
+
/*
* According to acpi spec 3.0a, if a DEVICE_CHECK notification
* is sent and _DCK is present, it is assumed to mean an undock
@@ -632,7 +476,6 @@ static void dock_notify(struct dock_station *ds, u32 event)
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
- acpi_bus_get_device(handle, &adev);
if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) {
begin_dock(ds);
dock(ds);
@@ -662,49 +505,8 @@ static void dock_notify(struct dock_station *ds, u32 event)
else
dock_event(ds, event, UNDOCK_EVENT);
break;
- default:
- acpi_handle_err(handle, "Unknown dock event %d\n", event);
}
-}
-
-static void acpi_dock_deferred_cb(void *data, u32 event)
-{
- acpi_scan_lock_acquire();
- dock_notify(data, event);
- acpi_scan_lock_release();
-}
-
-static void dock_notify_handler(acpi_handle handle, u32 event, void *data)
-{
- if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
- && event != ACPI_NOTIFY_EJECT_REQUEST)
- return;
-
- acpi_hotplug_execute(acpi_dock_deferred_cb, data, event);
-}
-
-/**
- * find_dock_devices - find devices on the dock station
- * @handle: the handle of the device we are examining
- * @lvl: unused
- * @context: the dock station private data
- * @rv: unused
- *
- * This function is called by acpi_walk_namespace. It will
- * check to see if an object has an _EJD method. If it does, then it
- * will see if it is dependent on the dock station.
- */
-static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl,
- void *context, void **rv)
-{
- struct dock_station *ds = context;
- acpi_handle ejd = NULL;
-
- acpi_bus_get_ejd(handle, &ejd);
- if (ejd == ds->handle)
- add_dock_dependent_device(ds, handle);
-
- return AE_OK;
+ return 0;
}
/*
@@ -713,13 +515,11 @@ static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl,
static ssize_t show_docked(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct acpi_device *tmp;
-
struct dock_station *dock_station = dev->platform_data;
+ struct acpi_device *adev = NULL;
- if (!acpi_bus_get_device(dock_station->handle, &tmp))
- return snprintf(buf, PAGE_SIZE, "1\n");
- return snprintf(buf, PAGE_SIZE, "0\n");
+ acpi_bus_get_device(dock_station->handle, &adev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", acpi_device_enumerated(adev));
}
static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
@@ -805,23 +605,28 @@ static struct attribute_group dock_attribute_group = {
};
/**
- * dock_add - add a new dock station
- * @handle: the dock station handle
+ * acpi_dock_add - Add a new dock station
+ * @adev: Dock station ACPI device object.
*
- * allocated and initialize a new dock station device. Find all devices
- * that are on the dock station, and register for dock event notifications.
+ * allocated and initialize a new dock station device.
*/
-static int __init dock_add(acpi_handle handle)
+void acpi_dock_add(struct acpi_device *adev)
{
struct dock_station *dock_station, ds = { NULL, };
+ struct platform_device_info pdevinfo;
+ acpi_handle handle = adev->handle;
struct platform_device *dd;
- acpi_status status;
int ret;
- dd = platform_device_register_data(NULL, "dock", dock_station_count,
- &ds, sizeof(ds));
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ pdevinfo.name = "dock";
+ pdevinfo.id = dock_station_count;
+ pdevinfo.acpi_node.companion = adev;
+ pdevinfo.data = &ds;
+ pdevinfo.size_data = sizeof(ds);
+ dd = platform_device_register_full(&pdevinfo);
if (IS_ERR(dd))
- return PTR_ERR(dd);
+ return;
dock_station = dd->dev.platform_data;
@@ -839,72 +644,29 @@ static int __init dock_add(acpi_handle handle)
dock_station->flags |= DOCK_IS_DOCK;
if (acpi_ata_match(handle))
dock_station->flags |= DOCK_IS_ATA;
- if (is_battery(handle))
+ if (acpi_device_is_battery(adev))
dock_station->flags |= DOCK_IS_BAT;
ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group);
if (ret)
goto err_unregister;
- /* Find dependent devices */
- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, find_dock_devices, NULL,
- dock_station, NULL);
-
/* add the dock station as a device dependent on itself */
- ret = add_dock_dependent_device(dock_station, handle);
+ ret = add_dock_dependent_device(dock_station, adev);
if (ret)
goto err_rmgroup;
- status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- dock_notify_handler, dock_station);
- if (ACPI_FAILURE(status)) {
- ret = -ENODEV;
- goto err_rmgroup;
- }
-
dock_station_count++;
list_add(&dock_station->sibling, &dock_stations);
- return 0;
+ adev->flags.is_dock_station = true;
+ dev_info(&adev->dev, "ACPI dock station (docks/bays count: %d)\n",
+ dock_station_count);
+ return;
err_rmgroup:
- remove_dock_dependent_devices(dock_station);
sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
+
err_unregister:
platform_device_unregister(dd);
acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret);
- return ret;
-}
-
-/**
- * find_dock_and_bay - look for dock stations and bays
- * @handle: acpi handle of a device
- * @lvl: unused
- * @context: unused
- * @rv: unused
- *
- * This is called by acpi_walk_namespace to look for dock stations and bays.
- */
-static acpi_status __init
-find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- if (acpi_dock_match(handle) || is_ejectable_bay(handle))
- dock_add(handle);
-
- return AE_OK;
-}
-
-void __init acpi_dock_init(void)
-{
- /* look for dock stations and bays */
- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL);
-
- if (!dock_station_count) {
- pr_info(PREFIX "No dock devices found.\n");
- return;
- }
-
- pr_info(PREFIX "%s: %d docks/bays found\n",
- ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 959d41acc108..d7d32c28829b 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -67,6 +67,8 @@ enum ec_command {
#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
#define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */
+#define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query
+ * when trying to clear the EC */
enum {
EC_FLAGS_QUERY_PENDING, /* Query is pending */
@@ -116,6 +118,7 @@ EXPORT_SYMBOL(first_ec);
static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
+static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
/* --------------------------------------------------------------------------
Transaction Management
@@ -440,6 +443,29 @@ acpi_handle ec_get_handle(void)
EXPORT_SYMBOL(ec_get_handle);
+static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data);
+
+/*
+ * Clears stale _Q events that might have accumulated in the EC.
+ * Run with locked ec mutex.
+ */
+static void acpi_ec_clear(struct acpi_ec *ec)
+{
+ int i, status;
+ u8 value = 0;
+
+ for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
+ status = acpi_ec_query_unlocked(ec, &value);
+ if (status || !value)
+ break;
+ }
+
+ if (unlikely(i == ACPI_EC_CLEAR_MAX))
+ pr_warn("Warning: Maximum of %d stale EC events cleared\n", i);
+ else
+ pr_info("%d stale EC events cleared\n", i);
+}
+
void acpi_ec_block_transactions(void)
{
struct acpi_ec *ec = first_ec;
@@ -463,6 +489,10 @@ void acpi_ec_unblock_transactions(void)
mutex_lock(&ec->mutex);
/* Allow transactions to be carried out again */
clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
+
+ if (EC_FLAGS_CLEAR_ON_RESUME)
+ acpi_ec_clear(ec);
+
mutex_unlock(&ec->mutex);
}
@@ -821,6 +851,13 @@ static int acpi_ec_add(struct acpi_device *device)
/* EC is fully operational, allow queries */
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+
+ /* Clear stale _Q events if hardware might require that */
+ if (EC_FLAGS_CLEAR_ON_RESUME) {
+ mutex_lock(&ec->mutex);
+ acpi_ec_clear(ec);
+ mutex_unlock(&ec->mutex);
+ }
return ret;
}
@@ -922,6 +959,30 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
return 0;
}
+/*
+ * On some hardware it is necessary to clear events accumulated by the EC during
+ * sleep. These ECs stop reporting GPEs until they are manually polled, if too
+ * many events are accumulated. (e.g. Samsung Series 5/9 notebooks)
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=44161
+ *
+ * Ideally, the EC should also be instructed NOT to accumulate events during
+ * sleep (which Windows seems to do somehow), but the interface to control this
+ * behaviour is not known at this time.
+ *
+ * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx,
+ * however it is very likely that other Samsung models are affected.
+ *
+ * On systems which don't accumulate _Q events during sleep, this extra check
+ * should be harmless.
+ */
+static int ec_clear_on_resume(const struct dmi_system_id *id)
+{
+ pr_debug("Detected system needing EC poll on resume.\n");
+ EC_FLAGS_CLEAR_ON_RESUME = 1;
+ return 0;
+}
+
static struct dmi_system_id ec_dmi_table[] __initdata = {
{
ec_skip_dsdt_scan, "Compal JFL92", {
@@ -965,6 +1026,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
ec_validate_ecdt, "ASUS hardware", {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL},
+ {
+ ec_clear_on_resume, "Samsung hardware", {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
{},
};
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 1fb62900f32a..8acf53e62966 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -55,8 +55,16 @@ MODULE_DEVICE_TABLE(acpi, fan_device_ids);
#ifdef CONFIG_PM_SLEEP
static int acpi_fan_suspend(struct device *dev);
static int acpi_fan_resume(struct device *dev);
+static struct dev_pm_ops acpi_fan_pm = {
+ .resume = acpi_fan_resume,
+ .freeze = acpi_fan_suspend,
+ .thaw = acpi_fan_resume,
+ .restore = acpi_fan_resume,
+};
+#define FAN_PM_OPS_PTR (&acpi_fan_pm)
+#else
+#define FAN_PM_OPS_PTR NULL
#endif
-static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume);
static struct acpi_driver acpi_fan_driver = {
.name = "fan",
@@ -66,7 +74,7 @@ static struct acpi_driver acpi_fan_driver = {
.add = acpi_fan_add,
.remove = acpi_fan_remove,
},
- .drv.pm = &acpi_fan_pm,
+ .drv.pm = FAN_PM_OPS_PTR,
};
/* thermal cooling device callbacks */
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 0c789224d40d..f774c65ecb8b 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -287,6 +287,7 @@ EXPORT_SYMBOL_GPL(acpi_unbind_one);
static int acpi_platform_notify(struct device *dev)
{
struct acpi_bus_type *type = acpi_get_bus_type(dev);
+ struct acpi_device *adev;
int ret;
ret = acpi_bind_one(dev, NULL);
@@ -303,9 +304,14 @@ static int acpi_platform_notify(struct device *dev)
if (ret)
goto out;
}
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ goto out;
if (type && type->setup)
type->setup(dev);
+ else if (adev->handler && adev->handler->bind)
+ adev->handler->bind(dev);
out:
#if ACPI_GLUE_DEBUG
@@ -324,11 +330,17 @@ static int acpi_platform_notify(struct device *dev)
static int acpi_platform_notify_remove(struct device *dev)
{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_bus_type *type;
+ if (!adev)
+ return 0;
+
type = acpi_get_bus_type(dev);
if (type && type->cleanup)
type->cleanup(dev);
+ else if (adev->handler && adev->handler->unbind)
+ adev->handler->unbind(dev);
acpi_unbind_one(dev);
return 0;
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index dedbb2d802f1..957391306cbf 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -37,9 +37,15 @@ void acpi_container_init(void);
static inline void acpi_container_init(void) {}
#endif
#ifdef CONFIG_ACPI_DOCK
-void acpi_dock_init(void);
+void register_dock_dependent_device(struct acpi_device *adev,
+ acpi_handle dshandle);
+int dock_notify(struct acpi_device *adev, u32 event);
+void acpi_dock_add(struct acpi_device *adev);
#else
-static inline void acpi_dock_init(void) {}
+static inline void register_dock_dependent_device(struct acpi_device *adev,
+ acpi_handle dshandle) {}
+static inline int dock_notify(struct acpi_device *adev, u32 event) { return -ENODEV; }
+static inline void acpi_dock_add(struct acpi_device *adev) {}
#endif
#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
void acpi_memory_hotplug_init(void);
@@ -72,7 +78,9 @@ void acpi_lpss_init(void);
static inline void acpi_lpss_init(void) {}
#endif
+acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src);
bool acpi_queue_hotplug_work(struct work_struct *work);
+void acpi_device_hotplug(struct acpi_device *adev, u32 src);
bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent);
/* --------------------------------------------------------------------------
@@ -90,6 +98,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
int acpi_bind_one(struct device *dev, struct acpi_device *adev);
int acpi_unbind_one(struct device *dev);
bool acpi_device_is_present(struct acpi_device *adev);
+bool acpi_device_is_battery(struct acpi_device *adev);
/* --------------------------------------------------------------------------
Power Resource
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 9e6816ef280a..24b5476449a1 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -60,7 +60,7 @@ int node_to_pxm(int node)
return node_to_pxm_map[node];
}
-void __acpi_map_pxm_to_node(int pxm, int node)
+static void __acpi_map_pxm_to_node(int pxm, int node)
{
if (pxm_to_node_map[pxm] == NUMA_NO_NODE || node < pxm_to_node_map[pxm])
pxm_to_node_map[pxm] = node;
@@ -193,7 +193,7 @@ static int __init acpi_parse_slit(struct acpi_table_header *table)
return 0;
}
-void __init __attribute__ ((weak))
+void __init __weak
acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
{
printk(KERN_WARNING PREFIX
@@ -314,7 +314,7 @@ int __init acpi_numa_init(void)
return 0;
}
-int acpi_get_pxm(acpi_handle h)
+static int acpi_get_pxm(acpi_handle h)
{
unsigned long long pxm;
acpi_status status;
@@ -331,14 +331,14 @@ int acpi_get_pxm(acpi_handle h)
return -1;
}
-int acpi_get_node(acpi_handle *handle)
+int acpi_get_node(acpi_handle handle)
{
- int pxm, node = NUMA_NO_NODE;
+ int pxm;
pxm = acpi_get_pxm(handle);
- if (pxm >= 0 && pxm < MAX_PXM_DOMAINS)
- node = acpi_map_pxm_to_node(pxm);
+ if (pxm < 0 || pxm >= MAX_PXM_DOMAINS)
+ return NUMA_NO_NODE;
- return node;
+ return acpi_map_pxm_to_node(pxm);
}
EXPORT_SYMBOL(acpi_get_node);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index fc1aa7909690..f7fd72ac69cf 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -52,7 +52,7 @@
#define _COMPONENT ACPI_OS_SERVICES
ACPI_MODULE_NAME("osl");
-#define PREFIX "ACPI: "
+
struct acpi_os_dpc {
acpi_osd_exec_callback function;
void *context;
@@ -1168,8 +1168,7 @@ void acpi_os_wait_events_complete(void)
struct acpi_hp_work {
struct work_struct work;
- acpi_hp_callback func;
- void *data;
+ struct acpi_device *adev;
u32 src;
};
@@ -1178,25 +1177,24 @@ static void acpi_hotplug_work_fn(struct work_struct *work)
struct acpi_hp_work *hpw = container_of(work, struct acpi_hp_work, work);
acpi_os_wait_events_complete();
- hpw->func(hpw->data, hpw->src);
+ acpi_device_hotplug(hpw->adev, hpw->src);
kfree(hpw);
}
-acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src)
+acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src)
{
struct acpi_hp_work *hpw;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Scheduling function [%p(%p, %u)] for deferred execution.\n",
- func, data, src));
+ "Scheduling hotplug event (%p, %u) for deferred execution.\n",
+ adev, src));
hpw = kmalloc(sizeof(*hpw), GFP_KERNEL);
if (!hpw)
return AE_NO_MEMORY;
INIT_WORK(&hpw->work, acpi_hotplug_work_fn);
- hpw->func = func;
- hpw->data = data;
+ hpw->adev = adev;
hpw->src = src;
/*
* We can't run hotplug code in kacpid_wq/kacpid_notify_wq etc., because
@@ -1539,17 +1537,21 @@ static int __init osi_setup(char *str)
__setup("acpi_osi=", osi_setup);
-/* enable serialization to combat AE_ALREADY_EXISTS errors */
-static int __init acpi_serialize_setup(char *str)
+/*
+ * Disable the auto-serialization of named objects creation methods.
+ *
+ * This feature is enabled by default. It marks the AML control methods
+ * that contain the opcodes to create named objects as "Serialized".
+ */
+static int __init acpi_no_auto_serialize_setup(char *str)
{
- printk(KERN_INFO PREFIX "serialize enabled\n");
-
- acpi_gbl_all_methods_serialized = TRUE;
+ acpi_gbl_auto_serialize_methods = FALSE;
+ pr_info("ACPI: auto-serialization disabled\n");
return 1;
}
-__setup("acpi_serialize", acpi_serialize_setup);
+__setup("acpi_no_auto_serialize", acpi_no_auto_serialize_setup);
/* Check of resource interference between native drivers and ACPI
* OperationRegions (SystemIO and System Memory only).
@@ -1780,6 +1782,17 @@ static int __init acpi_no_auto_ssdt_setup(char *s)
__setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup);
+static int __init acpi_disable_return_repair(char *s)
+{
+ printk(KERN_NOTICE PREFIX
+ "ACPI: Predefined validation mechanism disabled\n");
+ acpi_gbl_disable_auto_repair = TRUE;
+
+ return 1;
+}
+
+__setup("acpica_no_return_repair", acpi_disable_return_repair);
+
acpi_status __init acpi_os_initialize(void)
{
acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 52d45ea2bc4f..9c62340c2360 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -370,6 +370,30 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
return NULL;
}
+#if IS_ENABLED(CONFIG_ISA) || IS_ENABLED(CONFIG_EISA)
+static int acpi_isa_register_gsi(struct pci_dev *dev)
+{
+ u32 dev_gsi;
+
+ /* Interrupt Line values above 0xF are forbidden */
+ if (dev->irq > 0 && (dev->irq <= 0xF) &&
+ (acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) {
+ dev_warn(&dev->dev, "PCI INT %c: no GSI - using ISA IRQ %d\n",
+ pin_name(dev->pin), dev->irq);
+ acpi_register_gsi(&dev->dev, dev_gsi,
+ ACPI_LEVEL_SENSITIVE,
+ ACPI_ACTIVE_LOW);
+ return 0;
+ }
+ return -EINVAL;
+}
+#else
+static inline int acpi_isa_register_gsi(struct pci_dev *dev)
+{
+ return -ENODEV;
+}
+#endif
+
int acpi_pci_irq_enable(struct pci_dev *dev)
{
struct acpi_prt_entry *entry;
@@ -416,20 +440,11 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
* driver reported one, then use it. Exit in any case.
*/
if (gsi < 0) {
- u32 dev_gsi;
- /* Interrupt Line values above 0xF are forbidden */
- if (dev->irq > 0 && (dev->irq <= 0xF) &&
- (acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) {
- dev_warn(&dev->dev, "PCI INT %c: no GSI - using ISA IRQ %d\n",
- pin_name(pin), dev->irq);
- acpi_register_gsi(&dev->dev, dev_gsi,
- ACPI_LEVEL_SENSITIVE,
- ACPI_ACTIVE_LOW);
- } else {
+ if (acpi_isa_register_gsi(dev))
dev_warn(&dev->dev, "PCI INT %c: no GSI\n",
pin_name(pin));
- }
+ kfree(entry);
return 0;
}
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 9418c7a1f786..cfd7581cc19f 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -43,8 +43,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_link");
#define ACPI_PCI_LINK_CLASS "pci_irq_routing"
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index c1c4102e6478..d388f13d48b4 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -39,8 +39,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_root");
#define ACPI_PCI_ROOT_CLASS "pci_bridge"
@@ -51,7 +49,7 @@ static void acpi_pci_root_remove(struct acpi_device *device);
static int acpi_pci_root_scan_dependent(struct acpi_device *adev)
{
- acpiphp_check_host_bridge(adev->handle);
+ acpiphp_check_host_bridge(adev);
return 0;
}
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index ad7da686e6e6..e0bcfb642b52 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -46,8 +46,6 @@
#include "sleep.h"
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define _COMPONENT ACPI_POWER_COMPONENT
ACPI_MODULE_NAME("power");
#define ACPI_POWER_CLASS "power_resource"
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index a4eea9a508d3..71e2065639a6 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -15,28 +15,9 @@
#include "internal.h"
-#define PREFIX "ACPI: "
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_core");
-static int __init set_no_mwait(const struct dmi_system_id *id)
-{
- printk(KERN_NOTICE PREFIX "%s detected - "
- "disabling mwait for CPU C-states\n", id->ident);
- boot_option_idle_override = IDLE_NOMWAIT;
- return 0;
-}
-
-static struct dmi_system_id processor_idle_dmi_table[] __initdata = {
- {
- set_no_mwait, "Extensa 5220", {
- DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
- DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
- DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
- {},
-};
-
static int map_lapic_id(struct acpi_subtable_header *entry,
u32 acpi_id, int *apic_id)
{
@@ -323,7 +304,7 @@ static struct acpi_object_list *acpi_processor_alloc_pdc(void)
* _PDC is required for a BIOS-OS handshake for most of the newer
* ACPI processor features.
*/
-static int
+static acpi_status
acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
{
acpi_status status = AE_OK;
@@ -379,16 +360,43 @@ early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
-void __init acpi_early_processor_set_pdc(void)
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
+static int __init set_no_mwait(const struct dmi_system_id *id)
+{
+ pr_notice(PREFIX "%s detected - disabling mwait for CPU C-states\n",
+ id->ident);
+ boot_option_idle_override = IDLE_NOMWAIT;
+ return 0;
+}
+
+static struct dmi_system_id processor_idle_dmi_table[] __initdata = {
+ {
+ set_no_mwait, "Extensa 5220", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
+ DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
+ {},
+};
+
+static void __init processor_dmi_check(void)
{
/*
* Check whether the system is DMI table. If yes, OSPM
* should not use mwait for CPU-states.
*/
dmi_check_system(processor_idle_dmi_table);
+}
+#else
+static inline void processor_dmi_check(void) {}
+#endif
+
+void __init acpi_early_processor_set_pdc(void)
+{
+ processor_dmi_check();
acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
early_init_pdc, NULL, NULL, NULL);
- acpi_get_devices("ACPI0007", early_init_pdc, NULL, NULL);
+ acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, early_init_pdc, NULL, NULL);
}
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index c1c35623550f..7f70f3182d50 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -41,8 +41,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
#define ACPI_PROCESSOR_NOTIFY_POWER 0x81
#define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index ff90054f04fd..cfc8aba72f86 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -156,17 +156,9 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
*/
static void acpi_processor_ppc_ost(acpi_handle handle, int status)
{
- union acpi_object params[2] = {
- {.type = ACPI_TYPE_INTEGER,},
- {.type = ACPI_TYPE_INTEGER,},
- };
- struct acpi_object_list arg_list = {2, params};
-
- if (acpi_has_method(handle, "_OST")) {
- params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE;
- params[1].integer.value = status;
- acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
- }
+ if (acpi_has_method(handle, "_OST"))
+ acpi_evaluate_ost(handle, ACPI_PROCESSOR_NOTIFY_PERFORMANCE,
+ status, NULL);
}
int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 28baa05b8018..84243c32e29c 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -56,6 +56,12 @@ struct throttling_tstate {
int target_state; /* target T-state */
};
+struct acpi_processor_throttling_arg {
+ struct acpi_processor *pr;
+ int target_state;
+ bool force;
+};
+
#define THROTTLING_PRECHANGE (1)
#define THROTTLING_POSTCHANGE (2)
@@ -1060,16 +1066,24 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
return 0;
}
+static long acpi_processor_throttling_fn(void *data)
+{
+ struct acpi_processor_throttling_arg *arg = data;
+ struct acpi_processor *pr = arg->pr;
+
+ return pr->throttling.acpi_processor_set_throttling(pr,
+ arg->target_state, arg->force);
+}
+
int acpi_processor_set_throttling(struct acpi_processor *pr,
int state, bool force)
{
- cpumask_var_t saved_mask;
int ret = 0;
unsigned int i;
struct acpi_processor *match_pr;
struct acpi_processor_throttling *p_throttling;
+ struct acpi_processor_throttling_arg arg;
struct throttling_tstate t_state;
- cpumask_var_t online_throttling_cpus;
if (!pr)
return -EINVAL;
@@ -1080,14 +1094,6 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
if ((state < 0) || (state > (pr->throttling.state_count - 1)))
return -EINVAL;
- if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL))
- return -ENOMEM;
-
- if (!alloc_cpumask_var(&online_throttling_cpus, GFP_KERNEL)) {
- free_cpumask_var(saved_mask);
- return -ENOMEM;
- }
-
if (cpu_is_offline(pr->id)) {
/*
* the cpu pointed by pr->id is offline. Unnecessary to change
@@ -1096,17 +1102,15 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
return -ENODEV;
}
- cpumask_copy(saved_mask, &current->cpus_allowed);
t_state.target_state = state;
p_throttling = &(pr->throttling);
- cpumask_and(online_throttling_cpus, cpu_online_mask,
- p_throttling->shared_cpu_map);
+
/*
* The throttling notifier will be called for every
* affected cpu in order to get one proper T-state.
* The notifier event is THROTTLING_PRECHANGE.
*/
- for_each_cpu(i, online_throttling_cpus) {
+ for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
t_state.cpu = i;
acpi_processor_throttling_notifier(THROTTLING_PRECHANGE,
&t_state);
@@ -1118,21 +1122,18 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
* it can be called only for the cpu pointed by pr.
*/
if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
- /* FIXME: use work_on_cpu() */
- if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) {
- /* Can't migrate to the pr->id CPU. Exit */
- ret = -ENODEV;
- goto exit;
- }
- ret = p_throttling->acpi_processor_set_throttling(pr,
- t_state.target_state, force);
+ arg.pr = pr;
+ arg.target_state = state;
+ arg.force = force;
+ ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg);
} else {
/*
* When the T-state coordination is SW_ALL or HW_ALL,
* it is necessary to set T-state for every affected
* cpus.
*/
- for_each_cpu(i, online_throttling_cpus) {
+ for_each_cpu_and(i, cpu_online_mask,
+ p_throttling->shared_cpu_map) {
match_pr = per_cpu(processors, i);
/*
* If the pointer is invalid, we will report the
@@ -1153,13 +1154,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
"on CPU %d\n", i));
continue;
}
- t_state.cpu = i;
- /* FIXME: use work_on_cpu() */
- if (set_cpus_allowed_ptr(current, cpumask_of(i)))
- continue;
- ret = match_pr->throttling.
- acpi_processor_set_throttling(
- match_pr, t_state.target_state, force);
+
+ arg.pr = match_pr;
+ arg.target_state = state;
+ arg.force = force;
+ ret = work_on_cpu(pr->id, acpi_processor_throttling_fn,
+ &arg);
}
}
/*
@@ -1168,17 +1168,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
* affected cpu to update the T-states.
* The notifier event is THROTTLING_POSTCHANGE
*/
- for_each_cpu(i, online_throttling_cpus) {
+ for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
t_state.cpu = i;
acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE,
&t_state);
}
- /* restore the previous state */
- /* FIXME: use work_on_cpu() */
- set_cpus_allowed_ptr(current, saved_mask);
-exit:
- free_cpumask_var(online_throttling_cpus);
- free_cpumask_var(saved_mask);
+
return ret;
}
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index b7201fc6f1e1..0bdacc5e26a3 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -77,18 +77,24 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
switch (ares->type) {
case ACPI_RESOURCE_TYPE_MEMORY24:
memory24 = &ares->data.memory24;
+ if (!memory24->address_length)
+ return false;
acpi_dev_get_memresource(res, memory24->minimum,
memory24->address_length,
memory24->write_protect);
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
memory32 = &ares->data.memory32;
+ if (!memory32->address_length)
+ return false;
acpi_dev_get_memresource(res, memory32->minimum,
memory32->address_length,
memory32->write_protect);
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
fixed_memory32 = &ares->data.fixed_memory32;
+ if (!fixed_memory32->address_length)
+ return false;
acpi_dev_get_memresource(res, fixed_memory32->address,
fixed_memory32->address_length,
fixed_memory32->write_protect);
@@ -144,12 +150,16 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
switch (ares->type) {
case ACPI_RESOURCE_TYPE_IO:
io = &ares->data.io;
+ if (!io->address_length)
+ return false;
acpi_dev_get_ioresource(res, io->minimum,
io->address_length,
io->io_decode);
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
fixed_io = &ares->data.fixed_io;
+ if (!fixed_io->address_length)
+ return false;
acpi_dev_get_ioresource(res, fixed_io->address,
fixed_io->address_length,
ACPI_DECODE_10);
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index d465ae6cdd00..366ca40a6f70 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -37,12 +37,12 @@
#include <linux/power_supply.h>
#include "sbshc.h"
+#include "battery.h"
#define PREFIX "ACPI: "
#define ACPI_SBS_CLASS "sbs"
#define ACPI_AC_CLASS "ac_adapter"
-#define ACPI_BATTERY_CLASS "battery"
#define ACPI_SBS_DEVICE_NAME "Smart Battery System"
#define ACPI_SBS_FILE_INFO "info"
#define ACPI_SBS_FILE_STATE "state"
@@ -450,7 +450,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev,
{
unsigned long x;
struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
- if (sscanf(buf, "%ld\n", &x) == 1)
+ if (sscanf(buf, "%lu\n", &x) == 1)
battery->alarm_capacity = x /
(1000 * acpi_battery_scale(battery));
if (battery->present)
@@ -668,6 +668,8 @@ static int acpi_sbs_resume(struct device *dev)
acpi_sbs_callback(sbs);
return 0;
}
+#else
+#define acpi_sbs_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(acpi_sbs_pm, NULL, acpi_sbs_resume);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 57b053f424d1..7efe546a8c42 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -41,6 +41,7 @@ static DEFINE_MUTEX(acpi_scan_lock);
static LIST_HEAD(acpi_scan_handlers_list);
DEFINE_MUTEX(acpi_device_lock);
LIST_HEAD(acpi_wakeup_device_list);
+static DEFINE_MUTEX(acpi_hp_context_lock);
struct acpi_device_bus_id{
char bus_id[15];
@@ -60,6 +61,27 @@ void acpi_scan_lock_release(void)
}
EXPORT_SYMBOL_GPL(acpi_scan_lock_release);
+void acpi_lock_hp_context(void)
+{
+ mutex_lock(&acpi_hp_context_lock);
+}
+
+void acpi_unlock_hp_context(void)
+{
+ mutex_unlock(&acpi_hp_context_lock);
+}
+
+void acpi_initialize_hp_context(struct acpi_device *adev,
+ struct acpi_hotplug_context *hp,
+ int (*notify)(struct acpi_device *, u32),
+ void (*uevent)(struct acpi_device *, u32))
+{
+ acpi_lock_hp_context();
+ acpi_set_hp_context(adev, hp, notify, uevent, NULL);
+ acpi_unlock_hp_context();
+}
+EXPORT_SYMBOL_GPL(acpi_initialize_hp_context);
+
int acpi_scan_add_handler(struct acpi_scan_handler *handler)
{
if (!handler || !handler->attach)
@@ -439,90 +461,75 @@ static int acpi_scan_bus_check(struct acpi_device *adev)
return 0;
}
-static void acpi_device_hotplug(void *data, u32 src)
+static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
{
- u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
- struct acpi_device *adev = data;
- int error;
-
- lock_device_hotplug();
- mutex_lock(&acpi_scan_lock);
-
- /*
- * The device object's ACPI handle cannot become invalid as long as we
- * are holding acpi_scan_lock, but it may have become invalid before
- * that lock was acquired.
- */
- if (adev->handle == INVALID_ACPI_HANDLE)
- goto out;
-
- switch (src) {
+ switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
- error = acpi_scan_bus_check(adev);
- break;
+ return acpi_scan_bus_check(adev);
case ACPI_NOTIFY_DEVICE_CHECK:
- error = acpi_scan_device_check(adev);
- break;
+ return acpi_scan_device_check(adev);
case ACPI_NOTIFY_EJECT_REQUEST:
case ACPI_OST_EC_OSPM_EJECT:
- error = acpi_scan_hot_remove(adev);
- break;
- default:
- error = -EINVAL;
- break;
+ if (adev->handler && !adev->handler->hotplug.enabled) {
+ dev_info(&adev->dev, "Eject disabled\n");
+ return -EPERM;
+ }
+ acpi_evaluate_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST,
+ ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+ return acpi_scan_hot_remove(adev);
}
- if (!error)
- ost_code = ACPI_OST_SC_SUCCESS;
-
- out:
- acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL);
- put_device(&adev->dev);
- mutex_unlock(&acpi_scan_lock);
- unlock_device_hotplug();
+ return -EINVAL;
}
-static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
+void acpi_device_hotplug(struct acpi_device *adev, u32 src)
{
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
- struct acpi_device *adev;
- acpi_status status;
+ int error = -ENODEV;
- if (acpi_bus_get_device(handle, &adev))
- goto err_out;
+ lock_device_hotplug();
+ mutex_lock(&acpi_scan_lock);
- switch (type) {
- case ACPI_NOTIFY_BUS_CHECK:
- acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
- break;
- case ACPI_NOTIFY_DEVICE_CHECK:
- acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
- break;
- case ACPI_NOTIFY_EJECT_REQUEST:
- acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
- if (!adev->handler)
- goto err_out;
+ /*
+ * The device object's ACPI handle cannot become invalid as long as we
+ * are holding acpi_scan_lock, but it might have become invalid before
+ * that lock was acquired.
+ */
+ if (adev->handle == INVALID_ACPI_HANDLE)
+ goto err_out;
- if (!adev->handler->hotplug.enabled) {
- acpi_handle_err(handle, "Eject disabled\n");
+ if (adev->flags.is_dock_station) {
+ error = dock_notify(adev, src);
+ } else if (adev->flags.hotplug_notify) {
+ error = acpi_generic_hotplug_event(adev, src);
+ if (error == -EPERM) {
ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
goto err_out;
}
- acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
- ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
- break;
- default:
- /* non-hotplug event; possibly handled by other handler */
- return;
- }
- get_device(&adev->dev);
- status = acpi_hotplug_execute(acpi_device_hotplug, adev, type);
- if (ACPI_SUCCESS(status))
- return;
+ } else {
+ int (*notify)(struct acpi_device *, u32);
- put_device(&adev->dev);
+ acpi_lock_hp_context();
+ notify = adev->hp ? adev->hp->notify : NULL;
+ acpi_unlock_hp_context();
+ /*
+ * There may be additional notify handlers for device objects
+ * without the .event() callback, so ignore them here.
+ */
+ if (notify)
+ error = notify(adev, src);
+ else
+ goto out;
+ }
+ if (!error)
+ ost_code = ACPI_OST_SC_SUCCESS;
err_out:
- acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
+ acpi_evaluate_ost(adev->handle, src, ost_code, NULL);
+
+ out:
+ acpi_bus_put_acpi_device(adev);
+ mutex_unlock(&acpi_scan_lock);
+ unlock_device_hotplug();
}
static ssize_t real_power_state_show(struct device *dev,
@@ -570,17 +577,14 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
return -ENODEV;
- acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
- ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
get_device(&acpi_device->dev);
- status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device,
- ACPI_OST_EC_OSPM_EJECT);
+ status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT);
if (ACPI_SUCCESS(status))
return count;
put_device(&acpi_device->dev);
- acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
- ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+ acpi_evaluate_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
+ ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
}
@@ -1114,14 +1118,16 @@ static void acpi_scan_drop_device(acpi_handle handle, void *context)
mutex_unlock(&acpi_device_del_lock);
}
-int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
+static int acpi_get_device_data(acpi_handle handle, struct acpi_device **device,
+ void (*callback)(void *))
{
acpi_status status;
if (!device)
return -EINVAL;
- status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device);
+ status = acpi_get_data_full(handle, acpi_scan_drop_device,
+ (void **)device, callback);
if (ACPI_FAILURE(status) || !*device) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
handle));
@@ -1129,8 +1135,32 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
}
return 0;
}
+
+int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
+{
+ return acpi_get_device_data(handle, device, NULL);
+}
EXPORT_SYMBOL(acpi_bus_get_device);
+static void get_acpi_device(void *dev)
+{
+ if (dev)
+ get_device(&((struct acpi_device *)dev)->dev);
+}
+
+struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle)
+{
+ struct acpi_device *adev = NULL;
+
+ acpi_get_device_data(handle, &adev, get_acpi_device);
+ return adev;
+}
+
+void acpi_bus_put_acpi_device(struct acpi_device *adev)
+{
+ put_device(&adev->dev);
+}
+
int acpi_device_add(struct acpi_device *device,
void (*release)(struct device *))
{
@@ -1641,6 +1671,27 @@ bool acpi_bay_match(acpi_handle handle)
return acpi_ata_match(phandle);
}
+bool acpi_device_is_battery(struct acpi_device *adev)
+{
+ struct acpi_hardware_id *hwid;
+
+ list_for_each_entry(hwid, &adev->pnp.ids, list)
+ if (!strcmp("PNP0C0A", hwid->id))
+ return true;
+
+ return false;
+}
+
+static bool is_ejectable_bay(struct acpi_device *adev)
+{
+ acpi_handle handle = adev->handle;
+
+ if (acpi_has_method(handle, "_EJ0") && acpi_device_is_battery(adev))
+ return true;
+
+ return acpi_bay_match(handle);
+}
+
/*
* acpi_dock_match - see if an acpi object has a _DCK method
*/
@@ -1706,6 +1757,20 @@ static bool acpi_ibm_smbus_match(acpi_handle handle)
return false;
}
+static bool acpi_object_is_system_bus(acpi_handle handle)
+{
+ acpi_handle tmp;
+
+ if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_SB", &tmp)) &&
+ tmp == handle)
+ return true;
+ if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_TZ", &tmp)) &&
+ tmp == handle)
+ return true;
+
+ return false;
+}
+
static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
int device_type)
{
@@ -1757,8 +1822,10 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
acpi_add_id(pnp, ACPI_DOCK_HID);
else if (acpi_ibm_smbus_match(handle))
acpi_add_id(pnp, ACPI_SMBUS_IBM_HID);
- else if (list_empty(&pnp->ids) && handle == ACPI_ROOT_OBJECT) {
- acpi_add_id(pnp, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
+ else if (list_empty(&pnp->ids) &&
+ acpi_object_is_system_bus(handle)) {
+ /* \_SB, \_TZ, LNXSYBUS */
+ acpi_add_id(pnp, ACPI_BUS_HID);
strcpy(pnp->device_name, ACPI_BUS_DEVICE_NAME);
strcpy(pnp->device_class, ACPI_BUS_CLASS);
}
@@ -1941,33 +2008,23 @@ void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
mutex_unlock(&acpi_scan_lock);
}
-static void acpi_scan_init_hotplug(acpi_handle handle, int type)
+static void acpi_scan_init_hotplug(struct acpi_device *adev)
{
- struct acpi_device_pnp pnp = {};
struct acpi_hardware_id *hwid;
- struct acpi_scan_handler *handler;
- INIT_LIST_HEAD(&pnp.ids);
- acpi_set_pnp_ids(handle, &pnp, type);
-
- if (!pnp.type.hardware_id)
- goto out;
+ if (acpi_dock_match(adev->handle) || is_ejectable_bay(adev)) {
+ acpi_dock_add(adev);
+ return;
+ }
+ list_for_each_entry(hwid, &adev->pnp.ids, list) {
+ struct acpi_scan_handler *handler;
- /*
- * This relies on the fact that acpi_install_notify_handler() will not
- * install the same notify handler routine twice for the same handle.
- */
- list_for_each_entry(hwid, &pnp.ids, list) {
handler = acpi_scan_match_handler(hwid->id, NULL);
if (handler) {
- acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- acpi_hotplug_notify_cb, handler);
+ adev->flags.hotplug_notify = true;
break;
}
}
-
-out:
- acpi_free_pnp_ids(&pnp);
}
static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
@@ -1991,12 +2048,12 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
return AE_OK;
}
- acpi_scan_init_hotplug(handle, type);
-
acpi_add_single_object(&device, handle, type, sta);
if (!device)
return AE_CTRL_DEPTH;
+ acpi_scan_init_hotplug(device);
+
out:
if (!*return_value)
*return_value = device;
@@ -2015,13 +2072,14 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
handler = acpi_scan_match_handler(hwid->id, &devid);
if (handler) {
+ device->handler = handler;
ret = handler->attach(device, devid);
- if (ret > 0) {
- device->handler = handler;
+ if (ret > 0)
break;
- } else if (ret < 0) {
+
+ device->handler = NULL;
+ if (ret < 0)
break;
- }
}
}
return ret;
@@ -2030,8 +2088,12 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
static void acpi_bus_attach(struct acpi_device *device)
{
struct acpi_device *child;
+ acpi_handle ejd;
int ret;
+ if (ACPI_SUCCESS(acpi_bus_get_ejd(device->handle, &ejd)))
+ register_dock_dependent_device(device, ejd);
+
acpi_bus_get_status(device);
/* Skip devices that are not present. */
if (!acpi_device_is_present(device)) {
@@ -2184,7 +2246,6 @@ int __init acpi_scan_init(void)
acpi_cmos_rtc_init();
acpi_container_init();
acpi_memory_hotplug_init();
- acpi_dock_init();
mutex_lock(&acpi_scan_lock);
/*
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index b718806657cd..c40fb2e81bbc 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -71,6 +71,17 @@ static int acpi_sleep_prepare(u32 acpi_state)
return 0;
}
+static bool acpi_sleep_state_supported(u8 sleep_state)
+{
+ acpi_status status;
+ u8 type_a, type_b;
+
+ status = acpi_get_sleep_type_data(sleep_state, &type_a, &type_b);
+ return ACPI_SUCCESS(status) && (!acpi_gbl_reduced_hardware
+ || (acpi_gbl_FADT.sleep_control.address
+ && acpi_gbl_FADT.sleep_status.address));
+}
+
#ifdef CONFIG_ACPI_SLEEP
static u32 acpi_target_sleep_state = ACPI_STATE_S0;
@@ -604,15 +615,9 @@ static void acpi_sleep_suspend_setup(void)
{
int i;
- for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
- acpi_status status;
- u8 type_a, type_b;
-
- status = acpi_get_sleep_type_data(i, &type_a, &type_b);
- if (ACPI_SUCCESS(status)) {
+ for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++)
+ if (acpi_sleep_state_supported(i))
sleep_states[i] = 1;
- }
- }
suspend_set_ops(old_suspend_ordering ?
&acpi_suspend_ops_old : &acpi_suspend_ops);
@@ -740,11 +745,7 @@ static const struct platform_hibernation_ops acpi_hibernation_ops_old = {
static void acpi_sleep_hibernate_setup(void)
{
- acpi_status status;
- u8 type_a, type_b;
-
- status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
- if (ACPI_FAILURE(status))
+ if (!acpi_sleep_state_supported(ACPI_STATE_S4))
return;
hibernation_set_ops(old_suspend_ordering ?
@@ -793,8 +794,6 @@ static void acpi_power_off(void)
int __init acpi_sleep_init(void)
{
- acpi_status status;
- u8 type_a, type_b;
char supported[ACPI_S_STATE_COUNT * 3 + 1];
char *pos = supported;
int i;
@@ -806,8 +805,7 @@ int __init acpi_sleep_init(void)
acpi_sleep_suspend_setup();
acpi_sleep_hibernate_setup();
- status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
- if (ACPI_SUCCESS(status)) {
+ if (acpi_sleep_state_supported(ACPI_STATE_S5)) {
sleep_states[ACPI_STATE_S5] = 1;
pm_power_off_prepare = acpi_power_off_prepare;
pm_power_off = acpi_power_off;
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 91a32cefb11f..38cb9782d4b8 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -12,8 +12,6 @@
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("sysfs");
-#define PREFIX "ACPI: "
-
#ifdef CONFIG_ACPI_DEBUG
/*
* ACPI debug sysfs I/F, including:
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 5837f857ac2e..21782290df41 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -23,6 +23,8 @@
*
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/smp.h>
@@ -33,8 +35,6 @@
#include <linux/acpi.h>
#include <linux/bootmem.h>
-#define PREFIX "ACPI: "
-
#define ACPI_MAX_TABLES 128
static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
@@ -55,10 +55,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_local_apic *p =
(struct acpi_madt_local_apic *)header;
- printk(KERN_INFO PREFIX
- "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
- p->processor_id, p->id,
- (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
+ pr_info("LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
+ p->processor_id, p->id,
+ (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
}
break;
@@ -66,11 +65,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_local_x2apic *p =
(struct acpi_madt_local_x2apic *)header;
- printk(KERN_INFO PREFIX
- "X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n",
- p->local_apic_id, p->uid,
- (p->lapic_flags & ACPI_MADT_ENABLED) ?
- "enabled" : "disabled");
+ pr_info("X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n",
+ p->local_apic_id, p->uid,
+ (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
}
break;
@@ -78,9 +75,8 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_io_apic *p =
(struct acpi_madt_io_apic *)header;
- printk(KERN_INFO PREFIX
- "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
- p->id, p->address, p->global_irq_base);
+ pr_info("IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
+ p->id, p->address, p->global_irq_base);
}
break;
@@ -88,18 +84,15 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_interrupt_override *p =
(struct acpi_madt_interrupt_override *)header;
- printk(KERN_INFO PREFIX
- "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
- p->bus, p->source_irq, p->global_irq,
- mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
- mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
+ pr_info("INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
+ p->bus, p->source_irq, p->global_irq,
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
if (p->inti_flags &
~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK))
- printk(KERN_INFO PREFIX
- "INT_SRC_OVR unexpected reserved flags: 0x%x\n",
- p->inti_flags &
+ pr_info("INT_SRC_OVR unexpected reserved flags: 0x%x\n",
+ p->inti_flags &
~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK));
-
}
break;
@@ -107,11 +100,10 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_nmi_source *p =
(struct acpi_madt_nmi_source *)header;
- printk(KERN_INFO PREFIX
- "NMI_SRC (%s %s global_irq %d)\n",
- mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
- mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
- p->global_irq);
+ pr_info("NMI_SRC (%s %s global_irq %d)\n",
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+ p->global_irq);
}
break;
@@ -119,12 +111,11 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_local_apic_nmi *p =
(struct acpi_madt_local_apic_nmi *)header;
- printk(KERN_INFO PREFIX
- "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
- p->processor_id,
- mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ],
- mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
- p->lint);
+ pr_info("LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
+ p->processor_id,
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+ p->lint);
}
break;
@@ -137,12 +128,11 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
polarity = p->inti_flags & ACPI_MADT_POLARITY_MASK;
trigger = (p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
- printk(KERN_INFO PREFIX
- "X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n",
- p->uid,
- mps_inti_flags_polarity[polarity],
- mps_inti_flags_trigger[trigger],
- p->lint);
+ pr_info("X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n",
+ p->uid,
+ mps_inti_flags_polarity[polarity],
+ mps_inti_flags_trigger[trigger],
+ p->lint);
}
break;
@@ -150,9 +140,8 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_local_apic_override *p =
(struct acpi_madt_local_apic_override *)header;
- printk(KERN_INFO PREFIX
- "LAPIC_ADDR_OVR (address[%p])\n",
- (void *)(unsigned long)p->address);
+ pr_info("LAPIC_ADDR_OVR (address[%p])\n",
+ (void *)(unsigned long)p->address);
}
break;
@@ -160,10 +149,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_io_sapic *p =
(struct acpi_madt_io_sapic *)header;
- printk(KERN_INFO PREFIX
- "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
- p->id, (void *)(unsigned long)p->address,
- p->global_irq_base);
+ pr_info("IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
+ p->id, (void *)(unsigned long)p->address,
+ p->global_irq_base);
}
break;
@@ -171,10 +159,9 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_local_sapic *p =
(struct acpi_madt_local_sapic *)header;
- printk(KERN_INFO PREFIX
- "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
- p->processor_id, p->id, p->eid,
- (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
+ pr_info("LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
+ p->processor_id, p->id, p->eid,
+ (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
}
break;
@@ -182,19 +169,17 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
struct acpi_madt_interrupt_source *p =
(struct acpi_madt_interrupt_source *)header;
- printk(KERN_INFO PREFIX
- "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
- mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
- mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
- p->type, p->id, p->eid, p->io_sapic_vector,
- p->global_irq);
+ pr_info("PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+ p->type, p->id, p->eid, p->io_sapic_vector,
+ p->global_irq);
}
break;
default:
- printk(KERN_WARNING PREFIX
- "Found unsupported MADT entry (type = 0x%x)\n",
- header->type);
+ pr_warn("Found unsupported MADT entry (type = 0x%x)\n",
+ header->type);
break;
}
}
@@ -225,7 +210,7 @@ acpi_table_parse_entries(char *id,
acpi_get_table_with_size(id, 0, &table_header, &tbl_size);
if (!table_header) {
- printk(KERN_WARNING PREFIX "%4.4s not present\n", id);
+ pr_warn("%4.4s not present\n", id);
return -ENODEV;
}
@@ -248,7 +233,7 @@ acpi_table_parse_entries(char *id,
* infinite loop.
*/
if (entry->length == 0) {
- pr_err(PREFIX "[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
+ pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
goto err;
}
@@ -256,8 +241,8 @@ acpi_table_parse_entries(char *id,
((unsigned long)entry + entry->length);
}
if (max_entries && count > max_entries) {
- printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of "
- "%i found\n", id, entry_id, count - max_entries, count);
+ pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n",
+ id, entry_id, count - max_entries, count);
}
early_acpi_os_unmap_memory((char *)table_header, tbl_size);
@@ -322,13 +307,11 @@ static void __init check_multiple_madt(void)
acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size);
if (table) {
- printk(KERN_WARNING PREFIX
- "BIOS bug: multiple APIC/MADT found,"
- " using %d\n", acpi_apic_instance);
- printk(KERN_WARNING PREFIX
- "If \"acpi_apic_instance=%d\" works better, "
- "notify linux-acpi@vger.kernel.org\n",
- acpi_apic_instance ? 0 : 2);
+ pr_warn("BIOS bug: multiple APIC/MADT found, using %d\n",
+ acpi_apic_instance);
+ pr_warn("If \"acpi_apic_instance=%d\" works better, "
+ "notify linux-acpi@vger.kernel.org\n",
+ acpi_apic_instance ? 0 : 2);
early_acpi_os_unmap_memory(table, tbl_size);
} else
@@ -365,8 +348,7 @@ static int __init acpi_parse_apic_instance(char *str)
acpi_apic_instance = simple_strtoul(str, NULL, 0);
- printk(KERN_NOTICE PREFIX "Shall use APIC/MADT table %d\n",
- acpi_apic_instance);
+ pr_notice("Shall use APIC/MADT table %d\n", acpi_apic_instance);
return 0;
}
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 8349a555b92b..964068553334 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -43,6 +43,7 @@
#include <linux/device.h>
#include <linux/thermal.h>
#include <linux/acpi.h>
+#include <linux/workqueue.h>
#include <asm/uaccess.h>
#define PREFIX "ACPI: "
@@ -90,6 +91,8 @@ static int psv;
module_param(psv, int, 0644);
MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
+static struct workqueue_struct *acpi_thermal_pm_queue;
+
static int acpi_thermal_add(struct acpi_device *device);
static int acpi_thermal_remove(struct acpi_device *device);
static void acpi_thermal_notify(struct acpi_device *device, u32 event);
@@ -101,9 +104,13 @@ static const struct acpi_device_id thermal_device_ids[] = {
MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
#ifdef CONFIG_PM_SLEEP
+static int acpi_thermal_suspend(struct device *dev);
static int acpi_thermal_resume(struct device *dev);
+#else
+#define acpi_thermal_suspend NULL
+#define acpi_thermal_resume NULL
#endif
-static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume);
+static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, acpi_thermal_suspend, acpi_thermal_resume);
static struct acpi_driver acpi_thermal_driver = {
.name = "thermal",
@@ -184,6 +191,7 @@ struct acpi_thermal {
struct thermal_zone_device *thermal_zone;
int tz_enabled;
int kelvin_offset;
+ struct work_struct thermal_check_work;
};
/* --------------------------------------------------------------------------
@@ -1062,6 +1070,13 @@ static void acpi_thermal_guess_offset(struct acpi_thermal *tz)
tz->kelvin_offset = 2732;
}
+static void acpi_thermal_check_fn(struct work_struct *work)
+{
+ struct acpi_thermal *tz = container_of(work, struct acpi_thermal,
+ thermal_check_work);
+ acpi_thermal_check(tz);
+}
+
static int acpi_thermal_add(struct acpi_device *device)
{
int result = 0;
@@ -1091,6 +1106,8 @@ static int acpi_thermal_add(struct acpi_device *device)
if (result)
goto free_memory;
+ INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn);
+
pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device),
acpi_device_bid(device), KELVIN_TO_CELSIUS(tz->temperature));
goto end;
@@ -1108,6 +1125,7 @@ static int acpi_thermal_remove(struct acpi_device *device)
if (!device || !acpi_driver_data(device))
return -EINVAL;
+ flush_workqueue(acpi_thermal_pm_queue);
tz = acpi_driver_data(device);
acpi_thermal_unregister_thermal_zone(tz);
@@ -1116,6 +1134,13 @@ static int acpi_thermal_remove(struct acpi_device *device)
}
#ifdef CONFIG_PM_SLEEP
+static int acpi_thermal_suspend(struct device *dev)
+{
+ /* Make sure the previously queued thermal check work has been done */
+ flush_workqueue(acpi_thermal_pm_queue);
+ return 0;
+}
+
static int acpi_thermal_resume(struct device *dev)
{
struct acpi_thermal *tz;
@@ -1146,7 +1171,7 @@ static int acpi_thermal_resume(struct device *dev)
tz->state.active |= tz->trips.active[i].flags.enabled;
}
- acpi_thermal_check(tz);
+ queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
return AE_OK;
}
@@ -1238,16 +1263,22 @@ static int __init acpi_thermal_init(void)
return -ENODEV;
}
+ acpi_thermal_pm_queue = create_workqueue("acpi_thermal_pm");
+ if (!acpi_thermal_pm_queue)
+ return -ENODEV;
+
result = acpi_bus_register_driver(&acpi_thermal_driver);
- if (result < 0)
+ if (result < 0) {
+ destroy_workqueue(acpi_thermal_pm_queue);
return -ENODEV;
+ }
return 0;
}
static void __exit acpi_thermal_exit(void)
{
-
+ destroy_workqueue(acpi_thermal_pm_queue);
acpi_bus_unregister_driver(&acpi_thermal_driver);
return;
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 85e3b612bdc0..0f5f78fa6545 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -422,7 +422,7 @@ out:
EXPORT_SYMBOL(acpi_get_physical_device_location);
/**
- * acpi_evaluate_hotplug_ost: Evaluate _OST for hotplug operations
+ * acpi_evaluate_ost: Evaluate _OST for hotplug operations
* @handle: ACPI device handle
* @source_event: source event code
* @status_code: status code
@@ -433,17 +433,15 @@ EXPORT_SYMBOL(acpi_get_physical_device_location);
* When the platform does not support _OST, this function has no effect.
*/
acpi_status
-acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
- u32 status_code, struct acpi_buffer *status_buf)
+acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code,
+ struct acpi_buffer *status_buf)
{
-#ifdef ACPI_HOTPLUG_OST
union acpi_object params[3] = {
{.type = ACPI_TYPE_INTEGER,},
{.type = ACPI_TYPE_INTEGER,},
{.type = ACPI_TYPE_BUFFER,}
};
struct acpi_object_list arg_list = {3, params};
- acpi_status status;
params[0].integer.value = source_event;
params[1].integer.value = status_code;
@@ -455,13 +453,9 @@ acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
params[2].buffer.length = 0;
}
- status = acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
- return status;
-#else
- return AE_OK;
-#endif
+ return acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
}
-EXPORT_SYMBOL(acpi_evaluate_hotplug_ost);
+EXPORT_SYMBOL(acpi_evaluate_ost);
/**
* acpi_handle_printk: Print message with ACPI prefix and object path
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index b727d105046d..48c7e8af9c96 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -45,8 +45,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
#define ACPI_VIDEO_BUS_NAME "Video Bus"
#define ACPI_VIDEO_DEVICE_NAME "Video Device"
#define ACPI_VIDEO_NOTIFY_SWITCH 0x80
@@ -81,11 +79,12 @@ static bool allow_duplicates;
module_param(allow_duplicates, bool, 0644);
/*
- * For Windows 8 systems: if set ture and the GPU driver has
- * registered a backlight interface, skip registering ACPI video's.
+ * For Windows 8 systems: used to decide if video module
+ * should skip registering backlight interface of its own.
*/
-static bool use_native_backlight = false;
-module_param(use_native_backlight, bool, 0644);
+static int use_native_backlight_param = -1;
+module_param_named(use_native_backlight, use_native_backlight_param, int, 0444);
+static bool use_native_backlight_dmi = false;
static int register_count;
static struct mutex video_list_lock;
@@ -231,9 +230,17 @@ static int acpi_video_get_next_level(struct acpi_video_device *device,
static int acpi_video_switch_brightness(struct acpi_video_device *device,
int event);
+static bool acpi_video_use_native_backlight(void)
+{
+ if (use_native_backlight_param != -1)
+ return use_native_backlight_param;
+ else
+ return use_native_backlight_dmi;
+}
+
static bool acpi_video_verify_backlight_support(void)
{
- if (acpi_osi_is_win8() && use_native_backlight &&
+ if (acpi_osi_is_win8() && acpi_video_use_native_backlight() &&
backlight_device_registered(BACKLIGHT_RAW))
return false;
return acpi_video_backlight_support();
@@ -398,6 +405,12 @@ static int __init video_set_bqc_offset(const struct dmi_system_id *d)
return 0;
}
+static int __init video_set_use_native_backlight(const struct dmi_system_id *d)
+{
+ use_native_backlight_dmi = true;
+ return 0;
+}
+
static struct dmi_system_id video_dmi_table[] __initdata = {
/*
* Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121
@@ -442,6 +455,120 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"),
},
},
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "ThinkPad T430s",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430s"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "ThinkPad X230",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "ThinkPad X1 Carbon",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X1 Carbon"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "Lenovo Yoga 13",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "Dell Inspiron 7520",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Inspiron 7520"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "Acer Aspire 5733Z",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5733Z"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "Acer Aspire V5-431",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-431"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP ProBook 4340s",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "HP ProBook 4340s"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP ProBook 2013 models",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "),
+ DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP EliteBook 2013 models",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "),
+ DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP ZBook 14",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP ZBook 15",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP ZBook 17",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
+ .ident = "HP EliteBook 8780w",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"),
+ },
+ },
{}
};
@@ -685,6 +812,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
union acpi_object *o;
struct acpi_video_device_brightness *br = NULL;
int result = -EINVAL;
+ u32 value;
if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available "
@@ -715,7 +843,12 @@ acpi_video_init_brightness(struct acpi_video_device *device)
printk(KERN_ERR PREFIX "Invalid data\n");
continue;
}
- br->levels[count] = (u32) o->integer.value;
+ value = (u32) o->integer.value;
+ /* Skip duplicate entries */
+ if (count > 2 && br->levels[count - 1] == value)
+ continue;
+
+ br->levels[count] = value;
if (br->levels[count] > max_level)
max_level = br->levels[count];
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index a697b77b8865..33e3db548a29 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -40,8 +40,6 @@
#include "internal.h"
-#define PREFIX "ACPI: "
-
ACPI_MODULE_NAME("video");
#define _COMPONENT ACPI_VIDEO_COMPONENT
@@ -168,22 +166,6 @@ static struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
},
},
- {
- .callback = video_detect_force_vendor,
- .ident = "HP EliteBook Revolve 810",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook Revolve 810 G1"),
- },
- },
- {
- .callback = video_detect_force_vendor,
- .ident = "Lenovo Yoga 13",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"),
- },
- },
{ },
};
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 4e737728aee2..20e03a7eb8b4 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -11,13 +11,13 @@ config HAVE_PATA_PLATFORM
to update the PATA_PLATFORM entry.
menuconfig ATA
- tristate "Serial ATA and Parallel ATA drivers"
+ tristate "Serial ATA and Parallel ATA drivers (libata)"
depends on HAS_IOMEM
depends on BLOCK
depends on !(M32R || M68K || S390) || BROKEN
select SCSI
---help---
- If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
+ If you want to use an ATA hard disk, ATA tape drive, ATA CD-ROM or
any other ATA device under Linux, say Y and make sure that you know
the name of your ATA host adapter (the card inside your computer
that "speaks" the ATA protocol, also called ATA controller),
@@ -60,7 +60,7 @@ config ATA_ACPI
config SATA_ZPODD
bool "SATA Zero Power Optical Disc Drive (ZPODD) support"
- depends on ATA_ACPI
+ depends on ATA_ACPI && PM_RUNTIME
default n
help
This option adds support for SATA Zero Power Optical Disc
@@ -97,15 +97,48 @@ config SATA_AHCI_PLATFORM
If unsure, say N.
+config AHCI_DA850
+ tristate "DaVinci DA850 AHCI SATA support"
+ depends on ARCH_DAVINCI_DA850
+ help
+ This option enables support for the DaVinci DA850 SoC's
+ onboard AHCI SATA.
+
+ If unsure, say N.
+
+config AHCI_ST
+ tristate "ST AHCI SATA support"
+ depends on ARCH_STI
+ help
+ This option enables support for ST AHCI SATA controller.
+
+ If unsure, say N.
+
config AHCI_IMX
tristate "Freescale i.MX AHCI SATA support"
- depends on SATA_AHCI_PLATFORM && MFD_SYSCON
+ depends on MFD_SYSCON
help
This option enables support for the Freescale i.MX SoC's
onboard AHCI SATA.
If unsure, say N.
+config AHCI_SUNXI
+ tristate "Allwinner sunxi AHCI SATA support"
+ depends on ARCH_SUNXI
+ help
+ This option enables support for the Allwinner sunxi SoC's
+ onboard AHCI SATA.
+
+ If unsure, say N.
+
+config AHCI_XGENE
+ tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support"
+ depends on ARM64 || COMPILE_TEST
+ select PHY_XGENE
+ help
+ This option enables support for APM X-Gene SoC SATA host controller.
+
config SATA_FSL
tristate "Freescale 3.0Gbps SATA support"
depends on FSL_SOC
@@ -239,6 +272,7 @@ config SATA_DWC_VDEBUG
config SATA_HIGHBANK
tristate "Calxeda Highbank SATA support"
+ depends on ARCH_HIGHBANK || COMPILE_TEST
help
This option enables support for the Calxeda Highbank SoC's
onboard SATA.
@@ -247,6 +281,9 @@ config SATA_HIGHBANK
config SATA_MV
tristate "Marvell SATA support"
+ depends on PCI || ARCH_DOVE || ARCH_KIRKWOOD || ARCH_MV78XX0 || \
+ ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST
+ select GENERIC_PHY
help
This option enables support for the Marvell Serial ATA family.
Currently supports 88SX[56]0[48][01] PCI(-X) chips,
@@ -272,6 +309,7 @@ config SATA_PROMISE
config SATA_RCAR
tristate "Renesas R-Car SATA support"
+ depends on ARCH_SHMOBILE || COMPILE_TEST
help
This option enables support for Renesas R-Car Serial ATA.
@@ -351,6 +389,7 @@ config PATA_AMD
config PATA_ARASAN_CF
tristate "ARASAN CompactFlash PATA Controller Support"
+ depends on ARCH_SPEAR13XX || COMPILE_TEST
depends on DMADEVICES
select DMA_ENGINE
help
@@ -402,7 +441,7 @@ config PATA_CMD64X
config PATA_CS5520
tristate "CS5510/5520 PATA support"
- depends on PCI
+ depends on PCI && (X86_32 || COMPILE_TEST)
help
This option enables support for the Cyrix 5510/5520
companion chip used with the MediaGX/Geode processor family.
@@ -411,7 +450,7 @@ config PATA_CS5520
config PATA_CS5530
tristate "CS5530 PATA support"
- depends on PCI
+ depends on PCI && (X86_32 || COMPILE_TEST)
help
This option enables support for the Cyrix/NatSemi/AMD CS5530
companion chip used with the MediaGX/Geode processor family.
@@ -420,7 +459,7 @@ config PATA_CS5530
config PATA_CS5535
tristate "CS5535 PATA support (Experimental)"
- depends on PCI && X86 && !X86_64
+ depends on PCI && X86_32
help
This option enables support for the NatSemi/AMD CS5535
companion chip used with the Geode processor family.
@@ -429,7 +468,7 @@ config PATA_CS5535
config PATA_CS5536
tristate "CS5536 PATA support"
- depends on PCI
+ depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
help
This option enables support for the AMD CS5536
companion chip used with the Geode LX processor family.
@@ -665,7 +704,7 @@ config PATA_RDC
config PATA_SC1200
tristate "SC1200 PATA support"
- depends on PCI
+ depends on PCI && (X86_32 || COMPILE_TEST)
help
This option enables support for the NatSemi/AMD SC1200 SoC
companion chip used with the Geode processor family.
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 46518c622460..44c8016e565c 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -4,13 +4,17 @@ obj-$(CONFIG_ATA) += libata.o
# non-SFF interface
obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o
-obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
+obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o libahci_platform.o
obj-$(CONFIG_SATA_FSL) += sata_fsl.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
-obj-$(CONFIG_AHCI_IMX) += ahci_imx.o
+obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o
# SFF w/ custom DMA
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c
index fd665d919df2..b51605ac5974 100644
--- a/drivers/ata/acard-ahci.c
+++ b/drivers/ata/acard-ahci.c
@@ -36,7 +36,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index dc2756fb6f33..5a0bf8ed649b 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -35,7 +35,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -61,6 +60,7 @@ enum board_ids {
/* board IDs by feature in alphabetical order */
board_ahci,
board_ahci_ign_iferr,
+ board_ahci_noncq,
board_ahci_nosntf,
board_ahci_yes_fbs,
@@ -121,6 +121,13 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
+ [board_ahci_noncq] = {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
[board_ahci_nosntf] = {
AHCI_HFLAGS (AHCI_HFLAG_NO_SNTF),
.flags = AHCI_FLAG_COMMON,
@@ -452,6 +459,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */
{ PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */
+ /*
+ * Samsung SSDs found on some macbooks. NCQ times out.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=60731
+ */
+ { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_noncq },
+
/* Enmotus */
{ PCI_DEVICE(0x1c44, 0x8000), board_ahci },
@@ -564,6 +577,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
bool online;
int rc;
@@ -574,7 +588,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline, &online, NULL);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
@@ -589,6 +603,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
{
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
@@ -604,7 +619,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline, &online, NULL);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* The pseudo configuration device on SIMG4726 attached to
* ASUS P5W-DH Deluxe doesn't send signature FIS after
@@ -1151,13 +1166,13 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
struct ahci_host_priv *hpriv)
{
- int rc, nvec;
+ int nvec;
if (hpriv->flags & AHCI_HFLAG_NO_MSI)
goto intx;
- rc = pci_msi_vec_count(pdev);
- if (rc < 0)
+ nvec = pci_msi_vec_count(pdev);
+ if (nvec < 0)
goto intx;
/*
@@ -1165,19 +1180,19 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
* Message mode could be enforced. In this case assume that advantage
* of multipe MSIs is negated and use single MSI mode instead.
*/
- if (rc < n_ports)
+ if (nvec < n_ports)
goto single_msi;
- nvec = rc;
- rc = pci_enable_msi_block(pdev, nvec);
- if (rc)
+ nvec = pci_enable_msi_range(pdev, nvec, nvec);
+ if (nvec == -ENOSPC)
+ goto single_msi;
+ else if (nvec < 0)
goto intx;
return nvec;
single_msi:
- rc = pci_enable_msi(pdev);
- if (rc)
+ if (pci_enable_msi(pdev))
goto intx;
return 1;
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 2289efdf8203..51af275b3388 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -37,6 +37,8 @@
#include <linux/clk.h>
#include <linux/libata.h>
+#include <linux/phy/phy.h>
+#include <linux/regulator/consumer.h>
/* Enclosure Management Control */
#define EM_CTRL_MSG_TYPE 0x000f0000
@@ -51,6 +53,7 @@
enum {
AHCI_MAX_PORTS = 32,
+ AHCI_MAX_CLKS = 3,
AHCI_MAX_SG = 168, /* hardware max is 64K */
AHCI_DMA_BOUNDARY = 0xffffffff,
AHCI_MAX_CMDS = 32,
@@ -321,8 +324,17 @@ struct ahci_host_priv {
u32 em_loc; /* enclosure management location */
u32 em_buf_sz; /* EM buffer size in byte */
u32 em_msg_type; /* EM message type */
- struct clk *clk; /* Only for platforms supporting clk */
+ bool got_runtime_pm; /* Did we do pm_runtime_get? */
+ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
+ struct regulator *target_pwr; /* Optional */
+ struct phy *phy; /* If platform uses phy */
void *plat_data; /* Other platform data */
+ /*
+ * Optional ahci_start_engine override, if not set this gets set to the
+ * default ahci_start_engine during ahci_save_initial_config, this can
+ * be overridden anytime before the host is activated.
+ */
+ void (*start_engine)(struct ata_port *ap);
};
extern int ahci_ignore_sss;
diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c
new file mode 100644
index 000000000000..2c83613ce2db
--- /dev/null
+++ b/drivers/ata/ahci_da850.c
@@ -0,0 +1,114 @@
+/*
+ * DaVinci DA850 AHCI SATA platform 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, or (at your option)
+ * any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include "ahci.h"
+
+/* SATA PHY Control Register offset from AHCI base */
+#define SATA_P0PHYCR_REG 0x178
+
+#define SATA_PHY_MPY(x) ((x) << 0)
+#define SATA_PHY_LOS(x) ((x) << 6)
+#define SATA_PHY_RXCDR(x) ((x) << 10)
+#define SATA_PHY_RXEQ(x) ((x) << 13)
+#define SATA_PHY_TXSWING(x) ((x) << 19)
+#define SATA_PHY_ENPLL(x) ((x) << 31)
+
+/*
+ * The multiplier needed for 1.5GHz PLL output.
+ *
+ * NOTE: This is currently hardcoded to be suitable for 100MHz crystal
+ * frequency (which is used by DA850 EVM board) and may need to be changed
+ * if you would like to use this driver on some other board.
+ */
+#define DA850_SATA_CLK_MULTIPLIER 7
+
+static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg,
+ void __iomem *ahci_base)
+{
+ unsigned int val;
+
+ /* Enable SATA clock receiver */
+ val = readl(pwrdn_reg);
+ val &= ~BIT(0);
+ writel(val, pwrdn_reg);
+
+ val = SATA_PHY_MPY(DA850_SATA_CLK_MULTIPLIER + 1) | SATA_PHY_LOS(1) |
+ SATA_PHY_RXCDR(4) | SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) |
+ SATA_PHY_ENPLL(1);
+
+ writel(val, ahci_base + SATA_P0PHYCR_REG);
+}
+
+static const struct ata_port_info ahci_da850_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
+};
+
+static int ahci_da850_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct resource *res;
+ void __iomem *pwrdn_reg;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ goto disable_resources;
+
+ pwrdn_reg = devm_ioremap(dev, res->start, resource_size(res));
+ if (!pwrdn_reg)
+ goto disable_resources;
+
+ da850_sata_init(dev, pwrdn_reg, hpriv->mmio);
+
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info, 0, 0);
+ if (rc)
+ goto disable_resources;
+
+ return 0;
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+
+static SIMPLE_DEV_PM_OPS(ahci_da850_pm_ops, ahci_platform_suspend,
+ ahci_platform_resume);
+
+static struct platform_driver ahci_da850_driver = {
+ .probe = ahci_da850_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "ahci_da850",
+ .owner = THIS_MODULE,
+ .pm = &ahci_da850_pm_ops,
+ },
+};
+module_platform_driver(ahci_da850_driver);
+
+MODULE_DESCRIPTION("DaVinci DA850 AHCI SATA platform driver");
+MODULE_AUTHOR("Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index dd4d6f74d7bd..497c7abe1c7d 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -42,13 +42,7 @@ enum ahci_imx_type {
struct imx_ahci_priv {
struct platform_device *ahci_pdev;
enum ahci_imx_type type;
-
- /* i.MX53 clock */
- struct clk *sata_gate_clk;
- /* Common clock */
- struct clk *sata_ref_clk;
struct clk *ahb_clk;
-
struct regmap *gpr;
bool no_device;
bool first_time;
@@ -58,28 +52,52 @@ static int ahci_imx_hotplug;
module_param_named(hotplug, ahci_imx_hotplug, int, 0644);
MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)");
-static int imx_sata_clock_enable(struct device *dev)
+static void ahci_imx_host_stop(struct ata_host *host);
+
+static int imx_sata_enable(struct ahci_host_priv *hpriv)
{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
int ret;
- if (imxpriv->type == AHCI_IMX53) {
- ret = clk_prepare_enable(imxpriv->sata_gate_clk);
- if (ret < 0) {
- dev_err(dev, "prepare-enable sata_gate clock err:%d\n",
- ret);
+ if (imxpriv->no_device)
+ return 0;
+
+ if (hpriv->target_pwr) {
+ ret = regulator_enable(hpriv->target_pwr);
+ if (ret)
return ret;
- }
}
- ret = clk_prepare_enable(imxpriv->sata_ref_clk);
- if (ret < 0) {
- dev_err(dev, "prepare-enable sata_ref clock err:%d\n",
- ret);
- goto clk_err;
- }
+ ret = ahci_platform_enable_clks(hpriv);
+ if (ret < 0)
+ goto disable_regulator;
if (imxpriv->type == AHCI_IMX6Q) {
+ /*
+ * set PHY Paremeters, two steps to configure the GPR13,
+ * one write for rest of parameters, mask of first write
+ * is 0x07ffffff, and the other one write for setting
+ * the mpll_clk_en.
+ */
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+ IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK |
+ IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK |
+ IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK |
+ IMX6Q_GPR13_SATA_SPD_MODE_MASK |
+ IMX6Q_GPR13_SATA_MPLL_SS_EN |
+ IMX6Q_GPR13_SATA_TX_ATTEN_MASK |
+ IMX6Q_GPR13_SATA_TX_BOOST_MASK |
+ IMX6Q_GPR13_SATA_TX_LVL_MASK |
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN |
+ IMX6Q_GPR13_SATA_TX_EDGE_RATE,
+ IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
+ IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
+ IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
+ IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
+ IMX6Q_GPR13_SATA_MPLL_SS_EN |
+ IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
+ IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
+ IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
IMX6Q_GPR13_SATA_MPLL_CLK_EN,
IMX6Q_GPR13_SATA_MPLL_CLK_EN);
@@ -89,15 +107,19 @@ static int imx_sata_clock_enable(struct device *dev)
return 0;
-clk_err:
- if (imxpriv->type == AHCI_IMX53)
- clk_disable_unprepare(imxpriv->sata_gate_clk);
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+
return ret;
}
-static void imx_sata_clock_disable(struct device *dev)
+static void imx_sata_disable(struct ahci_host_priv *hpriv)
{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+
+ if (imxpriv->no_device)
+ return;
if (imxpriv->type == AHCI_IMX6Q) {
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
@@ -105,10 +127,10 @@ static void imx_sata_clock_disable(struct device *dev)
!IMX6Q_GPR13_SATA_MPLL_CLK_EN);
}
- clk_disable_unprepare(imxpriv->sata_ref_clk);
+ ahci_platform_disable_clks(hpriv);
- if (imxpriv->type == AHCI_IMX53)
- clk_disable_unprepare(imxpriv->sata_gate_clk);
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
}
static void ahci_imx_error_handler(struct ata_port *ap)
@@ -118,7 +140,7 @@ static void ahci_imx_error_handler(struct ata_port *ap)
struct ata_host *host = dev_get_drvdata(ap->dev);
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->mmio;
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
ahci_error_handler(ap);
@@ -136,7 +158,7 @@ static void ahci_imx_error_handler(struct ata_port *ap)
*/
reg_val = readl(mmio + PORT_PHY_CTL);
writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
- imx_sata_clock_disable(ap->dev);
+ imx_sata_disable(hpriv);
imxpriv->no_device = true;
}
@@ -144,7 +166,9 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+ struct ata_host *host = dev_get_drvdata(ap->dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
int ret = -EIO;
if (imxpriv->type == AHCI_IMX53)
@@ -156,7 +180,8 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
}
static struct ata_port_operations ahci_imx_ops = {
- .inherits = &ahci_platform_ops,
+ .inherits = &ahci_ops,
+ .host_stop = ahci_imx_host_stop,
.error_handler = ahci_imx_error_handler,
.softreset = ahci_imx_softreset,
};
@@ -168,79 +193,6 @@ static const struct ata_port_info ahci_imx_port_info = {
.port_ops = &ahci_imx_ops,
};
-static int imx_sata_init(struct device *dev, void __iomem *mmio)
-{
- int ret = 0;
- unsigned int reg_val;
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
-
- ret = imx_sata_clock_enable(dev);
- if (ret < 0)
- return ret;
-
- /*
- * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
- * and IP vendor specific register HOST_TIMER1MS.
- * Configure CAP_SSS (support stagered spin up).
- * Implement the port0.
- * Get the ahb clock rate, and configure the TIMER1MS register.
- */
- reg_val = readl(mmio + HOST_CAP);
- if (!(reg_val & HOST_CAP_SSS)) {
- reg_val |= HOST_CAP_SSS;
- writel(reg_val, mmio + HOST_CAP);
- }
- reg_val = readl(mmio + HOST_PORTS_IMPL);
- if (!(reg_val & 0x1)) {
- reg_val |= 0x1;
- writel(reg_val, mmio + HOST_PORTS_IMPL);
- }
-
- reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
- writel(reg_val, mmio + HOST_TIMER1MS);
-
- return 0;
-}
-
-static void imx_sata_exit(struct device *dev)
-{
- imx_sata_clock_disable(dev);
-}
-
-static int imx_ahci_suspend(struct device *dev)
-{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
-
- /*
- * If no_device is set, The CLKs had been gated off in the
- * initialization so don't do it again here.
- */
- if (!imxpriv->no_device)
- imx_sata_clock_disable(dev);
-
- return 0;
-}
-
-static int imx_ahci_resume(struct device *dev)
-{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
- int ret = 0;
-
- if (!imxpriv->no_device)
- ret = imx_sata_clock_enable(dev);
-
- return ret;
-}
-
-static struct ahci_platform_data imx_sata_pdata = {
- .init = imx_sata_init,
- .exit = imx_sata_exit,
- .ata_port_info = &ahci_imx_port_info,
- .suspend = imx_ahci_suspend,
- .resume = imx_ahci_resume,
-
-};
-
static const struct of_device_id imx_ahci_of_match[] = {
{ .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 },
{ .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q },
@@ -251,151 +203,124 @@ MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
static int imx_ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct resource *mem, *irq, res[2];
const struct of_device_id *of_id;
- enum ahci_imx_type type;
- const struct ahci_platform_data *pdata = NULL;
+ struct ahci_host_priv *hpriv;
struct imx_ahci_priv *imxpriv;
- struct device *ahci_dev;
- struct platform_device *ahci_pdev;
+ unsigned int reg_val;
int ret;
of_id = of_match_device(imx_ahci_of_match, dev);
if (!of_id)
return -EINVAL;
- type = (enum ahci_imx_type)of_id->data;
- pdata = &imx_sata_pdata;
-
imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
- if (!imxpriv) {
- dev_err(dev, "can't alloc ahci_host_priv\n");
+ if (!imxpriv)
return -ENOMEM;
- }
-
- ahci_pdev = platform_device_alloc("ahci", -1);
- if (!ahci_pdev)
- return -ENODEV;
-
- ahci_dev = &ahci_pdev->dev;
- ahci_dev->parent = dev;
imxpriv->no_device = false;
imxpriv->first_time = true;
- imxpriv->type = type;
-
+ imxpriv->type = (enum ahci_imx_type)of_id->data;
imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
if (IS_ERR(imxpriv->ahb_clk)) {
dev_err(dev, "can't get ahb clock.\n");
- ret = PTR_ERR(imxpriv->ahb_clk);
- goto err_out;
+ return PTR_ERR(imxpriv->ahb_clk);
}
- if (type == AHCI_IMX53) {
- imxpriv->sata_gate_clk = devm_clk_get(dev, "sata_gate");
- if (IS_ERR(imxpriv->sata_gate_clk)) {
- dev_err(dev, "can't get sata_gate clock.\n");
- ret = PTR_ERR(imxpriv->sata_gate_clk);
- goto err_out;
+ if (imxpriv->type == AHCI_IMX6Q) {
+ imxpriv->gpr = syscon_regmap_lookup_by_compatible(
+ "fsl,imx6q-iomuxc-gpr");
+ if (IS_ERR(imxpriv->gpr)) {
+ dev_err(dev,
+ "failed to find fsl,imx6q-iomux-gpr regmap\n");
+ return PTR_ERR(imxpriv->gpr);
}
}
- imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref");
- if (IS_ERR(imxpriv->sata_ref_clk)) {
- dev_err(dev, "can't get sata_ref clock.\n");
- ret = PTR_ERR(imxpriv->sata_ref_clk);
- goto err_out;
- }
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ hpriv->plat_data = imxpriv;
- imxpriv->ahci_pdev = ahci_pdev;
- platform_set_drvdata(pdev, imxpriv);
+ ret = imx_sata_enable(hpriv);
+ if (ret)
+ return ret;
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!mem || !irq) {
- dev_err(dev, "no mmio/irq resource\n");
- ret = -ENOMEM;
- goto err_out;
+ /*
+ * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
+ * and IP vendor specific register HOST_TIMER1MS.
+ * Configure CAP_SSS (support stagered spin up).
+ * Implement the port0.
+ * Get the ahb clock rate, and configure the TIMER1MS register.
+ */
+ reg_val = readl(hpriv->mmio + HOST_CAP);
+ if (!(reg_val & HOST_CAP_SSS)) {
+ reg_val |= HOST_CAP_SSS;
+ writel(reg_val, hpriv->mmio + HOST_CAP);
+ }
+ reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL);
+ if (!(reg_val & 0x1)) {
+ reg_val |= 0x1;
+ writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
}
- res[0] = *mem;
- res[1] = *irq;
+ reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
+ writel(reg_val, hpriv->mmio + HOST_TIMER1MS);
- ahci_dev->coherent_dma_mask = DMA_BIT_MASK(32);
- ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask;
- ahci_dev->of_node = dev->of_node;
+ ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0);
+ if (ret)
+ imx_sata_disable(hpriv);
- if (type == AHCI_IMX6Q) {
- imxpriv->gpr = syscon_regmap_lookup_by_compatible(
- "fsl,imx6q-iomuxc-gpr");
- if (IS_ERR(imxpriv->gpr)) {
- dev_err(dev,
- "failed to find fsl,imx6q-iomux-gpr regmap\n");
- ret = PTR_ERR(imxpriv->gpr);
- goto err_out;
- }
+ return ret;
+}
- /*
- * Set PHY Paremeters, two steps to configure the GPR13,
- * one write for rest of parameters, mask of first write
- * is 0x07fffffe, and the other one write for setting
- * the mpll_clk_en happens in imx_sata_clock_enable().
- */
- regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK |
- IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK |
- IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK |
- IMX6Q_GPR13_SATA_SPD_MODE_MASK |
- IMX6Q_GPR13_SATA_MPLL_SS_EN |
- IMX6Q_GPR13_SATA_TX_ATTEN_MASK |
- IMX6Q_GPR13_SATA_TX_BOOST_MASK |
- IMX6Q_GPR13_SATA_TX_LVL_MASK |
- IMX6Q_GPR13_SATA_MPLL_CLK_EN |
- IMX6Q_GPR13_SATA_TX_EDGE_RATE,
- IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
- IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
- IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
- IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
- IMX6Q_GPR13_SATA_MPLL_SS_EN |
- IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
- IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
- IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
- }
+static void ahci_imx_host_stop(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
- ret = platform_device_add_resources(ahci_pdev, res, 2);
- if (ret)
- goto err_out;
+ imx_sata_disable(hpriv);
+}
- ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata));
- if (ret)
- goto err_out;
+#ifdef CONFIG_PM_SLEEP
+static int imx_ahci_suspend(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int ret;
- ret = platform_device_add(ahci_pdev);
- if (ret) {
-err_out:
- platform_device_put(ahci_pdev);
+ ret = ahci_platform_suspend_host(dev);
+ if (ret)
return ret;
- }
+
+ imx_sata_disable(hpriv);
return 0;
}
-static int imx_ahci_remove(struct platform_device *pdev)
+static int imx_ahci_resume(struct device *dev)
{
- struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev);
- struct platform_device *ahci_pdev = imxpriv->ahci_pdev;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int ret;
- platform_device_unregister(ahci_pdev);
- return 0;
+ ret = imx_sata_enable(hpriv);
+ if (ret)
+ return ret;
+
+ return ahci_platform_resume_host(dev);
}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume);
static struct platform_driver imx_ahci_driver = {
.probe = imx_ahci_probe,
- .remove = imx_ahci_remove,
+ .remove = ata_platform_remove_one,
.driver = {
.name = "ahci-imx",
.owner = THIS_MODULE,
.of_match_table = imx_ahci_of_match,
+ .pm = &ahci_imx_pm_ops,
},
};
module_platform_driver(imx_ahci_driver);
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 4b231baceb09..ef67e79944f9 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -12,135 +12,36 @@
* any later version.
*/
-#include <linux/clk.h>
#include <linux/kernel.h>
-#include <linux/gfp.h>
#include <linux/module.h>
#include <linux/pm.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/libata.h>
#include <linux/ahci_platform.h>
#include "ahci.h"
-static void ahci_host_stop(struct ata_host *host);
-
-enum ahci_type {
- AHCI, /* standard platform ahci */
- IMX53_AHCI, /* ahci on i.mx53 */
- STRICT_AHCI, /* delayed DMA engine start */
-};
-
-static struct platform_device_id ahci_devtype[] = {
- {
- .name = "ahci",
- .driver_data = AHCI,
- }, {
- .name = "imx53-ahci",
- .driver_data = IMX53_AHCI,
- }, {
- .name = "strict-ahci",
- .driver_data = STRICT_AHCI,
- }, {
- /* sentinel */
- }
-};
-MODULE_DEVICE_TABLE(platform, ahci_devtype);
-
-struct ata_port_operations ahci_platform_ops = {
- .inherits = &ahci_ops,
- .host_stop = ahci_host_stop,
-};
-EXPORT_SYMBOL_GPL(ahci_platform_ops);
-
-static struct ata_port_operations ahci_platform_retry_srst_ops = {
- .inherits = &ahci_pmp_retry_srst_ops,
- .host_stop = ahci_host_stop,
-};
-
-static const struct ata_port_info ahci_port_info[] = {
- /* by features */
- [AHCI] = {
- .flags = AHCI_FLAG_COMMON,
- .pio_mask = ATA_PIO4,
- .udma_mask = ATA_UDMA6,
- .port_ops = &ahci_platform_ops,
- },
- [IMX53_AHCI] = {
- .flags = AHCI_FLAG_COMMON,
- .pio_mask = ATA_PIO4,
- .udma_mask = ATA_UDMA6,
- .port_ops = &ahci_platform_retry_srst_ops,
- },
- [STRICT_AHCI] = {
- AHCI_HFLAGS (AHCI_HFLAG_DELAY_ENGINE),
- .flags = AHCI_FLAG_COMMON,
- .pio_mask = ATA_PIO4,
- .udma_mask = ATA_UDMA6,
- .port_ops = &ahci_platform_ops,
- },
-};
-
-static struct scsi_host_template ahci_platform_sht = {
- AHCI_SHT("ahci_platform"),
+static const struct ata_port_info ahci_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
};
static int ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ahci_platform_data *pdata = dev_get_platdata(dev);
- const struct platform_device_id *id = platform_get_device_id(pdev);
- struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0];
- const struct ata_port_info *ppi[] = { &pi, NULL };
struct ahci_host_priv *hpriv;
- struct ata_host *host;
- struct resource *mem;
- int irq;
- int n_ports;
- int i;
int rc;
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(dev, "no mmio space\n");
- return -EINVAL;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- dev_err(dev, "no irq\n");
- return -EINVAL;
- }
-
- if (pdata && pdata->ata_port_info)
- pi = *pdata->ata_port_info;
-
- hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- dev_err(dev, "can't alloc ahci_host_priv\n");
- return -ENOMEM;
- }
-
- hpriv->flags |= (unsigned long)pi.private_data;
-
- hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
- if (!hpriv->mmio) {
- dev_err(dev, "can't map %pR\n", mem);
- return -ENOMEM;
- }
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
- hpriv->clk = clk_get(dev, NULL);
- if (IS_ERR(hpriv->clk)) {
- dev_err(dev, "can't get clock\n");
- } else {
- rc = clk_prepare_enable(hpriv->clk);
- if (rc) {
- dev_err(dev, "clock prepare enable failed");
- goto free_clk;
- }
- }
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
/*
* Some platforms might need to prepare for mmio region access,
@@ -151,69 +52,10 @@ static int ahci_probe(struct platform_device *pdev)
if (pdata && pdata->init) {
rc = pdata->init(dev, hpriv->mmio);
if (rc)
- goto disable_unprepare_clk;
- }
-
- ahci_save_initial_config(dev, hpriv,
- pdata ? pdata->force_port_map : 0,
- pdata ? pdata->mask_port_map : 0);
-
- /* prepare host */
- if (hpriv->cap & HOST_CAP_NCQ)
- pi.flags |= ATA_FLAG_NCQ;
-
- if (hpriv->cap & HOST_CAP_PMP)
- pi.flags |= ATA_FLAG_PMP;
-
- ahci_set_em_messages(hpriv, &pi);
-
- /* CAP.NP sometimes indicate the index of the last enabled
- * port, at other times, that of the last possible port, so
- * determining the maximum port number requires looking at
- * both CAP.NP and port_map.
- */
- n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
-
- host = ata_host_alloc_pinfo(dev, ppi, n_ports);
- if (!host) {
- rc = -ENOMEM;
- goto pdata_exit;
- }
-
- host->private_data = hpriv;
-
- if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
- host->flags |= ATA_HOST_PARALLEL_SCAN;
- else
- dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
-
- if (pi.flags & ATA_FLAG_EM)
- ahci_reset_em(host);
-
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
-
- ata_port_desc(ap, "mmio %pR", mem);
- ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
-
- /* set enclosure management message type */
- if (ap->flags & ATA_FLAG_EM)
- ap->em_message_type = hpriv->em_msg_type;
-
- /* disabled/not-implemented port */
- if (!(hpriv->port_map & (1 << i)))
- ap->ops = &ata_dummy_port_ops;
+ goto disable_resources;
}
- rc = ahci_reset_controller(host);
- if (rc)
- goto pdata_exit;
-
- ahci_init_controller(host);
- ahci_print_info(host, "platform");
-
- rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
- &ahci_platform_sht);
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info, 0, 0);
if (rc)
goto pdata_exit;
@@ -221,115 +63,19 @@ static int ahci_probe(struct platform_device *pdev)
pdata_exit:
if (pdata && pdata->exit)
pdata->exit(dev);
-disable_unprepare_clk:
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
-free_clk:
- if (!IS_ERR(hpriv->clk))
- clk_put(hpriv->clk);
- return rc;
-}
-
-static void ahci_host_stop(struct ata_host *host)
-{
- struct device *dev = host->dev;
- struct ahci_platform_data *pdata = dev_get_platdata(dev);
- struct ahci_host_priv *hpriv = host->private_data;
-
- if (pdata && pdata->exit)
- pdata->exit(dev);
-
- if (!IS_ERR(hpriv->clk)) {
- clk_disable_unprepare(hpriv->clk);
- clk_put(hpriv->clk);
- }
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int ahci_suspend(struct device *dev)
-{
- struct ahci_platform_data *pdata = dev_get_platdata(dev);
- struct ata_host *host = dev_get_drvdata(dev);
- struct ahci_host_priv *hpriv = host->private_data;
- void __iomem *mmio = hpriv->mmio;
- u32 ctl;
- int rc;
-
- if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
- dev_err(dev, "firmware update required for suspend/resume\n");
- return -EIO;
- }
-
- /*
- * AHCI spec rev1.1 section 8.3.3:
- * Software must disable interrupts prior to requesting a
- * transition of the HBA to D3 state.
- */
- ctl = readl(mmio + HOST_CTL);
- ctl &= ~HOST_IRQ_EN;
- writel(ctl, mmio + HOST_CTL);
- readl(mmio + HOST_CTL); /* flush */
-
- rc = ata_host_suspend(host, PMSG_SUSPEND);
- if (rc)
- return rc;
-
- if (pdata && pdata->suspend)
- return pdata->suspend(dev);
-
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
-
- return 0;
-}
-
-static int ahci_resume(struct device *dev)
-{
- struct ahci_platform_data *pdata = dev_get_platdata(dev);
- struct ata_host *host = dev_get_drvdata(dev);
- struct ahci_host_priv *hpriv = host->private_data;
- int rc;
-
- if (!IS_ERR(hpriv->clk)) {
- rc = clk_prepare_enable(hpriv->clk);
- if (rc) {
- dev_err(dev, "clock prepare enable failed");
- return rc;
- }
- }
-
- if (pdata && pdata->resume) {
- rc = pdata->resume(dev);
- if (rc)
- goto disable_unprepare_clk;
- }
-
- if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
- rc = ahci_reset_controller(host);
- if (rc)
- goto disable_unprepare_clk;
-
- ahci_init_controller(host);
- }
-
- ata_host_resume(host);
-
- return 0;
-
-disable_unprepare_clk:
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
-
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
return rc;
}
-#endif
-static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume);
+static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
+ ahci_platform_resume);
static const struct of_device_id ahci_of_match[] = {
{ .compatible = "snps,spear-ahci", },
{ .compatible = "snps,exynos5440-ahci", },
{ .compatible = "ibm,476gtr-ahci", },
+ { .compatible = "snps,dwc-ahci", },
{},
};
MODULE_DEVICE_TABLE(of, ahci_of_match);
@@ -343,7 +89,6 @@ static struct platform_driver ahci_driver = {
.of_match_table = ahci_of_match,
.pm = &ahci_pm_ops,
},
- .id_table = ahci_devtype,
};
module_platform_driver(ahci_driver);
diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c
new file mode 100644
index 000000000000..633222226c19
--- /dev/null
+++ b/drivers/ata/ahci_st.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2012 STMicroelectronics Limited
+ *
+ * Authors: Francesco Virlinzi <francesco.virlinzi@st.com>
+ * Alexandre Torgue <alexandre.torgue@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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/ahci_platform.h>
+#include <linux/libata.h>
+#include <linux/reset.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+
+#include "ahci.h"
+
+#define ST_AHCI_OOBR 0xbc
+#define ST_AHCI_OOBR_WE BIT(31)
+#define ST_AHCI_OOBR_CWMIN_SHIFT 24
+#define ST_AHCI_OOBR_CWMAX_SHIFT 16
+#define ST_AHCI_OOBR_CIMIN_SHIFT 8
+#define ST_AHCI_OOBR_CIMAX_SHIFT 0
+
+struct st_ahci_drv_data {
+ struct platform_device *ahci;
+ struct reset_control *pwr;
+ struct reset_control *sw_rst;
+ struct reset_control *pwr_rst;
+ struct ahci_host_priv *hpriv;
+};
+
+static void st_ahci_configure_oob(void __iomem *mmio)
+{
+ unsigned long old_val, new_val;
+
+ new_val = (0x02 << ST_AHCI_OOBR_CWMIN_SHIFT) |
+ (0x04 << ST_AHCI_OOBR_CWMAX_SHIFT) |
+ (0x08 << ST_AHCI_OOBR_CIMIN_SHIFT) |
+ (0x0C << ST_AHCI_OOBR_CIMAX_SHIFT);
+
+ old_val = readl(mmio + ST_AHCI_OOBR);
+ writel(old_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
+ writel(new_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
+ writel(new_val, mmio + ST_AHCI_OOBR);
+}
+
+static int st_ahci_deassert_resets(struct device *dev)
+{
+ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+ int err;
+
+ if (drv_data->pwr) {
+ err = reset_control_deassert(drv_data->pwr);
+ if (err) {
+ dev_err(dev, "unable to bring out of pwrdwn\n");
+ return err;
+ }
+ }
+
+ st_ahci_configure_oob(drv_data->hpriv->mmio);
+
+ if (drv_data->sw_rst) {
+ err = reset_control_deassert(drv_data->sw_rst);
+ if (err) {
+ dev_err(dev, "unable to bring out of sw-rst\n");
+ return err;
+ }
+ }
+
+ if (drv_data->pwr_rst) {
+ err = reset_control_deassert(drv_data->pwr_rst);
+ if (err) {
+ dev_err(dev, "unable to bring out of pwr-rst\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static void st_ahci_host_stop(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct device *dev = host->dev;
+ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+ int err;
+
+ if (drv_data->pwr) {
+ err = reset_control_assert(drv_data->pwr);
+ if (err)
+ dev_err(dev, "unable to pwrdwn\n");
+ }
+
+ ahci_platform_disable_resources(hpriv);
+}
+
+static int st_ahci_probe_resets(struct platform_device *pdev)
+{
+ struct st_ahci_drv_data *drv_data = platform_get_drvdata(pdev);
+
+ drv_data->pwr = devm_reset_control_get(&pdev->dev, "pwr-dwn");
+ if (IS_ERR(drv_data->pwr)) {
+ dev_info(&pdev->dev, "power reset control not defined\n");
+ drv_data->pwr = NULL;
+ }
+
+ drv_data->sw_rst = devm_reset_control_get(&pdev->dev, "sw-rst");
+ if (IS_ERR(drv_data->sw_rst)) {
+ dev_info(&pdev->dev, "soft reset control not defined\n");
+ drv_data->sw_rst = NULL;
+ }
+
+ drv_data->pwr_rst = devm_reset_control_get(&pdev->dev, "pwr-rst");
+ if (IS_ERR(drv_data->pwr_rst)) {
+ dev_dbg(&pdev->dev, "power soft reset control not defined\n");
+ drv_data->pwr_rst = NULL;
+ }
+
+ return st_ahci_deassert_resets(&pdev->dev);
+}
+
+static struct ata_port_operations st_ahci_port_ops = {
+ .inherits = &ahci_platform_ops,
+ .host_stop = st_ahci_host_stop,
+};
+
+static const struct ata_port_info st_ahci_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &st_ahci_port_ops,
+};
+
+static int st_ahci_probe(struct platform_device *pdev)
+{
+ struct st_ahci_drv_data *drv_data;
+ struct ahci_host_priv *hpriv;
+ int err;
+
+ drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
+ if (!drv_data)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, drv_data);
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ drv_data->hpriv = hpriv;
+
+ err = st_ahci_probe_resets(pdev);
+ if (err)
+ return err;
+
+ err = ahci_platform_enable_resources(hpriv);
+ if (err)
+ return err;
+
+ err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info, 0, 0);
+ if (err) {
+ ahci_platform_disable_resources(hpriv);
+ return err;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int st_ahci_suspend(struct device *dev)
+{
+ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = drv_data->hpriv;
+ int err;
+
+ err = ahci_platform_suspend_host(dev);
+ if (err)
+ return err;
+
+ if (drv_data->pwr) {
+ err = reset_control_assert(drv_data->pwr);
+ if (err) {
+ dev_err(dev, "unable to pwrdwn");
+ return err;
+ }
+ }
+
+ ahci_platform_disable_resources(hpriv);
+
+ return 0;
+}
+
+static int st_ahci_resume(struct device *dev)
+{
+ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = drv_data->hpriv;
+ int err;
+
+ err = ahci_platform_enable_resources(hpriv);
+ if (err)
+ return err;
+
+ err = st_ahci_deassert_resets(dev);
+ if (err) {
+ ahci_platform_disable_resources(hpriv);
+ return err;
+ }
+
+ return ahci_platform_resume_host(dev);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(st_ahci_pm_ops, st_ahci_suspend, st_ahci_resume);
+
+static struct of_device_id st_ahci_match[] = {
+ { .compatible = "st,ahci", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, st_ahci_match);
+
+static struct platform_driver st_ahci_driver = {
+ .driver = {
+ .name = "st_ahci",
+ .owner = THIS_MODULE,
+ .pm = &st_ahci_pm_ops,
+ .of_match_table = of_match_ptr(st_ahci_match),
+ },
+ .probe = st_ahci_probe,
+ .remove = ata_platform_remove_one,
+};
+module_platform_driver(st_ahci_driver);
+
+MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>");
+MODULE_AUTHOR("Francesco Virlinzi <francesco.virlinzi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics SATA AHCI Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
new file mode 100644
index 000000000000..42d3f64e74b3
--- /dev/null
+++ b/drivers/ata/ahci_sunxi.c
@@ -0,0 +1,249 @@
+/*
+ * Allwinner sunxi AHCI SATA platform driver
+ * Copyright 2013 Olliver Schinagl <oliver@schinagl.nl>
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
+ * Based on code from Allwinner Technology Co., Ltd. <www.allwinnertech.com>,
+ * Daniel Wang <danielwang@allwinnertech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/ahci_platform.h>
+#include <linux/clk.h>
+#include <linux/errno.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 "ahci.h"
+
+#define AHCI_BISTAFR 0x00a0
+#define AHCI_BISTCR 0x00a4
+#define AHCI_BISTFCTR 0x00a8
+#define AHCI_BISTSR 0x00ac
+#define AHCI_BISTDECR 0x00b0
+#define AHCI_DIAGNR0 0x00b4
+#define AHCI_DIAGNR1 0x00b8
+#define AHCI_OOBR 0x00bc
+#define AHCI_PHYCS0R 0x00c0
+#define AHCI_PHYCS1R 0x00c4
+#define AHCI_PHYCS2R 0x00c8
+#define AHCI_TIMER1MS 0x00e0
+#define AHCI_GPARAM1R 0x00e8
+#define AHCI_GPARAM2R 0x00ec
+#define AHCI_PPARAMR 0x00f0
+#define AHCI_TESTR 0x00f4
+#define AHCI_VERSIONR 0x00f8
+#define AHCI_IDR 0x00fc
+#define AHCI_RWCR 0x00fc
+#define AHCI_P0DMACR 0x0170
+#define AHCI_P0PHYCR 0x0178
+#define AHCI_P0PHYSR 0x017c
+
+static void sunxi_clrbits(void __iomem *reg, u32 clr_val)
+{
+ u32 reg_val;
+
+ reg_val = readl(reg);
+ reg_val &= ~(clr_val);
+ writel(reg_val, reg);
+}
+
+static void sunxi_setbits(void __iomem *reg, u32 set_val)
+{
+ u32 reg_val;
+
+ reg_val = readl(reg);
+ reg_val |= set_val;
+ writel(reg_val, reg);
+}
+
+static void sunxi_clrsetbits(void __iomem *reg, u32 clr_val, u32 set_val)
+{
+ u32 reg_val;
+
+ reg_val = readl(reg);
+ reg_val &= ~(clr_val);
+ reg_val |= set_val;
+ writel(reg_val, reg);
+}
+
+static u32 sunxi_getbits(void __iomem *reg, u8 mask, u8 shift)
+{
+ return (readl(reg) >> shift) & mask;
+}
+
+static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base)
+{
+ u32 reg_val;
+ int timeout;
+
+ /* This magic is from the original code */
+ writel(0, reg_base + AHCI_RWCR);
+ msleep(5);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
+ (0x7 << 24),
+ (0x5 << 24) | BIT(23) | BIT(18));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS1R,
+ (0x3 << 16) | (0x1f << 8) | (0x3 << 6),
+ (0x2 << 16) | (0x6 << 8) | (0x2 << 6));
+ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(28) | BIT(15));
+ sunxi_clrbits(reg_base + AHCI_PHYCS1R, BIT(19));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
+ (0x7 << 20), (0x3 << 20));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS2R,
+ (0x1f << 5), (0x19 << 5));
+ msleep(5);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19));
+
+ timeout = 250; /* Power up takes aprox 50 us */
+ do {
+ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28);
+ if (reg_val == 0x02)
+ break;
+
+ if (--timeout == 0) {
+ dev_err(dev, "PHY power up failed.\n");
+ return -EIO;
+ }
+ udelay(1);
+ } while (1);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS2R, (0x1 << 24));
+
+ timeout = 100; /* Calibration takes aprox 10 us */
+ do {
+ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24);
+ if (reg_val == 0x00)
+ break;
+
+ if (--timeout == 0) {
+ dev_err(dev, "PHY calibration failed.\n");
+ return -EIO;
+ }
+ udelay(1);
+ } while (1);
+
+ msleep(15);
+
+ writel(0x7, reg_base + AHCI_RWCR);
+
+ return 0;
+}
+
+static void ahci_sunxi_start_engine(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
+ /* Setup DMA before DMA start */
+ sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ff00, 0x00004400);
+
+ /* Start DMA */
+ sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START);
+}
+
+static const struct ata_port_info ahci_sunxi_port_info = {
+ AHCI_HFLAGS(AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
+ AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ),
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
+};
+
+static int ahci_sunxi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ hpriv->start_engine = ahci_sunxi_start_engine;
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
+ if (rc)
+ goto disable_resources;
+
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info, 0, 0);
+ if (rc)
+ goto disable_resources;
+
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ahci_sunxi_resume(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
+ if (rc)
+ goto disable_resources;
+
+ rc = ahci_platform_resume_host(dev);
+ if (rc)
+ goto disable_resources;
+
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend,
+ ahci_sunxi_resume);
+
+static const struct of_device_id ahci_sunxi_of_match[] = {
+ { .compatible = "allwinner,sun4i-a10-ahci", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match);
+
+static struct platform_driver ahci_sunxi_driver = {
+ .probe = ahci_sunxi_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "ahci-sunxi",
+ .owner = THIS_MODULE,
+ .of_match_table = ahci_sunxi_of_match,
+ .pm = &ahci_sunxi_pm_ops,
+ },
+};
+module_platform_driver(ahci_sunxi_driver);
+
+MODULE_DESCRIPTION("Allwinner sunxi AHCI SATA driver");
+MODULE_AUTHOR("Olliver Schinagl <oliver@schinagl.nl>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
new file mode 100644
index 000000000000..77c89bf171f1
--- /dev/null
+++ b/drivers/ata/ahci_xgene.c
@@ -0,0 +1,486 @@
+/*
+ * AppliedMicro X-Gene SoC SATA Host Controller Driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Author: Loc Ho <lho@apm.com>
+ * Tuan Phan <tphan@apm.com>
+ * Suman Tripathi <stripathi@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/>.
+ *
+ * NOTE: PM support is not currently available.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/ahci_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/phy/phy.h>
+#include "ahci.h"
+
+/* Max # of disk per a controller */
+#define MAX_AHCI_CHN_PERCTR 2
+
+/* MUX CSR */
+#define SATA_ENET_CONFIG_REG 0x00000000
+#define CFG_SATA_ENET_SELECT_MASK 0x00000001
+
+/* SATA core host controller CSR */
+#define SLVRDERRATTRIBUTES 0x00000000
+#define SLVWRERRATTRIBUTES 0x00000004
+#define MSTRDERRATTRIBUTES 0x00000008
+#define MSTWRERRATTRIBUTES 0x0000000c
+#define BUSCTLREG 0x00000014
+#define IOFMSTRWAUX 0x00000018
+#define INTSTATUSMASK 0x0000002c
+#define ERRINTSTATUS 0x00000030
+#define ERRINTSTATUSMASK 0x00000034
+
+/* SATA host AHCI CSR */
+#define PORTCFG 0x000000a4
+#define PORTADDR_SET(dst, src) \
+ (((dst) & ~0x0000003f) | (((u32)(src)) & 0x0000003f))
+#define PORTPHY1CFG 0x000000a8
+#define PORTPHY1CFG_FRCPHYRDY_SET(dst, src) \
+ (((dst) & ~0x00100000) | (((u32)(src) << 0x14) & 0x00100000))
+#define PORTPHY2CFG 0x000000ac
+#define PORTPHY3CFG 0x000000b0
+#define PORTPHY4CFG 0x000000b4
+#define PORTPHY5CFG 0x000000b8
+#define SCTL0 0x0000012C
+#define PORTPHY5CFG_RTCHG_SET(dst, src) \
+ (((dst) & ~0xfff00000) | (((u32)(src) << 0x14) & 0xfff00000))
+#define PORTAXICFG_EN_CONTEXT_SET(dst, src) \
+ (((dst) & ~0x01000000) | (((u32)(src) << 0x18) & 0x01000000))
+#define PORTAXICFG 0x000000bc
+#define PORTAXICFG_OUTTRANS_SET(dst, src) \
+ (((dst) & ~0x00f00000) | (((u32)(src) << 0x14) & 0x00f00000))
+
+/* SATA host controller AXI CSR */
+#define INT_SLV_TMOMASK 0x00000010
+
+/* SATA diagnostic CSR */
+#define CFG_MEM_RAM_SHUTDOWN 0x00000070
+#define BLOCK_MEM_RDY 0x00000074
+
+struct xgene_ahci_context {
+ struct ahci_host_priv *hpriv;
+ struct device *dev;
+ void __iomem *csr_core; /* Core CSR address of IP */
+ void __iomem *csr_diag; /* Diag CSR address of IP */
+ void __iomem *csr_axi; /* AXI CSR address of IP */
+ void __iomem *csr_mux; /* MUX CSR address of IP */
+};
+
+static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx)
+{
+ dev_dbg(ctx->dev, "Release memory from shutdown\n");
+ writel(0x0, ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN);
+ readl(ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); /* Force a barrier */
+ msleep(1); /* reset may take up to 1ms */
+ if (readl(ctx->csr_diag + BLOCK_MEM_RDY) != 0xFFFFFFFF) {
+ dev_err(ctx->dev, "failed to release memory from shutdown\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/**
+ * xgene_ahci_read_id - Read ID data from the specified device
+ * @dev: device
+ * @tf: proposed taskfile
+ * @id: data buffer
+ *
+ * This custom read ID function is required due to the fact that the HW
+ * does not support DEVSLP and the controller state machine may get stuck
+ * after processing the ID query command.
+ */
+static unsigned int xgene_ahci_read_id(struct ata_device *dev,
+ struct ata_taskfile *tf, u16 *id)
+{
+ u32 err_mask;
+ void __iomem *port_mmio = ahci_port_base(dev->link->ap);
+
+ err_mask = ata_do_dev_read_id(dev, tf, id);
+ if (err_mask)
+ return err_mask;
+
+ /*
+ * Mask reserved area. Word78 spec of Link Power Management
+ * bit15-8: reserved
+ * bit7: NCQ autosence
+ * bit6: Software settings preservation supported
+ * bit5: reserved
+ * bit4: In-order sata delivery supported
+ * bit3: DIPM requests supported
+ * bit2: DMA Setup FIS Auto-Activate optimization supported
+ * bit1: DMA Setup FIX non-Zero buffer offsets supported
+ * bit0: Reserved
+ *
+ * Clear reserved bit 8 (DEVSLP bit) as we don't support DEVSLP
+ */
+ id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8);
+
+ /*
+ * Due to HW errata, restart the port if no other command active.
+ * Otherwise the controller may get stuck.
+ */
+ if (!readl(port_mmio + PORT_CMD_ISSUE)) {
+ writel(PORT_CMD_FIS_RX, port_mmio + PORT_CMD);
+ readl(port_mmio + PORT_CMD); /* Force a barrier */
+ writel(PORT_CMD_FIS_RX | PORT_CMD_START, port_mmio + PORT_CMD);
+ readl(port_mmio + PORT_CMD); /* Force a barrier */
+ }
+ return 0;
+}
+
+static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel)
+{
+ void __iomem *mmio = ctx->hpriv->mmio;
+ u32 val;
+
+ dev_dbg(ctx->dev, "port configure mmio 0x%p channel %d\n",
+ mmio, channel);
+ val = readl(mmio + PORTCFG);
+ val = PORTADDR_SET(val, channel == 0 ? 2 : 3);
+ writel(val, mmio + PORTCFG);
+ readl(mmio + PORTCFG); /* Force a barrier */
+ /* Disable fix rate */
+ writel(0x0001fffe, mmio + PORTPHY1CFG);
+ readl(mmio + PORTPHY1CFG); /* Force a barrier */
+ writel(0x5018461c, mmio + PORTPHY2CFG);
+ readl(mmio + PORTPHY2CFG); /* Force a barrier */
+ writel(0x1c081907, mmio + PORTPHY3CFG);
+ readl(mmio + PORTPHY3CFG); /* Force a barrier */
+ writel(0x1c080815, mmio + PORTPHY4CFG);
+ readl(mmio + PORTPHY4CFG); /* Force a barrier */
+ /* Set window negotiation */
+ val = readl(mmio + PORTPHY5CFG);
+ val = PORTPHY5CFG_RTCHG_SET(val, 0x300);
+ writel(val, mmio + PORTPHY5CFG);
+ readl(mmio + PORTPHY5CFG); /* Force a barrier */
+ val = readl(mmio + PORTAXICFG);
+ val = PORTAXICFG_EN_CONTEXT_SET(val, 0x1); /* Enable context mgmt */
+ val = PORTAXICFG_OUTTRANS_SET(val, 0xe); /* Set outstanding */
+ writel(val, mmio + PORTAXICFG);
+ readl(mmio + PORTAXICFG); /* Force a barrier */
+}
+
+/**
+ * xgene_ahci_do_hardreset - Issue the actual COMRESET
+ * @link: link to reset
+ * @deadline: deadline jiffies for the operation
+ * @online: Return value to indicate if device online
+ *
+ * Due to the limitation of the hardware PHY, a difference set of setting is
+ * required for each supported disk speed - Gen3 (6.0Gbps), Gen2 (3.0Gbps),
+ * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will
+ * report disparity error and etc. In addition, during COMRESET, there can
+ * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and
+ * SERR_10B_8B_ERR, the PHY receiver line must be reseted. The following
+ * algorithm is followed to proper configure the hardware PHY during COMRESET:
+ *
+ * Alg Part 1:
+ * 1. Start the PHY at Gen3 speed (default setting)
+ * 2. Issue the COMRESET
+ * 3. If no link, go to Alg Part 3
+ * 4. If link up, determine if the negotiated speed matches the PHY
+ * configured speed
+ * 5. If they matched, go to Alg Part 2
+ * 6. If they do not matched and first time, configure the PHY for the linked
+ * up disk speed and repeat step 2
+ * 7. Go to Alg Part 2
+ *
+ * Alg Part 2:
+ * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error
+ * reported in the register PORT_SCR_ERR, then reset the PHY receiver line
+ * 2. Go to Alg Part 3
+ *
+ * Alg Part 3:
+ * 1. Clear any pending from register PORT_SCR_ERR.
+ *
+ * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition
+ * and until the underlying PHY supports an method to reset the receiver
+ * line, on detection of SERR_DISPARITY or SERR_10B_8B_ERR errors,
+ * an warning message will be printed.
+ */
+static int xgene_ahci_do_hardreset(struct ata_link *link,
+ unsigned long deadline, bool *online)
+{
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+ struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct xgene_ahci_context *ctx = hpriv->plat_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ata_taskfile tf;
+ int rc;
+ u32 val;
+
+ /* clear D2H reception area to properly wait for D2H FIS */
+ ata_tf_init(link->device, &tf);
+ tf.command = ATA_BUSY;
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+ rc = sata_link_hardreset(link, timing, deadline, online,
+ ahci_check_ready);
+
+ val = readl(port_mmio + PORT_SCR_ERR);
+ if (val & (SERR_DISPARITY | SERR_10B_8B_ERR))
+ dev_warn(ctx->dev, "link has error\n");
+
+ /* clear all errors if any pending */
+ val = readl(port_mmio + PORT_SCR_ERR);
+ writel(val, port_mmio + PORT_SCR_ERR);
+
+ return rc;
+}
+
+static int xgene_ahci_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ bool online;
+ int rc;
+ u32 portcmd_saved;
+ u32 portclb_saved;
+ u32 portclbhi_saved;
+ u32 portrxfis_saved;
+ u32 portrxfishi_saved;
+
+ /* As hardreset resets these CSR, save it to restore later */
+ portcmd_saved = readl(port_mmio + PORT_CMD);
+ portclb_saved = readl(port_mmio + PORT_LST_ADDR);
+ portclbhi_saved = readl(port_mmio + PORT_LST_ADDR_HI);
+ portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR);
+ portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI);
+
+ ahci_stop_engine(ap);
+
+ rc = xgene_ahci_do_hardreset(link, deadline, &online);
+
+ /* As controller hardreset clears them, restore them */
+ writel(portcmd_saved, port_mmio + PORT_CMD);
+ writel(portclb_saved, port_mmio + PORT_LST_ADDR);
+ writel(portclbhi_saved, port_mmio + PORT_LST_ADDR_HI);
+ writel(portrxfis_saved, port_mmio + PORT_FIS_ADDR);
+ writel(portrxfishi_saved, port_mmio + PORT_FIS_ADDR_HI);
+
+ hpriv->start_engine(ap);
+
+ if (online)
+ *class = ahci_dev_classify(ap);
+
+ return rc;
+}
+
+static void xgene_ahci_host_stop(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+
+ ahci_platform_disable_resources(hpriv);
+}
+
+static struct ata_port_operations xgene_ahci_ops = {
+ .inherits = &ahci_ops,
+ .host_stop = xgene_ahci_host_stop,
+ .hardreset = xgene_ahci_hardreset,
+ .read_id = xgene_ahci_read_id,
+};
+
+static const struct ata_port_info xgene_ahci_port_info = {
+ AHCI_HFLAGS(AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ),
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &xgene_ahci_ops,
+};
+
+static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv)
+{
+ struct xgene_ahci_context *ctx = hpriv->plat_data;
+ int i;
+ int rc;
+ u32 val;
+
+ /* Remove IP RAM out of shutdown */
+ rc = xgene_ahci_init_memram(ctx);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < MAX_AHCI_CHN_PERCTR; i++)
+ xgene_ahci_set_phy_cfg(ctx, i);
+
+ /* AXI disable Mask */
+ writel(0xffffffff, hpriv->mmio + HOST_IRQ_STAT);
+ readl(hpriv->mmio + HOST_IRQ_STAT); /* Force a barrier */
+ writel(0, ctx->csr_core + INTSTATUSMASK);
+ val = readl(ctx->csr_core + INTSTATUSMASK); /* Force a barrier */
+ dev_dbg(ctx->dev, "top level interrupt mask 0x%X value 0x%08X\n",
+ INTSTATUSMASK, val);
+
+ writel(0x0, ctx->csr_core + ERRINTSTATUSMASK);
+ readl(ctx->csr_core + ERRINTSTATUSMASK); /* Force a barrier */
+ writel(0x0, ctx->csr_axi + INT_SLV_TMOMASK);
+ readl(ctx->csr_axi + INT_SLV_TMOMASK);
+
+ /* Enable AXI Interrupt */
+ writel(0xffffffff, ctx->csr_core + SLVRDERRATTRIBUTES);
+ writel(0xffffffff, ctx->csr_core + SLVWRERRATTRIBUTES);
+ writel(0xffffffff, ctx->csr_core + MSTRDERRATTRIBUTES);
+ writel(0xffffffff, ctx->csr_core + MSTWRERRATTRIBUTES);
+
+ /* Enable coherency */
+ val = readl(ctx->csr_core + BUSCTLREG);
+ val &= ~0x00000002; /* Enable write coherency */
+ val &= ~0x00000001; /* Enable read coherency */
+ writel(val, ctx->csr_core + BUSCTLREG);
+
+ val = readl(ctx->csr_core + IOFMSTRWAUX);
+ val |= (1 << 3); /* Enable read coherency */
+ val |= (1 << 9); /* Enable write coherency */
+ writel(val, ctx->csr_core + IOFMSTRWAUX);
+ val = readl(ctx->csr_core + IOFMSTRWAUX);
+ dev_dbg(ctx->dev, "coherency 0x%X value 0x%08X\n",
+ IOFMSTRWAUX, val);
+
+ return rc;
+}
+
+static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx)
+{
+ u32 val;
+
+ /* Check for optional MUX resource */
+ if (IS_ERR(ctx->csr_mux))
+ return 0;
+
+ val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG);
+ val &= ~CFG_SATA_ENET_SELECT_MASK;
+ writel(val, ctx->csr_mux + SATA_ENET_CONFIG_REG);
+ val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG);
+ return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0;
+}
+
+static int xgene_ahci_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct xgene_ahci_context *ctx;
+ struct resource *res;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ hpriv->plat_data = ctx;
+ ctx->hpriv = hpriv;
+ ctx->dev = dev;
+
+ /* Retrieve the IP core resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ ctx->csr_core = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ctx->csr_core))
+ return PTR_ERR(ctx->csr_core);
+
+ /* Retrieve the IP diagnostic resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ ctx->csr_diag = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ctx->csr_diag))
+ return PTR_ERR(ctx->csr_diag);
+
+ /* Retrieve the IP AXI resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ ctx->csr_axi = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ctx->csr_axi))
+ return PTR_ERR(ctx->csr_axi);
+
+ /* Retrieve the optional IP mux resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+ ctx->csr_mux = devm_ioremap_resource(dev, res);
+
+ dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core,
+ hpriv->mmio);
+
+ /* Select ATA */
+ if ((rc = xgene_ahci_mux_select(ctx))) {
+ dev_err(dev, "SATA mux selection failed error %d\n", rc);
+ return -ENODEV;
+ }
+
+ /* Due to errata, HW requires full toggle transition */
+ rc = ahci_platform_enable_clks(hpriv);
+ if (rc)
+ goto disable_resources;
+ ahci_platform_disable_clks(hpriv);
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ goto disable_resources;
+
+ /* Configure the host controller */
+ xgene_ahci_hw_init(hpriv);
+
+ /*
+ * Setup DMA mask. This is preliminary until the DMA range is sorted
+ * out.
+ */
+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+ if (rc) {
+ dev_err(dev, "Unable to set dma mask\n");
+ goto disable_resources;
+ }
+
+ rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, 0, 0);
+ if (rc)
+ goto disable_resources;
+
+ dev_dbg(dev, "X-Gene SATA host controller initialized\n");
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+
+static const struct of_device_id xgene_ahci_of_match[] = {
+ {.compatible = "apm,xgene-ahci"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, xgene_ahci_of_match);
+
+static struct platform_driver xgene_ahci_driver = {
+ .probe = xgene_ahci_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "xgene-ahci",
+ .owner = THIS_MODULE,
+ .of_match_table = xgene_ahci_of_match,
+ },
+};
+
+module_platform_driver(xgene_ahci_driver);
+
+MODULE_DESCRIPTION("APM X-Gene AHCI SATA driver");
+MODULE_AUTHOR("Loc Ho <lho@apm.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.4");
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 7d196656adb5..9498a7d3846f 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 36605abe5a67..6bd4f660b4e1 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -35,7 +35,6 @@
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -394,6 +393,9 @@ static ssize_t ahci_show_em_supported(struct device *dev,
*
* If inconsistent, config values are fixed up by this function.
*
+ * If it is not set already this function sets hpriv->start_engine to
+ * ahci_start_engine.
+ *
* LOCKING:
* None.
*/
@@ -500,6 +502,9 @@ void ahci_save_initial_config(struct device *dev,
hpriv->cap = cap;
hpriv->cap2 = cap2;
hpriv->port_map = port_map;
+
+ if (!hpriv->start_engine)
+ hpriv->start_engine = ahci_start_engine;
}
EXPORT_SYMBOL_GPL(ahci_save_initial_config);
@@ -766,7 +771,7 @@ static void ahci_start_port(struct ata_port *ap)
/* enable DMA */
if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* turn on LEDs */
if (ap->flags & ATA_FLAG_EM) {
@@ -1032,12 +1037,13 @@ static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
size_t size)
{
- int state;
+ unsigned int state;
int pmp;
struct ahci_port_priv *pp = ap->private_data;
struct ahci_em_priv *emp;
- state = simple_strtoul(buf, NULL, 0);
+ if (kstrtouint(buf, 0, &state) < 0)
+ return -EINVAL;
/* get the slot number from the message */
pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
@@ -1234,7 +1240,7 @@ int ahci_kick_engine(struct ata_port *ap)
/* restart engine */
out_restart:
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
return rc;
}
EXPORT_SYMBOL_GPL(ahci_kick_engine);
@@ -1387,8 +1393,8 @@ static int ahci_bad_pmp_check_ready(struct ata_link *link)
return ata_check_ready(status);
}
-int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
+static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
{
struct ata_port *ap = link->ap;
void __iomem *port_mmio = ahci_port_base(ap);
@@ -1426,6 +1432,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
@@ -1443,7 +1450,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, timing, deadline, &online,
ahci_check_ready);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
if (online)
*class = ahci_dev_classify(ap);
@@ -1629,7 +1636,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
}
if (irq_stat & PORT_IRQ_UNK_FIS) {
- u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
+ u32 *unk = pp->rx_fis + RX_FIS_UNK;
active_ehi->err_mask |= AC_ERR_HSM;
active_ehi->action |= ATA_EH_RESET;
@@ -2007,10 +2014,12 @@ static void ahci_thaw(struct ata_port *ap)
void ahci_error_handler(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
/* restart engine */
ahci_stop_engine(ap);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
}
sata_pmp_error_handler(ap);
@@ -2031,6 +2040,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
struct ata_device *dev = ap->link.device;
u32 devslp, dm, dito, mdat, deto;
@@ -2094,7 +2104,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
PORT_DEVSLP_ADSE);
writel(devslp, port_mmio + PORT_DEVSLP);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* enable device sleep feature for the drive */
err_mask = ata_dev_set_feature(dev,
@@ -2106,6 +2116,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
static void ahci_enable_fbs(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 fbs;
@@ -2134,11 +2145,12 @@ static void ahci_enable_fbs(struct ata_port *ap)
} else
dev_err(ap->host->dev, "Failed to enable FBS\n");
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
}
static void ahci_disable_fbs(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 fbs;
@@ -2166,7 +2178,7 @@ static void ahci_disable_fbs(struct ata_port *ap)
pp->fbs_enabled = false;
}
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
}
static void ahci_pmp_attach(struct ata_port *ap)
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
new file mode 100644
index 000000000000..7cb3a85719c0
--- /dev/null
+++ b/drivers/ata/libahci_platform.c
@@ -0,0 +1,541 @@
+/*
+ * AHCI SATA platform library
+ *
+ * Copyright 2004-2005 Red Hat, Inc.
+ * Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2010 MontaVista Software, LLC.
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/pm_runtime.h>
+#include "ahci.h"
+
+static void ahci_host_stop(struct ata_host *host);
+
+struct ata_port_operations ahci_platform_ops = {
+ .inherits = &ahci_ops,
+ .host_stop = ahci_host_stop,
+};
+EXPORT_SYMBOL_GPL(ahci_platform_ops);
+
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT("ahci_platform"),
+};
+
+/**
+ * ahci_platform_enable_clks - Enable platform clocks
+ * @hpriv: host private area to store config values
+ *
+ * This function enables all the clks found in hpriv->clks, starting at
+ * index 0. If any clk fails to enable it disables all the clks already
+ * enabled in reverse order, and then returns an error.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
+{
+ int c, rc;
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
+ rc = clk_prepare_enable(hpriv->clks[c]);
+ if (rc)
+ goto disable_unprepare_clk;
+ }
+ return 0;
+
+disable_unprepare_clk:
+ while (--c >= 0)
+ clk_disable_unprepare(hpriv->clks[c]);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
+
+/**
+ * ahci_platform_disable_clks - Disable platform clocks
+ * @hpriv: host private area to store config values
+ *
+ * This function disables all the clks found in hpriv->clks, in reverse
+ * order of ahci_platform_enable_clks (starting at the end of the array).
+ */
+void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
+{
+ int c;
+
+ for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
+ if (hpriv->clks[c])
+ clk_disable_unprepare(hpriv->clks[c]);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
+
+/**
+ * ahci_platform_enable_resources - Enable platform resources
+ * @hpriv: host private area to store config values
+ *
+ * This function enables all ahci_platform managed resources in the
+ * following order:
+ * 1) Regulator
+ * 2) Clocks (through ahci_platform_enable_clks)
+ * 3) Phy
+ *
+ * If resource enabling fails at any point the previous enabled resources
+ * are disabled in reverse order.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
+{
+ int rc;
+
+ if (hpriv->target_pwr) {
+ rc = regulator_enable(hpriv->target_pwr);
+ if (rc)
+ return rc;
+ }
+
+ rc = ahci_platform_enable_clks(hpriv);
+ if (rc)
+ goto disable_regulator;
+
+ if (hpriv->phy) {
+ rc = phy_init(hpriv->phy);
+ if (rc)
+ goto disable_clks;
+
+ rc = phy_power_on(hpriv->phy);
+ if (rc) {
+ phy_exit(hpriv->phy);
+ goto disable_clks;
+ }
+ }
+
+ return 0;
+
+disable_clks:
+ ahci_platform_disable_clks(hpriv);
+
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
+
+/**
+ * ahci_platform_disable_resources - Disable platform resources
+ * @hpriv: host private area to store config values
+ *
+ * This function disables all ahci_platform managed resources in the
+ * following order:
+ * 1) Phy
+ * 2) Clocks (through ahci_platform_disable_clks)
+ * 3) Regulator
+ */
+void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
+{
+ if (hpriv->phy) {
+ phy_power_off(hpriv->phy);
+ phy_exit(hpriv->phy);
+ }
+
+ ahci_platform_disable_clks(hpriv);
+
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
+
+static void ahci_platform_put_resources(struct device *dev, void *res)
+{
+ struct ahci_host_priv *hpriv = res;
+ int c;
+
+ if (hpriv->got_runtime_pm) {
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+ }
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
+ clk_put(hpriv->clks[c]);
+}
+
+/**
+ * ahci_platform_get_resources - Get platform resources
+ * @pdev: platform device to get resources for
+ *
+ * This function allocates an ahci_host_priv struct, and gets the following
+ * resources, storing a reference to them inside the returned struct:
+ *
+ * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
+ * 2) regulator for controlling the targets power (optional)
+ * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
+ * or for non devicetree enabled platforms a single clock
+ * 4) phy (optional)
+ *
+ * RETURNS:
+ * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
+ */
+struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct clk *clk;
+ int i, rc = -ENOMEM;
+
+ if (!devres_open_group(dev, NULL, GFP_KERNEL))
+ return ERR_PTR(-ENOMEM);
+
+ hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
+ GFP_KERNEL);
+ if (!hpriv)
+ goto err_out;
+
+ devres_add(dev, hpriv);
+
+ hpriv->mmio = devm_ioremap_resource(dev,
+ platform_get_resource(pdev, IORESOURCE_MEM, 0));
+ if (IS_ERR(hpriv->mmio)) {
+ dev_err(dev, "no mmio space\n");
+ rc = PTR_ERR(hpriv->mmio);
+ goto err_out;
+ }
+
+ hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
+ if (IS_ERR(hpriv->target_pwr)) {
+ rc = PTR_ERR(hpriv->target_pwr);
+ if (rc == -EPROBE_DEFER)
+ goto err_out;
+ hpriv->target_pwr = NULL;
+ }
+
+ for (i = 0; i < AHCI_MAX_CLKS; i++) {
+ /*
+ * For now we must use clk_get(dev, NULL) for the first clock,
+ * because some platforms (da850, spear13xx) are not yet
+ * converted to use devicetree for clocks. For new platforms
+ * this is equivalent to of_clk_get(dev->of_node, 0).
+ */
+ if (i == 0)
+ clk = clk_get(dev, NULL);
+ else
+ clk = of_clk_get(dev->of_node, i);
+
+ if (IS_ERR(clk)) {
+ rc = PTR_ERR(clk);
+ if (rc == -EPROBE_DEFER)
+ goto err_out;
+ break;
+ }
+ hpriv->clks[i] = clk;
+ }
+
+ hpriv->phy = devm_phy_get(dev, "sata-phy");
+ if (IS_ERR(hpriv->phy)) {
+ rc = PTR_ERR(hpriv->phy);
+ switch (rc) {
+ case -ENODEV:
+ case -ENOSYS:
+ /* continue normally */
+ hpriv->phy = NULL;
+ break;
+
+ case -EPROBE_DEFER:
+ goto err_out;
+
+ default:
+ dev_err(dev, "couldn't get sata-phy\n");
+ goto err_out;
+ }
+ }
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+ hpriv->got_runtime_pm = true;
+
+ devres_remove_group(dev, NULL);
+ return hpriv;
+
+err_out:
+ devres_release_group(dev, NULL);
+ return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
+
+/**
+ * ahci_platform_init_host - Bring up an ahci-platform host
+ * @pdev: platform device pointer for the host
+ * @hpriv: ahci-host private data for the host
+ * @pi_template: template for the ata_port_info to use
+ * @force_port_map: param passed to ahci_save_initial_config
+ * @mask_port_map: param passed to ahci_save_initial_config
+ *
+ * This function does all the usual steps needed to bring up an
+ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
+ * must be initialized / enabled before calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_init_host(struct platform_device *pdev,
+ struct ahci_host_priv *hpriv,
+ const struct ata_port_info *pi_template,
+ unsigned int force_port_map,
+ unsigned int mask_port_map)
+{
+ struct device *dev = &pdev->dev;
+ struct ata_port_info pi = *pi_template;
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+ struct ata_host *host;
+ int i, irq, n_ports, rc;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(dev, "no irq\n");
+ return -EINVAL;
+ }
+
+ /* prepare host */
+ hpriv->flags |= (unsigned long)pi.private_data;
+
+ ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map);
+
+ if (hpriv->cap & HOST_CAP_NCQ)
+ pi.flags |= ATA_FLAG_NCQ;
+
+ if (hpriv->cap & HOST_CAP_PMP)
+ pi.flags |= ATA_FLAG_PMP;
+
+ ahci_set_em_messages(hpriv, &pi);
+
+ /* CAP.NP sometimes indicate the index of the last enabled
+ * port, at other times, that of the last possible port, so
+ * determining the maximum port number requires looking at
+ * both CAP.NP and port_map.
+ */
+ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+ host = ata_host_alloc_pinfo(dev, ppi, n_ports);
+ if (!host)
+ return -ENOMEM;
+
+ host->private_data = hpriv;
+
+ if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+ else
+ dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
+
+ if (pi.flags & ATA_FLAG_EM)
+ ahci_reset_em(host);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ ata_port_desc(ap, "mmio %pR",
+ platform_get_resource(pdev, IORESOURCE_MEM, 0));
+ ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
+
+ /* set enclosure management message type */
+ if (ap->flags & ATA_FLAG_EM)
+ ap->em_message_type = hpriv->em_msg_type;
+
+ /* disabled/not-implemented port */
+ if (!(hpriv->port_map & (1 << i)))
+ ap->ops = &ata_dummy_port_ops;
+ }
+
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(host);
+ ahci_print_info(host, "platform");
+
+ return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
+ &ahci_platform_sht);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_init_host);
+
+static void ahci_host_stop(struct ata_host *host)
+{
+ struct device *dev = host->dev;
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+
+ if (pdata && pdata->exit)
+ pdata->exit(dev);
+
+ ahci_platform_disable_resources(hpriv);
+}
+
+#ifdef CONFIG_PM_SLEEP
+/**
+ * ahci_platform_suspend_host - Suspend an ahci-platform host
+ * @dev: device pointer for the host
+ *
+ * This function does all the usual steps needed to suspend an
+ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
+ * must be disabled after calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_suspend_host(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ u32 ctl;
+
+ if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
+ dev_err(dev, "firmware update required for suspend/resume\n");
+ return -EIO;
+ }
+
+ /*
+ * AHCI spec rev1.1 section 8.3.3:
+ * Software must disable interrupts prior to requesting a
+ * transition of the HBA to D3 state.
+ */
+ ctl = readl(mmio + HOST_CTL);
+ ctl &= ~HOST_IRQ_EN;
+ writel(ctl, mmio + HOST_CTL);
+ readl(mmio + HOST_CTL); /* flush */
+
+ return ata_host_suspend(host, PMSG_SUSPEND);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
+
+/**
+ * ahci_platform_resume_host - Resume an ahci-platform host
+ * @dev: device pointer for the host
+ *
+ * This function does all the usual steps needed to resume an ahci-platform
+ * host, note any necessary resources (ie clks, phy, etc.) must be
+ * initialized / enabled before calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_resume_host(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ int rc;
+
+ if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(host);
+ }
+
+ ata_host_resume(host);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
+
+/**
+ * ahci_platform_suspend - Suspend an ahci-platform device
+ * @dev: the platform device to suspend
+ *
+ * This function suspends the host associated with the device, followed by
+ * disabling all the resources of the device.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_suspend(struct device *dev)
+{
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
+ rc = ahci_platform_suspend_host(dev);
+ if (rc)
+ return rc;
+
+ if (pdata && pdata->suspend) {
+ rc = pdata->suspend(dev);
+ if (rc)
+ goto resume_host;
+ }
+
+ ahci_platform_disable_resources(hpriv);
+
+ return 0;
+
+resume_host:
+ ahci_platform_resume_host(dev);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_suspend);
+
+/**
+ * ahci_platform_resume - Resume an ahci-platform device
+ * @dev: the platform device to resume
+ *
+ * This function enables all the resources of the device followed by
+ * resuming the host associated with the device.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_resume(struct device *dev)
+{
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ if (pdata && pdata->resume) {
+ rc = pdata->resume(dev);
+ if (rc)
+ goto disable_resources;
+ }
+
+ rc = ahci_platform_resume_host(dev);
+ if (rc)
+ goto disable_resources;
+
+ /* We resumed so update PM runtime state */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_resume);
+#endif
+
+MODULE_DESCRIPTION("AHCI SATA platform library");
+MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 9e69a5308693..97a14fe47de1 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -38,6 +38,16 @@ static void ata_acpi_clear_gtf(struct ata_device *dev)
dev->gtf_cache = NULL;
}
+struct ata_acpi_hotplug_context {
+ struct acpi_hotplug_context hp;
+ union {
+ struct ata_port *ap;
+ struct ata_device *dev;
+ } data;
+};
+
+#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data)
+
/**
* ata_dev_acpi_handle - provide the acpi_handle for an ata_device
* @dev: the acpi_handle returned will correspond to this device
@@ -121,18 +131,17 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
ata_port_wait_eh(ap);
}
-static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
+static int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event)
{
- struct ata_device *dev = data;
-
+ struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
ata_acpi_handle_hotplug(dev->link->ap, dev, event);
+ return 0;
}
-static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
+static int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event)
{
- struct ata_port *ap = data;
-
- ata_acpi_handle_hotplug(ap, NULL, event);
+ ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event);
+ return 0;
}
static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
@@ -154,31 +163,23 @@ static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
}
}
-static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event)
{
- ata_acpi_uevent(data, NULL, event);
+ ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event);
}
-static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event)
{
- struct ata_device *dev = data;
+ struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
ata_acpi_uevent(dev->link->ap, dev, event);
}
-static const struct acpi_dock_ops ata_acpi_dev_dock_ops = {
- .handler = ata_acpi_dev_notify_dock,
- .uevent = ata_acpi_dev_uevent,
-};
-
-static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
- .handler = ata_acpi_ap_notify_dock,
- .uevent = ata_acpi_ap_uevent,
-};
-
/* bind acpi handle to pata port */
void ata_acpi_bind_port(struct ata_port *ap)
{
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
+ struct acpi_device *adev;
+ struct ata_acpi_hotplug_context *context;
if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion)
return;
@@ -188,9 +189,17 @@ void ata_acpi_bind_port(struct ata_port *ap)
if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
- /* we might be on a docking station */
- register_hotplug_dock_device(ACPI_HANDLE(&ap->tdev),
- &ata_acpi_ap_dock_ops, ap, NULL, NULL);
+ adev = ACPI_COMPANION(&ap->tdev);
+ if (!adev || adev->hp)
+ return;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return;
+
+ context->data.ap = ap;
+ acpi_initialize_hp_context(adev, &context->hp, ata_acpi_ap_notify_dock,
+ ata_acpi_ap_uevent);
}
void ata_acpi_bind_dev(struct ata_device *dev)
@@ -198,7 +207,8 @@ void ata_acpi_bind_dev(struct ata_device *dev)
struct ata_port *ap = dev->link->ap;
struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev);
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
- struct acpi_device *parent;
+ struct acpi_device *parent, *adev;
+ struct ata_acpi_hotplug_context *context;
u64 adr;
/*
@@ -221,9 +231,17 @@ void ata_acpi_bind_dev(struct ata_device *dev)
}
acpi_preset_companion(&dev->tdev, parent, adr);
+ adev = ACPI_COMPANION(&dev->tdev);
+ if (!adev || adev->hp)
+ return;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return;
- register_hotplug_dock_device(ata_dev_acpi_handle(dev),
- &ata_acpi_dev_dock_ops, dev, NULL, NULL);
+ context->data.dev = dev;
+ acpi_initialize_hp_context(adev, &context->hp, ata_acpi_dev_notify_dock,
+ ata_acpi_dev_uevent);
}
/**
@@ -835,6 +853,7 @@ void ata_acpi_on_resume(struct ata_port *ap)
ata_for_each_dev(dev, &ap->link, ALL) {
ata_acpi_clear_gtf(dev);
if (ata_dev_enabled(dev) &&
+ ata_dev_acpi_handle(dev) &&
ata_dev_get_GTF(dev, NULL) >= 0)
dev->flags |= ATA_DFLAG_ACPI_PENDING;
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index a440958d34e4..c19734d96d7e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4175,6 +4175,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Seagate Momentus SpinPoint M8 seem to have FPMDA_AA issues */
{ "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA },
+ { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA },
/* Blacklist entries taken from Silicon Image 3124/3132
Windows driver .inf file - also several Linux problem reports */
@@ -4224,7 +4225,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* devices that don't properly handle queued TRIM commands */
{ "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, },
- { "Crucial_CT???M500SSD1", NULL, ATA_HORKAGE_NO_NCQ_TRIM, },
+ { "Crucial_CT???M500SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, },
/*
* Some WD SATA-I drives spin up and down erratically when the link
@@ -5351,22 +5352,17 @@ bool ata_link_offline(struct ata_link *link)
}
#ifdef CONFIG_PM
-static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
- unsigned int action, unsigned int ehi_flags,
- int *async)
+static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
+ unsigned int action, unsigned int ehi_flags,
+ bool async)
{
struct ata_link *link;
unsigned long flags;
- int rc = 0;
/* Previous resume operation might still be in
* progress. Wait for PM_PENDING to clear.
*/
if (ap->pflags & ATA_PFLAG_PM_PENDING) {
- if (async) {
- *async = -EAGAIN;
- return 0;
- }
ata_port_wait_eh(ap);
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
}
@@ -5375,11 +5371,6 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
spin_lock_irqsave(ap->lock, flags);
ap->pm_mesg = mesg;
- if (async)
- ap->pm_result = async;
- else
- ap->pm_result = &rc;
-
ap->pflags |= ATA_PFLAG_PM_PENDING;
ata_for_each_link(link, ap, HOST_FIRST) {
link->eh_info.action |= action;
@@ -5390,87 +5381,81 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
spin_unlock_irqrestore(ap->lock, flags);
- /* wait and check result */
if (!async) {
ata_port_wait_eh(ap);
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
}
-
- return rc;
}
-static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async)
+/*
+ * On some hardware, device fails to respond after spun down for suspend. As
+ * the device won't be used before being resumed, we don't need to touch the
+ * device. Ask EH to skip the usual stuff and proceed directly to suspend.
+ *
+ * http://thread.gmane.org/gmane.linux.ide/46764
+ */
+static const unsigned int ata_port_suspend_ehi = ATA_EHI_QUIET
+ | ATA_EHI_NO_AUTOPSY
+ | ATA_EHI_NO_RECOVERY;
+
+static void ata_port_suspend(struct ata_port *ap, pm_message_t mesg)
{
- /*
- * On some hardware, device fails to respond after spun down
- * for suspend. As the device won't be used before being
- * resumed, we don't need to touch the device. Ask EH to skip
- * the usual stuff and proceed directly to suspend.
- *
- * http://thread.gmane.org/gmane.linux.ide/46764
- */
- unsigned int ehi_flags = ATA_EHI_QUIET | ATA_EHI_NO_AUTOPSY |
- ATA_EHI_NO_RECOVERY;
- return ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
+ ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, false);
}
-static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
+static void ata_port_suspend_async(struct ata_port *ap, pm_message_t mesg)
{
- struct ata_port *ap = to_ata_port(dev);
-
- return __ata_port_suspend_common(ap, mesg, NULL);
+ ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, true);
}
-static int ata_port_suspend(struct device *dev)
+static int ata_port_pm_suspend(struct device *dev)
{
+ struct ata_port *ap = to_ata_port(dev);
+
if (pm_runtime_suspended(dev))
return 0;
- return ata_port_suspend_common(dev, PMSG_SUSPEND);
+ ata_port_suspend(ap, PMSG_SUSPEND);
+ return 0;
}
-static int ata_port_do_freeze(struct device *dev)
+static int ata_port_pm_freeze(struct device *dev)
{
+ struct ata_port *ap = to_ata_port(dev);
+
if (pm_runtime_suspended(dev))
return 0;
- return ata_port_suspend_common(dev, PMSG_FREEZE);
+ ata_port_suspend(ap, PMSG_FREEZE);
+ return 0;
}
-static int ata_port_poweroff(struct device *dev)
+static int ata_port_pm_poweroff(struct device *dev)
{
- return ata_port_suspend_common(dev, PMSG_HIBERNATE);
+ ata_port_suspend(to_ata_port(dev), PMSG_HIBERNATE);
+ return 0;
}
-static int __ata_port_resume_common(struct ata_port *ap, pm_message_t mesg,
- int *async)
-{
- int rc;
+static const unsigned int ata_port_resume_ehi = ATA_EHI_NO_AUTOPSY
+ | ATA_EHI_QUIET;
- rc = ata_port_request_pm(ap, mesg, ATA_EH_RESET,
- ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
- return rc;
+static void ata_port_resume(struct ata_port *ap, pm_message_t mesg)
+{
+ ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, false);
}
-static int ata_port_resume_common(struct device *dev, pm_message_t mesg)
+static void ata_port_resume_async(struct ata_port *ap, pm_message_t mesg)
{
- struct ata_port *ap = to_ata_port(dev);
-
- return __ata_port_resume_common(ap, mesg, NULL);
+ ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, true);
}
-static int ata_port_resume(struct device *dev)
+static int ata_port_pm_resume(struct device *dev)
{
- int rc;
-
- rc = ata_port_resume_common(dev, PMSG_RESUME);
- if (!rc) {
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
- }
-
- return rc;
+ ata_port_resume_async(to_ata_port(dev), PMSG_RESUME);
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ return 0;
}
/*
@@ -5499,21 +5484,23 @@ static int ata_port_runtime_idle(struct device *dev)
static int ata_port_runtime_suspend(struct device *dev)
{
- return ata_port_suspend_common(dev, PMSG_AUTO_SUSPEND);
+ ata_port_suspend(to_ata_port(dev), PMSG_AUTO_SUSPEND);
+ return 0;
}
static int ata_port_runtime_resume(struct device *dev)
{
- return ata_port_resume_common(dev, PMSG_AUTO_RESUME);
+ ata_port_resume(to_ata_port(dev), PMSG_AUTO_RESUME);
+ return 0;
}
static const struct dev_pm_ops ata_port_pm_ops = {
- .suspend = ata_port_suspend,
- .resume = ata_port_resume,
- .freeze = ata_port_do_freeze,
- .thaw = ata_port_resume,
- .poweroff = ata_port_poweroff,
- .restore = ata_port_resume,
+ .suspend = ata_port_pm_suspend,
+ .resume = ata_port_pm_resume,
+ .freeze = ata_port_pm_freeze,
+ .thaw = ata_port_pm_resume,
+ .poweroff = ata_port_pm_poweroff,
+ .restore = ata_port_pm_resume,
.runtime_suspend = ata_port_runtime_suspend,
.runtime_resume = ata_port_runtime_resume,
@@ -5525,18 +5512,17 @@ static const struct dev_pm_ops ata_port_pm_ops = {
* level. sas suspend/resume is async to allow parallel port recovery
* since sas has multiple ata_port instances per Scsi_Host.
*/
-int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
+void ata_sas_port_suspend(struct ata_port *ap)
{
- return __ata_port_suspend_common(ap, PMSG_SUSPEND, async);
+ ata_port_suspend_async(ap, PMSG_SUSPEND);
}
-EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend);
+EXPORT_SYMBOL_GPL(ata_sas_port_suspend);
-int ata_sas_port_async_resume(struct ata_port *ap, int *async)
+void ata_sas_port_resume(struct ata_port *ap)
{
- return __ata_port_resume_common(ap, PMSG_RESUME, async);
+ ata_port_resume_async(ap, PMSG_RESUME);
}
-EXPORT_SYMBOL_GPL(ata_sas_port_async_resume);
-
+EXPORT_SYMBOL_GPL(ata_sas_port_resume);
/**
* ata_host_suspend - suspend host
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 6d8757008318..6760fc4e85b8 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -95,12 +95,13 @@ enum {
* represents timeout for that try. The first try can be soft or
* hardreset. All others are hardreset if available. In most cases
* the first reset w/ 10sec timeout should succeed. Following entries
- * are mostly for error handling, hotplug and retarded devices.
+ * are mostly for error handling, hotplug and those outlier devices that
+ * take an exceptionally long time to recover from reset.
*/
static const unsigned long ata_eh_reset_timeouts[] = {
10000, /* most drives spin up by 10sec */
10000, /* > 99% working drives spin up before 20sec */
- 35000, /* give > 30 secs of idleness for retarded devices */
+ 35000, /* give > 30 secs of idleness for outlier devices */
5000, /* and sweet one last chance */
ULONG_MAX, /* > 1 min has elapsed, give up */
};
@@ -4069,7 +4070,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
ata_acpi_set_state(ap, ap->pm_mesg);
out:
- /* report result */
+ /* update the flags */
spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~ATA_PFLAG_PM_PENDING;
@@ -4078,11 +4079,6 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
else if (ap->pflags & ATA_PFLAG_FROZEN)
ata_port_schedule_eh(ap);
- if (ap->pm_result) {
- *ap->pm_result = rc;
- ap->pm_result = NULL;
- }
-
spin_unlock_irqrestore(ap->lock, flags);
return;
@@ -4134,13 +4130,9 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
/* tell ACPI that we're resuming */
ata_acpi_on_resume(ap);
- /* report result */
+ /* update the flags */
spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
- if (ap->pm_result) {
- *ap->pm_result = rc;
- ap->pm_result = NULL;
- }
spin_unlock_irqrestore(ap->lock, flags);
}
#endif /* CONFIG_PM */
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
index 20fd337a5731..7ccc084bf1df 100644
--- a/drivers/ata/libata-pmp.c
+++ b/drivers/ata/libata-pmp.c
@@ -447,8 +447,11 @@ static void sata_pmp_quirks(struct ata_port *ap)
* otherwise. Don't try hard to recover it.
*/
ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
- } else if (vendor == 0x197b && devid == 0x2352) {
- /* chip found in Thermaltake BlackX Duet, jmicron JMB350? */
+ } else if (vendor == 0x197b && (devid == 0x2352 || devid == 0x0325)) {
+ /*
+ * 0x2352: found in Thermaltake BlackX Duet, jmicron JMB350?
+ * 0x0325: jmicron JMB394.
+ */
ata_for_each_link(link, ap, EDGE) {
/* SRST breaks detection and disks get misclassified
* LPM disabled to avoid potential problems
diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c
index 88949c6d55dd..f3a65a3140d3 100644
--- a/drivers/ata/libata-zpodd.c
+++ b/drivers/ata/libata-zpodd.c
@@ -85,21 +85,6 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
return ODD_MECH_TYPE_UNSUPPORTED;
}
-static bool odd_can_poweroff(struct ata_device *ata_dev)
-{
- acpi_handle handle;
- struct acpi_device *acpi_dev;
-
- handle = ata_dev_acpi_handle(ata_dev);
- if (!handle)
- return false;
-
- if (acpi_bus_get_device(handle, &acpi_dev))
- return false;
-
- return acpi_device_can_poweroff(acpi_dev);
-}
-
/* Test if ODD is zero power ready by sense code */
static bool zpready(struct ata_device *dev)
{
@@ -267,13 +252,11 @@ static void ata_acpi_remove_pm_notifier(struct ata_device *dev)
void zpodd_init(struct ata_device *dev)
{
+ struct acpi_device *adev = ACPI_COMPANION(&dev->tdev);
enum odd_mech_type mech_type;
struct zpodd *zpodd;
- if (dev->zpodd)
- return;
-
- if (!odd_can_poweroff(dev))
+ if (dev->zpodd || !adev || !acpi_device_can_poweroff(adev))
return;
mech_type = zpodd_get_mech_type(dev);
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
index 62c9ac80c6e9..5108b8744dce 100644
--- a/drivers/ata/pata_acpi.c
+++ b/drivers/ata/pata_acpi.c
@@ -7,7 +7,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index d23e2b3ca0b6..1206fa6b62ca 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
index 73492dd4a4bc..6fac524c2f50 100644
--- a/drivers/ata/pata_arasan_cf.c
+++ b/drivers/ata/pata_arasan_cf.c
@@ -356,7 +356,7 @@ static void cf_exit(struct arasan_cf_dev *acdev)
static void dma_callback(void *dev)
{
- struct arasan_cf_dev *acdev = (struct arasan_cf_dev *) dev;
+ struct arasan_cf_dev *acdev = dev;
complete(&acdev->dma_completion);
}
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index 1581dee2967a..3aa4e655e3c6 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c
index d63ee8f41a4f..e9c87274a781 100644
--- a/drivers/ata/pata_at91.c
+++ b/drivers/ata/pata_at91.c
@@ -18,7 +18,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/gfp.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 24e51056ac26..30fa4ca4cef6 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_atp867x.c b/drivers/ata/pata_atp867x.c
index 2ca5026f2c15..7e73a0f1e323 100644
--- a/drivers/ata/pata_atp867x.c
+++ b/drivers/ata/pata_atp867x.c
@@ -29,7 +29,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c
index 8fb69e5ca1b7..57f1be64dbf2 100644
--- a/drivers/ata/pata_cmd640.c
+++ b/drivers/ata/pata_cmd640.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/gfp.h>
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index 1275a8d4dedc..6bca3505b9e9 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index f10baabbf5db..bcde4b786807 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -34,7 +34,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index f07f2296acdc..8afe854a5a50 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 997e16a3a63f..2c0986fa4bb2 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c
index 0448860a2077..32ddcae5a360 100644
--- a/drivers/ata/pata_cs5536.c
+++ b/drivers/ata/pata_cs5536.c
@@ -33,7 +33,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/libata.h>
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index 810bc9964dde..3435bd6a5cc9 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index 3c12fd7acd41..f440892225f4 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
index 980b88e109fc..cad9d45749c4 100644
--- a/drivers/ata/pata_ep93xx.c
+++ b/drivers/ata/pata_ep93xx.c
@@ -34,7 +34,6 @@
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <scsi/scsi_host.h>
#include <linux/ata.h>
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 35b521348d31..8e76f79689d3 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index a9d74eff5fc4..3ba843f5cdc0 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index 4be0398c153d..b93c0f0729e7 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index 85cf2861e0b7..255c5aaff3a8 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c
index 26386f0b89a8..e0872db913d6 100644
--- a/drivers/ata/pata_imx.c
+++ b/drivers/ata/pata_imx.c
@@ -15,7 +15,6 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <scsi/scsi_host.h>
#include <linux/ata.h>
@@ -100,13 +99,9 @@ static int pata_imx_probe(struct platform_device *pdev)
struct resource *io_res;
int ret;
- io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (io_res == NULL)
- return -EINVAL;
-
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return -EINVAL;
+ if (irq < 0)
+ return irq;
priv = devm_kzalloc(&pdev->dev,
sizeof(struct pata_imx_priv), GFP_KERNEL);
@@ -119,7 +114,9 @@ static int pata_imx_probe(struct platform_device *pdev)
return PTR_ERR(priv->clk);
}
- clk_prepare_enable(priv->clk);
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
host = ata_host_alloc(&pdev->dev, 1);
if (!host) {
@@ -134,11 +131,10 @@ static int pata_imx_probe(struct platform_device *pdev)
ap->pio_mask = ATA_PIO0;
ap->flags |= ATA_FLAG_SLAVE_POSS;
- priv->host_regs = devm_ioremap(&pdev->dev, io_res->start,
- resource_size(io_res));
- if (!priv->host_regs) {
- dev_err(&pdev->dev, "failed to map IO/CTL base\n");
- ret = -EBUSY;
+ io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->host_regs = devm_ioremap_resource(&pdev->dev, io_res);
+ if (IS_ERR(priv->host_regs)) {
+ ret = PTR_ERR(priv->host_regs);
goto err;
}
@@ -212,7 +208,9 @@ static int pata_imx_resume(struct device *dev)
struct ata_host *host = dev_get_drvdata(dev);
struct pata_imx_priv *priv = host->private_data;
- clk_prepare_enable(priv->clk);
+ int ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
__raw_writel(priv->ata_ctl, priv->host_regs + PATA_IMX_ATA_CONTROL);
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
index 2a8dd9527ecc..81369d187a5c 100644
--- a/drivers/ata/pata_it8213.c
+++ b/drivers/ata/pata_it8213.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 581e04d80367..dc3d7877f29d 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -72,7 +72,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/slab.h>
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 76e739b031b6..b1cfa0258fd3 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index be816428b430..bce2a8ca4678 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -916,7 +916,6 @@ static __init int probe_chip_type(struct legacy_probe *probe)
local_irq_restore(flags);
return BIOS;
}
- local_irq_restore(flags);
}
if (ht6560a & mask)
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index a4f5e781c8c2..6bad3df3a13c 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 1f5f28bb0bb8..f39a5379e816 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -28,7 +28,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index ad1a0febd620..e3b97093ef9a 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -7,7 +7,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c
index 9513e071040d..56201a69af12 100644
--- a/drivers/ata/pata_ninja32.c
+++ b/drivers/ata/pata_ninja32.c
@@ -37,7 +37,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 0c424dae56e7..6154c3ee11a5 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c
index 16dc3a63a23d..d44df7ccfe43 100644
--- a/drivers/ata/pata_ns87415.c
+++ b/drivers/ata/pata_ns87415.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index d77b2e1054ef..319b64491b7b 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index 4ea70cd22aee..fb042e0519d0 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index 78ede3fd1875..bb71ea214b99 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 40254f4df584..bcc4b968c049 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/slab.h>
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 9d874c85d64d..1151f23177bb 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index c34fc50070a6..defa050e1784 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_piccolo.c b/drivers/ata/pata_piccolo.c
index 2beb6b5045f8..0b46be117051 100644
--- a/drivers/ata/pata_piccolo.c
+++ b/drivers/ata/pata_piccolo.c
@@ -18,7 +18,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 02794885de10..a5579b55e332 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -13,7 +13,6 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <scsi/scsi_host.h>
#include <linux/ata.h>
diff --git a/drivers/ata/pata_pxa.c b/drivers/ata/pata_pxa.c
index a6f05acad61e..73259bfda1e3 100644
--- a/drivers/ata/pata_pxa.c
+++ b/drivers/ata/pata_pxa.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/ata.h>
#include <linux/libata.h>
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index f582ba180a7d..be3f10240dca 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_rdc.c b/drivers/ata/pata_rdc.c
index 79a970f05a2e..521b2137ea3e 100644
--- a/drivers/ata/pata_rdc.c
+++ b/drivers/ata/pata_rdc.c
@@ -24,7 +24,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index 040b093617a4..caedc90855b2 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index ce2f828c17b3..96a232fffae6 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -32,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index f35f15f4d83e..f1f5b5ae3382 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -35,7 +35,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_sch.c b/drivers/ata/pata_sch.c
index d3830c45a369..5a1cde0ea360 100644
--- a/drivers/ata/pata_sch.c
+++ b/drivers/ata/pata_sch.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index 96c6a79ef606..e27f31fe1b67 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -34,7 +34,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index c4b0b073ba8e..73fe362d9716 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 1e8363640bf5..78d913aa93c8 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index 6816911ac422..900f0e4a1faf 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index 94473da68c02..7bc78e264f9e 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -36,7 +36,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index c3ab9a6c3965..f6c9632bdff6 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -55,7 +55,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/gfp.h>
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 8ea6e6afd041..f10631beffa8 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -36,7 +36,6 @@
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c
index 523524b68022..0bb2cabd2197 100644
--- a/drivers/ata/sata_dwc_460ex.c
+++ b/drivers/ata/sata_dwc_460ex.c
@@ -29,7 +29,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -462,8 +461,7 @@ static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance)
int chan;
u32 tfr_reg, err_reg;
unsigned long flags;
- struct sata_dwc_device *hsdev =
- (struct sata_dwc_device *)hsdev_instance;
+ struct sata_dwc_device *hsdev = hsdev_instance;
struct ata_host *host = (struct ata_host *)hsdev->host;
struct ata_port *ap;
struct sata_dwc_device_port *hsdevp;
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index 870b11eadc6d..65965cf5af06 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/types.h>
#include <linux/err.h>
#include <linux/io.h>
@@ -142,7 +141,7 @@ static ssize_t ecx_transmit_led_message(struct ata_port *ap, u32 state,
ssize_t size)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
- struct ecx_plat_data *pdata = (struct ecx_plat_data *) hpriv->plat_data;
+ struct ecx_plat_data *pdata = hpriv->plat_data;
struct ahci_port_priv *pp = ap->private_data;
unsigned long flags;
int pmp, i;
@@ -403,6 +402,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
static const unsigned long timing[] = { 5, 100, 500};
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
@@ -431,7 +431,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
break;
} while (!online && retry--);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
if (online)
*class = ahci_dev_classify(ap);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 52b8181ddafd..05c8a44adf8e 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -4104,7 +4104,6 @@ static int mv_platform_probe(struct platform_device *pdev)
if (!hpriv->port_phys)
return -ENOMEM;
host->private_data = hpriv;
- hpriv->n_ports = n_ports;
hpriv->board_idx = chip_soc;
host->iomap = NULL;
@@ -4132,13 +4131,18 @@ static int mv_platform_probe(struct platform_device *pdev)
rc = PTR_ERR(hpriv->port_phys[port]);
hpriv->port_phys[port] = NULL;
if (rc != -EPROBE_DEFER)
- dev_warn(&pdev->dev, "error getting phy %d",
- rc);
+ dev_warn(&pdev->dev, "error getting phy %d", rc);
+
+ /* Cleanup only the initialized ports */
+ hpriv->n_ports = port;
goto err;
} else
phy_power_on(hpriv->port_phys[port]);
}
+ /* All the ports have been initialized */
+ hpriv->n_ports = n_ports;
+
/*
* (Re-)program MBUS remapping windows if we are asked to.
*/
@@ -4176,7 +4180,7 @@ err:
clk_disable_unprepare(hpriv->clk);
clk_put(hpriv->clk);
}
- for (port = 0; port < n_ports; port++) {
+ for (port = 0; port < hpriv->n_ports; port++) {
if (!IS_ERR(hpriv->port_clks[port])) {
clk_disable_unprepare(hpriv->port_clks[port]);
clk_put(hpriv->port_clks[port]);
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index d74def823d3e..ba5f27120332 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -40,7 +40,6 @@
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 97f4acb54ad6..3638887476f6 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -35,7 +35,6 @@
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 3b0dd57984e1..9a6bd4cd29a0 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -31,7 +31,6 @@
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index d67fc351343c..3062f8605b29 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -37,7 +37,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -157,6 +156,7 @@ static const struct sil_drivelist {
{ "ST380011ASL", SIL_QUIRK_MOD15WRITE },
{ "ST3120022ASL", SIL_QUIRK_MOD15WRITE },
{ "ST3160021ASL", SIL_QUIRK_MOD15WRITE },
+ { "TOSHIBA MK2561GSYN", SIL_QUIRK_MOD15WRITE },
{ "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX },
{ }
};
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 1ad2f62d34b9..b513428171b3 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -33,7 +33,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index dc4f70179e7d..c630fa812624 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -39,7 +39,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 9947010afc0f..39b5de60a1f9 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -82,7 +82,6 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -1021,8 +1020,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
idx++;
dist = ((long) (window_size - (offset + size))) >= 0 ? size :
(long) (window_size - offset);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
- dist);
+ memcpy_fromio(psource, dimm_mmio + offset / 4, dist);
psource += dist;
size -= dist;
@@ -1031,8 +1029,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
readl(mmio + PDC_GENERAL_CTLR);
writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio),
- window_size / 4);
+ memcpy_fromio(psource, dimm_mmio, window_size / 4);
psource += window_size;
size -= window_size;
idx++;
@@ -1043,8 +1040,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
readl(mmio + PDC_GENERAL_CTLR);
writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio),
- size / 4);
+ memcpy_fromio(psource, dimm_mmio, size / 4);
}
}
#endif
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index 6d6489118873..08f98c3ed5c8 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -28,7 +28,6 @@
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 87f056e54a9d..f72e84228c5c 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -36,7 +36,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 44f304b3de63..29e847aac34b 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -37,7 +37,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index ec36e7772e57..8fa8deab6449 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -185,6 +185,9 @@ config GENERIC_CPU_DEVICES
bool
default n
+config GENERIC_CPU_AUTOPROBE
+ bool
+
config SOC_BUS
bool
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c
index ecc1929d7f6a..b84ca8f13f9e 100644
--- a/drivers/base/attribute_container.c
+++ b/drivers/base/attribute_container.c
@@ -12,7 +12,6 @@
*/
#include <linux/attribute_container.h>
-#include <linux/init.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
diff --git a/drivers/base/core.c b/drivers/base/core.c
index b5d1b8479ab6..0dd65281cc65 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -23,7 +23,6 @@
#include <linux/genhd.h>
#include <linux/kallsyms.h>
#include <linux/mutex.h>
-#include <linux/async.h>
#include <linux/pm_runtime.h>
#include <linux/netdevice.h>
#include <linux/sysfs.h>
@@ -571,6 +570,23 @@ void device_remove_file(struct device *dev,
EXPORT_SYMBOL_GPL(device_remove_file);
/**
+ * device_remove_file_self - remove sysfs attribute file from its own method.
+ * @dev: device.
+ * @attr: device attribute descriptor.
+ *
+ * See kernfs_remove_self() for details.
+ */
+bool device_remove_file_self(struct device *dev,
+ const struct device_attribute *attr)
+{
+ if (dev)
+ return sysfs_remove_file_self(&dev->kobj, &attr->attr);
+ else
+ return false;
+}
+EXPORT_SYMBOL_GPL(device_remove_file_self);
+
+/**
* device_create_bin_file - create sysfs binary attribute file for device.
* @dev: device.
* @attr: device binary attribute descriptor.
@@ -2003,7 +2019,6 @@ void device_shutdown(void)
spin_lock(&devices_kset->list_lock);
}
spin_unlock(&devices_kset->list_lock);
- async_synchronize_full();
}
/*
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index f48370dfc908..006b1bc5297d 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -15,6 +15,7 @@
#include <linux/percpu.h>
#include <linux/acpi.h>
#include <linux/of.h>
+#include <linux/cpufeature.h>
#include "base.h"
@@ -286,6 +287,41 @@ static void cpu_device_release(struct device *dev)
*/
}
+#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
+static ssize_t print_cpu_modalias(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ ssize_t n;
+ u32 i;
+
+ n = sprintf(buf, "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:",
+ CPU_FEATURE_TYPEVAL);
+
+ for (i = 0; i < MAX_CPU_FEATURES; i++)
+ if (cpu_have_feature(i)) {
+ if (PAGE_SIZE < n + sizeof(",XXXX\n")) {
+ WARN(1, "CPU features overflow page\n");
+ break;
+ }
+ n += sprintf(&buf[n], ",%04X", i);
+ }
+ buf[n++] = '\n';
+ return n;
+}
+
+static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (buf) {
+ print_cpu_modalias(NULL, NULL, buf);
+ add_uevent_var(env, "MODALIAS=%s", buf);
+ kfree(buf);
+ }
+ return 0;
+}
+#endif
+
/*
* register_cpu - Setup a sysfs device for a CPU.
* @cpu - cpu->hotpluggable field set to 1 will generate a control file in
@@ -306,8 +342,8 @@ int register_cpu(struct cpu *cpu, int num)
cpu->dev.offline_disabled = !cpu->hotpluggable;
cpu->dev.offline = !cpu_online(num);
cpu->dev.of_node = of_get_cpu_node(num, NULL);
-#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
- cpu->dev.bus->uevent = arch_cpu_uevent;
+#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
+ cpu->dev.bus->uevent = cpu_uevent;
#endif
cpu->dev.groups = common_cpu_attr_groups;
if (cpu->hotpluggable)
@@ -330,8 +366,8 @@ struct device *get_cpu_device(unsigned cpu)
}
EXPORT_SYMBOL_GPL(get_cpu_device);
-#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
-static DEVICE_ATTR(modalias, 0444, arch_print_cpu_modalias, NULL);
+#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
+static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL);
#endif
static struct attribute *cpu_root_attrs[] = {
@@ -344,7 +380,7 @@ static struct attribute *cpu_root_attrs[] = {
&cpu_attrs[2].attr.attr,
&dev_attr_kernel_max.attr,
&dev_attr_offline.attr,
-#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
+#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
&dev_attr_modalias.attr,
#endif
NULL
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 545c4de412c3..db4e264eecb6 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -791,6 +791,32 @@ void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
EXPORT_SYMBOL_GPL(devm_kmalloc);
/**
+ * devm_kstrdup - Allocate resource managed space and
+ * copy an existing string into that.
+ * @dev: Device to allocate memory for
+ * @s: the string to duplicate
+ * @gfp: the GFP mask used in the devm_kmalloc() call when
+ * allocating memory
+ * RETURNS:
+ * Pointer to allocated string on success, NULL on failure.
+ */
+char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
+{
+ size_t size;
+ char *buf;
+
+ if (!s)
+ return NULL;
+
+ size = strlen(s) + 1;
+ buf = devm_kmalloc(dev, size, gfp);
+ if (buf)
+ memcpy(buf, s, size);
+ return buf;
+}
+EXPORT_SYMBOL_GPL(devm_kstrdup);
+
+/**
* devm_kfree - Resource-managed kfree
* @dev: Device this memory belongs to
* @p: Memory to free
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 1e16cbd61da2..ea77701deda4 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -251,9 +251,8 @@ EXPORT_SYMBOL_GPL(dma_buf_put);
* @dmabuf: [in] buffer to attach device to.
* @dev: [in] device to be attached.
*
- * Returns struct dma_buf_attachment * for this attachment; may return negative
- * error codes.
- *
+ * Returns struct dma_buf_attachment * for this attachment; returns ERR_PTR on
+ * error.
*/
struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
struct device *dev)
@@ -319,9 +318,8 @@ EXPORT_SYMBOL_GPL(dma_buf_detach);
* @attach: [in] attachment whose scatterlist is to be returned
* @direction: [in] direction of DMA transfer
*
- * Returns sg_table containing the scatterlist to be returned; may return NULL
- * or ERR_PTR.
- *
+ * Returns sg_table containing the scatterlist to be returned; returns ERR_PTR
+ * on error.
*/
struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
enum dma_data_direction direction)
@@ -334,6 +332,8 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
return ERR_PTR(-EINVAL);
sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
+ if (!sg_table)
+ sg_table = ERR_PTR(-ENOMEM);
return sg_table;
}
@@ -544,6 +544,8 @@ EXPORT_SYMBOL_GPL(dma_buf_mmap);
* These calls are optional in drivers. The intended use for them
* is for mapping objects linear in kernel space for high use objects.
* Please attempt to use kmap/kunmap before thinking about these interfaces.
+ *
+ * Returns NULL on error.
*/
void *dma_buf_vmap(struct dma_buf *dmabuf)
{
@@ -566,7 +568,9 @@ void *dma_buf_vmap(struct dma_buf *dmabuf)
BUG_ON(dmabuf->vmap_ptr);
ptr = dmabuf->ops->vmap(dmabuf);
- if (IS_ERR_OR_NULL(ptr))
+ if (WARN_ON_ONCE(IS_ERR(ptr)))
+ ptr = NULL;
+ if (!ptr)
goto out_unlock;
dmabuf->vmap_ptr = ptr;
@@ -616,36 +620,35 @@ static int dma_buf_describe(struct seq_file *s)
if (ret)
return ret;
- seq_printf(s, "\nDma-buf Objects:\n");
- seq_printf(s, "\texp_name\tsize\tflags\tmode\tcount\n");
+ seq_puts(s, "\nDma-buf Objects:\n");
+ seq_puts(s, "size\tflags\tmode\tcount\texp_name\n");
list_for_each_entry(buf_obj, &db_list.head, list_node) {
ret = mutex_lock_interruptible(&buf_obj->lock);
if (ret) {
- seq_printf(s,
- "\tERROR locking buffer object: skipping\n");
+ seq_puts(s,
+ "\tERROR locking buffer object: skipping\n");
continue;
}
- seq_printf(s, "\t");
-
- seq_printf(s, "\t%s\t%08zu\t%08x\t%08x\t%08ld\n",
- buf_obj->exp_name, buf_obj->size,
+ seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\n",
+ buf_obj->size,
buf_obj->file->f_flags, buf_obj->file->f_mode,
- (long)(buf_obj->file->f_count.counter));
+ (long)(buf_obj->file->f_count.counter),
+ buf_obj->exp_name);
- seq_printf(s, "\t\tAttached Devices:\n");
+ seq_puts(s, "\tAttached Devices:\n");
attach_count = 0;
list_for_each_entry(attach_obj, &buf_obj->attachments, node) {
- seq_printf(s, "\t\t");
+ seq_puts(s, "\t");
- seq_printf(s, "%s\n", attach_obj->dev->init_name);
+ seq_printf(s, "%s\n", dev_name(attach_obj->dev));
attach_count++;
}
- seq_printf(s, "\n\t\tTotal %d devices attached\n",
+ seq_printf(s, "Total %d devices attached\n\n",
attach_count);
count++;
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 8a97ddfa6122..d276e33880be 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -649,7 +649,9 @@ static ssize_t firmware_loading_store(struct device *dev,
* see the mapped 'buf->data' once the loading
* is completed.
* */
- fw_map_pages_buf(fw_buf);
+ if (fw_map_pages_buf(fw_buf))
+ dev_err(dev, "%s: map pages failed\n",
+ __func__);
list_del_init(&fw_buf->pending_list);
complete_all(&fw_buf->completion);
break;
@@ -900,7 +902,8 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
dev_set_uevent_suppress(f_dev, false);
dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id);
if (timeout != MAX_SCHEDULE_TIMEOUT)
- schedule_delayed_work(&fw_priv->timeout_work, timeout);
+ queue_delayed_work(system_power_efficient_wq,
+ &fw_priv->timeout_work, timeout);
kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
}
@@ -908,6 +911,8 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
wait_for_completion(&buf->completion);
cancel_delayed_work_sync(&fw_priv->timeout_work);
+ if (!buf->data)
+ retval = -ENOMEM;
device_remove_file(f_dev, &dev_attr_loading);
err_del_bin_attr:
@@ -1570,8 +1575,8 @@ static void device_uncache_fw_images_work(struct work_struct *work)
*/
static void device_uncache_fw_images_delay(unsigned long delay)
{
- schedule_delayed_work(&fw_cache.work,
- msecs_to_jiffies(delay));
+ queue_delayed_work(system_power_efficient_wq, &fw_cache.work,
+ msecs_to_jiffies(delay));
}
static int fw_pm_notify(struct notifier_block *notify_block,
@@ -1580,6 +1585,7 @@ static int fw_pm_notify(struct notifier_block *notify_block,
switch (mode) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
+ case PM_RESTORE_PREPARE:
kill_requests_without_uevent();
device_cache_fw_images();
break;
diff --git a/drivers/base/node.c b/drivers/base/node.c
index bc9f43bf7e29..8f7ed9933a7c 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -599,7 +599,11 @@ int register_one_node(int nid)
void unregister_one_node(int nid)
{
+ if (!node_devices[nid])
+ return;
+
unregister_node(node_devices[nid]);
+ kfree(node_devices[nid]);
node_devices[nid] = NULL;
}
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index bc78848dd59a..e714709704e4 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -481,11 +481,10 @@ static int platform_drv_probe(struct device *_dev)
struct platform_device *dev = to_platform_device(_dev);
int ret;
- if (ACPI_HANDLE(_dev))
- acpi_dev_pm_attach(_dev, true);
+ acpi_dev_pm_attach(_dev, true);
ret = drv->probe(dev);
- if (ret && ACPI_HANDLE(_dev))
+ if (ret)
acpi_dev_pm_detach(_dev, true);
if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
@@ -508,8 +507,7 @@ static int platform_drv_remove(struct device *_dev)
int ret;
ret = drv->remove(dev);
- if (ACPI_HANDLE(_dev))
- acpi_dev_pm_detach(_dev, true);
+ acpi_dev_pm_detach(_dev, true);
return ret;
}
@@ -520,8 +518,7 @@ static void platform_drv_shutdown(struct device *_dev)
struct platform_device *dev = to_platform_device(_dev);
drv->shutdown(dev);
- if (ACPI_HANDLE(_dev))
- acpi_dev_pm_detach(_dev, true);
+ acpi_dev_pm_detach(_dev, true);
}
/**
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 2e58ebb1f6c0..1cb8544598d5 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,6 +1,5 @@
-obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o
+obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o
obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
-obj-$(CONFIG_PM_RUNTIME) += runtime.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
obj-$(CONFIG_PM_OPP) += opp.o
obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index e870bbe9ec4e..b99e6c06ee67 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -6,7 +6,6 @@
* This file is released under the GPLv2.
*/
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/io.h>
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c
index 5da914041305..df2e5eeaeb05 100644
--- a/drivers/base/power/common.c
+++ b/drivers/base/power/common.c
@@ -6,7 +6,6 @@
* This file is released under the GPLv2.
*/
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/export.h>
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index bfb8955c406c..6f54962aae1d 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -6,7 +6,6 @@
* This file is released under the GPLv2.
*/
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
@@ -42,7 +41,7 @@
struct gpd_timing_data *__td = &dev_gpd_data(dev)->td; \
if (!__retval && __elapsed > __td->field) { \
__td->field = __elapsed; \
- dev_warn(dev, name " latency exceeded, new value %lld ns\n", \
+ dev_dbg(dev, name " latency exceeded, new value %lld ns\n", \
__elapsed); \
genpd->max_off_time_changed = true; \
__td->constraint_changed = true; \
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index 28dee3053f1f..a089e3bcdfbc 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -6,7 +6,6 @@
* This file is released under the GPLv2.
*/
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pm_domain.h>
#include <linux/pm_qos.h>
diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c
index a2e55bfdf572..96a92db83cad 100644
--- a/drivers/base/power/generic_ops.c
+++ b/drivers/base/power/generic_ops.c
@@ -285,7 +285,7 @@ int pm_generic_restore(struct device *dev)
EXPORT_SYMBOL_GPL(pm_generic_restore);
/**
- * pm_generic_complete - Generic routine competing a device power transition.
+ * pm_generic_complete - Generic routine completing a device power transition.
* @dev: Device to handle.
*
* Complete a device power transition during a system-wide power transition.
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 1b41fca3d65a..86d5e4fb5b98 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -29,6 +29,7 @@
#include <linux/async.h>
#include <linux/suspend.h>
#include <trace/events/power.h>
+#include <linux/cpufreq.h>
#include <linux/cpuidle.h>
#include <linux/timer.h>
@@ -91,6 +92,8 @@ void device_pm_sleep_init(struct device *dev)
{
dev->power.is_prepared = false;
dev->power.is_suspended = false;
+ dev->power.is_noirq_suspended = false;
+ dev->power.is_late_suspended = false;
init_completion(&dev->power.completion);
complete_all(&dev->power.completion);
dev->power.wakeup = NULL;
@@ -467,7 +470,7 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
* The driver of @dev will not receive interrupts while this function is being
* executed.
*/
-static int device_resume_noirq(struct device *dev, pm_message_t state)
+static int device_resume_noirq(struct device *dev, pm_message_t state, bool async)
{
pm_callback_t callback = NULL;
char *info = NULL;
@@ -479,6 +482,11 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
if (dev->power.syscore)
goto Out;
+ if (!dev->power.is_noirq_suspended)
+ goto Out;
+
+ dpm_wait(dev->parent, async);
+
if (dev->pm_domain) {
info = "noirq power domain ";
callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -499,12 +507,32 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
}
error = dpm_run_callback(callback, dev, state, info);
+ dev->power.is_noirq_suspended = false;
Out:
+ complete_all(&dev->power.completion);
TRACE_RESUME(error);
return error;
}
+static bool is_async(struct device *dev)
+{
+ return dev->power.async_suspend && pm_async_enabled
+ && !pm_trace_is_enabled();
+}
+
+static void async_resume_noirq(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+ int error;
+
+ error = device_resume_noirq(dev, pm_transition, true);
+ if (error)
+ pm_dev_err(dev, pm_transition, " async", error);
+
+ put_device(dev);
+}
+
/**
* dpm_resume_noirq - Execute "noirq resume" callbacks for all devices.
* @state: PM transition of the system being carried out.
@@ -514,29 +542,48 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
*/
static void dpm_resume_noirq(pm_message_t state)
{
+ struct device *dev;
ktime_t starttime = ktime_get();
mutex_lock(&dpm_list_mtx);
- while (!list_empty(&dpm_noirq_list)) {
- struct device *dev = to_device(dpm_noirq_list.next);
- int error;
+ pm_transition = state;
+ /*
+ * Advanced the async threads upfront,
+ * in case the starting of async threads is
+ * delayed by non-async resuming devices.
+ */
+ list_for_each_entry(dev, &dpm_noirq_list, power.entry) {
+ reinit_completion(&dev->power.completion);
+ if (is_async(dev)) {
+ get_device(dev);
+ async_schedule(async_resume_noirq, dev);
+ }
+ }
+
+ while (!list_empty(&dpm_noirq_list)) {
+ dev = to_device(dpm_noirq_list.next);
get_device(dev);
list_move_tail(&dev->power.entry, &dpm_late_early_list);
mutex_unlock(&dpm_list_mtx);
- error = device_resume_noirq(dev, state);
- if (error) {
- suspend_stats.failed_resume_noirq++;
- dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
- dpm_save_failed_dev(dev_name(dev));
- pm_dev_err(dev, state, " noirq", error);
+ if (!is_async(dev)) {
+ int error;
+
+ error = device_resume_noirq(dev, state, false);
+ if (error) {
+ suspend_stats.failed_resume_noirq++;
+ dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
+ dpm_save_failed_dev(dev_name(dev));
+ pm_dev_err(dev, state, " noirq", error);
+ }
}
mutex_lock(&dpm_list_mtx);
put_device(dev);
}
mutex_unlock(&dpm_list_mtx);
+ async_synchronize_full();
dpm_show_time(starttime, state, "noirq");
resume_device_irqs();
cpuidle_resume();
@@ -549,7 +596,7 @@ static void dpm_resume_noirq(pm_message_t state)
*
* Runtime PM is disabled for @dev while this function is being executed.
*/
-static int device_resume_early(struct device *dev, pm_message_t state)
+static int device_resume_early(struct device *dev, pm_message_t state, bool async)
{
pm_callback_t callback = NULL;
char *info = NULL;
@@ -561,6 +608,11 @@ static int device_resume_early(struct device *dev, pm_message_t state)
if (dev->power.syscore)
goto Out;
+ if (!dev->power.is_late_suspended)
+ goto Out;
+
+ dpm_wait(dev->parent, async);
+
if (dev->pm_domain) {
info = "early power domain ";
callback = pm_late_early_op(&dev->pm_domain->ops, state);
@@ -581,43 +633,75 @@ static int device_resume_early(struct device *dev, pm_message_t state)
}
error = dpm_run_callback(callback, dev, state, info);
+ dev->power.is_late_suspended = false;
Out:
TRACE_RESUME(error);
pm_runtime_enable(dev);
+ complete_all(&dev->power.completion);
return error;
}
+static void async_resume_early(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+ int error;
+
+ error = device_resume_early(dev, pm_transition, true);
+ if (error)
+ pm_dev_err(dev, pm_transition, " async", error);
+
+ put_device(dev);
+}
+
/**
* dpm_resume_early - Execute "early resume" callbacks for all devices.
* @state: PM transition of the system being carried out.
*/
static void dpm_resume_early(pm_message_t state)
{
+ struct device *dev;
ktime_t starttime = ktime_get();
mutex_lock(&dpm_list_mtx);
- while (!list_empty(&dpm_late_early_list)) {
- struct device *dev = to_device(dpm_late_early_list.next);
- int error;
+ pm_transition = state;
+ /*
+ * Advanced the async threads upfront,
+ * in case the starting of async threads is
+ * delayed by non-async resuming devices.
+ */
+ list_for_each_entry(dev, &dpm_late_early_list, power.entry) {
+ reinit_completion(&dev->power.completion);
+ if (is_async(dev)) {
+ get_device(dev);
+ async_schedule(async_resume_early, dev);
+ }
+ }
+
+ while (!list_empty(&dpm_late_early_list)) {
+ dev = to_device(dpm_late_early_list.next);
get_device(dev);
list_move_tail(&dev->power.entry, &dpm_suspended_list);
mutex_unlock(&dpm_list_mtx);
- error = device_resume_early(dev, state);
- if (error) {
- suspend_stats.failed_resume_early++;
- dpm_save_failed_step(SUSPEND_RESUME_EARLY);
- dpm_save_failed_dev(dev_name(dev));
- pm_dev_err(dev, state, " early", error);
- }
+ if (!is_async(dev)) {
+ int error;
+ error = device_resume_early(dev, state, false);
+ if (error) {
+ suspend_stats.failed_resume_early++;
+ dpm_save_failed_step(SUSPEND_RESUME_EARLY);
+ dpm_save_failed_dev(dev_name(dev));
+ pm_dev_err(dev, state, " early", error);
+ }
+ }
mutex_lock(&dpm_list_mtx);
put_device(dev);
}
mutex_unlock(&dpm_list_mtx);
+ async_synchronize_full();
dpm_show_time(starttime, state, "early");
}
@@ -732,12 +816,6 @@ static void async_resume(void *data, async_cookie_t cookie)
put_device(dev);
}
-static bool is_async(struct device *dev)
-{
- return dev->power.async_suspend && pm_async_enabled
- && !pm_trace_is_enabled();
-}
-
/**
* dpm_resume - Execute "resume" callbacks for non-sysdev devices.
* @state: PM transition of the system being carried out.
@@ -789,6 +867,8 @@ void dpm_resume(pm_message_t state)
mutex_unlock(&dpm_list_mtx);
async_synchronize_full();
dpm_show_time(starttime, state, NULL);
+
+ cpufreq_resume();
}
/**
@@ -913,13 +993,24 @@ static pm_message_t resume_event(pm_message_t sleep_state)
* The driver of @dev will not receive interrupts while this function is being
* executed.
*/
-static int device_suspend_noirq(struct device *dev, pm_message_t state)
+static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async)
{
pm_callback_t callback = NULL;
char *info = NULL;
+ int error = 0;
+
+ if (async_error)
+ goto Complete;
+
+ if (pm_wakeup_pending()) {
+ async_error = -EBUSY;
+ goto Complete;
+ }
if (dev->power.syscore)
- return 0;
+ goto Complete;
+
+ dpm_wait_for_children(dev, async);
if (dev->pm_domain) {
info = "noirq power domain ";
@@ -940,7 +1031,41 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
callback = pm_noirq_op(dev->driver->pm, state);
}
- return dpm_run_callback(callback, dev, state, info);
+ error = dpm_run_callback(callback, dev, state, info);
+ if (!error)
+ dev->power.is_noirq_suspended = true;
+ else
+ async_error = error;
+
+Complete:
+ complete_all(&dev->power.completion);
+ return error;
+}
+
+static void async_suspend_noirq(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+ int error;
+
+ error = __device_suspend_noirq(dev, pm_transition, true);
+ if (error) {
+ dpm_save_failed_dev(dev_name(dev));
+ pm_dev_err(dev, pm_transition, " async", error);
+ }
+
+ put_device(dev);
+}
+
+static int device_suspend_noirq(struct device *dev)
+{
+ reinit_completion(&dev->power.completion);
+
+ if (pm_async_enabled && dev->power.async_suspend) {
+ get_device(dev);
+ async_schedule(async_suspend_noirq, dev);
+ return 0;
+ }
+ return __device_suspend_noirq(dev, pm_transition, false);
}
/**
@@ -958,19 +1083,20 @@ static int dpm_suspend_noirq(pm_message_t state)
cpuidle_pause();
suspend_device_irqs();
mutex_lock(&dpm_list_mtx);
+ pm_transition = state;
+ async_error = 0;
+
while (!list_empty(&dpm_late_early_list)) {
struct device *dev = to_device(dpm_late_early_list.prev);
get_device(dev);
mutex_unlock(&dpm_list_mtx);
- error = device_suspend_noirq(dev, state);
+ error = device_suspend_noirq(dev);
mutex_lock(&dpm_list_mtx);
if (error) {
pm_dev_err(dev, state, " noirq", error);
- suspend_stats.failed_suspend_noirq++;
- dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
dpm_save_failed_dev(dev_name(dev));
put_device(dev);
break;
@@ -979,16 +1105,21 @@ static int dpm_suspend_noirq(pm_message_t state)
list_move(&dev->power.entry, &dpm_noirq_list);
put_device(dev);
- if (pm_wakeup_pending()) {
- error = -EBUSY;
+ if (async_error)
break;
- }
}
mutex_unlock(&dpm_list_mtx);
- if (error)
+ async_synchronize_full();
+ if (!error)
+ error = async_error;
+
+ if (error) {
+ suspend_stats.failed_suspend_noirq++;
+ dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
dpm_resume_noirq(resume_event(state));
- else
+ } else {
dpm_show_time(starttime, state, "noirq");
+ }
return error;
}
@@ -999,15 +1130,26 @@ static int dpm_suspend_noirq(pm_message_t state)
*
* Runtime PM is disabled for @dev while this function is being executed.
*/
-static int device_suspend_late(struct device *dev, pm_message_t state)
+static int __device_suspend_late(struct device *dev, pm_message_t state, bool async)
{
pm_callback_t callback = NULL;
char *info = NULL;
+ int error = 0;
__pm_runtime_disable(dev, false);
+ if (async_error)
+ goto Complete;
+
+ if (pm_wakeup_pending()) {
+ async_error = -EBUSY;
+ goto Complete;
+ }
+
if (dev->power.syscore)
- return 0;
+ goto Complete;
+
+ dpm_wait_for_children(dev, async);
if (dev->pm_domain) {
info = "late power domain ";
@@ -1028,7 +1170,41 @@ static int device_suspend_late(struct device *dev, pm_message_t state)
callback = pm_late_early_op(dev->driver->pm, state);
}
- return dpm_run_callback(callback, dev, state, info);
+ error = dpm_run_callback(callback, dev, state, info);
+ if (!error)
+ dev->power.is_late_suspended = true;
+ else
+ async_error = error;
+
+Complete:
+ complete_all(&dev->power.completion);
+ return error;
+}
+
+static void async_suspend_late(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+ int error;
+
+ error = __device_suspend_late(dev, pm_transition, true);
+ if (error) {
+ dpm_save_failed_dev(dev_name(dev));
+ pm_dev_err(dev, pm_transition, " async", error);
+ }
+ put_device(dev);
+}
+
+static int device_suspend_late(struct device *dev)
+{
+ reinit_completion(&dev->power.completion);
+
+ if (pm_async_enabled && dev->power.async_suspend) {
+ get_device(dev);
+ async_schedule(async_suspend_late, dev);
+ return 0;
+ }
+
+ return __device_suspend_late(dev, pm_transition, false);
}
/**
@@ -1041,19 +1217,20 @@ static int dpm_suspend_late(pm_message_t state)
int error = 0;
mutex_lock(&dpm_list_mtx);
+ pm_transition = state;
+ async_error = 0;
+
while (!list_empty(&dpm_suspended_list)) {
struct device *dev = to_device(dpm_suspended_list.prev);
get_device(dev);
mutex_unlock(&dpm_list_mtx);
- error = device_suspend_late(dev, state);
+ error = device_suspend_late(dev);
mutex_lock(&dpm_list_mtx);
if (error) {
pm_dev_err(dev, state, " late", error);
- suspend_stats.failed_suspend_late++;
- dpm_save_failed_step(SUSPEND_SUSPEND_LATE);
dpm_save_failed_dev(dev_name(dev));
put_device(dev);
break;
@@ -1062,17 +1239,18 @@ static int dpm_suspend_late(pm_message_t state)
list_move(&dev->power.entry, &dpm_late_early_list);
put_device(dev);
- if (pm_wakeup_pending()) {
- error = -EBUSY;
+ if (async_error)
break;
- }
}
mutex_unlock(&dpm_list_mtx);
- if (error)
+ async_synchronize_full();
+ if (error) {
+ suspend_stats.failed_suspend_late++;
+ dpm_save_failed_step(SUSPEND_SUSPEND_LATE);
dpm_resume_early(resume_event(state));
- else
+ } else {
dpm_show_time(starttime, state, "late");
-
+ }
return error;
}
@@ -1259,6 +1437,8 @@ int dpm_suspend(pm_message_t state)
might_sleep();
+ cpufreq_suspend();
+
mutex_lock(&dpm_list_mtx);
pm_transition = state;
async_error = 0;
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index fa4187418440..25538675d59e 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/cpufreq.h>
#include <linux/device.h>
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index cfc3226ec492..a21223d95926 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -89,8 +89,8 @@ extern void dpm_sysfs_remove(struct device *dev);
extern void rpm_sysfs_remove(struct device *dev);
extern int wakeup_sysfs_add(struct device *dev);
extern void wakeup_sysfs_remove(struct device *dev);
-extern int pm_qos_sysfs_add_latency(struct device *dev);
-extern void pm_qos_sysfs_remove_latency(struct device *dev);
+extern int pm_qos_sysfs_add_resume_latency(struct device *dev);
+extern void pm_qos_sysfs_remove_resume_latency(struct device *dev);
extern int pm_qos_sysfs_add_flags(struct device *dev);
extern void pm_qos_sysfs_remove_flags(struct device *dev);
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 5c1361a9e5dd..36b9eb4862cb 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -105,7 +105,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
s32 __dev_pm_qos_read_value(struct device *dev)
{
return IS_ERR_OR_NULL(dev->power.qos) ?
- 0 : pm_qos_read_value(&dev->power.qos->latency);
+ 0 : pm_qos_read_value(&dev->power.qos->resume_latency);
}
/**
@@ -141,16 +141,24 @@ static int apply_constraint(struct dev_pm_qos_request *req,
int ret;
switch(req->type) {
- case DEV_PM_QOS_LATENCY:
- ret = pm_qos_update_target(&qos->latency, &req->data.pnode,
- action, value);
+ case DEV_PM_QOS_RESUME_LATENCY:
+ ret = pm_qos_update_target(&qos->resume_latency,
+ &req->data.pnode, action, value);
if (ret) {
- value = pm_qos_read_value(&qos->latency);
+ value = pm_qos_read_value(&qos->resume_latency);
blocking_notifier_call_chain(&dev_pm_notifiers,
(unsigned long)value,
req);
}
break;
+ case DEV_PM_QOS_LATENCY_TOLERANCE:
+ ret = pm_qos_update_target(&qos->latency_tolerance,
+ &req->data.pnode, action, value);
+ if (ret) {
+ value = pm_qos_read_value(&qos->latency_tolerance);
+ req->dev->power.set_latency_tolerance(req->dev, value);
+ }
+ break;
case DEV_PM_QOS_FLAGS:
ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
action, value);
@@ -186,13 +194,21 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
}
BLOCKING_INIT_NOTIFIER_HEAD(n);
- c = &qos->latency;
+ c = &qos->resume_latency;
plist_head_init(&c->list);
- c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
- c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
+ c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
+ c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
+ c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
c->type = PM_QOS_MIN;
c->notifiers = n;
+ c = &qos->latency_tolerance;
+ plist_head_init(&c->list);
+ c->target_value = PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE;
+ c->default_value = PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE;
+ c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
+ c->type = PM_QOS_MIN;
+
INIT_LIST_HEAD(&qos->flags.list);
spin_lock_irq(&dev->power.lock);
@@ -224,7 +240,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
* If the device's PM QoS resume latency limit or PM QoS flags have been
* exposed to user space, they have to be hidden at this point.
*/
- pm_qos_sysfs_remove_latency(dev);
+ pm_qos_sysfs_remove_resume_latency(dev);
pm_qos_sysfs_remove_flags(dev);
mutex_lock(&dev_pm_qos_mtx);
@@ -237,7 +253,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
goto out;
/* Flush the constraints lists for the device. */
- c = &qos->latency;
+ c = &qos->resume_latency;
plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
/*
* Update constraints list and call the notification
@@ -246,6 +262,11 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
memset(req, 0, sizeof(*req));
}
+ c = &qos->latency_tolerance;
+ plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
+ apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
+ memset(req, 0, sizeof(*req));
+ }
f = &qos->flags;
list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
@@ -265,6 +286,40 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
mutex_unlock(&dev_pm_qos_sysfs_mtx);
}
+static bool dev_pm_qos_invalid_request(struct device *dev,
+ struct dev_pm_qos_request *req)
+{
+ return !req || (req->type == DEV_PM_QOS_LATENCY_TOLERANCE
+ && !dev->power.set_latency_tolerance);
+}
+
+static int __dev_pm_qos_add_request(struct device *dev,
+ struct dev_pm_qos_request *req,
+ enum dev_pm_qos_req_type type, s32 value)
+{
+ int ret = 0;
+
+ if (!dev || dev_pm_qos_invalid_request(dev, req))
+ return -EINVAL;
+
+ if (WARN(dev_pm_qos_request_active(req),
+ "%s() called for already added request\n", __func__))
+ return -EINVAL;
+
+ if (IS_ERR(dev->power.qos))
+ ret = -ENODEV;
+ else if (!dev->power.qos)
+ ret = dev_pm_qos_constraints_allocate(dev);
+
+ trace_dev_pm_qos_add_request(dev_name(dev), type, value);
+ if (!ret) {
+ req->dev = dev;
+ req->type = type;
+ ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
+ }
+ return ret;
+}
+
/**
* dev_pm_qos_add_request - inserts new qos request into the list
* @dev: target device for the constraint
@@ -290,31 +345,11 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
enum dev_pm_qos_req_type type, s32 value)
{
- int ret = 0;
-
- if (!dev || !req) /*guard against callers passing in null */
- return -EINVAL;
-
- if (WARN(dev_pm_qos_request_active(req),
- "%s() called for already added request\n", __func__))
- return -EINVAL;
+ int ret;
mutex_lock(&dev_pm_qos_mtx);
-
- if (IS_ERR(dev->power.qos))
- ret = -ENODEV;
- else if (!dev->power.qos)
- ret = dev_pm_qos_constraints_allocate(dev);
-
- trace_dev_pm_qos_add_request(dev_name(dev), type, value);
- if (!ret) {
- req->dev = dev;
- req->type = type;
- ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
- }
-
+ ret = __dev_pm_qos_add_request(dev, req, type, value);
mutex_unlock(&dev_pm_qos_mtx);
-
return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
@@ -341,7 +376,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
return -ENODEV;
switch(req->type) {
- case DEV_PM_QOS_LATENCY:
+ case DEV_PM_QOS_RESUME_LATENCY:
+ case DEV_PM_QOS_LATENCY_TOLERANCE:
curr_value = req->data.pnode.prio;
break;
case DEV_PM_QOS_FLAGS:
@@ -460,8 +496,8 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
ret = dev_pm_qos_constraints_allocate(dev);
if (!ret)
- ret = blocking_notifier_chain_register(
- dev->power.qos->latency.notifiers, notifier);
+ ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
+ notifier);
mutex_unlock(&dev_pm_qos_mtx);
return ret;
@@ -487,9 +523,8 @@ int dev_pm_qos_remove_notifier(struct device *dev,
/* Silently return if the constraints object is not present. */
if (!IS_ERR_OR_NULL(dev->power.qos))
- retval = blocking_notifier_chain_unregister(
- dev->power.qos->latency.notifiers,
- notifier);
+ retval = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
+ notifier);
mutex_unlock(&dev_pm_qos_mtx);
return retval;
@@ -530,20 +565,32 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);
* dev_pm_qos_add_ancestor_request - Add PM QoS request for device's ancestor.
* @dev: Device whose ancestor to add the request for.
* @req: Pointer to the preallocated handle.
+ * @type: Type of the request.
* @value: Constraint latency value.
*/
int dev_pm_qos_add_ancestor_request(struct device *dev,
- struct dev_pm_qos_request *req, s32 value)
+ struct dev_pm_qos_request *req,
+ enum dev_pm_qos_req_type type, s32 value)
{
struct device *ancestor = dev->parent;
int ret = -ENODEV;
- while (ancestor && !ancestor->power.ignore_children)
- ancestor = ancestor->parent;
+ switch (type) {
+ case DEV_PM_QOS_RESUME_LATENCY:
+ while (ancestor && !ancestor->power.ignore_children)
+ ancestor = ancestor->parent;
+ break;
+ case DEV_PM_QOS_LATENCY_TOLERANCE:
+ while (ancestor && !ancestor->power.set_latency_tolerance)
+ ancestor = ancestor->parent;
+
+ break;
+ default:
+ ancestor = NULL;
+ }
if (ancestor)
- ret = dev_pm_qos_add_request(ancestor, req,
- DEV_PM_QOS_LATENCY, value);
+ ret = dev_pm_qos_add_request(ancestor, req, type, value);
if (ret < 0)
req->dev = NULL;
@@ -559,9 +606,13 @@ static void __dev_pm_qos_drop_user_request(struct device *dev,
struct dev_pm_qos_request *req = NULL;
switch(type) {
- case DEV_PM_QOS_LATENCY:
- req = dev->power.qos->latency_req;
- dev->power.qos->latency_req = NULL;
+ case DEV_PM_QOS_RESUME_LATENCY:
+ req = dev->power.qos->resume_latency_req;
+ dev->power.qos->resume_latency_req = NULL;
+ break;
+ case DEV_PM_QOS_LATENCY_TOLERANCE:
+ req = dev->power.qos->latency_tolerance_req;
+ dev->power.qos->latency_tolerance_req = NULL;
break;
case DEV_PM_QOS_FLAGS:
req = dev->power.qos->flags_req;
@@ -597,7 +648,7 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
if (!req)
return -ENOMEM;
- ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY, value);
+ ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_RESUME_LATENCY, value);
if (ret < 0) {
kfree(req);
return ret;
@@ -609,7 +660,7 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
if (IS_ERR_OR_NULL(dev->power.qos))
ret = -ENODEV;
- else if (dev->power.qos->latency_req)
+ else if (dev->power.qos->resume_latency_req)
ret = -EEXIST;
if (ret < 0) {
@@ -618,13 +669,13 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
mutex_unlock(&dev_pm_qos_mtx);
goto out;
}
- dev->power.qos->latency_req = req;
+ dev->power.qos->resume_latency_req = req;
mutex_unlock(&dev_pm_qos_mtx);
- ret = pm_qos_sysfs_add_latency(dev);
+ ret = pm_qos_sysfs_add_resume_latency(dev);
if (ret)
- dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
+ dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_RESUME_LATENCY);
out:
mutex_unlock(&dev_pm_qos_sysfs_mtx);
@@ -634,8 +685,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
static void __dev_pm_qos_hide_latency_limit(struct device *dev)
{
- if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req)
- __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
+ if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->resume_latency_req)
+ __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_RESUME_LATENCY);
}
/**
@@ -646,7 +697,7 @@ void dev_pm_qos_hide_latency_limit(struct device *dev)
{
mutex_lock(&dev_pm_qos_sysfs_mtx);
- pm_qos_sysfs_remove_latency(dev);
+ pm_qos_sysfs_remove_resume_latency(dev);
mutex_lock(&dev_pm_qos_mtx);
__dev_pm_qos_hide_latency_limit(dev);
@@ -768,6 +819,67 @@ int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set)
pm_runtime_put(dev);
return ret;
}
+
+/**
+ * dev_pm_qos_get_user_latency_tolerance - Get user space latency tolerance.
+ * @dev: Device to obtain the user space latency tolerance for.
+ */
+s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev)
+{
+ s32 ret;
+
+ mutex_lock(&dev_pm_qos_mtx);
+ ret = IS_ERR_OR_NULL(dev->power.qos)
+ || !dev->power.qos->latency_tolerance_req ?
+ PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT :
+ dev->power.qos->latency_tolerance_req->data.pnode.prio;
+ mutex_unlock(&dev_pm_qos_mtx);
+ return ret;
+}
+
+/**
+ * dev_pm_qos_update_user_latency_tolerance - Update user space latency tolerance.
+ * @dev: Device to update the user space latency tolerance for.
+ * @val: New user space latency tolerance for @dev (negative values disable).
+ */
+int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val)
+{
+ int ret;
+
+ mutex_lock(&dev_pm_qos_mtx);
+
+ if (IS_ERR_OR_NULL(dev->power.qos)
+ || !dev->power.qos->latency_tolerance_req) {
+ struct dev_pm_qos_request *req;
+
+ if (val < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = __dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY_TOLERANCE, val);
+ if (ret < 0) {
+ kfree(req);
+ goto out;
+ }
+ dev->power.qos->latency_tolerance_req = req;
+ } else {
+ if (val < 0) {
+ __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY_TOLERANCE);
+ ret = 0;
+ } else {
+ ret = __dev_pm_qos_update_request(dev->power.qos->latency_tolerance_req, val);
+ }
+ }
+
+ out:
+ mutex_unlock(&dev_pm_qos_mtx);
+ return ret;
+}
#else /* !CONFIG_PM_RUNTIME */
static void __dev_pm_qos_hide_latency_limit(struct device *dev) {}
static void __dev_pm_qos_hide_flags(struct device *dev) {}
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 72e00e66ecc5..67c7938e430b 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -13,6 +13,43 @@
#include <trace/events/rpm.h>
#include "power.h"
+#define RPM_GET_CALLBACK(dev, cb) \
+({ \
+ int (*__rpm_cb)(struct device *__d); \
+ \
+ if (dev->pm_domain) \
+ __rpm_cb = dev->pm_domain->ops.cb; \
+ else if (dev->type && dev->type->pm) \
+ __rpm_cb = dev->type->pm->cb; \
+ else if (dev->class && dev->class->pm) \
+ __rpm_cb = dev->class->pm->cb; \
+ else if (dev->bus && dev->bus->pm) \
+ __rpm_cb = dev->bus->pm->cb; \
+ else \
+ __rpm_cb = NULL; \
+ \
+ if (!__rpm_cb && dev->driver && dev->driver->pm) \
+ __rpm_cb = dev->driver->pm->cb; \
+ \
+ __rpm_cb; \
+})
+
+static int (*rpm_get_suspend_cb(struct device *dev))(struct device *)
+{
+ return RPM_GET_CALLBACK(dev, runtime_suspend);
+}
+
+static int (*rpm_get_resume_cb(struct device *dev))(struct device *)
+{
+ return RPM_GET_CALLBACK(dev, runtime_resume);
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int (*rpm_get_idle_cb(struct device *dev))(struct device *)
+{
+ return RPM_GET_CALLBACK(dev, runtime_idle);
+}
+
static int rpm_resume(struct device *dev, int rpmflags);
static int rpm_suspend(struct device *dev, int rpmflags);
@@ -310,19 +347,7 @@ static int rpm_idle(struct device *dev, int rpmflags)
dev->power.idle_notification = true;
- if (dev->pm_domain)
- callback = dev->pm_domain->ops.runtime_idle;
- else if (dev->type && dev->type->pm)
- callback = dev->type->pm->runtime_idle;
- else if (dev->class && dev->class->pm)
- callback = dev->class->pm->runtime_idle;
- else if (dev->bus && dev->bus->pm)
- callback = dev->bus->pm->runtime_idle;
- else
- callback = NULL;
-
- if (!callback && dev->driver && dev->driver->pm)
- callback = dev->driver->pm->runtime_idle;
+ callback = rpm_get_idle_cb(dev);
if (callback)
retval = __rpm_callback(callback, dev);
@@ -492,19 +517,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
__update_runtime_status(dev, RPM_SUSPENDING);
- if (dev->pm_domain)
- callback = dev->pm_domain->ops.runtime_suspend;
- else if (dev->type && dev->type->pm)
- callback = dev->type->pm->runtime_suspend;
- else if (dev->class && dev->class->pm)
- callback = dev->class->pm->runtime_suspend;
- else if (dev->bus && dev->bus->pm)
- callback = dev->bus->pm->runtime_suspend;
- else
- callback = NULL;
-
- if (!callback && dev->driver && dev->driver->pm)
- callback = dev->driver->pm->runtime_suspend;
+ callback = rpm_get_suspend_cb(dev);
retval = rpm_callback(callback, dev);
if (retval)
@@ -724,19 +737,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
__update_runtime_status(dev, RPM_RESUMING);
- if (dev->pm_domain)
- callback = dev->pm_domain->ops.runtime_resume;
- else if (dev->type && dev->type->pm)
- callback = dev->type->pm->runtime_resume;
- else if (dev->class && dev->class->pm)
- callback = dev->class->pm->runtime_resume;
- else if (dev->bus && dev->bus->pm)
- callback = dev->bus->pm->runtime_resume;
- else
- callback = NULL;
-
- if (!callback && dev->driver && dev->driver->pm)
- callback = dev->driver->pm->runtime_resume;
+ callback = rpm_get_resume_cb(dev);
retval = rpm_callback(callback, dev);
if (retval) {
@@ -1130,7 +1131,7 @@ EXPORT_SYMBOL_GPL(pm_runtime_barrier);
* @dev: Device to handle.
* @check_resume: If set, check if there's a resume request for the device.
*
- * Increment power.disable_depth for the device and if was zero previously,
+ * Increment power.disable_depth for the device and if it was zero previously,
* cancel all pending runtime PM requests for the device and wait for all
* operations in progress to complete. The device can be either active or
* suspended after its runtime PM has been disabled.
@@ -1401,3 +1402,86 @@ void pm_runtime_remove(struct device *dev)
if (dev->power.irq_safe && dev->parent)
pm_runtime_put(dev->parent);
}
+#endif
+
+/**
+ * pm_runtime_force_suspend - Force a device into suspend state if needed.
+ * @dev: Device to suspend.
+ *
+ * Disable runtime PM so we safely can check the device's runtime PM status and
+ * if it is active, invoke it's .runtime_suspend callback to bring it into
+ * suspend state. Keep runtime PM disabled to preserve the state unless we
+ * encounter errors.
+ *
+ * Typically this function may be invoked from a system suspend callback to make
+ * sure the device is put into low power state.
+ */
+int pm_runtime_force_suspend(struct device *dev)
+{
+ int (*callback)(struct device *);
+ int ret = 0;
+
+ pm_runtime_disable(dev);
+
+ /*
+ * Note that pm_runtime_status_suspended() returns false while
+ * !CONFIG_PM_RUNTIME, which means the device will be put into low
+ * power state.
+ */
+ if (pm_runtime_status_suspended(dev))
+ return 0;
+
+ callback = rpm_get_suspend_cb(dev);
+
+ if (!callback) {
+ ret = -ENOSYS;
+ goto err;
+ }
+
+ ret = callback(dev);
+ if (ret)
+ goto err;
+
+ pm_runtime_set_suspended(dev);
+ return 0;
+err:
+ pm_runtime_enable(dev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_force_suspend);
+
+/**
+ * pm_runtime_force_resume - Force a device into resume state.
+ * @dev: Device to resume.
+ *
+ * Prior invoking this function we expect the user to have brought the device
+ * into low power state by a call to pm_runtime_force_suspend(). Here we reverse
+ * those actions and brings the device into full power. We update the runtime PM
+ * status and re-enables runtime PM.
+ *
+ * Typically this function may be invoked from a system resume callback to make
+ * sure the device is put into full power state.
+ */
+int pm_runtime_force_resume(struct device *dev)
+{
+ int (*callback)(struct device *);
+ int ret = 0;
+
+ callback = rpm_get_resume_cb(dev);
+
+ if (!callback) {
+ ret = -ENOSYS;
+ goto out;
+ }
+
+ ret = callback(dev);
+ if (ret)
+ goto out;
+
+ pm_runtime_set_active(dev);
+ pm_runtime_mark_last_busy(dev);
+out:
+ pm_runtime_enable(dev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_force_resume);
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 03e089ade5ce..95b181d1ca6d 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -218,15 +218,16 @@ static ssize_t autosuspend_delay_ms_store(struct device *dev,
static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show,
autosuspend_delay_ms_store);
-static ssize_t pm_qos_latency_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t pm_qos_resume_latency_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- return sprintf(buf, "%d\n", dev_pm_qos_requested_latency(dev));
+ return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev));
}
-static ssize_t pm_qos_latency_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t n)
+static ssize_t pm_qos_resume_latency_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t n)
{
s32 value;
int ret;
@@ -237,12 +238,47 @@ static ssize_t pm_qos_latency_store(struct device *dev,
if (value < 0)
return -EINVAL;
- ret = dev_pm_qos_update_request(dev->power.qos->latency_req, value);
+ ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
+ value);
return ret < 0 ? ret : n;
}
static DEVICE_ATTR(pm_qos_resume_latency_us, 0644,
- pm_qos_latency_show, pm_qos_latency_store);
+ pm_qos_resume_latency_show, pm_qos_resume_latency_store);
+
+static ssize_t pm_qos_latency_tolerance_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ s32 value = dev_pm_qos_get_user_latency_tolerance(dev);
+
+ if (value < 0)
+ return sprintf(buf, "auto\n");
+ else if (value == PM_QOS_LATENCY_ANY)
+ return sprintf(buf, "any\n");
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t pm_qos_latency_tolerance_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ s32 value;
+ int ret;
+
+ if (kstrtos32(buf, 0, &value)) {
+ if (!strcmp(buf, "auto") || !strcmp(buf, "auto\n"))
+ value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
+ else if (!strcmp(buf, "any") || !strcmp(buf, "any\n"))
+ value = PM_QOS_LATENCY_ANY;
+ }
+ ret = dev_pm_qos_update_user_latency_tolerance(dev, value);
+ return ret < 0 ? ret : n;
+}
+
+static DEVICE_ATTR(pm_qos_latency_tolerance_us, 0644,
+ pm_qos_latency_tolerance_show, pm_qos_latency_tolerance_store);
static ssize_t pm_qos_no_power_off_show(struct device *dev,
struct device_attribute *attr,
@@ -618,15 +654,26 @@ static struct attribute_group pm_runtime_attr_group = {
.attrs = runtime_attrs,
};
-static struct attribute *pm_qos_latency_attrs[] = {
+static struct attribute *pm_qos_resume_latency_attrs[] = {
#ifdef CONFIG_PM_RUNTIME
&dev_attr_pm_qos_resume_latency_us.attr,
#endif /* CONFIG_PM_RUNTIME */
NULL,
};
-static struct attribute_group pm_qos_latency_attr_group = {
+static struct attribute_group pm_qos_resume_latency_attr_group = {
+ .name = power_group_name,
+ .attrs = pm_qos_resume_latency_attrs,
+};
+
+static struct attribute *pm_qos_latency_tolerance_attrs[] = {
+#ifdef CONFIG_PM_RUNTIME
+ &dev_attr_pm_qos_latency_tolerance_us.attr,
+#endif /* CONFIG_PM_RUNTIME */
+ NULL,
+};
+static struct attribute_group pm_qos_latency_tolerance_attr_group = {
.name = power_group_name,
- .attrs = pm_qos_latency_attrs,
+ .attrs = pm_qos_latency_tolerance_attrs,
};
static struct attribute *pm_qos_flags_attrs[] = {
@@ -654,18 +701,23 @@ int dpm_sysfs_add(struct device *dev)
if (rc)
goto err_out;
}
-
if (device_can_wakeup(dev)) {
rc = sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group);
- if (rc) {
- if (pm_runtime_callbacks_present(dev))
- sysfs_unmerge_group(&dev->kobj,
- &pm_runtime_attr_group);
- goto err_out;
- }
+ if (rc)
+ goto err_runtime;
+ }
+ if (dev->power.set_latency_tolerance) {
+ rc = sysfs_merge_group(&dev->kobj,
+ &pm_qos_latency_tolerance_attr_group);
+ if (rc)
+ goto err_wakeup;
}
return 0;
+ err_wakeup:
+ sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
+ err_runtime:
+ sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);
err_out:
sysfs_remove_group(&dev->kobj, &pm_attr_group);
return rc;
@@ -681,14 +733,14 @@ void wakeup_sysfs_remove(struct device *dev)
sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
}
-int pm_qos_sysfs_add_latency(struct device *dev)
+int pm_qos_sysfs_add_resume_latency(struct device *dev)
{
- return sysfs_merge_group(&dev->kobj, &pm_qos_latency_attr_group);
+ return sysfs_merge_group(&dev->kobj, &pm_qos_resume_latency_attr_group);
}
-void pm_qos_sysfs_remove_latency(struct device *dev)
+void pm_qos_sysfs_remove_resume_latency(struct device *dev)
{
- sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_attr_group);
+ sysfs_unmerge_group(&dev->kobj, &pm_qos_resume_latency_attr_group);
}
int pm_qos_sysfs_add_flags(struct device *dev)
@@ -708,6 +760,7 @@ void rpm_sysfs_remove(struct device *dev)
void dpm_sysfs_remove(struct device *dev)
{
+ sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_tolerance_attr_group);
dev_pm_qos_constraints_destroy(dev);
rpm_sysfs_remove(dev);
sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 33414b1de201..7d1326985bee 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -134,6 +134,8 @@ struct regmap {
/* if set, converts bulk rw to single rw */
bool use_single_rw;
+ /* if set, the device supports multi write mode */
+ bool can_multi_write;
struct rb_root range_tree;
void *selector_work_buf; /* Scratch buffer used for selector */
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index d4dd77134814..29b4128da0b0 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -249,11 +249,12 @@ static int regcache_default_sync(struct regmap *map, unsigned int min,
{
unsigned int reg;
- for (reg = min; reg <= max; reg++) {
+ for (reg = min; reg <= max; reg += map->reg_stride) {
unsigned int val;
int ret;
- if (regmap_volatile(map, reg))
+ if (regmap_volatile(map, reg) ||
+ !regmap_writeable(map, reg))
continue;
ret = regcache_read(map, reg, &val);
@@ -312,10 +313,6 @@ int regcache_sync(struct regmap *map)
/* Apply any patch first */
map->cache_bypass = 1;
for (i = 0; i < map->patch_regs; i++) {
- if (map->patch[i].reg % map->reg_stride) {
- ret = -EINVAL;
- goto out;
- }
ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
if (ret != 0) {
dev_err(map->dev, "Failed to write %x = %x: %d\n",
@@ -636,10 +633,10 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data,
if (*data == NULL)
return 0;
- count = cur - base;
+ count = (cur - base) / map->reg_stride;
dev_dbg(map->dev, "Writing %zu bytes for %d registers from 0x%x-0x%x\n",
- count * val_bytes, count, base, cur - 1);
+ count * val_bytes, count, base, cur - map->reg_stride);
map->cache_bypass = 1;
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index c5471cd6ebb7..45d812c0ea77 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -511,7 +511,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
debugfs_create_file("range", 0400, map->debugfs,
map, &regmap_reg_ranges_fops);
- if (map->max_register) {
+ if (map->max_register || regmap_readable(map, 0)) {
debugfs_create_file("registers", 0400, map->debugfs,
map, &regmap_map_fops);
debugfs_create_file("access", 0400, map->debugfs,
diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c
index fa6bf5279d28..ebd189529760 100644
--- a/drivers/base/regmap/regmap-i2c.c
+++ b/drivers/base/regmap/regmap-i2c.c
@@ -13,7 +13,6 @@
#include <linux/regmap.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/init.h>
static int regmap_i2c_write(void *context, const void *data, size_t count)
{
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 82692068d3cb..edf88f20cbce 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -368,8 +368,6 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
if (!d)
return -ENOMEM;
- *data = d;
-
d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
GFP_KERNEL);
if (!d->status_buf)
@@ -506,6 +504,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
goto err_domain;
}
+ *data = d;
+
return 0;
err_domain:
@@ -533,7 +533,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
return;
free_irq(irq, d);
- /* We should unmap the domain but... */
+ irq_domain_remove(d->domain);
kfree(d->wake_buf);
kfree(d->mask_buf_def);
kfree(d->mask_buf);
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index 81f977510775..1e03e7f8bacb 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -18,7 +18,6 @@
#include <linux/clk.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -26,10 +25,47 @@
struct regmap_mmio_context {
void __iomem *regs;
+ unsigned reg_bytes;
unsigned val_bytes;
+ unsigned pad_bytes;
struct clk *clk;
};
+static inline void regmap_mmio_regsize_check(size_t reg_size)
+{
+ switch (reg_size) {
+ case 1:
+ case 2:
+ case 4:
+#ifdef CONFIG_64BIT
+ case 8:
+#endif
+ break;
+ default:
+ BUG();
+ }
+}
+
+static int regmap_mmio_regbits_check(size_t reg_bits)
+{
+ switch (reg_bits) {
+ case 8:
+ case 16:
+ case 32:
+#ifdef CONFIG_64BIT
+ case 64:
+#endif
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static inline void regmap_mmio_count_check(size_t count)
+{
+ BUG_ON(count % 2 != 0);
+}
+
static int regmap_mmio_gather_write(void *context,
const void *reg, size_t reg_size,
const void *val, size_t val_size)
@@ -38,7 +74,7 @@ static int regmap_mmio_gather_write(void *context,
u32 offset;
int ret;
- BUG_ON(reg_size != 4);
+ regmap_mmio_regsize_check(reg_size);
if (!IS_ERR(ctx->clk)) {
ret = clk_enable(ctx->clk);
@@ -81,9 +117,13 @@ static int regmap_mmio_gather_write(void *context,
static int regmap_mmio_write(void *context, const void *data, size_t count)
{
- BUG_ON(count < 4);
+ struct regmap_mmio_context *ctx = context;
+ u32 offset = ctx->reg_bytes + ctx->pad_bytes;
+
+ regmap_mmio_count_check(count);
- return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4);
+ return regmap_mmio_gather_write(context, data, ctx->reg_bytes,
+ data + offset, count - offset);
}
static int regmap_mmio_read(void *context,
@@ -94,7 +134,7 @@ static int regmap_mmio_read(void *context,
u32 offset;
int ret;
- BUG_ON(reg_size != 4);
+ regmap_mmio_regsize_check(reg_size);
if (!IS_ERR(ctx->clk)) {
ret = clk_enable(ctx->clk);
@@ -165,8 +205,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
int min_stride;
int ret;
- if (config->reg_bits != 32)
- return ERR_PTR(-EINVAL);
+ ret = regmap_mmio_regbits_check(config->reg_bits);
+ if (ret)
+ return ERR_PTR(ret);
if (config->pad_bits)
return ERR_PTR(-EINVAL);
@@ -209,6 +250,8 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
ctx->regs = regs;
ctx->val_bytes = config->val_bits / 8;
+ ctx->reg_bytes = config->reg_bits / 8;
+ ctx->pad_bytes = config->pad_bits / 8;
ctx->clk = ERR_PTR(-ENODEV);
if (clk_id == NULL)
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c
index 37f12ae7aada..0eb3097c0d76 100644
--- a/drivers/base/regmap/regmap-spi.c
+++ b/drivers/base/regmap/regmap-spi.c
@@ -12,7 +12,6 @@
#include <linux/regmap.h>
#include <linux/spi/spi.h>
-#include <linux/init.h>
#include <linux/module.h>
#include "internal.h"
diff --git a/drivers/base/regmap/regmap-spmi.c b/drivers/base/regmap/regmap-spmi.c
index ac2391013db1..d7026dc33388 100644
--- a/drivers/base/regmap/regmap-spmi.c
+++ b/drivers/base/regmap/regmap-spmi.c
@@ -22,69 +22,235 @@
#include <linux/module.h>
#include <linux/init.h>
-static int regmap_spmi_read(void *context,
- const void *reg, size_t reg_size,
- void *val, size_t val_size)
+static int regmap_spmi_base_read(void *context,
+ const void *reg, size_t reg_size,
+ void *val, size_t val_size)
{
+ u8 addr = *(u8 *)reg;
+ int err = 0;
+
+ BUG_ON(reg_size != 1);
+
+ while (val_size-- && !err)
+ err = spmi_register_read(context, addr++, val++);
+
+ return err;
+}
+
+static int regmap_spmi_base_gather_write(void *context,
+ const void *reg, size_t reg_size,
+ const void *val, size_t val_size)
+{
+ const u8 *data = val;
+ u8 addr = *(u8 *)reg;
+ int err = 0;
+
+ BUG_ON(reg_size != 1);
+
+ /*
+ * SPMI defines a more bandwidth-efficient 'Register 0 Write' sequence,
+ * use it when possible.
+ */
+ if (addr == 0 && val_size) {
+ err = spmi_register_zero_write(context, *data);
+ if (err)
+ goto err_out;
+
+ data++;
+ addr++;
+ val_size--;
+ }
+
+ while (val_size) {
+ err = spmi_register_write(context, addr, *data);
+ if (err)
+ goto err_out;
+
+ data++;
+ addr++;
+ val_size--;
+ }
+
+err_out:
+ return err;
+}
+
+static int regmap_spmi_base_write(void *context, const void *data,
+ size_t count)
+{
+ BUG_ON(count < 1);
+ return regmap_spmi_base_gather_write(context, data, 1, data + 1,
+ count - 1);
+}
+
+static struct regmap_bus regmap_spmi_base = {
+ .read = regmap_spmi_base_read,
+ .write = regmap_spmi_base_write,
+ .gather_write = regmap_spmi_base_gather_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+/**
+ * regmap_init_spmi_base(): Create regmap for the Base register space
+ * @sdev: SPMI device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ */
+struct regmap *regmap_init_spmi_base(struct spmi_device *sdev,
+ const struct regmap_config *config)
+{
+ return regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config);
+}
+EXPORT_SYMBOL_GPL(regmap_init_spmi_base);
+
+/**
+ * devm_regmap_init_spmi_base(): Create managed regmap for Base register space
+ * @sdev: SPMI device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap. The regmap will be automatically freed by the
+ * device management code.
+ */
+struct regmap *devm_regmap_init_spmi_base(struct spmi_device *sdev,
+ const struct regmap_config *config)
+{
+ return devm_regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_base);
+
+static int regmap_spmi_ext_read(void *context,
+ const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ int err = 0;
+ size_t len;
+ u16 addr;
+
BUG_ON(reg_size != 2);
- return spmi_ext_register_readl(context, *(u16 *)reg,
- val, val_size);
+
+ addr = *(u16 *)reg;
+
+ /*
+ * Split accesses into two to take advantage of the more
+ * bandwidth-efficient 'Extended Register Read' command when possible
+ */
+ while (addr <= 0xFF && val_size) {
+ len = min_t(size_t, val_size, 16);
+
+ err = spmi_ext_register_read(context, addr, val, len);
+ if (err)
+ goto err_out;
+
+ addr += len;
+ val += len;
+ val_size -= len;
+ }
+
+ while (val_size) {
+ len = min_t(size_t, val_size, 8);
+
+ err = spmi_ext_register_readl(context, addr, val, val_size);
+ if (err)
+ goto err_out;
+
+ addr += len;
+ val += len;
+ val_size -= len;
+ }
+
+err_out:
+ return err;
}
-static int regmap_spmi_gather_write(void *context,
- const void *reg, size_t reg_size,
- const void *val, size_t val_size)
+static int regmap_spmi_ext_gather_write(void *context,
+ const void *reg, size_t reg_size,
+ const void *val, size_t val_size)
{
+ int err = 0;
+ size_t len;
+ u16 addr;
+
BUG_ON(reg_size != 2);
- return spmi_ext_register_writel(context, *(u16 *)reg, val, val_size);
+
+ addr = *(u16 *)reg;
+
+ while (addr <= 0xFF && val_size) {
+ len = min_t(size_t, val_size, 16);
+
+ err = spmi_ext_register_write(context, addr, val, len);
+ if (err)
+ goto err_out;
+
+ addr += len;
+ val += len;
+ val_size -= len;
+ }
+
+ while (val_size) {
+ len = min_t(size_t, val_size, 8);
+
+ err = spmi_ext_register_writel(context, addr, val, len);
+ if (err)
+ goto err_out;
+
+ addr += len;
+ val += len;
+ val_size -= len;
+ }
+
+err_out:
+ return err;
}
-static int regmap_spmi_write(void *context, const void *data,
- size_t count)
+static int regmap_spmi_ext_write(void *context, const void *data,
+ size_t count)
{
BUG_ON(count < 2);
- return regmap_spmi_gather_write(context, data, 2, data + 2, count - 2);
+ return regmap_spmi_ext_gather_write(context, data, 2, data + 2,
+ count - 2);
}
-static struct regmap_bus regmap_spmi = {
- .read = regmap_spmi_read,
- .write = regmap_spmi_write,
- .gather_write = regmap_spmi_gather_write,
+static struct regmap_bus regmap_spmi_ext = {
+ .read = regmap_spmi_ext_read,
+ .write = regmap_spmi_ext_write,
+ .gather_write = regmap_spmi_ext_gather_write,
.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
};
/**
- * regmap_init_spmi(): Initialize register map
- *
- * @sdev: Device that will be interacted with
- * @config: Configuration for register map
+ * regmap_init_spmi_ext(): Create regmap for Ext register space
+ * @sdev: Device that will be interacted with
+ * @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
-struct regmap *regmap_init_spmi(struct spmi_device *sdev,
- const struct regmap_config *config)
+struct regmap *regmap_init_spmi_ext(struct spmi_device *sdev,
+ const struct regmap_config *config)
{
- return regmap_init(&sdev->dev, &regmap_spmi, sdev, config);
+ return regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config);
}
-EXPORT_SYMBOL_GPL(regmap_init_spmi);
+EXPORT_SYMBOL_GPL(regmap_init_spmi_ext);
/**
- * devm_regmap_init_spmi(): Initialise managed register map
- *
- * @sdev: Device that will be interacted with
- * @config: Configuration for register map
+ * devm_regmap_init_spmi_ext(): Create managed regmap for Ext register space
+ * @sdev: SPMI device that will be interacted with
+ * @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
-struct regmap *devm_regmap_init_spmi(struct spmi_device *sdev,
+struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *sdev,
const struct regmap_config *config)
{
- return devm_regmap_init(&sdev->dev, &regmap_spmi, sdev, config);
+ return devm_regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config);
}
-EXPORT_SYMBOL_GPL(devm_regmap_init_spmi);
+EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_ext);
MODULE_LICENSE("GPL");
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 6a19515f8a45..d0a072463a04 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -380,6 +380,28 @@ static void regmap_range_exit(struct regmap *map)
kfree(map->selector_work_buf);
}
+int regmap_attach_dev(struct device *dev, struct regmap *map,
+ const struct regmap_config *config)
+{
+ struct regmap **m;
+
+ map->dev = dev;
+
+ regmap_debugfs_init(map, config->name);
+
+ /* Add a devres resource for dev_get_regmap() */
+ m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
+ if (!m) {
+ regmap_debugfs_exit(map);
+ return -ENOMEM;
+ }
+ *m = map;
+ devres_add(dev, m);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(regmap_attach_dev);
+
/**
* regmap_init(): Initialise register map
*
@@ -397,7 +419,7 @@ struct regmap *regmap_init(struct device *dev,
void *bus_context,
const struct regmap_config *config)
{
- struct regmap *map, **m;
+ struct regmap *map;
int ret = -EINVAL;
enum regmap_endian reg_endian, val_endian;
int i, j;
@@ -439,6 +461,7 @@ struct regmap *regmap_init(struct device *dev,
else
map->reg_stride = 1;
map->use_single_rw = config->use_single_rw;
+ map->can_multi_write = config->can_multi_write;
map->dev = dev;
map->bus = bus;
map->bus_context = bus_context;
@@ -718,7 +741,7 @@ skip_format_initialization:
new->window_start = range_cfg->window_start;
new->window_len = range_cfg->window_len;
- if (_regmap_range_add(map, new) == false) {
+ if (!_regmap_range_add(map, new)) {
dev_err(map->dev, "Failed to add range %d\n", i);
kfree(new);
goto err_range;
@@ -734,25 +757,18 @@ skip_format_initialization:
}
}
- regmap_debugfs_init(map, config->name);
-
ret = regcache_init(map, config);
if (ret != 0)
goto err_range;
- /* Add a devres resource for dev_get_regmap() */
- m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
- if (!m) {
- ret = -ENOMEM;
- goto err_debugfs;
- }
- *m = map;
- devres_add(dev, m);
+ if (dev)
+ ret = regmap_attach_dev(dev, map, config);
+ if (ret != 0)
+ goto err_regcache;
return map;
-err_debugfs:
- regmap_debugfs_exit(map);
+err_regcache:
regcache_exit(map);
err_range:
regmap_range_exit(map);
@@ -1520,12 +1536,12 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if (reg % map->reg_stride)
return -EINVAL;
- map->lock(map->lock_arg);
/*
* Some devices don't support bulk write, for
* them we have a series of single write operations.
*/
if (!map->bus || map->use_single_rw) {
+ map->lock(map->lock_arg);
for (i = 0; i < val_count; i++) {
unsigned int ival;
@@ -1554,31 +1570,239 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if (ret != 0)
goto out;
}
+out:
+ map->unlock(map->lock_arg);
} else {
void *wval;
wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL);
if (!wval) {
- ret = -ENOMEM;
dev_err(map->dev, "Error in memory allocation\n");
- goto out;
+ return -ENOMEM;
}
for (i = 0; i < val_count * val_bytes; i += val_bytes)
map->format.parse_inplace(wval + i);
+ map->lock(map->lock_arg);
ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
+ map->unlock(map->lock_arg);
kfree(wval);
}
-out:
- map->unlock(map->lock_arg);
return ret;
}
EXPORT_SYMBOL_GPL(regmap_bulk_write);
/*
+ * _regmap_raw_multi_reg_write()
+ *
+ * the (register,newvalue) pairs in regs have not been formatted, but
+ * they are all in the same page and have been changed to being page
+ * relative. The page register has been written if that was neccessary.
+ */
+static int _regmap_raw_multi_reg_write(struct regmap *map,
+ const struct reg_default *regs,
+ size_t num_regs)
+{
+ int ret;
+ void *buf;
+ int i;
+ u8 *u8;
+ size_t val_bytes = map->format.val_bytes;
+ size_t reg_bytes = map->format.reg_bytes;
+ size_t pad_bytes = map->format.pad_bytes;
+ size_t pair_size = reg_bytes + pad_bytes + val_bytes;
+ size_t len = pair_size * num_regs;
+
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ /* We have to linearise by hand. */
+
+ u8 = buf;
+
+ for (i = 0; i < num_regs; i++) {
+ int reg = regs[i].reg;
+ int val = regs[i].def;
+ trace_regmap_hw_write_start(map->dev, reg, 1);
+ map->format.format_reg(u8, reg, map->reg_shift);
+ u8 += reg_bytes + pad_bytes;
+ map->format.format_val(u8, val, 0);
+ u8 += val_bytes;
+ }
+ u8 = buf;
+ *u8 |= map->write_flag_mask;
+
+ ret = map->bus->write(map->bus_context, buf, len);
+
+ kfree(buf);
+
+ for (i = 0; i < num_regs; i++) {
+ int reg = regs[i].reg;
+ trace_regmap_hw_write_done(map->dev, reg, 1);
+ }
+ return ret;
+}
+
+static unsigned int _regmap_register_page(struct regmap *map,
+ unsigned int reg,
+ struct regmap_range_node *range)
+{
+ unsigned int win_page = (reg - range->range_min) / range->window_len;
+
+ return win_page;
+}
+
+static int _regmap_range_multi_paged_reg_write(struct regmap *map,
+ struct reg_default *regs,
+ size_t num_regs)
+{
+ int ret;
+ int i, n;
+ struct reg_default *base;
+ unsigned int this_page;
+ /*
+ * the set of registers are not neccessarily in order, but
+ * since the order of write must be preserved this algorithm
+ * chops the set each time the page changes
+ */
+ base = regs;
+ for (i = 0, n = 0; i < num_regs; i++, n++) {
+ unsigned int reg = regs[i].reg;
+ struct regmap_range_node *range;
+
+ range = _regmap_range_lookup(map, reg);
+ if (range) {
+ unsigned int win_page = _regmap_register_page(map, reg,
+ range);
+
+ if (i == 0)
+ this_page = win_page;
+ if (win_page != this_page) {
+ this_page = win_page;
+ ret = _regmap_raw_multi_reg_write(map, base, n);
+ if (ret != 0)
+ return ret;
+ base += n;
+ n = 0;
+ }
+ ret = _regmap_select_page(map, &base[n].reg, range, 1);
+ if (ret != 0)
+ return ret;
+ }
+ }
+ if (n > 0)
+ return _regmap_raw_multi_reg_write(map, base, n);
+ return 0;
+}
+
+static int _regmap_multi_reg_write(struct regmap *map,
+ const struct reg_default *regs,
+ size_t num_regs)
+{
+ int i;
+ int ret;
+
+ if (!map->can_multi_write) {
+ for (i = 0; i < num_regs; i++) {
+ ret = _regmap_write(map, regs[i].reg, regs[i].def);
+ if (ret != 0)
+ return ret;
+ }
+ return 0;
+ }
+
+ if (!map->format.parse_inplace)
+ return -EINVAL;
+
+ if (map->writeable_reg)
+ for (i = 0; i < num_regs; i++) {
+ int reg = regs[i].reg;
+ if (!map->writeable_reg(map->dev, reg))
+ return -EINVAL;
+ if (reg % map->reg_stride)
+ return -EINVAL;
+ }
+
+ if (!map->cache_bypass) {
+ for (i = 0; i < num_regs; i++) {
+ unsigned int val = regs[i].def;
+ unsigned int reg = regs[i].reg;
+ ret = regcache_write(map, reg, val);
+ if (ret) {
+ dev_err(map->dev,
+ "Error in caching of register: %x ret: %d\n",
+ reg, ret);
+ return ret;
+ }
+ }
+ if (map->cache_only) {
+ map->cache_dirty = true;
+ return 0;
+ }
+ }
+
+ WARN_ON(!map->bus);
+
+ for (i = 0; i < num_regs; i++) {
+ unsigned int reg = regs[i].reg;
+ struct regmap_range_node *range;
+ range = _regmap_range_lookup(map, reg);
+ if (range) {
+ size_t len = sizeof(struct reg_default)*num_regs;
+ struct reg_default *base = kmemdup(regs, len,
+ GFP_KERNEL);
+ if (!base)
+ return -ENOMEM;
+ ret = _regmap_range_multi_paged_reg_write(map, base,
+ num_regs);
+ kfree(base);
+
+ return ret;
+ }
+ }
+ return _regmap_raw_multi_reg_write(map, regs, num_regs);
+}
+
+/*
* regmap_multi_reg_write(): Write multiple registers to the device
*
+ * where the set of register,value pairs are supplied in any order,
+ * possibly not all in a single range.
+ *
+ * @map: Register map to write to
+ * @regs: Array of structures containing register,value to be written
+ * @num_regs: Number of registers to write
+ *
+ * The 'normal' block write mode will send ultimately send data on the
+ * target bus as R,V1,V2,V3,..,Vn where successively higer registers are
+ * addressed. However, this alternative block multi write mode will send
+ * the data as R1,V1,R2,V2,..,Rn,Vn on the target bus. The target device
+ * must of course support the mode.
+ *
+ * A value of zero will be returned on success, a negative errno will be
+ * returned in error cases.
+ */
+int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
+ int num_regs)
+{
+ int ret;
+
+ map->lock(map->lock_arg);
+
+ ret = _regmap_multi_reg_write(map, regs, num_regs);
+
+ map->unlock(map->lock_arg);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
+
+/*
+ * regmap_multi_reg_write_bypassed(): Write multiple registers to the
+ * device but not the cache
+ *
* where the set of register are supplied in any order
*
* @map: Register map to write to
@@ -1592,30 +1816,27 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
-int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs,
- int num_regs)
+int regmap_multi_reg_write_bypassed(struct regmap *map,
+ const struct reg_default *regs,
+ int num_regs)
{
- int ret = 0, i;
-
- for (i = 0; i < num_regs; i++) {
- int reg = regs[i].reg;
- if (reg % map->reg_stride)
- return -EINVAL;
- }
+ int ret;
+ bool bypass;
map->lock(map->lock_arg);
- for (i = 0; i < num_regs; i++) {
- ret = _regmap_write(map, regs[i].reg, regs[i].def);
- if (ret != 0)
- goto out;
- }
-out:
+ bypass = map->cache_bypass;
+ map->cache_bypass = true;
+
+ ret = _regmap_multi_reg_write(map, regs, num_regs);
+
+ map->cache_bypass = bypass;
+
map->unlock(map->lock_arg);
return ret;
}
-EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
+EXPORT_SYMBOL_GPL(regmap_multi_reg_write_bypassed);
/**
* regmap_raw_write_async(): Write raw values to one or more registers
@@ -1736,6 +1957,9 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
if (map->cache_only)
return -EBUSY;
+ if (!regmap_readable(map, reg))
+ return -EIO;
+
ret = map->reg_read(context, reg, val);
if (ret == 0) {
#ifdef LOG_DEVICE
@@ -1966,9 +2190,11 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
if (tmp != orig) {
ret = _regmap_write(map, reg, tmp);
- *change = true;
+ if (change)
+ *change = true;
} else {
- *change = false;
+ if (change)
+ *change = false;
}
return ret;
@@ -1987,11 +2213,10 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
int regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val)
{
- bool change;
int ret;
map->lock(map->lock_arg);
- ret = _regmap_update_bits(map, reg, mask, val, &change);
+ ret = _regmap_update_bits(map, reg, mask, val, NULL);
map->unlock(map->lock_arg);
return ret;
@@ -2016,14 +2241,13 @@ EXPORT_SYMBOL_GPL(regmap_update_bits);
int regmap_update_bits_async(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val)
{
- bool change;
int ret;
map->lock(map->lock_arg);
map->async = true;
- ret = _regmap_update_bits(map, reg, mask, val, &change);
+ ret = _regmap_update_bits(map, reg, mask, val, NULL);
map->async = false;
@@ -2173,35 +2397,21 @@ EXPORT_SYMBOL_GPL(regmap_async_complete);
* apply them immediately. Typically this is used to apply
* corrections to be applied to the device defaults on startup, such
* as the updates some vendors provide to undocumented registers.
+ *
+ * The caller must ensure that this function cannot be called
+ * concurrently with either itself or regcache_sync().
*/
int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
int num_regs)
{
struct reg_default *p;
- int i, ret;
+ int ret;
bool bypass;
if (WARN_ONCE(num_regs <= 0, "invalid registers number (%d)\n",
num_regs))
return 0;
- map->lock(map->lock_arg);
-
- bypass = map->cache_bypass;
-
- map->cache_bypass = true;
- map->async = true;
-
- /* Write out first; it's useful to apply even if we fail later. */
- for (i = 0; i < num_regs; i++) {
- ret = _regmap_write(map, regs[i].reg, regs[i].def);
- if (ret != 0) {
- dev_err(map->dev, "Failed to write %x = %x: %d\n",
- regs[i].reg, regs[i].def, ret);
- goto out;
- }
- }
-
p = krealloc(map->patch,
sizeof(struct reg_default) * (map->patch_regs + num_regs),
GFP_KERNEL);
@@ -2210,9 +2420,20 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
map->patch = p;
map->patch_regs += num_regs;
} else {
- ret = -ENOMEM;
+ return -ENOMEM;
}
+ map->lock(map->lock_arg);
+
+ bypass = map->cache_bypass;
+
+ map->cache_bypass = true;
+ map->async = true;
+
+ ret = _regmap_multi_reg_write(map, regs, num_regs);
+ if (ret != 0)
+ goto out;
+
out:
map->async = false;
map->cache_bypass = bypass;
@@ -2240,6 +2461,18 @@ int regmap_get_val_bytes(struct regmap *map)
}
EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
+int regmap_parse_val(struct regmap *map, const void *buf,
+ unsigned int *val)
+{
+ if (!map->format.parse_val)
+ return -EINVAL;
+
+ *val = map->format.parse_val(buf);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(regmap_parse_val);
+
static int __init regmap_initcall(void)
{
regmap_debugfs_initcall();
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 94ffee378f10..ad9d17762664 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -23,7 +23,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
-#include <linux/init.h>
#include <linux/mm.h>
#include <linux/cpu.h>
#include <linux/module.h>
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index eb3950113e42..125d84505738 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -6411,12 +6411,12 @@ static bool DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller,
.ScatterGatherSegments[0]
.SegmentByteCount =
CommandMailbox->ControllerInfo.DataTransferSize;
- DAC960_ExecuteCommand(Command);
- while (Controller->V2.NewControllerInformation->PhysicalScanActive)
- {
- DAC960_ExecuteCommand(Command);
- sleep_on_timeout(&Controller->CommandWaitQueue, HZ);
- }
+ while (1) {
+ DAC960_ExecuteCommand(Command);
+ if (!Controller->V2.NewControllerInformation->PhysicalScanActive)
+ break;
+ msleep(1000);
+ }
DAC960_UserCritical("Discovery Completed\n", Controller);
}
}
@@ -7035,18 +7035,16 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request,
ErrorCode = -EFAULT;
break;
}
- while (Controller->V2.HealthStatusBuffer->StatusChangeCounter
- == HealthStatusBuffer.StatusChangeCounter &&
- Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
- == HealthStatusBuffer.NextEventSequenceNumber)
- {
- interruptible_sleep_on_timeout(&Controller->HealthStatusWaitQueue,
- DAC960_MonitoringTimerInterval);
- if (signal_pending(current)) {
- ErrorCode = -EINTR;
- break;
- }
- }
+ ErrorCode = wait_event_interruptible_timeout(Controller->HealthStatusWaitQueue,
+ !(Controller->V2.HealthStatusBuffer->StatusChangeCounter
+ == HealthStatusBuffer.StatusChangeCounter &&
+ Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
+ == HealthStatusBuffer.NextEventSequenceNumber),
+ DAC960_MonitoringTimerInterval);
+ if (ErrorCode == -ERESTARTSYS) {
+ ErrorCode = -EINTR;
+ break;
+ }
if (copy_to_user(GetHealthStatus.HealthStatusBuffer,
Controller->V2.HealthStatusBuffer,
sizeof(DAC960_V2_HealthStatusBuffer_T)))
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 8184451b57c0..422b7d84f686 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -874,7 +874,7 @@ bio_pageinc(struct bio *bio)
/* Non-zero page count for non-head members of
* compound pages is no longer allowed by the kernel.
*/
- page = compound_trans_head(bv.bv_page);
+ page = compound_head(bv.bv_page);
atomic_inc(&page->_count);
}
}
@@ -887,7 +887,7 @@ bio_pagedec(struct bio *bio)
struct bvec_iter iter;
bio_for_each_segment(bv, bio, iter) {
- page = compound_trans_head(bv.bv_page);
+ page = compound_head(bv.bv_page);
atomic_dec(&page->_count);
}
}
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 0e30c6e5492a..96b629e1f0c9 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -68,6 +68,8 @@
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/wait.h>
#include <asm/atafd.h>
#include <asm/atafdreg.h>
@@ -301,7 +303,7 @@ module_param_array(UserSteprate, int, NULL, 0);
/* Synchronization of FDC access. */
static volatile int fdc_busy = 0;
static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
-static DECLARE_WAIT_QUEUE_HEAD(format_wait);
+static DECLARE_COMPLETION(format_wait);
static unsigned long changed_floppies = 0xff, fake_change = 0;
#define CHECK_CHANGE_DELAY HZ/2
@@ -608,7 +610,7 @@ static void fd_error( void )
if (IsFormatting) {
IsFormatting = 0;
FormatError = 1;
- wake_up( &format_wait );
+ complete(&format_wait);
return;
}
@@ -650,9 +652,8 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n",
drive, desc->track, desc->head, desc->sect_offset ));
+ wait_event(fdc_wait, cmpxchg(&fdc_busy, 0, 1) == 0);
local_irq_save(flags);
- while( fdc_busy ) sleep_on( &fdc_wait );
- fdc_busy = 1;
stdma_lock(floppy_irq, NULL);
atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */
local_irq_restore(flags);
@@ -706,7 +707,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
ReqSide = desc->head;
do_fd_action( drive );
- sleep_on( &format_wait );
+ wait_for_completion(&format_wait);
redo_fd_request();
return( FormatError ? -EIO : 0 );
@@ -1229,7 +1230,7 @@ static void fd_writetrack_done( int status )
goto err_end;
}
- wake_up( &format_wait );
+ complete(&format_wait);
return;
err_end:
@@ -1497,8 +1498,7 @@ repeat:
void do_fd_request(struct request_queue * q)
{
DPRINT(("do_fd_request for pid %d\n",current->pid));
- while( fdc_busy ) sleep_on( &fdc_wait );
- fdc_busy = 1;
+ wait_event(fdc_wait, cmpxchg(&fdc_busy, 0, 1) == 0);
stdma_lock(floppy_irq, NULL);
atari_disable_irq( IRQ_MFP_FDC );
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 036e8ab86c71..73894ca33956 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -4092,11 +4092,9 @@ static void cciss_interrupt_mode(ctlr_info_t *h)
if (err > 0) {
dev_warn(&h->pdev->dev,
"only %d MSI-X vectors available\n", err);
- goto default_int_mode;
} else {
dev_warn(&h->pdev->dev,
"MSI-X init failed %d\n", err);
- goto default_int_mode;
}
}
if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) {
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
index a9b13f2cc420..90ae4ba8f9ee 100644
--- a/drivers/block/drbd/drbd_actlog.c
+++ b/drivers/block/drbd/drbd_actlog.c
@@ -95,34 +95,36 @@ struct __packed al_transaction_on_disk {
struct update_odbm_work {
struct drbd_work w;
+ struct drbd_device *device;
unsigned int enr;
};
struct update_al_work {
struct drbd_work w;
+ struct drbd_device *device;
struct completion event;
int err;
};
-void *drbd_md_get_buffer(struct drbd_conf *mdev)
+void *drbd_md_get_buffer(struct drbd_device *device)
{
int r;
- wait_event(mdev->misc_wait,
- (r = atomic_cmpxchg(&mdev->md_io_in_use, 0, 1)) == 0 ||
- mdev->state.disk <= D_FAILED);
+ wait_event(device->misc_wait,
+ (r = atomic_cmpxchg(&device->md_io_in_use, 0, 1)) == 0 ||
+ device->state.disk <= D_FAILED);
- return r ? NULL : page_address(mdev->md_io_page);
+ return r ? NULL : page_address(device->md_io_page);
}
-void drbd_md_put_buffer(struct drbd_conf *mdev)
+void drbd_md_put_buffer(struct drbd_device *device)
{
- if (atomic_dec_and_test(&mdev->md_io_in_use))
- wake_up(&mdev->misc_wait);
+ if (atomic_dec_and_test(&device->md_io_in_use))
+ wake_up(&device->misc_wait);
}
-void wait_until_done_or_force_detached(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
+void wait_until_done_or_force_detached(struct drbd_device *device, struct drbd_backing_dev *bdev,
unsigned int *done)
{
long dt;
@@ -134,15 +136,15 @@ void wait_until_done_or_force_detached(struct drbd_conf *mdev, struct drbd_backi
if (dt == 0)
dt = MAX_SCHEDULE_TIMEOUT;
- dt = wait_event_timeout(mdev->misc_wait,
- *done || test_bit(FORCE_DETACH, &mdev->flags), dt);
+ dt = wait_event_timeout(device->misc_wait,
+ *done || test_bit(FORCE_DETACH, &device->flags), dt);
if (dt == 0) {
- dev_err(DEV, "meta-data IO operation timed out\n");
- drbd_chk_io_error(mdev, 1, DRBD_FORCE_DETACH);
+ drbd_err(device, "meta-data IO operation timed out\n");
+ drbd_chk_io_error(device, 1, DRBD_FORCE_DETACH);
}
}
-static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
+static int _drbd_md_sync_page_io(struct drbd_device *device,
struct drbd_backing_dev *bdev,
struct page *page, sector_t sector,
int rw, int size)
@@ -150,10 +152,10 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
struct bio *bio;
int err;
- mdev->md_io.done = 0;
- mdev->md_io.error = -ENODEV;
+ device->md_io.done = 0;
+ device->md_io.error = -ENODEV;
- if ((rw & WRITE) && !test_bit(MD_NO_FUA, &mdev->flags))
+ if ((rw & WRITE) && !test_bit(MD_NO_FUA, &device->flags))
rw |= REQ_FUA | REQ_FLUSH;
rw |= REQ_SYNC;
@@ -163,69 +165,69 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
err = -EIO;
if (bio_add_page(bio, page, size, 0) != size)
goto out;
- bio->bi_private = &mdev->md_io;
+ bio->bi_private = &device->md_io;
bio->bi_end_io = drbd_md_io_complete;
bio->bi_rw = rw;
- if (!(rw & WRITE) && mdev->state.disk == D_DISKLESS && mdev->ldev == NULL)
+ if (!(rw & WRITE) && device->state.disk == D_DISKLESS && device->ldev == NULL)
/* special case, drbd_md_read() during drbd_adm_attach(): no get_ldev */
;
- else if (!get_ldev_if_state(mdev, D_ATTACHING)) {
+ else if (!get_ldev_if_state(device, D_ATTACHING)) {
/* Corresponding put_ldev in drbd_md_io_complete() */
- dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in _drbd_md_sync_page_io()\n");
+ drbd_err(device, "ASSERT FAILED: get_ldev_if_state() == 1 in _drbd_md_sync_page_io()\n");
err = -ENODEV;
goto out;
}
bio_get(bio); /* one bio_put() is in the completion handler */
- atomic_inc(&mdev->md_io_in_use); /* drbd_md_put_buffer() is in the completion handler */
- if (drbd_insert_fault(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD))
+ atomic_inc(&device->md_io_in_use); /* drbd_md_put_buffer() is in the completion handler */
+ if (drbd_insert_fault(device, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD))
bio_endio(bio, -EIO);
else
submit_bio(rw, bio);
- wait_until_done_or_force_detached(mdev, bdev, &mdev->md_io.done);
+ wait_until_done_or_force_detached(device, bdev, &device->md_io.done);
if (bio_flagged(bio, BIO_UPTODATE))
- err = mdev->md_io.error;
+ err = device->md_io.error;
out:
bio_put(bio);
return err;
}
-int drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
+int drbd_md_sync_page_io(struct drbd_device *device, struct drbd_backing_dev *bdev,
sector_t sector, int rw)
{
int err;
- struct page *iop = mdev->md_io_page;
+ struct page *iop = device->md_io_page;
- D_ASSERT(atomic_read(&mdev->md_io_in_use) == 1);
+ D_ASSERT(device, atomic_read(&device->md_io_in_use) == 1);
BUG_ON(!bdev->md_bdev);
- dev_dbg(DEV, "meta_data io: %s [%d]:%s(,%llus,%s) %pS\n",
+ drbd_dbg(device, "meta_data io: %s [%d]:%s(,%llus,%s) %pS\n",
current->comm, current->pid, __func__,
(unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ",
(void*)_RET_IP_ );
if (sector < drbd_md_first_sector(bdev) ||
sector + 7 > drbd_md_last_sector(bdev))
- dev_alert(DEV, "%s [%d]:%s(,%llus,%s) out of range md access!\n",
+ drbd_alert(device, "%s [%d]:%s(,%llus,%s) out of range md access!\n",
current->comm, current->pid, __func__,
(unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ");
/* we do all our meta data IO in aligned 4k blocks. */
- err = _drbd_md_sync_page_io(mdev, bdev, iop, sector, rw, 4096);
+ err = _drbd_md_sync_page_io(device, bdev, iop, sector, rw, 4096);
if (err) {
- dev_err(DEV, "drbd_md_sync_page_io(,%llus,%s) failed with error %d\n",
+ drbd_err(device, "drbd_md_sync_page_io(,%llus,%s) failed with error %d\n",
(unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ", err);
}
return err;
}
-static struct bm_extent *find_active_resync_extent(struct drbd_conf *mdev, unsigned int enr)
+static struct bm_extent *find_active_resync_extent(struct drbd_device *device, unsigned int enr)
{
struct lc_element *tmp;
- tmp = lc_find(mdev->resync, enr/AL_EXT_PER_BM_SECT);
+ tmp = lc_find(device->resync, enr/AL_EXT_PER_BM_SECT);
if (unlikely(tmp != NULL)) {
struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce);
if (test_bit(BME_NO_WRITES, &bm_ext->flags))
@@ -234,47 +236,48 @@ static struct bm_extent *find_active_resync_extent(struct drbd_conf *mdev, unsig
return NULL;
}
-static struct lc_element *_al_get(struct drbd_conf *mdev, unsigned int enr, bool nonblock)
+static struct lc_element *_al_get(struct drbd_device *device, unsigned int enr, bool nonblock)
{
struct lc_element *al_ext;
struct bm_extent *bm_ext;
int wake;
- spin_lock_irq(&mdev->al_lock);
- bm_ext = find_active_resync_extent(mdev, enr);
+ spin_lock_irq(&device->al_lock);
+ bm_ext = find_active_resync_extent(device, enr);
if (bm_ext) {
wake = !test_and_set_bit(BME_PRIORITY, &bm_ext->flags);
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
if (wake)
- wake_up(&mdev->al_wait);
+ wake_up(&device->al_wait);
return NULL;
}
if (nonblock)
- al_ext = lc_try_get(mdev->act_log, enr);
+ al_ext = lc_try_get(device->act_log, enr);
else
- al_ext = lc_get(mdev->act_log, enr);
- spin_unlock_irq(&mdev->al_lock);
+ al_ext = lc_get(device->act_log, enr);
+ spin_unlock_irq(&device->al_lock);
return al_ext;
}
-bool drbd_al_begin_io_fastpath(struct drbd_conf *mdev, struct drbd_interval *i)
+bool drbd_al_begin_io_fastpath(struct drbd_device *device, struct drbd_interval *i)
{
/* for bios crossing activity log extent boundaries,
* we may need to activate two extents in one go */
unsigned first = i->sector >> (AL_EXTENT_SHIFT-9);
unsigned last = i->size == 0 ? first : (i->sector + (i->size >> 9) - 1) >> (AL_EXTENT_SHIFT-9);
- D_ASSERT((unsigned)(last - first) <= 1);
- D_ASSERT(atomic_read(&mdev->local_cnt) > 0);
+ D_ASSERT(device, (unsigned)(last - first) <= 1);
+ D_ASSERT(device, atomic_read(&device->local_cnt) > 0);
/* FIXME figure out a fast path for bios crossing AL extent boundaries */
if (first != last)
return false;
- return _al_get(mdev, first, true);
+ return _al_get(device, first, true);
}
-bool drbd_al_begin_io_prepare(struct drbd_conf *mdev, struct drbd_interval *i)
+static
+bool drbd_al_begin_io_prepare(struct drbd_device *device, struct drbd_interval *i)
{
/* for bios crossing activity log extent boundaries,
* we may need to activate two extents in one go */
@@ -283,20 +286,20 @@ bool drbd_al_begin_io_prepare(struct drbd_conf *mdev, struct drbd_interval *i)
unsigned enr;
bool need_transaction = false;
- D_ASSERT(first <= last);
- D_ASSERT(atomic_read(&mdev->local_cnt) > 0);
+ D_ASSERT(device, first <= last);
+ D_ASSERT(device, atomic_read(&device->local_cnt) > 0);
for (enr = first; enr <= last; enr++) {
struct lc_element *al_ext;
- wait_event(mdev->al_wait,
- (al_ext = _al_get(mdev, enr, false)) != NULL);
+ wait_event(device->al_wait,
+ (al_ext = _al_get(device, enr, false)) != NULL);
if (al_ext->lc_number != enr)
need_transaction = true;
}
return need_transaction;
}
-static int al_write_transaction(struct drbd_conf *mdev, bool delegate);
+static int al_write_transaction(struct drbd_device *device, bool delegate);
/* When called through generic_make_request(), we must delegate
* activity log I/O to the worker thread: a further request
@@ -310,58 +313,58 @@ static int al_write_transaction(struct drbd_conf *mdev, bool delegate);
/*
* @delegate: delegate activity log I/O to the worker thread
*/
-void drbd_al_begin_io_commit(struct drbd_conf *mdev, bool delegate)
+void drbd_al_begin_io_commit(struct drbd_device *device, bool delegate)
{
bool locked = false;
- BUG_ON(delegate && current == mdev->tconn->worker.task);
+ BUG_ON(delegate && current == first_peer_device(device)->connection->worker.task);
/* Serialize multiple transactions.
* This uses test_and_set_bit, memory barrier is implicit.
*/
- wait_event(mdev->al_wait,
- mdev->act_log->pending_changes == 0 ||
- (locked = lc_try_lock_for_transaction(mdev->act_log)));
+ wait_event(device->al_wait,
+ device->act_log->pending_changes == 0 ||
+ (locked = lc_try_lock_for_transaction(device->act_log)));
if (locked) {
/* Double check: it may have been committed by someone else,
* while we have been waiting for the lock. */
- if (mdev->act_log->pending_changes) {
+ if (device->act_log->pending_changes) {
bool write_al_updates;
rcu_read_lock();
- write_al_updates = rcu_dereference(mdev->ldev->disk_conf)->al_updates;
+ write_al_updates = rcu_dereference(device->ldev->disk_conf)->al_updates;
rcu_read_unlock();
if (write_al_updates)
- al_write_transaction(mdev, delegate);
- spin_lock_irq(&mdev->al_lock);
+ al_write_transaction(device, delegate);
+ spin_lock_irq(&device->al_lock);
/* FIXME
if (err)
we need an "lc_cancel" here;
*/
- lc_committed(mdev->act_log);
- spin_unlock_irq(&mdev->al_lock);
+ lc_committed(device->act_log);
+ spin_unlock_irq(&device->al_lock);
}
- lc_unlock(mdev->act_log);
- wake_up(&mdev->al_wait);
+ lc_unlock(device->act_log);
+ wake_up(&device->al_wait);
}
}
/*
* @delegate: delegate activity log I/O to the worker thread
*/
-void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i, bool delegate)
+void drbd_al_begin_io(struct drbd_device *device, struct drbd_interval *i, bool delegate)
{
- BUG_ON(delegate && current == mdev->tconn->worker.task);
+ BUG_ON(delegate && current == first_peer_device(device)->connection->worker.task);
- if (drbd_al_begin_io_prepare(mdev, i))
- drbd_al_begin_io_commit(mdev, delegate);
+ if (drbd_al_begin_io_prepare(device, i))
+ drbd_al_begin_io_commit(device, delegate);
}
-int drbd_al_begin_io_nonblock(struct drbd_conf *mdev, struct drbd_interval *i)
+int drbd_al_begin_io_nonblock(struct drbd_device *device, struct drbd_interval *i)
{
- struct lru_cache *al = mdev->act_log;
+ struct lru_cache *al = device->act_log;
/* for bios crossing activity log extent boundaries,
* we may need to activate two extents in one go */
unsigned first = i->sector >> (AL_EXTENT_SHIFT-9);
@@ -370,7 +373,7 @@ int drbd_al_begin_io_nonblock(struct drbd_conf *mdev, struct drbd_interval *i)
unsigned available_update_slots;
unsigned enr;
- D_ASSERT(first <= last);
+ D_ASSERT(device, first <= last);
nr_al_extents = 1 + last - first; /* worst case: all touched extends are cold. */
available_update_slots = min(al->nr_elements - al->used,
@@ -385,7 +388,7 @@ int drbd_al_begin_io_nonblock(struct drbd_conf *mdev, struct drbd_interval *i)
/* Is resync active in this area? */
for (enr = first; enr <= last; enr++) {
struct lc_element *tmp;
- tmp = lc_find(mdev->resync, enr/AL_EXT_PER_BM_SECT);
+ tmp = lc_find(device->resync, enr/AL_EXT_PER_BM_SECT);
if (unlikely(tmp != NULL)) {
struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce);
if (test_bit(BME_NO_WRITES, &bm_ext->flags)) {
@@ -401,14 +404,14 @@ int drbd_al_begin_io_nonblock(struct drbd_conf *mdev, struct drbd_interval *i)
* this has to be successful. */
for (enr = first; enr <= last; enr++) {
struct lc_element *al_ext;
- al_ext = lc_get_cumulative(mdev->act_log, enr);
+ al_ext = lc_get_cumulative(device->act_log, enr);
if (!al_ext)
- dev_info(DEV, "LOGIC BUG for enr=%u\n", enr);
+ drbd_info(device, "LOGIC BUG for enr=%u\n", enr);
}
return 0;
}
-void drbd_al_complete_io(struct drbd_conf *mdev, struct drbd_interval *i)
+void drbd_al_complete_io(struct drbd_device *device, struct drbd_interval *i)
{
/* for bios crossing activity log extent boundaries,
* we may need to activate two extents in one go */
@@ -418,19 +421,19 @@ void drbd_al_complete_io(struct drbd_conf *mdev, struct drbd_interval *i)
struct lc_element *extent;
unsigned long flags;
- D_ASSERT(first <= last);
- spin_lock_irqsave(&mdev->al_lock, flags);
+ D_ASSERT(device, first <= last);
+ spin_lock_irqsave(&device->al_lock, flags);
for (enr = first; enr <= last; enr++) {
- extent = lc_find(mdev->act_log, enr);
+ extent = lc_find(device->act_log, enr);
if (!extent) {
- dev_err(DEV, "al_complete_io() called on inactive extent %u\n", enr);
+ drbd_err(device, "al_complete_io() called on inactive extent %u\n", enr);
continue;
}
- lc_put(mdev->act_log, extent);
+ lc_put(device->act_log, extent);
}
- spin_unlock_irqrestore(&mdev->al_lock, flags);
- wake_up(&mdev->al_wait);
+ spin_unlock_irqrestore(&device->al_lock, flags);
+ wake_up(&device->al_wait);
}
#if (PAGE_SHIFT + 3) < (AL_EXTENT_SHIFT - BM_BLOCK_SHIFT)
@@ -460,13 +463,13 @@ static unsigned int rs_extent_to_bm_page(unsigned int rs_enr)
(BM_EXT_SHIFT - BM_BLOCK_SHIFT));
}
-static sector_t al_tr_number_to_on_disk_sector(struct drbd_conf *mdev)
+static sector_t al_tr_number_to_on_disk_sector(struct drbd_device *device)
{
- const unsigned int stripes = mdev->ldev->md.al_stripes;
- const unsigned int stripe_size_4kB = mdev->ldev->md.al_stripe_size_4k;
+ const unsigned int stripes = device->ldev->md.al_stripes;
+ const unsigned int stripe_size_4kB = device->ldev->md.al_stripe_size_4k;
/* transaction number, modulo on-disk ring buffer wrap around */
- unsigned int t = mdev->al_tr_number % (mdev->ldev->md.al_size_4k);
+ unsigned int t = device->al_tr_number % (device->ldev->md.al_size_4k);
/* ... to aligned 4k on disk block */
t = ((t % stripes) * stripe_size_4kB) + t/stripes;
@@ -475,11 +478,11 @@ static sector_t al_tr_number_to_on_disk_sector(struct drbd_conf *mdev)
t *= 8;
/* ... plus offset to the on disk position */
- return mdev->ldev->md.md_offset + mdev->ldev->md.al_offset + t;
+ return device->ldev->md.md_offset + device->ldev->md.al_offset + t;
}
static int
-_al_write_transaction(struct drbd_conf *mdev)
+_al_write_transaction(struct drbd_device *device)
{
struct al_transaction_on_disk *buffer;
struct lc_element *e;
@@ -489,31 +492,31 @@ _al_write_transaction(struct drbd_conf *mdev)
unsigned crc = 0;
int err = 0;
- if (!get_ldev(mdev)) {
- dev_err(DEV, "disk is %s, cannot start al transaction\n",
- drbd_disk_str(mdev->state.disk));
+ if (!get_ldev(device)) {
+ drbd_err(device, "disk is %s, cannot start al transaction\n",
+ drbd_disk_str(device->state.disk));
return -EIO;
}
/* The bitmap write may have failed, causing a state change. */
- if (mdev->state.disk < D_INCONSISTENT) {
- dev_err(DEV,
+ if (device->state.disk < D_INCONSISTENT) {
+ drbd_err(device,
"disk is %s, cannot write al transaction\n",
- drbd_disk_str(mdev->state.disk));
- put_ldev(mdev);
+ drbd_disk_str(device->state.disk));
+ put_ldev(device);
return -EIO;
}
- buffer = drbd_md_get_buffer(mdev); /* protects md_io_buffer, al_tr_cycle, ... */
+ buffer = drbd_md_get_buffer(device); /* protects md_io_buffer, al_tr_cycle, ... */
if (!buffer) {
- dev_err(DEV, "disk failed while waiting for md_io buffer\n");
- put_ldev(mdev);
+ drbd_err(device, "disk failed while waiting for md_io buffer\n");
+ put_ldev(device);
return -ENODEV;
}
memset(buffer, 0, sizeof(*buffer));
buffer->magic = cpu_to_be32(DRBD_AL_MAGIC);
- buffer->tr_number = cpu_to_be32(mdev->al_tr_number);
+ buffer->tr_number = cpu_to_be32(device->al_tr_number);
i = 0;
@@ -521,8 +524,8 @@ _al_write_transaction(struct drbd_conf *mdev)
* once we set the LC_LOCKED -- from drbd_al_begin_io(),
* lc_try_lock_for_transaction() --, someone may still
* be in the process of changing it. */
- spin_lock_irq(&mdev->al_lock);
- list_for_each_entry(e, &mdev->act_log->to_be_changed, list) {
+ spin_lock_irq(&device->al_lock);
+ list_for_each_entry(e, &device->act_log->to_be_changed, list) {
if (i == AL_UPDATES_PER_TRANSACTION) {
i++;
break;
@@ -530,11 +533,11 @@ _al_write_transaction(struct drbd_conf *mdev)
buffer->update_slot_nr[i] = cpu_to_be16(e->lc_index);
buffer->update_extent_nr[i] = cpu_to_be32(e->lc_new_number);
if (e->lc_number != LC_FREE)
- drbd_bm_mark_for_writeout(mdev,
+ drbd_bm_mark_for_writeout(device,
al_extent_to_bm_page(e->lc_number));
i++;
}
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
BUG_ON(i > AL_UPDATES_PER_TRANSACTION);
buffer->n_updates = cpu_to_be16(i);
@@ -543,48 +546,48 @@ _al_write_transaction(struct drbd_conf *mdev)
buffer->update_extent_nr[i] = cpu_to_be32(LC_FREE);
}
- buffer->context_size = cpu_to_be16(mdev->act_log->nr_elements);
- buffer->context_start_slot_nr = cpu_to_be16(mdev->al_tr_cycle);
+ buffer->context_size = cpu_to_be16(device->act_log->nr_elements);
+ buffer->context_start_slot_nr = cpu_to_be16(device->al_tr_cycle);
mx = min_t(int, AL_CONTEXT_PER_TRANSACTION,
- mdev->act_log->nr_elements - mdev->al_tr_cycle);
+ device->act_log->nr_elements - device->al_tr_cycle);
for (i = 0; i < mx; i++) {
- unsigned idx = mdev->al_tr_cycle + i;
- extent_nr = lc_element_by_index(mdev->act_log, idx)->lc_number;
+ unsigned idx = device->al_tr_cycle + i;
+ extent_nr = lc_element_by_index(device->act_log, idx)->lc_number;
buffer->context[i] = cpu_to_be32(extent_nr);
}
for (; i < AL_CONTEXT_PER_TRANSACTION; i++)
buffer->context[i] = cpu_to_be32(LC_FREE);
- mdev->al_tr_cycle += AL_CONTEXT_PER_TRANSACTION;
- if (mdev->al_tr_cycle >= mdev->act_log->nr_elements)
- mdev->al_tr_cycle = 0;
+ device->al_tr_cycle += AL_CONTEXT_PER_TRANSACTION;
+ if (device->al_tr_cycle >= device->act_log->nr_elements)
+ device->al_tr_cycle = 0;
- sector = al_tr_number_to_on_disk_sector(mdev);
+ sector = al_tr_number_to_on_disk_sector(device);
crc = crc32c(0, buffer, 4096);
buffer->crc32c = cpu_to_be32(crc);
- if (drbd_bm_write_hinted(mdev))
+ if (drbd_bm_write_hinted(device))
err = -EIO;
else {
bool write_al_updates;
rcu_read_lock();
- write_al_updates = rcu_dereference(mdev->ldev->disk_conf)->al_updates;
+ write_al_updates = rcu_dereference(device->ldev->disk_conf)->al_updates;
rcu_read_unlock();
if (write_al_updates) {
- if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) {
+ if (drbd_md_sync_page_io(device, device->ldev, sector, WRITE)) {
err = -EIO;
- drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
+ drbd_chk_io_error(device, 1, DRBD_META_IO_ERROR);
} else {
- mdev->al_tr_number++;
- mdev->al_writ_cnt++;
+ device->al_tr_number++;
+ device->al_writ_cnt++;
}
}
}
- drbd_md_put_buffer(mdev);
- put_ldev(mdev);
+ drbd_md_put_buffer(device);
+ put_ldev(device);
return err;
}
@@ -593,10 +596,10 @@ _al_write_transaction(struct drbd_conf *mdev)
static int w_al_write_transaction(struct drbd_work *w, int unused)
{
struct update_al_work *aw = container_of(w, struct update_al_work, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device = aw->device;
int err;
- err = _al_write_transaction(mdev);
+ err = _al_write_transaction(device);
aw->err = err;
complete(&aw->event);
@@ -606,63 +609,64 @@ static int w_al_write_transaction(struct drbd_work *w, int unused)
/* Calls from worker context (see w_restart_disk_io()) need to write the
transaction directly. Others came through generic_make_request(),
those need to delegate it to the worker. */
-static int al_write_transaction(struct drbd_conf *mdev, bool delegate)
+static int al_write_transaction(struct drbd_device *device, bool delegate)
{
if (delegate) {
struct update_al_work al_work;
init_completion(&al_work.event);
al_work.w.cb = w_al_write_transaction;
- al_work.w.mdev = mdev;
- drbd_queue_work_front(&mdev->tconn->sender_work, &al_work.w);
+ al_work.device = device;
+ drbd_queue_work_front(&first_peer_device(device)->connection->sender_work,
+ &al_work.w);
wait_for_completion(&al_work.event);
return al_work.err;
} else
- return _al_write_transaction(mdev);
+ return _al_write_transaction(device);
}
-static int _try_lc_del(struct drbd_conf *mdev, struct lc_element *al_ext)
+static int _try_lc_del(struct drbd_device *device, struct lc_element *al_ext)
{
int rv;
- spin_lock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
rv = (al_ext->refcnt == 0);
if (likely(rv))
- lc_del(mdev->act_log, al_ext);
- spin_unlock_irq(&mdev->al_lock);
+ lc_del(device->act_log, al_ext);
+ spin_unlock_irq(&device->al_lock);
return rv;
}
/**
* drbd_al_shrink() - Removes all active extents form the activity log
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Removes all active extents form the activity log, waiting until
* the reference count of each entry dropped to 0 first, of course.
*
- * You need to lock mdev->act_log with lc_try_lock() / lc_unlock()
+ * You need to lock device->act_log with lc_try_lock() / lc_unlock()
*/
-void drbd_al_shrink(struct drbd_conf *mdev)
+void drbd_al_shrink(struct drbd_device *device)
{
struct lc_element *al_ext;
int i;
- D_ASSERT(test_bit(__LC_LOCKED, &mdev->act_log->flags));
+ D_ASSERT(device, test_bit(__LC_LOCKED, &device->act_log->flags));
- for (i = 0; i < mdev->act_log->nr_elements; i++) {
- al_ext = lc_element_by_index(mdev->act_log, i);
+ for (i = 0; i < device->act_log->nr_elements; i++) {
+ al_ext = lc_element_by_index(device->act_log, i);
if (al_ext->lc_number == LC_FREE)
continue;
- wait_event(mdev->al_wait, _try_lc_del(mdev, al_ext));
+ wait_event(device->al_wait, _try_lc_del(device, al_ext));
}
- wake_up(&mdev->al_wait);
+ wake_up(&device->al_wait);
}
-int drbd_initialize_al(struct drbd_conf *mdev, void *buffer)
+int drbd_initialize_al(struct drbd_device *device, void *buffer)
{
struct al_transaction_on_disk *al = buffer;
- struct drbd_md *md = &mdev->ldev->md;
+ struct drbd_md *md = &device->ldev->md;
sector_t al_base = md->md_offset + md->al_offset;
int al_size_4k = md->al_stripes * md->al_stripe_size_4k;
int i;
@@ -673,7 +677,7 @@ int drbd_initialize_al(struct drbd_conf *mdev, void *buffer)
al->crc32c = cpu_to_be32(crc32c(0, al, 4096));
for (i = 0; i < al_size_4k; i++) {
- int err = drbd_md_sync_page_io(mdev, mdev->ldev, al_base + i * 8, WRITE);
+ int err = drbd_md_sync_page_io(device, device->ldev, al_base + i * 8, WRITE);
if (err)
return err;
}
@@ -683,32 +687,32 @@ int drbd_initialize_al(struct drbd_conf *mdev, void *buffer)
static int w_update_odbm(struct drbd_work *w, int unused)
{
struct update_odbm_work *udw = container_of(w, struct update_odbm_work, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device = udw->device;
struct sib_info sib = { .sib_reason = SIB_SYNC_PROGRESS, };
- if (!get_ldev(mdev)) {
+ if (!get_ldev(device)) {
if (__ratelimit(&drbd_ratelimit_state))
- dev_warn(DEV, "Can not update on disk bitmap, local IO disabled.\n");
+ drbd_warn(device, "Can not update on disk bitmap, local IO disabled.\n");
kfree(udw);
return 0;
}
- drbd_bm_write_page(mdev, rs_extent_to_bm_page(udw->enr));
- put_ldev(mdev);
+ drbd_bm_write_page(device, rs_extent_to_bm_page(udw->enr));
+ put_ldev(device);
kfree(udw);
- if (drbd_bm_total_weight(mdev) <= mdev->rs_failed) {
- switch (mdev->state.conn) {
+ if (drbd_bm_total_weight(device) <= device->rs_failed) {
+ switch (device->state.conn) {
case C_SYNC_SOURCE: case C_SYNC_TARGET:
case C_PAUSED_SYNC_S: case C_PAUSED_SYNC_T:
- drbd_resync_finished(mdev);
+ drbd_resync_finished(device);
default:
/* nothing to do */
break;
}
}
- drbd_bcast_event(mdev, &sib);
+ drbd_bcast_event(device, &sib);
return 0;
}
@@ -720,7 +724,7 @@ static int w_update_odbm(struct drbd_work *w, int unused)
*
* TODO will be obsoleted once we have a caching lru of the on disk bitmap
*/
-static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
+static void drbd_try_clear_on_disk_bm(struct drbd_device *device, sector_t sector,
int count, int success)
{
struct lc_element *e;
@@ -728,13 +732,13 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
unsigned int enr;
- D_ASSERT(atomic_read(&mdev->local_cnt));
+ D_ASSERT(device, atomic_read(&device->local_cnt));
/* I simply assume that a sector/size pair never crosses
* a 16 MB extent border. (Currently this is true...) */
enr = BM_SECT_TO_EXT(sector);
- e = lc_get(mdev->resync, enr);
+ e = lc_get(device->resync, enr);
if (e) {
struct bm_extent *ext = lc_entry(e, struct bm_extent, lce);
if (ext->lce.lc_number == enr) {
@@ -743,12 +747,12 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
else
ext->rs_failed += count;
if (ext->rs_left < ext->rs_failed) {
- dev_warn(DEV, "BAD! sector=%llus enr=%u rs_left=%d "
+ drbd_warn(device, "BAD! sector=%llus enr=%u rs_left=%d "
"rs_failed=%d count=%d cstate=%s\n",
(unsigned long long)sector,
ext->lce.lc_number, ext->rs_left,
ext->rs_failed, count,
- drbd_conn_str(mdev->state.conn));
+ drbd_conn_str(device->state.conn));
/* We don't expect to be able to clear more bits
* than have been set when we originally counted
@@ -756,7 +760,7 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
* Whatever the reason (disconnect during resync,
* delayed local completion of an application write),
* try to fix it up by recounting here. */
- ext->rs_left = drbd_bm_e_weight(mdev, enr);
+ ext->rs_left = drbd_bm_e_weight(device, enr);
}
} else {
/* Normally this element should be in the cache,
@@ -765,16 +769,16 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
* But maybe an application write finished, and we set
* something outside the resync lru_cache in sync.
*/
- int rs_left = drbd_bm_e_weight(mdev, enr);
+ int rs_left = drbd_bm_e_weight(device, enr);
if (ext->flags != 0) {
- dev_warn(DEV, "changing resync lce: %d[%u;%02lx]"
+ drbd_warn(device, "changing resync lce: %d[%u;%02lx]"
" -> %d[%u;00]\n",
ext->lce.lc_number, ext->rs_left,
ext->flags, enr, rs_left);
ext->flags = 0;
}
if (ext->rs_failed) {
- dev_warn(DEV, "Kicking resync_lru element enr=%u "
+ drbd_warn(device, "Kicking resync_lru element enr=%u "
"out with rs_failed=%d\n",
ext->lce.lc_number, ext->rs_failed);
}
@@ -782,9 +786,9 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
ext->rs_failed = success ? 0 : count;
/* we don't keep a persistent log of the resync lru,
* we can commit any change right away. */
- lc_committed(mdev->resync);
+ lc_committed(device->resync);
}
- lc_put(mdev->resync, &ext->lce);
+ lc_put(device->resync, &ext->lce);
/* no race, we are within the al_lock! */
if (ext->rs_left == ext->rs_failed) {
@@ -794,32 +798,33 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
if (udw) {
udw->enr = ext->lce.lc_number;
udw->w.cb = w_update_odbm;
- udw->w.mdev = mdev;
- drbd_queue_work_front(&mdev->tconn->sender_work, &udw->w);
+ udw->device = device;
+ drbd_queue_work_front(&first_peer_device(device)->connection->sender_work,
+ &udw->w);
} else {
- dev_warn(DEV, "Could not kmalloc an udw\n");
+ drbd_warn(device, "Could not kmalloc an udw\n");
}
}
} else {
- dev_err(DEV, "lc_get() failed! locked=%d/%d flags=%lu\n",
- mdev->resync_locked,
- mdev->resync->nr_elements,
- mdev->resync->flags);
+ drbd_err(device, "lc_get() failed! locked=%d/%d flags=%lu\n",
+ device->resync_locked,
+ device->resync->nr_elements,
+ device->resync->flags);
}
}
-void drbd_advance_rs_marks(struct drbd_conf *mdev, unsigned long still_to_go)
+void drbd_advance_rs_marks(struct drbd_device *device, unsigned long still_to_go)
{
unsigned long now = jiffies;
- unsigned long last = mdev->rs_mark_time[mdev->rs_last_mark];
- int next = (mdev->rs_last_mark + 1) % DRBD_SYNC_MARKS;
+ unsigned long last = device->rs_mark_time[device->rs_last_mark];
+ int next = (device->rs_last_mark + 1) % DRBD_SYNC_MARKS;
if (time_after_eq(now, last + DRBD_SYNC_MARK_STEP)) {
- if (mdev->rs_mark_left[mdev->rs_last_mark] != still_to_go &&
- mdev->state.conn != C_PAUSED_SYNC_T &&
- mdev->state.conn != C_PAUSED_SYNC_S) {
- mdev->rs_mark_time[next] = now;
- mdev->rs_mark_left[next] = still_to_go;
- mdev->rs_last_mark = next;
+ if (device->rs_mark_left[device->rs_last_mark] != still_to_go &&
+ device->state.conn != C_PAUSED_SYNC_T &&
+ device->state.conn != C_PAUSED_SYNC_S) {
+ device->rs_mark_time[next] = now;
+ device->rs_mark_left[next] = still_to_go;
+ device->rs_last_mark = next;
}
}
}
@@ -831,7 +836,7 @@ void drbd_advance_rs_marks(struct drbd_conf *mdev, unsigned long still_to_go)
* called by worker on C_SYNC_TARGET and receiver on SyncSource.
*
*/
-void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size,
+void __drbd_set_in_sync(struct drbd_device *device, sector_t sector, int size,
const char *file, const unsigned int line)
{
/* Is called from worker and receiver context _only_ */
@@ -842,15 +847,15 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size,
unsigned long flags;
if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) {
- dev_err(DEV, "drbd_set_in_sync: sector=%llus size=%d nonsense!\n",
+ drbd_err(device, "drbd_set_in_sync: sector=%llus size=%d nonsense!\n",
(unsigned long long)sector, size);
return;
}
- if (!get_ldev(mdev))
+ if (!get_ldev(device))
return; /* no disk, no metadata, no bitmap to clear bits in */
- nr_sectors = drbd_get_capacity(mdev->this_bdev);
+ nr_sectors = drbd_get_capacity(device->this_bdev);
esector = sector + (size >> 9) - 1;
if (!expect(sector < nr_sectors))
@@ -878,21 +883,21 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size,
* ok, (capacity & 7) != 0 sometimes, but who cares...
* we count rs_{total,left} in bits, not sectors.
*/
- count = drbd_bm_clear_bits(mdev, sbnr, ebnr);
+ count = drbd_bm_clear_bits(device, sbnr, ebnr);
if (count) {
- drbd_advance_rs_marks(mdev, drbd_bm_total_weight(mdev));
- spin_lock_irqsave(&mdev->al_lock, flags);
- drbd_try_clear_on_disk_bm(mdev, sector, count, true);
- spin_unlock_irqrestore(&mdev->al_lock, flags);
+ drbd_advance_rs_marks(device, drbd_bm_total_weight(device));
+ spin_lock_irqsave(&device->al_lock, flags);
+ drbd_try_clear_on_disk_bm(device, sector, count, true);
+ spin_unlock_irqrestore(&device->al_lock, flags);
/* just wake_up unconditional now, various lc_chaged(),
* lc_put() in drbd_try_clear_on_disk_bm(). */
wake_up = 1;
}
out:
- put_ldev(mdev);
+ put_ldev(device);
if (wake_up)
- wake_up(&mdev->al_wait);
+ wake_up(&device->al_wait);
}
/*
@@ -903,7 +908,7 @@ out:
* called by tl_clear and drbd_send_dblock (==drbd_make_request).
* so this can be _any_ process.
*/
-int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size,
+int __drbd_set_out_of_sync(struct drbd_device *device, sector_t sector, int size,
const char *file, const unsigned int line)
{
unsigned long sbnr, ebnr, flags;
@@ -916,15 +921,15 @@ int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size,
return 0;
if (size < 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) {
- dev_err(DEV, "sector: %llus, size: %d\n",
+ drbd_err(device, "sector: %llus, size: %d\n",
(unsigned long long)sector, size);
return 0;
}
- if (!get_ldev(mdev))
+ if (!get_ldev(device))
return 0; /* no disk, no metadata, no bitmap to set bits in */
- nr_sectors = drbd_get_capacity(mdev->this_bdev);
+ nr_sectors = drbd_get_capacity(device->this_bdev);
esector = sector + (size >> 9) - 1;
if (!expect(sector < nr_sectors))
@@ -939,55 +944,55 @@ int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size,
/* ok, (capacity & 7) != 0 sometimes, but who cares...
* we count rs_{total,left} in bits, not sectors. */
- spin_lock_irqsave(&mdev->al_lock, flags);
- count = drbd_bm_set_bits(mdev, sbnr, ebnr);
+ spin_lock_irqsave(&device->al_lock, flags);
+ count = drbd_bm_set_bits(device, sbnr, ebnr);
enr = BM_SECT_TO_EXT(sector);
- e = lc_find(mdev->resync, enr);
+ e = lc_find(device->resync, enr);
if (e)
lc_entry(e, struct bm_extent, lce)->rs_left += count;
- spin_unlock_irqrestore(&mdev->al_lock, flags);
+ spin_unlock_irqrestore(&device->al_lock, flags);
out:
- put_ldev(mdev);
+ put_ldev(device);
return count;
}
static
-struct bm_extent *_bme_get(struct drbd_conf *mdev, unsigned int enr)
+struct bm_extent *_bme_get(struct drbd_device *device, unsigned int enr)
{
struct lc_element *e;
struct bm_extent *bm_ext;
int wakeup = 0;
unsigned long rs_flags;
- spin_lock_irq(&mdev->al_lock);
- if (mdev->resync_locked > mdev->resync->nr_elements/2) {
- spin_unlock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
+ if (device->resync_locked > device->resync->nr_elements/2) {
+ spin_unlock_irq(&device->al_lock);
return NULL;
}
- e = lc_get(mdev->resync, enr);
+ e = lc_get(device->resync, enr);
bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
if (bm_ext) {
if (bm_ext->lce.lc_number != enr) {
- bm_ext->rs_left = drbd_bm_e_weight(mdev, enr);
+ bm_ext->rs_left = drbd_bm_e_weight(device, enr);
bm_ext->rs_failed = 0;
- lc_committed(mdev->resync);
+ lc_committed(device->resync);
wakeup = 1;
}
if (bm_ext->lce.refcnt == 1)
- mdev->resync_locked++;
+ device->resync_locked++;
set_bit(BME_NO_WRITES, &bm_ext->flags);
}
- rs_flags = mdev->resync->flags;
- spin_unlock_irq(&mdev->al_lock);
+ rs_flags = device->resync->flags;
+ spin_unlock_irq(&device->al_lock);
if (wakeup)
- wake_up(&mdev->al_wait);
+ wake_up(&device->al_wait);
if (!bm_ext) {
if (rs_flags & LC_STARVING)
- dev_warn(DEV, "Have to wait for element"
+ drbd_warn(device, "Have to wait for element"
" (resync LRU too small?)\n");
BUG_ON(rs_flags & LC_LOCKED);
}
@@ -995,25 +1000,25 @@ struct bm_extent *_bme_get(struct drbd_conf *mdev, unsigned int enr)
return bm_ext;
}
-static int _is_in_al(struct drbd_conf *mdev, unsigned int enr)
+static int _is_in_al(struct drbd_device *device, unsigned int enr)
{
int rv;
- spin_lock_irq(&mdev->al_lock);
- rv = lc_is_used(mdev->act_log, enr);
- spin_unlock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
+ rv = lc_is_used(device->act_log, enr);
+ spin_unlock_irq(&device->al_lock);
return rv;
}
/**
* drbd_rs_begin_io() - Gets an extent in the resync LRU cache and sets it to BME_LOCKED
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @sector: The sector number.
*
* This functions sleeps on al_wait. Returns 0 on success, -EINTR if interrupted.
*/
-int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
+int drbd_rs_begin_io(struct drbd_device *device, sector_t sector)
{
unsigned int enr = BM_SECT_TO_EXT(sector);
struct bm_extent *bm_ext;
@@ -1022,8 +1027,8 @@ int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
200 times -> 20 seconds. */
retry:
- sig = wait_event_interruptible(mdev->al_wait,
- (bm_ext = _bme_get(mdev, enr)));
+ sig = wait_event_interruptible(device->al_wait,
+ (bm_ext = _bme_get(device, enr)));
if (sig)
return -EINTR;
@@ -1031,24 +1036,24 @@ retry:
return 0;
for (i = 0; i < AL_EXT_PER_BM_SECT; i++) {
- sig = wait_event_interruptible(mdev->al_wait,
- !_is_in_al(mdev, enr * AL_EXT_PER_BM_SECT + i) ||
+ sig = wait_event_interruptible(device->al_wait,
+ !_is_in_al(device, enr * AL_EXT_PER_BM_SECT + i) ||
test_bit(BME_PRIORITY, &bm_ext->flags));
if (sig || (test_bit(BME_PRIORITY, &bm_ext->flags) && sa)) {
- spin_lock_irq(&mdev->al_lock);
- if (lc_put(mdev->resync, &bm_ext->lce) == 0) {
+ spin_lock_irq(&device->al_lock);
+ if (lc_put(device->resync, &bm_ext->lce) == 0) {
bm_ext->flags = 0; /* clears BME_NO_WRITES and eventually BME_PRIORITY */
- mdev->resync_locked--;
- wake_up(&mdev->al_wait);
+ device->resync_locked--;
+ wake_up(&device->al_wait);
}
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
if (sig)
return -EINTR;
if (schedule_timeout_interruptible(HZ/10))
return -EINTR;
if (sa && --sa == 0)
- dev_warn(DEV,"drbd_rs_begin_io() stepped aside for 20sec."
+ drbd_warn(device, "drbd_rs_begin_io() stepped aside for 20sec."
"Resync stalled?\n");
goto retry;
}
@@ -1059,14 +1064,14 @@ retry:
/**
* drbd_try_rs_begin_io() - Gets an extent in the resync LRU cache, does not sleep
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @sector: The sector number.
*
* Gets an extent in the resync LRU cache, sets it to BME_NO_WRITES, then
* tries to set it to BME_LOCKED. Returns 0 upon success, and -EAGAIN
* if there is still application IO going on in this area.
*/
-int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
+int drbd_try_rs_begin_io(struct drbd_device *device, sector_t sector)
{
unsigned int enr = BM_SECT_TO_EXT(sector);
const unsigned int al_enr = enr*AL_EXT_PER_BM_SECT;
@@ -1074,8 +1079,8 @@ int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
struct bm_extent *bm_ext;
int i;
- spin_lock_irq(&mdev->al_lock);
- if (mdev->resync_wenr != LC_FREE && mdev->resync_wenr != enr) {
+ spin_lock_irq(&device->al_lock);
+ if (device->resync_wenr != LC_FREE && device->resync_wenr != enr) {
/* in case you have very heavy scattered io, it may
* stall the syncer undefined if we give up the ref count
* when we try again and requeue.
@@ -1089,193 +1094,193 @@ int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
* the lc_put here...
* we also have to wake_up
*/
- e = lc_find(mdev->resync, mdev->resync_wenr);
+ e = lc_find(device->resync, device->resync_wenr);
bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
if (bm_ext) {
- D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags));
- D_ASSERT(test_bit(BME_NO_WRITES, &bm_ext->flags));
+ D_ASSERT(device, !test_bit(BME_LOCKED, &bm_ext->flags));
+ D_ASSERT(device, test_bit(BME_NO_WRITES, &bm_ext->flags));
clear_bit(BME_NO_WRITES, &bm_ext->flags);
- mdev->resync_wenr = LC_FREE;
- if (lc_put(mdev->resync, &bm_ext->lce) == 0)
- mdev->resync_locked--;
- wake_up(&mdev->al_wait);
+ device->resync_wenr = LC_FREE;
+ if (lc_put(device->resync, &bm_ext->lce) == 0)
+ device->resync_locked--;
+ wake_up(&device->al_wait);
} else {
- dev_alert(DEV, "LOGIC BUG\n");
+ drbd_alert(device, "LOGIC BUG\n");
}
}
/* TRY. */
- e = lc_try_get(mdev->resync, enr);
+ e = lc_try_get(device->resync, enr);
bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
if (bm_ext) {
if (test_bit(BME_LOCKED, &bm_ext->flags))
goto proceed;
if (!test_and_set_bit(BME_NO_WRITES, &bm_ext->flags)) {
- mdev->resync_locked++;
+ device->resync_locked++;
} else {
/* we did set the BME_NO_WRITES,
* but then could not set BME_LOCKED,
* so we tried again.
* drop the extra reference. */
bm_ext->lce.refcnt--;
- D_ASSERT(bm_ext->lce.refcnt > 0);
+ D_ASSERT(device, bm_ext->lce.refcnt > 0);
}
goto check_al;
} else {
/* do we rather want to try later? */
- if (mdev->resync_locked > mdev->resync->nr_elements-3)
+ if (device->resync_locked > device->resync->nr_elements-3)
goto try_again;
/* Do or do not. There is no try. -- Yoda */
- e = lc_get(mdev->resync, enr);
+ e = lc_get(device->resync, enr);
bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
if (!bm_ext) {
- const unsigned long rs_flags = mdev->resync->flags;
+ const unsigned long rs_flags = device->resync->flags;
if (rs_flags & LC_STARVING)
- dev_warn(DEV, "Have to wait for element"
+ drbd_warn(device, "Have to wait for element"
" (resync LRU too small?)\n");
BUG_ON(rs_flags & LC_LOCKED);
goto try_again;
}
if (bm_ext->lce.lc_number != enr) {
- bm_ext->rs_left = drbd_bm_e_weight(mdev, enr);
+ bm_ext->rs_left = drbd_bm_e_weight(device, enr);
bm_ext->rs_failed = 0;
- lc_committed(mdev->resync);
- wake_up(&mdev->al_wait);
- D_ASSERT(test_bit(BME_LOCKED, &bm_ext->flags) == 0);
+ lc_committed(device->resync);
+ wake_up(&device->al_wait);
+ D_ASSERT(device, test_bit(BME_LOCKED, &bm_ext->flags) == 0);
}
set_bit(BME_NO_WRITES, &bm_ext->flags);
- D_ASSERT(bm_ext->lce.refcnt == 1);
- mdev->resync_locked++;
+ D_ASSERT(device, bm_ext->lce.refcnt == 1);
+ device->resync_locked++;
goto check_al;
}
check_al:
for (i = 0; i < AL_EXT_PER_BM_SECT; i++) {
- if (lc_is_used(mdev->act_log, al_enr+i))
+ if (lc_is_used(device->act_log, al_enr+i))
goto try_again;
}
set_bit(BME_LOCKED, &bm_ext->flags);
proceed:
- mdev->resync_wenr = LC_FREE;
- spin_unlock_irq(&mdev->al_lock);
+ device->resync_wenr = LC_FREE;
+ spin_unlock_irq(&device->al_lock);
return 0;
try_again:
if (bm_ext)
- mdev->resync_wenr = enr;
- spin_unlock_irq(&mdev->al_lock);
+ device->resync_wenr = enr;
+ spin_unlock_irq(&device->al_lock);
return -EAGAIN;
}
-void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector)
+void drbd_rs_complete_io(struct drbd_device *device, sector_t sector)
{
unsigned int enr = BM_SECT_TO_EXT(sector);
struct lc_element *e;
struct bm_extent *bm_ext;
unsigned long flags;
- spin_lock_irqsave(&mdev->al_lock, flags);
- e = lc_find(mdev->resync, enr);
+ spin_lock_irqsave(&device->al_lock, flags);
+ e = lc_find(device->resync, enr);
bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
if (!bm_ext) {
- spin_unlock_irqrestore(&mdev->al_lock, flags);
+ spin_unlock_irqrestore(&device->al_lock, flags);
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "drbd_rs_complete_io() called, but extent not found\n");
+ drbd_err(device, "drbd_rs_complete_io() called, but extent not found\n");
return;
}
if (bm_ext->lce.refcnt == 0) {
- spin_unlock_irqrestore(&mdev->al_lock, flags);
- dev_err(DEV, "drbd_rs_complete_io(,%llu [=%u]) called, "
+ spin_unlock_irqrestore(&device->al_lock, flags);
+ drbd_err(device, "drbd_rs_complete_io(,%llu [=%u]) called, "
"but refcnt is 0!?\n",
(unsigned long long)sector, enr);
return;
}
- if (lc_put(mdev->resync, &bm_ext->lce) == 0) {
+ if (lc_put(device->resync, &bm_ext->lce) == 0) {
bm_ext->flags = 0; /* clear BME_LOCKED, BME_NO_WRITES and BME_PRIORITY */
- mdev->resync_locked--;
- wake_up(&mdev->al_wait);
+ device->resync_locked--;
+ wake_up(&device->al_wait);
}
- spin_unlock_irqrestore(&mdev->al_lock, flags);
+ spin_unlock_irqrestore(&device->al_lock, flags);
}
/**
* drbd_rs_cancel_all() - Removes all extents from the resync LRU (even BME_LOCKED)
- * @mdev: DRBD device.
+ * @device: DRBD device.
*/
-void drbd_rs_cancel_all(struct drbd_conf *mdev)
+void drbd_rs_cancel_all(struct drbd_device *device)
{
- spin_lock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
- if (get_ldev_if_state(mdev, D_FAILED)) { /* Makes sure ->resync is there. */
- lc_reset(mdev->resync);
- put_ldev(mdev);
+ if (get_ldev_if_state(device, D_FAILED)) { /* Makes sure ->resync is there. */
+ lc_reset(device->resync);
+ put_ldev(device);
}
- mdev->resync_locked = 0;
- mdev->resync_wenr = LC_FREE;
- spin_unlock_irq(&mdev->al_lock);
- wake_up(&mdev->al_wait);
+ device->resync_locked = 0;
+ device->resync_wenr = LC_FREE;
+ spin_unlock_irq(&device->al_lock);
+ wake_up(&device->al_wait);
}
/**
* drbd_rs_del_all() - Gracefully remove all extents from the resync LRU
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Returns 0 upon success, -EAGAIN if at least one reference count was
* not zero.
*/
-int drbd_rs_del_all(struct drbd_conf *mdev)
+int drbd_rs_del_all(struct drbd_device *device)
{
struct lc_element *e;
struct bm_extent *bm_ext;
int i;
- spin_lock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
- if (get_ldev_if_state(mdev, D_FAILED)) {
+ if (get_ldev_if_state(device, D_FAILED)) {
/* ok, ->resync is there. */
- for (i = 0; i < mdev->resync->nr_elements; i++) {
- e = lc_element_by_index(mdev->resync, i);
+ for (i = 0; i < device->resync->nr_elements; i++) {
+ e = lc_element_by_index(device->resync, i);
bm_ext = lc_entry(e, struct bm_extent, lce);
if (bm_ext->lce.lc_number == LC_FREE)
continue;
- if (bm_ext->lce.lc_number == mdev->resync_wenr) {
- dev_info(DEV, "dropping %u in drbd_rs_del_all, apparently"
+ if (bm_ext->lce.lc_number == device->resync_wenr) {
+ drbd_info(device, "dropping %u in drbd_rs_del_all, apparently"
" got 'synced' by application io\n",
- mdev->resync_wenr);
- D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags));
- D_ASSERT(test_bit(BME_NO_WRITES, &bm_ext->flags));
+ device->resync_wenr);
+ D_ASSERT(device, !test_bit(BME_LOCKED, &bm_ext->flags));
+ D_ASSERT(device, test_bit(BME_NO_WRITES, &bm_ext->flags));
clear_bit(BME_NO_WRITES, &bm_ext->flags);
- mdev->resync_wenr = LC_FREE;
- lc_put(mdev->resync, &bm_ext->lce);
+ device->resync_wenr = LC_FREE;
+ lc_put(device->resync, &bm_ext->lce);
}
if (bm_ext->lce.refcnt != 0) {
- dev_info(DEV, "Retrying drbd_rs_del_all() later. "
+ drbd_info(device, "Retrying drbd_rs_del_all() later. "
"refcnt=%d\n", bm_ext->lce.refcnt);
- put_ldev(mdev);
- spin_unlock_irq(&mdev->al_lock);
+ put_ldev(device);
+ spin_unlock_irq(&device->al_lock);
return -EAGAIN;
}
- D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags));
- D_ASSERT(!test_bit(BME_NO_WRITES, &bm_ext->flags));
- lc_del(mdev->resync, &bm_ext->lce);
+ D_ASSERT(device, !test_bit(BME_LOCKED, &bm_ext->flags));
+ D_ASSERT(device, !test_bit(BME_NO_WRITES, &bm_ext->flags));
+ lc_del(device->resync, &bm_ext->lce);
}
- D_ASSERT(mdev->resync->used == 0);
- put_ldev(mdev);
+ D_ASSERT(device, device->resync->used == 0);
+ put_ldev(device);
}
- spin_unlock_irq(&mdev->al_lock);
- wake_up(&mdev->al_wait);
+ spin_unlock_irq(&device->al_lock);
+ wake_up(&device->al_wait);
return 0;
}
/**
* drbd_rs_failed_io() - Record information on a failure to resync the specified blocks
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @sector: The sector number.
* @size: Size of failed IO operation, in byte.
*/
-void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size)
+void drbd_rs_failed_io(struct drbd_device *device, sector_t sector, int size)
{
/* Is called from worker and receiver context _only_ */
unsigned long sbnr, ebnr, lbnr;
@@ -1284,11 +1289,11 @@ void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size)
int wake_up = 0;
if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) {
- dev_err(DEV, "drbd_rs_failed_io: sector=%llus size=%d nonsense!\n",
+ drbd_err(device, "drbd_rs_failed_io: sector=%llus size=%d nonsense!\n",
(unsigned long long)sector, size);
return;
}
- nr_sectors = drbd_get_capacity(mdev->this_bdev);
+ nr_sectors = drbd_get_capacity(device->this_bdev);
esector = sector + (size >> 9) - 1;
if (!expect(sector < nr_sectors))
@@ -1316,21 +1321,21 @@ void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size)
* ok, (capacity & 7) != 0 sometimes, but who cares...
* we count rs_{total,left} in bits, not sectors.
*/
- spin_lock_irq(&mdev->al_lock);
- count = drbd_bm_count_bits(mdev, sbnr, ebnr);
+ spin_lock_irq(&device->al_lock);
+ count = drbd_bm_count_bits(device, sbnr, ebnr);
if (count) {
- mdev->rs_failed += count;
+ device->rs_failed += count;
- if (get_ldev(mdev)) {
- drbd_try_clear_on_disk_bm(mdev, sector, count, false);
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ drbd_try_clear_on_disk_bm(device, sector, count, false);
+ put_ldev(device);
}
/* just wake_up unconditional now, various lc_chaged(),
* lc_put() in drbd_try_clear_on_disk_bm(). */
wake_up = 1;
}
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
if (wake_up)
- wake_up(&mdev->al_wait);
+ wake_up(&device->al_wait);
}
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
index 597f111df67b..1aa29f8fdfe1 100644
--- a/drivers/block/drbd/drbd_bitmap.c
+++ b/drivers/block/drbd/drbd_bitmap.c
@@ -113,54 +113,54 @@ struct drbd_bitmap {
};
#define bm_print_lock_info(m) __bm_print_lock_info(m, __func__)
-static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func)
+static void __bm_print_lock_info(struct drbd_device *device, const char *func)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
if (!__ratelimit(&drbd_ratelimit_state))
return;
- dev_err(DEV, "FIXME %s in %s, bitmap locked for '%s' by %s\n",
- drbd_task_to_thread_name(mdev->tconn, current),
- func, b->bm_why ?: "?",
- drbd_task_to_thread_name(mdev->tconn, b->bm_task));
+ drbd_err(device, "FIXME %s[%d] in %s, bitmap locked for '%s' by %s[%d]\n",
+ current->comm, task_pid_nr(current),
+ func, b->bm_why ?: "?",
+ b->bm_task->comm, task_pid_nr(b->bm_task));
}
-void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags)
+void drbd_bm_lock(struct drbd_device *device, char *why, enum bm_flag flags)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
int trylock_failed;
if (!b) {
- dev_err(DEV, "FIXME no bitmap in drbd_bm_lock!?\n");
+ drbd_err(device, "FIXME no bitmap in drbd_bm_lock!?\n");
return;
}
trylock_failed = !mutex_trylock(&b->bm_change);
if (trylock_failed) {
- dev_warn(DEV, "%s going to '%s' but bitmap already locked for '%s' by %s\n",
- drbd_task_to_thread_name(mdev->tconn, current),
- why, b->bm_why ?: "?",
- drbd_task_to_thread_name(mdev->tconn, b->bm_task));
+ drbd_warn(device, "%s[%d] going to '%s' but bitmap already locked for '%s' by %s[%d]\n",
+ current->comm, task_pid_nr(current),
+ why, b->bm_why ?: "?",
+ b->bm_task->comm, task_pid_nr(b->bm_task));
mutex_lock(&b->bm_change);
}
if (BM_LOCKED_MASK & b->bm_flags)
- dev_err(DEV, "FIXME bitmap already locked in bm_lock\n");
+ drbd_err(device, "FIXME bitmap already locked in bm_lock\n");
b->bm_flags |= flags & BM_LOCKED_MASK;
b->bm_why = why;
b->bm_task = current;
}
-void drbd_bm_unlock(struct drbd_conf *mdev)
+void drbd_bm_unlock(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
if (!b) {
- dev_err(DEV, "FIXME no bitmap in drbd_bm_unlock!?\n");
+ drbd_err(device, "FIXME no bitmap in drbd_bm_unlock!?\n");
return;
}
- if (!(BM_LOCKED_MASK & mdev->bitmap->bm_flags))
- dev_err(DEV, "FIXME bitmap not locked in bm_unlock\n");
+ if (!(BM_LOCKED_MASK & device->bitmap->bm_flags))
+ drbd_err(device, "FIXME bitmap not locked in bm_unlock\n");
b->bm_flags &= ~BM_LOCKED_MASK;
b->bm_why = NULL;
@@ -211,19 +211,19 @@ static unsigned long bm_page_to_idx(struct page *page)
/* As is very unlikely that the same page is under IO from more than one
* context, we can get away with a bit per page and one wait queue per bitmap.
*/
-static void bm_page_lock_io(struct drbd_conf *mdev, int page_nr)
+static void bm_page_lock_io(struct drbd_device *device, int page_nr)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
void *addr = &page_private(b->bm_pages[page_nr]);
wait_event(b->bm_io_wait, !test_and_set_bit(BM_PAGE_IO_LOCK, addr));
}
-static void bm_page_unlock_io(struct drbd_conf *mdev, int page_nr)
+static void bm_page_unlock_io(struct drbd_device *device, int page_nr)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
void *addr = &page_private(b->bm_pages[page_nr]);
clear_bit_unlock(BM_PAGE_IO_LOCK, addr);
- wake_up(&mdev->bitmap->bm_io_wait);
+ wake_up(&device->bitmap->bm_io_wait);
}
/* set _before_ submit_io, so it may be reset due to being changed
@@ -242,22 +242,22 @@ static void bm_set_page_need_writeout(struct page *page)
/**
* drbd_bm_mark_for_writeout() - mark a page with a "hint" to be considered for writeout
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @page_nr: the bitmap page to mark with the "hint" flag
*
* From within an activity log transaction, we mark a few pages with these
* hints, then call drbd_bm_write_hinted(), which will only write out changed
* pages which are flagged with this mark.
*/
-void drbd_bm_mark_for_writeout(struct drbd_conf *mdev, int page_nr)
+void drbd_bm_mark_for_writeout(struct drbd_device *device, int page_nr)
{
struct page *page;
- if (page_nr >= mdev->bitmap->bm_number_of_pages) {
- dev_warn(DEV, "BAD: page_nr: %u, number_of_pages: %u\n",
- page_nr, (int)mdev->bitmap->bm_number_of_pages);
+ if (page_nr >= device->bitmap->bm_number_of_pages) {
+ drbd_warn(device, "BAD: page_nr: %u, number_of_pages: %u\n",
+ page_nr, (int)device->bitmap->bm_number_of_pages);
return;
}
- page = mdev->bitmap->bm_pages[page_nr];
+ page = device->bitmap->bm_pages[page_nr];
set_bit(BM_PAGE_HINT_WRITEOUT, &page_private(page));
}
@@ -340,7 +340,7 @@ static void bm_unmap(unsigned long *p_addr)
/*
* actually most functions herein should take a struct drbd_bitmap*, not a
- * struct drbd_conf*, but for the debug macros I like to have the mdev around
+ * struct drbd_device*, but for the debug macros I like to have the device around
* to be able to report device specific.
*/
@@ -436,11 +436,11 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want)
/*
* called on driver init only. TODO call when a device is created.
- * allocates the drbd_bitmap, and stores it in mdev->bitmap.
+ * allocates the drbd_bitmap, and stores it in device->bitmap.
*/
-int drbd_bm_init(struct drbd_conf *mdev)
+int drbd_bm_init(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
WARN_ON(b != NULL);
b = kzalloc(sizeof(struct drbd_bitmap), GFP_KERNEL);
if (!b)
@@ -449,28 +449,28 @@ int drbd_bm_init(struct drbd_conf *mdev)
mutex_init(&b->bm_change);
init_waitqueue_head(&b->bm_io_wait);
- mdev->bitmap = b;
+ device->bitmap = b;
return 0;
}
-sector_t drbd_bm_capacity(struct drbd_conf *mdev)
+sector_t drbd_bm_capacity(struct drbd_device *device)
{
- if (!expect(mdev->bitmap))
+ if (!expect(device->bitmap))
return 0;
- return mdev->bitmap->bm_dev_capacity;
+ return device->bitmap->bm_dev_capacity;
}
/* called on driver unload. TODO: call when a device is destroyed.
*/
-void drbd_bm_cleanup(struct drbd_conf *mdev)
+void drbd_bm_cleanup(struct drbd_device *device)
{
- if (!expect(mdev->bitmap))
+ if (!expect(device->bitmap))
return;
- bm_free_pages(mdev->bitmap->bm_pages, mdev->bitmap->bm_number_of_pages);
- bm_vk_free(mdev->bitmap->bm_pages, (BM_P_VMALLOCED & mdev->bitmap->bm_flags));
- kfree(mdev->bitmap);
- mdev->bitmap = NULL;
+ bm_free_pages(device->bitmap->bm_pages, device->bitmap->bm_number_of_pages);
+ bm_vk_free(device->bitmap->bm_pages, (BM_P_VMALLOCED & device->bitmap->bm_flags));
+ kfree(device->bitmap);
+ device->bitmap = NULL;
}
/*
@@ -631,9 +631,9 @@ static u64 drbd_md_on_disk_bits(struct drbd_backing_dev *ldev)
* In case this is actually a resize, we copy the old bitmap into the new one.
* Otherwise, the bitmap is initialized to all bits set.
*/
-int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
+int drbd_bm_resize(struct drbd_device *device, sector_t capacity, int set_new_bits)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long bits, words, owords, obits;
unsigned long want, have, onpages; /* number of pages */
struct page **npages, **opages = NULL;
@@ -643,9 +643,9 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
if (!expect(b))
return -ENOMEM;
- drbd_bm_lock(mdev, "resize", BM_LOCKED_MASK);
+ drbd_bm_lock(device, "resize", BM_LOCKED_MASK);
- dev_info(DEV, "drbd_bm_resize called with capacity == %llu\n",
+ drbd_info(device, "drbd_bm_resize called with capacity == %llu\n",
(unsigned long long)capacity);
if (capacity == b->bm_dev_capacity)
@@ -678,12 +678,12 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
*/
words = ALIGN(bits, 64) >> LN2_BPL;
- if (get_ldev(mdev)) {
- u64 bits_on_disk = drbd_md_on_disk_bits(mdev->ldev);
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ u64 bits_on_disk = drbd_md_on_disk_bits(device->ldev);
+ put_ldev(device);
if (bits > bits_on_disk) {
- dev_info(DEV, "bits = %lu\n", bits);
- dev_info(DEV, "bits_on_disk = %llu\n", bits_on_disk);
+ drbd_info(device, "bits = %lu\n", bits);
+ drbd_info(device, "bits_on_disk = %llu\n", bits_on_disk);
err = -ENOSPC;
goto out;
}
@@ -692,10 +692,10 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
want = ALIGN(words*sizeof(long), PAGE_SIZE) >> PAGE_SHIFT;
have = b->bm_number_of_pages;
if (want == have) {
- D_ASSERT(b->bm_pages != NULL);
+ D_ASSERT(device, b->bm_pages != NULL);
npages = b->bm_pages;
} else {
- if (drbd_insert_fault(mdev, DRBD_FAULT_BM_ALLOC))
+ if (drbd_insert_fault(device, DRBD_FAULT_BM_ALLOC))
npages = NULL;
else
npages = bm_realloc_pages(b, want);
@@ -742,10 +742,10 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
bm_vk_free(opages, opages_vmalloced);
if (!growing)
b->bm_set = bm_count_bits(b);
- dev_info(DEV, "resync bitmap: bits=%lu words=%lu pages=%lu\n", bits, words, want);
+ drbd_info(device, "resync bitmap: bits=%lu words=%lu pages=%lu\n", bits, words, want);
out:
- drbd_bm_unlock(mdev);
+ drbd_bm_unlock(device);
return err;
}
@@ -757,9 +757,9 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits)
*
* maybe bm_set should be atomic_t ?
*/
-unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev)
+unsigned long _drbd_bm_total_weight(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long s;
unsigned long flags;
@@ -775,20 +775,20 @@ unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev)
return s;
}
-unsigned long drbd_bm_total_weight(struct drbd_conf *mdev)
+unsigned long drbd_bm_total_weight(struct drbd_device *device)
{
unsigned long s;
/* if I don't have a disk, I don't know about out-of-sync status */
- if (!get_ldev_if_state(mdev, D_NEGOTIATING))
+ if (!get_ldev_if_state(device, D_NEGOTIATING))
return 0;
- s = _drbd_bm_total_weight(mdev);
- put_ldev(mdev);
+ s = _drbd_bm_total_weight(device);
+ put_ldev(device);
return s;
}
-size_t drbd_bm_words(struct drbd_conf *mdev)
+size_t drbd_bm_words(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
if (!expect(b))
return 0;
if (!expect(b->bm_pages))
@@ -797,9 +797,9 @@ size_t drbd_bm_words(struct drbd_conf *mdev)
return b->bm_words;
}
-unsigned long drbd_bm_bits(struct drbd_conf *mdev)
+unsigned long drbd_bm_bits(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
if (!expect(b))
return 0;
@@ -811,10 +811,10 @@ unsigned long drbd_bm_bits(struct drbd_conf *mdev)
* bitmap must be locked by drbd_bm_lock.
* currently only used from receive_bitmap.
*/
-void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number,
+void drbd_bm_merge_lel(struct drbd_device *device, size_t offset, size_t number,
unsigned long *buffer)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long *p_addr, *bm;
unsigned long word, bits;
unsigned int idx;
@@ -860,10 +860,10 @@ void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number,
/* copy number words from the bitmap starting at offset into the buffer.
* buffer[i] will be little endian unsigned long.
*/
-void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number,
+void drbd_bm_get_lel(struct drbd_device *device, size_t offset, size_t number,
unsigned long *buffer)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long *p_addr, *bm;
size_t end, do_now;
@@ -878,7 +878,7 @@ void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number,
if ((offset >= b->bm_words) ||
(end > b->bm_words) ||
(number <= 0))
- dev_err(DEV, "offset=%lu number=%lu bm_words=%lu\n",
+ drbd_err(device, "offset=%lu number=%lu bm_words=%lu\n",
(unsigned long) offset,
(unsigned long) number,
(unsigned long) b->bm_words);
@@ -897,9 +897,9 @@ void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number,
}
/* set all bits in the bitmap */
-void drbd_bm_set_all(struct drbd_conf *mdev)
+void drbd_bm_set_all(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
if (!expect(b))
return;
if (!expect(b->bm_pages))
@@ -913,9 +913,9 @@ void drbd_bm_set_all(struct drbd_conf *mdev)
}
/* clear all bits in the bitmap */
-void drbd_bm_clear_all(struct drbd_conf *mdev)
+void drbd_bm_clear_all(struct drbd_device *device)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
if (!expect(b))
return;
if (!expect(b->bm_pages))
@@ -928,7 +928,7 @@ void drbd_bm_clear_all(struct drbd_conf *mdev)
}
struct bm_aio_ctx {
- struct drbd_conf *mdev;
+ struct drbd_device *device;
atomic_t in_flight;
unsigned int done;
unsigned flags;
@@ -943,7 +943,7 @@ static void bm_aio_ctx_destroy(struct kref *kref)
{
struct bm_aio_ctx *ctx = container_of(kref, struct bm_aio_ctx, kref);
- put_ldev(ctx->mdev);
+ put_ldev(ctx->device);
kfree(ctx);
}
@@ -951,8 +951,8 @@ static void bm_aio_ctx_destroy(struct kref *kref)
static void bm_async_io_complete(struct bio *bio, int error)
{
struct bm_aio_ctx *ctx = bio->bi_private;
- struct drbd_conf *mdev = ctx->mdev;
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_device *device = ctx->device;
+ struct drbd_bitmap *b = device->bitmap;
unsigned int idx = bm_page_to_idx(bio->bi_io_vec[0].bv_page);
int uptodate = bio_flagged(bio, BIO_UPTODATE);
@@ -966,7 +966,7 @@ static void bm_async_io_complete(struct bio *bio, int error)
if ((ctx->flags & BM_AIO_COPY_PAGES) == 0 &&
!bm_test_page_unchanged(b->bm_pages[idx]))
- dev_warn(DEV, "bitmap page idx %u changed during IO!\n", idx);
+ drbd_warn(device, "bitmap page idx %u changed during IO!\n", idx);
if (error) {
/* ctx error will hold the completed-last non-zero error code,
@@ -976,14 +976,14 @@ static void bm_async_io_complete(struct bio *bio, int error)
/* Not identical to on disk version of it.
* Is BM_PAGE_IO_ERROR enough? */
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "IO ERROR %d on bitmap page idx %u\n",
+ drbd_err(device, "IO ERROR %d on bitmap page idx %u\n",
error, idx);
} else {
bm_clear_page_io_err(b->bm_pages[idx]);
- dynamic_dev_dbg(DEV, "bitmap page idx %u completed\n", idx);
+ dynamic_drbd_dbg(device, "bitmap page idx %u completed\n", idx);
}
- bm_page_unlock_io(mdev, idx);
+ bm_page_unlock_io(device, idx);
if (ctx->flags & BM_AIO_COPY_PAGES)
mempool_free(bio->bi_io_vec[0].bv_page, drbd_md_io_page_pool);
@@ -992,7 +992,7 @@ static void bm_async_io_complete(struct bio *bio, int error)
if (atomic_dec_and_test(&ctx->in_flight)) {
ctx->done = 1;
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
}
}
@@ -1000,23 +1000,23 @@ static void bm_async_io_complete(struct bio *bio, int error)
static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must_hold(local)
{
struct bio *bio = bio_alloc_drbd(GFP_NOIO);
- struct drbd_conf *mdev = ctx->mdev;
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_device *device = ctx->device;
+ struct drbd_bitmap *b = device->bitmap;
struct page *page;
unsigned int len;
sector_t on_disk_sector =
- mdev->ldev->md.md_offset + mdev->ldev->md.bm_offset;
+ device->ldev->md.md_offset + device->ldev->md.bm_offset;
on_disk_sector += ((sector_t)page_nr) << (PAGE_SHIFT-9);
/* this might happen with very small
* flexible external meta data device,
* or with PAGE_SIZE > 4k */
len = min_t(unsigned int, PAGE_SIZE,
- (drbd_md_last_sector(mdev->ldev) - on_disk_sector + 1)<<9);
+ (drbd_md_last_sector(device->ldev) - on_disk_sector + 1)<<9);
/* serialize IO on this page */
- bm_page_lock_io(mdev, page_nr);
+ bm_page_lock_io(device, page_nr);
/* before memcpy and submit,
* so it can be redirtied any time */
bm_set_page_unchanged(b->bm_pages[page_nr]);
@@ -1027,7 +1027,7 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must
bm_store_page_idx(page, page_nr);
} else
page = b->bm_pages[page_nr];
- bio->bi_bdev = mdev->ldev->md_bdev;
+ bio->bi_bdev = device->ldev->md_bdev;
bio->bi_iter.bi_sector = on_disk_sector;
/* bio_add_page of a single page to an empty bio will always succeed,
* according to api. Do we want to assert that? */
@@ -1035,24 +1035,24 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must
bio->bi_private = ctx;
bio->bi_end_io = bm_async_io_complete;
- if (drbd_insert_fault(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) {
+ if (drbd_insert_fault(device, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) {
bio->bi_rw |= rw;
bio_endio(bio, -EIO);
} else {
submit_bio(rw, bio);
/* this should not count as user activity and cause the
* resync to throttle -- see drbd_rs_should_slow_down(). */
- atomic_add(len >> 9, &mdev->rs_sect_ev);
+ atomic_add(len >> 9, &device->rs_sect_ev);
}
}
/*
* bm_rw: read/write the whole bitmap from/to its on disk location.
*/
-static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_writeout_upper_idx) __must_hold(local)
+static int bm_rw(struct drbd_device *device, int rw, unsigned flags, unsigned lazy_writeout_upper_idx) __must_hold(local)
{
struct bm_aio_ctx *ctx;
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
int num_pages, i, count = 0;
unsigned long now;
char ppb[10];
@@ -1072,7 +1072,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
return -ENOMEM;
*ctx = (struct bm_aio_ctx) {
- .mdev = mdev,
+ .device = device,
.in_flight = ATOMIC_INIT(1),
.done = 0,
.flags = flags,
@@ -1080,8 +1080,8 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
.kref = { ATOMIC_INIT(2) },
};
- if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */
- dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in bm_rw()\n");
+ if (!get_ldev_if_state(device, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */
+ drbd_err(device, "ASSERT FAILED: get_ldev_if_state() == 1 in bm_rw()\n");
kfree(ctx);
return -ENODEV;
}
@@ -1106,14 +1106,14 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
if (!(flags & BM_WRITE_ALL_PAGES) &&
bm_test_page_unchanged(b->bm_pages[i])) {
- dynamic_dev_dbg(DEV, "skipped bm write for idx %u\n", i);
+ dynamic_drbd_dbg(device, "skipped bm write for idx %u\n", i);
continue;
}
/* during lazy writeout,
* ignore those pages not marked for lazy writeout. */
if (lazy_writeout_upper_idx &&
!bm_test_page_lazy_writeout(b->bm_pages[i])) {
- dynamic_dev_dbg(DEV, "skipped bm lazy write for idx %u\n", i);
+ dynamic_drbd_dbg(device, "skipped bm lazy write for idx %u\n", i);
continue;
}
}
@@ -1132,19 +1132,19 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
* "in_flight reached zero, all done" event.
*/
if (!atomic_dec_and_test(&ctx->in_flight))
- wait_until_done_or_force_detached(mdev, mdev->ldev, &ctx->done);
+ wait_until_done_or_force_detached(device, device->ldev, &ctx->done);
else
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
/* summary for global bitmap IO */
if (flags == 0)
- dev_info(DEV, "bitmap %s of %u pages took %lu jiffies\n",
+ drbd_info(device, "bitmap %s of %u pages took %lu jiffies\n",
rw == WRITE ? "WRITE" : "READ",
count, jiffies - now);
if (ctx->error) {
- dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n");
- drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
+ drbd_alert(device, "we had at least one MD IO ERROR during bitmap IO\n");
+ drbd_chk_io_error(device, 1, DRBD_META_IO_ERROR);
err = -EIO; /* ctx->error ? */
}
@@ -1153,16 +1153,16 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
now = jiffies;
if (rw == WRITE) {
- drbd_md_flush(mdev);
+ drbd_md_flush(device);
} else /* rw == READ */ {
b->bm_set = bm_count_bits(b);
- dev_info(DEV, "recounting of set bits took additional %lu jiffies\n",
+ drbd_info(device, "recounting of set bits took additional %lu jiffies\n",
jiffies - now);
}
now = b->bm_set;
if (flags == 0)
- dev_info(DEV, "%s (%lu bits) marked out-of-sync by on disk bit-map.\n",
+ drbd_info(device, "%s (%lu bits) marked out-of-sync by on disk bit-map.\n",
ppsize(ppb, now << (BM_BLOCK_SHIFT-10)), now);
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
@@ -1171,48 +1171,38 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
/**
* drbd_bm_read() - Read the whole bitmap from its on disk location.
- * @mdev: DRBD device.
+ * @device: DRBD device.
*/
-int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local)
+int drbd_bm_read(struct drbd_device *device) __must_hold(local)
{
- return bm_rw(mdev, READ, 0, 0);
+ return bm_rw(device, READ, 0, 0);
}
/**
* drbd_bm_write() - Write the whole bitmap to its on disk location.
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Will only write pages that have changed since last IO.
*/
-int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local)
+int drbd_bm_write(struct drbd_device *device) __must_hold(local)
{
- return bm_rw(mdev, WRITE, 0, 0);
+ return bm_rw(device, WRITE, 0, 0);
}
/**
* drbd_bm_write_all() - Write the whole bitmap to its on disk location.
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Will write all pages.
*/
-int drbd_bm_write_all(struct drbd_conf *mdev) __must_hold(local)
+int drbd_bm_write_all(struct drbd_device *device) __must_hold(local)
{
- return bm_rw(mdev, WRITE, BM_WRITE_ALL_PAGES, 0);
-}
-
-/**
- * drbd_bm_lazy_write_out() - Write bitmap pages 0 to @upper_idx-1, if they have changed.
- * @mdev: DRBD device.
- * @upper_idx: 0: write all changed pages; +ve: page index to stop scanning for changed pages
- */
-int drbd_bm_write_lazy(struct drbd_conf *mdev, unsigned upper_idx) __must_hold(local)
-{
- return bm_rw(mdev, WRITE, BM_AIO_COPY_PAGES, upper_idx);
+ return bm_rw(device, WRITE, BM_WRITE_ALL_PAGES, 0);
}
/**
* drbd_bm_write_copy_pages() - Write the whole bitmap to its on disk location.
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Will only write pages that have changed since last IO.
* In contrast to drbd_bm_write(), this will copy the bitmap pages
@@ -1221,23 +1211,23 @@ int drbd_bm_write_lazy(struct drbd_conf *mdev, unsigned upper_idx) __must_hold(l
* verify is aborted due to a failed peer disk, while local IO continues, or
* pending resync acks are still being processed.
*/
-int drbd_bm_write_copy_pages(struct drbd_conf *mdev) __must_hold(local)
+int drbd_bm_write_copy_pages(struct drbd_device *device) __must_hold(local)
{
- return bm_rw(mdev, WRITE, BM_AIO_COPY_PAGES, 0);
+ return bm_rw(device, WRITE, BM_AIO_COPY_PAGES, 0);
}
/**
* drbd_bm_write_hinted() - Write bitmap pages with "hint" marks, if they have changed.
- * @mdev: DRBD device.
+ * @device: DRBD device.
*/
-int drbd_bm_write_hinted(struct drbd_conf *mdev) __must_hold(local)
+int drbd_bm_write_hinted(struct drbd_device *device) __must_hold(local)
{
- return bm_rw(mdev, WRITE, BM_AIO_WRITE_HINTED | BM_AIO_COPY_PAGES, 0);
+ return bm_rw(device, WRITE, BM_AIO_WRITE_HINTED | BM_AIO_COPY_PAGES, 0);
}
/**
* drbd_bm_write_page() - Writes a PAGE_SIZE aligned piece of bitmap
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @idx: bitmap page index
*
* We don't want to special case on logical_block_size of the backend device,
@@ -1247,13 +1237,13 @@ int drbd_bm_write_hinted(struct drbd_conf *mdev) __must_hold(local)
* In case this becomes an issue on systems with larger PAGE_SIZE,
* we may want to change this again to write 4k aligned 4k pieces.
*/
-int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local)
+int drbd_bm_write_page(struct drbd_device *device, unsigned int idx) __must_hold(local)
{
struct bm_aio_ctx *ctx;
int err;
- if (bm_test_page_unchanged(mdev->bitmap->bm_pages[idx])) {
- dynamic_dev_dbg(DEV, "skipped bm page write for idx %u\n", idx);
+ if (bm_test_page_unchanged(device->bitmap->bm_pages[idx])) {
+ dynamic_drbd_dbg(device, "skipped bm page write for idx %u\n", idx);
return 0;
}
@@ -1262,7 +1252,7 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc
return -ENOMEM;
*ctx = (struct bm_aio_ctx) {
- .mdev = mdev,
+ .device = device,
.in_flight = ATOMIC_INIT(1),
.done = 0,
.flags = BM_AIO_COPY_PAGES,
@@ -1270,21 +1260,21 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc
.kref = { ATOMIC_INIT(2) },
};
- if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */
- dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in drbd_bm_write_page()\n");
+ if (!get_ldev_if_state(device, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */
+ drbd_err(device, "ASSERT FAILED: get_ldev_if_state() == 1 in drbd_bm_write_page()\n");
kfree(ctx);
return -ENODEV;
}
bm_page_io_async(ctx, idx, WRITE_SYNC);
- wait_until_done_or_force_detached(mdev, mdev->ldev, &ctx->done);
+ wait_until_done_or_force_detached(device, device->ldev, &ctx->done);
if (ctx->error)
- drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
+ drbd_chk_io_error(device, 1, DRBD_META_IO_ERROR);
/* that causes us to detach, so the in memory bitmap will be
* gone in a moment as well. */
- mdev->bm_writ_cnt++;
+ device->bm_writ_cnt++;
err = atomic_read(&ctx->in_flight) ? -EIO : ctx->error;
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
return err;
@@ -1298,17 +1288,17 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc
*
* this returns a bit number, NOT a sector!
*/
-static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo,
+static unsigned long __bm_find_next(struct drbd_device *device, unsigned long bm_fo,
const int find_zero_bit)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long *p_addr;
unsigned long bit_offset;
unsigned i;
if (bm_fo > b->bm_bits) {
- dev_err(DEV, "bm_fo=%lu bm_bits=%lu\n", bm_fo, b->bm_bits);
+ drbd_err(device, "bm_fo=%lu bm_bits=%lu\n", bm_fo, b->bm_bits);
bm_fo = DRBD_END_OF_BITMAP;
} else {
while (bm_fo < b->bm_bits) {
@@ -1338,10 +1328,10 @@ static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo,
return bm_fo;
}
-static unsigned long bm_find_next(struct drbd_conf *mdev,
+static unsigned long bm_find_next(struct drbd_device *device,
unsigned long bm_fo, const int find_zero_bit)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long i = DRBD_END_OF_BITMAP;
if (!expect(b))
@@ -1351,39 +1341,39 @@ static unsigned long bm_find_next(struct drbd_conf *mdev,
spin_lock_irq(&b->bm_lock);
if (BM_DONT_TEST & b->bm_flags)
- bm_print_lock_info(mdev);
+ bm_print_lock_info(device);
- i = __bm_find_next(mdev, bm_fo, find_zero_bit);
+ i = __bm_find_next(device, bm_fo, find_zero_bit);
spin_unlock_irq(&b->bm_lock);
return i;
}
-unsigned long drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo)
+unsigned long drbd_bm_find_next(struct drbd_device *device, unsigned long bm_fo)
{
- return bm_find_next(mdev, bm_fo, 0);
+ return bm_find_next(device, bm_fo, 0);
}
#if 0
/* not yet needed for anything. */
-unsigned long drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo)
+unsigned long drbd_bm_find_next_zero(struct drbd_device *device, unsigned long bm_fo)
{
- return bm_find_next(mdev, bm_fo, 1);
+ return bm_find_next(device, bm_fo, 1);
}
#endif
/* does not spin_lock_irqsave.
* you must take drbd_bm_lock() first */
-unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo)
+unsigned long _drbd_bm_find_next(struct drbd_device *device, unsigned long bm_fo)
{
- /* WARN_ON(!(BM_DONT_SET & mdev->b->bm_flags)); */
- return __bm_find_next(mdev, bm_fo, 0);
+ /* WARN_ON(!(BM_DONT_SET & device->b->bm_flags)); */
+ return __bm_find_next(device, bm_fo, 0);
}
-unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo)
+unsigned long _drbd_bm_find_next_zero(struct drbd_device *device, unsigned long bm_fo)
{
- /* WARN_ON(!(BM_DONT_SET & mdev->b->bm_flags)); */
- return __bm_find_next(mdev, bm_fo, 1);
+ /* WARN_ON(!(BM_DONT_SET & device->b->bm_flags)); */
+ return __bm_find_next(device, bm_fo, 1);
}
/* returns number of bits actually changed.
@@ -1392,10 +1382,10 @@ unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_f
* wants bitnr, not sector.
* expected to be called for only a few bits (e - s about BITS_PER_LONG).
* Must hold bitmap lock already. */
-static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
+static int __bm_change_bits_to(struct drbd_device *device, const unsigned long s,
unsigned long e, int val)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long *p_addr = NULL;
unsigned long bitnr;
unsigned int last_page_nr = -1U;
@@ -1403,7 +1393,7 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
int changed_total = 0;
if (e >= b->bm_bits) {
- dev_err(DEV, "ASSERT FAILED: bit_s=%lu bit_e=%lu bm_bits=%lu\n",
+ drbd_err(device, "ASSERT FAILED: bit_s=%lu bit_e=%lu bm_bits=%lu\n",
s, e, b->bm_bits);
e = b->bm_bits ? b->bm_bits -1 : 0;
}
@@ -1441,11 +1431,11 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
* for val != 0, we change 0 -> 1, return code positive
* for val == 0, we change 1 -> 0, return code negative
* wants bitnr, not sector */
-static int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
+static int bm_change_bits_to(struct drbd_device *device, const unsigned long s,
const unsigned long e, int val)
{
unsigned long flags;
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
int c = 0;
if (!expect(b))
@@ -1455,24 +1445,24 @@ static int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
spin_lock_irqsave(&b->bm_lock, flags);
if ((val ? BM_DONT_SET : BM_DONT_CLEAR) & b->bm_flags)
- bm_print_lock_info(mdev);
+ bm_print_lock_info(device);
- c = __bm_change_bits_to(mdev, s, e, val);
+ c = __bm_change_bits_to(device, s, e, val);
spin_unlock_irqrestore(&b->bm_lock, flags);
return c;
}
/* returns number of bits changed 0 -> 1 */
-int drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+int drbd_bm_set_bits(struct drbd_device *device, const unsigned long s, const unsigned long e)
{
- return bm_change_bits_to(mdev, s, e, 1);
+ return bm_change_bits_to(device, s, e, 1);
}
/* returns number of bits changed 1 -> 0 */
-int drbd_bm_clear_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+int drbd_bm_clear_bits(struct drbd_device *device, const unsigned long s, const unsigned long e)
{
- return -bm_change_bits_to(mdev, s, e, 0);
+ return -bm_change_bits_to(device, s, e, 0);
}
/* sets all bits in full words,
@@ -1504,7 +1494,7 @@ static inline void bm_set_full_words_within_one_page(struct drbd_bitmap *b,
* You must first drbd_bm_lock().
* Can be called to set the whole bitmap in one go.
* Sets bits from s to e _inclusive_. */
-void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+void _drbd_bm_set_bits(struct drbd_device *device, const unsigned long s, const unsigned long e)
{
/* First set_bit from the first bit (s)
* up to the next long boundary (sl),
@@ -1514,7 +1504,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
* Do not use memset, because we must account for changes,
* so we need to loop over the words with hweight() anyways.
*/
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long sl = ALIGN(s,BITS_PER_LONG);
unsigned long el = (e+1) & ~((unsigned long)BITS_PER_LONG-1);
int first_page;
@@ -1526,7 +1516,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
if (e - s <= 3*BITS_PER_LONG) {
/* don't bother; el and sl may even be wrong. */
spin_lock_irq(&b->bm_lock);
- __bm_change_bits_to(mdev, s, e, 1);
+ __bm_change_bits_to(device, s, e, 1);
spin_unlock_irq(&b->bm_lock);
return;
}
@@ -1537,7 +1527,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
/* bits filling the current long */
if (sl)
- __bm_change_bits_to(mdev, s, sl-1, 1);
+ __bm_change_bits_to(device, s, sl-1, 1);
first_page = sl >> (3 + PAGE_SHIFT);
last_page = el >> (3 + PAGE_SHIFT);
@@ -1549,7 +1539,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
/* first and full pages, unless first page == last page */
for (page_nr = first_page; page_nr < last_page; page_nr++) {
- bm_set_full_words_within_one_page(mdev->bitmap, page_nr, first_word, last_word);
+ bm_set_full_words_within_one_page(device->bitmap, page_nr, first_word, last_word);
spin_unlock_irq(&b->bm_lock);
cond_resched();
first_word = 0;
@@ -1565,7 +1555,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
* as we did not allocate it, it is not present in bitmap->bm_pages.
*/
if (last_word)
- bm_set_full_words_within_one_page(mdev->bitmap, last_page, first_word, last_word);
+ bm_set_full_words_within_one_page(device->bitmap, last_page, first_word, last_word);
/* possibly trailing bits.
* example: (e & 63) == 63, el will be e+1.
@@ -1573,7 +1563,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
* it would trigger an assert in __bm_change_bits_to()
*/
if (el <= e)
- __bm_change_bits_to(mdev, el, e, 1);
+ __bm_change_bits_to(device, el, e, 1);
spin_unlock_irq(&b->bm_lock);
}
@@ -1584,10 +1574,10 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
* 0 ... bit not set
* -1 ... first out of bounds access, stop testing for bits!
*/
-int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr)
+int drbd_bm_test_bit(struct drbd_device *device, const unsigned long bitnr)
{
unsigned long flags;
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long *p_addr;
int i;
@@ -1598,7 +1588,7 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr)
spin_lock_irqsave(&b->bm_lock, flags);
if (BM_DONT_TEST & b->bm_flags)
- bm_print_lock_info(mdev);
+ bm_print_lock_info(device);
if (bitnr < b->bm_bits) {
p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, bitnr));
i = test_bit_le(bitnr & BITS_PER_PAGE_MASK, p_addr) ? 1 : 0;
@@ -1606,7 +1596,7 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr)
} else if (bitnr == b->bm_bits) {
i = -1;
} else { /* (bitnr > b->bm_bits) */
- dev_err(DEV, "bitnr=%lu > bm_bits=%lu\n", bitnr, b->bm_bits);
+ drbd_err(device, "bitnr=%lu > bm_bits=%lu\n", bitnr, b->bm_bits);
i = 0;
}
@@ -1615,10 +1605,10 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr)
}
/* returns number of bits set in the range [s, e] */
-int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+int drbd_bm_count_bits(struct drbd_device *device, const unsigned long s, const unsigned long e)
{
unsigned long flags;
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
unsigned long *p_addr = NULL;
unsigned long bitnr;
unsigned int page_nr = -1U;
@@ -1635,7 +1625,7 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
spin_lock_irqsave(&b->bm_lock, flags);
if (BM_DONT_TEST & b->bm_flags)
- bm_print_lock_info(mdev);
+ bm_print_lock_info(device);
for (bitnr = s; bitnr <= e; bitnr++) {
unsigned int idx = bm_bit_to_page_idx(b, bitnr);
if (page_nr != idx) {
@@ -1647,7 +1637,7 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
if (expect(bitnr < b->bm_bits))
c += (0 != test_bit_le(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr));
else
- dev_err(DEV, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits);
+ drbd_err(device, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits);
}
if (p_addr)
bm_unmap(p_addr);
@@ -1670,9 +1660,9 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
* reference count of some bitmap extent element from some lru instead...
*
*/
-int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr)
+int drbd_bm_e_weight(struct drbd_device *device, unsigned long enr)
{
- struct drbd_bitmap *b = mdev->bitmap;
+ struct drbd_bitmap *b = device->bitmap;
int count, s, e;
unsigned long flags;
unsigned long *p_addr, *bm;
@@ -1684,7 +1674,7 @@ int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr)
spin_lock_irqsave(&b->bm_lock, flags);
if (BM_DONT_TEST & b->bm_flags)
- bm_print_lock_info(mdev);
+ bm_print_lock_info(device);
s = S2W(enr);
e = min((size_t)S2W(enr+1), b->bm_words);
@@ -1697,7 +1687,7 @@ int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr)
count += hweight_long(*bm++);
bm_unmap(p_addr);
} else {
- dev_err(DEV, "start offset (%d) too large in drbd_bm_e_weight\n", s);
+ drbd_err(device, "start offset (%d) too large in drbd_bm_e_weight\n", s);
}
spin_unlock_irqrestore(&b->bm_lock, flags);
return count;
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index 0e06f0c5dd1e..e7093d4291f1 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -45,7 +45,9 @@
#include <linux/prefetch.h>
#include <linux/drbd_genl_api.h>
#include <linux/drbd.h>
+#include "drbd_strings.h"
#include "drbd_state.h"
+#include "drbd_protocol.h"
#ifdef __CHECKER__
# define __protected_by(x) __attribute__((require_context(x,1,999,"rdwr")))
@@ -65,6 +67,7 @@
extern unsigned int minor_count;
extern bool disable_sendpage;
extern bool allow_oos;
+void tl_abort_disk_io(struct drbd_device *device);
#ifdef CONFIG_DRBD_FAULT_INJECTION
extern int enable_faults;
@@ -95,25 +98,60 @@ extern char usermode_helper[];
#define UUID_NEW_BM_OFFSET ((u64)0x0001000000000000ULL)
-struct drbd_conf;
-struct drbd_tconn;
-
-
-/* to shorten dev_warn(DEV, "msg"); and relatives statements */
-#define DEV (disk_to_dev(mdev->vdisk))
-
-#define conn_printk(LEVEL, TCONN, FMT, ARGS...) \
- printk(LEVEL "d-con %s: " FMT, TCONN->name , ## ARGS)
-#define conn_alert(TCONN, FMT, ARGS...) conn_printk(KERN_ALERT, TCONN, FMT, ## ARGS)
-#define conn_crit(TCONN, FMT, ARGS...) conn_printk(KERN_CRIT, TCONN, FMT, ## ARGS)
-#define conn_err(TCONN, FMT, ARGS...) conn_printk(KERN_ERR, TCONN, FMT, ## ARGS)
-#define conn_warn(TCONN, FMT, ARGS...) conn_printk(KERN_WARNING, TCONN, FMT, ## ARGS)
-#define conn_notice(TCONN, FMT, ARGS...) conn_printk(KERN_NOTICE, TCONN, FMT, ## ARGS)
-#define conn_info(TCONN, FMT, ARGS...) conn_printk(KERN_INFO, TCONN, FMT, ## ARGS)
-#define conn_dbg(TCONN, FMT, ARGS...) conn_printk(KERN_DEBUG, TCONN, FMT, ## ARGS)
-
-#define D_ASSERT(exp) if (!(exp)) \
- dev_err(DEV, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__)
+struct drbd_device;
+struct drbd_connection;
+
+#define __drbd_printk_device(level, device, fmt, args...) \
+ dev_printk(level, disk_to_dev((device)->vdisk), fmt, ## args)
+#define __drbd_printk_peer_device(level, peer_device, fmt, args...) \
+ dev_printk(level, disk_to_dev((peer_device)->device->vdisk), fmt, ## args)
+#define __drbd_printk_resource(level, resource, fmt, args...) \
+ printk(level "drbd %s: " fmt, (resource)->name, ## args)
+#define __drbd_printk_connection(level, connection, fmt, args...) \
+ printk(level "drbd %s: " fmt, (connection)->resource->name, ## args)
+
+void drbd_printk_with_wrong_object_type(void);
+
+#define __drbd_printk_if_same_type(obj, type, func, level, fmt, args...) \
+ (__builtin_types_compatible_p(typeof(obj), type) || \
+ __builtin_types_compatible_p(typeof(obj), const type)), \
+ func(level, (const type)(obj), fmt, ## args)
+
+#define drbd_printk(level, obj, fmt, args...) \
+ __builtin_choose_expr( \
+ __drbd_printk_if_same_type(obj, struct drbd_device *, \
+ __drbd_printk_device, level, fmt, ## args), \
+ __builtin_choose_expr( \
+ __drbd_printk_if_same_type(obj, struct drbd_resource *, \
+ __drbd_printk_resource, level, fmt, ## args), \
+ __builtin_choose_expr( \
+ __drbd_printk_if_same_type(obj, struct drbd_connection *, \
+ __drbd_printk_connection, level, fmt, ## args), \
+ __builtin_choose_expr( \
+ __drbd_printk_if_same_type(obj, struct drbd_peer_device *, \
+ __drbd_printk_peer_device, level, fmt, ## args), \
+ drbd_printk_with_wrong_object_type()))))
+
+#define drbd_dbg(obj, fmt, args...) \
+ drbd_printk(KERN_DEBUG, obj, fmt, ## args)
+#define drbd_alert(obj, fmt, args...) \
+ drbd_printk(KERN_ALERT, obj, fmt, ## args)
+#define drbd_err(obj, fmt, args...) \
+ drbd_printk(KERN_ERR, obj, fmt, ## args)
+#define drbd_warn(obj, fmt, args...) \
+ drbd_printk(KERN_WARNING, obj, fmt, ## args)
+#define drbd_info(obj, fmt, args...) \
+ drbd_printk(KERN_INFO, obj, fmt, ## args)
+#define drbd_emerg(obj, fmt, args...) \
+ drbd_printk(KERN_EMERG, obj, fmt, ## args)
+
+#define dynamic_drbd_dbg(device, fmt, args...) \
+ dynamic_dev_dbg(disk_to_dev(device->vdisk), fmt, ## args)
+
+#define D_ASSERT(device, exp) do { \
+ if (!(exp)) \
+ drbd_err(device, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__); \
+ } while (0)
/**
* expect - Make an assertion
@@ -123,7 +161,7 @@ struct drbd_tconn;
#define expect(exp) ({ \
bool _bool = (exp); \
if (!_bool) \
- dev_err(DEV, "ASSERTION %s FAILED in %s\n", \
+ drbd_err(device, "ASSERTION %s FAILED in %s\n", \
#exp, __func__); \
_bool; \
})
@@ -145,14 +183,14 @@ enum {
};
extern unsigned int
-_drbd_insert_fault(struct drbd_conf *mdev, unsigned int type);
+_drbd_insert_fault(struct drbd_device *device, unsigned int type);
static inline int
-drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) {
+drbd_insert_fault(struct drbd_device *device, unsigned int type) {
#ifdef CONFIG_DRBD_FAULT_INJECTION
return fault_rate &&
(enable_faults & (1<<type)) &&
- _drbd_insert_fault(mdev, type);
+ _drbd_insert_fault(device, type);
#else
return 0;
#endif
@@ -164,74 +202,8 @@ drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) {
#define div_floor(A, B) ((A)/(B))
extern struct ratelimit_state drbd_ratelimit_state;
-extern struct idr minors; /* RCU, updates: genl_lock() */
-extern struct list_head drbd_tconns; /* RCU, updates: genl_lock() */
-
-/* on the wire */
-enum drbd_packet {
- /* receiver (data socket) */
- P_DATA = 0x00,
- P_DATA_REPLY = 0x01, /* Response to P_DATA_REQUEST */
- P_RS_DATA_REPLY = 0x02, /* Response to P_RS_DATA_REQUEST */
- P_BARRIER = 0x03,
- P_BITMAP = 0x04,
- P_BECOME_SYNC_TARGET = 0x05,
- P_BECOME_SYNC_SOURCE = 0x06,
- P_UNPLUG_REMOTE = 0x07, /* Used at various times to hint the peer */
- P_DATA_REQUEST = 0x08, /* Used to ask for a data block */
- P_RS_DATA_REQUEST = 0x09, /* Used to ask for a data block for resync */
- P_SYNC_PARAM = 0x0a,
- P_PROTOCOL = 0x0b,
- P_UUIDS = 0x0c,
- P_SIZES = 0x0d,
- P_STATE = 0x0e,
- P_SYNC_UUID = 0x0f,
- P_AUTH_CHALLENGE = 0x10,
- P_AUTH_RESPONSE = 0x11,
- P_STATE_CHG_REQ = 0x12,
-
- /* asender (meta socket */
- P_PING = 0x13,
- P_PING_ACK = 0x14,
- P_RECV_ACK = 0x15, /* Used in protocol B */
- P_WRITE_ACK = 0x16, /* Used in protocol C */
- P_RS_WRITE_ACK = 0x17, /* Is a P_WRITE_ACK, additionally call set_in_sync(). */
- P_SUPERSEDED = 0x18, /* Used in proto C, two-primaries conflict detection */
- P_NEG_ACK = 0x19, /* Sent if local disk is unusable */
- P_NEG_DREPLY = 0x1a, /* Local disk is broken... */
- P_NEG_RS_DREPLY = 0x1b, /* Local disk is broken... */
- P_BARRIER_ACK = 0x1c,
- P_STATE_CHG_REPLY = 0x1d,
-
- /* "new" commands, no longer fitting into the ordering scheme above */
-
- P_OV_REQUEST = 0x1e, /* data socket */
- P_OV_REPLY = 0x1f,
- P_OV_RESULT = 0x20, /* meta socket */
- P_CSUM_RS_REQUEST = 0x21, /* data socket */
- P_RS_IS_IN_SYNC = 0x22, /* meta socket */
- P_SYNC_PARAM89 = 0x23, /* data socket, protocol version 89 replacement for P_SYNC_PARAM */
- P_COMPRESSED_BITMAP = 0x24, /* compressed or otherwise encoded bitmap transfer */
- /* P_CKPT_FENCE_REQ = 0x25, * currently reserved for protocol D */
- /* P_CKPT_DISABLE_REQ = 0x26, * currently reserved for protocol D */
- P_DELAY_PROBE = 0x27, /* is used on BOTH sockets */
- P_OUT_OF_SYNC = 0x28, /* Mark as out of sync (Outrunning), data socket */
- P_RS_CANCEL = 0x29, /* meta: Used to cancel RS_DATA_REQUEST packet by SyncSource */
- P_CONN_ST_CHG_REQ = 0x2a, /* data sock: Connection wide state request */
- P_CONN_ST_CHG_REPLY = 0x2b, /* meta sock: Connection side state req reply */
- P_RETRY_WRITE = 0x2c, /* Protocol C: retry conflicting write request */
- P_PROTOCOL_UPDATE = 0x2d, /* data sock: is used in established connections */
-
- P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */
- P_MAX_OPT_CMD = 0x101,
-
- /* special command ids for handshake */
-
- P_INITIAL_META = 0xfff1, /* First Packet on the MetaSock */
- P_INITIAL_DATA = 0xfff2, /* First Packet on the Socket */
-
- P_CONNECTION_FEATURES = 0xfffe /* FIXED for the next century! */
-};
+extern struct idr drbd_devices; /* RCU, updates: genl_lock() */
+extern struct list_head drbd_resources; /* RCU, updates: genl_lock() */
extern const char *cmdname(enum drbd_packet cmd);
@@ -253,7 +225,7 @@ struct bm_xfer_ctx {
unsigned bytes[2];
};
-extern void INFO_bm_xfer_stats(struct drbd_conf *mdev,
+extern void INFO_bm_xfer_stats(struct drbd_device *device,
const char *direction, struct bm_xfer_ctx *c);
static inline void bm_xfer_ctx_bit_to_word_offset(struct bm_xfer_ctx *c)
@@ -275,233 +247,7 @@ static inline void bm_xfer_ctx_bit_to_word_offset(struct bm_xfer_ctx *c)
#endif
}
-#ifndef __packed
-#define __packed __attribute__((packed))
-#endif
-
-/* This is the layout for a packet on the wire.
- * The byteorder is the network byte order.
- * (except block_id and barrier fields.
- * these are pointers to local structs
- * and have no relevance for the partner,
- * which just echoes them as received.)
- *
- * NOTE that the payload starts at a long aligned offset,
- * regardless of 32 or 64 bit arch!
- */
-struct p_header80 {
- u32 magic;
- u16 command;
- u16 length; /* bytes of data after this header */
-} __packed;
-
-/* Header for big packets, Used for data packets exceeding 64kB */
-struct p_header95 {
- u16 magic; /* use DRBD_MAGIC_BIG here */
- u16 command;
- u32 length;
-} __packed;
-
-struct p_header100 {
- u32 magic;
- u16 volume;
- u16 command;
- u32 length;
- u32 pad;
-} __packed;
-
-extern unsigned int drbd_header_size(struct drbd_tconn *tconn);
-
-/* these defines must not be changed without changing the protocol version */
-#define DP_HARDBARRIER 1 /* depricated */
-#define DP_RW_SYNC 2 /* equals REQ_SYNC */
-#define DP_MAY_SET_IN_SYNC 4
-#define DP_UNPLUG 8 /* not used anymore */
-#define DP_FUA 16 /* equals REQ_FUA */
-#define DP_FLUSH 32 /* equals REQ_FLUSH */
-#define DP_DISCARD 64 /* equals REQ_DISCARD */
-#define DP_SEND_RECEIVE_ACK 128 /* This is a proto B write request */
-#define DP_SEND_WRITE_ACK 256 /* This is a proto C write request */
-
-struct p_data {
- u64 sector; /* 64 bits sector number */
- u64 block_id; /* to identify the request in protocol B&C */
- u32 seq_num;
- u32 dp_flags;
-} __packed;
-
-/*
- * commands which share a struct:
- * p_block_ack:
- * P_RECV_ACK (proto B), P_WRITE_ACK (proto C),
- * P_SUPERSEDED (proto C, two-primaries conflict detection)
- * p_block_req:
- * P_DATA_REQUEST, P_RS_DATA_REQUEST
- */
-struct p_block_ack {
- u64 sector;
- u64 block_id;
- u32 blksize;
- u32 seq_num;
-} __packed;
-
-struct p_block_req {
- u64 sector;
- u64 block_id;
- u32 blksize;
- u32 pad; /* to multiple of 8 Byte */
-} __packed;
-
-/*
- * commands with their own struct for additional fields:
- * P_CONNECTION_FEATURES
- * P_BARRIER
- * P_BARRIER_ACK
- * P_SYNC_PARAM
- * ReportParams
- */
-
-struct p_connection_features {
- u32 protocol_min;
- u32 feature_flags;
- u32 protocol_max;
-
- /* should be more than enough for future enhancements
- * for now, feature_flags and the reserved array shall be zero.
- */
-
- u32 _pad;
- u64 reserved[7];
-} __packed;
-
-struct p_barrier {
- u32 barrier; /* barrier number _handle_ only */
- u32 pad; /* to multiple of 8 Byte */
-} __packed;
-
-struct p_barrier_ack {
- u32 barrier;
- u32 set_size;
-} __packed;
-
-struct p_rs_param {
- u32 resync_rate;
-
- /* Since protocol version 88 and higher. */
- char verify_alg[0];
-} __packed;
-
-struct p_rs_param_89 {
- u32 resync_rate;
- /* protocol version 89: */
- char verify_alg[SHARED_SECRET_MAX];
- char csums_alg[SHARED_SECRET_MAX];
-} __packed;
-
-struct p_rs_param_95 {
- u32 resync_rate;
- char verify_alg[SHARED_SECRET_MAX];
- char csums_alg[SHARED_SECRET_MAX];
- u32 c_plan_ahead;
- u32 c_delay_target;
- u32 c_fill_target;
- u32 c_max_rate;
-} __packed;
-
-enum drbd_conn_flags {
- CF_DISCARD_MY_DATA = 1,
- CF_DRY_RUN = 2,
-};
-
-struct p_protocol {
- u32 protocol;
- u32 after_sb_0p;
- u32 after_sb_1p;
- u32 after_sb_2p;
- u32 conn_flags;
- u32 two_primaries;
-
- /* Since protocol version 87 and higher. */
- char integrity_alg[0];
-
-} __packed;
-
-struct p_uuids {
- u64 uuid[UI_EXTENDED_SIZE];
-} __packed;
-
-struct p_rs_uuid {
- u64 uuid;
-} __packed;
-
-struct p_sizes {
- u64 d_size; /* size of disk */
- u64 u_size; /* user requested size */
- u64 c_size; /* current exported size */
- u32 max_bio_size; /* Maximal size of a BIO */
- u16 queue_order_type; /* not yet implemented in DRBD*/
- u16 dds_flags; /* use enum dds_flags here. */
-} __packed;
-
-struct p_state {
- u32 state;
-} __packed;
-
-struct p_req_state {
- u32 mask;
- u32 val;
-} __packed;
-
-struct p_req_state_reply {
- u32 retcode;
-} __packed;
-
-struct p_drbd06_param {
- u64 size;
- u32 state;
- u32 blksize;
- u32 protocol;
- u32 version;
- u32 gen_cnt[5];
- u32 bit_map_gen[5];
-} __packed;
-
-struct p_block_desc {
- u64 sector;
- u32 blksize;
- u32 pad; /* to multiple of 8 Byte */
-} __packed;
-
-/* Valid values for the encoding field.
- * Bump proto version when changing this. */
-enum drbd_bitmap_code {
- /* RLE_VLI_Bytes = 0,
- * and other bit variants had been defined during
- * algorithm evaluation. */
- RLE_VLI_Bits = 2,
-};
-
-struct p_compressed_bm {
- /* (encoding & 0x0f): actual encoding, see enum drbd_bitmap_code
- * (encoding & 0x80): polarity (set/unset) of first runlength
- * ((encoding >> 4) & 0x07): pad_bits, number of trailing zero bits
- * used to pad up to head.length bytes
- */
- u8 encoding;
-
- u8 code[0];
-} __packed;
-
-struct p_delay_probe93 {
- u32 seq_num; /* sequence number to match the two probe packets */
- u32 offset; /* usecs the probe got sent after the reference time point */
-} __packed;
-
-/*
- * Bitmap packets need to fit within a single page on the sender and receiver,
- * so we are limited to 4 KiB (and not to PAGE_SIZE, which can be bigger).
- */
-#define DRBD_SOCKET_BUFFER_SIZE 4096
+extern unsigned int drbd_header_size(struct drbd_connection *connection);
/**********************************************************************/
enum drbd_thread_state {
@@ -517,9 +263,10 @@ struct drbd_thread {
struct completion stop;
enum drbd_thread_state t_state;
int (*function) (struct drbd_thread *);
- struct drbd_tconn *tconn;
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
int reset_cpu_mask;
- char name[9];
+ const char *name;
};
static inline enum drbd_thread_state get_t_state(struct drbd_thread *thi)
@@ -535,18 +282,20 @@ static inline enum drbd_thread_state get_t_state(struct drbd_thread *thi)
struct drbd_work {
struct list_head list;
int (*cb)(struct drbd_work *, int cancel);
- union {
- struct drbd_conf *mdev;
- struct drbd_tconn *tconn;
- };
+};
+
+struct drbd_device_work {
+ struct drbd_work w;
+ struct drbd_device *device;
};
#include "drbd_interval.h"
-extern int drbd_wait_misc(struct drbd_conf *, struct drbd_interval *);
+extern int drbd_wait_misc(struct drbd_device *, struct drbd_interval *);
struct drbd_request {
struct drbd_work w;
+ struct drbd_device *device;
/* if local IO is not allowed, will be NULL.
* if local IO _is_ allowed, holds the locally submitted bio clone,
@@ -579,7 +328,7 @@ struct drbd_request {
};
struct drbd_epoch {
- struct drbd_tconn *tconn;
+ struct drbd_connection *connection;
struct list_head list;
unsigned int barrier_nr;
atomic_t epoch_size; /* increased on every request added. */
@@ -587,6 +336,10 @@ struct drbd_epoch {
unsigned long flags;
};
+/* Prototype declaration of function defined in drbd_receiver.c */
+int drbdd_init(struct drbd_thread *);
+int drbd_asender(struct drbd_thread *);
+
/* drbd_epoch flag bits */
enum {
DE_HAVE_BARRIER_NUMBER,
@@ -599,11 +352,6 @@ enum epoch_event {
EV_CLEANUP = 32, /* used as flag */
};
-struct drbd_wq_barrier {
- struct drbd_work w;
- struct completion done;
-};
-
struct digest_info {
int digest_size;
void *digest;
@@ -611,6 +359,7 @@ struct digest_info {
struct drbd_peer_request {
struct drbd_work w;
+ struct drbd_peer_device *peer_device;
struct drbd_epoch *epoch; /* for writes */
struct page *pages;
atomic_t pending_bios;
@@ -663,7 +412,7 @@ enum {
#define EE_SEND_WRITE_ACK (1<<__EE_SEND_WRITE_ACK)
#define EE_IN_INTERVAL_TREE (1<<__EE_IN_INTERVAL_TREE)
-/* flag bits per mdev */
+/* flag bits per device */
enum {
UNPLUG_REMOTE, /* sending a "UnplugRemote" could help */
MD_DIRTY, /* current uuids and flags not yet on disk */
@@ -695,7 +444,7 @@ enum {
READ_BALANCE_RR,
};
-struct drbd_bitmap; /* opaque for drbd_conf */
+struct drbd_bitmap; /* opaque for drbd_device */
/* definition of bits in bm_flags to be used in drbd_bm_lock
* and drbd_bitmap_io and friends. */
@@ -769,7 +518,7 @@ struct drbd_backing_dev {
struct block_device *backing_bdev;
struct block_device *md_bdev;
struct drbd_md md;
- struct disk_conf *disk_conf; /* RCU, for updates: mdev->tconn->conf_update */
+ struct disk_conf *disk_conf; /* RCU, for updates: resource->conf_update */
sector_t known_size; /* last known size of that backing device */
};
@@ -782,8 +531,8 @@ struct bm_io_work {
struct drbd_work w;
char *why;
enum bm_flag flags;
- int (*io_fn)(struct drbd_conf *mdev);
- void (*done)(struct drbd_conf *mdev, int rv);
+ int (*io_fn)(struct drbd_device *device);
+ void (*done)(struct drbd_device *device, int rv);
};
enum write_ordering_e {
@@ -800,7 +549,7 @@ struct fifo_buffer {
};
extern struct fifo_buffer *fifo_alloc(int fifo_size);
-/* flag bits per tconn */
+/* flag bits per connection */
enum {
NET_CONGESTED, /* The data socket is congested */
RESOLVE_CONFLICTS, /* Set on one node, cleared on the peer! */
@@ -822,23 +571,35 @@ enum {
DISCONNECT_SENT,
};
-struct drbd_tconn { /* is a resource from the config file */
- char *name; /* Resource name */
- struct list_head all_tconn; /* linked on global drbd_tconns */
+struct drbd_resource {
+ char *name;
struct kref kref;
- struct idr volumes; /* <tconn, vnr> to mdev mapping */
- enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */
+ struct idr devices; /* volume number to device mapping */
+ struct list_head connections;
+ struct list_head resources;
+ struct res_opts res_opts;
+ struct mutex conf_update; /* mutex for ready-copy-update of net_conf and disk_conf */
+ spinlock_t req_lock;
+
unsigned susp:1; /* IO suspended by user */
unsigned susp_nod:1; /* IO suspended because no data */
unsigned susp_fen:1; /* IO suspended because fence peer handler runs */
+
+ cpumask_var_t cpu_mask;
+};
+
+struct drbd_connection {
+ struct list_head connections;
+ struct drbd_resource *resource;
+ struct kref kref;
+ struct idr peer_devices; /* volume number to peer device mapping */
+ enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */
struct mutex cstate_mutex; /* Protects graceful disconnects */
unsigned int connect_cnt; /* Inc each time a connection is established */
unsigned long flags;
struct net_conf *net_conf; /* content protected by rcu */
- struct mutex conf_update; /* mutex for ready-copy-update of net_conf and disk_conf */
wait_queue_head_t ping_wait; /* Woken upon reception of a ping, and a state change */
- struct res_opts res_opts;
struct sockaddr_storage my_addr;
int my_addr_len;
@@ -851,12 +612,10 @@ struct drbd_tconn { /* is a resource from the config file */
unsigned long last_received; /* in jiffies, either socket */
unsigned int ko_count;
- spinlock_t req_lock;
-
struct list_head transfer_log; /* all requests not yet fully processed */
struct crypto_hash *cram_hmac_tfm;
- struct crypto_hash *integrity_tfm; /* checksums we compute, updates protected by tconn->data->mutex */
+ struct crypto_hash *integrity_tfm; /* checksums we compute, updates protected by connection->data->mutex */
struct crypto_hash *peer_integrity_tfm; /* checksums we verify, only accessed from receiver thread */
struct crypto_hash *csums_tfm;
struct crypto_hash *verify_tfm;
@@ -875,7 +634,6 @@ struct drbd_tconn { /* is a resource from the config file */
struct drbd_thread receiver;
struct drbd_thread worker;
struct drbd_thread asender;
- cpumask_var_t cpu_mask;
/* sender side */
struct drbd_work_queue sender_work;
@@ -903,8 +661,15 @@ struct submit_worker {
struct list_head writes;
};
-struct drbd_conf {
- struct drbd_tconn *tconn;
+struct drbd_peer_device {
+ struct list_head peer_devices;
+ struct drbd_device *device;
+ struct drbd_connection *connection;
+};
+
+struct drbd_device {
+ struct drbd_resource *resource;
+ struct list_head peer_devices;
int vnr; /* volume number within the connection */
struct kref kref;
@@ -920,11 +685,11 @@ struct drbd_conf {
struct gendisk *vdisk;
unsigned long last_reattach_jif;
- struct drbd_work resync_work,
- unplug_work,
- go_diskless,
- md_sync_work,
- start_resync_work;
+ struct drbd_work resync_work;
+ struct drbd_work unplug_work;
+ struct drbd_work go_diskless;
+ struct drbd_work md_sync_work;
+ struct drbd_work start_resync_work;
struct timer_list resync_timer;
struct timer_list md_sync_timer;
struct timer_list start_resync_timer;
@@ -1030,7 +795,7 @@ struct drbd_conf {
struct bm_io_work bm_io_work;
u64 ed_uuid; /* UUID of the exposed data */
struct mutex own_state_mutex;
- struct mutex *state_mutex; /* either own_state_mutex or mdev->tconn->cstate_mutex */
+ struct mutex *state_mutex; /* either own_state_mutex or first_peer_device(device)->connection->cstate_mutex */
char congestion_reason; /* Why we where congested... */
atomic_t rs_sect_in; /* for incoming resync data rate, SyncTarget */
atomic_t rs_sect_ev; /* for submitted resync data rate, both */
@@ -1038,7 +803,7 @@ struct drbd_conf {
int rs_last_events; /* counter of read or write "events" (unit sectors)
* on the lower level device when we last looked. */
int c_sync_rate; /* current resync rate after syncer throttle magic */
- struct fifo_buffer *rs_plan_s; /* correction values of resync planer (RCU, tconn->conn_update) */
+ struct fifo_buffer *rs_plan_s; /* correction values of resync planer (RCU, connection->conn_update) */
int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */
atomic_t ap_in_flight; /* App sectors in flight (waiting for ack) */
unsigned int peer_max_bio_size;
@@ -1049,19 +814,46 @@ struct drbd_conf {
struct submit_worker submit;
};
-static inline struct drbd_conf *minor_to_mdev(unsigned int minor)
+static inline struct drbd_device *minor_to_device(unsigned int minor)
{
- return (struct drbd_conf *)idr_find(&minors, minor);
+ return (struct drbd_device *)idr_find(&drbd_devices, minor);
}
-static inline unsigned int mdev_to_minor(struct drbd_conf *mdev)
+static inline struct drbd_peer_device *first_peer_device(struct drbd_device *device)
{
- return mdev->minor;
+ return list_first_entry(&device->peer_devices, struct drbd_peer_device, peer_devices);
}
-static inline struct drbd_conf *vnr_to_mdev(struct drbd_tconn *tconn, int vnr)
+#define for_each_resource(resource, _resources) \
+ list_for_each_entry(resource, _resources, resources)
+
+#define for_each_resource_rcu(resource, _resources) \
+ list_for_each_entry_rcu(resource, _resources, resources)
+
+#define for_each_resource_safe(resource, tmp, _resources) \
+ list_for_each_entry_safe(resource, tmp, _resources, resources)
+
+#define for_each_connection(connection, resource) \
+ list_for_each_entry(connection, &resource->connections, connections)
+
+#define for_each_connection_rcu(connection, resource) \
+ list_for_each_entry_rcu(connection, &resource->connections, connections)
+
+#define for_each_connection_safe(connection, tmp, resource) \
+ list_for_each_entry_safe(connection, tmp, &resource->connections, connections)
+
+#define for_each_peer_device(peer_device, device) \
+ list_for_each_entry(peer_device, &device->peer_devices, peer_devices)
+
+#define for_each_peer_device_rcu(peer_device, device) \
+ list_for_each_entry_rcu(peer_device, &device->peer_devices, peer_devices)
+
+#define for_each_peer_device_safe(peer_device, tmp, device) \
+ list_for_each_entry_safe(peer_device, tmp, &device->peer_devices, peer_devices)
+
+static inline unsigned int device_to_minor(struct drbd_device *device)
{
- return (struct drbd_conf *)idr_find(&tconn->volumes, vnr);
+ return device->minor;
}
/*
@@ -1075,96 +867,93 @@ enum dds_flags {
DDSF_NO_RESYNC = 2, /* Do not run a resync for the new space */
};
-extern void drbd_init_set_defaults(struct drbd_conf *mdev);
+extern void drbd_init_set_defaults(struct drbd_device *device);
extern int drbd_thread_start(struct drbd_thread *thi);
extern void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait);
-extern char *drbd_task_to_thread_name(struct drbd_tconn *tconn, struct task_struct *task);
#ifdef CONFIG_SMP
extern void drbd_thread_current_set_cpu(struct drbd_thread *thi);
-extern void drbd_calc_cpu_mask(struct drbd_tconn *tconn);
#else
#define drbd_thread_current_set_cpu(A) ({})
-#define drbd_calc_cpu_mask(A) ({})
#endif
-extern void tl_release(struct drbd_tconn *, unsigned int barrier_nr,
+extern void tl_release(struct drbd_connection *, unsigned int barrier_nr,
unsigned int set_size);
-extern void tl_clear(struct drbd_tconn *);
-extern void drbd_free_sock(struct drbd_tconn *tconn);
-extern int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
+extern void tl_clear(struct drbd_connection *);
+extern void drbd_free_sock(struct drbd_connection *connection);
+extern int drbd_send(struct drbd_connection *connection, struct socket *sock,
void *buf, size_t size, unsigned msg_flags);
-extern int drbd_send_all(struct drbd_tconn *, struct socket *, void *, size_t,
+extern int drbd_send_all(struct drbd_connection *, struct socket *, void *, size_t,
unsigned);
-extern int __drbd_send_protocol(struct drbd_tconn *tconn, enum drbd_packet cmd);
-extern int drbd_send_protocol(struct drbd_tconn *tconn);
-extern int drbd_send_uuids(struct drbd_conf *mdev);
-extern int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev);
-extern void drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev);
-extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags);
-extern int drbd_send_state(struct drbd_conf *mdev, union drbd_state s);
-extern int drbd_send_current_state(struct drbd_conf *mdev);
-extern int drbd_send_sync_param(struct drbd_conf *mdev);
-extern void drbd_send_b_ack(struct drbd_tconn *tconn, u32 barrier_nr,
+extern int __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cmd);
+extern int drbd_send_protocol(struct drbd_connection *connection);
+extern int drbd_send_uuids(struct drbd_peer_device *);
+extern int drbd_send_uuids_skip_initial_sync(struct drbd_peer_device *);
+extern void drbd_gen_and_send_sync_uuid(struct drbd_peer_device *);
+extern int drbd_send_sizes(struct drbd_peer_device *, int trigger_reply, enum dds_flags flags);
+extern int drbd_send_state(struct drbd_peer_device *, union drbd_state s);
+extern int drbd_send_current_state(struct drbd_peer_device *);
+extern int drbd_send_sync_param(struct drbd_peer_device *);
+extern void drbd_send_b_ack(struct drbd_connection *connection, u32 barrier_nr,
u32 set_size);
-extern int drbd_send_ack(struct drbd_conf *, enum drbd_packet,
+extern int drbd_send_ack(struct drbd_peer_device *, enum drbd_packet,
struct drbd_peer_request *);
-extern void drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packet cmd,
+extern void drbd_send_ack_rp(struct drbd_peer_device *, enum drbd_packet,
struct p_block_req *rp);
-extern void drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packet cmd,
+extern void drbd_send_ack_dp(struct drbd_peer_device *, enum drbd_packet,
struct p_data *dp, int data_size);
-extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packet cmd,
+extern int drbd_send_ack_ex(struct drbd_peer_device *, enum drbd_packet,
sector_t sector, int blksize, u64 block_id);
-extern int drbd_send_out_of_sync(struct drbd_conf *, struct drbd_request *);
-extern int drbd_send_block(struct drbd_conf *, enum drbd_packet,
+extern int drbd_send_out_of_sync(struct drbd_peer_device *, struct drbd_request *);
+extern int drbd_send_block(struct drbd_peer_device *, enum drbd_packet,
struct drbd_peer_request *);
-extern int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req);
-extern int drbd_send_drequest(struct drbd_conf *mdev, int cmd,
+extern int drbd_send_dblock(struct drbd_peer_device *, struct drbd_request *req);
+extern int drbd_send_drequest(struct drbd_peer_device *, int cmd,
sector_t sector, int size, u64 block_id);
-extern int drbd_send_drequest_csum(struct drbd_conf *mdev, sector_t sector,
+extern int drbd_send_drequest_csum(struct drbd_peer_device *, sector_t sector,
int size, void *digest, int digest_size,
enum drbd_packet cmd);
-extern int drbd_send_ov_request(struct drbd_conf *mdev,sector_t sector,int size);
+extern int drbd_send_ov_request(struct drbd_peer_device *, sector_t sector, int size);
-extern int drbd_send_bitmap(struct drbd_conf *mdev);
-extern void drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode);
-extern void conn_send_sr_reply(struct drbd_tconn *tconn, enum drbd_state_rv retcode);
+extern int drbd_send_bitmap(struct drbd_device *device);
+extern void drbd_send_sr_reply(struct drbd_peer_device *, enum drbd_state_rv retcode);
+extern void conn_send_sr_reply(struct drbd_connection *connection, enum drbd_state_rv retcode);
extern void drbd_free_bc(struct drbd_backing_dev *ldev);
-extern void drbd_mdev_cleanup(struct drbd_conf *mdev);
-void drbd_print_uuids(struct drbd_conf *mdev, const char *text);
-
-extern void conn_md_sync(struct drbd_tconn *tconn);
-extern void drbd_md_write(struct drbd_conf *mdev, void *buffer);
-extern void drbd_md_sync(struct drbd_conf *mdev);
-extern int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev);
-extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local);
-extern void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local);
-extern void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local);
-extern void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local);
-extern void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local);
-extern void __drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local);
-extern void drbd_md_set_flag(struct drbd_conf *mdev, int flags) __must_hold(local);
-extern void drbd_md_clear_flag(struct drbd_conf *mdev, int flags)__must_hold(local);
+extern void drbd_device_cleanup(struct drbd_device *device);
+void drbd_print_uuids(struct drbd_device *device, const char *text);
+
+extern void conn_md_sync(struct drbd_connection *connection);
+extern void drbd_md_write(struct drbd_device *device, void *buffer);
+extern void drbd_md_sync(struct drbd_device *device);
+extern int drbd_md_read(struct drbd_device *device, struct drbd_backing_dev *bdev);
+extern void drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local);
+extern void _drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local);
+extern void drbd_uuid_new_current(struct drbd_device *device) __must_hold(local);
+extern void drbd_uuid_set_bm(struct drbd_device *device, u64 val) __must_hold(local);
+extern void drbd_uuid_move_history(struct drbd_device *device) __must_hold(local);
+extern void __drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local);
+extern void drbd_md_set_flag(struct drbd_device *device, int flags) __must_hold(local);
+extern void drbd_md_clear_flag(struct drbd_device *device, int flags)__must_hold(local);
extern int drbd_md_test_flag(struct drbd_backing_dev *, int);
#ifndef DRBD_DEBUG_MD_SYNC
-extern void drbd_md_mark_dirty(struct drbd_conf *mdev);
+extern void drbd_md_mark_dirty(struct drbd_device *device);
#else
#define drbd_md_mark_dirty(m) drbd_md_mark_dirty_(m, __LINE__ , __func__ )
-extern void drbd_md_mark_dirty_(struct drbd_conf *mdev,
+extern void drbd_md_mark_dirty_(struct drbd_device *device,
unsigned int line, const char *func);
#endif
-extern void drbd_queue_bitmap_io(struct drbd_conf *mdev,
- int (*io_fn)(struct drbd_conf *),
- void (*done)(struct drbd_conf *, int),
+extern void drbd_queue_bitmap_io(struct drbd_device *device,
+ int (*io_fn)(struct drbd_device *),
+ void (*done)(struct drbd_device *, int),
char *why, enum bm_flag flags);
-extern int drbd_bitmap_io(struct drbd_conf *mdev,
- int (*io_fn)(struct drbd_conf *),
+extern int drbd_bitmap_io(struct drbd_device *device,
+ int (*io_fn)(struct drbd_device *),
char *why, enum bm_flag flags);
-extern int drbd_bitmap_io_from_worker(struct drbd_conf *mdev,
- int (*io_fn)(struct drbd_conf *),
+extern int drbd_bitmap_io_from_worker(struct drbd_device *device,
+ int (*io_fn)(struct drbd_device *),
char *why, enum bm_flag flags);
-extern int drbd_bmio_set_n_write(struct drbd_conf *mdev);
-extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev);
-extern void drbd_ldev_destroy(struct drbd_conf *mdev);
+extern int drbd_bmio_set_n_write(struct drbd_device *device);
+extern int drbd_bmio_clear_n_write(struct drbd_device *device);
+extern void drbd_ldev_destroy(struct drbd_device *device);
/* Meta data layout
*
@@ -1350,52 +1139,52 @@ struct bm_extent {
#define DRBD_MAX_SIZE_H80_PACKET (1U << 15) /* Header 80 only allows packets up to 32KiB data */
#define DRBD_MAX_BIO_SIZE_P95 (1U << 17) /* Protocol 95 to 99 allows bios up to 128KiB */
-extern int drbd_bm_init(struct drbd_conf *mdev);
-extern int drbd_bm_resize(struct drbd_conf *mdev, sector_t sectors, int set_new_bits);
-extern void drbd_bm_cleanup(struct drbd_conf *mdev);
-extern void drbd_bm_set_all(struct drbd_conf *mdev);
-extern void drbd_bm_clear_all(struct drbd_conf *mdev);
+extern int drbd_bm_init(struct drbd_device *device);
+extern int drbd_bm_resize(struct drbd_device *device, sector_t sectors, int set_new_bits);
+extern void drbd_bm_cleanup(struct drbd_device *device);
+extern void drbd_bm_set_all(struct drbd_device *device);
+extern void drbd_bm_clear_all(struct drbd_device *device);
/* set/clear/test only a few bits at a time */
extern int drbd_bm_set_bits(
- struct drbd_conf *mdev, unsigned long s, unsigned long e);
+ struct drbd_device *device, unsigned long s, unsigned long e);
extern int drbd_bm_clear_bits(
- struct drbd_conf *mdev, unsigned long s, unsigned long e);
+ struct drbd_device *device, unsigned long s, unsigned long e);
extern int drbd_bm_count_bits(
- struct drbd_conf *mdev, const unsigned long s, const unsigned long e);
+ struct drbd_device *device, const unsigned long s, const unsigned long e);
/* bm_set_bits variant for use while holding drbd_bm_lock,
* may process the whole bitmap in one go */
-extern void _drbd_bm_set_bits(struct drbd_conf *mdev,
+extern void _drbd_bm_set_bits(struct drbd_device *device,
const unsigned long s, const unsigned long e);
-extern int drbd_bm_test_bit(struct drbd_conf *mdev, unsigned long bitnr);
-extern int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr);
-extern int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local);
-extern int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local);
-extern void drbd_bm_mark_for_writeout(struct drbd_conf *mdev, int page_nr);
-extern int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local);
-extern int drbd_bm_write_hinted(struct drbd_conf *mdev) __must_hold(local);
-extern int drbd_bm_write_all(struct drbd_conf *mdev) __must_hold(local);
-extern int drbd_bm_write_copy_pages(struct drbd_conf *mdev) __must_hold(local);
-extern size_t drbd_bm_words(struct drbd_conf *mdev);
-extern unsigned long drbd_bm_bits(struct drbd_conf *mdev);
-extern sector_t drbd_bm_capacity(struct drbd_conf *mdev);
+extern int drbd_bm_test_bit(struct drbd_device *device, unsigned long bitnr);
+extern int drbd_bm_e_weight(struct drbd_device *device, unsigned long enr);
+extern int drbd_bm_write_page(struct drbd_device *device, unsigned int idx) __must_hold(local);
+extern int drbd_bm_read(struct drbd_device *device) __must_hold(local);
+extern void drbd_bm_mark_for_writeout(struct drbd_device *device, int page_nr);
+extern int drbd_bm_write(struct drbd_device *device) __must_hold(local);
+extern int drbd_bm_write_hinted(struct drbd_device *device) __must_hold(local);
+extern int drbd_bm_write_all(struct drbd_device *device) __must_hold(local);
+extern int drbd_bm_write_copy_pages(struct drbd_device *device) __must_hold(local);
+extern size_t drbd_bm_words(struct drbd_device *device);
+extern unsigned long drbd_bm_bits(struct drbd_device *device);
+extern sector_t drbd_bm_capacity(struct drbd_device *device);
#define DRBD_END_OF_BITMAP (~(unsigned long)0)
-extern unsigned long drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo);
+extern unsigned long drbd_bm_find_next(struct drbd_device *device, unsigned long bm_fo);
/* bm_find_next variants for use while you hold drbd_bm_lock() */
-extern unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo);
-extern unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo);
-extern unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev);
-extern unsigned long drbd_bm_total_weight(struct drbd_conf *mdev);
-extern int drbd_bm_rs_done(struct drbd_conf *mdev);
+extern unsigned long _drbd_bm_find_next(struct drbd_device *device, unsigned long bm_fo);
+extern unsigned long _drbd_bm_find_next_zero(struct drbd_device *device, unsigned long bm_fo);
+extern unsigned long _drbd_bm_total_weight(struct drbd_device *device);
+extern unsigned long drbd_bm_total_weight(struct drbd_device *device);
+extern int drbd_bm_rs_done(struct drbd_device *device);
/* for receive_bitmap */
-extern void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset,
+extern void drbd_bm_merge_lel(struct drbd_device *device, size_t offset,
size_t number, unsigned long *buffer);
/* for _drbd_send_bitmap */
-extern void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset,
+extern void drbd_bm_get_lel(struct drbd_device *device, size_t offset,
size_t number, unsigned long *buffer);
-extern void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags);
-extern void drbd_bm_unlock(struct drbd_conf *mdev);
+extern void drbd_bm_lock(struct drbd_device *device, char *why, enum bm_flag flags);
+extern void drbd_bm_unlock(struct drbd_device *device);
/* drbd_main.c */
extern struct kmem_cache *drbd_request_cache;
@@ -1439,35 +1228,40 @@ extern struct bio *bio_alloc_drbd(gfp_t gfp_mask);
extern rwlock_t global_state_lock;
-extern int conn_lowest_minor(struct drbd_tconn *tconn);
-enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr);
-extern void drbd_minor_destroy(struct kref *kref);
+extern int conn_lowest_minor(struct drbd_connection *connection);
+enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned int minor, int vnr);
+extern void drbd_destroy_device(struct kref *kref);
+extern void drbd_delete_device(struct drbd_device *mdev);
+
+extern struct drbd_resource *drbd_create_resource(const char *name);
+extern void drbd_free_resource(struct drbd_resource *resource);
-extern int set_resource_options(struct drbd_tconn *tconn, struct res_opts *res_opts);
-extern struct drbd_tconn *conn_create(const char *name, struct res_opts *res_opts);
-extern void conn_destroy(struct kref *kref);
-struct drbd_tconn *conn_get_by_name(const char *name);
-extern struct drbd_tconn *conn_get_by_addrs(void *my_addr, int my_addr_len,
+extern int set_resource_options(struct drbd_resource *resource, struct res_opts *res_opts);
+extern struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts);
+extern void drbd_destroy_connection(struct kref *kref);
+extern struct drbd_connection *conn_get_by_addrs(void *my_addr, int my_addr_len,
void *peer_addr, int peer_addr_len);
-extern void conn_free_crypto(struct drbd_tconn *tconn);
+extern struct drbd_resource *drbd_find_resource(const char *name);
+extern void drbd_destroy_resource(struct kref *kref);
+extern void conn_free_crypto(struct drbd_connection *connection);
extern int proc_details;
/* drbd_req */
extern void do_submit(struct work_struct *ws);
-extern void __drbd_make_request(struct drbd_conf *, struct bio *, unsigned long);
+extern void __drbd_make_request(struct drbd_device *, struct bio *, unsigned long);
extern void drbd_make_request(struct request_queue *q, struct bio *bio);
-extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req);
+extern int drbd_read_remote(struct drbd_device *device, struct drbd_request *req);
extern int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec);
extern int is_valid_ar_handle(struct drbd_request *, sector_t);
/* drbd_nl.c */
extern int drbd_msg_put_info(const char *info);
-extern void drbd_suspend_io(struct drbd_conf *mdev);
-extern void drbd_resume_io(struct drbd_conf *mdev);
+extern void drbd_suspend_io(struct drbd_device *device);
+extern void drbd_resume_io(struct drbd_device *device);
extern char *ppsize(char *buf, unsigned long long size);
-extern sector_t drbd_new_dev_size(struct drbd_conf *, struct drbd_backing_dev *, sector_t, int);
+extern sector_t drbd_new_dev_size(struct drbd_device *, struct drbd_backing_dev *, sector_t, int);
enum determine_dev_size {
DS_ERROR_SHRINK = -3,
DS_ERROR_SPACE_MD = -2,
@@ -1478,48 +1272,47 @@ enum determine_dev_size {
DS_GREW_FROM_ZERO = 3,
};
extern enum determine_dev_size
-drbd_determine_dev_size(struct drbd_conf *, enum dds_flags, struct resize_parms *) __must_hold(local);
-extern void resync_after_online_grow(struct drbd_conf *);
-extern void drbd_reconsider_max_bio_size(struct drbd_conf *mdev);
-extern enum drbd_state_rv drbd_set_role(struct drbd_conf *mdev,
+drbd_determine_dev_size(struct drbd_device *, enum dds_flags, struct resize_parms *) __must_hold(local);
+extern void resync_after_online_grow(struct drbd_device *);
+extern void drbd_reconsider_max_bio_size(struct drbd_device *device);
+extern enum drbd_state_rv drbd_set_role(struct drbd_device *device,
enum drbd_role new_role,
int force);
-extern bool conn_try_outdate_peer(struct drbd_tconn *tconn);
-extern void conn_try_outdate_peer_async(struct drbd_tconn *tconn);
-extern int drbd_khelper(struct drbd_conf *mdev, char *cmd);
+extern bool conn_try_outdate_peer(struct drbd_connection *connection);
+extern void conn_try_outdate_peer_async(struct drbd_connection *connection);
+extern int drbd_khelper(struct drbd_device *device, char *cmd);
/* drbd_worker.c */
extern int drbd_worker(struct drbd_thread *thi);
-enum drbd_ret_code drbd_resync_after_valid(struct drbd_conf *mdev, int o_minor);
-void drbd_resync_after_changed(struct drbd_conf *mdev);
-extern void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side);
-extern void resume_next_sg(struct drbd_conf *mdev);
-extern void suspend_other_sg(struct drbd_conf *mdev);
-extern int drbd_resync_finished(struct drbd_conf *mdev);
+enum drbd_ret_code drbd_resync_after_valid(struct drbd_device *device, int o_minor);
+void drbd_resync_after_changed(struct drbd_device *device);
+extern void drbd_start_resync(struct drbd_device *device, enum drbd_conns side);
+extern void resume_next_sg(struct drbd_device *device);
+extern void suspend_other_sg(struct drbd_device *device);
+extern int drbd_resync_finished(struct drbd_device *device);
/* maybe rather drbd_main.c ? */
-extern void *drbd_md_get_buffer(struct drbd_conf *mdev);
-extern void drbd_md_put_buffer(struct drbd_conf *mdev);
-extern int drbd_md_sync_page_io(struct drbd_conf *mdev,
+extern void *drbd_md_get_buffer(struct drbd_device *device);
+extern void drbd_md_put_buffer(struct drbd_device *device);
+extern int drbd_md_sync_page_io(struct drbd_device *device,
struct drbd_backing_dev *bdev, sector_t sector, int rw);
-extern void drbd_ov_out_of_sync_found(struct drbd_conf *, sector_t, int);
-extern void wait_until_done_or_force_detached(struct drbd_conf *mdev,
+extern void drbd_ov_out_of_sync_found(struct drbd_device *, sector_t, int);
+extern void wait_until_done_or_force_detached(struct drbd_device *device,
struct drbd_backing_dev *bdev, unsigned int *done);
-extern void drbd_rs_controller_reset(struct drbd_conf *mdev);
+extern void drbd_rs_controller_reset(struct drbd_device *device);
-static inline void ov_out_of_sync_print(struct drbd_conf *mdev)
+static inline void ov_out_of_sync_print(struct drbd_device *device)
{
- if (mdev->ov_last_oos_size) {
- dev_err(DEV, "Out of sync: start=%llu, size=%lu (sectors)\n",
- (unsigned long long)mdev->ov_last_oos_start,
- (unsigned long)mdev->ov_last_oos_size);
+ if (device->ov_last_oos_size) {
+ drbd_err(device, "Out of sync: start=%llu, size=%lu (sectors)\n",
+ (unsigned long long)device->ov_last_oos_start,
+ (unsigned long)device->ov_last_oos_size);
}
- mdev->ov_last_oos_size=0;
+ device->ov_last_oos_size = 0;
}
-extern void drbd_csum_bio(struct drbd_conf *, struct crypto_hash *, struct bio *, void *);
-extern void drbd_csum_ee(struct drbd_conf *, struct crypto_hash *,
- struct drbd_peer_request *, void *);
+extern void drbd_csum_bio(struct crypto_hash *, struct bio *, void *);
+extern void drbd_csum_ee(struct crypto_hash *, struct drbd_peer_request *, void *);
/* worker callbacks */
extern int w_e_end_data_req(struct drbd_work *, int);
extern int w_e_end_rsdata_req(struct drbd_work *, int);
@@ -1529,10 +1322,8 @@ extern int w_e_end_ov_req(struct drbd_work *, int);
extern int w_ov_finished(struct drbd_work *, int);
extern int w_resync_timer(struct drbd_work *, int);
extern int w_send_write_hint(struct drbd_work *, int);
-extern int w_make_resync_request(struct drbd_work *, int);
extern int w_send_dblock(struct drbd_work *, int);
extern int w_send_read_req(struct drbd_work *, int);
-extern int w_prev_work_done(struct drbd_work *, int);
extern int w_e_reissue(struct drbd_work *, int);
extern int w_restart_disk_io(struct drbd_work *, int);
extern int w_send_out_of_sync(struct drbd_work *, int);
@@ -1542,27 +1333,24 @@ extern void resync_timer_fn(unsigned long data);
extern void start_resync_timer_fn(unsigned long data);
/* drbd_receiver.c */
-extern int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector);
-extern int drbd_submit_peer_request(struct drbd_conf *,
+extern int drbd_receiver(struct drbd_thread *thi);
+extern int drbd_asender(struct drbd_thread *thi);
+extern int drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector);
+extern int drbd_submit_peer_request(struct drbd_device *,
struct drbd_peer_request *, const unsigned,
const int);
-extern int drbd_free_peer_reqs(struct drbd_conf *, struct list_head *);
-extern struct drbd_peer_request *drbd_alloc_peer_req(struct drbd_conf *, u64,
+extern int drbd_free_peer_reqs(struct drbd_device *, struct list_head *);
+extern struct drbd_peer_request *drbd_alloc_peer_req(struct drbd_peer_device *, u64,
sector_t, unsigned int,
gfp_t) __must_hold(local);
-extern void __drbd_free_peer_req(struct drbd_conf *, struct drbd_peer_request *,
+extern void __drbd_free_peer_req(struct drbd_device *, struct drbd_peer_request *,
int);
#define drbd_free_peer_req(m,e) __drbd_free_peer_req(m, e, 0)
#define drbd_free_net_peer_req(m,e) __drbd_free_peer_req(m, e, 1)
-extern struct page *drbd_alloc_pages(struct drbd_conf *, unsigned int, bool);
-extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled);
-extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed);
-extern void conn_flush_workqueue(struct drbd_tconn *tconn);
-extern int drbd_connected(struct drbd_conf *mdev);
-static inline void drbd_flush_workqueue(struct drbd_conf *mdev)
-{
- conn_flush_workqueue(mdev->tconn);
-}
+extern struct page *drbd_alloc_pages(struct drbd_peer_device *, unsigned int, bool);
+extern void drbd_set_recv_tcq(struct drbd_device *device, int tcq_enabled);
+extern void _drbd_clear_done_ee(struct drbd_device *device, struct list_head *to_be_freed);
+extern int drbd_connected(struct drbd_peer_device *);
/* Yes, there is kernel_setsockopt, but only since 2.6.18.
* So we have our own copy of it here. */
@@ -1613,7 +1401,7 @@ static inline void drbd_tcp_quickack(struct socket *sock)
(char*)&val, sizeof(val));
}
-void drbd_bump_write_ordering(struct drbd_tconn *tconn, enum write_ordering_e wo);
+void drbd_bump_write_ordering(struct drbd_connection *connection, enum write_ordering_e wo);
/* drbd_proc.c */
extern struct proc_dir_entry *drbd_proc;
@@ -1622,29 +1410,29 @@ extern const char *drbd_conn_str(enum drbd_conns s);
extern const char *drbd_role_str(enum drbd_role s);
/* drbd_actlog.c */
-extern int drbd_al_begin_io_nonblock(struct drbd_conf *mdev, struct drbd_interval *i);
-extern void drbd_al_begin_io_commit(struct drbd_conf *mdev, bool delegate);
-extern bool drbd_al_begin_io_fastpath(struct drbd_conf *mdev, struct drbd_interval *i);
-extern void drbd_al_begin_io(struct drbd_conf *mdev, struct drbd_interval *i, bool delegate);
-extern void drbd_al_complete_io(struct drbd_conf *mdev, struct drbd_interval *i);
-extern void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector);
-extern int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector);
-extern int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector);
-extern void drbd_rs_cancel_all(struct drbd_conf *mdev);
-extern int drbd_rs_del_all(struct drbd_conf *mdev);
-extern void drbd_rs_failed_io(struct drbd_conf *mdev,
+extern int drbd_al_begin_io_nonblock(struct drbd_device *device, struct drbd_interval *i);
+extern void drbd_al_begin_io_commit(struct drbd_device *device, bool delegate);
+extern bool drbd_al_begin_io_fastpath(struct drbd_device *device, struct drbd_interval *i);
+extern void drbd_al_begin_io(struct drbd_device *device, struct drbd_interval *i, bool delegate);
+extern void drbd_al_complete_io(struct drbd_device *device, struct drbd_interval *i);
+extern void drbd_rs_complete_io(struct drbd_device *device, sector_t sector);
+extern int drbd_rs_begin_io(struct drbd_device *device, sector_t sector);
+extern int drbd_try_rs_begin_io(struct drbd_device *device, sector_t sector);
+extern void drbd_rs_cancel_all(struct drbd_device *device);
+extern int drbd_rs_del_all(struct drbd_device *device);
+extern void drbd_rs_failed_io(struct drbd_device *device,
sector_t sector, int size);
-extern void drbd_advance_rs_marks(struct drbd_conf *mdev, unsigned long still_to_go);
-extern void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector,
+extern void drbd_advance_rs_marks(struct drbd_device *device, unsigned long still_to_go);
+extern void __drbd_set_in_sync(struct drbd_device *device, sector_t sector,
int size, const char *file, const unsigned int line);
-#define drbd_set_in_sync(mdev, sector, size) \
- __drbd_set_in_sync(mdev, sector, size, __FILE__, __LINE__)
-extern int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector,
+#define drbd_set_in_sync(device, sector, size) \
+ __drbd_set_in_sync(device, sector, size, __FILE__, __LINE__)
+extern int __drbd_set_out_of_sync(struct drbd_device *device, sector_t sector,
int size, const char *file, const unsigned int line);
-#define drbd_set_out_of_sync(mdev, sector, size) \
- __drbd_set_out_of_sync(mdev, sector, size, __FILE__, __LINE__)
-extern void drbd_al_shrink(struct drbd_conf *mdev);
-extern int drbd_initialize_al(struct drbd_conf *, void *);
+#define drbd_set_out_of_sync(device, sector, size) \
+ __drbd_set_out_of_sync(device, sector, size, __FILE__, __LINE__)
+extern void drbd_al_shrink(struct drbd_device *device);
+extern int drbd_initialize_al(struct drbd_device *, void *);
/* drbd_nl.c */
/* state info broadcast */
@@ -1661,7 +1449,7 @@ struct sib_info {
};
};
};
-void drbd_bcast_event(struct drbd_conf *mdev, const struct sib_info *sib);
+void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib);
/*
* inline helper functions
@@ -1690,26 +1478,27 @@ static inline int drbd_peer_req_has_active_page(struct drbd_peer_request *peer_r
}
static inline enum drbd_state_rv
-_drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
+_drbd_set_state(struct drbd_device *device, union drbd_state ns,
enum chg_state_flags flags, struct completion *done)
{
enum drbd_state_rv rv;
read_lock(&global_state_lock);
- rv = __drbd_set_state(mdev, ns, flags, done);
+ rv = __drbd_set_state(device, ns, flags, done);
read_unlock(&global_state_lock);
return rv;
}
-static inline union drbd_state drbd_read_state(struct drbd_conf *mdev)
+static inline union drbd_state drbd_read_state(struct drbd_device *device)
{
+ struct drbd_resource *resource = device->resource;
union drbd_state rv;
- rv.i = mdev->state.i;
- rv.susp = mdev->tconn->susp;
- rv.susp_nod = mdev->tconn->susp_nod;
- rv.susp_fen = mdev->tconn->susp_fen;
+ rv.i = device->state.i;
+ rv.susp = resource->susp;
+ rv.susp_nod = resource->susp_nod;
+ rv.susp_fen = resource->susp_fen;
return rv;
}
@@ -1722,22 +1511,22 @@ enum drbd_force_detach_flags {
};
#define __drbd_chk_io_error(m,f) __drbd_chk_io_error_(m,f, __func__)
-static inline void __drbd_chk_io_error_(struct drbd_conf *mdev,
+static inline void __drbd_chk_io_error_(struct drbd_device *device,
enum drbd_force_detach_flags df,
const char *where)
{
enum drbd_io_error_p ep;
rcu_read_lock();
- ep = rcu_dereference(mdev->ldev->disk_conf)->on_io_error;
+ ep = rcu_dereference(device->ldev->disk_conf)->on_io_error;
rcu_read_unlock();
switch (ep) {
case EP_PASS_ON: /* FIXME would this be better named "Ignore"? */
if (df == DRBD_READ_ERROR || df == DRBD_WRITE_ERROR) {
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Local IO failed in %s.\n", where);
- if (mdev->state.disk > D_INCONSISTENT)
- _drbd_set_state(_NS(mdev, disk, D_INCONSISTENT), CS_HARD, NULL);
+ drbd_err(device, "Local IO failed in %s.\n", where);
+ if (device->state.disk > D_INCONSISTENT)
+ _drbd_set_state(_NS(device, disk, D_INCONSISTENT), CS_HARD, NULL);
break;
}
/* NOTE fall through for DRBD_META_IO_ERROR or DRBD_FORCE_DETACH */
@@ -1763,14 +1552,14 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev,
* we read meta data only once during attach,
* which will fail in case of errors.
*/
- set_bit(WAS_IO_ERROR, &mdev->flags);
+ set_bit(WAS_IO_ERROR, &device->flags);
if (df == DRBD_READ_ERROR)
- set_bit(WAS_READ_ERROR, &mdev->flags);
+ set_bit(WAS_READ_ERROR, &device->flags);
if (df == DRBD_FORCE_DETACH)
- set_bit(FORCE_DETACH, &mdev->flags);
- if (mdev->state.disk > D_FAILED) {
- _drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
- dev_err(DEV,
+ set_bit(FORCE_DETACH, &device->flags);
+ if (device->state.disk > D_FAILED) {
+ _drbd_set_state(_NS(device, disk, D_FAILED), CS_HARD, NULL);
+ drbd_err(device,
"Local IO failed in %s. Detaching...\n", where);
}
break;
@@ -1779,21 +1568,21 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev,
/**
* drbd_chk_io_error: Handle the on_io_error setting, should be called from all io completion handlers
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @error: Error code passed to the IO completion callback
* @forcedetach: Force detach. I.e. the error happened while accessing the meta data
*
* See also drbd_main.c:after_state_ch() if (os.disk > D_FAILED && ns.disk == D_FAILED)
*/
#define drbd_chk_io_error(m,e,f) drbd_chk_io_error_(m,e,f, __func__)
-static inline void drbd_chk_io_error_(struct drbd_conf *mdev,
+static inline void drbd_chk_io_error_(struct drbd_device *device,
int error, enum drbd_force_detach_flags forcedetach, const char *where)
{
if (error) {
unsigned long flags;
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- __drbd_chk_io_error_(mdev, forcedetach, where);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ __drbd_chk_io_error_(device, forcedetach, where);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
}
}
@@ -1916,31 +1705,33 @@ drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w)
wake_up(&q->q_wait);
}
-static inline void wake_asender(struct drbd_tconn *tconn)
+extern void drbd_flush_workqueue(struct drbd_work_queue *work_queue);
+
+static inline void wake_asender(struct drbd_connection *connection)
{
- if (test_bit(SIGNAL_ASENDER, &tconn->flags))
- force_sig(DRBD_SIG, tconn->asender.task);
+ if (test_bit(SIGNAL_ASENDER, &connection->flags))
+ force_sig(DRBD_SIG, connection->asender.task);
}
-static inline void request_ping(struct drbd_tconn *tconn)
+static inline void request_ping(struct drbd_connection *connection)
{
- set_bit(SEND_PING, &tconn->flags);
- wake_asender(tconn);
+ set_bit(SEND_PING, &connection->flags);
+ wake_asender(connection);
}
-extern void *conn_prepare_command(struct drbd_tconn *, struct drbd_socket *);
-extern void *drbd_prepare_command(struct drbd_conf *, struct drbd_socket *);
-extern int conn_send_command(struct drbd_tconn *, struct drbd_socket *,
+extern void *conn_prepare_command(struct drbd_connection *, struct drbd_socket *);
+extern void *drbd_prepare_command(struct drbd_peer_device *, struct drbd_socket *);
+extern int conn_send_command(struct drbd_connection *, struct drbd_socket *,
enum drbd_packet, unsigned int, void *,
unsigned int);
-extern int drbd_send_command(struct drbd_conf *, struct drbd_socket *,
+extern int drbd_send_command(struct drbd_peer_device *, struct drbd_socket *,
enum drbd_packet, unsigned int, void *,
unsigned int);
-extern int drbd_send_ping(struct drbd_tconn *tconn);
-extern int drbd_send_ping_ack(struct drbd_tconn *tconn);
-extern int drbd_send_state_req(struct drbd_conf *, union drbd_state, union drbd_state);
-extern int conn_send_state_req(struct drbd_tconn *, union drbd_state, union drbd_state);
+extern int drbd_send_ping(struct drbd_connection *connection);
+extern int drbd_send_ping_ack(struct drbd_connection *connection);
+extern int drbd_send_state_req(struct drbd_peer_device *, union drbd_state, union drbd_state);
+extern int conn_send_state_req(struct drbd_connection *, union drbd_state, union drbd_state);
static inline void drbd_thread_stop(struct drbd_thread *thi)
{
@@ -1979,22 +1770,22 @@ static inline void drbd_thread_restart_nowait(struct drbd_thread *thi)
* _req_mod(req, CONNECTION_LOST_WHILE_PENDING)
* [from tl_clear_barrier]
*/
-static inline void inc_ap_pending(struct drbd_conf *mdev)
+static inline void inc_ap_pending(struct drbd_device *device)
{
- atomic_inc(&mdev->ap_pending_cnt);
+ atomic_inc(&device->ap_pending_cnt);
}
#define ERR_IF_CNT_IS_NEGATIVE(which, func, line) \
- if (atomic_read(&mdev->which) < 0) \
- dev_err(DEV, "in %s:%d: " #which " = %d < 0 !\n", \
+ if (atomic_read(&device->which) < 0) \
+ drbd_err(device, "in %s:%d: " #which " = %d < 0 !\n", \
func, line, \
- atomic_read(&mdev->which))
+ atomic_read(&device->which))
-#define dec_ap_pending(mdev) _dec_ap_pending(mdev, __FUNCTION__, __LINE__)
-static inline void _dec_ap_pending(struct drbd_conf *mdev, const char *func, int line)
+#define dec_ap_pending(device) _dec_ap_pending(device, __FUNCTION__, __LINE__)
+static inline void _dec_ap_pending(struct drbd_device *device, const char *func, int line)
{
- if (atomic_dec_and_test(&mdev->ap_pending_cnt))
- wake_up(&mdev->misc_wait);
+ if (atomic_dec_and_test(&device->ap_pending_cnt))
+ wake_up(&device->misc_wait);
ERR_IF_CNT_IS_NEGATIVE(ap_pending_cnt, func, line);
}
@@ -2004,15 +1795,15 @@ static inline void _dec_ap_pending(struct drbd_conf *mdev, const char *func, int
* C_SYNC_SOURCE sends P_RS_DATA_REPLY (and expects P_WRITE_ACK with ID_SYNCER)
* (or P_NEG_ACK with ID_SYNCER)
*/
-static inline void inc_rs_pending(struct drbd_conf *mdev)
+static inline void inc_rs_pending(struct drbd_device *device)
{
- atomic_inc(&mdev->rs_pending_cnt);
+ atomic_inc(&device->rs_pending_cnt);
}
-#define dec_rs_pending(mdev) _dec_rs_pending(mdev, __FUNCTION__, __LINE__)
-static inline void _dec_rs_pending(struct drbd_conf *mdev, const char *func, int line)
+#define dec_rs_pending(device) _dec_rs_pending(device, __FUNCTION__, __LINE__)
+static inline void _dec_rs_pending(struct drbd_device *device, const char *func, int line)
{
- atomic_dec(&mdev->rs_pending_cnt);
+ atomic_dec(&device->rs_pending_cnt);
ERR_IF_CNT_IS_NEGATIVE(rs_pending_cnt, func, line);
}
@@ -2025,103 +1816,104 @@ static inline void _dec_rs_pending(struct drbd_conf *mdev, const char *func, int
* receive_DataRequest (receive_RSDataRequest) we need to send back P_DATA
* receive_Barrier_* we need to send a P_BARRIER_ACK
*/
-static inline void inc_unacked(struct drbd_conf *mdev)
+static inline void inc_unacked(struct drbd_device *device)
{
- atomic_inc(&mdev->unacked_cnt);
+ atomic_inc(&device->unacked_cnt);
}
-#define dec_unacked(mdev) _dec_unacked(mdev, __FUNCTION__, __LINE__)
-static inline void _dec_unacked(struct drbd_conf *mdev, const char *func, int line)
+#define dec_unacked(device) _dec_unacked(device, __FUNCTION__, __LINE__)
+static inline void _dec_unacked(struct drbd_device *device, const char *func, int line)
{
- atomic_dec(&mdev->unacked_cnt);
+ atomic_dec(&device->unacked_cnt);
ERR_IF_CNT_IS_NEGATIVE(unacked_cnt, func, line);
}
-#define sub_unacked(mdev, n) _sub_unacked(mdev, n, __FUNCTION__, __LINE__)
-static inline void _sub_unacked(struct drbd_conf *mdev, int n, const char *func, int line)
+#define sub_unacked(device, n) _sub_unacked(device, n, __FUNCTION__, __LINE__)
+static inline void _sub_unacked(struct drbd_device *device, int n, const char *func, int line)
{
- atomic_sub(n, &mdev->unacked_cnt);
+ atomic_sub(n, &device->unacked_cnt);
ERR_IF_CNT_IS_NEGATIVE(unacked_cnt, func, line);
}
/**
- * get_ldev() - Increase the ref count on mdev->ldev. Returns 0 if there is no ldev
+ * get_ldev() - Increase the ref count on device->ldev. Returns 0 if there is no ldev
* @M: DRBD device.
*
- * You have to call put_ldev() when finished working with mdev->ldev.
+ * You have to call put_ldev() when finished working with device->ldev.
*/
#define get_ldev(M) __cond_lock(local, _get_ldev_if_state(M,D_INCONSISTENT))
#define get_ldev_if_state(M,MINS) __cond_lock(local, _get_ldev_if_state(M,MINS))
-static inline void put_ldev(struct drbd_conf *mdev)
+static inline void put_ldev(struct drbd_device *device)
{
- int i = atomic_dec_return(&mdev->local_cnt);
+ int i = atomic_dec_return(&device->local_cnt);
/* This may be called from some endio handler,
* so we must not sleep here. */
__release(local);
- D_ASSERT(i >= 0);
+ D_ASSERT(device, i >= 0);
if (i == 0) {
- if (mdev->state.disk == D_DISKLESS)
+ if (device->state.disk == D_DISKLESS)
/* even internal references gone, safe to destroy */
- drbd_ldev_destroy(mdev);
- if (mdev->state.disk == D_FAILED) {
+ drbd_ldev_destroy(device);
+ if (device->state.disk == D_FAILED) {
/* all application IO references gone. */
- if (!test_and_set_bit(GO_DISKLESS, &mdev->flags))
- drbd_queue_work(&mdev->tconn->sender_work, &mdev->go_diskless);
+ if (!test_and_set_bit(GO_DISKLESS, &device->flags))
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &device->go_diskless);
}
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
}
}
#ifndef __CHECKER__
-static inline int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins)
+static inline int _get_ldev_if_state(struct drbd_device *device, enum drbd_disk_state mins)
{
int io_allowed;
/* never get a reference while D_DISKLESS */
- if (mdev->state.disk == D_DISKLESS)
+ if (device->state.disk == D_DISKLESS)
return 0;
- atomic_inc(&mdev->local_cnt);
- io_allowed = (mdev->state.disk >= mins);
+ atomic_inc(&device->local_cnt);
+ io_allowed = (device->state.disk >= mins);
if (!io_allowed)
- put_ldev(mdev);
+ put_ldev(device);
return io_allowed;
}
#else
-extern int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins);
+extern int _get_ldev_if_state(struct drbd_device *device, enum drbd_disk_state mins);
#endif
/* you must have an "get_ldev" reference */
-static inline void drbd_get_syncer_progress(struct drbd_conf *mdev,
+static inline void drbd_get_syncer_progress(struct drbd_device *device,
unsigned long *bits_left, unsigned int *per_mil_done)
{
/* this is to break it at compile time when we change that, in case we
* want to support more than (1<<32) bits on a 32bit arch. */
- typecheck(unsigned long, mdev->rs_total);
+ typecheck(unsigned long, device->rs_total);
/* note: both rs_total and rs_left are in bits, i.e. in
* units of BM_BLOCK_SIZE.
* for the percentage, we don't care. */
- if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
- *bits_left = mdev->ov_left;
+ if (device->state.conn == C_VERIFY_S || device->state.conn == C_VERIFY_T)
+ *bits_left = device->ov_left;
else
- *bits_left = drbd_bm_total_weight(mdev) - mdev->rs_failed;
+ *bits_left = drbd_bm_total_weight(device) - device->rs_failed;
/* >> 10 to prevent overflow,
* +1 to prevent division by zero */
- if (*bits_left > mdev->rs_total) {
+ if (*bits_left > device->rs_total) {
/* doh. maybe a logic bug somewhere.
* may also be just a race condition
* between this and a disconnect during sync.
* for now, just prevent in-kernel buffer overflow.
*/
smp_rmb();
- dev_warn(DEV, "cs:%s rs_left=%lu > rs_total=%lu (rs_failed %lu)\n",
- drbd_conn_str(mdev->state.conn),
- *bits_left, mdev->rs_total, mdev->rs_failed);
+ drbd_warn(device, "cs:%s rs_left=%lu > rs_total=%lu (rs_failed %lu)\n",
+ drbd_conn_str(device->state.conn),
+ *bits_left, device->rs_total, device->rs_failed);
*per_mil_done = 0;
} else {
/* Make sure the division happens in long context.
@@ -2133,9 +1925,9 @@ static inline void drbd_get_syncer_progress(struct drbd_conf *mdev,
* Note: currently we don't support such large bitmaps on 32bit
* arch anyways, but no harm done to be prepared for it here.
*/
- unsigned int shift = mdev->rs_total > UINT_MAX ? 16 : 10;
+ unsigned int shift = device->rs_total > UINT_MAX ? 16 : 10;
unsigned long left = *bits_left >> shift;
- unsigned long total = 1UL + (mdev->rs_total >> shift);
+ unsigned long total = 1UL + (device->rs_total >> shift);
unsigned long tmp = 1000UL - left * 1000UL/total;
*per_mil_done = tmp;
}
@@ -2145,22 +1937,22 @@ static inline void drbd_get_syncer_progress(struct drbd_conf *mdev,
/* this throttles on-the-fly application requests
* according to max_buffers settings;
* maybe re-implement using semaphores? */
-static inline int drbd_get_max_buffers(struct drbd_conf *mdev)
+static inline int drbd_get_max_buffers(struct drbd_device *device)
{
struct net_conf *nc;
int mxb;
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
mxb = nc ? nc->max_buffers : 1000000; /* arbitrary limit on open requests */
rcu_read_unlock();
return mxb;
}
-static inline int drbd_state_is_stable(struct drbd_conf *mdev)
+static inline int drbd_state_is_stable(struct drbd_device *device)
{
- union drbd_dev_state s = mdev->state;
+ union drbd_dev_state s = device->state;
/* DO NOT add a default clause, we want the compiler to warn us
* for any newly introduced state we may have forgotten to add here */
@@ -2194,7 +1986,7 @@ static inline int drbd_state_is_stable(struct drbd_conf *mdev)
/* Allow IO in BM exchange states with new protocols */
case C_WF_BITMAP_S:
- if (mdev->tconn->agreed_pro_version < 96)
+ if (first_peer_device(device)->connection->agreed_pro_version < 96)
return 0;
break;
@@ -2228,20 +2020,20 @@ static inline int drbd_state_is_stable(struct drbd_conf *mdev)
return 1;
}
-static inline int drbd_suspended(struct drbd_conf *mdev)
+static inline int drbd_suspended(struct drbd_device *device)
{
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_resource *resource = device->resource;
- return tconn->susp || tconn->susp_fen || tconn->susp_nod;
+ return resource->susp || resource->susp_fen || resource->susp_nod;
}
-static inline bool may_inc_ap_bio(struct drbd_conf *mdev)
+static inline bool may_inc_ap_bio(struct drbd_device *device)
{
- int mxb = drbd_get_max_buffers(mdev);
+ int mxb = drbd_get_max_buffers(device);
- if (drbd_suspended(mdev))
+ if (drbd_suspended(device))
return false;
- if (test_bit(SUSPEND_IO, &mdev->flags))
+ if (test_bit(SUSPEND_IO, &device->flags))
return false;
/* to avoid potential deadlock or bitmap corruption,
@@ -2249,32 +2041,32 @@ static inline bool may_inc_ap_bio(struct drbd_conf *mdev)
* to start during "stable" states. */
/* no new io accepted when attaching or detaching the disk */
- if (!drbd_state_is_stable(mdev))
+ if (!drbd_state_is_stable(device))
return false;
/* since some older kernels don't have atomic_add_unless,
* and we are within the spinlock anyways, we have this workaround. */
- if (atomic_read(&mdev->ap_bio_cnt) > mxb)
+ if (atomic_read(&device->ap_bio_cnt) > mxb)
return false;
- if (test_bit(BITMAP_IO, &mdev->flags))
+ if (test_bit(BITMAP_IO, &device->flags))
return false;
return true;
}
-static inline bool inc_ap_bio_cond(struct drbd_conf *mdev)
+static inline bool inc_ap_bio_cond(struct drbd_device *device)
{
bool rv = false;
- spin_lock_irq(&mdev->tconn->req_lock);
- rv = may_inc_ap_bio(mdev);
+ spin_lock_irq(&device->resource->req_lock);
+ rv = may_inc_ap_bio(device);
if (rv)
- atomic_inc(&mdev->ap_bio_cnt);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ atomic_inc(&device->ap_bio_cnt);
+ spin_unlock_irq(&device->resource->req_lock);
return rv;
}
-static inline void inc_ap_bio(struct drbd_conf *mdev)
+static inline void inc_ap_bio(struct drbd_device *device)
{
/* we wait here
* as long as the device is suspended
@@ -2284,42 +2076,44 @@ static inline void inc_ap_bio(struct drbd_conf *mdev)
* to avoid races with the reconnect code,
* we need to atomic_inc within the spinlock. */
- wait_event(mdev->misc_wait, inc_ap_bio_cond(mdev));
+ wait_event(device->misc_wait, inc_ap_bio_cond(device));
}
-static inline void dec_ap_bio(struct drbd_conf *mdev)
+static inline void dec_ap_bio(struct drbd_device *device)
{
- int mxb = drbd_get_max_buffers(mdev);
- int ap_bio = atomic_dec_return(&mdev->ap_bio_cnt);
+ int mxb = drbd_get_max_buffers(device);
+ int ap_bio = atomic_dec_return(&device->ap_bio_cnt);
- D_ASSERT(ap_bio >= 0);
+ D_ASSERT(device, ap_bio >= 0);
- if (ap_bio == 0 && test_bit(BITMAP_IO, &mdev->flags)) {
- if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags))
- drbd_queue_work(&mdev->tconn->sender_work, &mdev->bm_io_work.w);
+ if (ap_bio == 0 && test_bit(BITMAP_IO, &device->flags)) {
+ if (!test_and_set_bit(BITMAP_IO_QUEUED, &device->flags))
+ drbd_queue_work(&first_peer_device(device)->
+ connection->sender_work,
+ &device->bm_io_work.w);
}
/* this currently does wake_up for every dec_ap_bio!
* maybe rather introduce some type of hysteresis?
* e.g. (ap_bio == mxb/2 || ap_bio == 0) ? */
if (ap_bio < mxb)
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
}
-static inline bool verify_can_do_stop_sector(struct drbd_conf *mdev)
+static inline bool verify_can_do_stop_sector(struct drbd_device *device)
{
- return mdev->tconn->agreed_pro_version >= 97 &&
- mdev->tconn->agreed_pro_version != 100;
+ return first_peer_device(device)->connection->agreed_pro_version >= 97 &&
+ first_peer_device(device)->connection->agreed_pro_version != 100;
}
-static inline int drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val)
+static inline int drbd_set_ed_uuid(struct drbd_device *device, u64 val)
{
- int changed = mdev->ed_uuid != val;
- mdev->ed_uuid = val;
+ int changed = device->ed_uuid != val;
+ device->ed_uuid = val;
return changed;
}
-static inline int drbd_queue_order_type(struct drbd_conf *mdev)
+static inline int drbd_queue_order_type(struct drbd_device *device)
{
/* sorry, we currently have no working implementation
* of distributed TCQ stuff */
@@ -2329,23 +2123,29 @@ static inline int drbd_queue_order_type(struct drbd_conf *mdev)
return QUEUE_ORDERED_NONE;
}
-static inline void drbd_md_flush(struct drbd_conf *mdev)
+static inline void drbd_md_flush(struct drbd_device *device)
{
int r;
- if (mdev->ldev == NULL) {
- dev_warn(DEV, "mdev->ldev == NULL in drbd_md_flush\n");
+ if (device->ldev == NULL) {
+ drbd_warn(device, "device->ldev == NULL in drbd_md_flush\n");
return;
}
- if (test_bit(MD_NO_FUA, &mdev->flags))
+ if (test_bit(MD_NO_FUA, &device->flags))
return;
- r = blkdev_issue_flush(mdev->ldev->md_bdev, GFP_NOIO, NULL);
+ r = blkdev_issue_flush(device->ldev->md_bdev, GFP_NOIO, NULL);
if (r) {
- set_bit(MD_NO_FUA, &mdev->flags);
- dev_err(DEV, "meta data flush failed with status %d, disabling md-flushes\n", r);
+ set_bit(MD_NO_FUA, &device->flags);
+ drbd_err(device, "meta data flush failed with status %d, disabling md-flushes\n", r);
}
}
+static inline struct drbd_connection *first_connection(struct drbd_resource *resource)
+{
+ return list_first_entry(&resource->connections,
+ struct drbd_connection, connections);
+}
+
#endif
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 929468e1512a..331e5cc1227d 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -52,16 +52,12 @@
#include <linux/drbd_limits.h>
#include "drbd_int.h"
+#include "drbd_protocol.h"
#include "drbd_req.h" /* only for _req_mod in tl_release and tl_clear */
#include "drbd_vli.h"
static DEFINE_MUTEX(drbd_main_mutex);
-int drbdd_init(struct drbd_thread *);
-int drbd_worker(struct drbd_thread *);
-int drbd_asender(struct drbd_thread *);
-
-int drbd_init(void);
static int drbd_open(struct block_device *bdev, fmode_t mode);
static void drbd_release(struct gendisk *gd, fmode_t mode);
static int w_md_sync(struct drbd_work *w, int unused);
@@ -118,8 +114,8 @@ module_param_string(usermode_helper, usermode_helper, sizeof(usermode_helper), 0
/* in 2.6.x, our device mapping and config info contains our virtual gendisks
* as member "struct gendisk *vdisk;"
*/
-struct idr minors;
-struct list_head drbd_tconns; /* list of struct drbd_tconn */
+struct idr drbd_devices;
+struct list_head drbd_resources;
struct kmem_cache *drbd_request_cache;
struct kmem_cache *drbd_ee_cache; /* peer requests */
@@ -166,15 +162,15 @@ struct bio *bio_alloc_drbd(gfp_t gfp_mask)
/* When checking with sparse, and this is an inline function, sparse will
give tons of false positives. When this is a real functions sparse works.
*/
-int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins)
+int _get_ldev_if_state(struct drbd_device *device, enum drbd_disk_state mins)
{
int io_allowed;
- atomic_inc(&mdev->local_cnt);
- io_allowed = (mdev->state.disk >= mins);
+ atomic_inc(&device->local_cnt);
+ io_allowed = (device->state.disk >= mins);
if (!io_allowed) {
- if (atomic_dec_and_test(&mdev->local_cnt))
- wake_up(&mdev->misc_wait);
+ if (atomic_dec_and_test(&device->local_cnt))
+ wake_up(&device->misc_wait);
}
return io_allowed;
}
@@ -183,7 +179,7 @@ int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins)
/**
* tl_release() - mark as BARRIER_ACKED all requests in the corresponding transfer log epoch
- * @tconn: DRBD connection.
+ * @connection: DRBD connection.
* @barrier_nr: Expected identifier of the DRBD write barrier packet.
* @set_size: Expected number of requests before that barrier.
*
@@ -191,7 +187,7 @@ int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins)
* epoch of not yet barrier-acked requests, this function will cause a
* termination of the connection.
*/
-void tl_release(struct drbd_tconn *tconn, unsigned int barrier_nr,
+void tl_release(struct drbd_connection *connection, unsigned int barrier_nr,
unsigned int set_size)
{
struct drbd_request *r;
@@ -199,11 +195,11 @@ void tl_release(struct drbd_tconn *tconn, unsigned int barrier_nr,
int expect_epoch = 0;
int expect_size = 0;
- spin_lock_irq(&tconn->req_lock);
+ spin_lock_irq(&connection->resource->req_lock);
/* find oldest not yet barrier-acked write request,
* count writes in its epoch. */
- list_for_each_entry(r, &tconn->transfer_log, tl_requests) {
+ list_for_each_entry(r, &connection->transfer_log, tl_requests) {
const unsigned s = r->rq_state;
if (!req) {
if (!(s & RQ_WRITE))
@@ -228,18 +224,18 @@ void tl_release(struct drbd_tconn *tconn, unsigned int barrier_nr,
/* first some paranoia code */
if (req == NULL) {
- conn_err(tconn, "BAD! BarrierAck #%u received, but no epoch in tl!?\n",
+ drbd_err(connection, "BAD! BarrierAck #%u received, but no epoch in tl!?\n",
barrier_nr);
goto bail;
}
if (expect_epoch != barrier_nr) {
- conn_err(tconn, "BAD! BarrierAck #%u received, expected #%u!\n",
+ drbd_err(connection, "BAD! BarrierAck #%u received, expected #%u!\n",
barrier_nr, expect_epoch);
goto bail;
}
if (expect_size != set_size) {
- conn_err(tconn, "BAD! BarrierAck #%u received with n_writes=%u, expected n_writes=%u!\n",
+ drbd_err(connection, "BAD! BarrierAck #%u received with n_writes=%u, expected n_writes=%u!\n",
barrier_nr, set_size, expect_size);
goto bail;
}
@@ -248,90 +244,91 @@ void tl_release(struct drbd_tconn *tconn, unsigned int barrier_nr,
/* this extra list walk restart is paranoia,
* to catch requests being barrier-acked "unexpectedly".
* It usually should find the same req again, or some READ preceding it. */
- list_for_each_entry(req, &tconn->transfer_log, tl_requests)
+ list_for_each_entry(req, &connection->transfer_log, tl_requests)
if (req->epoch == expect_epoch)
break;
- list_for_each_entry_safe_from(req, r, &tconn->transfer_log, tl_requests) {
+ list_for_each_entry_safe_from(req, r, &connection->transfer_log, tl_requests) {
if (req->epoch != expect_epoch)
break;
_req_mod(req, BARRIER_ACKED);
}
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
return;
bail:
- spin_unlock_irq(&tconn->req_lock);
- conn_request_state(tconn, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
+ spin_unlock_irq(&connection->resource->req_lock);
+ conn_request_state(connection, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
}
/**
* _tl_restart() - Walks the transfer log, and applies an action to all requests
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @what: The action/event to perform with all request objects
*
* @what might be one of CONNECTION_LOST_WHILE_PENDING, RESEND, FAIL_FROZEN_DISK_IO,
* RESTART_FROZEN_DISK_IO.
*/
/* must hold resource->req_lock */
-void _tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what)
+void _tl_restart(struct drbd_connection *connection, enum drbd_req_event what)
{
struct drbd_request *req, *r;
- list_for_each_entry_safe(req, r, &tconn->transfer_log, tl_requests)
+ list_for_each_entry_safe(req, r, &connection->transfer_log, tl_requests)
_req_mod(req, what);
}
-void tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what)
+void tl_restart(struct drbd_connection *connection, enum drbd_req_event what)
{
- spin_lock_irq(&tconn->req_lock);
- _tl_restart(tconn, what);
- spin_unlock_irq(&tconn->req_lock);
+ spin_lock_irq(&connection->resource->req_lock);
+ _tl_restart(connection, what);
+ spin_unlock_irq(&connection->resource->req_lock);
}
/**
* tl_clear() - Clears all requests and &struct drbd_tl_epoch objects out of the TL
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* This is called after the connection to the peer was lost. The storage covered
* by the requests on the transfer gets marked as our of sync. Called from the
* receiver thread and the worker thread.
*/
-void tl_clear(struct drbd_tconn *tconn)
+void tl_clear(struct drbd_connection *connection)
{
- tl_restart(tconn, CONNECTION_LOST_WHILE_PENDING);
+ tl_restart(connection, CONNECTION_LOST_WHILE_PENDING);
}
/**
- * tl_abort_disk_io() - Abort disk I/O for all requests for a certain mdev in the TL
- * @mdev: DRBD device.
+ * tl_abort_disk_io() - Abort disk I/O for all requests for a certain device in the TL
+ * @device: DRBD device.
*/
-void tl_abort_disk_io(struct drbd_conf *mdev)
+void tl_abort_disk_io(struct drbd_device *device)
{
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
struct drbd_request *req, *r;
- spin_lock_irq(&tconn->req_lock);
- list_for_each_entry_safe(req, r, &tconn->transfer_log, tl_requests) {
+ spin_lock_irq(&connection->resource->req_lock);
+ list_for_each_entry_safe(req, r, &connection->transfer_log, tl_requests) {
if (!(req->rq_state & RQ_LOCAL_PENDING))
continue;
- if (req->w.mdev != mdev)
+ if (req->device != device)
continue;
_req_mod(req, ABORT_DISK_IO);
}
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
}
static int drbd_thread_setup(void *arg)
{
struct drbd_thread *thi = (struct drbd_thread *) arg;
- struct drbd_tconn *tconn = thi->tconn;
+ struct drbd_resource *resource = thi->resource;
unsigned long flags;
int retval;
snprintf(current->comm, sizeof(current->comm), "drbd_%c_%s",
- thi->name[0], thi->tconn->name);
+ thi->name[0],
+ resource->name);
restart:
retval = thi->function(thi);
@@ -349,7 +346,7 @@ restart:
*/
if (thi->t_state == RESTARTING) {
- conn_info(tconn, "Restarting %s thread\n", thi->name);
+ drbd_info(resource, "Restarting %s thread\n", thi->name);
thi->t_state = RUNNING;
spin_unlock_irqrestore(&thi->t_lock, flags);
goto restart;
@@ -361,29 +358,32 @@ restart:
complete_all(&thi->stop);
spin_unlock_irqrestore(&thi->t_lock, flags);
- conn_info(tconn, "Terminating %s\n", current->comm);
+ drbd_info(resource, "Terminating %s\n", current->comm);
/* Release mod reference taken when thread was started */
- kref_put(&tconn->kref, &conn_destroy);
+ if (thi->connection)
+ kref_put(&thi->connection->kref, drbd_destroy_connection);
+ kref_put(&resource->kref, drbd_destroy_resource);
module_put(THIS_MODULE);
return retval;
}
-static void drbd_thread_init(struct drbd_tconn *tconn, struct drbd_thread *thi,
- int (*func) (struct drbd_thread *), char *name)
+static void drbd_thread_init(struct drbd_resource *resource, struct drbd_thread *thi,
+ int (*func) (struct drbd_thread *), const char *name)
{
spin_lock_init(&thi->t_lock);
thi->task = NULL;
thi->t_state = NONE;
thi->function = func;
- thi->tconn = tconn;
- strncpy(thi->name, name, ARRAY_SIZE(thi->name));
+ thi->resource = resource;
+ thi->connection = NULL;
+ thi->name = name;
}
int drbd_thread_start(struct drbd_thread *thi)
{
- struct drbd_tconn *tconn = thi->tconn;
+ struct drbd_resource *resource = thi->resource;
struct task_struct *nt;
unsigned long flags;
@@ -393,17 +393,19 @@ int drbd_thread_start(struct drbd_thread *thi)
switch (thi->t_state) {
case NONE:
- conn_info(tconn, "Starting %s thread (from %s [%d])\n",
+ drbd_info(resource, "Starting %s thread (from %s [%d])\n",
thi->name, current->comm, current->pid);
/* Get ref on module for thread - this is released when thread exits */
if (!try_module_get(THIS_MODULE)) {
- conn_err(tconn, "Failed to get module reference in drbd_thread_start\n");
+ drbd_err(resource, "Failed to get module reference in drbd_thread_start\n");
spin_unlock_irqrestore(&thi->t_lock, flags);
return false;
}
- kref_get(&thi->tconn->kref);
+ kref_get(&resource->kref);
+ if (thi->connection)
+ kref_get(&thi->connection->kref);
init_completion(&thi->stop);
thi->reset_cpu_mask = 1;
@@ -412,12 +414,14 @@ int drbd_thread_start(struct drbd_thread *thi)
flush_signals(current); /* otherw. may get -ERESTARTNOINTR */
nt = kthread_create(drbd_thread_setup, (void *) thi,
- "drbd_%c_%s", thi->name[0], thi->tconn->name);
+ "drbd_%c_%s", thi->name[0], thi->resource->name);
if (IS_ERR(nt)) {
- conn_err(tconn, "Couldn't start thread\n");
+ drbd_err(resource, "Couldn't start thread\n");
- kref_put(&tconn->kref, &conn_destroy);
+ if (thi->connection)
+ kref_put(&thi->connection->kref, drbd_destroy_connection);
+ kref_put(&resource->kref, drbd_destroy_resource);
module_put(THIS_MODULE);
return false;
}
@@ -429,7 +433,7 @@ int drbd_thread_start(struct drbd_thread *thi)
break;
case EXITING:
thi->t_state = RESTARTING;
- conn_info(tconn, "Restarting %s thread (from %s [%d])\n",
+ drbd_info(resource, "Restarting %s thread (from %s [%d])\n",
thi->name, current->comm, current->pid);
/* fall through */
case RUNNING:
@@ -478,65 +482,60 @@ void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait)
wait_for_completion(&thi->stop);
}
-static struct drbd_thread *drbd_task_to_thread(struct drbd_tconn *tconn, struct task_struct *task)
-{
- struct drbd_thread *thi =
- task == tconn->receiver.task ? &tconn->receiver :
- task == tconn->asender.task ? &tconn->asender :
- task == tconn->worker.task ? &tconn->worker : NULL;
-
- return thi;
-}
-
-char *drbd_task_to_thread_name(struct drbd_tconn *tconn, struct task_struct *task)
+int conn_lowest_minor(struct drbd_connection *connection)
{
- struct drbd_thread *thi = drbd_task_to_thread(tconn, task);
- return thi ? thi->name : task->comm;
-}
-
-int conn_lowest_minor(struct drbd_tconn *tconn)
-{
- struct drbd_conf *mdev;
- int vnr = 0, m;
+ struct drbd_peer_device *peer_device;
+ int vnr = 0, minor = -1;
rcu_read_lock();
- mdev = idr_get_next(&tconn->volumes, &vnr);
- m = mdev ? mdev_to_minor(mdev) : -1;
+ peer_device = idr_get_next(&connection->peer_devices, &vnr);
+ if (peer_device)
+ minor = device_to_minor(peer_device->device);
rcu_read_unlock();
- return m;
+ return minor;
}
#ifdef CONFIG_SMP
/**
* drbd_calc_cpu_mask() - Generate CPU masks, spread over all CPUs
- * @mdev: DRBD device.
*
- * Forces all threads of a device onto the same CPU. This is beneficial for
+ * Forces all threads of a resource onto the same CPU. This is beneficial for
* DRBD's performance. May be overwritten by user's configuration.
*/
-void drbd_calc_cpu_mask(struct drbd_tconn *tconn)
+static void drbd_calc_cpu_mask(cpumask_var_t *cpu_mask)
{
- int ord, cpu;
+ unsigned int *resources_per_cpu, min_index = ~0;
- /* user override. */
- if (cpumask_weight(tconn->cpu_mask))
- return;
+ resources_per_cpu = kzalloc(nr_cpu_ids * sizeof(*resources_per_cpu), GFP_KERNEL);
+ if (resources_per_cpu) {
+ struct drbd_resource *resource;
+ unsigned int cpu, min = ~0;
- ord = conn_lowest_minor(tconn) % cpumask_weight(cpu_online_mask);
- for_each_online_cpu(cpu) {
- if (ord-- == 0) {
- cpumask_set_cpu(cpu, tconn->cpu_mask);
- return;
+ rcu_read_lock();
+ for_each_resource_rcu(resource, &drbd_resources) {
+ for_each_cpu(cpu, resource->cpu_mask)
+ resources_per_cpu[cpu]++;
}
+ rcu_read_unlock();
+ for_each_online_cpu(cpu) {
+ if (resources_per_cpu[cpu] < min) {
+ min = resources_per_cpu[cpu];
+ min_index = cpu;
+ }
+ }
+ kfree(resources_per_cpu);
}
- /* should not be reached */
- cpumask_setall(tconn->cpu_mask);
+ if (min_index == ~0) {
+ cpumask_setall(*cpu_mask);
+ return;
+ }
+ cpumask_set_cpu(min_index, *cpu_mask);
}
/**
* drbd_thread_current_set_cpu() - modifies the cpu mask of the _current_ thread
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @thi: drbd_thread object
*
* call in the "main loop" of _all_ threads, no need for any mutex, current won't die
@@ -544,13 +543,16 @@ void drbd_calc_cpu_mask(struct drbd_tconn *tconn)
*/
void drbd_thread_current_set_cpu(struct drbd_thread *thi)
{
+ struct drbd_resource *resource = thi->resource;
struct task_struct *p = current;
if (!thi->reset_cpu_mask)
return;
thi->reset_cpu_mask = 0;
- set_cpus_allowed_ptr(p, thi->tconn->cpu_mask);
+ set_cpus_allowed_ptr(p, resource->cpu_mask);
}
+#else
+#define drbd_calc_cpu_mask(A) ({})
#endif
/**
@@ -560,9 +562,9 @@ void drbd_thread_current_set_cpu(struct drbd_thread *thi)
* word aligned on 64-bit architectures. (The bitmap send and receive code
* relies on this.)
*/
-unsigned int drbd_header_size(struct drbd_tconn *tconn)
+unsigned int drbd_header_size(struct drbd_connection *connection)
{
- if (tconn->agreed_pro_version >= 100) {
+ if (connection->agreed_pro_version >= 100) {
BUILD_BUG_ON(!IS_ALIGNED(sizeof(struct p_header100), 8));
return sizeof(struct p_header100);
} else {
@@ -600,44 +602,44 @@ static unsigned int prepare_header100(struct p_header100 *h, enum drbd_packet cm
return sizeof(struct p_header100);
}
-static unsigned int prepare_header(struct drbd_tconn *tconn, int vnr,
+static unsigned int prepare_header(struct drbd_connection *connection, int vnr,
void *buffer, enum drbd_packet cmd, int size)
{
- if (tconn->agreed_pro_version >= 100)
+ if (connection->agreed_pro_version >= 100)
return prepare_header100(buffer, cmd, size, vnr);
- else if (tconn->agreed_pro_version >= 95 &&
+ else if (connection->agreed_pro_version >= 95 &&
size > DRBD_MAX_SIZE_H80_PACKET)
return prepare_header95(buffer, cmd, size);
else
return prepare_header80(buffer, cmd, size);
}
-static void *__conn_prepare_command(struct drbd_tconn *tconn,
+static void *__conn_prepare_command(struct drbd_connection *connection,
struct drbd_socket *sock)
{
if (!sock->socket)
return NULL;
- return sock->sbuf + drbd_header_size(tconn);
+ return sock->sbuf + drbd_header_size(connection);
}
-void *conn_prepare_command(struct drbd_tconn *tconn, struct drbd_socket *sock)
+void *conn_prepare_command(struct drbd_connection *connection, struct drbd_socket *sock)
{
void *p;
mutex_lock(&sock->mutex);
- p = __conn_prepare_command(tconn, sock);
+ p = __conn_prepare_command(connection, sock);
if (!p)
mutex_unlock(&sock->mutex);
return p;
}
-void *drbd_prepare_command(struct drbd_conf *mdev, struct drbd_socket *sock)
+void *drbd_prepare_command(struct drbd_peer_device *peer_device, struct drbd_socket *sock)
{
- return conn_prepare_command(mdev->tconn, sock);
+ return conn_prepare_command(peer_device->connection, sock);
}
-static int __send_command(struct drbd_tconn *tconn, int vnr,
+static int __send_command(struct drbd_connection *connection, int vnr,
struct drbd_socket *sock, enum drbd_packet cmd,
unsigned int header_size, void *data,
unsigned int size)
@@ -654,82 +656,82 @@ static int __send_command(struct drbd_tconn *tconn, int vnr,
*/
msg_flags = data ? MSG_MORE : 0;
- header_size += prepare_header(tconn, vnr, sock->sbuf, cmd,
+ header_size += prepare_header(connection, vnr, sock->sbuf, cmd,
header_size + size);
- err = drbd_send_all(tconn, sock->socket, sock->sbuf, header_size,
+ err = drbd_send_all(connection, sock->socket, sock->sbuf, header_size,
msg_flags);
if (data && !err)
- err = drbd_send_all(tconn, sock->socket, data, size, 0);
+ err = drbd_send_all(connection, sock->socket, data, size, 0);
return err;
}
-static int __conn_send_command(struct drbd_tconn *tconn, struct drbd_socket *sock,
+static int __conn_send_command(struct drbd_connection *connection, struct drbd_socket *sock,
enum drbd_packet cmd, unsigned int header_size,
void *data, unsigned int size)
{
- return __send_command(tconn, 0, sock, cmd, header_size, data, size);
+ return __send_command(connection, 0, sock, cmd, header_size, data, size);
}
-int conn_send_command(struct drbd_tconn *tconn, struct drbd_socket *sock,
+int conn_send_command(struct drbd_connection *connection, struct drbd_socket *sock,
enum drbd_packet cmd, unsigned int header_size,
void *data, unsigned int size)
{
int err;
- err = __conn_send_command(tconn, sock, cmd, header_size, data, size);
+ err = __conn_send_command(connection, sock, cmd, header_size, data, size);
mutex_unlock(&sock->mutex);
return err;
}
-int drbd_send_command(struct drbd_conf *mdev, struct drbd_socket *sock,
+int drbd_send_command(struct drbd_peer_device *peer_device, struct drbd_socket *sock,
enum drbd_packet cmd, unsigned int header_size,
void *data, unsigned int size)
{
int err;
- err = __send_command(mdev->tconn, mdev->vnr, sock, cmd, header_size,
- data, size);
+ err = __send_command(peer_device->connection, peer_device->device->vnr,
+ sock, cmd, header_size, data, size);
mutex_unlock(&sock->mutex);
return err;
}
-int drbd_send_ping(struct drbd_tconn *tconn)
+int drbd_send_ping(struct drbd_connection *connection)
{
struct drbd_socket *sock;
- sock = &tconn->meta;
- if (!conn_prepare_command(tconn, sock))
+ sock = &connection->meta;
+ if (!conn_prepare_command(connection, sock))
return -EIO;
- return conn_send_command(tconn, sock, P_PING, 0, NULL, 0);
+ return conn_send_command(connection, sock, P_PING, 0, NULL, 0);
}
-int drbd_send_ping_ack(struct drbd_tconn *tconn)
+int drbd_send_ping_ack(struct drbd_connection *connection)
{
struct drbd_socket *sock;
- sock = &tconn->meta;
- if (!conn_prepare_command(tconn, sock))
+ sock = &connection->meta;
+ if (!conn_prepare_command(connection, sock))
return -EIO;
- return conn_send_command(tconn, sock, P_PING_ACK, 0, NULL, 0);
+ return conn_send_command(connection, sock, P_PING_ACK, 0, NULL, 0);
}
-int drbd_send_sync_param(struct drbd_conf *mdev)
+int drbd_send_sync_param(struct drbd_peer_device *peer_device)
{
struct drbd_socket *sock;
struct p_rs_param_95 *p;
int size;
- const int apv = mdev->tconn->agreed_pro_version;
+ const int apv = peer_device->connection->agreed_pro_version;
enum drbd_packet cmd;
struct net_conf *nc;
struct disk_conf *dc;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(peer_device->connection->net_conf);
size = apv <= 87 ? sizeof(struct p_rs_param)
: apv == 88 ? sizeof(struct p_rs_param)
@@ -742,14 +744,14 @@ int drbd_send_sync_param(struct drbd_conf *mdev)
/* initialize verify_alg and csums_alg */
memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX);
- if (get_ldev(mdev)) {
- dc = rcu_dereference(mdev->ldev->disk_conf);
+ if (get_ldev(peer_device->device)) {
+ dc = rcu_dereference(peer_device->device->ldev->disk_conf);
p->resync_rate = cpu_to_be32(dc->resync_rate);
p->c_plan_ahead = cpu_to_be32(dc->c_plan_ahead);
p->c_delay_target = cpu_to_be32(dc->c_delay_target);
p->c_fill_target = cpu_to_be32(dc->c_fill_target);
p->c_max_rate = cpu_to_be32(dc->c_max_rate);
- put_ldev(mdev);
+ put_ldev(peer_device->device);
} else {
p->resync_rate = cpu_to_be32(DRBD_RESYNC_RATE_DEF);
p->c_plan_ahead = cpu_to_be32(DRBD_C_PLAN_AHEAD_DEF);
@@ -764,33 +766,33 @@ int drbd_send_sync_param(struct drbd_conf *mdev)
strcpy(p->csums_alg, nc->csums_alg);
rcu_read_unlock();
- return drbd_send_command(mdev, sock, cmd, size, NULL, 0);
+ return drbd_send_command(peer_device, sock, cmd, size, NULL, 0);
}
-int __drbd_send_protocol(struct drbd_tconn *tconn, enum drbd_packet cmd)
+int __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cmd)
{
struct drbd_socket *sock;
struct p_protocol *p;
struct net_conf *nc;
int size, cf;
- sock = &tconn->data;
- p = __conn_prepare_command(tconn, sock);
+ sock = &connection->data;
+ p = __conn_prepare_command(connection, sock);
if (!p)
return -EIO;
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
- if (nc->tentative && tconn->agreed_pro_version < 92) {
+ if (nc->tentative && connection->agreed_pro_version < 92) {
rcu_read_unlock();
mutex_unlock(&sock->mutex);
- conn_err(tconn, "--dry-run is not supported by peer");
+ drbd_err(connection, "--dry-run is not supported by peer");
return -EOPNOTSUPP;
}
size = sizeof(*p);
- if (tconn->agreed_pro_version >= 87)
+ if (connection->agreed_pro_version >= 87)
size += strlen(nc->integrity_alg) + 1;
p->protocol = cpu_to_be32(nc->wire_protocol);
@@ -805,128 +807,131 @@ int __drbd_send_protocol(struct drbd_tconn *tconn, enum drbd_packet cmd)
cf |= CF_DRY_RUN;
p->conn_flags = cpu_to_be32(cf);
- if (tconn->agreed_pro_version >= 87)
+ if (connection->agreed_pro_version >= 87)
strcpy(p->integrity_alg, nc->integrity_alg);
rcu_read_unlock();
- return __conn_send_command(tconn, sock, cmd, size, NULL, 0);
+ return __conn_send_command(connection, sock, cmd, size, NULL, 0);
}
-int drbd_send_protocol(struct drbd_tconn *tconn)
+int drbd_send_protocol(struct drbd_connection *connection)
{
int err;
- mutex_lock(&tconn->data.mutex);
- err = __drbd_send_protocol(tconn, P_PROTOCOL);
- mutex_unlock(&tconn->data.mutex);
+ mutex_lock(&connection->data.mutex);
+ err = __drbd_send_protocol(connection, P_PROTOCOL);
+ mutex_unlock(&connection->data.mutex);
return err;
}
-int _drbd_send_uuids(struct drbd_conf *mdev, u64 uuid_flags)
+static int _drbd_send_uuids(struct drbd_peer_device *peer_device, u64 uuid_flags)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_socket *sock;
struct p_uuids *p;
int i;
- if (!get_ldev_if_state(mdev, D_NEGOTIATING))
+ if (!get_ldev_if_state(device, D_NEGOTIATING))
return 0;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p) {
- put_ldev(mdev);
+ put_ldev(device);
return -EIO;
}
- spin_lock_irq(&mdev->ldev->md.uuid_lock);
+ spin_lock_irq(&device->ldev->md.uuid_lock);
for (i = UI_CURRENT; i < UI_SIZE; i++)
- p->uuid[i] = cpu_to_be64(mdev->ldev->md.uuid[i]);
- spin_unlock_irq(&mdev->ldev->md.uuid_lock);
+ p->uuid[i] = cpu_to_be64(device->ldev->md.uuid[i]);
+ spin_unlock_irq(&device->ldev->md.uuid_lock);
- mdev->comm_bm_set = drbd_bm_total_weight(mdev);
- p->uuid[UI_SIZE] = cpu_to_be64(mdev->comm_bm_set);
+ device->comm_bm_set = drbd_bm_total_weight(device);
+ p->uuid[UI_SIZE] = cpu_to_be64(device->comm_bm_set);
rcu_read_lock();
- uuid_flags |= rcu_dereference(mdev->tconn->net_conf)->discard_my_data ? 1 : 0;
+ uuid_flags |= rcu_dereference(peer_device->connection->net_conf)->discard_my_data ? 1 : 0;
rcu_read_unlock();
- uuid_flags |= test_bit(CRASHED_PRIMARY, &mdev->flags) ? 2 : 0;
- uuid_flags |= mdev->new_state_tmp.disk == D_INCONSISTENT ? 4 : 0;
+ uuid_flags |= test_bit(CRASHED_PRIMARY, &device->flags) ? 2 : 0;
+ uuid_flags |= device->new_state_tmp.disk == D_INCONSISTENT ? 4 : 0;
p->uuid[UI_FLAGS] = cpu_to_be64(uuid_flags);
- put_ldev(mdev);
- return drbd_send_command(mdev, sock, P_UUIDS, sizeof(*p), NULL, 0);
+ put_ldev(device);
+ return drbd_send_command(peer_device, sock, P_UUIDS, sizeof(*p), NULL, 0);
}
-int drbd_send_uuids(struct drbd_conf *mdev)
+int drbd_send_uuids(struct drbd_peer_device *peer_device)
{
- return _drbd_send_uuids(mdev, 0);
+ return _drbd_send_uuids(peer_device, 0);
}
-int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev)
+int drbd_send_uuids_skip_initial_sync(struct drbd_peer_device *peer_device)
{
- return _drbd_send_uuids(mdev, 8);
+ return _drbd_send_uuids(peer_device, 8);
}
-void drbd_print_uuids(struct drbd_conf *mdev, const char *text)
+void drbd_print_uuids(struct drbd_device *device, const char *text)
{
- if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
- u64 *uuid = mdev->ldev->md.uuid;
- dev_info(DEV, "%s %016llX:%016llX:%016llX:%016llX\n",
+ if (get_ldev_if_state(device, D_NEGOTIATING)) {
+ u64 *uuid = device->ldev->md.uuid;
+ drbd_info(device, "%s %016llX:%016llX:%016llX:%016llX\n",
text,
(unsigned long long)uuid[UI_CURRENT],
(unsigned long long)uuid[UI_BITMAP],
(unsigned long long)uuid[UI_HISTORY_START],
(unsigned long long)uuid[UI_HISTORY_END]);
- put_ldev(mdev);
+ put_ldev(device);
} else {
- dev_info(DEV, "%s effective data uuid: %016llX\n",
+ drbd_info(device, "%s effective data uuid: %016llX\n",
text,
- (unsigned long long)mdev->ed_uuid);
+ (unsigned long long)device->ed_uuid);
}
}
-void drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev)
+void drbd_gen_and_send_sync_uuid(struct drbd_peer_device *peer_device)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_socket *sock;
struct p_rs_uuid *p;
u64 uuid;
- D_ASSERT(mdev->state.disk == D_UP_TO_DATE);
+ D_ASSERT(device, device->state.disk == D_UP_TO_DATE);
- uuid = mdev->ldev->md.uuid[UI_BITMAP];
+ uuid = device->ldev->md.uuid[UI_BITMAP];
if (uuid && uuid != UUID_JUST_CREATED)
uuid = uuid + UUID_NEW_BM_OFFSET;
else
get_random_bytes(&uuid, sizeof(u64));
- drbd_uuid_set(mdev, UI_BITMAP, uuid);
- drbd_print_uuids(mdev, "updated sync UUID");
- drbd_md_sync(mdev);
+ drbd_uuid_set(device, UI_BITMAP, uuid);
+ drbd_print_uuids(device, "updated sync UUID");
+ drbd_md_sync(device);
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (p) {
p->uuid = cpu_to_be64(uuid);
- drbd_send_command(mdev, sock, P_SYNC_UUID, sizeof(*p), NULL, 0);
+ drbd_send_command(peer_device, sock, P_SYNC_UUID, sizeof(*p), NULL, 0);
}
}
-int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags)
+int drbd_send_sizes(struct drbd_peer_device *peer_device, int trigger_reply, enum dds_flags flags)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_socket *sock;
struct p_sizes *p;
sector_t d_size, u_size;
int q_order_type;
unsigned int max_bio_size;
- if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
- D_ASSERT(mdev->ldev->backing_bdev);
- d_size = drbd_get_max_capacity(mdev->ldev);
+ if (get_ldev_if_state(device, D_NEGOTIATING)) {
+ D_ASSERT(device, device->ldev->backing_bdev);
+ d_size = drbd_get_max_capacity(device->ldev);
rcu_read_lock();
- u_size = rcu_dereference(mdev->ldev->disk_conf)->disk_size;
+ u_size = rcu_dereference(device->ldev->disk_conf)->disk_size;
rcu_read_unlock();
- q_order_type = drbd_queue_order_type(mdev);
- max_bio_size = queue_max_hw_sectors(mdev->ldev->backing_bdev->bd_disk->queue) << 9;
+ q_order_type = drbd_queue_order_type(device);
+ max_bio_size = queue_max_hw_sectors(device->ldev->backing_bdev->bd_disk->queue) << 9;
max_bio_size = min(max_bio_size, DRBD_MAX_BIO_SIZE);
- put_ldev(mdev);
+ put_ldev(device);
} else {
d_size = 0;
u_size = 0;
@@ -934,45 +939,45 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl
max_bio_size = DRBD_MAX_BIO_SIZE; /* ... multiple BIOs per peer_request */
}
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
- if (mdev->tconn->agreed_pro_version <= 94)
+ if (peer_device->connection->agreed_pro_version <= 94)
max_bio_size = min(max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
- else if (mdev->tconn->agreed_pro_version < 100)
+ else if (peer_device->connection->agreed_pro_version < 100)
max_bio_size = min(max_bio_size, DRBD_MAX_BIO_SIZE_P95);
p->d_size = cpu_to_be64(d_size);
p->u_size = cpu_to_be64(u_size);
- p->c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(mdev->this_bdev));
+ p->c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(device->this_bdev));
p->max_bio_size = cpu_to_be32(max_bio_size);
p->queue_order_type = cpu_to_be16(q_order_type);
p->dds_flags = cpu_to_be16(flags);
- return drbd_send_command(mdev, sock, P_SIZES, sizeof(*p), NULL, 0);
+ return drbd_send_command(peer_device, sock, P_SIZES, sizeof(*p), NULL, 0);
}
/**
* drbd_send_current_state() - Sends the drbd state to the peer
- * @mdev: DRBD device.
+ * @peer_device: DRBD peer device.
*/
-int drbd_send_current_state(struct drbd_conf *mdev)
+int drbd_send_current_state(struct drbd_peer_device *peer_device)
{
struct drbd_socket *sock;
struct p_state *p;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
- p->state = cpu_to_be32(mdev->state.i); /* Within the send mutex */
- return drbd_send_command(mdev, sock, P_STATE, sizeof(*p), NULL, 0);
+ p->state = cpu_to_be32(peer_device->device->state.i); /* Within the send mutex */
+ return drbd_send_command(peer_device, sock, P_STATE, sizeof(*p), NULL, 0);
}
/**
* drbd_send_state() - After a state change, sends the new state to the peer
- * @mdev: DRBD device.
+ * @peer_device: DRBD peer device.
* @state: the state to send, not necessarily the current state.
*
* Each state change queues an "after_state_ch" work, which will eventually
@@ -980,73 +985,73 @@ int drbd_send_current_state(struct drbd_conf *mdev)
* between queuing and processing of the after_state_ch work, we still
* want to send each intermediary state in the order it occurred.
*/
-int drbd_send_state(struct drbd_conf *mdev, union drbd_state state)
+int drbd_send_state(struct drbd_peer_device *peer_device, union drbd_state state)
{
struct drbd_socket *sock;
struct p_state *p;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->state = cpu_to_be32(state.i); /* Within the send mutex */
- return drbd_send_command(mdev, sock, P_STATE, sizeof(*p), NULL, 0);
+ return drbd_send_command(peer_device, sock, P_STATE, sizeof(*p), NULL, 0);
}
-int drbd_send_state_req(struct drbd_conf *mdev, union drbd_state mask, union drbd_state val)
+int drbd_send_state_req(struct drbd_peer_device *peer_device, union drbd_state mask, union drbd_state val)
{
struct drbd_socket *sock;
struct p_req_state *p;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->mask = cpu_to_be32(mask.i);
p->val = cpu_to_be32(val.i);
- return drbd_send_command(mdev, sock, P_STATE_CHG_REQ, sizeof(*p), NULL, 0);
+ return drbd_send_command(peer_device, sock, P_STATE_CHG_REQ, sizeof(*p), NULL, 0);
}
-int conn_send_state_req(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val)
+int conn_send_state_req(struct drbd_connection *connection, union drbd_state mask, union drbd_state val)
{
enum drbd_packet cmd;
struct drbd_socket *sock;
struct p_req_state *p;
- cmd = tconn->agreed_pro_version < 100 ? P_STATE_CHG_REQ : P_CONN_ST_CHG_REQ;
- sock = &tconn->data;
- p = conn_prepare_command(tconn, sock);
+ cmd = connection->agreed_pro_version < 100 ? P_STATE_CHG_REQ : P_CONN_ST_CHG_REQ;
+ sock = &connection->data;
+ p = conn_prepare_command(connection, sock);
if (!p)
return -EIO;
p->mask = cpu_to_be32(mask.i);
p->val = cpu_to_be32(val.i);
- return conn_send_command(tconn, sock, cmd, sizeof(*p), NULL, 0);
+ return conn_send_command(connection, sock, cmd, sizeof(*p), NULL, 0);
}
-void drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode)
+void drbd_send_sr_reply(struct drbd_peer_device *peer_device, enum drbd_state_rv retcode)
{
struct drbd_socket *sock;
struct p_req_state_reply *p;
- sock = &mdev->tconn->meta;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->meta;
+ p = drbd_prepare_command(peer_device, sock);
if (p) {
p->retcode = cpu_to_be32(retcode);
- drbd_send_command(mdev, sock, P_STATE_CHG_REPLY, sizeof(*p), NULL, 0);
+ drbd_send_command(peer_device, sock, P_STATE_CHG_REPLY, sizeof(*p), NULL, 0);
}
}
-void conn_send_sr_reply(struct drbd_tconn *tconn, enum drbd_state_rv retcode)
+void conn_send_sr_reply(struct drbd_connection *connection, enum drbd_state_rv retcode)
{
struct drbd_socket *sock;
struct p_req_state_reply *p;
- enum drbd_packet cmd = tconn->agreed_pro_version < 100 ? P_STATE_CHG_REPLY : P_CONN_ST_CHG_REPLY;
+ enum drbd_packet cmd = connection->agreed_pro_version < 100 ? P_STATE_CHG_REPLY : P_CONN_ST_CHG_REPLY;
- sock = &tconn->meta;
- p = conn_prepare_command(tconn, sock);
+ sock = &connection->meta;
+ p = conn_prepare_command(connection, sock);
if (p) {
p->retcode = cpu_to_be32(retcode);
- conn_send_command(tconn, sock, cmd, sizeof(*p), NULL, 0);
+ conn_send_command(connection, sock, cmd, sizeof(*p), NULL, 0);
}
}
@@ -1067,7 +1072,7 @@ static void dcbp_set_pad_bits(struct p_compressed_bm *p, int n)
p->encoding = (p->encoding & (~0x7 << 4)) | (n << 4);
}
-int fill_bitmap_rle_bits(struct drbd_conf *mdev,
+static int fill_bitmap_rle_bits(struct drbd_device *device,
struct p_compressed_bm *p,
unsigned int size,
struct bm_xfer_ctx *c)
@@ -1082,9 +1087,9 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev,
/* may we use this feature? */
rcu_read_lock();
- use_rle = rcu_dereference(mdev->tconn->net_conf)->use_rle;
+ use_rle = rcu_dereference(first_peer_device(device)->connection->net_conf)->use_rle;
rcu_read_unlock();
- if (!use_rle || mdev->tconn->agreed_pro_version < 90)
+ if (!use_rle || first_peer_device(device)->connection->agreed_pro_version < 90)
return 0;
if (c->bit_offset >= c->bm_bits)
@@ -1104,8 +1109,8 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev,
/* see how much plain bits we can stuff into one packet
* using RLE and VLI. */
do {
- tmp = (toggle == 0) ? _drbd_bm_find_next_zero(mdev, c->bit_offset)
- : _drbd_bm_find_next(mdev, c->bit_offset);
+ tmp = (toggle == 0) ? _drbd_bm_find_next_zero(device, c->bit_offset)
+ : _drbd_bm_find_next(device, c->bit_offset);
if (tmp == -1UL)
tmp = c->bm_bits;
rl = tmp - c->bit_offset;
@@ -1125,7 +1130,7 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev,
/* paranoia: catch zero runlength.
* can only happen if bitmap is modified while we scan it. */
if (rl == 0) {
- dev_err(DEV, "unexpected zero runlength while encoding bitmap "
+ drbd_err(device, "unexpected zero runlength while encoding bitmap "
"t:%u bo:%lu\n", toggle, c->bit_offset);
return -1;
}
@@ -1134,7 +1139,7 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev,
if (bits == -ENOBUFS) /* buffer full */
break;
if (bits <= 0) {
- dev_err(DEV, "error while encoding bitmap: %d\n", bits);
+ drbd_err(device, "error while encoding bitmap: %d\n", bits);
return 0;
}
@@ -1171,21 +1176,21 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev,
* code upon failure.
*/
static int
-send_bitmap_rle_or_plain(struct drbd_conf *mdev, struct bm_xfer_ctx *c)
+send_bitmap_rle_or_plain(struct drbd_device *device, struct bm_xfer_ctx *c)
{
- struct drbd_socket *sock = &mdev->tconn->data;
- unsigned int header_size = drbd_header_size(mdev->tconn);
+ struct drbd_socket *sock = &first_peer_device(device)->connection->data;
+ unsigned int header_size = drbd_header_size(first_peer_device(device)->connection);
struct p_compressed_bm *p = sock->sbuf + header_size;
int len, err;
- len = fill_bitmap_rle_bits(mdev, p,
+ len = fill_bitmap_rle_bits(device, p,
DRBD_SOCKET_BUFFER_SIZE - header_size - sizeof(*p), c);
if (len < 0)
return -EIO;
if (len) {
dcbp_set_code(p, RLE_VLI_Bits);
- err = __send_command(mdev->tconn, mdev->vnr, sock,
+ err = __send_command(first_peer_device(device)->connection, device->vnr, sock,
P_COMPRESSED_BITMAP, sizeof(*p) + len,
NULL, 0);
c->packets[0]++;
@@ -1205,8 +1210,8 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, struct bm_xfer_ctx *c)
c->bm_words - c->word_offset);
len = num_words * sizeof(*p);
if (len)
- drbd_bm_get_lel(mdev, c->word_offset, num_words, p);
- err = __send_command(mdev->tconn, mdev->vnr, sock, P_BITMAP, len, NULL, 0);
+ drbd_bm_get_lel(device, c->word_offset, num_words, p);
+ err = __send_command(first_peer_device(device)->connection, device->vnr, sock, P_BITMAP, len, NULL, 0);
c->word_offset += num_words;
c->bit_offset = c->word_offset * BITS_PER_LONG;
@@ -1218,7 +1223,7 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, struct bm_xfer_ctx *c)
}
if (!err) {
if (len == 0) {
- INFO_bm_xfer_stats(mdev, "send", c);
+ INFO_bm_xfer_stats(device, "send", c);
return 0;
} else
return 1;
@@ -1227,128 +1232,128 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, struct bm_xfer_ctx *c)
}
/* See the comment at receive_bitmap() */
-static int _drbd_send_bitmap(struct drbd_conf *mdev)
+static int _drbd_send_bitmap(struct drbd_device *device)
{
struct bm_xfer_ctx c;
int err;
- if (!expect(mdev->bitmap))
+ if (!expect(device->bitmap))
return false;
- if (get_ldev(mdev)) {
- if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC)) {
- dev_info(DEV, "Writing the whole bitmap, MDF_FullSync was set.\n");
- drbd_bm_set_all(mdev);
- if (drbd_bm_write(mdev)) {
+ if (get_ldev(device)) {
+ if (drbd_md_test_flag(device->ldev, MDF_FULL_SYNC)) {
+ drbd_info(device, "Writing the whole bitmap, MDF_FullSync was set.\n");
+ drbd_bm_set_all(device);
+ if (drbd_bm_write(device)) {
/* write_bm did fail! Leave full sync flag set in Meta P_DATA
* but otherwise process as per normal - need to tell other
* side that a full resync is required! */
- dev_err(DEV, "Failed to write bitmap to disk!\n");
+ drbd_err(device, "Failed to write bitmap to disk!\n");
} else {
- drbd_md_clear_flag(mdev, MDF_FULL_SYNC);
- drbd_md_sync(mdev);
+ drbd_md_clear_flag(device, MDF_FULL_SYNC);
+ drbd_md_sync(device);
}
}
- put_ldev(mdev);
+ put_ldev(device);
}
c = (struct bm_xfer_ctx) {
- .bm_bits = drbd_bm_bits(mdev),
- .bm_words = drbd_bm_words(mdev),
+ .bm_bits = drbd_bm_bits(device),
+ .bm_words = drbd_bm_words(device),
};
do {
- err = send_bitmap_rle_or_plain(mdev, &c);
+ err = send_bitmap_rle_or_plain(device, &c);
} while (err > 0);
return err == 0;
}
-int drbd_send_bitmap(struct drbd_conf *mdev)
+int drbd_send_bitmap(struct drbd_device *device)
{
- struct drbd_socket *sock = &mdev->tconn->data;
+ struct drbd_socket *sock = &first_peer_device(device)->connection->data;
int err = -1;
mutex_lock(&sock->mutex);
if (sock->socket)
- err = !_drbd_send_bitmap(mdev);
+ err = !_drbd_send_bitmap(device);
mutex_unlock(&sock->mutex);
return err;
}
-void drbd_send_b_ack(struct drbd_tconn *tconn, u32 barrier_nr, u32 set_size)
+void drbd_send_b_ack(struct drbd_connection *connection, u32 barrier_nr, u32 set_size)
{
struct drbd_socket *sock;
struct p_barrier_ack *p;
- if (tconn->cstate < C_WF_REPORT_PARAMS)
+ if (connection->cstate < C_WF_REPORT_PARAMS)
return;
- sock = &tconn->meta;
- p = conn_prepare_command(tconn, sock);
+ sock = &connection->meta;
+ p = conn_prepare_command(connection, sock);
if (!p)
return;
p->barrier = barrier_nr;
p->set_size = cpu_to_be32(set_size);
- conn_send_command(tconn, sock, P_BARRIER_ACK, sizeof(*p), NULL, 0);
+ conn_send_command(connection, sock, P_BARRIER_ACK, sizeof(*p), NULL, 0);
}
/**
* _drbd_send_ack() - Sends an ack packet
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @cmd: Packet command code.
* @sector: sector, needs to be in big endian byte order
* @blksize: size in byte, needs to be in big endian byte order
* @block_id: Id, big endian byte order
*/
-static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packet cmd,
+static int _drbd_send_ack(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
u64 sector, u32 blksize, u64 block_id)
{
struct drbd_socket *sock;
struct p_block_ack *p;
- if (mdev->state.conn < C_CONNECTED)
+ if (peer_device->device->state.conn < C_CONNECTED)
return -EIO;
- sock = &mdev->tconn->meta;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->meta;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->sector = sector;
p->block_id = block_id;
p->blksize = blksize;
- p->seq_num = cpu_to_be32(atomic_inc_return(&mdev->packet_seq));
- return drbd_send_command(mdev, sock, cmd, sizeof(*p), NULL, 0);
+ p->seq_num = cpu_to_be32(atomic_inc_return(&peer_device->device->packet_seq));
+ return drbd_send_command(peer_device, sock, cmd, sizeof(*p), NULL, 0);
}
/* dp->sector and dp->block_id already/still in network byte order,
* data_size is payload size according to dp->head,
* and may need to be corrected for digest size. */
-void drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packet cmd,
+void drbd_send_ack_dp(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
struct p_data *dp, int data_size)
{
- if (mdev->tconn->peer_integrity_tfm)
- data_size -= crypto_hash_digestsize(mdev->tconn->peer_integrity_tfm);
- _drbd_send_ack(mdev, cmd, dp->sector, cpu_to_be32(data_size),
+ if (peer_device->connection->peer_integrity_tfm)
+ data_size -= crypto_hash_digestsize(peer_device->connection->peer_integrity_tfm);
+ _drbd_send_ack(peer_device, cmd, dp->sector, cpu_to_be32(data_size),
dp->block_id);
}
-void drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packet cmd,
+void drbd_send_ack_rp(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
struct p_block_req *rp)
{
- _drbd_send_ack(mdev, cmd, rp->sector, rp->blksize, rp->block_id);
+ _drbd_send_ack(peer_device, cmd, rp->sector, rp->blksize, rp->block_id);
}
/**
* drbd_send_ack() - Sends an ack packet
- * @mdev: DRBD device
+ * @device: DRBD device
* @cmd: packet command code
* @peer_req: peer request
*/
-int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packet cmd,
+int drbd_send_ack(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
struct drbd_peer_request *peer_req)
{
- return _drbd_send_ack(mdev, cmd,
+ return _drbd_send_ack(peer_device, cmd,
cpu_to_be64(peer_req->i.sector),
cpu_to_be32(peer_req->i.size),
peer_req->block_id);
@@ -1356,32 +1361,32 @@ int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packet cmd,
/* This function misuses the block_id field to signal if the blocks
* are is sync or not. */
-int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packet cmd,
+int drbd_send_ack_ex(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
sector_t sector, int blksize, u64 block_id)
{
- return _drbd_send_ack(mdev, cmd,
+ return _drbd_send_ack(peer_device, cmd,
cpu_to_be64(sector),
cpu_to_be32(blksize),
cpu_to_be64(block_id));
}
-int drbd_send_drequest(struct drbd_conf *mdev, int cmd,
+int drbd_send_drequest(struct drbd_peer_device *peer_device, int cmd,
sector_t sector, int size, u64 block_id)
{
struct drbd_socket *sock;
struct p_block_req *p;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->sector = cpu_to_be64(sector);
p->block_id = block_id;
p->blksize = cpu_to_be32(size);
- return drbd_send_command(mdev, sock, cmd, sizeof(*p), NULL, 0);
+ return drbd_send_command(peer_device, sock, cmd, sizeof(*p), NULL, 0);
}
-int drbd_send_drequest_csum(struct drbd_conf *mdev, sector_t sector, int size,
+int drbd_send_drequest_csum(struct drbd_peer_device *peer_device, sector_t sector, int size,
void *digest, int digest_size, enum drbd_packet cmd)
{
struct drbd_socket *sock;
@@ -1389,64 +1394,63 @@ int drbd_send_drequest_csum(struct drbd_conf *mdev, sector_t sector, int size,
/* FIXME: Put the digest into the preallocated socket buffer. */
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->sector = cpu_to_be64(sector);
p->block_id = ID_SYNCER /* unused */;
p->blksize = cpu_to_be32(size);
- return drbd_send_command(mdev, sock, cmd, sizeof(*p),
- digest, digest_size);
+ return drbd_send_command(peer_device, sock, cmd, sizeof(*p), digest, digest_size);
}
-int drbd_send_ov_request(struct drbd_conf *mdev, sector_t sector, int size)
+int drbd_send_ov_request(struct drbd_peer_device *peer_device, sector_t sector, int size)
{
struct drbd_socket *sock;
struct p_block_req *p;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->sector = cpu_to_be64(sector);
p->block_id = ID_SYNCER /* unused */;
p->blksize = cpu_to_be32(size);
- return drbd_send_command(mdev, sock, P_OV_REQUEST, sizeof(*p), NULL, 0);
+ return drbd_send_command(peer_device, sock, P_OV_REQUEST, sizeof(*p), NULL, 0);
}
/* called on sndtimeo
* returns false if we should retry,
* true if we think connection is dead
*/
-static int we_should_drop_the_connection(struct drbd_tconn *tconn, struct socket *sock)
+static int we_should_drop_the_connection(struct drbd_connection *connection, struct socket *sock)
{
int drop_it;
- /* long elapsed = (long)(jiffies - mdev->last_received); */
+ /* long elapsed = (long)(jiffies - device->last_received); */
- drop_it = tconn->meta.socket == sock
- || !tconn->asender.task
- || get_t_state(&tconn->asender) != RUNNING
- || tconn->cstate < C_WF_REPORT_PARAMS;
+ drop_it = connection->meta.socket == sock
+ || !connection->asender.task
+ || get_t_state(&connection->asender) != RUNNING
+ || connection->cstate < C_WF_REPORT_PARAMS;
if (drop_it)
return true;
- drop_it = !--tconn->ko_count;
+ drop_it = !--connection->ko_count;
if (!drop_it) {
- conn_err(tconn, "[%s/%d] sock_sendmsg time expired, ko = %u\n",
- current->comm, current->pid, tconn->ko_count);
- request_ping(tconn);
+ drbd_err(connection, "[%s/%d] sock_sendmsg time expired, ko = %u\n",
+ current->comm, current->pid, connection->ko_count);
+ request_ping(connection);
}
- return drop_it; /* && (mdev->state == R_PRIMARY) */;
+ return drop_it; /* && (device->state == R_PRIMARY) */;
}
-static void drbd_update_congested(struct drbd_tconn *tconn)
+static void drbd_update_congested(struct drbd_connection *connection)
{
- struct sock *sk = tconn->data.socket->sk;
+ struct sock *sk = connection->data.socket->sk;
if (sk->sk_wmem_queued > sk->sk_sndbuf * 4 / 5)
- set_bit(NET_CONGESTED, &tconn->flags);
+ set_bit(NET_CONGESTED, &connection->flags);
}
/* The idea of sendpage seems to be to put some kind of reference
@@ -1470,26 +1474,26 @@ static void drbd_update_congested(struct drbd_tconn *tconn)
* As a workaround, we disable sendpage on pages
* with page_count == 0 or PageSlab.
*/
-static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page,
+static int _drbd_no_send_page(struct drbd_peer_device *peer_device, struct page *page,
int offset, size_t size, unsigned msg_flags)
{
struct socket *socket;
void *addr;
int err;
- socket = mdev->tconn->data.socket;
+ socket = peer_device->connection->data.socket;
addr = kmap(page) + offset;
- err = drbd_send_all(mdev->tconn, socket, addr, size, msg_flags);
+ err = drbd_send_all(peer_device->connection, socket, addr, size, msg_flags);
kunmap(page);
if (!err)
- mdev->send_cnt += size >> 9;
+ peer_device->device->send_cnt += size >> 9;
return err;
}
-static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
+static int _drbd_send_page(struct drbd_peer_device *peer_device, struct page *page,
int offset, size_t size, unsigned msg_flags)
{
- struct socket *socket = mdev->tconn->data.socket;
+ struct socket *socket = peer_device->connection->data.socket;
mm_segment_t oldfs = get_fs();
int len = size;
int err = -EIO;
@@ -1501,10 +1505,10 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
* __page_cache_release a page that would actually still be referenced
* by someone, leading to some obscure delayed Oops somewhere else. */
if (disable_sendpage || (page_count(page) < 1) || PageSlab(page))
- return _drbd_no_send_page(mdev, page, offset, size, msg_flags);
+ return _drbd_no_send_page(peer_device, page, offset, size, msg_flags);
msg_flags |= MSG_NOSIGNAL;
- drbd_update_congested(mdev->tconn);
+ drbd_update_congested(peer_device->connection);
set_fs(KERNEL_DS);
do {
int sent;
@@ -1512,11 +1516,11 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
sent = socket->ops->sendpage(socket, page, offset, len, msg_flags);
if (sent <= 0) {
if (sent == -EAGAIN) {
- if (we_should_drop_the_connection(mdev->tconn, socket))
+ if (we_should_drop_the_connection(peer_device->connection, socket))
break;
continue;
}
- dev_warn(DEV, "%s: size=%d len=%d sent=%d\n",
+ drbd_warn(peer_device->device, "%s: size=%d len=%d sent=%d\n",
__func__, (int)size, len, sent);
if (sent < 0)
err = sent;
@@ -1524,18 +1528,18 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
}
len -= sent;
offset += sent;
- } while (len > 0 /* THINK && mdev->cstate >= C_CONNECTED*/);
+ } while (len > 0 /* THINK && device->cstate >= C_CONNECTED*/);
set_fs(oldfs);
- clear_bit(NET_CONGESTED, &mdev->tconn->flags);
+ clear_bit(NET_CONGESTED, &peer_device->connection->flags);
if (len == 0) {
err = 0;
- mdev->send_cnt += size >> 9;
+ peer_device->device->send_cnt += size >> 9;
}
return err;
}
-static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio)
+static int _drbd_send_bio(struct drbd_peer_device *peer_device, struct bio *bio)
{
struct bio_vec bvec;
struct bvec_iter iter;
@@ -1544,7 +1548,7 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio)
bio_for_each_segment(bvec, bio, iter) {
int err;
- err = _drbd_no_send_page(mdev, bvec.bv_page,
+ err = _drbd_no_send_page(peer_device, bvec.bv_page,
bvec.bv_offset, bvec.bv_len,
bio_iter_last(bvec, iter)
? 0 : MSG_MORE);
@@ -1554,7 +1558,7 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio)
return 0;
}
-static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio)
+static int _drbd_send_zc_bio(struct drbd_peer_device *peer_device, struct bio *bio)
{
struct bio_vec bvec;
struct bvec_iter iter;
@@ -1563,7 +1567,7 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio)
bio_for_each_segment(bvec, bio, iter) {
int err;
- err = _drbd_send_page(mdev, bvec.bv_page,
+ err = _drbd_send_page(peer_device, bvec.bv_page,
bvec.bv_offset, bvec.bv_len,
bio_iter_last(bvec, iter) ? 0 : MSG_MORE);
if (err)
@@ -1572,7 +1576,7 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio)
return 0;
}
-static int _drbd_send_zc_ee(struct drbd_conf *mdev,
+static int _drbd_send_zc_ee(struct drbd_peer_device *peer_device,
struct drbd_peer_request *peer_req)
{
struct page *page = peer_req->pages;
@@ -1583,7 +1587,7 @@ static int _drbd_send_zc_ee(struct drbd_conf *mdev,
page_chain_for_each(page) {
unsigned l = min_t(unsigned, len, PAGE_SIZE);
- err = _drbd_send_page(mdev, page, 0, l,
+ err = _drbd_send_page(peer_device, page, 0, l,
page_chain_next(page) ? MSG_MORE : 0);
if (err)
return err;
@@ -1592,9 +1596,9 @@ static int _drbd_send_zc_ee(struct drbd_conf *mdev,
return 0;
}
-static u32 bio_flags_to_wire(struct drbd_conf *mdev, unsigned long bi_rw)
+static u32 bio_flags_to_wire(struct drbd_connection *connection, unsigned long bi_rw)
{
- if (mdev->tconn->agreed_pro_version >= 95)
+ if (connection->agreed_pro_version >= 95)
return (bi_rw & REQ_SYNC ? DP_RW_SYNC : 0) |
(bi_rw & REQ_FUA ? DP_FUA : 0) |
(bi_rw & REQ_FLUSH ? DP_FLUSH : 0) |
@@ -1606,28 +1610,30 @@ static u32 bio_flags_to_wire(struct drbd_conf *mdev, unsigned long bi_rw)
/* Used to send write requests
* R_PRIMARY -> Peer (P_DATA)
*/
-int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
+int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request *req)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_socket *sock;
struct p_data *p;
unsigned int dp_flags = 0;
int dgs;
int err;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
- dgs = mdev->tconn->integrity_tfm ? crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0;
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
+ dgs = peer_device->connection->integrity_tfm ?
+ crypto_hash_digestsize(peer_device->connection->integrity_tfm) : 0;
if (!p)
return -EIO;
p->sector = cpu_to_be64(req->i.sector);
p->block_id = (unsigned long)req;
- p->seq_num = cpu_to_be32(atomic_inc_return(&mdev->packet_seq));
- dp_flags = bio_flags_to_wire(mdev, req->master_bio->bi_rw);
- if (mdev->state.conn >= C_SYNC_SOURCE &&
- mdev->state.conn <= C_PAUSED_SYNC_T)
+ p->seq_num = cpu_to_be32(atomic_inc_return(&device->packet_seq));
+ dp_flags = bio_flags_to_wire(peer_device->connection, req->master_bio->bi_rw);
+ if (device->state.conn >= C_SYNC_SOURCE &&
+ device->state.conn <= C_PAUSED_SYNC_T)
dp_flags |= DP_MAY_SET_IN_SYNC;
- if (mdev->tconn->agreed_pro_version >= 100) {
+ if (peer_device->connection->agreed_pro_version >= 100) {
if (req->rq_state & RQ_EXP_RECEIVE_ACK)
dp_flags |= DP_SEND_RECEIVE_ACK;
if (req->rq_state & RQ_EXP_WRITE_ACK)
@@ -1635,8 +1641,8 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
}
p->dp_flags = cpu_to_be32(dp_flags);
if (dgs)
- drbd_csum_bio(mdev, mdev->tconn->integrity_tfm, req->master_bio, p + 1);
- err = __send_command(mdev->tconn, mdev->vnr, sock, P_DATA, sizeof(*p) + dgs, NULL, req->i.size);
+ drbd_csum_bio(peer_device->connection->integrity_tfm, req->master_bio, p + 1);
+ err = __send_command(peer_device->connection, device->vnr, sock, P_DATA, sizeof(*p) + dgs, NULL, req->i.size);
if (!err) {
/* For protocol A, we have to memcpy the payload into
* socket buffers, as we may complete right away
@@ -1650,18 +1656,18 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
* receiving side, we sure have detected corruption elsewhere.
*/
if (!(req->rq_state & (RQ_EXP_RECEIVE_ACK | RQ_EXP_WRITE_ACK)) || dgs)
- err = _drbd_send_bio(mdev, req->master_bio);
+ err = _drbd_send_bio(peer_device, req->master_bio);
else
- err = _drbd_send_zc_bio(mdev, req->master_bio);
+ err = _drbd_send_zc_bio(peer_device, req->master_bio);
/* double check digest, sometimes buffers have been modified in flight. */
if (dgs > 0 && dgs <= 64) {
/* 64 byte, 512 bit, is the largest digest size
* currently supported in kernel crypto. */
unsigned char digest[64];
- drbd_csum_bio(mdev, mdev->tconn->integrity_tfm, req->master_bio, digest);
+ drbd_csum_bio(peer_device->connection->integrity_tfm, req->master_bio, digest);
if (memcmp(p + 1, digest, dgs)) {
- dev_warn(DEV,
+ drbd_warn(device,
"Digest mismatch, buffer modified by upper layers during write: %llus +%u\n",
(unsigned long long)req->i.sector, req->i.size);
}
@@ -1678,18 +1684,20 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
* Peer -> (diskless) R_PRIMARY (P_DATA_REPLY)
* C_SYNC_SOURCE -> C_SYNC_TARGET (P_RS_DATA_REPLY)
*/
-int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd,
+int drbd_send_block(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
struct drbd_peer_request *peer_req)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_socket *sock;
struct p_data *p;
int err;
int dgs;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
- dgs = mdev->tconn->integrity_tfm ? crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0;
+ dgs = peer_device->connection->integrity_tfm ?
+ crypto_hash_digestsize(peer_device->connection->integrity_tfm) : 0;
if (!p)
return -EIO;
@@ -1698,27 +1706,27 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd,
p->seq_num = 0; /* unused */
p->dp_flags = 0;
if (dgs)
- drbd_csum_ee(mdev, mdev->tconn->integrity_tfm, peer_req, p + 1);
- err = __send_command(mdev->tconn, mdev->vnr, sock, cmd, sizeof(*p) + dgs, NULL, peer_req->i.size);
+ drbd_csum_ee(peer_device->connection->integrity_tfm, peer_req, p + 1);
+ err = __send_command(peer_device->connection, device->vnr, sock, cmd, sizeof(*p) + dgs, NULL, peer_req->i.size);
if (!err)
- err = _drbd_send_zc_ee(mdev, peer_req);
+ err = _drbd_send_zc_ee(peer_device, peer_req);
mutex_unlock(&sock->mutex); /* locked by drbd_prepare_command() */
return err;
}
-int drbd_send_out_of_sync(struct drbd_conf *mdev, struct drbd_request *req)
+int drbd_send_out_of_sync(struct drbd_peer_device *peer_device, struct drbd_request *req)
{
struct drbd_socket *sock;
struct p_block_desc *p;
- sock = &mdev->tconn->data;
- p = drbd_prepare_command(mdev, sock);
+ sock = &peer_device->connection->data;
+ p = drbd_prepare_command(peer_device, sock);
if (!p)
return -EIO;
p->sector = cpu_to_be64(req->i.sector);
p->blksize = cpu_to_be32(req->i.size);
- return drbd_send_command(mdev, sock, P_OUT_OF_SYNC, sizeof(*p), NULL, 0);
+ return drbd_send_command(peer_device, sock, P_OUT_OF_SYNC, sizeof(*p), NULL, 0);
}
/*
@@ -1737,7 +1745,7 @@ int drbd_send_out_of_sync(struct drbd_conf *mdev, struct drbd_request *req)
/*
* you must have down()ed the appropriate [m]sock_mutex elsewhere!
*/
-int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
+int drbd_send(struct drbd_connection *connection, struct socket *sock,
void *buf, size_t size, unsigned msg_flags)
{
struct kvec iov;
@@ -1758,11 +1766,11 @@ int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
msg.msg_controllen = 0;
msg.msg_flags = msg_flags | MSG_NOSIGNAL;
- if (sock == tconn->data.socket) {
+ if (sock == connection->data.socket) {
rcu_read_lock();
- tconn->ko_count = rcu_dereference(tconn->net_conf)->ko_count;
+ connection->ko_count = rcu_dereference(connection->net_conf)->ko_count;
rcu_read_unlock();
- drbd_update_congested(tconn);
+ drbd_update_congested(connection);
}
do {
/* STRANGE
@@ -1776,7 +1784,7 @@ int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
*/
rv = kernel_sendmsg(sock, &msg, &iov, 1, size);
if (rv == -EAGAIN) {
- if (we_should_drop_the_connection(tconn, sock))
+ if (we_should_drop_the_connection(connection, sock))
break;
else
continue;
@@ -1792,17 +1800,17 @@ int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
iov.iov_len -= rv;
} while (sent < size);
- if (sock == tconn->data.socket)
- clear_bit(NET_CONGESTED, &tconn->flags);
+ if (sock == connection->data.socket)
+ clear_bit(NET_CONGESTED, &connection->flags);
if (rv <= 0) {
if (rv != -EAGAIN) {
- conn_err(tconn, "%s_sendmsg returned %d\n",
- sock == tconn->meta.socket ? "msock" : "sock",
+ drbd_err(connection, "%s_sendmsg returned %d\n",
+ sock == connection->meta.socket ? "msock" : "sock",
rv);
- conn_request_state(tconn, NS(conn, C_BROKEN_PIPE), CS_HARD);
+ conn_request_state(connection, NS(conn, C_BROKEN_PIPE), CS_HARD);
} else
- conn_request_state(tconn, NS(conn, C_TIMEOUT), CS_HARD);
+ conn_request_state(connection, NS(conn, C_TIMEOUT), CS_HARD);
}
return sent;
@@ -1813,12 +1821,12 @@ int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
*
* Returns 0 upon success and a negative error value otherwise.
*/
-int drbd_send_all(struct drbd_tconn *tconn, struct socket *sock, void *buffer,
+int drbd_send_all(struct drbd_connection *connection, struct socket *sock, void *buffer,
size_t size, unsigned msg_flags)
{
int err;
- err = drbd_send(tconn, sock, buffer, size, msg_flags);
+ err = drbd_send(connection, sock, buffer, size, msg_flags);
if (err < 0)
return err;
if (err != size)
@@ -1828,16 +1836,16 @@ int drbd_send_all(struct drbd_tconn *tconn, struct socket *sock, void *buffer,
static int drbd_open(struct block_device *bdev, fmode_t mode)
{
- struct drbd_conf *mdev = bdev->bd_disk->private_data;
+ struct drbd_device *device = bdev->bd_disk->private_data;
unsigned long flags;
int rv = 0;
mutex_lock(&drbd_main_mutex);
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- /* to have a stable mdev->state.role
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ /* to have a stable device->state.role
* and no race with updating open_cnt */
- if (mdev->state.role != R_PRIMARY) {
+ if (device->state.role != R_PRIMARY) {
if (mode & FMODE_WRITE)
rv = -EROFS;
else if (!allow_oos)
@@ -1845,8 +1853,8 @@ static int drbd_open(struct block_device *bdev, fmode_t mode)
}
if (!rv)
- mdev->open_cnt++;
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ device->open_cnt++;
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
mutex_unlock(&drbd_main_mutex);
return rv;
@@ -1854,17 +1862,17 @@ static int drbd_open(struct block_device *bdev, fmode_t mode)
static void drbd_release(struct gendisk *gd, fmode_t mode)
{
- struct drbd_conf *mdev = gd->private_data;
+ struct drbd_device *device = gd->private_data;
mutex_lock(&drbd_main_mutex);
- mdev->open_cnt--;
+ device->open_cnt--;
mutex_unlock(&drbd_main_mutex);
}
-static void drbd_set_defaults(struct drbd_conf *mdev)
+static void drbd_set_defaults(struct drbd_device *device)
{
/* Beware! The actual layout differs
* between big endian and little endian */
- mdev->state = (union drbd_dev_state) {
+ device->state = (union drbd_dev_state) {
{ .role = R_SECONDARY,
.peer = R_UNKNOWN,
.conn = C_STANDALONE,
@@ -1873,130 +1881,123 @@ static void drbd_set_defaults(struct drbd_conf *mdev)
} };
}
-void drbd_init_set_defaults(struct drbd_conf *mdev)
+void drbd_init_set_defaults(struct drbd_device *device)
{
/* the memset(,0,) did most of this.
* note: only assignments, no allocation in here */
- drbd_set_defaults(mdev);
-
- atomic_set(&mdev->ap_bio_cnt, 0);
- atomic_set(&mdev->ap_pending_cnt, 0);
- atomic_set(&mdev->rs_pending_cnt, 0);
- atomic_set(&mdev->unacked_cnt, 0);
- atomic_set(&mdev->local_cnt, 0);
- atomic_set(&mdev->pp_in_use_by_net, 0);
- atomic_set(&mdev->rs_sect_in, 0);
- atomic_set(&mdev->rs_sect_ev, 0);
- atomic_set(&mdev->ap_in_flight, 0);
- atomic_set(&mdev->md_io_in_use, 0);
-
- mutex_init(&mdev->own_state_mutex);
- mdev->state_mutex = &mdev->own_state_mutex;
-
- spin_lock_init(&mdev->al_lock);
- spin_lock_init(&mdev->peer_seq_lock);
-
- INIT_LIST_HEAD(&mdev->active_ee);
- INIT_LIST_HEAD(&mdev->sync_ee);
- INIT_LIST_HEAD(&mdev->done_ee);
- INIT_LIST_HEAD(&mdev->read_ee);
- INIT_LIST_HEAD(&mdev->net_ee);
- INIT_LIST_HEAD(&mdev->resync_reads);
- INIT_LIST_HEAD(&mdev->resync_work.list);
- INIT_LIST_HEAD(&mdev->unplug_work.list);
- INIT_LIST_HEAD(&mdev->go_diskless.list);
- INIT_LIST_HEAD(&mdev->md_sync_work.list);
- INIT_LIST_HEAD(&mdev->start_resync_work.list);
- INIT_LIST_HEAD(&mdev->bm_io_work.w.list);
-
- mdev->resync_work.cb = w_resync_timer;
- mdev->unplug_work.cb = w_send_write_hint;
- mdev->go_diskless.cb = w_go_diskless;
- mdev->md_sync_work.cb = w_md_sync;
- mdev->bm_io_work.w.cb = w_bitmap_io;
- mdev->start_resync_work.cb = w_start_resync;
-
- mdev->resync_work.mdev = mdev;
- mdev->unplug_work.mdev = mdev;
- mdev->go_diskless.mdev = mdev;
- mdev->md_sync_work.mdev = mdev;
- mdev->bm_io_work.w.mdev = mdev;
- mdev->start_resync_work.mdev = mdev;
-
- init_timer(&mdev->resync_timer);
- init_timer(&mdev->md_sync_timer);
- init_timer(&mdev->start_resync_timer);
- init_timer(&mdev->request_timer);
- mdev->resync_timer.function = resync_timer_fn;
- mdev->resync_timer.data = (unsigned long) mdev;
- mdev->md_sync_timer.function = md_sync_timer_fn;
- mdev->md_sync_timer.data = (unsigned long) mdev;
- mdev->start_resync_timer.function = start_resync_timer_fn;
- mdev->start_resync_timer.data = (unsigned long) mdev;
- mdev->request_timer.function = request_timer_fn;
- mdev->request_timer.data = (unsigned long) mdev;
-
- init_waitqueue_head(&mdev->misc_wait);
- init_waitqueue_head(&mdev->state_wait);
- init_waitqueue_head(&mdev->ee_wait);
- init_waitqueue_head(&mdev->al_wait);
- init_waitqueue_head(&mdev->seq_wait);
-
- mdev->resync_wenr = LC_FREE;
- mdev->peer_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
- mdev->local_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
-}
-
-void drbd_mdev_cleanup(struct drbd_conf *mdev)
+ drbd_set_defaults(device);
+
+ atomic_set(&device->ap_bio_cnt, 0);
+ atomic_set(&device->ap_pending_cnt, 0);
+ atomic_set(&device->rs_pending_cnt, 0);
+ atomic_set(&device->unacked_cnt, 0);
+ atomic_set(&device->local_cnt, 0);
+ atomic_set(&device->pp_in_use_by_net, 0);
+ atomic_set(&device->rs_sect_in, 0);
+ atomic_set(&device->rs_sect_ev, 0);
+ atomic_set(&device->ap_in_flight, 0);
+ atomic_set(&device->md_io_in_use, 0);
+
+ mutex_init(&device->own_state_mutex);
+ device->state_mutex = &device->own_state_mutex;
+
+ spin_lock_init(&device->al_lock);
+ spin_lock_init(&device->peer_seq_lock);
+
+ INIT_LIST_HEAD(&device->active_ee);
+ INIT_LIST_HEAD(&device->sync_ee);
+ INIT_LIST_HEAD(&device->done_ee);
+ INIT_LIST_HEAD(&device->read_ee);
+ INIT_LIST_HEAD(&device->net_ee);
+ INIT_LIST_HEAD(&device->resync_reads);
+ INIT_LIST_HEAD(&device->resync_work.list);
+ INIT_LIST_HEAD(&device->unplug_work.list);
+ INIT_LIST_HEAD(&device->go_diskless.list);
+ INIT_LIST_HEAD(&device->md_sync_work.list);
+ INIT_LIST_HEAD(&device->start_resync_work.list);
+ INIT_LIST_HEAD(&device->bm_io_work.w.list);
+
+ device->resync_work.cb = w_resync_timer;
+ device->unplug_work.cb = w_send_write_hint;
+ device->go_diskless.cb = w_go_diskless;
+ device->md_sync_work.cb = w_md_sync;
+ device->bm_io_work.w.cb = w_bitmap_io;
+ device->start_resync_work.cb = w_start_resync;
+
+ init_timer(&device->resync_timer);
+ init_timer(&device->md_sync_timer);
+ init_timer(&device->start_resync_timer);
+ init_timer(&device->request_timer);
+ device->resync_timer.function = resync_timer_fn;
+ device->resync_timer.data = (unsigned long) device;
+ device->md_sync_timer.function = md_sync_timer_fn;
+ device->md_sync_timer.data = (unsigned long) device;
+ device->start_resync_timer.function = start_resync_timer_fn;
+ device->start_resync_timer.data = (unsigned long) device;
+ device->request_timer.function = request_timer_fn;
+ device->request_timer.data = (unsigned long) device;
+
+ init_waitqueue_head(&device->misc_wait);
+ init_waitqueue_head(&device->state_wait);
+ init_waitqueue_head(&device->ee_wait);
+ init_waitqueue_head(&device->al_wait);
+ init_waitqueue_head(&device->seq_wait);
+
+ device->resync_wenr = LC_FREE;
+ device->peer_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
+ device->local_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
+}
+
+void drbd_device_cleanup(struct drbd_device *device)
{
int i;
- if (mdev->tconn->receiver.t_state != NONE)
- dev_err(DEV, "ASSERT FAILED: receiver t_state == %d expected 0.\n",
- mdev->tconn->receiver.t_state);
-
- mdev->al_writ_cnt =
- mdev->bm_writ_cnt =
- mdev->read_cnt =
- mdev->recv_cnt =
- mdev->send_cnt =
- mdev->writ_cnt =
- mdev->p_size =
- mdev->rs_start =
- mdev->rs_total =
- mdev->rs_failed = 0;
- mdev->rs_last_events = 0;
- mdev->rs_last_sect_ev = 0;
+ if (first_peer_device(device)->connection->receiver.t_state != NONE)
+ drbd_err(device, "ASSERT FAILED: receiver t_state == %d expected 0.\n",
+ first_peer_device(device)->connection->receiver.t_state);
+
+ device->al_writ_cnt =
+ device->bm_writ_cnt =
+ device->read_cnt =
+ device->recv_cnt =
+ device->send_cnt =
+ device->writ_cnt =
+ device->p_size =
+ device->rs_start =
+ device->rs_total =
+ device->rs_failed = 0;
+ device->rs_last_events = 0;
+ device->rs_last_sect_ev = 0;
for (i = 0; i < DRBD_SYNC_MARKS; i++) {
- mdev->rs_mark_left[i] = 0;
- mdev->rs_mark_time[i] = 0;
+ device->rs_mark_left[i] = 0;
+ device->rs_mark_time[i] = 0;
}
- D_ASSERT(mdev->tconn->net_conf == NULL);
+ D_ASSERT(device, first_peer_device(device)->connection->net_conf == NULL);
- drbd_set_my_capacity(mdev, 0);
- if (mdev->bitmap) {
+ drbd_set_my_capacity(device, 0);
+ if (device->bitmap) {
/* maybe never allocated. */
- drbd_bm_resize(mdev, 0, 1);
- drbd_bm_cleanup(mdev);
+ drbd_bm_resize(device, 0, 1);
+ drbd_bm_cleanup(device);
}
- drbd_free_bc(mdev->ldev);
- mdev->ldev = NULL;
+ drbd_free_bc(device->ldev);
+ device->ldev = NULL;
- clear_bit(AL_SUSPENDED, &mdev->flags);
+ clear_bit(AL_SUSPENDED, &device->flags);
- D_ASSERT(list_empty(&mdev->active_ee));
- D_ASSERT(list_empty(&mdev->sync_ee));
- D_ASSERT(list_empty(&mdev->done_ee));
- D_ASSERT(list_empty(&mdev->read_ee));
- D_ASSERT(list_empty(&mdev->net_ee));
- D_ASSERT(list_empty(&mdev->resync_reads));
- D_ASSERT(list_empty(&mdev->tconn->sender_work.q));
- D_ASSERT(list_empty(&mdev->resync_work.list));
- D_ASSERT(list_empty(&mdev->unplug_work.list));
- D_ASSERT(list_empty(&mdev->go_diskless.list));
+ D_ASSERT(device, list_empty(&device->active_ee));
+ D_ASSERT(device, list_empty(&device->sync_ee));
+ D_ASSERT(device, list_empty(&device->done_ee));
+ D_ASSERT(device, list_empty(&device->read_ee));
+ D_ASSERT(device, list_empty(&device->net_ee));
+ D_ASSERT(device, list_empty(&device->resync_reads));
+ D_ASSERT(device, list_empty(&first_peer_device(device)->connection->sender_work.q));
+ D_ASSERT(device, list_empty(&device->resync_work.list));
+ D_ASSERT(device, list_empty(&device->unplug_work.list));
+ D_ASSERT(device, list_empty(&device->go_diskless.list));
- drbd_set_defaults(mdev);
+ drbd_set_defaults(device);
}
@@ -2011,7 +2012,7 @@ static void drbd_destroy_mempools(void)
drbd_pp_vacant--;
}
- /* D_ASSERT(atomic_read(&drbd_pp_vacant)==0); */
+ /* D_ASSERT(device, atomic_read(&drbd_pp_vacant)==0); */
if (drbd_md_io_bio_set)
bioset_free(drbd_md_io_bio_set);
@@ -2131,69 +2132,73 @@ static struct notifier_block drbd_notifier = {
.notifier_call = drbd_notify_sys,
};
-static void drbd_release_all_peer_reqs(struct drbd_conf *mdev)
+static void drbd_release_all_peer_reqs(struct drbd_device *device)
{
int rr;
- rr = drbd_free_peer_reqs(mdev, &mdev->active_ee);
+ rr = drbd_free_peer_reqs(device, &device->active_ee);
if (rr)
- dev_err(DEV, "%d EEs in active list found!\n", rr);
+ drbd_err(device, "%d EEs in active list found!\n", rr);
- rr = drbd_free_peer_reqs(mdev, &mdev->sync_ee);
+ rr = drbd_free_peer_reqs(device, &device->sync_ee);
if (rr)
- dev_err(DEV, "%d EEs in sync list found!\n", rr);
+ drbd_err(device, "%d EEs in sync list found!\n", rr);
- rr = drbd_free_peer_reqs(mdev, &mdev->read_ee);
+ rr = drbd_free_peer_reqs(device, &device->read_ee);
if (rr)
- dev_err(DEV, "%d EEs in read list found!\n", rr);
+ drbd_err(device, "%d EEs in read list found!\n", rr);
- rr = drbd_free_peer_reqs(mdev, &mdev->done_ee);
+ rr = drbd_free_peer_reqs(device, &device->done_ee);
if (rr)
- dev_err(DEV, "%d EEs in done list found!\n", rr);
+ drbd_err(device, "%d EEs in done list found!\n", rr);
- rr = drbd_free_peer_reqs(mdev, &mdev->net_ee);
+ rr = drbd_free_peer_reqs(device, &device->net_ee);
if (rr)
- dev_err(DEV, "%d EEs in net list found!\n", rr);
+ drbd_err(device, "%d EEs in net list found!\n", rr);
}
/* caution. no locking. */
-void drbd_minor_destroy(struct kref *kref)
+void drbd_destroy_device(struct kref *kref)
{
- struct drbd_conf *mdev = container_of(kref, struct drbd_conf, kref);
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_device *device = container_of(kref, struct drbd_device, kref);
+ struct drbd_resource *resource = device->resource;
+ struct drbd_connection *connection;
- del_timer_sync(&mdev->request_timer);
+ del_timer_sync(&device->request_timer);
/* paranoia asserts */
- D_ASSERT(mdev->open_cnt == 0);
+ D_ASSERT(device, device->open_cnt == 0);
/* end paranoia asserts */
/* cleanup stuff that may have been allocated during
* device (re-)configuration or state changes */
- if (mdev->this_bdev)
- bdput(mdev->this_bdev);
+ if (device->this_bdev)
+ bdput(device->this_bdev);
- drbd_free_bc(mdev->ldev);
- mdev->ldev = NULL;
+ drbd_free_bc(device->ldev);
+ device->ldev = NULL;
- drbd_release_all_peer_reqs(mdev);
+ drbd_release_all_peer_reqs(device);
- lc_destroy(mdev->act_log);
- lc_destroy(mdev->resync);
+ lc_destroy(device->act_log);
+ lc_destroy(device->resync);
- kfree(mdev->p_uuid);
- /* mdev->p_uuid = NULL; */
+ kfree(device->p_uuid);
+ /* device->p_uuid = NULL; */
- if (mdev->bitmap) /* should no longer be there. */
- drbd_bm_cleanup(mdev);
- __free_page(mdev->md_io_page);
- put_disk(mdev->vdisk);
- blk_cleanup_queue(mdev->rq_queue);
- kfree(mdev->rs_plan_s);
- kfree(mdev);
+ if (device->bitmap) /* should no longer be there. */
+ drbd_bm_cleanup(device);
+ __free_page(device->md_io_page);
+ put_disk(device->vdisk);
+ blk_cleanup_queue(device->rq_queue);
+ kfree(device->rs_plan_s);
+ kfree(first_peer_device(device));
+ kfree(device);
- kref_put(&tconn->kref, &conn_destroy);
+ for_each_connection(connection, resource)
+ kref_put(&connection->kref, drbd_destroy_connection);
+ kref_put(&resource->kref, drbd_destroy_resource);
}
/* One global retry thread, if we need to push back some bio and have it
@@ -2218,19 +2223,19 @@ static void do_retry(struct work_struct *ws)
spin_unlock_irq(&retry->lock);
list_for_each_entry_safe(req, tmp, &writes, tl_requests) {
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct bio *bio = req->master_bio;
unsigned long start_time = req->start_time;
bool expected;
- expected =
+ expected =
expect(atomic_read(&req->completion_ref) == 0) &&
expect(req->rq_state & RQ_POSTPONED) &&
expect((req->rq_state & RQ_LOCAL_PENDING) == 0 ||
(req->rq_state & RQ_LOCAL_ABORTED) != 0);
if (!expected)
- dev_err(DEV, "req=%p completion_ref=%d rq_state=%x\n",
+ drbd_err(device, "req=%p completion_ref=%d rq_state=%x\n",
req, atomic_read(&req->completion_ref),
req->rq_state);
@@ -2254,8 +2259,8 @@ static void do_retry(struct work_struct *ws)
/* We are not just doing generic_make_request(),
* as we want to keep the start_time information. */
- inc_ap_bio(mdev);
- __drbd_make_request(mdev, bio, start_time);
+ inc_ap_bio(device);
+ __drbd_make_request(device, bio, start_time);
}
}
@@ -2269,17 +2274,38 @@ void drbd_restart_request(struct drbd_request *req)
/* Drop the extra reference that would otherwise
* have been dropped by complete_master_bio.
* do_retry() needs to grab a new one. */
- dec_ap_bio(req->w.mdev);
+ dec_ap_bio(req->device);
queue_work(retry.wq, &retry.worker);
}
+void drbd_destroy_resource(struct kref *kref)
+{
+ struct drbd_resource *resource =
+ container_of(kref, struct drbd_resource, kref);
+
+ idr_destroy(&resource->devices);
+ free_cpumask_var(resource->cpu_mask);
+ kfree(resource->name);
+ kfree(resource);
+}
+
+void drbd_free_resource(struct drbd_resource *resource)
+{
+ struct drbd_connection *connection, *tmp;
+
+ for_each_connection_safe(connection, tmp, resource) {
+ list_del(&connection->connections);
+ kref_put(&connection->kref, drbd_destroy_connection);
+ }
+ kref_put(&resource->kref, drbd_destroy_resource);
+}
static void drbd_cleanup(void)
{
unsigned int i;
- struct drbd_conf *mdev;
- struct drbd_tconn *tconn, *tmp;
+ struct drbd_device *device;
+ struct drbd_resource *resource, *tmp;
unregister_reboot_notifier(&drbd_notifier);
@@ -2299,26 +2325,19 @@ static void drbd_cleanup(void)
drbd_genl_unregister();
- idr_for_each_entry(&minors, mdev, i) {
- idr_remove(&minors, mdev_to_minor(mdev));
- idr_remove(&mdev->tconn->volumes, mdev->vnr);
- destroy_workqueue(mdev->submit.wq);
- del_gendisk(mdev->vdisk);
- /* synchronize_rcu(); No other threads running at this point */
- kref_put(&mdev->kref, &drbd_minor_destroy);
- }
+ idr_for_each_entry(&drbd_devices, device, i)
+ drbd_delete_device(device);
/* not _rcu since, no other updater anymore. Genl already unregistered */
- list_for_each_entry_safe(tconn, tmp, &drbd_tconns, all_tconn) {
- list_del(&tconn->all_tconn); /* not _rcu no proc, not other threads */
- /* synchronize_rcu(); */
- kref_put(&tconn->kref, &conn_destroy);
+ for_each_resource_safe(resource, tmp, &drbd_resources) {
+ list_del(&resource->resources);
+ drbd_free_resource(resource);
}
drbd_destroy_mempools();
unregister_blkdev(DRBD_MAJOR, "drbd");
- idr_destroy(&minors);
+ idr_destroy(&drbd_devices);
printk(KERN_INFO "drbd: module cleanup done.\n");
}
@@ -2332,49 +2351,50 @@ static void drbd_cleanup(void)
*/
static int drbd_congested(void *congested_data, int bdi_bits)
{
- struct drbd_conf *mdev = congested_data;
+ struct drbd_device *device = congested_data;
struct request_queue *q;
char reason = '-';
int r = 0;
- if (!may_inc_ap_bio(mdev)) {
+ if (!may_inc_ap_bio(device)) {
/* DRBD has frozen IO */
r = bdi_bits;
reason = 'd';
goto out;
}
- if (test_bit(CALLBACK_PENDING, &mdev->tconn->flags)) {
+ if (test_bit(CALLBACK_PENDING, &first_peer_device(device)->connection->flags)) {
r |= (1 << BDI_async_congested);
/* Without good local data, we would need to read from remote,
* and that would need the worker thread as well, which is
* currently blocked waiting for that usermode helper to
* finish.
*/
- if (!get_ldev_if_state(mdev, D_UP_TO_DATE))
+ if (!get_ldev_if_state(device, D_UP_TO_DATE))
r |= (1 << BDI_sync_congested);
else
- put_ldev(mdev);
+ put_ldev(device);
r &= bdi_bits;
reason = 'c';
goto out;
}
- if (get_ldev(mdev)) {
- q = bdev_get_queue(mdev->ldev->backing_bdev);
+ if (get_ldev(device)) {
+ q = bdev_get_queue(device->ldev->backing_bdev);
r = bdi_congested(&q->backing_dev_info, bdi_bits);
- put_ldev(mdev);
+ put_ldev(device);
if (r)
reason = 'b';
}
- if (bdi_bits & (1 << BDI_async_congested) && test_bit(NET_CONGESTED, &mdev->tconn->flags)) {
+ if (bdi_bits & (1 << BDI_async_congested) &&
+ test_bit(NET_CONGESTED, &first_peer_device(device)->connection->flags)) {
r |= (1 << BDI_async_congested);
reason = reason == 'b' ? 'a' : 'n';
}
out:
- mdev->congestion_reason = reason;
+ device->congestion_reason = reason;
return r;
}
@@ -2385,45 +2405,72 @@ static void drbd_init_workqueue(struct drbd_work_queue* wq)
init_waitqueue_head(&wq->q_wait);
}
-struct drbd_tconn *conn_get_by_name(const char *name)
+struct completion_work {
+ struct drbd_work w;
+ struct completion done;
+};
+
+static int w_complete(struct drbd_work *w, int cancel)
+{
+ struct completion_work *completion_work =
+ container_of(w, struct completion_work, w);
+
+ complete(&completion_work->done);
+ return 0;
+}
+
+void drbd_flush_workqueue(struct drbd_work_queue *work_queue)
+{
+ struct completion_work completion_work;
+
+ completion_work.w.cb = w_complete;
+ init_completion(&completion_work.done);
+ drbd_queue_work(work_queue, &completion_work.w);
+ wait_for_completion(&completion_work.done);
+}
+
+struct drbd_resource *drbd_find_resource(const char *name)
{
- struct drbd_tconn *tconn;
+ struct drbd_resource *resource;
if (!name || !name[0])
return NULL;
rcu_read_lock();
- list_for_each_entry_rcu(tconn, &drbd_tconns, all_tconn) {
- if (!strcmp(tconn->name, name)) {
- kref_get(&tconn->kref);
+ for_each_resource_rcu(resource, &drbd_resources) {
+ if (!strcmp(resource->name, name)) {
+ kref_get(&resource->kref);
goto found;
}
}
- tconn = NULL;
+ resource = NULL;
found:
rcu_read_unlock();
- return tconn;
+ return resource;
}
-struct drbd_tconn *conn_get_by_addrs(void *my_addr, int my_addr_len,
+struct drbd_connection *conn_get_by_addrs(void *my_addr, int my_addr_len,
void *peer_addr, int peer_addr_len)
{
- struct drbd_tconn *tconn;
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
rcu_read_lock();
- list_for_each_entry_rcu(tconn, &drbd_tconns, all_tconn) {
- if (tconn->my_addr_len == my_addr_len &&
- tconn->peer_addr_len == peer_addr_len &&
- !memcmp(&tconn->my_addr, my_addr, my_addr_len) &&
- !memcmp(&tconn->peer_addr, peer_addr, peer_addr_len)) {
- kref_get(&tconn->kref);
- goto found;
+ for_each_resource_rcu(resource, &drbd_resources) {
+ for_each_connection_rcu(connection, resource) {
+ if (connection->my_addr_len == my_addr_len &&
+ connection->peer_addr_len == peer_addr_len &&
+ !memcmp(&connection->my_addr, my_addr, my_addr_len) &&
+ !memcmp(&connection->peer_addr, peer_addr, peer_addr_len)) {
+ kref_get(&connection->kref);
+ goto found;
+ }
}
}
- tconn = NULL;
+ connection = NULL;
found:
rcu_read_unlock();
- return tconn;
+ return connection;
}
static int drbd_alloc_socket(struct drbd_socket *socket)
@@ -2443,29 +2490,30 @@ static void drbd_free_socket(struct drbd_socket *socket)
free_page((unsigned long) socket->rbuf);
}
-void conn_free_crypto(struct drbd_tconn *tconn)
+void conn_free_crypto(struct drbd_connection *connection)
{
- drbd_free_sock(tconn);
+ drbd_free_sock(connection);
- crypto_free_hash(tconn->csums_tfm);
- crypto_free_hash(tconn->verify_tfm);
- crypto_free_hash(tconn->cram_hmac_tfm);
- crypto_free_hash(tconn->integrity_tfm);
- crypto_free_hash(tconn->peer_integrity_tfm);
- kfree(tconn->int_dig_in);
- kfree(tconn->int_dig_vv);
+ crypto_free_hash(connection->csums_tfm);
+ crypto_free_hash(connection->verify_tfm);
+ crypto_free_hash(connection->cram_hmac_tfm);
+ crypto_free_hash(connection->integrity_tfm);
+ crypto_free_hash(connection->peer_integrity_tfm);
+ kfree(connection->int_dig_in);
+ kfree(connection->int_dig_vv);
- tconn->csums_tfm = NULL;
- tconn->verify_tfm = NULL;
- tconn->cram_hmac_tfm = NULL;
- tconn->integrity_tfm = NULL;
- tconn->peer_integrity_tfm = NULL;
- tconn->int_dig_in = NULL;
- tconn->int_dig_vv = NULL;
+ connection->csums_tfm = NULL;
+ connection->verify_tfm = NULL;
+ connection->cram_hmac_tfm = NULL;
+ connection->integrity_tfm = NULL;
+ connection->peer_integrity_tfm = NULL;
+ connection->int_dig_in = NULL;
+ connection->int_dig_vv = NULL;
}
-int set_resource_options(struct drbd_tconn *tconn, struct res_opts *res_opts)
+int set_resource_options(struct drbd_resource *resource, struct res_opts *res_opts)
{
+ struct drbd_connection *connection;
cpumask_var_t new_cpu_mask;
int err;
@@ -2478,22 +2526,24 @@ int set_resource_options(struct drbd_tconn *tconn, struct res_opts *res_opts)
/* silently ignore cpu mask on UP kernel */
if (nr_cpu_ids > 1 && res_opts->cpu_mask[0] != 0) {
- /* FIXME: Get rid of constant 32 here */
- err = bitmap_parse(res_opts->cpu_mask, 32,
+ err = bitmap_parse(res_opts->cpu_mask, DRBD_CPU_MASK_SIZE,
cpumask_bits(new_cpu_mask), nr_cpu_ids);
if (err) {
- conn_warn(tconn, "bitmap_parse() failed with %d\n", err);
+ drbd_warn(resource, "bitmap_parse() failed with %d\n", err);
/* retcode = ERR_CPU_MASK_PARSE; */
goto fail;
}
}
- tconn->res_opts = *res_opts;
- if (!cpumask_equal(tconn->cpu_mask, new_cpu_mask)) {
- cpumask_copy(tconn->cpu_mask, new_cpu_mask);
- drbd_calc_cpu_mask(tconn);
- tconn->receiver.reset_cpu_mask = 1;
- tconn->asender.reset_cpu_mask = 1;
- tconn->worker.reset_cpu_mask = 1;
+ resource->res_opts = *res_opts;
+ if (cpumask_empty(new_cpu_mask))
+ drbd_calc_cpu_mask(&new_cpu_mask);
+ if (!cpumask_equal(resource->cpu_mask, new_cpu_mask)) {
+ cpumask_copy(resource->cpu_mask, new_cpu_mask);
+ for_each_connection_rcu(connection, resource) {
+ connection->receiver.reset_cpu_mask = 1;
+ connection->asender.reset_cpu_mask = 1;
+ connection->worker.reset_cpu_mask = 1;
+ }
}
err = 0;
@@ -2503,146 +2553,177 @@ fail:
}
+struct drbd_resource *drbd_create_resource(const char *name)
+{
+ struct drbd_resource *resource;
+
+ resource = kzalloc(sizeof(struct drbd_resource), GFP_KERNEL);
+ if (!resource)
+ goto fail;
+ resource->name = kstrdup(name, GFP_KERNEL);
+ if (!resource->name)
+ goto fail_free_resource;
+ if (!zalloc_cpumask_var(&resource->cpu_mask, GFP_KERNEL))
+ goto fail_free_name;
+ kref_init(&resource->kref);
+ idr_init(&resource->devices);
+ INIT_LIST_HEAD(&resource->connections);
+ list_add_tail_rcu(&resource->resources, &drbd_resources);
+ mutex_init(&resource->conf_update);
+ spin_lock_init(&resource->req_lock);
+ return resource;
+
+fail_free_name:
+ kfree(resource->name);
+fail_free_resource:
+ kfree(resource);
+fail:
+ return NULL;
+}
+
/* caller must be under genl_lock() */
-struct drbd_tconn *conn_create(const char *name, struct res_opts *res_opts)
+struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
{
- struct drbd_tconn *tconn;
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
- tconn = kzalloc(sizeof(struct drbd_tconn), GFP_KERNEL);
- if (!tconn)
+ connection = kzalloc(sizeof(struct drbd_connection), GFP_KERNEL);
+ if (!connection)
return NULL;
- tconn->name = kstrdup(name, GFP_KERNEL);
- if (!tconn->name)
+ if (drbd_alloc_socket(&connection->data))
goto fail;
-
- if (drbd_alloc_socket(&tconn->data))
- goto fail;
- if (drbd_alloc_socket(&tconn->meta))
+ if (drbd_alloc_socket(&connection->meta))
goto fail;
- if (!zalloc_cpumask_var(&tconn->cpu_mask, GFP_KERNEL))
+ connection->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL);
+ if (!connection->current_epoch)
goto fail;
- if (set_resource_options(tconn, res_opts))
- goto fail;
+ INIT_LIST_HEAD(&connection->transfer_log);
- tconn->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL);
- if (!tconn->current_epoch)
- goto fail;
+ INIT_LIST_HEAD(&connection->current_epoch->list);
+ connection->epochs = 1;
+ spin_lock_init(&connection->epoch_lock);
+ connection->write_ordering = WO_bdev_flush;
- INIT_LIST_HEAD(&tconn->transfer_log);
+ connection->send.seen_any_write_yet = false;
+ connection->send.current_epoch_nr = 0;
+ connection->send.current_epoch_writes = 0;
- INIT_LIST_HEAD(&tconn->current_epoch->list);
- tconn->epochs = 1;
- spin_lock_init(&tconn->epoch_lock);
- tconn->write_ordering = WO_bdev_flush;
+ resource = drbd_create_resource(name);
+ if (!resource)
+ goto fail;
- tconn->send.seen_any_write_yet = false;
- tconn->send.current_epoch_nr = 0;
- tconn->send.current_epoch_writes = 0;
+ connection->cstate = C_STANDALONE;
+ mutex_init(&connection->cstate_mutex);
+ init_waitqueue_head(&connection->ping_wait);
+ idr_init(&connection->peer_devices);
- tconn->cstate = C_STANDALONE;
- mutex_init(&tconn->cstate_mutex);
- spin_lock_init(&tconn->req_lock);
- mutex_init(&tconn->conf_update);
- init_waitqueue_head(&tconn->ping_wait);
- idr_init(&tconn->volumes);
+ drbd_init_workqueue(&connection->sender_work);
+ mutex_init(&connection->data.mutex);
+ mutex_init(&connection->meta.mutex);
- drbd_init_workqueue(&tconn->sender_work);
- mutex_init(&tconn->data.mutex);
- mutex_init(&tconn->meta.mutex);
+ drbd_thread_init(resource, &connection->receiver, drbd_receiver, "receiver");
+ connection->receiver.connection = connection;
+ drbd_thread_init(resource, &connection->worker, drbd_worker, "worker");
+ connection->worker.connection = connection;
+ drbd_thread_init(resource, &connection->asender, drbd_asender, "asender");
+ connection->asender.connection = connection;
- drbd_thread_init(tconn, &tconn->receiver, drbdd_init, "receiver");
- drbd_thread_init(tconn, &tconn->worker, drbd_worker, "worker");
- drbd_thread_init(tconn, &tconn->asender, drbd_asender, "asender");
+ kref_init(&connection->kref);
- kref_init(&tconn->kref);
- list_add_tail_rcu(&tconn->all_tconn, &drbd_tconns);
+ connection->resource = resource;
- return tconn;
+ if (set_resource_options(resource, res_opts))
+ goto fail_resource;
-fail:
- kfree(tconn->current_epoch);
- free_cpumask_var(tconn->cpu_mask);
- drbd_free_socket(&tconn->meta);
- drbd_free_socket(&tconn->data);
- kfree(tconn->name);
- kfree(tconn);
+ kref_get(&resource->kref);
+ list_add_tail_rcu(&connection->connections, &resource->connections);
+ return connection;
+fail_resource:
+ list_del(&resource->resources);
+ drbd_free_resource(resource);
+fail:
+ kfree(connection->current_epoch);
+ drbd_free_socket(&connection->meta);
+ drbd_free_socket(&connection->data);
+ kfree(connection);
return NULL;
}
-void conn_destroy(struct kref *kref)
+void drbd_destroy_connection(struct kref *kref)
{
- struct drbd_tconn *tconn = container_of(kref, struct drbd_tconn, kref);
+ struct drbd_connection *connection = container_of(kref, struct drbd_connection, kref);
+ struct drbd_resource *resource = connection->resource;
- if (atomic_read(&tconn->current_epoch->epoch_size) != 0)
- conn_err(tconn, "epoch_size:%d\n", atomic_read(&tconn->current_epoch->epoch_size));
- kfree(tconn->current_epoch);
+ if (atomic_read(&connection->current_epoch->epoch_size) != 0)
+ drbd_err(connection, "epoch_size:%d\n", atomic_read(&connection->current_epoch->epoch_size));
+ kfree(connection->current_epoch);
- idr_destroy(&tconn->volumes);
+ idr_destroy(&connection->peer_devices);
- free_cpumask_var(tconn->cpu_mask);
- drbd_free_socket(&tconn->meta);
- drbd_free_socket(&tconn->data);
- kfree(tconn->name);
- kfree(tconn->int_dig_in);
- kfree(tconn->int_dig_vv);
- kfree(tconn);
+ drbd_free_socket(&connection->meta);
+ drbd_free_socket(&connection->data);
+ kfree(connection->int_dig_in);
+ kfree(connection->int_dig_vv);
+ kfree(connection);
+ kref_put(&resource->kref, drbd_destroy_resource);
}
-int init_submitter(struct drbd_conf *mdev)
+static int init_submitter(struct drbd_device *device)
{
/* opencoded create_singlethread_workqueue(),
* to be able to say "drbd%d", ..., minor */
- mdev->submit.wq = alloc_workqueue("drbd%u_submit",
- WQ_UNBOUND | WQ_MEM_RECLAIM, 1, mdev->minor);
- if (!mdev->submit.wq)
+ device->submit.wq = alloc_workqueue("drbd%u_submit",
+ WQ_UNBOUND | WQ_MEM_RECLAIM, 1, device->minor);
+ if (!device->submit.wq)
return -ENOMEM;
- INIT_WORK(&mdev->submit.worker, do_submit);
- spin_lock_init(&mdev->submit.lock);
- INIT_LIST_HEAD(&mdev->submit.writes);
+ INIT_WORK(&device->submit.worker, do_submit);
+ spin_lock_init(&device->submit.lock);
+ INIT_LIST_HEAD(&device->submit.writes);
return 0;
}
-enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr)
+enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned int minor, int vnr)
{
- struct drbd_conf *mdev;
+ struct drbd_connection *connection;
+ struct drbd_device *device;
+ struct drbd_peer_device *peer_device, *tmp_peer_device;
struct gendisk *disk;
struct request_queue *q;
- int vnr_got = vnr;
- int minor_got = minor;
+ int id;
enum drbd_ret_code err = ERR_NOMEM;
- mdev = minor_to_mdev(minor);
- if (mdev)
+ device = minor_to_device(minor);
+ if (device)
return ERR_MINOR_EXISTS;
/* GFP_KERNEL, we are outside of all write-out paths */
- mdev = kzalloc(sizeof(struct drbd_conf), GFP_KERNEL);
- if (!mdev)
+ device = kzalloc(sizeof(struct drbd_device), GFP_KERNEL);
+ if (!device)
return ERR_NOMEM;
+ kref_init(&device->kref);
- kref_get(&tconn->kref);
- mdev->tconn = tconn;
+ kref_get(&resource->kref);
+ device->resource = resource;
+ device->minor = minor;
+ device->vnr = vnr;
- mdev->minor = minor;
- mdev->vnr = vnr;
-
- drbd_init_set_defaults(mdev);
+ drbd_init_set_defaults(device);
q = blk_alloc_queue(GFP_KERNEL);
if (!q)
goto out_no_q;
- mdev->rq_queue = q;
- q->queuedata = mdev;
+ device->rq_queue = q;
+ q->queuedata = device;
disk = alloc_disk(1);
if (!disk)
goto out_no_disk;
- mdev->vdisk = disk;
+ device->vdisk = disk;
set_disk_ro(disk, true);
@@ -2651,14 +2732,14 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor,
disk->first_minor = minor;
disk->fops = &drbd_ops;
sprintf(disk->disk_name, "drbd%d", minor);
- disk->private_data = mdev;
+ disk->private_data = device;
- mdev->this_bdev = bdget(MKDEV(DRBD_MAJOR, minor));
+ device->this_bdev = bdget(MKDEV(DRBD_MAJOR, minor));
/* we have no partitions. we contain only ourselves. */
- mdev->this_bdev->bd_contains = mdev->this_bdev;
+ device->this_bdev->bd_contains = device->this_bdev;
q->backing_dev_info.congested_fn = drbd_congested;
- q->backing_dev_info.congested_data = mdev;
+ q->backing_dev_info.congested_data = device;
blk_queue_make_request(q, drbd_make_request);
blk_queue_flush(q, REQ_FLUSH | REQ_FUA);
@@ -2667,70 +2748,125 @@ enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor,
blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE_SAFE >> 8);
blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
blk_queue_merge_bvec(q, drbd_merge_bvec);
- q->queue_lock = &mdev->tconn->req_lock; /* needed since we use */
+ q->queue_lock = &resource->req_lock;
- mdev->md_io_page = alloc_page(GFP_KERNEL);
- if (!mdev->md_io_page)
+ device->md_io_page = alloc_page(GFP_KERNEL);
+ if (!device->md_io_page)
goto out_no_io_page;
- if (drbd_bm_init(mdev))
+ if (drbd_bm_init(device))
goto out_no_bitmap;
- mdev->read_requests = RB_ROOT;
- mdev->write_requests = RB_ROOT;
+ device->read_requests = RB_ROOT;
+ device->write_requests = RB_ROOT;
- minor_got = idr_alloc(&minors, mdev, minor, minor + 1, GFP_KERNEL);
- if (minor_got < 0) {
- if (minor_got == -ENOSPC) {
+ id = idr_alloc(&drbd_devices, device, minor, minor + 1, GFP_KERNEL);
+ if (id < 0) {
+ if (id == -ENOSPC) {
err = ERR_MINOR_EXISTS;
drbd_msg_put_info("requested minor exists already");
}
goto out_no_minor_idr;
}
+ kref_get(&device->kref);
- vnr_got = idr_alloc(&tconn->volumes, mdev, vnr, vnr + 1, GFP_KERNEL);
- if (vnr_got < 0) {
- if (vnr_got == -ENOSPC) {
- err = ERR_INVALID_REQUEST;
- drbd_msg_put_info("requested volume exists already");
+ id = idr_alloc(&resource->devices, device, vnr, vnr + 1, GFP_KERNEL);
+ if (id < 0) {
+ if (id == -ENOSPC) {
+ err = ERR_MINOR_EXISTS;
+ drbd_msg_put_info("requested minor exists already");
}
goto out_idr_remove_minor;
}
+ kref_get(&device->kref);
+
+ INIT_LIST_HEAD(&device->peer_devices);
+ for_each_connection(connection, resource) {
+ peer_device = kzalloc(sizeof(struct drbd_peer_device), GFP_KERNEL);
+ if (!peer_device)
+ goto out_idr_remove_from_resource;
+ peer_device->connection = connection;
+ peer_device->device = device;
+
+ list_add(&peer_device->peer_devices, &device->peer_devices);
+ kref_get(&device->kref);
- if (init_submitter(mdev)) {
+ id = idr_alloc(&connection->peer_devices, peer_device, vnr, vnr + 1, GFP_KERNEL);
+ if (id < 0) {
+ if (id == -ENOSPC) {
+ err = ERR_INVALID_REQUEST;
+ drbd_msg_put_info("requested volume exists already");
+ }
+ goto out_idr_remove_from_resource;
+ }
+ kref_get(&connection->kref);
+ }
+
+ if (init_submitter(device)) {
err = ERR_NOMEM;
drbd_msg_put_info("unable to create submit workqueue");
goto out_idr_remove_vol;
}
add_disk(disk);
- kref_init(&mdev->kref); /* one ref for both idrs and the the add_disk */
/* inherit the connection state */
- mdev->state.conn = tconn->cstate;
- if (mdev->state.conn == C_WF_REPORT_PARAMS)
- drbd_connected(mdev);
+ device->state.conn = first_connection(resource)->cstate;
+ if (device->state.conn == C_WF_REPORT_PARAMS) {
+ for_each_peer_device(peer_device, device)
+ drbd_connected(peer_device);
+ }
return NO_ERROR;
out_idr_remove_vol:
- idr_remove(&tconn->volumes, vnr_got);
+ idr_remove(&connection->peer_devices, vnr);
+out_idr_remove_from_resource:
+ for_each_connection(connection, resource) {
+ peer_device = idr_find(&connection->peer_devices, vnr);
+ if (peer_device) {
+ idr_remove(&connection->peer_devices, vnr);
+ kref_put(&connection->kref, drbd_destroy_connection);
+ }
+ }
+ for_each_peer_device_safe(peer_device, tmp_peer_device, device) {
+ list_del(&peer_device->peer_devices);
+ kfree(peer_device);
+ }
+ idr_remove(&resource->devices, vnr);
out_idr_remove_minor:
- idr_remove(&minors, minor_got);
+ idr_remove(&drbd_devices, minor);
synchronize_rcu();
out_no_minor_idr:
- drbd_bm_cleanup(mdev);
+ drbd_bm_cleanup(device);
out_no_bitmap:
- __free_page(mdev->md_io_page);
+ __free_page(device->md_io_page);
out_no_io_page:
put_disk(disk);
out_no_disk:
blk_cleanup_queue(q);
out_no_q:
- kfree(mdev);
- kref_put(&tconn->kref, &conn_destroy);
+ kref_put(&resource->kref, drbd_destroy_resource);
+ kfree(device);
return err;
}
+void drbd_delete_device(struct drbd_device *device)
+{
+ struct drbd_resource *resource = device->resource;
+ struct drbd_connection *connection;
+ int refs = 3;
+
+ for_each_connection(connection, resource) {
+ idr_remove(&connection->peer_devices, device->vnr);
+ refs++;
+ }
+ idr_remove(&resource->devices, device->vnr);
+ idr_remove(&drbd_devices, device_to_minor(device));
+ del_gendisk(device->vdisk);
+ synchronize_rcu();
+ kref_sub(&device->kref, refs, drbd_destroy_device);
+}
+
int __init drbd_init(void)
{
int err;
@@ -2761,10 +2897,10 @@ int __init drbd_init(void)
init_waitqueue_head(&drbd_pp_wait);
drbd_proc = NULL; /* play safe for drbd_cleanup */
- idr_init(&minors);
+ idr_init(&drbd_devices);
rwlock_init(&global_state_lock);
- INIT_LIST_HEAD(&drbd_tconns);
+ INIT_LIST_HEAD(&drbd_resources);
err = drbd_genl_register();
if (err) {
@@ -2822,37 +2958,39 @@ void drbd_free_bc(struct drbd_backing_dev *ldev)
kfree(ldev);
}
-void drbd_free_sock(struct drbd_tconn *tconn)
+void drbd_free_sock(struct drbd_connection *connection)
{
- if (tconn->data.socket) {
- mutex_lock(&tconn->data.mutex);
- kernel_sock_shutdown(tconn->data.socket, SHUT_RDWR);
- sock_release(tconn->data.socket);
- tconn->data.socket = NULL;
- mutex_unlock(&tconn->data.mutex);
+ if (connection->data.socket) {
+ mutex_lock(&connection->data.mutex);
+ kernel_sock_shutdown(connection->data.socket, SHUT_RDWR);
+ sock_release(connection->data.socket);
+ connection->data.socket = NULL;
+ mutex_unlock(&connection->data.mutex);
}
- if (tconn->meta.socket) {
- mutex_lock(&tconn->meta.mutex);
- kernel_sock_shutdown(tconn->meta.socket, SHUT_RDWR);
- sock_release(tconn->meta.socket);
- tconn->meta.socket = NULL;
- mutex_unlock(&tconn->meta.mutex);
+ if (connection->meta.socket) {
+ mutex_lock(&connection->meta.mutex);
+ kernel_sock_shutdown(connection->meta.socket, SHUT_RDWR);
+ sock_release(connection->meta.socket);
+ connection->meta.socket = NULL;
+ mutex_unlock(&connection->meta.mutex);
}
}
/* meta data management */
-void conn_md_sync(struct drbd_tconn *tconn)
+void conn_md_sync(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- kref_get(&mdev->kref);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+
+ kref_get(&device->kref);
rcu_read_unlock();
- drbd_md_sync(mdev);
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ drbd_md_sync(device);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
}
rcu_read_unlock();
@@ -2883,7 +3021,7 @@ struct meta_data_on_disk {
-void drbd_md_write(struct drbd_conf *mdev, void *b)
+void drbd_md_write(struct drbd_device *device, void *b)
{
struct meta_data_on_disk *buffer = b;
sector_t sector;
@@ -2891,39 +3029,39 @@ void drbd_md_write(struct drbd_conf *mdev, void *b)
memset(buffer, 0, sizeof(*buffer));
- buffer->la_size_sect = cpu_to_be64(drbd_get_capacity(mdev->this_bdev));
+ buffer->la_size_sect = cpu_to_be64(drbd_get_capacity(device->this_bdev));
for (i = UI_CURRENT; i < UI_SIZE; i++)
- buffer->uuid[i] = cpu_to_be64(mdev->ldev->md.uuid[i]);
- buffer->flags = cpu_to_be32(mdev->ldev->md.flags);
+ buffer->uuid[i] = cpu_to_be64(device->ldev->md.uuid[i]);
+ buffer->flags = cpu_to_be32(device->ldev->md.flags);
buffer->magic = cpu_to_be32(DRBD_MD_MAGIC_84_UNCLEAN);
- buffer->md_size_sect = cpu_to_be32(mdev->ldev->md.md_size_sect);
- buffer->al_offset = cpu_to_be32(mdev->ldev->md.al_offset);
- buffer->al_nr_extents = cpu_to_be32(mdev->act_log->nr_elements);
+ buffer->md_size_sect = cpu_to_be32(device->ldev->md.md_size_sect);
+ buffer->al_offset = cpu_to_be32(device->ldev->md.al_offset);
+ buffer->al_nr_extents = cpu_to_be32(device->act_log->nr_elements);
buffer->bm_bytes_per_bit = cpu_to_be32(BM_BLOCK_SIZE);
- buffer->device_uuid = cpu_to_be64(mdev->ldev->md.device_uuid);
+ buffer->device_uuid = cpu_to_be64(device->ldev->md.device_uuid);
- buffer->bm_offset = cpu_to_be32(mdev->ldev->md.bm_offset);
- buffer->la_peer_max_bio_size = cpu_to_be32(mdev->peer_max_bio_size);
+ buffer->bm_offset = cpu_to_be32(device->ldev->md.bm_offset);
+ buffer->la_peer_max_bio_size = cpu_to_be32(device->peer_max_bio_size);
- buffer->al_stripes = cpu_to_be32(mdev->ldev->md.al_stripes);
- buffer->al_stripe_size_4k = cpu_to_be32(mdev->ldev->md.al_stripe_size_4k);
+ buffer->al_stripes = cpu_to_be32(device->ldev->md.al_stripes);
+ buffer->al_stripe_size_4k = cpu_to_be32(device->ldev->md.al_stripe_size_4k);
- D_ASSERT(drbd_md_ss(mdev->ldev) == mdev->ldev->md.md_offset);
- sector = mdev->ldev->md.md_offset;
+ D_ASSERT(device, drbd_md_ss(device->ldev) == device->ldev->md.md_offset);
+ sector = device->ldev->md.md_offset;
- if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) {
+ if (drbd_md_sync_page_io(device, device->ldev, sector, WRITE)) {
/* this was a try anyways ... */
- dev_err(DEV, "meta data update failed!\n");
- drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
+ drbd_err(device, "meta data update failed!\n");
+ drbd_chk_io_error(device, 1, DRBD_META_IO_ERROR);
}
}
/**
* drbd_md_sync() - Writes the meta data super block if the MD_DIRTY flag bit is set
- * @mdev: DRBD device.
+ * @device: DRBD device.
*/
-void drbd_md_sync(struct drbd_conf *mdev)
+void drbd_md_sync(struct drbd_device *device)
{
struct meta_data_on_disk *buffer;
@@ -2931,32 +3069,32 @@ void drbd_md_sync(struct drbd_conf *mdev)
BUILD_BUG_ON(UI_SIZE != 4);
BUILD_BUG_ON(sizeof(struct meta_data_on_disk) != 4096);
- del_timer(&mdev->md_sync_timer);
+ del_timer(&device->md_sync_timer);
/* timer may be rearmed by drbd_md_mark_dirty() now. */
- if (!test_and_clear_bit(MD_DIRTY, &mdev->flags))
+ if (!test_and_clear_bit(MD_DIRTY, &device->flags))
return;
/* We use here D_FAILED and not D_ATTACHING because we try to write
* metadata even if we detach due to a disk failure! */
- if (!get_ldev_if_state(mdev, D_FAILED))
+ if (!get_ldev_if_state(device, D_FAILED))
return;
- buffer = drbd_md_get_buffer(mdev);
+ buffer = drbd_md_get_buffer(device);
if (!buffer)
goto out;
- drbd_md_write(mdev, buffer);
+ drbd_md_write(device, buffer);
- /* Update mdev->ldev->md.la_size_sect,
+ /* Update device->ldev->md.la_size_sect,
* since we updated it on metadata. */
- mdev->ldev->md.la_size_sect = drbd_get_capacity(mdev->this_bdev);
+ device->ldev->md.la_size_sect = drbd_get_capacity(device->this_bdev);
- drbd_md_put_buffer(mdev);
+ drbd_md_put_buffer(device);
out:
- put_ldev(mdev);
+ put_ldev(device);
}
-static int check_activity_log_stripe_size(struct drbd_conf *mdev,
+static int check_activity_log_stripe_size(struct drbd_device *device,
struct meta_data_on_disk *on_disk,
struct drbd_md *in_core)
{
@@ -2996,12 +3134,12 @@ static int check_activity_log_stripe_size(struct drbd_conf *mdev,
return 0;
err:
- dev_err(DEV, "invalid activity log striping: al_stripes=%u, al_stripe_size_4k=%u\n",
+ drbd_err(device, "invalid activity log striping: al_stripes=%u, al_stripe_size_4k=%u\n",
al_stripes, al_stripe_size_4k);
return -EINVAL;
}
-static int check_offsets_and_sizes(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
+static int check_offsets_and_sizes(struct drbd_device *device, struct drbd_backing_dev *bdev)
{
sector_t capacity = drbd_get_capacity(bdev->md_bdev);
struct drbd_md *in_core = &bdev->md;
@@ -3068,7 +3206,7 @@ static int check_offsets_and_sizes(struct drbd_conf *mdev, struct drbd_backing_d
return 0;
err:
- dev_err(DEV, "meta data offsets don't make sense: idx=%d "
+ drbd_err(device, "meta data offsets don't make sense: idx=%d "
"al_s=%u, al_sz4k=%u, al_offset=%d, bm_offset=%d, "
"md_size_sect=%u, la_size=%llu, md_capacity=%llu\n",
in_core->meta_dev_idx,
@@ -3083,25 +3221,25 @@ err:
/**
* drbd_md_read() - Reads in the meta data super block
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @bdev: Device from which the meta data should be read in.
*
* Return NO_ERROR on success, and an enum drbd_ret_code in case
* something goes wrong.
*
* Called exactly once during drbd_adm_attach(), while still being D_DISKLESS,
- * even before @bdev is assigned to @mdev->ldev.
+ * even before @bdev is assigned to @device->ldev.
*/
-int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
+int drbd_md_read(struct drbd_device *device, struct drbd_backing_dev *bdev)
{
struct meta_data_on_disk *buffer;
u32 magic, flags;
int i, rv = NO_ERROR;
- if (mdev->state.disk != D_DISKLESS)
+ if (device->state.disk != D_DISKLESS)
return ERR_DISK_CONFIGURED;
- buffer = drbd_md_get_buffer(mdev);
+ buffer = drbd_md_get_buffer(device);
if (!buffer)
return ERR_NOMEM;
@@ -3110,10 +3248,10 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
bdev->md.meta_dev_idx = bdev->disk_conf->meta_dev_idx;
bdev->md.md_offset = drbd_md_ss(bdev);
- if (drbd_md_sync_page_io(mdev, bdev, bdev->md.md_offset, READ)) {
+ if (drbd_md_sync_page_io(device, bdev, bdev->md.md_offset, READ)) {
/* NOTE: can't do normal error processing here as this is
called BEFORE disk is attached */
- dev_err(DEV, "Error while reading metadata.\n");
+ drbd_err(device, "Error while reading metadata.\n");
rv = ERR_IO_MD_DISK;
goto err;
}
@@ -3123,7 +3261,7 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
if (magic == DRBD_MD_MAGIC_84_UNCLEAN ||
(magic == DRBD_MD_MAGIC_08 && !(flags & MDF_AL_CLEAN))) {
/* btw: that's Activity Log clean, not "all" clean. */
- dev_err(DEV, "Found unclean meta data. Did you \"drbdadm apply-al\"?\n");
+ drbd_err(device, "Found unclean meta data. Did you \"drbdadm apply-al\"?\n");
rv = ERR_MD_UNCLEAN;
goto err;
}
@@ -3131,14 +3269,14 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
rv = ERR_MD_INVALID;
if (magic != DRBD_MD_MAGIC_08) {
if (magic == DRBD_MD_MAGIC_07)
- dev_err(DEV, "Found old (0.7) meta data magic. Did you \"drbdadm create-md\"?\n");
+ drbd_err(device, "Found old (0.7) meta data magic. Did you \"drbdadm create-md\"?\n");
else
- dev_err(DEV, "Meta data magic not found. Did you \"drbdadm create-md\"?\n");
+ drbd_err(device, "Meta data magic not found. Did you \"drbdadm create-md\"?\n");
goto err;
}
if (be32_to_cpu(buffer->bm_bytes_per_bit) != BM_BLOCK_SIZE) {
- dev_err(DEV, "unexpected bm_bytes_per_bit: %u (expected %u)\n",
+ drbd_err(device, "unexpected bm_bytes_per_bit: %u (expected %u)\n",
be32_to_cpu(buffer->bm_bytes_per_bit), BM_BLOCK_SIZE);
goto err;
}
@@ -3155,182 +3293,182 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
bdev->md.al_offset = be32_to_cpu(buffer->al_offset);
bdev->md.bm_offset = be32_to_cpu(buffer->bm_offset);
- if (check_activity_log_stripe_size(mdev, buffer, &bdev->md))
+ if (check_activity_log_stripe_size(device, buffer, &bdev->md))
goto err;
- if (check_offsets_and_sizes(mdev, bdev))
+ if (check_offsets_and_sizes(device, bdev))
goto err;
if (be32_to_cpu(buffer->bm_offset) != bdev->md.bm_offset) {
- dev_err(DEV, "unexpected bm_offset: %d (expected %d)\n",
+ drbd_err(device, "unexpected bm_offset: %d (expected %d)\n",
be32_to_cpu(buffer->bm_offset), bdev->md.bm_offset);
goto err;
}
if (be32_to_cpu(buffer->md_size_sect) != bdev->md.md_size_sect) {
- dev_err(DEV, "unexpected md_size: %u (expected %u)\n",
+ drbd_err(device, "unexpected md_size: %u (expected %u)\n",
be32_to_cpu(buffer->md_size_sect), bdev->md.md_size_sect);
goto err;
}
rv = NO_ERROR;
- spin_lock_irq(&mdev->tconn->req_lock);
- if (mdev->state.conn < C_CONNECTED) {
+ spin_lock_irq(&device->resource->req_lock);
+ if (device->state.conn < C_CONNECTED) {
unsigned int peer;
peer = be32_to_cpu(buffer->la_peer_max_bio_size);
peer = max(peer, DRBD_MAX_BIO_SIZE_SAFE);
- mdev->peer_max_bio_size = peer;
+ device->peer_max_bio_size = peer;
}
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
err:
- drbd_md_put_buffer(mdev);
+ drbd_md_put_buffer(device);
return rv;
}
/**
* drbd_md_mark_dirty() - Mark meta data super block as dirty
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Call this function if you change anything that should be written to
* the meta-data super block. This function sets MD_DIRTY, and starts a
* timer that ensures that within five seconds you have to call drbd_md_sync().
*/
#ifdef DEBUG
-void drbd_md_mark_dirty_(struct drbd_conf *mdev, unsigned int line, const char *func)
+void drbd_md_mark_dirty_(struct drbd_device *device, unsigned int line, const char *func)
{
- if (!test_and_set_bit(MD_DIRTY, &mdev->flags)) {
- mod_timer(&mdev->md_sync_timer, jiffies + HZ);
- mdev->last_md_mark_dirty.line = line;
- mdev->last_md_mark_dirty.func = func;
+ if (!test_and_set_bit(MD_DIRTY, &device->flags)) {
+ mod_timer(&device->md_sync_timer, jiffies + HZ);
+ device->last_md_mark_dirty.line = line;
+ device->last_md_mark_dirty.func = func;
}
}
#else
-void drbd_md_mark_dirty(struct drbd_conf *mdev)
+void drbd_md_mark_dirty(struct drbd_device *device)
{
- if (!test_and_set_bit(MD_DIRTY, &mdev->flags))
- mod_timer(&mdev->md_sync_timer, jiffies + 5*HZ);
+ if (!test_and_set_bit(MD_DIRTY, &device->flags))
+ mod_timer(&device->md_sync_timer, jiffies + 5*HZ);
}
#endif
-void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local)
+void drbd_uuid_move_history(struct drbd_device *device) __must_hold(local)
{
int i;
for (i = UI_HISTORY_START; i < UI_HISTORY_END; i++)
- mdev->ldev->md.uuid[i+1] = mdev->ldev->md.uuid[i];
+ device->ldev->md.uuid[i+1] = device->ldev->md.uuid[i];
}
-void __drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local)
+void __drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local)
{
if (idx == UI_CURRENT) {
- if (mdev->state.role == R_PRIMARY)
+ if (device->state.role == R_PRIMARY)
val |= 1;
else
val &= ~((u64)1);
- drbd_set_ed_uuid(mdev, val);
+ drbd_set_ed_uuid(device, val);
}
- mdev->ldev->md.uuid[idx] = val;
- drbd_md_mark_dirty(mdev);
+ device->ldev->md.uuid[idx] = val;
+ drbd_md_mark_dirty(device);
}
-void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local)
+void _drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local)
{
unsigned long flags;
- spin_lock_irqsave(&mdev->ldev->md.uuid_lock, flags);
- __drbd_uuid_set(mdev, idx, val);
- spin_unlock_irqrestore(&mdev->ldev->md.uuid_lock, flags);
+ spin_lock_irqsave(&device->ldev->md.uuid_lock, flags);
+ __drbd_uuid_set(device, idx, val);
+ spin_unlock_irqrestore(&device->ldev->md.uuid_lock, flags);
}
-void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local)
+void drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local)
{
unsigned long flags;
- spin_lock_irqsave(&mdev->ldev->md.uuid_lock, flags);
- if (mdev->ldev->md.uuid[idx]) {
- drbd_uuid_move_history(mdev);
- mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[idx];
+ spin_lock_irqsave(&device->ldev->md.uuid_lock, flags);
+ if (device->ldev->md.uuid[idx]) {
+ drbd_uuid_move_history(device);
+ device->ldev->md.uuid[UI_HISTORY_START] = device->ldev->md.uuid[idx];
}
- __drbd_uuid_set(mdev, idx, val);
- spin_unlock_irqrestore(&mdev->ldev->md.uuid_lock, flags);
+ __drbd_uuid_set(device, idx, val);
+ spin_unlock_irqrestore(&device->ldev->md.uuid_lock, flags);
}
/**
* drbd_uuid_new_current() - Creates a new current UUID
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Creates a new current UUID, and rotates the old current UUID into
* the bitmap slot. Causes an incremental resync upon next connect.
*/
-void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local)
+void drbd_uuid_new_current(struct drbd_device *device) __must_hold(local)
{
u64 val;
unsigned long long bm_uuid;
get_random_bytes(&val, sizeof(u64));
- spin_lock_irq(&mdev->ldev->md.uuid_lock);
- bm_uuid = mdev->ldev->md.uuid[UI_BITMAP];
+ spin_lock_irq(&device->ldev->md.uuid_lock);
+ bm_uuid = device->ldev->md.uuid[UI_BITMAP];
if (bm_uuid)
- dev_warn(DEV, "bm UUID was already set: %llX\n", bm_uuid);
+ drbd_warn(device, "bm UUID was already set: %llX\n", bm_uuid);
- mdev->ldev->md.uuid[UI_BITMAP] = mdev->ldev->md.uuid[UI_CURRENT];
- __drbd_uuid_set(mdev, UI_CURRENT, val);
- spin_unlock_irq(&mdev->ldev->md.uuid_lock);
+ device->ldev->md.uuid[UI_BITMAP] = device->ldev->md.uuid[UI_CURRENT];
+ __drbd_uuid_set(device, UI_CURRENT, val);
+ spin_unlock_irq(&device->ldev->md.uuid_lock);
- drbd_print_uuids(mdev, "new current UUID");
+ drbd_print_uuids(device, "new current UUID");
/* get it to stable storage _now_ */
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
}
-void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local)
+void drbd_uuid_set_bm(struct drbd_device *device, u64 val) __must_hold(local)
{
unsigned long flags;
- if (mdev->ldev->md.uuid[UI_BITMAP] == 0 && val == 0)
+ if (device->ldev->md.uuid[UI_BITMAP] == 0 && val == 0)
return;
- spin_lock_irqsave(&mdev->ldev->md.uuid_lock, flags);
+ spin_lock_irqsave(&device->ldev->md.uuid_lock, flags);
if (val == 0) {
- drbd_uuid_move_history(mdev);
- mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP];
- mdev->ldev->md.uuid[UI_BITMAP] = 0;
+ drbd_uuid_move_history(device);
+ device->ldev->md.uuid[UI_HISTORY_START] = device->ldev->md.uuid[UI_BITMAP];
+ device->ldev->md.uuid[UI_BITMAP] = 0;
} else {
- unsigned long long bm_uuid = mdev->ldev->md.uuid[UI_BITMAP];
+ unsigned long long bm_uuid = device->ldev->md.uuid[UI_BITMAP];
if (bm_uuid)
- dev_warn(DEV, "bm UUID was already set: %llX\n", bm_uuid);
+ drbd_warn(device, "bm UUID was already set: %llX\n", bm_uuid);
- mdev->ldev->md.uuid[UI_BITMAP] = val & ~((u64)1);
+ device->ldev->md.uuid[UI_BITMAP] = val & ~((u64)1);
}
- spin_unlock_irqrestore(&mdev->ldev->md.uuid_lock, flags);
+ spin_unlock_irqrestore(&device->ldev->md.uuid_lock, flags);
- drbd_md_mark_dirty(mdev);
+ drbd_md_mark_dirty(device);
}
/**
* drbd_bmio_set_n_write() - io_fn for drbd_queue_bitmap_io() or drbd_bitmap_io()
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Sets all bits in the bitmap and writes the whole bitmap to stable storage.
*/
-int drbd_bmio_set_n_write(struct drbd_conf *mdev)
+int drbd_bmio_set_n_write(struct drbd_device *device)
{
int rv = -EIO;
- if (get_ldev_if_state(mdev, D_ATTACHING)) {
- drbd_md_set_flag(mdev, MDF_FULL_SYNC);
- drbd_md_sync(mdev);
- drbd_bm_set_all(mdev);
+ if (get_ldev_if_state(device, D_ATTACHING)) {
+ drbd_md_set_flag(device, MDF_FULL_SYNC);
+ drbd_md_sync(device);
+ drbd_bm_set_all(device);
- rv = drbd_bm_write(mdev);
+ rv = drbd_bm_write(device);
if (!rv) {
- drbd_md_clear_flag(mdev, MDF_FULL_SYNC);
- drbd_md_sync(mdev);
+ drbd_md_clear_flag(device, MDF_FULL_SYNC);
+ drbd_md_sync(device);
}
- put_ldev(mdev);
+ put_ldev(device);
}
return rv;
@@ -3338,19 +3476,19 @@ int drbd_bmio_set_n_write(struct drbd_conf *mdev)
/**
* drbd_bmio_clear_n_write() - io_fn for drbd_queue_bitmap_io() or drbd_bitmap_io()
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Clears all bits in the bitmap and writes the whole bitmap to stable storage.
*/
-int drbd_bmio_clear_n_write(struct drbd_conf *mdev)
+int drbd_bmio_clear_n_write(struct drbd_device *device)
{
int rv = -EIO;
- drbd_resume_al(mdev);
- if (get_ldev_if_state(mdev, D_ATTACHING)) {
- drbd_bm_clear_all(mdev);
- rv = drbd_bm_write(mdev);
- put_ldev(mdev);
+ drbd_resume_al(device);
+ if (get_ldev_if_state(device, D_ATTACHING)) {
+ drbd_bm_clear_all(device);
+ rv = drbd_bm_write(device);
+ put_ldev(device);
}
return rv;
@@ -3358,50 +3496,52 @@ int drbd_bmio_clear_n_write(struct drbd_conf *mdev)
static int w_bitmap_io(struct drbd_work *w, int unused)
{
- struct bm_io_work *work = container_of(w, struct bm_io_work, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device =
+ container_of(w, struct drbd_device, bm_io_work.w);
+ struct bm_io_work *work = &device->bm_io_work;
int rv = -EIO;
- D_ASSERT(atomic_read(&mdev->ap_bio_cnt) == 0);
+ D_ASSERT(device, atomic_read(&device->ap_bio_cnt) == 0);
- if (get_ldev(mdev)) {
- drbd_bm_lock(mdev, work->why, work->flags);
- rv = work->io_fn(mdev);
- drbd_bm_unlock(mdev);
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ drbd_bm_lock(device, work->why, work->flags);
+ rv = work->io_fn(device);
+ drbd_bm_unlock(device);
+ put_ldev(device);
}
- clear_bit_unlock(BITMAP_IO, &mdev->flags);
- wake_up(&mdev->misc_wait);
+ clear_bit_unlock(BITMAP_IO, &device->flags);
+ wake_up(&device->misc_wait);
if (work->done)
- work->done(mdev, rv);
+ work->done(device, rv);
- clear_bit(BITMAP_IO_QUEUED, &mdev->flags);
+ clear_bit(BITMAP_IO_QUEUED, &device->flags);
work->why = NULL;
work->flags = 0;
return 0;
}
-void drbd_ldev_destroy(struct drbd_conf *mdev)
+void drbd_ldev_destroy(struct drbd_device *device)
{
- lc_destroy(mdev->resync);
- mdev->resync = NULL;
- lc_destroy(mdev->act_log);
- mdev->act_log = NULL;
+ lc_destroy(device->resync);
+ device->resync = NULL;
+ lc_destroy(device->act_log);
+ device->act_log = NULL;
__no_warn(local,
- drbd_free_bc(mdev->ldev);
- mdev->ldev = NULL;);
+ drbd_free_bc(device->ldev);
+ device->ldev = NULL;);
- clear_bit(GO_DISKLESS, &mdev->flags);
+ clear_bit(GO_DISKLESS, &device->flags);
}
static int w_go_diskless(struct drbd_work *w, int unused)
{
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device =
+ container_of(w, struct drbd_device, go_diskless);
- D_ASSERT(mdev->state.disk == D_FAILED);
+ D_ASSERT(device, device->state.disk == D_FAILED);
/* we cannot assert local_cnt == 0 here, as get_ldev_if_state will
* inc/dec it frequently. Once we are D_DISKLESS, no one will touch
* the protected members anymore, though, so once put_ldev reaches zero
@@ -3420,27 +3560,27 @@ static int w_go_diskless(struct drbd_work *w, int unused)
* We still need to check if both bitmap and ldev are present, we may
* end up here after a failed attach, before ldev was even assigned.
*/
- if (mdev->bitmap && mdev->ldev) {
+ if (device->bitmap && device->ldev) {
/* An interrupted resync or similar is allowed to recounts bits
* while we detach.
* Any modifications would not be expected anymore, though.
*/
- if (drbd_bitmap_io_from_worker(mdev, drbd_bm_write,
+ if (drbd_bitmap_io_from_worker(device, drbd_bm_write,
"detach", BM_LOCKED_TEST_ALLOWED)) {
- if (test_bit(WAS_READ_ERROR, &mdev->flags)) {
- drbd_md_set_flag(mdev, MDF_FULL_SYNC);
- drbd_md_sync(mdev);
+ if (test_bit(WAS_READ_ERROR, &device->flags)) {
+ drbd_md_set_flag(device, MDF_FULL_SYNC);
+ drbd_md_sync(device);
}
}
}
- drbd_force_state(mdev, NS(disk, D_DISKLESS));
+ drbd_force_state(device, NS(disk, D_DISKLESS));
return 0;
}
/**
* drbd_queue_bitmap_io() - Queues an IO operation on the whole bitmap
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @io_fn: IO callback to be called when bitmap IO is possible
* @done: callback to be called after the bitmap IO was performed
* @why: Descriptive text of the reason for doing the IO
@@ -3450,76 +3590,77 @@ static int w_go_diskless(struct drbd_work *w, int unused)
* called from worker context. It MUST NOT be used while a previous such
* work is still pending!
*/
-void drbd_queue_bitmap_io(struct drbd_conf *mdev,
- int (*io_fn)(struct drbd_conf *),
- void (*done)(struct drbd_conf *, int),
+void drbd_queue_bitmap_io(struct drbd_device *device,
+ int (*io_fn)(struct drbd_device *),
+ void (*done)(struct drbd_device *, int),
char *why, enum bm_flag flags)
{
- D_ASSERT(current == mdev->tconn->worker.task);
+ D_ASSERT(device, current == first_peer_device(device)->connection->worker.task);
- D_ASSERT(!test_bit(BITMAP_IO_QUEUED, &mdev->flags));
- D_ASSERT(!test_bit(BITMAP_IO, &mdev->flags));
- D_ASSERT(list_empty(&mdev->bm_io_work.w.list));
- if (mdev->bm_io_work.why)
- dev_err(DEV, "FIXME going to queue '%s' but '%s' still pending?\n",
- why, mdev->bm_io_work.why);
+ D_ASSERT(device, !test_bit(BITMAP_IO_QUEUED, &device->flags));
+ D_ASSERT(device, !test_bit(BITMAP_IO, &device->flags));
+ D_ASSERT(device, list_empty(&device->bm_io_work.w.list));
+ if (device->bm_io_work.why)
+ drbd_err(device, "FIXME going to queue '%s' but '%s' still pending?\n",
+ why, device->bm_io_work.why);
- mdev->bm_io_work.io_fn = io_fn;
- mdev->bm_io_work.done = done;
- mdev->bm_io_work.why = why;
- mdev->bm_io_work.flags = flags;
+ device->bm_io_work.io_fn = io_fn;
+ device->bm_io_work.done = done;
+ device->bm_io_work.why = why;
+ device->bm_io_work.flags = flags;
- spin_lock_irq(&mdev->tconn->req_lock);
- set_bit(BITMAP_IO, &mdev->flags);
- if (atomic_read(&mdev->ap_bio_cnt) == 0) {
- if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags))
- drbd_queue_work(&mdev->tconn->sender_work, &mdev->bm_io_work.w);
+ spin_lock_irq(&device->resource->req_lock);
+ set_bit(BITMAP_IO, &device->flags);
+ if (atomic_read(&device->ap_bio_cnt) == 0) {
+ if (!test_and_set_bit(BITMAP_IO_QUEUED, &device->flags))
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &device->bm_io_work.w);
}
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
}
/**
* drbd_bitmap_io() - Does an IO operation on the whole bitmap
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @io_fn: IO callback to be called when bitmap IO is possible
* @why: Descriptive text of the reason for doing the IO
*
* freezes application IO while that the actual IO operations runs. This
* functions MAY NOT be called from worker context.
*/
-int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *),
+int drbd_bitmap_io(struct drbd_device *device, int (*io_fn)(struct drbd_device *),
char *why, enum bm_flag flags)
{
int rv;
- D_ASSERT(current != mdev->tconn->worker.task);
+ D_ASSERT(device, current != first_peer_device(device)->connection->worker.task);
if ((flags & BM_LOCKED_SET_ALLOWED) == 0)
- drbd_suspend_io(mdev);
+ drbd_suspend_io(device);
- drbd_bm_lock(mdev, why, flags);
- rv = io_fn(mdev);
- drbd_bm_unlock(mdev);
+ drbd_bm_lock(device, why, flags);
+ rv = io_fn(device);
+ drbd_bm_unlock(device);
if ((flags & BM_LOCKED_SET_ALLOWED) == 0)
- drbd_resume_io(mdev);
+ drbd_resume_io(device);
return rv;
}
-void drbd_md_set_flag(struct drbd_conf *mdev, int flag) __must_hold(local)
+void drbd_md_set_flag(struct drbd_device *device, int flag) __must_hold(local)
{
- if ((mdev->ldev->md.flags & flag) != flag) {
- drbd_md_mark_dirty(mdev);
- mdev->ldev->md.flags |= flag;
+ if ((device->ldev->md.flags & flag) != flag) {
+ drbd_md_mark_dirty(device);
+ device->ldev->md.flags |= flag;
}
}
-void drbd_md_clear_flag(struct drbd_conf *mdev, int flag) __must_hold(local)
+void drbd_md_clear_flag(struct drbd_device *device, int flag) __must_hold(local)
{
- if ((mdev->ldev->md.flags & flag) != 0) {
- drbd_md_mark_dirty(mdev);
- mdev->ldev->md.flags &= ~flag;
+ if ((device->ldev->md.flags & flag) != 0) {
+ drbd_md_mark_dirty(device);
+ device->ldev->md.flags &= ~flag;
}
}
int drbd_md_test_flag(struct drbd_backing_dev *bdev, int flag)
@@ -3529,23 +3670,25 @@ int drbd_md_test_flag(struct drbd_backing_dev *bdev, int flag)
static void md_sync_timer_fn(unsigned long data)
{
- struct drbd_conf *mdev = (struct drbd_conf *) data;
+ struct drbd_device *device = (struct drbd_device *) data;
/* must not double-queue! */
- if (list_empty(&mdev->md_sync_work.list))
- drbd_queue_work_front(&mdev->tconn->sender_work, &mdev->md_sync_work);
+ if (list_empty(&device->md_sync_work.list))
+ drbd_queue_work_front(&first_peer_device(device)->connection->sender_work,
+ &device->md_sync_work);
}
static int w_md_sync(struct drbd_work *w, int unused)
{
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device =
+ container_of(w, struct drbd_device, md_sync_work);
- dev_warn(DEV, "md_sync_timer expired! Worker calls drbd_md_sync().\n");
+ drbd_warn(device, "md_sync_timer expired! Worker calls drbd_md_sync().\n");
#ifdef DEBUG
- dev_warn(DEV, "last md_mark_dirty: %s:%u\n",
- mdev->last_md_mark_dirty.func, mdev->last_md_mark_dirty.line);
+ drbd_warn(device, "last md_mark_dirty: %s:%u\n",
+ device->last_md_mark_dirty.func, device->last_md_mark_dirty.line);
#endif
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
return 0;
}
@@ -3621,18 +3764,18 @@ const char *cmdname(enum drbd_packet cmd)
/**
* drbd_wait_misc - wait for a request to make progress
- * @mdev: device associated with the request
+ * @device: device associated with the request
* @i: the struct drbd_interval embedded in struct drbd_request or
* struct drbd_peer_request
*/
-int drbd_wait_misc(struct drbd_conf *mdev, struct drbd_interval *i)
+int drbd_wait_misc(struct drbd_device *device, struct drbd_interval *i)
{
struct net_conf *nc;
DEFINE_WAIT(wait);
long timeout;
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
if (!nc) {
rcu_read_unlock();
return -ETIMEDOUT;
@@ -3640,14 +3783,14 @@ int drbd_wait_misc(struct drbd_conf *mdev, struct drbd_interval *i)
timeout = nc->ko_count ? nc->timeout * HZ / 10 * nc->ko_count : MAX_SCHEDULE_TIMEOUT;
rcu_read_unlock();
- /* Indicate to wake up mdev->misc_wait on progress. */
+ /* Indicate to wake up device->misc_wait on progress. */
i->waiting = true;
- prepare_to_wait(&mdev->misc_wait, &wait, TASK_INTERRUPTIBLE);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ prepare_to_wait(&device->misc_wait, &wait, TASK_INTERRUPTIBLE);
+ spin_unlock_irq(&device->resource->req_lock);
timeout = schedule_timeout(timeout);
- finish_wait(&mdev->misc_wait, &wait);
- spin_lock_irq(&mdev->tconn->req_lock);
- if (!timeout || mdev->state.conn < C_CONNECTED)
+ finish_wait(&device->misc_wait, &wait);
+ spin_lock_irq(&device->resource->req_lock);
+ if (!timeout || device->state.conn < C_CONNECTED)
return -ETIMEDOUT;
if (signal_pending(current))
return -ERESTARTSYS;
@@ -3703,20 +3846,20 @@ _drbd_fault_str(unsigned int type) {
}
unsigned int
-_drbd_insert_fault(struct drbd_conf *mdev, unsigned int type)
+_drbd_insert_fault(struct drbd_device *device, unsigned int type)
{
static struct fault_random_state rrs = {0, 0};
unsigned int ret = (
(fault_devs == 0 ||
- ((1 << mdev_to_minor(mdev)) & fault_devs) != 0) &&
+ ((1 << device_to_minor(device)) & fault_devs) != 0) &&
(((_drbd_fault_random(&rrs) % 100) + 1) <= fault_rate));
if (ret) {
fault_count++;
if (__ratelimit(&drbd_ratelimit_state))
- dev_warn(DEV, "***Simulating %s failure\n",
+ drbd_warn(device, "***Simulating %s failure\n",
_drbd_fault_str(type));
}
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index c706d50a8b06..526414bc2cab 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -32,6 +32,7 @@
#include <linux/blkpg.h>
#include <linux/cpumask.h>
#include "drbd_int.h"
+#include "drbd_protocol.h"
#include "drbd_req.h"
#include "drbd_wrappers.h"
#include <asm/unaligned.h>
@@ -44,8 +45,8 @@
// int drbd_adm_create_resource(struct sk_buff *skb, struct genl_info *info);
// int drbd_adm_delete_resource(struct sk_buff *skb, struct genl_info *info);
-int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info);
-int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info);
+int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info);
+int drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info);
int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info);
int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info);
@@ -102,8 +103,9 @@ static struct drbd_config_context {
/* pointer into reply buffer */
struct drbd_genlmsghdr *reply_dh;
/* resolved from attributes, if possible */
- struct drbd_conf *mdev;
- struct drbd_tconn *tconn;
+ struct drbd_device *device;
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
} adm_ctx;
static void drbd_adm_send_reply(struct sk_buff *skb, struct genl_info *info)
@@ -202,62 +204,67 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
adm_ctx.my_addr = nested_attr_tb[__nla_type(T_ctx_my_addr)];
adm_ctx.peer_addr = nested_attr_tb[__nla_type(T_ctx_peer_addr)];
if ((adm_ctx.my_addr &&
- nla_len(adm_ctx.my_addr) > sizeof(adm_ctx.tconn->my_addr)) ||
+ nla_len(adm_ctx.my_addr) > sizeof(adm_ctx.connection->my_addr)) ||
(adm_ctx.peer_addr &&
- nla_len(adm_ctx.peer_addr) > sizeof(adm_ctx.tconn->peer_addr))) {
+ nla_len(adm_ctx.peer_addr) > sizeof(adm_ctx.connection->peer_addr))) {
err = -EINVAL;
goto fail;
}
}
adm_ctx.minor = d_in->minor;
- adm_ctx.mdev = minor_to_mdev(d_in->minor);
- adm_ctx.tconn = conn_get_by_name(adm_ctx.resource_name);
+ adm_ctx.device = minor_to_device(d_in->minor);
+ if (adm_ctx.resource_name) {
+ adm_ctx.resource = drbd_find_resource(adm_ctx.resource_name);
+ }
- if (!adm_ctx.mdev && (flags & DRBD_ADM_NEED_MINOR)) {
+ if (!adm_ctx.device && (flags & DRBD_ADM_NEED_MINOR)) {
drbd_msg_put_info("unknown minor");
return ERR_MINOR_INVALID;
}
- if (!adm_ctx.tconn && (flags & DRBD_ADM_NEED_RESOURCE)) {
+ if (!adm_ctx.resource && (flags & DRBD_ADM_NEED_RESOURCE)) {
drbd_msg_put_info("unknown resource");
+ if (adm_ctx.resource_name)
+ return ERR_RES_NOT_KNOWN;
return ERR_INVALID_REQUEST;
}
if (flags & DRBD_ADM_NEED_CONNECTION) {
- if (adm_ctx.tconn && !(flags & DRBD_ADM_NEED_RESOURCE)) {
+ if (adm_ctx.resource) {
drbd_msg_put_info("no resource name expected");
return ERR_INVALID_REQUEST;
}
- if (adm_ctx.mdev) {
+ if (adm_ctx.device) {
drbd_msg_put_info("no minor number expected");
return ERR_INVALID_REQUEST;
}
if (adm_ctx.my_addr && adm_ctx.peer_addr)
- adm_ctx.tconn = conn_get_by_addrs(nla_data(adm_ctx.my_addr),
+ adm_ctx.connection = conn_get_by_addrs(nla_data(adm_ctx.my_addr),
nla_len(adm_ctx.my_addr),
nla_data(adm_ctx.peer_addr),
nla_len(adm_ctx.peer_addr));
- if (!adm_ctx.tconn) {
+ if (!adm_ctx.connection) {
drbd_msg_put_info("unknown connection");
return ERR_INVALID_REQUEST;
}
}
/* some more paranoia, if the request was over-determined */
- if (adm_ctx.mdev && adm_ctx.tconn &&
- adm_ctx.mdev->tconn != adm_ctx.tconn) {
- pr_warning("request: minor=%u, resource=%s; but that minor belongs to connection %s\n",
- adm_ctx.minor, adm_ctx.resource_name,
- adm_ctx.mdev->tconn->name);
+ if (adm_ctx.device && adm_ctx.resource &&
+ adm_ctx.device->resource != adm_ctx.resource) {
+ pr_warning("request: minor=%u, resource=%s; but that minor belongs to resource %s\n",
+ adm_ctx.minor, adm_ctx.resource->name,
+ adm_ctx.device->resource->name);
drbd_msg_put_info("minor exists in different resource");
return ERR_INVALID_REQUEST;
}
- if (adm_ctx.mdev &&
+ if (adm_ctx.device &&
adm_ctx.volume != VOLUME_UNSPECIFIED &&
- adm_ctx.volume != adm_ctx.mdev->vnr) {
+ adm_ctx.volume != adm_ctx.device->vnr) {
pr_warning("request: minor=%u, volume=%u; but that minor is volume %u in %s\n",
adm_ctx.minor, adm_ctx.volume,
- adm_ctx.mdev->vnr, adm_ctx.mdev->tconn->name);
+ adm_ctx.device->vnr,
+ adm_ctx.device->resource->name);
drbd_msg_put_info("minor exists as different volume");
return ERR_INVALID_REQUEST;
}
@@ -272,9 +279,13 @@ fail:
static int drbd_adm_finish(struct genl_info *info, int retcode)
{
- if (adm_ctx.tconn) {
- kref_put(&adm_ctx.tconn->kref, &conn_destroy);
- adm_ctx.tconn = NULL;
+ if (adm_ctx.connection) {
+ kref_put(&adm_ctx.connection->kref, drbd_destroy_connection);
+ adm_ctx.connection = NULL;
+ }
+ if (adm_ctx.resource) {
+ kref_put(&adm_ctx.resource->kref, drbd_destroy_resource);
+ adm_ctx.resource = NULL;
}
if (!adm_ctx.reply_skb)
@@ -285,34 +296,34 @@ static int drbd_adm_finish(struct genl_info *info, int retcode)
return 0;
}
-static void setup_khelper_env(struct drbd_tconn *tconn, char **envp)
+static void setup_khelper_env(struct drbd_connection *connection, char **envp)
{
char *afs;
/* FIXME: A future version will not allow this case. */
- if (tconn->my_addr_len == 0 || tconn->peer_addr_len == 0)
+ if (connection->my_addr_len == 0 || connection->peer_addr_len == 0)
return;
- switch (((struct sockaddr *)&tconn->peer_addr)->sa_family) {
+ switch (((struct sockaddr *)&connection->peer_addr)->sa_family) {
case AF_INET6:
afs = "ipv6";
snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI6",
- &((struct sockaddr_in6 *)&tconn->peer_addr)->sin6_addr);
+ &((struct sockaddr_in6 *)&connection->peer_addr)->sin6_addr);
break;
case AF_INET:
afs = "ipv4";
snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4",
- &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr);
+ &((struct sockaddr_in *)&connection->peer_addr)->sin_addr);
break;
default:
afs = "ssocks";
snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4",
- &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr);
+ &((struct sockaddr_in *)&connection->peer_addr)->sin_addr);
}
snprintf(envp[3], 20, "DRBD_PEER_AF=%s", afs);
}
-int drbd_khelper(struct drbd_conf *mdev, char *cmd)
+int drbd_khelper(struct drbd_device *device, char *cmd)
{
char *envp[] = { "HOME=/",
"TERM=linux",
@@ -322,39 +333,39 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd)
NULL };
char mb[12];
char *argv[] = {usermode_helper, cmd, mb, NULL };
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
struct sib_info sib;
int ret;
- if (current == tconn->worker.task)
- set_bit(CALLBACK_PENDING, &tconn->flags);
+ if (current == connection->worker.task)
+ set_bit(CALLBACK_PENDING, &connection->flags);
- snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev));
- setup_khelper_env(tconn, envp);
+ snprintf(mb, 12, "minor-%d", device_to_minor(device));
+ setup_khelper_env(connection, envp);
/* The helper may take some time.
* write out any unsynced meta data changes now */
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
- dev_info(DEV, "helper command: %s %s %s\n", usermode_helper, cmd, mb);
+ drbd_info(device, "helper command: %s %s %s\n", usermode_helper, cmd, mb);
sib.sib_reason = SIB_HELPER_PRE;
sib.helper_name = cmd;
- drbd_bcast_event(mdev, &sib);
+ drbd_bcast_event(device, &sib);
ret = call_usermodehelper(usermode_helper, argv, envp, UMH_WAIT_PROC);
if (ret)
- dev_warn(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
+ drbd_warn(device, "helper command: %s %s %s exit code %u (0x%x)\n",
usermode_helper, cmd, mb,
(ret >> 8) & 0xff, ret);
else
- dev_info(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
+ drbd_info(device, "helper command: %s %s %s exit code %u (0x%x)\n",
usermode_helper, cmd, mb,
(ret >> 8) & 0xff, ret);
sib.sib_reason = SIB_HELPER_POST;
sib.helper_exit_code = ret;
- drbd_bcast_event(mdev, &sib);
+ drbd_bcast_event(device, &sib);
- if (current == tconn->worker.task)
- clear_bit(CALLBACK_PENDING, &tconn->flags);
+ if (current == connection->worker.task)
+ clear_bit(CALLBACK_PENDING, &connection->flags);
if (ret < 0) /* Ignore any ERRNOs we got. */
ret = 0;
@@ -362,7 +373,7 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd)
return ret;
}
-int conn_khelper(struct drbd_tconn *tconn, char *cmd)
+static int conn_khelper(struct drbd_connection *connection, char *cmd)
{
char *envp[] = { "HOME=/",
"TERM=linux",
@@ -370,23 +381,24 @@ int conn_khelper(struct drbd_tconn *tconn, char *cmd)
(char[20]) { }, /* address family */
(char[60]) { }, /* address */
NULL };
- char *argv[] = {usermode_helper, cmd, tconn->name, NULL };
+ char *resource_name = connection->resource->name;
+ char *argv[] = {usermode_helper, cmd, resource_name, NULL };
int ret;
- setup_khelper_env(tconn, envp);
- conn_md_sync(tconn);
+ setup_khelper_env(connection, envp);
+ conn_md_sync(connection);
- conn_info(tconn, "helper command: %s %s %s\n", usermode_helper, cmd, tconn->name);
+ drbd_info(connection, "helper command: %s %s %s\n", usermode_helper, cmd, resource_name);
/* TODO: conn_bcast_event() ?? */
ret = call_usermodehelper(usermode_helper, argv, envp, UMH_WAIT_PROC);
if (ret)
- conn_warn(tconn, "helper command: %s %s %s exit code %u (0x%x)\n",
- usermode_helper, cmd, tconn->name,
+ drbd_warn(connection, "helper command: %s %s %s exit code %u (0x%x)\n",
+ usermode_helper, cmd, resource_name,
(ret >> 8) & 0xff, ret);
else
- conn_info(tconn, "helper command: %s %s %s exit code %u (0x%x)\n",
- usermode_helper, cmd, tconn->name,
+ drbd_info(connection, "helper command: %s %s %s exit code %u (0x%x)\n",
+ usermode_helper, cmd, resource_name,
(ret >> 8) & 0xff, ret);
/* TODO: conn_bcast_event() ?? */
@@ -396,18 +408,20 @@ int conn_khelper(struct drbd_tconn *tconn, char *cmd)
return ret;
}
-static enum drbd_fencing_p highest_fencing_policy(struct drbd_tconn *tconn)
+static enum drbd_fencing_p highest_fencing_policy(struct drbd_connection *connection)
{
enum drbd_fencing_p fp = FP_NOT_AVAIL;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (get_ldev_if_state(mdev, D_CONSISTENT)) {
- fp = max_t(enum drbd_fencing_p, fp,
- rcu_dereference(mdev->ldev->disk_conf)->fencing);
- put_ldev(mdev);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ if (get_ldev_if_state(device, D_CONSISTENT)) {
+ struct disk_conf *disk_conf =
+ rcu_dereference(peer_device->device->ldev->disk_conf);
+ fp = max_t(enum drbd_fencing_p, fp, disk_conf->fencing);
+ put_ldev(device);
}
}
rcu_read_unlock();
@@ -415,7 +429,7 @@ static enum drbd_fencing_p highest_fencing_policy(struct drbd_tconn *tconn)
return fp;
}
-bool conn_try_outdate_peer(struct drbd_tconn *tconn)
+bool conn_try_outdate_peer(struct drbd_connection *connection)
{
unsigned int connect_cnt;
union drbd_state mask = { };
@@ -424,26 +438,26 @@ bool conn_try_outdate_peer(struct drbd_tconn *tconn)
char *ex_to_string;
int r;
- if (tconn->cstate >= C_WF_REPORT_PARAMS) {
- conn_err(tconn, "Expected cstate < C_WF_REPORT_PARAMS\n");
+ if (connection->cstate >= C_WF_REPORT_PARAMS) {
+ drbd_err(connection, "Expected cstate < C_WF_REPORT_PARAMS\n");
return false;
}
- spin_lock_irq(&tconn->req_lock);
- connect_cnt = tconn->connect_cnt;
- spin_unlock_irq(&tconn->req_lock);
+ spin_lock_irq(&connection->resource->req_lock);
+ connect_cnt = connection->connect_cnt;
+ spin_unlock_irq(&connection->resource->req_lock);
- fp = highest_fencing_policy(tconn);
+ fp = highest_fencing_policy(connection);
switch (fp) {
case FP_NOT_AVAIL:
- conn_warn(tconn, "Not fencing peer, I'm not even Consistent myself.\n");
+ drbd_warn(connection, "Not fencing peer, I'm not even Consistent myself.\n");
goto out;
case FP_DONT_CARE:
return true;
default: ;
}
- r = conn_khelper(tconn, "fence-peer");
+ r = conn_khelper(connection, "fence-peer");
switch ((r>>8) & 0xff) {
case 3: /* peer is inconsistent */
@@ -457,7 +471,7 @@ bool conn_try_outdate_peer(struct drbd_tconn *tconn)
val.pdsk = D_OUTDATED;
break;
case 5: /* peer was down */
- if (conn_highest_disk(tconn) == D_UP_TO_DATE) {
+ if (conn_highest_disk(connection) == D_UP_TO_DATE) {
/* we will(have) create(d) a new UUID anyways... */
ex_to_string = "peer is unreachable, assumed to be dead";
mask.pdsk = D_MASK;
@@ -470,70 +484,70 @@ bool conn_try_outdate_peer(struct drbd_tconn *tconn)
* This is useful when an unconnected R_SECONDARY is asked to
* become R_PRIMARY, but finds the other peer being active. */
ex_to_string = "peer is active";
- conn_warn(tconn, "Peer is primary, outdating myself.\n");
+ drbd_warn(connection, "Peer is primary, outdating myself.\n");
mask.disk = D_MASK;
val.disk = D_OUTDATED;
break;
case 7:
if (fp != FP_STONITH)
- conn_err(tconn, "fence-peer() = 7 && fencing != Stonith !!!\n");
+ drbd_err(connection, "fence-peer() = 7 && fencing != Stonith !!!\n");
ex_to_string = "peer was stonithed";
mask.pdsk = D_MASK;
val.pdsk = D_OUTDATED;
break;
default:
/* The script is broken ... */
- conn_err(tconn, "fence-peer helper broken, returned %d\n", (r>>8)&0xff);
+ drbd_err(connection, "fence-peer helper broken, returned %d\n", (r>>8)&0xff);
return false; /* Eventually leave IO frozen */
}
- conn_info(tconn, "fence-peer helper returned %d (%s)\n",
+ drbd_info(connection, "fence-peer helper returned %d (%s)\n",
(r>>8) & 0xff, ex_to_string);
out:
/* Not using
- conn_request_state(tconn, mask, val, CS_VERBOSE);
+ conn_request_state(connection, mask, val, CS_VERBOSE);
here, because we might were able to re-establish the connection in the
meantime. */
- spin_lock_irq(&tconn->req_lock);
- if (tconn->cstate < C_WF_REPORT_PARAMS && !test_bit(STATE_SENT, &tconn->flags)) {
- if (tconn->connect_cnt != connect_cnt)
+ spin_lock_irq(&connection->resource->req_lock);
+ if (connection->cstate < C_WF_REPORT_PARAMS && !test_bit(STATE_SENT, &connection->flags)) {
+ if (connection->connect_cnt != connect_cnt)
/* In case the connection was established and droped
while the fence-peer handler was running, ignore it */
- conn_info(tconn, "Ignoring fence-peer exit code\n");
+ drbd_info(connection, "Ignoring fence-peer exit code\n");
else
- _conn_request_state(tconn, mask, val, CS_VERBOSE);
+ _conn_request_state(connection, mask, val, CS_VERBOSE);
}
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
- return conn_highest_pdsk(tconn) <= D_OUTDATED;
+ return conn_highest_pdsk(connection) <= D_OUTDATED;
}
static int _try_outdate_peer_async(void *data)
{
- struct drbd_tconn *tconn = (struct drbd_tconn *)data;
+ struct drbd_connection *connection = (struct drbd_connection *)data;
- conn_try_outdate_peer(tconn);
+ conn_try_outdate_peer(connection);
- kref_put(&tconn->kref, &conn_destroy);
+ kref_put(&connection->kref, drbd_destroy_connection);
return 0;
}
-void conn_try_outdate_peer_async(struct drbd_tconn *tconn)
+void conn_try_outdate_peer_async(struct drbd_connection *connection)
{
struct task_struct *opa;
- kref_get(&tconn->kref);
- opa = kthread_run(_try_outdate_peer_async, tconn, "drbd_async_h");
+ kref_get(&connection->kref);
+ opa = kthread_run(_try_outdate_peer_async, connection, "drbd_async_h");
if (IS_ERR(opa)) {
- conn_err(tconn, "out of mem, failed to invoke fence-peer helper\n");
- kref_put(&tconn->kref, &conn_destroy);
+ drbd_err(connection, "out of mem, failed to invoke fence-peer helper\n");
+ kref_put(&connection->kref, drbd_destroy_connection);
}
}
enum drbd_state_rv
-drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
+drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
{
const int max_tries = 4;
enum drbd_state_rv rv = SS_UNKNOWN_ERROR;
@@ -542,16 +556,24 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
int forced = 0;
union drbd_state mask, val;
- if (new_role == R_PRIMARY)
- request_ping(mdev->tconn); /* Detect a dead peer ASAP */
+ if (new_role == R_PRIMARY) {
+ struct drbd_connection *connection;
- mutex_lock(mdev->state_mutex);
+ /* Detect dead peers as soon as possible. */
+
+ rcu_read_lock();
+ for_each_connection(connection, device->resource)
+ request_ping(connection);
+ rcu_read_unlock();
+ }
+
+ mutex_lock(device->state_mutex);
mask.i = 0; mask.role = R_MASK;
val.i = 0; val.role = new_role;
while (try++ < max_tries) {
- rv = _drbd_request_state(mdev, mask, val, CS_WAIT_COMPLETE);
+ rv = _drbd_request_state(device, mask, val, CS_WAIT_COMPLETE);
/* in case we first succeeded to outdate,
* but now suddenly could establish a connection */
@@ -562,8 +584,8 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
}
if (rv == SS_NO_UP_TO_DATE_DISK && force &&
- (mdev->state.disk < D_UP_TO_DATE &&
- mdev->state.disk >= D_INCONSISTENT)) {
+ (device->state.disk < D_UP_TO_DATE &&
+ device->state.disk >= D_INCONSISTENT)) {
mask.disk = D_MASK;
val.disk = D_UP_TO_DATE;
forced = 1;
@@ -571,10 +593,10 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
}
if (rv == SS_NO_UP_TO_DATE_DISK &&
- mdev->state.disk == D_CONSISTENT && mask.pdsk == 0) {
- D_ASSERT(mdev->state.pdsk == D_UNKNOWN);
+ device->state.disk == D_CONSISTENT && mask.pdsk == 0) {
+ D_ASSERT(device, device->state.pdsk == D_UNKNOWN);
- if (conn_try_outdate_peer(mdev->tconn)) {
+ if (conn_try_outdate_peer(first_peer_device(device)->connection)) {
val.disk = D_UP_TO_DATE;
mask.disk = D_MASK;
}
@@ -584,8 +606,8 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
if (rv == SS_NOTHING_TO_DO)
goto out;
if (rv == SS_PRIMARY_NOP && mask.pdsk == 0) {
- if (!conn_try_outdate_peer(mdev->tconn) && force) {
- dev_warn(DEV, "Forced into split brain situation!\n");
+ if (!conn_try_outdate_peer(first_peer_device(device)->connection) && force) {
+ drbd_warn(device, "Forced into split brain situation!\n");
mask.pdsk = D_MASK;
val.pdsk = D_OUTDATED;
@@ -597,7 +619,7 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
retry at most once more in this case. */
int timeo;
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
timeo = nc ? (nc->ping_timeo + 1) * HZ / 10 : 1;
rcu_read_unlock();
schedule_timeout_interruptible(timeo);
@@ -606,7 +628,7 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
continue;
}
if (rv < SS_SUCCESS) {
- rv = _drbd_request_state(mdev, mask, val,
+ rv = _drbd_request_state(device, mask, val,
CS_VERBOSE + CS_WAIT_COMPLETE);
if (rv < SS_SUCCESS)
goto out;
@@ -618,53 +640,53 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
goto out;
if (forced)
- dev_warn(DEV, "Forced to consider local data as UpToDate!\n");
+ drbd_warn(device, "Forced to consider local data as UpToDate!\n");
/* Wait until nothing is on the fly :) */
- wait_event(mdev->misc_wait, atomic_read(&mdev->ap_pending_cnt) == 0);
+ wait_event(device->misc_wait, atomic_read(&device->ap_pending_cnt) == 0);
/* FIXME also wait for all pending P_BARRIER_ACK? */
if (new_role == R_SECONDARY) {
- set_disk_ro(mdev->vdisk, true);
- if (get_ldev(mdev)) {
- mdev->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
- put_ldev(mdev);
+ set_disk_ro(device->vdisk, true);
+ if (get_ldev(device)) {
+ device->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
+ put_ldev(device);
}
} else {
- mutex_lock(&mdev->tconn->conf_update);
- nc = mdev->tconn->net_conf;
+ mutex_lock(&device->resource->conf_update);
+ nc = first_peer_device(device)->connection->net_conf;
if (nc)
nc->discard_my_data = 0; /* without copy; single bit op is atomic */
- mutex_unlock(&mdev->tconn->conf_update);
+ mutex_unlock(&device->resource->conf_update);
- set_disk_ro(mdev->vdisk, false);
- if (get_ldev(mdev)) {
- if (((mdev->state.conn < C_CONNECTED ||
- mdev->state.pdsk <= D_FAILED)
- && mdev->ldev->md.uuid[UI_BITMAP] == 0) || forced)
- drbd_uuid_new_current(mdev);
+ set_disk_ro(device->vdisk, false);
+ if (get_ldev(device)) {
+ if (((device->state.conn < C_CONNECTED ||
+ device->state.pdsk <= D_FAILED)
+ && device->ldev->md.uuid[UI_BITMAP] == 0) || forced)
+ drbd_uuid_new_current(device);
- mdev->ldev->md.uuid[UI_CURRENT] |= (u64)1;
- put_ldev(mdev);
+ device->ldev->md.uuid[UI_CURRENT] |= (u64)1;
+ put_ldev(device);
}
}
/* writeout of activity log covered areas of the bitmap
* to stable storage done in after state change already */
- if (mdev->state.conn >= C_WF_REPORT_PARAMS) {
+ if (device->state.conn >= C_WF_REPORT_PARAMS) {
/* if this was forced, we should consider sync */
if (forced)
- drbd_send_uuids(mdev);
- drbd_send_current_state(mdev);
+ drbd_send_uuids(first_peer_device(device));
+ drbd_send_current_state(first_peer_device(device));
}
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
- kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
+ kobject_uevent(&disk_to_dev(device->vdisk)->kobj, KOBJ_CHANGE);
out:
- mutex_unlock(mdev->state_mutex);
+ mutex_unlock(device->state_mutex);
return rv;
}
@@ -699,9 +721,9 @@ int drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info)
}
if (info->genlhdr->cmd == DRBD_ADM_PRIMARY)
- retcode = drbd_set_role(adm_ctx.mdev, R_PRIMARY, parms.assume_uptodate);
+ retcode = drbd_set_role(adm_ctx.device, R_PRIMARY, parms.assume_uptodate);
else
- retcode = drbd_set_role(adm_ctx.mdev, R_SECONDARY, 0);
+ retcode = drbd_set_role(adm_ctx.device, R_SECONDARY, 0);
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -728,7 +750,7 @@ out:
* Activity log size used to be fixed 32kB,
* but is about to become configurable.
*/
-static void drbd_md_set_sector_offsets(struct drbd_conf *mdev,
+static void drbd_md_set_sector_offsets(struct drbd_device *device,
struct drbd_backing_dev *bdev)
{
sector_t md_size_sect = 0;
@@ -804,35 +826,35 @@ char *ppsize(char *buf, unsigned long long size)
* drbd_adm_suspend_io/drbd_adm_resume_io,
* which are (sub) state changes triggered by admin (drbdsetup),
* and can be long lived.
- * This changes an mdev->flag, is triggered by drbd internals,
+ * This changes an device->flag, is triggered by drbd internals,
* and should be short-lived. */
-void drbd_suspend_io(struct drbd_conf *mdev)
+void drbd_suspend_io(struct drbd_device *device)
{
- set_bit(SUSPEND_IO, &mdev->flags);
- if (drbd_suspended(mdev))
+ set_bit(SUSPEND_IO, &device->flags);
+ if (drbd_suspended(device))
return;
- wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt));
+ wait_event(device->misc_wait, !atomic_read(&device->ap_bio_cnt));
}
-void drbd_resume_io(struct drbd_conf *mdev)
+void drbd_resume_io(struct drbd_device *device)
{
- clear_bit(SUSPEND_IO, &mdev->flags);
- wake_up(&mdev->misc_wait);
+ clear_bit(SUSPEND_IO, &device->flags);
+ wake_up(&device->misc_wait);
}
/**
* drbd_determine_dev_size() - Sets the right device size obeying all constraints
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Returns 0 on success, negative return values indicate errors.
* You should call drbd_md_sync() after calling this function.
*/
enum determine_dev_size
-drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct resize_parms *rs) __must_hold(local)
+drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct resize_parms *rs) __must_hold(local)
{
sector_t prev_first_sect, prev_size; /* previous meta location */
sector_t la_size_sect, u_size;
- struct drbd_md *md = &mdev->ldev->md;
+ struct drbd_md *md = &device->ldev->md;
u32 prev_al_stripe_size_4k;
u32 prev_al_stripes;
sector_t size;
@@ -851,19 +873,19 @@ drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct res
* Suspend IO right here.
* still lock the act_log to not trigger ASSERTs there.
*/
- drbd_suspend_io(mdev);
- buffer = drbd_md_get_buffer(mdev); /* Lock meta-data IO */
+ drbd_suspend_io(device);
+ buffer = drbd_md_get_buffer(device); /* Lock meta-data IO */
if (!buffer) {
- drbd_resume_io(mdev);
+ drbd_resume_io(device);
return DS_ERROR;
}
/* no wait necessary anymore, actually we could assert that */
- wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
+ wait_event(device->al_wait, lc_try_lock(device->act_log));
- prev_first_sect = drbd_md_first_sector(mdev->ldev);
- prev_size = mdev->ldev->md.md_size_sect;
- la_size_sect = mdev->ldev->md.la_size_sect;
+ prev_first_sect = drbd_md_first_sector(device->ldev);
+ prev_size = device->ldev->md.md_size_sect;
+ la_size_sect = device->ldev->md.la_size_sect;
if (rs) {
/* rs is non NULL if we should change the AL layout only */
@@ -876,18 +898,18 @@ drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct res
md->al_size_4k = (u64)rs->al_stripes * rs->al_stripe_size / 4;
}
- drbd_md_set_sector_offsets(mdev, mdev->ldev);
+ drbd_md_set_sector_offsets(device, device->ldev);
rcu_read_lock();
- u_size = rcu_dereference(mdev->ldev->disk_conf)->disk_size;
+ u_size = rcu_dereference(device->ldev->disk_conf)->disk_size;
rcu_read_unlock();
- size = drbd_new_dev_size(mdev, mdev->ldev, u_size, flags & DDSF_FORCED);
+ size = drbd_new_dev_size(device, device->ldev, u_size, flags & DDSF_FORCED);
if (size < la_size_sect) {
if (rs && u_size == 0) {
/* Remove "rs &&" later. This check should always be active, but
right now the receiver expects the permissive behavior */
- dev_warn(DEV, "Implicit shrink not allowed. "
+ drbd_warn(device, "Implicit shrink not allowed. "
"Use --size=%llus for explicit shrink.\n",
(unsigned long long)size);
rv = DS_ERROR_SHRINK;
@@ -898,60 +920,60 @@ drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct res
goto err_out;
}
- if (drbd_get_capacity(mdev->this_bdev) != size ||
- drbd_bm_capacity(mdev) != size) {
+ if (drbd_get_capacity(device->this_bdev) != size ||
+ drbd_bm_capacity(device) != size) {
int err;
- err = drbd_bm_resize(mdev, size, !(flags & DDSF_NO_RESYNC));
+ err = drbd_bm_resize(device, size, !(flags & DDSF_NO_RESYNC));
if (unlikely(err)) {
/* currently there is only one error: ENOMEM! */
- size = drbd_bm_capacity(mdev)>>1;
+ size = drbd_bm_capacity(device)>>1;
if (size == 0) {
- dev_err(DEV, "OUT OF MEMORY! "
+ drbd_err(device, "OUT OF MEMORY! "
"Could not allocate bitmap!\n");
} else {
- dev_err(DEV, "BM resizing failed. "
+ drbd_err(device, "BM resizing failed. "
"Leaving size unchanged at size = %lu KB\n",
(unsigned long)size);
}
rv = DS_ERROR;
}
/* racy, see comments above. */
- drbd_set_my_capacity(mdev, size);
- mdev->ldev->md.la_size_sect = size;
- dev_info(DEV, "size = %s (%llu KB)\n", ppsize(ppb, size>>1),
+ drbd_set_my_capacity(device, size);
+ device->ldev->md.la_size_sect = size;
+ drbd_info(device, "size = %s (%llu KB)\n", ppsize(ppb, size>>1),
(unsigned long long)size>>1);
}
if (rv <= DS_ERROR)
goto err_out;
- la_size_changed = (la_size_sect != mdev->ldev->md.la_size_sect);
+ la_size_changed = (la_size_sect != device->ldev->md.la_size_sect);
- md_moved = prev_first_sect != drbd_md_first_sector(mdev->ldev)
- || prev_size != mdev->ldev->md.md_size_sect;
+ md_moved = prev_first_sect != drbd_md_first_sector(device->ldev)
+ || prev_size != device->ldev->md.md_size_sect;
if (la_size_changed || md_moved || rs) {
u32 prev_flags;
- drbd_al_shrink(mdev); /* All extents inactive. */
+ drbd_al_shrink(device); /* All extents inactive. */
prev_flags = md->flags;
md->flags &= ~MDF_PRIMARY_IND;
- drbd_md_write(mdev, buffer);
+ drbd_md_write(device, buffer);
- dev_info(DEV, "Writing the whole bitmap, %s\n",
+ drbd_info(device, "Writing the whole bitmap, %s\n",
la_size_changed && md_moved ? "size changed and md moved" :
la_size_changed ? "size changed" : "md moved");
/* next line implicitly does drbd_suspend_io()+drbd_resume_io() */
- drbd_bitmap_io(mdev, md_moved ? &drbd_bm_write_all : &drbd_bm_write,
+ drbd_bitmap_io(device, md_moved ? &drbd_bm_write_all : &drbd_bm_write,
"size changed", BM_LOCKED_MASK);
- drbd_initialize_al(mdev, buffer);
+ drbd_initialize_al(device, buffer);
md->flags = prev_flags;
- drbd_md_write(mdev, buffer);
+ drbd_md_write(device, buffer);
if (rs)
- dev_info(DEV, "Changed AL layout to al-stripes = %d, al-stripe-size-kB = %d\n",
- md->al_stripes, md->al_stripe_size_4k * 4);
+ drbd_info(device, "Changed AL layout to al-stripes = %d, al-stripe-size-kB = %d\n",
+ md->al_stripes, md->al_stripe_size_4k * 4);
}
if (size > la_size_sect)
@@ -966,30 +988,30 @@ drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct res
md->al_stripe_size_4k = prev_al_stripe_size_4k;
md->al_size_4k = (u64)prev_al_stripes * prev_al_stripe_size_4k;
- drbd_md_set_sector_offsets(mdev, mdev->ldev);
+ drbd_md_set_sector_offsets(device, device->ldev);
}
}
- lc_unlock(mdev->act_log);
- wake_up(&mdev->al_wait);
- drbd_md_put_buffer(mdev);
- drbd_resume_io(mdev);
+ lc_unlock(device->act_log);
+ wake_up(&device->al_wait);
+ drbd_md_put_buffer(device);
+ drbd_resume_io(device);
return rv;
}
sector_t
-drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
+drbd_new_dev_size(struct drbd_device *device, struct drbd_backing_dev *bdev,
sector_t u_size, int assume_peer_has_space)
{
- sector_t p_size = mdev->p_size; /* partner's disk size. */
+ sector_t p_size = device->p_size; /* partner's disk size. */
sector_t la_size_sect = bdev->md.la_size_sect; /* last agreed size. */
sector_t m_size; /* my size */
sector_t size = 0;
m_size = drbd_get_max_capacity(bdev);
- if (mdev->state.conn < C_CONNECTED && assume_peer_has_space) {
- dev_warn(DEV, "Resize while not connected was forced by the user!\n");
+ if (device->state.conn < C_CONNECTED && assume_peer_has_space) {
+ drbd_warn(device, "Resize while not connected was forced by the user!\n");
p_size = m_size;
}
@@ -1011,11 +1033,11 @@ drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
}
if (size == 0)
- dev_err(DEV, "Both nodes diskless!\n");
+ drbd_err(device, "Both nodes diskless!\n");
if (u_size) {
if (u_size > size)
- dev_err(DEV, "Requested disk size is too big (%lu > %lu)\n",
+ drbd_err(device, "Requested disk size is too big (%lu > %lu)\n",
(unsigned long)u_size>>1, (unsigned long)size>>1);
else
size = u_size;
@@ -1026,71 +1048,71 @@ drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
/**
* drbd_check_al_size() - Ensures that the AL is of the right size
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Returns -EBUSY if current al lru is still used, -ENOMEM when allocation
* failed, and 0 on success. You should call drbd_md_sync() after you called
* this function.
*/
-static int drbd_check_al_size(struct drbd_conf *mdev, struct disk_conf *dc)
+static int drbd_check_al_size(struct drbd_device *device, struct disk_conf *dc)
{
struct lru_cache *n, *t;
struct lc_element *e;
unsigned int in_use;
int i;
- if (mdev->act_log &&
- mdev->act_log->nr_elements == dc->al_extents)
+ if (device->act_log &&
+ device->act_log->nr_elements == dc->al_extents)
return 0;
in_use = 0;
- t = mdev->act_log;
+ t = device->act_log;
n = lc_create("act_log", drbd_al_ext_cache, AL_UPDATES_PER_TRANSACTION,
dc->al_extents, sizeof(struct lc_element), 0);
if (n == NULL) {
- dev_err(DEV, "Cannot allocate act_log lru!\n");
+ drbd_err(device, "Cannot allocate act_log lru!\n");
return -ENOMEM;
}
- spin_lock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
if (t) {
for (i = 0; i < t->nr_elements; i++) {
e = lc_element_by_index(t, i);
if (e->refcnt)
- dev_err(DEV, "refcnt(%d)==%d\n",
+ drbd_err(device, "refcnt(%d)==%d\n",
e->lc_number, e->refcnt);
in_use += e->refcnt;
}
}
if (!in_use)
- mdev->act_log = n;
- spin_unlock_irq(&mdev->al_lock);
+ device->act_log = n;
+ spin_unlock_irq(&device->al_lock);
if (in_use) {
- dev_err(DEV, "Activity log still in use!\n");
+ drbd_err(device, "Activity log still in use!\n");
lc_destroy(n);
return -EBUSY;
} else {
if (t)
lc_destroy(t);
}
- drbd_md_mark_dirty(mdev); /* we changed mdev->act_log->nr_elemens */
+ drbd_md_mark_dirty(device); /* we changed device->act_log->nr_elemens */
return 0;
}
-static void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size)
+static void drbd_setup_queue_param(struct drbd_device *device, unsigned int max_bio_size)
{
- struct request_queue * const q = mdev->rq_queue;
+ struct request_queue * const q = device->rq_queue;
unsigned int max_hw_sectors = max_bio_size >> 9;
unsigned int max_segments = 0;
- if (get_ldev_if_state(mdev, D_ATTACHING)) {
- struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
+ if (get_ldev_if_state(device, D_ATTACHING)) {
+ struct request_queue * const b = device->ldev->backing_bdev->bd_disk->queue;
max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9);
rcu_read_lock();
- max_segments = rcu_dereference(mdev->ldev->disk_conf)->max_bio_bvecs;
+ max_segments = rcu_dereference(device->ldev->disk_conf)->max_bio_bvecs;
rcu_read_unlock();
- put_ldev(mdev);
+ put_ldev(device);
}
blk_queue_logical_block_size(q, 512);
@@ -1099,46 +1121,46 @@ static void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_
blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS);
blk_queue_segment_boundary(q, PAGE_CACHE_SIZE-1);
- if (get_ldev_if_state(mdev, D_ATTACHING)) {
- struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
+ if (get_ldev_if_state(device, D_ATTACHING)) {
+ struct request_queue * const b = device->ldev->backing_bdev->bd_disk->queue;
blk_queue_stack_limits(q, b);
if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
- dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
+ drbd_info(device, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
q->backing_dev_info.ra_pages,
b->backing_dev_info.ra_pages);
q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
}
- put_ldev(mdev);
+ put_ldev(device);
}
}
-void drbd_reconsider_max_bio_size(struct drbd_conf *mdev)
+void drbd_reconsider_max_bio_size(struct drbd_device *device)
{
unsigned int now, new, local, peer;
- now = queue_max_hw_sectors(mdev->rq_queue) << 9;
- local = mdev->local_max_bio_size; /* Eventually last known value, from volatile memory */
- peer = mdev->peer_max_bio_size; /* Eventually last known value, from meta data */
+ now = queue_max_hw_sectors(device->rq_queue) << 9;
+ local = device->local_max_bio_size; /* Eventually last known value, from volatile memory */
+ peer = device->peer_max_bio_size; /* Eventually last known value, from meta data */
- if (get_ldev_if_state(mdev, D_ATTACHING)) {
- local = queue_max_hw_sectors(mdev->ldev->backing_bdev->bd_disk->queue) << 9;
- mdev->local_max_bio_size = local;
- put_ldev(mdev);
+ if (get_ldev_if_state(device, D_ATTACHING)) {
+ local = queue_max_hw_sectors(device->ldev->backing_bdev->bd_disk->queue) << 9;
+ device->local_max_bio_size = local;
+ put_ldev(device);
}
local = min(local, DRBD_MAX_BIO_SIZE);
/* We may ignore peer limits if the peer is modern enough.
Because new from 8.3.8 onwards the peer can use multiple
BIOs for a single peer_request */
- if (mdev->state.conn >= C_WF_REPORT_PARAMS) {
- if (mdev->tconn->agreed_pro_version < 94)
- peer = min(mdev->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
+ if (device->state.conn >= C_WF_REPORT_PARAMS) {
+ if (first_peer_device(device)->connection->agreed_pro_version < 94)
+ peer = min(device->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
/* Correct old drbd (up to 8.3.7) if it believes it can do more than 32KiB */
- else if (mdev->tconn->agreed_pro_version == 94)
+ else if (first_peer_device(device)->connection->agreed_pro_version == 94)
peer = DRBD_MAX_SIZE_H80_PACKET;
- else if (mdev->tconn->agreed_pro_version < 100)
+ else if (first_peer_device(device)->connection->agreed_pro_version < 100)
peer = DRBD_MAX_BIO_SIZE_P95; /* drbd 8.3.8 onwards, before 8.4.0 */
else
peer = DRBD_MAX_BIO_SIZE;
@@ -1146,57 +1168,57 @@ void drbd_reconsider_max_bio_size(struct drbd_conf *mdev)
new = min(local, peer);
- if (mdev->state.role == R_PRIMARY && new < now)
- dev_err(DEV, "ASSERT FAILED new < now; (%u < %u)\n", new, now);
+ if (device->state.role == R_PRIMARY && new < now)
+ drbd_err(device, "ASSERT FAILED new < now; (%u < %u)\n", new, now);
if (new != now)
- dev_info(DEV, "max BIO size = %u\n", new);
+ drbd_info(device, "max BIO size = %u\n", new);
- drbd_setup_queue_param(mdev, new);
+ drbd_setup_queue_param(device, new);
}
/* Starts the worker thread */
-static void conn_reconfig_start(struct drbd_tconn *tconn)
+static void conn_reconfig_start(struct drbd_connection *connection)
{
- drbd_thread_start(&tconn->worker);
- conn_flush_workqueue(tconn);
+ drbd_thread_start(&connection->worker);
+ drbd_flush_workqueue(&connection->sender_work);
}
/* if still unconfigured, stops worker again. */
-static void conn_reconfig_done(struct drbd_tconn *tconn)
+static void conn_reconfig_done(struct drbd_connection *connection)
{
bool stop_threads;
- spin_lock_irq(&tconn->req_lock);
- stop_threads = conn_all_vols_unconf(tconn) &&
- tconn->cstate == C_STANDALONE;
- spin_unlock_irq(&tconn->req_lock);
+ spin_lock_irq(&connection->resource->req_lock);
+ stop_threads = conn_all_vols_unconf(connection) &&
+ connection->cstate == C_STANDALONE;
+ spin_unlock_irq(&connection->resource->req_lock);
if (stop_threads) {
/* asender is implicitly stopped by receiver
* in conn_disconnect() */
- drbd_thread_stop(&tconn->receiver);
- drbd_thread_stop(&tconn->worker);
+ drbd_thread_stop(&connection->receiver);
+ drbd_thread_stop(&connection->worker);
}
}
/* Make sure IO is suspended before calling this function(). */
-static void drbd_suspend_al(struct drbd_conf *mdev)
+static void drbd_suspend_al(struct drbd_device *device)
{
int s = 0;
- if (!lc_try_lock(mdev->act_log)) {
- dev_warn(DEV, "Failed to lock al in drbd_suspend_al()\n");
+ if (!lc_try_lock(device->act_log)) {
+ drbd_warn(device, "Failed to lock al in drbd_suspend_al()\n");
return;
}
- drbd_al_shrink(mdev);
- spin_lock_irq(&mdev->tconn->req_lock);
- if (mdev->state.conn < C_CONNECTED)
- s = !test_and_set_bit(AL_SUSPENDED, &mdev->flags);
- spin_unlock_irq(&mdev->tconn->req_lock);
- lc_unlock(mdev->act_log);
+ drbd_al_shrink(device);
+ spin_lock_irq(&device->resource->req_lock);
+ if (device->state.conn < C_CONNECTED)
+ s = !test_and_set_bit(AL_SUSPENDED, &device->flags);
+ spin_unlock_irq(&device->resource->req_lock);
+ lc_unlock(device->act_log);
if (s)
- dev_info(DEV, "Suspended AL updates\n");
+ drbd_info(device, "Suspended AL updates\n");
}
@@ -1237,7 +1259,7 @@ static unsigned int drbd_al_extents_max(struct drbd_backing_dev *bdev)
int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
{
enum drbd_ret_code retcode;
- struct drbd_conf *mdev;
+ struct drbd_device *device;
struct disk_conf *new_disk_conf, *old_disk_conf;
struct fifo_buffer *old_plan = NULL, *new_plan = NULL;
int err, fifo_size;
@@ -1248,11 +1270,11 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- mdev = adm_ctx.mdev;
+ device = adm_ctx.device;
/* we also need a disk
* to change the options on */
- if (!get_ldev(mdev)) {
+ if (!get_ldev(device)) {
retcode = ERR_NO_DISK;
goto out;
}
@@ -1263,8 +1285,8 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
goto fail;
}
- mutex_lock(&mdev->tconn->conf_update);
- old_disk_conf = mdev->ldev->disk_conf;
+ mutex_lock(&device->resource->conf_update);
+ old_disk_conf = device->ldev->disk_conf;
*new_disk_conf = *old_disk_conf;
if (should_set_defaults(info))
set_disk_conf_defaults(new_disk_conf);
@@ -1273,6 +1295,7 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
if (err && err != -ENOMSG) {
retcode = ERR_MANDATORY_TAG;
drbd_msg_put_info(from_attrs_err_to_txt(err));
+ goto fail_unlock;
}
if (!expect(new_disk_conf->resync_rate >= 1))
@@ -1280,29 +1303,29 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
if (new_disk_conf->al_extents < DRBD_AL_EXTENTS_MIN)
new_disk_conf->al_extents = DRBD_AL_EXTENTS_MIN;
- if (new_disk_conf->al_extents > drbd_al_extents_max(mdev->ldev))
- new_disk_conf->al_extents = drbd_al_extents_max(mdev->ldev);
+ if (new_disk_conf->al_extents > drbd_al_extents_max(device->ldev))
+ new_disk_conf->al_extents = drbd_al_extents_max(device->ldev);
if (new_disk_conf->c_plan_ahead > DRBD_C_PLAN_AHEAD_MAX)
new_disk_conf->c_plan_ahead = DRBD_C_PLAN_AHEAD_MAX;
fifo_size = (new_disk_conf->c_plan_ahead * 10 * SLEEP_TIME) / HZ;
- if (fifo_size != mdev->rs_plan_s->size) {
+ if (fifo_size != device->rs_plan_s->size) {
new_plan = fifo_alloc(fifo_size);
if (!new_plan) {
- dev_err(DEV, "kmalloc of fifo_buffer failed");
+ drbd_err(device, "kmalloc of fifo_buffer failed");
retcode = ERR_NOMEM;
goto fail_unlock;
}
}
- drbd_suspend_io(mdev);
- wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
- drbd_al_shrink(mdev);
- err = drbd_check_al_size(mdev, new_disk_conf);
- lc_unlock(mdev->act_log);
- wake_up(&mdev->al_wait);
- drbd_resume_io(mdev);
+ drbd_suspend_io(device);
+ wait_event(device->al_wait, lc_try_lock(device->act_log));
+ drbd_al_shrink(device);
+ err = drbd_check_al_size(device, new_disk_conf);
+ lc_unlock(device->act_log);
+ wake_up(&device->al_wait);
+ drbd_resume_io(device);
if (err) {
retcode = ERR_NOMEM;
@@ -1310,10 +1333,10 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
}
write_lock_irq(&global_state_lock);
- retcode = drbd_resync_after_valid(mdev, new_disk_conf->resync_after);
+ retcode = drbd_resync_after_valid(device, new_disk_conf->resync_after);
if (retcode == NO_ERROR) {
- rcu_assign_pointer(mdev->ldev->disk_conf, new_disk_conf);
- drbd_resync_after_changed(mdev);
+ rcu_assign_pointer(device->ldev->disk_conf, new_disk_conf);
+ drbd_resync_after_changed(device);
}
write_unlock_irq(&global_state_lock);
@@ -1321,42 +1344,46 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
goto fail_unlock;
if (new_plan) {
- old_plan = mdev->rs_plan_s;
- rcu_assign_pointer(mdev->rs_plan_s, new_plan);
+ old_plan = device->rs_plan_s;
+ rcu_assign_pointer(device->rs_plan_s, new_plan);
}
- mutex_unlock(&mdev->tconn->conf_update);
+ mutex_unlock(&device->resource->conf_update);
if (new_disk_conf->al_updates)
- mdev->ldev->md.flags &= ~MDF_AL_DISABLED;
+ device->ldev->md.flags &= ~MDF_AL_DISABLED;
else
- mdev->ldev->md.flags |= MDF_AL_DISABLED;
+ device->ldev->md.flags |= MDF_AL_DISABLED;
if (new_disk_conf->md_flushes)
- clear_bit(MD_NO_FUA, &mdev->flags);
+ clear_bit(MD_NO_FUA, &device->flags);
else
- set_bit(MD_NO_FUA, &mdev->flags);
+ set_bit(MD_NO_FUA, &device->flags);
- drbd_bump_write_ordering(mdev->tconn, WO_bdev_flush);
+ drbd_bump_write_ordering(first_peer_device(device)->connection, WO_bdev_flush);
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
- if (mdev->state.conn >= C_CONNECTED)
- drbd_send_sync_param(mdev);
+ if (device->state.conn >= C_CONNECTED) {
+ struct drbd_peer_device *peer_device;
+
+ for_each_peer_device(peer_device, device)
+ drbd_send_sync_param(peer_device);
+ }
synchronize_rcu();
kfree(old_disk_conf);
kfree(old_plan);
- mod_timer(&mdev->request_timer, jiffies + HZ);
+ mod_timer(&device->request_timer, jiffies + HZ);
goto success;
fail_unlock:
- mutex_unlock(&mdev->tconn->conf_update);
+ mutex_unlock(&device->resource->conf_update);
fail:
kfree(new_disk_conf);
kfree(new_plan);
success:
- put_ldev(mdev);
+ put_ldev(device);
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -1364,7 +1391,7 @@ success:
int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
+ struct drbd_device *device;
int err;
enum drbd_ret_code retcode;
enum determine_dev_size dd;
@@ -1385,11 +1412,11 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto finish;
- mdev = adm_ctx.mdev;
- conn_reconfig_start(mdev->tconn);
+ device = adm_ctx.device;
+ conn_reconfig_start(first_peer_device(device)->connection);
/* if you want to reconfigure, please tear down first */
- if (mdev->state.disk > D_DISKLESS) {
+ if (device->state.disk > D_DISKLESS) {
retcode = ERR_DISK_CONFIGURED;
goto fail;
}
@@ -1397,17 +1424,17 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
* drbd_ldev_destroy is done already, we may end up here very fast,
* e.g. if someone calls attach from the on-io-error handler,
* to realize a "hot spare" feature (not that I'd recommend that) */
- wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
+ wait_event(device->misc_wait, !atomic_read(&device->local_cnt));
/* make sure there is no leftover from previous force-detach attempts */
- clear_bit(FORCE_DETACH, &mdev->flags);
- clear_bit(WAS_IO_ERROR, &mdev->flags);
- clear_bit(WAS_READ_ERROR, &mdev->flags);
+ clear_bit(FORCE_DETACH, &device->flags);
+ clear_bit(WAS_IO_ERROR, &device->flags);
+ clear_bit(WAS_READ_ERROR, &device->flags);
/* and no leftover from previously aborted resync or verify, either */
- mdev->rs_total = 0;
- mdev->rs_failed = 0;
- atomic_set(&mdev->rs_pending_cnt, 0);
+ device->rs_total = 0;
+ device->rs_failed = 0;
+ atomic_set(&device->rs_pending_cnt, 0);
/* allocation not in the IO path, drbdsetup context */
nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
@@ -1447,13 +1474,13 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
}
write_lock_irq(&global_state_lock);
- retcode = drbd_resync_after_valid(mdev, new_disk_conf->resync_after);
+ retcode = drbd_resync_after_valid(device, new_disk_conf->resync_after);
write_unlock_irq(&global_state_lock);
if (retcode != NO_ERROR)
goto fail;
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
if (nc) {
if (new_disk_conf->fencing == FP_STONITH && nc->wire_protocol == DRBD_PROT_A) {
rcu_read_unlock();
@@ -1464,9 +1491,9 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
rcu_read_unlock();
bdev = blkdev_get_by_path(new_disk_conf->backing_dev,
- FMODE_READ | FMODE_WRITE | FMODE_EXCL, mdev);
+ FMODE_READ | FMODE_WRITE | FMODE_EXCL, device);
if (IS_ERR(bdev)) {
- dev_err(DEV, "open(\"%s\") failed with %ld\n", new_disk_conf->backing_dev,
+ drbd_err(device, "open(\"%s\") failed with %ld\n", new_disk_conf->backing_dev,
PTR_ERR(bdev));
retcode = ERR_OPEN_DISK;
goto fail;
@@ -1484,9 +1511,9 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
bdev = blkdev_get_by_path(new_disk_conf->meta_dev,
FMODE_READ | FMODE_WRITE | FMODE_EXCL,
(new_disk_conf->meta_dev_idx < 0) ?
- (void *)mdev : (void *)drbd_m_holder);
+ (void *)device : (void *)drbd_m_holder);
if (IS_ERR(bdev)) {
- dev_err(DEV, "open(\"%s\") failed with %ld\n", new_disk_conf->meta_dev,
+ drbd_err(device, "open(\"%s\") failed with %ld\n", new_disk_conf->meta_dev,
PTR_ERR(bdev));
retcode = ERR_OPEN_MD_DISK;
goto fail;
@@ -1510,7 +1537,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
/* Read our meta data super block early.
* This also sets other on-disk offsets. */
- retcode = drbd_md_read(mdev, nbc);
+ retcode = drbd_md_read(device, nbc);
if (retcode != NO_ERROR)
goto fail;
@@ -1520,7 +1547,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
new_disk_conf->al_extents = drbd_al_extents_max(nbc);
if (drbd_get_max_capacity(nbc) < new_disk_conf->disk_size) {
- dev_err(DEV, "max capacity %llu smaller than disk size %llu\n",
+ drbd_err(device, "max capacity %llu smaller than disk size %llu\n",
(unsigned long long) drbd_get_max_capacity(nbc),
(unsigned long long) new_disk_conf->disk_size);
retcode = ERR_DISK_TOO_SMALL;
@@ -1538,7 +1565,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
if (drbd_get_capacity(nbc->md_bdev) < min_md_device_sectors) {
retcode = ERR_MD_DISK_TOO_SMALL;
- dev_warn(DEV, "refusing attach: md-device too small, "
+ drbd_warn(device, "refusing attach: md-device too small, "
"at least %llu sectors needed for this meta-disk type\n",
(unsigned long long) min_md_device_sectors);
goto fail;
@@ -1547,7 +1574,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
/* Make sure the new disk is big enough
* (we may currently be R_PRIMARY with no local disk...) */
if (drbd_get_max_capacity(nbc) <
- drbd_get_capacity(mdev->this_bdev)) {
+ drbd_get_capacity(device->this_bdev)) {
retcode = ERR_DISK_TOO_SMALL;
goto fail;
}
@@ -1555,15 +1582,15 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
nbc->known_size = drbd_get_capacity(nbc->backing_bdev);
if (nbc->known_size > max_possible_sectors) {
- dev_warn(DEV, "==> truncating very big lower level device "
+ drbd_warn(device, "==> truncating very big lower level device "
"to currently maximum possible %llu sectors <==\n",
(unsigned long long) max_possible_sectors);
if (new_disk_conf->meta_dev_idx >= 0)
- dev_warn(DEV, "==>> using internal or flexible "
+ drbd_warn(device, "==>> using internal or flexible "
"meta data may help <<==\n");
}
- drbd_suspend_io(mdev);
+ drbd_suspend_io(device);
/* also wait for the last barrier ack. */
/* FIXME see also https://daiquiri.linbit/cgi-bin/bugzilla/show_bug.cgi?id=171
* We need a way to either ignore barrier acks for barriers sent before a device
@@ -1571,45 +1598,45 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
* As barriers are counted per resource,
* we'd need to suspend io on all devices of a resource.
*/
- wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_pending_cnt) || drbd_suspended(mdev));
+ wait_event(device->misc_wait, !atomic_read(&device->ap_pending_cnt) || drbd_suspended(device));
/* and for any other previously queued work */
- drbd_flush_workqueue(mdev);
+ drbd_flush_workqueue(&first_peer_device(device)->connection->sender_work);
- rv = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE);
+ rv = _drbd_request_state(device, NS(disk, D_ATTACHING), CS_VERBOSE);
retcode = rv; /* FIXME: Type mismatch. */
- drbd_resume_io(mdev);
+ drbd_resume_io(device);
if (rv < SS_SUCCESS)
goto fail;
- if (!get_ldev_if_state(mdev, D_ATTACHING))
+ if (!get_ldev_if_state(device, D_ATTACHING))
goto force_diskless;
- if (!mdev->bitmap) {
- if (drbd_bm_init(mdev)) {
+ if (!device->bitmap) {
+ if (drbd_bm_init(device)) {
retcode = ERR_NOMEM;
goto force_diskless_dec;
}
}
- if (mdev->state.conn < C_CONNECTED &&
- mdev->state.role == R_PRIMARY &&
- (mdev->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) {
- dev_err(DEV, "Can only attach to data with current UUID=%016llX\n",
- (unsigned long long)mdev->ed_uuid);
+ if (device->state.conn < C_CONNECTED &&
+ device->state.role == R_PRIMARY &&
+ (device->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) {
+ drbd_err(device, "Can only attach to data with current UUID=%016llX\n",
+ (unsigned long long)device->ed_uuid);
retcode = ERR_DATA_NOT_CURRENT;
goto force_diskless_dec;
}
/* Since we are diskless, fix the activity log first... */
- if (drbd_check_al_size(mdev, new_disk_conf)) {
+ if (drbd_check_al_size(device, new_disk_conf)) {
retcode = ERR_NOMEM;
goto force_diskless_dec;
}
/* Prevent shrinking of consistent devices ! */
if (drbd_md_test_flag(nbc, MDF_CONSISTENT) &&
- drbd_new_dev_size(mdev, nbc, nbc->disk_conf->disk_size, 0) < nbc->md.la_size_sect) {
- dev_warn(DEV, "refusing to truncate a consistent device\n");
+ drbd_new_dev_size(device, nbc, nbc->disk_conf->disk_size, 0) < nbc->md.la_size_sect) {
+ drbd_warn(device, "refusing to truncate a consistent device\n");
retcode = ERR_DISK_TOO_SMALL;
goto force_diskless_dec;
}
@@ -1617,40 +1644,40 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
/* Reset the "barriers don't work" bits here, then force meta data to
* be written, to ensure we determine if barriers are supported. */
if (new_disk_conf->md_flushes)
- clear_bit(MD_NO_FUA, &mdev->flags);
+ clear_bit(MD_NO_FUA, &device->flags);
else
- set_bit(MD_NO_FUA, &mdev->flags);
+ set_bit(MD_NO_FUA, &device->flags);
/* Point of no return reached.
* Devices and memory are no longer released by error cleanup below.
- * now mdev takes over responsibility, and the state engine should
+ * now device takes over responsibility, and the state engine should
* clean it up somewhere. */
- D_ASSERT(mdev->ldev == NULL);
- mdev->ldev = nbc;
- mdev->resync = resync_lru;
- mdev->rs_plan_s = new_plan;
+ D_ASSERT(device, device->ldev == NULL);
+ device->ldev = nbc;
+ device->resync = resync_lru;
+ device->rs_plan_s = new_plan;
nbc = NULL;
resync_lru = NULL;
new_disk_conf = NULL;
new_plan = NULL;
- drbd_bump_write_ordering(mdev->tconn, WO_bdev_flush);
+ drbd_bump_write_ordering(first_peer_device(device)->connection, WO_bdev_flush);
- if (drbd_md_test_flag(mdev->ldev, MDF_CRASHED_PRIMARY))
- set_bit(CRASHED_PRIMARY, &mdev->flags);
+ if (drbd_md_test_flag(device->ldev, MDF_CRASHED_PRIMARY))
+ set_bit(CRASHED_PRIMARY, &device->flags);
else
- clear_bit(CRASHED_PRIMARY, &mdev->flags);
+ clear_bit(CRASHED_PRIMARY, &device->flags);
- if (drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND) &&
- !(mdev->state.role == R_PRIMARY && mdev->tconn->susp_nod))
- set_bit(CRASHED_PRIMARY, &mdev->flags);
+ if (drbd_md_test_flag(device->ldev, MDF_PRIMARY_IND) &&
+ !(device->state.role == R_PRIMARY && device->resource->susp_nod))
+ set_bit(CRASHED_PRIMARY, &device->flags);
- mdev->send_cnt = 0;
- mdev->recv_cnt = 0;
- mdev->read_cnt = 0;
- mdev->writ_cnt = 0;
+ device->send_cnt = 0;
+ device->recv_cnt = 0;
+ device->read_cnt = 0;
+ device->writ_cnt = 0;
- drbd_reconsider_max_bio_size(mdev);
+ drbd_reconsider_max_bio_size(device);
/* If I am currently not R_PRIMARY,
* but meta data primary indicator is set,
@@ -1666,50 +1693,50 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
* so we can automatically recover from a crash of a
* degraded but active "cluster" after a certain timeout.
*/
- clear_bit(USE_DEGR_WFC_T, &mdev->flags);
- if (mdev->state.role != R_PRIMARY &&
- drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND) &&
- !drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND))
- set_bit(USE_DEGR_WFC_T, &mdev->flags);
+ clear_bit(USE_DEGR_WFC_T, &device->flags);
+ if (device->state.role != R_PRIMARY &&
+ drbd_md_test_flag(device->ldev, MDF_PRIMARY_IND) &&
+ !drbd_md_test_flag(device->ldev, MDF_CONNECTED_IND))
+ set_bit(USE_DEGR_WFC_T, &device->flags);
- dd = drbd_determine_dev_size(mdev, 0, NULL);
+ dd = drbd_determine_dev_size(device, 0, NULL);
if (dd <= DS_ERROR) {
retcode = ERR_NOMEM_BITMAP;
goto force_diskless_dec;
} else if (dd == DS_GREW)
- set_bit(RESYNC_AFTER_NEG, &mdev->flags);
+ set_bit(RESYNC_AFTER_NEG, &device->flags);
- if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC) ||
- (test_bit(CRASHED_PRIMARY, &mdev->flags) &&
- drbd_md_test_flag(mdev->ldev, MDF_AL_DISABLED))) {
- dev_info(DEV, "Assuming that all blocks are out of sync "
+ if (drbd_md_test_flag(device->ldev, MDF_FULL_SYNC) ||
+ (test_bit(CRASHED_PRIMARY, &device->flags) &&
+ drbd_md_test_flag(device->ldev, MDF_AL_DISABLED))) {
+ drbd_info(device, "Assuming that all blocks are out of sync "
"(aka FullSync)\n");
- if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write,
+ if (drbd_bitmap_io(device, &drbd_bmio_set_n_write,
"set_n_write from attaching", BM_LOCKED_MASK)) {
retcode = ERR_IO_MD_DISK;
goto force_diskless_dec;
}
} else {
- if (drbd_bitmap_io(mdev, &drbd_bm_read,
+ if (drbd_bitmap_io(device, &drbd_bm_read,
"read from attaching", BM_LOCKED_MASK)) {
retcode = ERR_IO_MD_DISK;
goto force_diskless_dec;
}
}
- if (_drbd_bm_total_weight(mdev) == drbd_bm_bits(mdev))
- drbd_suspend_al(mdev); /* IO is still suspended here... */
+ if (_drbd_bm_total_weight(device) == drbd_bm_bits(device))
+ drbd_suspend_al(device); /* IO is still suspended here... */
- spin_lock_irq(&mdev->tconn->req_lock);
- os = drbd_read_state(mdev);
+ spin_lock_irq(&device->resource->req_lock);
+ os = drbd_read_state(device);
ns = os;
/* If MDF_CONSISTENT is not set go into inconsistent state,
otherwise investigate MDF_WasUpToDate...
If MDF_WAS_UP_TO_DATE is not set go into D_OUTDATED disk state,
otherwise into D_CONSISTENT state.
*/
- if (drbd_md_test_flag(mdev->ldev, MDF_CONSISTENT)) {
- if (drbd_md_test_flag(mdev->ldev, MDF_WAS_UP_TO_DATE))
+ if (drbd_md_test_flag(device->ldev, MDF_CONSISTENT)) {
+ if (drbd_md_test_flag(device->ldev, MDF_WAS_UP_TO_DATE))
ns.disk = D_CONSISTENT;
else
ns.disk = D_OUTDATED;
@@ -1717,12 +1744,12 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
ns.disk = D_INCONSISTENT;
}
- if (drbd_md_test_flag(mdev->ldev, MDF_PEER_OUT_DATED))
+ if (drbd_md_test_flag(device->ldev, MDF_PEER_OUT_DATED))
ns.pdsk = D_OUTDATED;
rcu_read_lock();
if (ns.disk == D_CONSISTENT &&
- (ns.pdsk == D_OUTDATED || rcu_dereference(mdev->ldev->disk_conf)->fencing == FP_DONT_CARE))
+ (ns.pdsk == D_OUTDATED || rcu_dereference(device->ldev->disk_conf)->fencing == FP_DONT_CARE))
ns.disk = D_UP_TO_DATE;
/* All tests on MDF_PRIMARY_IND, MDF_CONNECTED_IND,
@@ -1730,56 +1757,56 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
this point, because drbd_request_state() modifies these
flags. */
- if (rcu_dereference(mdev->ldev->disk_conf)->al_updates)
- mdev->ldev->md.flags &= ~MDF_AL_DISABLED;
+ if (rcu_dereference(device->ldev->disk_conf)->al_updates)
+ device->ldev->md.flags &= ~MDF_AL_DISABLED;
else
- mdev->ldev->md.flags |= MDF_AL_DISABLED;
+ device->ldev->md.flags |= MDF_AL_DISABLED;
rcu_read_unlock();
/* In case we are C_CONNECTED postpone any decision on the new disk
state after the negotiation phase. */
- if (mdev->state.conn == C_CONNECTED) {
- mdev->new_state_tmp.i = ns.i;
+ if (device->state.conn == C_CONNECTED) {
+ device->new_state_tmp.i = ns.i;
ns.i = os.i;
ns.disk = D_NEGOTIATING;
/* We expect to receive up-to-date UUIDs soon.
To avoid a race in receive_state, free p_uuid while
holding req_lock. I.e. atomic with the state change */
- kfree(mdev->p_uuid);
- mdev->p_uuid = NULL;
+ kfree(device->p_uuid);
+ device->p_uuid = NULL;
}
- rv = _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ rv = _drbd_set_state(device, ns, CS_VERBOSE, NULL);
+ spin_unlock_irq(&device->resource->req_lock);
if (rv < SS_SUCCESS)
goto force_diskless_dec;
- mod_timer(&mdev->request_timer, jiffies + HZ);
+ mod_timer(&device->request_timer, jiffies + HZ);
- if (mdev->state.role == R_PRIMARY)
- mdev->ldev->md.uuid[UI_CURRENT] |= (u64)1;
+ if (device->state.role == R_PRIMARY)
+ device->ldev->md.uuid[UI_CURRENT] |= (u64)1;
else
- mdev->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
+ device->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
- drbd_md_mark_dirty(mdev);
- drbd_md_sync(mdev);
+ drbd_md_mark_dirty(device);
+ drbd_md_sync(device);
- kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
- put_ldev(mdev);
- conn_reconfig_done(mdev->tconn);
+ kobject_uevent(&disk_to_dev(device->vdisk)->kobj, KOBJ_CHANGE);
+ put_ldev(device);
+ conn_reconfig_done(first_peer_device(device)->connection);
drbd_adm_finish(info, retcode);
return 0;
force_diskless_dec:
- put_ldev(mdev);
+ put_ldev(device);
force_diskless:
- drbd_force_state(mdev, NS(disk, D_DISKLESS));
- drbd_md_sync(mdev);
+ drbd_force_state(device, NS(disk, D_DISKLESS));
+ drbd_md_sync(device);
fail:
- conn_reconfig_done(mdev->tconn);
+ conn_reconfig_done(first_peer_device(device)->connection);
if (nbc) {
if (nbc->backing_bdev)
blkdev_put(nbc->backing_bdev,
@@ -1798,26 +1825,26 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
return 0;
}
-static int adm_detach(struct drbd_conf *mdev, int force)
+static int adm_detach(struct drbd_device *device, int force)
{
enum drbd_state_rv retcode;
int ret;
if (force) {
- set_bit(FORCE_DETACH, &mdev->flags);
- drbd_force_state(mdev, NS(disk, D_FAILED));
+ set_bit(FORCE_DETACH, &device->flags);
+ drbd_force_state(device, NS(disk, D_FAILED));
retcode = SS_SUCCESS;
goto out;
}
- drbd_suspend_io(mdev); /* so no-one is stuck in drbd_al_begin_io */
- drbd_md_get_buffer(mdev); /* make sure there is no in-flight meta-data IO */
- retcode = drbd_request_state(mdev, NS(disk, D_FAILED));
- drbd_md_put_buffer(mdev);
+ drbd_suspend_io(device); /* so no-one is stuck in drbd_al_begin_io */
+ drbd_md_get_buffer(device); /* make sure there is no in-flight meta-data IO */
+ retcode = drbd_request_state(device, NS(disk, D_FAILED));
+ drbd_md_put_buffer(device);
/* D_FAILED will transition to DISKLESS. */
- ret = wait_event_interruptible(mdev->misc_wait,
- mdev->state.disk != D_FAILED);
- drbd_resume_io(mdev);
+ ret = wait_event_interruptible(device->misc_wait,
+ device->state.disk != D_FAILED);
+ drbd_resume_io(device);
if ((int)retcode == (int)SS_IS_DISKLESS)
retcode = SS_NOTHING_TO_DO;
if (ret)
@@ -1852,24 +1879,25 @@ int drbd_adm_detach(struct sk_buff *skb, struct genl_info *info)
}
}
- retcode = adm_detach(adm_ctx.mdev, parms.force_detach);
+ retcode = adm_detach(adm_ctx.device, parms.force_detach);
out:
drbd_adm_finish(info, retcode);
return 0;
}
-static bool conn_resync_running(struct drbd_tconn *tconn)
+static bool conn_resync_running(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
bool rv = false;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (mdev->state.conn == C_SYNC_SOURCE ||
- mdev->state.conn == C_SYNC_TARGET ||
- mdev->state.conn == C_PAUSED_SYNC_S ||
- mdev->state.conn == C_PAUSED_SYNC_T) {
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ if (device->state.conn == C_SYNC_SOURCE ||
+ device->state.conn == C_SYNC_TARGET ||
+ device->state.conn == C_PAUSED_SYNC_S ||
+ device->state.conn == C_PAUSED_SYNC_T) {
rv = true;
break;
}
@@ -1879,16 +1907,17 @@ static bool conn_resync_running(struct drbd_tconn *tconn)
return rv;
}
-static bool conn_ov_running(struct drbd_tconn *tconn)
+static bool conn_ov_running(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
bool rv = false;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (mdev->state.conn == C_VERIFY_S ||
- mdev->state.conn == C_VERIFY_T) {
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ if (device->state.conn == C_VERIFY_S ||
+ device->state.conn == C_VERIFY_T) {
rv = true;
break;
}
@@ -1899,63 +1928,65 @@ static bool conn_ov_running(struct drbd_tconn *tconn)
}
static enum drbd_ret_code
-_check_net_options(struct drbd_tconn *tconn, struct net_conf *old_conf, struct net_conf *new_conf)
+_check_net_options(struct drbd_connection *connection, struct net_conf *old_net_conf, struct net_conf *new_net_conf)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int i;
- if (old_conf && tconn->cstate == C_WF_REPORT_PARAMS && tconn->agreed_pro_version < 100) {
- if (new_conf->wire_protocol != old_conf->wire_protocol)
+ if (old_net_conf && connection->cstate == C_WF_REPORT_PARAMS && connection->agreed_pro_version < 100) {
+ if (new_net_conf->wire_protocol != old_net_conf->wire_protocol)
return ERR_NEED_APV_100;
- if (new_conf->two_primaries != old_conf->two_primaries)
+ if (new_net_conf->two_primaries != old_net_conf->two_primaries)
return ERR_NEED_APV_100;
- if (strcmp(new_conf->integrity_alg, old_conf->integrity_alg))
+ if (strcmp(new_net_conf->integrity_alg, old_net_conf->integrity_alg))
return ERR_NEED_APV_100;
}
- if (!new_conf->two_primaries &&
- conn_highest_role(tconn) == R_PRIMARY &&
- conn_highest_peer(tconn) == R_PRIMARY)
+ if (!new_net_conf->two_primaries &&
+ conn_highest_role(connection) == R_PRIMARY &&
+ conn_highest_peer(connection) == R_PRIMARY)
return ERR_NEED_ALLOW_TWO_PRI;
- if (new_conf->two_primaries &&
- (new_conf->wire_protocol != DRBD_PROT_C))
+ if (new_net_conf->two_primaries &&
+ (new_net_conf->wire_protocol != DRBD_PROT_C))
return ERR_NOT_PROTO_C;
- idr_for_each_entry(&tconn->volumes, mdev, i) {
- if (get_ldev(mdev)) {
- enum drbd_fencing_p fp = rcu_dereference(mdev->ldev->disk_conf)->fencing;
- put_ldev(mdev);
- if (new_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH)
+ idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+ struct drbd_device *device = peer_device->device;
+ if (get_ldev(device)) {
+ enum drbd_fencing_p fp = rcu_dereference(device->ldev->disk_conf)->fencing;
+ put_ldev(device);
+ if (new_net_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH)
return ERR_STONITH_AND_PROT_A;
}
- if (mdev->state.role == R_PRIMARY && new_conf->discard_my_data)
+ if (device->state.role == R_PRIMARY && new_net_conf->discard_my_data)
return ERR_DISCARD_IMPOSSIBLE;
}
- if (new_conf->on_congestion != OC_BLOCK && new_conf->wire_protocol != DRBD_PROT_A)
+ if (new_net_conf->on_congestion != OC_BLOCK && new_net_conf->wire_protocol != DRBD_PROT_A)
return ERR_CONG_NOT_PROTO_A;
return NO_ERROR;
}
static enum drbd_ret_code
-check_net_options(struct drbd_tconn *tconn, struct net_conf *new_conf)
+check_net_options(struct drbd_connection *connection, struct net_conf *new_net_conf)
{
static enum drbd_ret_code rv;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int i;
rcu_read_lock();
- rv = _check_net_options(tconn, rcu_dereference(tconn->net_conf), new_conf);
+ rv = _check_net_options(connection, rcu_dereference(connection->net_conf), new_net_conf);
rcu_read_unlock();
- /* tconn->volumes protected by genl_lock() here */
- idr_for_each_entry(&tconn->volumes, mdev, i) {
- if (!mdev->bitmap) {
- if(drbd_bm_init(mdev))
+ /* connection->volumes protected by genl_lock() here */
+ idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+ struct drbd_device *device = peer_device->device;
+ if (!device->bitmap) {
+ if (drbd_bm_init(device))
return ERR_NOMEM;
}
}
@@ -1986,26 +2017,26 @@ alloc_hash(struct crypto_hash **tfm, char *tfm_name, int err_alg)
}
static enum drbd_ret_code
-alloc_crypto(struct crypto *crypto, struct net_conf *new_conf)
+alloc_crypto(struct crypto *crypto, struct net_conf *new_net_conf)
{
char hmac_name[CRYPTO_MAX_ALG_NAME];
enum drbd_ret_code rv;
- rv = alloc_hash(&crypto->csums_tfm, new_conf->csums_alg,
+ rv = alloc_hash(&crypto->csums_tfm, new_net_conf->csums_alg,
ERR_CSUMS_ALG);
if (rv != NO_ERROR)
return rv;
- rv = alloc_hash(&crypto->verify_tfm, new_conf->verify_alg,
+ rv = alloc_hash(&crypto->verify_tfm, new_net_conf->verify_alg,
ERR_VERIFY_ALG);
if (rv != NO_ERROR)
return rv;
- rv = alloc_hash(&crypto->integrity_tfm, new_conf->integrity_alg,
+ rv = alloc_hash(&crypto->integrity_tfm, new_net_conf->integrity_alg,
ERR_INTEGRITY_ALG);
if (rv != NO_ERROR)
return rv;
- if (new_conf->cram_hmac_alg[0] != 0) {
+ if (new_net_conf->cram_hmac_alg[0] != 0) {
snprintf(hmac_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)",
- new_conf->cram_hmac_alg);
+ new_net_conf->cram_hmac_alg);
rv = alloc_hash(&crypto->cram_hmac_tfm, hmac_name,
ERR_AUTH_ALG);
@@ -2025,8 +2056,8 @@ static void free_crypto(struct crypto *crypto)
int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
{
enum drbd_ret_code retcode;
- struct drbd_tconn *tconn;
- struct net_conf *old_conf, *new_conf = NULL;
+ struct drbd_connection *connection;
+ struct net_conf *old_net_conf, *new_net_conf = NULL;
int err;
int ovr; /* online verify running */
int rsr; /* re-sync running */
@@ -2038,98 +2069,103 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- tconn = adm_ctx.tconn;
+ connection = adm_ctx.connection;
- new_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL);
- if (!new_conf) {
+ new_net_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL);
+ if (!new_net_conf) {
retcode = ERR_NOMEM;
goto out;
}
- conn_reconfig_start(tconn);
+ conn_reconfig_start(connection);
- mutex_lock(&tconn->data.mutex);
- mutex_lock(&tconn->conf_update);
- old_conf = tconn->net_conf;
+ mutex_lock(&connection->data.mutex);
+ mutex_lock(&connection->resource->conf_update);
+ old_net_conf = connection->net_conf;
- if (!old_conf) {
+ if (!old_net_conf) {
drbd_msg_put_info("net conf missing, try connect");
retcode = ERR_INVALID_REQUEST;
goto fail;
}
- *new_conf = *old_conf;
+ *new_net_conf = *old_net_conf;
if (should_set_defaults(info))
- set_net_conf_defaults(new_conf);
+ set_net_conf_defaults(new_net_conf);
- err = net_conf_from_attrs_for_change(new_conf, info);
+ err = net_conf_from_attrs_for_change(new_net_conf, info);
if (err && err != -ENOMSG) {
retcode = ERR_MANDATORY_TAG;
drbd_msg_put_info(from_attrs_err_to_txt(err));
goto fail;
}
- retcode = check_net_options(tconn, new_conf);
+ retcode = check_net_options(connection, new_net_conf);
if (retcode != NO_ERROR)
goto fail;
/* re-sync running */
- rsr = conn_resync_running(tconn);
- if (rsr && strcmp(new_conf->csums_alg, old_conf->csums_alg)) {
+ rsr = conn_resync_running(connection);
+ if (rsr && strcmp(new_net_conf->csums_alg, old_net_conf->csums_alg)) {
retcode = ERR_CSUMS_RESYNC_RUNNING;
goto fail;
}
/* online verify running */
- ovr = conn_ov_running(tconn);
- if (ovr && strcmp(new_conf->verify_alg, old_conf->verify_alg)) {
+ ovr = conn_ov_running(connection);
+ if (ovr && strcmp(new_net_conf->verify_alg, old_net_conf->verify_alg)) {
retcode = ERR_VERIFY_RUNNING;
goto fail;
}
- retcode = alloc_crypto(&crypto, new_conf);
+ retcode = alloc_crypto(&crypto, new_net_conf);
if (retcode != NO_ERROR)
goto fail;
- rcu_assign_pointer(tconn->net_conf, new_conf);
+ rcu_assign_pointer(connection->net_conf, new_net_conf);
if (!rsr) {
- crypto_free_hash(tconn->csums_tfm);
- tconn->csums_tfm = crypto.csums_tfm;
+ crypto_free_hash(connection->csums_tfm);
+ connection->csums_tfm = crypto.csums_tfm;
crypto.csums_tfm = NULL;
}
if (!ovr) {
- crypto_free_hash(tconn->verify_tfm);
- tconn->verify_tfm = crypto.verify_tfm;
+ crypto_free_hash(connection->verify_tfm);
+ connection->verify_tfm = crypto.verify_tfm;
crypto.verify_tfm = NULL;
}
- crypto_free_hash(tconn->integrity_tfm);
- tconn->integrity_tfm = crypto.integrity_tfm;
- if (tconn->cstate >= C_WF_REPORT_PARAMS && tconn->agreed_pro_version >= 100)
- /* Do this without trying to take tconn->data.mutex again. */
- __drbd_send_protocol(tconn, P_PROTOCOL_UPDATE);
+ crypto_free_hash(connection->integrity_tfm);
+ connection->integrity_tfm = crypto.integrity_tfm;
+ if (connection->cstate >= C_WF_REPORT_PARAMS && connection->agreed_pro_version >= 100)
+ /* Do this without trying to take connection->data.mutex again. */
+ __drbd_send_protocol(connection, P_PROTOCOL_UPDATE);
- crypto_free_hash(tconn->cram_hmac_tfm);
- tconn->cram_hmac_tfm = crypto.cram_hmac_tfm;
+ crypto_free_hash(connection->cram_hmac_tfm);
+ connection->cram_hmac_tfm = crypto.cram_hmac_tfm;
- mutex_unlock(&tconn->conf_update);
- mutex_unlock(&tconn->data.mutex);
+ mutex_unlock(&connection->resource->conf_update);
+ mutex_unlock(&connection->data.mutex);
synchronize_rcu();
- kfree(old_conf);
+ kfree(old_net_conf);
+
+ if (connection->cstate >= C_WF_REPORT_PARAMS) {
+ struct drbd_peer_device *peer_device;
+ int vnr;
- if (tconn->cstate >= C_WF_REPORT_PARAMS)
- drbd_send_sync_param(minor_to_mdev(conn_lowest_minor(tconn)));
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr)
+ drbd_send_sync_param(peer_device);
+ }
goto done;
fail:
- mutex_unlock(&tconn->conf_update);
- mutex_unlock(&tconn->data.mutex);
+ mutex_unlock(&connection->resource->conf_update);
+ mutex_unlock(&connection->data.mutex);
free_crypto(&crypto);
- kfree(new_conf);
+ kfree(new_net_conf);
done:
- conn_reconfig_done(tconn);
+ conn_reconfig_done(connection);
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -2137,10 +2173,11 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
- struct net_conf *old_conf, *new_conf = NULL;
+ struct drbd_peer_device *peer_device;
+ struct net_conf *old_net_conf, *new_net_conf = NULL;
struct crypto crypto = { };
- struct drbd_tconn *tconn;
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
enum drbd_ret_code retcode;
int i;
int err;
@@ -2160,106 +2197,111 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
/* No need for _rcu here. All reconfiguration is
* strictly serialized on genl_lock(). We are protected against
* concurrent reconfiguration/addition/deletion */
- list_for_each_entry(tconn, &drbd_tconns, all_tconn) {
- if (nla_len(adm_ctx.my_addr) == tconn->my_addr_len &&
- !memcmp(nla_data(adm_ctx.my_addr), &tconn->my_addr, tconn->my_addr_len)) {
- retcode = ERR_LOCAL_ADDR;
- goto out;
- }
+ for_each_resource(resource, &drbd_resources) {
+ for_each_connection(connection, resource) {
+ if (nla_len(adm_ctx.my_addr) == connection->my_addr_len &&
+ !memcmp(nla_data(adm_ctx.my_addr), &connection->my_addr,
+ connection->my_addr_len)) {
+ retcode = ERR_LOCAL_ADDR;
+ goto out;
+ }
- if (nla_len(adm_ctx.peer_addr) == tconn->peer_addr_len &&
- !memcmp(nla_data(adm_ctx.peer_addr), &tconn->peer_addr, tconn->peer_addr_len)) {
- retcode = ERR_PEER_ADDR;
- goto out;
+ if (nla_len(adm_ctx.peer_addr) == connection->peer_addr_len &&
+ !memcmp(nla_data(adm_ctx.peer_addr), &connection->peer_addr,
+ connection->peer_addr_len)) {
+ retcode = ERR_PEER_ADDR;
+ goto out;
+ }
}
}
- tconn = adm_ctx.tconn;
- conn_reconfig_start(tconn);
+ connection = first_connection(adm_ctx.resource);
+ conn_reconfig_start(connection);
- if (tconn->cstate > C_STANDALONE) {
+ if (connection->cstate > C_STANDALONE) {
retcode = ERR_NET_CONFIGURED;
goto fail;
}
/* allocation not in the IO path, drbdsetup / netlink process context */
- new_conf = kzalloc(sizeof(*new_conf), GFP_KERNEL);
- if (!new_conf) {
+ new_net_conf = kzalloc(sizeof(*new_net_conf), GFP_KERNEL);
+ if (!new_net_conf) {
retcode = ERR_NOMEM;
goto fail;
}
- set_net_conf_defaults(new_conf);
+ set_net_conf_defaults(new_net_conf);
- err = net_conf_from_attrs(new_conf, info);
+ err = net_conf_from_attrs(new_net_conf, info);
if (err && err != -ENOMSG) {
retcode = ERR_MANDATORY_TAG;
drbd_msg_put_info(from_attrs_err_to_txt(err));
goto fail;
}
- retcode = check_net_options(tconn, new_conf);
+ retcode = check_net_options(connection, new_net_conf);
if (retcode != NO_ERROR)
goto fail;
- retcode = alloc_crypto(&crypto, new_conf);
+ retcode = alloc_crypto(&crypto, new_net_conf);
if (retcode != NO_ERROR)
goto fail;
- ((char *)new_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0;
+ ((char *)new_net_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0;
- conn_flush_workqueue(tconn);
+ drbd_flush_workqueue(&connection->sender_work);
- mutex_lock(&tconn->conf_update);
- old_conf = tconn->net_conf;
- if (old_conf) {
+ mutex_lock(&adm_ctx.resource->conf_update);
+ old_net_conf = connection->net_conf;
+ if (old_net_conf) {
retcode = ERR_NET_CONFIGURED;
- mutex_unlock(&tconn->conf_update);
+ mutex_unlock(&adm_ctx.resource->conf_update);
goto fail;
}
- rcu_assign_pointer(tconn->net_conf, new_conf);
+ rcu_assign_pointer(connection->net_conf, new_net_conf);
- conn_free_crypto(tconn);
- tconn->cram_hmac_tfm = crypto.cram_hmac_tfm;
- tconn->integrity_tfm = crypto.integrity_tfm;
- tconn->csums_tfm = crypto.csums_tfm;
- tconn->verify_tfm = crypto.verify_tfm;
+ conn_free_crypto(connection);
+ connection->cram_hmac_tfm = crypto.cram_hmac_tfm;
+ connection->integrity_tfm = crypto.integrity_tfm;
+ connection->csums_tfm = crypto.csums_tfm;
+ connection->verify_tfm = crypto.verify_tfm;
- tconn->my_addr_len = nla_len(adm_ctx.my_addr);
- memcpy(&tconn->my_addr, nla_data(adm_ctx.my_addr), tconn->my_addr_len);
- tconn->peer_addr_len = nla_len(adm_ctx.peer_addr);
- memcpy(&tconn->peer_addr, nla_data(adm_ctx.peer_addr), tconn->peer_addr_len);
+ connection->my_addr_len = nla_len(adm_ctx.my_addr);
+ memcpy(&connection->my_addr, nla_data(adm_ctx.my_addr), connection->my_addr_len);
+ connection->peer_addr_len = nla_len(adm_ctx.peer_addr);
+ memcpy(&connection->peer_addr, nla_data(adm_ctx.peer_addr), connection->peer_addr_len);
- mutex_unlock(&tconn->conf_update);
+ mutex_unlock(&adm_ctx.resource->conf_update);
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, i) {
- mdev->send_cnt = 0;
- mdev->recv_cnt = 0;
+ idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+ struct drbd_device *device = peer_device->device;
+ device->send_cnt = 0;
+ device->recv_cnt = 0;
}
rcu_read_unlock();
- retcode = conn_request_state(tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE);
+ retcode = conn_request_state(connection, NS(conn, C_UNCONNECTED), CS_VERBOSE);
- conn_reconfig_done(tconn);
+ conn_reconfig_done(connection);
drbd_adm_finish(info, retcode);
return 0;
fail:
free_crypto(&crypto);
- kfree(new_conf);
+ kfree(new_net_conf);
- conn_reconfig_done(tconn);
+ conn_reconfig_done(connection);
out:
drbd_adm_finish(info, retcode);
return 0;
}
-static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool force)
+static enum drbd_state_rv conn_try_disconnect(struct drbd_connection *connection, bool force)
{
enum drbd_state_rv rv;
- rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING),
+ rv = conn_request_state(connection, NS(conn, C_DISCONNECTING),
force ? CS_HARD : 0);
switch (rv) {
@@ -2269,18 +2311,18 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool for
return SS_SUCCESS;
case SS_PRIMARY_NOP:
/* Our state checking code wants to see the peer outdated. */
- rv = conn_request_state(tconn, NS2(conn, C_DISCONNECTING, pdsk, D_OUTDATED), 0);
+ rv = conn_request_state(connection, NS2(conn, C_DISCONNECTING, pdsk, D_OUTDATED), 0);
if (rv == SS_OUTDATE_WO_CONN) /* lost connection before graceful disconnect succeeded */
- rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_VERBOSE);
+ rv = conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_VERBOSE);
break;
case SS_CW_FAILED_BY_PEER:
/* The peer probably wants to see us outdated. */
- rv = conn_request_state(tconn, NS2(conn, C_DISCONNECTING,
+ rv = conn_request_state(connection, NS2(conn, C_DISCONNECTING,
disk, D_OUTDATED), 0);
if (rv == SS_IS_DISKLESS || rv == SS_LOWER_THAN_OUTDATED) {
- rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING),
+ rv = conn_request_state(connection, NS(conn, C_DISCONNECTING),
CS_HARD);
}
break;
@@ -2294,18 +2336,18 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool for
* The state handling only uses drbd_thread_stop_nowait(),
* we want to really wait here until the receiver is no more.
*/
- drbd_thread_stop(&adm_ctx.tconn->receiver);
+ drbd_thread_stop(&connection->receiver);
/* Race breaker. This additional state change request may be
* necessary, if this was a forced disconnect during a receiver
* restart. We may have "killed" the receiver thread just
- * after drbdd_init() returned. Typically, we should be
+ * after drbd_receiver() returned. Typically, we should be
* C_STANDALONE already, now, and this becomes a no-op.
*/
- rv2 = conn_request_state(tconn, NS(conn, C_STANDALONE),
+ rv2 = conn_request_state(connection, NS(conn, C_STANDALONE),
CS_VERBOSE | CS_HARD);
if (rv2 < SS_SUCCESS)
- conn_err(tconn,
+ drbd_err(connection,
"unexpected rv2=%d in conn_try_disconnect()\n",
rv2);
}
@@ -2315,7 +2357,7 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool for
int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
{
struct disconnect_parms parms;
- struct drbd_tconn *tconn;
+ struct drbd_connection *connection;
enum drbd_state_rv rv;
enum drbd_ret_code retcode;
int err;
@@ -2326,7 +2368,7 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto fail;
- tconn = adm_ctx.tconn;
+ connection = adm_ctx.connection;
memset(&parms, 0, sizeof(parms));
if (info->attrs[DRBD_NLA_DISCONNECT_PARMS]) {
err = disconnect_parms_from_attrs(&parms, info);
@@ -2337,7 +2379,7 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
}
}
- rv = conn_try_disconnect(tconn, parms.force_disconnect);
+ rv = conn_try_disconnect(connection, parms.force_disconnect);
if (rv < SS_SUCCESS)
retcode = rv; /* FIXME: Type mismatch. */
else
@@ -2347,27 +2389,27 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
return 0;
}
-void resync_after_online_grow(struct drbd_conf *mdev)
+void resync_after_online_grow(struct drbd_device *device)
{
int iass; /* I am sync source */
- dev_info(DEV, "Resync of new storage after online grow\n");
- if (mdev->state.role != mdev->state.peer)
- iass = (mdev->state.role == R_PRIMARY);
+ drbd_info(device, "Resync of new storage after online grow\n");
+ if (device->state.role != device->state.peer)
+ iass = (device->state.role == R_PRIMARY);
else
- iass = test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags);
+ iass = test_bit(RESOLVE_CONFLICTS, &first_peer_device(device)->connection->flags);
if (iass)
- drbd_start_resync(mdev, C_SYNC_SOURCE);
+ drbd_start_resync(device, C_SYNC_SOURCE);
else
- _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE + CS_SERIALIZE);
+ _drbd_request_state(device, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE + CS_SERIALIZE);
}
int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
{
struct disk_conf *old_disk_conf, *new_disk_conf = NULL;
struct resize_parms rs;
- struct drbd_conf *mdev;
+ struct drbd_device *device;
enum drbd_ret_code retcode;
enum determine_dev_size dd;
bool change_al_layout = false;
@@ -2381,15 +2423,15 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto fail;
- mdev = adm_ctx.mdev;
- if (!get_ldev(mdev)) {
+ device = adm_ctx.device;
+ if (!get_ldev(device)) {
retcode = ERR_NO_DISK;
goto fail;
}
memset(&rs, 0, sizeof(struct resize_parms));
- rs.al_stripes = mdev->ldev->md.al_stripes;
- rs.al_stripe_size = mdev->ldev->md.al_stripe_size_4k * 4;
+ rs.al_stripes = device->ldev->md.al_stripes;
+ rs.al_stripe_size = device->ldev->md.al_stripe_size_4k * 4;
if (info->attrs[DRBD_NLA_RESIZE_PARMS]) {
err = resize_parms_from_attrs(&rs, info);
if (err) {
@@ -2399,24 +2441,24 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
}
}
- if (mdev->state.conn > C_CONNECTED) {
+ if (device->state.conn > C_CONNECTED) {
retcode = ERR_RESIZE_RESYNC;
goto fail_ldev;
}
- if (mdev->state.role == R_SECONDARY &&
- mdev->state.peer == R_SECONDARY) {
+ if (device->state.role == R_SECONDARY &&
+ device->state.peer == R_SECONDARY) {
retcode = ERR_NO_PRIMARY;
goto fail_ldev;
}
- if (rs.no_resync && mdev->tconn->agreed_pro_version < 93) {
+ if (rs.no_resync && first_peer_device(device)->connection->agreed_pro_version < 93) {
retcode = ERR_NEED_APV_93;
goto fail_ldev;
}
rcu_read_lock();
- u_size = rcu_dereference(mdev->ldev->disk_conf)->disk_size;
+ u_size = rcu_dereference(device->ldev->disk_conf)->disk_size;
rcu_read_unlock();
if (u_size != (sector_t)rs.resize_size) {
new_disk_conf = kmalloc(sizeof(struct disk_conf), GFP_KERNEL);
@@ -2426,8 +2468,8 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
}
}
- if (mdev->ldev->md.al_stripes != rs.al_stripes ||
- mdev->ldev->md.al_stripe_size_4k != rs.al_stripe_size / 4) {
+ if (device->ldev->md.al_stripes != rs.al_stripes ||
+ device->ldev->md.al_stripe_size_4k != rs.al_stripe_size / 4) {
u32 al_size_k = rs.al_stripes * rs.al_stripe_size;
if (al_size_k > (16 * 1024 * 1024)) {
@@ -2440,7 +2482,7 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
goto fail_ldev;
}
- if (mdev->state.conn != C_CONNECTED) {
+ if (device->state.conn != C_CONNECTED) {
retcode = ERR_MD_LAYOUT_CONNECTED;
goto fail_ldev;
}
@@ -2448,24 +2490,24 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
change_al_layout = true;
}
- if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev))
- mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev);
+ if (device->ldev->known_size != drbd_get_capacity(device->ldev->backing_bdev))
+ device->ldev->known_size = drbd_get_capacity(device->ldev->backing_bdev);
if (new_disk_conf) {
- mutex_lock(&mdev->tconn->conf_update);
- old_disk_conf = mdev->ldev->disk_conf;
+ mutex_lock(&device->resource->conf_update);
+ old_disk_conf = device->ldev->disk_conf;
*new_disk_conf = *old_disk_conf;
new_disk_conf->disk_size = (sector_t)rs.resize_size;
- rcu_assign_pointer(mdev->ldev->disk_conf, new_disk_conf);
- mutex_unlock(&mdev->tconn->conf_update);
+ rcu_assign_pointer(device->ldev->disk_conf, new_disk_conf);
+ mutex_unlock(&device->resource->conf_update);
synchronize_rcu();
kfree(old_disk_conf);
}
ddsf = (rs.resize_force ? DDSF_FORCED : 0) | (rs.no_resync ? DDSF_NO_RESYNC : 0);
- dd = drbd_determine_dev_size(mdev, ddsf, change_al_layout ? &rs : NULL);
- drbd_md_sync(mdev);
- put_ldev(mdev);
+ dd = drbd_determine_dev_size(device, ddsf, change_al_layout ? &rs : NULL);
+ drbd_md_sync(device);
+ put_ldev(device);
if (dd == DS_ERROR) {
retcode = ERR_NOMEM_BITMAP;
goto fail;
@@ -2477,12 +2519,12 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
goto fail;
}
- if (mdev->state.conn == C_CONNECTED) {
+ if (device->state.conn == C_CONNECTED) {
if (dd == DS_GREW)
- set_bit(RESIZE_PENDING, &mdev->flags);
+ set_bit(RESIZE_PENDING, &device->flags);
- drbd_send_uuids(mdev);
- drbd_send_sizes(mdev, 1, ddsf);
+ drbd_send_uuids(first_peer_device(device));
+ drbd_send_sizes(first_peer_device(device), 1, ddsf);
}
fail:
@@ -2490,14 +2532,13 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
return 0;
fail_ldev:
- put_ldev(mdev);
+ put_ldev(device);
goto fail;
}
int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info)
{
enum drbd_ret_code retcode;
- struct drbd_tconn *tconn;
struct res_opts res_opts;
int err;
@@ -2506,9 +2547,8 @@ int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info)
return retcode;
if (retcode != NO_ERROR)
goto fail;
- tconn = adm_ctx.tconn;
- res_opts = tconn->res_opts;
+ res_opts = adm_ctx.resource->res_opts;
if (should_set_defaults(info))
set_res_opts_defaults(&res_opts);
@@ -2519,7 +2559,7 @@ int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info)
goto fail;
}
- err = set_resource_options(tconn, &res_opts);
+ err = set_resource_options(adm_ctx.resource, &res_opts);
if (err) {
retcode = ERR_INVALID_REQUEST;
if (err == -ENOMEM)
@@ -2533,7 +2573,7 @@ fail:
int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
+ struct drbd_device *device;
int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
@@ -2542,29 +2582,29 @@ int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- mdev = adm_ctx.mdev;
+ device = adm_ctx.device;
/* If there is still bitmap IO pending, probably because of a previous
* resync just being finished, wait for it before requesting a new resync.
* Also wait for it's after_state_ch(). */
- drbd_suspend_io(mdev);
- wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
- drbd_flush_workqueue(mdev);
+ drbd_suspend_io(device);
+ wait_event(device->misc_wait, !test_bit(BITMAP_IO, &device->flags));
+ drbd_flush_workqueue(&first_peer_device(device)->connection->sender_work);
/* If we happen to be C_STANDALONE R_SECONDARY, just change to
* D_INCONSISTENT, and set all bits in the bitmap. Otherwise,
* try to start a resync handshake as sync target for full sync.
*/
- if (mdev->state.conn == C_STANDALONE && mdev->state.role == R_SECONDARY) {
- retcode = drbd_request_state(mdev, NS(disk, D_INCONSISTENT));
+ if (device->state.conn == C_STANDALONE && device->state.role == R_SECONDARY) {
+ retcode = drbd_request_state(device, NS(disk, D_INCONSISTENT));
if (retcode >= SS_SUCCESS) {
- if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write,
+ if (drbd_bitmap_io(device, &drbd_bmio_set_n_write,
"set_n_write from invalidate", BM_LOCKED_MASK))
retcode = ERR_IO_MD_DISK;
}
} else
- retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T));
- drbd_resume_io(mdev);
+ retcode = drbd_request_state(device, NS(conn, C_STARTING_SYNC_T));
+ drbd_resume_io(device);
out:
drbd_adm_finish(info, retcode);
@@ -2582,25 +2622,25 @@ static int drbd_adm_simple_request_state(struct sk_buff *skb, struct genl_info *
if (retcode != NO_ERROR)
goto out;
- retcode = drbd_request_state(adm_ctx.mdev, mask, val);
+ retcode = drbd_request_state(adm_ctx.device, mask, val);
out:
drbd_adm_finish(info, retcode);
return 0;
}
-static int drbd_bmio_set_susp_al(struct drbd_conf *mdev)
+static int drbd_bmio_set_susp_al(struct drbd_device *device)
{
int rv;
- rv = drbd_bmio_set_n_write(mdev);
- drbd_suspend_al(mdev);
+ rv = drbd_bmio_set_n_write(device);
+ drbd_suspend_al(device);
return rv;
}
int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info)
{
int retcode; /* drbd_ret_code, drbd_state_rv */
- struct drbd_conf *mdev;
+ struct drbd_device *device;
retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
if (!adm_ctx.reply_skb)
@@ -2608,32 +2648,32 @@ int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- mdev = adm_ctx.mdev;
+ device = adm_ctx.device;
/* If there is still bitmap IO pending, probably because of a previous
* resync just being finished, wait for it before requesting a new resync.
* Also wait for it's after_state_ch(). */
- drbd_suspend_io(mdev);
- wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
- drbd_flush_workqueue(mdev);
+ drbd_suspend_io(device);
+ wait_event(device->misc_wait, !test_bit(BITMAP_IO, &device->flags));
+ drbd_flush_workqueue(&first_peer_device(device)->connection->sender_work);
/* If we happen to be C_STANDALONE R_PRIMARY, just set all bits
* in the bitmap. Otherwise, try to start a resync handshake
* as sync source for full sync.
*/
- if (mdev->state.conn == C_STANDALONE && mdev->state.role == R_PRIMARY) {
+ if (device->state.conn == C_STANDALONE && device->state.role == R_PRIMARY) {
/* The peer will get a resync upon connect anyways. Just make that
into a full resync. */
- retcode = drbd_request_state(mdev, NS(pdsk, D_INCONSISTENT));
+ retcode = drbd_request_state(device, NS(pdsk, D_INCONSISTENT));
if (retcode >= SS_SUCCESS) {
- if (drbd_bitmap_io(mdev, &drbd_bmio_set_susp_al,
+ if (drbd_bitmap_io(device, &drbd_bmio_set_susp_al,
"set_n_write from invalidate_peer",
BM_LOCKED_SET_ALLOWED))
retcode = ERR_IO_MD_DISK;
}
} else
- retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S));
- drbd_resume_io(mdev);
+ retcode = drbd_request_state(device, NS(conn, C_STARTING_SYNC_S));
+ drbd_resume_io(device);
out:
drbd_adm_finish(info, retcode);
@@ -2650,7 +2690,7 @@ int drbd_adm_pause_sync(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- if (drbd_request_state(adm_ctx.mdev, NS(user_isp, 1)) == SS_NOTHING_TO_DO)
+ if (drbd_request_state(adm_ctx.device, NS(user_isp, 1)) == SS_NOTHING_TO_DO)
retcode = ERR_PAUSE_IS_SET;
out:
drbd_adm_finish(info, retcode);
@@ -2668,8 +2708,8 @@ int drbd_adm_resume_sync(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- if (drbd_request_state(adm_ctx.mdev, NS(user_isp, 0)) == SS_NOTHING_TO_DO) {
- s = adm_ctx.mdev->state;
+ if (drbd_request_state(adm_ctx.device, NS(user_isp, 0)) == SS_NOTHING_TO_DO) {
+ s = adm_ctx.device->state;
if (s.conn == C_PAUSED_SYNC_S || s.conn == C_PAUSED_SYNC_T) {
retcode = s.aftr_isp ? ERR_PIC_AFTER_DEP :
s.peer_isp ? ERR_PIC_PEER_DEP : ERR_PAUSE_IS_CLEAR;
@@ -2690,7 +2730,7 @@ int drbd_adm_suspend_io(struct sk_buff *skb, struct genl_info *info)
int drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
+ struct drbd_device *device;
int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
@@ -2699,20 +2739,20 @@ int drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- mdev = adm_ctx.mdev;
- if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
- drbd_uuid_new_current(mdev);
- clear_bit(NEW_CUR_UUID, &mdev->flags);
+ device = adm_ctx.device;
+ if (test_bit(NEW_CUR_UUID, &device->flags)) {
+ drbd_uuid_new_current(device);
+ clear_bit(NEW_CUR_UUID, &device->flags);
}
- drbd_suspend_io(mdev);
- retcode = drbd_request_state(mdev, NS3(susp, 0, susp_nod, 0, susp_fen, 0));
+ drbd_suspend_io(device);
+ retcode = drbd_request_state(device, NS3(susp, 0, susp_nod, 0, susp_fen, 0));
if (retcode == SS_SUCCESS) {
- if (mdev->state.conn < C_CONNECTED)
- tl_clear(mdev->tconn);
- if (mdev->state.disk == D_DISKLESS || mdev->state.disk == D_FAILED)
- tl_restart(mdev->tconn, FAIL_FROZEN_DISK_IO);
+ if (device->state.conn < C_CONNECTED)
+ tl_clear(first_peer_device(device)->connection);
+ if (device->state.disk == D_DISKLESS || device->state.disk == D_FAILED)
+ tl_restart(first_peer_device(device)->connection, FAIL_FROZEN_DISK_IO);
}
- drbd_resume_io(mdev);
+ drbd_resume_io(device);
out:
drbd_adm_finish(info, retcode);
@@ -2724,23 +2764,28 @@ int drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info)
return drbd_adm_simple_request_state(skb, info, NS(disk, D_OUTDATED));
}
-int nla_put_drbd_cfg_context(struct sk_buff *skb, struct drbd_tconn *tconn, unsigned vnr)
+static int nla_put_drbd_cfg_context(struct sk_buff *skb,
+ struct drbd_resource *resource,
+ struct drbd_connection *connection,
+ struct drbd_device *device)
{
struct nlattr *nla;
nla = nla_nest_start(skb, DRBD_NLA_CFG_CONTEXT);
if (!nla)
goto nla_put_failure;
- if (vnr != VOLUME_UNSPECIFIED &&
- nla_put_u32(skb, T_ctx_volume, vnr))
- goto nla_put_failure;
- if (nla_put_string(skb, T_ctx_resource_name, tconn->name))
- goto nla_put_failure;
- if (tconn->my_addr_len &&
- nla_put(skb, T_ctx_my_addr, tconn->my_addr_len, &tconn->my_addr))
+ if (device &&
+ nla_put_u32(skb, T_ctx_volume, device->vnr))
goto nla_put_failure;
- if (tconn->peer_addr_len &&
- nla_put(skb, T_ctx_peer_addr, tconn->peer_addr_len, &tconn->peer_addr))
+ if (nla_put_string(skb, T_ctx_resource_name, resource->name))
goto nla_put_failure;
+ if (connection) {
+ if (connection->my_addr_len &&
+ nla_put(skb, T_ctx_my_addr, connection->my_addr_len, &connection->my_addr))
+ goto nla_put_failure;
+ if (connection->peer_addr_len &&
+ nla_put(skb, T_ctx_peer_addr, connection->peer_addr_len, &connection->peer_addr))
+ goto nla_put_failure;
+ }
nla_nest_end(skb, nla);
return 0;
@@ -2750,9 +2795,22 @@ nla_put_failure:
return -EMSGSIZE;
}
-int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
+/*
+ * Return the connection of @resource if @resource has exactly one connection.
+ */
+static struct drbd_connection *the_only_connection(struct drbd_resource *resource)
+{
+ struct list_head *connections = &resource->connections;
+
+ if (list_empty(connections) || connections->next->next != connections)
+ return NULL;
+ return list_first_entry(&resource->connections, struct drbd_connection, connections);
+}
+
+int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
const struct sib_info *sib)
{
+ struct drbd_resource *resource = device->resource;
struct state_info *si = NULL; /* for sizeof(si->member); */
struct nlattr *nla;
int got_ldev;
@@ -2772,27 +2830,27 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
* always in the context of the receiving process */
exclude_sensitive = sib || !capable(CAP_SYS_ADMIN);
- got_ldev = get_ldev(mdev);
+ got_ldev = get_ldev(device);
/* We need to add connection name and volume number information still.
* Minor number is in drbd_genlmsghdr. */
- if (nla_put_drbd_cfg_context(skb, mdev->tconn, mdev->vnr))
+ if (nla_put_drbd_cfg_context(skb, resource, the_only_connection(resource), device))
goto nla_put_failure;
- if (res_opts_to_skb(skb, &mdev->tconn->res_opts, exclude_sensitive))
+ if (res_opts_to_skb(skb, &device->resource->res_opts, exclude_sensitive))
goto nla_put_failure;
rcu_read_lock();
if (got_ldev) {
struct disk_conf *disk_conf;
- disk_conf = rcu_dereference(mdev->ldev->disk_conf);
+ disk_conf = rcu_dereference(device->ldev->disk_conf);
err = disk_conf_to_skb(skb, disk_conf, exclude_sensitive);
}
if (!err) {
struct net_conf *nc;
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
if (nc)
err = net_conf_to_skb(skb, nc, exclude_sensitive);
}
@@ -2804,38 +2862,38 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
if (!nla)
goto nla_put_failure;
if (nla_put_u32(skb, T_sib_reason, sib ? sib->sib_reason : SIB_GET_STATUS_REPLY) ||
- nla_put_u32(skb, T_current_state, mdev->state.i) ||
- nla_put_u64(skb, T_ed_uuid, mdev->ed_uuid) ||
- nla_put_u64(skb, T_capacity, drbd_get_capacity(mdev->this_bdev)) ||
- nla_put_u64(skb, T_send_cnt, mdev->send_cnt) ||
- nla_put_u64(skb, T_recv_cnt, mdev->recv_cnt) ||
- nla_put_u64(skb, T_read_cnt, mdev->read_cnt) ||
- nla_put_u64(skb, T_writ_cnt, mdev->writ_cnt) ||
- nla_put_u64(skb, T_al_writ_cnt, mdev->al_writ_cnt) ||
- nla_put_u64(skb, T_bm_writ_cnt, mdev->bm_writ_cnt) ||
- nla_put_u32(skb, T_ap_bio_cnt, atomic_read(&mdev->ap_bio_cnt)) ||
- nla_put_u32(skb, T_ap_pending_cnt, atomic_read(&mdev->ap_pending_cnt)) ||
- nla_put_u32(skb, T_rs_pending_cnt, atomic_read(&mdev->rs_pending_cnt)))
+ nla_put_u32(skb, T_current_state, device->state.i) ||
+ nla_put_u64(skb, T_ed_uuid, device->ed_uuid) ||
+ nla_put_u64(skb, T_capacity, drbd_get_capacity(device->this_bdev)) ||
+ nla_put_u64(skb, T_send_cnt, device->send_cnt) ||
+ nla_put_u64(skb, T_recv_cnt, device->recv_cnt) ||
+ nla_put_u64(skb, T_read_cnt, device->read_cnt) ||
+ nla_put_u64(skb, T_writ_cnt, device->writ_cnt) ||
+ nla_put_u64(skb, T_al_writ_cnt, device->al_writ_cnt) ||
+ nla_put_u64(skb, T_bm_writ_cnt, device->bm_writ_cnt) ||
+ nla_put_u32(skb, T_ap_bio_cnt, atomic_read(&device->ap_bio_cnt)) ||
+ nla_put_u32(skb, T_ap_pending_cnt, atomic_read(&device->ap_pending_cnt)) ||
+ nla_put_u32(skb, T_rs_pending_cnt, atomic_read(&device->rs_pending_cnt)))
goto nla_put_failure;
if (got_ldev) {
int err;
- spin_lock_irq(&mdev->ldev->md.uuid_lock);
- err = nla_put(skb, T_uuids, sizeof(si->uuids), mdev->ldev->md.uuid);
- spin_unlock_irq(&mdev->ldev->md.uuid_lock);
+ spin_lock_irq(&device->ldev->md.uuid_lock);
+ err = nla_put(skb, T_uuids, sizeof(si->uuids), device->ldev->md.uuid);
+ spin_unlock_irq(&device->ldev->md.uuid_lock);
if (err)
goto nla_put_failure;
- if (nla_put_u32(skb, T_disk_flags, mdev->ldev->md.flags) ||
- nla_put_u64(skb, T_bits_total, drbd_bm_bits(mdev)) ||
- nla_put_u64(skb, T_bits_oos, drbd_bm_total_weight(mdev)))
+ if (nla_put_u32(skb, T_disk_flags, device->ldev->md.flags) ||
+ nla_put_u64(skb, T_bits_total, drbd_bm_bits(device)) ||
+ nla_put_u64(skb, T_bits_oos, drbd_bm_total_weight(device)))
goto nla_put_failure;
- if (C_SYNC_SOURCE <= mdev->state.conn &&
- C_PAUSED_SYNC_T >= mdev->state.conn) {
- if (nla_put_u64(skb, T_bits_rs_total, mdev->rs_total) ||
- nla_put_u64(skb, T_bits_rs_failed, mdev->rs_failed))
+ if (C_SYNC_SOURCE <= device->state.conn &&
+ C_PAUSED_SYNC_T >= device->state.conn) {
+ if (nla_put_u64(skb, T_bits_rs_total, device->rs_total) ||
+ nla_put_u64(skb, T_bits_rs_failed, device->rs_failed))
goto nla_put_failure;
}
}
@@ -2867,7 +2925,7 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
nla_put_failure:
err = -EMSGSIZE;
if (got_ldev)
- put_ldev(mdev);
+ put_ldev(device);
return err;
}
@@ -2882,7 +2940,7 @@ int drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- err = nla_put_status_info(adm_ctx.reply_skb, adm_ctx.mdev, NULL);
+ err = nla_put_status_info(adm_ctx.reply_skb, adm_ctx.device, NULL);
if (err) {
nlmsg_free(adm_ctx.reply_skb);
return err;
@@ -2892,22 +2950,23 @@ out:
return 0;
}
-int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
+static int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
{
- struct drbd_conf *mdev;
+ struct drbd_device *device;
struct drbd_genlmsghdr *dh;
- struct drbd_tconn *pos = (struct drbd_tconn*)cb->args[0];
- struct drbd_tconn *tconn = NULL;
- struct drbd_tconn *tmp;
+ struct drbd_resource *pos = (struct drbd_resource *)cb->args[0];
+ struct drbd_resource *resource = NULL;
+ struct drbd_resource *tmp;
unsigned volume = cb->args[1];
/* Open coded, deferred, iteration:
- * list_for_each_entry_safe(tconn, tmp, &drbd_tconns, all_tconn) {
- * idr_for_each_entry(&tconn->volumes, mdev, i) {
+ * for_each_resource_safe(resource, tmp, &drbd_resources) {
+ * connection = "first connection of resource or undefined";
+ * idr_for_each_entry(&resource->devices, device, i) {
* ...
* }
* }
- * where tconn is cb->args[0];
+ * where resource is cb->args[0];
* and i is cb->args[1];
*
* cb->args[2] indicates if we shall loop over all resources,
@@ -2916,44 +2975,44 @@ int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
* This may miss entries inserted after this dump started,
* or entries deleted before they are reached.
*
- * We need to make sure the mdev won't disappear while
+ * We need to make sure the device won't disappear while
* we are looking at it, and revalidate our iterators
* on each iteration.
*/
- /* synchronize with conn_create()/conn_destroy() */
+ /* synchronize with conn_create()/drbd_destroy_connection() */
rcu_read_lock();
/* revalidate iterator position */
- list_for_each_entry_rcu(tmp, &drbd_tconns, all_tconn) {
+ for_each_resource_rcu(tmp, &drbd_resources) {
if (pos == NULL) {
/* first iteration */
pos = tmp;
- tconn = pos;
+ resource = pos;
break;
}
if (tmp == pos) {
- tconn = pos;
+ resource = pos;
break;
}
}
- if (tconn) {
-next_tconn:
- mdev = idr_get_next(&tconn->volumes, &volume);
- if (!mdev) {
- /* No more volumes to dump on this tconn.
- * Advance tconn iterator. */
- pos = list_entry_rcu(tconn->all_tconn.next,
- struct drbd_tconn, all_tconn);
- /* Did we dump any volume on this tconn yet? */
+ if (resource) {
+next_resource:
+ device = idr_get_next(&resource->devices, &volume);
+ if (!device) {
+ /* No more volumes to dump on this resource.
+ * Advance resource iterator. */
+ pos = list_entry_rcu(resource->resources.next,
+ struct drbd_resource, resources);
+ /* Did we dump any volume of this resource yet? */
if (volume != 0) {
/* If we reached the end of the list,
* or only a single resource dump was requested,
* we are done. */
- if (&pos->all_tconn == &drbd_tconns || cb->args[2])
+ if (&pos->resources == &drbd_resources || cb->args[2])
goto out;
volume = 0;
- tconn = pos;
- goto next_tconn;
+ resource = pos;
+ goto next_resource;
}
}
@@ -2963,43 +3022,49 @@ next_tconn:
if (!dh)
goto out;
- if (!mdev) {
- /* This is a tconn without a single volume.
+ if (!device) {
+ /* This is a connection without a single volume.
* Suprisingly enough, it may have a network
* configuration. */
- struct net_conf *nc;
+ struct drbd_connection *connection;
+
dh->minor = -1U;
dh->ret_code = NO_ERROR;
- if (nla_put_drbd_cfg_context(skb, tconn, VOLUME_UNSPECIFIED))
- goto cancel;
- nc = rcu_dereference(tconn->net_conf);
- if (nc && net_conf_to_skb(skb, nc, 1) != 0)
+ connection = the_only_connection(resource);
+ if (nla_put_drbd_cfg_context(skb, resource, connection, NULL))
goto cancel;
+ if (connection) {
+ struct net_conf *nc;
+
+ nc = rcu_dereference(connection->net_conf);
+ if (nc && net_conf_to_skb(skb, nc, 1) != 0)
+ goto cancel;
+ }
goto done;
}
- D_ASSERT(mdev->vnr == volume);
- D_ASSERT(mdev->tconn == tconn);
+ D_ASSERT(device, device->vnr == volume);
+ D_ASSERT(device, device->resource == resource);
- dh->minor = mdev_to_minor(mdev);
+ dh->minor = device_to_minor(device);
dh->ret_code = NO_ERROR;
- if (nla_put_status_info(skb, mdev, NULL)) {
+ if (nla_put_status_info(skb, device, NULL)) {
cancel:
genlmsg_cancel(skb, dh);
goto out;
}
done:
genlmsg_end(skb, dh);
- }
+ }
out:
rcu_read_unlock();
/* where to start the next iteration */
- cb->args[0] = (long)pos;
- cb->args[1] = (pos == tconn) ? volume + 1 : 0;
+ cb->args[0] = (long)pos;
+ cb->args[1] = (pos == resource) ? volume + 1 : 0;
- /* No more tconns/volumes/minors found results in an empty skb.
+ /* No more resources/volumes/minors found results in an empty skb.
* Which will terminate the dump. */
return skb->len;
}
@@ -3019,7 +3084,7 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
const unsigned hdrlen = GENL_HDRLEN + GENL_MAGIC_FAMILY_HDRSZ;
struct nlattr *nla;
const char *resource_name;
- struct drbd_tconn *tconn;
+ struct drbd_resource *resource;
int maxtype;
/* Is this a followup call? */
@@ -3048,18 +3113,19 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
if (!nla)
return -EINVAL;
resource_name = nla_data(nla);
- tconn = conn_get_by_name(resource_name);
-
- if (!tconn)
+ if (!*resource_name)
+ return -ENODEV;
+ resource = drbd_find_resource(resource_name);
+ if (!resource)
return -ENODEV;
- kref_put(&tconn->kref, &conn_destroy); /* get_one_status() (re)validates tconn by itself */
+ kref_put(&resource->kref, drbd_destroy_resource); /* get_one_status() revalidates the resource */
/* prime iterators, and set "filter" mode mark:
- * only dump this tconn. */
- cb->args[0] = (long)tconn;
+ * only dump this connection. */
+ cb->args[0] = (long)resource;
/* cb->args[1] = 0; passed in this way. */
- cb->args[2] = (long)tconn;
+ cb->args[2] = (long)resource;
dump:
return get_one_status(skb, cb);
@@ -3078,8 +3144,8 @@ int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info)
goto out;
tp.timeout_type =
- adm_ctx.mdev->state.pdsk == D_OUTDATED ? UT_PEER_OUTDATED :
- test_bit(USE_DEGR_WFC_T, &adm_ctx.mdev->flags) ? UT_DEGRADED :
+ adm_ctx.device->state.pdsk == D_OUTDATED ? UT_PEER_OUTDATED :
+ test_bit(USE_DEGR_WFC_T, &adm_ctx.device->flags) ? UT_DEGRADED :
UT_DEFAULT;
err = timeout_parms_to_priv_skb(adm_ctx.reply_skb, &tp);
@@ -3094,7 +3160,7 @@ out:
int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
+ struct drbd_device *device;
enum drbd_ret_code retcode;
struct start_ov_parms parms;
@@ -3104,10 +3170,10 @@ int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- mdev = adm_ctx.mdev;
+ device = adm_ctx.device;
/* resume from last known position, if possible */
- parms.ov_start_sector = mdev->ov_start_sector;
+ parms.ov_start_sector = device->ov_start_sector;
parms.ov_stop_sector = ULLONG_MAX;
if (info->attrs[DRBD_NLA_START_OV_PARMS]) {
int err = start_ov_parms_from_attrs(&parms, info);
@@ -3118,15 +3184,15 @@ int drbd_adm_start_ov(struct sk_buff *skb, struct genl_info *info)
}
}
/* w_make_ov_request expects position to be aligned */
- mdev->ov_start_sector = parms.ov_start_sector & ~(BM_SECT_PER_BIT-1);
- mdev->ov_stop_sector = parms.ov_stop_sector;
+ device->ov_start_sector = parms.ov_start_sector & ~(BM_SECT_PER_BIT-1);
+ device->ov_stop_sector = parms.ov_stop_sector;
/* If there is still bitmap IO pending, e.g. previous resync or verify
* just being finished, wait for it before requesting a new resync. */
- drbd_suspend_io(mdev);
- wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
- retcode = drbd_request_state(mdev,NS(conn,C_VERIFY_S));
- drbd_resume_io(mdev);
+ drbd_suspend_io(device);
+ wait_event(device->misc_wait, !test_bit(BITMAP_IO, &device->flags));
+ retcode = drbd_request_state(device, NS(conn, C_VERIFY_S));
+ drbd_resume_io(device);
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -3135,7 +3201,7 @@ out:
int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
+ struct drbd_device *device;
enum drbd_ret_code retcode;
int skip_initial_sync = 0;
int err;
@@ -3147,7 +3213,7 @@ int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out_nolock;
- mdev = adm_ctx.mdev;
+ device = adm_ctx.device;
memset(&args, 0, sizeof(args));
if (info->attrs[DRBD_NLA_NEW_C_UUID_PARMS]) {
err = new_c_uuid_parms_from_attrs(&args, info);
@@ -3158,49 +3224,50 @@ int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info)
}
}
- mutex_lock(mdev->state_mutex); /* Protects us against serialized state changes. */
+ mutex_lock(device->state_mutex); /* Protects us against serialized state changes. */
- if (!get_ldev(mdev)) {
+ if (!get_ldev(device)) {
retcode = ERR_NO_DISK;
goto out;
}
/* this is "skip initial sync", assume to be clean */
- if (mdev->state.conn == C_CONNECTED && mdev->tconn->agreed_pro_version >= 90 &&
- mdev->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED && args.clear_bm) {
- dev_info(DEV, "Preparing to skip initial sync\n");
+ if (device->state.conn == C_CONNECTED &&
+ first_peer_device(device)->connection->agreed_pro_version >= 90 &&
+ device->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED && args.clear_bm) {
+ drbd_info(device, "Preparing to skip initial sync\n");
skip_initial_sync = 1;
- } else if (mdev->state.conn != C_STANDALONE) {
+ } else if (device->state.conn != C_STANDALONE) {
retcode = ERR_CONNECTED;
goto out_dec;
}
- drbd_uuid_set(mdev, UI_BITMAP, 0); /* Rotate UI_BITMAP to History 1, etc... */
- drbd_uuid_new_current(mdev); /* New current, previous to UI_BITMAP */
+ drbd_uuid_set(device, UI_BITMAP, 0); /* Rotate UI_BITMAP to History 1, etc... */
+ drbd_uuid_new_current(device); /* New current, previous to UI_BITMAP */
if (args.clear_bm) {
- err = drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write,
+ err = drbd_bitmap_io(device, &drbd_bmio_clear_n_write,
"clear_n_write from new_c_uuid", BM_LOCKED_MASK);
if (err) {
- dev_err(DEV, "Writing bitmap failed with %d\n",err);
+ drbd_err(device, "Writing bitmap failed with %d\n", err);
retcode = ERR_IO_MD_DISK;
}
if (skip_initial_sync) {
- drbd_send_uuids_skip_initial_sync(mdev);
- _drbd_uuid_set(mdev, UI_BITMAP, 0);
- drbd_print_uuids(mdev, "cleared bitmap UUID");
- spin_lock_irq(&mdev->tconn->req_lock);
- _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
+ drbd_send_uuids_skip_initial_sync(first_peer_device(device));
+ _drbd_uuid_set(device, UI_BITMAP, 0);
+ drbd_print_uuids(device, "cleared bitmap UUID");
+ spin_lock_irq(&device->resource->req_lock);
+ _drbd_set_state(_NS2(device, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
CS_VERBOSE, NULL);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
}
}
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
out_dec:
- put_ldev(mdev);
+ put_ldev(device);
out:
- mutex_unlock(mdev->state_mutex);
+ mutex_unlock(device->state_mutex);
out_nolock:
drbd_adm_finish(info, retcode);
return 0;
@@ -3246,7 +3313,7 @@ int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- if (adm_ctx.tconn) {
+ if (adm_ctx.resource) {
if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) {
retcode = ERR_INVALID_REQUEST;
drbd_msg_put_info("resource exists");
@@ -3262,7 +3329,7 @@ out:
return 0;
}
-int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info)
+int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info)
{
struct drbd_genlmsghdr *dh = info->userhdr;
enum drbd_ret_code retcode;
@@ -3285,41 +3352,36 @@ int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info)
}
/* drbd_adm_prepare made sure already
- * that mdev->tconn and mdev->vnr match the request. */
- if (adm_ctx.mdev) {
+ * that first_peer_device(device)->connection and device->vnr match the request. */
+ if (adm_ctx.device) {
if (info->nlhdr->nlmsg_flags & NLM_F_EXCL)
retcode = ERR_MINOR_EXISTS;
/* else: still NO_ERROR */
goto out;
}
- retcode = conn_new_minor(adm_ctx.tconn, dh->minor, adm_ctx.volume);
+ retcode = drbd_create_device(adm_ctx.resource, dh->minor, adm_ctx.volume);
out:
drbd_adm_finish(info, retcode);
return 0;
}
-static enum drbd_ret_code adm_delete_minor(struct drbd_conf *mdev)
+static enum drbd_ret_code adm_del_minor(struct drbd_device *device)
{
- if (mdev->state.disk == D_DISKLESS &&
- /* no need to be mdev->state.conn == C_STANDALONE &&
+ if (device->state.disk == D_DISKLESS &&
+ /* no need to be device->state.conn == C_STANDALONE &&
* we may want to delete a minor from a live replication group.
*/
- mdev->state.role == R_SECONDARY) {
- _drbd_request_state(mdev, NS(conn, C_WF_REPORT_PARAMS),
+ device->state.role == R_SECONDARY) {
+ _drbd_request_state(device, NS(conn, C_WF_REPORT_PARAMS),
CS_VERBOSE + CS_WAIT_COMPLETE);
- idr_remove(&mdev->tconn->volumes, mdev->vnr);
- idr_remove(&minors, mdev_to_minor(mdev));
- destroy_workqueue(mdev->submit.wq);
- del_gendisk(mdev->vdisk);
- synchronize_rcu();
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ drbd_delete_device(device);
return NO_ERROR;
} else
return ERR_MINOR_CONFIGURED;
}
-int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info)
+int drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info)
{
enum drbd_ret_code retcode;
@@ -3329,7 +3391,7 @@ int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- retcode = adm_delete_minor(adm_ctx.mdev);
+ retcode = adm_del_minor(adm_ctx.device);
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -3337,55 +3399,58 @@ out:
int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
{
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
+ struct drbd_device *device;
int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
- struct drbd_conf *mdev;
unsigned i;
- retcode = drbd_adm_prepare(skb, info, 0);
+ retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
if (!adm_ctx.reply_skb)
return retcode;
if (retcode != NO_ERROR)
goto out;
- if (!adm_ctx.tconn) {
- retcode = ERR_RES_NOT_KNOWN;
- goto out;
- }
-
+ resource = adm_ctx.resource;
/* demote */
- idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
- retcode = drbd_set_role(mdev, R_SECONDARY, 0);
+ for_each_connection(connection, resource) {
+ struct drbd_peer_device *peer_device;
+
+ idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+ retcode = drbd_set_role(peer_device->device, R_SECONDARY, 0);
+ if (retcode < SS_SUCCESS) {
+ drbd_msg_put_info("failed to demote");
+ goto out;
+ }
+ }
+
+ retcode = conn_try_disconnect(connection, 0);
if (retcode < SS_SUCCESS) {
- drbd_msg_put_info("failed to demote");
+ drbd_msg_put_info("failed to disconnect");
goto out;
}
}
- retcode = conn_try_disconnect(adm_ctx.tconn, 0);
- if (retcode < SS_SUCCESS) {
- drbd_msg_put_info("failed to disconnect");
- goto out;
- }
-
/* detach */
- idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
- retcode = adm_detach(mdev, 0);
+ idr_for_each_entry(&resource->devices, device, i) {
+ retcode = adm_detach(device, 0);
if (retcode < SS_SUCCESS || retcode > NO_ERROR) {
drbd_msg_put_info("failed to detach");
goto out;
}
}
- /* If we reach this, all volumes (of this tconn) are Secondary,
+ /* If we reach this, all volumes (of this connection) are Secondary,
* Disconnected, Diskless, aka Unconfigured. Make sure all threads have
* actually stopped, state handling only does drbd_thread_stop_nowait(). */
- drbd_thread_stop(&adm_ctx.tconn->worker);
+ for_each_connection(connection, resource)
+ drbd_thread_stop(&connection->worker);
/* Now, nothing can fail anymore */
/* delete volumes */
- idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
- retcode = adm_delete_minor(mdev);
+ idr_for_each_entry(&resource->devices, device, i) {
+ retcode = adm_del_minor(device);
if (retcode != NO_ERROR) {
/* "can not happen" */
drbd_msg_put_info("failed to delete volume");
@@ -3393,19 +3458,11 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
}
}
- /* delete connection */
- if (conn_lowest_minor(adm_ctx.tconn) < 0) {
- list_del_rcu(&adm_ctx.tconn->all_tconn);
- synchronize_rcu();
- kref_put(&adm_ctx.tconn->kref, &conn_destroy);
+ list_del_rcu(&resource->resources);
+ synchronize_rcu();
+ drbd_free_resource(resource);
+ retcode = NO_ERROR;
- retcode = NO_ERROR;
- } else {
- /* "can not happen" */
- retcode = ERR_RES_IN_USE;
- drbd_msg_put_info("failed to delete connection");
- }
- goto out;
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -3413,6 +3470,8 @@ out:
int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info)
{
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
enum drbd_ret_code retcode;
retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
@@ -3421,24 +3480,30 @@ int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- if (conn_lowest_minor(adm_ctx.tconn) < 0) {
- list_del_rcu(&adm_ctx.tconn->all_tconn);
- synchronize_rcu();
- kref_put(&adm_ctx.tconn->kref, &conn_destroy);
-
- retcode = NO_ERROR;
- } else {
+ resource = adm_ctx.resource;
+ for_each_connection(connection, resource) {
+ if (connection->cstate > C_STANDALONE) {
+ retcode = ERR_NET_CONFIGURED;
+ goto out;
+ }
+ }
+ if (!idr_is_empty(&resource->devices)) {
retcode = ERR_RES_IN_USE;
+ goto out;
}
- if (retcode == NO_ERROR)
- drbd_thread_stop(&adm_ctx.tconn->worker);
+ list_del_rcu(&resource->resources);
+ for_each_connection(connection, resource)
+ drbd_thread_stop(&connection->worker);
+ synchronize_rcu();
+ drbd_free_resource(resource);
+ retcode = NO_ERROR;
out:
drbd_adm_finish(info, retcode);
return 0;
}
-void drbd_bcast_event(struct drbd_conf *mdev, const struct sib_info *sib)
+void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib)
{
static atomic_t drbd_genl_seq = ATOMIC_INIT(2); /* two. */
struct sk_buff *msg;
@@ -3447,8 +3512,8 @@ void drbd_bcast_event(struct drbd_conf *mdev, const struct sib_info *sib)
int err = -ENOMEM;
if (sib->sib_reason == SIB_SYNC_PROGRESS) {
- if (time_after(jiffies, mdev->rs_last_bcast + HZ))
- mdev->rs_last_bcast = jiffies;
+ if (time_after(jiffies, device->rs_last_bcast + HZ))
+ device->rs_last_bcast = jiffies;
else
return;
}
@@ -3462,10 +3527,10 @@ void drbd_bcast_event(struct drbd_conf *mdev, const struct sib_info *sib)
d_out = genlmsg_put(msg, 0, seq, &drbd_genl_family, 0, DRBD_EVENT);
if (!d_out) /* cannot happen, but anyways. */
goto nla_put_failure;
- d_out->minor = mdev_to_minor(mdev);
+ d_out->minor = device_to_minor(device);
d_out->ret_code = NO_ERROR;
- if (nla_put_status_info(msg, mdev, sib))
+ if (nla_put_status_info(msg, device, sib))
goto nla_put_failure;
genlmsg_end(msg, d_out);
err = drbd_genl_multicast_events(msg, 0);
@@ -3478,7 +3543,7 @@ void drbd_bcast_event(struct drbd_conf *mdev, const struct sib_info *sib)
nla_put_failure:
nlmsg_free(msg);
failed:
- dev_err(DEV, "Error %d while broadcasting event. "
+ drbd_err(device, "Error %d while broadcasting event. "
"Event seq:%u sib_reason:%u\n",
err, seq, sib->sib_reason);
}
diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c
index bf31d41dbaad..2f26e8ffa45b 100644
--- a/drivers/block/drbd/drbd_proc.c
+++ b/drivers/block/drbd/drbd_proc.c
@@ -46,7 +46,7 @@ const struct file_operations drbd_proc_fops = {
.release = drbd_proc_release,
};
-void seq_printf_with_thousands_grouping(struct seq_file *seq, long v)
+static void seq_printf_with_thousands_grouping(struct seq_file *seq, long v)
{
/* v is in kB/sec. We don't expect TiByte/sec yet. */
if (unlikely(v >= 1000000)) {
@@ -66,14 +66,14 @@ void seq_printf_with_thousands_grouping(struct seq_file *seq, long v)
* [=====>..............] 33.5% (23456/123456)
* finish: 2:20:20 speed: 6,345 (6,456) K/sec
*/
-static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
+static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *seq)
{
unsigned long db, dt, dbdt, rt, rs_left;
unsigned int res;
int i, x, y;
int stalled = 0;
- drbd_get_syncer_progress(mdev, &rs_left, &res);
+ drbd_get_syncer_progress(device, &rs_left, &res);
x = res/50;
y = 20-x;
@@ -85,21 +85,21 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
seq_printf(seq, ".");
seq_printf(seq, "] ");
- if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
+ if (device->state.conn == C_VERIFY_S || device->state.conn == C_VERIFY_T)
seq_printf(seq, "verified:");
else
seq_printf(seq, "sync'ed:");
seq_printf(seq, "%3u.%u%% ", res / 10, res % 10);
/* if more than a few GB, display in MB */
- if (mdev->rs_total > (4UL << (30 - BM_BLOCK_SHIFT)))
+ if (device->rs_total > (4UL << (30 - BM_BLOCK_SHIFT)))
seq_printf(seq, "(%lu/%lu)M",
(unsigned long) Bit2KB(rs_left >> 10),
- (unsigned long) Bit2KB(mdev->rs_total >> 10));
+ (unsigned long) Bit2KB(device->rs_total >> 10));
else
seq_printf(seq, "(%lu/%lu)K\n\t",
(unsigned long) Bit2KB(rs_left),
- (unsigned long) Bit2KB(mdev->rs_total));
+ (unsigned long) Bit2KB(device->rs_total));
/* see drivers/md/md.c
* We do not want to overflow, so the order of operands and
@@ -114,14 +114,14 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
* at least (DRBD_SYNC_MARKS-2)*DRBD_SYNC_MARK_STEP old, and has at
* least DRBD_SYNC_MARK_STEP time before it will be modified. */
/* ------------------------ ~18s average ------------------------ */
- i = (mdev->rs_last_mark + 2) % DRBD_SYNC_MARKS;
- dt = (jiffies - mdev->rs_mark_time[i]) / HZ;
+ i = (device->rs_last_mark + 2) % DRBD_SYNC_MARKS;
+ dt = (jiffies - device->rs_mark_time[i]) / HZ;
if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS))
stalled = 1;
if (!dt)
dt++;
- db = mdev->rs_mark_left[i] - rs_left;
+ db = device->rs_mark_left[i] - rs_left;
rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */
seq_printf(seq, "finish: %lu:%02lu:%02lu",
@@ -134,11 +134,11 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
/* ------------------------- ~3s average ------------------------ */
if (proc_details >= 1) {
/* this is what drbd_rs_should_slow_down() uses */
- i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS;
- dt = (jiffies - mdev->rs_mark_time[i]) / HZ;
+ i = (device->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS;
+ dt = (jiffies - device->rs_mark_time[i]) / HZ;
if (!dt)
dt++;
- db = mdev->rs_mark_left[i] - rs_left;
+ db = device->rs_mark_left[i] - rs_left;
dbdt = Bit2KB(db/dt);
seq_printf_with_thousands_grouping(seq, dbdt);
seq_printf(seq, " -- ");
@@ -147,34 +147,34 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
/* --------------------- long term average ---------------------- */
/* mean speed since syncer started
* we do account for PausedSync periods */
- dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
+ dt = (jiffies - device->rs_start - device->rs_paused) / HZ;
if (dt == 0)
dt = 1;
- db = mdev->rs_total - rs_left;
+ db = device->rs_total - rs_left;
dbdt = Bit2KB(db/dt);
seq_printf_with_thousands_grouping(seq, dbdt);
seq_printf(seq, ")");
- if (mdev->state.conn == C_SYNC_TARGET ||
- mdev->state.conn == C_VERIFY_S) {
+ if (device->state.conn == C_SYNC_TARGET ||
+ device->state.conn == C_VERIFY_S) {
seq_printf(seq, " want: ");
- seq_printf_with_thousands_grouping(seq, mdev->c_sync_rate);
+ seq_printf_with_thousands_grouping(seq, device->c_sync_rate);
}
seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : "");
if (proc_details >= 1) {
/* 64 bit:
* we convert to sectors in the display below. */
- unsigned long bm_bits = drbd_bm_bits(mdev);
+ unsigned long bm_bits = drbd_bm_bits(device);
unsigned long bit_pos;
unsigned long long stop_sector = 0;
- if (mdev->state.conn == C_VERIFY_S ||
- mdev->state.conn == C_VERIFY_T) {
- bit_pos = bm_bits - mdev->ov_left;
- if (verify_can_do_stop_sector(mdev))
- stop_sector = mdev->ov_stop_sector;
+ if (device->state.conn == C_VERIFY_S ||
+ device->state.conn == C_VERIFY_T) {
+ bit_pos = bm_bits - device->ov_left;
+ if (verify_can_do_stop_sector(device))
+ stop_sector = device->ov_stop_sector;
} else
- bit_pos = mdev->bm_resync_fo;
+ bit_pos = device->bm_resync_fo;
/* Total sectors may be slightly off for oddly
* sized devices. So what. */
seq_printf(seq,
@@ -202,7 +202,7 @@ static int drbd_seq_show(struct seq_file *seq, void *v)
{
int i, prev_i = -1;
const char *sn;
- struct drbd_conf *mdev;
+ struct drbd_device *device;
struct net_conf *nc;
char wp;
@@ -236,72 +236,72 @@ static int drbd_seq_show(struct seq_file *seq, void *v)
*/
rcu_read_lock();
- idr_for_each_entry(&minors, mdev, i) {
+ idr_for_each_entry(&drbd_devices, device, i) {
if (prev_i != i - 1)
seq_printf(seq, "\n");
prev_i = i;
- sn = drbd_conn_str(mdev->state.conn);
+ sn = drbd_conn_str(device->state.conn);
- if (mdev->state.conn == C_STANDALONE &&
- mdev->state.disk == D_DISKLESS &&
- mdev->state.role == R_SECONDARY) {
+ if (device->state.conn == C_STANDALONE &&
+ device->state.disk == D_DISKLESS &&
+ device->state.role == R_SECONDARY) {
seq_printf(seq, "%2d: cs:Unconfigured\n", i);
} else {
- /* reset mdev->congestion_reason */
- bdi_rw_congested(&mdev->rq_queue->backing_dev_info);
+ /* reset device->congestion_reason */
+ bdi_rw_congested(&device->rq_queue->backing_dev_info);
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
wp = nc ? nc->wire_protocol - DRBD_PROT_A + 'A' : ' ';
seq_printf(seq,
"%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c%c\n"
" ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
"lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
i, sn,
- drbd_role_str(mdev->state.role),
- drbd_role_str(mdev->state.peer),
- drbd_disk_str(mdev->state.disk),
- drbd_disk_str(mdev->state.pdsk),
+ drbd_role_str(device->state.role),
+ drbd_role_str(device->state.peer),
+ drbd_disk_str(device->state.disk),
+ drbd_disk_str(device->state.pdsk),
wp,
- drbd_suspended(mdev) ? 's' : 'r',
- mdev->state.aftr_isp ? 'a' : '-',
- mdev->state.peer_isp ? 'p' : '-',
- mdev->state.user_isp ? 'u' : '-',
- mdev->congestion_reason ?: '-',
- test_bit(AL_SUSPENDED, &mdev->flags) ? 's' : '-',
- mdev->send_cnt/2,
- mdev->recv_cnt/2,
- mdev->writ_cnt/2,
- mdev->read_cnt/2,
- mdev->al_writ_cnt,
- mdev->bm_writ_cnt,
- atomic_read(&mdev->local_cnt),
- atomic_read(&mdev->ap_pending_cnt) +
- atomic_read(&mdev->rs_pending_cnt),
- atomic_read(&mdev->unacked_cnt),
- atomic_read(&mdev->ap_bio_cnt),
- mdev->tconn->epochs,
- write_ordering_chars[mdev->tconn->write_ordering]
+ drbd_suspended(device) ? 's' : 'r',
+ device->state.aftr_isp ? 'a' : '-',
+ device->state.peer_isp ? 'p' : '-',
+ device->state.user_isp ? 'u' : '-',
+ device->congestion_reason ?: '-',
+ test_bit(AL_SUSPENDED, &device->flags) ? 's' : '-',
+ device->send_cnt/2,
+ device->recv_cnt/2,
+ device->writ_cnt/2,
+ device->read_cnt/2,
+ device->al_writ_cnt,
+ device->bm_writ_cnt,
+ atomic_read(&device->local_cnt),
+ atomic_read(&device->ap_pending_cnt) +
+ atomic_read(&device->rs_pending_cnt),
+ atomic_read(&device->unacked_cnt),
+ atomic_read(&device->ap_bio_cnt),
+ first_peer_device(device)->connection->epochs,
+ write_ordering_chars[first_peer_device(device)->connection->write_ordering]
);
seq_printf(seq, " oos:%llu\n",
Bit2KB((unsigned long long)
- drbd_bm_total_weight(mdev)));
+ drbd_bm_total_weight(device)));
}
- if (mdev->state.conn == C_SYNC_SOURCE ||
- mdev->state.conn == C_SYNC_TARGET ||
- mdev->state.conn == C_VERIFY_S ||
- mdev->state.conn == C_VERIFY_T)
- drbd_syncer_progress(mdev, seq);
-
- if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) {
- lc_seq_printf_stats(seq, mdev->resync);
- lc_seq_printf_stats(seq, mdev->act_log);
- put_ldev(mdev);
+ if (device->state.conn == C_SYNC_SOURCE ||
+ device->state.conn == C_SYNC_TARGET ||
+ device->state.conn == C_VERIFY_S ||
+ device->state.conn == C_VERIFY_T)
+ drbd_syncer_progress(device, seq);
+
+ if (proc_details >= 1 && get_ldev_if_state(device, D_FAILED)) {
+ lc_seq_printf_stats(seq, device->resync);
+ lc_seq_printf_stats(seq, device->act_log);
+ put_ldev(device);
}
if (proc_details >= 2) {
- if (mdev->resync) {
- lc_seq_dump_details(seq, mdev->resync, "rs_left",
+ if (device->resync) {
+ lc_seq_dump_details(seq, device->resync, "rs_left",
resync_dump_detail);
}
}
diff --git a/drivers/block/drbd/drbd_protocol.h b/drivers/block/drbd/drbd_protocol.h
new file mode 100644
index 000000000000..3c04ec0ea333
--- /dev/null
+++ b/drivers/block/drbd/drbd_protocol.h
@@ -0,0 +1,295 @@
+#ifndef __DRBD_PROTOCOL_H
+#define __DRBD_PROTOCOL_H
+
+enum drbd_packet {
+ /* receiver (data socket) */
+ P_DATA = 0x00,
+ P_DATA_REPLY = 0x01, /* Response to P_DATA_REQUEST */
+ P_RS_DATA_REPLY = 0x02, /* Response to P_RS_DATA_REQUEST */
+ P_BARRIER = 0x03,
+ P_BITMAP = 0x04,
+ P_BECOME_SYNC_TARGET = 0x05,
+ P_BECOME_SYNC_SOURCE = 0x06,
+ P_UNPLUG_REMOTE = 0x07, /* Used at various times to hint the peer */
+ P_DATA_REQUEST = 0x08, /* Used to ask for a data block */
+ P_RS_DATA_REQUEST = 0x09, /* Used to ask for a data block for resync */
+ P_SYNC_PARAM = 0x0a,
+ P_PROTOCOL = 0x0b,
+ P_UUIDS = 0x0c,
+ P_SIZES = 0x0d,
+ P_STATE = 0x0e,
+ P_SYNC_UUID = 0x0f,
+ P_AUTH_CHALLENGE = 0x10,
+ P_AUTH_RESPONSE = 0x11,
+ P_STATE_CHG_REQ = 0x12,
+
+ /* asender (meta socket */
+ P_PING = 0x13,
+ P_PING_ACK = 0x14,
+ P_RECV_ACK = 0x15, /* Used in protocol B */
+ P_WRITE_ACK = 0x16, /* Used in protocol C */
+ P_RS_WRITE_ACK = 0x17, /* Is a P_WRITE_ACK, additionally call set_in_sync(). */
+ P_SUPERSEDED = 0x18, /* Used in proto C, two-primaries conflict detection */
+ P_NEG_ACK = 0x19, /* Sent if local disk is unusable */
+ P_NEG_DREPLY = 0x1a, /* Local disk is broken... */
+ P_NEG_RS_DREPLY = 0x1b, /* Local disk is broken... */
+ P_BARRIER_ACK = 0x1c,
+ P_STATE_CHG_REPLY = 0x1d,
+
+ /* "new" commands, no longer fitting into the ordering scheme above */
+
+ P_OV_REQUEST = 0x1e, /* data socket */
+ P_OV_REPLY = 0x1f,
+ P_OV_RESULT = 0x20, /* meta socket */
+ P_CSUM_RS_REQUEST = 0x21, /* data socket */
+ P_RS_IS_IN_SYNC = 0x22, /* meta socket */
+ P_SYNC_PARAM89 = 0x23, /* data socket, protocol version 89 replacement for P_SYNC_PARAM */
+ P_COMPRESSED_BITMAP = 0x24, /* compressed or otherwise encoded bitmap transfer */
+ /* P_CKPT_FENCE_REQ = 0x25, * currently reserved for protocol D */
+ /* P_CKPT_DISABLE_REQ = 0x26, * currently reserved for protocol D */
+ P_DELAY_PROBE = 0x27, /* is used on BOTH sockets */
+ P_OUT_OF_SYNC = 0x28, /* Mark as out of sync (Outrunning), data socket */
+ P_RS_CANCEL = 0x29, /* meta: Used to cancel RS_DATA_REQUEST packet by SyncSource */
+ P_CONN_ST_CHG_REQ = 0x2a, /* data sock: Connection wide state request */
+ P_CONN_ST_CHG_REPLY = 0x2b, /* meta sock: Connection side state req reply */
+ P_RETRY_WRITE = 0x2c, /* Protocol C: retry conflicting write request */
+ P_PROTOCOL_UPDATE = 0x2d, /* data sock: is used in established connections */
+
+ P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */
+ P_MAX_OPT_CMD = 0x101,
+
+ /* special command ids for handshake */
+
+ P_INITIAL_META = 0xfff1, /* First Packet on the MetaSock */
+ P_INITIAL_DATA = 0xfff2, /* First Packet on the Socket */
+
+ P_CONNECTION_FEATURES = 0xfffe /* FIXED for the next century! */
+};
+
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+/* This is the layout for a packet on the wire.
+ * The byteorder is the network byte order.
+ * (except block_id and barrier fields.
+ * these are pointers to local structs
+ * and have no relevance for the partner,
+ * which just echoes them as received.)
+ *
+ * NOTE that the payload starts at a long aligned offset,
+ * regardless of 32 or 64 bit arch!
+ */
+struct p_header80 {
+ u32 magic;
+ u16 command;
+ u16 length; /* bytes of data after this header */
+} __packed;
+
+/* Header for big packets, Used for data packets exceeding 64kB */
+struct p_header95 {
+ u16 magic; /* use DRBD_MAGIC_BIG here */
+ u16 command;
+ u32 length;
+} __packed;
+
+struct p_header100 {
+ u32 magic;
+ u16 volume;
+ u16 command;
+ u32 length;
+ u32 pad;
+} __packed;
+
+/* these defines must not be changed without changing the protocol version */
+#define DP_HARDBARRIER 1 /* depricated */
+#define DP_RW_SYNC 2 /* equals REQ_SYNC */
+#define DP_MAY_SET_IN_SYNC 4
+#define DP_UNPLUG 8 /* not used anymore */
+#define DP_FUA 16 /* equals REQ_FUA */
+#define DP_FLUSH 32 /* equals REQ_FLUSH */
+#define DP_DISCARD 64 /* equals REQ_DISCARD */
+#define DP_SEND_RECEIVE_ACK 128 /* This is a proto B write request */
+#define DP_SEND_WRITE_ACK 256 /* This is a proto C write request */
+
+struct p_data {
+ u64 sector; /* 64 bits sector number */
+ u64 block_id; /* to identify the request in protocol B&C */
+ u32 seq_num;
+ u32 dp_flags;
+} __packed;
+
+/*
+ * commands which share a struct:
+ * p_block_ack:
+ * P_RECV_ACK (proto B), P_WRITE_ACK (proto C),
+ * P_SUPERSEDED (proto C, two-primaries conflict detection)
+ * p_block_req:
+ * P_DATA_REQUEST, P_RS_DATA_REQUEST
+ */
+struct p_block_ack {
+ u64 sector;
+ u64 block_id;
+ u32 blksize;
+ u32 seq_num;
+} __packed;
+
+struct p_block_req {
+ u64 sector;
+ u64 block_id;
+ u32 blksize;
+ u32 pad; /* to multiple of 8 Byte */
+} __packed;
+
+/*
+ * commands with their own struct for additional fields:
+ * P_CONNECTION_FEATURES
+ * P_BARRIER
+ * P_BARRIER_ACK
+ * P_SYNC_PARAM
+ * ReportParams
+ */
+
+struct p_connection_features {
+ u32 protocol_min;
+ u32 feature_flags;
+ u32 protocol_max;
+
+ /* should be more than enough for future enhancements
+ * for now, feature_flags and the reserved array shall be zero.
+ */
+
+ u32 _pad;
+ u64 reserved[7];
+} __packed;
+
+struct p_barrier {
+ u32 barrier; /* barrier number _handle_ only */
+ u32 pad; /* to multiple of 8 Byte */
+} __packed;
+
+struct p_barrier_ack {
+ u32 barrier;
+ u32 set_size;
+} __packed;
+
+struct p_rs_param {
+ u32 resync_rate;
+
+ /* Since protocol version 88 and higher. */
+ char verify_alg[0];
+} __packed;
+
+struct p_rs_param_89 {
+ u32 resync_rate;
+ /* protocol version 89: */
+ char verify_alg[SHARED_SECRET_MAX];
+ char csums_alg[SHARED_SECRET_MAX];
+} __packed;
+
+struct p_rs_param_95 {
+ u32 resync_rate;
+ char verify_alg[SHARED_SECRET_MAX];
+ char csums_alg[SHARED_SECRET_MAX];
+ u32 c_plan_ahead;
+ u32 c_delay_target;
+ u32 c_fill_target;
+ u32 c_max_rate;
+} __packed;
+
+enum drbd_conn_flags {
+ CF_DISCARD_MY_DATA = 1,
+ CF_DRY_RUN = 2,
+};
+
+struct p_protocol {
+ u32 protocol;
+ u32 after_sb_0p;
+ u32 after_sb_1p;
+ u32 after_sb_2p;
+ u32 conn_flags;
+ u32 two_primaries;
+
+ /* Since protocol version 87 and higher. */
+ char integrity_alg[0];
+
+} __packed;
+
+struct p_uuids {
+ u64 uuid[UI_EXTENDED_SIZE];
+} __packed;
+
+struct p_rs_uuid {
+ u64 uuid;
+} __packed;
+
+struct p_sizes {
+ u64 d_size; /* size of disk */
+ u64 u_size; /* user requested size */
+ u64 c_size; /* current exported size */
+ u32 max_bio_size; /* Maximal size of a BIO */
+ u16 queue_order_type; /* not yet implemented in DRBD*/
+ u16 dds_flags; /* use enum dds_flags here. */
+} __packed;
+
+struct p_state {
+ u32 state;
+} __packed;
+
+struct p_req_state {
+ u32 mask;
+ u32 val;
+} __packed;
+
+struct p_req_state_reply {
+ u32 retcode;
+} __packed;
+
+struct p_drbd06_param {
+ u64 size;
+ u32 state;
+ u32 blksize;
+ u32 protocol;
+ u32 version;
+ u32 gen_cnt[5];
+ u32 bit_map_gen[5];
+} __packed;
+
+struct p_block_desc {
+ u64 sector;
+ u32 blksize;
+ u32 pad; /* to multiple of 8 Byte */
+} __packed;
+
+/* Valid values for the encoding field.
+ * Bump proto version when changing this. */
+enum drbd_bitmap_code {
+ /* RLE_VLI_Bytes = 0,
+ * and other bit variants had been defined during
+ * algorithm evaluation. */
+ RLE_VLI_Bits = 2,
+};
+
+struct p_compressed_bm {
+ /* (encoding & 0x0f): actual encoding, see enum drbd_bitmap_code
+ * (encoding & 0x80): polarity (set/unset) of first runlength
+ * ((encoding >> 4) & 0x07): pad_bits, number of trailing zero bits
+ * used to pad up to head.length bytes
+ */
+ u8 encoding;
+
+ u8 code[0];
+} __packed;
+
+struct p_delay_probe93 {
+ u32 seq_num; /* sequence number to match the two probe packets */
+ u32 offset; /* usecs the probe got sent after the reference time point */
+} __packed;
+
+/*
+ * Bitmap packets need to fit within a single page on the sender and receiver,
+ * so we are limited to 4 KiB (and not to PAGE_SIZE, which can be bigger).
+ */
+#define DRBD_SOCKET_BUFFER_SIZE 4096
+
+#endif /* __DRBD_PROTOCOL_H */
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index d073305ffd5e..18c76e84d540 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -44,6 +44,7 @@
#include <linux/string.h>
#include <linux/scatterlist.h>
#include "drbd_int.h"
+#include "drbd_protocol.h"
#include "drbd_req.h"
#include "drbd_vli.h"
@@ -61,11 +62,11 @@ enum finish_epoch {
FE_RECYCLED,
};
-static int drbd_do_features(struct drbd_tconn *tconn);
-static int drbd_do_auth(struct drbd_tconn *tconn);
-static int drbd_disconnected(struct drbd_conf *mdev);
+static int drbd_do_features(struct drbd_connection *connection);
+static int drbd_do_auth(struct drbd_connection *connection);
+static int drbd_disconnected(struct drbd_peer_device *);
-static enum finish_epoch drbd_may_finish_epoch(struct drbd_tconn *, struct drbd_epoch *, enum epoch_event);
+static enum finish_epoch drbd_may_finish_epoch(struct drbd_connection *, struct drbd_epoch *, enum epoch_event);
static int e_end_block(struct drbd_work *, int);
@@ -150,7 +151,7 @@ static void page_chain_add(struct page **head,
*head = chain_first;
}
-static struct page *__drbd_alloc_pages(struct drbd_conf *mdev,
+static struct page *__drbd_alloc_pages(struct drbd_device *device,
unsigned int number)
{
struct page *page = NULL;
@@ -196,41 +197,39 @@ static struct page *__drbd_alloc_pages(struct drbd_conf *mdev,
return NULL;
}
-static void reclaim_finished_net_peer_reqs(struct drbd_conf *mdev,
+static void reclaim_finished_net_peer_reqs(struct drbd_device *device,
struct list_head *to_be_freed)
{
- struct drbd_peer_request *peer_req;
- struct list_head *le, *tle;
+ struct drbd_peer_request *peer_req, *tmp;
/* The EEs are always appended to the end of the list. Since
they are sent in order over the wire, they have to finish
in order. As soon as we see the first not finished we can
stop to examine the list... */
- list_for_each_safe(le, tle, &mdev->net_ee) {
- peer_req = list_entry(le, struct drbd_peer_request, w.list);
+ list_for_each_entry_safe(peer_req, tmp, &device->net_ee, w.list) {
if (drbd_peer_req_has_active_page(peer_req))
break;
- list_move(le, to_be_freed);
+ list_move(&peer_req->w.list, to_be_freed);
}
}
-static void drbd_kick_lo_and_reclaim_net(struct drbd_conf *mdev)
+static void drbd_kick_lo_and_reclaim_net(struct drbd_device *device)
{
LIST_HEAD(reclaimed);
struct drbd_peer_request *peer_req, *t;
- spin_lock_irq(&mdev->tconn->req_lock);
- reclaim_finished_net_peer_reqs(mdev, &reclaimed);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ reclaim_finished_net_peer_reqs(device, &reclaimed);
+ spin_unlock_irq(&device->resource->req_lock);
list_for_each_entry_safe(peer_req, t, &reclaimed, w.list)
- drbd_free_net_peer_req(mdev, peer_req);
+ drbd_free_net_peer_req(device, peer_req);
}
/**
* drbd_alloc_pages() - Returns @number pages, retries forever (or until signalled)
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @number: number of pages requested
* @retry: whether to retry, if not enough pages are available right now
*
@@ -240,9 +239,10 @@ static void drbd_kick_lo_and_reclaim_net(struct drbd_conf *mdev)
*
* Returns a page chain linked via page->private.
*/
-struct page *drbd_alloc_pages(struct drbd_conf *mdev, unsigned int number,
+struct page *drbd_alloc_pages(struct drbd_peer_device *peer_device, unsigned int number,
bool retry)
{
+ struct drbd_device *device = peer_device->device;
struct page *page = NULL;
struct net_conf *nc;
DEFINE_WAIT(wait);
@@ -251,20 +251,20 @@ struct page *drbd_alloc_pages(struct drbd_conf *mdev, unsigned int number,
/* Yes, we may run up to @number over max_buffers. If we
* follow it strictly, the admin will get it wrong anyways. */
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(peer_device->connection->net_conf);
mxb = nc ? nc->max_buffers : 1000000;
rcu_read_unlock();
- if (atomic_read(&mdev->pp_in_use) < mxb)
- page = __drbd_alloc_pages(mdev, number);
+ if (atomic_read(&device->pp_in_use) < mxb)
+ page = __drbd_alloc_pages(device, number);
while (page == NULL) {
prepare_to_wait(&drbd_pp_wait, &wait, TASK_INTERRUPTIBLE);
- drbd_kick_lo_and_reclaim_net(mdev);
+ drbd_kick_lo_and_reclaim_net(device);
- if (atomic_read(&mdev->pp_in_use) < mxb) {
- page = __drbd_alloc_pages(mdev, number);
+ if (atomic_read(&device->pp_in_use) < mxb) {
+ page = __drbd_alloc_pages(device, number);
if (page)
break;
}
@@ -273,7 +273,7 @@ struct page *drbd_alloc_pages(struct drbd_conf *mdev, unsigned int number,
break;
if (signal_pending(current)) {
- dev_warn(DEV, "drbd_alloc_pages interrupted!\n");
+ drbd_warn(device, "drbd_alloc_pages interrupted!\n");
break;
}
@@ -282,17 +282,17 @@ struct page *drbd_alloc_pages(struct drbd_conf *mdev, unsigned int number,
finish_wait(&drbd_pp_wait, &wait);
if (page)
- atomic_add(number, &mdev->pp_in_use);
+ atomic_add(number, &device->pp_in_use);
return page;
}
/* Must not be used from irq, as that may deadlock: see drbd_alloc_pages.
- * Is also used from inside an other spin_lock_irq(&mdev->tconn->req_lock);
+ * Is also used from inside an other spin_lock_irq(&resource->req_lock);
* Either links the page chain back to the global pool,
* or returns all pages to the system. */
-static void drbd_free_pages(struct drbd_conf *mdev, struct page *page, int is_net)
+static void drbd_free_pages(struct drbd_device *device, struct page *page, int is_net)
{
- atomic_t *a = is_net ? &mdev->pp_in_use_by_net : &mdev->pp_in_use;
+ atomic_t *a = is_net ? &device->pp_in_use_by_net : &device->pp_in_use;
int i;
if (page == NULL)
@@ -310,7 +310,7 @@ static void drbd_free_pages(struct drbd_conf *mdev, struct page *page, int is_ne
}
i = atomic_sub_return(i, a);
if (i < 0)
- dev_warn(DEV, "ASSERTION FAILED: %s: %d < 0\n",
+ drbd_warn(device, "ASSERTION FAILED: %s: %d < 0\n",
is_net ? "pp_in_use_by_net" : "pp_in_use", i);
wake_up(&drbd_pp_wait);
}
@@ -330,25 +330,26 @@ You must not have the req_lock:
*/
struct drbd_peer_request *
-drbd_alloc_peer_req(struct drbd_conf *mdev, u64 id, sector_t sector,
+drbd_alloc_peer_req(struct drbd_peer_device *peer_device, u64 id, sector_t sector,
unsigned int data_size, gfp_t gfp_mask) __must_hold(local)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_peer_request *peer_req;
struct page *page = NULL;
unsigned nr_pages = (data_size + PAGE_SIZE -1) >> PAGE_SHIFT;
- if (drbd_insert_fault(mdev, DRBD_FAULT_AL_EE))
+ if (drbd_insert_fault(device, DRBD_FAULT_AL_EE))
return NULL;
peer_req = mempool_alloc(drbd_ee_mempool, gfp_mask & ~__GFP_HIGHMEM);
if (!peer_req) {
if (!(gfp_mask & __GFP_NOWARN))
- dev_err(DEV, "%s: allocation failed\n", __func__);
+ drbd_err(device, "%s: allocation failed\n", __func__);
return NULL;
}
if (data_size) {
- page = drbd_alloc_pages(mdev, nr_pages, (gfp_mask & __GFP_WAIT));
+ page = drbd_alloc_pages(peer_device, nr_pages, (gfp_mask & __GFP_WAIT));
if (!page)
goto fail;
}
@@ -360,7 +361,7 @@ drbd_alloc_peer_req(struct drbd_conf *mdev, u64 id, sector_t sector,
peer_req->i.waiting = false;
peer_req->epoch = NULL;
- peer_req->w.mdev = mdev;
+ peer_req->peer_device = peer_device;
peer_req->pages = page;
atomic_set(&peer_req->pending_bios, 0);
peer_req->flags = 0;
@@ -377,30 +378,30 @@ drbd_alloc_peer_req(struct drbd_conf *mdev, u64 id, sector_t sector,
return NULL;
}
-void __drbd_free_peer_req(struct drbd_conf *mdev, struct drbd_peer_request *peer_req,
+void __drbd_free_peer_req(struct drbd_device *device, struct drbd_peer_request *peer_req,
int is_net)
{
if (peer_req->flags & EE_HAS_DIGEST)
kfree(peer_req->digest);
- drbd_free_pages(mdev, peer_req->pages, is_net);
- D_ASSERT(atomic_read(&peer_req->pending_bios) == 0);
- D_ASSERT(drbd_interval_empty(&peer_req->i));
+ drbd_free_pages(device, peer_req->pages, is_net);
+ D_ASSERT(device, atomic_read(&peer_req->pending_bios) == 0);
+ D_ASSERT(device, drbd_interval_empty(&peer_req->i));
mempool_free(peer_req, drbd_ee_mempool);
}
-int drbd_free_peer_reqs(struct drbd_conf *mdev, struct list_head *list)
+int drbd_free_peer_reqs(struct drbd_device *device, struct list_head *list)
{
LIST_HEAD(work_list);
struct drbd_peer_request *peer_req, *t;
int count = 0;
- int is_net = list == &mdev->net_ee;
+ int is_net = list == &device->net_ee;
- spin_lock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
list_splice_init(list, &work_list);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
list_for_each_entry_safe(peer_req, t, &work_list, w.list) {
- __drbd_free_peer_req(mdev, peer_req, is_net);
+ __drbd_free_peer_req(device, peer_req, is_net);
count++;
}
return count;
@@ -409,20 +410,20 @@ int drbd_free_peer_reqs(struct drbd_conf *mdev, struct list_head *list)
/*
* See also comments in _req_mod(,BARRIER_ACKED) and receive_Barrier.
*/
-static int drbd_finish_peer_reqs(struct drbd_conf *mdev)
+static int drbd_finish_peer_reqs(struct drbd_device *device)
{
LIST_HEAD(work_list);
LIST_HEAD(reclaimed);
struct drbd_peer_request *peer_req, *t;
int err = 0;
- spin_lock_irq(&mdev->tconn->req_lock);
- reclaim_finished_net_peer_reqs(mdev, &reclaimed);
- list_splice_init(&mdev->done_ee, &work_list);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ reclaim_finished_net_peer_reqs(device, &reclaimed);
+ list_splice_init(&device->done_ee, &work_list);
+ spin_unlock_irq(&device->resource->req_lock);
list_for_each_entry_safe(peer_req, t, &reclaimed, w.list)
- drbd_free_net_peer_req(mdev, peer_req);
+ drbd_free_net_peer_req(device, peer_req);
/* possible callbacks here:
* e_end_block, and e_end_resync_block, e_send_superseded.
@@ -435,14 +436,14 @@ static int drbd_finish_peer_reqs(struct drbd_conf *mdev)
err2 = peer_req->w.cb(&peer_req->w, !!err);
if (!err)
err = err2;
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
}
- wake_up(&mdev->ee_wait);
+ wake_up(&device->ee_wait);
return err;
}
-static void _drbd_wait_ee_list_empty(struct drbd_conf *mdev,
+static void _drbd_wait_ee_list_empty(struct drbd_device *device,
struct list_head *head)
{
DEFINE_WAIT(wait);
@@ -450,20 +451,20 @@ static void _drbd_wait_ee_list_empty(struct drbd_conf *mdev,
/* avoids spin_lock/unlock
* and calling prepare_to_wait in the fast path */
while (!list_empty(head)) {
- prepare_to_wait(&mdev->ee_wait, &wait, TASK_UNINTERRUPTIBLE);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ prepare_to_wait(&device->ee_wait, &wait, TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq(&device->resource->req_lock);
io_schedule();
- finish_wait(&mdev->ee_wait, &wait);
- spin_lock_irq(&mdev->tconn->req_lock);
+ finish_wait(&device->ee_wait, &wait);
+ spin_lock_irq(&device->resource->req_lock);
}
}
-static void drbd_wait_ee_list_empty(struct drbd_conf *mdev,
+static void drbd_wait_ee_list_empty(struct drbd_device *device,
struct list_head *head)
{
- spin_lock_irq(&mdev->tconn->req_lock);
- _drbd_wait_ee_list_empty(mdev, head);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ _drbd_wait_ee_list_empty(device, head);
+ spin_unlock_irq(&device->resource->req_lock);
}
static int drbd_recv_short(struct socket *sock, void *buf, size_t size, int flags)
@@ -488,44 +489,44 @@ static int drbd_recv_short(struct socket *sock, void *buf, size_t size, int flag
return rv;
}
-static int drbd_recv(struct drbd_tconn *tconn, void *buf, size_t size)
+static int drbd_recv(struct drbd_connection *connection, void *buf, size_t size)
{
int rv;
- rv = drbd_recv_short(tconn->data.socket, buf, size, 0);
+ rv = drbd_recv_short(connection->data.socket, buf, size, 0);
if (rv < 0) {
if (rv == -ECONNRESET)
- conn_info(tconn, "sock was reset by peer\n");
+ drbd_info(connection, "sock was reset by peer\n");
else if (rv != -ERESTARTSYS)
- conn_err(tconn, "sock_recvmsg returned %d\n", rv);
+ drbd_err(connection, "sock_recvmsg returned %d\n", rv);
} else if (rv == 0) {
- if (test_bit(DISCONNECT_SENT, &tconn->flags)) {
+ if (test_bit(DISCONNECT_SENT, &connection->flags)) {
long t;
rcu_read_lock();
- t = rcu_dereference(tconn->net_conf)->ping_timeo * HZ/10;
+ t = rcu_dereference(connection->net_conf)->ping_timeo * HZ/10;
rcu_read_unlock();
- t = wait_event_timeout(tconn->ping_wait, tconn->cstate < C_WF_REPORT_PARAMS, t);
+ t = wait_event_timeout(connection->ping_wait, connection->cstate < C_WF_REPORT_PARAMS, t);
if (t)
goto out;
}
- conn_info(tconn, "sock was shut down by peer\n");
+ drbd_info(connection, "sock was shut down by peer\n");
}
if (rv != size)
- conn_request_state(tconn, NS(conn, C_BROKEN_PIPE), CS_HARD);
+ conn_request_state(connection, NS(conn, C_BROKEN_PIPE), CS_HARD);
out:
return rv;
}
-static int drbd_recv_all(struct drbd_tconn *tconn, void *buf, size_t size)
+static int drbd_recv_all(struct drbd_connection *connection, void *buf, size_t size)
{
int err;
- err = drbd_recv(tconn, buf, size);
+ err = drbd_recv(connection, buf, size);
if (err != size) {
if (err >= 0)
err = -EIO;
@@ -534,13 +535,13 @@ static int drbd_recv_all(struct drbd_tconn *tconn, void *buf, size_t size)
return err;
}
-static int drbd_recv_all_warn(struct drbd_tconn *tconn, void *buf, size_t size)
+static int drbd_recv_all_warn(struct drbd_connection *connection, void *buf, size_t size)
{
int err;
- err = drbd_recv_all(tconn, buf, size);
+ err = drbd_recv_all(connection, buf, size);
if (err && !signal_pending(current))
- conn_warn(tconn, "short read (expected size %d)\n", (int)size);
+ drbd_warn(connection, "short read (expected size %d)\n", (int)size);
return err;
}
@@ -563,7 +564,7 @@ static void drbd_setbufsize(struct socket *sock, unsigned int snd,
}
}
-static struct socket *drbd_try_connect(struct drbd_tconn *tconn)
+static struct socket *drbd_try_connect(struct drbd_connection *connection)
{
const char *what;
struct socket *sock;
@@ -575,7 +576,7 @@ static struct socket *drbd_try_connect(struct drbd_tconn *tconn)
int disconnect_on_error = 1;
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
if (!nc) {
rcu_read_unlock();
return NULL;
@@ -585,16 +586,16 @@ static struct socket *drbd_try_connect(struct drbd_tconn *tconn)
connect_int = nc->connect_int;
rcu_read_unlock();
- my_addr_len = min_t(int, tconn->my_addr_len, sizeof(src_in6));
- memcpy(&src_in6, &tconn->my_addr, my_addr_len);
+ my_addr_len = min_t(int, connection->my_addr_len, sizeof(src_in6));
+ memcpy(&src_in6, &connection->my_addr, my_addr_len);
- if (((struct sockaddr *)&tconn->my_addr)->sa_family == AF_INET6)
+ if (((struct sockaddr *)&connection->my_addr)->sa_family == AF_INET6)
src_in6.sin6_port = 0;
else
((struct sockaddr_in *)&src_in6)->sin_port = 0; /* AF_INET & AF_SCI */
- peer_addr_len = min_t(int, tconn->peer_addr_len, sizeof(src_in6));
- memcpy(&peer_in6, &tconn->peer_addr, peer_addr_len);
+ peer_addr_len = min_t(int, connection->peer_addr_len, sizeof(src_in6));
+ memcpy(&peer_in6, &connection->peer_addr, peer_addr_len);
what = "sock_create_kern";
err = sock_create_kern(((struct sockaddr *)&src_in6)->sa_family,
@@ -642,17 +643,17 @@ out:
disconnect_on_error = 0;
break;
default:
- conn_err(tconn, "%s failed, err = %d\n", what, err);
+ drbd_err(connection, "%s failed, err = %d\n", what, err);
}
if (disconnect_on_error)
- conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
}
return sock;
}
struct accept_wait_data {
- struct drbd_tconn *tconn;
+ struct drbd_connection *connection;
struct socket *s_listen;
struct completion door_bell;
void (*original_sk_state_change)(struct sock *sk);
@@ -670,7 +671,7 @@ static void drbd_incoming_connection(struct sock *sk)
state_change(sk);
}
-static int prepare_listen_socket(struct drbd_tconn *tconn, struct accept_wait_data *ad)
+static int prepare_listen_socket(struct drbd_connection *connection, struct accept_wait_data *ad)
{
int err, sndbuf_size, rcvbuf_size, my_addr_len;
struct sockaddr_in6 my_addr;
@@ -679,7 +680,7 @@ static int prepare_listen_socket(struct drbd_tconn *tconn, struct accept_wait_da
const char *what;
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
if (!nc) {
rcu_read_unlock();
return -EIO;
@@ -688,8 +689,8 @@ static int prepare_listen_socket(struct drbd_tconn *tconn, struct accept_wait_da
rcvbuf_size = nc->rcvbuf_size;
rcu_read_unlock();
- my_addr_len = min_t(int, tconn->my_addr_len, sizeof(struct sockaddr_in6));
- memcpy(&my_addr, &tconn->my_addr, my_addr_len);
+ my_addr_len = min_t(int, connection->my_addr_len, sizeof(struct sockaddr_in6));
+ memcpy(&my_addr, &connection->my_addr, my_addr_len);
what = "sock_create_kern";
err = sock_create_kern(((struct sockaddr *)&my_addr)->sa_family,
@@ -725,8 +726,8 @@ out:
sock_release(s_listen);
if (err < 0) {
if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) {
- conn_err(tconn, "%s failed, err = %d\n", what, err);
- conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ drbd_err(connection, "%s failed, err = %d\n", what, err);
+ conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
}
}
@@ -741,14 +742,14 @@ static void unregister_state_change(struct sock *sk, struct accept_wait_data *ad
write_unlock_bh(&sk->sk_callback_lock);
}
-static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct accept_wait_data *ad)
+static struct socket *drbd_wait_for_connect(struct drbd_connection *connection, struct accept_wait_data *ad)
{
int timeo, connect_int, err = 0;
struct socket *s_estab = NULL;
struct net_conf *nc;
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
if (!nc) {
rcu_read_unlock();
return NULL;
@@ -767,8 +768,8 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct acc
err = kernel_accept(ad->s_listen, &s_estab, 0);
if (err < 0) {
if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) {
- conn_err(tconn, "accept failed, err = %d\n", err);
- conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ drbd_err(connection, "accept failed, err = %d\n", err);
+ conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
}
}
@@ -778,29 +779,29 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct acc
return s_estab;
}
-static int decode_header(struct drbd_tconn *, void *, struct packet_info *);
+static int decode_header(struct drbd_connection *, void *, struct packet_info *);
-static int send_first_packet(struct drbd_tconn *tconn, struct drbd_socket *sock,
+static int send_first_packet(struct drbd_connection *connection, struct drbd_socket *sock,
enum drbd_packet cmd)
{
- if (!conn_prepare_command(tconn, sock))
+ if (!conn_prepare_command(connection, sock))
return -EIO;
- return conn_send_command(tconn, sock, cmd, 0, NULL, 0);
+ return conn_send_command(connection, sock, cmd, 0, NULL, 0);
}
-static int receive_first_packet(struct drbd_tconn *tconn, struct socket *sock)
+static int receive_first_packet(struct drbd_connection *connection, struct socket *sock)
{
- unsigned int header_size = drbd_header_size(tconn);
+ unsigned int header_size = drbd_header_size(connection);
struct packet_info pi;
int err;
- err = drbd_recv_short(sock, tconn->data.rbuf, header_size, 0);
+ err = drbd_recv_short(sock, connection->data.rbuf, header_size, 0);
if (err != header_size) {
if (err >= 0)
err = -EIO;
return err;
}
- err = decode_header(tconn, tconn->data.rbuf, &pi);
+ err = decode_header(connection, connection->data.rbuf, &pi);
if (err)
return err;
return pi.cmd;
@@ -830,28 +831,29 @@ static int drbd_socket_okay(struct socket **sock)
}
/* Gets called if a connection is established, or if a new minor gets created
in a connection */
-int drbd_connected(struct drbd_conf *mdev)
+int drbd_connected(struct drbd_peer_device *peer_device)
{
+ struct drbd_device *device = peer_device->device;
int err;
- atomic_set(&mdev->packet_seq, 0);
- mdev->peer_seq = 0;
+ atomic_set(&device->packet_seq, 0);
+ device->peer_seq = 0;
- mdev->state_mutex = mdev->tconn->agreed_pro_version < 100 ?
- &mdev->tconn->cstate_mutex :
- &mdev->own_state_mutex;
+ device->state_mutex = peer_device->connection->agreed_pro_version < 100 ?
+ &peer_device->connection->cstate_mutex :
+ &device->own_state_mutex;
- err = drbd_send_sync_param(mdev);
+ err = drbd_send_sync_param(peer_device);
if (!err)
- err = drbd_send_sizes(mdev, 0, 0);
+ err = drbd_send_sizes(peer_device, 0, 0);
if (!err)
- err = drbd_send_uuids(mdev);
+ err = drbd_send_uuids(peer_device);
if (!err)
- err = drbd_send_current_state(mdev);
- clear_bit(USE_DEGR_WFC_T, &mdev->flags);
- clear_bit(RESIZE_PENDING, &mdev->flags);
- atomic_set(&mdev->ap_in_flight, 0);
- mod_timer(&mdev->request_timer, jiffies + HZ); /* just start it here. */
+ err = drbd_send_current_state(peer_device);
+ clear_bit(USE_DEGR_WFC_T, &device->flags);
+ clear_bit(RESIZE_PENDING, &device->flags);
+ atomic_set(&device->ap_in_flight, 0);
+ mod_timer(&device->request_timer, jiffies + HZ); /* just start it here. */
return err;
}
@@ -863,59 +865,59 @@ int drbd_connected(struct drbd_conf *mdev)
* no point in trying again, please go standalone.
* -2 We do not have a network config...
*/
-static int conn_connect(struct drbd_tconn *tconn)
+static int conn_connect(struct drbd_connection *connection)
{
struct drbd_socket sock, msock;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
struct net_conf *nc;
int vnr, timeout, h, ok;
bool discard_my_data;
enum drbd_state_rv rv;
struct accept_wait_data ad = {
- .tconn = tconn,
+ .connection = connection,
.door_bell = COMPLETION_INITIALIZER_ONSTACK(ad.door_bell),
};
- clear_bit(DISCONNECT_SENT, &tconn->flags);
- if (conn_request_state(tconn, NS(conn, C_WF_CONNECTION), CS_VERBOSE) < SS_SUCCESS)
+ clear_bit(DISCONNECT_SENT, &connection->flags);
+ if (conn_request_state(connection, NS(conn, C_WF_CONNECTION), CS_VERBOSE) < SS_SUCCESS)
return -2;
mutex_init(&sock.mutex);
- sock.sbuf = tconn->data.sbuf;
- sock.rbuf = tconn->data.rbuf;
+ sock.sbuf = connection->data.sbuf;
+ sock.rbuf = connection->data.rbuf;
sock.socket = NULL;
mutex_init(&msock.mutex);
- msock.sbuf = tconn->meta.sbuf;
- msock.rbuf = tconn->meta.rbuf;
+ msock.sbuf = connection->meta.sbuf;
+ msock.rbuf = connection->meta.rbuf;
msock.socket = NULL;
/* Assume that the peer only understands protocol 80 until we know better. */
- tconn->agreed_pro_version = 80;
+ connection->agreed_pro_version = 80;
- if (prepare_listen_socket(tconn, &ad))
+ if (prepare_listen_socket(connection, &ad))
return 0;
do {
struct socket *s;
- s = drbd_try_connect(tconn);
+ s = drbd_try_connect(connection);
if (s) {
if (!sock.socket) {
sock.socket = s;
- send_first_packet(tconn, &sock, P_INITIAL_DATA);
+ send_first_packet(connection, &sock, P_INITIAL_DATA);
} else if (!msock.socket) {
- clear_bit(RESOLVE_CONFLICTS, &tconn->flags);
+ clear_bit(RESOLVE_CONFLICTS, &connection->flags);
msock.socket = s;
- send_first_packet(tconn, &msock, P_INITIAL_META);
+ send_first_packet(connection, &msock, P_INITIAL_META);
} else {
- conn_err(tconn, "Logic error in conn_connect()\n");
+ drbd_err(connection, "Logic error in conn_connect()\n");
goto out_release_sockets;
}
}
if (sock.socket && msock.socket) {
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
timeout = nc->ping_timeo * HZ / 10;
rcu_read_unlock();
schedule_timeout_interruptible(timeout);
@@ -926,15 +928,15 @@ static int conn_connect(struct drbd_tconn *tconn)
}
retry:
- s = drbd_wait_for_connect(tconn, &ad);
+ s = drbd_wait_for_connect(connection, &ad);
if (s) {
- int fp = receive_first_packet(tconn, s);
+ int fp = receive_first_packet(connection, s);
drbd_socket_okay(&sock.socket);
drbd_socket_okay(&msock.socket);
switch (fp) {
case P_INITIAL_DATA:
if (sock.socket) {
- conn_warn(tconn, "initial packet S crossed\n");
+ drbd_warn(connection, "initial packet S crossed\n");
sock_release(sock.socket);
sock.socket = s;
goto randomize;
@@ -942,9 +944,9 @@ retry:
sock.socket = s;
break;
case P_INITIAL_META:
- set_bit(RESOLVE_CONFLICTS, &tconn->flags);
+ set_bit(RESOLVE_CONFLICTS, &connection->flags);
if (msock.socket) {
- conn_warn(tconn, "initial packet M crossed\n");
+ drbd_warn(connection, "initial packet M crossed\n");
sock_release(msock.socket);
msock.socket = s;
goto randomize;
@@ -952,7 +954,7 @@ retry:
msock.socket = s;
break;
default:
- conn_warn(tconn, "Error receiving initial packet\n");
+ drbd_warn(connection, "Error receiving initial packet\n");
sock_release(s);
randomize:
if (prandom_u32() & 1)
@@ -960,12 +962,12 @@ randomize:
}
}
- if (tconn->cstate <= C_DISCONNECTING)
+ if (connection->cstate <= C_DISCONNECTING)
goto out_release_sockets;
if (signal_pending(current)) {
flush_signals(current);
smp_rmb();
- if (get_t_state(&tconn->receiver) == EXITING)
+ if (get_t_state(&connection->receiver) == EXITING)
goto out_release_sockets;
}
@@ -986,12 +988,12 @@ randomize:
msock.socket->sk->sk_priority = TC_PRIO_INTERACTIVE;
/* NOT YET ...
- * sock.socket->sk->sk_sndtimeo = tconn->net_conf->timeout*HZ/10;
+ * sock.socket->sk->sk_sndtimeo = connection->net_conf->timeout*HZ/10;
* sock.socket->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
* first set it to the P_CONNECTION_FEATURES timeout,
* which we set to 4x the configured ping_timeout. */
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
sock.socket->sk->sk_sndtimeo =
sock.socket->sk->sk_rcvtimeo = nc->ping_timeo*4*HZ/10;
@@ -1008,37 +1010,38 @@ randomize:
drbd_tcp_nodelay(sock.socket);
drbd_tcp_nodelay(msock.socket);
- tconn->data.socket = sock.socket;
- tconn->meta.socket = msock.socket;
- tconn->last_received = jiffies;
+ connection->data.socket = sock.socket;
+ connection->meta.socket = msock.socket;
+ connection->last_received = jiffies;
- h = drbd_do_features(tconn);
+ h = drbd_do_features(connection);
if (h <= 0)
return h;
- if (tconn->cram_hmac_tfm) {
- /* drbd_request_state(mdev, NS(conn, WFAuth)); */
- switch (drbd_do_auth(tconn)) {
+ if (connection->cram_hmac_tfm) {
+ /* drbd_request_state(device, NS(conn, WFAuth)); */
+ switch (drbd_do_auth(connection)) {
case -1:
- conn_err(tconn, "Authentication of peer failed\n");
+ drbd_err(connection, "Authentication of peer failed\n");
return -1;
case 0:
- conn_err(tconn, "Authentication of peer failed, trying again.\n");
+ drbd_err(connection, "Authentication of peer failed, trying again.\n");
return 0;
}
}
- tconn->data.socket->sk->sk_sndtimeo = timeout;
- tconn->data.socket->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
+ connection->data.socket->sk->sk_sndtimeo = timeout;
+ connection->data.socket->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
- if (drbd_send_protocol(tconn) == -EOPNOTSUPP)
+ if (drbd_send_protocol(connection) == -EOPNOTSUPP)
return -1;
- set_bit(STATE_SENT, &tconn->flags);
+ set_bit(STATE_SENT, &connection->flags);
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- kref_get(&mdev->kref);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ kref_get(&device->kref);
rcu_read_unlock();
/* Prevent a race between resync-handshake and
@@ -1048,35 +1051,35 @@ randomize:
* drbd_set_role() is finished, and any incoming drbd_set_role
* will see the STATE_SENT flag, and wait for it to be cleared.
*/
- mutex_lock(mdev->state_mutex);
- mutex_unlock(mdev->state_mutex);
+ mutex_lock(device->state_mutex);
+ mutex_unlock(device->state_mutex);
if (discard_my_data)
- set_bit(DISCARD_MY_DATA, &mdev->flags);
+ set_bit(DISCARD_MY_DATA, &device->flags);
else
- clear_bit(DISCARD_MY_DATA, &mdev->flags);
+ clear_bit(DISCARD_MY_DATA, &device->flags);
- drbd_connected(mdev);
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ drbd_connected(peer_device);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
}
rcu_read_unlock();
- rv = conn_request_state(tconn, NS(conn, C_WF_REPORT_PARAMS), CS_VERBOSE);
- if (rv < SS_SUCCESS || tconn->cstate != C_WF_REPORT_PARAMS) {
- clear_bit(STATE_SENT, &tconn->flags);
+ rv = conn_request_state(connection, NS(conn, C_WF_REPORT_PARAMS), CS_VERBOSE);
+ if (rv < SS_SUCCESS || connection->cstate != C_WF_REPORT_PARAMS) {
+ clear_bit(STATE_SENT, &connection->flags);
return 0;
}
- drbd_thread_start(&tconn->asender);
+ drbd_thread_start(&connection->asender);
- mutex_lock(&tconn->conf_update);
+ mutex_lock(&connection->resource->conf_update);
/* The discard_my_data flag is a single-shot modifier to the next
* connection attempt, the handshake of which is now well underway.
* No need for rcu style copying of the whole struct
* just to clear a single value. */
- tconn->net_conf->discard_my_data = 0;
- mutex_unlock(&tconn->conf_update);
+ connection->net_conf->discard_my_data = 0;
+ mutex_unlock(&connection->resource->conf_update);
return h;
@@ -1090,15 +1093,15 @@ out_release_sockets:
return -1;
}
-static int decode_header(struct drbd_tconn *tconn, void *header, struct packet_info *pi)
+static int decode_header(struct drbd_connection *connection, void *header, struct packet_info *pi)
{
- unsigned int header_size = drbd_header_size(tconn);
+ unsigned int header_size = drbd_header_size(connection);
if (header_size == sizeof(struct p_header100) &&
*(__be32 *)header == cpu_to_be32(DRBD_MAGIC_100)) {
struct p_header100 *h = header;
if (h->pad != 0) {
- conn_err(tconn, "Header padding is not zero\n");
+ drbd_err(connection, "Header padding is not zero\n");
return -EINVAL;
}
pi->vnr = be16_to_cpu(h->volume);
@@ -1117,55 +1120,57 @@ static int decode_header(struct drbd_tconn *tconn, void *header, struct packet_i
pi->size = be16_to_cpu(h->length);
pi->vnr = 0;
} else {
- conn_err(tconn, "Wrong magic value 0x%08x in protocol version %d\n",
+ drbd_err(connection, "Wrong magic value 0x%08x in protocol version %d\n",
be32_to_cpu(*(__be32 *)header),
- tconn->agreed_pro_version);
+ connection->agreed_pro_version);
return -EINVAL;
}
pi->data = header + header_size;
return 0;
}
-static int drbd_recv_header(struct drbd_tconn *tconn, struct packet_info *pi)
+static int drbd_recv_header(struct drbd_connection *connection, struct packet_info *pi)
{
- void *buffer = tconn->data.rbuf;
+ void *buffer = connection->data.rbuf;
int err;
- err = drbd_recv_all_warn(tconn, buffer, drbd_header_size(tconn));
+ err = drbd_recv_all_warn(connection, buffer, drbd_header_size(connection));
if (err)
return err;
- err = decode_header(tconn, buffer, pi);
- tconn->last_received = jiffies;
+ err = decode_header(connection, buffer, pi);
+ connection->last_received = jiffies;
return err;
}
-static void drbd_flush(struct drbd_tconn *tconn)
+static void drbd_flush(struct drbd_connection *connection)
{
int rv;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
- if (tconn->write_ordering >= WO_bdev_flush) {
+ if (connection->write_ordering >= WO_bdev_flush) {
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (!get_ldev(mdev))
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+
+ if (!get_ldev(device))
continue;
- kref_get(&mdev->kref);
+ kref_get(&device->kref);
rcu_read_unlock();
- rv = blkdev_issue_flush(mdev->ldev->backing_bdev,
+ rv = blkdev_issue_flush(device->ldev->backing_bdev,
GFP_NOIO, NULL);
if (rv) {
- dev_info(DEV, "local disk flush failed with status %d\n", rv);
+ drbd_info(device, "local disk flush failed with status %d\n", rv);
/* would rather check on EOPNOTSUPP, but that is not reliable.
* don't try again for ANY return value != 0
* if (rv == -EOPNOTSUPP) */
- drbd_bump_write_ordering(tconn, WO_drain_io);
+ drbd_bump_write_ordering(connection, WO_drain_io);
}
- put_ldev(mdev);
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ put_ldev(device);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
if (rv)
@@ -1177,11 +1182,11 @@ static void drbd_flush(struct drbd_tconn *tconn)
/**
* drbd_may_finish_epoch() - Applies an epoch_event to the epoch's state, eventually finishes it.
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @epoch: Epoch object.
* @ev: Epoch event.
*/
-static enum finish_epoch drbd_may_finish_epoch(struct drbd_tconn *tconn,
+static enum finish_epoch drbd_may_finish_epoch(struct drbd_connection *connection,
struct drbd_epoch *epoch,
enum epoch_event ev)
{
@@ -1189,7 +1194,7 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_tconn *tconn,
struct drbd_epoch *next_epoch;
enum finish_epoch rv = FE_STILL_LIVE;
- spin_lock(&tconn->epoch_lock);
+ spin_lock(&connection->epoch_lock);
do {
next_epoch = NULL;
@@ -1211,22 +1216,22 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_tconn *tconn,
atomic_read(&epoch->active) == 0 &&
(test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags) || ev & EV_CLEANUP)) {
if (!(ev & EV_CLEANUP)) {
- spin_unlock(&tconn->epoch_lock);
- drbd_send_b_ack(epoch->tconn, epoch->barrier_nr, epoch_size);
- spin_lock(&tconn->epoch_lock);
+ spin_unlock(&connection->epoch_lock);
+ drbd_send_b_ack(epoch->connection, epoch->barrier_nr, epoch_size);
+ spin_lock(&connection->epoch_lock);
}
#if 0
/* FIXME: dec unacked on connection, once we have
* something to count pending connection packets in. */
if (test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags))
- dec_unacked(epoch->tconn);
+ dec_unacked(epoch->connection);
#endif
- if (tconn->current_epoch != epoch) {
+ if (connection->current_epoch != epoch) {
next_epoch = list_entry(epoch->list.next, struct drbd_epoch, list);
list_del(&epoch->list);
ev = EV_BECAME_LAST | (ev & EV_CLEANUP);
- tconn->epochs--;
+ connection->epochs--;
kfree(epoch);
if (rv == FE_STILL_LIVE)
@@ -1246,20 +1251,20 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_tconn *tconn,
epoch = next_epoch;
} while (1);
- spin_unlock(&tconn->epoch_lock);
+ spin_unlock(&connection->epoch_lock);
return rv;
}
/**
* drbd_bump_write_ordering() - Fall back to an other write ordering method
- * @tconn: DRBD connection.
+ * @connection: DRBD connection.
* @wo: Write ordering method to try.
*/
-void drbd_bump_write_ordering(struct drbd_tconn *tconn, enum write_ordering_e wo)
+void drbd_bump_write_ordering(struct drbd_connection *connection, enum write_ordering_e wo)
{
struct disk_conf *dc;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
enum write_ordering_e pwo;
int vnr;
static char *write_ordering_str[] = {
@@ -1268,29 +1273,31 @@ void drbd_bump_write_ordering(struct drbd_tconn *tconn, enum write_ordering_e wo
[WO_bdev_flush] = "flush",
};
- pwo = tconn->write_ordering;
+ pwo = connection->write_ordering;
wo = min(pwo, wo);
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (!get_ldev_if_state(mdev, D_ATTACHING))
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+
+ if (!get_ldev_if_state(device, D_ATTACHING))
continue;
- dc = rcu_dereference(mdev->ldev->disk_conf);
+ dc = rcu_dereference(device->ldev->disk_conf);
if (wo == WO_bdev_flush && !dc->disk_flushes)
wo = WO_drain_io;
if (wo == WO_drain_io && !dc->disk_drain)
wo = WO_none;
- put_ldev(mdev);
+ put_ldev(device);
}
rcu_read_unlock();
- tconn->write_ordering = wo;
- if (pwo != tconn->write_ordering || wo == WO_bdev_flush)
- conn_info(tconn, "Method to ensure write ordering: %s\n", write_ordering_str[tconn->write_ordering]);
+ connection->write_ordering = wo;
+ if (pwo != connection->write_ordering || wo == WO_bdev_flush)
+ drbd_info(connection, "Method to ensure write ordering: %s\n", write_ordering_str[connection->write_ordering]);
}
/**
* drbd_submit_peer_request()
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @peer_req: peer request
* @rw: flag field, see bio->bi_rw
*
@@ -1305,7 +1312,7 @@ void drbd_bump_write_ordering(struct drbd_tconn *tconn, enum write_ordering_e wo
* on certain Xen deployments.
*/
/* TODO allocate from our own bio_set. */
-int drbd_submit_peer_request(struct drbd_conf *mdev,
+int drbd_submit_peer_request(struct drbd_device *device,
struct drbd_peer_request *peer_req,
const unsigned rw, const int fault_type)
{
@@ -1329,12 +1336,12 @@ int drbd_submit_peer_request(struct drbd_conf *mdev,
next_bio:
bio = bio_alloc(GFP_NOIO, nr_pages);
if (!bio) {
- dev_err(DEV, "submit_ee: Allocation of a bio failed\n");
+ drbd_err(device, "submit_ee: Allocation of a bio failed\n");
goto fail;
}
/* > peer_req->i.sector, unless this is the first bio */
bio->bi_iter.bi_sector = sector;
- bio->bi_bdev = mdev->ldev->backing_bdev;
+ bio->bi_bdev = device->ldev->backing_bdev;
bio->bi_rw = rw;
bio->bi_private = peer_req;
bio->bi_end_io = drbd_peer_request_endio;
@@ -1350,7 +1357,7 @@ next_bio:
* But in case it fails anyways,
* we deal with it, and complain (below). */
if (bio->bi_vcnt == 0) {
- dev_err(DEV,
+ drbd_err(device,
"bio_add_page failed for len=%u, "
"bi_vcnt=0 (bi_sector=%llu)\n",
len, (uint64_t)bio->bi_iter.bi_sector);
@@ -1363,8 +1370,8 @@ next_bio:
sector += len >> 9;
--nr_pages;
}
- D_ASSERT(page == NULL);
- D_ASSERT(ds == 0);
+ D_ASSERT(device, page == NULL);
+ D_ASSERT(device, ds == 0);
atomic_set(&peer_req->pending_bios, n_bios);
do {
@@ -1372,7 +1379,7 @@ next_bio:
bios = bios->bi_next;
bio->bi_next = NULL;
- drbd_generic_make_request(mdev, fault_type, bio);
+ drbd_generic_make_request(device, fault_type, bio);
} while (bios);
return 0;
@@ -1385,36 +1392,44 @@ fail:
return err;
}
-static void drbd_remove_epoch_entry_interval(struct drbd_conf *mdev,
+static void drbd_remove_epoch_entry_interval(struct drbd_device *device,
struct drbd_peer_request *peer_req)
{
struct drbd_interval *i = &peer_req->i;
- drbd_remove_interval(&mdev->write_requests, i);
+ drbd_remove_interval(&device->write_requests, i);
drbd_clear_interval(i);
/* Wake up any processes waiting for this peer request to complete. */
if (i->waiting)
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
}
-void conn_wait_active_ee_empty(struct drbd_tconn *tconn)
+static void conn_wait_active_ee_empty(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- kref_get(&mdev->kref);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+
+ kref_get(&device->kref);
rcu_read_unlock();
- drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ drbd_wait_ee_list_empty(device, &device->active_ee);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
}
rcu_read_unlock();
}
-static int receive_Barrier(struct drbd_tconn *tconn, struct packet_info *pi)
+static struct drbd_peer_device *
+conn_peer_device(struct drbd_connection *connection, int volume_number)
+{
+ return idr_find(&connection->peer_devices, volume_number);
+}
+
+static int receive_Barrier(struct drbd_connection *connection, struct packet_info *pi)
{
int rv;
struct p_barrier *p = pi->data;
@@ -1423,16 +1438,16 @@ static int receive_Barrier(struct drbd_tconn *tconn, struct packet_info *pi)
/* FIXME these are unacked on connection,
* not a specific (peer)device.
*/
- tconn->current_epoch->barrier_nr = p->barrier;
- tconn->current_epoch->tconn = tconn;
- rv = drbd_may_finish_epoch(tconn, tconn->current_epoch, EV_GOT_BARRIER_NR);
+ connection->current_epoch->barrier_nr = p->barrier;
+ connection->current_epoch->connection = connection;
+ rv = drbd_may_finish_epoch(connection, connection->current_epoch, EV_GOT_BARRIER_NR);
/* P_BARRIER_ACK may imply that the corresponding extent is dropped from
* the activity log, which means it would not be resynced in case the
* R_PRIMARY crashes now.
* Therefore we must send the barrier_ack after the barrier request was
* completed. */
- switch (tconn->write_ordering) {
+ switch (connection->write_ordering) {
case WO_none:
if (rv == FE_RECYCLED)
return 0;
@@ -1443,15 +1458,15 @@ static int receive_Barrier(struct drbd_tconn *tconn, struct packet_info *pi)
if (epoch)
break;
else
- conn_warn(tconn, "Allocation of an epoch failed, slowing down\n");
+ drbd_warn(connection, "Allocation of an epoch failed, slowing down\n");
/* Fall through */
case WO_bdev_flush:
case WO_drain_io:
- conn_wait_active_ee_empty(tconn);
- drbd_flush(tconn);
+ conn_wait_active_ee_empty(connection);
+ drbd_flush(connection);
- if (atomic_read(&tconn->current_epoch->epoch_size)) {
+ if (atomic_read(&connection->current_epoch->epoch_size)) {
epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
if (epoch)
break;
@@ -1459,7 +1474,7 @@ static int receive_Barrier(struct drbd_tconn *tconn, struct packet_info *pi)
return 0;
default:
- conn_err(tconn, "Strangeness in tconn->write_ordering %d\n", tconn->write_ordering);
+ drbd_err(connection, "Strangeness in connection->write_ordering %d\n", connection->write_ordering);
return -EIO;
}
@@ -1467,16 +1482,16 @@ static int receive_Barrier(struct drbd_tconn *tconn, struct packet_info *pi)
atomic_set(&epoch->epoch_size, 0);
atomic_set(&epoch->active, 0);
- spin_lock(&tconn->epoch_lock);
- if (atomic_read(&tconn->current_epoch->epoch_size)) {
- list_add(&epoch->list, &tconn->current_epoch->list);
- tconn->current_epoch = epoch;
- tconn->epochs++;
+ spin_lock(&connection->epoch_lock);
+ if (atomic_read(&connection->current_epoch->epoch_size)) {
+ list_add(&epoch->list, &connection->current_epoch->list);
+ connection->current_epoch = epoch;
+ connection->epochs++;
} else {
/* The current_epoch got recycled while we allocated this one... */
kfree(epoch);
}
- spin_unlock(&tconn->epoch_lock);
+ spin_unlock(&connection->epoch_lock);
return 0;
}
@@ -1484,25 +1499,26 @@ static int receive_Barrier(struct drbd_tconn *tconn, struct packet_info *pi)
/* used from receive_RSDataReply (recv_resync_read)
* and from receive_Data */
static struct drbd_peer_request *
-read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector,
+read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector,
int data_size) __must_hold(local)
{
- const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
+ struct drbd_device *device = peer_device->device;
+ const sector_t capacity = drbd_get_capacity(device->this_bdev);
struct drbd_peer_request *peer_req;
struct page *page;
int dgs, ds, err;
- void *dig_in = mdev->tconn->int_dig_in;
- void *dig_vv = mdev->tconn->int_dig_vv;
+ void *dig_in = peer_device->connection->int_dig_in;
+ void *dig_vv = peer_device->connection->int_dig_vv;
unsigned long *data;
dgs = 0;
- if (mdev->tconn->peer_integrity_tfm) {
- dgs = crypto_hash_digestsize(mdev->tconn->peer_integrity_tfm);
+ if (peer_device->connection->peer_integrity_tfm) {
+ dgs = crypto_hash_digestsize(peer_device->connection->peer_integrity_tfm);
/*
* FIXME: Receive the incoming digest into the receive buffer
* here, together with its struct p_data?
*/
- err = drbd_recv_all_warn(mdev->tconn, dig_in, dgs);
+ err = drbd_recv_all_warn(peer_device->connection, dig_in, dgs);
if (err)
return NULL;
data_size -= dgs;
@@ -1516,7 +1532,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector,
/* even though we trust out peer,
* we sometimes have to double check. */
if (sector + (data_size>>9) > capacity) {
- dev_err(DEV, "request from peer beyond end of local disk: "
+ drbd_err(device, "request from peer beyond end of local disk: "
"capacity: %llus < sector: %llus + size: %u\n",
(unsigned long long)capacity,
(unsigned long long)sector, data_size);
@@ -1526,7 +1542,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector,
/* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD
* "criss-cross" setup, that might cause write-out on some other DRBD,
* which in turn might block on the other node at this very place. */
- peer_req = drbd_alloc_peer_req(mdev, id, sector, data_size, GFP_NOIO);
+ peer_req = drbd_alloc_peer_req(peer_device, id, sector, data_size, GFP_NOIO);
if (!peer_req)
return NULL;
@@ -1538,36 +1554,36 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector,
page_chain_for_each(page) {
unsigned len = min_t(int, ds, PAGE_SIZE);
data = kmap(page);
- err = drbd_recv_all_warn(mdev->tconn, data, len);
- if (drbd_insert_fault(mdev, DRBD_FAULT_RECEIVE)) {
- dev_err(DEV, "Fault injection: Corrupting data on receive\n");
+ err = drbd_recv_all_warn(peer_device->connection, data, len);
+ if (drbd_insert_fault(device, DRBD_FAULT_RECEIVE)) {
+ drbd_err(device, "Fault injection: Corrupting data on receive\n");
data[0] = data[0] ^ (unsigned long)-1;
}
kunmap(page);
if (err) {
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
return NULL;
}
ds -= len;
}
if (dgs) {
- drbd_csum_ee(mdev, mdev->tconn->peer_integrity_tfm, peer_req, dig_vv);
+ drbd_csum_ee(peer_device->connection->peer_integrity_tfm, peer_req, dig_vv);
if (memcmp(dig_in, dig_vv, dgs)) {
- dev_err(DEV, "Digest integrity check FAILED: %llus +%u\n",
+ drbd_err(device, "Digest integrity check FAILED: %llus +%u\n",
(unsigned long long)sector, data_size);
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
return NULL;
}
}
- mdev->recv_cnt += data_size>>9;
+ device->recv_cnt += data_size>>9;
return peer_req;
}
/* drbd_drain_block() just takes a data block
* out of the socket input buffer, and discards it.
*/
-static int drbd_drain_block(struct drbd_conf *mdev, int data_size)
+static int drbd_drain_block(struct drbd_peer_device *peer_device, int data_size)
{
struct page *page;
int err = 0;
@@ -1576,36 +1592,36 @@ static int drbd_drain_block(struct drbd_conf *mdev, int data_size)
if (!data_size)
return 0;
- page = drbd_alloc_pages(mdev, 1, 1);
+ page = drbd_alloc_pages(peer_device, 1, 1);
data = kmap(page);
while (data_size) {
unsigned int len = min_t(int, data_size, PAGE_SIZE);
- err = drbd_recv_all_warn(mdev->tconn, data, len);
+ err = drbd_recv_all_warn(peer_device->connection, data, len);
if (err)
break;
data_size -= len;
}
kunmap(page);
- drbd_free_pages(mdev, page, 0);
+ drbd_free_pages(peer_device->device, page, 0);
return err;
}
-static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req,
+static int recv_dless_read(struct drbd_peer_device *peer_device, struct drbd_request *req,
sector_t sector, int data_size)
{
struct bio_vec bvec;
struct bvec_iter iter;
struct bio *bio;
int dgs, err, expect;
- void *dig_in = mdev->tconn->int_dig_in;
- void *dig_vv = mdev->tconn->int_dig_vv;
+ void *dig_in = peer_device->connection->int_dig_in;
+ void *dig_vv = peer_device->connection->int_dig_vv;
dgs = 0;
- if (mdev->tconn->peer_integrity_tfm) {
- dgs = crypto_hash_digestsize(mdev->tconn->peer_integrity_tfm);
- err = drbd_recv_all_warn(mdev->tconn, dig_in, dgs);
+ if (peer_device->connection->peer_integrity_tfm) {
+ dgs = crypto_hash_digestsize(peer_device->connection->peer_integrity_tfm);
+ err = drbd_recv_all_warn(peer_device->connection, dig_in, dgs);
if (err)
return err;
data_size -= dgs;
@@ -1613,15 +1629,15 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req,
/* optimistically update recv_cnt. if receiving fails below,
* we disconnect anyways, and counters will be reset. */
- mdev->recv_cnt += data_size>>9;
+ peer_device->device->recv_cnt += data_size>>9;
bio = req->master_bio;
- D_ASSERT(sector == bio->bi_iter.bi_sector);
+ D_ASSERT(peer_device->device, sector == bio->bi_iter.bi_sector);
bio_for_each_segment(bvec, bio, iter) {
void *mapped = kmap(bvec.bv_page) + bvec.bv_offset;
expect = min_t(int, data_size, bvec.bv_len);
- err = drbd_recv_all_warn(mdev->tconn, mapped, expect);
+ err = drbd_recv_all_warn(peer_device->connection, mapped, expect);
kunmap(bvec.bv_page);
if (err)
return err;
@@ -1629,14 +1645,14 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req,
}
if (dgs) {
- drbd_csum_bio(mdev, mdev->tconn->peer_integrity_tfm, bio, dig_vv);
+ drbd_csum_bio(peer_device->connection->peer_integrity_tfm, bio, dig_vv);
if (memcmp(dig_in, dig_vv, dgs)) {
- dev_err(DEV, "Digest integrity check FAILED. Broken NICs?\n");
+ drbd_err(peer_device, "Digest integrity check FAILED. Broken NICs?\n");
return -EINVAL;
}
}
- D_ASSERT(data_size == 0);
+ D_ASSERT(peer_device->device, data_size == 0);
return 0;
}
@@ -1648,64 +1664,67 @@ static int e_end_resync_block(struct drbd_work *w, int unused)
{
struct drbd_peer_request *peer_req =
container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
sector_t sector = peer_req->i.sector;
int err;
- D_ASSERT(drbd_interval_empty(&peer_req->i));
+ D_ASSERT(device, drbd_interval_empty(&peer_req->i));
if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) {
- drbd_set_in_sync(mdev, sector, peer_req->i.size);
- err = drbd_send_ack(mdev, P_RS_WRITE_ACK, peer_req);
+ drbd_set_in_sync(device, sector, peer_req->i.size);
+ err = drbd_send_ack(peer_device, P_RS_WRITE_ACK, peer_req);
} else {
/* Record failure to sync */
- drbd_rs_failed_io(mdev, sector, peer_req->i.size);
+ drbd_rs_failed_io(device, sector, peer_req->i.size);
- err = drbd_send_ack(mdev, P_NEG_ACK, peer_req);
+ err = drbd_send_ack(peer_device, P_NEG_ACK, peer_req);
}
- dec_unacked(mdev);
+ dec_unacked(device);
return err;
}
-static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_size) __releases(local)
+static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t sector,
+ int data_size) __releases(local)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_peer_request *peer_req;
- peer_req = read_in_block(mdev, ID_SYNCER, sector, data_size);
+ peer_req = read_in_block(peer_device, ID_SYNCER, sector, data_size);
if (!peer_req)
goto fail;
- dec_rs_pending(mdev);
+ dec_rs_pending(device);
- inc_unacked(mdev);
+ inc_unacked(device);
/* corresponding dec_unacked() in e_end_resync_block()
* respective _drbd_clear_done_ee */
peer_req->w.cb = e_end_resync_block;
- spin_lock_irq(&mdev->tconn->req_lock);
- list_add(&peer_req->w.list, &mdev->sync_ee);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ list_add(&peer_req->w.list, &device->sync_ee);
+ spin_unlock_irq(&device->resource->req_lock);
- atomic_add(data_size >> 9, &mdev->rs_sect_ev);
- if (drbd_submit_peer_request(mdev, peer_req, WRITE, DRBD_FAULT_RS_WR) == 0)
+ atomic_add(data_size >> 9, &device->rs_sect_ev);
+ if (drbd_submit_peer_request(device, peer_req, WRITE, DRBD_FAULT_RS_WR) == 0)
return 0;
/* don't care for the reason here */
- dev_err(DEV, "submit failed, triggering re-connect\n");
- spin_lock_irq(&mdev->tconn->req_lock);
+ drbd_err(device, "submit failed, triggering re-connect\n");
+ spin_lock_irq(&device->resource->req_lock);
list_del(&peer_req->w.list);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
fail:
- put_ldev(mdev);
+ put_ldev(device);
return -EIO;
}
static struct drbd_request *
-find_request(struct drbd_conf *mdev, struct rb_root *root, u64 id,
+find_request(struct drbd_device *device, struct rb_root *root, u64 id,
sector_t sector, bool missing_ok, const char *func)
{
struct drbd_request *req;
@@ -1715,36 +1734,38 @@ find_request(struct drbd_conf *mdev, struct rb_root *root, u64 id,
if (drbd_contains_interval(root, sector, &req->i) && req->i.local)
return req;
if (!missing_ok) {
- dev_err(DEV, "%s: failed to find request 0x%lx, sector %llus\n", func,
+ drbd_err(device, "%s: failed to find request 0x%lx, sector %llus\n", func,
(unsigned long)id, (unsigned long long)sector);
}
return NULL;
}
-static int receive_DataReply(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_DataReply(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct drbd_request *req;
sector_t sector;
int err;
struct p_data *p = pi->data;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
sector = be64_to_cpu(p->sector);
- spin_lock_irq(&mdev->tconn->req_lock);
- req = find_request(mdev, &mdev->read_requests, p->block_id, sector, false, __func__);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ req = find_request(device, &device->read_requests, p->block_id, sector, false, __func__);
+ spin_unlock_irq(&device->resource->req_lock);
if (unlikely(!req))
return -EIO;
/* hlist_del(&req->collision) is done in _req_may_be_done, to avoid
* special casing it there for the various failure cases.
* still no race with drbd_fail_pending_reads */
- err = recv_dless_read(mdev, req, sector, pi->size);
+ err = recv_dless_read(peer_device, req, sector, pi->size);
if (!err)
req_mod(req, DATA_RECEIVED);
/* else: nothing. handled from drbd_disconnect...
@@ -1754,46 +1775,48 @@ static int receive_DataReply(struct drbd_tconn *tconn, struct packet_info *pi)
return err;
}
-static int receive_RSDataReply(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_RSDataReply(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
sector_t sector;
int err;
struct p_data *p = pi->data;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
sector = be64_to_cpu(p->sector);
- D_ASSERT(p->block_id == ID_SYNCER);
+ D_ASSERT(device, p->block_id == ID_SYNCER);
- if (get_ldev(mdev)) {
+ if (get_ldev(device)) {
/* data is submitted to disk within recv_resync_read.
* corresponding put_ldev done below on error,
* or in drbd_peer_request_endio. */
- err = recv_resync_read(mdev, sector, pi->size);
+ err = recv_resync_read(peer_device, sector, pi->size);
} else {
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Can not write resync data to local disk.\n");
+ drbd_err(device, "Can not write resync data to local disk.\n");
- err = drbd_drain_block(mdev, pi->size);
+ err = drbd_drain_block(peer_device, pi->size);
- drbd_send_ack_dp(mdev, P_NEG_ACK, p, pi->size);
+ drbd_send_ack_dp(peer_device, P_NEG_ACK, p, pi->size);
}
- atomic_add(pi->size >> 9, &mdev->rs_sect_in);
+ atomic_add(pi->size >> 9, &device->rs_sect_in);
return err;
}
-static void restart_conflicting_writes(struct drbd_conf *mdev,
+static void restart_conflicting_writes(struct drbd_device *device,
sector_t sector, int size)
{
struct drbd_interval *i;
struct drbd_request *req;
- drbd_for_each_overlap(i, &mdev->write_requests, sector, size) {
+ drbd_for_each_overlap(i, &device->write_requests, sector, size) {
if (!i->local)
continue;
req = container_of(i, struct drbd_request, i);
@@ -1813,52 +1836,53 @@ static int e_end_block(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req =
container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
sector_t sector = peer_req->i.sector;
int err = 0, pcmd;
if (peer_req->flags & EE_SEND_WRITE_ACK) {
if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) {
- pcmd = (mdev->state.conn >= C_SYNC_SOURCE &&
- mdev->state.conn <= C_PAUSED_SYNC_T &&
+ pcmd = (device->state.conn >= C_SYNC_SOURCE &&
+ device->state.conn <= C_PAUSED_SYNC_T &&
peer_req->flags & EE_MAY_SET_IN_SYNC) ?
P_RS_WRITE_ACK : P_WRITE_ACK;
- err = drbd_send_ack(mdev, pcmd, peer_req);
+ err = drbd_send_ack(peer_device, pcmd, peer_req);
if (pcmd == P_RS_WRITE_ACK)
- drbd_set_in_sync(mdev, sector, peer_req->i.size);
+ drbd_set_in_sync(device, sector, peer_req->i.size);
} else {
- err = drbd_send_ack(mdev, P_NEG_ACK, peer_req);
+ err = drbd_send_ack(peer_device, P_NEG_ACK, peer_req);
/* we expect it to be marked out of sync anyways...
* maybe assert this? */
}
- dec_unacked(mdev);
+ dec_unacked(device);
}
/* we delete from the conflict detection hash _after_ we sent out the
* P_WRITE_ACK / P_NEG_ACK, to get the sequence number right. */
if (peer_req->flags & EE_IN_INTERVAL_TREE) {
- spin_lock_irq(&mdev->tconn->req_lock);
- D_ASSERT(!drbd_interval_empty(&peer_req->i));
- drbd_remove_epoch_entry_interval(mdev, peer_req);
+ spin_lock_irq(&device->resource->req_lock);
+ D_ASSERT(device, !drbd_interval_empty(&peer_req->i));
+ drbd_remove_epoch_entry_interval(device, peer_req);
if (peer_req->flags & EE_RESTART_REQUESTS)
- restart_conflicting_writes(mdev, sector, peer_req->i.size);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ restart_conflicting_writes(device, sector, peer_req->i.size);
+ spin_unlock_irq(&device->resource->req_lock);
} else
- D_ASSERT(drbd_interval_empty(&peer_req->i));
+ D_ASSERT(device, drbd_interval_empty(&peer_req->i));
- drbd_may_finish_epoch(mdev->tconn, peer_req->epoch, EV_PUT + (cancel ? EV_CLEANUP : 0));
+ drbd_may_finish_epoch(first_peer_device(device)->connection, peer_req->epoch, EV_PUT + (cancel ? EV_CLEANUP : 0));
return err;
}
static int e_send_ack(struct drbd_work *w, enum drbd_packet ack)
{
- struct drbd_conf *mdev = w->mdev;
struct drbd_peer_request *peer_req =
container_of(w, struct drbd_peer_request, w);
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
int err;
- err = drbd_send_ack(mdev, ack, peer_req);
- dec_unacked(mdev);
+ err = drbd_send_ack(peer_device, ack, peer_req);
+ dec_unacked(peer_device->device);
return err;
}
@@ -1870,9 +1894,11 @@ static int e_send_superseded(struct drbd_work *w, int unused)
static int e_send_retry_write(struct drbd_work *w, int unused)
{
- struct drbd_tconn *tconn = w->mdev->tconn;
+ struct drbd_peer_request *peer_req =
+ container_of(w, struct drbd_peer_request, w);
+ struct drbd_connection *connection = peer_req->peer_device->connection;
- return e_send_ack(w, tconn->agreed_pro_version >= 100 ?
+ return e_send_ack(w, connection->agreed_pro_version >= 100 ?
P_RETRY_WRITE : P_SUPERSEDED);
}
@@ -1891,18 +1917,19 @@ static u32 seq_max(u32 a, u32 b)
return seq_greater(a, b) ? a : b;
}
-static void update_peer_seq(struct drbd_conf *mdev, unsigned int peer_seq)
+static void update_peer_seq(struct drbd_peer_device *peer_device, unsigned int peer_seq)
{
+ struct drbd_device *device = peer_device->device;
unsigned int newest_peer_seq;
- if (test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags)) {
- spin_lock(&mdev->peer_seq_lock);
- newest_peer_seq = seq_max(mdev->peer_seq, peer_seq);
- mdev->peer_seq = newest_peer_seq;
- spin_unlock(&mdev->peer_seq_lock);
- /* wake up only if we actually changed mdev->peer_seq */
+ if (test_bit(RESOLVE_CONFLICTS, &peer_device->connection->flags)) {
+ spin_lock(&device->peer_seq_lock);
+ newest_peer_seq = seq_max(device->peer_seq, peer_seq);
+ device->peer_seq = newest_peer_seq;
+ spin_unlock(&device->peer_seq_lock);
+ /* wake up only if we actually changed device->peer_seq */
if (peer_seq == newest_peer_seq)
- wake_up(&mdev->seq_wait);
+ wake_up(&device->seq_wait);
}
}
@@ -1912,20 +1939,20 @@ static inline int overlaps(sector_t s1, int l1, sector_t s2, int l2)
}
/* maybe change sync_ee into interval trees as well? */
-static bool overlapping_resync_write(struct drbd_conf *mdev, struct drbd_peer_request *peer_req)
+static bool overlapping_resync_write(struct drbd_device *device, struct drbd_peer_request *peer_req)
{
struct drbd_peer_request *rs_req;
bool rv = 0;
- spin_lock_irq(&mdev->tconn->req_lock);
- list_for_each_entry(rs_req, &mdev->sync_ee, w.list) {
+ spin_lock_irq(&device->resource->req_lock);
+ list_for_each_entry(rs_req, &device->sync_ee, w.list) {
if (overlaps(peer_req->i.sector, peer_req->i.size,
rs_req->i.sector, rs_req->i.size)) {
rv = 1;
break;
}
}
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
return rv;
}
@@ -1939,9 +1966,9 @@ static bool overlapping_resync_write(struct drbd_conf *mdev, struct drbd_peer_re
*
* Note: we don't care for Ack packets overtaking P_DATA packets.
*
- * In case packet_seq is larger than mdev->peer_seq number, there are
+ * In case packet_seq is larger than device->peer_seq number, there are
* outstanding packets on the msock. We wait for them to arrive.
- * In case we are the logically next packet, we update mdev->peer_seq
+ * In case we are the logically next packet, we update device->peer_seq
* ourselves. Correctly handles 32bit wrap around.
*
* Assume we have a 10 GBit connection, that is about 1<<30 byte per second,
@@ -1951,19 +1978,20 @@ static bool overlapping_resync_write(struct drbd_conf *mdev, struct drbd_peer_re
*
* returns 0 if we may process the packet,
* -ERESTARTSYS if we were interrupted (by disconnect signal). */
-static int wait_for_and_update_peer_seq(struct drbd_conf *mdev, const u32 peer_seq)
+static int wait_for_and_update_peer_seq(struct drbd_peer_device *peer_device, const u32 peer_seq)
{
+ struct drbd_device *device = peer_device->device;
DEFINE_WAIT(wait);
long timeout;
int ret = 0, tp;
- if (!test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags))
+ if (!test_bit(RESOLVE_CONFLICTS, &peer_device->connection->flags))
return 0;
- spin_lock(&mdev->peer_seq_lock);
+ spin_lock(&device->peer_seq_lock);
for (;;) {
- if (!seq_greater(peer_seq - 1, mdev->peer_seq)) {
- mdev->peer_seq = seq_max(mdev->peer_seq, peer_seq);
+ if (!seq_greater(peer_seq - 1, device->peer_seq)) {
+ device->peer_seq = seq_max(device->peer_seq, peer_seq);
break;
}
@@ -1973,35 +2001,35 @@ static int wait_for_and_update_peer_seq(struct drbd_conf *mdev, const u32 peer_s
}
rcu_read_lock();
- tp = rcu_dereference(mdev->tconn->net_conf)->two_primaries;
+ tp = rcu_dereference(first_peer_device(device)->connection->net_conf)->two_primaries;
rcu_read_unlock();
if (!tp)
break;
/* Only need to wait if two_primaries is enabled */
- prepare_to_wait(&mdev->seq_wait, &wait, TASK_INTERRUPTIBLE);
- spin_unlock(&mdev->peer_seq_lock);
+ prepare_to_wait(&device->seq_wait, &wait, TASK_INTERRUPTIBLE);
+ spin_unlock(&device->peer_seq_lock);
rcu_read_lock();
- timeout = rcu_dereference(mdev->tconn->net_conf)->ping_timeo*HZ/10;
+ timeout = rcu_dereference(peer_device->connection->net_conf)->ping_timeo*HZ/10;
rcu_read_unlock();
timeout = schedule_timeout(timeout);
- spin_lock(&mdev->peer_seq_lock);
+ spin_lock(&device->peer_seq_lock);
if (!timeout) {
ret = -ETIMEDOUT;
- dev_err(DEV, "Timed out waiting for missing ack packets; disconnecting\n");
+ drbd_err(device, "Timed out waiting for missing ack packets; disconnecting\n");
break;
}
}
- spin_unlock(&mdev->peer_seq_lock);
- finish_wait(&mdev->seq_wait, &wait);
+ spin_unlock(&device->peer_seq_lock);
+ finish_wait(&device->seq_wait, &wait);
return ret;
}
/* see also bio_flags_to_wire()
* DRBD_REQ_*, because we need to semantically map the flags to data packet
* flags and back. We may replicate to other kernel versions. */
-static unsigned long wire_flags_to_bio(struct drbd_conf *mdev, u32 dpf)
+static unsigned long wire_flags_to_bio(u32 dpf)
{
return (dpf & DP_RW_SYNC ? REQ_SYNC : 0) |
(dpf & DP_FUA ? REQ_FUA : 0) |
@@ -2009,13 +2037,13 @@ static unsigned long wire_flags_to_bio(struct drbd_conf *mdev, u32 dpf)
(dpf & DP_DISCARD ? REQ_DISCARD : 0);
}
-static void fail_postponed_requests(struct drbd_conf *mdev, sector_t sector,
+static void fail_postponed_requests(struct drbd_device *device, sector_t sector,
unsigned int size)
{
struct drbd_interval *i;
repeat:
- drbd_for_each_overlap(i, &mdev->write_requests, sector, size) {
+ drbd_for_each_overlap(i, &device->write_requests, sector, size) {
struct drbd_request *req;
struct bio_and_error m;
@@ -2026,19 +2054,19 @@ static void fail_postponed_requests(struct drbd_conf *mdev, sector_t sector,
continue;
req->rq_state &= ~RQ_POSTPONED;
__req_mod(req, NEG_ACKED, &m);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
if (m.bio)
- complete_master_bio(mdev, &m);
- spin_lock_irq(&mdev->tconn->req_lock);
+ complete_master_bio(device, &m);
+ spin_lock_irq(&device->resource->req_lock);
goto repeat;
}
}
-static int handle_write_conflicts(struct drbd_conf *mdev,
+static int handle_write_conflicts(struct drbd_device *device,
struct drbd_peer_request *peer_req)
{
- struct drbd_tconn *tconn = mdev->tconn;
- bool resolve_conflicts = test_bit(RESOLVE_CONFLICTS, &tconn->flags);
+ struct drbd_connection *connection = peer_req->peer_device->connection;
+ bool resolve_conflicts = test_bit(RESOLVE_CONFLICTS, &connection->flags);
sector_t sector = peer_req->i.sector;
const unsigned int size = peer_req->i.size;
struct drbd_interval *i;
@@ -2049,10 +2077,10 @@ static int handle_write_conflicts(struct drbd_conf *mdev,
* Inserting the peer request into the write_requests tree will prevent
* new conflicting local requests from being added.
*/
- drbd_insert_interval(&mdev->write_requests, &peer_req->i);
+ drbd_insert_interval(&device->write_requests, &peer_req->i);
repeat:
- drbd_for_each_overlap(i, &mdev->write_requests, sector, size) {
+ drbd_for_each_overlap(i, &device->write_requests, sector, size) {
if (i == &peer_req->i)
continue;
@@ -2062,7 +2090,7 @@ static int handle_write_conflicts(struct drbd_conf *mdev,
* should not happen in a two-node setup. Wait for the
* earlier peer request to complete.
*/
- err = drbd_wait_misc(mdev, i);
+ err = drbd_wait_misc(device, i);
if (err)
goto out;
goto repeat;
@@ -2080,18 +2108,18 @@ static int handle_write_conflicts(struct drbd_conf *mdev,
(i->size >> 9) >= sector + (size >> 9);
if (!equal)
- dev_alert(DEV, "Concurrent writes detected: "
+ drbd_alert(device, "Concurrent writes detected: "
"local=%llus +%u, remote=%llus +%u, "
"assuming %s came first\n",
(unsigned long long)i->sector, i->size,
(unsigned long long)sector, size,
superseded ? "local" : "remote");
- inc_unacked(mdev);
+ inc_unacked(device);
peer_req->w.cb = superseded ? e_send_superseded :
e_send_retry_write;
- list_add_tail(&peer_req->w.list, &mdev->done_ee);
- wake_asender(mdev->tconn);
+ list_add_tail(&peer_req->w.list, &device->done_ee);
+ wake_asender(connection);
err = -ENOENT;
goto out;
@@ -2100,7 +2128,7 @@ static int handle_write_conflicts(struct drbd_conf *mdev,
container_of(i, struct drbd_request, i);
if (!equal)
- dev_alert(DEV, "Concurrent writes detected: "
+ drbd_alert(device, "Concurrent writes detected: "
"local=%llus +%u, remote=%llus +%u\n",
(unsigned long long)i->sector, i->size,
(unsigned long long)sector, size);
@@ -2118,12 +2146,10 @@ static int handle_write_conflicts(struct drbd_conf *mdev,
* request to finish locally before submitting
* the conflicting peer request.
*/
- err = drbd_wait_misc(mdev, &req->i);
+ err = drbd_wait_misc(device, &req->i);
if (err) {
- _conn_request_state(mdev->tconn,
- NS(conn, C_TIMEOUT),
- CS_HARD);
- fail_postponed_requests(mdev, sector, size);
+ _conn_request_state(connection, NS(conn, C_TIMEOUT), CS_HARD);
+ fail_postponed_requests(device, sector, size);
goto out;
}
goto repeat;
@@ -2139,14 +2165,15 @@ static int handle_write_conflicts(struct drbd_conf *mdev,
out:
if (err)
- drbd_remove_epoch_entry_interval(mdev, peer_req);
+ drbd_remove_epoch_entry_interval(device, peer_req);
return err;
}
/* mirrored write */
-static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_Data(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
sector_t sector;
struct drbd_peer_request *peer_req;
struct p_data *p = pi->data;
@@ -2155,17 +2182,18 @@ static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi)
u32 dp_flags;
int err, tp;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- if (!get_ldev(mdev)) {
+ if (!get_ldev(device)) {
int err2;
- err = wait_for_and_update_peer_seq(mdev, peer_seq);
- drbd_send_ack_dp(mdev, P_NEG_ACK, p, pi->size);
- atomic_inc(&tconn->current_epoch->epoch_size);
- err2 = drbd_drain_block(mdev, pi->size);
+ err = wait_for_and_update_peer_seq(peer_device, peer_seq);
+ drbd_send_ack_dp(peer_device, P_NEG_ACK, p, pi->size);
+ atomic_inc(&connection->current_epoch->epoch_size);
+ err2 = drbd_drain_block(peer_device, pi->size);
if (!err)
err = err2;
return err;
@@ -2178,61 +2206,61 @@ static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi)
*/
sector = be64_to_cpu(p->sector);
- peer_req = read_in_block(mdev, p->block_id, sector, pi->size);
+ peer_req = read_in_block(peer_device, p->block_id, sector, pi->size);
if (!peer_req) {
- put_ldev(mdev);
+ put_ldev(device);
return -EIO;
}
peer_req->w.cb = e_end_block;
dp_flags = be32_to_cpu(p->dp_flags);
- rw |= wire_flags_to_bio(mdev, dp_flags);
+ rw |= wire_flags_to_bio(dp_flags);
if (peer_req->pages == NULL) {
- D_ASSERT(peer_req->i.size == 0);
- D_ASSERT(dp_flags & DP_FLUSH);
+ D_ASSERT(device, peer_req->i.size == 0);
+ D_ASSERT(device, dp_flags & DP_FLUSH);
}
if (dp_flags & DP_MAY_SET_IN_SYNC)
peer_req->flags |= EE_MAY_SET_IN_SYNC;
- spin_lock(&tconn->epoch_lock);
- peer_req->epoch = tconn->current_epoch;
+ spin_lock(&connection->epoch_lock);
+ peer_req->epoch = connection->current_epoch;
atomic_inc(&peer_req->epoch->epoch_size);
atomic_inc(&peer_req->epoch->active);
- spin_unlock(&tconn->epoch_lock);
+ spin_unlock(&connection->epoch_lock);
rcu_read_lock();
- tp = rcu_dereference(mdev->tconn->net_conf)->two_primaries;
+ tp = rcu_dereference(peer_device->connection->net_conf)->two_primaries;
rcu_read_unlock();
if (tp) {
peer_req->flags |= EE_IN_INTERVAL_TREE;
- err = wait_for_and_update_peer_seq(mdev, peer_seq);
+ err = wait_for_and_update_peer_seq(peer_device, peer_seq);
if (err)
goto out_interrupted;
- spin_lock_irq(&mdev->tconn->req_lock);
- err = handle_write_conflicts(mdev, peer_req);
+ spin_lock_irq(&device->resource->req_lock);
+ err = handle_write_conflicts(device, peer_req);
if (err) {
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
if (err == -ENOENT) {
- put_ldev(mdev);
+ put_ldev(device);
return 0;
}
goto out_interrupted;
}
} else {
- update_peer_seq(mdev, peer_seq);
- spin_lock_irq(&mdev->tconn->req_lock);
+ update_peer_seq(peer_device, peer_seq);
+ spin_lock_irq(&device->resource->req_lock);
}
- list_add(&peer_req->w.list, &mdev->active_ee);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ list_add(&peer_req->w.list, &device->active_ee);
+ spin_unlock_irq(&device->resource->req_lock);
- if (mdev->state.conn == C_SYNC_TARGET)
- wait_event(mdev->ee_wait, !overlapping_resync_write(mdev, peer_req));
+ if (device->state.conn == C_SYNC_TARGET)
+ wait_event(device->ee_wait, !overlapping_resync_write(device, peer_req));
- if (mdev->tconn->agreed_pro_version < 100) {
+ if (peer_device->connection->agreed_pro_version < 100) {
rcu_read_lock();
- switch (rcu_dereference(mdev->tconn->net_conf)->wire_protocol) {
+ switch (rcu_dereference(peer_device->connection->net_conf)->wire_protocol) {
case DRBD_PROT_C:
dp_flags |= DP_SEND_WRITE_ACK;
break;
@@ -2245,7 +2273,7 @@ static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi)
if (dp_flags & DP_SEND_WRITE_ACK) {
peer_req->flags |= EE_SEND_WRITE_ACK;
- inc_unacked(mdev);
+ inc_unacked(device);
/* corresponding dec_unacked() in e_end_block()
* respective _drbd_clear_done_ee */
}
@@ -2253,34 +2281,34 @@ static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi)
if (dp_flags & DP_SEND_RECEIVE_ACK) {
/* I really don't like it that the receiver thread
* sends on the msock, but anyways */
- drbd_send_ack(mdev, P_RECV_ACK, peer_req);
+ drbd_send_ack(first_peer_device(device), P_RECV_ACK, peer_req);
}
- if (mdev->state.pdsk < D_INCONSISTENT) {
+ if (device->state.pdsk < D_INCONSISTENT) {
/* In case we have the only disk of the cluster, */
- drbd_set_out_of_sync(mdev, peer_req->i.sector, peer_req->i.size);
+ drbd_set_out_of_sync(device, peer_req->i.sector, peer_req->i.size);
peer_req->flags |= EE_CALL_AL_COMPLETE_IO;
peer_req->flags &= ~EE_MAY_SET_IN_SYNC;
- drbd_al_begin_io(mdev, &peer_req->i, true);
+ drbd_al_begin_io(device, &peer_req->i, true);
}
- err = drbd_submit_peer_request(mdev, peer_req, rw, DRBD_FAULT_DT_WR);
+ err = drbd_submit_peer_request(device, peer_req, rw, DRBD_FAULT_DT_WR);
if (!err)
return 0;
/* don't care for the reason here */
- dev_err(DEV, "submit failed, triggering re-connect\n");
- spin_lock_irq(&mdev->tconn->req_lock);
+ drbd_err(device, "submit failed, triggering re-connect\n");
+ spin_lock_irq(&device->resource->req_lock);
list_del(&peer_req->w.list);
- drbd_remove_epoch_entry_interval(mdev, peer_req);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ drbd_remove_epoch_entry_interval(device, peer_req);
+ spin_unlock_irq(&device->resource->req_lock);
if (peer_req->flags & EE_CALL_AL_COMPLETE_IO)
- drbd_al_complete_io(mdev, &peer_req->i);
+ drbd_al_complete_io(device, &peer_req->i);
out_interrupted:
- drbd_may_finish_epoch(tconn, peer_req->epoch, EV_PUT + EV_CLEANUP);
- put_ldev(mdev);
- drbd_free_peer_req(mdev, peer_req);
+ drbd_may_finish_epoch(connection, peer_req->epoch, EV_PUT + EV_CLEANUP);
+ put_ldev(device);
+ drbd_free_peer_req(device, peer_req);
return err;
}
@@ -2295,9 +2323,9 @@ out_interrupted:
* The current sync rate used here uses only the most recent two step marks,
* to have a short time average so we can react faster.
*/
-int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector)
+int drbd_rs_should_slow_down(struct drbd_device *device, sector_t sector)
{
- struct gendisk *disk = mdev->ldev->backing_bdev->bd_contains->bd_disk;
+ struct gendisk *disk = device->ldev->backing_bdev->bd_contains->bd_disk;
unsigned long db, dt, dbdt;
struct lc_element *tmp;
int curr_events;
@@ -2305,48 +2333,48 @@ int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector)
unsigned int c_min_rate;
rcu_read_lock();
- c_min_rate = rcu_dereference(mdev->ldev->disk_conf)->c_min_rate;
+ c_min_rate = rcu_dereference(device->ldev->disk_conf)->c_min_rate;
rcu_read_unlock();
/* feature disabled? */
if (c_min_rate == 0)
return 0;
- spin_lock_irq(&mdev->al_lock);
- tmp = lc_find(mdev->resync, BM_SECT_TO_EXT(sector));
+ spin_lock_irq(&device->al_lock);
+ tmp = lc_find(device->resync, BM_SECT_TO_EXT(sector));
if (tmp) {
struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce);
if (test_bit(BME_PRIORITY, &bm_ext->flags)) {
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
return 0;
}
/* Do not slow down if app IO is already waiting for this extent */
}
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
curr_events = (int)part_stat_read(&disk->part0, sectors[0]) +
(int)part_stat_read(&disk->part0, sectors[1]) -
- atomic_read(&mdev->rs_sect_ev);
+ atomic_read(&device->rs_sect_ev);
- if (!mdev->rs_last_events || curr_events - mdev->rs_last_events > 64) {
+ if (!device->rs_last_events || curr_events - device->rs_last_events > 64) {
unsigned long rs_left;
int i;
- mdev->rs_last_events = curr_events;
+ device->rs_last_events = curr_events;
/* sync speed average over the last 2*DRBD_SYNC_MARK_STEP,
* approx. */
- i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS;
+ i = (device->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS;
- if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
- rs_left = mdev->ov_left;
+ if (device->state.conn == C_VERIFY_S || device->state.conn == C_VERIFY_T)
+ rs_left = device->ov_left;
else
- rs_left = drbd_bm_total_weight(mdev) - mdev->rs_failed;
+ rs_left = drbd_bm_total_weight(device) - device->rs_failed;
- dt = ((long)jiffies - (long)mdev->rs_mark_time[i]) / HZ;
+ dt = ((long)jiffies - (long)device->rs_mark_time[i]) / HZ;
if (!dt)
dt++;
- db = mdev->rs_mark_left[i] - rs_left;
+ db = device->rs_mark_left[i] - rs_left;
dbdt = Bit2KB(db/dt);
if (dbdt > c_min_rate)
@@ -2356,9 +2384,10 @@ int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector)
}
-static int receive_DataRequest(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_DataRequest(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
sector_t sector;
sector_t capacity;
struct drbd_peer_request *peer_req;
@@ -2367,58 +2396,59 @@ static int receive_DataRequest(struct drbd_tconn *tconn, struct packet_info *pi)
unsigned int fault_type;
struct p_block_req *p = pi->data;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
- capacity = drbd_get_capacity(mdev->this_bdev);
+ device = peer_device->device;
+ capacity = drbd_get_capacity(device->this_bdev);
sector = be64_to_cpu(p->sector);
size = be32_to_cpu(p->blksize);
if (size <= 0 || !IS_ALIGNED(size, 512) || size > DRBD_MAX_BIO_SIZE) {
- dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__,
+ drbd_err(device, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__,
(unsigned long long)sector, size);
return -EINVAL;
}
if (sector + (size>>9) > capacity) {
- dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__,
+ drbd_err(device, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__,
(unsigned long long)sector, size);
return -EINVAL;
}
- if (!get_ldev_if_state(mdev, D_UP_TO_DATE)) {
+ if (!get_ldev_if_state(device, D_UP_TO_DATE)) {
verb = 1;
switch (pi->cmd) {
case P_DATA_REQUEST:
- drbd_send_ack_rp(mdev, P_NEG_DREPLY, p);
+ drbd_send_ack_rp(peer_device, P_NEG_DREPLY, p);
break;
case P_RS_DATA_REQUEST:
case P_CSUM_RS_REQUEST:
case P_OV_REQUEST:
- drbd_send_ack_rp(mdev, P_NEG_RS_DREPLY , p);
+ drbd_send_ack_rp(peer_device, P_NEG_RS_DREPLY , p);
break;
case P_OV_REPLY:
verb = 0;
- dec_rs_pending(mdev);
- drbd_send_ack_ex(mdev, P_OV_RESULT, sector, size, ID_IN_SYNC);
+ dec_rs_pending(device);
+ drbd_send_ack_ex(peer_device, P_OV_RESULT, sector, size, ID_IN_SYNC);
break;
default:
BUG();
}
if (verb && __ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Can not satisfy peer's read request, "
+ drbd_err(device, "Can not satisfy peer's read request, "
"no local data.\n");
/* drain possibly payload */
- return drbd_drain_block(mdev, pi->size);
+ return drbd_drain_block(peer_device, pi->size);
}
/* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD
* "criss-cross" setup, that might cause write-out on some other DRBD,
* which in turn might block on the other node at this very place. */
- peer_req = drbd_alloc_peer_req(mdev, p->block_id, sector, size, GFP_NOIO);
+ peer_req = drbd_alloc_peer_req(peer_device, p->block_id, sector, size, GFP_NOIO);
if (!peer_req) {
- put_ldev(mdev);
+ put_ldev(device);
return -ENOMEM;
}
@@ -2433,7 +2463,7 @@ static int receive_DataRequest(struct drbd_tconn *tconn, struct packet_info *pi)
peer_req->w.cb = w_e_end_rsdata_req;
fault_type = DRBD_FAULT_RS_RD;
/* used in the sector offset progress display */
- mdev->bm_resync_fo = BM_SECT_TO_BIT(sector);
+ device->bm_resync_fo = BM_SECT_TO_BIT(sector);
break;
case P_OV_REPLY:
@@ -2449,19 +2479,19 @@ static int receive_DataRequest(struct drbd_tconn *tconn, struct packet_info *pi)
peer_req->digest = di;
peer_req->flags |= EE_HAS_DIGEST;
- if (drbd_recv_all(mdev->tconn, di->digest, pi->size))
+ if (drbd_recv_all(peer_device->connection, di->digest, pi->size))
goto out_free_e;
if (pi->cmd == P_CSUM_RS_REQUEST) {
- D_ASSERT(mdev->tconn->agreed_pro_version >= 89);
+ D_ASSERT(device, peer_device->connection->agreed_pro_version >= 89);
peer_req->w.cb = w_e_end_csum_rs_req;
/* used in the sector offset progress display */
- mdev->bm_resync_fo = BM_SECT_TO_BIT(sector);
+ device->bm_resync_fo = BM_SECT_TO_BIT(sector);
} else if (pi->cmd == P_OV_REPLY) {
/* track progress, we may need to throttle */
- atomic_add(size >> 9, &mdev->rs_sect_in);
+ atomic_add(size >> 9, &device->rs_sect_in);
peer_req->w.cb = w_e_end_ov_reply;
- dec_rs_pending(mdev);
+ dec_rs_pending(device);
/* drbd_rs_begin_io done when we sent this request,
* but accounting still needs to be done. */
goto submit_for_resync;
@@ -2469,19 +2499,19 @@ static int receive_DataRequest(struct drbd_tconn *tconn, struct packet_info *pi)
break;
case P_OV_REQUEST:
- if (mdev->ov_start_sector == ~(sector_t)0 &&
- mdev->tconn->agreed_pro_version >= 90) {
+ if (device->ov_start_sector == ~(sector_t)0 &&
+ peer_device->connection->agreed_pro_version >= 90) {
unsigned long now = jiffies;
int i;
- mdev->ov_start_sector = sector;
- mdev->ov_position = sector;
- mdev->ov_left = drbd_bm_bits(mdev) - BM_SECT_TO_BIT(sector);
- mdev->rs_total = mdev->ov_left;
+ device->ov_start_sector = sector;
+ device->ov_position = sector;
+ device->ov_left = drbd_bm_bits(device) - BM_SECT_TO_BIT(sector);
+ device->rs_total = device->ov_left;
for (i = 0; i < DRBD_SYNC_MARKS; i++) {
- mdev->rs_mark_left[i] = mdev->ov_left;
- mdev->rs_mark_time[i] = now;
+ device->rs_mark_left[i] = device->ov_left;
+ device->rs_mark_time[i] = now;
}
- dev_info(DEV, "Online Verify start sector: %llu\n",
+ drbd_info(device, "Online Verify start sector: %llu\n",
(unsigned long long)sector);
}
peer_req->w.cb = w_e_end_ov_req;
@@ -2514,57 +2544,61 @@ static int receive_DataRequest(struct drbd_tconn *tconn, struct packet_info *pi)
* we would also throttle its application reads.
* In that case, throttling is done on the SyncTarget only.
*/
- if (mdev->state.peer != R_PRIMARY && drbd_rs_should_slow_down(mdev, sector))
+ if (device->state.peer != R_PRIMARY && drbd_rs_should_slow_down(device, sector))
schedule_timeout_uninterruptible(HZ/10);
- if (drbd_rs_begin_io(mdev, sector))
+ if (drbd_rs_begin_io(device, sector))
goto out_free_e;
submit_for_resync:
- atomic_add(size >> 9, &mdev->rs_sect_ev);
+ atomic_add(size >> 9, &device->rs_sect_ev);
submit:
- inc_unacked(mdev);
- spin_lock_irq(&mdev->tconn->req_lock);
- list_add_tail(&peer_req->w.list, &mdev->read_ee);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ inc_unacked(device);
+ spin_lock_irq(&device->resource->req_lock);
+ list_add_tail(&peer_req->w.list, &device->read_ee);
+ spin_unlock_irq(&device->resource->req_lock);
- if (drbd_submit_peer_request(mdev, peer_req, READ, fault_type) == 0)
+ if (drbd_submit_peer_request(device, peer_req, READ, fault_type) == 0)
return 0;
/* don't care for the reason here */
- dev_err(DEV, "submit failed, triggering re-connect\n");
- spin_lock_irq(&mdev->tconn->req_lock);
+ drbd_err(device, "submit failed, triggering re-connect\n");
+ spin_lock_irq(&device->resource->req_lock);
list_del(&peer_req->w.list);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
/* no drbd_rs_complete_io(), we are dropping the connection anyways */
out_free_e:
- put_ldev(mdev);
- drbd_free_peer_req(mdev, peer_req);
+ put_ldev(device);
+ drbd_free_peer_req(device, peer_req);
return -EIO;
}
-static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local)
+/**
+ * drbd_asb_recover_0p - Recover after split-brain with no remaining primaries
+ */
+static int drbd_asb_recover_0p(struct drbd_peer_device *peer_device) __must_hold(local)
{
+ struct drbd_device *device = peer_device->device;
int self, peer, rv = -100;
unsigned long ch_self, ch_peer;
enum drbd_after_sb_p after_sb_0p;
- self = mdev->ldev->md.uuid[UI_BITMAP] & 1;
- peer = mdev->p_uuid[UI_BITMAP] & 1;
+ self = device->ldev->md.uuid[UI_BITMAP] & 1;
+ peer = device->p_uuid[UI_BITMAP] & 1;
- ch_peer = mdev->p_uuid[UI_SIZE];
- ch_self = mdev->comm_bm_set;
+ ch_peer = device->p_uuid[UI_SIZE];
+ ch_self = device->comm_bm_set;
rcu_read_lock();
- after_sb_0p = rcu_dereference(mdev->tconn->net_conf)->after_sb_0p;
+ after_sb_0p = rcu_dereference(peer_device->connection->net_conf)->after_sb_0p;
rcu_read_unlock();
switch (after_sb_0p) {
case ASB_CONSENSUS:
case ASB_DISCARD_SECONDARY:
case ASB_CALL_HELPER:
case ASB_VIOLENTLY:
- dev_err(DEV, "Configuration error.\n");
+ drbd_err(device, "Configuration error.\n");
break;
case ASB_DISCONNECT:
break;
@@ -2588,11 +2622,11 @@ static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local)
break;
}
/* Else fall through to one of the other strategies... */
- dev_warn(DEV, "Discard younger/older primary did not find a decision\n"
+ drbd_warn(device, "Discard younger/older primary did not find a decision\n"
"Using discard-least-changes instead\n");
case ASB_DISCARD_ZERO_CHG:
if (ch_peer == 0 && ch_self == 0) {
- rv = test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags)
+ rv = test_bit(RESOLVE_CONFLICTS, &peer_device->connection->flags)
? -1 : 1;
break;
} else {
@@ -2608,7 +2642,7 @@ static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local)
rv = 1;
else /* ( ch_self == ch_peer ) */
/* Well, then use something else. */
- rv = test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags)
+ rv = test_bit(RESOLVE_CONFLICTS, &peer_device->connection->flags)
? -1 : 1;
break;
case ASB_DISCARD_LOCAL:
@@ -2621,13 +2655,17 @@ static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local)
return rv;
}
-static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local)
+/**
+ * drbd_asb_recover_1p - Recover after split-brain with one remaining primary
+ */
+static int drbd_asb_recover_1p(struct drbd_peer_device *peer_device) __must_hold(local)
{
+ struct drbd_device *device = peer_device->device;
int hg, rv = -100;
enum drbd_after_sb_p after_sb_1p;
rcu_read_lock();
- after_sb_1p = rcu_dereference(mdev->tconn->net_conf)->after_sb_1p;
+ after_sb_1p = rcu_dereference(peer_device->connection->net_conf)->after_sb_1p;
rcu_read_unlock();
switch (after_sb_1p) {
case ASB_DISCARD_YOUNGER_PRI:
@@ -2636,35 +2674,35 @@ static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local)
case ASB_DISCARD_LOCAL:
case ASB_DISCARD_REMOTE:
case ASB_DISCARD_ZERO_CHG:
- dev_err(DEV, "Configuration error.\n");
+ drbd_err(device, "Configuration error.\n");
break;
case ASB_DISCONNECT:
break;
case ASB_CONSENSUS:
- hg = drbd_asb_recover_0p(mdev);
- if (hg == -1 && mdev->state.role == R_SECONDARY)
+ hg = drbd_asb_recover_0p(peer_device);
+ if (hg == -1 && device->state.role == R_SECONDARY)
rv = hg;
- if (hg == 1 && mdev->state.role == R_PRIMARY)
+ if (hg == 1 && device->state.role == R_PRIMARY)
rv = hg;
break;
case ASB_VIOLENTLY:
- rv = drbd_asb_recover_0p(mdev);
+ rv = drbd_asb_recover_0p(peer_device);
break;
case ASB_DISCARD_SECONDARY:
- return mdev->state.role == R_PRIMARY ? 1 : -1;
+ return device->state.role == R_PRIMARY ? 1 : -1;
case ASB_CALL_HELPER:
- hg = drbd_asb_recover_0p(mdev);
- if (hg == -1 && mdev->state.role == R_PRIMARY) {
+ hg = drbd_asb_recover_0p(peer_device);
+ if (hg == -1 && device->state.role == R_PRIMARY) {
enum drbd_state_rv rv2;
/* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE,
* we might be here in C_WF_REPORT_PARAMS which is transient.
* we do not need to wait for the after state change work either. */
- rv2 = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY));
+ rv2 = drbd_change_state(device, CS_VERBOSE, NS(role, R_SECONDARY));
if (rv2 != SS_SUCCESS) {
- drbd_khelper(mdev, "pri-lost-after-sb");
+ drbd_khelper(device, "pri-lost-after-sb");
} else {
- dev_warn(DEV, "Successfully gave up primary role.\n");
+ drbd_warn(device, "Successfully gave up primary role.\n");
rv = hg;
}
} else
@@ -2674,13 +2712,17 @@ static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local)
return rv;
}
-static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local)
+/**
+ * drbd_asb_recover_2p - Recover after split-brain with two remaining primaries
+ */
+static int drbd_asb_recover_2p(struct drbd_peer_device *peer_device) __must_hold(local)
{
+ struct drbd_device *device = peer_device->device;
int hg, rv = -100;
enum drbd_after_sb_p after_sb_2p;
rcu_read_lock();
- after_sb_2p = rcu_dereference(mdev->tconn->net_conf)->after_sb_2p;
+ after_sb_2p = rcu_dereference(peer_device->connection->net_conf)->after_sb_2p;
rcu_read_unlock();
switch (after_sb_2p) {
case ASB_DISCARD_YOUNGER_PRI:
@@ -2691,26 +2733,26 @@ static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local)
case ASB_CONSENSUS:
case ASB_DISCARD_SECONDARY:
case ASB_DISCARD_ZERO_CHG:
- dev_err(DEV, "Configuration error.\n");
+ drbd_err(device, "Configuration error.\n");
break;
case ASB_VIOLENTLY:
- rv = drbd_asb_recover_0p(mdev);
+ rv = drbd_asb_recover_0p(peer_device);
break;
case ASB_DISCONNECT:
break;
case ASB_CALL_HELPER:
- hg = drbd_asb_recover_0p(mdev);
+ hg = drbd_asb_recover_0p(peer_device);
if (hg == -1) {
enum drbd_state_rv rv2;
/* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE,
* we might be here in C_WF_REPORT_PARAMS which is transient.
* we do not need to wait for the after state change work either. */
- rv2 = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY));
+ rv2 = drbd_change_state(device, CS_VERBOSE, NS(role, R_SECONDARY));
if (rv2 != SS_SUCCESS) {
- drbd_khelper(mdev, "pri-lost-after-sb");
+ drbd_khelper(device, "pri-lost-after-sb");
} else {
- dev_warn(DEV, "Successfully gave up primary role.\n");
+ drbd_warn(device, "Successfully gave up primary role.\n");
rv = hg;
}
} else
@@ -2720,14 +2762,14 @@ static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local)
return rv;
}
-static void drbd_uuid_dump(struct drbd_conf *mdev, char *text, u64 *uuid,
+static void drbd_uuid_dump(struct drbd_device *device, char *text, u64 *uuid,
u64 bits, u64 flags)
{
if (!uuid) {
- dev_info(DEV, "%s uuid info vanished while I was looking!\n", text);
+ drbd_info(device, "%s uuid info vanished while I was looking!\n", text);
return;
}
- dev_info(DEV, "%s %016llX:%016llX:%016llX:%016llX bits:%llu flags:%llX\n",
+ drbd_info(device, "%s %016llX:%016llX:%016llX:%016llX bits:%llu flags:%llX\n",
text,
(unsigned long long)uuid[UI_CURRENT],
(unsigned long long)uuid[UI_BITMAP],
@@ -2749,13 +2791,13 @@ static void drbd_uuid_dump(struct drbd_conf *mdev, char *text, u64 *uuid,
-1091 requires proto 91
-1096 requires proto 96
*/
-static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(local)
+static int drbd_uuid_compare(struct drbd_device *device, int *rule_nr) __must_hold(local)
{
u64 self, peer;
int i, j;
- self = mdev->ldev->md.uuid[UI_CURRENT] & ~((u64)1);
- peer = mdev->p_uuid[UI_CURRENT] & ~((u64)1);
+ self = device->ldev->md.uuid[UI_CURRENT] & ~((u64)1);
+ peer = device->p_uuid[UI_CURRENT] & ~((u64)1);
*rule_nr = 10;
if (self == UUID_JUST_CREATED && peer == UUID_JUST_CREATED)
@@ -2774,46 +2816,46 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l
if (self == peer) {
int rct, dc; /* roles at crash time */
- if (mdev->p_uuid[UI_BITMAP] == (u64)0 && mdev->ldev->md.uuid[UI_BITMAP] != (u64)0) {
+ if (device->p_uuid[UI_BITMAP] == (u64)0 && device->ldev->md.uuid[UI_BITMAP] != (u64)0) {
- if (mdev->tconn->agreed_pro_version < 91)
+ if (first_peer_device(device)->connection->agreed_pro_version < 91)
return -1091;
- if ((mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) &&
- (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1))) {
- dev_info(DEV, "was SyncSource, missed the resync finished event, corrected myself:\n");
- drbd_uuid_move_history(mdev);
- mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP];
- mdev->ldev->md.uuid[UI_BITMAP] = 0;
+ if ((device->ldev->md.uuid[UI_BITMAP] & ~((u64)1)) == (device->p_uuid[UI_HISTORY_START] & ~((u64)1)) &&
+ (device->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (device->p_uuid[UI_HISTORY_START + 1] & ~((u64)1))) {
+ drbd_info(device, "was SyncSource, missed the resync finished event, corrected myself:\n");
+ drbd_uuid_move_history(device);
+ device->ldev->md.uuid[UI_HISTORY_START] = device->ldev->md.uuid[UI_BITMAP];
+ device->ldev->md.uuid[UI_BITMAP] = 0;
- drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid,
- mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0);
+ drbd_uuid_dump(device, "self", device->ldev->md.uuid,
+ device->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(device) : 0, 0);
*rule_nr = 34;
} else {
- dev_info(DEV, "was SyncSource (peer failed to write sync_uuid)\n");
+ drbd_info(device, "was SyncSource (peer failed to write sync_uuid)\n");
*rule_nr = 36;
}
return 1;
}
- if (mdev->ldev->md.uuid[UI_BITMAP] == (u64)0 && mdev->p_uuid[UI_BITMAP] != (u64)0) {
+ if (device->ldev->md.uuid[UI_BITMAP] == (u64)0 && device->p_uuid[UI_BITMAP] != (u64)0) {
- if (mdev->tconn->agreed_pro_version < 91)
+ if (first_peer_device(device)->connection->agreed_pro_version < 91)
return -1091;
- if ((mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_BITMAP] & ~((u64)1)) &&
- (mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1))) {
- dev_info(DEV, "was SyncTarget, peer missed the resync finished event, corrected peer:\n");
+ if ((device->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (device->p_uuid[UI_BITMAP] & ~((u64)1)) &&
+ (device->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) == (device->p_uuid[UI_HISTORY_START] & ~((u64)1))) {
+ drbd_info(device, "was SyncTarget, peer missed the resync finished event, corrected peer:\n");
- mdev->p_uuid[UI_HISTORY_START + 1] = mdev->p_uuid[UI_HISTORY_START];
- mdev->p_uuid[UI_HISTORY_START] = mdev->p_uuid[UI_BITMAP];
- mdev->p_uuid[UI_BITMAP] = 0UL;
+ device->p_uuid[UI_HISTORY_START + 1] = device->p_uuid[UI_HISTORY_START];
+ device->p_uuid[UI_HISTORY_START] = device->p_uuid[UI_BITMAP];
+ device->p_uuid[UI_BITMAP] = 0UL;
- drbd_uuid_dump(mdev, "peer", mdev->p_uuid, mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]);
+ drbd_uuid_dump(device, "peer", device->p_uuid, device->p_uuid[UI_SIZE], device->p_uuid[UI_FLAGS]);
*rule_nr = 35;
} else {
- dev_info(DEV, "was SyncTarget (failed to write sync_uuid)\n");
+ drbd_info(device, "was SyncTarget (failed to write sync_uuid)\n");
*rule_nr = 37;
}
@@ -2821,8 +2863,8 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l
}
/* Common power [off|failure] */
- rct = (test_bit(CRASHED_PRIMARY, &mdev->flags) ? 1 : 0) +
- (mdev->p_uuid[UI_FLAGS] & 2);
+ rct = (test_bit(CRASHED_PRIMARY, &device->flags) ? 1 : 0) +
+ (device->p_uuid[UI_FLAGS] & 2);
/* lowest bit is set when we were primary,
* next bit (weight 2) is set when peer was primary */
*rule_nr = 40;
@@ -2832,72 +2874,72 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l
case 1: /* self_pri && !peer_pri */ return 1;
case 2: /* !self_pri && peer_pri */ return -1;
case 3: /* self_pri && peer_pri */
- dc = test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags);
+ dc = test_bit(RESOLVE_CONFLICTS, &first_peer_device(device)->connection->flags);
return dc ? -1 : 1;
}
}
*rule_nr = 50;
- peer = mdev->p_uuid[UI_BITMAP] & ~((u64)1);
+ peer = device->p_uuid[UI_BITMAP] & ~((u64)1);
if (self == peer)
return -1;
*rule_nr = 51;
- peer = mdev->p_uuid[UI_HISTORY_START] & ~((u64)1);
+ peer = device->p_uuid[UI_HISTORY_START] & ~((u64)1);
if (self == peer) {
- if (mdev->tconn->agreed_pro_version < 96 ?
- (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) ==
- (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1)) :
- peer + UUID_NEW_BM_OFFSET == (mdev->p_uuid[UI_BITMAP] & ~((u64)1))) {
+ if (first_peer_device(device)->connection->agreed_pro_version < 96 ?
+ (device->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) ==
+ (device->p_uuid[UI_HISTORY_START + 1] & ~((u64)1)) :
+ peer + UUID_NEW_BM_OFFSET == (device->p_uuid[UI_BITMAP] & ~((u64)1))) {
/* The last P_SYNC_UUID did not get though. Undo the last start of
resync as sync source modifications of the peer's UUIDs. */
- if (mdev->tconn->agreed_pro_version < 91)
+ if (first_peer_device(device)->connection->agreed_pro_version < 91)
return -1091;
- mdev->p_uuid[UI_BITMAP] = mdev->p_uuid[UI_HISTORY_START];
- mdev->p_uuid[UI_HISTORY_START] = mdev->p_uuid[UI_HISTORY_START + 1];
+ device->p_uuid[UI_BITMAP] = device->p_uuid[UI_HISTORY_START];
+ device->p_uuid[UI_HISTORY_START] = device->p_uuid[UI_HISTORY_START + 1];
- dev_info(DEV, "Lost last syncUUID packet, corrected:\n");
- drbd_uuid_dump(mdev, "peer", mdev->p_uuid, mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]);
+ drbd_info(device, "Lost last syncUUID packet, corrected:\n");
+ drbd_uuid_dump(device, "peer", device->p_uuid, device->p_uuid[UI_SIZE], device->p_uuid[UI_FLAGS]);
return -1;
}
}
*rule_nr = 60;
- self = mdev->ldev->md.uuid[UI_CURRENT] & ~((u64)1);
+ self = device->ldev->md.uuid[UI_CURRENT] & ~((u64)1);
for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) {
- peer = mdev->p_uuid[i] & ~((u64)1);
+ peer = device->p_uuid[i] & ~((u64)1);
if (self == peer)
return -2;
}
*rule_nr = 70;
- self = mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1);
- peer = mdev->p_uuid[UI_CURRENT] & ~((u64)1);
+ self = device->ldev->md.uuid[UI_BITMAP] & ~((u64)1);
+ peer = device->p_uuid[UI_CURRENT] & ~((u64)1);
if (self == peer)
return 1;
*rule_nr = 71;
- self = mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1);
+ self = device->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1);
if (self == peer) {
- if (mdev->tconn->agreed_pro_version < 96 ?
- (mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) ==
- (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) :
- self + UUID_NEW_BM_OFFSET == (mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1))) {
+ if (first_peer_device(device)->connection->agreed_pro_version < 96 ?
+ (device->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) ==
+ (device->p_uuid[UI_HISTORY_START] & ~((u64)1)) :
+ self + UUID_NEW_BM_OFFSET == (device->ldev->md.uuid[UI_BITMAP] & ~((u64)1))) {
/* The last P_SYNC_UUID did not get though. Undo the last start of
resync as sync source modifications of our UUIDs. */
- if (mdev->tconn->agreed_pro_version < 91)
+ if (first_peer_device(device)->connection->agreed_pro_version < 91)
return -1091;
- __drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_HISTORY_START]);
- __drbd_uuid_set(mdev, UI_HISTORY_START, mdev->ldev->md.uuid[UI_HISTORY_START + 1]);
+ __drbd_uuid_set(device, UI_BITMAP, device->ldev->md.uuid[UI_HISTORY_START]);
+ __drbd_uuid_set(device, UI_HISTORY_START, device->ldev->md.uuid[UI_HISTORY_START + 1]);
- dev_info(DEV, "Last syncUUID did not get through, corrected:\n");
- drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid,
- mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0);
+ drbd_info(device, "Last syncUUID did not get through, corrected:\n");
+ drbd_uuid_dump(device, "self", device->ldev->md.uuid,
+ device->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(device) : 0, 0);
return 1;
}
@@ -2905,24 +2947,24 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l
*rule_nr = 80;
- peer = mdev->p_uuid[UI_CURRENT] & ~((u64)1);
+ peer = device->p_uuid[UI_CURRENT] & ~((u64)1);
for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) {
- self = mdev->ldev->md.uuid[i] & ~((u64)1);
+ self = device->ldev->md.uuid[i] & ~((u64)1);
if (self == peer)
return 2;
}
*rule_nr = 90;
- self = mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1);
- peer = mdev->p_uuid[UI_BITMAP] & ~((u64)1);
+ self = device->ldev->md.uuid[UI_BITMAP] & ~((u64)1);
+ peer = device->p_uuid[UI_BITMAP] & ~((u64)1);
if (self == peer && self != ((u64)0))
return 100;
*rule_nr = 100;
for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) {
- self = mdev->ldev->md.uuid[i] & ~((u64)1);
+ self = device->ldev->md.uuid[i] & ~((u64)1);
for (j = UI_HISTORY_START; j <= UI_HISTORY_END; j++) {
- peer = mdev->p_uuid[j] & ~((u64)1);
+ peer = device->p_uuid[j] & ~((u64)1);
if (self == peer)
return -100;
}
@@ -2934,36 +2976,38 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l
/* drbd_sync_handshake() returns the new conn state on success, or
CONN_MASK (-1) on failure.
*/
-static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_role peer_role,
+static enum drbd_conns drbd_sync_handshake(struct drbd_peer_device *peer_device,
+ enum drbd_role peer_role,
enum drbd_disk_state peer_disk) __must_hold(local)
{
+ struct drbd_device *device = peer_device->device;
enum drbd_conns rv = C_MASK;
enum drbd_disk_state mydisk;
struct net_conf *nc;
int hg, rule_nr, rr_conflict, tentative;
- mydisk = mdev->state.disk;
+ mydisk = device->state.disk;
if (mydisk == D_NEGOTIATING)
- mydisk = mdev->new_state_tmp.disk;
+ mydisk = device->new_state_tmp.disk;
- dev_info(DEV, "drbd_sync_handshake:\n");
+ drbd_info(device, "drbd_sync_handshake:\n");
- spin_lock_irq(&mdev->ldev->md.uuid_lock);
- drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid, mdev->comm_bm_set, 0);
- drbd_uuid_dump(mdev, "peer", mdev->p_uuid,
- mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]);
+ spin_lock_irq(&device->ldev->md.uuid_lock);
+ drbd_uuid_dump(device, "self", device->ldev->md.uuid, device->comm_bm_set, 0);
+ drbd_uuid_dump(device, "peer", device->p_uuid,
+ device->p_uuid[UI_SIZE], device->p_uuid[UI_FLAGS]);
- hg = drbd_uuid_compare(mdev, &rule_nr);
- spin_unlock_irq(&mdev->ldev->md.uuid_lock);
+ hg = drbd_uuid_compare(device, &rule_nr);
+ spin_unlock_irq(&device->ldev->md.uuid_lock);
- dev_info(DEV, "uuid_compare()=%d by rule %d\n", hg, rule_nr);
+ drbd_info(device, "uuid_compare()=%d by rule %d\n", hg, rule_nr);
if (hg == -1000) {
- dev_alert(DEV, "Unrelated data, aborting!\n");
+ drbd_alert(device, "Unrelated data, aborting!\n");
return C_MASK;
}
if (hg < -1000) {
- dev_alert(DEV, "To resolve this both sides have to support at least protocol %d\n", -hg - 1000);
+ drbd_alert(device, "To resolve this both sides have to support at least protocol %d\n", -hg - 1000);
return C_MASK;
}
@@ -2973,38 +3017,38 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol
hg = mydisk > D_INCONSISTENT ? 1 : -1;
if (f)
hg = hg*2;
- dev_info(DEV, "Becoming sync %s due to disk states.\n",
+ drbd_info(device, "Becoming sync %s due to disk states.\n",
hg > 0 ? "source" : "target");
}
if (abs(hg) == 100)
- drbd_khelper(mdev, "initial-split-brain");
+ drbd_khelper(device, "initial-split-brain");
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(peer_device->connection->net_conf);
if (hg == 100 || (hg == -100 && nc->always_asbp)) {
- int pcount = (mdev->state.role == R_PRIMARY)
+ int pcount = (device->state.role == R_PRIMARY)
+ (peer_role == R_PRIMARY);
int forced = (hg == -100);
switch (pcount) {
case 0:
- hg = drbd_asb_recover_0p(mdev);
+ hg = drbd_asb_recover_0p(peer_device);
break;
case 1:
- hg = drbd_asb_recover_1p(mdev);
+ hg = drbd_asb_recover_1p(peer_device);
break;
case 2:
- hg = drbd_asb_recover_2p(mdev);
+ hg = drbd_asb_recover_2p(peer_device);
break;
}
if (abs(hg) < 100) {
- dev_warn(DEV, "Split-Brain detected, %d primaries, "
+ drbd_warn(device, "Split-Brain detected, %d primaries, "
"automatically solved. Sync from %s node\n",
pcount, (hg < 0) ? "peer" : "this");
if (forced) {
- dev_warn(DEV, "Doing a full sync, since"
+ drbd_warn(device, "Doing a full sync, since"
" UUIDs where ambiguous.\n");
hg = hg*2;
}
@@ -3012,13 +3056,13 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol
}
if (hg == -100) {
- if (test_bit(DISCARD_MY_DATA, &mdev->flags) && !(mdev->p_uuid[UI_FLAGS]&1))
+ if (test_bit(DISCARD_MY_DATA, &device->flags) && !(device->p_uuid[UI_FLAGS]&1))
hg = -1;
- if (!test_bit(DISCARD_MY_DATA, &mdev->flags) && (mdev->p_uuid[UI_FLAGS]&1))
+ if (!test_bit(DISCARD_MY_DATA, &device->flags) && (device->p_uuid[UI_FLAGS]&1))
hg = 1;
if (abs(hg) < 100)
- dev_warn(DEV, "Split-Brain detected, manually solved. "
+ drbd_warn(device, "Split-Brain detected, manually solved. "
"Sync from %s node\n",
(hg < 0) ? "peer" : "this");
}
@@ -3031,44 +3075,44 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol
* after an attempted attach on a diskless node.
* We just refuse to attach -- well, we drop the "connection"
* to that disk, in a way... */
- dev_alert(DEV, "Split-Brain detected but unresolved, dropping connection!\n");
- drbd_khelper(mdev, "split-brain");
+ drbd_alert(device, "Split-Brain detected but unresolved, dropping connection!\n");
+ drbd_khelper(device, "split-brain");
return C_MASK;
}
if (hg > 0 && mydisk <= D_INCONSISTENT) {
- dev_err(DEV, "I shall become SyncSource, but I am inconsistent!\n");
+ drbd_err(device, "I shall become SyncSource, but I am inconsistent!\n");
return C_MASK;
}
if (hg < 0 && /* by intention we do not use mydisk here. */
- mdev->state.role == R_PRIMARY && mdev->state.disk >= D_CONSISTENT) {
+ device->state.role == R_PRIMARY && device->state.disk >= D_CONSISTENT) {
switch (rr_conflict) {
case ASB_CALL_HELPER:
- drbd_khelper(mdev, "pri-lost");
+ drbd_khelper(device, "pri-lost");
/* fall through */
case ASB_DISCONNECT:
- dev_err(DEV, "I shall become SyncTarget, but I am primary!\n");
+ drbd_err(device, "I shall become SyncTarget, but I am primary!\n");
return C_MASK;
case ASB_VIOLENTLY:
- dev_warn(DEV, "Becoming SyncTarget, violating the stable-data"
+ drbd_warn(device, "Becoming SyncTarget, violating the stable-data"
"assumption\n");
}
}
- if (tentative || test_bit(CONN_DRY_RUN, &mdev->tconn->flags)) {
+ if (tentative || test_bit(CONN_DRY_RUN, &peer_device->connection->flags)) {
if (hg == 0)
- dev_info(DEV, "dry-run connect: No resync, would become Connected immediately.\n");
+ drbd_info(device, "dry-run connect: No resync, would become Connected immediately.\n");
else
- dev_info(DEV, "dry-run connect: Would become %s, doing a %s resync.",
+ drbd_info(device, "dry-run connect: Would become %s, doing a %s resync.",
drbd_conn_str(hg > 0 ? C_SYNC_SOURCE : C_SYNC_TARGET),
abs(hg) >= 2 ? "full" : "bit-map based");
return C_MASK;
}
if (abs(hg) >= 2) {
- dev_info(DEV, "Writing the whole bitmap, full sync required after drbd_sync_handshake.\n");
- if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from sync_handshake",
+ drbd_info(device, "Writing the whole bitmap, full sync required after drbd_sync_handshake.\n");
+ if (drbd_bitmap_io(device, &drbd_bmio_set_n_write, "set_n_write from sync_handshake",
BM_LOCKED_SET_ALLOWED))
return C_MASK;
}
@@ -3079,9 +3123,9 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol
rv = C_WF_BITMAP_T;
} else {
rv = C_CONNECTED;
- if (drbd_bm_total_weight(mdev)) {
- dev_info(DEV, "No resync, but %lu bits in bitmap!\n",
- drbd_bm_total_weight(mdev));
+ if (drbd_bm_total_weight(device)) {
+ drbd_info(device, "No resync, but %lu bits in bitmap!\n",
+ drbd_bm_total_weight(device));
}
}
@@ -3102,7 +3146,7 @@ static enum drbd_after_sb_p convert_after_sb(enum drbd_after_sb_p peer)
return peer;
}
-static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_protocol(struct drbd_connection *connection, struct packet_info *pi)
{
struct p_protocol *p = pi->data;
enum drbd_after_sb_p p_after_sb_0p, p_after_sb_1p, p_after_sb_2p;
@@ -3120,58 +3164,58 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi)
cf = be32_to_cpu(p->conn_flags);
p_discard_my_data = cf & CF_DISCARD_MY_DATA;
- if (tconn->agreed_pro_version >= 87) {
+ if (connection->agreed_pro_version >= 87) {
int err;
if (pi->size > sizeof(integrity_alg))
return -EIO;
- err = drbd_recv_all(tconn, integrity_alg, pi->size);
+ err = drbd_recv_all(connection, integrity_alg, pi->size);
if (err)
return err;
integrity_alg[SHARED_SECRET_MAX - 1] = 0;
}
if (pi->cmd != P_PROTOCOL_UPDATE) {
- clear_bit(CONN_DRY_RUN, &tconn->flags);
+ clear_bit(CONN_DRY_RUN, &connection->flags);
if (cf & CF_DRY_RUN)
- set_bit(CONN_DRY_RUN, &tconn->flags);
+ set_bit(CONN_DRY_RUN, &connection->flags);
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
if (p_proto != nc->wire_protocol) {
- conn_err(tconn, "incompatible %s settings\n", "protocol");
+ drbd_err(connection, "incompatible %s settings\n", "protocol");
goto disconnect_rcu_unlock;
}
if (convert_after_sb(p_after_sb_0p) != nc->after_sb_0p) {
- conn_err(tconn, "incompatible %s settings\n", "after-sb-0pri");
+ drbd_err(connection, "incompatible %s settings\n", "after-sb-0pri");
goto disconnect_rcu_unlock;
}
if (convert_after_sb(p_after_sb_1p) != nc->after_sb_1p) {
- conn_err(tconn, "incompatible %s settings\n", "after-sb-1pri");
+ drbd_err(connection, "incompatible %s settings\n", "after-sb-1pri");
goto disconnect_rcu_unlock;
}
if (convert_after_sb(p_after_sb_2p) != nc->after_sb_2p) {
- conn_err(tconn, "incompatible %s settings\n", "after-sb-2pri");
+ drbd_err(connection, "incompatible %s settings\n", "after-sb-2pri");
goto disconnect_rcu_unlock;
}
if (p_discard_my_data && nc->discard_my_data) {
- conn_err(tconn, "incompatible %s settings\n", "discard-my-data");
+ drbd_err(connection, "incompatible %s settings\n", "discard-my-data");
goto disconnect_rcu_unlock;
}
if (p_two_primaries != nc->two_primaries) {
- conn_err(tconn, "incompatible %s settings\n", "allow-two-primaries");
+ drbd_err(connection, "incompatible %s settings\n", "allow-two-primaries");
goto disconnect_rcu_unlock;
}
if (strcmp(integrity_alg, nc->integrity_alg)) {
- conn_err(tconn, "incompatible %s settings\n", "data-integrity-alg");
+ drbd_err(connection, "incompatible %s settings\n", "data-integrity-alg");
goto disconnect_rcu_unlock;
}
@@ -3192,7 +3236,7 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi)
peer_integrity_tfm = crypto_alloc_hash(integrity_alg, 0, CRYPTO_ALG_ASYNC);
if (!peer_integrity_tfm) {
- conn_err(tconn, "peer data-integrity-alg %s not supported\n",
+ drbd_err(connection, "peer data-integrity-alg %s not supported\n",
integrity_alg);
goto disconnect;
}
@@ -3201,20 +3245,20 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi)
int_dig_in = kmalloc(hash_size, GFP_KERNEL);
int_dig_vv = kmalloc(hash_size, GFP_KERNEL);
if (!(int_dig_in && int_dig_vv)) {
- conn_err(tconn, "Allocation of buffers for data integrity checking failed\n");
+ drbd_err(connection, "Allocation of buffers for data integrity checking failed\n");
goto disconnect;
}
}
new_net_conf = kmalloc(sizeof(struct net_conf), GFP_KERNEL);
if (!new_net_conf) {
- conn_err(tconn, "Allocation of new net_conf failed\n");
+ drbd_err(connection, "Allocation of new net_conf failed\n");
goto disconnect;
}
- mutex_lock(&tconn->data.mutex);
- mutex_lock(&tconn->conf_update);
- old_net_conf = tconn->net_conf;
+ mutex_lock(&connection->data.mutex);
+ mutex_lock(&connection->resource->conf_update);
+ old_net_conf = connection->net_conf;
*new_net_conf = *old_net_conf;
new_net_conf->wire_protocol = p_proto;
@@ -3223,19 +3267,19 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi)
new_net_conf->after_sb_2p = convert_after_sb(p_after_sb_2p);
new_net_conf->two_primaries = p_two_primaries;
- rcu_assign_pointer(tconn->net_conf, new_net_conf);
- mutex_unlock(&tconn->conf_update);
- mutex_unlock(&tconn->data.mutex);
+ rcu_assign_pointer(connection->net_conf, new_net_conf);
+ mutex_unlock(&connection->resource->conf_update);
+ mutex_unlock(&connection->data.mutex);
- crypto_free_hash(tconn->peer_integrity_tfm);
- kfree(tconn->int_dig_in);
- kfree(tconn->int_dig_vv);
- tconn->peer_integrity_tfm = peer_integrity_tfm;
- tconn->int_dig_in = int_dig_in;
- tconn->int_dig_vv = int_dig_vv;
+ crypto_free_hash(connection->peer_integrity_tfm);
+ kfree(connection->int_dig_in);
+ kfree(connection->int_dig_vv);
+ connection->peer_integrity_tfm = peer_integrity_tfm;
+ connection->int_dig_in = int_dig_in;
+ connection->int_dig_vv = int_dig_vv;
if (strcmp(old_net_conf->integrity_alg, integrity_alg))
- conn_info(tconn, "peer data-integrity-alg: %s\n",
+ drbd_info(connection, "peer data-integrity-alg: %s\n",
integrity_alg[0] ? integrity_alg : "(none)");
synchronize_rcu();
@@ -3248,7 +3292,7 @@ disconnect:
crypto_free_hash(peer_integrity_tfm);
kfree(int_dig_in);
kfree(int_dig_vv);
- conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
return -EIO;
}
@@ -3257,7 +3301,8 @@ disconnect:
* return: NULL (alg name was "")
* ERR_PTR(error) if something goes wrong
* or the crypto hash ptr, if it worked out ok. */
-struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev,
+static
+struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_device *device,
const char *alg, const char *name)
{
struct crypto_hash *tfm;
@@ -3267,21 +3312,21 @@ struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev,
tfm = crypto_alloc_hash(alg, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm)) {
- dev_err(DEV, "Can not allocate \"%s\" as %s (reason: %ld)\n",
+ drbd_err(device, "Can not allocate \"%s\" as %s (reason: %ld)\n",
alg, name, PTR_ERR(tfm));
return tfm;
}
return tfm;
}
-static int ignore_remaining_packet(struct drbd_tconn *tconn, struct packet_info *pi)
+static int ignore_remaining_packet(struct drbd_connection *connection, struct packet_info *pi)
{
- void *buffer = tconn->data.rbuf;
+ void *buffer = connection->data.rbuf;
int size = pi->size;
while (size) {
int s = min_t(int, size, DRBD_SOCKET_BUFFER_SIZE);
- s = drbd_recv(tconn, buffer, s);
+ s = drbd_recv(connection, buffer, s);
if (s <= 0) {
if (s < 0)
return s;
@@ -3305,30 +3350,32 @@ static int ignore_remaining_packet(struct drbd_tconn *tconn, struct packet_info
*
* (We can also end up here if drbd is misconfigured.)
*/
-static int config_unknown_volume(struct drbd_tconn *tconn, struct packet_info *pi)
+static int config_unknown_volume(struct drbd_connection *connection, struct packet_info *pi)
{
- conn_warn(tconn, "%s packet received for volume %u, which is not configured locally\n",
+ drbd_warn(connection, "%s packet received for volume %u, which is not configured locally\n",
cmdname(pi->cmd), pi->vnr);
- return ignore_remaining_packet(tconn, pi);
+ return ignore_remaining_packet(connection, pi);
}
-static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_SyncParam(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_rs_param_95 *p;
unsigned int header_size, data_size, exp_max_sz;
struct crypto_hash *verify_tfm = NULL;
struct crypto_hash *csums_tfm = NULL;
struct net_conf *old_net_conf, *new_net_conf = NULL;
struct disk_conf *old_disk_conf = NULL, *new_disk_conf = NULL;
- const int apv = tconn->agreed_pro_version;
+ const int apv = connection->agreed_pro_version;
struct fifo_buffer *old_plan = NULL, *new_plan = NULL;
int fifo_size = 0;
int err;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
- return config_unknown_volume(tconn, pi);
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
+ return config_unknown_volume(connection, pi);
+ device = peer_device->device;
exp_max_sz = apv <= 87 ? sizeof(struct p_rs_param)
: apv == 88 ? sizeof(struct p_rs_param)
@@ -3337,7 +3384,7 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
: /* apv >= 95 */ sizeof(struct p_rs_param_95);
if (pi->size > exp_max_sz) {
- dev_err(DEV, "SyncParam packet too long: received %u, expected <= %u bytes\n",
+ drbd_err(device, "SyncParam packet too long: received %u, expected <= %u bytes\n",
pi->size, exp_max_sz);
return -EIO;
}
@@ -3348,33 +3395,33 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
} else if (apv <= 94) {
header_size = sizeof(struct p_rs_param_89);
data_size = pi->size - header_size;
- D_ASSERT(data_size == 0);
+ D_ASSERT(device, data_size == 0);
} else {
header_size = sizeof(struct p_rs_param_95);
data_size = pi->size - header_size;
- D_ASSERT(data_size == 0);
+ D_ASSERT(device, data_size == 0);
}
/* initialize verify_alg and csums_alg */
p = pi->data;
memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX);
- err = drbd_recv_all(mdev->tconn, p, header_size);
+ err = drbd_recv_all(peer_device->connection, p, header_size);
if (err)
return err;
- mutex_lock(&mdev->tconn->conf_update);
- old_net_conf = mdev->tconn->net_conf;
- if (get_ldev(mdev)) {
+ mutex_lock(&connection->resource->conf_update);
+ old_net_conf = peer_device->connection->net_conf;
+ if (get_ldev(device)) {
new_disk_conf = kzalloc(sizeof(struct disk_conf), GFP_KERNEL);
if (!new_disk_conf) {
- put_ldev(mdev);
- mutex_unlock(&mdev->tconn->conf_update);
- dev_err(DEV, "Allocation of new disk_conf failed\n");
+ put_ldev(device);
+ mutex_unlock(&connection->resource->conf_update);
+ drbd_err(device, "Allocation of new disk_conf failed\n");
return -ENOMEM;
}
- old_disk_conf = mdev->ldev->disk_conf;
+ old_disk_conf = device->ldev->disk_conf;
*new_disk_conf = *old_disk_conf;
new_disk_conf->resync_rate = be32_to_cpu(p->resync_rate);
@@ -3383,37 +3430,37 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
if (apv >= 88) {
if (apv == 88) {
if (data_size > SHARED_SECRET_MAX || data_size == 0) {
- dev_err(DEV, "verify-alg of wrong size, "
+ drbd_err(device, "verify-alg of wrong size, "
"peer wants %u, accepting only up to %u byte\n",
data_size, SHARED_SECRET_MAX);
err = -EIO;
goto reconnect;
}
- err = drbd_recv_all(mdev->tconn, p->verify_alg, data_size);
+ err = drbd_recv_all(peer_device->connection, p->verify_alg, data_size);
if (err)
goto reconnect;
/* we expect NUL terminated string */
/* but just in case someone tries to be evil */
- D_ASSERT(p->verify_alg[data_size-1] == 0);
+ D_ASSERT(device, p->verify_alg[data_size-1] == 0);
p->verify_alg[data_size-1] = 0;
} else /* apv >= 89 */ {
/* we still expect NUL terminated strings */
/* but just in case someone tries to be evil */
- D_ASSERT(p->verify_alg[SHARED_SECRET_MAX-1] == 0);
- D_ASSERT(p->csums_alg[SHARED_SECRET_MAX-1] == 0);
+ D_ASSERT(device, p->verify_alg[SHARED_SECRET_MAX-1] == 0);
+ D_ASSERT(device, p->csums_alg[SHARED_SECRET_MAX-1] == 0);
p->verify_alg[SHARED_SECRET_MAX-1] = 0;
p->csums_alg[SHARED_SECRET_MAX-1] = 0;
}
if (strcmp(old_net_conf->verify_alg, p->verify_alg)) {
- if (mdev->state.conn == C_WF_REPORT_PARAMS) {
- dev_err(DEV, "Different verify-alg settings. me=\"%s\" peer=\"%s\"\n",
+ if (device->state.conn == C_WF_REPORT_PARAMS) {
+ drbd_err(device, "Different verify-alg settings. me=\"%s\" peer=\"%s\"\n",
old_net_conf->verify_alg, p->verify_alg);
goto disconnect;
}
- verify_tfm = drbd_crypto_alloc_digest_safe(mdev,
+ verify_tfm = drbd_crypto_alloc_digest_safe(device,
p->verify_alg, "verify-alg");
if (IS_ERR(verify_tfm)) {
verify_tfm = NULL;
@@ -3422,12 +3469,12 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
}
if (apv >= 89 && strcmp(old_net_conf->csums_alg, p->csums_alg)) {
- if (mdev->state.conn == C_WF_REPORT_PARAMS) {
- dev_err(DEV, "Different csums-alg settings. me=\"%s\" peer=\"%s\"\n",
+ if (device->state.conn == C_WF_REPORT_PARAMS) {
+ drbd_err(device, "Different csums-alg settings. me=\"%s\" peer=\"%s\"\n",
old_net_conf->csums_alg, p->csums_alg);
goto disconnect;
}
- csums_tfm = drbd_crypto_alloc_digest_safe(mdev,
+ csums_tfm = drbd_crypto_alloc_digest_safe(device,
p->csums_alg, "csums-alg");
if (IS_ERR(csums_tfm)) {
csums_tfm = NULL;
@@ -3442,11 +3489,11 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
new_disk_conf->c_max_rate = be32_to_cpu(p->c_max_rate);
fifo_size = (new_disk_conf->c_plan_ahead * 10 * SLEEP_TIME) / HZ;
- if (fifo_size != mdev->rs_plan_s->size) {
+ if (fifo_size != device->rs_plan_s->size) {
new_plan = fifo_alloc(fifo_size);
if (!new_plan) {
- dev_err(DEV, "kmalloc of fifo_buffer failed");
- put_ldev(mdev);
+ drbd_err(device, "kmalloc of fifo_buffer failed");
+ put_ldev(device);
goto disconnect;
}
}
@@ -3455,7 +3502,7 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
if (verify_tfm || csums_tfm) {
new_net_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL);
if (!new_net_conf) {
- dev_err(DEV, "Allocation of new net_conf failed\n");
+ drbd_err(device, "Allocation of new net_conf failed\n");
goto disconnect;
}
@@ -3464,32 +3511,32 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
if (verify_tfm) {
strcpy(new_net_conf->verify_alg, p->verify_alg);
new_net_conf->verify_alg_len = strlen(p->verify_alg) + 1;
- crypto_free_hash(mdev->tconn->verify_tfm);
- mdev->tconn->verify_tfm = verify_tfm;
- dev_info(DEV, "using verify-alg: \"%s\"\n", p->verify_alg);
+ crypto_free_hash(peer_device->connection->verify_tfm);
+ peer_device->connection->verify_tfm = verify_tfm;
+ drbd_info(device, "using verify-alg: \"%s\"\n", p->verify_alg);
}
if (csums_tfm) {
strcpy(new_net_conf->csums_alg, p->csums_alg);
new_net_conf->csums_alg_len = strlen(p->csums_alg) + 1;
- crypto_free_hash(mdev->tconn->csums_tfm);
- mdev->tconn->csums_tfm = csums_tfm;
- dev_info(DEV, "using csums-alg: \"%s\"\n", p->csums_alg);
+ crypto_free_hash(peer_device->connection->csums_tfm);
+ peer_device->connection->csums_tfm = csums_tfm;
+ drbd_info(device, "using csums-alg: \"%s\"\n", p->csums_alg);
}
- rcu_assign_pointer(tconn->net_conf, new_net_conf);
+ rcu_assign_pointer(connection->net_conf, new_net_conf);
}
}
if (new_disk_conf) {
- rcu_assign_pointer(mdev->ldev->disk_conf, new_disk_conf);
- put_ldev(mdev);
+ rcu_assign_pointer(device->ldev->disk_conf, new_disk_conf);
+ put_ldev(device);
}
if (new_plan) {
- old_plan = mdev->rs_plan_s;
- rcu_assign_pointer(mdev->rs_plan_s, new_plan);
+ old_plan = device->rs_plan_s;
+ rcu_assign_pointer(device->rs_plan_s, new_plan);
}
- mutex_unlock(&mdev->tconn->conf_update);
+ mutex_unlock(&connection->resource->conf_update);
synchronize_rcu();
if (new_net_conf)
kfree(old_net_conf);
@@ -3500,30 +3547,30 @@ static int receive_SyncParam(struct drbd_tconn *tconn, struct packet_info *pi)
reconnect:
if (new_disk_conf) {
- put_ldev(mdev);
+ put_ldev(device);
kfree(new_disk_conf);
}
- mutex_unlock(&mdev->tconn->conf_update);
+ mutex_unlock(&connection->resource->conf_update);
return -EIO;
disconnect:
kfree(new_plan);
if (new_disk_conf) {
- put_ldev(mdev);
+ put_ldev(device);
kfree(new_disk_conf);
}
- mutex_unlock(&mdev->tconn->conf_update);
+ mutex_unlock(&connection->resource->conf_update);
/* just for completeness: actually not needed,
* as this is not reached if csums_tfm was ok. */
crypto_free_hash(csums_tfm);
/* but free the verify_tfm again, if csums_tfm did not work out */
crypto_free_hash(verify_tfm);
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD);
return -EIO;
}
/* warn if the arguments differ by more than 12.5% */
-static void warn_if_differ_considerably(struct drbd_conf *mdev,
+static void warn_if_differ_considerably(struct drbd_device *device,
const char *s, sector_t a, sector_t b)
{
sector_t d;
@@ -3531,54 +3578,56 @@ static void warn_if_differ_considerably(struct drbd_conf *mdev,
return;
d = (a > b) ? (a - b) : (b - a);
if (d > (a>>3) || d > (b>>3))
- dev_warn(DEV, "Considerable difference in %s: %llus vs. %llus\n", s,
+ drbd_warn(device, "Considerable difference in %s: %llus vs. %llus\n", s,
(unsigned long long)a, (unsigned long long)b);
}
-static int receive_sizes(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_sizes(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_sizes *p = pi->data;
enum determine_dev_size dd = DS_UNCHANGED;
sector_t p_size, p_usize, my_usize;
int ldsc = 0; /* local disk size changed */
enum dds_flags ddsf;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
- return config_unknown_volume(tconn, pi);
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
+ return config_unknown_volume(connection, pi);
+ device = peer_device->device;
p_size = be64_to_cpu(p->d_size);
p_usize = be64_to_cpu(p->u_size);
/* just store the peer's disk size for now.
* we still need to figure out whether we accept that. */
- mdev->p_size = p_size;
+ device->p_size = p_size;
- if (get_ldev(mdev)) {
+ if (get_ldev(device)) {
rcu_read_lock();
- my_usize = rcu_dereference(mdev->ldev->disk_conf)->disk_size;
+ my_usize = rcu_dereference(device->ldev->disk_conf)->disk_size;
rcu_read_unlock();
- warn_if_differ_considerably(mdev, "lower level device sizes",
- p_size, drbd_get_max_capacity(mdev->ldev));
- warn_if_differ_considerably(mdev, "user requested size",
+ warn_if_differ_considerably(device, "lower level device sizes",
+ p_size, drbd_get_max_capacity(device->ldev));
+ warn_if_differ_considerably(device, "user requested size",
p_usize, my_usize);
/* if this is the first connect, or an otherwise expected
* param exchange, choose the minimum */
- if (mdev->state.conn == C_WF_REPORT_PARAMS)
+ if (device->state.conn == C_WF_REPORT_PARAMS)
p_usize = min_not_zero(my_usize, p_usize);
/* Never shrink a device with usable data during connect.
But allow online shrinking if we are connected. */
- if (drbd_new_dev_size(mdev, mdev->ldev, p_usize, 0) <
- drbd_get_capacity(mdev->this_bdev) &&
- mdev->state.disk >= D_OUTDATED &&
- mdev->state.conn < C_CONNECTED) {
- dev_err(DEV, "The peer's disk size is too small!\n");
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
- put_ldev(mdev);
+ if (drbd_new_dev_size(device, device->ldev, p_usize, 0) <
+ drbd_get_capacity(device->this_bdev) &&
+ device->state.disk >= D_OUTDATED &&
+ device->state.conn < C_CONNECTED) {
+ drbd_err(device, "The peer's disk size is too small!\n");
+ conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD);
+ put_ldev(device);
return -EIO;
}
@@ -3587,145 +3636,147 @@ static int receive_sizes(struct drbd_tconn *tconn, struct packet_info *pi)
new_disk_conf = kzalloc(sizeof(struct disk_conf), GFP_KERNEL);
if (!new_disk_conf) {
- dev_err(DEV, "Allocation of new disk_conf failed\n");
- put_ldev(mdev);
+ drbd_err(device, "Allocation of new disk_conf failed\n");
+ put_ldev(device);
return -ENOMEM;
}
- mutex_lock(&mdev->tconn->conf_update);
- old_disk_conf = mdev->ldev->disk_conf;
+ mutex_lock(&connection->resource->conf_update);
+ old_disk_conf = device->ldev->disk_conf;
*new_disk_conf = *old_disk_conf;
new_disk_conf->disk_size = p_usize;
- rcu_assign_pointer(mdev->ldev->disk_conf, new_disk_conf);
- mutex_unlock(&mdev->tconn->conf_update);
+ rcu_assign_pointer(device->ldev->disk_conf, new_disk_conf);
+ mutex_unlock(&connection->resource->conf_update);
synchronize_rcu();
kfree(old_disk_conf);
- dev_info(DEV, "Peer sets u_size to %lu sectors\n",
+ drbd_info(device, "Peer sets u_size to %lu sectors\n",
(unsigned long)my_usize);
}
- put_ldev(mdev);
+ put_ldev(device);
}
ddsf = be16_to_cpu(p->dds_flags);
- if (get_ldev(mdev)) {
- dd = drbd_determine_dev_size(mdev, ddsf, NULL);
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ dd = drbd_determine_dev_size(device, ddsf, NULL);
+ put_ldev(device);
if (dd == DS_ERROR)
return -EIO;
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
} else {
/* I am diskless, need to accept the peer's size. */
- drbd_set_my_capacity(mdev, p_size);
+ drbd_set_my_capacity(device, p_size);
}
- mdev->peer_max_bio_size = be32_to_cpu(p->max_bio_size);
- drbd_reconsider_max_bio_size(mdev);
+ device->peer_max_bio_size = be32_to_cpu(p->max_bio_size);
+ drbd_reconsider_max_bio_size(device);
- if (get_ldev(mdev)) {
- if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev)) {
- mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev);
+ if (get_ldev(device)) {
+ if (device->ldev->known_size != drbd_get_capacity(device->ldev->backing_bdev)) {
+ device->ldev->known_size = drbd_get_capacity(device->ldev->backing_bdev);
ldsc = 1;
}
- put_ldev(mdev);
+ put_ldev(device);
}
- if (mdev->state.conn > C_WF_REPORT_PARAMS) {
+ if (device->state.conn > C_WF_REPORT_PARAMS) {
if (be64_to_cpu(p->c_size) !=
- drbd_get_capacity(mdev->this_bdev) || ldsc) {
+ drbd_get_capacity(device->this_bdev) || ldsc) {
/* we have different sizes, probably peer
* needs to know my new size... */
- drbd_send_sizes(mdev, 0, ddsf);
+ drbd_send_sizes(peer_device, 0, ddsf);
}
- if (test_and_clear_bit(RESIZE_PENDING, &mdev->flags) ||
- (dd == DS_GREW && mdev->state.conn == C_CONNECTED)) {
- if (mdev->state.pdsk >= D_INCONSISTENT &&
- mdev->state.disk >= D_INCONSISTENT) {
+ if (test_and_clear_bit(RESIZE_PENDING, &device->flags) ||
+ (dd == DS_GREW && device->state.conn == C_CONNECTED)) {
+ if (device->state.pdsk >= D_INCONSISTENT &&
+ device->state.disk >= D_INCONSISTENT) {
if (ddsf & DDSF_NO_RESYNC)
- dev_info(DEV, "Resync of new storage suppressed with --assume-clean\n");
+ drbd_info(device, "Resync of new storage suppressed with --assume-clean\n");
else
- resync_after_online_grow(mdev);
+ resync_after_online_grow(device);
} else
- set_bit(RESYNC_AFTER_NEG, &mdev->flags);
+ set_bit(RESYNC_AFTER_NEG, &device->flags);
}
}
return 0;
}
-static int receive_uuids(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_uuids(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_uuids *p = pi->data;
u64 *p_uuid;
int i, updated_uuids = 0;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
- return config_unknown_volume(tconn, pi);
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
+ return config_unknown_volume(connection, pi);
+ device = peer_device->device;
p_uuid = kmalloc(sizeof(u64)*UI_EXTENDED_SIZE, GFP_NOIO);
if (!p_uuid) {
- dev_err(DEV, "kmalloc of p_uuid failed\n");
+ drbd_err(device, "kmalloc of p_uuid failed\n");
return false;
}
for (i = UI_CURRENT; i < UI_EXTENDED_SIZE; i++)
p_uuid[i] = be64_to_cpu(p->uuid[i]);
- kfree(mdev->p_uuid);
- mdev->p_uuid = p_uuid;
+ kfree(device->p_uuid);
+ device->p_uuid = p_uuid;
- if (mdev->state.conn < C_CONNECTED &&
- mdev->state.disk < D_INCONSISTENT &&
- mdev->state.role == R_PRIMARY &&
- (mdev->ed_uuid & ~((u64)1)) != (p_uuid[UI_CURRENT] & ~((u64)1))) {
- dev_err(DEV, "Can only connect to data with current UUID=%016llX\n",
- (unsigned long long)mdev->ed_uuid);
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ if (device->state.conn < C_CONNECTED &&
+ device->state.disk < D_INCONSISTENT &&
+ device->state.role == R_PRIMARY &&
+ (device->ed_uuid & ~((u64)1)) != (p_uuid[UI_CURRENT] & ~((u64)1))) {
+ drbd_err(device, "Can only connect to data with current UUID=%016llX\n",
+ (unsigned long long)device->ed_uuid);
+ conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD);
return -EIO;
}
- if (get_ldev(mdev)) {
+ if (get_ldev(device)) {
int skip_initial_sync =
- mdev->state.conn == C_CONNECTED &&
- mdev->tconn->agreed_pro_version >= 90 &&
- mdev->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED &&
+ device->state.conn == C_CONNECTED &&
+ peer_device->connection->agreed_pro_version >= 90 &&
+ device->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED &&
(p_uuid[UI_FLAGS] & 8);
if (skip_initial_sync) {
- dev_info(DEV, "Accepted new current UUID, preparing to skip initial sync\n");
- drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write,
+ drbd_info(device, "Accepted new current UUID, preparing to skip initial sync\n");
+ drbd_bitmap_io(device, &drbd_bmio_clear_n_write,
"clear_n_write from receive_uuids",
BM_LOCKED_TEST_ALLOWED);
- _drbd_uuid_set(mdev, UI_CURRENT, p_uuid[UI_CURRENT]);
- _drbd_uuid_set(mdev, UI_BITMAP, 0);
- _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
+ _drbd_uuid_set(device, UI_CURRENT, p_uuid[UI_CURRENT]);
+ _drbd_uuid_set(device, UI_BITMAP, 0);
+ _drbd_set_state(_NS2(device, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
CS_VERBOSE, NULL);
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
updated_uuids = 1;
}
- put_ldev(mdev);
- } else if (mdev->state.disk < D_INCONSISTENT &&
- mdev->state.role == R_PRIMARY) {
+ put_ldev(device);
+ } else if (device->state.disk < D_INCONSISTENT &&
+ device->state.role == R_PRIMARY) {
/* I am a diskless primary, the peer just created a new current UUID
for me. */
- updated_uuids = drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]);
+ updated_uuids = drbd_set_ed_uuid(device, p_uuid[UI_CURRENT]);
}
/* Before we test for the disk state, we should wait until an eventually
ongoing cluster wide state change is finished. That is important if
we are primary and are detaching from our disk. We need to see the
new disk state... */
- mutex_lock(mdev->state_mutex);
- mutex_unlock(mdev->state_mutex);
- if (mdev->state.conn >= C_CONNECTED && mdev->state.disk < D_INCONSISTENT)
- updated_uuids |= drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]);
+ mutex_lock(device->state_mutex);
+ mutex_unlock(device->state_mutex);
+ if (device->state.conn >= C_CONNECTED && device->state.disk < D_INCONSISTENT)
+ updated_uuids |= drbd_set_ed_uuid(device, p_uuid[UI_CURRENT]);
if (updated_uuids)
- drbd_print_uuids(mdev, "receiver updated UUIDs to");
+ drbd_print_uuids(device, "receiver updated UUIDs to");
return 0;
}
@@ -3761,38 +3812,40 @@ static union drbd_state convert_state(union drbd_state ps)
return ms;
}
-static int receive_req_state(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_req_state(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_req_state *p = pi->data;
union drbd_state mask, val;
enum drbd_state_rv rv;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
mask.i = be32_to_cpu(p->mask);
val.i = be32_to_cpu(p->val);
- if (test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags) &&
- mutex_is_locked(mdev->state_mutex)) {
- drbd_send_sr_reply(mdev, SS_CONCURRENT_ST_CHG);
+ if (test_bit(RESOLVE_CONFLICTS, &peer_device->connection->flags) &&
+ mutex_is_locked(device->state_mutex)) {
+ drbd_send_sr_reply(peer_device, SS_CONCURRENT_ST_CHG);
return 0;
}
mask = convert_state(mask);
val = convert_state(val);
- rv = drbd_change_state(mdev, CS_VERBOSE, mask, val);
- drbd_send_sr_reply(mdev, rv);
+ rv = drbd_change_state(device, CS_VERBOSE, mask, val);
+ drbd_send_sr_reply(peer_device, rv);
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
return 0;
}
-static int receive_req_conn_state(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_req_conn_state(struct drbd_connection *connection, struct packet_info *pi)
{
struct p_req_state *p = pi->data;
union drbd_state mask, val;
@@ -3801,46 +3854,48 @@ static int receive_req_conn_state(struct drbd_tconn *tconn, struct packet_info *
mask.i = be32_to_cpu(p->mask);
val.i = be32_to_cpu(p->val);
- if (test_bit(RESOLVE_CONFLICTS, &tconn->flags) &&
- mutex_is_locked(&tconn->cstate_mutex)) {
- conn_send_sr_reply(tconn, SS_CONCURRENT_ST_CHG);
+ if (test_bit(RESOLVE_CONFLICTS, &connection->flags) &&
+ mutex_is_locked(&connection->cstate_mutex)) {
+ conn_send_sr_reply(connection, SS_CONCURRENT_ST_CHG);
return 0;
}
mask = convert_state(mask);
val = convert_state(val);
- rv = conn_request_state(tconn, mask, val, CS_VERBOSE | CS_LOCAL_ONLY | CS_IGN_OUTD_FAIL);
- conn_send_sr_reply(tconn, rv);
+ rv = conn_request_state(connection, mask, val, CS_VERBOSE | CS_LOCAL_ONLY | CS_IGN_OUTD_FAIL);
+ conn_send_sr_reply(connection, rv);
return 0;
}
-static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_state(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_state *p = pi->data;
union drbd_state os, ns, peer_state;
enum drbd_disk_state real_peer_disk;
enum chg_state_flags cs_flags;
int rv;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
- return config_unknown_volume(tconn, pi);
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
+ return config_unknown_volume(connection, pi);
+ device = peer_device->device;
peer_state.i = be32_to_cpu(p->state);
real_peer_disk = peer_state.disk;
if (peer_state.disk == D_NEGOTIATING) {
- real_peer_disk = mdev->p_uuid[UI_FLAGS] & 4 ? D_INCONSISTENT : D_CONSISTENT;
- dev_info(DEV, "real peer disk state = %s\n", drbd_disk_str(real_peer_disk));
+ real_peer_disk = device->p_uuid[UI_FLAGS] & 4 ? D_INCONSISTENT : D_CONSISTENT;
+ drbd_info(device, "real peer disk state = %s\n", drbd_disk_str(real_peer_disk));
}
- spin_lock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
retry:
- os = ns = drbd_read_state(mdev);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ os = ns = drbd_read_state(device);
+ spin_unlock_irq(&device->resource->req_lock);
/* If some other part of the code (asender thread, timeout)
* already decided to close the connection again,
@@ -3872,8 +3927,8 @@ static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
* Maybe we should finish it up, too? */
else if (os.conn >= C_SYNC_SOURCE &&
peer_state.conn == C_CONNECTED) {
- if (drbd_bm_total_weight(mdev) <= mdev->rs_failed)
- drbd_resync_finished(mdev);
+ if (drbd_bm_total_weight(device) <= device->rs_failed)
+ drbd_resync_finished(device);
return 0;
}
}
@@ -3881,8 +3936,8 @@ static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
/* explicit verify finished notification, stop sector reached. */
if (os.conn == C_VERIFY_T && os.disk == D_UP_TO_DATE &&
peer_state.conn == C_CONNECTED && real_peer_disk == D_UP_TO_DATE) {
- ov_out_of_sync_print(mdev);
- drbd_resync_finished(mdev);
+ ov_out_of_sync_print(device);
+ drbd_resync_finished(device);
return 0;
}
@@ -3901,8 +3956,8 @@ static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
if (peer_state.conn == C_AHEAD)
ns.conn = C_BEHIND;
- if (mdev->p_uuid && peer_state.disk >= D_NEGOTIATING &&
- get_ldev_if_state(mdev, D_NEGOTIATING)) {
+ if (device->p_uuid && peer_state.disk >= D_NEGOTIATING &&
+ get_ldev_if_state(device, D_NEGOTIATING)) {
int cr; /* consider resync */
/* if we established a new connection */
@@ -3914,7 +3969,7 @@ static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
os.disk == D_NEGOTIATING));
/* if we have both been inconsistent, and the peer has been
* forced to be UpToDate with --overwrite-data */
- cr |= test_bit(CONSIDER_RESYNC, &mdev->flags);
+ cr |= test_bit(CONSIDER_RESYNC, &device->flags);
/* if we had been plain connected, and the admin requested to
* start a sync by "invalidate" or "invalidate-remote" */
cr |= (os.conn == C_CONNECTED &&
@@ -3922,55 +3977,55 @@ static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
peer_state.conn <= C_WF_BITMAP_T));
if (cr)
- ns.conn = drbd_sync_handshake(mdev, peer_state.role, real_peer_disk);
+ ns.conn = drbd_sync_handshake(peer_device, peer_state.role, real_peer_disk);
- put_ldev(mdev);
+ put_ldev(device);
if (ns.conn == C_MASK) {
ns.conn = C_CONNECTED;
- if (mdev->state.disk == D_NEGOTIATING) {
- drbd_force_state(mdev, NS(disk, D_FAILED));
+ if (device->state.disk == D_NEGOTIATING) {
+ drbd_force_state(device, NS(disk, D_FAILED));
} else if (peer_state.disk == D_NEGOTIATING) {
- dev_err(DEV, "Disk attach process on the peer node was aborted.\n");
+ drbd_err(device, "Disk attach process on the peer node was aborted.\n");
peer_state.disk = D_DISKLESS;
real_peer_disk = D_DISKLESS;
} else {
- if (test_and_clear_bit(CONN_DRY_RUN, &mdev->tconn->flags))
+ if (test_and_clear_bit(CONN_DRY_RUN, &peer_device->connection->flags))
return -EIO;
- D_ASSERT(os.conn == C_WF_REPORT_PARAMS);
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ D_ASSERT(device, os.conn == C_WF_REPORT_PARAMS);
+ conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD);
return -EIO;
}
}
}
- spin_lock_irq(&mdev->tconn->req_lock);
- if (os.i != drbd_read_state(mdev).i)
+ spin_lock_irq(&device->resource->req_lock);
+ if (os.i != drbd_read_state(device).i)
goto retry;
- clear_bit(CONSIDER_RESYNC, &mdev->flags);
+ clear_bit(CONSIDER_RESYNC, &device->flags);
ns.peer = peer_state.role;
ns.pdsk = real_peer_disk;
ns.peer_isp = (peer_state.aftr_isp | peer_state.user_isp);
if ((ns.conn == C_CONNECTED || ns.conn == C_WF_BITMAP_S) && ns.disk == D_NEGOTIATING)
- ns.disk = mdev->new_state_tmp.disk;
+ ns.disk = device->new_state_tmp.disk;
cs_flags = CS_VERBOSE + (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED ? 0 : CS_HARD);
- if (ns.pdsk == D_CONSISTENT && drbd_suspended(mdev) && ns.conn == C_CONNECTED && os.conn < C_CONNECTED &&
- test_bit(NEW_CUR_UUID, &mdev->flags)) {
+ if (ns.pdsk == D_CONSISTENT && drbd_suspended(device) && ns.conn == C_CONNECTED && os.conn < C_CONNECTED &&
+ test_bit(NEW_CUR_UUID, &device->flags)) {
/* Do not allow tl_restart(RESEND) for a rebooted peer. We can only allow this
for temporal network outages! */
- spin_unlock_irq(&mdev->tconn->req_lock);
- dev_err(DEV, "Aborting Connect, can not thaw IO with an only Consistent peer\n");
- tl_clear(mdev->tconn);
- drbd_uuid_new_current(mdev);
- clear_bit(NEW_CUR_UUID, &mdev->flags);
- conn_request_state(mdev->tconn, NS2(conn, C_PROTOCOL_ERROR, susp, 0), CS_HARD);
+ spin_unlock_irq(&device->resource->req_lock);
+ drbd_err(device, "Aborting Connect, can not thaw IO with an only Consistent peer\n");
+ tl_clear(peer_device->connection);
+ drbd_uuid_new_current(device);
+ clear_bit(NEW_CUR_UUID, &device->flags);
+ conn_request_state(peer_device->connection, NS2(conn, C_PROTOCOL_ERROR, susp, 0), CS_HARD);
return -EIO;
}
- rv = _drbd_set_state(mdev, ns, cs_flags, NULL);
- ns = drbd_read_state(mdev);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ rv = _drbd_set_state(device, ns, cs_flags, NULL);
+ ns = drbd_read_state(device);
+ spin_unlock_irq(&device->resource->req_lock);
if (rv < SS_SUCCESS) {
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD);
return -EIO;
}
@@ -3980,47 +4035,49 @@ static int receive_state(struct drbd_tconn *tconn, struct packet_info *pi)
/* we want resync, peer has not yet decided to sync... */
/* Nowadays only used when forcing a node into primary role and
setting its disk to UpToDate with that */
- drbd_send_uuids(mdev);
- drbd_send_current_state(mdev);
+ drbd_send_uuids(peer_device);
+ drbd_send_current_state(peer_device);
}
}
- clear_bit(DISCARD_MY_DATA, &mdev->flags);
+ clear_bit(DISCARD_MY_DATA, &device->flags);
- drbd_md_sync(mdev); /* update connected indicator, la_size_sect, ... */
+ drbd_md_sync(device); /* update connected indicator, la_size_sect, ... */
return 0;
}
-static int receive_sync_uuid(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_sync_uuid(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_rs_uuid *p = pi->data;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- wait_event(mdev->misc_wait,
- mdev->state.conn == C_WF_SYNC_UUID ||
- mdev->state.conn == C_BEHIND ||
- mdev->state.conn < C_CONNECTED ||
- mdev->state.disk < D_NEGOTIATING);
+ wait_event(device->misc_wait,
+ device->state.conn == C_WF_SYNC_UUID ||
+ device->state.conn == C_BEHIND ||
+ device->state.conn < C_CONNECTED ||
+ device->state.disk < D_NEGOTIATING);
- /* D_ASSERT( mdev->state.conn == C_WF_SYNC_UUID ); */
+ /* D_ASSERT(device, device->state.conn == C_WF_SYNC_UUID ); */
/* Here the _drbd_uuid_ functions are right, current should
_not_ be rotated into the history */
- if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
- _drbd_uuid_set(mdev, UI_CURRENT, be64_to_cpu(p->uuid));
- _drbd_uuid_set(mdev, UI_BITMAP, 0UL);
+ if (get_ldev_if_state(device, D_NEGOTIATING)) {
+ _drbd_uuid_set(device, UI_CURRENT, be64_to_cpu(p->uuid));
+ _drbd_uuid_set(device, UI_BITMAP, 0UL);
- drbd_print_uuids(mdev, "updated sync uuid");
- drbd_start_resync(mdev, C_SYNC_TARGET);
+ drbd_print_uuids(device, "updated sync uuid");
+ drbd_start_resync(device, C_SYNC_TARGET);
- put_ldev(mdev);
+ put_ldev(device);
} else
- dev_err(DEV, "Ignoring SyncUUID packet!\n");
+ drbd_err(device, "Ignoring SyncUUID packet!\n");
return 0;
}
@@ -4032,27 +4089,27 @@ static int receive_sync_uuid(struct drbd_tconn *tconn, struct packet_info *pi)
* code upon failure.
*/
static int
-receive_bitmap_plain(struct drbd_conf *mdev, unsigned int size,
+receive_bitmap_plain(struct drbd_peer_device *peer_device, unsigned int size,
unsigned long *p, struct bm_xfer_ctx *c)
{
unsigned int data_size = DRBD_SOCKET_BUFFER_SIZE -
- drbd_header_size(mdev->tconn);
+ drbd_header_size(peer_device->connection);
unsigned int num_words = min_t(size_t, data_size / sizeof(*p),
c->bm_words - c->word_offset);
unsigned int want = num_words * sizeof(*p);
int err;
if (want != size) {
- dev_err(DEV, "%s:want (%u) != size (%u)\n", __func__, want, size);
+ drbd_err(peer_device, "%s:want (%u) != size (%u)\n", __func__, want, size);
return -EIO;
}
if (want == 0)
return 0;
- err = drbd_recv_all(mdev->tconn, p, want);
+ err = drbd_recv_all(peer_device->connection, p, want);
if (err)
return err;
- drbd_bm_merge_lel(mdev, c->word_offset, num_words, p);
+ drbd_bm_merge_lel(peer_device->device, c->word_offset, num_words, p);
c->word_offset += num_words;
c->bit_offset = c->word_offset * BITS_PER_LONG;
@@ -4084,7 +4141,7 @@ static int dcbp_get_pad_bits(struct p_compressed_bm *p)
* code upon failure.
*/
static int
-recv_bm_rle_bits(struct drbd_conf *mdev,
+recv_bm_rle_bits(struct drbd_peer_device *peer_device,
struct p_compressed_bm *p,
struct bm_xfer_ctx *c,
unsigned int len)
@@ -4113,14 +4170,14 @@ recv_bm_rle_bits(struct drbd_conf *mdev,
if (toggle) {
e = s + rl -1;
if (e >= c->bm_bits) {
- dev_err(DEV, "bitmap overflow (e:%lu) while decoding bm RLE packet\n", e);
+ drbd_err(peer_device, "bitmap overflow (e:%lu) while decoding bm RLE packet\n", e);
return -EIO;
}
- _drbd_bm_set_bits(mdev, s, e);
+ _drbd_bm_set_bits(peer_device->device, s, e);
}
if (have < bits) {
- dev_err(DEV, "bitmap decoding error: h:%d b:%d la:0x%08llx l:%u/%u\n",
+ drbd_err(peer_device, "bitmap decoding error: h:%d b:%d la:0x%08llx l:%u/%u\n",
have, bits, look_ahead,
(unsigned int)(bs.cur.b - p->code),
(unsigned int)bs.buf_len);
@@ -4153,28 +4210,28 @@ recv_bm_rle_bits(struct drbd_conf *mdev,
* code upon failure.
*/
static int
-decode_bitmap_c(struct drbd_conf *mdev,
+decode_bitmap_c(struct drbd_peer_device *peer_device,
struct p_compressed_bm *p,
struct bm_xfer_ctx *c,
unsigned int len)
{
if (dcbp_get_code(p) == RLE_VLI_Bits)
- return recv_bm_rle_bits(mdev, p, c, len - sizeof(*p));
+ return recv_bm_rle_bits(peer_device, p, c, len - sizeof(*p));
/* other variants had been implemented for evaluation,
* but have been dropped as this one turned out to be "best"
* during all our tests. */
- dev_err(DEV, "receive_bitmap_c: unknown encoding %u\n", p->encoding);
- conn_request_state(mdev->tconn, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
+ drbd_err(peer_device, "receive_bitmap_c: unknown encoding %u\n", p->encoding);
+ conn_request_state(peer_device->connection, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
return -EIO;
}
-void INFO_bm_xfer_stats(struct drbd_conf *mdev,
+void INFO_bm_xfer_stats(struct drbd_device *device,
const char *direction, struct bm_xfer_ctx *c)
{
/* what would it take to transfer it "plaintext" */
- unsigned int header_size = drbd_header_size(mdev->tconn);
+ unsigned int header_size = drbd_header_size(first_peer_device(device)->connection);
unsigned int data_size = DRBD_SOCKET_BUFFER_SIZE - header_size;
unsigned int plain =
header_size * (DIV_ROUND_UP(c->bm_words, data_size) + 1) +
@@ -4198,7 +4255,7 @@ void INFO_bm_xfer_stats(struct drbd_conf *mdev,
r = 1000;
r = 1000 - r;
- dev_info(DEV, "%s bitmap stats [Bytes(packets)]: plain %u(%u), RLE %u(%u), "
+ drbd_info(device, "%s bitmap stats [Bytes(packets)]: plain %u(%u), RLE %u(%u), "
"total %u; compression: %u.%u%%\n",
direction,
c->bytes[1], c->packets[1],
@@ -4214,129 +4271,133 @@ void INFO_bm_xfer_stats(struct drbd_conf *mdev,
in order to be agnostic to the 32 vs 64 bits issue.
returns 0 on failure, 1 if we successfully received it. */
-static int receive_bitmap(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_bitmap(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct bm_xfer_ctx c;
int err;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- drbd_bm_lock(mdev, "receive bitmap", BM_LOCKED_SET_ALLOWED);
+ drbd_bm_lock(device, "receive bitmap", BM_LOCKED_SET_ALLOWED);
/* you are supposed to send additional out-of-sync information
* if you actually set bits during this phase */
c = (struct bm_xfer_ctx) {
- .bm_bits = drbd_bm_bits(mdev),
- .bm_words = drbd_bm_words(mdev),
+ .bm_bits = drbd_bm_bits(device),
+ .bm_words = drbd_bm_words(device),
};
for(;;) {
if (pi->cmd == P_BITMAP)
- err = receive_bitmap_plain(mdev, pi->size, pi->data, &c);
+ err = receive_bitmap_plain(peer_device, pi->size, pi->data, &c);
else if (pi->cmd == P_COMPRESSED_BITMAP) {
/* MAYBE: sanity check that we speak proto >= 90,
* and the feature is enabled! */
struct p_compressed_bm *p = pi->data;
- if (pi->size > DRBD_SOCKET_BUFFER_SIZE - drbd_header_size(tconn)) {
- dev_err(DEV, "ReportCBitmap packet too large\n");
+ if (pi->size > DRBD_SOCKET_BUFFER_SIZE - drbd_header_size(connection)) {
+ drbd_err(device, "ReportCBitmap packet too large\n");
err = -EIO;
goto out;
}
if (pi->size <= sizeof(*p)) {
- dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", pi->size);
+ drbd_err(device, "ReportCBitmap packet too small (l:%u)\n", pi->size);
err = -EIO;
goto out;
}
- err = drbd_recv_all(mdev->tconn, p, pi->size);
+ err = drbd_recv_all(peer_device->connection, p, pi->size);
if (err)
goto out;
- err = decode_bitmap_c(mdev, p, &c, pi->size);
+ err = decode_bitmap_c(peer_device, p, &c, pi->size);
} else {
- dev_warn(DEV, "receive_bitmap: cmd neither ReportBitMap nor ReportCBitMap (is 0x%x)", pi->cmd);
+ drbd_warn(device, "receive_bitmap: cmd neither ReportBitMap nor ReportCBitMap (is 0x%x)", pi->cmd);
err = -EIO;
goto out;
}
c.packets[pi->cmd == P_BITMAP]++;
- c.bytes[pi->cmd == P_BITMAP] += drbd_header_size(tconn) + pi->size;
+ c.bytes[pi->cmd == P_BITMAP] += drbd_header_size(connection) + pi->size;
if (err <= 0) {
if (err < 0)
goto out;
break;
}
- err = drbd_recv_header(mdev->tconn, pi);
+ err = drbd_recv_header(peer_device->connection, pi);
if (err)
goto out;
}
- INFO_bm_xfer_stats(mdev, "receive", &c);
+ INFO_bm_xfer_stats(device, "receive", &c);
- if (mdev->state.conn == C_WF_BITMAP_T) {
+ if (device->state.conn == C_WF_BITMAP_T) {
enum drbd_state_rv rv;
- err = drbd_send_bitmap(mdev);
+ err = drbd_send_bitmap(device);
if (err)
goto out;
/* Omit CS_ORDERED with this state transition to avoid deadlocks. */
- rv = _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE);
- D_ASSERT(rv == SS_SUCCESS);
- } else if (mdev->state.conn != C_WF_BITMAP_S) {
+ rv = _drbd_request_state(device, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE);
+ D_ASSERT(device, rv == SS_SUCCESS);
+ } else if (device->state.conn != C_WF_BITMAP_S) {
/* admin may have requested C_DISCONNECTING,
* other threads may have noticed network errors */
- dev_info(DEV, "unexpected cstate (%s) in receive_bitmap\n",
- drbd_conn_str(mdev->state.conn));
+ drbd_info(device, "unexpected cstate (%s) in receive_bitmap\n",
+ drbd_conn_str(device->state.conn));
}
err = 0;
out:
- drbd_bm_unlock(mdev);
- if (!err && mdev->state.conn == C_WF_BITMAP_S)
- drbd_start_resync(mdev, C_SYNC_SOURCE);
+ drbd_bm_unlock(device);
+ if (!err && device->state.conn == C_WF_BITMAP_S)
+ drbd_start_resync(device, C_SYNC_SOURCE);
return err;
}
-static int receive_skip(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_skip(struct drbd_connection *connection, struct packet_info *pi)
{
- conn_warn(tconn, "skipping unknown optional packet type %d, l: %d!\n",
+ drbd_warn(connection, "skipping unknown optional packet type %d, l: %d!\n",
pi->cmd, pi->size);
- return ignore_remaining_packet(tconn, pi);
+ return ignore_remaining_packet(connection, pi);
}
-static int receive_UnplugRemote(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_UnplugRemote(struct drbd_connection *connection, struct packet_info *pi)
{
/* Make sure we've acked all the TCP data associated
* with the data requests being unplugged */
- drbd_tcp_quickack(tconn->data.socket);
+ drbd_tcp_quickack(connection->data.socket);
return 0;
}
-static int receive_out_of_sync(struct drbd_tconn *tconn, struct packet_info *pi)
+static int receive_out_of_sync(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_block_desc *p = pi->data;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- switch (mdev->state.conn) {
+ switch (device->state.conn) {
case C_WF_SYNC_UUID:
case C_WF_BITMAP_T:
case C_BEHIND:
break;
default:
- dev_err(DEV, "ASSERT FAILED cstate = %s, expected: WFSyncUUID|WFBitMapT|Behind\n",
- drbd_conn_str(mdev->state.conn));
+ drbd_err(device, "ASSERT FAILED cstate = %s, expected: WFSyncUUID|WFBitMapT|Behind\n",
+ drbd_conn_str(device->state.conn));
}
- drbd_set_out_of_sync(mdev, be64_to_cpu(p->sector), be32_to_cpu(p->blksize));
+ drbd_set_out_of_sync(device, be64_to_cpu(p->sector), be32_to_cpu(p->blksize));
return 0;
}
@@ -4344,7 +4405,7 @@ static int receive_out_of_sync(struct drbd_tconn *tconn, struct packet_info *pi)
struct data_cmd {
int expect_payload;
size_t pkt_size;
- int (*fn)(struct drbd_tconn *, struct packet_info *);
+ int (*fn)(struct drbd_connection *, struct packet_info *);
};
static struct data_cmd drbd_cmd_handler[] = {
@@ -4374,43 +4435,43 @@ static struct data_cmd drbd_cmd_handler[] = {
[P_PROTOCOL_UPDATE] = { 1, sizeof(struct p_protocol), receive_protocol },
};
-static void drbdd(struct drbd_tconn *tconn)
+static void drbdd(struct drbd_connection *connection)
{
struct packet_info pi;
size_t shs; /* sub header size */
int err;
- while (get_t_state(&tconn->receiver) == RUNNING) {
+ while (get_t_state(&connection->receiver) == RUNNING) {
struct data_cmd *cmd;
- drbd_thread_current_set_cpu(&tconn->receiver);
- if (drbd_recv_header(tconn, &pi))
+ drbd_thread_current_set_cpu(&connection->receiver);
+ if (drbd_recv_header(connection, &pi))
goto err_out;
cmd = &drbd_cmd_handler[pi.cmd];
if (unlikely(pi.cmd >= ARRAY_SIZE(drbd_cmd_handler) || !cmd->fn)) {
- conn_err(tconn, "Unexpected data packet %s (0x%04x)",
+ drbd_err(connection, "Unexpected data packet %s (0x%04x)",
cmdname(pi.cmd), pi.cmd);
goto err_out;
}
shs = cmd->pkt_size;
if (pi.size > shs && !cmd->expect_payload) {
- conn_err(tconn, "No payload expected %s l:%d\n",
+ drbd_err(connection, "No payload expected %s l:%d\n",
cmdname(pi.cmd), pi.size);
goto err_out;
}
if (shs) {
- err = drbd_recv_all_warn(tconn, pi.data, shs);
+ err = drbd_recv_all_warn(connection, pi.data, shs);
if (err)
goto err_out;
pi.size -= shs;
}
- err = cmd->fn(tconn, &pi);
+ err = cmd->fn(connection, &pi);
if (err) {
- conn_err(tconn, "error receiving %s, e: %d l: %d!\n",
+ drbd_err(connection, "error receiving %s, e: %d l: %d!\n",
cmdname(pi.cmd), err, pi.size);
goto err_out;
}
@@ -4418,27 +4479,16 @@ static void drbdd(struct drbd_tconn *tconn)
return;
err_out:
- conn_request_state(tconn, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
-}
-
-void conn_flush_workqueue(struct drbd_tconn *tconn)
-{
- struct drbd_wq_barrier barr;
-
- barr.w.cb = w_prev_work_done;
- barr.w.tconn = tconn;
- init_completion(&barr.done);
- drbd_queue_work(&tconn->sender_work, &barr.w);
- wait_for_completion(&barr.done);
+ conn_request_state(connection, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
}
-static void conn_disconnect(struct drbd_tconn *tconn)
+static void conn_disconnect(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
enum drbd_conns oc;
int vnr;
- if (tconn->cstate == C_STANDALONE)
+ if (connection->cstate == C_STANDALONE)
return;
/* We are about to start the cleanup after connection loss.
@@ -4446,54 +4496,56 @@ static void conn_disconnect(struct drbd_tconn *tconn)
* Usually we should be in some network failure state already,
* but just in case we are not, we fix it up here.
*/
- conn_request_state(tconn, NS(conn, C_NETWORK_FAILURE), CS_HARD);
+ conn_request_state(connection, NS(conn, C_NETWORK_FAILURE), CS_HARD);
/* asender does not clean up anything. it must not interfere, either */
- drbd_thread_stop(&tconn->asender);
- drbd_free_sock(tconn);
+ drbd_thread_stop(&connection->asender);
+ drbd_free_sock(connection);
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- kref_get(&mdev->kref);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ kref_get(&device->kref);
rcu_read_unlock();
- drbd_disconnected(mdev);
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ drbd_disconnected(peer_device);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
}
rcu_read_unlock();
- if (!list_empty(&tconn->current_epoch->list))
- conn_err(tconn, "ASSERTION FAILED: tconn->current_epoch->list not empty\n");
+ if (!list_empty(&connection->current_epoch->list))
+ drbd_err(connection, "ASSERTION FAILED: connection->current_epoch->list not empty\n");
/* ok, no more ee's on the fly, it is safe to reset the epoch_size */
- atomic_set(&tconn->current_epoch->epoch_size, 0);
- tconn->send.seen_any_write_yet = false;
+ atomic_set(&connection->current_epoch->epoch_size, 0);
+ connection->send.seen_any_write_yet = false;
- conn_info(tconn, "Connection closed\n");
+ drbd_info(connection, "Connection closed\n");
- if (conn_highest_role(tconn) == R_PRIMARY && conn_highest_pdsk(tconn) >= D_UNKNOWN)
- conn_try_outdate_peer_async(tconn);
+ if (conn_highest_role(connection) == R_PRIMARY && conn_highest_pdsk(connection) >= D_UNKNOWN)
+ conn_try_outdate_peer_async(connection);
- spin_lock_irq(&tconn->req_lock);
- oc = tconn->cstate;
+ spin_lock_irq(&connection->resource->req_lock);
+ oc = connection->cstate;
if (oc >= C_UNCONNECTED)
- _conn_request_state(tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE);
+ _conn_request_state(connection, NS(conn, C_UNCONNECTED), CS_VERBOSE);
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
if (oc == C_DISCONNECTING)
- conn_request_state(tconn, NS(conn, C_STANDALONE), CS_VERBOSE | CS_HARD);
+ conn_request_state(connection, NS(conn, C_STANDALONE), CS_VERBOSE | CS_HARD);
}
-static int drbd_disconnected(struct drbd_conf *mdev)
+static int drbd_disconnected(struct drbd_peer_device *peer_device)
{
+ struct drbd_device *device = peer_device->device;
unsigned int i;
/* wait for current activity to cease. */
- spin_lock_irq(&mdev->tconn->req_lock);
- _drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
- _drbd_wait_ee_list_empty(mdev, &mdev->sync_ee);
- _drbd_wait_ee_list_empty(mdev, &mdev->read_ee);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ _drbd_wait_ee_list_empty(device, &device->active_ee);
+ _drbd_wait_ee_list_empty(device, &device->sync_ee);
+ _drbd_wait_ee_list_empty(device, &device->read_ee);
+ spin_unlock_irq(&device->resource->req_lock);
/* We do not have data structures that would allow us to
* get the rs_pending_cnt down to 0 again.
@@ -4505,42 +4557,42 @@ static int drbd_disconnected(struct drbd_conf *mdev)
* resync_LRU. The resync_LRU tracks the whole operation including
* the disk-IO, while the rs_pending_cnt only tracks the blocks
* on the fly. */
- drbd_rs_cancel_all(mdev);
- mdev->rs_total = 0;
- mdev->rs_failed = 0;
- atomic_set(&mdev->rs_pending_cnt, 0);
- wake_up(&mdev->misc_wait);
+ drbd_rs_cancel_all(device);
+ device->rs_total = 0;
+ device->rs_failed = 0;
+ atomic_set(&device->rs_pending_cnt, 0);
+ wake_up(&device->misc_wait);
- del_timer_sync(&mdev->resync_timer);
- resync_timer_fn((unsigned long)mdev);
+ del_timer_sync(&device->resync_timer);
+ resync_timer_fn((unsigned long)device);
/* wait for all w_e_end_data_req, w_e_end_rsdata_req, w_send_barrier,
* w_make_resync_request etc. which may still be on the worker queue
* to be "canceled" */
- drbd_flush_workqueue(mdev);
+ drbd_flush_workqueue(&peer_device->connection->sender_work);
- drbd_finish_peer_reqs(mdev);
+ drbd_finish_peer_reqs(device);
/* This second workqueue flush is necessary, since drbd_finish_peer_reqs()
might have issued a work again. The one before drbd_finish_peer_reqs() is
necessary to reclain net_ee in drbd_finish_peer_reqs(). */
- drbd_flush_workqueue(mdev);
+ drbd_flush_workqueue(&peer_device->connection->sender_work);
/* need to do it again, drbd_finish_peer_reqs() may have populated it
* again via drbd_try_clear_on_disk_bm(). */
- drbd_rs_cancel_all(mdev);
+ drbd_rs_cancel_all(device);
- kfree(mdev->p_uuid);
- mdev->p_uuid = NULL;
+ kfree(device->p_uuid);
+ device->p_uuid = NULL;
- if (!drbd_suspended(mdev))
- tl_clear(mdev->tconn);
+ if (!drbd_suspended(device))
+ tl_clear(peer_device->connection);
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
/* serialize with bitmap writeout triggered by the state change,
* if any. */
- wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
+ wait_event(device->misc_wait, !test_bit(BITMAP_IO, &device->flags));
/* tcp_close and release of sendpage pages can be deferred. I don't
* want to use SO_LINGER, because apparently it can be deferred for
@@ -4549,20 +4601,20 @@ static int drbd_disconnected(struct drbd_conf *mdev)
* Actually we don't care for exactly when the network stack does its
* put_page(), but release our reference on these pages right here.
*/
- i = drbd_free_peer_reqs(mdev, &mdev->net_ee);
+ i = drbd_free_peer_reqs(device, &device->net_ee);
if (i)
- dev_info(DEV, "net_ee not empty, killed %u entries\n", i);
- i = atomic_read(&mdev->pp_in_use_by_net);
+ drbd_info(device, "net_ee not empty, killed %u entries\n", i);
+ i = atomic_read(&device->pp_in_use_by_net);
if (i)
- dev_info(DEV, "pp_in_use_by_net = %d, expected 0\n", i);
- i = atomic_read(&mdev->pp_in_use);
+ drbd_info(device, "pp_in_use_by_net = %d, expected 0\n", i);
+ i = atomic_read(&device->pp_in_use);
if (i)
- dev_info(DEV, "pp_in_use = %d, expected 0\n", i);
+ drbd_info(device, "pp_in_use = %d, expected 0\n", i);
- D_ASSERT(list_empty(&mdev->read_ee));
- D_ASSERT(list_empty(&mdev->active_ee));
- D_ASSERT(list_empty(&mdev->sync_ee));
- D_ASSERT(list_empty(&mdev->done_ee));
+ D_ASSERT(device, list_empty(&device->read_ee));
+ D_ASSERT(device, list_empty(&device->active_ee));
+ D_ASSERT(device, list_empty(&device->sync_ee));
+ D_ASSERT(device, list_empty(&device->done_ee));
return 0;
}
@@ -4576,19 +4628,19 @@ static int drbd_disconnected(struct drbd_conf *mdev)
*
* for now, they are expected to be zero, but ignored.
*/
-static int drbd_send_features(struct drbd_tconn *tconn)
+static int drbd_send_features(struct drbd_connection *connection)
{
struct drbd_socket *sock;
struct p_connection_features *p;
- sock = &tconn->data;
- p = conn_prepare_command(tconn, sock);
+ sock = &connection->data;
+ p = conn_prepare_command(connection, sock);
if (!p)
return -EIO;
memset(p, 0, sizeof(*p));
p->protocol_min = cpu_to_be32(PRO_VERSION_MIN);
p->protocol_max = cpu_to_be32(PRO_VERSION_MAX);
- return conn_send_command(tconn, sock, P_CONNECTION_FEATURES, sizeof(*p), NULL, 0);
+ return conn_send_command(connection, sock, P_CONNECTION_FEATURES, sizeof(*p), NULL, 0);
}
/*
@@ -4598,36 +4650,36 @@ static int drbd_send_features(struct drbd_tconn *tconn)
* -1 peer talks different language,
* no point in trying again, please go standalone.
*/
-static int drbd_do_features(struct drbd_tconn *tconn)
+static int drbd_do_features(struct drbd_connection *connection)
{
- /* ASSERT current == tconn->receiver ... */
+ /* ASSERT current == connection->receiver ... */
struct p_connection_features *p;
const int expect = sizeof(struct p_connection_features);
struct packet_info pi;
int err;
- err = drbd_send_features(tconn);
+ err = drbd_send_features(connection);
if (err)
return 0;
- err = drbd_recv_header(tconn, &pi);
+ err = drbd_recv_header(connection, &pi);
if (err)
return 0;
if (pi.cmd != P_CONNECTION_FEATURES) {
- conn_err(tconn, "expected ConnectionFeatures packet, received: %s (0x%04x)\n",
+ drbd_err(connection, "expected ConnectionFeatures packet, received: %s (0x%04x)\n",
cmdname(pi.cmd), pi.cmd);
return -1;
}
if (pi.size != expect) {
- conn_err(tconn, "expected ConnectionFeatures length: %u, received: %u\n",
+ drbd_err(connection, "expected ConnectionFeatures length: %u, received: %u\n",
expect, pi.size);
return -1;
}
p = pi.data;
- err = drbd_recv_all_warn(tconn, p, expect);
+ err = drbd_recv_all_warn(connection, p, expect);
if (err)
return 0;
@@ -4640,15 +4692,15 @@ static int drbd_do_features(struct drbd_tconn *tconn)
PRO_VERSION_MIN > p->protocol_max)
goto incompat;
- tconn->agreed_pro_version = min_t(int, PRO_VERSION_MAX, p->protocol_max);
+ connection->agreed_pro_version = min_t(int, PRO_VERSION_MAX, p->protocol_max);
- conn_info(tconn, "Handshake successful: "
- "Agreed network protocol version %d\n", tconn->agreed_pro_version);
+ drbd_info(connection, "Handshake successful: "
+ "Agreed network protocol version %d\n", connection->agreed_pro_version);
return 1;
incompat:
- conn_err(tconn, "incompatible DRBD dialects: "
+ drbd_err(connection, "incompatible DRBD dialects: "
"I support %d-%d, peer supports %d-%d\n",
PRO_VERSION_MIN, PRO_VERSION_MAX,
p->protocol_min, p->protocol_max);
@@ -4656,10 +4708,10 @@ static int drbd_do_features(struct drbd_tconn *tconn)
}
#if !defined(CONFIG_CRYPTO_HMAC) && !defined(CONFIG_CRYPTO_HMAC_MODULE)
-static int drbd_do_auth(struct drbd_tconn *tconn)
+static int drbd_do_auth(struct drbd_connection *connection)
{
- conn_err(tconn, "This kernel was build without CONFIG_CRYPTO_HMAC.\n");
- conn_err(tconn, "You need to disable 'cram-hmac-alg' in drbd.conf.\n");
+ drbd_err(connection, "This kernel was build without CONFIG_CRYPTO_HMAC.\n");
+ drbd_err(connection, "You need to disable 'cram-hmac-alg' in drbd.conf.\n");
return -1;
}
#else
@@ -4671,7 +4723,7 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
-1 - auth failed, don't try again.
*/
-static int drbd_do_auth(struct drbd_tconn *tconn)
+static int drbd_do_auth(struct drbd_connection *connection)
{
struct drbd_socket *sock;
char my_challenge[CHALLENGE_LEN]; /* 64 Bytes... */
@@ -4690,69 +4742,69 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
/* FIXME: Put the challenge/response into the preallocated socket buffer. */
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
key_len = strlen(nc->shared_secret);
memcpy(secret, nc->shared_secret, key_len);
rcu_read_unlock();
- desc.tfm = tconn->cram_hmac_tfm;
+ desc.tfm = connection->cram_hmac_tfm;
desc.flags = 0;
- rv = crypto_hash_setkey(tconn->cram_hmac_tfm, (u8 *)secret, key_len);
+ rv = crypto_hash_setkey(connection->cram_hmac_tfm, (u8 *)secret, key_len);
if (rv) {
- conn_err(tconn, "crypto_hash_setkey() failed with %d\n", rv);
+ drbd_err(connection, "crypto_hash_setkey() failed with %d\n", rv);
rv = -1;
goto fail;
}
get_random_bytes(my_challenge, CHALLENGE_LEN);
- sock = &tconn->data;
- if (!conn_prepare_command(tconn, sock)) {
+ sock = &connection->data;
+ if (!conn_prepare_command(connection, sock)) {
rv = 0;
goto fail;
}
- rv = !conn_send_command(tconn, sock, P_AUTH_CHALLENGE, 0,
+ rv = !conn_send_command(connection, sock, P_AUTH_CHALLENGE, 0,
my_challenge, CHALLENGE_LEN);
if (!rv)
goto fail;
- err = drbd_recv_header(tconn, &pi);
+ err = drbd_recv_header(connection, &pi);
if (err) {
rv = 0;
goto fail;
}
if (pi.cmd != P_AUTH_CHALLENGE) {
- conn_err(tconn, "expected AuthChallenge packet, received: %s (0x%04x)\n",
+ drbd_err(connection, "expected AuthChallenge packet, received: %s (0x%04x)\n",
cmdname(pi.cmd), pi.cmd);
rv = 0;
goto fail;
}
if (pi.size > CHALLENGE_LEN * 2) {
- conn_err(tconn, "expected AuthChallenge payload too big.\n");
+ drbd_err(connection, "expected AuthChallenge payload too big.\n");
rv = -1;
goto fail;
}
peers_ch = kmalloc(pi.size, GFP_NOIO);
if (peers_ch == NULL) {
- conn_err(tconn, "kmalloc of peers_ch failed\n");
+ drbd_err(connection, "kmalloc of peers_ch failed\n");
rv = -1;
goto fail;
}
- err = drbd_recv_all_warn(tconn, peers_ch, pi.size);
+ err = drbd_recv_all_warn(connection, peers_ch, pi.size);
if (err) {
rv = 0;
goto fail;
}
- resp_size = crypto_hash_digestsize(tconn->cram_hmac_tfm);
+ resp_size = crypto_hash_digestsize(connection->cram_hmac_tfm);
response = kmalloc(resp_size, GFP_NOIO);
if (response == NULL) {
- conn_err(tconn, "kmalloc of response failed\n");
+ drbd_err(connection, "kmalloc of response failed\n");
rv = -1;
goto fail;
}
@@ -4762,40 +4814,40 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
rv = crypto_hash_digest(&desc, &sg, sg.length, response);
if (rv) {
- conn_err(tconn, "crypto_hash_digest() failed with %d\n", rv);
+ drbd_err(connection, "crypto_hash_digest() failed with %d\n", rv);
rv = -1;
goto fail;
}
- if (!conn_prepare_command(tconn, sock)) {
+ if (!conn_prepare_command(connection, sock)) {
rv = 0;
goto fail;
}
- rv = !conn_send_command(tconn, sock, P_AUTH_RESPONSE, 0,
+ rv = !conn_send_command(connection, sock, P_AUTH_RESPONSE, 0,
response, resp_size);
if (!rv)
goto fail;
- err = drbd_recv_header(tconn, &pi);
+ err = drbd_recv_header(connection, &pi);
if (err) {
rv = 0;
goto fail;
}
if (pi.cmd != P_AUTH_RESPONSE) {
- conn_err(tconn, "expected AuthResponse packet, received: %s (0x%04x)\n",
+ drbd_err(connection, "expected AuthResponse packet, received: %s (0x%04x)\n",
cmdname(pi.cmd), pi.cmd);
rv = 0;
goto fail;
}
if (pi.size != resp_size) {
- conn_err(tconn, "expected AuthResponse payload of wrong size\n");
+ drbd_err(connection, "expected AuthResponse payload of wrong size\n");
rv = 0;
goto fail;
}
- err = drbd_recv_all_warn(tconn, response , resp_size);
+ err = drbd_recv_all_warn(connection, response , resp_size);
if (err) {
rv = 0;
goto fail;
@@ -4803,7 +4855,7 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
right_response = kmalloc(resp_size, GFP_NOIO);
if (right_response == NULL) {
- conn_err(tconn, "kmalloc of right_response failed\n");
+ drbd_err(connection, "kmalloc of right_response failed\n");
rv = -1;
goto fail;
}
@@ -4812,7 +4864,7 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
rv = crypto_hash_digest(&desc, &sg, sg.length, right_response);
if (rv) {
- conn_err(tconn, "crypto_hash_digest() failed with %d\n", rv);
+ drbd_err(connection, "crypto_hash_digest() failed with %d\n", rv);
rv = -1;
goto fail;
}
@@ -4820,7 +4872,7 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
rv = !memcmp(response, right_response, resp_size);
if (rv)
- conn_info(tconn, "Peer authenticated using %d bytes HMAC\n",
+ drbd_info(connection, "Peer authenticated using %d bytes HMAC\n",
resp_size);
else
rv = -1;
@@ -4834,163 +4886,169 @@ static int drbd_do_auth(struct drbd_tconn *tconn)
}
#endif
-int drbdd_init(struct drbd_thread *thi)
+int drbd_receiver(struct drbd_thread *thi)
{
- struct drbd_tconn *tconn = thi->tconn;
+ struct drbd_connection *connection = thi->connection;
int h;
- conn_info(tconn, "receiver (re)started\n");
+ drbd_info(connection, "receiver (re)started\n");
do {
- h = conn_connect(tconn);
+ h = conn_connect(connection);
if (h == 0) {
- conn_disconnect(tconn);
+ conn_disconnect(connection);
schedule_timeout_interruptible(HZ);
}
if (h == -1) {
- conn_warn(tconn, "Discarding network configuration.\n");
- conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ drbd_warn(connection, "Discarding network configuration.\n");
+ conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
}
} while (h == 0);
if (h > 0)
- drbdd(tconn);
+ drbdd(connection);
- conn_disconnect(tconn);
+ conn_disconnect(connection);
- conn_info(tconn, "receiver terminated\n");
+ drbd_info(connection, "receiver terminated\n");
return 0;
}
/* ********* acknowledge sender ******** */
-static int got_conn_RqSReply(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_conn_RqSReply(struct drbd_connection *connection, struct packet_info *pi)
{
struct p_req_state_reply *p = pi->data;
int retcode = be32_to_cpu(p->retcode);
if (retcode >= SS_SUCCESS) {
- set_bit(CONN_WD_ST_CHG_OKAY, &tconn->flags);
+ set_bit(CONN_WD_ST_CHG_OKAY, &connection->flags);
} else {
- set_bit(CONN_WD_ST_CHG_FAIL, &tconn->flags);
- conn_err(tconn, "Requested state change failed by peer: %s (%d)\n",
+ set_bit(CONN_WD_ST_CHG_FAIL, &connection->flags);
+ drbd_err(connection, "Requested state change failed by peer: %s (%d)\n",
drbd_set_st_err_str(retcode), retcode);
}
- wake_up(&tconn->ping_wait);
+ wake_up(&connection->ping_wait);
return 0;
}
-static int got_RqSReply(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_RqSReply(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_req_state_reply *p = pi->data;
int retcode = be32_to_cpu(p->retcode);
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- if (test_bit(CONN_WD_ST_CHG_REQ, &tconn->flags)) {
- D_ASSERT(tconn->agreed_pro_version < 100);
- return got_conn_RqSReply(tconn, pi);
+ if (test_bit(CONN_WD_ST_CHG_REQ, &connection->flags)) {
+ D_ASSERT(device, connection->agreed_pro_version < 100);
+ return got_conn_RqSReply(connection, pi);
}
if (retcode >= SS_SUCCESS) {
- set_bit(CL_ST_CHG_SUCCESS, &mdev->flags);
+ set_bit(CL_ST_CHG_SUCCESS, &device->flags);
} else {
- set_bit(CL_ST_CHG_FAIL, &mdev->flags);
- dev_err(DEV, "Requested state change failed by peer: %s (%d)\n",
+ set_bit(CL_ST_CHG_FAIL, &device->flags);
+ drbd_err(device, "Requested state change failed by peer: %s (%d)\n",
drbd_set_st_err_str(retcode), retcode);
}
- wake_up(&mdev->state_wait);
+ wake_up(&device->state_wait);
return 0;
}
-static int got_Ping(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_Ping(struct drbd_connection *connection, struct packet_info *pi)
{
- return drbd_send_ping_ack(tconn);
+ return drbd_send_ping_ack(connection);
}
-static int got_PingAck(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_PingAck(struct drbd_connection *connection, struct packet_info *pi)
{
/* restore idle timeout */
- tconn->meta.socket->sk->sk_rcvtimeo = tconn->net_conf->ping_int*HZ;
- if (!test_and_set_bit(GOT_PING_ACK, &tconn->flags))
- wake_up(&tconn->ping_wait);
+ connection->meta.socket->sk->sk_rcvtimeo = connection->net_conf->ping_int*HZ;
+ if (!test_and_set_bit(GOT_PING_ACK, &connection->flags))
+ wake_up(&connection->ping_wait);
return 0;
}
-static int got_IsInSync(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_IsInSync(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_block_ack *p = pi->data;
sector_t sector = be64_to_cpu(p->sector);
int blksize = be32_to_cpu(p->blksize);
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- D_ASSERT(mdev->tconn->agreed_pro_version >= 89);
+ D_ASSERT(device, peer_device->connection->agreed_pro_version >= 89);
- update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+ update_peer_seq(peer_device, be32_to_cpu(p->seq_num));
- if (get_ldev(mdev)) {
- drbd_rs_complete_io(mdev, sector);
- drbd_set_in_sync(mdev, sector, blksize);
+ if (get_ldev(device)) {
+ drbd_rs_complete_io(device, sector);
+ drbd_set_in_sync(device, sector, blksize);
/* rs_same_csums is supposed to count in units of BM_BLOCK_SIZE */
- mdev->rs_same_csum += (blksize >> BM_BLOCK_SHIFT);
- put_ldev(mdev);
+ device->rs_same_csum += (blksize >> BM_BLOCK_SHIFT);
+ put_ldev(device);
}
- dec_rs_pending(mdev);
- atomic_add(blksize >> 9, &mdev->rs_sect_in);
+ dec_rs_pending(device);
+ atomic_add(blksize >> 9, &device->rs_sect_in);
return 0;
}
static int
-validate_req_change_req_state(struct drbd_conf *mdev, u64 id, sector_t sector,
+validate_req_change_req_state(struct drbd_device *device, u64 id, sector_t sector,
struct rb_root *root, const char *func,
enum drbd_req_event what, bool missing_ok)
{
struct drbd_request *req;
struct bio_and_error m;
- spin_lock_irq(&mdev->tconn->req_lock);
- req = find_request(mdev, root, id, sector, missing_ok, func);
+ spin_lock_irq(&device->resource->req_lock);
+ req = find_request(device, root, id, sector, missing_ok, func);
if (unlikely(!req)) {
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
return -EIO;
}
__req_mod(req, what, &m);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
if (m.bio)
- complete_master_bio(mdev, &m);
+ complete_master_bio(device, &m);
return 0;
}
-static int got_BlockAck(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_BlockAck(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_block_ack *p = pi->data;
sector_t sector = be64_to_cpu(p->sector);
int blksize = be32_to_cpu(p->blksize);
enum drbd_req_event what;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+ update_peer_seq(peer_device, be32_to_cpu(p->seq_num));
if (p->block_id == ID_SYNCER) {
- drbd_set_in_sync(mdev, sector, blksize);
- dec_rs_pending(mdev);
+ drbd_set_in_sync(device, sector, blksize);
+ dec_rs_pending(device);
return 0;
}
switch (pi->cmd) {
@@ -5013,33 +5071,35 @@ static int got_BlockAck(struct drbd_tconn *tconn, struct packet_info *pi)
BUG();
}
- return validate_req_change_req_state(mdev, p->block_id, sector,
- &mdev->write_requests, __func__,
+ return validate_req_change_req_state(device, p->block_id, sector,
+ &device->write_requests, __func__,
what, false);
}
-static int got_NegAck(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_NegAck(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_block_ack *p = pi->data;
sector_t sector = be64_to_cpu(p->sector);
int size = be32_to_cpu(p->blksize);
int err;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+ update_peer_seq(peer_device, be32_to_cpu(p->seq_num));
if (p->block_id == ID_SYNCER) {
- dec_rs_pending(mdev);
- drbd_rs_failed_io(mdev, sector, size);
+ dec_rs_pending(device);
+ drbd_rs_failed_io(device, sector, size);
return 0;
}
- err = validate_req_change_req_state(mdev, p->block_id, sector,
- &mdev->write_requests, __func__,
+ err = validate_req_change_req_state(device, p->block_id, sector,
+ &device->write_requests, __func__,
NEG_ACKED, true);
if (err) {
/* Protocol A has no P_WRITE_ACKs, but has P_NEG_ACKs.
@@ -5047,80 +5107,86 @@ static int got_NegAck(struct drbd_tconn *tconn, struct packet_info *pi)
request is no longer in the collision hash. */
/* In Protocol B we might already have got a P_RECV_ACK
but then get a P_NEG_ACK afterwards. */
- drbd_set_out_of_sync(mdev, sector, size);
+ drbd_set_out_of_sync(device, sector, size);
}
return 0;
}
-static int got_NegDReply(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_NegDReply(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_block_ack *p = pi->data;
sector_t sector = be64_to_cpu(p->sector);
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
- update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+ update_peer_seq(peer_device, be32_to_cpu(p->seq_num));
- dev_err(DEV, "Got NegDReply; Sector %llus, len %u.\n",
+ drbd_err(device, "Got NegDReply; Sector %llus, len %u.\n",
(unsigned long long)sector, be32_to_cpu(p->blksize));
- return validate_req_change_req_state(mdev, p->block_id, sector,
- &mdev->read_requests, __func__,
+ return validate_req_change_req_state(device, p->block_id, sector,
+ &device->read_requests, __func__,
NEG_ACKED, false);
}
-static int got_NegRSDReply(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_NegRSDReply(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
sector_t sector;
int size;
struct p_block_ack *p = pi->data;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
sector = be64_to_cpu(p->sector);
size = be32_to_cpu(p->blksize);
- update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+ update_peer_seq(peer_device, be32_to_cpu(p->seq_num));
- dec_rs_pending(mdev);
+ dec_rs_pending(device);
- if (get_ldev_if_state(mdev, D_FAILED)) {
- drbd_rs_complete_io(mdev, sector);
+ if (get_ldev_if_state(device, D_FAILED)) {
+ drbd_rs_complete_io(device, sector);
switch (pi->cmd) {
case P_NEG_RS_DREPLY:
- drbd_rs_failed_io(mdev, sector, size);
+ drbd_rs_failed_io(device, sector, size);
case P_RS_CANCEL:
break;
default:
BUG();
}
- put_ldev(mdev);
+ put_ldev(device);
}
return 0;
}
-static int got_BarrierAck(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_BarrierAck(struct drbd_connection *connection, struct packet_info *pi)
{
struct p_barrier_ack *p = pi->data;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
- tl_release(tconn, p->barrier, be32_to_cpu(p->set_size));
+ tl_release(connection, p->barrier, be32_to_cpu(p->set_size));
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (mdev->state.conn == C_AHEAD &&
- atomic_read(&mdev->ap_in_flight) == 0 &&
- !test_and_set_bit(AHEAD_TO_SYNC_SOURCE, &mdev->flags)) {
- mdev->start_resync_timer.expires = jiffies + HZ;
- add_timer(&mdev->start_resync_timer);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+
+ if (device->state.conn == C_AHEAD &&
+ atomic_read(&device->ap_in_flight) == 0 &&
+ !test_and_set_bit(AHEAD_TO_SYNC_SOURCE, &device->flags)) {
+ device->start_resync_timer.expires = jiffies + HZ;
+ add_timer(&device->start_resync_timer);
}
}
rcu_read_unlock();
@@ -5128,90 +5194,94 @@ static int got_BarrierAck(struct drbd_tconn *tconn, struct packet_info *pi)
return 0;
}
-static int got_OVResult(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_OVResult(struct drbd_connection *connection, struct packet_info *pi)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
+ struct drbd_device *device;
struct p_block_ack *p = pi->data;
- struct drbd_work *w;
+ struct drbd_device_work *dw;
sector_t sector;
int size;
- mdev = vnr_to_mdev(tconn, pi->vnr);
- if (!mdev)
+ peer_device = conn_peer_device(connection, pi->vnr);
+ if (!peer_device)
return -EIO;
+ device = peer_device->device;
sector = be64_to_cpu(p->sector);
size = be32_to_cpu(p->blksize);
- update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+ update_peer_seq(peer_device, be32_to_cpu(p->seq_num));
if (be64_to_cpu(p->block_id) == ID_OUT_OF_SYNC)
- drbd_ov_out_of_sync_found(mdev, sector, size);
+ drbd_ov_out_of_sync_found(device, sector, size);
else
- ov_out_of_sync_print(mdev);
+ ov_out_of_sync_print(device);
- if (!get_ldev(mdev))
+ if (!get_ldev(device))
return 0;
- drbd_rs_complete_io(mdev, sector);
- dec_rs_pending(mdev);
+ drbd_rs_complete_io(device, sector);
+ dec_rs_pending(device);
- --mdev->ov_left;
+ --device->ov_left;
/* let's advance progress step marks only for every other megabyte */
- if ((mdev->ov_left & 0x200) == 0x200)
- drbd_advance_rs_marks(mdev, mdev->ov_left);
-
- if (mdev->ov_left == 0) {
- w = kmalloc(sizeof(*w), GFP_NOIO);
- if (w) {
- w->cb = w_ov_finished;
- w->mdev = mdev;
- drbd_queue_work(&mdev->tconn->sender_work, w);
+ if ((device->ov_left & 0x200) == 0x200)
+ drbd_advance_rs_marks(device, device->ov_left);
+
+ if (device->ov_left == 0) {
+ dw = kmalloc(sizeof(*dw), GFP_NOIO);
+ if (dw) {
+ dw->w.cb = w_ov_finished;
+ dw->device = device;
+ drbd_queue_work(&peer_device->connection->sender_work, &dw->w);
} else {
- dev_err(DEV, "kmalloc(w) failed.");
- ov_out_of_sync_print(mdev);
- drbd_resync_finished(mdev);
+ drbd_err(device, "kmalloc(dw) failed.");
+ ov_out_of_sync_print(device);
+ drbd_resync_finished(device);
}
}
- put_ldev(mdev);
+ put_ldev(device);
return 0;
}
-static int got_skip(struct drbd_tconn *tconn, struct packet_info *pi)
+static int got_skip(struct drbd_connection *connection, struct packet_info *pi)
{
return 0;
}
-static int tconn_finish_peer_reqs(struct drbd_tconn *tconn)
+static int connection_finish_peer_reqs(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr, not_empty = 0;
do {
- clear_bit(SIGNAL_ASENDER, &tconn->flags);
+ clear_bit(SIGNAL_ASENDER, &connection->flags);
flush_signals(current);
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- kref_get(&mdev->kref);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ kref_get(&device->kref);
rcu_read_unlock();
- if (drbd_finish_peer_reqs(mdev)) {
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ if (drbd_finish_peer_reqs(device)) {
+ kref_put(&device->kref, drbd_destroy_device);
return 1;
}
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
}
- set_bit(SIGNAL_ASENDER, &tconn->flags);
+ set_bit(SIGNAL_ASENDER, &connection->flags);
- spin_lock_irq(&tconn->req_lock);
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- not_empty = !list_empty(&mdev->done_ee);
+ spin_lock_irq(&connection->resource->req_lock);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ not_empty = !list_empty(&device->done_ee);
if (not_empty)
break;
}
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
rcu_read_unlock();
} while (not_empty);
@@ -5220,7 +5290,7 @@ static int tconn_finish_peer_reqs(struct drbd_tconn *tconn)
struct asender_cmd {
size_t pkt_size;
- int (*fn)(struct drbd_tconn *tconn, struct packet_info *);
+ int (*fn)(struct drbd_connection *connection, struct packet_info *);
};
static struct asender_cmd asender_tbl[] = {
@@ -5245,13 +5315,13 @@ static struct asender_cmd asender_tbl[] = {
int drbd_asender(struct drbd_thread *thi)
{
- struct drbd_tconn *tconn = thi->tconn;
+ struct drbd_connection *connection = thi->connection;
struct asender_cmd *cmd = NULL;
struct packet_info pi;
int rv;
- void *buf = tconn->meta.rbuf;
+ void *buf = connection->meta.rbuf;
int received = 0;
- unsigned int header_size = drbd_header_size(tconn);
+ unsigned int header_size = drbd_header_size(connection);
int expect = header_size;
bool ping_timeout_active = false;
struct net_conf *nc;
@@ -5260,45 +5330,45 @@ int drbd_asender(struct drbd_thread *thi)
rv = sched_setscheduler(current, SCHED_RR, &param);
if (rv < 0)
- conn_err(tconn, "drbd_asender: ERROR set priority, ret=%d\n", rv);
+ drbd_err(connection, "drbd_asender: ERROR set priority, ret=%d\n", rv);
while (get_t_state(thi) == RUNNING) {
drbd_thread_current_set_cpu(thi);
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
ping_timeo = nc->ping_timeo;
tcp_cork = nc->tcp_cork;
ping_int = nc->ping_int;
rcu_read_unlock();
- if (test_and_clear_bit(SEND_PING, &tconn->flags)) {
- if (drbd_send_ping(tconn)) {
- conn_err(tconn, "drbd_send_ping has failed\n");
+ if (test_and_clear_bit(SEND_PING, &connection->flags)) {
+ if (drbd_send_ping(connection)) {
+ drbd_err(connection, "drbd_send_ping has failed\n");
goto reconnect;
}
- tconn->meta.socket->sk->sk_rcvtimeo = ping_timeo * HZ / 10;
+ connection->meta.socket->sk->sk_rcvtimeo = ping_timeo * HZ / 10;
ping_timeout_active = true;
}
/* TODO: conditionally cork; it may hurt latency if we cork without
much to send */
if (tcp_cork)
- drbd_tcp_cork(tconn->meta.socket);
- if (tconn_finish_peer_reqs(tconn)) {
- conn_err(tconn, "tconn_finish_peer_reqs() failed\n");
+ drbd_tcp_cork(connection->meta.socket);
+ if (connection_finish_peer_reqs(connection)) {
+ drbd_err(connection, "connection_finish_peer_reqs() failed\n");
goto reconnect;
}
/* but unconditionally uncork unless disabled */
if (tcp_cork)
- drbd_tcp_uncork(tconn->meta.socket);
+ drbd_tcp_uncork(connection->meta.socket);
/* short circuit, recv_msg would return EINTR anyways. */
if (signal_pending(current))
continue;
- rv = drbd_recv_short(tconn->meta.socket, buf, expect-received, 0);
- clear_bit(SIGNAL_ASENDER, &tconn->flags);
+ rv = drbd_recv_short(connection->meta.socket, buf, expect-received, 0);
+ clear_bit(SIGNAL_ASENDER, &connection->flags);
flush_signals(current);
@@ -5316,51 +5386,51 @@ int drbd_asender(struct drbd_thread *thi)
received += rv;
buf += rv;
} else if (rv == 0) {
- if (test_bit(DISCONNECT_SENT, &tconn->flags)) {
+ if (test_bit(DISCONNECT_SENT, &connection->flags)) {
long t;
rcu_read_lock();
- t = rcu_dereference(tconn->net_conf)->ping_timeo * HZ/10;
+ t = rcu_dereference(connection->net_conf)->ping_timeo * HZ/10;
rcu_read_unlock();
- t = wait_event_timeout(tconn->ping_wait,
- tconn->cstate < C_WF_REPORT_PARAMS,
+ t = wait_event_timeout(connection->ping_wait,
+ connection->cstate < C_WF_REPORT_PARAMS,
t);
if (t)
break;
}
- conn_err(tconn, "meta connection shut down by peer.\n");
+ drbd_err(connection, "meta connection shut down by peer.\n");
goto reconnect;
} else if (rv == -EAGAIN) {
/* If the data socket received something meanwhile,
* that is good enough: peer is still alive. */
- if (time_after(tconn->last_received,
- jiffies - tconn->meta.socket->sk->sk_rcvtimeo))
+ if (time_after(connection->last_received,
+ jiffies - connection->meta.socket->sk->sk_rcvtimeo))
continue;
if (ping_timeout_active) {
- conn_err(tconn, "PingAck did not arrive in time.\n");
+ drbd_err(connection, "PingAck did not arrive in time.\n");
goto reconnect;
}
- set_bit(SEND_PING, &tconn->flags);
+ set_bit(SEND_PING, &connection->flags);
continue;
} else if (rv == -EINTR) {
continue;
} else {
- conn_err(tconn, "sock_recvmsg returned %d\n", rv);
+ drbd_err(connection, "sock_recvmsg returned %d\n", rv);
goto reconnect;
}
if (received == expect && cmd == NULL) {
- if (decode_header(tconn, tconn->meta.rbuf, &pi))
+ if (decode_header(connection, connection->meta.rbuf, &pi))
goto reconnect;
cmd = &asender_tbl[pi.cmd];
if (pi.cmd >= ARRAY_SIZE(asender_tbl) || !cmd->fn) {
- conn_err(tconn, "Unexpected meta packet %s (0x%04x)\n",
+ drbd_err(connection, "Unexpected meta packet %s (0x%04x)\n",
cmdname(pi.cmd), pi.cmd);
goto disconnect;
}
expect = header_size + cmd->pkt_size;
if (pi.size != expect - header_size) {
- conn_err(tconn, "Wrong packet size on meta (c: %d, l: %d)\n",
+ drbd_err(connection, "Wrong packet size on meta (c: %d, l: %d)\n",
pi.cmd, pi.size);
goto reconnect;
}
@@ -5368,21 +5438,21 @@ int drbd_asender(struct drbd_thread *thi)
if (received == expect) {
bool err;
- err = cmd->fn(tconn, &pi);
+ err = cmd->fn(connection, &pi);
if (err) {
- conn_err(tconn, "%pf failed\n", cmd->fn);
+ drbd_err(connection, "%pf failed\n", cmd->fn);
goto reconnect;
}
- tconn->last_received = jiffies;
+ connection->last_received = jiffies;
if (cmd == &asender_tbl[P_PING_ACK]) {
/* restore idle timeout */
- tconn->meta.socket->sk->sk_rcvtimeo = ping_int * HZ;
+ connection->meta.socket->sk->sk_rcvtimeo = ping_int * HZ;
ping_timeout_active = false;
}
- buf = tconn->meta.rbuf;
+ buf = connection->meta.rbuf;
received = 0;
expect = header_size;
cmd = NULL;
@@ -5391,16 +5461,16 @@ int drbd_asender(struct drbd_thread *thi)
if (0) {
reconnect:
- conn_request_state(tconn, NS(conn, C_NETWORK_FAILURE), CS_HARD);
- conn_md_sync(tconn);
+ conn_request_state(connection, NS(conn, C_NETWORK_FAILURE), CS_HARD);
+ conn_md_sync(connection);
}
if (0) {
disconnect:
- conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
}
- clear_bit(SIGNAL_ASENDER, &tconn->flags);
+ clear_bit(SIGNAL_ASENDER, &connection->flags);
- conn_info(tconn, "asender terminated\n");
+ drbd_info(connection, "asender terminated\n");
return 0;
}
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 104a040f24de..3779c8d2875b 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -31,37 +31,37 @@
#include "drbd_req.h"
-static bool drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int size);
+static bool drbd_may_do_local_read(struct drbd_device *device, sector_t sector, int size);
/* Update disk stats at start of I/O request */
-static void _drbd_start_io_acct(struct drbd_conf *mdev, struct drbd_request *req)
+static void _drbd_start_io_acct(struct drbd_device *device, struct drbd_request *req)
{
const int rw = bio_data_dir(req->master_bio);
int cpu;
cpu = part_stat_lock();
- part_round_stats(cpu, &mdev->vdisk->part0);
- part_stat_inc(cpu, &mdev->vdisk->part0, ios[rw]);
- part_stat_add(cpu, &mdev->vdisk->part0, sectors[rw], req->i.size >> 9);
+ part_round_stats(cpu, &device->vdisk->part0);
+ part_stat_inc(cpu, &device->vdisk->part0, ios[rw]);
+ part_stat_add(cpu, &device->vdisk->part0, sectors[rw], req->i.size >> 9);
(void) cpu; /* The macro invocations above want the cpu argument, I do not like
the compiler warning about cpu only assigned but never used... */
- part_inc_in_flight(&mdev->vdisk->part0, rw);
+ part_inc_in_flight(&device->vdisk->part0, rw);
part_stat_unlock();
}
/* Update disk stats when completing request upwards */
-static void _drbd_end_io_acct(struct drbd_conf *mdev, struct drbd_request *req)
+static void _drbd_end_io_acct(struct drbd_device *device, struct drbd_request *req)
{
int rw = bio_data_dir(req->master_bio);
unsigned long duration = jiffies - req->start_time;
int cpu;
cpu = part_stat_lock();
- part_stat_add(cpu, &mdev->vdisk->part0, ticks[rw], duration);
- part_round_stats(cpu, &mdev->vdisk->part0);
- part_dec_in_flight(&mdev->vdisk->part0, rw);
+ part_stat_add(cpu, &device->vdisk->part0, ticks[rw], duration);
+ part_round_stats(cpu, &device->vdisk->part0);
+ part_dec_in_flight(&device->vdisk->part0, rw);
part_stat_unlock();
}
-static struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
+static struct drbd_request *drbd_req_new(struct drbd_device *device,
struct bio *bio_src)
{
struct drbd_request *req;
@@ -72,7 +72,7 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
drbd_req_make_private_bio(req, bio_src);
req->rq_state = bio_data_dir(bio_src) == WRITE ? RQ_WRITE : 0;
- req->w.mdev = mdev;
+ req->device = device;
req->master_bio = bio_src;
req->epoch = 0;
@@ -95,14 +95,14 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
void drbd_req_destroy(struct kref *kref)
{
struct drbd_request *req = container_of(kref, struct drbd_request, kref);
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
const unsigned s = req->rq_state;
if ((req->master_bio && !(s & RQ_POSTPONED)) ||
atomic_read(&req->completion_ref) ||
(s & RQ_LOCAL_PENDING) ||
((s & RQ_NET_MASK) && !(s & RQ_NET_DONE))) {
- dev_err(DEV, "drbd_req_destroy: Logic BUG rq_state = 0x%x, completion_ref = %d\n",
+ drbd_err(device, "drbd_req_destroy: Logic BUG rq_state = 0x%x, completion_ref = %d\n",
s, atomic_read(&req->completion_ref));
return;
}
@@ -132,10 +132,10 @@ void drbd_req_destroy(struct kref *kref)
*/
if ((s & (RQ_POSTPONED|RQ_LOCAL_MASK|RQ_NET_MASK)) != RQ_POSTPONED) {
if (!(s & RQ_NET_OK) || !(s & RQ_LOCAL_OK))
- drbd_set_out_of_sync(mdev, req->i.sector, req->i.size);
+ drbd_set_out_of_sync(device, req->i.sector, req->i.size);
if ((s & RQ_NET_OK) && (s & RQ_LOCAL_OK) && (s & RQ_NET_SIS))
- drbd_set_in_sync(mdev, req->i.sector, req->i.size);
+ drbd_set_in_sync(device, req->i.sector, req->i.size);
}
/* one might be tempted to move the drbd_al_complete_io
@@ -149,11 +149,11 @@ void drbd_req_destroy(struct kref *kref)
* we would forget to resync the corresponding extent.
*/
if (s & RQ_IN_ACT_LOG) {
- if (get_ldev_if_state(mdev, D_FAILED)) {
- drbd_al_complete_io(mdev, &req->i);
- put_ldev(mdev);
+ if (get_ldev_if_state(device, D_FAILED)) {
+ drbd_al_complete_io(device, &req->i);
+ put_ldev(device);
} else if (__ratelimit(&drbd_ratelimit_state)) {
- dev_warn(DEV, "Should have called drbd_al_complete_io(, %llu, %u), "
+ drbd_warn(device, "Should have called drbd_al_complete_io(, %llu, %u), "
"but my Disk seems to have failed :(\n",
(unsigned long long) req->i.sector, req->i.size);
}
@@ -163,41 +163,42 @@ void drbd_req_destroy(struct kref *kref)
mempool_free(req, drbd_request_mempool);
}
-static void wake_all_senders(struct drbd_tconn *tconn) {
- wake_up(&tconn->sender_work.q_wait);
+static void wake_all_senders(struct drbd_connection *connection)
+{
+ wake_up(&connection->sender_work.q_wait);
}
/* must hold resource->req_lock */
-void start_new_tl_epoch(struct drbd_tconn *tconn)
+void start_new_tl_epoch(struct drbd_connection *connection)
{
/* no point closing an epoch, if it is empty, anyways. */
- if (tconn->current_tle_writes == 0)
+ if (connection->current_tle_writes == 0)
return;
- tconn->current_tle_writes = 0;
- atomic_inc(&tconn->current_tle_nr);
- wake_all_senders(tconn);
+ connection->current_tle_writes = 0;
+ atomic_inc(&connection->current_tle_nr);
+ wake_all_senders(connection);
}
-void complete_master_bio(struct drbd_conf *mdev,
+void complete_master_bio(struct drbd_device *device,
struct bio_and_error *m)
{
bio_endio(m->bio, m->error);
- dec_ap_bio(mdev);
+ dec_ap_bio(device);
}
static void drbd_remove_request_interval(struct rb_root *root,
struct drbd_request *req)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct drbd_interval *i = &req->i;
drbd_remove_interval(root, i);
/* Wake up any processes waiting for this request to complete. */
if (i->waiting)
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
}
/* Helper for __req_mod().
@@ -210,7 +211,7 @@ static
void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m)
{
const unsigned s = req->rq_state;
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
int rw;
int error, ok;
@@ -226,12 +227,12 @@ void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m)
if ((s & RQ_LOCAL_PENDING && !(s & RQ_LOCAL_ABORTED)) ||
(s & RQ_NET_QUEUED) || (s & RQ_NET_PENDING) ||
(s & RQ_COMPLETION_SUSP)) {
- dev_err(DEV, "drbd_req_complete: Logic BUG rq_state = 0x%x\n", s);
+ drbd_err(device, "drbd_req_complete: Logic BUG rq_state = 0x%x\n", s);
return;
}
if (!req->master_bio) {
- dev_err(DEV, "drbd_req_complete: Logic BUG, master_bio == NULL!\n");
+ drbd_err(device, "drbd_req_complete: Logic BUG, master_bio == NULL!\n");
return;
}
@@ -259,9 +260,9 @@ void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m)
struct rb_root *root;
if (rw == WRITE)
- root = &mdev->write_requests;
+ root = &device->write_requests;
else
- root = &mdev->read_requests;
+ root = &device->read_requests;
drbd_remove_request_interval(root, req);
}
@@ -273,11 +274,11 @@ void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m)
* and reset the transfer log epoch write_cnt.
*/
if (rw == WRITE &&
- req->epoch == atomic_read(&mdev->tconn->current_tle_nr))
- start_new_tl_epoch(mdev->tconn);
+ req->epoch == atomic_read(&first_peer_device(device)->connection->current_tle_nr))
+ start_new_tl_epoch(first_peer_device(device)->connection);
/* Update disk stats */
- _drbd_end_io_acct(mdev, req);
+ _drbd_end_io_acct(device, req);
/* If READ failed,
* have it be pushed back to the retry work queue,
@@ -305,8 +306,8 @@ void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m)
static int drbd_req_put_completion_ref(struct drbd_request *req, struct bio_and_error *m, int put)
{
- struct drbd_conf *mdev = req->w.mdev;
- D_ASSERT(m || (req->rq_state & RQ_POSTPONED));
+ struct drbd_device *device = req->device;
+ D_ASSERT(device, m || (req->rq_state & RQ_POSTPONED));
if (!atomic_sub_and_test(put, &req->completion_ref))
return 0;
@@ -328,12 +329,12 @@ static int drbd_req_put_completion_ref(struct drbd_request *req, struct bio_and_
static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
int clear, int set)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
unsigned s = req->rq_state;
int c_put = 0;
int k_put = 0;
- if (drbd_suspended(mdev) && !((s | clear) & RQ_COMPLETION_SUSP))
+ if (drbd_suspended(device) && !((s | clear) & RQ_COMPLETION_SUSP))
set |= RQ_COMPLETION_SUSP;
/* apply */
@@ -351,7 +352,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
atomic_inc(&req->completion_ref);
if (!(s & RQ_NET_PENDING) && (set & RQ_NET_PENDING)) {
- inc_ap_pending(mdev);
+ inc_ap_pending(device);
atomic_inc(&req->completion_ref);
}
@@ -362,7 +363,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
kref_get(&req->kref); /* wait for the DONE */
if (!(s & RQ_NET_SENT) && (set & RQ_NET_SENT))
- atomic_add(req->i.size >> 9, &mdev->ap_in_flight);
+ atomic_add(req->i.size >> 9, &device->ap_in_flight);
if (!(s & RQ_COMPLETION_SUSP) && (set & RQ_COMPLETION_SUSP))
atomic_inc(&req->completion_ref);
@@ -373,7 +374,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
++c_put;
if (!(s & RQ_LOCAL_ABORTED) && (set & RQ_LOCAL_ABORTED)) {
- D_ASSERT(req->rq_state & RQ_LOCAL_PENDING);
+ D_ASSERT(device, req->rq_state & RQ_LOCAL_PENDING);
/* local completion may still come in later,
* we need to keep the req object around. */
kref_get(&req->kref);
@@ -388,7 +389,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
}
if ((s & RQ_NET_PENDING) && (clear & RQ_NET_PENDING)) {
- dec_ap_pending(mdev);
+ dec_ap_pending(device);
++c_put;
}
@@ -397,7 +398,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
if ((s & RQ_EXP_BARR_ACK) && !(s & RQ_NET_DONE) && (set & RQ_NET_DONE)) {
if (req->rq_state & RQ_NET_SENT)
- atomic_sub(req->i.size >> 9, &mdev->ap_in_flight);
+ atomic_sub(req->i.size >> 9, &device->ap_in_flight);
++k_put;
}
@@ -409,14 +410,14 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
int at_least = k_put + !!c_put;
int refcount = atomic_read(&req->kref.refcount);
if (refcount < at_least)
- dev_err(DEV,
+ drbd_err(device,
"mod_rq_state: Logic BUG: %x -> %x: refcount = %d, should be >= %d\n",
s, req->rq_state, refcount, at_least);
}
/* If we made progress, retry conflicting peer requests, if any. */
if (req->i.waiting)
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
if (c_put)
k_put += drbd_req_put_completion_ref(req, m, c_put);
@@ -424,18 +425,18 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
kref_sub(&req->kref, k_put, drbd_req_destroy);
}
-static void drbd_report_io_error(struct drbd_conf *mdev, struct drbd_request *req)
+static void drbd_report_io_error(struct drbd_device *device, struct drbd_request *req)
{
char b[BDEVNAME_SIZE];
if (!__ratelimit(&drbd_ratelimit_state))
return;
- dev_warn(DEV, "local %s IO error sector %llu+%u on %s\n",
+ drbd_warn(device, "local %s IO error sector %llu+%u on %s\n",
(req->rq_state & RQ_WRITE) ? "WRITE" : "READ",
(unsigned long long)req->i.sector,
req->i.size >> 9,
- bdevname(mdev->ldev->backing_bdev, b));
+ bdevname(device->ldev->backing_bdev, b));
}
/* obviously this could be coded as many single functions
@@ -453,7 +454,7 @@ static void drbd_report_io_error(struct drbd_conf *mdev, struct drbd_request *re
int __req_mod(struct drbd_request *req, enum drbd_req_event what,
struct bio_and_error *m)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct net_conf *nc;
int p, rv = 0;
@@ -462,7 +463,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
switch (what) {
default:
- dev_err(DEV, "LOGIC BUG in %s:%u\n", __FILE__ , __LINE__);
+ drbd_err(device, "LOGIC BUG in %s:%u\n", __FILE__ , __LINE__);
break;
/* does not happen...
@@ -474,9 +475,9 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
case TO_BE_SENT: /* via network */
/* reached via __drbd_make_request
* and from w_read_retry_remote */
- D_ASSERT(!(req->rq_state & RQ_NET_MASK));
+ D_ASSERT(device, !(req->rq_state & RQ_NET_MASK));
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
p = nc->wire_protocol;
rcu_read_unlock();
req->rq_state |=
@@ -487,15 +488,15 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
case TO_BE_SUBMITTED: /* locally */
/* reached via __drbd_make_request */
- D_ASSERT(!(req->rq_state & RQ_LOCAL_MASK));
+ D_ASSERT(device, !(req->rq_state & RQ_LOCAL_MASK));
mod_rq_state(req, m, 0, RQ_LOCAL_PENDING);
break;
case COMPLETED_OK:
if (req->rq_state & RQ_WRITE)
- mdev->writ_cnt += req->i.size >> 9;
+ device->writ_cnt += req->i.size >> 9;
else
- mdev->read_cnt += req->i.size >> 9;
+ device->read_cnt += req->i.size >> 9;
mod_rq_state(req, m, RQ_LOCAL_PENDING,
RQ_LOCAL_COMPLETED|RQ_LOCAL_OK);
@@ -506,15 +507,15 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
break;
case WRITE_COMPLETED_WITH_ERROR:
- drbd_report_io_error(mdev, req);
- __drbd_chk_io_error(mdev, DRBD_WRITE_ERROR);
+ drbd_report_io_error(device, req);
+ __drbd_chk_io_error(device, DRBD_WRITE_ERROR);
mod_rq_state(req, m, RQ_LOCAL_PENDING, RQ_LOCAL_COMPLETED);
break;
case READ_COMPLETED_WITH_ERROR:
- drbd_set_out_of_sync(mdev, req->i.sector, req->i.size);
- drbd_report_io_error(mdev, req);
- __drbd_chk_io_error(mdev, DRBD_READ_ERROR);
+ drbd_set_out_of_sync(device, req->i.sector, req->i.size);
+ drbd_report_io_error(device, req);
+ __drbd_chk_io_error(device, DRBD_READ_ERROR);
/* fall through. */
case READ_AHEAD_COMPLETED_WITH_ERROR:
/* it is legal to fail READA, no __drbd_chk_io_error in that case. */
@@ -532,16 +533,17 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
/* So we can verify the handle in the answer packet.
* Corresponding drbd_remove_request_interval is in
* drbd_req_complete() */
- D_ASSERT(drbd_interval_empty(&req->i));
- drbd_insert_interval(&mdev->read_requests, &req->i);
+ D_ASSERT(device, drbd_interval_empty(&req->i));
+ drbd_insert_interval(&device->read_requests, &req->i);
- set_bit(UNPLUG_REMOTE, &mdev->flags);
+ set_bit(UNPLUG_REMOTE, &device->flags);
- D_ASSERT(req->rq_state & RQ_NET_PENDING);
- D_ASSERT((req->rq_state & RQ_LOCAL_MASK) == 0);
+ D_ASSERT(device, req->rq_state & RQ_NET_PENDING);
+ D_ASSERT(device, (req->rq_state & RQ_LOCAL_MASK) == 0);
mod_rq_state(req, m, 0, RQ_NET_QUEUED);
req->w.cb = w_send_read_req;
- drbd_queue_work(&mdev->tconn->sender_work, &req->w);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &req->w);
break;
case QUEUE_FOR_NET_WRITE:
@@ -550,8 +552,8 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
/* Corresponding drbd_remove_request_interval is in
* drbd_req_complete() */
- D_ASSERT(drbd_interval_empty(&req->i));
- drbd_insert_interval(&mdev->write_requests, &req->i);
+ D_ASSERT(device, drbd_interval_empty(&req->i));
+ drbd_insert_interval(&device->write_requests, &req->i);
/* NOTE
* In case the req ended up on the transfer log before being
@@ -570,28 +572,30 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
/* otherwise we may lose an unplug, which may cause some remote
* io-scheduler timeout to expire, increasing maximum latency,
* hurting performance. */
- set_bit(UNPLUG_REMOTE, &mdev->flags);
+ set_bit(UNPLUG_REMOTE, &device->flags);
/* queue work item to send data */
- D_ASSERT(req->rq_state & RQ_NET_PENDING);
+ D_ASSERT(device, req->rq_state & RQ_NET_PENDING);
mod_rq_state(req, m, 0, RQ_NET_QUEUED|RQ_EXP_BARR_ACK);
req->w.cb = w_send_dblock;
- drbd_queue_work(&mdev->tconn->sender_work, &req->w);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &req->w);
/* close the epoch, in case it outgrew the limit */
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
p = nc->max_epoch_size;
rcu_read_unlock();
- if (mdev->tconn->current_tle_writes >= p)
- start_new_tl_epoch(mdev->tconn);
+ if (first_peer_device(device)->connection->current_tle_writes >= p)
+ start_new_tl_epoch(first_peer_device(device)->connection);
break;
case QUEUE_FOR_SEND_OOS:
mod_rq_state(req, m, 0, RQ_NET_QUEUED);
req->w.cb = w_send_out_of_sync;
- drbd_queue_work(&mdev->tconn->sender_work, &req->w);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &req->w);
break;
case READ_RETRY_REMOTE_CANCELED:
@@ -639,15 +643,15 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
* If this request had been marked as RQ_POSTPONED before,
* it will actually not be completed, but "restarted",
* resubmitted from the retry worker context. */
- D_ASSERT(req->rq_state & RQ_NET_PENDING);
- D_ASSERT(req->rq_state & RQ_EXP_WRITE_ACK);
+ D_ASSERT(device, req->rq_state & RQ_NET_PENDING);
+ D_ASSERT(device, req->rq_state & RQ_EXP_WRITE_ACK);
mod_rq_state(req, m, RQ_NET_PENDING, RQ_NET_DONE|RQ_NET_OK);
break;
case WRITE_ACKED_BY_PEER_AND_SIS:
req->rq_state |= RQ_NET_SIS;
case WRITE_ACKED_BY_PEER:
- D_ASSERT(req->rq_state & RQ_EXP_WRITE_ACK);
+ D_ASSERT(device, req->rq_state & RQ_EXP_WRITE_ACK);
/* protocol C; successfully written on peer.
* Nothing more to do here.
* We want to keep the tl in place for all protocols, to cater
@@ -655,25 +659,25 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
goto ack_common;
case RECV_ACKED_BY_PEER:
- D_ASSERT(req->rq_state & RQ_EXP_RECEIVE_ACK);
+ D_ASSERT(device, req->rq_state & RQ_EXP_RECEIVE_ACK);
/* protocol B; pretends to be successfully written on peer.
* see also notes above in HANDED_OVER_TO_NETWORK about
* protocol != C */
ack_common:
- D_ASSERT(req->rq_state & RQ_NET_PENDING);
+ D_ASSERT(device, req->rq_state & RQ_NET_PENDING);
mod_rq_state(req, m, RQ_NET_PENDING, RQ_NET_OK);
break;
case POSTPONE_WRITE:
- D_ASSERT(req->rq_state & RQ_EXP_WRITE_ACK);
+ D_ASSERT(device, req->rq_state & RQ_EXP_WRITE_ACK);
/* If this node has already detected the write conflict, the
* worker will be waiting on misc_wait. Wake it up once this
* request has completed locally.
*/
- D_ASSERT(req->rq_state & RQ_NET_PENDING);
+ D_ASSERT(device, req->rq_state & RQ_NET_PENDING);
req->rq_state |= RQ_POSTPONED;
if (req->i.waiting)
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
/* Do not clear RQ_NET_PENDING. This request will make further
* progress via restart_conflicting_writes() or
* fail_postponed_requests(). Hopefully. */
@@ -701,9 +705,10 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
if (bio_data_dir(req->master_bio) == WRITE)
rv = MR_WRITE;
- get_ldev(mdev); /* always succeeds in this call path */
+ get_ldev(device); /* always succeeds in this call path */
req->w.cb = w_restart_disk_io;
- drbd_queue_work(&mdev->tconn->sender_work, &req->w);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &req->w);
break;
case RESEND:
@@ -719,12 +724,13 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
Throwing them out of the TL here by pretending we got a BARRIER_ACK.
During connection handshake, we ensure that the peer was not rebooted. */
if (!(req->rq_state & RQ_NET_OK)) {
- /* FIXME could this possibly be a req->w.cb == w_send_out_of_sync?
+ /* FIXME could this possibly be a req->dw.cb == w_send_out_of_sync?
* in that case we must not set RQ_NET_PENDING. */
mod_rq_state(req, m, RQ_COMPLETION_SUSP, RQ_NET_QUEUED|RQ_NET_PENDING);
if (req->w.cb) {
- drbd_queue_work(&mdev->tconn->sender_work, &req->w);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &req->w);
rv = req->rq_state & RQ_WRITE ? MR_WRITE : MR_READ;
} /* else: FIXME can this happen? */
break;
@@ -740,7 +746,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
/* barrier came in before all requests were acked.
* this is bad, because if the connection is lost now,
* we won't be able to clean them up... */
- dev_err(DEV, "FIXME (BARRIER_ACKED but pending)\n");
+ drbd_err(device, "FIXME (BARRIER_ACKED but pending)\n");
}
/* Allowed to complete requests, even while suspended.
* As this is called for all requests within a matching epoch,
@@ -751,12 +757,12 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
break;
case DATA_RECEIVED:
- D_ASSERT(req->rq_state & RQ_NET_PENDING);
+ D_ASSERT(device, req->rq_state & RQ_NET_PENDING);
mod_rq_state(req, m, RQ_NET_PENDING, RQ_NET_OK|RQ_NET_DONE);
break;
case QUEUE_AS_DRBD_BARRIER:
- start_new_tl_epoch(mdev->tconn);
+ start_new_tl_epoch(first_peer_device(device)->connection);
mod_rq_state(req, m, 0, RQ_NET_OK|RQ_NET_DONE);
break;
};
@@ -771,27 +777,27 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
* since size may be bigger than BM_BLOCK_SIZE,
* we may need to check several bits.
*/
-static bool drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int size)
+static bool drbd_may_do_local_read(struct drbd_device *device, sector_t sector, int size)
{
unsigned long sbnr, ebnr;
sector_t esector, nr_sectors;
- if (mdev->state.disk == D_UP_TO_DATE)
+ if (device->state.disk == D_UP_TO_DATE)
return true;
- if (mdev->state.disk != D_INCONSISTENT)
+ if (device->state.disk != D_INCONSISTENT)
return false;
esector = sector + (size >> 9) - 1;
- nr_sectors = drbd_get_capacity(mdev->this_bdev);
- D_ASSERT(sector < nr_sectors);
- D_ASSERT(esector < nr_sectors);
+ nr_sectors = drbd_get_capacity(device->this_bdev);
+ D_ASSERT(device, sector < nr_sectors);
+ D_ASSERT(device, esector < nr_sectors);
sbnr = BM_SECT_TO_BIT(sector);
ebnr = BM_SECT_TO_BIT(esector);
- return drbd_bm_count_bits(mdev, sbnr, ebnr) == 0;
+ return drbd_bm_count_bits(device, sbnr, ebnr) == 0;
}
-static bool remote_due_to_read_balancing(struct drbd_conf *mdev, sector_t sector,
+static bool remote_due_to_read_balancing(struct drbd_device *device, sector_t sector,
enum drbd_read_balancing rbm)
{
struct backing_dev_info *bdi;
@@ -799,11 +805,11 @@ static bool remote_due_to_read_balancing(struct drbd_conf *mdev, sector_t sector
switch (rbm) {
case RB_CONGESTED_REMOTE:
- bdi = &mdev->ldev->backing_bdev->bd_disk->queue->backing_dev_info;
+ bdi = &device->ldev->backing_bdev->bd_disk->queue->backing_dev_info;
return bdi_read_congested(bdi);
case RB_LEAST_PENDING:
- return atomic_read(&mdev->local_cnt) >
- atomic_read(&mdev->ap_pending_cnt) + atomic_read(&mdev->rs_pending_cnt);
+ return atomic_read(&device->local_cnt) >
+ atomic_read(&device->ap_pending_cnt) + atomic_read(&device->rs_pending_cnt);
case RB_32K_STRIPING: /* stripe_shift = 15 */
case RB_64K_STRIPING:
case RB_128K_STRIPING:
@@ -813,7 +819,7 @@ static bool remote_due_to_read_balancing(struct drbd_conf *mdev, sector_t sector
stripe_shift = (rbm - RB_32K_STRIPING + 15);
return (sector >> (stripe_shift - 9)) & 1;
case RB_ROUND_ROBIN:
- return test_and_change_bit(READ_BALANCE_RR, &mdev->flags);
+ return test_and_change_bit(READ_BALANCE_RR, &device->flags);
case RB_PREFER_REMOTE:
return true;
case RB_PREFER_LOCAL:
@@ -834,73 +840,73 @@ static bool remote_due_to_read_balancing(struct drbd_conf *mdev, sector_t sector
static void complete_conflicting_writes(struct drbd_request *req)
{
DEFINE_WAIT(wait);
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct drbd_interval *i;
sector_t sector = req->i.sector;
int size = req->i.size;
- i = drbd_find_overlap(&mdev->write_requests, sector, size);
+ i = drbd_find_overlap(&device->write_requests, sector, size);
if (!i)
return;
for (;;) {
- prepare_to_wait(&mdev->misc_wait, &wait, TASK_UNINTERRUPTIBLE);
- i = drbd_find_overlap(&mdev->write_requests, sector, size);
+ prepare_to_wait(&device->misc_wait, &wait, TASK_UNINTERRUPTIBLE);
+ i = drbd_find_overlap(&device->write_requests, sector, size);
if (!i)
break;
/* Indicate to wake up device->misc_wait on progress. */
i->waiting = true;
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
schedule();
- spin_lock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
}
- finish_wait(&mdev->misc_wait, &wait);
+ finish_wait(&device->misc_wait, &wait);
}
/* called within req_lock and rcu_read_lock() */
-static void maybe_pull_ahead(struct drbd_conf *mdev)
+static void maybe_pull_ahead(struct drbd_device *device)
{
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
struct net_conf *nc;
bool congested = false;
enum drbd_on_congestion on_congestion;
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
+ nc = rcu_dereference(connection->net_conf);
on_congestion = nc ? nc->on_congestion : OC_BLOCK;
rcu_read_unlock();
if (on_congestion == OC_BLOCK ||
- tconn->agreed_pro_version < 96)
+ connection->agreed_pro_version < 96)
return;
/* If I don't even have good local storage, we can not reasonably try
* to pull ahead of the peer. We also need the local reference to make
- * sure mdev->act_log is there.
+ * sure device->act_log is there.
*/
- if (!get_ldev_if_state(mdev, D_UP_TO_DATE))
+ if (!get_ldev_if_state(device, D_UP_TO_DATE))
return;
if (nc->cong_fill &&
- atomic_read(&mdev->ap_in_flight) >= nc->cong_fill) {
- dev_info(DEV, "Congestion-fill threshold reached\n");
+ atomic_read(&device->ap_in_flight) >= nc->cong_fill) {
+ drbd_info(device, "Congestion-fill threshold reached\n");
congested = true;
}
- if (mdev->act_log->used >= nc->cong_extents) {
- dev_info(DEV, "Congestion-extents threshold reached\n");
+ if (device->act_log->used >= nc->cong_extents) {
+ drbd_info(device, "Congestion-extents threshold reached\n");
congested = true;
}
if (congested) {
/* start a new epoch for non-mirrored writes */
- start_new_tl_epoch(mdev->tconn);
+ start_new_tl_epoch(first_peer_device(device)->connection);
if (on_congestion == OC_PULL_AHEAD)
- _drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL);
+ _drbd_set_state(_NS(device, conn, C_AHEAD), 0, NULL);
else /*nc->on_congestion == OC_DISCONNECT */
- _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL);
+ _drbd_set_state(_NS(device, conn, C_DISCONNECTING), 0, NULL);
}
- put_ldev(mdev);
+ put_ldev(device);
}
/* If this returns false, and req->private_bio is still set,
@@ -914,19 +920,19 @@ static void maybe_pull_ahead(struct drbd_conf *mdev)
*/
static bool do_remote_read(struct drbd_request *req)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
enum drbd_read_balancing rbm;
if (req->private_bio) {
- if (!drbd_may_do_local_read(mdev,
+ if (!drbd_may_do_local_read(device,
req->i.sector, req->i.size)) {
bio_put(req->private_bio);
req->private_bio = NULL;
- put_ldev(mdev);
+ put_ldev(device);
}
}
- if (mdev->state.pdsk != D_UP_TO_DATE)
+ if (device->state.pdsk != D_UP_TO_DATE)
return false;
if (req->private_bio == NULL)
@@ -936,17 +942,17 @@ static bool do_remote_read(struct drbd_request *req)
* protocol, pending requests etc. */
rcu_read_lock();
- rbm = rcu_dereference(mdev->ldev->disk_conf)->read_balancing;
+ rbm = rcu_dereference(device->ldev->disk_conf)->read_balancing;
rcu_read_unlock();
if (rbm == RB_PREFER_LOCAL && req->private_bio)
return false; /* submit locally */
- if (remote_due_to_read_balancing(mdev, req->i.sector, rbm)) {
+ if (remote_due_to_read_balancing(device, req->i.sector, rbm)) {
if (req->private_bio) {
bio_put(req->private_bio);
req->private_bio = NULL;
- put_ldev(mdev);
+ put_ldev(device);
}
return true;
}
@@ -959,11 +965,11 @@ static bool do_remote_read(struct drbd_request *req)
* which does NOT include those that we are L_AHEAD for. */
static int drbd_process_write_request(struct drbd_request *req)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
int remote, send_oos;
- remote = drbd_should_do_remote(mdev->state);
- send_oos = drbd_should_send_out_of_sync(mdev->state);
+ remote = drbd_should_do_remote(device->state);
+ send_oos = drbd_should_send_out_of_sync(device->state);
/* Need to replicate writes. Unless it is an empty flush,
* which is better mapped to a DRBD P_BARRIER packet,
@@ -973,7 +979,7 @@ static int drbd_process_write_request(struct drbd_request *req)
* replicating, in which case there is no point. */
if (unlikely(req->i.size == 0)) {
/* The only size==0 bios we expect are empty flushes. */
- D_ASSERT(req->master_bio->bi_rw & REQ_FLUSH);
+ D_ASSERT(device, req->master_bio->bi_rw & REQ_FLUSH);
if (remote)
_req_mod(req, QUEUE_AS_DRBD_BARRIER);
return remote;
@@ -982,12 +988,12 @@ static int drbd_process_write_request(struct drbd_request *req)
if (!remote && !send_oos)
return 0;
- D_ASSERT(!(remote && send_oos));
+ D_ASSERT(device, !(remote && send_oos));
if (remote) {
_req_mod(req, TO_BE_SENT);
_req_mod(req, QUEUE_FOR_NET_WRITE);
- } else if (drbd_set_out_of_sync(mdev, req->i.sector, req->i.size))
+ } else if (drbd_set_out_of_sync(device, req->i.sector, req->i.size))
_req_mod(req, QUEUE_FOR_SEND_OOS);
return remote;
@@ -996,36 +1002,36 @@ static int drbd_process_write_request(struct drbd_request *req)
static void
drbd_submit_req_private_bio(struct drbd_request *req)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct bio *bio = req->private_bio;
const int rw = bio_rw(bio);
- bio->bi_bdev = mdev->ldev->backing_bdev;
+ bio->bi_bdev = device->ldev->backing_bdev;
/* State may have changed since we grabbed our reference on the
* ->ldev member. Double check, and short-circuit to endio.
* In case the last activity log transaction failed to get on
* stable storage, and this is a WRITE, we may not even submit
* this bio. */
- if (get_ldev(mdev)) {
- if (drbd_insert_fault(mdev,
+ if (get_ldev(device)) {
+ if (drbd_insert_fault(device,
rw == WRITE ? DRBD_FAULT_DT_WR
: rw == READ ? DRBD_FAULT_DT_RD
: DRBD_FAULT_DT_RA))
bio_endio(bio, -EIO);
else
generic_make_request(bio);
- put_ldev(mdev);
+ put_ldev(device);
} else
bio_endio(bio, -EIO);
}
-static void drbd_queue_write(struct drbd_conf *mdev, struct drbd_request *req)
+static void drbd_queue_write(struct drbd_device *device, struct drbd_request *req)
{
- spin_lock(&mdev->submit.lock);
- list_add_tail(&req->tl_requests, &mdev->submit.writes);
- spin_unlock(&mdev->submit.lock);
- queue_work(mdev->submit.wq, &mdev->submit.worker);
+ spin_lock(&device->submit.lock);
+ list_add_tail(&req->tl_requests, &device->submit.writes);
+ spin_unlock(&device->submit.lock);
+ queue_work(device->submit.wq, &device->submit.worker);
}
/* returns the new drbd_request pointer, if the caller is expected to
@@ -1033,36 +1039,36 @@ static void drbd_queue_write(struct drbd_conf *mdev, struct drbd_request *req)
* request on the submitter thread.
* Returns ERR_PTR(-ENOMEM) if we cannot allocate a drbd_request.
*/
-struct drbd_request *
-drbd_request_prepare(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time)
+static struct drbd_request *
+drbd_request_prepare(struct drbd_device *device, struct bio *bio, unsigned long start_time)
{
const int rw = bio_data_dir(bio);
struct drbd_request *req;
/* allocate outside of all locks; */
- req = drbd_req_new(mdev, bio);
+ req = drbd_req_new(device, bio);
if (!req) {
- dec_ap_bio(mdev);
+ dec_ap_bio(device);
/* only pass the error to the upper layers.
* if user cannot handle io errors, that's not our business. */
- dev_err(DEV, "could not kmalloc() req\n");
+ drbd_err(device, "could not kmalloc() req\n");
bio_endio(bio, -ENOMEM);
return ERR_PTR(-ENOMEM);
}
req->start_time = start_time;
- if (!get_ldev(mdev)) {
+ if (!get_ldev(device)) {
bio_put(req->private_bio);
req->private_bio = NULL;
}
/* Update disk stats */
- _drbd_start_io_acct(mdev, req);
+ _drbd_start_io_acct(device, req);
if (rw == WRITE && req->private_bio && req->i.size
- && !test_bit(AL_SUSPENDED, &mdev->flags)) {
- if (!drbd_al_begin_io_fastpath(mdev, &req->i)) {
- drbd_queue_write(mdev, req);
+ && !test_bit(AL_SUSPENDED, &device->flags)) {
+ if (!drbd_al_begin_io_fastpath(device, &req->i)) {
+ drbd_queue_write(device, req);
return NULL;
}
req->rq_state |= RQ_IN_ACT_LOG;
@@ -1071,13 +1077,13 @@ drbd_request_prepare(struct drbd_conf *mdev, struct bio *bio, unsigned long star
return req;
}
-static void drbd_send_and_submit(struct drbd_conf *mdev, struct drbd_request *req)
+static void drbd_send_and_submit(struct drbd_device *device, struct drbd_request *req)
{
const int rw = bio_rw(req->master_bio);
struct bio_and_error m = { NULL, };
bool no_remote = false;
- spin_lock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
if (rw == WRITE) {
/* This may temporarily give up the req_lock,
* but will re-aquire it before it returns here.
@@ -1087,17 +1093,17 @@ static void drbd_send_and_submit(struct drbd_conf *mdev, struct drbd_request *re
/* check for congestion, and potentially stop sending
* full data updates, but start sending "dirty bits" only. */
- maybe_pull_ahead(mdev);
+ maybe_pull_ahead(device);
}
- if (drbd_suspended(mdev)) {
+ if (drbd_suspended(device)) {
/* push back and retry: */
req->rq_state |= RQ_POSTPONED;
if (req->private_bio) {
bio_put(req->private_bio);
req->private_bio = NULL;
- put_ldev(mdev);
+ put_ldev(device);
}
goto out;
}
@@ -1111,15 +1117,15 @@ static void drbd_send_and_submit(struct drbd_conf *mdev, struct drbd_request *re
}
/* which transfer log epoch does this belong to? */
- req->epoch = atomic_read(&mdev->tconn->current_tle_nr);
+ req->epoch = atomic_read(&first_peer_device(device)->connection->current_tle_nr);
/* no point in adding empty flushes to the transfer log,
* they are mapped to drbd barriers already. */
if (likely(req->i.size!=0)) {
if (rw == WRITE)
- mdev->tconn->current_tle_writes++;
+ first_peer_device(device)->connection->current_tle_writes++;
- list_add_tail(&req->tl_requests, &mdev->tconn->transfer_log);
+ list_add_tail(&req->tl_requests, &first_peer_device(device)->connection->transfer_log);
}
if (rw == WRITE) {
@@ -1139,13 +1145,13 @@ static void drbd_send_and_submit(struct drbd_conf *mdev, struct drbd_request *re
/* needs to be marked within the same spinlock */
_req_mod(req, TO_BE_SUBMITTED);
/* but we need to give up the spinlock to submit */
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
drbd_submit_req_private_bio(req);
- spin_lock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
} else if (no_remote) {
nodata:
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "IO ERROR: neither local nor remote data, sector %llu+%u\n",
+ drbd_err(device, "IO ERROR: neither local nor remote data, sector %llu+%u\n",
(unsigned long long)req->i.sector, req->i.size >> 9);
/* A write may have been queued for send_oos, however.
* So we can not simply free it, we must go through drbd_req_put_completion_ref() */
@@ -1154,21 +1160,21 @@ nodata:
out:
if (drbd_req_put_completion_ref(req, &m, 1))
kref_put(&req->kref, drbd_req_destroy);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
if (m.bio)
- complete_master_bio(mdev, &m);
+ complete_master_bio(device, &m);
}
-void __drbd_make_request(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time)
+void __drbd_make_request(struct drbd_device *device, struct bio *bio, unsigned long start_time)
{
- struct drbd_request *req = drbd_request_prepare(mdev, bio, start_time);
+ struct drbd_request *req = drbd_request_prepare(device, bio, start_time);
if (IS_ERR_OR_NULL(req))
return;
- drbd_send_and_submit(mdev, req);
+ drbd_send_and_submit(device, req);
}
-static void submit_fast_path(struct drbd_conf *mdev, struct list_head *incoming)
+static void submit_fast_path(struct drbd_device *device, struct list_head *incoming)
{
struct drbd_request *req, *tmp;
list_for_each_entry_safe(req, tmp, incoming, tl_requests) {
@@ -1176,19 +1182,19 @@ static void submit_fast_path(struct drbd_conf *mdev, struct list_head *incoming)
if (rw == WRITE /* rw != WRITE should not even end up here! */
&& req->private_bio && req->i.size
- && !test_bit(AL_SUSPENDED, &mdev->flags)) {
- if (!drbd_al_begin_io_fastpath(mdev, &req->i))
+ && !test_bit(AL_SUSPENDED, &device->flags)) {
+ if (!drbd_al_begin_io_fastpath(device, &req->i))
continue;
req->rq_state |= RQ_IN_ACT_LOG;
}
list_del_init(&req->tl_requests);
- drbd_send_and_submit(mdev, req);
+ drbd_send_and_submit(device, req);
}
}
-static bool prepare_al_transaction_nonblock(struct drbd_conf *mdev,
+static bool prepare_al_transaction_nonblock(struct drbd_device *device,
struct list_head *incoming,
struct list_head *pending)
{
@@ -1196,9 +1202,9 @@ static bool prepare_al_transaction_nonblock(struct drbd_conf *mdev,
int wake = 0;
int err;
- spin_lock_irq(&mdev->al_lock);
+ spin_lock_irq(&device->al_lock);
list_for_each_entry_safe(req, tmp, incoming, tl_requests) {
- err = drbd_al_begin_io_nonblock(mdev, &req->i);
+ err = drbd_al_begin_io_nonblock(device, &req->i);
if (err == -EBUSY)
wake = 1;
if (err)
@@ -1206,30 +1212,30 @@ static bool prepare_al_transaction_nonblock(struct drbd_conf *mdev,
req->rq_state |= RQ_IN_ACT_LOG;
list_move_tail(&req->tl_requests, pending);
}
- spin_unlock_irq(&mdev->al_lock);
+ spin_unlock_irq(&device->al_lock);
if (wake)
- wake_up(&mdev->al_wait);
+ wake_up(&device->al_wait);
return !list_empty(pending);
}
void do_submit(struct work_struct *ws)
{
- struct drbd_conf *mdev = container_of(ws, struct drbd_conf, submit.worker);
+ struct drbd_device *device = container_of(ws, struct drbd_device, submit.worker);
LIST_HEAD(incoming);
LIST_HEAD(pending);
struct drbd_request *req, *tmp;
for (;;) {
- spin_lock(&mdev->submit.lock);
- list_splice_tail_init(&mdev->submit.writes, &incoming);
- spin_unlock(&mdev->submit.lock);
+ spin_lock(&device->submit.lock);
+ list_splice_tail_init(&device->submit.writes, &incoming);
+ spin_unlock(&device->submit.lock);
- submit_fast_path(mdev, &incoming);
+ submit_fast_path(device, &incoming);
if (list_empty(&incoming))
break;
- wait_event(mdev->al_wait, prepare_al_transaction_nonblock(mdev, &incoming, &pending));
+ wait_event(device->al_wait, prepare_al_transaction_nonblock(device, &incoming, &pending));
/* Maybe more was queued, while we prepared the transaction?
* Try to stuff them into this transaction as well.
* Be strictly non-blocking here, no wait_event, we already
@@ -1243,17 +1249,17 @@ void do_submit(struct work_struct *ws)
/* It is ok to look outside the lock,
* it's only an optimization anyways */
- if (list_empty(&mdev->submit.writes))
+ if (list_empty(&device->submit.writes))
break;
- spin_lock(&mdev->submit.lock);
- list_splice_tail_init(&mdev->submit.writes, &more_incoming);
- spin_unlock(&mdev->submit.lock);
+ spin_lock(&device->submit.lock);
+ list_splice_tail_init(&device->submit.writes, &more_incoming);
+ spin_unlock(&device->submit.lock);
if (list_empty(&more_incoming))
break;
- made_progress = prepare_al_transaction_nonblock(mdev, &more_incoming, &more_pending);
+ made_progress = prepare_al_transaction_nonblock(device, &more_incoming, &more_pending);
list_splice_tail_init(&more_pending, &pending);
list_splice_tail_init(&more_incoming, &incoming);
@@ -1261,18 +1267,18 @@ void do_submit(struct work_struct *ws)
if (!made_progress)
break;
}
- drbd_al_begin_io_commit(mdev, false);
+ drbd_al_begin_io_commit(device, false);
list_for_each_entry_safe(req, tmp, &pending, tl_requests) {
list_del_init(&req->tl_requests);
- drbd_send_and_submit(mdev, req);
+ drbd_send_and_submit(device, req);
}
}
}
void drbd_make_request(struct request_queue *q, struct bio *bio)
{
- struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata;
+ struct drbd_device *device = (struct drbd_device *) q->queuedata;
unsigned long start_time;
start_time = jiffies;
@@ -1280,10 +1286,10 @@ void drbd_make_request(struct request_queue *q, struct bio *bio)
/*
* what we "blindly" assume:
*/
- D_ASSERT(IS_ALIGNED(bio->bi_iter.bi_size, 512));
+ D_ASSERT(device, IS_ALIGNED(bio->bi_iter.bi_size, 512));
- inc_ap_bio(mdev);
- __drbd_make_request(mdev, bio, start_time);
+ inc_ap_bio(device);
+ __drbd_make_request(device, bio, start_time);
}
/* This is called by bio_add_page().
@@ -1300,32 +1306,32 @@ void drbd_make_request(struct request_queue *q, struct bio *bio)
*/
int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec)
{
- struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata;
+ struct drbd_device *device = (struct drbd_device *) q->queuedata;
unsigned int bio_size = bvm->bi_size;
int limit = DRBD_MAX_BIO_SIZE;
int backing_limit;
- if (bio_size && get_ldev(mdev)) {
+ if (bio_size && get_ldev(device)) {
unsigned int max_hw_sectors = queue_max_hw_sectors(q);
struct request_queue * const b =
- mdev->ldev->backing_bdev->bd_disk->queue;
+ device->ldev->backing_bdev->bd_disk->queue;
if (b->merge_bvec_fn) {
backing_limit = b->merge_bvec_fn(b, bvm, bvec);
limit = min(limit, backing_limit);
}
- put_ldev(mdev);
+ put_ldev(device);
if ((limit >> 9) > max_hw_sectors)
limit = max_hw_sectors << 9;
}
return limit;
}
-struct drbd_request *find_oldest_request(struct drbd_tconn *tconn)
+static struct drbd_request *find_oldest_request(struct drbd_connection *connection)
{
/* Walk the transfer log,
* and find the oldest not yet completed request */
struct drbd_request *r;
- list_for_each_entry(r, &tconn->transfer_log, tl_requests) {
+ list_for_each_entry(r, &connection->transfer_log, tl_requests) {
if (atomic_read(&r->completion_ref))
return r;
}
@@ -1334,21 +1340,21 @@ struct drbd_request *find_oldest_request(struct drbd_tconn *tconn)
void request_timer_fn(unsigned long data)
{
- struct drbd_conf *mdev = (struct drbd_conf *) data;
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_device *device = (struct drbd_device *) data;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
struct drbd_request *req; /* oldest request */
struct net_conf *nc;
unsigned long ent = 0, dt = 0, et, nt; /* effective timeout = ko_count * timeout */
unsigned long now;
rcu_read_lock();
- nc = rcu_dereference(tconn->net_conf);
- if (nc && mdev->state.conn >= C_WF_REPORT_PARAMS)
+ nc = rcu_dereference(connection->net_conf);
+ if (nc && device->state.conn >= C_WF_REPORT_PARAMS)
ent = nc->timeout * HZ/10 * nc->ko_count;
- if (get_ldev(mdev)) { /* implicit state.disk >= D_INCONSISTENT */
- dt = rcu_dereference(mdev->ldev->disk_conf)->disk_timeout * HZ / 10;
- put_ldev(mdev);
+ if (get_ldev(device)) { /* implicit state.disk >= D_INCONSISTENT */
+ dt = rcu_dereference(device->ldev->disk_conf)->disk_timeout * HZ / 10;
+ put_ldev(device);
}
rcu_read_unlock();
@@ -1359,11 +1365,11 @@ void request_timer_fn(unsigned long data)
now = jiffies;
- spin_lock_irq(&tconn->req_lock);
- req = find_oldest_request(tconn);
+ spin_lock_irq(&device->resource->req_lock);
+ req = find_oldest_request(connection);
if (!req) {
- spin_unlock_irq(&tconn->req_lock);
- mod_timer(&mdev->request_timer, now + et);
+ spin_unlock_irq(&device->resource->req_lock);
+ mod_timer(&device->request_timer, now + et);
return;
}
@@ -1385,17 +1391,17 @@ void request_timer_fn(unsigned long data)
*/
if (ent && req->rq_state & RQ_NET_PENDING &&
time_after(now, req->start_time + ent) &&
- !time_in_range(now, tconn->last_reconnect_jif, tconn->last_reconnect_jif + ent)) {
- dev_warn(DEV, "Remote failed to finish a request within ko-count * timeout\n");
- _drbd_set_state(_NS(mdev, conn, C_TIMEOUT), CS_VERBOSE | CS_HARD, NULL);
+ !time_in_range(now, connection->last_reconnect_jif, connection->last_reconnect_jif + ent)) {
+ drbd_warn(device, "Remote failed to finish a request within ko-count * timeout\n");
+ _drbd_set_state(_NS(device, conn, C_TIMEOUT), CS_VERBOSE | CS_HARD, NULL);
}
- if (dt && req->rq_state & RQ_LOCAL_PENDING && req->w.mdev == mdev &&
+ if (dt && req->rq_state & RQ_LOCAL_PENDING && req->device == device &&
time_after(now, req->start_time + dt) &&
- !time_in_range(now, mdev->last_reattach_jif, mdev->last_reattach_jif + dt)) {
- dev_warn(DEV, "Local backing device failed to meet the disk-timeout\n");
- __drbd_chk_io_error(mdev, DRBD_FORCE_DETACH);
+ !time_in_range(now, device->last_reattach_jif, device->last_reattach_jif + dt)) {
+ drbd_warn(device, "Local backing device failed to meet the disk-timeout\n");
+ __drbd_chk_io_error(device, DRBD_FORCE_DETACH);
}
nt = (time_after(now, req->start_time + et) ? now : req->start_time) + et;
- spin_unlock_irq(&tconn->req_lock);
- mod_timer(&mdev->request_timer, nt);
+ spin_unlock_irq(&connection->resource->req_lock);
+ mod_timer(&device->request_timer, nt);
}
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h
index 28e15d91197a..c684c963538e 100644
--- a/drivers/block/drbd/drbd_req.h
+++ b/drivers/block/drbd/drbd_req.h
@@ -275,17 +275,17 @@ struct bio_and_error {
int error;
};
-extern void start_new_tl_epoch(struct drbd_tconn *tconn);
+extern void start_new_tl_epoch(struct drbd_connection *connection);
extern void drbd_req_destroy(struct kref *kref);
extern void _req_may_be_done(struct drbd_request *req,
struct bio_and_error *m);
extern int __req_mod(struct drbd_request *req, enum drbd_req_event what,
struct bio_and_error *m);
-extern void complete_master_bio(struct drbd_conf *mdev,
+extern void complete_master_bio(struct drbd_device *device,
struct bio_and_error *m);
extern void request_timer_fn(unsigned long data);
-extern void tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what);
-extern void _tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what);
+extern void tl_restart(struct drbd_connection *connection, enum drbd_req_event what);
+extern void _tl_restart(struct drbd_connection *connection, enum drbd_req_event what);
/* this is in drbd_main.c */
extern void drbd_restart_request(struct drbd_request *req);
@@ -294,14 +294,14 @@ extern void drbd_restart_request(struct drbd_request *req);
* outside the spinlock, e.g. when walking some list on cleanup. */
static inline int _req_mod(struct drbd_request *req, enum drbd_req_event what)
{
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct bio_and_error m;
int rv;
/* __req_mod possibly frees req, do not touch req after that! */
rv = __req_mod(req, what, &m);
if (m.bio)
- complete_master_bio(mdev, &m);
+ complete_master_bio(device, &m);
return rv;
}
@@ -314,16 +314,16 @@ static inline int req_mod(struct drbd_request *req,
enum drbd_req_event what)
{
unsigned long flags;
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct bio_and_error m;
int rv;
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
rv = __req_mod(req, what, &m);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
if (m.bio)
- complete_master_bio(mdev, &m);
+ complete_master_bio(device, &m);
return rv;
}
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c
index 216d47b7e88b..1a84345a3868 100644
--- a/drivers/block/drbd/drbd_state.c
+++ b/drivers/block/drbd/drbd_state.c
@@ -27,13 +27,12 @@
#include <linux/drbd_limits.h>
#include "drbd_int.h"
+#include "drbd_protocol.h"
#include "drbd_req.h"
-/* in drbd_main.c */
-extern void tl_abort_disk_io(struct drbd_conf *mdev);
-
struct after_state_chg_work {
struct drbd_work w;
+ struct drbd_device *device;
union drbd_state os;
union drbd_state ns;
enum chg_state_flags flags;
@@ -50,12 +49,12 @@ enum sanitize_state_warnings {
};
static int w_after_state_ch(struct drbd_work *w, int unused);
-static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
+static void after_state_ch(struct drbd_device *device, union drbd_state os,
union drbd_state ns, enum chg_state_flags flags);
-static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state);
-static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state, struct drbd_tconn *);
+static enum drbd_state_rv is_valid_state(struct drbd_device *, union drbd_state);
+static enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state, struct drbd_connection *);
static enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns);
-static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state ns,
+static union drbd_state sanitize_state(struct drbd_device *device, union drbd_state ns,
enum sanitize_state_warnings *warn);
static inline bool is_susp(union drbd_state s)
@@ -63,17 +62,18 @@ static inline bool is_susp(union drbd_state s)
return s.susp || s.susp_nod || s.susp_fen;
}
-bool conn_all_vols_unconf(struct drbd_tconn *tconn)
+bool conn_all_vols_unconf(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
bool rv = true;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (mdev->state.disk != D_DISKLESS ||
- mdev->state.conn != C_STANDALONE ||
- mdev->state.role != R_SECONDARY) {
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ if (device->state.disk != D_DISKLESS ||
+ device->state.conn != C_STANDALONE ||
+ device->state.role != R_SECONDARY) {
rv = false;
break;
}
@@ -102,99 +102,111 @@ static enum drbd_role min_role(enum drbd_role role1, enum drbd_role role2)
return R_PRIMARY;
}
-enum drbd_role conn_highest_role(struct drbd_tconn *tconn)
+enum drbd_role conn_highest_role(struct drbd_connection *connection)
{
enum drbd_role role = R_UNKNOWN;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- role = max_role(role, mdev->state.role);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ role = max_role(role, device->state.role);
+ }
rcu_read_unlock();
return role;
}
-enum drbd_role conn_highest_peer(struct drbd_tconn *tconn)
+enum drbd_role conn_highest_peer(struct drbd_connection *connection)
{
enum drbd_role peer = R_UNKNOWN;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- peer = max_role(peer, mdev->state.peer);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ peer = max_role(peer, device->state.peer);
+ }
rcu_read_unlock();
return peer;
}
-enum drbd_disk_state conn_highest_disk(struct drbd_tconn *tconn)
+enum drbd_disk_state conn_highest_disk(struct drbd_connection *connection)
{
enum drbd_disk_state ds = D_DISKLESS;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- ds = max_t(enum drbd_disk_state, ds, mdev->state.disk);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ ds = max_t(enum drbd_disk_state, ds, device->state.disk);
+ }
rcu_read_unlock();
return ds;
}
-enum drbd_disk_state conn_lowest_disk(struct drbd_tconn *tconn)
+enum drbd_disk_state conn_lowest_disk(struct drbd_connection *connection)
{
enum drbd_disk_state ds = D_MASK;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- ds = min_t(enum drbd_disk_state, ds, mdev->state.disk);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ ds = min_t(enum drbd_disk_state, ds, device->state.disk);
+ }
rcu_read_unlock();
return ds;
}
-enum drbd_disk_state conn_highest_pdsk(struct drbd_tconn *tconn)
+enum drbd_disk_state conn_highest_pdsk(struct drbd_connection *connection)
{
enum drbd_disk_state ds = D_DISKLESS;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- ds = max_t(enum drbd_disk_state, ds, mdev->state.pdsk);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ ds = max_t(enum drbd_disk_state, ds, device->state.pdsk);
+ }
rcu_read_unlock();
return ds;
}
-enum drbd_conns conn_lowest_conn(struct drbd_tconn *tconn)
+enum drbd_conns conn_lowest_conn(struct drbd_connection *connection)
{
enum drbd_conns conn = C_MASK;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- conn = min_t(enum drbd_conns, conn, mdev->state.conn);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ conn = min_t(enum drbd_conns, conn, device->state.conn);
+ }
rcu_read_unlock();
return conn;
}
-static bool no_peer_wf_report_params(struct drbd_tconn *tconn)
+static bool no_peer_wf_report_params(struct drbd_connection *connection)
{
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
bool rv = true;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr)
- if (mdev->state.conn == C_WF_REPORT_PARAMS) {
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr)
+ if (peer_device->device->state.conn == C_WF_REPORT_PARAMS) {
rv = false;
break;
}
@@ -206,11 +218,11 @@ static bool no_peer_wf_report_params(struct drbd_tconn *tconn)
/**
* cl_wide_st_chg() - true if the state change is a cluster wide one
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @os: old (current) state.
* @ns: new (wanted) state.
*/
-static int cl_wide_st_chg(struct drbd_conf *mdev,
+static int cl_wide_st_chg(struct drbd_device *device,
union drbd_state os, union drbd_state ns)
{
return (os.conn >= C_CONNECTED && ns.conn >= C_CONNECTED &&
@@ -232,72 +244,72 @@ apply_mask_val(union drbd_state os, union drbd_state mask, union drbd_state val)
}
enum drbd_state_rv
-drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f,
+drbd_change_state(struct drbd_device *device, enum chg_state_flags f,
union drbd_state mask, union drbd_state val)
{
unsigned long flags;
union drbd_state ns;
enum drbd_state_rv rv;
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- ns = apply_mask_val(drbd_read_state(mdev), mask, val);
- rv = _drbd_set_state(mdev, ns, f, NULL);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ ns = apply_mask_val(drbd_read_state(device), mask, val);
+ rv = _drbd_set_state(device, ns, f, NULL);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
return rv;
}
/**
* drbd_force_state() - Impose a change which happens outside our control on our state
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @mask: mask of state bits to change.
* @val: value of new state bits.
*/
-void drbd_force_state(struct drbd_conf *mdev,
+void drbd_force_state(struct drbd_device *device,
union drbd_state mask, union drbd_state val)
{
- drbd_change_state(mdev, CS_HARD, mask, val);
+ drbd_change_state(device, CS_HARD, mask, val);
}
static enum drbd_state_rv
-_req_st_cond(struct drbd_conf *mdev, union drbd_state mask,
+_req_st_cond(struct drbd_device *device, union drbd_state mask,
union drbd_state val)
{
union drbd_state os, ns;
unsigned long flags;
enum drbd_state_rv rv;
- if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &mdev->flags))
+ if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &device->flags))
return SS_CW_SUCCESS;
- if (test_and_clear_bit(CL_ST_CHG_FAIL, &mdev->flags))
+ if (test_and_clear_bit(CL_ST_CHG_FAIL, &device->flags))
return SS_CW_FAILED_BY_PEER;
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- os = drbd_read_state(mdev);
- ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ os = drbd_read_state(device);
+ ns = sanitize_state(device, apply_mask_val(os, mask, val), NULL);
rv = is_valid_transition(os, ns);
if (rv >= SS_SUCCESS)
rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */
- if (!cl_wide_st_chg(mdev, os, ns))
+ if (!cl_wide_st_chg(device, os, ns))
rv = SS_CW_NO_NEED;
if (rv == SS_UNKNOWN_ERROR) {
- rv = is_valid_state(mdev, ns);
+ rv = is_valid_state(device, ns);
if (rv >= SS_SUCCESS) {
- rv = is_valid_soft_transition(os, ns, mdev->tconn);
+ rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection);
if (rv >= SS_SUCCESS)
rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */
}
}
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
return rv;
}
/**
* drbd_req_state() - Perform an eventually cluster wide state change
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @mask: mask of state bits to change.
* @val: value of new state bits.
* @f: flags
@@ -306,7 +318,7 @@ _req_st_cond(struct drbd_conf *mdev, union drbd_state mask,
* _drbd_request_state().
*/
static enum drbd_state_rv
-drbd_req_state(struct drbd_conf *mdev, union drbd_state mask,
+drbd_req_state(struct drbd_device *device, union drbd_state mask,
union drbd_state val, enum chg_state_flags f)
{
struct completion done;
@@ -317,68 +329,68 @@ drbd_req_state(struct drbd_conf *mdev, union drbd_state mask,
init_completion(&done);
if (f & CS_SERIALIZE)
- mutex_lock(mdev->state_mutex);
+ mutex_lock(device->state_mutex);
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- os = drbd_read_state(mdev);
- ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ os = drbd_read_state(device);
+ ns = sanitize_state(device, apply_mask_val(os, mask, val), NULL);
rv = is_valid_transition(os, ns);
if (rv < SS_SUCCESS) {
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
goto abort;
}
- if (cl_wide_st_chg(mdev, os, ns)) {
- rv = is_valid_state(mdev, ns);
+ if (cl_wide_st_chg(device, os, ns)) {
+ rv = is_valid_state(device, ns);
if (rv == SS_SUCCESS)
- rv = is_valid_soft_transition(os, ns, mdev->tconn);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
if (rv < SS_SUCCESS) {
if (f & CS_VERBOSE)
- print_st_err(mdev, os, ns, rv);
+ print_st_err(device, os, ns, rv);
goto abort;
}
- if (drbd_send_state_req(mdev, mask, val)) {
+ if (drbd_send_state_req(first_peer_device(device), mask, val)) {
rv = SS_CW_FAILED_BY_PEER;
if (f & CS_VERBOSE)
- print_st_err(mdev, os, ns, rv);
+ print_st_err(device, os, ns, rv);
goto abort;
}
- wait_event(mdev->state_wait,
- (rv = _req_st_cond(mdev, mask, val)));
+ wait_event(device->state_wait,
+ (rv = _req_st_cond(device, mask, val)));
if (rv < SS_SUCCESS) {
if (f & CS_VERBOSE)
- print_st_err(mdev, os, ns, rv);
+ print_st_err(device, os, ns, rv);
goto abort;
}
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- ns = apply_mask_val(drbd_read_state(mdev), mask, val);
- rv = _drbd_set_state(mdev, ns, f, &done);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ ns = apply_mask_val(drbd_read_state(device), mask, val);
+ rv = _drbd_set_state(device, ns, f, &done);
} else {
- rv = _drbd_set_state(mdev, ns, f, &done);
+ rv = _drbd_set_state(device, ns, f, &done);
}
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
if (f & CS_WAIT_COMPLETE && rv == SS_SUCCESS) {
- D_ASSERT(current != mdev->tconn->worker.task);
+ D_ASSERT(device, current != first_peer_device(device)->connection->worker.task);
wait_for_completion(&done);
}
abort:
if (f & CS_SERIALIZE)
- mutex_unlock(mdev->state_mutex);
+ mutex_unlock(device->state_mutex);
return rv;
}
/**
* _drbd_request_state() - Request a state change (with flags)
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @mask: mask of state bits to change.
* @val: value of new state bits.
* @f: flags
@@ -387,20 +399,20 @@ abort:
* flag, or when logging of failed state change requests is not desired.
*/
enum drbd_state_rv
-_drbd_request_state(struct drbd_conf *mdev, union drbd_state mask,
+_drbd_request_state(struct drbd_device *device, union drbd_state mask,
union drbd_state val, enum chg_state_flags f)
{
enum drbd_state_rv rv;
- wait_event(mdev->state_wait,
- (rv = drbd_req_state(mdev, mask, val, f)) != SS_IN_TRANSIENT_STATE);
+ wait_event(device->state_wait,
+ (rv = drbd_req_state(device, mask, val, f)) != SS_IN_TRANSIENT_STATE);
return rv;
}
-static void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns)
+static void print_st(struct drbd_device *device, char *name, union drbd_state ns)
{
- dev_err(DEV, " %s = { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c%c%c }\n",
+ drbd_err(device, " %s = { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c%c%c }\n",
name,
drbd_conn_str(ns.conn),
drbd_role_str(ns.role),
@@ -416,14 +428,14 @@ static void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns)
);
}
-void print_st_err(struct drbd_conf *mdev, union drbd_state os,
+void print_st_err(struct drbd_device *device, union drbd_state os,
union drbd_state ns, enum drbd_state_rv err)
{
if (err == SS_IN_TRANSIENT_STATE)
return;
- dev_err(DEV, "State change failed: %s\n", drbd_set_st_err_str(err));
- print_st(mdev, " state", os);
- print_st(mdev, "wanted", ns);
+ drbd_err(device, "State change failed: %s\n", drbd_set_st_err_str(err));
+ print_st(device, " state", os);
+ print_st(device, "wanted", ns);
}
static long print_state_change(char *pb, union drbd_state os, union drbd_state ns,
@@ -457,7 +469,7 @@ static long print_state_change(char *pb, union drbd_state os, union drbd_state n
return pbp - pb;
}
-static void drbd_pr_state_change(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns,
+static void drbd_pr_state_change(struct drbd_device *device, union drbd_state os, union drbd_state ns,
enum chg_state_flags flags)
{
char pb[300];
@@ -479,10 +491,10 @@ static void drbd_pr_state_change(struct drbd_conf *mdev, union drbd_state os, un
ns.user_isp);
if (pbp != pb)
- dev_info(DEV, "%s\n", pb);
+ drbd_info(device, "%s\n", pb);
}
-static void conn_pr_state_change(struct drbd_tconn *tconn, union drbd_state os, union drbd_state ns,
+static void conn_pr_state_change(struct drbd_connection *connection, union drbd_state os, union drbd_state ns,
enum chg_state_flags flags)
{
char pb[300];
@@ -496,17 +508,17 @@ static void conn_pr_state_change(struct drbd_tconn *tconn, union drbd_state os,
is_susp(ns));
if (pbp != pb)
- conn_info(tconn, "%s\n", pb);
+ drbd_info(connection, "%s\n", pb);
}
/**
* is_valid_state() - Returns an SS_ error code if ns is not valid
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @ns: State to consider.
*/
static enum drbd_state_rv
-is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
+is_valid_state(struct drbd_device *device, union drbd_state ns)
{
/* See drbd_state_sw_errors in drbd_strings.c */
@@ -516,24 +528,24 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
rcu_read_lock();
fp = FP_DONT_CARE;
- if (get_ldev(mdev)) {
- fp = rcu_dereference(mdev->ldev->disk_conf)->fencing;
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ fp = rcu_dereference(device->ldev->disk_conf)->fencing;
+ put_ldev(device);
}
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
if (nc) {
if (!nc->two_primaries && ns.role == R_PRIMARY) {
if (ns.peer == R_PRIMARY)
rv = SS_TWO_PRIMARIES;
- else if (conn_highest_peer(mdev->tconn) == R_PRIMARY)
+ else if (conn_highest_peer(first_peer_device(device)->connection) == R_PRIMARY)
rv = SS_O_VOL_PEER_PRI;
}
}
if (rv <= 0)
/* already found a reason to abort */;
- else if (ns.role == R_SECONDARY && mdev->open_cnt)
+ else if (ns.role == R_SECONDARY && device->open_cnt)
rv = SS_DEVICE_IN_USE;
else if (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.disk < D_UP_TO_DATE)
@@ -567,7 +579,7 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
rv = SS_NO_VERIFY_ALG;
else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) &&
- mdev->tconn->agreed_pro_version < 88)
+ first_peer_device(device)->connection->agreed_pro_version < 88)
rv = SS_NOT_SUPPORTED;
else if (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE)
@@ -589,12 +601,12 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
* is_valid_soft_transition() - Returns an SS_ error code if the state transition is not possible
* This function limits state transitions that may be declined by DRBD. I.e.
* user requests (aka soft transitions).
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @ns: new state.
* @os: old state.
*/
static enum drbd_state_rv
-is_valid_soft_transition(union drbd_state os, union drbd_state ns, struct drbd_tconn *tconn)
+is_valid_soft_transition(union drbd_state os, union drbd_state ns, struct drbd_connection *connection)
{
enum drbd_state_rv rv = SS_SUCCESS;
@@ -622,7 +634,7 @@ is_valid_soft_transition(union drbd_state os, union drbd_state ns, struct drbd_t
/* While establishing a connection only allow cstate to change.
Delay/refuse role changes, detach attach etc... */
- if (test_bit(STATE_SENT, &tconn->flags) &&
+ if (test_bit(STATE_SENT, &connection->flags) &&
!(os.conn == C_WF_REPORT_PARAMS ||
(ns.conn == C_WF_REPORT_PARAMS && os.conn == C_WF_CONNECTION)))
rv = SS_IN_TRANSIENT_STATE;
@@ -703,7 +715,7 @@ is_valid_transition(union drbd_state os, union drbd_state ns)
return rv;
}
-static void print_sanitize_warnings(struct drbd_conf *mdev, enum sanitize_state_warnings warn)
+static void print_sanitize_warnings(struct drbd_device *device, enum sanitize_state_warnings warn)
{
static const char *msg_table[] = {
[NO_WARNING] = "",
@@ -715,12 +727,12 @@ static void print_sanitize_warnings(struct drbd_conf *mdev, enum sanitize_state_
};
if (warn != NO_WARNING)
- dev_warn(DEV, "%s\n", msg_table[warn]);
+ drbd_warn(device, "%s\n", msg_table[warn]);
}
/**
* sanitize_state() - Resolves implicitly necessary additional changes to a state transition
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @os: old state.
* @ns: new state.
* @warn_sync_abort:
@@ -728,7 +740,7 @@ static void print_sanitize_warnings(struct drbd_conf *mdev, enum sanitize_state_
* When we loose connection, we have to set the state of the peers disk (pdsk)
* to D_UNKNOWN. This rule and many more along those lines are in this function.
*/
-static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state ns,
+static union drbd_state sanitize_state(struct drbd_device *device, union drbd_state ns,
enum sanitize_state_warnings *warn)
{
enum drbd_fencing_p fp;
@@ -738,11 +750,11 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state
*warn = NO_WARNING;
fp = FP_DONT_CARE;
- if (get_ldev(mdev)) {
+ if (get_ldev(device)) {
rcu_read_lock();
- fp = rcu_dereference(mdev->ldev->disk_conf)->fencing;
+ fp = rcu_dereference(device->ldev->disk_conf)->fencing;
rcu_read_unlock();
- put_ldev(mdev);
+ put_ldev(device);
}
/* Implications from connection to peer and peer_isp */
@@ -768,17 +780,17 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state
/* Connection breaks down before we finished "Negotiating" */
if (ns.conn < C_CONNECTED && ns.disk == D_NEGOTIATING &&
- get_ldev_if_state(mdev, D_NEGOTIATING)) {
- if (mdev->ed_uuid == mdev->ldev->md.uuid[UI_CURRENT]) {
- ns.disk = mdev->new_state_tmp.disk;
- ns.pdsk = mdev->new_state_tmp.pdsk;
+ get_ldev_if_state(device, D_NEGOTIATING)) {
+ if (device->ed_uuid == device->ldev->md.uuid[UI_CURRENT]) {
+ ns.disk = device->new_state_tmp.disk;
+ ns.pdsk = device->new_state_tmp.pdsk;
} else {
if (warn)
*warn = CONNECTION_LOST_NEGOTIATING;
ns.disk = D_DISKLESS;
ns.pdsk = D_UNKNOWN;
}
- put_ldev(mdev);
+ put_ldev(device);
}
/* D_CONSISTENT and D_OUTDATED vanish when we get connected */
@@ -873,7 +885,7 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state
(ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED))
ns.susp_fen = 1; /* Suspend IO while fence-peer handler runs (peer lost) */
- if (mdev->tconn->res_opts.on_no_data == OND_SUSPEND_IO &&
+ if (device->resource->res_opts.on_no_data == OND_SUSPEND_IO &&
(ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE))
ns.susp_nod = 1; /* Suspend IO while no data available (no accessible data available) */
@@ -892,42 +904,42 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state
return ns;
}
-void drbd_resume_al(struct drbd_conf *mdev)
+void drbd_resume_al(struct drbd_device *device)
{
- if (test_and_clear_bit(AL_SUSPENDED, &mdev->flags))
- dev_info(DEV, "Resumed AL updates\n");
+ if (test_and_clear_bit(AL_SUSPENDED, &device->flags))
+ drbd_info(device, "Resumed AL updates\n");
}
/* helper for __drbd_set_state */
-static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs)
+static void set_ov_position(struct drbd_device *device, enum drbd_conns cs)
{
- if (mdev->tconn->agreed_pro_version < 90)
- mdev->ov_start_sector = 0;
- mdev->rs_total = drbd_bm_bits(mdev);
- mdev->ov_position = 0;
+ if (first_peer_device(device)->connection->agreed_pro_version < 90)
+ device->ov_start_sector = 0;
+ device->rs_total = drbd_bm_bits(device);
+ device->ov_position = 0;
if (cs == C_VERIFY_T) {
/* starting online verify from an arbitrary position
* does not fit well into the existing protocol.
* on C_VERIFY_T, we initialize ov_left and friends
* implicitly in receive_DataRequest once the
* first P_OV_REQUEST is received */
- mdev->ov_start_sector = ~(sector_t)0;
+ device->ov_start_sector = ~(sector_t)0;
} else {
- unsigned long bit = BM_SECT_TO_BIT(mdev->ov_start_sector);
- if (bit >= mdev->rs_total) {
- mdev->ov_start_sector =
- BM_BIT_TO_SECT(mdev->rs_total - 1);
- mdev->rs_total = 1;
+ unsigned long bit = BM_SECT_TO_BIT(device->ov_start_sector);
+ if (bit >= device->rs_total) {
+ device->ov_start_sector =
+ BM_BIT_TO_SECT(device->rs_total - 1);
+ device->rs_total = 1;
} else
- mdev->rs_total -= bit;
- mdev->ov_position = mdev->ov_start_sector;
+ device->rs_total -= bit;
+ device->ov_position = device->ov_start_sector;
}
- mdev->ov_left = mdev->rs_total;
+ device->ov_left = device->rs_total;
}
/**
* __drbd_set_state() - Set a new DRBD state
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @ns: new state.
* @flags: Flags
* @done: Optional completion, that will get completed after the after_state_ch() finished
@@ -935,7 +947,7 @@ static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs)
* Caller needs to hold req_lock, and global_state_lock. Do not call directly.
*/
enum drbd_state_rv
-__drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
+__drbd_set_state(struct drbd_device *device, union drbd_state ns,
enum chg_state_flags flags, struct completion *done)
{
union drbd_state os;
@@ -944,9 +956,9 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
struct after_state_chg_work *ascw;
bool did_remote, should_do_remote;
- os = drbd_read_state(mdev);
+ os = drbd_read_state(device);
- ns = sanitize_state(mdev, ns, &ssw);
+ ns = sanitize_state(device, ns, &ssw);
if (ns.i == os.i)
return SS_NOTHING_TO_DO;
@@ -958,32 +970,33 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
/* pre-state-change checks ; only look at ns */
/* See drbd_state_sw_errors in drbd_strings.c */
- rv = is_valid_state(mdev, ns);
+ rv = is_valid_state(device, ns);
if (rv < SS_SUCCESS) {
/* If the old state was illegal as well, then let
this happen...*/
- if (is_valid_state(mdev, os) == rv)
- rv = is_valid_soft_transition(os, ns, mdev->tconn);
+ if (is_valid_state(device, os) == rv)
+ rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection);
} else
- rv = is_valid_soft_transition(os, ns, mdev->tconn);
+ rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection);
}
if (rv < SS_SUCCESS) {
if (flags & CS_VERBOSE)
- print_st_err(mdev, os, ns, rv);
+ print_st_err(device, os, ns, rv);
return rv;
}
- print_sanitize_warnings(mdev, ssw);
+ print_sanitize_warnings(device, ssw);
- drbd_pr_state_change(mdev, os, ns, flags);
+ drbd_pr_state_change(device, os, ns, flags);
/* Display changes to the susp* flags that where caused by the call to
sanitize_state(). Only display it here if we where not called from
_conn_request_state() */
if (!(flags & CS_DC_SUSP))
- conn_pr_state_change(mdev->tconn, os, ns, (flags & ~CS_DC_MASK) | CS_DC_SUSP);
+ conn_pr_state_change(first_peer_device(device)->connection, os, ns,
+ (flags & ~CS_DC_MASK) | CS_DC_SUSP);
/* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference
* on the ldev here, to be sure the transition -> D_DISKLESS resp.
@@ -991,55 +1004,55 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
* after_state_ch works run, where we put_ldev again. */
if ((os.disk != D_FAILED && ns.disk == D_FAILED) ||
(os.disk != D_DISKLESS && ns.disk == D_DISKLESS))
- atomic_inc(&mdev->local_cnt);
+ atomic_inc(&device->local_cnt);
- did_remote = drbd_should_do_remote(mdev->state);
- mdev->state.i = ns.i;
- should_do_remote = drbd_should_do_remote(mdev->state);
- mdev->tconn->susp = ns.susp;
- mdev->tconn->susp_nod = ns.susp_nod;
- mdev->tconn->susp_fen = ns.susp_fen;
+ did_remote = drbd_should_do_remote(device->state);
+ device->state.i = ns.i;
+ should_do_remote = drbd_should_do_remote(device->state);
+ device->resource->susp = ns.susp;
+ device->resource->susp_nod = ns.susp_nod;
+ device->resource->susp_fen = ns.susp_fen;
/* put replicated vs not-replicated requests in seperate epochs */
if (did_remote != should_do_remote)
- start_new_tl_epoch(mdev->tconn);
+ start_new_tl_epoch(first_peer_device(device)->connection);
if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING)
- drbd_print_uuids(mdev, "attached to UUIDs");
+ drbd_print_uuids(device, "attached to UUIDs");
/* Wake up role changes, that were delayed because of connection establishing */
if (os.conn == C_WF_REPORT_PARAMS && ns.conn != C_WF_REPORT_PARAMS &&
- no_peer_wf_report_params(mdev->tconn))
- clear_bit(STATE_SENT, &mdev->tconn->flags);
+ no_peer_wf_report_params(first_peer_device(device)->connection))
+ clear_bit(STATE_SENT, &first_peer_device(device)->connection->flags);
- wake_up(&mdev->misc_wait);
- wake_up(&mdev->state_wait);
- wake_up(&mdev->tconn->ping_wait);
+ wake_up(&device->misc_wait);
+ wake_up(&device->state_wait);
+ wake_up(&first_peer_device(device)->connection->ping_wait);
/* Aborted verify run, or we reached the stop sector.
* Log the last position, unless end-of-device. */
if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) &&
ns.conn <= C_CONNECTED) {
- mdev->ov_start_sector =
- BM_BIT_TO_SECT(drbd_bm_bits(mdev) - mdev->ov_left);
- if (mdev->ov_left)
- dev_info(DEV, "Online Verify reached sector %llu\n",
- (unsigned long long)mdev->ov_start_sector);
+ device->ov_start_sector =
+ BM_BIT_TO_SECT(drbd_bm_bits(device) - device->ov_left);
+ if (device->ov_left)
+ drbd_info(device, "Online Verify reached sector %llu\n",
+ (unsigned long long)device->ov_start_sector);
}
if ((os.conn == C_PAUSED_SYNC_T || os.conn == C_PAUSED_SYNC_S) &&
(ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE)) {
- dev_info(DEV, "Syncer continues.\n");
- mdev->rs_paused += (long)jiffies
- -(long)mdev->rs_mark_time[mdev->rs_last_mark];
+ drbd_info(device, "Syncer continues.\n");
+ device->rs_paused += (long)jiffies
+ -(long)device->rs_mark_time[device->rs_last_mark];
if (ns.conn == C_SYNC_TARGET)
- mod_timer(&mdev->resync_timer, jiffies);
+ mod_timer(&device->resync_timer, jiffies);
}
if ((os.conn == C_SYNC_TARGET || os.conn == C_SYNC_SOURCE) &&
(ns.conn == C_PAUSED_SYNC_T || ns.conn == C_PAUSED_SYNC_S)) {
- dev_info(DEV, "Resync suspended\n");
- mdev->rs_mark_time[mdev->rs_last_mark] = jiffies;
+ drbd_info(device, "Resync suspended\n");
+ device->rs_mark_time[device->rs_last_mark] = jiffies;
}
if (os.conn == C_CONNECTED &&
@@ -1047,77 +1060,77 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
unsigned long now = jiffies;
int i;
- set_ov_position(mdev, ns.conn);
- mdev->rs_start = now;
- mdev->rs_last_events = 0;
- mdev->rs_last_sect_ev = 0;
- mdev->ov_last_oos_size = 0;
- mdev->ov_last_oos_start = 0;
+ set_ov_position(device, ns.conn);
+ device->rs_start = now;
+ device->rs_last_events = 0;
+ device->rs_last_sect_ev = 0;
+ device->ov_last_oos_size = 0;
+ device->ov_last_oos_start = 0;
for (i = 0; i < DRBD_SYNC_MARKS; i++) {
- mdev->rs_mark_left[i] = mdev->ov_left;
- mdev->rs_mark_time[i] = now;
+ device->rs_mark_left[i] = device->ov_left;
+ device->rs_mark_time[i] = now;
}
- drbd_rs_controller_reset(mdev);
+ drbd_rs_controller_reset(device);
if (ns.conn == C_VERIFY_S) {
- dev_info(DEV, "Starting Online Verify from sector %llu\n",
- (unsigned long long)mdev->ov_position);
- mod_timer(&mdev->resync_timer, jiffies);
+ drbd_info(device, "Starting Online Verify from sector %llu\n",
+ (unsigned long long)device->ov_position);
+ mod_timer(&device->resync_timer, jiffies);
}
}
- if (get_ldev(mdev)) {
- u32 mdf = mdev->ldev->md.flags & ~(MDF_CONSISTENT|MDF_PRIMARY_IND|
+ if (get_ldev(device)) {
+ u32 mdf = device->ldev->md.flags & ~(MDF_CONSISTENT|MDF_PRIMARY_IND|
MDF_CONNECTED_IND|MDF_WAS_UP_TO_DATE|
MDF_PEER_OUT_DATED|MDF_CRASHED_PRIMARY);
mdf &= ~MDF_AL_CLEAN;
- if (test_bit(CRASHED_PRIMARY, &mdev->flags))
+ if (test_bit(CRASHED_PRIMARY, &device->flags))
mdf |= MDF_CRASHED_PRIMARY;
- if (mdev->state.role == R_PRIMARY ||
- (mdev->state.pdsk < D_INCONSISTENT && mdev->state.peer == R_PRIMARY))
+ if (device->state.role == R_PRIMARY ||
+ (device->state.pdsk < D_INCONSISTENT && device->state.peer == R_PRIMARY))
mdf |= MDF_PRIMARY_IND;
- if (mdev->state.conn > C_WF_REPORT_PARAMS)
+ if (device->state.conn > C_WF_REPORT_PARAMS)
mdf |= MDF_CONNECTED_IND;
- if (mdev->state.disk > D_INCONSISTENT)
+ if (device->state.disk > D_INCONSISTENT)
mdf |= MDF_CONSISTENT;
- if (mdev->state.disk > D_OUTDATED)
+ if (device->state.disk > D_OUTDATED)
mdf |= MDF_WAS_UP_TO_DATE;
- if (mdev->state.pdsk <= D_OUTDATED && mdev->state.pdsk >= D_INCONSISTENT)
+ if (device->state.pdsk <= D_OUTDATED && device->state.pdsk >= D_INCONSISTENT)
mdf |= MDF_PEER_OUT_DATED;
- if (mdf != mdev->ldev->md.flags) {
- mdev->ldev->md.flags = mdf;
- drbd_md_mark_dirty(mdev);
+ if (mdf != device->ldev->md.flags) {
+ device->ldev->md.flags = mdf;
+ drbd_md_mark_dirty(device);
}
if (os.disk < D_CONSISTENT && ns.disk >= D_CONSISTENT)
- drbd_set_ed_uuid(mdev, mdev->ldev->md.uuid[UI_CURRENT]);
- put_ldev(mdev);
+ drbd_set_ed_uuid(device, device->ldev->md.uuid[UI_CURRENT]);
+ put_ldev(device);
}
/* Peer was forced D_UP_TO_DATE & R_PRIMARY, consider to resync */
if (os.disk == D_INCONSISTENT && os.pdsk == D_INCONSISTENT &&
os.peer == R_SECONDARY && ns.peer == R_PRIMARY)
- set_bit(CONSIDER_RESYNC, &mdev->flags);
+ set_bit(CONSIDER_RESYNC, &device->flags);
/* Receiver should clean up itself */
if (os.conn != C_DISCONNECTING && ns.conn == C_DISCONNECTING)
- drbd_thread_stop_nowait(&mdev->tconn->receiver);
+ drbd_thread_stop_nowait(&first_peer_device(device)->connection->receiver);
/* Now the receiver finished cleaning up itself, it should die */
if (os.conn != C_STANDALONE && ns.conn == C_STANDALONE)
- drbd_thread_stop_nowait(&mdev->tconn->receiver);
+ drbd_thread_stop_nowait(&first_peer_device(device)->connection->receiver);
/* Upon network failure, we need to restart the receiver. */
if (os.conn > C_WF_CONNECTION &&
ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT)
- drbd_thread_restart_nowait(&mdev->tconn->receiver);
+ drbd_thread_restart_nowait(&first_peer_device(device)->connection->receiver);
/* Resume AL writing if we get a connection */
if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) {
- drbd_resume_al(mdev);
- mdev->tconn->connect_cnt++;
+ drbd_resume_al(device);
+ first_peer_device(device)->connection->connect_cnt++;
}
/* remember last attach time so request_timer_fn() won't
@@ -1125,7 +1138,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
* previously frozen IO */
if ((os.disk == D_ATTACHING || os.disk == D_NEGOTIATING) &&
ns.disk > D_NEGOTIATING)
- mdev->last_reattach_jif = jiffies;
+ device->last_reattach_jif = jiffies;
ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC);
if (ascw) {
@@ -1133,11 +1146,12 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
ascw->ns = ns;
ascw->flags = flags;
ascw->w.cb = w_after_state_ch;
- ascw->w.mdev = mdev;
+ ascw->device = device;
ascw->done = done;
- drbd_queue_work(&mdev->tconn->sender_work, &ascw->w);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &ascw->w);
} else {
- dev_err(DEV, "Could not kmalloc an ascw\n");
+ drbd_err(device, "Could not kmalloc an ascw\n");
}
return rv;
@@ -1147,66 +1161,65 @@ static int w_after_state_ch(struct drbd_work *w, int unused)
{
struct after_state_chg_work *ascw =
container_of(w, struct after_state_chg_work, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device = ascw->device;
- after_state_ch(mdev, ascw->os, ascw->ns, ascw->flags);
- if (ascw->flags & CS_WAIT_COMPLETE) {
- D_ASSERT(ascw->done != NULL);
+ after_state_ch(device, ascw->os, ascw->ns, ascw->flags);
+ if (ascw->flags & CS_WAIT_COMPLETE)
complete(ascw->done);
- }
kfree(ascw);
return 0;
}
-static void abw_start_sync(struct drbd_conf *mdev, int rv)
+static void abw_start_sync(struct drbd_device *device, int rv)
{
if (rv) {
- dev_err(DEV, "Writing the bitmap failed not starting resync.\n");
- _drbd_request_state(mdev, NS(conn, C_CONNECTED), CS_VERBOSE);
+ drbd_err(device, "Writing the bitmap failed not starting resync.\n");
+ _drbd_request_state(device, NS(conn, C_CONNECTED), CS_VERBOSE);
return;
}
- switch (mdev->state.conn) {
+ switch (device->state.conn) {
case C_STARTING_SYNC_T:
- _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE);
+ _drbd_request_state(device, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE);
break;
case C_STARTING_SYNC_S:
- drbd_start_resync(mdev, C_SYNC_SOURCE);
+ drbd_start_resync(device, C_SYNC_SOURCE);
break;
}
}
-int drbd_bitmap_io_from_worker(struct drbd_conf *mdev,
- int (*io_fn)(struct drbd_conf *),
+int drbd_bitmap_io_from_worker(struct drbd_device *device,
+ int (*io_fn)(struct drbd_device *),
char *why, enum bm_flag flags)
{
int rv;
- D_ASSERT(current == mdev->tconn->worker.task);
+ D_ASSERT(device, current == first_peer_device(device)->connection->worker.task);
- /* open coded non-blocking drbd_suspend_io(mdev); */
- set_bit(SUSPEND_IO, &mdev->flags);
+ /* open coded non-blocking drbd_suspend_io(device); */
+ set_bit(SUSPEND_IO, &device->flags);
- drbd_bm_lock(mdev, why, flags);
- rv = io_fn(mdev);
- drbd_bm_unlock(mdev);
+ drbd_bm_lock(device, why, flags);
+ rv = io_fn(device);
+ drbd_bm_unlock(device);
- drbd_resume_io(mdev);
+ drbd_resume_io(device);
return rv;
}
/**
* after_state_ch() - Perform after state change actions that may sleep
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @os: old state.
* @ns: new state.
* @flags: Flags
*/
-static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
+static void after_state_ch(struct drbd_device *device, union drbd_state os,
union drbd_state ns, enum chg_state_flags flags)
{
+ struct drbd_resource *resource = device->resource;
struct sib_info sib;
sib.sib_reason = SIB_STATE_CHANGE;
@@ -1214,63 +1227,63 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
sib.ns = ns;
if (os.conn != C_CONNECTED && ns.conn == C_CONNECTED) {
- clear_bit(CRASHED_PRIMARY, &mdev->flags);
- if (mdev->p_uuid)
- mdev->p_uuid[UI_FLAGS] &= ~((u64)2);
+ clear_bit(CRASHED_PRIMARY, &device->flags);
+ if (device->p_uuid)
+ device->p_uuid[UI_FLAGS] &= ~((u64)2);
}
/* Inform userspace about the change... */
- drbd_bcast_event(mdev, &sib);
+ drbd_bcast_event(device, &sib);
if (!(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE) &&
(ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE))
- drbd_khelper(mdev, "pri-on-incon-degr");
+ drbd_khelper(device, "pri-on-incon-degr");
/* Here we have the actions that are performed after a
state change. This function might sleep */
if (ns.susp_nod) {
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
enum drbd_req_event what = NOTHING;
- spin_lock_irq(&tconn->req_lock);
- if (os.conn < C_CONNECTED && conn_lowest_conn(tconn) >= C_CONNECTED)
+ spin_lock_irq(&device->resource->req_lock);
+ if (os.conn < C_CONNECTED && conn_lowest_conn(connection) >= C_CONNECTED)
what = RESEND;
if ((os.disk == D_ATTACHING || os.disk == D_NEGOTIATING) &&
- conn_lowest_disk(tconn) > D_NEGOTIATING)
+ conn_lowest_disk(connection) > D_NEGOTIATING)
what = RESTART_FROZEN_DISK_IO;
- if (tconn->susp_nod && what != NOTHING) {
- _tl_restart(tconn, what);
- _conn_request_state(tconn,
+ if (resource->susp_nod && what != NOTHING) {
+ _tl_restart(connection, what);
+ _conn_request_state(connection,
(union drbd_state) { { .susp_nod = 1 } },
(union drbd_state) { { .susp_nod = 0 } },
CS_VERBOSE);
}
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
}
if (ns.susp_fen) {
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
- spin_lock_irq(&tconn->req_lock);
- if (tconn->susp_fen && conn_lowest_conn(tconn) >= C_CONNECTED) {
+ spin_lock_irq(&device->resource->req_lock);
+ if (resource->susp_fen && conn_lowest_conn(connection) >= C_CONNECTED) {
/* case2: The connection was established again: */
- struct drbd_conf *odev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, odev, vnr)
- clear_bit(NEW_CUR_UUID, &odev->flags);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr)
+ clear_bit(NEW_CUR_UUID, &peer_device->device->flags);
rcu_read_unlock();
- _tl_restart(tconn, RESEND);
- _conn_request_state(tconn,
+ _tl_restart(connection, RESEND);
+ _conn_request_state(connection,
(union drbd_state) { { .susp_fen = 1 } },
(union drbd_state) { { .susp_fen = 0 } },
CS_VERBOSE);
}
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
}
/* Became sync source. With protocol >= 96, we still need to send out
@@ -1279,9 +1292,9 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
* which is unexpected. */
if ((os.conn != C_SYNC_SOURCE && os.conn != C_PAUSED_SYNC_S) &&
(ns.conn == C_SYNC_SOURCE || ns.conn == C_PAUSED_SYNC_S) &&
- mdev->tconn->agreed_pro_version >= 96 && get_ldev(mdev)) {
- drbd_gen_and_send_sync_uuid(mdev);
- put_ldev(mdev);
+ first_peer_device(device)->connection->agreed_pro_version >= 96 && get_ldev(device)) {
+ drbd_gen_and_send_sync_uuid(first_peer_device(device));
+ put_ldev(device);
}
/* Do not change the order of the if above and the two below... */
@@ -1289,20 +1302,20 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
ns.pdsk > D_DISKLESS && ns.pdsk != D_UNKNOWN) { /* attach on the peer */
/* we probably will start a resync soon.
* make sure those things are properly reset. */
- mdev->rs_total = 0;
- mdev->rs_failed = 0;
- atomic_set(&mdev->rs_pending_cnt, 0);
- drbd_rs_cancel_all(mdev);
+ device->rs_total = 0;
+ device->rs_failed = 0;
+ atomic_set(&device->rs_pending_cnt, 0);
+ drbd_rs_cancel_all(device);
- drbd_send_uuids(mdev);
- drbd_send_state(mdev, ns);
+ drbd_send_uuids(first_peer_device(device));
+ drbd_send_state(first_peer_device(device), ns);
}
/* No point in queuing send_bitmap if we don't have a connection
* anymore, so check also the _current_ state, not only the new state
* at the time this work was queued. */
if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S &&
- mdev->state.conn == C_WF_BITMAP_S)
- drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL,
+ device->state.conn == C_WF_BITMAP_S)
+ drbd_queue_bitmap_io(device, &drbd_send_bitmap, NULL,
"send_bitmap (WFBitMapS)",
BM_LOCKED_TEST_ALLOWED);
@@ -1313,80 +1326,80 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
&& (ns.pdsk < D_INCONSISTENT ||
ns.pdsk == D_UNKNOWN ||
ns.pdsk == D_OUTDATED)) {
- if (get_ldev(mdev)) {
+ if (get_ldev(device)) {
if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) &&
- mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
- if (drbd_suspended(mdev)) {
- set_bit(NEW_CUR_UUID, &mdev->flags);
+ device->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
+ if (drbd_suspended(device)) {
+ set_bit(NEW_CUR_UUID, &device->flags);
} else {
- drbd_uuid_new_current(mdev);
- drbd_send_uuids(mdev);
+ drbd_uuid_new_current(device);
+ drbd_send_uuids(first_peer_device(device));
}
}
- put_ldev(mdev);
+ put_ldev(device);
}
}
- if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) {
+ if (ns.pdsk < D_INCONSISTENT && get_ldev(device)) {
if (os.peer == R_SECONDARY && ns.peer == R_PRIMARY &&
- mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
- drbd_uuid_new_current(mdev);
- drbd_send_uuids(mdev);
+ device->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
+ drbd_uuid_new_current(device);
+ drbd_send_uuids(first_peer_device(device));
}
/* D_DISKLESS Peer becomes secondary */
if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY)
/* We may still be Primary ourselves.
* No harm done if the bitmap still changes,
* redirtied pages will follow later. */
- drbd_bitmap_io_from_worker(mdev, &drbd_bm_write,
+ drbd_bitmap_io_from_worker(device, &drbd_bm_write,
"demote diskless peer", BM_LOCKED_SET_ALLOWED);
- put_ldev(mdev);
+ put_ldev(device);
}
/* Write out all changed bits on demote.
* Though, no need to da that just yet
* if there is a resync going on still */
if (os.role == R_PRIMARY && ns.role == R_SECONDARY &&
- mdev->state.conn <= C_CONNECTED && get_ldev(mdev)) {
+ device->state.conn <= C_CONNECTED && get_ldev(device)) {
/* No changes to the bitmap expected this time, so assert that,
* even though no harm was done if it did change. */
- drbd_bitmap_io_from_worker(mdev, &drbd_bm_write,
+ drbd_bitmap_io_from_worker(device, &drbd_bm_write,
"demote", BM_LOCKED_TEST_ALLOWED);
- put_ldev(mdev);
+ put_ldev(device);
}
/* Last part of the attaching process ... */
if (ns.conn >= C_CONNECTED &&
os.disk == D_ATTACHING && ns.disk == D_NEGOTIATING) {
- drbd_send_sizes(mdev, 0, 0); /* to start sync... */
- drbd_send_uuids(mdev);
- drbd_send_state(mdev, ns);
+ drbd_send_sizes(first_peer_device(device), 0, 0); /* to start sync... */
+ drbd_send_uuids(first_peer_device(device));
+ drbd_send_state(first_peer_device(device), ns);
}
/* We want to pause/continue resync, tell peer. */
if (ns.conn >= C_CONNECTED &&
((os.aftr_isp != ns.aftr_isp) ||
(os.user_isp != ns.user_isp)))
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
/* In case one of the isp bits got set, suspend other devices. */
if ((!os.aftr_isp && !os.peer_isp && !os.user_isp) &&
(ns.aftr_isp || ns.peer_isp || ns.user_isp))
- suspend_other_sg(mdev);
+ suspend_other_sg(device);
/* Make sure the peer gets informed about eventual state
changes (ISP bits) while we were in WFReportParams. */
if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED)
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
if (os.conn != C_AHEAD && ns.conn == C_AHEAD)
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
/* We are in the progress to start a full sync... */
if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) ||
(os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S))
/* no other bitmap changes expected during this phase */
- drbd_queue_bitmap_io(mdev,
+ drbd_queue_bitmap_io(device,
&drbd_bmio_set_n_write, &abw_start_sync,
"set_n_write from StartingSync", BM_LOCKED_TEST_ALLOWED);
@@ -1399,15 +1412,15 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
* our cleanup here with the transition to D_DISKLESS.
* But is is still not save to dreference ldev here, since
* we might come from an failed Attach before ldev was set. */
- if (mdev->ldev) {
+ if (device->ldev) {
rcu_read_lock();
- eh = rcu_dereference(mdev->ldev->disk_conf)->on_io_error;
+ eh = rcu_dereference(device->ldev->disk_conf)->on_io_error;
rcu_read_unlock();
- was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags);
+ was_io_error = test_and_clear_bit(WAS_IO_ERROR, &device->flags);
if (was_io_error && eh == EP_CALL_HELPER)
- drbd_khelper(mdev, "local-io-error");
+ drbd_khelper(device, "local-io-error");
/* Immediately allow completion of all application IO,
* that waits for completion from the local disk,
@@ -1422,76 +1435,76 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
* So aborting local requests may cause crashes,
* or even worse, silent data corruption.
*/
- if (test_and_clear_bit(FORCE_DETACH, &mdev->flags))
- tl_abort_disk_io(mdev);
+ if (test_and_clear_bit(FORCE_DETACH, &device->flags))
+ tl_abort_disk_io(device);
/* current state still has to be D_FAILED,
* there is only one way out: to D_DISKLESS,
* and that may only happen after our put_ldev below. */
- if (mdev->state.disk != D_FAILED)
- dev_err(DEV,
+ if (device->state.disk != D_FAILED)
+ drbd_err(device,
"ASSERT FAILED: disk is %s during detach\n",
- drbd_disk_str(mdev->state.disk));
+ drbd_disk_str(device->state.disk));
if (ns.conn >= C_CONNECTED)
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
- drbd_rs_cancel_all(mdev);
+ drbd_rs_cancel_all(device);
/* In case we want to get something to stable storage still,
* this may be the last chance.
* Following put_ldev may transition to D_DISKLESS. */
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
}
- put_ldev(mdev);
+ put_ldev(device);
}
- /* second half of local IO error, failure to attach,
- * or administrative detach,
- * after local_cnt references have reached zero again */
- if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) {
- /* We must still be diskless,
- * re-attach has to be serialized with this! */
- if (mdev->state.disk != D_DISKLESS)
- dev_err(DEV,
- "ASSERT FAILED: disk is %s while going diskless\n",
- drbd_disk_str(mdev->state.disk));
+ /* second half of local IO error, failure to attach,
+ * or administrative detach,
+ * after local_cnt references have reached zero again */
+ if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) {
+ /* We must still be diskless,
+ * re-attach has to be serialized with this! */
+ if (device->state.disk != D_DISKLESS)
+ drbd_err(device,
+ "ASSERT FAILED: disk is %s while going diskless\n",
+ drbd_disk_str(device->state.disk));
if (ns.conn >= C_CONNECTED)
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
/* corresponding get_ldev in __drbd_set_state
* this may finally trigger drbd_ldev_destroy. */
- put_ldev(mdev);
+ put_ldev(device);
}
/* Notify peer that I had a local IO error, and did not detached.. */
if (os.disk == D_UP_TO_DATE && ns.disk == D_INCONSISTENT && ns.conn >= C_CONNECTED)
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
/* Disks got bigger while they were detached */
if (ns.disk > D_NEGOTIATING && ns.pdsk > D_NEGOTIATING &&
- test_and_clear_bit(RESYNC_AFTER_NEG, &mdev->flags)) {
+ test_and_clear_bit(RESYNC_AFTER_NEG, &device->flags)) {
if (ns.conn == C_CONNECTED)
- resync_after_online_grow(mdev);
+ resync_after_online_grow(device);
}
/* A resync finished or aborted, wake paused devices... */
if ((os.conn > C_CONNECTED && ns.conn <= C_CONNECTED) ||
(os.peer_isp && !ns.peer_isp) ||
(os.user_isp && !ns.user_isp))
- resume_next_sg(mdev);
+ resume_next_sg(device);
/* sync target done with resync. Explicitly notify peer, even though
* it should (at least for non-empty resyncs) already know itself. */
if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED)
- drbd_send_state(mdev, ns);
+ drbd_send_state(first_peer_device(device), ns);
/* Verify finished, or reached stop sector. Peer did not know about
* the stop sector, and we may even have changed the stop sector during
* verify to interrupt/stop early. Send the new state. */
if (os.conn == C_VERIFY_S && ns.conn == C_CONNECTED
- && verify_can_do_stop_sector(mdev))
- drbd_send_state(mdev, ns);
+ && verify_can_do_stop_sector(device))
+ drbd_send_state(first_peer_device(device), ns);
/* This triggers bitmap writeout of potentially still unwritten pages
* if the resync finished cleanly, or aborted because of peer disk
@@ -1500,56 +1513,57 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
* any bitmap writeout anymore.
* No harm done if some bits change during this phase.
*/
- if (os.conn > C_CONNECTED && ns.conn <= C_CONNECTED && get_ldev(mdev)) {
- drbd_queue_bitmap_io(mdev, &drbd_bm_write_copy_pages, NULL,
+ if (os.conn > C_CONNECTED && ns.conn <= C_CONNECTED && get_ldev(device)) {
+ drbd_queue_bitmap_io(device, &drbd_bm_write_copy_pages, NULL,
"write from resync_finished", BM_LOCKED_CHANGE_ALLOWED);
- put_ldev(mdev);
+ put_ldev(device);
}
if (ns.disk == D_DISKLESS &&
ns.conn == C_STANDALONE &&
ns.role == R_SECONDARY) {
if (os.aftr_isp != ns.aftr_isp)
- resume_next_sg(mdev);
+ resume_next_sg(device);
}
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
}
struct after_conn_state_chg_work {
struct drbd_work w;
enum drbd_conns oc;
union drbd_state ns_min;
- union drbd_state ns_max; /* new, max state, over all mdevs */
+ union drbd_state ns_max; /* new, max state, over all devices */
enum chg_state_flags flags;
+ struct drbd_connection *connection;
};
static int w_after_conn_state_ch(struct drbd_work *w, int unused)
{
struct after_conn_state_chg_work *acscw =
container_of(w, struct after_conn_state_chg_work, w);
- struct drbd_tconn *tconn = w->tconn;
+ struct drbd_connection *connection = acscw->connection;
enum drbd_conns oc = acscw->oc;
union drbd_state ns_max = acscw->ns_max;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
kfree(acscw);
/* Upon network configuration, we need to start the receiver */
if (oc == C_STANDALONE && ns_max.conn == C_UNCONNECTED)
- drbd_thread_start(&tconn->receiver);
+ drbd_thread_start(&connection->receiver);
if (oc == C_DISCONNECTING && ns_max.conn == C_STANDALONE) {
struct net_conf *old_conf;
- mutex_lock(&tconn->conf_update);
- old_conf = tconn->net_conf;
- tconn->my_addr_len = 0;
- tconn->peer_addr_len = 0;
- rcu_assign_pointer(tconn->net_conf, NULL);
- conn_free_crypto(tconn);
- mutex_unlock(&tconn->conf_update);
+ mutex_lock(&connection->resource->conf_update);
+ old_conf = connection->net_conf;
+ connection->my_addr_len = 0;
+ connection->peer_addr_len = 0;
+ rcu_assign_pointer(connection->net_conf, NULL);
+ conn_free_crypto(connection);
+ mutex_unlock(&connection->resource->conf_update);
synchronize_rcu();
kfree(old_conf);
@@ -1559,45 +1573,47 @@ static int w_after_conn_state_ch(struct drbd_work *w, int unused)
/* case1: The outdate peer handler is successful: */
if (ns_max.pdsk <= D_OUTDATED) {
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
- drbd_uuid_new_current(mdev);
- clear_bit(NEW_CUR_UUID, &mdev->flags);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ if (test_bit(NEW_CUR_UUID, &device->flags)) {
+ drbd_uuid_new_current(device);
+ clear_bit(NEW_CUR_UUID, &device->flags);
}
}
rcu_read_unlock();
- spin_lock_irq(&tconn->req_lock);
- _tl_restart(tconn, CONNECTION_LOST_WHILE_PENDING);
- _conn_request_state(tconn,
+ spin_lock_irq(&connection->resource->req_lock);
+ _tl_restart(connection, CONNECTION_LOST_WHILE_PENDING);
+ _conn_request_state(connection,
(union drbd_state) { { .susp_fen = 1 } },
(union drbd_state) { { .susp_fen = 0 } },
CS_VERBOSE);
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
}
}
- kref_put(&tconn->kref, &conn_destroy);
+ kref_put(&connection->kref, drbd_destroy_connection);
- conn_md_sync(tconn);
+ conn_md_sync(connection);
return 0;
}
-void conn_old_common_state(struct drbd_tconn *tconn, union drbd_state *pcs, enum chg_state_flags *pf)
+void conn_old_common_state(struct drbd_connection *connection, union drbd_state *pcs, enum chg_state_flags *pf)
{
enum chg_state_flags flags = ~0;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr, first_vol = 1;
union drbd_dev_state os, cs = {
{ .role = R_SECONDARY,
.peer = R_UNKNOWN,
- .conn = tconn->cstate,
+ .conn = connection->cstate,
.disk = D_DISKLESS,
.pdsk = D_UNKNOWN,
} };
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- os = mdev->state;
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ os = device->state;
if (first_vol) {
cs = os;
@@ -1628,18 +1644,19 @@ void conn_old_common_state(struct drbd_tconn *tconn, union drbd_state *pcs, enum
}
static enum drbd_state_rv
-conn_is_valid_transition(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+conn_is_valid_transition(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
enum chg_state_flags flags)
{
enum drbd_state_rv rv = SS_SUCCESS;
union drbd_state ns, os;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
int vnr;
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- os = drbd_read_state(mdev);
- ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ os = drbd_read_state(device);
+ ns = sanitize_state(device, apply_mask_val(os, mask, val), NULL);
if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED)
ns.disk = os.disk;
@@ -1648,30 +1665,29 @@ conn_is_valid_transition(struct drbd_tconn *tconn, union drbd_state mask, union
continue;
rv = is_valid_transition(os, ns);
- if (rv < SS_SUCCESS)
- break;
- if (!(flags & CS_HARD)) {
- rv = is_valid_state(mdev, ns);
+ if (rv >= SS_SUCCESS && !(flags & CS_HARD)) {
+ rv = is_valid_state(device, ns);
if (rv < SS_SUCCESS) {
- if (is_valid_state(mdev, os) == rv)
- rv = is_valid_soft_transition(os, ns, tconn);
+ if (is_valid_state(device, os) == rv)
+ rv = is_valid_soft_transition(os, ns, connection);
} else
- rv = is_valid_soft_transition(os, ns, tconn);
+ rv = is_valid_soft_transition(os, ns, connection);
}
- if (rv < SS_SUCCESS)
+
+ if (rv < SS_SUCCESS) {
+ if (flags & CS_VERBOSE)
+ print_st_err(device, os, ns, rv);
break;
+ }
}
rcu_read_unlock();
- if (rv < SS_SUCCESS && flags & CS_VERBOSE)
- print_st_err(mdev, os, ns, rv);
-
return rv;
}
void
-conn_set_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+conn_set_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
union drbd_state *pns_min, union drbd_state *pns_max, enum chg_state_flags flags)
{
union drbd_state ns, os, ns_max = { };
@@ -1682,7 +1698,7 @@ conn_set_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state
.disk = D_MASK,
.pdsk = D_MASK
} };
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
enum drbd_state_rv rv;
int vnr, number_of_volumes = 0;
@@ -1690,27 +1706,28 @@ conn_set_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state
/* remember last connect time so request_timer_fn() won't
* kill newly established sessions while we are still trying to thaw
* previously frozen IO */
- if (tconn->cstate != C_WF_REPORT_PARAMS && val.conn == C_WF_REPORT_PARAMS)
- tconn->last_reconnect_jif = jiffies;
+ if (connection->cstate != C_WF_REPORT_PARAMS && val.conn == C_WF_REPORT_PARAMS)
+ connection->last_reconnect_jif = jiffies;
- tconn->cstate = val.conn;
+ connection->cstate = val.conn;
}
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
number_of_volumes++;
- os = drbd_read_state(mdev);
+ os = drbd_read_state(device);
ns = apply_mask_val(os, mask, val);
- ns = sanitize_state(mdev, ns, NULL);
+ ns = sanitize_state(device, ns, NULL);
if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED)
ns.disk = os.disk;
- rv = __drbd_set_state(mdev, ns, flags, NULL);
+ rv = __drbd_set_state(device, ns, flags, NULL);
if (rv < SS_SUCCESS)
BUG();
- ns.i = mdev->state.i;
+ ns.i = device->state.i;
ns_max.role = max_role(ns.role, ns_max.role);
ns_max.peer = max_role(ns.peer, ns_max.peer);
ns_max.conn = max_t(enum drbd_conns, ns.conn, ns_max.conn);
@@ -1735,39 +1752,39 @@ conn_set_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state
} };
}
- ns_min.susp = ns_max.susp = tconn->susp;
- ns_min.susp_nod = ns_max.susp_nod = tconn->susp_nod;
- ns_min.susp_fen = ns_max.susp_fen = tconn->susp_fen;
+ ns_min.susp = ns_max.susp = connection->resource->susp;
+ ns_min.susp_nod = ns_max.susp_nod = connection->resource->susp_nod;
+ ns_min.susp_fen = ns_max.susp_fen = connection->resource->susp_fen;
*pns_min = ns_min;
*pns_max = ns_max;
}
static enum drbd_state_rv
-_conn_rq_cond(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val)
+_conn_rq_cond(struct drbd_connection *connection, union drbd_state mask, union drbd_state val)
{
enum drbd_state_rv rv;
- if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &tconn->flags))
+ if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &connection->flags))
return SS_CW_SUCCESS;
- if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &tconn->flags))
+ if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &connection->flags))
return SS_CW_FAILED_BY_PEER;
- rv = conn_is_valid_transition(tconn, mask, val, 0);
- if (rv == SS_SUCCESS && tconn->cstate == C_WF_REPORT_PARAMS)
+ rv = conn_is_valid_transition(connection, mask, val, 0);
+ if (rv == SS_SUCCESS && connection->cstate == C_WF_REPORT_PARAMS)
rv = SS_UNKNOWN_ERROR; /* continue waiting */
return rv;
}
enum drbd_state_rv
-_conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+_conn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
enum chg_state_flags flags)
{
enum drbd_state_rv rv = SS_SUCCESS;
struct after_conn_state_chg_work *acscw;
- enum drbd_conns oc = tconn->cstate;
+ enum drbd_conns oc = connection->cstate;
union drbd_state ns_max, ns_min, os;
bool have_mutex = false;
@@ -1777,7 +1794,7 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_
goto abort;
}
- rv = conn_is_valid_transition(tconn, mask, val, flags);
+ rv = conn_is_valid_transition(connection, mask, val, flags);
if (rv < SS_SUCCESS)
goto abort;
@@ -1787,38 +1804,38 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_
/* This will be a cluster-wide state change.
* Need to give up the spinlock, grab the mutex,
* then send the state change request, ... */
- spin_unlock_irq(&tconn->req_lock);
- mutex_lock(&tconn->cstate_mutex);
+ spin_unlock_irq(&connection->resource->req_lock);
+ mutex_lock(&connection->cstate_mutex);
have_mutex = true;
- set_bit(CONN_WD_ST_CHG_REQ, &tconn->flags);
- if (conn_send_state_req(tconn, mask, val)) {
+ set_bit(CONN_WD_ST_CHG_REQ, &connection->flags);
+ if (conn_send_state_req(connection, mask, val)) {
/* sending failed. */
- clear_bit(CONN_WD_ST_CHG_REQ, &tconn->flags);
+ clear_bit(CONN_WD_ST_CHG_REQ, &connection->flags);
rv = SS_CW_FAILED_BY_PEER;
/* need to re-aquire the spin lock, though */
goto abort_unlocked;
}
if (val.conn == C_DISCONNECTING)
- set_bit(DISCONNECT_SENT, &tconn->flags);
+ set_bit(DISCONNECT_SENT, &connection->flags);
/* ... and re-aquire the spinlock.
* If _conn_rq_cond() returned >= SS_SUCCESS, we must call
* conn_set_state() within the same spinlock. */
- spin_lock_irq(&tconn->req_lock);
- wait_event_lock_irq(tconn->ping_wait,
- (rv = _conn_rq_cond(tconn, mask, val)),
- tconn->req_lock);
- clear_bit(CONN_WD_ST_CHG_REQ, &tconn->flags);
+ spin_lock_irq(&connection->resource->req_lock);
+ wait_event_lock_irq(connection->ping_wait,
+ (rv = _conn_rq_cond(connection, mask, val)),
+ connection->resource->req_lock);
+ clear_bit(CONN_WD_ST_CHG_REQ, &connection->flags);
if (rv < SS_SUCCESS)
goto abort;
}
- conn_old_common_state(tconn, &os, &flags);
+ conn_old_common_state(connection, &os, &flags);
flags |= CS_DC_SUSP;
- conn_set_state(tconn, mask, val, &ns_min, &ns_max, flags);
- conn_pr_state_change(tconn, os, ns_max, flags);
+ conn_set_state(connection, mask, val, &ns_min, &ns_max, flags);
+ conn_pr_state_change(connection, os, ns_max, flags);
acscw = kmalloc(sizeof(*acscw), GFP_ATOMIC);
if (acscw) {
@@ -1827,39 +1844,39 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_
acscw->ns_max = ns_max;
acscw->flags = flags;
acscw->w.cb = w_after_conn_state_ch;
- kref_get(&tconn->kref);
- acscw->w.tconn = tconn;
- drbd_queue_work(&tconn->sender_work, &acscw->w);
+ kref_get(&connection->kref);
+ acscw->connection = connection;
+ drbd_queue_work(&connection->sender_work, &acscw->w);
} else {
- conn_err(tconn, "Could not kmalloc an acscw\n");
+ drbd_err(connection, "Could not kmalloc an acscw\n");
}
abort:
if (have_mutex) {
/* mutex_unlock() "... must not be used in interrupt context.",
* so give up the spinlock, then re-aquire it */
- spin_unlock_irq(&tconn->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
abort_unlocked:
- mutex_unlock(&tconn->cstate_mutex);
- spin_lock_irq(&tconn->req_lock);
+ mutex_unlock(&connection->cstate_mutex);
+ spin_lock_irq(&connection->resource->req_lock);
}
if (rv < SS_SUCCESS && flags & CS_VERBOSE) {
- conn_err(tconn, "State change failed: %s\n", drbd_set_st_err_str(rv));
- conn_err(tconn, " mask = 0x%x val = 0x%x\n", mask.i, val.i);
- conn_err(tconn, " old_conn:%s wanted_conn:%s\n", drbd_conn_str(oc), drbd_conn_str(val.conn));
+ drbd_err(connection, "State change failed: %s\n", drbd_set_st_err_str(rv));
+ drbd_err(connection, " mask = 0x%x val = 0x%x\n", mask.i, val.i);
+ drbd_err(connection, " old_conn:%s wanted_conn:%s\n", drbd_conn_str(oc), drbd_conn_str(val.conn));
}
return rv;
}
enum drbd_state_rv
-conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+conn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
enum chg_state_flags flags)
{
enum drbd_state_rv rv;
- spin_lock_irq(&tconn->req_lock);
- rv = _conn_request_state(tconn, mask, val, flags);
- spin_unlock_irq(&tconn->req_lock);
+ spin_lock_irq(&connection->resource->req_lock);
+ rv = _conn_request_state(connection, mask, val, flags);
+ spin_unlock_irq(&connection->resource->req_lock);
return rv;
}
diff --git a/drivers/block/drbd/drbd_state.h b/drivers/block/drbd/drbd_state.h
index a3c361bbc4b6..cc41605ba21c 100644
--- a/drivers/block/drbd/drbd_state.h
+++ b/drivers/block/drbd/drbd_state.h
@@ -1,8 +1,8 @@
#ifndef DRBD_STATE_H
#define DRBD_STATE_H
-struct drbd_conf;
-struct drbd_tconn;
+struct drbd_device;
+struct drbd_connection;
/**
* DOC: DRBD State macros
@@ -107,36 +107,36 @@ union drbd_dev_state {
unsigned int i;
};
-extern enum drbd_state_rv drbd_change_state(struct drbd_conf *mdev,
+extern enum drbd_state_rv drbd_change_state(struct drbd_device *device,
enum chg_state_flags f,
union drbd_state mask,
union drbd_state val);
-extern void drbd_force_state(struct drbd_conf *, union drbd_state,
+extern void drbd_force_state(struct drbd_device *, union drbd_state,
union drbd_state);
-extern enum drbd_state_rv _drbd_request_state(struct drbd_conf *,
+extern enum drbd_state_rv _drbd_request_state(struct drbd_device *,
union drbd_state,
union drbd_state,
enum chg_state_flags);
-extern enum drbd_state_rv __drbd_set_state(struct drbd_conf *, union drbd_state,
+extern enum drbd_state_rv __drbd_set_state(struct drbd_device *, union drbd_state,
enum chg_state_flags,
struct completion *done);
-extern void print_st_err(struct drbd_conf *, union drbd_state,
+extern void print_st_err(struct drbd_device *, union drbd_state,
union drbd_state, int);
enum drbd_state_rv
-_conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+_conn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
enum chg_state_flags flags);
enum drbd_state_rv
-conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+conn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
enum chg_state_flags flags);
-extern void drbd_resume_al(struct drbd_conf *mdev);
-extern bool conn_all_vols_unconf(struct drbd_tconn *tconn);
+extern void drbd_resume_al(struct drbd_device *device);
+extern bool conn_all_vols_unconf(struct drbd_connection *connection);
/**
* drbd_request_state() - Reqest a state change
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @mask: mask of state bits to change.
* @val: value of new state bits.
*
@@ -144,18 +144,18 @@ extern bool conn_all_vols_unconf(struct drbd_tconn *tconn);
* quite verbose in case the state change is not possible, and all those
* state changes are globally serialized.
*/
-static inline int drbd_request_state(struct drbd_conf *mdev,
+static inline int drbd_request_state(struct drbd_device *device,
union drbd_state mask,
union drbd_state val)
{
- return _drbd_request_state(mdev, mask, val, CS_VERBOSE + CS_ORDERED);
+ return _drbd_request_state(device, mask, val, CS_VERBOSE + CS_ORDERED);
}
-enum drbd_role conn_highest_role(struct drbd_tconn *tconn);
-enum drbd_role conn_highest_peer(struct drbd_tconn *tconn);
-enum drbd_disk_state conn_highest_disk(struct drbd_tconn *tconn);
-enum drbd_disk_state conn_lowest_disk(struct drbd_tconn *tconn);
-enum drbd_disk_state conn_highest_pdsk(struct drbd_tconn *tconn);
-enum drbd_conns conn_lowest_conn(struct drbd_tconn *tconn);
+enum drbd_role conn_highest_role(struct drbd_connection *connection);
+enum drbd_role conn_highest_peer(struct drbd_connection *connection);
+enum drbd_disk_state conn_highest_disk(struct drbd_connection *connection);
+enum drbd_disk_state conn_lowest_disk(struct drbd_connection *connection);
+enum drbd_disk_state conn_highest_pdsk(struct drbd_connection *connection);
+enum drbd_conns conn_lowest_conn(struct drbd_connection *connection);
#endif
diff --git a/drivers/block/drbd/drbd_strings.c b/drivers/block/drbd/drbd_strings.c
index 58e08ff2b2ce..80b0f63c7075 100644
--- a/drivers/block/drbd/drbd_strings.c
+++ b/drivers/block/drbd/drbd_strings.c
@@ -24,6 +24,7 @@
*/
#include <linux/drbd.h>
+#include "drbd_strings.h"
static const char *drbd_conn_s_names[] = {
[C_STANDALONE] = "StandAlone",
diff --git a/drivers/block/drbd/drbd_strings.h b/drivers/block/drbd/drbd_strings.h
new file mode 100644
index 000000000000..f9923cc88afb
--- /dev/null
+++ b/drivers/block/drbd/drbd_strings.h
@@ -0,0 +1,9 @@
+#ifndef __DRBD_STRINGS_H
+#define __DRBD_STRINGS_H
+
+extern const char *drbd_conn_str(enum drbd_conns);
+extern const char *drbd_role_str(enum drbd_role);
+extern const char *drbd_disk_str(enum drbd_disk_state);
+extern const char *drbd_set_st_err_str(enum drbd_state_rv);
+
+#endif /* __DRBD_STRINGS_H */
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index 84d3175d493a..2c4ce42c3657 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -21,7 +21,7 @@
along with drbd; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+*/
#include <linux/module.h>
#include <linux/drbd.h>
@@ -36,10 +36,11 @@
#include <linux/scatterlist.h>
#include "drbd_int.h"
+#include "drbd_protocol.h"
#include "drbd_req.h"
-static int w_make_ov_request(struct drbd_work *w, int cancel);
-
+static int make_ov_request(struct drbd_device *, int);
+static int make_resync_request(struct drbd_device *, int);
/* endio handlers:
* drbd_md_io_complete (defined here)
@@ -67,10 +68,10 @@ rwlock_t global_state_lock;
void drbd_md_io_complete(struct bio *bio, int error)
{
struct drbd_md_io *md_io;
- struct drbd_conf *mdev;
+ struct drbd_device *device;
md_io = (struct drbd_md_io *)bio->bi_private;
- mdev = container_of(md_io, struct drbd_conf, md_io);
+ device = container_of(md_io, struct drbd_device, md_io);
md_io->error = error;
@@ -83,35 +84,36 @@ void drbd_md_io_complete(struct bio *bio, int error)
* Make sure we first drop the reference, and only then signal
* completion, or we may (in drbd_al_read_log()) cycle so fast into the
* next drbd_md_sync_page_io(), that we trigger the
- * ASSERT(atomic_read(&mdev->md_io_in_use) == 1) there.
+ * ASSERT(atomic_read(&device->md_io_in_use) == 1) there.
*/
- drbd_md_put_buffer(mdev);
+ drbd_md_put_buffer(device);
md_io->done = 1;
- wake_up(&mdev->misc_wait);
+ wake_up(&device->misc_wait);
bio_put(bio);
- if (mdev->ldev) /* special case: drbd_md_read() during drbd_adm_attach() */
- put_ldev(mdev);
+ if (device->ldev) /* special case: drbd_md_read() during drbd_adm_attach() */
+ put_ldev(device);
}
/* reads on behalf of the partner,
* "submitted" by the receiver
*/
-void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __releases(local)
+static void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __releases(local)
{
unsigned long flags = 0;
- struct drbd_conf *mdev = peer_req->w.mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- mdev->read_cnt += peer_req->i.size >> 9;
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ device->read_cnt += peer_req->i.size >> 9;
list_del(&peer_req->w.list);
- if (list_empty(&mdev->read_ee))
- wake_up(&mdev->ee_wait);
+ if (list_empty(&device->read_ee))
+ wake_up(&device->ee_wait);
if (test_bit(__EE_WAS_ERROR, &peer_req->flags))
- __drbd_chk_io_error(mdev, DRBD_READ_ERROR);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ __drbd_chk_io_error(device, DRBD_READ_ERROR);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
- drbd_queue_work(&mdev->tconn->sender_work, &peer_req->w);
- put_ldev(mdev);
+ drbd_queue_work(&peer_device->connection->sender_work, &peer_req->w);
+ put_ldev(device);
}
/* writes on behalf of the partner, or resync writes,
@@ -119,7 +121,8 @@ void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __releases(lo
static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(local)
{
unsigned long flags = 0;
- struct drbd_conf *mdev = peer_req->w.mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
struct drbd_interval i;
int do_wake;
u64 block_id;
@@ -133,35 +136,35 @@ static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __rel
do_al_complete_io = peer_req->flags & EE_CALL_AL_COMPLETE_IO;
block_id = peer_req->block_id;
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
- mdev->writ_cnt += peer_req->i.size >> 9;
- list_move_tail(&peer_req->w.list, &mdev->done_ee);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
+ device->writ_cnt += peer_req->i.size >> 9;
+ list_move_tail(&peer_req->w.list, &device->done_ee);
/*
* Do not remove from the write_requests tree here: we did not send the
* Ack yet and did not wake possibly waiting conflicting requests.
* Removed from the tree from "drbd_process_done_ee" within the
- * appropriate w.cb (e_end_block/e_end_resync_block) or from
+ * appropriate dw.cb (e_end_block/e_end_resync_block) or from
* _drbd_clear_done_ee.
*/
- do_wake = list_empty(block_id == ID_SYNCER ? &mdev->sync_ee : &mdev->active_ee);
+ do_wake = list_empty(block_id == ID_SYNCER ? &device->sync_ee : &device->active_ee);
if (test_bit(__EE_WAS_ERROR, &peer_req->flags))
- __drbd_chk_io_error(mdev, DRBD_WRITE_ERROR);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
+ __drbd_chk_io_error(device, DRBD_WRITE_ERROR);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
if (block_id == ID_SYNCER)
- drbd_rs_complete_io(mdev, i.sector);
+ drbd_rs_complete_io(device, i.sector);
if (do_wake)
- wake_up(&mdev->ee_wait);
+ wake_up(&device->ee_wait);
if (do_al_complete_io)
- drbd_al_complete_io(mdev, &i);
+ drbd_al_complete_io(device, &i);
- wake_asender(mdev->tconn);
- put_ldev(mdev);
+ wake_asender(peer_device->connection);
+ put_ldev(device);
}
/* writes on behalf of the partner, or resync writes,
@@ -170,17 +173,17 @@ static void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __rel
void drbd_peer_request_endio(struct bio *bio, int error)
{
struct drbd_peer_request *peer_req = bio->bi_private;
- struct drbd_conf *mdev = peer_req->w.mdev;
+ struct drbd_device *device = peer_req->peer_device->device;
int uptodate = bio_flagged(bio, BIO_UPTODATE);
int is_write = bio_data_dir(bio) == WRITE;
if (error && __ratelimit(&drbd_ratelimit_state))
- dev_warn(DEV, "%s: error=%d s=%llus\n",
+ drbd_warn(device, "%s: error=%d s=%llus\n",
is_write ? "write" : "read", error,
(unsigned long long)peer_req->i.sector);
if (!error && !uptodate) {
if (__ratelimit(&drbd_ratelimit_state))
- dev_warn(DEV, "%s: setting error to -EIO s=%llus\n",
+ drbd_warn(device, "%s: setting error to -EIO s=%llus\n",
is_write ? "write" : "read",
(unsigned long long)peer_req->i.sector);
/* strange behavior of some lower level drivers...
@@ -207,13 +210,13 @@ void drbd_request_endio(struct bio *bio, int error)
{
unsigned long flags;
struct drbd_request *req = bio->bi_private;
- struct drbd_conf *mdev = req->w.mdev;
+ struct drbd_device *device = req->device;
struct bio_and_error m;
enum drbd_req_event what;
int uptodate = bio_flagged(bio, BIO_UPTODATE);
if (!error && !uptodate) {
- dev_warn(DEV, "p %s: setting error to -EIO\n",
+ drbd_warn(device, "p %s: setting error to -EIO\n",
bio_data_dir(bio) == WRITE ? "write" : "read");
/* strange behavior of some lower level drivers...
* fail the request by clearing the uptodate flag,
@@ -252,7 +255,7 @@ void drbd_request_endio(struct bio *bio, int error)
*/
if (unlikely(req->rq_state & RQ_LOCAL_ABORTED)) {
if (__ratelimit(&drbd_ratelimit_state))
- dev_emerg(DEV, "delayed completion of aborted local request; disk-timeout may be too aggressive\n");
+ drbd_emerg(device, "delayed completion of aborted local request; disk-timeout may be too aggressive\n");
if (!error)
panic("possible random memory corruption caused by delayed completion of aborted local request\n");
@@ -272,17 +275,16 @@ void drbd_request_endio(struct bio *bio, int error)
req->private_bio = ERR_PTR(error);
/* not req_mod(), we need irqsave here! */
- spin_lock_irqsave(&mdev->tconn->req_lock, flags);
+ spin_lock_irqsave(&device->resource->req_lock, flags);
__req_mod(req, what, &m);
- spin_unlock_irqrestore(&mdev->tconn->req_lock, flags);
- put_ldev(mdev);
+ spin_unlock_irqrestore(&device->resource->req_lock, flags);
+ put_ldev(device);
if (m.bio)
- complete_master_bio(mdev, &m);
+ complete_master_bio(device, &m);
}
-void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm,
- struct drbd_peer_request *peer_req, void *digest)
+void drbd_csum_ee(struct crypto_hash *tfm, struct drbd_peer_request *peer_req, void *digest)
{
struct hash_desc desc;
struct scatterlist sg;
@@ -309,7 +311,7 @@ void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm,
crypto_hash_final(&desc, digest);
}
-void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *bio, void *digest)
+void drbd_csum_bio(struct crypto_hash *tfm, struct bio *bio, void *digest)
{
struct hash_desc desc;
struct scatterlist sg;
@@ -333,7 +335,8 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *
static int w_e_send_csum(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
int digest_size;
void *digest;
int err = 0;
@@ -344,89 +347,92 @@ static int w_e_send_csum(struct drbd_work *w, int cancel)
if (unlikely((peer_req->flags & EE_WAS_ERROR) != 0))
goto out;
- digest_size = crypto_hash_digestsize(mdev->tconn->csums_tfm);
+ digest_size = crypto_hash_digestsize(peer_device->connection->csums_tfm);
digest = kmalloc(digest_size, GFP_NOIO);
if (digest) {
sector_t sector = peer_req->i.sector;
unsigned int size = peer_req->i.size;
- drbd_csum_ee(mdev, mdev->tconn->csums_tfm, peer_req, digest);
+ drbd_csum_ee(peer_device->connection->csums_tfm, peer_req, digest);
/* Free peer_req and pages before send.
* In case we block on congestion, we could otherwise run into
* some distributed deadlock, if the other side blocks on
* congestion as well, because our receiver blocks in
* drbd_alloc_pages due to pp_in_use > max_buffers. */
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
peer_req = NULL;
- inc_rs_pending(mdev);
- err = drbd_send_drequest_csum(mdev, sector, size,
+ inc_rs_pending(device);
+ err = drbd_send_drequest_csum(peer_device, sector, size,
digest, digest_size,
P_CSUM_RS_REQUEST);
kfree(digest);
} else {
- dev_err(DEV, "kmalloc() of digest failed.\n");
+ drbd_err(device, "kmalloc() of digest failed.\n");
err = -ENOMEM;
}
out:
if (peer_req)
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
if (unlikely(err))
- dev_err(DEV, "drbd_send_drequest(..., csum) failed\n");
+ drbd_err(device, "drbd_send_drequest(..., csum) failed\n");
return err;
}
#define GFP_TRY (__GFP_HIGHMEM | __GFP_NOWARN)
-static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size)
+static int read_for_csum(struct drbd_peer_device *peer_device, sector_t sector, int size)
{
+ struct drbd_device *device = peer_device->device;
struct drbd_peer_request *peer_req;
- if (!get_ldev(mdev))
+ if (!get_ldev(device))
return -EIO;
- if (drbd_rs_should_slow_down(mdev, sector))
+ if (drbd_rs_should_slow_down(device, sector))
goto defer;
/* GFP_TRY, because if there is no memory available right now, this may
* be rescheduled for later. It is "only" background resync, after all. */
- peer_req = drbd_alloc_peer_req(mdev, ID_SYNCER /* unused */, sector,
+ peer_req = drbd_alloc_peer_req(peer_device, ID_SYNCER /* unused */, sector,
size, GFP_TRY);
if (!peer_req)
goto defer;
peer_req->w.cb = w_e_send_csum;
- spin_lock_irq(&mdev->tconn->req_lock);
- list_add(&peer_req->w.list, &mdev->read_ee);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
+ list_add(&peer_req->w.list, &device->read_ee);
+ spin_unlock_irq(&device->resource->req_lock);
- atomic_add(size >> 9, &mdev->rs_sect_ev);
- if (drbd_submit_peer_request(mdev, peer_req, READ, DRBD_FAULT_RS_RD) == 0)
+ atomic_add(size >> 9, &device->rs_sect_ev);
+ if (drbd_submit_peer_request(device, peer_req, READ, DRBD_FAULT_RS_RD) == 0)
return 0;
/* If it failed because of ENOMEM, retry should help. If it failed
* because bio_add_page failed (probably broken lower level driver),
* retry may or may not help.
* If it does not, you may need to force disconnect. */
- spin_lock_irq(&mdev->tconn->req_lock);
+ spin_lock_irq(&device->resource->req_lock);
list_del(&peer_req->w.list);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ spin_unlock_irq(&device->resource->req_lock);
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
defer:
- put_ldev(mdev);
+ put_ldev(device);
return -EAGAIN;
}
int w_resync_timer(struct drbd_work *w, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
- switch (mdev->state.conn) {
+ struct drbd_device *device =
+ container_of(w, struct drbd_device, resync_work);
+
+ switch (device->state.conn) {
case C_VERIFY_S:
- w_make_ov_request(w, cancel);
+ make_ov_request(device, cancel);
break;
case C_SYNC_TARGET:
- w_make_resync_request(w, cancel);
+ make_resync_request(device, cancel);
break;
}
@@ -435,10 +441,11 @@ int w_resync_timer(struct drbd_work *w, int cancel)
void resync_timer_fn(unsigned long data)
{
- struct drbd_conf *mdev = (struct drbd_conf *) data;
+ struct drbd_device *device = (struct drbd_device *) data;
- if (list_empty(&mdev->resync_work.list))
- drbd_queue_work(&mdev->tconn->sender_work, &mdev->resync_work);
+ if (list_empty(&device->resync_work.list))
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &device->resync_work);
}
static void fifo_set(struct fifo_buffer *fb, int value)
@@ -485,7 +492,7 @@ struct fifo_buffer *fifo_alloc(int fifo_size)
return fb;
}
-static int drbd_rs_controller(struct drbd_conf *mdev)
+static int drbd_rs_controller(struct drbd_device *device)
{
struct disk_conf *dc;
unsigned int sect_in; /* Number of sectors that came in since the last turn */
@@ -498,22 +505,22 @@ static int drbd_rs_controller(struct drbd_conf *mdev)
int max_sect;
struct fifo_buffer *plan;
- sect_in = atomic_xchg(&mdev->rs_sect_in, 0); /* Number of sectors that came in */
- mdev->rs_in_flight -= sect_in;
+ sect_in = atomic_xchg(&device->rs_sect_in, 0); /* Number of sectors that came in */
+ device->rs_in_flight -= sect_in;
- dc = rcu_dereference(mdev->ldev->disk_conf);
- plan = rcu_dereference(mdev->rs_plan_s);
+ dc = rcu_dereference(device->ldev->disk_conf);
+ plan = rcu_dereference(device->rs_plan_s);
steps = plan->size; /* (dc->c_plan_ahead * 10 * SLEEP_TIME) / HZ; */
- if (mdev->rs_in_flight + sect_in == 0) { /* At start of resync */
+ if (device->rs_in_flight + sect_in == 0) { /* At start of resync */
want = ((dc->resync_rate * 2 * SLEEP_TIME) / HZ) * steps;
} else { /* normal path */
want = dc->c_fill_target ? dc->c_fill_target :
sect_in * dc->c_delay_target * HZ / (SLEEP_TIME * 10);
}
- correction = want - mdev->rs_in_flight - plan->total;
+ correction = want - device->rs_in_flight - plan->total;
/* Plan ahead */
cps = correction / steps;
@@ -533,25 +540,25 @@ static int drbd_rs_controller(struct drbd_conf *mdev)
req_sect = max_sect;
/*
- dev_warn(DEV, "si=%u if=%d wa=%u co=%d st=%d cps=%d pl=%d cc=%d rs=%d\n",
- sect_in, mdev->rs_in_flight, want, correction,
- steps, cps, mdev->rs_planed, curr_corr, req_sect);
+ drbd_warn(device, "si=%u if=%d wa=%u co=%d st=%d cps=%d pl=%d cc=%d rs=%d\n",
+ sect_in, device->rs_in_flight, want, correction,
+ steps, cps, device->rs_planed, curr_corr, req_sect);
*/
return req_sect;
}
-static int drbd_rs_number_requests(struct drbd_conf *mdev)
+static int drbd_rs_number_requests(struct drbd_device *device)
{
int number;
rcu_read_lock();
- if (rcu_dereference(mdev->rs_plan_s)->size) {
- number = drbd_rs_controller(mdev) >> (BM_BLOCK_SHIFT - 9);
- mdev->c_sync_rate = number * HZ * (BM_BLOCK_SIZE / 1024) / SLEEP_TIME;
+ if (rcu_dereference(device->rs_plan_s)->size) {
+ number = drbd_rs_controller(device) >> (BM_BLOCK_SHIFT - 9);
+ device->c_sync_rate = number * HZ * (BM_BLOCK_SIZE / 1024) / SLEEP_TIME;
} else {
- mdev->c_sync_rate = rcu_dereference(mdev->ldev->disk_conf)->resync_rate;
- number = SLEEP_TIME * mdev->c_sync_rate / ((BM_BLOCK_SIZE / 1024) * HZ);
+ device->c_sync_rate = rcu_dereference(device->ldev->disk_conf)->resync_rate;
+ number = SLEEP_TIME * device->c_sync_rate / ((BM_BLOCK_SIZE / 1024) * HZ);
}
rcu_read_unlock();
@@ -560,12 +567,11 @@ static int drbd_rs_number_requests(struct drbd_conf *mdev)
return number;
}
-int w_make_resync_request(struct drbd_work *w, int cancel)
+static int make_resync_request(struct drbd_device *device, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
unsigned long bit;
sector_t sector;
- const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
+ const sector_t capacity = drbd_get_capacity(device->this_bdev);
int max_bio_size;
int number, rollback_i, size;
int align, queued, sndbuf;
@@ -574,61 +580,61 @@ int w_make_resync_request(struct drbd_work *w, int cancel)
if (unlikely(cancel))
return 0;
- if (mdev->rs_total == 0) {
+ if (device->rs_total == 0) {
/* empty resync? */
- drbd_resync_finished(mdev);
+ drbd_resync_finished(device);
return 0;
}
- if (!get_ldev(mdev)) {
- /* Since we only need to access mdev->rsync a
- get_ldev_if_state(mdev,D_FAILED) would be sufficient, but
+ if (!get_ldev(device)) {
+ /* Since we only need to access device->rsync a
+ get_ldev_if_state(device,D_FAILED) would be sufficient, but
to continue resync with a broken disk makes no sense at
all */
- dev_err(DEV, "Disk broke down during resync!\n");
+ drbd_err(device, "Disk broke down during resync!\n");
return 0;
}
- max_bio_size = queue_max_hw_sectors(mdev->rq_queue) << 9;
- number = drbd_rs_number_requests(mdev);
+ max_bio_size = queue_max_hw_sectors(device->rq_queue) << 9;
+ number = drbd_rs_number_requests(device);
if (number == 0)
goto requeue;
for (i = 0; i < number; i++) {
/* Stop generating RS requests, when half of the send buffer is filled */
- mutex_lock(&mdev->tconn->data.mutex);
- if (mdev->tconn->data.socket) {
- queued = mdev->tconn->data.socket->sk->sk_wmem_queued;
- sndbuf = mdev->tconn->data.socket->sk->sk_sndbuf;
+ mutex_lock(&first_peer_device(device)->connection->data.mutex);
+ if (first_peer_device(device)->connection->data.socket) {
+ queued = first_peer_device(device)->connection->data.socket->sk->sk_wmem_queued;
+ sndbuf = first_peer_device(device)->connection->data.socket->sk->sk_sndbuf;
} else {
queued = 1;
sndbuf = 0;
}
- mutex_unlock(&mdev->tconn->data.mutex);
+ mutex_unlock(&first_peer_device(device)->connection->data.mutex);
if (queued > sndbuf / 2)
goto requeue;
next_sector:
size = BM_BLOCK_SIZE;
- bit = drbd_bm_find_next(mdev, mdev->bm_resync_fo);
+ bit = drbd_bm_find_next(device, device->bm_resync_fo);
if (bit == DRBD_END_OF_BITMAP) {
- mdev->bm_resync_fo = drbd_bm_bits(mdev);
- put_ldev(mdev);
+ device->bm_resync_fo = drbd_bm_bits(device);
+ put_ldev(device);
return 0;
}
sector = BM_BIT_TO_SECT(bit);
- if (drbd_rs_should_slow_down(mdev, sector) ||
- drbd_try_rs_begin_io(mdev, sector)) {
- mdev->bm_resync_fo = bit;
+ if (drbd_rs_should_slow_down(device, sector) ||
+ drbd_try_rs_begin_io(device, sector)) {
+ device->bm_resync_fo = bit;
goto requeue;
}
- mdev->bm_resync_fo = bit + 1;
+ device->bm_resync_fo = bit + 1;
- if (unlikely(drbd_bm_test_bit(mdev, bit) == 0)) {
- drbd_rs_complete_io(mdev, sector);
+ if (unlikely(drbd_bm_test_bit(device, bit) == 0)) {
+ drbd_rs_complete_io(device, sector);
goto next_sector;
}
@@ -657,7 +663,7 @@ next_sector:
* obscure reason; ( b == 0 ) would get the out-of-band
* only accidentally right because of the "oddly sized"
* adjustment below */
- if (drbd_bm_test_bit(mdev, bit+1) != 1)
+ if (drbd_bm_test_bit(device, bit+1) != 1)
break;
bit++;
size += BM_BLOCK_SIZE;
@@ -668,20 +674,21 @@ next_sector:
/* if we merged some,
* reset the offset to start the next drbd_bm_find_next from */
if (size > BM_BLOCK_SIZE)
- mdev->bm_resync_fo = bit + 1;
+ device->bm_resync_fo = bit + 1;
#endif
/* adjust very last sectors, in case we are oddly sized */
if (sector + (size>>9) > capacity)
size = (capacity-sector)<<9;
- if (mdev->tconn->agreed_pro_version >= 89 && mdev->tconn->csums_tfm) {
- switch (read_for_csum(mdev, sector, size)) {
+ if (first_peer_device(device)->connection->agreed_pro_version >= 89 &&
+ first_peer_device(device)->connection->csums_tfm) {
+ switch (read_for_csum(first_peer_device(device), sector, size)) {
case -EIO: /* Disk failure */
- put_ldev(mdev);
+ put_ldev(device);
return -EIO;
case -EAGAIN: /* allocation failed, or ldev busy */
- drbd_rs_complete_io(mdev, sector);
- mdev->bm_resync_fo = BM_SECT_TO_BIT(sector);
+ drbd_rs_complete_io(device, sector);
+ device->bm_resync_fo = BM_SECT_TO_BIT(sector);
i = rollback_i;
goto requeue;
case 0:
@@ -693,50 +700,49 @@ next_sector:
} else {
int err;
- inc_rs_pending(mdev);
- err = drbd_send_drequest(mdev, P_RS_DATA_REQUEST,
+ inc_rs_pending(device);
+ err = drbd_send_drequest(first_peer_device(device), P_RS_DATA_REQUEST,
sector, size, ID_SYNCER);
if (err) {
- dev_err(DEV, "drbd_send_drequest() failed, aborting...\n");
- dec_rs_pending(mdev);
- put_ldev(mdev);
+ drbd_err(device, "drbd_send_drequest() failed, aborting...\n");
+ dec_rs_pending(device);
+ put_ldev(device);
return err;
}
}
}
- if (mdev->bm_resync_fo >= drbd_bm_bits(mdev)) {
+ if (device->bm_resync_fo >= drbd_bm_bits(device)) {
/* last syncer _request_ was sent,
* but the P_RS_DATA_REPLY not yet received. sync will end (and
* next sync group will resume), as soon as we receive the last
* resync data block, and the last bit is cleared.
* until then resync "work" is "inactive" ...
*/
- put_ldev(mdev);
+ put_ldev(device);
return 0;
}
requeue:
- mdev->rs_in_flight += (i << (BM_BLOCK_SHIFT - 9));
- mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME);
- put_ldev(mdev);
+ device->rs_in_flight += (i << (BM_BLOCK_SHIFT - 9));
+ mod_timer(&device->resync_timer, jiffies + SLEEP_TIME);
+ put_ldev(device);
return 0;
}
-static int w_make_ov_request(struct drbd_work *w, int cancel)
+static int make_ov_request(struct drbd_device *device, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
int number, i, size;
sector_t sector;
- const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
+ const sector_t capacity = drbd_get_capacity(device->this_bdev);
bool stop_sector_reached = false;
if (unlikely(cancel))
return 1;
- number = drbd_rs_number_requests(mdev);
+ number = drbd_rs_number_requests(device);
- sector = mdev->ov_position;
+ sector = device->ov_position;
for (i = 0; i < number; i++) {
if (sector >= capacity)
return 1;
@@ -745,116 +751,121 @@ static int w_make_ov_request(struct drbd_work *w, int cancel)
* w_e_end_ov_reply().
* We need to send at least one request out. */
stop_sector_reached = i > 0
- && verify_can_do_stop_sector(mdev)
- && sector >= mdev->ov_stop_sector;
+ && verify_can_do_stop_sector(device)
+ && sector >= device->ov_stop_sector;
if (stop_sector_reached)
break;
size = BM_BLOCK_SIZE;
- if (drbd_rs_should_slow_down(mdev, sector) ||
- drbd_try_rs_begin_io(mdev, sector)) {
- mdev->ov_position = sector;
+ if (drbd_rs_should_slow_down(device, sector) ||
+ drbd_try_rs_begin_io(device, sector)) {
+ device->ov_position = sector;
goto requeue;
}
if (sector + (size>>9) > capacity)
size = (capacity-sector)<<9;
- inc_rs_pending(mdev);
- if (drbd_send_ov_request(mdev, sector, size)) {
- dec_rs_pending(mdev);
+ inc_rs_pending(device);
+ if (drbd_send_ov_request(first_peer_device(device), sector, size)) {
+ dec_rs_pending(device);
return 0;
}
sector += BM_SECT_PER_BIT;
}
- mdev->ov_position = sector;
+ device->ov_position = sector;
requeue:
- mdev->rs_in_flight += (i << (BM_BLOCK_SHIFT - 9));
+ device->rs_in_flight += (i << (BM_BLOCK_SHIFT - 9));
if (i == 0 || !stop_sector_reached)
- mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME);
+ mod_timer(&device->resync_timer, jiffies + SLEEP_TIME);
return 1;
}
int w_ov_finished(struct drbd_work *w, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
- kfree(w);
- ov_out_of_sync_print(mdev);
- drbd_resync_finished(mdev);
+ struct drbd_device_work *dw =
+ container_of(w, struct drbd_device_work, w);
+ struct drbd_device *device = dw->device;
+ kfree(dw);
+ ov_out_of_sync_print(device);
+ drbd_resync_finished(device);
return 0;
}
static int w_resync_finished(struct drbd_work *w, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
- kfree(w);
+ struct drbd_device_work *dw =
+ container_of(w, struct drbd_device_work, w);
+ struct drbd_device *device = dw->device;
+ kfree(dw);
- drbd_resync_finished(mdev);
+ drbd_resync_finished(device);
return 0;
}
-static void ping_peer(struct drbd_conf *mdev)
+static void ping_peer(struct drbd_device *device)
{
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
- clear_bit(GOT_PING_ACK, &tconn->flags);
- request_ping(tconn);
- wait_event(tconn->ping_wait,
- test_bit(GOT_PING_ACK, &tconn->flags) || mdev->state.conn < C_CONNECTED);
+ clear_bit(GOT_PING_ACK, &connection->flags);
+ request_ping(connection);
+ wait_event(connection->ping_wait,
+ test_bit(GOT_PING_ACK, &connection->flags) || device->state.conn < C_CONNECTED);
}
-int drbd_resync_finished(struct drbd_conf *mdev)
+int drbd_resync_finished(struct drbd_device *device)
{
unsigned long db, dt, dbdt;
unsigned long n_oos;
union drbd_state os, ns;
- struct drbd_work *w;
+ struct drbd_device_work *dw;
char *khelper_cmd = NULL;
int verify_done = 0;
/* Remove all elements from the resync LRU. Since future actions
* might set bits in the (main) bitmap, then the entries in the
* resync LRU would be wrong. */
- if (drbd_rs_del_all(mdev)) {
+ if (drbd_rs_del_all(device)) {
/* In case this is not possible now, most probably because
* there are P_RS_DATA_REPLY Packets lingering on the worker's
* queue (or even the read operations for those packets
* is not finished by now). Retry in 100ms. */
schedule_timeout_interruptible(HZ / 10);
- w = kmalloc(sizeof(struct drbd_work), GFP_ATOMIC);
- if (w) {
- w->cb = w_resync_finished;
- w->mdev = mdev;
- drbd_queue_work(&mdev->tconn->sender_work, w);
+ dw = kmalloc(sizeof(struct drbd_device_work), GFP_ATOMIC);
+ if (dw) {
+ dw->w.cb = w_resync_finished;
+ dw->device = device;
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &dw->w);
return 1;
}
- dev_err(DEV, "Warn failed to drbd_rs_del_all() and to kmalloc(w).\n");
+ drbd_err(device, "Warn failed to drbd_rs_del_all() and to kmalloc(dw).\n");
}
- dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
+ dt = (jiffies - device->rs_start - device->rs_paused) / HZ;
if (dt <= 0)
dt = 1;
-
- db = mdev->rs_total;
+
+ db = device->rs_total;
/* adjust for verify start and stop sectors, respective reached position */
- if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
- db -= mdev->ov_left;
+ if (device->state.conn == C_VERIFY_S || device->state.conn == C_VERIFY_T)
+ db -= device->ov_left;
dbdt = Bit2KB(db/dt);
- mdev->rs_paused /= HZ;
+ device->rs_paused /= HZ;
- if (!get_ldev(mdev))
+ if (!get_ldev(device))
goto out;
- ping_peer(mdev);
+ ping_peer(device);
- spin_lock_irq(&mdev->tconn->req_lock);
- os = drbd_read_state(mdev);
+ spin_lock_irq(&device->resource->req_lock);
+ os = drbd_read_state(device);
verify_done = (os.conn == C_VERIFY_S || os.conn == C_VERIFY_T);
@@ -866,41 +877,41 @@ int drbd_resync_finished(struct drbd_conf *mdev)
ns = os;
ns.conn = C_CONNECTED;
- dev_info(DEV, "%s done (total %lu sec; paused %lu sec; %lu K/sec)\n",
+ drbd_info(device, "%s done (total %lu sec; paused %lu sec; %lu K/sec)\n",
verify_done ? "Online verify" : "Resync",
- dt + mdev->rs_paused, mdev->rs_paused, dbdt);
+ dt + device->rs_paused, device->rs_paused, dbdt);
- n_oos = drbd_bm_total_weight(mdev);
+ n_oos = drbd_bm_total_weight(device);
if (os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) {
if (n_oos) {
- dev_alert(DEV, "Online verify found %lu %dk block out of sync!\n",
+ drbd_alert(device, "Online verify found %lu %dk block out of sync!\n",
n_oos, Bit2KB(1));
khelper_cmd = "out-of-sync";
}
} else {
- D_ASSERT((n_oos - mdev->rs_failed) == 0);
+ D_ASSERT(device, (n_oos - device->rs_failed) == 0);
if (os.conn == C_SYNC_TARGET || os.conn == C_PAUSED_SYNC_T)
khelper_cmd = "after-resync-target";
- if (mdev->tconn->csums_tfm && mdev->rs_total) {
- const unsigned long s = mdev->rs_same_csum;
- const unsigned long t = mdev->rs_total;
+ if (first_peer_device(device)->connection->csums_tfm && device->rs_total) {
+ const unsigned long s = device->rs_same_csum;
+ const unsigned long t = device->rs_total;
const int ratio =
(t == 0) ? 0 :
(t < 100000) ? ((s*100)/t) : (s/(t/100));
- dev_info(DEV, "%u %% had equal checksums, eliminated: %luK; "
+ drbd_info(device, "%u %% had equal checksums, eliminated: %luK; "
"transferred %luK total %luK\n",
ratio,
- Bit2KB(mdev->rs_same_csum),
- Bit2KB(mdev->rs_total - mdev->rs_same_csum),
- Bit2KB(mdev->rs_total));
+ Bit2KB(device->rs_same_csum),
+ Bit2KB(device->rs_total - device->rs_same_csum),
+ Bit2KB(device->rs_total));
}
}
- if (mdev->rs_failed) {
- dev_info(DEV, " %lu failed blocks\n", mdev->rs_failed);
+ if (device->rs_failed) {
+ drbd_info(device, " %lu failed blocks\n", device->rs_failed);
if (os.conn == C_SYNC_TARGET || os.conn == C_PAUSED_SYNC_T) {
ns.disk = D_INCONSISTENT;
@@ -914,179 +925,181 @@ int drbd_resync_finished(struct drbd_conf *mdev)
ns.pdsk = D_UP_TO_DATE;
if (os.conn == C_SYNC_TARGET || os.conn == C_PAUSED_SYNC_T) {
- if (mdev->p_uuid) {
+ if (device->p_uuid) {
int i;
for (i = UI_BITMAP ; i <= UI_HISTORY_END ; i++)
- _drbd_uuid_set(mdev, i, mdev->p_uuid[i]);
- drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_CURRENT]);
- _drbd_uuid_set(mdev, UI_CURRENT, mdev->p_uuid[UI_CURRENT]);
+ _drbd_uuid_set(device, i, device->p_uuid[i]);
+ drbd_uuid_set(device, UI_BITMAP, device->ldev->md.uuid[UI_CURRENT]);
+ _drbd_uuid_set(device, UI_CURRENT, device->p_uuid[UI_CURRENT]);
} else {
- dev_err(DEV, "mdev->p_uuid is NULL! BUG\n");
+ drbd_err(device, "device->p_uuid is NULL! BUG\n");
}
}
if (!(os.conn == C_VERIFY_S || os.conn == C_VERIFY_T)) {
/* for verify runs, we don't update uuids here,
* so there would be nothing to report. */
- drbd_uuid_set_bm(mdev, 0UL);
- drbd_print_uuids(mdev, "updated UUIDs");
- if (mdev->p_uuid) {
+ drbd_uuid_set_bm(device, 0UL);
+ drbd_print_uuids(device, "updated UUIDs");
+ if (device->p_uuid) {
/* Now the two UUID sets are equal, update what we
* know of the peer. */
int i;
for (i = UI_CURRENT ; i <= UI_HISTORY_END ; i++)
- mdev->p_uuid[i] = mdev->ldev->md.uuid[i];
+ device->p_uuid[i] = device->ldev->md.uuid[i];
}
}
}
- _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
+ _drbd_set_state(device, ns, CS_VERBOSE, NULL);
out_unlock:
- spin_unlock_irq(&mdev->tconn->req_lock);
- put_ldev(mdev);
+ spin_unlock_irq(&device->resource->req_lock);
+ put_ldev(device);
out:
- mdev->rs_total = 0;
- mdev->rs_failed = 0;
- mdev->rs_paused = 0;
+ device->rs_total = 0;
+ device->rs_failed = 0;
+ device->rs_paused = 0;
/* reset start sector, if we reached end of device */
- if (verify_done && mdev->ov_left == 0)
- mdev->ov_start_sector = 0;
+ if (verify_done && device->ov_left == 0)
+ device->ov_start_sector = 0;
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
if (khelper_cmd)
- drbd_khelper(mdev, khelper_cmd);
+ drbd_khelper(device, khelper_cmd);
return 1;
}
/* helper */
-static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_peer_request *peer_req)
+static void move_to_net_ee_or_free(struct drbd_device *device, struct drbd_peer_request *peer_req)
{
if (drbd_peer_req_has_active_page(peer_req)) {
/* This might happen if sendpage() has not finished */
int i = (peer_req->i.size + PAGE_SIZE -1) >> PAGE_SHIFT;
- atomic_add(i, &mdev->pp_in_use_by_net);
- atomic_sub(i, &mdev->pp_in_use);
- spin_lock_irq(&mdev->tconn->req_lock);
- list_add_tail(&peer_req->w.list, &mdev->net_ee);
- spin_unlock_irq(&mdev->tconn->req_lock);
+ atomic_add(i, &device->pp_in_use_by_net);
+ atomic_sub(i, &device->pp_in_use);
+ spin_lock_irq(&device->resource->req_lock);
+ list_add_tail(&peer_req->w.list, &device->net_ee);
+ spin_unlock_irq(&device->resource->req_lock);
wake_up(&drbd_pp_wait);
} else
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
}
/**
* w_e_end_data_req() - Worker callback, to send a P_DATA_REPLY packet in response to a P_DATA_REQUEST
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @w: work object.
* @cancel: The connection will be closed anyways
*/
int w_e_end_data_req(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
int err;
if (unlikely(cancel)) {
- drbd_free_peer_req(mdev, peer_req);
- dec_unacked(mdev);
+ drbd_free_peer_req(device, peer_req);
+ dec_unacked(device);
return 0;
}
if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) {
- err = drbd_send_block(mdev, P_DATA_REPLY, peer_req);
+ err = drbd_send_block(peer_device, P_DATA_REPLY, peer_req);
} else {
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Sending NegDReply. sector=%llus.\n",
+ drbd_err(device, "Sending NegDReply. sector=%llus.\n",
(unsigned long long)peer_req->i.sector);
- err = drbd_send_ack(mdev, P_NEG_DREPLY, peer_req);
+ err = drbd_send_ack(peer_device, P_NEG_DREPLY, peer_req);
}
- dec_unacked(mdev);
+ dec_unacked(device);
- move_to_net_ee_or_free(mdev, peer_req);
+ move_to_net_ee_or_free(device, peer_req);
if (unlikely(err))
- dev_err(DEV, "drbd_send_block() failed\n");
+ drbd_err(device, "drbd_send_block() failed\n");
return err;
}
/**
* w_e_end_rsdata_req() - Worker callback to send a P_RS_DATA_REPLY packet in response to a P_RS_DATA_REQUEST
- * @mdev: DRBD device.
* @w: work object.
* @cancel: The connection will be closed anyways
*/
int w_e_end_rsdata_req(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
int err;
if (unlikely(cancel)) {
- drbd_free_peer_req(mdev, peer_req);
- dec_unacked(mdev);
+ drbd_free_peer_req(device, peer_req);
+ dec_unacked(device);
return 0;
}
- if (get_ldev_if_state(mdev, D_FAILED)) {
- drbd_rs_complete_io(mdev, peer_req->i.sector);
- put_ldev(mdev);
+ if (get_ldev_if_state(device, D_FAILED)) {
+ drbd_rs_complete_io(device, peer_req->i.sector);
+ put_ldev(device);
}
- if (mdev->state.conn == C_AHEAD) {
- err = drbd_send_ack(mdev, P_RS_CANCEL, peer_req);
+ if (device->state.conn == C_AHEAD) {
+ err = drbd_send_ack(peer_device, P_RS_CANCEL, peer_req);
} else if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) {
- if (likely(mdev->state.pdsk >= D_INCONSISTENT)) {
- inc_rs_pending(mdev);
- err = drbd_send_block(mdev, P_RS_DATA_REPLY, peer_req);
+ if (likely(device->state.pdsk >= D_INCONSISTENT)) {
+ inc_rs_pending(device);
+ err = drbd_send_block(peer_device, P_RS_DATA_REPLY, peer_req);
} else {
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Not sending RSDataReply, "
+ drbd_err(device, "Not sending RSDataReply, "
"partner DISKLESS!\n");
err = 0;
}
} else {
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Sending NegRSDReply. sector %llus.\n",
+ drbd_err(device, "Sending NegRSDReply. sector %llus.\n",
(unsigned long long)peer_req->i.sector);
- err = drbd_send_ack(mdev, P_NEG_RS_DREPLY, peer_req);
+ err = drbd_send_ack(peer_device, P_NEG_RS_DREPLY, peer_req);
/* update resync data with failure */
- drbd_rs_failed_io(mdev, peer_req->i.sector, peer_req->i.size);
+ drbd_rs_failed_io(device, peer_req->i.sector, peer_req->i.size);
}
- dec_unacked(mdev);
+ dec_unacked(device);
- move_to_net_ee_or_free(mdev, peer_req);
+ move_to_net_ee_or_free(device, peer_req);
if (unlikely(err))
- dev_err(DEV, "drbd_send_block() failed\n");
+ drbd_err(device, "drbd_send_block() failed\n");
return err;
}
int w_e_end_csum_rs_req(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
struct digest_info *di;
int digest_size;
void *digest = NULL;
int err, eq = 0;
if (unlikely(cancel)) {
- drbd_free_peer_req(mdev, peer_req);
- dec_unacked(mdev);
+ drbd_free_peer_req(device, peer_req);
+ dec_unacked(device);
return 0;
}
- if (get_ldev(mdev)) {
- drbd_rs_complete_io(mdev, peer_req->i.sector);
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ drbd_rs_complete_io(device, peer_req->i.sector);
+ put_ldev(device);
}
di = peer_req->digest;
@@ -1095,47 +1108,48 @@ int w_e_end_csum_rs_req(struct drbd_work *w, int cancel)
/* quick hack to try to avoid a race against reconfiguration.
* a real fix would be much more involved,
* introducing more locking mechanisms */
- if (mdev->tconn->csums_tfm) {
- digest_size = crypto_hash_digestsize(mdev->tconn->csums_tfm);
- D_ASSERT(digest_size == di->digest_size);
+ if (peer_device->connection->csums_tfm) {
+ digest_size = crypto_hash_digestsize(peer_device->connection->csums_tfm);
+ D_ASSERT(device, digest_size == di->digest_size);
digest = kmalloc(digest_size, GFP_NOIO);
}
if (digest) {
- drbd_csum_ee(mdev, mdev->tconn->csums_tfm, peer_req, digest);
+ drbd_csum_ee(peer_device->connection->csums_tfm, peer_req, digest);
eq = !memcmp(digest, di->digest, digest_size);
kfree(digest);
}
if (eq) {
- drbd_set_in_sync(mdev, peer_req->i.sector, peer_req->i.size);
+ drbd_set_in_sync(device, peer_req->i.sector, peer_req->i.size);
/* rs_same_csums unit is BM_BLOCK_SIZE */
- mdev->rs_same_csum += peer_req->i.size >> BM_BLOCK_SHIFT;
- err = drbd_send_ack(mdev, P_RS_IS_IN_SYNC, peer_req);
+ device->rs_same_csum += peer_req->i.size >> BM_BLOCK_SHIFT;
+ err = drbd_send_ack(peer_device, P_RS_IS_IN_SYNC, peer_req);
} else {
- inc_rs_pending(mdev);
+ inc_rs_pending(device);
peer_req->block_id = ID_SYNCER; /* By setting block_id, digest pointer becomes invalid! */
peer_req->flags &= ~EE_HAS_DIGEST; /* This peer request no longer has a digest pointer */
kfree(di);
- err = drbd_send_block(mdev, P_RS_DATA_REPLY, peer_req);
+ err = drbd_send_block(peer_device, P_RS_DATA_REPLY, peer_req);
}
} else {
- err = drbd_send_ack(mdev, P_NEG_RS_DREPLY, peer_req);
+ err = drbd_send_ack(peer_device, P_NEG_RS_DREPLY, peer_req);
if (__ratelimit(&drbd_ratelimit_state))
- dev_err(DEV, "Sending NegDReply. I guess it gets messy.\n");
+ drbd_err(device, "Sending NegDReply. I guess it gets messy.\n");
}
- dec_unacked(mdev);
- move_to_net_ee_or_free(mdev, peer_req);
+ dec_unacked(device);
+ move_to_net_ee_or_free(device, peer_req);
if (unlikely(err))
- dev_err(DEV, "drbd_send_block/ack() failed\n");
+ drbd_err(device, "drbd_send_block/ack() failed\n");
return err;
}
int w_e_end_ov_req(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
sector_t sector = peer_req->i.sector;
unsigned int size = peer_req->i.size;
int digest_size;
@@ -1145,7 +1159,7 @@ int w_e_end_ov_req(struct drbd_work *w, int cancel)
if (unlikely(cancel))
goto out;
- digest_size = crypto_hash_digestsize(mdev->tconn->verify_tfm);
+ digest_size = crypto_hash_digestsize(peer_device->connection->verify_tfm);
digest = kmalloc(digest_size, GFP_NOIO);
if (!digest) {
err = 1; /* terminate the connection in case the allocation failed */
@@ -1153,7 +1167,7 @@ int w_e_end_ov_req(struct drbd_work *w, int cancel)
}
if (likely(!(peer_req->flags & EE_WAS_ERROR)))
- drbd_csum_ee(mdev, mdev->tconn->verify_tfm, peer_req, digest);
+ drbd_csum_ee(peer_device->connection->verify_tfm, peer_req, digest);
else
memset(digest, 0, digest_size);
@@ -1162,36 +1176,37 @@ int w_e_end_ov_req(struct drbd_work *w, int cancel)
* some distributed deadlock, if the other side blocks on
* congestion as well, because our receiver blocks in
* drbd_alloc_pages due to pp_in_use > max_buffers. */
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
peer_req = NULL;
- inc_rs_pending(mdev);
- err = drbd_send_drequest_csum(mdev, sector, size, digest, digest_size, P_OV_REPLY);
+ inc_rs_pending(device);
+ err = drbd_send_drequest_csum(peer_device, sector, size, digest, digest_size, P_OV_REPLY);
if (err)
- dec_rs_pending(mdev);
+ dec_rs_pending(device);
kfree(digest);
out:
if (peer_req)
- drbd_free_peer_req(mdev, peer_req);
- dec_unacked(mdev);
+ drbd_free_peer_req(device, peer_req);
+ dec_unacked(device);
return err;
}
-void drbd_ov_out_of_sync_found(struct drbd_conf *mdev, sector_t sector, int size)
+void drbd_ov_out_of_sync_found(struct drbd_device *device, sector_t sector, int size)
{
- if (mdev->ov_last_oos_start + mdev->ov_last_oos_size == sector) {
- mdev->ov_last_oos_size += size>>9;
+ if (device->ov_last_oos_start + device->ov_last_oos_size == sector) {
+ device->ov_last_oos_size += size>>9;
} else {
- mdev->ov_last_oos_start = sector;
- mdev->ov_last_oos_size = size>>9;
+ device->ov_last_oos_start = sector;
+ device->ov_last_oos_size = size>>9;
}
- drbd_set_out_of_sync(mdev, sector, size);
+ drbd_set_out_of_sync(device, sector, size);
}
int w_e_end_ov_reply(struct drbd_work *w, int cancel)
{
struct drbd_peer_request *peer_req = container_of(w, struct drbd_peer_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_peer_device *peer_device = peer_req->peer_device;
+ struct drbd_device *device = peer_device->device;
struct digest_info *di;
void *digest;
sector_t sector = peer_req->i.sector;
@@ -1201,27 +1216,27 @@ int w_e_end_ov_reply(struct drbd_work *w, int cancel)
bool stop_sector_reached = false;
if (unlikely(cancel)) {
- drbd_free_peer_req(mdev, peer_req);
- dec_unacked(mdev);
+ drbd_free_peer_req(device, peer_req);
+ dec_unacked(device);
return 0;
}
/* after "cancel", because after drbd_disconnect/drbd_rs_cancel_all
* the resync lru has been cleaned up already */
- if (get_ldev(mdev)) {
- drbd_rs_complete_io(mdev, peer_req->i.sector);
- put_ldev(mdev);
+ if (get_ldev(device)) {
+ drbd_rs_complete_io(device, peer_req->i.sector);
+ put_ldev(device);
}
di = peer_req->digest;
if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) {
- digest_size = crypto_hash_digestsize(mdev->tconn->verify_tfm);
+ digest_size = crypto_hash_digestsize(peer_device->connection->verify_tfm);
digest = kmalloc(digest_size, GFP_NOIO);
if (digest) {
- drbd_csum_ee(mdev, mdev->tconn->verify_tfm, peer_req, digest);
+ drbd_csum_ee(peer_device->connection->verify_tfm, peer_req, digest);
- D_ASSERT(digest_size == di->digest_size);
+ D_ASSERT(device, digest_size == di->digest_size);
eq = !memcmp(digest, di->digest, digest_size);
kfree(digest);
}
@@ -1232,102 +1247,95 @@ int w_e_end_ov_reply(struct drbd_work *w, int cancel)
* some distributed deadlock, if the other side blocks on
* congestion as well, because our receiver blocks in
* drbd_alloc_pages due to pp_in_use > max_buffers. */
- drbd_free_peer_req(mdev, peer_req);
+ drbd_free_peer_req(device, peer_req);
if (!eq)
- drbd_ov_out_of_sync_found(mdev, sector, size);
+ drbd_ov_out_of_sync_found(device, sector, size);
else
- ov_out_of_sync_print(mdev);
+ ov_out_of_sync_print(device);
- err = drbd_send_ack_ex(mdev, P_OV_RESULT, sector, size,
+ err = drbd_send_ack_ex(peer_device, P_OV_RESULT, sector, size,
eq ? ID_IN_SYNC : ID_OUT_OF_SYNC);
- dec_unacked(mdev);
+ dec_unacked(device);
- --mdev->ov_left;
+ --device->ov_left;
/* let's advance progress step marks only for every other megabyte */
- if ((mdev->ov_left & 0x200) == 0x200)
- drbd_advance_rs_marks(mdev, mdev->ov_left);
+ if ((device->ov_left & 0x200) == 0x200)
+ drbd_advance_rs_marks(device, device->ov_left);
- stop_sector_reached = verify_can_do_stop_sector(mdev) &&
- (sector + (size>>9)) >= mdev->ov_stop_sector;
+ stop_sector_reached = verify_can_do_stop_sector(device) &&
+ (sector + (size>>9)) >= device->ov_stop_sector;
- if (mdev->ov_left == 0 || stop_sector_reached) {
- ov_out_of_sync_print(mdev);
- drbd_resync_finished(mdev);
+ if (device->ov_left == 0 || stop_sector_reached) {
+ ov_out_of_sync_print(device);
+ drbd_resync_finished(device);
}
return err;
}
-int w_prev_work_done(struct drbd_work *w, int cancel)
-{
- struct drbd_wq_barrier *b = container_of(w, struct drbd_wq_barrier, w);
-
- complete(&b->done);
- return 0;
-}
-
/* FIXME
* We need to track the number of pending barrier acks,
* and to be able to wait for them.
* See also comment in drbd_adm_attach before drbd_suspend_io.
*/
-int drbd_send_barrier(struct drbd_tconn *tconn)
+static int drbd_send_barrier(struct drbd_connection *connection)
{
struct p_barrier *p;
struct drbd_socket *sock;
- sock = &tconn->data;
- p = conn_prepare_command(tconn, sock);
+ sock = &connection->data;
+ p = conn_prepare_command(connection, sock);
if (!p)
return -EIO;
- p->barrier = tconn->send.current_epoch_nr;
+ p->barrier = connection->send.current_epoch_nr;
p->pad = 0;
- tconn->send.current_epoch_writes = 0;
+ connection->send.current_epoch_writes = 0;
- return conn_send_command(tconn, sock, P_BARRIER, sizeof(*p), NULL, 0);
+ return conn_send_command(connection, sock, P_BARRIER, sizeof(*p), NULL, 0);
}
int w_send_write_hint(struct drbd_work *w, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device =
+ container_of(w, struct drbd_device, unplug_work);
struct drbd_socket *sock;
if (cancel)
return 0;
- sock = &mdev->tconn->data;
- if (!drbd_prepare_command(mdev, sock))
+ sock = &first_peer_device(device)->connection->data;
+ if (!drbd_prepare_command(first_peer_device(device), sock))
return -EIO;
- return drbd_send_command(mdev, sock, P_UNPLUG_REMOTE, 0, NULL, 0);
+ return drbd_send_command(first_peer_device(device), sock, P_UNPLUG_REMOTE, 0, NULL, 0);
}
-static void re_init_if_first_write(struct drbd_tconn *tconn, unsigned int epoch)
+static void re_init_if_first_write(struct drbd_connection *connection, unsigned int epoch)
{
- if (!tconn->send.seen_any_write_yet) {
- tconn->send.seen_any_write_yet = true;
- tconn->send.current_epoch_nr = epoch;
- tconn->send.current_epoch_writes = 0;
+ if (!connection->send.seen_any_write_yet) {
+ connection->send.seen_any_write_yet = true;
+ connection->send.current_epoch_nr = epoch;
+ connection->send.current_epoch_writes = 0;
}
}
-static void maybe_send_barrier(struct drbd_tconn *tconn, unsigned int epoch)
+static void maybe_send_barrier(struct drbd_connection *connection, unsigned int epoch)
{
/* re-init if first write on this connection */
- if (!tconn->send.seen_any_write_yet)
+ if (!connection->send.seen_any_write_yet)
return;
- if (tconn->send.current_epoch_nr != epoch) {
- if (tconn->send.current_epoch_writes)
- drbd_send_barrier(tconn);
- tconn->send.current_epoch_nr = epoch;
+ if (connection->send.current_epoch_nr != epoch) {
+ if (connection->send.current_epoch_writes)
+ drbd_send_barrier(connection);
+ connection->send.current_epoch_nr = epoch;
}
}
int w_send_out_of_sync(struct drbd_work *w, int cancel)
{
struct drbd_request *req = container_of(w, struct drbd_request, w);
- struct drbd_conf *mdev = w->mdev;
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_device *device = req->device;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
int err;
if (unlikely(cancel)) {
@@ -1335,13 +1343,13 @@ int w_send_out_of_sync(struct drbd_work *w, int cancel)
return 0;
}
- /* this time, no tconn->send.current_epoch_writes++;
+ /* this time, no connection->send.current_epoch_writes++;
* If it was sent, it was the closing barrier for the last
* replicated epoch, before we went into AHEAD mode.
* No more barriers will be sent, until we leave AHEAD mode again. */
- maybe_send_barrier(tconn, req->epoch);
+ maybe_send_barrier(connection, req->epoch);
- err = drbd_send_out_of_sync(mdev, req);
+ err = drbd_send_out_of_sync(first_peer_device(device), req);
req_mod(req, OOS_HANDED_TO_NETWORK);
return err;
@@ -1349,15 +1357,14 @@ int w_send_out_of_sync(struct drbd_work *w, int cancel)
/**
* w_send_dblock() - Worker callback to send a P_DATA packet in order to mirror a write request
- * @mdev: DRBD device.
* @w: work object.
* @cancel: The connection will be closed anyways
*/
int w_send_dblock(struct drbd_work *w, int cancel)
{
struct drbd_request *req = container_of(w, struct drbd_request, w);
- struct drbd_conf *mdev = w->mdev;
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_device *device = req->device;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
int err;
if (unlikely(cancel)) {
@@ -1365,11 +1372,11 @@ int w_send_dblock(struct drbd_work *w, int cancel)
return 0;
}
- re_init_if_first_write(tconn, req->epoch);
- maybe_send_barrier(tconn, req->epoch);
- tconn->send.current_epoch_writes++;
+ re_init_if_first_write(connection, req->epoch);
+ maybe_send_barrier(connection, req->epoch);
+ connection->send.current_epoch_writes++;
- err = drbd_send_dblock(mdev, req);
+ err = drbd_send_dblock(first_peer_device(device), req);
req_mod(req, err ? SEND_FAILED : HANDED_OVER_TO_NETWORK);
return err;
@@ -1377,15 +1384,14 @@ int w_send_dblock(struct drbd_work *w, int cancel)
/**
* w_send_read_req() - Worker callback to send a read request (P_DATA_REQUEST) packet
- * @mdev: DRBD device.
* @w: work object.
* @cancel: The connection will be closed anyways
*/
int w_send_read_req(struct drbd_work *w, int cancel)
{
struct drbd_request *req = container_of(w, struct drbd_request, w);
- struct drbd_conf *mdev = w->mdev;
- struct drbd_tconn *tconn = mdev->tconn;
+ struct drbd_device *device = req->device;
+ struct drbd_connection *connection = first_peer_device(device)->connection;
int err;
if (unlikely(cancel)) {
@@ -1395,9 +1401,9 @@ int w_send_read_req(struct drbd_work *w, int cancel)
/* Even read requests may close a write epoch,
* if there was any yet. */
- maybe_send_barrier(tconn, req->epoch);
+ maybe_send_barrier(connection, req->epoch);
- err = drbd_send_drequest(mdev, P_DATA_REQUEST, req->i.sector, req->i.size,
+ err = drbd_send_drequest(first_peer_device(device), P_DATA_REQUEST, req->i.sector, req->i.size,
(unsigned long)req);
req_mod(req, err ? SEND_FAILED : HANDED_OVER_TO_NETWORK);
@@ -1408,21 +1414,21 @@ int w_send_read_req(struct drbd_work *w, int cancel)
int w_restart_disk_io(struct drbd_work *w, int cancel)
{
struct drbd_request *req = container_of(w, struct drbd_request, w);
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device = req->device;
if (bio_data_dir(req->master_bio) == WRITE && req->rq_state & RQ_IN_ACT_LOG)
- drbd_al_begin_io(mdev, &req->i, false);
+ drbd_al_begin_io(device, &req->i, false);
drbd_req_make_private_bio(req, req->master_bio);
- req->private_bio->bi_bdev = mdev->ldev->backing_bdev;
+ req->private_bio->bi_bdev = device->ldev->backing_bdev;
generic_make_request(req->private_bio);
return 0;
}
-static int _drbd_may_sync_now(struct drbd_conf *mdev)
+static int _drbd_may_sync_now(struct drbd_device *device)
{
- struct drbd_conf *odev = mdev;
+ struct drbd_device *odev = device;
int resync_after;
while (1) {
@@ -1433,7 +1439,7 @@ static int _drbd_may_sync_now(struct drbd_conf *mdev)
rcu_read_unlock();
if (resync_after == -1)
return 1;
- odev = minor_to_mdev(resync_after);
+ odev = minor_to_device(resync_after);
if (!odev)
return 1;
if ((odev->state.conn >= C_SYNC_SOURCE &&
@@ -1446,17 +1452,17 @@ static int _drbd_may_sync_now(struct drbd_conf *mdev)
/**
* _drbd_pause_after() - Pause resync on all devices that may not resync now
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Called from process context only (admin command and after_state_ch).
*/
-static int _drbd_pause_after(struct drbd_conf *mdev)
+static int _drbd_pause_after(struct drbd_device *device)
{
- struct drbd_conf *odev;
+ struct drbd_device *odev;
int i, rv = 0;
rcu_read_lock();
- idr_for_each_entry(&minors, odev, i) {
+ idr_for_each_entry(&drbd_devices, odev, i) {
if (odev->state.conn == C_STANDALONE && odev->state.disk == D_DISKLESS)
continue;
if (!_drbd_may_sync_now(odev))
@@ -1470,17 +1476,17 @@ static int _drbd_pause_after(struct drbd_conf *mdev)
/**
* _drbd_resume_next() - Resume resync on all devices that may resync now
- * @mdev: DRBD device.
+ * @device: DRBD device.
*
* Called from process context only (admin command and worker).
*/
-static int _drbd_resume_next(struct drbd_conf *mdev)
+static int _drbd_resume_next(struct drbd_device *device)
{
- struct drbd_conf *odev;
+ struct drbd_device *odev;
int i, rv = 0;
rcu_read_lock();
- idr_for_each_entry(&minors, odev, i) {
+ idr_for_each_entry(&drbd_devices, odev, i) {
if (odev->state.conn == C_STANDALONE && odev->state.disk == D_DISKLESS)
continue;
if (odev->state.aftr_isp) {
@@ -1494,24 +1500,24 @@ static int _drbd_resume_next(struct drbd_conf *mdev)
return rv;
}
-void resume_next_sg(struct drbd_conf *mdev)
+void resume_next_sg(struct drbd_device *device)
{
write_lock_irq(&global_state_lock);
- _drbd_resume_next(mdev);
+ _drbd_resume_next(device);
write_unlock_irq(&global_state_lock);
}
-void suspend_other_sg(struct drbd_conf *mdev)
+void suspend_other_sg(struct drbd_device *device)
{
write_lock_irq(&global_state_lock);
- _drbd_pause_after(mdev);
+ _drbd_pause_after(device);
write_unlock_irq(&global_state_lock);
}
/* caller must hold global_state_lock */
-enum drbd_ret_code drbd_resync_after_valid(struct drbd_conf *mdev, int o_minor)
+enum drbd_ret_code drbd_resync_after_valid(struct drbd_device *device, int o_minor)
{
- struct drbd_conf *odev;
+ struct drbd_device *odev;
int resync_after;
if (o_minor == -1)
@@ -1520,9 +1526,9 @@ enum drbd_ret_code drbd_resync_after_valid(struct drbd_conf *mdev, int o_minor)
return ERR_RESYNC_AFTER;
/* check for loops */
- odev = minor_to_mdev(o_minor);
+ odev = minor_to_device(o_minor);
while (1) {
- if (odev == mdev)
+ if (odev == device)
return ERR_RESYNC_AFTER_CYCLE;
/* You are free to depend on diskless, non-existing,
@@ -1542,35 +1548,35 @@ enum drbd_ret_code drbd_resync_after_valid(struct drbd_conf *mdev, int o_minor)
return NO_ERROR;
/* follow the dependency chain */
- odev = minor_to_mdev(resync_after);
+ odev = minor_to_device(resync_after);
}
}
/* caller must hold global_state_lock */
-void drbd_resync_after_changed(struct drbd_conf *mdev)
+void drbd_resync_after_changed(struct drbd_device *device)
{
int changes;
do {
- changes = _drbd_pause_after(mdev);
- changes |= _drbd_resume_next(mdev);
+ changes = _drbd_pause_after(device);
+ changes |= _drbd_resume_next(device);
} while (changes);
}
-void drbd_rs_controller_reset(struct drbd_conf *mdev)
+void drbd_rs_controller_reset(struct drbd_device *device)
{
struct fifo_buffer *plan;
- atomic_set(&mdev->rs_sect_in, 0);
- atomic_set(&mdev->rs_sect_ev, 0);
- mdev->rs_in_flight = 0;
+ atomic_set(&device->rs_sect_in, 0);
+ atomic_set(&device->rs_sect_ev, 0);
+ device->rs_in_flight = 0;
/* Updating the RCU protected object in place is necessary since
this function gets called from atomic context.
It is valid since all other updates also lead to an completely
empty fifo */
rcu_read_lock();
- plan = rcu_dereference(mdev->rs_plan_s);
+ plan = rcu_dereference(device->rs_plan_s);
plan->total = 0;
fifo_set(plan, 0);
rcu_read_unlock();
@@ -1578,101 +1584,104 @@ void drbd_rs_controller_reset(struct drbd_conf *mdev)
void start_resync_timer_fn(unsigned long data)
{
- struct drbd_conf *mdev = (struct drbd_conf *) data;
+ struct drbd_device *device = (struct drbd_device *) data;
- drbd_queue_work(&mdev->tconn->sender_work, &mdev->start_resync_work);
+ drbd_queue_work(&first_peer_device(device)->connection->sender_work,
+ &device->start_resync_work);
}
int w_start_resync(struct drbd_work *w, int cancel)
{
- struct drbd_conf *mdev = w->mdev;
+ struct drbd_device *device =
+ container_of(w, struct drbd_device, start_resync_work);
- if (atomic_read(&mdev->unacked_cnt) || atomic_read(&mdev->rs_pending_cnt)) {
- dev_warn(DEV, "w_start_resync later...\n");
- mdev->start_resync_timer.expires = jiffies + HZ/10;
- add_timer(&mdev->start_resync_timer);
+ if (atomic_read(&device->unacked_cnt) || atomic_read(&device->rs_pending_cnt)) {
+ drbd_warn(device, "w_start_resync later...\n");
+ device->start_resync_timer.expires = jiffies + HZ/10;
+ add_timer(&device->start_resync_timer);
return 0;
}
- drbd_start_resync(mdev, C_SYNC_SOURCE);
- clear_bit(AHEAD_TO_SYNC_SOURCE, &mdev->flags);
+ drbd_start_resync(device, C_SYNC_SOURCE);
+ clear_bit(AHEAD_TO_SYNC_SOURCE, &device->flags);
return 0;
}
/**
* drbd_start_resync() - Start the resync process
- * @mdev: DRBD device.
+ * @device: DRBD device.
* @side: Either C_SYNC_SOURCE or C_SYNC_TARGET
*
* This function might bring you directly into one of the
* C_PAUSED_SYNC_* states.
*/
-void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
+void drbd_start_resync(struct drbd_device *device, enum drbd_conns side)
{
union drbd_state ns;
int r;
- if (mdev->state.conn >= C_SYNC_SOURCE && mdev->state.conn < C_AHEAD) {
- dev_err(DEV, "Resync already running!\n");
+ if (device->state.conn >= C_SYNC_SOURCE && device->state.conn < C_AHEAD) {
+ drbd_err(device, "Resync already running!\n");
return;
}
- if (!test_bit(B_RS_H_DONE, &mdev->flags)) {
+ if (!test_bit(B_RS_H_DONE, &device->flags)) {
if (side == C_SYNC_TARGET) {
/* Since application IO was locked out during C_WF_BITMAP_T and
C_WF_SYNC_UUID we are still unmodified. Before going to C_SYNC_TARGET
we check that we might make the data inconsistent. */
- r = drbd_khelper(mdev, "before-resync-target");
+ r = drbd_khelper(device, "before-resync-target");
r = (r >> 8) & 0xff;
if (r > 0) {
- dev_info(DEV, "before-resync-target handler returned %d, "
+ drbd_info(device, "before-resync-target handler returned %d, "
"dropping connection.\n", r);
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(first_peer_device(device)->connection, NS(conn, C_DISCONNECTING), CS_HARD);
return;
}
} else /* C_SYNC_SOURCE */ {
- r = drbd_khelper(mdev, "before-resync-source");
+ r = drbd_khelper(device, "before-resync-source");
r = (r >> 8) & 0xff;
if (r > 0) {
if (r == 3) {
- dev_info(DEV, "before-resync-source handler returned %d, "
+ drbd_info(device, "before-resync-source handler returned %d, "
"ignoring. Old userland tools?", r);
} else {
- dev_info(DEV, "before-resync-source handler returned %d, "
+ drbd_info(device, "before-resync-source handler returned %d, "
"dropping connection.\n", r);
- conn_request_state(mdev->tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ conn_request_state(first_peer_device(device)->connection,
+ NS(conn, C_DISCONNECTING), CS_HARD);
return;
}
}
}
}
- if (current == mdev->tconn->worker.task) {
+ if (current == first_peer_device(device)->connection->worker.task) {
/* The worker should not sleep waiting for state_mutex,
that can take long */
- if (!mutex_trylock(mdev->state_mutex)) {
- set_bit(B_RS_H_DONE, &mdev->flags);
- mdev->start_resync_timer.expires = jiffies + HZ/5;
- add_timer(&mdev->start_resync_timer);
+ if (!mutex_trylock(device->state_mutex)) {
+ set_bit(B_RS_H_DONE, &device->flags);
+ device->start_resync_timer.expires = jiffies + HZ/5;
+ add_timer(&device->start_resync_timer);
return;
}
} else {
- mutex_lock(mdev->state_mutex);
+ mutex_lock(device->state_mutex);
}
- clear_bit(B_RS_H_DONE, &mdev->flags);
+ clear_bit(B_RS_H_DONE, &device->flags);
write_lock_irq(&global_state_lock);
/* Did some connection breakage or IO error race with us? */
- if (mdev->state.conn < C_CONNECTED
- || !get_ldev_if_state(mdev, D_NEGOTIATING)) {
+ if (device->state.conn < C_CONNECTED
+ || !get_ldev_if_state(device, D_NEGOTIATING)) {
write_unlock_irq(&global_state_lock);
- mutex_unlock(mdev->state_mutex);
+ mutex_unlock(device->state_mutex);
return;
}
- ns = drbd_read_state(mdev);
+ ns = drbd_read_state(device);
- ns.aftr_isp = !_drbd_may_sync_now(mdev);
+ ns.aftr_isp = !_drbd_may_sync_now(device);
ns.conn = side;
@@ -1681,43 +1690,43 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
else /* side == C_SYNC_SOURCE */
ns.pdsk = D_INCONSISTENT;
- r = __drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
- ns = drbd_read_state(mdev);
+ r = __drbd_set_state(device, ns, CS_VERBOSE, NULL);
+ ns = drbd_read_state(device);
if (ns.conn < C_CONNECTED)
r = SS_UNKNOWN_ERROR;
if (r == SS_SUCCESS) {
- unsigned long tw = drbd_bm_total_weight(mdev);
+ unsigned long tw = drbd_bm_total_weight(device);
unsigned long now = jiffies;
int i;
- mdev->rs_failed = 0;
- mdev->rs_paused = 0;
- mdev->rs_same_csum = 0;
- mdev->rs_last_events = 0;
- mdev->rs_last_sect_ev = 0;
- mdev->rs_total = tw;
- mdev->rs_start = now;
+ device->rs_failed = 0;
+ device->rs_paused = 0;
+ device->rs_same_csum = 0;
+ device->rs_last_events = 0;
+ device->rs_last_sect_ev = 0;
+ device->rs_total = tw;
+ device->rs_start = now;
for (i = 0; i < DRBD_SYNC_MARKS; i++) {
- mdev->rs_mark_left[i] = tw;
- mdev->rs_mark_time[i] = now;
+ device->rs_mark_left[i] = tw;
+ device->rs_mark_time[i] = now;
}
- _drbd_pause_after(mdev);
+ _drbd_pause_after(device);
}
write_unlock_irq(&global_state_lock);
if (r == SS_SUCCESS) {
/* reset rs_last_bcast when a resync or verify is started,
* to deal with potential jiffies wrap. */
- mdev->rs_last_bcast = jiffies - HZ;
+ device->rs_last_bcast = jiffies - HZ;
- dev_info(DEV, "Began resync as %s (will sync %lu KB [%lu bits set]).\n",
+ drbd_info(device, "Began resync as %s (will sync %lu KB [%lu bits set]).\n",
drbd_conn_str(ns.conn),
- (unsigned long) mdev->rs_total << (BM_BLOCK_SHIFT-10),
- (unsigned long) mdev->rs_total);
+ (unsigned long) device->rs_total << (BM_BLOCK_SHIFT-10),
+ (unsigned long) device->rs_total);
if (side == C_SYNC_TARGET)
- mdev->bm_resync_fo = 0;
+ device->bm_resync_fo = 0;
/* Since protocol 96, we must serialize drbd_gen_and_send_sync_uuid
* with w_send_oos, or the sync target will get confused as to
@@ -1726,10 +1735,12 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
* drbd_resync_finished from here in that case.
* We drbd_gen_and_send_sync_uuid here for protocol < 96,
* and from after_state_ch otherwise. */
- if (side == C_SYNC_SOURCE && mdev->tconn->agreed_pro_version < 96)
- drbd_gen_and_send_sync_uuid(mdev);
+ if (side == C_SYNC_SOURCE &&
+ first_peer_device(device)->connection->agreed_pro_version < 96)
+ drbd_gen_and_send_sync_uuid(first_peer_device(device));
- if (mdev->tconn->agreed_pro_version < 95 && mdev->rs_total == 0) {
+ if (first_peer_device(device)->connection->agreed_pro_version < 95 &&
+ device->rs_total == 0) {
/* This still has a race (about when exactly the peers
* detect connection loss) that can lead to a full sync
* on next handshake. In 8.3.9 we fixed this with explicit
@@ -1745,33 +1756,33 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
int timeo;
rcu_read_lock();
- nc = rcu_dereference(mdev->tconn->net_conf);
+ nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
timeo = nc->ping_int * HZ + nc->ping_timeo * HZ / 9;
rcu_read_unlock();
schedule_timeout_interruptible(timeo);
}
- drbd_resync_finished(mdev);
+ drbd_resync_finished(device);
}
- drbd_rs_controller_reset(mdev);
- /* ns.conn may already be != mdev->state.conn,
+ drbd_rs_controller_reset(device);
+ /* ns.conn may already be != device->state.conn,
* we may have been paused in between, or become paused until
* the timer triggers.
* No matter, that is handled in resync_timer_fn() */
if (ns.conn == C_SYNC_TARGET)
- mod_timer(&mdev->resync_timer, jiffies);
+ mod_timer(&device->resync_timer, jiffies);
- drbd_md_sync(mdev);
+ drbd_md_sync(device);
}
- put_ldev(mdev);
- mutex_unlock(mdev->state_mutex);
+ put_ldev(device);
+ mutex_unlock(device->state_mutex);
}
/* If the resource already closed the current epoch, but we did not
* (because we have not yet seen new requests), we should send the
* corresponding barrier now. Must be checked within the same spinlock
* that is used to check for new requests. */
-bool need_to_send_barrier(struct drbd_tconn *connection)
+static bool need_to_send_barrier(struct drbd_connection *connection)
{
if (!connection->send.seen_any_write_yet)
return false;
@@ -1795,7 +1806,7 @@ bool need_to_send_barrier(struct drbd_tconn *connection)
return true;
}
-bool dequeue_work_batch(struct drbd_work_queue *queue, struct list_head *work_list)
+static bool dequeue_work_batch(struct drbd_work_queue *queue, struct list_head *work_list)
{
spin_lock_irq(&queue->q_lock);
list_splice_init(&queue->q, work_list);
@@ -1803,7 +1814,7 @@ bool dequeue_work_batch(struct drbd_work_queue *queue, struct list_head *work_li
return !list_empty(work_list);
}
-bool dequeue_work_item(struct drbd_work_queue *queue, struct list_head *work_list)
+static bool dequeue_work_item(struct drbd_work_queue *queue, struct list_head *work_list)
{
spin_lock_irq(&queue->q_lock);
if (!list_empty(&queue->q))
@@ -1812,7 +1823,7 @@ bool dequeue_work_item(struct drbd_work_queue *queue, struct list_head *work_lis
return !list_empty(work_list);
}
-void wait_for_work(struct drbd_tconn *connection, struct list_head *work_list)
+static void wait_for_work(struct drbd_connection *connection, struct list_head *work_list)
{
DEFINE_WAIT(wait);
struct net_conf *nc;
@@ -1842,7 +1853,7 @@ void wait_for_work(struct drbd_tconn *connection, struct list_head *work_list)
for (;;) {
int send_barrier;
prepare_to_wait(&connection->sender_work.q_wait, &wait, TASK_INTERRUPTIBLE);
- spin_lock_irq(&connection->req_lock);
+ spin_lock_irq(&connection->resource->req_lock);
spin_lock(&connection->sender_work.q_lock); /* FIXME get rid of this one? */
/* dequeue single item only,
* we still use drbd_queue_work_front() in some places */
@@ -1850,11 +1861,11 @@ void wait_for_work(struct drbd_tconn *connection, struct list_head *work_list)
list_move(connection->sender_work.q.next, work_list);
spin_unlock(&connection->sender_work.q_lock); /* FIXME get rid of this one? */
if (!list_empty(work_list) || signal_pending(current)) {
- spin_unlock_irq(&connection->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
break;
}
send_barrier = need_to_send_barrier(connection);
- spin_unlock_irq(&connection->req_lock);
+ spin_unlock_irq(&connection->resource->req_lock);
if (send_barrier) {
drbd_send_barrier(connection);
connection->send.current_epoch_nr++;
@@ -1883,9 +1894,9 @@ void wait_for_work(struct drbd_tconn *connection, struct list_head *work_list)
int drbd_worker(struct drbd_thread *thi)
{
- struct drbd_tconn *tconn = thi->tconn;
+ struct drbd_connection *connection = thi->connection;
struct drbd_work *w = NULL;
- struct drbd_conf *mdev;
+ struct drbd_peer_device *peer_device;
LIST_HEAD(work_list);
int vnr;
@@ -1895,12 +1906,12 @@ int drbd_worker(struct drbd_thread *thi)
/* as long as we use drbd_queue_work_front(),
* we may only dequeue single work items here, not batches. */
if (list_empty(&work_list))
- wait_for_work(tconn, &work_list);
+ wait_for_work(connection, &work_list);
if (signal_pending(current)) {
flush_signals(current);
if (get_t_state(thi) == RUNNING) {
- conn_warn(tconn, "Worker got an unexpected signal\n");
+ drbd_warn(connection, "Worker got an unexpected signal\n");
continue;
}
break;
@@ -1912,10 +1923,10 @@ int drbd_worker(struct drbd_thread *thi)
while (!list_empty(&work_list)) {
w = list_first_entry(&work_list, struct drbd_work, list);
list_del_init(&w->list);
- if (w->cb(w, tconn->cstate < C_WF_REPORT_PARAMS) == 0)
+ if (w->cb(w, connection->cstate < C_WF_REPORT_PARAMS) == 0)
continue;
- if (tconn->cstate >= C_WF_REPORT_PARAMS)
- conn_request_state(tconn, NS(conn, C_NETWORK_FAILURE), CS_HARD);
+ if (connection->cstate >= C_WF_REPORT_PARAMS)
+ conn_request_state(connection, NS(conn, C_NETWORK_FAILURE), CS_HARD);
}
}
@@ -1925,16 +1936,17 @@ int drbd_worker(struct drbd_thread *thi)
list_del_init(&w->list);
w->cb(w, 1);
}
- dequeue_work_batch(&tconn->sender_work, &work_list);
+ dequeue_work_batch(&connection->sender_work, &work_list);
} while (!list_empty(&work_list));
rcu_read_lock();
- idr_for_each_entry(&tconn->volumes, mdev, vnr) {
- D_ASSERT(mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE);
- kref_get(&mdev->kref);
+ idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+ struct drbd_device *device = peer_device->device;
+ D_ASSERT(device, device->state.disk == D_DISKLESS && device->state.conn == C_STANDALONE);
+ kref_get(&device->kref);
rcu_read_unlock();
- drbd_mdev_cleanup(mdev);
- kref_put(&mdev->kref, &drbd_minor_destroy);
+ drbd_device_cleanup(device);
+ kref_put(&device->kref, drbd_destroy_device);
rcu_read_lock();
}
rcu_read_unlock();
diff --git a/drivers/block/drbd/drbd_wrappers.h b/drivers/block/drbd/drbd_wrappers.h
index 328f18e4b4ee..3db9ebaf64f6 100644
--- a/drivers/block/drbd/drbd_wrappers.h
+++ b/drivers/block/drbd/drbd_wrappers.h
@@ -9,12 +9,12 @@
extern char *drbd_sec_holder;
/* sets the number of 512 byte sectors of our virtual device */
-static inline void drbd_set_my_capacity(struct drbd_conf *mdev,
+static inline void drbd_set_my_capacity(struct drbd_device *device,
sector_t size)
{
- /* set_capacity(mdev->this_bdev->bd_disk, size); */
- set_capacity(mdev->vdisk, size);
- mdev->this_bdev->bd_inode->i_size = (loff_t)size << 9;
+ /* set_capacity(device->this_bdev->bd_disk, size); */
+ set_capacity(device->vdisk, size);
+ device->this_bdev->bd_inode->i_size = (loff_t)size << 9;
}
#define drbd_bio_uptodate(bio) bio_flagged(bio, BIO_UPTODATE)
@@ -27,20 +27,20 @@ extern void drbd_request_endio(struct bio *bio, int error);
/*
* used to submit our private bio
*/
-static inline void drbd_generic_make_request(struct drbd_conf *mdev,
+static inline void drbd_generic_make_request(struct drbd_device *device,
int fault_type, struct bio *bio)
{
__release(local);
if (!bio->bi_bdev) {
printk(KERN_ERR "drbd%d: drbd_generic_make_request: "
"bio->bi_bdev == NULL\n",
- mdev_to_minor(mdev));
+ device_to_minor(device));
dump_stack();
bio_endio(bio, -ENODEV);
return;
}
- if (drbd_insert_fault(mdev, fault_type))
+ if (drbd_insert_fault(device, fault_type))
bio_endio(bio, -EIO);
else
generic_make_request(bio);
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 2023043ce7c0..8f5565bf34cd 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -961,17 +961,31 @@ static void empty(void)
{
}
-static DECLARE_WORK(floppy_work, NULL);
+static void (*floppy_work_fn)(void);
+
+static void floppy_work_workfn(struct work_struct *work)
+{
+ floppy_work_fn();
+}
+
+static DECLARE_WORK(floppy_work, floppy_work_workfn);
static void schedule_bh(void (*handler)(void))
{
WARN_ON(work_pending(&floppy_work));
- PREPARE_WORK(&floppy_work, (work_func_t)handler);
+ floppy_work_fn = handler;
queue_work(floppy_wq, &floppy_work);
}
-static DECLARE_DELAYED_WORK(fd_timer, NULL);
+static void (*fd_timer_fn)(void) = NULL;
+
+static void fd_timer_workfn(struct work_struct *work)
+{
+ fd_timer_fn();
+}
+
+static DECLARE_DELAYED_WORK(fd_timer, fd_timer_workfn);
static void cancel_activity(void)
{
@@ -982,7 +996,7 @@ static void cancel_activity(void)
/* this function makes sure that the disk stays in the drive during the
* transfer */
-static void fd_watchdog(struct work_struct *arg)
+static void fd_watchdog(void)
{
debug_dcl(DP->flags, "calling disk change from watchdog\n");
@@ -993,7 +1007,7 @@ static void fd_watchdog(struct work_struct *arg)
reset_fdc();
} else {
cancel_delayed_work(&fd_timer);
- PREPARE_DELAYED_WORK(&fd_timer, fd_watchdog);
+ fd_timer_fn = fd_watchdog;
queue_delayed_work(floppy_wq, &fd_timer, HZ / 10);
}
}
@@ -1005,7 +1019,8 @@ static void main_command_interrupt(void)
}
/* waits for a delay (spinup or select) to pass */
-static int fd_wait_for_completion(unsigned long expires, work_func_t function)
+static int fd_wait_for_completion(unsigned long expires,
+ void (*function)(void))
{
if (FDCS->reset) {
reset_fdc(); /* do the reset during sleep to win time
@@ -1016,7 +1031,7 @@ static int fd_wait_for_completion(unsigned long expires, work_func_t function)
if (time_before(jiffies, expires)) {
cancel_delayed_work(&fd_timer);
- PREPARE_DELAYED_WORK(&fd_timer, function);
+ fd_timer_fn = function;
queue_delayed_work(floppy_wq, &fd_timer, expires - jiffies);
return 1;
}
@@ -1334,8 +1349,7 @@ static int fdc_dtr(void)
* Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
*/
FDCS->dtr = raw_cmd->rate & 3;
- return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
- (work_func_t)floppy_ready);
+ return fd_wait_for_completion(jiffies + 2UL * HZ / 100, floppy_ready);
} /* fdc_dtr */
static void tell_sector(void)
@@ -1440,7 +1454,7 @@ static void setup_rw_floppy(void)
int flags;
int dflags;
unsigned long ready_date;
- work_func_t function;
+ void (*function)(void);
flags = raw_cmd->flags;
if (flags & (FD_RAW_READ | FD_RAW_WRITE))
@@ -1454,9 +1468,9 @@ static void setup_rw_floppy(void)
*/
if (time_after(ready_date, jiffies + DP->select_delay)) {
ready_date -= DP->select_delay;
- function = (work_func_t)floppy_start;
+ function = floppy_start;
} else
- function = (work_func_t)setup_rw_floppy;
+ function = setup_rw_floppy;
/* wait until the floppy is spinning fast enough */
if (fd_wait_for_completion(ready_date, function))
@@ -1486,7 +1500,7 @@ static void setup_rw_floppy(void)
inr = result();
cont->interrupt();
} else if (flags & FD_RAW_NEED_DISK)
- fd_watchdog(NULL);
+ fd_watchdog();
}
static int blind_seek;
@@ -1863,7 +1877,7 @@ static int start_motor(void (*function)(void))
/* wait_for_completion also schedules reset if needed. */
return fd_wait_for_completion(DRS->select_date + DP->select_delay,
- (work_func_t)function);
+ function);
}
static void floppy_ready(void)
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 516026954be6..59c5abe32f06 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -252,38 +252,45 @@ static void mtip_async_complete(struct mtip_port *port,
void *data,
int status)
{
- struct mtip_cmd *command;
+ struct mtip_cmd *cmd;
struct driver_data *dd = data;
- int cb_status = status ? -EIO : 0;
+ int unaligned, cb_status = status ? -EIO : 0;
+ void (*func)(void *, int);
if (unlikely(!dd) || unlikely(!port))
return;
- command = &port->commands[tag];
+ cmd = &port->commands[tag];
if (unlikely(status == PORT_IRQ_TF_ERR)) {
dev_warn(&port->dd->pdev->dev,
"Command tag %d failed due to TFE\n", tag);
}
+ /* Clear the active flag */
+ atomic_set(&port->commands[tag].active, 0);
+
/* Upper layer callback */
- if (likely(command->async_callback))
- command->async_callback(command->async_data, cb_status);
+ func = cmd->async_callback;
+ if (likely(func && cmpxchg(&cmd->async_callback, func, 0) == func)) {
- command->async_callback = NULL;
- command->comp_func = NULL;
+ /* Unmap the DMA scatter list entries */
+ dma_unmap_sg(&dd->pdev->dev,
+ cmd->sg,
+ cmd->scatter_ents,
+ cmd->direction);
- /* Unmap the DMA scatter list entries */
- dma_unmap_sg(&dd->pdev->dev,
- command->sg,
- command->scatter_ents,
- command->direction);
+ func(cmd->async_data, cb_status);
+ unaligned = cmd->unaligned;
- /* Clear the allocated and active bits for the command */
- atomic_set(&port->commands[tag].active, 0);
- release_slot(port, tag);
+ /* Clear the allocated bit for the command */
+ release_slot(port, tag);
- up(&port->cmd_slot);
+ if (unlikely(unaligned))
+ up(&port->cmd_slot_unal);
+ else
+ up(&port->cmd_slot);
+ }
}
/*
@@ -660,11 +667,12 @@ static void mtip_timeout_function(unsigned long int data)
{
struct mtip_port *port = (struct mtip_port *) data;
struct host_to_dev_fis *fis;
- struct mtip_cmd *command;
- int tag, cmdto_cnt = 0;
+ struct mtip_cmd *cmd;
+ int unaligned, tag, cmdto_cnt = 0;
unsigned int bit, group;
unsigned int num_command_slots;
unsigned long to, tagaccum[SLOTBITS_IN_LONGS];
+ void (*func)(void *, int);
if (unlikely(!port))
return;
@@ -694,8 +702,8 @@ static void mtip_timeout_function(unsigned long int data)
group = tag >> 5;
bit = tag & 0x1F;
- command = &port->commands[tag];
- fis = (struct host_to_dev_fis *) command->command;
+ cmd = &port->commands[tag];
+ fis = (struct host_to_dev_fis *) cmd->command;
set_bit(tag, tagaccum);
cmdto_cnt++;
@@ -709,27 +717,30 @@ static void mtip_timeout_function(unsigned long int data)
*/
writel(1 << bit, port->completed[group]);
- /* Call the async completion callback. */
- if (likely(command->async_callback))
- command->async_callback(command->async_data,
- -EIO);
- command->async_callback = NULL;
- command->comp_func = NULL;
+ /* Clear the active flag for the command */
+ atomic_set(&port->commands[tag].active, 0);
- /* Unmap the DMA scatter list entries */
- dma_unmap_sg(&port->dd->pdev->dev,
- command->sg,
- command->scatter_ents,
- command->direction);
+ func = cmd->async_callback;
+ if (func &&
+ cmpxchg(&cmd->async_callback, func, 0) == func) {
- /*
- * Clear the allocated bit and active tag for the
- * command.
- */
- atomic_set(&port->commands[tag].active, 0);
- release_slot(port, tag);
+ /* Unmap the DMA scatter list entries */
+ dma_unmap_sg(&port->dd->pdev->dev,
+ cmd->sg,
+ cmd->scatter_ents,
+ cmd->direction);
- up(&port->cmd_slot);
+ func(cmd->async_data, -EIO);
+ unaligned = cmd->unaligned;
+
+ /* Clear the allocated bit for the command. */
+ release_slot(port, tag);
+
+ if (unaligned)
+ up(&port->cmd_slot_unal);
+ else
+ up(&port->cmd_slot);
+ }
}
}
@@ -4213,6 +4224,7 @@ skip_create_disk:
blk_queue_max_hw_sectors(dd->queue, 0xffff);
blk_queue_max_segment_size(dd->queue, 0x400000);
blk_queue_io_min(dd->queue, 4096);
+ blk_queue_bounce_limit(dd->queue, dd->pdev->dma_mask);
/*
* write back cache is not supported in the device. FUA depends on
@@ -4498,7 +4510,7 @@ static int mtip_pci_probe(struct pci_dev *pdev,
}
dev_info(&pdev->dev, "NUMA node %d (closest: %d,%d, probe on %d:%d)\n",
my_node, pcibus_to_node(pdev->bus), dev_to_node(&pdev->dev),
- cpu_to_node(smp_processor_id()), smp_processor_id());
+ cpu_to_node(raw_smp_processor_id()), raw_smp_processor_id());
dd = kzalloc_node(sizeof(struct driver_data), GFP_KERNEL, my_node);
if (dd == NULL) {
@@ -4615,7 +4627,7 @@ static int mtip_pci_probe(struct pci_dev *pdev,
if (rv) {
dev_warn(&pdev->dev,
"Unable to enable MSI interrupt.\n");
- goto block_initialize_err;
+ goto msi_initialize_err;
}
/* Initialize the block layer. */
@@ -4645,6 +4657,8 @@ static int mtip_pci_probe(struct pci_dev *pdev,
block_initialize_err:
pci_disable_msi(pdev);
+
+msi_initialize_err:
if (dd->isr_workq) {
flush_workqueue(dd->isr_workq);
destroy_workqueue(dd->isr_workq);
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h
index b52e9a6d6aad..ffb955e7ccb9 100644
--- a/drivers/block/mtip32xx/mtip32xx.h
+++ b/drivers/block/mtip32xx/mtip32xx.h
@@ -53,7 +53,7 @@
#define MTIP_FTL_REBUILD_TIMEOUT_MS 2400000
/* unaligned IO handling */
-#define MTIP_MAX_UNALIGNED_SLOTS 8
+#define MTIP_MAX_UNALIGNED_SLOTS 2
/* Macro to extract the tag bit number from a tag value. */
#define MTIP_TAG_BIT(tag) (tag & 0x1F)
@@ -92,7 +92,7 @@
/* Driver name and version strings */
#define MTIP_DRV_NAME "mtip32xx"
-#define MTIP_DRV_VERSION "1.3.0"
+#define MTIP_DRV_VERSION "1.3.1"
/* Maximum number of minor device numbers per device. */
#define MTIP_MAX_MINORS 16
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index 51824d1f23ea..da085ff10d25 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -993,7 +993,7 @@ static void nvme_abort_cmd(int cmdid, struct nvme_queue *nvmeq)
dev_warn(&dev->pci_dev->dev,
"I/O %d QID %d timeout, reset controller\n", cmdid,
nvmeq->qid);
- PREPARE_WORK(&dev->reset_work, nvme_reset_failed_dev);
+ dev->reset_workfn = nvme_reset_failed_dev;
queue_work(nvme_workq, &dev->reset_work);
return;
}
@@ -1696,8 +1696,7 @@ static int nvme_kthread(void *data)
list_del_init(&dev->node);
dev_warn(&dev->pci_dev->dev,
"Failed status, reset controller\n");
- PREPARE_WORK(&dev->reset_work,
- nvme_reset_failed_dev);
+ dev->reset_workfn = nvme_reset_failed_dev;
queue_work(nvme_workq, &dev->reset_work);
continue;
}
@@ -1837,31 +1836,16 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
/* Deregister the admin queue's interrupt */
free_irq(dev->entry[0].vector, adminq);
- vecs = nr_io_queues;
- for (i = 0; i < vecs; i++)
+ for (i = 0; i < nr_io_queues; i++)
dev->entry[i].entry = i;
- for (;;) {
- result = pci_enable_msix(pdev, dev->entry, vecs);
- if (result <= 0)
- break;
- vecs = result;
- }
-
- if (result < 0) {
- vecs = nr_io_queues;
- if (vecs > 32)
- vecs = 32;
- for (;;) {
- result = pci_enable_msi_block(pdev, vecs);
- if (result == 0) {
- for (i = 0; i < vecs; i++)
- dev->entry[i].vector = i + pdev->irq;
- break;
- } else if (result < 0) {
- vecs = 1;
- break;
- }
- vecs = result;
+ 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;
}
}
@@ -2406,7 +2390,7 @@ static int nvme_dev_resume(struct nvme_dev *dev)
return ret;
if (ret == -EBUSY) {
spin_lock(&dev_list_lock);
- PREPARE_WORK(&dev->reset_work, nvme_remove_disks);
+ dev->reset_workfn = nvme_remove_disks;
queue_work(nvme_workq, &dev->reset_work);
spin_unlock(&dev_list_lock);
}
@@ -2435,6 +2419,12 @@ static void nvme_reset_failed_dev(struct work_struct *ws)
nvme_dev_reset(dev);
}
+static void nvme_reset_workfn(struct work_struct *work)
+{
+ struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work);
+ dev->reset_workfn(work);
+}
+
static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
int result = -ENOMEM;
@@ -2453,7 +2443,8 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto free;
INIT_LIST_HEAD(&dev->namespaces);
- INIT_WORK(&dev->reset_work, nvme_reset_failed_dev);
+ dev->reset_workfn = nvme_reset_failed_dev;
+ INIT_WORK(&dev->reset_work, nvme_reset_workfn);
dev->pci_dev = pdev;
pci_set_drvdata(pdev, dev);
result = nvme_set_instance(dev);
@@ -2553,7 +2544,7 @@ static int nvme_resume(struct device *dev)
struct nvme_dev *ndev = pci_get_drvdata(pdev);
if (nvme_dev_resume(ndev) && !work_busy(&ndev->reset_work)) {
- PREPARE_WORK(&ndev->reset_work, nvme_reset_failed_dev);
+ ndev->reset_workfn = nvme_reset_failed_dev;
queue_work(nvme_workq, &ndev->reset_work);
}
return 0;
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index b365e0dfccb6..34898d53395b 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -2109,7 +2109,6 @@ static void rbd_img_obj_callback(struct rbd_obj_request *obj_request)
rbd_assert(img_request->obj_request_count > 0);
rbd_assert(which != BAD_WHICH);
rbd_assert(which < img_request->obj_request_count);
- rbd_assert(which >= img_request->next_completion);
spin_lock_irq(&img_request->completion_lock);
if (which != img_request->next_completion)
diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c
index eb6e1e0e8db2..a69dd93d1bd5 100644
--- a/drivers/block/skd_main.c
+++ b/drivers/block/skd_main.c
@@ -3910,18 +3910,22 @@ static void skd_release_msix(struct skd_device *skdev)
struct skd_msix_entry *qentry;
int i;
- if (skdev->msix_entries == NULL)
- return;
- for (i = 0; i < skdev->msix_count; i++) {
- qentry = &skdev->msix_entries[i];
- skdev = qentry->rsp;
+ if (skdev->msix_entries) {
+ for (i = 0; i < skdev->msix_count; i++) {
+ qentry = &skdev->msix_entries[i];
+ skdev = qentry->rsp;
+
+ if (qentry->have_irq)
+ devm_free_irq(&skdev->pdev->dev,
+ qentry->vector, qentry->rsp);
+ }
- if (qentry->have_irq)
- devm_free_irq(&skdev->pdev->dev,
- qentry->vector, qentry->rsp);
+ kfree(skdev->msix_entries);
}
- pci_disable_msix(skdev->pdev);
- kfree(skdev->msix_entries);
+
+ if (skdev->msix_count)
+ pci_disable_msix(skdev->pdev);
+
skdev->msix_count = 0;
skdev->msix_entries = NULL;
}
@@ -3929,12 +3933,10 @@ static void skd_release_msix(struct skd_device *skdev)
static int skd_acquire_msix(struct skd_device *skdev)
{
int i, rc;
- struct pci_dev *pdev;
- struct msix_entry *entries = NULL;
+ struct pci_dev *pdev = skdev->pdev;
+ struct msix_entry *entries;
struct skd_msix_entry *qentry;
- pdev = skdev->pdev;
- skdev->msix_count = SKD_MAX_MSIX_COUNT;
entries = kzalloc(sizeof(struct msix_entry) * SKD_MAX_MSIX_COUNT,
GFP_KERNEL);
if (!entries)
@@ -3943,40 +3945,26 @@ static int skd_acquire_msix(struct skd_device *skdev)
for (i = 0; i < SKD_MAX_MSIX_COUNT; i++)
entries[i].entry = i;
- rc = pci_enable_msix(pdev, entries, SKD_MAX_MSIX_COUNT);
- if (rc < 0)
+ rc = pci_enable_msix_range(pdev, entries,
+ SKD_MIN_MSIX_COUNT, SKD_MAX_MSIX_COUNT);
+ if (rc < 0) {
+ pr_err("(%s): failed to enable MSI-X %d\n",
+ skd_name(skdev), rc);
goto msix_out;
- if (rc) {
- if (rc < SKD_MIN_MSIX_COUNT) {
- pr_err("(%s): failed to enable MSI-X %d\n",
- skd_name(skdev), rc);
- goto msix_out;
- }
- pr_debug("%s:%s:%d %s: <%s> allocated %d MSI-X vectors\n",
- skdev->name, __func__, __LINE__,
- pci_name(pdev), skdev->name, rc);
-
- skdev->msix_count = rc;
- rc = pci_enable_msix(pdev, entries, skdev->msix_count);
- if (rc) {
- pr_err("(%s): failed to enable MSI-X "
- "support (%d) %d\n",
- skd_name(skdev), skdev->msix_count, rc);
- goto msix_out;
- }
}
+
+ skdev->msix_count = rc;
skdev->msix_entries = kzalloc(sizeof(struct skd_msix_entry) *
skdev->msix_count, GFP_KERNEL);
if (!skdev->msix_entries) {
rc = -ENOMEM;
- skdev->msix_count = 0;
pr_err("(%s): msix table allocation error\n",
skd_name(skdev));
goto msix_out;
}
- qentry = skdev->msix_entries;
for (i = 0; i < skdev->msix_count; i++) {
+ qentry = &skdev->msix_entries[i];
qentry->vector = entries[i].vector;
qentry->entry = entries[i].entry;
qentry->rsp = NULL;
@@ -3985,11 +3973,10 @@ static int skd_acquire_msix(struct skd_device *skdev)
skdev->name, __func__, __LINE__,
pci_name(pdev), skdev->name,
i, qentry->vector, qentry->entry);
- qentry++;
}
/* Enable MSI-X vectors for the base queue */
- for (i = 0; i < SKD_MAX_MSIX_COUNT; i++) {
+ for (i = 0; i < skdev->msix_count; i++) {
qentry = &skdev->msix_entries[i];
snprintf(qentry->isr_name, sizeof(qentry->isr_name),
"%s%d-msix %s", DRV_NAME, skdev->devno,
@@ -4045,8 +4032,8 @@ RETRY_IRQ_TYPE:
case SKD_IRQ_MSI:
snprintf(skdev->isr_name, sizeof(skdev->isr_name), "%s%d-msi",
DRV_NAME, skdev->devno);
- rc = pci_enable_msi(pdev);
- if (!rc) {
+ rc = pci_enable_msi_range(pdev, 1, 1);
+ if (rc > 0) {
rc = devm_request_irq(&pdev->dev, pdev->irq, skd_isr, 0,
skdev->isr_name, skdev);
if (rc) {
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 20e061c3e023..c74f7b56e7c4 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -30,6 +30,7 @@
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/wait.h>
#include <asm/io.h>
#include <asm/dbdma.h>
#include <asm/prom.h>
@@ -840,14 +841,17 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
spin_lock_irqsave(&swim3_lock, flags);
if (fs->state != idle && fs->state != available) {
++fs->wanted;
- while (fs->state != available) {
+ /* this will enable irqs in order to sleep */
+ if (!interruptible)
+ wait_event_lock_irq(fs->wait,
+ fs->state == available,
+ swim3_lock);
+ else if (wait_event_interruptible_lock_irq(fs->wait,
+ fs->state == available,
+ swim3_lock)) {
+ --fs->wanted;
spin_unlock_irqrestore(&swim3_lock, flags);
- if (interruptible && signal_pending(current)) {
- --fs->wanted;
- return -EINTR;
- }
- interruptible_sleep_on(&fs->wait);
- spin_lock_irqsave(&swim3_lock, flags);
+ return -EINTR;
}
--fs->wanted;
}
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index b1cb3f4c4db4..6d8a87f252de 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -158,6 +158,7 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req)
unsigned long flags;
unsigned int num;
const bool last = (req->cmd_flags & REQ_END) != 0;
+ int err;
BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);
@@ -198,11 +199,16 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req)
}
spin_lock_irqsave(&vblk->vq_lock, flags);
- if (__virtblk_add_req(vblk->vq, vbr, vbr->sg, num) < 0) {
+ err = __virtblk_add_req(vblk->vq, vbr, vbr->sg, num);
+ if (err) {
virtqueue_kick(vblk->vq);
spin_unlock_irqrestore(&vblk->vq_lock, flags);
blk_mq_stop_hw_queue(hctx);
- return BLK_MQ_RQ_QUEUE_BUSY;
+ /* Out of mem doesn't actually happen, since we fall back
+ * to direct descriptors */
+ if (err == -ENOMEM || err == -ENOSPC)
+ return BLK_MQ_RQ_QUEUE_BUSY;
+ return BLK_MQ_RQ_QUEUE_ERROR;
}
if (last)
@@ -485,18 +491,20 @@ static struct blk_mq_ops virtio_mq_ops = {
static struct blk_mq_reg virtio_mq_reg = {
.ops = &virtio_mq_ops,
.nr_hw_queues = 1,
- .queue_depth = 64,
+ .queue_depth = 0, /* Set in virtblk_probe */
.numa_node = NUMA_NO_NODE,
.flags = BLK_MQ_F_SHOULD_MERGE,
};
+module_param_named(queue_depth, virtio_mq_reg.queue_depth, uint, 0444);
-static void virtblk_init_vbr(void *data, struct blk_mq_hw_ctx *hctx,
+static int virtblk_init_vbr(void *data, struct blk_mq_hw_ctx *hctx,
struct request *rq, unsigned int nr)
{
struct virtio_blk *vblk = data;
struct virtblk_req *vbr = rq->special;
sg_init_table(vbr->sg, vblk->sg_elems);
+ return 0;
}
static int virtblk_probe(struct virtio_device *vdev)
@@ -552,6 +560,13 @@ static int virtblk_probe(struct virtio_device *vdev)
goto out_free_vq;
}
+ /* Default queue sizing is to fill the ring. */
+ if (!virtio_mq_reg.queue_depth) {
+ virtio_mq_reg.queue_depth = vblk->vq->num_free;
+ /* ... but without indirect descs, we use 2 descs per req */
+ if (!virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC))
+ virtio_mq_reg.queue_depth /= 2;
+ }
virtio_mq_reg.cmd_size =
sizeof(struct virtblk_req) +
sizeof(struct scatterlist) * sg_elems;
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 011e55d820b1..51c557cfd92b 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -612,6 +612,8 @@ static ssize_t disksize_store(struct device *dev,
disksize = PAGE_ALIGN(disksize);
meta = zram_meta_alloc(disksize);
+ if (!meta)
+ return -ENOMEM;
down_write(&zram->init_lock);
if (zram->init_done) {
up_write(&zram->init_lock);
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 725c46162bbd..2ac754e18bcf 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -870,14 +870,14 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np,
ret = of_property_read_u32_array(np, "pcie-mem-aperture", reg, ARRAY_SIZE(reg));
if (!ret) {
mem->start = reg[0];
- mem->end = mem->start + reg[1];
+ mem->end = mem->start + reg[1] - 1;
mem->flags = IORESOURCE_MEM;
}
ret = of_property_read_u32_array(np, "pcie-io-aperture", reg, ARRAY_SIZE(reg));
if (!ret) {
io->start = reg[0];
- io->end = io->start + reg[1];
+ io->end = io->start + reg[1] - 1;
io->flags = IORESOURCE_IO;
}
}
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index 1b192395a90c..8121b4c70ede 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -31,7 +31,6 @@
#include <linux/module.h>
#include <linux/mman.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/agp_backend.h>
#include <linux/agpgart.h>
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index f39437addb58..0fbccce1cee9 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -29,7 +29,6 @@
*/
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/pagemap.h>
#include <linux/miscdevice.h>
#include <linux/pm.h>
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 5c85350f4c3d..9a024f899dd4 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pagemap.h>
#include <linux/agp_backend.h>
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index 05b8d0241bde..3051c73bc383 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/init.h>
#include <linux/agp_backend.h>
#include <asm/sn/addrs.h>
#include <asm/sn/io.h>
diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c
index 43577ca780e3..8c3b255e629a 100644
--- a/drivers/char/hw_random/bcm2835-rng.c
+++ b/drivers/char/hw_random/bcm2835-rng.c
@@ -8,7 +8,6 @@
*/
#include <linux/hw_random.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index a0f7724852eb..b9495a8c05c6 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -37,7 +37,6 @@
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/sched.h>
-#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/slab.h>
diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c
index 402ccfb625c5..9f8277cc44b4 100644
--- a/drivers/char/hw_random/exynos-rng.c
+++ b/drivers/char/hw_random/exynos-rng.c
@@ -22,7 +22,6 @@
#include <linux/hw_random.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
index f9beed54d0c8..432232eefe05 100644
--- a/drivers/char/hw_random/n2-drv.c
+++ b/drivers/char/hw_random/n2-drv.c
@@ -7,7 +7,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/preempt.h>
diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c
index 232b87fb5fc9..00e9d2d46634 100644
--- a/drivers/char/hw_random/nomadik-rng.c
+++ b/drivers/char/hw_random/nomadik-rng.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/device.h>
#include <linux/amba/bus.h>
#include <linux/hw_random.h>
diff --git a/drivers/char/hw_random/octeon-rng.c b/drivers/char/hw_random/octeon-rng.c
index f2885dbe1849..b5cc3420c659 100644
--- a/drivers/char/hw_random/octeon-rng.c
+++ b/drivers/char/hw_random/octeon-rng.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/hw_random.h>
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index c12398d1517c..2ce0e225e58c 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -47,8 +47,7 @@ static void register_buffer(u8 *buf, size_t size)
sg_init_one(&sg, buf, size);
/* There should always be room for one buffer. */
- if (virtqueue_add_inbuf(vq, &sg, 1, buf, GFP_KERNEL) < 0)
- BUG();
+ virtqueue_add_inbuf(vq, &sg, 1, buf, GFP_KERNEL);
virtqueue_kick(vq);
}
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 03f41896d090..b7efd3c1a882 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -61,7 +61,6 @@
#include <linux/ipmi_smi.h>
#include <asm/io.h>
#include "ipmi_si_sm.h"
-#include <linux/init.h>
#include <linux/dmi.h>
#include <linux/string.h>
#include <linux/ctype.h>
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 92c5937f80c3..917403fe10da 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -99,6 +99,9 @@ static ssize_t read_mem(struct file *file, char __user *buf,
ssize_t read, sz;
char *ptr;
+ if (p != *ppos)
+ return 0;
+
if (!valid_phys_addr_range(p, count))
return -EFAULT;
read = 0;
@@ -157,6 +160,9 @@ static ssize_t write_mem(struct file *file, const char __user *buf,
unsigned long copied;
void *ptr;
+ if (p != *ppos)
+ return -EFBIG;
+
if (!valid_phys_addr_range(p, count))
return -EFAULT;
diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c
index 881c9e595939..28740046bc83 100644
--- a/drivers/char/mwave/3780i.c
+++ b/drivers/char/mwave/3780i.c
@@ -50,7 +50,6 @@
#include <linux/unistd.h>
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/sched.h> /* cond_resched() */
diff --git a/drivers/char/tile-srom.c b/drivers/char/tile-srom.c
index 0e506bad1986..bd377472dcfb 100644
--- a/drivers/char/tile-srom.c
+++ b/drivers/char/tile-srom.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/init.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
index 52b9b2b2f300..472af4bb1b61 100644
--- a/drivers/char/tpm/tpm_i2c_infineon.c
+++ b/drivers/char/tpm/tpm_i2c_infineon.c
@@ -21,7 +21,6 @@
*
*
*/
-#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/wait.h>
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index 5b0dd8ef74c0..3b7bf2162898 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -38,7 +38,6 @@
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/wait.h>
#include <linux/string.h>
#include <linux/interrupt.h>
diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
index bd313f7816a8..c1af80bcdf20 100644
--- a/drivers/clk/at91/clk-master.c
+++ b/drivers/clk/at91/clk-master.c
@@ -242,7 +242,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
irq = irq_of_parse_and_map(np, 0);
if (!irq)
- return;
+ goto out_free_characteristics;
clk = at91_clk_register_master(pmc, irq, name, num_parents,
parent_names, layout,
diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c
index 6a934a5296bd..05e04ce0f148 100644
--- a/drivers/clk/clk-nomadik.c
+++ b/drivers/clk/clk-nomadik.c
@@ -494,6 +494,9 @@ static const struct file_operations nomadik_src_clk_debugfs_ops = {
static int __init nomadik_src_clk_init_debugfs(void)
{
+ /* Vital for multiplatform */
+ if (!src_base)
+ return -ENODEV;
src_pcksr0_boot = readl(src_base + SRC_PCKSR0);
src_pcksr1_boot = readl(src_base + SRC_PCKSR1);
debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO,
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 5517944495d8..c42e608af6bb 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2226,24 +2226,25 @@ EXPORT_SYMBOL_GPL(devm_clk_unregister);
*/
int __clk_get(struct clk *clk)
{
- if (clk && !try_module_get(clk->owner))
- return 0;
+ if (clk) {
+ if (!try_module_get(clk->owner))
+ return 0;
- kref_get(&clk->ref);
+ kref_get(&clk->ref);
+ }
return 1;
}
void __clk_put(struct clk *clk)
{
- if (WARN_ON_ONCE(IS_ERR(clk)))
+ if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
return;
clk_prepare_lock();
kref_put(&clk->ref, __clk_release);
clk_prepare_unlock();
- if (clk)
- module_put(clk->owner);
+ module_put(clk->owner);
}
/*** clk rate change notifiers ***/
diff --git a/drivers/clk/keystone/gate.c b/drivers/clk/keystone/gate.c
index 17a598398a53..86f1e362eafb 100644
--- a/drivers/clk/keystone/gate.c
+++ b/drivers/clk/keystone/gate.c
@@ -179,6 +179,7 @@ static struct clk *clk_register_psc(struct device *dev,
init.name = name;
init.ops = &clk_psc_ops;
+ init.flags = 0;
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c
index 81a202d12a7a..bef198a83863 100644
--- a/drivers/clk/mvebu/armada-370.c
+++ b/drivers/clk/mvebu/armada-370.c
@@ -141,13 +141,6 @@ static const struct coreclk_soc_desc a370_coreclks = {
.num_ratios = ARRAY_SIZE(a370_coreclk_ratios),
};
-static void __init a370_coreclk_init(struct device_node *np)
-{
- mvebu_coreclk_setup(np, &a370_coreclks);
-}
-CLK_OF_DECLARE(a370_core_clk, "marvell,armada-370-core-clock",
- a370_coreclk_init);
-
/*
* Clock Gating Control
*/
@@ -168,9 +161,15 @@ static const struct clk_gating_soc_desc a370_gating_desc[] __initconst = {
{ }
};
-static void __init a370_clk_gating_init(struct device_node *np)
+static void __init a370_clk_init(struct device_node *np)
{
- mvebu_clk_gating_setup(np, a370_gating_desc);
+ struct device_node *cgnp =
+ of_find_compatible_node(NULL, NULL, "marvell,armada-370-gating-clock");
+
+ mvebu_coreclk_setup(np, &a370_coreclks);
+
+ if (cgnp)
+ mvebu_clk_gating_setup(cgnp, a370_gating_desc);
}
-CLK_OF_DECLARE(a370_clk_gating, "marvell,armada-370-gating-clock",
- a370_clk_gating_init);
+CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init);
+
diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c
index 9922c4475aa8..b3094315a3c0 100644
--- a/drivers/clk/mvebu/armada-xp.c
+++ b/drivers/clk/mvebu/armada-xp.c
@@ -158,13 +158,6 @@ static const struct coreclk_soc_desc axp_coreclks = {
.num_ratios = ARRAY_SIZE(axp_coreclk_ratios),
};
-static void __init axp_coreclk_init(struct device_node *np)
-{
- mvebu_coreclk_setup(np, &axp_coreclks);
-}
-CLK_OF_DECLARE(axp_core_clk, "marvell,armada-xp-core-clock",
- axp_coreclk_init);
-
/*
* Clock Gating Control
*/
@@ -202,9 +195,14 @@ static const struct clk_gating_soc_desc axp_gating_desc[] __initconst = {
{ }
};
-static void __init axp_clk_gating_init(struct device_node *np)
+static void __init axp_clk_init(struct device_node *np)
{
- mvebu_clk_gating_setup(np, axp_gating_desc);
+ struct device_node *cgnp =
+ of_find_compatible_node(NULL, NULL, "marvell,armada-xp-gating-clock");
+
+ mvebu_coreclk_setup(np, &axp_coreclks);
+
+ if (cgnp)
+ mvebu_clk_gating_setup(cgnp, axp_gating_desc);
}
-CLK_OF_DECLARE(axp_clk_gating, "marvell,armada-xp-gating-clock",
- axp_clk_gating_init);
+CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init);
diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c
index 38aee1e3f242..b8c2424ac926 100644
--- a/drivers/clk/mvebu/dove.c
+++ b/drivers/clk/mvebu/dove.c
@@ -154,12 +154,6 @@ static const struct coreclk_soc_desc dove_coreclks = {
.num_ratios = ARRAY_SIZE(dove_coreclk_ratios),
};
-static void __init dove_coreclk_init(struct device_node *np)
-{
- mvebu_coreclk_setup(np, &dove_coreclks);
-}
-CLK_OF_DECLARE(dove_core_clk, "marvell,dove-core-clock", dove_coreclk_init);
-
/*
* Clock Gating Control
*/
@@ -186,9 +180,14 @@ static const struct clk_gating_soc_desc dove_gating_desc[] __initconst = {
{ }
};
-static void __init dove_clk_gating_init(struct device_node *np)
+static void __init dove_clk_init(struct device_node *np)
{
- mvebu_clk_gating_setup(np, dove_gating_desc);
+ struct device_node *cgnp =
+ of_find_compatible_node(NULL, NULL, "marvell,dove-gating-clock");
+
+ mvebu_coreclk_setup(np, &dove_coreclks);
+
+ if (cgnp)
+ mvebu_clk_gating_setup(cgnp, dove_gating_desc);
}
-CLK_OF_DECLARE(dove_clk_gating, "marvell,dove-gating-clock",
- dove_clk_gating_init);
+CLK_OF_DECLARE(dove_clk, "marvell,dove-core-clock", dove_clk_init);
diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c
index 2636a55f29f9..ddb666a86500 100644
--- a/drivers/clk/mvebu/kirkwood.c
+++ b/drivers/clk/mvebu/kirkwood.c
@@ -193,13 +193,6 @@ static const struct coreclk_soc_desc kirkwood_coreclks = {
.num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
};
-static void __init kirkwood_coreclk_init(struct device_node *np)
-{
- mvebu_coreclk_setup(np, &kirkwood_coreclks);
-}
-CLK_OF_DECLARE(kirkwood_core_clk, "marvell,kirkwood-core-clock",
- kirkwood_coreclk_init);
-
static const struct coreclk_soc_desc mv88f6180_coreclks = {
.get_tclk_freq = kirkwood_get_tclk_freq,
.get_cpu_freq = mv88f6180_get_cpu_freq,
@@ -208,13 +201,6 @@ static const struct coreclk_soc_desc mv88f6180_coreclks = {
.num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
};
-static void __init mv88f6180_coreclk_init(struct device_node *np)
-{
- mvebu_coreclk_setup(np, &mv88f6180_coreclks);
-}
-CLK_OF_DECLARE(mv88f6180_core_clk, "marvell,mv88f6180-core-clock",
- mv88f6180_coreclk_init);
-
/*
* Clock Gating Control
*/
@@ -239,9 +225,21 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = {
{ }
};
-static void __init kirkwood_clk_gating_init(struct device_node *np)
+static void __init kirkwood_clk_init(struct device_node *np)
{
- mvebu_clk_gating_setup(np, kirkwood_gating_desc);
+ struct device_node *cgnp =
+ of_find_compatible_node(NULL, NULL, "marvell,kirkwood-gating-clock");
+
+
+ if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock"))
+ mvebu_coreclk_setup(np, &mv88f6180_coreclks);
+ else
+ mvebu_coreclk_setup(np, &kirkwood_coreclks);
+
+ if (cgnp)
+ mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc);
}
-CLK_OF_DECLARE(kirkwood_clk_gating, "marvell,kirkwood-gating-clock",
- kirkwood_clk_gating_init);
+CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
+ kirkwood_clk_init);
+CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock",
+ kirkwood_clk_init);
diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c
index a59ec217a124..99c27b1c625b 100644
--- a/drivers/clk/shmobile/clk-rcar-gen2.c
+++ b/drivers/clk/shmobile/clk-rcar-gen2.c
@@ -26,6 +26,8 @@ struct rcar_gen2_cpg {
void __iomem *reg;
};
+#define CPG_FRQCRB 0x00000004
+#define CPG_FRQCRB_KICK BIT(31)
#define CPG_SDCKCR 0x00000074
#define CPG_PLL0CR 0x000000d8
#define CPG_FRQCRC 0x000000e0
@@ -45,6 +47,7 @@ struct rcar_gen2_cpg {
struct cpg_z_clk {
struct clk_hw hw;
void __iomem *reg;
+ void __iomem *kick_reg;
};
#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw)
@@ -83,17 +86,45 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct cpg_z_clk *zclk = to_z_clk(hw);
unsigned int mult;
- u32 val;
+ u32 val, kick;
+ unsigned int i;
mult = div_u64((u64)rate * 32, parent_rate);
mult = clamp(mult, 1U, 32U);
+ if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
+ return -EBUSY;
+
val = clk_readl(zclk->reg);
val &= ~CPG_FRQCRC_ZFC_MASK;
val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT;
clk_writel(val, zclk->reg);
- return 0;
+ /*
+ * Set KICK bit in FRQCRB to update hardware setting and wait for
+ * clock change completion.
+ */
+ kick = clk_readl(zclk->kick_reg);
+ kick |= CPG_FRQCRB_KICK;
+ clk_writel(kick, zclk->kick_reg);
+
+ /*
+ * Note: There is no HW information about the worst case latency.
+ *
+ * Using experimental measurements, it seems that no more than
+ * ~10 iterations are needed, independently of the CPU rate.
+ * Since this value might be dependant of external xtal rate, pll1
+ * rate or even the other emulation clocks rate, use 1000 as a
+ * "super" safe value.
+ */
+ for (i = 1000; i; i--) {
+ if (!(clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK))
+ return 0;
+
+ cpu_relax();
+ }
+
+ return -ETIMEDOUT;
}
static const struct clk_ops cpg_z_clk_ops = {
@@ -120,6 +151,7 @@ static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
init.num_parents = 1;
zclk->reg = cpg->reg + CPG_FRQCRC;
+ zclk->kick_reg = cpg->reg + CPG_FRQCRB;
zclk->hw.init = &init;
clk = clk_register(NULL, &zclk->hw);
@@ -186,7 +218,7 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
const char *name)
{
const struct clk_div_table *table = NULL;
- const char *parent_name = "main";
+ const char *parent_name;
unsigned int shift;
unsigned int mult = 1;
unsigned int div = 1;
@@ -201,23 +233,31 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
* the multiplier value.
*/
u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+ parent_name = "main";
mult = ((value >> 24) & ((1 << 7) - 1)) + 1;
} else if (!strcmp(name, "pll1")) {
+ parent_name = "main";
mult = config->pll1_mult / 2;
} else if (!strcmp(name, "pll3")) {
+ parent_name = "main";
mult = config->pll3_mult;
} else if (!strcmp(name, "lb")) {
+ parent_name = "pll1_div2";
div = cpg_mode & BIT(18) ? 36 : 24;
} else if (!strcmp(name, "qspi")) {
+ parent_name = "pll1_div2";
div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2)
- ? 16 : 20;
+ ? 8 : 10;
} else if (!strcmp(name, "sdh")) {
+ parent_name = "pll1_div2";
table = cpg_sdh_div_table;
shift = 8;
} else if (!strcmp(name, "sd0")) {
+ parent_name = "pll1_div2";
table = cpg_sd01_div_table;
shift = 4;
} else if (!strcmp(name, "sd1")) {
+ parent_name = "pll1_div2";
table = cpg_sd01_div_table;
shift = 0;
} else if (!strcmp(name, "z")) {
diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
index 4d75b1f37e3a..290f9c1a3749 100644
--- a/drivers/clk/tegra/clk-divider.c
+++ b/drivers/clk/tegra/clk-divider.c
@@ -59,7 +59,7 @@ static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate,
return 0;
if (divider_ux1 > get_max_div(divider))
- return -EINVAL;
+ return get_max_div(divider);
return divider_ux1;
}
diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index cf0c323f2c36..c39613c519af 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -180,9 +180,13 @@ enum clk_id {
tegra_clk_sbc6_8,
tegra_clk_sclk,
tegra_clk_sdmmc1,
+ tegra_clk_sdmmc1_8,
tegra_clk_sdmmc2,
+ tegra_clk_sdmmc2_8,
tegra_clk_sdmmc3,
+ tegra_clk_sdmmc3_8,
tegra_clk_sdmmc4,
+ tegra_clk_sdmmc4_8,
tegra_clk_se,
tegra_clk_soc_therm,
tegra_clk_sor0,
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index 5c35885f4a7c..1fa5c3f33b20 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -371,9 +371,7 @@ static const char *mux_pllp3_pllc_clkm[] = {
static const char *mux_pllm_pllc_pllp_plla_pllc2_c3_clkm[] = {
"pll_m", "pll_c", "pll_p", "pll_a", "pll_c2", "pll_c3", "clk_m"
};
-static u32 mux_pllm_pllc_pllp_plla_pllc2_c3_clkm_idx[] = {
- [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6,
-};
+#define mux_pllm_pllc_pllp_plla_pllc2_c3_clkm_idx NULL
static const char *mux_pllm_pllc2_c_c3_pllp_plla_pllc4[] = {
"pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0", "pll_c4",
@@ -465,6 +463,10 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1),
MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1),
MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2),
+ MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, 0, tegra_clk_sdmmc1_8),
+ MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, 0, tegra_clk_sdmmc2_8),
+ MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, 0, tegra_clk_sdmmc3_8),
+ MUX8("sdmmc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC4, 15, 0, tegra_clk_sdmmc4_8),
MUX8("sbc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_8),
MUX8("sbc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_8),
MUX8("sbc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_8),
@@ -492,7 +494,7 @@ static struct tegra_periph_init_data periph_clks[] = {
UART("uartb", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, tegra_clk_uartb),
UART("uartc", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, tegra_clk_uartc),
UART("uartd", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, tegra_clk_uartd),
- UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 65, tegra_clk_uarte),
+ UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 66, tegra_clk_uarte),
XUSB("xusb_host_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src),
XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src),
XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src),
diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c
index 05dce4aa2c11..feb3201c85ce 100644
--- a/drivers/clk/tegra/clk-tegra-super-gen4.c
+++ b/drivers/clk/tegra/clk-tegra-super-gen4.c
@@ -120,7 +120,7 @@ void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
ARRAY_SIZE(cclk_lp_parents),
CLK_SET_RATE_PARENT,
clk_base + CCLKLP_BURST_POLICY,
- 0, 4, 8, 9, NULL);
+ TEGRA_DIVIDER_2, 4, 8, 9, NULL);
*dt_clk = clk;
}
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 90d9d25f2228..80431f0fb268 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -682,12 +682,12 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
[tegra_clk_timer] = { .dt_id = TEGRA114_CLK_TIMER, .present = true },
[tegra_clk_uarta] = { .dt_id = TEGRA114_CLK_UARTA, .present = true },
[tegra_clk_uartd] = { .dt_id = TEGRA114_CLK_UARTD, .present = true },
- [tegra_clk_sdmmc2] = { .dt_id = TEGRA114_CLK_SDMMC2, .present = true },
+ [tegra_clk_sdmmc2_8] = { .dt_id = TEGRA114_CLK_SDMMC2, .present = true },
[tegra_clk_i2s1] = { .dt_id = TEGRA114_CLK_I2S1, .present = true },
[tegra_clk_i2c1] = { .dt_id = TEGRA114_CLK_I2C1, .present = true },
[tegra_clk_ndflash] = { .dt_id = TEGRA114_CLK_NDFLASH, .present = true },
- [tegra_clk_sdmmc1] = { .dt_id = TEGRA114_CLK_SDMMC1, .present = true },
- [tegra_clk_sdmmc4] = { .dt_id = TEGRA114_CLK_SDMMC4, .present = true },
+ [tegra_clk_sdmmc1_8] = { .dt_id = TEGRA114_CLK_SDMMC1, .present = true },
+ [tegra_clk_sdmmc4_8] = { .dt_id = TEGRA114_CLK_SDMMC4, .present = true },
[tegra_clk_pwm] = { .dt_id = TEGRA114_CLK_PWM, .present = true },
[tegra_clk_i2s0] = { .dt_id = TEGRA114_CLK_I2S0, .present = true },
[tegra_clk_i2s2] = { .dt_id = TEGRA114_CLK_I2S2, .present = true },
@@ -723,7 +723,7 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
[tegra_clk_bsev] = { .dt_id = TEGRA114_CLK_BSEV, .present = true },
[tegra_clk_i2c3] = { .dt_id = TEGRA114_CLK_I2C3, .present = true },
[tegra_clk_sbc4_8] = { .dt_id = TEGRA114_CLK_SBC4, .present = true },
- [tegra_clk_sdmmc3] = { .dt_id = TEGRA114_CLK_SDMMC3, .present = true },
+ [tegra_clk_sdmmc3_8] = { .dt_id = TEGRA114_CLK_SDMMC3, .present = true },
[tegra_clk_owr] = { .dt_id = TEGRA114_CLK_OWR, .present = true },
[tegra_clk_csite] = { .dt_id = TEGRA114_CLK_CSITE, .present = true },
[tegra_clk_la] = { .dt_id = TEGRA114_CLK_LA, .present = true },
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index aff86b5bc745..166e02f16c8a 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -516,11 +516,11 @@ static struct div_nmp pllp_nmp = {
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
- {12000000, 216000000, 432, 12, 1, 8},
- {13000000, 216000000, 432, 13, 1, 8},
- {16800000, 216000000, 360, 14, 1, 8},
- {19200000, 216000000, 360, 16, 1, 8},
- {26000000, 216000000, 432, 26, 1, 8},
+ {12000000, 408000000, 408, 12, 0, 8},
+ {13000000, 408000000, 408, 13, 0, 8},
+ {16800000, 408000000, 340, 14, 0, 8},
+ {19200000, 408000000, 340, 16, 0, 8},
+ {26000000, 408000000, 408, 26, 0, 8},
{0, 0, 0, 0, 0, 0},
};
@@ -570,6 +570,15 @@ static struct tegra_clk_pll_params pll_a_params = {
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
};
+static struct div_nmp plld_nmp = {
+ .divm_shift = 0,
+ .divm_width = 5,
+ .divn_shift = 8,
+ .divn_width = 11,
+ .divp_shift = 20,
+ .divp_width = 3,
+};
+
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
{12000000, 216000000, 864, 12, 4, 12},
{13000000, 216000000, 864, 13, 4, 12},
@@ -603,19 +612,18 @@ static struct tegra_clk_pll_params pll_d_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
- .div_nmp = &pllp_nmp,
+ .div_nmp = &plld_nmp,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
TEGRA_PLL_USE_LOCK,
};
static struct tegra_clk_pll_freq_table tegra124_pll_d2_freq_table[] = {
- { 12000000, 148500000, 99, 1, 8},
- { 12000000, 594000000, 99, 1, 1},
- { 13000000, 594000000, 91, 1, 1}, /* actual: 591.5 MHz */
- { 16800000, 594000000, 71, 1, 1}, /* actual: 596.4 MHz */
- { 19200000, 594000000, 62, 1, 1}, /* actual: 595.2 MHz */
- { 26000000, 594000000, 91, 2, 1}, /* actual: 591.5 MHz */
+ { 12000000, 594000000, 99, 1, 2},
+ { 13000000, 594000000, 91, 1, 2}, /* actual: 591.5 MHz */
+ { 16800000, 594000000, 71, 1, 2}, /* actual: 596.4 MHz */
+ { 19200000, 594000000, 62, 1, 2}, /* actual: 595.2 MHz */
+ { 26000000, 594000000, 91, 2, 2}, /* actual: 591.5 MHz */
{ 0, 0, 0, 0, 0, 0 },
};
@@ -753,21 +761,19 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
[tegra_clk_rtc] = { .dt_id = TEGRA124_CLK_RTC, .present = true },
[tegra_clk_timer] = { .dt_id = TEGRA124_CLK_TIMER, .present = true },
[tegra_clk_uarta] = { .dt_id = TEGRA124_CLK_UARTA, .present = true },
- [tegra_clk_sdmmc2] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true },
+ [tegra_clk_sdmmc2_8] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true },
[tegra_clk_i2s1] = { .dt_id = TEGRA124_CLK_I2S1, .present = true },
[tegra_clk_i2c1] = { .dt_id = TEGRA124_CLK_I2C1, .present = true },
[tegra_clk_ndflash] = { .dt_id = TEGRA124_CLK_NDFLASH, .present = true },
- [tegra_clk_sdmmc1] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true },
- [tegra_clk_sdmmc4] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true },
+ [tegra_clk_sdmmc1_8] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true },
+ [tegra_clk_sdmmc4_8] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true },
[tegra_clk_pwm] = { .dt_id = TEGRA124_CLK_PWM, .present = true },
[tegra_clk_i2s2] = { .dt_id = TEGRA124_CLK_I2S2, .present = true },
- [tegra_clk_gr2d] = { .dt_id = TEGRA124_CLK_GR_2D, .present = true },
[tegra_clk_usbd] = { .dt_id = TEGRA124_CLK_USBD, .present = true },
[tegra_clk_isp_8] = { .dt_id = TEGRA124_CLK_ISP, .present = true },
- [tegra_clk_gr3d] = { .dt_id = TEGRA124_CLK_GR_3D, .present = true },
[tegra_clk_disp2] = { .dt_id = TEGRA124_CLK_DISP2, .present = true },
[tegra_clk_disp1] = { .dt_id = TEGRA124_CLK_DISP1, .present = true },
- [tegra_clk_host1x] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true },
+ [tegra_clk_host1x_8] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true },
[tegra_clk_vcp] = { .dt_id = TEGRA124_CLK_VCP, .present = true },
[tegra_clk_i2s0] = { .dt_id = TEGRA124_CLK_I2S0, .present = true },
[tegra_clk_apbdma] = { .dt_id = TEGRA124_CLK_APBDMA, .present = true },
@@ -794,7 +800,7 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
[tegra_clk_uartd] = { .dt_id = TEGRA124_CLK_UARTD, .present = true },
[tegra_clk_i2c3] = { .dt_id = TEGRA124_CLK_I2C3, .present = true },
[tegra_clk_sbc4] = { .dt_id = TEGRA124_CLK_SBC4, .present = true },
- [tegra_clk_sdmmc3] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true },
+ [tegra_clk_sdmmc3_8] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true },
[tegra_clk_pcie] = { .dt_id = TEGRA124_CLK_PCIE, .present = true },
[tegra_clk_owr] = { .dt_id = TEGRA124_CLK_OWR, .present = true },
[tegra_clk_afi] = { .dt_id = TEGRA124_CLK_AFI, .present = true },
@@ -1286,9 +1292,9 @@ static void __init tegra124_pll_init(void __iomem *clk_base,
clk_register_clkdev(clk, "pll_d2", NULL);
clks[TEGRA124_CLK_PLL_D2] = clk;
- /* PLLD2_OUT0 ?? */
+ /* PLLD2_OUT0 */
clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2",
- CLK_SET_RATE_PARENT, 1, 2);
+ CLK_SET_RATE_PARENT, 1, 1);
clk_register_clkdev(clk, "pll_d2_out0", NULL);
clks[TEGRA124_CLK_PLL_D2_OUT0] = clk;
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index dbace152b2fa..dace2b1b5ae6 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -574,6 +574,8 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = {
[tegra_clk_tvdac] = { .dt_id = TEGRA20_CLK_TVDAC, .present = true },
[tegra_clk_vi_sensor] = { .dt_id = TEGRA20_CLK_VI_SENSOR, .present = true },
[tegra_clk_afi] = { .dt_id = TEGRA20_CLK_AFI, .present = true },
+ [tegra_clk_fuse] = { .dt_id = TEGRA20_CLK_FUSE, .present = true },
+ [tegra_clk_kfuse] = { .dt_id = TEGRA20_CLK_KFUSE, .present = true },
};
static unsigned long tegra20_clk_measure_input_freq(void)
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index cd6950fd8caf..52e9329e3c51 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -140,3 +140,51 @@ config VF_PIT_TIMER
bool
help
Support for Period Interrupt Timer on Freescale Vybrid Family SoCs.
+
+config SYS_SUPPORTS_SH_CMT
+ bool
+
+config SYS_SUPPORTS_SH_MTU2
+ bool
+
+config SYS_SUPPORTS_SH_TMU
+ bool
+
+config SYS_SUPPORTS_EM_STI
+ bool
+
+config SH_TIMER_CMT
+ bool "Renesas CMT timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ default SYS_SUPPORTS_SH_CMT
+ help
+ This enables build of a clocksource and clockevent driver for
+ the Compare Match Timer (CMT) hardware available in 16/32/48-bit
+ variants on a wide range of Mobile and Automotive SoCs from Renesas.
+
+config SH_TIMER_MTU2
+ bool "Renesas MTU2 timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ default SYS_SUPPORTS_SH_MTU2
+ help
+ This enables build of a clockevent driver for the Multi-Function
+ Timer Pulse Unit 2 (TMU2) hardware available on SoCs from Renesas.
+ This hardware comes with 16 bit-timer registers.
+
+config SH_TIMER_TMU
+ bool "Renesas TMU timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ default SYS_SUPPORTS_SH_TMU
+ help
+ This enables build of a clocksource and clockevent driver for
+ the 32-bit Timer Unit (TMU) hardware available on a wide range
+ SoCs from Renesas.
+
+config EM_TIMER_STI
+ bool "Renesas STI timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ default SYS_SUPPORTS_EM_STI
+ help
+ This enables build of a clocksource and clockevent driver for
+ the 48-bit System Timer (STI) hardware available on a SoCs
+ such as EMEV2 from former NEC Electronics.
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index c7ca50a9c232..f3fe4cb4974b 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -1,6 +1,5 @@
obj-$(CONFIG_CLKSRC_OF) += clksrc-of.o
obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
-obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o
obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o
obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o
@@ -21,6 +20,7 @@ obj-$(CONFIG_ARCH_MARCO) += timer-marco.o
obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o
obj-$(CONFIG_ARCH_MXS) += mxs_timer.o
obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o
+obj-$(CONFIG_ARCH_U300) += timer-u300.o
obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o
obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o
obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o
@@ -37,3 +37,4 @@ obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
+obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 95fb944e15ee..57e823c44d2a 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -277,6 +277,7 @@ static void __arch_timer_setup(unsigned type,
clk->set_next_event = arch_timer_set_next_event_phys;
}
} else {
+ clk->features |= CLOCK_EVT_FEAT_DYNIRQ;
clk->name = "arch_mem_timer";
clk->rating = 400;
clk->cpumask = cpu_all_mask;
diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c
index 63f176de0d02..49fbe2847c84 100644
--- a/drivers/clocksource/cadence_ttc_timer.c
+++ b/drivers/clocksource/cadence_ttc_timer.c
@@ -16,6 +16,7 @@
*/
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/interrupt.h>
#include <linux/clockchips.h>
#include <linux/of_address.h>
@@ -52,6 +53,8 @@
#define TTC_CNT_CNTRL_DISABLE_MASK 0x1
#define TTC_CLK_CNTRL_CSRC_MASK (1 << 5) /* clock source */
+#define TTC_CLK_CNTRL_PSV_MASK 0x1e
+#define TTC_CLK_CNTRL_PSV_SHIFT 1
/*
* Setup the timers to use pre-scaling, using a fixed value for now that will
@@ -63,6 +66,8 @@
#define CLK_CNTRL_PRESCALE_EN 1
#define CNT_CNTRL_RESET (1 << 4)
+#define MAX_F_ERR 50
+
/**
* struct ttc_timer - This definition defines local timer structure
*
@@ -82,6 +87,8 @@ struct ttc_timer {
container_of(x, struct ttc_timer, clk_rate_change_nb)
struct ttc_timer_clocksource {
+ u32 scale_clk_ctrl_reg_old;
+ u32 scale_clk_ctrl_reg_new;
struct ttc_timer ttc;
struct clocksource cs;
};
@@ -229,32 +236,89 @@ static int ttc_rate_change_clocksource_cb(struct notifier_block *nb,
struct ttc_timer_clocksource, ttc);
switch (event) {
- case POST_RATE_CHANGE:
+ case PRE_RATE_CHANGE:
+ {
+ u32 psv;
+ unsigned long factor, rate_low, rate_high;
+
+ if (ndata->new_rate > ndata->old_rate) {
+ factor = DIV_ROUND_CLOSEST(ndata->new_rate,
+ ndata->old_rate);
+ rate_low = ndata->old_rate;
+ rate_high = ndata->new_rate;
+ } else {
+ factor = DIV_ROUND_CLOSEST(ndata->old_rate,
+ ndata->new_rate);
+ rate_low = ndata->new_rate;
+ rate_high = ndata->old_rate;
+ }
+
+ if (!is_power_of_2(factor))
+ return NOTIFY_BAD;
+
+ if (abs(rate_high - (factor * rate_low)) > MAX_F_ERR)
+ return NOTIFY_BAD;
+
+ factor = __ilog2_u32(factor);
+
/*
- * Do whatever is necessary to maintain a proper time base
- *
- * I cannot find a way to adjust the currently used clocksource
- * to the new frequency. __clocksource_updatefreq_hz() sounds
- * good, but does not work. Not sure what's that missing.
- *
- * This approach works, but triggers two clocksource switches.
- * The first after unregister to clocksource jiffies. And
- * another one after the register to the newly registered timer.
- *
- * Alternatively we could 'waste' another HW timer to ping pong
- * between clock sources. That would also use one register and
- * one unregister call, but only trigger one clocksource switch
- * for the cost of another HW timer used by the OS.
+ * store timer clock ctrl register so we can restore it in case
+ * of an abort.
*/
- clocksource_unregister(&ttccs->cs);
- clocksource_register_hz(&ttccs->cs,
- ndata->new_rate / PRESCALE);
- /* fall through */
- case PRE_RATE_CHANGE:
+ ttccs->scale_clk_ctrl_reg_old =
+ __raw_readl(ttccs->ttc.base_addr +
+ TTC_CLK_CNTRL_OFFSET);
+
+ psv = (ttccs->scale_clk_ctrl_reg_old &
+ TTC_CLK_CNTRL_PSV_MASK) >>
+ TTC_CLK_CNTRL_PSV_SHIFT;
+ if (ndata->new_rate < ndata->old_rate)
+ psv -= factor;
+ else
+ psv += factor;
+
+ /* prescaler within legal range? */
+ if (psv & ~(TTC_CLK_CNTRL_PSV_MASK >> TTC_CLK_CNTRL_PSV_SHIFT))
+ return NOTIFY_BAD;
+
+ ttccs->scale_clk_ctrl_reg_new = ttccs->scale_clk_ctrl_reg_old &
+ ~TTC_CLK_CNTRL_PSV_MASK;
+ ttccs->scale_clk_ctrl_reg_new |= psv << TTC_CLK_CNTRL_PSV_SHIFT;
+
+
+ /* scale down: adjust divider in post-change notification */
+ if (ndata->new_rate < ndata->old_rate)
+ return NOTIFY_DONE;
+
+ /* scale up: adjust divider now - before frequency change */
+ __raw_writel(ttccs->scale_clk_ctrl_reg_new,
+ ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET);
+ break;
+ }
+ case POST_RATE_CHANGE:
+ /* scale up: pre-change notification did the adjustment */
+ if (ndata->new_rate > ndata->old_rate)
+ return NOTIFY_OK;
+
+ /* scale down: adjust divider now - after frequency change */
+ __raw_writel(ttccs->scale_clk_ctrl_reg_new,
+ ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET);
+ break;
+
case ABORT_RATE_CHANGE:
+ /* we have to undo the adjustment in case we scale up */
+ if (ndata->new_rate < ndata->old_rate)
+ return NOTIFY_OK;
+
+ /* restore original register value */
+ __raw_writel(ttccs->scale_clk_ctrl_reg_old,
+ ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET);
+ /* fall through */
default:
return NOTIFY_DONE;
}
+
+ return NOTIFY_DONE;
}
static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base)
@@ -321,25 +385,12 @@ static int ttc_rate_change_clockevent_cb(struct notifier_block *nb,
switch (event) {
case POST_RATE_CHANGE:
- {
- unsigned long flags;
-
- /*
- * clockevents_update_freq should be called with IRQ disabled on
- * the CPU the timer provides events for. The timer we use is
- * common to both CPUs, not sure if we need to run on both
- * cores.
- */
- local_irq_save(flags);
- clockevents_update_freq(&ttcce->ce,
- ndata->new_rate / PRESCALE);
- local_irq_restore(flags);
-
/* update cached frequency */
ttc->freq = ndata->new_rate;
+ clockevents_update_freq(&ttcce->ce, ndata->new_rate / PRESCALE);
+
/* fall through */
- }
case PRE_RATE_CHANGE:
case ABORT_RATE_CHANGE:
default:
diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c
deleted file mode 100644
index 9e0998f22885..000000000000
--- a/drivers/clocksource/cyclone.c
+++ /dev/null
@@ -1,113 +0,0 @@
-#include <linux/clocksource.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/timex.h>
-#include <linux/init.h>
-
-#include <asm/pgtable.h>
-#include <asm/io.h>
-
-#include <asm/mach_timer.h>
-
-#define CYCLONE_CBAR_ADDR 0xFEB00CD0 /* base address ptr */
-#define CYCLONE_PMCC_OFFSET 0x51A0 /* offset to control register */
-#define CYCLONE_MPCS_OFFSET 0x51A8 /* offset to select register */
-#define CYCLONE_MPMC_OFFSET 0x51D0 /* offset to count register */
-#define CYCLONE_TIMER_FREQ 99780000 /* 100Mhz, but not really */
-#define CYCLONE_TIMER_MASK CLOCKSOURCE_MASK(32) /* 32 bit mask */
-
-int use_cyclone = 0;
-static void __iomem *cyclone_ptr;
-
-static cycle_t read_cyclone(struct clocksource *cs)
-{
- return (cycle_t)readl(cyclone_ptr);
-}
-
-static struct clocksource clocksource_cyclone = {
- .name = "cyclone",
- .rating = 250,
- .read = read_cyclone,
- .mask = CYCLONE_TIMER_MASK,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static int __init init_cyclone_clocksource(void)
-{
- unsigned long base; /* saved value from CBAR */
- unsigned long offset;
- u32 __iomem* volatile cyclone_timer; /* Cyclone MPMC0 register */
- u32 __iomem* reg;
- int i;
-
- /* make sure we're on a summit box: */
- if (!use_cyclone)
- return -ENODEV;
-
- printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
-
- /* find base address: */
- offset = CYCLONE_CBAR_ADDR;
- reg = ioremap_nocache(offset, sizeof(reg));
- if (!reg) {
- printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
- return -ENODEV;
- }
- /* even on 64bit systems, this is only 32bits: */
- base = readl(reg);
- iounmap(reg);
- if (!base) {
- printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
- return -ENODEV;
- }
-
- /* setup PMCC: */
- offset = base + CYCLONE_PMCC_OFFSET;
- reg = ioremap_nocache(offset, sizeof(reg));
- if (!reg) {
- printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
- return -ENODEV;
- }
- writel(0x00000001,reg);
- iounmap(reg);
-
- /* setup MPCS: */
- offset = base + CYCLONE_MPCS_OFFSET;
- reg = ioremap_nocache(offset, sizeof(reg));
- if (!reg) {
- printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
- return -ENODEV;
- }
- writel(0x00000001,reg);
- iounmap(reg);
-
- /* map in cyclone_timer: */
- offset = base + CYCLONE_MPMC_OFFSET;
- cyclone_timer = ioremap_nocache(offset, sizeof(u64));
- if (!cyclone_timer) {
- printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
- return -ENODEV;
- }
-
- /* quick test to make sure its ticking: */
- for (i = 0; i < 3; i++){
- u32 old = readl(cyclone_timer);
- int stall = 100;
-
- while (stall--)
- barrier();
-
- if (readl(cyclone_timer) == old) {
- printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
- iounmap(cyclone_timer);
- cyclone_timer = NULL;
- return -ENODEV;
- }
- }
- cyclone_ptr = cyclone_timer;
-
- return clocksource_register_hz(&clocksource_cyclone,
- CYCLONE_TIMER_FREQ);
-}
-
-arch_initcall(init_cyclone_clocksource);
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index 48f76bc05da0..c2e390efbdca 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -410,7 +410,7 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt)
mevt = container_of(evt, struct mct_clock_event_device, evt);
mevt->base = EXYNOS4_MCT_L_BASE(cpu);
- sprintf(mevt->name, "mct_tick%d", cpu);
+ snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d", cpu);
evt->name = mevt->name;
evt->cpumask = cpumask_of(cpu);
diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c
index bf497afba9ad..efb17c3ee120 100644
--- a/drivers/clocksource/sun4i_timer.c
+++ b/drivers/clocksource/sun4i_timer.c
@@ -196,5 +196,5 @@ static void __init sun4i_timer_init(struct device_node *node)
clockevents_config_and_register(&sun4i_clockevent, rate,
TIMER_SYNC_TICKS, 0xffffffff);
}
-CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-timer",
+CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer",
sun4i_timer_init);
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index ee8691b89944..0451e62fac7a 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/time-armada-370-xp.c
@@ -85,12 +85,6 @@ static u32 ticks_per_jiffy;
static struct clock_event_device __percpu *armada_370_xp_evt;
-static void timer_ctrl_clrset(u32 clr, u32 set)
-{
- writel((readl(timer_base + TIMER_CTRL_OFF) & ~clr) | set,
- timer_base + TIMER_CTRL_OFF);
-}
-
static void local_timer_ctrl_clrset(u32 clr, u32 set)
{
writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set,
@@ -245,7 +239,7 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
clr = TIMER0_25MHZ;
enable_mask = TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT);
}
- timer_ctrl_clrset(clr, set);
+ atomic_io_modify(timer_base + TIMER_CTRL_OFF, clr | set, set);
local_timer_ctrl_clrset(clr, set);
/*
@@ -263,7 +257,9 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
- timer_ctrl_clrset(0, TIMER0_RELOAD_EN | enable_mask);
+ atomic_io_modify(timer_base + TIMER_CTRL_OFF,
+ TIMER0_RELOAD_EN | enable_mask,
+ TIMER0_RELOAD_EN | enable_mask);
/*
* Set scale and timer for sched_clock.
diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c
index 20066222f3f2..0b3ce0399c51 100644
--- a/drivers/clocksource/time-orion.c
+++ b/drivers/clocksource/time-orion.c
@@ -35,20 +35,6 @@
#define ORION_ONESHOT_MAX 0xfffffffe
static void __iomem *timer_base;
-static DEFINE_SPINLOCK(timer_ctrl_lock);
-
-/*
- * Thread-safe access to TIMER_CTRL register
- * (shared with watchdog timer)
- */
-void orion_timer_ctrl_clrset(u32 clr, u32 set)
-{
- spin_lock(&timer_ctrl_lock);
- writel((readl(timer_base + TIMER_CTRL) & ~clr) | set,
- timer_base + TIMER_CTRL);
- spin_unlock(&timer_ctrl_lock);
-}
-EXPORT_SYMBOL(orion_timer_ctrl_clrset);
/*
* Free-running clocksource handling.
@@ -68,7 +54,8 @@ static int orion_clkevt_next_event(unsigned long delta,
{
/* setup and enable one-shot timer */
writel(delta, timer_base + TIMER1_VAL);
- orion_timer_ctrl_clrset(TIMER1_RELOAD_EN, TIMER1_EN);
+ atomic_io_modify(timer_base + TIMER_CTRL,
+ TIMER1_RELOAD_EN | TIMER1_EN, TIMER1_EN);
return 0;
}
@@ -80,10 +67,13 @@ static void orion_clkevt_mode(enum clock_event_mode mode,
/* setup and enable periodic timer at 1/HZ intervals */
writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD);
writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL);
- orion_timer_ctrl_clrset(0, TIMER1_RELOAD_EN | TIMER1_EN);
+ atomic_io_modify(timer_base + TIMER_CTRL,
+ TIMER1_RELOAD_EN | TIMER1_EN,
+ TIMER1_RELOAD_EN | TIMER1_EN);
} else {
/* disable timer */
- orion_timer_ctrl_clrset(TIMER1_RELOAD_EN | TIMER1_EN, 0);
+ atomic_io_modify(timer_base + TIMER_CTRL,
+ TIMER1_RELOAD_EN | TIMER1_EN, 0);
}
}
@@ -131,7 +121,9 @@ static void __init orion_timer_init(struct device_node *np)
/* setup timer0 as free-running clocksource */
writel(~0, timer_base + TIMER0_VAL);
writel(~0, timer_base + TIMER0_RELOAD);
- orion_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | TIMER0_EN);
+ atomic_io_modify(timer_base + TIMER_CTRL,
+ TIMER0_RELOAD_EN | TIMER0_EN,
+ TIMER0_RELOAD_EN | TIMER0_EN);
clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource",
clk_get_rate(clk), 300, 32,
clocksource_mmio_readl_down);
diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c
new file mode 100644
index 000000000000..0250354f7e55
--- /dev/null
+++ b/drivers/clocksource/timer-keystone.c
@@ -0,0 +1,241 @@
+/*
+ * Keystone broadcast clock-event
+ *
+ * Copyright 2013 Texas Instruments, Inc.
+ *
+ * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define TIMER_NAME "timer-keystone"
+
+/* Timer register offsets */
+#define TIM12 0x10
+#define TIM34 0x14
+#define PRD12 0x18
+#define PRD34 0x1c
+#define TCR 0x20
+#define TGCR 0x24
+#define INTCTLSTAT 0x44
+
+/* Timer register bitfields */
+#define TCR_ENAMODE_MASK 0xC0
+#define TCR_ENAMODE_ONESHOT_MASK 0x40
+#define TCR_ENAMODE_PERIODIC_MASK 0x80
+
+#define TGCR_TIM_UNRESET_MASK 0x03
+#define INTCTLSTAT_ENINT_MASK 0x01
+
+/**
+ * struct keystone_timer: holds timer's data
+ * @base: timer memory base address
+ * @hz_period: cycles per HZ period
+ * @event_dev: event device based on timer
+ */
+static struct keystone_timer {
+ void __iomem *base;
+ unsigned long hz_period;
+ struct clock_event_device event_dev;
+} timer;
+
+static inline u32 keystone_timer_readl(unsigned long rg)
+{
+ return readl_relaxed(timer.base + rg);
+}
+
+static inline void keystone_timer_writel(u32 val, unsigned long rg)
+{
+ writel_relaxed(val, timer.base + rg);
+}
+
+/**
+ * keystone_timer_barrier: write memory barrier
+ * use explicit barrier to avoid using readl/writel non relaxed function
+ * variants, because in our case non relaxed variants hide the true places
+ * where barrier is needed.
+ */
+static inline void keystone_timer_barrier(void)
+{
+ __iowmb();
+}
+
+/**
+ * keystone_timer_config: configures timer to work in oneshot/periodic modes.
+ * @ mode: mode to configure
+ * @ period: cycles number to configure for
+ */
+static int keystone_timer_config(u64 period, enum clock_event_mode mode)
+{
+ u32 tcr;
+ u32 off;
+
+ tcr = keystone_timer_readl(TCR);
+ off = tcr & ~(TCR_ENAMODE_MASK);
+
+ /* set enable mode */
+ switch (mode) {
+ case CLOCK_EVT_MODE_ONESHOT:
+ tcr |= TCR_ENAMODE_ONESHOT_MASK;
+ break;
+ case CLOCK_EVT_MODE_PERIODIC:
+ tcr |= TCR_ENAMODE_PERIODIC_MASK;
+ break;
+ default:
+ return -1;
+ }
+
+ /* disable timer */
+ keystone_timer_writel(off, TCR);
+ /* here we have to be sure the timer has been disabled */
+ keystone_timer_barrier();
+
+ /* reset counter to zero, set new period */
+ keystone_timer_writel(0, TIM12);
+ keystone_timer_writel(0, TIM34);
+ keystone_timer_writel(period & 0xffffffff, PRD12);
+ keystone_timer_writel(period >> 32, PRD34);
+
+ /*
+ * enable timer
+ * here we have to be sure that CNTLO, CNTHI, PRDLO, PRDHI registers
+ * have been written.
+ */
+ keystone_timer_barrier();
+ keystone_timer_writel(tcr, TCR);
+ return 0;
+}
+
+static void keystone_timer_disable(void)
+{
+ u32 tcr;
+
+ tcr = keystone_timer_readl(TCR);
+
+ /* disable timer */
+ tcr &= ~(TCR_ENAMODE_MASK);
+ keystone_timer_writel(tcr, TCR);
+}
+
+static irqreturn_t keystone_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+}
+
+static int keystone_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ return keystone_timer_config(cycles, evt->mode);
+}
+
+static void keystone_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ keystone_timer_config(timer.hz_period, CLOCK_EVT_MODE_PERIODIC);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_ONESHOT:
+ keystone_timer_disable();
+ break;
+ default:
+ break;
+ }
+}
+
+static void __init keystone_timer_init(struct device_node *np)
+{
+ struct clock_event_device *event_dev = &timer.event_dev;
+ unsigned long rate;
+ struct clk *clk;
+ int irq, error;
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (irq == NO_IRQ) {
+ pr_err("%s: failed to map interrupts\n", __func__);
+ return;
+ }
+
+ timer.base = of_iomap(np, 0);
+ if (!timer.base) {
+ pr_err("%s: failed to map registers\n", __func__);
+ return;
+ }
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to get clock\n", __func__);
+ iounmap(timer.base);
+ return;
+ }
+
+ error = clk_prepare_enable(clk);
+ if (error) {
+ pr_err("%s: failed to enable clock\n", __func__);
+ goto err;
+ }
+
+ rate = clk_get_rate(clk);
+
+ /* disable, use internal clock source */
+ keystone_timer_writel(0, TCR);
+ /* here we have to be sure the timer has been disabled */
+ keystone_timer_barrier();
+
+ /* reset timer as 64-bit, no pre-scaler, plus features are disabled */
+ keystone_timer_writel(0, TGCR);
+
+ /* unreset timer */
+ keystone_timer_writel(TGCR_TIM_UNRESET_MASK, TGCR);
+
+ /* init counter to zero */
+ keystone_timer_writel(0, TIM12);
+ keystone_timer_writel(0, TIM34);
+
+ timer.hz_period = DIV_ROUND_UP(rate, HZ);
+
+ /* enable timer interrupts */
+ keystone_timer_writel(INTCTLSTAT_ENINT_MASK, INTCTLSTAT);
+
+ error = request_irq(irq, keystone_timer_interrupt, IRQF_TIMER,
+ TIMER_NAME, event_dev);
+ if (error) {
+ pr_err("%s: failed to setup irq\n", __func__);
+ goto err;
+ }
+
+ /* setup clockevent */
+ event_dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+ event_dev->set_next_event = keystone_set_next_event;
+ event_dev->set_mode = keystone_set_mode;
+ event_dev->cpumask = cpu_all_mask;
+ event_dev->owner = THIS_MODULE;
+ event_dev->name = TIMER_NAME;
+ event_dev->irq = irq;
+
+ clockevents_config_and_register(event_dev, rate, 1, ULONG_MAX);
+
+ pr_info("keystone timer clock @%lu Hz\n", rate);
+ return;
+err:
+ clk_put(clk);
+ iounmap(timer.base);
+}
+
+CLOCKSOURCE_OF_DECLARE(keystone_timer, "ti,keystone-timer",
+ keystone_timer_init);
diff --git a/arch/arm/mach-u300/timer.c b/drivers/clocksource/timer-u300.c
index fe08fd34c0ce..e63d469661fd 100644
--- a/arch/arm/mach-u300/timer.c
+++ b/drivers/clocksource/timer-u300.c
@@ -1,8 +1,4 @@
/*
- *
- * arch/arm/mach-u300/timer.c
- *
- *
* Copyright (C) 2007-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Timer COH 901 328, runs the OS timer interrupt.
diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/vf_pit_timer.c
index 02821b06a39e..a918bc481c52 100644
--- a/drivers/clocksource/vf_pit_timer.c
+++ b/drivers/clocksource/vf_pit_timer.c
@@ -54,7 +54,7 @@ static inline void pit_irq_acknowledge(void)
static u64 pit_read_sched_clock(void)
{
- return __raw_readl(clksrc_base + PITCVAL);
+ return ~__raw_readl(clksrc_base + PITCVAL);
}
static int __init pit_clocksource_init(unsigned long rate)
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index 18c5b9b16645..148d707a1d43 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -95,7 +95,7 @@ void proc_fork_connector(struct task_struct *task)
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
/* If cn_netlink_send() failed, the data is not sent */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_exec_connector(struct task_struct *task)
@@ -122,7 +122,7 @@ void proc_exec_connector(struct task_struct *task)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_id_connector(struct task_struct *task, int which_id)
@@ -163,7 +163,7 @@ void proc_id_connector(struct task_struct *task, int which_id)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_sid_connector(struct task_struct *task)
@@ -190,7 +190,7 @@ void proc_sid_connector(struct task_struct *task)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
@@ -225,7 +225,7 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_comm_connector(struct task_struct *task)
@@ -253,7 +253,7 @@ void proc_comm_connector(struct task_struct *task)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_coredump_connector(struct task_struct *task)
@@ -280,7 +280,7 @@ void proc_coredump_connector(struct task_struct *task)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
void proc_exit_connector(struct task_struct *task)
@@ -309,7 +309,7 @@ void proc_exit_connector(struct task_struct *task)
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
/*
@@ -343,7 +343,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
msg->ack = rcvd_ack + 1;
msg->len = sizeof(*ev);
msg->flags = 0; /* not used */
- cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+ cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_KERNEL);
}
/**
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index a36749f1e44a..77afe7487d34 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -50,7 +50,7 @@ static int cn_already_initialized;
*
* Sequence number is incremented with each message to be sent.
*
- * If we expect reply to our message then the sequence number in
+ * If we expect a reply to our message then the sequence number in
* received message MUST be the same as in original message, and
* acknowledge number MUST be the same + 1.
*
@@ -62,8 +62,11 @@ static int cn_already_initialized;
* the acknowledgement number in the original message + 1, then it is
* a new message.
*
+ * The message is sent to, the portid if given, the group if given, both if
+ * both, or if both are zero then the group is looked up and sent there.
*/
-int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
+int cn_netlink_send(struct cn_msg *msg, u32 portid, u32 __group,
+ gfp_t gfp_mask)
{
struct cn_callback_entry *__cbq;
unsigned int size;
@@ -74,7 +77,9 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
u32 group = 0;
int found = 0;
- if (!__group) {
+ if (portid || __group) {
+ group = __group;
+ } else {
spin_lock_bh(&dev->cbdev->queue_lock);
list_for_each_entry(__cbq, &dev->cbdev->queue_list,
callback_entry) {
@@ -88,11 +93,9 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
if (!found)
return -ENODEV;
- } else {
- group = __group;
}
- if (!netlink_has_listeners(dev->nls, group))
+ if (!portid && !netlink_has_listeners(dev->nls, group))
return -ESRCH;
size = sizeof(*msg) + msg->len;
@@ -113,7 +116,10 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
NETLINK_CB(skb).dst_group = group;
- return netlink_broadcast(dev->nls, skb, 0, group, gfp_mask);
+ if (group)
+ return netlink_broadcast(dev->nls, skb, portid, group,
+ gfp_mask);
+ return netlink_unicast(dev->nls, skb, portid, !(gfp_mask&__GFP_WAIT));
}
EXPORT_SYMBOL_GPL(cn_netlink_send);
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 4b029c0944af..1fbe11f2a146 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -200,7 +200,7 @@ source "drivers/cpufreq/Kconfig.x86"
endmenu
menu "ARM CPU frequency scaling drivers"
-depends on ARM
+depends on ARM || ARM64
source "drivers/cpufreq/Kconfig.arm"
endmenu
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 31297499a60a..9fb627046e17 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -2,6 +2,7 @@
# ARM CPU Frequency scaling drivers
#
+# big LITTLE core layer and glue drivers
config ARM_BIG_LITTLE_CPUFREQ
tristate "Generic ARM big LITTLE CPUfreq driver"
depends on ARM && BIG_LITTLE && ARM_CPU_TOPOLOGY && HAVE_CLK
@@ -16,6 +17,14 @@ config ARM_DT_BL_CPUFREQ
This enables probing via DT for Generic CPUfreq driver for ARM
big.LITTLE platform. This gets frequency tables from DT.
+config ARM_VEXPRESS_SPC_CPUFREQ
+ tristate "Versatile Express SPC based CPUfreq driver"
+ depends on ARM_BIG_LITTLE_CPUFREQ && ARCH_VEXPRESS_SPC
+ help
+ This add the CPUfreq driver support for Versatile Express
+ big.LITTLE platforms using SPC for power management.
+
+
config ARM_EXYNOS_CPUFREQ
bool
@@ -241,11 +250,3 @@ config ARM_TEGRA_CPUFREQ
default y
help
This adds the CPUFreq driver support for TEGRA SOCs.
-
-config ARM_VEXPRESS_SPC_CPUFREQ
- tristate "Versatile Express SPC based CPUfreq driver"
- select ARM_BIG_LITTLE_CPUFREQ
- depends on ARCH_VEXPRESS_SPC
- help
- This add the CPUfreq driver support for Versatile Express
- big.LITTLE platforms using SPC for power management.
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 18448a7e9f86..822ca03a87f7 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -855,7 +855,6 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
pr_debug("acpi_cpufreq_cpu_exit\n");
if (data) {
- cpufreq_frequency_table_put_attr(policy->cpu);
per_cpu(acfreq_data, policy->cpu) = NULL;
acpi_processor_unregister_performance(data->acpi_data,
policy->cpu);
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index 72f87e9317e3..bad2ed317ba2 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -446,9 +446,12 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
}
if (cur_cluster < MAX_CLUSTERS) {
+ int cpu;
+
cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
- per_cpu(physical_cluster, policy->cpu) = cur_cluster;
+ for_each_cpu(cpu, policy->cpus)
+ per_cpu(physical_cluster, cpu) = cur_cluster;
} else {
/* Assumption: during init, we are always running on A15 */
per_cpu(physical_cluster, policy->cpu) = A15_CLUSTER;
@@ -478,7 +481,6 @@ static int bL_cpufreq_exit(struct cpufreq_policy *policy)
return -ENODEV;
}
- cpufreq_frequency_table_put_attr(policy->cpu);
put_cluster_clk_and_freq_table(cpu_dev);
dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu);
diff --git a/drivers/cpufreq/blackfin-cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c
index e9e63fc9c2c9..a9f8e5bd0716 100644
--- a/drivers/cpufreq/blackfin-cpufreq.c
+++ b/drivers/cpufreq/blackfin-cpufreq.c
@@ -195,7 +195,6 @@ static struct cpufreq_driver bfin_driver = {
.target_index = bfin_target,
.get = bfin_getfreq_khz,
.init = __bfin_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "bfin cpufreq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index 0c12ffc0ebcb..1bf6bbac3e03 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -109,7 +109,6 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
.target_index = cpu0_set_target,
.get = cpufreq_generic_get,
.init = cpu0_cpufreq_init,
- .exit = cpufreq_generic_exit,
.name = "generic_cpu0",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c
index a05b876f375e..bc447b9003c3 100644
--- a/drivers/cpufreq/cpufreq-nforce2.c
+++ b/drivers/cpufreq/cpufreq-nforce2.c
@@ -270,7 +270,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
pr_debug("Old CPU frequency %d kHz, new %d kHz\n",
freqs.old, freqs.new);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
/* Disable IRQs */
/* local_irq_save(flags); */
@@ -285,7 +285,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
/* Enable IRQs */
/* local_irq_restore(flags); */
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
return 0;
}
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 08ca8c9f41cd..abda6609d3e7 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -26,7 +26,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/syscore_ops.h>
+#include <linux/suspend.h>
#include <linux/tick.h>
#include <trace/events/power.h>
@@ -42,10 +42,11 @@ static DEFINE_RWLOCK(cpufreq_driver_lock);
DEFINE_MUTEX(cpufreq_governor_lock);
static LIST_HEAD(cpufreq_policy_list);
-#ifdef CONFIG_HOTPLUG_CPU
/* This one keeps track of the previously set governor of a removed CPU */
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
-#endif
+
+/* Flag to suspend/resume CPUFreq governors */
+static bool cpufreq_suspended;
static inline bool has_target(void)
{
@@ -181,8 +182,8 @@ unsigned int cpufreq_generic_get(unsigned int cpu)
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
if (!policy || IS_ERR(policy->clk)) {
- pr_err("%s: No %s associated to cpu: %d\n", __func__,
- policy ? "clk" : "policy", cpu);
+ pr_err("%s: No %s associated to cpu: %d\n",
+ __func__, policy ? "clk" : "policy", cpu);
return 0;
}
@@ -190,6 +191,12 @@ unsigned int cpufreq_generic_get(unsigned int cpu)
}
EXPORT_SYMBOL_GPL(cpufreq_generic_get);
+/* Only for cpufreq core internal use */
+struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
+{
+ return per_cpu(cpufreq_cpu_data, cpu);
+}
+
struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
{
struct cpufreq_policy *policy = NULL;
@@ -254,15 +261,14 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
if (!l_p_j_ref_freq) {
l_p_j_ref = loops_per_jiffy;
l_p_j_ref_freq = ci->old;
- pr_debug("saving %lu as reference value for loops_per_jiffy; "
- "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
+ pr_debug("saving %lu as reference value for loops_per_jiffy; freq is %u kHz\n",
+ l_p_j_ref, l_p_j_ref_freq);
}
- if ((val == CPUFREQ_POSTCHANGE && ci->old != ci->new) ||
- (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
+ if (val == CPUFREQ_POSTCHANGE && ci->old != ci->new) {
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
ci->new);
- pr_debug("scaling loops_per_jiffy to %lu "
- "for frequency %u kHz\n", loops_per_jiffy, ci->new);
+ pr_debug("scaling loops_per_jiffy to %lu for frequency %u kHz\n",
+ loops_per_jiffy, ci->new);
}
}
#else
@@ -282,7 +288,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
freqs->flags = cpufreq_driver->flags;
pr_debug("notification %u of frequency transition to %u kHz\n",
- state, freqs->new);
+ state, freqs->new);
switch (state) {
@@ -294,9 +300,8 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
if ((policy) && (policy->cpu == freqs->cpu) &&
(policy->cur) && (policy->cur != freqs->old)) {
- pr_debug("Warning: CPU frequency is"
- " %u, cpufreq assumed %u kHz.\n",
- freqs->old, policy->cur);
+ pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n",
+ freqs->old, policy->cur);
freqs->old = policy->cur;
}
}
@@ -307,8 +312,8 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
case CPUFREQ_POSTCHANGE:
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
- pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
- (unsigned long)freqs->cpu);
+ pr_debug("FREQ: %lu - CPU: %lu\n",
+ (unsigned long)freqs->new, (unsigned long)freqs->cpu);
trace_cpu_frequency(freqs->new, freqs->cpu);
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_POSTCHANGE, freqs);
@@ -326,16 +331,15 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
* function. It is called twice on all CPU frequency changes that have
* external effects.
*/
-void cpufreq_notify_transition(struct cpufreq_policy *policy,
+static void cpufreq_notify_transition(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, unsigned int state)
{
for_each_cpu(freqs->cpu, policy->cpus)
__cpufreq_notify_transition(policy, freqs, state);
}
-EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/* Do post notifications when there are chances that transition has failed */
-void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
+static void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, int transition_failed)
{
cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE);
@@ -346,13 +350,47 @@ void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE);
cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE);
}
-EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition);
+
+void cpufreq_freq_transition_begin(struct cpufreq_policy *policy,
+ struct cpufreq_freqs *freqs)
+{
+wait:
+ wait_event(policy->transition_wait, !policy->transition_ongoing);
+
+ spin_lock(&policy->transition_lock);
+
+ if (unlikely(policy->transition_ongoing)) {
+ spin_unlock(&policy->transition_lock);
+ goto wait;
+ }
+
+ policy->transition_ongoing = true;
+
+ spin_unlock(&policy->transition_lock);
+
+ cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE);
+}
+EXPORT_SYMBOL_GPL(cpufreq_freq_transition_begin);
+
+void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
+ struct cpufreq_freqs *freqs, int transition_failed)
+{
+ if (unlikely(WARN_ON(!policy->transition_ongoing)))
+ return;
+
+ cpufreq_notify_post_transition(policy, freqs, transition_failed);
+
+ policy->transition_ongoing = false;
+
+ wake_up(&policy->transition_wait);
+}
+EXPORT_SYMBOL_GPL(cpufreq_freq_transition_end);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
-ssize_t show_boost(struct kobject *kobj,
+static ssize_t show_boost(struct kobject *kobj,
struct attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
@@ -368,13 +406,13 @@ static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
return -EINVAL;
if (cpufreq_boost_trigger_state(enable)) {
- pr_err("%s: Cannot %s BOOST!\n", __func__,
- enable ? "enable" : "disable");
+ pr_err("%s: Cannot %s BOOST!\n",
+ __func__, enable ? "enable" : "disable");
return -EINVAL;
}
- pr_debug("%s: cpufreq BOOST %s\n", __func__,
- enable ? "enabled" : "disabled");
+ pr_debug("%s: cpufreq BOOST %s\n",
+ __func__, enable ? "enabled" : "disabled");
return count;
}
@@ -879,18 +917,25 @@ err_out_kobj_put:
static void cpufreq_init_policy(struct cpufreq_policy *policy)
{
+ struct cpufreq_governor *gov = NULL;
struct cpufreq_policy new_policy;
int ret = 0;
memcpy(&new_policy, policy, sizeof(*policy));
+ /* Update governor of new_policy to the governor used before hotplug */
+ gov = __find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu));
+ if (gov)
+ pr_debug("Restoring governor %s for cpu %d\n",
+ policy->governor->name, policy->cpu);
+ else
+ gov = CPUFREQ_DEFAULT_GOVERNOR;
+
+ new_policy.governor = gov;
+
/* Use the default policy if its valid. */
if (cpufreq_driver->setpolicy)
- cpufreq_parse_governor(policy->governor->name,
- &new_policy.policy, NULL);
-
- /* assure that the starting sequence is run in cpufreq_set_policy */
- policy->governor = NULL;
+ cpufreq_parse_governor(gov->name, &new_policy.policy, NULL);
/* set default policy */
ret = cpufreq_set_policy(policy, &new_policy);
@@ -927,8 +972,11 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
up_write(&policy->rwsem);
if (has_target()) {
- if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
- (ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
+ if (!ret)
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+
+ if (ret) {
pr_err("%s: Failed to start governor\n", __func__);
return ret;
}
@@ -949,6 +997,8 @@ static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ policy->governor = NULL;
+
return policy;
}
@@ -968,6 +1018,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void)
INIT_LIST_HEAD(&policy->policy_list);
init_rwsem(&policy->rwsem);
+ spin_lock_init(&policy->transition_lock);
+ init_waitqueue_head(&policy->transition_wait);
return policy;
@@ -1022,21 +1074,19 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
up_write(&policy->rwsem);
- cpufreq_frequency_table_update_policy_cpu(policy);
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_UPDATE_POLICY_CPU, policy);
}
-static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
- bool frozen)
+static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{
unsigned int j, cpu = dev->id;
int ret = -ENOMEM;
struct cpufreq_policy *policy;
unsigned long flags;
+ bool recover_policy = cpufreq_suspended;
#ifdef CONFIG_HOTPLUG_CPU
struct cpufreq_policy *tpolicy;
- struct cpufreq_governor *gov;
#endif
if (cpu_is_offline(cpu))
@@ -1075,9 +1125,9 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
* Restore the saved policy when doing light-weight init and fall back
* to the full init if that fails.
*/
- policy = frozen ? cpufreq_policy_restore(cpu) : NULL;
+ policy = recover_policy ? cpufreq_policy_restore(cpu) : NULL;
if (!policy) {
- frozen = false;
+ recover_policy = false;
policy = cpufreq_policy_alloc();
if (!policy)
goto nomem_out;
@@ -1089,12 +1139,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
* the creation of a brand new one. So we need to perform this update
* by invoking update_policy_cpu().
*/
- if (frozen && cpu != policy->cpu)
+ if (recover_policy && cpu != policy->cpu)
update_policy_cpu(policy, cpu);
else
policy->cpu = cpu;
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
cpumask_copy(policy->cpus, cpumask_of(cpu));
init_completion(&policy->kobj_unregister);
@@ -1109,12 +1158,27 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
goto err_set_policy_cpu;
}
+ /* related cpus should atleast have policy->cpus */
+ cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
+
+ /*
+ * affected cpus must always be the one, which are online. We aren't
+ * managing offline cpus here.
+ */
+ cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
+
+ if (!recover_policy) {
+ policy->user_policy.min = policy->min;
+ policy->user_policy.max = policy->max;
+ }
+
+ down_write(&policy->rwsem);
write_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus)
per_cpu(cpufreq_cpu_data, j) = policy;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
- if (cpufreq_driver->get) {
+ if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
policy->cur = cpufreq_driver->get(policy->cpu);
if (!policy->cur) {
pr_err("%s: ->get() failed\n", __func__);
@@ -1162,33 +1226,10 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
}
}
- /* related cpus should atleast have policy->cpus */
- cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
-
- /*
- * affected cpus must always be the one, which are online. We aren't
- * managing offline cpus here.
- */
- cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
-
- if (!frozen) {
- policy->user_policy.min = policy->min;
- policy->user_policy.max = policy->max;
- }
-
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_START, policy);
-#ifdef CONFIG_HOTPLUG_CPU
- gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
- if (gov) {
- policy->governor = gov;
- pr_debug("Restoring governor %s for cpu %d\n",
- policy->governor->name, cpu);
- }
-#endif
-
- if (!frozen) {
+ if (!recover_policy) {
ret = cpufreq_add_dev_interface(policy, dev);
if (ret)
goto err_out_unregister;
@@ -1202,10 +1243,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
cpufreq_init_policy(policy);
- if (!frozen) {
+ if (!recover_policy) {
policy->user_policy.policy = policy->policy;
policy->user_policy.governor = policy->governor;
}
+ up_write(&policy->rwsem);
kobject_uevent(&policy->kobj, KOBJ_ADD);
up_read(&cpufreq_rwsem);
@@ -1224,7 +1266,7 @@ err_get_freq:
if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);
err_set_policy_cpu:
- if (frozen) {
+ if (recover_policy) {
/* Do not leave stale fallback data behind. */
per_cpu(cpufreq_cpu_data_fallback, cpu) = NULL;
cpufreq_policy_put_kobj(policy);
@@ -1248,7 +1290,7 @@ nomem_out:
*/
static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{
- return __cpufreq_add_dev(dev, sif, false);
+ return __cpufreq_add_dev(dev, sif);
}
static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
@@ -1263,7 +1305,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
if (ret) {
- pr_err("%s: Failed to move kobj: %d", __func__, ret);
+ pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
down_write(&policy->rwsem);
cpumask_set_cpu(old_cpu, policy->cpus);
@@ -1279,8 +1321,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
}
static int __cpufreq_remove_dev_prepare(struct device *dev,
- struct subsys_interface *sif,
- bool frozen)
+ struct subsys_interface *sif)
{
unsigned int cpu = dev->id, cpus;
int new_cpu, ret;
@@ -1294,7 +1335,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
policy = per_cpu(cpufreq_cpu_data, cpu);
/* Save the policy somewhere when doing a light-weight tear-down */
- if (frozen)
+ if (cpufreq_suspended)
per_cpu(cpufreq_cpu_data_fallback, cpu) = policy;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -1312,37 +1353,34 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
}
}
-#ifdef CONFIG_HOTPLUG_CPU
if (!cpufreq_driver->setpolicy)
strncpy(per_cpu(cpufreq_cpu_governor, cpu),
policy->governor->name, CPUFREQ_NAME_LEN);
-#endif
down_read(&policy->rwsem);
cpus = cpumask_weight(policy->cpus);
up_read(&policy->rwsem);
if (cpu != policy->cpu) {
- if (!frozen)
- sysfs_remove_link(&dev->kobj, "cpufreq");
+ sysfs_remove_link(&dev->kobj, "cpufreq");
} else if (cpus > 1) {
new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu);
if (new_cpu >= 0) {
update_policy_cpu(policy, new_cpu);
- if (!frozen) {
+ if (!cpufreq_suspended)
pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
- __func__, new_cpu, cpu);
- }
+ __func__, new_cpu, cpu);
}
+ } else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) {
+ cpufreq_driver->stop_cpu(policy);
}
return 0;
}
static int __cpufreq_remove_dev_finish(struct device *dev,
- struct subsys_interface *sif,
- bool frozen)
+ struct subsys_interface *sif)
{
unsigned int cpu = dev->id, cpus;
int ret;
@@ -1372,12 +1410,12 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
CPUFREQ_GOV_POLICY_EXIT);
if (ret) {
pr_err("%s: Failed to exit governor\n",
- __func__);
+ __func__);
return ret;
}
}
- if (!frozen)
+ if (!cpufreq_suspended)
cpufreq_policy_put_kobj(policy);
/*
@@ -1393,16 +1431,16 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
list_del(&policy->policy_list);
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
- if (!frozen)
+ if (!cpufreq_suspended)
cpufreq_policy_free(policy);
- } else {
- if (has_target()) {
- if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
- (ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
- pr_err("%s: Failed to start governor\n",
- __func__);
- return ret;
- }
+ } else if (has_target()) {
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
+ if (!ret)
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+
+ if (ret) {
+ pr_err("%s: Failed to start governor\n", __func__);
+ return ret;
}
}
@@ -1423,10 +1461,10 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
if (cpu_is_offline(cpu))
return 0;
- ret = __cpufreq_remove_dev_prepare(dev, sif, false);
+ ret = __cpufreq_remove_dev_prepare(dev, sif);
if (!ret)
- ret = __cpufreq_remove_dev_finish(dev, sif, false);
+ ret = __cpufreq_remove_dev_finish(dev, sif);
return ret;
}
@@ -1457,8 +1495,8 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
struct cpufreq_freqs freqs;
unsigned long flags;
- pr_debug("Warning: CPU frequency out of sync: cpufreq and timing "
- "core thinks of %u, is %u kHz.\n", old_freq, new_freq);
+ pr_debug("Warning: CPU frequency out of sync: cpufreq and timing core thinks of %u, is %u kHz\n",
+ old_freq, new_freq);
freqs.old = old_freq;
freqs.new = new_freq;
@@ -1467,8 +1505,8 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
policy = per_cpu(cpufreq_cpu_data, cpu);
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
}
/**
@@ -1547,23 +1585,16 @@ static unsigned int __cpufreq_get(unsigned int cpu)
*/
unsigned int cpufreq_get(unsigned int cpu)
{
- struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
unsigned int ret_freq = 0;
- if (cpufreq_disabled() || !cpufreq_driver)
- return -ENOENT;
-
- BUG_ON(!policy);
-
- if (!down_read_trylock(&cpufreq_rwsem))
- return 0;
-
- down_read(&policy->rwsem);
-
- ret_freq = __cpufreq_get(cpu);
+ if (policy) {
+ down_read(&policy->rwsem);
+ ret_freq = __cpufreq_get(cpu);
+ up_read(&policy->rwsem);
- up_read(&policy->rwsem);
- up_read(&cpufreq_rwsem);
+ cpufreq_cpu_put(policy);
+ }
return ret_freq;
}
@@ -1576,83 +1607,103 @@ static struct subsys_interface cpufreq_interface = {
.remove_dev = cpufreq_remove_dev,
};
+/*
+ * In case platform wants some specific frequency to be configured
+ * during suspend..
+ */
+int cpufreq_generic_suspend(struct cpufreq_policy *policy)
+{
+ int ret;
+
+ if (!policy->suspend_freq) {
+ pr_err("%s: suspend_freq can't be zero\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: Setting suspend-freq: %u\n", __func__,
+ policy->suspend_freq);
+
+ ret = __cpufreq_driver_target(policy, policy->suspend_freq,
+ CPUFREQ_RELATION_H);
+ if (ret)
+ pr_err("%s: unable to set suspend-freq: %u. err: %d\n",
+ __func__, policy->suspend_freq, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL(cpufreq_generic_suspend);
+
/**
- * cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
+ * cpufreq_suspend() - Suspend CPUFreq governors
*
- * This function is only executed for the boot processor. The other CPUs
- * have been put offline by means of CPU hotplug.
+ * Called during system wide Suspend/Hibernate cycles for suspending governors
+ * as some platforms can't change frequency after this point in suspend cycle.
+ * Because some of the devices (like: i2c, regulators, etc) they use for
+ * changing frequency are suspended quickly after this point.
*/
-static int cpufreq_bp_suspend(void)
+void cpufreq_suspend(void)
{
- int ret = 0;
-
- int cpu = smp_processor_id();
struct cpufreq_policy *policy;
- pr_debug("suspending cpu %u\n", cpu);
+ if (!cpufreq_driver)
+ return;
- /* If there's no policy for the boot CPU, we have nothing to do. */
- policy = cpufreq_cpu_get(cpu);
- if (!policy)
- return 0;
+ if (!has_target())
+ return;
- if (cpufreq_driver->suspend) {
- ret = cpufreq_driver->suspend(policy);
- if (ret)
- printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
- "step on CPU %u\n", policy->cpu);
+ pr_debug("%s: Suspending Governors\n", __func__);
+
+ list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP))
+ pr_err("%s: Failed to stop governor for policy: %p\n",
+ __func__, policy);
+ else if (cpufreq_driver->suspend
+ && cpufreq_driver->suspend(policy))
+ pr_err("%s: Failed to suspend driver: %p\n", __func__,
+ policy);
}
- cpufreq_cpu_put(policy);
- return ret;
+ cpufreq_suspended = true;
}
/**
- * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU.
- *
- * 1.) resume CPUfreq hardware support (cpufreq_driver->resume())
- * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are
- * restored. It will verify that the current freq is in sync with
- * what we believe it to be. This is a bit later than when it
- * should be, but nonethteless it's better than calling
- * cpufreq_driver->get() here which might re-enable interrupts...
+ * cpufreq_resume() - Resume CPUFreq governors
*
- * This function is only executed for the boot CPU. The other CPUs have not
- * been turned on yet.
+ * Called during system wide Suspend/Hibernate cycle for resuming governors that
+ * are suspended with cpufreq_suspend().
*/
-static void cpufreq_bp_resume(void)
+void cpufreq_resume(void)
{
- int ret = 0;
-
- int cpu = smp_processor_id();
struct cpufreq_policy *policy;
- pr_debug("resuming cpu %u\n", cpu);
+ if (!cpufreq_driver)
+ return;
- /* If there's no policy for the boot CPU, we have nothing to do. */
- policy = cpufreq_cpu_get(cpu);
- if (!policy)
+ if (!has_target())
return;
- if (cpufreq_driver->resume) {
- ret = cpufreq_driver->resume(policy);
- if (ret) {
- printk(KERN_ERR "cpufreq: resume failed in ->resume "
- "step on CPU %u\n", policy->cpu);
- goto fail;
- }
- }
+ pr_debug("%s: Resuming Governors\n", __func__);
- schedule_work(&policy->update);
+ cpufreq_suspended = false;
-fail:
- cpufreq_cpu_put(policy);
-}
+ list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ if (cpufreq_driver->resume && cpufreq_driver->resume(policy))
+ pr_err("%s: Failed to resume driver: %p\n", __func__,
+ policy);
+ else if (__cpufreq_governor(policy, CPUFREQ_GOV_START)
+ || __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))
+ pr_err("%s: Failed to start governor for policy: %p\n",
+ __func__, policy);
-static struct syscore_ops cpufreq_syscore_ops = {
- .suspend = cpufreq_bp_suspend,
- .resume = cpufreq_bp_resume,
-};
+ /*
+ * schedule call cpufreq_update_policy() for boot CPU, i.e. last
+ * policy in list. It will verify that the current freq is in
+ * sync with what we believe it to be.
+ */
+ if (list_is_last(&policy->policy_list, &cpufreq_policy_list))
+ schedule_work(&policy->update);
+ }
+}
/**
* cpufreq_get_current_driver - return current driver's name
@@ -1768,7 +1819,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
target_freq = policy->min;
pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n",
- policy->cpu, target_freq, relation, old_target_freq);
+ policy->cpu, target_freq, relation, old_target_freq);
/*
* This might look like a redundant call as we are checking it again
@@ -1813,20 +1864,18 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
freqs.flags = 0;
pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
- __func__, policy->cpu, freqs.old,
- freqs.new);
+ __func__, policy->cpu, freqs.old, freqs.new);
- cpufreq_notify_transition(policy, &freqs,
- CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
}
retval = cpufreq_driver->target_index(policy, index);
if (retval)
pr_err("%s: Failed to change cpu frequency: %d\n",
- __func__, retval);
+ __func__, retval);
if (notify)
- cpufreq_notify_post_transition(policy, &freqs, retval);
+ cpufreq_freq_transition_end(policy, &freqs, retval);
}
out:
@@ -1869,17 +1918,18 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
struct cpufreq_governor *gov = NULL;
#endif
+ /* Don't start any governor operations if we are entering suspend */
+ if (cpufreq_suspended)
+ return 0;
+
if (policy->governor->max_transition_latency &&
policy->cpuinfo.transition_latency >
policy->governor->max_transition_latency) {
if (!gov)
return -EINVAL;
else {
- printk(KERN_WARNING "%s governor failed, too long"
- " transition latency of HW, fallback"
- " to %s governor\n",
- policy->governor->name,
- gov->name);
+ pr_warn("%s governor failed, too long transition latency of HW, fallback to %s governor\n",
+ policy->governor->name, gov->name);
policy->governor = gov;
}
}
@@ -1889,7 +1939,7 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
return -EINVAL;
pr_debug("__cpufreq_governor for CPU %u, event %u\n",
- policy->cpu, event);
+ policy->cpu, event);
mutex_lock(&cpufreq_governor_lock);
if ((policy->governor_enabled && event == CPUFREQ_GOV_START)
@@ -1956,9 +2006,7 @@ EXPORT_SYMBOL_GPL(cpufreq_register_governor);
void cpufreq_unregister_governor(struct cpufreq_governor *governor)
{
-#ifdef CONFIG_HOTPLUG_CPU
int cpu;
-#endif
if (!governor)
return;
@@ -1966,14 +2014,12 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
if (cpufreq_disabled())
return;
-#ifdef CONFIG_HOTPLUG_CPU
for_each_present_cpu(cpu) {
if (cpu_online(cpu))
continue;
if (!strcmp(per_cpu(cpufreq_cpu_governor, cpu), governor->name))
strcpy(per_cpu(cpufreq_cpu_governor, cpu), "\0");
}
-#endif
mutex_lock(&cpufreq_governor_mutex);
list_del(&governor->governor_list);
@@ -2018,22 +2064,21 @@ EXPORT_SYMBOL(cpufreq_get_policy);
static int cpufreq_set_policy(struct cpufreq_policy *policy,
struct cpufreq_policy *new_policy)
{
- int ret = 0, failed = 1;
+ struct cpufreq_governor *old_gov;
+ int ret;
- pr_debug("setting new policy for CPU %u: %u - %u kHz\n", new_policy->cpu,
- new_policy->min, new_policy->max);
+ pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
+ new_policy->cpu, new_policy->min, new_policy->max);
memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
- if (new_policy->min > policy->max || new_policy->max < policy->min) {
- ret = -EINVAL;
- goto error_out;
- }
+ if (new_policy->min > policy->max || new_policy->max < policy->min)
+ return -EINVAL;
/* verify the cpu speed can be set within this limit */
ret = cpufreq_driver->verify(new_policy);
if (ret)
- goto error_out;
+ return ret;
/* adjust if necessary - all reasons */
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
@@ -2049,7 +2094,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
*/
ret = cpufreq_driver->verify(new_policy);
if (ret)
- goto error_out;
+ return ret;
/* notification of the new policy */
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
@@ -2059,63 +2104,53 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
policy->max = new_policy->max;
pr_debug("new min and max freqs are %u - %u kHz\n",
- policy->min, policy->max);
+ policy->min, policy->max);
if (cpufreq_driver->setpolicy) {
policy->policy = new_policy->policy;
pr_debug("setting range\n");
- ret = cpufreq_driver->setpolicy(new_policy);
- } else {
- if (new_policy->governor != policy->governor) {
- /* save old, working values */
- struct cpufreq_governor *old_gov = policy->governor;
-
- pr_debug("governor switch\n");
-
- /* end old governor */
- if (policy->governor) {
- __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
- up_write(&policy->rwsem);
- __cpufreq_governor(policy,
- CPUFREQ_GOV_POLICY_EXIT);
- down_write(&policy->rwsem);
- }
+ return cpufreq_driver->setpolicy(new_policy);
+ }
- /* start new governor */
- policy->governor = new_policy->governor;
- if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {
- if (!__cpufreq_governor(policy, CPUFREQ_GOV_START)) {
- failed = 0;
- } else {
- up_write(&policy->rwsem);
- __cpufreq_governor(policy,
- CPUFREQ_GOV_POLICY_EXIT);
- down_write(&policy->rwsem);
- }
- }
+ if (new_policy->governor == policy->governor)
+ goto out;
- if (failed) {
- /* new governor failed, so re-start old one */
- pr_debug("starting governor %s failed\n",
- policy->governor->name);
- if (old_gov) {
- policy->governor = old_gov;
- __cpufreq_governor(policy,
- CPUFREQ_GOV_POLICY_INIT);
- __cpufreq_governor(policy,
- CPUFREQ_GOV_START);
- }
- ret = -EINVAL;
- goto error_out;
- }
- /* might be a policy change, too, so fall through */
- }
- pr_debug("governor: change or update limits\n");
- ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ pr_debug("governor switch\n");
+
+ /* save old, working values */
+ old_gov = policy->governor;
+ /* end old governor */
+ if (old_gov) {
+ __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+ up_write(&policy->rwsem);
+ __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
+ down_write(&policy->rwsem);
}
-error_out:
- return ret;
+ /* start new governor */
+ policy->governor = new_policy->governor;
+ if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {
+ if (!__cpufreq_governor(policy, CPUFREQ_GOV_START))
+ goto out;
+
+ up_write(&policy->rwsem);
+ __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
+ down_write(&policy->rwsem);
+ }
+
+ /* new governor failed, so re-start old one */
+ pr_debug("starting governor %s failed\n", policy->governor->name);
+ if (old_gov) {
+ policy->governor = old_gov;
+ __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT);
+ __cpufreq_governor(policy, CPUFREQ_GOV_START);
+ }
+
+ return -EINVAL;
+
+ out:
+ pr_debug("governor: change or update limits\n");
+ return __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
}
/**
@@ -2149,10 +2184,15 @@ int cpufreq_update_policy(unsigned int cpu)
* BIOS might change freq behind our back
* -> ask driver for current freq and notify governors about a change
*/
- if (cpufreq_driver->get) {
+ if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
new_policy.cur = cpufreq_driver->get(cpu);
+ if (WARN_ON(!new_policy.cur)) {
+ ret = -EIO;
+ goto no_policy;
+ }
+
if (!policy->cur) {
- pr_debug("Driver did not initialize current freq");
+ pr_debug("Driver did not initialize current freq\n");
policy->cur = new_policy.cur;
} else {
if (policy->cur != new_policy.cur && has_target())
@@ -2176,30 +2216,24 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
{
unsigned int cpu = (unsigned long)hcpu;
struct device *dev;
- bool frozen = false;
dev = get_cpu_device(cpu);
if (dev) {
-
- if (action & CPU_TASKS_FROZEN)
- frozen = true;
-
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
- __cpufreq_add_dev(dev, NULL, frozen);
- cpufreq_update_policy(cpu);
+ __cpufreq_add_dev(dev, NULL);
break;
case CPU_DOWN_PREPARE:
- __cpufreq_remove_dev_prepare(dev, NULL, frozen);
+ __cpufreq_remove_dev_prepare(dev, NULL);
break;
case CPU_POST_DEAD:
- __cpufreq_remove_dev_finish(dev, NULL, frozen);
+ __cpufreq_remove_dev_finish(dev, NULL);
break;
case CPU_DOWN_FAILED:
- __cpufreq_add_dev(dev, NULL, frozen);
+ __cpufreq_add_dev(dev, NULL);
break;
}
}
@@ -2255,8 +2289,8 @@ int cpufreq_boost_trigger_state(int state)
cpufreq_driver->boost_enabled = !state;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
- pr_err("%s: Cannot %s BOOST\n", __func__,
- state ? "enable" : "disable");
+ pr_err("%s: Cannot %s BOOST\n",
+ __func__, state ? "enable" : "disable");
}
return ret;
@@ -2301,7 +2335,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
if (!driver_data || !driver_data->verify || !driver_data->init ||
!(driver_data->setpolicy || driver_data->target_index ||
- driver_data->target))
+ driver_data->target) ||
+ (driver_data->setpolicy && (driver_data->target_index ||
+ driver_data->target)))
return -EINVAL;
pr_debug("trying to register driver %s\n", driver_data->name);
@@ -2328,7 +2364,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
ret = cpufreq_sysfs_create_file(&boost.attr);
if (ret) {
pr_err("%s: cannot register global BOOST sysfs file\n",
- __func__);
+ __func__);
goto err_null_driver;
}
}
@@ -2351,7 +2387,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
/* if all ->init() calls failed, unregister */
if (ret) {
pr_debug("no CPU initialized for driver %s\n",
- driver_data->name);
+ driver_data->name);
goto err_if_unreg;
}
}
@@ -2415,7 +2451,6 @@ static int __init cpufreq_core_init(void)
cpufreq_global_kobject = kobject_create();
BUG_ON(!cpufreq_global_kobject);
- register_syscore_ops(&cpufreq_syscore_ops);
return 0;
}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 5793e1447fb1..ecaaebf969fc 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -13,7 +13,7 @@
#include <linux/cpufreq.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
static spinlock_t cpufreq_stats_lock;
@@ -180,27 +180,25 @@ static void cpufreq_stats_free_table(unsigned int cpu)
cpufreq_cpu_put(policy);
}
-static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
- struct cpufreq_frequency_table *table)
+static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
{
unsigned int i, j, count = 0, ret = 0;
struct cpufreq_stats *stat;
- struct cpufreq_policy *current_policy;
unsigned int alloc_size;
unsigned int cpu = policy->cpu;
+ struct cpufreq_frequency_table *table;
+
+ table = cpufreq_frequency_get_table(cpu);
+ if (unlikely(!table))
+ return 0;
+
if (per_cpu(cpufreq_stats_table, cpu))
return -EBUSY;
stat = kzalloc(sizeof(*stat), GFP_KERNEL);
if ((stat) == NULL)
return -ENOMEM;
- current_policy = cpufreq_cpu_get(cpu);
- if (current_policy == NULL) {
- ret = -EINVAL;
- goto error_get_fail;
- }
-
- ret = sysfs_create_group(&current_policy->kobj, &stats_attr_group);
+ ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
if (ret)
goto error_out;
@@ -223,7 +221,7 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
if (!stat->time_in_state) {
ret = -ENOMEM;
- goto error_out;
+ goto error_alloc;
}
stat->freq_table = (unsigned int *)(stat->time_in_state + count);
@@ -243,11 +241,10 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
stat->last_time = get_jiffies_64();
stat->last_index = freq_table_get_index(stat, policy->cur);
spin_unlock(&cpufreq_stats_lock);
- cpufreq_cpu_put(current_policy);
return 0;
+error_alloc:
+ sysfs_remove_group(&policy->kobj, &stats_attr_group);
error_out:
- cpufreq_cpu_put(current_policy);
-error_get_fail:
kfree(stat);
per_cpu(cpufreq_stats_table, cpu) = NULL;
return ret;
@@ -256,7 +253,6 @@ error_get_fail:
static void cpufreq_stats_create_table(unsigned int cpu)
{
struct cpufreq_policy *policy;
- struct cpufreq_frequency_table *table;
/*
* "likely(!policy)" because normally cpufreq_stats will be registered
@@ -266,9 +262,7 @@ static void cpufreq_stats_create_table(unsigned int cpu)
if (likely(!policy))
return;
- table = cpufreq_frequency_get_table(policy->cpu);
- if (likely(table))
- __cpufreq_stats_create_table(policy, table);
+ __cpufreq_stats_create_table(policy);
cpufreq_cpu_put(policy);
}
@@ -291,20 +285,14 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
{
int ret = 0;
struct cpufreq_policy *policy = data;
- struct cpufreq_frequency_table *table;
- unsigned int cpu = policy->cpu;
if (val == CPUFREQ_UPDATE_POLICY_CPU) {
cpufreq_stats_update_policy_cpu(policy);
return 0;
}
- table = cpufreq_frequency_get_table(cpu);
- if (!table)
- return 0;
-
if (val == CPUFREQ_CREATE_POLICY)
- ret = __cpufreq_stats_create_table(policy, table);
+ ret = __cpufreq_stats_create_table(policy);
else if (val == CPUFREQ_REMOVE_POLICY)
__cpufreq_stats_free_table(policy);
diff --git a/drivers/cpufreq/cris-artpec3-cpufreq.c b/drivers/cpufreq/cris-artpec3-cpufreq.c
index 86559040c54c..d4573032cbbc 100644
--- a/drivers/cpufreq/cris-artpec3-cpufreq.c
+++ b/drivers/cpufreq/cris-artpec3-cpufreq.c
@@ -57,7 +57,6 @@ static struct cpufreq_driver cris_freq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = cris_freq_target,
.init = cris_freq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "cris_freq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/cris-etraxfs-cpufreq.c b/drivers/cpufreq/cris-etraxfs-cpufreq.c
index 26d940d40b1d..13c3361437f7 100644
--- a/drivers/cpufreq/cris-etraxfs-cpufreq.c
+++ b/drivers/cpufreq/cris-etraxfs-cpufreq.c
@@ -57,7 +57,6 @@ static struct cpufreq_driver cris_freq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = cris_freq_target,
.init = cris_freq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "cris_freq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c
index 2cf33848d86e..28a16dc6e02e 100644
--- a/drivers/cpufreq/davinci-cpufreq.c
+++ b/drivers/cpufreq/davinci-cpufreq.c
@@ -125,7 +125,6 @@ static struct cpufreq_driver davinci_driver = {
.target_index = davinci_target,
.get = cpufreq_generic_get,
.init = davinci_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "davinci",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c
index 9012b8bb6b64..a0d2a423cea9 100644
--- a/drivers/cpufreq/e_powersaver.c
+++ b/drivers/cpufreq/e_powersaver.c
@@ -382,7 +382,6 @@ static int eps_cpu_exit(struct cpufreq_policy *policy)
unsigned int cpu = policy->cpu;
/* Bye */
- cpufreq_frequency_table_put_attr(policy->cpu);
kfree(eps_cpu[cpu]);
eps_cpu[cpu] = NULL;
return 0;
diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c
index de08acff5101..c987e94708f5 100644
--- a/drivers/cpufreq/elanfreq.c
+++ b/drivers/cpufreq/elanfreq.c
@@ -198,7 +198,6 @@ static struct cpufreq_driver elanfreq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = elanfreq_target,
.init = elanfreq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "elanfreq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index fcd2914d081a..f99cfe24e7bc 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -16,7 +16,6 @@
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/cpufreq.h>
-#include <linux/suspend.h>
#include <linux/platform_device.h>
#include <plat/cpu.h>
@@ -24,12 +23,8 @@
#include "exynos-cpufreq.h"
static struct exynos_dvfs_info *exynos_info;
-
static struct regulator *arm_regulator;
-
static unsigned int locking_frequency;
-static bool frequency_locked;
-static DEFINE_MUTEX(cpufreq_lock);
static int exynos_cpufreq_get_index(unsigned int freq)
{
@@ -134,83 +129,13 @@ out:
static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
{
- struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
- int ret = 0;
-
- mutex_lock(&cpufreq_lock);
-
- if (frequency_locked)
- goto out;
-
- ret = exynos_cpufreq_scale(freq_table[index].frequency);
-
-out:
- mutex_unlock(&cpufreq_lock);
-
- return ret;
-}
-
-#ifdef CONFIG_PM
-static int exynos_cpufreq_suspend(struct cpufreq_policy *policy)
-{
- return 0;
-}
-
-static int exynos_cpufreq_resume(struct cpufreq_policy *policy)
-{
- return 0;
-}
-#endif
-
-/**
- * exynos_cpufreq_pm_notifier - block CPUFREQ's activities in suspend-resume
- * context
- * @notifier
- * @pm_event
- * @v
- *
- * While frequency_locked == true, target() ignores every frequency but
- * locking_frequency. The locking_frequency value is the initial frequency,
- * which is set by the bootloader. In order to eliminate possible
- * inconsistency in clock values, we save and restore frequencies during
- * suspend and resume and block CPUFREQ activities. Note that the standard
- * suspend/resume cannot be used as they are too deep (syscore_ops) for
- * regulator actions.
- */
-static int exynos_cpufreq_pm_notifier(struct notifier_block *notifier,
- unsigned long pm_event, void *v)
-{
- int ret;
-
- switch (pm_event) {
- case PM_SUSPEND_PREPARE:
- mutex_lock(&cpufreq_lock);
- frequency_locked = true;
- mutex_unlock(&cpufreq_lock);
-
- ret = exynos_cpufreq_scale(locking_frequency);
- if (ret < 0)
- return NOTIFY_BAD;
-
- break;
-
- case PM_POST_SUSPEND:
- mutex_lock(&cpufreq_lock);
- frequency_locked = false;
- mutex_unlock(&cpufreq_lock);
- break;
- }
-
- return NOTIFY_OK;
+ return exynos_cpufreq_scale(exynos_info->freq_table[index].frequency);
}
-static struct notifier_block exynos_cpufreq_nb = {
- .notifier_call = exynos_cpufreq_pm_notifier,
-};
-
static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
policy->clk = exynos_info->cpu_clk;
+ policy->suspend_freq = locking_frequency;
return cpufreq_generic_init(policy, exynos_info->freq_table, 100000);
}
@@ -220,15 +145,13 @@ static struct cpufreq_driver exynos_driver = {
.target_index = exynos_target,
.get = cpufreq_generic_get,
.init = exynos_cpufreq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "exynos_cpufreq",
.attr = cpufreq_generic_attr,
#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
.boost_supported = true,
#endif
#ifdef CONFIG_PM
- .suspend = exynos_cpufreq_suspend,
- .resume = exynos_cpufreq_resume,
+ .suspend = cpufreq_generic_suspend,
#endif
};
@@ -263,19 +186,13 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
goto err_vdd_arm;
}
+ /* Done here as we want to capture boot frequency */
locking_frequency = clk_get_rate(exynos_info->cpu_clk) / 1000;
- register_pm_notifier(&exynos_cpufreq_nb);
-
- if (cpufreq_register_driver(&exynos_driver)) {
- pr_err("%s: failed to register cpufreq driver\n", __func__);
- goto err_cpufreq;
- }
-
- return 0;
-err_cpufreq:
- unregister_pm_notifier(&exynos_cpufreq_nb);
+ if (!cpufreq_register_driver(&exynos_driver))
+ return 0;
+ pr_err("%s: failed to register cpufreq driver\n", __func__);
regulator_put(arm_regulator);
err_vdd_arm:
kfree(exynos_info);
diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c
index 49b756015316..a6b8214d7b77 100644
--- a/drivers/cpufreq/exynos5440-cpufreq.c
+++ b/drivers/cpufreq/exynos5440-cpufreq.c
@@ -219,7 +219,7 @@ static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
freqs.old = policy->cur;
freqs.new = freq_table[index].frequency;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
/* Set the target frequency in all C0_3_PSTATE register */
for_each_cpu(i, policy->cpus) {
@@ -258,7 +258,7 @@ static void exynos_cpufreq_work(struct work_struct *work)
dev_crit(dvfs_info->dev, "New frequency out of range\n");
freqs.new = freqs.old;
}
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
cpufreq_cpu_put(policy);
mutex_unlock(&cpufreq_lock);
@@ -312,7 +312,6 @@ static struct cpufreq_driver exynos_driver = {
.target_index = exynos_target,
.get = cpufreq_generic_get,
.init = exynos_cpufreq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = CPUFREQ_NAME,
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index 8e54f97899ba..65a477075b3f 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -91,8 +91,8 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
/*
- * Generic routine to verify policy & frequency table, requires driver to call
- * cpufreq_frequency_table_get_attr() prior to it.
+ * Generic routine to verify policy & frequency table, requires driver to set
+ * policy->freq_table prior to it.
*/
int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy)
{
@@ -203,8 +203,6 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
-static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
-
/**
* show_available_freqs - show available frequencies for the specified CPU
*/
@@ -212,15 +210,12 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
bool show_boost)
{
unsigned int i = 0;
- unsigned int cpu = policy->cpu;
ssize_t count = 0;
- struct cpufreq_frequency_table *table;
+ struct cpufreq_frequency_table *table = policy->freq_table;
- if (!per_cpu(cpufreq_show_table, cpu))
+ if (!table)
return -ENODEV;
- table = per_cpu(cpufreq_show_table, cpu);
-
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
@@ -283,49 +278,24 @@ struct freq_attr *cpufreq_generic_attr[] = {
};
EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
-/*
- * if you use these, you must assure that the frequency table is valid
- * all the time between get_attr and put_attr!
- */
-void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
- unsigned int cpu)
-{
- pr_debug("setting show_table for cpu %u to %p\n", cpu, table);
- per_cpu(cpufreq_show_table, cpu) = table;
-}
-EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr);
-
-void cpufreq_frequency_table_put_attr(unsigned int cpu)
-{
- pr_debug("clearing show_table for cpu %u\n", cpu);
- per_cpu(cpufreq_show_table, cpu) = NULL;
-}
-EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
-
int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
int ret = cpufreq_frequency_table_cpuinfo(policy, table);
if (!ret)
- cpufreq_frequency_table_get_attr(table, policy->cpu);
+ policy->freq_table = table;
return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
-void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy)
-{
- pr_debug("Updating show_table for new_cpu %u from last_cpu %u\n",
- policy->cpu, policy->last_cpu);
- per_cpu(cpufreq_show_table, policy->cpu) = per_cpu(cpufreq_show_table,
- policy->last_cpu);
- per_cpu(cpufreq_show_table, policy->last_cpu) = NULL;
-}
+struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu);
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
{
- return per_cpu(cpufreq_show_table, cpu);
+ struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
+ return policy ? policy->freq_table : NULL;
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c
index d83e8266a58e..1d723dc8880c 100644
--- a/drivers/cpufreq/gx-suspmod.c
+++ b/drivers/cpufreq/gx-suspmod.c
@@ -265,7 +265,7 @@ static void gx_set_cpuspeed(struct cpufreq_policy *policy, unsigned int khz)
freqs.new = new_khz;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
local_irq_save(flags);
if (new_khz != stock_freq) {
@@ -314,7 +314,7 @@ static void gx_set_cpuspeed(struct cpufreq_policy *policy, unsigned int khz)
gx_params->pci_suscfg = suscfg;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
pr_debug("suspend modulation w/ duration of ON:%d us, OFF:%d us\n",
gx_params->on_duration * 32, gx_params->off_duration * 32);
diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c
index 53c6ac637e10..a22b5d182e0e 100644
--- a/drivers/cpufreq/ia64-acpi-cpufreq.c
+++ b/drivers/cpufreq/ia64-acpi-cpufreq.c
@@ -332,7 +332,6 @@ acpi_cpufreq_cpu_exit (
pr_debug("acpi_cpufreq_cpu_exit\n");
if (data) {
- cpufreq_frequency_table_put_attr(policy->cpu);
acpi_io_data[policy->cpu] = NULL;
acpi_processor_unregister_performance(&data->acpi_data,
policy->cpu);
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index ce69059be1fc..e27fca86fe4f 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -144,7 +144,6 @@ static struct cpufreq_driver imx6q_cpufreq_driver = {
.target_index = imx6q_set_target,
.get = cpufreq_generic_get,
.init = imx6q_cpufreq_init,
- .exit = cpufreq_generic_exit,
.name = "imx6q-cpufreq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/integrator-cpufreq.c b/drivers/cpufreq/integrator-cpufreq.c
index 0e27844e8c2d..e5122f1bfe78 100644
--- a/drivers/cpufreq/integrator-cpufreq.c
+++ b/drivers/cpufreq/integrator-cpufreq.c
@@ -122,7 +122,7 @@ static int integrator_set_target(struct cpufreq_policy *policy,
return 0;
}
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET);
@@ -143,7 +143,7 @@ static int integrator_set_target(struct cpufreq_policy *policy,
*/
set_cpus_allowed(current, cpus_allowed);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
return 0;
}
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index c788abf1c457..099967302bf2 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -34,12 +34,15 @@
#define SAMPLE_COUNT 3
-#define BYT_RATIOS 0x66a
-#define BYT_VIDS 0x66b
+#define BYT_RATIOS 0x66a
+#define BYT_VIDS 0x66b
+#define BYT_TURBO_RATIOS 0x66c
-#define FRAC_BITS 8
+
+#define FRAC_BITS 6
#define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
#define fp_toint(X) ((X) >> FRAC_BITS)
+#define FP_ROUNDUP(X) ((X) += 1 << FRAC_BITS)
static inline int32_t mul_fp(int32_t x, int32_t y)
{
@@ -96,8 +99,7 @@ struct cpudata {
u64 prev_aperf;
u64 prev_mperf;
unsigned long long prev_tsc;
- int sample_ptr;
- struct sample samples[SAMPLE_COUNT];
+ struct sample sample;
};
static struct cpudata **all_cpu_data;
@@ -151,7 +153,7 @@ static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
pid->setpoint = setpoint;
pid->deadband = deadband;
pid->integral = int_tofp(integral);
- pid->last_err = setpoint - busy;
+ pid->last_err = int_tofp(setpoint) - int_tofp(busy);
}
static inline void pid_p_gain_set(struct _pid *pid, int percent)
@@ -357,7 +359,7 @@ static int byt_get_min_pstate(void)
{
u64 value;
rdmsrl(BYT_RATIOS, value);
- return value & 0xFF;
+ return (value >> 8) & 0xFF;
}
static int byt_get_max_pstate(void)
@@ -367,6 +369,13 @@ static int byt_get_max_pstate(void)
return (value >> 16) & 0xFF;
}
+static int byt_get_turbo_pstate(void)
+{
+ u64 value;
+ rdmsrl(BYT_TURBO_RATIOS, value);
+ return value & 0x3F;
+}
+
static void byt_set_pstate(struct cpudata *cpudata, int pstate)
{
u64 val;
@@ -437,7 +446,7 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate)
if (limits.no_turbo)
val |= (u64)1 << 32;
- wrmsrl(MSR_IA32_PERF_CTL, val);
+ wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
}
static struct cpu_defaults core_params = {
@@ -469,7 +478,7 @@ static struct cpu_defaults byt_params = {
.funcs = {
.get_max = byt_get_max_pstate,
.get_min = byt_get_min_pstate,
- .get_turbo = byt_get_max_pstate,
+ .get_turbo = byt_get_turbo_pstate,
.set = byt_set_pstate,
.get_vid = byt_get_vid,
},
@@ -547,18 +556,20 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
static inline void intel_pstate_calc_busy(struct cpudata *cpu,
struct sample *sample)
{
- u64 core_pct;
- u64 c0_pct;
+ int32_t core_pct;
+ int32_t c0_pct;
+
+ core_pct = div_fp(int_tofp((sample->aperf)),
+ int_tofp((sample->mperf)));
+ core_pct = mul_fp(core_pct, int_tofp(100));
+ FP_ROUNDUP(core_pct);
- core_pct = div64_u64(sample->aperf * 100, sample->mperf);
+ c0_pct = div_fp(int_tofp(sample->mperf), int_tofp(sample->tsc));
- c0_pct = div64_u64(sample->mperf * 100, sample->tsc);
sample->freq = fp_toint(
- mul_fp(int_tofp(cpu->pstate.max_pstate),
- int_tofp(core_pct * 1000)));
+ mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct));
- sample->core_pct_busy = mul_fp(int_tofp(core_pct),
- div_fp(int_tofp(c0_pct + 1), int_tofp(100)));
+ sample->core_pct_busy = mul_fp(core_pct, c0_pct);
}
static inline void intel_pstate_sample(struct cpudata *cpu)
@@ -570,15 +581,18 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
rdmsrl(MSR_IA32_MPERF, mperf);
tsc = native_read_tsc();
- cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT;
- cpu->samples[cpu->sample_ptr].aperf = aperf;
- cpu->samples[cpu->sample_ptr].mperf = mperf;
- cpu->samples[cpu->sample_ptr].tsc = tsc;
- cpu->samples[cpu->sample_ptr].aperf -= cpu->prev_aperf;
- cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf;
- cpu->samples[cpu->sample_ptr].tsc -= cpu->prev_tsc;
+ aperf = aperf >> FRAC_BITS;
+ mperf = mperf >> FRAC_BITS;
+ tsc = tsc >> FRAC_BITS;
+
+ cpu->sample.aperf = aperf;
+ cpu->sample.mperf = mperf;
+ cpu->sample.tsc = tsc;
+ cpu->sample.aperf -= cpu->prev_aperf;
+ cpu->sample.mperf -= cpu->prev_mperf;
+ cpu->sample.tsc -= cpu->prev_tsc;
- intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]);
+ intel_pstate_calc_busy(cpu, &cpu->sample);
cpu->prev_aperf = aperf;
cpu->prev_mperf = mperf;
@@ -598,10 +612,11 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
{
int32_t core_busy, max_pstate, current_pstate;
- core_busy = cpu->samples[cpu->sample_ptr].core_pct_busy;
+ core_busy = cpu->sample.core_pct_busy;
max_pstate = int_tofp(cpu->pstate.max_pstate);
current_pstate = int_tofp(cpu->pstate.current_pstate);
- return mul_fp(core_busy, div_fp(max_pstate, current_pstate));
+ core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
+ return FP_ROUNDUP(core_busy);
}
static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
@@ -631,7 +646,7 @@ static void intel_pstate_timer_func(unsigned long __data)
intel_pstate_sample(cpu);
- sample = &cpu->samples[cpu->sample_ptr];
+ sample = &cpu->sample;
intel_pstate_adjust_busy_pstate(cpu);
@@ -712,7 +727,7 @@ static unsigned int intel_pstate_get(unsigned int cpu_num)
cpu = all_cpu_data[cpu_num];
if (!cpu)
return 0;
- sample = &cpu->samples[cpu->sample_ptr];
+ sample = &cpu->sample;
return sample->freq;
}
@@ -756,14 +771,17 @@ static int intel_pstate_verify_policy(struct cpufreq_policy *policy)
return 0;
}
-static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
+static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
{
- int cpu = policy->cpu;
+ int cpu_num = policy->cpu;
+ struct cpudata *cpu = all_cpu_data[cpu_num];
- del_timer(&all_cpu_data[cpu]->timer);
- kfree(all_cpu_data[cpu]);
- all_cpu_data[cpu] = NULL;
- return 0;
+ pr_info("intel_pstate CPU %d exiting\n", cpu_num);
+
+ del_timer_sync(&all_cpu_data[cpu_num]->timer);
+ intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
+ kfree(all_cpu_data[cpu_num]);
+ all_cpu_data[cpu_num] = NULL;
}
static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
@@ -801,7 +819,7 @@ static struct cpufreq_driver intel_pstate_driver = {
.setpolicy = intel_pstate_set_policy,
.get = intel_pstate_get,
.init = intel_pstate_cpu_init,
- .exit = intel_pstate_cpu_exit,
+ .stop_cpu = intel_pstate_stop_cpu,
.name = "intel_pstate",
};
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c
index eb7abe345b50..3d114bc5a97a 100644
--- a/drivers/cpufreq/kirkwood-cpufreq.c
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -102,7 +102,6 @@ static struct cpufreq_driver kirkwood_cpufreq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = kirkwood_cpufreq_target,
.init = kirkwood_cpufreq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "kirkwood-cpufreq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index 45bafddfd8ea..5c440f87ba8a 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -269,7 +269,7 @@ static void longhaul_setstate(struct cpufreq_policy *policy,
freqs.old = calc_speed(longhaul_get_cpu_mult());
freqs.new = speed;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
fsb, mult/10, mult%10, print_speed(speed/1000));
@@ -386,7 +386,7 @@ retry_loop:
}
}
/* Report true CPU frequency */
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
if (!bm_timeout)
printk(KERN_INFO PFX "Warning: Timeout while waiting for "
@@ -913,7 +913,6 @@ static struct cpufreq_driver longhaul_driver = {
.target_index = longhaul_target,
.get = longhaul_get,
.init = longhaul_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "longhaul",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c
index b6581abc9207..a3588d61d933 100644
--- a/drivers/cpufreq/loongson2_cpufreq.c
+++ b/drivers/cpufreq/loongson2_cpufreq.c
@@ -104,7 +104,6 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
static int loongson2_cpufreq_exit(struct cpufreq_policy *policy)
{
- cpufreq_frequency_table_put_attr(policy->cpu);
clk_put(policy->clk);
return 0;
}
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 590f5b66d181..5f69c9aa703c 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -143,7 +143,6 @@ fail:
static int omap_cpu_exit(struct cpufreq_policy *policy)
{
- cpufreq_frequency_table_put_attr(policy->cpu);
freq_table_free();
clk_put(policy->clk);
return 0;
diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c
index 3d1cba9fd5f9..74f593e70e19 100644
--- a/drivers/cpufreq/p4-clockmod.c
+++ b/drivers/cpufreq/p4-clockmod.c
@@ -237,7 +237,6 @@ static struct cpufreq_driver p4clockmod_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = cpufreq_p4_target,
.init = cpufreq_p4_cpu_init,
- .exit = cpufreq_generic_exit,
.get = cpufreq_p4_get,
.name = "p4-clockmod",
.attr = cpufreq_generic_attr,
diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c
index 0426008380d8..6a2b7d3e85a7 100644
--- a/drivers/cpufreq/pasemi-cpufreq.c
+++ b/drivers/cpufreq/pasemi-cpufreq.c
@@ -234,7 +234,6 @@ static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy)
if (sdcpwr_mapbase)
iounmap(sdcpwr_mapbase);
- cpufreq_frequency_table_put_attr(policy->cpu);
return 0;
}
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 1c0f1067af73..728a2d879499 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -215,7 +215,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
freqs.old = policy->cur;
freqs.new = target_freq;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
input_buffer = 0x1 | (((target_freq * 100)
/ (ioread32(&pcch_hdr->nominal) * 1000)) << 8);
@@ -231,7 +231,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
status = ioread16(&pcch_hdr->status);
iowrite16(0, &pcch_hdr->status);
- cpufreq_notify_post_transition(policy, &freqs, status != CMD_COMPLETE);
+ cpufreq_freq_transition_end(policy, &freqs, status != CMD_COMPLETE);
spin_unlock(&pcc_lock);
if (status != CMD_COMPLETE) {
diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c
index b9a444e358b5..62c6f2e5afce 100644
--- a/drivers/cpufreq/powernow-k6.c
+++ b/drivers/cpufreq/powernow-k6.c
@@ -148,11 +148,11 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
freqs.old = busfreq * powernow_k6_get_cpu_multiplier();
freqs.new = busfreq * clock_ratio[best_i].driver_data;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
powernow_k6_set_cpu_multiplier(best_i);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
return 0;
}
@@ -231,7 +231,6 @@ static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
if (i == max_multiplier)
powernow_k6_target(policy, i);
}
- cpufreq_frequency_table_put_attr(policy->cpu);
return 0;
}
diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c
index 946708a1d745..f911645c3f6d 100644
--- a/drivers/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -269,7 +269,7 @@ static int powernow_target(struct cpufreq_policy *policy, unsigned int index)
freqs.new = powernow_table[index].frequency;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
/* Now do the magic poking into the MSRs. */
@@ -290,7 +290,7 @@ static int powernow_target(struct cpufreq_policy *policy, unsigned int index)
if (have_a0 == 1)
local_irq_enable();
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
return 0;
}
@@ -664,8 +664,6 @@ static int powernow_cpu_init(struct cpufreq_policy *policy)
static int powernow_cpu_exit(struct cpufreq_policy *policy)
{
- cpufreq_frequency_table_put_attr(policy->cpu);
-
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
if (acpi_processor_perf) {
acpi_processor_unregister_performance(acpi_processor_perf, 0);
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index e10b646634d7..770a9e1b3468 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -963,9 +963,9 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
policy = cpufreq_cpu_get(smp_processor_id());
cpufreq_cpu_put(policy);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
res = transition_fid_vid(data, fid, vid);
- cpufreq_notify_post_transition(policy, &freqs, res);
+ cpufreq_freq_transition_end(policy, &freqs, res);
return res;
}
@@ -1076,7 +1076,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
{
struct powernow_k8_data *data;
struct init_on_cpu init_on_cpu;
- int rc;
+ int rc, cpu;
smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1);
if (rc)
@@ -1140,7 +1140,9 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n",
data->currfid, data->currvid);
- per_cpu(powernow_data, pol->cpu) = data;
+ /* Point all the CPUs in this policy to the same data */
+ for_each_cpu(cpu, pol->cpus)
+ per_cpu(powernow_data, cpu) = data;
return 0;
@@ -1155,17 +1157,17 @@ err_out:
static int powernowk8_cpu_exit(struct cpufreq_policy *pol)
{
struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
+ int cpu;
if (!data)
return -EINVAL;
powernow_k8_cpu_exit_acpi(data);
- cpufreq_frequency_table_put_attr(pol->cpu);
-
kfree(data->powernow_table);
kfree(data);
- per_cpu(powernow_data, pol->cpu) = NULL;
+ for_each_cpu(cpu, pol->cpus)
+ per_cpu(powernow_data, cpu) = NULL;
return 0;
}
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
index 051000f44ca2..3bd9123e7026 100644
--- a/drivers/cpufreq/ppc-corenet-cpufreq.c
+++ b/drivers/cpufreq/ppc-corenet-cpufreq.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/smp.h>
+#include <sysdev/fsl_soc.h>
/**
* struct cpu_data - per CPU data struct
@@ -205,7 +206,8 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
for_each_cpu(i, per_cpu(cpu_mask, cpu))
per_cpu(cpu_data, i) = data;
- policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+ policy->cpuinfo.transition_latency =
+ (12 * NSEC_PER_SEC) / fsl_get_sys_freq();
of_node_put(np);
return 0;
@@ -228,7 +230,6 @@ static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy)
struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
unsigned int cpu;
- cpufreq_frequency_table_put_attr(policy->cpu);
of_node_put(data->parent);
kfree(data->table);
kfree(data);
diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c
index e42ca9c31cea..af7b1cabd1e7 100644
--- a/drivers/cpufreq/ppc_cbe_cpufreq.c
+++ b/drivers/cpufreq/ppc_cbe_cpufreq.c
@@ -141,7 +141,6 @@ static struct cpufreq_driver cbe_cpufreq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = cbe_cpufreq_target,
.init = cbe_cpufreq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "cbe-cpufreq",
.flags = CPUFREQ_CONST_LOOPS,
};
diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c
index a9195a86b069..e24269ab4e9b 100644
--- a/drivers/cpufreq/pxa2xx-cpufreq.c
+++ b/drivers/cpufreq/pxa2xx-cpufreq.c
@@ -427,7 +427,6 @@ static struct cpufreq_driver pxa_cpufreq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = pxa_set_target,
.init = pxa_cpufreq_init,
- .exit = cpufreq_generic_exit,
.get = pxa_cpufreq_get,
.name = "PXA2xx",
};
diff --git a/drivers/cpufreq/pxa3xx-cpufreq.c b/drivers/cpufreq/pxa3xx-cpufreq.c
index 3785687e9d70..a01275900389 100644
--- a/drivers/cpufreq/pxa3xx-cpufreq.c
+++ b/drivers/cpufreq/pxa3xx-cpufreq.c
@@ -205,7 +205,6 @@ static struct cpufreq_driver pxa3xx_cpufreq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = pxa3xx_cpufreq_set,
.init = pxa3xx_cpufreq_init,
- .exit = cpufreq_generic_exit,
.get = pxa3xx_cpufreq_get,
.name = "pxa3xx-cpufreq",
};
diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c
index 25069741b507..a3dc192d21f9 100644
--- a/drivers/cpufreq/s3c24xx-cpufreq.c
+++ b/drivers/cpufreq/s3c24xx-cpufreq.c
@@ -217,7 +217,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
s3c_cpufreq_updateclk(clk_pclk, cpu_new.freq.pclk);
/* start the frequency change */
- cpufreq_notify_transition(policy, &freqs.freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs.freqs);
/* If hclk is staying the same, then we do not need to
* re-write the IO or the refresh timings whilst we are changing
@@ -261,7 +261,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
local_irq_restore(flags);
/* notify everyone we've done this */
- cpufreq_notify_transition(policy, &freqs.freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs.freqs, 0);
s3c_freq_dbg("%s: finished\n", __func__);
return 0;
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c
index 55a8e9fa9435..72421534fff5 100644
--- a/drivers/cpufreq/s5pv210-cpufreq.c
+++ b/drivers/cpufreq/s5pv210-cpufreq.c
@@ -18,7 +18,6 @@
#include <linux/cpufreq.h>
#include <linux/reboot.h>
#include <linux/regulator/consumer.h>
-#include <linux/suspend.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
@@ -435,18 +434,6 @@ exit:
return ret;
}
-#ifdef CONFIG_PM
-static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy)
-{
- return 0;
-}
-
-static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy)
-{
- return 0;
-}
-#endif
-
static int check_mem_type(void __iomem *dmc_reg)
{
unsigned long val;
@@ -502,6 +489,7 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
s5pv210_dram_conf[1].refresh = (__raw_readl(S5P_VA_DMC1 + 0x30) * 1000);
s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk);
+ policy->suspend_freq = SLEEP_FREQ;
return cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
out_dmc1:
@@ -511,32 +499,6 @@ out_dmc0:
return ret;
}
-static int s5pv210_cpufreq_notifier_event(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- int ret;
-
- switch (event) {
- case PM_SUSPEND_PREPARE:
- ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
- if (ret < 0)
- return NOTIFY_BAD;
-
- /* Disable updation of cpu frequency */
- no_cpufreq_access = true;
- return NOTIFY_OK;
- case PM_POST_RESTORE:
- case PM_POST_SUSPEND:
- /* Enable updation of cpu frequency */
- no_cpufreq_access = false;
- cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
-
- return NOTIFY_OK;
- }
-
- return NOTIFY_DONE;
-}
-
static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
@@ -558,15 +520,11 @@ static struct cpufreq_driver s5pv210_driver = {
.init = s5pv210_cpu_init,
.name = "s5pv210",
#ifdef CONFIG_PM
- .suspend = s5pv210_cpufreq_suspend,
- .resume = s5pv210_cpufreq_resume,
+ .suspend = cpufreq_generic_suspend,
+ .resume = cpufreq_generic_suspend, /* We need to set SLEEP FREQ again */
#endif
};
-static struct notifier_block s5pv210_cpufreq_notifier = {
- .notifier_call = s5pv210_cpufreq_notifier_event,
-};
-
static struct notifier_block s5pv210_cpufreq_reboot_notifier = {
.notifier_call = s5pv210_cpufreq_reboot_notifier_event,
};
@@ -586,7 +544,6 @@ static int __init s5pv210_cpufreq_init(void)
return PTR_ERR(int_regulator);
}
- register_pm_notifier(&s5pv210_cpufreq_notifier);
register_reboot_notifier(&s5pv210_cpufreq_reboot_notifier);
return cpufreq_register_driver(&s5pv210_driver);
diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c
index 6adb354e359c..69371bf0886d 100644
--- a/drivers/cpufreq/sc520_freq.c
+++ b/drivers/cpufreq/sc520_freq.c
@@ -93,7 +93,6 @@ static struct cpufreq_driver sc520_freq_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = sc520_freq_target,
.init = sc520_freq_cpu_init,
- .exit = cpufreq_generic_exit,
.name = "sc520_freq",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c
index 387af12503a6..86628e22b2a3 100644
--- a/drivers/cpufreq/sh-cpufreq.c
+++ b/drivers/cpufreq/sh-cpufreq.c
@@ -68,10 +68,10 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy,
freqs.new = (freq + 500) / 1000;
freqs.flags = 0;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
set_cpus_allowed_ptr(current, &cpus_allowed);
clk_set_rate(cpuclk, freq);
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
dev_dbg(dev, "set frequency %lu Hz\n", freq);
@@ -143,7 +143,6 @@ static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy)
unsigned int cpu = policy->cpu;
struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
- cpufreq_frequency_table_put_attr(cpu);
clk_put(cpuclk);
return 0;
diff --git a/drivers/cpufreq/sparc-us2e-cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c
index 62aa23e219d4..b73feeb666f9 100644
--- a/drivers/cpufreq/sparc-us2e-cpufreq.c
+++ b/drivers/cpufreq/sparc-us2e-cpufreq.c
@@ -301,10 +301,8 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
static int us2e_freq_cpu_exit(struct cpufreq_policy *policy)
{
- if (cpufreq_us2e_driver) {
- cpufreq_frequency_table_put_attr(policy->cpu);
+ if (cpufreq_us2e_driver)
us2e_freq_target(policy, 0);
- }
return 0;
}
diff --git a/drivers/cpufreq/sparc-us3-cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c
index 724ffbd7105d..9bb42ba50efa 100644
--- a/drivers/cpufreq/sparc-us3-cpufreq.c
+++ b/drivers/cpufreq/sparc-us3-cpufreq.c
@@ -156,10 +156,8 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
static int us3_freq_cpu_exit(struct cpufreq_policy *policy)
{
- if (cpufreq_us3_driver) {
- cpufreq_frequency_table_put_attr(policy->cpu);
+ if (cpufreq_us3_driver)
us3_freq_target(policy, 0);
- }
return 0;
}
diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c
index 5c86e3fa5593..4cfdcff8a310 100644
--- a/drivers/cpufreq/spear-cpufreq.c
+++ b/drivers/cpufreq/spear-cpufreq.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -163,11 +164,10 @@ static struct cpufreq_driver spear_cpufreq_driver = {
.target_index = spear_cpufreq_target,
.get = cpufreq_generic_get,
.init = spear_cpufreq_init,
- .exit = cpufreq_generic_exit,
.attr = cpufreq_generic_attr,
};
-static int spear_cpufreq_driver_init(void)
+static int spear_cpufreq_probe(struct platform_device *pdev)
{
struct device_node *np;
const struct property *prop;
@@ -235,7 +235,15 @@ out_put_node:
of_node_put(np);
return ret;
}
-late_initcall(spear_cpufreq_driver_init);
+
+static struct platform_driver spear_cpufreq_platdrv = {
+ .driver = {
+ .name = "spear-cpufreq",
+ .owner = THIS_MODULE,
+ },
+ .probe = spear_cpufreq_probe,
+};
+module_platform_driver(spear_cpufreq_platdrv);
MODULE_AUTHOR("Deepak Sikri <deepak.sikri@st.com>");
MODULE_DESCRIPTION("SPEAr CPUFreq driver");
diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c
index 4e1daca5ce3b..6723f0390f20 100644
--- a/drivers/cpufreq/speedstep-centrino.c
+++ b/drivers/cpufreq/speedstep-centrino.c
@@ -406,8 +406,6 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy)
if (!per_cpu(centrino_model, cpu))
return -ENODEV;
- cpufreq_frequency_table_put_attr(cpu);
-
per_cpu(centrino_model, cpu) = NULL;
return 0;
diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c
index 7639b2be2a90..394ac159312a 100644
--- a/drivers/cpufreq/speedstep-ich.c
+++ b/drivers/cpufreq/speedstep-ich.c
@@ -311,7 +311,6 @@ static struct cpufreq_driver speedstep_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = speedstep_target,
.init = speedstep_cpu_init,
- .exit = cpufreq_generic_exit,
.get = speedstep_get,
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c
index 998c17b42200..db5d274dc13a 100644
--- a/drivers/cpufreq/speedstep-smi.c
+++ b/drivers/cpufreq/speedstep-smi.c
@@ -280,7 +280,6 @@ static struct cpufreq_driver speedstep_driver = {
.verify = cpufreq_generic_frequency_table_verify,
.target_index = speedstep_target,
.init = speedstep_cpu_init,
- .exit = cpufreq_generic_exit,
.get = speedstep_get,
.resume = speedstep_resume,
.attr = cpufreq_generic_attr,
diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c
index e652c1bd8d0f..63f00598a251 100644
--- a/drivers/cpufreq/tegra-cpufreq.c
+++ b/drivers/cpufreq/tegra-cpufreq.c
@@ -26,7 +26,6 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
-#include <linux/suspend.h>
static struct cpufreq_frequency_table freq_table[] = {
{ .frequency = 216000 },
@@ -47,9 +46,6 @@ static struct clk *pll_x_clk;
static struct clk *pll_p_clk;
static struct clk *emc_clk;
-static DEFINE_MUTEX(tegra_cpu_lock);
-static bool is_suspended;
-
static int tegra_cpu_clk_set_rate(unsigned long rate)
{
int ret;
@@ -112,42 +108,9 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
{
- int ret = -EBUSY;
-
- mutex_lock(&tegra_cpu_lock);
-
- if (!is_suspended)
- ret = tegra_update_cpu_speed(policy,
- freq_table[index].frequency);
-
- mutex_unlock(&tegra_cpu_lock);
- return ret;
+ return tegra_update_cpu_speed(policy, freq_table[index].frequency);
}
-static int tegra_pm_notify(struct notifier_block *nb, unsigned long event,
- void *dummy)
-{
- mutex_lock(&tegra_cpu_lock);
- if (event == PM_SUSPEND_PREPARE) {
- struct cpufreq_policy *policy = cpufreq_cpu_get(0);
- is_suspended = true;
- pr_info("Tegra cpufreq suspend: setting frequency to %d kHz\n",
- freq_table[0].frequency);
- if (clk_get_rate(cpu_clk) / 1000 != freq_table[0].frequency)
- tegra_update_cpu_speed(policy, freq_table[0].frequency);
- cpufreq_cpu_put(policy);
- } else if (event == PM_POST_SUSPEND) {
- is_suspended = false;
- }
- mutex_unlock(&tegra_cpu_lock);
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block tegra_cpu_pm_notifier = {
- .notifier_call = tegra_pm_notify,
-};
-
static int tegra_cpu_init(struct cpufreq_policy *policy)
{
int ret;
@@ -166,16 +129,13 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
return ret;
}
- if (policy->cpu == 0)
- register_pm_notifier(&tegra_cpu_pm_notifier);
-
policy->clk = cpu_clk;
+ policy->suspend_freq = freq_table[0].frequency;
return 0;
}
static int tegra_cpu_exit(struct cpufreq_policy *policy)
{
- cpufreq_frequency_table_put_attr(policy->cpu);
clk_disable_unprepare(cpu_clk);
clk_disable_unprepare(emc_clk);
return 0;
@@ -190,6 +150,9 @@ static struct cpufreq_driver tegra_cpufreq_driver = {
.exit = tegra_cpu_exit,
.name = "tegra",
.attr = cpufreq_generic_attr,
+#ifdef CONFIG_PM
+ .suspend = cpufreq_generic_suspend,
+#endif
};
static int __init tegra_cpufreq_init(void)
diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c
index 36cc330b8747..13be802b6170 100644
--- a/drivers/cpufreq/unicore2-cpufreq.c
+++ b/drivers/cpufreq/unicore2-cpufreq.c
@@ -44,9 +44,9 @@ static int ucv2_target(struct cpufreq_policy *policy,
freqs.old = policy->cur;
freqs.new = target_freq;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_freq_transition_begin(policy, &freqs);
ret = clk_set_rate(policy->mclk, target_freq * 1000);
- cpufreq_notify_post_transition(policy, &freqs, ret);
+ cpufreq_freq_transition_end(policy, &freqs, ret);
return ret;
}
diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c
index e952936418d0..cb6654bfad77 100644
--- a/drivers/cpuidle/coupled.c
+++ b/drivers/cpuidle/coupled.c
@@ -323,7 +323,7 @@ static void cpuidle_coupled_poke(int cpu)
struct call_single_data *csd = &per_cpu(cpuidle_coupled_poke_cb, cpu);
if (!cpumask_test_and_set_cpu(cpu, &cpuidle_coupled_poke_pending))
- __smp_call_function_single(cpu, csd, 0);
+ smp_call_function_single_async(cpu, csd);
}
/**
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
index 78fd174c57e8..719f6fb5b1c3 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -11,9 +11,18 @@
#include <linux/cpuidle.h>
#include <linux/cpu.h>
#include <linux/notifier.h>
+#include <linux/clockchips.h>
+#include <linux/of.h>
#include <asm/machdep.h>
#include <asm/firmware.h>
+#include <asm/runlatch.h>
+
+/* Flags and constants used in PowerNV platform */
+
+#define MAX_POWERNV_IDLE_STATES 8
+#define IDLE_USE_INST_NAP 0x00010000 /* Use nap instruction */
+#define IDLE_USE_INST_SLEEP 0x00020000 /* Use sleep instruction */
struct cpuidle_driver powernv_idle_driver = {
.name = "powernv_idle",
@@ -30,12 +39,14 @@ static int snooze_loop(struct cpuidle_device *dev,
local_irq_enable();
set_thread_flag(TIF_POLLING_NRFLAG);
+ ppc64_runlatch_off();
while (!need_resched()) {
HMT_low();
HMT_very_low();
}
HMT_medium();
+ ppc64_runlatch_on();
clear_thread_flag(TIF_POLLING_NRFLAG);
smp_mb();
return index;
@@ -45,14 +56,42 @@ static int nap_loop(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
+ ppc64_runlatch_off();
power7_idle();
+ ppc64_runlatch_on();
+ return index;
+}
+
+static int fastsleep_loop(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ unsigned long old_lpcr = mfspr(SPRN_LPCR);
+ unsigned long new_lpcr;
+
+ if (unlikely(system_state < SYSTEM_RUNNING))
+ return index;
+
+ new_lpcr = old_lpcr;
+ new_lpcr &= ~(LPCR_MER | LPCR_PECE); /* lpcr[mer] must be 0 */
+
+ /* exit powersave upon external interrupt, but not decrementer
+ * interrupt.
+ */
+ new_lpcr |= LPCR_PECE0;
+
+ mtspr(SPRN_LPCR, new_lpcr);
+ power7_sleep();
+
+ mtspr(SPRN_LPCR, old_lpcr);
+
return index;
}
/*
* States for dedicated partition case.
*/
-static struct cpuidle_state powernv_states[] = {
+static struct cpuidle_state powernv_states[MAX_POWERNV_IDLE_STATES] = {
{ /* Snooze */
.name = "snooze",
.desc = "snooze",
@@ -60,13 +99,6 @@ static struct cpuidle_state powernv_states[] = {
.exit_latency = 0,
.target_residency = 0,
.enter = &snooze_loop },
- { /* NAP */
- .name = "NAP",
- .desc = "NAP",
- .flags = CPUIDLE_FLAG_TIME_VALID,
- .exit_latency = 10,
- .target_residency = 100,
- .enter = &nap_loop },
};
static int powernv_cpuidle_add_cpu_notifier(struct notifier_block *n,
@@ -127,19 +159,74 @@ static int powernv_cpuidle_driver_init(void)
return 0;
}
+static int powernv_add_idle_states(void)
+{
+ struct device_node *power_mgt;
+ struct property *prop;
+ int nr_idle_states = 1; /* Snooze */
+ int dt_idle_states;
+ u32 *flags;
+ int i;
+
+ /* Currently we have snooze statically defined */
+
+ power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
+ if (!power_mgt) {
+ pr_warn("opal: PowerMgmt Node not found\n");
+ return nr_idle_states;
+ }
+
+ prop = of_find_property(power_mgt, "ibm,cpu-idle-state-flags", NULL);
+ if (!prop) {
+ pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-flags\n");
+ return nr_idle_states;
+ }
+
+ dt_idle_states = prop->length / sizeof(u32);
+ flags = (u32 *) prop->value;
+
+ for (i = 0; i < dt_idle_states; i++) {
+
+ if (flags[i] & IDLE_USE_INST_NAP) {
+ /* Add NAP state */
+ strcpy(powernv_states[nr_idle_states].name, "Nap");
+ strcpy(powernv_states[nr_idle_states].desc, "Nap");
+ powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIME_VALID;
+ powernv_states[nr_idle_states].exit_latency = 10;
+ powernv_states[nr_idle_states].target_residency = 100;
+ powernv_states[nr_idle_states].enter = &nap_loop;
+ nr_idle_states++;
+ }
+
+ if (flags[i] & IDLE_USE_INST_SLEEP) {
+ /* Add FASTSLEEP state */
+ strcpy(powernv_states[nr_idle_states].name, "FastSleep");
+ strcpy(powernv_states[nr_idle_states].desc, "FastSleep");
+ powernv_states[nr_idle_states].flags =
+ CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TIMER_STOP;
+ powernv_states[nr_idle_states].exit_latency = 300;
+ powernv_states[nr_idle_states].target_residency = 1000000;
+ powernv_states[nr_idle_states].enter = &fastsleep_loop;
+ nr_idle_states++;
+ }
+ }
+
+ return nr_idle_states;
+}
+
/*
* powernv_idle_probe()
* Choose state table for shared versus dedicated partition
*/
static int powernv_idle_probe(void)
{
-
if (cpuidle_disable != IDLE_NO_OVERRIDE)
return -ENODEV;
if (firmware_has_feature(FW_FEATURE_OPALv3)) {
cpuidle_state_table = powernv_states;
- max_idle_state = ARRAY_SIZE(powernv_states);
+ /* Device tree can indicate more idle states */
+ max_idle_state = powernv_add_idle_states();
} else
return -ENODEV;
diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c
index 7ab564aa0b1c..6f7b01956885 100644
--- a/drivers/cpuidle/cpuidle-pseries.c
+++ b/drivers/cpuidle/cpuidle-pseries.c
@@ -17,6 +17,7 @@
#include <asm/reg.h>
#include <asm/machdep.h>
#include <asm/firmware.h>
+#include <asm/runlatch.h>
#include <asm/plpar_wrappers.h>
struct cpuidle_driver pseries_idle_driver = {
@@ -29,6 +30,7 @@ static struct cpuidle_state *cpuidle_state_table;
static inline void idle_loop_prolog(unsigned long *in_purr)
{
+ ppc64_runlatch_off();
*in_purr = mfspr(SPRN_PURR);
/*
* Indicate to the HV that we are idle. Now would be
@@ -45,6 +47,10 @@ static inline void idle_loop_epilog(unsigned long in_purr)
wait_cycles += mfspr(SPRN_PURR) - in_purr;
get_lppaca()->wait_state_cycles = cpu_to_be64(wait_cycles);
get_lppaca()->idle = 0;
+
+ if (irqs_disabled())
+ local_irq_enable();
+ ppc64_runlatch_on();
}
static int snooze_loop(struct cpuidle_device *dev,
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index a55e68f2cfc8..8236746e46bb 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -65,6 +65,26 @@ int cpuidle_play_dead(void)
}
/**
+ * cpuidle_enabled - check if the cpuidle framework is ready
+ * @dev: cpuidle device for this cpu
+ * @drv: cpuidle driver for this cpu
+ *
+ * Return 0 on success, otherwise:
+ * -NODEV : the cpuidle framework is not available
+ * -EBUSY : the cpuidle framework is not initialized
+ */
+int cpuidle_enabled(struct cpuidle_driver *drv, struct cpuidle_device *dev)
+{
+ if (off || !initialized)
+ return -ENODEV;
+
+ if (!drv || !dev || !dev->enabled)
+ return -EBUSY;
+
+ return 0;
+}
+
+/**
* cpuidle_enter_state - enter the state and update stats
* @dev: cpuidle device for this cpu
* @drv: cpuidle driver for this cpu
@@ -85,7 +105,8 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
time_end = ktime_get();
- local_irq_enable();
+ if (!cpuidle_state_is_coupled(dev, drv, entered_state))
+ local_irq_enable();
diff = ktime_to_us(ktime_sub(time_end, time_start));
if (diff > INT_MAX)
@@ -108,61 +129,48 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
}
/**
- * cpuidle_idle_call - the main idle loop
+ * cpuidle_select - ask the cpuidle framework to choose an idle state
*
- * NOTE: no locks or semaphores should be used here
- * return non-zero on failure
+ * @drv: the cpuidle driver
+ * @dev: the cpuidle device
+ *
+ * Returns the index of the idle state.
*/
-int cpuidle_idle_call(void)
+int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
{
- struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
- struct cpuidle_driver *drv;
- int next_state, entered_state;
- bool broadcast;
-
- if (off || !initialized)
- return -ENODEV;
-
- /* check if the device is ready */
- if (!dev || !dev->enabled)
- return -EBUSY;
-
- drv = cpuidle_get_cpu_driver(dev);
-
- /* ask the governor for the next state */
- next_state = cpuidle_curr_governor->select(drv, dev);
- if (need_resched()) {
- dev->last_residency = 0;
- /* give the governor an opportunity to reflect on the outcome */
- if (cpuidle_curr_governor->reflect)
- cpuidle_curr_governor->reflect(dev, next_state);
- local_irq_enable();
- return 0;
- }
-
- trace_cpu_idle_rcuidle(next_state, dev->cpu);
-
- broadcast = !!(drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP);
-
- if (broadcast)
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
-
- if (cpuidle_state_is_coupled(dev, drv, next_state))
- entered_state = cpuidle_enter_state_coupled(dev, drv,
- next_state);
- else
- entered_state = cpuidle_enter_state(dev, drv, next_state);
-
- if (broadcast)
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
+ return cpuidle_curr_governor->select(drv, dev);
+}
- trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
+/**
+ * cpuidle_enter - enter into the specified idle state
+ *
+ * @drv: the cpuidle driver tied with the cpu
+ * @dev: the cpuidle device
+ * @index: the index in the idle state table
+ *
+ * Returns the index in the idle state, < 0 in case of error.
+ * The error code depends on the backend driver
+ */
+int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev,
+ int index)
+{
+ if (cpuidle_state_is_coupled(dev, drv, index))
+ return cpuidle_enter_state_coupled(dev, drv, index);
+ return cpuidle_enter_state(dev, drv, index);
+}
- /* give the governor an opportunity to reflect on the outcome */
+/**
+ * cpuidle_reflect - tell the underlying governor what was the state
+ * we were in
+ *
+ * @dev : the cpuidle device
+ * @index: the index in the idle state table
+ *
+ */
+void cpuidle_reflect(struct cpuidle_device *dev, int index)
+{
if (cpuidle_curr_governor->reflect)
- cpuidle_curr_governor->reflect(dev, entered_state);
-
- return 0;
+ cpuidle_curr_governor->reflect(dev, index);
}
/**
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 06dbe7c86199..136d6a283e0a 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -209,7 +209,7 @@ static void poll_idle_init(struct cpuidle_driver *drv)
state->exit_latency = 0;
state->target_residency = 0;
state->power_usage = -1;
- state->flags = 0;
+ state->flags = CPUIDLE_FLAG_TIME_VALID;
state->enter = poll_idle;
state->disabled = false;
}
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index cf7f2f0e4ef5..71b523293354 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -122,9 +122,8 @@ struct menu_device {
int last_state_idx;
int needs_update;
- unsigned int expected_us;
+ unsigned int next_timer_us;
unsigned int predicted_us;
- unsigned int exit_us;
unsigned int bucket;
unsigned int correction_factor[BUCKETS];
unsigned int intervals[INTERVALS];
@@ -257,7 +256,7 @@ again:
stddev = int_sqrt(stddev);
if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
|| stddev <= 20) {
- if (data->expected_us > avg)
+ if (data->next_timer_us > avg)
data->predicted_us = avg;
return;
}
@@ -289,7 +288,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
struct menu_device *data = &__get_cpu_var(menu_devices);
int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
int i;
- int multiplier;
+ unsigned int interactivity_req;
struct timespec t;
if (data->needs_update) {
@@ -298,7 +297,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
}
data->last_state_idx = 0;
- data->exit_us = 0;
/* Special case when user has set very strict latency requirement */
if (unlikely(latency_req == 0))
@@ -306,13 +304,11 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
/* determine the expected residency time, round up */
t = ktime_to_timespec(tick_nohz_get_sleep_length());
- data->expected_us =
+ data->next_timer_us =
t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC;
- data->bucket = which_bucket(data->expected_us);
-
- multiplier = performance_multiplier();
+ data->bucket = which_bucket(data->next_timer_us);
/*
* if the correction factor is 0 (eg first time init or cpu hotplug
@@ -326,17 +322,26 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
* operands are 32 bits.
* Make sure to round up for half microseconds.
*/
- data->predicted_us = div_round64((uint64_t)data->expected_us *
+ data->predicted_us = div_round64((uint64_t)data->next_timer_us *
data->correction_factor[data->bucket],
RESOLUTION * DECAY);
get_typical_interval(data);
/*
+ * Performance multiplier defines a minimum predicted idle
+ * duration / latency ratio. Adjust the latency limit if
+ * necessary.
+ */
+ interactivity_req = data->predicted_us / performance_multiplier();
+ if (latency_req > interactivity_req)
+ latency_req = interactivity_req;
+
+ /*
* We want to default to C1 (hlt), not to busy polling
* unless the timer is happening really really soon.
*/
- if (data->expected_us > 5 &&
+ if (data->next_timer_us > 5 &&
!drv->states[CPUIDLE_DRIVER_STATE_START].disabled &&
dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0)
data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
@@ -355,11 +360,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
continue;
if (s->exit_latency > latency_req)
continue;
- if (s->exit_latency * multiplier > data->predicted_us)
- continue;
data->last_state_idx = i;
- data->exit_us = s->exit_latency;
}
return data->last_state_idx;
@@ -390,36 +392,47 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
{
struct menu_device *data = &__get_cpu_var(menu_devices);
int last_idx = data->last_state_idx;
- unsigned int last_idle_us = cpuidle_get_last_residency(dev);
struct cpuidle_state *target = &drv->states[last_idx];
unsigned int measured_us;
unsigned int new_factor;
/*
- * Ugh, this idle state doesn't support residency measurements, so we
- * are basically lost in the dark. As a compromise, assume we slept
- * for the whole expected time.
+ * Try to figure out how much time passed between entry to low
+ * power state and occurrence of the wakeup event.
+ *
+ * If the entered idle state didn't support residency measurements,
+ * we are basically lost in the dark how much time passed.
+ * As a compromise, assume we slept for the whole expected time.
+ *
+ * Any measured amount of time will include the exit latency.
+ * Since we are interested in when the wakeup begun, not when it
+ * was completed, we must substract the exit latency. However, if
+ * the measured amount of time is less than the exit latency,
+ * assume the state was never reached and the exit latency is 0.
*/
- if (unlikely(!(target->flags & CPUIDLE_FLAG_TIME_VALID)))
- last_idle_us = data->expected_us;
+ if (unlikely(!(target->flags & CPUIDLE_FLAG_TIME_VALID))) {
+ /* Use timer value as is */
+ measured_us = data->next_timer_us;
+ } else {
+ /* Use measured value */
+ measured_us = cpuidle_get_last_residency(dev);
- measured_us = last_idle_us;
-
- /*
- * We correct for the exit latency; we are assuming here that the
- * exit latency happens after the event that we're interested in.
- */
- if (measured_us > data->exit_us)
- measured_us -= data->exit_us;
+ /* Deduct exit latency */
+ if (measured_us > target->exit_latency)
+ measured_us -= target->exit_latency;
+ /* Make sure our coefficients do not exceed unity */
+ if (measured_us > data->next_timer_us)
+ measured_us = data->next_timer_us;
+ }
/* Update our correction ratio */
new_factor = data->correction_factor[data->bucket];
new_factor -= new_factor / DECAY;
- if (data->expected_us > 0 && measured_us < MAX_INTERESTING)
- new_factor += RESOLUTION * measured_us / data->expected_us;
+ if (data->next_timer_us > 0 && measured_us < MAX_INTERESTING)
+ new_factor += RESOLUTION * measured_us / data->next_timer_us;
else
/*
* we were idle so long that we count it as a perfect
@@ -439,7 +452,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
data->correction_factor[data->bucket] = new_factor;
/* update the repeating-pattern data */
- data->intervals[data->interval_ptr++] = last_idle_us;
+ data->intervals[data->interval_ptr++] = measured_us;
if (data->interval_ptr >= INTERVALS)
data->interval_ptr = 0;
}
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index a0b2f7e0eedb..2042ec3656ba 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -91,26 +91,35 @@ static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
*/
static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
{
- int lev, prev_lev;
+ int lev, prev_lev, ret = 0;
unsigned long cur_time;
- lev = devfreq_get_freq_level(devfreq, freq);
- if (lev < 0)
- return lev;
-
cur_time = jiffies;
- devfreq->time_in_state[lev] +=
+
+ prev_lev = devfreq_get_freq_level(devfreq, devfreq->previous_freq);
+ if (prev_lev < 0) {
+ ret = prev_lev;
+ goto out;
+ }
+
+ devfreq->time_in_state[prev_lev] +=
cur_time - devfreq->last_stat_updated;
- if (freq != devfreq->previous_freq) {
- prev_lev = devfreq_get_freq_level(devfreq,
- devfreq->previous_freq);
+
+ lev = devfreq_get_freq_level(devfreq, freq);
+ if (lev < 0) {
+ ret = lev;
+ goto out;
+ }
+
+ if (lev != prev_lev) {
devfreq->trans_table[(prev_lev *
devfreq->profile->max_state) + lev]++;
devfreq->total_trans++;
}
- devfreq->last_stat_updated = cur_time;
- return 0;
+out:
+ devfreq->last_stat_updated = cur_time;
+ return ret;
}
/**
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 4e7918339b12..19041cefabb1 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -449,6 +449,7 @@ static const struct of_device_id sdma_dt_ids[] = {
{ .compatible = "fsl,imx51-sdma", .data = &sdma_imx51, },
{ .compatible = "fsl,imx35-sdma", .data = &sdma_imx35, },
{ .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, },
+ { .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sdma_dt_ids);
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
index 87529181efcc..4e3549a16132 100644
--- a/drivers/dma/ioat/dma.c
+++ b/drivers/dma/ioat/dma.c
@@ -77,7 +77,8 @@ static irqreturn_t ioat_dma_do_interrupt(int irq, void *data)
attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET);
for_each_set_bit(bit, &attnstatus, BITS_PER_LONG) {
chan = ioat_chan_by_index(instance, bit);
- tasklet_schedule(&chan->cleanup_task);
+ if (test_bit(IOAT_RUN, &chan->state))
+ tasklet_schedule(&chan->cleanup_task);
}
writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
@@ -93,7 +94,8 @@ static irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data)
{
struct ioat_chan_common *chan = data;
- tasklet_schedule(&chan->cleanup_task);
+ if (test_bit(IOAT_RUN, &chan->state))
+ tasklet_schedule(&chan->cleanup_task);
return IRQ_HANDLED;
}
@@ -116,7 +118,6 @@ void ioat_init_channel(struct ioatdma_device *device, struct ioat_chan_common *c
chan->timer.function = device->timer_fn;
chan->timer.data = data;
tasklet_init(&chan->cleanup_task, device->cleanup_fn, data);
- tasklet_disable(&chan->cleanup_task);
}
/**
@@ -354,13 +355,49 @@ static int ioat1_dma_alloc_chan_resources(struct dma_chan *c)
writel(((u64) chan->completion_dma) >> 32,
chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
- tasklet_enable(&chan->cleanup_task);
+ set_bit(IOAT_RUN, &chan->state);
ioat1_dma_start_null_desc(ioat); /* give chain to dma device */
dev_dbg(to_dev(chan), "%s: allocated %d descriptors\n",
__func__, ioat->desccount);
return ioat->desccount;
}
+void ioat_stop(struct ioat_chan_common *chan)
+{
+ struct ioatdma_device *device = chan->device;
+ struct pci_dev *pdev = device->pdev;
+ int chan_id = chan_num(chan);
+ struct msix_entry *msix;
+
+ /* 1/ stop irq from firing tasklets
+ * 2/ stop the tasklet from re-arming irqs
+ */
+ clear_bit(IOAT_RUN, &chan->state);
+
+ /* flush inflight interrupts */
+ switch (device->irq_mode) {
+ case IOAT_MSIX:
+ msix = &device->msix_entries[chan_id];
+ synchronize_irq(msix->vector);
+ break;
+ case IOAT_MSI:
+ case IOAT_INTX:
+ synchronize_irq(pdev->irq);
+ break;
+ default:
+ break;
+ }
+
+ /* flush inflight timers */
+ del_timer_sync(&chan->timer);
+
+ /* flush inflight tasklet runs */
+ tasklet_kill(&chan->cleanup_task);
+
+ /* final cleanup now that everything is quiesced and can't re-arm */
+ device->cleanup_fn((unsigned long) &chan->common);
+}
+
/**
* ioat1_dma_free_chan_resources - release all the descriptors
* @chan: the channel to be cleaned
@@ -379,9 +416,7 @@ static void ioat1_dma_free_chan_resources(struct dma_chan *c)
if (ioat->desccount == 0)
return;
- tasklet_disable(&chan->cleanup_task);
- del_timer_sync(&chan->timer);
- ioat1_cleanup(ioat);
+ ioat_stop(chan);
/* Delay 100ms after reset to allow internal DMA logic to quiesce
* before removing DMA descriptor resources.
@@ -526,8 +561,11 @@ ioat1_dma_prep_memcpy(struct dma_chan *c, dma_addr_t dma_dest,
static void ioat1_cleanup_event(unsigned long data)
{
struct ioat_dma_chan *ioat = to_ioat_chan((void *) data);
+ struct ioat_chan_common *chan = &ioat->base;
ioat1_cleanup(ioat);
+ if (!test_bit(IOAT_RUN, &chan->state))
+ return;
writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
}
diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h
index 11fb877ddca9..e982f00a9843 100644
--- a/drivers/dma/ioat/dma.h
+++ b/drivers/dma/ioat/dma.h
@@ -356,6 +356,7 @@ bool ioat_cleanup_preamble(struct ioat_chan_common *chan,
void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type);
void ioat_kobject_del(struct ioatdma_device *device);
int ioat_dma_setup_interrupts(struct ioatdma_device *device);
+void ioat_stop(struct ioat_chan_common *chan);
extern const struct sysfs_ops ioat_sysfs_ops;
extern struct ioat_sysfs_entry ioat_version_attr;
extern struct ioat_sysfs_entry ioat_cap_attr;
diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c
index 5d3affe7e976..8d1058085eeb 100644
--- a/drivers/dma/ioat/dma_v2.c
+++ b/drivers/dma/ioat/dma_v2.c
@@ -190,8 +190,11 @@ static void ioat2_cleanup(struct ioat2_dma_chan *ioat)
void ioat2_cleanup_event(unsigned long data)
{
struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data);
+ struct ioat_chan_common *chan = &ioat->base;
ioat2_cleanup(ioat);
+ if (!test_bit(IOAT_RUN, &chan->state))
+ return;
writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
}
@@ -553,10 +556,10 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
ioat->issued = 0;
ioat->tail = 0;
ioat->alloc_order = order;
+ set_bit(IOAT_RUN, &chan->state);
spin_unlock_bh(&ioat->prep_lock);
spin_unlock_bh(&chan->cleanup_lock);
- tasklet_enable(&chan->cleanup_task);
ioat2_start_null_desc(ioat);
/* check that we got off the ground */
@@ -566,7 +569,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
} while (i++ < 20 && !is_ioat_active(status) && !is_ioat_idle(status));
if (is_ioat_active(status) || is_ioat_idle(status)) {
- set_bit(IOAT_RUN, &chan->state);
return 1 << ioat->alloc_order;
} else {
u32 chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
@@ -809,11 +811,8 @@ void ioat2_free_chan_resources(struct dma_chan *c)
if (!ioat->ring)
return;
- tasklet_disable(&chan->cleanup_task);
- del_timer_sync(&chan->timer);
- device->cleanup_fn((unsigned long) c);
+ ioat_stop(chan);
device->reset_hw(chan);
- clear_bit(IOAT_RUN, &chan->state);
spin_lock_bh(&chan->cleanup_lock);
spin_lock_bh(&ioat->prep_lock);
diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c
index 820817e97e62..b9b38a1cf92f 100644
--- a/drivers/dma/ioat/dma_v3.c
+++ b/drivers/dma/ioat/dma_v3.c
@@ -464,8 +464,11 @@ static void ioat3_cleanup(struct ioat2_dma_chan *ioat)
static void ioat3_cleanup_event(unsigned long data)
{
struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data);
+ struct ioat_chan_common *chan = &ioat->base;
ioat3_cleanup(ioat);
+ if (!test_bit(IOAT_RUN, &chan->state))
+ return;
writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
}
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 00a2de957b23..bf18c786ed40 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -1641,6 +1641,7 @@ static void dma_tasklet(unsigned long data)
struct d40_chan *d40c = (struct d40_chan *) data;
struct d40_desc *d40d;
unsigned long flags;
+ bool callback_active;
dma_async_tx_callback callback;
void *callback_param;
@@ -1668,6 +1669,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;
@@ -1690,7 +1692,7 @@ static void dma_tasklet(unsigned long data)
spin_unlock_irqrestore(&d40c->lock, flags);
- if (callback && (d40d->txd.flags & DMA_PREP_INTERRUPT))
+ if (callback_active && callback)
callback(callback_param);
return;
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 98e14ee4833c..f8bf00010d45 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -1239,9 +1239,17 @@ static u8 f15_m30h_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
if (num_dcts_intlv == 2) {
select = (sys_addr >> 8) & 0x3;
channel = select ? 0x3 : 0;
- } else if (num_dcts_intlv == 4)
- channel = (sys_addr >> 8) & 0x7;
-
+ } else if (num_dcts_intlv == 4) {
+ u8 intlv_addr = dct_sel_interleave_addr(pvt);
+ switch (intlv_addr) {
+ case 0x4:
+ channel = (sys_addr >> 8) & 0x3;
+ break;
+ case 0x5:
+ channel = (sys_addr >> 9) & 0x3;
+ break;
+ }
+ }
return channel;
}
@@ -1799,6 +1807,17 @@ static struct amd64_family_type family_types[] = {
.read_dct_pci_cfg = f10_read_dct_pci_cfg,
}
},
+ [F16_M30H_CPUS] = {
+ .ctl_name = "F16h_M30h",
+ .f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1,
+ .f3_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F3,
+ .ops = {
+ .early_channel_count = f1x_early_channel_count,
+ .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
+ .dbam_to_cs = f16_dbam_to_chip_select,
+ .read_dct_pci_cfg = f10_read_dct_pci_cfg,
+ }
+ },
};
/*
@@ -2578,6 +2597,11 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
break;
case 0x16:
+ if (pvt->model == 0x30) {
+ fam_type = &family_types[F16_M30H_CPUS];
+ pvt->ops = &family_types[F16_M30H_CPUS].ops;
+ break;
+ }
fam_type = &family_types[F16_CPUS];
pvt->ops = &family_types[F16_CPUS].ops;
break;
@@ -2830,6 +2854,14 @@ static const struct pci_device_id amd64_pci_table[] = {
.class = 0,
.class_mask = 0,
},
+ {
+ .vendor = PCI_VENDOR_ID_AMD,
+ .device = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = 0,
+ .class_mask = 0,
+ },
{0, }
};
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 6dc1fcc25afb..d903e0c21144 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -168,6 +168,8 @@
#define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602
#define PCI_DEVICE_ID_AMD_16H_NB_F1 0x1531
#define PCI_DEVICE_ID_AMD_16H_NB_F2 0x1532
+#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F1 0x1581
+#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F2 0x1582
/*
* Function 1 - Address Map
@@ -300,6 +302,7 @@ enum amd_families {
F15_CPUS,
F15_M30H_CPUS,
F16_CPUS,
+ F16_M30H_CPUS,
NUM_FAMILIES,
};
diff --git a/drivers/edac/amd8111_edac.c b/drivers/edac/amd8111_edac.c
index ddd890052ce2..2b63f7c2d6d2 100644
--- a/drivers/edac/amd8111_edac.c
+++ b/drivers/edac/amd8111_edac.c
@@ -350,6 +350,7 @@ static int amd8111_dev_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
struct amd8111_dev_info *dev_info = &amd8111_devices[id->driver_data];
+ int ret = -ENODEV;
dev_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
dev_info->err_dev, NULL);
@@ -359,16 +360,15 @@ static int amd8111_dev_probe(struct pci_dev *dev,
"vendor %x, device %x, name %s\n",
PCI_VENDOR_ID_AMD, dev_info->err_dev,
dev_info->ctl_name);
- return -ENODEV;
+ goto err;
}
if (pci_enable_device(dev_info->dev)) {
- pci_dev_put(dev_info->dev);
printk(KERN_ERR "failed to enable:"
"vendor %x, device %x, name %s\n",
PCI_VENDOR_ID_AMD, dev_info->err_dev,
dev_info->ctl_name);
- return -ENODEV;
+ goto err_dev_put;
}
/*
@@ -381,8 +381,10 @@ static int amd8111_dev_probe(struct pci_dev *dev,
edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1,
NULL, 0, 0,
NULL, 0, dev_info->edac_idx);
- if (!dev_info->edac_dev)
- return -ENOMEM;
+ if (!dev_info->edac_dev) {
+ ret = -ENOMEM;
+ goto err_dev_put;
+ }
dev_info->edac_dev->pvt_info = dev_info;
dev_info->edac_dev->dev = &dev_info->dev->dev;
@@ -399,8 +401,7 @@ static int amd8111_dev_probe(struct pci_dev *dev,
if (edac_device_add_device(dev_info->edac_dev) > 0) {
printk(KERN_ERR "failed to add edac_dev for %s\n",
dev_info->ctl_name);
- edac_device_free_ctl_info(dev_info->edac_dev);
- return -ENODEV;
+ goto err_edac_free_ctl;
}
printk(KERN_INFO "added one edac_dev on AMD8111 "
@@ -409,6 +410,13 @@ static int amd8111_dev_probe(struct pci_dev *dev,
dev_info->ctl_name);
return 0;
+
+err_edac_free_ctl:
+ edac_device_free_ctl_info(dev_info->edac_dev);
+err_dev_put:
+ pci_dev_put(dev_info->dev);
+err:
+ return ret;
}
static void amd8111_dev_remove(struct pci_dev *dev)
@@ -437,6 +445,7 @@ static int amd8111_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data];
+ int ret = -ENODEV;
pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
pci_info->err_dev, NULL);
@@ -446,16 +455,15 @@ static int amd8111_pci_probe(struct pci_dev *dev,
"vendor %x, device %x, name %s\n",
PCI_VENDOR_ID_AMD, pci_info->err_dev,
pci_info->ctl_name);
- return -ENODEV;
+ goto err;
}
if (pci_enable_device(pci_info->dev)) {
- pci_dev_put(pci_info->dev);
printk(KERN_ERR "failed to enable:"
"vendor %x, device %x, name %s\n",
PCI_VENDOR_ID_AMD, pci_info->err_dev,
pci_info->ctl_name);
- return -ENODEV;
+ goto err_dev_put;
}
/*
@@ -465,8 +473,10 @@ static int amd8111_pci_probe(struct pci_dev *dev,
*/
pci_info->edac_idx = edac_pci_alloc_index();
pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name);
- if (!pci_info->edac_dev)
- return -ENOMEM;
+ if (!pci_info->edac_dev) {
+ ret = -ENOMEM;
+ goto err_dev_put;
+ }
pci_info->edac_dev->pvt_info = pci_info;
pci_info->edac_dev->dev = &pci_info->dev->dev;
@@ -483,8 +493,7 @@ static int amd8111_pci_probe(struct pci_dev *dev,
if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) {
printk(KERN_ERR "failed to add edac_pci for %s\n",
pci_info->ctl_name);
- edac_pci_free_ctl_info(pci_info->edac_dev);
- return -ENODEV;
+ goto err_edac_free_ctl;
}
printk(KERN_INFO "added one edac_pci on AMD8111 "
@@ -493,6 +502,13 @@ static int amd8111_pci_probe(struct pci_dev *dev,
pci_info->ctl_name);
return 0;
+
+err_edac_free_ctl:
+ edac_pci_free_ctl_info(pci_info->edac_dev);
+err_dev_put:
+ pci_dev_put(pci_info->dev);
+err:
+ return ret;
}
static void amd8111_pci_remove(struct pci_dev *dev)
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 92d54fa65f93..b2d71388172b 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -209,7 +209,6 @@ enum e752x_chips {
*/
struct e752x_pvt {
- struct pci_dev *bridge_ck;
struct pci_dev *dev_d0f0;
struct pci_dev *dev_d0f1;
u32 tolm;
@@ -891,7 +890,7 @@ static void e752x_get_error_info(struct mem_ctl_info *mci,
info->buf_ferr);
if (info->dram_ferr)
- pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR,
+ pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_FERR,
info->dram_ferr, info->dram_ferr);
pci_write_config_dword(dev, E752X_FERR_GLOBAL,
@@ -936,7 +935,7 @@ static void e752x_get_error_info(struct mem_ctl_info *mci,
info->buf_nerr);
if (info->dram_nerr)
- pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR,
+ pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_NERR,
info->dram_nerr, info->dram_nerr);
pci_write_config_dword(dev, E752X_NERR_GLOBAL,
@@ -1177,38 +1176,33 @@ static void e752x_init_mem_map_table(struct pci_dev *pdev,
static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
struct e752x_pvt *pvt)
{
- struct pci_dev *dev;
-
- pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
- pvt->dev_info->err_dev, pvt->bridge_ck);
+ pvt->dev_d0f1 = pci_get_device(PCI_VENDOR_ID_INTEL,
+ pvt->dev_info->err_dev, NULL);
- if (pvt->bridge_ck == NULL) {
- pvt->bridge_ck = pci_scan_single_device(pdev->bus,
+ if (pvt->dev_d0f1 == NULL) {
+ pvt->dev_d0f1 = pci_scan_single_device(pdev->bus,
PCI_DEVFN(0, 1));
- pci_dev_get(pvt->bridge_ck);
+ pci_dev_get(pvt->dev_d0f1);
}
- if (pvt->bridge_ck == NULL) {
+ if (pvt->dev_d0f1 == NULL) {
e752x_printk(KERN_ERR, "error reporting device not found:"
"vendor %x device 0x%x (broken BIOS?)\n",
PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
return 1;
}
- dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ pvt->dev_d0f0 = pci_get_device(PCI_VENDOR_ID_INTEL,
e752x_devs[dev_idx].ctl_dev,
NULL);
- if (dev == NULL)
+ if (pvt->dev_d0f0 == NULL)
goto fail;
- pvt->dev_d0f0 = dev;
- pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck);
-
return 0;
fail:
- pci_dev_put(pvt->bridge_ck);
+ pci_dev_put(pvt->dev_d0f1);
return 1;
}
@@ -1385,7 +1379,6 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
fail:
pci_dev_put(pvt->dev_d0f0);
pci_dev_put(pvt->dev_d0f1);
- pci_dev_put(pvt->bridge_ck);
edac_mc_free(mci);
return -ENODEV;
@@ -1419,7 +1412,6 @@ static void e752x_remove_one(struct pci_dev *pdev)
pvt = (struct e752x_pvt *)mci->pvt_info;
pci_dev_put(pvt->dev_d0f0);
pci_dev_put(pvt->dev_d0f1);
- pci_dev_put(pvt->bridge_ck);
edac_mc_free(mci);
}
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index fa1326e5a4b0..022a70273ada 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -464,6 +464,8 @@ static void i3200_remove_one(struct pci_dev *pdev)
iounmap(priv->window);
edac_mc_free(mci);
+
+ pci_disable_device(pdev);
}
static const struct pci_device_id i3200_pci_tbl[] = {
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index 36a38ee94fa8..6247d186177e 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -869,16 +869,13 @@ static void i5100_init_csrows(struct mem_ctl_info *mci)
chan, rank, 0);
dimm->nr_pages = npages;
- if (npages) {
- dimm->grain = 32;
- dimm->dtype = (priv->mtr[chan][rank].width == 4) ?
- DEV_X4 : DEV_X8;
- dimm->mtype = MEM_RDDR2;
- dimm->edac_mode = EDAC_SECDED;
- snprintf(dimm->label, sizeof(dimm->label),
- "DIMM%u",
- i5100_rank_to_slot(mci, chan, rank));
- }
+ dimm->grain = 32;
+ dimm->dtype = (priv->mtr[chan][rank].width == 4) ?
+ DEV_X4 : DEV_X8;
+ dimm->mtype = MEM_RDDR2;
+ dimm->edac_mode = EDAC_SECDED;
+ snprintf(dimm->label, sizeof(dimm->label), "DIMM%u",
+ i5100_rank_to_slot(mci, chan, rank));
edac_dbg(2, "dimm channel %d, rank %d, size %ld\n",
chan, rank, (long)PAGES_TO_MiB(npages));
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c
index e080cbfa8fc9..5381e98d9c0c 100644
--- a/drivers/edac/i5400_edac.c
+++ b/drivers/edac/i5400_edac.c
@@ -1408,6 +1408,8 @@ static void i5400_remove_one(struct pci_dev *pdev)
/* retrieve references to resources, and free those resources */
i5400_put_devices(mci);
+ pci_disable_device(pdev);
+
edac_mc_free(mci);
}
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index d63f4798f7d0..57e96a3350f0 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
@@ -943,33 +943,35 @@ static int i7300_get_devices(struct mem_ctl_info *mci)
/* Attempt to 'get' the MCH register we want */
pdev = NULL;
- while (!pvt->pci_dev_16_1_fsb_addr_map ||
- !pvt->pci_dev_16_2_fsb_err_regs) {
- pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev);
- if (!pdev) {
- /* End of list, leave */
- i7300_printk(KERN_ERR,
- "'system address,Process Bus' "
- "device not found:"
- "vendor 0x%x device 0x%x ERR funcs "
- "(broken BIOS?)\n",
- PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
- goto error;
- }
-
+ while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I7300_MCH_ERR,
+ pdev))) {
/* Store device 16 funcs 1 and 2 */
switch (PCI_FUNC(pdev->devfn)) {
case 1:
- pvt->pci_dev_16_1_fsb_addr_map = pdev;
+ if (!pvt->pci_dev_16_1_fsb_addr_map)
+ pvt->pci_dev_16_1_fsb_addr_map =
+ pci_dev_get(pdev);
break;
case 2:
- pvt->pci_dev_16_2_fsb_err_regs = pdev;
+ if (!pvt->pci_dev_16_2_fsb_err_regs)
+ pvt->pci_dev_16_2_fsb_err_regs =
+ pci_dev_get(pdev);
break;
}
}
+ if (!pvt->pci_dev_16_1_fsb_addr_map ||
+ !pvt->pci_dev_16_2_fsb_err_regs) {
+ /* At least one device was not found */
+ i7300_printk(KERN_ERR,
+ "'system address,Process Bus' device not found:"
+ "vendor 0x%x device 0x%x ERR funcs (broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
+ goto error;
+ }
+
edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s %x:%x\n",
pci_name(pvt->pci_dev_16_0_fsb_ctlr),
pvt->pci_dev_16_0_fsb_ctlr->vendor,
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 87533ca7752e..8bc83b99974b 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -1334,14 +1334,19 @@ static int i7core_get_onedevice(struct pci_dev **prev,
* is at addr 8086:2c40, instead of 8086:2c41. So, we need
* to probe for the alternate address in case of failure
*/
- if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev)
+ if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) {
+ pci_dev_get(*prev); /* pci_get_device will put it */
pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev);
+ }
- if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev)
+ if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE &&
+ !pdev) {
+ pci_dev_get(*prev); /* pci_get_device will put it */
pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,
*prev);
+ }
if (!pdev) {
if (*prev) {
@@ -1703,7 +1708,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
const struct mce *m)
{
struct i7core_pvt *pvt = mci->pvt_info;
- char *type, *optype, *err;
+ char *optype, *err;
enum hw_event_mc_err_type tp_event;
unsigned long error = m->status & 0x1ff0000l;
bool uncorrected_error = m->mcgstatus & 1ll << 61;
@@ -1716,15 +1721,11 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
u32 errnum = find_first_bit(&error, 32);
if (uncorrected_error) {
- if (ripv) {
- type = "FATAL";
+ if (ripv)
tp_event = HW_EVENT_ERR_FATAL;
- } else {
- type = "NON_FATAL";
+ else
tp_event = HW_EVENT_ERR_UNCORRECTED;
- }
} else {
- type = "CORRECTED";
tp_event = HW_EVENT_ERR_CORRECTED;
}
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 80573df0a4d7..8d0450b9b9af 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -406,8 +406,6 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
edac_dbg(0, "\n");
- ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
-
if (i82875p_setup_overfl_dev(pdev, &ovrfl_pdev, &ovrfl_window))
return -ENODEV;
drc = readl(ovrfl_window + I82875P_DRC);
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index 30f7309446a6..51b9caa0b024 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -741,6 +741,36 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
if (amd_filter_mce(m))
return NOTIFY_STOP;
+ pr_emerg(HW_ERR "%s\n", decode_error_status(m));
+
+ pr_emerg(HW_ERR "CPU:%d (%x:%x:%x) MC%d_STATUS[%s|%s|%s|%s|%s",
+ m->extcpu,
+ c->x86, c->x86_model, c->x86_mask,
+ m->bank,
+ ((m->status & MCI_STATUS_OVER) ? "Over" : "-"),
+ ((m->status & MCI_STATUS_UC) ? "UE" : "CE"),
+ ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"),
+ ((m->status & MCI_STATUS_PCC) ? "PCC" : "-"),
+ ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-"));
+
+ if (c->x86 == 0x15 || c->x86 == 0x16)
+ pr_cont("|%s|%s",
+ ((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"),
+ ((m->status & MCI_STATUS_POISON) ? "Poison" : "-"));
+
+ /* do the two bits[14:13] together */
+ ecc = (m->status >> 45) & 0x3;
+ if (ecc)
+ pr_cont("|%sECC", ((ecc == 2) ? "C" : "U"));
+
+ pr_cont("]: 0x%016llx\n", m->status);
+
+ if (m->status & MCI_STATUS_ADDRV)
+ pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr);
+
+ if (!fam_ops)
+ goto err_code;
+
switch (m->bank) {
case 0:
decode_mc0_mce(m);
@@ -774,33 +804,7 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
break;
}
- pr_emerg(HW_ERR "Error Status: %s\n", decode_error_status(m));
-
- pr_emerg(HW_ERR "CPU:%d (%x:%x:%x) MC%d_STATUS[%s|%s|%s|%s|%s",
- m->extcpu,
- c->x86, c->x86_model, c->x86_mask,
- m->bank,
- ((m->status & MCI_STATUS_OVER) ? "Over" : "-"),
- ((m->status & MCI_STATUS_UC) ? "UE" : "CE"),
- ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"),
- ((m->status & MCI_STATUS_PCC) ? "PCC" : "-"),
- ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-"));
-
- if (c->x86 == 0x15 || c->x86 == 0x16)
- pr_cont("|%s|%s",
- ((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"),
- ((m->status & MCI_STATUS_POISON) ? "Poison" : "-"));
-
- /* do the two bits[14:13] together */
- ecc = (m->status >> 45) & 0x3;
- if (ecc)
- pr_cont("|%sECC", ((ecc == 2) ? "C" : "U"));
-
- pr_cont("]: 0x%016llx\n", m->status);
-
- if (m->status & MCI_STATUS_ADDRV)
- pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr);
-
+ err_code:
amd_decode_err_code(m->status & 0xffff);
return NOTIFY_STOP;
@@ -816,10 +820,7 @@ static int __init mce_amd_init(void)
struct cpuinfo_x86 *c = &boot_cpu_data;
if (c->x86_vendor != X86_VENDOR_AMD)
- return 0;
-
- if (c->x86 < 0xf || c->x86 > 0x16)
- return 0;
+ return -ENODEV;
fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL);
if (!fam_ops)
@@ -874,7 +875,7 @@ static int __init mce_amd_init(void)
default:
printk(KERN_WARNING "Huh? What family is it: 0x%x?!\n", c->x86);
kfree(fam_ops);
- return -EINVAL;
+ fam_ops = NULL;
}
pr_info("MCE: In-kernel MCE decoding enabled.\n");
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 8f9182179a7c..f4aec2e6ef56 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -357,7 +357,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
mpc85xx_pci_isr,
- IRQF_DISABLED | IRQF_SHARED,
+ IRQF_SHARED,
"[EDAC] PCI err", pci);
if (res < 0) {
printk(KERN_ERR
@@ -633,7 +633,7 @@ static int mpc85xx_l2_err_probe(struct platform_device *op)
if (edac_op_state == EDAC_OPSTATE_INT) {
pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
- mpc85xx_l2_isr, IRQF_DISABLED,
+ mpc85xx_l2_isr, 0,
"[EDAC] L2 err", edac_dev);
if (res < 0) {
printk(KERN_ERR
@@ -1133,7 +1133,7 @@ static int mpc85xx_mc_err_probe(struct platform_device *op)
pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
mpc85xx_mc_isr,
- IRQF_DISABLED | IRQF_SHARED,
+ IRQF_SHARED,
"[EDAC] MC err", mci);
if (res < 0) {
printk(KERN_ERR "%s: Unable to request irq %d for "
diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c
index 93412d6b3af1..4bd10f94f068 100644
--- a/drivers/edac/octeon_edac-lmc.c
+++ b/drivers/edac/octeon_edac-lmc.c
@@ -5,12 +5,16 @@
*
* Copyright (C) 2009 Wind River Systems,
* written by Ralf Baechle <ralf@linux-mips.org>
+ *
+ * Copyright (c) 2013 by Cisco Systems, Inc.
+ * All rights reserved.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/edac.h>
+#include <linux/ctype.h>
#include <asm/octeon/octeon.h>
#include <asm/octeon/cvmx-lmcx-defs.h>
@@ -20,6 +24,18 @@
#define OCTEON_MAX_MC 4
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
+
+struct octeon_lmc_pvt {
+ unsigned long inject;
+ unsigned long error_type;
+ unsigned long dimm;
+ unsigned long rank;
+ unsigned long bank;
+ unsigned long row;
+ unsigned long col;
+};
+
static void octeon_lmc_edac_poll(struct mem_ctl_info *mci)
{
union cvmx_lmcx_mem_cfg0 cfg0;
@@ -55,14 +71,31 @@ static void octeon_lmc_edac_poll(struct mem_ctl_info *mci)
static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci)
{
+ struct octeon_lmc_pvt *pvt = mci->pvt_info;
union cvmx_lmcx_int int_reg;
bool do_clear = false;
char msg[64];
- int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx));
+ if (!pvt->inject)
+ int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx));
+ else {
+ if (pvt->error_type == 1)
+ int_reg.s.sec_err = 1;
+ if (pvt->error_type == 2)
+ int_reg.s.ded_err = 1;
+ }
+
if (int_reg.s.sec_err || int_reg.s.ded_err) {
union cvmx_lmcx_fadr fadr;
- fadr.u64 = cvmx_read_csr(CVMX_LMCX_FADR(mci->mc_idx));
+ if (likely(!pvt->inject))
+ fadr.u64 = cvmx_read_csr(CVMX_LMCX_FADR(mci->mc_idx));
+ else {
+ fadr.cn61xx.fdimm = pvt->dimm;
+ fadr.cn61xx.fbunk = pvt->rank;
+ fadr.cn61xx.fbank = pvt->bank;
+ fadr.cn61xx.frow = pvt->row;
+ fadr.cn61xx.fcol = pvt->col;
+ }
snprintf(msg, sizeof(msg),
"DIMM %d rank %d bank %d row %d col %d",
fadr.cn61xx.fdimm, fadr.cn61xx.fbunk,
@@ -82,8 +115,128 @@ static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci)
int_reg.s.ded_err = -1; /* Done, re-arm */
do_clear = true;
}
- if (do_clear)
- cvmx_write_csr(CVMX_LMCX_INT(mci->mc_idx), int_reg.u64);
+
+ if (do_clear) {
+ if (likely(!pvt->inject))
+ cvmx_write_csr(CVMX_LMCX_INT(mci->mc_idx), int_reg.u64);
+ else
+ pvt->inject = 0;
+ }
+}
+
+/************************ MC SYSFS parts ***********************************/
+
+/* Only a couple naming differences per template, so very similar */
+#define TEMPLATE_SHOW(reg) \
+static ssize_t octeon_mc_inject_##reg##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *data) \
+{ \
+ struct mem_ctl_info *mci = to_mci(dev); \
+ struct octeon_lmc_pvt *pvt = mci->pvt_info; \
+ return sprintf(data, "%016llu\n", (u64)pvt->reg); \
+}
+
+#define TEMPLATE_STORE(reg) \
+static ssize_t octeon_mc_inject_##reg##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *data, size_t count) \
+{ \
+ struct mem_ctl_info *mci = to_mci(dev); \
+ struct octeon_lmc_pvt *pvt = mci->pvt_info; \
+ if (isdigit(*data)) { \
+ if (!kstrtoul(data, 0, &pvt->reg)) \
+ return count; \
+ } \
+ return 0; \
+}
+
+TEMPLATE_SHOW(inject);
+TEMPLATE_STORE(inject);
+TEMPLATE_SHOW(dimm);
+TEMPLATE_STORE(dimm);
+TEMPLATE_SHOW(bank);
+TEMPLATE_STORE(bank);
+TEMPLATE_SHOW(rank);
+TEMPLATE_STORE(rank);
+TEMPLATE_SHOW(row);
+TEMPLATE_STORE(row);
+TEMPLATE_SHOW(col);
+TEMPLATE_STORE(col);
+
+static ssize_t octeon_mc_inject_error_type_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *data,
+ size_t count)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct octeon_lmc_pvt *pvt = mci->pvt_info;
+
+ if (!strncmp(data, "single", 6))
+ pvt->error_type = 1;
+ else if (!strncmp(data, "double", 6))
+ pvt->error_type = 2;
+
+ return count;
+}
+
+static ssize_t octeon_mc_inject_error_type_show(struct device *dev,
+ struct device_attribute *attr,
+ char *data)
+{
+ struct mem_ctl_info *mci = to_mci(dev);
+ struct octeon_lmc_pvt *pvt = mci->pvt_info;
+ if (pvt->error_type == 1)
+ return sprintf(data, "single");
+ else if (pvt->error_type == 2)
+ return sprintf(data, "double");
+
+ return 0;
+}
+
+static DEVICE_ATTR(inject, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_inject_show, octeon_mc_inject_inject_store);
+static DEVICE_ATTR(error_type, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_error_type_show, octeon_mc_inject_error_type_store);
+static DEVICE_ATTR(dimm, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_dimm_show, octeon_mc_inject_dimm_store);
+static DEVICE_ATTR(rank, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_rank_show, octeon_mc_inject_rank_store);
+static DEVICE_ATTR(bank, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_bank_show, octeon_mc_inject_bank_store);
+static DEVICE_ATTR(row, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_row_show, octeon_mc_inject_row_store);
+static DEVICE_ATTR(col, S_IRUGO | S_IWUSR,
+ octeon_mc_inject_col_show, octeon_mc_inject_col_store);
+
+
+static int octeon_set_mc_sysfs_attributes(struct mem_ctl_info *mci)
+{
+ int rc;
+
+ rc = device_create_file(&mci->dev, &dev_attr_inject);
+ if (rc < 0)
+ return rc;
+ rc = device_create_file(&mci->dev, &dev_attr_error_type);
+ if (rc < 0)
+ return rc;
+ rc = device_create_file(&mci->dev, &dev_attr_dimm);
+ if (rc < 0)
+ return rc;
+ rc = device_create_file(&mci->dev, &dev_attr_rank);
+ if (rc < 0)
+ return rc;
+ rc = device_create_file(&mci->dev, &dev_attr_bank);
+ if (rc < 0)
+ return rc;
+ rc = device_create_file(&mci->dev, &dev_attr_row);
+ if (rc < 0)
+ return rc;
+ rc = device_create_file(&mci->dev, &dev_attr_col);
+ if (rc < 0)
+ return rc;
+
+ return 0;
}
static int octeon_lmc_edac_probe(struct platform_device *pdev)
@@ -92,6 +245,8 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)
struct edac_mc_layer layers[1];
int mc = pdev->id;
+ opstate_init();
+
layers[0].type = EDAC_MC_LAYER_CHANNEL;
layers[0].size = 1;
layers[0].is_virt_csrow = false;
@@ -105,7 +260,7 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)
return 0;
}
- mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, 0);
+ mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, sizeof(struct octeon_lmc_pvt));
if (!mci)
return -ENXIO;
@@ -122,6 +277,12 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)
return -ENXIO;
}
+ if (octeon_set_mc_sysfs_attributes(mci)) {
+ dev_err(&pdev->dev, "octeon_set_mc_sysfs_attributes() failed\n");
+ return -ENXIO;
+ }
+
+
cfg0.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mc));
cfg0.s.intr_ded_ena = 0; /* We poll */
cfg0.s.intr_sec_ena = 0;
@@ -137,7 +298,7 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)
return 0;
}
- mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, 0);
+ mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, sizeof(struct octeon_lmc_pvt));
if (!mci)
return -ENXIO;
@@ -154,6 +315,12 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev)
return -ENXIO;
}
+ if (octeon_set_mc_sysfs_attributes(mci)) {
+ dev_err(&pdev->dev, "octeon_set_mc_sysfs_attributes() failed\n");
+ return -ENXIO;
+ }
+
+
en.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mc));
en.s.intr_ded_ena = 0; /* We poll */
en.s.intr_sec_ena = 0;
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 54e2abe671f7..347c7a1c2725 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -1263,7 +1263,7 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
struct pci_dev *pdev = NULL;
u8 bus = 0;
- sbridge_printk(KERN_INFO,
+ sbridge_printk(KERN_DEBUG,
"Seeking for: dev %02x.%d PCI ID %04x:%04x\n",
dev_descr->dev, dev_descr->func,
PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index bdb5a00f1dfa..be56e8ac95e6 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -14,10 +14,6 @@ if EXTCON
comment "Extcon Device Drivers"
-config OF_EXTCON
- def_tristate y
- depends on OF
-
config EXTCON_GPIO
tristate "GPIO extcon support"
depends on GPIOLIB
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 43eccc0e3448..bf7861ec0906 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -2,8 +2,6 @@
# Makefile for external connector class (extcon) devices
#
-obj-$(CONFIG_OF_EXTCON) += of_extcon.o
-
obj-$(CONFIG_EXTCON) += extcon-class.o
obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index c20602f601ee..98a14f6143a7 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -222,27 +222,19 @@ static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
struct snd_soc_dapm_context *dapm = arizona->dapm;
int ret;
- mutex_lock(&dapm->card->dapm_mutex);
-
ret = snd_soc_dapm_force_enable_pin(dapm, widget);
if (ret != 0)
dev_warn(arizona->dev, "Failed to enable %s: %d\n",
widget, ret);
- mutex_unlock(&dapm->card->dapm_mutex);
-
snd_soc_dapm_sync(dapm);
if (!arizona->pdata.micd_force_micbias) {
- mutex_lock(&dapm->card->dapm_mutex);
-
ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
if (ret != 0)
dev_warn(arizona->dev, "Failed to disable %s: %d\n",
widget, ret);
- mutex_unlock(&dapm->card->dapm_mutex);
-
snd_soc_dapm_sync(dapm);
}
}
@@ -304,16 +296,12 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)
ARIZONA_MICD_ENA, 0,
&change);
- mutex_lock(&dapm->card->dapm_mutex);
-
ret = snd_soc_dapm_disable_pin(dapm, widget);
if (ret != 0)
dev_warn(arizona->dev,
"Failed to disable %s: %d\n",
widget, ret);
- mutex_unlock(&dapm->card->dapm_mutex);
-
snd_soc_dapm_sync(dapm);
if (info->micd_reva) {
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c
index 76322330cbd7..7ab21aa6eaa1 100644
--- a/drivers/extcon/extcon-class.c
+++ b/drivers/extcon/extcon-class.c
@@ -31,6 +31,7 @@
#include <linux/extcon.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
+#include <linux/of.h>
/*
* extcon_cable_name suggests the standard cable names for commonly used
@@ -818,6 +819,47 @@ void extcon_dev_unregister(struct extcon_dev *edev)
}
EXPORT_SYMBOL_GPL(extcon_dev_unregister);
+#ifdef CONFIG_OF
+/*
+ * extcon_get_edev_by_phandle - Get the extcon device from devicetree
+ * @dev - instance to the given device
+ * @index - index into list of extcon_dev
+ *
+ * return the instance of extcon device
+ */
+struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
+{
+ struct device_node *node;
+ struct extcon_dev *edev;
+
+ if (!dev->of_node) {
+ dev_err(dev, "device does not have a device node entry\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ node = of_parse_phandle(dev->of_node, "extcon", index);
+ if (!node) {
+ dev_err(dev, "failed to get phandle in %s node\n",
+ dev->of_node->full_name);
+ return ERR_PTR(-ENODEV);
+ }
+
+ edev = extcon_get_extcon_dev(node->name);
+ if (!edev) {
+ dev_err(dev, "unable to get extcon device : %s\n", node->name);
+ return ERR_PTR(-ENODEV);
+ }
+
+ return edev;
+}
+#else
+struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
+{
+ return ERR_PTR(-ENOSYS);
+}
+#endif /* CONFIG_OF */
+EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle);
+
static int __init extcon_class_init(void)
{
return create_extcon_class();
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index a63a6b21c9ad..13d522255d81 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -176,9 +176,7 @@ static int gpio_extcon_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops gpio_extcon_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(NULL, gpio_extcon_resume)
-};
+static SIMPLE_DEV_PM_OPS(gpio_extcon_pm_ops, NULL, gpio_extcon_resume);
static struct platform_driver gpio_extcon_driver = {
.probe = gpio_extcon_probe,
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c
index 2aea4bcdd7f3..ddff2b72f0a8 100644
--- a/drivers/extcon/extcon-palmas.c
+++ b/drivers/extcon/extcon-palmas.c
@@ -271,10 +271,7 @@ static int palmas_usb_resume(struct device *dev)
};
#endif
-static const struct dev_pm_ops palmas_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(palmas_usb_suspend,
- palmas_usb_resume)
-};
+static SIMPLE_DEV_PM_OPS(palmas_pm_ops, palmas_usb_suspend, palmas_usb_resume);
static struct of_device_id of_palmas_match_tbl[] = {
{ .compatible = "ti,palmas-usb", },
diff --git a/drivers/extcon/of_extcon.c b/drivers/extcon/of_extcon.c
deleted file mode 100644
index 72173ecbb311..000000000000
--- a/drivers/extcon/of_extcon.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * OF helpers for External connector (extcon) framework
- *
- * Copyright (C) 2013 Texas Instruments, Inc.
- * Kishon Vijay Abraham I <kishon@ti.com>
- *
- * Copyright (C) 2013 Samsung Electronics
- * Chanwoo Choi <cw00.choi@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/extcon.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/extcon/of_extcon.h>
-
-/*
- * of_extcon_get_extcon_dev - Get the name of extcon device from devicetree
- * @dev - instance to the given device
- * @index - index into list of extcon_dev
- *
- * return the instance of extcon device
- */
-struct extcon_dev *of_extcon_get_extcon_dev(struct device *dev, int index)
-{
- struct device_node *node;
- struct extcon_dev *edev;
- struct platform_device *extcon_parent_dev;
-
- if (!dev->of_node) {
- dev_dbg(dev, "device does not have a device node entry\n");
- return ERR_PTR(-EINVAL);
- }
-
- node = of_parse_phandle(dev->of_node, "extcon", index);
- if (!node) {
- dev_dbg(dev, "failed to get phandle in %s node\n",
- dev->of_node->full_name);
- return ERR_PTR(-ENODEV);
- }
-
- extcon_parent_dev = of_find_device_by_node(node);
- if (!extcon_parent_dev) {
- dev_dbg(dev, "unable to find device by node\n");
- return ERR_PTR(-EPROBE_DEFER);
- }
-
- edev = extcon_get_extcon_dev(dev_name(&extcon_parent_dev->dev));
- if (!edev) {
- dev_dbg(dev, "unable to get extcon device : %s\n",
- dev_name(&extcon_parent_dev->dev));
- return ERR_PTR(-ENODEV);
- }
-
- return edev;
-}
-EXPORT_SYMBOL_GPL(of_extcon_get_extcon_dev);
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index de4aa409abe2..2c6d5e118ac1 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -916,7 +916,7 @@ static int lookup_existing_device(struct device *dev, void *data)
old->config_rom_retries = 0;
fw_notice(card, "rediscovered device %s\n", dev_name(dev));
- PREPARE_DELAYED_WORK(&old->work, fw_device_update);
+ old->workfn = fw_device_update;
fw_schedule_device_work(old, 0);
if (current_node == card->root_node)
@@ -1075,7 +1075,7 @@ static void fw_device_init(struct work_struct *work)
if (atomic_cmpxchg(&device->state,
FW_DEVICE_INITIALIZING,
FW_DEVICE_RUNNING) == FW_DEVICE_GONE) {
- PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+ device->workfn = fw_device_shutdown;
fw_schedule_device_work(device, SHUTDOWN_DELAY);
} else {
fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n",
@@ -1196,13 +1196,20 @@ static void fw_device_refresh(struct work_struct *work)
dev_name(&device->device), fw_rcode_string(ret));
gone:
atomic_set(&device->state, FW_DEVICE_GONE);
- PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+ device->workfn = fw_device_shutdown;
fw_schedule_device_work(device, SHUTDOWN_DELAY);
out:
if (node_id == card->root_node->node_id)
fw_schedule_bm_work(card, 0);
}
+static void fw_device_workfn(struct work_struct *work)
+{
+ struct fw_device *device = container_of(to_delayed_work(work),
+ struct fw_device, work);
+ device->workfn(work);
+}
+
void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
{
struct fw_device *device;
@@ -1252,7 +1259,8 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
* power-up after getting plugged in. We schedule the
* first config rom scan half a second after bus reset.
*/
- INIT_DELAYED_WORK(&device->work, fw_device_init);
+ device->workfn = fw_device_init;
+ INIT_DELAYED_WORK(&device->work, fw_device_workfn);
fw_schedule_device_work(device, INITIAL_DELAY);
break;
@@ -1268,7 +1276,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
if (atomic_cmpxchg(&device->state,
FW_DEVICE_RUNNING,
FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) {
- PREPARE_DELAYED_WORK(&device->work, fw_device_refresh);
+ device->workfn = fw_device_refresh;
fw_schedule_device_work(device,
device->is_local ? 0 : INITIAL_DELAY);
}
@@ -1283,7 +1291,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
smp_wmb(); /* update node_id before generation */
device->generation = card->generation;
if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
- PREPARE_DELAYED_WORK(&device->work, fw_device_update);
+ device->workfn = fw_device_update;
fw_schedule_device_work(device, 0);
}
break;
@@ -1308,7 +1316,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
device = node->data;
if (atomic_xchg(&device->state,
FW_DEVICE_GONE) == FW_DEVICE_RUNNING) {
- PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+ device->workfn = fw_device_shutdown;
fw_schedule_device_work(device,
list_empty(&card->link) ? 0 : SHUTDOWN_DELAY);
}
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index 6b895986dc22..4af0a7bad7f2 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -929,8 +929,6 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,
if (rcode == RCODE_COMPLETE) {
fwnet_transmit_packet_done(ptask);
} else {
- fwnet_transmit_packet_failed(ptask);
-
if (printk_timed_ratelimit(&j, 1000) || rcode != last_rcode) {
dev_err(&ptask->dev->netdev->dev,
"fwnet_write_complete failed: %x (skipped %d)\n",
@@ -938,8 +936,10 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,
errors_skipped = 0;
last_rcode = rcode;
- } else
+ } else {
errors_skipped++;
+ }
+ fwnet_transmit_packet_failed(ptask);
}
}
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 6f74d8d3f700..8db663219560 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -290,7 +290,6 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
#define QUIRK_NO_MSI 0x10
#define QUIRK_TI_SLLZ059 0x20
#define QUIRK_IR_WAKE 0x40
-#define QUIRK_PHY_LCTRL_TIMEOUT 0x80
/* In case of multiple matches in ohci_quirks[], only the first one is used. */
static const struct {
@@ -303,10 +302,7 @@ static const struct {
QUIRK_BE_HEADERS},
{PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6,
- QUIRK_PHY_LCTRL_TIMEOUT | QUIRK_NO_MSI},
-
- {PCI_VENDOR_ID_ATT, PCI_ANY_ID, PCI_ANY_ID,
- QUIRK_PHY_LCTRL_TIMEOUT},
+ QUIRK_NO_MSI},
{PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_SB1394, PCI_ANY_ID,
QUIRK_RESET_PACKET},
@@ -353,7 +349,6 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
", disable MSI = " __stringify(QUIRK_NO_MSI)
", TI SLLZ059 erratum = " __stringify(QUIRK_TI_SLLZ059)
", IR wake unreliable = " __stringify(QUIRK_IR_WAKE)
- ", phy LCtrl timeout = " __stringify(QUIRK_PHY_LCTRL_TIMEOUT)
")");
#define OHCI_PARAM_DEBUG_AT_AR 1
@@ -2299,9 +2294,6 @@ static int ohci_enable(struct fw_card *card,
* TI TSB82AA2 + TSB81BA3(A) cards signal LPS enabled early but
* cannot actually use the phy at that time. These need tens of
* millisecods pause between LPS write and first phy access too.
- *
- * But do not wait for 50msec on Agere/LSI cards. Their phy
- * arbitration state machine may time out during such a long wait.
*/
reg_write(ohci, OHCI1394_HCControlSet,
@@ -2309,11 +2301,8 @@ static int ohci_enable(struct fw_card *card,
OHCI1394_HCControl_postedWriteEnable);
flush_writes(ohci);
- if (!(ohci->quirks & QUIRK_PHY_LCTRL_TIMEOUT))
+ for (lps = 0, i = 0; !lps && i < 3; i++) {
msleep(50);
-
- for (lps = 0, i = 0; !lps && i < 150; i++) {
- msleep(1);
lps = reg_read(ohci, OHCI1394_HCControlSet) &
OHCI1394_HCControl_LPS;
}
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 281029daf98c..7aef911fdc71 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -146,6 +146,7 @@ struct sbp2_logical_unit {
*/
int generation;
int retries;
+ work_func_t workfn;
struct delayed_work work;
bool has_sdev;
bool blocked;
@@ -864,7 +865,7 @@ static void sbp2_login(struct work_struct *work)
/* set appropriate retry limit(s) in BUSY_TIMEOUT register */
sbp2_set_busy_timeout(lu);
- PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
+ lu->workfn = sbp2_reconnect;
sbp2_agent_reset(lu);
/* This was a re-login. */
@@ -918,7 +919,7 @@ static void sbp2_login(struct work_struct *work)
* If a bus reset happened, sbp2_update will have requeued
* lu->work already. Reset the work from reconnect to login.
*/
- PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
+ lu->workfn = sbp2_login;
}
static void sbp2_reconnect(struct work_struct *work)
@@ -952,7 +953,7 @@ static void sbp2_reconnect(struct work_struct *work)
lu->retries++ >= 5) {
dev_err(tgt_dev(tgt), "failed to reconnect\n");
lu->retries = 0;
- PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
+ lu->workfn = sbp2_login;
}
sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
@@ -972,6 +973,13 @@ static void sbp2_reconnect(struct work_struct *work)
sbp2_conditionally_unblock(lu);
}
+static void sbp2_lu_workfn(struct work_struct *work)
+{
+ struct sbp2_logical_unit *lu = container_of(to_delayed_work(work),
+ struct sbp2_logical_unit, work);
+ lu->workfn(work);
+}
+
static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
{
struct sbp2_logical_unit *lu;
@@ -998,7 +1006,8 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
lu->blocked = false;
++tgt->dont_block;
INIT_LIST_HEAD(&lu->orb_list);
- INIT_DELAYED_WORK(&lu->work, sbp2_login);
+ lu->workfn = sbp2_login;
+ INIT_DELAYED_WORK(&lu->work, sbp2_lu_workfn);
list_add_tail(&lu->link, &tgt->lu_list);
return 0;
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index 1b5e8e46226d..7160c43c59fc 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -584,7 +584,7 @@ static struct platform_driver dcdbas_driver = {
.remove = dcdbas_remove,
};
-static const struct platform_device_info dcdbas_dev_info __initdata = {
+static const struct platform_device_info dcdbas_dev_info __initconst = {
.name = DRIVER_NAME,
.id = -1,
.dma_mask = DMA_BIT_MASK(32),
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index b6bffbfd3be7..ff50aeebf0d9 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -16,18 +16,6 @@ struct file_info {
u64 size;
};
-
-
-
-static void efi_char16_printk(efi_system_table_t *sys_table_arg,
- efi_char16_t *str)
-{
- struct efi_simple_text_output_protocol *out;
-
- out = (struct efi_simple_text_output_protocol *)sys_table_arg->con_out;
- efi_call_phys2(out->output_string, out, str);
-}
-
static void efi_printk(efi_system_table_t *sys_table_arg, char *str)
{
char *s8;
@@ -65,20 +53,23 @@ again:
* allocation which may be in a new descriptor region.
*/
*map_size += sizeof(*m);
- status = efi_call_phys3(sys_table_arg->boottime->allocate_pool,
- EFI_LOADER_DATA, *map_size, (void **)&m);
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ *map_size, (void **)&m);
if (status != EFI_SUCCESS)
goto fail;
- status = efi_call_phys5(sys_table_arg->boottime->get_memory_map,
- map_size, m, &key, desc_size, &desc_version);
+ *desc_size = 0;
+ key = 0;
+ status = efi_call_early(get_memory_map, map_size, m,
+ &key, desc_size, &desc_version);
if (status == EFI_BUFFER_TOO_SMALL) {
- efi_call_phys1(sys_table_arg->boottime->free_pool, m);
+ efi_call_early(free_pool, m);
goto again;
}
if (status != EFI_SUCCESS)
- efi_call_phys1(sys_table_arg->boottime->free_pool, m);
+ efi_call_early(free_pool, m);
+
if (key_ptr && status == EFI_SUCCESS)
*key_ptr = key;
if (desc_ver && status == EFI_SUCCESS)
@@ -158,7 +149,7 @@ again:
if (!max_addr)
status = EFI_NOT_FOUND;
else {
- status = efi_call_phys4(sys_table_arg->boottime->allocate_pages,
+ status = efi_call_early(allocate_pages,
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
nr_pages, &max_addr);
if (status != EFI_SUCCESS) {
@@ -170,8 +161,7 @@ again:
*addr = max_addr;
}
- efi_call_phys1(sys_table_arg->boottime->free_pool, map);
-
+ efi_call_early(free_pool, map);
fail:
return status;
}
@@ -231,7 +221,7 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
if ((start + size) > end)
continue;
- status = efi_call_phys4(sys_table_arg->boottime->allocate_pages,
+ status = efi_call_early(allocate_pages,
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
nr_pages, &start);
if (status == EFI_SUCCESS) {
@@ -243,7 +233,7 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
if (i == map_size / desc_size)
status = EFI_NOT_FOUND;
- efi_call_phys1(sys_table_arg->boottime->free_pool, map);
+ efi_call_early(free_pool, map);
fail:
return status;
}
@@ -257,7 +247,7 @@ static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size,
return;
nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
- efi_call_phys2(sys_table_arg->boottime->free_pages, addr, nr_pages);
+ efi_call_early(free_pages, addr, nr_pages);
}
@@ -276,9 +266,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
{
struct file_info *files;
unsigned long file_addr;
- efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
u64 file_size_total;
- efi_file_io_interface_t *io;
efi_file_handle_t *fh;
efi_status_t status;
int nr_files;
@@ -319,10 +307,8 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
if (!nr_files)
return EFI_SUCCESS;
- status = efi_call_phys3(sys_table_arg->boottime->allocate_pool,
- EFI_LOADER_DATA,
- nr_files * sizeof(*files),
- (void **)&files);
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+ nr_files * sizeof(*files), (void **)&files);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n");
goto fail;
@@ -331,13 +317,8 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
str = cmd_line;
for (i = 0; i < nr_files; i++) {
struct file_info *file;
- efi_file_handle_t *h;
- efi_file_info_t *info;
efi_char16_t filename_16[256];
- unsigned long info_sz;
- efi_guid_t info_guid = EFI_FILE_INFO_ID;
efi_char16_t *p;
- u64 file_sz;
str = strstr(str, option_string);
if (!str)
@@ -368,71 +349,18 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
/* Only open the volume once. */
if (!i) {
- efi_boot_services_t *boottime;
-
- boottime = sys_table_arg->boottime;
-
- status = efi_call_phys3(boottime->handle_protocol,
- image->device_handle, &fs_proto,
- (void **)&io);
- if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
- goto free_files;
- }
-
- status = efi_call_phys2(io->open_volume, io, &fh);
- if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "Failed to open volume\n");
+ status = efi_open_volume(sys_table_arg, image,
+ (void **)&fh);
+ if (status != EFI_SUCCESS)
goto free_files;
- }
}
- status = efi_call_phys5(fh->open, fh, &h, filename_16,
- EFI_FILE_MODE_READ, (u64)0);
- if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "Failed to open file: ");
- efi_char16_printk(sys_table_arg, filename_16);
- efi_printk(sys_table_arg, "\n");
+ status = efi_file_size(sys_table_arg, fh, filename_16,
+ (void **)&file->handle, &file->size);
+ if (status != EFI_SUCCESS)
goto close_handles;
- }
- file->handle = h;
-
- info_sz = 0;
- status = efi_call_phys4(h->get_info, h, &info_guid,
- &info_sz, NULL);
- if (status != EFI_BUFFER_TOO_SMALL) {
- efi_printk(sys_table_arg, "Failed to get file info size\n");
- goto close_handles;
- }
-
-grow:
- status = efi_call_phys3(sys_table_arg->boottime->allocate_pool,
- EFI_LOADER_DATA, info_sz,
- (void **)&info);
- if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "Failed to alloc mem for file info\n");
- goto close_handles;
- }
-
- status = efi_call_phys4(h->get_info, h, &info_guid,
- &info_sz, info);
- if (status == EFI_BUFFER_TOO_SMALL) {
- efi_call_phys1(sys_table_arg->boottime->free_pool,
- info);
- goto grow;
- }
-
- file_sz = info->file_size;
- efi_call_phys1(sys_table_arg->boottime->free_pool, info);
-
- if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "Failed to get file info\n");
- goto close_handles;
- }
-
- file->size = file_sz;
- file_size_total += file_sz;
+ file_size_total += file->size;
}
if (file_size_total) {
@@ -468,10 +396,10 @@ grow:
chunksize = EFI_READ_CHUNK_SIZE;
else
chunksize = size;
- status = efi_call_phys3(fh->read,
- files[j].handle,
- &chunksize,
- (void *)addr);
+
+ status = efi_file_read(fh, files[j].handle,
+ &chunksize,
+ (void *)addr);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to read file\n");
goto free_file_total;
@@ -480,12 +408,12 @@ grow:
size -= chunksize;
}
- efi_call_phys1(fh->close, files[j].handle);
+ efi_file_close(fh, files[j].handle);
}
}
- efi_call_phys1(sys_table_arg->boottime->free_pool, files);
+ efi_call_early(free_pool, files);
*load_addr = file_addr;
*load_size = file_size_total;
@@ -497,9 +425,9 @@ free_file_total:
close_handles:
for (k = j; k < i; k++)
- efi_call_phys1(fh->close, files[k].handle);
+ efi_file_close(fh, files[k].handle);
free_files:
- efi_call_phys1(sys_table_arg->boottime->free_pool, files);
+ efi_call_early(free_pool, files);
fail:
*load_addr = 0;
*load_size = 0;
@@ -545,7 +473,7 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
* as possible while respecting the required alignment.
*/
nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
- status = efi_call_phys4(sys_table_arg->boottime->allocate_pages,
+ status = efi_call_early(allocate_pages,
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
nr_pages, &efi_addr);
new_addr = efi_addr;
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 4753bac65279..af20f1712337 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -233,7 +233,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
{SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
{UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
- {NULL_GUID, NULL, 0},
+ {NULL_GUID, NULL, NULL},
};
static __init int match_config_table(efi_guid_t *guid,
@@ -313,5 +313,8 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
}
pr_cont("\n");
early_iounmap(config_tables, efi.systab->nr_tables * sz);
+
+ set_bit(EFI_CONFIG_TABLES, &efi.flags);
+
return 0;
}
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index 3dc248239197..50ea412a25e6 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -227,7 +227,7 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
memcpy(&entry->var, new_var, count);
err = efivar_entry_set(entry, new_var->Attributes,
- new_var->DataSize, new_var->Data, false);
+ new_var->DataSize, new_var->Data, NULL);
if (err) {
printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err);
return -EIO;
diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c
index e5a67b24587a..f1ab05ea56bb 100644
--- a/drivers/firmware/google/gsmi.c
+++ b/drivers/firmware/google/gsmi.c
@@ -892,13 +892,6 @@ static __init int gsmi_init(void)
goto out_remove_sysfs_files;
}
- ret = efivars_sysfs_init();
- if (ret) {
- printk(KERN_INFO "gsmi: Failed to create efivars files\n");
- efivars_unregister(&efivars);
- goto out_remove_sysfs_files;
- }
-
register_reboot_notifier(&gsmi_reboot_notifier);
register_die_notifier(&gsmi_die_notifier);
atomic_notifier_chain_register(&panic_notifier_list,
diff --git a/drivers/firmware/google/memconsole.c b/drivers/firmware/google/memconsole.c
index 2a90ba613613..2f569aaed4c7 100644
--- a/drivers/firmware/google/memconsole.c
+++ b/drivers/firmware/google/memconsole.c
@@ -15,6 +15,7 @@
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/dmi.h>
+#include <linux/io.h>
#include <asm/bios_ebda.h>
#define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE
@@ -41,15 +42,25 @@ struct biosmemcon_ebda {
};
} __packed;
-static char *memconsole_baseaddr;
+static u32 memconsole_baseaddr;
static size_t memconsole_length;
static ssize_t memconsole_read(struct file *filp, struct kobject *kobp,
struct bin_attribute *bin_attr, char *buf,
loff_t pos, size_t count)
{
- return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr,
- memconsole_length);
+ char *memconsole;
+ ssize_t ret;
+
+ memconsole = ioremap_cache(memconsole_baseaddr, memconsole_length);
+ if (!memconsole) {
+ pr_err("memconsole: ioremap_cache failed\n");
+ return -ENOMEM;
+ }
+ ret = memory_read_from_buffer(buf, count, &pos, memconsole,
+ memconsole_length);
+ iounmap(memconsole);
+ return ret;
}
static struct bin_attribute memconsole_bin_attr = {
@@ -58,43 +69,42 @@ static struct bin_attribute memconsole_bin_attr = {
};
-static void found_v1_header(struct biosmemcon_ebda *hdr)
+static void __init found_v1_header(struct biosmemcon_ebda *hdr)
{
- printk(KERN_INFO "BIOS console v1 EBDA structure found at %p\n", hdr);
- printk(KERN_INFO "BIOS console buffer at 0x%.8x, "
+ pr_info("BIOS console v1 EBDA structure found at %p\n", hdr);
+ pr_info("BIOS console buffer at 0x%.8x, "
"start = %d, end = %d, num = %d\n",
hdr->v1.buffer_addr, hdr->v1.start,
hdr->v1.end, hdr->v1.num_chars);
memconsole_length = hdr->v1.num_chars;
- memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr);
+ memconsole_baseaddr = hdr->v1.buffer_addr;
}
-static void found_v2_header(struct biosmemcon_ebda *hdr)
+static void __init found_v2_header(struct biosmemcon_ebda *hdr)
{
- printk(KERN_INFO "BIOS console v2 EBDA structure found at %p\n", hdr);
- printk(KERN_INFO "BIOS console buffer at 0x%.8x, "
+ pr_info("BIOS console v2 EBDA structure found at %p\n", hdr);
+ pr_info("BIOS console buffer at 0x%.8x, "
"start = %d, end = %d, num_bytes = %d\n",
hdr->v2.buffer_addr, hdr->v2.start,
hdr->v2.end, hdr->v2.num_bytes);
memconsole_length = hdr->v2.end - hdr->v2.start;
- memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr
- + hdr->v2.start);
+ memconsole_baseaddr = hdr->v2.buffer_addr + hdr->v2.start;
}
/*
* Search through the EBDA for the BIOS Memory Console, and
* set the global variables to point to it. Return true if found.
*/
-static bool found_memconsole(void)
+static bool __init found_memconsole(void)
{
unsigned int address;
size_t length, cur;
address = get_bios_ebda();
if (!address) {
- printk(KERN_INFO "BIOS EBDA non-existent.\n");
+ pr_info("BIOS EBDA non-existent.\n");
return false;
}
@@ -122,7 +132,7 @@ static bool found_memconsole(void)
}
}
- printk(KERN_INFO "BIOS console EBDA structure not found!\n");
+ pr_info("BIOS console EBDA structure not found!\n");
return false;
}
@@ -139,8 +149,6 @@ MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table);
static int __init memconsole_init(void)
{
- int ret;
-
if (!dmi_check_system(memconsole_dmi_table))
return -ENODEV;
@@ -148,10 +156,7 @@ static int __init memconsole_init(void)
return -ENODEV;
memconsole_bin_attr.size = memconsole_length;
-
- ret = sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr);
-
- return ret;
+ return sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr);
}
static void __exit memconsole_exit(void)
diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c
index 24d52497524d..353fc546fb08 100644
--- a/drivers/fmc/fmc-core.c
+++ b/drivers/fmc/fmc-core.c
@@ -99,10 +99,23 @@ static ssize_t fmc_read_eeprom(struct file *file, struct kobject *kobj,
return count;
}
+static ssize_t fmc_write_eeprom(struct file *file, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev;
+ struct fmc_device *fmc;
+
+ dev = container_of(kobj, struct device, kobj);
+ fmc = container_of(dev, struct fmc_device, dev);
+ return fmc->op->write_ee(fmc, off, buf, count);
+}
+
static struct bin_attribute fmc_eeprom_attr = {
- .attr = { .name = "eeprom", .mode = S_IRUGO, },
+ .attr = { .name = "eeprom", .mode = S_IRUGO | S_IWUSR, },
.size = 8192, /* more or less standard */
.read = fmc_read_eeprom,
+ .write = fmc_write_eeprom,
};
/*
@@ -154,7 +167,7 @@ int fmc_device_register_n(struct fmc_device **devs, int n)
ret = -EINVAL;
break;
}
- if (fmc->flags == FMC_DEVICE_NO_MEZZANINE) {
+ if (fmc->flags & FMC_DEVICE_NO_MEZZANINE) {
dev_info(fmc->hwdev, "absent mezzanine in slot %d\n",
fmc->slot_id);
continue;
@@ -189,9 +202,6 @@ int fmc_device_register_n(struct fmc_device **devs, int n)
for (i = 0; i < n; i++) {
fmc = devarray[i];
- if (fmc->flags == FMC_DEVICE_NO_MEZZANINE)
- continue; /* dev_info already done above */
-
fmc->nr_slots = n; /* each slot must know how many are there */
fmc->devarray = devarray;
@@ -263,8 +273,6 @@ void fmc_device_unregister_n(struct fmc_device **devs, int n)
kfree(devs[0]->devarray);
for (i = 0; i < n; i++) {
- if (devs[i]->flags == FMC_DEVICE_NO_MEZZANINE)
- continue;
sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr);
device_del(&devs[i]->dev);
fmc_free_id_info(devs[i]);
diff --git a/drivers/fmc/fmc-sdb.c b/drivers/fmc/fmc-sdb.c
index 79adc39221ea..4603fdb74465 100644
--- a/drivers/fmc/fmc-sdb.c
+++ b/drivers/fmc/fmc-sdb.c
@@ -150,23 +150,36 @@ int fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw,
}
EXPORT_SYMBOL(fmc_reprogram);
+static char *__strip_trailing_space(char *buf, char *str, int len)
+{
+ int i = len - 1;
+
+ memcpy(buf, str, len);
+ while(i >= 0 && buf[i] == ' ')
+ buf[i--] = '\0';
+ return buf;
+}
+
+#define __sdb_string(buf, field) ({ \
+ BUILD_BUG_ON(sizeof(buf) < sizeof(field)); \
+ __strip_trailing_space(buf, (void *)(field), sizeof(field)); \
+ })
+
static void __fmc_show_sdb_tree(const struct fmc_device *fmc,
const struct sdb_array *arr)
{
+ unsigned long base = arr->baseaddr;
int i, j, n = arr->len, level = arr->level;
- const struct sdb_array *ap;
+ char buf[64];
for (i = 0; i < n; i++) {
- unsigned long base;
union sdb_record *r;
struct sdb_product *p;
struct sdb_component *c;
r = &arr->record[i];
c = &r->dev.sdb_component;
p = &c->product;
- base = 0;
- for (ap = arr; ap; ap = ap->parent)
- base += ap->baseaddr;
+
dev_info(&fmc->dev, "SDB: ");
for (j = 0; j < level; j++)
@@ -193,8 +206,8 @@ static void __fmc_show_sdb_tree(const struct fmc_device *fmc,
p->name,
__be64_to_cpu(c->addr_first) + base);
if (IS_ERR(arr->subtree[i])) {
- printk(KERN_CONT "(bridge error %li)\n",
- PTR_ERR(arr->subtree[i]));
+ dev_info(&fmc->dev, "SDB: (bridge error %li)\n",
+ PTR_ERR(arr->subtree[i]));
break;
}
__fmc_show_sdb_tree(fmc, arr->subtree[i]);
@@ -203,10 +216,20 @@ static void __fmc_show_sdb_tree(const struct fmc_device *fmc,
printk(KERN_CONT "integration\n");
break;
case sdb_type_repo_url:
- printk(KERN_CONT "repo-url\n");
+ printk(KERN_CONT "Synthesis repository: %s\n",
+ __sdb_string(buf, r->repo_url.repo_url));
break;
case sdb_type_synthesis:
- printk(KERN_CONT "synthesis-info\n");
+ printk(KERN_CONT "Bitstream '%s' ",
+ __sdb_string(buf, r->synthesis.syn_name));
+ printk(KERN_CONT "synthesized %08x by %s ",
+ __be32_to_cpu(r->synthesis.date),
+ __sdb_string(buf, r->synthesis.user_name));
+ printk(KERN_CONT "(%s version %x), ",
+ __sdb_string(buf, r->synthesis.tool_name),
+ __be32_to_cpu(r->synthesis.tool_version));
+ printk(KERN_CONT "commit %pm\n",
+ r->synthesis.commit_id);
break;
case sdb_type_empty:
printk(KERN_CONT "empty\n");
diff --git a/drivers/fmc/fmc-write-eeprom.c b/drivers/fmc/fmc-write-eeprom.c
index ee5b47904130..9bb2cbd5c9f2 100644
--- a/drivers/fmc/fmc-write-eeprom.c
+++ b/drivers/fmc/fmc-write-eeprom.c
@@ -27,7 +27,7 @@ FMC_PARAM_BUSID(fwe_drv);
/* The "file=" is like the generic "gateware=" used elsewhere */
static char *fwe_file[FMC_MAX_CARDS];
static int fwe_file_n;
-module_param_array_named(file, fwe_file, charp, &fwe_file_n, 444);
+module_param_array_named(file, fwe_file, charp, &fwe_file_n, 0444);
static int fwe_run_tlv(struct fmc_device *fmc, const struct firmware *fw,
int write)
diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c
index 9902732a382d..66cbcc108e62 100644
--- a/drivers/gpio/gpio-vr41xx.c
+++ b/drivers/gpio/gpio-vr41xx.c
@@ -81,6 +81,7 @@ static DEFINE_SPINLOCK(giu_lock);
static unsigned long giu_flags;
static void __iomem *giu_base;
+static struct gpio_chip vr41xx_gpio_chip;
#define giu_read(offset) readw(giu_base + (offset))
#define giu_write(offset, value) writew((value), giu_base + (offset))
@@ -135,12 +136,31 @@ static void unmask_giuint_low(struct irq_data *d)
giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq));
}
+static unsigned int startup_giuint(struct irq_data *data)
+{
+ if (gpio_lock_as_irq(&vr41xx_gpio_chip, data->hwirq))
+ dev_err(vr41xx_gpio_chip.dev,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ data->hwirq);
+ /* Satisfy the .enable semantics by unmasking the line */
+ unmask_giuint_low(data);
+ return 0;
+}
+
+static void shutdown_giuint(struct irq_data *data)
+{
+ mask_giuint_low(data);
+ gpio_unlock_as_irq(&vr41xx_gpio_chip, data->hwirq);
+}
+
static struct irq_chip giuint_low_irq_chip = {
.name = "GIUINTL",
.irq_ack = ack_giuint_low,
.irq_mask = mask_giuint_low,
.irq_mask_ack = mask_ack_giuint_low,
.irq_unmask = unmask_giuint_low,
+ .irq_startup = startup_giuint,
+ .irq_shutdown = shutdown_giuint,
};
static void ack_giuint_high(struct irq_data *d)
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index acf3a36c9ebc..32982da82694 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -68,15 +68,7 @@ void __armada_drm_queue_unref_work(struct drm_device *dev,
{
struct armada_private *priv = dev->dev_private;
- /*
- * Yes, we really must jump through these hoops just to store a
- * _pointer_ to something into the kfifo. This is utterly insane
- * and idiotic, because it kfifo requires the _data_ pointed to by
- * the pointer const, not the pointer itself. Not only that, but
- * you have to pass a pointer _to_ the pointer you want stored.
- */
- const struct drm_framebuffer *silly_api_alert = fb;
- WARN_ON(!kfifo_put(&priv->fb_unref, &silly_api_alert));
+ WARN_ON(!kfifo_put(&priv->fb_unref, fb));
schedule_work(&priv->fb_unref_work);
}
diff --git a/drivers/gpu/drm/bochs/Kconfig b/drivers/gpu/drm/bochs/Kconfig
index c8fcf12019f0..5f8b0c2b9a44 100644
--- a/drivers/gpu/drm/bochs/Kconfig
+++ b/drivers/gpu/drm/bochs/Kconfig
@@ -2,6 +2,7 @@ config DRM_BOCHS
tristate "DRM Support for bochs dispi vga interface (qemu stdvga)"
depends on DRM && PCI
select DRM_KMS_HELPER
+ select DRM_KMS_FB_HELPER
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index bb8f58012189..534cb89b160d 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -32,6 +32,12 @@
#include <drm/drmP.h>
#if defined(CONFIG_X86)
+
+/*
+ * clflushopt is an unordered instruction which needs fencing with mfence or
+ * sfence to avoid ordering issues. For drm_clflush_page this fencing happens
+ * in the caller.
+ */
static void
drm_clflush_page(struct page *page)
{
@@ -44,7 +50,7 @@ drm_clflush_page(struct page *page)
page_virtual = kmap_atomic(page);
for (i = 0; i < PAGE_SIZE; i += size)
- clflush(page_virtual + i);
+ clflushopt(page_virtual + i);
kunmap_atomic(page_virtual);
}
@@ -133,7 +139,7 @@ drm_clflush_virt_range(char *addr, unsigned long length)
mb();
for (; addr < end; addr += boot_cpu_data.x86_clflush_size)
clflush(addr);
- clflush(end - 1);
+ clflushopt(end - 1);
mb();
return;
}
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 7f2af9aca038..309023f12d7f 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -319,7 +319,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
pci_dev_put(pci_dev);
}
if (!dev->hose) {
- struct pci_bus *b = pci_bus_b(pci_root_buses.next);
+ struct pci_bus *b = list_entry(pci_root_buses.next,
+ struct pci_bus, node);
if (b)
dev->hose = b->sysdata;
}
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index dffc836144cc..f4dc9b7a3831 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -296,6 +296,18 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
case DRM_CAP_ASYNC_PAGE_FLIP:
req->value = dev->mode_config.async_page_flip;
break;
+ case DRM_CAP_CURSOR_WIDTH:
+ if (dev->mode_config.cursor_width)
+ req->value = dev->mode_config.cursor_width;
+ else
+ req->value = 64;
+ break;
+ case DRM_CAP_CURSOR_HEIGHT:
+ if (dev->mode_config.cursor_height)
+ req->value = dev->mode_config.cursor_height;
+ else
+ req->value = 64;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 5736aaa7e86c..f7af69bcf3f4 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -468,8 +468,8 @@ void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
} else {
list_for_each_entry_safe(dev, tmp, &driver->legacy_dev_list,
legacy_dev_list) {
- drm_put_dev(dev);
list_del(&dev->legacy_dev_list);
+ drm_put_dev(dev);
}
}
DRM_INFO("Module unloaded\n");
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 56805c39c906..bb516fdd195d 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -471,7 +471,7 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
get_dma_buf(dma_buf);
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
- if (IS_ERR_OR_NULL(sgt)) {
+ if (IS_ERR(sgt)) {
ret = PTR_ERR(sgt);
goto fail_detach;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
index 59827cc5e770..c786cd4f457b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
@@ -224,7 +224,7 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
get_dma_buf(dma_buf);
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
- if (IS_ERR_OR_NULL(sgt)) {
+ if (IS_ERR(sgt)) {
ret = PTR_ERR(sgt);
goto err_buf_detach;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 215131ab1dd2..c204b4e3356e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -172,20 +172,24 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
ret = exynos_drm_subdrv_open(dev, file);
if (ret)
- goto out;
+ goto err_file_priv_free;
anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops,
NULL, 0);
if (IS_ERR(anon_filp)) {
ret = PTR_ERR(anon_filp);
- goto out;
+ goto err_subdrv_close;
}
anon_filp->f_mode = FMODE_READ | FMODE_WRITE;
file_priv->anon_filp = anon_filp;
return ret;
-out:
+
+err_subdrv_close:
+ exynos_drm_subdrv_close(dev, file);
+
+err_file_priv_free:
kfree(file_priv);
file->driver_priv = NULL;
return ret;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 0eaf5a27e120..a8f9dba2a816 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -237,7 +237,6 @@ struct drm_exynos_file_private {
* otherwise default one.
* @da_space_size: size of device address space.
* if 0 then default value is used for it.
- * @da_space_order: order to device address space.
*/
struct exynos_drm_private {
struct drm_fb_helper *fb_helper;
@@ -255,7 +254,6 @@ struct exynos_drm_private {
unsigned long da_start;
unsigned long da_space_size;
- unsigned long da_space_order;
};
/*
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c
index fb8db0378274..b32b291f88ff 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c
@@ -36,12 +36,10 @@ int drm_create_iommu_mapping(struct drm_device *drm_dev)
priv->da_start = EXYNOS_DEV_ADDR_START;
if (!priv->da_space_size)
priv->da_space_size = EXYNOS_DEV_ADDR_SIZE;
- if (!priv->da_space_order)
- priv->da_space_order = EXYNOS_DEV_ADDR_ORDER;
mapping = arm_iommu_create_mapping(&platform_bus_type, priv->da_start,
- priv->da_space_size,
- priv->da_space_order);
+ priv->da_space_size);
+
if (IS_ERR(mapping))
return PTR_ERR(mapping);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h
index 598e60f57d4b..72376d41c512 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_iommu.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.h
@@ -14,7 +14,6 @@
#define EXYNOS_DEV_ADDR_START 0x20000000
#define EXYNOS_DEV_ADDR_SIZE 0x40000000
-#define EXYNOS_DEV_ADDR_ORDER 0x0
#ifdef CONFIG_DRM_EXYNOS_IOMMU
diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig
index 508cf99a292d..17f928ec84ea 100644
--- a/drivers/gpu/drm/gma500/Kconfig
+++ b/drivers/gpu/drm/gma500/Kconfig
@@ -10,7 +10,6 @@ config DRM_GMA500
# GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915
select ACPI_VIDEO if ACPI
select BACKLIGHT_CLASS_DEVICE if ACPI
- select VIDEO_OUTPUT_CONTROL if ACPI
select INPUT if ACPI
help
Say yes for an experimental 2D KMS framebuffer driver for the
diff --git a/drivers/gpu/drm/gma500/mmu.c b/drivers/gpu/drm/gma500/mmu.c
index 49bac41beefb..c3e67ba94446 100644
--- a/drivers/gpu/drm/gma500/mmu.c
+++ b/drivers/gpu/drm/gma500/mmu.c
@@ -520,7 +520,7 @@ struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers,
driver->has_clflush = 0;
- if (boot_cpu_has(X86_FEATURE_CLFLSH)) {
+ if (boot_cpu_has(X86_FEATURE_CLFLUSH)) {
uint32_t tfms, misc, cap0, cap4, clflush_size;
/*
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index fa18cf374470..faa77f543a07 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -1151,8 +1151,10 @@ tda998x_encoder_init(struct i2c_client *client,
priv->current_page = 0xff;
priv->cec = i2c_new_dummy(client->adapter, 0x34);
- if (!priv->cec)
+ if (!priv->cec) {
+ kfree(priv);
return -ENODEV;
+ }
priv->dpms = DRM_MODE_DPMS_OFF;
encoder_slave->slave_priv = priv;
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 73ed59eff139..bea2d67196fb 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -14,7 +14,6 @@ config DRM_I915
# but for select to work, need to select ACPI_VIDEO's dependencies, ick
select BACKLIGHT_LCD_SUPPORT if ACPI
select BACKLIGHT_CLASS_DEVICE if ACPI
- select VIDEO_OUTPUT_CONTROL if ACPI
select INPUT if ACPI
select ACPI_VIDEO if ACPI
select ACPI_BUTTON if ACPI
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 04f1f02c4019..ec7bb0fc71bc 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -403,7 +403,7 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
void intel_detect_pch(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct pci_dev *pch;
+ struct pci_dev *pch = NULL;
/* In all current cases, num_pipes is equivalent to the PCH_NOP setting
* (which really amounts to a PCH but no South Display).
@@ -424,12 +424,9 @@ void intel_detect_pch(struct drm_device *dev)
* all the ISA bridge devices and check for the first match, instead
* of only checking the first one.
*/
- pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
- while (pch) {
- struct pci_dev *curr = pch;
+ while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) {
if (pch->vendor == PCI_VENDOR_ID_INTEL) {
- unsigned short id;
- id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
+ unsigned short id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
dev_priv->pch_id = id;
if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
@@ -461,18 +458,16 @@ void intel_detect_pch(struct drm_device *dev)
DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
WARN_ON(!IS_HASWELL(dev));
WARN_ON(!IS_ULT(dev));
- } else {
- goto check_next;
- }
- pci_dev_put(pch);
+ } else
+ continue;
+
break;
}
-check_next:
- pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, curr);
- pci_dev_put(curr);
}
if (!pch)
- DRM_DEBUG_KMS("No PCH found?\n");
+ DRM_DEBUG_KMS("No PCH found.\n");
+
+ pci_dev_put(pch);
}
bool i915_semaphore_is_enabled(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 40a2b36b276b..d278be110805 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -842,7 +842,7 @@ void i915_gem_suspend_gtt_mappings(struct drm_device *dev)
dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
dev_priv->gtt.base.start / PAGE_SIZE,
dev_priv->gtt.base.total / PAGE_SIZE,
- false);
+ true);
}
void i915_gem_restore_gtt_mappings(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index 1a24e84f2315..28d24caa49f3 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -82,9 +82,22 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
r = devm_request_mem_region(dev->dev, base, dev_priv->gtt.stolen_size,
"Graphics Stolen Memory");
if (r == NULL) {
- DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n",
- base, base + (uint32_t)dev_priv->gtt.stolen_size);
- base = 0;
+ /*
+ * One more attempt but this time requesting region from
+ * base + 1, as we have seen that this resolves the region
+ * conflict with the PCI Bus.
+ * This is a BIOS w/a: Some BIOS wrap stolen in the root
+ * PCI bus, but have an off-by-one error. Hence retry the
+ * reservation starting from 1 instead of 0.
+ */
+ r = devm_request_mem_region(dev->dev, base + 1,
+ dev_priv->gtt.stolen_size - 1,
+ "Graphics Stolen Memory");
+ if (r == NULL) {
+ DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n",
+ base, base + (uint32_t)dev_priv->gtt.stolen_size);
+ base = 0;
+ }
}
return base;
@@ -201,6 +214,13 @@ int i915_gem_init_stolen(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int bios_reserved = 0;
+#ifdef CONFIG_INTEL_IOMMU
+ if (intel_iommu_gfx_mapped) {
+ DRM_INFO("DMAR active, disabling use of stolen memory\n");
+ return 0;
+ }
+#endif
+
if (dev_priv->gtt.stolen_size == 0)
return 0;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 9fec71175571..d554169ac592 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -618,33 +618,25 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
/* raw reads, only for fast reads of display block, no need for forcewake etc. */
#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
-#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__))
static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t status;
-
- if (INTEL_INFO(dev)->gen < 7) {
- status = pipe == PIPE_A ?
- DE_PIPEA_VBLANK :
- DE_PIPEB_VBLANK;
+ int reg;
+
+ if (INTEL_INFO(dev)->gen >= 8) {
+ status = GEN8_PIPE_VBLANK;
+ reg = GEN8_DE_PIPE_ISR(pipe);
+ } else if (INTEL_INFO(dev)->gen >= 7) {
+ status = DE_PIPE_VBLANK_IVB(pipe);
+ reg = DEISR;
} else {
- switch (pipe) {
- default:
- case PIPE_A:
- status = DE_PIPEA_VBLANK_IVB;
- break;
- case PIPE_B:
- status = DE_PIPEB_VBLANK_IVB;
- break;
- case PIPE_C:
- status = DE_PIPEC_VBLANK_IVB;
- break;
- }
+ status = DE_PIPE_VBLANK(pipe);
+ reg = DEISR;
}
- return __raw_i915_read32(dev_priv, DEISR) & status;
+ return __raw_i915_read32(dev_priv, reg) & status;
}
static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
@@ -702,7 +694,28 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
else
position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
- if (HAS_PCH_SPLIT(dev)) {
+ if (HAS_DDI(dev)) {
+ /*
+ * On HSW HDMI outputs there seems to be a 2 line
+ * difference, whereas eDP has the normal 1 line
+ * difference that earlier platforms have. External
+ * DP is unknown. For now just check for the 2 line
+ * difference case on all output types on HSW+.
+ *
+ * This might misinterpret the scanline counter being
+ * one line too far along on eDP, but that's less
+ * dangerous than the alternative since that would lead
+ * the vblank timestamp code astray when it sees a
+ * scanline count before vblank_start during a vblank
+ * interrupt.
+ */
+ in_vbl = ilk_pipe_in_vblank_locked(dev, pipe);
+ if ((in_vbl && (position == vbl_start - 2 ||
+ position == vbl_start - 1)) ||
+ (!in_vbl && (position == vbl_end - 2 ||
+ position == vbl_end - 1)))
+ position = (position + 2) % vtotal;
+ } else if (HAS_PCH_SPLIT(dev)) {
/*
* The scanline counter increments at the leading edge
* of hsync, ie. it completely misses the active portion
@@ -2769,10 +2782,9 @@ static void ibx_irq_postinstall(struct drm_device *dev)
return;
if (HAS_PCH_IBX(dev)) {
- mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER |
- SDE_TRANSA_FIFO_UNDER | SDE_POISON;
+ mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON;
} else {
- mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT;
+ mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
I915_WRITE(SERR_INT, I915_READ(SERR_INT));
}
@@ -2832,20 +2844,19 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB |
DE_PLANEB_FLIP_DONE_IVB |
- DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB |
- DE_ERR_INT_IVB);
+ DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB);
extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
- DE_PIPEA_VBLANK_IVB);
+ DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB);
I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
} else {
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
DE_AUX_CHANNEL_A |
- DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN |
DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE |
DE_POISON);
- extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT;
+ extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT |
+ DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN;
}
dev_priv->irq_mask = ~display_mask;
@@ -2961,9 +2972,9 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
struct drm_device *dev = dev_priv->dev;
uint32_t de_pipe_masked = GEN8_PIPE_FLIP_DONE |
GEN8_PIPE_CDCLK_CRC_DONE |
- GEN8_PIPE_FIFO_UNDERRUN |
GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
- uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK;
+ uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
+ GEN8_PIPE_FIFO_UNDERRUN;
int pipe;
dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked;
dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked;
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index e06b9e017d6b..234ac5f7bc5a 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1244,6 +1244,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+ ironlake_edp_panel_vdd_on(intel_dp);
ironlake_edp_panel_off(intel_dp);
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9fa24347963a..9b8a7c7ea7fc 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1092,12 +1092,12 @@ static void assert_cursor(struct drm_i915_private *dev_priv,
struct drm_device *dev = dev_priv->dev;
bool cur_state;
- if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
- cur_state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE;
- else if (IS_845G(dev) || IS_I865G(dev))
+ if (IS_845G(dev) || IS_I865G(dev))
cur_state = I915_READ(_CURACNTR) & CURSOR_ENABLE;
- else
+ else if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev))
cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
+ else
+ cur_state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE;
WARN(cur_state != state,
"cursor on pipe %c assertion failure (expected %s, current %s)\n",
@@ -8586,6 +8586,20 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
if (ring->id == RCS)
len += 6;
+ /*
+ * BSpec MI_DISPLAY_FLIP for IVB:
+ * "The full packet must be contained within the same cache line."
+ *
+ * Currently the LRI+SRM+MI_DISPLAY_FLIP all fit within the same
+ * cacheline, if we ever start emitting more commands before
+ * the MI_DISPLAY_FLIP we may need to first emit everything else,
+ * then do the cacheline alignment, and finally emit the
+ * MI_DISPLAY_FLIP.
+ */
+ ret = intel_ring_cacheline_align(ring);
+ if (ret)
+ goto err_unpin;
+
ret = intel_ring_begin(ring, len);
if (ret)
goto err_unpin;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 2f517b85b3f4..2688f6d64bb9 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -537,6 +537,7 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp,
uint8_t msg[20];
int msg_bytes;
uint8_t ack;
+ int retry;
if (WARN_ON(send_bytes > 16))
return -E2BIG;
@@ -548,19 +549,21 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp,
msg[3] = send_bytes - 1;
memcpy(&msg[4], send, send_bytes);
msg_bytes = send_bytes + 4;
- for (;;) {
+ for (retry = 0; retry < 7; retry++) {
ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, &ack, 1);
if (ret < 0)
return ret;
ack >>= 4;
if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK)
- break;
+ return send_bytes;
else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
- udelay(100);
+ usleep_range(400, 500);
else
return -EIO;
}
- return send_bytes;
+
+ DRM_ERROR("too many retries, giving up\n");
+ return -EIO;
}
/* Write a single byte to the aux channel in native mode */
@@ -582,6 +585,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,
int reply_bytes;
uint8_t ack;
int ret;
+ int retry;
if (WARN_ON(recv_bytes > 19))
return -E2BIG;
@@ -595,7 +599,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,
msg_bytes = 4;
reply_bytes = recv_bytes + 1;
- for (;;) {
+ for (retry = 0; retry < 7; retry++) {
ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes,
reply, reply_bytes);
if (ret == 0)
@@ -608,10 +612,13 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,
return ret - 1;
}
else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
- udelay(100);
+ usleep_range(400, 500);
else
return -EIO;
}
+
+ DRM_ERROR("too many retries, giving up\n");
+ return -EIO;
}
static int
@@ -1242,17 +1249,24 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp)
DRM_DEBUG_KMS("Turn eDP power off\n");
+ WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
+
pp = ironlake_get_pp_control(intel_dp);
/* We need to switch off panel power _and_ force vdd, for otherwise some
* panels get very unhappy and cease to work. */
- pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE);
+ pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
I915_WRITE(pp_ctrl_reg, pp);
POSTING_READ(pp_ctrl_reg);
+ intel_dp->want_panel_vdd = false;
+
ironlake_wait_panel_off(intel_dp);
+
+ /* We got a reference when we enabled the VDD. */
+ intel_runtime_pm_put(dev_priv);
}
void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
@@ -1632,7 +1646,7 @@ static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
val |= EDP_PSR_LINK_DISABLE;
I915_WRITE(EDP_PSR_CTL(dev), val |
- IS_BROADWELL(dev) ? 0 : link_entry_time |
+ (IS_BROADWELL(dev) ? 0 : link_entry_time) |
max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |
EDP_PSR_ENABLE);
@@ -1777,6 +1791,7 @@ static void intel_disable_dp(struct intel_encoder *encoder)
/* Make sure the panel is off before trying to change the mode. But also
* ensure that we have vdd while we switch off the panel. */
+ ironlake_edp_panel_vdd_on(intel_dp);
ironlake_edp_backlight_off(intel_dp);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
ironlake_edp_panel_off(intel_dp);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 6db0d9d17f47..ee3181ebcc92 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -845,7 +845,7 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi)
{
struct drm_device *dev = intel_hdmi_to_dev(hdmi);
- if (IS_G4X(dev))
+ if (!hdmi->has_hdmi_sink || IS_G4X(dev))
return 165000;
else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8)
return 300000;
@@ -899,8 +899,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
* outputs. We also need to check that the higher clock still fits
* within limits.
*/
- if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= portclock_limit
- && HAS_PCH_SPLIT(dev)) {
+ if (pipe_config->pipe_bpp > 8*3 && intel_hdmi->has_hdmi_sink &&
+ clock_12bpc <= portclock_limit && HAS_PCH_SPLIT(dev)) {
DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
desired_bpp = 12*3;
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 350de359123a..079ea38f14d9 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -698,7 +698,7 @@ static void i9xx_enable_backlight(struct intel_connector *connector)
freq /= 0xff;
ctl = freq << 17;
- if (IS_GEN2(dev) && panel->backlight.combination_mode)
+ if (panel->backlight.combination_mode)
ctl |= BLM_LEGACY_MODE;
if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm)
ctl |= BLM_POLARITY_PNV;
@@ -979,7 +979,7 @@ static int i9xx_setup_backlight(struct intel_connector *connector)
ctl = I915_READ(BLC_PWM_CTL);
- if (IS_GEN2(dev))
+ if (IS_GEN2(dev) || IS_I915GM(dev) || IS_I945GM(dev))
panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
if (IS_PINEVIEW(dev))
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index d77cc81900f9..e1fc35a72656 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3493,6 +3493,8 @@ static void valleyview_setup_pctx(struct drm_device *dev)
u32 pcbr;
int pctx_size = 24*1024;
+ WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
pcbr = I915_READ(VLV_PCBR);
if (pcbr) {
/* BIOS set it up already, grab the pre-alloc'd space */
@@ -3542,8 +3544,6 @@ static void valleyview_enable_rps(struct drm_device *dev)
I915_WRITE(GTFIFODBG, gtfifodbg);
}
- valleyview_setup_pctx(dev);
-
/* If VLV, Forcewake all wells, else re-direct to regular path */
gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
@@ -4395,6 +4395,8 @@ void intel_enable_gt_powersave(struct drm_device *dev)
ironlake_enable_rc6(dev);
intel_init_emon(dev);
} else if (IS_GEN6(dev) || IS_GEN7(dev)) {
+ if (IS_VALLEYVIEW(dev))
+ valleyview_setup_pctx(dev);
/*
* PCU communication is slow and this doesn't need to be
* done at any specific time, so do this out of our fast path
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index b7f1742caf87..31b36c5ac894 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1653,6 +1653,27 @@ int intel_ring_begin(struct intel_ring_buffer *ring,
return 0;
}
+/* Align the ring tail to a cacheline boundary */
+int intel_ring_cacheline_align(struct intel_ring_buffer *ring)
+{
+ int num_dwords = (64 - (ring->tail & 63)) / sizeof(uint32_t);
+ int ret;
+
+ if (num_dwords == 0)
+ return 0;
+
+ ret = intel_ring_begin(ring, num_dwords);
+ if (ret)
+ return ret;
+
+ while (num_dwords--)
+ intel_ring_emit(ring, MI_NOOP);
+
+ intel_ring_advance(ring);
+
+ return 0;
+}
+
void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 71a73f4fe252..0b243ce33714 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -233,6 +233,7 @@ intel_write_status_page(struct intel_ring_buffer *ring,
void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n);
+int __must_check intel_ring_cacheline_align(struct intel_ring_buffer *ring);
static inline void intel_ring_emit(struct intel_ring_buffer *ring,
u32 data)
{
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index 7cf787d697b1..637c29a33127 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -11,7 +11,7 @@ config DRM_NOUVEAU
select FB
select FRAMEBUFFER_CONSOLE if !EXPERT
select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
- select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
+ select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && INPUT
select X86_PLATFORM_DEVICES if ACPI && X86
select ACPI_WMI if ACPI && X86
select MXM_WMI if ACPI && X86
@@ -19,7 +19,6 @@ config DRM_NOUVEAU
# Similar to i915, we need to select ACPI_VIDEO and it's dependencies
select BACKLIGHT_LCD_SUPPORT if ACPI && X86
select BACKLIGHT_CLASS_DEVICE if ACPI && X86
- select VIDEO_OUTPUT_CONTROL if ACPI && X86
select INPUT if ACPI && X86
select THERMAL if ACPI && X86
select ACPI_VIDEO if ACPI && X86
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index e88145ba1bf5..d310c195bdfe 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -141,6 +141,7 @@ nouveau-y += core/subdev/mc/base.o
nouveau-y += core/subdev/mc/nv04.o
nouveau-y += core/subdev/mc/nv40.o
nouveau-y += core/subdev/mc/nv44.o
+nouveau-y += core/subdev/mc/nv4c.o
nouveau-y += core/subdev/mc/nv50.o
nouveau-y += core/subdev/mc/nv94.o
nouveau-y += core/subdev/mc/nv98.o
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c
index 1b653dd74a70..08b88591ed60 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c
@@ -311,7 +311,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
@@ -334,7 +334,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nv4e_fb_oclass;
@@ -357,7 +357,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
@@ -380,7 +380,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
@@ -403,7 +403,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index 940eaa5d8b9a..9ad722e4e087 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -1142,7 +1142,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
if (conf != ~0) {
if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) {
u32 soff = (ffs(outp.or) - 1) * 0x08;
- u32 ctrl = nv_rd32(priv, 0x610798 + soff);
+ u32 ctrl = nv_rd32(priv, 0x610794 + soff);
u32 datarate;
switch ((ctrl & 0x000f0000) >> 16) {
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
index 9a850fe19515..54c1b5b471cd 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
@@ -112,7 +112,7 @@ nve0_fifo_runlist_update(struct nve0_fifo_priv *priv, u32 engine)
nv_wr32(priv, 0x002270, cur->addr >> 12);
nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
- if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000))
+ if (!nv_wait(priv, 0x002284 + (engine * 8), 0x00100000, 0x00000000))
nv_error(priv, "runlist %d update timeout\n", engine);
mutex_unlock(&nv_subdev(priv)->mutex);
}
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
index 30ed19c52e05..7a367c402978 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
@@ -539,7 +539,7 @@ nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old,
ustatus &= ~0x04030000;
}
if (ustatus && display) {
- nv_error("%s - TP%d:", name, i);
+ nv_error(priv, "%s - TP%d:", name, i);
nouveau_bitfield_print(nv50_mpc_traps, ustatus);
pr_cont("\n");
ustatus = 0;
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
index adc88b73d911..3c6738edd127 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
@@ -47,6 +47,7 @@ struct nouveau_mc_oclass {
extern struct nouveau_oclass *nv04_mc_oclass;
extern struct nouveau_oclass *nv40_mc_oclass;
extern struct nouveau_oclass *nv44_mc_oclass;
+extern struct nouveau_oclass *nv4c_mc_oclass;
extern struct nouveau_oclass *nv50_mc_oclass;
extern struct nouveau_oclass *nv94_mc_oclass;
extern struct nouveau_oclass *nv98_mc_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
index aa0fbbec7f08..ef0c9c4a8cc3 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
@@ -130,6 +130,10 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios)
u16 pcir;
int i;
+ /* there is no prom on nv4x IGP's */
+ if (device->card_type == NV_40 && device->chipset >= 0x4c)
+ return;
+
/* enable access to rom */
if (device->card_type >= NV_50)
pcireg = 0x088050;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
index 9159a5ccee93..265d1253624a 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
@@ -36,7 +36,7 @@ nv1a_fb_oclass = &(struct nv04_fb_impl) {
.fini = _nouveau_fb_fini,
},
.base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv10_ram_oclass,
+ .base.ram = &nv1a_ram_oclass,
.tile.regions = 8,
.tile.init = nv10_fb_tile_init,
.tile.fini = nv10_fb_tile_fini,
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h
index b0d5c31606c1..81a408e7d034 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h
@@ -14,6 +14,7 @@ int nv04_mc_ctor(struct nouveau_object *, struct nouveau_object *,
extern const struct nouveau_mc_intr nv04_mc_intr[];
int nv04_mc_init(struct nouveau_object *);
void nv40_mc_msi_rearm(struct nouveau_mc *);
+int nv44_mc_init(struct nouveau_object *object);
int nv50_mc_init(struct nouveau_object *);
extern const struct nouveau_mc_intr nv50_mc_intr[];
extern const struct nouveau_mc_intr nvc0_mc_intr[];
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
index 3bfee5c6c4f2..cc4d0d2d886e 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
@@ -24,7 +24,7 @@
#include "nv04.h"
-static int
+int
nv44_mc_init(struct nouveau_object *object)
{
struct nv04_mc_priv *priv = (void *)object;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c
new file mode 100644
index 000000000000..a75c35ccf25c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014 Ilia Mirkin
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ilia Mirkin
+ */
+
+#include "nv04.h"
+
+static void
+nv4c_mc_msi_rearm(struct nouveau_mc *pmc)
+{
+ struct nv04_mc_priv *priv = (void *)pmc;
+ nv_wr08(priv, 0x088050, 0xff);
+}
+
+struct nouveau_oclass *
+nv4c_mc_oclass = &(struct nouveau_mc_oclass) {
+ .base.handle = NV_SUBDEV(MC, 0x4c),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv04_mc_ctor,
+ .dtor = _nouveau_mc_dtor,
+ .init = nv44_mc_init,
+ .fini = _nouveau_mc_fini,
+ },
+ .intr = nv04_mc_intr,
+ .msi_rearm = nv4c_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 4ef83df2b246..83face3f608f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -106,6 +106,29 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
return 0;
}
+/*
+ * On some platforms, _DSM(nouveau_op_dsm_muid, func0) has special
+ * requirements on the fourth parameter, so a private implementation
+ * instead of using acpi_check_dsm().
+ */
+static int nouveau_check_optimus_dsm(acpi_handle handle)
+{
+ int result;
+
+ /*
+ * Function 0 returns a Buffer containing available functions.
+ * The args parameter is ignored for function 0, so just put 0 in it
+ */
+ if (nouveau_optimus_dsm(handle, 0, 0, &result))
+ return 0;
+
+ /*
+ * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported.
+ * If the n-th bit is enabled, function n is supported
+ */
+ return result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS);
+}
+
static int nouveau_dsm(acpi_handle handle, int func, int arg)
{
int ret = 0;
@@ -207,8 +230,7 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
1 << NOUVEAU_DSM_POWER))
retval |= NOUVEAU_DSM_HAS_MUX;
- if (acpi_check_dsm(dhandle, nouveau_op_dsm_muid, 0x00000100,
- 1 << NOUVEAU_DSM_OPTIMUS_CAPS))
+ if (nouveau_check_optimus_dsm(dhandle))
retval |= NOUVEAU_DSM_HAS_OPT;
if (retval & NOUVEAU_DSM_HAS_OPT) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 488686d490c0..4aed1714b9ab 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -1249,7 +1249,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
mem->bus.is_iomem = !dev->agp->cant_use_aperture;
}
#endif
- if (!node->memtype)
+ if (nv_device(drm->device)->card_type < NV_50 || !node->memtype)
/* untiled */
break;
/* fallthrough, tiled memory */
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 78c8e7146d56..4ee702ac8907 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -376,6 +376,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
if (ret)
goto fail_device;
+ dev->irq_enabled = true;
+
/* workaround an odd issue on nvc1 by disabling the device's
* nosnoop capability. hopefully won't cause issues until a
* better fix is found - assuming there is one...
@@ -475,6 +477,7 @@ nouveau_drm_remove(struct pci_dev *pdev)
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_object *device;
+ dev->irq_enabled = false;
device = drm->client.base.device;
drm_put_dev(dev);
@@ -863,13 +866,16 @@ static int nouveau_pmops_runtime_suspend(struct device *dev)
struct drm_device *drm_dev = pci_get_drvdata(pdev);
int ret;
- if (nouveau_runtime_pm == 0)
- return -EINVAL;
+ if (nouveau_runtime_pm == 0) {
+ pm_runtime_forbid(dev);
+ return -EBUSY;
+ }
/* are we optimus enabled? */
if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
- return -EINVAL;
+ pm_runtime_forbid(dev);
+ return -EBUSY;
}
nv_debug_level(SILENT);
@@ -920,12 +926,15 @@ static int nouveau_pmops_runtime_idle(struct device *dev)
struct nouveau_drm *drm = nouveau_drm(drm_dev);
struct drm_crtc *crtc;
- if (nouveau_runtime_pm == 0)
+ if (nouveau_runtime_pm == 0) {
+ pm_runtime_forbid(dev);
return -EBUSY;
+ }
/* are we optimus enabled? */
if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
+ pm_runtime_forbid(dev);
return -EBUSY;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c
index 81638d7f2eff..471347edc27e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vga.c
+++ b/drivers/gpu/drm/nouveau/nouveau_vga.c
@@ -14,7 +14,9 @@ nouveau_vga_set_decode(void *priv, bool state)
{
struct nouveau_device *device = nouveau_dev(priv);
- if (device->chipset >= 0x40)
+ if (device->card_type == NV_40 && device->chipset >= 0x4c)
+ nv_wr32(device, 0x088060, state);
+ else if (device->chipset >= 0x40)
nv_wr32(device, 0x088054, state);
else
nv_wr32(device, 0x001854, state);
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index a9338c85630f..daa4dd375ab1 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -559,7 +559,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
u32 adjusted_clock = mode->clock;
int encoder_mode = atombios_get_encoder_mode(encoder);
u32 dp_clock = mode->clock;
- int bpc = radeon_get_monitor_bpc(connector);
+ int bpc = radeon_crtc->bpc;
bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);
/* reset the pll flags */
@@ -1176,7 +1176,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split);
/* Set NUM_BANKS. */
- if (rdev->family >= CHIP_BONAIRE) {
+ if (rdev->family >= CHIP_TAHITI) {
unsigned tileb, index, num_banks, tile_split_bytes;
/* Calculate the macrotile mode index. */
@@ -1194,13 +1194,14 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
return -EINVAL;
}
- num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3;
+ if (rdev->family >= CHIP_BONAIRE)
+ num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3;
+ else
+ num_banks = (rdev->config.si.tile_mode_array[index] >> 20) & 0x3;
fb_format |= EVERGREEN_GRPH_NUM_BANKS(num_banks);
} else {
- /* SI and older. */
- if (rdev->family >= CHIP_TAHITI)
- tmp = rdev->config.si.tile_config;
- else if (rdev->family >= CHIP_CAYMAN)
+ /* NI and older. */
+ if (rdev->family >= CHIP_CAYMAN)
tmp = rdev->config.cayman.tile_config;
else
tmp = rdev->config.evergreen.tile_config;
@@ -1773,6 +1774,20 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
return ATOM_PPLL1;
DRM_ERROR("unable to allocate a PPLL\n");
return ATOM_PPLL_INVALID;
+ } else if (ASIC_IS_DCE41(rdev)) {
+ /* Don't share PLLs on DCE4.1 chips */
+ if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
+ if (rdev->clock.dp_extclk)
+ /* skip PPLL programming if using ext clock */
+ return ATOM_PPLL_INVALID;
+ }
+ pll_in_use = radeon_get_pll_use_mask(crtc);
+ if (!(pll_in_use & (1 << ATOM_PPLL1)))
+ return ATOM_PPLL1;
+ if (!(pll_in_use & (1 << ATOM_PPLL2)))
+ return ATOM_PPLL2;
+ DRM_ERROR("unable to allocate a PPLL\n");
+ return ATOM_PPLL_INVALID;
} else if (ASIC_IS_DCE4(rdev)) {
/* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,
* depending on the asic:
@@ -1800,7 +1815,7 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
if (pll != ATOM_PPLL_INVALID)
return pll;
}
- } else if (!ASIC_IS_DCE41(rdev)) { /* Don't share PLLs on DCE4.1 chips */
+ } else {
/* use the same PPLL for all monitors with the same clock */
pll = radeon_get_shared_nondp_ppll(crtc);
if (pll != ATOM_PPLL_INVALID)
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index a42d61571f49..607dc14d195e 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -464,11 +464,12 @@ atombios_tv_setup(struct drm_encoder *encoder, int action)
static u8 radeon_atom_get_bpc(struct drm_encoder *encoder)
{
- struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
int bpc = 8;
- if (connector)
- bpc = radeon_get_monitor_bpc(connector);
+ if (encoder->crtc) {
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+ bpc = radeon_crtc->bpc;
+ }
switch (bpc) {
case 0:
@@ -1313,7 +1314,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
}
if (is_dp)
args.v5.ucLaneNum = dp_lane_count;
- else if (radeon_encoder->pixel_clock > 165000)
+ else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
args.v5.ucLaneNum = 8;
else
args.v5.ucLaneNum = 4;
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index e6419ca7cd37..bbb17841a9e5 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -3046,7 +3046,7 @@ static u32 cik_create_bitmask(u32 bit_width)
}
/**
- * cik_select_se_sh - select which SE, SH to address
+ * cik_get_rb_disabled - computes the mask of disabled RBs
*
* @rdev: radeon_device pointer
* @max_rb_num: max RBs (render backends) for the asic
@@ -4134,8 +4134,11 @@ static void cik_cp_compute_enable(struct radeon_device *rdev, bool enable)
{
if (enable)
WREG32(CP_MEC_CNTL, 0);
- else
+ else {
WREG32(CP_MEC_CNTL, (MEC_ME1_HALT | MEC_ME2_HALT));
+ rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false;
+ rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false;
+ }
udelay(50);
}
@@ -7902,7 +7905,8 @@ int cik_resume(struct radeon_device *rdev)
/* init golden registers */
cik_init_golden_registers(rdev);
- radeon_pm_resume(rdev);
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_resume(rdev);
rdev->accel_working = true;
r = cik_startup(rdev);
diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c
index 1ecb3f1070e3..94626ea90fa5 100644
--- a/drivers/gpu/drm/radeon/cik_sdma.c
+++ b/drivers/gpu/drm/radeon/cik_sdma.c
@@ -264,6 +264,8 @@ static void cik_sdma_gfx_stop(struct radeon_device *rdev)
WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl);
WREG32(SDMA0_GFX_IB_CNTL + reg_offset, 0);
}
+ rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false;
+ rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready = false;
}
/**
@@ -291,6 +293,11 @@ void cik_sdma_enable(struct radeon_device *rdev, bool enable)
u32 me_cntl, reg_offset;
int i;
+ if (enable == false) {
+ cik_sdma_gfx_stop(rdev);
+ cik_sdma_rlc_stop(rdev);
+ }
+
for (i = 0; i < 2; i++) {
if (i == 0)
reg_offset = SDMA0_REGISTER_OFFSET;
@@ -420,10 +427,6 @@ static int cik_sdma_load_microcode(struct radeon_device *rdev)
if (!rdev->sdma_fw)
return -EINVAL;
- /* stop the gfx rings and rlc compute queues */
- cik_sdma_gfx_stop(rdev);
- cik_sdma_rlc_stop(rdev);
-
/* halt the MEs */
cik_sdma_enable(rdev, false);
@@ -492,9 +495,6 @@ int cik_sdma_resume(struct radeon_device *rdev)
*/
void cik_sdma_fini(struct radeon_device *rdev)
{
- /* stop the gfx rings and rlc compute queues */
- cik_sdma_gfx_stop(rdev);
- cik_sdma_rlc_stop(rdev);
/* halt the MEs */
cik_sdma_enable(rdev, false);
radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]);
diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c
index 713a5d359901..94e858751994 100644
--- a/drivers/gpu/drm/radeon/dce6_afmt.c
+++ b/drivers/gpu/drm/radeon/dce6_afmt.c
@@ -278,13 +278,15 @@ static int dce6_audio_chipset_supported(struct radeon_device *rdev)
return !ASIC_IS_NODCE(rdev);
}
-static void dce6_audio_enable(struct radeon_device *rdev,
- struct r600_audio_pin *pin,
- bool enable)
+void dce6_audio_enable(struct radeon_device *rdev,
+ struct r600_audio_pin *pin,
+ bool enable)
{
+ if (!pin)
+ return;
+
WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL,
- AUDIO_ENABLED);
- DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id);
+ enable ? AUDIO_ENABLED : 0);
}
static const u32 pin_offsets[7] =
@@ -323,7 +325,8 @@ int dce6_audio_init(struct radeon_device *rdev)
rdev->audio.pin[i].connected = false;
rdev->audio.pin[i].offset = pin_offsets[i];
rdev->audio.pin[i].id = i;
- dce6_audio_enable(rdev, &rdev->audio.pin[i], true);
+ /* disable audio. it will be set up later */
+ dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
}
return 0;
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index f2b9e21ce4da..27b0ff16082e 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -1680,7 +1680,7 @@ bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
case RADEON_HPD_6:
if (RREG32(DC_HPD6_INT_STATUS) & DC_HPDx_SENSE)
connected = true;
- break;
+ break;
default:
break;
}
@@ -5299,7 +5299,8 @@ int evergreen_resume(struct radeon_device *rdev)
/* init golden registers */
evergreen_init_golden_registers(rdev);
- radeon_pm_resume(rdev);
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_resume(rdev);
rdev->accel_working = true;
r = evergreen_startup(rdev);
@@ -5475,9 +5476,9 @@ void evergreen_fini(struct radeon_device *rdev)
radeon_wb_fini(rdev);
radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
- evergreen_pcie_gart_fini(rdev);
uvd_v1_0_fini(rdev);
radeon_uvd_fini(rdev);
+ evergreen_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
radeon_fence_driver_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c
index 0c6d5cef4cf1..05b0c95813fd 100644
--- a/drivers/gpu/drm/radeon/evergreen_hdmi.c
+++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c
@@ -306,6 +306,15 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
return;
offset = dig->afmt->offset;
+ /* disable audio prior to setting up hw */
+ if (ASIC_IS_DCE6(rdev)) {
+ dig->afmt->pin = dce6_audio_get_pin(rdev);
+ dce6_audio_enable(rdev, dig->afmt->pin, false);
+ } else {
+ dig->afmt->pin = r600_audio_get_pin(rdev);
+ r600_audio_enable(rdev, dig->afmt->pin, false);
+ }
+
evergreen_audio_set_dto(encoder, mode->clock);
WREG32(HDMI_VBI_PACKET_CONTROL + offset,
@@ -409,12 +418,16 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF);
WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001);
WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001);
+
+ /* enable audio after to setting up hw */
+ if (ASIC_IS_DCE6(rdev))
+ dce6_audio_enable(rdev, dig->afmt->pin, true);
+ else
+ r600_audio_enable(rdev, dig->afmt->pin, true);
}
void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
@@ -427,15 +440,6 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
if (!enable && !dig->afmt->enabled)
return;
- if (enable) {
- if (ASIC_IS_DCE6(rdev))
- dig->afmt->pin = dce6_audio_get_pin(rdev);
- else
- dig->afmt->pin = r600_audio_get_pin(rdev);
- } else {
- dig->afmt->pin = NULL;
- }
-
dig->afmt->enabled = enable;
DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",
diff --git a/drivers/gpu/drm/radeon/evergreen_smc.h b/drivers/gpu/drm/radeon/evergreen_smc.h
index 76ada8cfe902..3a03ba37d043 100644
--- a/drivers/gpu/drm/radeon/evergreen_smc.h
+++ b/drivers/gpu/drm/radeon/evergreen_smc.h
@@ -57,7 +57,7 @@ typedef struct SMC_Evergreen_MCRegisters SMC_Evergreen_MCRegisters;
#define EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION 0x100
-#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters 0x0
+#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters 0x8
#define EVERGREEN_SMC_FIRMWARE_HEADER_stateTable 0xC
#define EVERGREEN_SMC_FIRMWARE_HEADER_mcRegisterTable 0x20
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index ea932ac66fc6..bf6300cfd62d 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -2105,7 +2105,8 @@ int cayman_resume(struct radeon_device *rdev)
/* init golden registers */
ni_init_golden_registers(rdev);
- radeon_pm_resume(rdev);
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_resume(rdev);
rdev->accel_working = true;
r = cayman_startup(rdev);
diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
index 1217fbcbdcca..ca814276b075 100644
--- a/drivers/gpu/drm/radeon/ni_dpm.c
+++ b/drivers/gpu/drm/radeon/ni_dpm.c
@@ -2588,7 +2588,7 @@ static int ni_populate_sq_ramping_values(struct radeon_device *rdev,
if (NISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
enable_sq_ramping = false;
- if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
+ if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
enable_sq_ramping = false;
for (i = 0; i < state->performance_level_count; i++) {
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index ef024ce3f7cc..3cc78bb66042 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -3942,8 +3942,6 @@ int r100_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = r100_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 7c63ef840e86..0b658b34b33a 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -1430,8 +1430,6 @@ int r300_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = r300_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index 3768aab2710b..802b19220a21 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -325,8 +325,6 @@ int r420_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = r420_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index e209eb75024f..98d6053c36c6 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -240,8 +240,6 @@ int r520_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = r520_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index cdbc4171fe73..647ef4079217 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -2968,7 +2968,8 @@ int r600_resume(struct radeon_device *rdev)
/* post card */
atom_asic_init(rdev->mode_info.atom_context);
- radeon_pm_resume(rdev);
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_resume(rdev);
rdev->accel_working = true;
r = r600_startup(rdev);
diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c
index 47fc2b886979..bffac10c4296 100644
--- a/drivers/gpu/drm/radeon/r600_audio.c
+++ b/drivers/gpu/drm/radeon/r600_audio.c
@@ -142,12 +142,15 @@ void r600_audio_update_hdmi(struct work_struct *work)
}
/* enable the audio stream */
-static void r600_audio_enable(struct radeon_device *rdev,
- struct r600_audio_pin *pin,
- bool enable)
+void r600_audio_enable(struct radeon_device *rdev,
+ struct r600_audio_pin *pin,
+ bool enable)
{
u32 value = 0;
+ if (!pin)
+ return;
+
if (ASIC_IS_DCE4(rdev)) {
if (enable) {
value |= 0x81000000; /* Required to enable audio */
@@ -158,7 +161,6 @@ static void r600_audio_enable(struct radeon_device *rdev,
WREG32_P(R600_AUDIO_ENABLE,
enable ? 0x81000000 : 0x0, ~0x81000000);
}
- DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id);
}
/*
@@ -178,8 +180,8 @@ int r600_audio_init(struct radeon_device *rdev)
rdev->audio.pin[0].status_bits = 0;
rdev->audio.pin[0].category_code = 0;
rdev->audio.pin[0].id = 0;
-
- r600_audio_enable(rdev, &rdev->audio.pin[0], true);
+ /* disable audio. it will be set up later */
+ r600_audio_enable(rdev, &rdev->audio.pin[0], false);
return 0;
}
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index 3016fc14f502..85a2bb28aed2 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -329,9 +329,6 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
u8 *sadb;
int sad_count;
- /* XXX: setting this register causes hangs on some asics */
- return;
-
list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
if (connector->encoder == encoder) {
radeon_connector = to_radeon_connector(connector);
@@ -460,6 +457,10 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
return;
offset = dig->afmt->offset;
+ /* disable audio prior to setting up hw */
+ dig->afmt->pin = r600_audio_get_pin(rdev);
+ r600_audio_enable(rdev, dig->afmt->pin, false);
+
r600_audio_set_dto(encoder, mode->clock);
WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
@@ -531,6 +532,9 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
r600_hdmi_audio_workaround(encoder);
+
+ /* enable audio after to setting up hw */
+ r600_audio_enable(rdev, dig->afmt->pin, true);
}
/*
@@ -651,11 +655,6 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)
if (!enable && !dig->afmt->enabled)
return;
- if (enable)
- dig->afmt->pin = r600_audio_get_pin(rdev);
- else
- dig->afmt->pin = NULL;
-
/* Older chipsets require setting HDMI and routing manually */
if (!ASIC_IS_DCE3(rdev)) {
if (enable)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 4a8ac1cd6b4c..e887d027b6d0 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -135,6 +135,9 @@ extern int radeon_hard_reset;
/* R600+ */
#define R600_RING_TYPE_UVD_INDEX 5
+/* number of hw syncs before falling back on blocking */
+#define RADEON_NUM_SYNCS 4
+
/* hardcode those limit for now */
#define RADEON_VA_IB_OFFSET (1 << 20)
#define RADEON_VA_RESERVED_SIZE (8 << 20)
@@ -554,7 +557,6 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
/*
* Semaphores.
*/
-/* everything here is constant */
struct radeon_semaphore {
struct radeon_sa_bo *sa_bo;
signed waiters;
@@ -2745,6 +2747,12 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev,
void r600_audio_update_hdmi(struct work_struct *work);
struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev);
struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev);
+void r600_audio_enable(struct radeon_device *rdev,
+ struct r600_audio_pin *pin,
+ bool enable);
+void dce6_audio_enable(struct radeon_device *rdev,
+ struct r600_audio_pin *pin,
+ bool enable);
/*
* R600 vram scratch functions
diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
index 485848f889f5..fa9a9c02751e 100644
--- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c
+++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
@@ -219,7 +219,8 @@ static int radeon_atpx_verify_interface(struct radeon_atpx *atpx)
memcpy(&output, info->buffer.pointer, size);
/* TODO: check version? */
- printk("ATPX version %u\n", output.version);
+ printk("ATPX version %u, functions 0x%08x\n",
+ output.version, output.function_bits);
radeon_atpx_parse_functions(&atpx->functions, output.function_bits);
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index b012cbbc3ed5..044bc98fb459 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1521,13 +1521,16 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
if (r)
DRM_ERROR("ib ring test failed (%d).\n", r);
- if (rdev->pm.dpm_enabled) {
+ if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
/* do dpm late init */
r = radeon_pm_late_init(rdev);
if (r) {
rdev->pm.dpm_enabled = false;
DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n");
}
+ } else {
+ /* resume old pm late */
+ radeon_pm_resume(rdev);
}
radeon_restore_bios_scratch_regs(rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index d680608f6f5b..fbd8b930f2be 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -571,6 +571,8 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
radeon_crtc->max_cursor_width = CURSOR_WIDTH;
radeon_crtc->max_cursor_height = CURSOR_HEIGHT;
}
+ dev->mode_config.cursor_width = radeon_crtc->max_cursor_width;
+ dev->mode_config.cursor_height = radeon_crtc->max_cursor_height;
#if 0
radeon_crtc->mode_set.crtc = &radeon_crtc->base;
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 84a1bbb75f91..f633c2782170 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -403,11 +403,15 @@ static int radeon_pmops_runtime_suspend(struct device *dev)
struct drm_device *drm_dev = pci_get_drvdata(pdev);
int ret;
- if (radeon_runtime_pm == 0)
- return -EINVAL;
+ if (radeon_runtime_pm == 0) {
+ pm_runtime_forbid(dev);
+ return -EBUSY;
+ }
- if (radeon_runtime_pm == -1 && !radeon_is_px())
- return -EINVAL;
+ if (radeon_runtime_pm == -1 && !radeon_is_px()) {
+ pm_runtime_forbid(dev);
+ return -EBUSY;
+ }
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
drm_kms_helper_poll_disable(drm_dev);
@@ -456,12 +460,15 @@ static int radeon_pmops_runtime_idle(struct device *dev)
struct drm_device *drm_dev = pci_get_drvdata(pdev);
struct drm_crtc *crtc;
- if (radeon_runtime_pm == 0)
+ if (radeon_runtime_pm == 0) {
+ pm_runtime_forbid(dev);
return -EBUSY;
+ }
/* are we PX enabled? */
if (radeon_runtime_pm == -1 && !radeon_is_px()) {
DRM_DEBUG_DRIVER("failing to power off - not px\n");
+ pm_runtime_forbid(dev);
return -EBUSY;
}
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 114d1672d616..66ed3ea71440 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -33,6 +33,13 @@
#include <linux/vga_switcheroo.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
+
+#if defined(CONFIG_VGA_SWITCHEROO)
+bool radeon_is_px(void);
+#else
+static inline bool radeon_is_px(void) { return false; }
+#endif
+
/**
* radeon_driver_unload_kms - Main unload function for KMS.
*
@@ -130,7 +137,8 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
"Error during ACPI methods call\n");
}
- if (radeon_runtime_pm != 0) {
+ if ((radeon_runtime_pm == 1) ||
+ ((radeon_runtime_pm == -1) && radeon_is_px())) {
pm_runtime_use_autosuspend(dev->dev);
pm_runtime_set_autosuspend_delay(dev->dev, 5000);
pm_runtime_set_active(dev->dev);
@@ -537,6 +545,10 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
radeon_vm_init(rdev, &fpriv->vm);
+ r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);
+ if (r)
+ return r;
+
/* map the ib pool buffer read only into
* virtual address space */
bo_va = radeon_vm_bo_add(rdev, &fpriv->vm,
@@ -544,6 +556,8 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
r = radeon_vm_bo_set_addr(rdev, bo_va, RADEON_VA_IB_OFFSET,
RADEON_VM_PAGE_READABLE |
RADEON_VM_PAGE_SNOOPED);
+
+ radeon_bo_unreserve(rdev->ring_tmp_bo.bo);
if (r) {
radeon_vm_fini(rdev, &fpriv->vm);
kfree(fpriv);
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index 1b783f0e6d3a..15e44a7281ab 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -139,7 +139,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
}
/* 64 dwords should be enough for fence too */
- r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_RINGS * 8);
+ r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_SYNCS * 8);
if (r) {
dev_err(rdev->dev, "scheduling IB failed (%d).\n", r);
return r;
diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c
index 2b42aa1914f2..9006b32d5eed 100644
--- a/drivers/gpu/drm/radeon/radeon_semaphore.c
+++ b/drivers/gpu/drm/radeon/radeon_semaphore.c
@@ -34,14 +34,15 @@
int radeon_semaphore_create(struct radeon_device *rdev,
struct radeon_semaphore **semaphore)
{
+ uint32_t *cpu_addr;
int i, r;
*semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL);
if (*semaphore == NULL) {
return -ENOMEM;
}
- r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo,
- &(*semaphore)->sa_bo, 8, 8, true);
+ r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &(*semaphore)->sa_bo,
+ 8 * RADEON_NUM_SYNCS, 8, true);
if (r) {
kfree(*semaphore);
*semaphore = NULL;
@@ -49,7 +50,10 @@ int radeon_semaphore_create(struct radeon_device *rdev,
}
(*semaphore)->waiters = 0;
(*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr((*semaphore)->sa_bo);
- *((uint64_t*)radeon_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0;
+
+ cpu_addr = radeon_sa_bo_cpu_addr((*semaphore)->sa_bo);
+ for (i = 0; i < RADEON_NUM_SYNCS; ++i)
+ cpu_addr[i] = 0;
for (i = 0; i < RADEON_NUM_RINGS; ++i)
(*semaphore)->sync_to[i] = NULL;
@@ -125,6 +129,7 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
struct radeon_semaphore *semaphore,
int ring)
{
+ unsigned count = 0;
int i, r;
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
@@ -140,6 +145,12 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
return -EINVAL;
}
+ if (++count > RADEON_NUM_SYNCS) {
+ /* not enough room, wait manually */
+ radeon_fence_wait_locked(fence);
+ continue;
+ }
+
/* allocate enough space for sync command */
r = radeon_ring_alloc(rdev, &rdev->ring[i], 16);
if (r) {
@@ -164,6 +175,8 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
radeon_ring_commit(rdev, &rdev->ring[i]);
radeon_fence_note_sync(fence, ring);
+
+ semaphore->gpu_addr += 8;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 77f5b0c3edb8..040a2a10ea17 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -714,6 +714,9 @@ int radeon_ttm_init(struct radeon_device *rdev)
DRM_ERROR("Failed initializing VRAM heap.\n");
return r;
}
+ /* Change the size here instead of the init above so only lpfn is affected */
+ radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+
r = radeon_bo_create(rdev, 256 * 1024, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM,
NULL, &rdev->stollen_vga_memory);
@@ -935,7 +938,7 @@ static ssize_t radeon_ttm_gtt_read(struct file *f, char __user *buf,
while (size) {
loff_t p = *pos / PAGE_SIZE;
unsigned off = *pos & ~PAGE_MASK;
- ssize_t cur_size = min(size, PAGE_SIZE - off);
+ size_t cur_size = min_t(size_t, size, PAGE_SIZE - off);
struct page *page;
void *ptr;
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c
index 6781fee1eaad..3e6804b2b2ef 100644
--- a/drivers/gpu/drm/radeon/radeon_uvd.c
+++ b/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -171,6 +171,8 @@ void radeon_uvd_fini(struct radeon_device *rdev)
radeon_bo_unref(&rdev->uvd.vcpu_bo);
+ radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX]);
+
release_firmware(rdev->uvd_fw);
}
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index b5c2369cda2f..130d5cc50d43 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -474,8 +474,6 @@ int rs400_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = rs400_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index fdcde7693032..72d3616de08e 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -1048,8 +1048,6 @@ int rs600_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = rs600_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 35950738bd5e..3462b64369bf 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -756,8 +756,6 @@ int rs690_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = rs690_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index 98e8138ff779..237dd29d9f1c 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -586,8 +586,6 @@ int rv515_resume(struct radeon_device *rdev)
/* Initialize surface registers */
radeon_surface_init(rdev);
- radeon_pm_resume(rdev);
-
rdev->accel_working = true;
r = rv515_startup(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 6c772e58c784..fef310773aad 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -1811,7 +1811,8 @@ int rv770_resume(struct radeon_device *rdev)
/* init golden registers */
rv770_init_golden_registers(rdev);
- radeon_pm_resume(rdev);
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_resume(rdev);
rdev->accel_working = true;
r = rv770_startup(rdev);
@@ -1955,9 +1956,9 @@ void rv770_fini(struct radeon_device *rdev)
radeon_wb_fini(rdev);
radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
- rv770_pcie_gart_fini(rdev);
uvd_v1_0_fini(rdev);
radeon_uvd_fini(rdev);
+ rv770_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
radeon_fence_driver_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
index 5b2ea8ac0731..b5f63f5e22a3 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.c
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -2526,14 +2526,7 @@ u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low)
bool rv770_dpm_vblank_too_short(struct radeon_device *rdev)
{
u32 vblank_time = r600_dpm_get_vblank_time(rdev);
- u32 switch_limit = 300;
-
- /* quirks */
- /* ASUS K70AF */
- if ((rdev->pdev->device == 0x9553) &&
- (rdev->pdev->subsystem_vendor == 0x1043) &&
- (rdev->pdev->subsystem_device == 0x1c42))
- switch_limit = 200;
+ u32 switch_limit = 200; /* 300 */
/* RV770 */
/* mclk switching doesn't seem to work reliably on desktop RV770s */
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index 83578324e5d1..9a124d0608b3 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -6618,7 +6618,8 @@ int si_resume(struct radeon_device *rdev)
/* init golden registers */
si_init_golden_registers(rdev);
- radeon_pm_resume(rdev);
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_resume(rdev);
rdev->accel_working = true;
r = si_startup(rdev);
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index eafb0e6bc67e..0a2f5b4bca43 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -2395,7 +2395,7 @@ static int si_populate_sq_ramping_values(struct radeon_device *rdev,
if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
enable_sq_ramping = false;
- if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
+ if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
enable_sq_ramping = false;
for (i = 0; i < state->performance_level_count; i++) {
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 88a529008ce0..c71594754f46 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -104,7 +104,7 @@ static void tegra_drm_context_free(struct tegra_drm_context *context)
static void tegra_drm_lastclose(struct drm_device *drm)
{
-#ifdef CONFIG_TEGRA_DRM_FBDEV
+#ifdef CONFIG_DRM_TEGRA_FBDEV
struct tegra_drm *tegra = drm->dev_private;
tegra_fbdev_restore_mode(tegra->fbdev);
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index 338f7f6561d7..0266fb40479e 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -15,6 +15,7 @@
struct tegra_rgb {
struct tegra_output output;
struct tegra_dc *dc;
+ bool enabled;
struct clk *clk_parent;
struct clk *clk;
@@ -89,6 +90,9 @@ static int tegra_output_rgb_enable(struct tegra_output *output)
struct tegra_rgb *rgb = to_rgb(output);
unsigned long value;
+ if (rgb->enabled)
+ return 0;
+
tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable));
value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL;
@@ -122,6 +126,8 @@ static int tegra_output_rgb_enable(struct tegra_output *output)
tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+ rgb->enabled = true;
+
return 0;
}
@@ -130,6 +136,9 @@ static int tegra_output_rgb_disable(struct tegra_output *output)
struct tegra_rgb *rgb = to_rgb(output);
unsigned long value;
+ if (!rgb->enabled)
+ return 0;
+
value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL);
value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
@@ -144,6 +153,8 @@ static int tegra_output_rgb_disable(struct tegra_output *output)
tegra_dc_write_regs(rgb->dc, rgb_disable, ARRAY_SIZE(rgb_disable));
+ rgb->enabled = false;
+
return 0;
}
diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c
index 3302f99e7497..764be36397fd 100644
--- a/drivers/gpu/drm/ttm/ttm_agp_backend.c
+++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c
@@ -126,6 +126,7 @@ struct ttm_tt *ttm_agp_tt_create(struct ttm_bo_device *bdev,
agp_be->ttm.func = &ttm_agp_func;
if (ttm_tt_init(&agp_be->ttm, bdev, size, page_flags, dummy_read_page)) {
+ kfree(agp_be);
return NULL;
}
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index a06651309388..214b7992a3aa 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -351,9 +351,11 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
moved:
if (bo->evicted) {
- ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
- if (ret)
- pr_err("Can not flush read caches\n");
+ if (bdev->driver->invalidate_caches) {
+ ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
+ if (ret)
+ pr_err("Can not flush read caches\n");
+ }
bo->evicted = false;
}
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index 801231c9ae48..0ce48e5a9cb4 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -339,11 +339,13 @@ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,
vma->vm_private_data = bo;
/*
- * PFNMAP is faster than MIXEDMAP due to reduced page
- * administration. So use MIXEDMAP only if private VMA, where
- * we need to support COW.
+ * We'd like to use VM_PFNMAP on shared mappings, where
+ * (vma->vm_flags & VM_SHARED) != 0, for performance reasons,
+ * but for some reason VM_PFNMAP + x86 PAT + write-combine is very
+ * bad for performance. Until that has been sorted out, use
+ * VM_MIXEDMAP on all mappings. See freedesktop.org bug #75719
*/
- vma->vm_flags |= (vma->vm_flags & VM_SHARED) ? VM_PFNMAP : VM_MIXEDMAP;
+ vma->vm_flags |= VM_MIXEDMAP;
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
return 0;
out_unref:
@@ -359,7 +361,7 @@ int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
vma->vm_ops = &ttm_bo_vm_ops;
vma->vm_private_data = ttm_bo_reference(bo);
- vma->vm_flags |= (vma->vm_flags & VM_SHARED) ? VM_PFNMAP : VM_MIXEDMAP;
+ vma->vm_flags |= VM_MIXEDMAP;
vma->vm_flags |= VM_IO | VM_DONTEXPAND;
return 0;
}
diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c
index 8d67b943ac05..0394811251bd 100644
--- a/drivers/gpu/drm/udl/udl_gem.c
+++ b/drivers/gpu/drm/udl/udl_gem.c
@@ -177,8 +177,10 @@ void udl_gem_free_object(struct drm_gem_object *gem_obj)
if (obj->vmapping)
udl_gem_vunmap(obj);
- if (gem_obj->import_attach)
+ if (gem_obj->import_attach) {
drm_prime_gem_destroy(gem_obj, obj->sg);
+ put_device(gem_obj->dev->dev);
+ }
if (obj->pages)
udl_gem_put_pages(obj);
@@ -256,9 +258,12 @@ struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,
int ret;
/* need to attach */
+ get_device(dev->dev);
attach = dma_buf_attach(dma_buf, dev->dev);
- if (IS_ERR(attach))
+ if (IS_ERR(attach)) {
+ put_device(dev->dev);
return ERR_CAST(attach);
+ }
get_dma_buf(dma_buf);
@@ -282,6 +287,6 @@ fail_unmap:
fail_detach:
dma_buf_detach(dma_buf, attach);
dma_buf_put(dma_buf);
-
+ put_device(dev->dev);
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/vmwgfx/svga3d_reg.h b/drivers/gpu/drm/vmwgfx/svga3d_reg.h
index b645647b7776..f58dc7dd15c5 100644
--- a/drivers/gpu/drm/vmwgfx/svga3d_reg.h
+++ b/drivers/gpu/drm/vmwgfx/svga3d_reg.h
@@ -261,12 +261,7 @@ typedef enum SVGA3dSurfaceFormat {
/* Planar video formats. */
SVGA3D_YV12 = 121,
- /* Shader constant formats. */
- SVGA3D_SURFACE_SHADERCONST_FLOAT = 122,
- SVGA3D_SURFACE_SHADERCONST_INT = 123,
- SVGA3D_SURFACE_SHADERCONST_BOOL = 124,
-
- SVGA3D_FORMAT_MAX = 125,
+ SVGA3D_FORMAT_MAX = 122,
} SVGA3dSurfaceFormat;
typedef uint32 SVGA3dColor; /* a, r, g, b */
@@ -1223,9 +1218,19 @@ typedef enum {
#define SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL 1129
#define SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE 1130
-
+#define SVGA_3D_CMD_GB_SCREEN_DMA 1131
+#define SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH 1132
+#define SVGA_3D_CMD_GB_MOB_FENCE 1133
+#define SVGA_3D_CMD_DEFINE_GB_SURFACE_V2 1134
#define SVGA_3D_CMD_DEFINE_GB_MOB64 1135
#define SVGA_3D_CMD_REDEFINE_GB_MOB64 1136
+#define SVGA_3D_CMD_NOP_ERROR 1137
+
+#define SVGA_3D_CMD_RESERVED1 1138
+#define SVGA_3D_CMD_RESERVED2 1139
+#define SVGA_3D_CMD_RESERVED3 1140
+#define SVGA_3D_CMD_RESERVED4 1141
+#define SVGA_3D_CMD_RESERVED5 1142
#define SVGA_3D_CMD_MAX 1142
#define SVGA_3D_CMD_FUTURE_MAX 3000
@@ -1973,8 +1978,7 @@ struct {
uint32 sizeInBytes;
uint32 validSizeInBytes;
SVGAMobFormat ptDepth;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdSetOTableBase; /* SVGA_3D_CMD_SET_OTABLE_BASE */
typedef
@@ -1984,15 +1988,13 @@ struct {
uint32 sizeInBytes;
uint32 validSizeInBytes;
SVGAMobFormat ptDepth;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdSetOTableBase64; /* SVGA_3D_CMD_SET_OTABLE_BASE64 */
typedef
struct {
SVGAOTableType type;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdReadbackOTable; /* SVGA_3D_CMD_READBACK_OTABLE */
/*
@@ -2005,8 +2007,7 @@ struct SVGA3dCmdDefineGBMob {
SVGAMobFormat ptDepth;
PPN base;
uint32 sizeInBytes;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdDefineGBMob; /* SVGA_3D_CMD_DEFINE_GB_MOB */
@@ -2017,8 +2018,7 @@ SVGA3dCmdDefineGBMob; /* SVGA_3D_CMD_DEFINE_GB_MOB */
typedef
struct SVGA3dCmdDestroyGBMob {
SVGAMobId mobid;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdDestroyGBMob; /* SVGA_3D_CMD_DESTROY_GB_MOB */
/*
@@ -2031,8 +2031,7 @@ struct SVGA3dCmdRedefineGBMob {
SVGAMobFormat ptDepth;
PPN base;
uint32 sizeInBytes;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdRedefineGBMob; /* SVGA_3D_CMD_REDEFINE_GB_MOB */
/*
@@ -2045,8 +2044,7 @@ struct SVGA3dCmdDefineGBMob64 {
SVGAMobFormat ptDepth;
PPN64 base;
uint32 sizeInBytes;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdDefineGBMob64; /* SVGA_3D_CMD_DEFINE_GB_MOB64 */
/*
@@ -2059,8 +2057,7 @@ struct SVGA3dCmdRedefineGBMob64 {
SVGAMobFormat ptDepth;
PPN64 base;
uint32 sizeInBytes;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdRedefineGBMob64; /* SVGA_3D_CMD_REDEFINE_GB_MOB64 */
/*
@@ -2070,8 +2067,7 @@ SVGA3dCmdRedefineGBMob64; /* SVGA_3D_CMD_REDEFINE_GB_MOB64 */
typedef
struct SVGA3dCmdUpdateGBMobMapping {
SVGAMobId mobid;
-}
-__attribute__((__packed__))
+} __packed
SVGA3dCmdUpdateGBMobMapping; /* SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING */
/*
@@ -2087,7 +2083,8 @@ struct SVGA3dCmdDefineGBSurface {
uint32 multisampleCount;
SVGA3dTextureFilter autogenFilter;
SVGA3dSize size;
-} SVGA3dCmdDefineGBSurface; /* SVGA_3D_CMD_DEFINE_GB_SURFACE */
+} __packed
+SVGA3dCmdDefineGBSurface; /* SVGA_3D_CMD_DEFINE_GB_SURFACE */
/*
* Destroy a guest-backed surface.
@@ -2096,7 +2093,8 @@ struct SVGA3dCmdDefineGBSurface {
typedef
struct SVGA3dCmdDestroyGBSurface {
uint32 sid;
-} SVGA3dCmdDestroyGBSurface; /* SVGA_3D_CMD_DESTROY_GB_SURFACE */
+} __packed
+SVGA3dCmdDestroyGBSurface; /* SVGA_3D_CMD_DESTROY_GB_SURFACE */
/*
* Bind a guest-backed surface to an object.
@@ -2106,7 +2104,8 @@ typedef
struct SVGA3dCmdBindGBSurface {
uint32 sid;
SVGAMobId mobid;
-} SVGA3dCmdBindGBSurface; /* SVGA_3D_CMD_BIND_GB_SURFACE */
+} __packed
+SVGA3dCmdBindGBSurface; /* SVGA_3D_CMD_BIND_GB_SURFACE */
/*
* Conditionally bind a mob to a guest backed surface if testMobid
@@ -2123,7 +2122,7 @@ struct{
SVGAMobId testMobid;
SVGAMobId mobid;
uint32 flags;
-}
+} __packed
SVGA3dCmdCondBindGBSurface; /* SVGA_3D_CMD_COND_BIND_GB_SURFACE */
/*
@@ -2135,7 +2134,8 @@ typedef
struct SVGA3dCmdUpdateGBImage {
SVGA3dSurfaceImageId image;
SVGA3dBox box;
-} SVGA3dCmdUpdateGBImage; /* SVGA_3D_CMD_UPDATE_GB_IMAGE */
+} __packed
+SVGA3dCmdUpdateGBImage; /* SVGA_3D_CMD_UPDATE_GB_IMAGE */
/*
* Update an entire guest-backed surface.
@@ -2145,7 +2145,8 @@ struct SVGA3dCmdUpdateGBImage {
typedef
struct SVGA3dCmdUpdateGBSurface {
uint32 sid;
-} SVGA3dCmdUpdateGBSurface; /* SVGA_3D_CMD_UPDATE_GB_SURFACE */
+} __packed
+SVGA3dCmdUpdateGBSurface; /* SVGA_3D_CMD_UPDATE_GB_SURFACE */
/*
* Readback an image in a guest-backed surface.
@@ -2155,7 +2156,8 @@ struct SVGA3dCmdUpdateGBSurface {
typedef
struct SVGA3dCmdReadbackGBImage {
SVGA3dSurfaceImageId image;
-} SVGA3dCmdReadbackGBImage; /* SVGA_3D_CMD_READBACK_GB_IMAGE*/
+} __packed
+SVGA3dCmdReadbackGBImage; /* SVGA_3D_CMD_READBACK_GB_IMAGE*/
/*
* Readback an entire guest-backed surface.
@@ -2165,7 +2167,8 @@ struct SVGA3dCmdReadbackGBImage {
typedef
struct SVGA3dCmdReadbackGBSurface {
uint32 sid;
-} SVGA3dCmdReadbackGBSurface; /* SVGA_3D_CMD_READBACK_GB_SURFACE */
+} __packed
+SVGA3dCmdReadbackGBSurface; /* SVGA_3D_CMD_READBACK_GB_SURFACE */
/*
* Readback a sub rect of an image in a guest-backed surface. After
@@ -2179,7 +2182,7 @@ struct SVGA3dCmdReadbackGBImagePartial {
SVGA3dSurfaceImageId image;
SVGA3dBox box;
uint32 invertBox;
-}
+} __packed
SVGA3dCmdReadbackGBImagePartial; /* SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL */
/*
@@ -2190,7 +2193,8 @@ SVGA3dCmdReadbackGBImagePartial; /* SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL */
typedef
struct SVGA3dCmdInvalidateGBImage {
SVGA3dSurfaceImageId image;
-} SVGA3dCmdInvalidateGBImage; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE */
+} __packed
+SVGA3dCmdInvalidateGBImage; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE */
/*
* Invalidate an entire guest-backed surface.
@@ -2200,7 +2204,8 @@ struct SVGA3dCmdInvalidateGBImage {
typedef
struct SVGA3dCmdInvalidateGBSurface {
uint32 sid;
-} SVGA3dCmdInvalidateGBSurface; /* SVGA_3D_CMD_INVALIDATE_GB_SURFACE */
+} __packed
+SVGA3dCmdInvalidateGBSurface; /* SVGA_3D_CMD_INVALIDATE_GB_SURFACE */
/*
* Invalidate a sub rect of an image in a guest-backed surface. After
@@ -2214,7 +2219,7 @@ struct SVGA3dCmdInvalidateGBImagePartial {
SVGA3dSurfaceImageId image;
SVGA3dBox box;
uint32 invertBox;
-}
+} __packed
SVGA3dCmdInvalidateGBImagePartial; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL */
/*
@@ -2224,7 +2229,8 @@ SVGA3dCmdInvalidateGBImagePartial; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL */
typedef
struct SVGA3dCmdDefineGBContext {
uint32 cid;
-} SVGA3dCmdDefineGBContext; /* SVGA_3D_CMD_DEFINE_GB_CONTEXT */
+} __packed
+SVGA3dCmdDefineGBContext; /* SVGA_3D_CMD_DEFINE_GB_CONTEXT */
/*
* Destroy a guest-backed context.
@@ -2233,7 +2239,8 @@ struct SVGA3dCmdDefineGBContext {
typedef
struct SVGA3dCmdDestroyGBContext {
uint32 cid;
-} SVGA3dCmdDestroyGBContext; /* SVGA_3D_CMD_DESTROY_GB_CONTEXT */
+} __packed
+SVGA3dCmdDestroyGBContext; /* SVGA_3D_CMD_DESTROY_GB_CONTEXT */
/*
* Bind a guest-backed context.
@@ -2252,7 +2259,8 @@ struct SVGA3dCmdBindGBContext {
uint32 cid;
SVGAMobId mobid;
uint32 validContents;
-} SVGA3dCmdBindGBContext; /* SVGA_3D_CMD_BIND_GB_CONTEXT */
+} __packed
+SVGA3dCmdBindGBContext; /* SVGA_3D_CMD_BIND_GB_CONTEXT */
/*
* Readback a guest-backed context.
@@ -2262,7 +2270,8 @@ struct SVGA3dCmdBindGBContext {
typedef
struct SVGA3dCmdReadbackGBContext {
uint32 cid;
-} SVGA3dCmdReadbackGBContext; /* SVGA_3D_CMD_READBACK_GB_CONTEXT */
+} __packed
+SVGA3dCmdReadbackGBContext; /* SVGA_3D_CMD_READBACK_GB_CONTEXT */
/*
* Invalidate a guest-backed context.
@@ -2270,7 +2279,8 @@ struct SVGA3dCmdReadbackGBContext {
typedef
struct SVGA3dCmdInvalidateGBContext {
uint32 cid;
-} SVGA3dCmdInvalidateGBContext; /* SVGA_3D_CMD_INVALIDATE_GB_CONTEXT */
+} __packed
+SVGA3dCmdInvalidateGBContext; /* SVGA_3D_CMD_INVALIDATE_GB_CONTEXT */
/*
* Define a guest-backed shader.
@@ -2281,7 +2291,8 @@ struct SVGA3dCmdDefineGBShader {
uint32 shid;
SVGA3dShaderType type;
uint32 sizeInBytes;
-} SVGA3dCmdDefineGBShader; /* SVGA_3D_CMD_DEFINE_GB_SHADER */
+} __packed
+SVGA3dCmdDefineGBShader; /* SVGA_3D_CMD_DEFINE_GB_SHADER */
/*
* Bind a guest-backed shader.
@@ -2291,7 +2302,8 @@ typedef struct SVGA3dCmdBindGBShader {
uint32 shid;
SVGAMobId mobid;
uint32 offsetInBytes;
-} SVGA3dCmdBindGBShader; /* SVGA_3D_CMD_BIND_GB_SHADER */
+} __packed
+SVGA3dCmdBindGBShader; /* SVGA_3D_CMD_BIND_GB_SHADER */
/*
* Destroy a guest-backed shader.
@@ -2299,7 +2311,8 @@ typedef struct SVGA3dCmdBindGBShader {
typedef struct SVGA3dCmdDestroyGBShader {
uint32 shid;
-} SVGA3dCmdDestroyGBShader; /* SVGA_3D_CMD_DESTROY_GB_SHADER */
+} __packed
+SVGA3dCmdDestroyGBShader; /* SVGA_3D_CMD_DESTROY_GB_SHADER */
typedef
struct {
@@ -2314,14 +2327,16 @@ struct {
* Note that FLOAT and INT constants are 4-dwords in length, while
* BOOL constants are 1-dword in length.
*/
-} SVGA3dCmdSetGBShaderConstInline;
+} __packed
+SVGA3dCmdSetGBShaderConstInline;
/* SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE */
typedef
struct {
uint32 cid;
SVGA3dQueryType type;
-} SVGA3dCmdBeginGBQuery; /* SVGA_3D_CMD_BEGIN_GB_QUERY */
+} __packed
+SVGA3dCmdBeginGBQuery; /* SVGA_3D_CMD_BEGIN_GB_QUERY */
typedef
struct {
@@ -2329,7 +2344,8 @@ struct {
SVGA3dQueryType type;
SVGAMobId mobid;
uint32 offset;
-} SVGA3dCmdEndGBQuery; /* SVGA_3D_CMD_END_GB_QUERY */
+} __packed
+SVGA3dCmdEndGBQuery; /* SVGA_3D_CMD_END_GB_QUERY */
/*
@@ -2346,21 +2362,22 @@ struct {
SVGA3dQueryType type;
SVGAMobId mobid;
uint32 offset;
-} SVGA3dCmdWaitForGBQuery; /* SVGA_3D_CMD_WAIT_FOR_GB_QUERY */
+} __packed
+SVGA3dCmdWaitForGBQuery; /* SVGA_3D_CMD_WAIT_FOR_GB_QUERY */
typedef
struct {
SVGAMobId mobid;
uint32 fbOffset;
uint32 initalized;
-}
+} __packed
SVGA3dCmdEnableGart; /* SVGA_3D_CMD_ENABLE_GART */
typedef
struct {
SVGAMobId mobid;
uint32 gartOffset;
-}
+} __packed
SVGA3dCmdMapMobIntoGart; /* SVGA_3D_CMD_MAP_MOB_INTO_GART */
@@ -2368,7 +2385,7 @@ typedef
struct {
uint32 gartOffset;
uint32 numPages;
-}
+} __packed
SVGA3dCmdUnmapGartRange; /* SVGA_3D_CMD_UNMAP_GART_RANGE */
@@ -2385,27 +2402,27 @@ struct {
int32 xRoot;
int32 yRoot;
uint32 flags;
-}
+} __packed
SVGA3dCmdDefineGBScreenTarget; /* SVGA_3D_CMD_DEFINE_GB_SCREENTARGET */
typedef
struct {
uint32 stid;
-}
+} __packed
SVGA3dCmdDestroyGBScreenTarget; /* SVGA_3D_CMD_DESTROY_GB_SCREENTARGET */
typedef
struct {
uint32 stid;
SVGA3dSurfaceImageId image;
-}
+} __packed
SVGA3dCmdBindGBScreenTarget; /* SVGA_3D_CMD_BIND_GB_SCREENTARGET */
typedef
struct {
uint32 stid;
SVGA3dBox box;
-}
+} __packed
SVGA3dCmdUpdateGBScreenTarget; /* SVGA_3D_CMD_UPDATE_GB_SCREENTARGET */
/*
diff --git a/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h b/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h
index 8369c3ba10fe..ef3385096145 100644
--- a/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h
+++ b/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h
@@ -38,8 +38,11 @@
#define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
#define max_t(type, x, y) ((x) > (y) ? (x) : (y))
+#define min_t(type, x, y) ((x) < (y) ? (x) : (y))
#define surf_size_struct SVGA3dSize
#define u32 uint32
+#define u64 uint64_t
+#define U32_MAX ((u32)~0U)
#endif /* __KERNEL__ */
@@ -704,8 +707,8 @@ static const struct svga3d_surface_desc svga3d_surface_descs[] = {
static inline u32 clamped_umul32(u32 a, u32 b)
{
- uint64_t tmp = (uint64_t) a*b;
- return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp;
+ u64 tmp = (u64) a*b;
+ return (tmp > (u64) U32_MAX) ? U32_MAX : tmp;
}
static inline const struct svga3d_surface_desc *
@@ -834,7 +837,7 @@ svga3dsurface_get_serialized_size(SVGA3dSurfaceFormat format,
bool cubemap)
{
const struct svga3d_surface_desc *desc = svga3dsurface_get_desc(format);
- u32 total_size = 0;
+ u64 total_size = 0;
u32 mip;
for (mip = 0; mip < num_mip_levels; mip++) {
@@ -847,7 +850,7 @@ svga3dsurface_get_serialized_size(SVGA3dSurfaceFormat format,
if (cubemap)
total_size *= SVGA3D_MAX_SURFACE_FACES;
- return total_size;
+ return (u32) min_t(u64, total_size, (u64) U32_MAX);
}
diff --git a/drivers/gpu/drm/vmwgfx/svga_reg.h b/drivers/gpu/drm/vmwgfx/svga_reg.h
index 71defa4d2d75..11323dd5196f 100644
--- a/drivers/gpu/drm/vmwgfx/svga_reg.h
+++ b/drivers/gpu/drm/vmwgfx/svga_reg.h
@@ -169,10 +169,17 @@ enum {
SVGA_REG_TRACES = 45, /* Enable trace-based updates even when FIFO is on */
SVGA_REG_GMRS_MAX_PAGES = 46, /* Maximum number of 4KB pages for all GMRs */
SVGA_REG_MEMORY_SIZE = 47, /* Total dedicated device memory excluding FIFO */
+ SVGA_REG_COMMAND_LOW = 48, /* Lower 32 bits and submits commands */
+ SVGA_REG_COMMAND_HIGH = 49, /* Upper 32 bits of command buffer PA */
SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM = 50, /* Max primary memory */
SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB = 51, /* Suggested limit on mob mem */
SVGA_REG_DEV_CAP = 52, /* Write dev cap index, read value */
- SVGA_REG_TOP = 53, /* Must be 1 more than the last register */
+ SVGA_REG_CMD_PREPEND_LOW = 53,
+ SVGA_REG_CMD_PREPEND_HIGH = 54,
+ SVGA_REG_SCREENTARGET_MAX_WIDTH = 55,
+ SVGA_REG_SCREENTARGET_MAX_HEIGHT = 56,
+ SVGA_REG_MOB_MAX_SIZE = 57,
+ SVGA_REG_TOP = 58, /* Must be 1 more than the last register */
SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */
/* Next 768 (== 256*3) registers exist for colormap */
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
index 9426c53fb483..1e80152674b5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c
@@ -551,8 +551,7 @@ static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind)
cmd->header.size = sizeof(cmd->body);
cmd->body.cid = bi->ctx->id;
cmd->body.type = bi->i1.shader_type;
- cmd->body.shid =
- cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
+ cmd->body.shid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
vmw_fifo_commit(dev_priv, sizeof(*cmd));
return 0;
@@ -585,8 +584,7 @@ static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi,
cmd->header.size = sizeof(cmd->body);
cmd->body.cid = bi->ctx->id;
cmd->body.type = bi->i1.rt_type;
- cmd->body.target.sid =
- cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
+ cmd->body.target.sid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
cmd->body.target.face = 0;
cmd->body.target.mipmap = 0;
vmw_fifo_commit(dev_priv, sizeof(*cmd));
@@ -628,8 +626,7 @@ static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi,
cmd->body.c.cid = bi->ctx->id;
cmd->body.s1.stage = bi->i1.texture_stage;
cmd->body.s1.name = SVGA3D_TS_BIND_TEXTURE;
- cmd->body.s1.value =
- cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
+ cmd->body.s1.value = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
vmw_fifo_commit(dev_priv, sizeof(*cmd));
return 0;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 3bdc0adc656d..0083cbf99edf 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -667,6 +667,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->memory_size = 512*1024*1024;
}
dev_priv->max_mob_pages = 0;
+ dev_priv->max_mob_size = 0;
if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) {
uint64_t mem_size =
vmw_read(dev_priv,
@@ -676,6 +677,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->prim_bb_mem =
vmw_read(dev_priv,
SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM);
+ dev_priv->max_mob_size =
+ vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE);
} else
dev_priv->prim_bb_mem = dev_priv->vram_size;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index ecaa302a6154..07831554dad7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -40,7 +40,7 @@
#include <drm/ttm/ttm_module.h>
#include "vmwgfx_fence.h"
-#define VMWGFX_DRIVER_DATE "20121114"
+#define VMWGFX_DRIVER_DATE "20140228"
#define VMWGFX_DRIVER_MAJOR 2
#define VMWGFX_DRIVER_MINOR 5
#define VMWGFX_DRIVER_PATCHLEVEL 0
@@ -386,6 +386,7 @@ struct vmw_private {
uint32_t max_gmr_ids;
uint32_t max_gmr_pages;
uint32_t max_mob_pages;
+ uint32_t max_mob_size;
uint32_t memory_size;
bool has_gmr;
bool has_mob;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 269b85cc875a..efb575a7996c 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -602,7 +602,7 @@ static int vmw_cmd_cid_check(struct vmw_private *dev_priv,
{
struct vmw_cid_cmd {
SVGA3dCmdHeader header;
- __le32 cid;
+ uint32_t cid;
} *cmd;
cmd = container_of(header, struct vmw_cid_cmd, header);
@@ -1835,7 +1835,7 @@ static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,
return 0;
}
-static const struct vmw_cmd_entry const vmw_cmd_entries[SVGA_3D_CMD_MAX] = {
+static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = {
VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid,
false, false, false),
VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid,
@@ -2032,6 +2032,9 @@ static int vmw_cmd_check(struct vmw_private *dev_priv,
goto out_invalid;
entry = &vmw_cmd_entries[cmd_id];
+ if (unlikely(!entry->func))
+ goto out_invalid;
+
if (unlikely(!entry->user_allow && !sw_context->kernel))
goto out_privileged;
@@ -2469,7 +2472,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
if (dev_priv->has_mob) {
ret = vmw_rebind_contexts(sw_context);
if (unlikely(ret != 0))
- goto out_err;
+ goto out_unlock_binding;
}
cmd = vmw_fifo_reserve(dev_priv, command_size);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index f9881f9e62bd..47b70949bf3a 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -102,6 +102,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
vmw_fp->gb_aware = true;
param->value = dev_priv->max_mob_pages * PAGE_SIZE;
break;
+ case DRM_VMW_PARAM_MAX_MOB_SIZE:
+ param->value = dev_priv->max_mob_size;
+ break;
default:
DRM_ERROR("Illegal vmwgfx get param request: %d\n",
param->param);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
index d4a5a19cb8c3..04a64b8cd3cd 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
@@ -188,18 +188,20 @@ static void vmw_takedown_otable_base(struct vmw_private *dev_priv,
bo = otable->page_table->pt_bo;
cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
- if (unlikely(cmd == NULL))
- DRM_ERROR("Failed reserving FIFO space for OTable setup.\n");
-
- memset(cmd, 0, sizeof(*cmd));
- cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;
- cmd->header.size = sizeof(cmd->body);
- cmd->body.type = type;
- cmd->body.baseAddress = 0;
- cmd->body.sizeInBytes = 0;
- cmd->body.validSizeInBytes = 0;
- cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID;
- vmw_fifo_commit(dev_priv, sizeof(*cmd));
+ if (unlikely(cmd == NULL)) {
+ DRM_ERROR("Failed reserving FIFO space for OTable "
+ "takedown.\n");
+ } else {
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;
+ cmd->header.size = sizeof(cmd->body);
+ cmd->body.type = type;
+ cmd->body.baseAddress = 0;
+ cmd->body.sizeInBytes = 0;
+ cmd->body.validSizeInBytes = 0;
+ cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID;
+ vmw_fifo_commit(dev_priv, sizeof(*cmd));
+ }
if (bo) {
int ret;
@@ -562,11 +564,12 @@ void vmw_mob_unbind(struct vmw_private *dev_priv,
if (unlikely(cmd == NULL)) {
DRM_ERROR("Failed reserving FIFO space for Memory "
"Object unbinding.\n");
+ } else {
+ cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB;
+ cmd->header.size = sizeof(cmd->body);
+ cmd->body.mobid = mob->id;
+ vmw_fifo_commit(dev_priv, sizeof(*cmd));
}
- cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB;
- cmd->header.size = sizeof(cmd->body);
- cmd->body.mobid = mob->id;
- vmw_fifo_commit(dev_priv, sizeof(*cmd));
if (bo) {
vmw_fence_single_bo(bo, NULL);
ttm_bo_unreserve(bo);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 2aa4bc6a4d60..9757b57f8388 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -427,8 +427,7 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv,
INIT_LIST_HEAD(&vmw_bo->res_list);
ret = ttm_bo_init(bdev, &vmw_bo->base, size,
- (user) ? ttm_bo_type_device :
- ttm_bo_type_kernel, placement,
+ ttm_bo_type_device, placement,
0, interruptible,
NULL, acc_size, NULL, bo_free);
return ret;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
index 217d941b8176..ee3856578a12 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
@@ -371,13 +371,13 @@ int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
TTM_REF_USAGE);
}
-int vmw_shader_alloc(struct vmw_private *dev_priv,
- struct vmw_dma_buffer *buffer,
- size_t shader_size,
- size_t offset,
- SVGA3dShaderType shader_type,
- struct ttm_object_file *tfile,
- u32 *handle)
+static int vmw_shader_alloc(struct vmw_private *dev_priv,
+ struct vmw_dma_buffer *buffer,
+ size_t shader_size,
+ size_t offset,
+ SVGA3dShaderType shader_type,
+ struct ttm_object_file *tfile,
+ u32 *handle)
{
struct vmw_user_shader *ushader;
struct vmw_resource *res, *tmp;
@@ -779,6 +779,8 @@ vmw_compat_shader_man_create(struct vmw_private *dev_priv)
int ret;
man = kzalloc(sizeof(*man), GFP_KERNEL);
+ if (man == NULL)
+ return ERR_PTR(-ENOMEM);
man->dev_priv = dev_priv;
INIT_LIST_HEAD(&man->list);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index 82468d902915..e7af580ab977 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -830,6 +830,24 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
if (unlikely(ret != 0))
goto out_unlock;
+ /*
+ * A gb-aware client referencing a shared surface will
+ * expect a backup buffer to be present.
+ */
+ if (dev_priv->has_mob && req->shareable) {
+ uint32_t backup_handle;
+
+ ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
+ res->backup_size,
+ true,
+ &backup_handle,
+ &res->backup);
+ if (unlikely(ret != 0)) {
+ vmw_resource_unreference(&res);
+ goto out_unlock;
+ }
+ }
+
tmp = vmw_resource_reference(&srf->res);
ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime,
req->shareable, VMW_RES_SURFACE,
diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c
index 1146e3bba6e1..112f27e51bc7 100644
--- a/drivers/gpu/host1x/job.c
+++ b/drivers/gpu/host1x/job.c
@@ -538,7 +538,7 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev)
g->base = job->gather_addr_phys[i];
- for (j = 0; j < job->num_gathers; j++)
+ for (j = i + 1; j < job->num_gathers; j++)
if (job->gathers[j].bo == g->bo)
job->gathers[j].handled = true;
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 497558127bb3..f822fd2a1ada 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -469,6 +469,9 @@ static const struct hid_device_id apple_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 3bfac3accd22..2448d757b449 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1679,6 +1679,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
@@ -1779,6 +1780,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) },
@@ -2275,6 +2278,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },
{ HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) },
{ }
};
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 8fae6d1414cc..c24908f14934 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -157,6 +157,7 @@ struct mousevsc_dev {
u32 report_desc_size;
struct hv_input_dev_info hid_dev_info;
struct hid_device *hid_device;
+ u8 input_buf[HID_MAX_BUFFER_SIZE];
};
@@ -256,6 +257,7 @@ static void mousevsc_on_receive(struct hv_device *device,
struct synthhid_msg *hid_msg;
struct mousevsc_dev *input_dev = hv_get_drvdata(device);
struct synthhid_input_report *input_report;
+ size_t len;
pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
(packet->offset8 << 3));
@@ -300,9 +302,12 @@ static void mousevsc_on_receive(struct hv_device *device,
(struct synthhid_input_report *)pipe_msg->data;
if (!input_dev->init_complete)
break;
- hid_input_report(input_dev->hid_device,
- HID_INPUT_REPORT, input_report->buffer,
- input_report->header.size, 1);
+
+ len = min(input_report->header.size,
+ (u32)sizeof(input_dev->input_buf));
+ memcpy(input_dev->input_buf, input_report->buffer, len);
+ hid_input_report(input_dev->hid_device, HID_INPUT_REPORT,
+ input_dev->input_buf, len, 1);
break;
default:
pr_err("unsupported hid msg type - type %d len %d",
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 5a5248f2cc07..830de69d2df0 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -135,6 +135,7 @@
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI 0x0255
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS 0x0257
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291
#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292
@@ -240,6 +241,7 @@
#define USB_VENDOR_ID_CYGNAL 0x10c4
#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
+#define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH 0x81b9
#define USB_DEVICE_ID_CYGNAL_RADIO_SI4713 0x8244
@@ -451,6 +453,9 @@
#define USB_VENDOR_ID_INTEL_1 0x8087
#define USB_DEVICE_ID_INTEL_HID_SENSOR 0x09fa
+#define USB_VENDOR_ID_STM_0 0x0483
+#define USB_DEVICE_ID_STM_HID_SENSOR 0x91d1
+
#define USB_VENDOR_ID_ION 0x15e4
#define USB_DEVICE_ID_ICADE 0x0132
@@ -619,6 +624,8 @@
#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730
#define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c
+#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
+#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
#define USB_VENDOR_ID_MOJO 0x8282
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
@@ -644,6 +651,7 @@
#define USB_VENDOR_ID_NEXIO 0x1870
#define USB_DEVICE_ID_NEXIO_MULTITOUCH_420 0x010d
+#define USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750 0x0110
#define USB_VENDOR_ID_NEXTWINDOW 0x1926
#define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003
@@ -953,4 +961,7 @@
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
+#define USB_VENDOR_ID_RISO_KAGAKU 0x1294 /* Riso Kagaku Corp. */
+#define USB_DEVICE_ID_RI_KA_WEBMAIL 0x1320 /* Webmail Notifier */
+
#endif
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index d50e7313b171..a713e6211419 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1178,7 +1178,7 @@ static void hidinput_led_worker(struct work_struct *work)
/* fall back to generic raw-output-report */
len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
- buf = kmalloc(len, GFP_KERNEL);
+ buf = hid_alloc_report_buf(report, GFP_KERNEL);
if (!buf)
return;
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index befe0e336471..24883b4d1a49 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -43,6 +43,7 @@
#define G25_REV_MIN 0x22
#define G27_REV_MAJ 0x12
#define G27_REV_MIN 0x38
+#define G27_2_REV_MIN 0x39
#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
@@ -130,6 +131,7 @@ static const struct lg4ff_usb_revision lg4ff_revs[] = {
{DFP_REV_MAJ, DFP_REV_MIN, &native_dfp}, /* Driving Force Pro */
{G25_REV_MAJ, G25_REV_MIN, &native_g25}, /* G25 */
{G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */
+ {G27_REV_MAJ, G27_2_REV_MIN, &native_g27}, /* G27 v2 */
};
/* Recalculates X axis value accordingly to currently selected range */
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index c6ef6eed3091..404a3a8a82f1 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -208,6 +208,10 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500),
.driver_data = MS_DUPLICATE_USAGES },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2),
+ .driver_data = 0 },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2),
+ .driver_data = 0 },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
.driver_data = MS_PRESENTER },
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index f134d73beca1..221d503f1c24 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -1166,6 +1166,11 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG,
USB_DEVICE_ID_MULTITOUCH_3200) },
+ /* FocalTech Panels */
+ { .driver_data = MT_CLS_SERIAL,
+ MT_USB_DEVICE(USB_VENDOR_ID_CYGNAL,
+ USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH) },
+
/* GeneralTouch panel */
{ .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS,
MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index 7ed828056414..91fab975063c 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -624,7 +624,8 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
/* Setup sound card */
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pm->pk->hdev->dev, index[dev], id[dev],
+ THIS_MODULE, 0, &card);
if (err < 0) {
pk_error("failed to create pc-midi sound card\n");
err = -ENOMEM;
@@ -660,8 +661,6 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
snd_rawmidi_set_ops(rwmidi, SNDRV_RAWMIDI_STREAM_INPUT,
&pcmidi_in_ops);
- snd_card_set_dev(card, &pm->pk->hdev->dev);
-
/* create sysfs variables */
err = device_create_file(&pm->pk->hdev->dev,
sysfs_device_attr_channel);
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 46f4480035bc..9c22e14c57f0 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -665,6 +665,9 @@ static const struct hid_device_id sensor_hub_devices[] = {
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1,
USB_DEVICE_ID_INTEL_HID_SENSOR),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_STM_0,
+ USB_DEVICE_ID_STM_HID_SENSOR),
+ .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 12354055d474..2f19b15f47f2 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -42,6 +42,7 @@
#define DUALSHOCK4_CONTROLLER_BT BIT(6)
#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER | DUALSHOCK4_CONTROLLER_USB)
+#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER_USB | DUALSHOCK4_CONTROLLER_USB)
#define MAX_LEDS 4
@@ -499,6 +500,7 @@ struct sony_sc {
__u8 right;
#endif
+ __u8 worker_initialized;
__u8 led_state[MAX_LEDS];
__u8 led_count;
};
@@ -993,22 +995,11 @@ static int sony_init_ff(struct hid_device *hdev)
return input_ff_create_memless(input_dev, NULL, sony_play_effect);
}
-static void sony_destroy_ff(struct hid_device *hdev)
-{
- struct sony_sc *sc = hid_get_drvdata(hdev);
-
- cancel_work_sync(&sc->state_worker);
-}
-
#else
static int sony_init_ff(struct hid_device *hdev)
{
return 0;
}
-
-static void sony_destroy_ff(struct hid_device *hdev)
-{
-}
#endif
static int sony_set_output_report(struct sony_sc *sc, int req_id, int req_size)
@@ -1077,6 +1068,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
ret = sixaxis_set_operational_usb(hdev);
+
+ sc->worker_initialized = 1;
INIT_WORK(&sc->state_worker, sixaxis_state_worker);
}
else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
@@ -1087,6 +1080,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret < 0)
goto err_stop;
+ sc->worker_initialized = 1;
INIT_WORK(&sc->state_worker, dualshock4_state_worker);
} else {
ret = 0;
@@ -1101,9 +1095,11 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_stop;
}
- ret = sony_init_ff(hdev);
- if (ret < 0)
- goto err_stop;
+ if (sc->quirks & SONY_FF_SUPPORT) {
+ ret = sony_init_ff(hdev);
+ if (ret < 0)
+ goto err_stop;
+ }
return 0;
err_stop:
@@ -1120,7 +1116,8 @@ static void sony_remove(struct hid_device *hdev)
if (sc->quirks & SONY_LED_SUPPORT)
sony_leds_remove(hdev);
- sony_destroy_ff(hdev);
+ if (sc->worker_initialized)
+ cancel_work_sync(&sc->state_worker);
hid_hw_stop(hdev);
}
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index cb0137b3718d..ab24ce2eb28f 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -320,13 +320,13 @@ static void drop_ref(struct hidraw *hidraw, int exists_bit)
hid_hw_close(hidraw->hid);
wake_up_interruptible(&hidraw->wait);
}
+ device_destroy(hidraw_class,
+ MKDEV(hidraw_major, hidraw->minor));
} else {
--hidraw->open;
}
if (!hidraw->open) {
if (!hidraw->exist) {
- device_destroy(hidraw_class,
- MKDEV(hidraw_major, hidraw->minor));
hidraw_table[hidraw->minor] = NULL;
kfree(hidraw);
} else {
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index d1f81f52481a..42eebd14de1f 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -582,7 +582,7 @@ static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep,
int ret;
int len = i2c_hid_get_report_length(rep) - 2;
- buf = kzalloc(len, GFP_KERNEL);
+ buf = hid_alloc_report_buf(rep, GFP_KERNEL);
if (!buf)
return;
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 175ec0afb70c..dbd83878ff99 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -74,6 +74,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile
index 0a74b5661186..5e4dfa4cfe22 100644
--- a/drivers/hv/Makefile
+++ b/drivers/hv/Makefile
@@ -5,4 +5,4 @@ obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o
hv_vmbus-y := vmbus_drv.o \
hv.o connection.o channel.o \
channel_mgmt.o ring_buffer.o
-hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o
+hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 69ea36f07b4d..602ca86a6488 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/hyperv.h>
+#include <linux/uio.h>
#include "hyperv_vmbus.h"
@@ -554,14 +555,14 @@ EXPORT_SYMBOL_GPL(vmbus_close);
*
* Mainly used by Hyper-V drivers.
*/
-int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
+int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer,
u32 bufferlen, u64 requestid,
enum vmbus_packet_type type, u32 flags)
{
struct vmpacket_descriptor desc;
u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen;
u32 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
- struct scatterlist bufferlist[3];
+ struct kvec bufferlist[3];
u64 aligned_data = 0;
int ret;
bool signal = false;
@@ -575,11 +576,12 @@ int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
desc.len8 = (u16)(packetlen_aligned >> 3);
desc.trans_id = requestid;
- sg_init_table(bufferlist, 3);
- sg_set_buf(&bufferlist[0], &desc, sizeof(struct vmpacket_descriptor));
- sg_set_buf(&bufferlist[1], buffer, bufferlen);
- sg_set_buf(&bufferlist[2], &aligned_data,
- packetlen_aligned - packetlen);
+ bufferlist[0].iov_base = &desc;
+ bufferlist[0].iov_len = sizeof(struct vmpacket_descriptor);
+ bufferlist[1].iov_base = buffer;
+ bufferlist[1].iov_len = bufferlen;
+ bufferlist[2].iov_base = &aligned_data;
+ bufferlist[2].iov_len = (packetlen_aligned - packetlen);
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
@@ -605,7 +607,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
u32 descsize;
u32 packetlen;
u32 packetlen_aligned;
- struct scatterlist bufferlist[3];
+ struct kvec bufferlist[3];
u64 aligned_data = 0;
bool signal = false;
@@ -637,11 +639,12 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
desc.range[i].pfn = pagebuffers[i].pfn;
}
- sg_init_table(bufferlist, 3);
- sg_set_buf(&bufferlist[0], &desc, descsize);
- sg_set_buf(&bufferlist[1], buffer, bufferlen);
- sg_set_buf(&bufferlist[2], &aligned_data,
- packetlen_aligned - packetlen);
+ bufferlist[0].iov_base = &desc;
+ bufferlist[0].iov_len = descsize;
+ bufferlist[1].iov_base = buffer;
+ bufferlist[1].iov_len = bufferlen;
+ bufferlist[2].iov_base = &aligned_data;
+ bufferlist[2].iov_len = (packetlen_aligned - packetlen);
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
@@ -665,7 +668,7 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
u32 descsize;
u32 packetlen;
u32 packetlen_aligned;
- struct scatterlist bufferlist[3];
+ struct kvec bufferlist[3];
u64 aligned_data = 0;
bool signal = false;
u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
@@ -700,11 +703,12 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
memcpy(desc.range.pfn_array, multi_pagebuffer->pfn_array,
pfncount * sizeof(u64));
- sg_init_table(bufferlist, 3);
- sg_set_buf(&bufferlist[0], &desc, descsize);
- sg_set_buf(&bufferlist[1], buffer, bufferlen);
- sg_set_buf(&bufferlist[2], &aligned_data,
- packetlen_aligned - packetlen);
+ bufferlist[0].iov_base = &desc;
+ bufferlist[0].iov_len = descsize;
+ bufferlist[1].iov_base = buffer;
+ bufferlist[1].iov_len = bufferlen;
+ bufferlist[2].iov_base = &aligned_data;
+ bufferlist[2].iov_len = (packetlen_aligned - packetlen);
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index 7e17a5495e02..7e6d78dc9437 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -1171,7 +1171,8 @@ static int dm_thread_func(void *dm_dev)
int t;
while (!kthread_should_stop()) {
- t = wait_for_completion_timeout(&dm_device.config_event, 1*HZ);
+ t = wait_for_completion_interruptible_timeout(
+ &dm_device.config_event, 1*HZ);
/*
* The host expects us to post information on the memory
* pressure every second.
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
new file mode 100644
index 000000000000..eaaa3d843b80
--- /dev/null
+++ b/drivers/hv/hv_fcopy.c
@@ -0,0 +1,414 @@
+/*
+ * An implementation of file copy service.
+ *
+ * Copyright (C) 2014, Microsoft, Inc.
+ *
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/semaphore.h>
+#include <linux/fs.h>
+#include <linux/nls.h>
+#include <linux/workqueue.h>
+#include <linux/cdev.h>
+#include <linux/hyperv.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+
+#include "hyperv_vmbus.h"
+
+#define WIN8_SRV_MAJOR 1
+#define WIN8_SRV_MINOR 1
+#define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
+
+/*
+ * Global state maintained for transaction that is being processed.
+ * For a class of integration services, including the "file copy service",
+ * the specified protocol is a "request/response" protocol which means that
+ * there can only be single outstanding transaction from the host at any
+ * given point in time. We use this to simplify memory management in this
+ * driver - we cache and process only one message at a time.
+ *
+ * While the request/response protocol is guaranteed by the host, we further
+ * ensure this by serializing packet processing in this driver - we do not
+ * read additional packets from the VMBUs until the current packet is fully
+ * handled.
+ *
+ * The transaction "active" state is set when we receive a request from the
+ * host and we cleanup this state when the transaction is completed - when we
+ * respond to the host with our response. When the transaction active state is
+ * set, we defer handling incoming packets.
+ */
+
+static struct {
+ bool active; /* transaction status - active or not */
+ int recv_len; /* number of bytes received. */
+ struct hv_fcopy_hdr *fcopy_msg; /* current message */
+ struct hv_start_fcopy message; /* sent to daemon */
+ struct vmbus_channel *recv_channel; /* chn we got the request */
+ u64 recv_req_id; /* request ID. */
+ void *fcopy_context; /* for the channel callback */
+ struct semaphore read_sema;
+} fcopy_transaction;
+
+static bool opened; /* currently device opened */
+
+/*
+ * Before we can accept copy messages from the host, we need
+ * to handshake with the user level daemon. This state tracks
+ * if we are in the handshake phase.
+ */
+static bool in_hand_shake = true;
+static void fcopy_send_data(void);
+static void fcopy_respond_to_host(int error);
+static void fcopy_work_func(struct work_struct *dummy);
+static DECLARE_DELAYED_WORK(fcopy_work, fcopy_work_func);
+static u8 *recv_buffer;
+
+static void fcopy_work_func(struct work_struct *dummy)
+{
+ /*
+ * If the timer fires, the user-mode component has not responded;
+ * process the pending transaction.
+ */
+ fcopy_respond_to_host(HV_E_FAIL);
+}
+
+static int fcopy_handle_handshake(u32 version)
+{
+ switch (version) {
+ case FCOPY_CURRENT_VERSION:
+ break;
+ default:
+ /*
+ * For now we will fail the registration.
+ * If and when we have multiple versions to
+ * deal with, we will be backward compatible.
+ * We will add this code when needed.
+ */
+ return -EINVAL;
+ }
+ pr_info("FCP: user-mode registering done. Daemon version: %d\n",
+ version);
+ fcopy_transaction.active = false;
+ if (fcopy_transaction.fcopy_context)
+ hv_fcopy_onchannelcallback(fcopy_transaction.fcopy_context);
+ in_hand_shake = false;
+ return 0;
+}
+
+static void fcopy_send_data(void)
+{
+ struct hv_start_fcopy *smsg_out = &fcopy_transaction.message;
+ int operation = fcopy_transaction.fcopy_msg->operation;
+ struct hv_start_fcopy *smsg_in;
+
+ /*
+ * The strings sent from the host are encoded in
+ * in utf16; convert it to utf8 strings.
+ * The host assures us that the utf16 strings will not exceed
+ * the max lengths specified. We will however, reserve room
+ * for the string terminating character - in the utf16s_utf8s()
+ * function we limit the size of the buffer where the converted
+ * string is placed to W_MAX_PATH -1 to guarantee
+ * that the strings can be properly terminated!
+ */
+
+ switch (operation) {
+ case START_FILE_COPY:
+ memset(smsg_out, 0, sizeof(struct hv_start_fcopy));
+ smsg_out->hdr.operation = operation;
+ smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg;
+
+ utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH,
+ UTF16_LITTLE_ENDIAN,
+ (__u8 *)smsg_out->file_name, W_MAX_PATH - 1);
+
+ utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH,
+ UTF16_LITTLE_ENDIAN,
+ (__u8 *)smsg_out->path_name, W_MAX_PATH - 1);
+
+ smsg_out->copy_flags = smsg_in->copy_flags;
+ smsg_out->file_size = smsg_in->file_size;
+ break;
+
+ default:
+ break;
+ }
+ up(&fcopy_transaction.read_sema);
+ return;
+}
+
+/*
+ * Send a response back to the host.
+ */
+
+static void
+fcopy_respond_to_host(int error)
+{
+ struct icmsg_hdr *icmsghdr;
+ u32 buf_len;
+ struct vmbus_channel *channel;
+ u64 req_id;
+
+ /*
+ * Copy the global state for completing the transaction. Note that
+ * only one transaction can be active at a time. This is guaranteed
+ * by the file copy protocol implemented by the host. Furthermore,
+ * the "transaction active" state we maintain ensures that there can
+ * only be one active transaction at a time.
+ */
+
+ buf_len = fcopy_transaction.recv_len;
+ channel = fcopy_transaction.recv_channel;
+ req_id = fcopy_transaction.recv_req_id;
+
+ fcopy_transaction.active = false;
+
+ icmsghdr = (struct icmsg_hdr *)
+ &recv_buffer[sizeof(struct vmbuspipe_hdr)];
+
+ if (channel->onchannel_callback == NULL)
+ /*
+ * We have raced with util driver being unloaded;
+ * silently return.
+ */
+ return;
+
+ icmsghdr->status = error;
+ icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
+ vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
+ VM_PKT_DATA_INBAND, 0);
+}
+
+void hv_fcopy_onchannelcallback(void *context)
+{
+ struct vmbus_channel *channel = context;
+ u32 recvlen;
+ u64 requestid;
+ struct hv_fcopy_hdr *fcopy_msg;
+ struct icmsg_hdr *icmsghdr;
+ struct icmsg_negotiate *negop = NULL;
+ int util_fw_version;
+ int fcopy_srv_version;
+
+ if (fcopy_transaction.active) {
+ /*
+ * We will defer processing this callback once
+ * the current transaction is complete.
+ */
+ fcopy_transaction.fcopy_context = context;
+ return;
+ }
+
+ vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
+ &requestid);
+ if (recvlen <= 0)
+ return;
+
+ icmsghdr = (struct icmsg_hdr *)&recv_buffer[
+ sizeof(struct vmbuspipe_hdr)];
+ if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ util_fw_version = UTIL_FW_VERSION;
+ fcopy_srv_version = WIN8_SRV_VERSION;
+ vmbus_prep_negotiate_resp(icmsghdr, negop, recv_buffer,
+ util_fw_version, fcopy_srv_version);
+ } else {
+ fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+
+ /*
+ * Stash away this global state for completing the
+ * transaction; note transactions are serialized.
+ */
+
+ fcopy_transaction.active = true;
+ fcopy_transaction.recv_len = recvlen;
+ fcopy_transaction.recv_channel = channel;
+ fcopy_transaction.recv_req_id = requestid;
+ fcopy_transaction.fcopy_msg = fcopy_msg;
+
+ /*
+ * Send the information to the user-level daemon.
+ */
+ fcopy_send_data();
+ schedule_delayed_work(&fcopy_work, 5*HZ);
+ return;
+ }
+ icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
+ vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
+ VM_PKT_DATA_INBAND, 0);
+}
+
+/*
+ * Create a char device that can support read/write for passing
+ * the payload.
+ */
+
+static ssize_t fcopy_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ void *src;
+ size_t copy_size;
+ int operation;
+
+ /*
+ * Wait until there is something to be read.
+ */
+ if (down_interruptible(&fcopy_transaction.read_sema))
+ return -EINTR;
+
+ /*
+ * The channel may be rescinded and in this case, we will wakeup the
+ * the thread blocked on the semaphore and we will use the opened
+ * state to correctly handle this case.
+ */
+ if (!opened)
+ return -ENODEV;
+
+ operation = fcopy_transaction.fcopy_msg->operation;
+
+ if (operation == START_FILE_COPY) {
+ src = &fcopy_transaction.message;
+ copy_size = sizeof(struct hv_start_fcopy);
+ if (count < copy_size)
+ return 0;
+ } else {
+ src = fcopy_transaction.fcopy_msg;
+ copy_size = sizeof(struct hv_do_fcopy);
+ if (count < copy_size)
+ return 0;
+ }
+ if (copy_to_user(buf, src, copy_size))
+ return -EFAULT;
+
+ return copy_size;
+}
+
+static ssize_t fcopy_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int response = 0;
+
+ if (count != sizeof(int))
+ return -EINVAL;
+
+ if (copy_from_user(&response, buf, sizeof(int)))
+ return -EFAULT;
+
+ if (in_hand_shake) {
+ if (fcopy_handle_handshake(response))
+ return -EINVAL;
+ return sizeof(int);
+ }
+
+ /*
+ * Complete the transaction by forwarding the result
+ * to the host. But first, cancel the timeout.
+ */
+ if (cancel_delayed_work_sync(&fcopy_work))
+ fcopy_respond_to_host(response);
+
+ return sizeof(int);
+}
+
+static int fcopy_open(struct inode *inode, struct file *f)
+{
+ /*
+ * The user level daemon that will open this device is
+ * really an extension of this driver. We can have only
+ * active open at a time.
+ */
+ if (opened)
+ return -EBUSY;
+
+ /*
+ * The daemon is alive; setup the state.
+ */
+ opened = true;
+ return 0;
+}
+
+static int fcopy_release(struct inode *inode, struct file *f)
+{
+ /*
+ * The daemon has exited; reset the state.
+ */
+ in_hand_shake = true;
+ opened = false;
+ return 0;
+}
+
+
+static const struct file_operations fcopy_fops = {
+ .read = fcopy_read,
+ .write = fcopy_write,
+ .release = fcopy_release,
+ .open = fcopy_open,
+};
+
+static struct miscdevice fcopy_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "vmbus/hv_fcopy",
+ .fops = &fcopy_fops,
+};
+
+static int fcopy_dev_init(void)
+{
+ return misc_register(&fcopy_misc);
+}
+
+static void fcopy_dev_deinit(void)
+{
+
+ /*
+ * The device is going away - perhaps because the
+ * host has rescinded the channel. Setup state so that
+ * user level daemon can gracefully exit if it is blocked
+ * on the read semaphore.
+ */
+ opened = false;
+ /*
+ * Signal the semaphore as the device is
+ * going away.
+ */
+ up(&fcopy_transaction.read_sema);
+ misc_deregister(&fcopy_misc);
+}
+
+int hv_fcopy_init(struct hv_util_service *srv)
+{
+ recv_buffer = srv->recv_buffer;
+
+ /*
+ * When this driver loads, the user level daemon that
+ * processes the host requests may not yet be running.
+ * Defer processing channel callbacks until the daemon
+ * has registered.
+ */
+ fcopy_transaction.active = true;
+ sema_init(&fcopy_transaction.read_sema, 0);
+
+ return fcopy_dev_init();
+}
+
+void hv_fcopy_deinit(void)
+{
+ cancel_delayed_work_sync(&fcopy_work);
+ fcopy_dev_deinit();
+}
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 09988b289622..ea852537307e 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -113,7 +113,7 @@ kvp_register(int reg_value)
kvp_msg->kvp_hdr.operation = reg_value;
strcpy(version, HV_DRV_VERSION);
msg->len = sizeof(struct hv_kvp_msg);
- cn_netlink_send(msg, 0, GFP_ATOMIC);
+ cn_netlink_send(msg, 0, 0, GFP_ATOMIC);
kfree(msg);
}
}
@@ -435,7 +435,7 @@ kvp_send_key(struct work_struct *dummy)
}
msg->len = sizeof(struct hv_kvp_msg);
- cn_netlink_send(msg, 0, GFP_ATOMIC);
+ cn_netlink_send(msg, 0, 0, GFP_ATOMIC);
kfree(msg);
return;
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index 0c3546224376..34f14fddb666 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -98,7 +98,7 @@ static void vss_send_op(struct work_struct *dummy)
vss_msg->vss_hdr.operation = op;
msg->len = sizeof(struct hv_vss_msg);
- cn_netlink_send(msg, 0, GFP_ATOMIC);
+ cn_netlink_send(msg, 0, 0, GFP_ATOMIC);
kfree(msg);
return;
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index 62dfd246b948..dd761806f0e8 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -28,6 +28,7 @@
#include <linux/reboot.h>
#include <linux/hyperv.h>
+#include "hyperv_vmbus.h"
#define SD_MAJOR 3
#define SD_MINOR 0
@@ -82,6 +83,12 @@ static struct hv_util_service util_vss = {
.util_deinit = hv_vss_deinit,
};
+static struct hv_util_service util_fcopy = {
+ .util_cb = hv_fcopy_onchannelcallback,
+ .util_init = hv_fcopy_init,
+ .util_deinit = hv_fcopy_deinit,
+};
+
static void perform_shutdown(struct work_struct *dummy)
{
orderly_poweroff(true);
@@ -401,6 +408,10 @@ static const struct hv_vmbus_device_id id_table[] = {
{ HV_VSS_GUID,
.driver_data = (unsigned long)&util_vss
},
+ /* File copy GUID */
+ { HV_FCOPY_GUID,
+ .driver_data = (unsigned long)&util_fcopy
+ },
{ },
};
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index e05517616a06..860134da8039 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -559,8 +559,8 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer,
void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
- struct scatterlist *sglist,
- u32 sgcount, bool *signal);
+ struct kvec *kv_list,
+ u32 kv_count, bool *signal);
int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
u32 buflen);
@@ -669,5 +669,9 @@ int vmbus_set_event(struct vmbus_channel *channel);
void vmbus_on_event(unsigned long data);
+int hv_fcopy_init(struct hv_util_service *);
+void hv_fcopy_deinit(void);
+void hv_fcopy_onchannelcallback(void *);
+
#endif /* _HYPERV_VMBUS_H */
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index 26c93cf9f6be..15db66b74141 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/hyperv.h>
+#include <linux/uio.h>
#include "hyperv_vmbus.h"
@@ -387,23 +388,20 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
*
*/
int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
- struct scatterlist *sglist, u32 sgcount, bool *signal)
+ struct kvec *kv_list, u32 kv_count, bool *signal)
{
int i = 0;
u32 bytes_avail_towrite;
u32 bytes_avail_toread;
u32 totalbytes_towrite = 0;
- struct scatterlist *sg;
u32 next_write_location;
u32 old_write;
u64 prev_indices = 0;
unsigned long flags;
- for_each_sg(sglist, sg, sgcount, i)
- {
- totalbytes_towrite += sg->length;
- }
+ for (i = 0; i < kv_count; i++)
+ totalbytes_towrite += kv_list[i].iov_len;
totalbytes_towrite += sizeof(u64);
@@ -427,12 +425,11 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
old_write = next_write_location;
- for_each_sg(sglist, sg, sgcount, i)
- {
+ for (i = 0; i < kv_count; i++) {
next_write_location = hv_copyto_ringbuffer(outring_info,
next_write_location,
- sg_virt(sg),
- sg->length);
+ kv_list[i].iov_base,
+ kv_list[i].iov_len);
}
/* Set previous packet start */
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 077bb1bdac34..8e53a3c2607e 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -25,7 +25,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
-#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/sysctl.h>
#include <linux/slab.h>
@@ -44,6 +43,12 @@ static struct tasklet_struct msg_dpc;
static struct completion probe_event;
static int irq;
+struct resource hyperv_mmio = {
+ .name = "hyperv mmio",
+ .flags = IORESOURCE_MEM,
+};
+EXPORT_SYMBOL_GPL(hyperv_mmio);
+
static int vmbus_exists(void)
{
if (hv_acpi_dev == NULL)
@@ -558,9 +563,6 @@ static struct bus_type hv_bus = {
.dev_groups = vmbus_groups,
};
-static const char *driver_name = "hyperv";
-
-
struct onmessage_work_context {
struct work_struct work;
struct hv_message msg;
@@ -619,7 +621,7 @@ static void vmbus_on_msg_dpc(unsigned long data)
}
}
-static irqreturn_t vmbus_isr(int irq, void *dev_id)
+static void vmbus_isr(void)
{
int cpu = smp_processor_id();
void *page_addr;
@@ -629,7 +631,7 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
page_addr = hv_context.synic_event_page[cpu];
if (page_addr == NULL)
- return IRQ_NONE;
+ return;
event = (union hv_synic_event_flags *)page_addr +
VMBUS_MESSAGE_SINT;
@@ -665,28 +667,8 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
/* Check if there are actual msgs to be processed */
- if (msg->header.message_type != HVMSG_NONE) {
- handled = true;
+ if (msg->header.message_type != HVMSG_NONE)
tasklet_schedule(&msg_dpc);
- }
-
- if (handled)
- return IRQ_HANDLED;
- else
- return IRQ_NONE;
-}
-
-/*
- * vmbus interrupt flow handler:
- * vmbus interrupts can concurrently occur on multiple CPUs and
- * can be handled concurrently.
- */
-
-static void vmbus_flow_handler(unsigned int irq, struct irq_desc *desc)
-{
- kstat_incr_irqs_this_cpu(irq, desc);
-
- desc->action->handler(irq, desc->action->dev_id);
}
/*
@@ -715,25 +697,7 @@ static int vmbus_bus_init(int irq)
if (ret)
goto err_cleanup;
- ret = request_irq(irq, vmbus_isr, 0, driver_name, hv_acpi_dev);
-
- if (ret != 0) {
- pr_err("Unable to request IRQ %d\n",
- irq);
- goto err_unregister;
- }
-
- /*
- * Vmbus interrupts can be handled concurrently on
- * different CPUs. Establish an appropriate interrupt flow
- * handler that can support this model.
- */
- irq_set_handler(irq, vmbus_flow_handler);
-
- /*
- * Register our interrupt handler.
- */
- hv_register_vmbus_handler(irq, vmbus_isr);
+ hv_setup_vmbus_irq(vmbus_isr);
ret = hv_synic_alloc();
if (ret)
@@ -753,9 +717,8 @@ static int vmbus_bus_init(int irq)
err_alloc:
hv_synic_free();
- free_irq(irq, hv_acpi_dev);
+ hv_remove_vmbus_irq();
-err_unregister:
bus_unregister(&hv_bus);
err_cleanup:
@@ -886,18 +849,21 @@ void vmbus_device_unregister(struct hv_device *device_obj)
/*
- * VMBUS is an acpi enumerated device. Get the the IRQ information
- * from DSDT.
+ * VMBUS is an acpi enumerated device. Get the the information we
+ * need from DSDT.
*/
-static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *irq)
+static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
{
+ switch (res->type) {
+ case ACPI_RESOURCE_TYPE_IRQ:
+ irq = res->data.irq.interrupts[0];
+ break;
- if (res->type == ACPI_RESOURCE_TYPE_IRQ) {
- struct acpi_resource_irq *irqp;
- irqp = &res->data.irq;
-
- *((unsigned int *)irq) = irqp->interrupts[0];
+ case ACPI_RESOURCE_TYPE_ADDRESS64:
+ hyperv_mmio.start = res->data.address64.minimum;
+ hyperv_mmio.end = res->data.address64.maximum;
+ break;
}
return AE_OK;
@@ -906,18 +872,34 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *irq)
static int vmbus_acpi_add(struct acpi_device *device)
{
acpi_status result;
+ int ret_val = -ENODEV;
hv_acpi_dev = device;
result = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
- vmbus_walk_resources, &irq);
+ vmbus_walk_resources, NULL);
- if (ACPI_FAILURE(result)) {
- complete(&probe_event);
- return -ENODEV;
+ if (ACPI_FAILURE(result))
+ goto acpi_walk_err;
+ /*
+ * The parent of the vmbus acpi device (Gen2 firmware) is the VMOD that
+ * has the mmio ranges. Get that.
+ */
+ if (device->parent) {
+ result = acpi_walk_resources(device->parent->handle,
+ METHOD_NAME__CRS,
+ vmbus_walk_resources, NULL);
+
+ if (ACPI_FAILURE(result))
+ goto acpi_walk_err;
+ if (hyperv_mmio.start && hyperv_mmio.end)
+ request_resource(&iomem_resource, &hyperv_mmio);
}
+ ret_val = 0;
+
+acpi_walk_err:
complete(&probe_event);
- return 0;
+ return ret_val;
}
static const struct acpi_device_id vmbus_acpi_device_ids[] = {
@@ -947,7 +929,6 @@ static int __init hv_acpi_init(void)
/*
* Get irq resources first.
*/
-
ret = acpi_bus_register_driver(&vmbus_acpi_driver);
if (ret)
@@ -978,8 +959,7 @@ cleanup:
static void __exit vmbus_exit(void)
{
-
- free_irq(irq, hv_acpi_dev);
+ hv_remove_vmbus_irq();
vmbus_free_channels();
bus_unregister(&hv_bus);
hv_cleanup();
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 5ce43d8dfa98..b53d87958710 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -111,22 +111,6 @@ config SENSORS_AD7418
This driver can also be built as a module. If so, the module
will be called ad7418.
-config SENSORS_ADCXX
- tristate "National Semiconductor ADCxxxSxxx"
- depends on SPI_MASTER
- help
- If you say yes here you get support for the National Semiconductor
- ADC<bb><c>S<sss> chip family, where
- * bb is the resolution in number of bits (8, 10, 12)
- * c is the number of channels (1, 2, 4, 8)
- * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500
- kSPS and 101 for 1 MSPS)
-
- Examples : ADC081S101, ADC124S501, ...
-
- This driver can also be built as a module. If so, the module
- will be called adcxx.
-
config SENSORS_ADM1021
tristate "Analog Devices ADM1021 and compatibles"
depends on I2C
@@ -312,6 +296,31 @@ config SENSORS_FAM15H_POWER
This driver can also be built as a module. If so, the module
will be called fam15h_power.
+config SENSORS_APPLESMC
+ tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
+ depends on INPUT && X86
+ select NEW_LEDS
+ select LEDS_CLASS
+ select INPUT_POLLDEV
+ default n
+ help
+ This driver provides support for the Apple System Management
+ Controller, which provides an accelerometer (Apple Sudden Motion
+ Sensor), light sensors, temperature sensors, keyboard backlight
+ control and fan control.
+
+ Only Intel-based Apple's computers are supported (MacBook Pro,
+ MacBook, MacMini).
+
+ Data from the different sensors, keyboard backlight control and fan
+ control are accessible via sysfs.
+
+ This driver also provides an absolute input class device, allowing
+ the laptop to act as a pinball machine-esque joystick.
+
+ Say Y here if you have an applicable laptop and want to experience
+ the awesome power of applesmc.
+
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
depends on X86 && I2C
@@ -435,6 +444,12 @@ config SENSORS_F75375S
This driver can also be built as a module. If so, the module
will be called f75375s.
+config SENSORS_MC13783_ADC
+ tristate "Freescale MC13783/MC13892 ADC"
+ depends on MFD_MC13XXX
+ help
+ Support for the A/D converter on MC13783 and MC13892 PMIC.
+
config SENSORS_FSCHMD
tristate "Fujitsu Siemens Computers sensor chips"
depends on X86 && I2C
@@ -451,26 +466,6 @@ config SENSORS_FSCHMD
This driver can also be built as a module. If so, the module
will be called fschmd.
-config SENSORS_G760A
- tristate "GMT G760A"
- depends on I2C
- help
- If you say yes here you get support for Global Mixed-mode
- Technology Inc G760A fan speed PWM controller chips.
-
- This driver can also be built as a module. If so, the module
- will be called g760a.
-
-config SENSORS_G762
- tristate "GMT G762 and G763"
- depends on I2C
- help
- If you say yes here you get support for Global Mixed-mode
- Technology Inc G762 and G763 fan speed PWM controller chips.
-
- This driver can also be built as a module. If so, the module
- will be called g762.
-
config SENSORS_GL518SM
tristate "Genesys Logic GL518SM"
depends on I2C
@@ -492,6 +487,26 @@ config SENSORS_GL520SM
This driver can also be built as a module. If so, the module
will be called gl520sm.
+config SENSORS_G760A
+ tristate "GMT G760A"
+ depends on I2C
+ help
+ If you say yes here you get support for Global Mixed-mode
+ Technology Inc G760A fan speed PWM controller chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called g760a.
+
+config SENSORS_G762
+ tristate "GMT G762 and G763"
+ depends on I2C
+ help
+ If you say yes here you get support for Global Mixed-mode
+ Technology Inc G762 and G763 fan speed PWM controller chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called g762.
+
config SENSORS_GPIO_FAN
tristate "GPIO fan"
depends on GPIOLIB
@@ -511,24 +526,6 @@ config SENSORS_HIH6130
This driver can also be built as a module. If so, the module
will be called hih6130.
-config SENSORS_HTU21
- tristate "Measurement Specialties HTU21D humidity/temperature sensors"
- depends on I2C
- help
- If you say yes here you get support for the Measurement Specialties
- HTU21D humidity and temperature sensors.
-
- This driver can also be built as a module. If so, the module
- will be called htu21.
-
-config SENSORS_CORETEMP
- tristate "Intel Core/Core2/Atom temperature sensor"
- depends on X86
- help
- If you say yes here you get support for the temperature
- sensor inside your CPU. Most of the family 6 CPUs
- are supported. Check Documentation/hwmon/coretemp for details.
-
config SENSORS_IBMAEM
tristate "IBM Active Energy Manager temperature/power sensors and control"
select IPMI_SI
@@ -557,6 +554,14 @@ config SENSORS_IBMPEX
This driver can also be built as a module. If so, the module
will be called ibmpex.
+config SENSORS_IBMPOWERNV
+ tristate "IBM PowerNv Platform temperature/power/fan sensor"
+ depends on PPC_POWERNV
+ default y
+ help
+ If you say yes here you get support for the temperature/fan/power
+ sensors on your platform.
+
config SENSORS_IIO_HWMON
tristate "Hwmon driver that uses channels specified via iio maps"
depends on IIO
@@ -566,6 +571,14 @@ config SENSORS_IIO_HWMON
for those channels specified in the map. This map can be provided
either via platform data or the device tree bindings.
+config SENSORS_CORETEMP
+ tristate "Intel Core/Core2/Atom temperature sensor"
+ depends on X86
+ help
+ If you say yes here you get support for the temperature
+ sensor inside your CPU. Most of the family 6 CPUs
+ are supported. Check Documentation/hwmon/coretemp for details.
+
config SENSORS_IT87
tristate "ITE IT87xx and compatibles"
depends on !PPC
@@ -614,6 +627,219 @@ config SENSORS_LINEAGE
This driver can also be built as a module. If so, the module
will be called lineage-pem.
+config SENSORS_LTC2945
+ tristate "Linear Technology LTC2945"
+ depends on I2C
+ select REGMAP_I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC2945
+ I2C System Monitor.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc2945.
+
+config SENSORS_LTC4151
+ tristate "Linear Technology LTC4151"
+ depends on I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4151
+ High Voltage I2C Current and Voltage Monitor interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4151.
+
+config SENSORS_LTC4215
+ tristate "Linear Technology LTC4215"
+ depends on I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4215
+ Hot Swap Controller I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4215.
+
+config SENSORS_LTC4222
+ tristate "Linear Technology LTC4222"
+ depends on I2C
+ select REGMAP_I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4222
+ Dual Hot Swap Controller I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4222.
+
+config SENSORS_LTC4245
+ tristate "Linear Technology LTC4245"
+ depends on I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4245
+ Multiple Supply Hot Swap Controller I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4245.
+
+config SENSORS_LTC4260
+ tristate "Linear Technology LTC4260"
+ depends on I2C
+ select REGMAP_I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4260
+ Positive Voltage Hot Swap Controller I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4260.
+
+config SENSORS_LTC4261
+ tristate "Linear Technology LTC4261"
+ depends on I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4261
+ Negative Voltage Hot Swap Controller I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4261.
+
+config SENSORS_MAX1111
+ tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
+ depends on SPI_MASTER
+ help
+ Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113
+ ADC chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called max1111.
+
+config SENSORS_MAX16065
+ tristate "Maxim MAX16065 System Manager and compatibles"
+ depends on I2C
+ help
+ If you say yes here you get support for hardware monitoring
+ capabilities of the following Maxim System Manager chips.
+ MAX16065
+ MAX16066
+ MAX16067
+ MAX16068
+ MAX16070
+ MAX16071
+
+ This driver can also be built as a module. If so, the module
+ will be called max16065.
+
+config SENSORS_MAX1619
+ tristate "Maxim MAX1619 sensor chip"
+ depends on I2C
+ help
+ If you say yes here you get support for MAX1619 sensor chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called max1619.
+
+config SENSORS_MAX1668
+ tristate "Maxim MAX1668 and compatibles"
+ depends on I2C
+ help
+ If you say yes here you get support for MAX1668, MAX1989 and
+ MAX1805 chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called max1668.
+
+config SENSORS_MAX197
+ tristate "Maxim MAX197 and compatibles"
+ help
+ Support for the Maxim MAX197 A/D converter.
+ Support will include, but not be limited to, MAX197, and MAX199.
+
+ This driver can also be built as a module. If so, the module
+ will be called max197.
+
+config SENSORS_MAX6639
+ tristate "Maxim MAX6639 sensor chip"
+ depends on I2C
+ help
+ If you say yes here you get support for the MAX6639
+ sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called max6639.
+
+config SENSORS_MAX6642
+ tristate "Maxim MAX6642 sensor chip"
+ depends on I2C
+ help
+ If you say yes here you get support for MAX6642 sensor chip.
+ MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
+ with Overtemperature Alarm from Maxim.
+
+ This driver can also be built as a module. If so, the module
+ will be called max6642.
+
+config SENSORS_MAX6650
+ tristate "Maxim MAX6650 sensor chip"
+ depends on I2C
+ help
+ If you say yes here you get support for the MAX6650 / MAX6651
+ sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called max6650.
+
+config SENSORS_MAX6697
+ tristate "Maxim MAX6697 and compatibles"
+ depends on I2C
+ help
+ If you say yes here you get support for MAX6581, MAX6602, MAX6622,
+ MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699
+ temperature sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called max6697.
+
+config SENSORS_HTU21
+ tristate "Measurement Specialties HTU21D humidity/temperature sensors"
+ depends on I2C
+ help
+ If you say yes here you get support for the Measurement Specialties
+ HTU21D humidity and temperature sensors.
+
+ This driver can also be built as a module. If so, the module
+ will be called htu21.
+
+config SENSORS_MCP3021
+ tristate "Microchip MCP3021 and compatibles"
+ depends on I2C
+ help
+ If you say yes here you get support for MCP3021 and MCP3221.
+ The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221
+ with 12-bit resolution.
+
+ This driver can also be built as a module. If so, the module
+ will be called mcp3021.
+
+config SENSORS_ADCXX
+ tristate "National Semiconductor ADCxxxSxxx"
+ depends on SPI_MASTER
+ help
+ If you say yes here you get support for the National Semiconductor
+ ADC<bb><c>S<sss> chip family, where
+ * bb is the resolution in number of bits (8, 10, 12)
+ * c is the number of channels (1, 2, 4, 8)
+ * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500
+ kSPS and 101 for 1 MSPS)
+
+ Examples : ADC081S101, ADC124S501, ...
+
+ This driver can also be built as a module. If so, the module
+ will be called adcxx.
+
config SENSORS_LM63
tristate "National Semiconductor LM63 and compatibles"
depends on I2C
@@ -776,50 +1002,6 @@ config SENSORS_LM93
This driver can also be built as a module. If so, the module
will be called lm93.
-config SENSORS_LTC4151
- tristate "Linear Technology LTC4151"
- depends on I2C
- default n
- help
- If you say yes here you get support for Linear Technology LTC4151
- High Voltage I2C Current and Voltage Monitor interface.
-
- This driver can also be built as a module. If so, the module will
- be called ltc4151.
-
-config SENSORS_LTC4215
- tristate "Linear Technology LTC4215"
- depends on I2C
- default n
- help
- If you say yes here you get support for Linear Technology LTC4215
- Hot Swap Controller I2C interface.
-
- This driver can also be built as a module. If so, the module will
- be called ltc4215.
-
-config SENSORS_LTC4245
- tristate "Linear Technology LTC4245"
- depends on I2C
- default n
- help
- If you say yes here you get support for Linear Technology LTC4245
- Multiple Supply Hot Swap Controller I2C interface.
-
- This driver can also be built as a module. If so, the module will
- be called ltc4245.
-
-config SENSORS_LTC4261
- tristate "Linear Technology LTC4261"
- depends on I2C
- default n
- help
- If you say yes here you get support for Linear Technology LTC4261
- Negative Voltage Hot Swap Controller I2C interface.
-
- This driver can also be built as a module. If so, the module will
- be called ltc4261.
-
config SENSORS_LM95234
tristate "National Semiconductor LM95234"
depends on I2C
@@ -849,125 +1031,33 @@ config SENSORS_LM95245
This driver can also be built as a module. If so, the module
will be called lm95245.
-config SENSORS_MAX1111
- tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
- depends on SPI_MASTER
- help
- Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113
- ADC chips.
-
- This driver can also be built as a module. If so, the module
- will be called max1111.
-
-config SENSORS_MAX16065
- tristate "Maxim MAX16065 System Manager and compatibles"
- depends on I2C
- help
- If you say yes here you get support for hardware monitoring
- capabilities of the following Maxim System Manager chips.
- MAX16065
- MAX16066
- MAX16067
- MAX16068
- MAX16070
- MAX16071
-
- This driver can also be built as a module. If so, the module
- will be called max16065.
-
-config SENSORS_MAX1619
- tristate "Maxim MAX1619 sensor chip"
- depends on I2C
- help
- If you say yes here you get support for MAX1619 sensor chip.
-
- This driver can also be built as a module. If so, the module
- will be called max1619.
-
-config SENSORS_MAX1668
- tristate "Maxim MAX1668 and compatibles"
- depends on I2C
- help
- If you say yes here you get support for MAX1668, MAX1989 and
- MAX1805 chips.
-
- This driver can also be built as a module. If so, the module
- will be called max1668.
-
-config SENSORS_MAX197
- tristate "Maxim MAX197 and compatibles"
- help
- Support for the Maxim MAX197 A/D converter.
- Support will include, but not be limited to, MAX197, and MAX199.
-
- This driver can also be built as a module. If so, the module
- will be called max197.
-
-config SENSORS_MAX6639
- tristate "Maxim MAX6639 sensor chip"
- depends on I2C
- help
- If you say yes here you get support for the MAX6639
- sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called max6639.
-
-config SENSORS_MAX6642
- tristate "Maxim MAX6642 sensor chip"
- depends on I2C
- help
- If you say yes here you get support for MAX6642 sensor chip.
- MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
- with Overtemperature Alarm from Maxim.
-
- This driver can also be built as a module. If so, the module
- will be called max6642.
-
-config SENSORS_MAX6650
- tristate "Maxim MAX6650 sensor chip"
- depends on I2C
- help
- If you say yes here you get support for the MAX6650 / MAX6651
- sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called max6650.
-
-config SENSORS_MAX6697
- tristate "Maxim MAX6697 and compatibles"
- depends on I2C
- help
- If you say yes here you get support for MAX6581, MAX6602, MAX6622,
- MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699
- temperature sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called max6697.
-
-config SENSORS_MCP3021
- tristate "Microchip MCP3021 and compatibles"
- depends on I2C
+config SENSORS_PC87360
+ tristate "National Semiconductor PC87360 family"
+ depends on !PPC
+ select HWMON_VID
help
- If you say yes here you get support for MCP3021 and MCP3221.
- The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221
- with 12-bit resolution.
+ If you say yes here you get access to the hardware monitoring
+ functions of the National Semiconductor PC8736x Super-I/O chips.
+ The PC87360, PC87363 and PC87364 only have fan monitoring and
+ control. The PC87365 and PC87366 additionally have voltage and
+ temperature monitoring.
This driver can also be built as a module. If so, the module
- will be called mcp3021.
+ will be called pc87360.
-config SENSORS_NCT6775
- tristate "Nuvoton NCT6775F and compatibles"
+config SENSORS_PC87427
+ tristate "National Semiconductor PC87427"
depends on !PPC
- select HWMON_VID
help
- If you say yes here you get support for the hardware monitoring
- functionality of the Nuvoton NCT6775F, NCT6776F, NCT6779D
- and compatible Super-I/O chips. This driver replaces the
- w83627ehf driver for NCT6775F and NCT6776F.
+ If you say yes here you get access to the hardware monitoring
+ functions of the National Semiconductor PC87427 Super-I/O chip.
+ The chip has two distinct logical devices, one for fan speed
+ monitoring and control, and one for voltage and temperature
+ monitoring. Fan speed monitoring and control are supported, as
+ well as temperature monitoring. Voltages aren't supported yet.
This driver can also be built as a module. If so, the module
- will be called nct6775.
+ will be called pc87427.
config SENSORS_NTC_THERMISTOR
tristate "NTC thermistor support"
@@ -983,33 +1073,18 @@ config SENSORS_NTC_THERMISTOR
This driver can also be built as a module. If so, the module
will be called ntc-thermistor.
-config SENSORS_PC87360
- tristate "National Semiconductor PC87360 family"
+config SENSORS_NCT6775
+ tristate "Nuvoton NCT6775F and compatibles"
depends on !PPC
select HWMON_VID
help
- If you say yes here you get access to the hardware monitoring
- functions of the National Semiconductor PC8736x Super-I/O chips.
- The PC87360, PC87363 and PC87364 only have fan monitoring and
- control. The PC87365 and PC87366 additionally have voltage and
- temperature monitoring.
-
- This driver can also be built as a module. If so, the module
- will be called pc87360.
-
-config SENSORS_PC87427
- tristate "National Semiconductor PC87427"
- depends on !PPC
- help
- If you say yes here you get access to the hardware monitoring
- functions of the National Semiconductor PC87427 Super-I/O chip.
- The chip has two distinct logical devices, one for fan speed
- monitoring and control, and one for voltage and temperature
- monitoring. Fan speed monitoring and control are supported, as
- well as temperature monitoring. Voltages aren't supported yet.
+ If you say yes here you get support for the hardware monitoring
+ functionality of the Nuvoton NCT6775F, NCT6776F, NCT6779D
+ and compatible Super-I/O chips. This driver replaces the
+ w83627ehf driver for NCT6775F and NCT6776F.
This driver can also be built as a module. If so, the module
- will be called pc87427.
+ will be called nct6775.
config SENSORS_PCF8591
tristate "Philips PCF8591 ADC/DAC"
@@ -1074,21 +1149,6 @@ config SENSORS_SIS5595
This driver can also be built as a module. If so, the module
will be called sis5595.
-config SENSORS_SMM665
- tristate "Summit Microelectronics SMM665"
- depends on I2C
- default n
- help
- If you say yes here you get support for the hardware monitoring
- features of the Summit Microelectronics SMM665/SMM665B Six-Channel
- Active DC Output Controller / Monitor.
-
- Other supported chips are SMM465, SMM665C, SMM764, and SMM766.
- Support for those chips is untested.
-
- This driver can also be built as a module. If so, the module will
- be called smm665.
-
config SENSORS_DME1737
tristate "SMSC DME1737, SCH311x and compatibles"
depends on I2C && !PPC
@@ -1210,6 +1270,31 @@ config SENSORS_SCH5636
This driver can also be built as a module. If so, the module
will be called sch5636.
+config SENSORS_SMM665
+ tristate "Summit Microelectronics SMM665"
+ depends on I2C
+ default n
+ help
+ If you say yes here you get support for the hardware monitoring
+ features of the Summit Microelectronics SMM665/SMM665B Six-Channel
+ Active DC Output Controller / Monitor.
+
+ Other supported chips are SMM465, SMM665C, SMM764, and SMM766.
+ Support for those chips is untested.
+
+ This driver can also be built as a module. If so, the module will
+ be called smm665.
+
+config SENSORS_ADC128D818
+ tristate "Texas Instruments ADC128D818"
+ depends on I2C
+ help
+ If you say yes here you get support for the Texas Instruments
+ ADC128D818 System Monitor with Temperature Sensor chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called adc128d818.
+
config SENSORS_ADS1015
tristate "Texas Instruments ADS1015"
depends on I2C
@@ -1525,37 +1610,6 @@ config SENSORS_ULTRA45
This driver provides support for the Ultra45 workstation environmental
sensors.
-config SENSORS_APPLESMC
- tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
- depends on INPUT && X86
- select NEW_LEDS
- select LEDS_CLASS
- select INPUT_POLLDEV
- default n
- help
- This driver provides support for the Apple System Management
- Controller, which provides an accelerometer (Apple Sudden Motion
- Sensor), light sensors, temperature sensors, keyboard backlight
- control and fan control.
-
- Only Intel-based Apple's computers are supported (MacBook Pro,
- MacBook, MacMini).
-
- Data from the different sensors, keyboard backlight control and fan
- control are accessible via sysfs.
-
- This driver also provides an absolute input class device, allowing
- the laptop to act as a pinball machine-esque joystick.
-
- Say Y here if you have an applicable laptop and want to experience
- the awesome power of applesmc.
-
-config SENSORS_MC13783_ADC
- tristate "Freescale MC13783/MC13892 ADC"
- depends on MFD_MC13XXX
- help
- Support for the A/D converter on MC13783 and MC13892 PMIC.
-
if ACPI
comment "ACPI drivers"
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index ec7cde06eb52..199c401bf8d9 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
obj-$(CONFIG_SENSORS_AD7314) += ad7314.o
obj-$(CONFIG_SENSORS_AD7414) += ad7414.o
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
+obj-$(CONFIG_SENSORS_ADC128D818) += adc128d818.o
obj-$(CONFIG_SENSORS_ADCXX) += adcxx.o
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
@@ -70,6 +71,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
+obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o
obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o
obj-$(CONFIG_SENSORS_INA209) += ina209.o
obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o
@@ -95,9 +97,12 @@ obj-$(CONFIG_SENSORS_LM93) += lm93.o
obj-$(CONFIG_SENSORS_LM95234) += lm95234.o
obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
obj-$(CONFIG_SENSORS_LM95245) += lm95245.o
+obj-$(CONFIG_SENSORS_LTC2945) += ltc2945.o
obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
+obj-$(CONFIG_SENSORS_LTC4222) += ltc4222.o
obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o
+obj-$(CONFIG_SENSORS_LTC4260) += ltc4260.o
obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o
obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
obj-$(CONFIG_SENSORS_MAX16065) += max16065.o
diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c
new file mode 100644
index 000000000000..5ffd81f19d01
--- /dev/null
+++ b/drivers/hwmon/adc128d818.c
@@ -0,0 +1,491 @@
+/*
+ * Driver for TI ADC128D818 System Monitor with Temperature Sensor
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * Derived from lm80.c
+ * Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
+ * and Philip Edelbrock <phil@netroedge.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/module.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
+
+/* Addresses to scan
+ * The chip also supports addresses 0x35..0x37. Don't scan those addresses
+ * since they are also used by some EEPROMs, which may result in false
+ * positives.
+ */
+static const unsigned short normal_i2c[] = {
+ 0x1d, 0x1e, 0x1f, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+
+/* registers */
+#define ADC128_REG_IN_MAX(nr) (0x2a + (nr) * 2)
+#define ADC128_REG_IN_MIN(nr) (0x2b + (nr) * 2)
+#define ADC128_REG_IN(nr) (0x20 + (nr))
+
+#define ADC128_REG_TEMP 0x27
+#define ADC128_REG_TEMP_MAX 0x38
+#define ADC128_REG_TEMP_HYST 0x39
+
+#define ADC128_REG_CONFIG 0x00
+#define ADC128_REG_ALARM 0x01
+#define ADC128_REG_MASK 0x03
+#define ADC128_REG_CONV_RATE 0x07
+#define ADC128_REG_ONESHOT 0x09
+#define ADC128_REG_SHUTDOWN 0x0a
+#define ADC128_REG_CONFIG_ADV 0x0b
+#define ADC128_REG_BUSY_STATUS 0x0c
+
+#define ADC128_REG_MAN_ID 0x3e
+#define ADC128_REG_DEV_ID 0x3f
+
+struct adc128_data {
+ struct i2c_client *client;
+ struct regulator *regulator;
+ int vref; /* Reference voltage in mV */
+ struct mutex update_lock;
+ bool valid; /* true if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ u16 in[3][7]; /* Register value, normalized to 12 bit
+ * 0: input voltage
+ * 1: min limit
+ * 2: max limit
+ */
+ s16 temp[3]; /* Register value, normalized to 9 bit
+ * 0: sensor 1: limit 2: hyst
+ */
+ u8 alarms; /* alarm register value */
+};
+
+static struct adc128_data *adc128_update_device(struct device *dev)
+{
+ struct adc128_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ struct adc128_data *ret = data;
+ int i, rv;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ for (i = 0; i < 7; i++) {
+ rv = i2c_smbus_read_word_swapped(client,
+ ADC128_REG_IN(i));
+ if (rv < 0)
+ goto abort;
+ data->in[0][i] = rv >> 4;
+
+ rv = i2c_smbus_read_byte_data(client,
+ ADC128_REG_IN_MIN(i));
+ if (rv < 0)
+ goto abort;
+ data->in[1][i] = rv << 4;
+
+ rv = i2c_smbus_read_byte_data(client,
+ ADC128_REG_IN_MAX(i));
+ if (rv < 0)
+ goto abort;
+ data->in[2][i] = rv << 4;
+ }
+
+ rv = i2c_smbus_read_word_swapped(client, ADC128_REG_TEMP);
+ if (rv < 0)
+ goto abort;
+ data->temp[0] = rv >> 7;
+
+ rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_MAX);
+ if (rv < 0)
+ goto abort;
+ data->temp[1] = rv << 1;
+
+ rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_HYST);
+ if (rv < 0)
+ goto abort;
+ data->temp[2] = rv << 1;
+
+ rv = i2c_smbus_read_byte_data(client, ADC128_REG_ALARM);
+ if (rv < 0)
+ goto abort;
+ data->alarms |= rv;
+
+ data->last_updated = jiffies;
+ data->valid = true;
+ }
+ goto done;
+
+abort:
+ ret = ERR_PTR(rv);
+ data->valid = false;
+done:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static ssize_t adc128_show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct adc128_data *data = adc128_update_device(dev);
+ int index = to_sensor_dev_attr_2(attr)->index;
+ int nr = to_sensor_dev_attr_2(attr)->nr;
+ int val;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ val = DIV_ROUND_CLOSEST(data->in[index][nr] * data->vref, 4095);
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t adc128_set_in(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adc128_data *data = dev_get_drvdata(dev);
+ int index = to_sensor_dev_attr_2(attr)->index;
+ int nr = to_sensor_dev_attr_2(attr)->nr;
+ u8 reg, regval;
+ long val;
+ int err;
+
+ err = kstrtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&data->update_lock);
+ /* 10 mV LSB on limit registers */
+ regval = clamp_val(DIV_ROUND_CLOSEST(val, 10), 0, 255);
+ data->in[index][nr] = regval << 4;
+ reg = index == 1 ? ADC128_REG_IN_MIN(nr) : ADC128_REG_IN_MAX(nr);
+ i2c_smbus_write_byte_data(data->client, reg, regval);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t adc128_show_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct adc128_data *data = adc128_update_device(dev);
+ int index = to_sensor_dev_attr(attr)->index;
+ int temp;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ temp = (data->temp[index] << 7) >> 7; /* sign extend */
+ return sprintf(buf, "%d\n", temp * 500);/* 0.5 degrees C resolution */
+}
+
+static ssize_t adc128_set_temp(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adc128_data *data = dev_get_drvdata(dev);
+ int index = to_sensor_dev_attr(attr)->index;
+ long val;
+ int err;
+ s8 regval;
+
+ err = kstrtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&data->update_lock);
+ regval = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+ data->temp[index] = regval << 1;
+ i2c_smbus_write_byte_data(data->client,
+ index == 1 ? ADC128_REG_TEMP_MAX
+ : ADC128_REG_TEMP_HYST,
+ regval);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t adc128_show_alarm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct adc128_data *data = adc128_update_device(dev);
+ int mask = 1 << to_sensor_dev_attr(attr)->index;
+ u8 alarms;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ /*
+ * Clear an alarm after reporting it to user space. If it is still
+ * active, the next update sequence will set the alarm bit again.
+ */
+ alarms = data->alarms;
+ data->alarms &= ~mask;
+
+ return sprintf(buf, "%u\n", !!(alarms & mask));
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 0, 1);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 0, 2);
+
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 1, 0);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 1, 1);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 1, 2);
+
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 2, 0);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 2, 1);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 2, 2);
+
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 3, 0);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 3, 1);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 3, 2);
+
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 4, 0);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 4, 1);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 4, 2);
+
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 5, 0);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 5, 1);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 5, 2);
+
+static SENSOR_DEVICE_ATTR_2(in6_input, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 6, 0);
+static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 6, 1);
+static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO,
+ adc128_show_in, adc128_set_in, 6, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adc128_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+ adc128_show_temp, adc128_set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+ adc128_show_temp, adc128_set_temp, 2);
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, adc128_show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, adc128_show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, adc128_show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, adc128_show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, adc128_show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, adc128_show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, adc128_show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adc128_show_alarm, NULL, 7);
+
+static struct attribute *adc128_attrs[] = {
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(adc128);
+
+static int adc128_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+ int man_id, dev_id;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
+
+ man_id = i2c_smbus_read_byte_data(client, ADC128_REG_MAN_ID);
+ dev_id = i2c_smbus_read_byte_data(client, ADC128_REG_DEV_ID);
+ if (man_id != 0x01 || dev_id != 0x09)
+ return -ENODEV;
+
+ /* Check unused bits for confirmation */
+ if (i2c_smbus_read_byte_data(client, ADC128_REG_CONFIG) & 0xf4)
+ return -ENODEV;
+ if (i2c_smbus_read_byte_data(client, ADC128_REG_CONV_RATE) & 0xfe)
+ return -ENODEV;
+ if (i2c_smbus_read_byte_data(client, ADC128_REG_ONESHOT) & 0xfe)
+ return -ENODEV;
+ if (i2c_smbus_read_byte_data(client, ADC128_REG_SHUTDOWN) & 0xfe)
+ return -ENODEV;
+ if (i2c_smbus_read_byte_data(client, ADC128_REG_CONFIG_ADV) & 0xf8)
+ return -ENODEV;
+ if (i2c_smbus_read_byte_data(client, ADC128_REG_BUSY_STATUS) & 0xfc)
+ return -ENODEV;
+
+ strlcpy(info->type, "adc128d818", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int adc128_init_client(struct adc128_data *data)
+{
+ struct i2c_client *client = data->client;
+ int err;
+
+ /*
+ * Reset chip to defaults.
+ * This makes most other initializations unnecessary.
+ */
+ err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG, 0x80);
+ if (err)
+ return err;
+
+ /* Start monitoring */
+ err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG, 0x01);
+ if (err)
+ return err;
+
+ /* If external vref is selected, configure the chip to use it */
+ if (data->regulator) {
+ err = i2c_smbus_write_byte_data(client,
+ ADC128_REG_CONFIG_ADV, 0x01);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int adc128_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct regulator *regulator;
+ struct device *hwmon_dev;
+ struct adc128_data *data;
+ int err, vref;
+
+ data = devm_kzalloc(dev, sizeof(struct adc128_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /* vref is optional. If specified, is used as chip reference voltage */
+ regulator = devm_regulator_get_optional(dev, "vref");
+ if (!IS_ERR(regulator)) {
+ data->regulator = regulator;
+ err = regulator_enable(regulator);
+ if (err < 0)
+ return err;
+ vref = regulator_get_voltage(regulator);
+ if (vref < 0) {
+ err = vref;
+ goto error;
+ }
+ data->vref = DIV_ROUND_CLOSEST(vref, 1000);
+ } else {
+ data->vref = 2560; /* 2.56V, in mV */
+ }
+
+ data->client = client;
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* Initialize the chip */
+ err = adc128_init_client(data);
+ if (err < 0)
+ goto error;
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data, adc128_groups);
+ if (IS_ERR(hwmon_dev)) {
+ err = PTR_ERR(hwmon_dev);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ if (data->regulator)
+ regulator_disable(data->regulator);
+ return err;
+}
+
+static int adc128_remove(struct i2c_client *client)
+{
+ struct adc128_data *data = i2c_get_clientdata(client);
+
+ if (data->regulator)
+ regulator_disable(data->regulator);
+
+ return 0;
+}
+
+static const struct i2c_device_id adc128_id[] = {
+ { "adc128d818", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adc128_id);
+
+static struct i2c_driver adc128_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "adc128d818",
+ },
+ .probe = adc128_probe,
+ .remove = adc128_remove,
+ .id_table = adc128_id,
+ .detect = adc128_detect,
+ .address_list = normal_i2c,
+};
+
+module_i2c_driver(adc128_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("Driver for ADC128D818");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index bbb0b0d463f7..f31bc4c48644 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -94,6 +94,8 @@ struct temp_data {
bool valid;
struct sensor_device_attribute sd_attrs[TOTAL_ATTRS];
char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH];
+ struct attribute *attrs[TOTAL_ATTRS + 1];
+ struct attribute_group attr_group;
struct mutex update_lock;
};
@@ -114,12 +116,6 @@ struct pdev_entry {
static LIST_HEAD(pdev_list);
static DEFINE_MUTEX(pdev_list_mutex);
-static ssize_t show_name(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- return sprintf(buf, "%s\n", DRVNAME);
-}
-
static ssize_t show_label(struct device *dev,
struct device_attribute *devattr, char *buf)
{
@@ -393,20 +389,10 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
return adjust_tjmax(c, id, dev);
}
-static int create_name_attr(struct platform_data *pdata,
- struct device *dev)
-{
- sysfs_attr_init(&pdata->name_attr.attr);
- pdata->name_attr.attr.name = "name";
- pdata->name_attr.attr.mode = S_IRUGO;
- pdata->name_attr.show = show_name;
- return device_create_file(dev, &pdata->name_attr);
-}
-
static int create_core_attrs(struct temp_data *tdata, struct device *dev,
int attr_no)
{
- int err, i;
+ int i;
static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
struct device_attribute *devattr, char *buf) = {
show_label, show_crit_alarm, show_temp, show_tjmax,
@@ -424,16 +410,10 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
tdata->sd_attrs[i].index = attr_no;
- err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
- if (err)
- goto exit_free;
+ tdata->attrs[i] = &tdata->sd_attrs[i].dev_attr.attr;
}
- return 0;
-
-exit_free:
- while (--i >= 0)
- device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
- return err;
+ tdata->attr_group.attrs = tdata->attrs;
+ return sysfs_create_group(&dev->kobj, &tdata->attr_group);
}
@@ -548,7 +528,7 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
pdata->core_data[attr_no] = tdata;
/* Create sysfs interfaces */
- err = create_core_attrs(tdata, &pdev->dev, attr_no);
+ err = create_core_attrs(tdata, pdata->hwmon_dev, attr_no);
if (err)
goto exit_free;
@@ -573,14 +553,12 @@ static void coretemp_add_core(unsigned int cpu, int pkg_flag)
}
static void coretemp_remove_core(struct platform_data *pdata,
- struct device *dev, int indx)
+ int indx)
{
- int i;
struct temp_data *tdata = pdata->core_data[indx];
/* Remove the sysfs attributes */
- for (i = 0; i < tdata->attr_size; i++)
- device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
+ sysfs_remove_group(&pdata->hwmon_dev->kobj, &tdata->attr_group);
kfree(pdata->core_data[indx]);
pdata->core_data[indx] = NULL;
@@ -588,34 +566,20 @@ static void coretemp_remove_core(struct platform_data *pdata,
static int coretemp_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct platform_data *pdata;
- int err;
/* Initialize the per-package data structures */
- pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL);
+ pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- err = create_name_attr(pdata, &pdev->dev);
- if (err)
- goto exit_free;
-
pdata->phys_proc_id = pdev->id;
platform_set_drvdata(pdev, pdata);
- pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(pdata->hwmon_dev)) {
- err = PTR_ERR(pdata->hwmon_dev);
- dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
- goto exit_name;
- }
- return 0;
-
-exit_name:
- device_remove_file(&pdev->dev, &pdata->name_attr);
-exit_free:
- kfree(pdata);
- return err;
+ pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME,
+ pdata, NULL);
+ return PTR_ERR_OR_ZERO(pdata->hwmon_dev);
}
static int coretemp_remove(struct platform_device *pdev)
@@ -625,11 +589,8 @@ static int coretemp_remove(struct platform_device *pdev)
for (i = MAX_CORE_DATA - 1; i >= 0; --i)
if (pdata->core_data[i])
- coretemp_remove_core(pdata, &pdev->dev, i);
+ coretemp_remove_core(pdata, i);
- device_remove_file(&pdev->dev, &pdata->name_attr);
- hwmon_device_unregister(pdata->hwmon_dev);
- kfree(pdata);
return 0;
}
@@ -777,7 +738,7 @@ static void put_core_offline(unsigned int cpu)
return;
if (pdata->core_data[indx] && pdata->core_data[indx]->cpu == cpu)
- coretemp_remove_core(pdata, &pdev->dev, indx);
+ coretemp_remove_core(pdata, indx);
/*
* If a HT sibling of a core is taken offline, but another HT sibling
diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c
index 2c137b26acb4..fd892dd48e4c 100644
--- a/drivers/hwmon/emc2103.c
+++ b/drivers/hwmon/emc2103.c
@@ -349,7 +349,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
dev_dbg(&client->dev, "reg 0x%02x, err %d\n",
REG_FAN_CONF1, status);
mutex_unlock(&data->update_lock);
- return -EIO;
+ return status;
}
status &= 0x9F;
status |= (new_range_bits << 5);
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index e176a43af63d..a26c385a435b 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -22,6 +22,7 @@
#include <linux/gfp.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
+#include <linux/string.h>
#define HWMON_ID_PREFIX "hwmon"
#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
@@ -99,6 +100,10 @@ hwmon_device_register_with_groups(struct device *dev, const char *name,
struct hwmon_device *hwdev;
int err, id;
+ /* Do not accept invalid characters in hwmon name attribute */
+ if (name && (!strlen(name) || strpbrk(name, "-* \t\n")))
+ return ERR_PTR(-EINVAL);
+
id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL);
if (id < 0)
return ERR_PTR(id);
diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c
new file mode 100644
index 000000000000..b7b1297a9b02
--- /dev/null
+++ b/drivers/hwmon/ibmpowernv.c
@@ -0,0 +1,529 @@
+/*
+ * hwmon driver for temperature/power/fan on IBM PowerNV platform
+ * Copyright (C) 2013 IBM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <asm/opal.h>
+#include <linux/err.h>
+
+MODULE_DESCRIPTION("IBM PowerNV Platform power/temp/fan sensor hwmon module");
+MODULE_LICENSE("GPL");
+
+#define MAX_ATTR_LENGTH 32
+
+/* Device tree sensor name prefixes. The device tree has the names in the
+ * format "cooling-fan#2-faulted" where the "cooling-fan" is the sensor type,
+ * 2 is the sensor count, and "faulted" is the sensor data attribute type.
+ */
+#define DT_FAULT_ATTR_SUFFIX "faulted"
+#define DT_DATA_ATTR_SUFFIX "data"
+#define DT_THRESHOLD_ATTR_SUFFIX "thrs"
+
+enum sensors {
+ FAN,
+ TEMPERATURE,
+ POWERSUPPLY,
+ POWER,
+ MAX_SENSOR_TYPE,
+};
+
+enum attributes {
+ INPUT,
+ MINIMUM,
+ MAXIMUM,
+ FAULT,
+ MAX_ATTR_TYPES
+};
+
+static struct sensor_name {
+ char *name;
+ char *compaible;
+} sensor_names[] = {
+ {"fan-sensor", "ibm,opal-sensor-cooling-fan"},
+ {"amb-temp-sensor", "ibm,opal-sensor-amb-temp"},
+ {"power-sensor", "ibm,opal-sensor-power-supply"},
+ {"power", "ibm,opal-sensor-power"}
+};
+
+static const char * const attribute_type_table[] = {
+ "input",
+ "min",
+ "max",
+ "fault",
+ NULL
+};
+
+struct pdev_entry {
+ struct list_head list;
+ struct platform_device *pdev;
+ enum sensors type;
+};
+
+static LIST_HEAD(pdev_list);
+
+/* The sensors are categorised on type.
+ *
+ * The sensors of same type are categorised under a common platform device.
+ * So, The pdev is shared by all sensors of same type.
+ * Ex : temp1_input, temp1_max, temp2_input,temp2_max all share same platform
+ * device.
+ *
+ * "sensor_data" is the Platform device specific data.
+ * There is one hwmon_device instance for all the sensors of same type.
+ * This also holds the list of all sensors with same type but different
+ * attribute and index.
+ */
+struct sensor_specific_data {
+ u32 sensor_id; /* The hex value as in the device tree */
+ u32 sensor_index; /* The sensor instance index */
+ struct sensor_device_attribute sd_attr;
+ enum attributes attr_type;
+ char attr_name[64];
+};
+
+struct sensor_data {
+ struct device *hwmon_dev;
+ struct list_head sensor_list;
+ struct device_attribute name_attr;
+};
+
+struct sensor_entry {
+ struct list_head list;
+ struct sensor_specific_data *sensor_data;
+};
+
+static struct platform_device *powernv_sensor_get_pdev(enum sensors type)
+{
+ struct pdev_entry *p;
+ list_for_each_entry(p, &pdev_list, list)
+ if (p->type == type)
+ return p->pdev;
+
+ return NULL;
+}
+
+static struct sensor_specific_data *powernv_sensor_get_sensor_data(
+ struct sensor_data *pdata,
+ int index, enum attributes attr_type)
+{
+ struct sensor_entry *p;
+ list_for_each_entry(p, &pdata->sensor_list, list)
+ if ((p->sensor_data->sensor_index == index) &&
+ (attr_type == p->sensor_data->attr_type))
+ return p->sensor_data;
+
+ return NULL;
+}
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ return sprintf(buf, "%s\n", pdev->name);
+}
+
+/* Note: Data from the sensors for each sensor type needs to be converted to
+ * the dimension appropriate.
+ */
+static ssize_t show_sensor(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(devattr);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sensor_data *pdata = platform_get_drvdata(pdev);
+ struct sensor_specific_data *tdata = NULL;
+ enum sensors sensor_type = pdev->id;
+ u32 x = -1;
+ int ret;
+
+ if (sd_attr && sd_attr->dev_attr.attr.name) {
+ char *pos = strchr(sd_attr->dev_attr.attr.name, '_');
+ int i;
+
+ for (i = 0; i < MAX_ATTR_TYPES; i++) {
+ if (strcmp(pos+1, attribute_type_table[i]) == 0) {
+ tdata = powernv_sensor_get_sensor_data(pdata,
+ sd_attr->index, i);
+ break;
+ }
+ }
+ }
+
+ if (tdata) {
+ ret = opal_get_sensor_data(tdata->sensor_id, &x);
+ if (ret)
+ x = -1;
+ }
+
+ if (sensor_type == TEMPERATURE && x > 0) {
+ /* Temperature comes in Degrees and convert it to
+ * milli-degrees.
+ */
+ x = x*1000;
+ } else if (sensor_type == POWER && x > 0) {
+ /* Power value comes in watts, convert to micro-watts */
+ x = x * 1000000;
+ }
+
+ return sprintf(buf, "%d\n", x);
+}
+
+static u32 get_sensor_index_from_name(const char *name)
+{
+ char *hash_position = strchr(name, '#');
+ u32 index = 0, copy_length;
+ char newbuf[8];
+
+ if (hash_position) {
+ copy_length = strchr(hash_position, '-') - hash_position - 1;
+ if (copy_length < sizeof(newbuf)) {
+ strncpy(newbuf, hash_position + 1, copy_length);
+ sscanf(newbuf, "%d", &index);
+ }
+ }
+
+ return index;
+}
+
+static inline void get_sensor_suffix_from_name(const char *name, char *suffix)
+{
+ char *dash_position = strrchr(name, '-');
+ if (dash_position)
+ strncpy(suffix, dash_position+1, MAX_ATTR_LENGTH);
+ else
+ strcpy(suffix,"");
+}
+
+static int get_sensor_attr_properties(const char *sensor_name,
+ enum sensors sensor_type, enum attributes *attr_type,
+ u32 *sensor_index)
+{
+ char suffix[MAX_ATTR_LENGTH];
+
+ *attr_type = MAX_ATTR_TYPES;
+ *sensor_index = get_sensor_index_from_name(sensor_name);
+ if (*sensor_index == 0)
+ return -EINVAL;
+
+ get_sensor_suffix_from_name(sensor_name, suffix);
+ if (strcmp(suffix, "") == 0)
+ return -EINVAL;
+
+ if (strcmp(suffix, DT_FAULT_ATTR_SUFFIX) == 0)
+ *attr_type = FAULT;
+ else if (strcmp(suffix, DT_DATA_ATTR_SUFFIX) == 0)
+ *attr_type = INPUT;
+ else if ((sensor_type == TEMPERATURE) &&
+ (strcmp(suffix, DT_THRESHOLD_ATTR_SUFFIX) == 0))
+ *attr_type = MAXIMUM;
+ else if ((sensor_type == FAN) &&
+ (strcmp(suffix, DT_THRESHOLD_ATTR_SUFFIX) == 0))
+ *attr_type = MINIMUM;
+ else
+ return -ENOENT;
+
+ if (((sensor_type == FAN) && ((*attr_type == INPUT) ||
+ (*attr_type == MINIMUM)))
+ || ((sensor_type == TEMPERATURE) && ((*attr_type == INPUT) ||
+ (*attr_type == MAXIMUM)))
+ || ((sensor_type == POWER) && ((*attr_type == INPUT))))
+ return 0;
+
+ return -ENOENT;
+}
+
+static int create_sensor_attr(struct sensor_specific_data *tdata,
+ struct device *dev, enum sensors sensor_type,
+ enum attributes attr_type)
+{
+ int err = 0;
+ char temp_file_prefix[50];
+ static const char *const file_name_format = "%s%d_%s";
+
+ tdata->attr_type = attr_type;
+
+ if (sensor_type == FAN)
+ strcpy(temp_file_prefix, "fan");
+ else if (sensor_type == TEMPERATURE)
+ strcpy(temp_file_prefix, "temp");
+ else if (sensor_type == POWERSUPPLY)
+ strcpy(temp_file_prefix, "powersupply");
+ else if (sensor_type == POWER)
+ strcpy(temp_file_prefix, "power");
+
+ snprintf(tdata->attr_name, sizeof(tdata->attr_name), file_name_format,
+ temp_file_prefix, tdata->sensor_index,
+ attribute_type_table[tdata->attr_type]);
+
+ sysfs_attr_init(&tdata->sd_attr.dev_attr.attr);
+ tdata->sd_attr.dev_attr.attr.name = tdata->attr_name;
+ tdata->sd_attr.dev_attr.attr.mode = S_IRUGO;
+ tdata->sd_attr.dev_attr.show = show_sensor;
+
+ tdata->sd_attr.index = tdata->sensor_index;
+ err = device_create_file(dev, &tdata->sd_attr.dev_attr);
+
+ return err;
+}
+
+static int create_name_attr(struct sensor_data *pdata,
+ struct device *dev)
+{
+ sysfs_attr_init(&pdata->name_attr.attr);
+ pdata->name_attr.attr.name = "name";
+ pdata->name_attr.attr.mode = S_IRUGO;
+ pdata->name_attr.show = show_name;
+ return device_create_file(dev, &pdata->name_attr);
+}
+
+static int create_platform_device(enum sensors sensor_type,
+ struct platform_device **pdev)
+{
+ struct pdev_entry *pdev_entry = NULL;
+ int err;
+
+ *pdev = platform_device_alloc(sensor_names[sensor_type].name,
+ sensor_type);
+ if (!*pdev) {
+ pr_err("Device allocation failed\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
+ if (!pdev_entry) {
+ pr_err("Device allocation failed\n");
+ err = -ENOMEM;
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(*pdev);
+ if (err) {
+ pr_err("Device addition failed (%d)\n", err);
+ goto exit_device_free;
+ }
+
+ pdev_entry->pdev = *pdev;
+ pdev_entry->type = (*pdev)->id;
+
+ list_add_tail(&pdev_entry->list, &pdev_list);
+
+ return 0;
+exit_device_free:
+ kfree(pdev_entry);
+exit_device_put:
+ platform_device_put(*pdev);
+exit:
+ return err;
+}
+
+static int create_sensor_data(struct platform_device *pdev)
+{
+ struct sensor_data *pdata = NULL;
+ int err = 0;
+
+ pdata = kzalloc(sizeof(struct sensor_data), GFP_KERNEL);
+ if (!pdata) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ err = create_name_attr(pdata, &pdev->dev);
+ if (err)
+ goto exit_free;
+
+ pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(pdata->hwmon_dev)) {
+ err = PTR_ERR(pdata->hwmon_dev);
+ dev_err(&pdev->dev, "Class registration failed (%d)\n",
+ err);
+ goto exit_name;
+ }
+
+ INIT_LIST_HEAD(&pdata->sensor_list);
+ platform_set_drvdata(pdev, pdata);
+
+ return 0;
+
+exit_name:
+ device_remove_file(&pdev->dev, &pdata->name_attr);
+exit_free:
+ kfree(pdata);
+exit:
+ return err;
+}
+
+static void delete_sensor_attr(struct sensor_data *pdata)
+{
+ struct sensor_entry *s, *l;
+
+ list_for_each_entry_safe(s, l, &pdata->sensor_list, list) {
+ struct sensor_specific_data *tdata = s->sensor_data;
+ kfree(tdata);
+ list_del(&s->list);
+ kfree(s);
+ }
+}
+
+static int powernv_sensor_init(u32 sensor_id, const struct device_node *np,
+ enum sensors sensor_type, enum attributes attr_type,
+ u32 sensor_index)
+{
+ struct platform_device *pdev = powernv_sensor_get_pdev(sensor_type);
+ struct sensor_specific_data *tdata;
+ struct sensor_entry *sensor_entry;
+ struct sensor_data *pdata;
+ int err = 0;
+
+ if (!pdev) {
+ err = create_platform_device(sensor_type, &pdev);
+ if (err)
+ goto exit;
+
+ err = create_sensor_data(pdev);
+ if (err)
+ goto exit;
+ }
+
+ pdata = platform_get_drvdata(pdev);
+ if (!pdata) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ tdata = kzalloc(sizeof(struct sensor_specific_data), GFP_KERNEL);
+ if (!tdata) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ tdata->sensor_id = sensor_id;
+ tdata->sensor_index = sensor_index;
+
+ err = create_sensor_attr(tdata, &pdev->dev, sensor_type, attr_type);
+ if (err)
+ goto exit_free;
+
+ sensor_entry = kzalloc(sizeof(struct sensor_entry), GFP_KERNEL);
+ if (!sensor_entry) {
+ err = -ENOMEM;
+ goto exit_attr;
+ }
+
+ sensor_entry->sensor_data = tdata;
+
+ list_add_tail(&sensor_entry->list, &pdata->sensor_list);
+
+ return 0;
+exit_attr:
+ device_remove_file(&pdev->dev, &tdata->sd_attr.dev_attr);
+exit_free:
+ kfree(tdata);
+exit:
+ return err;
+}
+
+static void delete_unregister_sensors(void)
+{
+ struct pdev_entry *p, *n;
+
+ list_for_each_entry_safe(p, n, &pdev_list, list) {
+ struct sensor_data *pdata = platform_get_drvdata(p->pdev);
+ if (pdata) {
+ delete_sensor_attr(pdata);
+
+ hwmon_device_unregister(pdata->hwmon_dev);
+ kfree(pdata);
+ }
+ platform_device_unregister(p->pdev);
+ list_del(&p->list);
+ kfree(p);
+ }
+}
+
+static int __init powernv_hwmon_init(void)
+{
+ struct device_node *opal, *np = NULL;
+ enum attributes attr_type;
+ enum sensors type;
+ const u32 *sensor_id;
+ u32 sensor_index;
+ int err;
+
+ opal = of_find_node_by_path("/ibm,opal/sensors");
+ if (!opal) {
+ pr_err("%s: Opal 'sensors' node not found\n", __func__);
+ return -ENXIO;
+ }
+
+ for_each_child_of_node(opal, np) {
+ if (np->name == NULL)
+ continue;
+
+ for (type = 0; type < MAX_SENSOR_TYPE; type++)
+ if (of_device_is_compatible(np,
+ sensor_names[type].compaible))
+ break;
+
+ if (type == MAX_SENSOR_TYPE)
+ continue;
+
+ if (get_sensor_attr_properties(np->name, type, &attr_type,
+ &sensor_index))
+ continue;
+
+ sensor_id = of_get_property(np, "sensor-id", NULL);
+ if (!sensor_id) {
+ pr_info("%s: %s doesn't have sensor-id\n", __func__,
+ np->name);
+ continue;
+ }
+
+ err = powernv_sensor_init(*sensor_id, np, type, attr_type,
+ sensor_index);
+ if (err) {
+ of_node_put(opal);
+ goto exit;
+ }
+ }
+ of_node_put(opal);
+
+ return 0;
+exit:
+ delete_unregister_sensors();
+ return err;
+
+}
+
+static void powernv_hwmon_exit(void)
+{
+ delete_unregister_sensors();
+}
+
+module_init(powernv_hwmon_init);
+module_exit(powernv_hwmon_exit);
diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
index 708081b68c6f..9fbb1b1fdff3 100644
--- a/drivers/hwmon/iio_hwmon.c
+++ b/drivers/hwmon/iio_hwmon.c
@@ -31,6 +31,7 @@ struct iio_hwmon_state {
int num_channels;
struct device *hwmon_dev;
struct attribute_group attr_group;
+ const struct attribute_group *groups[2];
struct attribute **attrs;
};
@@ -56,19 +57,6 @@ static ssize_t iio_hwmon_read_val(struct device *dev,
return sprintf(buf, "%d\n", result);
}
-static ssize_t show_name(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- const char *name = "iio_hwmon";
-
- if (dev->of_node && dev->of_node->name)
- name = dev->of_node->name;
-
- return sprintf(buf, "%s\n", name);
-}
-
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-
static int iio_hwmon_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -78,6 +66,10 @@ static int iio_hwmon_probe(struct platform_device *pdev)
int in_i = 1, temp_i = 1, curr_i = 1;
enum iio_chan_type type;
struct iio_channel *channels;
+ const char *name = "iio_hwmon";
+
+ if (dev->of_node && dev->of_node->name)
+ name = dev->of_node->name;
channels = iio_channel_get_all(dev);
if (IS_ERR(channels))
@@ -96,7 +88,7 @@ static int iio_hwmon_probe(struct platform_device *pdev)
st->num_channels++;
st->attrs = devm_kzalloc(dev,
- sizeof(*st->attrs) * (st->num_channels + 2),
+ sizeof(*st->attrs) * (st->num_channels + 1),
GFP_KERNEL);
if (st->attrs == NULL) {
ret = -ENOMEM;
@@ -144,22 +136,18 @@ static int iio_hwmon_probe(struct platform_device *pdev)
a->index = i;
st->attrs[i] = &a->dev_attr.attr;
}
- st->attrs[st->num_channels] = &dev_attr_name.attr;
- st->attr_group.attrs = st->attrs;
- platform_set_drvdata(pdev, st);
- ret = sysfs_create_group(&dev->kobj, &st->attr_group);
- if (ret < 0)
- goto error_release_channels;
- st->hwmon_dev = hwmon_device_register(dev);
+ st->attr_group.attrs = st->attrs;
+ st->groups[0] = &st->attr_group;
+ st->hwmon_dev = hwmon_device_register_with_groups(dev, name, st,
+ st->groups);
if (IS_ERR(st->hwmon_dev)) {
ret = PTR_ERR(st->hwmon_dev);
- goto error_remove_group;
+ goto error_release_channels;
}
+ platform_set_drvdata(pdev, st);
return 0;
-error_remove_group:
- sysfs_remove_group(&dev->kobj, &st->attr_group);
error_release_channels:
iio_channel_release_all(channels);
return ret;
@@ -170,7 +158,6 @@ static int iio_hwmon_remove(struct platform_device *pdev)
struct iio_hwmon_state *st = platform_get_drvdata(pdev);
hwmon_device_unregister(st->hwmon_dev);
- sysfs_remove_group(&pdev->dev.kobj, &st->attr_group);
iio_channel_release_all(st->channels);
return 0;
diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c
index a183e488db78..7488e36809c8 100644
--- a/drivers/hwmon/jz4740-hwmon.c
+++ b/drivers/hwmon/jz4740-hwmon.c
@@ -28,7 +28,6 @@
#include <linux/hwmon.h>
struct jz4740_hwmon {
- struct resource *mem;
void __iomem *base;
int irq;
@@ -106,6 +105,7 @@ static int jz4740_hwmon_probe(struct platform_device *pdev)
{
int ret;
struct jz4740_hwmon *hwmon;
+ struct resource *mem;
hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
if (!hwmon)
@@ -120,25 +120,10 @@ static int jz4740_hwmon_probe(struct platform_device *pdev)
return hwmon->irq;
}
- hwmon->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!hwmon->mem) {
- dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
- return -ENOENT;
- }
-
- hwmon->mem = devm_request_mem_region(&pdev->dev, hwmon->mem->start,
- resource_size(hwmon->mem), pdev->name);
- if (!hwmon->mem) {
- dev_err(&pdev->dev, "Failed to request mmio memory region\n");
- return -EBUSY;
- }
-
- hwmon->base = devm_ioremap_nocache(&pdev->dev, hwmon->mem->start,
- resource_size(hwmon->mem));
- if (!hwmon->base) {
- dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
- return -EBUSY;
- }
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hwmon->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(hwmon->base))
+ return PTR_ERR(hwmon->base);
init_completion(&hwmon->read_completion);
mutex_init(&hwmon->lock);
diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c
index 4b68fb2a31d7..cdf19adaec79 100644
--- a/drivers/hwmon/lm95241.c
+++ b/drivers/hwmon/lm95241.c
@@ -89,7 +89,7 @@ static const u8 lm95241_reg_address[] = {
/* Client data (each client gets its own) */
struct lm95241_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
struct mutex update_lock;
unsigned long last_updated, interval; /* in jiffies */
char valid; /* zero until following fields are valid */
@@ -113,8 +113,8 @@ static int temp_from_reg_unsigned(u8 val_h, u8 val_l)
static struct lm95241_data *lm95241_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
mutex_lock(&data->update_lock);
@@ -122,7 +122,7 @@ static struct lm95241_data *lm95241_update_device(struct device *dev)
!data->valid) {
int i;
- dev_dbg(&client->dev, "Updating lm95241 data.\n");
+ dev_dbg(dev, "Updating lm95241 data.\n");
for (i = 0; i < ARRAY_SIZE(lm95241_reg_address); i++)
data->temp[i]
= i2c_smbus_read_byte_data(client,
@@ -153,8 +153,7 @@ static ssize_t show_input(struct device *dev, struct device_attribute *attr,
static ssize_t show_type(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE - 1,
data->model & to_sensor_dev_attr(attr)->index ? "1\n" : "2\n");
@@ -163,8 +162,8 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr,
static ssize_t set_type(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
int shift;
u8 mask = to_sensor_dev_attr(attr)->index;
@@ -201,8 +200,7 @@ static ssize_t set_type(struct device *dev, struct device_attribute *attr,
static ssize_t show_min(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE - 1,
data->config & to_sensor_dev_attr(attr)->index ?
@@ -212,8 +210,7 @@ static ssize_t show_min(struct device *dev, struct device_attribute *attr,
static ssize_t set_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
long val;
if (kstrtol(buf, 10, &val) < 0)
@@ -229,7 +226,8 @@ static ssize_t set_min(struct device *dev, struct device_attribute *attr,
data->config &= ~to_sensor_dev_attr(attr)->index;
data->valid = 0;
- i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
+ i2c_smbus_write_byte_data(data->client, LM95241_REG_RW_CONFIG,
+ data->config);
mutex_unlock(&data->update_lock);
@@ -239,8 +237,7 @@ static ssize_t set_min(struct device *dev, struct device_attribute *attr,
static ssize_t show_max(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE - 1,
data->config & to_sensor_dev_attr(attr)->index ?
@@ -250,8 +247,7 @@ static ssize_t show_max(struct device *dev, struct device_attribute *attr,
static ssize_t set_max(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
long val;
if (kstrtol(buf, 10, &val) < 0)
@@ -267,7 +263,8 @@ static ssize_t set_max(struct device *dev, struct device_attribute *attr,
data->config &= ~to_sensor_dev_attr(attr)->index;
data->valid = 0;
- i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
+ i2c_smbus_write_byte_data(data->client, LM95241_REG_RW_CONFIG,
+ data->config);
mutex_unlock(&data->update_lock);
@@ -286,8 +283,7 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95241_data *data = i2c_get_clientdata(client);
+ struct lm95241_data *data = dev_get_drvdata(dev);
unsigned long val;
if (kstrtoul(buf, 10, &val) < 0)
@@ -316,7 +312,7 @@ static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max, set_max,
static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
set_interval);
-static struct attribute *lm95241_attributes[] = {
+static struct attribute *lm95241_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
@@ -329,10 +325,7 @@ static struct attribute *lm95241_attributes[] = {
&dev_attr_update_interval.attr,
NULL
};
-
-static const struct attribute_group lm95241_group = {
- .attrs = lm95241_attributes,
-};
+ATTRIBUTE_GROUPS(lm95241);
/* Return 0 if detection is successful, -ENODEV otherwise */
static int lm95241_detect(struct i2c_client *new_client,
@@ -366,14 +359,11 @@ static int lm95241_detect(struct i2c_client *new_client,
return 0;
}
-static void lm95241_init_client(struct i2c_client *client)
+static void lm95241_init_client(struct i2c_client *client,
+ struct lm95241_data *data)
{
- struct lm95241_data *data = i2c_get_clientdata(client);
-
data->interval = HZ; /* 1 sec default */
- data->valid = 0;
data->config = CFG_CR0076;
- data->model = 0;
data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT);
i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config);
@@ -385,49 +375,27 @@ static void lm95241_init_client(struct i2c_client *client)
data->model);
}
-static int lm95241_probe(struct i2c_client *new_client,
+static int lm95241_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct device *dev = &client->dev;
struct lm95241_data *data;
- int err;
+ struct device *hwmon_dev;
- data = devm_kzalloc(&new_client->dev, sizeof(struct lm95241_data),
- GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct lm95241_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(new_client, data);
+ data->client = client;
mutex_init(&data->update_lock);
/* Initialize the LM95241 chip */
- lm95241_init_client(new_client);
+ lm95241_init_client(client, data);
- /* Register sysfs hooks */
- err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group);
- if (err)
- return err;
-
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto exit_remove_files;
- }
-
- return 0;
-
-exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &lm95241_group);
- return err;
-}
-
-static int lm95241_remove(struct i2c_client *client)
-{
- struct lm95241_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &lm95241_group);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data,
+ lm95241_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
/* Driver data (common to all clients) */
@@ -444,7 +412,6 @@ static struct i2c_driver lm95241_driver = {
.name = DEVNAME,
},
.probe = lm95241_probe,
- .remove = lm95241_remove,
.id_table = lm95241_id,
.detect = lm95241_detect,
.address_list = normal_i2c,
diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c
index a6c85f0ff8f3..0ae0dfdafdff 100644
--- a/drivers/hwmon/lm95245.c
+++ b/drivers/hwmon/lm95245.c
@@ -115,7 +115,7 @@ static const u8 lm95245_reg_address[] = {
/* Client data (each client gets its own) */
struct lm95245_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
struct mutex update_lock;
unsigned long last_updated; /* in jiffies */
unsigned long interval; /* in msecs */
@@ -140,8 +140,8 @@ static int temp_from_reg_signed(u8 val_h, u8 val_l)
static struct lm95245_data *lm95245_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95245_data *data = i2c_get_clientdata(client);
+ struct lm95245_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
mutex_lock(&data->update_lock);
@@ -149,7 +149,6 @@ static struct lm95245_data *lm95245_update_device(struct device *dev)
+ msecs_to_jiffies(data->interval)) || !data->valid) {
int i;
- dev_dbg(&client->dev, "Updating lm95245 data.\n");
for (i = 0; i < ARRAY_SIZE(lm95245_reg_address); i++)
data->regs[i]
= i2c_smbus_read_byte_data(client,
@@ -249,9 +248,9 @@ static ssize_t show_limit(struct device *dev, struct device_attribute *attr,
static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95245_data *data = i2c_get_clientdata(client);
+ struct lm95245_data *data = dev_get_drvdata(dev);
int index = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = data->client;
unsigned long val;
if (kstrtoul(buf, 10, &val) < 0)
@@ -272,27 +271,38 @@ static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
return count;
}
+static ssize_t show_crit_hyst(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lm95245_data *data = lm95245_update_device(dev);
+ int index = to_sensor_dev_attr(attr)->index;
+ int hyst = data->regs[index] - data->regs[8];
+
+ return snprintf(buf, PAGE_SIZE - 1, "%d\n", hyst * 1000);
+}
+
static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95245_data *data = i2c_get_clientdata(client);
+ struct lm95245_data *data = dev_get_drvdata(dev);
+ int index = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = data->client;
unsigned long val;
+ int hyst, limit;
if (kstrtoul(buf, 10, &val) < 0)
return -EINVAL;
- val /= 1000;
-
- val = clamp_val(val, 0, 31);
-
mutex_lock(&data->update_lock);
- data->valid = 0;
+ limit = i2c_smbus_read_byte_data(client, lm95245_reg_address[index]);
+ hyst = limit - val / 1000;
+ hyst = clamp_val(hyst, 0, 31);
+ data->regs[8] = hyst;
/* shared crit hysteresis */
i2c_smbus_write_byte_data(client, LM95245_REG_RW_COMMON_HYSTERESIS,
- val);
+ hyst);
mutex_unlock(&data->update_lock);
@@ -302,8 +312,7 @@ static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr,
static ssize_t show_type(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95245_data *data = i2c_get_clientdata(client);
+ struct lm95245_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE - 1,
data->config2 & CFG2_REMOTE_TT ? "1\n" : "2\n");
@@ -312,8 +321,8 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr,
static ssize_t set_type(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95245_data *data = i2c_get_clientdata(client);
+ struct lm95245_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
if (kstrtoul(buf, 10, &val) < 0)
@@ -359,8 +368,8 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm95245_data *data = i2c_get_clientdata(client);
+ struct lm95245_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
if (kstrtoul(buf, 10, &val) < 0)
@@ -378,16 +387,15 @@ static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_limit,
set_limit, 6);
-static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
- set_crit_hyst, 8);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_crit_hyst,
+ set_crit_hyst, 6);
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
STATUS1_LOC);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2);
static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_limit,
set_limit, 7);
-static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
- set_crit_hyst, 8);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_crit_hyst, NULL, 7);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
STATUS1_RTCRIT);
static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type,
@@ -398,7 +406,7 @@ static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL,
static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
set_interval);
-static struct attribute *lm95245_attributes[] = {
+static struct attribute *lm95245_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
@@ -412,10 +420,7 @@ static struct attribute *lm95245_attributes[] = {
&dev_attr_update_interval.attr,
NULL
};
-
-static const struct attribute_group lm95245_group = {
- .attrs = lm95245_attributes,
-};
+ATTRIBUTE_GROUPS(lm95245);
/* Return 0 if detection is successful, -ENODEV otherwise */
static int lm95245_detect(struct i2c_client *new_client,
@@ -436,11 +441,9 @@ static int lm95245_detect(struct i2c_client *new_client,
return 0;
}
-static void lm95245_init_client(struct i2c_client *client)
+static void lm95245_init_client(struct i2c_client *client,
+ struct lm95245_data *data)
{
- struct lm95245_data *data = i2c_get_clientdata(client);
-
- data->valid = 0;
data->interval = lm95245_read_conversion_rate(client);
data->config1 = i2c_smbus_read_byte_data(client,
@@ -456,49 +459,27 @@ static void lm95245_init_client(struct i2c_client *client)
}
}
-static int lm95245_probe(struct i2c_client *new_client,
+static int lm95245_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct device *dev = &client->dev;
struct lm95245_data *data;
- int err;
+ struct device *hwmon_dev;
- data = devm_kzalloc(&new_client->dev, sizeof(struct lm95245_data),
- GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct lm95245_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(new_client, data);
+ data->client = client;
mutex_init(&data->update_lock);
/* Initialize the LM95245 chip */
- lm95245_init_client(new_client);
-
- /* Register sysfs hooks */
- err = sysfs_create_group(&new_client->dev.kobj, &lm95245_group);
- if (err)
- return err;
-
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto exit_remove_files;
- }
-
- return 0;
-
-exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &lm95245_group);
- return err;
-}
+ lm95245_init_client(client, data);
-static int lm95245_remove(struct i2c_client *client)
-{
- struct lm95245_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &lm95245_group);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data,
+ lm95245_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
/* Driver data (common to all clients) */
@@ -514,7 +495,6 @@ static struct i2c_driver lm95245_driver = {
.name = DEVNAME,
},
.probe = lm95245_probe,
- .remove = lm95245_remove,
.id_table = lm95245_id,
.detect = lm95245_detect,
.address_list = normal_i2c,
diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c
new file mode 100644
index 000000000000..c104cc32989d
--- /dev/null
+++ b/drivers/hwmon/ltc2945.c
@@ -0,0 +1,519 @@
+/*
+ * Driver for Linear Technology LTC2945 I2C Power Monitor
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * This program is free software; 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/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+
+/* chip registers */
+#define LTC2945_CONTROL 0x00
+#define LTC2945_ALERT 0x01
+#define LTC2945_STATUS 0x02
+#define LTC2945_FAULT 0x03
+#define LTC2945_POWER_H 0x05
+#define LTC2945_MAX_POWER_H 0x08
+#define LTC2945_MIN_POWER_H 0x0b
+#define LTC2945_MAX_POWER_THRES_H 0x0e
+#define LTC2945_MIN_POWER_THRES_H 0x11
+#define LTC2945_SENSE_H 0x14
+#define LTC2945_MAX_SENSE_H 0x16
+#define LTC2945_MIN_SENSE_H 0x18
+#define LTC2945_MAX_SENSE_THRES_H 0x1a
+#define LTC2945_MIN_SENSE_THRES_H 0x1c
+#define LTC2945_VIN_H 0x1e
+#define LTC2945_MAX_VIN_H 0x20
+#define LTC2945_MIN_VIN_H 0x22
+#define LTC2945_MAX_VIN_THRES_H 0x24
+#define LTC2945_MIN_VIN_THRES_H 0x26
+#define LTC2945_ADIN_H 0x28
+#define LTC2945_MAX_ADIN_H 0x2a
+#define LTC2945_MIN_ADIN_H 0x2c
+#define LTC2945_MAX_ADIN_THRES_H 0x2e
+#define LTC2945_MIN_ADIN_THRES_H 0x30
+#define LTC2945_MIN_ADIN_THRES_L 0x31
+
+/* Fault register bits */
+
+#define FAULT_ADIN_UV (1 << 0)
+#define FAULT_ADIN_OV (1 << 1)
+#define FAULT_VIN_UV (1 << 2)
+#define FAULT_VIN_OV (1 << 3)
+#define FAULT_SENSE_UV (1 << 4)
+#define FAULT_SENSE_OV (1 << 5)
+#define FAULT_POWER_UV (1 << 6)
+#define FAULT_POWER_OV (1 << 7)
+
+/* Control register bits */
+
+#define CONTROL_MULT_SELECT (1 << 0)
+#define CONTROL_TEST_MODE (1 << 4)
+
+static inline bool is_power_reg(u8 reg)
+{
+ return reg < LTC2945_SENSE_H;
+}
+
+/* Return the value from the given register in uW, mV, or mA */
+static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int control;
+ u8 buf[3];
+ long long val;
+ int ret;
+
+ ret = regmap_bulk_read(regmap, reg, buf,
+ is_power_reg(reg) ? 3 : 2);
+ if (ret < 0)
+ return ret;
+
+ if (is_power_reg(reg)) {
+ /* power */
+ val = (buf[0] << 16) + (buf[1] << 8) + buf[2];
+ } else {
+ /* current, voltage */
+ val = (buf[0] << 4) + (buf[1] >> 4);
+ }
+
+ switch (reg) {
+ case LTC2945_POWER_H:
+ case LTC2945_MAX_POWER_H:
+ case LTC2945_MIN_POWER_H:
+ case LTC2945_MAX_POWER_THRES_H:
+ case LTC2945_MIN_POWER_THRES_H:
+ /*
+ * Convert to uW by assuming current is measured with
+ * an 1mOhm sense resistor, similar to current
+ * measurements.
+ * Control register bit 0 selects if voltage at SENSE+/VDD
+ * or voltage at ADIN is used to measure power.
+ */
+ ret = regmap_read(regmap, LTC2945_CONTROL, &control);
+ if (ret < 0)
+ return ret;
+ if (control & CONTROL_MULT_SELECT) {
+ /* 25 mV * 25 uV = 0.625 uV resolution. */
+ val *= 625LL;
+ } else {
+ /* 0.5 mV * 25 uV = 0.0125 uV resolution. */
+ val = (val * 25LL) >> 1;
+ }
+ break;
+ case LTC2945_VIN_H:
+ case LTC2945_MAX_VIN_H:
+ case LTC2945_MIN_VIN_H:
+ case LTC2945_MAX_VIN_THRES_H:
+ case LTC2945_MIN_VIN_THRES_H:
+ /* 25 mV resolution. Convert to mV. */
+ val *= 25;
+ break;
+ case LTC2945_ADIN_H:
+ case LTC2945_MAX_ADIN_H:
+ case LTC2945_MIN_ADIN_THRES_H:
+ case LTC2945_MAX_ADIN_THRES_H:
+ case LTC2945_MIN_ADIN_H:
+ /* 0.5mV resolution. Convert to mV. */
+ val = val >> 1;
+ break;
+ case LTC2945_SENSE_H:
+ case LTC2945_MAX_SENSE_H:
+ case LTC2945_MIN_SENSE_H:
+ case LTC2945_MAX_SENSE_THRES_H:
+ case LTC2945_MIN_SENSE_THRES_H:
+ /*
+ * 25 uV resolution. Convert to current as measured with
+ * an 1 mOhm sense resistor, in mA. If a different sense
+ * resistor is installed, calculate the actual current by
+ * dividing the reported current by the sense resistor value
+ * in mOhm.
+ */
+ val *= 25;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return val;
+}
+
+static int ltc2945_val_to_reg(struct device *dev, u8 reg,
+ unsigned long val)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int control;
+ int ret;
+
+ switch (reg) {
+ case LTC2945_POWER_H:
+ case LTC2945_MAX_POWER_H:
+ case LTC2945_MIN_POWER_H:
+ case LTC2945_MAX_POWER_THRES_H:
+ case LTC2945_MIN_POWER_THRES_H:
+ /*
+ * Convert to register value by assuming current is measured
+ * with an 1mOhm sense resistor, similar to current
+ * measurements.
+ * Control register bit 0 selects if voltage at SENSE+/VDD
+ * or voltage at ADIN is used to measure power, which in turn
+ * determines register calculations.
+ */
+ ret = regmap_read(regmap, LTC2945_CONTROL, &control);
+ if (ret < 0)
+ return ret;
+ if (control & CONTROL_MULT_SELECT) {
+ /* 25 mV * 25 uV = 0.625 uV resolution. */
+ val = DIV_ROUND_CLOSEST(val, 625);
+ } else {
+ /*
+ * 0.5 mV * 25 uV = 0.0125 uV resolution.
+ * Divide first to avoid overflow;
+ * accept loss of accuracy.
+ */
+ val = DIV_ROUND_CLOSEST(val, 25) * 2;
+ }
+ break;
+ case LTC2945_VIN_H:
+ case LTC2945_MAX_VIN_H:
+ case LTC2945_MIN_VIN_H:
+ case LTC2945_MAX_VIN_THRES_H:
+ case LTC2945_MIN_VIN_THRES_H:
+ /* 25 mV resolution. */
+ val /= 25;
+ break;
+ case LTC2945_ADIN_H:
+ case LTC2945_MAX_ADIN_H:
+ case LTC2945_MIN_ADIN_THRES_H:
+ case LTC2945_MAX_ADIN_THRES_H:
+ case LTC2945_MIN_ADIN_H:
+ /* 0.5mV resolution. */
+ val *= 2;
+ break;
+ case LTC2945_SENSE_H:
+ case LTC2945_MAX_SENSE_H:
+ case LTC2945_MIN_SENSE_H:
+ case LTC2945_MAX_SENSE_THRES_H:
+ case LTC2945_MIN_SENSE_THRES_H:
+ /*
+ * 25 uV resolution. Convert to current as measured with
+ * an 1 mOhm sense resistor, in mA. If a different sense
+ * resistor is installed, calculate the actual current by
+ * dividing the reported current by the sense resistor value
+ * in mOhm.
+ */
+ val = DIV_ROUND_CLOSEST(val, 25);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return val;
+}
+
+static ssize_t ltc2945_show_value(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ long long value;
+
+ value = ltc2945_reg_to_val(dev, attr->index);
+ if (value < 0)
+ return value;
+ return snprintf(buf, PAGE_SIZE, "%lld\n", value);
+}
+
+static ssize_t ltc2945_set_value(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct regmap *regmap = dev_get_drvdata(dev);
+ u8 reg = attr->index;
+ unsigned long val;
+ u8 regbuf[3];
+ int num_regs;
+ int regval;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ /* convert to register value, then clamp and write result */
+ regval = ltc2945_val_to_reg(dev, reg, val);
+ if (is_power_reg(reg)) {
+ regval = clamp_val(regval, 0, 0xffffff);
+ regbuf[0] = regval >> 16;
+ regbuf[1] = (regval >> 8) & 0xff;
+ regbuf[2] = regval;
+ num_regs = 3;
+ } else {
+ regval = clamp_val(regval, 0, 0xfff) << 4;
+ regbuf[0] = regval >> 8;
+ regbuf[1] = regval & 0xff;
+ num_regs = 2;
+ }
+ ret = regmap_bulk_write(regmap, reg, regbuf, num_regs);
+ return ret < 0 ? ret : count;
+}
+
+static ssize_t ltc2945_reset_history(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct regmap *regmap = dev_get_drvdata(dev);
+ u8 reg = attr->index;
+ int num_regs = is_power_reg(reg) ? 3 : 2;
+ u8 buf_min[3] = { 0xff, 0xff, 0xff };
+ u8 buf_max[3] = { 0, 0, 0 };
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+ if (val != 1)
+ return -EINVAL;
+
+ ret = regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE,
+ CONTROL_TEST_MODE);
+
+ /* Reset minimum */
+ ret = regmap_bulk_write(regmap, reg, buf_min, num_regs);
+ if (ret)
+ return ret;
+
+ switch (reg) {
+ case LTC2945_MIN_POWER_H:
+ reg = LTC2945_MAX_POWER_H;
+ break;
+ case LTC2945_MIN_SENSE_H:
+ reg = LTC2945_MAX_SENSE_H;
+ break;
+ case LTC2945_MIN_VIN_H:
+ reg = LTC2945_MAX_VIN_H;
+ break;
+ case LTC2945_MIN_ADIN_H:
+ reg = LTC2945_MAX_ADIN_H;
+ break;
+ default:
+ BUG();
+ break;
+ }
+ /* Reset maximum */
+ ret = regmap_bulk_write(regmap, reg, buf_max, num_regs);
+
+ /* Try resetting test mode even if there was an error */
+ regmap_update_bits(regmap, LTC2945_CONTROL, CONTROL_TEST_MODE, 0);
+
+ return ret ? : count;
+}
+
+static ssize_t ltc2945_show_bool(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int fault;
+ int ret;
+
+ ret = regmap_read(regmap, LTC2945_FAULT, &fault);
+ if (ret < 0)
+ return ret;
+
+ fault &= attr->index;
+ if (fault) /* Clear reported faults in chip register */
+ regmap_update_bits(regmap, LTC2945_FAULT, attr->index, 0);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+}
+
+/* Input voltages */
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_VIN_H);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MIN_VIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MAX_VIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in1_lowest, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_MIN_VIN_H);
+static SENSOR_DEVICE_ATTR(in1_highest, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_MAX_VIN_H);
+static SENSOR_DEVICE_ATTR(in1_reset_history, S_IWUSR, NULL,
+ ltc2945_reset_history, LTC2945_MIN_VIN_H);
+
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MIN_ADIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MAX_ADIN_THRES_H);
+static SENSOR_DEVICE_ATTR(in2_lowest, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_MIN_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_highest, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_MAX_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_reset_history, S_IWUSR, NULL,
+ ltc2945_reset_history, LTC2945_MIN_ADIN_H);
+
+/* Voltage alarms */
+
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_VIN_UV);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_VIN_OV);
+static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_ADIN_UV);
+static SENSOR_DEVICE_ATTR(in2_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_ADIN_OV);
+
+/* Currents (via sense resistor) */
+
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MIN_SENSE_THRES_H);
+static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MAX_SENSE_THRES_H);
+static SENSOR_DEVICE_ATTR(curr1_lowest, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_MIN_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_highest, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_MAX_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_reset_history, S_IWUSR, NULL,
+ ltc2945_reset_history, LTC2945_MIN_SENSE_H);
+
+/* Current alarms */
+
+static SENSOR_DEVICE_ATTR(curr1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_SENSE_UV);
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_SENSE_OV);
+
+/* Power */
+
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc2945_show_value, NULL,
+ LTC2945_POWER_H);
+static SENSOR_DEVICE_ATTR(power1_min, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MIN_POWER_THRES_H);
+static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO | S_IWUSR, ltc2945_show_value,
+ ltc2945_set_value, LTC2945_MAX_POWER_THRES_H);
+static SENSOR_DEVICE_ATTR(power1_input_lowest, S_IRUGO, ltc2945_show_value,
+ NULL, LTC2945_MIN_POWER_H);
+static SENSOR_DEVICE_ATTR(power1_input_highest, S_IRUGO, ltc2945_show_value,
+ NULL, LTC2945_MAX_POWER_H);
+static SENSOR_DEVICE_ATTR(power1_reset_history, S_IWUSR, NULL,
+ ltc2945_reset_history, LTC2945_MIN_POWER_H);
+
+/* Power alarms */
+
+static SENSOR_DEVICE_ATTR(power1_min_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_POWER_UV);
+static SENSOR_DEVICE_ATTR(power1_max_alarm, S_IRUGO, ltc2945_show_bool, NULL,
+ FAULT_POWER_OV);
+
+static struct attribute *ltc2945_attrs[] = {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_lowest.dev_attr.attr,
+ &sensor_dev_attr_in1_highest.dev_attr.attr,
+ &sensor_dev_attr_in1_reset_history.dev_attr.attr,
+ &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_lowest.dev_attr.attr,
+ &sensor_dev_attr_in2_highest.dev_attr.attr,
+ &sensor_dev_attr_in2_reset_history.dev_attr.attr,
+ &sensor_dev_attr_in2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_max_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_curr1_min.dev_attr.attr,
+ &sensor_dev_attr_curr1_max.dev_attr.attr,
+ &sensor_dev_attr_curr1_lowest.dev_attr.attr,
+ &sensor_dev_attr_curr1_highest.dev_attr.attr,
+ &sensor_dev_attr_curr1_reset_history.dev_attr.attr,
+ &sensor_dev_attr_curr1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_power1_input.dev_attr.attr,
+ &sensor_dev_attr_power1_min.dev_attr.attr,
+ &sensor_dev_attr_power1_max.dev_attr.attr,
+ &sensor_dev_attr_power1_input_lowest.dev_attr.attr,
+ &sensor_dev_attr_power1_input_highest.dev_attr.attr,
+ &sensor_dev_attr_power1_reset_history.dev_attr.attr,
+ &sensor_dev_attr_power1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_power1_max_alarm.dev_attr.attr,
+
+ NULL,
+};
+ATTRIBUTE_GROUPS(ltc2945);
+
+static struct regmap_config ltc2945_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = LTC2945_MIN_ADIN_THRES_L,
+};
+
+static int ltc2945_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct device *hwmon_dev;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &ltc2945_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "failed to allocate register map\n");
+ return PTR_ERR(regmap);
+ }
+
+ /* Clear faults */
+ regmap_write(regmap, LTC2945_FAULT, 0x00);
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ regmap,
+ ltc2945_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc2945_id[] = {
+ {"ltc2945", 0},
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc2945_id);
+
+static struct i2c_driver ltc2945_driver = {
+ .driver = {
+ .name = "ltc2945",
+ },
+ .probe = ltc2945_probe,
+ .id_table = ltc2945_id,
+};
+
+module_i2c_driver(ltc2945_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LTC2945 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c
index 8a142960d69e..c8a9bd9b050f 100644
--- a/drivers/hwmon/ltc4215.c
+++ b/drivers/hwmon/ltc4215.c
@@ -33,7 +33,7 @@ enum ltc4215_cmd {
};
struct ltc4215_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
struct mutex update_lock;
bool valid;
@@ -45,8 +45,8 @@ struct ltc4215_data {
static struct ltc4215_data *ltc4215_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct ltc4215_data *data = i2c_get_clientdata(client);
+ struct ltc4215_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
s32 val;
int i;
@@ -214,7 +214,7 @@ static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
* Finally, construct an array of pointers to members of the above objects,
* as required for sysfs_create_group()
*/
-static struct attribute *ltc4215_attributes[] = {
+static struct attribute *ltc4215_attrs[] = {
&sensor_dev_attr_curr1_input.dev_attr.attr,
&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
@@ -229,57 +229,33 @@ static struct attribute *ltc4215_attributes[] = {
NULL,
};
-
-static const struct attribute_group ltc4215_group = {
- .attrs = ltc4215_attributes,
-};
+ATTRIBUTE_GROUPS(ltc4215);
static int ltc4215_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = client->adapter;
+ struct device *dev = &client->dev;
struct ltc4215_data *data;
- int ret;
+ struct device *hwmon_dev;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(client, data);
+ data->client = client;
mutex_init(&data->update_lock);
/* Initialize the LTC4215 chip */
i2c_smbus_write_byte_data(client, LTC4215_FAULT, 0x00);
- /* Register sysfs hooks */
- ret = sysfs_create_group(&client->dev.kobj, &ltc4215_group);
- if (ret)
- return ret;
-
- data->hwmon_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- ret = PTR_ERR(data->hwmon_dev);
- goto out_hwmon_device_register;
- }
-
- return 0;
-
-out_hwmon_device_register:
- sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
- return ret;
-}
-
-static int ltc4215_remove(struct i2c_client *client)
-{
- struct ltc4215_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data,
+ ltc4215_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id ltc4215_id[] = {
@@ -294,7 +270,6 @@ static struct i2c_driver ltc4215_driver = {
.name = "ltc4215",
},
.probe = ltc4215_probe,
- .remove = ltc4215_remove,
.id_table = ltc4215_id,
};
diff --git a/drivers/hwmon/ltc4222.c b/drivers/hwmon/ltc4222.c
new file mode 100644
index 000000000000..07c25653659f
--- /dev/null
+++ b/drivers/hwmon/ltc4222.c
@@ -0,0 +1,237 @@
+/*
+ * Driver for Linear Technology LTC4222 Dual Hot Swap controller
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * This program is free software; 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/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+
+/* chip registers */
+
+#define LTC4222_CONTROL1 0xd0
+#define LTC4222_ALERT1 0xd1
+#define LTC4222_STATUS1 0xd2
+#define LTC4222_FAULT1 0xd3
+#define LTC4222_CONTROL2 0xd4
+#define LTC4222_ALERT2 0xd5
+#define LTC4222_STATUS2 0xd6
+#define LTC4222_FAULT2 0xd7
+#define LTC4222_SOURCE1 0xd8
+#define LTC4222_SOURCE2 0xda
+#define LTC4222_ADIN1 0xdc
+#define LTC4222_ADIN2 0xde
+#define LTC4222_SENSE1 0xe0
+#define LTC4222_SENSE2 0xe2
+#define LTC4222_ADC_CONTROL 0xe4
+
+/*
+ * Fault register bits
+ */
+#define FAULT_OV BIT(0)
+#define FAULT_UV BIT(1)
+#define FAULT_OC BIT(2)
+#define FAULT_POWER_BAD BIT(3)
+#define FAULT_FET_BAD BIT(5)
+
+/* Return the voltage from the given register in mV or mA */
+static int ltc4222_get_value(struct device *dev, u8 reg)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int val;
+ u8 buf[2];
+ int ret;
+
+ ret = regmap_bulk_read(regmap, reg, buf, 2);
+ if (ret < 0)
+ return ret;
+
+ val = ((buf[0] << 8) + buf[1]) >> 6;
+
+ switch (reg) {
+ case LTC4222_ADIN1:
+ case LTC4222_ADIN2:
+ /* 1.25 mV resolution. Convert to mV. */
+ val = DIV_ROUND_CLOSEST(val * 5, 4);
+ break;
+ case LTC4222_SOURCE1:
+ case LTC4222_SOURCE2:
+ /* 31.25 mV resolution. Convert to mV. */
+ val = DIV_ROUND_CLOSEST(val * 125, 4);
+ break;
+ case LTC4222_SENSE1:
+ case LTC4222_SENSE2:
+ /*
+ * 62.5 uV resolution. Convert to current as measured with
+ * an 1 mOhm sense resistor, in mA. If a different sense
+ * resistor is installed, calculate the actual current by
+ * dividing the reported current by the sense resistor value
+ * in mOhm.
+ */
+ val = DIV_ROUND_CLOSEST(val * 125, 2);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return val;
+}
+
+static ssize_t ltc4222_show_value(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int value;
+
+ value = ltc4222_get_value(dev, attr->index);
+ if (value < 0)
+ return value;
+ return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t ltc4222_show_bool(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int fault;
+ int ret;
+
+ ret = regmap_read(regmap, attr->nr, &fault);
+ if (ret < 0)
+ return ret;
+ fault &= attr->index;
+ if (fault) /* Clear reported faults in chip register */
+ regmap_update_bits(regmap, attr->nr, attr->index, 0);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+}
+
+/* Voltages */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4222_show_value, NULL,
+ LTC4222_SOURCE1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4222_show_value, NULL,
+ LTC4222_ADIN1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc4222_show_value, NULL,
+ LTC4222_SOURCE2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc4222_show_value, NULL,
+ LTC4222_ADIN2);
+
+/*
+ * Voltage alarms
+ * UV/OV faults are associated with the input voltage, and power bad and fet
+ * faults are associated with the output voltage.
+ */
+static SENSOR_DEVICE_ATTR_2(in1_min_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT1, FAULT_UV);
+static SENSOR_DEVICE_ATTR_2(in1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT1, FAULT_OV);
+static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT1, FAULT_POWER_BAD | FAULT_FET_BAD);
+
+static SENSOR_DEVICE_ATTR_2(in3_min_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT2, FAULT_UV);
+static SENSOR_DEVICE_ATTR_2(in3_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT2, FAULT_OV);
+static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT2, FAULT_POWER_BAD | FAULT_FET_BAD);
+
+/* Current (via sense resistor) */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4222_show_value, NULL,
+ LTC4222_SENSE1);
+static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc4222_show_value, NULL,
+ LTC4222_SENSE2);
+
+/* Overcurrent alarm */
+static SENSOR_DEVICE_ATTR_2(curr1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT1, FAULT_OC);
+static SENSOR_DEVICE_ATTR_2(curr2_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
+ LTC4222_FAULT2, FAULT_OC);
+
+static struct attribute *ltc4222_attrs[] = {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_curr2_input.dev_attr.attr,
+ &sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
+
+ NULL,
+};
+ATTRIBUTE_GROUPS(ltc4222);
+
+static struct regmap_config ltc4222_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = LTC4222_ADC_CONTROL,
+};
+
+static int ltc4222_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct device *hwmon_dev;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &ltc4222_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "failed to allocate register map\n");
+ return PTR_ERR(regmap);
+ }
+
+ /* Clear faults */
+ regmap_write(regmap, LTC4222_FAULT1, 0x00);
+ regmap_write(regmap, LTC4222_FAULT2, 0x00);
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ regmap,
+ ltc4222_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc4222_id[] = {
+ {"ltc4222", 0},
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc4222_id);
+
+static struct i2c_driver ltc4222_driver = {
+ .driver = {
+ .name = "ltc4222",
+ },
+ .probe = ltc4222_probe,
+ .id_table = ltc4222_id,
+};
+
+module_i2c_driver(ltc4222_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LTC4222 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c
index d4172933ce4f..681b5b7b3c3b 100644
--- a/drivers/hwmon/ltc4245.c
+++ b/drivers/hwmon/ltc4245.c
@@ -95,7 +95,6 @@ static void ltc4245_update_gpios(struct device *dev)
* readings as stale by setting them to -EAGAIN
*/
if (time_after(jiffies, data->last_updated + 5 * HZ)) {
- dev_dbg(&client->dev, "Marking GPIOs invalid\n");
for (i = 0; i < ARRAY_SIZE(data->gpios); i++)
data->gpios[i] = -EAGAIN;
}
@@ -141,8 +140,6 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
- dev_dbg(&client->dev, "Starting ltc4245 update\n");
-
/* Read control registers -- 0x00 to 0x07 */
for (i = 0; i < ARRAY_SIZE(data->cregs); i++) {
val = i2c_smbus_read_byte_data(client, i);
@@ -470,19 +467,15 @@ static void ltc4245_sysfs_add_groups(struct ltc4245_data *data)
static bool ltc4245_use_extra_gpios(struct i2c_client *client)
{
struct ltc4245_platform_data *pdata = dev_get_platdata(&client->dev);
-#ifdef CONFIG_OF
struct device_node *np = client->dev.of_node;
-#endif
/* prefer platform data */
if (pdata)
return pdata->use_extra_gpios;
-#ifdef CONFIG_OF
/* fallback on OF */
if (of_find_property(np, "ltc4245,use-extra-gpios", NULL))
return true;
-#endif
return false;
}
@@ -512,24 +505,10 @@ static int ltc4245_probe(struct i2c_client *client,
/* Add sysfs hooks */
ltc4245_sysfs_add_groups(data);
- hwmon_dev = hwmon_device_register_with_groups(&client->dev,
- client->name, data,
- data->groups);
- if (IS_ERR(hwmon_dev))
- return PTR_ERR(hwmon_dev);
-
- i2c_set_clientdata(client, hwmon_dev);
-
- return 0;
-}
-
-static int ltc4245_remove(struct i2c_client *client)
-{
- struct device *hwmon_dev = i2c_get_clientdata(client);
-
- hwmon_device_unregister(hwmon_dev);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
+ client->name, data,
+ data->groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id ltc4245_id[] = {
@@ -544,7 +523,6 @@ static struct i2c_driver ltc4245_driver = {
.name = "ltc4245",
},
.probe = ltc4245_probe,
- .remove = ltc4245_remove,
.id_table = ltc4245_id,
};
diff --git a/drivers/hwmon/ltc4260.c b/drivers/hwmon/ltc4260.c
new file mode 100644
index 000000000000..453a250d9df5
--- /dev/null
+++ b/drivers/hwmon/ltc4260.c
@@ -0,0 +1,200 @@
+/*
+ * Driver for Linear Technology LTC4260 I2C Positive Voltage Hot Swap Controller
+ *
+ * Copyright (c) 2014 Guenter Roeck
+ *
+ * This program is free software; 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/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+
+/* chip registers */
+#define LTC4260_CONTROL 0x00
+#define LTC4260_ALERT 0x01
+#define LTC4260_STATUS 0x02
+#define LTC4260_FAULT 0x03
+#define LTC4260_SENSE 0x04
+#define LTC4260_SOURCE 0x05
+#define LTC4260_ADIN 0x06
+
+/*
+ * Fault register bits
+ */
+#define FAULT_OV (1 << 0)
+#define FAULT_UV (1 << 1)
+#define FAULT_OC (1 << 2)
+#define FAULT_POWER_BAD (1 << 3)
+#define FAULT_FET_SHORT (1 << 5)
+
+/* Return the voltage from the given register in mV or mA */
+static int ltc4260_get_value(struct device *dev, u8 reg)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(regmap, reg, &val);
+ if (ret < 0)
+ return ret;
+
+ switch (reg) {
+ case LTC4260_ADIN:
+ /* 10 mV resolution. Convert to mV. */
+ val = val * 10;
+ break;
+ case LTC4260_SOURCE:
+ /* 400 mV resolution. Convert to mV. */
+ val = val * 400;
+ break;
+ case LTC4260_SENSE:
+ /*
+ * 300 uV resolution. Convert to current as measured with
+ * an 1 mOhm sense resistor, in mA. If a different sense
+ * resistor is installed, calculate the actual current by
+ * dividing the reported current by the sense resistor value
+ * in mOhm.
+ */
+ val = val * 300;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return val;
+}
+
+static ssize_t ltc4260_show_value(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int value;
+
+ value = ltc4260_get_value(dev, attr->index);
+ if (value < 0)
+ return value;
+ return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t ltc4260_show_bool(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int fault;
+ int ret;
+
+ ret = regmap_read(regmap, LTC4260_FAULT, &fault);
+ if (ret < 0)
+ return ret;
+
+ fault &= attr->index;
+ if (fault) /* Clear reported faults in chip register */
+ regmap_update_bits(regmap, LTC4260_FAULT, attr->index, 0);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+}
+
+/* Voltages */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4260_show_value, NULL,
+ LTC4260_SOURCE);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4260_show_value, NULL,
+ LTC4260_ADIN);
+
+/*
+ * Voltage alarms
+ * UV/OV faults are associated with the input voltage, and the POWER BAD and
+ * FET SHORT faults are associated with the output voltage.
+ */
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+ FAULT_UV);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+ FAULT_OV);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+ FAULT_POWER_BAD | FAULT_FET_SHORT);
+
+/* Current (via sense resistor) */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4260_show_value, NULL,
+ LTC4260_SENSE);
+
+/* Overcurrent alarm */
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4260_show_bool, NULL,
+ FAULT_OC);
+
+static struct attribute *ltc4260_attrs[] = {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+ NULL,
+};
+ATTRIBUTE_GROUPS(ltc4260);
+
+static struct regmap_config ltc4260_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = LTC4260_ADIN,
+};
+
+static int ltc4260_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct device *hwmon_dev;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &ltc4260_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "failed to allocate register map\n");
+ return PTR_ERR(regmap);
+ }
+
+ /* Clear faults */
+ regmap_write(regmap, LTC4260_FAULT, 0x00);
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ regmap,
+ ltc4260_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id ltc4260_id[] = {
+ {"ltc4260", 0},
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc4260_id);
+
+static struct i2c_driver ltc4260_driver = {
+ .driver = {
+ .name = "ltc4260",
+ },
+ .probe = ltc4260_probe,
+ .id_table = ltc4260_id,
+};
+
+module_i2c_driver(ltc4260_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LTC4260 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c
index a7626358c95d..e3ed0a5b6d94 100644
--- a/drivers/hwmon/max1668.c
+++ b/drivers/hwmon/max1668.c
@@ -66,7 +66,8 @@ MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
enum chips { max1668, max1805, max1989 };
struct max1668_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
+ const struct attribute_group *groups[3];
enum chips type;
struct mutex update_lock;
@@ -82,8 +83,8 @@ struct max1668_data {
static struct max1668_data *max1668_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max1668_data *data = i2c_get_clientdata(client);
+ struct max1668_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
struct max1668_data *ret = data;
s32 val;
int i;
@@ -205,8 +206,8 @@ static ssize_t set_temp_max(struct device *dev,
const char *buf, size_t count)
{
int index = to_sensor_dev_attr(devattr)->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct max1668_data *data = i2c_get_clientdata(client);
+ struct max1668_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
long temp;
int ret;
@@ -216,10 +217,11 @@ static ssize_t set_temp_max(struct device *dev,
mutex_lock(&data->update_lock);
data->temp_max[index] = clamp_val(temp/1000, -128, 127);
- if (i2c_smbus_write_byte_data(client,
+ ret = i2c_smbus_write_byte_data(client,
MAX1668_REG_LIMH_WR(index),
- data->temp_max[index]))
- count = -EIO;
+ data->temp_max[index]);
+ if (ret < 0)
+ count = ret;
mutex_unlock(&data->update_lock);
return count;
@@ -230,8 +232,8 @@ static ssize_t set_temp_min(struct device *dev,
const char *buf, size_t count)
{
int index = to_sensor_dev_attr(devattr)->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct max1668_data *data = i2c_get_clientdata(client);
+ struct max1668_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
long temp;
int ret;
@@ -241,10 +243,11 @@ static ssize_t set_temp_min(struct device *dev,
mutex_lock(&data->update_lock);
data->temp_min[index] = clamp_val(temp/1000, -128, 127);
- if (i2c_smbus_write_byte_data(client,
+ ret = i2c_smbus_write_byte_data(client,
MAX1668_REG_LIML_WR(index),
- data->temp_max[index]))
- count = -EIO;
+ data->temp_min[index]);
+ if (ret < 0)
+ count = ret;
mutex_unlock(&data->update_lock);
return count;
@@ -405,60 +408,29 @@ static int max1668_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = client->adapter;
+ struct device *dev = &client->dev;
+ struct device *hwmon_dev;
struct max1668_data *data;
- int err;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- data = devm_kzalloc(&client->dev, sizeof(struct max1668_data),
- GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct max1668_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(client, data);
+ data->client = client;
data->type = id->driver_data;
mutex_init(&data->update_lock);
- /* Register sysfs hooks */
- err = sysfs_create_group(&client->dev.kobj, &max1668_group_common);
- if (err)
- return err;
-
- if (data->type == max1668 || data->type == max1989) {
- err = sysfs_create_group(&client->dev.kobj,
- &max1668_group_unique);
- if (err)
- goto error_sysrem0;
- }
-
- data->hwmon_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto error_sysrem1;
- }
-
- return 0;
-
-error_sysrem1:
+ /* sysfs hooks */
+ data->groups[0] = &max1668_group_common;
if (data->type == max1668 || data->type == max1989)
- sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
-error_sysrem0:
- sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
- return err;
-}
-
-static int max1668_remove(struct i2c_client *client)
-{
- struct max1668_data *data = i2c_get_clientdata(client);
+ data->groups[1] = &max1668_group_unique;
- hwmon_device_unregister(data->hwmon_dev);
- if (data->type == max1668 || data->type == max1989)
- sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
-
- sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data, data->groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id max1668_id[] = {
@@ -476,7 +448,6 @@ static struct i2c_driver max1668_driver = {
.name = "max1668",
},
.probe = max1668_probe,
- .remove = max1668_remove,
.id_table = max1668_id,
.detect = max1668_detect,
.address_list = max1668_addr_list,
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index 066e587a18a5..70650de2cbd1 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -80,7 +80,7 @@ static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 };
* Client data (each client gets its own)
*/
struct max6639_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -104,8 +104,8 @@ struct max6639_data {
static struct max6639_data *max6639_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
+ struct max6639_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
struct max6639_data *ret = data;
int i;
int status_reg;
@@ -191,9 +191,8 @@ static ssize_t show_temp_fault(struct device *dev,
static ssize_t show_temp_max(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", (data->temp_therm[attr->index] * 1000));
}
@@ -202,9 +201,9 @@ static ssize_t set_temp_max(struct device *dev,
struct device_attribute *dev_attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
int res;
@@ -224,9 +223,8 @@ static ssize_t set_temp_max(struct device *dev,
static ssize_t show_temp_crit(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", (data->temp_alert[attr->index] * 1000));
}
@@ -235,9 +233,9 @@ static ssize_t set_temp_crit(struct device *dev,
struct device_attribute *dev_attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
int res;
@@ -258,9 +256,8 @@ static ssize_t show_temp_emergency(struct device *dev,
struct device_attribute *dev_attr,
char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", (data->temp_ot[attr->index] * 1000));
}
@@ -269,9 +266,9 @@ static ssize_t set_temp_emergency(struct device *dev,
struct device_attribute *dev_attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
int res;
@@ -291,9 +288,8 @@ static ssize_t set_temp_emergency(struct device *dev,
static ssize_t show_pwm(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->pwm[attr->index] * 255 / 120);
}
@@ -302,9 +298,9 @@ static ssize_t set_pwm(struct device *dev,
struct device_attribute *dev_attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6639_data *data = i2c_get_clientdata(client);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ struct max6639_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long val;
int res;
@@ -378,7 +374,7 @@ static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO, show_alarm, NULL, 5);
static SENSOR_DEVICE_ATTR(temp2_emergency_alarm, S_IRUGO, show_alarm, NULL, 4);
-static struct attribute *max6639_attributes[] = {
+static struct attribute *max6639_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp1_fault.dev_attr.attr,
@@ -403,10 +399,7 @@ static struct attribute *max6639_attributes[] = {
&sensor_dev_attr_temp2_emergency_alarm.dev_attr.attr,
NULL
};
-
-static const struct attribute_group max6639_group = {
- .attrs = max6639_attributes,
-};
+ATTRIBUTE_GROUPS(max6639);
/*
* returns respective index in rpm_ranges table
@@ -424,9 +417,9 @@ static int rpm_range_to_reg(int range)
return 1; /* default: 4000 RPM */
}
-static int max6639_init_client(struct i2c_client *client)
+static int max6639_init_client(struct i2c_client *client,
+ struct max6639_data *data)
{
- struct max6639_data *data = i2c_get_clientdata(client);
struct max6639_platform_data *max6639_info =
dev_get_platdata(&client->dev);
int i;
@@ -545,50 +538,27 @@ static int max6639_detect(struct i2c_client *client,
static int max6639_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct device *dev = &client->dev;
struct max6639_data *data;
+ struct device *hwmon_dev;
int err;
- data = devm_kzalloc(&client->dev, sizeof(struct max6639_data),
- GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- i2c_set_clientdata(client, data);
+ data->client = client;
mutex_init(&data->update_lock);
/* Initialize the max6639 chip */
- err = max6639_init_client(client);
+ err = max6639_init_client(client, data);
if (err < 0)
return err;
- /* Register sysfs hooks */
- err = sysfs_create_group(&client->dev.kobj, &max6639_group);
- if (err)
- return err;
-
- data->hwmon_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- goto error_remove;
- }
-
- dev_info(&client->dev, "temperature sensor and fan control found\n");
-
- return 0;
-
-error_remove:
- sysfs_remove_group(&client->dev.kobj, &max6639_group);
- return err;
-}
-
-static int max6639_remove(struct i2c_client *client)
-{
- struct max6639_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &max6639_group);
-
- return 0;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data,
+ max6639_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
#ifdef CONFIG_PM_SLEEP
@@ -622,9 +592,7 @@ static const struct i2c_device_id max6639_id[] = {
MODULE_DEVICE_TABLE(i2c, max6639_id);
-static const struct dev_pm_ops max6639_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(max6639_suspend, max6639_resume)
-};
+static SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);
static struct i2c_driver max6639_driver = {
.class = I2C_CLASS_HWMON,
@@ -633,7 +601,6 @@ static struct i2c_driver max6639_driver = {
.pm = &max6639_pm_ops,
},
.probe = max6639_probe,
- .remove = max6639_remove,
.id_table = max6639_id,
.detect = max6639_detect,
.address_list = normal_i2c,
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index 0cafc390db4d..162a520f4bd6 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -105,38 +105,13 @@ module_param(clock, int, S_IRUGO);
#define DIV_FROM_REG(reg) (1 << (reg & 7))
-static int max6650_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
-static int max6650_init_client(struct i2c_client *client);
-static int max6650_remove(struct i2c_client *client);
-static struct max6650_data *max6650_update_device(struct device *dev);
-
-/*
- * Driver data (common to all clients)
- */
-
-static const struct i2c_device_id max6650_id[] = {
- { "max6650", 1 },
- { "max6651", 4 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, max6650_id);
-
-static struct i2c_driver max6650_driver = {
- .driver = {
- .name = "max6650",
- },
- .probe = max6650_probe,
- .remove = max6650_remove,
- .id_table = max6650_id,
-};
-
/*
* Client data (each client gets its own)
*/
struct max6650_data {
- struct device *hwmon_dev;
+ struct i2c_client *client;
+ const struct attribute_group *groups[3];
struct mutex update_lock;
int nr_fans;
char valid; /* zero until following fields are valid */
@@ -151,6 +126,51 @@ struct max6650_data {
u8 alarm;
};
+static const u8 tach_reg[] = {
+ MAX6650_REG_TACH0,
+ MAX6650_REG_TACH1,
+ MAX6650_REG_TACH2,
+ MAX6650_REG_TACH3,
+};
+
+static struct max6650_data *max6650_update_device(struct device *dev)
+{
+ struct max6650_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int i;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ data->speed = i2c_smbus_read_byte_data(client,
+ MAX6650_REG_SPEED);
+ data->config = i2c_smbus_read_byte_data(client,
+ MAX6650_REG_CONFIG);
+ for (i = 0; i < data->nr_fans; i++) {
+ data->tach[i] = i2c_smbus_read_byte_data(client,
+ tach_reg[i]);
+ }
+ data->count = i2c_smbus_read_byte_data(client,
+ MAX6650_REG_COUNT);
+ data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
+
+ /*
+ * Alarms are cleared on read in case the condition that
+ * caused the alarm is removed. Keep the value latched here
+ * for providing the register through different alarm files.
+ */
+ data->alarm |= i2c_smbus_read_byte_data(client,
+ MAX6650_REG_ALARM);
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
static ssize_t get_fan(struct device *dev, struct device_attribute *devattr,
char *buf)
{
@@ -235,8 +255,8 @@ static ssize_t get_target(struct device *dev, struct device_attribute *devattr,
static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6650_data *data = i2c_get_clientdata(client);
+ struct max6650_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
int kscale, ktach;
unsigned long rpm;
int err;
@@ -304,8 +324,8 @@ static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr,
static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6650_data *data = i2c_get_clientdata(client);
+ struct max6650_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long pwm;
int err;
@@ -350,8 +370,8 @@ static ssize_t get_enable(struct device *dev, struct device_attribute *devattr,
static ssize_t set_enable(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6650_data *data = i2c_get_clientdata(client);
+ struct max6650_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
int max6650_modes[3] = {0, 3, 2};
unsigned long mode;
int err;
@@ -400,8 +420,8 @@ static ssize_t get_div(struct device *dev, struct device_attribute *devattr,
static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct max6650_data *data = i2c_get_clientdata(client);
+ struct max6650_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
unsigned long div;
int err;
@@ -446,7 +466,7 @@ static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct max6650_data *data = max6650_update_device(dev);
- struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_client *client = data->client;
int alarm = 0;
if (data->alarm & attr->index) {
@@ -484,7 +504,8 @@ static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
- struct i2c_client *client = to_i2c_client(dev);
+ struct max6650_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
struct device_attribute *devattr;
@@ -519,7 +540,7 @@ static struct attribute *max6650_attrs[] = {
NULL
};
-static struct attribute_group max6650_attr_grp = {
+static const struct attribute_group max6650_group = {
.attrs = max6650_attrs,
.is_visible = max6650_attrs_visible,
};
@@ -531,7 +552,7 @@ static struct attribute *max6651_attrs[] = {
NULL
};
-static const struct attribute_group max6651_attr_grp = {
+static const struct attribute_group max6651_group = {
.attrs = max6651_attrs,
};
@@ -539,74 +560,17 @@ static const struct attribute_group max6651_attr_grp = {
* Real code
*/
-static int max6650_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct max6650_data *data;
- int err;
-
- data = devm_kzalloc(&client->dev, sizeof(struct max6650_data),
- GFP_KERNEL);
- if (!data) {
- dev_err(&client->dev, "out of memory.\n");
- return -ENOMEM;
- }
-
- i2c_set_clientdata(client, data);
- mutex_init(&data->update_lock);
- data->nr_fans = id->driver_data;
-
- /*
- * Initialize the max6650 chip
- */
- err = max6650_init_client(client);
- if (err)
- return err;
-
- err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);
- if (err)
- return err;
- /* 3 additional fan inputs for the MAX6651 */
- if (data->nr_fans == 4) {
- err = sysfs_create_group(&client->dev.kobj, &max6651_attr_grp);
- if (err)
- goto err_remove;
- }
-
- data->hwmon_dev = hwmon_device_register(&client->dev);
- if (!IS_ERR(data->hwmon_dev))
- return 0;
-
- err = PTR_ERR(data->hwmon_dev);
- dev_err(&client->dev, "error registering hwmon device.\n");
- if (data->nr_fans == 4)
- sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
-err_remove:
- sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
- return err;
-}
-
-static int max6650_remove(struct i2c_client *client)
+static int max6650_init_client(struct max6650_data *data,
+ struct i2c_client *client)
{
- struct max6650_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- if (data->nr_fans == 4)
- sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
- sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
- return 0;
-}
-
-static int max6650_init_client(struct i2c_client *client)
-{
- struct max6650_data *data = i2c_get_clientdata(client);
+ struct device *dev = &client->dev;
int config;
int err = -EIO;
config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
if (config < 0) {
- dev_err(&client->dev, "Error reading config, aborting.\n");
+ dev_err(dev, "Error reading config, aborting.\n");
return err;
}
@@ -620,11 +584,11 @@ static int max6650_init_client(struct i2c_client *client)
config |= MAX6650_CFG_V12;
break;
default:
- dev_err(&client->dev, "illegal value for fan_voltage (%d)\n",
+ dev_err(dev, "illegal value for fan_voltage (%d)\n",
fan_voltage);
}
- dev_info(&client->dev, "Fan voltage is set to %dV.\n",
+ dev_info(dev, "Fan voltage is set to %dV.\n",
(config & MAX6650_CFG_V12) ? 12 : 5);
switch (prescaler) {
@@ -650,11 +614,10 @@ static int max6650_init_client(struct i2c_client *client)
| MAX6650_CFG_PRESCALER_16;
break;
default:
- dev_err(&client->dev, "illegal value for prescaler (%d)\n",
- prescaler);
+ dev_err(dev, "illegal value for prescaler (%d)\n", prescaler);
}
- dev_info(&client->dev, "Prescaler is set to %d.\n",
+ dev_info(dev, "Prescaler is set to %d.\n",
1 << (config & MAX6650_CFG_PRESCALER_MASK));
/*
@@ -664,17 +627,17 @@ static int max6650_init_client(struct i2c_client *client)
*/
if ((config & MAX6650_CFG_MODE_MASK) == MAX6650_CFG_MODE_OFF) {
- dev_dbg(&client->dev, "Change mode to open loop, full off.\n");
+ dev_dbg(dev, "Change mode to open loop, full off.\n");
config = (config & ~MAX6650_CFG_MODE_MASK)
| MAX6650_CFG_MODE_OPEN_LOOP;
if (i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, 255)) {
- dev_err(&client->dev, "DAC write error, aborting.\n");
+ dev_err(dev, "DAC write error, aborting.\n");
return err;
}
}
if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) {
- dev_err(&client->dev, "Config write error, aborting.\n");
+ dev_err(dev, "Config write error, aborting.\n");
return err;
}
@@ -684,51 +647,55 @@ static int max6650_init_client(struct i2c_client *client)
return 0;
}
-static const u8 tach_reg[] = {
- MAX6650_REG_TACH0,
- MAX6650_REG_TACH1,
- MAX6650_REG_TACH2,
- MAX6650_REG_TACH3,
-};
-
-static struct max6650_data *max6650_update_device(struct device *dev)
+static int max6650_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- int i;
- struct i2c_client *client = to_i2c_client(dev);
- struct max6650_data *data = i2c_get_clientdata(client);
-
- mutex_lock(&data->update_lock);
+ struct device *dev = &client->dev;
+ struct max6650_data *data;
+ struct device *hwmon_dev;
+ int err;
- if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
- data->speed = i2c_smbus_read_byte_data(client,
- MAX6650_REG_SPEED);
- data->config = i2c_smbus_read_byte_data(client,
- MAX6650_REG_CONFIG);
- for (i = 0; i < data->nr_fans; i++) {
- data->tach[i] = i2c_smbus_read_byte_data(client,
- tach_reg[i]);
- }
- data->count = i2c_smbus_read_byte_data(client,
- MAX6650_REG_COUNT);
- data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
+ data = devm_kzalloc(dev, sizeof(struct max6650_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
- /*
- * Alarms are cleared on read in case the condition that
- * caused the alarm is removed. Keep the value latched here
- * for providing the register through different alarm files.
- */
- data->alarm |= i2c_smbus_read_byte_data(client,
- MAX6650_REG_ALARM);
+ data->client = client;
+ mutex_init(&data->update_lock);
+ data->nr_fans = id->driver_data;
- data->last_updated = jiffies;
- data->valid = 1;
- }
+ /*
+ * Initialize the max6650 chip
+ */
+ err = max6650_init_client(data, client);
+ if (err)
+ return err;
- mutex_unlock(&data->update_lock);
+ data->groups[0] = &max6650_group;
+ /* 3 additional fan inputs for the MAX6651 */
+ if (data->nr_fans == 4)
+ data->groups[1] = &max6651_group;
- return data;
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+ client->name, data,
+ data->groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
}
+static const struct i2c_device_id max6650_id[] = {
+ { "max6650", 1 },
+ { "max6651", 4 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max6650_id);
+
+static struct i2c_driver max6650_driver = {
+ .driver = {
+ .name = "max6650",
+ },
+ .probe = max6650_probe,
+ .id_table = max6650_id,
+};
+
module_i2c_driver(max6650_driver);
MODULE_AUTHOR("Hans J. Koch");
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
index de3c152a1d9a..e24ed521051a 100644
--- a/drivers/hwmon/pmbus/ltc2978.c
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -1,9 +1,9 @@
/*
* Hardware monitoring driver for LTC2974, LTC2977, LTC2978, LTC3880,
- * and LTC3883
+ * LTC3883, and LTM4676
*
* Copyright (c) 2011 Ericsson AB.
- * Copyright (c) 2013 Guenter Roeck
+ * Copyright (c) 2013, 2014 Guenter Roeck
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,10 +14,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 program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
@@ -28,7 +24,7 @@
#include <linux/i2c.h>
#include "pmbus.h"
-enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
+enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 };
/* Common for all chips */
#define LTC2978_MFR_VOUT_PEAK 0xdd
@@ -45,7 +41,7 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
#define LTC2974_MFR_IOUT_PEAK 0xd7
#define LTC2974_MFR_IOUT_MIN 0xd8
-/* LTC3880 and LTC3883 */
+/* LTC3880, LTC3883, and LTM4676 */
#define LTC3880_MFR_IOUT_PEAK 0xd7
#define LTC3880_MFR_CLEAR_PEAKS 0xe3
#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4
@@ -53,7 +49,8 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
/* LTC3883 only */
#define LTC3883_MFR_IIN_PEAK 0xe1
-#define LTC2974_ID 0x0212
+#define LTC2974_ID_REV1 0x0212
+#define LTC2974_ID_REV2 0x0213
#define LTC2977_ID 0x0130
#define LTC2978_ID_REV1 0x0121
#define LTC2978_ID_REV2 0x0122
@@ -62,6 +59,8 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 };
#define LTC3880_ID_MASK 0xff00
#define LTC3883_ID 0x4300
#define LTC3883_ID_MASK 0xff00
+#define LTM4676_ID 0x4480 /* datasheet claims 0x440X */
+#define LTM4676_ID_MASK 0xfff0
#define LTC2974_NUM_PAGES 4
#define LTC2978_NUM_PAGES 8
@@ -370,6 +369,7 @@ static const struct i2c_device_id ltc2978_id[] = {
{"ltc2978", ltc2978},
{"ltc3880", ltc3880},
{"ltc3883", ltc3883},
+ {"ltm4676", ltm4676},
{}
};
MODULE_DEVICE_TABLE(i2c, ltc2978_id);
@@ -394,7 +394,7 @@ static int ltc2978_probe(struct i2c_client *client,
if (chip_id < 0)
return chip_id;
- if (chip_id == LTC2974_ID) {
+ if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) {
data->id = ltc2974;
} else if (chip_id == LTC2977_ID) {
data->id = ltc2977;
@@ -405,6 +405,8 @@ static int ltc2978_probe(struct i2c_client *client,
data->id = ltc3880;
} else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) {
data->id = ltc3883;
+ } else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID) {
+ data->id = ltm4676;
} else {
dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
return -ENODEV;
@@ -458,6 +460,7 @@ static int ltc2978_probe(struct i2c_client *client,
}
break;
case ltc3880:
+ case ltm4676:
info->read_word_data = ltc3880_read_word_data;
info->pages = LTC3880_NUM_PAGES;
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
@@ -500,5 +503,5 @@ static struct i2c_driver ltc2978_driver = {
module_i2c_driver(ltc2978_driver);
MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, and LTC3883");
+MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, LTC3883, and LTM4676");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c
index d9e1b7de78da..4ef5802df6d8 100644
--- a/drivers/hwmon/smm665.c
+++ b/drivers/hwmon/smm665.c
@@ -222,7 +222,7 @@ static int smm665_read_adc(struct smm665_data *data, int adc)
rv = i2c_smbus_read_word_swapped(client, 0);
if (rv < 0) {
dev_dbg(&client->dev, "Failed to read ADC value: error %d", rv);
- return -1;
+ return rv;
}
/*
* Validate/verify readback adc channel (in bit 11..14).
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index f5ed03164d86..de17c5593d97 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -387,7 +387,7 @@ config I2C_CBUS_GPIO
config I2C_CPM
tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
- depends on (CPM1 || CPM2) && OF_I2C
+ depends on CPM1 || CPM2
help
This supports the use of the I2C interface on Freescale
processors with CPM1 or CPM2.
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index be7f0a20d634..f3b89a4698b6 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -39,7 +39,9 @@
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <sysdev/fsl_soc.h>
#include <asm/cpm.h>
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
index bfec313492b3..a7e68c81f89d 100644
--- a/drivers/iio/accel/bma180.c
+++ b/drivers/iio/accel/bma180.c
@@ -451,9 +451,9 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = {
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##_axis, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = AXIS_##_axis, \
.scan_type = { \
.sign = 's', \
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 2209f28441e9..4bf4c16de976 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -155,6 +155,16 @@ config MCP3422
This driver can also be built as a module. If so, the module will be
called mcp3422.
+config MEN_Z188_ADC
+ tristate "MEN 16z188 ADC IP Core support"
+ depends on MCB
+ help
+ Say yes here to enable support for the MEN 16z188 ADC IP-Core on a MCB
+ carrier.
+
+ This driver can also be built as a module. If so, the module will be
+ called men_z188_adc.
+
config NAU7802
tristate "Nuvoton NAU7802 ADC driver"
depends on I2C
@@ -197,6 +207,16 @@ config TWL6030_GPADC
This driver can also be built as a module. If so, the module will be
called twl6030-gpadc.
+config VF610_ADC
+ tristate "Freescale vf610 ADC driver"
+ depends on OF
+ help
+ Say yes here to support for Vybrid board analog-to-digital converter.
+ Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX.
+
+ This driver can also be built as a module. If so, the module will be
+ called vf610_adc.
+
config VIPERBOARD_ADC
tristate "Viperboard ADC support"
depends on MFD_VIPERBOARD && USB
@@ -204,4 +224,17 @@ config VIPERBOARD_ADC
Say yes here to access the ADC part of the Nano River
Technologies Viperboard.
+config XILINX_XADC
+ tristate "Xilinx XADC driver"
+ depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST
+ depends on HAS_IOMEM
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to have support for the Xilinx XADC. The driver does support
+ both the ZYNQ interface to the XADC as well as the AXI-XADC interface.
+
+ The driver can also be build as a module. If so, the module will be called
+ xilinx-xadc.
+
endmenu
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index ba9a10a24cd0..bb252540664a 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -17,8 +17,12 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
+obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
+obj-$(CONFIG_VF610_ADC) += vf610_adc.o
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
+xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o
+obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index 360259266d4f..9cf3229a7272 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -8,17 +8,11 @@
* based on linux/drivers/acron/char/pcf8583.c
* Copyright (C) 2000 Russell King
*
+ * Driver for max1363 and similar chips.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
- * max1363.c
- *
- * Partial support for max1363 and similar chips.
- *
- * Not currently implemented.
- *
- * - Control of internal reference.
*/
#include <linux/interrupt.h>
@@ -1253,7 +1247,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
},
[max11604] = {
.bits = 8,
- .int_vref_mv = 4098,
+ .int_vref_mv = 4096,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
@@ -1313,7 +1307,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
},
[max11610] = {
.bits = 10,
- .int_vref_mv = 4098,
+ .int_vref_mv = 4096,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
@@ -1373,7 +1367,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
},
[max11616] = {
.bits = 12,
- .int_vref_mv = 4098,
+ .int_vref_mv = 4096,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
diff --git a/drivers/iio/adc/men_z188_adc.c b/drivers/iio/adc/men_z188_adc.c
new file mode 100644
index 000000000000..6989c16aec2b
--- /dev/null
+++ b/drivers/iio/adc/men_z188_adc.c
@@ -0,0 +1,172 @@
+/*
+ * MEN 16z188 Analog to Digial Converter
+ *
+ * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
+ * Author: Johannes Thumshirn <johannes.thumshirn@men.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; version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mcb.h>
+#include <linux/io.h>
+#include <linux/iio/iio.h>
+
+#define Z188_ADC_MAX_CHAN 8
+#define Z188_ADC_GAIN 0x0700000
+#define Z188_MODE_VOLTAGE BIT(27)
+#define Z188_CFG_AUTO 0x1
+#define Z188_CTRL_REG 0x40
+
+#define ADC_DATA(x) (((x) >> 2) & 0x7ffffc)
+#define ADC_OVR(x) ((x) & 0x1)
+
+struct z188_adc {
+ struct resource *mem;
+ void __iomem *base;
+};
+
+#define Z188_ADC_CHANNEL(idx) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (idx), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+}
+
+static const struct iio_chan_spec z188_adc_iio_channels[] = {
+ Z188_ADC_CHANNEL(0),
+ Z188_ADC_CHANNEL(1),
+ Z188_ADC_CHANNEL(2),
+ Z188_ADC_CHANNEL(3),
+ Z188_ADC_CHANNEL(4),
+ Z188_ADC_CHANNEL(5),
+ Z188_ADC_CHANNEL(6),
+ Z188_ADC_CHANNEL(7),
+};
+
+static int z188_iio_read_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long info)
+{
+ struct z188_adc *adc = iio_priv(iio_dev);
+ int ret;
+ u16 tmp;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ tmp = readw(adc->base + chan->channel * 4);
+
+ if (ADC_OVR(tmp)) {
+ dev_info(&iio_dev->dev,
+ "Oversampling error on ADC channel %d\n",
+ chan->channel);
+ return -EIO;
+ }
+ *val = ADC_DATA(tmp);
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static struct iio_info z188_adc_info = {
+ .read_raw = &z188_iio_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static void men_z188_config_channels(void __iomem *addr)
+{
+ int i;
+ u32 cfg;
+ u32 ctl;
+
+ ctl = readl(addr + Z188_CTRL_REG);
+ ctl |= Z188_CFG_AUTO;
+ writel(ctl, addr + Z188_CTRL_REG);
+
+ for (i = 0; i < Z188_ADC_MAX_CHAN; i++) {
+ cfg = readl(addr + i);
+ cfg &= ~Z188_ADC_GAIN;
+ cfg |= Z188_MODE_VOLTAGE;
+ writel(cfg, addr + i);
+ }
+}
+
+static int men_z188_probe(struct mcb_device *dev,
+ const struct mcb_device_id *id)
+{
+ struct z188_adc *adc;
+ struct iio_dev *indio_dev;
+ struct resource *mem;
+
+ indio_dev = devm_iio_device_alloc(&dev->dev, sizeof(struct z188_adc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ adc = iio_priv(indio_dev);
+ indio_dev->name = "z188-adc";
+ indio_dev->dev.parent = &dev->dev;
+ indio_dev->info = &z188_adc_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = z188_adc_iio_channels;
+ indio_dev->num_channels = ARRAY_SIZE(z188_adc_iio_channels);
+
+ mem = mcb_request_mem(dev, "z188-adc");
+ if (!mem)
+ return -ENOMEM;
+
+ adc->base = ioremap(mem->start, resource_size(mem));
+ if (adc->base == NULL)
+ goto err;
+
+ men_z188_config_channels(adc->base);
+
+ adc->mem = mem;
+ mcb_set_drvdata(dev, indio_dev);
+
+ return iio_device_register(indio_dev);
+
+err:
+ mcb_release_mem(mem);
+ return -ENXIO;
+}
+
+static void men_z188_remove(struct mcb_device *dev)
+{
+ struct iio_dev *indio_dev = mcb_get_drvdata(dev);
+ struct z188_adc *adc = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iounmap(adc->base);
+ mcb_release_mem(adc->mem);
+}
+
+static const struct mcb_device_id men_z188_ids[] = {
+ { .device = 0xbc },
+};
+MODULE_DEVICE_TABLE(mcb, men_z188_ids);
+
+static struct mcb_driver men_z188_driver = {
+ .driver = {
+ .name = "z188-adc",
+ .owner = THIS_MODULE,
+ },
+ .probe = men_z188_probe,
+ .remove = men_z188_remove,
+ .id_table = men_z188_ids,
+};
+module_mcb_driver(men_z188_driver);
+
+MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IIO ADC driver for MEN 16z188 ADC Core");
+MODULE_ALIAS("mcb:16z188");
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index 31e786e3999b..a4db3026bec6 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -13,7 +13,6 @@
* GNU General Public License for more details.
*/
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/module.h>
diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c
index 53a24ebb92c3..15282f148b3b 100644
--- a/drivers/iio/adc/twl6030-gpadc.c
+++ b/drivers/iio/adc/twl6030-gpadc.c
@@ -28,7 +28,6 @@
* 02110-1301 USA
*
*/
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
new file mode 100644
index 000000000000..44799eb5930e
--- /dev/null
+++ b/drivers/iio/adc/vf610_adc.c
@@ -0,0 +1,711 @@
+/*
+ * Freescale Vybrid vf610 ADC driver
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_platform.h>
+#include <linux/err.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/driver.h>
+
+/* This will be the driver name the kernel reports */
+#define DRIVER_NAME "vf610-adc"
+
+/* Vybrid/IMX ADC registers */
+#define VF610_REG_ADC_HC0 0x00
+#define VF610_REG_ADC_HC1 0x04
+#define VF610_REG_ADC_HS 0x08
+#define VF610_REG_ADC_R0 0x0c
+#define VF610_REG_ADC_R1 0x10
+#define VF610_REG_ADC_CFG 0x14
+#define VF610_REG_ADC_GC 0x18
+#define VF610_REG_ADC_GS 0x1c
+#define VF610_REG_ADC_CV 0x20
+#define VF610_REG_ADC_OFS 0x24
+#define VF610_REG_ADC_CAL 0x28
+#define VF610_REG_ADC_PCTL 0x30
+
+/* Configuration register field define */
+#define VF610_ADC_MODE_BIT8 0x00
+#define VF610_ADC_MODE_BIT10 0x04
+#define VF610_ADC_MODE_BIT12 0x08
+#define VF610_ADC_MODE_MASK 0x0c
+#define VF610_ADC_BUSCLK2_SEL 0x01
+#define VF610_ADC_ALTCLK_SEL 0x02
+#define VF610_ADC_ADACK_SEL 0x03
+#define VF610_ADC_ADCCLK_MASK 0x03
+#define VF610_ADC_CLK_DIV2 0x20
+#define VF610_ADC_CLK_DIV4 0x40
+#define VF610_ADC_CLK_DIV8 0x60
+#define VF610_ADC_CLK_MASK 0x60
+#define VF610_ADC_ADLSMP_LONG 0x10
+#define VF610_ADC_ADSTS_MASK 0x300
+#define VF610_ADC_ADLPC_EN 0x80
+#define VF610_ADC_ADHSC_EN 0x400
+#define VF610_ADC_REFSEL_VALT 0x100
+#define VF610_ADC_REFSEL_VBG 0x1000
+#define VF610_ADC_ADTRG_HARD 0x2000
+#define VF610_ADC_AVGS_8 0x4000
+#define VF610_ADC_AVGS_16 0x8000
+#define VF610_ADC_AVGS_32 0xC000
+#define VF610_ADC_AVGS_MASK 0xC000
+#define VF610_ADC_OVWREN 0x10000
+
+/* General control register field define */
+#define VF610_ADC_ADACKEN 0x1
+#define VF610_ADC_DMAEN 0x2
+#define VF610_ADC_ACREN 0x4
+#define VF610_ADC_ACFGT 0x8
+#define VF610_ADC_ACFE 0x10
+#define VF610_ADC_AVGEN 0x20
+#define VF610_ADC_ADCON 0x40
+#define VF610_ADC_CAL 0x80
+
+/* Other field define */
+#define VF610_ADC_ADCHC(x) ((x) & 0xF)
+#define VF610_ADC_AIEN (0x1 << 7)
+#define VF610_ADC_CONV_DISABLE 0x1F
+#define VF610_ADC_HS_COCO0 0x1
+#define VF610_ADC_CALF 0x2
+#define VF610_ADC_TIMEOUT msecs_to_jiffies(100)
+
+enum clk_sel {
+ VF610_ADCIOC_BUSCLK_SET,
+ VF610_ADCIOC_ALTCLK_SET,
+ VF610_ADCIOC_ADACK_SET,
+};
+
+enum vol_ref {
+ VF610_ADCIOC_VR_VREF_SET,
+ VF610_ADCIOC_VR_VALT_SET,
+ VF610_ADCIOC_VR_VBG_SET,
+};
+
+enum average_sel {
+ VF610_ADC_SAMPLE_1,
+ VF610_ADC_SAMPLE_4,
+ VF610_ADC_SAMPLE_8,
+ VF610_ADC_SAMPLE_16,
+ VF610_ADC_SAMPLE_32,
+};
+
+struct vf610_adc_feature {
+ enum clk_sel clk_sel;
+ enum vol_ref vol_ref;
+
+ int clk_div;
+ int sample_rate;
+ int res_mode;
+
+ bool lpm;
+ bool calibration;
+ bool ovwren;
+};
+
+struct vf610_adc {
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *clk;
+
+ u32 vref_uv;
+ u32 value;
+ struct regulator *vref;
+ struct vf610_adc_feature adc_feature;
+
+ struct completion completion;
+};
+
+#define VF610_ADC_CHAN(_idx, _chan_type) { \
+ .type = (_chan_type), \
+ .indexed = 1, \
+ .channel = (_idx), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+}
+
+static const struct iio_chan_spec vf610_adc_iio_channels[] = {
+ VF610_ADC_CHAN(0, IIO_VOLTAGE),
+ VF610_ADC_CHAN(1, IIO_VOLTAGE),
+ VF610_ADC_CHAN(2, IIO_VOLTAGE),
+ VF610_ADC_CHAN(3, IIO_VOLTAGE),
+ VF610_ADC_CHAN(4, IIO_VOLTAGE),
+ VF610_ADC_CHAN(5, IIO_VOLTAGE),
+ VF610_ADC_CHAN(6, IIO_VOLTAGE),
+ VF610_ADC_CHAN(7, IIO_VOLTAGE),
+ VF610_ADC_CHAN(8, IIO_VOLTAGE),
+ VF610_ADC_CHAN(9, IIO_VOLTAGE),
+ VF610_ADC_CHAN(10, IIO_VOLTAGE),
+ VF610_ADC_CHAN(11, IIO_VOLTAGE),
+ VF610_ADC_CHAN(12, IIO_VOLTAGE),
+ VF610_ADC_CHAN(13, IIO_VOLTAGE),
+ VF610_ADC_CHAN(14, IIO_VOLTAGE),
+ VF610_ADC_CHAN(15, IIO_VOLTAGE),
+ /* sentinel */
+};
+
+/*
+ * ADC sample frequency, unit is ADCK cycles.
+ * ADC clk source is ipg clock, which is the same as bus clock.
+ *
+ * ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder)
+ * SFCAdder: fixed to 6 ADCK cycles
+ * AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
+ * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
+ * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
+ *
+ * By default, enable 12 bit resolution mode, clock source
+ * set to ipg clock, So get below frequency group:
+ */
+static const u32 vf610_sample_freq_avail[5] =
+{1941176, 559332, 286957, 145374, 73171};
+
+static inline void vf610_adc_cfg_init(struct vf610_adc *info)
+{
+ /* set default Configuration for ADC controller */
+ info->adc_feature.clk_sel = VF610_ADCIOC_BUSCLK_SET;
+ info->adc_feature.vol_ref = VF610_ADCIOC_VR_VREF_SET;
+
+ info->adc_feature.calibration = true;
+ info->adc_feature.ovwren = true;
+
+ info->adc_feature.clk_div = 1;
+ info->adc_feature.res_mode = 12;
+ info->adc_feature.sample_rate = 1;
+ info->adc_feature.lpm = true;
+}
+
+static void vf610_adc_cfg_post_set(struct vf610_adc *info)
+{
+ struct vf610_adc_feature *adc_feature = &info->adc_feature;
+ int cfg_data = 0;
+ int gc_data = 0;
+
+ switch (adc_feature->clk_sel) {
+ case VF610_ADCIOC_ALTCLK_SET:
+ cfg_data |= VF610_ADC_ALTCLK_SEL;
+ break;
+ case VF610_ADCIOC_ADACK_SET:
+ cfg_data |= VF610_ADC_ADACK_SEL;
+ break;
+ default:
+ break;
+ }
+
+ /* low power set for calibration */
+ cfg_data |= VF610_ADC_ADLPC_EN;
+
+ /* enable high speed for calibration */
+ cfg_data |= VF610_ADC_ADHSC_EN;
+
+ /* voltage reference */
+ switch (adc_feature->vol_ref) {
+ case VF610_ADCIOC_VR_VREF_SET:
+ break;
+ case VF610_ADCIOC_VR_VALT_SET:
+ cfg_data |= VF610_ADC_REFSEL_VALT;
+ break;
+ case VF610_ADCIOC_VR_VBG_SET:
+ cfg_data |= VF610_ADC_REFSEL_VBG;
+ break;
+ default:
+ dev_err(info->dev, "error voltage reference\n");
+ }
+
+ /* data overwrite enable */
+ if (adc_feature->ovwren)
+ cfg_data |= VF610_ADC_OVWREN;
+
+ writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
+ writel(gc_data, info->regs + VF610_REG_ADC_GC);
+}
+
+static void vf610_adc_calibration(struct vf610_adc *info)
+{
+ int adc_gc, hc_cfg;
+ int timeout;
+
+ if (!info->adc_feature.calibration)
+ return;
+
+ /* enable calibration interrupt */
+ hc_cfg = VF610_ADC_AIEN | VF610_ADC_CONV_DISABLE;
+ writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
+
+ adc_gc = readl(info->regs + VF610_REG_ADC_GC);
+ writel(adc_gc | VF610_ADC_CAL, info->regs + VF610_REG_ADC_GC);
+
+ timeout = wait_for_completion_timeout
+ (&info->completion, VF610_ADC_TIMEOUT);
+ if (timeout == 0)
+ dev_err(info->dev, "Timeout for adc calibration\n");
+
+ adc_gc = readl(info->regs + VF610_REG_ADC_GS);
+ if (adc_gc & VF610_ADC_CALF)
+ dev_err(info->dev, "ADC calibration failed\n");
+
+ info->adc_feature.calibration = false;
+}
+
+static void vf610_adc_cfg_set(struct vf610_adc *info)
+{
+ struct vf610_adc_feature *adc_feature = &(info->adc_feature);
+ int cfg_data;
+
+ cfg_data = readl(info->regs + VF610_REG_ADC_CFG);
+
+ /* low power configuration */
+ cfg_data &= ~VF610_ADC_ADLPC_EN;
+ if (adc_feature->lpm)
+ cfg_data |= VF610_ADC_ADLPC_EN;
+
+ /* disable high speed */
+ cfg_data &= ~VF610_ADC_ADHSC_EN;
+
+ writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
+}
+
+static void vf610_adc_sample_set(struct vf610_adc *info)
+{
+ struct vf610_adc_feature *adc_feature = &(info->adc_feature);
+ int cfg_data, gc_data;
+
+ cfg_data = readl(info->regs + VF610_REG_ADC_CFG);
+ gc_data = readl(info->regs + VF610_REG_ADC_GC);
+
+ /* resolution mode */
+ cfg_data &= ~VF610_ADC_MODE_MASK;
+ switch (adc_feature->res_mode) {
+ case 8:
+ cfg_data |= VF610_ADC_MODE_BIT8;
+ break;
+ case 10:
+ cfg_data |= VF610_ADC_MODE_BIT10;
+ break;
+ case 12:
+ cfg_data |= VF610_ADC_MODE_BIT12;
+ break;
+ default:
+ dev_err(info->dev, "error resolution mode\n");
+ break;
+ }
+
+ /* clock select and clock divider */
+ cfg_data &= ~(VF610_ADC_CLK_MASK | VF610_ADC_ADCCLK_MASK);
+ switch (adc_feature->clk_div) {
+ case 1:
+ break;
+ case 2:
+ cfg_data |= VF610_ADC_CLK_DIV2;
+ break;
+ case 4:
+ cfg_data |= VF610_ADC_CLK_DIV4;
+ break;
+ case 8:
+ cfg_data |= VF610_ADC_CLK_DIV8;
+ break;
+ case 16:
+ switch (adc_feature->clk_sel) {
+ case VF610_ADCIOC_BUSCLK_SET:
+ cfg_data |= VF610_ADC_BUSCLK2_SEL | VF610_ADC_CLK_DIV8;
+ break;
+ default:
+ dev_err(info->dev, "error clk divider\n");
+ break;
+ }
+ break;
+ }
+
+ /* Use the short sample mode */
+ cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK);
+
+ /* update hardware average selection */
+ cfg_data &= ~VF610_ADC_AVGS_MASK;
+ gc_data &= ~VF610_ADC_AVGEN;
+ switch (adc_feature->sample_rate) {
+ case VF610_ADC_SAMPLE_1:
+ break;
+ case VF610_ADC_SAMPLE_4:
+ gc_data |= VF610_ADC_AVGEN;
+ break;
+ case VF610_ADC_SAMPLE_8:
+ gc_data |= VF610_ADC_AVGEN;
+ cfg_data |= VF610_ADC_AVGS_8;
+ break;
+ case VF610_ADC_SAMPLE_16:
+ gc_data |= VF610_ADC_AVGEN;
+ cfg_data |= VF610_ADC_AVGS_16;
+ break;
+ case VF610_ADC_SAMPLE_32:
+ gc_data |= VF610_ADC_AVGEN;
+ cfg_data |= VF610_ADC_AVGS_32;
+ break;
+ default:
+ dev_err(info->dev,
+ "error hardware sample average select\n");
+ }
+
+ writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
+ writel(gc_data, info->regs + VF610_REG_ADC_GC);
+}
+
+static void vf610_adc_hw_init(struct vf610_adc *info)
+{
+ /* CFG: Feature set */
+ vf610_adc_cfg_post_set(info);
+ vf610_adc_sample_set(info);
+
+ /* adc calibration */
+ vf610_adc_calibration(info);
+
+ /* CFG: power and speed set */
+ vf610_adc_cfg_set(info);
+}
+
+static int vf610_adc_read_data(struct vf610_adc *info)
+{
+ int result;
+
+ result = readl(info->regs + VF610_REG_ADC_R0);
+
+ switch (info->adc_feature.res_mode) {
+ case 8:
+ result &= 0xFF;
+ break;
+ case 10:
+ result &= 0x3FF;
+ break;
+ case 12:
+ result &= 0xFFF;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
+{
+ struct vf610_adc *info = (struct vf610_adc *)dev_id;
+ int coco;
+
+ coco = readl(info->regs + VF610_REG_ADC_HS);
+ if (coco & VF610_ADC_HS_COCO0) {
+ info->value = vf610_adc_read_data(info);
+ complete(&info->completion);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("1941176, 559332, 286957, 145374, 73171");
+
+static struct attribute *vf610_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group vf610_attribute_group = {
+ .attrs = vf610_attributes,
+};
+
+static int vf610_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ struct vf610_adc *info = iio_priv(indio_dev);
+ unsigned int hc_cfg;
+ long ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+ reinit_completion(&info->completion);
+
+ hc_cfg = VF610_ADC_ADCHC(chan->channel);
+ hc_cfg |= VF610_ADC_AIEN;
+ writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
+ ret = wait_for_completion_interruptible_timeout
+ (&info->completion, VF610_ADC_TIMEOUT);
+ if (ret == 0) {
+ mutex_unlock(&indio_dev->mlock);
+ return -ETIMEDOUT;
+ }
+ if (ret < 0) {
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+ }
+
+ *val = info->value;
+ mutex_unlock(&indio_dev->mlock);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ *val = info->vref_uv / 1000;
+ *val2 = info->adc_feature.res_mode;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = vf610_sample_freq_avail[info->adc_feature.sample_rate];
+ *val2 = 0;
+ return IIO_VAL_INT;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int vf610_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct vf610_adc *info = iio_priv(indio_dev);
+ int i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ for (i = 0;
+ i < ARRAY_SIZE(vf610_sample_freq_avail);
+ i++)
+ if (val == vf610_sample_freq_avail[i]) {
+ info->adc_feature.sample_rate = i;
+ vf610_adc_sample_set(info);
+ return 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int vf610_adc_reg_access(struct iio_dev *indio_dev,
+ unsigned reg, unsigned writeval,
+ unsigned *readval)
+{
+ struct vf610_adc *info = iio_priv(indio_dev);
+
+ if ((readval == NULL) ||
+ (!(reg % 4) || (reg > VF610_REG_ADC_PCTL)))
+ return -EINVAL;
+
+ *readval = readl(info->regs + reg);
+
+ return 0;
+}
+
+static const struct iio_info vf610_adc_iio_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &vf610_read_raw,
+ .write_raw = &vf610_write_raw,
+ .debugfs_reg_access = &vf610_adc_reg_access,
+ .attrs = &vf610_attribute_group,
+};
+
+static const struct of_device_id vf610_adc_match[] = {
+ { .compatible = "fsl,vf610-adc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, vf610_adc_match);
+
+static int vf610_adc_probe(struct platform_device *pdev)
+{
+ struct vf610_adc *info;
+ struct iio_dev *indio_dev;
+ struct resource *mem;
+ int irq;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc));
+ if (!indio_dev) {
+ dev_err(&pdev->dev, "Failed allocating iio device\n");
+ return -ENOMEM;
+ }
+
+ info = iio_priv(indio_dev);
+ info->dev = &pdev->dev;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ info->regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(info->regs))
+ return PTR_ERR(info->regs);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return -EINVAL;
+ }
+
+ ret = devm_request_irq(info->dev, irq,
+ vf610_adc_isr, 0,
+ dev_name(&pdev->dev), info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq);
+ return ret;
+ }
+
+ info->clk = devm_clk_get(&pdev->dev, "adc");
+ if (IS_ERR(info->clk)) {
+ dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
+ PTR_ERR(info->clk));
+ ret = PTR_ERR(info->clk);
+ return ret;
+ }
+
+ info->vref = devm_regulator_get(&pdev->dev, "vref");
+ if (IS_ERR(info->vref))
+ return PTR_ERR(info->vref);
+
+ ret = regulator_enable(info->vref);
+ if (ret)
+ return ret;
+
+ info->vref_uv = regulator_get_voltage(info->vref);
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ init_completion(&info->completion);
+
+ indio_dev->name = dev_name(&pdev->dev);
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->dev.of_node = pdev->dev.of_node;
+ indio_dev->info = &vf610_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = vf610_adc_iio_channels;
+ indio_dev->num_channels = ARRAY_SIZE(vf610_adc_iio_channels);
+
+ ret = clk_prepare_enable(info->clk);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Could not prepare or enable the clock.\n");
+ goto error_adc_clk_enable;
+ }
+
+ vf610_adc_cfg_init(info);
+ vf610_adc_hw_init(info);
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't register the device.\n");
+ goto error_iio_device_register;
+ }
+
+ return 0;
+
+
+error_iio_device_register:
+ clk_disable_unprepare(info->clk);
+error_adc_clk_enable:
+ regulator_disable(info->vref);
+
+ return ret;
+}
+
+static int vf610_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct vf610_adc *info = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ regulator_disable(info->vref);
+ clk_disable_unprepare(info->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int vf610_adc_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct vf610_adc *info = iio_priv(indio_dev);
+ int hc_cfg;
+
+ /* ADC controller enters to stop mode */
+ hc_cfg = readl(info->regs + VF610_REG_ADC_HC0);
+ hc_cfg |= VF610_ADC_CONV_DISABLE;
+ writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
+
+ clk_disable_unprepare(info->clk);
+ regulator_disable(info->vref);
+
+ return 0;
+}
+
+static int vf610_adc_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct vf610_adc *info = iio_priv(indio_dev);
+ int ret;
+
+ ret = regulator_enable(info->vref);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(info->clk);
+ if (ret)
+ return ret;
+
+ vf610_adc_hw_init(info);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops,
+ vf610_adc_suspend,
+ vf610_adc_resume);
+
+static struct platform_driver vf610_adc_driver = {
+ .probe = vf610_adc_probe,
+ .remove = vf610_adc_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = vf610_adc_match,
+ .pm = &vf610_adc_pm_ops,
+ },
+};
+
+module_platform_driver(vf610_adc_driver);
+
+MODULE_AUTHOR("Fugang Duan <B38611@freescale.com>");
+MODULE_DESCRIPTION("Freescale VF610 ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c
index d0add8f9416b..9acf6b6d705b 100644
--- a/drivers/iio/adc/viperboard_adc.c
+++ b/drivers/iio/adc/viperboard_adc.c
@@ -139,8 +139,6 @@ static int vprbrd_adc_probe(struct platform_device *pdev)
return ret;
}
- platform_set_drvdata(pdev, indio_dev);
-
return 0;
}
diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c
new file mode 100644
index 000000000000..ab52be29141b
--- /dev/null
+++ b/drivers/iio/adc/xilinx-xadc-core.c
@@ -0,0 +1,1333 @@
+/*
+ * Xilinx XADC driver
+ *
+ * Copyright 2013-2014 Analog Devices Inc.
+ * Author: Lars-Peter Clauen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ *
+ * Documentation for the parts can be found at:
+ * - XADC hardmacro: Xilinx UG480
+ * - ZYNQ XADC interface: Xilinx UG585
+ * - AXI XADC interface: Xilinx PG019
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.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/slab.h>
+#include <linux/sysfs.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include "xilinx-xadc.h"
+
+static const unsigned int XADC_ZYNQ_UNMASK_TIMEOUT = 500;
+
+/* ZYNQ register definitions */
+#define XADC_ZYNQ_REG_CFG 0x00
+#define XADC_ZYNQ_REG_INTSTS 0x04
+#define XADC_ZYNQ_REG_INTMSK 0x08
+#define XADC_ZYNQ_REG_STATUS 0x0c
+#define XADC_ZYNQ_REG_CFIFO 0x10
+#define XADC_ZYNQ_REG_DFIFO 0x14
+#define XADC_ZYNQ_REG_CTL 0x18
+
+#define XADC_ZYNQ_CFG_ENABLE BIT(31)
+#define XADC_ZYNQ_CFG_CFIFOTH_MASK (0xf << 20)
+#define XADC_ZYNQ_CFG_CFIFOTH_OFFSET 20
+#define XADC_ZYNQ_CFG_DFIFOTH_MASK (0xf << 16)
+#define XADC_ZYNQ_CFG_DFIFOTH_OFFSET 16
+#define XADC_ZYNQ_CFG_WEDGE BIT(13)
+#define XADC_ZYNQ_CFG_REDGE BIT(12)
+#define XADC_ZYNQ_CFG_TCKRATE_MASK (0x3 << 8)
+#define XADC_ZYNQ_CFG_TCKRATE_DIV2 (0x0 << 8)
+#define XADC_ZYNQ_CFG_TCKRATE_DIV4 (0x1 << 8)
+#define XADC_ZYNQ_CFG_TCKRATE_DIV8 (0x2 << 8)
+#define XADC_ZYNQ_CFG_TCKRATE_DIV16 (0x3 << 8)
+#define XADC_ZYNQ_CFG_IGAP_MASK 0x1f
+#define XADC_ZYNQ_CFG_IGAP(x) (x)
+
+#define XADC_ZYNQ_INT_CFIFO_LTH BIT(9)
+#define XADC_ZYNQ_INT_DFIFO_GTH BIT(8)
+#define XADC_ZYNQ_INT_ALARM_MASK 0xff
+#define XADC_ZYNQ_INT_ALARM_OFFSET 0
+
+#define XADC_ZYNQ_STATUS_CFIFO_LVL_MASK (0xf << 16)
+#define XADC_ZYNQ_STATUS_CFIFO_LVL_OFFSET 16
+#define XADC_ZYNQ_STATUS_DFIFO_LVL_MASK (0xf << 12)
+#define XADC_ZYNQ_STATUS_DFIFO_LVL_OFFSET 12
+#define XADC_ZYNQ_STATUS_CFIFOF BIT(11)
+#define XADC_ZYNQ_STATUS_CFIFOE BIT(10)
+#define XADC_ZYNQ_STATUS_DFIFOF BIT(9)
+#define XADC_ZYNQ_STATUS_DFIFOE BIT(8)
+#define XADC_ZYNQ_STATUS_OT BIT(7)
+#define XADC_ZYNQ_STATUS_ALM(x) BIT(x)
+
+#define XADC_ZYNQ_CTL_RESET BIT(4)
+
+#define XADC_ZYNQ_CMD_NOP 0x00
+#define XADC_ZYNQ_CMD_READ 0x01
+#define XADC_ZYNQ_CMD_WRITE 0x02
+
+#define XADC_ZYNQ_CMD(cmd, addr, data) (((cmd) << 26) | ((addr) << 16) | (data))
+
+/* AXI register definitions */
+#define XADC_AXI_REG_RESET 0x00
+#define XADC_AXI_REG_STATUS 0x04
+#define XADC_AXI_REG_ALARM_STATUS 0x08
+#define XADC_AXI_REG_CONVST 0x0c
+#define XADC_AXI_REG_XADC_RESET 0x10
+#define XADC_AXI_REG_GIER 0x5c
+#define XADC_AXI_REG_IPISR 0x60
+#define XADC_AXI_REG_IPIER 0x68
+#define XADC_AXI_ADC_REG_OFFSET 0x200
+
+#define XADC_AXI_RESET_MAGIC 0xa
+#define XADC_AXI_GIER_ENABLE BIT(31)
+
+#define XADC_AXI_INT_EOS BIT(4)
+#define XADC_AXI_INT_ALARM_MASK 0x3c0f
+
+#define XADC_FLAGS_BUFFERED BIT(0)
+
+static void xadc_write_reg(struct xadc *xadc, unsigned int reg,
+ uint32_t val)
+{
+ writel(val, xadc->base + reg);
+}
+
+static void xadc_read_reg(struct xadc *xadc, unsigned int reg,
+ uint32_t *val)
+{
+ *val = readl(xadc->base + reg);
+}
+
+/*
+ * The ZYNQ interface uses two asynchronous FIFOs for communication with the
+ * XADC. Reads and writes to the XADC register are performed by submitting a
+ * request to the command FIFO (CFIFO), once the request has been completed the
+ * result can be read from the data FIFO (DFIFO). The method currently used in
+ * this driver is to submit the request for a read/write operation, then go to
+ * sleep and wait for an interrupt that signals that a response is available in
+ * the data FIFO.
+ */
+
+static void xadc_zynq_write_fifo(struct xadc *xadc, uint32_t *cmd,
+ unsigned int n)
+{
+ unsigned int i;
+
+ for (i = 0; i < n; i++)
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_CFIFO, cmd[i]);
+}
+
+static void xadc_zynq_drain_fifo(struct xadc *xadc)
+{
+ uint32_t status, tmp;
+
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &status);
+
+ while (!(status & XADC_ZYNQ_STATUS_DFIFOE)) {
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &tmp);
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &status);
+ }
+}
+
+static void xadc_zynq_update_intmsk(struct xadc *xadc, unsigned int mask,
+ unsigned int val)
+{
+ xadc->zynq_intmask &= ~mask;
+ xadc->zynq_intmask |= val;
+
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_INTMSK,
+ xadc->zynq_intmask | xadc->zynq_masked_alarm);
+}
+
+static int xadc_zynq_write_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t val)
+{
+ uint32_t cmd[1];
+ uint32_t tmp;
+ int ret;
+
+ spin_lock_irq(&xadc->lock);
+ xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH,
+ XADC_ZYNQ_INT_DFIFO_GTH);
+
+ reinit_completion(&xadc->completion);
+
+ cmd[0] = XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_WRITE, reg, val);
+ xadc_zynq_write_fifo(xadc, cmd, ARRAY_SIZE(cmd));
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &tmp);
+ tmp &= ~XADC_ZYNQ_CFG_DFIFOTH_MASK;
+ tmp |= 0 << XADC_ZYNQ_CFG_DFIFOTH_OFFSET;
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, tmp);
+
+ xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, 0);
+ spin_unlock_irq(&xadc->lock);
+
+ ret = wait_for_completion_interruptible_timeout(&xadc->completion, HZ);
+ if (ret == 0)
+ ret = -EIO;
+ else
+ ret = 0;
+
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &tmp);
+
+ return ret;
+}
+
+static int xadc_zynq_read_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t *val)
+{
+ uint32_t cmd[2];
+ uint32_t resp, tmp;
+ int ret;
+
+ cmd[0] = XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_READ, reg, 0);
+ cmd[1] = XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_NOP, 0, 0);
+
+ spin_lock_irq(&xadc->lock);
+ xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH,
+ XADC_ZYNQ_INT_DFIFO_GTH);
+ xadc_zynq_drain_fifo(xadc);
+ reinit_completion(&xadc->completion);
+
+ xadc_zynq_write_fifo(xadc, cmd, ARRAY_SIZE(cmd));
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &tmp);
+ tmp &= ~XADC_ZYNQ_CFG_DFIFOTH_MASK;
+ tmp |= 1 << XADC_ZYNQ_CFG_DFIFOTH_OFFSET;
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, tmp);
+
+ xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, 0);
+ spin_unlock_irq(&xadc->lock);
+ ret = wait_for_completion_interruptible_timeout(&xadc->completion, HZ);
+ if (ret == 0)
+ ret = -EIO;
+ if (ret < 0)
+ return ret;
+
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &resp);
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &resp);
+
+ *val = resp & 0xffff;
+
+ return 0;
+}
+
+static unsigned int xadc_zynq_transform_alarm(unsigned int alarm)
+{
+ return ((alarm & 0x80) >> 4) |
+ ((alarm & 0x78) << 1) |
+ (alarm & 0x07);
+}
+
+/*
+ * The ZYNQ threshold interrupts are level sensitive. Since we can't make the
+ * threshold condition go way from within the interrupt handler, this means as
+ * soon as a threshold condition is present we would enter the interrupt handler
+ * again and again. To work around this we mask all active thresholds interrupts
+ * in the interrupt handler and start a timer. In this timer we poll the
+ * interrupt status and only if the interrupt is inactive we unmask it again.
+ */
+static void xadc_zynq_unmask_worker(struct work_struct *work)
+{
+ struct xadc *xadc = container_of(work, struct xadc, zynq_unmask_work.work);
+ unsigned int misc_sts, unmask;
+
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &misc_sts);
+
+ misc_sts &= XADC_ZYNQ_INT_ALARM_MASK;
+
+ spin_lock_irq(&xadc->lock);
+
+ /* Clear those bits which are not active anymore */
+ unmask = (xadc->zynq_masked_alarm ^ misc_sts) & xadc->zynq_masked_alarm;
+ xadc->zynq_masked_alarm &= misc_sts;
+
+ /* Also clear those which are masked out anyway */
+ xadc->zynq_masked_alarm &= ~xadc->zynq_intmask;
+
+ /* Clear the interrupts before we unmask them */
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, unmask);
+
+ xadc_zynq_update_intmsk(xadc, 0, 0);
+
+ spin_unlock_irq(&xadc->lock);
+
+ /* if still pending some alarm re-trigger the timer */
+ if (xadc->zynq_masked_alarm) {
+ schedule_delayed_work(&xadc->zynq_unmask_work,
+ msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
+ }
+}
+
+static irqreturn_t xadc_zynq_threaded_interrupt_handler(int irq, void *devid)
+{
+ struct iio_dev *indio_dev = devid;
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned int alarm;
+
+ spin_lock_irq(&xadc->lock);
+ alarm = xadc->zynq_alarm;
+ xadc->zynq_alarm = 0;
+ spin_unlock_irq(&xadc->lock);
+
+ xadc_handle_events(indio_dev, xadc_zynq_transform_alarm(alarm));
+
+ /* unmask the required interrupts in timer. */
+ schedule_delayed_work(&xadc->zynq_unmask_work,
+ msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid)
+{
+ struct iio_dev *indio_dev = devid;
+ struct xadc *xadc = iio_priv(indio_dev);
+ irqreturn_t ret = IRQ_HANDLED;
+ uint32_t status;
+
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status);
+
+ status &= ~(xadc->zynq_intmask | xadc->zynq_masked_alarm);
+
+ if (!status)
+ return IRQ_NONE;
+
+ spin_lock(&xadc->lock);
+
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, status);
+
+ if (status & XADC_ZYNQ_INT_DFIFO_GTH) {
+ xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH,
+ XADC_ZYNQ_INT_DFIFO_GTH);
+ complete(&xadc->completion);
+ }
+
+ status &= XADC_ZYNQ_INT_ALARM_MASK;
+ if (status) {
+ xadc->zynq_alarm |= status;
+ xadc->zynq_masked_alarm |= status;
+ /*
+ * mask the current event interrupt,
+ * unmask it when the interrupt is no more active.
+ */
+ xadc_zynq_update_intmsk(xadc, 0, 0);
+ ret = IRQ_WAKE_THREAD;
+ }
+ spin_unlock(&xadc->lock);
+
+ return ret;
+}
+
+#define XADC_ZYNQ_TCK_RATE_MAX 50000000
+#define XADC_ZYNQ_IGAP_DEFAULT 20
+
+static int xadc_zynq_setup(struct platform_device *pdev,
+ struct iio_dev *indio_dev, int irq)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned long pcap_rate;
+ unsigned int tck_div;
+ unsigned int div;
+ unsigned int igap;
+ unsigned int tck_rate;
+
+ /* TODO: Figure out how to make igap and tck_rate configurable */
+ igap = XADC_ZYNQ_IGAP_DEFAULT;
+ tck_rate = XADC_ZYNQ_TCK_RATE_MAX;
+
+ xadc->zynq_intmask = ~0;
+
+ pcap_rate = clk_get_rate(xadc->clk);
+
+ if (tck_rate > XADC_ZYNQ_TCK_RATE_MAX)
+ tck_rate = XADC_ZYNQ_TCK_RATE_MAX;
+ if (tck_rate > pcap_rate / 2) {
+ div = 2;
+ } else {
+ div = pcap_rate / tck_rate;
+ if (pcap_rate / div > XADC_ZYNQ_TCK_RATE_MAX)
+ div++;
+ }
+
+ if (div <= 3)
+ tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV2;
+ else if (div <= 7)
+ tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV4;
+ else if (div <= 15)
+ tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV8;
+ else
+ tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV16;
+
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_CTL, XADC_ZYNQ_CTL_RESET);
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_CTL, 0);
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, ~0);
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_INTMSK, xadc->zynq_intmask);
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, XADC_ZYNQ_CFG_ENABLE |
+ XADC_ZYNQ_CFG_REDGE | XADC_ZYNQ_CFG_WEDGE |
+ tck_div | XADC_ZYNQ_CFG_IGAP(igap));
+
+ return 0;
+}
+
+static unsigned long xadc_zynq_get_dclk_rate(struct xadc *xadc)
+{
+ unsigned int div;
+ uint32_t val;
+
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &val);
+
+ switch (val & XADC_ZYNQ_CFG_TCKRATE_MASK) {
+ case XADC_ZYNQ_CFG_TCKRATE_DIV4:
+ div = 4;
+ break;
+ case XADC_ZYNQ_CFG_TCKRATE_DIV8:
+ div = 8;
+ break;
+ case XADC_ZYNQ_CFG_TCKRATE_DIV16:
+ div = 16;
+ break;
+ default:
+ div = 2;
+ break;
+ }
+
+ return clk_get_rate(xadc->clk) / div;
+}
+
+static void xadc_zynq_update_alarm(struct xadc *xadc, unsigned int alarm)
+{
+ unsigned long flags;
+ uint32_t status;
+
+ /* Move OT to bit 7 */
+ alarm = ((alarm & 0x08) << 4) | ((alarm & 0xf0) >> 1) | (alarm & 0x07);
+
+ spin_lock_irqsave(&xadc->lock, flags);
+
+ /* Clear previous interrupts if any. */
+ xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status);
+ xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, status & alarm);
+
+ xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_ALARM_MASK,
+ ~alarm & XADC_ZYNQ_INT_ALARM_MASK);
+
+ spin_unlock_irqrestore(&xadc->lock, flags);
+}
+
+static const struct xadc_ops xadc_zynq_ops = {
+ .read = xadc_zynq_read_adc_reg,
+ .write = xadc_zynq_write_adc_reg,
+ .setup = xadc_zynq_setup,
+ .get_dclk_rate = xadc_zynq_get_dclk_rate,
+ .interrupt_handler = xadc_zynq_interrupt_handler,
+ .threaded_interrupt_handler = xadc_zynq_threaded_interrupt_handler,
+ .update_alarm = xadc_zynq_update_alarm,
+};
+
+static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t *val)
+{
+ uint32_t val32;
+
+ xadc_read_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, &val32);
+ *val = val32 & 0xffff;
+
+ return 0;
+}
+
+static int xadc_axi_write_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t val)
+{
+ xadc_write_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, val);
+
+ return 0;
+}
+
+static int xadc_axi_setup(struct platform_device *pdev,
+ struct iio_dev *indio_dev, int irq)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+
+ xadc_write_reg(xadc, XADC_AXI_REG_RESET, XADC_AXI_RESET_MAGIC);
+ xadc_write_reg(xadc, XADC_AXI_REG_GIER, XADC_AXI_GIER_ENABLE);
+
+ return 0;
+}
+
+static irqreturn_t xadc_axi_interrupt_handler(int irq, void *devid)
+{
+ struct iio_dev *indio_dev = devid;
+ struct xadc *xadc = iio_priv(indio_dev);
+ uint32_t status, mask;
+ unsigned int events;
+
+ xadc_read_reg(xadc, XADC_AXI_REG_IPISR, &status);
+ xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &mask);
+ status &= mask;
+
+ if (!status)
+ return IRQ_NONE;
+
+ if ((status & XADC_AXI_INT_EOS) && xadc->trigger)
+ iio_trigger_poll(xadc->trigger, 0);
+
+ if (status & XADC_AXI_INT_ALARM_MASK) {
+ /*
+ * The order of the bits in the AXI-XADC status register does
+ * not match the order of the bits in the XADC alarm enable
+ * register. xadc_handle_events() expects the events to be in
+ * the same order as the XADC alarm enable register.
+ */
+ events = (status & 0x000e) >> 1;
+ events |= (status & 0x0001) << 3;
+ events |= (status & 0x3c00) >> 6;
+ xadc_handle_events(indio_dev, events);
+ }
+
+ xadc_write_reg(xadc, XADC_AXI_REG_IPISR, status);
+
+ return IRQ_HANDLED;
+}
+
+static void xadc_axi_update_alarm(struct xadc *xadc, unsigned int alarm)
+{
+ uint32_t val;
+ unsigned long flags;
+
+ /*
+ * The order of the bits in the AXI-XADC status register does not match
+ * the order of the bits in the XADC alarm enable register. We get
+ * passed the alarm mask in the same order as in the XADC alarm enable
+ * register.
+ */
+ alarm = ((alarm & 0x07) << 1) | ((alarm & 0x08) >> 3) |
+ ((alarm & 0xf0) << 6);
+
+ spin_lock_irqsave(&xadc->lock, flags);
+ xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &val);
+ val &= ~XADC_AXI_INT_ALARM_MASK;
+ val |= alarm;
+ xadc_write_reg(xadc, XADC_AXI_REG_IPIER, val);
+ spin_unlock_irqrestore(&xadc->lock, flags);
+}
+
+static unsigned long xadc_axi_get_dclk(struct xadc *xadc)
+{
+ return clk_get_rate(xadc->clk);
+}
+
+static const struct xadc_ops xadc_axi_ops = {
+ .read = xadc_axi_read_adc_reg,
+ .write = xadc_axi_write_adc_reg,
+ .setup = xadc_axi_setup,
+ .get_dclk_rate = xadc_axi_get_dclk,
+ .update_alarm = xadc_axi_update_alarm,
+ .interrupt_handler = xadc_axi_interrupt_handler,
+ .flags = XADC_FLAGS_BUFFERED,
+};
+
+static int _xadc_update_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t mask, uint16_t val)
+{
+ uint16_t tmp;
+ int ret;
+
+ ret = _xadc_read_adc_reg(xadc, reg, &tmp);
+ if (ret)
+ return ret;
+
+ return _xadc_write_adc_reg(xadc, reg, (tmp & ~mask) | val);
+}
+
+static int xadc_update_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t mask, uint16_t val)
+{
+ int ret;
+
+ mutex_lock(&xadc->mutex);
+ ret = _xadc_update_adc_reg(xadc, reg, mask, val);
+ mutex_unlock(&xadc->mutex);
+
+ return ret;
+}
+
+static unsigned long xadc_get_dclk_rate(struct xadc *xadc)
+{
+ return xadc->ops->get_dclk_rate(xadc);
+}
+
+static int xadc_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *mask)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned int n;
+
+ n = bitmap_weight(mask, indio_dev->masklength);
+
+ kfree(xadc->data);
+ xadc->data = kcalloc(n, sizeof(*xadc->data), GFP_KERNEL);
+ if (!xadc->data)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static unsigned int xadc_scan_index_to_channel(unsigned int scan_index)
+{
+ switch (scan_index) {
+ case 5:
+ return XADC_REG_VCCPINT;
+ case 6:
+ return XADC_REG_VCCPAUX;
+ case 7:
+ return XADC_REG_VCCO_DDR;
+ case 8:
+ return XADC_REG_TEMP;
+ case 9:
+ return XADC_REG_VCCINT;
+ case 10:
+ return XADC_REG_VCCAUX;
+ case 11:
+ return XADC_REG_VPVN;
+ case 12:
+ return XADC_REG_VREFP;
+ case 13:
+ return XADC_REG_VREFN;
+ case 14:
+ return XADC_REG_VCCBRAM;
+ default:
+ return XADC_REG_VAUX(scan_index - 16);
+ }
+}
+
+static irqreturn_t xadc_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned int chan;
+ int i, j;
+
+ if (!xadc->data)
+ goto out;
+
+ j = 0;
+ for_each_set_bit(i, indio_dev->active_scan_mask,
+ indio_dev->masklength) {
+ chan = xadc_scan_index_to_channel(i);
+ xadc_read_adc_reg(xadc, chan, &xadc->data[j]);
+ j++;
+ }
+
+ iio_push_to_buffers(indio_dev, xadc->data);
+
+out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int xadc_trigger_set_state(struct iio_trigger *trigger, bool state)
+{
+ struct xadc *xadc = iio_trigger_get_drvdata(trigger);
+ unsigned long flags;
+ unsigned int convst;
+ unsigned int val;
+ int ret = 0;
+
+ mutex_lock(&xadc->mutex);
+
+ if (state) {
+ /* Only one of the two triggers can be active at the a time. */
+ if (xadc->trigger != NULL) {
+ ret = -EBUSY;
+ goto err_out;
+ } else {
+ xadc->trigger = trigger;
+ if (trigger == xadc->convst_trigger)
+ convst = XADC_CONF0_EC;
+ else
+ convst = 0;
+ }
+ ret = _xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF0_EC,
+ convst);
+ if (ret)
+ goto err_out;
+ } else {
+ xadc->trigger = NULL;
+ }
+
+ spin_lock_irqsave(&xadc->lock, flags);
+ xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &val);
+ xadc_write_reg(xadc, XADC_AXI_REG_IPISR, val & XADC_AXI_INT_EOS);
+ if (state)
+ val |= XADC_AXI_INT_EOS;
+ else
+ val &= ~XADC_AXI_INT_EOS;
+ xadc_write_reg(xadc, XADC_AXI_REG_IPIER, val);
+ spin_unlock_irqrestore(&xadc->lock, flags);
+
+err_out:
+ mutex_unlock(&xadc->mutex);
+
+ return ret;
+}
+
+static const struct iio_trigger_ops xadc_trigger_ops = {
+ .owner = THIS_MODULE,
+ .set_trigger_state = &xadc_trigger_set_state,
+};
+
+static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev,
+ const char *name)
+{
+ struct iio_trigger *trig;
+ int ret;
+
+ trig = iio_trigger_alloc("%s%d-%s", indio_dev->name,
+ indio_dev->id, name);
+ if (trig == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ trig->dev.parent = indio_dev->dev.parent;
+ trig->ops = &xadc_trigger_ops;
+ iio_trigger_set_drvdata(trig, iio_priv(indio_dev));
+
+ ret = iio_trigger_register(trig);
+ if (ret)
+ goto error_free_trig;
+
+ return trig;
+
+error_free_trig:
+ iio_trigger_free(trig);
+ return ERR_PTR(ret);
+}
+
+static int xadc_power_adc_b(struct xadc *xadc, unsigned int seq_mode)
+{
+ uint16_t val;
+
+ switch (seq_mode) {
+ case XADC_CONF1_SEQ_SIMULTANEOUS:
+ case XADC_CONF1_SEQ_INDEPENDENT:
+ val = XADC_CONF2_PD_ADC_B;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+
+ return xadc_update_adc_reg(xadc, XADC_REG_CONF2, XADC_CONF2_PD_MASK,
+ val);
+}
+
+static int xadc_get_seq_mode(struct xadc *xadc, unsigned long scan_mode)
+{
+ unsigned int aux_scan_mode = scan_mode >> 16;
+
+ if (xadc->external_mux_mode == XADC_EXTERNAL_MUX_DUAL)
+ return XADC_CONF1_SEQ_SIMULTANEOUS;
+
+ if ((aux_scan_mode & 0xff00) == 0 ||
+ (aux_scan_mode & 0x00ff) == 0)
+ return XADC_CONF1_SEQ_CONTINUOUS;
+
+ return XADC_CONF1_SEQ_SIMULTANEOUS;
+}
+
+static int xadc_postdisable(struct iio_dev *indio_dev)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned long scan_mask;
+ int ret;
+ int i;
+
+ scan_mask = 1; /* Run calibration as part of the sequence */
+ for (i = 0; i < indio_dev->num_channels; i++)
+ scan_mask |= BIT(indio_dev->channels[i].scan_index);
+
+ /* Enable all channels and calibration */
+ ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(0), scan_mask & 0xffff);
+ if (ret)
+ return ret;
+
+ ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(1), scan_mask >> 16);
+ if (ret)
+ return ret;
+
+ ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK,
+ XADC_CONF1_SEQ_CONTINUOUS);
+ if (ret)
+ return ret;
+
+ return xadc_power_adc_b(xadc, XADC_CONF1_SEQ_CONTINUOUS);
+}
+
+static int xadc_preenable(struct iio_dev *indio_dev)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned long scan_mask;
+ int seq_mode;
+ int ret;
+
+ ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK,
+ XADC_CONF1_SEQ_DEFAULT);
+ if (ret)
+ goto err;
+
+ scan_mask = *indio_dev->active_scan_mask;
+ seq_mode = xadc_get_seq_mode(xadc, scan_mask);
+
+ ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(0), scan_mask & 0xffff);
+ if (ret)
+ goto err;
+
+ ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(1), scan_mask >> 16);
+ if (ret)
+ goto err;
+
+ ret = xadc_power_adc_b(xadc, seq_mode);
+ if (ret)
+ goto err;
+
+ ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK,
+ seq_mode);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ xadc_postdisable(indio_dev);
+ return ret;
+}
+
+static struct iio_buffer_setup_ops xadc_buffer_ops = {
+ .preenable = &xadc_preenable,
+ .postenable = &iio_triggered_buffer_postenable,
+ .predisable = &iio_triggered_buffer_predisable,
+ .postdisable = &xadc_postdisable,
+};
+
+static int xadc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2, long info)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned int div;
+ uint16_t val16;
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+ ret = xadc_read_adc_reg(xadc, chan->address, &val16);
+ if (ret < 0)
+ return ret;
+
+ val16 >>= 4;
+ if (chan->scan_type.sign == 'u')
+ *val = val16;
+ else
+ *val = sign_extend32(val16, 11);
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ /* V = (val * 3.0) / 4096 */
+ switch (chan->address) {
+ case XADC_REG_VCCINT:
+ case XADC_REG_VCCAUX:
+ case XADC_REG_VCCBRAM:
+ case XADC_REG_VCCPINT:
+ case XADC_REG_VCCPAUX:
+ case XADC_REG_VCCO_DDR:
+ *val = 3000;
+ break;
+ default:
+ *val = 1000;
+ break;
+ }
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_TEMP:
+ /* Temp in C = (val * 503.975) / 4096 - 273.15 */
+ *val = 503975;
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OFFSET:
+ /* Only the temperature channel has an offset */
+ *val = -((273150 << 12) / 503975);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = xadc_read_adc_reg(xadc, XADC_REG_CONF2, &val16);
+ if (ret)
+ return ret;
+
+ div = (val16 & XADC_CONF2_DIV_MASK) >> XADC_CONF2_DIV_OFFSET;
+ if (div < 2)
+ div = 2;
+
+ *val = xadc_get_dclk_rate(xadc) / div / 26;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int xadc_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2, long info)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ unsigned long clk_rate = xadc_get_dclk_rate(xadc);
+ unsigned int div;
+
+ if (info != IIO_CHAN_INFO_SAMP_FREQ)
+ return -EINVAL;
+
+ if (val <= 0)
+ return -EINVAL;
+
+ /* Max. 150 kSPS */
+ if (val > 150000)
+ val = 150000;
+
+ val *= 26;
+
+ /* Min 1MHz */
+ if (val < 1000000)
+ val = 1000000;
+
+ /*
+ * We want to round down, but only if we do not exceed the 150 kSPS
+ * limit.
+ */
+ div = clk_rate / val;
+ if (clk_rate / div / 26 > 150000)
+ div++;
+ if (div < 2)
+ div = 2;
+ else if (div > 0xff)
+ div = 0xff;
+
+ return xadc_update_adc_reg(xadc, XADC_REG_CONF2, XADC_CONF2_DIV_MASK,
+ div << XADC_CONF2_DIV_OFFSET);
+}
+
+static const struct iio_event_spec xadc_temp_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_HYSTERESIS),
+ },
+};
+
+/* Separate values for upper and lower thresholds, but only a shared enabled */
+static const struct iio_event_spec xadc_voltage_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ }, {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ }, {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+#define XADC_CHAN_TEMP(_chan, _scan_index, _addr) { \
+ .type = IIO_TEMP, \
+ .indexed = 1, \
+ .channel = (_chan), \
+ .address = (_addr), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .event_spec = xadc_temp_events, \
+ .num_event_specs = ARRAY_SIZE(xadc_temp_events), \
+ .scan_index = (_scan_index), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ .shift = 4, \
+ .endianness = IIO_CPU, \
+ }, \
+}
+
+#define XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, _ext, _alarm) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_chan), \
+ .address = (_addr), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .event_spec = (_alarm) ? xadc_voltage_events : NULL, \
+ .num_event_specs = (_alarm) ? ARRAY_SIZE(xadc_voltage_events) : 0, \
+ .scan_index = (_scan_index), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ .shift = 4, \
+ .endianness = IIO_CPU, \
+ }, \
+ .extend_name = _ext, \
+}
+
+static const struct iio_chan_spec xadc_channels[] = {
+ XADC_CHAN_TEMP(0, 8, XADC_REG_TEMP),
+ XADC_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true),
+ XADC_CHAN_VOLTAGE(1, 10, XADC_REG_VCCINT, "vccaux", true),
+ XADC_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true),
+ XADC_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpint", true),
+ XADC_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpaux", true),
+ XADC_CHAN_VOLTAGE(5, 7, XADC_REG_VCCO_DDR, "vccoddr", true),
+ XADC_CHAN_VOLTAGE(6, 12, XADC_REG_VREFP, "vrefp", false),
+ XADC_CHAN_VOLTAGE(7, 13, XADC_REG_VREFN, "vrefn", false),
+ XADC_CHAN_VOLTAGE(8, 11, XADC_REG_VPVN, NULL, false),
+ XADC_CHAN_VOLTAGE(9, 16, XADC_REG_VAUX(0), NULL, false),
+ XADC_CHAN_VOLTAGE(10, 17, XADC_REG_VAUX(1), NULL, false),
+ XADC_CHAN_VOLTAGE(11, 18, XADC_REG_VAUX(2), NULL, false),
+ XADC_CHAN_VOLTAGE(12, 19, XADC_REG_VAUX(3), NULL, false),
+ XADC_CHAN_VOLTAGE(13, 20, XADC_REG_VAUX(4), NULL, false),
+ XADC_CHAN_VOLTAGE(14, 21, XADC_REG_VAUX(5), NULL, false),
+ XADC_CHAN_VOLTAGE(15, 22, XADC_REG_VAUX(6), NULL, false),
+ XADC_CHAN_VOLTAGE(16, 23, XADC_REG_VAUX(7), NULL, false),
+ XADC_CHAN_VOLTAGE(17, 24, XADC_REG_VAUX(8), NULL, false),
+ XADC_CHAN_VOLTAGE(18, 25, XADC_REG_VAUX(9), NULL, false),
+ XADC_CHAN_VOLTAGE(19, 26, XADC_REG_VAUX(10), NULL, false),
+ XADC_CHAN_VOLTAGE(20, 27, XADC_REG_VAUX(11), NULL, false),
+ XADC_CHAN_VOLTAGE(21, 28, XADC_REG_VAUX(12), NULL, false),
+ XADC_CHAN_VOLTAGE(22, 29, XADC_REG_VAUX(13), NULL, false),
+ XADC_CHAN_VOLTAGE(23, 30, XADC_REG_VAUX(14), NULL, false),
+ XADC_CHAN_VOLTAGE(24, 31, XADC_REG_VAUX(15), NULL, false),
+};
+
+static const struct iio_info xadc_info = {
+ .read_raw = &xadc_read_raw,
+ .write_raw = &xadc_write_raw,
+ .read_event_config = &xadc_read_event_config,
+ .write_event_config = &xadc_write_event_config,
+ .read_event_value = &xadc_read_event_value,
+ .write_event_value = &xadc_write_event_value,
+ .update_scan_mode = &xadc_update_scan_mode,
+ .driver_module = THIS_MODULE,
+};
+
+static const struct of_device_id xadc_of_match_table[] = {
+ { .compatible = "xlnx,zynq-xadc-1.00.a", (void *)&xadc_zynq_ops },
+ { .compatible = "xlnx,axi-xadc-1.00.a", (void *)&xadc_axi_ops },
+ { },
+};
+MODULE_DEVICE_TABLE(of, xadc_of_match_table);
+
+static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
+ unsigned int *conf)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+ struct iio_chan_spec *channels, *chan;
+ struct device_node *chan_node, *child;
+ unsigned int num_channels;
+ const char *external_mux;
+ u32 ext_mux_chan;
+ int reg;
+ int ret;
+
+ *conf = 0;
+
+ ret = of_property_read_string(np, "xlnx,external-mux", &external_mux);
+ if (ret < 0 || strcasecmp(external_mux, "none") == 0)
+ xadc->external_mux_mode = XADC_EXTERNAL_MUX_NONE;
+ else if (strcasecmp(external_mux, "single") == 0)
+ xadc->external_mux_mode = XADC_EXTERNAL_MUX_SINGLE;
+ else if (strcasecmp(external_mux, "dual") == 0)
+ xadc->external_mux_mode = XADC_EXTERNAL_MUX_DUAL;
+ else
+ return -EINVAL;
+
+ if (xadc->external_mux_mode != XADC_EXTERNAL_MUX_NONE) {
+ ret = of_property_read_u32(np, "xlnx,external-mux-channel",
+ &ext_mux_chan);
+ if (ret < 0)
+ return ret;
+
+ if (xadc->external_mux_mode == XADC_EXTERNAL_MUX_SINGLE) {
+ if (ext_mux_chan == 0)
+ ext_mux_chan = XADC_REG_VPVN;
+ else if (ext_mux_chan <= 16)
+ ext_mux_chan = XADC_REG_VAUX(ext_mux_chan - 1);
+ else
+ return -EINVAL;
+ } else {
+ if (ext_mux_chan > 0 && ext_mux_chan <= 8)
+ ext_mux_chan = XADC_REG_VAUX(ext_mux_chan - 1);
+ else
+ return -EINVAL;
+ }
+
+ *conf |= XADC_CONF0_MUX | XADC_CONF0_CHAN(ext_mux_chan);
+ }
+
+ channels = kmemdup(xadc_channels, sizeof(xadc_channels), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ num_channels = 9;
+ chan = &channels[9];
+
+ chan_node = of_get_child_by_name(np, "xlnx,channels");
+ if (chan_node) {
+ for_each_child_of_node(chan_node, child) {
+ if (num_channels >= ARRAY_SIZE(xadc_channels)) {
+ of_node_put(child);
+ break;
+ }
+
+ ret = of_property_read_u32(child, "reg", &reg);
+ if (ret || reg > 16)
+ continue;
+
+ if (of_property_read_bool(child, "xlnx,bipolar"))
+ chan->scan_type.sign = 's';
+
+ if (reg == 0) {
+ chan->scan_index = 11;
+ chan->address = XADC_REG_VPVN;
+ } else {
+ chan->scan_index = 15 + reg;
+ chan->scan_index = XADC_REG_VAUX(reg - 1);
+ }
+ num_channels++;
+ chan++;
+ }
+ }
+ of_node_put(chan_node);
+
+ indio_dev->num_channels = num_channels;
+ indio_dev->channels = krealloc(channels, sizeof(*channels) *
+ num_channels, GFP_KERNEL);
+ /* If we can't resize the channels array, just use the original */
+ if (!indio_dev->channels)
+ indio_dev->channels = channels;
+
+ return 0;
+}
+
+static int xadc_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *id;
+ struct iio_dev *indio_dev;
+ unsigned int bipolar_mask;
+ struct resource *mem;
+ unsigned int conf0;
+ struct xadc *xadc;
+ int ret;
+ int irq;
+ int i;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ id = of_match_node(xadc_of_match_table, pdev->dev.of_node);
+ if (!id)
+ return -EINVAL;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0)
+ return -ENXIO;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*xadc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ xadc = iio_priv(indio_dev);
+ xadc->ops = id->data;
+ init_completion(&xadc->completion);
+ mutex_init(&xadc->mutex);
+ spin_lock_init(&xadc->lock);
+ INIT_DELAYED_WORK(&xadc->zynq_unmask_work, xadc_zynq_unmask_worker);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xadc->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(xadc->base))
+ return PTR_ERR(xadc->base);
+
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->dev.of_node = pdev->dev.of_node;
+ indio_dev->name = "xadc";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &xadc_info;
+
+ ret = xadc_parse_dt(indio_dev, pdev->dev.of_node, &conf0);
+ if (ret)
+ goto err_device_free;
+
+ if (xadc->ops->flags & XADC_FLAGS_BUFFERED) {
+ ret = iio_triggered_buffer_setup(indio_dev,
+ &iio_pollfunc_store_time, &xadc_trigger_handler,
+ &xadc_buffer_ops);
+ if (ret)
+ goto err_device_free;
+
+ xadc->convst_trigger = xadc_alloc_trigger(indio_dev, "convst");
+ if (IS_ERR(xadc->convst_trigger))
+ goto err_triggered_buffer_cleanup;
+ xadc->samplerate_trigger = xadc_alloc_trigger(indio_dev,
+ "samplerate");
+ if (IS_ERR(xadc->samplerate_trigger))
+ goto err_free_convst_trigger;
+ }
+
+ xadc->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(xadc->clk)) {
+ ret = PTR_ERR(xadc->clk);
+ goto err_free_samplerate_trigger;
+ }
+ clk_prepare_enable(xadc->clk);
+
+ ret = xadc->ops->setup(pdev, indio_dev, irq);
+ if (ret)
+ goto err_free_samplerate_trigger;
+
+ ret = request_threaded_irq(irq, xadc->ops->interrupt_handler,
+ xadc->ops->threaded_interrupt_handler,
+ 0, dev_name(&pdev->dev), indio_dev);
+ if (ret)
+ goto err_clk_disable_unprepare;
+
+ for (i = 0; i < 16; i++)
+ xadc_read_adc_reg(xadc, XADC_REG_THRESHOLD(i),
+ &xadc->threshold[i]);
+
+ ret = xadc_write_adc_reg(xadc, XADC_REG_CONF0, conf0);
+ if (ret)
+ goto err_free_irq;
+
+ bipolar_mask = 0;
+ for (i = 0; i < indio_dev->num_channels; i++) {
+ if (indio_dev->channels[i].scan_type.sign == 's')
+ bipolar_mask |= BIT(indio_dev->channels[i].scan_index);
+ }
+
+ ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(0), bipolar_mask);
+ if (ret)
+ goto err_free_irq;
+ ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(1),
+ bipolar_mask >> 16);
+ if (ret)
+ goto err_free_irq;
+
+ /* Disable all alarms */
+ xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK,
+ XADC_CONF1_ALARM_MASK);
+
+ /* Set thresholds to min/max */
+ for (i = 0; i < 16; i++) {
+ /*
+ * Set max voltage threshold and both temperature thresholds to
+ * 0xffff, min voltage threshold to 0.
+ */
+ if (i % 8 < 4 || i == 7)
+ xadc->threshold[i] = 0xffff;
+ else
+ xadc->threshold[i] = 0;
+ xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(i),
+ xadc->threshold[i]);
+ }
+
+ /* Go to non-buffered mode */
+ xadc_postdisable(indio_dev);
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto err_free_irq;
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ return 0;
+
+err_free_irq:
+ free_irq(irq, indio_dev);
+err_free_samplerate_trigger:
+ if (xadc->ops->flags & XADC_FLAGS_BUFFERED)
+ iio_trigger_free(xadc->samplerate_trigger);
+err_free_convst_trigger:
+ if (xadc->ops->flags & XADC_FLAGS_BUFFERED)
+ iio_trigger_free(xadc->convst_trigger);
+err_triggered_buffer_cleanup:
+ if (xadc->ops->flags & XADC_FLAGS_BUFFERED)
+ iio_triggered_buffer_cleanup(indio_dev);
+err_clk_disable_unprepare:
+ clk_disable_unprepare(xadc->clk);
+err_device_free:
+ kfree(indio_dev->channels);
+
+ return ret;
+}
+
+static int xadc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct xadc *xadc = iio_priv(indio_dev);
+ int irq = platform_get_irq(pdev, 0);
+
+ iio_device_unregister(indio_dev);
+ if (xadc->ops->flags & XADC_FLAGS_BUFFERED) {
+ iio_trigger_free(xadc->samplerate_trigger);
+ iio_trigger_free(xadc->convst_trigger);
+ iio_triggered_buffer_cleanup(indio_dev);
+ }
+ free_irq(irq, indio_dev);
+ clk_disable_unprepare(xadc->clk);
+ cancel_delayed_work(&xadc->zynq_unmask_work);
+ kfree(xadc->data);
+ kfree(indio_dev->channels);
+
+ return 0;
+}
+
+static struct platform_driver xadc_driver = {
+ .probe = xadc_probe,
+ .remove = xadc_remove,
+ .driver = {
+ .name = "xadc",
+ .owner = THIS_MODULE,
+ .of_match_table = xadc_of_match_table,
+ },
+};
+module_platform_driver(xadc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Xilinx XADC IIO driver");
diff --git a/drivers/iio/adc/xilinx-xadc-events.c b/drivers/iio/adc/xilinx-xadc-events.c
new file mode 100644
index 000000000000..3e7f0d7a80c3
--- /dev/null
+++ b/drivers/iio/adc/xilinx-xadc-events.c
@@ -0,0 +1,254 @@
+/*
+ * Xilinx XADC driver
+ *
+ * Copyright 2013 Analog Devices Inc.
+ * Author: Lars-Peter Clauen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+
+#include "xilinx-xadc.h"
+
+static const struct iio_chan_spec *xadc_event_to_channel(
+ struct iio_dev *indio_dev, unsigned int event)
+{
+ switch (event) {
+ case XADC_THRESHOLD_OT_MAX:
+ case XADC_THRESHOLD_TEMP_MAX:
+ return &indio_dev->channels[0];
+ case XADC_THRESHOLD_VCCINT_MAX:
+ case XADC_THRESHOLD_VCCAUX_MAX:
+ return &indio_dev->channels[event];
+ default:
+ return &indio_dev->channels[event-1];
+ }
+}
+
+static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event)
+{
+ const struct iio_chan_spec *chan;
+ unsigned int offset;
+
+ /* Temperature threshold error, we don't handle this yet */
+ if (event == 0)
+ return;
+
+ if (event < 4)
+ offset = event;
+ else
+ offset = event + 4;
+
+ chan = xadc_event_to_channel(indio_dev, event);
+
+ if (chan->type == IIO_TEMP) {
+ /*
+ * The temperature channel only supports over-temperature
+ * events.
+ */
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
+ IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
+ iio_get_time_ns());
+ } else {
+ /*
+ * For other channels we don't know whether it is a upper or
+ * lower threshold event. Userspace will have to check the
+ * channel value if it wants to know.
+ */
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
+ IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER),
+ iio_get_time_ns());
+ }
+}
+
+void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events)
+{
+ unsigned int i;
+
+ for_each_set_bit(i, &events, 8)
+ xadc_handle_event(indio_dev, i);
+}
+
+static unsigned xadc_get_threshold_offset(const struct iio_chan_spec *chan,
+ enum iio_event_direction dir)
+{
+ unsigned int offset;
+
+ if (chan->type == IIO_TEMP) {
+ offset = XADC_THRESHOLD_OT_MAX;
+ } else {
+ if (chan->channel < 2)
+ offset = chan->channel + 1;
+ else
+ offset = chan->channel + 6;
+ }
+
+ if (dir == IIO_EV_DIR_FALLING)
+ offset += 4;
+
+ return offset;
+}
+
+static unsigned int xadc_get_alarm_mask(const struct iio_chan_spec *chan)
+{
+ if (chan->type == IIO_TEMP) {
+ return XADC_ALARM_OT_MASK;
+ } else {
+ switch (chan->channel) {
+ case 0:
+ return XADC_ALARM_VCCINT_MASK;
+ case 1:
+ return XADC_ALARM_VCCAUX_MASK;
+ case 2:
+ return XADC_ALARM_VCCBRAM_MASK;
+ case 3:
+ return XADC_ALARM_VCCPINT_MASK;
+ case 4:
+ return XADC_ALARM_VCCPAUX_MASK;
+ case 5:
+ return XADC_ALARM_VCCODDR_MASK;
+ default:
+ /* We will never get here */
+ return 0;
+ }
+ }
+}
+
+int xadc_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct xadc *xadc = iio_priv(indio_dev);
+
+ return (bool)(xadc->alarm_mask & xadc_get_alarm_mask(chan));
+}
+
+int xadc_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, int state)
+{
+ unsigned int alarm = xadc_get_alarm_mask(chan);
+ struct xadc *xadc = iio_priv(indio_dev);
+ uint16_t cfg, old_cfg;
+ int ret;
+
+ mutex_lock(&xadc->mutex);
+
+ if (state)
+ xadc->alarm_mask |= alarm;
+ else
+ xadc->alarm_mask &= ~alarm;
+
+ xadc->ops->update_alarm(xadc, xadc->alarm_mask);
+
+ ret = _xadc_read_adc_reg(xadc, XADC_REG_CONF1, &cfg);
+ if (ret)
+ goto err_out;
+
+ old_cfg = cfg;
+ cfg |= XADC_CONF1_ALARM_MASK;
+ cfg &= ~((xadc->alarm_mask & 0xf0) << 4); /* bram, pint, paux, ddr */
+ cfg &= ~((xadc->alarm_mask & 0x08) >> 3); /* ot */
+ cfg &= ~((xadc->alarm_mask & 0x07) << 1); /* temp, vccint, vccaux */
+ if (old_cfg != cfg)
+ ret = _xadc_write_adc_reg(xadc, XADC_REG_CONF1, cfg);
+
+err_out:
+ mutex_unlock(&xadc->mutex);
+
+ return ret;
+}
+
+/* Register value is msb aligned, the lower 4 bits are ignored */
+#define XADC_THRESHOLD_VALUE_SHIFT 4
+
+int xadc_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, enum iio_event_info info,
+ int *val, int *val2)
+{
+ unsigned int offset = xadc_get_threshold_offset(chan, dir);
+ struct xadc *xadc = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ *val = xadc->threshold[offset];
+ break;
+ case IIO_EV_INFO_HYSTERESIS:
+ *val = xadc->temp_hysteresis;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *val >>= XADC_THRESHOLD_VALUE_SHIFT;
+
+ return IIO_VAL_INT;
+}
+
+int xadc_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, enum iio_event_info info,
+ int val, int val2)
+{
+ unsigned int offset = xadc_get_threshold_offset(chan, dir);
+ struct xadc *xadc = iio_priv(indio_dev);
+ int ret = 0;
+
+ val <<= XADC_THRESHOLD_VALUE_SHIFT;
+
+ if (val < 0 || val > 0xffff)
+ return -EINVAL;
+
+ mutex_lock(&xadc->mutex);
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ xadc->threshold[offset] = val;
+ break;
+ case IIO_EV_INFO_HYSTERESIS:
+ xadc->temp_hysteresis = val;
+ break;
+ default:
+ mutex_unlock(&xadc->mutex);
+ return -EINVAL;
+ }
+
+ if (chan->type == IIO_TEMP) {
+ /*
+ * According to the datasheet we need to set the lower 4 bits to
+ * 0x3, otherwise 125 degree celsius will be used as the
+ * threshold.
+ */
+ val |= 0x3;
+
+ /*
+ * Since we store the hysteresis as relative (to the threshold)
+ * value, but the hardware expects an absolute value we need to
+ * recalcualte this value whenever the hysteresis or the
+ * threshold changes.
+ */
+ if (xadc->threshold[offset] < xadc->temp_hysteresis)
+ xadc->threshold[offset + 4] = 0;
+ else
+ xadc->threshold[offset + 4] = xadc->threshold[offset] -
+ xadc->temp_hysteresis;
+ ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset + 4),
+ xadc->threshold[offset + 4]);
+ if (ret)
+ goto out_unlock;
+ }
+
+ if (info == IIO_EV_INFO_VALUE)
+ ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset), val);
+
+out_unlock:
+ mutex_unlock(&xadc->mutex);
+
+ return ret;
+}
diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h
new file mode 100644
index 000000000000..c7487e8d7f80
--- /dev/null
+++ b/drivers/iio/adc/xilinx-xadc.h
@@ -0,0 +1,209 @@
+/*
+ * Xilinx XADC driver
+ *
+ * Copyright 2013 Analog Devices Inc.
+ * Author: Lars-Peter Clauen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __IIO_XILINX_XADC__
+#define __IIO_XILINX_XADC__
+
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
+struct iio_dev;
+struct clk;
+struct xadc_ops;
+struct platform_device;
+
+void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events);
+
+int xadc_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir);
+int xadc_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, int state);
+int xadc_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, enum iio_event_info info,
+ int *val, int *val2);
+int xadc_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, enum iio_event_info info,
+ int val, int val2);
+
+enum xadc_external_mux_mode {
+ XADC_EXTERNAL_MUX_NONE,
+ XADC_EXTERNAL_MUX_SINGLE,
+ XADC_EXTERNAL_MUX_DUAL,
+};
+
+struct xadc {
+ void __iomem *base;
+ struct clk *clk;
+
+ const struct xadc_ops *ops;
+
+ uint16_t threshold[16];
+ uint16_t temp_hysteresis;
+ unsigned int alarm_mask;
+
+ uint16_t *data;
+
+ struct iio_trigger *trigger;
+ struct iio_trigger *convst_trigger;
+ struct iio_trigger *samplerate_trigger;
+
+ enum xadc_external_mux_mode external_mux_mode;
+
+ unsigned int zynq_alarm;
+ unsigned int zynq_masked_alarm;
+ unsigned int zynq_intmask;
+ struct delayed_work zynq_unmask_work;
+
+ struct mutex mutex;
+ spinlock_t lock;
+
+ struct completion completion;
+};
+
+struct xadc_ops {
+ int (*read)(struct xadc *, unsigned int, uint16_t *);
+ int (*write)(struct xadc *, unsigned int, uint16_t);
+ int (*setup)(struct platform_device *pdev, struct iio_dev *indio_dev,
+ int irq);
+ void (*update_alarm)(struct xadc *, unsigned int);
+ unsigned long (*get_dclk_rate)(struct xadc *);
+ irqreturn_t (*interrupt_handler)(int, void *);
+ irqreturn_t (*threaded_interrupt_handler)(int, void *);
+
+ unsigned int flags;
+};
+
+static inline int _xadc_read_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t *val)
+{
+ lockdep_assert_held(&xadc->mutex);
+ return xadc->ops->read(xadc, reg, val);
+}
+
+static inline int _xadc_write_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t val)
+{
+ lockdep_assert_held(&xadc->mutex);
+ return xadc->ops->write(xadc, reg, val);
+}
+
+static inline int xadc_read_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t *val)
+{
+ int ret;
+
+ mutex_lock(&xadc->mutex);
+ ret = _xadc_read_adc_reg(xadc, reg, val);
+ mutex_unlock(&xadc->mutex);
+ return ret;
+}
+
+static inline int xadc_write_adc_reg(struct xadc *xadc, unsigned int reg,
+ uint16_t val)
+{
+ int ret;
+
+ mutex_lock(&xadc->mutex);
+ ret = _xadc_write_adc_reg(xadc, reg, val);
+ mutex_unlock(&xadc->mutex);
+ return ret;
+}
+
+/* XADC hardmacro register definitions */
+#define XADC_REG_TEMP 0x00
+#define XADC_REG_VCCINT 0x01
+#define XADC_REG_VCCAUX 0x02
+#define XADC_REG_VPVN 0x03
+#define XADC_REG_VREFP 0x04
+#define XADC_REG_VREFN 0x05
+#define XADC_REG_VCCBRAM 0x06
+
+#define XADC_REG_VCCPINT 0x0d
+#define XADC_REG_VCCPAUX 0x0e
+#define XADC_REG_VCCO_DDR 0x0f
+#define XADC_REG_VAUX(x) (0x10 + (x))
+
+#define XADC_REG_MAX_TEMP 0x20
+#define XADC_REG_MAX_VCCINT 0x21
+#define XADC_REG_MAX_VCCAUX 0x22
+#define XADC_REG_MAX_VCCBRAM 0x23
+#define XADC_REG_MIN_TEMP 0x24
+#define XADC_REG_MIN_VCCINT 0x25
+#define XADC_REG_MIN_VCCAUX 0x26
+#define XADC_REG_MIN_VCCBRAM 0x27
+#define XADC_REG_MAX_VCCPINT 0x28
+#define XADC_REG_MAX_VCCPAUX 0x29
+#define XADC_REG_MAX_VCCO_DDR 0x2a
+#define XADC_REG_MIN_VCCPINT 0x2b
+#define XADC_REG_MIN_VCCPAUX 0x2c
+#define XADC_REG_MIN_VCCO_DDR 0x2d
+
+#define XADC_REG_CONF0 0x40
+#define XADC_REG_CONF1 0x41
+#define XADC_REG_CONF2 0x42
+#define XADC_REG_SEQ(x) (0x48 + (x))
+#define XADC_REG_INPUT_MODE(x) (0x4c + (x))
+#define XADC_REG_THRESHOLD(x) (0x50 + (x))
+
+#define XADC_REG_FLAG 0x3f
+
+#define XADC_CONF0_EC BIT(9)
+#define XADC_CONF0_ACQ BIT(8)
+#define XADC_CONF0_MUX BIT(11)
+#define XADC_CONF0_CHAN(x) (x)
+
+#define XADC_CONF1_SEQ_MASK (0xf << 12)
+#define XADC_CONF1_SEQ_DEFAULT (0 << 12)
+#define XADC_CONF1_SEQ_SINGLE_PASS (1 << 12)
+#define XADC_CONF1_SEQ_CONTINUOUS (2 << 12)
+#define XADC_CONF1_SEQ_SINGLE_CHANNEL (3 << 12)
+#define XADC_CONF1_SEQ_SIMULTANEOUS (4 << 12)
+#define XADC_CONF1_SEQ_INDEPENDENT (8 << 12)
+#define XADC_CONF1_ALARM_MASK 0x0f0f
+
+#define XADC_CONF2_DIV_MASK 0xff00
+#define XADC_CONF2_DIV_OFFSET 8
+
+#define XADC_CONF2_PD_MASK (0x3 << 4)
+#define XADC_CONF2_PD_NONE (0x0 << 4)
+#define XADC_CONF2_PD_ADC_B (0x2 << 4)
+#define XADC_CONF2_PD_BOTH (0x3 << 4)
+
+#define XADC_ALARM_TEMP_MASK BIT(0)
+#define XADC_ALARM_VCCINT_MASK BIT(1)
+#define XADC_ALARM_VCCAUX_MASK BIT(2)
+#define XADC_ALARM_OT_MASK BIT(3)
+#define XADC_ALARM_VCCBRAM_MASK BIT(4)
+#define XADC_ALARM_VCCPINT_MASK BIT(5)
+#define XADC_ALARM_VCCPAUX_MASK BIT(6)
+#define XADC_ALARM_VCCODDR_MASK BIT(7)
+
+#define XADC_THRESHOLD_TEMP_MAX 0x0
+#define XADC_THRESHOLD_VCCINT_MAX 0x1
+#define XADC_THRESHOLD_VCCAUX_MAX 0x2
+#define XADC_THRESHOLD_OT_MAX 0x3
+#define XADC_THRESHOLD_TEMP_MIN 0x4
+#define XADC_THRESHOLD_VCCINT_MIN 0x5
+#define XADC_THRESHOLD_VCCAUX_MIN 0x6
+#define XADC_THRESHOLD_OT_MIN 0x7
+#define XADC_THRESHOLD_VCCBRAM_MAX 0x8
+#define XADC_THRESHOLD_VCCPINT_MAX 0x9
+#define XADC_THRESHOLD_VCCPAUX_MAX 0xa
+#define XADC_THRESHOLD_VCCODDR_MAX 0xb
+#define XADC_THRESHOLD_VCCBRAM_MIN 0xc
+#define XADC_THRESHOLD_VCCPINT_MIN 0xd
+#define XADC_THRESHOLD_VCCPAUX_MIN 0xe
+#define XADC_THRESHOLD_VCCODDR_MIN 0xf
+
+#endif
diff --git a/drivers/iio/buffer_cb.c b/drivers/iio/buffer_cb.c
index 2d9c6f8c06db..eb46e728aa2e 100644
--- a/drivers/iio/buffer_cb.c
+++ b/drivers/iio/buffer_cb.c
@@ -46,10 +46,8 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
struct iio_channel *chan;
cb_buff = kzalloc(sizeof(*cb_buff), GFP_KERNEL);
- if (cb_buff == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ if (cb_buff == NULL)
+ return ERR_PTR(-ENOMEM);
iio_buffer_init(&cb_buff->buffer);
@@ -91,7 +89,6 @@ error_release_channels:
iio_channel_release_all(cb_buff->channels);
error_free_cb_buff:
kfree(cb_buff);
-error_ret:
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(iio_channel_get_all_cb);
diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c
index d0505fd22ef4..fa2810032968 100644
--- a/drivers/iio/dac/ad7303.c
+++ b/drivers/iio/dac/ad7303.c
@@ -92,7 +92,7 @@ static ssize_t ad7303_write_dac_powerdown(struct iio_dev *indio_dev,
ad7303_write(st, chan->channel, st->dac_cache[chan->channel]);
mutex_unlock(&indio_dev->mlock);
- return ret ? ret : len;
+ return len;
}
static int ad7303_get_vref(struct ad7303_state *st,
diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c
index de76e6a34c1e..9a82a7255ebb 100644
--- a/drivers/iio/dac/max517.c
+++ b/drivers/iio/dac/max517.c
@@ -19,7 +19,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c
index 7d9f5c31d2fc..43d14588448d 100644
--- a/drivers/iio/dac/mcp4725.c
+++ b/drivers/iio/dac/mcp4725.c
@@ -15,7 +15,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/delay.h>
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
index 41c64a43bcab..ac2d69e34c8c 100644
--- a/drivers/iio/gyro/Kconfig
+++ b/drivers/iio/gyro/Kconfig
@@ -70,7 +70,7 @@ config IIO_ST_GYRO_3AXIS
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
help
Say yes here to build support for STMicroelectronics gyroscopes:
- L3G4200D, LSM330DL, L3GD20, L3GD20H, LSM330DLC, L3G4IS, LSM330.
+ L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330.
This driver can also be built as a module. If so, these modules
will be created:
diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h
index f8f2bf84a5a2..c197360c450b 100644
--- a/drivers/iio/gyro/st_gyro.h
+++ b/drivers/iio/gyro/st_gyro.h
@@ -19,7 +19,6 @@
#define LSM330DL_GYRO_DEV_NAME "lsm330dl_gyro"
#define LSM330DLC_GYRO_DEV_NAME "lsm330dlc_gyro"
#define L3GD20_GYRO_DEV_NAME "l3gd20"
-#define L3GD20H_GYRO_DEV_NAME "l3gd20h"
#define L3G4IS_GYRO_DEV_NAME "l3g4is_ui"
#define LSM330_GYRO_DEV_NAME "lsm330_gyro"
diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c
index d53d91adfb55..a8e174a47bc4 100644
--- a/drivers/iio/gyro/st_gyro_core.c
+++ b/drivers/iio/gyro/st_gyro_core.c
@@ -167,11 +167,10 @@ static const struct st_sensors st_gyro_sensors[] = {
.wai = ST_GYRO_2_WAI_EXP,
.sensors_supported = {
[0] = L3GD20_GYRO_DEV_NAME,
- [1] = L3GD20H_GYRO_DEV_NAME,
- [2] = LSM330D_GYRO_DEV_NAME,
- [3] = LSM330DLC_GYRO_DEV_NAME,
- [4] = L3G4IS_GYRO_DEV_NAME,
- [5] = LSM330_GYRO_DEV_NAME,
+ [1] = LSM330D_GYRO_DEV_NAME,
+ [2] = LSM330DLC_GYRO_DEV_NAME,
+ [3] = L3G4IS_GYRO_DEV_NAME,
+ [4] = LSM330_GYRO_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
.odr = {
diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c
index 16b8b8d70bf1..23c12f361b05 100644
--- a/drivers/iio/gyro/st_gyro_i2c.c
+++ b/drivers/iio/gyro/st_gyro_i2c.c
@@ -55,7 +55,6 @@ static const struct i2c_device_id st_gyro_id_table[] = {
{ LSM330DL_GYRO_DEV_NAME },
{ LSM330DLC_GYRO_DEV_NAME },
{ L3GD20_GYRO_DEV_NAME },
- { L3GD20H_GYRO_DEV_NAME },
{ L3G4IS_GYRO_DEV_NAME },
{ LSM330_GYRO_DEV_NAME },
{},
diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c
index 94763e25caf9..b4ad3be26687 100644
--- a/drivers/iio/gyro/st_gyro_spi.c
+++ b/drivers/iio/gyro/st_gyro_spi.c
@@ -54,7 +54,6 @@ static const struct spi_device_id st_gyro_id_table[] = {
{ LSM330DL_GYRO_DEV_NAME },
{ LSM330DLC_GYRO_DEV_NAME },
{ L3GD20_GYRO_DEV_NAME },
- { L3GD20H_GYRO_DEV_NAME },
{ L3G4IS_GYRO_DEV_NAME },
{ LSM330_GYRO_DEV_NAME },
{},
diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig
index 463c4d9da79e..e116bd8dd0e4 100644
--- a/drivers/iio/humidity/Kconfig
+++ b/drivers/iio/humidity/Kconfig
@@ -12,4 +12,14 @@ config DHT11
Other sensors should work as well as long as they speak the
same protocol.
+config SI7005
+ tristate "SI7005 relative humidity and temperature sensor"
+ depends on I2C
+ help
+ Say yes here to build support for the Silabs Si7005 relative
+ humidity and temperature sensor.
+
+ To compile this driver as a module, choose M here: the module
+ will be called si7005.
+
endmenu
diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile
index d5d36c0c95f9..e3f3d942e646 100644
--- a/drivers/iio/humidity/Makefile
+++ b/drivers/iio/humidity/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_DHT11) += dht11.o
+obj-$(CONFIG_SI7005) += si7005.o
diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c
new file mode 100644
index 000000000000..bdd586e6d955
--- /dev/null
+++ b/drivers/iio/humidity/si7005.c
@@ -0,0 +1,189 @@
+/*
+ * si7005.c - Support for Silabs Si7005 humidity and temperature sensor
+ *
+ * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * (7-bit I2C slave address 0x40)
+ *
+ * TODO: heater, fast mode, processed mode (temp. / linearity compensation)
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define SI7005_STATUS 0x00
+#define SI7005_DATA 0x01 /* 16-bit, MSB */
+#define SI7005_CONFIG 0x03
+#define SI7005_ID 0x11
+
+#define SI7005_STATUS_NRDY BIT(0)
+#define SI7005_CONFIG_TEMP BIT(4)
+#define SI7005_CONFIG_START BIT(0)
+
+#define SI7005_ID_7005 0x50
+#define SI7005_ID_7015 0xf0
+
+struct si7005_data {
+ struct i2c_client *client;
+ struct mutex lock;
+ u8 config;
+};
+
+static int si7005_read_measurement(struct si7005_data *data, bool temp)
+{
+ int tries = 50;
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ ret = i2c_smbus_write_byte_data(data->client, SI7005_CONFIG,
+ data->config | SI7005_CONFIG_START |
+ (temp ? SI7005_CONFIG_TEMP : 0));
+ if (ret < 0)
+ goto done;
+
+ while (tries-- > 0) {
+ msleep(20);
+ ret = i2c_smbus_read_byte_data(data->client, SI7005_STATUS);
+ if (ret < 0)
+ goto done;
+ if (!(ret & SI7005_STATUS_NRDY))
+ break;
+ }
+ if (tries < 0) {
+ ret = -EIO;
+ goto done;
+ }
+
+ ret = i2c_smbus_read_word_swapped(data->client, SI7005_DATA);
+
+done:
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static int si7005_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct si7005_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = si7005_read_measurement(data, chan->type == IIO_TEMP);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type == IIO_TEMP) {
+ *val = 7;
+ *val2 = 812500;
+ } else {
+ *val = 3;
+ *val2 = 906250;
+ }
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_OFFSET:
+ if (chan->type == IIO_TEMP)
+ *val = -50 * 32 * 4;
+ else
+ *val = -24 * 16 * 16;
+ return IIO_VAL_INT;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_chan_spec si7005_channels[] = {
+ {
+ .type = IIO_HUMIDITYRELATIVE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+ },
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+ }
+};
+
+static const struct iio_info si7005_info = {
+ .read_raw = si7005_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int si7005_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct si7005_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+ mutex_init(&data->lock);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = dev_name(&client->dev);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &si7005_info;
+
+ indio_dev->channels = si7005_channels;
+ indio_dev->num_channels = ARRAY_SIZE(si7005_channels);
+
+ ret = i2c_smbus_read_byte_data(client, SI7005_ID);
+ if (ret < 0)
+ return ret;
+ if (ret != SI7005_ID_7005 && ret != SI7005_ID_7015)
+ return -ENODEV;
+
+ ret = i2c_smbus_read_byte_data(client, SI7005_CONFIG);
+ if (ret < 0)
+ return ret;
+ data->config = ret;
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id si7005_id[] = {
+ { "si7005", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, si7005_id);
+
+static struct i2c_driver si7005_driver = {
+ .driver = {
+ .name = "si7005",
+ .owner = THIS_MODULE,
+ },
+ .probe = si7005_probe,
+ .id_table = si7005_id,
+};
+module_i2c_driver(si7005_driver);
+
+MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
+MODULE_DESCRIPTION("Silabs Si7005 humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 663e88a1a3c1..2b0e45133e9d 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -25,6 +25,8 @@ config ADIS16480
Say yes here to build support for Analog Devices ADIS16375, ADIS16480,
ADIS16485, ADIS16488 inertial sensors.
+source "drivers/iio/imu/inv_mpu6050/Kconfig"
+
endmenu
config IIO_ADIS_LIB
@@ -38,5 +40,3 @@ config IIO_ADIS_LIB_BUFFER
help
A set of buffer helper functions for the Analog Devices ADIS* device
family.
-
-source "drivers/iio/imu/inv_mpu6050/Kconfig"
diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c
index 7c582f7ae34e..433583b6f800 100644
--- a/drivers/iio/imu/adis16400_core.c
+++ b/drivers/iio/imu/adis16400_core.c
@@ -281,7 +281,7 @@ static ssize_t adis16400_write_frequency(struct device *dev,
st->variant->set_freq(st, val);
mutex_unlock(&indio_dev->mlock);
- return ret ? ret : len;
+ return len;
}
/* Power down the device */
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index df7f1e1157ae..cb9f96b446a5 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
@@ -117,7 +116,7 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
return result;
if (en) {
- /* Wait for output stablize */
+ /* Wait for output stabilize */
msleep(INV_MPU6050_TEMP_UP_TIME);
if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) {
/* switch internal clock to PLL */
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index f38395529a44..0ab382be1e64 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -126,35 +126,35 @@ struct inv_mpu6050_state {
#define INV_MPU6050_REG_SAMPLE_RATE_DIV 0x19
#define INV_MPU6050_REG_CONFIG 0x1A
#define INV_MPU6050_REG_GYRO_CONFIG 0x1B
-#define INV_MPU6050_REG_ACCEL_CONFIG 0x1C
+#define INV_MPU6050_REG_ACCEL_CONFIG 0x1C
#define INV_MPU6050_REG_FIFO_EN 0x23
-#define INV_MPU6050_BIT_ACCEL_OUT 0x08
-#define INV_MPU6050_BITS_GYRO_OUT 0x70
+#define INV_MPU6050_BIT_ACCEL_OUT 0x08
+#define INV_MPU6050_BITS_GYRO_OUT 0x70
#define INV_MPU6050_REG_INT_ENABLE 0x38
-#define INV_MPU6050_BIT_DATA_RDY_EN 0x01
-#define INV_MPU6050_BIT_DMP_INT_EN 0x02
+#define INV_MPU6050_BIT_DATA_RDY_EN 0x01
+#define INV_MPU6050_BIT_DMP_INT_EN 0x02
#define INV_MPU6050_REG_RAW_ACCEL 0x3B
#define INV_MPU6050_REG_TEMPERATURE 0x41
#define INV_MPU6050_REG_RAW_GYRO 0x43
#define INV_MPU6050_REG_USER_CTRL 0x6A
-#define INV_MPU6050_BIT_FIFO_RST 0x04
-#define INV_MPU6050_BIT_DMP_RST 0x08
-#define INV_MPU6050_BIT_I2C_MST_EN 0x20
-#define INV_MPU6050_BIT_FIFO_EN 0x40
-#define INV_MPU6050_BIT_DMP_EN 0x80
+#define INV_MPU6050_BIT_FIFO_RST 0x04
+#define INV_MPU6050_BIT_DMP_RST 0x08
+#define INV_MPU6050_BIT_I2C_MST_EN 0x20
+#define INV_MPU6050_BIT_FIFO_EN 0x40
+#define INV_MPU6050_BIT_DMP_EN 0x80
#define INV_MPU6050_REG_PWR_MGMT_1 0x6B
-#define INV_MPU6050_BIT_H_RESET 0x80
-#define INV_MPU6050_BIT_SLEEP 0x40
-#define INV_MPU6050_BIT_CLK_MASK 0x7
+#define INV_MPU6050_BIT_H_RESET 0x80
+#define INV_MPU6050_BIT_SLEEP 0x40
+#define INV_MPU6050_BIT_CLK_MASK 0x7
#define INV_MPU6050_REG_PWR_MGMT_2 0x6C
-#define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38
-#define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07
+#define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38
+#define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07
#define INV_MPU6050_REG_FIFO_COUNT_H 0x72
#define INV_MPU6050_REG_FIFO_R_W 0x74
@@ -180,10 +180,10 @@ struct inv_mpu6050_state {
/* init parameters */
#define INV_MPU6050_INIT_FIFO_RATE 50
-#define INV_MPU6050_TIME_STAMP_TOR 5
-#define INV_MPU6050_MAX_FIFO_RATE 1000
-#define INV_MPU6050_MIN_FIFO_RATE 4
-#define INV_MPU6050_ONE_K_HZ 1000
+#define INV_MPU6050_TIME_STAMP_TOR 5
+#define INV_MPU6050_MAX_FIFO_RATE 1000
+#define INV_MPU6050_MIN_FIFO_RATE 4
+#define INV_MPU6050_ONE_K_HZ 1000
/* scan element definition */
enum inv_mpu6050_scan {
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
index 429517117eff..0cd306a72a6e 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index c67d83bdc8f0..e108f2a9d827 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -264,7 +264,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
&indio_dev->dev,
&buffer->scan_el_dev_attr_list);
if (ret)
- goto error_ret;
+ return ret;
attrcount++;
ret = __iio_add_chan_devattr("type",
chan,
@@ -275,7 +275,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
&indio_dev->dev,
&buffer->scan_el_dev_attr_list);
if (ret)
- goto error_ret;
+ return ret;
attrcount++;
if (chan->type != IIO_TIMESTAMP)
ret = __iio_add_chan_devattr("en",
@@ -296,10 +296,9 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
&indio_dev->dev,
&buffer->scan_el_dev_attr_list);
if (ret)
- goto error_ret;
+ return ret;
attrcount++;
ret = attrcount;
-error_ret:
return ret;
}
@@ -553,13 +552,13 @@ static int __iio_update_buffers(struct iio_dev *indio_dev,
if (indio_dev->setup_ops->predisable) {
ret = indio_dev->setup_ops->predisable(indio_dev);
if (ret)
- goto error_ret;
+ return ret;
}
indio_dev->currentmode = INDIO_DIRECT_MODE;
if (indio_dev->setup_ops->postdisable) {
ret = indio_dev->setup_ops->postdisable(indio_dev);
if (ret)
- goto error_ret;
+ return ret;
}
}
/* Keep a copy of current setup to allow roll back */
@@ -613,7 +612,7 @@ static int __iio_update_buffers(struct iio_dev *indio_dev,
else {
kfree(compound_mask);
ret = -EINVAL;
- goto error_ret;
+ return ret;
}
}
} else {
@@ -696,13 +695,10 @@ error_run_postdisable:
if (indio_dev->setup_ops->postdisable)
indio_dev->setup_ops->postdisable(indio_dev);
error_remove_inserted:
-
if (insert_buffer)
iio_buffer_deactivate(insert_buffer);
indio_dev->active_scan_mask = old_mask;
kfree(compound_mask);
-error_ret:
-
return ret;
}
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index acc911a836ca..ede16aec20fb 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -540,7 +540,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
enum iio_shared_by shared_by)
{
int ret = 0;
- char *name_format = NULL;
+ char *name = NULL;
char *full_postfix;
sysfs_attr_init(&dev_attr->attr);
@@ -558,7 +558,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
->channel2],
postfix);
} else {
- if (chan->extend_name == NULL)
+ if (chan->extend_name == NULL || shared_by != IIO_SEPARATE)
full_postfix = kstrdup(postfix, GFP_KERNEL);
else
full_postfix = kasprintf(GFP_KERNEL,
@@ -572,16 +572,15 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
if (chan->differential) { /* Differential can not have modifier */
switch (shared_by) {
case IIO_SHARED_BY_ALL:
- name_format = kasprintf(GFP_KERNEL, "%s", full_postfix);
+ name = kasprintf(GFP_KERNEL, "%s", full_postfix);
break;
case IIO_SHARED_BY_DIR:
- name_format = kasprintf(GFP_KERNEL, "%s_%s",
+ name = kasprintf(GFP_KERNEL, "%s_%s",
iio_direction[chan->output],
full_postfix);
break;
case IIO_SHARED_BY_TYPE:
- name_format
- = kasprintf(GFP_KERNEL, "%s_%s-%s_%s",
+ name = kasprintf(GFP_KERNEL, "%s_%s-%s_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
iio_chan_type_name_spec[chan->type],
@@ -593,8 +592,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
ret = -EINVAL;
goto error_free_full_postfix;
}
- name_format
- = kasprintf(GFP_KERNEL,
+ name = kasprintf(GFP_KERNEL,
"%s_%s%d-%s%d_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
@@ -607,16 +605,15 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
} else { /* Single ended */
switch (shared_by) {
case IIO_SHARED_BY_ALL:
- name_format = kasprintf(GFP_KERNEL, "%s", full_postfix);
+ name = kasprintf(GFP_KERNEL, "%s", full_postfix);
break;
case IIO_SHARED_BY_DIR:
- name_format = kasprintf(GFP_KERNEL, "%s_%s",
+ name = kasprintf(GFP_KERNEL, "%s_%s",
iio_direction[chan->output],
full_postfix);
break;
case IIO_SHARED_BY_TYPE:
- name_format
- = kasprintf(GFP_KERNEL, "%s_%s_%s",
+ name = kasprintf(GFP_KERNEL, "%s_%s_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
full_postfix);
@@ -624,33 +621,24 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
case IIO_SEPARATE:
if (chan->indexed)
- name_format
- = kasprintf(GFP_KERNEL, "%s_%s%d_%s",
+ name = kasprintf(GFP_KERNEL, "%s_%s%d_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
chan->channel,
full_postfix);
else
- name_format
- = kasprintf(GFP_KERNEL, "%s_%s_%s",
+ name = kasprintf(GFP_KERNEL, "%s_%s_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
full_postfix);
break;
}
}
- if (name_format == NULL) {
+ if (name == NULL) {
ret = -ENOMEM;
goto error_free_full_postfix;
}
- dev_attr->attr.name = kasprintf(GFP_KERNEL,
- name_format,
- chan->channel,
- chan->channel2);
- if (dev_attr->attr.name == NULL) {
- ret = -ENOMEM;
- goto error_free_name_format;
- }
+ dev_attr->attr.name = name;
if (readfunc) {
dev_attr->attr.mode |= S_IRUGO;
@@ -661,8 +649,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
dev_attr->attr.mode |= S_IWUSR;
dev_attr->store = writefunc;
}
-error_free_name_format:
- kfree(name_format);
+
error_free_full_postfix:
kfree(full_postfix);
@@ -692,10 +679,8 @@ int __iio_add_chan_devattr(const char *postfix,
struct iio_dev_attr *iio_attr, *t;
iio_attr = kzalloc(sizeof(*iio_attr), GFP_KERNEL);
- if (iio_attr == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ if (iio_attr == NULL)
+ return -ENOMEM;
ret = __iio_device_attr_init(&iio_attr->dev_attr,
postfix, chan,
readfunc, writefunc, shared_by);
@@ -720,7 +705,6 @@ error_device_attr_deinit:
__iio_device_attr_deinit(&iio_attr->dev_attr);
error_iio_dev_attr_free:
kfree(iio_attr);
-error_ret:
return ret;
}
@@ -1134,7 +1118,7 @@ int iio_device_register(struct iio_dev *indio_dev)
if (ret) {
dev_err(indio_dev->dev.parent,
"Failed to register debugfs interfaces\n");
- goto error_ret;
+ return ret;
}
ret = iio_device_register_sysfs(indio_dev);
if (ret) {
@@ -1175,7 +1159,6 @@ error_free_sysfs:
iio_device_unregister_sysfs(indio_dev);
error_unreg_debugfs:
iio_device_unregister_debugfs(indio_dev);
-error_ret:
return ret;
}
EXPORT_SYMBOL(iio_device_register);
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index c9c1419fe6e0..ea6e06b9c7d4 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -40,6 +40,7 @@ struct iio_event_interface {
struct list_head dev_attr_list;
unsigned long flags;
struct attribute_group group;
+ struct mutex read_lock;
};
/**
@@ -47,16 +48,17 @@ struct iio_event_interface {
* @indio_dev: IIO device structure
* @ev_code: What event
* @timestamp: When the event occurred
+ *
+ * Note: The caller must make sure that this function is not running
+ * concurrently for the same indio_dev more than once.
**/
int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
{
struct iio_event_interface *ev_int = indio_dev->event_interface;
struct iio_event_data ev;
- unsigned long flags;
int copied;
/* Does anyone care? */
- spin_lock_irqsave(&ev_int->wait.lock, flags);
if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
ev.id = ev_code;
@@ -64,9 +66,8 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
copied = kfifo_put(&ev_int->det_events, ev);
if (copied != 0)
- wake_up_locked_poll(&ev_int->wait, POLLIN);
+ wake_up_poll(&ev_int->wait, POLLIN);
}
- spin_unlock_irqrestore(&ev_int->wait.lock, flags);
return 0;
}
@@ -87,10 +88,8 @@ static unsigned int iio_event_poll(struct file *filep,
poll_wait(filep, &ev_int->wait, wait);
- spin_lock_irq(&ev_int->wait.lock);
if (!kfifo_is_empty(&ev_int->det_events))
events = POLLIN | POLLRDNORM;
- spin_unlock_irq(&ev_int->wait.lock);
return events;
}
@@ -111,31 +110,40 @@ static ssize_t iio_event_chrdev_read(struct file *filep,
if (count < sizeof(struct iio_event_data))
return -EINVAL;
- spin_lock_irq(&ev_int->wait.lock);
- if (kfifo_is_empty(&ev_int->det_events)) {
- if (filep->f_flags & O_NONBLOCK) {
- ret = -EAGAIN;
- goto error_unlock;
- }
- /* Blocking on device; waiting for something to be there */
- ret = wait_event_interruptible_locked_irq(ev_int->wait,
+ do {
+ if (kfifo_is_empty(&ev_int->det_events)) {
+ if (filep->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ ret = wait_event_interruptible(ev_int->wait,
!kfifo_is_empty(&ev_int->det_events) ||
indio_dev->info == NULL);
- if (ret)
- goto error_unlock;
- if (indio_dev->info == NULL) {
- ret = -ENODEV;
- goto error_unlock;
+ if (ret)
+ return ret;
+ if (indio_dev->info == NULL)
+ return -ENODEV;
}
- /* Single access device so no one else can get the data */
- }
- ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied);
+ if (mutex_lock_interruptible(&ev_int->read_lock))
+ return -ERESTARTSYS;
+ ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied);
+ mutex_unlock(&ev_int->read_lock);
-error_unlock:
- spin_unlock_irq(&ev_int->wait.lock);
+ if (ret)
+ return ret;
+
+ /*
+ * If we couldn't read anything from the fifo (a different
+ * thread might have been faster) we either return -EAGAIN if
+ * the file descriptor is non-blocking, otherwise we go back to
+ * sleep and wait for more data to arrive.
+ */
+ if (copied == 0 && (filep->f_flags & O_NONBLOCK))
+ return -EAGAIN;
- return ret ? ret : copied;
+ } while (copied == 0);
+
+ return copied;
}
static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
@@ -143,15 +151,7 @@ static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
struct iio_dev *indio_dev = filep->private_data;
struct iio_event_interface *ev_int = indio_dev->event_interface;
- spin_lock_irq(&ev_int->wait.lock);
- __clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
- /*
- * In order to maintain a clean state for reopening,
- * clear out any awaiting events. The mask will prevent
- * any new __iio_push_event calls running.
- */
- kfifo_reset_out(&ev_int->det_events);
- spin_unlock_irq(&ev_int->wait.lock);
+ clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
iio_device_put(indio_dev);
@@ -174,22 +174,20 @@ int iio_event_getfd(struct iio_dev *indio_dev)
if (ev_int == NULL)
return -ENODEV;
- spin_lock_irq(&ev_int->wait.lock);
- if (__test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
- spin_unlock_irq(&ev_int->wait.lock);
+ if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags))
return -EBUSY;
- }
- spin_unlock_irq(&ev_int->wait.lock);
+
iio_device_get(indio_dev);
fd = anon_inode_getfd("iio:event", &iio_event_chrdev_fileops,
indio_dev, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
- spin_lock_irq(&ev_int->wait.lock);
- __clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
- spin_unlock_irq(&ev_int->wait.lock);
+ clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
iio_device_put(indio_dev);
+ } else {
+ kfifo_reset_out(&ev_int->det_events);
}
+
return fd;
}
@@ -366,32 +364,31 @@ static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
ret = iio_device_add_event(indio_dev, chan, i, type, dir,
IIO_SEPARATE, &chan->event_spec[i].mask_separate);
if (ret < 0)
- goto error_ret;
+ return ret;
attrcount += ret;
ret = iio_device_add_event(indio_dev, chan, i, type, dir,
IIO_SHARED_BY_TYPE,
&chan->event_spec[i].mask_shared_by_type);
if (ret < 0)
- goto error_ret;
+ return ret;
attrcount += ret;
ret = iio_device_add_event(indio_dev, chan, i, type, dir,
IIO_SHARED_BY_DIR,
&chan->event_spec[i].mask_shared_by_dir);
if (ret < 0)
- goto error_ret;
+ return ret;
attrcount += ret;
ret = iio_device_add_event(indio_dev, chan, i, type, dir,
IIO_SHARED_BY_ALL,
&chan->event_spec[i].mask_shared_by_all);
if (ret < 0)
- goto error_ret;
+ return ret;
attrcount += ret;
}
ret = attrcount;
-error_ret:
return ret;
}
@@ -425,6 +422,7 @@ static void iio_setup_ev_int(struct iio_event_interface *ev_int)
{
INIT_KFIFO(ev_int->det_events);
init_waitqueue_head(&ev_int->wait);
+ mutex_init(&ev_int->read_lock);
}
static const char *iio_event_group_name = "events";
@@ -440,10 +438,8 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
indio_dev->event_interface =
kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL);
- if (indio_dev->event_interface == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ if (indio_dev->event_interface == NULL)
+ return -ENOMEM;
INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list);
@@ -489,8 +485,6 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
error_free_setup_event_lines:
iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list);
kfree(indio_dev->event_interface);
-error_ret:
-
return ret;
}
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 766fab24b720..3383b025f62e 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -62,10 +62,9 @@ int iio_trigger_register(struct iio_trigger *trig_info)
int ret;
trig_info->id = ida_simple_get(&iio_trigger_ida, 0, 0, GFP_KERNEL);
- if (trig_info->id < 0) {
- ret = trig_info->id;
- goto error_ret;
- }
+ if (trig_info->id < 0)
+ return trig_info->id;
+
/* Set the name used for the sysfs directory etc */
dev_set_name(&trig_info->dev, "trigger%ld",
(unsigned long) trig_info->id);
@@ -83,7 +82,6 @@ int iio_trigger_register(struct iio_trigger *trig_info)
error_unregister_id:
ida_simple_remove(&iio_trigger_ida, trig_info->id);
-error_ret:
return ret;
}
EXPORT_SYMBOL(iio_trigger_register);
@@ -234,13 +232,12 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig,
if (trig->ops && trig->ops->set_trigger_state && no_other_users) {
ret = trig->ops->set_trigger_state(trig, false);
if (ret)
- goto error_ret;
+ return ret;
}
iio_trigger_put_irq(trig, pf->irq);
free_irq(pf->irq, pf);
module_put(pf->indio_dev->info->driver_module);
-error_ret:
return ret;
}
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index d12b2a0dbfbc..c89740d4748f 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -73,6 +73,20 @@ config HID_SENSOR_ALS
Say yes here to build support for the HID SENSOR
Ambient light sensor.
+config HID_SENSOR_PROX
+ depends on HID_SENSOR_HUB
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ select HID_SENSOR_IIO_COMMON
+ select HID_SENSOR_IIO_TRIGGER
+ tristate "HID PROX"
+ help
+ Say yes here to build support for the HID SENSOR
+ Proximity sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hid-sensor-prox.
+
config SENSORS_LM3533
tristate "LM3533 ambient light sensor"
depends on MFD_LM3533
@@ -90,6 +104,18 @@ config SENSORS_LM3533
changes. The ALS-control output values can be set per zone for the
three current output channels.
+config LTR501
+ tristate "LTR-501ALS-01 light sensor"
+ depends on I2C
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ If you say yes here you get support for the Lite-On LTR-501ALS-01
+ ambient light and proximity sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called ltr501.
+
config TCS3472
tristate "TAOS TCS3472 color light-to-digital converter"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 60e35ac07ff0..3eb36e5151fa 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -9,7 +9,9 @@ obj-$(CONFIG_CM32181) += cm32181.o
obj-$(CONFIG_CM36651) += cm36651.o
obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
+obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
+obj-$(CONFIG_LTR501) += ltr501.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_TCS3472) += tcs3472.o
obj-$(CONFIG_TSL4531) += tsl4531.o
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index f3068477b466..09ad5f1ce539 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -14,7 +14,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
@@ -120,7 +119,6 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct adjd_s311_data *data = iio_priv(indio_dev);
s64 time_ns = iio_get_time_ns();
- int len = 0;
int i, j = 0;
int ret = adjd_s311_req_data(indio_dev);
@@ -135,7 +133,6 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
goto done;
data->buffer[j++] = ret & ADJD_S311_DATA_MASK;
- len += 2;
}
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, time_ns);
diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index f17b4e6183c6..47a6dbac2d0c 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -103,13 +103,13 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
/**
* cm32181_read_als_it() - Get sensor integration time (ms)
* @cm32181: pointer of struct cm32181
- * @val: pointer of int to load the als_it value.
+ * @val2: pointer of int to load the als_it value.
*
* Report the current integartion time by millisecond.
*
- * Return: IIO_VAL_INT for success, otherwise -EINVAL.
+ * Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
*/
-static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val)
+static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2)
{
u16 als_it;
int i;
@@ -119,8 +119,8 @@ static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val)
als_it >>= CM32181_CMD_ALS_IT_SHIFT;
for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
if (als_it == als_it_bits[i]) {
- *val = als_it_value[i];
- return IIO_VAL_INT;
+ *val2 = als_it_value[i];
+ return IIO_VAL_INT_PLUS_MICRO;
}
}
@@ -221,7 +221,7 @@ static int cm32181_read_raw(struct iio_dev *indio_dev,
*val = cm32181->calibscale;
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
- ret = cm32181_read_als_it(cm32181, val);
+ ret = cm32181_read_als_it(cm32181, val2);
return ret;
}
@@ -240,7 +240,7 @@ static int cm32181_write_raw(struct iio_dev *indio_dev,
cm32181->calibscale = val;
return val;
case IIO_CHAN_INFO_INT_TIME:
- ret = cm32181_write_als_it(cm32181, val);
+ ret = cm32181_write_als_it(cm32181, val2);
return ret;
}
@@ -264,7 +264,7 @@ static ssize_t cm32181_get_it_available(struct device *dev,
n = ARRAY_SIZE(als_it_value);
for (i = 0, len = 0; i < n; i++)
- len += sprintf(buf + len, "%d ", als_it_value[i]);
+ len += sprintf(buf + len, "0.%06u ", als_it_value[i]);
return len + sprintf(buf + len, "\n");
}
diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c
index 0a142af83e25..a45e07492db3 100644
--- a/drivers/iio/light/cm36651.c
+++ b/drivers/iio/light/cm36651.c
@@ -50,10 +50,10 @@
#define CM36651_CS_CONF2_DEFAULT_BIT 0x08
/* CS_CONF3 channel integration time */
-#define CM36651_CS_IT1 0x00 /* Integration time 80000 usec */
-#define CM36651_CS_IT2 0x40 /* Integration time 160000 usec */
-#define CM36651_CS_IT3 0x80 /* Integration time 320000 usec */
-#define CM36651_CS_IT4 0xC0 /* Integration time 640000 usec */
+#define CM36651_CS_IT1 0x00 /* Integration time 80 msec */
+#define CM36651_CS_IT2 0x40 /* Integration time 160 msec */
+#define CM36651_CS_IT3 0x80 /* Integration time 320 msec */
+#define CM36651_CS_IT4 0xC0 /* Integration time 640 msec */
/* PS_CONF1 command code */
#define CM36651_PS_ENABLE 0x00
@@ -64,10 +64,10 @@
#define CM36651_PS_PERS4 0x0C
/* PS_CONF1 command code: integration time */
-#define CM36651_PS_IT1 0x00 /* Integration time 320 usec */
-#define CM36651_PS_IT2 0x10 /* Integration time 420 usec */
-#define CM36651_PS_IT3 0x20 /* Integration time 520 usec */
-#define CM36651_PS_IT4 0x30 /* Integration time 640 usec */
+#define CM36651_PS_IT1 0x00 /* Integration time 0.32 msec */
+#define CM36651_PS_IT2 0x10 /* Integration time 0.42 msec */
+#define CM36651_PS_IT3 0x20 /* Integration time 0.52 msec */
+#define CM36651_PS_IT4 0x30 /* Integration time 0.64 msec */
/* PS_CONF1 command code: duty ratio */
#define CM36651_PS_DR1 0x00 /* Duty ratio 1/80 */
@@ -93,8 +93,8 @@
#define CM36651_CLOSE_PROXIMITY 0x32
#define CM36651_FAR_PROXIMITY 0x33
-#define CM36651_CS_INT_TIME_AVAIL "80000 160000 320000 640000"
-#define CM36651_PS_INT_TIME_AVAIL "320 420 520 640"
+#define CM36651_CS_INT_TIME_AVAIL "0.08 0.16 0.32 0.64"
+#define CM36651_PS_INT_TIME_AVAIL "0.000320 0.000420 0.000520 0.000640"
enum cm36651_operation_mode {
CM36651_LIGHT_EN,
@@ -356,30 +356,30 @@ static int cm36651_read_channel(struct cm36651_data *cm36651,
}
static int cm36651_read_int_time(struct cm36651_data *cm36651,
- struct iio_chan_spec const *chan, int *val)
+ struct iio_chan_spec const *chan, int *val2)
{
switch (chan->type) {
case IIO_LIGHT:
if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT1)
- *val = 80000;
+ *val2 = 80000;
else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT2)
- *val = 160000;
+ *val2 = 160000;
else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT3)
- *val = 320000;
+ *val2 = 320000;
else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT4)
- *val = 640000;
+ *val2 = 640000;
else
return -EINVAL;
break;
case IIO_PROXIMITY:
if (cm36651->ps_int_time == CM36651_PS_IT1)
- *val = 320;
+ *val2 = 320;
else if (cm36651->ps_int_time == CM36651_PS_IT2)
- *val = 420;
+ *val2 = 420;
else if (cm36651->ps_int_time == CM36651_PS_IT3)
- *val = 520;
+ *val2 = 520;
else if (cm36651->ps_int_time == CM36651_PS_IT4)
- *val = 640;
+ *val2 = 640;
else
return -EINVAL;
break;
@@ -387,7 +387,7 @@ static int cm36651_read_int_time(struct cm36651_data *cm36651,
return -EINVAL;
}
- return IIO_VAL_INT;
+ return IIO_VAL_INT_PLUS_MICRO;
}
static int cm36651_write_int_time(struct cm36651_data *cm36651,
@@ -459,7 +459,8 @@ static int cm36651_read_raw(struct iio_dev *indio_dev,
ret = cm36651_read_channel(cm36651, chan, val);
break;
case IIO_CHAN_INFO_INT_TIME:
- ret = cm36651_read_int_time(cm36651, chan, val);
+ *val = 0;
+ ret = cm36651_read_int_time(cm36651, chan, val2);
break;
default:
ret = -EINVAL;
@@ -479,7 +480,7 @@ static int cm36651_write_raw(struct iio_dev *indio_dev,
int ret = -EINVAL;
if (mask == IIO_CHAN_INFO_INT_TIME) {
- ret = cm36651_write_int_time(cm36651, chan, val);
+ ret = cm36651_write_int_time(cm36651, chan, val2);
if (ret < 0)
dev_err(&client->dev, "Integration time write failed\n");
}
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
new file mode 100644
index 000000000000..1894ab196f97
--- /dev/null
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -0,0 +1,375 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.
+ *
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/hid-sensor-hub.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include "../common/hid-sensors/hid-sensor-trigger.h"
+
+#define CHANNEL_SCAN_INDEX_PRESENCE 0
+
+struct prox_state {
+ struct hid_sensor_hub_callbacks callbacks;
+ struct hid_sensor_common common_attributes;
+ struct hid_sensor_hub_attribute_info prox_attr;
+ u32 human_presence;
+};
+
+/* Channel definitions */
+static const struct iio_chan_spec prox_channels[] = {
+ {
+ .type = IIO_PROXIMITY,
+ .modified = 1,
+ .channel2 = IIO_NO_MOD,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
+ .scan_index = CHANNEL_SCAN_INDEX_PRESENCE,
+ }
+};
+
+/* Adjust channel real bits based on report descriptor */
+static void prox_adjust_channel_bit_mask(struct iio_chan_spec *channels,
+ int channel, int size)
+{
+ channels[channel].scan_type.sign = 's';
+ /* Real storage bits will change based on the report desc. */
+ channels[channel].scan_type.realbits = size * 8;
+ /* Maximum size of a sample to capture is u32 */
+ channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+/* Channel read_raw handler */
+static int prox_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2,
+ long mask)
+{
+ struct prox_state *prox_state = iio_priv(indio_dev);
+ int report_id = -1;
+ u32 address;
+ int ret;
+ int ret_type;
+
+ *val = 0;
+ *val2 = 0;
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->scan_index) {
+ case CHANNEL_SCAN_INDEX_PRESENCE:
+ report_id = prox_state->prox_attr.report_id;
+ address =
+ HID_USAGE_SENSOR_HUMAN_PRESENCE;
+ break;
+ default:
+ report_id = -1;
+ break;
+ }
+ if (report_id >= 0)
+ *val = sensor_hub_input_attr_get_raw_value(
+ prox_state->common_attributes.hsdev,
+ HID_USAGE_SENSOR_PROX, address,
+ report_id);
+ else {
+ *val = 0;
+ return -EINVAL;
+ }
+ ret_type = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ *val = prox_state->prox_attr.units;
+ ret_type = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = hid_sensor_convert_exponent(
+ prox_state->prox_attr.unit_expo);
+ ret_type = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = hid_sensor_read_samp_freq_value(
+ &prox_state->common_attributes, val, val2);
+ ret_type = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ case IIO_CHAN_INFO_HYSTERESIS:
+ ret = hid_sensor_read_raw_hyst_value(
+ &prox_state->common_attributes, val, val2);
+ ret_type = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ default:
+ ret_type = -EINVAL;
+ break;
+ }
+
+ return ret_type;
+}
+
+/* Channel write_raw handler */
+static int prox_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct prox_state *prox_state = iio_priv(indio_dev);
+ int ret = 0;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = hid_sensor_write_samp_freq_value(
+ &prox_state->common_attributes, val, val2);
+ break;
+ case IIO_CHAN_INFO_HYSTERESIS:
+ ret = hid_sensor_write_raw_hyst_value(
+ &prox_state->common_attributes, val, val2);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct iio_info prox_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &prox_read_raw,
+ .write_raw = &prox_write_raw,
+};
+
+/* Function to push data to buffer */
+static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,
+ int len)
+{
+ dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
+ iio_push_to_buffers(indio_dev, data);
+}
+
+/* Callback handler to send event after all samples are received and captured */
+static int prox_proc_event(struct hid_sensor_hub_device *hsdev,
+ unsigned usage_id,
+ void *priv)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(priv);
+ struct prox_state *prox_state = iio_priv(indio_dev);
+
+ dev_dbg(&indio_dev->dev, "prox_proc_event [%d]\n",
+ prox_state->common_attributes.data_ready);
+ if (prox_state->common_attributes.data_ready)
+ hid_sensor_push_data(indio_dev,
+ &prox_state->human_presence,
+ sizeof(prox_state->human_presence));
+
+ return 0;
+}
+
+/* Capture samples in local storage */
+static int prox_capture_sample(struct hid_sensor_hub_device *hsdev,
+ unsigned usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(priv);
+ struct prox_state *prox_state = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ switch (usage_id) {
+ case HID_USAGE_SENSOR_HUMAN_PRESENCE:
+ prox_state->human_presence = *(u32 *)raw_data;
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/* Parse report which is specific to an usage id*/
+static int prox_parse_report(struct platform_device *pdev,
+ struct hid_sensor_hub_device *hsdev,
+ struct iio_chan_spec *channels,
+ unsigned usage_id,
+ struct prox_state *st)
+{
+ int ret;
+
+ ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_HUMAN_PRESENCE,
+ &st->prox_attr);
+ if (ret < 0)
+ return ret;
+ prox_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESENCE,
+ st->prox_attr.size);
+
+ dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr.index,
+ st->prox_attr.report_id);
+
+ /* Set Sensitivity field ids, when there is no individual modifier */
+ if (st->common_attributes.sensitivity.index < 0) {
+ sensor_hub_input_get_attribute_info(hsdev,
+ HID_FEATURE_REPORT, usage_id,
+ HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
+ HID_USAGE_SENSOR_DATA_PRESENCE,
+ &st->common_attributes.sensitivity);
+ dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
+ st->common_attributes.sensitivity.index,
+ st->common_attributes.sensitivity.report_id);
+ }
+ return ret;
+}
+
+/* Function to initialize the processing for usage id */
+static int hid_prox_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ static const char *name = "prox";
+ struct iio_dev *indio_dev;
+ struct prox_state *prox_state;
+ struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+ struct iio_chan_spec *channels;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev,
+ sizeof(struct prox_state));
+ if (!indio_dev)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, indio_dev);
+
+ prox_state = iio_priv(indio_dev);
+ prox_state->common_attributes.hsdev = hsdev;
+ prox_state->common_attributes.pdev = pdev;
+
+ ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PROX,
+ &prox_state->common_attributes);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to setup common attributes\n");
+ return ret;
+ }
+
+ channels = kmemdup(prox_channels, sizeof(prox_channels), GFP_KERNEL);
+ if (!channels) {
+ dev_err(&pdev->dev, "failed to duplicate channels\n");
+ return -ENOMEM;
+ }
+
+ ret = prox_parse_report(pdev, hsdev, channels,
+ HID_USAGE_SENSOR_PROX, prox_state);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to setup attributes\n");
+ goto error_free_dev_mem;
+ }
+
+ indio_dev->channels = channels;
+ indio_dev->num_channels =
+ ARRAY_SIZE(prox_channels);
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->info = &prox_info;
+ indio_dev->name = name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+ NULL, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
+ goto error_free_dev_mem;
+ }
+ prox_state->common_attributes.data_ready = false;
+ ret = hid_sensor_setup_trigger(indio_dev, name,
+ &prox_state->common_attributes);
+ if (ret) {
+ dev_err(&pdev->dev, "trigger setup failed\n");
+ goto error_unreg_buffer_funcs;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_trigger;
+ }
+
+ prox_state->callbacks.send_event = prox_proc_event;
+ prox_state->callbacks.capture_sample = prox_capture_sample;
+ prox_state->callbacks.pdev = pdev;
+ ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PROX,
+ &prox_state->callbacks);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "callback reg failed\n");
+ goto error_iio_unreg;
+ }
+
+ return ret;
+
+error_iio_unreg:
+ iio_device_unregister(indio_dev);
+error_remove_trigger:
+ hid_sensor_remove_trigger(&prox_state->common_attributes);
+error_unreg_buffer_funcs:
+ iio_triggered_buffer_cleanup(indio_dev);
+error_free_dev_mem:
+ kfree(indio_dev->channels);
+ return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int hid_prox_remove(struct platform_device *pdev)
+{
+ struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct prox_state *prox_state = iio_priv(indio_dev);
+
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PROX);
+ iio_device_unregister(indio_dev);
+ hid_sensor_remove_trigger(&prox_state->common_attributes);
+ iio_triggered_buffer_cleanup(indio_dev);
+ kfree(indio_dev->channels);
+
+ return 0;
+}
+
+static struct platform_device_id hid_prox_ids[] = {
+ {
+ /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+ .name = "HID-SENSOR-200011",
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_prox_ids);
+
+static struct platform_driver hid_prox_platform_driver = {
+ .id_table = hid_prox_ids,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = hid_prox_probe,
+ .remove = hid_prox_remove,
+};
+module_platform_driver(hid_prox_platform_driver);
+
+MODULE_DESCRIPTION("HID Sensor Proximity");
+MODULE_AUTHOR("Archana Patni <archana.patni@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c
new file mode 100644
index 000000000000..62b7072af4de
--- /dev/null
+++ b/drivers/iio/light/ltr501.c
@@ -0,0 +1,445 @@
+/*
+ * ltr501.c - Support for Lite-On LTR501 ambient light and proximity sensor
+ *
+ * Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * 7-bit I2C slave address 0x23
+ *
+ * TODO: interrupt, threshold, measurement rate, IR LED characteristics
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define LTR501_DRV_NAME "ltr501"
+
+#define LTR501_ALS_CONTR 0x80 /* ALS operation mode, SW reset */
+#define LTR501_PS_CONTR 0x81 /* PS operation mode */
+#define LTR501_PART_ID 0x86
+#define LTR501_MANUFAC_ID 0x87
+#define LTR501_ALS_DATA1 0x88 /* 16-bit, little endian */
+#define LTR501_ALS_DATA0 0x8a /* 16-bit, little endian */
+#define LTR501_ALS_PS_STATUS 0x8c
+#define LTR501_PS_DATA 0x8d /* 16-bit, little endian */
+
+#define LTR501_ALS_CONTR_SW_RESET BIT(2)
+#define LTR501_CONTR_PS_GAIN_MASK (BIT(3) | BIT(2))
+#define LTR501_CONTR_PS_GAIN_SHIFT 2
+#define LTR501_CONTR_ALS_GAIN_MASK BIT(3)
+#define LTR501_CONTR_ACTIVE BIT(1)
+
+#define LTR501_STATUS_ALS_RDY BIT(2)
+#define LTR501_STATUS_PS_RDY BIT(0)
+
+#define LTR501_PS_DATA_MASK 0x7ff
+
+struct ltr501_data {
+ struct i2c_client *client;
+ struct mutex lock_als, lock_ps;
+ u8 als_contr, ps_contr;
+};
+
+static int ltr501_drdy(struct ltr501_data *data, u8 drdy_mask)
+{
+ int tries = 100;
+ int ret;
+
+ while (tries--) {
+ ret = i2c_smbus_read_byte_data(data->client,
+ LTR501_ALS_PS_STATUS);
+ if (ret < 0)
+ return ret;
+ if ((ret & drdy_mask) == drdy_mask)
+ return 0;
+ msleep(25);
+ }
+
+ dev_err(&data->client->dev, "ltr501_drdy() failed, data not ready\n");
+ return -EIO;
+}
+
+static int ltr501_read_als(struct ltr501_data *data, __le16 buf[2])
+{
+ int ret = ltr501_drdy(data, LTR501_STATUS_ALS_RDY);
+ if (ret < 0)
+ return ret;
+ /* always read both ALS channels in given order */
+ return i2c_smbus_read_i2c_block_data(data->client,
+ LTR501_ALS_DATA1, 2 * sizeof(__le16), (u8 *) buf);
+}
+
+static int ltr501_read_ps(struct ltr501_data *data)
+{
+ int ret = ltr501_drdy(data, LTR501_STATUS_PS_RDY);
+ if (ret < 0)
+ return ret;
+ return i2c_smbus_read_word_data(data->client, LTR501_PS_DATA);
+}
+
+#define LTR501_INTENSITY_CHANNEL(_idx, _addr, _mod, _shared) { \
+ .type = IIO_INTENSITY, \
+ .modified = 1, \
+ .address = (_addr), \
+ .channel2 = (_mod), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = (_shared), \
+ .scan_index = (_idx), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ } \
+}
+
+static const struct iio_chan_spec ltr501_channels[] = {
+ LTR501_INTENSITY_CHANNEL(0, LTR501_ALS_DATA0, IIO_MOD_LIGHT_BOTH, 0),
+ LTR501_INTENSITY_CHANNEL(1, LTR501_ALS_DATA1, IIO_MOD_LIGHT_IR,
+ BIT(IIO_CHAN_INFO_SCALE)),
+ {
+ .type = IIO_PROXIMITY,
+ .address = LTR501_PS_DATA,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 2,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 11,
+ .storagebits = 16,
+ .endianness = IIO_CPU,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const int ltr501_ps_gain[4][2] = {
+ {1, 0}, {0, 250000}, {0, 125000}, {0, 62500}
+};
+
+static int ltr501_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct ltr501_data *data = iio_priv(indio_dev);
+ __le16 buf[2];
+ int ret, i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+
+ switch (chan->type) {
+ case IIO_INTENSITY:
+ mutex_lock(&data->lock_als);
+ ret = ltr501_read_als(data, buf);
+ mutex_unlock(&data->lock_als);
+ if (ret < 0)
+ return ret;
+ *val = le16_to_cpu(chan->address == LTR501_ALS_DATA1 ?
+ buf[0] : buf[1]);
+ return IIO_VAL_INT;
+ case IIO_PROXIMITY:
+ mutex_lock(&data->lock_ps);
+ ret = ltr501_read_ps(data);
+ mutex_unlock(&data->lock_ps);
+ if (ret < 0)
+ return ret;
+ *val = ret & LTR501_PS_DATA_MASK;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_INTENSITY:
+ if (data->als_contr & LTR501_CONTR_ALS_GAIN_MASK) {
+ *val = 0;
+ *val2 = 5000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ } else {
+ *val = 1;
+ *val2 = 0;
+ return IIO_VAL_INT;
+ }
+ case IIO_PROXIMITY:
+ i = (data->ps_contr & LTR501_CONTR_PS_GAIN_MASK) >>
+ LTR501_CONTR_PS_GAIN_SHIFT;
+ *val = ltr501_ps_gain[i][0];
+ *val2 = ltr501_ps_gain[i][1];
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ }
+ return -EINVAL;
+}
+
+static int ltr501_get_ps_gain_index(int val, int val2)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ltr501_ps_gain); i++)
+ if (val == ltr501_ps_gain[i][0] && val2 == ltr501_ps_gain[i][1])
+ return i;
+
+ return -1;
+}
+
+static int ltr501_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ltr501_data *data = iio_priv(indio_dev);
+ int i;
+
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_INTENSITY:
+ if (val == 0 && val2 == 5000)
+ data->als_contr |= LTR501_CONTR_ALS_GAIN_MASK;
+ else if (val == 1 && val2 == 0)
+ data->als_contr &= ~LTR501_CONTR_ALS_GAIN_MASK;
+ else
+ return -EINVAL;
+ return i2c_smbus_write_byte_data(data->client,
+ LTR501_ALS_CONTR, data->als_contr);
+ case IIO_PROXIMITY:
+ i = ltr501_get_ps_gain_index(val, val2);
+ if (i < 0)
+ return -EINVAL;
+ data->ps_contr &= ~LTR501_CONTR_PS_GAIN_MASK;
+ data->ps_contr |= i << LTR501_CONTR_PS_GAIN_SHIFT;
+ return i2c_smbus_write_byte_data(data->client,
+ LTR501_PS_CONTR, data->ps_contr);
+ default:
+ return -EINVAL;
+ }
+ }
+ return -EINVAL;
+}
+
+static IIO_CONST_ATTR(in_proximity_scale_available, "1 0.25 0.125 0.0625");
+static IIO_CONST_ATTR(in_intensity_scale_available, "1 0.005");
+
+static struct attribute *ltr501_attributes[] = {
+ &iio_const_attr_in_proximity_scale_available.dev_attr.attr,
+ &iio_const_attr_in_intensity_scale_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group ltr501_attribute_group = {
+ .attrs = ltr501_attributes,
+};
+
+static const struct iio_info ltr501_info = {
+ .read_raw = ltr501_read_raw,
+ .write_raw = ltr501_write_raw,
+ .attrs = &ltr501_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static int ltr501_write_contr(struct i2c_client *client, u8 als_val, u8 ps_val)
+{
+ int ret = i2c_smbus_write_byte_data(client, LTR501_ALS_CONTR, als_val);
+ if (ret < 0)
+ return ret;
+
+ return i2c_smbus_write_byte_data(client, LTR501_PS_CONTR, ps_val);
+}
+
+static irqreturn_t ltr501_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ltr501_data *data = iio_priv(indio_dev);
+ u16 buf[8];
+ __le16 als_buf[2];
+ u8 mask = 0;
+ int j = 0;
+ int ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ /* figure out which data needs to be ready */
+ if (test_bit(0, indio_dev->active_scan_mask) ||
+ test_bit(1, indio_dev->active_scan_mask))
+ mask |= LTR501_STATUS_ALS_RDY;
+ if (test_bit(2, indio_dev->active_scan_mask))
+ mask |= LTR501_STATUS_PS_RDY;
+
+ ret = ltr501_drdy(data, mask);
+ if (ret < 0)
+ goto done;
+
+ if (mask & LTR501_STATUS_ALS_RDY) {
+ ret = i2c_smbus_read_i2c_block_data(data->client,
+ LTR501_ALS_DATA1, sizeof(als_buf), (u8 *) als_buf);
+ if (ret < 0)
+ return ret;
+ if (test_bit(0, indio_dev->active_scan_mask))
+ buf[j++] = le16_to_cpu(als_buf[1]);
+ if (test_bit(1, indio_dev->active_scan_mask))
+ buf[j++] = le16_to_cpu(als_buf[0]);
+ }
+
+ if (mask & LTR501_STATUS_PS_RDY) {
+ ret = i2c_smbus_read_word_data(data->client, LTR501_PS_DATA);
+ if (ret < 0)
+ goto done;
+ buf[j++] = ret & LTR501_PS_DATA_MASK;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, buf,
+ iio_get_time_ns());
+
+done:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int ltr501_init(struct ltr501_data *data)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, LTR501_ALS_CONTR);
+ if (ret < 0)
+ return ret;
+ data->als_contr = ret | LTR501_CONTR_ACTIVE;
+
+ ret = i2c_smbus_read_byte_data(data->client, LTR501_PS_CONTR);
+ if (ret < 0)
+ return ret;
+ data->ps_contr = ret | LTR501_CONTR_ACTIVE;
+
+ return ltr501_write_contr(data->client, data->als_contr,
+ data->ps_contr);
+}
+
+static int ltr501_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ltr501_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+ mutex_init(&data->lock_als);
+ mutex_init(&data->lock_ps);
+
+ ret = i2c_smbus_read_byte_data(data->client, LTR501_PART_ID);
+ if (ret < 0)
+ return ret;
+ if ((ret >> 4) != 0x8)
+ return -ENODEV;
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->info = &ltr501_info;
+ indio_dev->channels = ltr501_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ltr501_channels);
+ indio_dev->name = LTR501_DRV_NAME;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = ltr501_init(data);
+ if (ret < 0)
+ return ret;
+
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ ltr501_trigger_handler, NULL);
+ if (ret)
+ return ret;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_unreg_buffer;
+
+ return 0;
+
+error_unreg_buffer:
+ iio_triggered_buffer_cleanup(indio_dev);
+ return ret;
+}
+
+static int ltr501_powerdown(struct ltr501_data *data)
+{
+ return ltr501_write_contr(data->client,
+ data->als_contr & ~LTR501_CONTR_ACTIVE,
+ data->ps_contr & ~LTR501_CONTR_ACTIVE);
+}
+
+static int ltr501_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+ ltr501_powerdown(iio_priv(indio_dev));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ltr501_suspend(struct device *dev)
+{
+ struct ltr501_data *data = iio_priv(i2c_get_clientdata(
+ to_i2c_client(dev)));
+ return ltr501_powerdown(data);
+}
+
+static int ltr501_resume(struct device *dev)
+{
+ struct ltr501_data *data = iio_priv(i2c_get_clientdata(
+ to_i2c_client(dev)));
+
+ return ltr501_write_contr(data->client, data->als_contr,
+ data->ps_contr);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume);
+
+static const struct i2c_device_id ltr501_id[] = {
+ { "ltr501", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ltr501_id);
+
+static struct i2c_driver ltr501_driver = {
+ .driver = {
+ .name = LTR501_DRV_NAME,
+ .pm = &ltr501_pm_ops,
+ .owner = THIS_MODULE,
+ },
+ .probe = ltr501_probe,
+ .remove = ltr501_remove,
+ .id_table = ltr501_id,
+};
+
+module_i2c_driver(ltr501_driver);
+
+MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
+MODULE_DESCRIPTION("Lite-On LTR501 ambient light and proximity sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c
index 887fecf1f9bb..fe063a0a21cd 100644
--- a/drivers/iio/light/tcs3472.c
+++ b/drivers/iio/light/tcs3472.c
@@ -179,7 +179,6 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct tcs3472_data *data = iio_priv(indio_dev);
- int len = 0;
int i, j = 0;
int ret = tcs3472_req_data(data);
@@ -194,7 +193,6 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p)
goto done;
data->buffer[j++] = ret;
- len += 2;
}
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index 05423543f89d..74866d1efd1b 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -513,6 +513,7 @@ static int ak8975_probe(struct i2c_client *client,
indio_dev->channels = ak8975_channels;
indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
indio_dev->info = &ak8975_info;
+ indio_dev->name = id->name;
indio_dev->modes = INDIO_DIRECT_MODE;
err = iio_device_register(indio_dev);
diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c
index f66955fb3509..8b77782474d7 100644
--- a/drivers/iio/magnetometer/mag3110.c
+++ b/drivers/iio/magnetometer/mag3110.c
@@ -183,9 +183,17 @@ static int mag3110_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
- *val = 0;
- *val2 = 1000;
- return IIO_VAL_INT_PLUS_MICRO;
+ switch (chan->type) {
+ case IIO_MAGN:
+ *val = 0;
+ *val2 = 1000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_TEMP:
+ *val = 1000;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
case IIO_CHAN_INFO_SAMP_FREQ:
i = data->ctrl_reg1 >> MAG3110_CTRL_DR_SHIFT;
*val = mag3110_samp_freq[i][0];
@@ -270,7 +278,8 @@ static const struct iio_chan_spec mag3110_channels[] = {
MAG3110_CHANNEL(Z, 2),
{
.type = IIO_TEMP,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 3,
.scan_type = {
.sign = 's',
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index a8b9cae5c173..d88ff17fedb2 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -5,6 +5,20 @@
menu "Pressure sensors"
+config HID_SENSOR_PRESS
+ depends on HID_SENSOR_HUB
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ select HID_SENSOR_IIO_COMMON
+ select HID_SENSOR_IIO_TRIGGER
+ tristate "HID PRESS"
+ help
+ Say yes here to build support for the HID SENSOR
+ Pressure driver
+
+ To compile this driver as a module, choose M here: the module
+ will be called hid-sensor-press.
+
config MPL3115
tristate "Freescale MPL3115A2 pressure sensor driver"
depends on I2C
@@ -26,7 +40,7 @@ config IIO_ST_PRESS
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
help
Say yes here to build support for STMicroelectronics pressure
- sensors: LPS001WP, LPS331AP.
+ sensors: LPS001WP, LPS25H, LPS331AP.
This driver can also be built as a module. If so, these modules
will be created:
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index 42bb9fcf5436..4a57bf65b04b 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -3,6 +3,7 @@
#
# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o
obj-$(CONFIG_MPL3115) += mpl3115.o
obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
st_pressure-y := st_pressure_core.o
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
new file mode 100644
index 000000000000..e0e6409aa94e
--- /dev/null
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -0,0 +1,376 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.
+ *
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/hid-sensor-hub.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include "../common/hid-sensors/hid-sensor-trigger.h"
+
+#define CHANNEL_SCAN_INDEX_PRESSURE 0
+
+struct press_state {
+ struct hid_sensor_hub_callbacks callbacks;
+ struct hid_sensor_common common_attributes;
+ struct hid_sensor_hub_attribute_info press_attr;
+ u32 press_data;
+};
+
+/* Channel definitions */
+static const struct iio_chan_spec press_channels[] = {
+ {
+ .type = IIO_PRESSURE,
+ .modified = 1,
+ .channel2 = IIO_NO_MOD,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
+ .scan_index = CHANNEL_SCAN_INDEX_PRESSURE,
+ }
+};
+
+/* Adjust channel real bits based on report descriptor */
+static void press_adjust_channel_bit_mask(struct iio_chan_spec *channels,
+ int channel, int size)
+{
+ channels[channel].scan_type.sign = 's';
+ /* Real storage bits will change based on the report desc. */
+ channels[channel].scan_type.realbits = size * 8;
+ /* Maximum size of a sample to capture is u32 */
+ channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+/* Channel read_raw handler */
+static int press_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2,
+ long mask)
+{
+ struct press_state *press_state = iio_priv(indio_dev);
+ int report_id = -1;
+ u32 address;
+ int ret;
+ int ret_type;
+
+ *val = 0;
+ *val2 = 0;
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->scan_index) {
+ case CHANNEL_SCAN_INDEX_PRESSURE:
+ report_id = press_state->press_attr.report_id;
+ address =
+ HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE;
+ break;
+ default:
+ report_id = -1;
+ break;
+ }
+ if (report_id >= 0)
+ *val = sensor_hub_input_attr_get_raw_value(
+ press_state->common_attributes.hsdev,
+ HID_USAGE_SENSOR_PRESSURE, address,
+ report_id);
+ else {
+ *val = 0;
+ return -EINVAL;
+ }
+ ret_type = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ *val = press_state->press_attr.units;
+ ret_type = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = hid_sensor_convert_exponent(
+ press_state->press_attr.unit_expo);
+ ret_type = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = hid_sensor_read_samp_freq_value(
+ &press_state->common_attributes, val, val2);
+ ret_type = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ case IIO_CHAN_INFO_HYSTERESIS:
+ ret = hid_sensor_read_raw_hyst_value(
+ &press_state->common_attributes, val, val2);
+ ret_type = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ default:
+ ret_type = -EINVAL;
+ break;
+ }
+
+ return ret_type;
+}
+
+/* Channel write_raw handler */
+static int press_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct press_state *press_state = iio_priv(indio_dev);
+ int ret = 0;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = hid_sensor_write_samp_freq_value(
+ &press_state->common_attributes, val, val2);
+ break;
+ case IIO_CHAN_INFO_HYSTERESIS:
+ ret = hid_sensor_write_raw_hyst_value(
+ &press_state->common_attributes, val, val2);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct iio_info press_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &press_read_raw,
+ .write_raw = &press_write_raw,
+};
+
+/* Function to push data to buffer */
+static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,
+ int len)
+{
+ dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
+ iio_push_to_buffers(indio_dev, data);
+}
+
+/* Callback handler to send event after all samples are received and captured */
+static int press_proc_event(struct hid_sensor_hub_device *hsdev,
+ unsigned usage_id,
+ void *priv)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(priv);
+ struct press_state *press_state = iio_priv(indio_dev);
+
+ dev_dbg(&indio_dev->dev, "press_proc_event [%d]\n",
+ press_state->common_attributes.data_ready);
+ if (press_state->common_attributes.data_ready)
+ hid_sensor_push_data(indio_dev,
+ &press_state->press_data,
+ sizeof(press_state->press_data));
+
+ return 0;
+}
+
+/* Capture samples in local storage */
+static int press_capture_sample(struct hid_sensor_hub_device *hsdev,
+ unsigned usage_id,
+ size_t raw_len, char *raw_data,
+ void *priv)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(priv);
+ struct press_state *press_state = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ switch (usage_id) {
+ case HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE:
+ press_state->press_data = *(u32 *)raw_data;
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/* Parse report which is specific to an usage id*/
+static int press_parse_report(struct platform_device *pdev,
+ struct hid_sensor_hub_device *hsdev,
+ struct iio_chan_spec *channels,
+ unsigned usage_id,
+ struct press_state *st)
+{
+ int ret;
+
+ ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE,
+ &st->press_attr);
+ if (ret < 0)
+ return ret;
+ press_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESSURE,
+ st->press_attr.size);
+
+ dev_dbg(&pdev->dev, "press %x:%x\n", st->press_attr.index,
+ st->press_attr.report_id);
+
+ /* Set Sensitivity field ids, when there is no individual modifier */
+ if (st->common_attributes.sensitivity.index < 0) {
+ sensor_hub_input_get_attribute_info(hsdev,
+ HID_FEATURE_REPORT, usage_id,
+ HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
+ HID_USAGE_SENSOR_DATA_ATMOSPHERIC_PRESSURE,
+ &st->common_attributes.sensitivity);
+ dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
+ st->common_attributes.sensitivity.index,
+ st->common_attributes.sensitivity.report_id);
+ }
+ return ret;
+}
+
+/* Function to initialize the processing for usage id */
+static int hid_press_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ static const char *name = "press";
+ struct iio_dev *indio_dev;
+ struct press_state *press_state;
+ struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+ struct iio_chan_spec *channels;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev,
+ sizeof(struct press_state));
+ if (!indio_dev)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, indio_dev);
+
+ press_state = iio_priv(indio_dev);
+ press_state->common_attributes.hsdev = hsdev;
+ press_state->common_attributes.pdev = pdev;
+
+ ret = hid_sensor_parse_common_attributes(hsdev,
+ HID_USAGE_SENSOR_PRESSURE,
+ &press_state->common_attributes);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to setup common attributes\n");
+ return ret;
+ }
+
+ channels = kmemdup(press_channels, sizeof(press_channels), GFP_KERNEL);
+ if (!channels) {
+ dev_err(&pdev->dev, "failed to duplicate channels\n");
+ return -ENOMEM;
+ }
+
+ ret = press_parse_report(pdev, hsdev, channels,
+ HID_USAGE_SENSOR_PRESSURE, press_state);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to setup attributes\n");
+ goto error_free_dev_mem;
+ }
+
+ indio_dev->channels = channels;
+ indio_dev->num_channels =
+ ARRAY_SIZE(press_channels);
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->info = &press_info;
+ indio_dev->name = name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+ NULL, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
+ goto error_free_dev_mem;
+ }
+ press_state->common_attributes.data_ready = false;
+ ret = hid_sensor_setup_trigger(indio_dev, name,
+ &press_state->common_attributes);
+ if (ret) {
+ dev_err(&pdev->dev, "trigger setup failed\n");
+ goto error_unreg_buffer_funcs;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "device register failed\n");
+ goto error_remove_trigger;
+ }
+
+ press_state->callbacks.send_event = press_proc_event;
+ press_state->callbacks.capture_sample = press_capture_sample;
+ press_state->callbacks.pdev = pdev;
+ ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PRESSURE,
+ &press_state->callbacks);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "callback reg failed\n");
+ goto error_iio_unreg;
+ }
+
+ return ret;
+
+error_iio_unreg:
+ iio_device_unregister(indio_dev);
+error_remove_trigger:
+ hid_sensor_remove_trigger(&press_state->common_attributes);
+error_unreg_buffer_funcs:
+ iio_triggered_buffer_cleanup(indio_dev);
+error_free_dev_mem:
+ kfree(indio_dev->channels);
+ return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int hid_press_remove(struct platform_device *pdev)
+{
+ struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct press_state *press_state = iio_priv(indio_dev);
+
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
+ iio_device_unregister(indio_dev);
+ hid_sensor_remove_trigger(&press_state->common_attributes);
+ iio_triggered_buffer_cleanup(indio_dev);
+ kfree(indio_dev->channels);
+
+ return 0;
+}
+
+static struct platform_device_id hid_press_ids[] = {
+ {
+ /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+ .name = "HID-SENSOR-200031",
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_press_ids);
+
+static struct platform_driver hid_press_platform_driver = {
+ .id_table = hid_press_ids,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = hid_press_probe,
+ .remove = hid_press_remove,
+};
+module_platform_driver(hid_press_platform_driver);
+
+MODULE_DESCRIPTION("HID Sensor Pressure");
+MODULE_AUTHOR("Archana Patni <archana.patni@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c
index ac8c8ab723e5..ba6d0c520e63 100644
--- a/drivers/iio/pressure/mpl3115.c
+++ b/drivers/iio/pressure/mpl3115.c
@@ -77,7 +77,7 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct mpl3115_data *data = iio_priv(indio_dev);
- s32 tmp = 0;
+ __be32 tmp = 0;
int ret;
switch (mask) {
diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h
index 049c21acf1f0..242943c0c4e4 100644
--- a/drivers/iio/pressure/st_pressure.h
+++ b/drivers/iio/pressure/st_pressure.h
@@ -15,6 +15,7 @@
#include <linux/iio/common/st_sensors.h>
#define LPS001WP_PRESS_DEV_NAME "lps001wp"
+#define LPS25H_PRESS_DEV_NAME "lps25h"
#define LPS331AP_PRESS_DEV_NAME "lps331ap"
/**
diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c
index 58083f9d51c5..7418768ed49c 100644
--- a/drivers/iio/pressure/st_pressure_core.c
+++ b/drivers/iio/pressure/st_pressure_core.c
@@ -40,6 +40,9 @@
/* FULLSCALE */
#define ST_PRESS_FS_AVL_1260MB 1260
+#define ST_PRESS_1_OUT_XL_ADDR 0x28
+#define ST_TEMP_1_OUT_L_ADDR 0x2b
+
/* CUSTOM VALUES FOR LPS331AP SENSOR */
#define ST_PRESS_LPS331AP_WAI_EXP 0xbb
#define ST_PRESS_LPS331AP_ODR_ADDR 0x20
@@ -62,8 +65,6 @@
#define ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK 0x20
#define ST_PRESS_LPS331AP_MULTIREAD_BIT true
#define ST_PRESS_LPS331AP_TEMP_OFFSET 42500
-#define ST_PRESS_LPS331AP_OUT_XL_ADDR 0x28
-#define ST_TEMP_LPS331AP_OUT_L_ADDR 0x2b
/* CUSTOM VALUES FOR LPS001WP SENSOR */
#define ST_PRESS_LPS001WP_WAI_EXP 0xba
@@ -80,11 +81,36 @@
#define ST_PRESS_LPS001WP_OUT_L_ADDR 0x28
#define ST_TEMP_LPS001WP_OUT_L_ADDR 0x2a
-static const struct iio_chan_spec st_press_lps331ap_channels[] = {
+/* CUSTOM VALUES FOR LPS25H SENSOR */
+#define ST_PRESS_LPS25H_WAI_EXP 0xbd
+#define ST_PRESS_LPS25H_ODR_ADDR 0x20
+#define ST_PRESS_LPS25H_ODR_MASK 0x70
+#define ST_PRESS_LPS25H_ODR_AVL_1HZ_VAL 0x01
+#define ST_PRESS_LPS25H_ODR_AVL_7HZ_VAL 0x02
+#define ST_PRESS_LPS25H_ODR_AVL_13HZ_VAL 0x03
+#define ST_PRESS_LPS25H_ODR_AVL_25HZ_VAL 0x04
+#define ST_PRESS_LPS25H_PW_ADDR 0x20
+#define ST_PRESS_LPS25H_PW_MASK 0x80
+#define ST_PRESS_LPS25H_FS_ADDR 0x00
+#define ST_PRESS_LPS25H_FS_MASK 0x00
+#define ST_PRESS_LPS25H_FS_AVL_1260_VAL 0x00
+#define ST_PRESS_LPS25H_FS_AVL_1260_GAIN ST_PRESS_KPASCAL_NANO_SCALE
+#define ST_PRESS_LPS25H_FS_AVL_TEMP_GAIN ST_PRESS_CELSIUS_NANO_SCALE
+#define ST_PRESS_LPS25H_BDU_ADDR 0x20
+#define ST_PRESS_LPS25H_BDU_MASK 0x04
+#define ST_PRESS_LPS25H_DRDY_IRQ_ADDR 0x23
+#define ST_PRESS_LPS25H_DRDY_IRQ_INT1_MASK 0x01
+#define ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK 0x10
+#define ST_PRESS_LPS25H_MULTIREAD_BIT true
+#define ST_PRESS_LPS25H_TEMP_OFFSET 42500
+#define ST_PRESS_LPS25H_OUT_XL_ADDR 0x28
+#define ST_TEMP_LPS25H_OUT_L_ADDR 0x2b
+
+static const struct iio_chan_spec st_press_1_channels[] = {
{
.type = IIO_PRESSURE,
.channel2 = IIO_NO_MOD,
- .address = ST_PRESS_LPS331AP_OUT_XL_ADDR,
+ .address = ST_PRESS_1_OUT_XL_ADDR,
.scan_index = ST_SENSORS_SCAN_X,
.scan_type = {
.sign = 'u',
@@ -99,7 +125,7 @@ static const struct iio_chan_spec st_press_lps331ap_channels[] = {
{
.type = IIO_TEMP,
.channel2 = IIO_NO_MOD,
- .address = ST_TEMP_LPS331AP_OUT_L_ADDR,
+ .address = ST_TEMP_1_OUT_L_ADDR,
.scan_index = -1,
.scan_type = {
.sign = 'u',
@@ -156,8 +182,8 @@ static const struct st_sensors st_press_sensors[] = {
.sensors_supported = {
[0] = LPS331AP_PRESS_DEV_NAME,
},
- .ch = (struct iio_chan_spec *)st_press_lps331ap_channels,
- .num_ch = ARRAY_SIZE(st_press_lps331ap_channels),
+ .ch = (struct iio_chan_spec *)st_press_1_channels,
+ .num_ch = ARRAY_SIZE(st_press_1_channels),
.odr = {
.addr = ST_PRESS_LPS331AP_ODR_ADDR,
.mask = ST_PRESS_LPS331AP_ODR_MASK,
@@ -233,6 +259,53 @@ static const struct st_sensors st_press_sensors[] = {
.multi_read_bit = ST_PRESS_LPS001WP_MULTIREAD_BIT,
.bootime = 2,
},
+ {
+ .wai = ST_PRESS_LPS25H_WAI_EXP,
+ .sensors_supported = {
+ [0] = LPS25H_PRESS_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_press_1_channels,
+ .num_ch = ARRAY_SIZE(st_press_1_channels),
+ .odr = {
+ .addr = ST_PRESS_LPS25H_ODR_ADDR,
+ .mask = ST_PRESS_LPS25H_ODR_MASK,
+ .odr_avl = {
+ { 1, ST_PRESS_LPS25H_ODR_AVL_1HZ_VAL, },
+ { 7, ST_PRESS_LPS25H_ODR_AVL_7HZ_VAL, },
+ { 13, ST_PRESS_LPS25H_ODR_AVL_13HZ_VAL, },
+ { 25, ST_PRESS_LPS25H_ODR_AVL_25HZ_VAL, },
+ },
+ },
+ .pw = {
+ .addr = ST_PRESS_LPS25H_PW_ADDR,
+ .mask = ST_PRESS_LPS25H_PW_MASK,
+ .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
+ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+ },
+ .fs = {
+ .addr = ST_PRESS_LPS25H_FS_ADDR,
+ .mask = ST_PRESS_LPS25H_FS_MASK,
+ .fs_avl = {
+ [0] = {
+ .num = ST_PRESS_FS_AVL_1260MB,
+ .value = ST_PRESS_LPS25H_FS_AVL_1260_VAL,
+ .gain = ST_PRESS_LPS25H_FS_AVL_1260_GAIN,
+ .gain2 = ST_PRESS_LPS25H_FS_AVL_TEMP_GAIN,
+ },
+ },
+ },
+ .bdu = {
+ .addr = ST_PRESS_LPS25H_BDU_ADDR,
+ .mask = ST_PRESS_LPS25H_BDU_MASK,
+ },
+ .drdy_irq = {
+ .addr = ST_PRESS_LPS25H_DRDY_IRQ_ADDR,
+ .mask_int1 = ST_PRESS_LPS25H_DRDY_IRQ_INT1_MASK,
+ .mask_int2 = ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK,
+ },
+ .multi_read_bit = ST_PRESS_LPS25H_MULTIREAD_BIT,
+ .bootime = 2,
+ },
};
static int st_press_read_raw(struct iio_dev *indio_dev,
diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
index 51eab7fcb194..3cd73e39b840 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -50,6 +50,7 @@ static int st_press_i2c_remove(struct i2c_client *client)
static const struct i2c_device_id st_press_id_table[] = {
{ LPS001WP_PRESS_DEV_NAME },
+ { LPS25H_PRESS_DEV_NAME },
{ LPS331AP_PRESS_DEV_NAME },
{},
};
diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c
index 27322af6d665..f45d430ec529 100644
--- a/drivers/iio/pressure/st_pressure_spi.c
+++ b/drivers/iio/pressure/st_pressure_spi.c
@@ -49,6 +49,7 @@ static int st_press_spi_remove(struct spi_device *spi)
static const struct spi_device_id st_press_id_table[] = {
{ LPS001WP_PRESS_DEV_NAME },
+ { LPS25H_PRESS_DEV_NAME },
{ LPS331AP_PRESS_DEV_NAME },
{},
};
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index e81c5547e647..f9c12e92fdd6 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -53,8 +53,8 @@
#include "user.h"
#define DRV_NAME MLX4_IB_DRV_NAME
-#define DRV_VERSION "1.0"
-#define DRV_RELDATE "April 4, 2008"
+#define DRV_VERSION "2.2-1"
+#define DRV_RELDATE "Feb 2014"
#define MLX4_IB_FLOW_MAX_PRIO 0xFFF
#define MLX4_IB_FLOW_QPN_MASK 0xFFFFFF
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index aa03e732b6a8..bf900579ac08 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -46,8 +46,8 @@
#include "mlx5_ib.h"
#define DRIVER_NAME "mlx5_ib"
-#define DRIVER_VERSION "1.0"
-#define DRIVER_RELDATE "June 2013"
+#define DRIVER_VERSION "2.2-1"
+#define DRIVER_RELDATE "Feb 2014"
MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
MODULE_DESCRIPTION("Mellanox Connect-IB HCA IB driver");
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index d18d08a076e8..8ee228e9ab5a 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -492,12 +492,11 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
isert_conn->state = ISER_CONN_INIT;
INIT_LIST_HEAD(&isert_conn->conn_accept_node);
init_completion(&isert_conn->conn_login_comp);
- init_waitqueue_head(&isert_conn->conn_wait);
- init_waitqueue_head(&isert_conn->conn_wait_comp_err);
+ init_completion(&isert_conn->conn_wait);
+ init_completion(&isert_conn->conn_wait_comp_err);
kref_init(&isert_conn->conn_kref);
kref_get(&isert_conn->conn_kref);
mutex_init(&isert_conn->conn_mutex);
- mutex_init(&isert_conn->conn_comp_mutex);
spin_lock_init(&isert_conn->conn_lock);
cma_id->context = isert_conn;
@@ -688,11 +687,11 @@ isert_disconnect_work(struct work_struct *work)
pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
mutex_lock(&isert_conn->conn_mutex);
- isert_conn->state = ISER_CONN_DOWN;
+ if (isert_conn->state == ISER_CONN_UP)
+ isert_conn->state = ISER_CONN_TERMINATING;
if (isert_conn->post_recv_buf_count == 0 &&
atomic_read(&isert_conn->post_send_buf_count) == 0) {
- pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");
mutex_unlock(&isert_conn->conn_mutex);
goto wake_up;
}
@@ -712,7 +711,7 @@ isert_disconnect_work(struct work_struct *work)
mutex_unlock(&isert_conn->conn_mutex);
wake_up:
- wake_up(&isert_conn->conn_wait);
+ complete(&isert_conn->conn_wait);
isert_put_conn(isert_conn);
}
@@ -888,16 +887,17 @@ isert_init_send_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
* Coalesce send completion interrupts by only setting IB_SEND_SIGNALED
* bit for every ISERT_COMP_BATCH_COUNT number of ib_post_send() calls.
*/
- mutex_lock(&isert_conn->conn_comp_mutex);
- if (coalesce &&
+ mutex_lock(&isert_conn->conn_mutex);
+ if (coalesce && isert_conn->state == ISER_CONN_UP &&
++isert_conn->conn_comp_batch < ISERT_COMP_BATCH_COUNT) {
+ tx_desc->llnode_active = true;
llist_add(&tx_desc->comp_llnode, &isert_conn->conn_comp_llist);
- mutex_unlock(&isert_conn->conn_comp_mutex);
+ mutex_unlock(&isert_conn->conn_mutex);
return;
}
isert_conn->conn_comp_batch = 0;
tx_desc->comp_llnode_batch = llist_del_all(&isert_conn->conn_comp_llist);
- mutex_unlock(&isert_conn->conn_comp_mutex);
+ mutex_unlock(&isert_conn->conn_mutex);
send_wr->send_flags = IB_SEND_SIGNALED;
}
@@ -1464,7 +1464,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
case ISCSI_OP_SCSI_CMD:
spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node))
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
if (cmd->data_direction == DMA_TO_DEVICE)
@@ -1476,7 +1476,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
case ISCSI_OP_SCSI_TMFUNC:
spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node))
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
transport_generic_free_cmd(&cmd->se_cmd, 0);
@@ -1486,7 +1486,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
case ISCSI_OP_TEXT:
spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node))
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
/*
@@ -1549,6 +1549,7 @@ isert_completion_rdma_read(struct iser_tx_desc *tx_desc,
iscsit_stop_dataout_timer(cmd);
device->unreg_rdma_mem(isert_cmd, isert_conn);
cmd->write_data_done = wr->cur_rdma_length;
+ wr->send_wr_num = 0;
pr_debug("Cmd: %p RDMA_READ comp calling execute_cmd\n", isert_cmd);
spin_lock_bh(&cmd->istate_lock);
@@ -1589,7 +1590,7 @@ isert_do_control_comp(struct work_struct *work)
pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n");
/*
* Call atomic_dec(&isert_conn->post_send_buf_count)
- * from isert_free_conn()
+ * from isert_wait_conn()
*/
isert_conn->logout_posted = true;
iscsit_logout_post_handler(cmd, cmd->conn);
@@ -1613,6 +1614,7 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
struct ib_device *ib_dev)
{
struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
+ struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
if (cmd->i_state == ISTATE_SEND_TASKMGTRSP ||
cmd->i_state == ISTATE_SEND_LOGOUTRSP ||
@@ -1624,7 +1626,7 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
queue_work(isert_comp_wq, &isert_cmd->comp_work);
return;
}
- atomic_dec(&isert_conn->post_send_buf_count);
+ atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
cmd->i_state = ISTATE_SENT_STATUS;
isert_completion_put(tx_desc, isert_cmd, ib_dev);
@@ -1662,7 +1664,7 @@ __isert_send_completion(struct iser_tx_desc *tx_desc,
case ISER_IB_RDMA_READ:
pr_debug("isert_send_completion: Got ISER_IB_RDMA_READ:\n");
- atomic_dec(&isert_conn->post_send_buf_count);
+ atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);
isert_completion_rdma_read(tx_desc, isert_cmd);
break;
default:
@@ -1691,31 +1693,76 @@ isert_send_completion(struct iser_tx_desc *tx_desc,
}
static void
-isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
+isert_cq_drain_comp_llist(struct isert_conn *isert_conn, struct ib_device *ib_dev)
+{
+ struct llist_node *llnode;
+ struct isert_rdma_wr *wr;
+ struct iser_tx_desc *t;
+
+ mutex_lock(&isert_conn->conn_mutex);
+ llnode = llist_del_all(&isert_conn->conn_comp_llist);
+ isert_conn->conn_comp_batch = 0;
+ mutex_unlock(&isert_conn->conn_mutex);
+
+ while (llnode) {
+ t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
+ llnode = llist_next(llnode);
+ wr = &t->isert_cmd->rdma_wr;
+
+ atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
+ isert_completion_put(t, t->isert_cmd, ib_dev);
+ }
+}
+
+static void
+isert_cq_tx_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
{
struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+ struct llist_node *llnode = tx_desc->comp_llnode_batch;
+ struct isert_rdma_wr *wr;
+ struct iser_tx_desc *t;
- if (tx_desc) {
- struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+ while (llnode) {
+ t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
+ llnode = llist_next(llnode);
+ wr = &t->isert_cmd->rdma_wr;
- if (!isert_cmd)
- isert_unmap_tx_desc(tx_desc, ib_dev);
- else
- isert_completion_put(tx_desc, isert_cmd, ib_dev);
+ atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
+ isert_completion_put(t, t->isert_cmd, ib_dev);
}
+ tx_desc->comp_llnode_batch = NULL;
- if (isert_conn->post_recv_buf_count == 0 &&
- atomic_read(&isert_conn->post_send_buf_count) == 0) {
- pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
- pr_debug("Calling wake_up from isert_cq_comp_err\n");
+ if (!isert_cmd)
+ isert_unmap_tx_desc(tx_desc, ib_dev);
+ else
+ isert_completion_put(tx_desc, isert_cmd, ib_dev);
+}
- mutex_lock(&isert_conn->conn_mutex);
- if (isert_conn->state != ISER_CONN_DOWN)
- isert_conn->state = ISER_CONN_TERMINATING;
- mutex_unlock(&isert_conn->conn_mutex);
+static void
+isert_cq_rx_comp_err(struct isert_conn *isert_conn)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct iscsi_conn *conn = isert_conn->conn;
- wake_up(&isert_conn->conn_wait_comp_err);
+ if (isert_conn->post_recv_buf_count)
+ return;
+
+ isert_cq_drain_comp_llist(isert_conn, ib_dev);
+
+ if (conn->sess) {
+ target_sess_cmd_list_set_waiting(conn->sess->se_sess);
+ target_wait_for_sess_cmds(conn->sess->se_sess);
}
+
+ while (atomic_read(&isert_conn->post_send_buf_count))
+ msleep(3000);
+
+ mutex_lock(&isert_conn->conn_mutex);
+ isert_conn->state = ISER_CONN_DOWN;
+ mutex_unlock(&isert_conn->conn_mutex);
+
+ complete(&isert_conn->conn_wait_comp_err);
}
static void
@@ -1740,8 +1787,14 @@ isert_cq_tx_work(struct work_struct *work)
pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
pr_debug("TX wc.status: 0x%08x\n", wc.status);
pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err);
- atomic_dec(&isert_conn->post_send_buf_count);
- isert_cq_comp_err(tx_desc, isert_conn);
+
+ if (wc.wr_id != ISER_FASTREG_LI_WRID) {
+ if (tx_desc->llnode_active)
+ continue;
+
+ atomic_dec(&isert_conn->post_send_buf_count);
+ isert_cq_tx_comp_err(tx_desc, isert_conn);
+ }
}
}
@@ -1784,7 +1837,7 @@ isert_cq_rx_work(struct work_struct *work)
wc.vendor_err);
}
isert_conn->post_recv_buf_count--;
- isert_cq_comp_err(NULL, isert_conn);
+ isert_cq_rx_comp_err(isert_conn);
}
}
@@ -2202,6 +2255,7 @@ isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,
if (!fr_desc->valid) {
memset(&inv_wr, 0, sizeof(inv_wr));
+ inv_wr.wr_id = ISER_FASTREG_LI_WRID;
inv_wr.opcode = IB_WR_LOCAL_INV;
inv_wr.ex.invalidate_rkey = fr_desc->data_mr->rkey;
wr = &inv_wr;
@@ -2212,6 +2266,7 @@ isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,
/* Prepare FASTREG WR */
memset(&fr_wr, 0, sizeof(fr_wr));
+ fr_wr.wr_id = ISER_FASTREG_LI_WRID;
fr_wr.opcode = IB_WR_FAST_REG_MR;
fr_wr.wr.fast_reg.iova_start =
fr_desc->data_frpl->page_list[0] + page_off;
@@ -2377,12 +2432,12 @@ isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
isert_init_send_wr(isert_conn, isert_cmd,
&isert_cmd->tx_desc.send_wr, true);
- atomic_inc(&isert_conn->post_send_buf_count);
+ atomic_add(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
if (rc) {
pr_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n");
- atomic_dec(&isert_conn->post_send_buf_count);
+ atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
}
pr_debug("Cmd: %p posted RDMA_WRITE + Response for iSER Data READ\n",
isert_cmd);
@@ -2410,12 +2465,12 @@ isert_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, bool recovery)
return rc;
}
- atomic_inc(&isert_conn->post_send_buf_count);
+ atomic_add(wr->send_wr_num, &isert_conn->post_send_buf_count);
rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
if (rc) {
pr_warn("ib_post_send() failed for IB_WR_RDMA_READ\n");
- atomic_dec(&isert_conn->post_send_buf_count);
+ atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);
}
pr_debug("Cmd: %p posted RDMA_READ memory for ISER Data WRITE\n",
isert_cmd);
@@ -2702,22 +2757,11 @@ isert_free_np(struct iscsi_np *np)
kfree(isert_np);
}
-static int isert_check_state(struct isert_conn *isert_conn, int state)
-{
- int ret;
-
- mutex_lock(&isert_conn->conn_mutex);
- ret = (isert_conn->state == state);
- mutex_unlock(&isert_conn->conn_mutex);
-
- return ret;
-}
-
-static void isert_free_conn(struct iscsi_conn *conn)
+static void isert_wait_conn(struct iscsi_conn *conn)
{
struct isert_conn *isert_conn = conn->context;
- pr_debug("isert_free_conn: Starting \n");
+ pr_debug("isert_wait_conn: Starting \n");
/*
* Decrement post_send_buf_count for special case when called
* from isert_do_control_comp() -> iscsit_logout_post_handler()
@@ -2727,38 +2771,29 @@ static void isert_free_conn(struct iscsi_conn *conn)
atomic_dec(&isert_conn->post_send_buf_count);
if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) {
- pr_debug("Calling rdma_disconnect from isert_free_conn\n");
+ pr_debug("Calling rdma_disconnect from isert_wait_conn\n");
rdma_disconnect(isert_conn->conn_cm_id);
}
/*
* Only wait for conn_wait_comp_err if the isert_conn made it
* into full feature phase..
*/
- if (isert_conn->state == ISER_CONN_UP) {
- pr_debug("isert_free_conn: Before wait_event comp_err %d\n",
- isert_conn->state);
- mutex_unlock(&isert_conn->conn_mutex);
-
- wait_event(isert_conn->conn_wait_comp_err,
- (isert_check_state(isert_conn, ISER_CONN_TERMINATING)));
-
- wait_event(isert_conn->conn_wait,
- (isert_check_state(isert_conn, ISER_CONN_DOWN)));
-
- isert_put_conn(isert_conn);
- return;
- }
if (isert_conn->state == ISER_CONN_INIT) {
mutex_unlock(&isert_conn->conn_mutex);
- isert_put_conn(isert_conn);
return;
}
- pr_debug("isert_free_conn: wait_event conn_wait %d\n",
- isert_conn->state);
+ if (isert_conn->state == ISER_CONN_UP)
+ isert_conn->state = ISER_CONN_TERMINATING;
mutex_unlock(&isert_conn->conn_mutex);
- wait_event(isert_conn->conn_wait,
- (isert_check_state(isert_conn, ISER_CONN_DOWN)));
+ wait_for_completion(&isert_conn->conn_wait_comp_err);
+
+ wait_for_completion(&isert_conn->conn_wait);
+}
+
+static void isert_free_conn(struct iscsi_conn *conn)
+{
+ struct isert_conn *isert_conn = conn->context;
isert_put_conn(isert_conn);
}
@@ -2771,6 +2806,7 @@ static struct iscsit_transport iser_target_transport = {
.iscsit_setup_np = isert_setup_np,
.iscsit_accept_np = isert_accept_np,
.iscsit_free_np = isert_free_np,
+ .iscsit_wait_conn = isert_wait_conn,
.iscsit_free_conn = isert_free_conn,
.iscsit_get_login_rx = isert_get_login_rx,
.iscsit_put_login_tx = isert_put_login_tx,
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h
index 708a069002f3..f6ae7f5dd408 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.h
+++ b/drivers/infiniband/ulp/isert/ib_isert.h
@@ -6,6 +6,7 @@
#define ISERT_RDMA_LISTEN_BACKLOG 10
#define ISCSI_ISER_SG_TABLESIZE 256
+#define ISER_FASTREG_LI_WRID 0xffffffffffffffffULL
enum isert_desc_type {
ISCSI_TX_CONTROL,
@@ -45,6 +46,7 @@ struct iser_tx_desc {
struct isert_cmd *isert_cmd;
struct llist_node *comp_llnode_batch;
struct llist_node comp_llnode;
+ bool llnode_active;
struct ib_send_wr send_wr;
} __packed;
@@ -116,8 +118,8 @@ struct isert_conn {
struct isert_device *conn_device;
struct work_struct conn_logout_work;
struct mutex conn_mutex;
- wait_queue_head_t conn_wait;
- wait_queue_head_t conn_wait_comp_err;
+ struct completion conn_wait;
+ struct completion conn_wait_comp_err;
struct kref conn_kref;
struct list_head conn_fr_pool;
int conn_fr_pool_size;
@@ -126,7 +128,6 @@ struct isert_conn {
#define ISERT_COMP_BATCH_COUNT 8
int conn_comp_batch;
struct llist_head conn_comp_llist;
- struct mutex conn_comp_mutex;
};
#define ISERT_MAX_CQ 64
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index a06e12552886..ce953d895f5b 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -954,11 +954,13 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;
error = input_ff_upload(dev, &effect, file);
+ if (error)
+ return error;
if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
return -EFAULT;
- return error;
+ return 0;
}
/* Multi-number variable-length handlers */
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index bb3b57bea8ba..5ef7fcf0e250 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -76,8 +76,18 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
+ int val;
- return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
+ mutex_lock(&kpad->gpio_lock);
+
+ if (kpad->dir[bank] & bit)
+ val = kpad->dat_out[bank];
+ else
+ val = adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank);
+
+ mutex_unlock(&kpad->gpio_lock);
+
+ return !!(val & bit);
}
static void adp5588_gpio_set_value(struct gpio_chip *chip,
diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c
index 7a04f54ef961..ef2e281b0a43 100644
--- a/drivers/input/misc/arizona-haptics.c
+++ b/drivers/input/misc/arizona-haptics.c
@@ -37,7 +37,6 @@ static void arizona_haptics_work(struct work_struct *work)
struct arizona_haptics,
work);
struct arizona *arizona = haptics->arizona;
- struct mutex *dapm_mutex = &arizona->dapm->card->dapm_mutex;
int ret;
if (!haptics->arizona->dapm) {
@@ -67,13 +66,10 @@ static void arizona_haptics_work(struct work_struct *work)
return;
}
- mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");
if (ret != 0) {
dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
ret);
- mutex_unlock(dapm_mutex);
return;
}
@@ -81,21 +77,14 @@ static void arizona_haptics_work(struct work_struct *work)
if (ret != 0) {
dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
ret);
- mutex_unlock(dapm_mutex);
return;
}
-
- mutex_unlock(dapm_mutex);
-
} else {
/* This disable sequence will be a noop if already enabled */
- mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS");
if (ret != 0) {
dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
ret);
- mutex_unlock(dapm_mutex);
return;
}
@@ -103,12 +92,9 @@ static void arizona_haptics_work(struct work_struct *work)
if (ret != 0) {
dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
ret);
- mutex_unlock(dapm_mutex);
return;
}
- mutex_unlock(dapm_mutex);
-
ret = regmap_update_bits(arizona->regmap,
ARIZONA_HAPTICS_CONTROL_1,
ARIZONA_HAP_CTRL_MASK,
@@ -155,16 +141,11 @@ static int arizona_haptics_play(struct input_dev *input, void *data,
static void arizona_haptics_close(struct input_dev *input)
{
struct arizona_haptics *haptics = input_get_drvdata(input);
- struct mutex *dapm_mutex = &haptics->arizona->dapm->card->dapm_mutex;
cancel_work_sync(&haptics->work);
- mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
if (haptics->arizona->dapm)
snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS");
-
- mutex_unlock(dapm_mutex);
}
static int arizona_haptics_probe(struct platform_device *pdev)
diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c
index 1f695f229ea8..184c8f21ab59 100644
--- a/drivers/input/misc/da9052_onkey.c
+++ b/drivers/input/misc/da9052_onkey.c
@@ -27,29 +27,32 @@ struct da9052_onkey {
static void da9052_onkey_query(struct da9052_onkey *onkey)
{
- int key_stat;
+ int ret;
- key_stat = da9052_reg_read(onkey->da9052, DA9052_EVENT_B_REG);
- if (key_stat < 0) {
+ ret = da9052_reg_read(onkey->da9052, DA9052_STATUS_A_REG);
+ if (ret < 0) {
dev_err(onkey->da9052->dev,
- "Failed to read onkey event %d\n", key_stat);
+ "Failed to read onkey event err=%d\n", ret);
} else {
/*
* Since interrupt for deassertion of ONKEY pin is not
* generated, onkey event state determines the onkey
* button state.
*/
- key_stat &= DA9052_EVENTB_ENONKEY;
- input_report_key(onkey->input, KEY_POWER, key_stat);
+ bool pressed = !(ret & DA9052_STATUSA_NONKEY);
+
+ input_report_key(onkey->input, KEY_POWER, pressed);
input_sync(onkey->input);
- }
- /*
- * Interrupt is generated only when the ONKEY pin is asserted.
- * Hence the deassertion of the pin is simulated through work queue.
- */
- if (key_stat)
- schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
+ /*
+ * Interrupt is generated only when the ONKEY pin
+ * is asserted. Hence the deassertion of the pin
+ * is simulated through work queue.
+ */
+ if (pressed)
+ schedule_delayed_work(&onkey->work,
+ msecs_to_jiffies(50));
+ }
}
static void da9052_onkey_work(struct work_struct *work)
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
index 87095e2f5153..8af34ffe208b 100644
--- a/drivers/input/mouse/cypress_ps2.c
+++ b/drivers/input/mouse/cypress_ps2.c
@@ -409,7 +409,6 @@ static int cypress_set_input_params(struct input_dev *input,
__clear_bit(REL_X, input->relbit);
__clear_bit(REL_Y, input->relbit);
- __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
__set_bit(EV_KEY, input->evbit);
__set_bit(BTN_LEFT, input->keybit);
__set_bit(BTN_RIGHT, input->keybit);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 26386f9d2569..d8d49d10f9bb 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -265,11 +265,22 @@ static int synaptics_identify(struct psmouse *psmouse)
* Read touchpad resolution and maximum reported coordinates
* Resolution is left zero if touchpad does not support the query
*/
+
+static const int *quirk_min_max;
+
static int synaptics_resolution(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
unsigned char resp[3];
+ if (quirk_min_max) {
+ priv->x_min = quirk_min_max[0];
+ priv->x_max = quirk_min_max[1];
+ priv->y_min = quirk_min_max[2];
+ priv->y_max = quirk_min_max[3];
+ return 0;
+ }
+
if (SYN_ID_MAJOR(priv->identity) < 4)
return 0;
@@ -1485,10 +1496,54 @@ static const struct dmi_system_id olpc_dmi_table[] __initconst = {
{ }
};
+static const struct dmi_system_id min_max_dmi_table[] __initconst = {
+#if defined(CONFIG_DMI)
+ {
+ /* Lenovo ThinkPad Helix */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix"),
+ },
+ .driver_data = (int []){1024, 5052, 2258, 4832},
+ },
+ {
+ /* Lenovo ThinkPad X240 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X240"),
+ },
+ .driver_data = (int []){1232, 5710, 1156, 4696},
+ },
+ {
+ /* Lenovo ThinkPad T440s */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T440"),
+ },
+ .driver_data = (int []){1024, 5112, 2024, 4832},
+ },
+ {
+ /* Lenovo ThinkPad T540p */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T540"),
+ },
+ .driver_data = (int []){1024, 5056, 2058, 4832},
+ },
+#endif
+ { }
+};
+
void __init synaptics_module_init(void)
{
+ const struct dmi_system_id *min_max_dmi;
+
impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
broken_olpc_ec = dmi_check_system(olpc_dmi_table);
+
+ min_max_dmi = dmi_first_match(min_max_dmi_table);
+ if (min_max_dmi)
+ quirk_min_max = min_max_dmi->driver_data;
}
static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 4c842c320c2e..b604564dec5c 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -67,7 +67,6 @@ struct mousedev {
struct device dev;
struct cdev cdev;
bool exist;
- bool is_mixdev;
struct list_head mixdev_node;
bool opened_by_mixdev;
@@ -77,6 +76,9 @@ struct mousedev {
int old_x[4], old_y[4];
int frac_dx, frac_dy;
unsigned long touch;
+
+ int (*open_device)(struct mousedev *mousedev);
+ void (*close_device)(struct mousedev *mousedev);
};
enum mousedev_emul {
@@ -116,9 +118,6 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
static struct mousedev *mousedev_mix;
static LIST_HEAD(mousedev_mix_list);
-static void mixdev_open_devices(void);
-static void mixdev_close_devices(void);
-
#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
@@ -428,9 +427,7 @@ static int mousedev_open_device(struct mousedev *mousedev)
if (retval)
return retval;
- if (mousedev->is_mixdev)
- mixdev_open_devices();
- else if (!mousedev->exist)
+ if (!mousedev->exist)
retval = -ENODEV;
else if (!mousedev->open++) {
retval = input_open_device(&mousedev->handle);
@@ -446,9 +443,7 @@ static void mousedev_close_device(struct mousedev *mousedev)
{
mutex_lock(&mousedev->mutex);
- if (mousedev->is_mixdev)
- mixdev_close_devices();
- else if (mousedev->exist && !--mousedev->open)
+ if (mousedev->exist && !--mousedev->open)
input_close_device(&mousedev->handle);
mutex_unlock(&mousedev->mutex);
@@ -459,21 +454,29 @@ static void mousedev_close_device(struct mousedev *mousedev)
* stream. Note that this function is called with mousedev_mix->mutex
* held.
*/
-static void mixdev_open_devices(void)
+static int mixdev_open_devices(struct mousedev *mixdev)
{
- struct mousedev *mousedev;
+ int error;
+
+ error = mutex_lock_interruptible(&mixdev->mutex);
+ if (error)
+ return error;
- if (mousedev_mix->open++)
- return;
+ if (!mixdev->open++) {
+ struct mousedev *mousedev;
- list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
- if (!mousedev->opened_by_mixdev) {
- if (mousedev_open_device(mousedev))
- continue;
+ list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+ if (!mousedev->opened_by_mixdev) {
+ if (mousedev_open_device(mousedev))
+ continue;
- mousedev->opened_by_mixdev = true;
+ mousedev->opened_by_mixdev = true;
+ }
}
}
+
+ mutex_unlock(&mixdev->mutex);
+ return 0;
}
/*
@@ -481,19 +484,22 @@ static void mixdev_open_devices(void)
* device. Note that this function is called with mousedev_mix->mutex
* held.
*/
-static void mixdev_close_devices(void)
+static void mixdev_close_devices(struct mousedev *mixdev)
{
- struct mousedev *mousedev;
+ mutex_lock(&mixdev->mutex);
- if (--mousedev_mix->open)
- return;
+ if (!--mixdev->open) {
+ struct mousedev *mousedev;
- list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
- if (mousedev->opened_by_mixdev) {
- mousedev->opened_by_mixdev = false;
- mousedev_close_device(mousedev);
+ list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+ if (mousedev->opened_by_mixdev) {
+ mousedev->opened_by_mixdev = false;
+ mousedev_close_device(mousedev);
+ }
}
}
+
+ mutex_unlock(&mixdev->mutex);
}
@@ -522,7 +528,7 @@ static int mousedev_release(struct inode *inode, struct file *file)
mousedev_detach_client(mousedev, client);
kfree(client);
- mousedev_close_device(mousedev);
+ mousedev->close_device(mousedev);
return 0;
}
@@ -550,7 +556,7 @@ static int mousedev_open(struct inode *inode, struct file *file)
client->mousedev = mousedev;
mousedev_attach_client(mousedev, client);
- error = mousedev_open_device(mousedev);
+ error = mousedev->open_device(mousedev);
if (error)
goto err_free_client;
@@ -861,16 +867,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
if (mixdev) {
dev_set_name(&mousedev->dev, "mice");
+
+ mousedev->open_device = mixdev_open_devices;
+ mousedev->close_device = mixdev_close_devices;
} else {
int dev_no = minor;
/* Normalize device number if it falls into legacy range */
if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS)
dev_no -= MOUSEDEV_MINOR_BASE;
dev_set_name(&mousedev->dev, "mouse%d", dev_no);
+
+ mousedev->open_device = mousedev_open_device;
+ mousedev->close_device = mousedev_close_device;
}
mousedev->exist = true;
- mousedev->is_mixdev = mixdev;
mousedev->handle.dev = input_get_device(dev);
mousedev->handle.name = dev_name(&mousedev->dev);
mousedev->handle.handler = handler;
@@ -919,7 +930,7 @@ static void mousedev_destroy(struct mousedev *mousedev)
device_del(&mousedev->dev);
mousedev_cleanup(mousedev);
input_free_minor(MINOR(mousedev->dev.devt));
- if (!mousedev->is_mixdev)
+ if (mousedev != mousedev_mix)
input_unregister_handle(&mousedev->handle);
put_device(&mousedev->dev);
}
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index 5c342b3139e8..3c0f57efe7b1 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -134,7 +134,8 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
} else if (!ts->low_latency_req.dev) {
/* First contact, request 100 us latency. */
dev_pm_qos_add_ancestor_request(&ts->client->dev,
- &ts->low_latency_req, 100);
+ &ts->low_latency_req,
+ DEV_PM_QOS_RESUME_LATENCY, 100);
}
/* SYN_REPORT */
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index e400fbe411de..cff039df056e 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -25,6 +25,7 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
+#include <linux/irqreturn.h>
/*
* Maximum number of IOMMUs supported
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 8911850c9444..1d9ab39af29f 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -79,7 +79,6 @@
#define ARM_SMMU_PTE_CONT_SIZE (PAGE_SIZE * ARM_SMMU_PTE_CONT_ENTRIES)
#define ARM_SMMU_PTE_CONT_MASK (~(ARM_SMMU_PTE_CONT_SIZE - 1))
-#define ARM_SMMU_PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(pte_t))
/* Stage-1 PTE */
#define ARM_SMMU_PTE_AP_UNPRIV (((pteval_t)1) << 6)
@@ -191,6 +190,9 @@
#define ARM_SMMU_GR1_CBAR(n) (0x0 + ((n) << 2))
#define CBAR_VMID_SHIFT 0
#define CBAR_VMID_MASK 0xff
+#define CBAR_S1_BPSHCFG_SHIFT 8
+#define CBAR_S1_BPSHCFG_MASK 3
+#define CBAR_S1_BPSHCFG_NSH 3
#define CBAR_S1_MEMATTR_SHIFT 12
#define CBAR_S1_MEMATTR_MASK 0xf
#define CBAR_S1_MEMATTR_WB 0xf
@@ -393,7 +395,7 @@ struct arm_smmu_domain {
struct arm_smmu_cfg root_cfg;
phys_addr_t output_mask;
- struct mutex lock;
+ spinlock_t lock;
};
static DEFINE_SPINLOCK(arm_smmu_devices_lock);
@@ -632,6 +634,28 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
return IRQ_HANDLED;
}
+static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr,
+ size_t size)
+{
+ unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
+
+
+ /* Ensure new page tables are visible to the hardware walker */
+ if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) {
+ dsb();
+ } else {
+ /*
+ * If the SMMU can't walk tables in the CPU caches, treat them
+ * like non-coherent DMA since we need to flush the new entries
+ * all the way out to memory. There's no possibility of
+ * recursion here as the SMMU table walker will not be wired
+ * through another SMMU.
+ */
+ dma_map_page(smmu->dev, virt_to_page(addr), offset, size,
+ DMA_TO_DEVICE);
+ }
+}
+
static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
{
u32 reg;
@@ -650,11 +674,16 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
if (smmu->version == 1)
reg |= root_cfg->irptndx << CBAR_IRPTNDX_SHIFT;
- /* Use the weakest memory type, so it is overridden by the pte */
- if (stage1)
- reg |= (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
- else
+ /*
+ * Use the weakest shareability/memory types, so they are
+ * overridden by the ttbcr/pte.
+ */
+ if (stage1) {
+ reg |= (CBAR_S1_BPSHCFG_NSH << CBAR_S1_BPSHCFG_SHIFT) |
+ (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
+ } else {
reg |= ARM_SMMU_CB_VMID(root_cfg) << CBAR_VMID_SHIFT;
+ }
writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(root_cfg->cbndx));
if (smmu->version > 1) {
@@ -715,6 +744,8 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
}
/* TTBR0 */
+ arm_smmu_flush_pgtable(smmu, root_cfg->pgd,
+ PTRS_PER_PGD * sizeof(pgd_t));
reg = __pa(root_cfg->pgd);
writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
@@ -901,7 +932,7 @@ static int arm_smmu_domain_init(struct iommu_domain *domain)
goto out_free_domain;
smmu_domain->root_cfg.pgd = pgd;
- mutex_init(&smmu_domain->lock);
+ spin_lock_init(&smmu_domain->lock);
domain->priv = smmu_domain;
return 0;
@@ -1128,6 +1159,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
struct arm_smmu_domain *smmu_domain = domain->priv;
struct arm_smmu_device *device_smmu = dev->archdata.iommu;
struct arm_smmu_master *master;
+ unsigned long flags;
if (!device_smmu) {
dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n");
@@ -1138,7 +1170,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
* Sanity check the domain. We don't currently support domains
* that cross between different SMMU chains.
*/
- mutex_lock(&smmu_domain->lock);
+ spin_lock_irqsave(&smmu_domain->lock, flags);
if (!smmu_domain->leaf_smmu) {
/* Now that we have a master, we can finalise the domain */
ret = arm_smmu_init_domain_context(domain, dev);
@@ -1153,7 +1185,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
dev_name(device_smmu->dev));
goto err_unlock;
}
- mutex_unlock(&smmu_domain->lock);
+ spin_unlock_irqrestore(&smmu_domain->lock, flags);
/* Looks ok, so add the device to the domain */
master = find_smmu_master(smmu_domain->leaf_smmu, dev->of_node);
@@ -1163,7 +1195,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
return arm_smmu_domain_add_master(smmu_domain, master);
err_unlock:
- mutex_unlock(&smmu_domain->lock);
+ spin_unlock_irqrestore(&smmu_domain->lock, flags);
return ret;
}
@@ -1177,23 +1209,6 @@ static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev)
arm_smmu_domain_remove_master(smmu_domain, master);
}
-static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr,
- size_t size)
-{
- unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
-
- /*
- * If the SMMU can't walk tables in the CPU caches, treat them
- * like non-coherent DMA since we need to flush the new entries
- * all the way out to memory. There's no possibility of recursion
- * here as the SMMU table walker will not be wired through another
- * SMMU.
- */
- if (!(smmu->features & ARM_SMMU_FEAT_COHERENT_WALK))
- dma_map_page(smmu->dev, virt_to_page(addr), offset, size,
- DMA_TO_DEVICE);
-}
-
static bool arm_smmu_pte_is_contiguous_range(unsigned long addr,
unsigned long end)
{
@@ -1210,12 +1225,11 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd,
if (pmd_none(*pmd)) {
/* Allocate a new set of tables */
- pgtable_t table = alloc_page(PGALLOC_GFP);
+ pgtable_t table = alloc_page(GFP_ATOMIC|__GFP_ZERO);
if (!table)
return -ENOMEM;
- arm_smmu_flush_pgtable(smmu, page_address(table),
- ARM_SMMU_PTE_HWTABLE_SIZE);
+ arm_smmu_flush_pgtable(smmu, page_address(table), PAGE_SIZE);
if (!pgtable_page_ctor(table)) {
__free_page(table);
return -ENOMEM;
@@ -1317,9 +1331,15 @@ static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud,
#ifndef __PAGETABLE_PMD_FOLDED
if (pud_none(*pud)) {
- pmd = pmd_alloc_one(NULL, addr);
+ pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
if (!pmd)
return -ENOMEM;
+
+ arm_smmu_flush_pgtable(smmu, pmd, PAGE_SIZE);
+ pud_populate(NULL, pud, pmd);
+ arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud));
+
+ pmd += pmd_index(addr);
} else
#endif
pmd = pmd_offset(pud, addr);
@@ -1328,8 +1348,6 @@ static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud,
next = pmd_addr_end(addr, end);
ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, end, pfn,
flags, stage);
- pud_populate(NULL, pud, pmd);
- arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud));
phys += next - addr;
} while (pmd++, addr = next, addr < end);
@@ -1346,9 +1364,15 @@ static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd,
#ifndef __PAGETABLE_PUD_FOLDED
if (pgd_none(*pgd)) {
- pud = pud_alloc_one(NULL, addr);
+ pud = (pud_t *)get_zeroed_page(GFP_ATOMIC);
if (!pud)
return -ENOMEM;
+
+ arm_smmu_flush_pgtable(smmu, pud, PAGE_SIZE);
+ pgd_populate(NULL, pgd, pud);
+ arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd));
+
+ pud += pud_index(addr);
} else
#endif
pud = pud_offset(pgd, addr);
@@ -1357,8 +1381,6 @@ static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd,
next = pud_addr_end(addr, end);
ret = arm_smmu_alloc_init_pmd(smmu, pud, addr, next, phys,
flags, stage);
- pgd_populate(NULL, pud, pgd);
- arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd));
phys += next - addr;
} while (pud++, addr = next, addr < end);
@@ -1375,6 +1397,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
pgd_t *pgd = root_cfg->pgd;
struct arm_smmu_device *smmu = root_cfg->smmu;
+ unsigned long irqflags;
if (root_cfg->cbar == CBAR_TYPE_S2_TRANS) {
stage = 2;
@@ -1397,7 +1420,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
if (paddr & ~output_mask)
return -ERANGE;
- mutex_lock(&smmu_domain->lock);
+ spin_lock_irqsave(&smmu_domain->lock, irqflags);
pgd += pgd_index(iova);
end = iova + size;
do {
@@ -1413,11 +1436,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
} while (pgd++, iova != end);
out_unlock:
- mutex_unlock(&smmu_domain->lock);
-
- /* Ensure new page tables are visible to the hardware walker */
- if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
- dsb();
+ spin_unlock_irqrestore(&smmu_domain->lock, irqflags);
return ret;
}
@@ -1987,8 +2006,10 @@ static int __init arm_smmu_init(void)
if (!iommu_present(&platform_bus_type))
bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
+#ifdef CONFIG_ARM_AMBA
if (!iommu_present(&amba_bustype))
bus_set_iommu(&amba_bustype, &arm_smmu_ops);
+#endif
return 0;
}
diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c
index d97fbe4fb9b1..80fffba7f12d 100644
--- a/drivers/iommu/omap-iommu-debug.c
+++ b/drivers/iommu/omap-iommu-debug.c
@@ -354,8 +354,8 @@ DEBUG_FOPS(mem);
return -ENOMEM; \
}
-#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 600)
-#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 400)
+#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 0600)
+#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 0400)
static int iommu_debug_register(struct device *dev, void *data)
{
diff --git a/drivers/iommu/shmobile-iommu.c b/drivers/iommu/shmobile-iommu.c
index 7a3b928fad1c..464acda0bbc4 100644
--- a/drivers/iommu/shmobile-iommu.c
+++ b/drivers/iommu/shmobile-iommu.c
@@ -343,7 +343,7 @@ static int shmobile_iommu_add_device(struct device *dev)
mapping = archdata->iommu_mapping;
if (!mapping) {
mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
- L1_LEN << 20, 0);
+ L1_LEN << 20);
if (IS_ERR(mapping))
return PTR_ERR(mapping);
archdata->iommu_mapping = mapping;
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 5194afb39e78..1c0c151d108c 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o
obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
+obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o
obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 540956465ed2..41be897df8d5 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -42,6 +43,7 @@
#define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4)
#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
+#define ARMADA_375_PPI_CAUSE (0x10)
#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4)
#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc)
@@ -352,7 +354,63 @@ static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
.xlate = irq_domain_xlate_onecell,
};
-static asmlinkage void __exception_irq_entry
+#ifdef CONFIG_PCI_MSI
+static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
+{
+ u32 msimask, msinr;
+
+ msimask = readl_relaxed(per_cpu_int_base +
+ ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
+ & PCI_MSI_DOORBELL_MASK;
+
+ writel(~msimask, per_cpu_int_base +
+ ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
+
+ for (msinr = PCI_MSI_DOORBELL_START;
+ msinr < PCI_MSI_DOORBELL_END; msinr++) {
+ int irq;
+
+ if (!(msimask & BIT(msinr)))
+ continue;
+
+ irq = irq_find_mapping(armada_370_xp_msi_domain,
+ msinr - 16);
+
+ if (is_chained)
+ generic_handle_irq(irq);
+ else
+ handle_IRQ(irq, regs);
+ }
+}
+#else
+static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {}
+#endif
+
+static void armada_370_xp_mpic_handle_cascade_irq(unsigned int irq,
+ struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_get_chip(irq);
+ unsigned long irqmap, irqn;
+ unsigned int cascade_irq;
+
+ chained_irq_enter(chip, desc);
+
+ irqmap = readl_relaxed(per_cpu_int_base + ARMADA_375_PPI_CAUSE);
+
+ if (irqmap & BIT(0)) {
+ armada_370_xp_handle_msi_irq(NULL, true);
+ irqmap &= ~BIT(0);
+ }
+
+ for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) {
+ cascade_irq = irq_find_mapping(armada_370_xp_mpic_domain, irqn);
+ generic_handle_irq(cascade_irq);
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void __exception_irq_entry
armada_370_xp_handle_irq(struct pt_regs *regs)
{
u32 irqstat, irqnr;
@@ -372,31 +430,9 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
continue;
}
-#ifdef CONFIG_PCI_MSI
/* MSI handling */
- if (irqnr == 1) {
- u32 msimask, msinr;
-
- msimask = readl_relaxed(per_cpu_int_base +
- ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
- & PCI_MSI_DOORBELL_MASK;
-
- writel(~msimask, per_cpu_int_base +
- ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
-
- for (msinr = PCI_MSI_DOORBELL_START;
- msinr < PCI_MSI_DOORBELL_END; msinr++) {
- int irq;
-
- if (!(msimask & BIT(msinr)))
- continue;
-
- irq = irq_find_mapping(armada_370_xp_msi_domain,
- msinr - 16);
- handle_IRQ(irq, regs);
- }
- }
-#endif
+ if (irqnr == 1)
+ armada_370_xp_handle_msi_irq(regs, false);
#ifdef CONFIG_SMP
/* IPI Handling */
@@ -427,6 +463,7 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
struct device_node *parent)
{
struct resource main_int_res, per_cpu_int_res;
+ int parent_irq;
u32 control;
BUG_ON(of_address_to_resource(node, 0, &main_int_res));
@@ -455,8 +492,6 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
BUG_ON(!armada_370_xp_mpic_domain);
- irq_set_default_host(armada_370_xp_mpic_domain);
-
#ifdef CONFIG_SMP
armada_xp_mpic_smp_cpu_init();
@@ -472,7 +507,14 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
armada_370_xp_msi_init(node, main_int_res.start);
- set_handle_irq(armada_370_xp_handle_irq);
+ parent_irq = irq_of_parse_and_map(node, 0);
+ if (parent_irq <= 0) {
+ irq_set_default_host(armada_370_xp_mpic_domain);
+ set_handle_irq(armada_370_xp_handle_irq);
+ } else {
+ irq_set_chained_handler(parent_irq,
+ armada_370_xp_mpic_handle_cascade_irq);
+ }
return 0;
}
diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
index 1693b8e7f26a..5916d6cdafa1 100644
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -95,7 +95,7 @@ struct armctrl_ic {
};
static struct armctrl_ic intc __read_mostly;
-static asmlinkage void __exception_irq_entry bcm2835_handle_irq(
+static void __exception_irq_entry bcm2835_handle_irq(
struct pt_regs *regs);
static void armctrl_mask_irq(struct irq_data *d)
@@ -196,7 +196,7 @@ static void armctrl_handle_shortcut(int bank, struct pt_regs *regs,
handle_IRQ(irq_linear_revmap(intc.domain, irq), regs);
}
-static asmlinkage void __exception_irq_entry bcm2835_handle_irq(
+static void __exception_irq_entry bcm2835_handle_irq(
struct pt_regs *regs)
{
u32 stat, irq;
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 341c6016812d..531769b2433a 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -50,7 +50,7 @@
union gic_base {
void __iomem *common_base;
- void __percpu __iomem **percpu_base;
+ void __percpu * __iomem *percpu_base;
};
struct gic_chip_data {
@@ -279,7 +279,7 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
#define gic_set_wake NULL
#endif
-static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
u32 irqstat, irqnr;
struct gic_chip_data *gic = &gic_data[0];
@@ -648,7 +648,7 @@ static void __init gic_pm_init(struct gic_chip_data *gic)
#endif
#ifdef CONFIG_SMP
-void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
+static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{
int cpu;
unsigned long flags, map = 0;
@@ -869,7 +869,7 @@ static struct notifier_block gic_cpu_notifier = {
};
#endif
-const struct irq_domain_ops gic_irq_domain_ops = {
+static const struct irq_domain_ops gic_irq_domain_ops = {
.map = gic_irq_domain_map,
.xlate = gic_irq_domain_xlate,
};
@@ -974,7 +974,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
#ifdef CONFIG_OF
static int gic_cnt __initdata;
-int __init gic_of_init(struct device_node *node, struct device_node *parent)
+static int __init
+gic_of_init(struct device_node *node, struct device_node *parent)
{
void __iomem *cpu_base;
void __iomem *dist_base;
diff --git a/drivers/irqchip/irq-metag-ext.c b/drivers/irqchip/irq-metag-ext.c
index 92c41ab4dbfd..2cb474ad8809 100644
--- a/drivers/irqchip/irq-metag-ext.c
+++ b/drivers/irqchip/irq-metag-ext.c
@@ -515,7 +515,7 @@ static int meta_intc_set_affinity(struct irq_data *data,
* one cpu (the interrupt code doesn't support it), so we just
* pick the first cpu we find in 'cpumask'.
*/
- cpu = cpumask_any(cpumask);
+ cpu = cpumask_any_and(cpumask, cpu_online_mask);
thread = cpu_2_hwthread_id[cpu];
metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR2(thread)), vec_addr);
diff --git a/drivers/irqchip/irq-metag.c b/drivers/irqchip/irq-metag.c
index 8e94d7a3b20d..c16c186d97d3 100644
--- a/drivers/irqchip/irq-metag.c
+++ b/drivers/irqchip/irq-metag.c
@@ -201,7 +201,7 @@ static int metag_internal_irq_set_affinity(struct irq_data *data,
* one cpu (the interrupt code doesn't support it), so we just
* pick the first cpu we find in 'cpumask'.
*/
- cpu = cpumask_any(cpumask);
+ cpu = cpumask_any_and(cpumask, cpu_online_mask);
thread = cpu_2_hwthread_id[cpu];
metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR1(thread)),
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 2cb7cd0bc2f5..3c8827fe83f3 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -194,8 +194,7 @@ static struct mmp_intc_conf mmp2_conf = {
.conf_mask = 0x7f,
};
-static asmlinkage void __exception_irq_entry
-mmp_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
{
int irq, hwirq;
@@ -207,8 +206,7 @@ mmp_handle_irq(struct pt_regs *regs)
handle_IRQ(irq, regs);
}
-static asmlinkage void __exception_irq_entry
-mmp2_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs)
{
int irq, hwirq;
diff --git a/drivers/irqchip/irq-moxart.c b/drivers/irqchip/irq-moxart.c
index 5552fc2bf28a..00b3cc908f76 100644
--- a/drivers/irqchip/irq-moxart.c
+++ b/drivers/irqchip/irq-moxart.c
@@ -44,7 +44,7 @@ struct moxart_irq_data {
static struct moxart_irq_data intc;
-static asmlinkage void __exception_irq_entry handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry handle_irq(struct pt_regs *regs)
{
u32 irqstat;
int hwirq;
diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c
index e51d40031884..e25f246cd2fb 100644
--- a/drivers/irqchip/irq-orion.c
+++ b/drivers/irqchip/irq-orion.c
@@ -30,7 +30,7 @@
static struct irq_domain *orion_irq_domain;
-static asmlinkage void
+static void
__exception_irq_entry orion_handle_irq(struct pt_regs *regs)
{
struct irq_domain_chip_generic *dgc = orion_irq_domain->gc;
@@ -111,7 +111,8 @@ IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init);
static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
{
struct irq_domain *d = irq_get_handler_data(irq);
- struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq);
+
+ struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0);
u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
gc->mask_cache;
@@ -123,6 +124,19 @@ static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
}
}
+/*
+ * Bridge IRQ_CAUSE is asserted regardless of IRQ_MASK register.
+ * To avoid interrupt events on stale irqs, we clear them before unmask.
+ */
+static unsigned int orion_bridge_irq_startup(struct irq_data *d)
+{
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
+
+ ct->chip.irq_ack(d);
+ ct->chip.irq_unmask(d);
+ return 0;
+}
+
static int __init orion_bridge_irq_init(struct device_node *np,
struct device_node *parent)
{
@@ -143,7 +157,7 @@ static int __init orion_bridge_irq_init(struct device_node *np,
}
ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name,
- handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
+ handle_edge_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
if (ret) {
pr_err("%s: unable to alloc irq domain gc\n", np->name);
return ret;
@@ -176,12 +190,14 @@ static int __init orion_bridge_irq_init(struct device_node *np,
gc->chip_types[0].regs.ack = ORION_BRIDGE_IRQ_CAUSE;
gc->chip_types[0].regs.mask = ORION_BRIDGE_IRQ_MASK;
+ gc->chip_types[0].chip.irq_startup = orion_bridge_irq_startup;
gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;
gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
- /* mask all interrupts */
+ /* mask and clear all interrupts */
writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK);
+ writel(0, gc->reg_base + ORION_BRIDGE_IRQ_CAUSE);
irq_set_handler_data(irq, domain);
irq_set_chained_handler(irq, orion_bridge_irq_handler);
diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c
index 3a070c587ed9..581eefe331ae 100644
--- a/drivers/irqchip/irq-sirfsoc.c
+++ b/drivers/irqchip/irq-sirfsoc.c
@@ -47,7 +47,7 @@ sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
ct->regs.mask = SIRFSOC_INT_RISC_MASK0;
}
-static asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
{
void __iomem *base = sirfsoc_irqdomain->host_data;
u32 irqstat, irqnr;
diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
index a5438d889245..6fcef4a95a18 100644
--- a/drivers/irqchip/irq-sun4i.c
+++ b/drivers/irqchip/irq-sun4i.c
@@ -36,18 +36,16 @@
static void __iomem *sun4i_irq_base;
static struct irq_domain *sun4i_irq_domain;
-static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs);
+static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs);
static void sun4i_irq_ack(struct irq_data *irqd)
{
unsigned int irq = irqd_to_hwirq(irqd);
- unsigned int irq_off = irq % 32;
- int reg = irq / 32;
- u32 val;
- val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
- writel(val | (1 << irq_off),
- sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
+ if (irq != 0)
+ return; /* Only IRQ 0 / the ENMI needs to be acked */
+
+ writel(BIT(0), sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0));
}
static void sun4i_irq_mask(struct irq_data *irqd)
@@ -76,16 +74,16 @@ static void sun4i_irq_unmask(struct irq_data *irqd)
static struct irq_chip sun4i_irq_chip = {
.name = "sun4i_irq",
- .irq_ack = sun4i_irq_ack,
+ .irq_eoi = sun4i_irq_ack,
.irq_mask = sun4i_irq_mask,
.irq_unmask = sun4i_irq_unmask,
+ .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED,
};
static int sun4i_irq_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hw)
{
- irq_set_chip_and_handler(virq, &sun4i_irq_chip,
- handle_level_irq);
+ irq_set_chip_and_handler(virq, &sun4i_irq_chip, handle_fasteoi_irq);
set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
return 0;
@@ -109,7 +107,7 @@ static int __init sun4i_of_init(struct device_node *node,
writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1));
writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2));
- /* Mask all the interrupts */
+ /* Unmask all the interrupts, ENABLE_REG(x) is used for masking */
writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0));
writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1));
writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2));
@@ -134,16 +132,30 @@ static int __init sun4i_of_init(struct device_node *node,
return 0;
}
-IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-ic", sun4i_of_init);
+IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-a10-ic", sun4i_of_init);
-static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
{
u32 irq, hwirq;
+ /*
+ * hwirq == 0 can mean one of 3 things:
+ * 1) no more irqs pending
+ * 2) irq 0 pending
+ * 3) spurious irq
+ * So if we immediately get a reading of 0, check the irq-pending reg
+ * to differentiate between 2 and 3. We only do this once to avoid
+ * the extra check in the common case of 1 hapening after having
+ * read the vector-reg once.
+ */
hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
- while (hwirq != 0) {
+ if (hwirq == 0 &&
+ !(readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)) & BIT(0)))
+ return;
+
+ do {
irq = irq_find_mapping(sun4i_irq_domain, hwirq);
handle_IRQ(irq, regs);
hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
- }
+ } while (hwirq != 0);
}
diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c
new file mode 100644
index 000000000000..12f547a44ae4
--- /dev/null
+++ b/drivers/irqchip/irq-sunxi-nmi.c
@@ -0,0 +1,208 @@
+/*
+ * Allwinner A20/A31 SoCs NMI IRQ chip driver.
+ *
+ * Carlo Caione <carlo.caione@gmail.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/bitops.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/irqchip/chained_irq.h>
+#include "irqchip.h"
+
+#define SUNXI_NMI_SRC_TYPE_MASK 0x00000003
+
+enum {
+ SUNXI_SRC_TYPE_LEVEL_LOW = 0,
+ SUNXI_SRC_TYPE_EDGE_FALLING,
+ SUNXI_SRC_TYPE_LEVEL_HIGH,
+ SUNXI_SRC_TYPE_EDGE_RISING,
+};
+
+struct sunxi_sc_nmi_reg_offs {
+ u32 ctrl;
+ u32 pend;
+ u32 enable;
+};
+
+static struct sunxi_sc_nmi_reg_offs sun7i_reg_offs = {
+ .ctrl = 0x00,
+ .pend = 0x04,
+ .enable = 0x08,
+};
+
+static struct sunxi_sc_nmi_reg_offs sun6i_reg_offs = {
+ .ctrl = 0x00,
+ .pend = 0x04,
+ .enable = 0x34,
+};
+
+static inline void sunxi_sc_nmi_write(struct irq_chip_generic *gc, u32 off,
+ u32 val)
+{
+ irq_reg_writel(val, gc->reg_base + off);
+}
+
+static inline u32 sunxi_sc_nmi_read(struct irq_chip_generic *gc, u32 off)
+{
+ return irq_reg_readl(gc->reg_base + off);
+}
+
+static void sunxi_sc_nmi_handle_irq(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_domain *domain = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_get_chip(irq);
+ unsigned int virq = irq_find_mapping(domain, 0);
+
+ chained_irq_enter(chip, desc);
+ generic_handle_irq(virq);
+ chained_irq_exit(chip, desc);
+}
+
+static int sunxi_sc_nmi_set_type(struct irq_data *data, unsigned int flow_type)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+ struct irq_chip_type *ct = gc->chip_types;
+ u32 src_type_reg;
+ u32 ctrl_off = ct->regs.type;
+ unsigned int src_type;
+ unsigned int i;
+
+ irq_gc_lock(gc);
+
+ switch (flow_type & IRQF_TRIGGER_MASK) {
+ case IRQ_TYPE_EDGE_FALLING:
+ src_type = SUNXI_SRC_TYPE_EDGE_FALLING;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ src_type = SUNXI_SRC_TYPE_EDGE_RISING;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ src_type = SUNXI_SRC_TYPE_LEVEL_HIGH;
+ break;
+ case IRQ_TYPE_NONE:
+ case IRQ_TYPE_LEVEL_LOW:
+ src_type = SUNXI_SRC_TYPE_LEVEL_LOW;
+ break;
+ default:
+ irq_gc_unlock(gc);
+ pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
+ __func__, data->irq);
+ return -EBADR;
+ }
+
+ irqd_set_trigger_type(data, flow_type);
+ irq_setup_alt_chip(data, flow_type);
+
+ for (i = 0; i <= gc->num_ct; i++, ct++)
+ if (ct->type & flow_type)
+ ctrl_off = ct->regs.type;
+
+ src_type_reg = sunxi_sc_nmi_read(gc, ctrl_off);
+ src_type_reg &= ~SUNXI_NMI_SRC_TYPE_MASK;
+ src_type_reg |= src_type;
+ sunxi_sc_nmi_write(gc, ctrl_off, src_type_reg);
+
+ irq_gc_unlock(gc);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static int __init sunxi_sc_nmi_irq_init(struct device_node *node,
+ struct sunxi_sc_nmi_reg_offs *reg_offs)
+{
+ struct irq_domain *domain;
+ struct irq_chip_generic *gc;
+ unsigned int irq;
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+ int ret;
+
+
+ domain = irq_domain_add_linear(node, 1, &irq_generic_chip_ops, NULL);
+ if (!domain) {
+ pr_err("%s: Could not register interrupt domain.\n", node->name);
+ return -ENOMEM;
+ }
+
+ ret = irq_alloc_domain_generic_chips(domain, 1, 2, node->name,
+ handle_fasteoi_irq, clr, 0,
+ IRQ_GC_INIT_MASK_CACHE);
+ if (ret) {
+ pr_err("%s: Could not allocate generic interrupt chip.\n",
+ node->name);
+ goto fail_irqd_remove;
+ }
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (irq <= 0) {
+ pr_err("%s: unable to parse irq\n", node->name);
+ ret = -EINVAL;
+ goto fail_irqd_remove;
+ }
+
+ gc = irq_get_domain_generic_chip(domain, 0);
+ gc->reg_base = of_iomap(node, 0);
+ if (!gc->reg_base) {
+ pr_err("%s: unable to map resource\n", node->name);
+ ret = -ENOMEM;
+ goto fail_irqd_remove;
+ }
+
+ gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[0].chip.irq_eoi = irq_gc_ack_set_bit;
+ gc->chip_types[0].chip.irq_set_type = sunxi_sc_nmi_set_type;
+ gc->chip_types[0].chip.flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED;
+ gc->chip_types[0].regs.ack = reg_offs->pend;
+ gc->chip_types[0].regs.mask = reg_offs->enable;
+ gc->chip_types[0].regs.type = reg_offs->ctrl;
+
+ gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
+ gc->chip_types[1].chip.name = gc->chip_types[0].chip.name;
+ gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit;
+ gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[1].chip.irq_set_type = sunxi_sc_nmi_set_type;
+ gc->chip_types[1].regs.ack = reg_offs->pend;
+ gc->chip_types[1].regs.mask = reg_offs->enable;
+ gc->chip_types[1].regs.type = reg_offs->ctrl;
+ gc->chip_types[1].handler = handle_edge_irq;
+
+ sunxi_sc_nmi_write(gc, reg_offs->enable, 0);
+ sunxi_sc_nmi_write(gc, reg_offs->pend, 0x1);
+
+ irq_set_handler_data(irq, domain);
+ irq_set_chained_handler(irq, sunxi_sc_nmi_handle_irq);
+
+ return 0;
+
+fail_irqd_remove:
+ irq_domain_remove(domain);
+
+ return ret;
+}
+
+static int __init sun6i_sc_nmi_irq_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return sunxi_sc_nmi_irq_init(node, &sun6i_reg_offs);
+}
+IRQCHIP_DECLARE(sun6i_sc_nmi, "allwinner,sun6i-a31-sc-nmi", sun6i_sc_nmi_irq_init);
+
+static int __init sun7i_sc_nmi_irq_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return sunxi_sc_nmi_irq_init(node, &sun7i_reg_offs);
+}
+IRQCHIP_DECLARE(sun7i_sc_nmi, "allwinner,sun7i-a20-sc-nmi", sun7i_sc_nmi_irq_init);
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 8e21ae0bab46..473f09a74d4d 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -228,7 +228,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
* Keep iterating over all registered VIC's until there are no pending
* interrupts.
*/
-static asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
{
int i, handled;
diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c
index 1846e7d66681..eb6e91efdec8 100644
--- a/drivers/irqchip/irq-vt8500.c
+++ b/drivers/irqchip/irq-vt8500.c
@@ -178,8 +178,7 @@ static struct irq_domain_ops vt8500_irq_domain_ops = {
.xlate = irq_domain_xlate_onecell,
};
-static asmlinkage
-void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
{
u32 stat, i;
int irqnr, virq;
diff --git a/drivers/irqchip/irq-xtensa-mx.c b/drivers/irqchip/irq-xtensa-mx.c
index f693f1bc1348..e1c2f9632893 100644
--- a/drivers/irqchip/irq-xtensa-mx.c
+++ b/drivers/irqchip/irq-xtensa-mx.c
@@ -122,7 +122,7 @@ static int xtensa_mx_irq_retrigger(struct irq_data *d)
static int xtensa_mx_irq_set_affinity(struct irq_data *d,
const struct cpumask *dest, bool force)
{
- unsigned mask = 1u << cpumask_any(dest);
+ unsigned mask = 1u << cpumask_any_and(dest, cpu_online_mask);
set_er(mask, MIROUT(d->hwirq - HW_IRQ_MX_BASE));
return 0;
diff --git a/drivers/irqchip/irq-zevio.c b/drivers/irqchip/irq-zevio.c
index 8ed04c4a43ee..ceb3a4318f73 100644
--- a/drivers/irqchip/irq-zevio.c
+++ b/drivers/irqchip/irq-zevio.c
@@ -50,7 +50,7 @@ static void zevio_irq_ack(struct irq_data *irqd)
readl(gc->reg_base + regs->ack);
}
-static asmlinkage void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
+static void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
{
int irqnr;
diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c
index f496afce29de..cad3e2495552 100644
--- a/drivers/irqchip/irqchip.c
+++ b/drivers/irqchip/irqchip.c
@@ -10,8 +10,7 @@
#include <linux/init.h>
#include <linux/of_irq.h>
-
-#include "irqchip.h"
+#include <linux/irqchip.h>
/*
* This special of_device_id is the sentinel at the end of the
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index f04686580040..9816c51eb5c2 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -16,9 +16,17 @@ config CAPI_TRACE
This will increase the size of the kernelcapi module by 20 KB.
If unsure, say Y.
+config ISDN_CAPI_CAPI20
+ tristate "CAPI2.0 /dev/capi support"
+ help
+ This option will provide the CAPI 2.0 interface to userspace
+ applications via /dev/capi20. Applications should use the
+ standardized libcapi20 to access this functionality. You should say
+ Y/M here.
+
config ISDN_CAPI_MIDDLEWARE
bool "CAPI2.0 Middleware support"
- depends on TTY
+ depends on ISDN_CAPI_CAPI20 && TTY
help
This option will enhance the capabilities of the /dev/capi20
interface. It will provide a means of moving a data connection,
@@ -26,14 +34,6 @@ config ISDN_CAPI_MIDDLEWARE
device. If you want to use pppd with pppdcapiplugin to dial up to
your ISP, say Y here.
-config ISDN_CAPI_CAPI20
- tristate "CAPI2.0 /dev/capi support"
- help
- This option will provide the CAPI 2.0 interface to userspace
- applications via /dev/capi20. Applications should use the
- standardized libcapi20 to access this functionality. You should say
- Y/M here.
-
config ISDN_CAPI_CAPIDRV
tristate "CAPI2.0 capidrv interface support"
depends on ISDN_I4L
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 04a50498f257..9e9c56758a08 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -38,7 +38,7 @@
#include <linux/platform_device.h>
#include <linux/mutex.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#ifdef CONFIG_PPC
#include <asm/prom.h>
#include <asm/machdep.h>
@@ -193,8 +193,7 @@ static int adb_scan_bus(void)
break;
noMovement = 0;
- }
- else {
+ } else {
/*
* No devices left at address i; move the
* one(s) we moved to `highFree' back to i.
@@ -263,7 +262,7 @@ adb_reset_bus(void)
/*
* notify clients before sleep
*/
-static int adb_suspend(struct platform_device *dev, pm_message_t state)
+static int __adb_suspend(struct platform_device *dev, pm_message_t state)
{
adb_got_sleep = 1;
/* We need to get a lock on the probe thread */
@@ -276,10 +275,25 @@ static int adb_suspend(struct platform_device *dev, pm_message_t state)
return 0;
}
+static int adb_suspend(struct device *dev)
+{
+ return __adb_suspend(to_platform_device(dev), PMSG_SUSPEND);
+}
+
+static int adb_freeze(struct device *dev)
+{
+ return __adb_suspend(to_platform_device(dev), PMSG_FREEZE);
+}
+
+static int adb_poweroff(struct device *dev)
+{
+ return __adb_suspend(to_platform_device(dev), PMSG_HIBERNATE);
+}
+
/*
* reset bus after sleep
*/
-static int adb_resume(struct platform_device *dev)
+static int __adb_resume(struct platform_device *dev)
{
adb_got_sleep = 0;
up(&adb_probe_mutex);
@@ -287,6 +301,11 @@ static int adb_resume(struct platform_device *dev)
return 0;
}
+
+static int adb_resume(struct device *dev)
+{
+ return __adb_resume(to_platform_device(dev));
+}
#endif /* CONFIG_PM */
static int __init adb_init(void)
@@ -502,7 +521,7 @@ void
adb_input(unsigned char *buf, int nb, int autopoll)
{
int i, id;
- static int dump_adb_input = 0;
+ static int dump_adb_input;
unsigned long flags;
void (*handler)(unsigned char *, int, int);
@@ -624,8 +643,7 @@ do_adb_query(struct adb_request *req)
{
int ret = -EINVAL;
- switch(req->data[1])
- {
+ switch(req->data[1]) {
case ADB_QUERY_GETDEVINFO:
if (req->nbytes < 3)
break;
@@ -697,7 +715,7 @@ static ssize_t adb_read(struct file *file, char __user *buf,
int ret = 0;
struct adbdev_state *state = file->private_data;
struct adb_request *req;
- DECLARE_WAITQUEUE(wait,current);
+ DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
if (count < 2)
@@ -794,8 +812,8 @@ static ssize_t adb_write(struct file *file, const char __user *buf,
}
/* Special case for ADB_BUSRESET request, all others are sent to
the controller */
- else if ((req->data[0] == ADB_PACKET)&&(count > 1)
- &&(req->data[1] == ADB_BUSRESET)) {
+ else if ((req->data[0] == ADB_PACKET) && (count > 1)
+ && (req->data[1] == ADB_BUSRESET)) {
ret = do_adb_reset_bus();
up(&adb_probe_mutex);
atomic_dec(&state->n_pending);
@@ -831,14 +849,25 @@ static const struct file_operations adb_fops = {
.release = adb_release,
};
+#ifdef CONFIG_PM
+static const struct dev_pm_ops adb_dev_pm_ops = {
+ .suspend = adb_suspend,
+ .resume = adb_resume,
+ /* Hibernate hooks */
+ .freeze = adb_freeze,
+ .thaw = adb_resume,
+ .poweroff = adb_poweroff,
+ .restore = adb_resume,
+};
+#endif
+
static struct platform_driver adb_pfdrv = {
.driver = {
.name = "adb",
- },
#ifdef CONFIG_PM
- .suspend = adb_suspend,
- .resume = adb_resume,
+ .pm = &adb_dev_pm_ops,
#endif
+ },
};
static struct platform_device adb_pfdev = {
diff --git a/drivers/mcb/Kconfig b/drivers/mcb/Kconfig
new file mode 100644
index 000000000000..e9a6976e1010
--- /dev/null
+++ b/drivers/mcb/Kconfig
@@ -0,0 +1,31 @@
+#
+# MEN Chameleon Bus (MCB) support
+#
+
+menuconfig MCB
+ tristate "MCB support"
+ default n
+ depends on HAS_IOMEM
+ help
+
+ The MCB (MEN Chameleon Bus) is a Bus specific to MEN Mikroelektronik
+ FPGA based devices. It is used to identify MCB based IP-Cores within
+ an FPGA and provide the necessary framework for instantiating drivers
+ for these devices.
+
+ If build as a module, the module is called mcb.ko
+
+if MCB
+config MCB_PCI
+ tristate "PCI based MCB carrier"
+ default n
+ depends on PCI
+ help
+
+ This is a MCB carrier on a PCI device. Both PCI attached on-board
+ FPGAs as well as CompactPCI attached MCB FPGAs are supported with
+ this driver.
+
+ If build as a module, the module is called mcb-pci.ko
+
+endif # MCB
diff --git a/drivers/mcb/Makefile b/drivers/mcb/Makefile
new file mode 100644
index 000000000000..1ae141311def
--- /dev/null
+++ b/drivers/mcb/Makefile
@@ -0,0 +1,7 @@
+
+obj-$(CONFIG_MCB) += mcb.o
+
+mcb-y += mcb-core.o
+mcb-y += mcb-parse.o
+
+obj-$(CONFIG_MCB_PCI) += mcb-pci.o
diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c
new file mode 100644
index 000000000000..bbe12932d404
--- /dev/null
+++ b/drivers/mcb/mcb-core.c
@@ -0,0 +1,414 @@
+/*
+ * MEN Chameleon Bus.
+ *
+ * Copyright (C) 2013 MEN Mikroelektronik GmbH (www.men.de)
+ * Author: Johannes Thumshirn <johannes.thumshirn@men.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; version 2 of the License.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/idr.h>
+#include <linux/mcb.h>
+
+static DEFINE_IDA(mcb_ida);
+
+static const struct mcb_device_id *mcb_match_id(const struct mcb_device_id *ids,
+ struct mcb_device *dev)
+{
+ if (ids) {
+ while (ids->device) {
+ if (ids->device == dev->id)
+ return ids;
+ ids++;
+ }
+ }
+
+ return NULL;
+}
+
+static int mcb_match(struct device *dev, struct device_driver *drv)
+{
+ struct mcb_driver *mdrv = to_mcb_driver(drv);
+ struct mcb_device *mdev = to_mcb_device(dev);
+ const struct mcb_device_id *found_id;
+
+ found_id = mcb_match_id(mdrv->id_table, mdev);
+ if (found_id)
+ return 1;
+
+ return 0;
+}
+
+static int mcb_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct mcb_device *mdev = to_mcb_device(dev);
+ int ret;
+
+ ret = add_uevent_var(env, "MODALIAS=mcb:16z%03d", mdev->id);
+ if (ret)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int mcb_probe(struct device *dev)
+{
+ struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
+ struct mcb_device *mdev = to_mcb_device(dev);
+ const struct mcb_device_id *found_id;
+
+ found_id = mcb_match_id(mdrv->id_table, mdev);
+ if (!found_id)
+ return -ENODEV;
+
+ return mdrv->probe(mdev, found_id);
+}
+
+static int mcb_remove(struct device *dev)
+{
+ struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
+ struct mcb_device *mdev = to_mcb_device(dev);
+
+ mdrv->remove(mdev);
+
+ put_device(&mdev->dev);
+
+ return 0;
+}
+
+static void mcb_shutdown(struct device *dev)
+{
+ struct mcb_device *mdev = to_mcb_device(dev);
+ struct mcb_driver *mdrv = mdev->driver;
+
+ if (mdrv && mdrv->shutdown)
+ mdrv->shutdown(mdev);
+}
+
+static struct bus_type mcb_bus_type = {
+ .name = "mcb",
+ .match = mcb_match,
+ .uevent = mcb_uevent,
+ .probe = mcb_probe,
+ .remove = mcb_remove,
+ .shutdown = mcb_shutdown,
+};
+
+/**
+ * __mcb_register_driver() - Register a @mcb_driver at the system
+ * @drv: The @mcb_driver
+ * @owner: The @mcb_driver's module
+ * @mod_name: The name of the @mcb_driver's module
+ *
+ * Register a @mcb_driver at the system. Perform some sanity checks, if
+ * the .probe and .remove methods are provided by the driver.
+ */
+int __mcb_register_driver(struct mcb_driver *drv, struct module *owner,
+ const char *mod_name)
+{
+ if (!drv->probe || !drv->remove)
+ return -EINVAL;
+
+ drv->driver.owner = owner;
+ drv->driver.bus = &mcb_bus_type;
+ drv->driver.mod_name = mod_name;
+
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(__mcb_register_driver);
+
+/**
+ * mcb_unregister_driver() - Unregister a @mcb_driver from the system
+ * @drv: The @mcb_driver
+ *
+ * Unregister a @mcb_driver from the system.
+ */
+void mcb_unregister_driver(struct mcb_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(mcb_unregister_driver);
+
+static void mcb_release_dev(struct device *dev)
+{
+ struct mcb_device *mdev = to_mcb_device(dev);
+
+ mcb_bus_put(mdev->bus);
+ kfree(mdev);
+}
+
+/**
+ * mcb_device_register() - Register a mcb_device
+ * @bus: The @mcb_bus of the device
+ * @dev: The @mcb_device
+ *
+ * Register a specific @mcb_device at a @mcb_bus and the system itself.
+ */
+int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev)
+{
+ int ret;
+ int device_id;
+
+ device_initialize(&dev->dev);
+ dev->dev.bus = &mcb_bus_type;
+ dev->dev.parent = bus->dev.parent;
+ dev->dev.release = mcb_release_dev;
+
+ device_id = dev->id;
+ dev_set_name(&dev->dev, "mcb%d-16z%03d-%d:%d:%d",
+ bus->bus_nr, device_id, dev->inst, dev->group, dev->var);
+
+ ret = device_add(&dev->dev);
+ if (ret < 0) {
+ pr_err("Failed registering device 16z%03d on bus mcb%d (%d)\n",
+ device_id, bus->bus_nr, ret);
+ goto out;
+ }
+
+ return 0;
+
+out:
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mcb_device_register);
+
+/**
+ * mcb_alloc_bus() - Allocate a new @mcb_bus
+ *
+ * Allocate a new @mcb_bus.
+ */
+struct mcb_bus *mcb_alloc_bus(void)
+{
+ struct mcb_bus *bus;
+ int bus_nr;
+
+ bus = kzalloc(sizeof(struct mcb_bus), GFP_KERNEL);
+ if (!bus)
+ return NULL;
+
+ bus_nr = ida_simple_get(&mcb_ida, 0, 0, GFP_KERNEL);
+ if (bus_nr < 0) {
+ kfree(bus);
+ return ERR_PTR(bus_nr);
+ }
+
+ INIT_LIST_HEAD(&bus->children);
+ bus->bus_nr = bus_nr;
+
+ return bus;
+}
+EXPORT_SYMBOL_GPL(mcb_alloc_bus);
+
+static int __mcb_devices_unregister(struct device *dev, void *data)
+{
+ device_unregister(dev);
+ return 0;
+}
+
+static void mcb_devices_unregister(struct mcb_bus *bus)
+{
+ bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_devices_unregister);
+}
+/**
+ * mcb_release_bus() - Free a @mcb_bus
+ * @bus: The @mcb_bus to release
+ *
+ * Release an allocated @mcb_bus from the system.
+ */
+void mcb_release_bus(struct mcb_bus *bus)
+{
+ mcb_devices_unregister(bus);
+
+ ida_simple_remove(&mcb_ida, bus->bus_nr);
+
+ kfree(bus);
+}
+EXPORT_SYMBOL_GPL(mcb_release_bus);
+
+/**
+ * mcb_bus_put() - Increment refcnt
+ * @bus: The @mcb_bus
+ *
+ * Get a @mcb_bus' ref
+ */
+struct mcb_bus *mcb_bus_get(struct mcb_bus *bus)
+{
+ if (bus)
+ get_device(&bus->dev);
+
+ return bus;
+}
+EXPORT_SYMBOL_GPL(mcb_bus_get);
+
+/**
+ * mcb_bus_put() - Decrement refcnt
+ * @bus: The @mcb_bus
+ *
+ * Release a @mcb_bus' ref
+ */
+void mcb_bus_put(struct mcb_bus *bus)
+{
+ if (bus)
+ put_device(&bus->dev);
+}
+EXPORT_SYMBOL_GPL(mcb_bus_put);
+
+/**
+ * mcb_alloc_dev() - Allocate a device
+ * @bus: The @mcb_bus the device is part of
+ *
+ * Allocate a @mcb_device and add bus.
+ */
+struct mcb_device *mcb_alloc_dev(struct mcb_bus *bus)
+{
+ struct mcb_device *dev;
+
+ dev = kzalloc(sizeof(struct mcb_device), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ INIT_LIST_HEAD(&dev->bus_list);
+ dev->bus = bus;
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(mcb_alloc_dev);
+
+/**
+ * mcb_free_dev() - Free @mcb_device
+ * @dev: The device to free
+ *
+ * Free a @mcb_device
+ */
+void mcb_free_dev(struct mcb_device *dev)
+{
+ kfree(dev);
+}
+EXPORT_SYMBOL_GPL(mcb_free_dev);
+
+static int __mcb_bus_add_devices(struct device *dev, void *data)
+{
+ struct mcb_device *mdev = to_mcb_device(dev);
+ int retval;
+
+ if (mdev->is_added)
+ return 0;
+
+ retval = device_attach(dev);
+ if (retval < 0)
+ dev_err(dev, "Error adding device (%d)\n", retval);
+
+ mdev->is_added = true;
+
+ return 0;
+}
+
+static int __mcb_bus_add_child(struct device *dev, void *data)
+{
+ struct mcb_device *mdev = to_mcb_device(dev);
+ struct mcb_bus *child;
+
+ BUG_ON(!mdev->is_added);
+ child = mdev->subordinate;
+
+ if (child)
+ mcb_bus_add_devices(child);
+
+ return 0;
+}
+
+/**
+ * mcb_bus_add_devices() - Add devices in the bus' internal device list
+ * @bus: The @mcb_bus we add the devices
+ *
+ * Add devices in the bus' internal device list to the system.
+ */
+void mcb_bus_add_devices(const struct mcb_bus *bus)
+{
+ bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_devices);
+ bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_child);
+
+}
+EXPORT_SYMBOL_GPL(mcb_bus_add_devices);
+
+/**
+ * mcb_request_mem() - Request memory
+ * @dev: The @mcb_device the memory is for
+ * @name: The name for the memory reference.
+ *
+ * Request memory for a @mcb_device. If @name is NULL the driver name will
+ * be used.
+ */
+struct resource *mcb_request_mem(struct mcb_device *dev, const char *name)
+{
+ struct resource *mem;
+ u32 size;
+
+ if (!name)
+ name = dev->dev.driver->name;
+
+ size = resource_size(&dev->mem);
+
+ mem = request_mem_region(dev->mem.start, size, name);
+ if (!mem)
+ return ERR_PTR(-EBUSY);
+
+ return mem;
+}
+EXPORT_SYMBOL_GPL(mcb_request_mem);
+
+/**
+ * mcb_release_mem() - Release memory requested by device
+ * @dev: The @mcb_device that requested the memory
+ *
+ * Release memory that was prior requested via @mcb_request_mem().
+ */
+void mcb_release_mem(struct resource *mem)
+{
+ u32 size;
+
+ size = resource_size(mem);
+ release_mem_region(mem->start, size);
+}
+EXPORT_SYMBOL_GPL(mcb_release_mem);
+
+/**
+ * mcb_get_irq() - Get device's IRQ number
+ * @dev: The @mcb_device the IRQ is for
+ *
+ * Get the IRQ number of a given @mcb_device.
+ */
+int mcb_get_irq(struct mcb_device *dev)
+{
+ struct resource *irq = &dev->irq;
+
+ return irq->start;
+}
+EXPORT_SYMBOL_GPL(mcb_get_irq);
+
+static int mcb_init(void)
+{
+ return bus_register(&mcb_bus_type);
+}
+
+static void mcb_exit(void)
+{
+ bus_unregister(&mcb_bus_type);
+}
+
+/* mcb must be initialized after PCI but before the chameleon drivers.
+ * That means we must use some initcall between subsys_initcall and
+ * device_initcall.
+ */
+fs_initcall(mcb_init);
+module_exit(mcb_exit);
+
+MODULE_DESCRIPTION("MEN Chameleon Bus Driver");
+MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mcb/mcb-internal.h b/drivers/mcb/mcb-internal.h
new file mode 100644
index 000000000000..f956ef26c0ce
--- /dev/null
+++ b/drivers/mcb/mcb-internal.h
@@ -0,0 +1,118 @@
+#ifndef __MCB_INTERNAL
+#define __MCB_INTERNAL
+
+#include <linux/types.h>
+
+#define PCI_VENDOR_ID_MEN 0x1a88
+#define PCI_DEVICE_ID_MEN_CHAMELEON 0x4d45
+#define CHAMELEON_FILENAME_LEN 12
+#define CHAMELEONV2_MAGIC 0xabce
+
+enum chameleon_descriptor_type {
+ CHAMELEON_DTYPE_GENERAL = 0x0,
+ CHAMELEON_DTYPE_BRIDGE = 0x1,
+ CHAMELEON_DTYPE_CPU = 0x2,
+ CHAMELEON_DTYPE_BAR = 0x3,
+ CHAMELEON_DTYPE_END = 0xf,
+};
+
+enum chameleon_bus_type {
+ CHAMELEON_BUS_WISHBONE,
+ CHAMELEON_BUS_AVALON,
+ CHAMELEON_BUS_LPC,
+ CHAMELEON_BUS_ISA,
+};
+
+/**
+ * struct chameleon_fpga_header
+ *
+ * @revision: Revison of Chameleon table in FPGA
+ * @model: Chameleon table model ASCII char
+ * @minor: Revision minor
+ * @bus_type: Bus type (usually %CHAMELEON_BUS_WISHBONE)
+ * @magic: Chameleon header magic number (0xabce for version 2)
+ * @reserved: Reserved
+ * @filename: Filename of FPGA bitstream
+ */
+struct chameleon_fpga_header {
+ u8 revision;
+ char model;
+ u8 minor;
+ u8 bus_type;
+ u16 magic;
+ u16 reserved;
+ /* This one has no '\0' at the end!!! */
+ char filename[CHAMELEON_FILENAME_LEN];
+} __packed;
+#define HEADER_MAGIC_OFFSET 0x4
+
+/**
+ * struct chameleon_gdd - Chameleon General Device Descriptor
+ *
+ * @irq: the position in the FPGA's IRQ controller vector
+ * @rev: the revision of the variant's implementation
+ * @var: the variant of the IP core
+ * @dev: the device the IP core is
+ * @dtype: device descriptor type
+ * @bar: BAR offset that must be added to module offset
+ * @inst: the instance number of the device, 0 is first instance
+ * @group: the group the device belongs to (0 = no group)
+ * @reserved: reserved
+ * @offset: beginning of the address window of desired module
+ * @size: size of the module's address window
+ */
+struct chameleon_gdd {
+ __le32 reg1;
+ __le32 reg2;
+ __le32 offset;
+ __le32 size;
+
+} __packed;
+
+/* GDD Register 1 fields */
+#define GDD_IRQ(x) ((x) & 0x1f)
+#define GDD_REV(x) (((x) >> 5) & 0x3f)
+#define GDD_VAR(x) (((x) >> 11) & 0x3f)
+#define GDD_DEV(x) (((x) >> 18) & 0x3ff)
+#define GDD_DTY(x) (((x) >> 28) & 0xf)
+
+/* GDD Register 2 fields */
+#define GDD_BAR(x) ((x) & 0x7)
+#define GDD_INS(x) (((x) >> 3) & 0x3f)
+#define GDD_GRP(x) (((x) >> 9) & 0x3f)
+
+/**
+ * struct chameleon_bdd - Chameleon Bridge Device Descriptor
+ *
+ * @irq: the position in the FPGA's IRQ controller vector
+ * @rev: the revision of the variant's implementation
+ * @var: the variant of the IP core
+ * @dev: the device the IP core is
+ * @dtype: device descriptor type
+ * @bar: BAR offset that must be added to module offset
+ * @inst: the instance number of the device, 0 is first instance
+ * @dbar: destination bar from the bus _behind_ the bridge
+ * @chamoff: offset within the BAR of the source bus
+ * @offset:
+ * @size:
+ */
+struct chameleon_bdd {
+ unsigned int irq:6;
+ unsigned int rev:6;
+ unsigned int var:6;
+ unsigned int dev:10;
+ unsigned int dtype:4;
+ unsigned int bar:3;
+ unsigned int inst:6;
+ unsigned int dbar:3;
+ unsigned int group:6;
+ unsigned int reserved:14;
+ u32 chamoff;
+ u32 offset;
+ u32 size;
+} __packed;
+
+int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
+ void __iomem *base);
+
+#endif
diff --git a/drivers/mcb/mcb-parse.c b/drivers/mcb/mcb-parse.c
new file mode 100644
index 000000000000..d1278b5f3028
--- /dev/null
+++ b/drivers/mcb/mcb-parse.c
@@ -0,0 +1,159 @@
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/mcb.h>
+
+#include "mcb-internal.h"
+
+struct mcb_parse_priv {
+ phys_addr_t mapbase;
+ void __iomem *base;
+};
+
+#define for_each_chameleon_cell(dtype, p) \
+ for ((dtype) = get_next_dtype((p)); \
+ (dtype) != CHAMELEON_DTYPE_END; \
+ (dtype) = get_next_dtype((p)))
+
+static inline uint32_t get_next_dtype(void __iomem *p)
+{
+ uint32_t dtype;
+
+ dtype = readl(p);
+ return dtype >> 28;
+}
+
+static int chameleon_parse_bdd(struct mcb_bus *bus,
+ phys_addr_t mapbase,
+ void __iomem *base)
+{
+ return 0;
+}
+
+static int chameleon_parse_gdd(struct mcb_bus *bus,
+ phys_addr_t mapbase,
+ void __iomem *base)
+{
+ struct chameleon_gdd __iomem *gdd =
+ (struct chameleon_gdd __iomem *) base;
+ struct mcb_device *mdev;
+ u32 offset;
+ u32 size;
+ int ret;
+ __le32 reg1;
+ __le32 reg2;
+
+ mdev = mcb_alloc_dev(bus);
+ if (!mdev)
+ return -ENOMEM;
+
+ reg1 = readl(&gdd->reg1);
+ reg2 = readl(&gdd->reg2);
+ offset = readl(&gdd->offset);
+ size = readl(&gdd->size);
+
+ mdev->id = GDD_DEV(reg1);
+ mdev->rev = GDD_REV(reg1);
+ mdev->var = GDD_VAR(reg1);
+ mdev->bar = GDD_BAR(reg1);
+ mdev->group = GDD_GRP(reg2);
+ mdev->inst = GDD_INS(reg2);
+
+ pr_debug("Found a 16z%03d\n", mdev->id);
+
+ mdev->irq.start = GDD_IRQ(reg1);
+ mdev->irq.end = GDD_IRQ(reg1);
+ mdev->irq.flags = IORESOURCE_IRQ;
+
+ mdev->mem.start = mapbase + offset;
+ mdev->mem.end = mdev->mem.start + size - 1;
+ mdev->mem.flags = IORESOURCE_MEM;
+
+ mdev->is_added = false;
+
+ ret = mcb_device_register(bus, mdev);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ mcb_free_dev(mdev);
+
+ return ret;
+}
+
+int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
+ void __iomem *base)
+{
+ char __iomem *p = base;
+ struct chameleon_fpga_header *header;
+ uint32_t dtype;
+ int num_cells = 0;
+ int ret = 0;
+ u32 hsize;
+
+ hsize = sizeof(struct chameleon_fpga_header);
+
+ header = kzalloc(hsize, GFP_KERNEL);
+ if (!header)
+ return -ENOMEM;
+
+ /* Extract header information */
+ memcpy_fromio(header, p, hsize);
+ /* We only support chameleon v2 at the moment */
+ header->magic = le16_to_cpu(header->magic);
+ if (header->magic != CHAMELEONV2_MAGIC) {
+ pr_err("Unsupported chameleon version 0x%x\n",
+ header->magic);
+ kfree(header);
+ return -ENODEV;
+ }
+ p += hsize;
+
+ pr_debug("header->revision = %d\n", header->revision);
+ pr_debug("header->model = 0x%x ('%c')\n", header->model,
+ header->model);
+ pr_debug("header->minor = %d\n", header->minor);
+ pr_debug("header->bus_type = 0x%x\n", header->bus_type);
+
+
+ pr_debug("header->magic = 0x%x\n", header->magic);
+ pr_debug("header->filename = \"%.*s\"\n", CHAMELEON_FILENAME_LEN,
+ header->filename);
+
+ for_each_chameleon_cell(dtype, p) {
+ switch (dtype) {
+ case CHAMELEON_DTYPE_GENERAL:
+ ret = chameleon_parse_gdd(bus, mapbase, p);
+ if (ret < 0)
+ goto out;
+ p += sizeof(struct chameleon_gdd);
+ break;
+ case CHAMELEON_DTYPE_BRIDGE:
+ chameleon_parse_bdd(bus, mapbase, p);
+ p += sizeof(struct chameleon_bdd);
+ break;
+ case CHAMELEON_DTYPE_END:
+ break;
+ default:
+ pr_err("Invalid chameleon descriptor type 0x%x\n",
+ dtype);
+ return -EINVAL;
+ }
+ num_cells++;
+ }
+
+ if (num_cells == 0)
+ num_cells = -EINVAL;
+
+ kfree(header);
+ return num_cells;
+
+out:
+ kfree(header);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(chameleon_parse_cells);
diff --git a/drivers/mcb/mcb-pci.c b/drivers/mcb/mcb-pci.c
new file mode 100644
index 000000000000..99c742cbfb5b
--- /dev/null
+++ b/drivers/mcb/mcb-pci.c
@@ -0,0 +1,114 @@
+/*
+ * MEN Chameleon Bus.
+ *
+ * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
+ * Author: Johannes Thumshirn <johannes.thumshirn@men.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; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/mcb.h>
+
+#include "mcb-internal.h"
+
+struct priv {
+ struct mcb_bus *bus;
+ void __iomem *base;
+};
+
+static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct priv *priv;
+ phys_addr_t mapbase;
+ int ret;
+ int num_cells;
+ unsigned long flags;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to enable PCI device\n");
+ return -ENODEV;
+ }
+
+ mapbase = pci_resource_start(pdev, 0);
+ if (!mapbase) {
+ dev_err(&pdev->dev, "No PCI resource\n");
+ goto err_start;
+ }
+
+ ret = pci_request_region(pdev, 0, KBUILD_MODNAME);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request PCI BARs\n");
+ goto err_start;
+ }
+
+ priv->base = pci_iomap(pdev, 0, 0);
+ if (!priv->base) {
+ dev_err(&pdev->dev, "Cannot ioremap\n");
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ flags = pci_resource_flags(pdev, 0);
+ if (flags & IORESOURCE_IO) {
+ ret = -ENOTSUPP;
+ dev_err(&pdev->dev,
+ "IO mapped PCI devices are not supported\n");
+ goto err_ioremap;
+ }
+
+ pci_set_drvdata(pdev, priv);
+
+ priv->bus = mcb_alloc_bus();
+
+ ret = chameleon_parse_cells(priv->bus, mapbase, priv->base);
+ if (ret < 0)
+ goto err_drvdata;
+ num_cells = ret;
+
+ dev_dbg(&pdev->dev, "Found %d cells\n", num_cells);
+
+ mcb_bus_add_devices(priv->bus);
+
+err_drvdata:
+ pci_iounmap(pdev, priv->base);
+err_ioremap:
+ pci_release_region(pdev, 0);
+err_start:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static void mcb_pci_remove(struct pci_dev *pdev)
+{
+ struct priv *priv = pci_get_drvdata(pdev);
+
+ mcb_release_bus(priv->bus);
+}
+
+static const struct pci_device_id mcb_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_MEN, PCI_DEVICE_ID_MEN_CHAMELEON) },
+ { 0 },
+};
+MODULE_DEVICE_TABLE(pci, mcb_pci_tbl);
+
+static struct pci_driver mcb_pci_driver = {
+ .name = "mcb-pci",
+ .id_table = mcb_pci_tbl,
+ .probe = mcb_pci_probe,
+ .remove = mcb_pci_remove,
+};
+
+module_pci_driver(mcb_pci_driver);
+
+MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MCB over PCI support");
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 9a06fe883766..95ad936e6048 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -254,16 +254,6 @@ config DM_THIN_PROVISIONING
---help---
Provides thin provisioning and snapshots that share a data store.
-config DM_DEBUG_BLOCK_STACK_TRACING
- boolean "Keep stack trace of persistent data block lock holders"
- depends on STACKTRACE_SUPPORT && DM_PERSISTENT_DATA
- select STACKTRACE
- ---help---
- Enable this for messages that may help debug problems with the
- block manager locking used by thin provisioning and caching.
-
- If unsure, say N.
-
config DM_CACHE
tristate "Cache target (EXPERIMENTAL)"
depends on BLK_DEV_DM
diff --git a/drivers/md/bcache/Kconfig b/drivers/md/bcache/Kconfig
index 2638417b19aa..4d200883c505 100644
--- a/drivers/md/bcache/Kconfig
+++ b/drivers/md/bcache/Kconfig
@@ -24,11 +24,3 @@ config BCACHE_CLOSURES_DEBUG
Keeps all active closures in a linked list and provides a debugfs
interface to list them, which makes it possible to see asynchronous
operations that get stuck.
-
-# cgroup code needs to be updated:
-#
-#config CGROUP_BCACHE
-# bool "Cgroup controls for bcache"
-# depends on BCACHE && BLK_CGROUP
-# ---help---
-# TODO
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index c0d37d082443..443d03fbac47 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -78,12 +78,6 @@ uint8_t bch_inc_gen(struct cache *ca, struct bucket *b)
ca->set->need_gc = max(ca->set->need_gc, bucket_gc_gen(b));
WARN_ON_ONCE(ca->set->need_gc > BUCKET_GC_GEN_MAX);
- if (CACHE_SYNC(&ca->set->sb)) {
- ca->need_save_prio = max(ca->need_save_prio,
- bucket_disk_gen(b));
- WARN_ON_ONCE(ca->need_save_prio > BUCKET_DISK_GEN_MAX);
- }
-
return ret;
}
@@ -120,51 +114,45 @@ void bch_rescale_priorities(struct cache_set *c, int sectors)
mutex_unlock(&c->bucket_lock);
}
-/* Allocation */
+/*
+ * Background allocation thread: scans for buckets to be invalidated,
+ * invalidates them, rewrites prios/gens (marking them as invalidated on disk),
+ * then optionally issues discard commands to the newly free buckets, then puts
+ * them on the various freelists.
+ */
static inline bool can_inc_bucket_gen(struct bucket *b)
{
- return bucket_gc_gen(b) < BUCKET_GC_GEN_MAX &&
- bucket_disk_gen(b) < BUCKET_DISK_GEN_MAX;
+ return bucket_gc_gen(b) < BUCKET_GC_GEN_MAX;
}
-bool bch_bucket_add_unused(struct cache *ca, struct bucket *b)
+bool bch_can_invalidate_bucket(struct cache *ca, struct bucket *b)
{
- BUG_ON(GC_MARK(b) || GC_SECTORS_USED(b));
-
- if (CACHE_REPLACEMENT(&ca->sb) == CACHE_REPLACEMENT_FIFO) {
- unsigned i;
-
- for (i = 0; i < RESERVE_NONE; i++)
- if (!fifo_full(&ca->free[i]))
- goto add;
+ BUG_ON(!ca->set->gc_mark_valid);
- return false;
- }
-add:
- b->prio = 0;
-
- if (can_inc_bucket_gen(b) &&
- fifo_push(&ca->unused, b - ca->buckets)) {
- atomic_inc(&b->pin);
- return true;
- }
-
- return false;
-}
-
-static bool can_invalidate_bucket(struct cache *ca, struct bucket *b)
-{
- return GC_MARK(b) == GC_MARK_RECLAIMABLE &&
+ return (!GC_MARK(b) ||
+ GC_MARK(b) == GC_MARK_RECLAIMABLE) &&
!atomic_read(&b->pin) &&
can_inc_bucket_gen(b);
}
-static void invalidate_one_bucket(struct cache *ca, struct bucket *b)
+void __bch_invalidate_one_bucket(struct cache *ca, struct bucket *b)
{
+ lockdep_assert_held(&ca->set->bucket_lock);
+ BUG_ON(GC_MARK(b) && GC_MARK(b) != GC_MARK_RECLAIMABLE);
+
+ if (GC_SECTORS_USED(b))
+ trace_bcache_invalidate(ca, b - ca->buckets);
+
bch_inc_gen(ca, b);
b->prio = INITIAL_PRIO;
atomic_inc(&b->pin);
+}
+
+static void bch_invalidate_one_bucket(struct cache *ca, struct bucket *b)
+{
+ __bch_invalidate_one_bucket(ca, b);
+
fifo_push(&ca->free_inc, b - ca->buckets);
}
@@ -195,20 +183,7 @@ static void invalidate_buckets_lru(struct cache *ca)
ca->heap.used = 0;
for_each_bucket(b, ca) {
- /*
- * If we fill up the unused list, if we then return before
- * adding anything to the free_inc list we'll skip writing
- * prios/gens and just go back to allocating from the unused
- * list:
- */
- if (fifo_full(&ca->unused))
- return;
-
- if (!can_invalidate_bucket(ca, b))
- continue;
-
- if (!GC_SECTORS_USED(b) &&
- bch_bucket_add_unused(ca, b))
+ if (!bch_can_invalidate_bucket(ca, b))
continue;
if (!heap_full(&ca->heap))
@@ -233,7 +208,7 @@ static void invalidate_buckets_lru(struct cache *ca)
return;
}
- invalidate_one_bucket(ca, b);
+ bch_invalidate_one_bucket(ca, b);
}
}
@@ -249,8 +224,8 @@ static void invalidate_buckets_fifo(struct cache *ca)
b = ca->buckets + ca->fifo_last_bucket++;
- if (can_invalidate_bucket(ca, b))
- invalidate_one_bucket(ca, b);
+ if (bch_can_invalidate_bucket(ca, b))
+ bch_invalidate_one_bucket(ca, b);
if (++checked >= ca->sb.nbuckets) {
ca->invalidate_needs_gc = 1;
@@ -274,8 +249,8 @@ static void invalidate_buckets_random(struct cache *ca)
b = ca->buckets + n;
- if (can_invalidate_bucket(ca, b))
- invalidate_one_bucket(ca, b);
+ if (bch_can_invalidate_bucket(ca, b))
+ bch_invalidate_one_bucket(ca, b);
if (++checked >= ca->sb.nbuckets / 2) {
ca->invalidate_needs_gc = 1;
@@ -287,8 +262,7 @@ static void invalidate_buckets_random(struct cache *ca)
static void invalidate_buckets(struct cache *ca)
{
- if (ca->invalidate_needs_gc)
- return;
+ BUG_ON(ca->invalidate_needs_gc);
switch (CACHE_REPLACEMENT(&ca->sb)) {
case CACHE_REPLACEMENT_LRU:
@@ -301,8 +275,6 @@ static void invalidate_buckets(struct cache *ca)
invalidate_buckets_random(ca);
break;
}
-
- trace_bcache_alloc_invalidate(ca);
}
#define allocator_wait(ca, cond) \
@@ -350,17 +322,10 @@ static int bch_allocator_thread(void *arg)
* possibly issue discards to them, then we add the bucket to
* the free list:
*/
- while (1) {
+ while (!fifo_empty(&ca->free_inc)) {
long bucket;
- if ((!atomic_read(&ca->set->prio_blocked) ||
- !CACHE_SYNC(&ca->set->sb)) &&
- !fifo_empty(&ca->unused))
- fifo_pop(&ca->unused, bucket);
- else if (!fifo_empty(&ca->free_inc))
- fifo_pop(&ca->free_inc, bucket);
- else
- break;
+ fifo_pop(&ca->free_inc, bucket);
if (ca->discard) {
mutex_unlock(&ca->set->bucket_lock);
@@ -371,6 +336,7 @@ static int bch_allocator_thread(void *arg)
}
allocator_wait(ca, bch_allocator_push(ca, bucket));
+ wake_up(&ca->set->btree_cache_wait);
wake_up(&ca->set->bucket_wait);
}
@@ -380,9 +346,9 @@ static int bch_allocator_thread(void *arg)
* them to the free_inc list:
*/
+retry_invalidate:
allocator_wait(ca, ca->set->gc_mark_valid &&
- (ca->need_save_prio > 64 ||
- !ca->invalidate_needs_gc));
+ !ca->invalidate_needs_gc);
invalidate_buckets(ca);
/*
@@ -390,13 +356,28 @@ static int bch_allocator_thread(void *arg)
* new stuff to them:
*/
allocator_wait(ca, !atomic_read(&ca->set->prio_blocked));
- if (CACHE_SYNC(&ca->set->sb) &&
- (!fifo_empty(&ca->free_inc) ||
- ca->need_save_prio > 64))
+ if (CACHE_SYNC(&ca->set->sb)) {
+ /*
+ * This could deadlock if an allocation with a btree
+ * node locked ever blocked - having the btree node
+ * locked would block garbage collection, but here we're
+ * waiting on garbage collection before we invalidate
+ * and free anything.
+ *
+ * But this should be safe since the btree code always
+ * uses btree_check_reserve() before allocating now, and
+ * if it fails it blocks without btree nodes locked.
+ */
+ if (!fifo_full(&ca->free_inc))
+ goto retry_invalidate;
+
bch_prio_write(ca);
+ }
}
}
+/* Allocation */
+
long bch_bucket_alloc(struct cache *ca, unsigned reserve, bool wait)
{
DEFINE_WAIT(w);
@@ -408,8 +389,10 @@ long bch_bucket_alloc(struct cache *ca, unsigned reserve, bool wait)
fifo_pop(&ca->free[reserve], r))
goto out;
- if (!wait)
+ if (!wait) {
+ trace_bcache_alloc_fail(ca, reserve);
return -1;
+ }
do {
prepare_to_wait(&ca->set->bucket_wait, &w,
@@ -425,6 +408,8 @@ long bch_bucket_alloc(struct cache *ca, unsigned reserve, bool wait)
out:
wake_up_process(ca->alloc_thread);
+ trace_bcache_alloc(ca, reserve);
+
if (expensive_debug_checks(ca->set)) {
size_t iter;
long i;
@@ -438,8 +423,6 @@ out:
BUG_ON(i == r);
fifo_for_each(i, &ca->free_inc, iter)
BUG_ON(i == r);
- fifo_for_each(i, &ca->unused, iter)
- BUG_ON(i == r);
}
b = ca->buckets + r;
@@ -461,17 +444,19 @@ out:
return r;
}
+void __bch_bucket_free(struct cache *ca, struct bucket *b)
+{
+ SET_GC_MARK(b, 0);
+ SET_GC_SECTORS_USED(b, 0);
+}
+
void bch_bucket_free(struct cache_set *c, struct bkey *k)
{
unsigned i;
- for (i = 0; i < KEY_PTRS(k); i++) {
- struct bucket *b = PTR_BUCKET(c, k, i);
-
- SET_GC_MARK(b, GC_MARK_RECLAIMABLE);
- SET_GC_SECTORS_USED(b, 0);
- bch_bucket_add_unused(PTR_CACHE(c, k, i), b);
- }
+ for (i = 0; i < KEY_PTRS(k); i++)
+ __bch_bucket_free(PTR_CACHE(c, k, i),
+ PTR_BUCKET(c, k, i));
}
int __bch_bucket_alloc_set(struct cache_set *c, unsigned reserve,
@@ -709,25 +694,3 @@ int bch_cache_allocator_start(struct cache *ca)
ca->alloc_thread = k;
return 0;
}
-
-int bch_cache_allocator_init(struct cache *ca)
-{
- /*
- * Reserve:
- * Prio/gen writes first
- * Then 8 for btree allocations
- * Then half for the moving garbage collector
- */
-#if 0
- ca->watermark[WATERMARK_PRIO] = 0;
-
- ca->watermark[WATERMARK_METADATA] = prio_buckets(ca);
-
- ca->watermark[WATERMARK_MOVINGGC] = 8 +
- ca->watermark[WATERMARK_METADATA];
-
- ca->watermark[WATERMARK_NONE] = ca->free.size / 2 +
- ca->watermark[WATERMARK_MOVINGGC];
-#endif
- return 0;
-}
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index a4c7306ff43d..82c9c5d35251 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -195,9 +195,7 @@ struct bucket {
atomic_t pin;
uint16_t prio;
uint8_t gen;
- uint8_t disk_gen;
uint8_t last_gc; /* Most out of date gen in the btree */
- uint8_t gc_gen;
uint16_t gc_mark; /* Bitfield used by GC. See below for field */
};
@@ -207,9 +205,9 @@ struct bucket {
*/
BITMASK(GC_MARK, struct bucket, gc_mark, 0, 2);
-#define GC_MARK_RECLAIMABLE 0
-#define GC_MARK_DIRTY 1
-#define GC_MARK_METADATA 2
+#define GC_MARK_RECLAIMABLE 1
+#define GC_MARK_DIRTY 2
+#define GC_MARK_METADATA 3
#define GC_SECTORS_USED_SIZE 13
#define MAX_GC_SECTORS_USED (~(~0ULL << GC_SECTORS_USED_SIZE))
BITMASK(GC_SECTORS_USED, struct bucket, gc_mark, 2, GC_SECTORS_USED_SIZE);
@@ -426,14 +424,9 @@ struct cache {
* their new gen to disk. After prio_write() finishes writing the new
* gens/prios, they'll be moved to the free list (and possibly discarded
* in the process)
- *
- * unused: GC found nothing pointing into these buckets (possibly
- * because all the data they contained was overwritten), so we only
- * need to discard them before they can be moved to the free list.
*/
DECLARE_FIFO(long, free)[RESERVE_NR];
DECLARE_FIFO(long, free_inc);
- DECLARE_FIFO(long, unused);
size_t fifo_last_bucket;
@@ -443,12 +436,6 @@ struct cache {
DECLARE_HEAP(struct bucket *, heap);
/*
- * max(gen - disk_gen) for all buckets. When it gets too big we have to
- * call prio_write() to keep gens from wrapping.
- */
- uint8_t need_save_prio;
-
- /*
* If nonzero, we know we aren't going to find any buckets to invalidate
* until a gc finishes - otherwise we could pointlessly burn a ton of
* cpu
@@ -562,19 +549,16 @@ struct cache_set {
struct list_head btree_cache_freed;
/* Number of elements in btree_cache + btree_cache_freeable lists */
- unsigned bucket_cache_used;
+ unsigned btree_cache_used;
/*
* If we need to allocate memory for a new btree node and that
* allocation fails, we can cannibalize another node in the btree cache
- * to satisfy the allocation. However, only one thread can be doing this
- * at a time, for obvious reasons - try_harder and try_wait are
- * basically a lock for this that we can wait on asynchronously. The
- * btree_root() macro releases the lock when it returns.
+ * to satisfy the allocation - lock to guarantee only one thread does
+ * this at a time:
*/
- struct task_struct *try_harder;
- wait_queue_head_t try_wait;
- uint64_t try_harder_start;
+ wait_queue_head_t btree_cache_wait;
+ struct task_struct *btree_cache_alloc_lock;
/*
* When we free a btree node, we increment the gen of the bucket the
@@ -603,7 +587,7 @@ struct cache_set {
uint16_t min_prio;
/*
- * max(gen - gc_gen) for all buckets. When it gets too big we have to gc
+ * max(gen - last_gc) for all buckets. When it gets too big we have to gc
* to keep gens from wrapping around.
*/
uint8_t need_gc;
@@ -628,6 +612,8 @@ struct cache_set {
/* Number of moving GC bios in flight */
struct semaphore moving_in_flight;
+ struct workqueue_struct *moving_gc_wq;
+
struct btree *root;
#ifdef CONFIG_BCACHE_DEBUG
@@ -667,7 +653,6 @@ struct cache_set {
struct time_stats btree_gc_time;
struct time_stats btree_split_time;
struct time_stats btree_read_time;
- struct time_stats try_harder_time;
atomic_long_t cache_read_races;
atomic_long_t writeback_keys_done;
@@ -850,9 +835,6 @@ static inline bool cached_dev_get(struct cached_dev *dc)
/*
* bucket_gc_gen() returns the difference between the bucket's current gen and
* the oldest gen of any pointer into that bucket in the btree (last_gc).
- *
- * bucket_disk_gen() returns the difference between the current gen and the gen
- * on disk; they're both used to make sure gens don't wrap around.
*/
static inline uint8_t bucket_gc_gen(struct bucket *b)
@@ -860,13 +842,7 @@ static inline uint8_t bucket_gc_gen(struct bucket *b)
return b->gen - b->last_gc;
}
-static inline uint8_t bucket_disk_gen(struct bucket *b)
-{
- return b->gen - b->disk_gen;
-}
-
#define BUCKET_GC_GEN_MAX 96U
-#define BUCKET_DISK_GEN_MAX 64U
#define kobj_attribute_write(n, fn) \
static struct kobj_attribute ksysfs_##n = __ATTR(n, S_IWUSR, NULL, fn)
@@ -899,11 +875,14 @@ void bch_submit_bbio(struct bio *, struct cache_set *, struct bkey *, unsigned);
uint8_t bch_inc_gen(struct cache *, struct bucket *);
void bch_rescale_priorities(struct cache_set *, int);
-bool bch_bucket_add_unused(struct cache *, struct bucket *);
-long bch_bucket_alloc(struct cache *, unsigned, bool);
+bool bch_can_invalidate_bucket(struct cache *, struct bucket *);
+void __bch_invalidate_one_bucket(struct cache *, struct bucket *);
+
+void __bch_bucket_free(struct cache *, struct bucket *);
void bch_bucket_free(struct cache_set *, struct bkey *);
+long bch_bucket_alloc(struct cache *, unsigned, bool);
int __bch_bucket_alloc_set(struct cache_set *, unsigned,
struct bkey *, int, bool);
int bch_bucket_alloc_set(struct cache_set *, unsigned,
@@ -954,13 +933,10 @@ int bch_open_buckets_alloc(struct cache_set *);
void bch_open_buckets_free(struct cache_set *);
int bch_cache_allocator_start(struct cache *ca);
-int bch_cache_allocator_init(struct cache *ca);
void bch_debug_exit(void);
int bch_debug_init(struct kobject *);
void bch_request_exit(void);
int bch_request_init(void);
-void bch_btree_exit(void);
-int bch_btree_init(void);
#endif /* _BCACHE_H */
diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c
index 3f74b4b0747b..545416415305 100644
--- a/drivers/md/bcache/bset.c
+++ b/drivers/md/bcache/bset.c
@@ -23,8 +23,8 @@ void bch_dump_bset(struct btree_keys *b, struct bset *i, unsigned set)
for (k = i->start; k < bset_bkey_last(i); k = next) {
next = bkey_next(k);
- printk(KERN_ERR "block %u key %li/%u: ", set,
- (uint64_t *) k - i->d, i->keys);
+ printk(KERN_ERR "block %u key %u/%u: ", set,
+ (unsigned) ((u64 *) k - i->d), i->keys);
if (b->ops->key_dump)
b->ops->key_dump(b, k);
diff --git a/drivers/md/bcache/bset.h b/drivers/md/bcache/bset.h
index 003260f4ddf6..5f6728d5d4dd 100644
--- a/drivers/md/bcache/bset.h
+++ b/drivers/md/bcache/bset.h
@@ -478,6 +478,12 @@ static inline void bch_keylist_init(struct keylist *l)
l->top_p = l->keys_p = l->inline_keys;
}
+static inline void bch_keylist_init_single(struct keylist *l, struct bkey *k)
+{
+ l->keys = k;
+ l->top = bkey_next(k);
+}
+
static inline void bch_keylist_push(struct keylist *l)
{
l->top = bkey_next(l->top);
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 5f9c2a665ca5..7347b6100961 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -68,15 +68,11 @@
* alloc_bucket() cannot fail. This should be true but is not completely
* obvious.
*
- * Make sure all allocations get charged to the root cgroup
- *
* Plugging?
*
* If data write is less than hard sector size of ssd, round up offset in open
* bucket to the next whole sector
*
- * Also lookup by cgroup in get_open_bucket()
- *
* Superblock needs to be fleshed out for multiple cache devices
*
* Add a sysfs tunable for the number of writeback IOs in flight
@@ -97,8 +93,6 @@
#define PTR_HASH(c, k) \
(((k)->ptr[0] >> c->bucket_bits) | PTR_GEN(k, 0))
-static struct workqueue_struct *btree_io_wq;
-
#define insert_lock(s, b) ((b)->level <= (s)->lock)
/*
@@ -123,7 +117,7 @@ static struct workqueue_struct *btree_io_wq;
({ \
int _r, l = (b)->level - 1; \
bool _w = l <= (op)->lock; \
- struct btree *_child = bch_btree_node_get((b)->c, key, l, _w); \
+ struct btree *_child = bch_btree_node_get((b)->c, op, key, l, _w);\
if (!IS_ERR(_child)) { \
_child->parent = (b); \
_r = bch_btree_ ## fn(_child, op, ##__VA_ARGS__); \
@@ -152,17 +146,12 @@ static struct workqueue_struct *btree_io_wq;
_r = bch_btree_ ## fn(_b, op, ##__VA_ARGS__); \
} \
rw_unlock(_w, _b); \
+ bch_cannibalize_unlock(c); \
if (_r == -EINTR) \
schedule(); \
- bch_cannibalize_unlock(c); \
- if (_r == -ENOSPC) { \
- wait_event((c)->try_wait, \
- !(c)->try_harder); \
- _r = -EINTR; \
- } \
} while (_r == -EINTR); \
\
- finish_wait(&(c)->bucket_wait, &(op)->wait); \
+ finish_wait(&(c)->btree_cache_wait, &(op)->wait); \
_r; \
})
@@ -171,6 +160,20 @@ static inline struct bset *write_block(struct btree *b)
return ((void *) btree_bset_first(b)) + b->written * block_bytes(b->c);
}
+static void bch_btree_init_next(struct btree *b)
+{
+ /* If not a leaf node, always sort */
+ if (b->level && b->keys.nsets)
+ bch_btree_sort(&b->keys, &b->c->sort);
+ else
+ bch_btree_sort_lazy(&b->keys, &b->c->sort);
+
+ if (b->written < btree_blocks(b))
+ bch_bset_init_next(&b->keys, write_block(b),
+ bset_magic(&b->c->sb));
+
+}
+
/* Btree key manipulation */
void bkey_put(struct cache_set *c, struct bkey *k)
@@ -352,8 +355,7 @@ static void __btree_node_write_done(struct closure *cl)
btree_complete_write(b, w);
if (btree_node_dirty(b))
- queue_delayed_work(btree_io_wq, &b->work,
- msecs_to_jiffies(30000));
+ schedule_delayed_work(&b->work, 30 * HZ);
closure_return_with_destructor(cl, btree_node_write_unlock);
}
@@ -442,10 +444,12 @@ static void do_btree_node_write(struct btree *b)
}
}
-void bch_btree_node_write(struct btree *b, struct closure *parent)
+void __bch_btree_node_write(struct btree *b, struct closure *parent)
{
struct bset *i = btree_bset_last(b);
+ lockdep_assert_held(&b->write_lock);
+
trace_bcache_btree_write(b);
BUG_ON(current->bio_list);
@@ -469,23 +473,24 @@ void bch_btree_node_write(struct btree *b, struct closure *parent)
&PTR_CACHE(b->c, &b->key, 0)->btree_sectors_written);
b->written += set_blocks(i, block_bytes(b->c));
+}
- /* If not a leaf node, always sort */
- if (b->level && b->keys.nsets)
- bch_btree_sort(&b->keys, &b->c->sort);
- else
- bch_btree_sort_lazy(&b->keys, &b->c->sort);
+void bch_btree_node_write(struct btree *b, struct closure *parent)
+{
+ unsigned nsets = b->keys.nsets;
+
+ lockdep_assert_held(&b->lock);
+
+ __bch_btree_node_write(b, parent);
/*
* do verify if there was more than one set initially (i.e. we did a
* sort) and we sorted down to a single set:
*/
- if (i != b->keys.set->data && !b->keys.nsets)
+ if (nsets && !b->keys.nsets)
bch_btree_verify(b);
- if (b->written < btree_blocks(b))
- bch_bset_init_next(&b->keys, write_block(b),
- bset_magic(&b->c->sb));
+ bch_btree_init_next(b);
}
static void bch_btree_node_write_sync(struct btree *b)
@@ -493,7 +498,11 @@ static void bch_btree_node_write_sync(struct btree *b)
struct closure cl;
closure_init_stack(&cl);
+
+ mutex_lock(&b->write_lock);
bch_btree_node_write(b, &cl);
+ mutex_unlock(&b->write_lock);
+
closure_sync(&cl);
}
@@ -501,11 +510,10 @@ static void btree_node_write_work(struct work_struct *w)
{
struct btree *b = container_of(to_delayed_work(w), struct btree, work);
- rw_lock(true, b, b->level);
-
+ mutex_lock(&b->write_lock);
if (btree_node_dirty(b))
- bch_btree_node_write(b, NULL);
- rw_unlock(true, b);
+ __bch_btree_node_write(b, NULL);
+ mutex_unlock(&b->write_lock);
}
static void bch_btree_leaf_dirty(struct btree *b, atomic_t *journal_ref)
@@ -513,11 +521,13 @@ static void bch_btree_leaf_dirty(struct btree *b, atomic_t *journal_ref)
struct bset *i = btree_bset_last(b);
struct btree_write *w = btree_current_write(b);
+ lockdep_assert_held(&b->write_lock);
+
BUG_ON(!b->written);
BUG_ON(!i->keys);
if (!btree_node_dirty(b))
- queue_delayed_work(btree_io_wq, &b->work, 30 * HZ);
+ schedule_delayed_work(&b->work, 30 * HZ);
set_btree_node_dirty(b);
@@ -548,7 +558,7 @@ static void bch_btree_leaf_dirty(struct btree *b, atomic_t *journal_ref)
#define mca_reserve(c) (((c->root && c->root->level) \
? c->root->level : 1) * 8 + 16)
#define mca_can_free(c) \
- max_t(int, 0, c->bucket_cache_used - mca_reserve(c))
+ max_t(int, 0, c->btree_cache_used - mca_reserve(c))
static void mca_data_free(struct btree *b)
{
@@ -556,7 +566,7 @@ static void mca_data_free(struct btree *b)
bch_btree_keys_free(&b->keys);
- b->c->bucket_cache_used--;
+ b->c->btree_cache_used--;
list_move(&b->list, &b->c->btree_cache_freed);
}
@@ -581,7 +591,7 @@ static void mca_data_alloc(struct btree *b, struct bkey *k, gfp_t gfp)
ilog2(b->c->btree_pages),
btree_order(k)),
gfp)) {
- b->c->bucket_cache_used++;
+ b->c->btree_cache_used++;
list_move(&b->list, &b->c->btree_cache);
} else {
list_move(&b->list, &b->c->btree_cache_freed);
@@ -597,6 +607,8 @@ static struct btree *mca_bucket_alloc(struct cache_set *c,
init_rwsem(&b->lock);
lockdep_set_novalidate_class(&b->lock);
+ mutex_init(&b->write_lock);
+ lockdep_set_novalidate_class(&b->write_lock);
INIT_LIST_HEAD(&b->list);
INIT_DELAYED_WORK(&b->work, btree_node_write_work);
b->c = c;
@@ -630,8 +642,12 @@ static int mca_reap(struct btree *b, unsigned min_order, bool flush)
up(&b->io_mutex);
}
+ mutex_lock(&b->write_lock);
if (btree_node_dirty(b))
- bch_btree_node_write_sync(b);
+ __bch_btree_node_write(b, &cl);
+ mutex_unlock(&b->write_lock);
+
+ closure_sync(&cl);
/* wait for any in flight btree write */
down(&b->io_mutex);
@@ -654,7 +670,7 @@ static unsigned long bch_mca_scan(struct shrinker *shrink,
if (c->shrinker_disabled)
return SHRINK_STOP;
- if (c->try_harder)
+ if (c->btree_cache_alloc_lock)
return SHRINK_STOP;
/* Return -1 if we can't do anything right now */
@@ -686,7 +702,7 @@ static unsigned long bch_mca_scan(struct shrinker *shrink,
}
}
- for (i = 0; (nr--) && i < c->bucket_cache_used; i++) {
+ for (i = 0; (nr--) && i < c->btree_cache_used; i++) {
if (list_empty(&c->btree_cache))
goto out;
@@ -715,7 +731,7 @@ static unsigned long bch_mca_count(struct shrinker *shrink,
if (c->shrinker_disabled)
return 0;
- if (c->try_harder)
+ if (c->btree_cache_alloc_lock)
return 0;
return mca_can_free(c) * c->btree_pages;
@@ -819,17 +835,30 @@ out:
return b;
}
-static struct btree *mca_cannibalize(struct cache_set *c, struct bkey *k)
+static int mca_cannibalize_lock(struct cache_set *c, struct btree_op *op)
+{
+ struct task_struct *old;
+
+ old = cmpxchg(&c->btree_cache_alloc_lock, NULL, current);
+ if (old && old != current) {
+ if (op)
+ prepare_to_wait(&c->btree_cache_wait, &op->wait,
+ TASK_UNINTERRUPTIBLE);
+ return -EINTR;
+ }
+
+ return 0;
+}
+
+static struct btree *mca_cannibalize(struct cache_set *c, struct btree_op *op,
+ struct bkey *k)
{
struct btree *b;
trace_bcache_btree_cache_cannibalize(c);
- if (!c->try_harder) {
- c->try_harder = current;
- c->try_harder_start = local_clock();
- } else if (c->try_harder != current)
- return ERR_PTR(-ENOSPC);
+ if (mca_cannibalize_lock(c, op))
+ return ERR_PTR(-EINTR);
list_for_each_entry_reverse(b, &c->btree_cache, list)
if (!mca_reap(b, btree_order(k), false))
@@ -839,6 +868,7 @@ static struct btree *mca_cannibalize(struct cache_set *c, struct bkey *k)
if (!mca_reap(b, btree_order(k), true))
return b;
+ WARN(1, "btree cache cannibalize failed\n");
return ERR_PTR(-ENOMEM);
}
@@ -850,14 +880,14 @@ static struct btree *mca_cannibalize(struct cache_set *c, struct bkey *k)
*/
static void bch_cannibalize_unlock(struct cache_set *c)
{
- if (c->try_harder == current) {
- bch_time_stats_update(&c->try_harder_time, c->try_harder_start);
- c->try_harder = NULL;
- wake_up(&c->try_wait);
+ if (c->btree_cache_alloc_lock == current) {
+ c->btree_cache_alloc_lock = NULL;
+ wake_up(&c->btree_cache_wait);
}
}
-static struct btree *mca_alloc(struct cache_set *c, struct bkey *k, int level)
+static struct btree *mca_alloc(struct cache_set *c, struct btree_op *op,
+ struct bkey *k, int level)
{
struct btree *b;
@@ -920,7 +950,7 @@ err:
if (b)
rw_unlock(true, b);
- b = mca_cannibalize(c, k);
+ b = mca_cannibalize(c, op, k);
if (!IS_ERR(b))
goto out;
@@ -936,8 +966,8 @@ err:
* The btree node will have either a read or a write lock held, depending on
* level and op->lock.
*/
-struct btree *bch_btree_node_get(struct cache_set *c, struct bkey *k,
- int level, bool write)
+struct btree *bch_btree_node_get(struct cache_set *c, struct btree_op *op,
+ struct bkey *k, int level, bool write)
{
int i = 0;
struct btree *b;
@@ -951,7 +981,7 @@ retry:
return ERR_PTR(-EAGAIN);
mutex_lock(&c->bucket_lock);
- b = mca_alloc(c, k, level);
+ b = mca_alloc(c, op, k, level);
mutex_unlock(&c->bucket_lock);
if (!b)
@@ -997,7 +1027,7 @@ static void btree_node_prefetch(struct cache_set *c, struct bkey *k, int level)
struct btree *b;
mutex_lock(&c->bucket_lock);
- b = mca_alloc(c, k, level);
+ b = mca_alloc(c, NULL, k, level);
mutex_unlock(&c->bucket_lock);
if (!IS_ERR_OR_NULL(b)) {
@@ -1010,46 +1040,41 @@ static void btree_node_prefetch(struct cache_set *c, struct bkey *k, int level)
static void btree_node_free(struct btree *b)
{
- unsigned i;
-
trace_bcache_btree_node_free(b);
BUG_ON(b == b->c->root);
+ mutex_lock(&b->write_lock);
+
if (btree_node_dirty(b))
btree_complete_write(b, btree_current_write(b));
clear_bit(BTREE_NODE_dirty, &b->flags);
+ mutex_unlock(&b->write_lock);
+
cancel_delayed_work(&b->work);
mutex_lock(&b->c->bucket_lock);
-
- for (i = 0; i < KEY_PTRS(&b->key); i++) {
- BUG_ON(atomic_read(&PTR_BUCKET(b->c, &b->key, i)->pin));
-
- bch_inc_gen(PTR_CACHE(b->c, &b->key, i),
- PTR_BUCKET(b->c, &b->key, i));
- }
-
bch_bucket_free(b->c, &b->key);
mca_bucket_free(b);
mutex_unlock(&b->c->bucket_lock);
}
-struct btree *bch_btree_node_alloc(struct cache_set *c, int level, bool wait)
+struct btree *bch_btree_node_alloc(struct cache_set *c, struct btree_op *op,
+ int level)
{
BKEY_PADDED(key) k;
struct btree *b = ERR_PTR(-EAGAIN);
mutex_lock(&c->bucket_lock);
retry:
- if (__bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, 1, wait))
+ if (__bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, 1, op != NULL))
goto err;
bkey_put(c, &k.key);
SET_KEY_SIZE(&k.key, c->btree_pages * PAGE_SECTORS);
- b = mca_alloc(c, &k.key, level);
+ b = mca_alloc(c, op, &k.key, level);
if (IS_ERR(b))
goto err_free;
@@ -1075,12 +1100,15 @@ err:
return b;
}
-static struct btree *btree_node_alloc_replacement(struct btree *b, bool wait)
+static struct btree *btree_node_alloc_replacement(struct btree *b,
+ struct btree_op *op)
{
- struct btree *n = bch_btree_node_alloc(b->c, b->level, wait);
+ struct btree *n = bch_btree_node_alloc(b->c, op, b->level);
if (!IS_ERR_OR_NULL(n)) {
+ mutex_lock(&n->write_lock);
bch_btree_sort_into(&b->keys, &n->keys, &b->c->sort);
bkey_copy_key(&n->key, &b->key);
+ mutex_unlock(&n->write_lock);
}
return n;
@@ -1090,43 +1118,47 @@ static void make_btree_freeing_key(struct btree *b, struct bkey *k)
{
unsigned i;
+ mutex_lock(&b->c->bucket_lock);
+
+ atomic_inc(&b->c->prio_blocked);
+
bkey_copy(k, &b->key);
bkey_copy_key(k, &ZERO_KEY);
- for (i = 0; i < KEY_PTRS(k); i++) {
- uint8_t g = PTR_BUCKET(b->c, k, i)->gen + 1;
-
- SET_PTR_GEN(k, i, g);
- }
+ for (i = 0; i < KEY_PTRS(k); i++)
+ SET_PTR_GEN(k, i,
+ bch_inc_gen(PTR_CACHE(b->c, &b->key, i),
+ PTR_BUCKET(b->c, &b->key, i)));
- atomic_inc(&b->c->prio_blocked);
+ mutex_unlock(&b->c->bucket_lock);
}
static int btree_check_reserve(struct btree *b, struct btree_op *op)
{
struct cache_set *c = b->c;
struct cache *ca;
- unsigned i, reserve = c->root->level * 2 + 1;
- int ret = 0;
+ unsigned i, reserve = (c->root->level - b->level) * 2 + 1;
mutex_lock(&c->bucket_lock);
for_each_cache(ca, c, i)
if (fifo_used(&ca->free[RESERVE_BTREE]) < reserve) {
if (op)
- prepare_to_wait(&c->bucket_wait, &op->wait,
+ prepare_to_wait(&c->btree_cache_wait, &op->wait,
TASK_UNINTERRUPTIBLE);
- ret = -EINTR;
- break;
+ mutex_unlock(&c->bucket_lock);
+ return -EINTR;
}
mutex_unlock(&c->bucket_lock);
- return ret;
+
+ return mca_cannibalize_lock(b->c, op);
}
/* Garbage collection */
-uint8_t __bch_btree_mark_key(struct cache_set *c, int level, struct bkey *k)
+static uint8_t __bch_btree_mark_key(struct cache_set *c, int level,
+ struct bkey *k)
{
uint8_t stale = 0;
unsigned i;
@@ -1146,8 +1178,8 @@ uint8_t __bch_btree_mark_key(struct cache_set *c, int level, struct bkey *k)
g = PTR_BUCKET(c, k, i);
- if (gen_after(g->gc_gen, PTR_GEN(k, i)))
- g->gc_gen = PTR_GEN(k, i);
+ if (gen_after(g->last_gc, PTR_GEN(k, i)))
+ g->last_gc = PTR_GEN(k, i);
if (ptr_stale(c, k, i)) {
stale = max(stale, ptr_stale(c, k, i));
@@ -1163,6 +1195,8 @@ uint8_t __bch_btree_mark_key(struct cache_set *c, int level, struct bkey *k)
SET_GC_MARK(g, GC_MARK_METADATA);
else if (KEY_DIRTY(k))
SET_GC_MARK(g, GC_MARK_DIRTY);
+ else if (!GC_MARK(g))
+ SET_GC_MARK(g, GC_MARK_RECLAIMABLE);
/* guard against overflow */
SET_GC_SECTORS_USED(g, min_t(unsigned,
@@ -1177,6 +1211,26 @@ uint8_t __bch_btree_mark_key(struct cache_set *c, int level, struct bkey *k)
#define btree_mark_key(b, k) __bch_btree_mark_key(b->c, b->level, k)
+void bch_initial_mark_key(struct cache_set *c, int level, struct bkey *k)
+{
+ unsigned i;
+
+ for (i = 0; i < KEY_PTRS(k); i++)
+ if (ptr_available(c, k, i) &&
+ !ptr_stale(c, k, i)) {
+ struct bucket *b = PTR_BUCKET(c, k, i);
+
+ b->gen = PTR_GEN(k, i);
+
+ if (level && bkey_cmp(k, &ZERO_KEY))
+ b->prio = BTREE_PRIO;
+ else if (!level && b->prio == BTREE_PRIO)
+ b->prio = INITIAL_PRIO;
+ }
+
+ __bch_btree_mark_key(c, level, k);
+}
+
static bool btree_gc_mark_node(struct btree *b, struct gc_stat *gc)
{
uint8_t stale = 0;
@@ -1230,14 +1284,19 @@ static int bch_btree_insert_node(struct btree *, struct btree_op *,
struct keylist *, atomic_t *, struct bkey *);
static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
- struct keylist *keylist, struct gc_stat *gc,
- struct gc_merge_info *r)
+ struct gc_stat *gc, struct gc_merge_info *r)
{
unsigned i, nodes = 0, keys = 0, blocks;
struct btree *new_nodes[GC_MERGE_NODES];
+ struct keylist keylist;
struct closure cl;
struct bkey *k;
+ bch_keylist_init(&keylist);
+
+ if (btree_check_reserve(b, NULL))
+ return 0;
+
memset(new_nodes, 0, sizeof(new_nodes));
closure_init_stack(&cl);
@@ -1252,11 +1311,23 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
return 0;
for (i = 0; i < nodes; i++) {
- new_nodes[i] = btree_node_alloc_replacement(r[i].b, false);
+ new_nodes[i] = btree_node_alloc_replacement(r[i].b, NULL);
if (IS_ERR_OR_NULL(new_nodes[i]))
goto out_nocoalesce;
}
+ /*
+ * We have to check the reserve here, after we've allocated our new
+ * nodes, to make sure the insert below will succeed - we also check
+ * before as an optimization to potentially avoid a bunch of expensive
+ * allocs/sorts
+ */
+ if (btree_check_reserve(b, NULL))
+ goto out_nocoalesce;
+
+ for (i = 0; i < nodes; i++)
+ mutex_lock(&new_nodes[i]->write_lock);
+
for (i = nodes - 1; i > 0; --i) {
struct bset *n1 = btree_bset_first(new_nodes[i]);
struct bset *n2 = btree_bset_first(new_nodes[i - 1]);
@@ -1315,28 +1386,34 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
n2->keys -= keys;
- if (__bch_keylist_realloc(keylist,
+ if (__bch_keylist_realloc(&keylist,
bkey_u64s(&new_nodes[i]->key)))
goto out_nocoalesce;
bch_btree_node_write(new_nodes[i], &cl);
- bch_keylist_add(keylist, &new_nodes[i]->key);
+ bch_keylist_add(&keylist, &new_nodes[i]->key);
}
- for (i = 0; i < nodes; i++) {
- if (__bch_keylist_realloc(keylist, bkey_u64s(&r[i].b->key)))
- goto out_nocoalesce;
+ for (i = 0; i < nodes; i++)
+ mutex_unlock(&new_nodes[i]->write_lock);
- make_btree_freeing_key(r[i].b, keylist->top);
- bch_keylist_push(keylist);
- }
+ closure_sync(&cl);
/* We emptied out this node */
BUG_ON(btree_bset_first(new_nodes[0])->keys);
btree_node_free(new_nodes[0]);
rw_unlock(true, new_nodes[0]);
- closure_sync(&cl);
+ for (i = 0; i < nodes; i++) {
+ if (__bch_keylist_realloc(&keylist, bkey_u64s(&r[i].b->key)))
+ goto out_nocoalesce;
+
+ make_btree_freeing_key(r[i].b, keylist.top);
+ bch_keylist_push(&keylist);
+ }
+
+ bch_btree_insert_node(b, op, &keylist, NULL, NULL);
+ BUG_ON(!bch_keylist_empty(&keylist));
for (i = 0; i < nodes; i++) {
btree_node_free(r[i].b);
@@ -1345,22 +1422,22 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
r[i].b = new_nodes[i];
}
- bch_btree_insert_node(b, op, keylist, NULL, NULL);
- BUG_ON(!bch_keylist_empty(keylist));
-
memmove(r, r + 1, sizeof(r[0]) * (nodes - 1));
r[nodes - 1].b = ERR_PTR(-EINTR);
trace_bcache_btree_gc_coalesce(nodes);
gc->nodes--;
+ bch_keylist_free(&keylist);
+
/* Invalidated our iterator */
return -EINTR;
out_nocoalesce:
closure_sync(&cl);
+ bch_keylist_free(&keylist);
- while ((k = bch_keylist_pop(keylist)))
+ while ((k = bch_keylist_pop(&keylist)))
if (!bkey_cmp(k, &ZERO_KEY))
atomic_dec(&b->c->prio_blocked);
@@ -1372,6 +1449,42 @@ out_nocoalesce:
return 0;
}
+static int btree_gc_rewrite_node(struct btree *b, struct btree_op *op,
+ struct btree *replace)
+{
+ struct keylist keys;
+ struct btree *n;
+
+ if (btree_check_reserve(b, NULL))
+ return 0;
+
+ n = btree_node_alloc_replacement(replace, NULL);
+
+ /* recheck reserve after allocating replacement node */
+ if (btree_check_reserve(b, NULL)) {
+ btree_node_free(n);
+ rw_unlock(true, n);
+ return 0;
+ }
+
+ bch_btree_node_write_sync(n);
+
+ bch_keylist_init(&keys);
+ bch_keylist_add(&keys, &n->key);
+
+ make_btree_freeing_key(replace, keys.top);
+ bch_keylist_push(&keys);
+
+ bch_btree_insert_node(b, op, &keys, NULL, NULL);
+ BUG_ON(!bch_keylist_empty(&keys));
+
+ btree_node_free(replace);
+ rw_unlock(true, n);
+
+ /* Invalidated our iterator */
+ return -EINTR;
+}
+
static unsigned btree_gc_count_keys(struct btree *b)
{
struct bkey *k;
@@ -1387,26 +1500,23 @@ static unsigned btree_gc_count_keys(struct btree *b)
static int btree_gc_recurse(struct btree *b, struct btree_op *op,
struct closure *writes, struct gc_stat *gc)
{
- unsigned i;
int ret = 0;
bool should_rewrite;
- struct btree *n;
struct bkey *k;
- struct keylist keys;
struct btree_iter iter;
struct gc_merge_info r[GC_MERGE_NODES];
- struct gc_merge_info *last = r + GC_MERGE_NODES - 1;
+ struct gc_merge_info *i, *last = r + ARRAY_SIZE(r) - 1;
- bch_keylist_init(&keys);
bch_btree_iter_init(&b->keys, &iter, &b->c->gc_done);
- for (i = 0; i < GC_MERGE_NODES; i++)
- r[i].b = ERR_PTR(-EINTR);
+ for (i = r; i < r + ARRAY_SIZE(r); i++)
+ i->b = ERR_PTR(-EINTR);
while (1) {
k = bch_btree_iter_next_filter(&iter, &b->keys, bch_ptr_bad);
if (k) {
- r->b = bch_btree_node_get(b->c, k, b->level - 1, true);
+ r->b = bch_btree_node_get(b->c, op, k, b->level - 1,
+ true);
if (IS_ERR(r->b)) {
ret = PTR_ERR(r->b);
break;
@@ -1414,7 +1524,7 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
r->keys = btree_gc_count_keys(r->b);
- ret = btree_gc_coalesce(b, op, &keys, gc, r);
+ ret = btree_gc_coalesce(b, op, gc, r);
if (ret)
break;
}
@@ -1424,32 +1534,10 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
if (!IS_ERR(last->b)) {
should_rewrite = btree_gc_mark_node(last->b, gc);
- if (should_rewrite &&
- !btree_check_reserve(b, NULL)) {
- n = btree_node_alloc_replacement(last->b,
- false);
-
- if (!IS_ERR_OR_NULL(n)) {
- bch_btree_node_write_sync(n);
- bch_keylist_add(&keys, &n->key);
-
- make_btree_freeing_key(last->b,
- keys.top);
- bch_keylist_push(&keys);
-
- btree_node_free(last->b);
-
- bch_btree_insert_node(b, op, &keys,
- NULL, NULL);
- BUG_ON(!bch_keylist_empty(&keys));
-
- rw_unlock(true, last->b);
- last->b = n;
-
- /* Invalidated our iterator */
- ret = -EINTR;
+ if (should_rewrite) {
+ ret = btree_gc_rewrite_node(b, op, last->b);
+ if (ret)
break;
- }
}
if (last->b->level) {
@@ -1464,8 +1552,10 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
* Must flush leaf nodes before gc ends, since replace
* operations aren't journalled
*/
+ mutex_lock(&last->b->write_lock);
if (btree_node_dirty(last->b))
bch_btree_node_write(last->b, writes);
+ mutex_unlock(&last->b->write_lock);
rw_unlock(true, last->b);
}
@@ -1478,15 +1568,15 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
}
}
- for (i = 0; i < GC_MERGE_NODES; i++)
- if (!IS_ERR_OR_NULL(r[i].b)) {
- if (btree_node_dirty(r[i].b))
- bch_btree_node_write(r[i].b, writes);
- rw_unlock(true, r[i].b);
+ for (i = r; i < r + ARRAY_SIZE(r); i++)
+ if (!IS_ERR_OR_NULL(i->b)) {
+ mutex_lock(&i->b->write_lock);
+ if (btree_node_dirty(i->b))
+ bch_btree_node_write(i->b, writes);
+ mutex_unlock(&i->b->write_lock);
+ rw_unlock(true, i->b);
}
- bch_keylist_free(&keys);
-
return ret;
}
@@ -1499,10 +1589,11 @@ static int bch_btree_gc_root(struct btree *b, struct btree_op *op,
should_rewrite = btree_gc_mark_node(b, gc);
if (should_rewrite) {
- n = btree_node_alloc_replacement(b, false);
+ n = btree_node_alloc_replacement(b, NULL);
if (!IS_ERR_OR_NULL(n)) {
bch_btree_node_write_sync(n);
+
bch_btree_set_root(n);
btree_node_free(b);
rw_unlock(true, n);
@@ -1511,6 +1602,8 @@ static int bch_btree_gc_root(struct btree *b, struct btree_op *op,
}
}
+ __bch_btree_mark_key(b->c, b->level + 1, &b->key);
+
if (b->level) {
ret = btree_gc_recurse(b, op, writes, gc);
if (ret)
@@ -1538,9 +1631,9 @@ static void btree_gc_start(struct cache_set *c)
for_each_cache(ca, c, i)
for_each_bucket(b, ca) {
- b->gc_gen = b->gen;
+ b->last_gc = b->gen;
if (!atomic_read(&b->pin)) {
- SET_GC_MARK(b, GC_MARK_RECLAIMABLE);
+ SET_GC_MARK(b, 0);
SET_GC_SECTORS_USED(b, 0);
}
}
@@ -1548,7 +1641,7 @@ static void btree_gc_start(struct cache_set *c)
mutex_unlock(&c->bucket_lock);
}
-size_t bch_btree_gc_finish(struct cache_set *c)
+static size_t bch_btree_gc_finish(struct cache_set *c)
{
size_t available = 0;
struct bucket *b;
@@ -1561,11 +1654,6 @@ size_t bch_btree_gc_finish(struct cache_set *c)
c->gc_mark_valid = 1;
c->need_gc = 0;
- if (c->root)
- for (i = 0; i < KEY_PTRS(&c->root->key); i++)
- SET_GC_MARK(PTR_BUCKET(c, &c->root->key, i),
- GC_MARK_METADATA);
-
for (i = 0; i < KEY_PTRS(&c->uuid_bucket); i++)
SET_GC_MARK(PTR_BUCKET(c, &c->uuid_bucket, i),
GC_MARK_METADATA);
@@ -1605,15 +1693,15 @@ size_t bch_btree_gc_finish(struct cache_set *c)
SET_GC_MARK(ca->buckets + *i, GC_MARK_METADATA);
for_each_bucket(b, ca) {
- b->last_gc = b->gc_gen;
c->need_gc = max(c->need_gc, bucket_gc_gen(b));
- if (!atomic_read(&b->pin) &&
- GC_MARK(b) == GC_MARK_RECLAIMABLE) {
+ if (atomic_read(&b->pin))
+ continue;
+
+ BUG_ON(!GC_MARK(b) && GC_SECTORS_USED(b));
+
+ if (!GC_MARK(b) || GC_MARK(b) == GC_MARK_RECLAIMABLE)
available++;
- if (!GC_SECTORS_USED(b))
- bch_bucket_add_unused(ca, b);
- }
}
}
@@ -1705,36 +1793,16 @@ int bch_gc_thread_start(struct cache_set *c)
/* Initial partial gc */
-static int bch_btree_check_recurse(struct btree *b, struct btree_op *op,
- unsigned long **seen)
+static int bch_btree_check_recurse(struct btree *b, struct btree_op *op)
{
int ret = 0;
- unsigned i;
struct bkey *k, *p = NULL;
- struct bucket *g;
struct btree_iter iter;
- for_each_key_filter(&b->keys, k, &iter, bch_ptr_invalid) {
- for (i = 0; i < KEY_PTRS(k); i++) {
- if (!ptr_available(b->c, k, i))
- continue;
-
- g = PTR_BUCKET(b->c, k, i);
+ for_each_key_filter(&b->keys, k, &iter, bch_ptr_invalid)
+ bch_initial_mark_key(b->c, b->level, k);
- if (!__test_and_set_bit(PTR_BUCKET_NR(b->c, k, i),
- seen[PTR_DEV(k, i)]) ||
- !ptr_stale(b->c, k, i)) {
- g->gen = PTR_GEN(k, i);
-
- if (b->level)
- g->prio = BTREE_PRIO;
- else if (g->prio == BTREE_PRIO)
- g->prio = INITIAL_PRIO;
- }
- }
-
- btree_mark_key(b, k);
- }
+ bch_initial_mark_key(b->c, b->level + 1, &b->key);
if (b->level) {
bch_btree_iter_init(&b->keys, &iter, NULL);
@@ -1746,40 +1814,58 @@ static int bch_btree_check_recurse(struct btree *b, struct btree_op *op,
btree_node_prefetch(b->c, k, b->level - 1);
if (p)
- ret = btree(check_recurse, p, b, op, seen);
+ ret = btree(check_recurse, p, b, op);
p = k;
} while (p && !ret);
}
- return 0;
+ return ret;
}
int bch_btree_check(struct cache_set *c)
{
- int ret = -ENOMEM;
- unsigned i;
- unsigned long *seen[MAX_CACHES_PER_SET];
struct btree_op op;
- memset(seen, 0, sizeof(seen));
bch_btree_op_init(&op, SHRT_MAX);
- for (i = 0; c->cache[i]; i++) {
- size_t n = DIV_ROUND_UP(c->cache[i]->sb.nbuckets, 8);
- seen[i] = kmalloc(n, GFP_KERNEL);
- if (!seen[i])
- goto err;
+ return btree_root(check_recurse, c, &op);
+}
+
+void bch_initial_gc_finish(struct cache_set *c)
+{
+ struct cache *ca;
+ struct bucket *b;
+ unsigned i;
+
+ bch_btree_gc_finish(c);
- /* Disables the seen array until prio_read() uses it too */
- memset(seen[i], 0xFF, n);
+ mutex_lock(&c->bucket_lock);
+
+ /*
+ * We need to put some unused buckets directly on the prio freelist in
+ * order to get the allocator thread started - it needs freed buckets in
+ * order to rewrite the prios and gens, and it needs to rewrite prios
+ * and gens in order to free buckets.
+ *
+ * This is only safe for buckets that have no live data in them, which
+ * there should always be some of.
+ */
+ for_each_cache(ca, c, i) {
+ for_each_bucket(b, ca) {
+ if (fifo_full(&ca->free[RESERVE_PRIO]))
+ break;
+
+ if (bch_can_invalidate_bucket(ca, b) &&
+ !GC_MARK(b)) {
+ __bch_invalidate_one_bucket(ca, b);
+ fifo_push(&ca->free[RESERVE_PRIO],
+ b - ca->buckets);
+ }
+ }
}
- ret = btree_root(check_recurse, c, &op, seen);
-err:
- for (i = 0; i < MAX_CACHES_PER_SET; i++)
- kfree(seen[i]);
- return ret;
+ mutex_unlock(&c->bucket_lock);
}
/* Btree insertion */
@@ -1871,11 +1957,14 @@ static int btree_split(struct btree *b, struct btree_op *op,
closure_init_stack(&cl);
bch_keylist_init(&parent_keys);
- if (!b->level &&
- btree_check_reserve(b, op))
- return -EINTR;
+ if (btree_check_reserve(b, op)) {
+ if (!b->level)
+ return -EINTR;
+ else
+ WARN(1, "insufficient reserve for split\n");
+ }
- n1 = btree_node_alloc_replacement(b, true);
+ n1 = btree_node_alloc_replacement(b, op);
if (IS_ERR(n1))
goto err;
@@ -1887,16 +1976,19 @@ static int btree_split(struct btree *b, struct btree_op *op,
trace_bcache_btree_node_split(b, btree_bset_first(n1)->keys);
- n2 = bch_btree_node_alloc(b->c, b->level, true);
+ n2 = bch_btree_node_alloc(b->c, op, b->level);
if (IS_ERR(n2))
goto err_free1;
if (!b->parent) {
- n3 = bch_btree_node_alloc(b->c, b->level + 1, true);
+ n3 = bch_btree_node_alloc(b->c, op, b->level + 1);
if (IS_ERR(n3))
goto err_free2;
}
+ mutex_lock(&n1->write_lock);
+ mutex_lock(&n2->write_lock);
+
bch_btree_insert_keys(n1, op, insert_keys, replace_key);
/*
@@ -1923,45 +2015,45 @@ static int btree_split(struct btree *b, struct btree_op *op,
bch_keylist_add(&parent_keys, &n2->key);
bch_btree_node_write(n2, &cl);
+ mutex_unlock(&n2->write_lock);
rw_unlock(true, n2);
} else {
trace_bcache_btree_node_compact(b, btree_bset_first(n1)->keys);
+ mutex_lock(&n1->write_lock);
bch_btree_insert_keys(n1, op, insert_keys, replace_key);
}
bch_keylist_add(&parent_keys, &n1->key);
bch_btree_node_write(n1, &cl);
+ mutex_unlock(&n1->write_lock);
if (n3) {
/* Depth increases, make a new root */
+ mutex_lock(&n3->write_lock);
bkey_copy_key(&n3->key, &MAX_KEY);
bch_btree_insert_keys(n3, op, &parent_keys, NULL);
bch_btree_node_write(n3, &cl);
+ mutex_unlock(&n3->write_lock);
closure_sync(&cl);
bch_btree_set_root(n3);
rw_unlock(true, n3);
-
- btree_node_free(b);
} else if (!b->parent) {
/* Root filled up but didn't need to be split */
closure_sync(&cl);
bch_btree_set_root(n1);
-
- btree_node_free(b);
} else {
/* Split a non root node */
closure_sync(&cl);
make_btree_freeing_key(b, parent_keys.top);
bch_keylist_push(&parent_keys);
- btree_node_free(b);
-
bch_btree_insert_node(b->parent, op, &parent_keys, NULL, NULL);
BUG_ON(!bch_keylist_empty(&parent_keys));
}
+ btree_node_free(b);
rw_unlock(true, n1);
bch_time_stats_update(&b->c->btree_split_time, start_time);
@@ -1976,7 +2068,7 @@ err_free1:
btree_node_free(n1);
rw_unlock(true, n1);
err:
- WARN(1, "bcache: btree split failed");
+ WARN(1, "bcache: btree split failed (level %u)", b->level);
if (n3 == ERR_PTR(-EAGAIN) ||
n2 == ERR_PTR(-EAGAIN) ||
@@ -1991,33 +2083,54 @@ static int bch_btree_insert_node(struct btree *b, struct btree_op *op,
atomic_t *journal_ref,
struct bkey *replace_key)
{
+ struct closure cl;
+
BUG_ON(b->level && replace_key);
+ closure_init_stack(&cl);
+
+ mutex_lock(&b->write_lock);
+
+ if (write_block(b) != btree_bset_last(b) &&
+ b->keys.last_set_unwritten)
+ bch_btree_init_next(b); /* just wrote a set */
+
if (bch_keylist_nkeys(insert_keys) > insert_u64s_remaining(b)) {
- if (current->bio_list) {
- op->lock = b->c->root->level + 1;
- return -EAGAIN;
- } else if (op->lock <= b->c->root->level) {
- op->lock = b->c->root->level + 1;
- return -EINTR;
- } else {
- /* Invalidated all iterators */
- int ret = btree_split(b, op, insert_keys, replace_key);
+ mutex_unlock(&b->write_lock);
+ goto split;
+ }
- return bch_keylist_empty(insert_keys) ?
- 0 : ret ?: -EINTR;
- }
- } else {
- BUG_ON(write_block(b) != btree_bset_last(b));
+ BUG_ON(write_block(b) != btree_bset_last(b));
- if (bch_btree_insert_keys(b, op, insert_keys, replace_key)) {
- if (!b->level)
- bch_btree_leaf_dirty(b, journal_ref);
- else
- bch_btree_node_write_sync(b);
- }
+ if (bch_btree_insert_keys(b, op, insert_keys, replace_key)) {
+ if (!b->level)
+ bch_btree_leaf_dirty(b, journal_ref);
+ else
+ bch_btree_node_write(b, &cl);
+ }
- return 0;
+ mutex_unlock(&b->write_lock);
+
+ /* wait for btree node write if necessary, after unlock */
+ closure_sync(&cl);
+
+ return 0;
+split:
+ if (current->bio_list) {
+ op->lock = b->c->root->level + 1;
+ return -EAGAIN;
+ } else if (op->lock <= b->c->root->level) {
+ op->lock = b->c->root->level + 1;
+ return -EINTR;
+ } else {
+ /* Invalidated all iterators */
+ int ret = btree_split(b, op, insert_keys, replace_key);
+
+ if (bch_keylist_empty(insert_keys))
+ return 0;
+ else if (!ret)
+ return -EINTR;
+ return ret;
}
}
@@ -2403,18 +2516,3 @@ void bch_keybuf_init(struct keybuf *buf)
spin_lock_init(&buf->lock);
array_allocator_init(&buf->freelist);
}
-
-void bch_btree_exit(void)
-{
- if (btree_io_wq)
- destroy_workqueue(btree_io_wq);
-}
-
-int __init bch_btree_init(void)
-{
- btree_io_wq = create_singlethread_workqueue("bch_btree_io");
- if (!btree_io_wq)
- return -ENOMEM;
-
- return 0;
-}
diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h
index af065e97e55c..91dfa5e69685 100644
--- a/drivers/md/bcache/btree.h
+++ b/drivers/md/bcache/btree.h
@@ -127,6 +127,8 @@ struct btree {
struct cache_set *c;
struct btree *parent;
+ struct mutex write_lock;
+
unsigned long flags;
uint16_t written; /* would be nice to kill */
uint8_t level;
@@ -236,11 +238,13 @@ static inline void rw_unlock(bool w, struct btree *b)
}
void bch_btree_node_read_done(struct btree *);
+void __bch_btree_node_write(struct btree *, struct closure *);
void bch_btree_node_write(struct btree *, struct closure *);
void bch_btree_set_root(struct btree *);
-struct btree *bch_btree_node_alloc(struct cache_set *, int, bool);
-struct btree *bch_btree_node_get(struct cache_set *, struct bkey *, int, bool);
+struct btree *bch_btree_node_alloc(struct cache_set *, struct btree_op *, int);
+struct btree *bch_btree_node_get(struct cache_set *, struct btree_op *,
+ struct bkey *, int, bool);
int bch_btree_insert_check_key(struct btree *, struct btree_op *,
struct bkey *);
@@ -248,10 +252,10 @@ int bch_btree_insert(struct cache_set *, struct keylist *,
atomic_t *, struct bkey *);
int bch_gc_thread_start(struct cache_set *);
-size_t bch_btree_gc_finish(struct cache_set *);
+void bch_initial_gc_finish(struct cache_set *);
void bch_moving_gc(struct cache_set *);
int bch_btree_check(struct cache_set *);
-uint8_t __bch_btree_mark_key(struct cache_set *, int, struct bkey *);
+void bch_initial_mark_key(struct cache_set *, int, struct bkey *);
static inline void wake_up_gc(struct cache_set *c)
{
diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c
index 416d1a3e028e..3a0de4cf9771 100644
--- a/drivers/md/bcache/extents.c
+++ b/drivers/md/bcache/extents.c
@@ -194,9 +194,9 @@ err:
mutex_unlock(&b->c->bucket_lock);
bch_extent_to_text(buf, sizeof(buf), k);
btree_bug(b,
-"inconsistent btree pointer %s: bucket %zi pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i",
+"inconsistent btree pointer %s: bucket %zi pin %i prio %i gen %i last_gc %i mark %llu",
buf, PTR_BUCKET_NR(b->c, k, i), atomic_read(&g->pin),
- g->prio, g->gen, g->last_gc, GC_MARK(g), g->gc_gen);
+ g->prio, g->gen, g->last_gc, GC_MARK(g));
return true;
}
@@ -308,6 +308,16 @@ static struct bkey *bch_extent_sort_fixup(struct btree_iter *iter,
return NULL;
}
+static void bch_subtract_dirty(struct bkey *k,
+ struct cache_set *c,
+ uint64_t offset,
+ int sectors)
+{
+ if (KEY_DIRTY(k))
+ bcache_dev_sectors_dirty_add(c, KEY_INODE(k),
+ offset, -sectors);
+}
+
static bool bch_extent_insert_fixup(struct btree_keys *b,
struct bkey *insert,
struct btree_iter *iter,
@@ -315,13 +325,6 @@ static bool bch_extent_insert_fixup(struct btree_keys *b,
{
struct cache_set *c = container_of(b, struct btree, keys)->c;
- void subtract_dirty(struct bkey *k, uint64_t offset, int sectors)
- {
- if (KEY_DIRTY(k))
- bcache_dev_sectors_dirty_add(c, KEY_INODE(k),
- offset, -sectors);
- }
-
uint64_t old_offset;
unsigned old_size, sectors_found = 0;
@@ -398,7 +401,8 @@ static bool bch_extent_insert_fixup(struct btree_keys *b,
struct bkey *top;
- subtract_dirty(k, KEY_START(insert), KEY_SIZE(insert));
+ bch_subtract_dirty(k, c, KEY_START(insert),
+ KEY_SIZE(insert));
if (bkey_written(b, k)) {
/*
@@ -448,7 +452,7 @@ static bool bch_extent_insert_fixup(struct btree_keys *b,
}
}
- subtract_dirty(k, old_offset, old_size - KEY_SIZE(k));
+ bch_subtract_dirty(k, c, old_offset, old_size - KEY_SIZE(k));
}
check_failed:
@@ -499,9 +503,9 @@ static bool bch_extent_bad_expensive(struct btree *b, const struct bkey *k,
if (mutex_trylock(&b->c->bucket_lock)) {
if (b->c->gc_mark_valid &&
- ((GC_MARK(g) != GC_MARK_DIRTY &&
- KEY_DIRTY(k)) ||
- GC_MARK(g) == GC_MARK_METADATA))
+ (!GC_MARK(g) ||
+ GC_MARK(g) == GC_MARK_METADATA ||
+ (GC_MARK(g) != GC_MARK_DIRTY && KEY_DIRTY(k))))
goto err;
if (g->prio == BTREE_PRIO)
@@ -515,9 +519,9 @@ err:
mutex_unlock(&b->c->bucket_lock);
bch_extent_to_text(buf, sizeof(buf), k);
btree_bug(b,
-"inconsistent extent pointer %s:\nbucket %zu pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i",
+"inconsistent extent pointer %s:\nbucket %zu pin %i prio %i gen %i last_gc %i mark %llu",
buf, PTR_BUCKET_NR(b->c, k, ptr), atomic_read(&g->pin),
- g->prio, g->gen, g->last_gc, GC_MARK(g), g->gc_gen);
+ g->prio, g->gen, g->last_gc, GC_MARK(g));
return true;
}
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
index 18039affc306..59e82021b5bb 100644
--- a/drivers/md/bcache/journal.c
+++ b/drivers/md/bcache/journal.c
@@ -237,8 +237,14 @@ bsearch:
for (i = 0; i < ca->sb.njournal_buckets; i++)
if (ja->seq[i] > seq) {
seq = ja->seq[i];
- ja->cur_idx = ja->discard_idx =
- ja->last_idx = i;
+ /*
+ * When journal_reclaim() goes to allocate for
+ * the first time, it'll use the bucket after
+ * ja->cur_idx
+ */
+ ja->cur_idx = i;
+ ja->last_idx = ja->discard_idx = (i + 1) %
+ ca->sb.njournal_buckets;
}
}
@@ -288,16 +294,11 @@ void bch_journal_mark(struct cache_set *c, struct list_head *list)
k = bkey_next(k)) {
unsigned j;
- for (j = 0; j < KEY_PTRS(k); j++) {
- struct bucket *g = PTR_BUCKET(c, k, j);
- atomic_inc(&g->pin);
+ for (j = 0; j < KEY_PTRS(k); j++)
+ if (ptr_available(c, k, j))
+ atomic_inc(&PTR_BUCKET(c, k, j)->pin);
- if (g->prio == BTREE_PRIO &&
- !ptr_stale(c, k, j))
- g->prio = INITIAL_PRIO;
- }
-
- __bch_btree_mark_key(c, 0, k);
+ bch_initial_mark_key(c, 0, k);
}
}
}
@@ -312,8 +313,6 @@ int bch_journal_replay(struct cache_set *s, struct list_head *list)
uint64_t start = i->j.last_seq, end = i->j.seq, n = start;
struct keylist keylist;
- bch_keylist_init(&keylist);
-
list_for_each_entry(i, list, list) {
BUG_ON(i->pin && atomic_read(i->pin) != 1);
@@ -326,8 +325,7 @@ int bch_journal_replay(struct cache_set *s, struct list_head *list)
k = bkey_next(k)) {
trace_bcache_journal_replay_key(k);
- bkey_copy(keylist.top, k);
- bch_keylist_push(&keylist);
+ bch_keylist_init_single(&keylist, k);
ret = bch_btree_insert(s, &keylist, i->pin, NULL);
if (ret)
@@ -383,16 +381,15 @@ retry:
b = best;
if (b) {
- rw_lock(true, b, b->level);
-
+ mutex_lock(&b->write_lock);
if (!btree_current_write(b)->journal) {
- rw_unlock(true, b);
+ mutex_unlock(&b->write_lock);
/* We raced */
goto retry;
}
- bch_btree_node_write(b, NULL);
- rw_unlock(true, b);
+ __bch_btree_node_write(b, NULL);
+ mutex_unlock(&b->write_lock);
}
}
@@ -536,6 +533,7 @@ void bch_journal_next(struct journal *j)
atomic_set(&fifo_back(&j->pin), 1);
j->cur->data->seq = ++j->seq;
+ j->cur->dirty = false;
j->cur->need_write = false;
j->cur->data->keys = 0;
@@ -731,7 +729,10 @@ static void journal_write_work(struct work_struct *work)
struct cache_set,
journal.work);
spin_lock(&c->journal.lock);
- journal_try_write(c);
+ if (c->journal.cur->dirty)
+ journal_try_write(c);
+ else
+ spin_unlock(&c->journal.lock);
}
/*
@@ -761,7 +762,8 @@ atomic_t *bch_journal(struct cache_set *c,
if (parent) {
closure_wait(&w->wait, parent);
journal_try_write(c);
- } else if (!w->need_write) {
+ } else if (!w->dirty) {
+ w->dirty = true;
schedule_delayed_work(&c->journal.work,
msecs_to_jiffies(c->journal_delay_ms));
spin_unlock(&c->journal.lock);
diff --git a/drivers/md/bcache/journal.h b/drivers/md/bcache/journal.h
index 9180c4465075..e3c39457afbb 100644
--- a/drivers/md/bcache/journal.h
+++ b/drivers/md/bcache/journal.h
@@ -95,6 +95,7 @@ struct journal_write {
struct cache_set *c;
struct closure_waitlist wait;
+ bool dirty;
bool need_write;
};
diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c
index 9eb60d102de8..cd7490311e51 100644
--- a/drivers/md/bcache/movinggc.c
+++ b/drivers/md/bcache/movinggc.c
@@ -24,12 +24,10 @@ static bool moving_pred(struct keybuf *buf, struct bkey *k)
moving_gc_keys);
unsigned i;
- for (i = 0; i < KEY_PTRS(k); i++) {
- struct bucket *g = PTR_BUCKET(c, k, i);
-
- if (GC_MOVE(g))
+ for (i = 0; i < KEY_PTRS(k); i++)
+ if (ptr_available(c, k, i) &&
+ GC_MOVE(PTR_BUCKET(c, k, i)))
return true;
- }
return false;
}
@@ -115,7 +113,7 @@ static void write_moving(struct closure *cl)
closure_call(&op->cl, bch_data_insert, NULL, cl);
}
- continue_at(cl, write_moving_finish, system_wq);
+ continue_at(cl, write_moving_finish, op->wq);
}
static void read_moving_submit(struct closure *cl)
@@ -125,7 +123,7 @@ static void read_moving_submit(struct closure *cl)
bch_submit_bbio(bio, io->op.c, &io->w->key, 0);
- continue_at(cl, write_moving, system_wq);
+ continue_at(cl, write_moving, io->op.wq);
}
static void read_moving(struct cache_set *c)
@@ -160,6 +158,7 @@ static void read_moving(struct cache_set *c)
io->w = w;
io->op.inode = KEY_INODE(&w->key);
io->op.c = c;
+ io->op.wq = c->moving_gc_wq;
moving_init(io);
bio = &io->bio.bio;
@@ -216,7 +215,10 @@ void bch_moving_gc(struct cache_set *c)
ca->heap.used = 0;
for_each_bucket(b, ca) {
- if (!GC_SECTORS_USED(b))
+ if (GC_MARK(b) == GC_MARK_METADATA ||
+ !GC_SECTORS_USED(b) ||
+ GC_SECTORS_USED(b) == ca->sb.bucket_size ||
+ atomic_read(&b->pin))
continue;
if (!heap_full(&ca->heap)) {
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 5d5d031cf381..15fff4f68a7c 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -12,11 +12,9 @@
#include "request.h"
#include "writeback.h"
-#include <linux/cgroup.h>
#include <linux/module.h>
#include <linux/hash.h>
#include <linux/random.h>
-#include "blk-cgroup.h"
#include <trace/events/bcache.h>
@@ -27,171 +25,13 @@ struct kmem_cache *bch_search_cache;
static void bch_data_insert_start(struct closure *);
-/* Cgroup interface */
-
-#ifdef CONFIG_CGROUP_BCACHE
-static struct bch_cgroup bcache_default_cgroup = { .cache_mode = -1 };
-
-static struct bch_cgroup *cgroup_to_bcache(struct cgroup *cgroup)
-{
- struct cgroup_subsys_state *css;
- return cgroup &&
- (css = cgroup_subsys_state(cgroup, bcache_subsys_id))
- ? container_of(css, struct bch_cgroup, css)
- : &bcache_default_cgroup;
-}
-
-struct bch_cgroup *bch_bio_to_cgroup(struct bio *bio)
-{
- struct cgroup_subsys_state *css = bio->bi_css
- ? cgroup_subsys_state(bio->bi_css->cgroup, bcache_subsys_id)
- : task_subsys_state(current, bcache_subsys_id);
-
- return css
- ? container_of(css, struct bch_cgroup, css)
- : &bcache_default_cgroup;
-}
-
-static ssize_t cache_mode_read(struct cgroup *cgrp, struct cftype *cft,
- struct file *file,
- char __user *buf, size_t nbytes, loff_t *ppos)
-{
- char tmp[1024];
- int len = bch_snprint_string_list(tmp, PAGE_SIZE, bch_cache_modes,
- cgroup_to_bcache(cgrp)->cache_mode + 1);
-
- if (len < 0)
- return len;
-
- return simple_read_from_buffer(buf, nbytes, ppos, tmp, len);
-}
-
-static int cache_mode_write(struct cgroup *cgrp, struct cftype *cft,
- const char *buf)
-{
- int v = bch_read_string_list(buf, bch_cache_modes);
- if (v < 0)
- return v;
-
- cgroup_to_bcache(cgrp)->cache_mode = v - 1;
- return 0;
-}
-
-static u64 bch_verify_read(struct cgroup *cgrp, struct cftype *cft)
-{
- return cgroup_to_bcache(cgrp)->verify;
-}
-
-static int bch_verify_write(struct cgroup *cgrp, struct cftype *cft, u64 val)
-{
- cgroup_to_bcache(cgrp)->verify = val;
- return 0;
-}
-
-static u64 bch_cache_hits_read(struct cgroup *cgrp, struct cftype *cft)
-{
- struct bch_cgroup *bcachecg = cgroup_to_bcache(cgrp);
- return atomic_read(&bcachecg->stats.cache_hits);
-}
-
-static u64 bch_cache_misses_read(struct cgroup *cgrp, struct cftype *cft)
-{
- struct bch_cgroup *bcachecg = cgroup_to_bcache(cgrp);
- return atomic_read(&bcachecg->stats.cache_misses);
-}
-
-static u64 bch_cache_bypass_hits_read(struct cgroup *cgrp,
- struct cftype *cft)
-{
- struct bch_cgroup *bcachecg = cgroup_to_bcache(cgrp);
- return atomic_read(&bcachecg->stats.cache_bypass_hits);
-}
-
-static u64 bch_cache_bypass_misses_read(struct cgroup *cgrp,
- struct cftype *cft)
-{
- struct bch_cgroup *bcachecg = cgroup_to_bcache(cgrp);
- return atomic_read(&bcachecg->stats.cache_bypass_misses);
-}
-
-static struct cftype bch_files[] = {
- {
- .name = "cache_mode",
- .read = cache_mode_read,
- .write_string = cache_mode_write,
- },
- {
- .name = "verify",
- .read_u64 = bch_verify_read,
- .write_u64 = bch_verify_write,
- },
- {
- .name = "cache_hits",
- .read_u64 = bch_cache_hits_read,
- },
- {
- .name = "cache_misses",
- .read_u64 = bch_cache_misses_read,
- },
- {
- .name = "cache_bypass_hits",
- .read_u64 = bch_cache_bypass_hits_read,
- },
- {
- .name = "cache_bypass_misses",
- .read_u64 = bch_cache_bypass_misses_read,
- },
- { } /* terminate */
-};
-
-static void init_bch_cgroup(struct bch_cgroup *cg)
-{
- cg->cache_mode = -1;
-}
-
-static struct cgroup_subsys_state *bcachecg_create(struct cgroup *cgroup)
-{
- struct bch_cgroup *cg;
-
- cg = kzalloc(sizeof(*cg), GFP_KERNEL);
- if (!cg)
- return ERR_PTR(-ENOMEM);
- init_bch_cgroup(cg);
- return &cg->css;
-}
-
-static void bcachecg_destroy(struct cgroup *cgroup)
-{
- struct bch_cgroup *cg = cgroup_to_bcache(cgroup);
- kfree(cg);
-}
-
-struct cgroup_subsys bcache_subsys = {
- .create = bcachecg_create,
- .destroy = bcachecg_destroy,
- .subsys_id = bcache_subsys_id,
- .name = "bcache",
- .module = THIS_MODULE,
-};
-EXPORT_SYMBOL_GPL(bcache_subsys);
-#endif
-
static unsigned cache_mode(struct cached_dev *dc, struct bio *bio)
{
-#ifdef CONFIG_CGROUP_BCACHE
- int r = bch_bio_to_cgroup(bio)->cache_mode;
- if (r >= 0)
- return r;
-#endif
return BDEV_CACHE_MODE(&dc->sb);
}
static bool verify(struct cached_dev *dc, struct bio *bio)
{
-#ifdef CONFIG_CGROUP_BCACHE
- if (bch_bio_to_cgroup(bio)->verify)
- return true;
-#endif
return dc->verify;
}
@@ -248,7 +88,7 @@ static void bch_data_insert_keys(struct closure *cl)
atomic_dec_bug(journal_ref);
if (!op->insert_data_done)
- continue_at(cl, bch_data_insert_start, bcache_wq);
+ continue_at(cl, bch_data_insert_start, op->wq);
bch_keylist_free(&op->insert_keys);
closure_return(cl);
@@ -297,7 +137,7 @@ static void bch_data_invalidate(struct closure *cl)
op->insert_data_done = true;
bio_put(bio);
out:
- continue_at(cl, bch_data_insert_keys, bcache_wq);
+ continue_at(cl, bch_data_insert_keys, op->wq);
}
static void bch_data_insert_error(struct closure *cl)
@@ -340,7 +180,7 @@ static void bch_data_insert_endio(struct bio *bio, int error)
if (op->writeback)
op->error = error;
else if (!op->replace)
- set_closure_fn(cl, bch_data_insert_error, bcache_wq);
+ set_closure_fn(cl, bch_data_insert_error, op->wq);
else
set_closure_fn(cl, NULL, NULL);
}
@@ -376,7 +216,7 @@ static void bch_data_insert_start(struct closure *cl)
if (bch_keylist_realloc(&op->insert_keys,
3 + (op->csum ? 1 : 0),
op->c))
- continue_at(cl, bch_data_insert_keys, bcache_wq);
+ continue_at(cl, bch_data_insert_keys, op->wq);
k = op->insert_keys.top;
bkey_init(k);
@@ -413,7 +253,7 @@ static void bch_data_insert_start(struct closure *cl)
} while (n != bio);
op->insert_data_done = true;
- continue_at(cl, bch_data_insert_keys, bcache_wq);
+ continue_at(cl, bch_data_insert_keys, op->wq);
err:
/* bch_alloc_sectors() blocks if s->writeback = true */
BUG_ON(op->writeback);
@@ -442,7 +282,7 @@ err:
bio_put(bio);
if (!bch_keylist_empty(&op->insert_keys))
- continue_at(cl, bch_data_insert_keys, bcache_wq);
+ continue_at(cl, bch_data_insert_keys, op->wq);
else
closure_return(cl);
}
@@ -824,6 +664,7 @@ static inline struct search *search_alloc(struct bio *bio,
s->iop.error = 0;
s->iop.flags = 0;
s->iop.flush_journal = (bio->bi_rw & (REQ_FLUSH|REQ_FUA)) != 0;
+ s->iop.wq = bcache_wq;
return s;
}
@@ -1203,22 +1044,13 @@ void bch_cached_dev_request_init(struct cached_dev *dc)
static int flash_dev_cache_miss(struct btree *b, struct search *s,
struct bio *bio, unsigned sectors)
{
- struct bio_vec bv;
- struct bvec_iter iter;
-
- /* Zero fill bio */
+ unsigned bytes = min(sectors, bio_sectors(bio)) << 9;
- bio_for_each_segment(bv, bio, iter) {
- unsigned j = min(bv.bv_len >> 9, sectors);
-
- void *p = kmap(bv.bv_page);
- memset(p + bv.bv_offset, 0, j << 9);
- kunmap(bv.bv_page);
-
- sectors -= j;
- }
+ swap(bio->bi_iter.bi_size, bytes);
+ zero_fill_bio(bio);
+ swap(bio->bi_iter.bi_size, bytes);
- bio_advance(bio, min(sectors << 9, bio->bi_iter.bi_size));
+ bio_advance(bio, bytes);
if (!bio->bi_iter.bi_size)
return MAP_DONE;
@@ -1313,9 +1145,6 @@ void bch_flash_dev_request_init(struct bcache_device *d)
void bch_request_exit(void)
{
-#ifdef CONFIG_CGROUP_BCACHE
- cgroup_unload_subsys(&bcache_subsys);
-#endif
if (bch_search_cache)
kmem_cache_destroy(bch_search_cache);
}
@@ -1326,11 +1155,5 @@ int __init bch_request_init(void)
if (!bch_search_cache)
return -ENOMEM;
-#ifdef CONFIG_CGROUP_BCACHE
- cgroup_load_subsys(&bcache_subsys);
- init_bch_cgroup(&bcache_default_cgroup);
-
- cgroup_add_cftypes(&bcache_subsys, bch_files);
-#endif
return 0;
}
diff --git a/drivers/md/bcache/request.h b/drivers/md/bcache/request.h
index 39f21dbedc38..1ff36875c2b3 100644
--- a/drivers/md/bcache/request.h
+++ b/drivers/md/bcache/request.h
@@ -1,12 +1,11 @@
#ifndef _BCACHE_REQUEST_H_
#define _BCACHE_REQUEST_H_
-#include <linux/cgroup.h>
-
struct data_insert_op {
struct closure cl;
struct cache_set *c;
struct bio *bio;
+ struct workqueue_struct *wq;
unsigned inode;
uint16_t write_point;
@@ -41,20 +40,4 @@ void bch_flash_dev_request_init(struct bcache_device *d);
extern struct kmem_cache *bch_search_cache, *bch_passthrough_cache;
-struct bch_cgroup {
-#ifdef CONFIG_CGROUP_BCACHE
- struct cgroup_subsys_state css;
-#endif
- /*
- * We subtract one from the index into bch_cache_modes[], so that
- * default == -1; this makes it so the rest match up with d->cache_mode,
- * and we use d->cache_mode if cgrp->cache_mode < 0
- */
- short cache_mode;
- bool verify;
- struct cache_stat_collector stats;
-};
-
-struct bch_cgroup *bch_bio_to_cgroup(struct bio *bio);
-
#endif /* _BCACHE_REQUEST_H_ */
diff --git a/drivers/md/bcache/stats.c b/drivers/md/bcache/stats.c
index 84d0782f702e..0ca072c20d0d 100644
--- a/drivers/md/bcache/stats.c
+++ b/drivers/md/bcache/stats.c
@@ -201,9 +201,6 @@ void bch_mark_cache_accounting(struct cache_set *c, struct bcache_device *d,
struct cached_dev *dc = container_of(d, struct cached_dev, disk);
mark_cache_stats(&dc->accounting.collector, hit, bypass);
mark_cache_stats(&c->accounting.collector, hit, bypass);
-#ifdef CONFIG_CGROUP_BCACHE
- mark_cache_stats(&(bch_bio_to_cgroup(s->orig_bio)->stats), hit, bypass);
-#endif
}
void bch_mark_cache_readahead(struct cache_set *c, struct bcache_device *d)
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 24a3a1546caa..926ded8ccbf5 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -541,9 +541,6 @@ static void prio_io(struct cache *ca, uint64_t bucket, unsigned long rw)
closure_sync(cl);
}
-#define buckets_free(c) "free %zu, free_inc %zu, unused %zu", \
- fifo_used(&c->free), fifo_used(&c->free_inc), fifo_used(&c->unused)
-
void bch_prio_write(struct cache *ca)
{
int i;
@@ -554,10 +551,6 @@ void bch_prio_write(struct cache *ca)
lockdep_assert_held(&ca->set->bucket_lock);
- for (b = ca->buckets;
- b < ca->buckets + ca->sb.nbuckets; b++)
- b->disk_gen = b->gen;
-
ca->disk_buckets->seq++;
atomic_long_add(ca->sb.bucket_size * prio_buckets(ca),
@@ -601,14 +594,17 @@ void bch_prio_write(struct cache *ca)
mutex_lock(&ca->set->bucket_lock);
- ca->need_save_prio = 0;
-
/*
* Don't want the old priorities to get garbage collected until after we
* finish writing the new ones, and they're journalled
*/
- for (i = 0; i < prio_buckets(ca); i++)
+ for (i = 0; i < prio_buckets(ca); i++) {
+ if (ca->prio_last_buckets[i])
+ __bch_bucket_free(ca,
+ &ca->buckets[ca->prio_last_buckets[i]]);
+
ca->prio_last_buckets[i] = ca->prio_buckets[i];
+ }
}
static void prio_read(struct cache *ca, uint64_t bucket)
@@ -639,7 +635,7 @@ static void prio_read(struct cache *ca, uint64_t bucket)
}
b->prio = le16_to_cpu(d->prio);
- b->gen = b->disk_gen = b->last_gc = b->gc_gen = d->gen;
+ b->gen = b->last_gc = d->gen;
}
}
@@ -843,6 +839,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size,
q->limits.max_segment_size = UINT_MAX;
q->limits.max_segments = BIO_MAX_PAGES;
q->limits.max_discard_sectors = UINT_MAX;
+ q->limits.discard_granularity = 512;
q->limits.io_min = block_size;
q->limits.logical_block_size = block_size;
q->limits.physical_block_size = block_size;
@@ -1355,6 +1352,8 @@ static void cache_set_free(struct closure *cl)
bch_bset_sort_state_free(&c->sort);
free_pages((unsigned long) c->uuids, ilog2(bucket_pages(c)));
+ if (c->moving_gc_wq)
+ destroy_workqueue(c->moving_gc_wq);
if (c->bio_split)
bioset_free(c->bio_split);
if (c->fill_iter)
@@ -1395,14 +1394,21 @@ static void cache_set_flush(struct closure *cl)
list_add(&c->root->list, &c->btree_cache);
/* Should skip this if we're unregistering because of an error */
- list_for_each_entry(b, &c->btree_cache, list)
+ list_for_each_entry(b, &c->btree_cache, list) {
+ mutex_lock(&b->write_lock);
if (btree_node_dirty(b))
- bch_btree_node_write(b, NULL);
+ __bch_btree_node_write(b, NULL);
+ mutex_unlock(&b->write_lock);
+ }
for_each_cache(ca, c, i)
if (ca->alloc_thread)
kthread_stop(ca->alloc_thread);
+ cancel_delayed_work_sync(&c->journal.work);
+ /* flush last journal entry if needed */
+ c->journal.work.work.func(&c->journal.work.work);
+
closure_return(cl);
}
@@ -1485,14 +1491,13 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
sema_init(&c->sb_write_mutex, 1);
mutex_init(&c->bucket_lock);
- init_waitqueue_head(&c->try_wait);
+ init_waitqueue_head(&c->btree_cache_wait);
init_waitqueue_head(&c->bucket_wait);
sema_init(&c->uuid_write_mutex, 1);
spin_lock_init(&c->btree_gc_time.lock);
spin_lock_init(&c->btree_split_time.lock);
spin_lock_init(&c->btree_read_time.lock);
- spin_lock_init(&c->try_harder_time.lock);
bch_moving_init_cache_set(c);
@@ -1517,6 +1522,7 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
!(c->fill_iter = mempool_create_kmalloc_pool(1, iter_size)) ||
!(c->bio_split = bioset_create(4, offsetof(struct bbio, bio))) ||
!(c->uuids = alloc_bucket_pages(GFP_KERNEL, c)) ||
+ !(c->moving_gc_wq = create_workqueue("bcache_gc")) ||
bch_journal_alloc(c) ||
bch_btree_cache_alloc(c) ||
bch_open_buckets_alloc(c) ||
@@ -1580,7 +1586,7 @@ static void run_cache_set(struct cache_set *c)
goto err;
err = "error reading btree root";
- c->root = bch_btree_node_get(c, k, j->btree_level, true);
+ c->root = bch_btree_node_get(c, NULL, k, j->btree_level, true);
if (IS_ERR_OR_NULL(c->root))
goto err;
@@ -1596,7 +1602,7 @@ static void run_cache_set(struct cache_set *c)
goto err;
bch_journal_mark(c, &journal);
- bch_btree_gc_finish(c);
+ bch_initial_gc_finish(c);
pr_debug("btree_check() done");
/*
@@ -1638,7 +1644,7 @@ static void run_cache_set(struct cache_set *c)
ca->sb.d[j] = ca->sb.first_bucket + j;
}
- bch_btree_gc_finish(c);
+ bch_initial_gc_finish(c);
err = "error starting allocator thread";
for_each_cache(ca, c, i)
@@ -1655,12 +1661,14 @@ static void run_cache_set(struct cache_set *c)
goto err;
err = "cannot allocate new btree root";
- c->root = bch_btree_node_alloc(c, 0, true);
+ c->root = bch_btree_node_alloc(c, NULL, 0);
if (IS_ERR_OR_NULL(c->root))
goto err;
+ mutex_lock(&c->root->write_lock);
bkey_copy_key(&c->root->key, &MAX_KEY);
bch_btree_node_write(c->root, &cl);
+ mutex_unlock(&c->root->write_lock);
bch_btree_set_root(c->root);
rw_unlock(true, c->root);
@@ -1782,7 +1790,6 @@ void bch_cache_release(struct kobject *kobj)
vfree(ca->buckets);
free_heap(&ca->heap);
- free_fifo(&ca->unused);
free_fifo(&ca->free_inc);
for (i = 0; i < RESERVE_NR; i++)
@@ -1819,7 +1826,6 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca)
!init_fifo(&ca->free[RESERVE_MOVINGGC], free, GFP_KERNEL) ||
!init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL) ||
!init_fifo(&ca->free_inc, free << 2, GFP_KERNEL) ||
- !init_fifo(&ca->unused, free << 2, GFP_KERNEL) ||
!init_heap(&ca->heap, free << 3, GFP_KERNEL) ||
!(ca->buckets = vzalloc(sizeof(struct bucket) *
ca->sb.nbuckets)) ||
@@ -1834,13 +1840,7 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca)
for_each_bucket(b, ca)
atomic_set(&b->pin, 0);
- if (bch_cache_allocator_init(ca))
- goto err;
-
return 0;
-err:
- kobject_put(&ca->kobj);
- return -ENOMEM;
}
static void register_cache(struct cache_sb *sb, struct page *sb_page,
@@ -1869,7 +1869,10 @@ static void register_cache(struct cache_sb *sb, struct page *sb_page,
if (kobject_add(&ca->kobj, &part_to_dev(bdev->bd_part)->kobj, "bcache"))
goto err;
+ mutex_lock(&bch_register_lock);
err = register_cache_set(ca);
+ mutex_unlock(&bch_register_lock);
+
if (err)
goto err;
@@ -1931,8 +1934,6 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
if (!try_module_get(THIS_MODULE))
return -EBUSY;
- mutex_lock(&bch_register_lock);
-
if (!(path = kstrndup(buffer, size, GFP_KERNEL)) ||
!(sb = kmalloc(sizeof(struct cache_sb), GFP_KERNEL)))
goto err;
@@ -1965,7 +1966,9 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
if (!dc)
goto err_close;
+ mutex_lock(&bch_register_lock);
register_bdev(sb, sb_page, bdev, dc);
+ mutex_unlock(&bch_register_lock);
} else {
struct cache *ca = kzalloc(sizeof(*ca), GFP_KERNEL);
if (!ca)
@@ -1978,7 +1981,6 @@ out:
put_page(sb_page);
kfree(sb);
kfree(path);
- mutex_unlock(&bch_register_lock);
module_put(THIS_MODULE);
return ret;
@@ -2057,7 +2059,6 @@ static void bcache_exit(void)
{
bch_debug_exit();
bch_request_exit();
- bch_btree_exit();
if (bcache_kobj)
kobject_put(bcache_kobj);
if (bcache_wq)
@@ -2087,7 +2088,6 @@ static int __init bcache_init(void)
if (!(bcache_wq = create_workqueue("bcache")) ||
!(bcache_kobj = kobject_create_and_add("bcache", fs_kobj)) ||
sysfs_create_files(bcache_kobj, files) ||
- bch_btree_init() ||
bch_request_init() ||
bch_debug_init(bcache_kobj))
goto err;
diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c
index d8458d477a12..b3ff57d61dde 100644
--- a/drivers/md/bcache/sysfs.c
+++ b/drivers/md/bcache/sysfs.c
@@ -54,7 +54,6 @@ sysfs_time_stats_attribute(btree_gc, sec, ms);
sysfs_time_stats_attribute(btree_split, sec, us);
sysfs_time_stats_attribute(btree_sort, ms, us);
sysfs_time_stats_attribute(btree_read, ms, us);
-sysfs_time_stats_attribute(try_harder, ms, us);
read_attribute(btree_nodes);
read_attribute(btree_used_percent);
@@ -406,7 +405,7 @@ struct bset_stats_op {
struct bset_stats stats;
};
-static int btree_bset_stats(struct btree_op *b_op, struct btree *b)
+static int bch_btree_bset_stats(struct btree_op *b_op, struct btree *b)
{
struct bset_stats_op *op = container_of(b_op, struct bset_stats_op, op);
@@ -424,7 +423,7 @@ static int bch_bset_print_stats(struct cache_set *c, char *buf)
memset(&op, 0, sizeof(op));
bch_btree_op_init(&op.op, -1);
- ret = bch_btree_map_nodes(&op.op, c, &ZERO_KEY, btree_bset_stats);
+ ret = bch_btree_map_nodes(&op.op, c, &ZERO_KEY, bch_btree_bset_stats);
if (ret < 0)
return ret;
@@ -442,81 +441,81 @@ static int bch_bset_print_stats(struct cache_set *c, char *buf)
op.stats.floats, op.stats.failed);
}
-SHOW(__bch_cache_set)
+static unsigned bch_root_usage(struct cache_set *c)
{
- unsigned root_usage(struct cache_set *c)
- {
- unsigned bytes = 0;
- struct bkey *k;
- struct btree *b;
- struct btree_iter iter;
+ unsigned bytes = 0;
+ struct bkey *k;
+ struct btree *b;
+ struct btree_iter iter;
- goto lock_root;
+ goto lock_root;
- do {
- rw_unlock(false, b);
+ do {
+ rw_unlock(false, b);
lock_root:
- b = c->root;
- rw_lock(false, b, b->level);
- } while (b != c->root);
+ b = c->root;
+ rw_lock(false, b, b->level);
+ } while (b != c->root);
- for_each_key_filter(&b->keys, k, &iter, bch_ptr_bad)
- bytes += bkey_bytes(k);
+ for_each_key_filter(&b->keys, k, &iter, bch_ptr_bad)
+ bytes += bkey_bytes(k);
- rw_unlock(false, b);
+ rw_unlock(false, b);
- return (bytes * 100) / btree_bytes(c);
- }
+ return (bytes * 100) / btree_bytes(c);
+}
- size_t cache_size(struct cache_set *c)
- {
- size_t ret = 0;
- struct btree *b;
+static size_t bch_cache_size(struct cache_set *c)
+{
+ size_t ret = 0;
+ struct btree *b;
- mutex_lock(&c->bucket_lock);
- list_for_each_entry(b, &c->btree_cache, list)
- ret += 1 << (b->keys.page_order + PAGE_SHIFT);
+ mutex_lock(&c->bucket_lock);
+ list_for_each_entry(b, &c->btree_cache, list)
+ ret += 1 << (b->keys.page_order + PAGE_SHIFT);
- mutex_unlock(&c->bucket_lock);
- return ret;
- }
-
- unsigned cache_max_chain(struct cache_set *c)
- {
- unsigned ret = 0;
- struct hlist_head *h;
+ mutex_unlock(&c->bucket_lock);
+ return ret;
+}
- mutex_lock(&c->bucket_lock);
+static unsigned bch_cache_max_chain(struct cache_set *c)
+{
+ unsigned ret = 0;
+ struct hlist_head *h;
- for (h = c->bucket_hash;
- h < c->bucket_hash + (1 << BUCKET_HASH_BITS);
- h++) {
- unsigned i = 0;
- struct hlist_node *p;
+ mutex_lock(&c->bucket_lock);
- hlist_for_each(p, h)
- i++;
+ for (h = c->bucket_hash;
+ h < c->bucket_hash + (1 << BUCKET_HASH_BITS);
+ h++) {
+ unsigned i = 0;
+ struct hlist_node *p;
- ret = max(ret, i);
- }
+ hlist_for_each(p, h)
+ i++;
- mutex_unlock(&c->bucket_lock);
- return ret;
+ ret = max(ret, i);
}
- unsigned btree_used(struct cache_set *c)
- {
- return div64_u64(c->gc_stats.key_bytes * 100,
- (c->gc_stats.nodes ?: 1) * btree_bytes(c));
- }
+ mutex_unlock(&c->bucket_lock);
+ return ret;
+}
- unsigned average_key_size(struct cache_set *c)
- {
- return c->gc_stats.nkeys
- ? div64_u64(c->gc_stats.data, c->gc_stats.nkeys)
- : 0;
- }
+static unsigned bch_btree_used(struct cache_set *c)
+{
+ return div64_u64(c->gc_stats.key_bytes * 100,
+ (c->gc_stats.nodes ?: 1) * btree_bytes(c));
+}
+static unsigned bch_average_key_size(struct cache_set *c)
+{
+ return c->gc_stats.nkeys
+ ? div64_u64(c->gc_stats.data, c->gc_stats.nkeys)
+ : 0;
+}
+
+SHOW(__bch_cache_set)
+{
struct cache_set *c = container_of(kobj, struct cache_set, kobj);
sysfs_print(synchronous, CACHE_SYNC(&c->sb));
@@ -524,21 +523,20 @@ lock_root:
sysfs_hprint(bucket_size, bucket_bytes(c));
sysfs_hprint(block_size, block_bytes(c));
sysfs_print(tree_depth, c->root->level);
- sysfs_print(root_usage_percent, root_usage(c));
+ sysfs_print(root_usage_percent, bch_root_usage(c));
- sysfs_hprint(btree_cache_size, cache_size(c));
- sysfs_print(btree_cache_max_chain, cache_max_chain(c));
+ sysfs_hprint(btree_cache_size, bch_cache_size(c));
+ sysfs_print(btree_cache_max_chain, bch_cache_max_chain(c));
sysfs_print(cache_available_percent, 100 - c->gc_stats.in_use);
sysfs_print_time_stats(&c->btree_gc_time, btree_gc, sec, ms);
sysfs_print_time_stats(&c->btree_split_time, btree_split, sec, us);
sysfs_print_time_stats(&c->sort.time, btree_sort, ms, us);
sysfs_print_time_stats(&c->btree_read_time, btree_read, ms, us);
- sysfs_print_time_stats(&c->try_harder_time, try_harder, ms, us);
- sysfs_print(btree_used_percent, btree_used(c));
+ sysfs_print(btree_used_percent, bch_btree_used(c));
sysfs_print(btree_nodes, c->gc_stats.nodes);
- sysfs_hprint(average_key_size, average_key_size(c));
+ sysfs_hprint(average_key_size, bch_average_key_size(c));
sysfs_print(cache_read_races,
atomic_long_read(&c->cache_read_races));
@@ -709,7 +707,6 @@ static struct attribute *bch_cache_set_internal_files[] = {
sysfs_time_stats_attribute_list(btree_split, sec, us)
sysfs_time_stats_attribute_list(btree_sort, ms, us)
sysfs_time_stats_attribute_list(btree_read, ms, us)
- sysfs_time_stats_attribute_list(try_harder, ms, us)
&sysfs_btree_nodes,
&sysfs_btree_used_percent,
@@ -761,7 +758,9 @@ SHOW(__bch_cache)
int cmp(const void *l, const void *r)
{ return *((uint16_t *) r) - *((uint16_t *) l); }
- size_t n = ca->sb.nbuckets, i, unused, btree;
+ struct bucket *b;
+ size_t n = ca->sb.nbuckets, i;
+ size_t unused = 0, available = 0, dirty = 0, meta = 0;
uint64_t sum = 0;
/* Compute 31 quantiles */
uint16_t q[31], *p, *cached;
@@ -772,6 +771,17 @@ SHOW(__bch_cache)
return -ENOMEM;
mutex_lock(&ca->set->bucket_lock);
+ for_each_bucket(b, ca) {
+ if (!GC_SECTORS_USED(b))
+ unused++;
+ if (GC_MARK(b) == GC_MARK_RECLAIMABLE)
+ available++;
+ if (GC_MARK(b) == GC_MARK_DIRTY)
+ dirty++;
+ if (GC_MARK(b) == GC_MARK_METADATA)
+ meta++;
+ }
+
for (i = ca->sb.first_bucket; i < n; i++)
p[i] = ca->buckets[i].prio;
mutex_unlock(&ca->set->bucket_lock);
@@ -786,10 +796,7 @@ SHOW(__bch_cache)
while (cached < p + n &&
*cached == BTREE_PRIO)
- cached++;
-
- btree = cached - p;
- n -= btree;
+ cached++, n--;
for (i = 0; i < n; i++)
sum += INITIAL_PRIO - cached[i];
@@ -805,12 +812,16 @@ SHOW(__bch_cache)
ret = scnprintf(buf, PAGE_SIZE,
"Unused: %zu%%\n"
+ "Clean: %zu%%\n"
+ "Dirty: %zu%%\n"
"Metadata: %zu%%\n"
"Average: %llu\n"
"Sectors per Q: %zu\n"
"Quantiles: [",
unused * 100 / (size_t) ca->sb.nbuckets,
- btree * 100 / (size_t) ca->sb.nbuckets, sum,
+ available * 100 / (size_t) ca->sb.nbuckets,
+ dirty * 100 / (size_t) ca->sb.nbuckets,
+ meta * 100 / (size_t) ca->sb.nbuckets, sum,
n * ca->sb.bucket_size / (ARRAY_SIZE(q) + 1));
for (i = 0; i < ARRAY_SIZE(q); i++)
diff --git a/drivers/md/bcache/trace.c b/drivers/md/bcache/trace.c
index adbc3df17a80..b7820b0d2621 100644
--- a/drivers/md/bcache/trace.c
+++ b/drivers/md/bcache/trace.c
@@ -45,7 +45,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_node_split);
EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_node_compact);
EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_set_root);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_alloc_invalidate);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_invalidate);
EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_alloc_fail);
EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_writeback);
diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c
index 1e018e986610..0e385e40909e 100644
--- a/drivers/md/dm-cache-policy-mq.c
+++ b/drivers/md/dm-cache-policy-mq.c
@@ -872,7 +872,7 @@ static void mq_destroy(struct dm_cache_policy *p)
{
struct mq_policy *mq = to_mq_policy(p);
- kfree(mq->table);
+ vfree(mq->table);
epool_exit(&mq->cache_pool);
epool_exit(&mq->pre_cache_pool);
kfree(mq);
@@ -1245,7 +1245,7 @@ static struct dm_cache_policy *mq_create(dm_cblock_t cache_size,
mq->nr_buckets = next_power(from_cblock(cache_size) / 2, 16);
mq->hash_bits = ffs(mq->nr_buckets) - 1;
- mq->table = kzalloc(sizeof(*mq->table) * mq->nr_buckets, GFP_KERNEL);
+ mq->table = vzalloc(sizeof(*mq->table) * mq->nr_buckets);
if (!mq->table)
goto bad_alloc_table;
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index ffd472e015ca..074b9c8e4cf0 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -289,6 +289,7 @@ struct per_bio_data {
bool tick:1;
unsigned req_nr:2;
struct dm_deferred_entry *all_io_entry;
+ struct dm_hook_info hook_info;
/*
* writethrough fields. These MUST remain at the end of this
@@ -297,7 +298,6 @@ struct per_bio_data {
*/
struct cache *cache;
dm_cblock_t cblock;
- struct dm_hook_info hook_info;
struct dm_bio_details bio_details;
};
@@ -671,15 +671,16 @@ static void remap_to_cache(struct cache *cache, struct bio *bio,
dm_cblock_t cblock)
{
sector_t bi_sector = bio->bi_iter.bi_sector;
+ sector_t block = from_cblock(cblock);
bio->bi_bdev = cache->cache_dev->bdev;
if (!block_size_is_power_of_two(cache))
bio->bi_iter.bi_sector =
- (from_cblock(cblock) * cache->sectors_per_block) +
+ (block * cache->sectors_per_block) +
sector_div(bi_sector, cache->sectors_per_block);
else
bio->bi_iter.bi_sector =
- (from_cblock(cblock) << cache->sectors_per_block_shift) |
+ (block << cache->sectors_per_block_shift) |
(bi_sector & (cache->sectors_per_block - 1));
}
@@ -978,12 +979,13 @@ static void issue_copy_real(struct dm_cache_migration *mg)
int r;
struct dm_io_region o_region, c_region;
struct cache *cache = mg->cache;
+ sector_t cblock = from_cblock(mg->cblock);
o_region.bdev = cache->origin_dev->bdev;
o_region.count = cache->sectors_per_block;
c_region.bdev = cache->cache_dev->bdev;
- c_region.sector = from_cblock(mg->cblock) * cache->sectors_per_block;
+ c_region.sector = cblock * cache->sectors_per_block;
c_region.count = cache->sectors_per_block;
if (mg->writeback || mg->demote) {
@@ -1010,13 +1012,15 @@ static void overwrite_endio(struct bio *bio, int err)
struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
unsigned long flags;
+ dm_unhook_bio(&pb->hook_info, bio);
+
if (err)
mg->err = true;
+ mg->requeue_holder = false;
+
spin_lock_irqsave(&cache->lock, flags);
list_add_tail(&mg->list, &cache->completed_migrations);
- dm_unhook_bio(&pb->hook_info, bio);
- mg->requeue_holder = false;
spin_unlock_irqrestore(&cache->lock, flags);
wake_worker(cache);
@@ -2461,20 +2465,18 @@ static int cache_map(struct dm_target *ti, struct bio *bio)
bool discarded_block;
struct dm_bio_prison_cell *cell;
struct policy_result lookup_result;
- struct per_bio_data *pb;
+ struct per_bio_data *pb = init_per_bio_data(bio, pb_data_size);
- if (from_oblock(block) > from_oblock(cache->origin_blocks)) {
+ if (unlikely(from_oblock(block) >= from_oblock(cache->origin_blocks))) {
/*
* This can only occur if the io goes to a partial block at
* the end of the origin device. We don't cache these.
* Just remap to the origin and carry on.
*/
- remap_to_origin_clear_discard(cache, bio, block);
+ remap_to_origin(cache, bio);
return DM_MAPIO_REMAPPED;
}
- pb = init_per_bio_data(bio, pb_data_size);
-
if (bio->bi_rw & (REQ_FLUSH | REQ_FUA | REQ_DISCARD)) {
defer_bio(cache, bio);
return DM_MAPIO_SUBMITTED;
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index b2b8a10e8427..3842ac738f98 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -201,29 +201,28 @@ static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned offse
/*
* Functions for getting the pages from a bvec.
*/
-static void bio_get_page(struct dpages *dp,
- struct page **p, unsigned long *len, unsigned *offset)
+static void bio_get_page(struct dpages *dp, struct page **p,
+ unsigned long *len, unsigned *offset)
{
- struct bio *bio = dp->context_ptr;
- struct bio_vec bvec = bio_iovec(bio);
- *p = bvec.bv_page;
- *len = bvec.bv_len;
- *offset = bvec.bv_offset;
+ struct bio_vec *bvec = dp->context_ptr;
+ *p = bvec->bv_page;
+ *len = bvec->bv_len - dp->context_u;
+ *offset = bvec->bv_offset + dp->context_u;
}
static void bio_next_page(struct dpages *dp)
{
- struct bio *bio = dp->context_ptr;
- struct bio_vec bvec = bio_iovec(bio);
-
- bio_advance(bio, bvec.bv_len);
+ struct bio_vec *bvec = dp->context_ptr;
+ dp->context_ptr = bvec + 1;
+ dp->context_u = 0;
}
static void bio_dp_init(struct dpages *dp, struct bio *bio)
{
dp->get_page = bio_get_page;
dp->next_page = bio_next_page;
- dp->context_ptr = bio;
+ dp->context_ptr = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
+ dp->context_u = bio->bi_iter.bi_bvec_done;
}
/*
diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c
index 08d9a207259a..b428c0ae63d5 100644
--- a/drivers/md/dm-log-userspace-transfer.c
+++ b/drivers/md/dm-log-userspace-transfer.c
@@ -66,7 +66,7 @@ static int dm_ulog_sendto_server(struct dm_ulog_request *tfr)
msg->seq = tfr->seq;
msg->len = sizeof(struct dm_ulog_request) + tfr->data_size;
- r = cn_netlink_send(msg, 0, gfp_any());
+ r = cn_netlink_send(msg, 0, 0, gfp_any());
return r;
}
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 6eb9dc9ef8f3..422a9fdeb53e 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1626,8 +1626,11 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
/*
* Only pass ioctls through if the device sizes match exactly.
*/
- if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
- r = scsi_verify_blk_ioctl(NULL, cmd);
+ if (!bdev || ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) {
+ int err = scsi_verify_blk_ioctl(NULL, cmd);
+ if (err)
+ r = err;
+ }
if (r == -ENOTCONN && !fatal_signal_pending(current))
queue_work(kmultipathd, &m->process_queued_ios);
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index f284e0bfb25f..7dfdb5c746d6 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -1244,6 +1244,9 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
dm_bio_restore(bd, bio);
bio_record->details.bi_bdev = NULL;
+
+ atomic_inc(&bio->bi_remaining);
+
queue_bio(ms, bio, rw);
return DM_ENDIO_INCOMPLETE;
}
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index afc3d017de4c..d6e88178d22c 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -546,6 +546,9 @@ static int read_exceptions(struct pstore *ps,
r = insert_exceptions(ps, area, callback, callback_context,
&full);
+ if (!full)
+ memcpy(ps->area, area, ps->store->chunk_size << SECTOR_SHIFT);
+
dm_bufio_release(bp);
dm_bufio_forget(client, chunk);
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 7da347665552..fb9efc829182 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -76,7 +76,7 @@
#define THIN_SUPERBLOCK_MAGIC 27022010
#define THIN_SUPERBLOCK_LOCATION 0
-#define THIN_VERSION 1
+#define THIN_VERSION 2
#define THIN_METADATA_CACHE_SIZE 64
#define SECTOR_TO_BLOCK_SHIFT 3
@@ -483,7 +483,7 @@ static int __write_initial_superblock(struct dm_pool_metadata *pmd)
disk_super->data_mapping_root = cpu_to_le64(pmd->root);
disk_super->device_details_root = cpu_to_le64(pmd->details_root);
- disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT);
+ disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE);
disk_super->metadata_nr_blocks = cpu_to_le64(bdev_size >> SECTOR_TO_BLOCK_SHIFT);
disk_super->data_block_size = cpu_to_le32(pmd->data_block_size);
@@ -651,7 +651,7 @@ static int __create_persistent_data_objects(struct dm_pool_metadata *pmd, bool f
{
int r;
- pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE,
+ pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
THIN_METADATA_CACHE_SIZE,
THIN_MAX_CONCURRENT_LOCKS);
if (IS_ERR(pmd->bm)) {
@@ -1489,6 +1489,23 @@ bool dm_thin_changed_this_transaction(struct dm_thin_device *td)
return r;
}
+bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd)
+{
+ bool r = false;
+ struct dm_thin_device *td, *tmp;
+
+ down_read(&pmd->root_lock);
+ list_for_each_entry_safe(td, tmp, &pmd->thin_devices, list) {
+ if (td->changed) {
+ r = td->changed;
+ break;
+ }
+ }
+ up_read(&pmd->root_lock);
+
+ return r;
+}
+
bool dm_thin_aborted_changes(struct dm_thin_device *td)
{
bool r;
@@ -1738,3 +1755,38 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
return r;
}
+
+int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd)
+{
+ int r;
+ struct dm_block *sblock;
+ struct thin_disk_superblock *disk_super;
+
+ down_write(&pmd->root_lock);
+ pmd->flags |= THIN_METADATA_NEEDS_CHECK_FLAG;
+
+ r = superblock_lock(pmd, &sblock);
+ if (r) {
+ DMERR("couldn't read superblock");
+ goto out;
+ }
+
+ disk_super = dm_block_data(sblock);
+ disk_super->flags = cpu_to_le32(pmd->flags);
+
+ dm_bm_unlock(sblock);
+out:
+ up_write(&pmd->root_lock);
+ return r;
+}
+
+bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd)
+{
+ bool needs_check;
+
+ down_read(&pmd->root_lock);
+ needs_check = pmd->flags & THIN_METADATA_NEEDS_CHECK_FLAG;
+ up_read(&pmd->root_lock);
+
+ return needs_check;
+}
diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h
index 9a368567632f..e3c857db195a 100644
--- a/drivers/md/dm-thin-metadata.h
+++ b/drivers/md/dm-thin-metadata.h
@@ -9,16 +9,14 @@
#include "persistent-data/dm-block-manager.h"
#include "persistent-data/dm-space-map.h"
+#include "persistent-data/dm-space-map-metadata.h"
-#define THIN_METADATA_BLOCK_SIZE 4096
+#define THIN_METADATA_BLOCK_SIZE DM_SM_METADATA_BLOCK_SIZE
/*
* The metadata device is currently limited in size.
- *
- * We have one block of index, which can hold 255 index entries. Each
- * index entry contains allocation info about 16k metadata blocks.
*/
-#define THIN_METADATA_MAX_SECTORS (255 * (1 << 14) * (THIN_METADATA_BLOCK_SIZE / (1 << SECTOR_SHIFT)))
+#define THIN_METADATA_MAX_SECTORS DM_SM_METADATA_MAX_SECTORS
/*
* A metadata device larger than 16GB triggers a warning.
@@ -27,6 +25,11 @@
/*----------------------------------------------------------------*/
+/*
+ * Thin metadata superblock flags.
+ */
+#define THIN_METADATA_NEEDS_CHECK_FLAG (1 << 0)
+
struct dm_pool_metadata;
struct dm_thin_device;
@@ -161,6 +164,8 @@ int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block);
*/
bool dm_thin_changed_this_transaction(struct dm_thin_device *td);
+bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd);
+
bool dm_thin_aborted_changes(struct dm_thin_device *td);
int dm_thin_get_highest_mapped_block(struct dm_thin_device *td,
@@ -202,6 +207,12 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
dm_sm_threshold_fn fn,
void *context);
+/*
+ * Updates the superblock immediately.
+ */
+int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd);
+bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd);
+
/*----------------------------------------------------------------*/
#endif
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index faaf944597ab..be70d38745f7 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -130,10 +130,11 @@ static void build_virtual_key(struct dm_thin_device *td, dm_block_t b,
struct dm_thin_new_mapping;
/*
- * The pool runs in 3 modes. Ordered in degraded order for comparisons.
+ * The pool runs in 4 modes. Ordered in degraded order for comparisons.
*/
enum pool_mode {
PM_WRITE, /* metadata may be changed */
+ PM_OUT_OF_DATA_SPACE, /* metadata may be changed, though data may not be allocated */
PM_READ_ONLY, /* metadata may not be changed */
PM_FAIL, /* all I/O fails */
};
@@ -198,7 +199,6 @@ struct pool {
};
static enum pool_mode get_pool_mode(struct pool *pool);
-static void out_of_data_space(struct pool *pool);
static void metadata_operation_failed(struct pool *pool, const char *op, int r);
/*
@@ -226,6 +226,7 @@ struct thin_c {
struct pool *pool;
struct dm_thin_device *td;
+ bool requeue_mode:1;
};
/*----------------------------------------------------------------*/
@@ -369,14 +370,18 @@ struct dm_thin_endio_hook {
struct dm_thin_new_mapping *overwrite_mapping;
};
-static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
+static void requeue_bio_list(struct thin_c *tc, struct bio_list *master)
{
struct bio *bio;
struct bio_list bios;
+ unsigned long flags;
bio_list_init(&bios);
+
+ spin_lock_irqsave(&tc->pool->lock, flags);
bio_list_merge(&bios, master);
bio_list_init(master);
+ spin_unlock_irqrestore(&tc->pool->lock, flags);
while ((bio = bio_list_pop(&bios))) {
struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
@@ -391,12 +396,26 @@ static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
static void requeue_io(struct thin_c *tc)
{
struct pool *pool = tc->pool;
+
+ requeue_bio_list(tc, &pool->deferred_bios);
+ requeue_bio_list(tc, &pool->retry_on_resume_list);
+}
+
+static void error_retry_list(struct pool *pool)
+{
+ struct bio *bio;
unsigned long flags;
+ struct bio_list bios;
+
+ bio_list_init(&bios);
spin_lock_irqsave(&pool->lock, flags);
- __requeue_bio_list(tc, &pool->deferred_bios);
- __requeue_bio_list(tc, &pool->retry_on_resume_list);
+ bio_list_merge(&bios, &pool->retry_on_resume_list);
+ bio_list_init(&pool->retry_on_resume_list);
spin_unlock_irqrestore(&pool->lock, flags);
+
+ while ((bio = bio_list_pop(&bios)))
+ bio_io_error(bio);
}
/*
@@ -925,13 +944,15 @@ static void check_low_water_mark(struct pool *pool, dm_block_t free_blocks)
}
}
+static void set_pool_mode(struct pool *pool, enum pool_mode new_mode);
+
static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
{
int r;
dm_block_t free_blocks;
struct pool *pool = tc->pool;
- if (get_pool_mode(pool) != PM_WRITE)
+ if (WARN_ON(get_pool_mode(pool) != PM_WRITE))
return -EINVAL;
r = dm_pool_get_free_block_count(pool->pmd, &free_blocks);
@@ -958,7 +979,7 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
}
if (!free_blocks) {
- out_of_data_space(pool);
+ set_pool_mode(pool, PM_OUT_OF_DATA_SPACE);
return -ENOSPC;
}
}
@@ -988,15 +1009,32 @@ static void retry_on_resume(struct bio *bio)
spin_unlock_irqrestore(&pool->lock, flags);
}
-static void handle_unserviceable_bio(struct pool *pool, struct bio *bio)
+static bool should_error_unserviceable_bio(struct pool *pool)
{
- /*
- * When pool is read-only, no cell locking is needed because
- * nothing is changing.
- */
- WARN_ON_ONCE(get_pool_mode(pool) != PM_READ_ONLY);
+ enum pool_mode m = get_pool_mode(pool);
- if (pool->pf.error_if_no_space)
+ switch (m) {
+ case PM_WRITE:
+ /* Shouldn't get here */
+ DMERR_LIMIT("bio unserviceable, yet pool is in PM_WRITE mode");
+ return true;
+
+ case PM_OUT_OF_DATA_SPACE:
+ return pool->pf.error_if_no_space;
+
+ case PM_READ_ONLY:
+ case PM_FAIL:
+ return true;
+ default:
+ /* Shouldn't get here */
+ DMERR_LIMIT("bio unserviceable, yet pool has an unknown mode");
+ return true;
+ }
+}
+
+static void handle_unserviceable_bio(struct pool *pool, struct bio *bio)
+{
+ if (should_error_unserviceable_bio(pool))
bio_io_error(bio);
else
retry_on_resume(bio);
@@ -1007,11 +1045,20 @@ static void retry_bios_on_resume(struct pool *pool, struct dm_bio_prison_cell *c
struct bio *bio;
struct bio_list bios;
+ if (should_error_unserviceable_bio(pool)) {
+ cell_error(pool, cell);
+ return;
+ }
+
bio_list_init(&bios);
cell_release(pool, cell, &bios);
- while ((bio = bio_list_pop(&bios)))
- handle_unserviceable_bio(pool, bio);
+ if (should_error_unserviceable_bio(pool))
+ while ((bio = bio_list_pop(&bios)))
+ bio_io_error(bio);
+ else
+ while ((bio = bio_list_pop(&bios)))
+ retry_on_resume(bio);
}
static void process_discard(struct thin_c *tc, struct bio *bio)
@@ -1296,6 +1343,11 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
}
}
+static void process_bio_success(struct thin_c *tc, struct bio *bio)
+{
+ bio_endio(bio, 0);
+}
+
static void process_bio_fail(struct thin_c *tc, struct bio *bio)
{
bio_io_error(bio);
@@ -1328,6 +1380,11 @@ static void process_deferred_bios(struct pool *pool)
struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
struct thin_c *tc = h->tc;
+ if (tc->requeue_mode) {
+ bio_endio(bio, DM_ENDIO_REQUEUE);
+ continue;
+ }
+
/*
* If we've got no free new_mapping structs, and processing
* this bio might require one, we pause until there are some
@@ -1357,7 +1414,8 @@ static void process_deferred_bios(struct pool *pool)
bio_list_init(&pool->deferred_flush_bios);
spin_unlock_irqrestore(&pool->lock, flags);
- if (bio_list_empty(&bios) && !need_commit_due_to_time(pool))
+ if (bio_list_empty(&bios) &&
+ !(dm_pool_changed_this_transaction(pool->pmd) && need_commit_due_to_time(pool)))
return;
if (commit(pool)) {
@@ -1393,51 +1451,134 @@ static void do_waker(struct work_struct *ws)
/*----------------------------------------------------------------*/
+struct noflush_work {
+ struct work_struct worker;
+ struct thin_c *tc;
+
+ atomic_t complete;
+ wait_queue_head_t wait;
+};
+
+static void complete_noflush_work(struct noflush_work *w)
+{
+ atomic_set(&w->complete, 1);
+ wake_up(&w->wait);
+}
+
+static void do_noflush_start(struct work_struct *ws)
+{
+ struct noflush_work *w = container_of(ws, struct noflush_work, worker);
+ w->tc->requeue_mode = true;
+ requeue_io(w->tc);
+ complete_noflush_work(w);
+}
+
+static void do_noflush_stop(struct work_struct *ws)
+{
+ struct noflush_work *w = container_of(ws, struct noflush_work, worker);
+ w->tc->requeue_mode = false;
+ complete_noflush_work(w);
+}
+
+static void noflush_work(struct thin_c *tc, void (*fn)(struct work_struct *))
+{
+ struct noflush_work w;
+
+ INIT_WORK(&w.worker, fn);
+ w.tc = tc;
+ atomic_set(&w.complete, 0);
+ init_waitqueue_head(&w.wait);
+
+ queue_work(tc->pool->wq, &w.worker);
+
+ wait_event(w.wait, atomic_read(&w.complete));
+}
+
+/*----------------------------------------------------------------*/
+
static enum pool_mode get_pool_mode(struct pool *pool)
{
return pool->pf.mode;
}
+static void notify_of_pool_mode_change(struct pool *pool, const char *new_mode)
+{
+ dm_table_event(pool->ti->table);
+ DMINFO("%s: switching pool to %s mode",
+ dm_device_name(pool->pool_md), new_mode);
+}
+
static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
{
- int r;
- enum pool_mode old_mode = pool->pf.mode;
+ struct pool_c *pt = pool->ti->private;
+ bool needs_check = dm_pool_metadata_needs_check(pool->pmd);
+ enum pool_mode old_mode = get_pool_mode(pool);
+
+ /*
+ * Never allow the pool to transition to PM_WRITE mode if user
+ * intervention is required to verify metadata and data consistency.
+ */
+ if (new_mode == PM_WRITE && needs_check) {
+ DMERR("%s: unable to switch pool to write mode until repaired.",
+ dm_device_name(pool->pool_md));
+ if (old_mode != new_mode)
+ new_mode = old_mode;
+ else
+ new_mode = PM_READ_ONLY;
+ }
+ /*
+ * If we were in PM_FAIL mode, rollback of metadata failed. We're
+ * not going to recover without a thin_repair. So we never let the
+ * pool move out of the old mode.
+ */
+ if (old_mode == PM_FAIL)
+ new_mode = old_mode;
switch (new_mode) {
case PM_FAIL:
if (old_mode != new_mode)
- DMERR("%s: switching pool to failure mode",
- dm_device_name(pool->pool_md));
+ notify_of_pool_mode_change(pool, "failure");
dm_pool_metadata_read_only(pool->pmd);
pool->process_bio = process_bio_fail;
pool->process_discard = process_bio_fail;
pool->process_prepared_mapping = process_prepared_mapping_fail;
pool->process_prepared_discard = process_prepared_discard_fail;
+
+ error_retry_list(pool);
break;
case PM_READ_ONLY:
if (old_mode != new_mode)
- DMERR("%s: switching pool to read-only mode",
- dm_device_name(pool->pool_md));
- r = dm_pool_abort_metadata(pool->pmd);
- if (r) {
- DMERR("%s: aborting transaction failed",
- dm_device_name(pool->pool_md));
- new_mode = PM_FAIL;
- set_pool_mode(pool, new_mode);
- } else {
- dm_pool_metadata_read_only(pool->pmd);
- pool->process_bio = process_bio_read_only;
- pool->process_discard = process_discard;
- pool->process_prepared_mapping = process_prepared_mapping_fail;
- pool->process_prepared_discard = process_prepared_discard_passdown;
- }
+ notify_of_pool_mode_change(pool, "read-only");
+ dm_pool_metadata_read_only(pool->pmd);
+ pool->process_bio = process_bio_read_only;
+ pool->process_discard = process_bio_success;
+ pool->process_prepared_mapping = process_prepared_mapping_fail;
+ pool->process_prepared_discard = process_prepared_discard_passdown;
+
+ error_retry_list(pool);
+ break;
+
+ case PM_OUT_OF_DATA_SPACE:
+ /*
+ * Ideally we'd never hit this state; the low water mark
+ * would trigger userland to extend the pool before we
+ * completely run out of data space. However, many small
+ * IOs to unprovisioned space can consume data space at an
+ * alarming rate. Adjust your low water mark if you're
+ * frequently seeing this mode.
+ */
+ if (old_mode != new_mode)
+ notify_of_pool_mode_change(pool, "out-of-data-space");
+ pool->process_bio = process_bio_read_only;
+ pool->process_discard = process_discard;
+ pool->process_prepared_mapping = process_prepared_mapping;
+ pool->process_prepared_discard = process_prepared_discard_passdown;
break;
case PM_WRITE:
if (old_mode != new_mode)
- DMINFO("%s: switching pool to write mode",
- dm_device_name(pool->pool_md));
+ notify_of_pool_mode_change(pool, "write");
dm_pool_metadata_read_write(pool->pmd);
pool->process_bio = process_bio;
pool->process_discard = process_discard;
@@ -1447,32 +1588,35 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
}
pool->pf.mode = new_mode;
+ /*
+ * The pool mode may have changed, sync it so bind_control_target()
+ * doesn't cause an unexpected mode transition on resume.
+ */
+ pt->adjusted_pf.mode = new_mode;
}
-/*
- * Rather than calling set_pool_mode directly, use these which describe the
- * reason for mode degradation.
- */
-static void out_of_data_space(struct pool *pool)
+static void abort_transaction(struct pool *pool)
{
- DMERR_LIMIT("%s: no free data space available.",
- dm_device_name(pool->pool_md));
- set_pool_mode(pool, PM_READ_ONLY);
+ const char *dev_name = dm_device_name(pool->pool_md);
+
+ DMERR_LIMIT("%s: aborting current metadata transaction", dev_name);
+ if (dm_pool_abort_metadata(pool->pmd)) {
+ DMERR("%s: failed to abort metadata transaction", dev_name);
+ set_pool_mode(pool, PM_FAIL);
+ }
+
+ if (dm_pool_metadata_set_needs_check(pool->pmd)) {
+ DMERR("%s: failed to set 'needs_check' flag in metadata", dev_name);
+ set_pool_mode(pool, PM_FAIL);
+ }
}
static void metadata_operation_failed(struct pool *pool, const char *op, int r)
{
- dm_block_t free_blocks;
-
DMERR_LIMIT("%s: metadata operation '%s' failed: error = %d",
dm_device_name(pool->pool_md), op, r);
- if (r == -ENOSPC &&
- !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) &&
- !free_blocks)
- DMERR_LIMIT("%s: no free metadata space available.",
- dm_device_name(pool->pool_md));
-
+ abort_transaction(pool);
set_pool_mode(pool, PM_READ_ONLY);
}
@@ -1523,6 +1667,11 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
thin_hook_bio(tc, bio);
+ if (tc->requeue_mode) {
+ bio_endio(bio, DM_ENDIO_REQUEUE);
+ return DM_MAPIO_SUBMITTED;
+ }
+
if (get_pool_mode(tc->pool) == PM_FAIL) {
bio_io_error(bio);
return DM_MAPIO_SUBMITTED;
@@ -1686,7 +1835,7 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
/*
* We want to make sure that a pool in PM_FAIL mode is never upgraded.
*/
- enum pool_mode old_mode = pool->pf.mode;
+ enum pool_mode old_mode = get_pool_mode(pool);
enum pool_mode new_mode = pt->adjusted_pf.mode;
/*
@@ -1700,16 +1849,6 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
pool->pf = pt->adjusted_pf;
pool->low_water_blocks = pt->low_water_blocks;
- /*
- * If we were in PM_FAIL mode, rollback of metadata failed. We're
- * not going to recover without a thin_repair. So we never let the
- * pool move out of the old mode. On the other hand a PM_READ_ONLY
- * may have been due to a lack of metadata or data space, and may
- * now work (ie. if the underlying devices have been resized).
- */
- if (old_mode == PM_FAIL)
- new_mode = old_mode;
-
set_pool_mode(pool, new_mode);
return 0;
@@ -1999,16 +2138,27 @@ static void metadata_low_callback(void *context)
dm_table_event(pool->ti->table);
}
-static sector_t get_metadata_dev_size(struct block_device *bdev)
+static sector_t get_dev_size(struct block_device *bdev)
+{
+ return i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
+}
+
+static void warn_if_metadata_device_too_big(struct block_device *bdev)
{
- sector_t metadata_dev_size = i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
+ sector_t metadata_dev_size = get_dev_size(bdev);
char buffer[BDEVNAME_SIZE];
- if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING) {
+ if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING)
DMWARN("Metadata device %s is larger than %u sectors: excess space will not be used.",
bdevname(bdev, buffer), THIN_METADATA_MAX_SECTORS);
- metadata_dev_size = THIN_METADATA_MAX_SECTORS_WARNING;
- }
+}
+
+static sector_t get_metadata_dev_size(struct block_device *bdev)
+{
+ sector_t metadata_dev_size = get_dev_size(bdev);
+
+ if (metadata_dev_size > THIN_METADATA_MAX_SECTORS)
+ metadata_dev_size = THIN_METADATA_MAX_SECTORS;
return metadata_dev_size;
}
@@ -2017,7 +2167,7 @@ static dm_block_t get_metadata_dev_size_in_blocks(struct block_device *bdev)
{
sector_t metadata_dev_size = get_metadata_dev_size(bdev);
- sector_div(metadata_dev_size, THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT);
+ sector_div(metadata_dev_size, THIN_METADATA_BLOCK_SIZE);
return metadata_dev_size;
}
@@ -2095,12 +2245,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
ti->error = "Error opening metadata block device";
goto out_unlock;
}
-
- /*
- * Run for the side-effect of possibly issuing a warning if the
- * device is too big.
- */
- (void) get_metadata_dev_size(metadata_dev->bdev);
+ warn_if_metadata_device_too_big(metadata_dev->bdev);
r = dm_get_device(ti, argv[1], FMODE_READ | FMODE_WRITE, &data_dev);
if (r) {
@@ -2246,6 +2391,12 @@ static int maybe_resize_data_dev(struct dm_target *ti, bool *need_commit)
return -EINVAL;
} else if (data_size > sb_data_size) {
+ if (dm_pool_metadata_needs_check(pool->pmd)) {
+ DMERR("%s: unable to grow the data device until repaired.",
+ dm_device_name(pool->pool_md));
+ return 0;
+ }
+
if (sb_data_size)
DMINFO("%s: growing the data device from %llu to %llu blocks",
dm_device_name(pool->pool_md),
@@ -2287,6 +2438,13 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit)
return -EINVAL;
} else if (metadata_dev_size > sb_metadata_dev_size) {
+ if (dm_pool_metadata_needs_check(pool->pmd)) {
+ DMERR("%s: unable to grow the metadata device until repaired.",
+ dm_device_name(pool->pool_md));
+ return 0;
+ }
+
+ warn_if_metadata_device_too_big(pool->md_dev);
DMINFO("%s: growing the metadata device from %llu to %llu blocks",
dm_device_name(pool->pool_md),
sb_metadata_dev_size, metadata_dev_size);
@@ -2673,7 +2831,9 @@ static void pool_status(struct dm_target *ti, status_type_t type,
else
DMEMIT("- ");
- if (pool->pf.mode == PM_READ_ONLY)
+ if (pool->pf.mode == PM_OUT_OF_DATA_SPACE)
+ DMEMIT("out_of_data_space ");
+ else if (pool->pf.mode == PM_READ_ONLY)
DMEMIT("ro ");
else
DMEMIT("rw ");
@@ -2787,7 +2947,7 @@ static struct target_type pool_target = {
.name = "thin-pool",
.features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
DM_TARGET_IMMUTABLE,
- .version = {1, 10, 0},
+ .version = {1, 11, 0},
.module = THIS_MODULE,
.ctr = pool_ctr,
.dtr = pool_dtr,
@@ -2894,6 +3054,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
if (get_pool_mode(tc->pool) == PM_FAIL) {
ti->error = "Couldn't open thin device, Pool is in fail mode";
+ r = -EINVAL;
goto bad_thin_open;
}
@@ -2905,7 +3066,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
r = dm_set_target_max_io_len(ti, tc->pool->sectors_per_block);
if (r)
- goto bad_thin_open;
+ goto bad_target_max_io_len;
ti->num_flush_bios = 1;
ti->flush_supported = true;
@@ -2926,6 +3087,8 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
return 0;
+bad_target_max_io_len:
+ dm_pool_close_thin_device(tc->td);
bad_thin_open:
__pool_dec(tc->pool);
bad_pool_lookup:
@@ -2986,10 +3149,23 @@ static int thin_endio(struct dm_target *ti, struct bio *bio, int err)
return 0;
}
-static void thin_postsuspend(struct dm_target *ti)
+static void thin_presuspend(struct dm_target *ti)
{
+ struct thin_c *tc = ti->private;
+
if (dm_noflush_suspending(ti))
- requeue_io((struct thin_c *)ti->private);
+ noflush_work(tc, do_noflush_start);
+}
+
+static void thin_postsuspend(struct dm_target *ti)
+{
+ struct thin_c *tc = ti->private;
+
+ /*
+ * The dm_noflush_suspending flag has been cleared by now, so
+ * unfortunately we must always run this.
+ */
+ noflush_work(tc, do_noflush_stop);
}
/*
@@ -3074,12 +3250,13 @@ static int thin_iterate_devices(struct dm_target *ti,
static struct target_type thin_target = {
.name = "thin",
- .version = {1, 10, 0},
+ .version = {1, 11, 0},
.module = THIS_MODULE,
.ctr = thin_ctr,
.dtr = thin_dtr,
.map = thin_map,
.end_io = thin_endio,
+ .presuspend = thin_presuspend,
.postsuspend = thin_postsuspend,
.status = thin_status,
.iterate_devices = thin_iterate_devices,
diff --git a/drivers/md/persistent-data/Kconfig b/drivers/md/persistent-data/Kconfig
index 19b268795415..0c2dec7aec20 100644
--- a/drivers/md/persistent-data/Kconfig
+++ b/drivers/md/persistent-data/Kconfig
@@ -6,3 +6,13 @@ config DM_PERSISTENT_DATA
---help---
Library providing immutable on-disk data structure support for
device-mapper targets such as the thin provisioning target.
+
+config DM_DEBUG_BLOCK_STACK_TRACING
+ boolean "Keep stack trace of persistent data block lock holders"
+ depends on STACKTRACE_SUPPORT && DM_PERSISTENT_DATA
+ select STACKTRACE
+ ---help---
+ Enable this for messages that may help debug problems with the
+ block manager locking used by thin provisioning and caching.
+
+ If unsure, say N.
diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c
index 536782e3bcb7..786b689bdfc7 100644
--- a/drivers/md/persistent-data/dm-space-map-metadata.c
+++ b/drivers/md/persistent-data/dm-space-map-metadata.c
@@ -91,6 +91,69 @@ struct block_op {
dm_block_t block;
};
+struct bop_ring_buffer {
+ unsigned begin;
+ unsigned end;
+ struct block_op bops[MAX_RECURSIVE_ALLOCATIONS + 1];
+};
+
+static void brb_init(struct bop_ring_buffer *brb)
+{
+ brb->begin = 0;
+ brb->end = 0;
+}
+
+static bool brb_empty(struct bop_ring_buffer *brb)
+{
+ return brb->begin == brb->end;
+}
+
+static unsigned brb_next(struct bop_ring_buffer *brb, unsigned old)
+{
+ unsigned r = old + 1;
+ return (r >= (sizeof(brb->bops) / sizeof(*brb->bops))) ? 0 : r;
+}
+
+static int brb_push(struct bop_ring_buffer *brb,
+ enum block_op_type type, dm_block_t b)
+{
+ struct block_op *bop;
+ unsigned next = brb_next(brb, brb->end);
+
+ /*
+ * We don't allow the last bop to be filled, this way we can
+ * differentiate between full and empty.
+ */
+ if (next == brb->begin)
+ return -ENOMEM;
+
+ bop = brb->bops + brb->end;
+ bop->type = type;
+ bop->block = b;
+
+ brb->end = next;
+
+ return 0;
+}
+
+static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result)
+{
+ struct block_op *bop;
+
+ if (brb_empty(brb))
+ return -ENODATA;
+
+ bop = brb->bops + brb->begin;
+ result->type = bop->type;
+ result->block = bop->block;
+
+ brb->begin = brb_next(brb, brb->begin);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------*/
+
struct sm_metadata {
struct dm_space_map sm;
@@ -101,25 +164,20 @@ struct sm_metadata {
unsigned recursion_count;
unsigned allocated_this_transaction;
- unsigned nr_uncommitted;
- struct block_op uncommitted[MAX_RECURSIVE_ALLOCATIONS];
+ struct bop_ring_buffer uncommitted;
struct threshold threshold;
};
static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t b)
{
- struct block_op *op;
+ int r = brb_push(&smm->uncommitted, type, b);
- if (smm->nr_uncommitted == MAX_RECURSIVE_ALLOCATIONS) {
+ if (r) {
DMERR("too many recursive allocations");
return -ENOMEM;
}
- op = smm->uncommitted + smm->nr_uncommitted++;
- op->type = type;
- op->block = b;
-
return 0;
}
@@ -158,11 +216,17 @@ static int out(struct sm_metadata *smm)
return -ENOMEM;
}
- if (smm->recursion_count == 1 && smm->nr_uncommitted) {
- while (smm->nr_uncommitted && !r) {
- smm->nr_uncommitted--;
- r = commit_bop(smm, smm->uncommitted +
- smm->nr_uncommitted);
+ if (smm->recursion_count == 1) {
+ while (!brb_empty(&smm->uncommitted)) {
+ struct block_op bop;
+
+ r = brb_pop(&smm->uncommitted, &bop);
+ if (r) {
+ DMERR("bug in bop ring buffer");
+ break;
+ }
+
+ r = commit_bop(smm, &bop);
if (r)
break;
}
@@ -217,7 +281,8 @@ static int sm_metadata_get_nr_free(struct dm_space_map *sm, dm_block_t *count)
static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
uint32_t *result)
{
- int r, i;
+ int r;
+ unsigned i;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
unsigned adjustment = 0;
@@ -225,8 +290,10 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
* We may have some uncommitted adjustments to add. This list
* should always be really short.
*/
- for (i = 0; i < smm->nr_uncommitted; i++) {
- struct block_op *op = smm->uncommitted + i;
+ for (i = smm->uncommitted.begin;
+ i != smm->uncommitted.end;
+ i = brb_next(&smm->uncommitted, i)) {
+ struct block_op *op = smm->uncommitted.bops + i;
if (op->block != b)
continue;
@@ -254,7 +321,8 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm,
dm_block_t b, int *result)
{
- int r, i, adjustment = 0;
+ int r, adjustment = 0;
+ unsigned i;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
uint32_t rc;
@@ -262,8 +330,11 @@ static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm,
* We may have some uncommitted adjustments to add. This list
* should always be really short.
*/
- for (i = 0; i < smm->nr_uncommitted; i++) {
- struct block_op *op = smm->uncommitted + i;
+ for (i = smm->uncommitted.begin;
+ i != smm->uncommitted.end;
+ i = brb_next(&smm->uncommitted, i)) {
+
+ struct block_op *op = smm->uncommitted.bops + i;
if (op->block != b)
continue;
@@ -671,7 +742,7 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
smm->begin = superblock + 1;
smm->recursion_count = 0;
smm->allocated_this_transaction = 0;
- smm->nr_uncommitted = 0;
+ brb_init(&smm->uncommitted);
threshold_init(&smm->threshold);
memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm));
@@ -680,6 +751,8 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
if (r)
return r;
+ if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS)
+ nr_blocks = DM_SM_METADATA_MAX_BLOCKS;
r = sm_ll_extend(&smm->ll, nr_blocks);
if (r)
return r;
@@ -713,7 +786,7 @@ int dm_sm_metadata_open(struct dm_space_map *sm,
smm->begin = 0;
smm->recursion_count = 0;
smm->allocated_this_transaction = 0;
- smm->nr_uncommitted = 0;
+ brb_init(&smm->uncommitted);
threshold_init(&smm->threshold);
memcpy(&smm->old_ll, &smm->ll, sizeof(smm->old_ll));
diff --git a/drivers/md/persistent-data/dm-space-map-metadata.h b/drivers/md/persistent-data/dm-space-map-metadata.h
index 39bba0801cf2..64df923974d8 100644
--- a/drivers/md/persistent-data/dm-space-map-metadata.h
+++ b/drivers/md/persistent-data/dm-space-map-metadata.h
@@ -9,6 +9,17 @@
#include "dm-transaction-manager.h"
+#define DM_SM_METADATA_BLOCK_SIZE (4096 >> SECTOR_SHIFT)
+
+/*
+ * The metadata device is currently limited in size.
+ *
+ * We have one block of index, which can hold 255 index entries. Each
+ * index entry contains allocation info about ~16k metadata blocks.
+ */
+#define DM_SM_METADATA_MAX_BLOCKS (255 * ((1 << 14) - 64))
+#define DM_SM_METADATA_MAX_SECTORS (DM_SM_METADATA_MAX_BLOCKS * DM_SM_METADATA_BLOCK_SIZE)
+
/*
* Unfortunately we have to use two-phase construction due to the cycle
* between the tm and sm.
diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c
index d4e15a617c3b..9d38f7b36cd1 100644
--- a/drivers/media/i2c/adv7343.c
+++ b/drivers/media/i2c/adv7343.c
@@ -26,12 +26,12 @@
#include <linux/videodev2.h>
#include <linux/uaccess.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <media/adv7343.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-of.h>
#include "adv7343_regs.h"
@@ -410,7 +410,7 @@ adv7343_get_pdata(struct i2c_client *client)
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return client->dev.platform_data;
- np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+ np = of_graph_get_next_endpoint(client->dev.of_node, NULL);
if (!np)
return NULL;
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index e5ddf47030fd..192c4aad05d6 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
+#include <linux/of_graph.h>
#include <linux/pm.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -29,7 +30,6 @@
#include <media/mt9p031.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-of.h>
#include <media/v4l2-subdev.h>
#include "aptina-pll.h"
@@ -943,7 +943,7 @@ mt9p031_get_pdata(struct i2c_client *client)
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return client->dev.platform_data;
- np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+ np = of_graph_get_next_endpoint(client->dev.of_node, NULL);
if (!np)
return NULL;
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 77e10e0fd8d6..2d768ef67cc5 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -21,6 +21,7 @@
#include <linux/media.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
+#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -1855,7 +1856,7 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev)
if (ret < 0)
return ret;
- node_ep = v4l2_of_get_next_endpoint(node, NULL);
+ node_ep = of_graph_get_next_endpoint(node, NULL);
if (!node_ep) {
dev_err(dev, "no endpoint defined at node %s\n",
node->full_name);
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index 83d85df4853a..ca001178c5bf 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -36,6 +36,7 @@
#include <linux/module.h>
#include <linux/v4l2-mediabus.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
@@ -1068,7 +1069,7 @@ tvp514x_get_pdata(struct i2c_client *client)
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return client->dev.platform_data;
- endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+ endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL);
if (!endpoint)
return NULL;
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index 912e1cccdd1c..c4e1e2cb3094 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -30,6 +30,7 @@
#include <linux/videodev2.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <linux/v4l2-dv-timings.h>
#include <media/tvp7002.h>
#include <media/v4l2-async.h>
@@ -957,7 +958,7 @@ tvp7002_get_pdata(struct i2c_client *client)
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return client->dev.platform_data;
- endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+ endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL);
if (!endpoint)
return NULL;
diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c
index b2c8c3439fea..ea272bcb38df 100644
--- a/drivers/media/pci/cx18/cx18-alsa-main.c
+++ b/drivers/media/pci/cx18/cx18-alsa-main.c
@@ -145,11 +145,12 @@ static int snd_cx18_init(struct v4l2_device *v4l2_dev)
/* This is a no-op for us. We'll use the cx->instance */
/* (2) Create a card instance */
- ret = snd_card_create(SNDRV_DEFAULT_IDX1, /* use first available id */
- SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
- THIS_MODULE, 0, &sc);
+ ret = snd_card_new(&cx->pci_dev->dev,
+ SNDRV_DEFAULT_IDX1, /* use first available id */
+ SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
+ THIS_MODULE, 0, &sc);
if (ret) {
- CX18_ALSA_ERR("%s: snd_card_create() failed with err %d\n",
+ CX18_ALSA_ERR("%s: snd_card_new() failed with err %d\n",
__func__, ret);
goto err_exit;
}
diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c
index c6c9bd58f8be..554798dcedd0 100644
--- a/drivers/media/pci/cx23885/cx23885-alsa.c
+++ b/drivers/media/pci/cx23885/cx23885-alsa.c
@@ -489,7 +489,8 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev)
return NULL;
}
- err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ err = snd_card_new(&dev->pci->dev,
+ SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
THIS_MODULE, sizeof(struct cx23885_audio_dev), &card);
if (err < 0)
goto error;
@@ -500,8 +501,6 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev)
chip->card = card;
spin_lock_init(&chip->lock);
- snd_card_set_dev(card, &dev->pci->dev);
-
err = snd_cx23885_pcm(chip, 0, "CX23885 Digital");
if (err < 0)
goto error;
diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c
index b1e08c3e55cd..2dd5bcaa7e53 100644
--- a/drivers/media/pci/cx25821/cx25821-alsa.c
+++ b/drivers/media/pci/cx25821/cx25821-alsa.c
@@ -645,8 +645,9 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
return -ENOENT;
}
- err = snd_card_create(index[devno], id[devno], THIS_MODULE,
- sizeof(struct cx25821_audio_dev), &card);
+ err = snd_card_new(&dev->pci->dev, index[devno], id[devno],
+ THIS_MODULE,
+ sizeof(struct cx25821_audio_dev), &card);
if (err < 0) {
pr_info("DEBUG ERROR: cannot create snd_card_new in %s\n",
__func__);
@@ -682,8 +683,6 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
goto error;
}
- snd_card_set_dev(card, &chip->pci->dev);
-
strcpy(card->shortname, "cx25821");
sprintf(card->longname, "%s at 0x%lx irq %d", chip->dev->name,
chip->iobase, chip->irq);
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c
index d014206e7176..a72579a9f67f 100644
--- a/drivers/media/pci/cx88/cx88-alsa.c
+++ b/drivers/media/pci/cx88/cx88-alsa.c
@@ -852,8 +852,6 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci,
chip->irq = pci->irq;
synchronize_irq(chip->irq);
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
*core_ptr = core;
@@ -876,8 +874,8 @@ static int cx88_audio_initdev(struct pci_dev *pci,
return (-ENOENT);
}
- err = snd_card_create(index[devno], id[devno], THIS_MODULE,
- sizeof(snd_cx88_card_t), &card);
+ err = snd_card_new(&pci->dev, index[devno], id[devno], THIS_MODULE,
+ sizeof(snd_cx88_card_t), &card);
if (err < 0)
return err;
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-main.c b/drivers/media/pci/ivtv/ivtv-alsa-main.c
index e970cface70e..39b52929755a 100644
--- a/drivers/media/pci/ivtv/ivtv-alsa-main.c
+++ b/drivers/media/pci/ivtv/ivtv-alsa-main.c
@@ -145,11 +145,12 @@ static int snd_ivtv_init(struct v4l2_device *v4l2_dev)
/* This is a no-op for us. We'll use the itv->instance */
/* (2) Create a card instance */
- ret = snd_card_create(SNDRV_DEFAULT_IDX1, /* use first available id */
- SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
- THIS_MODULE, 0, &sc);
+ ret = snd_card_new(&itv->pdev->dev,
+ SNDRV_DEFAULT_IDX1, /* use first available id */
+ SNDRV_DEFAULT_STR1, /* xid from end of shortname*/
+ THIS_MODULE, 0, &sc);
if (ret) {
- IVTV_ALSA_ERR("%s: snd_card_create() failed with err %d\n",
+ IVTV_ALSA_ERR("%s: snd_card_new() failed with err %d\n",
__func__, ret);
goto err_exit;
}
diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c
index dd67c8a400cc..e04a4d5d6672 100644
--- a/drivers/media/pci/saa7134/saa7134-alsa.c
+++ b/drivers/media/pci/saa7134/saa7134-alsa.c
@@ -1072,8 +1072,8 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
if (!enable[devnum])
return -ENODEV;
- err = snd_card_create(index[devnum], id[devnum], THIS_MODULE,
- sizeof(snd_card_saa7134_t), &card);
+ err = snd_card_new(&dev->pci->dev, index[devnum], id[devnum],
+ THIS_MODULE, sizeof(snd_card_saa7134_t), &card);
if (err < 0)
return err;
@@ -1115,8 +1115,6 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
if ((err = snd_card_saa7134_pcm(chip, 0)) < 0)
goto __nodev;
- snd_card_set_dev(card, &chip->pci->dev);
-
/* End of "creation" */
strcpy(card->shortname, "SAA7134");
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
index 13a4228952e3..9bdfa4599bc3 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -24,13 +24,13 @@
#include <linux/i2c.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
+#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/videodev2.h>
-#include <media/v4l2-of.h>
#include <media/videobuf2-dma-contig.h>
#include "media-dev.h"
@@ -167,10 +167,10 @@ static int fimc_is_parse_sensor_config(struct fimc_is_sensor *sensor,
u32 tmp = 0;
int ret;
- np = v4l2_of_get_next_endpoint(np, NULL);
+ np = of_graph_get_next_endpoint(np, NULL);
if (!np)
return -ENXIO;
- np = v4l2_of_get_remote_port(np);
+ np = of_graph_get_remote_port(np);
if (!np)
return -ENXIO;
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index c1bce170df6f..04d6ecdd314c 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -20,6 +20,7 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
+#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/types.h>
@@ -468,12 +469,12 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
return 0;
v4l2_of_parse_endpoint(ep, &endpoint);
- if (WARN_ON(endpoint.port == 0) || index >= FIMC_MAX_SENSORS)
+ if (WARN_ON(endpoint.base.port == 0) || index >= FIMC_MAX_SENSORS)
return -EINVAL;
- pd->mux_id = (endpoint.port - 1) & 0x1;
+ pd->mux_id = (endpoint.base.port - 1) & 0x1;
- rem = v4l2_of_get_remote_port_parent(ep);
+ rem = of_graph_get_remote_port_parent(ep);
of_node_put(ep);
if (rem == NULL) {
v4l2_info(&fmd->v4l2_dev, "Remote device at %s not found\n",
@@ -493,13 +494,13 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
return -EINVAL;
}
- if (fimc_input_is_parallel(endpoint.port)) {
+ if (fimc_input_is_parallel(endpoint.base.port)) {
if (endpoint.bus_type == V4L2_MBUS_PARALLEL)
pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_601;
else
pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_656;
pd->flags = endpoint.bus.parallel.flags;
- } else if (fimc_input_is_mipi_csi(endpoint.port)) {
+ } else if (fimc_input_is_mipi_csi(endpoint.base.port)) {
/*
* MIPI CSI-2: only input mux selection and
* the sensor's clock frequency is needed.
@@ -507,7 +508,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
pd->sensor_bus_type = FIMC_BUS_TYPE_MIPI_CSI2;
} else {
v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %s\n",
- endpoint.port, rem->full_name);
+ endpoint.base.port, rem->full_name);
}
/*
* For FIMC-IS handled sensors, that are placed under i2c-isp device
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index f3c3591fdc5d..3678ba59725c 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -20,6 +20,7 @@
#include <linux/memory.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <linux/phy/phy.h>
#include <linux/platform_data/mipi-csis.h>
#include <linux/platform_device.h>
@@ -762,7 +763,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
&state->max_num_lanes))
return -EINVAL;
- node = v4l2_of_get_next_endpoint(node, NULL);
+ node = of_graph_get_next_endpoint(node, NULL);
if (!node) {
dev_err(&pdev->dev, "No port node at %s\n",
pdev->dev.of_node->full_name);
@@ -771,7 +772,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
/* Get port node and validate MIPI-CSI channel id. */
v4l2_of_parse_endpoint(node, &endpoint);
- state->index = endpoint.port - FIMC_INPUT_MIPI_CSI2_0;
+ state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0;
if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES)
return -ENXIO;
diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
index 81a1d971d797..9b925874d392 100644
--- a/drivers/media/usb/cx231xx/cx231xx-audio.c
+++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -665,8 +665,8 @@ static int cx231xx_audio_init(struct cx231xx *dev)
cx231xx_info("cx231xx-audio.c: probing for cx231xx "
"non standard usbaudio\n");
- err = snd_card_create(index[devnr], "Cx231xx Audio", THIS_MODULE,
- 0, &card);
+ err = snd_card_new(&dev->udev->dev, index[devnr], "Cx231xx Audio",
+ THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -682,7 +682,6 @@ static int cx231xx_audio_init(struct cx231xx *dev)
pcm->info_flags = 0;
pcm->private_data = dev;
strcpy(pcm->name, "Conexant cx231xx Capture");
- snd_card_set_dev(card, &dev->udev->dev);
strcpy(card->driver, "Cx231xx-Audio");
strcpy(card->shortname, "Cx231xx Audio");
strcpy(card->longname, "Conexant cx231xx Audio");
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 05e9bd11a3ff..1a28897af183 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -900,8 +900,8 @@ static int em28xx_audio_init(struct em28xx *dev)
printk(KERN_INFO
"em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
- err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
- &card);
+ err = snd_card_new(&dev->udev->dev, index[devnr], "Em28xx Audio",
+ THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -918,7 +918,6 @@ static int em28xx_audio_init(struct em28xx *dev)
pcm->private_data = dev;
strcpy(pcm->name, "Empia 28xx Capture");
- snd_card_set_dev(card, &dev->udev->dev);
strcpy(card->driver, "Em28xx-Audio");
strcpy(card->shortname, "Em28xx Audio");
strcpy(card->longname, "Empia Em28xx Audio");
diff --git a/drivers/media/usb/stk1160/stk1160-ac97.c b/drivers/media/usb/stk1160/stk1160-ac97.c
index c8583c262c3d..c46c8be89602 100644
--- a/drivers/media/usb/stk1160/stk1160-ac97.c
+++ b/drivers/media/usb/stk1160/stk1160-ac97.c
@@ -98,13 +98,11 @@ int stk1160_ac97_register(struct stk1160 *dev)
* Just want a card to access ac96 controls,
* the actual capture interface will be handled by snd-usb-audio
*/
- rc = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- THIS_MODULE, 0, &card);
+ rc = snd_card_new(dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &card);
if (rc < 0)
return rc;
- snd_card_set_dev(card, dev->dev);
-
/* TODO: I'm not sure where should I get these names :-( */
snprintf(card->shortname, sizeof(card->shortname),
"stk1160-mixer");
diff --git a/drivers/media/usb/tlg2300/pd-alsa.c b/drivers/media/usb/tlg2300/pd-alsa.c
index 3f3e141f70fb..dd8fe100590f 100644
--- a/drivers/media/usb/tlg2300/pd-alsa.c
+++ b/drivers/media/usb/tlg2300/pd-alsa.c
@@ -300,7 +300,8 @@ int poseidon_audio_init(struct poseidon *p)
struct snd_pcm *pcm;
int ret;
- ret = snd_card_create(-1, "Telegent", THIS_MODULE, 0, &card);
+ ret = snd_card_new(&p->interface->dev, -1, "Telegent",
+ THIS_MODULE, 0, &card);
if (ret != 0)
return ret;
diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/media/usb/tm6000/tm6000-alsa.c
index 813c1ec53608..3239cd62e452 100644
--- a/drivers/media/usb/tm6000/tm6000-alsa.c
+++ b/drivers/media/usb/tm6000/tm6000-alsa.c
@@ -431,7 +431,8 @@ static int tm6000_audio_init(struct tm6000_core *dev)
if (!enable[devnr])
return -ENOENT;
- rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
+ rc = snd_card_new(&dev->udev->dev, index[devnr], "tm6000",
+ THIS_MODULE, 0, &card);
if (rc < 0) {
snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
return rc;
@@ -445,7 +446,6 @@ static int tm6000_audio_init(struct tm6000_core *dev)
le16_to_cpu(dev->udev->descriptor.idVendor),
le16_to_cpu(dev->udev->descriptor.idProduct));
snd_component_add(card, component);
- snd_card_set_dev(card, &dev->udev->dev);
chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
if (!chip) {
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 8f7a6a454a4c..6191968db8fa 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -733,7 +733,7 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u
copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
put_user(kp->pending, &up->pending) ||
put_user(kp->sequence, &up->sequence) ||
- put_compat_timespec(&kp->timestamp, &up->timestamp) ||
+ compat_put_timespec(&kp->timestamp, &up->timestamp) ||
put_user(kp->id, &up->id) ||
copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
return -EFAULT;
diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c
index 42e3e8a5e361..b4ed9a955fbe 100644
--- a/drivers/media/v4l2-core/v4l2-of.c
+++ b/drivers/media/v4l2-core/v4l2-of.c
@@ -127,17 +127,9 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node,
int v4l2_of_parse_endpoint(const struct device_node *node,
struct v4l2_of_endpoint *endpoint)
{
- struct device_node *port_node = of_get_parent(node);
-
- memset(endpoint, 0, offsetof(struct v4l2_of_endpoint, head));
-
- endpoint->local_node = node;
- /*
- * It doesn't matter whether the two calls below succeed.
- * If they don't then the default value 0 is used.
- */
- of_property_read_u32(port_node, "reg", &endpoint->port);
- of_property_read_u32(node, "reg", &endpoint->id);
+ of_graph_parse_endpoint(node, &endpoint->base);
+ endpoint->bus_type = 0;
+ memset(&endpoint->bus, 0, sizeof(endpoint->bus));
v4l2_of_parse_csi_bus(node, endpoint);
/*
@@ -147,125 +139,6 @@ int v4l2_of_parse_endpoint(const struct device_node *node,
if (endpoint->bus.mipi_csi2.flags == 0)
v4l2_of_parse_parallel_bus(node, endpoint);
- of_node_put(port_node);
-
return 0;
}
EXPORT_SYMBOL(v4l2_of_parse_endpoint);
-
-/**
- * v4l2_of_get_next_endpoint() - get next endpoint node
- * @parent: pointer to the parent device node
- * @prev: previous endpoint node, or NULL to get first
- *
- * Return: An 'endpoint' node pointer with refcount incremented. Refcount
- * of the passed @prev node is not decremented, the caller have to use
- * of_node_put() on it when done.
- */
-struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent,
- struct device_node *prev)
-{
- struct device_node *endpoint;
- struct device_node *port = NULL;
-
- if (!parent)
- return NULL;
-
- if (!prev) {
- struct device_node *node;
- /*
- * It's the first call, we have to find a port subnode
- * within this node or within an optional 'ports' node.
- */
- node = of_get_child_by_name(parent, "ports");
- if (node)
- parent = node;
-
- port = of_get_child_by_name(parent, "port");
-
- if (port) {
- /* Found a port, get an endpoint. */
- endpoint = of_get_next_child(port, NULL);
- of_node_put(port);
- } else {
- endpoint = NULL;
- }
-
- if (!endpoint)
- pr_err("%s(): no endpoint nodes specified for %s\n",
- __func__, parent->full_name);
- of_node_put(node);
- } else {
- port = of_get_parent(prev);
- if (!port)
- /* Hm, has someone given us the root node ?... */
- return NULL;
-
- /* Avoid dropping prev node refcount to 0. */
- of_node_get(prev);
- endpoint = of_get_next_child(port, prev);
- if (endpoint) {
- of_node_put(port);
- return endpoint;
- }
-
- /* No more endpoints under this port, try the next one. */
- do {
- port = of_get_next_child(parent, port);
- if (!port)
- return NULL;
- } while (of_node_cmp(port->name, "port"));
-
- /* Pick up the first endpoint in this port. */
- endpoint = of_get_next_child(port, NULL);
- of_node_put(port);
- }
-
- return endpoint;
-}
-EXPORT_SYMBOL(v4l2_of_get_next_endpoint);
-
-/**
- * v4l2_of_get_remote_port_parent() - get remote port's parent node
- * @node: pointer to a local endpoint device_node
- *
- * Return: Remote device node associated with remote endpoint node linked
- * to @node. Use of_node_put() on it when done.
- */
-struct device_node *v4l2_of_get_remote_port_parent(
- const struct device_node *node)
-{
- struct device_node *np;
- unsigned int depth;
-
- /* Get remote endpoint node. */
- np = of_parse_phandle(node, "remote-endpoint", 0);
-
- /* Walk 3 levels up only if there is 'ports' node. */
- for (depth = 3; depth && np; depth--) {
- np = of_get_next_parent(np);
- if (depth == 2 && of_node_cmp(np->name, "ports"))
- break;
- }
- return np;
-}
-EXPORT_SYMBOL(v4l2_of_get_remote_port_parent);
-
-/**
- * v4l2_of_get_remote_port() - get remote port node
- * @node: pointer to a local endpoint device_node
- *
- * Return: Remote port node associated with remote endpoint node linked
- * to @node. Use of_node_put() on it when done.
- */
-struct device_node *v4l2_of_get_remote_port(const struct device_node *node)
-{
- struct device_node *np;
-
- /* Get remote endpoint node. */
- np = of_parse_phandle(node, "remote-endpoint", 0);
- if (!np)
- return NULL;
- return of_get_next_parent(np);
-}
-EXPORT_SYMBOL(v4l2_of_get_remote_port);
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 33d3871d1e13..880be0782dd9 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -719,7 +719,7 @@ static int vb2_dc_map_dmabuf(void *mem_priv)
/* get the associated scatterlist for this buffer */
sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir);
- if (IS_ERR_OR_NULL(sgt)) {
+ if (IS_ERR(sgt)) {
pr_err("Error getting dmabuf scatterlist\n");
return -EINVAL;
}
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 29a11db365bc..c59e9c96e86d 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -7,6 +7,17 @@ menuconfig MEMORY
if MEMORY
+config TI_AEMIF
+ tristate "Texas Instruments AEMIF driver"
+ depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF
+ help
+ This driver is for the AEMIF module available in Texas Instruments
+ SoCs. AEMIF stands for Asynchronous External Memory Interface and
+ is intended to provide a glue-less interface to a variety of
+ asynchronuous memory devices like ASRAM, NOR and NAND memory. A total
+ of 256M bytes of any of these memories can be accessed at a given
+ time via four chip selects with 64M byte access per chip select.
+
config TI_EMIF
tristate "Texas Instruments EMIF driver"
depends on ARCH_OMAP2PLUS
@@ -50,4 +61,8 @@ config TEGRA30_MC
analysis, especially for IOMMU/SMMU(System Memory Management
Unit) module.
+config FSL_IFC
+ bool
+ depends on FSL_SOC
+
endif
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 969d923dad93..71160a2b7313 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -5,7 +5,9 @@
ifeq ($(CONFIG_DDR),y)
obj-$(CONFIG_OF) += of_memory.o
endif
+obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
obj-$(CONFIG_TI_EMIF) += emif.o
+obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o
obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o
diff --git a/arch/powerpc/sysdev/fsl_ifc.c b/drivers/memory/fsl_ifc.c
index fbc885b31946..3d5d792d5cb2 100644
--- a/arch/powerpc/sysdev/fsl_ifc.c
+++ b/drivers/memory/fsl_ifc.c
@@ -29,8 +29,8 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/fsl_ifc.h>
#include <asm/prom.h>
-#include <asm/fsl_ifc.h>
struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
EXPORT_SYMBOL(fsl_ifc_ctrl_dev);
@@ -298,7 +298,11 @@ static struct platform_driver fsl_ifc_ctrl_driver = {
.remove = fsl_ifc_ctrl_remove,
};
-module_platform_driver(fsl_ifc_ctrl_driver);
+static int __init fsl_ifc_init(void)
+{
+ return platform_driver_register(&fsl_ifc_ctrl_driver);
+}
+subsys_initcall(fsl_ifc_init);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Freescale Semiconductor");
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c
new file mode 100644
index 000000000000..d3df7602f406
--- /dev/null
+++ b/drivers/memory/ti-aemif.c
@@ -0,0 +1,427 @@
+/*
+ * TI AEMIF driver
+ *
+ * Copyright (C) 2010 - 2013 Texas Instruments Incorporated. http://www.ti.com/
+ *
+ * Authors:
+ * Murali Karicheri <m-karicheri2@ti.com>
+ * Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#define TA_SHIFT 2
+#define RHOLD_SHIFT 4
+#define RSTROBE_SHIFT 7
+#define RSETUP_SHIFT 13
+#define WHOLD_SHIFT 17
+#define WSTROBE_SHIFT 20
+#define WSETUP_SHIFT 26
+#define EW_SHIFT 30
+#define SS_SHIFT 31
+
+#define TA(x) ((x) << TA_SHIFT)
+#define RHOLD(x) ((x) << RHOLD_SHIFT)
+#define RSTROBE(x) ((x) << RSTROBE_SHIFT)
+#define RSETUP(x) ((x) << RSETUP_SHIFT)
+#define WHOLD(x) ((x) << WHOLD_SHIFT)
+#define WSTROBE(x) ((x) << WSTROBE_SHIFT)
+#define WSETUP(x) ((x) << WSETUP_SHIFT)
+#define EW(x) ((x) << EW_SHIFT)
+#define SS(x) ((x) << SS_SHIFT)
+
+#define ASIZE_MAX 0x1
+#define TA_MAX 0x3
+#define RHOLD_MAX 0x7
+#define RSTROBE_MAX 0x3f
+#define RSETUP_MAX 0xf
+#define WHOLD_MAX 0x7
+#define WSTROBE_MAX 0x3f
+#define WSETUP_MAX 0xf
+#define EW_MAX 0x1
+#define SS_MAX 0x1
+#define NUM_CS 4
+
+#define TA_VAL(x) (((x) & TA(TA_MAX)) >> TA_SHIFT)
+#define RHOLD_VAL(x) (((x) & RHOLD(RHOLD_MAX)) >> RHOLD_SHIFT)
+#define RSTROBE_VAL(x) (((x) & RSTROBE(RSTROBE_MAX)) >> RSTROBE_SHIFT)
+#define RSETUP_VAL(x) (((x) & RSETUP(RSETUP_MAX)) >> RSETUP_SHIFT)
+#define WHOLD_VAL(x) (((x) & WHOLD(WHOLD_MAX)) >> WHOLD_SHIFT)
+#define WSTROBE_VAL(x) (((x) & WSTROBE(WSTROBE_MAX)) >> WSTROBE_SHIFT)
+#define WSETUP_VAL(x) (((x) & WSETUP(WSETUP_MAX)) >> WSETUP_SHIFT)
+#define EW_VAL(x) (((x) & EW(EW_MAX)) >> EW_SHIFT)
+#define SS_VAL(x) (((x) & SS(SS_MAX)) >> SS_SHIFT)
+
+#define NRCSR_OFFSET 0x00
+#define AWCCR_OFFSET 0x04
+#define A1CR_OFFSET 0x10
+
+#define ACR_ASIZE_MASK 0x3
+#define ACR_EW_MASK BIT(30)
+#define ACR_SS_MASK BIT(31)
+#define ASIZE_16BIT 1
+
+#define CONFIG_MASK (TA(TA_MAX) | \
+ RHOLD(RHOLD_MAX) | \
+ RSTROBE(RSTROBE_MAX) | \
+ RSETUP(RSETUP_MAX) | \
+ WHOLD(WHOLD_MAX) | \
+ WSTROBE(WSTROBE_MAX) | \
+ WSETUP(WSETUP_MAX) | \
+ EW(EW_MAX) | SS(SS_MAX) | \
+ ASIZE_MAX)
+
+/**
+ * struct aemif_cs_data: structure to hold cs parameters
+ * @cs: chip-select number
+ * @wstrobe: write strobe width, ns
+ * @rstrobe: read strobe width, ns
+ * @wsetup: write setup width, ns
+ * @whold: write hold width, ns
+ * @rsetup: read setup width, ns
+ * @rhold: read hold width, ns
+ * @ta: minimum turn around time, ns
+ * @enable_ss: enable/disable select strobe mode
+ * @enable_ew: enable/disable extended wait mode
+ * @asize: width of the asynchronous device's data bus
+ */
+struct aemif_cs_data {
+ u8 cs;
+ u16 wstrobe;
+ u16 rstrobe;
+ u8 wsetup;
+ u8 whold;
+ u8 rsetup;
+ u8 rhold;
+ u8 ta;
+ u8 enable_ss;
+ u8 enable_ew;
+ u8 asize;
+};
+
+/**
+ * struct aemif_device: structure to hold device data
+ * @base: base address of AEMIF registers
+ * @clk: source clock
+ * @clk_rate: clock's rate in kHz
+ * @num_cs: number of assigned chip-selects
+ * @cs_offset: start number of cs nodes
+ * @cs_data: array of chip-select settings
+ */
+struct aemif_device {
+ void __iomem *base;
+ struct clk *clk;
+ unsigned long clk_rate;
+ u8 num_cs;
+ int cs_offset;
+ struct aemif_cs_data cs_data[NUM_CS];
+};
+
+/**
+ * aemif_calc_rate - calculate timing data.
+ * @pdev: platform device to calculate for
+ * @wanted: The cycle time needed in nanoseconds.
+ * @clk: The input clock rate in kHz.
+ * @max: The maximum divider value that can be programmed.
+ *
+ * On success, returns the calculated timing value minus 1 for easy
+ * programming into AEMIF timing registers, else negative errno.
+ */
+static int aemif_calc_rate(struct platform_device *pdev, int wanted,
+ unsigned long clk, int max)
+{
+ int result;
+
+ result = DIV_ROUND_UP((wanted * clk), NSEC_PER_MSEC) - 1;
+
+ dev_dbg(&pdev->dev, "%s: result %d from %ld, %d\n", __func__, result,
+ clk, wanted);
+
+ /* It is generally OK to have a more relaxed timing than requested... */
+ if (result < 0)
+ result = 0;
+
+ /* ... But configuring tighter timings is not an option. */
+ else if (result > max)
+ result = -EINVAL;
+
+ return result;
+}
+
+/**
+ * aemif_config_abus - configure async bus parameters
+ * @pdev: platform device to configure for
+ * @csnum: aemif chip select number
+ *
+ * This function programs the given timing values (in real clock) into the
+ * AEMIF registers taking the AEMIF clock into account.
+ *
+ * This function does not use any locking while programming the AEMIF
+ * because it is expected that there is only one user of a given
+ * chip-select.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+static int aemif_config_abus(struct platform_device *pdev, int csnum)
+{
+ struct aemif_device *aemif = platform_get_drvdata(pdev);
+ struct aemif_cs_data *data = &aemif->cs_data[csnum];
+ int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
+ unsigned long clk_rate = aemif->clk_rate;
+ unsigned offset;
+ u32 set, val;
+
+ offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
+
+ ta = aemif_calc_rate(pdev, data->ta, clk_rate, TA_MAX);
+ rhold = aemif_calc_rate(pdev, data->rhold, clk_rate, RHOLD_MAX);
+ rstrobe = aemif_calc_rate(pdev, data->rstrobe, clk_rate, RSTROBE_MAX);
+ rsetup = aemif_calc_rate(pdev, data->rsetup, clk_rate, RSETUP_MAX);
+ whold = aemif_calc_rate(pdev, data->whold, clk_rate, WHOLD_MAX);
+ wstrobe = aemif_calc_rate(pdev, data->wstrobe, clk_rate, WSTROBE_MAX);
+ wsetup = aemif_calc_rate(pdev, data->wsetup, clk_rate, WSETUP_MAX);
+
+ if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
+ whold < 0 || wstrobe < 0 || wsetup < 0) {
+ dev_err(&pdev->dev, "%s: cannot get suitable timings\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
+ WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
+
+ set |= (data->asize & ACR_ASIZE_MASK);
+ if (data->enable_ew)
+ set |= ACR_EW_MASK;
+ if (data->enable_ss)
+ set |= ACR_SS_MASK;
+
+ val = readl(aemif->base + offset);
+ val &= ~CONFIG_MASK;
+ val |= set;
+ writel(val, aemif->base + offset);
+
+ return 0;
+}
+
+static inline int aemif_cycles_to_nsec(int val, unsigned long clk_rate)
+{
+ return ((val + 1) * NSEC_PER_MSEC) / clk_rate;
+}
+
+/**
+ * aemif_get_hw_params - function to read hw register values
+ * @pdev: platform device to read for
+ * @csnum: aemif chip select number
+ *
+ * This function reads the defaults from the registers and update
+ * the timing values. Required for get/set commands and also for
+ * the case when driver needs to use defaults in hardware.
+ */
+static void aemif_get_hw_params(struct platform_device *pdev, int csnum)
+{
+ struct aemif_device *aemif = platform_get_drvdata(pdev);
+ struct aemif_cs_data *data = &aemif->cs_data[csnum];
+ unsigned long clk_rate = aemif->clk_rate;
+ u32 val, offset;
+
+ offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
+ val = readl(aemif->base + offset);
+
+ data->ta = aemif_cycles_to_nsec(TA_VAL(val), clk_rate);
+ data->rhold = aemif_cycles_to_nsec(RHOLD_VAL(val), clk_rate);
+ data->rstrobe = aemif_cycles_to_nsec(RSTROBE_VAL(val), clk_rate);
+ data->rsetup = aemif_cycles_to_nsec(RSETUP_VAL(val), clk_rate);
+ data->whold = aemif_cycles_to_nsec(WHOLD_VAL(val), clk_rate);
+ data->wstrobe = aemif_cycles_to_nsec(WSTROBE_VAL(val), clk_rate);
+ data->wsetup = aemif_cycles_to_nsec(WSETUP_VAL(val), clk_rate);
+ data->enable_ew = EW_VAL(val);
+ data->enable_ss = SS_VAL(val);
+ data->asize = val & ASIZE_MAX;
+}
+
+/**
+ * of_aemif_parse_abus_config - parse CS configuration from DT
+ * @pdev: platform device to parse for
+ * @np: device node ptr
+ *
+ * This function update the emif async bus configuration based on the values
+ * configured in a cs device binding node.
+ */
+static int of_aemif_parse_abus_config(struct platform_device *pdev,
+ struct device_node *np)
+{
+ struct aemif_device *aemif = platform_get_drvdata(pdev);
+ struct aemif_cs_data *data;
+ u32 cs;
+ u32 val;
+
+ if (of_property_read_u32(np, "ti,cs-chipselect", &cs)) {
+ dev_dbg(&pdev->dev, "cs property is required");
+ return -EINVAL;
+ }
+
+ if (cs - aemif->cs_offset >= NUM_CS || cs < aemif->cs_offset) {
+ dev_dbg(&pdev->dev, "cs number is incorrect %d", cs);
+ return -EINVAL;
+ }
+
+ if (aemif->num_cs >= NUM_CS) {
+ dev_dbg(&pdev->dev, "cs count is more than %d", NUM_CS);
+ return -EINVAL;
+ }
+
+ data = &aemif->cs_data[aemif->num_cs];
+ data->cs = cs;
+
+ /* read the current value in the hw register */
+ aemif_get_hw_params(pdev, aemif->num_cs++);
+
+ /* override the values from device node */
+ if (!of_property_read_u32(np, "ti,cs-min-turnaround-ns", &val))
+ data->ta = val;
+
+ if (!of_property_read_u32(np, "ti,cs-read-hold-ns", &val))
+ data->rhold = val;
+
+ if (!of_property_read_u32(np, "ti,cs-read-strobe-ns", &val))
+ data->rstrobe = val;
+
+ if (!of_property_read_u32(np, "ti,cs-read-setup-ns", &val))
+ data->rsetup = val;
+
+ if (!of_property_read_u32(np, "ti,cs-write-hold-ns", &val))
+ data->whold = val;
+
+ if (!of_property_read_u32(np, "ti,cs-write-strobe-ns", &val))
+ data->wstrobe = val;
+
+ if (!of_property_read_u32(np, "ti,cs-write-setup-ns", &val))
+ data->wsetup = val;
+
+ if (!of_property_read_u32(np, "ti,cs-bus-width", &val))
+ if (val == 16)
+ data->asize = 1;
+ data->enable_ew = of_property_read_bool(np, "ti,cs-extended-wait-mode");
+ data->enable_ss = of_property_read_bool(np, "ti,cs-select-strobe-mode");
+ return 0;
+}
+
+static const struct of_device_id aemif_of_match[] = {
+ { .compatible = "ti,davinci-aemif", },
+ { .compatible = "ti,da850-aemif", },
+ {},
+};
+
+static int aemif_probe(struct platform_device *pdev)
+{
+ int i;
+ int ret = -ENODEV;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *child_np;
+ struct aemif_device *aemif;
+
+ if (np == NULL)
+ return 0;
+
+ aemif = devm_kzalloc(dev, sizeof(*aemif), GFP_KERNEL);
+ if (!aemif)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, aemif);
+
+ aemif->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(aemif->clk)) {
+ dev_err(dev, "cannot get clock 'aemif'\n");
+ return PTR_ERR(aemif->clk);
+ }
+
+ clk_prepare_enable(aemif->clk);
+ aemif->clk_rate = clk_get_rate(aemif->clk) / MSEC_PER_SEC;
+
+ if (of_device_is_compatible(np, "ti,da850-aemif"))
+ aemif->cs_offset = 2;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ aemif->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(aemif->base)) {
+ ret = PTR_ERR(aemif->base);
+ goto error;
+ }
+
+ /*
+ * For every controller device node, there is a cs device node that
+ * describe the bus configuration parameters. This functions iterate
+ * over these nodes and update the cs data array.
+ */
+ for_each_available_child_of_node(np, child_np) {
+ ret = of_aemif_parse_abus_config(pdev, child_np);
+ if (ret < 0)
+ goto error;
+ }
+
+ for (i = 0; i < aemif->num_cs; i++) {
+ ret = aemif_config_abus(pdev, i);
+ if (ret < 0) {
+ dev_err(dev, "Error configuring chip select %d\n",
+ aemif->cs_data[i].cs);
+ goto error;
+ }
+ }
+
+ /*
+ * Create a child devices explicitly from here to
+ * guarantee that the child will be probed after the AEMIF timing
+ * parameters are set.
+ */
+ for_each_available_child_of_node(np, child_np) {
+ ret = of_platform_populate(child_np, NULL, NULL, dev);
+ if (ret < 0)
+ goto error;
+ }
+
+ return 0;
+error:
+ clk_disable_unprepare(aemif->clk);
+ return ret;
+}
+
+static int aemif_remove(struct platform_device *pdev)
+{
+ struct aemif_device *aemif = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(aemif->clk);
+ return 0;
+}
+
+static struct platform_driver aemif_driver = {
+ .probe = aemif_probe,
+ .remove = aemif_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(aemif_of_match),
+ },
+};
+
+module_platform_driver(aemif_driver);
+
+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
+MODULE_AUTHOR("Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>");
+MODULE_DESCRIPTION("Texas Instruments AEMIF driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" KBUILD_MODNAME);
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
index a8c08f332da0..92752fb5b2d3 100644
--- a/drivers/message/i2o/iop.c
+++ b/drivers/message/i2o/iop.c
@@ -652,6 +652,44 @@ static int i2o_iop_activate(struct i2o_controller *c)
return i2o_hrt_get(c);
};
+static void i2o_res_alloc(struct i2o_controller *c, unsigned long flags)
+{
+ i2o_status_block *sb = c->status_block.virt;
+ struct resource *res = &c->mem_resource;
+ resource_size_t size, align;
+ int err;
+
+ res->name = c->pdev->bus->name;
+ res->flags = flags;
+ res->start = 0;
+ res->end = 0;
+ osm_info("%s: requires private memory resources.\n", c->name);
+
+ if (flags & IORESOURCE_MEM) {
+ size = sb->desired_mem_size;
+ align = 1 << 20; /* unspecified, use 1Mb and play safe */
+ } else {
+ size = sb->desired_io_size;
+ align = 1 << 12; /* unspecified, use 4Kb and play safe */
+ }
+
+ err = pci_bus_alloc_resource(c->pdev->bus, res, size, align, 0, 0,
+ NULL, NULL);
+ if (err < 0)
+ return;
+
+ if (flags & IORESOURCE_MEM) {
+ c->mem_alloc = 1;
+ sb->current_mem_size = resource_size(res);
+ sb->current_mem_base = res->start;
+ } else if (flags & IORESOURCE_IO) {
+ c->io_alloc = 1;
+ sb->current_io_size = resource_size(res);
+ sb->current_io_base = res->start;
+ }
+ osm_info("%s: allocated PCI space %pR\n", c->name, res);
+}
+
/**
* i2o_iop_systab_set - Set the I2O System Table of the specified IOP
* @c: I2O controller to which the system table should be send
@@ -665,52 +703,13 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
struct i2o_message *msg;
i2o_status_block *sb = c->status_block.virt;
struct device *dev = &c->pdev->dev;
- struct resource *root;
int rc;
- if (sb->current_mem_size < sb->desired_mem_size) {
- struct resource *res = &c->mem_resource;
- res->name = c->pdev->bus->name;
- res->flags = IORESOURCE_MEM;
- res->start = 0;
- res->end = 0;
- osm_info("%s: requires private memory resources.\n", c->name);
- root = pci_find_parent_resource(c->pdev, res);
- if (root == NULL)
- osm_warn("%s: Can't find parent resource!\n", c->name);
- if (root && allocate_resource(root, res, sb->desired_mem_size, sb->desired_mem_size, sb->desired_mem_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */
- NULL, NULL) >= 0) {
- c->mem_alloc = 1;
- sb->current_mem_size = resource_size(res);
- sb->current_mem_base = res->start;
- osm_info("%s: allocated %llu bytes of PCI memory at "
- "0x%016llX.\n", c->name,
- (unsigned long long)resource_size(res),
- (unsigned long long)res->start);
- }
- }
+ if (sb->current_mem_size < sb->desired_mem_size)
+ i2o_res_alloc(c, IORESOURCE_MEM);
- if (sb->current_io_size < sb->desired_io_size) {
- struct resource *res = &c->io_resource;
- res->name = c->pdev->bus->name;
- res->flags = IORESOURCE_IO;
- res->start = 0;
- res->end = 0;
- osm_info("%s: requires private memory resources.\n", c->name);
- root = pci_find_parent_resource(c->pdev, res);
- if (root == NULL)
- osm_warn("%s: Can't find parent resource!\n", c->name);
- if (root && allocate_resource(root, res, sb->desired_io_size, sb->desired_io_size, sb->desired_io_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */
- NULL, NULL) >= 0) {
- c->io_alloc = 1;
- sb->current_io_size = resource_size(res);
- sb->current_mem_base = res->start;
- osm_info("%s: allocated %llu bytes of PCI I/O at "
- "0x%016llX.\n", c->name,
- (unsigned long long)resource_size(res),
- (unsigned long long)res->start);
- }
- }
+ if (sb->current_io_size < sb->desired_io_size)
+ i2o_res_alloc(c, IORESOURCE_IO);
msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
if (IS_ERR(msg))
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index a45aab9f6bb1..1c3ae57082ed 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -251,8 +251,6 @@ static int arizona_apply_hardware_patch(struct arizona* arizona)
unsigned int fll, sysclk;
int ret, err;
- regcache_cache_bypass(arizona->regmap, true);
-
/* Cache existing FLL and SYSCLK settings */
ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll);
if (ret != 0) {
@@ -322,8 +320,6 @@ err_fll:
err);
}
- regcache_cache_bypass(arizona->regmap, false);
-
if (ret != 0)
return ret;
else
diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c
index 13af7e50021e..8103e4362132 100644
--- a/drivers/mfd/da9055-i2c.c
+++ b/drivers/mfd/da9055-i2c.c
@@ -53,17 +53,25 @@ static int da9055_i2c_remove(struct i2c_client *i2c)
return 0;
}
+/*
+ * DO NOT change the device Ids. The naming is intentionally specific as both
+ * the PMIC and CODEC parts of this chip are instantiated separately as I2C
+ * devices (both have configurable I2C addresses, and are to all intents and
+ * purposes separate). As a result there are specific DA9055 ids for PMIC
+ * and CODEC, which must be different to operate together.
+ */
static struct i2c_device_id da9055_i2c_id[] = {
- {"da9055", 0},
+ {"da9055-pmic", 0},
{ }
};
+MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
static struct i2c_driver da9055_i2c_driver = {
.probe = da9055_i2c_probe,
.remove = da9055_i2c_remove,
.id_table = da9055_i2c_id,
.driver = {
- .name = "da9055",
+ .name = "da9055-pmic",
.owner = THIS_MODULE,
},
};
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c
index ac514fb2b877..71aa14a6bfbb 100644
--- a/drivers/mfd/max14577.c
+++ b/drivers/mfd/max14577.c
@@ -173,6 +173,7 @@ static const struct i2c_device_id max14577_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
+#ifdef CONFIG_PM_SLEEP
static int max14577_suspend(struct device *dev)
{
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
@@ -208,6 +209,7 @@ static int max14577_resume(struct device *dev)
return 0;
}
+#endif /* CONFIG_PM_SLEEP */
static struct of_device_id max14577_dt_match[] = {
{ .compatible = "maxim,max14577", },
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
index be88a3bf7b85..5adede0fb04c 100644
--- a/drivers/mfd/max8997.c
+++ b/drivers/mfd/max8997.c
@@ -164,15 +164,15 @@ static struct max8997_platform_data *max8997_i2c_parse_dt_pdata(
return pd;
}
-static inline int max8997_i2c_get_driver_data(struct i2c_client *i2c,
+static inline unsigned long max8997_i2c_get_driver_data(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(max8997_pmic_dt_match, i2c->dev.of_node);
- return (int)match->data;
+ return (unsigned long)match->data;
}
- return (int)id->driver_data;
+ return id->driver_data;
}
static int max8997_i2c_probe(struct i2c_client *i2c,
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
index 612ca404e150..5d5e186b5d8b 100644
--- a/drivers/mfd/max8998.c
+++ b/drivers/mfd/max8998.c
@@ -169,16 +169,16 @@ static struct max8998_platform_data *max8998_i2c_parse_dt_pdata(
return pd;
}
-static inline int max8998_i2c_get_driver_data(struct i2c_client *i2c,
+static inline unsigned long max8998_i2c_get_driver_data(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(max8998_dt_match, i2c->dev.of_node);
- return (int)(long)match->data;
+ return (unsigned long)match->data;
}
- return (int)id->driver_data;
+ return id->driver_data;
}
static int max8998_i2c_probe(struct i2c_client *i2c,
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
index a139798b8065..281a82747275 100644
--- a/drivers/mfd/sec-core.c
+++ b/drivers/mfd/sec-core.c
@@ -26,7 +26,9 @@
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/irq.h>
#include <linux/mfd/samsung/rtc.h>
+#include <linux/mfd/samsung/s2mpa01.h>
#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s2mps14.h>
#include <linux/mfd/samsung/s5m8763.h>
#include <linux/mfd/samsung/s5m8767.h>
#include <linux/regmap.h>
@@ -69,18 +71,53 @@ static const struct mfd_cell s2mps11_devs[] = {
}
};
+static const struct mfd_cell s2mps14_devs[] = {
+ {
+ .name = "s2mps14-pmic",
+ }, {
+ .name = "s2mps14-rtc",
+ }, {
+ .name = "s2mps14-clk",
+ }
+};
+
+static const struct mfd_cell s2mpa01_devs[] = {
+ {
+ .name = "s2mpa01-pmic",
+ },
+};
+
#ifdef CONFIG_OF
static struct of_device_id sec_dt_match[] = {
{ .compatible = "samsung,s5m8767-pmic",
.data = (void *)S5M8767X,
- },
- { .compatible = "samsung,s2mps11-pmic",
+ }, {
+ .compatible = "samsung,s2mps11-pmic",
.data = (void *)S2MPS11X,
+ }, {
+ .compatible = "samsung,s2mps14-pmic",
+ .data = (void *)S2MPS14X,
+ }, {
+ .compatible = "samsung,s2mpa01-pmic",
+ .data = (void *)S2MPA01,
+ }, {
+ /* Sentinel */
},
- {},
};
#endif
+static bool s2mpa01_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case S2MPA01_REG_INT1M:
+ case S2MPA01_REG_INT2M:
+ case S2MPA01_REG_INT3M:
+ return false;
+ default:
+ return true;
+ }
+}
+
static bool s2mps11_volatile(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -111,6 +148,15 @@ static const struct regmap_config sec_regmap_config = {
.val_bits = 8,
};
+static const struct regmap_config s2mpa01_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S2MPA01_REG_LDO_OVCB4,
+ .volatile_reg = s2mpa01_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
static const struct regmap_config s2mps11_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -120,6 +166,15 @@ static const struct regmap_config s2mps11_regmap_config = {
.cache_type = REGCACHE_FLAT,
};
+static const struct regmap_config s2mps14_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S2MPS14_REG_LDODSCH3,
+ .volatile_reg = s2mps11_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
static const struct regmap_config s5m8763_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -138,9 +193,18 @@ static const struct regmap_config s5m8767_regmap_config = {
.cache_type = REGCACHE_FLAT,
};
-static const struct regmap_config sec_rtc_regmap_config = {
+static const struct regmap_config s5m_rtc_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = SEC_RTC_REG_MAX,
+};
+
+static const struct regmap_config s2mps14_rtc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
+
+ .max_register = S2MPS_RTC_REG_MAX,
};
#ifdef CONFIG_OF
@@ -180,24 +244,24 @@ static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
}
#endif
-static inline int sec_i2c_get_driver_data(struct i2c_client *i2c,
+static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
#ifdef CONFIG_OF
if (i2c->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(sec_dt_match, i2c->dev.of_node);
- return (int)match->data;
+ return (unsigned long)match->data;
}
#endif
- return (int)id->driver_data;
+ return id->driver_data;
}
static int sec_pmic_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev);
- const struct regmap_config *regmap;
+ const struct regmap_config *regmap, *regmap_rtc;
struct sec_pmic_dev *sec_pmic;
int ret;
@@ -229,17 +293,34 @@ static int sec_pmic_probe(struct i2c_client *i2c,
}
switch (sec_pmic->device_type) {
+ case S2MPA01:
+ regmap = &s2mpa01_regmap_config;
+ break;
case S2MPS11X:
regmap = &s2mps11_regmap_config;
+ /*
+ * The rtc-s5m driver does not support S2MPS11 and there
+ * is no mfd_cell for S2MPS11 RTC device.
+ * However we must pass something to devm_regmap_init_i2c()
+ * so use S5M-like regmap config even though it wouldn't work.
+ */
+ regmap_rtc = &s5m_rtc_regmap_config;
+ break;
+ case S2MPS14X:
+ regmap = &s2mps14_regmap_config;
+ regmap_rtc = &s2mps14_rtc_regmap_config;
break;
case S5M8763X:
regmap = &s5m8763_regmap_config;
+ regmap_rtc = &s5m_rtc_regmap_config;
break;
case S5M8767X:
regmap = &s5m8767_regmap_config;
+ regmap_rtc = &s5m_rtc_regmap_config;
break;
default:
regmap = &sec_regmap_config;
+ regmap_rtc = &s5m_rtc_regmap_config;
break;
}
@@ -252,10 +333,13 @@ static int sec_pmic_probe(struct i2c_client *i2c,
}
sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
+ if (!sec_pmic->rtc) {
+ dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n");
+ return -ENODEV;
+ }
i2c_set_clientdata(sec_pmic->rtc, sec_pmic);
- sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc,
- &sec_rtc_regmap_config);
+ sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc);
if (IS_ERR(sec_pmic->regmap_rtc)) {
ret = PTR_ERR(sec_pmic->regmap_rtc);
dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n",
@@ -283,10 +367,18 @@ static int sec_pmic_probe(struct i2c_client *i2c,
ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs,
ARRAY_SIZE(s5m8767_devs), NULL, 0, NULL);
break;
+ case S2MPA01:
+ ret = mfd_add_devices(sec_pmic->dev, -1, s2mpa01_devs,
+ ARRAY_SIZE(s2mpa01_devs), NULL, 0, NULL);
+ break;
case S2MPS11X:
ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs,
ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL);
break;
+ case S2MPS14X:
+ ret = mfd_add_devices(sec_pmic->dev, -1, s2mps14_devs,
+ ARRAY_SIZE(s2mps14_devs), NULL, 0, NULL);
+ break;
default:
/* If this happens the probe function is problem */
BUG();
@@ -315,6 +407,7 @@ static int sec_pmic_remove(struct i2c_client *i2c)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
static int sec_pmic_suspend(struct device *dev)
{
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
@@ -349,6 +442,7 @@ static int sec_pmic_resume(struct device *dev)
return 0;
}
+#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume);
diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c
index 4de494f51d40..64e7913aadc6 100644
--- a/drivers/mfd/sec-irq.c
+++ b/drivers/mfd/sec-irq.c
@@ -1,7 +1,7 @@
/*
* sec-irq.c
*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify it
@@ -19,6 +19,7 @@
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/irq.h>
#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s2mps14.h>
#include <linux/mfd/samsung/s5m8763.h>
#include <linux/mfd/samsung/s5m8767.h>
@@ -59,13 +60,13 @@ static const struct regmap_irq s2mps11_irqs[] = {
.reg_offset = 1,
.mask = S2MPS11_IRQ_RTC60S_MASK,
},
- [S2MPS11_IRQ_RTCA1] = {
+ [S2MPS11_IRQ_RTCA0] = {
.reg_offset = 1,
- .mask = S2MPS11_IRQ_RTCA1_MASK,
+ .mask = S2MPS11_IRQ_RTCA0_MASK,
},
- [S2MPS11_IRQ_RTCA2] = {
+ [S2MPS11_IRQ_RTCA1] = {
.reg_offset = 1,
- .mask = S2MPS11_IRQ_RTCA2_MASK,
+ .mask = S2MPS11_IRQ_RTCA1_MASK,
},
[S2MPS11_IRQ_SMPL] = {
.reg_offset = 1,
@@ -89,6 +90,76 @@ static const struct regmap_irq s2mps11_irqs[] = {
},
};
+static const struct regmap_irq s2mps14_irqs[] = {
+ [S2MPS14_IRQ_PWRONF] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_PWRONF_MASK,
+ },
+ [S2MPS14_IRQ_PWRONR] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_PWRONR_MASK,
+ },
+ [S2MPS14_IRQ_JIGONBF] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_JIGONBF_MASK,
+ },
+ [S2MPS14_IRQ_JIGONBR] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_JIGONBR_MASK,
+ },
+ [S2MPS14_IRQ_ACOKBF] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_ACOKBF_MASK,
+ },
+ [S2MPS14_IRQ_ACOKBR] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_ACOKBR_MASK,
+ },
+ [S2MPS14_IRQ_PWRON1S] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_PWRON1S_MASK,
+ },
+ [S2MPS14_IRQ_MRB] = {
+ .reg_offset = 0,
+ .mask = S2MPS11_IRQ_MRB_MASK,
+ },
+ [S2MPS14_IRQ_RTC60S] = {
+ .reg_offset = 1,
+ .mask = S2MPS11_IRQ_RTC60S_MASK,
+ },
+ [S2MPS14_IRQ_RTCA1] = {
+ .reg_offset = 1,
+ .mask = S2MPS11_IRQ_RTCA1_MASK,
+ },
+ [S2MPS14_IRQ_RTCA0] = {
+ .reg_offset = 1,
+ .mask = S2MPS11_IRQ_RTCA0_MASK,
+ },
+ [S2MPS14_IRQ_SMPL] = {
+ .reg_offset = 1,
+ .mask = S2MPS11_IRQ_SMPL_MASK,
+ },
+ [S2MPS14_IRQ_RTC1S] = {
+ .reg_offset = 1,
+ .mask = S2MPS11_IRQ_RTC1S_MASK,
+ },
+ [S2MPS14_IRQ_WTSR] = {
+ .reg_offset = 1,
+ .mask = S2MPS11_IRQ_WTSR_MASK,
+ },
+ [S2MPS14_IRQ_INT120C] = {
+ .reg_offset = 2,
+ .mask = S2MPS11_IRQ_INT120C_MASK,
+ },
+ [S2MPS14_IRQ_INT140C] = {
+ .reg_offset = 2,
+ .mask = S2MPS11_IRQ_INT140C_MASK,
+ },
+ [S2MPS14_IRQ_TSD] = {
+ .reg_offset = 2,
+ .mask = S2MPS14_IRQ_TSD_MASK,
+ },
+};
static const struct regmap_irq s5m8767_irqs[] = {
[S5M8767_IRQ_PWRR] = {
@@ -246,6 +317,16 @@ static const struct regmap_irq_chip s2mps11_irq_chip = {
.ack_base = S2MPS11_REG_INT1,
};
+static const struct regmap_irq_chip s2mps14_irq_chip = {
+ .name = "s2mps14",
+ .irqs = s2mps14_irqs,
+ .num_irqs = ARRAY_SIZE(s2mps14_irqs),
+ .num_regs = 3,
+ .status_base = S2MPS14_REG_INT1,
+ .mask_base = S2MPS14_REG_INT1M,
+ .ack_base = S2MPS14_REG_INT1,
+};
+
static const struct regmap_irq_chip s5m8767_irq_chip = {
.name = "s5m8767",
.irqs = s5m8767_irqs,
@@ -297,6 +378,12 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
sec_pmic->irq_base, &s2mps11_irq_chip,
&sec_pmic->irq_data);
break;
+ case S2MPS14X:
+ ret = regmap_add_irq_chip(sec_pmic->regmap_pmic, sec_pmic->irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ sec_pmic->irq_base, &s2mps14_irq_chip,
+ &sec_pmic->irq_data);
+ break;
default:
dev_err(sec_pmic->dev, "Unknown device type %d\n",
sec_pmic->device_type);
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
index 966cf65c5c36..3cc4c7084b92 100644
--- a/drivers/mfd/tps65217.c
+++ b/drivers/mfd/tps65217.c
@@ -158,7 +158,7 @@ static int tps65217_probe(struct i2c_client *client,
{
struct tps65217 *tps;
unsigned int version;
- unsigned int chip_id = ids->driver_data;
+ unsigned long chip_id = ids->driver_data;
const struct of_device_id *match;
bool status_off = false;
int ret;
@@ -170,7 +170,7 @@ static int tps65217_probe(struct i2c_client *client,
"Failed to find matching dt id\n");
return -EINVAL;
}
- chip_id = (unsigned int)(unsigned long)match->data;
+ chip_id = (unsigned long)match->data;
status_off = of_property_read_bool(client->dev.of_node,
"ti,pmic-shutdown-controller");
}
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index 1e9a4b2102f9..bffc584e4a43 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -80,8 +80,7 @@ static const struct reg_default wm5102_revb_patch[] = {
int wm5102_patch(struct arizona *arizona)
{
const struct reg_default *wm5102_patch;
- int ret = 0;
- int i, patch_size;
+ int patch_size;
switch (arizona->rev) {
case 0:
@@ -92,21 +91,9 @@ int wm5102_patch(struct arizona *arizona)
patch_size = ARRAY_SIZE(wm5102_revb_patch);
}
- regcache_cache_bypass(arizona->regmap, true);
-
- for (i = 0; i < patch_size; i++) {
- ret = regmap_write(arizona->regmap, wm5102_patch[i].reg,
- wm5102_patch[i].def);
- if (ret != 0) {
- dev_err(arizona->dev, "Failed to write %x = %x: %d\n",
- wm5102_patch[i].reg, wm5102_patch[i].def, ret);
- goto out;
- }
- }
-
-out:
- regcache_cache_bypass(arizona->regmap, false);
- return ret;
+ return regmap_multi_reg_write_bypassed(arizona->regmap,
+ wm5102_patch,
+ patch_size);
}
static const struct regmap_irq wm5102_aod_irqs[ARIZONA_NUM_IRQ] = {
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index ba04f1bc70eb..e6fab94e2c8a 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -636,7 +636,7 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
if (i2c->dev.of_node) {
of_id = of_match_device(wm8994_of_match, &i2c->dev);
if (of_id)
- wm8994->type = (int)of_id->data;
+ wm8994->type = (enum wm8994_type)of_id->data;
} else {
wm8994->type = id->driver_data;
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 6cb388e8fb7d..1cb74085e410 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -235,7 +235,7 @@ config SGI_XP
config CS5535_MFGPT
tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support"
- depends on PCI && X86 && MFD_CS5535
+ depends on MFD_CS5535
default n
help
This driver provides access to MFGPT functionality for other
@@ -526,4 +526,5 @@ source "drivers/misc/mei/Kconfig"
source "drivers/misc/vmw_vmci/Kconfig"
source "drivers/misc/mic/Kconfig"
source "drivers/misc/genwqe/Kconfig"
+source "drivers/misc/echo/Kconfig"
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 99b9424ce31d..7eb4b69580c0 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -54,3 +54,4 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
obj-$(CONFIG_SRAM) += sram.o
obj-y += mic/
obj-$(CONFIG_GENWQE) += genwqe/
+obj-$(CONFIG_ECHO) += echo/
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c
index d3eee113baeb..a43053daad0e 100644
--- a/drivers/misc/ad525x_dpot.c
+++ b/drivers/misc/ad525x_dpot.c
@@ -72,7 +72,6 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c
index 0c6e037153d2..c6cc3dc8ae1f 100644
--- a/drivers/misc/apds9802als.c
+++ b/drivers/misc/apds9802als.c
@@ -22,7 +22,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
index 5be808406edc..22de13727641 100644
--- a/drivers/misc/atmel-ssc.c
+++ b/drivers/misc/atmel-ssc.c
@@ -150,6 +150,12 @@ static int ssc_probe(struct platform_device *pdev)
return -ENODEV;
ssc->pdata = (struct atmel_ssc_platform_data *)plat_dat;
+ if (pdev->dev.of_node) {
+ struct device_node *np = pdev->dev.of_node;
+ ssc->clk_from_rk_pin =
+ of_property_read_bool(np, "atmel,clk-from-rk-pin");
+ }
+
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ssc->regs = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(ssc->regs))
diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c
index 820e53d0048f..9b313f7810f5 100644
--- a/drivers/misc/bmp085.c
+++ b/drivers/misc/bmp085.c
@@ -47,7 +47,6 @@
#include <linux/module.h>
#include <linux/device.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/of.h>
#include "bmp085.h"
diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c
index 9e2b985293fc..14d90eae605b 100644
--- a/drivers/misc/carma/carma-fpga.c
+++ b/drivers/misc/carma/carma-fpga.c
@@ -101,7 +101,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/poll.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kref.h>
#include <linux/io.h>
diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c
index 154b02e5094f..6a672f9ef522 100644
--- a/drivers/misc/ds1682.c
+++ b/drivers/misc/ds1682.c
@@ -32,7 +32,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/string.h>
#include <linux/list.h>
diff --git a/drivers/staging/echo/Kconfig b/drivers/misc/echo/Kconfig
index f1d41ea9cd48..f1d41ea9cd48 100644
--- a/drivers/staging/echo/Kconfig
+++ b/drivers/misc/echo/Kconfig
diff --git a/drivers/staging/echo/Makefile b/drivers/misc/echo/Makefile
index 7d4caac12a8d..7d4caac12a8d 100644
--- a/drivers/staging/echo/Makefile
+++ b/drivers/misc/echo/Makefile
diff --git a/drivers/staging/echo/echo.c b/drivers/misc/echo/echo.c
index 9597e9523cac..9597e9523cac 100644
--- a/drivers/staging/echo/echo.c
+++ b/drivers/misc/echo/echo.c
diff --git a/drivers/staging/echo/echo.h b/drivers/misc/echo/echo.h
index 9b08c63e6369..9b08c63e6369 100644
--- a/drivers/staging/echo/echo.h
+++ b/drivers/misc/echo/echo.h
diff --git a/drivers/staging/echo/fir.h b/drivers/misc/echo/fir.h
index 7b9fabf1fea5..7b9fabf1fea5 100644
--- a/drivers/staging/echo/fir.h
+++ b/drivers/misc/echo/fir.h
diff --git a/drivers/staging/echo/oslec.h b/drivers/misc/echo/oslec.h
index f4175360ce27..f4175360ce27 100644
--- a/drivers/staging/echo/oslec.h
+++ b/drivers/misc/echo/oslec.h
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 4f3bca1003a1..634f72929e12 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -10,7 +10,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
diff --git a/drivers/misc/eeprom/eeprom.c b/drivers/misc/eeprom/eeprom.c
index f0fa4e8ca124..33f8673d23a6 100644
--- a/drivers/misc/eeprom/eeprom.c
+++ b/drivers/misc/eeprom/eeprom.c
@@ -17,7 +17,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index 78e55b501c94..9ebeacdb8ec4 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -11,7 +11,6 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c
index e36157d5d3ab..580ff9df5529 100644
--- a/drivers/misc/eeprom/max6875.c
+++ b/drivers/misc/eeprom/max6875.c
@@ -27,7 +27,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c
index 9c34e5704304..3f2b625b2032 100644
--- a/drivers/misc/eeprom/sunxi_sid.c
+++ b/drivers/misc/eeprom/sunxi_sid.c
@@ -21,7 +21,6 @@
#include <linux/err.h>
#include <linux/export.h>
#include <linux/fs.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
@@ -96,7 +95,7 @@ static int sunxi_sid_remove(struct platform_device *pdev)
}
static const struct of_device_id sunxi_sid_of_match[] = {
- { .compatible = "allwinner,sun4i-sid", .data = (void *)16},
+ { .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
{/* sentinel */},
};
diff --git a/drivers/misc/genwqe/card_debugfs.c b/drivers/misc/genwqe/card_debugfs.c
index 3bfdc07a7248..50d2096ea1c7 100644
--- a/drivers/misc/genwqe/card_debugfs.c
+++ b/drivers/misc/genwqe/card_debugfs.c
@@ -26,7 +26,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
diff --git a/drivers/misc/hmc6352.c b/drivers/misc/hmc6352.c
index 170bd3daf336..90520d76633f 100644
--- a/drivers/misc/hmc6352.c
+++ b/drivers/misc/hmc6352.c
@@ -22,7 +22,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c
index e3183f26216b..12c30b486b27 100644
--- a/drivers/misc/isl29003.c
+++ b/drivers/misc/isl29003.c
@@ -26,7 +26,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c
index b7f84dacf822..4a9c50a43afb 100644
--- a/drivers/misc/isl29020.c
+++ b/drivers/misc/isl29020.c
@@ -23,7 +23,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
diff --git a/drivers/misc/lattice-ecp3-config.c b/drivers/misc/lattice-ecp3-config.c
index 61fbe6acabef..0a1565e63c71 100644
--- a/drivers/misc/lattice-ecp3-config.c
+++ b/drivers/misc/lattice-ecp3-config.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/spi/spi.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
index 036effe9a795..3ef4627f9cb1 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -23,7 +23,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/types.h>
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
index 7c97550240f1..d324f8a97b88 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
@@ -26,7 +26,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c
index 9aa2bd2a71ae..bd06d0cfac45 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/err.h>
#include <linux/input.h>
#include <linux/interrupt.h>
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index 49c7a23f02fc..d66a2f24f6b3 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -30,6 +30,7 @@
*
* See Documentation/fault-injection/provoke-crashes.txt for instructions
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -45,6 +46,7 @@
#include <linux/debugfs.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
+#include <asm/cacheflush.h>
#ifdef CONFIG_IDE
#include <linux/ide.h>
@@ -101,6 +103,7 @@ enum ctype {
CT_EXEC_USERSPACE,
CT_ACCESS_USERSPACE,
CT_WRITE_RO,
+ CT_WRITE_KERN,
};
static char* cp_name[] = {
@@ -137,6 +140,7 @@ static char* cp_type[] = {
"EXEC_USERSPACE",
"ACCESS_USERSPACE",
"WRITE_RO",
+ "WRITE_KERN",
};
static struct jprobe lkdtm;
@@ -316,6 +320,13 @@ static void do_nothing(void)
return;
}
+/* Must immediately follow do_nothing for size calculuations to work out. */
+static void do_overwritten(void)
+{
+ pr_info("do_overwritten wasn't overwritten!\n");
+ return;
+}
+
static noinline void corrupt_stack(void)
{
/* Use default char array length that triggers stack protection. */
@@ -328,7 +339,12 @@ static void execute_location(void *dst)
{
void (*func)(void) = dst;
+ pr_info("attempting ok execution at %p\n", do_nothing);
+ do_nothing();
+
memcpy(dst, do_nothing, EXEC_SIZE);
+ flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE);
+ pr_info("attempting bad execution at %p\n", func);
func();
}
@@ -337,8 +353,13 @@ static void execute_user_location(void *dst)
/* Intentionally crossing kernel/user memory boundary. */
void (*func)(void) = dst;
+ pr_info("attempting ok execution at %p\n", do_nothing);
+ do_nothing();
+
if (copy_to_user((void __user *)dst, do_nothing, EXEC_SIZE))
return;
+ flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE);
+ pr_info("attempting bad execution at %p\n", func);
func();
}
@@ -463,8 +484,12 @@ static void lkdtm_do_action(enum ctype which)
}
ptr = (unsigned long *)user_addr;
+
+ pr_info("attempting bad read at %p\n", ptr);
tmp = *ptr;
tmp += 0xc0dec0de;
+
+ pr_info("attempting bad write at %p\n", ptr);
*ptr = tmp;
vm_munmap(user_addr, PAGE_SIZE);
@@ -475,10 +500,28 @@ static void lkdtm_do_action(enum ctype which)
unsigned long *ptr;
ptr = (unsigned long *)&rodata;
+
+ pr_info("attempting bad write at %p\n", ptr);
*ptr ^= 0xabcd1234;
break;
}
+ case CT_WRITE_KERN: {
+ size_t size;
+ unsigned char *ptr;
+
+ size = (unsigned long)do_overwritten -
+ (unsigned long)do_nothing;
+ ptr = (unsigned char *)do_overwritten;
+
+ pr_info("attempting bad %zu byte write at %p\n", size, ptr);
+ memcpy(ptr, (unsigned char *)do_nothing, size);
+ flush_icache_range((unsigned long)ptr,
+ (unsigned long)(ptr + size));
+
+ do_overwritten();
+ break;
+ }
case CT_NONE:
default:
break;
@@ -493,8 +536,8 @@ static void lkdtm_handler(void)
spin_lock_irqsave(&count_lock, flags);
count--;
- printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds\n",
- cp_name_to_str(cpoint), cp_type_to_str(cptype), count);
+ pr_info("Crash point %s of type %s hit, trigger in %d rounds\n",
+ cp_name_to_str(cpoint), cp_type_to_str(cptype), count);
if (count == 0) {
do_it = true;
@@ -551,18 +594,18 @@ static int lkdtm_register_cpoint(enum cname which)
lkdtm.kp.symbol_name = "generic_ide_ioctl";
lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl;
#else
- printk(KERN_INFO "lkdtm: Crash point not available\n");
+ pr_info("Crash point not available\n");
return -EINVAL;
#endif
break;
default:
- printk(KERN_INFO "lkdtm: Invalid Crash Point\n");
+ pr_info("Invalid Crash Point\n");
return -EINVAL;
}
cpoint = which;
if ((ret = register_jprobe(&lkdtm)) < 0) {
- printk(KERN_INFO "lkdtm: Couldn't register jprobe\n");
+ pr_info("Couldn't register jprobe\n");
cpoint = CN_INVALID;
}
@@ -709,8 +752,7 @@ static ssize_t direct_entry(struct file *f, const char __user *user_buf,
if (type == CT_NONE)
return -EINVAL;
- printk(KERN_INFO "lkdtm: Performing direct entry %s\n",
- cp_type_to_str(type));
+ pr_info("Performing direct entry %s\n", cp_type_to_str(type));
lkdtm_do_action(type);
*off += count;
@@ -772,7 +814,7 @@ static int __init lkdtm_module_init(void)
/* Register debugfs interface */
lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL);
if (!lkdtm_debugfs_root) {
- printk(KERN_ERR "lkdtm: creating root dir failed\n");
+ pr_err("creating root dir failed\n");
return -ENODEV;
}
@@ -787,28 +829,26 @@ static int __init lkdtm_module_init(void)
de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root,
NULL, &cur->fops);
if (de == NULL) {
- printk(KERN_ERR "lkdtm: could not create %s\n",
- cur->name);
+ pr_err("could not create %s\n", cur->name);
goto out_err;
}
}
if (lkdtm_parse_commandline() == -EINVAL) {
- printk(KERN_INFO "lkdtm: Invalid command\n");
+ pr_info("Invalid command\n");
goto out_err;
}
if (cpoint != CN_INVALID && cptype != CT_NONE) {
ret = lkdtm_register_cpoint(cpoint);
if (ret < 0) {
- printk(KERN_INFO "lkdtm: Invalid crash point %d\n",
- cpoint);
+ pr_info("Invalid crash point %d\n", cpoint);
goto out_err;
}
- printk(KERN_INFO "lkdtm: Crash point %s of type %s registered\n",
- cpoint_name, cpoint_type);
+ pr_info("Crash point %s of type %s registered\n",
+ cpoint_name, cpoint_type);
} else {
- printk(KERN_INFO "lkdtm: No crash points registered, enable through debugfs\n");
+ pr_info("No crash points registered, enable through debugfs\n");
}
return 0;
@@ -823,7 +863,7 @@ static void __exit lkdtm_module_exit(void)
debugfs_remove_recursive(lkdtm_debugfs_root);
unregister_jprobe(&lkdtm);
- printk(KERN_INFO "lkdtm: Crash point unregistered\n");
+ pr_info("Crash point unregistered\n");
}
module_init(lkdtm_module_init);
diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
index c76fa31e9bf6..d23384dde73b 100644
--- a/drivers/misc/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
@@ -34,3 +34,12 @@ config INTEL_MEI_ME
82Q33 Express
82X38/X48 Express
+config INTEL_MEI_TXE
+ tristate "Intel Trusted Execution Environment with ME Interface"
+ select INTEL_MEI
+ depends on X86 && PCI && WATCHDOG_CORE
+ help
+ MEI Support for Trusted Execution Environment device on Intel SoCs
+
+ Supported SoCs:
+ Intel Bay Trail
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 08698a466268..8ebc6cda1373 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -1,6 +1,6 @@
#
# Makefile - Intel Management Engine Interface (Intel MEI) Linux driver
-# Copyright (c) 2010-2011, Intel Corporation.
+# Copyright (c) 2010-2014, Intel Corporation.
#
obj-$(CONFIG_INTEL_MEI) += mei.o
mei-objs := init.o
@@ -17,3 +17,7 @@ mei-$(CONFIG_DEBUG_FS) += debugfs.o
obj-$(CONFIG_INTEL_MEI_ME) += mei-me.o
mei-me-objs := pci-me.o
mei-me-objs += hw-me.o
+
+obj-$(CONFIG_INTEL_MEI_TXE) += mei-txe.o
+mei-txe-objs := pci-txe.o
+mei-txe-objs += hw-txe.o
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 2fad84432829..b8deb3455480 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -21,7 +21,6 @@
#include <linux/fcntl.h>
#include <linux/aio.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/list.h>
@@ -35,7 +34,6 @@
#include "mei_dev.h"
#include "hbm.h"
-#include "hw-me.h"
#include "client.h"
const uuid_le mei_amthif_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
@@ -79,10 +77,9 @@ int mei_amthif_host_init(struct mei_device *dev)
i = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
if (i < 0) {
- ret = i;
dev_info(&dev->pdev->dev,
- "amthif: failed to find the client %d\n", ret);
- return ret;
+ "amthif: failed to find the client %d\n", i);
+ return -ENOTTY;
}
cl->me_client_id = dev->me_clients[i].client_id;
@@ -116,14 +113,11 @@ int mei_amthif_host_init(struct mei_device *dev)
cl->state = MEI_FILE_CONNECTING;
- if (mei_hbm_cl_connect_req(dev, cl)) {
- dev_dbg(&dev->pdev->dev, "amthif: Failed to connect to ME client\n");
- cl->state = MEI_FILE_DISCONNECTED;
- cl->host_client_id = 0;
- } else {
- cl->timer_count = MEI_CONNECT_TIMEOUT;
- }
- return 0;
+ ret = mei_cl_connect(cl, NULL);
+
+ dev->iamthif_state = MEI_IAMTHIF_IDLE;
+
+ return ret;
}
/**
@@ -137,14 +131,12 @@ int mei_amthif_host_init(struct mei_device *dev)
struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
struct file *file)
{
- struct mei_cl_cb *pos = NULL;
- struct mei_cl_cb *next = NULL;
+ struct mei_cl_cb *cb;
- list_for_each_entry_safe(pos, next,
- &dev->amthif_rd_complete_list.list, list) {
- if (pos->cl && pos->cl == &dev->iamthif_cl &&
- pos->file_object == file)
- return pos;
+ list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list) {
+ if (cb->cl && cb->cl == &dev->iamthif_cl &&
+ cb->file_object == file)
+ return cb;
}
return NULL;
}
@@ -180,14 +172,13 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
/* Only possible if we are in timeout */
if (!cl || cl != &dev->iamthif_cl) {
dev_dbg(&dev->pdev->dev, "bad file ext.\n");
- return -ETIMEDOUT;
+ return -ETIME;
}
i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
-
if (i < 0) {
dev_dbg(&dev->pdev->dev, "amthif client not found.\n");
- return -ENODEV;
+ return -ENOTTY;
}
dev_dbg(&dev->pdev->dev, "checking amthif data\n");
cb = mei_amthif_find_read_list_entry(dev, file);
@@ -228,7 +219,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
dev_dbg(&dev->pdev->dev, "amthif Time out\n");
/* 15 sec for the message has expired */
list_del(&cb->list);
- rets = -ETIMEDOUT;
+ rets = -ETIME;
goto free;
}
}
@@ -253,9 +244,10 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
* the buf_idx may point beyond */
length = min_t(size_t, length, (cb->buf_idx - *offset));
- if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length))
+ if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
+ dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
- else {
+ } else {
rets = length;
if ((*offset + length) < cb->buf_idx) {
*offset += length;
@@ -302,9 +294,8 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
if (ret < 0)
return ret;
- if (ret && dev->hbuf_is_ready) {
+ if (ret && mei_hbuf_acquire(dev)) {
ret = 0;
- dev->hbuf_is_ready = false;
if (cb->request_buffer.size > mei_hbuf_max_len(dev)) {
mei_hdr.length = mei_hbuf_max_len(dev);
mei_hdr.msg_complete = 0;
@@ -336,10 +327,6 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
list_add_tail(&cb->list, &dev->write_list.list);
}
} else {
- if (!dev->hbuf_is_ready)
- dev_dbg(&dev->pdev->dev, "host buffer is not empty");
-
- dev_dbg(&dev->pdev->dev, "No flow control credentials, so add iamthif cb to write list.\n");
list_add_tail(&cb->list, &dev->write_list.list);
}
return 0;
@@ -365,7 +352,7 @@ int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb)
if (ret)
return ret;
- cb->fop_type = MEI_FOP_IOCTL;
+ cb->fop_type = MEI_FOP_WRITE;
if (!list_empty(&dev->amthif_cmd_list.list) ||
dev->iamthif_state != MEI_IAMTHIF_IDLE) {
@@ -447,23 +434,23 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
/**
- * mei_amthif_irq_write_completed - processes completed iamthif operation.
+ * mei_amthif_irq_write - write iamthif command in irq thread context.
*
* @dev: the device structure.
- * @slots: free slots.
* @cb_pos: callback block.
* @cl: private data of the file object.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
*/
-int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list)
+int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list)
{
struct mei_device *dev = cl->dev;
struct mei_msg_hdr mei_hdr;
size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index;
u32 msg_slots = mei_data2slots(len);
+ int slots;
int rets;
rets = mei_cl_flow_ctrl_creds(cl);
@@ -480,13 +467,15 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
mei_hdr.reserved = 0;
mei_hdr.internal = 0;
- if (*slots >= msg_slots) {
+ slots = mei_hbuf_empty_slots(dev);
+
+ if (slots >= msg_slots) {
mei_hdr.length = len;
mei_hdr.msg_complete = 1;
/* Split the message only if we can write the whole host buffer */
- } else if (*slots == dev->hbuf_depth) {
- msg_slots = *slots;
- len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
+ } else if (slots == dev->hbuf_depth) {
+ msg_slots = slots;
+ len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
mei_hdr.length = len;
mei_hdr.msg_complete = 0;
} else {
@@ -496,7 +485,6 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr));
- *slots -= msg_slots;
rets = mei_write_message(dev, &mei_hdr,
dev->iamthif_msg_buf + dev->iamthif_msg_buf_index);
if (rets) {
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 4bc7d620d695..ddc5ac92a200 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -26,7 +26,6 @@
#include <linux/mei_cl_bus.h>
#include "mei_dev.h"
-#include "hw-me.h"
#include "client.h"
#define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
@@ -145,9 +144,9 @@ static struct device_type mei_cl_device_type = {
static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
uuid_le uuid)
{
- struct mei_cl *cl, *next;
+ struct mei_cl *cl;
- list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
+ list_for_each_entry(cl, &dev->device_list, device_link) {
if (!uuid_le_cmp(uuid, cl->device_uuid))
return cl;
}
@@ -524,6 +523,22 @@ void mei_cl_bus_rx_event(struct mei_cl *cl)
schedule_work(&device->event_work);
}
+void mei_cl_bus_remove_devices(struct mei_device *dev)
+{
+ struct mei_cl *cl, *next;
+
+ mutex_lock(&dev->device_lock);
+ list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
+ if (cl->device)
+ mei_cl_remove_device(cl->device);
+
+ list_del(&cl->device_link);
+ mei_cl_unlink(cl);
+ kfree(cl);
+ }
+ mutex_unlock(&dev->device_lock);
+}
+
int __init mei_cl_bus_init(void)
{
return bus_register(&mei_cl_bus_type);
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 9b809cfc2899..8c078b808cd3 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -29,20 +29,21 @@
* mei_me_cl_by_uuid - locate index of me client
*
* @dev: mei device
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
* returns me client index or -ENOENT if not found
*/
int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
{
- int i, res = -ENOENT;
+ int i;
for (i = 0; i < dev->me_clients_num; ++i)
if (uuid_le_cmp(*uuid,
- dev->me_clients[i].props.protocol_name) == 0) {
- res = i;
- break;
- }
+ dev->me_clients[i].props.protocol_name) == 0)
+ return i;
- return res;
+ return -ENOENT;
}
@@ -60,37 +61,79 @@ int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
{
int i;
+
for (i = 0; i < dev->me_clients_num; i++)
if (dev->me_clients[i].client_id == client_id)
- break;
- if (WARN_ON(dev->me_clients[i].client_id != client_id))
- return -ENOENT;
-
- if (i == dev->me_clients_num)
- return -ENOENT;
+ return i;
- return i;
+ return -ENOENT;
}
/**
- * mei_io_list_flush - removes list entry belonging to cl.
+ * mei_cl_cmp_id - tells if the clients are the same
*
- * @list: An instance of our list structure
- * @cl: host client
+ * @cl1: host client 1
+ * @cl2: host client 2
+ *
+ * returns true - if the clients has same host and me ids
+ * false - otherwise
*/
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
+static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
+ const struct mei_cl *cl2)
+{
+ return cl1 && cl2 &&
+ (cl1->host_client_id == cl2->host_client_id) &&
+ (cl1->me_client_id == cl2->me_client_id);
+}
+
+/**
+ * mei_io_list_flush - removes cbs belonging to cl.
+ *
+ * @list: an instance of our list structure
+ * @cl: host client, can be NULL for flushing the whole list
+ * @free: whether to free the cbs
+ */
+static void __mei_io_list_flush(struct mei_cl_cb *list,
+ struct mei_cl *cl, bool free)
{
struct mei_cl_cb *cb;
struct mei_cl_cb *next;
+ /* enable removing everything if no cl is specified */
list_for_each_entry_safe(cb, next, &list->list, list) {
- if (cb->cl && mei_cl_cmp_id(cl, cb->cl))
+ if (!cl || (cb->cl && mei_cl_cmp_id(cl, cb->cl))) {
list_del(&cb->list);
+ if (free)
+ mei_io_cb_free(cb);
+ }
}
}
/**
+ * mei_io_list_flush - removes list entry belonging to cl.
+ *
+ * @list: An instance of our list structure
+ * @cl: host client
+ */
+static inline void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
+{
+ __mei_io_list_flush(list, cl, false);
+}
+
+
+/**
+ * mei_io_list_free - removes cb belonging to cl and free them
+ *
+ * @list: An instance of our list structure
+ * @cl: host client
+ */
+static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
+{
+ __mei_io_list_flush(list, cl, true);
+}
+
+/**
* mei_io_cb_free - free mei_cb_private related memory
*
* @cb: mei callback struct
@@ -196,8 +239,8 @@ int mei_cl_flush_queues(struct mei_cl *cl)
cl_dbg(dev, cl, "remove list entry belonging to cl\n");
mei_io_list_flush(&cl->dev->read_list, cl);
- mei_io_list_flush(&cl->dev->write_list, cl);
- mei_io_list_flush(&cl->dev->write_waiting_list, cl);
+ mei_io_list_free(&cl->dev->write_list, cl);
+ mei_io_list_free(&cl->dev->write_waiting_list, cl);
mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
@@ -254,10 +297,9 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
{
struct mei_device *dev = cl->dev;
- struct mei_cl_cb *cb = NULL;
- struct mei_cl_cb *next = NULL;
+ struct mei_cl_cb *cb;
- list_for_each_entry_safe(cb, next, &dev->read_list.list, list)
+ list_for_each_entry(cb, &dev->read_list.list, list)
if (mei_cl_cmp_id(cl, cb->cl))
return cb;
return NULL;
@@ -375,6 +417,23 @@ void mei_host_client_init(struct work_struct *work)
mutex_unlock(&dev->device_lock);
}
+/**
+ * mei_hbuf_acquire: try to acquire host buffer
+ *
+ * @dev: the device structure
+ * returns true if host buffer was acquired
+ */
+bool mei_hbuf_acquire(struct mei_device *dev)
+{
+ if (!dev->hbuf_is_ready) {
+ dev_dbg(&dev->pdev->dev, "hbuf is not ready\n");
+ return false;
+ }
+
+ dev->hbuf_is_ready = false;
+
+ return true;
+}
/**
* mei_cl_disconnect - disconnect host client from the me one
@@ -406,8 +465,7 @@ int mei_cl_disconnect(struct mei_cl *cl)
return -ENOMEM;
cb->fop_type = MEI_FOP_CLOSE;
- if (dev->hbuf_is_ready) {
- dev->hbuf_is_ready = false;
+ if (mei_hbuf_acquire(dev)) {
if (mei_hbm_cl_disconnect_req(dev, cl)) {
rets = -ENODEV;
cl_err(dev, cl, "failed to disconnect.\n");
@@ -461,17 +519,17 @@ free:
bool mei_cl_is_other_connecting(struct mei_cl *cl)
{
struct mei_device *dev;
- struct mei_cl *pos;
- struct mei_cl *next;
+ struct mei_cl *ocl; /* the other client */
if (WARN_ON(!cl || !cl->dev))
return false;
dev = cl->dev;
- list_for_each_entry_safe(pos, next, &dev->file_list, link) {
- if ((pos->state == MEI_FILE_CONNECTING) &&
- (pos != cl) && cl->me_client_id == pos->me_client_id)
+ list_for_each_entry(ocl, &dev->file_list, link) {
+ if (ocl->state == MEI_FILE_CONNECTING &&
+ ocl != cl &&
+ cl->me_client_id == ocl->me_client_id)
return true;
}
@@ -505,11 +563,10 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
goto out;
}
- cb->fop_type = MEI_FOP_IOCTL;
-
- if (dev->hbuf_is_ready && !mei_cl_is_other_connecting(cl)) {
- dev->hbuf_is_ready = false;
+ cb->fop_type = MEI_FOP_CONNECT;
+ /* run hbuf acquire last so we don't have to undo */
+ if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
if (mei_hbm_cl_connect_req(dev, cl)) {
rets = -ENODEV;
goto out;
@@ -521,18 +578,19 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
}
mutex_unlock(&dev->device_lock);
- rets = wait_event_timeout(dev->wait_recvd_msg,
- (cl->state == MEI_FILE_CONNECTED ||
- cl->state == MEI_FILE_DISCONNECTED),
- mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
+ wait_event_timeout(dev->wait_recvd_msg,
+ (cl->state == MEI_FILE_CONNECTED ||
+ cl->state == MEI_FILE_DISCONNECTED),
+ mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
mutex_lock(&dev->device_lock);
if (cl->state != MEI_FILE_CONNECTED) {
- rets = -EFAULT;
+ /* something went really wrong */
+ if (!cl->status)
+ cl->status = -EFAULT;
mei_io_list_flush(&dev->ctrl_rd_list, cl);
mei_io_list_flush(&dev->ctrl_wr_list, cl);
- goto out;
}
rets = cl->status;
@@ -554,7 +612,8 @@ out:
int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
{
struct mei_device *dev;
- int i;
+ struct mei_me_client *me_cl;
+ int id;
if (WARN_ON(!cl || !cl->dev))
return -EINVAL;
@@ -567,19 +626,19 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
if (cl->mei_flow_ctrl_creds > 0)
return 1;
- for (i = 0; i < dev->me_clients_num; i++) {
- struct mei_me_client *me_cl = &dev->me_clients[i];
- if (me_cl->client_id == cl->me_client_id) {
- if (me_cl->mei_flow_ctrl_creds) {
- if (WARN_ON(me_cl->props.single_recv_buf == 0))
- return -EINVAL;
- return 1;
- } else {
- return 0;
- }
- }
+ id = mei_me_cl_by_id(dev, cl->me_client_id);
+ if (id < 0) {
+ cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
+ return id;
}
- return -ENOENT;
+
+ me_cl = &dev->me_clients[id];
+ if (me_cl->mei_flow_ctrl_creds) {
+ if (WARN_ON(me_cl->props.single_recv_buf == 0))
+ return -EINVAL;
+ return 1;
+ }
+ return 0;
}
/**
@@ -595,32 +654,31 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
{
struct mei_device *dev;
- int i;
+ struct mei_me_client *me_cl;
+ int id;
if (WARN_ON(!cl || !cl->dev))
return -EINVAL;
dev = cl->dev;
- if (!dev->me_clients_num)
- return -ENOENT;
+ id = mei_me_cl_by_id(dev, cl->me_client_id);
+ if (id < 0) {
+ cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
+ return id;
+ }
- for (i = 0; i < dev->me_clients_num; i++) {
- struct mei_me_client *me_cl = &dev->me_clients[i];
- if (me_cl->client_id == cl->me_client_id) {
- if (me_cl->props.single_recv_buf != 0) {
- if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
- return -EINVAL;
- dev->me_clients[i].mei_flow_ctrl_creds--;
- } else {
- if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
- return -EINVAL;
- cl->mei_flow_ctrl_creds--;
- }
- return 0;
- }
+ me_cl = &dev->me_clients[id];
+ if (me_cl->props.single_recv_buf != 0) {
+ if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
+ return -EINVAL;
+ me_cl->mei_flow_ctrl_creds--;
+ } else {
+ if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
+ return -EINVAL;
+ cl->mei_flow_ctrl_creds--;
}
- return -ENOENT;
+ return 0;
}
/**
@@ -652,7 +710,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
i = mei_me_cl_by_id(dev, cl->me_client_id);
if (i < 0) {
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
- return -ENODEV;
+ return -ENOTTY;
}
cb = mei_io_cb_init(cl, NULL);
@@ -666,9 +724,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
goto err;
cb->fop_type = MEI_FOP_READ;
- cl->read_cb = cb;
- if (dev->hbuf_is_ready) {
- dev->hbuf_is_ready = false;
+ if (mei_hbuf_acquire(dev)) {
if (mei_hbm_cl_flow_control_req(dev, cl)) {
cl_err(dev, cl, "flow control send failed\n");
rets = -ENODEV;
@@ -678,6 +734,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
} else {
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
}
+
+ cl->read_cb = cb;
+
return rets;
err:
mei_io_cb_free(cb);
@@ -685,27 +744,26 @@ err:
}
/**
- * mei_cl_irq_write_complete - write a message to device
+ * mei_cl_irq_write - write a message to device
* from the interrupt thread context
*
* @cl: client
* @cb: callback block.
- * @slots: free slots.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise error.
*/
-int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list)
+int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list)
{
struct mei_device *dev;
struct mei_msg_data *buf;
struct mei_msg_hdr mei_hdr;
size_t len;
u32 msg_slots;
+ int slots;
int rets;
-
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
@@ -722,6 +780,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
return 0;
}
+ slots = mei_hbuf_empty_slots(dev);
len = buf->size - cb->buf_idx;
msg_slots = mei_data2slots(len);
@@ -730,13 +789,13 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
mei_hdr.reserved = 0;
mei_hdr.internal = cb->internal;
- if (*slots >= msg_slots) {
+ if (slots >= msg_slots) {
mei_hdr.length = len;
mei_hdr.msg_complete = 1;
/* Split the message only if we can write the whole host buffer */
- } else if (*slots == dev->hbuf_depth) {
- msg_slots = *slots;
- len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
+ } else if (slots == dev->hbuf_depth) {
+ msg_slots = slots;
+ len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
mei_hdr.length = len;
mei_hdr.msg_complete = 0;
} else {
@@ -747,7 +806,6 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
cb->request_buffer.size, cb->buf_idx);
- *slots -= msg_slots;
rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
if (rets) {
cl->status = rets;
@@ -800,21 +858,29 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
cb->fop_type = MEI_FOP_WRITE;
+ cb->buf_idx = 0;
+ cl->writing_state = MEI_IDLE;
+
+ mei_hdr.host_addr = cl->host_client_id;
+ mei_hdr.me_addr = cl->me_client_id;
+ mei_hdr.reserved = 0;
+ mei_hdr.msg_complete = 0;
+ mei_hdr.internal = cb->internal;
rets = mei_cl_flow_ctrl_creds(cl);
if (rets < 0)
goto err;
- /* Host buffer is not ready, we queue the request */
- if (rets == 0 || !dev->hbuf_is_ready) {
- cb->buf_idx = 0;
- /* unseting complete will enqueue the cb for write */
- mei_hdr.msg_complete = 0;
+ if (rets == 0) {
+ cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
+ rets = buf->size;
+ goto out;
+ }
+ if (!mei_hbuf_acquire(dev)) {
+ cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
rets = buf->size;
goto out;
}
-
- dev->hbuf_is_ready = false;
/* Check for a maximum length */
if (buf->size > mei_hbuf_max_len(dev)) {
@@ -825,12 +891,6 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
mei_hdr.msg_complete = 1;
}
- mei_hdr.host_addr = cl->host_client_id;
- mei_hdr.me_addr = cl->me_client_id;
- mei_hdr.reserved = 0;
- mei_hdr.internal = cb->internal;
-
-
rets = mei_write_message(dev, &mei_hdr, buf->data);
if (rets)
goto err;
@@ -838,13 +898,12 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
cl->writing_state = MEI_WRITING;
cb->buf_idx = mei_hdr.length;
- rets = buf->size;
out:
if (mei_hdr.msg_complete) {
- if (mei_cl_flow_ctrl_reduce(cl)) {
- rets = -ENODEV;
+ rets = mei_cl_flow_ctrl_reduce(cl);
+ if (rets < 0)
goto err;
- }
+
list_add_tail(&cb->list, &dev->write_waiting_list.list);
} else {
list_add_tail(&cb->list, &dev->write_list.list);
@@ -854,15 +913,18 @@ out:
if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
mutex_unlock(&dev->device_lock);
- if (wait_event_interruptible(cl->tx_wait,
- cl->writing_state == MEI_WRITE_COMPLETE)) {
- if (signal_pending(current))
- rets = -EINTR;
- else
- rets = -ERESTARTSYS;
- }
+ rets = wait_event_interruptible(cl->tx_wait,
+ cl->writing_state == MEI_WRITE_COMPLETE);
mutex_lock(&dev->device_lock);
+ /* wait_event_interruptible returns -ERESTARTSYS */
+ if (rets) {
+ if (signal_pending(current))
+ rets = -EINTR;
+ goto err;
+ }
}
+
+ rets = buf->size;
err:
return rets;
}
@@ -903,9 +965,9 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
void mei_cl_all_disconnect(struct mei_device *dev)
{
- struct mei_cl *cl, *next;
+ struct mei_cl *cl;
- list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+ list_for_each_entry(cl, &dev->file_list, link) {
cl->state = MEI_FILE_DISCONNECTED;
cl->mei_flow_ctrl_creds = 0;
cl->timer_count = 0;
@@ -920,8 +982,8 @@ void mei_cl_all_disconnect(struct mei_device *dev)
*/
void mei_cl_all_wakeup(struct mei_device *dev)
{
- struct mei_cl *cl, *next;
- list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+ struct mei_cl *cl;
+ list_for_each_entry(cl, &dev->file_list, link) {
if (waitqueue_active(&cl->rx_wait)) {
cl_dbg(dev, cl, "Waking up reading client!\n");
wake_up_interruptible(&cl->rx_wait);
@@ -940,20 +1002,8 @@ void mei_cl_all_wakeup(struct mei_device *dev)
*/
void mei_cl_all_write_clear(struct mei_device *dev)
{
- struct mei_cl_cb *cb, *next;
- struct list_head *list;
-
- list = &dev->write_list.list;
- list_for_each_entry_safe(cb, next, list, list) {
- list_del(&cb->list);
- mei_io_cb_free(cb);
- }
-
- list = &dev->write_waiting_list.list;
- list_for_each_entry_safe(cb, next, list, list) {
- list_del(&cb->list);
- mei_io_cb_free(cb);
- }
+ mei_io_list_free(&dev->write_list, NULL);
+ mei_io_list_free(&dev->write_waiting_list, NULL);
}
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index c8396e582f1c..96d5de0389f9 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -45,8 +45,6 @@ static inline void mei_io_list_init(struct mei_cl_cb *list)
{
INIT_LIST_HEAD(&list->list);
}
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl);
-
/*
* MEI Host Client Functions
*/
@@ -61,22 +59,6 @@ int mei_cl_unlink(struct mei_cl *cl);
int mei_cl_flush_queues(struct mei_cl *cl);
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl);
-/**
- * mei_cl_cmp_id - tells if file private data have same id
- *
- * @fe1: private data of 1. file object
- * @fe2: private data of 2. file object
- *
- * returns true - if ids are the same and not NULL
- */
-static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
- const struct mei_cl *cl2)
-{
- return cl1 && cl2 &&
- (cl1->host_client_id == cl2->host_client_id) &&
- (cl1->me_client_id == cl2->me_client_id);
-}
-
int mei_cl_flow_ctrl_creds(struct mei_cl *cl);
@@ -86,15 +68,15 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
*/
static inline bool mei_cl_is_connected(struct mei_cl *cl)
{
- return (cl->dev &&
+ return cl->dev &&
cl->dev->dev_state == MEI_DEV_ENABLED &&
- cl->state == MEI_FILE_CONNECTED);
+ cl->state == MEI_FILE_CONNECTED;
}
static inline bool mei_cl_is_transitioning(struct mei_cl *cl)
{
- return (MEI_FILE_INITIALIZING == cl->state ||
+ return MEI_FILE_INITIALIZING == cl->state ||
MEI_FILE_DISCONNECTED == cl->state ||
- MEI_FILE_DISCONNECTING == cl->state);
+ MEI_FILE_DISCONNECTING == cl->state;
}
bool mei_cl_is_other_connecting(struct mei_cl *cl);
@@ -102,8 +84,8 @@ int mei_cl_disconnect(struct mei_cl *cl);
int mei_cl_connect(struct mei_cl *cl, struct file *file);
int mei_cl_read_start(struct mei_cl *cl, size_t length);
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking);
-int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list);
+int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list);
void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index a3ae154444b2..ced5b777c70f 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -75,6 +75,54 @@ static const struct file_operations mei_dbgfs_fops_meclients = {
.llseek = generic_file_llseek,
};
+static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct mei_device *dev = fp->private_data;
+ struct mei_cl *cl;
+ const size_t bufsz = 1024;
+ char *buf;
+ int i = 0;
+ int pos = 0;
+ int ret;
+
+ if (!dev)
+ return -ENODEV;
+
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ " |me|host|state|rd|wr|\n");
+
+ mutex_lock(&dev->device_lock);
+
+ /* if the driver is not enabled the list won't b consitent */
+ if (dev->dev_state != MEI_DEV_ENABLED)
+ goto out;
+
+ list_for_each_entry(cl, &dev->file_list, link) {
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "%2d|%2d|%4d|%5d|%2d|%2d|\n",
+ i, cl->me_client_id, cl->host_client_id, cl->state,
+ cl->reading_state, cl->writing_state);
+ i++;
+ }
+out:
+ mutex_unlock(&dev->device_lock);
+ ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations mei_dbgfs_fops_active = {
+ .open = simple_open,
+ .read = mei_dbgfs_read_active,
+ .llseek = generic_file_llseek,
+};
+
static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
@@ -128,6 +176,12 @@ int mei_dbgfs_register(struct mei_device *dev, const char *name)
dev_err(&dev->pdev->dev, "meclients: registration failed\n");
goto err;
}
+ f = debugfs_create_file("active", S_IRUSR, dir,
+ dev, &mei_dbgfs_fops_active);
+ if (!f) {
+ dev_err(&dev->pdev->dev, "meclients: registration failed\n");
+ goto err;
+ }
f = debugfs_create_file("devstate", S_IRUSR, dir,
dev, &mei_dbgfs_fops_devstate);
if (!f) {
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 28cd74c073b9..4960288e543a 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -21,7 +21,41 @@
#include "mei_dev.h"
#include "hbm.h"
-#include "hw-me.h"
+#include "client.h"
+
+static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
+{
+#define MEI_CL_CS(status) case MEI_CL_CONN_##status: return #status
+ switch (status) {
+ MEI_CL_CS(SUCCESS);
+ MEI_CL_CS(NOT_FOUND);
+ MEI_CL_CS(ALREADY_STARTED);
+ MEI_CL_CS(OUT_OF_RESOURCES);
+ MEI_CL_CS(MESSAGE_SMALL);
+ default: return "unknown";
+ }
+#undef MEI_CL_CCS
+}
+
+/**
+ * mei_cl_conn_status_to_errno - convert client connect response
+ * status to error code
+ *
+ * @status: client connect response status
+ *
+ * returns corresponding error code
+ */
+static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
+{
+ switch (status) {
+ case MEI_CL_CONN_SUCCESS: return 0;
+ case MEI_CL_CONN_NOT_FOUND: return -ENOTTY;
+ case MEI_CL_CONN_ALREADY_STARTED: return -EBUSY;
+ case MEI_CL_CONN_OUT_OF_RESOURCES: return -EBUSY;
+ case MEI_CL_CONN_MESSAGE_SMALL: return -EINVAL;
+ default: return -EINVAL;
+ }
+}
/**
* mei_hbm_me_cl_allocate - allocates storage for me clients
@@ -100,33 +134,6 @@ bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf)
/**
- * is_treat_specially_client - checks if the message belongs
- * to the file private data.
- *
- * @cl: private data of the file object
- * @rs: connect response bus message
- *
- */
-static bool is_treat_specially_client(struct mei_cl *cl,
- struct hbm_client_connect_response *rs)
-{
- if (mei_hbm_cl_addr_equal(cl, rs)) {
- if (!rs->status) {
- cl->state = MEI_FILE_CONNECTED;
- cl->status = 0;
-
- } else {
- cl->state = MEI_FILE_DISCONNECTED;
- cl->status = -ENODEV;
- }
- cl->timer_count = 0;
-
- return true;
- }
- return false;
-}
-
-/**
* mei_hbm_idle - set hbm to idle state
*
* @dev: the device structure
@@ -147,13 +154,13 @@ int mei_hbm_start_wait(struct mei_device *dev)
ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
dev->hbm_state == MEI_HBM_IDLE ||
dev->hbm_state >= MEI_HBM_STARTED,
- mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
+ mei_secs_to_jiffies(MEI_HBM_TIMEOUT));
mutex_lock(&dev->device_lock);
if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
dev->hbm_state = MEI_HBM_IDLE;
dev_err(&dev->pdev->dev, "waiting for mei start failed\n");
- return -ETIMEDOUT;
+ return -ETIME;
}
return 0;
}
@@ -283,17 +290,18 @@ static int mei_hbm_prop_req(struct mei_device *dev)
}
/**
- * mei_hbm_stop_req_prepare - prepare stop request message
+ * mei_hbm_stop_req - send stop request message
*
* @dev - mei device
- * @mei_hdr - mei message header
- * @data - hbm message body buffer
+ * @cl: client info
+ *
+ * This function returns -EIO on write failure
*/
-static void mei_hbm_stop_req_prepare(struct mei_device *dev,
- struct mei_msg_hdr *mei_hdr, unsigned char *data)
+static int mei_hbm_stop_req(struct mei_device *dev)
{
+ struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
struct hbm_host_stop_request *req =
- (struct hbm_host_stop_request *)data;
+ (struct hbm_host_stop_request *)dev->wr_msg.data;
const size_t len = sizeof(struct hbm_host_stop_request);
mei_hbm_hdr(mei_hdr, len);
@@ -301,6 +309,8 @@ static void mei_hbm_stop_req_prepare(struct mei_device *dev,
memset(req, 0, len);
req->hbm_cmd = HOST_STOP_REQ_CMD;
req->reason = DRIVER_STOP_REQUEST;
+
+ return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
}
/**
@@ -319,8 +329,7 @@ int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
mei_hbm_hdr(mei_hdr, len);
mei_hbm_cl_hdr(cl, MEI_FLOW_CONTROL_CMD, dev->wr_msg.data, len);
- dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
- cl->host_client_id, cl->me_client_id);
+ cl_dbg(dev, cl, "sending flow control\n");
return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
}
@@ -330,27 +339,34 @@ int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
*
* @dev: the device structure
* @flow: flow control.
+ *
+ * return 0 on success, < 0 otherwise
*/
-static void mei_hbm_add_single_flow_creds(struct mei_device *dev,
+static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
struct hbm_flow_control *flow)
{
- struct mei_me_client *client;
- int i;
-
- for (i = 0; i < dev->me_clients_num; i++) {
- client = &dev->me_clients[i];
- if (client && flow->me_addr == client->client_id) {
- if (client->props.single_recv_buf) {
- client->mei_flow_ctrl_creds++;
- dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
- flow->me_addr);
- dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
- client->mei_flow_ctrl_creds);
- } else {
- BUG(); /* error in flow control */
- }
- }
+ struct mei_me_client *me_cl;
+ int id;
+
+ id = mei_me_cl_by_id(dev, flow->me_addr);
+ if (id < 0) {
+ dev_err(&dev->pdev->dev, "no such me client %d\n",
+ flow->me_addr);
+ return id;
}
+
+ me_cl = &dev->me_clients[id];
+ if (me_cl->props.single_recv_buf) {
+ me_cl->mei_flow_ctrl_creds++;
+ dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
+ flow->me_addr);
+ dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
+ me_cl->mei_flow_ctrl_creds);
+ } else {
+ BUG(); /* error in flow control */
+ }
+
+ return 0;
}
/**
@@ -362,8 +378,7 @@ static void mei_hbm_add_single_flow_creds(struct mei_device *dev,
static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
struct hbm_flow_control *flow_control)
{
- struct mei_cl *cl = NULL;
- struct mei_cl *next = NULL;
+ struct mei_cl *cl;
if (!flow_control->host_addr) {
/* single receive buffer */
@@ -372,7 +387,7 @@ static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
}
/* normal connection */
- list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+ list_for_each_entry(cl, &dev->file_list, link) {
if (mei_hbm_cl_addr_equal(cl, flow_control)) {
cl->mei_flow_ctrl_creds++;
dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
@@ -405,6 +420,25 @@ int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
}
/**
+ * mei_hbm_cl_disconnect_rsp - sends disconnect respose to the FW
+ *
+ * @dev: the device structure
+ * @cl: a client to disconnect from
+ *
+ * This function returns -EIO on write failure
+ */
+int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl)
+{
+ struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
+ const size_t len = sizeof(struct hbm_client_connect_response);
+
+ mei_hbm_hdr(mei_hdr, len);
+ mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD, dev->wr_msg.data, len);
+
+ return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
+}
+
+/**
* mei_hbm_cl_disconnect_res - disconnect response from ME
*
* @dev: the device structure
@@ -414,29 +448,23 @@ static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
struct hbm_client_connect_response *rs)
{
struct mei_cl *cl;
- struct mei_cl_cb *pos = NULL, *next = NULL;
-
- dev_dbg(&dev->pdev->dev,
- "disconnect_response:\n"
- "ME Client = %d\n"
- "Host Client = %d\n"
- "Status = %d\n",
- rs->me_addr,
- rs->host_addr,
- rs->status);
-
- list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
- cl = pos->cl;
-
- if (!cl) {
- list_del(&pos->list);
+ struct mei_cl_cb *cb, *next;
+
+ dev_dbg(&dev->pdev->dev, "hbm: disconnect response cl:host=%02d me=%02d status=%d\n",
+ rs->me_addr, rs->host_addr, rs->status);
+
+ list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
+ cl = cb->cl;
+
+ /* this should not happen */
+ if (WARN_ON(!cl)) {
+ list_del(&cb->list);
return;
}
- dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
if (mei_hbm_cl_addr_equal(cl, rs)) {
- list_del(&pos->list);
- if (!rs->status)
+ list_del(&cb->list);
+ if (rs->status == MEI_CL_DISCONN_SUCCESS)
cl->state = MEI_FILE_DISCONNECTED;
cl->status = 0;
@@ -476,46 +504,41 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
{
struct mei_cl *cl;
- struct mei_cl_cb *pos = NULL, *next = NULL;
+ struct mei_cl_cb *cb, *next;
- dev_dbg(&dev->pdev->dev,
- "connect_response:\n"
- "ME Client = %d\n"
- "Host Client = %d\n"
- "Status = %d\n",
- rs->me_addr,
- rs->host_addr,
- rs->status);
+ dev_dbg(&dev->pdev->dev, "hbm: connect response cl:host=%02d me=%02d status=%s\n",
+ rs->me_addr, rs->host_addr,
+ mei_cl_conn_status_str(rs->status));
- /* if WD or iamthif client treat specially */
+ cl = NULL;
- if (is_treat_specially_client(&dev->wd_cl, rs)) {
- dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
- mei_watchdog_register(dev);
+ list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
- return;
- }
+ cl = cb->cl;
+ /* this should not happen */
+ if (WARN_ON(!cl)) {
+ list_del_init(&cb->list);
+ continue;
+ }
- if (is_treat_specially_client(&dev->iamthif_cl, rs)) {
- dev->iamthif_state = MEI_IAMTHIF_IDLE;
- return;
- }
- list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
+ if (cb->fop_type != MEI_FOP_CONNECT)
+ continue;
- cl = pos->cl;
- if (!cl) {
- list_del(&pos->list);
- return;
- }
- if (pos->fop_type == MEI_FOP_IOCTL) {
- if (is_treat_specially_client(cl, rs)) {
- list_del(&pos->list);
- cl->status = 0;
- cl->timer_count = 0;
- break;
- }
+ if (mei_hbm_cl_addr_equal(cl, rs)) {
+ list_del(&cb->list);
+ break;
}
}
+
+ if (!cl)
+ return;
+
+ cl->timer_count = 0;
+ if (rs->status == MEI_CL_CONN_SUCCESS)
+ cl->state = MEI_FILE_CONNECTED;
+ else
+ cl->state = MEI_FILE_DISCONNECTED;
+ cl->status = mei_cl_conn_status_to_errno(rs->status);
}
@@ -525,32 +548,34 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
*
* @dev: the device structure.
* @disconnect_req: disconnect request bus message from the me
+ *
+ * returns -ENOMEM on allocation failure
*/
-static void mei_hbm_fw_disconnect_req(struct mei_device *dev,
+static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
struct hbm_client_connect_request *disconnect_req)
{
- struct mei_cl *cl, *next;
- const size_t len = sizeof(struct hbm_client_connect_response);
+ struct mei_cl *cl;
+ struct mei_cl_cb *cb;
- list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+ list_for_each_entry(cl, &dev->file_list, link) {
if (mei_hbm_cl_addr_equal(cl, disconnect_req)) {
dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
disconnect_req->host_addr,
disconnect_req->me_addr);
cl->state = MEI_FILE_DISCONNECTED;
cl->timer_count = 0;
- if (cl == &dev->wd_cl)
- dev->wd_pending = false;
- else if (cl == &dev->iamthif_cl)
- dev->iamthif_timer = 0;
-
- /* prepare disconnect response */
- mei_hbm_hdr(&dev->wr_ext_msg.hdr, len);
- mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD,
- dev->wr_ext_msg.data, len);
+
+ cb = mei_io_cb_init(cl, NULL);
+ if (!cb)
+ return -ENOMEM;
+ cb->fop_type = MEI_FOP_DISCONNECT_RSP;
+ cl_dbg(dev, cl, "add disconnect response as first\n");
+ list_add(&cb->list, &dev->ctrl_wr_list.list);
+
break;
}
}
+ return 0;
}
@@ -629,10 +654,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
dev_warn(&dev->pdev->dev, "hbm: start: version mismatch - stopping the driver.\n");
dev->hbm_state = MEI_HBM_STOPPED;
- mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
- dev->wr_msg.data);
- if (mei_write_message(dev, &dev->wr_msg.hdr,
- dev->wr_msg.data)) {
+ if (mei_hbm_stop_req(dev)) {
dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
return -EIO;
}
@@ -778,10 +800,11 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
case ME_STOP_REQ_CMD:
dev_dbg(&dev->pdev->dev, "hbm: stop request: message received\n");
-
dev->hbm_state = MEI_HBM_STOPPED;
- mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
- dev->wr_ext_msg.data);
+ if (mei_hbm_stop_req(dev)) {
+ dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
+ return -EIO;
+ }
break;
default:
BUG();
diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h
index 5f92188a5cd7..20e8782711c0 100644
--- a/drivers/misc/mei/hbm.h
+++ b/drivers/misc/mei/hbm.h
@@ -54,6 +54,7 @@ int mei_hbm_start_req(struct mei_device *dev);
int mei_hbm_start_wait(struct mei_device *dev);
int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl);
int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl);
+int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl);
int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl);
bool mei_hbm_version_is_supported(struct mei_device *dev);
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 6f656c053b14..8dbdaaef1af5 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -20,10 +20,10 @@
#include <linux/interrupt.h>
#include "mei_dev.h"
-#include "hw-me.h"
-
#include "hbm.h"
+#include "hw-me.h"
+#include "hw-me-regs.h"
/**
* mei_me_reg_read - Reads 32bit data from the mei device
@@ -240,11 +240,11 @@ static int mei_me_hw_ready_wait(struct mei_device *dev)
mutex_unlock(&dev->device_lock);
err = wait_event_interruptible_timeout(dev->wait_hw_ready,
dev->recvd_hw_ready,
- mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
+ mei_secs_to_jiffies(MEI_HW_READY_TIMEOUT));
mutex_lock(&dev->device_lock);
if (!err && !dev->recvd_hw_ready) {
if (!err)
- err = -ETIMEDOUT;
+ err = -ETIME;
dev_err(&dev->pdev->dev,
"wait hw ready failed. status = %d\n", err);
return err;
@@ -303,7 +303,7 @@ static bool mei_me_hbuf_is_empty(struct mei_device *dev)
*
* @dev: the device structure
*
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
+ * returns -EOVERFLOW if overflow, otherwise empty slots count
*/
static int mei_me_hbuf_empty_slots(struct mei_device *dev)
{
@@ -326,7 +326,7 @@ static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
/**
- * mei_write_message - writes a message to mei device.
+ * mei_me_write_message - writes a message to mei device.
*
* @dev: the device structure
* @header: mei HECI header of message
@@ -354,7 +354,7 @@ static int mei_me_write_message(struct mei_device *dev,
dw_cnt = mei_data2slots(length);
if (empty_slots < 0 || dw_cnt > empty_slots)
- return -EIO;
+ return -EMSGSIZE;
mei_me_reg_write(hw, H_CB_WW, *((u32 *) header));
@@ -381,7 +381,7 @@ static int mei_me_write_message(struct mei_device *dev,
*
* @dev: the device structure
*
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
+ * returns -EOVERFLOW if overflow, otherwise filled slots count
*/
static int mei_me_count_full_read_slots(struct mei_device *dev)
{
@@ -505,17 +505,25 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
/* check slots available for reading */
slots = mei_count_full_read_slots(dev);
while (slots > 0) {
- /* we have urgent data to send so break the read */
- if (dev->wr_ext_msg.hdr.length)
- break;
dev_dbg(&dev->pdev->dev, "slots to read = %08x\n", slots);
rets = mei_irq_read_handler(dev, &complete_list, &slots);
+ /* There is a race between ME write and interrupt delivery:
+ * Not all data is always available immediately after the
+ * interrupt, so try to read again on the next interrupt.
+ */
+ if (rets == -ENODATA)
+ break;
+
if (rets && dev->dev_state != MEI_DEV_RESETTING) {
+ dev_err(&dev->pdev->dev, "mei_irq_read_handler ret = %d.\n",
+ rets);
schedule_work(&dev->reset_work);
goto end;
}
}
+ dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
+
rets = mei_irq_write_handler(dev, &complete_list);
dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h
index 80bd829fbd9a..893d5119fa9b 100644
--- a/drivers/misc/mei/hw-me.h
+++ b/drivers/misc/mei/hw-me.h
@@ -20,6 +20,7 @@
#define _MEI_INTERFACE_H_
#include <linux/mei.h>
+#include <linux/irqreturn.h>
#include "mei_dev.h"
#include "client.h"
diff --git a/drivers/misc/mei/hw-txe-regs.h b/drivers/misc/mei/hw-txe-regs.h
new file mode 100644
index 000000000000..7283c24c1af1
--- /dev/null
+++ b/drivers/misc/mei/hw-txe-regs.h
@@ -0,0 +1,294 @@
+/******************************************************************************
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Intel MEI Interface Header
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING
+ *
+ * Contact Information:
+ * Intel Corporation.
+ * linux-mei@linux.intel.com
+ * http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * 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 Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY 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.
+ *
+ *****************************************************************************/
+#ifndef _MEI_HW_TXE_REGS_H_
+#define _MEI_HW_TXE_REGS_H_
+
+#include "hw.h"
+
+#define SEC_ALIVENESS_TIMER_TIMEOUT (5 * MSEC_PER_SEC)
+#define SEC_ALIVENESS_WAIT_TIMEOUT (1 * MSEC_PER_SEC)
+#define SEC_RESET_WAIT_TIMEOUT (1 * MSEC_PER_SEC)
+#define SEC_READY_WAIT_TIMEOUT (5 * MSEC_PER_SEC)
+#define START_MESSAGE_RESPONSE_WAIT_TIMEOUT (5 * MSEC_PER_SEC)
+#define RESET_CANCEL_WAIT_TIMEOUT (1 * MSEC_PER_SEC)
+
+enum {
+ SEC_BAR,
+ BRIDGE_BAR,
+
+ NUM_OF_MEM_BARS
+};
+
+/* SeC FW Status Register
+ *
+ * FW uses this register in order to report its status to host.
+ * This register resides in PCI-E config space.
+ */
+#define PCI_CFG_TXE_FW_STS0 0x40
+# define PCI_CFG_TXE_FW_STS0_WRK_ST_MSK 0x0000000F
+# define PCI_CFG_TXE_FW_STS0_OP_ST_MSK 0x000001C0
+# define PCI_CFG_TXE_FW_STS0_FW_INIT_CMPLT 0x00000200
+# define PCI_CFG_TXE_FW_STS0_ERR_CODE_MSK 0x0000F000
+# define PCI_CFG_TXE_FW_STS0_OP_MODE_MSK 0x000F0000
+# define PCI_CFG_TXE_FW_STS0_RST_CNT_MSK 0x00F00000
+
+
+#define IPC_BASE_ADDR 0x80400 /* SeC IPC Base Address */
+
+/* IPC Input Doorbell Register */
+#define SEC_IPC_INPUT_DOORBELL_REG (0x0000 + IPC_BASE_ADDR)
+
+/* IPC Input Status Register
+ * This register indicates whether or not processing of
+ * the most recent command has been completed by the SEC
+ * New commands and payloads should not be written by the Host
+ * until this indicates that the previous command has been processed.
+ */
+#define SEC_IPC_INPUT_STATUS_REG (0x0008 + IPC_BASE_ADDR)
+# define SEC_IPC_INPUT_STATUS_RDY BIT(0)
+
+/* IPC Host Interrupt Status Register */
+#define SEC_IPC_HOST_INT_STATUS_REG (0x0010 + IPC_BASE_ADDR)
+#define SEC_IPC_HOST_INT_STATUS_OUT_DB BIT(0)
+#define SEC_IPC_HOST_INT_STATUS_IN_RDY BIT(1)
+#define SEC_IPC_HOST_INT_STATUS_HDCP_M0_RCVD BIT(5)
+#define SEC_IPC_HOST_INT_STATUS_ILL_MEM_ACCESS BIT(17)
+#define SEC_IPC_HOST_INT_STATUS_AES_HKEY_ERR BIT(18)
+#define SEC_IPC_HOST_INT_STATUS_DES_HKEY_ERR BIT(19)
+#define SEC_IPC_HOST_INT_STATUS_TMRMTB_OVERFLOW BIT(21)
+
+/* Convenient mask for pending interrupts */
+#define SEC_IPC_HOST_INT_STATUS_PENDING \
+ (SEC_IPC_HOST_INT_STATUS_OUT_DB| \
+ SEC_IPC_HOST_INT_STATUS_IN_RDY)
+
+/* IPC Host Interrupt Mask Register */
+#define SEC_IPC_HOST_INT_MASK_REG (0x0014 + IPC_BASE_ADDR)
+
+# define SEC_IPC_HOST_INT_MASK_OUT_DB BIT(0) /* Output Doorbell Int Mask */
+# define SEC_IPC_HOST_INT_MASK_IN_RDY BIT(1) /* Input Ready Int Mask */
+
+/* IPC Input Payload RAM */
+#define SEC_IPC_INPUT_PAYLOAD_REG (0x0100 + IPC_BASE_ADDR)
+/* IPC Shared Payload RAM */
+#define IPC_SHARED_PAYLOAD_REG (0x0200 + IPC_BASE_ADDR)
+
+/* SeC Address Translation Table Entry 2 - Ctrl
+ *
+ * This register resides also in SeC's PCI-E Memory space.
+ */
+#define SATT2_CTRL_REG 0x1040
+# define SATT2_CTRL_VALID_MSK BIT(0)
+# define SATT2_CTRL_BR_BASE_ADDR_REG_SHIFT 8
+# define SATT2_CTRL_BRIDGE_HOST_EN_MSK BIT(12)
+
+/* SATT Table Entry 2 SAP Base Address Register */
+#define SATT2_SAP_BA_REG 0x1044
+/* SATT Table Entry 2 SAP Size Register. */
+#define SATT2_SAP_SIZE_REG 0x1048
+ /* SATT Table Entry 2 SAP Bridge Address - LSB Register */
+#define SATT2_BRG_BA_LSB_REG 0x104C
+
+/* Host High-level Interrupt Status Register */
+#define HHISR_REG 0x2020
+/* Host High-level Interrupt Enable Register
+ *
+ * Resides in PCI memory space. This is the top hierarchy for
+ * interrupts from SeC to host, aggregating both interrupts that
+ * arrive through HICR registers as well as interrupts
+ * that arrive via IPC.
+ */
+#define HHIER_REG 0x2024
+#define IPC_HHIER_SEC BIT(0)
+#define IPC_HHIER_BRIDGE BIT(1)
+#define IPC_HHIER_MSK (IPC_HHIER_SEC | IPC_HHIER_BRIDGE)
+
+/* Host High-level Interrupt Mask Register.
+ *
+ * Resides in PCI memory space.
+ * This is the top hierarchy for masking interrupts from SeC to host.
+ */
+#define HHIMR_REG 0x2028
+#define IPC_HHIMR_SEC BIT(0)
+#define IPC_HHIMR_BRIDGE BIT(1)
+
+/* Host High-level IRQ Status Register */
+#define HHIRQSR_REG 0x202C
+
+/* Host Interrupt Cause Register 0 - SeC IPC Readiness
+ *
+ * This register is both an ICR to Host from PCI Memory Space
+ * and it is also exposed in the SeC memory space.
+ * This register is used by SeC's IPC driver in order
+ * to synchronize with host about IPC interface state.
+ */
+#define HICR_SEC_IPC_READINESS_REG 0x2040
+#define HICR_SEC_IPC_READINESS_HOST_RDY BIT(0)
+#define HICR_SEC_IPC_READINESS_SEC_RDY BIT(1)
+#define HICR_SEC_IPC_READINESS_SYS_RDY \
+ (HICR_SEC_IPC_READINESS_HOST_RDY | \
+ HICR_SEC_IPC_READINESS_SEC_RDY)
+#define HICR_SEC_IPC_READINESS_RDY_CLR BIT(2)
+
+/* Host Interrupt Cause Register 1 - Aliveness Response */
+/* This register is both an ICR to Host from PCI Memory Space
+ * and it is also exposed in the SeC memory space.
+ * The register may be used by SeC to ACK a host request for aliveness.
+ */
+#define HICR_HOST_ALIVENESS_RESP_REG 0x2044
+#define HICR_HOST_ALIVENESS_RESP_ACK BIT(0)
+
+/* Host Interrupt Cause Register 2 - SeC IPC Output Doorbell */
+#define HICR_SEC_IPC_OUTPUT_DOORBELL_REG 0x2048
+
+/* Host Interrupt Status Register.
+ *
+ * Resides in PCI memory space.
+ * This is the main register involved in generating interrupts
+ * from SeC to host via HICRs.
+ * The interrupt generation rules are as follows:
+ * An interrupt will be generated whenever for any i,
+ * there is a transition from a state where at least one of
+ * the following conditions did not hold, to a state where
+ * ALL the following conditions hold:
+ * A) HISR.INT[i]_STS == 1.
+ * B) HIER.INT[i]_EN == 1.
+ */
+#define HISR_REG 0x2060
+#define HISR_INT_0_STS BIT(0)
+#define HISR_INT_1_STS BIT(1)
+#define HISR_INT_2_STS BIT(2)
+#define HISR_INT_3_STS BIT(3)
+#define HISR_INT_4_STS BIT(4)
+#define HISR_INT_5_STS BIT(5)
+#define HISR_INT_6_STS BIT(6)
+#define HISR_INT_7_STS BIT(7)
+#define HISR_INT_STS_MSK \
+ (HISR_INT_0_STS | HISR_INT_1_STS | HISR_INT_2_STS)
+
+/* Host Interrupt Enable Register. Resides in PCI memory space. */
+#define HIER_REG 0x2064
+#define HIER_INT_0_EN BIT(0)
+#define HIER_INT_1_EN BIT(1)
+#define HIER_INT_2_EN BIT(2)
+#define HIER_INT_3_EN BIT(3)
+#define HIER_INT_4_EN BIT(4)
+#define HIER_INT_5_EN BIT(5)
+#define HIER_INT_6_EN BIT(6)
+#define HIER_INT_7_EN BIT(7)
+
+#define HIER_INT_EN_MSK \
+ (HIER_INT_0_EN | HIER_INT_1_EN | HIER_INT_2_EN)
+
+
+/* SEC Memory Space IPC output payload.
+ *
+ * This register is part of the output payload which SEC provides to host.
+ */
+#define BRIDGE_IPC_OUTPUT_PAYLOAD_REG 0x20C0
+
+/* SeC Interrupt Cause Register - Host Aliveness Request
+ * This register is both an ICR to SeC and it is also exposed
+ * in the host-visible PCI memory space.
+ * The register is used by host to request SeC aliveness.
+ */
+#define SICR_HOST_ALIVENESS_REQ_REG 0x214C
+#define SICR_HOST_ALIVENESS_REQ_REQUESTED BIT(0)
+
+
+/* SeC Interrupt Cause Register - Host IPC Readiness
+ *
+ * This register is both an ICR to SeC and it is also exposed
+ * in the host-visible PCI memory space.
+ * This register is used by the host's SeC driver uses in order
+ * to synchronize with SeC about IPC interface state.
+ */
+#define SICR_HOST_IPC_READINESS_REQ_REG 0x2150
+
+
+#define SICR_HOST_IPC_READINESS_HOST_RDY BIT(0)
+#define SICR_HOST_IPC_READINESS_SEC_RDY BIT(1)
+#define SICR_HOST_IPC_READINESS_SYS_RDY \
+ (SICR_HOST_IPC_READINESS_HOST_RDY | \
+ SICR_HOST_IPC_READINESS_SEC_RDY)
+#define SICR_HOST_IPC_READINESS_RDY_CLR BIT(2)
+
+/* SeC Interrupt Cause Register - SeC IPC Output Status
+ *
+ * This register indicates whether or not processing of the most recent
+ * command has been completed by the Host.
+ * New commands and payloads should not be written by SeC until this
+ * register indicates that the previous command has been processed.
+ */
+#define SICR_SEC_IPC_OUTPUT_STATUS_REG 0x2154
+# define SEC_IPC_OUTPUT_STATUS_RDY BIT(0)
+
+
+
+/* MEI IPC Message payload size 64 bytes */
+#define PAYLOAD_SIZE 64
+
+/* MAX size for SATT range 32MB */
+#define SATT_RANGE_MAX (32 << 20)
+
+
+#endif /* _MEI_HW_TXE_REGS_H_ */
+
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c
new file mode 100644
index 000000000000..f60182a52f96
--- /dev/null
+++ b/drivers/misc/mei/hw-txe.c
@@ -0,0 +1,1107 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/irqreturn.h>
+
+#include <linux/mei.h>
+
+#include "mei_dev.h"
+#include "hw-txe.h"
+#include "client.h"
+#include "hbm.h"
+
+/**
+ * mei_txe_reg_read - Reads 32bit data from the device
+ *
+ * @base_addr: registers base address
+ * @offset: register offset
+ *
+ */
+static inline u32 mei_txe_reg_read(void __iomem *base_addr,
+ unsigned long offset)
+{
+ return ioread32(base_addr + offset);
+}
+
+/**
+ * mei_txe_reg_write - Writes 32bit data to the device
+ *
+ * @base_addr: registers base address
+ * @offset: register offset
+ * @value: the value to write
+ */
+static inline void mei_txe_reg_write(void __iomem *base_addr,
+ unsigned long offset, u32 value)
+{
+ iowrite32(value, base_addr + offset);
+}
+
+/**
+ * mei_txe_sec_reg_read_silent - Reads 32bit data from the SeC BAR
+ *
+ * @dev: the device structure
+ * @offset: register offset
+ *
+ * Doesn't check for aliveness while Reads 32bit data from the SeC BAR
+ */
+static inline u32 mei_txe_sec_reg_read_silent(struct mei_txe_hw *hw,
+ unsigned long offset)
+{
+ return mei_txe_reg_read(hw->mem_addr[SEC_BAR], offset);
+}
+
+/**
+ * mei_txe_sec_reg_read - Reads 32bit data from the SeC BAR
+ *
+ * @dev: the device structure
+ * @offset: register offset
+ *
+ * Reads 32bit data from the SeC BAR and shout loud if aliveness is not set
+ */
+static inline u32 mei_txe_sec_reg_read(struct mei_txe_hw *hw,
+ unsigned long offset)
+{
+ WARN(!hw->aliveness, "sec read: aliveness not asserted\n");
+ return mei_txe_sec_reg_read_silent(hw, offset);
+}
+/**
+ * mei_txe_sec_reg_write_silent - Writes 32bit data to the SeC BAR
+ * doesn't check for aliveness
+ *
+ * @dev: the device structure
+ * @offset: register offset
+ * @value: value to write
+ *
+ * Doesn't check for aliveness while writes 32bit data from to the SeC BAR
+ */
+static inline void mei_txe_sec_reg_write_silent(struct mei_txe_hw *hw,
+ unsigned long offset, u32 value)
+{
+ mei_txe_reg_write(hw->mem_addr[SEC_BAR], offset, value);
+}
+
+/**
+ * mei_txe_sec_reg_write - Writes 32bit data to the SeC BAR
+ *
+ * @dev: the device structure
+ * @offset: register offset
+ * @value: value to write
+ *
+ * Writes 32bit data from the SeC BAR and shout loud if aliveness is not set
+ */
+static inline void mei_txe_sec_reg_write(struct mei_txe_hw *hw,
+ unsigned long offset, u32 value)
+{
+ WARN(!hw->aliveness, "sec write: aliveness not asserted\n");
+ mei_txe_sec_reg_write_silent(hw, offset, value);
+}
+/**
+ * mei_txe_br_reg_read - Reads 32bit data from the Bridge BAR
+ *
+ * @hw: the device structure
+ * @offset: offset from which to read the data
+ *
+ */
+static inline u32 mei_txe_br_reg_read(struct mei_txe_hw *hw,
+ unsigned long offset)
+{
+ return mei_txe_reg_read(hw->mem_addr[BRIDGE_BAR], offset);
+}
+
+/**
+ * mei_txe_br_reg_write - Writes 32bit data to the Bridge BAR
+ *
+ * @hw: the device structure
+ * @offset: offset from which to write the data
+ * @value: the byte to write
+ */
+static inline void mei_txe_br_reg_write(struct mei_txe_hw *hw,
+ unsigned long offset, u32 value)
+{
+ mei_txe_reg_write(hw->mem_addr[BRIDGE_BAR], offset, value);
+}
+
+/**
+ * mei_txe_aliveness_set - request for aliveness change
+ *
+ * @dev: the device structure
+ * @req: requested aliveness value
+ *
+ * Request for aliveness change and returns true if the change is
+ * really needed and false if aliveness is already
+ * in the requested state
+ * Requires device lock to be held
+ */
+static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
+{
+
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ bool do_req = hw->aliveness != req;
+
+ dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n",
+ hw->aliveness, req);
+ if (do_req) {
+ hw->recvd_aliveness = false;
+ mei_txe_br_reg_write(hw, SICR_HOST_ALIVENESS_REQ_REG, req);
+ }
+ return do_req;
+}
+
+
+/**
+ * mei_txe_aliveness_req_get - get aliveness requested register value
+ *
+ * @dev: the device structure
+ *
+ * Extract HICR_HOST_ALIVENESS_RESP_ACK bit from
+ * from HICR_HOST_ALIVENESS_REQ register value
+ */
+static u32 mei_txe_aliveness_req_get(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 reg;
+ reg = mei_txe_br_reg_read(hw, SICR_HOST_ALIVENESS_REQ_REG);
+ return reg & SICR_HOST_ALIVENESS_REQ_REQUESTED;
+}
+
+/**
+ * mei_txe_aliveness_get - get aliveness response register value
+ * @dev: the device structure
+ *
+ * Extract HICR_HOST_ALIVENESS_RESP_ACK bit
+ * from HICR_HOST_ALIVENESS_RESP register value
+ */
+static u32 mei_txe_aliveness_get(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 reg;
+ reg = mei_txe_br_reg_read(hw, HICR_HOST_ALIVENESS_RESP_REG);
+ return reg & HICR_HOST_ALIVENESS_RESP_ACK;
+}
+
+/**
+ * mei_txe_aliveness_poll - waits for aliveness to settle
+ *
+ * @dev: the device structure
+ * @expected: expected aliveness value
+ *
+ * Polls for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set
+ * returns > 0 if the expected value was received, -ETIME otherwise
+ */
+static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ int t = 0;
+
+ do {
+ hw->aliveness = mei_txe_aliveness_get(dev);
+ if (hw->aliveness == expected) {
+ dev_dbg(&dev->pdev->dev,
+ "aliveness settled after %d msecs\n", t);
+ return t;
+ }
+ mutex_unlock(&dev->device_lock);
+ msleep(MSEC_PER_SEC / 5);
+ mutex_lock(&dev->device_lock);
+ t += MSEC_PER_SEC / 5;
+ } while (t < SEC_ALIVENESS_WAIT_TIMEOUT);
+
+ dev_err(&dev->pdev->dev, "aliveness timed out\n");
+ return -ETIME;
+}
+
+/**
+ * mei_txe_aliveness_wait - waits for aliveness to settle
+ *
+ * @dev: the device structure
+ * @expected: expected aliveness value
+ *
+ * Waits for HICR_HOST_ALIVENESS_RESP.ALIVENESS_RESP to be set
+ * returns returns 0 on success and < 0 otherwise
+ */
+static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ const unsigned long timeout =
+ msecs_to_jiffies(SEC_ALIVENESS_WAIT_TIMEOUT);
+ long err;
+ int ret;
+
+ hw->aliveness = mei_txe_aliveness_get(dev);
+ if (hw->aliveness == expected)
+ return 0;
+
+ mutex_unlock(&dev->device_lock);
+ err = wait_event_timeout(hw->wait_aliveness,
+ hw->recvd_aliveness, timeout);
+ mutex_lock(&dev->device_lock);
+
+ hw->aliveness = mei_txe_aliveness_get(dev);
+ ret = hw->aliveness == expected ? 0 : -ETIME;
+
+ if (ret)
+ dev_err(&dev->pdev->dev, "aliveness timed out");
+ else
+ dev_dbg(&dev->pdev->dev, "aliveness settled after %d msecs\n",
+ jiffies_to_msecs(timeout - err));
+ hw->recvd_aliveness = false;
+ return ret;
+}
+
+/**
+ * mei_txe_aliveness_set_sync - sets an wait for aliveness to complete
+ *
+ * @dev: the device structure
+ *
+ * returns returns 0 on success and < 0 otherwise
+ */
+int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req)
+{
+ if (mei_txe_aliveness_set(dev, req))
+ return mei_txe_aliveness_wait(dev, req);
+ return 0;
+}
+
+/**
+ * mei_txe_input_ready_interrupt_enable - sets the Input Ready Interrupt
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_input_ready_interrupt_enable(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 hintmsk;
+ /* Enable the SEC_IPC_HOST_INT_MASK_IN_RDY interrupt */
+ hintmsk = mei_txe_sec_reg_read(hw, SEC_IPC_HOST_INT_MASK_REG);
+ hintmsk |= SEC_IPC_HOST_INT_MASK_IN_RDY;
+ mei_txe_sec_reg_write(hw, SEC_IPC_HOST_INT_MASK_REG, hintmsk);
+}
+
+/**
+ * mei_txe_input_doorbell_set
+ * - Sets bit 0 in SEC_IPC_INPUT_DOORBELL.IPC_INPUT_DOORBELL.
+ * @dev: the device structure
+ */
+static void mei_txe_input_doorbell_set(struct mei_txe_hw *hw)
+{
+ /* Clear the interrupt cause */
+ clear_bit(TXE_INTR_IN_READY_BIT, &hw->intr_cause);
+ mei_txe_sec_reg_write(hw, SEC_IPC_INPUT_DOORBELL_REG, 1);
+}
+
+/**
+ * mei_txe_output_ready_set - Sets the SICR_SEC_IPC_OUTPUT_STATUS bit to 1
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_output_ready_set(struct mei_txe_hw *hw)
+{
+ mei_txe_br_reg_write(hw,
+ SICR_SEC_IPC_OUTPUT_STATUS_REG,
+ SEC_IPC_OUTPUT_STATUS_RDY);
+}
+
+/**
+ * mei_txe_is_input_ready - check if TXE is ready for receiving data
+ *
+ * @dev: the device structure
+ */
+static bool mei_txe_is_input_ready(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 status;
+ status = mei_txe_sec_reg_read(hw, SEC_IPC_INPUT_STATUS_REG);
+ return !!(SEC_IPC_INPUT_STATUS_RDY & status);
+}
+
+/**
+ * mei_txe_intr_clear - clear all interrupts
+ *
+ * @dev: the device structure
+ */
+static inline void mei_txe_intr_clear(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ mei_txe_sec_reg_write_silent(hw, SEC_IPC_HOST_INT_STATUS_REG,
+ SEC_IPC_HOST_INT_STATUS_PENDING);
+ mei_txe_br_reg_write(hw, HISR_REG, HISR_INT_STS_MSK);
+ mei_txe_br_reg_write(hw, HHISR_REG, IPC_HHIER_MSK);
+}
+
+/**
+ * mei_txe_intr_disable - disable all interrupts
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_intr_disable(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ mei_txe_br_reg_write(hw, HHIER_REG, 0);
+ mei_txe_br_reg_write(hw, HIER_REG, 0);
+}
+/**
+ * mei_txe_intr_disable - enable all interrupts
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_intr_enable(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ mei_txe_br_reg_write(hw, HHIER_REG, IPC_HHIER_MSK);
+ mei_txe_br_reg_write(hw, HIER_REG, HIER_INT_EN_MSK);
+}
+
+/**
+ * mei_txe_pending_interrupts - check if there are pending interrupts
+ * only Aliveness, Input ready, and output doorbell are of relevance
+ *
+ * @dev: the device structure
+ *
+ * Checks if there are pending interrupts
+ * only Aliveness, Readiness, Input ready, and Output doorbell are relevant
+ */
+static bool mei_txe_pending_interrupts(struct mei_device *dev)
+{
+
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ bool ret = (hw->intr_cause & (TXE_INTR_READINESS |
+ TXE_INTR_ALIVENESS |
+ TXE_INTR_IN_READY |
+ TXE_INTR_OUT_DB));
+
+ if (ret) {
+ dev_dbg(&dev->pdev->dev,
+ "Pending Interrupts InReady=%01d Readiness=%01d, Aliveness=%01d, OutDoor=%01d\n",
+ !!(hw->intr_cause & TXE_INTR_IN_READY),
+ !!(hw->intr_cause & TXE_INTR_READINESS),
+ !!(hw->intr_cause & TXE_INTR_ALIVENESS),
+ !!(hw->intr_cause & TXE_INTR_OUT_DB));
+ }
+ return ret;
+}
+
+/**
+ * mei_txe_input_payload_write - write a dword to the host buffer
+ * at offset idx
+ *
+ * @dev: the device structure
+ * @idx: index in the host buffer
+ * @value: value
+ */
+static void mei_txe_input_payload_write(struct mei_device *dev,
+ unsigned long idx, u32 value)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ mei_txe_sec_reg_write(hw, SEC_IPC_INPUT_PAYLOAD_REG +
+ (idx * sizeof(u32)), value);
+}
+
+/**
+ * mei_txe_out_data_read - read dword from the device buffer
+ * at offset idx
+ *
+ * @dev: the device structure
+ * @idx: index in the device buffer
+ *
+ * returns register value at index
+ */
+static u32 mei_txe_out_data_read(const struct mei_device *dev,
+ unsigned long idx)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ return mei_txe_br_reg_read(hw,
+ BRIDGE_IPC_OUTPUT_PAYLOAD_REG + (idx * sizeof(u32)));
+}
+
+/* Readiness */
+
+/**
+ * mei_txe_readiness_set_host_rdy
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_readiness_set_host_rdy(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ mei_txe_br_reg_write(hw,
+ SICR_HOST_IPC_READINESS_REQ_REG,
+ SICR_HOST_IPC_READINESS_HOST_RDY);
+}
+
+/**
+ * mei_txe_readiness_clear
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_readiness_clear(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ mei_txe_br_reg_write(hw, SICR_HOST_IPC_READINESS_REQ_REG,
+ SICR_HOST_IPC_READINESS_RDY_CLR);
+}
+/**
+ * mei_txe_readiness_get - Reads and returns
+ * the HICR_SEC_IPC_READINESS register value
+ *
+ * @dev: the device structure
+ */
+static u32 mei_txe_readiness_get(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ return mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG);
+}
+
+
+/**
+ * mei_txe_readiness_is_sec_rdy - check readiness
+ * for HICR_SEC_IPC_READINESS_SEC_RDY
+ *
+ * @readiness - cached readiness state
+ */
+static inline bool mei_txe_readiness_is_sec_rdy(u32 readiness)
+{
+ return !!(readiness & HICR_SEC_IPC_READINESS_SEC_RDY);
+}
+
+/**
+ * mei_txe_hw_is_ready - check if the hw is ready
+ *
+ * @dev: the device structure
+ */
+static bool mei_txe_hw_is_ready(struct mei_device *dev)
+{
+ u32 readiness = mei_txe_readiness_get(dev);
+ return mei_txe_readiness_is_sec_rdy(readiness);
+}
+
+/**
+ * mei_txe_host_is_ready - check if the host is ready
+ *
+ * @dev: the device structure
+ */
+static inline bool mei_txe_host_is_ready(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 reg = mei_txe_br_reg_read(hw, HICR_SEC_IPC_READINESS_REG);
+ return !!(reg & HICR_SEC_IPC_READINESS_HOST_RDY);
+}
+
+/**
+ * mei_txe_readiness_wait - wait till readiness settles
+ *
+ * @dev: the device structure
+ *
+ * returns 0 on success and -ETIME on timeout
+ */
+static int mei_txe_readiness_wait(struct mei_device *dev)
+{
+ if (mei_txe_hw_is_ready(dev))
+ return 0;
+
+ mutex_unlock(&dev->device_lock);
+ wait_event_timeout(dev->wait_hw_ready, dev->recvd_hw_ready,
+ msecs_to_jiffies(SEC_RESET_WAIT_TIMEOUT));
+ mutex_lock(&dev->device_lock);
+ if (!dev->recvd_hw_ready) {
+ dev_err(&dev->pdev->dev, "wait for readiness failed\n");
+ return -ETIME;
+ }
+
+ dev->recvd_hw_ready = false;
+ return 0;
+}
+
+/**
+ * mei_txe_hw_config - configure hardware at the start of the devices
+ *
+ * @dev: the device structure
+ *
+ * Configure hardware at the start of the device should be done only
+ * once at the device probe time
+ */
+static void mei_txe_hw_config(struct mei_device *dev)
+{
+
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ /* Doesn't change in runtime */
+ dev->hbuf_depth = PAYLOAD_SIZE / 4;
+
+ hw->aliveness = mei_txe_aliveness_get(dev);
+ hw->readiness = mei_txe_readiness_get(dev);
+
+ dev_dbg(&dev->pdev->dev, "aliveness_resp = 0x%08x, readiness = 0x%08x.\n",
+ hw->aliveness, hw->readiness);
+}
+
+
+/**
+ * mei_txe_write - writes a message to device.
+ *
+ * @dev: the device structure
+ * @header: header of message
+ * @buf: message buffer will be written
+ * returns 1 if success, 0 - otherwise.
+ */
+
+static int mei_txe_write(struct mei_device *dev,
+ struct mei_msg_hdr *header, unsigned char *buf)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ unsigned long rem;
+ unsigned long length;
+ int slots = dev->hbuf_depth;
+ u32 *reg_buf = (u32 *)buf;
+ u32 dw_cnt;
+ int i;
+
+ if (WARN_ON(!header || !buf))
+ return -EINVAL;
+
+ length = header->length;
+
+ dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
+
+ dw_cnt = mei_data2slots(length);
+ if (dw_cnt > slots)
+ return -EMSGSIZE;
+
+ if (WARN(!hw->aliveness, "txe write: aliveness not asserted\n"))
+ return -EAGAIN;
+
+ /* Enable Input Ready Interrupt. */
+ mei_txe_input_ready_interrupt_enable(dev);
+
+ if (!mei_txe_is_input_ready(dev)) {
+ dev_err(&dev->pdev->dev, "Input is not ready");
+ return -EAGAIN;
+ }
+
+ mei_txe_input_payload_write(dev, 0, *((u32 *)header));
+
+ for (i = 0; i < length / 4; i++)
+ mei_txe_input_payload_write(dev, i + 1, reg_buf[i]);
+
+ rem = length & 0x3;
+ if (rem > 0) {
+ u32 reg = 0;
+ memcpy(&reg, &buf[length - rem], rem);
+ mei_txe_input_payload_write(dev, i + 1, reg);
+ }
+
+ /* after each write the whole buffer is consumed */
+ hw->slots = 0;
+
+ /* Set Input-Doorbell */
+ mei_txe_input_doorbell_set(hw);
+
+ return 0;
+}
+
+/**
+ * mei_txe_hbuf_max_len - mimics the me hbuf circular buffer
+ *
+ * @dev: the device structure
+ *
+ * returns the PAYLOAD_SIZE - 4
+ */
+static size_t mei_txe_hbuf_max_len(const struct mei_device *dev)
+{
+ return PAYLOAD_SIZE - sizeof(struct mei_msg_hdr);
+}
+
+/**
+ * mei_txe_hbuf_empty_slots - mimics the me hbuf circular buffer
+ *
+ * @dev: the device structure
+ *
+ * returns always hbuf_depth
+ */
+static int mei_txe_hbuf_empty_slots(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ return hw->slots;
+}
+
+/**
+ * mei_txe_count_full_read_slots - mimics the me device circular buffer
+ *
+ * @dev: the device structure
+ *
+ * returns always buffer size in dwords count
+ */
+static int mei_txe_count_full_read_slots(struct mei_device *dev)
+{
+ /* read buffers has static size */
+ return PAYLOAD_SIZE / 4;
+}
+
+/**
+ * mei_txe_read_hdr - read message header which is always in 4 first bytes
+ *
+ * @dev: the device structure
+ *
+ * returns mei message header
+ */
+
+static u32 mei_txe_read_hdr(const struct mei_device *dev)
+{
+ return mei_txe_out_data_read(dev, 0);
+}
+/**
+ * mei_txe_read - reads a message from the txe device.
+ *
+ * @dev: the device structure
+ * @buf: message buffer will be written
+ * @len: message size will be read
+ *
+ * returns -EINVAL on error wrong argument and 0 on success
+ */
+static int mei_txe_read(struct mei_device *dev,
+ unsigned char *buf, unsigned long len)
+{
+
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 i;
+ u32 *reg_buf = (u32 *)buf;
+ u32 rem = len & 0x3;
+
+ if (WARN_ON(!buf || !len))
+ return -EINVAL;
+
+ dev_dbg(&dev->pdev->dev,
+ "buffer-length = %lu buf[0]0x%08X\n",
+ len, mei_txe_out_data_read(dev, 0));
+
+ for (i = 0; i < len / 4; i++) {
+ /* skip header: index starts from 1 */
+ u32 reg = mei_txe_out_data_read(dev, i + 1);
+ dev_dbg(&dev->pdev->dev, "buf[%d] = 0x%08X\n", i, reg);
+ *reg_buf++ = reg;
+ }
+
+ if (rem) {
+ u32 reg = mei_txe_out_data_read(dev, i + 1);
+ memcpy(reg_buf, &reg, rem);
+ }
+
+ mei_txe_output_ready_set(hw);
+ return 0;
+}
+
+/**
+ * mei_txe_hw_reset - resets host and fw.
+ *
+ * @dev: the device structure
+ * @intr_enable: if interrupt should be enabled after reset.
+ *
+ * returns 0 on success and < 0 in case of error
+ */
+static int mei_txe_hw_reset(struct mei_device *dev, bool intr_enable)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+
+ u32 aliveness_req;
+ /*
+ * read input doorbell to ensure consistency between Bridge and SeC
+ * return value might be garbage return
+ */
+ (void)mei_txe_sec_reg_read_silent(hw, SEC_IPC_INPUT_DOORBELL_REG);
+
+ aliveness_req = mei_txe_aliveness_req_get(dev);
+ hw->aliveness = mei_txe_aliveness_get(dev);
+
+ /* Disable interrupts in this stage we will poll */
+ mei_txe_intr_disable(dev);
+
+ /*
+ * If Aliveness Request and Aliveness Response are not equal then
+ * wait for them to be equal
+ * Since we might have interrupts disabled - poll for it
+ */
+ if (aliveness_req != hw->aliveness)
+ if (mei_txe_aliveness_poll(dev, aliveness_req) < 0) {
+ dev_err(&dev->pdev->dev,
+ "wait for aliveness settle failed ... bailing out\n");
+ return -EIO;
+ }
+
+ /*
+ * If Aliveness Request and Aliveness Response are set then clear them
+ */
+ if (aliveness_req) {
+ mei_txe_aliveness_set(dev, 0);
+ if (mei_txe_aliveness_poll(dev, 0) < 0) {
+ dev_err(&dev->pdev->dev,
+ "wait for aliveness failed ... bailing out\n");
+ return -EIO;
+ }
+ }
+
+ /*
+ * Set rediness RDY_CLR bit
+ */
+ mei_txe_readiness_clear(dev);
+
+ return 0;
+}
+
+/**
+ * mei_txe_hw_start - start the hardware after reset
+ *
+ * @dev: the device structure
+ *
+ * returns 0 on success and < 0 in case of error
+ */
+static int mei_txe_hw_start(struct mei_device *dev)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ int ret;
+
+ u32 hisr;
+
+ /* bring back interrupts */
+ mei_txe_intr_enable(dev);
+
+ ret = mei_txe_readiness_wait(dev);
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev, "wating for readiness failed\n");
+ return ret;
+ }
+
+ /*
+ * If HISR.INT2_STS interrupt status bit is set then clear it.
+ */
+ hisr = mei_txe_br_reg_read(hw, HISR_REG);
+ if (hisr & HISR_INT_2_STS)
+ mei_txe_br_reg_write(hw, HISR_REG, HISR_INT_2_STS);
+
+ /* Clear the interrupt cause of OutputDoorbell */
+ clear_bit(TXE_INTR_OUT_DB_BIT, &hw->intr_cause);
+
+ ret = mei_txe_aliveness_set_sync(dev, 1);
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev, "wait for aliveness failed ... bailing out\n");
+ return ret;
+ }
+
+ /* enable input ready interrupts:
+ * SEC_IPC_HOST_INT_MASK.IPC_INPUT_READY_INT_MASK
+ */
+ mei_txe_input_ready_interrupt_enable(dev);
+
+
+ /* Set the SICR_SEC_IPC_OUTPUT_STATUS.IPC_OUTPUT_READY bit */
+ mei_txe_output_ready_set(hw);
+
+ /* Set bit SICR_HOST_IPC_READINESS.HOST_RDY
+ */
+ mei_txe_readiness_set_host_rdy(dev);
+
+ return 0;
+}
+
+/**
+ * mei_txe_check_and_ack_intrs - translate multi BAR interrupt into
+ * single bit mask and acknowledge the interrupts
+ *
+ * @dev: the device structure
+ * @do_ack: acknowledge interrupts
+ */
+static bool mei_txe_check_and_ack_intrs(struct mei_device *dev, bool do_ack)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ u32 hisr;
+ u32 hhisr;
+ u32 ipc_isr;
+ u32 aliveness;
+ bool generated;
+
+ /* read interrupt registers */
+ hhisr = mei_txe_br_reg_read(hw, HHISR_REG);
+ generated = (hhisr & IPC_HHIER_MSK);
+ if (!generated)
+ goto out;
+
+ hisr = mei_txe_br_reg_read(hw, HISR_REG);
+
+ aliveness = mei_txe_aliveness_get(dev);
+ if (hhisr & IPC_HHIER_SEC && aliveness)
+ ipc_isr = mei_txe_sec_reg_read_silent(hw,
+ SEC_IPC_HOST_INT_STATUS_REG);
+ else
+ ipc_isr = 0;
+
+ generated = generated ||
+ (hisr & HISR_INT_STS_MSK) ||
+ (ipc_isr & SEC_IPC_HOST_INT_STATUS_PENDING);
+
+ if (generated && do_ack) {
+ /* Save the interrupt causes */
+ hw->intr_cause |= hisr & HISR_INT_STS_MSK;
+ if (ipc_isr & SEC_IPC_HOST_INT_STATUS_IN_RDY)
+ hw->intr_cause |= TXE_INTR_IN_READY;
+
+
+ mei_txe_intr_disable(dev);
+ /* Clear the interrupts in hierarchy:
+ * IPC and Bridge, than the High Level */
+ mei_txe_sec_reg_write_silent(hw,
+ SEC_IPC_HOST_INT_STATUS_REG, ipc_isr);
+ mei_txe_br_reg_write(hw, HISR_REG, hisr);
+ mei_txe_br_reg_write(hw, HHISR_REG, hhisr);
+ }
+
+out:
+ return generated;
+}
+
+/**
+ * mei_txe_irq_quick_handler - The ISR of the MEI device
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ */
+irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id)
+{
+ struct mei_device *dev = dev_id;
+
+ if (mei_txe_check_and_ack_intrs(dev, true))
+ return IRQ_WAKE_THREAD;
+ return IRQ_NONE;
+}
+
+
+/**
+ * mei_txe_irq_thread_handler - txe interrupt thread
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ *
+ */
+irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
+{
+ struct mei_device *dev = (struct mei_device *) dev_id;
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+ struct mei_cl_cb complete_list;
+ s32 slots;
+ int rets = 0;
+
+ dev_dbg(&dev->pdev->dev, "irq thread: Interrupt Registers HHISR|HISR|SEC=%02X|%04X|%02X\n",
+ mei_txe_br_reg_read(hw, HHISR_REG),
+ mei_txe_br_reg_read(hw, HISR_REG),
+ mei_txe_sec_reg_read_silent(hw, SEC_IPC_HOST_INT_STATUS_REG));
+
+
+ /* initialize our complete list */
+ mutex_lock(&dev->device_lock);
+ mei_io_list_init(&complete_list);
+
+ if (pci_dev_msi_enabled(dev->pdev))
+ mei_txe_check_and_ack_intrs(dev, true);
+
+ /* show irq events */
+ mei_txe_pending_interrupts(dev);
+
+ hw->aliveness = mei_txe_aliveness_get(dev);
+ hw->readiness = mei_txe_readiness_get(dev);
+
+ /* Readiness:
+ * Detection of TXE driver going through reset
+ * or TXE driver resetting the HECI interface.
+ */
+ if (test_and_clear_bit(TXE_INTR_READINESS_BIT, &hw->intr_cause)) {
+ dev_dbg(&dev->pdev->dev, "Readiness Interrupt was received...\n");
+
+ /* Check if SeC is going through reset */
+ if (mei_txe_readiness_is_sec_rdy(hw->readiness)) {
+ dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
+ dev->recvd_hw_ready = true;
+ } else {
+ dev->recvd_hw_ready = false;
+ if (dev->dev_state != MEI_DEV_RESETTING) {
+
+ dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n");
+ schedule_work(&dev->reset_work);
+ goto end;
+
+ }
+ }
+ wake_up(&dev->wait_hw_ready);
+ }
+
+ /************************************************************/
+ /* Check interrupt cause:
+ * Aliveness: Detection of SeC acknowledge of host request that
+ * it remain alive or host cancellation of that request.
+ */
+
+ if (test_and_clear_bit(TXE_INTR_ALIVENESS_BIT, &hw->intr_cause)) {
+ /* Clear the interrupt cause */
+ dev_dbg(&dev->pdev->dev,
+ "Aliveness Interrupt: Status: %d\n", hw->aliveness);
+ hw->recvd_aliveness = true;
+ if (waitqueue_active(&hw->wait_aliveness))
+ wake_up(&hw->wait_aliveness);
+ }
+
+
+ /* Output Doorbell:
+ * Detection of SeC having sent output to host
+ */
+ slots = mei_count_full_read_slots(dev);
+ if (test_and_clear_bit(TXE_INTR_OUT_DB_BIT, &hw->intr_cause)) {
+ /* Read from TXE */
+ rets = mei_irq_read_handler(dev, &complete_list, &slots);
+ if (rets && dev->dev_state != MEI_DEV_RESETTING) {
+ dev_err(&dev->pdev->dev,
+ "mei_irq_read_handler ret = %d.\n", rets);
+
+ schedule_work(&dev->reset_work);
+ goto end;
+ }
+ }
+ /* Input Ready: Detection if host can write to SeC */
+ if (test_and_clear_bit(TXE_INTR_IN_READY_BIT, &hw->intr_cause)) {
+ dev->hbuf_is_ready = true;
+ hw->slots = dev->hbuf_depth;
+ }
+
+ if (hw->aliveness && dev->hbuf_is_ready) {
+ /* get the real register value */
+ dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
+ rets = mei_irq_write_handler(dev, &complete_list);
+ if (rets && rets != -EMSGSIZE)
+ dev_err(&dev->pdev->dev, "mei_irq_write_handler ret = %d.\n",
+ rets);
+ dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
+ }
+
+ mei_irq_compl_handler(dev, &complete_list);
+
+end:
+ dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets);
+
+ mutex_unlock(&dev->device_lock);
+
+ mei_enable_interrupts(dev);
+ return IRQ_HANDLED;
+}
+
+static const struct mei_hw_ops mei_txe_hw_ops = {
+
+ .host_is_ready = mei_txe_host_is_ready,
+
+ .hw_is_ready = mei_txe_hw_is_ready,
+ .hw_reset = mei_txe_hw_reset,
+ .hw_config = mei_txe_hw_config,
+ .hw_start = mei_txe_hw_start,
+
+ .intr_clear = mei_txe_intr_clear,
+ .intr_enable = mei_txe_intr_enable,
+ .intr_disable = mei_txe_intr_disable,
+
+ .hbuf_free_slots = mei_txe_hbuf_empty_slots,
+ .hbuf_is_ready = mei_txe_is_input_ready,
+ .hbuf_max_len = mei_txe_hbuf_max_len,
+
+ .write = mei_txe_write,
+
+ .rdbuf_full_slots = mei_txe_count_full_read_slots,
+ .read_hdr = mei_txe_read_hdr,
+
+ .read = mei_txe_read,
+
+};
+
+/**
+ * mei_txe_dev_init - allocates and initializes txe hardware specific structure
+ *
+ * @pdev - pci device
+ * returns struct mei_device * on success or NULL;
+ *
+ */
+struct mei_device *mei_txe_dev_init(struct pci_dev *pdev)
+{
+ struct mei_device *dev;
+ struct mei_txe_hw *hw;
+
+ dev = kzalloc(sizeof(struct mei_device) +
+ sizeof(struct mei_txe_hw), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ mei_device_init(dev);
+
+ hw = to_txe_hw(dev);
+
+ init_waitqueue_head(&hw->wait_aliveness);
+
+ dev->ops = &mei_txe_hw_ops;
+
+ dev->pdev = pdev;
+ return dev;
+}
+
+/**
+ * mei_txe_setup_satt2 - SATT2 configuration for DMA support.
+ *
+ * @dev: the device structure
+ * @addr: physical address start of the range
+ * @range: physical range size
+ */
+int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range)
+{
+ struct mei_txe_hw *hw = to_txe_hw(dev);
+
+ u32 lo32 = lower_32_bits(addr);
+ u32 hi32 = upper_32_bits(addr);
+ u32 ctrl;
+
+ /* SATT is limited to 36 Bits */
+ if (hi32 & ~0xF)
+ return -EINVAL;
+
+ /* SATT has to be 16Byte aligned */
+ if (lo32 & 0xF)
+ return -EINVAL;
+
+ /* SATT range has to be 4Bytes aligned */
+ if (range & 0x4)
+ return -EINVAL;
+
+ /* SATT is limited to 32 MB range*/
+ if (range > SATT_RANGE_MAX)
+ return -EINVAL;
+
+ ctrl = SATT2_CTRL_VALID_MSK;
+ ctrl |= hi32 << SATT2_CTRL_BR_BASE_ADDR_REG_SHIFT;
+
+ mei_txe_br_reg_write(hw, SATT2_SAP_SIZE_REG, range);
+ mei_txe_br_reg_write(hw, SATT2_BRG_BA_LSB_REG, lo32);
+ mei_txe_br_reg_write(hw, SATT2_CTRL_REG, ctrl);
+ dev_dbg(&dev->pdev->dev, "SATT2: SAP_SIZE_OFFSET=0x%08X, BRG_BA_LSB_OFFSET=0x%08X, CTRL_OFFSET=0x%08X\n",
+ range, lo32, ctrl);
+
+ return 0;
+}
diff --git a/drivers/misc/mei/hw-txe.h b/drivers/misc/mei/hw-txe.h
new file mode 100644
index 000000000000..0812d98633a4
--- /dev/null
+++ b/drivers/misc/mei/hw-txe.h
@@ -0,0 +1,74 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef _MEI_HW_TXE_H_
+#define _MEI_HW_TXE_H_
+
+#include <linux/irqreturn.h>
+
+#include "hw.h"
+#include "hw-txe-regs.h"
+
+/* Flatten Hierarchy interrupt cause */
+#define TXE_INTR_READINESS_BIT 0 /* HISR_INT_0_STS */
+#define TXE_INTR_READINESS HISR_INT_0_STS
+#define TXE_INTR_ALIVENESS_BIT 1 /* HISR_INT_1_STS */
+#define TXE_INTR_ALIVENESS HISR_INT_1_STS
+#define TXE_INTR_OUT_DB_BIT 2 /* HISR_INT_2_STS */
+#define TXE_INTR_OUT_DB HISR_INT_2_STS
+#define TXE_INTR_IN_READY_BIT 8 /* beyond HISR */
+#define TXE_INTR_IN_READY BIT(8)
+
+/**
+ * struct mei_txe_hw - txe hardware specifics
+ *
+ * @mem_addr: SeC and BRIDGE bars
+ * @aliveness: aliveness (power gating) state of the hardware
+ * @readiness: readiness state of the hardware
+ * @wait_aliveness: aliveness wait queue
+ * @recvd_aliveness: aliveness interrupt was recived
+ * @intr_cause: translated interrupt cause
+ */
+struct mei_txe_hw {
+ void __iomem *mem_addr[NUM_OF_MEM_BARS];
+ u32 aliveness;
+ u32 readiness;
+ u32 slots;
+
+ wait_queue_head_t wait_aliveness;
+ bool recvd_aliveness;
+
+ unsigned long intr_cause;
+};
+
+#define to_txe_hw(dev) (struct mei_txe_hw *)((dev)->hw)
+
+static inline struct mei_device *hw_txe_to_mei(struct mei_txe_hw *hw)
+{
+ return container_of((void *)hw, struct mei_device, hw);
+}
+
+struct mei_device *mei_txe_dev_init(struct pci_dev *pdev);
+
+irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id);
+irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id);
+
+int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req);
+
+int mei_txe_setup_satt2(struct mei_device *dev, phys_addr_t addr, u32 range);
+
+
+#endif /* _MEI_HW_TXE_H_ */
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index dd44e33ad2b6..6b476ab49b2e 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -22,7 +22,7 @@
/*
* Timeouts in Seconds
*/
-#define MEI_INTEROP_TIMEOUT 7 /* Timeout on ready message */
+#define MEI_HW_READY_TIMEOUT 2 /* Timeout on ready message */
#define MEI_CONNECT_TIMEOUT 3 /* HPS: at least 2 seconds */
#define MEI_CL_CONNECT_TIMEOUT 15 /* HPS: Client Connect Timeout */
@@ -31,13 +31,13 @@
#define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */
#define MEI_IAMTHIF_READ_TIMER 10 /* HPS */
+#define MEI_HBM_TIMEOUT 1 /* 1 second */
/*
* MEI Version
*/
#define HBM_MINOR_VERSION 0
#define HBM_MAJOR_VERSION 1
-#define HBM_TIMEOUT 1 /* 1 second */
/* Host bus message command opcode */
#define MEI_HBM_CMD_OP_MSK 0x7f
@@ -89,19 +89,19 @@ enum mei_stop_reason_types {
* Client Connect Status
* used by hbm_client_connect_response.status
*/
-enum client_connect_status_types {
- CCS_SUCCESS = 0x00,
- CCS_NOT_FOUND = 0x01,
- CCS_ALREADY_STARTED = 0x02,
- CCS_OUT_OF_RESOURCES = 0x03,
- CCS_MESSAGE_SMALL = 0x04
+enum mei_cl_connect_status {
+ MEI_CL_CONN_SUCCESS = 0x00,
+ MEI_CL_CONN_NOT_FOUND = 0x01,
+ MEI_CL_CONN_ALREADY_STARTED = 0x02,
+ MEI_CL_CONN_OUT_OF_RESOURCES = 0x03,
+ MEI_CL_CONN_MESSAGE_SMALL = 0x04
};
/*
* Client Disconnect Status
*/
-enum client_disconnect_status_types {
- CDS_SUCCESS = 0x00
+enum mei_cl_disconnect_status {
+ MEI_CL_DISCONN_SUCCESS = 0x00
};
/*
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index cdd31c2a2a2b..4460975c0eef 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -116,7 +116,6 @@ int mei_reset(struct mei_device *dev)
mei_cl_unlink(&dev->wd_cl);
mei_cl_unlink(&dev->iamthif_cl);
mei_amthif_reset_params(dev);
- memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg));
}
@@ -126,7 +125,6 @@ int mei_reset(struct mei_device *dev)
if (ret) {
dev_err(&dev->pdev->dev, "hw_reset failed ret = %d\n", ret);
- dev->dev_state = MEI_DEV_DISABLED;
return ret;
}
@@ -139,7 +137,6 @@ int mei_reset(struct mei_device *dev)
ret = mei_hw_start(dev);
if (ret) {
dev_err(&dev->pdev->dev, "hw_start failed ret = %d\n", ret);
- dev->dev_state = MEI_DEV_DISABLED;
return ret;
}
@@ -149,7 +146,7 @@ int mei_reset(struct mei_device *dev)
ret = mei_hbm_start_req(dev);
if (ret) {
dev_err(&dev->pdev->dev, "hbm_start failed ret = %d\n", ret);
- dev->dev_state = MEI_DEV_DISABLED;
+ dev->dev_state = MEI_DEV_RESETTING;
return ret;
}
@@ -166,6 +163,7 @@ EXPORT_SYMBOL_GPL(mei_reset);
*/
int mei_start(struct mei_device *dev)
{
+ int ret;
mutex_lock(&dev->device_lock);
/* acknowledge interrupt and stop interrupts */
@@ -175,10 +173,18 @@ int mei_start(struct mei_device *dev)
dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
- dev->dev_state = MEI_DEV_INITIALIZING;
dev->reset_count = 0;
- mei_reset(dev);
+ do {
+ dev->dev_state = MEI_DEV_INITIALIZING;
+ ret = mei_reset(dev);
+
+ if (ret == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
+ dev_err(&dev->pdev->dev, "reset failed ret = %d", ret);
+ goto err;
+ }
+ } while (ret);
+ /* we cannot start the device w/o hbm start message completed */
if (dev->dev_state == MEI_DEV_DISABLED) {
dev_err(&dev->pdev->dev, "reset failed");
goto err;
@@ -238,27 +244,40 @@ int mei_restart(struct mei_device *dev)
mutex_unlock(&dev->device_lock);
- if (err || dev->dev_state == MEI_DEV_DISABLED)
+ if (err == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
+ dev_err(&dev->pdev->dev, "device disabled = %d\n", err);
return -ENODEV;
+ }
+
+ /* try to start again */
+ if (err)
+ schedule_work(&dev->reset_work);
+
return 0;
}
EXPORT_SYMBOL_GPL(mei_restart);
-
static void mei_reset_work(struct work_struct *work)
{
struct mei_device *dev =
container_of(work, struct mei_device, reset_work);
+ int ret;
mutex_lock(&dev->device_lock);
- mei_reset(dev);
+ ret = mei_reset(dev);
mutex_unlock(&dev->device_lock);
- if (dev->dev_state == MEI_DEV_DISABLED)
- dev_err(&dev->pdev->dev, "reset failed");
+ if (dev->dev_state == MEI_DEV_DISABLED) {
+ dev_err(&dev->pdev->dev, "device disabled = %d\n", ret);
+ return;
+ }
+
+ /* retry reset in case of failure */
+ if (ret)
+ schedule_work(&dev->reset_work);
}
void mei_stop(struct mei_device *dev)
@@ -269,6 +288,8 @@ void mei_stop(struct mei_device *dev)
mei_nfc_host_exit(dev);
+ mei_cl_bus_remove_devices(dev);
+
mutex_lock(&dev->device_lock);
mei_wd_stop(dev);
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index f0fbb5179f80..29b5af8efb71 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -26,7 +26,6 @@
#include "mei_dev.h"
#include "hbm.h"
-#include "hw-me.h"
#include "client.h"
@@ -161,29 +160,63 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
}
/**
+ * mei_cl_irq_disconnect_rsp - send disconnection response message
+ *
+ * @cl: client
+ * @cb: callback block.
+ * @cmpl_list: complete list.
+ *
+ * returns 0, OK; otherwise, error.
+ */
+static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list)
+{
+ struct mei_device *dev = cl->dev;
+ u32 msg_slots;
+ int slots;
+ int ret;
+
+ slots = mei_hbuf_empty_slots(dev);
+ msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_response));
+
+ if (slots < msg_slots)
+ return -EMSGSIZE;
+
+ ret = mei_hbm_cl_disconnect_rsp(dev, cl);
+
+ cl->state = MEI_FILE_DISCONNECTED;
+ cl->status = 0;
+ list_del(&cb->list);
+ mei_io_cb_free(cb);
+
+ return ret;
+}
+
+
+
+/**
* mei_cl_irq_close - processes close related operation from
* interrupt thread context - send disconnect request
*
* @cl: client
* @cb: callback block.
- * @slots: free slots.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
*/
static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list)
+ struct mei_cl_cb *cmpl_list)
{
struct mei_device *dev = cl->dev;
+ u32 msg_slots;
+ int slots;
- u32 msg_slots =
- mei_data2slots(sizeof(struct hbm_client_connect_request));
+ msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
+ slots = mei_hbuf_empty_slots(dev);
- if (*slots < msg_slots)
+ if (slots < msg_slots)
return -EMSGSIZE;
- *slots -= msg_slots;
-
if (mei_hbm_cl_disconnect_req(dev, cl)) {
cl->status = 0;
cb->buf_idx = 0;
@@ -207,27 +240,23 @@ static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
*
* @cl: client
* @cb: callback block.
- * @slots: free slots.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
*/
static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list)
+ struct mei_cl_cb *cmpl_list)
{
struct mei_device *dev = cl->dev;
- u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
-
+ u32 msg_slots;
+ int slots;
int ret;
+ msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
+ slots = mei_hbuf_empty_slots(dev);
- if (*slots < msg_slots) {
- /* return the cancel routine */
- list_del(&cb->list);
+ if (slots < msg_slots)
return -EMSGSIZE;
- }
-
- *slots -= msg_slots;
ret = mei_hbm_cl_flow_control_req(dev, cl);
if (ret) {
@@ -244,32 +273,30 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
/**
- * mei_cl_irq_ioctl - processes client ioctl related operation from the
- * interrupt thread context - send connection request
+ * mei_cl_irq_connect - send connect request in irq_thread context
*
* @cl: client
* @cb: callback block.
- * @slots: free slots.
* @cmpl_list: complete list.
*
* returns 0, OK; otherwise, error.
*/
-static int mei_cl_irq_ioctl(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list)
+static int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list)
{
struct mei_device *dev = cl->dev;
+ u32 msg_slots;
+ int slots;
int ret;
- u32 msg_slots =
- mei_data2slots(sizeof(struct hbm_client_connect_request));
+ msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
+ slots = mei_hbuf_empty_slots(dev);
- if (*slots < msg_slots) {
- /* return the cancel routine */
- list_del(&cb->list);
- return -EMSGSIZE;
- }
+ if (mei_cl_is_other_connecting(cl))
+ return 0;
- *slots -= msg_slots;
+ if (slots < msg_slots)
+ return -EMSGSIZE;
cl->state = MEI_FILE_CONNECTING;
@@ -323,7 +350,7 @@ int mei_irq_read_handler(struct mei_device *dev,
dev_err(&dev->pdev->dev, "less data available than length=%08x.\n",
*slots);
/* we can't read the message */
- ret = -ERANGE;
+ ret = -ENODATA;
goto end;
}
@@ -409,10 +436,10 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
s32 slots;
int ret;
- if (!mei_hbuf_is_ready(dev)) {
- dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
+
+ if (!mei_hbuf_acquire(dev))
return 0;
- }
+
slots = mei_hbuf_empty_slots(dev);
if (slots <= 0)
return -EMSGSIZE;
@@ -447,29 +474,16 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
if (dev->wd_state == MEI_WD_STOPPING) {
dev->wd_state = MEI_WD_IDLE;
- wake_up_interruptible(&dev->wait_stop_wd);
+ wake_up(&dev->wait_stop_wd);
}
- if (dev->wr_ext_msg.hdr.length) {
- mei_write_message(dev, &dev->wr_ext_msg.hdr,
- dev->wr_ext_msg.data);
- slots -= mei_data2slots(dev->wr_ext_msg.hdr.length);
- dev->wr_ext_msg.hdr.length = 0;
- }
- if (dev->dev_state == MEI_DEV_ENABLED) {
+ if (mei_cl_is_connected(&dev->wd_cl)) {
if (dev->wd_pending &&
mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
- if (mei_wd_send(dev))
- dev_dbg(&dev->pdev->dev, "wd send failed.\n");
- else if (mei_cl_flow_ctrl_reduce(&dev->wd_cl))
- return -ENODEV;
-
+ ret = mei_wd_send(dev);
+ if (ret)
+ return ret;
dev->wd_pending = false;
-
- if (dev->wd_state == MEI_WD_RUNNING)
- slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
- else
- slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE);
}
}
@@ -484,28 +498,31 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
switch (cb->fop_type) {
case MEI_FOP_CLOSE:
/* send disconnect message */
- ret = mei_cl_irq_close(cl, cb, &slots, cmpl_list);
+ ret = mei_cl_irq_close(cl, cb, cmpl_list);
if (ret)
return ret;
break;
case MEI_FOP_READ:
/* send flow control message */
- ret = mei_cl_irq_read(cl, cb, &slots, cmpl_list);
+ ret = mei_cl_irq_read(cl, cb, cmpl_list);
if (ret)
return ret;
break;
- case MEI_FOP_IOCTL:
+ case MEI_FOP_CONNECT:
/* connect message */
- if (mei_cl_is_other_connecting(cl))
- continue;
- ret = mei_cl_irq_ioctl(cl, cb, &slots, cmpl_list);
+ ret = mei_cl_irq_connect(cl, cb, cmpl_list);
if (ret)
return ret;
break;
-
+ case MEI_FOP_DISCONNECT_RSP:
+ /* send disconnect resp */
+ ret = mei_cl_irq_disconnect_rsp(cl, cb, cmpl_list);
+ if (ret)
+ return ret;
+ break;
default:
BUG();
}
@@ -518,11 +535,9 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
if (cl == NULL)
continue;
if (cl == &dev->iamthif_cl)
- ret = mei_amthif_irq_write_complete(cl, cb,
- &slots, cmpl_list);
+ ret = mei_amthif_irq_write(cl, cb, cmpl_list);
else
- ret = mei_cl_irq_write_complete(cl, cb,
- &slots, cmpl_list);
+ ret = mei_cl_irq_write(cl, cb, cmpl_list);
if (ret)
return ret;
}
@@ -541,8 +556,7 @@ EXPORT_SYMBOL_GPL(mei_irq_write_handler);
void mei_timer(struct work_struct *work)
{
unsigned long timeout;
- struct mei_cl *cl_pos = NULL;
- struct mei_cl *cl_next = NULL;
+ struct mei_cl *cl;
struct mei_cl_cb *cb_pos = NULL;
struct mei_cl_cb *cb_next = NULL;
@@ -570,9 +584,9 @@ void mei_timer(struct work_struct *work)
goto out;
/*** connect/disconnect timeouts ***/
- list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
- if (cl_pos->timer_count) {
- if (--cl_pos->timer_count == 0) {
+ list_for_each_entry(cl, &dev->file_list, link) {
+ if (cl->timer_count) {
+ if (--cl->timer_count == 0) {
dev_err(&dev->pdev->dev, "timer: connect/disconnect timeout.\n");
mei_reset(dev);
goto out;
@@ -580,6 +594,9 @@ void mei_timer(struct work_struct *work)
}
}
+ if (!mei_cl_is_connected(&dev->iamthif_cl))
+ goto out;
+
if (dev->iamthif_stall_timer) {
if (--dev->iamthif_stall_timer == 0) {
dev_err(&dev->pdev->dev, "timer: amthif hanged.\n");
@@ -619,10 +636,10 @@ void mei_timer(struct work_struct *work)
list_for_each_entry_safe(cb_pos, cb_next,
&dev->amthif_rd_complete_list.list, list) {
- cl_pos = cb_pos->file_object->private_data;
+ cl = cb_pos->file_object->private_data;
/* Finding the AMTHI entry. */
- if (cl_pos == &dev->iamthif_cl)
+ if (cl == &dev->iamthif_cl)
list_del(&cb_pos->list);
}
mei_io_cb_free(dev->iamthif_current_cb);
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 5424f8ff3f7f..b35594dbf52f 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -13,9 +13,6 @@
* more details.
*
*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -40,7 +37,6 @@
#include <linux/mei.h>
#include "mei_dev.h"
-#include "hw-me.h"
#include "client.h"
/**
@@ -129,17 +125,11 @@ static int mei_release(struct inode *inode, struct file *file)
}
if (cl->state == MEI_FILE_CONNECTED) {
cl->state = MEI_FILE_DISCONNECTING;
- dev_dbg(&dev->pdev->dev,
- "disconnecting client host client = %d, "
- "ME client = %d\n",
- cl->host_client_id,
- cl->me_client_id);
+ cl_dbg(dev, cl, "disconnecting\n");
rets = mei_cl_disconnect(cl);
}
mei_cl_flush_queues(cl);
- dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n",
- cl->host_client_id,
- cl->me_client_id);
+ cl_dbg(dev, cl, "removing\n");
mei_cl_unlink(cl);
@@ -284,6 +274,7 @@ copy_buffer:
length = min_t(size_t, length, cb->buf_idx - *offset);
if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
+ dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
goto free;
}
@@ -340,7 +331,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
id = mei_me_cl_by_id(dev, cl->me_client_id);
if (id < 0) {
- rets = -ENODEV;
+ rets = -ENOTTY;
goto out;
}
@@ -404,7 +395,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
rets = copy_from_user(write_cb->request_buffer.data, ubuf, length);
if (rets) {
- dev_err(&dev->pdev->dev, "failed to copy data from userland\n");
+ dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
rets = -EFAULT;
goto out;
}
@@ -471,7 +462,7 @@ static int mei_ioctl_connect_client(struct file *file,
if (i < 0 || dev->me_clients[i].props.fixed_address) {
dev_dbg(&dev->pdev->dev, "Cannot connect to FW Client UUID = %pUl\n",
&data->in_client_uuid);
- rets = -ENODEV;
+ rets = -ENOTTY;
goto end;
}
@@ -569,7 +560,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
dev_dbg(&dev->pdev->dev, "copy connect data from user\n");
if (copy_from_user(connect_data, (char __user *)data,
sizeof(struct mei_connect_client_data))) {
- dev_err(&dev->pdev->dev, "failed to copy data from userland\n");
+ dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
rets = -EFAULT;
goto out;
}
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index f7de95b4cdd9..94a516716d22 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -24,7 +24,6 @@
#include <linux/mei_cl_bus.h>
#include "hw.h"
-#include "hw-me-regs.h"
#include "hbm.h"
/*
@@ -130,16 +129,18 @@ enum mei_wd_states {
/**
* enum mei_cb_file_ops - file operation associated with the callback
- * @MEI_FOP_READ - read
- * @MEI_FOP_WRITE - write
- * @MEI_FOP_IOCTL - ioctl
- * @MEI_FOP_OPEN - open
- * @MEI_FOP_CLOSE - close
+ * @MEI_FOP_READ - read
+ * @MEI_FOP_WRITE - write
+ * @MEI_FOP_CONNECT - connect
+ * @MEI_FOP_DISCONNECT_RSP - disconnect response
+ * @MEI_FOP_OPEN - open
+ * @MEI_FOP_CLOSE - close
*/
enum mei_cb_file_ops {
MEI_FOP_READ = 0,
MEI_FOP_WRITE,
- MEI_FOP_IOCTL,
+ MEI_FOP_CONNECT,
+ MEI_FOP_DISCONNECT_RSP,
MEI_FOP_OPEN,
MEI_FOP_CLOSE
};
@@ -236,20 +237,20 @@ struct mei_cl {
*/
struct mei_hw_ops {
- bool (*host_is_ready) (struct mei_device *dev);
+ bool (*host_is_ready)(struct mei_device *dev);
- bool (*hw_is_ready) (struct mei_device *dev);
- int (*hw_reset) (struct mei_device *dev, bool enable);
- int (*hw_start) (struct mei_device *dev);
- void (*hw_config) (struct mei_device *dev);
+ bool (*hw_is_ready)(struct mei_device *dev);
+ int (*hw_reset)(struct mei_device *dev, bool enable);
+ int (*hw_start)(struct mei_device *dev);
+ void (*hw_config)(struct mei_device *dev);
- void (*intr_clear) (struct mei_device *dev);
- void (*intr_enable) (struct mei_device *dev);
- void (*intr_disable) (struct mei_device *dev);
+ void (*intr_clear)(struct mei_device *dev);
+ void (*intr_enable)(struct mei_device *dev);
+ void (*intr_disable)(struct mei_device *dev);
- int (*hbuf_free_slots) (struct mei_device *dev);
- bool (*hbuf_is_ready) (struct mei_device *dev);
- size_t (*hbuf_max_len) (const struct mei_device *dev);
+ int (*hbuf_free_slots)(struct mei_device *dev);
+ bool (*hbuf_is_ready)(struct mei_device *dev);
+ size_t (*hbuf_max_len)(const struct mei_device *dev);
int (*write)(struct mei_device *dev,
struct mei_msg_hdr *hdr,
@@ -258,7 +259,7 @@ struct mei_hw_ops {
int (*rdbuf_full_slots)(struct mei_device *dev);
u32 (*read_hdr)(const struct mei_device *dev);
- int (*read) (struct mei_device *dev,
+ int (*read)(struct mei_device *dev,
unsigned char *buf, unsigned long len);
};
@@ -294,6 +295,7 @@ int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
void mei_cl_bus_rx_event(struct mei_cl *cl);
+void mei_cl_bus_remove_devices(struct mei_device *dev);
int mei_cl_bus_init(void);
void mei_cl_bus_exit(void);
@@ -339,7 +341,6 @@ struct mei_cl_device {
* @hbuf_depth - depth of hardware host/write buffer is slots
* @hbuf_is_ready - query if the host host/write buffer is ready
* @wr_msg - the buffer for hbm control messages
- * @wr_ext_msg - the buffer for hbm control responses (set in read cycle)
*/
struct mei_device {
struct pci_dev *pdev; /* pointer to pci device struct */
@@ -394,11 +395,6 @@ struct mei_device {
unsigned char data[128];
} wr_msg;
- struct {
- struct mei_msg_hdr hdr;
- unsigned char data[4]; /* All HBM messages are 4 bytes */
- } wr_ext_msg; /* for control responses */
-
struct hbm_version version;
struct mei_me_client *me_clients; /* Note: memory has to be allocated */
@@ -518,8 +514,8 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
void mei_amthif_run_next_cmd(struct mei_device *dev);
-int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
- s32 *slots, struct mei_cl_cb *cmpl_list);
+int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+ struct mei_cl_cb *cmpl_list);
void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb);
int mei_amthif_irq_read_msg(struct mei_device *dev,
@@ -546,7 +542,7 @@ int mei_wd_host_init(struct mei_device *dev);
* once we got connection to the WD Client
* @dev - mei device
*/
-void mei_watchdog_register(struct mei_device *dev);
+int mei_watchdog_register(struct mei_device *dev);
/*
* mei_watchdog_unregister - Unregistering watchdog interface
* @dev - mei device
@@ -633,6 +629,8 @@ static inline int mei_count_full_read_slots(struct mei_device *dev)
return dev->ops->rdbuf_full_slots(dev);
}
+bool mei_hbuf_acquire(struct mei_device *dev);
+
#if IS_ENABLED(CONFIG_DEBUG_FS)
int mei_dbgfs_register(struct mei_device *dev, const char *name);
void mei_dbgfs_deregister(struct mei_device *dev);
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index a58320c0c049..3095fc514a65 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -364,7 +364,7 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
if (!wait_event_interruptible_timeout(ndev->send_wq,
ndev->recv_req_id == ndev->req_id, HZ)) {
dev_err(&dev->pdev->dev, "NFC MEI command timeout\n");
- err = -ETIMEDOUT;
+ err = -ETIME;
} else {
ndev->req_id++;
}
@@ -502,7 +502,7 @@ int mei_nfc_host_init(struct mei_device *dev)
i = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
if (i < 0) {
dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
- ret = -ENOENT;
+ ret = -ENOTTY;
goto err;
}
@@ -520,7 +520,7 @@ int mei_nfc_host_init(struct mei_device *dev)
i = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
if (i < 0) {
dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
- ret = -ENOENT;
+ ret = -ENOTTY;
goto err;
}
@@ -552,13 +552,7 @@ err:
void mei_nfc_host_exit(struct mei_device *dev)
{
struct mei_nfc_dev *ndev = &nfc_dev;
-
cancel_work_sync(&ndev->init_work);
+}
- mutex_lock(&dev->device_lock);
- if (ndev->cl && ndev->cl->device)
- mei_cl_remove_device(ndev->cl->device);
- mei_nfc_free(ndev);
- mutex_unlock(&dev->device_lock);
-}
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index ddadd08956f4..1c8fd3a3e135 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -13,9 +13,6 @@
* more details.
*
*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -27,7 +24,6 @@
#include <linux/aio.h>
#include <linux/pci.h>
#include <linux/poll.h>
-#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/sched.h>
@@ -40,11 +36,12 @@
#include <linux/mei.h>
#include "mei_dev.h"
-#include "hw-me.h"
#include "client.h"
+#include "hw-me-regs.h"
+#include "hw-me.h"
/* mei_pci_tbl - PCI Device ID Table */
-static DEFINE_PCI_DEVICE_TABLE(mei_me_pci_tbl) = {
+static const struct pci_device_id mei_me_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
@@ -270,7 +267,7 @@ static void mei_me_remove(struct pci_dev *pdev)
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int mei_me_pci_suspend(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
@@ -330,11 +327,12 @@ static int mei_me_pci_resume(struct device *device)
return 0;
}
+
static SIMPLE_DEV_PM_OPS(mei_me_pm_ops, mei_me_pci_suspend, mei_me_pci_resume);
#define MEI_ME_PM_OPS (&mei_me_pm_ops)
#else
#define MEI_ME_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
/*
* PCI driver structure
*/
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
new file mode 100644
index 000000000000..ad3adb009a1e
--- /dev/null
+++ b/drivers/misc/mei/pci-txe.c
@@ -0,0 +1,293 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.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/init.h>
+#include <linux/sched.h>
+#include <linux/uuid.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+
+#include <linux/mei.h>
+
+
+#include "mei_dev.h"
+#include "hw-txe.h"
+
+static const struct pci_device_id mei_txe_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0F18)}, /* Baytrail */
+ {0, }
+};
+MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl);
+
+
+static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw)
+{
+ int i;
+ for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
+ if (hw->mem_addr[i]) {
+ pci_iounmap(pdev, hw->mem_addr[i]);
+ hw->mem_addr[i] = NULL;
+ }
+ }
+}
+/**
+ * mei_probe - Device Initialization Routine
+ *
+ * @pdev: PCI device structure
+ * @ent: entry in mei_txe_pci_tbl
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct mei_device *dev;
+ struct mei_txe_hw *hw;
+ int err;
+ int i;
+
+ /* enable pci dev */
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to enable pci device.\n");
+ goto end;
+ }
+ /* set PCI host mastering */
+ pci_set_master(pdev);
+ /* pci request regions for mei driver */
+ err = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (err) {
+ dev_err(&pdev->dev, "failed to get pci regions.\n");
+ goto disable_device;
+ }
+
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
+ if (err) {
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err) {
+ dev_err(&pdev->dev, "No suitable DMA available.\n");
+ goto release_regions;
+ }
+ }
+
+ /* allocates and initializes the mei dev structure */
+ dev = mei_txe_dev_init(pdev);
+ if (!dev) {
+ err = -ENOMEM;
+ goto release_regions;
+ }
+ hw = to_txe_hw(dev);
+
+ /* mapping IO device memory */
+ for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
+ hw->mem_addr[i] = pci_iomap(pdev, i, 0);
+ if (!hw->mem_addr[i]) {
+ dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
+ err = -ENOMEM;
+ goto free_device;
+ }
+ }
+
+
+ pci_enable_msi(pdev);
+
+ /* clear spurious interrupts */
+ mei_clear_interrupts(dev);
+
+ /* request and enable interrupt */
+ if (pci_dev_msi_enabled(pdev))
+ err = request_threaded_irq(pdev->irq,
+ NULL,
+ mei_txe_irq_thread_handler,
+ IRQF_ONESHOT, KBUILD_MODNAME, dev);
+ else
+ err = request_threaded_irq(pdev->irq,
+ mei_txe_irq_quick_handler,
+ mei_txe_irq_thread_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+ if (err) {
+ dev_err(&pdev->dev, "mei: request_threaded_irq failure. irq = %d\n",
+ pdev->irq);
+ goto free_device;
+ }
+
+ if (mei_start(dev)) {
+ dev_err(&pdev->dev, "init hw failure.\n");
+ err = -ENODEV;
+ goto release_irq;
+ }
+
+ err = mei_register(dev);
+ if (err)
+ goto release_irq;
+
+ pci_set_drvdata(pdev, dev);
+
+ return 0;
+
+release_irq:
+
+ mei_cancel_work(dev);
+
+ /* disable interrupts */
+ mei_disable_interrupts(dev);
+
+ free_irq(pdev->irq, dev);
+ pci_disable_msi(pdev);
+
+free_device:
+ mei_txe_pci_iounmap(pdev, hw);
+
+ kfree(dev);
+release_regions:
+ pci_release_regions(pdev);
+disable_device:
+ pci_disable_device(pdev);
+end:
+ dev_err(&pdev->dev, "initialization failed.\n");
+ return err;
+}
+
+/**
+ * mei_remove - Device Removal Routine
+ *
+ * @pdev: PCI device structure
+ *
+ * mei_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.
+ */
+static void mei_txe_remove(struct pci_dev *pdev)
+{
+ struct mei_device *dev;
+ struct mei_txe_hw *hw;
+
+ dev = pci_get_drvdata(pdev);
+ if (!dev) {
+ dev_err(&pdev->dev, "mei: dev =NULL\n");
+ return;
+ }
+
+ hw = to_txe_hw(dev);
+
+ mei_stop(dev);
+
+ /* disable interrupts */
+ mei_disable_interrupts(dev);
+ free_irq(pdev->irq, dev);
+ pci_disable_msi(pdev);
+
+ pci_set_drvdata(pdev, NULL);
+
+ mei_txe_pci_iounmap(pdev, hw);
+
+ mei_deregister(dev);
+
+ kfree(dev);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+
+#ifdef CONFIG_PM_SLEEP
+static int mei_txe_pci_suspend(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct mei_device *dev = pci_get_drvdata(pdev);
+
+ if (!dev)
+ return -ENODEV;
+
+ dev_dbg(&pdev->dev, "suspend\n");
+
+ mei_stop(dev);
+
+ mei_disable_interrupts(dev);
+
+ free_irq(pdev->irq, dev);
+ pci_disable_msi(pdev);
+
+ return 0;
+}
+
+static int mei_txe_pci_resume(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct mei_device *dev;
+ int err;
+
+ dev = pci_get_drvdata(pdev);
+ if (!dev)
+ return -ENODEV;
+
+ pci_enable_msi(pdev);
+
+ mei_clear_interrupts(dev);
+
+ /* request and enable interrupt */
+ if (pci_dev_msi_enabled(pdev))
+ err = request_threaded_irq(pdev->irq,
+ NULL,
+ mei_txe_irq_thread_handler,
+ IRQF_ONESHOT, KBUILD_MODNAME, dev);
+ else
+ err = request_threaded_irq(pdev->irq,
+ mei_txe_irq_quick_handler,
+ mei_txe_irq_thread_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+ if (err) {
+ dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
+ pdev->irq);
+ return err;
+ }
+
+ err = mei_restart(dev);
+
+ return err;
+}
+
+static SIMPLE_DEV_PM_OPS(mei_txe_pm_ops,
+ mei_txe_pci_suspend,
+ mei_txe_pci_resume);
+
+#define MEI_TXE_PM_OPS (&mei_txe_pm_ops)
+#else
+#define MEI_TXE_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+/*
+ * PCI driver structure
+ */
+static struct pci_driver mei_txe_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = mei_txe_pci_tbl,
+ .probe = mei_txe_probe,
+ .remove = mei_txe_remove,
+ .shutdown = mei_txe_remove,
+ .driver.pm = MEI_TXE_PM_OPS,
+};
+
+module_pci_driver(mei_txe_driver);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel(R) Trusted Execution Environment Interface");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index f70945ed96f6..ebf1cbc198fd 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -25,7 +25,6 @@
#include "mei_dev.h"
#include "hbm.h"
-#include "hw-me.h"
#include "client.h"
static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
@@ -53,7 +52,7 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
*
* @dev: the device structure
*
- * returns -ENENT if wd client cannot be found
+ * returns -ENOTTY if wd client cannot be found
* -EIO if write has failed
* 0 on success
*/
@@ -73,7 +72,7 @@ int mei_wd_host_init(struct mei_device *dev)
id = mei_me_cl_by_uuid(dev, &mei_wd_guid);
if (id < 0) {
dev_info(&dev->pdev->dev, "wd: failed to find the client\n");
- return id;
+ return -ENOTTY;
}
cl->me_client_id = dev->me_clients[id].client_id;
@@ -87,15 +86,20 @@ int mei_wd_host_init(struct mei_device *dev)
cl->state = MEI_FILE_CONNECTING;
- if (mei_hbm_cl_connect_req(dev, cl)) {
- dev_err(&dev->pdev->dev, "wd: failed to connect to the client\n");
- cl->state = MEI_FILE_DISCONNECTED;
- cl->host_client_id = 0;
- return -EIO;
+ ret = mei_cl_connect(cl, NULL);
+
+ if (ret) {
+ dev_err(&dev->pdev->dev, "wd: failed to connect = %d\n", ret);
+ mei_cl_unlink(cl);
+ return ret;
}
- cl->timer_count = MEI_CONNECT_TIMEOUT;
- return 0;
+ ret = mei_watchdog_register(dev);
+ if (ret) {
+ mei_cl_disconnect(cl);
+ mei_cl_unlink(cl);
+ }
+ return ret;
}
/**
@@ -106,13 +110,16 @@ int mei_wd_host_init(struct mei_device *dev)
* returns 0 if success,
* -EIO when message send fails
* -EINVAL when invalid message is to be sent
+ * -ENODEV on flow control failure
*/
int mei_wd_send(struct mei_device *dev)
{
+ struct mei_cl *cl = &dev->wd_cl;
struct mei_msg_hdr hdr;
+ int ret;
- hdr.host_addr = dev->wd_cl.host_client_id;
- hdr.me_addr = dev->wd_cl.me_client_id;
+ hdr.host_addr = cl->host_client_id;
+ hdr.me_addr = cl->me_client_id;
hdr.msg_complete = 1;
hdr.reserved = 0;
hdr.internal = 0;
@@ -121,10 +128,24 @@ int mei_wd_send(struct mei_device *dev)
hdr.length = MEI_WD_START_MSG_SIZE;
else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
hdr.length = MEI_WD_STOP_MSG_SIZE;
- else
+ else {
+ dev_err(&dev->pdev->dev, "wd: invalid message is to be sent, aborting\n");
return -EINVAL;
+ }
- return mei_write_message(dev, &hdr, dev->wd_data);
+ ret = mei_write_message(dev, &hdr, dev->wd_data);
+ if (ret) {
+ dev_err(&dev->pdev->dev, "wd: write message failed\n");
+ return ret;
+ }
+
+ ret = mei_cl_flow_ctrl_reduce(cl);
+ if (ret) {
+ dev_err(&dev->pdev->dev, "wd: flow_ctrl_reduce failed.\n");
+ return ret;
+ }
+
+ return 0;
}
/**
@@ -133,9 +154,11 @@ int mei_wd_send(struct mei_device *dev)
* @dev: the device structure
* @preserve: indicate if to keep the timeout value
*
- * returns 0 if success,
- * -EIO when message send fails
+ * returns 0 if success
+ * on error:
+ * -EIO when message send fails
* -EINVAL when invalid message is to be sent
+ * -ETIME on message timeout
*/
int mei_wd_stop(struct mei_device *dev)
{
@@ -151,20 +174,12 @@ int mei_wd_stop(struct mei_device *dev)
ret = mei_cl_flow_ctrl_creds(&dev->wd_cl);
if (ret < 0)
- goto out;
-
- if (ret && dev->hbuf_is_ready) {
- ret = 0;
- dev->hbuf_is_ready = false;
-
- if (!mei_wd_send(dev)) {
- ret = mei_cl_flow_ctrl_reduce(&dev->wd_cl);
- if (ret)
- goto out;
- } else {
- dev_err(&dev->pdev->dev, "wd: send stop failed\n");
- }
+ goto err;
+ if (ret && mei_hbuf_acquire(dev)) {
+ ret = mei_wd_send(dev);
+ if (ret)
+ goto err;
dev->wd_pending = false;
} else {
dev->wd_pending = true;
@@ -172,21 +187,21 @@ int mei_wd_stop(struct mei_device *dev)
mutex_unlock(&dev->device_lock);
- ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
- dev->wd_state == MEI_WD_IDLE,
- msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
+ ret = wait_event_timeout(dev->wait_stop_wd,
+ dev->wd_state == MEI_WD_IDLE,
+ msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
mutex_lock(&dev->device_lock);
- if (dev->wd_state == MEI_WD_IDLE) {
- dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
- ret = 0;
- } else {
- if (!ret)
- ret = -ETIMEDOUT;
+ if (dev->wd_state != MEI_WD_IDLE) {
+ /* timeout */
+ ret = -ETIME;
dev_warn(&dev->pdev->dev,
"wd: stop failed to complete ret=%d.\n", ret);
+ goto err;
}
-
-out:
+ dev_dbg(&dev->pdev->dev, "wd: stop completed after %u msec\n",
+ MEI_WD_STOP_TIMEOUT - jiffies_to_msecs(ret));
+ return 0;
+err:
return ret;
}
@@ -260,8 +275,8 @@ static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
*/
static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
{
- int ret = 0;
struct mei_device *dev;
+ int ret;
dev = watchdog_get_drvdata(wd_dev);
if (!dev)
@@ -277,25 +292,18 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
dev->wd_state = MEI_WD_RUNNING;
+ ret = mei_cl_flow_ctrl_creds(&dev->wd_cl);
+ if (ret < 0)
+ goto end;
/* Check if we can send the ping to HW*/
- if (dev->hbuf_is_ready && mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
+ if (ret && mei_hbuf_acquire(dev)) {
- dev->hbuf_is_ready = false;
dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
- if (mei_wd_send(dev)) {
- dev_err(&dev->pdev->dev, "wd: send failed.\n");
- ret = -EIO;
+ ret = mei_wd_send(dev);
+ if (ret)
goto end;
- }
-
- if (mei_cl_flow_ctrl_reduce(&dev->wd_cl)) {
- dev_err(&dev->pdev->dev,
- "wd: mei_cl_flow_ctrl_reduce() failed.\n");
- ret = -EIO;
- goto end;
- }
-
+ dev->wd_pending = false;
} else {
dev->wd_pending = true;
}
@@ -363,17 +371,25 @@ static struct watchdog_device amt_wd_dev = {
};
-void mei_watchdog_register(struct mei_device *dev)
+int mei_watchdog_register(struct mei_device *dev)
{
- if (watchdog_register_device(&amt_wd_dev)) {
- dev_err(&dev->pdev->dev,
- "wd: unable to register watchdog device.\n");
- return;
+
+ int ret;
+
+ /* unlock to perserve correct locking order */
+ mutex_unlock(&dev->device_lock);
+ ret = watchdog_register_device(&amt_wd_dev);
+ mutex_lock(&dev->device_lock);
+ if (ret) {
+ dev_err(&dev->pdev->dev, "wd: unable to register watchdog device = %d.\n",
+ ret);
+ return ret;
}
dev_dbg(&dev->pdev->dev,
"wd: successfully register watchdog interface.\n");
watchdog_set_drvdata(&amt_wd_dev, dev);
+ return 0;
}
void mei_watchdog_unregister(struct mei_device *dev)
diff --git a/drivers/misc/mic/card/mic_device.h b/drivers/misc/mic/card/mic_device.h
index 347b9b3b7916..306f502be95e 100644
--- a/drivers/misc/mic/card/mic_device.h
+++ b/drivers/misc/mic/card/mic_device.h
@@ -29,6 +29,7 @@
#include <linux/workqueue.h>
#include <linux/io.h>
+#include <linux/irqreturn.h>
/**
* struct mic_intr_info - Contains h/w specific interrupt sources info
diff --git a/drivers/misc/mic/host/mic_device.h b/drivers/misc/mic/host/mic_device.h
index 1a6edce2ecde..0398c696d257 100644
--- a/drivers/misc/mic/host/mic_device.h
+++ b/drivers/misc/mic/host/mic_device.h
@@ -24,6 +24,7 @@
#include <linux/cdev.h>
#include <linux/idr.h>
#include <linux/notifier.h>
+#include <linux/irqreturn.h>
#include "mic_intr.h"
diff --git a/drivers/misc/mic/host/mic_intr.c b/drivers/misc/mic/host/mic_intr.c
index f9c29bc918bc..dbc5afde1392 100644
--- a/drivers/misc/mic/host/mic_intr.c
+++ b/drivers/misc/mic/host/mic_intr.c
@@ -194,7 +194,7 @@ static int mic_setup_msix(struct mic_device *mdev, struct pci_dev *pdev)
for (i = 0; i < MIC_MIN_MSIX; i++)
mdev->irq_info.msix_entries[i].entry = i;
- rc = pci_enable_msix(pdev, mdev->irq_info.msix_entries,
+ rc = pci_enable_msix_exact(pdev, mdev->irq_info.msix_entries,
MIC_MIN_MSIX);
if (rc) {
dev_dbg(&pdev->dev, "Error enabling MSIx. rc = %d\n", rc);
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c
index a5925f7f17f6..956597321d2a 100644
--- a/drivers/misc/pch_phub.c
+++ b/drivers/misc/pch_phub.c
@@ -636,6 +636,7 @@ static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr,
u8 mac[ETH_ALEN];
ssize_t rom_size;
struct pch_phub_reg *chip = dev_get_drvdata(dev);
+ int ret;
if (!mac_pton(buf, mac))
return -EINVAL;
@@ -644,8 +645,10 @@ static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr,
if (!chip->pch_phub_extrom_base_address)
return -ENOMEM;
- pch_phub_write_gbe_mac_addr(chip, mac);
+ ret = pch_phub_write_gbe_mac_addr(chip, mac);
pci_unmap_rom(chip->pdev, chip->pch_phub_extrom_base_address);
+ if (ret)
+ return ret;
return count;
}
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c
index b9e2000969f0..95c894482fdd 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -240,7 +240,7 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
nid = cpu_to_node(cpu);
page = alloc_pages_exact_node(nid,
- GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+ GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
pg_order);
if (page == NULL) {
dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
index afe66571ce0b..21181fa243df 100644
--- a/drivers/misc/sram.c
+++ b/drivers/misc/sram.c
@@ -24,6 +24,9 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/list.h>
+#include <linux/list_sort.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -36,14 +39,35 @@ struct sram_dev {
struct clk *clk;
};
+struct sram_reserve {
+ struct list_head list;
+ u32 start;
+ u32 size;
+};
+
+static int sram_reserve_cmp(void *priv, struct list_head *a,
+ struct list_head *b)
+{
+ struct sram_reserve *ra = list_entry(a, struct sram_reserve, list);
+ struct sram_reserve *rb = list_entry(b, struct sram_reserve, list);
+
+ return ra->start - rb->start;
+}
+
static int sram_probe(struct platform_device *pdev)
{
void __iomem *virt_base;
struct sram_dev *sram;
struct resource *res;
- unsigned long size;
+ struct device_node *np = pdev->dev.of_node, *child;
+ unsigned long size, cur_start, cur_size;
+ struct sram_reserve *rblocks, *block;
+ struct list_head reserve_list;
+ unsigned int nblocks;
int ret;
+ INIT_LIST_HEAD(&reserve_list);
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
virt_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(virt_base))
@@ -65,19 +89,106 @@ static int sram_probe(struct platform_device *pdev)
if (!sram->pool)
return -ENOMEM;
- ret = gen_pool_add_virt(sram->pool, (unsigned long)virt_base,
- res->start, size, -1);
- if (ret < 0) {
- if (sram->clk)
- clk_disable_unprepare(sram->clk);
- return ret;
+ /*
+ * We need an additional block to mark the end of the memory region
+ * after the reserved blocks from the dt are processed.
+ */
+ nblocks = (np) ? of_get_available_child_count(np) + 1 : 1;
+ rblocks = kmalloc((nblocks) * sizeof(*rblocks), GFP_KERNEL);
+ if (!rblocks) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ block = &rblocks[0];
+ for_each_available_child_of_node(np, child) {
+ struct resource child_res;
+
+ ret = of_address_to_resource(child, 0, &child_res);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "could not get address for node %s\n",
+ child->full_name);
+ goto err_chunks;
+ }
+
+ if (child_res.start < res->start || child_res.end > res->end) {
+ dev_err(&pdev->dev,
+ "reserved block %s outside the sram area\n",
+ child->full_name);
+ ret = -EINVAL;
+ goto err_chunks;
+ }
+
+ block->start = child_res.start - res->start;
+ block->size = resource_size(&child_res);
+ list_add_tail(&block->list, &reserve_list);
+
+ dev_dbg(&pdev->dev, "found reserved block 0x%x-0x%x\n",
+ block->start,
+ block->start + block->size);
+
+ block++;
+ }
+
+ /* the last chunk marks the end of the region */
+ rblocks[nblocks - 1].start = size;
+ rblocks[nblocks - 1].size = 0;
+ list_add_tail(&rblocks[nblocks - 1].list, &reserve_list);
+
+ list_sort(NULL, &reserve_list, sram_reserve_cmp);
+
+ cur_start = 0;
+
+ list_for_each_entry(block, &reserve_list, list) {
+ /* can only happen if sections overlap */
+ if (block->start < cur_start) {
+ dev_err(&pdev->dev,
+ "block at 0x%x starts after current offset 0x%lx\n",
+ block->start, cur_start);
+ ret = -EINVAL;
+ goto err_chunks;
+ }
+
+ /* current start is in a reserved block, so continue after it */
+ if (block->start == cur_start) {
+ cur_start = block->start + block->size;
+ continue;
+ }
+
+ /*
+ * allocate the space between the current starting
+ * address and the following reserved block, or the
+ * end of the region.
+ */
+ cur_size = block->start - cur_start;
+
+ dev_dbg(&pdev->dev, "adding chunk 0x%lx-0x%lx\n",
+ cur_start, cur_start + cur_size);
+ ret = gen_pool_add_virt(sram->pool,
+ (unsigned long)virt_base + cur_start,
+ res->start + cur_start, cur_size, -1);
+ if (ret < 0)
+ goto err_chunks;
+
+ /* next allocation after this reserved block */
+ cur_start = block->start + block->size;
}
+ kfree(rblocks);
+
platform_set_drvdata(pdev, sram);
dev_dbg(&pdev->dev, "SRAM pool: %ld KiB @ 0x%p\n", size / 1024, virt_base);
return 0;
+
+err_chunks:
+ kfree(rblocks);
+err_alloc:
+ if (sram->clk)
+ clk_disable_unprepare(sram->clk);
+ return ret;
}
static int sram_remove(struct platform_device *pdev)
@@ -87,8 +198,6 @@ static int sram_remove(struct platform_device *pdev)
if (gen_pool_avail(sram->pool) < gen_pool_size(sram->pool))
dev_dbg(&pdev->dev, "removed while SRAM allocated\n");
- gen_pool_destroy(sram->pool);
-
if (sram->clk)
clk_disable_unprepare(sram->clk);
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 3aed525e55b4..1972d57aadb3 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -22,7 +22,6 @@
#define pr_fmt(fmt) "(stc): " fmt
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/tty.h>
#include <linux/seq_file.h>
diff --git a/drivers/misc/ti_dac7512.c b/drivers/misc/ti_dac7512.c
index 83da711ce9f1..cb0289b44a17 100644
--- a/drivers/misc/ti_dac7512.c
+++ b/drivers/misc/ti_dac7512.c
@@ -20,7 +20,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c
index 5bc10fa193de..b00335652e52 100644
--- a/drivers/misc/tsl2550.c
+++ b/drivers/misc/tsl2550.c
@@ -20,7 +20,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c
index d35cda06b5e8..e0d5017785e5 100644
--- a/drivers/misc/vmw_vmci/vmci_guest.c
+++ b/drivers/misc/vmw_vmci/vmci_guest.c
@@ -383,11 +383,12 @@ static int vmci_enable_msix(struct pci_dev *pdev,
vmci_dev->msix_entries[i].vector = i;
}
- result = pci_enable_msix(pdev, vmci_dev->msix_entries, VMCI_MAX_INTRS);
+ result = pci_enable_msix_exact(pdev,
+ vmci_dev->msix_entries, VMCI_MAX_INTRS);
if (result == 0)
vmci_dev->exclusive_vectors = true;
- else if (result > 0)
- result = pci_enable_msix(pdev, vmci_dev->msix_entries, 1);
+ else if (result == -ENOSPC)
+ result = pci_enable_msix_exact(pdev, vmci_dev->msix_entries, 1);
return result;
}
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 357bbc54fe4b..3e049c13429c 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -197,7 +197,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
- limit = dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
+ limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
mq->card = card;
mq->queue = blk_init_queue(mmc_request_fn, lock);
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 55cd110a49c4..c204b7d1532c 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2607,7 +2607,7 @@ int dw_mci_probe(struct dw_mci *host)
tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
host->card_workqueue = alloc_workqueue("dw-mci-card",
- WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1);
+ WQ_MEM_RECLAIM, 1);
if (!host->card_workqueue) {
ret = -ENOMEM;
goto err_dmaunmap;
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 90ff447bf043..a4bee41ad5cb 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -428,6 +428,7 @@ config MTD_NAND_FSL_IFC
tristate "NAND support for Freescale IFC controller"
depends on MTD_NAND && FSL_SOC
select FSL_IFC
+ select MEMORY
help
Various Freescale chips e.g P1010, include a NAND Flash machine
with built-in hardware ECC capabilities.
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 90ca7e75d6f0..50d9161c4faf 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -30,7 +30,7 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand_ecc.h>
-#include <asm/fsl_ifc.h>
+#include <linux/fsl_ifc.h>
#define FSL_IFC_V1_1_0 0x01010000
#define ERR_BYTE 0xFF /* Value returned for read
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 59eba5d2c685..9715a7ba164a 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1584,7 +1584,7 @@ read_retry:
}
if (mtd->ecc_stats.failed - ecc_failures) {
- if (retry_mode + 1 <= chip->read_retries) {
+ if (retry_mode + 1 < chip->read_retries) {
retry_mode++;
ret = nand_setup_read_retry(mtd,
retry_mode);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index ef4190a02b7b..bf642ceef681 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -1633,6 +1633,7 @@ static int omap_nand_probe(struct platform_device *pdev)
int i;
dma_cap_mask_t mask;
unsigned sig;
+ unsigned oob_index;
struct resource *res;
struct mtd_part_parser_data ppdata = {};
@@ -1826,11 +1827,14 @@ static int omap_nand_probe(struct platform_device *pdev)
(mtd->writesize /
nand_chip->ecc.size);
if (nand_chip->options & NAND_BUSWIDTH_16)
- ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
+ oob_index = BADBLOCK_MARKER_LENGTH;
else
- ecclayout->eccpos[0] = 1;
- ecclayout->oobfree->offset = ecclayout->eccpos[0] +
- ecclayout->eccbytes;
+ oob_index = 1;
+ for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
+ ecclayout->eccpos[i] = oob_index;
+ /* no reserved-marker in ecclayout for this ecc-scheme */
+ ecclayout->oobfree->offset =
+ ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
break;
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
@@ -1847,9 +1851,15 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize /
nand_chip->ecc.size);
- ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
- ecclayout->oobfree->offset = ecclayout->eccpos[0] +
- ecclayout->eccbytes;
+ oob_index = BADBLOCK_MARKER_LENGTH;
+ for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
+ ecclayout->eccpos[i] = oob_index;
+ if (((i + 1) % nand_chip->ecc.bytes) == 0)
+ oob_index++;
+ }
+ /* include reserved-marker in ecclayout->oobfree calculation */
+ ecclayout->oobfree->offset = 1 +
+ ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
/* software bch library is used for locating errors */
nand_chip->ecc.priv = nand_bch_init(mtd,
nand_chip->ecc.size,
@@ -1883,9 +1893,12 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize /
nand_chip->ecc.size);
- ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
- ecclayout->oobfree->offset = ecclayout->eccpos[0] +
- ecclayout->eccbytes;
+ oob_index = BADBLOCK_MARKER_LENGTH;
+ for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
+ ecclayout->eccpos[i] = oob_index;
+ /* reserved marker already included in ecclayout->eccbytes */
+ ecclayout->oobfree->offset =
+ ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
/* This ECC scheme requires ELM H/W block */
if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) {
pr_err("nand: error: could not initialize ELM\n");
@@ -1913,9 +1926,15 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize /
nand_chip->ecc.size);
- ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
- ecclayout->oobfree->offset = ecclayout->eccpos[0] +
- ecclayout->eccbytes;
+ oob_index = BADBLOCK_MARKER_LENGTH;
+ for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
+ ecclayout->eccpos[i] = oob_index;
+ if (((i + 1) % nand_chip->ecc.bytes) == 0)
+ oob_index++;
+ }
+ /* include reserved-marker in ecclayout->oobfree calculation */
+ ecclayout->oobfree->offset = 1 +
+ ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
/* software bch library is used for locating errors */
nand_chip->ecc.priv = nand_bch_init(mtd,
nand_chip->ecc.size,
@@ -1956,9 +1975,12 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize /
nand_chip->ecc.size);
- ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
- ecclayout->oobfree->offset = ecclayout->eccpos[0] +
- ecclayout->eccbytes;
+ oob_index = BADBLOCK_MARKER_LENGTH;
+ for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
+ ecclayout->eccpos[i] = oob_index;
+ /* reserved marker already included in ecclayout->eccbytes */
+ ecclayout->oobfree->offset =
+ ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
break;
#else
pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
@@ -1972,11 +1994,8 @@ static int omap_nand_probe(struct platform_device *pdev)
goto return_error;
}
- /* populate remaining ECC layout data */
- ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH +
- ecclayout->eccbytes);
- for (i = 1; i < ecclayout->eccbytes; i++)
- ecclayout->eccpos[i] = ecclayout->eccpos[0] + i;
+ /* all OOB bytes from oobfree->offset till end off OOB are free */
+ ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
/* check if NAND device's OOB is enough to store ECC signatures */
if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
pr_err("not enough OOB bytes required = %d, available=%d\n",
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c
index d72783dd7b96..c0670237e7a2 100644
--- a/drivers/mtd/nand/sh_flctl.c
+++ b/drivers/mtd/nand/sh_flctl.c
@@ -897,7 +897,7 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
if (!flctl->qos_request) {
ret = dev_pm_qos_add_request(&flctl->pdev->dev,
&flctl->pm_qos,
- DEV_PM_QOS_LATENCY,
+ DEV_PM_QOS_RESUME_LATENCY,
100);
if (ret < 0)
dev_err(&flctl->pdev->dev,
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index ead861307b3c..c5dad652614d 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -463,8 +463,8 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai,
}
}
if (found_orphan) {
- kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
list_del(&tmp_aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
}
new_aeb = kmem_cache_alloc(ai->aeb_slab_cache,
@@ -846,16 +846,16 @@ fail_bad:
ret = UBI_BAD_FASTMAP;
fail:
list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &used, u.list) {
- kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
list_del(&tmp_aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
}
list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &eba_orphans, u.list) {
- kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
list_del(&tmp_aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
}
list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) {
- kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
list_del(&tmp_aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
}
return ret;
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f342278539d5..494b888a6568 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -139,7 +139,7 @@ config MACVTAP
This adds a specialized tap character device driver that is based
on the MAC-VLAN network interface, called macvtap. A macvtap device
can be added in the same way as a macvlan device, using 'type
- macvlan', and then be accessed through the tap user space interface.
+ macvtap', and then be accessed through the tap user space interface.
To compile this driver as a module, choose M here: the module
will be called macvtap.
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index cce1f1bf90b4..dcde56057fe1 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -181,7 +181,7 @@ static inline int __agg_has_partner(struct aggregator *agg)
*/
static inline void __disable_port(struct port *port)
{
- bond_set_slave_inactive_flags(port->slave);
+ bond_set_slave_inactive_flags(port->slave, BOND_SLAVE_NOTIFY_LATER);
}
/**
@@ -193,7 +193,7 @@ static inline void __enable_port(struct port *port)
struct slave *slave = port->slave;
if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev))
- bond_set_slave_active_flags(slave);
+ bond_set_slave_active_flags(slave, BOND_SLAVE_NOTIFY_LATER);
}
/**
@@ -1796,8 +1796,6 @@ void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout)
BOND_AD_INFO(bond).agg_select_timer = timeout;
}
-static u16 aggregator_identifier;
-
/**
* bond_3ad_initialize - initialize a bond's 802.3ad parameters and structures
* @bond: bonding struct to work on
@@ -1811,7 +1809,7 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution)
if (!MAC_ADDRESS_EQUAL(&(BOND_AD_INFO(bond).system.sys_mac_addr),
bond->dev->dev_addr)) {
- aggregator_identifier = 0;
+ BOND_AD_INFO(bond).aggregator_identifier = 0;
BOND_AD_INFO(bond).system.sys_priority = 0xFFFF;
BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr);
@@ -1880,7 +1878,7 @@ void bond_3ad_bind_slave(struct slave *slave)
ad_initialize_agg(aggregator);
aggregator->aggregator_mac_address = *((struct mac_addr *)bond->dev->dev_addr);
- aggregator->aggregator_identifier = (++aggregator_identifier);
+ aggregator->aggregator_identifier = ++BOND_AD_INFO(bond).aggregator_identifier;
aggregator->slave = slave;
aggregator->is_active = 0;
aggregator->num_of_ports = 0;
@@ -2064,6 +2062,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
struct list_head *iter;
struct slave *slave;
struct port *port;
+ bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
read_lock(&bond->lock);
rcu_read_lock();
@@ -2121,8 +2120,19 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
}
re_arm:
+ bond_for_each_slave_rcu(bond, slave, iter) {
+ if (slave->should_notify) {
+ should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
+ break;
+ }
+ }
rcu_read_unlock();
read_unlock(&bond->lock);
+
+ if (should_notify_rtnl && rtnl_trylock()) {
+ bond_slave_state_notify(bond);
+ rtnl_unlock();
+ }
queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
}
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index 13dc9d3c5e34..f4dd9592ac62 100644
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -253,6 +253,7 @@ struct ad_system {
struct ad_bond_info {
struct ad_system system; /* 802.3ad system structure */
u32 agg_select_timer; // Timer to select aggregator after all adapter's hand shakes
+ u16 aggregator_identifier;
};
struct ad_slave_info {
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index a2c47476804d..e8f133e926aa 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -730,7 +730,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
client_info->ntt = 0;
}
- if (!vlan_get_tag(skb, &client_info->vlan_id))
+ if (vlan_get_tag(skb, &client_info->vlan_id))
client_info->vlan_id = 0;
if (!client_info->assigned) {
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 71ba18efa15b..e5628fc725c3 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -829,21 +829,25 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
if (bond_is_lb(bond)) {
bond_alb_handle_active_change(bond, new_active);
if (old_active)
- bond_set_slave_inactive_flags(old_active);
+ bond_set_slave_inactive_flags(old_active,
+ BOND_SLAVE_NOTIFY_NOW);
if (new_active)
- bond_set_slave_active_flags(new_active);
+ bond_set_slave_active_flags(new_active,
+ BOND_SLAVE_NOTIFY_NOW);
} else {
rcu_assign_pointer(bond->curr_active_slave, new_active);
}
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
if (old_active)
- bond_set_slave_inactive_flags(old_active);
+ bond_set_slave_inactive_flags(old_active,
+ BOND_SLAVE_NOTIFY_NOW);
if (new_active) {
bool should_notify_peers = false;
- bond_set_slave_active_flags(new_active);
+ bond_set_slave_active_flags(new_active,
+ BOND_SLAVE_NOTIFY_NOW);
if (bond->params.fail_over_mac)
bond_do_fail_over_mac(bond, new_active,
@@ -1193,6 +1197,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
return -EBUSY;
}
+ if (bond_dev == slave_dev) {
+ pr_err("%s: cannot enslave bond to itself.\n", bond_dev->name);
+ return -EPERM;
+ }
+
/* vlan challenged mutual exclusion */
/* no need to lock since we're protected by rtnl_lock */
if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) {
@@ -1463,14 +1472,15 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
switch (bond->params.mode) {
case BOND_MODE_ACTIVEBACKUP:
- bond_set_slave_inactive_flags(new_slave);
+ bond_set_slave_inactive_flags(new_slave,
+ BOND_SLAVE_NOTIFY_NOW);
break;
case BOND_MODE_8023AD:
/* in 802.3ad mode, the internal mechanism
* will activate the slaves in the selected
* aggregator
*/
- bond_set_slave_inactive_flags(new_slave);
+ bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
/* if this is the first slave */
if (!prev_slave) {
SLAVE_AD_INFO(new_slave).id = 1;
@@ -1488,7 +1498,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
case BOND_MODE_TLB:
case BOND_MODE_ALB:
bond_set_active_slave(new_slave);
- bond_set_slave_inactive_flags(new_slave);
+ bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
break;
default:
pr_debug("This slave is always active in trunk mode\n");
@@ -1543,9 +1553,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
bond_set_carrier(bond);
if (USES_PRIMARY(bond->params.mode)) {
+ block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
write_unlock_bh(&bond->curr_slave_lock);
+ unblock_netpoll_tx();
}
pr_info("%s: enslaving %s as a%s interface with a%s link.\n",
@@ -1571,10 +1583,12 @@ err_detach:
if (bond->primary_slave == new_slave)
bond->primary_slave = NULL;
if (bond->curr_active_slave == new_slave) {
+ block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock);
bond_change_active_slave(bond, NULL);
bond_select_active_slave(bond);
write_unlock_bh(&bond->curr_slave_lock);
+ unblock_netpoll_tx();
}
slave_disable_netpoll(new_slave);
@@ -1650,9 +1664,6 @@ static int __bond_release_one(struct net_device *bond_dev,
return -EINVAL;
}
- /* release the slave from its bond */
- bond->slave_cnt--;
-
bond_sysfs_slave_del(slave);
bond_upper_dev_unlink(bond_dev, slave_dev);
@@ -1734,6 +1745,7 @@ static int __bond_release_one(struct net_device *bond_dev,
unblock_netpoll_tx();
synchronize_rcu();
+ bond->slave_cnt--;
if (!bond_has_slaves(bond)) {
call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
@@ -2011,7 +2023,8 @@ static void bond_miimon_commit(struct bonding *bond)
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP ||
bond->params.mode == BOND_MODE_8023AD)
- bond_set_slave_inactive_flags(slave);
+ bond_set_slave_inactive_flags(slave,
+ BOND_SLAVE_NOTIFY_NOW);
pr_info("%s: link status definitely down for interface %s, disabling it\n",
bond->dev->name, slave->dev->name);
@@ -2558,7 +2571,8 @@ static void bond_ab_arp_commit(struct bonding *bond)
slave->link = BOND_LINK_UP;
if (bond->current_arp_slave) {
bond_set_slave_inactive_flags(
- bond->current_arp_slave);
+ bond->current_arp_slave,
+ BOND_SLAVE_NOTIFY_NOW);
bond->current_arp_slave = NULL;
}
@@ -2578,7 +2592,8 @@ static void bond_ab_arp_commit(struct bonding *bond)
slave->link_failure_count++;
slave->link = BOND_LINK_DOWN;
- bond_set_slave_inactive_flags(slave);
+ bond_set_slave_inactive_flags(slave,
+ BOND_SLAVE_NOTIFY_NOW);
pr_info("%s: link status definitely down for interface %s, disabling it\n",
bond->dev->name, slave->dev->name);
@@ -2611,17 +2626,17 @@ do_failover:
/*
* Send ARP probes for active-backup mode ARP monitor.
+ *
+ * Called with rcu_read_lock hold.
*/
static bool bond_ab_arp_probe(struct bonding *bond)
{
struct slave *slave, *before = NULL, *new_slave = NULL,
- *curr_arp_slave, *curr_active_slave;
+ *curr_arp_slave = rcu_dereference(bond->current_arp_slave),
+ *curr_active_slave = rcu_dereference(bond->curr_active_slave);
struct list_head *iter;
bool found = false;
-
- rcu_read_lock();
- curr_arp_slave = rcu_dereference(bond->current_arp_slave);
- curr_active_slave = rcu_dereference(bond->curr_active_slave);
+ bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
if (curr_arp_slave && curr_active_slave)
pr_info("PROBE: c_arp %s && cas %s BAD\n",
@@ -2630,32 +2645,23 @@ static bool bond_ab_arp_probe(struct bonding *bond)
if (curr_active_slave) {
bond_arp_send_all(bond, curr_active_slave);
- rcu_read_unlock();
- return true;
+ return should_notify_rtnl;
}
- rcu_read_unlock();
/* if we don't have a curr_active_slave, search for the next available
* backup slave from the current_arp_slave and make it the candidate
* for becoming the curr_active_slave
*/
- if (!rtnl_trylock())
- return false;
- /* curr_arp_slave might have gone away */
- curr_arp_slave = ACCESS_ONCE(bond->current_arp_slave);
-
if (!curr_arp_slave) {
- curr_arp_slave = bond_first_slave(bond);
- if (!curr_arp_slave) {
- rtnl_unlock();
- return true;
- }
+ curr_arp_slave = bond_first_slave_rcu(bond);
+ if (!curr_arp_slave)
+ return should_notify_rtnl;
}
- bond_set_slave_inactive_flags(curr_arp_slave);
+ bond_set_slave_inactive_flags(curr_arp_slave, BOND_SLAVE_NOTIFY_LATER);
- bond_for_each_slave(bond, slave, iter) {
+ bond_for_each_slave_rcu(bond, slave, iter) {
if (!found && !before && IS_UP(slave->dev))
before = slave;
@@ -2673,7 +2679,8 @@ static bool bond_ab_arp_probe(struct bonding *bond)
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
- bond_set_slave_inactive_flags(slave);
+ bond_set_slave_inactive_flags(slave,
+ BOND_SLAVE_NOTIFY_LATER);
pr_info("%s: backup interface %s is now down.\n",
bond->dev->name, slave->dev->name);
@@ -2685,26 +2692,31 @@ static bool bond_ab_arp_probe(struct bonding *bond)
if (!new_slave && before)
new_slave = before;
- if (!new_slave) {
- rtnl_unlock();
- return true;
- }
+ if (!new_slave)
+ goto check_state;
new_slave->link = BOND_LINK_BACK;
- bond_set_slave_active_flags(new_slave);
+ bond_set_slave_active_flags(new_slave, BOND_SLAVE_NOTIFY_LATER);
bond_arp_send_all(bond, new_slave);
new_slave->jiffies = jiffies;
rcu_assign_pointer(bond->current_arp_slave, new_slave);
- rtnl_unlock();
- return true;
+check_state:
+ bond_for_each_slave_rcu(bond, slave, iter) {
+ if (slave->should_notify) {
+ should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
+ break;
+ }
+ }
+ return should_notify_rtnl;
}
static void bond_activebackup_arp_mon(struct work_struct *work)
{
struct bonding *bond = container_of(work, struct bonding,
arp_work.work);
- bool should_notify_peers = false, should_commit = false;
+ bool should_notify_peers = false;
+ bool should_notify_rtnl = false;
int delta_in_ticks;
delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
@@ -2713,11 +2725,12 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
goto re_arm;
rcu_read_lock();
+
should_notify_peers = bond_should_notify_peers(bond);
- should_commit = bond_ab_arp_inspect(bond);
- rcu_read_unlock();
- if (should_commit) {
+ if (bond_ab_arp_inspect(bond)) {
+ rcu_read_unlock();
+
/* Race avoidance with bond_close flush of workqueue */
if (!rtnl_trylock()) {
delta_in_ticks = 1;
@@ -2726,23 +2739,28 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
}
bond_ab_arp_commit(bond);
+
rtnl_unlock();
+ rcu_read_lock();
}
- if (!bond_ab_arp_probe(bond)) {
- /* rtnl locking failed, re-arm */
- delta_in_ticks = 1;
- should_notify_peers = false;
- }
+ should_notify_rtnl = bond_ab_arp_probe(bond);
+ rcu_read_unlock();
re_arm:
if (bond->params.arp_interval)
queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
- if (should_notify_peers) {
+ if (should_notify_peers || should_notify_rtnl) {
if (!rtnl_trylock())
return;
- call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, bond->dev);
+
+ if (should_notify_peers)
+ call_netdevice_notifiers(NETDEV_NOTIFY_PEERS,
+ bond->dev);
+ if (should_notify_rtnl)
+ bond_slave_state_notify(bond);
+
rtnl_unlock();
}
}
@@ -2864,9 +2882,12 @@ static int bond_slave_netdev_event(unsigned long event,
pr_info("%s: Primary slave changed to %s, reselecting active slave.\n",
bond->dev->name, bond->primary_slave ? slave_dev->name :
"none");
+
+ block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
write_unlock_bh(&bond->curr_slave_lock);
+ unblock_netpoll_tx();
break;
case NETDEV_FEAT_CHANGE:
bond_compute_features(bond);
@@ -3039,9 +3060,11 @@ static int bond_open(struct net_device *bond_dev)
bond_for_each_slave(bond, slave, iter) {
if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
&& (slave != bond->curr_active_slave)) {
- bond_set_slave_inactive_flags(slave);
+ bond_set_slave_inactive_flags(slave,
+ BOND_SLAVE_NOTIFY_NOW);
} else {
- bond_set_slave_active_flags(slave);
+ bond_set_slave_active_flags(slave,
+ BOND_SLAVE_NOTIFY_NOW);
}
}
read_unlock(&bond->curr_slave_lock);
@@ -3700,7 +3723,7 @@ static inline int bond_slave_override(struct bonding *bond,
static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
/*
* This helper function exists to help dev_pick_tx get the correct
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 11cb943222d5..298c26509095 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -14,7 +14,7 @@
#include <linux/errno.h>
#include <linux/if.h>
#include <linux/netdevice.h>
-#include <linux/rwlock.h>
+#include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <linux/ctype.h>
#include <linux/inet.h>
@@ -121,6 +121,7 @@ static struct bond_opt_value bond_resend_igmp_tbl[] = {
static struct bond_opt_value bond_lp_interval_tbl[] = {
{ "minval", 1, BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
{ "maxval", INT_MAX, BOND_VALFLAG_MAX},
+ { NULL, -1, 0},
};
static struct bond_option bond_opts[] = {
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 86ccfb9f71cc..2b0fdec695f7 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -195,7 +195,8 @@ struct slave {
s8 new_link;
u8 backup:1, /* indicates backup slave. Value corresponds with
BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
- inactive:1; /* indicates inactive slave */
+ inactive:1, /* indicates inactive slave */
+ should_notify:1; /* indicateds whether the state changed */
u8 duplex;
u32 original_mtu;
u32 link_failure_count;
@@ -303,6 +304,24 @@ static inline void bond_set_backup_slave(struct slave *slave)
}
}
+static inline void bond_set_slave_state(struct slave *slave,
+ int slave_state, bool notify)
+{
+ if (slave->backup == slave_state)
+ return;
+
+ slave->backup = slave_state;
+ if (notify) {
+ rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL);
+ slave->should_notify = 0;
+ } else {
+ if (slave->should_notify)
+ slave->should_notify = 0;
+ else
+ slave->should_notify = 1;
+ }
+}
+
static inline void bond_slave_state_change(struct bonding *bond)
{
struct list_head *iter;
@@ -316,6 +335,19 @@ static inline void bond_slave_state_change(struct bonding *bond)
}
}
+static inline void bond_slave_state_notify(struct bonding *bond)
+{
+ struct list_head *iter;
+ struct slave *tmp;
+
+ bond_for_each_slave(bond, tmp, iter) {
+ if (tmp->should_notify) {
+ rtmsg_ifinfo(RTM_NEWLINK, tmp->dev, 0, GFP_KERNEL);
+ tmp->should_notify = 0;
+ }
+ }
+}
+
static inline int bond_slave_state(struct slave *slave)
{
return slave->backup;
@@ -343,6 +375,9 @@ static inline bool bond_is_active_slave(struct slave *slave)
#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \
BOND_ARP_VALIDATE_BACKUP)
+#define BOND_SLAVE_NOTIFY_NOW true
+#define BOND_SLAVE_NOTIFY_LATER false
+
static inline int slave_do_arp_validate(struct bonding *bond,
struct slave *slave)
{
@@ -394,17 +429,19 @@ static inline void bond_netpoll_send_skb(const struct slave *slave,
}
#endif
-static inline void bond_set_slave_inactive_flags(struct slave *slave)
+static inline void bond_set_slave_inactive_flags(struct slave *slave,
+ bool notify)
{
if (!bond_is_lb(slave->bond))
- bond_set_backup_slave(slave);
+ bond_set_slave_state(slave, BOND_STATE_BACKUP, notify);
if (!slave->bond->params.all_slaves_active)
slave->inactive = 1;
}
-static inline void bond_set_slave_active_flags(struct slave *slave)
+static inline void bond_set_slave_active_flags(struct slave *slave,
+ bool notify)
{
- bond_set_active_slave(slave);
+ bond_set_slave_state(slave, BOND_STATE_ACTIVE, notify);
slave->inactive = 0;
}
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 320bef2dba42..61376abdab39 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -144,6 +144,8 @@
#define FLEXCAN_MB_CODE_MASK (0xf0ffffff)
+#define FLEXCAN_TIMEOUT_US (50)
+
/*
* FLEXCAN hardware feature flags
*
@@ -262,6 +264,22 @@ static inline void flexcan_write(u32 val, void __iomem *addr)
}
#endif
+static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
+{
+ if (!priv->reg_xceiver)
+ return 0;
+
+ return regulator_enable(priv->reg_xceiver);
+}
+
+static inline int flexcan_transceiver_disable(const struct flexcan_priv *priv)
+{
+ if (!priv->reg_xceiver)
+ return 0;
+
+ return regulator_disable(priv->reg_xceiver);
+}
+
static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
u32 reg_esr)
{
@@ -269,26 +287,95 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
(reg_esr & FLEXCAN_ESR_ERR_BUS);
}
-static inline void flexcan_chip_enable(struct flexcan_priv *priv)
+static int flexcan_chip_enable(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
reg = flexcan_read(&regs->mcr);
reg &= ~FLEXCAN_MCR_MDIS;
flexcan_write(reg, &regs->mcr);
- udelay(10);
+ while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ usleep_range(10, 20);
+
+ if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK)
+ return -ETIMEDOUT;
+
+ return 0;
}
-static inline void flexcan_chip_disable(struct flexcan_priv *priv)
+static int flexcan_chip_disable(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
reg = flexcan_read(&regs->mcr);
reg |= FLEXCAN_MCR_MDIS;
flexcan_write(reg, &regs->mcr);
+
+ while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ usleep_range(10, 20);
+
+ if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int flexcan_chip_freeze(struct flexcan_priv *priv)
+{
+ struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate;
+ u32 reg;
+
+ reg = flexcan_read(&regs->mcr);
+ reg |= FLEXCAN_MCR_HALT;
+ flexcan_write(reg, &regs->mcr);
+
+ while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+ usleep_range(100, 200);
+
+ if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int flexcan_chip_unfreeze(struct flexcan_priv *priv)
+{
+ struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+ u32 reg;
+
+ reg = flexcan_read(&regs->mcr);
+ reg &= ~FLEXCAN_MCR_HALT;
+ flexcan_write(reg, &regs->mcr);
+
+ while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+ usleep_range(10, 20);
+
+ if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int flexcan_chip_softreset(struct flexcan_priv *priv)
+{
+ struct flexcan_regs __iomem *regs = priv->base;
+ unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+
+ flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
+ while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST))
+ usleep_range(10, 20);
+
+ if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST)
+ return -ETIMEDOUT;
+
+ return 0;
}
static int flexcan_get_berr_counter(const struct net_device *dev,
@@ -709,19 +796,14 @@ static int flexcan_chip_start(struct net_device *dev)
u32 reg_mcr, reg_ctrl;
/* enable module */
- flexcan_chip_enable(priv);
+ err = flexcan_chip_enable(priv);
+ if (err)
+ return err;
/* soft reset */
- flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
- udelay(10);
-
- reg_mcr = flexcan_read(&regs->mcr);
- if (reg_mcr & FLEXCAN_MCR_SOFTRST) {
- netdev_err(dev, "Failed to softreset can module (mcr=0x%08x)\n",
- reg_mcr);
- err = -ENODEV;
- goto out;
- }
+ err = flexcan_chip_softreset(priv);
+ if (err)
+ goto out_chip_disable;
flexcan_set_bittiming(dev);
@@ -788,16 +870,14 @@ static int flexcan_chip_start(struct net_device *dev)
if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
flexcan_write(0x0, &regs->rxfgmask);
- if (priv->reg_xceiver) {
- err = regulator_enable(priv->reg_xceiver);
- if (err)
- goto out;
- }
+ err = flexcan_transceiver_enable(priv);
+ if (err)
+ goto out_chip_disable;
/* synchronize with the can bus */
- reg_mcr = flexcan_read(&regs->mcr);
- reg_mcr &= ~FLEXCAN_MCR_HALT;
- flexcan_write(reg_mcr, &regs->mcr);
+ err = flexcan_chip_unfreeze(priv);
+ if (err)
+ goto out_transceiver_disable;
priv->can.state = CAN_STATE_ERROR_ACTIVE;
@@ -810,7 +890,9 @@ static int flexcan_chip_start(struct net_device *dev)
return 0;
- out:
+ out_transceiver_disable:
+ flexcan_transceiver_disable(priv);
+ out_chip_disable:
flexcan_chip_disable(priv);
return err;
}
@@ -825,18 +907,17 @@ static void flexcan_chip_stop(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->base;
- u32 reg;
+
+ /* freeze + disable module */
+ flexcan_chip_freeze(priv);
+ flexcan_chip_disable(priv);
/* Disable all interrupts */
flexcan_write(0, &regs->imask1);
+ flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
+ &regs->ctrl);
- /* Disable + halt module */
- reg = flexcan_read(&regs->mcr);
- reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT;
- flexcan_write(reg, &regs->mcr);
-
- if (priv->reg_xceiver)
- regulator_disable(priv->reg_xceiver);
+ flexcan_transceiver_disable(priv);
priv->can.state = CAN_STATE_STOPPED;
return;
@@ -866,7 +947,7 @@ static int flexcan_open(struct net_device *dev)
/* start chip and queuing */
err = flexcan_chip_start(dev);
if (err)
- goto out_close;
+ goto out_free_irq;
can_led_event(dev, CAN_LED_EVENT_OPEN);
@@ -875,6 +956,8 @@ static int flexcan_open(struct net_device *dev)
return 0;
+ out_free_irq:
+ free_irq(dev->irq, dev);
out_close:
close_candev(dev);
out_disable_per:
@@ -945,12 +1028,16 @@ static int register_flexcandev(struct net_device *dev)
goto out_disable_ipg;
/* select "bus clock", chip must be disabled */
- flexcan_chip_disable(priv);
+ err = flexcan_chip_disable(priv);
+ if (err)
+ goto out_disable_per;
reg = flexcan_read(&regs->ctrl);
reg |= FLEXCAN_CTRL_CLK_SRC;
flexcan_write(reg, &regs->ctrl);
- flexcan_chip_enable(priv);
+ err = flexcan_chip_enable(priv);
+ if (err)
+ goto out_chip_disable;
/* set freeze, halt and activate FIFO, restrict register access */
reg = flexcan_read(&regs->mcr);
@@ -967,14 +1054,15 @@ static int register_flexcandev(struct net_device *dev)
if (!(reg & FLEXCAN_MCR_FEN)) {
netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
err = -ENODEV;
- goto out_disable_per;
+ goto out_chip_disable;
}
err = register_candev(dev);
- out_disable_per:
/* disable core and turn off clocks */
+ out_chip_disable:
flexcan_chip_disable(priv);
+ out_disable_per:
clk_disable_unprepare(priv->clk_per);
out_disable_ipg:
clk_disable_unprepare(priv->clk_ipg);
@@ -1104,9 +1192,10 @@ static int flexcan_probe(struct platform_device *pdev)
static int flexcan_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
+ struct flexcan_priv *priv = netdev_priv(dev);
unregister_flexcandev(dev);
-
+ netif_napi_del(&priv->napi);
free_candev(dev);
return 0;
@@ -1117,8 +1206,11 @@ static int flexcan_suspend(struct device *device)
{
struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
+ int err;
- flexcan_chip_disable(priv);
+ err = flexcan_chip_disable(priv);
+ if (err)
+ return err;
if (netif_running(dev)) {
netif_stop_queue(dev);
@@ -1139,9 +1231,7 @@ static int flexcan_resume(struct device *device)
netif_device_attach(dev);
netif_start_queue(dev);
}
- flexcan_chip_enable(priv);
-
- return 0;
+ return flexcan_chip_enable(priv);
}
#endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 6c859bba8b65..e77d11049747 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -473,6 +473,8 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
return err;
dev->nchannels = msg.u.cardinfo.nchannels;
+ if (dev->nchannels > MAX_NET_DEVICES)
+ return -EINVAL;
return 0;
}
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index 2e45f6ec1bf0..380d24922049 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -1248,19 +1248,13 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* shared register for the high 32 bits, so only a single, aligned,
* 4 GB physical address range can be used for descriptors.
*/
- if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) &&
- !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
+ if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
dev_dbg(&pdev->dev, "DMA to 64-BIT addresses\n");
} else {
- err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (err) {
- err = dma_set_coherent_mask(&pdev->dev,
- DMA_BIT_MASK(32));
- if (err) {
- dev_err(&pdev->dev,
- "No usable DMA config, aborting\n");
- goto out_pci_disable;
- }
+ dev_err(&pdev->dev, "No usable DMA config, aborting\n");
+ goto out_pci_disable;
}
}
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
index d5c2d3e912e5..422aab27ea1b 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -2436,7 +2436,7 @@ err_reset:
err_register:
err_sw_init:
err_eeprom:
- iounmap(adapter->hw.hw_addr);
+ pci_iounmap(pdev, adapter->hw.hw_addr);
err_init_netdev:
err_ioremap:
free_netdev(netdev);
@@ -2474,7 +2474,7 @@ static void atl1e_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
atl1e_free_ring_resources(adapter);
atl1e_force_ps(&adapter->hw);
- iounmap(adapter->hw.hw_addr);
+ pci_iounmap(pdev, adapter->hw.hw_addr);
pci_release_regions(pdev);
free_netdev(netdev);
pci_disable_device(pdev);
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 1f7b5aa114fa..8a7bf7dad898 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -1484,6 +1484,10 @@ static int b44_open(struct net_device *dev)
add_timer(&bp->timer);
b44_enable_ints(bp);
+
+ if (bp->flags & B44_FLAG_EXTERNAL_PHY)
+ phy_start(bp->phydev);
+
netif_start_queue(dev);
out:
return err;
@@ -1646,6 +1650,9 @@ static int b44_close(struct net_device *dev)
netif_stop_queue(dev);
+ if (bp->flags & B44_FLAG_EXTERNAL_PHY)
+ phy_stop(bp->phydev);
+
napi_disable(&bp->napi);
del_timer_sync(&bp->timer);
@@ -2222,7 +2229,12 @@ static void b44_adjust_link(struct net_device *dev)
}
if (status_changed) {
- b44_check_phy(bp);
+ u32 val = br32(bp, B44_TX_CTRL);
+ if (bp->flags & B44_FLAG_FULL_DUPLEX)
+ val |= TX_CTRL_DUPLEX;
+ else
+ val &= ~TX_CTRL_DUPLEX;
+ bw32(bp, B44_TX_CTRL, val);
phy_print_status(phydev);
}
}
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index cda25ac45b47..6c9e1c9bdeb8 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -2507,6 +2507,7 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
bp->fw_wr_seq++;
msg_data |= bp->fw_wr_seq;
+ bp->fw_last_msg = msg_data;
bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
@@ -4000,8 +4001,23 @@ bnx2_setup_wol(struct bnx2 *bp)
wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
}
- if (!(bp->flags & BNX2_FLAG_NO_WOL))
- bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 1, 0);
+ if (!(bp->flags & BNX2_FLAG_NO_WOL)) {
+ u32 val;
+
+ wol_msg |= BNX2_DRV_MSG_DATA_WAIT3;
+ if (bp->fw_last_msg || BNX2_CHIP(bp) != BNX2_CHIP_5709) {
+ bnx2_fw_sync(bp, wol_msg, 1, 0);
+ return;
+ }
+ /* Tell firmware not to power down the PHY yet, otherwise
+ * the chip will take a long time to respond to MMIO reads.
+ */
+ val = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
+ bnx2_shmem_wr(bp, BNX2_PORT_FEATURE,
+ val | BNX2_PORT_FEATURE_ASF_ENABLED);
+ bnx2_fw_sync(bp, wol_msg, 1, 0);
+ bnx2_shmem_wr(bp, BNX2_PORT_FEATURE, val);
+ }
}
@@ -4033,9 +4049,22 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
if (bp->wol)
pci_set_power_state(bp->pdev, PCI_D3hot);
- } else {
- pci_set_power_state(bp->pdev, PCI_D3hot);
+ break;
+
+ }
+ if (!bp->fw_last_msg && BNX2_CHIP(bp) == BNX2_CHIP_5709) {
+ u32 val;
+
+ /* Tell firmware not to power down the PHY yet,
+ * otherwise the other port may not respond to
+ * MMIO reads.
+ */
+ val = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
+ val &= ~BNX2_CONDITION_PM_STATE_MASK;
+ val |= BNX2_CONDITION_PM_STATE_UNPREP;
+ bnx2_shmem_wr(bp, BNX2_BC_STATE_CONDITION, val);
}
+ pci_set_power_state(bp->pdev, PCI_D3hot);
/* No more memory access after this point until
* device is brought back to D0.
diff --git a/drivers/net/ethernet/broadcom/bnx2.h b/drivers/net/ethernet/broadcom/bnx2.h
index f1cf2c44e7ed..e341bc366fa5 100644
--- a/drivers/net/ethernet/broadcom/bnx2.h
+++ b/drivers/net/ethernet/broadcom/bnx2.h
@@ -6900,6 +6900,7 @@ struct bnx2 {
u16 fw_wr_seq;
u16 fw_drv_pulse_wr_seq;
+ u32 fw_last_msg;
int rx_max_ring;
int rx_ring_size;
@@ -7406,6 +7407,10 @@ struct bnx2_rv2p_fw_file {
#define BNX2_CONDITION_MFW_RUN_NCSI 0x00006000
#define BNX2_CONDITION_MFW_RUN_NONE 0x0000e000
#define BNX2_CONDITION_MFW_RUN_MASK 0x0000e000
+#define BNX2_CONDITION_PM_STATE_MASK 0x00030000
+#define BNX2_CONDITION_PM_STATE_FULL 0x00030000
+#define BNX2_CONDITION_PM_STATE_PREP 0x00020000
+#define BNX2_CONDITION_PM_STATE_UNPREP 0x00010000
#define BNX2_BC_STATE_DEBUG_CMD 0x1dc
#define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE 0x42440000
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 9d7419e0390b..dbcff509dc3f 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -1873,7 +1873,7 @@ void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
}
u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
struct bnx2x *bp = netdev_priv(dev);
@@ -1895,7 +1895,7 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
}
/* select a non-FCoE queue */
- return __netdev_pick_tx(dev, skb) % BNX2X_NUM_ETH_QUEUES(bp);
+ return fallback(dev, skb) % BNX2X_NUM_ETH_QUEUES(bp);
}
void bnx2x_set_num_queues(struct bnx2x *bp)
@@ -3875,7 +3875,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
xmit_type);
}
- /* Add the macs to the parsing BD this is a vf */
+ /* Add the macs to the parsing BD if this is a vf or if
+ * Tx Switching is enabled.
+ */
if (IS_VF(bp)) {
/* override GRE parameters in BD */
bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi,
@@ -3887,6 +3889,11 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
&pbd_e2->data.mac_addr.dst_mid,
&pbd_e2->data.mac_addr.dst_lo,
eth->h_dest);
+ } else if (bp->flags & TX_SWITCHING) {
+ bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi,
+ &pbd_e2->data.mac_addr.dst_mid,
+ &pbd_e2->data.mac_addr.dst_lo,
+ eth->h_dest);
}
SET_FLAG(pbd_e2_parsing_data,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index bfc58d488bb5..a89a40f88c25 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -496,7 +496,7 @@ int bnx2x_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos);
/* select_queue callback */
u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv);
+ void *accel_priv, select_queue_fallback_t fallback);
static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
struct bnx2x_fastpath *fp,
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index fcf9105a5476..09f3fefcbf9c 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -1,6 +1,6 @@
/* cnic.c: Broadcom CNIC core network driver.
*
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -342,7 +342,7 @@ static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
while (retry < 3) {
rc = 0;
rcu_read_lock();
- ulp_ops = rcu_dereference(cnic_ulp_tbl[CNIC_ULP_ISCSI]);
+ ulp_ops = rcu_dereference(cp->ulp_ops[CNIC_ULP_ISCSI]);
if (ulp_ops)
rc = ulp_ops->iscsi_nl_send_msg(
cp->ulp_handle[CNIC_ULP_ISCSI],
@@ -726,7 +726,7 @@ static void cnic_free_dma(struct cnic_dev *dev, struct cnic_dma *dma)
for (i = 0; i < dma->num_pages; i++) {
if (dma->pg_arr[i]) {
- dma_free_coherent(&dev->pcidev->dev, BNX2_PAGE_SIZE,
+ dma_free_coherent(&dev->pcidev->dev, CNIC_PAGE_SIZE,
dma->pg_arr[i], dma->pg_map_arr[i]);
dma->pg_arr[i] = NULL;
}
@@ -785,7 +785,7 @@ static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma,
for (i = 0; i < pages; i++) {
dma->pg_arr[i] = dma_alloc_coherent(&dev->pcidev->dev,
- BNX2_PAGE_SIZE,
+ CNIC_PAGE_SIZE,
&dma->pg_map_arr[i],
GFP_ATOMIC);
if (dma->pg_arr[i] == NULL)
@@ -794,8 +794,8 @@ static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma,
if (!use_pg_tbl)
return 0;
- dma->pgtbl_size = ((pages * 8) + BNX2_PAGE_SIZE - 1) &
- ~(BNX2_PAGE_SIZE - 1);
+ dma->pgtbl_size = ((pages * 8) + CNIC_PAGE_SIZE - 1) &
+ ~(CNIC_PAGE_SIZE - 1);
dma->pgtbl = dma_alloc_coherent(&dev->pcidev->dev, dma->pgtbl_size,
&dma->pgtbl_map, GFP_ATOMIC);
if (dma->pgtbl == NULL)
@@ -900,8 +900,8 @@ static int cnic_alloc_context(struct cnic_dev *dev)
if (BNX2_CHIP(cp) == BNX2_CHIP_5709) {
int i, k, arr_size;
- cp->ctx_blk_size = BNX2_PAGE_SIZE;
- cp->cids_per_blk = BNX2_PAGE_SIZE / 128;
+ cp->ctx_blk_size = CNIC_PAGE_SIZE;
+ cp->cids_per_blk = CNIC_PAGE_SIZE / 128;
arr_size = BNX2_MAX_CID / cp->cids_per_blk *
sizeof(struct cnic_ctx);
cp->ctx_arr = kzalloc(arr_size, GFP_KERNEL);
@@ -933,7 +933,7 @@ static int cnic_alloc_context(struct cnic_dev *dev)
for (i = 0; i < cp->ctx_blks; i++) {
cp->ctx_arr[i].ctx =
dma_alloc_coherent(&dev->pcidev->dev,
- BNX2_PAGE_SIZE,
+ CNIC_PAGE_SIZE,
&cp->ctx_arr[i].mapping,
GFP_KERNEL);
if (cp->ctx_arr[i].ctx == NULL)
@@ -1013,7 +1013,7 @@ static int __cnic_alloc_uio_rings(struct cnic_uio_dev *udev, int pages)
if (udev->l2_ring)
return 0;
- udev->l2_ring_size = pages * BNX2_PAGE_SIZE;
+ udev->l2_ring_size = pages * CNIC_PAGE_SIZE;
udev->l2_ring = dma_alloc_coherent(&udev->pdev->dev, udev->l2_ring_size,
&udev->l2_ring_map,
GFP_KERNEL | __GFP_COMP);
@@ -1021,7 +1021,7 @@ static int __cnic_alloc_uio_rings(struct cnic_uio_dev *udev, int pages)
return -ENOMEM;
udev->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
- udev->l2_buf_size = PAGE_ALIGN(udev->l2_buf_size);
+ udev->l2_buf_size = CNIC_PAGE_ALIGN(udev->l2_buf_size);
udev->l2_buf = dma_alloc_coherent(&udev->pdev->dev, udev->l2_buf_size,
&udev->l2_buf_map,
GFP_KERNEL | __GFP_COMP);
@@ -1102,7 +1102,7 @@ static int cnic_init_uio(struct cnic_dev *dev)
uinfo->mem[0].size = MB_GET_CID_ADDR(TX_TSS_CID +
TX_MAX_TSS_RINGS + 1);
uinfo->mem[1].addr = (unsigned long) cp->status_blk.gen &
- PAGE_MASK;
+ CNIC_PAGE_MASK;
if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9;
else
@@ -1113,7 +1113,7 @@ static int cnic_init_uio(struct cnic_dev *dev)
uinfo->mem[0].size = pci_resource_len(dev->pcidev, 0);
uinfo->mem[1].addr = (unsigned long) cp->bnx2x_def_status_blk &
- PAGE_MASK;
+ CNIC_PAGE_MASK;
uinfo->mem[1].size = sizeof(*cp->bnx2x_def_status_blk);
uinfo->name = "bnx2x_cnic";
@@ -1267,14 +1267,14 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
for (i = MAX_ISCSI_TBL_SZ; i < cp->max_cid_space; i++)
cp->ctx_tbl[i].ulp_proto_id = CNIC_ULP_FCOE;
- pages = PAGE_ALIGN(cp->max_cid_space * CNIC_KWQ16_DATA_SIZE) /
- PAGE_SIZE;
+ pages = CNIC_PAGE_ALIGN(cp->max_cid_space * CNIC_KWQ16_DATA_SIZE) /
+ CNIC_PAGE_SIZE;
ret = cnic_alloc_dma(dev, kwq_16_dma, pages, 0);
if (ret)
return -ENOMEM;
- n = PAGE_SIZE / CNIC_KWQ16_DATA_SIZE;
+ n = CNIC_PAGE_SIZE / CNIC_KWQ16_DATA_SIZE;
for (i = 0, j = 0; i < cp->max_cid_space; i++) {
long off = CNIC_KWQ16_DATA_SIZE * (i % n);
@@ -1296,7 +1296,7 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
goto error;
}
- pages = PAGE_ALIGN(BNX2X_ISCSI_GLB_BUF_SIZE) / PAGE_SIZE;
+ pages = CNIC_PAGE_ALIGN(BNX2X_ISCSI_GLB_BUF_SIZE) / CNIC_PAGE_SIZE;
ret = cnic_alloc_dma(dev, &cp->gbl_buf_info, pages, 0);
if (ret)
goto error;
@@ -1466,8 +1466,8 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
cp->r2tq_size = cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS *
BNX2X_ISCSI_R2TQE_SIZE;
cp->hq_size = cp->num_ccells * BNX2X_ISCSI_HQ_BD_SIZE;
- pages = PAGE_ALIGN(cp->hq_size) / PAGE_SIZE;
- hq_bds = pages * (PAGE_SIZE / BNX2X_ISCSI_HQ_BD_SIZE);
+ pages = CNIC_PAGE_ALIGN(cp->hq_size) / CNIC_PAGE_SIZE;
+ hq_bds = pages * (CNIC_PAGE_SIZE / BNX2X_ISCSI_HQ_BD_SIZE);
cp->num_cqs = req1->num_cqs;
if (!dev->max_iscsi_conn)
@@ -1477,9 +1477,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_RQ_SIZE_OFFSET(pfid),
req1->rq_num_wqes);
CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
- PAGE_SIZE);
+ CNIC_PAGE_SIZE);
CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
- TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+ TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
CNIC_WR16(dev, BAR_TSTRORM_INTMEM +
TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
req1->num_tasks_per_conn);
@@ -1489,9 +1489,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfid),
req1->rq_buffer_size);
CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
- PAGE_SIZE);
+ CNIC_PAGE_SIZE);
CNIC_WR8(dev, BAR_USTRORM_INTMEM +
- USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+ USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
CNIC_WR16(dev, BAR_USTRORM_INTMEM +
USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
req1->num_tasks_per_conn);
@@ -1504,9 +1504,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
/* init Xstorm RAM */
CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
- PAGE_SIZE);
+ CNIC_PAGE_SIZE);
CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
- XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+ XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
CNIC_WR16(dev, BAR_XSTRORM_INTMEM +
XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
req1->num_tasks_per_conn);
@@ -1519,9 +1519,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
/* init Cstorm RAM */
CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
- PAGE_SIZE);
+ CNIC_PAGE_SIZE);
CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
- CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+ CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
req1->num_tasks_per_conn);
@@ -1623,18 +1623,18 @@ static int cnic_alloc_bnx2x_conn_resc(struct cnic_dev *dev, u32 l5_cid)
}
ctx->cid = cid;
- pages = PAGE_ALIGN(cp->task_array_size) / PAGE_SIZE;
+ pages = CNIC_PAGE_ALIGN(cp->task_array_size) / CNIC_PAGE_SIZE;
ret = cnic_alloc_dma(dev, &iscsi->task_array_info, pages, 1);
if (ret)
goto error;
- pages = PAGE_ALIGN(cp->r2tq_size) / PAGE_SIZE;
+ pages = CNIC_PAGE_ALIGN(cp->r2tq_size) / CNIC_PAGE_SIZE;
ret = cnic_alloc_dma(dev, &iscsi->r2tq_info, pages, 1);
if (ret)
goto error;
- pages = PAGE_ALIGN(cp->hq_size) / PAGE_SIZE;
+ pages = CNIC_PAGE_ALIGN(cp->hq_size) / CNIC_PAGE_SIZE;
ret = cnic_alloc_dma(dev, &iscsi->hq_info, pages, 1);
if (ret)
goto error;
@@ -1760,7 +1760,7 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
ictx->tstorm_st_context.iscsi.hdr_bytes_2_fetch = ISCSI_HEADER_SIZE;
/* TSTORM requires the base address of RQ DB & not PTE */
ictx->tstorm_st_context.iscsi.rq_db_phy_addr.lo =
- req2->rq_page_table_addr_lo & PAGE_MASK;
+ req2->rq_page_table_addr_lo & CNIC_PAGE_MASK;
ictx->tstorm_st_context.iscsi.rq_db_phy_addr.hi =
req2->rq_page_table_addr_hi;
ictx->tstorm_st_context.iscsi.iscsi_conn_id = req1->iscsi_conn_id;
@@ -1842,7 +1842,7 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
/* CSTORM and USTORM initialization is different, CSTORM requires
* CQ DB base & not PTE addr */
ictx->cstorm_st_context.cq_db_base.lo =
- req1->cq_page_table_addr_lo & PAGE_MASK;
+ req1->cq_page_table_addr_lo & CNIC_PAGE_MASK;
ictx->cstorm_st_context.cq_db_base.hi = req1->cq_page_table_addr_hi;
ictx->cstorm_st_context.iscsi_conn_id = req1->iscsi_conn_id;
ictx->cstorm_st_context.cq_proc_en_bit_map = (1 << cp->num_cqs) - 1;
@@ -2911,7 +2911,7 @@ static int cnic_l2_completion(struct cnic_local *cp)
u16 hw_cons, sw_cons;
struct cnic_uio_dev *udev = cp->udev;
union eth_rx_cqe *cqe, *cqe_ring = (union eth_rx_cqe *)
- (udev->l2_ring + (2 * BNX2_PAGE_SIZE));
+ (udev->l2_ring + (2 * CNIC_PAGE_SIZE));
u32 cmd;
int comp = 0;
@@ -3244,7 +3244,8 @@ static int cnic_copy_ulp_stats(struct cnic_dev *dev, int ulp_type)
int rc;
mutex_lock(&cnic_lock);
- ulp_ops = cnic_ulp_tbl_prot(ulp_type);
+ ulp_ops = rcu_dereference_protected(cp->ulp_ops[ulp_type],
+ lockdep_is_held(&cnic_lock));
if (ulp_ops && ulp_ops->cnic_get_stats)
rc = ulp_ops->cnic_get_stats(cp->ulp_handle[ulp_type]);
else
@@ -4384,7 +4385,7 @@ static int cnic_setup_5709_context(struct cnic_dev *dev, int valid)
u32 idx = cp->ctx_arr[i].cid / cp->cids_per_blk;
u32 val;
- memset(cp->ctx_arr[i].ctx, 0, BNX2_PAGE_SIZE);
+ memset(cp->ctx_arr[i].ctx, 0, CNIC_PAGE_SIZE);
CNIC_WR(dev, BNX2_CTX_HOST_PAGE_TBL_DATA0,
(cp->ctx_arr[i].mapping & 0xffffffff) | valid_bit);
@@ -4628,7 +4629,7 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
val = BNX2_L2CTX_L2_STATUSB_NUM(sb_id);
cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_HOST_BDIDX, val);
- rxbd = udev->l2_ring + BNX2_PAGE_SIZE;
+ rxbd = udev->l2_ring + CNIC_PAGE_SIZE;
for (i = 0; i < BNX2_MAX_RX_DESC_CNT; i++, rxbd++) {
dma_addr_t buf_map;
int n = (i % cp->l2_rx_ring_size) + 1;
@@ -4639,11 +4640,11 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
rxbd->rx_bd_haddr_hi = (u64) buf_map >> 32;
rxbd->rx_bd_haddr_lo = (u64) buf_map & 0xffffffff;
}
- val = (u64) (ring_map + BNX2_PAGE_SIZE) >> 32;
+ val = (u64) (ring_map + CNIC_PAGE_SIZE) >> 32;
cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
rxbd->rx_bd_haddr_hi = val;
- val = (u64) (ring_map + BNX2_PAGE_SIZE) & 0xffffffff;
+ val = (u64) (ring_map + CNIC_PAGE_SIZE) & 0xffffffff;
cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
rxbd->rx_bd_haddr_lo = val;
@@ -4709,10 +4710,10 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
val = CNIC_RD(dev, BNX2_MQ_CONFIG);
val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
- if (BNX2_PAGE_BITS > 12)
+ if (CNIC_PAGE_BITS > 12)
val |= (12 - 8) << 4;
else
- val |= (BNX2_PAGE_BITS - 8) << 4;
+ val |= (CNIC_PAGE_BITS - 8) << 4;
CNIC_WR(dev, BNX2_MQ_CONFIG, val);
@@ -4742,13 +4743,13 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
/* Initialize the kernel work queue context. */
val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
- (BNX2_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+ (CNIC_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_TYPE, val);
- val = (BNX2_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16;
+ val = (CNIC_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16;
cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
- val = ((BNX2_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT;
+ val = ((CNIC_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT;
cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
val = (u32) ((u64) cp->kwq_info.pgtbl_map >> 32);
@@ -4768,13 +4769,13 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
/* Initialize the kernel complete queue context. */
val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
- (BNX2_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+ (CNIC_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_TYPE, val);
- val = (BNX2_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16;
+ val = (CNIC_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16;
cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
- val = ((BNX2_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT;
+ val = ((CNIC_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT;
cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
val = (u32) ((u64) cp->kcq1.dma.pgtbl_map >> 32);
@@ -4918,7 +4919,7 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev,
u32 cli = cp->ethdev->iscsi_l2_client_id;
u32 val;
- memset(txbd, 0, BNX2_PAGE_SIZE);
+ memset(txbd, 0, CNIC_PAGE_SIZE);
buf_map = udev->l2_buf_map;
for (i = 0; i < BNX2_MAX_TX_DESC_CNT; i += 3, txbd += 3) {
@@ -4978,9 +4979,9 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
struct bnx2x *bp = netdev_priv(dev->netdev);
struct cnic_uio_dev *udev = cp->udev;
struct eth_rx_bd *rxbd = (struct eth_rx_bd *) (udev->l2_ring +
- BNX2_PAGE_SIZE);
+ CNIC_PAGE_SIZE);
struct eth_rx_cqe_next_page *rxcqe = (struct eth_rx_cqe_next_page *)
- (udev->l2_ring + (2 * BNX2_PAGE_SIZE));
+ (udev->l2_ring + (2 * CNIC_PAGE_SIZE));
struct host_sp_status_block *sb = cp->bnx2x_def_status_blk;
int i;
u32 cli = cp->ethdev->iscsi_l2_client_id;
@@ -5004,20 +5005,20 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
rxbd->addr_lo = cpu_to_le32(buf_map & 0xffffffff);
}
- val = (u64) (ring_map + BNX2_PAGE_SIZE) >> 32;
+ val = (u64) (ring_map + CNIC_PAGE_SIZE) >> 32;
rxbd->addr_hi = cpu_to_le32(val);
data->rx.bd_page_base.hi = cpu_to_le32(val);
- val = (u64) (ring_map + BNX2_PAGE_SIZE) & 0xffffffff;
+ val = (u64) (ring_map + CNIC_PAGE_SIZE) & 0xffffffff;
rxbd->addr_lo = cpu_to_le32(val);
data->rx.bd_page_base.lo = cpu_to_le32(val);
rxcqe += BNX2X_MAX_RCQ_DESC_CNT;
- val = (u64) (ring_map + (2 * BNX2_PAGE_SIZE)) >> 32;
+ val = (u64) (ring_map + (2 * CNIC_PAGE_SIZE)) >> 32;
rxcqe->addr_hi = cpu_to_le32(val);
data->rx.cqe_page_base.hi = cpu_to_le32(val);
- val = (u64) (ring_map + (2 * BNX2_PAGE_SIZE)) & 0xffffffff;
+ val = (u64) (ring_map + (2 * CNIC_PAGE_SIZE)) & 0xffffffff;
rxcqe->addr_lo = cpu_to_le32(val);
data->rx.cqe_page_base.lo = cpu_to_le32(val);
@@ -5265,8 +5266,8 @@ static void cnic_shutdown_rings(struct cnic_dev *dev)
msleep(10);
}
clear_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags);
- rx_ring = udev->l2_ring + BNX2_PAGE_SIZE;
- memset(rx_ring, 0, BNX2_PAGE_SIZE);
+ rx_ring = udev->l2_ring + CNIC_PAGE_SIZE;
+ memset(rx_ring, 0, CNIC_PAGE_SIZE);
}
static int cnic_register_netdev(struct cnic_dev *dev)
diff --git a/drivers/net/ethernet/broadcom/cnic.h b/drivers/net/ethernet/broadcom/cnic.h
index 0d6b13f854d9..d535ae4228b4 100644
--- a/drivers/net/ethernet/broadcom/cnic.h
+++ b/drivers/net/ethernet/broadcom/cnic.h
@@ -1,6 +1,6 @@
/* cnic.h: Broadcom CNIC core network driver.
*
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/net/ethernet/broadcom/cnic_defs.h b/drivers/net/ethernet/broadcom/cnic_defs.h
index 95a8e4b11c9f..dcbca6997e8f 100644
--- a/drivers/net/ethernet/broadcom/cnic_defs.h
+++ b/drivers/net/ethernet/broadcom/cnic_defs.h
@@ -1,7 +1,7 @@
/* cnic.c: Broadcom CNIC core network driver.
*
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h
index 8cf6b1926069..5f4d5573a73d 100644
--- a/drivers/net/ethernet/broadcom/cnic_if.h
+++ b/drivers/net/ethernet/broadcom/cnic_if.h
@@ -1,6 +1,6 @@
/* cnic_if.h: Broadcom CNIC core network driver.
*
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,8 +14,8 @@
#include "bnx2x/bnx2x_mfw_req.h"
-#define CNIC_MODULE_VERSION "2.5.19"
-#define CNIC_MODULE_RELDATE "December 19, 2013"
+#define CNIC_MODULE_VERSION "2.5.20"
+#define CNIC_MODULE_RELDATE "March 14, 2014"
#define CNIC_ULP_RDMA 0
#define CNIC_ULP_ISCSI 1
@@ -24,6 +24,16 @@
#define MAX_CNIC_ULP_TYPE_EXT 3
#define MAX_CNIC_ULP_TYPE 4
+/* Use CPU native page size up to 16K for cnic ring sizes. */
+#if (PAGE_SHIFT > 14)
+#define CNIC_PAGE_BITS 14
+#else
+#define CNIC_PAGE_BITS PAGE_SHIFT
+#endif
+#define CNIC_PAGE_SIZE (1 << (CNIC_PAGE_BITS))
+#define CNIC_PAGE_ALIGN(addr) ALIGN(addr, CNIC_PAGE_SIZE)
+#define CNIC_PAGE_MASK (~((CNIC_PAGE_SIZE) - 1))
+
struct kwqe {
u32 kwqe_op_flag;
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 3167ed6593b0..70a225c8df5c 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -6843,8 +6843,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
work_mask |= opaque_key;
- if ((desc->err_vlan & RXD_ERR_MASK) != 0 &&
- (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) {
+ if (desc->err_vlan & RXD_ERR_MASK) {
drop_it:
tg3_recycle_rx(tnapi, tpr, opaque_key,
desc_idx, *post_ptr);
@@ -17650,8 +17649,6 @@ static int tg3_init_one(struct pci_dev *pdev,
tg3_init_bufmgr_config(tp);
- features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
-
/* 5700 B0 chips do not support checksumming correctly due
* to hardware bugs.
*/
@@ -17683,7 +17680,8 @@ static int tg3_init_one(struct pci_dev *pdev,
features |= NETIF_F_TSO_ECN;
}
- dev->features |= features;
+ dev->features |= features | NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX;
dev->vlan_features |= features;
/*
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index ef472385bce4..04321e5a356e 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -2608,7 +2608,11 @@ struct tg3_rx_buffer_desc {
#define RXD_ERR_TOO_SMALL 0x00400000
#define RXD_ERR_NO_RESOURCES 0x00800000
#define RXD_ERR_HUGE_FRAME 0x01000000
-#define RXD_ERR_MASK 0xffff0000
+
+#define RXD_ERR_MASK (RXD_ERR_BAD_CRC | RXD_ERR_COLLISION | \
+ RXD_ERR_LINK_LOST | RXD_ERR_PHY_DECODE | \
+ RXD_ERR_MAC_ABRT | RXD_ERR_TOO_SMALL | \
+ RXD_ERR_NO_RESOURCES | RXD_ERR_HUGE_FRAME)
u32 reserved;
u32 opaque;
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
index 1803c3959044..354ae9792bad 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
@@ -1704,7 +1704,7 @@ bfa_flash_sem_get(void __iomem *bar)
while (!bfa_raw_sem_get(bar)) {
if (--n <= 0)
return BFA_STATUS_BADFLASH;
- udelay(10000);
+ mdelay(10);
}
return BFA_STATUS_OK;
}
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index cf64f3d0b60d..4ad1187e82fb 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -707,7 +707,8 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
else
skb_checksum_none_assert(skb);
- if (flags & BNA_CQ_EF_VLAN)
+ if ((flags & BNA_CQ_EF_VLAN) &&
+ (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX))
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(cmpl->vlan_tag));
if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type))
@@ -2094,7 +2095,9 @@ bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config)
rx_config->q1_buf_size = BFI_SMALL_RXBUF_SIZE;
}
- rx_config->vlan_strip_status = BNA_STATUS_T_ENABLED;
+ rx_config->vlan_strip_status =
+ (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) ?
+ BNA_STATUS_T_ENABLED : BNA_STATUS_T_DISABLED;
}
static void
@@ -3245,11 +3248,6 @@ bnad_set_rx_mode(struct net_device *netdev)
BNA_RXMODE_ALLMULTI;
bna_rx_mode_set(bnad->rx_info[0].rx, new_mode, mode_mask, NULL);
- if (bnad->cfg_flags & BNAD_CF_PROMISC)
- bna_rx_vlan_strip_disable(bnad->rx_info[0].rx);
- else
- bna_rx_vlan_strip_enable(bnad->rx_info[0].rx);
-
spin_unlock_irqrestore(&bnad->bna_lock, flags);
}
@@ -3374,6 +3372,27 @@ bnad_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
return 0;
}
+static int bnad_set_features(struct net_device *dev, netdev_features_t features)
+{
+ struct bnad *bnad = netdev_priv(dev);
+ netdev_features_t changed = features ^ dev->features;
+
+ if ((changed & NETIF_F_HW_VLAN_CTAG_RX) && netif_running(dev)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&bnad->bna_lock, flags);
+
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ bna_rx_vlan_strip_enable(bnad->rx_info[0].rx);
+ else
+ bna_rx_vlan_strip_disable(bnad->rx_info[0].rx);
+
+ spin_unlock_irqrestore(&bnad->bna_lock, flags);
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void
bnad_netpoll(struct net_device *netdev)
@@ -3421,6 +3440,7 @@ static const struct net_device_ops bnad_netdev_ops = {
.ndo_change_mtu = bnad_change_mtu,
.ndo_vlan_rx_add_vid = bnad_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = bnad_vlan_rx_kill_vid,
+ .ndo_set_features = bnad_set_features,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = bnad_netpoll
#endif
@@ -3433,14 +3453,14 @@ bnad_netdev_init(struct bnad *bnad, bool using_dac)
netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX;
+ NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX;
netdev->vlan_features = NETIF_F_SG | NETIF_F_HIGHDMA |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_TSO | NETIF_F_TSO6;
- netdev->features |= netdev->hw_features |
- NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;
+ netdev->features |= netdev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER;
if (using_dac)
netdev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index 3190d38e16fb..d0c38e01e99f 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -632,11 +632,16 @@ static void gem_rx_refill(struct macb *bp)
"Unable to allocate sk_buff\n");
break;
}
- bp->rx_skbuff[entry] = skb;
/* now fill corresponding descriptor entry */
paddr = dma_map_single(&bp->pdev->dev, skb->data,
bp->rx_buffer_size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&bp->pdev->dev, paddr)) {
+ dev_kfree_skb(skb);
+ break;
+ }
+
+ bp->rx_skbuff[entry] = skb;
if (entry == RX_RING_SIZE - 1)
paddr |= MACB_BIT(RX_WRAP);
@@ -725,7 +730,7 @@ static int gem_rx(struct macb *bp, int budget)
skb_put(skb, len);
addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, addr));
dma_unmap_single(&bp->pdev->dev, addr,
- len, DMA_FROM_DEVICE);
+ bp->rx_buffer_size, DMA_FROM_DEVICE);
skb->protocol = eth_type_trans(skb, bp->dev);
skb_checksum_none_assert(skb);
@@ -1036,11 +1041,15 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
entry = macb_tx_ring_wrap(bp->tx_head);
- bp->tx_head++;
netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry);
mapping = dma_map_single(&bp->pdev->dev, skb->data,
len, DMA_TO_DEVICE);
+ if (dma_mapping_error(&bp->pdev->dev, mapping)) {
+ kfree_skb(skb);
+ goto unlock;
+ }
+ bp->tx_head++;
tx_skb = &bp->tx_skb[entry];
tx_skb->skb = skb;
tx_skb->mapping = mapping;
@@ -1066,6 +1075,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (CIRC_SPACE(bp->tx_head, bp->tx_tail, TX_RING_SIZE) < 1)
netif_stop_queue(dev);
+unlock:
spin_unlock_irqrestore(&bp->lock, flags);
return NETDEV_TX_OK;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 43ab35fea48d..34e2488767d9 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -6179,6 +6179,7 @@ static struct pci_driver cxgb4_driver = {
.id_table = cxgb4_pci_tbl,
.probe = init_one,
.remove = remove_one,
+ .shutdown = remove_one,
.err_handler = &cxgb4_eeh,
};
diff --git a/drivers/net/ethernet/dec/tulip/tulip_core.c b/drivers/net/ethernet/dec/tulip/tulip_core.c
index add05f14b38b..1642de78aac8 100644
--- a/drivers/net/ethernet/dec/tulip/tulip_core.c
+++ b/drivers/net/ethernet/dec/tulip/tulip_core.c
@@ -1939,6 +1939,7 @@ static void tulip_remove_one(struct pci_dev *pdev)
pci_iounmap(pdev, tp->base_addr);
free_netdev (dev);
pci_release_regions (pdev);
+ pci_disable_device(pdev);
/* pci_power_off (pdev, -1); */
}
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 8d09615da585..05529e273050 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -350,11 +350,13 @@ struct be_drv_stats {
u32 roce_drops_crc;
};
+/* A vlan-id of 0xFFFF must be used to clear transparent vlan-tagging */
+#define BE_RESET_VLAN_TAG_ID 0xFFFF
+
struct be_vf_cfg {
unsigned char mac_addr[ETH_ALEN];
int if_handle;
int pmac_id;
- u16 def_vid;
u16 vlan_tag;
u32 tx_rate;
};
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 04ac9c6a0d39..36c80612e21a 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -913,24 +913,14 @@ static int be_ipv6_tx_stall_chk(struct be_adapter *adapter,
return BE3_chip(adapter) && be_ipv6_exthdr_check(skb);
}
-static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
- struct sk_buff *skb,
- bool *skip_hw_vlan)
+static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
+ struct sk_buff *skb,
+ bool *skip_hw_vlan)
{
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
unsigned int eth_hdr_len;
struct iphdr *ip;
- /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or less
- * may cause a transmit stall on that port. So the work-around is to
- * pad short packets (<= 32 bytes) to a 36-byte length.
- */
- if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
- if (skb_padto(skb, 36))
- goto tx_drop;
- skb->len = 36;
- }
-
/* For padded packets, BE HW modifies tot_len field in IP header
* incorrecly when VLAN tag is inserted by HW.
* For padded packets, Lancer computes incorrect checksum.
@@ -959,7 +949,7 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
vlan_tx_tag_present(skb)) {
skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
if (unlikely(!skb))
- goto tx_drop;
+ goto err;
}
/* HW may lockup when VLAN HW tagging is requested on
@@ -981,15 +971,39 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
be_vlan_tag_tx_chk(adapter, skb)) {
skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
if (unlikely(!skb))
- goto tx_drop;
+ goto err;
}
return skb;
tx_drop:
dev_kfree_skb_any(skb);
+err:
return NULL;
}
+static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
+ struct sk_buff *skb,
+ bool *skip_hw_vlan)
+{
+ /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or
+ * less may cause a transmit stall on that port. So the work-around is
+ * to pad short packets (<= 32 bytes) to a 36-byte length.
+ */
+ if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
+ if (skb_padto(skb, 36))
+ return NULL;
+ skb->len = 36;
+ }
+
+ if (BEx_chip(adapter) || lancer_chip(adapter)) {
+ skb = be_lancer_xmit_workarounds(adapter, skb, skip_hw_vlan);
+ if (!skb)
+ return NULL;
+ }
+
+ return skb;
+}
+
static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
@@ -1157,6 +1171,14 @@ ret:
return status;
}
+static void be_clear_promisc(struct be_adapter *adapter)
+{
+ adapter->promiscuous = false;
+ adapter->flags &= ~BE_FLAGS_VLAN_PROMISC;
+
+ be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
+}
+
static void be_set_rx_mode(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
@@ -1170,9 +1192,7 @@ static void be_set_rx_mode(struct net_device *netdev)
/* BE was previously in promiscuous mode; disable it */
if (adapter->promiscuous) {
- adapter->promiscuous = false;
- be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
-
+ be_clear_promisc(adapter);
if (adapter->vlans_added)
be_vid_config(adapter);
}
@@ -1287,24 +1307,20 @@ static int be_set_vf_vlan(struct net_device *netdev,
if (vlan || qos) {
vlan |= qos << VLAN_PRIO_SHIFT;
- if (vf_cfg->vlan_tag != vlan) {
- /* If this is new value, program it. Else skip. */
- vf_cfg->vlan_tag = vlan;
+ if (vf_cfg->vlan_tag != vlan)
status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
vf_cfg->if_handle, 0);
- }
} else {
/* Reset Transparent Vlan Tagging. */
- vf_cfg->vlan_tag = 0;
- vlan = vf_cfg->def_vid;
- status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
- vf_cfg->if_handle, 0);
+ status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID,
+ vf + 1, vf_cfg->if_handle, 0);
}
-
- if (status)
+ if (!status)
+ vf_cfg->vlan_tag = vlan;
+ else
dev_info(&adapter->pdev->dev,
- "VLAN %d config on VF %d failed\n", vlan, vf);
+ "VLAN %d config on VF %d failed\n", vlan, vf);
return status;
}
@@ -3013,11 +3029,11 @@ static int be_vf_setup_init(struct be_adapter *adapter)
static int be_vf_setup(struct be_adapter *adapter)
{
+ struct device *dev = &adapter->pdev->dev;
struct be_vf_cfg *vf_cfg;
- u16 def_vlan, lnk_speed;
int status, old_vfs, vf;
- struct device *dev = &adapter->pdev->dev;
u32 privileges;
+ u16 lnk_speed;
old_vfs = pci_num_vf(adapter->pdev);
if (old_vfs) {
@@ -3084,12 +3100,6 @@ static int be_vf_setup(struct be_adapter *adapter)
if (!status)
vf_cfg->tx_rate = lnk_speed;
- status = be_cmd_get_hsw_config(adapter, &def_vlan,
- vf + 1, vf_cfg->if_handle, NULL);
- if (status)
- goto err;
- vf_cfg->def_vid = def_vlan;
-
if (!old_vfs)
be_cmd_enable_vf(adapter, vf + 1);
}
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index d4782b42401b..03a351300013 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -389,12 +389,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
netdev_err(ndev, "Tx DMA memory map failed\n");
return NETDEV_TX_OK;
}
- /* Send it on its way. Tell FEC it's ready, interrupt when done,
- * it's the last BD of the frame, and to put the CRC on the end.
- */
- status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
- | BD_ENET_TX_LAST | BD_ENET_TX_TC);
- bdp->cbd_sc = status;
if (fep->bufdesc_ex) {
@@ -416,6 +410,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
}
+ /* Send it on its way. Tell FEC it's ready, interrupt when done,
+ * it's the last BD of the frame, and to put the CRC on the end.
+ */
+ status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
+ | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+ bdp->cbd_sc = status;
+
bdp_pre = fec_enet_get_prevdesc(bdp, fep);
if ((id_entry->driver_data & FEC_QUIRK_ERR006358) &&
!(bdp_pre->cbd_sc & BD_ENET_TX_READY)) {
@@ -527,13 +528,6 @@ fec_restart(struct net_device *ndev, int duplex)
/* Clear any outstanding interrupt. */
writel(0xffc00000, fep->hwp + FEC_IEVENT);
- /* Setup multicast filter. */
- set_multicast_list(ndev);
-#ifndef CONFIG_M5272
- writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
- writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
-#endif
-
/* Set maximum receive buffer size. */
writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
@@ -654,6 +648,13 @@ fec_restart(struct net_device *ndev, int duplex)
writel(rcntl, fep->hwp + FEC_R_CNTRL);
+ /* Setup multicast filter. */
+ set_multicast_list(ndev);
+#ifndef CONFIG_M5272
+ writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
+ writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
+#endif
+
if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
/* enable ENET endian swap */
ecntl |= (1 << 8);
@@ -1778,8 +1779,6 @@ fec_enet_open(struct net_device *ndev)
struct fec_enet_private *fep = netdev_priv(ndev);
int ret;
- napi_enable(&fep->napi);
-
/* I should reset the ring buffers here, but I don't yet know
* a simple way to do that.
*/
@@ -1794,6 +1793,8 @@ fec_enet_open(struct net_device *ndev)
fec_enet_free_buffers(ndev);
return ret;
}
+
+ napi_enable(&fep->napi);
phy_start(fep->phy_dev);
netif_start_queue(ndev);
fep->opened = 1;
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 4be971590461..1fc8334fc181 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -522,10 +522,21 @@ retry:
return rc;
}
+static u64 ibmveth_encode_mac_addr(u8 *mac)
+{
+ int i;
+ u64 encoded = 0;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ encoded = (encoded << 8) | mac[i];
+
+ return encoded;
+}
+
static int ibmveth_open(struct net_device *netdev)
{
struct ibmveth_adapter *adapter = netdev_priv(netdev);
- u64 mac_address = 0;
+ u64 mac_address;
int rxq_entries = 1;
unsigned long lpar_rc;
int rc;
@@ -579,8 +590,7 @@ static int ibmveth_open(struct net_device *netdev)
adapter->rx_queue.num_slots = rxq_entries;
adapter->rx_queue.toggle = 1;
- memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
- mac_address = mac_address >> 16;
+ mac_address = ibmveth_encode_mac_addr(netdev->dev_addr);
rxq_desc.fields.flags_len = IBMVETH_BUF_VALID |
adapter->rx_queue.queue_len;
@@ -1183,8 +1193,8 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
/* add the addresses to the filter table */
netdev_for_each_mc_addr(ha, netdev) {
/* add the multicast address to the filter table */
- unsigned long mcast_addr = 0;
- memcpy(((char *)&mcast_addr)+2, ha->addr, ETH_ALEN);
+ u64 mcast_addr;
+ mcast_addr = ibmveth_encode_mac_addr(ha->addr);
lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
IbmVethMcastAddFilter,
mcast_addr);
@@ -1372,9 +1382,6 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
- adapter->mac_addr = 0;
- memcpy(&adapter->mac_addr, mac_addr_p, ETH_ALEN);
-
netdev->irq = dev->irq;
netdev->netdev_ops = &ibmveth_netdev_ops;
netdev->ethtool_ops = &netdev_ethtool_ops;
@@ -1383,7 +1390,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
netdev->features |= netdev->hw_features;
- memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len);
+ memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN);
for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h
index 451ba7949e15..1f37499d4398 100644
--- a/drivers/net/ethernet/ibm/ibmveth.h
+++ b/drivers/net/ethernet/ibm/ibmveth.h
@@ -138,7 +138,6 @@ struct ibmveth_adapter {
struct napi_struct napi;
struct net_device_stats stats;
unsigned int mcastFilterSize;
- unsigned long mac_addr;
void * buffer_list_addr;
void * filter_list_addr;
dma_addr_t buffer_list_dma;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 6d4ada72dfd0..18076c4178b4 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -6881,7 +6881,7 @@ static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
}
static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
struct ixgbe_fwd_adapter *fwd_adapter = accel_priv;
#ifdef IXGBE_FCOE
@@ -6907,7 +6907,7 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
break;
default:
- return __netdev_pick_tx(dev, skb);
+ return fallback(dev, skb);
}
f = &adapter->ring_feature[RING_F_FCOE];
@@ -6920,7 +6920,7 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
return txq + f->offset;
#else
- return __netdev_pick_tx(dev, skb);
+ return fallback(dev, skb);
#endif
}
diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c
index 8f9266c64c75..fd4b6aecf6ee 100644
--- a/drivers/net/ethernet/lantiq_etop.c
+++ b/drivers/net/ethernet/lantiq_etop.c
@@ -619,7 +619,7 @@ ltq_etop_set_multicast_list(struct net_device *dev)
static u16
ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
/* we are currently only using the first queue */
return 0;
diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig
index 6300fd27f2db..68e6a6613e9a 100644
--- a/drivers/net/ethernet/marvell/Kconfig
+++ b/drivers/net/ethernet/marvell/Kconfig
@@ -43,12 +43,12 @@ config MVMDIO
This driver is used by the MV643XX_ETH and MVNETA drivers.
config MVNETA
- tristate "Marvell Armada 370/XP network interface support"
- depends on MACH_ARMADA_370_XP
+ tristate "Marvell Armada 370/38x/XP network interface support"
+ depends on PLAT_ORION
select MVMDIO
---help---
This driver supports the network interface units in the
- Marvell ARMADA XP and ARMADA 370 SoC family.
+ Marvell ARMADA XP, ARMADA 370 and ARMADA 38x SoC family.
Note that this driver is distinct from the mv643xx_eth
driver, which should be used for the older Marvell SoCs
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index f418f4f20f94..8d76fca7fde7 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -22,6 +22,7 @@
#include <linux/interrupt.h>
#include <net/ip.h>
#include <net/ipv6.h>
+#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
@@ -88,8 +89,9 @@
#define MVNETA_TX_IN_PRGRS BIT(1)
#define MVNETA_TX_FIFO_EMPTY BIT(8)
#define MVNETA_RX_MIN_FRAME_SIZE 0x247c
-#define MVNETA_SGMII_SERDES_CFG 0x24A0
+#define MVNETA_SERDES_CFG 0x24A0
#define MVNETA_SGMII_SERDES_PROTO 0x0cc7
+#define MVNETA_RGMII_SERDES_PROTO 0x0667
#define MVNETA_TYPE_PRIO 0x24bc
#define MVNETA_FORCE_UNI BIT(21)
#define MVNETA_TXQ_CMD_1 0x24e4
@@ -161,7 +163,7 @@
#define MVNETA_GMAC_MAX_RX_SIZE_MASK 0x7ffc
#define MVNETA_GMAC0_PORT_ENABLE BIT(0)
#define MVNETA_GMAC_CTRL_2 0x2c08
-#define MVNETA_GMAC2_PSC_ENABLE BIT(3)
+#define MVNETA_GMAC2_PCS_ENABLE BIT(3)
#define MVNETA_GMAC2_PORT_RGMII BIT(4)
#define MVNETA_GMAC2_PORT_RESET BIT(6)
#define MVNETA_GMAC_STATUS 0x2c10
@@ -710,35 +712,6 @@ static void mvneta_rxq_bm_disable(struct mvneta_port *pp,
mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val);
}
-
-
-/* Sets the RGMII Enable bit (RGMIIEn) in port MAC control register */
-static void mvneta_gmac_rgmii_set(struct mvneta_port *pp, int enable)
-{
- u32 val;
-
- val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
-
- if (enable)
- val |= MVNETA_GMAC2_PORT_RGMII;
- else
- val &= ~MVNETA_GMAC2_PORT_RGMII;
-
- mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
-}
-
-/* Config SGMII port */
-static void mvneta_port_sgmii_config(struct mvneta_port *pp)
-{
- u32 val;
-
- val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
- val |= MVNETA_GMAC2_PSC_ENABLE;
- mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
-
- mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
-}
-
/* Start the Ethernet port RX and TX activity */
static void mvneta_port_up(struct mvneta_port *pp)
{
@@ -2756,12 +2729,15 @@ static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
mvreg_write(pp, MVNETA_UNIT_INTR_CAUSE, 0);
if (phy_mode == PHY_INTERFACE_MODE_SGMII)
- mvneta_port_sgmii_config(pp);
+ mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
+ else
+ mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_RGMII_SERDES_PROTO);
+
+ val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
- mvneta_gmac_rgmii_set(pp, 1);
+ val |= MVNETA_GMAC2_PCS_ENABLE | MVNETA_GMAC2_PORT_RGMII;
/* Cancel Port Reset */
- val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
val &= ~MVNETA_GMAC2_PORT_RESET;
mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
@@ -2774,6 +2750,7 @@ static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
static int mvneta_probe(struct platform_device *pdev)
{
const struct mbus_dram_target_info *dram_target_info;
+ struct resource *res;
struct device_node *dn = pdev->dev.of_node;
struct device_node *phy_node;
u32 phy_addr;
@@ -2838,9 +2815,15 @@ static int mvneta_probe(struct platform_device *pdev)
clk_prepare_enable(pp->clk);
- pp->base = of_iomap(dn, 0);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ err = -ENODEV;
+ goto err_clk;
+ }
+
+ pp->base = devm_ioremap_resource(&pdev->dev, res);
if (pp->base == NULL) {
- err = -ENOMEM;
+ err = PTR_ERR(pp->base);
goto err_clk;
}
@@ -2848,7 +2831,7 @@ static int mvneta_probe(struct platform_device *pdev)
pp->stats = alloc_percpu(struct mvneta_pcpu_stats);
if (!pp->stats) {
err = -ENOMEM;
- goto err_unmap;
+ goto err_clk;
}
for_each_possible_cpu(cpu) {
@@ -2913,8 +2896,6 @@ err_deinit:
mvneta_deinit(pp);
err_free_stats:
free_percpu(pp->stats);
-err_unmap:
- iounmap(pp->base);
err_clk:
clk_disable_unprepare(pp->clk);
err_free_irq:
@@ -2934,7 +2915,6 @@ static int mvneta_remove(struct platform_device *pdev)
mvneta_deinit(pp);
clk_disable_unprepare(pp->clk);
free_percpu(pp->stats);
- iounmap(pp->base);
irq_dispose_mapping(dev->irq);
free_netdev(dev);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index fad45316200a..84a96f70dfb5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -742,6 +742,14 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
err = mlx4_en_uc_steer_add(priv, new_mac,
&qpn,
&entry->reg_id);
+ if (err)
+ return err;
+ if (priv->tunnel_reg_id) {
+ mlx4_flow_detach(priv->mdev->dev, priv->tunnel_reg_id);
+ priv->tunnel_reg_id = 0;
+ }
+ err = mlx4_en_tunnel_steer_add(priv, new_mac, qpn,
+ &priv->tunnel_reg_id);
return err;
}
}
@@ -1792,6 +1800,8 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
mc_list[5] = priv->port;
mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
mc_list, MLX4_PROT_ETH, mclist->reg_id);
+ if (mclist->tunnel_reg_id)
+ mlx4_flow_detach(mdev->dev, mclist->tunnel_reg_id);
}
mlx4_en_clear_list(dev);
list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) {
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 8e8a7eb43a2c..13457032d15f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -629,7 +629,7 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
}
u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
u16 rings_p_up = priv->num_tx_rings_p_up;
@@ -641,7 +641,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
if (vlan_tx_tag_present(skb))
up = vlan_tx_tag_get(skb) >> VLAN_PRIO_SHIFT;
- return __netdev_pick_tx(dev, skb) % rings_p_up + up * rings_p_up;
+ return fallback(dev, skb) % rings_p_up + up * rings_p_up;
}
static void mlx4_bf_copy(void __iomem *dst, unsigned long *src, unsigned bytecnt)
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index 91b69ff4b4a2..7e2995ecea6f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -129,13 +129,14 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
[0] = "RSS support",
[1] = "RSS Toeplitz Hash Function support",
[2] = "RSS XOR Hash Function support",
- [3] = "Device manage flow steering support",
+ [3] = "Device managed flow steering support",
[4] = "Automatic MAC reassignment support",
[5] = "Time stamping support",
[6] = "VST (control vlan insertion/stripping) support",
[7] = "FSM (MAC anti-spoofing) support",
[8] = "Dynamic QP updates support",
- [9] = "TCP/IP offloads/flow-steering for VXLAN support"
+ [9] = "Device managed flow steering IPoIB support",
+ [10] = "TCP/IP offloads/flow-steering for VXLAN support"
};
int i;
@@ -859,7 +860,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
/* For guests, disable vxlan tunneling */
- MLX4_GET(field, outbox, QUERY_DEV_CAP_VXLAN);
+ MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VXLAN);
field &= 0xf7;
MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VXLAN);
@@ -869,7 +870,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_BF_OFFSET);
/* For guests, disable mw type 2 */
- MLX4_GET(bmme_flags, outbox, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
+ MLX4_GET(bmme_flags, outbox->buf, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN;
MLX4_PUT(outbox->buf, bmme_flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
@@ -883,7 +884,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
}
/* turn off ipoib managed steering for guests */
- MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
+ MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
field &= ~0x80;
MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index d711158b0d4b..d413e60071d4 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -150,6 +150,8 @@ struct mlx4_port_config {
struct pci_dev *pdev;
};
+static atomic_t pf_loading = ATOMIC_INIT(0);
+
int mlx4_check_port_params(struct mlx4_dev *dev,
enum mlx4_port_type *port_type)
{
@@ -749,7 +751,7 @@ static void mlx4_request_modules(struct mlx4_dev *dev)
has_eth_port = true;
}
- if (has_ib_port)
+ if (has_ib_port || (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE))
request_module_nowait(IB_DRV_NAME);
if (has_eth_port)
request_module_nowait(EN_DRV_NAME);
@@ -1407,6 +1409,11 @@ static int mlx4_init_slave(struct mlx4_dev *dev)
u32 slave_read;
u32 cmd_channel_ver;
+ if (atomic_read(&pf_loading)) {
+ mlx4_warn(dev, "PF is not ready. Deferring probe\n");
+ return -EPROBE_DEFER;
+ }
+
mutex_lock(&priv->cmd.slave_cmd_mutex);
priv->cmd.max_cmds = 1;
mlx4_warn(dev, "Sending reset\n");
@@ -2319,7 +2326,11 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
if (num_vfs) {
mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n", num_vfs);
+
+ atomic_inc(&pf_loading);
err = pci_enable_sriov(pdev, num_vfs);
+ atomic_dec(&pf_loading);
+
if (err) {
mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d).\n",
err);
@@ -2670,7 +2681,11 @@ static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev,
static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev)
{
- int ret = __mlx4_init_one(pdev, 0);
+ const struct pci_device_id *id;
+ int ret;
+
+ id = pci_match_id(mlx4_pci_table, pdev);
+ ret = __mlx4_init_one(pdev, id->driver_data);
return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
}
@@ -2684,6 +2699,7 @@ static struct pci_driver mlx4_driver = {
.name = DRV_NAME,
.id_table = mlx4_pci_table,
.probe = mlx4_init_one,
+ .shutdown = mlx4_remove_one,
.remove = mlx4_remove_one,
.err_handler = &mlx4_err_handler,
};
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index 6b65f7795215..7aec6c833973 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -51,8 +51,8 @@
#define DRV_NAME "mlx4_core"
#define PFX DRV_NAME ": "
-#define DRV_VERSION "1.1"
-#define DRV_RELDATE "Dec, 2011"
+#define DRV_VERSION "2.2-1"
+#define DRV_RELDATE "Feb, 2014"
#define MLX4_FS_UDP_UC_EN (1 << 1)
#define MLX4_FS_TCP_UC_EN (1 << 2)
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 3af04c3f42ea..b57e8c87a34e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -57,8 +57,8 @@
#include "en_port.h"
#define DRV_NAME "mlx4_en"
-#define DRV_VERSION "2.0"
-#define DRV_RELDATE "Dec 2011"
+#define DRV_VERSION "2.2-1"
+#define DRV_RELDATE "Feb 2014"
#define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN)
@@ -723,7 +723,7 @@ int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
void mlx4_en_tx_irq(struct mlx4_cq *mcq);
u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv);
+ void *accel_priv, select_queue_fallback_t fallback);
netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev);
int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index a064f06e0cb8..23b7e2d35a93 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -46,8 +46,8 @@
#include "mlx5_core.h"
#define DRIVER_NAME "mlx5_core"
-#define DRIVER_VERSION "1.0"
-#define DRIVER_RELDATE "June 2013"
+#define DRIVER_VERSION "2.2-1"
+#define DRIVER_RELDATE "Feb 2014"
MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
MODULE_DESCRIPTION("Mellanox ConnectX-IB HCA core library");
diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c
index 727b546a9eb8..e0c92e0e5e1d 100644
--- a/drivers/net/ethernet/micrel/ks8851.c
+++ b/drivers/net/ethernet/micrel/ks8851.c
@@ -23,6 +23,7 @@
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/eeprom_93cx6.h>
+#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
@@ -83,6 +84,7 @@ union ks8851_tx_hdr {
* @rc_rxqcr: Cached copy of KS_RXQCR.
* @eeprom_size: Companion eeprom size in Bytes, 0 if no eeprom
* @eeprom: 93CX6 EEPROM state for accessing on-board EEPROM.
+ * @vdd_reg: Optional regulator supplying the chip
*
* The @lock ensures that the chip is protected when certain operations are
* in progress. When the read or write packet transfer is in progress, most
@@ -130,6 +132,7 @@ struct ks8851_net {
struct spi_transfer spi_xfer2[2];
struct eeprom_93cx6 eeprom;
+ struct regulator *vdd_reg;
};
static int msg_enable;
@@ -1414,6 +1417,21 @@ static int ks8851_probe(struct spi_device *spi)
ks->spidev = spi;
ks->tx_space = 6144;
+ ks->vdd_reg = regulator_get_optional(&spi->dev, "vdd");
+ if (IS_ERR(ks->vdd_reg)) {
+ ret = PTR_ERR(ks->vdd_reg);
+ if (ret == -EPROBE_DEFER)
+ goto err_reg;
+ } else {
+ ret = regulator_enable(ks->vdd_reg);
+ if (ret) {
+ dev_err(&spi->dev, "regulator enable fail: %d\n",
+ ret);
+ goto err_reg_en;
+ }
+ }
+
+
mutex_init(&ks->lock);
spin_lock_init(&ks->statelock);
@@ -1508,8 +1526,14 @@ static int ks8851_probe(struct spi_device *spi)
err_netdev:
free_irq(ndev->irq, ks);
-err_id:
err_irq:
+err_id:
+ if (!IS_ERR(ks->vdd_reg))
+ regulator_disable(ks->vdd_reg);
+err_reg_en:
+ if (!IS_ERR(ks->vdd_reg))
+ regulator_put(ks->vdd_reg);
+err_reg:
free_netdev(ndev);
return ret;
}
@@ -1523,6 +1547,10 @@ static int ks8851_remove(struct spi_device *spi)
unregister_netdev(priv->netdev);
free_irq(spi->irq, priv);
+ if (!IS_ERR(priv->vdd_reg)) {
+ regulator_disable(priv->vdd_reg);
+ regulator_put(priv->vdd_reg);
+ }
free_netdev(priv->netdev);
return 0;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index 4146664d4d6a..27c4f131863b 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -340,6 +340,7 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter)
if (qlcnic_sriov_vf_check(adapter))
return -EINVAL;
num_msix = 1;
+ adapter->drv_sds_rings = QLCNIC_SINGLE_RING;
adapter->drv_tx_rings = QLCNIC_SINGLE_RING;
}
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
index 77f1bce432d2..7d4f54912bad 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
@@ -807,7 +807,7 @@ qlcnic_dcb_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, u8 *prio,
!type->tc_param_valid)
return;
- if (tc < 0 || (tc > QLC_DCB_MAX_TC))
+ if (tc < 0 || (tc >= QLC_DCB_MAX_TC))
return;
tc_cfg = &type->tc_cfg[tc];
@@ -843,7 +843,7 @@ static void qlcnic_dcb_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid,
!type->tc_param_valid)
return;
- if (pgid < 0 || pgid > QLC_DCB_MAX_PG)
+ if (pgid < 0 || pgid >= QLC_DCB_MAX_PG)
return;
pgcfg = &type->pg_cfg[pgid];
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index ba78c7481fa3..1222865cfb73 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -816,9 +816,10 @@ static int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter)
if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
qlcnic_disable_multi_tx(adapter);
+ adapter->drv_sds_rings = QLCNIC_SINGLE_RING;
err = qlcnic_enable_msi_legacy(adapter);
- if (!err)
+ if (err)
return err;
}
}
@@ -3863,7 +3864,7 @@ int qlcnic_validate_rings(struct qlcnic_adapter *adapter, __u32 ring_cnt,
strcpy(buf, "Tx");
}
- if (!qlcnic_use_msi_x && !qlcnic_use_msi) {
+ if (!QLCNIC_IS_MSI_FAMILY(adapter)) {
netdev_err(netdev, "No RSS/TSS support in INT-x mode\n");
return -EINVAL;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
index 09acf15c3a56..e5277a632671 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
@@ -13,8 +13,6 @@
#define QLC_VF_MIN_TX_RATE 100
#define QLC_VF_MAX_TX_RATE 9999
#define QLC_MAC_OPCODE_MASK 0x7
-#define QLC_MAC_STAR_ADD 6
-#define QLC_MAC_STAR_DEL 7
#define QLC_VF_FLOOD_BIT BIT_16
#define QLC_FLOOD_MODE 0x5
@@ -1206,13 +1204,6 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter,
struct qlcnic_vport *vp = vf->vp;
u8 op, new_op;
- if (((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_ADD) ||
- ((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_DEL)) {
- netdev_err(adapter->netdev, "MAC + any VLAN filter not allowed from VF %d\n",
- vf->pci_func);
- return -EINVAL;
- }
-
if (!(cmd->req.arg[1] & BIT_8))
return -EINVAL;
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index ce2cfddbed50..656c65ddadb4 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -4765,7 +4765,9 @@ static int qlge_probe(struct pci_dev *pdev,
ndev->features = ndev->hw_features;
ndev->vlan_features = ndev->hw_features;
/* vlan gets same features (except vlan filter) */
- ndev->vlan_features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
+ ndev->vlan_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER |
+ NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX);
if (test_bit(QL_DMA64, &qdev->flags))
ndev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 91a67ae8f17b..3ff7bc3e7a23 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -209,7 +209,7 @@ static const struct {
[RTL_GIGA_MAC_VER_16] =
_R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
[RTL_GIGA_MAC_VER_17] =
- _R("RTL8168b/8111b", RTL_TD_1, NULL, JUMBO_4K, false),
+ _R("RTL8168b/8111b", RTL_TD_0, NULL, JUMBO_4K, false),
[RTL_GIGA_MAC_VER_18] =
_R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
[RTL_GIGA_MAC_VER_19] =
@@ -7118,6 +7118,8 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
mutex_init(&tp->wk.mutex);
+ u64_stats_init(&tp->rx_stats.syncp);
+ u64_stats_init(&tp->tx_stats.syncp);
/* Get MAC address */
for (i = 0; i < ETH_ALEN; i++)
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index eb75fbd11a01..d7a36829649a 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -1668,6 +1668,13 @@ void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev)
struct efx_ptp_data *ptp = efx->ptp_data;
int code = EFX_QWORD_FIELD(*ev, MCDI_EVENT_CODE);
+ if (!ptp) {
+ if (net_ratelimit())
+ netif_warn(efx, drv, efx->net_dev,
+ "Received PTP event but PTP not set up\n");
+ return;
+ }
+
if (!ptp->enabled)
return;
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index e2f202e3932f..f2d7c702c77f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -37,6 +37,17 @@ config DWMAC_SUNXI
stmmac device driver. This driver is used for A20/A31
GMAC ethernet controller.
+config DWMAC_STI
+ bool "STi GMAC support"
+ depends on STMMAC_PLATFORM && ARCH_STI
+ default y
+ ---help---
+ Support for ethernet controller on STi SOCs.
+
+ This selects STi SoC glue layer support for the stmmac
+ device driver. This driver is used on for the STi series
+ SOCs GMAC ethernet controller.
+
config STMMAC_PCI
bool "STMMAC PCI bus support"
depends on STMMAC_ETH && PCI
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index ecadecea79b2..dcef28775dad 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_STMMAC_ETH) += stmmac.o
stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
stmmac-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
+stmmac-$(CONFIG_DWMAC_STI) += dwmac-sti.o
stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index 72d282bf33a5..c553f6b5a913 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -151,7 +151,7 @@ static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
sizeof(struct dma_desc)));
}
-const struct stmmac_chain_mode_ops chain_mode_ops = {
+const struct stmmac_mode_ops chain_mode_ops = {
.init = stmmac_init_dma_chain,
.is_jumbo_frm = stmmac_is_jumbo_frm,
.jumbo_frm = stmmac_jumbo_frm,
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 7834a3993946..74610f3aca9e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -419,20 +419,13 @@ struct mii_regs {
unsigned int data; /* MII Data */
};
-struct stmmac_ring_mode_ops {
- unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
- unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
- void (*refill_desc3) (void *priv, struct dma_desc *p);
- void (*init_desc3) (struct dma_desc *p);
- void (*clean_desc3) (void *priv, struct dma_desc *p);
- int (*set_16kib_bfsize) (int mtu);
-};
-
-struct stmmac_chain_mode_ops {
+struct stmmac_mode_ops {
void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,
unsigned int extend_desc);
unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
+ int (*set_16kib_bfsize)(int mtu);
+ void (*init_desc3)(struct dma_desc *p);
void (*refill_desc3) (void *priv, struct dma_desc *p);
void (*clean_desc3) (void *priv, struct dma_desc *p);
};
@@ -441,8 +434,7 @@ struct mac_device_info {
const struct stmmac_ops *mac;
const struct stmmac_desc_ops *desc;
const struct stmmac_dma_ops *dma;
- const struct stmmac_ring_mode_ops *ring;
- const struct stmmac_chain_mode_ops *chain;
+ const struct stmmac_mode_ops *mode;
const struct stmmac_hwtimestamp *ptp;
struct mii_regs mii; /* MII register Addresses */
struct mac_link link;
@@ -460,7 +452,7 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
void stmmac_set_mac(void __iomem *ioaddr, bool enable);
void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
-extern const struct stmmac_ring_mode_ops ring_mode_ops;
-extern const struct stmmac_chain_mode_ops chain_mode_ops;
+extern const struct stmmac_mode_ops ring_mode_ops;
+extern const struct stmmac_mode_ops chain_mode_ops;
#endif /* __COMMON_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
new file mode 100644
index 000000000000..552bbc17863c
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
@@ -0,0 +1,330 @@
+/**
+ * dwmac-sti.c - STMicroelectronics DWMAC Specific Glue layer
+ *
+ * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/stmmac.h>
+#include <linux/phy.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+
+/**
+ * STi GMAC glue logic.
+ * --------------------
+ *
+ * _
+ * | \
+ * --------|0 \ ETH_SEL_INTERNAL_NOTEXT_PHYCLK
+ * phyclk | |___________________________________________
+ * | | | (phyclk-in)
+ * --------|1 / |
+ * int-clk |_ / |
+ * | _
+ * | | \
+ * |_______|1 \ ETH_SEL_TX_RETIME_CLK
+ * | |___________________________
+ * | | (tx-retime-clk)
+ * _______|0 /
+ * | |_ /
+ * _ |
+ * | \ |
+ * --------|0 \ |
+ * clk_125 | |__|
+ * | | ETH_SEL_TXCLK_NOT_CLK125
+ * --------|1 /
+ * txclk |_ /
+ *
+ *
+ * ETH_SEL_INTERNAL_NOTEXT_PHYCLK is valid only for RMII where PHY can
+ * generate 50MHz clock or MAC can generate it.
+ * This bit is configured by "st,ext-phyclk" property.
+ *
+ * ETH_SEL_TXCLK_NOT_CLK125 is only valid for gigabit modes, where the 125Mhz
+ * clock either comes from clk-125 pin or txclk pin. This configuration is
+ * totally driven by the board wiring. This bit is configured by
+ * "st,tx-retime-src" property.
+ *
+ * TXCLK configuration is different for different phy interface modes
+ * and changes according to link speed in modes like RGMII.
+ *
+ * Below table summarizes the clock requirement and clock sources for
+ * supported phy interface modes with link speeds.
+ * ________________________________________________
+ *| PHY_MODE | 1000 Mbit Link | 100 Mbit Link |
+ * ------------------------------------------------
+ *| MII | n/a | 25Mhz |
+ *| | | txclk |
+ * ------------------------------------------------
+ *| GMII | 125Mhz | 25Mhz |
+ *| | clk-125/txclk | txclk |
+ * ------------------------------------------------
+ *| RGMII | 125Mhz | 25Mhz |
+ *| | clk-125/txclk | clkgen |
+ * ------------------------------------------------
+ *| RMII | n/a | 25Mhz |
+ *| | |clkgen/phyclk-in |
+ * ------------------------------------------------
+ *
+ * TX lines are always retimed with a clk, which can vary depending
+ * on the board configuration. Below is the table of these bits
+ * in eth configuration register depending on source of retime clk.
+ *
+ *---------------------------------------------------------------
+ * src | tx_rt_clk | int_not_ext_phyclk | txclk_n_clk125|
+ *---------------------------------------------------------------
+ * txclk | 0 | n/a | 1 |
+ *---------------------------------------------------------------
+ * ck_125| 0 | n/a | 0 |
+ *---------------------------------------------------------------
+ * phyclk| 1 | 0 | n/a |
+ *---------------------------------------------------------------
+ * clkgen| 1 | 1 | n/a |
+ *---------------------------------------------------------------
+ */
+
+ /* Register definition */
+
+ /* 3 bits [8:6]
+ * [6:6] ETH_SEL_TXCLK_NOT_CLK125
+ * [7:7] ETH_SEL_INTERNAL_NOTEXT_PHYCLK
+ * [8:8] ETH_SEL_TX_RETIME_CLK
+ *
+ */
+
+#define TX_RETIME_SRC_MASK GENMASK(8, 6)
+#define ETH_SEL_TX_RETIME_CLK BIT(8)
+#define ETH_SEL_INTERNAL_NOTEXT_PHYCLK BIT(7)
+#define ETH_SEL_TXCLK_NOT_CLK125 BIT(6)
+
+#define ENMII_MASK GENMASK(5, 5)
+#define ENMII BIT(5)
+
+/**
+ * 3 bits [4:2]
+ * 000-GMII/MII
+ * 001-RGMII
+ * 010-SGMII
+ * 100-RMII
+*/
+#define MII_PHY_SEL_MASK GENMASK(4, 2)
+#define ETH_PHY_SEL_RMII BIT(4)
+#define ETH_PHY_SEL_SGMII BIT(3)
+#define ETH_PHY_SEL_RGMII BIT(2)
+#define ETH_PHY_SEL_GMII 0x0
+#define ETH_PHY_SEL_MII 0x0
+
+#define IS_PHY_IF_MODE_RGMII(iface) (iface == PHY_INTERFACE_MODE_RGMII || \
+ iface == PHY_INTERFACE_MODE_RGMII_ID || \
+ iface == PHY_INTERFACE_MODE_RGMII_RXID || \
+ iface == PHY_INTERFACE_MODE_RGMII_TXID)
+
+#define IS_PHY_IF_MODE_GBIT(iface) (IS_PHY_IF_MODE_RGMII(iface) || \
+ iface == PHY_INTERFACE_MODE_GMII)
+
+struct sti_dwmac {
+ int interface;
+ bool ext_phyclk;
+ bool is_tx_retime_src_clk_125;
+ struct clk *clk;
+ int reg;
+ struct device *dev;
+ struct regmap *regmap;
+};
+
+static u32 phy_intf_sels[] = {
+ [PHY_INTERFACE_MODE_MII] = ETH_PHY_SEL_MII,
+ [PHY_INTERFACE_MODE_GMII] = ETH_PHY_SEL_GMII,
+ [PHY_INTERFACE_MODE_RGMII] = ETH_PHY_SEL_RGMII,
+ [PHY_INTERFACE_MODE_RGMII_ID] = ETH_PHY_SEL_RGMII,
+ [PHY_INTERFACE_MODE_SGMII] = ETH_PHY_SEL_SGMII,
+ [PHY_INTERFACE_MODE_RMII] = ETH_PHY_SEL_RMII,
+};
+
+enum {
+ TX_RETIME_SRC_NA = 0,
+ TX_RETIME_SRC_TXCLK = 1,
+ TX_RETIME_SRC_CLK_125,
+ TX_RETIME_SRC_PHYCLK,
+ TX_RETIME_SRC_CLKGEN,
+};
+
+static const char *const tx_retime_srcs[] = {
+ [TX_RETIME_SRC_NA] = "",
+ [TX_RETIME_SRC_TXCLK] = "txclk",
+ [TX_RETIME_SRC_CLK_125] = "clk_125",
+ [TX_RETIME_SRC_PHYCLK] = "phyclk",
+ [TX_RETIME_SRC_CLKGEN] = "clkgen",
+};
+
+static u32 tx_retime_val[] = {
+ [TX_RETIME_SRC_TXCLK] = ETH_SEL_TXCLK_NOT_CLK125,
+ [TX_RETIME_SRC_CLK_125] = 0x0,
+ [TX_RETIME_SRC_PHYCLK] = ETH_SEL_TX_RETIME_CLK,
+ [TX_RETIME_SRC_CLKGEN] = ETH_SEL_TX_RETIME_CLK |
+ ETH_SEL_INTERNAL_NOTEXT_PHYCLK,
+};
+
+static void setup_retime_src(struct sti_dwmac *dwmac, u32 spd)
+{
+ u32 src = 0, freq = 0;
+
+ if (spd == SPEED_100) {
+ if (dwmac->interface == PHY_INTERFACE_MODE_MII ||
+ dwmac->interface == PHY_INTERFACE_MODE_GMII) {
+ src = TX_RETIME_SRC_TXCLK;
+ } else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) {
+ if (dwmac->ext_phyclk) {
+ src = TX_RETIME_SRC_PHYCLK;
+ } else {
+ src = TX_RETIME_SRC_CLKGEN;
+ freq = 50000000;
+ }
+
+ } else if (IS_PHY_IF_MODE_RGMII(dwmac->interface)) {
+ src = TX_RETIME_SRC_CLKGEN;
+ freq = 25000000;
+ }
+
+ if (src == TX_RETIME_SRC_CLKGEN && dwmac->clk)
+ clk_set_rate(dwmac->clk, freq);
+
+ } else if (spd == SPEED_1000) {
+ if (dwmac->is_tx_retime_src_clk_125)
+ src = TX_RETIME_SRC_CLK_125;
+ else
+ src = TX_RETIME_SRC_TXCLK;
+ }
+
+ regmap_update_bits(dwmac->regmap, dwmac->reg,
+ TX_RETIME_SRC_MASK, tx_retime_val[src]);
+}
+
+static void sti_dwmac_exit(struct platform_device *pdev, void *priv)
+{
+ struct sti_dwmac *dwmac = priv;
+
+ if (dwmac->clk)
+ clk_disable_unprepare(dwmac->clk);
+}
+
+static void sti_fix_mac_speed(void *priv, unsigned int spd)
+{
+ struct sti_dwmac *dwmac = priv;
+
+ setup_retime_src(dwmac, spd);
+
+ return;
+}
+
+static int sti_dwmac_parse_data(struct sti_dwmac *dwmac,
+ struct platform_device *pdev)
+{
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct regmap *regmap;
+ int err;
+
+ if (!np)
+ return -EINVAL;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-ethconf");
+ if (!res)
+ return -ENODATA;
+
+ regmap = syscon_regmap_lookup_by_phandle(np, "st,syscon");
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ dwmac->dev = dev;
+ dwmac->interface = of_get_phy_mode(np);
+ dwmac->regmap = regmap;
+ dwmac->reg = res->start;
+ dwmac->ext_phyclk = of_property_read_bool(np, "st,ext-phyclk");
+ dwmac->is_tx_retime_src_clk_125 = false;
+
+ if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) {
+ const char *rs;
+
+ err = of_property_read_string(np, "st,tx-retime-src", &rs);
+ if (err < 0) {
+ dev_err(dev, "st,tx-retime-src not specified\n");
+ return err;
+ }
+
+ if (!strcasecmp(rs, "clk_125"))
+ dwmac->is_tx_retime_src_clk_125 = true;
+ }
+
+ dwmac->clk = devm_clk_get(dev, "sti-ethclk");
+
+ if (IS_ERR(dwmac->clk))
+ dwmac->clk = NULL;
+
+ return 0;
+}
+
+static int sti_dwmac_init(struct platform_device *pdev, void *priv)
+{
+ struct sti_dwmac *dwmac = priv;
+ struct regmap *regmap = dwmac->regmap;
+ int iface = dwmac->interface;
+ u32 reg = dwmac->reg;
+ u32 val, spd;
+
+ if (dwmac->clk)
+ clk_prepare_enable(dwmac->clk);
+
+ regmap_update_bits(regmap, reg, MII_PHY_SEL_MASK, phy_intf_sels[iface]);
+
+ val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII;
+ regmap_update_bits(regmap, reg, ENMII_MASK, val);
+
+ if (IS_PHY_IF_MODE_GBIT(iface))
+ spd = SPEED_1000;
+ else
+ spd = SPEED_100;
+
+ setup_retime_src(dwmac, spd);
+
+ return 0;
+}
+
+static void *sti_dwmac_setup(struct platform_device *pdev)
+{
+ struct sti_dwmac *dwmac;
+ int ret;
+
+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
+ if (!dwmac)
+ return ERR_PTR(-ENOMEM);
+
+ ret = sti_dwmac_parse_data(dwmac, pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to parse OF data\n");
+ return ERR_PTR(ret);
+ }
+
+ return dwmac;
+}
+
+const struct stmmac_of_data sti_gmac_data = {
+ .fix_mac_speed = sti_fix_mac_speed,
+ .setup = sti_dwmac_setup,
+ .init = sti_dwmac_init,
+ .exit = sti_dwmac_exit,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index a96c7c2f5f3f..650a4be6bce5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -100,10 +100,9 @@ static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
{
struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
- if (unlikely(priv->plat->has_gmac))
- /* Fill DES3 in case of RING mode */
- if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
- p->des3 = p->des2 + BUF_SIZE_8KiB;
+ /* Fill DES3 in case of RING mode */
+ if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
+ p->des3 = p->des2 + BUF_SIZE_8KiB;
}
/* In ring mode we need to fill the desc3 because it is used as buffer */
@@ -126,7 +125,7 @@ static int stmmac_set_16kib_bfsize(int mtu)
return ret;
}
-const struct stmmac_ring_mode_ops ring_mode_ops = {
+const struct stmmac_mode_ops ring_mode_ops = {
.is_jumbo_frm = stmmac_is_jumbo_frm,
.jumbo_frm = stmmac_jumbo_frm,
.refill_desc3 = stmmac_refill_desc3,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index d9af26ed58ee..f9e60d7918c4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -133,6 +133,9 @@ bool stmmac_eee_init(struct stmmac_priv *priv);
#ifdef CONFIG_DWMAC_SUNXI
extern const struct stmmac_of_data sun7i_gmac_data;
#endif
+#ifdef CONFIG_DWMAC_STI
+extern const struct stmmac_of_data sti_gmac_data;
+#endif
extern struct platform_driver stmmac_pltfr_driver;
static inline int stmmac_register_platform(void)
{
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index a2e7d2c96e36..8543e1cfd55e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -92,8 +92,8 @@ static int tc = TC_DEFAULT;
module_param(tc, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(tc, "DMA threshold control value");
-#define DMA_BUFFER_SIZE BUF_SIZE_4KiB
-static int buf_sz = DMA_BUFFER_SIZE;
+#define DEFAULT_BUFSIZE 1536
+static int buf_sz = DEFAULT_BUFSIZE;
module_param(buf_sz, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(buf_sz, "DMA buffer size");
@@ -136,8 +136,8 @@ static void stmmac_verify_args(void)
dma_rxsize = DMA_RX_SIZE;
if (unlikely(dma_txsize < 0))
dma_txsize = DMA_TX_SIZE;
- if (unlikely((buf_sz < DMA_BUFFER_SIZE) || (buf_sz > BUF_SIZE_16KiB)))
- buf_sz = DMA_BUFFER_SIZE;
+ if (unlikely((buf_sz < DEFAULT_BUFSIZE) || (buf_sz > BUF_SIZE_16KiB)))
+ buf_sz = DEFAULT_BUFSIZE;
if (unlikely(flow_ctrl > 1))
flow_ctrl = FLOW_AUTO;
else if (likely(flow_ctrl < 0))
@@ -286,10 +286,25 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
/* MAC core supports the EEE feature. */
if (priv->dma_cap.eee) {
+ int tx_lpi_timer = priv->tx_lpi_timer;
+
/* Check if the PHY supports EEE */
- if (phy_init_eee(priv->phydev, 1))
+ if (phy_init_eee(priv->phydev, 1)) {
+ /* To manage at run-time if the EEE cannot be supported
+ * anymore (for example because the lp caps have been
+ * changed).
+ * In that case the driver disable own timers.
+ */
+ if (priv->eee_active) {
+ pr_debug("stmmac: disable EEE\n");
+ del_timer_sync(&priv->eee_ctrl_timer);
+ priv->hw->mac->set_eee_timer(priv->ioaddr, 0,
+ tx_lpi_timer);
+ }
+ priv->eee_active = 0;
goto out;
-
+ }
+ /* Activate the EEE and start timers */
if (!priv->eee_active) {
priv->eee_active = 1;
init_timer(&priv->eee_ctrl_timer);
@@ -300,13 +315,13 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
priv->hw->mac->set_eee_timer(priv->ioaddr,
STMMAC_DEFAULT_LIT_LS,
- priv->tx_lpi_timer);
+ tx_lpi_timer);
} else
/* Set HW EEE according to the speed */
priv->hw->mac->set_eee_pls(priv->ioaddr,
priv->phydev->link);
- pr_info("stmmac: Energy-Efficient Ethernet initialized\n");
+ pr_debug("stmmac: Energy-Efficient Ethernet initialized\n");
ret = true;
}
@@ -886,10 +901,10 @@ static int stmmac_set_bfsize(int mtu, int bufsize)
ret = BUF_SIZE_8KiB;
else if (mtu >= BUF_SIZE_2KiB)
ret = BUF_SIZE_4KiB;
- else if (mtu >= DMA_BUFFER_SIZE)
+ else if (mtu > DEFAULT_BUFSIZE)
ret = BUF_SIZE_2KiB;
else
- ret = DMA_BUFFER_SIZE;
+ ret = DEFAULT_BUFSIZE;
return ret;
}
@@ -951,9 +966,9 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
p->des2 = priv->rx_skbuff_dma[i];
- if ((priv->mode == STMMAC_RING_MODE) &&
+ if ((priv->hw->mode->init_desc3) &&
(priv->dma_buf_sz == BUF_SIZE_16KiB))
- priv->hw->ring->init_desc3(p);
+ priv->hw->mode->init_desc3(p);
return 0;
}
@@ -984,11 +999,8 @@ static int init_dma_desc_rings(struct net_device *dev)
unsigned int bfsize = 0;
int ret = -ENOMEM;
- /* Set the max buffer size according to the DESC mode
- * and the MTU. Note that RING mode allows 16KiB bsize.
- */
- if (priv->mode == STMMAC_RING_MODE)
- bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu);
+ if (priv->hw->mode->set_16kib_bfsize)
+ bfsize = priv->hw->mode->set_16kib_bfsize(dev->mtu);
if (bfsize < BUF_SIZE_16KiB)
bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
@@ -1029,15 +1041,15 @@ static int init_dma_desc_rings(struct net_device *dev)
/* Setup the chained descriptor addresses */
if (priv->mode == STMMAC_CHAIN_MODE) {
if (priv->extend_desc) {
- priv->hw->chain->init(priv->dma_erx, priv->dma_rx_phy,
- rxsize, 1);
- priv->hw->chain->init(priv->dma_etx, priv->dma_tx_phy,
- txsize, 1);
+ priv->hw->mode->init(priv->dma_erx, priv->dma_rx_phy,
+ rxsize, 1);
+ priv->hw->mode->init(priv->dma_etx, priv->dma_tx_phy,
+ txsize, 1);
} else {
- priv->hw->chain->init(priv->dma_rx, priv->dma_rx_phy,
- rxsize, 0);
- priv->hw->chain->init(priv->dma_tx, priv->dma_tx_phy,
- txsize, 0);
+ priv->hw->mode->init(priv->dma_rx, priv->dma_rx_phy,
+ rxsize, 0);
+ priv->hw->mode->init(priv->dma_tx, priv->dma_tx_phy,
+ txsize, 0);
}
}
@@ -1288,7 +1300,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
DMA_TO_DEVICE);
priv->tx_skbuff_dma[entry] = 0;
}
- priv->hw->ring->clean_desc3(priv, p);
+ priv->hw->mode->clean_desc3(priv, p);
if (likely(skb != NULL)) {
dev_kfree_skb(skb);
@@ -1705,7 +1717,7 @@ static int stmmac_open(struct net_device *dev)
priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
- alloc_dma_desc_resources(priv);
+ ret = alloc_dma_desc_resources(priv);
if (ret < 0) {
pr_err("%s: DMA descriptors allocation failed\n", __func__);
goto dma_desc_error;
@@ -1844,6 +1856,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
int nfrags = skb_shinfo(skb)->nr_frags;
struct dma_desc *desc, *first;
unsigned int nopaged_len = skb_headlen(skb);
+ unsigned int enh_desc = priv->plat->enh_desc;
if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
if (!netif_queue_stopped(dev)) {
@@ -1871,27 +1884,19 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
first = desc;
/* To program the descriptors according to the size of the frame */
- if (priv->mode == STMMAC_RING_MODE) {
- is_jumbo = priv->hw->ring->is_jumbo_frm(skb->len,
- priv->plat->enh_desc);
- if (unlikely(is_jumbo))
- entry = priv->hw->ring->jumbo_frm(priv, skb,
- csum_insertion);
- } else {
- is_jumbo = priv->hw->chain->is_jumbo_frm(skb->len,
- priv->plat->enh_desc);
- if (unlikely(is_jumbo))
- entry = priv->hw->chain->jumbo_frm(priv, skb,
- csum_insertion);
- }
+ if (enh_desc)
+ is_jumbo = priv->hw->mode->is_jumbo_frm(skb->len, enh_desc);
+
if (likely(!is_jumbo)) {
desc->des2 = dma_map_single(priv->device, skb->data,
nopaged_len, DMA_TO_DEVICE);
priv->tx_skbuff_dma[entry] = desc->des2;
priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
csum_insertion, priv->mode);
- } else
+ } else {
desc = first;
+ entry = priv->hw->mode->jumbo_frm(priv, skb, csum_insertion);
+ }
for (i = 0; i < nfrags; i++) {
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -2029,7 +2034,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
p->des2 = priv->rx_skbuff_dma[entry];
- priv->hw->ring->refill_desc3(priv, p);
+ priv->hw->mode->refill_desc3(priv, p);
if (netif_msg_rx_status(priv))
pr_debug("\trefill entry #%d\n", entry);
@@ -2633,11 +2638,11 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
/* To use the chained or ring mode */
if (chain_mode) {
- priv->hw->chain = &chain_mode_ops;
+ priv->hw->mode = &chain_mode_ops;
pr_info(" Chain mode enabled\n");
priv->mode = STMMAC_CHAIN_MODE;
} else {
- priv->hw->ring = &ring_mode_ops;
+ priv->hw->mode = &ring_mode_ops;
pr_info(" Ring mode enabled\n");
priv->mode = STMMAC_RING_MODE;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 5884a7d2063b..8fb32a80f1c1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -33,6 +33,11 @@ static const struct of_device_id stmmac_dt_ids[] = {
#ifdef CONFIG_DWMAC_SUNXI
{ .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
#endif
+#ifdef CONFIG_DWMAC_STI
+ { .compatible = "st,stih415-dwmac", .data = &sti_gmac_data},
+ { .compatible = "st,stih416-dwmac", .data = &sti_gmac_data},
+ { .compatible = "st,stid127-dwmac", .data = &sti_gmac_data},
+#endif
/* SoC specific glue layers should come before generic bindings */
{ .compatible = "st,spear600-gmac"},
{ .compatible = "snps,dwmac-3.610"},
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 1d860ce914ed..7d6d8ec676c8 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -554,7 +554,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
* common for both the interface as the interface shares
* the same hardware resource.
*/
- for (i = 0; i <= priv->data.slaves; i++)
+ for (i = 0; i < priv->data.slaves; i++)
if (priv->slaves[i].ndev->flags & IFF_PROMISC)
flag = true;
@@ -578,7 +578,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
unsigned long timeout = jiffies + HZ;
/* Disable Learn for all ports */
- for (i = 0; i <= priv->data.slaves; i++) {
+ for (i = 0; i < priv->data.slaves; i++) {
cpsw_ale_control_set(ale, i,
ALE_PORT_NOLEARN, 1);
cpsw_ale_control_set(ale, i,
@@ -606,7 +606,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 0);
/* Enable Learn for all ports */
- for (i = 0; i <= priv->data.slaves; i++) {
+ for (i = 0; i < priv->data.slaves; i++) {
cpsw_ale_control_set(ale, i,
ALE_PORT_NOLEARN, 0);
cpsw_ale_control_set(ale, i,
@@ -1164,11 +1164,17 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
{
+ u32 slave_port;
+
+ slave_port = cpsw_get_slave_port(priv, slave->slave_num);
+
if (!slave->phy)
return;
phy_stop(slave->phy);
phy_disconnect(slave->phy);
slave->phy = NULL;
+ cpsw_ale_control_set(priv->ale, slave_port,
+ ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
}
static int cpsw_ndo_open(struct net_device *ndev)
@@ -1896,6 +1902,11 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
slave_data->phy_if = of_get_phy_mode(slave_node);
+ if (slave_data->phy_if < 0) {
+ pr_err("Missing or malformed slave[%d] phy-mode property\n",
+ i);
+ return slave_data->phy_if;
+ }
if (data->dual_emac) {
if (of_property_read_u32(slave_node, "dual_emac_res_vlan",
@@ -2218,10 +2229,6 @@ static int cpsw_probe(struct platform_device *pdev)
goto clean_ale_ret;
}
- if (cpts_register(&pdev->dev, priv->cpts,
- data->cpts_clock_mult, data->cpts_clock_shift))
- dev_err(priv->dev, "error registering cpts device\n");
-
cpsw_notice(priv, probe, "initialized device (regs %pa, irq %d)\n",
&ss_res->start, ndev->irq);
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index 364d0c7952c0..88ef27067bf2 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -355,7 +355,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
int i;
spin_lock_irqsave(&ctlr->lock, flags);
- if (ctlr->state != CPDMA_STATE_ACTIVE) {
+ if (ctlr->state == CPDMA_STATE_TEARDOWN) {
spin_unlock_irqrestore(&ctlr->lock, flags);
return -EINVAL;
}
@@ -891,7 +891,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan)
unsigned timeout;
spin_lock_irqsave(&chan->lock, flags);
- if (chan->state != CPDMA_STATE_ACTIVE) {
+ if (chan->state == CPDMA_STATE_TEARDOWN) {
spin_unlock_irqrestore(&chan->lock, flags);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index cd9b164a0434..8f0e69ce07ca 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -1532,9 +1532,9 @@ static int emac_dev_open(struct net_device *ndev)
struct device *emac_dev = &ndev->dev;
u32 cnt;
struct resource *res;
- int ret;
+ int q, m, ret;
+ int res_num = 0, irq_num = 0;
int i = 0;
- int k = 0;
struct emac_priv *priv = netdev_priv(ndev);
pm_runtime_get(&priv->pdev->dev);
@@ -1564,15 +1564,24 @@ static int emac_dev_open(struct net_device *ndev)
}
/* Request IRQ */
+ while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ,
+ res_num))) {
+ for (irq_num = res->start; irq_num <= res->end; irq_num++) {
+ dev_err(emac_dev, "Request IRQ %d\n", irq_num);
+ if (request_irq(irq_num, emac_irq, 0, ndev->name,
+ ndev)) {
+ dev_err(emac_dev,
+ "DaVinci EMAC: request_irq() failed\n");
+ ret = -EBUSY;
- while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
- for (i = res->start; i <= res->end; i++) {
- if (devm_request_irq(&priv->pdev->dev, i, emac_irq,
- 0, ndev->name, ndev))
goto rollback;
+ }
}
- k++;
+ res_num++;
}
+ /* prepare counters for rollback in case of an error */
+ res_num--;
+ irq_num--;
/* Start/Enable EMAC hardware */
emac_hw_enable(priv);
@@ -1639,11 +1648,23 @@ static int emac_dev_open(struct net_device *ndev)
return 0;
-rollback:
-
- dev_err(emac_dev, "DaVinci EMAC: devm_request_irq() failed");
- ret = -EBUSY;
err:
+ emac_int_disable(priv);
+ napi_disable(&priv->napi);
+
+rollback:
+ for (q = res_num; q >= 0; q--) {
+ res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, q);
+ /* at the first iteration, irq_num is already set to the
+ * right value
+ */
+ if (q != res_num)
+ irq_num = res->end;
+
+ for (m = irq_num; m >= res->start; m--)
+ free_irq(m, ndev);
+ }
+ cpdma_ctlr_stop(priv->dma);
pm_runtime_put(&priv->pdev->dev);
return ret;
}
@@ -1659,6 +1680,9 @@ err:
*/
static int emac_dev_stop(struct net_device *ndev)
{
+ struct resource *res;
+ int i = 0;
+ int irq_num;
struct emac_priv *priv = netdev_priv(ndev);
struct device *emac_dev = &ndev->dev;
@@ -1674,6 +1698,13 @@ static int emac_dev_stop(struct net_device *ndev)
if (priv->phydev)
phy_disconnect(priv->phydev);
+ /* Free IRQ */
+ while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, i))) {
+ for (irq_num = res->start; irq_num <= res->end; irq_num++)
+ free_irq(irq_num, priv->ndev);
+ i++;
+ }
+
if (netif_msg_drv(priv))
dev_notice(emac_dev, "DaVinci EMAC: %s stopped\n", ndev->name);
diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c
index 023237a65720..17503da9f7a5 100644
--- a/drivers/net/ethernet/tile/tilegx.c
+++ b/drivers/net/ethernet/tile/tilegx.c
@@ -2071,7 +2071,7 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
/* Return subqueue id on this core (one per core). */
static u16 tile_net_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
return smp_processor_id();
}
diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
index ef312bc6b865..6ac20a6738f4 100644
--- a/drivers/net/ethernet/via/via-rhine.c
+++ b/drivers/net/ethernet/via/via-rhine.c
@@ -923,7 +923,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc) {
dev_err(&pdev->dev,
"32-bit PCI DMA addresses not supported by the card!?\n");
- goto err_out;
+ goto err_out_pci_disable;
}
/* sanity check */
@@ -931,7 +931,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
(pci_resource_len(pdev, 1) < io_size)) {
rc = -EIO;
dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n");
- goto err_out;
+ goto err_out_pci_disable;
}
pioaddr = pci_resource_start(pdev, 0);
@@ -942,7 +942,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev = alloc_etherdev(sizeof(struct rhine_private));
if (!dev) {
rc = -ENOMEM;
- goto err_out;
+ goto err_out_pci_disable;
}
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -1084,6 +1084,8 @@ err_out_free_res:
pci_release_regions(pdev);
err_out_free_netdev:
free_netdev(dev);
+err_out_pci_disable:
+ pci_disable_device(pdev);
err_out:
return rc;
}
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 1ec65feebb9e..4bfdf8c7ada0 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -26,6 +26,7 @@
#include <linux/netdevice.h>
#include <linux/of_mdio.h>
#include <linux/of_platform.h>
+#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
@@ -600,7 +601,8 @@ static void axienet_start_xmit_done(struct net_device *ndev)
size += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
packets++;
- lp->tx_bd_ci = ++lp->tx_bd_ci % TX_BD_NUM;
+ ++lp->tx_bd_ci;
+ lp->tx_bd_ci %= TX_BD_NUM;
cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
status = cur_p->status;
}
@@ -686,7 +688,8 @@ static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
skb_headlen(skb), DMA_TO_DEVICE);
for (ii = 0; ii < num_frag; ii++) {
- lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM;
+ ++lp->tx_bd_tail;
+ lp->tx_bd_tail %= TX_BD_NUM;
cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
frag = &skb_shinfo(skb)->frags[ii];
cur_p->phys = dma_map_single(ndev->dev.parent,
@@ -702,7 +705,8 @@ static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
/* Start the transfer */
axienet_dma_out32(lp, XAXIDMA_TX_TDESC_OFFSET, tail_p);
- lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM;
+ ++lp->tx_bd_tail;
+ lp->tx_bd_tail %= TX_BD_NUM;
return NETDEV_TX_OK;
}
@@ -774,7 +778,8 @@ static void axienet_recv(struct net_device *ndev)
cur_p->status = 0;
cur_p->sw_id_offset = (u32) new_skb;
- lp->rx_bd_ci = ++lp->rx_bd_ci % RX_BD_NUM;
+ ++lp->rx_bd_ci;
+ lp->rx_bd_ci %= RX_BD_NUM;
cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
}
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 7756118c2f0a..d6fce9750b95 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -88,8 +88,12 @@ static int netvsc_open(struct net_device *net)
{
struct net_device_context *net_device_ctx = netdev_priv(net);
struct hv_device *device_obj = net_device_ctx->device_ctx;
+ struct netvsc_device *nvdev;
+ struct rndis_device *rdev;
int ret = 0;
+ netif_carrier_off(net);
+
/* Open up the device */
ret = rndis_filter_open(device_obj);
if (ret != 0) {
@@ -99,6 +103,11 @@ static int netvsc_open(struct net_device *net)
netif_start_queue(net);
+ nvdev = hv_get_drvdata(device_obj);
+ rdev = nvdev->extension;
+ if (!rdev->link_state)
+ netif_carrier_on(net);
+
return ret;
}
@@ -229,23 +238,24 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
struct net_device *net;
struct net_device_context *ndev_ctx;
struct netvsc_device *net_device;
+ struct rndis_device *rdev;
net_device = hv_get_drvdata(device_obj);
+ rdev = net_device->extension;
+
+ rdev->link_state = status != 1;
+
net = net_device->ndev;
- if (!net) {
- netdev_err(net, "got link status but net device "
- "not initialized yet\n");
+ if (!net || net->reg_state != NETREG_REGISTERED)
return;
- }
+ ndev_ctx = netdev_priv(net);
if (status == 1) {
- netif_carrier_on(net);
- ndev_ctx = netdev_priv(net);
schedule_delayed_work(&ndev_ctx->dwork, 0);
schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
} else {
- netif_carrier_off(net);
+ schedule_delayed_work(&ndev_ctx->dwork, 0);
}
}
@@ -388,17 +398,35 @@ static const struct net_device_ops device_ops = {
* current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add
* another netif_notify_peers() into a delayed work, otherwise GARP packet
* will not be sent after quick migration, and cause network disconnection.
+ * Also, we update the carrier status here.
*/
-static void netvsc_send_garp(struct work_struct *w)
+static void netvsc_link_change(struct work_struct *w)
{
struct net_device_context *ndev_ctx;
struct net_device *net;
struct netvsc_device *net_device;
+ struct rndis_device *rdev;
+ bool notify;
+
+ rtnl_lock();
ndev_ctx = container_of(w, struct net_device_context, dwork.work);
net_device = hv_get_drvdata(ndev_ctx->device_ctx);
+ rdev = net_device->extension;
net = net_device->ndev;
- netdev_notify_peers(net);
+
+ if (rdev->link_state) {
+ netif_carrier_off(net);
+ notify = false;
+ } else {
+ netif_carrier_on(net);
+ notify = true;
+ }
+
+ rtnl_unlock();
+
+ if (notify)
+ netdev_notify_peers(net);
}
@@ -414,13 +442,12 @@ static int netvsc_probe(struct hv_device *dev,
if (!net)
return -ENOMEM;
- /* Set initial state */
netif_carrier_off(net);
net_device_ctx = netdev_priv(net);
net_device_ctx->device_ctx = dev;
hv_set_drvdata(dev, net);
- INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_send_garp);
+ INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
INIT_WORK(&net_device_ctx->work, do_set_multicast);
net->netdev_ops = &device_ops;
@@ -443,13 +470,13 @@ static int netvsc_probe(struct hv_device *dev,
}
memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
- netif_carrier_on(net);
-
ret = register_netdev(net);
if (ret != 0) {
pr_err("Unable to register netdev.\n");
rndis_filter_device_remove(dev);
free_netdev(net);
+ } else {
+ schedule_delayed_work(&net_device_ctx->dwork, 0);
}
return ret;
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 1084e5de3ceb..b54fd257652b 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -243,6 +243,22 @@ static int rndis_filter_send_request(struct rndis_device *dev,
return ret;
}
+static void rndis_set_link_state(struct rndis_device *rdev,
+ struct rndis_request *request)
+{
+ u32 link_status;
+ struct rndis_query_complete *query_complete;
+
+ query_complete = &request->response_msg.msg.query_complete;
+
+ if (query_complete->status == RNDIS_STATUS_SUCCESS &&
+ query_complete->info_buflen == sizeof(u32)) {
+ memcpy(&link_status, (void *)((unsigned long)query_complete +
+ query_complete->info_buf_offset), sizeof(u32));
+ rdev->link_state = link_status != 0;
+ }
+}
+
static void rndis_filter_receive_response(struct rndis_device *dev,
struct rndis_message *resp)
{
@@ -272,6 +288,10 @@ static void rndis_filter_receive_response(struct rndis_device *dev,
sizeof(struct rndis_message) + RNDIS_EXT_LEN) {
memcpy(&request->response_msg, resp,
resp->msg_len);
+ if (request->request_msg.ndis_msg_type ==
+ RNDIS_MSG_QUERY && request->request_msg.msg.
+ query_req.oid == RNDIS_OID_GEN_MEDIA_CONNECT_STATUS)
+ rndis_set_link_state(dev, request);
} else {
netdev_err(ndev,
"rndis response buffer overflow "
@@ -620,7 +640,6 @@ static int rndis_filter_query_device_link_status(struct rndis_device *dev)
ret = rndis_filter_query_device(dev,
RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
&link_status, &size);
- dev->link_state = (link_status != 0) ? true : false;
return ret;
}
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index ab31544bc254..a30258aad139 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -546,12 +546,12 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
int rc;
unsigned long flags;
- spin_lock(&lp->lock);
+ spin_lock_irqsave(&lp->lock, flags);
if (lp->irq_busy) {
- spin_unlock(&lp->lock);
+ spin_unlock_irqrestore(&lp->lock, flags);
return -EBUSY;
}
- spin_unlock(&lp->lock);
+ spin_unlock_irqrestore(&lp->lock, flags);
might_sleep();
@@ -725,10 +725,11 @@ static void at86rf230_irqwork_level(struct work_struct *work)
static irqreturn_t at86rf230_isr(int irq, void *data)
{
struct at86rf230_local *lp = data;
+ unsigned long flags;
- spin_lock(&lp->lock);
+ spin_lock_irqsave(&lp->lock, flags);
lp->irq_busy = 1;
- spin_unlock(&lp->lock);
+ spin_unlock_irqrestore(&lp->lock, flags);
schedule_work(&lp->irqwork);
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index c14d39bf32d0..d7b2e947184b 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -180,7 +180,8 @@ static void ifb_setup(struct net_device *dev)
dev->tx_queue_len = TX_Q_LIMIT;
dev->features |= IFB_FEATURES;
- dev->vlan_features |= IFB_FEATURES;
+ dev->vlan_features |= IFB_FEATURES & ~(NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_STAG_TX);
dev->flags |= IFF_NOARP;
dev->flags &= ~IFF_MULTICAST;
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 177441afeb96..24b6dddd7f2f 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -522,7 +522,6 @@ static void irtty_close(struct tty_struct *tty)
sirdev_put_instance(priv->dev);
/* Stop tty */
- irtty_stop_receiver(tty, TRUE);
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
if (tty->ops->stop)
tty->ops->stop(tty);
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 8433de4509c7..1831fb7cd017 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -506,6 +506,9 @@ static int macvlan_change_mtu(struct net_device *dev, int new_mtu)
static struct lock_class_key macvlan_netdev_xmit_lock_key;
static struct lock_class_key macvlan_netdev_addr_lock_key;
+#define ALWAYS_ON_FEATURES \
+ (NETIF_F_SG | NETIF_F_GEN_CSUM | NETIF_F_GSO_SOFTWARE | NETIF_F_LLTX)
+
#define MACVLAN_FEATURES \
(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
@@ -539,7 +542,7 @@ static int macvlan_init(struct net_device *dev)
dev->state = (dev->state & ~MACVLAN_STATE_MASK) |
(lowerdev->state & MACVLAN_STATE_MASK);
dev->features = lowerdev->features & MACVLAN_FEATURES;
- dev->features |= NETIF_F_LLTX;
+ dev->features |= ALWAYS_ON_FEATURES;
dev->gso_max_size = lowerdev->gso_max_size;
dev->iflink = lowerdev->ifindex;
dev->hard_header_len = lowerdev->hard_header_len;
@@ -699,7 +702,7 @@ static netdev_features_t macvlan_fix_features(struct net_device *dev,
features = netdev_increment_features(vlan->lowerdev->features,
features,
mask);
- features |= NETIF_F_LLTX;
+ features |= ALWAYS_ON_FEATURES;
return features;
}
@@ -879,14 +882,15 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
dev->priv_flags |= IFF_MACVLAN;
err = netdev_upper_dev_link(lowerdev, dev);
if (err)
- goto destroy_port;
-
+ goto unregister_netdev;
list_add_tail_rcu(&vlan->list, &port->vlans);
netif_stacked_transfer_operstate(lowerdev, dev);
return 0;
+unregister_netdev:
+ unregister_netdevice(dev);
destroy_port:
port->count -= 1;
if (!port->count)
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index 9414fa272160..98e7cbf720a5 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -1006,11 +1006,6 @@ static int dp83640_probe(struct phy_device *phydev)
} else
list_add_tail(&dp83640->list, &clock->phylist);
- if (clock->chosen && !list_empty(&clock->phylist))
- recalibrate(clock);
- else
- enable_broadcast(dp83640->phydev, clock->page, 1);
-
dp83640_clock_put(clock);
return 0;
@@ -1063,6 +1058,14 @@ static void dp83640_remove(struct phy_device *phydev)
static int dp83640_config_init(struct phy_device *phydev)
{
+ struct dp83640_private *dp83640 = phydev->priv;
+ struct dp83640_clock *clock = dp83640->clock;
+
+ if (clock->chosen && !list_empty(&clock->phylist))
+ recalibrate(clock);
+ else
+ enable_broadcast(phydev, clock->page, 1);
+
enable_status_frames(phydev, true);
ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE);
return 0;
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 19c9eca0ef26..76d96b9ebcdb 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -164,9 +164,9 @@ static const struct phy_setting settings[] = {
* of that setting. Returns the index of the last setting if
* none of the others match.
*/
-static inline int phy_find_setting(int speed, int duplex)
+static inline unsigned int phy_find_setting(int speed, int duplex)
{
- int idx = 0;
+ unsigned int idx = 0;
while (idx < ARRAY_SIZE(settings) &&
(settings[idx].speed != speed || settings[idx].duplex != duplex))
@@ -185,7 +185,7 @@ static inline int phy_find_setting(int speed, int duplex)
* the mask in features. Returns the index of the last setting
* if nothing else matches.
*/
-static inline int phy_find_valid(int idx, u32 features)
+static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
{
while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features))
idx++;
@@ -204,7 +204,7 @@ static inline int phy_find_valid(int idx, u32 features)
static void phy_sanitize_settings(struct phy_device *phydev)
{
u32 features = phydev->supported;
- int idx;
+ unsigned int idx;
/* Sanitize settings based on PHY capabilities */
if ((features & SUPPORTED_Autoneg) == 0)
@@ -954,7 +954,8 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
(phydev->interface == PHY_INTERFACE_MODE_RGMII))) {
int eee_lp, eee_cap, eee_adv;
u32 lp, cap, adv;
- int idx, status;
+ int status;
+ unsigned int idx;
/* Read phy status to properly get the right settings */
status = phy_read_status(phydev);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 82514e72b3d8..2f6989b1e0dc 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -683,10 +683,9 @@ EXPORT_SYMBOL(phy_detach);
int phy_suspend(struct phy_device *phydev)
{
struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
- struct ethtool_wolinfo wol;
+ struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
/* If the device has WOL enabled, we cannot suspend the PHY */
- wol.cmd = ETHTOOL_GWOL;
phy_ethtool_get_wol(phydev, &wol);
if (wol.wolopts)
return -EBUSY;
@@ -916,6 +915,8 @@ int genphy_read_status(struct phy_device *phydev)
int err;
int lpa;
int lpagb = 0;
+ int common_adv;
+ int common_adv_gb = 0;
/* Update the link, but return if there was an error */
err = genphy_update_link(phydev);
@@ -937,7 +938,7 @@ int genphy_read_status(struct phy_device *phydev)
phydev->lp_advertising =
mii_stat1000_to_ethtool_lpa_t(lpagb);
- lpagb &= adv << 2;
+ common_adv_gb = lpagb & adv << 2;
}
lpa = phy_read(phydev, MII_LPA);
@@ -950,25 +951,25 @@ int genphy_read_status(struct phy_device *phydev)
if (adv < 0)
return adv;
- lpa &= adv;
+ common_adv = lpa & adv;
phydev->speed = SPEED_10;
phydev->duplex = DUPLEX_HALF;
phydev->pause = 0;
phydev->asym_pause = 0;
- if (lpagb & (LPA_1000FULL | LPA_1000HALF)) {
+ if (common_adv_gb & (LPA_1000FULL | LPA_1000HALF)) {
phydev->speed = SPEED_1000;
- if (lpagb & LPA_1000FULL)
+ if (common_adv_gb & LPA_1000FULL)
phydev->duplex = DUPLEX_FULL;
- } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
+ } else if (common_adv & (LPA_100FULL | LPA_100HALF)) {
phydev->speed = SPEED_100;
- if (lpa & LPA_100FULL)
+ if (common_adv & LPA_100FULL)
phydev->duplex = DUPLEX_FULL;
} else
- if (lpa & LPA_10FULL)
+ if (common_adv & LPA_10FULL)
phydev->duplex = DUPLEX_FULL;
if (phydev->duplex == DUPLEX_FULL) {
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 28407426fd6f..c8624a8235ab 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1648,7 +1648,7 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
}
static u16 team_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
/*
* This helper function exists to help dev_pick_tx get the correct
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 44c4db8450f0..26f8635b027d 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -366,7 +366,7 @@ static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash)
* hope the rxq no. may help here.
*/
static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
struct tun_struct *tun = netdev_priv(dev);
struct tun_flow_entry *e;
@@ -1686,7 +1686,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_STAG_TX;
dev->features = dev->hw_features;
- dev->vlan_features = dev->features;
+ dev->vlan_features = dev->features &
+ ~(NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_STAG_TX);
INIT_LIST_HEAD(&tun->disabled);
err = tun_attach(tun, file, false);
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 409499fdb157..7e7269fd3707 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -296,7 +296,6 @@ config USB_NET_SR9800
tristate "CoreChip-sz SR9800 based USB 2.0 10/100 ethernet devices"
depends on USB_USBNET
select CRC32
- default y
---help---
Say Y if you want to use one of the following 100Mbps USB Ethernet
device based on the CoreChip-sz SR9800 chip.
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 433f0a00c683..e2797f1e1b31 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_USB_HSO) += hso.o
obj-$(CONFIG_USB_NET_AX8817X) += asix.o
asix-y := asix_devices.o asix_common.o ax88172a.o
obj-$(CONFIG_USB_NET_AX88179_178A) += ax88179_178a.o
-obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o r815x.o
+obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o
obj-$(CONFIG_USB_NET_DM9601) += dm9601.o
obj-$(CONFIG_USB_NET_SR9700) += sr9700.o
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 9765a7d4766d..5d194093f3e1 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -917,7 +917,8 @@ static const struct driver_info ax88178_info = {
.status = asix_status,
.link_reset = ax88178_link_reset,
.reset = ax88178_reset,
- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
+ FLAG_MULTI_PACKET,
.rx_fixup = asix_rx_fixup_common,
.tx_fixup = asix_tx_fixup,
};
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index d6f64dad05bc..054e59ca6946 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -1029,20 +1029,12 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
dev->mii.phy_id = 0x03;
dev->mii.supports_gmii = 1;
- if (usb_device_no_sg_constraint(dev->udev))
- dev->can_dma_sg = 1;
-
dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_RXCSUM;
dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_RXCSUM;
- if (dev->can_dma_sg) {
- dev->net->features |= NETIF_F_SG | NETIF_F_TSO;
- dev->net->hw_features |= NETIF_F_SG | NETIF_F_TSO;
- }
-
/* Enable checksum offload */
*tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
@@ -1118,6 +1110,10 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
u16 hdr_off;
u32 *pkt_hdr;
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
skb_trim(skb, skb->len - 4);
memcpy(&rx_hdr, skb_tail_pointer(skb), 4);
le32_to_cpus(&rx_hdr);
@@ -1391,6 +1387,19 @@ static const struct driver_info ax88178a_info = {
.tx_fixup = ax88179_tx_fixup,
};
+static const struct driver_info dlink_dub1312_info = {
+ .description = "D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter",
+ .bind = ax88179_bind,
+ .unbind = ax88179_unbind,
+ .status = ax88179_status,
+ .link_reset = ax88179_link_reset,
+ .reset = ax88179_reset,
+ .stop = ax88179_stop,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = ax88179_rx_fixup,
+ .tx_fixup = ax88179_tx_fixup,
+};
+
static const struct driver_info sitecom_info = {
.description = "Sitecom USB 3.0 to Gigabit Adapter",
.bind = ax88179_bind,
@@ -1417,6 +1426,19 @@ static const struct driver_info samsung_info = {
.tx_fixup = ax88179_tx_fixup,
};
+static const struct driver_info lenovo_info = {
+ .description = "Lenovo OneLinkDock Gigabit LAN",
+ .bind = ax88179_bind,
+ .unbind = ax88179_unbind,
+ .status = ax88179_status,
+ .link_reset = ax88179_link_reset,
+ .reset = ax88179_reset,
+ .stop = ax88179_stop,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = ax88179_rx_fixup,
+ .tx_fixup = ax88179_tx_fixup,
+};
+
static const struct usb_device_id products[] = {
{
/* ASIX AX88179 10/100/1000 */
@@ -1427,6 +1449,10 @@ static const struct usb_device_id products[] = {
USB_DEVICE(0x0b95, 0x178a),
.driver_info = (unsigned long)&ax88178a_info,
}, {
+ /* D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter */
+ USB_DEVICE(0x2001, 0x4a00),
+ .driver_info = (unsigned long)&dlink_dub1312_info,
+}, {
/* Sitecom USB 3.0 to Gigabit Adapter */
USB_DEVICE(0x0df6, 0x0072),
.driver_info = (unsigned long)&sitecom_info,
@@ -1434,6 +1460,10 @@ static const struct usb_device_id products[] = {
/* Samsung USB Ethernet Adapter */
USB_DEVICE(0x04e8, 0xa100),
.driver_info = (unsigned long)&samsung_info,
+}, {
+ /* Lenovo OneLinkDock Gigabit LAN */
+ USB_DEVICE(0x17ef, 0x304b),
+ .driver_info = (unsigned long)&lenovo_info,
},
{ },
};
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 42e176912c8e..bd363b27e854 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -652,6 +652,13 @@ static const struct usb_device_id products[] = {
.driver_info = 0,
},
+/* Samsung USB Ethernet Adapters */
+{
+ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, 0xa101, USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+ .driver_info = 0,
+},
+
/* WHITELIST!!!
*
* CDC Ether uses two interfaces, not necessarily consecutive.
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index dbff290ed0e4..d350d2795e10 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -68,7 +68,6 @@ static struct usb_driver cdc_ncm_driver;
static int cdc_ncm_setup(struct usbnet *dev)
{
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
- struct usb_cdc_ncm_ntb_parameters ncm_parm;
u32 val;
u8 flags;
u8 iface_no;
@@ -82,22 +81,22 @@ static int cdc_ncm_setup(struct usbnet *dev)
err = usbnet_read_cmd(dev, USB_CDC_GET_NTB_PARAMETERS,
USB_TYPE_CLASS | USB_DIR_IN
|USB_RECIP_INTERFACE,
- 0, iface_no, &ncm_parm,
- sizeof(ncm_parm));
+ 0, iface_no, &ctx->ncm_parm,
+ sizeof(ctx->ncm_parm));
if (err < 0) {
dev_err(&dev->intf->dev, "failed GET_NTB_PARAMETERS\n");
return err; /* GET_NTB_PARAMETERS is required */
}
/* read correct set of parameters according to device mode */
- ctx->rx_max = le32_to_cpu(ncm_parm.dwNtbInMaxSize);
- ctx->tx_max = le32_to_cpu(ncm_parm.dwNtbOutMaxSize);
- ctx->tx_remainder = le16_to_cpu(ncm_parm.wNdpOutPayloadRemainder);
- ctx->tx_modulus = le16_to_cpu(ncm_parm.wNdpOutDivisor);
- ctx->tx_ndp_modulus = le16_to_cpu(ncm_parm.wNdpOutAlignment);
+ ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize);
+ ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize);
+ ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
+ ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor);
+ ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
/* devices prior to NCM Errata shall set this field to zero */
- ctx->tx_max_datagrams = le16_to_cpu(ncm_parm.wNtbOutMaxDatagrams);
- ntb_fmt_supported = le16_to_cpu(ncm_parm.bmNtbFormatsSupported);
+ ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams);
+ ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported);
/* there are some minor differences in NCM and MBIM defaults */
if (cdc_ncm_comm_intf_is_mbim(ctx->control->cur_altsetting)) {
@@ -146,7 +145,7 @@ static int cdc_ncm_setup(struct usbnet *dev)
}
/* inform device about NTB input size changes */
- if (ctx->rx_max != le32_to_cpu(ncm_parm.dwNtbInMaxSize)) {
+ if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
__le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_INPUT_SIZE,
@@ -162,14 +161,6 @@ static int cdc_ncm_setup(struct usbnet *dev)
dev_dbg(&dev->intf->dev, "Using default maximum transmit length=%d\n",
CDC_NCM_NTB_MAX_SIZE_TX);
ctx->tx_max = CDC_NCM_NTB_MAX_SIZE_TX;
-
- /* Adding a pad byte here simplifies the handling in
- * cdc_ncm_fill_tx_frame, by making tx_max always
- * represent the real skb max size.
- */
- if (ctx->tx_max % usb_maxpacket(dev->udev, dev->out, 1) == 0)
- ctx->tx_max++;
-
}
/*
@@ -439,6 +430,10 @@ advance:
goto error2;
}
+ /* initialize data interface */
+ if (cdc_ncm_setup(dev))
+ goto error2;
+
/* configure data interface */
temp = usb_set_interface(dev->udev, iface_no, data_altsetting);
if (temp) {
@@ -453,12 +448,6 @@ advance:
goto error2;
}
- /* initialize data interface */
- if (cdc_ncm_setup(dev)) {
- dev_dbg(&intf->dev, "cdc_ncm_setup() failed\n");
- goto error2;
- }
-
usb_set_intfdata(ctx->data, dev);
usb_set_intfdata(ctx->control, dev);
@@ -475,6 +464,15 @@ advance:
dev->hard_mtu = ctx->tx_max;
dev->rx_urb_size = ctx->rx_max;
+ /* cdc_ncm_setup will override dwNtbOutMaxSize if it is
+ * outside the sane range. Adding a pad byte here if necessary
+ * simplifies the handling in cdc_ncm_fill_tx_frame, making
+ * tx_max always represent the real skb max size.
+ */
+ if (ctx->tx_max != le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) &&
+ ctx->tx_max % usb_maxpacket(dev->udev, dev->out, 1) == 0)
+ ctx->tx_max++;
+
return 0;
error2:
diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c
index e4a8a93fbaf7..1cc24e6f23e2 100644
--- a/drivers/net/usb/gl620a.c
+++ b/drivers/net/usb/gl620a.c
@@ -84,6 +84,10 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
u32 size;
u32 count;
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
header = (struct gl_header *) skb->data;
// get the packet count of the received skb
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index a305a7b2dae6..82d844a8ebd0 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -526,8 +526,9 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
u8 status;
- if (skb->len == 0) {
- dev_err(&dev->udev->dev, "unexpected empty rx frame\n");
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len) {
+ dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
return 0;
}
diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c
index 0a85d9227775..4cbdb1307f3e 100644
--- a/drivers/net/usb/net1080.c
+++ b/drivers/net/usb/net1080.c
@@ -364,6 +364,10 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
struct nc_trailer *trailer;
u16 hdr_len, packet_len;
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
if (!(skb->len & 0x01)) {
netdev_dbg(dev->net, "rx framesize %d range %d..%d mtu %d\n",
skb->len, dev->net->hard_header_len, dev->hard_mtu,
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index ff5c87128ffe..313cb6cd4848 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -80,10 +80,10 @@ static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
__be16 proto;
- /* usbnet rx_complete guarantees that skb->len is at least
- * hard_header_len, so we can inspect the dest address without
- * checking skb->len
- */
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
switch (skb->data[0] & 0xf0) {
case 0x40:
proto = htons(ETH_P_IP);
@@ -732,6 +732,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x1bc7, 0x1201, 2)}, /* Telit LE920 */
{QMI_FIXED_INTF(0x0b3c, 0xc005, 6)}, /* Olivetti Olicard 200 */
{QMI_FIXED_INTF(0x1e2d, 0x0060, 4)}, /* Cinterion PLxx */
+ {QMI_FIXED_INTF(0x1e2d, 0x0053, 4)}, /* Cinterion PHxx,PXxx */
/* 4. Gobi 1000 devices */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index d89dbe395ad2..adb12f349a61 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -449,9 +449,6 @@ enum rtl8152_flags {
#define MCU_TYPE_PLA 0x0100
#define MCU_TYPE_USB 0x0000
-#define REALTEK_USB_DEVICE(vend, prod) \
- USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC)
-
struct rx_desc {
__le32 opts1;
#define RX_LEN_MASK 0x7fff
@@ -2739,6 +2736,12 @@ static int rtl8152_probe(struct usb_interface *intf,
struct net_device *netdev;
int ret;
+ if (udev->actconfig->desc.bConfigurationValue != 1) {
+ usb_driver_set_configuration(udev, 1);
+ return -ENODEV;
+ }
+
+ usb_reset_device(udev);
netdev = alloc_etherdev(sizeof(struct r8152));
if (!netdev) {
dev_err(&intf->dev, "Out of memory\n");
@@ -2819,9 +2822,9 @@ static void rtl8152_disconnect(struct usb_interface *intf)
/* table of devices that work with this driver */
static struct usb_device_id rtl8152_table[] = {
- {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
- {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
- {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
+ {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
+ {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
+ {USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
{}
};
diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c
deleted file mode 100644
index f0a8791b7636..000000000000
--- a/drivers/net/usb/r815x.c
+++ /dev/null
@@ -1,248 +0,0 @@
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/mii.h>
-#include <linux/usb.h>
-#include <linux/usb/cdc.h>
-#include <linux/usb/usbnet.h>
-
-#define RTL815x_REQT_READ 0xc0
-#define RTL815x_REQT_WRITE 0x40
-#define RTL815x_REQ_GET_REGS 0x05
-#define RTL815x_REQ_SET_REGS 0x05
-
-#define MCU_TYPE_PLA 0x0100
-#define OCP_BASE 0xe86c
-#define BASE_MII 0xa400
-
-#define BYTE_EN_DWORD 0xff
-#define BYTE_EN_WORD 0x33
-#define BYTE_EN_BYTE 0x11
-
-#define R815x_PHY_ID 32
-#define REALTEK_VENDOR_ID 0x0bda
-
-
-static int pla_read_word(struct usb_device *udev, u16 index)
-{
- int ret;
- u8 shift = index & 2;
- __le32 *tmp;
-
- tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- index &= ~3;
-
- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
- index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
- if (ret < 0)
- goto out2;
-
- ret = __le32_to_cpu(*tmp);
- ret >>= (shift * 8);
- ret &= 0xffff;
-
-out2:
- kfree(tmp);
- return ret;
-}
-
-static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
-{
- __le32 *tmp;
- u32 mask = 0xffff;
- u16 byen = BYTE_EN_WORD;
- u8 shift = index & 2;
- int ret;
-
- tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- data &= mask;
-
- if (shift) {
- byen <<= shift;
- mask <<= (shift * 8);
- data <<= (shift * 8);
- index &= ~3;
- }
-
- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
- index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
- if (ret < 0)
- goto out3;
-
- data |= __le32_to_cpu(*tmp) & ~mask;
- *tmp = __cpu_to_le32(data);
-
- ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE,
- index, MCU_TYPE_PLA | byen, tmp, sizeof(*tmp),
- 500);
-
-out3:
- kfree(tmp);
- return ret;
-}
-
-static int ocp_reg_read(struct usbnet *dev, u16 addr)
-{
- u16 ocp_base, ocp_index;
- int ret;
-
- ocp_base = addr & 0xf000;
- ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
- if (ret < 0)
- goto out;
-
- ocp_index = (addr & 0x0fff) | 0xb000;
- ret = pla_read_word(dev->udev, ocp_index);
-
-out:
- return ret;
-}
-
-static int ocp_reg_write(struct usbnet *dev, u16 addr, u16 data)
-{
- u16 ocp_base, ocp_index;
- int ret;
-
- ocp_base = addr & 0xf000;
- ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
- if (ret < 0)
- goto out1;
-
- ocp_index = (addr & 0x0fff) | 0xb000;
- ret = pla_write_word(dev->udev, ocp_index, data);
-
-out1:
- return ret;
-}
-
-static int r815x_mdio_read(struct net_device *netdev, int phy_id, int reg)
-{
- struct usbnet *dev = netdev_priv(netdev);
- int ret;
-
- if (phy_id != R815x_PHY_ID)
- return -EINVAL;
-
- if (usb_autopm_get_interface(dev->intf) < 0)
- return -ENODEV;
-
- ret = ocp_reg_read(dev, BASE_MII + reg * 2);
-
- usb_autopm_put_interface(dev->intf);
- return ret;
-}
-
-static
-void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
-{
- struct usbnet *dev = netdev_priv(netdev);
-
- if (phy_id != R815x_PHY_ID)
- return;
-
- if (usb_autopm_get_interface(dev->intf) < 0)
- return;
-
- ocp_reg_write(dev, BASE_MII + reg * 2, val);
-
- usb_autopm_put_interface(dev->intf);
-}
-
-static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
-{
- int status;
-
- status = usbnet_cdc_bind(dev, intf);
- if (status < 0)
- return status;
-
- dev->mii.dev = dev->net;
- dev->mii.mdio_read = r815x_mdio_read;
- dev->mii.mdio_write = r815x_mdio_write;
- dev->mii.phy_id_mask = 0x3f;
- dev->mii.reg_num_mask = 0x1f;
- dev->mii.phy_id = R815x_PHY_ID;
- dev->mii.supports_gmii = 1;
-
- return status;
-}
-
-static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
-{
- int status;
-
- status = usbnet_cdc_bind(dev, intf);
- if (status < 0)
- return status;
-
- dev->mii.dev = dev->net;
- dev->mii.mdio_read = r815x_mdio_read;
- dev->mii.mdio_write = r815x_mdio_write;
- dev->mii.phy_id_mask = 0x3f;
- dev->mii.reg_num_mask = 0x1f;
- dev->mii.phy_id = R815x_PHY_ID;
- dev->mii.supports_gmii = 0;
-
- return status;
-}
-
-static const struct driver_info r8152_info = {
- .description = "RTL8152 ECM Device",
- .flags = FLAG_ETHER | FLAG_POINTTOPOINT,
- .bind = r8152_bind,
- .unbind = usbnet_cdc_unbind,
- .status = usbnet_cdc_status,
- .manage_power = usbnet_manage_power,
-};
-
-static const struct driver_info r8153_info = {
- .description = "RTL8153 ECM Device",
- .flags = FLAG_ETHER | FLAG_POINTTOPOINT,
- .bind = r8153_bind,
- .unbind = usbnet_cdc_unbind,
- .status = usbnet_cdc_status,
- .manage_power = usbnet_manage_power,
-};
-
-static const struct usb_device_id products[] = {
-{
- USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8152, USB_CLASS_COMM,
- USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
- .driver_info = (unsigned long) &r8152_info,
-},
-
-{
- USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8153, USB_CLASS_COMM,
- USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
- .driver_info = (unsigned long) &r8153_info,
-},
-
- { }, /* END */
-};
-MODULE_DEVICE_TABLE(usb, products);
-
-static struct usb_driver r815x_driver = {
- .name = "r815x",
- .id_table = products,
- .probe = usbnet_probe,
- .disconnect = usbnet_disconnect,
- .suspend = usbnet_suspend,
- .resume = usbnet_resume,
- .reset_resume = usbnet_resume,
- .supports_autosuspend = 1,
- .disable_hub_initiated_lpm = 1,
-};
-
-module_usb_driver(r815x_driver);
-
-MODULE_AUTHOR("Hayes Wang");
-MODULE_DESCRIPTION("Realtek USB ECM device");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index a48bc0f20c1a..524a47a28120 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -492,6 +492,10 @@ EXPORT_SYMBOL_GPL(rndis_unbind);
*/
int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
/* peripheral may have batched packets to us... */
while (likely(skb->len)) {
struct rndis_data_hdr *hdr = (void *)skb->data;
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index f17b9e02dd34..d9e7892262fa 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -2106,6 +2106,10 @@ static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb,
static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
while (skb->len > 0) {
u32 rx_cmd_a, rx_cmd_b, align_count, size;
struct sk_buff *ax_skb;
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 8dd54a0f7b29..424db65e4396 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1723,6 +1723,10 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb)
static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
while (skb->len > 0) {
u32 header, align_count;
struct sk_buff *ax_skb;
diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c
index 4175eb9fdeca..b94a0fbb8b3b 100644
--- a/drivers/net/usb/sr9800.c
+++ b/drivers/net/usb/sr9800.c
@@ -63,6 +63,10 @@ static int sr_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
int offset = 0;
+ /* This check is no longer done by usbnet */
+ if (skb->len < dev->net->hard_header_len)
+ return 0;
+
while (offset + sizeof(u32) < skb->len) {
struct sk_buff *sr_skb;
u16 size;
@@ -823,7 +827,7 @@ static int sr9800_bind(struct usbnet *dev, struct usb_interface *intf)
dev->rx_urb_size =
SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].size;
}
- netdev_dbg(dev->net, "%s : setting rx_urb_size with : %ld\n", __func__,
+ netdev_dbg(dev->net, "%s : setting rx_urb_size with : %zu\n", __func__,
dev->rx_urb_size);
return 0;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 4671da755e7b..f9e96c427558 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -542,17 +542,19 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
}
// else network stack removes extra byte if we forced a short packet
- if (skb->len) {
- /* all data was already cloned from skb inside the driver */
- if (dev->driver_info->flags & FLAG_MULTI_PACKET)
- dev_kfree_skb_any(skb);
- else
- usbnet_skb_return(dev, skb);
+ /* all data was already cloned from skb inside the driver */
+ if (dev->driver_info->flags & FLAG_MULTI_PACKET)
+ goto done;
+
+ if (skb->len < ETH_HLEN) {
+ dev->net->stats.rx_errors++;
+ dev->net->stats.rx_length_errors++;
+ netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len);
+ } else {
+ usbnet_skb_return(dev, skb);
return;
}
- netif_dbg(dev, rx_err, dev->net, "drop\n");
- dev->net->stats.rx_errors++;
done:
skb_queue_tail(&dev->done, skb);
}
@@ -574,13 +576,6 @@ static void rx_complete (struct urb *urb)
switch (urb_status) {
/* success */
case 0:
- if (skb->len < dev->net->hard_header_len) {
- state = rx_cleanup;
- dev->net->stats.rx_errors++;
- dev->net->stats.rx_length_errors++;
- netif_dbg(dev, rx_err, dev->net,
- "rx length %d\n", skb->len);
- }
break;
/* stalls need manual reset. this is rare ... except that
@@ -757,14 +752,12 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
// precondition: never called in_interrupt
static void usbnet_terminate_urbs(struct usbnet *dev)
{
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup);
DECLARE_WAITQUEUE(wait, current);
int temp;
/* ensure there are no more active urbs */
- add_wait_queue(&unlink_wakeup, &wait);
+ add_wait_queue(&dev->wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
- dev->wait = &unlink_wakeup;
temp = unlink_urbs(dev, &dev->txq) +
unlink_urbs(dev, &dev->rxq);
@@ -778,15 +771,14 @@ static void usbnet_terminate_urbs(struct usbnet *dev)
"waited for %d urb completions\n", temp);
}
set_current_state(TASK_RUNNING);
- dev->wait = NULL;
- remove_wait_queue(&unlink_wakeup, &wait);
+ remove_wait_queue(&dev->wait, &wait);
}
int usbnet_stop (struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
struct driver_info *info = dev->driver_info;
- int retval;
+ int retval, pm;
clear_bit(EVENT_DEV_OPEN, &dev->flags);
netif_stop_queue (net);
@@ -796,6 +788,8 @@ int usbnet_stop (struct net_device *net)
net->stats.rx_packets, net->stats.tx_packets,
net->stats.rx_errors, net->stats.tx_errors);
+ /* to not race resume */
+ pm = usb_autopm_get_interface(dev->intf);
/* allow minidriver to stop correctly (wireless devices to turn off
* radio etc) */
if (info->stop) {
@@ -822,6 +816,9 @@ int usbnet_stop (struct net_device *net)
dev->flags = 0;
del_timer_sync (&dev->delay);
tasklet_kill (&dev->bh);
+ if (!pm)
+ usb_autopm_put_interface(dev->intf);
+
if (info->manage_power &&
!test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags))
info->manage_power(dev, 0);
@@ -1442,11 +1439,12 @@ static void usbnet_bh (unsigned long param)
/* restart RX again after disabling due to high error rate */
clear_bit(EVENT_RX_KILL, &dev->flags);
- // waiting for all pending urbs to complete?
- if (dev->wait) {
- if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
- wake_up (dev->wait);
- }
+ /* waiting for all pending urbs to complete?
+ * only then can we forgo submitting anew
+ */
+ if (waitqueue_active(&dev->wait)) {
+ if (dev->txq.qlen + dev->rxq.qlen + dev->done.qlen == 0)
+ wake_up_all(&dev->wait);
// or are we maybe short a few urbs?
} else if (netif_running (dev->net) &&
@@ -1585,6 +1583,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev->driver_name = name;
dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
| NETIF_MSG_PROBE | NETIF_MSG_LINK);
+ init_waitqueue_head(&dev->wait);
skb_queue_head_init (&dev->rxq);
skb_queue_head_init (&dev->txq);
skb_queue_head_init (&dev->done);
@@ -1796,9 +1795,10 @@ int usbnet_resume (struct usb_interface *intf)
spin_unlock_irq(&dev->txq.lock);
if (test_bit(EVENT_DEV_OPEN, &dev->flags)) {
- /* handle remote wakeup ASAP */
- if (!dev->wait &&
- netif_device_present(dev->net) &&
+ /* handle remote wakeup ASAP
+ * we cannot race against stop
+ */
+ if (netif_device_present(dev->net) &&
!timer_pending(&dev->delay) &&
!test_bit(EVENT_RX_HALT, &dev->flags))
rx_alloc_submit(dev, GFP_NOIO);
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 2ec2041b62d4..c0e7c64765ab 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -285,7 +285,11 @@ static void veth_setup(struct net_device *dev)
dev->ethtool_ops = &veth_ethtool_ops;
dev->features |= NETIF_F_LLTX;
dev->features |= VETH_FEATURES;
- dev->vlan_features = dev->features;
+ dev->vlan_features = dev->features &
+ ~(NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_STAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_STAG_RX);
dev->destructor = veth_dev_free;
dev->hw_features = VETH_FEATURES;
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index d75f8edf4fb3..470b01f3e7b4 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -671,8 +671,7 @@ static bool try_fill_recv(struct receive_queue *rq, gfp_t gfp)
if (err)
break;
} while (rq->vq->num_free);
- if (unlikely(!virtqueue_kick(rq->vq)))
- return false;
+ virtqueue_kick(rq->vq);
return !oom;
}
@@ -877,7 +876,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
err = xmit_skb(sq, skb);
/* This should not happen! */
- if (unlikely(err) || unlikely(!virtqueue_kick(sq->vq))) {
+ if (unlikely(err)) {
dev->stats.tx_fifo_errors++;
if (net_ratelimit())
dev_warn(&dev->dev,
@@ -886,6 +885,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
kfree_skb(skb);
return NETDEV_TX_OK;
}
+ virtqueue_kick(sq->vq);
/* Don't wait up for transmitted skbs to be freed. */
skb_orphan(skb);
@@ -938,7 +938,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
sgs[out_num] = &stat;
BUG_ON(out_num + 1 > ARRAY_SIZE(sgs));
- BUG_ON(virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC) < 0);
+ virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC);
if (unlikely(!virtqueue_kick(vi->cvq)))
return status == VIRTIO_NET_OK;
@@ -1711,7 +1711,8 @@ static int virtnet_probe(struct virtio_device *vdev)
/* If we can receive ANY GSO packets, we must allocate large ones. */
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
- virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
+ virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) ||
+ virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO))
vi->big_packets = true;
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 3be786faaaec..0fa3b44f7342 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -1762,11 +1762,20 @@ vmxnet3_netpoll(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
- if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
- vmxnet3_disable_all_intrs(adapter);
-
- vmxnet3_do_poll(adapter, adapter->rx_queue[0].rx_ring[0].size);
- vmxnet3_enable_all_intrs(adapter);
+ switch (adapter->intr.type) {
+#ifdef CONFIG_PCI_MSI
+ case VMXNET3_IT_MSIX: {
+ int i;
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ vmxnet3_msix_rx(0, &adapter->rx_queue[i]);
+ break;
+ }
+#endif
+ case VMXNET3_IT_MSI:
+ default:
+ vmxnet3_intr(0, adapter->netdev);
+ break;
+ }
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index b0f705c2378f..1236812c7be6 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1318,6 +1318,9 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
neigh_release(n);
+ if (reply == NULL)
+ goto out;
+
skb_reset_mac_header(reply);
__skb_pull(reply, skb_network_offset(reply));
reply->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1339,15 +1342,103 @@ out:
}
#if IS_ENABLED(CONFIG_IPV6)
+
+static struct sk_buff *vxlan_na_create(struct sk_buff *request,
+ struct neighbour *n, bool isrouter)
+{
+ struct net_device *dev = request->dev;
+ struct sk_buff *reply;
+ struct nd_msg *ns, *na;
+ struct ipv6hdr *pip6;
+ u8 *daddr;
+ int na_olen = 8; /* opt hdr + ETH_ALEN for target */
+ int ns_olen;
+ int i, len;
+
+ if (dev == NULL)
+ return NULL;
+
+ len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
+ sizeof(*na) + na_olen + dev->needed_tailroom;
+ reply = alloc_skb(len, GFP_ATOMIC);
+ if (reply == NULL)
+ return NULL;
+
+ reply->protocol = htons(ETH_P_IPV6);
+ reply->dev = dev;
+ skb_reserve(reply, LL_RESERVED_SPACE(request->dev));
+ skb_push(reply, sizeof(struct ethhdr));
+ skb_set_mac_header(reply, 0);
+
+ ns = (struct nd_msg *)skb_transport_header(request);
+
+ daddr = eth_hdr(request)->h_source;
+ ns_olen = request->len - skb_transport_offset(request) - sizeof(*ns);
+ for (i = 0; i < ns_olen-1; i += (ns->opt[i+1]<<3)) {
+ if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) {
+ daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
+ break;
+ }
+ }
+
+ /* Ethernet header */
+ ether_addr_copy(eth_hdr(reply)->h_dest, daddr);
+ ether_addr_copy(eth_hdr(reply)->h_source, n->ha);
+ eth_hdr(reply)->h_proto = htons(ETH_P_IPV6);
+ reply->protocol = htons(ETH_P_IPV6);
+
+ skb_pull(reply, sizeof(struct ethhdr));
+ skb_set_network_header(reply, 0);
+ skb_put(reply, sizeof(struct ipv6hdr));
+
+ /* IPv6 header */
+
+ pip6 = ipv6_hdr(reply);
+ memset(pip6, 0, sizeof(struct ipv6hdr));
+ pip6->version = 6;
+ pip6->priority = ipv6_hdr(request)->priority;
+ pip6->nexthdr = IPPROTO_ICMPV6;
+ pip6->hop_limit = 255;
+ pip6->daddr = ipv6_hdr(request)->saddr;
+ pip6->saddr = *(struct in6_addr *)n->primary_key;
+
+ skb_pull(reply, sizeof(struct ipv6hdr));
+ skb_set_transport_header(reply, 0);
+
+ na = (struct nd_msg *)skb_put(reply, sizeof(*na) + na_olen);
+
+ /* Neighbor Advertisement */
+ memset(na, 0, sizeof(*na)+na_olen);
+ na->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
+ na->icmph.icmp6_router = isrouter;
+ na->icmph.icmp6_override = 1;
+ na->icmph.icmp6_solicited = 1;
+ na->target = ns->target;
+ ether_addr_copy(&na->opt[2], n->ha);
+ na->opt[0] = ND_OPT_TARGET_LL_ADDR;
+ na->opt[1] = na_olen >> 3;
+
+ na->icmph.icmp6_cksum = csum_ipv6_magic(&pip6->saddr,
+ &pip6->daddr, sizeof(*na)+na_olen, IPPROTO_ICMPV6,
+ csum_partial(na, sizeof(*na)+na_olen, 0));
+
+ pip6->payload_len = htons(sizeof(*na)+na_olen);
+
+ skb_push(reply, sizeof(struct ipv6hdr));
+
+ reply->ip_summed = CHECKSUM_UNNECESSARY;
+
+ return reply;
+}
+
static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
- struct neighbour *n;
- union vxlan_addr ipa;
+ struct nd_msg *msg;
const struct ipv6hdr *iphdr;
const struct in6_addr *saddr, *daddr;
- struct nd_msg *msg;
- struct inet6_dev *in6_dev = NULL;
+ struct neighbour *n;
+ struct inet6_dev *in6_dev;
in6_dev = __in6_dev_get(dev);
if (!in6_dev)
@@ -1360,19 +1451,20 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
saddr = &iphdr->saddr;
daddr = &iphdr->daddr;
- if (ipv6_addr_loopback(daddr) ||
- ipv6_addr_is_multicast(daddr))
- goto out;
-
msg = (struct nd_msg *)skb_transport_header(skb);
if (msg->icmph.icmp6_code != 0 ||
msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
goto out;
- n = neigh_lookup(ipv6_stub->nd_tbl, daddr, dev);
+ if (ipv6_addr_loopback(daddr) ||
+ ipv6_addr_is_multicast(&msg->target))
+ goto out;
+
+ n = neigh_lookup(ipv6_stub->nd_tbl, &msg->target, dev);
if (n) {
struct vxlan_fdb *f;
+ struct sk_buff *reply;
if (!(n->nud_state & NUD_CONNECTED)) {
neigh_release(n);
@@ -1386,13 +1478,23 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
goto out;
}
- ipv6_stub->ndisc_send_na(dev, n, saddr, &msg->target,
- !!in6_dev->cnf.forwarding,
- true, false, false);
+ reply = vxlan_na_create(skb, n,
+ !!(f ? f->flags & NTF_ROUTER : 0));
+
neigh_release(n);
+
+ if (reply == NULL)
+ goto out;
+
+ if (netif_rx_ni(reply) == NET_RX_DROP)
+ dev->stats.rx_dropped++;
+
} else if (vxlan->flags & VXLAN_F_L3MISS) {
- ipa.sin6.sin6_addr = *daddr;
- ipa.sa.sa_family = AF_INET6;
+ union vxlan_addr ipa = {
+ .sin6.sin6_addr = msg->target,
+ .sa.sa_family = AF_INET6,
+ };
+
vxlan_ip_miss(dev, &ipa);
}
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index d6bc7cb61bfb..1a2973b7acf2 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -110,7 +110,7 @@ ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band)
ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
if (ah->ah_version == AR5K_AR5210) {
- srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
+ srev = (ath5k_hw_reg_read(ah, AR5K_PHY(256)) >> 28) & 0xf;
ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
} else {
srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
index 1cc13569b17b..1b6b4d0cfa97 100644
--- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
@@ -57,7 +57,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e},
{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
- {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+ {0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5},
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
{0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
@@ -96,7 +96,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
{0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000},
{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
- {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+ {0x0000ae20, 0x000001a6, 0x000001a6, 0x000001aa, 0x000001aa},
{0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550},
};
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 11eab9f01fd8..9078a6c5a74e 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1534,7 +1534,7 @@ EXPORT_SYMBOL(ath9k_hw_check_nav);
bool ath9k_hw_check_alive(struct ath_hw *ah)
{
int count = 50;
- u32 reg;
+ u32 reg, last_val;
if (AR_SREV_9300(ah))
return !ath9k_hw_detect_mac_hang(ah);
@@ -1542,9 +1542,14 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
if (AR_SREV_9285_12_OR_LATER(ah))
return true;
+ last_val = REG_READ(ah, AR_OBS_BUS_1);
do {
reg = REG_READ(ah, AR_OBS_BUS_1);
+ if (reg != last_val)
+ return true;
+ udelay(1);
+ last_val = reg;
if ((reg & 0x7E7FFFEF) == 0x00702400)
continue;
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index a0ebdd000fc2..82e340d3ec60 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -732,11 +732,18 @@ static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc,
return NULL;
/*
- * mark descriptor as zero-length and set the 'more'
- * flag to ensure that both buffers get discarded
+ * Re-check previous descriptor, in case it has been filled
+ * in the mean time.
*/
- rs->rs_datalen = 0;
- rs->rs_more = true;
+ ret = ath9k_hw_rxprocdesc(ah, ds, rs);
+ if (ret == -EINPROGRESS) {
+ /*
+ * mark descriptor as zero-length and set the 'more'
+ * flag to ensure that both buffers get discarded
+ */
+ rs->rs_datalen = 0;
+ rs->rs_more = true;
+ }
}
list_del(&bf->list);
@@ -985,32 +992,32 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_hdr *hdr;
bool discard_current = sc->rx.discard_next;
- int ret = 0;
/*
* Discard corrupt descriptors which are marked in
* ath_get_next_rx_buf().
*/
- sc->rx.discard_next = rx_stats->rs_more;
if (discard_current)
- return -EINVAL;
+ goto corrupt;
+
+ sc->rx.discard_next = false;
/*
* Discard zero-length packets.
*/
if (!rx_stats->rs_datalen) {
RX_STAT_INC(rx_len_err);
- return -EINVAL;
+ goto corrupt;
}
- /*
- * rs_status follows rs_datalen so if rs_datalen is too large
- * we can take a hint that hardware corrupted it, so ignore
- * those frames.
- */
+ /*
+ * rs_status follows rs_datalen so if rs_datalen is too large
+ * we can take a hint that hardware corrupted it, so ignore
+ * those frames.
+ */
if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) {
RX_STAT_INC(rx_len_err);
- return -EINVAL;
+ goto corrupt;
}
/* Only use status info from the last fragment */
@@ -1024,10 +1031,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
* This is different from the other corrupt descriptor
* condition handled above.
*/
- if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) {
- ret = -EINVAL;
- goto exit;
- }
+ if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC)
+ goto corrupt;
hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len);
@@ -1043,18 +1048,15 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime))
RX_STAT_INC(rx_spectral);
- ret = -EINVAL;
- goto exit;
+ return -EINVAL;
}
/*
* everything but the rate is checked here, the rate check is done
* separately to avoid doing two lookups for a rate for each frame.
*/
- if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) {
- ret = -EINVAL;
- goto exit;
- }
+ if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
+ return -EINVAL;
if (ath_is_mybeacon(common, hdr)) {
RX_STAT_INC(rx_beacons);
@@ -1064,15 +1066,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
/*
* This shouldn't happen, but have a safety check anyway.
*/
- if (WARN_ON(!ah->curchan)) {
- ret = -EINVAL;
- goto exit;
- }
+ if (WARN_ON(!ah->curchan))
+ return -EINVAL;
- if (ath9k_process_rate(common, hw, rx_stats, rx_status)) {
- ret =-EINVAL;
- goto exit;
- }
+ if (ath9k_process_rate(common, hw, rx_stats, rx_status))
+ return -EINVAL;
ath9k_process_rssi(common, hw, rx_stats, rx_status);
@@ -1087,9 +1085,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
sc->rx.num_pkts++;
#endif
-exit:
- sc->rx.discard_next = false;
- return ret;
+ return 0;
+
+corrupt:
+ sc->rx.discard_next = rx_stats->rs_more;
+ return -EINVAL;
}
static void ath9k_rx_skb_postprocess(struct ath_common *common,
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 0a75e2f68c9d..55897d508a76 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1444,14 +1444,16 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
for (tidno = 0, tid = &an->tid[tidno];
tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
- if (!tid->sched)
- continue;
-
ac = tid->ac;
txq = ac->txq;
ath_txq_lock(sc, txq);
+ if (!tid->sched) {
+ ath_txq_unlock(sc, txq);
+ continue;
+ }
+
buffered = ath_tid_has_buffered(tid);
tid->sched = false;
@@ -2061,7 +2063,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
ATH_TXBUF_RESET(bf);
- if (tid) {
+ if (tid && ieee80211_is_data_present(hdr->frame_control)) {
fragno = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
seqno = tid->seq_next;
hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
@@ -2184,14 +2186,15 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
txq->stopped = true;
}
+ if (txctl->an && ieee80211_is_data_present(hdr->frame_control))
+ tid = ath_get_skb_tid(sc, txctl->an, skb);
+
if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) {
ath_txq_unlock(sc, txq);
txq = sc->tx.uapsdq;
ath_txq_lock(sc, txq);
} else if (txctl->an &&
ieee80211_is_data_present(hdr->frame_control)) {
- tid = ath_get_skb_tid(sc, txctl->an, skb);
-
WARN_ON(tid->ac->txq != txctl->txq);
if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 3e991897d7ca..ddaa9efd053d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -457,7 +457,6 @@ struct brcmf_sdio {
u8 tx_hdrlen; /* sdio bus header length for tx packet */
bool txglom; /* host tx glomming enable flag */
- struct sk_buff *txglom_sgpad; /* scatter-gather padding buffer */
u16 head_align; /* buffer pointer alignment */
u16 sgentry_align; /* scatter-gather buffer alignment */
};
@@ -1944,19 +1943,21 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
if (lastfrm && chain_pad)
tail_pad += blksize - chain_pad;
if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) {
- pkt_pad = bus->txglom_sgpad;
- if (pkt_pad == NULL)
- brcmu_pkt_buf_get_skb(tail_pad + tail_chop);
+ pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop +
+ bus->head_align);
if (pkt_pad == NULL)
return -ENOMEM;
ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ kfree_skb(pkt_pad);
return ret;
+ }
memcpy(pkt_pad->data,
pkt->data + pkt->len - tail_chop,
tail_chop);
*(u32 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
skb_trim(pkt, pkt->len - tail_chop);
+ skb_trim(pkt_pad, tail_pad + tail_chop);
__skb_queue_after(pktq, pkt, pkt_pad);
} else {
ntail = pkt->data_len + tail_pad -
@@ -2011,7 +2012,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
return ret;
head_pad = (u16)ret;
if (head_pad)
- memset(pkt_next->data, 0, head_pad + bus->tx_hdrlen);
+ memset(pkt_next->data + bus->tx_hdrlen, 0, head_pad);
total_len += pkt_next->len;
@@ -3486,10 +3487,6 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
bus->txglom = false;
value = 1;
pad_size = bus->sdiodev->func[2]->cur_blksize << 1;
- bus->txglom_sgpad = brcmu_pkt_buf_get_skb(pad_size);
- if (!bus->txglom_sgpad)
- brcmf_err("allocating txglom padding skb failed, reduced performance\n");
-
err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom",
&value, sizeof(u32));
if (err < 0) {
@@ -4053,7 +4050,6 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
brcmf_sdio_chip_detach(&bus->ci);
}
- brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
kfree(bus->rxbuf);
kfree(bus->hdrbuf);
kfree(bus);
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index d36e252d2ccb..596525528f50 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -147,7 +147,7 @@ static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
if (!sta->ap && sta->u.sta.challenge)
kfree(sta->u.sta.challenge);
- del_timer(&sta->timer);
+ del_timer_sync(&sta->timer);
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
kfree(sta);
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c
index aa7ad3a7a69b..4e5c0f8c9496 100644
--- a/drivers/net/wireless/hostap/hostap_proc.c
+++ b/drivers/net/wireless/hostap/hostap_proc.c
@@ -496,7 +496,7 @@ void hostap_init_proc(local_info_t *local)
void hostap_remove_proc(local_info_t *local)
{
- remove_proc_subtree(local->ddev->name, hostap_proc);
+ proc_remove(local->proc);
}
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index c24d1d3d55f6..73086c1629ca 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -696,6 +696,24 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return ret;
}
+static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg)
+{
+ if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
+ return false;
+ return true;
+}
+
+static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg)
+{
+ if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
+ return false;
+ if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG)
+ return true;
+
+ /* disabled by default */
+ return false;
+}
+
static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
@@ -717,7 +735,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
switch (action) {
case IEEE80211_AMPDU_RX_START:
- if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
+ if (!iwl_enable_rx_ampdu(priv->cfg))
break;
IWL_DEBUG_HT(priv, "start Rx\n");
ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
@@ -729,7 +747,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_TX_START:
if (!priv->trans->ops->txq_enable)
break;
- if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
+ if (!iwl_enable_tx_ampdu(priv->cfg))
break;
IWL_DEBUG_HT(priv, "start Tx\n");
ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c
index c0d070c5df5e..9cdd91cdf661 100644
--- a/drivers/net/wireless/iwlwifi/dvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/dvm/sta.c
@@ -590,6 +590,7 @@ void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
sizeof(priv->tid_data[sta_id][tid]));
priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+ priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
priv->num_stations--;
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
index a6839dfcb82d..398dd096674c 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tx.c
@@ -1291,8 +1291,6 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data;
struct iwl_ht_agg *agg;
struct sk_buff_head reclaimed_skbs;
- struct ieee80211_tx_info *info;
- struct ieee80211_hdr *hdr;
struct sk_buff *skb;
int sta_id;
int tid;
@@ -1379,22 +1377,28 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
freed = 0;
skb_queue_walk(&reclaimed_skbs, skb) {
- hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (ieee80211_is_data_qos(hdr->frame_control))
freed++;
else
WARN_ON_ONCE(1);
- info = IEEE80211_SKB_CB(skb);
iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]);
+ memset(&info->status, 0, sizeof(info->status));
+ /* Packet was transmitted successfully, failures come as single
+ * frames because before failing a frame the firmware transmits
+ * it without aggregation at least once.
+ */
+ info->flags |= IEEE80211_TX_STAT_ACK;
+
if (freed == 1) {
/* this is the first skb we deliver in this batch */
/* put the rate scaling data there */
info = IEEE80211_SKB_CB(skb);
memset(&info->status, 0, sizeof(info->status));
- info->flags |= IEEE80211_TX_STAT_ACK;
info->flags |= IEEE80211_TX_STAT_AMPDU;
info->status.ampdu_ack_len = ba_resp->txed_2_done;
info->status.ampdu_len = ba_resp->txed;
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index c3728163be46..75103554cd63 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -1286,7 +1286,7 @@ module_param_named(swcrypto, iwlwifi_mod_params.sw_crypto, int, S_IRUGO);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO);
MODULE_PARM_DESC(11n_disable,
- "disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX");
+ "disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX");
module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K,
int, S_IRUGO);
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)");
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h
index 0a84ade7edac..b29075c3da8e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-modparams.h
+++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h
@@ -79,9 +79,12 @@ enum iwl_power_level {
IWL_POWER_NUM
};
-#define IWL_DISABLE_HT_ALL BIT(0)
-#define IWL_DISABLE_HT_TXAGG BIT(1)
-#define IWL_DISABLE_HT_RXAGG BIT(2)
+enum iwl_disable_11n {
+ IWL_DISABLE_HT_ALL = BIT(0),
+ IWL_DISABLE_HT_TXAGG = BIT(1),
+ IWL_DISABLE_HT_RXAGG = BIT(2),
+ IWL_ENABLE_HT_TXAGG = BIT(3),
+};
/**
* struct iwl_mod_params
@@ -90,7 +93,7 @@ enum iwl_power_level {
*
* @sw_crypto: using hardware encryption, default = 0
* @disable_11n: disable 11n capabilities, default = 0,
- * use IWL_DISABLE_HT_* constants
+ * use IWL_[DIS,EN]ABLE_HT_* constants
* @amsdu_size_8K: enable 8K amsdu size, default = 0
* @restart_fw: restart firmware, default = 1
* @wd_disable: enable stuck queue check, default = 0
diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c
index 76cde6ce6551..18a895a949d4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c
@@ -872,8 +872,11 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
lockdep_assert_held(&mvm->mutex);
- /* Rssi update while not associated ?! */
- if (WARN_ON_ONCE(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT))
+ /*
+ * Rssi update while not associated - can happen since the statistics
+ * are handled asynchronously
+ */
+ if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
return;
/* No BT - reports should be disabled */
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 6bf9766e5982..c35b8661b395 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -328,6 +328,24 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
ieee80211_free_txskb(hw, skb);
}
+static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg)
+{
+ if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
+ return false;
+ return true;
+}
+
+static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg)
+{
+ if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
+ return false;
+ if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG)
+ return true;
+
+ /* enabled by default */
+ return true;
+}
+
static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
@@ -347,7 +365,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
switch (action) {
case IEEE80211_AMPDU_RX_START:
- if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) {
+ if (!iwl_enable_rx_ampdu(mvm->cfg)) {
ret = -EINVAL;
break;
}
@@ -357,7 +375,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false);
break;
case IEEE80211_AMPDU_TX_START:
- if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) {
+ if (!iwl_enable_tx_ampdu(mvm->cfg)) {
ret = -EINVAL;
break;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index e4ead86f06d6..2b0ba1fc3c82 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -152,7 +152,7 @@ enum iwl_power_scheme {
IWL_POWER_SCHEME_LP
};
-#define IWL_CONN_MAX_LISTEN_INTERVAL 70
+#define IWL_CONN_MAX_LISTEN_INTERVAL 10
#define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\
IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\
IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index 4df12fa9d336..76ee486039d7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -822,16 +822,12 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data;
struct sk_buff_head reclaimed_skbs;
struct iwl_mvm_tid_data *tid_data;
- struct ieee80211_tx_info *info;
struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvmsta;
- struct ieee80211_hdr *hdr;
struct sk_buff *skb;
int sta_id, tid, freed;
-
/* "flow" corresponds to Tx queue */
u16 scd_flow = le16_to_cpu(ba_notif->scd_flow);
-
/* "ssn" is start of block-ack Tx window, corresponds to index
* (in Tx queue's circular buffer) of first TFD/frame in window */
u16 ba_resp_scd_ssn = le16_to_cpu(ba_notif->scd_ssn);
@@ -888,22 +884,26 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
freed = 0;
skb_queue_walk(&reclaimed_skbs, skb) {
- hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (ieee80211_is_data_qos(hdr->frame_control))
freed++;
else
WARN_ON_ONCE(1);
- info = IEEE80211_SKB_CB(skb);
iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
+ memset(&info->status, 0, sizeof(info->status));
+ /* Packet was transmitted successfully, failures come as single
+ * frames because before failing a frame the firmware transmits
+ * it without aggregation at least once.
+ */
+ info->flags |= IEEE80211_TX_STAT_ACK;
+
if (freed == 1) {
/* this is the first skb we deliver in this batch */
/* put the rate scaling data there */
- info = IEEE80211_SKB_CB(skb);
- memset(&info->status, 0, sizeof(info->status));
- info->flags |= IEEE80211_TX_STAT_ACK;
info->flags |= IEEE80211_TX_STAT_AMPDU;
info->status.ampdu_ack_len = ba_notif->txed_2_done;
info->status.ampdu_len = ba_notif->txed;
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
index f47bcbe2945a..3872ead75488 100644
--- a/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -359,13 +359,12 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
/* 7265 Series */
{IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5110, iwl7265_2ac_cfg)},
- {IWL_PCI_DEVICE(0x095A, 0x5112, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5100, iwl7265_2ac_cfg)},
- {IWL_PCI_DEVICE(0x095A, 0x510A, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)},
- {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_n_cfg)},
{IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x095A, 0x5412, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5410, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5400, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x1010, iwl7265_2ac_cfg)},
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 32f75007a825..cb6d189bc3e6 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -621,7 +621,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
id = *pos++;
elen = *pos++;
left -= 2;
- if (elen > left || elen == 0) {
+ if (elen > left) {
lbs_deb_scan("scan response: invalid IE fmt\n");
goto done;
}
diff --git a/drivers/net/wireless/mwifiex/11ac.c b/drivers/net/wireless/mwifiex/11ac.c
index 5e0eec4d71c7..5d9a8084665d 100644
--- a/drivers/net/wireless/mwifiex/11ac.c
+++ b/drivers/net/wireless/mwifiex/11ac.c
@@ -189,8 +189,7 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
vht_cap->header.len =
cpu_to_le16(sizeof(struct ieee80211_vht_cap));
memcpy((u8 *)vht_cap + sizeof(struct mwifiex_ie_types_header),
- (u8 *)bss_desc->bcn_vht_cap +
- sizeof(struct ieee_types_header),
+ (u8 *)bss_desc->bcn_vht_cap,
le16_to_cpu(vht_cap->header.len));
mwifiex_fill_vht_cap_tlv(priv, vht_cap, bss_desc->bss_band);
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index 6261f8c53d44..7db1a89fdd95 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -308,8 +308,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
ht_cap->header.len =
cpu_to_le16(sizeof(struct ieee80211_ht_cap));
memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header),
- (u8 *) bss_desc->bcn_ht_cap +
- sizeof(struct ieee_types_header),
+ (u8 *)bss_desc->bcn_ht_cap,
le16_to_cpu(ht_cap->header.len));
mwifiex_fill_cap_info(priv, radio_type, ht_cap);
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 4d79761b9c87..9d3d2758ec35 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -748,7 +748,7 @@ static struct net_device_stats *mwifiex_get_stats(struct net_device *dev)
static u16
mwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
skb->priority = cfg80211_classify8021d(skb, NULL);
return mwifiex_1d_to_wmm_queue[skb->priority];
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index 03688aa14e8a..7fe7b53fb17a 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -1211,6 +1211,12 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
rd_index = card->rxbd_rdptr & reg->rx_mask;
skb_data = card->rx_buf_list[rd_index];
+ /* If skb allocation was failed earlier for Rx packet,
+ * rx_buf_list[rd_index] would have been left with a NULL.
+ */
+ if (!skb_data)
+ return -ENOMEM;
+
MWIFIEX_SKB_PACB(skb_data, &buf_pa);
pci_unmap_single(card->dev, buf_pa, MWIFIEX_RX_DATA_BUF_SIZE,
PCI_DMA_FROMDEVICE);
@@ -1525,6 +1531,14 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
mwifiex_process_sleep_confirm_resp(adapter, skb->data,
skb->len);
+ mwifiex_pcie_enable_host_int(adapter);
+ if (mwifiex_write_reg(adapter,
+ PCIE_CPU_INT_EVENT,
+ CPU_INTR_SLEEP_CFM_DONE)) {
+ dev_warn(adapter->dev,
+ "Write register failed\n");
+ return -1;
+ }
while (reg->sleep_cookie && (count++ < 10) &&
mwifiex_pcie_ok_to_access_hw(adapter))
usleep_range(50, 60);
@@ -1993,23 +2007,9 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
adapter->int_status |= pcie_ireg;
spin_unlock_irqrestore(&adapter->int_lock, flags);
- if (pcie_ireg & HOST_INTR_CMD_DONE) {
- if ((adapter->ps_state == PS_STATE_SLEEP_CFM) ||
- (adapter->ps_state == PS_STATE_SLEEP)) {
- mwifiex_pcie_enable_host_int(adapter);
- if (mwifiex_write_reg(adapter,
- PCIE_CPU_INT_EVENT,
- CPU_INTR_SLEEP_CFM_DONE)
- ) {
- dev_warn(adapter->dev,
- "Write register failed\n");
- return;
-
- }
- }
- } else if (!adapter->pps_uapsd_mode &&
- adapter->ps_state == PS_STATE_SLEEP &&
- mwifiex_pcie_ok_to_access_hw(adapter)) {
+ if (!adapter->pps_uapsd_mode &&
+ adapter->ps_state == PS_STATE_SLEEP &&
+ mwifiex_pcie_ok_to_access_hw(adapter)) {
/* Potentially for PCIe we could get other
* interrupts like shared. Don't change power
* state until cookie is set */
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 0a8a26e10f01..668547c2de84 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -2101,12 +2101,12 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
curr_bss->ht_info_offset);
if (curr_bss->bcn_vht_cap)
- curr_bss->bcn_ht_cap = (void *)(curr_bss->beacon_buf +
- curr_bss->vht_cap_offset);
+ curr_bss->bcn_vht_cap = (void *)(curr_bss->beacon_buf +
+ curr_bss->vht_cap_offset);
if (curr_bss->bcn_vht_oper)
- curr_bss->bcn_ht_oper = (void *)(curr_bss->beacon_buf +
- curr_bss->vht_info_offset);
+ curr_bss->bcn_vht_oper = (void *)(curr_bss->beacon_buf +
+ curr_bss->vht_info_offset);
if (curr_bss->bcn_bss_co_2040)
curr_bss->bcn_bss_co_2040 =
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c
index e8ebbd4bc3cd..208748804a55 100644
--- a/drivers/net/wireless/mwifiex/usb.c
+++ b/drivers/net/wireless/mwifiex/usb.c
@@ -22,8 +22,6 @@
#define USB_VERSION "1.0"
-static const char usbdriver_name[] = "usb8xxx";
-
static struct mwifiex_if_ops usb_ops;
static struct semaphore add_remove_card_sem;
static struct usb_card_rec *usb_card;
@@ -527,13 +525,6 @@ static int mwifiex_usb_resume(struct usb_interface *intf)
MWIFIEX_BSS_ROLE_ANY),
MWIFIEX_ASYNC_CMD);
-#ifdef CONFIG_PM
- /* Resume handler may be called due to remote wakeup,
- * force to exit suspend anyway
- */
- usb_disable_autosuspend(card->udev);
-#endif /* CONFIG_PM */
-
return 0;
}
@@ -567,13 +558,12 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf)
}
static struct usb_driver mwifiex_usb_driver = {
- .name = usbdriver_name,
+ .name = "mwifiex_usb",
.probe = mwifiex_usb_probe,
.disconnect = mwifiex_usb_disconnect,
.id_table = mwifiex_usb_table,
.suspend = mwifiex_usb_suspend,
.resume = mwifiex_usb_resume,
- .supports_autosuspend = 1,
};
static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index 13eaeed03898..981cf6e7c73b 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -559,7 +559,8 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)
mwifiex_wmm_delete_all_ralist(priv);
memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
- if (priv->adapter->if_ops.clean_pcie_ring)
+ if (priv->adapter->if_ops.clean_pcie_ring &&
+ !priv->adapter->surprise_removed)
priv->adapter->if_ops.clean_pcie_ring(priv->adapter);
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
}
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 7f8b5d156c8c..41d4a8167dc3 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -5460,14 +5460,15 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
rt2800_bbp_write(rt2x00dev, 68, 0x0b);
- rt2800_bbp_write(rt2x00dev, 69, 0x0d);
- rt2800_bbp_write(rt2x00dev, 70, 0x06);
+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
rt2800_bbp_write(rt2x00dev, 73, 0x13);
rt2800_bbp_write(rt2x00dev, 75, 0x46);
rt2800_bbp_write(rt2x00dev, 76, 0x28);
rt2800_bbp_write(rt2x00dev, 77, 0x59);
+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
+
rt2800_bbp_write(rt2x00dev, 79, 0x13);
rt2800_bbp_write(rt2x00dev, 80, 0x05);
rt2800_bbp_write(rt2x00dev, 81, 0x33);
@@ -5510,7 +5511,6 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
if (rt2x00_rt(rt2x00dev, RT5392)) {
rt2800_bbp_write(rt2x00dev, 134, 0xd0);
rt2800_bbp_write(rt2x00dev, 135, 0xf6);
- rt2800_bbp_write(rt2x00dev, 148, 0x84);
}
rt2800_disable_unused_dac_adc(rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index caddc1b427a9..42a2e06512f2 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -764,7 +764,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Overwrite TX done handler
*/
- PREPARE_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone);
+ INIT_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone);
return 0;
}
diff --git a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
index 56aee067f324..a6ad79f61bf9 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
+++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
@@ -15,6 +15,8 @@
#ifndef RTL8187_H
#define RTL8187_H
+#include <linux/cache.h>
+
#include "rtl818x.h"
#include "leds.h"
@@ -139,7 +141,10 @@ struct rtl8187_priv {
u8 aifsn[4];
u8 rfkill_mask;
struct {
- __le64 buf;
+ union {
+ __le64 buf;
+ u8 dummy1[L1_CACHE_BYTES];
+ } ____cacheline_aligned;
struct sk_buff_head queue;
} b_tx_status; /* This queue is used by both -b and non-b devices */
struct mutex io_mutex;
@@ -147,7 +152,8 @@ struct rtl8187_priv {
u8 bits8;
__le16 bits16;
__le32 bits32;
- } *io_dmabuf;
+ u8 dummy2[L1_CACHE_BYTES];
+ } *io_dmabuf ____cacheline_aligned;
bool rfkill_off;
u16 seqno;
};
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
index deedae3c5449..d1c0191a195b 100644
--- a/drivers/net/wireless/rtlwifi/ps.c
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -48,7 +48,7 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
/*<2> Enable Adapter */
if (rtlpriv->cfg->ops->hw_init(hw))
- return 1;
+ return false;
RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
/*<3> Enable Interrupt */
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
index a82b30a1996c..2eb0b38384dd 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -937,14 +937,26 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
bool is92c;
int err;
u8 tmp_u1b;
+ unsigned long flags;
rtlpci->being_init_adapter = true;
+
+ /* Since this function can take a very long time (up to 350 ms)
+ * and can be called with irqs disabled, reenable the irqs
+ * to let the other devices continue being serviced.
+ *
+ * It is safe doing so since our own interrupts will only be enabled
+ * in a subsequent step.
+ */
+ local_save_flags(flags);
+ local_irq_enable();
+
rtlpriv->intf_ops->disable_aspm(hw);
rtstatus = _rtl92ce_init_mac(hw);
if (!rtstatus) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
err = 1;
- return err;
+ goto exit;
}
err = rtl92c_download_fw(hw);
@@ -952,7 +964,7 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Failed to download FW. Init HW without FW now..\n");
err = 1;
- return err;
+ goto exit;
}
rtlhal->last_hmeboxnum = 0;
@@ -1032,6 +1044,8 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n");
}
rtl92c_dm_init(hw);
+exit:
+ local_irq_restore(flags);
rtlpci->being_init_adapter = false;
return err;
}
diff --git a/drivers/net/wireless/ti/wl1251/rx.c b/drivers/net/wireless/ti/wl1251/rx.c
index 123c4bb50e0a..cde0eaf99714 100644
--- a/drivers/net/wireless/ti/wl1251/rx.c
+++ b/drivers/net/wireless/ti/wl1251/rx.c
@@ -180,7 +180,7 @@ static void wl1251_rx_body(struct wl1251 *wl,
wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
/* The actual length doesn't include the target's alignment */
- skb->len = desc->length - PLCP_HEADER_LENGTH;
+ skb_trim(skb, desc->length - PLCP_HEADER_LENGTH);
fc = (u16 *)skb->data;
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 7669d49a67e2..301cc037fda8 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -132,8 +132,7 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* If the skb is GSO then we'll also need an extra slot for the
* metadata.
*/
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
- skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+ if (skb_is_gso(skb))
min_slots_needed++;
/* If the skb can't possibly fit in the remaining slots
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index e5284bca2d90..438d0c09b7e6 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -240,7 +240,7 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
struct gnttab_copy *copy_gop;
struct xenvif_rx_meta *meta;
unsigned long bytes;
- int gso_type;
+ int gso_type = XEN_NETIF_GSO_TYPE_NONE;
/* Data must not cross a page boundary. */
BUG_ON(size + offset > PAGE_SIZE<<compound_order(page));
@@ -299,12 +299,12 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
}
/* Leave a gap for the GSO descriptor. */
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
- gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
- else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
- gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
- else
- gso_type = XEN_NETIF_GSO_TYPE_NONE;
+ if (skb_is_gso(skb)) {
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+ gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
+ else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+ gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
+ }
if (*head && ((1 << gso_type) & vif->gso_mask))
vif->rx.req_cons++;
@@ -338,19 +338,15 @@ static int xenvif_gop_skb(struct sk_buff *skb,
int head = 1;
int old_meta_prod;
int gso_type;
- int gso_size;
old_meta_prod = npo->meta_prod;
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
- gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
- gso_size = skb_shinfo(skb)->gso_size;
- } else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
- gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
- gso_size = skb_shinfo(skb)->gso_size;
- } else {
- gso_type = XEN_NETIF_GSO_TYPE_NONE;
- gso_size = 0;
+ gso_type = XEN_NETIF_GSO_TYPE_NONE;
+ if (skb_is_gso(skb)) {
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+ gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
+ else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+ gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
}
/* Set up a GSO prefix descriptor, if necessary */
@@ -358,7 +354,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
meta = npo->meta + npo->meta_prod++;
meta->gso_type = gso_type;
- meta->gso_size = gso_size;
+ meta->gso_size = skb_shinfo(skb)->gso_size;
meta->size = 0;
meta->id = req->id;
}
@@ -368,7 +364,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
if ((1 << gso_type) & vif->gso_mask) {
meta->gso_type = gso_type;
- meta->gso_size = gso_size;
+ meta->gso_size = skb_shinfo(skb)->gso_size;
} else {
meta->gso_type = XEN_NETIF_GSO_TYPE_NONE;
meta->gso_size = 0;
@@ -500,8 +496,9 @@ static void xenvif_rx_action(struct xenvif *vif)
size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
max_slots_needed += DIV_ROUND_UP(size, PAGE_SIZE);
}
- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
- skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+ if (skb_is_gso(skb) &&
+ (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
+ skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6))
max_slots_needed++;
/* If the skb may not fit then bail out now */
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index f9daa9e183f2..e30d80033cbc 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -907,6 +907,7 @@ static int handle_incoming_queue(struct net_device *dev,
/* Ethernet work: Delayed to here as it peeks the header. */
skb->protocol = eth_type_trans(skb, dev);
+ skb_reset_network_header(skb);
if (checksum_setup(dev, skb)) {
kfree_skb(skb);
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index c6973f101a3e..889005fa4d04 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -7,14 +7,6 @@ config OF
menu "Device Tree and Open Firmware support"
depends on OF
-config PROC_DEVICETREE
- bool "Support for device tree in /proc"
- depends on PROC_FS && !SPARC
- help
- This option adds a device-tree directory under /proc which contains
- an image of the device tree that the kernel copies from Open
- Firmware or other boot firmware. If unsure, say Y here.
-
config OF_SELFTEST
bool "Device Tree Runtime self tests"
depends on OF_IRQ
@@ -44,6 +36,10 @@ config OF_DYNAMIC
config OF_ADDRESS
def_bool y
depends on !SPARC
+ select OF_ADDRESS_PCI if PCI
+
+config OF_ADDRESS_PCI
+ bool
config OF_IRQ
def_bool y
@@ -75,4 +71,10 @@ config OF_MTD
depends on MTD
def_bool y
+config OF_RESERVED_MEM
+ depends on OF_EARLY_FLATTREE
+ bool
+ help
+ Helpers to allow for reservation of memory regions
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index efd05102c405..ed9660adad77 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
+obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 1a54f1ffaadb..cb4242a69cd5 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -91,7 +91,7 @@ static unsigned int of_bus_default_get_flags(const __be32 *addr)
return IORESOURCE_MEM;
}
-#ifdef CONFIG_PCI
+#ifdef CONFIG_OF_ADDRESS_PCI
/*
* PCI bus specific translator
*/
@@ -166,7 +166,9 @@ static int of_bus_pci_translate(__be32 *addr, u64 offset, int na)
{
return of_bus_default_translate(addr + 1, offset, na - 1);
}
+#endif /* CONFIG_OF_ADDRESS_PCI */
+#ifdef CONFIG_PCI
const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
unsigned int *flags)
{
@@ -356,7 +358,7 @@ static unsigned int of_bus_isa_get_flags(const __be32 *addr)
*/
static struct of_bus of_busses[] = {
-#ifdef CONFIG_PCI
+#ifdef CONFIG_OF_ADDRESS_PCI
/* PCI */
{
.name = "pci",
@@ -367,7 +369,7 @@ static struct of_bus of_busses[] = {
.translate = of_bus_pci_translate,
.get_flags = of_bus_pci_get_flags,
},
-#endif /* CONFIG_PCI */
+#endif /* CONFIG_OF_ADDRESS_PCI */
/* ISA */
{
.name = "isa",
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 10b51106c854..4557a142c752 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -21,8 +21,10 @@
#include <linux/cpu.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/proc_fs.h>
#include "of_private.h"
@@ -35,6 +37,12 @@ struct device_node *of_chosen;
struct device_node *of_aliases;
static struct device_node *of_stdout;
+static struct kset *of_kset;
+
+/*
+ * Used to protect the of_aliases; but also overloaded to hold off addition of
+ * nodes to sysfs
+ */
DEFINE_MUTEX(of_aliases_mutex);
/* use when traversing tree through the allnext, child, sibling,
@@ -92,14 +100,14 @@ int __weak of_node_to_nid(struct device_node *np)
struct device_node *of_node_get(struct device_node *node)
{
if (node)
- kref_get(&node->kref);
+ kobject_get(&node->kobj);
return node;
}
EXPORT_SYMBOL(of_node_get);
-static inline struct device_node *kref_to_device_node(struct kref *kref)
+static inline struct device_node *kobj_to_device_node(struct kobject *kobj)
{
- return container_of(kref, struct device_node, kref);
+ return container_of(kobj, struct device_node, kobj);
}
/**
@@ -109,16 +117,15 @@ static inline struct device_node *kref_to_device_node(struct kref *kref)
* In of_node_put() this function is passed to kref_put()
* as the destructor.
*/
-static void of_node_release(struct kref *kref)
+static void of_node_release(struct kobject *kobj)
{
- struct device_node *node = kref_to_device_node(kref);
+ struct device_node *node = kobj_to_device_node(kobj);
struct property *prop = node->properties;
/* We should never be releasing nodes that haven't been detached. */
if (!of_node_check_flag(node, OF_DETACHED)) {
pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name);
dump_stack();
- kref_init(&node->kref);
return;
}
@@ -151,11 +158,154 @@ static void of_node_release(struct kref *kref)
void of_node_put(struct device_node *node)
{
if (node)
- kref_put(&node->kref, of_node_release);
+ kobject_put(&node->kobj);
}
EXPORT_SYMBOL(of_node_put);
+#else
+static void of_node_release(struct kobject *kobj)
+{
+ /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */
+}
#endif /* CONFIG_OF_DYNAMIC */
+struct kobj_type of_node_ktype = {
+ .release = of_node_release,
+};
+
+static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t offset, size_t count)
+{
+ struct property *pp = container_of(bin_attr, struct property, attr);
+ return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length);
+}
+
+static const char *safe_name(struct kobject *kobj, const char *orig_name)
+{
+ const char *name = orig_name;
+ struct kernfs_node *kn;
+ int i = 0;
+
+ /* don't be a hero. After 16 tries give up */
+ while (i < 16 && (kn = sysfs_get_dirent(kobj->sd, name))) {
+ sysfs_put(kn);
+ if (name != orig_name)
+ kfree(name);
+ name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i);
+ }
+
+ if (name != orig_name)
+ pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n",
+ kobject_name(kobj), name);
+ return name;
+}
+
+static int __of_add_property_sysfs(struct device_node *np, struct property *pp)
+{
+ int rc;
+
+ /* Important: Don't leak passwords */
+ bool secure = strncmp(pp->name, "security-", 9) == 0;
+
+ sysfs_bin_attr_init(&pp->attr);
+ pp->attr.attr.name = safe_name(&np->kobj, pp->name);
+ pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO;
+ pp->attr.size = secure ? 0 : pp->length;
+ pp->attr.read = of_node_property_read;
+
+ rc = sysfs_create_bin_file(&np->kobj, &pp->attr);
+ WARN(rc, "error adding attribute %s to node %s\n", pp->name, np->full_name);
+ return rc;
+}
+
+static int __of_node_add(struct device_node *np)
+{
+ const char *name;
+ struct property *pp;
+ int rc;
+
+ np->kobj.kset = of_kset;
+ if (!np->parent) {
+ /* Nodes without parents are new top level trees */
+ rc = kobject_add(&np->kobj, NULL, safe_name(&of_kset->kobj, "base"));
+ } else {
+ name = safe_name(&np->parent->kobj, kbasename(np->full_name));
+ if (!name || !name[0])
+ return -EINVAL;
+
+ rc = kobject_add(&np->kobj, &np->parent->kobj, "%s", name);
+ }
+ if (rc)
+ return rc;
+
+ for_each_property_of_node(np, pp)
+ __of_add_property_sysfs(np, pp);
+
+ return 0;
+}
+
+int of_node_add(struct device_node *np)
+{
+ int rc = 0;
+
+ BUG_ON(!of_node_is_initialized(np));
+
+ /*
+ * Grab the mutex here so that in a race condition between of_init() and
+ * of_node_add(), node addition will still be consistent.
+ */
+ mutex_lock(&of_aliases_mutex);
+ if (of_kset)
+ rc = __of_node_add(np);
+ else
+ /* This scenario may be perfectly valid, but report it anyway */
+ pr_info("of_node_add(%s) before of_init()\n", np->full_name);
+ mutex_unlock(&of_aliases_mutex);
+ return rc;
+}
+
+#if defined(CONFIG_OF_DYNAMIC)
+static void of_node_remove(struct device_node *np)
+{
+ struct property *pp;
+
+ BUG_ON(!of_node_is_initialized(np));
+
+ /* only remove properties if on sysfs */
+ if (of_node_is_attached(np)) {
+ for_each_property_of_node(np, pp)
+ sysfs_remove_bin_file(&np->kobj, &pp->attr);
+ kobject_del(&np->kobj);
+ }
+
+ /* finally remove the kobj_init ref */
+ of_node_put(np);
+}
+#endif
+
+static int __init of_init(void)
+{
+ struct device_node *np;
+
+ /* Create the kset, and register existing nodes */
+ mutex_lock(&of_aliases_mutex);
+ of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj);
+ if (!of_kset) {
+ mutex_unlock(&of_aliases_mutex);
+ return -ENOMEM;
+ }
+ for_each_of_allnodes(np)
+ __of_node_add(np);
+ mutex_unlock(&of_aliases_mutex);
+
+ /* Symlink in /proc as required by userspace ABI */
+ if (of_allnodes)
+ proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
+
+ return 0;
+}
+core_initcall(of_init);
+
static struct property *__of_find_property(const struct device_node *np,
const char *name, int *lenp)
{
@@ -342,27 +492,72 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
}
EXPORT_SYMBOL(of_get_cpu_node);
-/** Checks if the given "compat" string matches one of the strings in
- * the device's "compatible" property
+/**
+ * __of_device_is_compatible() - Check if the node matches given constraints
+ * @device: pointer to node
+ * @compat: required compatible string, NULL or "" for any match
+ * @type: required device_type value, NULL or "" for any match
+ * @name: required node name, NULL or "" for any match
+ *
+ * Checks if the given @compat, @type and @name strings match the
+ * properties of the given @device. A constraints can be skipped by
+ * passing NULL or an empty string as the constraint.
+ *
+ * Returns 0 for no match, and a positive integer on match. The return
+ * value is a relative score with larger values indicating better
+ * matches. The score is weighted for the most specific compatible value
+ * to get the highest score. Matching type is next, followed by matching
+ * name. Practically speaking, this results in the following priority
+ * order for matches:
+ *
+ * 1. specific compatible && type && name
+ * 2. specific compatible && type
+ * 3. specific compatible && name
+ * 4. specific compatible
+ * 5. general compatible && type && name
+ * 6. general compatible && type
+ * 7. general compatible && name
+ * 8. general compatible
+ * 9. type && name
+ * 10. type
+ * 11. name
*/
static int __of_device_is_compatible(const struct device_node *device,
- const char *compat)
+ const char *compat, const char *type, const char *name)
{
- const char* cp;
- int cplen, l;
+ struct property *prop;
+ const char *cp;
+ int index = 0, score = 0;
+
+ /* Compatible match has highest priority */
+ if (compat && compat[0]) {
+ prop = __of_find_property(device, "compatible", NULL);
+ for (cp = of_prop_next_string(prop, NULL); cp;
+ cp = of_prop_next_string(prop, cp), index++) {
+ if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
+ score = INT_MAX/2 - (index << 2);
+ break;
+ }
+ }
+ if (!score)
+ return 0;
+ }
- cp = __of_get_property(device, "compatible", &cplen);
- if (cp == NULL)
- return 0;
- while (cplen > 0) {
- if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
- return 1;
- l = strlen(cp) + 1;
- cp += l;
- cplen -= l;
+ /* Matching type is better than matching name */
+ if (type && type[0]) {
+ if (!device->type || of_node_cmp(type, device->type))
+ return 0;
+ score += 2;
}
- return 0;
+ /* Matching name is a bit better than not */
+ if (name && name[0]) {
+ if (!device->name || of_node_cmp(name, device->name))
+ return 0;
+ score++;
+ }
+
+ return score;
}
/** Checks if the given "compat" string matches one of the strings in
@@ -375,7 +570,7 @@ int of_device_is_compatible(const struct device_node *device,
int res;
raw_spin_lock_irqsave(&devtree_lock, flags);
- res = __of_device_is_compatible(device, compat);
+ res = __of_device_is_compatible(device, compat, NULL, NULL);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return res;
}
@@ -681,10 +876,7 @@ struct device_node *of_find_compatible_node(struct device_node *from,
raw_spin_lock_irqsave(&devtree_lock, flags);
np = from ? from->allnext : of_allnodes;
for (; np; np = np->allnext) {
- if (type
- && !(np->type && (of_node_cmp(np->type, type) == 0)))
- continue;
- if (__of_device_is_compatible(np, compatible) &&
+ if (__of_device_is_compatible(np, compatible, type, NULL) &&
of_node_get(np))
break;
}
@@ -730,65 +922,26 @@ out:
}
EXPORT_SYMBOL(of_find_node_with_property);
-static const struct of_device_id *
-of_match_compatible(const struct of_device_id *matches,
- const struct device_node *node)
-{
- const char *cp;
- int cplen, l;
- const struct of_device_id *m;
-
- cp = __of_get_property(node, "compatible", &cplen);
- while (cp && (cplen > 0)) {
- m = matches;
- while (m->name[0] || m->type[0] || m->compatible[0]) {
- /* Only match for the entries without type and name */
- if (m->name[0] || m->type[0] ||
- of_compat_cmp(m->compatible, cp,
- strlen(m->compatible)))
- m++;
- else
- return m;
- }
-
- /* Get node's next compatible string */
- l = strlen(cp) + 1;
- cp += l;
- cplen -= l;
- }
-
- return NULL;
-}
-
static
const struct of_device_id *__of_match_node(const struct of_device_id *matches,
const struct device_node *node)
{
- const struct of_device_id *m;
+ const struct of_device_id *best_match = NULL;
+ int score, best_score = 0;
if (!matches)
return NULL;
- m = of_match_compatible(matches, node);
- if (m)
- return m;
-
- while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
- int match = 1;
- if (matches->name[0])
- match &= node->name
- && !strcmp(matches->name, node->name);
- if (matches->type[0])
- match &= node->type
- && !strcmp(matches->type, node->type);
- if (matches->compatible[0])
- match &= __of_device_is_compatible(node,
- matches->compatible);
- if (match)
- return matches;
- matches++;
+ for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
+ score = __of_device_is_compatible(node, matches->compatible,
+ matches->type, matches->name);
+ if (score > best_score) {
+ best_match = matches;
+ best_score = score;
+ }
}
- return NULL;
+
+ return best_match;
}
/**
@@ -796,12 +949,7 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches,
* @matches: array of of device match structures to search in
* @node: the of device structure to match against
*
- * Low level utility function used by device matching. We have two ways
- * of matching:
- * - Try to find the best compatible match by comparing each compatible
- * string of device node with all the given matches respectively.
- * - If the above method failed, then try to match the compatible by using
- * __of_device_is_compatible() besides the match in type and name.
+ * Low level utility function used by device matching.
*/
const struct of_device_id *of_match_node(const struct of_device_id *matches,
const struct device_node *node)
@@ -906,6 +1054,38 @@ struct device_node *of_find_node_by_phandle(phandle handle)
EXPORT_SYMBOL(of_find_node_by_phandle);
/**
+ * of_property_count_elems_of_size - Count the number of elements in a property
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @elem_size: size of the individual element
+ *
+ * Search for a property in a device node and count the number of elements of
+ * size elem_size in it. Returns number of elements on sucess, -EINVAL if the
+ * property does not exist or its length does not match a multiple of elem_size
+ * and -ENODATA if the property does not have a value.
+ */
+int of_property_count_elems_of_size(const struct device_node *np,
+ const char *propname, int elem_size)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+
+ if (prop->length % elem_size != 0) {
+ pr_err("size of %s in node %s is not a multiple of %d\n",
+ propname, np->full_name, elem_size);
+ return -EINVAL;
+ }
+
+ return prop->length / elem_size;
+}
+EXPORT_SYMBOL_GPL(of_property_count_elems_of_size);
+
+/**
* of_find_property_value_of_size
*
* @np: device node from which the property value is to be read.
@@ -1500,6 +1680,10 @@ static int of_property_notify(int action, struct device_node *np,
{
struct of_prop_reconfig pr;
+ /* only call notifiers if the node is attached */
+ if (!of_node_is_attached(np))
+ return 0;
+
pr.dn = np;
pr.prop = prop;
return of_reconfig_notify(action, &pr);
@@ -1513,11 +1697,31 @@ static int of_property_notify(int action, struct device_node *np,
#endif
/**
+ * __of_add_property - Add a property to a node without lock operations
+ */
+static int __of_add_property(struct device_node *np, struct property *prop)
+{
+ struct property **next;
+
+ prop->next = NULL;
+ next = &np->properties;
+ while (*next) {
+ if (strcmp(prop->name, (*next)->name) == 0)
+ /* duplicate ! don't insert it */
+ return -EEXIST;
+
+ next = &(*next)->next;
+ }
+ *next = prop;
+
+ return 0;
+}
+
+/**
* of_add_property - Add a property to a node
*/
int of_add_property(struct device_node *np, struct property *prop)
{
- struct property **next;
unsigned long flags;
int rc;
@@ -1525,27 +1729,16 @@ int of_add_property(struct device_node *np, struct property *prop)
if (rc)
return rc;
- prop->next = NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
- next = &np->properties;
- while (*next) {
- if (strcmp(prop->name, (*next)->name) == 0) {
- /* duplicate ! don't insert it */
- raw_spin_unlock_irqrestore(&devtree_lock, flags);
- return -1;
- }
- next = &(*next)->next;
- }
- *next = prop;
+ rc = __of_add_property(np, prop);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
+ if (rc)
+ return rc;
-#ifdef CONFIG_PROC_DEVICETREE
- /* try to add to proc as well if it was initialized */
- if (np->pde)
- proc_device_tree_add_prop(np->pde, prop);
-#endif /* CONFIG_PROC_DEVICETREE */
+ if (of_node_is_attached(np))
+ __of_add_property_sysfs(np, prop);
- return 0;
+ return rc;
}
/**
@@ -1585,11 +1778,11 @@ int of_remove_property(struct device_node *np, struct property *prop)
if (!found)
return -ENODEV;
-#ifdef CONFIG_PROC_DEVICETREE
- /* try to remove the proc node as well */
- if (np->pde)
- proc_device_tree_remove_prop(np->pde, prop);
-#endif /* CONFIG_PROC_DEVICETREE */
+ /* at early boot, bail hear and defer setup to of_init() */
+ if (!of_kset)
+ return 0;
+
+ sysfs_remove_bin_file(&np->kobj, &prop->attr);
return 0;
}
@@ -1635,16 +1828,17 @@ int of_update_property(struct device_node *np, struct property *newprop)
next = &(*next)->next;
}
raw_spin_unlock_irqrestore(&devtree_lock, flags);
+ if (rc)
+ return rc;
+
+ /* Update the sysfs attribute */
+ if (oldprop)
+ sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
+ __of_add_property_sysfs(np, newprop);
if (!found)
return -ENODEV;
-#ifdef CONFIG_PROC_DEVICETREE
- /* try to add to proc as well if it was initialized */
- if (np->pde)
- proc_device_tree_update_prop(np->pde, newprop, oldprop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
return 0;
}
@@ -1679,22 +1873,6 @@ int of_reconfig_notify(unsigned long action, void *p)
return notifier_to_errno(rc);
}
-#ifdef CONFIG_PROC_DEVICETREE
-static void of_add_proc_dt_entry(struct device_node *dn)
-{
- struct proc_dir_entry *ent;
-
- ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde);
- if (ent)
- proc_device_tree_add_node(dn, ent);
-}
-#else
-static void of_add_proc_dt_entry(struct device_node *dn)
-{
- return;
-}
-#endif
-
/**
* of_attach_node - Plug a device node into the tree and global list.
*/
@@ -1712,24 +1890,13 @@ int of_attach_node(struct device_node *np)
np->allnext = of_allnodes;
np->parent->child = np;
of_allnodes = np;
+ of_node_clear_flag(np, OF_DETACHED);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
- of_add_proc_dt_entry(np);
+ of_node_add(np);
return 0;
}
-#ifdef CONFIG_PROC_DEVICETREE
-static void of_remove_proc_dt_entry(struct device_node *dn)
-{
- proc_remove(dn->pde);
-}
-#else
-static void of_remove_proc_dt_entry(struct device_node *dn)
-{
- return;
-}
-#endif
-
/**
* of_detach_node - "Unplug" a node from the device tree.
*
@@ -1785,7 +1952,7 @@ int of_detach_node(struct device_node *np)
of_node_set_flag(np, OF_DETACHED);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
- of_remove_proc_dt_entry(np);
+ of_node_remove(np);
return rc;
}
#endif /* defined(CONFIG_OF_DYNAMIC) */
@@ -1821,9 +1988,9 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
of_chosen = of_find_node_by_path("/chosen@0");
if (of_chosen) {
- const char *name;
-
- name = of_get_property(of_chosen, "linux,stdout-path", NULL);
+ const char *name = of_get_property(of_chosen, "stdout-path", NULL);
+ if (!name)
+ name = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (name)
of_stdout = of_find_node_by_path(name);
}
@@ -1984,3 +2151,153 @@ struct device_node *of_find_next_cache_node(const struct device_node *np)
return NULL;
}
+
+/**
+ * of_graph_parse_endpoint() - parse common endpoint node properties
+ * @node: pointer to endpoint device_node
+ * @endpoint: pointer to the OF endpoint data structure
+ *
+ * The caller should hold a reference to @node.
+ */
+int of_graph_parse_endpoint(const struct device_node *node,
+ struct of_endpoint *endpoint)
+{
+ struct device_node *port_node = of_get_parent(node);
+
+ WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n",
+ __func__, node->full_name);
+
+ memset(endpoint, 0, sizeof(*endpoint));
+
+ endpoint->local_node = node;
+ /*
+ * It doesn't matter whether the two calls below succeed.
+ * If they don't then the default value 0 is used.
+ */
+ of_property_read_u32(port_node, "reg", &endpoint->port);
+ of_property_read_u32(node, "reg", &endpoint->id);
+
+ of_node_put(port_node);
+
+ return 0;
+}
+EXPORT_SYMBOL(of_graph_parse_endpoint);
+
+/**
+ * of_graph_get_next_endpoint() - get next endpoint node
+ * @parent: pointer to the parent device node
+ * @prev: previous endpoint node, or NULL to get first
+ *
+ * Return: An 'endpoint' node pointer with refcount incremented. Refcount
+ * of the passed @prev node is not decremented, the caller have to use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
+ struct device_node *prev)
+{
+ struct device_node *endpoint;
+ struct device_node *port = NULL;
+
+ if (!parent)
+ return NULL;
+
+ if (!prev) {
+ struct device_node *node;
+ /*
+ * It's the first call, we have to find a port subnode
+ * within this node or within an optional 'ports' node.
+ */
+ node = of_get_child_by_name(parent, "ports");
+ if (node)
+ parent = node;
+
+ port = of_get_child_by_name(parent, "port");
+
+ if (port) {
+ /* Found a port, get an endpoint. */
+ endpoint = of_get_next_child(port, NULL);
+ of_node_put(port);
+ } else {
+ endpoint = NULL;
+ }
+
+ if (!endpoint)
+ pr_err("%s(): no endpoint nodes specified for %s\n",
+ __func__, parent->full_name);
+ of_node_put(node);
+
+ return endpoint;
+ }
+
+ port = of_get_parent(prev);
+ if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n",
+ __func__, prev->full_name))
+ return NULL;
+
+ /* Avoid dropping prev node refcount to 0. */
+ of_node_get(prev);
+ endpoint = of_get_next_child(port, prev);
+ if (endpoint) {
+ of_node_put(port);
+ return endpoint;
+ }
+
+ /* No more endpoints under this port, try the next one. */
+ do {
+ port = of_get_next_child(parent, port);
+ if (!port)
+ return NULL;
+ } while (of_node_cmp(port->name, "port"));
+
+ /* Pick up the first endpoint in this port. */
+ endpoint = of_get_next_child(port, NULL);
+ of_node_put(port);
+
+ return endpoint;
+}
+EXPORT_SYMBOL(of_graph_get_next_endpoint);
+
+/**
+ * of_graph_get_remote_port_parent() - get remote port's parent node
+ * @node: pointer to a local endpoint device_node
+ *
+ * Return: Remote device node associated with remote endpoint node linked
+ * to @node. Use of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_remote_port_parent(
+ const struct device_node *node)
+{
+ struct device_node *np;
+ unsigned int depth;
+
+ /* Get remote endpoint node. */
+ np = of_parse_phandle(node, "remote-endpoint", 0);
+
+ /* Walk 3 levels up only if there is 'ports' node. */
+ for (depth = 3; depth && np; depth--) {
+ np = of_get_next_parent(np);
+ if (depth == 2 && of_node_cmp(np->name, "ports"))
+ break;
+ }
+ return np;
+}
+EXPORT_SYMBOL(of_graph_get_remote_port_parent);
+
+/**
+ * of_graph_get_remote_port() - get remote port node
+ * @node: pointer to a local endpoint device_node
+ *
+ * Return: Remote port node associated with remote endpoint node linked
+ * to @node. Use of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_remote_port(const struct device_node *node)
+{
+ struct device_node *np;
+
+ /* Get remote endpoint node. */
+ np = of_parse_phandle(node, "remote-endpoint", 0);
+ if (!np)
+ return NULL;
+ return of_get_next_parent(np);
+}
+EXPORT_SYMBOL(of_graph_get_remote_port);
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 758b4f8b30b7..fa16a912a927 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -15,6 +15,8 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/sizes.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -202,6 +204,7 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
__alignof__(struct device_node));
if (allnextpp) {
char *fn;
+ of_node_init(np);
np->full_name = fn = ((char *)np) + sizeof(*np);
if (new_format) {
/* rebuild full path for new format */
@@ -232,7 +235,6 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
dad->next->sibling = np;
dad->next = np;
}
- kref_init(&np->kref);
}
/* process properties */
while (1) {
@@ -440,6 +442,129 @@ struct boot_param_header *initial_boot_params;
#ifdef CONFIG_OF_EARLY_FLATTREE
/**
+ * res_mem_reserve_reg() - reserve all memory described in 'reg' property
+ */
+static int __init __reserved_mem_reserve_reg(unsigned long node,
+ const char *uname)
+{
+ int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
+ phys_addr_t base, size;
+ unsigned long len;
+ __be32 *prop;
+ int nomap, first = 1;
+
+ prop = of_get_flat_dt_prop(node, "reg", &len);
+ if (!prop)
+ return -ENOENT;
+
+ if (len && len % t_len != 0) {
+ pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
+ uname);
+ return -EINVAL;
+ }
+
+ nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
+
+ while (len >= t_len) {
+ base = dt_mem_next_cell(dt_root_addr_cells, &prop);
+ size = dt_mem_next_cell(dt_root_size_cells, &prop);
+
+ if (base && size &&
+ early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
+ pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
+ uname, &base, (unsigned long)size / SZ_1M);
+ else
+ pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n",
+ uname, &base, (unsigned long)size / SZ_1M);
+
+ len -= t_len;
+ if (first) {
+ fdt_reserved_mem_save_node(node, uname, base, size);
+ first = 0;
+ }
+ }
+ return 0;
+}
+
+/**
+ * __reserved_mem_check_root() - check if #size-cells, #address-cells provided
+ * in /reserved-memory matches the values supported by the current implementation,
+ * also check if ranges property has been provided
+ */
+static int __reserved_mem_check_root(unsigned long node)
+{
+ __be32 *prop;
+
+ prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
+ if (!prop || be32_to_cpup(prop) != dt_root_size_cells)
+ return -EINVAL;
+
+ prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
+ if (!prop || be32_to_cpup(prop) != dt_root_addr_cells)
+ return -EINVAL;
+
+ prop = of_get_flat_dt_prop(node, "ranges", NULL);
+ if (!prop)
+ return -EINVAL;
+ return 0;
+}
+
+/**
+ * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
+ */
+static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ static int found;
+ const char *status;
+ int err;
+
+ if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) {
+ if (__reserved_mem_check_root(node) != 0) {
+ pr_err("Reserved memory: unsupported node format, ignoring\n");
+ /* break scan */
+ return 1;
+ }
+ found = 1;
+ /* scan next node */
+ return 0;
+ } else if (!found) {
+ /* scan next node */
+ return 0;
+ } else if (found && depth < 2) {
+ /* scanning of /reserved-memory has been finished */
+ return 1;
+ }
+
+ status = of_get_flat_dt_prop(node, "status", NULL);
+ if (status && strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0)
+ return 0;
+
+ err = __reserved_mem_reserve_reg(node, uname);
+ if (err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL))
+ fdt_reserved_mem_save_node(node, uname, 0, 0);
+
+ /* scan next node */
+ return 0;
+}
+
+/**
+ * early_init_fdt_scan_reserved_mem() - create reserved memory regions
+ *
+ * This function grabs memory from early allocator for device exclusive use
+ * defined in device tree structures. It should be called by arch specific code
+ * once the early allocator (i.e. memblock) has been fully activated.
+ */
+void __init early_init_fdt_scan_reserved_mem(void)
+{
+ if (!initial_boot_params)
+ return;
+
+ of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
+ fdt_init_reserved_mem();
+}
+
+/**
* of_scan_flat_dt - scan flattened tree blob and call callback on each.
* @it: callback function
* @data: context data pointer
@@ -856,6 +981,16 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
memblock_add(base, size);
}
+int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
+ phys_addr_t size, bool nomap)
+{
+ if (memblock_is_region_reserved(base, size))
+ return -EBUSY;
+ if (nomap)
+ return memblock_remove(base, size);
+ return memblock_reserve(base, size);
+}
+
/*
* called from unflatten_device_tree() to bootstrap devicetree itself
* Architectures can override this definition if memblock isn't used
@@ -864,6 +999,14 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
return __va(memblock_alloc(size, align));
}
+#else
+int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
+ phys_addr_t size, bool nomap)
+{
+ pr_err("Reserved memory not supported, ignoring range 0x%llx - 0x%llx%s\n",
+ base, size, nomap ? " (nomap)" : "");
+ return -ENOSYS;
+}
#endif
bool __init early_init_dt_scan(void *params)
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 875b7b6f0d2a..5b3c24f3cde5 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -24,7 +24,11 @@ MODULE_LICENSE("GPL");
static void of_set_phy_supported(struct phy_device *phydev, u32 max_speed)
{
- phydev->supported |= PHY_DEFAULT_FEATURES;
+ /* The default values for phydev->supported are provided by the PHY
+ * driver "features" member, we want to reset to sane defaults fist
+ * before supporting higher speeds.
+ */
+ phydev->supported &= PHY_DEFAULT_FEATURES;
switch (max_speed) {
default:
@@ -44,7 +48,7 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi
{
struct phy_device *phy;
bool is_c45;
- int rc, prev_irq;
+ int rc;
u32 max_speed = 0;
is_c45 = of_device_is_compatible(child,
@@ -54,12 +58,14 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi
if (!phy || IS_ERR(phy))
return 1;
- if (mdio->irq) {
- prev_irq = mdio->irq[addr];
- mdio->irq[addr] =
- irq_of_parse_and_map(child, 0);
- if (!mdio->irq[addr])
- mdio->irq[addr] = prev_irq;
+ rc = irq_of_parse_and_map(child, 0);
+ if (rc > 0) {
+ phy->irq = rc;
+ if (mdio->irq)
+ mdio->irq[addr] = rc;
+ } else {
+ if (mdio->irq)
+ phy->irq = mdio->irq[addr];
}
/* Associate the OF node with the device structure so it
diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c
index a208a457558c..a3df3428dac6 100644
--- a/drivers/of/of_net.c
+++ b/drivers/of/of_net.c
@@ -13,8 +13,8 @@
/**
* It maps 'enum phy_interface_t' found in include/linux/phy.h
- * into the device tree binding of 'phy-mode', so that Ethernet
- * device driver can get phy interface from device tree.
+ * into the device tree binding of 'phy-mode' or 'phy-connection-type',
+ * so that Ethernet device driver can get phy interface from device tree.
*/
static const char *phy_modes[] = {
[PHY_INTERFACE_MODE_NA] = "",
@@ -37,8 +37,9 @@ static const char *phy_modes[] = {
* of_get_phy_mode - Get phy mode for given device_node
* @np: Pointer to the given device_node
*
- * The function gets phy interface string from property 'phy-mode',
- * and return its index in phy_modes table, or errno in error case.
+ * The function gets phy interface string from property 'phy-mode' or
+ * 'phy-connection-type', and return its index in phy_modes table, or errno in
+ * error case.
*/
int of_get_phy_mode(struct device_node *np)
{
@@ -47,6 +48,8 @@ int of_get_phy_mode(struct device_node *np)
err = of_property_read_string(np, "phy-mode", &pm);
if (err < 0)
+ err = of_property_read_string(np, "phy-connection-type", &pm);
+ if (err < 0)
return err;
for (i = 0; i < ARRAY_SIZE(phy_modes); i++)
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
new file mode 100644
index 000000000000..daaaf935911d
--- /dev/null
+++ b/drivers/of/of_reserved_mem.c
@@ -0,0 +1,217 @@
+/*
+ * Device tree based initialization code for reserved memory.
+ *
+ * Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
+ * Copyright (c) 2013,2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ * Author: Marek Szyprowski <m.szyprowski@samsung.com>
+ * Author: Josh Cartwright <joshc@codeaurora.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 optional) any later version of the license.
+ */
+
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <linux/mm.h>
+#include <linux/sizes.h>
+#include <linux/of_reserved_mem.h>
+
+#define MAX_RESERVED_REGIONS 16
+static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
+static int reserved_mem_count;
+
+#if defined(CONFIG_HAVE_MEMBLOCK)
+#include <linux/memblock.h>
+int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
+ phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
+ phys_addr_t *res_base)
+{
+ /*
+ * We use __memblock_alloc_base() because memblock_alloc_base()
+ * panic()s on allocation failure.
+ */
+ phys_addr_t base = __memblock_alloc_base(size, align, end);
+ if (!base)
+ return -ENOMEM;
+
+ /*
+ * Check if the allocated region fits in to start..end window
+ */
+ if (base < start) {
+ memblock_free(base, size);
+ return -ENOMEM;
+ }
+
+ *res_base = base;
+ if (nomap)
+ return memblock_remove(base, size);
+ return 0;
+}
+#else
+int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
+ phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
+ phys_addr_t *res_base)
+{
+ pr_err("Reserved memory not supported, ignoring region 0x%llx%s\n",
+ size, nomap ? " (nomap)" : "");
+ return -ENOSYS;
+}
+#endif
+
+/**
+ * res_mem_save_node() - save fdt node for second pass initialization
+ */
+void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
+ phys_addr_t base, phys_addr_t size)
+{
+ struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
+
+ if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) {
+ pr_err("Reserved memory: not enough space all defined regions.\n");
+ return;
+ }
+
+ rmem->fdt_node = node;
+ rmem->name = uname;
+ rmem->base = base;
+ rmem->size = size;
+
+ reserved_mem_count++;
+ return;
+}
+
+/**
+ * res_mem_alloc_size() - allocate reserved memory described by 'size', 'align'
+ * and 'alloc-ranges' properties
+ */
+static int __init __reserved_mem_alloc_size(unsigned long node,
+ const char *uname, phys_addr_t *res_base, phys_addr_t *res_size)
+{
+ int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
+ phys_addr_t start = 0, end = 0;
+ phys_addr_t base = 0, align = 0, size;
+ unsigned long len;
+ __be32 *prop;
+ int nomap;
+ int ret;
+
+ prop = of_get_flat_dt_prop(node, "size", &len);
+ if (!prop)
+ return -EINVAL;
+
+ if (len != dt_root_size_cells * sizeof(__be32)) {
+ pr_err("Reserved memory: invalid size property in '%s' node.\n",
+ uname);
+ return -EINVAL;
+ }
+ size = dt_mem_next_cell(dt_root_size_cells, &prop);
+
+ nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
+
+ prop = of_get_flat_dt_prop(node, "alignment", &len);
+ if (prop) {
+ if (len != dt_root_addr_cells * sizeof(__be32)) {
+ pr_err("Reserved memory: invalid alignment property in '%s' node.\n",
+ uname);
+ return -EINVAL;
+ }
+ align = dt_mem_next_cell(dt_root_addr_cells, &prop);
+ }
+
+ prop = of_get_flat_dt_prop(node, "alloc-ranges", &len);
+ if (prop) {
+
+ if (len % t_len != 0) {
+ pr_err("Reserved memory: invalid alloc-ranges property in '%s', skipping node.\n",
+ uname);
+ return -EINVAL;
+ }
+
+ base = 0;
+
+ while (len > 0) {
+ start = dt_mem_next_cell(dt_root_addr_cells, &prop);
+ end = start + dt_mem_next_cell(dt_root_size_cells,
+ &prop);
+
+ ret = early_init_dt_alloc_reserved_memory_arch(size,
+ align, start, end, nomap, &base);
+ if (ret == 0) {
+ pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
+ uname, &base,
+ (unsigned long)size / SZ_1M);
+ break;
+ }
+ len -= t_len;
+ }
+
+ } else {
+ ret = early_init_dt_alloc_reserved_memory_arch(size, align,
+ 0, 0, nomap, &base);
+ if (ret == 0)
+ pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
+ uname, &base, (unsigned long)size / SZ_1M);
+ }
+
+ if (base == 0) {
+ pr_info("Reserved memory: failed to allocate memory for node '%s'\n",
+ uname);
+ return -ENOMEM;
+ }
+
+ *res_base = base;
+ *res_size = size;
+
+ return 0;
+}
+
+static const struct of_device_id __rmem_of_table_sentinel
+ __used __section(__reservedmem_of_table_end);
+
+/**
+ * res_mem_init_node() - call region specific reserved memory init code
+ */
+static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
+{
+ extern const struct of_device_id __reservedmem_of_table[];
+ const struct of_device_id *i;
+
+ for (i = __reservedmem_of_table; i < &__rmem_of_table_sentinel; i++) {
+ reservedmem_of_init_fn initfn = i->data;
+ const char *compat = i->compatible;
+
+ if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))
+ continue;
+
+ if (initfn(rmem, rmem->fdt_node, rmem->name) == 0) {
+ pr_info("Reserved memory: initialized node %s, compatible id %s\n",
+ rmem->name, compat);
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+/**
+ * fdt_init_reserved_mem - allocate and init all saved reserved memory regions
+ */
+void __init fdt_init_reserved_mem(void)
+{
+ int i;
+ for (i = 0; i < reserved_mem_count; i++) {
+ struct reserved_mem *rmem = &reserved_mem[i];
+ unsigned long node = rmem->fdt_node;
+ int err = 0;
+
+ if (rmem->size == 0)
+ err = __reserved_mem_alloc_size(node, rmem->name,
+ &rmem->base, &rmem->size);
+ if (err == 0)
+ __reserved_mem_init_node(rmem);
+ }
+}
diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c
index 7b666736c168..36b4035881b0 100644
--- a/drivers/of/pdt.c
+++ b/drivers/of/pdt.c
@@ -176,11 +176,10 @@ static struct device_node * __init of_pdt_create_node(phandle node,
return NULL;
dp = prom_early_alloc(sizeof(*dp));
+ of_node_init(dp);
of_pdt_incr_unique_id(dp);
dp->parent = parent;
- kref_init(&dp->kref);
-
dp->name = of_pdt_get_one_property(node, "name");
dp->type = of_pdt_get_one_property(node, "device_type");
dp->phandle = node;
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c
index e21012bde639..ae4450070503 100644
--- a/drivers/of/selftest.c
+++ b/drivers/of/selftest.c
@@ -30,6 +30,67 @@ static struct selftest_results {
} \
}
+static void __init of_selftest_dynamic(void)
+{
+ struct device_node *np;
+ struct property *prop;
+
+ np = of_find_node_by_path("/testcase-data");
+ if (!np) {
+ pr_err("missing testcase data\n");
+ return;
+ }
+
+ /* Array of 4 properties for the purpose of testing */
+ prop = kzalloc(sizeof(*prop) * 4, GFP_KERNEL);
+ if (!prop) {
+ selftest(0, "kzalloc() failed\n");
+ return;
+ }
+
+ /* Add a new property - should pass*/
+ prop->name = "new-property";
+ prop->value = "new-property-data";
+ prop->length = strlen(prop->value);
+ selftest(of_add_property(np, prop) == 0, "Adding a new property failed\n");
+
+ /* Try to add an existing property - should fail */
+ prop++;
+ prop->name = "new-property";
+ prop->value = "new-property-data-should-fail";
+ prop->length = strlen(prop->value);
+ selftest(of_add_property(np, prop) != 0,
+ "Adding an existing property should have failed\n");
+
+ /* Try to modify an existing property - should pass */
+ prop->value = "modify-property-data-should-pass";
+ prop->length = strlen(prop->value);
+ selftest(of_update_property(np, prop) == 0,
+ "Updating an existing property should have passed\n");
+
+ /* Try to modify non-existent property - should pass*/
+ prop++;
+ prop->name = "modify-property";
+ prop->value = "modify-missing-property-data-should-pass";
+ prop->length = strlen(prop->value);
+ selftest(of_update_property(np, prop) == 0,
+ "Updating a missing property should have passed\n");
+
+ /* Remove property - should pass */
+ selftest(of_remove_property(np, prop) == 0,
+ "Removing a property should have passed\n");
+
+ /* Adding very large property - should pass */
+ prop++;
+ prop->name = "large-property-PAGE_SIZEx8";
+ prop->length = PAGE_SIZE * 8;
+ prop->value = kzalloc(prop->length, GFP_KERNEL);
+ selftest(prop->value != NULL, "Unable to allocate large buffer\n");
+ if (prop->value)
+ selftest(of_add_property(np, prop) == 0,
+ "Adding a large property should have passed\n");
+}
+
static void __init of_selftest_parse_phandle_with_args(void)
{
struct device_node *np;
@@ -300,6 +361,72 @@ static void __init of_selftest_parse_interrupts_extended(void)
of_node_put(np);
}
+static struct of_device_id match_node_table[] = {
+ { .data = "A", .name = "name0", }, /* Name alone is lowest priority */
+ { .data = "B", .type = "type1", }, /* followed by type alone */
+
+ { .data = "Ca", .name = "name2", .type = "type1", }, /* followed by both together */
+ { .data = "Cb", .name = "name2", }, /* Only match when type doesn't match */
+ { .data = "Cc", .name = "name2", .type = "type2", },
+
+ { .data = "E", .compatible = "compat3" },
+ { .data = "G", .compatible = "compat2", },
+ { .data = "H", .compatible = "compat2", .name = "name5", },
+ { .data = "I", .compatible = "compat2", .type = "type1", },
+ { .data = "J", .compatible = "compat2", .type = "type1", .name = "name8", },
+ { .data = "K", .compatible = "compat2", .name = "name9", },
+ {}
+};
+
+static struct {
+ const char *path;
+ const char *data;
+} match_node_tests[] = {
+ { .path = "/testcase-data/match-node/name0", .data = "A", },
+ { .path = "/testcase-data/match-node/name1", .data = "B", },
+ { .path = "/testcase-data/match-node/a/name2", .data = "Ca", },
+ { .path = "/testcase-data/match-node/b/name2", .data = "Cb", },
+ { .path = "/testcase-data/match-node/c/name2", .data = "Cc", },
+ { .path = "/testcase-data/match-node/name3", .data = "E", },
+ { .path = "/testcase-data/match-node/name4", .data = "G", },
+ { .path = "/testcase-data/match-node/name5", .data = "H", },
+ { .path = "/testcase-data/match-node/name6", .data = "G", },
+ { .path = "/testcase-data/match-node/name7", .data = "I", },
+ { .path = "/testcase-data/match-node/name8", .data = "J", },
+ { .path = "/testcase-data/match-node/name9", .data = "K", },
+};
+
+static void __init of_selftest_match_node(void)
+{
+ struct device_node *np;
+ const struct of_device_id *match;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(match_node_tests); i++) {
+ np = of_find_node_by_path(match_node_tests[i].path);
+ if (!np) {
+ selftest(0, "missing testcase node %s\n",
+ match_node_tests[i].path);
+ continue;
+ }
+
+ match = of_match_node(match_node_table, np);
+ if (!match) {
+ selftest(0, "%s didn't match anything\n",
+ match_node_tests[i].path);
+ continue;
+ }
+
+ if (strcmp(match->data, match_node_tests[i].data) != 0) {
+ selftest(0, "%s got wrong match. expected %s, got %s\n",
+ match_node_tests[i].path, match_node_tests[i].data,
+ (const char *)match->data);
+ continue;
+ }
+ selftest(1, "passed");
+ }
+}
+
static int __init of_selftest(void)
{
struct device_node *np;
@@ -312,10 +439,12 @@ static int __init of_selftest(void)
of_node_put(np);
pr_info("start of selftest - you will see error messages\n");
+ of_selftest_dynamic();
of_selftest_parse_phandle_with_args();
of_selftest_property_match_string();
of_selftest_parse_interrupts();
of_selftest_parse_interrupts_extended();
+ of_selftest_match_node();
pr_info("end of selftest - %i passed, %i failed\n",
selftest_results.passed, selftest_results.failed);
return 0;
diff --git a/drivers/of/testcase-data/testcases.dtsi b/drivers/of/testcase-data/testcases.dtsi
new file mode 100644
index 000000000000..3a5b75a8e4d7
--- /dev/null
+++ b/drivers/of/testcase-data/testcases.dtsi
@@ -0,0 +1,3 @@
+#include "tests-phandle.dtsi"
+#include "tests-interrupts.dtsi"
+#include "tests-match.dtsi"
diff --git a/arch/arm/boot/dts/testcases/tests-interrupts.dtsi b/drivers/of/testcase-data/tests-interrupts.dtsi
index c843720bd3e5..c843720bd3e5 100644
--- a/arch/arm/boot/dts/testcases/tests-interrupts.dtsi
+++ b/drivers/of/testcase-data/tests-interrupts.dtsi
diff --git a/drivers/of/testcase-data/tests-match.dtsi b/drivers/of/testcase-data/tests-match.dtsi
new file mode 100644
index 000000000000..c9e541129534
--- /dev/null
+++ b/drivers/of/testcase-data/tests-match.dtsi
@@ -0,0 +1,19 @@
+
+/ {
+ testcase-data {
+ match-node {
+ name0 { };
+ name1 { device_type = "type1"; };
+ a { name2 { device_type = "type1"; }; };
+ b { name2 { }; };
+ c { name2 { device_type = "type2"; }; };
+ name3 { compatible = "compat3"; };
+ name4 { compatible = "compat2", "compat3"; };
+ name5 { compatible = "compat2", "compat3"; };
+ name6 { compatible = "compat1", "compat2", "compat3"; };
+ name7 { compatible = "compat2"; device_type = "type1"; };
+ name8 { compatible = "compat2"; device_type = "type1"; };
+ name9 { compatible = "compat2"; };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/testcases/tests-phandle.dtsi b/drivers/of/testcase-data/tests-phandle.dtsi
index 0007d3cd7dc2..788a4c24b8f5 100644
--- a/arch/arm/boot/dts/testcases/tests-phandle.dtsi
+++ b/drivers/of/testcase-data/tests-phandle.dtsi
@@ -1,6 +1,9 @@
/ {
testcase-data {
+ security-password = "password";
+ duplicate-name = "duplicate";
+ duplicate-name { };
phandle-tests {
provider0: provider0 {
#phandle-cells = <0>;
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index 6a83ee1e9178..3fa66244ce32 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -905,7 +905,8 @@ int parport_claim_or_block(struct pardevice *dev)
/* If dev->waiting is clear now, an interrupt
gave us the port and we would deadlock if we slept. */
if (dev->waiting) {
- interruptible_sleep_on (&dev->wait_q);
+ wait_event_interruptible(dev->wait_q,
+ !dev->waiting);
if (signal_pending (current)) {
return -EINTR;
}
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 17d2b07ee67c..e04fe2d9df3b 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -33,21 +33,14 @@ obj-$(CONFIG_PCI_IOV) += iov.o
#
# Some architectures use the generic PCI setup functions
#
-obj-$(CONFIG_X86) += setup-bus.o
-obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o
-obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
-obj-$(CONFIG_UNICORE32) += setup-bus.o setup-irq.o
-obj-$(CONFIG_PARISC) += setup-bus.o
-obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
-obj-$(CONFIG_PPC) += setup-bus.o
-obj-$(CONFIG_FRV) += setup-bus.o
-obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
-obj-$(CONFIG_X86_VISWS) += setup-irq.o
-obj-$(CONFIG_MN10300) += setup-bus.o
-obj-$(CONFIG_MICROBLAZE) += setup-bus.o
-obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o
-obj-$(CONFIG_SPARC_LEON) += setup-bus.o setup-irq.o
-obj-$(CONFIG_M68K) += setup-bus.o setup-irq.o
+obj-$(CONFIG_ALPHA) += setup-irq.o
+obj-$(CONFIG_ARM) += setup-irq.o
+obj-$(CONFIG_UNICORE32) += setup-irq.o
+obj-$(CONFIG_SUPERH) += setup-irq.o
+obj-$(CONFIG_MIPS) += setup-irq.o
+obj-$(CONFIG_TILE) += setup-irq.o
+obj-$(CONFIG_SPARC_LEON) += setup-irq.o
+obj-$(CONFIG_M68K) += setup-irq.o
#
# ACPI Related PCI FW Functions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 00660cc502c5..fb8aed307c28 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -132,7 +132,7 @@ static void pci_clip_resource_to_region(struct pci_bus *bus,
static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
resource_size_t size, resource_size_t align,
- resource_size_t min, unsigned int type_mask,
+ resource_size_t min, unsigned long type_mask,
resource_size_t (*alignf)(void *,
const struct resource *,
resource_size_t,
@@ -144,7 +144,7 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
struct resource *r, avail;
resource_size_t max;
- type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
+ type_mask |= IORESOURCE_TYPE_BITS;
pci_bus_for_each_resource(bus, r, i) {
if (!r)
@@ -162,8 +162,6 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
avail = *r;
pci_clip_resource_to_region(bus, &avail, region);
- if (!resource_size(&avail))
- continue;
/*
* "min" is typically PCIBIOS_MIN_IO or PCIBIOS_MIN_MEM to
@@ -202,7 +200,7 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
*/
int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
resource_size_t size, resource_size_t align,
- resource_size_t min, unsigned int type_mask,
+ resource_size_t min, unsigned long type_mask,
resource_size_t (*alignf)(void *,
const struct resource *,
resource_size_t,
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 06ace6248c61..47aaf22d814e 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -32,11 +32,6 @@ void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
bridge->release_data = release_data;
}
-static bool resource_contains(struct resource *res1, struct resource *res2)
-{
- return res1->start <= res2->start && res1->end >= res2->end;
-}
-
void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
struct resource *res)
{
@@ -45,9 +40,6 @@ void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
resource_size_t offset = 0;
list_for_each_entry(window, &bridge->windows, list) {
- if (resource_type(res) != resource_type(window->res))
- continue;
-
if (resource_contains(window->res, res)) {
offset = window->offset;
break;
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 47d46c6d8468..a6f67ec8882f 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -27,7 +27,7 @@ config PCI_TEGRA
config PCI_RCAR_GEN2
bool "Renesas R-Car Gen2 Internal PCI controller"
- depends on ARM && (ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST)
+ depends on ARCH_SHMOBILE || (ARM && COMPILE_TEST)
help
Say Y here if you want internal PCI support on R-Car Gen2 SoC.
There are 3 internal PCI controllers available with a single
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index e8663a8c3406..ee082509b0ba 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -424,20 +424,40 @@ static void imx6_pcie_reset_phy(struct pcie_port *pp)
static int imx6_pcie_link_up(struct pcie_port *pp)
{
- u32 rc, ltssm, rx_valid;
+ u32 rc, debug_r0, rx_valid;
+ int count = 5;
/*
- * Test if the PHY reports that the link is up and also that
- * the link training finished. It might happen that the PHY
- * reports the link is already up, but the link training bit
- * is still set, so make sure to check the training is done
- * as well here.
+ * Test if the PHY reports that the link is up and also that the LTSSM
+ * training finished. There are three possible states of the link when
+ * this code is called:
+ * 1) The link is DOWN (unlikely)
+ * The link didn't come up yet for some reason. This usually means
+ * we have a real problem somewhere. Reset the PHY and exit. This
+ * state calls for inspection of the DEBUG registers.
+ * 2) The link is UP, but still in LTSSM training
+ * Wait for the training to finish, which should take a very short
+ * time. If the training does not finish, we have a problem and we
+ * need to inspect the DEBUG registers. If the training does finish,
+ * the link is up and operating correctly.
+ * 3) The link is UP and no longer in LTSSM training
+ * The link is up and operating correctly.
*/
- rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
- if ((rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP) &&
- !(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING))
- return 1;
-
+ while (1) {
+ rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
+ if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP))
+ break;
+ if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING))
+ return 1;
+ if (!count--)
+ break;
+ dev_dbg(pp->dev, "Link is up, but still in training\n");
+ /*
+ * Wait a little bit, then re-check if the link finished
+ * the training.
+ */
+ usleep_range(1000, 2000);
+ }
/*
* From L0, initiate MAC entry to gen2 if EP/RC supports gen2.
* Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2).
@@ -446,15 +466,16 @@ static int imx6_pcie_link_up(struct pcie_port *pp)
* to gen2 is stuck
*/
pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
- ltssm = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0) & 0x3F;
+ debug_r0 = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0);
if (rx_valid & 0x01)
return 0;
- if (ltssm != 0x0d)
+ if ((debug_r0 & 0x3f) != 0x0d)
return 0;
dev_err(pp->dev, "transition to gen2 is stuck, reset PHY!\n");
+ dev_dbg(pp->dev, "debug_r0=%08x debug_r1=%08x\n", debug_r0, rc);
imx6_pcie_reset_phy(pp);
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
index 13478ecd4113..d3d1cfd51e09 100644
--- a/drivers/pci/host/pci-mvebu.c
+++ b/drivers/pci/host/pci-mvebu.c
@@ -60,14 +60,6 @@
#define PCIE_DEBUG_CTRL 0x1a60
#define PCIE_DEBUG_SOFT_RESET BIT(20)
-/*
- * This product ID is registered by Marvell, and used when the Marvell
- * SoC is not the root complex, but an endpoint on the PCIe bus. It is
- * therefore safe to re-use this PCI ID for our emulated PCI-to-PCI
- * bridge.
- */
-#define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 0x7846
-
/* PCI configuration space of a PCI-to-PCI bridge */
struct mvebu_sw_pci_bridge {
u16 vendor;
@@ -109,7 +101,9 @@ struct mvebu_pcie {
struct mvebu_pcie_port *ports;
struct msi_chip *msi;
struct resource io;
+ char io_name[30];
struct resource realio;
+ char mem_name[30];
struct resource mem;
struct resource busn;
int nports;
@@ -388,7 +382,8 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
bridge->class = PCI_CLASS_BRIDGE_PCI;
bridge->vendor = PCI_VENDOR_ID_MARVELL;
- bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID;
+ bridge->device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16;
+ bridge->revision = mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff;
bridge->header_type = PCI_HEADER_TYPE_BRIDGE;
bridge->cache_line_size = 0x10;
@@ -679,10 +674,30 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
{
struct mvebu_pcie *pcie = sys_to_pcie(sys);
int i;
+ int domain = 0;
+
+#ifdef CONFIG_PCI_DOMAINS
+ domain = sys->domain;
+#endif
+
+ snprintf(pcie->mem_name, sizeof(pcie->mem_name), "PCI MEM %04x",
+ domain);
+ pcie->mem.name = pcie->mem_name;
- if (resource_size(&pcie->realio) != 0)
+ snprintf(pcie->io_name, sizeof(pcie->io_name), "PCI I/O %04x", domain);
+ pcie->realio.name = pcie->io_name;
+
+ if (request_resource(&iomem_resource, &pcie->mem))
+ return 0;
+
+ if (resource_size(&pcie->realio) != 0) {
+ if (request_resource(&ioport_resource, &pcie->realio)) {
+ release_resource(&pcie->mem);
+ return 0;
+ }
pci_add_resource_offset(&sys->resources, &pcie->realio,
sys->io_offset);
+ }
pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
pci_add_resource(&sys->resources, &pcie->busn);
@@ -804,7 +819,7 @@ static int mvebu_get_tgt_attr(struct device_node *np, int devfn,
for (i = 0; i < nranges; i++) {
u32 flags = of_read_number(range, 1);
- u32 slot = of_read_number(range, 2);
+ u32 slot = of_read_number(range + 1, 1);
u64 cpuaddr = of_read_number(range + na, pna);
unsigned long rtype;
diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/host/pci-rcar-gen2.c
index ceec147baec3..fd3e3ab56509 100644
--- a/drivers/pci/host/pci-rcar-gen2.c
+++ b/drivers/pci/host/pci-rcar-gen2.c
@@ -18,6 +18,7 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/sizes.h>
#include <linux/slab.h>
/* AHB-PCI Bridge PCI communication registers */
@@ -39,9 +40,26 @@
#define RCAR_PCI_INT_ENABLE_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x20)
#define RCAR_PCI_INT_STATUS_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x24)
+#define RCAR_PCI_INT_SIGTABORT (1 << 0)
+#define RCAR_PCI_INT_SIGRETABORT (1 << 1)
+#define RCAR_PCI_INT_REMABORT (1 << 2)
+#define RCAR_PCI_INT_PERR (1 << 3)
+#define RCAR_PCI_INT_SIGSERR (1 << 4)
+#define RCAR_PCI_INT_RESERR (1 << 5)
+#define RCAR_PCI_INT_WIN1ERR (1 << 12)
+#define RCAR_PCI_INT_WIN2ERR (1 << 13)
#define RCAR_PCI_INT_A (1 << 16)
#define RCAR_PCI_INT_B (1 << 17)
#define RCAR_PCI_INT_PME (1 << 19)
+#define RCAR_PCI_INT_ALLERRORS (RCAR_PCI_INT_SIGTABORT | \
+ RCAR_PCI_INT_SIGRETABORT | \
+ RCAR_PCI_INT_SIGRETABORT | \
+ RCAR_PCI_INT_REMABORT | \
+ RCAR_PCI_INT_PERR | \
+ RCAR_PCI_INT_SIGSERR | \
+ RCAR_PCI_INT_RESERR | \
+ RCAR_PCI_INT_WIN1ERR | \
+ RCAR_PCI_INT_WIN2ERR)
#define RCAR_AHB_BUS_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x30)
#define RCAR_AHB_BUS_MMODE_HTRANS (1 << 0)
@@ -74,9 +92,6 @@
#define RCAR_PCI_UNIT_REV_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x48)
-/* Number of internal PCI controllers */
-#define RCAR_PCI_NR_CONTROLLERS 3
-
struct rcar_pci_priv {
struct device *dev;
void __iomem *reg;
@@ -84,6 +99,7 @@ struct rcar_pci_priv {
struct resource mem_res;
struct resource *cfg_res;
int irq;
+ unsigned long window_size;
};
/* PCI configuration space operations */
@@ -102,6 +118,10 @@ static void __iomem *rcar_pci_cfg_base(struct pci_bus *bus, unsigned int devfn,
if (slot > 2)
return NULL;
+ /* bridge logic only has registers to 0x40 */
+ if (slot == 0x0 && where >= 0x40)
+ return NULL;
+
val = slot ? RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG :
RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG;
@@ -156,7 +176,7 @@ static int rcar_pci_write_config(struct pci_bus *bus, unsigned int devfn,
}
/* PCI interrupt mapping */
-static int __init rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
struct pci_sys_data *sys = dev->bus->sysdata;
struct rcar_pci_priv *priv = sys->private_data;
@@ -164,8 +184,48 @@ static int __init rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
return priv->irq;
}
+#ifdef CONFIG_PCI_DEBUG
+/* if debug enabled, then attach an error handler irq to the bridge */
+
+static irqreturn_t rcar_pci_err_irq(int irq, void *pw)
+{
+ struct rcar_pci_priv *priv = pw;
+ u32 status = ioread32(priv->reg + RCAR_PCI_INT_STATUS_REG);
+
+ if (status & RCAR_PCI_INT_ALLERRORS) {
+ dev_err(priv->dev, "error irq: status %08x\n", status);
+
+ /* clear the error(s) */
+ iowrite32(status & RCAR_PCI_INT_ALLERRORS,
+ priv->reg + RCAR_PCI_INT_STATUS_REG);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static void rcar_pci_setup_errirq(struct rcar_pci_priv *priv)
+{
+ int ret;
+ u32 val;
+
+ ret = devm_request_irq(priv->dev, priv->irq, rcar_pci_err_irq,
+ IRQF_SHARED, "error irq", priv);
+ if (ret) {
+ dev_err(priv->dev, "cannot claim IRQ for error handling\n");
+ return;
+ }
+
+ val = ioread32(priv->reg + RCAR_PCI_INT_ENABLE_REG);
+ val |= RCAR_PCI_INT_ALLERRORS;
+ iowrite32(val, priv->reg + RCAR_PCI_INT_ENABLE_REG);
+}
+#else
+static inline void rcar_pci_setup_errirq(struct rcar_pci_priv *priv) { }
+#endif
+
/* PCI host controller setup */
-static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
+static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
{
struct rcar_pci_priv *priv = sys->private_data;
void __iomem *reg = priv->reg;
@@ -183,10 +243,31 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
iowrite32(val, reg + RCAR_USBCTR_REG);
udelay(4);
- /* De-assert reset and set PCIAHB window1 size to 1GB */
+ /* De-assert reset and reset PCIAHB window1 size */
val &= ~(RCAR_USBCTR_PCIAHB_WIN1_MASK | RCAR_USBCTR_PCICLK_MASK |
RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST);
- iowrite32(val | RCAR_USBCTR_PCIAHB_WIN1_1G, reg + RCAR_USBCTR_REG);
+
+ /* Setup PCIAHB window1 size */
+ switch (priv->window_size) {
+ case SZ_2G:
+ val |= RCAR_USBCTR_PCIAHB_WIN1_2G;
+ break;
+ case SZ_1G:
+ val |= RCAR_USBCTR_PCIAHB_WIN1_1G;
+ break;
+ case SZ_512M:
+ val |= RCAR_USBCTR_PCIAHB_WIN1_512M;
+ break;
+ default:
+ pr_warn("unknown window size %ld - defaulting to 256M\n",
+ priv->window_size);
+ priv->window_size = SZ_256M;
+ /* fall-through */
+ case SZ_256M:
+ val |= RCAR_USBCTR_PCIAHB_WIN1_256M;
+ break;
+ }
+ iowrite32(val, reg + RCAR_USBCTR_REG);
/* Configure AHB master and slave modes */
iowrite32(RCAR_AHB_BUS_MODE, reg + RCAR_AHB_BUS_CTR_REG);
@@ -197,7 +278,7 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
RCAR_PCI_ARBITER_PCIBP_MODE;
iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);
- /* PCI-AHB mapping: 0x40000000-0x80000000 */
+ /* PCI-AHB mapping: 0x40000000 base */
iowrite32(0x40000000 | RCAR_PCIAHB_PREFETCH16,
reg + RCAR_PCIAHB_WIN1_CTR_REG);
@@ -224,10 +305,15 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME,
reg + RCAR_PCI_INT_ENABLE_REG);
+ if (priv->irq > 0)
+ rcar_pci_setup_errirq(priv);
+
/* Add PCI resources */
pci_add_resource(&sys->resources, &priv->io_res);
pci_add_resource(&sys->resources, &priv->mem_res);
+ /* Setup bus number based on platform device id */
+ sys->busnr = to_platform_device(priv->dev)->id;
return 1;
}
@@ -236,48 +322,13 @@ static struct pci_ops rcar_pci_ops = {
.write = rcar_pci_write_config,
};
-static struct hw_pci rcar_hw_pci __initdata = {
- .map_irq = rcar_pci_map_irq,
- .ops = &rcar_pci_ops,
- .setup = rcar_pci_setup,
-};
-
-static int rcar_pci_count __initdata;
-
-static int __init rcar_pci_add_controller(struct rcar_pci_priv *priv)
-{
- void **private_data;
- int count;
-
- if (rcar_hw_pci.nr_controllers < rcar_pci_count)
- goto add_priv;
-
- /* (Re)allocate private data pointer array if needed */
- count = rcar_pci_count + RCAR_PCI_NR_CONTROLLERS;
- private_data = kzalloc(count * sizeof(void *), GFP_KERNEL);
- if (!private_data)
- return -ENOMEM;
-
- rcar_pci_count = count;
- if (rcar_hw_pci.private_data) {
- memcpy(private_data, rcar_hw_pci.private_data,
- rcar_hw_pci.nr_controllers * sizeof(void *));
- kfree(rcar_hw_pci.private_data);
- }
-
- rcar_hw_pci.private_data = private_data;
-
-add_priv:
- /* Add private data pointer to the array */
- rcar_hw_pci.private_data[rcar_hw_pci.nr_controllers++] = priv;
- return 0;
-}
-
-static int __init rcar_pci_probe(struct platform_device *pdev)
+static int rcar_pci_probe(struct platform_device *pdev)
{
struct resource *cfg_res, *mem_res;
struct rcar_pci_priv *priv;
void __iomem *reg;
+ struct hw_pci hw;
+ void *hw_private[1];
cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(&pdev->dev, cfg_res);
@@ -308,31 +359,34 @@ static int __init rcar_pci_probe(struct platform_device *pdev)
priv->reg = reg;
priv->dev = &pdev->dev;
- return rcar_pci_add_controller(priv);
+ if (priv->irq < 0) {
+ dev_err(&pdev->dev, "no valid irq found\n");
+ return priv->irq;
+ }
+
+ priv->window_size = SZ_1G;
+
+ hw_private[0] = priv;
+ memset(&hw, 0, sizeof(hw));
+ hw.nr_controllers = ARRAY_SIZE(hw_private);
+ hw.private_data = hw_private;
+ hw.map_irq = rcar_pci_map_irq;
+ hw.ops = &rcar_pci_ops;
+ hw.setup = rcar_pci_setup;
+ pci_common_init_dev(&pdev->dev, &hw);
+ return 0;
}
static struct platform_driver rcar_pci_driver = {
.driver = {
.name = "pci-rcar-gen2",
+ .owner = THIS_MODULE,
+ .suppress_bind_attrs = true,
},
+ .probe = rcar_pci_probe,
};
-static int __init rcar_pci_init(void)
-{
- int retval;
-
- retval = platform_driver_probe(&rcar_pci_driver, rcar_pci_probe);
- if (!retval)
- pci_common_init(&rcar_hw_pci);
-
- /* Private data pointer array is not needed any more */
- kfree(rcar_hw_pci.private_data);
- rcar_hw_pci.private_data = NULL;
-
- return retval;
-}
-
-subsys_initcall(rcar_pci_init);
+module_platform_driver(rcar_pci_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Renesas R-Car Gen2 internal PCI");
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 17ce88f79d2b..509a29d84509 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -294,14 +294,12 @@ no_valid_irq:
static void clear_irq(unsigned int irq)
{
unsigned int pos, nvec;
- struct irq_desc *desc;
struct msi_desc *msi;
struct pcie_port *pp;
struct irq_data *data = irq_get_irq_data(irq);
/* get the port structure */
- desc = irq_to_desc(irq);
- msi = irq_desc_get_msi_desc(desc);
+ msi = irq_data_get_msi(data);
pp = sys_to_pcie(msi->dev->bus->sysdata);
if (!pp) {
BUG();
@@ -800,7 +798,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
/* setup RC BARs */
dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_0);
- dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_1);
+ dw_pcie_writel_rc(pp, 0x00000000, PCI_BASE_ADDRESS_1);
/* setup interrupt pins */
dw_pcie_readl_rc(pp, PCI_INTERRUPT_LINE, &val);
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index b6162be4df40..2b859249303b 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -93,7 +93,6 @@ struct acpiphp_slot {
struct list_head funcs; /* one slot may have different
objects (i.e. for each function) */
struct slot *slot;
- struct mutex crit_sect;
u8 device; /* pci device# */
u32 flags; /* see below */
@@ -117,20 +116,30 @@ struct acpiphp_func {
};
struct acpiphp_context {
- acpi_handle handle;
+ struct acpi_hotplug_context hp;
struct acpiphp_func func;
struct acpiphp_bridge *bridge;
unsigned int refcount;
};
+static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp)
+{
+ return container_of(hp, struct acpiphp_context, hp);
+}
+
static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func)
{
return container_of(func, struct acpiphp_context, func);
}
+static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func)
+{
+ return func_to_context(func)->hp.self;
+}
+
static inline acpi_handle func_to_handle(struct acpiphp_func *func)
{
- return func_to_context(func)->handle;
+ return func_to_acpi_device(func)->handle;
}
/*
@@ -158,7 +167,6 @@ struct acpiphp_attention_info
#define FUNC_HAS_STA (0x00000001)
#define FUNC_HAS_EJ0 (0x00000002)
-#define FUNC_HAS_DCK (0x00000004)
/* function prototypes */
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 7c7a388c85ab..bccc27ee1030 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -58,71 +58,59 @@
static LIST_HEAD(bridge_list);
static DEFINE_MUTEX(bridge_mutex);
-static DEFINE_MUTEX(acpiphp_context_lock);
-static void handle_hotplug_event(acpi_handle handle, u32 type, void *data);
+static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type);
+static void acpiphp_post_dock_fixup(struct acpi_device *adev);
static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(struct pci_bus *bus);
-static void hotplug_event(acpi_handle handle, u32 type, void *data);
+static void hotplug_event(u32 type, struct acpiphp_context *context);
static void free_bridge(struct kref *kref);
-static void acpiphp_context_handler(acpi_handle handle, void *context)
-{
- /* Intentionally empty. */
-}
-
/**
* acpiphp_init_context - Create hotplug context and grab a reference to it.
- * @handle: ACPI object handle to create the context for.
+ * @adev: ACPI device object to create the context for.
*
- * Call under acpiphp_context_lock.
+ * Call under acpi_hp_context_lock.
*/
-static struct acpiphp_context *acpiphp_init_context(acpi_handle handle)
+static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev)
{
struct acpiphp_context *context;
- acpi_status status;
context = kzalloc(sizeof(*context), GFP_KERNEL);
if (!context)
return NULL;
- context->handle = handle;
context->refcount = 1;
- status = acpi_attach_data(handle, acpiphp_context_handler, context);
- if (ACPI_FAILURE(status)) {
- kfree(context);
- return NULL;
- }
+ acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_notify, NULL,
+ acpiphp_post_dock_fixup);
return context;
}
/**
* acpiphp_get_context - Get hotplug context and grab a reference to it.
- * @handle: ACPI object handle to get the context for.
+ * @adev: ACPI device object to get the context for.
*
- * Call under acpiphp_context_lock.
+ * Call under acpi_hp_context_lock.
*/
-static struct acpiphp_context *acpiphp_get_context(acpi_handle handle)
+static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev)
{
- struct acpiphp_context *context = NULL;
- acpi_status status;
- void *data;
+ struct acpiphp_context *context;
- status = acpi_get_data(handle, acpiphp_context_handler, &data);
- if (ACPI_SUCCESS(status)) {
- context = data;
- context->refcount++;
- }
+ if (!adev->hp)
+ return NULL;
+
+ context = to_acpiphp_context(adev->hp);
+ context->refcount++;
return context;
}
/**
* acpiphp_put_context - Drop a reference to ACPI hotplug context.
- * @handle: ACPI object handle to put the context for.
+ * @context: ACPI hotplug context to drop a reference to.
*
* The context object is removed if there are no more references to it.
*
- * Call under acpiphp_context_lock.
+ * Call under acpi_hp_context_lock.
*/
static void acpiphp_put_context(struct acpiphp_context *context)
{
@@ -130,7 +118,7 @@ static void acpiphp_put_context(struct acpiphp_context *context)
return;
WARN_ON(context->bridge);
- acpi_detach_data(context->handle, acpiphp_context_handler);
+ context->hp.self->hp = NULL;
kfree(context);
}
@@ -144,6 +132,27 @@ static inline void put_bridge(struct acpiphp_bridge *bridge)
kref_put(&bridge->ref, free_bridge);
}
+static struct acpiphp_context *acpiphp_grab_context(struct acpi_device *adev)
+{
+ struct acpiphp_context *context;
+
+ acpi_lock_hp_context();
+ context = acpiphp_get_context(adev);
+ if (!context || context->func.parent->is_going_away) {
+ acpi_unlock_hp_context();
+ return NULL;
+ }
+ get_bridge(context->func.parent);
+ acpiphp_put_context(context);
+ acpi_unlock_hp_context();
+ return context;
+}
+
+static void acpiphp_let_context_go(struct acpiphp_context *context)
+{
+ put_bridge(context->func.parent);
+}
+
static void free_bridge(struct kref *kref)
{
struct acpiphp_context *context;
@@ -151,7 +160,7 @@ static void free_bridge(struct kref *kref)
struct acpiphp_slot *slot, *next;
struct acpiphp_func *func, *tmp;
- mutex_lock(&acpiphp_context_lock);
+ acpi_lock_hp_context();
bridge = container_of(kref, struct acpiphp_bridge, ref);
@@ -175,31 +184,32 @@ static void free_bridge(struct kref *kref)
pci_dev_put(bridge->pci_dev);
kfree(bridge);
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
}
-/*
- * the _DCK method can do funny things... and sometimes not
- * hah-hah funny.
+/**
+ * acpiphp_post_dock_fixup - Post-dock fixups for PCI devices.
+ * @adev: ACPI device object corresponding to a PCI device.
*
- * TBD - figure out a way to only call fixups for
- * systems that require them.
+ * TBD - figure out a way to only call fixups for systems that require them.
*/
-static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
+static void acpiphp_post_dock_fixup(struct acpi_device *adev)
{
- struct acpiphp_context *context = data;
- struct pci_bus *bus = context->func.slot->bus;
+ struct acpiphp_context *context = acpiphp_grab_context(adev);
+ struct pci_bus *bus;
u32 buses;
- if (!bus->self)
+ if (!context)
return;
+ bus = context->func.slot->bus;
+ if (!bus->self)
+ goto out;
+
/* fixup bad _DCK function that rewrites
* secondary bridge on slot
*/
- pci_read_config_dword(bus->self,
- PCI_PRIMARY_BUS,
- &buses);
+ pci_read_config_dword(bus->self, PCI_PRIMARY_BUS, &buses);
if (((buses >> 8) & 0xff) != bus->busn_res.start) {
buses = (buses & 0xff000000)
@@ -208,33 +218,11 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
| ((unsigned int)(bus->busn_res.end) << 16);
pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
}
-}
-
-static void dock_event(acpi_handle handle, u32 type, void *data)
-{
- struct acpiphp_context *context;
-
- mutex_lock(&acpiphp_context_lock);
- context = acpiphp_get_context(handle);
- if (!context || WARN_ON(context->handle != handle)
- || context->func.parent->is_going_away) {
- mutex_unlock(&acpiphp_context_lock);
- return;
- }
- get_bridge(context->func.parent);
- acpiphp_put_context(context);
- mutex_unlock(&acpiphp_context_lock);
-
- hotplug_event(handle, type, data);
- put_bridge(context->func.parent);
+ out:
+ acpiphp_let_context_go(context);
}
-static const struct acpi_dock_ops acpiphp_dock_ops = {
- .fixup = post_dock_fixups,
- .handler = dock_event,
-};
-
/* Check whether the PCI device is managed by native PCIe hotplug driver */
static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)
{
@@ -264,26 +252,19 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)
return true;
}
-static void acpiphp_dock_init(void *data)
-{
- struct acpiphp_context *context = data;
-
- get_bridge(context->func.parent);
-}
-
-static void acpiphp_dock_release(void *data)
-{
- struct acpiphp_context *context = data;
-
- put_bridge(context->func.parent);
-}
-
-/* callback routine to register each ACPI PCI slot object */
-static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
- void **rv)
+/**
+ * acpiphp_add_context - Add ACPIPHP context to an ACPI device object.
+ * @handle: ACPI handle of the object to add a context to.
+ * @lvl: Not used.
+ * @data: The object's parent ACPIPHP bridge.
+ * @rv: Not used.
+ */
+static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data,
+ void **rv)
{
struct acpiphp_bridge *bridge = data;
struct acpiphp_context *context;
+ struct acpi_device *adev;
struct acpiphp_slot *slot;
struct acpiphp_func *newfunc;
acpi_status status = AE_OK;
@@ -293,9 +274,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
struct pci_dev *pdev = bridge->pci_dev;
u32 val;
- if (pdev && device_is_managed_by_native_pciehp(pdev))
- return AE_OK;
-
status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND)
@@ -303,31 +281,34 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
"can't evaluate _ADR (%#x)\n", status);
return AE_OK;
}
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
device = (adr >> 16) & 0xffff;
function = adr & 0xffff;
- mutex_lock(&acpiphp_context_lock);
- context = acpiphp_init_context(handle);
+ acpi_lock_hp_context();
+ context = acpiphp_init_context(adev);
if (!context) {
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
acpi_handle_err(handle, "No hotplug context\n");
return AE_NOT_EXIST;
}
newfunc = &context->func;
newfunc->function = function;
newfunc->parent = bridge;
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
- if (acpi_has_method(handle, "_EJ0"))
+ /*
+ * If this is a dock device, its _EJ0 should be executed by the dock
+ * notify handler after calling _DCK.
+ */
+ if (!is_dock_device(adev) && acpi_has_method(handle, "_EJ0"))
newfunc->flags = FUNC_HAS_EJ0;
if (acpi_has_method(handle, "_STA"))
newfunc->flags |= FUNC_HAS_STA;
- if (acpi_has_method(handle, "_DCK"))
- newfunc->flags |= FUNC_HAS_DCK;
-
/* search for objects that share the same slot */
list_for_each_entry(slot, &bridge->slots, node)
if (slot->device == device)
@@ -335,19 +316,26 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
if (!slot) {
- status = AE_NO_MEMORY;
- goto err;
+ acpi_lock_hp_context();
+ acpiphp_put_context(context);
+ acpi_unlock_hp_context();
+ return AE_NO_MEMORY;
}
slot->bus = bridge->pci_bus;
slot->device = device;
INIT_LIST_HEAD(&slot->funcs);
- mutex_init(&slot->crit_sect);
list_add_tail(&slot->node, &bridge->slots);
- /* Register slots for ejectable functions only. */
- if (acpi_pci_check_ejectable(pbus, handle) || is_dock_device(handle)) {
+ /*
+ * Expose slots to user space for functions that have _EJ0 or _RMV or
+ * are located in dock stations. Do not expose them for devices handled
+ * by the native PCIe hotplug (PCIeHP), becuase that code is supposed to
+ * expose slots to user space in those cases.
+ */
+ if ((acpi_pci_check_ejectable(pbus, handle) || is_dock_device(adev))
+ && !(pdev && device_is_managed_by_native_pciehp(pdev))) {
unsigned long long sun;
int retval;
@@ -381,44 +369,16 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
&val, 60*1000))
slot->flags |= SLOT_ENABLED;
- if (is_dock_device(handle)) {
- /* we don't want to call this device's _EJ0
- * because we want the dock notify handler
- * to call it after it calls _DCK
- */
- newfunc->flags &= ~FUNC_HAS_EJ0;
- if (register_hotplug_dock_device(handle,
- &acpiphp_dock_ops, context,
- acpiphp_dock_init, acpiphp_dock_release))
- pr_debug("failed to register dock device\n");
- }
-
- /* install notify handler */
- if (!(newfunc->flags & FUNC_HAS_DCK)) {
- status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event,
- context);
- if (ACPI_FAILURE(status))
- acpi_handle_err(handle,
- "failed to install notify handler\n");
- }
-
return AE_OK;
-
- err:
- mutex_lock(&acpiphp_context_lock);
- acpiphp_put_context(context);
- mutex_unlock(&acpiphp_context_lock);
- return status;
}
-static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
+static struct acpiphp_bridge *acpiphp_dev_to_bridge(struct acpi_device *adev)
{
struct acpiphp_context *context;
struct acpiphp_bridge *bridge = NULL;
- mutex_lock(&acpiphp_context_lock);
- context = acpiphp_get_context(handle);
+ acpi_lock_hp_context();
+ context = acpiphp_get_context(adev);
if (context) {
bridge = context->bridge;
if (bridge)
@@ -426,7 +386,7 @@ static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
acpiphp_put_context(context);
}
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
return bridge;
}
@@ -434,22 +394,15 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
{
struct acpiphp_slot *slot;
struct acpiphp_func *func;
- acpi_status status;
list_for_each_entry(slot, &bridge->slots, node) {
list_for_each_entry(func, &slot->funcs, sibling) {
- acpi_handle handle = func_to_handle(func);
-
- if (is_dock_device(handle))
- unregister_hotplug_dock_device(handle);
+ struct acpi_device *adev = func_to_acpi_device(func);
- if (!(func->flags & FUNC_HAS_DCK)) {
- status = acpi_remove_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event);
- if (ACPI_FAILURE(status))
- pr_err("failed to remove notify handler\n");
- }
+ acpi_lock_hp_context();
+ adev->hp->notify = NULL;
+ adev->hp->fixup = NULL;
+ acpi_unlock_hp_context();
}
slot->flags |= SLOT_IS_GOING_AWAY;
if (slot->slot)
@@ -460,9 +413,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
list_del(&bridge->list);
mutex_unlock(&bridge_mutex);
- mutex_lock(&acpiphp_context_lock);
+ acpi_lock_hp_context();
bridge->is_going_away = true;
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
}
/**
@@ -471,7 +424,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
*/
static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
{
- struct list_head *tmp;
+ struct pci_bus *tmp;
unsigned char max, n;
/*
@@ -484,41 +437,14 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
*/
max = bus->busn_res.start;
- list_for_each(tmp, &bus->children) {
- n = pci_bus_max_busnr(pci_bus_b(tmp));
+ list_for_each_entry(tmp, &bus->children, node) {
+ n = pci_bus_max_busnr(tmp);
if (n > max)
max = n;
}
return max;
}
-/**
- * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree.
- * @handle: ACPI device object handle to start from.
- */
-static void acpiphp_bus_trim(acpi_handle handle)
-{
- struct acpi_device *adev = NULL;
-
- acpi_bus_get_device(handle, &adev);
- if (adev)
- acpi_bus_trim(adev);
-}
-
-/**
- * acpiphp_bus_add - Scan ACPI namespace subtree.
- * @handle: ACPI object handle to start the scan from.
- */
-static void acpiphp_bus_add(acpi_handle handle)
-{
- struct acpi_device *adev = NULL;
-
- acpi_bus_scan(handle);
- acpi_bus_get_device(handle, &adev);
- if (acpi_device_enumerated(adev))
- acpi_device_set_power(adev, ACPI_STATE_D0);
-}
-
static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
{
struct acpiphp_func *func;
@@ -558,9 +484,13 @@ static int acpiphp_rescan_slot(struct acpiphp_slot *slot)
{
struct acpiphp_func *func;
- list_for_each_entry(func, &slot->funcs, sibling)
- acpiphp_bus_add(func_to_handle(func));
+ list_for_each_entry(func, &slot->funcs, sibling) {
+ struct acpi_device *adev = func_to_acpi_device(func);
+ acpi_bus_scan(adev->handle);
+ if (acpi_device_enumerated(adev))
+ acpi_device_set_power(adev, ACPI_STATE_D0);
+ }
return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0));
}
@@ -625,32 +555,15 @@ static void __ref enable_slot(struct acpiphp_slot *slot)
}
}
-/* return first device in slot, acquiring a reference on it */
-static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
-{
- struct pci_bus *bus = slot->bus;
- struct pci_dev *dev;
- struct pci_dev *ret = NULL;
-
- down_read(&pci_bus_sem);
- list_for_each_entry(dev, &bus->devices, bus_list)
- if (PCI_SLOT(dev->devfn) == slot->device) {
- ret = pci_dev_get(dev);
- break;
- }
- up_read(&pci_bus_sem);
-
- return ret;
-}
-
/**
* disable_slot - disable a slot
* @slot: ACPI PHP slot
*/
static void disable_slot(struct acpiphp_slot *slot)
{
+ struct pci_bus *bus = slot->bus;
+ struct pci_dev *dev, *prev;
struct acpiphp_func *func;
- struct pci_dev *pdev;
/*
* enable_slot() enumerates all functions in this device via
@@ -658,22 +571,18 @@ static void disable_slot(struct acpiphp_slot *slot)
* methods (_EJ0, etc.) or not. Therefore, we remove all functions
* here.
*/
- while ((pdev = dev_in_slot(slot))) {
- pci_stop_and_remove_bus_device(pdev);
- pci_dev_put(pdev);
- }
+ list_for_each_entry_safe_reverse(dev, prev, &bus->devices, bus_list)
+ if (PCI_SLOT(dev->devfn) == slot->device)
+ pci_stop_and_remove_bus_device(dev);
list_for_each_entry(func, &slot->funcs, sibling)
- acpiphp_bus_trim(func_to_handle(func));
+ acpi_bus_trim(func_to_acpi_device(func));
slot->flags &= (~SLOT_ENABLED);
}
-static bool acpiphp_no_hotplug(acpi_handle handle)
+static bool acpiphp_no_hotplug(struct acpi_device *adev)
{
- struct acpi_device *adev = NULL;
-
- acpi_bus_get_device(handle, &adev);
return adev && adev->flags.no_hotplug;
}
@@ -682,7 +591,7 @@ static bool slot_no_hotplug(struct acpiphp_slot *slot)
struct acpiphp_func *func;
list_for_each_entry(func, &slot->funcs, sibling)
- if (acpiphp_no_hotplug(func_to_handle(func)))
+ if (acpiphp_no_hotplug(func_to_acpi_device(func)))
return true;
return false;
@@ -747,28 +656,25 @@ static inline bool device_status_valid(unsigned int sta)
*/
static void trim_stale_devices(struct pci_dev *dev)
{
- acpi_handle handle = ACPI_HANDLE(&dev->dev);
+ struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
struct pci_bus *bus = dev->subordinate;
bool alive = false;
- if (handle) {
+ if (adev) {
acpi_status status;
unsigned long long sta;
- status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
alive = (ACPI_SUCCESS(status) && device_status_valid(sta))
- || acpiphp_no_hotplug(handle);
+ || acpiphp_no_hotplug(adev);
}
- if (!alive) {
- u32 v;
+ if (!alive)
+ alive = pci_device_is_present(dev);
- /* Check if the device responds. */
- alive = pci_bus_read_dev_vendor_id(dev->bus, dev->devfn, &v, 0);
- }
if (!alive) {
pci_stop_and_remove_bus_device(dev);
- if (handle)
- acpiphp_bus_trim(handle);
+ if (adev)
+ acpi_bus_trim(adev);
} else if (bus) {
struct pci_dev *child, *tmp;
@@ -800,7 +706,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
struct pci_bus *bus = slot->bus;
struct pci_dev *dev, *tmp;
- mutex_lock(&slot->crit_sect);
if (slot_no_hotplug(slot)) {
; /* do nothing */
} else if (device_status_valid(get_slot_status(slot))) {
@@ -815,7 +720,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
} else {
disable_slot(slot);
}
- mutex_unlock(&slot->crit_sect);
}
}
@@ -855,11 +759,11 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
* ACPI event handlers
*/
-void acpiphp_check_host_bridge(acpi_handle handle)
+void acpiphp_check_host_bridge(struct acpi_device *adev)
{
struct acpiphp_bridge *bridge;
- bridge = acpiphp_handle_to_bridge(handle);
+ bridge = acpiphp_dev_to_bridge(adev);
if (bridge) {
pci_lock_rescan_remove();
@@ -872,73 +776,52 @@ void acpiphp_check_host_bridge(acpi_handle handle)
static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot);
-static void hotplug_event(acpi_handle handle, u32 type, void *data)
+static void hotplug_event(u32 type, struct acpiphp_context *context)
{
- struct acpiphp_context *context = data;
+ acpi_handle handle = context->hp.self->handle;
struct acpiphp_func *func = &context->func;
+ struct acpiphp_slot *slot = func->slot;
struct acpiphp_bridge *bridge;
- char objname[64];
- struct acpi_buffer buffer = { .length = sizeof(objname),
- .pointer = objname };
- mutex_lock(&acpiphp_context_lock);
+ acpi_lock_hp_context();
bridge = context->bridge;
if (bridge)
get_bridge(bridge);
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
pci_lock_rescan_remove();
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* bus re-enumerate */
- pr_debug("%s: Bus check notify on %s\n", __func__, objname);
- pr_debug("%s: re-enumerating slots under %s\n",
- __func__, objname);
- if (bridge) {
+ acpi_handle_debug(handle, "Bus check in %s()\n", __func__);
+ if (bridge)
acpiphp_check_bridge(bridge);
- } else {
- struct acpiphp_slot *slot = func->slot;
-
- if (slot->flags & SLOT_IS_GOING_AWAY)
- break;
-
- mutex_lock(&slot->crit_sect);
+ else if (!(slot->flags & SLOT_IS_GOING_AWAY))
enable_slot(slot);
- mutex_unlock(&slot->crit_sect);
- }
+
break;
case ACPI_NOTIFY_DEVICE_CHECK:
/* device check */
- pr_debug("%s: Device check notify on %s\n", __func__, objname);
+ acpi_handle_debug(handle, "Device check in %s()\n", __func__);
if (bridge) {
acpiphp_check_bridge(bridge);
- } else {
- struct acpiphp_slot *slot = func->slot;
- int ret;
-
- if (slot->flags & SLOT_IS_GOING_AWAY)
- break;
-
+ } else if (!(slot->flags & SLOT_IS_GOING_AWAY)) {
/*
* Check if anything has changed in the slot and rescan
* from the parent if that's the case.
*/
- mutex_lock(&slot->crit_sect);
- ret = acpiphp_rescan_slot(slot);
- mutex_unlock(&slot->crit_sect);
- if (ret)
+ if (acpiphp_rescan_slot(slot))
acpiphp_check_bridge(func->parent);
}
break;
case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */
- pr_debug("%s: Device eject notify on %s\n", __func__, objname);
- acpiphp_disable_and_eject_slot(func->slot);
+ acpi_handle_debug(handle, "Eject request in %s()\n", __func__);
+ acpiphp_disable_and_eject_slot(slot);
break;
}
@@ -947,106 +830,41 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
put_bridge(bridge);
}
-static void hotplug_event_work(void *data, u32 type)
+static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type)
{
- struct acpiphp_context *context = data;
- acpi_handle handle = context->handle;
-
- acpi_scan_lock_acquire();
+ struct acpiphp_context *context;
- hotplug_event(handle, type, context);
+ context = acpiphp_grab_context(adev);
+ if (!context)
+ return -ENODATA;
- acpi_scan_lock_release();
- acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL);
- put_bridge(context->func.parent);
+ hotplug_event(type, context);
+ acpiphp_let_context_go(context);
+ return 0;
}
/**
- * handle_hotplug_event - handle ACPI hotplug event
- * @handle: Notify()'ed acpi_handle
- * @type: Notify code
- * @data: pointer to acpiphp_context structure
+ * acpiphp_enumerate_slots - Enumerate PCI slots for a given bus.
+ * @bus: PCI bus to enumerate the slots for.
*
- * Handles ACPI event notification on slots.
- */
-static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
-{
- struct acpiphp_context *context;
- u32 ost_code = ACPI_OST_SC_SUCCESS;
- acpi_status status;
-
- switch (type) {
- case ACPI_NOTIFY_BUS_CHECK:
- case ACPI_NOTIFY_DEVICE_CHECK:
- break;
- case ACPI_NOTIFY_EJECT_REQUEST:
- ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS;
- acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
- break;
-
- case ACPI_NOTIFY_DEVICE_WAKE:
- return;
-
- case ACPI_NOTIFY_FREQUENCY_MISMATCH:
- acpi_handle_err(handle, "Device cannot be configured due "
- "to a frequency mismatch\n");
- goto out;
-
- case ACPI_NOTIFY_BUS_MODE_MISMATCH:
- acpi_handle_err(handle, "Device cannot be configured due "
- "to a bus mode mismatch\n");
- goto out;
-
- case ACPI_NOTIFY_POWER_FAULT:
- acpi_handle_err(handle, "Device has suffered a power fault\n");
- goto out;
-
- default:
- acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
- ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
- goto out;
- }
-
- mutex_lock(&acpiphp_context_lock);
- context = acpiphp_get_context(handle);
- if (!context || WARN_ON(context->handle != handle)
- || context->func.parent->is_going_away)
- goto err_out;
-
- get_bridge(context->func.parent);
- acpiphp_put_context(context);
- status = acpi_hotplug_execute(hotplug_event_work, context, type);
- if (ACPI_SUCCESS(status)) {
- mutex_unlock(&acpiphp_context_lock);
- return;
- }
- put_bridge(context->func.parent);
-
- err_out:
- mutex_unlock(&acpiphp_context_lock);
- ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
-
- out:
- acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
-}
-
-/*
- * Create hotplug slots for the PCI bus.
- * It should always return 0 to avoid skipping following notifiers.
+ * A "slot" is an object associated with a PCI device number. All functions
+ * (PCI devices) with the same bus and device number belong to the same slot.
*/
void acpiphp_enumerate_slots(struct pci_bus *bus)
{
struct acpiphp_bridge *bridge;
+ struct acpi_device *adev;
acpi_handle handle;
acpi_status status;
if (acpiphp_disabled)
return;
- handle = ACPI_HANDLE(bus->bridge);
- if (!handle)
+ adev = ACPI_COMPANION(bus->bridge);
+ if (!adev)
return;
+ handle = adev->handle;
bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
if (!bridge) {
acpi_handle_err(handle, "No memory for bridge object\n");
@@ -1074,10 +892,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
* parent is going to be handled by pciehp, in which case this
* bridge is not interesting to us either.
*/
- mutex_lock(&acpiphp_context_lock);
- context = acpiphp_get_context(handle);
+ acpi_lock_hp_context();
+ context = acpiphp_get_context(adev);
if (!context) {
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
put_device(&bus->dev);
pci_dev_put(bridge->pci_dev);
kfree(bridge);
@@ -1087,17 +905,17 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
context->bridge = bridge;
/* Get a reference to the parent bridge. */
get_bridge(context->func.parent);
- mutex_unlock(&acpiphp_context_lock);
+ acpi_unlock_hp_context();
}
- /* must be added to the list prior to calling register_slot */
+ /* Must be added to the list prior to calling acpiphp_add_context(). */
mutex_lock(&bridge_mutex);
list_add(&bridge->list, &bridge_list);
mutex_unlock(&bridge_mutex);
/* register all slot objects under this bridge */
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
- register_slot, NULL, bridge, NULL);
+ acpiphp_add_context, NULL, bridge, NULL);
if (ACPI_FAILURE(status)) {
acpi_handle_err(handle, "failed to register slots\n");
cleanup_bridge(bridge);
@@ -1105,7 +923,10 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
}
}
-/* Destroy hotplug slots associated with the PCI bus */
+/**
+ * acpiphp_remove_slots - Remove slot objects associated with a given bus.
+ * @bus: PCI bus to remove the slot objects for.
+ */
void acpiphp_remove_slots(struct pci_bus *bus)
{
struct acpiphp_bridge *bridge;
@@ -1136,13 +957,10 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot)
if (slot->flags & SLOT_IS_GOING_AWAY)
return -ENODEV;
- mutex_lock(&slot->crit_sect);
/* configure all functions */
if (!(slot->flags & SLOT_ENABLED))
enable_slot(slot);
- mutex_unlock(&slot->crit_sect);
-
pci_unlock_rescan_remove();
return 0;
}
@@ -1158,8 +976,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
if (slot->flags & SLOT_IS_GOING_AWAY)
return -ENODEV;
- mutex_lock(&slot->crit_sect);
-
/* unconfigure all functions */
disable_slot(slot);
@@ -1173,7 +989,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
break;
}
- mutex_unlock(&slot->crit_sect);
return 0;
}
@@ -1181,9 +996,15 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot)
{
int ret;
+ /*
+ * Acquire acpi_scan_lock to ensure that the execution of _EJ0 in
+ * acpiphp_disable_and_eject_slot() will be synchronized properly.
+ */
+ acpi_scan_lock_acquire();
pci_lock_rescan_remove();
ret = acpiphp_disable_and_eject_slot(slot);
pci_unlock_rescan_remove();
+ acpi_scan_lock_release();
return ret;
}
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index 31273e155e6c..037e2612c5bd 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -920,12 +920,12 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
bus->max_bus_speed = PCI_SPEED_100MHz_PCIX;
break;
}
- if (bus_cap & 20) {
+ if (bus_cap & 0x20) {
dbg("bus max supports 66MHz PCI-X\n");
bus->max_bus_speed = PCI_SPEED_66MHz_PCIX;
break;
}
- if (bus_cap & 10) {
+ if (bus_cap & 0x10) {
dbg("bus max supports 66MHz PCI\n");
bus->max_bus_speed = PCI_SPEED_66MHz;
break;
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 88b37cad4b35..8a66866b8cf1 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -76,6 +76,7 @@ struct slot {
struct hotplug_slot *hotplug_slot;
struct delayed_work work; /* work for button event */
struct mutex lock;
+ struct mutex hotplug_lock;
struct workqueue_struct *wq;
};
@@ -109,6 +110,8 @@ struct controller {
#define INT_BUTTON_PRESS 7
#define INT_BUTTON_RELEASE 8
#define INT_BUTTON_CANCEL 9
+#define INT_LINK_UP 10
+#define INT_LINK_DOWN 11
#define STATIC_STATE 0
#define BLINKINGON_STATE 1
@@ -132,6 +135,7 @@ u8 pciehp_handle_attention_button(struct slot *p_slot);
u8 pciehp_handle_switch_change(struct slot *p_slot);
u8 pciehp_handle_presence_change(struct slot *p_slot);
u8 pciehp_handle_power_fault(struct slot *p_slot);
+void pciehp_handle_linkstate_change(struct slot *p_slot);
int pciehp_configure_device(struct slot *p_slot);
int pciehp_unconfigure_device(struct slot *p_slot);
void pciehp_queue_pushbutton_work(struct work_struct *work);
@@ -153,6 +157,7 @@ void pciehp_green_led_on(struct slot *slot);
void pciehp_green_led_off(struct slot *slot);
void pciehp_green_led_blink(struct slot *slot);
int pciehp_check_link_status(struct controller *ctrl);
+bool pciehp_check_link_active(struct controller *ctrl);
void pciehp_release_ctrl(struct controller *ctrl);
int pciehp_reset_slot(struct slot *slot, int probe);
diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c
index eddddd447d0d..20fea57d2149 100644
--- a/drivers/pci/hotplug/pciehp_acpi.c
+++ b/drivers/pci/hotplug/pciehp_acpi.c
@@ -112,6 +112,7 @@ static struct pcie_port_service_driver __initdata dummy_driver = {
static int __init select_detection_mode(void)
{
struct dummy_slot *slot, *tmp;
+
if (pcie_port_service_register(&dummy_driver))
return PCIEHP_DETECT_ACPI;
pcie_port_service_unregister(&dummy_driver);
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 53b58debc288..0e0a2fff20a3 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -108,6 +108,7 @@ static int init_slot(struct controller *ctrl)
ops = kzalloc(sizeof(*ops), GFP_KERNEL);
if (!ops)
goto out;
+
ops->enable_slot = enable_slot;
ops->disable_slot = disable_slot;
ops->get_power_status = get_power_status;
@@ -283,8 +284,11 @@ static int pciehp_probe(struct pcie_device *dev)
slot = ctrl->slot;
pciehp_get_adapter_status(slot, &occupied);
pciehp_get_power_status(slot, &poweron);
- if (occupied && pciehp_force)
+ if (occupied && pciehp_force) {
+ mutex_lock(&slot->hotplug_lock);
pciehp_enable_slot(slot);
+ mutex_unlock(&slot->hotplug_lock);
+ }
/* If empty slot's power status is on, turn power off */
if (!occupied && poweron && POWER_CTRL(ctrl))
pciehp_power_off_slot(slot);
@@ -328,10 +332,12 @@ static int pciehp_resume (struct pcie_device *dev)
/* Check if slot is occupied */
pciehp_get_adapter_status(slot, &status);
+ mutex_lock(&slot->hotplug_lock);
if (status)
pciehp_enable_slot(slot);
else
pciehp_disable_slot(slot);
+ mutex_unlock(&slot->hotplug_lock);
return 0;
}
#endif /* PM */
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 50628487597d..c75e6a678dcc 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -150,6 +150,27 @@ u8 pciehp_handle_power_fault(struct slot *p_slot)
return 1;
}
+void pciehp_handle_linkstate_change(struct slot *p_slot)
+{
+ u32 event_type;
+ struct controller *ctrl = p_slot->ctrl;
+
+ /* Link Status Change */
+ ctrl_dbg(ctrl, "Data Link Layer State change\n");
+
+ if (pciehp_check_link_active(ctrl)) {
+ ctrl_info(ctrl, "slot(%s): Link Up event\n",
+ slot_name(p_slot));
+ event_type = INT_LINK_UP;
+ } else {
+ ctrl_info(ctrl, "slot(%s): Link Down event\n",
+ slot_name(p_slot));
+ event_type = INT_LINK_DOWN;
+ }
+
+ queue_interrupt_event(p_slot, event_type);
+}
+
/* The following routines constitute the bulk of the
hotplug controller logic
*/
@@ -212,7 +233,8 @@ static int board_added(struct slot *p_slot)
if (retval) {
ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
pci_domain_nr(parent), parent->number);
- goto err_exit;
+ if (retval != -EEXIST)
+ goto err_exit;
}
pciehp_green_led_on(p_slot);
@@ -255,6 +277,9 @@ static int remove_board(struct slot *p_slot)
struct power_work_info {
struct slot *p_slot;
struct work_struct work;
+ unsigned int req;
+#define DISABLE_REQ 0
+#define ENABLE_REQ 1
};
/**
@@ -269,30 +294,38 @@ static void pciehp_power_thread(struct work_struct *work)
struct power_work_info *info =
container_of(work, struct power_work_info, work);
struct slot *p_slot = info->p_slot;
+ int ret;
- mutex_lock(&p_slot->lock);
- switch (p_slot->state) {
- case POWEROFF_STATE:
- mutex_unlock(&p_slot->lock);
+ switch (info->req) {
+ case DISABLE_REQ:
ctrl_dbg(p_slot->ctrl,
"Disabling domain:bus:device=%04x:%02x:00\n",
pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
p_slot->ctrl->pcie->port->subordinate->number);
+ mutex_lock(&p_slot->hotplug_lock);
pciehp_disable_slot(p_slot);
+ mutex_unlock(&p_slot->hotplug_lock);
mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE;
- break;
- case POWERON_STATE:
mutex_unlock(&p_slot->lock);
- if (pciehp_enable_slot(p_slot))
+ break;
+ case ENABLE_REQ:
+ ctrl_dbg(p_slot->ctrl,
+ "Enabling domain:bus:device=%04x:%02x:00\n",
+ pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
+ p_slot->ctrl->pcie->port->subordinate->number);
+ mutex_lock(&p_slot->hotplug_lock);
+ ret = pciehp_enable_slot(p_slot);
+ mutex_unlock(&p_slot->hotplug_lock);
+ if (ret)
pciehp_green_led_off(p_slot);
mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE;
+ mutex_unlock(&p_slot->lock);
break;
default:
break;
}
- mutex_unlock(&p_slot->lock);
kfree(info);
}
@@ -315,9 +348,11 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
switch (p_slot->state) {
case BLINKINGOFF_STATE:
p_slot->state = POWEROFF_STATE;
+ info->req = DISABLE_REQ;
break;
case BLINKINGON_STATE:
p_slot->state = POWERON_STATE;
+ info->req = ENABLE_REQ;
break;
default:
kfree(info);
@@ -364,11 +399,10 @@ static void handle_button_press_event(struct slot *p_slot)
*/
ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot));
cancel_delayed_work(&p_slot->work);
- if (p_slot->state == BLINKINGOFF_STATE) {
+ if (p_slot->state == BLINKINGOFF_STATE)
pciehp_green_led_on(p_slot);
- } else {
+ 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", slot_name(p_slot));
@@ -407,14 +441,81 @@ static void handle_surprise_event(struct slot *p_slot)
INIT_WORK(&info->work, pciehp_power_thread);
pciehp_get_adapter_status(p_slot, &getstatus);
- if (!getstatus)
+ if (!getstatus) {
p_slot->state = POWEROFF_STATE;
- else
+ info->req = DISABLE_REQ;
+ } else {
p_slot->state = POWERON_STATE;
+ info->req = ENABLE_REQ;
+ }
queue_work(p_slot->wq, &info->work);
}
+/*
+ * 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;
+ struct power_work_info *info;
+
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
+ __func__);
+ return;
+ }
+ info->p_slot = p_slot;
+ info->req = event == INT_LINK_UP ? ENABLE_REQ : DISABLE_REQ;
+ INIT_WORK(&info->work, pciehp_power_thread);
+
+ switch (p_slot->state) {
+ case BLINKINGON_STATE:
+ case BLINKINGOFF_STATE:
+ cancel_delayed_work(&p_slot->work);
+ /* Fall through */
+ case STATIC_STATE:
+ p_slot->state = event == INT_LINK_UP ?
+ POWERON_STATE : POWEROFF_STATE;
+ queue_work(p_slot->wq, &info->work);
+ break;
+ case POWERON_STATE:
+ if (event == INT_LINK_UP) {
+ ctrl_info(ctrl,
+ "Link Up event ignored on slot(%s): already powering on\n",
+ slot_name(p_slot));
+ kfree(info);
+ } else {
+ ctrl_info(ctrl,
+ "Link Down event queued on slot(%s): currently getting powered on\n",
+ slot_name(p_slot));
+ p_slot->state = POWEROFF_STATE;
+ queue_work(p_slot->wq, &info->work);
+ }
+ break;
+ case POWEROFF_STATE:
+ if (event == INT_LINK_UP) {
+ ctrl_info(ctrl,
+ "Link Up event queued on slot(%s): currently getting powered off\n",
+ slot_name(p_slot));
+ p_slot->state = POWERON_STATE;
+ queue_work(p_slot->wq, &info->work);
+ } else {
+ ctrl_info(ctrl,
+ "Link Down event ignored on slot(%s): already powering off\n",
+ slot_name(p_slot));
+ kfree(info);
+ }
+ break;
+ default:
+ ctrl_err(ctrl, "Not a valid state on slot(%s)\n",
+ slot_name(p_slot));
+ kfree(info);
+ break;
+ }
+}
+
static void interrupt_event_handler(struct work_struct *work)
{
struct event_info *info = container_of(work, struct event_info, work);
@@ -433,12 +534,23 @@ static void interrupt_event_handler(struct work_struct *work)
pciehp_green_led_off(p_slot);
break;
case INT_PRESENCE_ON:
- case INT_PRESENCE_OFF:
if (!HP_SUPR_RM(ctrl))
break;
+ ctrl_dbg(ctrl, "Surprise Insertion\n");
+ handle_surprise_event(p_slot);
+ break;
+ case INT_PRESENCE_OFF:
+ /*
+ * Regardless of surprise capability, we need to
+ * definitely remove a card that has been pulled out!
+ */
ctrl_dbg(ctrl, "Surprise Removal\n");
handle_surprise_event(p_slot);
break;
+ case INT_LINK_UP:
+ case INT_LINK_DOWN:
+ handle_link_event(p_slot, info->event_type);
+ break;
default:
break;
}
@@ -447,6 +559,9 @@ static void interrupt_event_handler(struct work_struct *work)
kfree(info);
}
+/*
+ * Note: This function must be called with slot->hotplug_lock held
+ */
int pciehp_enable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
@@ -479,13 +594,15 @@ int pciehp_enable_slot(struct slot *p_slot)
pciehp_get_latch_status(p_slot, &getstatus);
rc = board_added(p_slot);
- if (rc) {
+ if (rc)
pciehp_get_latch_status(p_slot, &getstatus);
- }
+
return rc;
}
-
+/*
+ * Note: This function must be called with slot->hotplug_lock held
+ */
int pciehp_disable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
@@ -494,24 +611,6 @@ int pciehp_disable_slot(struct slot *p_slot)
if (!p_slot->ctrl)
return 1;
- if (!HP_SUPR_RM(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));
- 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",
- slot_name(p_slot));
- return -ENODEV;
- }
- }
-
if (POWER_CTRL(p_slot->ctrl)) {
pciehp_get_power_status(p_slot, &getstatus);
if (!getstatus) {
@@ -536,7 +635,9 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
case STATIC_STATE:
p_slot->state = POWERON_STATE;
mutex_unlock(&p_slot->lock);
+ mutex_lock(&p_slot->hotplug_lock);
retval = pciehp_enable_slot(p_slot);
+ mutex_unlock(&p_slot->hotplug_lock);
mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE;
break;
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 14acfccb7670..d7d058fa19a4 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -206,7 +206,7 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
mutex_unlock(&ctrl->ctrl_lock);
}
-static bool check_link_active(struct controller *ctrl)
+bool pciehp_check_link_active(struct controller *ctrl)
{
struct pci_dev *pdev = ctrl_dev(ctrl);
u16 lnk_status;
@@ -225,12 +225,12 @@ static void __pcie_wait_link_active(struct controller *ctrl, bool active)
{
int timeout = 1000;
- if (check_link_active(ctrl) == active)
+ if (pciehp_check_link_active(ctrl) == active)
return;
while (timeout > 0) {
msleep(10);
timeout -= 10;
- if (check_link_active(ctrl) == active)
+ if (pciehp_check_link_active(ctrl) == active)
return;
}
ctrl_dbg(ctrl, "Data Link Layer Link Active not %s in 1000 msec\n",
@@ -242,11 +242,6 @@ static void pcie_wait_link_active(struct controller *ctrl)
__pcie_wait_link_active(ctrl, true);
}
-static void pcie_wait_link_not_active(struct controller *ctrl)
-{
- __pcie_wait_link_active(ctrl, false);
-}
-
static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
{
u32 l;
@@ -332,11 +327,6 @@ static int pciehp_link_enable(struct controller *ctrl)
return __pciehp_link_set(ctrl, true);
}
-static int pciehp_link_disable(struct controller *ctrl)
-{
- return __pciehp_link_set(ctrl, false);
-}
-
void pciehp_get_attention_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
@@ -508,14 +498,6 @@ void pciehp_power_off_slot(struct slot * slot)
{
struct controller *ctrl = slot->ctrl;
- /* Disable the link at first */
- pciehp_link_disable(ctrl);
- /* wait the link is down */
- if (ctrl->link_active_reporting)
- pcie_wait_link_not_active(ctrl);
- else
- msleep(1000);
-
pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
@@ -540,7 +522,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
- PCI_EXP_SLTSTA_CC);
+ PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC);
detected &= ~intr_loc;
intr_loc |= detected;
if (!intr_loc)
@@ -579,6 +561,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
ctrl->power_fault_detected = 1;
pciehp_handle_power_fault(slot);
}
+
+ if (intr_loc & PCI_EXP_SLTSTA_DLLSC)
+ pciehp_handle_linkstate_change(slot);
+
return IRQ_HANDLED;
}
@@ -596,9 +582,17 @@ void pcie_enable_notification(struct controller *ctrl)
* when it is cleared in the interrupt service routine, and
* next power fault detected interrupt was notified again.
*/
- cmd = PCI_EXP_SLTCTL_PDCE;
+
+ /*
+ * Always enable link events: thus link-up and link-down shall
+ * always be treated as hotplug and unplug respectively. Enable
+ * presence detect only if Attention Button is not present.
+ */
+ cmd = PCI_EXP_SLTCTL_DLLSCE;
if (ATTN_BUTTN(ctrl))
cmd |= PCI_EXP_SLTCTL_ABPE;
+ else
+ cmd |= PCI_EXP_SLTCTL_PDCE;
if (MRL_SENS(ctrl))
cmd |= PCI_EXP_SLTCTL_MRLSCE;
if (!pciehp_poll_mode)
@@ -606,7 +600,8 @@ void pcie_enable_notification(struct controller *ctrl)
mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE |
- PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE);
+ PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE |
+ PCI_EXP_SLTCTL_DLLSCE);
pcie_write_cmd(ctrl, cmd, mask);
}
@@ -624,33 +619,38 @@ static void pcie_disable_notification(struct controller *ctrl)
/*
* pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
- * bus reset of the bridge, but if the slot supports surprise removal we need
- * to disable presence detection around the bus reset and clear any spurious
+ * bus reset of the bridge, but at the same time we want to ensure that it is
+ * not seen as a hot-unplug, followed by the hot-plug of the device. Thus,
+ * disable link state notification and presence detection change notification
+ * momentarily, if we see that they could interfere. Also, clear any spurious
* events after.
*/
int pciehp_reset_slot(struct slot *slot, int probe)
{
struct controller *ctrl = slot->ctrl;
struct pci_dev *pdev = ctrl_dev(ctrl);
+ u16 stat_mask = 0, ctrl_mask = 0;
if (probe)
return 0;
- if (HP_SUPR_RM(ctrl)) {
- pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_PDCE);
- if (pciehp_poll_mode)
- del_timer_sync(&ctrl->poll_timer);
+ if (!ATTN_BUTTN(ctrl)) {
+ ctrl_mask |= PCI_EXP_SLTCTL_PDCE;
+ stat_mask |= PCI_EXP_SLTSTA_PDC;
}
+ ctrl_mask |= PCI_EXP_SLTCTL_DLLSCE;
+ stat_mask |= PCI_EXP_SLTSTA_DLLSC;
+
+ pcie_write_cmd(ctrl, 0, ctrl_mask);
+ if (pciehp_poll_mode)
+ del_timer_sync(&ctrl->poll_timer);
pci_reset_bridge_secondary_bus(ctrl->pcie->port);
- if (HP_SUPR_RM(ctrl)) {
- pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
- PCI_EXP_SLTSTA_PDC);
- pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PDCE, PCI_EXP_SLTCTL_PDCE);
- if (pciehp_poll_mode)
- int_poll_timeout(ctrl->poll_timer.data);
- }
+ pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask);
+ pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask);
+ if (pciehp_poll_mode)
+ int_poll_timeout(ctrl->poll_timer.data);
return 0;
}
@@ -687,6 +687,7 @@ static int pcie_init_slot(struct controller *ctrl)
slot->ctrl = ctrl;
mutex_init(&slot->lock);
+ mutex_init(&slot->hotplug_lock);
INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
ctrl->slot = slot;
return 0;
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index b07d7cc2d697..1b533060ce65 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -50,7 +50,7 @@ int pciehp_configure_device(struct slot *p_slot)
"at %04x:%02x:00, cannot hot-add\n", pci_name(dev),
pci_domain_nr(parent), parent->number);
pci_dev_put(dev);
- ret = -EINVAL;
+ ret = -EEXIST;
goto out;
}
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 9dce7c5e2a77..de7a74782f92 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -170,97 +170,6 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset)
pci_dev_put(dev);
}
-static int sriov_migration(struct pci_dev *dev)
-{
- u16 status;
- struct pci_sriov *iov = dev->sriov;
-
- if (!iov->num_VFs)
- return 0;
-
- if (!(iov->cap & PCI_SRIOV_CAP_VFM))
- return 0;
-
- pci_read_config_word(dev, iov->pos + PCI_SRIOV_STATUS, &status);
- if (!(status & PCI_SRIOV_STATUS_VFM))
- return 0;
-
- schedule_work(&iov->mtask);
-
- return 1;
-}
-
-static void sriov_migration_task(struct work_struct *work)
-{
- int i;
- u8 state;
- u16 status;
- struct pci_sriov *iov = container_of(work, struct pci_sriov, mtask);
-
- for (i = iov->initial_VFs; i < iov->num_VFs; i++) {
- state = readb(iov->mstate + i);
- if (state == PCI_SRIOV_VFM_MI) {
- writeb(PCI_SRIOV_VFM_AV, iov->mstate + i);
- state = readb(iov->mstate + i);
- if (state == PCI_SRIOV_VFM_AV)
- virtfn_add(iov->self, i, 1);
- } else if (state == PCI_SRIOV_VFM_MO) {
- virtfn_remove(iov->self, i, 1);
- writeb(PCI_SRIOV_VFM_UA, iov->mstate + i);
- state = readb(iov->mstate + i);
- if (state == PCI_SRIOV_VFM_AV)
- virtfn_add(iov->self, i, 0);
- }
- }
-
- pci_read_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, &status);
- status &= ~PCI_SRIOV_STATUS_VFM;
- pci_write_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, status);
-}
-
-static int sriov_enable_migration(struct pci_dev *dev, int nr_virtfn)
-{
- int bir;
- u32 table;
- resource_size_t pa;
- struct pci_sriov *iov = dev->sriov;
-
- if (nr_virtfn <= iov->initial_VFs)
- return 0;
-
- pci_read_config_dword(dev, iov->pos + PCI_SRIOV_VFM, &table);
- bir = PCI_SRIOV_VFM_BIR(table);
- if (bir > PCI_STD_RESOURCE_END)
- return -EIO;
-
- table = PCI_SRIOV_VFM_OFFSET(table);
- if (table + nr_virtfn > pci_resource_len(dev, bir))
- return -EIO;
-
- pa = pci_resource_start(dev, bir) + table;
- iov->mstate = ioremap(pa, nr_virtfn);
- if (!iov->mstate)
- return -ENOMEM;
-
- INIT_WORK(&iov->mtask, sriov_migration_task);
-
- iov->ctrl |= PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR;
- pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
-
- return 0;
-}
-
-static void sriov_disable_migration(struct pci_dev *dev)
-{
- struct pci_sriov *iov = dev->sriov;
-
- iov->ctrl &= ~(PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR);
- pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
-
- cancel_work_sync(&iov->mtask);
- iounmap(iov->mstate);
-}
-
static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
{
int rc;
@@ -351,12 +260,6 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
goto failed;
}
- if (iov->cap & PCI_SRIOV_CAP_VFM) {
- rc = sriov_enable_migration(dev, nr_virtfn);
- if (rc)
- goto failed;
- }
-
kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE);
iov->num_VFs = nr_virtfn;
@@ -387,9 +290,6 @@ static void sriov_disable(struct pci_dev *dev)
if (!iov->num_VFs)
return;
- if (iov->cap & PCI_SRIOV_CAP_VFM)
- sriov_disable_migration(dev);
-
for (i = 0; i < iov->num_VFs; i++)
virtfn_remove(dev, i, 0);
@@ -688,25 +588,6 @@ void pci_disable_sriov(struct pci_dev *dev)
EXPORT_SYMBOL_GPL(pci_disable_sriov);
/**
- * pci_sriov_migration - notify SR-IOV core of Virtual Function Migration
- * @dev: the PCI device
- *
- * Returns IRQ_HANDLED if the IRQ is handled, or IRQ_NONE if not.
- *
- * Physical Function driver is responsible to register IRQ handler using
- * VF Migration Interrupt Message Number, and call this function when the
- * interrupt is generated by the hardware.
- */
-irqreturn_t pci_sriov_migration(struct pci_dev *dev)
-{
- if (!dev->is_physfn)
- return IRQ_NONE;
-
- return sriov_migration(dev) ? IRQ_HANDLED : IRQ_NONE;
-}
-EXPORT_SYMBOL_GPL(pci_sriov_migration);
-
-/**
* pci_num_vf - return number of VFs associated with a PF device_release_driver
* @dev: the PCI device
*
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 7a0fec6ce571..955ab7990c5b 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -545,9 +545,15 @@ static int populate_msi_sysfs(struct pci_dev *pdev)
return -ENOMEM;
list_for_each_entry(entry, &pdev->msi_list, list) {
char *name = kmalloc(20, GFP_KERNEL);
+ if (!name)
+ goto error_attrs;
+
msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL);
- if (!msi_dev_attr)
+ if (!msi_dev_attr) {
+ kfree(name);
goto error_attrs;
+ }
+
sprintf(name, "%d", entry->irq);
sysfs_attr_init(&msi_dev_attr->attr);
msi_dev_attr->attr.name = name;
@@ -589,6 +595,7 @@ error_attrs:
++count;
msi_attr = msi_attrs[count];
}
+ kfree(msi_attrs);
return ret;
}
@@ -959,7 +966,6 @@ EXPORT_SYMBOL(pci_disable_msi);
/**
* pci_msix_vec_count - return the number of device's MSI-X table entries
* @dev: pointer to the pci_dev data structure of MSI-X device function
-
* This function returns the number of device's MSI-X table entries and
* therefore the number of MSI-X vectors device is capable of sending.
* It returns a negative errno if the device is not capable of sending MSI-X
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 25f0bc659164..d911e0c1f359 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -616,15 +616,11 @@ static int pci_pm_prepare(struct device *dev)
int error = 0;
/*
- * PCI devices suspended at run time need to be resumed at this
- * point, because in general it is necessary to reconfigure them for
- * system suspend. Namely, if the device is supposed to wake up the
- * system from the sleep state, we may need to reconfigure it for this
- * purpose. In turn, if the device is not supposed to wake up the
- * system from the sleep state, we'll have to prevent it from signaling
- * wake-up.
+ * Devices having power.ignore_children set may still be necessary for
+ * suspending their children in the next phase of device suspend.
*/
- pm_runtime_resume(dev);
+ if (dev->power.ignore_children)
+ pm_runtime_resume(dev);
if (drv && drv->pm && drv->pm->prepare)
error = drv->pm->prepare(dev);
@@ -654,6 +650,16 @@ static int pci_pm_suspend(struct device *dev)
goto Fixup;
}
+ /*
+ * PCI devices suspended at run time need to be resumed at this point,
+ * because in general it is necessary to reconfigure them for system
+ * suspend. Namely, if the device is supposed to wake up the system
+ * from the sleep state, we may need to reconfigure it for this purpose.
+ * In turn, if the device is not supposed to wake up the system from the
+ * sleep state, we'll have to prevent it from signaling wake-up.
+ */
+ pm_runtime_resume(dev);
+
pci_dev->state_saved = false;
if (pm->suspend) {
pci_power_t prev = pci_dev->current_state;
@@ -808,6 +814,14 @@ static int pci_pm_freeze(struct device *dev)
return 0;
}
+ /*
+ * This used to be done in pci_pm_prepare() for all devices and some
+ * drivers may depend on it, so do it here. Ideally, runtime-suspended
+ * devices should not be touched during freeze/thaw transitions,
+ * however.
+ */
+ pm_runtime_resume(dev);
+
pci_dev->state_saved = false;
if (pm->freeze) {
int error;
@@ -915,6 +929,9 @@ static int pci_pm_poweroff(struct device *dev)
goto Fixup;
}
+ /* The reason to do that is the same as in pci_pm_suspend(). */
+ pm_runtime_resume(dev);
+
pci_dev->state_saved = false;
if (pm->poweroff) {
int error;
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 276ef9c18802..4e0acefb7565 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -351,28 +351,17 @@ static struct device_attribute dev_rescan_attr = __ATTR(rescan,
(S_IWUSR|S_IWGRP),
NULL, dev_rescan_store);
-static void remove_callback(struct device *dev)
-{
- pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
-}
-
static ssize_t
-remove_store(struct device *dev, struct device_attribute *dummy,
+remove_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- int ret = 0;
unsigned long val;
if (kstrtoul(buf, 0, &val) < 0)
return -EINVAL;
- /* An attribute cannot be unregistered by one of its own methods,
- * so we have to use this roundabout approach.
- */
- if (val)
- ret = device_schedule_callback(dev, remove_callback);
- if (ret)
- count = ret;
+ if (val && device_remove_file_self(dev, attr))
+ pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
return count;
}
static struct device_attribute dev_remove_attr = __ATTR(remove,
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 1febe90831b4..7325d43bf030 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -108,12 +108,12 @@ static bool pcie_ari_disabled;
*/
unsigned char pci_bus_max_busnr(struct pci_bus* bus)
{
- struct list_head *tmp;
+ struct pci_bus *tmp;
unsigned char max, n;
max = bus->busn_res.end;
- list_for_each(tmp, &bus->children) {
- n = pci_bus_max_busnr(pci_bus_b(tmp));
+ list_for_each_entry(tmp, &bus->children, node) {
+ n = pci_bus_max_busnr(tmp);
if(n > max)
max = n;
}
@@ -401,33 +401,40 @@ EXPORT_SYMBOL_GPL(pci_find_ht_capability);
* @res: child resource record for which parent is sought
*
* For given resource region of given device, return the resource
- * region of parent bus the given region is contained in or where
- * it should be allocated from.
+ * region of parent bus the given region is contained in.
*/
struct resource *
pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
{
const struct pci_bus *bus = dev->bus;
+ struct resource *r;
int i;
- struct resource *best = NULL, *r;
pci_bus_for_each_resource(bus, r, i) {
if (!r)
continue;
- if (res->start && !(res->start >= r->start && res->end <= r->end))
- continue; /* Not contained */
- if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
- continue; /* Wrong type */
- if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
- return r; /* Exact match */
- /* We can't insert a non-prefetch resource inside a prefetchable parent .. */
- if (r->flags & IORESOURCE_PREFETCH)
- continue;
- /* .. but we can put a prefetchable resource inside a non-prefetchable one */
- if (!best)
- best = r;
+ if (res->start && resource_contains(r, res)) {
+
+ /*
+ * If the window is prefetchable but the BAR is
+ * not, the allocator made a mistake.
+ */
+ if (r->flags & IORESOURCE_PREFETCH &&
+ !(res->flags & IORESOURCE_PREFETCH))
+ return NULL;
+
+ /*
+ * If we're below a transparent bridge, there may
+ * be both a positively-decoded aperture and a
+ * subtractively-decoded region that contain the BAR.
+ * We want the positively-decoded one, so this depends
+ * on pci_bus_for_each_resource() giving us those
+ * first.
+ */
+ return r;
+ }
}
- return best;
+ return NULL;
}
/**
@@ -1178,9 +1185,16 @@ int pci_load_and_free_saved_state(struct pci_dev *dev,
}
EXPORT_SYMBOL_GPL(pci_load_and_free_saved_state);
+int __weak pcibios_enable_device(struct pci_dev *dev, int bars)
+{
+ return pci_enable_resources(dev, bars);
+}
+
static int do_pci_enable_device(struct pci_dev *dev, int bars)
{
int err;
+ u16 cmd;
+ u8 pin;
err = pci_set_power_state(dev, PCI_D0);
if (err < 0 && err != -EIO)
@@ -1190,6 +1204,17 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
return err;
pci_fixup_device(pci_fixup_enable, dev);
+ if (dev->msi_enabled || dev->msix_enabled)
+ return 0;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin) {
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ if (cmd & PCI_COMMAND_INTX_DISABLE)
+ pci_write_config_word(dev, PCI_COMMAND,
+ cmd & ~PCI_COMMAND_INTX_DISABLE);
+ }
+
return 0;
}
@@ -1611,29 +1636,27 @@ static void pci_pme_list_scan(struct work_struct *work)
struct pci_pme_device *pme_dev, *n;
mutex_lock(&pci_pme_list_mutex);
- if (!list_empty(&pci_pme_list)) {
- list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) {
- if (pme_dev->dev->pme_poll) {
- struct pci_dev *bridge;
-
- bridge = pme_dev->dev->bus->self;
- /*
- * If bridge is in low power state, the
- * configuration space of subordinate devices
- * may be not accessible
- */
- if (bridge && bridge->current_state != PCI_D0)
- continue;
- pci_pme_wakeup(pme_dev->dev, NULL);
- } else {
- list_del(&pme_dev->list);
- kfree(pme_dev);
- }
+ list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) {
+ if (pme_dev->dev->pme_poll) {
+ struct pci_dev *bridge;
+
+ bridge = pme_dev->dev->bus->self;
+ /*
+ * If bridge is in low power state, the
+ * configuration space of subordinate devices
+ * may be not accessible
+ */
+ if (bridge && bridge->current_state != PCI_D0)
+ continue;
+ pci_pme_wakeup(pme_dev->dev, NULL);
+ } else {
+ list_del(&pme_dev->list);
+ kfree(pme_dev);
}
- if (!list_empty(&pci_pme_list))
- schedule_delayed_work(&pci_pme_work,
- msecs_to_jiffies(PME_TIMEOUT));
}
+ if (!list_empty(&pci_pme_list))
+ schedule_delayed_work(&pci_pme_work,
+ msecs_to_jiffies(PME_TIMEOUT));
mutex_unlock(&pci_pme_list_mutex);
}
@@ -2180,21 +2203,18 @@ void pci_request_acs(void)
}
/**
- * pci_enable_acs - enable ACS if hardware support it
+ * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites
* @dev: the PCI device
*/
-void pci_enable_acs(struct pci_dev *dev)
+static int pci_std_enable_acs(struct pci_dev *dev)
{
int pos;
u16 cap;
u16 ctrl;
- if (!pci_acs_enable)
- return;
-
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
if (!pos)
- return;
+ return -ENODEV;
pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
@@ -2212,6 +2232,23 @@ void pci_enable_acs(struct pci_dev *dev)
ctrl |= (cap & PCI_ACS_UF);
pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
+
+ return 0;
+}
+
+/**
+ * pci_enable_acs - enable ACS if hardware support it
+ * @dev: the PCI device
+ */
+void pci_enable_acs(struct pci_dev *dev)
+{
+ if (!pci_acs_enable)
+ return;
+
+ if (!pci_std_enable_acs(dev))
+ return;
+
+ pci_dev_specific_enable_acs(dev);
}
static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
@@ -4237,6 +4274,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
"Rounding up size of resource #%d to %#llx.\n",
i, (unsigned long long)size);
}
+ r->flags |= IORESOURCE_UNSET;
r->end = size - 1;
r->start = 0;
}
@@ -4250,6 +4288,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
r = &dev->resource[i];
if (!(r->flags & IORESOURCE_MEM))
continue;
+ r->flags |= IORESOURCE_UNSET;
r->end = resource_size(r) - 1;
r->start = 0;
}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4df38df224f4..6bd082299e31 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1,8 +1,6 @@
#ifndef DRIVERS_PCI_H
#define DRIVERS_PCI_H
-#include <linux/workqueue.h>
-
#define PCI_CFG_SPACE_SIZE 256
#define PCI_CFG_SPACE_EXP_SIZE 4096
@@ -240,8 +238,6 @@ struct pci_sriov {
struct pci_dev *dev; /* lowest numbered PF */
struct pci_dev *self; /* this PF */
struct mutex lock; /* lock for VF bus */
- struct work_struct mtask; /* VF Migration task */
- u8 __iomem *mstate; /* VF Migration State Array */
};
#ifdef CONFIG_PCI_ATS
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6e34498ec9f0..ef09f5f2fe6c 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -252,6 +252,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
/* Address above 32-bit boundary; disable the BAR */
pci_write_config_dword(dev, pos, 0);
pci_write_config_dword(dev, pos + 4, 0);
+ res->flags |= IORESOURCE_UNSET;
region.start = 0;
region.end = sz64;
bar_disabled = true;
@@ -731,22 +732,6 @@ struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *de
return child;
}
-static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
-{
- struct pci_bus *parent = child->parent;
-
- /* Attempts to fix that up are really dangerous unless
- we're going to re-assign all bus numbers. */
- if (!pcibios_assign_all_busses())
- return;
-
- while (parent->parent && parent->busn_res.end < max) {
- parent->busn_res.end = max;
- pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max);
- parent = parent->parent;
- }
-}
-
/*
* If it's a bridge, configure it and scan the bus behind it.
* For CardBus bridges, we don't scan behind as the devices will
@@ -782,7 +767,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
/* Check if setup is sensible at all */
if (!pass &&
(primary != bus->number || secondary <= bus->number ||
- secondary > subordinate)) {
+ secondary > subordinate || subordinate > bus->busn_res.end)) {
dev_info(&dev->dev, "bridge configuration invalid ([bus %02x-%02x]), reconfiguring\n",
secondary, subordinate);
broken = 1;
@@ -805,11 +790,10 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
goto out;
/*
- * If we already got to this bus through a different bridge,
- * don't re-add it. This can happen with the i450NX chipset.
- *
- * However, we continue to descend down the hierarchy and
- * scan remaining child buses.
+ * The bus might already exist for two reasons: Either we are
+ * rescanning the bus or the bus is reachable through more than
+ * one bridge. The second case can happen with the i450NX
+ * chipset.
*/
child = pci_find_bus(pci_domain_nr(bus), secondary);
if (!child) {
@@ -822,17 +806,19 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
}
cmax = pci_scan_child_bus(child);
- if (cmax > max)
- max = cmax;
- if (child->busn_res.end > max)
- max = child->busn_res.end;
+ if (cmax > subordinate)
+ dev_warn(&dev->dev, "bridge has subordinate %02x but max busn %02x\n",
+ subordinate, cmax);
+ /* subordinate should equal child->busn_res.end */
+ if (subordinate > max)
+ max = subordinate;
} else {
/*
* We need to assign a number to this bus which we always
* do in the second pass.
*/
if (!pass) {
- if (pcibios_assign_all_busses() || broken)
+ if (pcibios_assign_all_busses() || broken || is_cardbus)
/* Temporarily disable forwarding of the
configuration cycles on all bridges in
this bus segment to avoid possible
@@ -844,19 +830,25 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
goto out;
}
+ if (max >= bus->busn_res.end) {
+ dev_warn(&dev->dev, "can't allocate child bus %02x from %pR\n",
+ max, &bus->busn_res);
+ goto out;
+ }
+
/* Clear errors */
pci_write_config_word(dev, PCI_STATUS, 0xffff);
- /* Prevent assigning a bus number that already exists.
- * This can happen when a bridge is hot-plugged, so in
- * this case we only re-scan this bus. */
+ /* The bus will already exist if we are rescanning */
child = pci_find_bus(pci_domain_nr(bus), max+1);
if (!child) {
- child = pci_add_new_bus(bus, dev, ++max);
+ child = pci_add_new_bus(bus, dev, max+1);
if (!child)
goto out;
- pci_bus_insert_busn_res(child, max, 0xff);
+ pci_bus_insert_busn_res(child, max+1,
+ bus->busn_res.end);
}
+ max++;
buses = (buses & 0xff000000)
| ((unsigned int)(child->primary) << 0)
| ((unsigned int)(child->busn_res.start) << 8)
@@ -878,20 +870,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
if (!is_cardbus) {
child->bridge_ctl = bctl;
- /*
- * Adjust subordinate busnr in parent buses.
- * We do this before scanning for children because
- * some devices may not be detected if the bios
- * was lazy.
- */
- pci_fixup_parent_subordinate_busnr(child, max);
- /* Now we can scan all subordinate buses... */
max = pci_scan_child_bus(child);
- /*
- * now fix it up again since we have found
- * the real value of max.
- */
- pci_fixup_parent_subordinate_busnr(child, max);
} else {
/*
* For CardBus bridges, we leave 4 bus numbers
@@ -922,11 +901,15 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
}
}
max += i;
- pci_fixup_parent_subordinate_busnr(child, max);
}
/*
* Set the subordinate bus number to its real value.
*/
+ if (max > bus->busn_res.end) {
+ dev_warn(&dev->dev, "max busn %02x is outside %pR\n",
+ max, &bus->busn_res);
+ max = bus->busn_res.end;
+ }
pci_bus_update_busn_res_end(child, max);
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
}
@@ -1125,10 +1108,10 @@ int pci_setup_device(struct pci_dev *dev)
pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
/*
- * Do the ugly legacy mode stuff here rather than broken chip
- * quirk code. Legacy mode ATA controllers have fixed
- * addresses. These are not always echoed in BAR0-3, and
- * BAR0-3 in a few cases contain junk!
+ * Do the ugly legacy mode stuff here rather than broken chip
+ * quirk code. Legacy mode ATA controllers have fixed
+ * addresses. These are not always echoed in BAR0-3, and
+ * BAR0-3 in a few cases contain junk!
*/
if (class == PCI_CLASS_STORAGE_IDE) {
u8 progif;
@@ -1139,11 +1122,15 @@ int pci_setup_device(struct pci_dev *dev)
res = &dev->resource[0];
res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev->bus, res, &region);
+ dev_info(&dev->dev, "legacy IDE quirk: reg 0x10: %pR\n",
+ res);
region.start = 0x3F6;
region.end = 0x3F6;
res = &dev->resource[1];
res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev->bus, res, &region);
+ dev_info(&dev->dev, "legacy IDE quirk: reg 0x14: %pR\n",
+ res);
}
if ((progif & 4) == 0) {
region.start = 0x170;
@@ -1151,11 +1138,15 @@ int pci_setup_device(struct pci_dev *dev)
res = &dev->resource[2];
res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev->bus, res, &region);
+ dev_info(&dev->dev, "legacy IDE quirk: reg 0x18: %pR\n",
+ res);
region.start = 0x376;
region.end = 0x376;
res = &dev->resource[3];
res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev->bus, res, &region);
+ dev_info(&dev->dev, "legacy IDE quirk: reg 0x1c: %pR\n",
+ res);
}
}
break;
@@ -1835,7 +1826,7 @@ int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
res->flags |= IORESOURCE_PCI_FIXED;
}
- conflict = insert_resource_conflict(parent_res, res);
+ conflict = request_resource_conflict(parent_res, res);
if (conflict)
dev_printk(KERN_DEBUG, &b->dev,
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 5cb726c193de..e7292065a1b1 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -296,6 +296,7 @@ static void quirk_s3_64M(struct pci_dev *dev)
struct resource *r = &dev->resource[0];
if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) {
+ r->flags |= IORESOURCE_UNSET;
r->start = 0;
r->end = 0x3ffffff;
}
@@ -937,6 +938,8 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C
static void quirk_dunord(struct pci_dev *dev)
{
struct resource *r = &dev->resource [1];
+
+ r->flags |= IORESOURCE_UNSET;
r->start = 0;
r->end = 0xffffff;
}
@@ -1740,6 +1743,7 @@ static void quirk_tc86c001_ide(struct pci_dev *dev)
struct resource *r = &dev->resource[0];
if (r->start & 0x8) {
+ r->flags |= IORESOURCE_UNSET;
r->start = 0;
r->end = 0xf;
}
@@ -1769,6 +1773,7 @@ static void quirk_plx_pci9050(struct pci_dev *dev)
dev_info(&dev->dev,
"Re-allocating PLX PCI 9050 BAR %u to length 256 to avoid bit 7 bug\n",
bar);
+ r->flags |= IORESOURCE_UNSET;
r->start = 0;
r->end = 0xff;
}
@@ -3423,6 +3428,61 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
#endif
}
+/*
+ * Many Intel PCH root ports do provide ACS-like features to disable peer
+ * transactions and validate bus numbers in requests, but do not provide an
+ * actual PCIe ACS capability. This is the list of device IDs known to fall
+ * into that category as provided by Intel in Red Hat bugzilla 1037684.
+ */
+static const u16 pci_quirk_intel_pch_acs_ids[] = {
+ /* Ibexpeak PCH */
+ 0x3b42, 0x3b43, 0x3b44, 0x3b45, 0x3b46, 0x3b47, 0x3b48, 0x3b49,
+ 0x3b4a, 0x3b4b, 0x3b4c, 0x3b4d, 0x3b4e, 0x3b4f, 0x3b50, 0x3b51,
+ /* Cougarpoint PCH */
+ 0x1c10, 0x1c11, 0x1c12, 0x1c13, 0x1c14, 0x1c15, 0x1c16, 0x1c17,
+ 0x1c18, 0x1c19, 0x1c1a, 0x1c1b, 0x1c1c, 0x1c1d, 0x1c1e, 0x1c1f,
+ /* Pantherpoint PCH */
+ 0x1e10, 0x1e11, 0x1e12, 0x1e13, 0x1e14, 0x1e15, 0x1e16, 0x1e17,
+ 0x1e18, 0x1e19, 0x1e1a, 0x1e1b, 0x1e1c, 0x1e1d, 0x1e1e, 0x1e1f,
+ /* Lynxpoint-H PCH */
+ 0x8c10, 0x8c11, 0x8c12, 0x8c13, 0x8c14, 0x8c15, 0x8c16, 0x8c17,
+ 0x8c18, 0x8c19, 0x8c1a, 0x8c1b, 0x8c1c, 0x8c1d, 0x8c1e, 0x8c1f,
+ /* Lynxpoint-LP PCH */
+ 0x9c10, 0x9c11, 0x9c12, 0x9c13, 0x9c14, 0x9c15, 0x9c16, 0x9c17,
+ 0x9c18, 0x9c19, 0x9c1a, 0x9c1b,
+ /* Wildcat PCH */
+ 0x9c90, 0x9c91, 0x9c92, 0x9c93, 0x9c94, 0x9c95, 0x9c96, 0x9c97,
+ 0x9c98, 0x9c99, 0x9c9a, 0x9c9b,
+};
+
+static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)
+{
+ int i;
+
+ /* Filter out a few obvious non-matches first */
+ if (!pci_is_pcie(dev) || pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT)
+ return false;
+
+ for (i = 0; i < ARRAY_SIZE(pci_quirk_intel_pch_acs_ids); i++)
+ if (pci_quirk_intel_pch_acs_ids[i] == dev->device)
+ return true;
+
+ return false;
+}
+
+#define INTEL_PCH_ACS_FLAGS (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_SV)
+
+static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags)
+{
+ u16 flags = dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK ?
+ INTEL_PCH_ACS_FLAGS : 0;
+
+ if (!pci_quirk_intel_pch_acs_match(dev))
+ return -ENOTTY;
+
+ return acs_flags & ~flags ? 0 : 1;
+}
+
static const struct pci_dev_acs_enabled {
u16 vendor;
u16 device;
@@ -3434,6 +3494,7 @@ static const struct pci_dev_acs_enabled {
{ PCI_VENDOR_ID_ATI, 0x439d, pci_quirk_amd_sb_acs },
{ PCI_VENDOR_ID_ATI, 0x4384, pci_quirk_amd_sb_acs },
{ PCI_VENDOR_ID_ATI, 0x4399, pci_quirk_amd_sb_acs },
+ { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
{ 0 }
};
@@ -3461,3 +3522,132 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
return -ENOTTY;
}
+
+/* Config space offset of Root Complex Base Address register */
+#define INTEL_LPC_RCBA_REG 0xf0
+/* 31:14 RCBA address */
+#define INTEL_LPC_RCBA_MASK 0xffffc000
+/* RCBA Enable */
+#define INTEL_LPC_RCBA_ENABLE (1 << 0)
+
+/* Backbone Scratch Pad Register */
+#define INTEL_BSPR_REG 0x1104
+/* Backbone Peer Non-Posted Disable */
+#define INTEL_BSPR_REG_BPNPD (1 << 8)
+/* Backbone Peer Posted Disable */
+#define INTEL_BSPR_REG_BPPD (1 << 9)
+
+/* Upstream Peer Decode Configuration Register */
+#define INTEL_UPDCR_REG 0x1114
+/* 5:0 Peer Decode Enable bits */
+#define INTEL_UPDCR_REG_MASK 0x3f
+
+static int pci_quirk_enable_intel_lpc_acs(struct pci_dev *dev)
+{
+ u32 rcba, bspr, updcr;
+ void __iomem *rcba_mem;
+
+ /*
+ * Read the RCBA register from the LPC (D31:F0). PCH root ports
+ * are D28:F* and therefore get probed before LPC, thus we can't
+ * use pci_get_slot/pci_read_config_dword here.
+ */
+ pci_bus_read_config_dword(dev->bus, PCI_DEVFN(31, 0),
+ INTEL_LPC_RCBA_REG, &rcba);
+ if (!(rcba & INTEL_LPC_RCBA_ENABLE))
+ return -EINVAL;
+
+ rcba_mem = ioremap_nocache(rcba & INTEL_LPC_RCBA_MASK,
+ PAGE_ALIGN(INTEL_UPDCR_REG));
+ if (!rcba_mem)
+ return -ENOMEM;
+
+ /*
+ * The BSPR can disallow peer cycles, but it's set by soft strap and
+ * therefore read-only. If both posted and non-posted peer cycles are
+ * disallowed, we're ok. If either are allowed, then we need to use
+ * the UPDCR to disable peer decodes for each port. This provides the
+ * PCIe ACS equivalent of PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF
+ */
+ bspr = readl(rcba_mem + INTEL_BSPR_REG);
+ bspr &= INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD;
+ if (bspr != (INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD)) {
+ updcr = readl(rcba_mem + INTEL_UPDCR_REG);
+ if (updcr & INTEL_UPDCR_REG_MASK) {
+ dev_info(&dev->dev, "Disabling UPDCR peer decodes\n");
+ updcr &= ~INTEL_UPDCR_REG_MASK;
+ writel(updcr, rcba_mem + INTEL_UPDCR_REG);
+ }
+ }
+
+ iounmap(rcba_mem);
+ return 0;
+}
+
+/* Miscellaneous Port Configuration register */
+#define INTEL_MPC_REG 0xd8
+/* MPC: Invalid Receive Bus Number Check Enable */
+#define INTEL_MPC_REG_IRBNCE (1 << 26)
+
+static void pci_quirk_enable_intel_rp_mpc_acs(struct pci_dev *dev)
+{
+ u32 mpc;
+
+ /*
+ * When enabled, the IRBNCE bit of the MPC register enables the
+ * equivalent of PCI ACS Source Validation (PCI_ACS_SV), which
+ * ensures that requester IDs fall within the bus number range
+ * of the bridge. Enable if not already.
+ */
+ pci_read_config_dword(dev, INTEL_MPC_REG, &mpc);
+ if (!(mpc & INTEL_MPC_REG_IRBNCE)) {
+ dev_info(&dev->dev, "Enabling MPC IRBNCE\n");
+ mpc |= INTEL_MPC_REG_IRBNCE;
+ pci_write_config_word(dev, INTEL_MPC_REG, mpc);
+ }
+}
+
+static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev)
+{
+ if (!pci_quirk_intel_pch_acs_match(dev))
+ return -ENOTTY;
+
+ if (pci_quirk_enable_intel_lpc_acs(dev)) {
+ dev_warn(&dev->dev, "Failed to enable Intel PCH ACS quirk\n");
+ return 0;
+ }
+
+ pci_quirk_enable_intel_rp_mpc_acs(dev);
+
+ dev->dev_flags |= PCI_DEV_FLAGS_ACS_ENABLED_QUIRK;
+
+ dev_info(&dev->dev, "Intel PCH root port ACS workaround enabled\n");
+
+ return 0;
+}
+
+static const struct pci_dev_enable_acs {
+ u16 vendor;
+ u16 device;
+ int (*enable_acs)(struct pci_dev *dev);
+} pci_dev_enable_acs[] = {
+ { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_enable_intel_pch_acs },
+ { 0 }
+};
+
+void pci_dev_specific_enable_acs(struct pci_dev *dev)
+{
+ const struct pci_dev_enable_acs *i;
+ int ret;
+
+ for (i = pci_dev_enable_acs; i->enable_acs; i++) {
+ if ((i->vendor == dev->vendor ||
+ i->vendor == (u16)PCI_ANY_ID) &&
+ (i->device == dev->device ||
+ i->device == (u16)PCI_ANY_ID)) {
+ ret = i->enable_acs(dev);
+ if (ret >= 0)
+ return;
+ }
+ }
+}
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index 5d595724e5f4..c1839450d4d6 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -197,8 +197,10 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
void pci_cleanup_rom(struct pci_dev *pdev)
{
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
+
if (res->flags & IORESOURCE_ROM_COPY) {
kfree((void*)(unsigned long)res->start);
+ res->flags |= IORESOURCE_UNSET;
res->flags &= ~IORESOURCE_ROM_COPY;
res->start = 0;
res->end = 0;
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 3ff2ac7c14e2..4a1b972efe7f 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -54,14 +54,14 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
{
- struct pci_bus* child;
- struct list_head *tmp;
+ struct pci_bus *child;
+ struct pci_bus *tmp;
if(bus->number == busnr)
return bus;
- list_for_each(tmp, &bus->children) {
- child = pci_do_find_bus(pci_bus_b(tmp), busnr);
+ list_for_each_entry(tmp, &bus->children, node) {
+ child = pci_do_find_bus(tmp, busnr);
if(child)
return child;
}
@@ -111,7 +111,7 @@ pci_find_next_bus(const struct pci_bus *from)
down_read(&pci_bus_sem);
n = from ? from->node.next : pci_root_buses.next;
if (n != &pci_root_buses)
- b = pci_bus_b(n);
+ b = list_entry(n, struct pci_bus, node);
up_read(&pci_bus_sem);
return b;
}
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 5c060b152ce6..7eed671d5586 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -44,6 +44,9 @@ void pci_update_resource(struct pci_dev *dev, int resno)
if (!res->flags)
return;
+ if (res->flags & IORESOURCE_UNSET)
+ return;
+
/*
* Ignore non-moveable resources. This might be legacy resources for
* which no functional BAR register exists or another important
@@ -101,11 +104,6 @@ void pci_update_resource(struct pci_dev *dev, int resno)
if (disable)
pci_write_config_word(dev, PCI_COMMAND, cmd);
-
- res->flags &= ~IORESOURCE_UNSET;
- dev_dbg(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx])\n",
- resno, res, (unsigned long long)region.start,
- (unsigned long long)region.end);
}
int pci_claim_resource(struct pci_dev *dev, int resource)
@@ -113,18 +111,23 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
struct resource *res = &dev->resource[resource];
struct resource *root, *conflict;
+ if (res->flags & IORESOURCE_UNSET) {
+ dev_info(&dev->dev, "can't claim BAR %d %pR: no address assigned\n",
+ resource, res);
+ return -EINVAL;
+ }
+
root = pci_find_parent_resource(dev, res);
if (!root) {
- dev_info(&dev->dev, "no compatible bridge window for %pR\n",
- res);
+ dev_info(&dev->dev, "can't claim BAR %d %pR: no compatible bridge window\n",
+ resource, res);
return -EINVAL;
}
conflict = request_resource_conflict(root, res);
if (conflict) {
- dev_info(&dev->dev,
- "address space collision: %pR conflicts with %s %pR\n",
- res, conflict->name, conflict);
+ dev_info(&dev->dev, "can't claim BAR %d %pR: address conflict with %s %pR\n",
+ resource, res, conflict->name, conflict);
return -EBUSY;
}
@@ -263,6 +266,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
resource_size_t align, size;
int ret;
+ res->flags |= IORESOURCE_UNSET;
align = pci_resource_alignment(dev, res);
if (!align) {
dev_info(&dev->dev, "BAR %d: can't assign %pR "
@@ -282,6 +286,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
ret = pci_revert_fw_address(res, dev, resno, size);
if (!ret) {
+ res->flags &= ~IORESOURCE_UNSET;
res->flags &= ~IORESOURCE_STARTALIGN;
dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
if (resno < PCI_BRIDGE_RESOURCES)
@@ -297,6 +302,7 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
resource_size_t new_size;
int ret;
+ res->flags |= IORESOURCE_UNSET;
if (!res->parent) {
dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resource %pR "
"\n", resno, res);
@@ -307,6 +313,7 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
new_size = resource_size(res) + addsize;
ret = _pci_assign_resource(dev, resno, new_size, min_align);
if (!ret) {
+ res->flags &= ~IORESOURCE_UNSET;
res->flags &= ~IORESOURCE_STARTALIGN;
dev_info(&dev->dev, "BAR %d: reassigned %pR\n", resno, res);
if (resno < PCI_BRIDGE_RESOURCES)
@@ -336,9 +343,15 @@ int pci_enable_resources(struct pci_dev *dev, int mask)
(!(r->flags & IORESOURCE_ROM_ENABLE)))
continue;
+ if (r->flags & IORESOURCE_UNSET) {
+ dev_err(&dev->dev, "can't enable device: BAR %d %pR not assigned\n",
+ i, r);
+ return -EINVAL;
+ }
+
if (!r->parent) {
- dev_err(&dev->dev, "device not available "
- "(can't reserve %pR)\n", r);
+ dev_err(&dev->dev, "can't enable device: BAR %d %pR not claimed\n",
+ i, r);
return -EINVAL;
}
diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c
index 6eecd7cddf57..54d3089d157b 100644
--- a/drivers/pcmcia/sa11xx_base.c
+++ b/drivers/pcmcia/sa11xx_base.c
@@ -125,9 +125,6 @@ sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
if (freqs->new < freqs->old)
sa1100_pcmcia_set_mecr(skt, freqs->new);
break;
- case CPUFREQ_RESUMECHANGE:
- sa1100_pcmcia_set_mecr(skt, freqs->new);
- break;
}
return 0;
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 8485761e76af..946f90ef6020 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -1076,7 +1076,7 @@ static void yenta_config_init(struct yenta_socket *socket)
*/
static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
{
- struct list_head *tmp;
+ struct pci_bus *sibling;
unsigned char upper_limit;
/*
* We only check and fix the parent bridge: All systems which need
@@ -1095,18 +1095,18 @@ static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
/* stay within the limits of the bus range of the parent: */
upper_limit = bridge_to_fix->parent->busn_res.end;
- /* check the bus ranges of all silbling bridges to prevent overlap */
- list_for_each(tmp, &bridge_to_fix->parent->children) {
- struct pci_bus *silbling = pci_bus_b(tmp);
+ /* check the bus ranges of all sibling bridges to prevent overlap */
+ list_for_each_entry(sibling, &bridge_to_fix->parent->children,
+ node) {
/*
- * If the silbling has a higher secondary bus number
+ * If the sibling has a higher secondary bus number
* and it's secondary is equal or smaller than our
* current upper limit, set the new upper limit to
- * the bus number below the silbling's range:
+ * the bus number below the sibling's range:
*/
- if (silbling->busn_res.start > bridge_to_fix->busn_res.end
- && silbling->busn_res.start <= upper_limit)
- upper_limit = silbling->busn_res.start - 1;
+ if (sibling->busn_res.start > bridge_to_fix->busn_res.end
+ && sibling->busn_res.start <= upper_limit)
+ upper_limit = sibling->busn_res.start - 1;
}
/* Show that the wanted subordinate number is not possible: */
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index afa2354f6600..8d3c49cc500f 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -5,7 +5,7 @@
menu "PHY Subsystem"
config GENERIC_PHY
- tristate "PHY Core"
+ bool "PHY Core"
help
Generic PHY support.
@@ -16,30 +16,56 @@ config GENERIC_PHY
framework should select this config.
config PHY_EXYNOS_MIPI_VIDEO
- depends on HAS_IOMEM
tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver"
+ depends on HAS_IOMEM
+ depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
+ select GENERIC_PHY
+ default y if ARCH_S5PV210 || ARCH_EXYNOS
help
Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P
and EXYNOS SoCs.
config PHY_MVEBU_SATA
def_bool y
- depends on ARCH_KIRKWOOD || ARCH_DOVE
+ depends on ARCH_KIRKWOOD || ARCH_DOVE || MACH_DOVE
depends on OF
select GENERIC_PHY
+config OMAP_CONTROL_PHY
+ tristate "OMAP CONTROL PHY Driver"
+ help
+ Enable this to add support for the PHY part present in the control
+ module. This driver has API to power on the USB2 PHY and to write to
+ the mailbox. The mailbox is present only in omap4 and the register to
+ power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
+ additional register to power on USB3 PHY/SATA PHY/PCIE PHY
+ (PIPE3 PHY).
+
config OMAP_USB2
tristate "OMAP USB2 PHY Driver"
depends on ARCH_OMAP2PLUS
depends on USB_PHY
select GENERIC_PHY
- select OMAP_CONTROL_USB
+ select OMAP_CONTROL_PHY
+ depends on OMAP_OCP2SCP
help
Enable this to support the transceiver that is part of SOC. This
driver takes care of all the PHY functionality apart from comparator.
The USB OTG controller communicates with the comparator using this
driver.
+config TI_PIPE3
+ tristate "TI PIPE3 PHY Driver"
+ depends on ARCH_OMAP2PLUS || COMPILE_TEST
+ select GENERIC_PHY
+ select OMAP_CONTROL_PHY
+ depends on OMAP_OCP2SCP
+ help
+ Enable this to support the PIPE3 PHY that is part of TI SOCs. This
+ driver takes care of all the PHY functionality apart from comparator.
+ This driver interacts with the "OMAP Control PHY Driver" to power
+ on/off the PHY.
+
config TWL4030_USB
tristate "TWL4030 USB Transceiver Driver"
depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
@@ -54,6 +80,8 @@ config TWL4030_USB
config PHY_EXYNOS_DP_VIDEO
tristate "EXYNOS SoC series Display Port PHY driver"
depends on OF
+ depends on ARCH_EXYNOS || COMPILE_TEST
+ default ARCH_EXYNOS
select GENERIC_PHY
help
Support for Display Port PHY found on Samsung EXYNOS SoCs.
@@ -61,7 +89,81 @@ config PHY_EXYNOS_DP_VIDEO
config BCM_KONA_USB2_PHY
tristate "Broadcom Kona USB2 PHY Driver"
depends on GENERIC_PHY
+ depends on HAS_IOMEM
help
Enable this to support the Broadcom Kona USB 2.0 PHY.
+config PHY_EXYNOS5250_SATA
+ tristate "Exynos5250 Sata SerDes/PHY driver"
+ depends on SOC_EXYNOS5250
+ depends on HAS_IOMEM
+ depends on OF
+ select GENERIC_PHY
+ select I2C
+ select I2C_S3C2410
+ select MFD_SYSCON
+ help
+ Enable this to support SATA SerDes/Phy found on Samsung's
+ Exynos5250 based SoCs.This SerDes/Phy supports SATA 1.5 Gb/s,
+ SATA 3.0 Gb/s, SATA 6.0 Gb/s speeds. It supports one SATA host
+ port to accept one SATA device.
+
+config PHY_SUN4I_USB
+ tristate "Allwinner sunxi SoC USB PHY driver"
+ depends on ARCH_SUNXI && HAS_IOMEM && OF
+ select GENERIC_PHY
+ help
+ Enable this to support the transceiver that is part of Allwinner
+ sunxi SoCs.
+
+ This driver controls the entire USB PHY block, both the USB OTG
+ parts, as well as the 2 regular USB 2 host PHYs.
+
+config PHY_SAMSUNG_USB2
+ tristate "Samsung USB 2.0 PHY driver"
+ select GENERIC_PHY
+ select MFD_SYSCON
+ help
+ Enable this to support the Samsung USB 2.0 PHY driver for Samsung
+ SoCs. This driver provides the interface for USB 2.0 PHY. Support for
+ particular SoCs has to be enabled in addition to this driver. Number
+ and type of supported phys depends on the SoC.
+
+config PHY_EXYNOS4210_USB2
+ bool "Support for Exynos 4210"
+ depends on PHY_SAMSUNG_USB2
+ depends on CPU_EXYNOS4210
+ help
+ Enable USB PHY support for Exynos 4210. This option requires that
+ Samsung USB 2.0 PHY driver is enabled and means that support for this
+ particular SoC is compiled in the driver. In case of Exynos 4210 four
+ phys are available - device, host, HSIC0 and HSIC1.
+
+config PHY_EXYNOS4X12_USB2
+ bool "Support for Exynos 4x12"
+ depends on PHY_SAMSUNG_USB2
+ depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
+ help
+ Enable USB PHY support for Exynos 4x12. This option requires that
+ Samsung USB 2.0 PHY driver is enabled and means that support for this
+ particular SoC is compiled in the driver. In case of Exynos 4x12 four
+ phys are available - device, host, HSIC0 and HSIC1.
+
+config PHY_EXYNOS5250_USB2
+ bool "Support for Exynos 5250"
+ depends on PHY_SAMSUNG_USB2
+ depends on SOC_EXYNOS5250
+ help
+ Enable USB PHY support for Exynos 5250. This option requires that
+ Samsung USB 2.0 PHY driver is enabled and means that support for this
+ particular SoC is compiled in the driver. In case of Exynos 5250 four
+ phys are available - device, host, HSIC0 and HSIC.
+
+config PHY_XGENE
+ tristate "APM X-Gene 15Gbps PHY support"
+ depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST)
+ select GENERIC_PHY
+ help
+ This option enables support for APM X-Gene SoC multi-purpose PHY.
+
endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index b57c25371cca..2faf78edc864 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -7,5 +7,14 @@ obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o
obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o
obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o
obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
+obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o
obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o
+obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o
obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
+obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o
+obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
+obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-samsung-usb2.o
+obj-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o
+obj-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o
+obj-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o
+obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
diff --git a/drivers/phy/phy-bcm-kona-usb2.c b/drivers/phy/phy-bcm-kona-usb2.c
index efc5c1a13a5d..e94f5a6a5645 100644
--- a/drivers/phy/phy-bcm-kona-usb2.c
+++ b/drivers/phy/phy-bcm-kona-usb2.c
@@ -128,10 +128,8 @@ static int bcm_kona_usb2_probe(struct platform_device *pdev)
phy_provider = devm_of_phy_provider_register(dev,
of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
- return 0;
+ return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id bcm_kona_usb2_dt_ids[] = {
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 5f5b0f4be5be..623b71c54b3e 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -176,6 +176,8 @@ int phy_init(struct phy *phy)
dev_err(&phy->dev, "phy init failed --> %d\n", ret);
goto out;
}
+ } else {
+ ret = 0; /* Override possible ret == -ENOTSUPP */
}
++phy->init_count;
@@ -232,6 +234,8 @@ int phy_power_on(struct phy *phy)
dev_err(&phy->dev, "phy poweron failed --> %d\n", ret);
goto out;
}
+ } else {
+ ret = 0; /* Override possible ret == -ENOTSUPP */
}
++phy->power_count;
mutex_unlock(&phy->mutex);
@@ -270,8 +274,8 @@ int phy_power_off(struct phy *phy)
EXPORT_SYMBOL_GPL(phy_power_off);
/**
- * of_phy_get() - lookup and obtain a reference to a phy by phandle
- * @dev: device that requests this phy
+ * _of_phy_get() - lookup and obtain a reference to a phy by phandle
+ * @np: device_node for which to get the phy
* @index: the index of the phy
*
* Returns the phy associated with the given phandle value,
@@ -280,20 +284,17 @@ EXPORT_SYMBOL_GPL(phy_power_off);
* not yet loaded. This function uses of_xlate call back function provided
* while registering the phy_provider to find the phy instance.
*/
-static struct phy *of_phy_get(struct device *dev, int index)
+static struct phy *_of_phy_get(struct device_node *np, int index)
{
int ret;
struct phy_provider *phy_provider;
struct phy *phy = NULL;
struct of_phandle_args args;
- ret = of_parse_phandle_with_args(dev->of_node, "phys", "#phy-cells",
+ ret = of_parse_phandle_with_args(np, "phys", "#phy-cells",
index, &args);
- if (ret) {
- dev_dbg(dev, "failed to get phy in %s node\n",
- dev->of_node->full_name);
+ if (ret)
return ERR_PTR(-ENODEV);
- }
mutex_lock(&phy_provider_mutex);
phy_provider = of_phy_provider_lookup(args.np);
@@ -313,6 +314,36 @@ err0:
}
/**
+ * of_phy_get() - lookup and obtain a reference to a phy using a device_node.
+ * @np: device_node for which to get the phy
+ * @con_id: name of the phy from device's point of view
+ *
+ * Returns the phy driver, after getting a refcount to it; or
+ * -ENODEV if there is no such phy. The caller is responsible for
+ * calling phy_put() to release that count.
+ */
+struct phy *of_phy_get(struct device_node *np, const char *con_id)
+{
+ struct phy *phy = NULL;
+ int index = 0;
+
+ if (con_id)
+ index = of_property_match_string(np, "phy-names", con_id);
+
+ phy = _of_phy_get(np, index);
+ if (IS_ERR(phy))
+ return phy;
+
+ if (!try_module_get(phy->ops->owner))
+ return ERR_PTR(-EPROBE_DEFER);
+
+ get_device(&phy->dev);
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(of_phy_get);
+
+/**
* phy_put() - release the PHY
* @phy: the phy returned by phy_get()
*
@@ -403,18 +434,12 @@ struct phy *phy_get(struct device *dev, const char *string)
if (dev->of_node) {
index = of_property_match_string(dev->of_node, "phy-names",
string);
- phy = of_phy_get(dev, index);
- if (IS_ERR(phy)) {
- dev_err(dev, "unable to find phy\n");
- return phy;
- }
+ phy = _of_phy_get(dev->of_node, index);
} else {
phy = phy_lookup(dev, string);
- if (IS_ERR(phy)) {
- dev_err(dev, "unable to find phy\n");
- return phy;
- }
}
+ if (IS_ERR(phy))
+ return phy;
if (!try_module_get(phy->ops->owner))
return ERR_PTR(-EPROBE_DEFER);
@@ -501,6 +526,37 @@ struct phy *devm_phy_optional_get(struct device *dev, const char *string)
EXPORT_SYMBOL_GPL(devm_phy_optional_get);
/**
+ * devm_of_phy_get() - lookup and obtain a reference to a phy.
+ * @dev: device that requests this phy
+ * @np: node containing the phy
+ * @con_id: name of the phy from device's point of view
+ *
+ * Gets the phy using of_phy_get(), and associates a device with it using
+ * devres. On driver detach, release function is invoked on the devres data,
+ * then, devres data is freed.
+ */
+struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
+ const char *con_id)
+{
+ struct phy **ptr, *phy;
+
+ ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ phy = of_phy_get(np, con_id);
+ if (!IS_ERR(phy)) {
+ *ptr = phy;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(devm_of_phy_get);
+
+/**
* phy_create() - create a new phy
* @dev: device that is creating the new phy
* @ops: function pointers for performing phy operations
diff --git a/drivers/phy/phy-exynos-dp-video.c b/drivers/phy/phy-exynos-dp-video.c
index 1dbe6ce7b2ce..0786fef842e7 100644
--- a/drivers/phy/phy-exynos-dp-video.c
+++ b/drivers/phy/phy-exynos-dp-video.c
@@ -76,10 +76,6 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)
if (IS_ERR(state->regs))
return PTR_ERR(state->regs);
- phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
-
phy = devm_phy_create(dev, &exynos_dp_video_phy_ops, NULL);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create Display Port PHY\n");
@@ -87,6 +83,10 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)
}
phy_set_drvdata(phy, state);
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
return 0;
}
diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c
index 0c5efab11af1..7f139326a642 100644
--- a/drivers/phy/phy-exynos-mipi-video.c
+++ b/drivers/phy/phy-exynos-mipi-video.c
@@ -134,11 +134,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
dev_set_drvdata(dev, state);
spin_lock_init(&state->slock);
- phy_provider = devm_of_phy_provider_register(dev,
- exynos_mipi_video_phy_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
-
for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
struct phy *phy = devm_phy_create(dev,
&exynos_mipi_video_phy_ops, NULL);
@@ -152,6 +147,11 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
phy_set_drvdata(phy, &state->phys[i]);
}
+ phy_provider = devm_of_phy_provider_register(dev,
+ exynos_mipi_video_phy_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
return 0;
}
diff --git a/drivers/phy/phy-exynos4210-usb2.c b/drivers/phy/phy-exynos4210-usb2.c
new file mode 100644
index 000000000000..236a52ad94eb
--- /dev/null
+++ b/drivers/phy/phy-exynos4210-usb2.c
@@ -0,0 +1,261 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+
+/* PHY power control */
+#define EXYNOS_4210_UPHYPWR 0x0
+
+#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND BIT(0)
+#define EXYNOS_4210_UPHYPWR_PHY0_PWR BIT(3)
+#define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR BIT(4)
+#define EXYNOS_4210_UPHYPWR_PHY0_SLEEP BIT(5)
+#define EXYNOS_4210_UPHYPWR_PHY0 ( \
+ EXYNOS_4210_UPHYPWR_PHY0_SUSPEND | \
+ EXYNOS_4210_UPHYPWR_PHY0_PWR | \
+ EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR | \
+ EXYNOS_4210_UPHYPWR_PHY0_SLEEP)
+
+#define EXYNOS_4210_UPHYPWR_PHY1_SUSPEND BIT(6)
+#define EXYNOS_4210_UPHYPWR_PHY1_PWR BIT(7)
+#define EXYNOS_4210_UPHYPWR_PHY1_SLEEP BIT(8)
+#define EXYNOS_4210_UPHYPWR_PHY1 ( \
+ EXYNOS_4210_UPHYPWR_PHY1_SUSPEND | \
+ EXYNOS_4210_UPHYPWR_PHY1_PWR | \
+ EXYNOS_4210_UPHYPWR_PHY1_SLEEP)
+
+#define EXYNOS_4210_UPHYPWR_HSIC0_SUSPEND BIT(9)
+#define EXYNOS_4210_UPHYPWR_HSIC0_SLEEP BIT(10)
+#define EXYNOS_4210_UPHYPWR_HSIC0 ( \
+ EXYNOS_4210_UPHYPWR_HSIC0_SUSPEND | \
+ EXYNOS_4210_UPHYPWR_HSIC0_SLEEP)
+
+#define EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND BIT(11)
+#define EXYNOS_4210_UPHYPWR_HSIC1_SLEEP BIT(12)
+#define EXYNOS_4210_UPHYPWR_HSIC1 ( \
+ EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND | \
+ EXYNOS_4210_UPHYPWR_HSIC1_SLEEP)
+
+/* PHY clock control */
+#define EXYNOS_4210_UPHYCLK 0x4
+
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK (0x3 << 0)
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET 0
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ (0x0 << 0)
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ (0x3 << 0)
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ (0x2 << 0)
+
+#define EXYNOS_4210_UPHYCLK_PHY0_ID_PULLUP BIT(2)
+#define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON BIT(4)
+#define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON BIT(7)
+
+/* PHY reset control */
+#define EXYNOS_4210_UPHYRST 0x8
+
+#define EXYNOS_4210_URSTCON_PHY0 BIT(0)
+#define EXYNOS_4210_URSTCON_OTG_HLINK BIT(1)
+#define EXYNOS_4210_URSTCON_OTG_PHYLINK BIT(2)
+#define EXYNOS_4210_URSTCON_PHY1_ALL BIT(3)
+#define EXYNOS_4210_URSTCON_PHY1_P0 BIT(4)
+#define EXYNOS_4210_URSTCON_PHY1_P1P2 BIT(5)
+#define EXYNOS_4210_URSTCON_HOST_LINK_ALL BIT(6)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P0 BIT(7)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P1 BIT(8)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P2 BIT(9)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET 0x704
+#define EXYNOS_4210_USB_ISOL_DEVICE BIT(0)
+#define EXYNOS_4210_USB_ISOL_HOST_OFFSET 0x708
+#define EXYNOS_4210_USB_ISOL_HOST BIT(0)
+
+/* USBYPHY1 Floating prevention */
+#define EXYNOS_4210_UPHY1CON 0x34
+#define EXYNOS_4210_UPHY1CON_FLOAT_PREVENTION 0x1
+
+/* Mode switching SUB Device <-> Host */
+#define EXYNOS_4210_MODE_SWITCH_OFFSET 0x21c
+#define EXYNOS_4210_MODE_SWITCH_MASK 1
+#define EXYNOS_4210_MODE_SWITCH_DEVICE 0
+#define EXYNOS_4210_MODE_SWITCH_HOST 1
+
+enum exynos4210_phy_id {
+ EXYNOS4210_DEVICE,
+ EXYNOS4210_HOST,
+ EXYNOS4210_HSIC0,
+ EXYNOS4210_HSIC1,
+ EXYNOS4210_NUM_PHYS,
+};
+
+/*
+ * exynos4210_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int exynos4210_rate_to_clk(unsigned long rate, u32 *reg)
+{
+ switch (rate) {
+ case 12 * MHZ:
+ *reg = EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ;
+ break;
+ case 24 * MHZ:
+ *reg = EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ;
+ break;
+ case 48 * MHZ:
+ *reg = EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void exynos4210_isol(struct samsung_usb2_phy_instance *inst, bool on)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 offset;
+ u32 mask;
+
+ switch (inst->cfg->id) {
+ case EXYNOS4210_DEVICE:
+ offset = EXYNOS_4210_USB_ISOL_DEVICE_OFFSET;
+ mask = EXYNOS_4210_USB_ISOL_DEVICE;
+ break;
+ case EXYNOS4210_HOST:
+ offset = EXYNOS_4210_USB_ISOL_HOST_OFFSET;
+ mask = EXYNOS_4210_USB_ISOL_HOST;
+ break;
+ default:
+ return;
+ };
+
+ regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 rstbits = 0;
+ u32 phypwr = 0;
+ u32 rst;
+ u32 pwr;
+ u32 clk;
+
+ switch (inst->cfg->id) {
+ case EXYNOS4210_DEVICE:
+ phypwr = EXYNOS_4210_UPHYPWR_PHY0;
+ rstbits = EXYNOS_4210_URSTCON_PHY0;
+ break;
+ case EXYNOS4210_HOST:
+ phypwr = EXYNOS_4210_UPHYPWR_PHY1;
+ rstbits = EXYNOS_4210_URSTCON_PHY1_ALL |
+ EXYNOS_4210_URSTCON_PHY1_P0 |
+ EXYNOS_4210_URSTCON_PHY1_P1P2 |
+ EXYNOS_4210_URSTCON_HOST_LINK_ALL |
+ EXYNOS_4210_URSTCON_HOST_LINK_P0;
+ writel(on, drv->reg_phy + EXYNOS_4210_UPHY1CON);
+ break;
+ case EXYNOS4210_HSIC0:
+ phypwr = EXYNOS_4210_UPHYPWR_HSIC0;
+ rstbits = EXYNOS_4210_URSTCON_PHY1_P1P2 |
+ EXYNOS_4210_URSTCON_HOST_LINK_P1;
+ break;
+ case EXYNOS4210_HSIC1:
+ phypwr = EXYNOS_4210_UPHYPWR_HSIC1;
+ rstbits = EXYNOS_4210_URSTCON_PHY1_P1P2 |
+ EXYNOS_4210_URSTCON_HOST_LINK_P2;
+ break;
+ };
+
+ if (on) {
+ clk = readl(drv->reg_phy + EXYNOS_4210_UPHYCLK);
+ clk &= ~EXYNOS_4210_UPHYCLK_PHYFSEL_MASK;
+ clk |= drv->ref_reg_val << EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET;
+ writel(clk, drv->reg_phy + EXYNOS_4210_UPHYCLK);
+
+ pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
+ pwr &= ~phypwr;
+ writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
+
+ rst = readl(drv->reg_phy + EXYNOS_4210_UPHYRST);
+ rst |= rstbits;
+ writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
+ udelay(10);
+ rst &= ~rstbits;
+ writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
+ /* The following delay is necessary for the reset sequence to be
+ * completed */
+ udelay(80);
+ } else {
+ pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
+ pwr |= phypwr;
+ writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
+ }
+}
+
+static int exynos4210_power_on(struct samsung_usb2_phy_instance *inst)
+{
+ /* Order of initialisation is important - first power then isolation */
+ exynos4210_phy_pwr(inst, 1);
+ exynos4210_isol(inst, 0);
+
+ return 0;
+}
+
+static int exynos4210_power_off(struct samsung_usb2_phy_instance *inst)
+{
+ exynos4210_isol(inst, 1);
+ exynos4210_phy_pwr(inst, 0);
+
+ return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos4210_phys[] = {
+ {
+ .label = "device",
+ .id = EXYNOS4210_DEVICE,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {
+ .label = "host",
+ .id = EXYNOS4210_HOST,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {
+ .label = "hsic0",
+ .id = EXYNOS4210_HSIC0,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {
+ .label = "hsic1",
+ .id = EXYNOS4210_HSIC1,
+ .power_on = exynos4210_power_on,
+ .power_off = exynos4210_power_off,
+ },
+ {},
+};
+
+const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
+ .has_mode_switch = 0,
+ .num_phys = EXYNOS4210_NUM_PHYS,
+ .phys = exynos4210_phys,
+ .rate_to_clk = exynos4210_rate_to_clk,
+};
diff --git a/drivers/phy/phy-exynos4x12-usb2.c b/drivers/phy/phy-exynos4x12-usb2.c
new file mode 100644
index 000000000000..d92a7cc5698a
--- /dev/null
+++ b/drivers/phy/phy-exynos4x12-usb2.c
@@ -0,0 +1,328 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4x12 support
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+
+/* PHY power control */
+#define EXYNOS_4x12_UPHYPWR 0x0
+
+#define EXYNOS_4x12_UPHYPWR_PHY0_SUSPEND BIT(0)
+#define EXYNOS_4x12_UPHYPWR_PHY0_PWR BIT(3)
+#define EXYNOS_4x12_UPHYPWR_PHY0_OTG_PWR BIT(4)
+#define EXYNOS_4x12_UPHYPWR_PHY0_SLEEP BIT(5)
+#define EXYNOS_4x12_UPHYPWR_PHY0 ( \
+ EXYNOS_4x12_UPHYPWR_PHY0_SUSPEND | \
+ EXYNOS_4x12_UPHYPWR_PHY0_PWR | \
+ EXYNOS_4x12_UPHYPWR_PHY0_OTG_PWR | \
+ EXYNOS_4x12_UPHYPWR_PHY0_SLEEP)
+
+#define EXYNOS_4x12_UPHYPWR_PHY1_SUSPEND BIT(6)
+#define EXYNOS_4x12_UPHYPWR_PHY1_PWR BIT(7)
+#define EXYNOS_4x12_UPHYPWR_PHY1_SLEEP BIT(8)
+#define EXYNOS_4x12_UPHYPWR_PHY1 ( \
+ EXYNOS_4x12_UPHYPWR_PHY1_SUSPEND | \
+ EXYNOS_4x12_UPHYPWR_PHY1_PWR | \
+ EXYNOS_4x12_UPHYPWR_PHY1_SLEEP)
+
+#define EXYNOS_4x12_UPHYPWR_HSIC0_SUSPEND BIT(9)
+#define EXYNOS_4x12_UPHYPWR_HSIC0_PWR BIT(10)
+#define EXYNOS_4x12_UPHYPWR_HSIC0_SLEEP BIT(11)
+#define EXYNOS_4x12_UPHYPWR_HSIC0 ( \
+ EXYNOS_4x12_UPHYPWR_HSIC0_SUSPEND | \
+ EXYNOS_4x12_UPHYPWR_HSIC0_PWR | \
+ EXYNOS_4x12_UPHYPWR_HSIC0_SLEEP)
+
+#define EXYNOS_4x12_UPHYPWR_HSIC1_SUSPEND BIT(12)
+#define EXYNOS_4x12_UPHYPWR_HSIC1_PWR BIT(13)
+#define EXYNOS_4x12_UPHYPWR_HSIC1_SLEEP BIT(14)
+#define EXYNOS_4x12_UPHYPWR_HSIC1 ( \
+ EXYNOS_4x12_UPHYPWR_HSIC1_SUSPEND | \
+ EXYNOS_4x12_UPHYPWR_HSIC1_PWR | \
+ EXYNOS_4x12_UPHYPWR_HSIC1_SLEEP)
+
+/* PHY clock control */
+#define EXYNOS_4x12_UPHYCLK 0x4
+
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK (0x7 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET 0
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_9MHZ6 (0x0 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_10MHZ (0x1 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_12MHZ (0x2 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_19MHZ2 (0x3 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_20MHZ (0x4 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ (0x5 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ (0x7 << 0)
+
+#define EXYNOS_4x12_UPHYCLK_PHY0_ID_PULLUP BIT(3)
+#define EXYNOS_4x12_UPHYCLK_PHY0_COMMON_ON BIT(4)
+#define EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON BIT(7)
+
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_MASK (0x7f << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_OFFSET 10
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_12MHZ (0x24 << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_15MHZ (0x1c << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_16MHZ (0x1a << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_19MHZ2 (0x15 << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_20MHZ (0x14 << 10)
+
+/* PHY reset control */
+#define EXYNOS_4x12_UPHYRST 0x8
+
+#define EXYNOS_4x12_URSTCON_PHY0 BIT(0)
+#define EXYNOS_4x12_URSTCON_OTG_HLINK BIT(1)
+#define EXYNOS_4x12_URSTCON_OTG_PHYLINK BIT(2)
+#define EXYNOS_4x12_URSTCON_HOST_PHY BIT(3)
+#define EXYNOS_4x12_URSTCON_PHY1 BIT(4)
+#define EXYNOS_4x12_URSTCON_HSIC0 BIT(5)
+#define EXYNOS_4x12_URSTCON_HSIC1 BIT(6)
+#define EXYNOS_4x12_URSTCON_HOST_LINK_ALL BIT(7)
+#define EXYNOS_4x12_URSTCON_HOST_LINK_P0 BIT(8)
+#define EXYNOS_4x12_URSTCON_HOST_LINK_P1 BIT(9)
+#define EXYNOS_4x12_URSTCON_HOST_LINK_P2 BIT(10)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_4x12_USB_ISOL_OFFSET 0x704
+#define EXYNOS_4x12_USB_ISOL_OTG BIT(0)
+#define EXYNOS_4x12_USB_ISOL_HSIC0_OFFSET 0x708
+#define EXYNOS_4x12_USB_ISOL_HSIC0 BIT(0)
+#define EXYNOS_4x12_USB_ISOL_HSIC1_OFFSET 0x70c
+#define EXYNOS_4x12_USB_ISOL_HSIC1 BIT(0)
+
+/* Mode switching SUB Device <-> Host */
+#define EXYNOS_4x12_MODE_SWITCH_OFFSET 0x21c
+#define EXYNOS_4x12_MODE_SWITCH_MASK 1
+#define EXYNOS_4x12_MODE_SWITCH_DEVICE 0
+#define EXYNOS_4x12_MODE_SWITCH_HOST 1
+
+enum exynos4x12_phy_id {
+ EXYNOS4x12_DEVICE,
+ EXYNOS4x12_HOST,
+ EXYNOS4x12_HSIC0,
+ EXYNOS4x12_HSIC1,
+ EXYNOS4x12_NUM_PHYS,
+};
+
+/*
+ * exynos4x12_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int exynos4x12_rate_to_clk(unsigned long rate, u32 *reg)
+{
+ /* EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK */
+
+ switch (rate) {
+ case 9600 * KHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_9MHZ6;
+ break;
+ case 10 * MHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_10MHZ;
+ break;
+ case 12 * MHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_12MHZ;
+ break;
+ case 19200 * KHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_19MHZ2;
+ break;
+ case 20 * MHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_20MHZ;
+ break;
+ case 24 * MHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ;
+ break;
+ case 50 * MHZ:
+ *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void exynos4x12_isol(struct samsung_usb2_phy_instance *inst, bool on)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 offset;
+ u32 mask;
+
+ switch (inst->cfg->id) {
+ case EXYNOS4x12_DEVICE:
+ case EXYNOS4x12_HOST:
+ offset = EXYNOS_4x12_USB_ISOL_OFFSET;
+ mask = EXYNOS_4x12_USB_ISOL_OTG;
+ break;
+ case EXYNOS4x12_HSIC0:
+ offset = EXYNOS_4x12_USB_ISOL_HSIC0_OFFSET;
+ mask = EXYNOS_4x12_USB_ISOL_HSIC0;
+ break;
+ case EXYNOS4x12_HSIC1:
+ offset = EXYNOS_4x12_USB_ISOL_HSIC1_OFFSET;
+ mask = EXYNOS_4x12_USB_ISOL_HSIC1;
+ break;
+ default:
+ return;
+ };
+
+ regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static void exynos4x12_setup_clk(struct samsung_usb2_phy_instance *inst)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 clk;
+
+ clk = readl(drv->reg_phy + EXYNOS_4x12_UPHYCLK);
+ clk &= ~EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK;
+ clk |= drv->ref_reg_val << EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET;
+ writel(clk, drv->reg_phy + EXYNOS_4x12_UPHYCLK);
+}
+
+static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 rstbits = 0;
+ u32 phypwr = 0;
+ u32 rst;
+ u32 pwr;
+ u32 mode = 0;
+ u32 switch_mode = 0;
+
+ switch (inst->cfg->id) {
+ case EXYNOS4x12_DEVICE:
+ phypwr = EXYNOS_4x12_UPHYPWR_PHY0;
+ rstbits = EXYNOS_4x12_URSTCON_PHY0;
+ mode = EXYNOS_4x12_MODE_SWITCH_DEVICE;
+ switch_mode = 1;
+ break;
+ case EXYNOS4x12_HOST:
+ phypwr = EXYNOS_4x12_UPHYPWR_PHY1;
+ rstbits = EXYNOS_4x12_URSTCON_HOST_PHY;
+ mode = EXYNOS_4x12_MODE_SWITCH_HOST;
+ switch_mode = 1;
+ break;
+ case EXYNOS4x12_HSIC0:
+ phypwr = EXYNOS_4x12_UPHYPWR_HSIC0;
+ rstbits = EXYNOS_4x12_URSTCON_HSIC1 |
+ EXYNOS_4x12_URSTCON_HOST_LINK_P0 |
+ EXYNOS_4x12_URSTCON_HOST_PHY;
+ break;
+ case EXYNOS4x12_HSIC1:
+ phypwr = EXYNOS_4x12_UPHYPWR_HSIC1;
+ rstbits = EXYNOS_4x12_URSTCON_HSIC1 |
+ EXYNOS_4x12_URSTCON_HOST_LINK_P1;
+ break;
+ };
+
+ if (on) {
+ if (switch_mode)
+ regmap_update_bits(drv->reg_sys,
+ EXYNOS_4x12_MODE_SWITCH_OFFSET,
+ EXYNOS_4x12_MODE_SWITCH_MASK, mode);
+
+ pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR);
+ pwr &= ~phypwr;
+ writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR);
+
+ rst = readl(drv->reg_phy + EXYNOS_4x12_UPHYRST);
+ rst |= rstbits;
+ writel(rst, drv->reg_phy + EXYNOS_4x12_UPHYRST);
+ udelay(10);
+ rst &= ~rstbits;
+ writel(rst, drv->reg_phy + EXYNOS_4x12_UPHYRST);
+ /* The following delay is necessary for the reset sequence to be
+ * completed */
+ udelay(80);
+ } else {
+ pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR);
+ pwr |= phypwr;
+ writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR);
+ }
+}
+
+static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+
+ inst->enabled = 1;
+ exynos4x12_setup_clk(inst);
+ exynos4x12_phy_pwr(inst, 1);
+ exynos4x12_isol(inst, 0);
+
+ /* Power on the device, as it is necessary for HSIC to work */
+ if (inst->cfg->id == EXYNOS4x12_HSIC0) {
+ struct samsung_usb2_phy_instance *device =
+ &drv->instances[EXYNOS4x12_DEVICE];
+ exynos4x12_phy_pwr(device, 1);
+ exynos4x12_isol(device, 0);
+ }
+
+ return 0;
+}
+
+static int exynos4x12_power_off(struct samsung_usb2_phy_instance *inst)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ struct samsung_usb2_phy_instance *device =
+ &drv->instances[EXYNOS4x12_DEVICE];
+
+ inst->enabled = 0;
+ exynos4x12_isol(inst, 1);
+ exynos4x12_phy_pwr(inst, 0);
+
+ if (inst->cfg->id == EXYNOS4x12_HSIC0 && !device->enabled) {
+ exynos4x12_isol(device, 1);
+ exynos4x12_phy_pwr(device, 0);
+ }
+
+ return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos4x12_phys[] = {
+ {
+ .label = "device",
+ .id = EXYNOS4x12_DEVICE,
+ .power_on = exynos4x12_power_on,
+ .power_off = exynos4x12_power_off,
+ },
+ {
+ .label = "host",
+ .id = EXYNOS4x12_HOST,
+ .power_on = exynos4x12_power_on,
+ .power_off = exynos4x12_power_off,
+ },
+ {
+ .label = "hsic0",
+ .id = EXYNOS4x12_HSIC0,
+ .power_on = exynos4x12_power_on,
+ .power_off = exynos4x12_power_off,
+ },
+ {
+ .label = "hsic1",
+ .id = EXYNOS4x12_HSIC1,
+ .power_on = exynos4x12_power_on,
+ .power_off = exynos4x12_power_off,
+ },
+ {},
+};
+
+const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config = {
+ .has_mode_switch = 1,
+ .num_phys = EXYNOS4x12_NUM_PHYS,
+ .phys = exynos4x12_phys,
+ .rate_to_clk = exynos4x12_rate_to_clk,
+};
diff --git a/drivers/phy/phy-exynos5250-sata.c b/drivers/phy/phy-exynos5250-sata.c
new file mode 100644
index 000000000000..c9361b731fa6
--- /dev/null
+++ b/drivers/phy/phy-exynos5250-sata.c
@@ -0,0 +1,251 @@
+/*
+ * Samsung SATA SerDes(PHY) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Authors: Girish K S <ks.giri@samsung.com>
+ * Yuvaraj Kumar C D <yuvaraj.cd@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include <linux/mfd/syscon.h>
+
+#define SATAPHY_CONTROL_OFFSET 0x0724
+#define EXYNOS5_SATAPHY_PMU_ENABLE BIT(0)
+#define EXYNOS5_SATA_RESET 0x4
+#define RESET_GLOBAL_RST_N BIT(0)
+#define RESET_CMN_RST_N BIT(1)
+#define RESET_CMN_BLOCK_RST_N BIT(2)
+#define RESET_CMN_I2C_RST_N BIT(3)
+#define RESET_TX_RX_PIPE_RST_N BIT(4)
+#define RESET_TX_RX_BLOCK_RST_N BIT(5)
+#define RESET_TX_RX_I2C_RST_N (BIT(6) | BIT(7))
+#define LINK_RESET 0xf0000
+#define EXYNOS5_SATA_MODE0 0x10
+#define SATA_SPD_GEN3 BIT(1)
+#define EXYNOS5_SATA_CTRL0 0x14
+#define CTRL0_P0_PHY_CALIBRATED_SEL BIT(9)
+#define CTRL0_P0_PHY_CALIBRATED BIT(8)
+#define EXYNOS5_SATA_PHSATA_CTRLM 0xe0
+#define PHCTRLM_REF_RATE BIT(1)
+#define PHCTRLM_HIGH_SPEED BIT(0)
+#define EXYNOS5_SATA_PHSATA_STATM 0xf0
+#define PHSTATM_PLL_LOCKED BIT(0)
+
+#define PHY_PLL_TIMEOUT (usecs_to_jiffies(1000))
+
+struct exynos_sata_phy {
+ struct phy *phy;
+ struct clk *phyclk;
+ void __iomem *regs;
+ struct regmap *pmureg;
+ struct i2c_client *client;
+};
+
+static int wait_for_reg_status(void __iomem *base, u32 reg, u32 checkbit,
+ u32 status)
+{
+ unsigned long timeout = jiffies + PHY_PLL_TIMEOUT;
+
+ while (time_before(jiffies, timeout)) {
+ if ((readl(base + reg) & checkbit) == status)
+ return 0;
+ }
+
+ return -EFAULT;
+}
+
+static int exynos_sata_phy_power_on(struct phy *phy)
+{
+ struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
+
+ return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
+ EXYNOS5_SATAPHY_PMU_ENABLE, true);
+
+}
+
+static int exynos_sata_phy_power_off(struct phy *phy)
+{
+ struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
+
+ return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
+ EXYNOS5_SATAPHY_PMU_ENABLE, false);
+
+}
+
+static int exynos_sata_phy_init(struct phy *phy)
+{
+ u32 val = 0;
+ int ret = 0;
+ u8 buf[] = { 0x3a, 0x0b };
+ struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
+
+ ret = regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
+ EXYNOS5_SATAPHY_PMU_ENABLE, true);
+ if (ret != 0)
+ dev_err(&sata_phy->phy->dev, "phy init failed\n");
+
+ writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+ val |= RESET_GLOBAL_RST_N | RESET_CMN_RST_N | RESET_CMN_BLOCK_RST_N
+ | RESET_CMN_I2C_RST_N | RESET_TX_RX_PIPE_RST_N
+ | RESET_TX_RX_BLOCK_RST_N | RESET_TX_RX_I2C_RST_N;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+ val |= LINK_RESET;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+ val |= RESET_CMN_RST_N;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
+ val &= ~PHCTRLM_REF_RATE;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
+
+ /* High speed enable for Gen3 */
+ val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
+ val |= PHCTRLM_HIGH_SPEED;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_CTRL0);
+ val |= CTRL0_P0_PHY_CALIBRATED_SEL | CTRL0_P0_PHY_CALIBRATED;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_CTRL0);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_MODE0);
+ val |= SATA_SPD_GEN3;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_MODE0);
+
+ ret = i2c_master_send(sata_phy->client, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ /* release cmu reset */
+ val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+ val &= ~RESET_CMN_RST_N;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+ val |= RESET_CMN_RST_N;
+ writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+ ret = wait_for_reg_status(sata_phy->regs,
+ EXYNOS5_SATA_PHSATA_STATM,
+ PHSTATM_PLL_LOCKED, 1);
+ if (ret < 0)
+ dev_err(&sata_phy->phy->dev,
+ "PHY PLL locking failed\n");
+ return ret;
+}
+
+static struct phy_ops exynos_sata_phy_ops = {
+ .init = exynos_sata_phy_init,
+ .power_on = exynos_sata_phy_power_on,
+ .power_off = exynos_sata_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int exynos_sata_phy_probe(struct platform_device *pdev)
+{
+ struct exynos_sata_phy *sata_phy;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct phy_provider *phy_provider;
+ struct device_node *node;
+ int ret = 0;
+
+ sata_phy = devm_kzalloc(dev, sizeof(*sata_phy), GFP_KERNEL);
+ if (!sata_phy)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ sata_phy->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(sata_phy->regs))
+ return PTR_ERR(sata_phy->regs);
+
+ sata_phy->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "samsung,syscon-phandle");
+ if (IS_ERR(sata_phy->pmureg)) {
+ dev_err(dev, "syscon regmap lookup failed.\n");
+ return PTR_ERR(sata_phy->pmureg);
+ }
+
+ node = of_parse_phandle(dev->of_node,
+ "samsung,exynos-sataphy-i2c-phandle", 0);
+ if (!node)
+ return -EINVAL;
+
+ sata_phy->client = of_find_i2c_device_by_node(node);
+ if (!sata_phy->client)
+ return -EPROBE_DEFER;
+
+ dev_set_drvdata(dev, sata_phy);
+
+ sata_phy->phyclk = devm_clk_get(dev, "sata_phyctrl");
+ if (IS_ERR(sata_phy->phyclk)) {
+ dev_err(dev, "failed to get clk for PHY\n");
+ return PTR_ERR(sata_phy->phyclk);
+ }
+
+ ret = clk_prepare_enable(sata_phy->phyclk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable source clk\n");
+ return ret;
+ }
+
+ sata_phy->phy = devm_phy_create(dev, &exynos_sata_phy_ops, NULL);
+ if (IS_ERR(sata_phy->phy)) {
+ clk_disable_unprepare(sata_phy->phyclk);
+ dev_err(dev, "failed to create PHY\n");
+ return PTR_ERR(sata_phy->phy);
+ }
+
+ phy_set_drvdata(sata_phy->phy, sata_phy);
+
+ phy_provider = devm_of_phy_provider_register(dev,
+ of_phy_simple_xlate);
+ if (IS_ERR(phy_provider)) {
+ clk_disable_unprepare(sata_phy->phyclk);
+ return PTR_ERR(phy_provider);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id exynos_sata_phy_of_match[] = {
+ { .compatible = "samsung,exynos5250-sata-phy" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, exynos_sata_phy_of_match);
+
+static struct platform_driver exynos_sata_phy_driver = {
+ .probe = exynos_sata_phy_probe,
+ .driver = {
+ .of_match_table = exynos_sata_phy_of_match,
+ .name = "samsung,sata-phy",
+ .owner = THIS_MODULE,
+ }
+};
+module_platform_driver(exynos_sata_phy_driver);
+
+MODULE_DESCRIPTION("Samsung SerDes PHY driver");
+MODULE_LICENSE("GPL V2");
+MODULE_AUTHOR("Girish K S <ks.giri@samsung.com>");
+MODULE_AUTHOR("Yuvaraj C D <yuvaraj.cd@samsung.com>");
diff --git a/drivers/phy/phy-exynos5250-usb2.c b/drivers/phy/phy-exynos5250-usb2.c
new file mode 100644
index 000000000000..94179afda951
--- /dev/null
+++ b/drivers/phy/phy-exynos5250-usb2.c
@@ -0,0 +1,404 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 5250 support
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+#define EXYNOS_5250_REFCLKSEL_CRYSTAL 0x0
+#define EXYNOS_5250_REFCLKSEL_XO 0x1
+#define EXYNOS_5250_REFCLKSEL_CLKCORE 0x2
+
+#define EXYNOS_5250_FSEL_9MHZ6 0x0
+#define EXYNOS_5250_FSEL_10MHZ 0x1
+#define EXYNOS_5250_FSEL_12MHZ 0x2
+#define EXYNOS_5250_FSEL_19MHZ2 0x3
+#define EXYNOS_5250_FSEL_20MHZ 0x4
+#define EXYNOS_5250_FSEL_24MHZ 0x5
+#define EXYNOS_5250_FSEL_50MHZ 0x7
+
+/* Normal host */
+#define EXYNOS_5250_HOSTPHYCTRL0 0x0
+
+#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL BIT(31)
+#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT 19
+#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_MASK \
+ (0x3 << EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT)
+#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT 16
+#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK \
+ (0x7 << EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT)
+#define EXYNOS_5250_HOSTPHYCTRL0_TESTBURNIN BIT(11)
+#define EXYNOS_5250_HOSTPHYCTRL0_RETENABLE BIT(10)
+#define EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N BIT(9)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_MASK (0x3 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_DUAL (0x0 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ID0 (0x1 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ANALOGTEST (0x2 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_SIDDQ BIT(6)
+#define EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP BIT(5)
+#define EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND BIT(4)
+#define EXYNOS_5250_HOSTPHYCTRL0_WORDINTERFACE BIT(3)
+#define EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST BIT(2)
+#define EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST BIT(1)
+#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST BIT(0)
+
+/* HSIC0 & HSIC1 */
+#define EXYNOS_5250_HSICPHYCTRL1 0x10
+#define EXYNOS_5250_HSICPHYCTRL2 0x20
+
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_MASK (0x3 << 23)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT (0x2 << 23)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_MASK (0x7f << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 (0x24 << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_15 (0x1c << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_16 (0x1a << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_19_2 (0x15 << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_20 (0x14 << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_SIDDQ BIT(6)
+#define EXYNOS_5250_HSICPHYCTRLX_FORCESLEEP BIT(5)
+#define EXYNOS_5250_HSICPHYCTRLX_FORCESUSPEND BIT(4)
+#define EXYNOS_5250_HSICPHYCTRLX_WORDINTERFACE BIT(3)
+#define EXYNOS_5250_HSICPHYCTRLX_UTMISWRST BIT(2)
+#define EXYNOS_5250_HSICPHYCTRLX_PHYSWRST BIT(0)
+
+/* EHCI control */
+#define EXYNOS_5250_HOSTEHCICTRL 0x30
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN BIT(29)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR4 BIT(28)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR8 BIT(27)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR16 BIT(26)
+#define EXYNOS_5250_HOSTEHCICTRL_AUTOPPDONOVRCUREN BIT(25)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT 19
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK \
+ (0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT 13
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_MASK \
+ (0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL2_SHIFT 7
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK \
+ (0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT 1
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_MASK \
+ (0x1 << EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_SIMULATIONMODE BIT(0)
+
+/* OHCI control */
+#define EXYNOS_5250_HOSTOHCICTRL 0x34
+#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT 1
+#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_MASK \
+ (0x3ff << EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT)
+#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVALEN BIT(0)
+
+/* USBOTG */
+#define EXYNOS_5250_USBOTGSYS 0x38
+#define EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET BIT(14)
+#define EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG BIT(13)
+#define EXYNOS_5250_USBOTGSYS_PHY_SW_RST BIT(12)
+#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT 9
+#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK \
+ (0x3 << EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT)
+#define EXYNOS_5250_USBOTGSYS_ID_PULLUP BIT(8)
+#define EXYNOS_5250_USBOTGSYS_COMMON_ON BIT(7)
+#define EXYNOS_5250_USBOTGSYS_FSEL_SHIFT 4
+#define EXYNOS_5250_USBOTGSYS_FSEL_MASK \
+ (0x3 << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT)
+#define EXYNOS_5250_USBOTGSYS_FORCE_SLEEP BIT(3)
+#define EXYNOS_5250_USBOTGSYS_OTGDISABLE BIT(2)
+#define EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG BIT(1)
+#define EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND BIT(0)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_5250_USB_ISOL_OTG_OFFSET 0x704
+#define EXYNOS_5250_USB_ISOL_OTG BIT(0)
+#define EXYNOS_5250_USB_ISOL_HOST_OFFSET 0x708
+#define EXYNOS_5250_USB_ISOL_HOST BIT(0)
+
+/* Mode swtich register */
+#define EXYNOS_5250_MODE_SWITCH_OFFSET 0x230
+#define EXYNOS_5250_MODE_SWITCH_MASK 1
+#define EXYNOS_5250_MODE_SWITCH_DEVICE 0
+#define EXYNOS_5250_MODE_SWITCH_HOST 1
+
+enum exynos4x12_phy_id {
+ EXYNOS5250_DEVICE,
+ EXYNOS5250_HOST,
+ EXYNOS5250_HSIC0,
+ EXYNOS5250_HSIC1,
+ EXYNOS5250_NUM_PHYS,
+};
+
+/*
+ * exynos5250_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int exynos5250_rate_to_clk(unsigned long rate, u32 *reg)
+{
+ /* EXYNOS_5250_FSEL_MASK */
+
+ switch (rate) {
+ case 9600 * KHZ:
+ *reg = EXYNOS_5250_FSEL_9MHZ6;
+ break;
+ case 10 * MHZ:
+ *reg = EXYNOS_5250_FSEL_10MHZ;
+ break;
+ case 12 * MHZ:
+ *reg = EXYNOS_5250_FSEL_12MHZ;
+ break;
+ case 19200 * KHZ:
+ *reg = EXYNOS_5250_FSEL_19MHZ2;
+ break;
+ case 20 * MHZ:
+ *reg = EXYNOS_5250_FSEL_20MHZ;
+ break;
+ case 24 * MHZ:
+ *reg = EXYNOS_5250_FSEL_24MHZ;
+ break;
+ case 50 * MHZ:
+ *reg = EXYNOS_5250_FSEL_50MHZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void exynos5250_isol(struct samsung_usb2_phy_instance *inst, bool on)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 offset;
+ u32 mask;
+
+ switch (inst->cfg->id) {
+ case EXYNOS5250_DEVICE:
+ offset = EXYNOS_5250_USB_ISOL_OTG_OFFSET;
+ mask = EXYNOS_5250_USB_ISOL_OTG;
+ break;
+ case EXYNOS5250_HOST:
+ offset = EXYNOS_5250_USB_ISOL_HOST_OFFSET;
+ mask = EXYNOS_5250_USB_ISOL_HOST;
+ break;
+ default:
+ return;
+ };
+
+ regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static int exynos5250_power_on(struct samsung_usb2_phy_instance *inst)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 ctrl0;
+ u32 otg;
+ u32 ehci;
+ u32 ohci;
+ u32 hsic;
+
+ switch (inst->cfg->id) {
+ case EXYNOS5250_DEVICE:
+ regmap_update_bits(drv->reg_sys,
+ EXYNOS_5250_MODE_SWITCH_OFFSET,
+ EXYNOS_5250_MODE_SWITCH_MASK,
+ EXYNOS_5250_MODE_SWITCH_DEVICE);
+
+ /* OTG configuration */
+ otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+ /* The clock */
+ otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
+ otg |= drv->ref_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
+ /* Reset */
+ otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
+ EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
+ EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
+ otg |= EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+ EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
+ EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+ EXYNOS_5250_USBOTGSYS_OTGDISABLE;
+ /* Ref clock */
+ otg &= ~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
+ otg |= EXYNOS_5250_REFCLKSEL_CLKCORE <<
+ EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
+ writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+ udelay(100);
+ otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+ EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+ EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
+ EXYNOS_5250_USBOTGSYS_OTGDISABLE);
+ writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+
+
+ break;
+ case EXYNOS5250_HOST:
+ case EXYNOS5250_HSIC0:
+ case EXYNOS5250_HSIC1:
+ /* Host registers configuration */
+ ctrl0 = readl(drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+ /* The clock */
+ ctrl0 &= ~EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK;
+ ctrl0 |= drv->ref_reg_val <<
+ EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT;
+
+ /* Reset */
+ ctrl0 &= ~(EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST |
+ EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL |
+ EXYNOS_5250_HOSTPHYCTRL0_SIDDQ |
+ EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND |
+ EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP);
+ ctrl0 |= EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
+ EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST |
+ EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N;
+ writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+ udelay(10);
+ ctrl0 &= ~(EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
+ EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST);
+ writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+
+ /* OTG configuration */
+ otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+ /* The clock */
+ otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
+ otg |= drv->ref_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
+ /* Reset */
+ otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
+ EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
+ EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
+ otg |= EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+ EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
+ EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+ EXYNOS_5250_USBOTGSYS_OTGDISABLE;
+ /* Ref clock */
+ otg &= ~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
+ otg |= EXYNOS_5250_REFCLKSEL_CLKCORE <<
+ EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
+ writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+ udelay(10);
+ otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+ EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+ EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET);
+
+ /* HSIC phy configuration */
+ hsic = (EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 |
+ EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT |
+ EXYNOS_5250_HSICPHYCTRLX_PHYSWRST);
+ writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1);
+ writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2);
+ udelay(10);
+ hsic &= ~EXYNOS_5250_HSICPHYCTRLX_PHYSWRST;
+ writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1);
+ writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2);
+ /* The following delay is necessary for the reset sequence to be
+ * completed */
+ udelay(80);
+
+ /* Enable EHCI DMA burst */
+ ehci = readl(drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
+ ehci |= EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN |
+ EXYNOS_5250_HOSTEHCICTRL_ENAINCR4 |
+ EXYNOS_5250_HOSTEHCICTRL_ENAINCR8 |
+ EXYNOS_5250_HOSTEHCICTRL_ENAINCR16;
+ writel(ehci, drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
+
+ /* OHCI settings */
+ ohci = readl(drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
+ /* Following code is based on the old driver */
+ ohci |= 0x1 << 3;
+ writel(ohci, drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
+
+ break;
+ }
+ inst->enabled = 1;
+ exynos5250_isol(inst, 0);
+
+ return 0;
+}
+
+static int exynos5250_power_off(struct samsung_usb2_phy_instance *inst)
+{
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ u32 ctrl0;
+ u32 otg;
+ u32 hsic;
+
+ inst->enabled = 0;
+ exynos5250_isol(inst, 1);
+
+ switch (inst->cfg->id) {
+ case EXYNOS5250_DEVICE:
+ otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+ otg |= (EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
+ EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG |
+ EXYNOS_5250_USBOTGSYS_FORCE_SLEEP);
+ writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+ break;
+ case EXYNOS5250_HOST:
+ ctrl0 = readl(drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+ ctrl0 |= (EXYNOS_5250_HOSTPHYCTRL0_SIDDQ |
+ EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND |
+ EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP |
+ EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST |
+ EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL);
+ writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+ break;
+ case EXYNOS5250_HSIC0:
+ case EXYNOS5250_HSIC1:
+ hsic = (EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 |
+ EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT |
+ EXYNOS_5250_HSICPHYCTRLX_SIDDQ |
+ EXYNOS_5250_HSICPHYCTRLX_FORCESLEEP |
+ EXYNOS_5250_HSICPHYCTRLX_FORCESUSPEND
+ );
+ writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1);
+ writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2);
+ break;
+ }
+
+ return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos5250_phys[] = {
+ {
+ .label = "device",
+ .id = EXYNOS5250_DEVICE,
+ .power_on = exynos5250_power_on,
+ .power_off = exynos5250_power_off,
+ },
+ {
+ .label = "host",
+ .id = EXYNOS5250_HOST,
+ .power_on = exynos5250_power_on,
+ .power_off = exynos5250_power_off,
+ },
+ {
+ .label = "hsic0",
+ .id = EXYNOS5250_HSIC0,
+ .power_on = exynos5250_power_on,
+ .power_off = exynos5250_power_off,
+ },
+ {
+ .label = "hsic1",
+ .id = EXYNOS5250_HSIC1,
+ .power_on = exynos5250_power_on,
+ .power_off = exynos5250_power_off,
+ },
+ {},
+};
+
+const struct samsung_usb2_phy_config exynos5250_usb2_phy_config = {
+ .has_mode_switch = 1,
+ .num_phys = EXYNOS5250_NUM_PHYS,
+ .phys = exynos5250_phys,
+ .rate_to_clk = exynos5250_rate_to_clk,
+};
diff --git a/drivers/phy/phy-mvebu-sata.c b/drivers/phy/phy-mvebu-sata.c
index d43786f62437..d70ecd6a1b3f 100644
--- a/drivers/phy/phy-mvebu-sata.c
+++ b/drivers/phy/phy-mvebu-sata.c
@@ -99,17 +99,17 @@ static int phy_mvebu_sata_probe(struct platform_device *pdev)
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
- phy_provider = devm_of_phy_provider_register(&pdev->dev,
- of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
-
phy = devm_phy_create(&pdev->dev, &phy_mvebu_sata_ops, NULL);
if (IS_ERR(phy))
return PTR_ERR(phy);
phy_set_drvdata(phy, priv);
+ phy_provider = devm_of_phy_provider_register(&pdev->dev,
+ of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
/* The boot loader may of left it on. Turn it off. */
phy_mvebu_sata_power_off(phy);
diff --git a/drivers/usb/phy/phy-omap-control.c b/drivers/phy/phy-omap-control.c
index e7253182e47d..311b4f9a5132 100644
--- a/drivers/usb/phy/phy-omap-control.c
+++ b/drivers/phy/phy-omap-control.c
@@ -1,5 +1,5 @@
/*
- * omap-control-usb.c - The USB part of control module.
+ * omap-control-phy.c - The PHY part of control module.
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
* This program is free software; you can redistribute it and/or modify
@@ -24,36 +24,36 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk.h>
-#include <linux/usb/omap_control_usb.h>
+#include <linux/phy/omap_control_phy.h>
/**
- * omap_control_usb_phy_power - power on/off the phy using control module reg
+ * omap_control_phy_power - power on/off the phy using control module reg
* @dev: the control module device
* @on: 0 or 1, based on powering on or off the PHY
*/
-void omap_control_usb_phy_power(struct device *dev, int on)
+void omap_control_phy_power(struct device *dev, int on)
{
u32 val;
unsigned long rate;
- struct omap_control_usb *control_usb;
+ struct omap_control_phy *control_phy;
if (IS_ERR(dev) || !dev) {
pr_err("%s: invalid device\n", __func__);
return;
}
- control_usb = dev_get_drvdata(dev);
- if (!control_usb) {
- dev_err(dev, "%s: invalid control usb device\n", __func__);
+ control_phy = dev_get_drvdata(dev);
+ if (!control_phy) {
+ dev_err(dev, "%s: invalid control phy device\n", __func__);
return;
}
- if (control_usb->type == OMAP_CTRL_TYPE_OTGHS)
+ if (control_phy->type == OMAP_CTRL_TYPE_OTGHS)
return;
- val = readl(control_usb->power);
+ val = readl(control_phy->power);
- switch (control_usb->type) {
+ switch (control_phy->type) {
case OMAP_CTRL_TYPE_USB2:
if (on)
val &= ~OMAP_CTRL_DEV_PHY_PD;
@@ -62,19 +62,20 @@ void omap_control_usb_phy_power(struct device *dev, int on)
break;
case OMAP_CTRL_TYPE_PIPE3:
- rate = clk_get_rate(control_usb->sys_clk);
+ rate = clk_get_rate(control_phy->sys_clk);
rate = rate/1000000;
if (on) {
- val &= ~(OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK |
- OMAP_CTRL_USB_PWRCTL_CLK_FREQ_MASK);
- val |= OMAP_CTRL_USB3_PHY_TX_RX_POWERON <<
- OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT;
- val |= rate << OMAP_CTRL_USB_PWRCTL_CLK_FREQ_SHIFT;
+ val &= ~(OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
+ OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK);
+ val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON <<
+ OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
+ val |= rate <<
+ OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
} else {
- val &= ~OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK;
- val |= OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF <<
- OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT;
+ val &= ~OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK;
+ val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF <<
+ OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
}
break;
@@ -100,66 +101,66 @@ void omap_control_usb_phy_power(struct device *dev, int on)
break;
default:
dev_err(dev, "%s: type %d not recognized\n",
- __func__, control_usb->type);
+ __func__, control_phy->type);
break;
}
- writel(val, control_usb->power);
+ writel(val, control_phy->power);
}
-EXPORT_SYMBOL_GPL(omap_control_usb_phy_power);
+EXPORT_SYMBOL_GPL(omap_control_phy_power);
/**
* omap_control_usb_host_mode - set AVALID, VBUSVALID and ID pin in grounded
- * @ctrl_usb: struct omap_control_usb *
+ * @ctrl_phy: struct omap_control_phy *
*
* Writes to the mailbox register to notify the usb core that a usb
* device has been connected.
*/
-static void omap_control_usb_host_mode(struct omap_control_usb *ctrl_usb)
+static void omap_control_usb_host_mode(struct omap_control_phy *ctrl_phy)
{
u32 val;
- val = readl(ctrl_usb->otghs_control);
+ val = readl(ctrl_phy->otghs_control);
val &= ~(OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND);
val |= OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID;
- writel(val, ctrl_usb->otghs_control);
+ writel(val, ctrl_phy->otghs_control);
}
/**
* omap_control_usb_device_mode - set AVALID, VBUSVALID and ID pin in high
* impedance
- * @ctrl_usb: struct omap_control_usb *
+ * @ctrl_phy: struct omap_control_phy *
*
* Writes to the mailbox register to notify the usb core that it has been
* connected to a usb host.
*/
-static void omap_control_usb_device_mode(struct omap_control_usb *ctrl_usb)
+static void omap_control_usb_device_mode(struct omap_control_phy *ctrl_phy)
{
u32 val;
- val = readl(ctrl_usb->otghs_control);
+ val = readl(ctrl_phy->otghs_control);
val &= ~OMAP_CTRL_DEV_SESSEND;
val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_AVALID |
OMAP_CTRL_DEV_VBUSVALID;
- writel(val, ctrl_usb->otghs_control);
+ writel(val, ctrl_phy->otghs_control);
}
/**
* omap_control_usb_set_sessionend - Enable SESSIONEND and IDIG to high
* impedance
- * @ctrl_usb: struct omap_control_usb *
+ * @ctrl_phy: struct omap_control_phy *
*
* Writes to the mailbox register to notify the usb core it's now in
* disconnected state.
*/
-static void omap_control_usb_set_sessionend(struct omap_control_usb *ctrl_usb)
+static void omap_control_usb_set_sessionend(struct omap_control_phy *ctrl_phy)
{
u32 val;
- val = readl(ctrl_usb->otghs_control);
+ val = readl(ctrl_phy->otghs_control);
val &= ~(OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID);
val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND;
- writel(val, ctrl_usb->otghs_control);
+ writel(val, ctrl_phy->otghs_control);
}
/**
@@ -174,30 +175,30 @@ static void omap_control_usb_set_sessionend(struct omap_control_usb *ctrl_usb)
void omap_control_usb_set_mode(struct device *dev,
enum omap_control_usb_mode mode)
{
- struct omap_control_usb *ctrl_usb;
+ struct omap_control_phy *ctrl_phy;
if (IS_ERR(dev) || !dev)
return;
- ctrl_usb = dev_get_drvdata(dev);
+ ctrl_phy = dev_get_drvdata(dev);
- if (!ctrl_usb) {
- dev_err(dev, "Invalid control usb device\n");
+ if (!ctrl_phy) {
+ dev_err(dev, "Invalid control phy device\n");
return;
}
- if (ctrl_usb->type != OMAP_CTRL_TYPE_OTGHS)
+ if (ctrl_phy->type != OMAP_CTRL_TYPE_OTGHS)
return;
switch (mode) {
case USB_MODE_HOST:
- omap_control_usb_host_mode(ctrl_usb);
+ omap_control_usb_host_mode(ctrl_phy);
break;
case USB_MODE_DEVICE:
- omap_control_usb_device_mode(ctrl_usb);
+ omap_control_usb_device_mode(ctrl_phy);
break;
case USB_MODE_DISCONNECT:
- omap_control_usb_set_sessionend(ctrl_usb);
+ omap_control_usb_set_sessionend(ctrl_phy);
break;
default:
dev_vdbg(dev, "invalid omap control usb mode\n");
@@ -207,13 +208,13 @@ EXPORT_SYMBOL_GPL(omap_control_usb_set_mode);
#ifdef CONFIG_OF
-static const enum omap_control_usb_type otghs_data = OMAP_CTRL_TYPE_OTGHS;
-static const enum omap_control_usb_type usb2_data = OMAP_CTRL_TYPE_USB2;
-static const enum omap_control_usb_type pipe3_data = OMAP_CTRL_TYPE_PIPE3;
-static const enum omap_control_usb_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2;
-static const enum omap_control_usb_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2;
+static const enum omap_control_phy_type otghs_data = OMAP_CTRL_TYPE_OTGHS;
+static const enum omap_control_phy_type usb2_data = OMAP_CTRL_TYPE_USB2;
+static const enum omap_control_phy_type pipe3_data = OMAP_CTRL_TYPE_PIPE3;
+static const enum omap_control_phy_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2;
+static const enum omap_control_phy_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2;
-static const struct of_device_id omap_control_usb_id_table[] = {
+static const struct of_device_id omap_control_phy_id_table[] = {
{
.compatible = "ti,control-phy-otghs",
.data = &otghs_data,
@@ -227,93 +228,93 @@ static const struct of_device_id omap_control_usb_id_table[] = {
.data = &pipe3_data,
},
{
- .compatible = "ti,control-phy-dra7usb2",
+ .compatible = "ti,control-phy-usb2-dra7",
.data = &dra7usb2_data,
},
{
- .compatible = "ti,control-phy-am437usb2",
+ .compatible = "ti,control-phy-usb2-am437",
.data = &am437usb2_data,
},
{},
};
-MODULE_DEVICE_TABLE(of, omap_control_usb_id_table);
+MODULE_DEVICE_TABLE(of, omap_control_phy_id_table);
#endif
-static int omap_control_usb_probe(struct platform_device *pdev)
+static int omap_control_phy_probe(struct platform_device *pdev)
{
struct resource *res;
const struct of_device_id *of_id;
- struct omap_control_usb *control_usb;
+ struct omap_control_phy *control_phy;
- of_id = of_match_device(of_match_ptr(omap_control_usb_id_table),
- &pdev->dev);
+ of_id = of_match_device(of_match_ptr(omap_control_phy_id_table),
+ &pdev->dev);
if (!of_id)
return -EINVAL;
- control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),
+ control_phy = devm_kzalloc(&pdev->dev, sizeof(*control_phy),
GFP_KERNEL);
- if (!control_usb) {
- dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
+ if (!control_phy) {
+ dev_err(&pdev->dev, "unable to alloc memory for control phy\n");
return -ENOMEM;
}
- control_usb->dev = &pdev->dev;
- control_usb->type = *(enum omap_control_usb_type *)of_id->data;
+ control_phy->dev = &pdev->dev;
+ control_phy->type = *(enum omap_control_phy_type *)of_id->data;
- if (control_usb->type == OMAP_CTRL_TYPE_OTGHS) {
+ if (control_phy->type == OMAP_CTRL_TYPE_OTGHS) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"otghs_control");
- control_usb->otghs_control = devm_ioremap_resource(
+ control_phy->otghs_control = devm_ioremap_resource(
&pdev->dev, res);
- if (IS_ERR(control_usb->otghs_control))
- return PTR_ERR(control_usb->otghs_control);
+ if (IS_ERR(control_phy->otghs_control))
+ return PTR_ERR(control_phy->otghs_control);
} else {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"power");
- control_usb->power = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(control_usb->power)) {
+ control_phy->power = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(control_phy->power)) {
dev_err(&pdev->dev, "Couldn't get power register\n");
- return PTR_ERR(control_usb->power);
+ return PTR_ERR(control_phy->power);
}
}
- if (control_usb->type == OMAP_CTRL_TYPE_PIPE3) {
- control_usb->sys_clk = devm_clk_get(control_usb->dev,
+ if (control_phy->type == OMAP_CTRL_TYPE_PIPE3) {
+ control_phy->sys_clk = devm_clk_get(control_phy->dev,
"sys_clkin");
- if (IS_ERR(control_usb->sys_clk)) {
+ if (IS_ERR(control_phy->sys_clk)) {
pr_err("%s: unable to get sys_clkin\n", __func__);
return -EINVAL;
}
}
- dev_set_drvdata(control_usb->dev, control_usb);
+ dev_set_drvdata(control_phy->dev, control_phy);
return 0;
}
-static struct platform_driver omap_control_usb_driver = {
- .probe = omap_control_usb_probe,
+static struct platform_driver omap_control_phy_driver = {
+ .probe = omap_control_phy_probe,
.driver = {
- .name = "omap-control-usb",
+ .name = "omap-control-phy",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(omap_control_usb_id_table),
+ .of_match_table = of_match_ptr(omap_control_phy_id_table),
},
};
-static int __init omap_control_usb_init(void)
+static int __init omap_control_phy_init(void)
{
- return platform_driver_register(&omap_control_usb_driver);
+ return platform_driver_register(&omap_control_phy_driver);
}
-subsys_initcall(omap_control_usb_init);
+subsys_initcall(omap_control_phy_init);
-static void __exit omap_control_usb_exit(void)
+static void __exit omap_control_phy_exit(void)
{
- platform_driver_unregister(&omap_control_usb_driver);
+ platform_driver_unregister(&omap_control_phy_driver);
}
-module_exit(omap_control_usb_exit);
+module_exit(omap_control_phy_exit);
-MODULE_ALIAS("platform: omap_control_usb");
+MODULE_ALIAS("platform: omap_control_phy");
MODULE_AUTHOR("Texas Instruments Inc.");
-MODULE_DESCRIPTION("OMAP Control Module USB Driver");
+MODULE_DESCRIPTION("OMAP Control Module PHY Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index bfc5c337f99a..a2205a841e5e 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -21,16 +21,19 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/io.h>
-#include <linux/usb/omap_usb.h>
+#include <linux/phy/omap_usb.h>
#include <linux/usb/phy_companion.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/pm_runtime.h>
#include <linux/delay.h>
-#include <linux/usb/omap_control_usb.h>
+#include <linux/phy/omap_control_phy.h>
#include <linux/phy/phy.h>
#include <linux/of_platform.h>
+#define USB2PHY_DISCON_BYP_LATCH (1 << 31)
+#define USB2PHY_ANA_CONFIG1 0x4c
+
/**
* omap_usb2_set_comparator - links the comparator present in the sytem with
* this phy
@@ -98,65 +101,116 @@ static int omap_usb_set_peripheral(struct usb_otg *otg,
return 0;
}
-static int omap_usb2_suspend(struct usb_phy *x, int suspend)
+static int omap_usb_power_off(struct phy *x)
{
- struct omap_usb *phy = phy_to_omapusb(x);
- int ret;
+ struct omap_usb *phy = phy_get_drvdata(x);
- if (suspend && !phy->is_suspended) {
- omap_control_usb_phy_power(phy->control_dev, 0);
- pm_runtime_put_sync(phy->dev);
- phy->is_suspended = 1;
- } else if (!suspend && phy->is_suspended) {
- ret = pm_runtime_get_sync(phy->dev);
- if (ret < 0) {
- dev_err(phy->dev, "get_sync failed with err %d\n", ret);
- return ret;
- }
- omap_control_usb_phy_power(phy->control_dev, 1);
- phy->is_suspended = 0;
- }
+ omap_control_phy_power(phy->control_dev, 0);
return 0;
}
-static int omap_usb_power_off(struct phy *x)
+static int omap_usb_power_on(struct phy *x)
{
struct omap_usb *phy = phy_get_drvdata(x);
- omap_control_usb_phy_power(phy->control_dev, 0);
+ omap_control_phy_power(phy->control_dev, 1);
return 0;
}
-static int omap_usb_power_on(struct phy *x)
+static int omap_usb_init(struct phy *x)
{
struct omap_usb *phy = phy_get_drvdata(x);
-
- omap_control_usb_phy_power(phy->control_dev, 1);
+ u32 val;
+
+ if (phy->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
+ /*
+ *
+ * Reduce the sensitivity of internal PHY by enabling the
+ * DISCON_BYP_LATCH of the USB2PHY_ANA_CONFIG1 register. This
+ * resolves issues with certain devices which can otherwise
+ * be prone to false disconnects.
+ *
+ */
+ val = omap_usb_readl(phy->phy_base, USB2PHY_ANA_CONFIG1);
+ val |= USB2PHY_DISCON_BYP_LATCH;
+ omap_usb_writel(phy->phy_base, USB2PHY_ANA_CONFIG1, val);
+ }
return 0;
}
static struct phy_ops ops = {
+ .init = omap_usb_init,
.power_on = omap_usb_power_on,
.power_off = omap_usb_power_off,
.owner = THIS_MODULE,
};
+#ifdef CONFIG_OF
+static const struct usb_phy_data omap_usb2_data = {
+ .label = "omap_usb2",
+ .flags = OMAP_USB2_HAS_START_SRP | OMAP_USB2_HAS_SET_VBUS,
+};
+
+static const struct usb_phy_data omap5_usb2_data = {
+ .label = "omap5_usb2",
+ .flags = 0,
+};
+
+static const struct usb_phy_data dra7x_usb2_data = {
+ .label = "dra7x_usb2",
+ .flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
+};
+
+static const struct usb_phy_data am437x_usb2_data = {
+ .label = "am437x_usb2",
+ .flags = 0,
+};
+
+static const struct of_device_id omap_usb2_id_table[] = {
+ {
+ .compatible = "ti,omap-usb2",
+ .data = &omap_usb2_data,
+ },
+ {
+ .compatible = "ti,omap5-usb2",
+ .data = &omap5_usb2_data,
+ },
+ {
+ .compatible = "ti,dra7x-usb2",
+ .data = &dra7x_usb2_data,
+ },
+ {
+ .compatible = "ti,am437x-usb2",
+ .data = &am437x_usb2_data,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
+#endif
+
static int omap_usb2_probe(struct platform_device *pdev)
{
struct omap_usb *phy;
struct phy *generic_phy;
+ struct resource *res;
struct phy_provider *phy_provider;
struct usb_otg *otg;
struct device_node *node = pdev->dev.of_node;
struct device_node *control_node;
struct platform_device *control_pdev;
+ const struct of_device_id *of_id;
+ struct usb_phy_data *phy_data;
+
+ of_id = of_match_device(of_match_ptr(omap_usb2_id_table), &pdev->dev);
- if (!node)
+ if (!of_id)
return -EINVAL;
+ phy_data = (struct usb_phy_data *)of_id->data;
+
phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
if (!phy) {
dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n");
@@ -172,15 +226,17 @@ static int omap_usb2_probe(struct platform_device *pdev)
phy->dev = &pdev->dev;
phy->phy.dev = phy->dev;
- phy->phy.label = "omap-usb2";
- phy->phy.set_suspend = omap_usb2_suspend;
+ phy->phy.label = phy_data->label;
phy->phy.otg = otg;
phy->phy.type = USB_PHY_TYPE_USB2;
- phy_provider = devm_of_phy_provider_register(phy->dev,
- of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
+ if (phy_data->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ phy->phy_base = devm_ioremap_resource(&pdev->dev, res);
+ if (!phy->phy_base)
+ return -ENOMEM;
+ phy->flags |= OMAP_USB2_CALIBRATE_FALSE_DISCONNECT;
+ }
control_node = of_parse_phandle(node, "ctrl-module", 0);
if (!control_node) {
@@ -195,14 +251,14 @@ static int omap_usb2_probe(struct platform_device *pdev)
}
phy->control_dev = &control_pdev->dev;
-
- phy->is_suspended = 1;
- omap_control_usb_phy_power(phy->control_dev, 0);
+ omap_control_phy_power(phy->control_dev, 0);
otg->set_host = omap_usb_set_host;
otg->set_peripheral = omap_usb_set_peripheral;
- otg->set_vbus = omap_usb_set_vbus;
- otg->start_srp = omap_usb_start_srp;
+ if (phy_data->flags & OMAP_USB2_HAS_SET_VBUS)
+ otg->set_vbus = omap_usb_set_vbus;
+ if (phy_data->flags & OMAP_USB2_HAS_START_SRP)
+ otg->start_srp = omap_usb_start_srp;
otg->phy = &phy->phy;
platform_set_drvdata(pdev, phy);
@@ -214,6 +270,11 @@ static int omap_usb2_probe(struct platform_device *pdev)
phy_set_drvdata(generic_phy, phy);
+ phy_provider = devm_of_phy_provider_register(phy->dev,
+ of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
if (IS_ERR(phy->wkupclk)) {
dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
@@ -297,14 +358,6 @@ static const struct dev_pm_ops omap_usb2_pm_ops = {
#define DEV_PM_OPS NULL
#endif
-#ifdef CONFIG_OF
-static const struct of_device_id omap_usb2_id_table[] = {
- { .compatible = "ti,omap-usb2" },
- {}
-};
-MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
-#endif
-
static struct platform_driver omap_usb2_driver = {
.probe = omap_usb2_probe,
.remove = omap_usb2_remove,
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
new file mode 100644
index 000000000000..8a8c6bc8709a
--- /dev/null
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -0,0 +1,228 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include "phy-samsung-usb2.h"
+
+static int samsung_usb2_phy_power_on(struct phy *phy)
+{
+ struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ int ret;
+
+ dev_dbg(drv->dev, "Request to power_on \"%s\" usb phy\n",
+ inst->cfg->label);
+ ret = clk_prepare_enable(drv->clk);
+ if (ret)
+ goto err_main_clk;
+ ret = clk_prepare_enable(drv->ref_clk);
+ if (ret)
+ goto err_instance_clk;
+ if (inst->cfg->power_on) {
+ spin_lock(&drv->lock);
+ ret = inst->cfg->power_on(inst);
+ spin_unlock(&drv->lock);
+ }
+
+ return 0;
+
+err_instance_clk:
+ clk_disable_unprepare(drv->clk);
+err_main_clk:
+ return ret;
+}
+
+static int samsung_usb2_phy_power_off(struct phy *phy)
+{
+ struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
+ struct samsung_usb2_phy_driver *drv = inst->drv;
+ int ret = 0;
+
+ dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n",
+ inst->cfg->label);
+ if (inst->cfg->power_off) {
+ spin_lock(&drv->lock);
+ ret = inst->cfg->power_off(inst);
+ spin_unlock(&drv->lock);
+ }
+ clk_disable_unprepare(drv->ref_clk);
+ clk_disable_unprepare(drv->clk);
+ return ret;
+}
+
+static struct phy_ops samsung_usb2_phy_ops = {
+ .power_on = samsung_usb2_phy_power_on,
+ .power_off = samsung_usb2_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *samsung_usb2_phy_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct samsung_usb2_phy_driver *drv;
+
+ drv = dev_get_drvdata(dev);
+ if (!drv)
+ return ERR_PTR(-EINVAL);
+
+ if (WARN_ON(args->args[0] >= drv->cfg->num_phys))
+ return ERR_PTR(-ENODEV);
+
+ return drv->instances[args->args[0]].phy;
+}
+
+static const struct of_device_id samsung_usb2_phy_of_match[] = {
+#ifdef CONFIG_PHY_EXYNOS4210_USB2
+ {
+ .compatible = "samsung,exynos4210-usb2-phy",
+ .data = &exynos4210_usb2_phy_config,
+ },
+#endif
+#ifdef CONFIG_PHY_EXYNOS4X12_USB2
+ {
+ .compatible = "samsung,exynos4x12-usb2-phy",
+ .data = &exynos4x12_usb2_phy_config,
+ },
+#endif
+#ifdef CONFIG_PHY_EXYNOS5250_USB2
+ {
+ .compatible = "samsung,exynos5250-usb2-phy",
+ .data = &exynos5250_usb2_phy_config,
+ },
+#endif
+ { },
+};
+
+static int samsung_usb2_phy_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ const struct samsung_usb2_phy_config *cfg;
+ struct device *dev = &pdev->dev;
+ struct phy_provider *phy_provider;
+ struct resource *mem;
+ struct samsung_usb2_phy_driver *drv;
+ int i, ret;
+
+ if (!pdev->dev.of_node) {
+ dev_err(dev, "This driver is required to be instantiated from device tree\n");
+ return -EINVAL;
+ }
+
+ match = of_match_node(samsung_usb2_phy_of_match, pdev->dev.of_node);
+ if (!match) {
+ dev_err(dev, "of_match_node() failed\n");
+ return -EINVAL;
+ }
+ cfg = match->data;
+
+ drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +
+ cfg->num_phys * sizeof(struct samsung_usb2_phy_instance),
+ GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, drv);
+ spin_lock_init(&drv->lock);
+
+ drv->cfg = cfg;
+ drv->dev = dev;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ drv->reg_phy = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(drv->reg_phy)) {
+ dev_err(dev, "Failed to map register memory (phy)\n");
+ return PTR_ERR(drv->reg_phy);
+ }
+
+ drv->reg_pmu = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "samsung,pmureg-phandle");
+ if (IS_ERR(drv->reg_pmu)) {
+ dev_err(dev, "Failed to map PMU registers (via syscon)\n");
+ return PTR_ERR(drv->reg_pmu);
+ }
+
+ if (drv->cfg->has_mode_switch) {
+ drv->reg_sys = syscon_regmap_lookup_by_phandle(
+ pdev->dev.of_node, "samsung,sysreg-phandle");
+ if (IS_ERR(drv->reg_sys)) {
+ dev_err(dev, "Failed to map system registers (via syscon)\n");
+ return PTR_ERR(drv->reg_sys);
+ }
+ }
+
+ drv->clk = devm_clk_get(dev, "phy");
+ if (IS_ERR(drv->clk)) {
+ dev_err(dev, "Failed to get clock of phy controller\n");
+ return PTR_ERR(drv->clk);
+ }
+
+ drv->ref_clk = devm_clk_get(dev, "ref");
+ if (IS_ERR(drv->ref_clk)) {
+ dev_err(dev, "Failed to get reference clock for the phy controller\n");
+ return PTR_ERR(drv->ref_clk);
+ }
+
+ drv->ref_rate = clk_get_rate(drv->ref_clk);
+ if (drv->cfg->rate_to_clk) {
+ ret = drv->cfg->rate_to_clk(drv->ref_rate, &drv->ref_reg_val);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < drv->cfg->num_phys; i++) {
+ char *label = drv->cfg->phys[i].label;
+ struct samsung_usb2_phy_instance *p = &drv->instances[i];
+
+ dev_dbg(dev, "Creating phy \"%s\"\n", label);
+ p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops, NULL);
+ if (IS_ERR(p->phy)) {
+ dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n",
+ label);
+ return PTR_ERR(p->phy);
+ }
+
+ p->cfg = &drv->cfg->phys[i];
+ p->drv = drv;
+ phy_set_bus_width(p->phy, 8);
+ phy_set_drvdata(p->phy, p);
+ }
+
+ phy_provider = devm_of_phy_provider_register(dev,
+ samsung_usb2_phy_xlate);
+ if (IS_ERR(phy_provider)) {
+ dev_err(drv->dev, "Failed to register phy provider\n");
+ return PTR_ERR(phy_provider);
+ }
+
+ return 0;
+}
+
+static struct platform_driver samsung_usb2_phy_driver = {
+ .probe = samsung_usb2_phy_probe,
+ .driver = {
+ .of_match_table = samsung_usb2_phy_of_match,
+ .name = "samsung-usb2-phy",
+ .owner = THIS_MODULE,
+ }
+};
+
+module_platform_driver(samsung_usb2_phy_driver);
+MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC USB PHY driver");
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:samsung-usb2-phy");
diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
new file mode 100644
index 000000000000..45b3170652bd
--- /dev/null
+++ b/drivers/phy/phy-samsung-usb2.h
@@ -0,0 +1,67 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _PHY_EXYNOS_USB2_H
+#define _PHY_EXYNOS_USB2_H
+
+#include <linux/clk.h>
+#include <linux/phy/phy.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+
+#define KHZ 1000
+#define MHZ (KHZ * KHZ)
+
+struct samsung_usb2_phy_driver;
+struct samsung_usb2_phy_instance;
+struct samsung_usb2_phy_config;
+
+struct samsung_usb2_phy_instance {
+ const struct samsung_usb2_common_phy *cfg;
+ struct phy *phy;
+ struct samsung_usb2_phy_driver *drv;
+ bool enabled;
+};
+
+struct samsung_usb2_phy_driver {
+ const struct samsung_usb2_phy_config *cfg;
+ struct clk *clk;
+ struct clk *ref_clk;
+ unsigned long ref_rate;
+ u32 ref_reg_val;
+ struct device *dev;
+ void __iomem *reg_phy;
+ struct regmap *reg_pmu;
+ struct regmap *reg_sys;
+ spinlock_t lock;
+ struct samsung_usb2_phy_instance instances[0];
+};
+
+struct samsung_usb2_common_phy {
+ int (*power_on)(struct samsung_usb2_phy_instance *);
+ int (*power_off)(struct samsung_usb2_phy_instance *);
+ unsigned int id;
+ char *label;
+};
+
+
+struct samsung_usb2_phy_config {
+ const struct samsung_usb2_common_phy *phys;
+ int (*rate_to_clk)(unsigned long, u32 *);
+ unsigned int num_phys;
+ bool has_mode_switch;
+};
+
+extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
+extern const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config;
+extern const struct samsung_usb2_phy_config exynos5250_usb2_phy_config;
+#endif
diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
new file mode 100644
index 000000000000..e6e6c4ba7145
--- /dev/null
+++ b/drivers/phy/phy-sun4i-usb.c
@@ -0,0 +1,331 @@
+/*
+ * Allwinner sun4i USB phy driver
+ *
+ * Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on code from
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ *
+ * Modelled after: Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+
+#define REG_ISCR 0x00
+#define REG_PHYCTL 0x04
+#define REG_PHYBIST 0x08
+#define REG_PHYTUNE 0x0c
+
+#define PHYCTL_DATA BIT(7)
+
+#define SUNXI_AHB_ICHR8_EN BIT(10)
+#define SUNXI_AHB_INCR4_BURST_EN BIT(9)
+#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
+#define SUNXI_ULPI_BYPASS_EN BIT(0)
+
+/* Common Control Bits for Both PHYs */
+#define PHY_PLL_BW 0x03
+#define PHY_RES45_CAL_EN 0x0c
+
+/* Private Control Bits for Each PHY */
+#define PHY_TX_AMPLITUDE_TUNE 0x20
+#define PHY_TX_SLEWRATE_TUNE 0x22
+#define PHY_VBUSVALID_TH_SEL 0x25
+#define PHY_PULLUP_RES_SEL 0x27
+#define PHY_OTG_FUNC_EN 0x28
+#define PHY_VBUS_DET_EN 0x29
+#define PHY_DISCON_TH_SEL 0x2a
+
+#define MAX_PHYS 3
+
+struct sun4i_usb_phy_data {
+ struct clk *clk;
+ void __iomem *base;
+ struct mutex mutex;
+ int num_phys;
+ u32 disc_thresh;
+ struct sun4i_usb_phy {
+ struct phy *phy;
+ void __iomem *pmu;
+ struct regulator *vbus;
+ struct reset_control *reset;
+ int index;
+ } phys[MAX_PHYS];
+};
+
+#define to_sun4i_usb_phy_data(phy) \
+ container_of((phy), struct sun4i_usb_phy_data, phys[(phy)->index])
+
+static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
+ int len)
+{
+ struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy);
+ u32 temp, usbc_bit = BIT(phy->index * 2);
+ int i;
+
+ mutex_lock(&phy_data->mutex);
+
+ for (i = 0; i < len; i++) {
+ temp = readl(phy_data->base + REG_PHYCTL);
+
+ /* clear the address portion */
+ temp &= ~(0xff << 8);
+
+ /* set the address */
+ temp |= ((addr + i) << 8);
+ writel(temp, phy_data->base + REG_PHYCTL);
+
+ /* set the data bit and clear usbc bit*/
+ temp = readb(phy_data->base + REG_PHYCTL);
+ if (data & 0x1)
+ temp |= PHYCTL_DATA;
+ else
+ temp &= ~PHYCTL_DATA;
+ temp &= ~usbc_bit;
+ writeb(temp, phy_data->base + REG_PHYCTL);
+
+ /* pulse usbc_bit */
+ temp = readb(phy_data->base + REG_PHYCTL);
+ temp |= usbc_bit;
+ writeb(temp, phy_data->base + REG_PHYCTL);
+
+ temp = readb(phy_data->base + REG_PHYCTL);
+ temp &= ~usbc_bit;
+ writeb(temp, phy_data->base + REG_PHYCTL);
+
+ data >>= 1;
+ }
+ mutex_unlock(&phy_data->mutex);
+}
+
+static void sun4i_usb_phy_passby(struct sun4i_usb_phy *phy, int enable)
+{
+ u32 bits, reg_value;
+
+ if (!phy->pmu)
+ return;
+
+ bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN |
+ SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN;
+
+ reg_value = readl(phy->pmu);
+
+ if (enable)
+ reg_value |= bits;
+ else
+ reg_value &= ~bits;
+
+ writel(reg_value, phy->pmu);
+}
+
+static int sun4i_usb_phy_init(struct phy *_phy)
+{
+ struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+ struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
+ int ret;
+
+ ret = clk_prepare_enable(data->clk);
+ if (ret)
+ return ret;
+
+ ret = reset_control_deassert(phy->reset);
+ if (ret) {
+ clk_disable_unprepare(data->clk);
+ return ret;
+ }
+
+ /* Adjust PHY's magnitude and rate */
+ sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
+
+ /* Disconnect threshold adjustment */
+ sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, data->disc_thresh, 2);
+
+ sun4i_usb_phy_passby(phy, 1);
+
+ return 0;
+}
+
+static int sun4i_usb_phy_exit(struct phy *_phy)
+{
+ struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+ struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
+
+ sun4i_usb_phy_passby(phy, 0);
+ reset_control_assert(phy->reset);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static int sun4i_usb_phy_power_on(struct phy *_phy)
+{
+ struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+ int ret = 0;
+
+ if (phy->vbus)
+ ret = regulator_enable(phy->vbus);
+
+ return ret;
+}
+
+static int sun4i_usb_phy_power_off(struct phy *_phy)
+{
+ struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+
+ if (phy->vbus)
+ regulator_disable(phy->vbus);
+
+ return 0;
+}
+
+static struct phy_ops sun4i_usb_phy_ops = {
+ .init = sun4i_usb_phy_init,
+ .exit = sun4i_usb_phy_exit,
+ .power_on = sun4i_usb_phy_power_on,
+ .power_off = sun4i_usb_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *sun4i_usb_phy_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
+
+ if (WARN_ON(args->args[0] == 0 || args->args[0] >= data->num_phys))
+ return ERR_PTR(-ENODEV);
+
+ return data->phys[args->args[0]].phy;
+}
+
+static int sun4i_usb_phy_probe(struct platform_device *pdev)
+{
+ struct sun4i_usb_phy_data *data;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ void __iomem *pmu = NULL;
+ struct phy_provider *phy_provider;
+ struct reset_control *reset;
+ struct regulator *vbus;
+ struct resource *res;
+ struct phy *phy;
+ char name[16];
+ int i;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ mutex_init(&data->mutex);
+
+ if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy"))
+ data->num_phys = 2;
+ else
+ data->num_phys = 3;
+
+ if (of_device_is_compatible(np, "allwinner,sun4i-a10-usb-phy"))
+ data->disc_thresh = 3;
+ else
+ data->disc_thresh = 2;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
+ data->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(data->base))
+ return PTR_ERR(data->base);
+
+ data->clk = devm_clk_get(dev, "usb_phy");
+ if (IS_ERR(data->clk)) {
+ dev_err(dev, "could not get usb_phy clock\n");
+ return PTR_ERR(data->clk);
+ }
+
+ /* Skip 0, 0 is the phy for otg which is not yet supported. */
+ for (i = 1; i < data->num_phys; i++) {
+ snprintf(name, sizeof(name), "usb%d_vbus", i);
+ vbus = devm_regulator_get_optional(dev, name);
+ if (IS_ERR(vbus)) {
+ if (PTR_ERR(vbus) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ vbus = NULL;
+ }
+
+ snprintf(name, sizeof(name), "usb%d_reset", i);
+ reset = devm_reset_control_get(dev, name);
+ if (IS_ERR(reset)) {
+ dev_err(dev, "failed to get reset %s\n", name);
+ return PTR_ERR(reset);
+ }
+
+ if (i) { /* No pmu for usbc0 */
+ snprintf(name, sizeof(name), "pmu%d", i);
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, name);
+ pmu = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pmu))
+ return PTR_ERR(pmu);
+ }
+
+ phy = devm_phy_create(dev, &sun4i_usb_phy_ops, NULL);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "failed to create PHY %d\n", i);
+ return PTR_ERR(phy);
+ }
+
+ data->phys[i].phy = phy;
+ data->phys[i].pmu = pmu;
+ data->phys[i].vbus = vbus;
+ data->phys[i].reset = reset;
+ data->phys[i].index = i;
+ phy_set_drvdata(phy, &data->phys[i]);
+ }
+
+ dev_set_drvdata(dev, data);
+ phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
+ return 0;
+}
+
+static const struct of_device_id sun4i_usb_phy_of_match[] = {
+ { .compatible = "allwinner,sun4i-a10-usb-phy" },
+ { .compatible = "allwinner,sun5i-a13-usb-phy" },
+ { .compatible = "allwinner,sun7i-a20-usb-phy" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);
+
+static struct platform_driver sun4i_usb_phy_driver = {
+ .probe = sun4i_usb_phy_probe,
+ .driver = {
+ .of_match_table = sun4i_usb_phy_of_match,
+ .name = "sun4i-usb-phy",
+ .owner = THIS_MODULE,
+ }
+};
+module_platform_driver(sun4i_usb_phy_driver);
+
+MODULE_DESCRIPTION("Allwinner sun4i USB phy driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
new file mode 100644
index 000000000000..591367654613
--- /dev/null
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -0,0 +1,470 @@
+/*
+ * phy-ti-pipe3 - PIPE3 PHY driver.
+ *
+ * Copyright (C) 2013 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/phy/phy.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/phy/omap_control_phy.h>
+#include <linux/of_platform.h>
+
+#define PLL_STATUS 0x00000004
+#define PLL_GO 0x00000008
+#define PLL_CONFIGURATION1 0x0000000C
+#define PLL_CONFIGURATION2 0x00000010
+#define PLL_CONFIGURATION3 0x00000014
+#define PLL_CONFIGURATION4 0x00000020
+
+#define PLL_REGM_MASK 0x001FFE00
+#define PLL_REGM_SHIFT 0x9
+#define PLL_REGM_F_MASK 0x0003FFFF
+#define PLL_REGM_F_SHIFT 0x0
+#define PLL_REGN_MASK 0x000001FE
+#define PLL_REGN_SHIFT 0x1
+#define PLL_SELFREQDCO_MASK 0x0000000E
+#define PLL_SELFREQDCO_SHIFT 0x1
+#define PLL_SD_MASK 0x0003FC00
+#define PLL_SD_SHIFT 10
+#define SET_PLL_GO 0x1
+#define PLL_LDOPWDN BIT(15)
+#define PLL_TICOPWDN BIT(16)
+#define PLL_LOCK 0x2
+#define PLL_IDLE 0x1
+
+/*
+ * This is an Empirical value that works, need to confirm the actual
+ * value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status
+ * to be correctly reflected in the PIPE3PHY_PLL_STATUS register.
+ */
+#define PLL_IDLE_TIME 100 /* in milliseconds */
+#define PLL_LOCK_TIME 100 /* in milliseconds */
+
+struct pipe3_dpll_params {
+ u16 m;
+ u8 n;
+ u8 freq:3;
+ u8 sd;
+ u32 mf;
+};
+
+struct pipe3_dpll_map {
+ unsigned long rate;
+ struct pipe3_dpll_params params;
+};
+
+struct ti_pipe3 {
+ void __iomem *pll_ctrl_base;
+ struct device *dev;
+ struct device *control_dev;
+ struct clk *wkupclk;
+ struct clk *sys_clk;
+ struct clk *refclk;
+ struct pipe3_dpll_map *dpll_map;
+};
+
+static struct pipe3_dpll_map dpll_map_usb[] = {
+ {12000000, {1250, 5, 4, 20, 0} }, /* 12 MHz */
+ {16800000, {3125, 20, 4, 20, 0} }, /* 16.8 MHz */
+ {19200000, {1172, 8, 4, 20, 65537} }, /* 19.2 MHz */
+ {20000000, {1000, 7, 4, 10, 0} }, /* 20 MHz */
+ {26000000, {1250, 12, 4, 20, 0} }, /* 26 MHz */
+ {38400000, {3125, 47, 4, 20, 92843} }, /* 38.4 MHz */
+ { }, /* Terminator */
+};
+
+static struct pipe3_dpll_map dpll_map_sata[] = {
+ {12000000, {1000, 7, 4, 6, 0} }, /* 12 MHz */
+ {16800000, {714, 7, 4, 6, 0} }, /* 16.8 MHz */
+ {19200000, {625, 7, 4, 6, 0} }, /* 19.2 MHz */
+ {20000000, {600, 7, 4, 6, 0} }, /* 20 MHz */
+ {26000000, {461, 7, 4, 6, 0} }, /* 26 MHz */
+ {38400000, {312, 7, 4, 6, 0} }, /* 38.4 MHz */
+ { }, /* Terminator */
+};
+
+static inline u32 ti_pipe3_readl(void __iomem *addr, unsigned offset)
+{
+ return __raw_readl(addr + offset);
+}
+
+static inline void ti_pipe3_writel(void __iomem *addr, unsigned offset,
+ u32 data)
+{
+ __raw_writel(data, addr + offset);
+}
+
+static struct pipe3_dpll_params *ti_pipe3_get_dpll_params(struct ti_pipe3 *phy)
+{
+ unsigned long rate;
+ struct pipe3_dpll_map *dpll_map = phy->dpll_map;
+
+ rate = clk_get_rate(phy->sys_clk);
+
+ for (; dpll_map->rate; dpll_map++) {
+ if (rate == dpll_map->rate)
+ return &dpll_map->params;
+ }
+
+ dev_err(phy->dev, "No DPLL configuration for %lu Hz SYS CLK\n", rate);
+
+ return NULL;
+}
+
+static int ti_pipe3_power_off(struct phy *x)
+{
+ struct ti_pipe3 *phy = phy_get_drvdata(x);
+
+ omap_control_phy_power(phy->control_dev, 0);
+
+ return 0;
+}
+
+static int ti_pipe3_power_on(struct phy *x)
+{
+ struct ti_pipe3 *phy = phy_get_drvdata(x);
+
+ omap_control_phy_power(phy->control_dev, 1);
+
+ return 0;
+}
+
+static int ti_pipe3_dpll_wait_lock(struct ti_pipe3 *phy)
+{
+ u32 val;
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(PLL_LOCK_TIME);
+ do {
+ cpu_relax();
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
+ if (val & PLL_LOCK)
+ break;
+ } while (!time_after(jiffies, timeout));
+
+ if (!(val & PLL_LOCK)) {
+ dev_err(phy->dev, "DPLL failed to lock\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int ti_pipe3_dpll_program(struct ti_pipe3 *phy)
+{
+ u32 val;
+ struct pipe3_dpll_params *dpll_params;
+
+ dpll_params = ti_pipe3_get_dpll_params(phy);
+ if (!dpll_params)
+ return -EINVAL;
+
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
+ val &= ~PLL_REGN_MASK;
+ val |= dpll_params->n << PLL_REGN_SHIFT;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
+
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+ val &= ~PLL_SELFREQDCO_MASK;
+ val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
+ val &= ~PLL_REGM_MASK;
+ val |= dpll_params->m << PLL_REGM_SHIFT;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
+
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
+ val &= ~PLL_REGM_F_MASK;
+ val |= dpll_params->mf << PLL_REGM_F_SHIFT;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
+
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
+ val &= ~PLL_SD_MASK;
+ val |= dpll_params->sd << PLL_SD_SHIFT;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
+
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO);
+
+ return ti_pipe3_dpll_wait_lock(phy);
+}
+
+static int ti_pipe3_init(struct phy *x)
+{
+ struct ti_pipe3 *phy = phy_get_drvdata(x);
+ u32 val;
+ int ret = 0;
+
+ /* Bring it out of IDLE if it is IDLE */
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+ if (val & PLL_IDLE) {
+ val &= ~PLL_IDLE;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+ ret = ti_pipe3_dpll_wait_lock(phy);
+ }
+
+ /* Program the DPLL only if not locked */
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
+ if (!(val & PLL_LOCK))
+ if (ti_pipe3_dpll_program(phy))
+ return -EINVAL;
+
+ return ret;
+}
+
+static int ti_pipe3_exit(struct phy *x)
+{
+ struct ti_pipe3 *phy = phy_get_drvdata(x);
+ u32 val;
+ unsigned long timeout;
+
+ /* SATA DPLL can't be powered down due to Errata i783 */
+ if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata"))
+ return 0;
+
+ /* Put DPLL in IDLE mode */
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+ val |= PLL_IDLE;
+ ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+
+ /* wait for LDO and Oscillator to power down */
+ timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME);
+ do {
+ cpu_relax();
+ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
+ if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
+ break;
+ } while (!time_after(jiffies, timeout));
+
+ if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
+ dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n",
+ val);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+static struct phy_ops ops = {
+ .init = ti_pipe3_init,
+ .exit = ti_pipe3_exit,
+ .power_on = ti_pipe3_power_on,
+ .power_off = ti_pipe3_power_off,
+ .owner = THIS_MODULE,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id ti_pipe3_id_table[];
+#endif
+
+static int ti_pipe3_probe(struct platform_device *pdev)
+{
+ struct ti_pipe3 *phy;
+ struct phy *generic_phy;
+ struct phy_provider *phy_provider;
+ struct resource *res;
+ struct device_node *node = pdev->dev.of_node;
+ struct device_node *control_node;
+ struct platform_device *control_pdev;
+ const struct of_device_id *match;
+
+ match = of_match_device(of_match_ptr(ti_pipe3_id_table), &pdev->dev);
+ if (!match)
+ return -EINVAL;
+
+ phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy) {
+ dev_err(&pdev->dev, "unable to alloc mem for TI PIPE3 PHY\n");
+ return -ENOMEM;
+ }
+
+ phy->dpll_map = (struct pipe3_dpll_map *)match->data;
+ if (!phy->dpll_map) {
+ dev_err(&pdev->dev, "no DPLL data\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_ctrl");
+ phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(phy->pll_ctrl_base))
+ return PTR_ERR(phy->pll_ctrl_base);
+
+ phy->dev = &pdev->dev;
+
+ if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
+
+ phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
+ if (IS_ERR(phy->wkupclk)) {
+ dev_err(&pdev->dev, "unable to get wkupclk\n");
+ return PTR_ERR(phy->wkupclk);
+ }
+
+ phy->refclk = devm_clk_get(phy->dev, "refclk");
+ if (IS_ERR(phy->refclk)) {
+ dev_err(&pdev->dev, "unable to get refclk\n");
+ return PTR_ERR(phy->refclk);
+ }
+ } else {
+ phy->wkupclk = ERR_PTR(-ENODEV);
+ phy->refclk = ERR_PTR(-ENODEV);
+ }
+
+ phy->sys_clk = devm_clk_get(phy->dev, "sysclk");
+ if (IS_ERR(phy->sys_clk)) {
+ dev_err(&pdev->dev, "unable to get sysclk\n");
+ return -EINVAL;
+ }
+
+ control_node = of_parse_phandle(node, "ctrl-module", 0);
+ if (!control_node) {
+ dev_err(&pdev->dev, "Failed to get control device phandle\n");
+ return -EINVAL;
+ }
+
+ control_pdev = of_find_device_by_node(control_node);
+ if (!control_pdev) {
+ dev_err(&pdev->dev, "Failed to get control device\n");
+ return -EINVAL;
+ }
+
+ phy->control_dev = &control_pdev->dev;
+
+ omap_control_phy_power(phy->control_dev, 0);
+
+ platform_set_drvdata(pdev, phy);
+ pm_runtime_enable(phy->dev);
+
+ generic_phy = devm_phy_create(phy->dev, &ops, NULL);
+ if (IS_ERR(generic_phy))
+ return PTR_ERR(generic_phy);
+
+ phy_set_drvdata(generic_phy, phy);
+ phy_provider = devm_of_phy_provider_register(phy->dev,
+ of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
+ pm_runtime_get(&pdev->dev);
+
+ return 0;
+}
+
+static int ti_pipe3_remove(struct platform_device *pdev)
+{
+ if (!pm_runtime_suspended(&pdev->dev))
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int ti_pipe3_runtime_suspend(struct device *dev)
+{
+ struct ti_pipe3 *phy = dev_get_drvdata(dev);
+
+ if (!IS_ERR(phy->wkupclk))
+ clk_disable_unprepare(phy->wkupclk);
+ if (!IS_ERR(phy->refclk))
+ clk_disable_unprepare(phy->refclk);
+
+ return 0;
+}
+
+static int ti_pipe3_runtime_resume(struct device *dev)
+{
+ u32 ret = 0;
+ struct ti_pipe3 *phy = dev_get_drvdata(dev);
+
+ if (!IS_ERR(phy->refclk)) {
+ ret = clk_prepare_enable(phy->refclk);
+ if (ret) {
+ dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
+ goto err1;
+ }
+ }
+
+ if (!IS_ERR(phy->wkupclk)) {
+ ret = clk_prepare_enable(phy->wkupclk);
+ if (ret) {
+ dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
+ goto err2;
+ }
+ }
+
+ return 0;
+
+err2:
+ if (!IS_ERR(phy->refclk))
+ clk_disable_unprepare(phy->refclk);
+
+err1:
+ return ret;
+}
+
+static const struct dev_pm_ops ti_pipe3_pm_ops = {
+ SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend,
+ ti_pipe3_runtime_resume, NULL)
+};
+
+#define DEV_PM_OPS (&ti_pipe3_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id ti_pipe3_id_table[] = {
+ {
+ .compatible = "ti,phy-usb3",
+ .data = dpll_map_usb,
+ },
+ {
+ .compatible = "ti,omap-usb3",
+ .data = dpll_map_usb,
+ },
+ {
+ .compatible = "ti,phy-pipe3-sata",
+ .data = dpll_map_sata,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ti_pipe3_id_table);
+#endif
+
+static struct platform_driver ti_pipe3_driver = {
+ .probe = ti_pipe3_probe,
+ .remove = ti_pipe3_remove,
+ .driver = {
+ .name = "ti-pipe3",
+ .owner = THIS_MODULE,
+ .pm = DEV_PM_OPS,
+ .of_match_table = of_match_ptr(ti_pipe3_id_table),
+ },
+};
+
+module_platform_driver(ti_pipe3_driver);
+
+MODULE_ALIAS("platform: ti_pipe3");
+MODULE_AUTHOR("Texas Instruments Inc.");
+MODULE_DESCRIPTION("TI PIPE3 phy driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index daf65e68aaab..2e0e9b3774c8 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -338,7 +338,7 @@ static void twl4030_usb_set_mode(struct twl4030_usb *twl, int mode)
dev_err(twl->dev, "unsupported T2 transceiver mode %d\n",
mode);
break;
- };
+ }
}
static void twl4030_i2c_access(struct twl4030_usb *twl, int on)
@@ -661,7 +661,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
struct phy_provider *phy_provider;
struct phy_init_data *init_data = NULL;
- twl = devm_kzalloc(&pdev->dev, sizeof *twl, GFP_KERNEL);
+ twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
if (!twl)
return -ENOMEM;
@@ -676,7 +676,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
return -EINVAL;
}
- otg = devm_kzalloc(&pdev->dev, sizeof *otg, GFP_KERNEL);
+ otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
if (!otg)
return -ENOMEM;
@@ -695,11 +695,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
otg->set_host = twl4030_set_host;
otg->set_peripheral = twl4030_set_peripheral;
- phy_provider = devm_of_phy_provider_register(twl->dev,
- of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
-
phy = devm_phy_create(twl->dev, &ops, init_data);
if (IS_ERR(phy)) {
dev_dbg(&pdev->dev, "Failed to create PHY\n");
@@ -708,6 +703,11 @@ static int twl4030_usb_probe(struct platform_device *pdev)
phy_set_drvdata(phy, twl);
+ phy_provider = devm_of_phy_provider_register(twl->dev,
+ of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
/* init spinlock for workqueue */
spin_lock_init(&twl->lock);
diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c
new file mode 100644
index 000000000000..4aa1ccd1511f
--- /dev/null
+++ b/drivers/phy/phy-xgene.c
@@ -0,0 +1,1750 @@
+/*
+ * AppliedMicro X-Gene Multi-purpose PHY driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Author: Loc Ho <lho@apm.com>
+ * Tuan Phan <tphan@apm.com>
+ * Suman Tripathi <stripathi@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/>.
+ *
+ * The APM X-Gene PHY consists of two PLL clock macro's (CMU) and lanes.
+ * The first PLL clock macro is used for internal reference clock. The second
+ * PLL clock macro is used to generate the clock for the PHY. This driver
+ * configures the first PLL CMU, the second PLL CMU, and programs the PHY to
+ * operate according to the mode of operation. The first PLL CMU is only
+ * required if internal clock is enabled.
+ *
+ * Logical Layer Out Of HW module units:
+ *
+ * -----------------
+ * | Internal | |------|
+ * | Ref PLL CMU |----| | ------------- ---------
+ * ------------ ---- | MUX |-----|PHY PLL CMU|----| Serdes|
+ * | | | | ---------
+ * External Clock ------| | -------------
+ * |------|
+ *
+ * The Ref PLL CMU CSR (Configuration System Registers) is accessed
+ * indirectly from the SDS offset at 0x2000. It is only required for
+ * internal reference clock.
+ * The PHY PLL CMU CSR is accessed indirectly from the SDS offset at 0x0000.
+ * The Serdes CSR is accessed indirectly from the SDS offset at 0x0400.
+ *
+ * The Ref PLL CMU can be located within the same PHY IP or outside the PHY IP
+ * due to shared Ref PLL CMU. For PHY with Ref PLL CMU shared with another IP,
+ * it is located outside the PHY IP. This is the case for the PHY located
+ * at 0x1f23a000 (SATA Port 4/5). For such PHY, another resource is required
+ * to located the SDS/Ref PLL CMU module and its clock for that IP enabled.
+ *
+ * Currently, this driver only supports Gen3 SATA mode with external clock.
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/phy/phy.h>
+#include <linux/clk.h>
+
+/* Max 2 lanes per a PHY unit */
+#define MAX_LANE 2
+
+/* Register offset inside the PHY */
+#define SERDES_PLL_INDIRECT_OFFSET 0x0000
+#define SERDES_PLL_REF_INDIRECT_OFFSET 0x2000
+#define SERDES_INDIRECT_OFFSET 0x0400
+#define SERDES_LANE_STRIDE 0x0200
+
+/* Some default Serdes parameters */
+#define DEFAULT_SATA_TXBOOST_GAIN { 0x1e, 0x1e, 0x1e }
+#define DEFAULT_SATA_TXEYEDIRECTION { 0x0, 0x0, 0x0 }
+#define DEFAULT_SATA_TXEYETUNING { 0xa, 0xa, 0xa }
+#define DEFAULT_SATA_SPD_SEL { 0x1, 0x3, 0x7 }
+#define DEFAULT_SATA_TXAMP { 0x8, 0x8, 0x8 }
+#define DEFAULT_SATA_TXCN1 { 0x2, 0x2, 0x2 }
+#define DEFAULT_SATA_TXCN2 { 0x0, 0x0, 0x0 }
+#define DEFAULT_SATA_TXCP1 { 0xa, 0xa, 0xa }
+
+#define SATA_SPD_SEL_GEN3 0x7
+#define SATA_SPD_SEL_GEN2 0x3
+#define SATA_SPD_SEL_GEN1 0x1
+
+#define SSC_DISABLE 0
+#define SSC_ENABLE 1
+
+#define FBDIV_VAL_50M 0x77
+#define REFDIV_VAL_50M 0x1
+#define FBDIV_VAL_100M 0x3B
+#define REFDIV_VAL_100M 0x0
+
+/* SATA Clock/Reset CSR */
+#define SATACLKENREG 0x00000000
+#define SATA0_CORE_CLKEN 0x00000002
+#define SATA1_CORE_CLKEN 0x00000004
+#define SATASRESETREG 0x00000004
+#define SATA_MEM_RESET_MASK 0x00000020
+#define SATA_MEM_RESET_RD(src) (((src) & 0x00000020) >> 5)
+#define SATA_SDS_RESET_MASK 0x00000004
+#define SATA_CSR_RESET_MASK 0x00000001
+#define SATA_CORE_RESET_MASK 0x00000002
+#define SATA_PMCLK_RESET_MASK 0x00000010
+#define SATA_PCLK_RESET_MASK 0x00000008
+
+/* SDS CSR used for PHY Indirect access */
+#define SATA_ENET_SDS_PCS_CTL0 0x00000000
+#define REGSPEC_CFG_I_TX_WORDMODE0_SET(dst, src) \
+ (((dst) & ~0x00070000) | (((u32) (src) << 16) & 0x00070000))
+#define REGSPEC_CFG_I_RX_WORDMODE0_SET(dst, src) \
+ (((dst) & ~0x00e00000) | (((u32) (src) << 21) & 0x00e00000))
+#define SATA_ENET_SDS_CTL0 0x0000000c
+#define REGSPEC_CFG_I_CUSTOMER_PIN_MODE0_SET(dst, src) \
+ (((dst) & ~0x00007fff) | (((u32) (src)) & 0x00007fff))
+#define SATA_ENET_SDS_CTL1 0x00000010
+#define CFG_I_SPD_SEL_CDR_OVR1_SET(dst, src) \
+ (((dst) & ~0x0000000f) | (((u32) (src)) & 0x0000000f))
+#define SATA_ENET_SDS_RST_CTL 0x00000024
+#define SATA_ENET_SDS_IND_CMD_REG 0x0000003c
+#define CFG_IND_WR_CMD_MASK 0x00000001
+#define CFG_IND_RD_CMD_MASK 0x00000002
+#define CFG_IND_CMD_DONE_MASK 0x00000004
+#define CFG_IND_ADDR_SET(dst, src) \
+ (((dst) & ~0x003ffff0) | (((u32) (src) << 4) & 0x003ffff0))
+#define SATA_ENET_SDS_IND_RDATA_REG 0x00000040
+#define SATA_ENET_SDS_IND_WDATA_REG 0x00000044
+#define SATA_ENET_CLK_MACRO_REG 0x0000004c
+#define I_RESET_B_SET(dst, src) \
+ (((dst) & ~0x00000001) | (((u32) (src)) & 0x00000001))
+#define I_PLL_FBDIV_SET(dst, src) \
+ (((dst) & ~0x001ff000) | (((u32) (src) << 12) & 0x001ff000))
+#define I_CUSTOMEROV_SET(dst, src) \
+ (((dst) & ~0x00000f80) | (((u32) (src) << 7) & 0x00000f80))
+#define O_PLL_LOCK_RD(src) (((src) & 0x40000000) >> 30)
+#define O_PLL_READY_RD(src) (((src) & 0x80000000) >> 31)
+
+/* PLL Clock Macro Unit (CMU) CSR accessing from SDS indirectly */
+#define CMU_REG0 0x00000
+#define CMU_REG0_PLL_REF_SEL_MASK 0x00002000
+#define CMU_REG0_PLL_REF_SEL_SET(dst, src) \
+ (((dst) & ~0x00002000) | (((u32) (src) << 13) & 0x00002000))
+#define CMU_REG0_PDOWN_MASK 0x00004000
+#define CMU_REG0_CAL_COUNT_RESOL_SET(dst, src) \
+ (((dst) & ~0x000000e0) | (((u32) (src) << 5) & 0x000000e0))
+#define CMU_REG1 0x00002
+#define CMU_REG1_PLL_CP_SET(dst, src) \
+ (((dst) & ~0x00003c00) | (((u32) (src) << 10) & 0x00003c00))
+#define CMU_REG1_PLL_MANUALCAL_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define CMU_REG1_PLL_CP_SEL_SET(dst, src) \
+ (((dst) & ~0x000003e0) | (((u32) (src) << 5) & 0x000003e0))
+#define CMU_REG1_REFCLK_CMOS_SEL_MASK 0x00000001
+#define CMU_REG1_REFCLK_CMOS_SEL_SET(dst, src) \
+ (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define CMU_REG2 0x00004
+#define CMU_REG2_PLL_REFDIV_SET(dst, src) \
+ (((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000))
+#define CMU_REG2_PLL_LFRES_SET(dst, src) \
+ (((dst) & ~0x0000001e) | (((u32) (src) << 1) & 0x0000001e))
+#define CMU_REG2_PLL_FBDIV_SET(dst, src) \
+ (((dst) & ~0x00003fe0) | (((u32) (src) << 5) & 0x00003fe0))
+#define CMU_REG3 0x00006
+#define CMU_REG3_VCOVARSEL_SET(dst, src) \
+ (((dst) & ~0x0000000f) | (((u32) (src) << 0) & 0x0000000f))
+#define CMU_REG3_VCO_MOMSEL_INIT_SET(dst, src) \
+ (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define CMU_REG3_VCO_MANMOMSEL_SET(dst, src) \
+ (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define CMU_REG4 0x00008
+#define CMU_REG5 0x0000a
+#define CMU_REG5_PLL_LFSMCAP_SET(dst, src) \
+ (((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000))
+#define CMU_REG5_PLL_LOCK_RESOLUTION_SET(dst, src) \
+ (((dst) & ~0x0000000e) | (((u32) (src) << 1) & 0x0000000e))
+#define CMU_REG5_PLL_LFCAP_SET(dst, src) \
+ (((dst) & ~0x00003000) | (((u32) (src) << 12) & 0x00003000))
+#define CMU_REG5_PLL_RESETB_MASK 0x00000001
+#define CMU_REG6 0x0000c
+#define CMU_REG6_PLL_VREGTRIM_SET(dst, src) \
+ (((dst) & ~0x00000600) | (((u32) (src) << 9) & 0x00000600))
+#define CMU_REG6_MAN_PVT_CAL_SET(dst, src) \
+ (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define CMU_REG7 0x0000e
+#define CMU_REG7_PLL_CALIB_DONE_RD(src) ((0x00004000 & (u32) (src)) >> 14)
+#define CMU_REG7_VCO_CAL_FAIL_RD(src) ((0x00000c00 & (u32) (src)) >> 10)
+#define CMU_REG8 0x00010
+#define CMU_REG9 0x00012
+#define CMU_REG9_WORD_LEN_8BIT 0x000
+#define CMU_REG9_WORD_LEN_10BIT 0x001
+#define CMU_REG9_WORD_LEN_16BIT 0x002
+#define CMU_REG9_WORD_LEN_20BIT 0x003
+#define CMU_REG9_WORD_LEN_32BIT 0x004
+#define CMU_REG9_WORD_LEN_40BIT 0x005
+#define CMU_REG9_WORD_LEN_64BIT 0x006
+#define CMU_REG9_WORD_LEN_66BIT 0x007
+#define CMU_REG9_TX_WORD_MODE_CH1_SET(dst, src) \
+ (((dst) & ~0x00000380) | (((u32) (src) << 7) & 0x00000380))
+#define CMU_REG9_TX_WORD_MODE_CH0_SET(dst, src) \
+ (((dst) & ~0x00000070) | (((u32) (src) << 4) & 0x00000070))
+#define CMU_REG9_PLL_POST_DIVBY2_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define CMU_REG9_VBG_BYPASSB_SET(dst, src) \
+ (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define CMU_REG9_IGEN_BYPASS_SET(dst, src) \
+ (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define CMU_REG10 0x00014
+#define CMU_REG10_VREG_REFSEL_SET(dst, src) \
+ (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define CMU_REG11 0x00016
+#define CMU_REG12 0x00018
+#define CMU_REG12_STATE_DELAY9_SET(dst, src) \
+ (((dst) & ~0x000000f0) | (((u32) (src) << 4) & 0x000000f0))
+#define CMU_REG13 0x0001a
+#define CMU_REG14 0x0001c
+#define CMU_REG15 0x0001e
+#define CMU_REG16 0x00020
+#define CMU_REG16_PVT_DN_MAN_ENA_MASK 0x00000001
+#define CMU_REG16_PVT_UP_MAN_ENA_MASK 0x00000002
+#define CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(dst, src) \
+ (((dst) & ~0x0000001c) | (((u32) (src) << 2) & 0x0000001c))
+#define CMU_REG16_CALIBRATION_DONE_OVERRIDE_SET(dst, src) \
+ (((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040))
+#define CMU_REG16_BYPASS_PLL_LOCK_SET(dst, src) \
+ (((dst) & ~0x00000020) | (((u32) (src) << 5) & 0x00000020))
+#define CMU_REG17 0x00022
+#define CMU_REG17_PVT_CODE_R2A_SET(dst, src) \
+ (((dst) & ~0x00007f00) | (((u32) (src) << 8) & 0x00007f00))
+#define CMU_REG17_RESERVED_7_SET(dst, src) \
+ (((dst) & ~0x000000e0) | (((u32) (src) << 5) & 0x000000e0))
+#define CMU_REG17_PVT_TERM_MAN_ENA_MASK 0x00008000
+#define CMU_REG18 0x00024
+#define CMU_REG19 0x00026
+#define CMU_REG20 0x00028
+#define CMU_REG21 0x0002a
+#define CMU_REG22 0x0002c
+#define CMU_REG23 0x0002e
+#define CMU_REG24 0x00030
+#define CMU_REG25 0x00032
+#define CMU_REG26 0x00034
+#define CMU_REG26_FORCE_PLL_LOCK_SET(dst, src) \
+ (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define CMU_REG27 0x00036
+#define CMU_REG28 0x00038
+#define CMU_REG29 0x0003a
+#define CMU_REG30 0x0003c
+#define CMU_REG30_LOCK_COUNT_SET(dst, src) \
+ (((dst) & ~0x00000006) | (((u32) (src) << 1) & 0x00000006))
+#define CMU_REG30_PCIE_MODE_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define CMU_REG31 0x0003e
+#define CMU_REG32 0x00040
+#define CMU_REG32_FORCE_VCOCAL_START_MASK 0x00004000
+#define CMU_REG32_PVT_CAL_WAIT_SEL_SET(dst, src) \
+ (((dst) & ~0x00000006) | (((u32) (src) << 1) & 0x00000006))
+#define CMU_REG32_IREF_ADJ_SET(dst, src) \
+ (((dst) & ~0x00000180) | (((u32) (src) << 7) & 0x00000180))
+#define CMU_REG33 0x00042
+#define CMU_REG34 0x00044
+#define CMU_REG34_VCO_CAL_VTH_LO_MAX_SET(dst, src) \
+ (((dst) & ~0x0000000f) | (((u32) (src) << 0) & 0x0000000f))
+#define CMU_REG34_VCO_CAL_VTH_HI_MAX_SET(dst, src) \
+ (((dst) & ~0x00000f00) | (((u32) (src) << 8) & 0x00000f00))
+#define CMU_REG34_VCO_CAL_VTH_LO_MIN_SET(dst, src) \
+ (((dst) & ~0x000000f0) | (((u32) (src) << 4) & 0x000000f0))
+#define CMU_REG34_VCO_CAL_VTH_HI_MIN_SET(dst, src) \
+ (((dst) & ~0x0000f000) | (((u32) (src) << 12) & 0x0000f000))
+#define CMU_REG35 0x00046
+#define CMU_REG35_PLL_SSC_MOD_SET(dst, src) \
+ (((dst) & ~0x0000fe00) | (((u32) (src) << 9) & 0x0000fe00))
+#define CMU_REG36 0x00048
+#define CMU_REG36_PLL_SSC_EN_SET(dst, src) \
+ (((dst) & ~0x00000010) | (((u32) (src) << 4) & 0x00000010))
+#define CMU_REG36_PLL_SSC_VSTEP_SET(dst, src) \
+ (((dst) & ~0x0000ffc0) | (((u32) (src) << 6) & 0x0000ffc0))
+#define CMU_REG36_PLL_SSC_DSMSEL_SET(dst, src) \
+ (((dst) & ~0x00000020) | (((u32) (src) << 5) & 0x00000020))
+#define CMU_REG37 0x0004a
+#define CMU_REG38 0x0004c
+#define CMU_REG39 0x0004e
+
+/* PHY lane CSR accessing from SDS indirectly */
+#define RXTX_REG0 0x000
+#define RXTX_REG0_CTLE_EQ_HR_SET(dst, src) \
+ (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define RXTX_REG0_CTLE_EQ_QR_SET(dst, src) \
+ (((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0))
+#define RXTX_REG0_CTLE_EQ_FR_SET(dst, src) \
+ (((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e))
+#define RXTX_REG1 0x002
+#define RXTX_REG1_RXACVCM_SET(dst, src) \
+ (((dst) & ~0x0000f000) | (((u32) (src) << 12) & 0x0000f000))
+#define RXTX_REG1_CTLE_EQ_SET(dst, src) \
+ (((dst) & ~0x00000f80) | (((u32) (src) << 7) & 0x00000f80))
+#define RXTX_REG1_RXVREG1_SET(dst, src) \
+ (((dst) & ~0x00000060) | (((u32) (src) << 5) & 0x00000060))
+#define RXTX_REG1_RXIREF_ADJ_SET(dst, src) \
+ (((dst) & ~0x00000006) | (((u32) (src) << 1) & 0x00000006))
+#define RXTX_REG2 0x004
+#define RXTX_REG2_VTT_ENA_SET(dst, src) \
+ (((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100))
+#define RXTX_REG2_TX_FIFO_ENA_SET(dst, src) \
+ (((dst) & ~0x00000020) | (((u32) (src) << 5) & 0x00000020))
+#define RXTX_REG2_VTT_SEL_SET(dst, src) \
+ (((dst) & ~0x000000c0) | (((u32) (src) << 6) & 0x000000c0))
+#define RXTX_REG4 0x008
+#define RXTX_REG4_TX_LOOPBACK_BUF_EN_MASK 0x00000040
+#define RXTX_REG4_TX_DATA_RATE_SET(dst, src) \
+ (((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000))
+#define RXTX_REG4_TX_WORD_MODE_SET(dst, src) \
+ (((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800))
+#define RXTX_REG5 0x00a
+#define RXTX_REG5_TX_CN1_SET(dst, src) \
+ (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define RXTX_REG5_TX_CP1_SET(dst, src) \
+ (((dst) & ~0x000007e0) | (((u32) (src) << 5) & 0x000007e0))
+#define RXTX_REG5_TX_CN2_SET(dst, src) \
+ (((dst) & ~0x0000001f) | (((u32) (src) << 0) & 0x0000001f))
+#define RXTX_REG6 0x00c
+#define RXTX_REG6_TXAMP_CNTL_SET(dst, src) \
+ (((dst) & ~0x00000780) | (((u32) (src) << 7) & 0x00000780))
+#define RXTX_REG6_TXAMP_ENA_SET(dst, src) \
+ (((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040))
+#define RXTX_REG6_RX_BIST_ERRCNT_RD_SET(dst, src) \
+ (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define RXTX_REG6_TX_IDLE_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define RXTX_REG6_RX_BIST_RESYNC_SET(dst, src) \
+ (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define RXTX_REG7 0x00e
+#define RXTX_REG7_RESETB_RXD_MASK 0x00000100
+#define RXTX_REG7_RESETB_RXA_MASK 0x00000080
+#define RXTX_REG7_BIST_ENA_RX_SET(dst, src) \
+ (((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040))
+#define RXTX_REG7_RX_WORD_MODE_SET(dst, src) \
+ (((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800))
+#define RXTX_REG8 0x010
+#define RXTX_REG8_CDR_LOOP_ENA_SET(dst, src) \
+ (((dst) & ~0x00004000) | (((u32) (src) << 14) & 0x00004000))
+#define RXTX_REG8_CDR_BYPASS_RXLOS_SET(dst, src) \
+ (((dst) & ~0x00000800) | (((u32) (src) << 11) & 0x00000800))
+#define RXTX_REG8_SSC_ENABLE_SET(dst, src) \
+ (((dst) & ~0x00000200) | (((u32) (src) << 9) & 0x00000200))
+#define RXTX_REG8_SD_VREF_SET(dst, src) \
+ (((dst) & ~0x000000f0) | (((u32) (src) << 4) & 0x000000f0))
+#define RXTX_REG8_SD_DISABLE_SET(dst, src) \
+ (((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100))
+#define RXTX_REG7 0x00e
+#define RXTX_REG7_RESETB_RXD_SET(dst, src) \
+ (((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100))
+#define RXTX_REG7_RESETB_RXA_SET(dst, src) \
+ (((dst) & ~0x00000080) | (((u32) (src) << 7) & 0x00000080))
+#define RXTX_REG7_LOOP_BACK_ENA_CTLE_MASK 0x00004000
+#define RXTX_REG7_LOOP_BACK_ENA_CTLE_SET(dst, src) \
+ (((dst) & ~0x00004000) | (((u32) (src) << 14) & 0x00004000))
+#define RXTX_REG11 0x016
+#define RXTX_REG11_PHASE_ADJUST_LIMIT_SET(dst, src) \
+ (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define RXTX_REG12 0x018
+#define RXTX_REG12_LATCH_OFF_ENA_SET(dst, src) \
+ (((dst) & ~0x00002000) | (((u32) (src) << 13) & 0x00002000))
+#define RXTX_REG12_SUMOS_ENABLE_SET(dst, src) \
+ (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define RXTX_REG12_RX_DET_TERM_ENABLE_MASK 0x00000002
+#define RXTX_REG12_RX_DET_TERM_ENABLE_SET(dst, src) \
+ (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define RXTX_REG13 0x01a
+#define RXTX_REG14 0x01c
+#define RXTX_REG14_CLTE_LATCAL_MAN_PROG_SET(dst, src) \
+ (((dst) & ~0x0000003f) | (((u32) (src) << 0) & 0x0000003f))
+#define RXTX_REG14_CTLE_LATCAL_MAN_ENA_SET(dst, src) \
+ (((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040))
+#define RXTX_REG26 0x034
+#define RXTX_REG26_PERIOD_ERROR_LATCH_SET(dst, src) \
+ (((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800))
+#define RXTX_REG26_BLWC_ENA_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define RXTX_REG21 0x02a
+#define RXTX_REG21_DO_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10)
+#define RXTX_REG21_XO_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4)
+#define RXTX_REG21_LATCH_CAL_FAIL_ODD_RD(src) ((0x0000000f & (u32)(src)))
+#define RXTX_REG22 0x02c
+#define RXTX_REG22_SO_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4)
+#define RXTX_REG22_EO_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10)
+#define RXTX_REG22_LATCH_CAL_FAIL_EVEN_RD(src) ((0x0000000f & (u32)(src)))
+#define RXTX_REG23 0x02e
+#define RXTX_REG23_DE_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10)
+#define RXTX_REG23_XE_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4)
+#define RXTX_REG24 0x030
+#define RXTX_REG24_EE_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10)
+#define RXTX_REG24_SE_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4)
+#define RXTX_REG27 0x036
+#define RXTX_REG28 0x038
+#define RXTX_REG31 0x03e
+#define RXTX_REG38 0x04c
+#define RXTX_REG38_CUSTOMER_PINMODE_INV_SET(dst, src) \
+ (((dst) & 0x0000fffe) | (((u32) (src) << 1) & 0x0000fffe))
+#define RXTX_REG39 0x04e
+#define RXTX_REG40 0x050
+#define RXTX_REG41 0x052
+#define RXTX_REG42 0x054
+#define RXTX_REG43 0x056
+#define RXTX_REG44 0x058
+#define RXTX_REG45 0x05a
+#define RXTX_REG46 0x05c
+#define RXTX_REG47 0x05e
+#define RXTX_REG48 0x060
+#define RXTX_REG49 0x062
+#define RXTX_REG50 0x064
+#define RXTX_REG51 0x066
+#define RXTX_REG52 0x068
+#define RXTX_REG53 0x06a
+#define RXTX_REG54 0x06c
+#define RXTX_REG55 0x06e
+#define RXTX_REG61 0x07a
+#define RXTX_REG61_ISCAN_INBERT_SET(dst, src) \
+ (((dst) & ~0x00000010) | (((u32) (src) << 4) & 0x00000010))
+#define RXTX_REG61_LOADFREQ_SHIFT_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define RXTX_REG61_EYE_COUNT_WIDTH_SEL_SET(dst, src) \
+ (((dst) & ~0x000000c0) | (((u32) (src) << 6) & 0x000000c0))
+#define RXTX_REG61_SPD_SEL_CDR_SET(dst, src) \
+ (((dst) & ~0x00003c00) | (((u32) (src) << 10) & 0x00003c00))
+#define RXTX_REG62 0x07c
+#define RXTX_REG62_PERIOD_H1_QLATCH_SET(dst, src) \
+ (((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800))
+#define RXTX_REG81 0x0a2
+#define RXTX_REG89_MU_TH7_SET(dst, src) \
+ (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define RXTX_REG89_MU_TH8_SET(dst, src) \
+ (((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0))
+#define RXTX_REG89_MU_TH9_SET(dst, src) \
+ (((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e))
+#define RXTX_REG96 0x0c0
+#define RXTX_REG96_MU_FREQ1_SET(dst, src) \
+ (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define RXTX_REG96_MU_FREQ2_SET(dst, src) \
+ (((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0))
+#define RXTX_REG96_MU_FREQ3_SET(dst, src) \
+ (((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e))
+#define RXTX_REG99 0x0c6
+#define RXTX_REG99_MU_PHASE1_SET(dst, src) \
+ (((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define RXTX_REG99_MU_PHASE2_SET(dst, src) \
+ (((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0))
+#define RXTX_REG99_MU_PHASE3_SET(dst, src) \
+ (((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e))
+#define RXTX_REG102 0x0cc
+#define RXTX_REG102_FREQLOOP_LIMIT_SET(dst, src) \
+ (((dst) & ~0x00000060) | (((u32) (src) << 5) & 0x00000060))
+#define RXTX_REG114 0x0e4
+#define RXTX_REG121 0x0f2
+#define RXTX_REG121_SUMOS_CAL_CODE_RD(src) ((0x0000003e & (u32)(src)) >> 0x1)
+#define RXTX_REG125 0x0fa
+#define RXTX_REG125_PQ_REG_SET(dst, src) \
+ (((dst) & ~0x0000fe00) | (((u32) (src) << 9) & 0x0000fe00))
+#define RXTX_REG125_SIGN_PQ_SET(dst, src) \
+ (((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100))
+#define RXTX_REG125_SIGN_PQ_2C_SET(dst, src) \
+ (((dst) & ~0x00000080) | (((u32) (src) << 7) & 0x00000080))
+#define RXTX_REG125_PHZ_MANUALCODE_SET(dst, src) \
+ (((dst) & ~0x0000007c) | (((u32) (src) << 2) & 0x0000007c))
+#define RXTX_REG125_PHZ_MANUAL_SET(dst, src) \
+ (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define RXTX_REG127 0x0fe
+#define RXTX_REG127_FORCE_SUM_CAL_START_MASK 0x00000002
+#define RXTX_REG127_FORCE_LAT_CAL_START_MASK 0x00000004
+#define RXTX_REG127_FORCE_SUM_CAL_START_SET(dst, src) \
+ (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define RXTX_REG127_FORCE_LAT_CAL_START_SET(dst, src) \
+ (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define RXTX_REG127_LATCH_MAN_CAL_ENA_SET(dst, src) \
+ (((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define RXTX_REG127_DO_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define RXTX_REG127_XO_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define RXTX_REG128 0x100
+#define RXTX_REG128_LATCH_CAL_WAIT_SEL_SET(dst, src) \
+ (((dst) & ~0x0000000c) | (((u32) (src) << 2) & 0x0000000c))
+#define RXTX_REG128_EO_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define RXTX_REG128_SO_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define RXTX_REG129 0x102
+#define RXTX_REG129_DE_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define RXTX_REG129_XE_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define RXTX_REG130 0x104
+#define RXTX_REG130_EE_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define RXTX_REG130_SE_LATCH_MANCAL_SET(dst, src) \
+ (((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define RXTX_REG145 0x122
+#define RXTX_REG145_TX_IDLE_SATA_SET(dst, src) \
+ (((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define RXTX_REG145_RXES_ENA_SET(dst, src) \
+ (((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define RXTX_REG145_RXDFE_CONFIG_SET(dst, src) \
+ (((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000))
+#define RXTX_REG145_RXVWES_LATENA_SET(dst, src) \
+ (((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define RXTX_REG147 0x126
+#define RXTX_REG148 0x128
+
+/* Clock macro type */
+enum cmu_type_t {
+ REF_CMU = 0, /* Clock macro is the internal reference clock */
+ PHY_CMU = 1, /* Clock macro is the PLL for the Serdes */
+};
+
+enum mux_type_t {
+ MUX_SELECT_ATA = 0, /* Switch the MUX to ATA */
+ MUX_SELECT_SGMMII = 0, /* Switch the MUX to SGMII */
+};
+
+enum clk_type_t {
+ CLK_EXT_DIFF = 0, /* External differential */
+ CLK_INT_DIFF = 1, /* Internal differential */
+ CLK_INT_SING = 2, /* Internal single ended */
+};
+
+enum phy_mode {
+ MODE_SATA = 0, /* List them for simple reference */
+ MODE_SGMII = 1,
+ MODE_PCIE = 2,
+ MODE_USB = 3,
+ MODE_XFI = 4,
+ MODE_MAX
+};
+
+struct xgene_sata_override_param {
+ u32 speed[MAX_LANE]; /* Index for override parameter per lane */
+ u32 txspeed[3]; /* Tx speed */
+ u32 txboostgain[MAX_LANE*3]; /* Tx freq boost and gain control */
+ u32 txeyetuning[MAX_LANE*3]; /* Tx eye tuning */
+ u32 txeyedirection[MAX_LANE*3]; /* Tx eye tuning direction */
+ u32 txamplitude[MAX_LANE*3]; /* Tx amplitude control */
+ u32 txprecursor_cn1[MAX_LANE*3]; /* Tx emphasis taps 1st pre-cursor */
+ u32 txprecursor_cn2[MAX_LANE*3]; /* Tx emphasis taps 2nd pre-cursor */
+ u32 txpostcursor_cp1[MAX_LANE*3]; /* Tx emphasis taps post-cursor */
+};
+
+struct xgene_phy_ctx {
+ struct device *dev;
+ struct phy *phy;
+ enum phy_mode mode; /* Mode of operation */
+ enum clk_type_t clk_type; /* Input clock selection */
+ void __iomem *sds_base; /* PHY CSR base addr */
+ struct clk *clk; /* Optional clock */
+
+ /* Override Serdes parameters */
+ struct xgene_sata_override_param sata_param;
+};
+
+/*
+ * For chip earlier than A3 version, enable this flag.
+ * To enable, pass boot argument phy_xgene.preA3Chip=1
+ */
+static int preA3Chip;
+MODULE_PARM_DESC(preA3Chip, "Enable pre-A3 chip support (1=enable 0=disable)");
+module_param_named(preA3Chip, preA3Chip, int, 0444);
+
+static void sds_wr(void __iomem *csr_base, u32 indirect_cmd_reg,
+ u32 indirect_data_reg, u32 addr, u32 data)
+{
+ unsigned long deadline = jiffies + HZ;
+ u32 val;
+ u32 cmd;
+
+ cmd = CFG_IND_WR_CMD_MASK | CFG_IND_CMD_DONE_MASK;
+ cmd = CFG_IND_ADDR_SET(cmd, addr);
+ writel(data, csr_base + indirect_data_reg);
+ readl(csr_base + indirect_data_reg); /* Force a barrier */
+ writel(cmd, csr_base + indirect_cmd_reg);
+ readl(csr_base + indirect_cmd_reg); /* Force a barrier */
+ do {
+ val = readl(csr_base + indirect_cmd_reg);
+ } while (!(val & CFG_IND_CMD_DONE_MASK) &&
+ time_before(jiffies, deadline));
+ if (!(val & CFG_IND_CMD_DONE_MASK))
+ pr_err("SDS WR timeout at 0x%p offset 0x%08X value 0x%08X\n",
+ csr_base + indirect_cmd_reg, addr, data);
+}
+
+static void sds_rd(void __iomem *csr_base, u32 indirect_cmd_reg,
+ u32 indirect_data_reg, u32 addr, u32 *data)
+{
+ unsigned long deadline = jiffies + HZ;
+ u32 val;
+ u32 cmd;
+
+ cmd = CFG_IND_RD_CMD_MASK | CFG_IND_CMD_DONE_MASK;
+ cmd = CFG_IND_ADDR_SET(cmd, addr);
+ writel(cmd, csr_base + indirect_cmd_reg);
+ readl(csr_base + indirect_cmd_reg); /* Force a barrier */
+ do {
+ val = readl(csr_base + indirect_cmd_reg);
+ } while (!(val & CFG_IND_CMD_DONE_MASK) &&
+ time_before(jiffies, deadline));
+ *data = readl(csr_base + indirect_data_reg);
+ if (!(val & CFG_IND_CMD_DONE_MASK))
+ pr_err("SDS WR timeout at 0x%p offset 0x%08X value 0x%08X\n",
+ csr_base + indirect_cmd_reg, addr, *data);
+}
+
+static void cmu_wr(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+ u32 reg, u32 data)
+{
+ void __iomem *sds_base = ctx->sds_base;
+ u32 val;
+
+ if (cmu_type == REF_CMU)
+ reg += SERDES_PLL_REF_INDIRECT_OFFSET;
+ else
+ reg += SERDES_PLL_INDIRECT_OFFSET;
+ sds_wr(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+ SATA_ENET_SDS_IND_WDATA_REG, reg, data);
+ sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+ SATA_ENET_SDS_IND_RDATA_REG, reg, &val);
+ pr_debug("CMU WR addr 0x%X value 0x%08X <-> 0x%08X\n", reg, data, val);
+}
+
+static void cmu_rd(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+ u32 reg, u32 *data)
+{
+ void __iomem *sds_base = ctx->sds_base;
+
+ if (cmu_type == REF_CMU)
+ reg += SERDES_PLL_REF_INDIRECT_OFFSET;
+ else
+ reg += SERDES_PLL_INDIRECT_OFFSET;
+ sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+ SATA_ENET_SDS_IND_RDATA_REG, reg, data);
+ pr_debug("CMU RD addr 0x%X value 0x%08X\n", reg, *data);
+}
+
+static void cmu_toggle1to0(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+ u32 reg, u32 bits)
+{
+ u32 val;
+
+ cmu_rd(ctx, cmu_type, reg, &val);
+ val |= bits;
+ cmu_wr(ctx, cmu_type, reg, val);
+ cmu_rd(ctx, cmu_type, reg, &val);
+ val &= ~bits;
+ cmu_wr(ctx, cmu_type, reg, val);
+}
+
+static void cmu_clrbits(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+ u32 reg, u32 bits)
+{
+ u32 val;
+
+ cmu_rd(ctx, cmu_type, reg, &val);
+ val &= ~bits;
+ cmu_wr(ctx, cmu_type, reg, val);
+}
+
+static void cmu_setbits(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+ u32 reg, u32 bits)
+{
+ u32 val;
+
+ cmu_rd(ctx, cmu_type, reg, &val);
+ val |= bits;
+ cmu_wr(ctx, cmu_type, reg, val);
+}
+
+static void serdes_wr(struct xgene_phy_ctx *ctx, int lane, u32 reg, u32 data)
+{
+ void __iomem *sds_base = ctx->sds_base;
+ u32 val;
+
+ reg += SERDES_INDIRECT_OFFSET;
+ reg += lane * SERDES_LANE_STRIDE;
+ sds_wr(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+ SATA_ENET_SDS_IND_WDATA_REG, reg, data);
+ sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+ SATA_ENET_SDS_IND_RDATA_REG, reg, &val);
+ pr_debug("SERDES WR addr 0x%X value 0x%08X <-> 0x%08X\n", reg, data,
+ val);
+}
+
+static void serdes_rd(struct xgene_phy_ctx *ctx, int lane, u32 reg, u32 *data)
+{
+ void __iomem *sds_base = ctx->sds_base;
+
+ reg += SERDES_INDIRECT_OFFSET;
+ reg += lane * SERDES_LANE_STRIDE;
+ sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+ SATA_ENET_SDS_IND_RDATA_REG, reg, data);
+ pr_debug("SERDES RD addr 0x%X value 0x%08X\n", reg, *data);
+}
+
+static void serdes_clrbits(struct xgene_phy_ctx *ctx, int lane, u32 reg,
+ u32 bits)
+{
+ u32 val;
+
+ serdes_rd(ctx, lane, reg, &val);
+ val &= ~bits;
+ serdes_wr(ctx, lane, reg, val);
+}
+
+static void serdes_setbits(struct xgene_phy_ctx *ctx, int lane, u32 reg,
+ u32 bits)
+{
+ u32 val;
+
+ serdes_rd(ctx, lane, reg, &val);
+ val |= bits;
+ serdes_wr(ctx, lane, reg, val);
+}
+
+static void xgene_phy_cfg_cmu_clk_type(struct xgene_phy_ctx *ctx,
+ enum cmu_type_t cmu_type,
+ enum clk_type_t clk_type)
+{
+ u32 val;
+
+ /* Set the reset sequence delay for TX ready assertion */
+ cmu_rd(ctx, cmu_type, CMU_REG12, &val);
+ val = CMU_REG12_STATE_DELAY9_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG12, val);
+ /* Set the programmable stage delays between various enable stages */
+ cmu_wr(ctx, cmu_type, CMU_REG13, 0x0222);
+ cmu_wr(ctx, cmu_type, CMU_REG14, 0x2225);
+
+ /* Configure clock type */
+ if (clk_type == CLK_EXT_DIFF) {
+ /* Select external clock mux */
+ cmu_rd(ctx, cmu_type, CMU_REG0, &val);
+ val = CMU_REG0_PLL_REF_SEL_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG0, val);
+ /* Select CMOS as reference clock */
+ cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+ val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG1, val);
+ dev_dbg(ctx->dev, "Set external reference clock\n");
+ } else if (clk_type == CLK_INT_DIFF) {
+ /* Select internal clock mux */
+ cmu_rd(ctx, cmu_type, CMU_REG0, &val);
+ val = CMU_REG0_PLL_REF_SEL_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG0, val);
+ /* Select CMOS as reference clock */
+ cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+ val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG1, val);
+ dev_dbg(ctx->dev, "Set internal reference clock\n");
+ } else if (clk_type == CLK_INT_SING) {
+ /*
+ * NOTE: This clock type is NOT support for controller
+ * whose internal clock shared in the PCIe controller
+ *
+ * Select internal clock mux
+ */
+ cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+ val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG1, val);
+ /* Select CML as reference clock */
+ cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+ val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG1, val);
+ dev_dbg(ctx->dev,
+ "Set internal single ended reference clock\n");
+ }
+}
+
+static void xgene_phy_sata_cfg_cmu_core(struct xgene_phy_ctx *ctx,
+ enum cmu_type_t cmu_type,
+ enum clk_type_t clk_type)
+{
+ u32 val;
+ int ref_100MHz;
+
+ if (cmu_type == REF_CMU) {
+ /* Set VCO calibration voltage threshold */
+ cmu_rd(ctx, cmu_type, CMU_REG34, &val);
+ val = CMU_REG34_VCO_CAL_VTH_LO_MAX_SET(val, 0x7);
+ val = CMU_REG34_VCO_CAL_VTH_HI_MAX_SET(val, 0xc);
+ val = CMU_REG34_VCO_CAL_VTH_LO_MIN_SET(val, 0x3);
+ val = CMU_REG34_VCO_CAL_VTH_HI_MIN_SET(val, 0x8);
+ cmu_wr(ctx, cmu_type, CMU_REG34, val);
+ }
+
+ /* Set the VCO calibration counter */
+ cmu_rd(ctx, cmu_type, CMU_REG0, &val);
+ if (cmu_type == REF_CMU || preA3Chip)
+ val = CMU_REG0_CAL_COUNT_RESOL_SET(val, 0x4);
+ else
+ val = CMU_REG0_CAL_COUNT_RESOL_SET(val, 0x7);
+ cmu_wr(ctx, cmu_type, CMU_REG0, val);
+
+ /* Configure PLL for calibration */
+ cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+ val = CMU_REG1_PLL_CP_SET(val, 0x1);
+ if (cmu_type == REF_CMU || preA3Chip)
+ val = CMU_REG1_PLL_CP_SEL_SET(val, 0x5);
+ else
+ val = CMU_REG1_PLL_CP_SEL_SET(val, 0x3);
+ if (cmu_type == REF_CMU)
+ val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x0);
+ else
+ val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG1, val);
+
+ if (cmu_type != REF_CMU)
+ cmu_clrbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK);
+
+ /* Configure the PLL for either 100MHz or 50MHz */
+ cmu_rd(ctx, cmu_type, CMU_REG2, &val);
+ if (cmu_type == REF_CMU) {
+ val = CMU_REG2_PLL_LFRES_SET(val, 0xa);
+ ref_100MHz = 1;
+ } else {
+ val = CMU_REG2_PLL_LFRES_SET(val, 0x3);
+ if (clk_type == CLK_EXT_DIFF)
+ ref_100MHz = 0;
+ else
+ ref_100MHz = 1;
+ }
+ if (ref_100MHz) {
+ val = CMU_REG2_PLL_FBDIV_SET(val, FBDIV_VAL_100M);
+ val = CMU_REG2_PLL_REFDIV_SET(val, REFDIV_VAL_100M);
+ } else {
+ val = CMU_REG2_PLL_FBDIV_SET(val, FBDIV_VAL_50M);
+ val = CMU_REG2_PLL_REFDIV_SET(val, REFDIV_VAL_50M);
+ }
+ cmu_wr(ctx, cmu_type, CMU_REG2, val);
+
+ /* Configure the VCO */
+ cmu_rd(ctx, cmu_type, CMU_REG3, &val);
+ if (cmu_type == REF_CMU) {
+ val = CMU_REG3_VCOVARSEL_SET(val, 0x3);
+ val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x10);
+ } else {
+ val = CMU_REG3_VCOVARSEL_SET(val, 0xF);
+ if (preA3Chip)
+ val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x15);
+ else
+ val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x1a);
+ val = CMU_REG3_VCO_MANMOMSEL_SET(val, 0x15);
+ }
+ cmu_wr(ctx, cmu_type, CMU_REG3, val);
+
+ /* Disable force PLL lock */
+ cmu_rd(ctx, cmu_type, CMU_REG26, &val);
+ val = CMU_REG26_FORCE_PLL_LOCK_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG26, val);
+
+ /* Setup PLL loop filter */
+ cmu_rd(ctx, cmu_type, CMU_REG5, &val);
+ val = CMU_REG5_PLL_LFSMCAP_SET(val, 0x3);
+ val = CMU_REG5_PLL_LFCAP_SET(val, 0x3);
+ if (cmu_type == REF_CMU || !preA3Chip)
+ val = CMU_REG5_PLL_LOCK_RESOLUTION_SET(val, 0x7);
+ else
+ val = CMU_REG5_PLL_LOCK_RESOLUTION_SET(val, 0x4);
+ cmu_wr(ctx, cmu_type, CMU_REG5, val);
+
+ /* Enable or disable manual calibration */
+ cmu_rd(ctx, cmu_type, CMU_REG6, &val);
+ val = CMU_REG6_PLL_VREGTRIM_SET(val, preA3Chip ? 0x0 : 0x2);
+ val = CMU_REG6_MAN_PVT_CAL_SET(val, preA3Chip ? 0x1 : 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG6, val);
+
+ /* Configure lane for 20-bits */
+ if (cmu_type == PHY_CMU) {
+ cmu_rd(ctx, cmu_type, CMU_REG9, &val);
+ val = CMU_REG9_TX_WORD_MODE_CH1_SET(val,
+ CMU_REG9_WORD_LEN_20BIT);
+ val = CMU_REG9_TX_WORD_MODE_CH0_SET(val,
+ CMU_REG9_WORD_LEN_20BIT);
+ val = CMU_REG9_PLL_POST_DIVBY2_SET(val, 0x1);
+ if (!preA3Chip) {
+ val = CMU_REG9_VBG_BYPASSB_SET(val, 0x0);
+ val = CMU_REG9_IGEN_BYPASS_SET(val , 0x0);
+ }
+ cmu_wr(ctx, cmu_type, CMU_REG9, val);
+
+ if (!preA3Chip) {
+ cmu_rd(ctx, cmu_type, CMU_REG10, &val);
+ val = CMU_REG10_VREG_REFSEL_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG10, val);
+ }
+ }
+
+ cmu_rd(ctx, cmu_type, CMU_REG16, &val);
+ val = CMU_REG16_CALIBRATION_DONE_OVERRIDE_SET(val, 0x1);
+ val = CMU_REG16_BYPASS_PLL_LOCK_SET(val, 0x1);
+ if (cmu_type == REF_CMU || preA3Chip)
+ val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x4);
+ else
+ val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x7);
+ cmu_wr(ctx, cmu_type, CMU_REG16, val);
+
+ /* Configure for SATA */
+ cmu_rd(ctx, cmu_type, CMU_REG30, &val);
+ val = CMU_REG30_PCIE_MODE_SET(val, 0x0);
+ val = CMU_REG30_LOCK_COUNT_SET(val, 0x3);
+ cmu_wr(ctx, cmu_type, CMU_REG30, val);
+
+ /* Disable state machine bypass */
+ cmu_wr(ctx, cmu_type, CMU_REG31, 0xF);
+
+ cmu_rd(ctx, cmu_type, CMU_REG32, &val);
+ val = CMU_REG32_PVT_CAL_WAIT_SEL_SET(val, 0x3);
+ if (cmu_type == REF_CMU || preA3Chip)
+ val = CMU_REG32_IREF_ADJ_SET(val, 0x3);
+ else
+ val = CMU_REG32_IREF_ADJ_SET(val, 0x1);
+ cmu_wr(ctx, cmu_type, CMU_REG32, val);
+
+ /* Set VCO calibration threshold */
+ if (cmu_type != REF_CMU && preA3Chip)
+ cmu_wr(ctx, cmu_type, CMU_REG34, 0x8d27);
+ else
+ cmu_wr(ctx, cmu_type, CMU_REG34, 0x873c);
+
+ /* Set CTLE Override and override waiting from state machine */
+ cmu_wr(ctx, cmu_type, CMU_REG37, 0xF00F);
+}
+
+static void xgene_phy_ssc_enable(struct xgene_phy_ctx *ctx,
+ enum cmu_type_t cmu_type)
+{
+ u32 val;
+
+ /* Set SSC modulation value */
+ cmu_rd(ctx, cmu_type, CMU_REG35, &val);
+ val = CMU_REG35_PLL_SSC_MOD_SET(val, 98);
+ cmu_wr(ctx, cmu_type, CMU_REG35, val);
+
+ /* Enable SSC, set vertical step and DSM value */
+ cmu_rd(ctx, cmu_type, CMU_REG36, &val);
+ val = CMU_REG36_PLL_SSC_VSTEP_SET(val, 30);
+ val = CMU_REG36_PLL_SSC_EN_SET(val, 1);
+ val = CMU_REG36_PLL_SSC_DSMSEL_SET(val, 1);
+ cmu_wr(ctx, cmu_type, CMU_REG36, val);
+
+ /* Reset the PLL */
+ cmu_clrbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK);
+ cmu_setbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK);
+
+ /* Force VCO calibration to restart */
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG32,
+ CMU_REG32_FORCE_VCOCAL_START_MASK);
+}
+
+static void xgene_phy_sata_cfg_lanes(struct xgene_phy_ctx *ctx)
+{
+ u32 val;
+ u32 reg;
+ int i;
+ int lane;
+
+ for (lane = 0; lane < MAX_LANE; lane++) {
+ serdes_wr(ctx, lane, RXTX_REG147, 0x6);
+
+ /* Set boost control for quarter, half, and full rate */
+ serdes_rd(ctx, lane, RXTX_REG0, &val);
+ val = RXTX_REG0_CTLE_EQ_HR_SET(val, 0x10);
+ val = RXTX_REG0_CTLE_EQ_QR_SET(val, 0x10);
+ val = RXTX_REG0_CTLE_EQ_FR_SET(val, 0x10);
+ serdes_wr(ctx, lane, RXTX_REG0, val);
+
+ /* Set boost control value */
+ serdes_rd(ctx, lane, RXTX_REG1, &val);
+ val = RXTX_REG1_RXACVCM_SET(val, 0x7);
+ val = RXTX_REG1_CTLE_EQ_SET(val,
+ ctx->sata_param.txboostgain[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ serdes_wr(ctx, lane, RXTX_REG1, val);
+
+ /* Latch VTT value based on the termination to ground and
+ enable TX FIFO */
+ serdes_rd(ctx, lane, RXTX_REG2, &val);
+ val = RXTX_REG2_VTT_ENA_SET(val, 0x1);
+ val = RXTX_REG2_VTT_SEL_SET(val, 0x1);
+ val = RXTX_REG2_TX_FIFO_ENA_SET(val, 0x1);
+ serdes_wr(ctx, lane, RXTX_REG2, val);
+
+ /* Configure Tx for 20-bits */
+ serdes_rd(ctx, lane, RXTX_REG4, &val);
+ val = RXTX_REG4_TX_WORD_MODE_SET(val, CMU_REG9_WORD_LEN_20BIT);
+ serdes_wr(ctx, lane, RXTX_REG4, val);
+
+ if (!preA3Chip) {
+ serdes_rd(ctx, lane, RXTX_REG1, &val);
+ val = RXTX_REG1_RXVREG1_SET(val, 0x2);
+ val = RXTX_REG1_RXIREF_ADJ_SET(val, 0x2);
+ serdes_wr(ctx, lane, RXTX_REG1, val);
+ }
+
+ /* Set pre-emphasis first 1 and 2, and post-emphasis values */
+ serdes_rd(ctx, lane, RXTX_REG5, &val);
+ val = RXTX_REG5_TX_CN1_SET(val,
+ ctx->sata_param.txprecursor_cn1[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ val = RXTX_REG5_TX_CP1_SET(val,
+ ctx->sata_param.txpostcursor_cp1[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ val = RXTX_REG5_TX_CN2_SET(val,
+ ctx->sata_param.txprecursor_cn2[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ serdes_wr(ctx, lane, RXTX_REG5, val);
+
+ /* Set TX amplitude value */
+ serdes_rd(ctx, lane, RXTX_REG6, &val);
+ val = RXTX_REG6_TXAMP_CNTL_SET(val,
+ ctx->sata_param.txamplitude[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ val = RXTX_REG6_TXAMP_ENA_SET(val, 0x1);
+ val = RXTX_REG6_TX_IDLE_SET(val, 0x0);
+ val = RXTX_REG6_RX_BIST_RESYNC_SET(val, 0x0);
+ val = RXTX_REG6_RX_BIST_ERRCNT_RD_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG6, val);
+
+ /* Configure Rx for 20-bits */
+ serdes_rd(ctx, lane, RXTX_REG7, &val);
+ val = RXTX_REG7_BIST_ENA_RX_SET(val, 0x0);
+ val = RXTX_REG7_RX_WORD_MODE_SET(val, CMU_REG9_WORD_LEN_20BIT);
+ serdes_wr(ctx, lane, RXTX_REG7, val);
+
+ /* Set CDR and LOS values and enable Rx SSC */
+ serdes_rd(ctx, lane, RXTX_REG8, &val);
+ val = RXTX_REG8_CDR_LOOP_ENA_SET(val, 0x1);
+ val = RXTX_REG8_CDR_BYPASS_RXLOS_SET(val, 0x0);
+ val = RXTX_REG8_SSC_ENABLE_SET(val, 0x1);
+ val = RXTX_REG8_SD_DISABLE_SET(val, 0x0);
+ val = RXTX_REG8_SD_VREF_SET(val, 0x4);
+ serdes_wr(ctx, lane, RXTX_REG8, val);
+
+ /* Set phase adjust upper/lower limits */
+ serdes_rd(ctx, lane, RXTX_REG11, &val);
+ val = RXTX_REG11_PHASE_ADJUST_LIMIT_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG11, val);
+
+ /* Enable Latch Off; disable SUMOS and Tx termination */
+ serdes_rd(ctx, lane, RXTX_REG12, &val);
+ val = RXTX_REG12_LATCH_OFF_ENA_SET(val, 0x1);
+ val = RXTX_REG12_SUMOS_ENABLE_SET(val, 0x0);
+ val = RXTX_REG12_RX_DET_TERM_ENABLE_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG12, val);
+
+ /* Set period error latch to 512T and enable BWL */
+ serdes_rd(ctx, lane, RXTX_REG26, &val);
+ val = RXTX_REG26_PERIOD_ERROR_LATCH_SET(val, 0x0);
+ val = RXTX_REG26_BLWC_ENA_SET(val, 0x1);
+ serdes_wr(ctx, lane, RXTX_REG26, val);
+
+ serdes_wr(ctx, lane, RXTX_REG28, 0x0);
+
+ /* Set DFE loop preset value */
+ serdes_wr(ctx, lane, RXTX_REG31, 0x0);
+
+ /* Set Eye Monitor counter width to 12-bit */
+ serdes_rd(ctx, lane, RXTX_REG61, &val);
+ val = RXTX_REG61_ISCAN_INBERT_SET(val, 0x1);
+ val = RXTX_REG61_LOADFREQ_SHIFT_SET(val, 0x0);
+ val = RXTX_REG61_EYE_COUNT_WIDTH_SEL_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG61, val);
+
+ serdes_rd(ctx, lane, RXTX_REG62, &val);
+ val = RXTX_REG62_PERIOD_H1_QLATCH_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG62, val);
+
+ /* Set BW select tap X for DFE loop */
+ for (i = 0; i < 9; i++) {
+ reg = RXTX_REG81 + i * 2;
+ serdes_rd(ctx, lane, reg, &val);
+ val = RXTX_REG89_MU_TH7_SET(val, 0xe);
+ val = RXTX_REG89_MU_TH8_SET(val, 0xe);
+ val = RXTX_REG89_MU_TH9_SET(val, 0xe);
+ serdes_wr(ctx, lane, reg, val);
+ }
+
+ /* Set BW select tap X for frequency adjust loop */
+ for (i = 0; i < 3; i++) {
+ reg = RXTX_REG96 + i * 2;
+ serdes_rd(ctx, lane, reg, &val);
+ val = RXTX_REG96_MU_FREQ1_SET(val, 0x10);
+ val = RXTX_REG96_MU_FREQ2_SET(val, 0x10);
+ val = RXTX_REG96_MU_FREQ3_SET(val, 0x10);
+ serdes_wr(ctx, lane, reg, val);
+ }
+
+ /* Set BW select tap X for phase adjust loop */
+ for (i = 0; i < 3; i++) {
+ reg = RXTX_REG99 + i * 2;
+ serdes_rd(ctx, lane, reg, &val);
+ val = RXTX_REG99_MU_PHASE1_SET(val, 0x7);
+ val = RXTX_REG99_MU_PHASE2_SET(val, 0x7);
+ val = RXTX_REG99_MU_PHASE3_SET(val, 0x7);
+ serdes_wr(ctx, lane, reg, val);
+ }
+
+ serdes_rd(ctx, lane, RXTX_REG102, &val);
+ val = RXTX_REG102_FREQLOOP_LIMIT_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG102, val);
+
+ serdes_wr(ctx, lane, RXTX_REG114, 0xffe0);
+
+ serdes_rd(ctx, lane, RXTX_REG125, &val);
+ val = RXTX_REG125_SIGN_PQ_SET(val,
+ ctx->sata_param.txeyedirection[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ val = RXTX_REG125_PQ_REG_SET(val,
+ ctx->sata_param.txeyetuning[lane * 3 +
+ ctx->sata_param.speed[lane]]);
+ val = RXTX_REG125_PHZ_MANUAL_SET(val, 0x1);
+ serdes_wr(ctx, lane, RXTX_REG125, val);
+
+ serdes_rd(ctx, lane, RXTX_REG127, &val);
+ val = RXTX_REG127_LATCH_MAN_CAL_ENA_SET(val, 0x0);
+ serdes_wr(ctx, lane, RXTX_REG127, val);
+
+ serdes_rd(ctx, lane, RXTX_REG128, &val);
+ val = RXTX_REG128_LATCH_CAL_WAIT_SEL_SET(val, 0x3);
+ serdes_wr(ctx, lane, RXTX_REG128, val);
+
+ serdes_rd(ctx, lane, RXTX_REG145, &val);
+ val = RXTX_REG145_RXDFE_CONFIG_SET(val, 0x3);
+ val = RXTX_REG145_TX_IDLE_SATA_SET(val, 0x0);
+ if (preA3Chip) {
+ val = RXTX_REG145_RXES_ENA_SET(val, 0x1);
+ val = RXTX_REG145_RXVWES_LATENA_SET(val, 0x1);
+ } else {
+ val = RXTX_REG145_RXES_ENA_SET(val, 0x0);
+ val = RXTX_REG145_RXVWES_LATENA_SET(val, 0x0);
+ }
+ serdes_wr(ctx, lane, RXTX_REG145, val);
+
+ /*
+ * Set Rx LOS filter clock rate, sample rate, and threshold
+ * windows
+ */
+ for (i = 0; i < 4; i++) {
+ reg = RXTX_REG148 + i * 2;
+ serdes_wr(ctx, lane, reg, 0xFFFF);
+ }
+ }
+}
+
+static int xgene_phy_cal_rdy_chk(struct xgene_phy_ctx *ctx,
+ enum cmu_type_t cmu_type,
+ enum clk_type_t clk_type)
+{
+ void __iomem *csr_serdes = ctx->sds_base;
+ int loop;
+ u32 val;
+
+ /* Release PHY main reset */
+ writel(0xdf, csr_serdes + SATA_ENET_SDS_RST_CTL);
+ readl(csr_serdes + SATA_ENET_SDS_RST_CTL); /* Force a barrier */
+
+ if (cmu_type != REF_CMU) {
+ cmu_setbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK);
+ /*
+ * As per PHY design spec, the PLL reset requires a minimum
+ * of 800us.
+ */
+ usleep_range(800, 1000);
+
+ cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+ val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG1, val);
+ /*
+ * As per PHY design spec, the PLL auto calibration requires
+ * a minimum of 800us.
+ */
+ usleep_range(800, 1000);
+
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG32,
+ CMU_REG32_FORCE_VCOCAL_START_MASK);
+ /*
+ * As per PHY design spec, the PLL requires a minimum of
+ * 800us to settle.
+ */
+ usleep_range(800, 1000);
+ }
+
+ if (!preA3Chip)
+ goto skip_manual_cal;
+
+ /*
+ * Configure the termination resister calibration
+ * The serial receive pins, RXP/RXN, have TERMination resistor
+ * that is required to be calibrated.
+ */
+ cmu_rd(ctx, cmu_type, CMU_REG17, &val);
+ val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x12);
+ val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG17, val);
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG17,
+ CMU_REG17_PVT_TERM_MAN_ENA_MASK);
+ /*
+ * The serial transmit pins, TXP/TXN, have Pull-UP and Pull-DOWN
+ * resistors that are required to the calibrated.
+ * Configure the pull DOWN calibration
+ */
+ cmu_rd(ctx, cmu_type, CMU_REG17, &val);
+ val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x29);
+ val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG17, val);
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG16,
+ CMU_REG16_PVT_DN_MAN_ENA_MASK);
+ /* Configure the pull UP calibration */
+ cmu_rd(ctx, cmu_type, CMU_REG17, &val);
+ val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x28);
+ val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+ cmu_wr(ctx, cmu_type, CMU_REG17, val);
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG16,
+ CMU_REG16_PVT_UP_MAN_ENA_MASK);
+
+skip_manual_cal:
+ /* Poll the PLL calibration completion status for at least 1 ms */
+ loop = 100;
+ do {
+ cmu_rd(ctx, cmu_type, CMU_REG7, &val);
+ if (CMU_REG7_PLL_CALIB_DONE_RD(val))
+ break;
+ /*
+ * As per PHY design spec, PLL calibration status requires
+ * a minimum of 10us to be updated.
+ */
+ usleep_range(10, 100);
+ } while (--loop > 0);
+
+ cmu_rd(ctx, cmu_type, CMU_REG7, &val);
+ dev_dbg(ctx->dev, "PLL calibration %s\n",
+ CMU_REG7_PLL_CALIB_DONE_RD(val) ? "done" : "failed");
+ if (CMU_REG7_VCO_CAL_FAIL_RD(val)) {
+ dev_err(ctx->dev,
+ "PLL calibration failed due to VCO failure\n");
+ return -1;
+ }
+ dev_dbg(ctx->dev, "PLL calibration successful\n");
+
+ cmu_rd(ctx, cmu_type, CMU_REG15, &val);
+ dev_dbg(ctx->dev, "PHY Tx is %sready\n", val & 0x300 ? "" : "not ");
+ return 0;
+}
+
+static void xgene_phy_pdwn_force_vco(struct xgene_phy_ctx *ctx,
+ enum cmu_type_t cmu_type,
+ enum clk_type_t clk_type)
+{
+ u32 val;
+
+ dev_dbg(ctx->dev, "Reset VCO and re-start again\n");
+ if (cmu_type == PHY_CMU) {
+ cmu_rd(ctx, cmu_type, CMU_REG16, &val);
+ val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x7);
+ cmu_wr(ctx, cmu_type, CMU_REG16, val);
+ }
+
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG0, CMU_REG0_PDOWN_MASK);
+ cmu_toggle1to0(ctx, cmu_type, CMU_REG32,
+ CMU_REG32_FORCE_VCOCAL_START_MASK);
+}
+
+static int xgene_phy_hw_init_sata(struct xgene_phy_ctx *ctx,
+ enum clk_type_t clk_type, int ssc_enable)
+{
+ void __iomem *sds_base = ctx->sds_base;
+ u32 val;
+ int i;
+
+ /* Configure the PHY for operation */
+ dev_dbg(ctx->dev, "Reset PHY\n");
+ /* Place PHY into reset */
+ writel(0x0, sds_base + SATA_ENET_SDS_RST_CTL);
+ val = readl(sds_base + SATA_ENET_SDS_RST_CTL); /* Force a barrier */
+ /* Release PHY lane from reset (active high) */
+ writel(0x20, sds_base + SATA_ENET_SDS_RST_CTL);
+ readl(sds_base + SATA_ENET_SDS_RST_CTL); /* Force a barrier */
+ /* Release all PHY module out of reset except PHY main reset */
+ writel(0xde, sds_base + SATA_ENET_SDS_RST_CTL);
+ readl(sds_base + SATA_ENET_SDS_RST_CTL); /* Force a barrier */
+
+ /* Set the operation speed */
+ val = readl(sds_base + SATA_ENET_SDS_CTL1);
+ val = CFG_I_SPD_SEL_CDR_OVR1_SET(val,
+ ctx->sata_param.txspeed[ctx->sata_param.speed[0]]);
+ writel(val, sds_base + SATA_ENET_SDS_CTL1);
+
+ dev_dbg(ctx->dev, "Set the customer pin mode to SATA\n");
+ val = readl(sds_base + SATA_ENET_SDS_CTL0);
+ val = REGSPEC_CFG_I_CUSTOMER_PIN_MODE0_SET(val, 0x4421);
+ writel(val, sds_base + SATA_ENET_SDS_CTL0);
+
+ /* Configure the clock macro unit (CMU) clock type */
+ xgene_phy_cfg_cmu_clk_type(ctx, PHY_CMU, clk_type);
+
+ /* Configure the clock macro */
+ xgene_phy_sata_cfg_cmu_core(ctx, PHY_CMU, clk_type);
+
+ /* Enable SSC if enabled */
+ if (ssc_enable)
+ xgene_phy_ssc_enable(ctx, PHY_CMU);
+
+ /* Configure PHY lanes */
+ xgene_phy_sata_cfg_lanes(ctx);
+
+ /* Set Rx/Tx 20-bit */
+ val = readl(sds_base + SATA_ENET_SDS_PCS_CTL0);
+ val = REGSPEC_CFG_I_RX_WORDMODE0_SET(val, 0x3);
+ val = REGSPEC_CFG_I_TX_WORDMODE0_SET(val, 0x3);
+ writel(val, sds_base + SATA_ENET_SDS_PCS_CTL0);
+
+ /* Start PLL calibration and try for three times */
+ i = 10;
+ do {
+ if (!xgene_phy_cal_rdy_chk(ctx, PHY_CMU, clk_type))
+ break;
+ /* If failed, toggle the VCO power signal and start again */
+ xgene_phy_pdwn_force_vco(ctx, PHY_CMU, clk_type);
+ } while (--i > 0);
+ /* Even on failure, allow to continue any way */
+ if (i <= 0)
+ dev_err(ctx->dev, "PLL calibration failed\n");
+
+ return 0;
+}
+
+static int xgene_phy_hw_initialize(struct xgene_phy_ctx *ctx,
+ enum clk_type_t clk_type,
+ int ssc_enable)
+{
+ int rc;
+
+ dev_dbg(ctx->dev, "PHY init clk type %d\n", clk_type);
+
+ if (ctx->mode == MODE_SATA) {
+ rc = xgene_phy_hw_init_sata(ctx, clk_type, ssc_enable);
+ if (rc)
+ return rc;
+ } else {
+ dev_err(ctx->dev, "Un-supported customer pin mode %d\n",
+ ctx->mode);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/*
+ * Receiver Offset Calibration:
+ *
+ * Calibrate the receiver signal path offset in two steps - summar and
+ * latch calibrations
+ */
+static void xgene_phy_force_lat_summer_cal(struct xgene_phy_ctx *ctx, int lane)
+{
+ int i;
+ struct {
+ u32 reg;
+ u32 val;
+ } serdes_reg[] = {
+ {RXTX_REG38, 0x0},
+ {RXTX_REG39, 0xff00},
+ {RXTX_REG40, 0xffff},
+ {RXTX_REG41, 0xffff},
+ {RXTX_REG42, 0xffff},
+ {RXTX_REG43, 0xffff},
+ {RXTX_REG44, 0xffff},
+ {RXTX_REG45, 0xffff},
+ {RXTX_REG46, 0xffff},
+ {RXTX_REG47, 0xfffc},
+ {RXTX_REG48, 0x0},
+ {RXTX_REG49, 0x0},
+ {RXTX_REG50, 0x0},
+ {RXTX_REG51, 0x0},
+ {RXTX_REG52, 0x0},
+ {RXTX_REG53, 0x0},
+ {RXTX_REG54, 0x0},
+ {RXTX_REG55, 0x0},
+ };
+
+ /* Start SUMMER calibration */
+ serdes_setbits(ctx, lane, RXTX_REG127,
+ RXTX_REG127_FORCE_SUM_CAL_START_MASK);
+ /*
+ * As per PHY design spec, the Summer calibration requires a minimum
+ * of 100us to complete.
+ */
+ usleep_range(100, 500);
+ serdes_clrbits(ctx, lane, RXTX_REG127,
+ RXTX_REG127_FORCE_SUM_CAL_START_MASK);
+ /*
+ * As per PHY design spec, the auto calibration requires a minimum
+ * of 100us to complete.
+ */
+ usleep_range(100, 500);
+
+ /* Start latch calibration */
+ serdes_setbits(ctx, lane, RXTX_REG127,
+ RXTX_REG127_FORCE_LAT_CAL_START_MASK);
+ /*
+ * As per PHY design spec, the latch calibration requires a minimum
+ * of 100us to complete.
+ */
+ usleep_range(100, 500);
+ serdes_clrbits(ctx, lane, RXTX_REG127,
+ RXTX_REG127_FORCE_LAT_CAL_START_MASK);
+
+ /* Configure the PHY lane for calibration */
+ serdes_wr(ctx, lane, RXTX_REG28, 0x7);
+ serdes_wr(ctx, lane, RXTX_REG31, 0x7e00);
+ serdes_clrbits(ctx, lane, RXTX_REG4,
+ RXTX_REG4_TX_LOOPBACK_BUF_EN_MASK);
+ serdes_clrbits(ctx, lane, RXTX_REG7,
+ RXTX_REG7_LOOP_BACK_ENA_CTLE_MASK);
+ for (i = 0; i < ARRAY_SIZE(serdes_reg); i++)
+ serdes_wr(ctx, lane, serdes_reg[i].reg,
+ serdes_reg[i].val);
+}
+
+static void xgene_phy_reset_rxd(struct xgene_phy_ctx *ctx, int lane)
+{
+ /* Reset digital Rx */
+ serdes_clrbits(ctx, lane, RXTX_REG7, RXTX_REG7_RESETB_RXD_MASK);
+ /* As per PHY design spec, the reset requires a minimum of 100us. */
+ usleep_range(100, 150);
+ serdes_setbits(ctx, lane, RXTX_REG7, RXTX_REG7_RESETB_RXD_MASK);
+}
+
+static int xgene_phy_get_avg(int accum, int samples)
+{
+ return (accum + (samples / 2)) / samples;
+}
+
+static void xgene_phy_gen_avg_val(struct xgene_phy_ctx *ctx, int lane)
+{
+ int max_loop = 10;
+ int avg_loop = 0;
+ int lat_do = 0, lat_xo = 0, lat_eo = 0, lat_so = 0;
+ int lat_de = 0, lat_xe = 0, lat_ee = 0, lat_se = 0;
+ int sum_cal = 0;
+ int lat_do_itr, lat_xo_itr, lat_eo_itr, lat_so_itr;
+ int lat_de_itr, lat_xe_itr, lat_ee_itr, lat_se_itr;
+ int sum_cal_itr;
+ int fail_even;
+ int fail_odd;
+ u32 val;
+
+ dev_dbg(ctx->dev, "Generating avg calibration value for lane %d\n",
+ lane);
+
+ /* Enable RX Hi-Z termination */
+ serdes_setbits(ctx, lane, RXTX_REG12,
+ RXTX_REG12_RX_DET_TERM_ENABLE_MASK);
+ /* Turn off DFE */
+ serdes_wr(ctx, lane, RXTX_REG28, 0x0000);
+ /* DFE Presets to zero */
+ serdes_wr(ctx, lane, RXTX_REG31, 0x0000);
+
+ /*
+ * Receiver Offset Calibration:
+ * Calibrate the receiver signal path offset in two steps - summar
+ * and latch calibration.
+ * Runs the "Receiver Offset Calibration multiple times to determine
+ * the average value to use.
+ */
+ while (avg_loop < max_loop) {
+ /* Start the calibration */
+ xgene_phy_force_lat_summer_cal(ctx, lane);
+
+ serdes_rd(ctx, lane, RXTX_REG21, &val);
+ lat_do_itr = RXTX_REG21_DO_LATCH_CALOUT_RD(val);
+ lat_xo_itr = RXTX_REG21_XO_LATCH_CALOUT_RD(val);
+ fail_odd = RXTX_REG21_LATCH_CAL_FAIL_ODD_RD(val);
+
+ serdes_rd(ctx, lane, RXTX_REG22, &val);
+ lat_eo_itr = RXTX_REG22_EO_LATCH_CALOUT_RD(val);
+ lat_so_itr = RXTX_REG22_SO_LATCH_CALOUT_RD(val);
+ fail_even = RXTX_REG22_LATCH_CAL_FAIL_EVEN_RD(val);
+
+ serdes_rd(ctx, lane, RXTX_REG23, &val);
+ lat_de_itr = RXTX_REG23_DE_LATCH_CALOUT_RD(val);
+ lat_xe_itr = RXTX_REG23_XE_LATCH_CALOUT_RD(val);
+
+ serdes_rd(ctx, lane, RXTX_REG24, &val);
+ lat_ee_itr = RXTX_REG24_EE_LATCH_CALOUT_RD(val);
+ lat_se_itr = RXTX_REG24_SE_LATCH_CALOUT_RD(val);
+
+ serdes_rd(ctx, lane, RXTX_REG121, &val);
+ sum_cal_itr = RXTX_REG121_SUMOS_CAL_CODE_RD(val);
+
+ /* Check for failure. If passed, sum them for averaging */
+ if ((fail_even == 0 || fail_even == 1) &&
+ (fail_odd == 0 || fail_odd == 1)) {
+ lat_do += lat_do_itr;
+ lat_xo += lat_xo_itr;
+ lat_eo += lat_eo_itr;
+ lat_so += lat_so_itr;
+ lat_de += lat_de_itr;
+ lat_xe += lat_xe_itr;
+ lat_ee += lat_ee_itr;
+ lat_se += lat_se_itr;
+ sum_cal += sum_cal_itr;
+
+ dev_dbg(ctx->dev, "Iteration %d:\n", avg_loop);
+ dev_dbg(ctx->dev, "DO 0x%x XO 0x%x EO 0x%x SO 0x%x\n",
+ lat_do_itr, lat_xo_itr, lat_eo_itr,
+ lat_so_itr);
+ dev_dbg(ctx->dev, "DE 0x%x XE 0x%x EE 0x%x SE 0x%x\n",
+ lat_de_itr, lat_xe_itr, lat_ee_itr,
+ lat_se_itr);
+ dev_dbg(ctx->dev, "SUM 0x%x\n", sum_cal_itr);
+ ++avg_loop;
+ } else {
+ dev_err(ctx->dev,
+ "Receiver calibration failed at %d loop\n",
+ avg_loop);
+ }
+ xgene_phy_reset_rxd(ctx, lane);
+ }
+
+ /* Update latch manual calibration with average value */
+ serdes_rd(ctx, lane, RXTX_REG127, &val);
+ val = RXTX_REG127_DO_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_do, max_loop));
+ val = RXTX_REG127_XO_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_xo, max_loop));
+ serdes_wr(ctx, lane, RXTX_REG127, val);
+
+ serdes_rd(ctx, lane, RXTX_REG128, &val);
+ val = RXTX_REG128_EO_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_eo, max_loop));
+ val = RXTX_REG128_SO_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_so, max_loop));
+ serdes_wr(ctx, lane, RXTX_REG128, val);
+
+ serdes_rd(ctx, lane, RXTX_REG129, &val);
+ val = RXTX_REG129_DE_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_de, max_loop));
+ val = RXTX_REG129_XE_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_xe, max_loop));
+ serdes_wr(ctx, lane, RXTX_REG129, val);
+
+ serdes_rd(ctx, lane, RXTX_REG130, &val);
+ val = RXTX_REG130_EE_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_ee, max_loop));
+ val = RXTX_REG130_SE_LATCH_MANCAL_SET(val,
+ xgene_phy_get_avg(lat_se, max_loop));
+ serdes_wr(ctx, lane, RXTX_REG130, val);
+
+ /* Update SUMMER calibration with average value */
+ serdes_rd(ctx, lane, RXTX_REG14, &val);
+ val = RXTX_REG14_CLTE_LATCAL_MAN_PROG_SET(val,
+ xgene_phy_get_avg(sum_cal, max_loop));
+ serdes_wr(ctx, lane, RXTX_REG14, val);
+
+ dev_dbg(ctx->dev, "Average Value:\n");
+ dev_dbg(ctx->dev, "DO 0x%x XO 0x%x EO 0x%x SO 0x%x\n",
+ xgene_phy_get_avg(lat_do, max_loop),
+ xgene_phy_get_avg(lat_xo, max_loop),
+ xgene_phy_get_avg(lat_eo, max_loop),
+ xgene_phy_get_avg(lat_so, max_loop));
+ dev_dbg(ctx->dev, "DE 0x%x XE 0x%x EE 0x%x SE 0x%x\n",
+ xgene_phy_get_avg(lat_de, max_loop),
+ xgene_phy_get_avg(lat_xe, max_loop),
+ xgene_phy_get_avg(lat_ee, max_loop),
+ xgene_phy_get_avg(lat_se, max_loop));
+ dev_dbg(ctx->dev, "SUM 0x%x\n",
+ xgene_phy_get_avg(sum_cal, max_loop));
+
+ serdes_rd(ctx, lane, RXTX_REG14, &val);
+ val = RXTX_REG14_CTLE_LATCAL_MAN_ENA_SET(val, 0x1);
+ serdes_wr(ctx, lane, RXTX_REG14, val);
+ dev_dbg(ctx->dev, "Enable Manual Summer calibration\n");
+
+ serdes_rd(ctx, lane, RXTX_REG127, &val);
+ val = RXTX_REG127_LATCH_MAN_CAL_ENA_SET(val, 0x1);
+ dev_dbg(ctx->dev, "Enable Manual Latch calibration\n");
+ serdes_wr(ctx, lane, RXTX_REG127, val);
+
+ /* Disable RX Hi-Z termination */
+ serdes_rd(ctx, lane, RXTX_REG12, &val);
+ val = RXTX_REG12_RX_DET_TERM_ENABLE_SET(val, 0);
+ serdes_wr(ctx, lane, RXTX_REG12, val);
+ /* Turn on DFE */
+ serdes_wr(ctx, lane, RXTX_REG28, 0x0007);
+ /* Set DFE preset */
+ serdes_wr(ctx, lane, RXTX_REG31, 0x7e00);
+}
+
+static int xgene_phy_hw_init(struct phy *phy)
+{
+ struct xgene_phy_ctx *ctx = phy_get_drvdata(phy);
+ int rc;
+ int i;
+
+ rc = xgene_phy_hw_initialize(ctx, CLK_EXT_DIFF, SSC_DISABLE);
+ if (rc) {
+ dev_err(ctx->dev, "PHY initialize failed %d\n", rc);
+ return rc;
+ }
+
+ /* Setup clock properly after PHY configuration */
+ if (!IS_ERR(ctx->clk)) {
+ /* HW requires an toggle of the clock */
+ clk_prepare_enable(ctx->clk);
+ clk_disable_unprepare(ctx->clk);
+ clk_prepare_enable(ctx->clk);
+ }
+
+ /* Compute average value */
+ for (i = 0; i < MAX_LANE; i++)
+ xgene_phy_gen_avg_val(ctx, i);
+
+ dev_dbg(ctx->dev, "PHY initialized\n");
+ return 0;
+}
+
+static const struct phy_ops xgene_phy_ops = {
+ .init = xgene_phy_hw_init,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *xgene_phy_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct xgene_phy_ctx *ctx = dev_get_drvdata(dev);
+
+ if (args->args_count <= 0)
+ return ERR_PTR(-EINVAL);
+ if (args->args[0] < MODE_SATA || args->args[0] >= MODE_MAX)
+ return ERR_PTR(-EINVAL);
+
+ ctx->mode = args->args[0];
+ return ctx->phy;
+}
+
+static void xgene_phy_get_param(struct platform_device *pdev,
+ const char *name, u32 *buffer,
+ int count, u32 *default_val,
+ u32 conv_factor)
+{
+ int i;
+
+ if (!of_property_read_u32_array(pdev->dev.of_node, name, buffer,
+ count)) {
+ for (i = 0; i < count; i++)
+ buffer[i] /= conv_factor;
+ return;
+ }
+ /* Does not exist, load default */
+ for (i = 0; i < count; i++)
+ buffer[i] = default_val[i % 3];
+}
+
+static int xgene_phy_probe(struct platform_device *pdev)
+{
+ struct phy_provider *phy_provider;
+ struct xgene_phy_ctx *ctx;
+ struct resource *res;
+ int rc = 0;
+ u32 default_spd[] = DEFAULT_SATA_SPD_SEL;
+ u32 default_txboost_gain[] = DEFAULT_SATA_TXBOOST_GAIN;
+ u32 default_txeye_direction[] = DEFAULT_SATA_TXEYEDIRECTION;
+ u32 default_txeye_tuning[] = DEFAULT_SATA_TXEYETUNING;
+ u32 default_txamp[] = DEFAULT_SATA_TXAMP;
+ u32 default_txcn1[] = DEFAULT_SATA_TXCN1;
+ u32 default_txcn2[] = DEFAULT_SATA_TXCN2;
+ u32 default_txcp1[] = DEFAULT_SATA_TXCP1;
+ int i;
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ctx->sds_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ctx->sds_base)) {
+ rc = PTR_ERR(ctx->sds_base);
+ goto error;
+ }
+
+ /* Retrieve optional clock */
+ ctx->clk = clk_get(&pdev->dev, NULL);
+
+ /* Load override paramaters */
+ xgene_phy_get_param(pdev, "apm,tx-eye-tuning",
+ ctx->sata_param.txeyetuning, 6, default_txeye_tuning, 1);
+ xgene_phy_get_param(pdev, "apm,tx-eye-direction",
+ ctx->sata_param.txeyedirection, 6, default_txeye_direction, 1);
+ xgene_phy_get_param(pdev, "apm,tx-boost-gain",
+ ctx->sata_param.txboostgain, 6, default_txboost_gain, 1);
+ xgene_phy_get_param(pdev, "apm,tx-amplitude",
+ ctx->sata_param.txamplitude, 6, default_txamp, 13300);
+ xgene_phy_get_param(pdev, "apm,tx-pre-cursor1",
+ ctx->sata_param.txprecursor_cn1, 6, default_txcn1, 18200);
+ xgene_phy_get_param(pdev, "apm,tx-pre-cursor2",
+ ctx->sata_param.txprecursor_cn2, 6, default_txcn2, 18200);
+ xgene_phy_get_param(pdev, "apm,tx-post-cursor",
+ ctx->sata_param.txpostcursor_cp1, 6, default_txcp1, 18200);
+ xgene_phy_get_param(pdev, "apm,tx-speed",
+ ctx->sata_param.txspeed, 3, default_spd, 1);
+ for (i = 0; i < MAX_LANE; i++)
+ ctx->sata_param.speed[i] = 2; /* Default to Gen3 */
+
+ ctx->dev = &pdev->dev;
+ platform_set_drvdata(pdev, ctx);
+
+ ctx->phy = devm_phy_create(ctx->dev, &xgene_phy_ops, NULL);
+ if (IS_ERR(ctx->phy)) {
+ dev_dbg(&pdev->dev, "Failed to create PHY\n");
+ rc = PTR_ERR(ctx->phy);
+ goto error;
+ }
+ phy_set_drvdata(ctx->phy, ctx);
+
+ phy_provider = devm_of_phy_provider_register(ctx->dev,
+ xgene_phy_xlate);
+ if (IS_ERR(phy_provider)) {
+ rc = PTR_ERR(phy_provider);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ return rc;
+}
+
+static const struct of_device_id xgene_phy_of_match[] = {
+ {.compatible = "apm,xgene-phy",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, xgene_phy_of_match);
+
+static struct platform_driver xgene_phy_driver = {
+ .probe = xgene_phy_probe,
+ .driver = {
+ .name = "xgene-phy",
+ .owner = THIS_MODULE,
+ .of_match_table = xgene_phy_of_match,
+ },
+};
+module_platform_driver(xgene_phy_driver);
+
+MODULE_DESCRIPTION("APM X-Gene Multi-Purpose PHY driver");
+MODULE_AUTHOR("Loc Ho <lho@apm.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.1");
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index be361b7cd30f..06cee0189f3e 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -217,14 +217,14 @@ config PINCTRL_IMX28
select PINCTRL_MXS
config PINCTRL_MSM
- tristate
+ bool
select PINMUX
select PINCONF
select GENERIC_PINCONF
config PINCTRL_MSM8X74
tristate "Qualcomm 8x74 pin controller driver"
- depends on GPIOLIB && OF && OF_IRQ
+ depends on GPIOLIB && OF
select PINCTRL_MSM
help
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index 340fb4e6c600..eda13de2e7c0 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -186,7 +186,9 @@ int pinctrl_dt_to_map(struct pinctrl *p)
/* CONFIG_OF enabled, p->dev not instantiated from DT */
if (!np) {
- dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n");
+ if (of_have_populated_dt())
+ dev_dbg(p->dev,
+ "no of_node; not parsing pinctrl DT\n");
return 0;
}
diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig
index 366fa541ee91..cc298fade93a 100644
--- a/drivers/pinctrl/mvebu/Kconfig
+++ b/drivers/pinctrl/mvebu/Kconfig
@@ -8,6 +8,7 @@ config PINCTRL_MVEBU
config PINCTRL_DOVE
bool
select PINCTRL_MVEBU
+ select MFD_SYSCON
config PINCTRL_KIRKWOOD
bool
@@ -17,6 +18,14 @@ config PINCTRL_ARMADA_370
bool
select PINCTRL_MVEBU
+config PINCTRL_ARMADA_375
+ bool
+ select PINCTRL_MVEBU
+
+config PINCTRL_ARMADA_38X
+ bool
+ select PINCTRL_MVEBU
+
config PINCTRL_ARMADA_XP
bool
select PINCTRL_MVEBU
diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile
index 37c253297af0..bc1b9f14f539 100644
--- a/drivers/pinctrl/mvebu/Makefile
+++ b/drivers/pinctrl/mvebu/Makefile
@@ -2,4 +2,6 @@ obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o
obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o
obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o
obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
+obj-$(CONFIG_PINCTRL_ARMADA_375) += pinctrl-armada-375.o
+obj-$(CONFIG_PINCTRL_ARMADA_38X) += pinctrl-armada-38x.o
obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-370.c b/drivers/pinctrl/mvebu/pinctrl-armada-370.c
index ae1f760cbdd2..670e5b01c678 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-370.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-370.c
@@ -23,6 +23,18 @@
#include "pinctrl-mvebu.h"
+static void __iomem *mpp_base;
+
+static int armada_370_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_370_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = {
MPP_MODE(0,
MPP_FUNCTION(0x0, "gpio", NULL),
@@ -373,7 +385,7 @@ static struct of_device_id armada_370_pinctrl_of_match[] = {
};
static struct mvebu_mpp_ctrl mv88f6710_mpp_controls[] = {
- MPP_REG_CTRL(0, 65),
+ MPP_FUNC_CTRL(0, 65, NULL, armada_370_mpp_ctrl),
};
static struct pinctrl_gpio_range mv88f6710_mpp_gpio_ranges[] = {
@@ -385,6 +397,12 @@ static struct pinctrl_gpio_range mv88f6710_mpp_gpio_ranges[] = {
static int armada_370_pinctrl_probe(struct platform_device *pdev)
{
struct mvebu_pinctrl_soc_info *soc = &armada_370_pinctrl_info;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mpp_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mpp_base))
+ return PTR_ERR(mpp_base);
soc->variant = 0; /* no variants for Armada 370 */
soc->controls = mv88f6710_mpp_controls;
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-375.c b/drivers/pinctrl/mvebu/pinctrl-armada-375.c
new file mode 100644
index 000000000000..db078fe7ace6
--- /dev/null
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-375.c
@@ -0,0 +1,459 @@
+/*
+ * Marvell Armada 375 pinctrl driver based on mvebu pinctrl core
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-mvebu.h"
+
+static void __iomem *mpp_base;
+
+static int armada_375_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_375_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
+static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
+ MPP_MODE(0,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad2"),
+ MPP_FUNCTION(0x2, "spi0", "cs1"),
+ MPP_FUNCTION(0x3, "spi1", "cs1"),
+ MPP_FUNCTION(0x5, "nand", "io2")),
+ MPP_MODE(1,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad3"),
+ MPP_FUNCTION(0x2, "spi0", "mosi"),
+ MPP_FUNCTION(0x3, "spi1", "mosi"),
+ MPP_FUNCTION(0x5, "nand", "io3")),
+ MPP_MODE(2,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad4"),
+ MPP_FUNCTION(0x2, "ptp", "eventreq"),
+ MPP_FUNCTION(0x3, "led", "c0"),
+ MPP_FUNCTION(0x4, "audio", "sdi"),
+ MPP_FUNCTION(0x5, "nand", "io4"),
+ MPP_FUNCTION(0x6, "spi1", "mosi")),
+ MPP_MODE(3,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad5"),
+ MPP_FUNCTION(0x2, "ptp", "triggen"),
+ MPP_FUNCTION(0x3, "led", "p3"),
+ MPP_FUNCTION(0x4, "audio", "mclk"),
+ MPP_FUNCTION(0x5, "nand", "io5"),
+ MPP_FUNCTION(0x6, "spi1", "miso")),
+ MPP_MODE(4,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad6"),
+ MPP_FUNCTION(0x2, "spi0", "miso"),
+ MPP_FUNCTION(0x3, "spi1", "miso"),
+ MPP_FUNCTION(0x5, "nand", "io6")),
+ MPP_MODE(5,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad7"),
+ MPP_FUNCTION(0x2, "spi0", "cs2"),
+ MPP_FUNCTION(0x3, "spi1", "cs2"),
+ MPP_FUNCTION(0x5, "nand", "io7"),
+ MPP_FUNCTION(0x6, "spi1", "miso")),
+ MPP_MODE(6,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad0"),
+ MPP_FUNCTION(0x3, "led", "p1"),
+ MPP_FUNCTION(0x4, "audio", "rclk"),
+ MPP_FUNCTION(0x5, "nand", "io0")),
+ MPP_MODE(7,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "ad1"),
+ MPP_FUNCTION(0x2, "ptp", "clk"),
+ MPP_FUNCTION(0x3, "led", "p2"),
+ MPP_FUNCTION(0x4, "audio", "extclk"),
+ MPP_FUNCTION(0x5, "nand", "io1")),
+ MPP_MODE(8,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev ", "bootcs"),
+ MPP_FUNCTION(0x2, "spi0", "cs0"),
+ MPP_FUNCTION(0x3, "spi1", "cs0"),
+ MPP_FUNCTION(0x5, "nand", "ce")),
+ MPP_MODE(9,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "nf", "wen"),
+ MPP_FUNCTION(0x2, "spi0", "sck"),
+ MPP_FUNCTION(0x3, "spi1", "sck"),
+ MPP_FUNCTION(0x5, "nand", "we")),
+ MPP_MODE(10,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "nf", "ren"),
+ MPP_FUNCTION(0x2, "dram", "vttctrl"),
+ MPP_FUNCTION(0x3, "led", "c1"),
+ MPP_FUNCTION(0x5, "nand", "re"),
+ MPP_FUNCTION(0x6, "spi1", "sck")),
+ MPP_MODE(11,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "a0"),
+ MPP_FUNCTION(0x3, "led", "c2"),
+ MPP_FUNCTION(0x4, "audio", "sdo"),
+ MPP_FUNCTION(0x5, "nand", "cle")),
+ MPP_MODE(12,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "a1"),
+ MPP_FUNCTION(0x4, "audio", "bclk"),
+ MPP_FUNCTION(0x5, "nand", "ale")),
+ MPP_MODE(13,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "dev", "readyn"),
+ MPP_FUNCTION(0x2, "pcie0", "rstoutn"),
+ MPP_FUNCTION(0x3, "pcie1", "rstoutn"),
+ MPP_FUNCTION(0x5, "nand", "rb"),
+ MPP_FUNCTION(0x6, "spi1", "mosi")),
+ MPP_MODE(14,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "i2c0", "sda"),
+ MPP_FUNCTION(0x3, "uart1", "txd")),
+ MPP_MODE(15,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "i2c0", "sck"),
+ MPP_FUNCTION(0x3, "uart1", "rxd")),
+ MPP_MODE(16,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "uart0", "txd")),
+ MPP_MODE(17,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "uart0", "rxd")),
+ MPP_MODE(18,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "tdm", "intn")),
+ MPP_MODE(19,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "tdm", "rstn")),
+ MPP_MODE(20,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "tdm", "pclk")),
+ MPP_MODE(21,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "tdm", "fsync")),
+ MPP_MODE(22,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "tdm", "drx")),
+ MPP_MODE(23,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "tdm", "dtx")),
+ MPP_MODE(24,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p0"),
+ MPP_FUNCTION(0x2, "ge1", "rxd0"),
+ MPP_FUNCTION(0x3, "sd", "cmd"),
+ MPP_FUNCTION(0x4, "uart0", "rts"),
+ MPP_FUNCTION(0x5, "spi0", "cs0"),
+ MPP_FUNCTION(0x6, "dev", "cs1")),
+ MPP_MODE(25,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p2"),
+ MPP_FUNCTION(0x2, "ge1", "rxd1"),
+ MPP_FUNCTION(0x3, "sd", "d0"),
+ MPP_FUNCTION(0x4, "uart0", "cts"),
+ MPP_FUNCTION(0x5, "spi0", "mosi"),
+ MPP_FUNCTION(0x6, "dev", "cs2")),
+ MPP_MODE(26,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie0", "clkreq"),
+ MPP_FUNCTION(0x2, "ge1", "rxd2"),
+ MPP_FUNCTION(0x3, "sd", "d2"),
+ MPP_FUNCTION(0x4, "uart1", "rts"),
+ MPP_FUNCTION(0x5, "spi0", "cs1"),
+ MPP_FUNCTION(0x6, "led", "c1")),
+ MPP_MODE(27,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie1", "clkreq"),
+ MPP_FUNCTION(0x2, "ge1", "rxd3"),
+ MPP_FUNCTION(0x3, "sd", "d1"),
+ MPP_FUNCTION(0x4, "uart1", "cts"),
+ MPP_FUNCTION(0x5, "spi0", "miso"),
+ MPP_FUNCTION(0x6, "led", "c2")),
+ MPP_MODE(28,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p3"),
+ MPP_FUNCTION(0x2, "ge1", "txctl"),
+ MPP_FUNCTION(0x3, "sd", "clk"),
+ MPP_FUNCTION(0x5, "dram", "vttctrl")),
+ MPP_MODE(29,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie1", "clkreq"),
+ MPP_FUNCTION(0x2, "ge1", "rxclk"),
+ MPP_FUNCTION(0x3, "sd", "d3"),
+ MPP_FUNCTION(0x5, "spi0", "sck"),
+ MPP_FUNCTION(0x6, "pcie0", "rstoutn")),
+ MPP_MODE(30,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge1", "txd0"),
+ MPP_FUNCTION(0x3, "spi1", "cs0"),
+ MPP_FUNCTION(0x5, "led", "p3"),
+ MPP_FUNCTION(0x6, "ptp", "eventreq")),
+ MPP_MODE(31,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge1", "txd1"),
+ MPP_FUNCTION(0x3, "spi1", "mosi"),
+ MPP_FUNCTION(0x5, "led", "p0")),
+ MPP_MODE(32,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge1", "txd2"),
+ MPP_FUNCTION(0x3, "spi1", "sck"),
+ MPP_FUNCTION(0x4, "ptp", "triggen"),
+ MPP_FUNCTION(0x5, "led", "c0")),
+ MPP_MODE(33,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge1", "txd3"),
+ MPP_FUNCTION(0x3, "spi1", "miso"),
+ MPP_FUNCTION(0x5, "led", "p2")),
+ MPP_MODE(34,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge1", "txclkout"),
+ MPP_FUNCTION(0x3, "spi1", "sck"),
+ MPP_FUNCTION(0x5, "led", "c1")),
+ MPP_MODE(35,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge1", "rxctl"),
+ MPP_FUNCTION(0x3, "spi1", "cs1"),
+ MPP_FUNCTION(0x4, "spi0", "cs2"),
+ MPP_FUNCTION(0x5, "led", "p1")),
+ MPP_MODE(36,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie0", "clkreq"),
+ MPP_FUNCTION(0x5, "led", "c2")),
+ MPP_MODE(37,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie0", "clkreq"),
+ MPP_FUNCTION(0x2, "tdm", "intn"),
+ MPP_FUNCTION(0x4, "ge", "mdc")),
+ MPP_MODE(38,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie1", "clkreq"),
+ MPP_FUNCTION(0x4, "ge", "mdio")),
+ MPP_MODE(39,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x4, "ref", "clkout"),
+ MPP_FUNCTION(0x5, "led", "p3")),
+ MPP_MODE(40,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x4, "uart1", "txd"),
+ MPP_FUNCTION(0x5, "led", "p0")),
+ MPP_MODE(41,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x4, "uart1", "rxd"),
+ MPP_FUNCTION(0x5, "led", "p1")),
+ MPP_MODE(42,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x3, "spi1", "cs2"),
+ MPP_FUNCTION(0x4, "led", "c0"),
+ MPP_FUNCTION(0x6, "ptp", "clk")),
+ MPP_MODE(43,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "sata0", "prsnt"),
+ MPP_FUNCTION(0x4, "dram", "vttctrl"),
+ MPP_FUNCTION(0x5, "led", "c1")),
+ MPP_MODE(44,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x4, "sata0", "prsnt")),
+ MPP_MODE(45,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "spi0", "cs2"),
+ MPP_FUNCTION(0x4, "pcie0", "rstoutn"),
+ MPP_FUNCTION(0x5, "led", "c2"),
+ MPP_FUNCTION(0x6, "spi1", "cs2")),
+ MPP_MODE(46,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p0"),
+ MPP_FUNCTION(0x2, "ge0", "txd0"),
+ MPP_FUNCTION(0x3, "ge1", "txd0"),
+ MPP_FUNCTION(0x6, "dev", "wen1")),
+ MPP_MODE(47,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p1"),
+ MPP_FUNCTION(0x2, "ge0", "txd1"),
+ MPP_FUNCTION(0x3, "ge1", "txd1"),
+ MPP_FUNCTION(0x5, "ptp", "triggen"),
+ MPP_FUNCTION(0x6, "dev", "ale0")),
+ MPP_MODE(48,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p2"),
+ MPP_FUNCTION(0x2, "ge0", "txd2"),
+ MPP_FUNCTION(0x3, "ge1", "txd2"),
+ MPP_FUNCTION(0x6, "dev", "ale1")),
+ MPP_MODE(49,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "p3"),
+ MPP_FUNCTION(0x2, "ge0", "txd3"),
+ MPP_FUNCTION(0x3, "ge1", "txd3"),
+ MPP_FUNCTION(0x6, "dev", "a2")),
+ MPP_MODE(50,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "c0"),
+ MPP_FUNCTION(0x2, "ge0", "rxd0"),
+ MPP_FUNCTION(0x3, "ge1", "rxd0"),
+ MPP_FUNCTION(0x5, "ptp", "eventreq"),
+ MPP_FUNCTION(0x6, "dev", "ad12")),
+ MPP_MODE(51,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "c1"),
+ MPP_FUNCTION(0x2, "ge0", "rxd1"),
+ MPP_FUNCTION(0x3, "ge1", "rxd1"),
+ MPP_FUNCTION(0x6, "dev", "ad8")),
+ MPP_MODE(52,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "led", "c2"),
+ MPP_FUNCTION(0x2, "ge0", "rxd2"),
+ MPP_FUNCTION(0x3, "ge1", "rxd2"),
+ MPP_FUNCTION(0x5, "i2c0", "sda"),
+ MPP_FUNCTION(0x6, "dev", "ad9")),
+ MPP_MODE(53,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie1", "rstoutn"),
+ MPP_FUNCTION(0x2, "ge0", "rxd3"),
+ MPP_FUNCTION(0x3, "ge1", "rxd3"),
+ MPP_FUNCTION(0x5, "i2c0", "sck"),
+ MPP_FUNCTION(0x6, "dev", "ad10")),
+ MPP_MODE(54,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "pcie0", "rstoutn"),
+ MPP_FUNCTION(0x2, "ge0", "rxctl"),
+ MPP_FUNCTION(0x3, "ge1", "rxctl"),
+ MPP_FUNCTION(0x6, "dev", "ad11")),
+ MPP_MODE(55,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge0", "rxclk"),
+ MPP_FUNCTION(0x3, "ge1", "rxclk"),
+ MPP_FUNCTION(0x6, "dev", "cs0")),
+ MPP_MODE(56,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge0", "txclkout"),
+ MPP_FUNCTION(0x3, "ge1", "txclkout"),
+ MPP_FUNCTION(0x6, "dev", "oe")),
+ MPP_MODE(57,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ge0", "txctl"),
+ MPP_FUNCTION(0x3, "ge1", "txctl"),
+ MPP_FUNCTION(0x6, "dev", "wen0")),
+ MPP_MODE(58,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x4, "led", "c0")),
+ MPP_MODE(59,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x4, "led", "c1")),
+ MPP_MODE(60,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "uart1", "txd"),
+ MPP_FUNCTION(0x4, "led", "c2"),
+ MPP_FUNCTION(0x6, "dev", "ad13")),
+ MPP_MODE(61,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "i2c1", "sda"),
+ MPP_FUNCTION(0x2, "uart1", "rxd"),
+ MPP_FUNCTION(0x3, "spi1", "cs2"),
+ MPP_FUNCTION(0x4, "led", "p0"),
+ MPP_FUNCTION(0x6, "dev", "ad14")),
+ MPP_MODE(62,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "i2c1", "sck"),
+ MPP_FUNCTION(0x4, "led", "p1"),
+ MPP_FUNCTION(0x6, "dev", "ad15")),
+ MPP_MODE(63,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ptp", "triggen"),
+ MPP_FUNCTION(0x4, "led", "p2"),
+ MPP_FUNCTION(0x6, "dev", "burst")),
+ MPP_MODE(64,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "dram", "vttctrl"),
+ MPP_FUNCTION(0x4, "led", "p3")),
+ MPP_MODE(65,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x1, "sata1", "prsnt")),
+ MPP_MODE(66,
+ MPP_FUNCTION(0x0, "gpio", NULL),
+ MPP_FUNCTION(0x2, "ptp", "eventreq"),
+ MPP_FUNCTION(0x4, "spi1", "cs3"),
+ MPP_FUNCTION(0x5, "pcie0", "rstoutn"),
+ MPP_FUNCTION(0x6, "dev", "cs3")),
+};
+
+static struct mvebu_pinctrl_soc_info armada_375_pinctrl_info;
+
+static struct of_device_id armada_375_pinctrl_of_match[] = {
+ { .compatible = "marvell,mv88f6720-pinctrl" },
+ { },
+};
+
+static struct mvebu_mpp_ctrl mv88f6720_mpp_controls[] = {
+ MPP_FUNC_CTRL(0, 69, NULL, armada_375_mpp_ctrl),
+};
+
+static struct pinctrl_gpio_range mv88f6720_mpp_gpio_ranges[] = {
+ MPP_GPIO_RANGE(0, 0, 0, 32),
+ MPP_GPIO_RANGE(1, 32, 32, 32),
+ MPP_GPIO_RANGE(2, 64, 64, 3),
+};
+
+static int armada_375_pinctrl_probe(struct platform_device *pdev)
+{
+ struct mvebu_pinctrl_soc_info *soc = &armada_375_pinctrl_info;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mpp_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mpp_base))
+ return PTR_ERR(mpp_base);
+
+ soc->variant = 0; /* no variants for Armada 375 */
+ soc->controls = mv88f6720_mpp_controls;
+ soc->ncontrols = ARRAY_SIZE(mv88f6720_mpp_controls);
+ soc->modes = mv88f6720_mpp_modes;
+ soc->nmodes = ARRAY_SIZE(mv88f6720_mpp_modes);
+ soc->gpioranges = mv88f6720_mpp_gpio_ranges;
+ soc->ngpioranges = ARRAY_SIZE(mv88f6720_mpp_gpio_ranges);
+
+ pdev->dev.platform_data = soc;
+
+ return mvebu_pinctrl_probe(pdev);
+}
+
+static int armada_375_pinctrl_remove(struct platform_device *pdev)
+{
+ return mvebu_pinctrl_remove(pdev);
+}
+
+static struct platform_driver armada_375_pinctrl_driver = {
+ .driver = {
+ .name = "armada-375-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(armada_375_pinctrl_of_match),
+ },
+ .probe = armada_375_pinctrl_probe,
+ .remove = armada_375_pinctrl_remove,
+};
+
+module_platform_driver(armada_375_pinctrl_driver);
+
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell Armada 375 pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
new file mode 100644
index 000000000000..1049f82fb62f
--- /dev/null
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
@@ -0,0 +1,462 @@
+/*
+ * Marvell Armada 380/385 pinctrl driver based on mvebu pinctrl core
+ *
+ * Copyright (C) 2013 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-mvebu.h"
+
+static void __iomem *mpp_base;
+
+static int armada_38x_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_38x_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
+enum {
+ V_88F6810 = BIT(0),
+ V_88F6820 = BIT(1),
+ V_88F6828 = BIT(2),
+ V_88F6810_PLUS = (V_88F6810 | V_88F6820 | V_88F6828),
+ V_88F6820_PLUS = (V_88F6820 | V_88F6828),
+};
+
+static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
+ MPP_MODE(0,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua0", "rxd", V_88F6810_PLUS)),
+ MPP_MODE(1,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua0", "txd", V_88F6810_PLUS)),
+ MPP_MODE(2,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "i2c0", "sck", V_88F6810_PLUS)),
+ MPP_MODE(3,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "i2c0", "sda", V_88F6810_PLUS)),
+ MPP_MODE(4,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge", "mdc", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ua1", "txd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "rts", V_88F6810_PLUS)),
+ MPP_MODE(5,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge", "mdio", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ua1", "rxd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6810_PLUS)),
+ MPP_MODE(6,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txclkout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge0", "crs", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "cs3", V_88F6810_PLUS)),
+ MPP_MODE(7,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txd0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad9", V_88F6810_PLUS)),
+ MPP_MODE(8,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txd1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad10", V_88F6810_PLUS)),
+ MPP_MODE(9,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txd2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad11", V_88F6810_PLUS)),
+ MPP_MODE(10,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txd3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad12", V_88F6810_PLUS)),
+ MPP_MODE(11,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txctl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad13", V_88F6810_PLUS)),
+ MPP_MODE(12,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxd0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "cs1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad14", V_88F6810_PLUS)),
+ MPP_MODE(13,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxd1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie0", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "clkreq", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "cs2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad15", V_88F6810_PLUS)),
+ MPP_MODE(14,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxd2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "m", "vtt_ctrl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "cs3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "wen1", V_88F6810_PLUS)),
+ MPP_MODE(15,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxd3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge", "mdc slave", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "mosi", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "pcie1", "rstout", V_88F6820_PLUS)),
+ MPP_MODE(16,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxctl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge", "mdio slave", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "m", "decc_err", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "miso", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "pcie0", "clkreq", V_88F6810_PLUS)),
+ MPP_MODE(17,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua1", "rxd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sata1", "prsnt", V_88F6810_PLUS)),
+ MPP_MODE(18,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxerr", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "trig_gen", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua1", "txd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "cs0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "pcie1", "rstout", V_88F6820_PLUS)),
+ MPP_MODE(19,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "col", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "event_req", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie0", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "ua0", "cts", V_88F6810_PLUS)),
+ MPP_MODE(20,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "ua0", "rts", V_88F6810_PLUS)),
+ MPP_MODE(21,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "cs1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxd0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "cmd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "bootcs", V_88F6810_PLUS)),
+ MPP_MODE(22,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "mosi", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad0", V_88F6810_PLUS)),
+ MPP_MODE(23,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad2", V_88F6810_PLUS)),
+ MPP_MODE(24,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "miso", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ua0", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua1", "rxd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d4", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ready", V_88F6810_PLUS)),
+ MPP_MODE(25,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "cs0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ua0", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua1", "txd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d5", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "cs0", V_88F6810_PLUS)),
+ MPP_MODE(26,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "cs2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "i2c1", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d6", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "cs1", V_88F6810_PLUS)),
+ MPP_MODE(27,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "cs3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txclkout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "i2c1", "sda", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d7", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "cs2", V_88F6810_PLUS)),
+ MPP_MODE(28,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txd0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad5", V_88F6810_PLUS)),
+ MPP_MODE(29,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txd1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ale0", V_88F6810_PLUS)),
+ MPP_MODE(30,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txd2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "oen", V_88F6810_PLUS)),
+ MPP_MODE(31,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txd3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ale1", V_88F6810_PLUS)),
+ MPP_MODE(32,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txctl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "wen0", V_88F6810_PLUS)),
+ MPP_MODE(33,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "m", "decc_err", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad3", V_88F6810_PLUS)),
+ MPP_MODE(34,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad1", V_88F6810_PLUS)),
+ MPP_MODE(35,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ref", "clk_out1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "a1", V_88F6810_PLUS)),
+ MPP_MODE(36,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ptp", "trig_gen", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "a0", V_88F6810_PLUS)),
+ MPP_MODE(37,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ptp", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad8", V_88F6810_PLUS)),
+ MPP_MODE(38,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ptp", "event_req", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxd1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ref", "clk_out0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad4", V_88F6810_PLUS)),
+ MPP_MODE(39,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "i2c1", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxd2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "a2", V_88F6810_PLUS)),
+ MPP_MODE(40,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "i2c1", "sda", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxd3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad6", V_88F6810_PLUS)),
+ MPP_MODE(41,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua1", "rxd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxctl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "cs3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "burst/last", V_88F6810_PLUS)),
+ MPP_MODE(42,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua1", "txd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad7", V_88F6810_PLUS)),
+ MPP_MODE(43,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie0", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "m", "vtt_ctrl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "m", "decc_err", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "clkout", V_88F6810_PLUS)),
+ MPP_MODE(44,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "sata2", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(4, "sata3", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(5, "pcie0", "rstout", V_88F6810_PLUS)),
+ MPP_MODE(45,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ref", "clk_out0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "pcie2", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "pcie3", "rstout", V_88F6810_PLUS)),
+ MPP_MODE(46,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ref", "clk_out1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "pcie2", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "pcie3", "rstout", V_88F6810_PLUS)),
+ MPP_MODE(47,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "sata2", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(4, "spi1", "cs2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sata3", "prsnt", V_88F6828)),
+ MPP_MODE(48,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "m", "vtt_ctrl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm2c", "pclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "mclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d4", V_88F6810_PLUS)),
+ MPP_MODE(49,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata2", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(2, "sata3", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(3, "tdm2c", "fsync", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "lrclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d5", V_88F6810_PLUS)),
+ MPP_MODE(50,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm2c", "drx", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "extclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "cmd", V_88F6810_PLUS)),
+ MPP_MODE(51,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm2c", "dtx", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "sdo", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "m", "decc_err", V_88F6810_PLUS)),
+ MPP_MODE(52,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm2c", "intn", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "sdi", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d6", V_88F6810_PLUS)),
+ MPP_MODE(53,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm2c", "rstn", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "bclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d7", V_88F6810_PLUS)),
+ MPP_MODE(54,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d3", V_88F6810_PLUS)),
+ MPP_MODE(55,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua1", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge", "mdio", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "clkreq", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "cs1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d0", V_88F6810_PLUS)),
+ MPP_MODE(56,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua1", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge", "mdc", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "m", "decc_err", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "mosi", V_88F6810_PLUS)),
+ MPP_MODE(57,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "clk", V_88F6810_PLUS)),
+ MPP_MODE(58,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie1", "clkreq", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(2, "i2c1", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie2", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "miso", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d1", V_88F6810_PLUS)),
+ MPP_MODE(59,
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "i2c1", "sda", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "cs0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d2", V_88F6810_PLUS)),
+};
+
+static struct mvebu_pinctrl_soc_info armada_38x_pinctrl_info;
+
+static struct of_device_id armada_38x_pinctrl_of_match[] = {
+ {
+ .compatible = "marvell,mv88f6810-pinctrl",
+ .data = (void *) V_88F6810,
+ },
+ {
+ .compatible = "marvell,mv88f6820-pinctrl",
+ .data = (void *) V_88F6820,
+ },
+ {
+ .compatible = "marvell,mv88f6828-pinctrl",
+ .data = (void *) V_88F6828,
+ },
+ { },
+};
+
+static struct mvebu_mpp_ctrl armada_38x_mpp_controls[] = {
+ MPP_FUNC_CTRL(0, 59, NULL, armada_38x_mpp_ctrl),
+};
+
+static struct pinctrl_gpio_range armada_38x_mpp_gpio_ranges[] = {
+ MPP_GPIO_RANGE(0, 0, 0, 32),
+ MPP_GPIO_RANGE(1, 32, 32, 27),
+};
+
+static int armada_38x_pinctrl_probe(struct platform_device *pdev)
+{
+ struct mvebu_pinctrl_soc_info *soc = &armada_38x_pinctrl_info;
+ const struct of_device_id *match =
+ of_match_device(armada_38x_pinctrl_of_match, &pdev->dev);
+ struct resource *res;
+
+ if (!match)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mpp_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mpp_base))
+ return PTR_ERR(mpp_base);
+
+ soc->variant = (unsigned) match->data & 0xff;
+ soc->controls = armada_38x_mpp_controls;
+ soc->ncontrols = ARRAY_SIZE(armada_38x_mpp_controls);
+ soc->gpioranges = armada_38x_mpp_gpio_ranges;
+ soc->ngpioranges = ARRAY_SIZE(armada_38x_mpp_gpio_ranges);
+ soc->modes = armada_38x_mpp_modes;
+ soc->nmodes = armada_38x_mpp_controls[0].npins;
+
+ pdev->dev.platform_data = soc;
+
+ return mvebu_pinctrl_probe(pdev);
+}
+
+static int armada_38x_pinctrl_remove(struct platform_device *pdev)
+{
+ return mvebu_pinctrl_remove(pdev);
+}
+
+static struct platform_driver armada_38x_pinctrl_driver = {
+ .driver = {
+ .name = "armada-38x-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(armada_38x_pinctrl_of_match),
+ },
+ .probe = armada_38x_pinctrl_probe,
+ .remove = armada_38x_pinctrl_remove,
+};
+
+module_platform_driver(armada_38x_pinctrl_driver);
+
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell Armada 38x pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
index 843a51f9d129..de311129f7a0 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
@@ -33,6 +33,18 @@
#include "pinctrl-mvebu.h"
+static void __iomem *mpp_base;
+
+static int armada_xp_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int armada_xp_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
enum armada_xp_variant {
V_MV78230 = BIT(0),
V_MV78260 = BIT(1),
@@ -366,7 +378,7 @@ static struct of_device_id armada_xp_pinctrl_of_match[] = {
};
static struct mvebu_mpp_ctrl mv78230_mpp_controls[] = {
- MPP_REG_CTRL(0, 48),
+ MPP_FUNC_CTRL(0, 48, NULL, armada_xp_mpp_ctrl),
};
static struct pinctrl_gpio_range mv78230_mpp_gpio_ranges[] = {
@@ -375,7 +387,7 @@ static struct pinctrl_gpio_range mv78230_mpp_gpio_ranges[] = {
};
static struct mvebu_mpp_ctrl mv78260_mpp_controls[] = {
- MPP_REG_CTRL(0, 66),
+ MPP_FUNC_CTRL(0, 66, NULL, armada_xp_mpp_ctrl),
};
static struct pinctrl_gpio_range mv78260_mpp_gpio_ranges[] = {
@@ -385,7 +397,7 @@ static struct pinctrl_gpio_range mv78260_mpp_gpio_ranges[] = {
};
static struct mvebu_mpp_ctrl mv78460_mpp_controls[] = {
- MPP_REG_CTRL(0, 66),
+ MPP_FUNC_CTRL(0, 66, NULL, armada_xp_mpp_ctrl),
};
static struct pinctrl_gpio_range mv78460_mpp_gpio_ranges[] = {
@@ -399,10 +411,16 @@ static int armada_xp_pinctrl_probe(struct platform_device *pdev)
struct mvebu_pinctrl_soc_info *soc = &armada_xp_pinctrl_info;
const struct of_device_id *match =
of_match_device(armada_xp_pinctrl_of_match, &pdev->dev);
+ struct resource *res;
if (!match)
return -ENODEV;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mpp_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mpp_base))
+ return PTR_ERR(mpp_base);
+
soc->variant = (unsigned) match->data & 0xff;
switch (soc->variant) {
diff --git a/drivers/pinctrl/mvebu/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c
index 47268393af34..3b022178a566 100644
--- a/drivers/pinctrl/mvebu/pinctrl-dove.c
+++ b/drivers/pinctrl/mvebu/pinctrl-dove.c
@@ -18,107 +18,122 @@
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/mfd/syscon.h>
#include <linux/pinctrl/pinctrl.h>
+#include <linux/regmap.h>
#include "pinctrl-mvebu.h"
-#define DOVE_SB_REGS_VIRT_BASE IOMEM(0xfde00000)
-#define DOVE_MPP_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE + 0xd0200)
-#define DOVE_PMU_MPP_GENERAL_CTRL (DOVE_MPP_VIRT_BASE + 0x10)
-#define DOVE_AU0_AC97_SEL BIT(16)
-#define DOVE_PMU_SIGNAL_SELECT_0 (DOVE_SB_REGS_VIRT_BASE + 0xd802C)
-#define DOVE_PMU_SIGNAL_SELECT_1 (DOVE_SB_REGS_VIRT_BASE + 0xd8030)
-#define DOVE_GLOBAL_CONFIG_1 (DOVE_SB_REGS_VIRT_BASE + 0xe802C)
-#define DOVE_GLOBAL_CONFIG_1 (DOVE_SB_REGS_VIRT_BASE + 0xe802C)
-#define DOVE_TWSI_ENABLE_OPTION1 BIT(7)
-#define DOVE_GLOBAL_CONFIG_2 (DOVE_SB_REGS_VIRT_BASE + 0xe8030)
-#define DOVE_TWSI_ENABLE_OPTION2 BIT(20)
-#define DOVE_TWSI_ENABLE_OPTION3 BIT(21)
-#define DOVE_TWSI_OPTION3_GPIO BIT(22)
-#define DOVE_SSP_CTRL_STATUS_1 (DOVE_SB_REGS_VIRT_BASE + 0xe8034)
-#define DOVE_SSP_ON_AU1 BIT(0)
-#define DOVE_MPP_GENERAL_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE + 0xe803c)
-#define DOVE_AU1_SPDIFO_GPIO_EN BIT(1)
-#define DOVE_NAND_GPIO_EN BIT(0)
-#define DOVE_GPIO_LO_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE + 0xd0400)
-#define DOVE_MPP_CTRL4_VIRT_BASE (DOVE_GPIO_LO_VIRT_BASE + 0x40)
-#define DOVE_SPI_GPIO_SEL BIT(5)
-#define DOVE_UART1_GPIO_SEL BIT(4)
-#define DOVE_AU1_GPIO_SEL BIT(3)
-#define DOVE_CAM_GPIO_SEL BIT(2)
-#define DOVE_SD1_GPIO_SEL BIT(1)
-#define DOVE_SD0_GPIO_SEL BIT(0)
-
-#define MPPS_PER_REG 8
-#define MPP_BITS 4
-#define MPP_MASK 0xf
+/* Internal registers can be configured at any 1 MiB aligned address */
+#define INT_REGS_MASK ~(SZ_1M - 1)
+#define MPP4_REGS_OFFS 0xd0440
+#define PMU_REGS_OFFS 0xd802c
+#define GC_REGS_OFFS 0xe802c
+
+/* MPP Base registers */
+#define PMU_MPP_GENERAL_CTRL 0x10
+#define AU0_AC97_SEL BIT(16)
+
+/* MPP Control 4 register */
+#define SPI_GPIO_SEL BIT(5)
+#define UART1_GPIO_SEL BIT(4)
+#define AU1_GPIO_SEL BIT(3)
+#define CAM_GPIO_SEL BIT(2)
+#define SD1_GPIO_SEL BIT(1)
+#define SD0_GPIO_SEL BIT(0)
+
+/* PMU Signal Select registers */
+#define PMU_SIGNAL_SELECT_0 0x00
+#define PMU_SIGNAL_SELECT_1 0x04
+
+/* Global Config regmap registers */
+#define GLOBAL_CONFIG_1 0x00
+#define TWSI_ENABLE_OPTION1 BIT(7)
+#define GLOBAL_CONFIG_2 0x04
+#define TWSI_ENABLE_OPTION2 BIT(20)
+#define TWSI_ENABLE_OPTION3 BIT(21)
+#define TWSI_OPTION3_GPIO BIT(22)
+#define SSP_CTRL_STATUS_1 0x08
+#define SSP_ON_AU1 BIT(0)
+#define MPP_GENERAL_CONFIG 0x10
+#define AU1_SPDIFO_GPIO_EN BIT(1)
+#define NAND_GPIO_EN BIT(0)
#define CONFIG_PMU BIT(4)
-static int dove_pmu_mpp_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
- unsigned long *config)
+static void __iomem *mpp_base;
+static void __iomem *mpp4_base;
+static void __iomem *pmu_base;
+static struct regmap *gconfmap;
+
+static int dove_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int dove_mpp_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned off = (ctrl->pid / MPPS_PER_REG) * MPP_BITS;
- unsigned shift = (ctrl->pid % MPPS_PER_REG) * MPP_BITS;
- unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
+static int dove_pmu_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
unsigned long func;
- if (pmu & (1 << ctrl->pid)) {
- func = readl(DOVE_PMU_SIGNAL_SELECT_0 + off);
- *config = (func >> shift) & MPP_MASK;
- *config |= CONFIG_PMU;
- } else {
- func = readl(DOVE_MPP_VIRT_BASE + off);
- *config = (func >> shift) & MPP_MASK;
- }
+ if ((pmu & BIT(pid)) == 0)
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+
+ func = readl(pmu_base + PMU_SIGNAL_SELECT_0 + off);
+ *config = (func >> shift) & MVEBU_MPP_MASK;
+ *config |= CONFIG_PMU;
+
return 0;
}
-static int dove_pmu_mpp_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
- unsigned long config)
+static int dove_pmu_mpp_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned off = (ctrl->pid / MPPS_PER_REG) * MPP_BITS;
- unsigned shift = (ctrl->pid % MPPS_PER_REG) * MPP_BITS;
- unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+ unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
unsigned long func;
- if (config & CONFIG_PMU) {
- writel(pmu | (1 << ctrl->pid), DOVE_PMU_MPP_GENERAL_CTRL);
- func = readl(DOVE_PMU_SIGNAL_SELECT_0 + off);
- func &= ~(MPP_MASK << shift);
- func |= (config & MPP_MASK) << shift;
- writel(func, DOVE_PMU_SIGNAL_SELECT_0 + off);
- } else {
- writel(pmu & ~(1 << ctrl->pid), DOVE_PMU_MPP_GENERAL_CTRL);
- func = readl(DOVE_MPP_VIRT_BASE + off);
- func &= ~(MPP_MASK << shift);
- func |= (config & MPP_MASK) << shift;
- writel(func, DOVE_MPP_VIRT_BASE + off);
+ if ((config & CONFIG_PMU) == 0) {
+ writel(pmu & ~BIT(pid), mpp_base + PMU_MPP_GENERAL_CTRL);
+ return default_mpp_ctrl_set(mpp_base, pid, config);
}
+
+ writel(pmu | BIT(pid), mpp_base + PMU_MPP_GENERAL_CTRL);
+ func = readl(pmu_base + PMU_SIGNAL_SELECT_0 + off);
+ func &= ~(MVEBU_MPP_MASK << shift);
+ func |= (config & MVEBU_MPP_MASK) << shift;
+ writel(func, pmu_base + PMU_SIGNAL_SELECT_0 + off);
+
return 0;
}
-static int dove_mpp4_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
- unsigned long *config)
+static int dove_mpp4_ctrl_get(unsigned pid, unsigned long *config)
{
- unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
+ unsigned long mpp4 = readl(mpp4_base);
unsigned long mask;
- switch (ctrl->pid) {
+ switch (pid) {
case 24: /* mpp_camera */
- mask = DOVE_CAM_GPIO_SEL;
+ mask = CAM_GPIO_SEL;
break;
case 40: /* mpp_sdio0 */
- mask = DOVE_SD0_GPIO_SEL;
+ mask = SD0_GPIO_SEL;
break;
case 46: /* mpp_sdio1 */
- mask = DOVE_SD1_GPIO_SEL;
+ mask = SD1_GPIO_SEL;
break;
case 58: /* mpp_spi0 */
- mask = DOVE_SPI_GPIO_SEL;
+ mask = SPI_GPIO_SEL;
break;
case 62: /* mpp_uart1 */
- mask = DOVE_UART1_GPIO_SEL;
+ mask = UART1_GPIO_SEL;
break;
default:
return -EINVAL;
@@ -129,27 +144,26 @@ static int dove_mpp4_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
return 0;
}
-static int dove_mpp4_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
- unsigned long config)
+static int dove_mpp4_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
+ unsigned long mpp4 = readl(mpp4_base);
unsigned long mask;
- switch (ctrl->pid) {
+ switch (pid) {
case 24: /* mpp_camera */
- mask = DOVE_CAM_GPIO_SEL;
+ mask = CAM_GPIO_SEL;
break;
case 40: /* mpp_sdio0 */
- mask = DOVE_SD0_GPIO_SEL;
+ mask = SD0_GPIO_SEL;
break;
case 46: /* mpp_sdio1 */
- mask = DOVE_SD1_GPIO_SEL;
+ mask = SD1_GPIO_SEL;
break;
case 58: /* mpp_spi0 */
- mask = DOVE_SPI_GPIO_SEL;
+ mask = SPI_GPIO_SEL;
break;
case 62: /* mpp_uart1 */
- mask = DOVE_UART1_GPIO_SEL;
+ mask = UART1_GPIO_SEL;
break;
default:
return -EINVAL;
@@ -159,74 +173,69 @@ static int dove_mpp4_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
if (config)
mpp4 |= mask;
- writel(mpp4, DOVE_MPP_CTRL4_VIRT_BASE);
+ writel(mpp4, mpp4_base);
return 0;
}
-static int dove_nand_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
- unsigned long *config)
+static int dove_nand_ctrl_get(unsigned pid, unsigned long *config)
{
- unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
+ unsigned int gmpp;
- *config = ((gmpp & DOVE_NAND_GPIO_EN) != 0);
+ regmap_read(gconfmap, MPP_GENERAL_CONFIG, &gmpp);
+ *config = ((gmpp & NAND_GPIO_EN) != 0);
return 0;
}
-static int dove_nand_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
- unsigned long config)
+static int dove_nand_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
-
- gmpp &= ~DOVE_NAND_GPIO_EN;
- if (config)
- gmpp |= DOVE_NAND_GPIO_EN;
-
- writel(gmpp, DOVE_MPP_GENERAL_VIRT_BASE);
-
+ regmap_update_bits(gconfmap, MPP_GENERAL_CONFIG,
+ NAND_GPIO_EN,
+ (config) ? NAND_GPIO_EN : 0);
return 0;
}
-static int dove_audio0_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
- unsigned long *config)
+static int dove_audio0_ctrl_get(unsigned pid, unsigned long *config)
{
- unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+ unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
- *config = ((pmu & DOVE_AU0_AC97_SEL) != 0);
+ *config = ((pmu & AU0_AC97_SEL) != 0);
return 0;
}
-static int dove_audio0_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
- unsigned long config)
+static int dove_audio0_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+ unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
- pmu &= ~DOVE_AU0_AC97_SEL;
+ pmu &= ~AU0_AC97_SEL;
if (config)
- pmu |= DOVE_AU0_AC97_SEL;
- writel(pmu, DOVE_PMU_MPP_GENERAL_CTRL);
+ pmu |= AU0_AC97_SEL;
+ writel(pmu, mpp_base + PMU_MPP_GENERAL_CTRL);
return 0;
}
-static int dove_audio1_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
- unsigned long *config)
+static int dove_audio1_ctrl_get(unsigned pid, unsigned long *config)
{
- unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
- unsigned long sspc1 = readl(DOVE_SSP_CTRL_STATUS_1);
- unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
- unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
+ unsigned int mpp4 = readl(mpp4_base);
+ unsigned int sspc1;
+ unsigned int gmpp;
+ unsigned int gcfg2;
+
+ regmap_read(gconfmap, SSP_CTRL_STATUS_1, &sspc1);
+ regmap_read(gconfmap, MPP_GENERAL_CONFIG, &gmpp);
+ regmap_read(gconfmap, GLOBAL_CONFIG_2, &gcfg2);
*config = 0;
- if (mpp4 & DOVE_AU1_GPIO_SEL)
+ if (mpp4 & AU1_GPIO_SEL)
*config |= BIT(3);
- if (sspc1 & DOVE_SSP_ON_AU1)
+ if (sspc1 & SSP_ON_AU1)
*config |= BIT(2);
- if (gmpp & DOVE_AU1_SPDIFO_GPIO_EN)
+ if (gmpp & AU1_SPDIFO_GPIO_EN)
*config |= BIT(1);
- if (gcfg2 & DOVE_TWSI_OPTION3_GPIO)
+ if (gcfg2 & TWSI_OPTION3_GPIO)
*config |= BIT(0);
/* SSP/TWSI only if I2S1 not set*/
@@ -238,35 +247,24 @@ static int dove_audio1_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
return 0;
}
-static int dove_audio1_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
- unsigned long config)
+static int dove_audio1_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned long mpp4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
- unsigned long sspc1 = readl(DOVE_SSP_CTRL_STATUS_1);
- unsigned long gmpp = readl(DOVE_MPP_GENERAL_VIRT_BASE);
- unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
+ unsigned int mpp4 = readl(mpp4_base);
- /*
- * clear all audio1 related bits before configure
- */
- gcfg2 &= ~DOVE_TWSI_OPTION3_GPIO;
- gmpp &= ~DOVE_AU1_SPDIFO_GPIO_EN;
- sspc1 &= ~DOVE_SSP_ON_AU1;
- mpp4 &= ~DOVE_AU1_GPIO_SEL;
-
- if (config & BIT(0))
- gcfg2 |= DOVE_TWSI_OPTION3_GPIO;
- if (config & BIT(1))
- gmpp |= DOVE_AU1_SPDIFO_GPIO_EN;
- if (config & BIT(2))
- sspc1 |= DOVE_SSP_ON_AU1;
+ mpp4 &= ~AU1_GPIO_SEL;
if (config & BIT(3))
- mpp4 |= DOVE_AU1_GPIO_SEL;
-
- writel(mpp4, DOVE_MPP_CTRL4_VIRT_BASE);
- writel(sspc1, DOVE_SSP_CTRL_STATUS_1);
- writel(gmpp, DOVE_MPP_GENERAL_VIRT_BASE);
- writel(gcfg2, DOVE_GLOBAL_CONFIG_2);
+ mpp4 |= AU1_GPIO_SEL;
+ writel(mpp4, mpp4_base);
+
+ regmap_update_bits(gconfmap, SSP_CTRL_STATUS_1,
+ SSP_ON_AU1,
+ (config & BIT(2)) ? SSP_ON_AU1 : 0);
+ regmap_update_bits(gconfmap, MPP_GENERAL_CONFIG,
+ AU1_SPDIFO_GPIO_EN,
+ (config & BIT(1)) ? AU1_SPDIFO_GPIO_EN : 0);
+ regmap_update_bits(gconfmap, GLOBAL_CONFIG_2,
+ TWSI_OPTION3_GPIO,
+ (config & BIT(0)) ? TWSI_OPTION3_GPIO : 0);
return 0;
}
@@ -276,11 +274,11 @@ static int dove_audio1_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
* break other functions. If you require all mpps as gpio
* enforce gpio setting by pinctrl mapping.
*/
-static int dove_audio1_ctrl_gpio_req(struct mvebu_mpp_ctrl *ctrl, u8 pid)
+static int dove_audio1_ctrl_gpio_req(unsigned pid)
{
unsigned long config;
- dove_audio1_ctrl_get(ctrl, &config);
+ dove_audio1_ctrl_get(pid, &config);
switch (config) {
case 0x02: /* i2s1 : gpio[56:57] */
@@ -303,76 +301,62 @@ static int dove_audio1_ctrl_gpio_req(struct mvebu_mpp_ctrl *ctrl, u8 pid)
}
/* mpp[52:57] has gpio pins capable of in and out */
-static int dove_audio1_ctrl_gpio_dir(struct mvebu_mpp_ctrl *ctrl, u8 pid,
- bool input)
+static int dove_audio1_ctrl_gpio_dir(unsigned pid, bool input)
{
if (pid < 52 || pid > 57)
return -ENOTSUPP;
return 0;
}
-static int dove_twsi_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
- unsigned long *config)
+static int dove_twsi_ctrl_get(unsigned pid, unsigned long *config)
{
- unsigned long gcfg1 = readl(DOVE_GLOBAL_CONFIG_1);
- unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
+ unsigned int gcfg1;
+ unsigned int gcfg2;
+
+ regmap_read(gconfmap, GLOBAL_CONFIG_1, &gcfg1);
+ regmap_read(gconfmap, GLOBAL_CONFIG_2, &gcfg2);
*config = 0;
- if (gcfg1 & DOVE_TWSI_ENABLE_OPTION1)
+ if (gcfg1 & TWSI_ENABLE_OPTION1)
*config = 1;
- else if (gcfg2 & DOVE_TWSI_ENABLE_OPTION2)
+ else if (gcfg2 & TWSI_ENABLE_OPTION2)
*config = 2;
- else if (gcfg2 & DOVE_TWSI_ENABLE_OPTION3)
+ else if (gcfg2 & TWSI_ENABLE_OPTION3)
*config = 3;
return 0;
}
-static int dove_twsi_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
- unsigned long config)
+static int dove_twsi_ctrl_set(unsigned pid, unsigned long config)
{
- unsigned long gcfg1 = readl(DOVE_GLOBAL_CONFIG_1);
- unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2);
-
- gcfg1 &= ~DOVE_TWSI_ENABLE_OPTION1;
- gcfg2 &= ~(DOVE_TWSI_ENABLE_OPTION2 | DOVE_TWSI_ENABLE_OPTION3);
+ unsigned int gcfg1 = 0;
+ unsigned int gcfg2 = 0;
switch (config) {
case 1:
- gcfg1 |= DOVE_TWSI_ENABLE_OPTION1;
+ gcfg1 = TWSI_ENABLE_OPTION1;
break;
case 2:
- gcfg2 |= DOVE_TWSI_ENABLE_OPTION2;
+ gcfg2 = TWSI_ENABLE_OPTION2;
break;
case 3:
- gcfg2 |= DOVE_TWSI_ENABLE_OPTION3;
+ gcfg2 = TWSI_ENABLE_OPTION3;
break;
}
- writel(gcfg1, DOVE_GLOBAL_CONFIG_1);
- writel(gcfg2, DOVE_GLOBAL_CONFIG_2);
+ regmap_update_bits(gconfmap, GLOBAL_CONFIG_1,
+ TWSI_ENABLE_OPTION1,
+ gcfg1);
+ regmap_update_bits(gconfmap, GLOBAL_CONFIG_2,
+ TWSI_ENABLE_OPTION2 | TWSI_ENABLE_OPTION3,
+ gcfg2);
return 0;
}
static struct mvebu_mpp_ctrl dove_mpp_controls[] = {
- MPP_FUNC_CTRL(0, 0, "mpp0", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(1, 1, "mpp1", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(2, 2, "mpp2", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(3, 3, "mpp3", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(4, 4, "mpp4", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(5, 5, "mpp5", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(6, 6, "mpp6", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(7, 7, "mpp7", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(8, 8, "mpp8", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(9, 9, "mpp9", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(10, 10, "mpp10", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(11, 11, "mpp11", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(12, 12, "mpp12", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(13, 13, "mpp13", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(14, 14, "mpp14", dove_pmu_mpp_ctrl),
- MPP_FUNC_CTRL(15, 15, "mpp15", dove_pmu_mpp_ctrl),
- MPP_REG_CTRL(16, 23),
+ MPP_FUNC_CTRL(0, 15, NULL, dove_pmu_mpp_ctrl),
+ MPP_FUNC_CTRL(16, 23, NULL, dove_mpp_ctrl),
MPP_FUNC_CTRL(24, 39, "mpp_camera", dove_mpp4_ctrl),
MPP_FUNC_CTRL(40, 45, "mpp_sdio0", dove_mpp4_ctrl),
MPP_FUNC_CTRL(46, 51, "mpp_sdio1", dove_mpp4_ctrl),
@@ -772,8 +756,17 @@ static struct of_device_id dove_pinctrl_of_match[] = {
{ }
};
+static struct regmap_config gc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 5,
+};
+
static int dove_pinctrl_probe(struct platform_device *pdev)
{
+ struct resource *res, *mpp_res;
+ struct resource fb_res;
const struct of_device_id *match =
of_match_device(dove_pinctrl_of_match, &pdev->dev);
pdev->dev.platform_data = (void *)match->data;
@@ -789,6 +782,59 @@ static int dove_pinctrl_probe(struct platform_device *pdev)
}
clk_prepare_enable(clk);
+ mpp_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mpp_base = devm_ioremap_resource(&pdev->dev, mpp_res);
+ if (IS_ERR(mpp_base))
+ return PTR_ERR(mpp_base);
+
+ /* prepare fallback resource */
+ memcpy(&fb_res, mpp_res, sizeof(struct resource));
+ fb_res.start = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_warn(&pdev->dev, "falling back to hardcoded MPP4 resource\n");
+ adjust_resource(&fb_res,
+ (mpp_res->start & INT_REGS_MASK) + MPP4_REGS_OFFS, 0x4);
+ res = &fb_res;
+ }
+
+ mpp4_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mpp4_base))
+ return PTR_ERR(mpp4_base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (!res) {
+ dev_warn(&pdev->dev, "falling back to hardcoded PMU resource\n");
+ adjust_resource(&fb_res,
+ (mpp_res->start & INT_REGS_MASK) + PMU_REGS_OFFS, 0x8);
+ res = &fb_res;
+ }
+
+ pmu_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pmu_base))
+ return PTR_ERR(pmu_base);
+
+ gconfmap = syscon_regmap_lookup_by_compatible("marvell,dove-global-config");
+ if (IS_ERR(gconfmap)) {
+ void __iomem *gc_base;
+
+ dev_warn(&pdev->dev, "falling back to hardcoded global registers\n");
+ adjust_resource(&fb_res,
+ (mpp_res->start & INT_REGS_MASK) + GC_REGS_OFFS, 0x14);
+ gc_base = devm_ioremap_resource(&pdev->dev, &fb_res);
+ if (IS_ERR(gc_base))
+ return PTR_ERR(gc_base);
+ gconfmap = devm_regmap_init_mmio(&pdev->dev,
+ gc_base, &gc_regmap_config);
+ if (IS_ERR(gconfmap))
+ return PTR_ERR(gconfmap);
+ }
+
+ /* Warn on any missing DT resource */
+ if (fb_res.start)
+ dev_warn(&pdev->dev, FW_BUG "Missing pinctrl regs in DTB. Please update your firmware.\n");
+
return mvebu_pinctrl_probe(pdev);
}
diff --git a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c
index 6b504b5935a5..0d0211a1a0b0 100644
--- a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c
+++ b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c
@@ -21,6 +21,18 @@
#include "pinctrl-mvebu.h"
+static void __iomem *mpp_base;
+
+static int kirkwood_mpp_ctrl_get(unsigned pid, unsigned long *config)
+{
+ return default_mpp_ctrl_get(mpp_base, pid, config);
+}
+
+static int kirkwood_mpp_ctrl_set(unsigned pid, unsigned long config)
+{
+ return default_mpp_ctrl_set(mpp_base, pid, config);
+}
+
#define V(f6180, f6190, f6192, f6281, f6282, dx4122) \
((f6180 << 0) | (f6190 << 1) | (f6192 << 2) | \
(f6281 << 3) | (f6282 << 4) | (dx4122 << 5))
@@ -359,7 +371,7 @@ static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
};
static struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = {
- MPP_REG_CTRL(0, 29),
+ MPP_FUNC_CTRL(0, 29, NULL, kirkwood_mpp_ctrl),
};
static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = {
@@ -367,7 +379,7 @@ static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = {
};
static struct mvebu_mpp_ctrl mv88f619x_mpp_controls[] = {
- MPP_REG_CTRL(0, 35),
+ MPP_FUNC_CTRL(0, 35, NULL, kirkwood_mpp_ctrl),
};
static struct pinctrl_gpio_range mv88f619x_gpio_ranges[] = {
@@ -376,7 +388,7 @@ static struct pinctrl_gpio_range mv88f619x_gpio_ranges[] = {
};
static struct mvebu_mpp_ctrl mv88f628x_mpp_controls[] = {
- MPP_REG_CTRL(0, 49),
+ MPP_FUNC_CTRL(0, 49, NULL, kirkwood_mpp_ctrl),
};
static struct pinctrl_gpio_range mv88f628x_gpio_ranges[] = {
@@ -456,9 +468,16 @@ static struct of_device_id kirkwood_pinctrl_of_match[] = {
static int kirkwood_pinctrl_probe(struct platform_device *pdev)
{
+ struct resource *res;
const struct of_device_id *match =
of_match_device(kirkwood_pinctrl_of_match, &pdev->dev);
pdev->dev.platform_data = (void *)match->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mpp_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mpp_base))
+ return PTR_ERR(mpp_base);
+
return mvebu_pinctrl_probe(pdev);
}
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
index 0fd1ad31fbf9..9908374f8f92 100644
--- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -50,7 +50,6 @@ struct mvebu_pinctrl {
struct device *dev;
struct pinctrl_dev *pctldev;
struct pinctrl_desc desc;
- void __iomem *base;
struct mvebu_pinctrl_group *groups;
unsigned num_groups;
struct mvebu_pinctrl_function *functions;
@@ -138,43 +137,6 @@ static struct mvebu_pinctrl_function *mvebu_pinctrl_find_function_by_name(
return NULL;
}
-/*
- * Common mpp pin configuration registers on MVEBU are
- * registers of eight 4-bit values for each mpp setting.
- * Register offset and bit mask are calculated accordingly below.
- */
-static int mvebu_common_mpp_get(struct mvebu_pinctrl *pctl,
- struct mvebu_pinctrl_group *grp,
- unsigned long *config)
-{
- unsigned pin = grp->gid;
- unsigned off = (pin / MPPS_PER_REG) * MPP_BITS;
- unsigned shift = (pin % MPPS_PER_REG) * MPP_BITS;
-
- *config = readl(pctl->base + off);
- *config >>= shift;
- *config &= MPP_MASK;
-
- return 0;
-}
-
-static int mvebu_common_mpp_set(struct mvebu_pinctrl *pctl,
- struct mvebu_pinctrl_group *grp,
- unsigned long config)
-{
- unsigned pin = grp->gid;
- unsigned off = (pin / MPPS_PER_REG) * MPP_BITS;
- unsigned shift = (pin % MPPS_PER_REG) * MPP_BITS;
- unsigned long reg;
-
- reg = readl(pctl->base + off);
- reg &= ~(MPP_MASK << shift);
- reg |= (config << shift);
- writel(reg, pctl->base + off);
-
- return 0;
-}
-
static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev,
unsigned gid, unsigned long *config)
{
@@ -184,10 +146,7 @@ static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev,
if (!grp->ctrl)
return -EINVAL;
- if (grp->ctrl->mpp_get)
- return grp->ctrl->mpp_get(grp->ctrl, config);
-
- return mvebu_common_mpp_get(pctl, grp, config);
+ return grp->ctrl->mpp_get(grp->pins[0], config);
}
static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev,
@@ -202,11 +161,7 @@ static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev,
return -EINVAL;
for (i = 0; i < num_configs; i++) {
- if (grp->ctrl->mpp_set)
- ret = grp->ctrl->mpp_set(grp->ctrl, configs[i]);
- else
- ret = mvebu_common_mpp_set(pctl, grp, configs[i]);
-
+ ret = grp->ctrl->mpp_set(grp->pins[0], configs[i]);
if (ret)
return ret;
} /* for each config */
@@ -347,7 +302,7 @@ static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
return -EINVAL;
if (grp->ctrl->mpp_gpio_req)
- return grp->ctrl->mpp_gpio_req(grp->ctrl, offset);
+ return grp->ctrl->mpp_gpio_req(offset);
setting = mvebu_pinctrl_find_gpio_setting(pctl, grp);
if (!setting)
@@ -370,7 +325,7 @@ static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
return -EINVAL;
if (grp->ctrl->mpp_gpio_dir)
- return grp->ctrl->mpp_gpio_dir(grp->ctrl, offset, input);
+ return grp->ctrl->mpp_gpio_dir(offset, input);
setting = mvebu_pinctrl_find_gpio_setting(pctl, grp);
if (!setting)
@@ -593,11 +548,12 @@ static int mvebu_pinctrl_build_functions(struct platform_device *pdev,
int mvebu_pinctrl_probe(struct platform_device *pdev)
{
struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev);
- struct resource *res;
struct mvebu_pinctrl *pctl;
- void __iomem *base;
struct pinctrl_pin_desc *pdesc;
unsigned gid, n, k;
+ unsigned size, noname = 0;
+ char *noname_buf;
+ void *p;
int ret;
if (!soc || !soc->controls || !soc->modes) {
@@ -605,11 +561,6 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
return -EINVAL;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
pctl = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pinctrl),
GFP_KERNEL);
if (!pctl) {
@@ -623,7 +574,6 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
pctl->desc.pmxops = &mvebu_pinmux_ops;
pctl->desc.confops = &mvebu_pinconf_ops;
pctl->variant = soc->variant;
- pctl->base = base;
pctl->dev = &pdev->dev;
platform_set_drvdata(pdev, pctl);
@@ -633,33 +583,23 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
pctl->desc.npins = 0;
for (n = 0; n < soc->ncontrols; n++) {
struct mvebu_mpp_ctrl *ctrl = &soc->controls[n];
- char *names;
pctl->desc.npins += ctrl->npins;
- /* initial control pins */
+ /* initialize control's pins[] array */
for (k = 0; k < ctrl->npins; k++)
ctrl->pins[k] = ctrl->pid + k;
- /* special soc specific control */
- if (ctrl->mpp_get || ctrl->mpp_set) {
- if (!ctrl->name || !ctrl->mpp_get || !ctrl->mpp_set) {
- dev_err(&pdev->dev, "wrong soc control info\n");
- return -EINVAL;
- }
+ /*
+ * We allow to pass controls with NULL name that we treat
+ * as a range of one-pin groups with generic mvebu register
+ * controls.
+ */
+ if (!ctrl->name) {
+ pctl->num_groups += ctrl->npins;
+ noname += ctrl->npins;
+ } else {
pctl->num_groups += 1;
- continue;
}
-
- /* generic mvebu register control */
- names = devm_kzalloc(&pdev->dev, ctrl->npins * 8, GFP_KERNEL);
- if (!names) {
- dev_err(&pdev->dev, "failed to alloc mpp names\n");
- return -ENOMEM;
- }
- for (k = 0; k < ctrl->npins; k++)
- sprintf(names + 8*k, "mpp%d", ctrl->pid+k);
- ctrl->name = names;
- pctl->num_groups += ctrl->npins;
}
pdesc = devm_kzalloc(&pdev->dev, pctl->desc.npins *
@@ -673,12 +613,17 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
pdesc[n].number = n;
pctl->desc.pins = pdesc;
- pctl->groups = devm_kzalloc(&pdev->dev, pctl->num_groups *
- sizeof(struct mvebu_pinctrl_group), GFP_KERNEL);
- if (!pctl->groups) {
- dev_err(&pdev->dev, "failed to alloc pinctrl groups\n");
+ /*
+ * allocate groups and name buffers for unnamed groups.
+ */
+ size = pctl->num_groups * sizeof(*pctl->groups) + noname * 8;
+ p = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ if (!p) {
+ dev_err(&pdev->dev, "failed to alloc group data\n");
return -ENOMEM;
}
+ pctl->groups = p;
+ noname_buf = p + pctl->num_groups * sizeof(*pctl->groups);
/* assign mpp controls to groups */
gid = 0;
@@ -690,17 +635,26 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
pctl->groups[gid].pins = ctrl->pins;
pctl->groups[gid].npins = ctrl->npins;
- /* generic mvebu register control maps to a number of groups */
- if (!ctrl->mpp_get && !ctrl->mpp_set) {
+ /*
+ * We treat unnamed controls as a range of one-pin groups
+ * with generic mvebu register controls. Use one group for
+ * each in this range and assign a default group name.
+ */
+ if (!ctrl->name) {
+ pctl->groups[gid].name = noname_buf;
pctl->groups[gid].npins = 1;
+ sprintf(noname_buf, "mpp%d", ctrl->pid+0);
+ noname_buf += 8;
for (k = 1; k < ctrl->npins; k++) {
gid++;
pctl->groups[gid].gid = gid;
pctl->groups[gid].ctrl = ctrl;
- pctl->groups[gid].name = &ctrl->name[8*k];
+ pctl->groups[gid].name = noname_buf;
pctl->groups[gid].pins = &ctrl->pins[k];
pctl->groups[gid].npins = 1;
+ sprintf(noname_buf, "mpp%d", ctrl->pid+k);
+ noname_buf += 8;
}
}
gid++;
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.h b/drivers/pinctrl/mvebu/pinctrl-mvebu.h
index 90bd3beee860..65a98e6f7265 100644
--- a/drivers/pinctrl/mvebu/pinctrl-mvebu.h
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.h
@@ -28,20 +28,19 @@
* between two or more different settings, e.g. assign mpp pin 13 to
* uart1 or sata.
*
- * If optional mpp_get/_set functions are set these are used to get/set
- * a specific mode. Otherwise it is assumed that the mpp control is based
- * on 4-bit groups in subsequent registers. The optional mpp_gpio_req/_dir
- * functions can be used to allow pin settings with varying gpio pins.
+ * The mpp_get/_set functions are mandatory and are used to get/set a
+ * specific mode. The optional mpp_gpio_req/_dir functions can be used
+ * to allow pin settings with varying gpio pins.
*/
struct mvebu_mpp_ctrl {
const char *name;
u8 pid;
u8 npins;
unsigned *pins;
- int (*mpp_get)(struct mvebu_mpp_ctrl *ctrl, unsigned long *config);
- int (*mpp_set)(struct mvebu_mpp_ctrl *ctrl, unsigned long config);
- int (*mpp_gpio_req)(struct mvebu_mpp_ctrl *ctrl, u8 pid);
- int (*mpp_gpio_dir)(struct mvebu_mpp_ctrl *ctrl, u8 pid, bool input);
+ int (*mpp_get)(unsigned pid, unsigned long *config);
+ int (*mpp_set)(unsigned pid, unsigned long config);
+ int (*mpp_gpio_req)(unsigned pid);
+ int (*mpp_gpio_dir)(unsigned pid, bool input);
};
/**
@@ -114,18 +113,6 @@ struct mvebu_pinctrl_soc_info {
int ngpioranges;
};
-#define MPP_REG_CTRL(_idl, _idh) \
- { \
- .name = NULL, \
- .pid = _idl, \
- .npins = _idh - _idl + 1, \
- .pins = (unsigned[_idh - _idl + 1]) { }, \
- .mpp_get = NULL, \
- .mpp_set = NULL, \
- .mpp_gpio_req = NULL, \
- .mpp_gpio_dir = NULL, \
- }
-
#define MPP_FUNC_CTRL(_idl, _idh, _name, _func) \
{ \
.name = _name, \
@@ -186,6 +173,34 @@ struct mvebu_pinctrl_soc_info {
.npins = _npins, \
}
+#define MVEBU_MPPS_PER_REG 8
+#define MVEBU_MPP_BITS 4
+#define MVEBU_MPP_MASK 0xf
+
+static inline int default_mpp_ctrl_get(void __iomem *base, unsigned int pid,
+ unsigned long *config)
+{
+ unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+
+ *config = (readl(base + off) >> shift) & MVEBU_MPP_MASK;
+
+ return 0;
+}
+
+static inline int default_mpp_ctrl_set(void __iomem *base, unsigned int pid,
+ unsigned long config)
+{
+ unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned long reg;
+
+ reg = readl(base + off) & ~(MVEBU_MPP_MASK << shift);
+ writel(reg | (config << shift), base + off);
+
+ return 0;
+}
+
int mvebu_pinctrl_probe(struct platform_device *pdev);
int mvebu_pinctrl_remove(struct platform_device *pdev);
diff --git a/drivers/pinctrl/pinctrl-adi2-bf54x.c b/drivers/pinctrl/pinctrl-adi2-bf54x.c
index ea9d9ab9cda1..008a29e92e56 100644
--- a/drivers/pinctrl/pinctrl-adi2-bf54x.c
+++ b/drivers/pinctrl/pinctrl-adi2-bf54x.c
@@ -309,39 +309,6 @@ static const unsigned keys_8x8_pins[] = {
GPIO_PE4, GPIO_PE5, GPIO_PE6, GPIO_PE7,
};
-static const struct adi_pin_group adi_pin_groups[] = {
- ADI_PIN_GROUP("uart0grp", uart0_pins),
- ADI_PIN_GROUP("uart1grp", uart1_pins),
- ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins),
- ADI_PIN_GROUP("uart2grp", uart2_pins),
- ADI_PIN_GROUP("uart3grp", uart3_pins),
- ADI_PIN_GROUP("uart3ctsrtsgrp", uart3_ctsrts_pins),
- ADI_PIN_GROUP("rsi0grp", rsi0_pins),
- ADI_PIN_GROUP("spi0grp", spi0_pins),
- ADI_PIN_GROUP("spi1grp", spi1_pins),
- ADI_PIN_GROUP("twi0grp", twi0_pins),
- ADI_PIN_GROUP("twi1grp", twi1_pins),
- ADI_PIN_GROUP("rotarygrp", rotary_pins),
- ADI_PIN_GROUP("can0grp", can0_pins),
- ADI_PIN_GROUP("can1grp", can1_pins),
- ADI_PIN_GROUP("smc0grp", smc0_pins),
- ADI_PIN_GROUP("sport0grp", sport0_pins),
- ADI_PIN_GROUP("sport1grp", sport1_pins),
- ADI_PIN_GROUP("sport2grp", sport2_pins),
- ADI_PIN_GROUP("sport3grp", sport3_pins),
- ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins),
- ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins),
- ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins),
- ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins),
- ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins),
- ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins),
- ADI_PIN_GROUP("atapigrp", atapi_pins),
- ADI_PIN_GROUP("atapialtergrp", atapi_alter_pins),
- ADI_PIN_GROUP("nfc0grp", nfc0_pins),
- ADI_PIN_GROUP("keys_4x4grp", keys_4x4_pins),
- ADI_PIN_GROUP("keys_8x8grp", keys_8x8_pins),
-};
-
static const unsigned short uart0_mux[] = {
P_UART0_TX, P_UART0_RX,
0
@@ -513,6 +480,39 @@ static const unsigned short keys_8x8_mux[] = {
0
};
+static const struct adi_pin_group adi_pin_groups[] = {
+ ADI_PIN_GROUP("uart0grp", uart0_pins, uart0_mux),
+ ADI_PIN_GROUP("uart1grp", uart1_pins, uart1_mux),
+ ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins, uart1_ctsrts_mux),
+ ADI_PIN_GROUP("uart2grp", uart2_pins, uart2_mux),
+ ADI_PIN_GROUP("uart3grp", uart3_pins, uart3_mux),
+ ADI_PIN_GROUP("uart3ctsrtsgrp", uart3_ctsrts_pins, uart3_ctsrts_mux),
+ ADI_PIN_GROUP("rsi0grp", rsi0_pins, rsi0_mux),
+ ADI_PIN_GROUP("spi0grp", spi0_pins, spi0_mux),
+ ADI_PIN_GROUP("spi1grp", spi1_pins, spi1_mux),
+ ADI_PIN_GROUP("twi0grp", twi0_pins, twi0_mux),
+ ADI_PIN_GROUP("twi1grp", twi1_pins, twi1_mux),
+ ADI_PIN_GROUP("rotarygrp", rotary_pins, rotary_mux),
+ ADI_PIN_GROUP("can0grp", can0_pins, can0_mux),
+ ADI_PIN_GROUP("can1grp", can1_pins, can1_mux),
+ ADI_PIN_GROUP("smc0grp", smc0_pins, smc0_mux),
+ ADI_PIN_GROUP("sport0grp", sport0_pins, sport0_mux),
+ ADI_PIN_GROUP("sport1grp", sport1_pins, sport1_mux),
+ ADI_PIN_GROUP("sport2grp", sport2_pins, sport2_mux),
+ ADI_PIN_GROUP("sport3grp", sport3_pins, sport3_mux),
+ ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins, ppi0_8b_mux),
+ ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins, ppi0_16b_mux),
+ ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins, ppi0_24b_mux),
+ ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins, ppi1_8b_mux),
+ ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins, ppi1_16b_mux),
+ ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins, ppi2_8b_mux),
+ ADI_PIN_GROUP("atapigrp", atapi_pins, atapi_mux),
+ ADI_PIN_GROUP("atapialtergrp", atapi_alter_pins, atapi_alter_mux),
+ ADI_PIN_GROUP("nfc0grp", nfc0_pins, nfc0_mux),
+ ADI_PIN_GROUP("keys_4x4grp", keys_4x4_pins, keys_4x4_mux),
+ ADI_PIN_GROUP("keys_8x8grp", keys_8x8_pins, keys_8x8_mux),
+};
+
static const char * const uart0grp[] = { "uart0grp" };
static const char * const uart1grp[] = { "uart1grp" };
static const char * const uart1ctsrtsgrp[] = { "uart1ctsrtsgrp" };
@@ -532,49 +532,45 @@ static const char * const sport0grp[] = { "sport0grp" };
static const char * const sport1grp[] = { "sport1grp" };
static const char * const sport2grp[] = { "sport2grp" };
static const char * const sport3grp[] = { "sport3grp" };
-static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" };
-static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" };
-static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" };
-static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" };
-static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" };
-static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" };
+static const char * const ppi0grp[] = { "ppi0_8bgrp",
+ "ppi0_16bgrp",
+ "ppi0_24bgrp" };
+static const char * const ppi1grp[] = { "ppi1_8bgrp",
+ "ppi1_16bgrp" };
+static const char * const ppi2grp[] = { "ppi2_8bgrp" };
static const char * const atapigrp[] = { "atapigrp" };
static const char * const atapialtergrp[] = { "atapialtergrp" };
static const char * const nfc0grp[] = { "nfc0grp" };
-static const char * const keys_4x4grp[] = { "keys_4x4grp" };
-static const char * const keys_8x8grp[] = { "keys_8x8grp" };
+static const char * const keysgrp[] = { "keys_4x4grp",
+ "keys_8x8grp" };
static const struct adi_pmx_func adi_pmx_functions[] = {
- ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux),
- ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux),
- ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp, uart1_ctsrts_mux),
- ADI_PMX_FUNCTION("uart2", uart2grp, uart2_mux),
- ADI_PMX_FUNCTION("uart3", uart3grp, uart3_mux),
- ADI_PMX_FUNCTION("uart3_ctsrts", uart3ctsrtsgrp, uart3_ctsrts_mux),
- ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux),
- ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux),
- ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux),
- ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux),
- ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux),
- ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux),
- ADI_PMX_FUNCTION("can0", can0grp, can0_mux),
- ADI_PMX_FUNCTION("can1", can1grp, can1_mux),
- ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux),
- ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux),
- ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux),
- ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux),
- ADI_PMX_FUNCTION("sport3", sport3grp, sport3_mux),
- ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux),
- ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux),
- ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux),
- ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux),
- ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux),
- ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux),
- ADI_PMX_FUNCTION("atapi", atapigrp, atapi_mux),
- ADI_PMX_FUNCTION("atapi_alter", atapialtergrp, atapi_alter_mux),
- ADI_PMX_FUNCTION("nfc0", nfc0grp, nfc0_mux),
- ADI_PMX_FUNCTION("keys_4x4", keys_4x4grp, keys_4x4_mux),
- ADI_PMX_FUNCTION("keys_8x8", keys_8x8grp, keys_8x8_mux),
+ ADI_PMX_FUNCTION("uart0", uart0grp),
+ ADI_PMX_FUNCTION("uart1", uart1grp),
+ ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp),
+ ADI_PMX_FUNCTION("uart2", uart2grp),
+ ADI_PMX_FUNCTION("uart3", uart3grp),
+ ADI_PMX_FUNCTION("uart3_ctsrts", uart3ctsrtsgrp),
+ ADI_PMX_FUNCTION("rsi0", rsi0grp),
+ ADI_PMX_FUNCTION("spi0", spi0grp),
+ ADI_PMX_FUNCTION("spi1", spi1grp),
+ ADI_PMX_FUNCTION("twi0", twi0grp),
+ ADI_PMX_FUNCTION("twi1", twi1grp),
+ ADI_PMX_FUNCTION("rotary", rotarygrp),
+ ADI_PMX_FUNCTION("can0", can0grp),
+ ADI_PMX_FUNCTION("can1", can1grp),
+ ADI_PMX_FUNCTION("smc0", smc0grp),
+ ADI_PMX_FUNCTION("sport0", sport0grp),
+ ADI_PMX_FUNCTION("sport1", sport1grp),
+ ADI_PMX_FUNCTION("sport2", sport2grp),
+ ADI_PMX_FUNCTION("sport3", sport3grp),
+ ADI_PMX_FUNCTION("ppi0", ppi0grp),
+ ADI_PMX_FUNCTION("ppi1", ppi1grp),
+ ADI_PMX_FUNCTION("ppi2", ppi2grp),
+ ADI_PMX_FUNCTION("atapi", atapigrp),
+ ADI_PMX_FUNCTION("atapi_alter", atapialtergrp),
+ ADI_PMX_FUNCTION("nfc0", nfc0grp),
+ ADI_PMX_FUNCTION("keys", keysgrp),
};
static const struct adi_pinctrl_soc_data adi_bf54x_soc = {
diff --git a/drivers/pinctrl/pinctrl-adi2-bf60x.c b/drivers/pinctrl/pinctrl-adi2-bf60x.c
index bf57aea2826c..4cb59fe9be70 100644
--- a/drivers/pinctrl/pinctrl-adi2-bf60x.c
+++ b/drivers/pinctrl/pinctrl-adi2-bf60x.c
@@ -259,37 +259,6 @@ static const unsigned lp3_pins[] = {
GPIO_PF12, GPIO_PF13, GPIO_PF14, GPIO_PF15,
};
-static const struct adi_pin_group adi_pin_groups[] = {
- ADI_PIN_GROUP("uart0grp", uart0_pins),
- ADI_PIN_GROUP("uart0ctsrtsgrp", uart0_ctsrts_pins),
- ADI_PIN_GROUP("uart1grp", uart1_pins),
- ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins),
- ADI_PIN_GROUP("rsi0grp", rsi0_pins),
- ADI_PIN_GROUP("eth0grp", eth0_pins),
- ADI_PIN_GROUP("eth1grp", eth1_pins),
- ADI_PIN_GROUP("spi0grp", spi0_pins),
- ADI_PIN_GROUP("spi1grp", spi1_pins),
- ADI_PIN_GROUP("twi0grp", twi0_pins),
- ADI_PIN_GROUP("twi1grp", twi1_pins),
- ADI_PIN_GROUP("rotarygrp", rotary_pins),
- ADI_PIN_GROUP("can0grp", can0_pins),
- ADI_PIN_GROUP("smc0grp", smc0_pins),
- ADI_PIN_GROUP("sport0grp", sport0_pins),
- ADI_PIN_GROUP("sport1grp", sport1_pins),
- ADI_PIN_GROUP("sport2grp", sport2_pins),
- ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins),
- ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins),
- ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins),
- ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins),
- ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins),
- ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins),
- ADI_PIN_GROUP("ppi2_16bgrp", ppi2_16b_pins),
- ADI_PIN_GROUP("lp0grp", lp0_pins),
- ADI_PIN_GROUP("lp1grp", lp1_pins),
- ADI_PIN_GROUP("lp2grp", lp2_pins),
- ADI_PIN_GROUP("lp3grp", lp3_pins),
-};
-
static const unsigned short uart0_mux[] = {
P_UART0_TX, P_UART0_RX,
0
@@ -446,6 +415,37 @@ static const unsigned short lp3_mux[] = {
0
};
+static const struct adi_pin_group adi_pin_groups[] = {
+ ADI_PIN_GROUP("uart0grp", uart0_pins, uart0_mux),
+ ADI_PIN_GROUP("uart0ctsrtsgrp", uart0_ctsrts_pins, uart0_ctsrts_mux),
+ ADI_PIN_GROUP("uart1grp", uart1_pins, uart1_mux),
+ ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins, uart1_ctsrts_mux),
+ ADI_PIN_GROUP("rsi0grp", rsi0_pins, rsi0_mux),
+ ADI_PIN_GROUP("eth0grp", eth0_pins, eth0_mux),
+ ADI_PIN_GROUP("eth1grp", eth1_pins, eth1_mux),
+ ADI_PIN_GROUP("spi0grp", spi0_pins, spi0_mux),
+ ADI_PIN_GROUP("spi1grp", spi1_pins, spi1_mux),
+ ADI_PIN_GROUP("twi0grp", twi0_pins, twi0_mux),
+ ADI_PIN_GROUP("twi1grp", twi1_pins, twi1_mux),
+ ADI_PIN_GROUP("rotarygrp", rotary_pins, rotary_mux),
+ ADI_PIN_GROUP("can0grp", can0_pins, can0_mux),
+ ADI_PIN_GROUP("smc0grp", smc0_pins, smc0_mux),
+ ADI_PIN_GROUP("sport0grp", sport0_pins, sport0_mux),
+ ADI_PIN_GROUP("sport1grp", sport1_pins, sport1_mux),
+ ADI_PIN_GROUP("sport2grp", sport2_pins, sport2_mux),
+ ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins, ppi0_8b_mux),
+ ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins, ppi0_16b_mux),
+ ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins, ppi0_24b_mux),
+ ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins, ppi1_8b_mux),
+ ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins, ppi1_16b_mux),
+ ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins, ppi2_8b_mux),
+ ADI_PIN_GROUP("ppi2_16bgrp", ppi2_16b_pins, ppi2_16b_mux),
+ ADI_PIN_GROUP("lp0grp", lp0_pins, lp0_mux),
+ ADI_PIN_GROUP("lp1grp", lp1_pins, lp1_mux),
+ ADI_PIN_GROUP("lp2grp", lp2_pins, lp2_mux),
+ ADI_PIN_GROUP("lp3grp", lp3_pins, lp3_mux),
+};
+
static const char * const uart0grp[] = { "uart0grp" };
static const char * const uart0ctsrtsgrp[] = { "uart0ctsrtsgrp" };
static const char * const uart1grp[] = { "uart1grp" };
@@ -463,47 +463,43 @@ static const char * const smc0grp[] = { "smc0grp" };
static const char * const sport0grp[] = { "sport0grp" };
static const char * const sport1grp[] = { "sport1grp" };
static const char * const sport2grp[] = { "sport2grp" };
-static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" };
-static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" };
-static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" };
-static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" };
-static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" };
-static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" };
-static const char * const ppi2_16bgrp[] = { "ppi2_16bgrp" };
+static const char * const ppi0grp[] = { "ppi0_8bgrp",
+ "ppi0_16bgrp",
+ "ppi0_24bgrp" };
+static const char * const ppi1grp[] = { "ppi1_8bgrp",
+ "ppi1_16bgrp" };
+static const char * const ppi2grp[] = { "ppi2_8bgrp",
+ "ppi2_16bgrp" };
static const char * const lp0grp[] = { "lp0grp" };
static const char * const lp1grp[] = { "lp1grp" };
static const char * const lp2grp[] = { "lp2grp" };
static const char * const lp3grp[] = { "lp3grp" };
static const struct adi_pmx_func adi_pmx_functions[] = {
- ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux),
- ADI_PMX_FUNCTION("uart0_ctsrts", uart0ctsrtsgrp, uart0_ctsrts_mux),
- ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux),
- ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp, uart1_ctsrts_mux),
- ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux),
- ADI_PMX_FUNCTION("eth0", eth0grp, eth0_mux),
- ADI_PMX_FUNCTION("eth1", eth1grp, eth1_mux),
- ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux),
- ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux),
- ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux),
- ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux),
- ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux),
- ADI_PMX_FUNCTION("can0", can0grp, can0_mux),
- ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux),
- ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux),
- ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux),
- ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux),
- ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux),
- ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux),
- ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux),
- ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux),
- ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux),
- ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux),
- ADI_PMX_FUNCTION("ppi2_16b", ppi2_16bgrp, ppi2_16b_mux),
- ADI_PMX_FUNCTION("lp0", lp0grp, lp0_mux),
- ADI_PMX_FUNCTION("lp1", lp1grp, lp1_mux),
- ADI_PMX_FUNCTION("lp2", lp2grp, lp2_mux),
- ADI_PMX_FUNCTION("lp3", lp3grp, lp3_mux),
+ ADI_PMX_FUNCTION("uart0", uart0grp),
+ ADI_PMX_FUNCTION("uart0_ctsrts", uart0ctsrtsgrp),
+ ADI_PMX_FUNCTION("uart1", uart1grp),
+ ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp),
+ ADI_PMX_FUNCTION("rsi0", rsi0grp),
+ ADI_PMX_FUNCTION("eth0", eth0grp),
+ ADI_PMX_FUNCTION("eth1", eth1grp),
+ ADI_PMX_FUNCTION("spi0", spi0grp),
+ ADI_PMX_FUNCTION("spi1", spi1grp),
+ ADI_PMX_FUNCTION("twi0", twi0grp),
+ ADI_PMX_FUNCTION("twi1", twi1grp),
+ ADI_PMX_FUNCTION("rotary", rotarygrp),
+ ADI_PMX_FUNCTION("can0", can0grp),
+ ADI_PMX_FUNCTION("smc0", smc0grp),
+ ADI_PMX_FUNCTION("sport0", sport0grp),
+ ADI_PMX_FUNCTION("sport1", sport1grp),
+ ADI_PMX_FUNCTION("sport2", sport2grp),
+ ADI_PMX_FUNCTION("ppi0", ppi0grp),
+ ADI_PMX_FUNCTION("ppi1", ppi1grp),
+ ADI_PMX_FUNCTION("ppi2", ppi2grp),
+ ADI_PMX_FUNCTION("lp0", lp0grp),
+ ADI_PMX_FUNCTION("lp1", lp1grp),
+ ADI_PMX_FUNCTION("lp2", lp2grp),
+ ADI_PMX_FUNCTION("lp3", lp3grp),
};
static const struct adi_pinctrl_soc_data adi_bf60x_soc = {
diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c
index 7a39562c3e42..200ea1e72d40 100644
--- a/drivers/pinctrl/pinctrl-adi2.c
+++ b/drivers/pinctrl/pinctrl-adi2.c
@@ -89,6 +89,19 @@ struct gpio_port_saved {
u32 mux;
};
+/*
+ * struct gpio_pint_saved - PINT registers saved in PM operations
+ *
+ * @assign: ASSIGN register
+ * @edge_set: EDGE_SET register
+ * @invert_set: INVERT_SET register
+ */
+struct gpio_pint_saved {
+ u32 assign;
+ u32 edge_set;
+ u32 invert_set;
+};
+
/**
* struct gpio_pint - Pin interrupt controller device. Multiple ADI GPIO
* banks can be mapped into one Pin interrupt controller.
@@ -114,7 +127,7 @@ struct gpio_pint {
int irq;
struct irq_domain *domain[2];
struct gpio_pint_regs *regs;
- struct adi_pm_pint_save saved_data;
+ struct gpio_pint_saved saved_data;
int map_count;
spinlock_t lock;
@@ -160,7 +173,7 @@ struct adi_pinctrl {
struct gpio_port {
struct list_head node;
void __iomem *base;
- unsigned int irq_base;
+ int irq_base;
unsigned int width;
struct gpio_port_t *regs;
struct gpio_port_saved saved_data;
@@ -605,8 +618,8 @@ static struct pinctrl_ops adi_pctrl_ops = {
.get_group_pins = adi_get_group_pins,
};
-static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
- unsigned group)
+static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned func_id,
+ unsigned group_id)
{
struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
struct gpio_port *port;
@@ -614,7 +627,7 @@ static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
unsigned long flags;
unsigned short *mux, pin;
- mux = (unsigned short *)pinctrl->soc->functions[selector].mux;
+ mux = (unsigned short *)pinctrl->soc->groups[group_id].mux;
while (*mux) {
pin = P_IDENT(*mux);
@@ -628,7 +641,7 @@ static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
spin_lock_irqsave(&port->lock, flags);
portmux_setup(port, pin_to_offset(range, pin),
- P_FUNCT2MUX(*mux));
+ P_FUNCT2MUX(*mux));
port_setup(port, pin_to_offset(range, pin), false);
mux++;
@@ -638,8 +651,8 @@ static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
return 0;
}
-static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector,
- unsigned group)
+static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned func_id,
+ unsigned group_id)
{
struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
struct gpio_port *port;
@@ -647,7 +660,7 @@ static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector,
unsigned long flags;
unsigned short *mux, pin;
- mux = (unsigned short *)pinctrl->soc->functions[selector].mux;
+ mux = (unsigned short *)pinctrl->soc->groups[group_id].mux;
while (*mux) {
pin = P_IDENT(*mux);
diff --git a/drivers/pinctrl/pinctrl-adi2.h b/drivers/pinctrl/pinctrl-adi2.h
index 1f06f8df1fa3..3ca29738213f 100644
--- a/drivers/pinctrl/pinctrl-adi2.h
+++ b/drivers/pinctrl/pinctrl-adi2.h
@@ -21,13 +21,15 @@ struct adi_pin_group {
const char *name;
const unsigned *pins;
const unsigned num;
+ const unsigned short *mux;
};
-#define ADI_PIN_GROUP(n, p) \
+#define ADI_PIN_GROUP(n, p, m) \
{ \
.name = n, \
.pins = p, \
.num = ARRAY_SIZE(p), \
+ .mux = m, \
}
/**
@@ -41,15 +43,13 @@ struct adi_pmx_func {
const char *name;
const char * const *groups;
const unsigned num_groups;
- const unsigned short *mux;
};
-#define ADI_PMX_FUNCTION(n, g, m) \
+#define ADI_PMX_FUNCTION(n, g) \
{ \
.name = n, \
.groups = g, \
.num_groups = ARRAY_SIZE(g), \
- .mux = m, \
}
/**
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index d990e33d8aa7..5d24aaec5dbc 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -1137,6 +1137,17 @@ static void at91_gpio_free(struct gpio_chip *chip, unsigned offset)
pinctrl_free_gpio(gpio);
}
+static int at91_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << offset;
+ u32 osr;
+
+ osr = readl_relaxed(pio + PIO_OSR);
+ return !(osr & mask);
+}
+
static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
@@ -1325,6 +1336,31 @@ static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
return 0;
}
+static unsigned int gpio_irq_startup(struct irq_data *d)
+{
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+ unsigned pin = d->hwirq;
+ int ret;
+
+ ret = gpio_lock_as_irq(&at91_gpio->chip, pin);
+ if (ret) {
+ dev_err(at91_gpio->chip.dev, "unable to lock pind %lu IRQ\n",
+ d->hwirq);
+ return ret;
+ }
+ gpio_irq_unmask(d);
+ return 0;
+}
+
+static void gpio_irq_shutdown(struct irq_data *d)
+{
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+ unsigned pin = d->hwirq;
+
+ gpio_irq_mask(d);
+ gpio_unlock_as_irq(&at91_gpio->chip, pin);
+}
+
#ifdef CONFIG_PM
static u32 wakeups[MAX_GPIO_BANKS];
@@ -1399,6 +1435,8 @@ void at91_pinctrl_gpio_resume(void)
static struct irq_chip gpio_irqchip = {
.name = "GPIO",
+ .irq_startup = gpio_irq_startup,
+ .irq_shutdown = gpio_irq_shutdown,
.irq_disable = gpio_irq_mask,
.irq_mask = gpio_irq_mask,
.irq_unmask = gpio_irq_unmask,
@@ -1543,6 +1581,7 @@ static int at91_gpio_of_irq_setup(struct device_node *node,
static struct gpio_chip at91_gpio_template = {
.request = at91_gpio_request,
.free = at91_gpio_free,
+ .get_direction = at91_gpio_get_direction,
.direction_input = at91_gpio_direction_input,
.get = at91_gpio_get,
.direction_output = at91_gpio_direction_output,
diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/pinctrl-baytrail.c
index 665b96bc0c3a..bf2b3f655469 100644
--- a/drivers/pinctrl/pinctrl-baytrail.c
+++ b/drivers/pinctrl/pinctrl-baytrail.c
@@ -60,6 +60,10 @@
#define BYT_NGPIO_NCORE 28
#define BYT_NGPIO_SUS 44
+#define BYT_SCORE_ACPI_UID "1"
+#define BYT_NCORE_ACPI_UID "2"
+#define BYT_SUS_ACPI_UID "3"
+
/*
* Baytrail gpio controller consist of three separate sub-controllers called
* SCORE, NCORE and SUS. The sub-controllers are identified by their acpi UID.
@@ -102,17 +106,17 @@ static unsigned const sus_pins[BYT_NGPIO_SUS] = {
static struct pinctrl_gpio_range byt_ranges[] = {
{
- .name = "1", /* match with acpi _UID in probe */
+ .name = BYT_SCORE_ACPI_UID, /* match with acpi _UID in probe */
.npins = BYT_NGPIO_SCORE,
.pins = score_pins,
},
{
- .name = "2",
+ .name = BYT_NCORE_ACPI_UID,
.npins = BYT_NGPIO_NCORE,
.pins = ncore_pins,
},
{
- .name = "3",
+ .name = BYT_SUS_ACPI_UID,
.npins = BYT_NGPIO_SUS,
.pins = sus_pins,
},
@@ -145,9 +149,41 @@ static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
return vg->reg_base + reg_offset + reg;
}
+static bool is_special_pin(struct byt_gpio *vg, unsigned offset)
+{
+ /* SCORE pin 92-93 */
+ if (!strcmp(vg->range->name, BYT_SCORE_ACPI_UID) &&
+ offset >= 92 && offset <= 93)
+ return true;
+
+ /* SUS pin 11-21 */
+ if (!strcmp(vg->range->name, BYT_SUS_ACPI_UID) &&
+ offset >= 11 && offset <= 21)
+ return true;
+
+ return false;
+}
+
static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
{
struct byt_gpio *vg = to_byt_gpio(chip);
+ void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
+ u32 value;
+ bool special;
+
+ /*
+ * In most cases, func pin mux 000 means GPIO function.
+ * But, some pins may have func pin mux 001 represents
+ * GPIO function. Only allow user to export pin with
+ * func pin mux preset as GPIO function by BIOS/FW.
+ */
+ value = readl(reg) & BYT_PIN_MUX;
+ special = is_special_pin(vg, offset);
+ if ((special && value != 1) || (!special && value)) {
+ dev_err(&vg->pdev->dev,
+ "pin %u cannot be used as GPIO.\n", offset);
+ return -EINVAL;
+ }
pm_runtime_get(&vg->pdev->dev);
diff --git a/drivers/pinctrl/pinctrl-capri.c b/drivers/pinctrl/pinctrl-capri.c
index 4669c53f99b0..eb2500212147 100644
--- a/drivers/pinctrl/pinctrl-capri.c
+++ b/drivers/pinctrl/pinctrl-capri.c
@@ -1435,7 +1435,7 @@ int __init capri_pinctrl_probe(struct platform_device *pdev)
}
static struct of_device_id capri_pinctrl_of_match[] = {
- { .compatible = "brcm,capri-pinctrl", },
+ { .compatible = "brcm,bcm11351-pinctrl", },
{ },
};
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index 155b1b3a0e7a..07c81306f2f3 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -1042,6 +1042,88 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
},
};
+/* pin banks of exynos5260 pin-controller 0 */
+static struct samsung_pin_bank exynos5260_pin_banks0[] = {
+ EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpa0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(7, 0x020, "gpa1", 0x04),
+ EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
+ EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpb0", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(4, 0x080, "gpb1", 0x10),
+ EXYNOS_PIN_BANK_EINTG(5, 0x0a0, "gpb2", 0x14),
+ EXYNOS_PIN_BANK_EINTG(8, 0x0c0, "gpb3", 0x18),
+ EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpb4", 0x1c),
+ EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpb5", 0x20),
+ EXYNOS_PIN_BANK_EINTG(8, 0x120, "gpd0", 0x24),
+ EXYNOS_PIN_BANK_EINTG(7, 0x140, "gpd1", 0x28),
+ EXYNOS_PIN_BANK_EINTG(5, 0x160, "gpd2", 0x2c),
+ EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpe0", 0x30),
+ EXYNOS_PIN_BANK_EINTG(5, 0x1a0, "gpe1", 0x34),
+ EXYNOS_PIN_BANK_EINTG(4, 0x1c0, "gpf0", 0x38),
+ EXYNOS_PIN_BANK_EINTG(8, 0x1e0, "gpf1", 0x3c),
+ EXYNOS_PIN_BANK_EINTG(2, 0x200, "gpk0", 0x40),
+ EXYNOS_PIN_BANK_EINTW(8, 0xc00, "gpx0", 0x00),
+ EXYNOS_PIN_BANK_EINTW(8, 0xc20, "gpx1", 0x04),
+ EXYNOS_PIN_BANK_EINTW(8, 0xc40, "gpx2", 0x08),
+ EXYNOS_PIN_BANK_EINTW(8, 0xc60, "gpx3", 0x0c),
+};
+
+/* pin banks of exynos5260 pin-controller 1 */
+static struct samsung_pin_bank exynos5260_pin_banks1[] = {
+ EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpc0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpc1", 0x04),
+ EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpc2", 0x08),
+ EXYNOS_PIN_BANK_EINTG(4, 0x060, "gpc3", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(4, 0x080, "gpc4", 0x10),
+};
+
+/* pin banks of exynos5260 pin-controller 2 */
+static struct samsung_pin_bank exynos5260_pin_banks2[] = {
+ EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04),
+};
+
+/*
+ * Samsung pinctrl driver data for Exynos5260 SoC. Exynos5260 SoC includes
+ * three gpio/pin-mux/pinconfig controllers.
+ */
+struct samsung_pin_ctrl exynos5260_pin_ctrl[] = {
+ {
+ /* pin-controller instance 0 data */
+ .pin_banks = exynos5260_pin_banks0,
+ .nr_banks = ARRAY_SIZE(exynos5260_pin_banks0),
+ .geint_con = EXYNOS_GPIO_ECON_OFFSET,
+ .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
+ .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
+ .weint_con = EXYNOS_WKUP_ECON_OFFSET,
+ .weint_mask = EXYNOS_WKUP_EMASK_OFFSET,
+ .weint_pend = EXYNOS_WKUP_EPEND_OFFSET,
+ .svc = EXYNOS_SVC_OFFSET,
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .eint_wkup_init = exynos_eint_wkup_init,
+ .label = "exynos5260-gpio-ctrl0",
+ }, {
+ /* pin-controller instance 1 data */
+ .pin_banks = exynos5260_pin_banks1,
+ .nr_banks = ARRAY_SIZE(exynos5260_pin_banks1),
+ .geint_con = EXYNOS_GPIO_ECON_OFFSET,
+ .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
+ .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
+ .svc = EXYNOS_SVC_OFFSET,
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .label = "exynos5260-gpio-ctrl1",
+ }, {
+ /* pin-controller instance 2 data */
+ .pin_banks = exynos5260_pin_banks2,
+ .nr_banks = ARRAY_SIZE(exynos5260_pin_banks2),
+ .geint_con = EXYNOS_GPIO_ECON_OFFSET,
+ .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
+ .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
+ .svc = EXYNOS_SVC_OFFSET,
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .label = "exynos5260-gpio-ctrl2",
+ },
+};
+
/* pin banks of exynos5420 pin-controller 0 */
static struct samsung_pin_bank exynos5420_pin_banks0[] = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpy7", 0x00),
diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c
index 4779b8e0eee8..e118fb121e02 100644
--- a/drivers/pinctrl/pinctrl-imx.c
+++ b/drivers/pinctrl/pinctrl-imx.c
@@ -491,7 +491,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
pin->mux_mode |= IOMUXC_CONFIG_SION;
pin->config = config & ~IMX_PAD_SION;
- dev_dbg(info->dev, "%s: %d 0x%08lx", info->pins[i].name,
+ dev_dbg(info->dev, "%s: %d 0x%08lx", info->pins[pin_id].name,
pin->mux_mode, pin->config);
}
diff --git a/drivers/pinctrl/pinctrl-msm.c b/drivers/pinctrl/pinctrl-msm.c
index ef2bf3126da6..343f421c7696 100644
--- a/drivers/pinctrl/pinctrl-msm.c
+++ b/drivers/pinctrl/pinctrl-msm.c
@@ -28,7 +28,6 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
-#include <linux/of_irq.h>
#include <linux/spinlock.h>
#include "core.h"
@@ -50,7 +49,6 @@
* @enabled_irqs: Bitmap of currently enabled irqs.
* @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge
* detection.
- * @wake_irqs: Bitmap of irqs with requested as wakeup source.
* @soc; Reference to soc_data of platform specific data.
* @regs: Base address for the TLMM register map.
*/
@@ -65,7 +63,6 @@ struct msm_pinctrl {
DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
- DECLARE_BITMAP(wake_irqs, MAX_NR_GPIO);
const struct msm_pinctrl_soc_data *soc;
void __iomem *regs;
@@ -203,42 +200,29 @@ static const struct pinmux_ops msm_pinmux_ops = {
static int msm_config_reg(struct msm_pinctrl *pctrl,
const struct msm_pingroup *g,
unsigned param,
- s16 *reg,
unsigned *mask,
unsigned *bit)
{
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
- *reg = g->ctl_reg;
- *bit = g->pull_bit;
- *mask = 3;
- break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- *reg = g->ctl_reg;
- *bit = g->pull_bit;
- *mask = 3;
- break;
case PIN_CONFIG_BIAS_PULL_UP:
- *reg = g->ctl_reg;
*bit = g->pull_bit;
*mask = 3;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
- *reg = g->ctl_reg;
*bit = g->drv_bit;
*mask = 7;
break;
+ case PIN_CONFIG_OUTPUT:
+ *bit = g->oe_bit;
+ *mask = 1;
+ break;
default:
dev_err(pctrl->dev, "Invalid config param %04x\n", param);
return -ENOTSUPP;
}
- if (*reg < 0) {
- dev_err(pctrl->dev, "Config param %04x not supported on group %s\n",
- param, g->name);
- return -ENOTSUPP;
- }
-
return 0;
}
@@ -261,8 +245,10 @@ static int msm_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
#define MSM_PULL_DOWN 1
#define MSM_PULL_UP 3
-static const unsigned msm_regval_to_drive[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
-static const unsigned msm_drive_to_regval[] = { -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, 4, -1, 5, -1, 6, -1, 7 };
+static unsigned msm_regval_to_drive(u32 val)
+{
+ return (val + 1) * 2;
+}
static int msm_config_group_get(struct pinctrl_dev *pctldev,
unsigned int group,
@@ -274,17 +260,16 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev,
unsigned mask;
unsigned arg;
unsigned bit;
- s16 reg;
int ret;
u32 val;
g = &pctrl->soc->groups[group];
- ret = msm_config_reg(pctrl, g, param, &reg, &mask, &bit);
+ ret = msm_config_reg(pctrl, g, param, &mask, &bit);
if (ret < 0)
return ret;
- val = readl(pctrl->regs + reg);
+ val = readl(pctrl->regs + g->ctl_reg);
arg = (val >> bit) & mask;
/* Convert register value to pinconf value */
@@ -299,7 +284,15 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev,
arg = arg == MSM_PULL_UP;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
- arg = msm_regval_to_drive[arg];
+ arg = msm_regval_to_drive(arg);
+ break;
+ case PIN_CONFIG_OUTPUT:
+ /* Pin is not output */
+ if (!arg)
+ return -EINVAL;
+
+ val = readl(pctrl->regs + g->io_reg);
+ arg = !!(val & BIT(g->in_bit));
break;
default:
dev_err(pctrl->dev, "Unsupported config parameter: %x\n",
@@ -324,7 +317,6 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
unsigned mask;
unsigned arg;
unsigned bit;
- s16 reg;
int ret;
u32 val;
int i;
@@ -335,7 +327,7 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
- ret = msm_config_reg(pctrl, g, param, &reg, &mask, &bit);
+ ret = msm_config_reg(pctrl, g, param, &mask, &bit);
if (ret < 0)
return ret;
@@ -352,10 +344,24 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
break;
case PIN_CONFIG_DRIVE_STRENGTH:
/* Check for invalid values */
- if (arg >= ARRAY_SIZE(msm_drive_to_regval))
+ if (arg > 16 || arg < 2 || (arg % 2) != 0)
arg = -1;
else
- arg = msm_drive_to_regval[arg];
+ arg = (arg / 2) - 1;
+ break;
+ case PIN_CONFIG_OUTPUT:
+ /* set output value */
+ spin_lock_irqsave(&pctrl->lock, flags);
+ val = readl(pctrl->regs + g->io_reg);
+ if (arg)
+ val |= BIT(g->out_bit);
+ else
+ val &= ~BIT(g->out_bit);
+ writel(val, pctrl->regs + g->io_reg);
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ /* enable output */
+ arg = 1;
break;
default:
dev_err(pctrl->dev, "Unsupported config parameter: %x\n",
@@ -370,10 +376,10 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
}
spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + reg);
+ val = readl(pctrl->regs + g->ctl_reg);
val &= ~(mask << bit);
val |= arg << bit;
- writel(val, pctrl->regs + reg);
+ writel(val, pctrl->regs + g->ctl_reg);
spin_unlock_irqrestore(&pctrl->lock, flags);
}
@@ -402,8 +408,6 @@ static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
u32 val;
g = &pctrl->soc->groups[offset];
- if (WARN_ON(g->io_reg < 0))
- return -EINVAL;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -424,8 +428,6 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in
u32 val;
g = &pctrl->soc->groups[offset];
- if (WARN_ON(g->io_reg < 0))
- return -EINVAL;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -452,8 +454,6 @@ static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
u32 val;
g = &pctrl->soc->groups[offset];
- if (WARN_ON(g->io_reg < 0))
- return -EINVAL;
val = readl(pctrl->regs + g->io_reg);
return !!(val & BIT(g->in_bit));
@@ -467,8 +467,6 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
u32 val;
g = &pctrl->soc->groups[offset];
- if (WARN_ON(g->io_reg < 0))
- return;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -534,7 +532,7 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
pull = (ctl_reg >> g->pull_bit) & 3;
seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func);
- seq_printf(s, " %dmA", msm_regval_to_drive[drive]);
+ seq_printf(s, " %dmA", msm_regval_to_drive(drive));
seq_printf(s, " %s", pulls[pull]);
}
@@ -617,8 +615,6 @@ static void msm_gpio_irq_mask(struct irq_data *d)
pctrl = irq_data_get_irq_chip_data(d);
g = &pctrl->soc->groups[d->hwirq];
- if (WARN_ON(g->intr_cfg_reg < 0))
- return;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -640,8 +636,6 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
pctrl = irq_data_get_irq_chip_data(d);
g = &pctrl->soc->groups[d->hwirq];
- if (WARN_ON(g->intr_status_reg < 0))
- return;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -667,8 +661,6 @@ static void msm_gpio_irq_ack(struct irq_data *d)
pctrl = irq_data_get_irq_chip_data(d);
g = &pctrl->soc->groups[d->hwirq];
- if (WARN_ON(g->intr_status_reg < 0))
- return;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -693,8 +685,6 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
pctrl = irq_data_get_irq_chip_data(d);
g = &pctrl->soc->groups[d->hwirq];
- if (WARN_ON(g->intr_cfg_reg < 0))
- return -EINVAL;
spin_lock_irqsave(&pctrl->lock, flags);
@@ -783,22 +773,12 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
{
struct msm_pinctrl *pctrl;
unsigned long flags;
- unsigned ngpio;
pctrl = irq_data_get_irq_chip_data(d);
- ngpio = pctrl->chip.ngpio;
spin_lock_irqsave(&pctrl->lock, flags);
- if (on) {
- if (bitmap_empty(pctrl->wake_irqs, ngpio))
- enable_irq_wake(pctrl->irq);
- set_bit(d->hwirq, pctrl->wake_irqs);
- } else {
- clear_bit(d->hwirq, pctrl->wake_irqs);
- if (bitmap_empty(pctrl->wake_irqs, ngpio))
- disable_irq_wake(pctrl->irq);
- }
+ irq_set_irq_wake(pctrl->irq, on);
spin_unlock_irqrestore(&pctrl->lock, flags);
@@ -869,6 +849,12 @@ static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key gpio_lock_class;
+
static int msm_gpio_init(struct msm_pinctrl *pctrl)
{
struct gpio_chip *chip;
@@ -876,10 +862,14 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
int ret;
int i;
int r;
+ unsigned ngpio = pctrl->soc->ngpios;
+
+ if (WARN_ON(ngpio > MAX_NR_GPIO))
+ return -EINVAL;
chip = &pctrl->chip;
chip->base = 0;
- chip->ngpio = pctrl->soc->ngpios;
+ chip->ngpio = ngpio;
chip->label = dev_name(pctrl->dev);
chip->dev = pctrl->dev;
chip->owner = THIS_MODULE;
@@ -907,6 +897,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
for (i = 0; i < chip->ngpio; i++) {
irq = irq_create_mapping(pctrl->domain, i);
+ irq_set_lockdep_class(irq, &gpio_lock_class);
irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, handle_edge_irq);
irq_set_chip_data(irq, pctrl);
}
diff --git a/drivers/pinctrl/pinctrl-msm.h b/drivers/pinctrl/pinctrl-msm.h
index 206e782e2daa..8fbe9fb19f36 100644
--- a/drivers/pinctrl/pinctrl-msm.h
+++ b/drivers/pinctrl/pinctrl-msm.h
@@ -13,10 +13,7 @@
#ifndef __PINCTRL_MSM_H__
#define __PINCTRL_MSM_H__
-#include <linux/pinctrl/pinctrl.h>
-#include <linux/pinctrl/pinmux.h>
-#include <linux/pinctrl/pinconf.h>
-#include <linux/pinctrl/machine.h>
+struct pinctrl_pin_desc;
/**
* struct msm_function - a pinmux function
diff --git a/drivers/pinctrl/pinctrl-msm8x74.c b/drivers/pinctrl/pinctrl-msm8x74.c
index f944bf2172ef..dde5529807aa 100644
--- a/drivers/pinctrl/pinctrl-msm8x74.c
+++ b/drivers/pinctrl/pinctrl-msm8x74.c
@@ -15,7 +15,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinctrl.h>
-#include <linux/pinctrl/pinmux.h>
#include "pinctrl-msm.h"
@@ -406,6 +405,7 @@ enum msm8x74_functions {
MSM_MUX_blsp_i2c6,
MSM_MUX_blsp_i2c11,
MSM_MUX_blsp_spi1,
+ MSM_MUX_blsp_spi8,
MSM_MUX_blsp_uart2,
MSM_MUX_blsp_uart8,
MSM_MUX_slimbus,
@@ -416,6 +416,9 @@ static const char * const blsp_i2c2_groups[] = { "gpio6", "gpio7" };
static const char * const blsp_i2c6_groups[] = { "gpio29", "gpio30" };
static const char * const blsp_i2c11_groups[] = { "gpio83", "gpio84" };
static const char * const blsp_spi1_groups[] = { "gpio0", "gpio1", "gpio2", "gpio3" };
+static const char * const blsp_spi8_groups[] = {
+ "gpio45", "gpio46", "gpio47", "gpio48"
+};
static const char * const blsp_uart2_groups[] = { "gpio4", "gpio5" };
static const char * const blsp_uart8_groups[] = { "gpio45", "gpio46" };
static const char * const slimbus_groups[] = { "gpio70", "gpio71" };
@@ -425,6 +428,7 @@ static const struct msm_function msm8x74_functions[] = {
FUNCTION(blsp_i2c6),
FUNCTION(blsp_i2c11),
FUNCTION(blsp_spi1),
+ FUNCTION(blsp_spi8),
FUNCTION(blsp_uart2),
FUNCTION(blsp_uart8),
FUNCTION(slimbus),
@@ -476,10 +480,10 @@ static const struct msm_pingroup msm8x74_groups[] = {
PINGROUP(42, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(43, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(44, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(45, NA, blsp_uart8, NA, NA, NA, NA, NA),
- PINGROUP(46, NA, blsp_uart8, NA, NA, NA, NA, NA),
- PINGROUP(47, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(48, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(45, blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA),
+ PINGROUP(46, blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA),
+ PINGROUP(47, blsp_spi8, NA, NA, NA, NA, NA, NA),
+ PINGROUP(48, blsp_spi8, NA, NA, NA, NA, NA, NA),
PINGROUP(49, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(50, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(51, NA, NA, NA, NA, NA, NA, NA),
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
index 53a11114927f..cec7762cf335 100644
--- a/drivers/pinctrl/pinctrl-nomadik.c
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -2035,27 +2035,29 @@ static const struct of_device_id nmk_pinctrl_match[] = {
{},
};
-static int nmk_pinctrl_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int nmk_pinctrl_suspend(struct device *dev)
{
struct nmk_pinctrl *npct;
- npct = platform_get_drvdata(pdev);
+ npct = dev_get_drvdata(dev);
if (!npct)
return -EINVAL;
return pinctrl_force_sleep(npct->pctl);
}
-static int nmk_pinctrl_resume(struct platform_device *pdev)
+static int nmk_pinctrl_resume(struct device *dev)
{
struct nmk_pinctrl *npct;
- npct = platform_get_drvdata(pdev);
+ npct = dev_get_drvdata(dev);
if (!npct)
return -EINVAL;
return pinctrl_force_default(npct->pctl);
}
+#endif
static int nmk_pinctrl_probe(struct platform_device *pdev)
{
@@ -2144,17 +2146,18 @@ static struct platform_driver nmk_gpio_driver = {
.probe = nmk_gpio_probe,
};
+static SIMPLE_DEV_PM_OPS(nmk_pinctrl_pm_ops,
+ nmk_pinctrl_suspend,
+ nmk_pinctrl_resume);
+
static struct platform_driver nmk_pinctrl_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "pinctrl-nomadik",
.of_match_table = nmk_pinctrl_match,
+ .pm = &nmk_pinctrl_pm_ops,
},
.probe = nmk_pinctrl_probe,
-#ifdef CONFIG_PM
- .suspend = nmk_pinctrl_suspend,
- .resume = nmk_pinctrl_resume,
-#endif
};
static int __init nmk_gpio_init(void)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index 47ec2e8741e4..0324d4cb19b2 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -1120,6 +1120,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
.data = (void *)exynos4x12_pin_ctrl },
{ .compatible = "samsung,exynos5250-pinctrl",
.data = (void *)exynos5250_pin_ctrl },
+ { .compatible = "samsung,exynos5260-pinctrl",
+ .data = (void *)exynos5260_pin_ctrl },
{ .compatible = "samsung,exynos5420-pinctrl",
.data = (void *)exynos5420_pin_ctrl },
{ .compatible = "samsung,s5pv210-pinctrl",
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index 30622d9afa2e..bab9c2122556 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -254,6 +254,7 @@ struct samsung_pmx_func {
extern struct samsung_pin_ctrl exynos4210_pin_ctrl[];
extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
extern struct samsung_pin_ctrl exynos5250_pin_ctrl[];
+extern struct samsung_pin_ctrl exynos5260_pin_ctrl[];
extern struct samsung_pin_ctrl exynos5420_pin_ctrl[];
extern struct samsung_pin_ctrl s3c64xx_pin_ctrl[];
extern struct samsung_pin_ctrl s3c2412_pin_ctrl[];
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index de6459628b4f..81075f2a1d3f 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -662,6 +662,7 @@ static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
break;
case PIN_CONFIG_DRIVE_STRENGTH:
case PIN_CONFIG_SLEW_RATE:
+ case PIN_CONFIG_LOW_POWER_MODE:
default:
*config = data;
break;
@@ -699,6 +700,7 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
case PIN_CONFIG_INPUT_SCHMITT:
case PIN_CONFIG_DRIVE_STRENGTH:
case PIN_CONFIG_SLEW_RATE:
+ case PIN_CONFIG_LOW_POWER_MODE:
shift = ffs(func->conf[i].mask) - 1;
data &= ~func->conf[i].mask;
data |= (arg << shift) & func->conf[i].mask;
@@ -1101,6 +1103,7 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
{ "pinctrl-single,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, },
{ "pinctrl-single,slew-rate", PIN_CONFIG_SLEW_RATE, },
{ "pinctrl-single,input-schmitt", PIN_CONFIG_INPUT_SCHMITT, },
+ { "pinctrl-single,low-power-mode", PIN_CONFIG_LOW_POWER_MODE, },
};
struct pcs_conf_type prop4[] = {
{ "pinctrl-single,bias-pullup", PIN_CONFIG_BIAS_PULL_UP, },
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index 320c27363cc8..bd725b0a4341 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -13,7 +13,12 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <linux/regmap.h>
@@ -266,11 +271,59 @@ struct st_pctl_group {
struct st_pinconf *pin_conf;
};
+/*
+ * Edge triggers are not supported at hardware level, it is supported by
+ * software by exploiting the level trigger support in hardware.
+ * Software uses a virtual register (EDGE_CONF) for edge trigger configuration
+ * of each gpio pin in a GPIO bank.
+ *
+ * Each bank has a 32 bit EDGE_CONF register which is divided in to 8 parts of
+ * 4-bits. Each 4-bit space is allocated for each pin in a gpio bank.
+ *
+ * bit allocation per pin is:
+ * Bits: [0 - 3] | [4 - 7] [8 - 11] ... ... ... ... [ 28 - 31]
+ * --------------------------------------------------------
+ * | pin-0 | pin-2 | pin-3 | ... ... ... ... | pin -7 |
+ * --------------------------------------------------------
+ *
+ * A pin can have one of following the values in its edge configuration field.
+ *
+ * ------- ----------------------------
+ * [0-3] - Description
+ * ------- ----------------------------
+ * 0000 - No edge IRQ.
+ * 0001 - Falling edge IRQ.
+ * 0010 - Rising edge IRQ.
+ * 0011 - Rising and Falling edge IRQ.
+ * ------- ----------------------------
+ */
+
+#define ST_IRQ_EDGE_CONF_BITS_PER_PIN 4
+#define ST_IRQ_EDGE_MASK 0xf
+#define ST_IRQ_EDGE_FALLING BIT(0)
+#define ST_IRQ_EDGE_RISING BIT(1)
+#define ST_IRQ_EDGE_BOTH (BIT(0) | BIT(1))
+
+#define ST_IRQ_RISING_EDGE_CONF(pin) \
+ (ST_IRQ_EDGE_RISING << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN))
+
+#define ST_IRQ_FALLING_EDGE_CONF(pin) \
+ (ST_IRQ_EDGE_FALLING << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN))
+
+#define ST_IRQ_BOTH_EDGE_CONF(pin) \
+ (ST_IRQ_EDGE_BOTH << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN))
+
+#define ST_IRQ_EDGE_CONF(conf, pin) \
+ (conf >> (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN) & ST_IRQ_EDGE_MASK)
+
struct st_gpio_bank {
struct gpio_chip gpio_chip;
struct pinctrl_gpio_range range;
void __iomem *base;
struct st_pio_control pc;
+ struct irq_domain *domain;
+ unsigned long irq_edge_conf;
+ spinlock_t lock;
};
struct st_pinctrl {
@@ -284,6 +337,7 @@ struct st_pinctrl {
int ngroups;
struct regmap *regmap;
const struct st_pctl_data *data;
+ void __iomem *irqmux_base;
};
/* SOC specific data */
@@ -330,12 +384,25 @@ static unsigned int stih416_delays[] = {0, 300, 500, 750, 1000, 1250, 1500,
static const struct st_pctl_data stih416_data = {
.rt_style = st_retime_style_dedicated,
.input_delays = stih416_delays,
- .ninput_delays = 14,
+ .ninput_delays = ARRAY_SIZE(stih416_delays),
.output_delays = stih416_delays,
- .noutput_delays = 14,
+ .noutput_delays = ARRAY_SIZE(stih416_delays),
.alt = 0, .oe = 40, .pu = 50, .od = 60, .rt = 100,
};
+static const struct st_pctl_data stih407_flashdata = {
+ .rt_style = st_retime_style_none,
+ .input_delays = stih416_delays,
+ .ninput_delays = ARRAY_SIZE(stih416_delays),
+ .output_delays = stih416_delays,
+ .noutput_delays = ARRAY_SIZE(stih416_delays),
+ .alt = 0,
+ .oe = -1, /* Not Available */
+ .pu = -1, /* Not Available */
+ .od = 60,
+ .rt = 100,
+};
+
/* Low level functions.. */
static inline int st_gpio_bank(int gpio)
{
@@ -356,25 +423,29 @@ static void st_pinconf_set_config(struct st_pio_control *pc,
unsigned int oe_value, pu_value, od_value;
unsigned long mask = BIT(pin);
- regmap_field_read(output_enable, &oe_value);
- regmap_field_read(pull_up, &pu_value);
- regmap_field_read(open_drain, &od_value);
-
- /* Clear old values */
- oe_value &= ~mask;
- pu_value &= ~mask;
- od_value &= ~mask;
-
- if (config & ST_PINCONF_OE)
- oe_value |= mask;
- if (config & ST_PINCONF_PU)
- pu_value |= mask;
- if (config & ST_PINCONF_OD)
- od_value |= mask;
-
- regmap_field_write(output_enable, oe_value);
- regmap_field_write(pull_up, pu_value);
- regmap_field_write(open_drain, od_value);
+ if (output_enable) {
+ regmap_field_read(output_enable, &oe_value);
+ oe_value &= ~mask;
+ if (config & ST_PINCONF_OE)
+ oe_value |= mask;
+ regmap_field_write(output_enable, oe_value);
+ }
+
+ if (pull_up) {
+ regmap_field_read(pull_up, &pu_value);
+ pu_value &= ~mask;
+ if (config & ST_PINCONF_PU)
+ pu_value |= mask;
+ regmap_field_write(pull_up, pu_value);
+ }
+
+ if (open_drain) {
+ regmap_field_read(open_drain, &od_value);
+ od_value &= ~mask;
+ if (config & ST_PINCONF_OD)
+ od_value |= mask;
+ regmap_field_write(open_drain, od_value);
+ }
}
static void st_pctl_set_function(struct st_pio_control *pc,
@@ -385,6 +456,9 @@ static void st_pctl_set_function(struct st_pio_control *pc,
int pin = st_gpio_pin(pin_id);
int offset = pin * 4;
+ if (!alt)
+ return;
+
regmap_field_read(alt, &val);
val &= ~(0xf << offset);
val |= function << offset;
@@ -522,17 +596,23 @@ static void st_pinconf_get_direction(struct st_pio_control *pc,
{
unsigned int oe_value, pu_value, od_value;
- regmap_field_read(pc->oe, &oe_value);
- regmap_field_read(pc->pu, &pu_value);
- regmap_field_read(pc->od, &od_value);
+ if (pc->oe) {
+ regmap_field_read(pc->oe, &oe_value);
+ if (oe_value & BIT(pin))
+ ST_PINCONF_PACK_OE(*config);
+ }
- if (oe_value & BIT(pin))
- ST_PINCONF_PACK_OE(*config);
- if (pu_value & BIT(pin))
- ST_PINCONF_PACK_PU(*config);
- if (od_value & BIT(pin))
- ST_PINCONF_PACK_OD(*config);
+ if (pc->pu) {
+ regmap_field_read(pc->pu, &pu_value);
+ if (pu_value & BIT(pin))
+ ST_PINCONF_PACK_PU(*config);
+ }
+ if (pc->od) {
+ regmap_field_read(pc->od, &od_value);
+ if (od_value & BIT(pin))
+ ST_PINCONF_PACK_OD(*config);
+ }
}
static int st_pinconf_get_retime_packed(struct st_pinctrl *info,
@@ -1051,8 +1131,21 @@ static int st_pctl_dt_setup_retime(struct st_pinctrl *info,
return -EINVAL;
}
-static int st_parse_syscfgs(struct st_pinctrl *info,
- int bank, struct device_node *np)
+
+static struct regmap_field *st_pc_get_value(struct device *dev,
+ struct regmap *regmap, int bank,
+ int data, int lsb, int msb)
+{
+ struct reg_field reg = REG_FIELD((data + bank) * 4, lsb, msb);
+
+ if (data < 0)
+ return NULL;
+
+ return devm_regmap_field_alloc(dev, regmap, reg);
+}
+
+static void st_parse_syscfgs(struct st_pinctrl *info, int bank,
+ struct device_node *np)
{
const struct st_pctl_data *data = info->data;
/**
@@ -1062,29 +1155,21 @@ static int st_parse_syscfgs(struct st_pinctrl *info,
*/
int lsb = (bank%4) * ST_GPIO_PINS_PER_BANK;
int msb = lsb + ST_GPIO_PINS_PER_BANK - 1;
- struct reg_field alt_reg = REG_FIELD((data->alt + bank) * 4, 0, 31);
- struct reg_field oe_reg = REG_FIELD((data->oe + bank/4) * 4, lsb, msb);
- struct reg_field pu_reg = REG_FIELD((data->pu + bank/4) * 4, lsb, msb);
- struct reg_field od_reg = REG_FIELD((data->od + bank/4) * 4, lsb, msb);
struct st_pio_control *pc = &info->banks[bank].pc;
struct device *dev = info->dev;
struct regmap *regmap = info->regmap;
- pc->alt = devm_regmap_field_alloc(dev, regmap, alt_reg);
- pc->oe = devm_regmap_field_alloc(dev, regmap, oe_reg);
- pc->pu = devm_regmap_field_alloc(dev, regmap, pu_reg);
- pc->od = devm_regmap_field_alloc(dev, regmap, od_reg);
-
- if (IS_ERR(pc->alt) || IS_ERR(pc->oe) ||
- IS_ERR(pc->pu) || IS_ERR(pc->od))
- return -EINVAL;
+ pc->alt = st_pc_get_value(dev, regmap, bank, data->alt, 0, 31);
+ pc->oe = st_pc_get_value(dev, regmap, bank/4, data->oe, lsb, msb);
+ pc->pu = st_pc_get_value(dev, regmap, bank/4, data->pu, lsb, msb);
+ pc->od = st_pc_get_value(dev, regmap, bank/4, data->od, lsb, msb);
/* retime avaiable for all pins by default */
pc->rt_pin_mask = 0xff;
of_property_read_u32(np, "st,retime-pin-mask", &pc->rt_pin_mask);
st_pctl_dt_setup_retime(info, bank, pc);
- return 0;
+ return;
}
/*
@@ -1200,6 +1285,194 @@ static int st_pctl_parse_functions(struct device_node *np,
return 0;
}
+static int st_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+ int irq = -ENXIO;
+
+ if (offset < chip->ngpio)
+ irq = irq_find_mapping(bank->domain, offset);
+
+ dev_info(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
+ chip->label, offset + chip->base, irq);
+ return irq;
+}
+
+static void st_gpio_irq_mask(struct irq_data *d)
+{
+ struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+ writel(BIT(d->hwirq), bank->base + REG_PIO_CLR_PMASK);
+}
+
+static void st_gpio_irq_unmask(struct irq_data *d)
+{
+ struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+ writel(BIT(d->hwirq), bank->base + REG_PIO_SET_PMASK);
+}
+
+static unsigned int st_gpio_irq_startup(struct irq_data *d)
+{
+ struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+ if (gpio_lock_as_irq(&bank->gpio_chip, d->hwirq))
+ dev_err(bank->gpio_chip.dev,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ d->hwirq);
+
+ st_gpio_irq_unmask(d);
+
+ return 0;
+}
+
+static void st_gpio_irq_shutdown(struct irq_data *d)
+{
+ struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+ st_gpio_irq_mask(d);
+ gpio_unlock_as_irq(&bank->gpio_chip, d->hwirq);
+}
+
+static int st_gpio_irq_set_type(struct irq_data *d, unsigned type)
+{
+ struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+ int comp, pin = d->hwirq;
+ u32 val;
+ u32 pin_edge_conf = 0;
+
+ switch (type) {
+ case IRQ_TYPE_LEVEL_HIGH:
+ comp = 0;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ comp = 0;
+ pin_edge_conf = ST_IRQ_FALLING_EDGE_CONF(pin);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ comp = 1;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ comp = 1;
+ pin_edge_conf = ST_IRQ_RISING_EDGE_CONF(pin);
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ comp = st_gpio_get(&bank->gpio_chip, pin);
+ pin_edge_conf = ST_IRQ_BOTH_EDGE_CONF(pin);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&bank->lock, flags);
+ bank->irq_edge_conf &= ~(ST_IRQ_EDGE_MASK << (
+ pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN));
+ bank->irq_edge_conf |= pin_edge_conf;
+ spin_unlock_irqrestore(&bank->lock, flags);
+
+ val = readl(bank->base + REG_PIO_PCOMP);
+ val &= ~BIT(pin);
+ val |= (comp << pin);
+ writel(val, bank->base + REG_PIO_PCOMP);
+
+ return 0;
+}
+
+/*
+ * As edge triggers are not supported at hardware level, it is supported by
+ * software by exploiting the level trigger support in hardware.
+ *
+ * Steps for detection raising edge interrupt in software.
+ *
+ * Step 1: CONFIGURE pin to detect level LOW interrupts.
+ *
+ * Step 2: DETECT level LOW interrupt and in irqmux/gpio bank interrupt handler,
+ * if the value of pin is low, then CONFIGURE pin for level HIGH interrupt.
+ * IGNORE calling the actual interrupt handler for the pin at this stage.
+ *
+ * Step 3: DETECT level HIGH interrupt and in irqmux/gpio-bank interrupt handler
+ * if the value of pin is HIGH, CONFIGURE pin for level LOW interrupt and then
+ * DISPATCH the interrupt to the interrupt handler of the pin.
+ *
+ * step-1 ________ __________
+ * | | step - 3
+ * | |
+ * step -2 |_____|
+ *
+ * falling edge is also detected int the same way.
+ *
+ */
+static void __gpio_irq_handler(struct st_gpio_bank *bank)
+{
+ unsigned long port_in, port_mask, port_comp, active_irqs;
+ unsigned long bank_edge_mask, flags;
+ int n, val, ecfg;
+
+ spin_lock_irqsave(&bank->lock, flags);
+ bank_edge_mask = bank->irq_edge_conf;
+ spin_unlock_irqrestore(&bank->lock, flags);
+
+ for (;;) {
+ port_in = readl(bank->base + REG_PIO_PIN);
+ port_comp = readl(bank->base + REG_PIO_PCOMP);
+ port_mask = readl(bank->base + REG_PIO_PMASK);
+
+ active_irqs = (port_in ^ port_comp) & port_mask;
+
+ if (active_irqs == 0)
+ break;
+
+ for_each_set_bit(n, &active_irqs, BITS_PER_LONG) {
+ /* check if we are detecting fake edges ... */
+ ecfg = ST_IRQ_EDGE_CONF(bank_edge_mask, n);
+
+ if (ecfg) {
+ /* edge detection. */
+ val = st_gpio_get(&bank->gpio_chip, n);
+
+ writel(BIT(n),
+ val ? bank->base + REG_PIO_SET_PCOMP :
+ bank->base + REG_PIO_CLR_PCOMP);
+
+ if (ecfg != ST_IRQ_EDGE_BOTH &&
+ !((ecfg & ST_IRQ_EDGE_FALLING) ^ val))
+ continue;
+ }
+
+ generic_handle_irq(irq_find_mapping(bank->domain, n));
+ }
+ }
+}
+
+static void st_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+ /* interrupt dedicated per bank */
+ struct irq_chip *chip = irq_get_chip(irq);
+ struct st_gpio_bank *bank = irq_get_handler_data(irq);
+
+ chained_irq_enter(chip, desc);
+ __gpio_irq_handler(bank);
+ chained_irq_exit(chip, desc);
+}
+
+static void st_gpio_irqmux_handler(unsigned irq, struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_get_chip(irq);
+ struct st_pinctrl *info = irq_get_handler_data(irq);
+ unsigned long status;
+ int n;
+
+ chained_irq_enter(chip, desc);
+
+ status = readl(info->irqmux_base);
+
+ for_each_set_bit(n, &status, ST_GPIO_PINS_PER_BANK)
+ __gpio_irq_handler(&info->banks[n]);
+
+ chained_irq_exit(chip, desc);
+}
+
static struct gpio_chip st_gpio_template = {
.request = st_gpio_request,
.free = st_gpio_free,
@@ -1210,6 +1483,34 @@ static struct gpio_chip st_gpio_template = {
.ngpio = ST_GPIO_PINS_PER_BANK,
.of_gpio_n_cells = 1,
.of_xlate = st_gpio_xlate,
+ .to_irq = st_gpio_to_irq,
+};
+
+static struct irq_chip st_gpio_irqchip = {
+ .name = "GPIO",
+ .irq_mask = st_gpio_irq_mask,
+ .irq_unmask = st_gpio_irq_unmask,
+ .irq_set_type = st_gpio_irq_set_type,
+ .irq_startup = st_gpio_irq_startup,
+ .irq_shutdown = st_gpio_irq_shutdown,
+};
+
+static int st_gpio_irq_domain_map(struct irq_domain *h,
+ unsigned int virq, irq_hw_number_t hw)
+{
+ struct st_gpio_bank *bank = h->host_data;
+
+ irq_set_chip(virq, &st_gpio_irqchip);
+ irq_set_handler(virq, handle_simple_irq);
+ set_irq_flags(virq, IRQF_VALID);
+ irq_set_chip_data(virq, bank);
+
+ return 0;
+}
+
+static struct irq_domain_ops st_gpio_irq_ops = {
+ .map = st_gpio_irq_domain_map,
+ .xlate = irq_domain_xlate_twocell,
};
static int st_gpiolib_register_bank(struct st_pinctrl *info,
@@ -1219,8 +1520,8 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
struct pinctrl_gpio_range *range = &bank->range;
struct device *dev = info->dev;
int bank_num = of_alias_get_id(np, "gpio");
- struct resource res;
- int err;
+ struct resource res, irq_res;
+ int gpio_irq = 0, err, i;
if (of_address_to_resource(np, 0, &res))
return -ENODEV;
@@ -1233,6 +1534,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
bank->gpio_chip.base = bank_num * ST_GPIO_PINS_PER_BANK;
bank->gpio_chip.ngpio = ST_GPIO_PINS_PER_BANK;
bank->gpio_chip.of_node = np;
+ spin_lock_init(&bank->lock);
of_property_read_string(np, "st,bank-name", &range->name);
bank->gpio_chip.label = range->name;
@@ -1248,6 +1550,51 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
}
dev_info(dev, "%s bank added.\n", range->name);
+ /**
+ * GPIO bank can have one of the two possible types of
+ * interrupt-wirings.
+ *
+ * First type is via irqmux, single interrupt is used by multiple
+ * gpio banks. This reduces number of overall interrupts numbers
+ * required. All these banks belong to a single pincontroller.
+ * _________
+ * | |----> [gpio-bank (n) ]
+ * | |----> [gpio-bank (n + 1)]
+ * [irqN]-- | irq-mux |----> [gpio-bank (n + 2)]
+ * | |----> [gpio-bank (... )]
+ * |_________|----> [gpio-bank (n + 7)]
+ *
+ * Second type has a dedicated interrupt per each gpio bank.
+ *
+ * [irqN]----> [gpio-bank (n)]
+ */
+
+ if (of_irq_to_resource(np, 0, &irq_res)) {
+ gpio_irq = irq_res.start;
+ irq_set_chained_handler(gpio_irq, st_gpio_irq_handler);
+ irq_set_handler_data(gpio_irq, bank);
+ }
+
+ if (info->irqmux_base > 0 || gpio_irq > 0) {
+ /* Setup IRQ domain */
+ bank->domain = irq_domain_add_linear(np,
+ ST_GPIO_PINS_PER_BANK,
+ &st_gpio_irq_ops, bank);
+ if (!bank->domain) {
+ dev_err(dev, "Failed to add irq domain for %s\n",
+ np->full_name);
+ } else {
+ for (i = 0; i < ST_GPIO_PINS_PER_BANK; i++) {
+ if (irq_create_mapping(bank->domain, i) < 0)
+ dev_err(dev,
+ "Failed to map IRQ %i\n", i);
+ }
+ }
+
+ } else {
+ dev_info(dev, "No IRQ support for %s bank\n", np->full_name);
+ }
+
return 0;
}
@@ -1264,6 +1611,10 @@ static struct of_device_id st_pctl_of_match[] = {
{ .compatible = "st,stih416-rear-pinctrl", .data = &stih416_data},
{ .compatible = "st,stih416-fvdp-fe-pinctrl", .data = &stih416_data},
{ .compatible = "st,stih416-fvdp-lite-pinctrl", .data = &stih416_data},
+ { .compatible = "st,stih407-sbc-pinctrl", .data = &stih416_data},
+ { .compatible = "st,stih407-front-pinctrl", .data = &stih416_data},
+ { .compatible = "st,stih407-rear-pinctrl", .data = &stih416_data},
+ { .compatible = "st,stih407-flash-pinctrl", .data = &stih407_flashdata},
{ /* sentinel */ }
};
@@ -1276,6 +1627,8 @@ static int st_pctl_probe_dt(struct platform_device *pdev,
struct device_node *np = pdev->dev.of_node;
struct device_node *child;
int grp_index = 0;
+ int irq = 0;
+ struct resource *res;
st_pctl_dt_child_count(info, np);
if (!info->nbanks) {
@@ -1306,6 +1659,21 @@ static int st_pctl_probe_dt(struct platform_device *pdev,
}
info->data = of_match_node(st_pctl_of_match, np)->data;
+ irq = platform_get_irq(pdev, 0);
+
+ if (irq > 0) {
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "irqmux");
+ info->irqmux_base = devm_ioremap_resource(&pdev->dev, res);
+
+ if (IS_ERR(info->irqmux_base))
+ return PTR_ERR(info->irqmux_base);
+
+ irq_set_chained_handler(irq, st_gpio_irqmux_handler);
+ irq_set_handler_data(irq, info);
+
+ }
+
pctl_desc->npins = info->nbanks * ST_GPIO_PINS_PER_BANK;
pdesc = devm_kzalloc(&pdev->dev,
sizeof(*pdesc) * pctl_desc->npins, GFP_KERNEL);
diff --git a/drivers/pinctrl/pinctrl-sunxi-pins.h b/drivers/pinctrl/pinctrl-sunxi-pins.h
index 6fd8d4d95140..3d6066988a72 100644
--- a/drivers/pinctrl/pinctrl-sunxi-pins.h
+++ b/drivers/pinctrl/pinctrl-sunxi-pins.h
@@ -1932,27 +1932,27 @@ static const struct sunxi_desc_pin sun5i_a13_pins[] = {
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x4, "mmc0")), /* D1 */
+ SUNXI_FUNCTION(0x2, "mmc0")), /* D1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x4, "mmc0")), /* D0 */
+ SUNXI_FUNCTION(0x2, "mmc0")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x4, "mmc0")), /* CLK */
+ SUNXI_FUNCTION(0x2, "mmc0")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x4, "mmc0")), /* CMD */
+ SUNXI_FUNCTION(0x2, "mmc0")), /* CMD */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x4, "mmc0")), /* D3 */
+ SUNXI_FUNCTION(0x2, "mmc0")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x4, "mmc0")), /* D2 */
+ SUNXI_FUNCTION(0x2, "mmc0")), /* D2 */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
SUNXI_FUNCTION(0x0, "gpio_in"),
diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c
index 9ccf681dad2f..f9fabe9bf47d 100644
--- a/drivers/pinctrl/pinctrl-sunxi.c
+++ b/drivers/pinctrl/pinctrl-sunxi.c
@@ -14,6 +14,7 @@
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -584,7 +585,7 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
spin_lock_irqsave(&pctl->lock, flags);
regval = readl(pctl->membase + reg);
- regval &= ~IRQ_CFG_IRQ_MASK;
+ regval &= ~(IRQ_CFG_IRQ_MASK << index);
writel(regval | (mode << index), pctl->membase + reg);
spin_unlock_irqrestore(&pctl->lock, flags);
@@ -665,6 +666,7 @@ static struct irq_chip sunxi_pinctrl_irq_chip = {
static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = irq_get_chip(irq);
struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);
@@ -674,10 +676,12 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
if (reg) {
int irqoffset;
+ chained_irq_enter(chip, desc);
for_each_set_bit(irqoffset, &reg, SUNXI_IRQ_NUMBER) {
int pin_irq = irq_find_mapping(pctl->domain, irqoffset);
generic_handle_irq(pin_irq);
}
+ chained_irq_exit(chip, desc);
}
}
diff --git a/drivers/pinctrl/pinctrl-sunxi.h b/drivers/pinctrl/pinctrl-sunxi.h
index 01c494f8a14f..552b0e97077a 100644
--- a/drivers/pinctrl/pinctrl-sunxi.h
+++ b/drivers/pinctrl/pinctrl-sunxi.h
@@ -511,7 +511,7 @@ static inline u32 sunxi_pull_offset(u16 pin)
static inline u32 sunxi_irq_cfg_reg(u16 irq)
{
- u8 reg = irq / IRQ_CFG_IRQ_PER_REG;
+ u8 reg = irq / IRQ_CFG_IRQ_PER_REG * 0x04;
return reg + IRQ_CFG_REG;
}
@@ -523,7 +523,7 @@ static inline u32 sunxi_irq_cfg_offset(u16 irq)
static inline u32 sunxi_irq_ctrl_reg(u16 irq)
{
- u8 reg = irq / IRQ_CTRL_IRQ_PER_REG;
+ u8 reg = irq / IRQ_CTRL_IRQ_PER_REG * 0x04;
return reg + IRQ_CTRL_REG;
}
@@ -535,7 +535,7 @@ static inline u32 sunxi_irq_ctrl_offset(u16 irq)
static inline u32 sunxi_irq_status_reg(u16 irq)
{
- u8 reg = irq / IRQ_STATUS_IRQ_PER_REG;
+ u8 reg = irq / IRQ_STATUS_IRQ_PER_REG * 0x04;
return reg + IRQ_STATUS_REG;
}
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index e767355ab0ad..65458096f41e 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -39,6 +39,7 @@ struct tegra_pmx {
struct pinctrl_dev *pctl;
const struct tegra_pinctrl_soc_data *soc;
+ const char **group_pins;
int nbanks;
void __iomem **regs;
@@ -620,6 +621,8 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
struct tegra_pmx *pmx;
struct resource *res;
int i;
+ const char **group_pins;
+ int fn, gn, gfn;
pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
if (!pmx) {
@@ -629,6 +632,41 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
pmx->dev = &pdev->dev;
pmx->soc = soc_data;
+ /*
+ * Each mux group will appear in 4 functions' list of groups.
+ * This over-allocates slightly, since not all groups are mux groups.
+ */
+ pmx->group_pins = devm_kzalloc(&pdev->dev,
+ soc_data->ngroups * 4 * sizeof(*pmx->group_pins),
+ GFP_KERNEL);
+ if (!pmx->group_pins)
+ return -ENOMEM;
+
+ group_pins = pmx->group_pins;
+ for (fn = 0; fn < soc_data->nfunctions; fn++) {
+ struct tegra_function *func = &soc_data->functions[fn];
+
+ func->groups = group_pins;
+
+ for (gn = 0; gn < soc_data->ngroups; gn++) {
+ const struct tegra_pingroup *g = &soc_data->groups[gn];
+
+ if (g->mux_reg == -1)
+ continue;
+
+ for (gfn = 0; gfn < 4; gfn++)
+ if (g->funcs[gfn] == fn)
+ break;
+ if (gfn == 4)
+ continue;
+
+ BUG_ON(group_pins - pmx->group_pins >=
+ soc_data->ngroups * 4);
+ *group_pins++ = g->name;
+ func->ngroups++;
+ }
+ }
+
tegra_pinctrl_gpio_range.npins = pmx->soc->ngpios;
tegra_pinctrl_desc.name = dev_name(&pdev->dev);
tegra_pinctrl_desc.pins = pmx->soc->pins;
diff --git a/drivers/pinctrl/pinctrl-tegra.h b/drivers/pinctrl/pinctrl-tegra.h
index 817f7061dc4c..6053832d433e 100644
--- a/drivers/pinctrl/pinctrl-tegra.h
+++ b/drivers/pinctrl/pinctrl-tegra.h
@@ -72,7 +72,7 @@ enum tegra_pinconf_tristate {
*/
struct tegra_function {
const char *name;
- const char * const *groups;
+ const char **groups;
unsigned ngroups;
};
@@ -193,7 +193,7 @@ struct tegra_pinctrl_soc_data {
unsigned ngpios;
const struct pinctrl_pin_desc *pins;
unsigned npins;
- const struct tegra_function *functions;
+ struct tegra_function *functions;
unsigned nfunctions;
const struct tegra_pingroup *groups;
unsigned ngroups;
diff --git a/drivers/pinctrl/pinctrl-tegra114.c b/drivers/pinctrl/pinctrl-tegra114.c
index 93c9e3899d5e..63fe7619d3ff 100644
--- a/drivers/pinctrl/pinctrl-tegra114.c
+++ b/drivers/pinctrl/pinctrl-tegra114.c
@@ -1,10 +1,8 @@
/*
- * Pinctrl data and driver for the NVIDIA Tegra114 pinmux
+ * Pinctrl data for the NVIDIA Tegra114 pinmux
*
* Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved.
*
- * Author: Pritesh Raithatha <praithatha@nvidia.com>
- *
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
@@ -13,9 +11,6 @@
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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>
@@ -203,8 +198,8 @@
#define TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5 _GPIO(245)
/* All non-GPIO pins follow */
-#define NUM_GPIOS (TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5 + 1)
-#define _PIN(offset) (NUM_GPIOS + (offset))
+#define NUM_GPIOS (TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5 + 1)
+#define _PIN(offset) (NUM_GPIOS + (offset))
/* Non-GPIO pins */
#define TEGRA_PIN_CORE_PWR_REQ _PIN(0)
@@ -212,8 +207,11 @@
#define TEGRA_PIN_PWR_INT_N _PIN(2)
#define TEGRA_PIN_RESET_OUT_N _PIN(3)
#define TEGRA_PIN_OWR _PIN(4)
+#define TEGRA_PIN_JTAG_RTCK _PIN(5)
+#define TEGRA_PIN_CLK_32K_IN _PIN(6)
+#define TEGRA_PIN_GMI_CLK_LB _PIN(7)
-static const struct pinctrl_pin_desc tegra114_pins[] = {
+static const struct pinctrl_pin_desc tegra114_pins[] = {
PINCTRL_PIN(TEGRA_PIN_CLK_32K_OUT_PA0, "CLK_32K_OUT PA0"),
PINCTRL_PIN(TEGRA_PIN_UART3_CTS_N_PA1, "UART3_CTS_N PA1"),
PINCTRL_PIN(TEGRA_PIN_DAP2_FS_PA2, "DAP2_FS PA2"),
@@ -385,9 +383,12 @@ static const struct pinctrl_pin_desc tegra114_pins[] = {
PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5, "SDMMC3_CLK_LB_IN PEE5"),
PINCTRL_PIN(TEGRA_PIN_CORE_PWR_REQ, "CORE_PWR_REQ"),
PINCTRL_PIN(TEGRA_PIN_CPU_PWR_REQ, "CPU_PWR_REQ"),
- PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
PINCTRL_PIN(TEGRA_PIN_PWR_INT_N, "PWR_INT_N"),
PINCTRL_PIN(TEGRA_PIN_RESET_OUT_N, "RESET_OUT_N"),
+ PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
+ PINCTRL_PIN(TEGRA_PIN_JTAG_RTCK, "JTAG_RTCK"),
+ PINCTRL_PIN(TEGRA_PIN_CLK_32K_IN, "CLK_32K_IN"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_CLK_LB, "GMI_CLK_LB"),
};
static const unsigned clk_32k_out_pa0_pins[] = {
@@ -1074,10 +1075,6 @@ static const unsigned cpu_pwr_req_pins[] = {
TEGRA_PIN_CPU_PWR_REQ,
};
-static const unsigned owr_pins[] = {
- TEGRA_PIN_OWR,
-};
-
static const unsigned pwr_int_n_pins[] = {
TEGRA_PIN_PWR_INT_N,
};
@@ -1086,6 +1083,22 @@ static const unsigned reset_out_n_pins[] = {
TEGRA_PIN_RESET_OUT_N,
};
+static const unsigned owr_pins[] = {
+ TEGRA_PIN_OWR,
+};
+
+static const unsigned jtag_rtck_pins[] = {
+ TEGRA_PIN_JTAG_RTCK,
+};
+
+static const unsigned clk_32k_in_pins[] = {
+ TEGRA_PIN_CLK_32K_IN,
+};
+
+static const unsigned gmi_clk_lb_pins[] = {
+ TEGRA_PIN_GMI_CLK_LB,
+};
+
static const unsigned drive_ao1_pins[] = {
TEGRA_PIN_KB_ROW0_PR0,
TEGRA_PIN_KB_ROW1_PR1,
@@ -1127,7 +1140,6 @@ static const unsigned drive_at1_pins[] = {
TEGRA_PIN_GMI_AD13_PH5,
TEGRA_PIN_GMI_AD14_PH6,
TEGRA_PIN_GMI_AD15_PH7,
-
TEGRA_PIN_GMI_IORDY_PI5,
TEGRA_PIN_GMI_CS7_N_PI6,
};
@@ -1141,15 +1153,12 @@ static const unsigned drive_at2_pins[] = {
TEGRA_PIN_GMI_AD5_PG5,
TEGRA_PIN_GMI_AD6_PG6,
TEGRA_PIN_GMI_AD7_PG7,
-
TEGRA_PIN_GMI_WR_N_PI0,
TEGRA_PIN_GMI_OE_N_PI1,
TEGRA_PIN_GMI_CS6_N_PI3,
TEGRA_PIN_GMI_RST_N_PI4,
TEGRA_PIN_GMI_WAIT_PI7,
-
TEGRA_PIN_GMI_DQS_P_PJ3,
-
TEGRA_PIN_GMI_ADV_N_PK0,
TEGRA_PIN_GMI_CLK_PK1,
TEGRA_PIN_GMI_CS4_N_PK2,
@@ -1342,14 +1351,37 @@ static const unsigned drive_uda_pins[] = {
};
static const unsigned drive_dev3_pins[] = {
- TEGRA_PIN_CLK3_OUT_PEE0,
- TEGRA_PIN_CLK3_REQ_PEE1,
+};
+
+static const unsigned drive_cec_pins[] = {
+};
+
+static const unsigned drive_at6_pins[] = {
+};
+
+static const unsigned drive_dap5_pins[] = {
+};
+
+static const unsigned drive_usb_vbus_en_pins[] = {
+};
+
+static const unsigned drive_ao3_pins[] = {
+};
+
+static const unsigned drive_hv0_pins[] = {
+};
+
+static const unsigned drive_sdio4_pins[] = {
+};
+
+static const unsigned drive_ao0_pins[] = {
};
enum tegra_mux {
TEGRA_MUX_BLINK,
TEGRA_MUX_CEC,
TEGRA_MUX_CLDVFS,
+ TEGRA_MUX_CLK,
TEGRA_MUX_CLK12,
TEGRA_MUX_CPU,
TEGRA_MUX_DAP,
@@ -1394,6 +1426,7 @@ enum tegra_mux {
TEGRA_MUX_RSVD2,
TEGRA_MUX_RSVD3,
TEGRA_MUX_RSVD4,
+ TEGRA_MUX_RTCK,
TEGRA_MUX_SDMMC1,
TEGRA_MUX_SDMMC2,
TEGRA_MUX_SDMMC3,
@@ -1425,944 +1458,16 @@ enum tegra_mux {
TEGRA_MUX_VI_ALT3,
};
-static const char * const blink_groups[] = {
- "clk_32k_out_pa0",
-};
-
-static const char * const cec_groups[] = {
- "hdmi_cec_pee3",
-};
-
-static const char * const cldvfs_groups[] = {
- "gmi_ad9_ph1",
- "gmi_ad10_ph2",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "dvfs_pwm_px0",
- "dvfs_clk_px2",
-};
-
-static const char * const clk12_groups[] = {
- "sdmmc1_wp_n_pv3",
- "sdmmc1_clk_pz0",
-};
-
-static const char * const cpu_groups[] = {
- "cpu_pwr_req",
-};
-
-static const char * const dap_groups[] = {
- "clk1_req_pee2",
- "clk2_req_pcc5",
-};
-
-static const char * const dap1_groups[] = {
- "clk1_req_pee2",
-};
-
-static const char * const dap2_groups[] = {
- "clk1_out_pw4",
- "gpio_x4_aud_px4",
-};
-
-static const char * const dev3_groups[] = {
- "clk3_req_pee1",
-};
-
-static const char * const displaya_groups[] = {
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_sclk_pp3",
- "uart3_rts_n_pc0",
- "pu3",
- "pu4",
- "pu5",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "kb_col3_pq3",
- "sdmmc3_dat2_pb5",
-};
-
-static const char * const displaya_alt_groups[] = {
- "kb_row6_pr6",
-};
-
-static const char * const displayb_groups[] = {
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_sclk_pp3",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "sdmmc3_dat3_pb4",
-};
-
-static const char * const dtv_groups[] = {
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
- "dap4_fs_pp4",
- "dap4_dout_pp6",
- "gmi_wait_pi7",
- "gmi_ad8_ph0",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
-};
-
-static const char * const emc_dll_groups[] = {
- "kb_col0_pq0",
- "kb_col1_pq1",
-};
-
-static const char * const extperiph1_groups[] = {
- "clk1_out_pw4",
-};
-
-static const char * const extperiph2_groups[] = {
- "clk2_out_pw5",
-};
-
-static const char * const extperiph3_groups[] = {
- "clk3_out_pee0",
-};
-
-static const char * const gmi_groups[] = {
- "gmi_wp_n_pc7",
-
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_ad8_ph0",
- "gmi_ad9_ph1",
- "gmi_ad10_ph2",
- "gmi_ad11_ph3",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_wr_n_pi0",
- "gmi_oe_n_pi1",
- "gmi_cs6_n_pi3",
- "gmi_rst_n_pi4",
- "gmi_iordy_pi5",
- "gmi_cs7_n_pi6",
- "gmi_wait_pi7",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
- "gmi_dqs_p_pj3",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs4_n_pk2",
- "gmi_cs2_n_pk3",
- "gmi_cs3_n_pk4",
- "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7",
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
-};
-
-static const char * const gmi_alt_groups[] = {
- "gmi_wp_n_pc7",
- "gmi_cs3_n_pk4",
- "gmi_a16_pj7",
-};
-
-static const char * const hda_groups[] = {
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
-};
-
-static const char * const hsi_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-};
-
-static const char * const i2c1_groups[] = {
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "gpio_w2_aud_pw2",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const i2c2_groups[] = {
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
-};
-
-static const char * const i2c3_groups[] = {
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
-};
-
-static const char * const i2c4_groups[] = {
- "ddc_scl_pv4",
- "ddc_sda_pv5",
-};
-
-static const char * const i2cpwr_groups[] = {
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
-};
-
-static const char * const i2s0_groups[] = {
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
-};
-
-static const char * const i2s1_groups[] = {
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
-};
-
-static const char * const i2s2_groups[] = {
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_sclk_pp3",
-};
-
-static const char * const i2s3_groups[] = {
- "dap4_fs_pp4",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_sclk_pp7",
-};
-
-static const char * const i2s4_groups[] = {
- "pcc1",
- "pbb0",
- "pbb7",
- "pcc2",
-};
-
-static const char * const irda_groups[] = {
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
-};
-
-static const char * const kbc_groups[] = {
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
-};
-
-static const char * const nand_groups[] = {
- "gmi_wp_n_pc7",
- "gmi_wait_pi7",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
- "gmi_cs2_n_pk3",
- "gmi_cs3_n_pk4",
- "gmi_cs4_n_pk2",
- "gmi_cs6_n_pi3",
- "gmi_cs7_n_pi6",
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_ad8_ph0",
- "gmi_ad9_ph1",
- "gmi_ad10_ph2",
- "gmi_ad11_ph3",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_wr_n_pi0",
- "gmi_oe_n_pi1",
- "gmi_dqs_p_pj3",
- "gmi_rst_n_pi4",
-};
-
-static const char * const nand_alt_groups[] = {
- "gmi_cs6_n_pi3",
- "gmi_cs7_n_pi6",
- "gmi_rst_n_pi4",
-};
-
-static const char * const owr_groups[] = {
- "pu0",
- "kb_col4_pq4",
- "owr",
- "sdmmc3_cd_n_pv2",
-};
-
-static const char * const pmi_groups[] = {
- "pwr_int_n",
-};
-
-static const char * const pwm0_groups[] = {
- "sdmmc1_dat2_py5",
- "uart3_rts_n_pc0",
- "pu3",
- "gmi_ad8_ph0",
- "sdmmc3_dat3_pb4",
-};
-
-static const char * const pwm1_groups[] = {
- "sdmmc1_dat1_py6",
- "pu4",
- "gmi_ad9_ph1",
- "sdmmc3_dat2_pb5",
-};
-
-static const char * const pwm2_groups[] = {
- "pu5",
- "gmi_ad10_ph2",
- "kb_col3_pq3",
- "sdmmc3_dat1_pb6",
-};
-
-static const char * const pwm3_groups[] = {
- "pu6",
- "gmi_ad11_ph3",
- "sdmmc3_cmd_pa7",
-};
-
-static const char * const pwron_groups[] = {
- "core_pwr_req",
-};
-
-static const char * const reset_out_n_groups[] = {
- "reset_out_n",
-};
-
-static const char * const rsvd1_groups[] = {
- "pv1",
- "hdmi_int_pn7",
- "pu1",
- "pu2",
- "gmi_wp_n_pc7",
- "gmi_adv_n_pk0",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_wr_n_pi0",
- "gmi_oe_n_pi1",
- "gpio_x4_aud_px4",
- "gpio_x5_aud_px5",
- "gpio_x7_aud_px7",
-
- "reset_out_n",
-};
-
-static const char * const rsvd2_groups[] = {
- "pv0",
- "pv1",
- "sdmmc1_dat0_py7",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "hdmi_int_pn7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "dap4_fs_pp4",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_sclk_pp7",
- "clk3_out_pee0",
- "clk3_req_pee1",
- "gmi_iordy_pi5",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat7_paa7",
- "pcc1",
- "pbb7",
- "pcc2",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "sys_clk_req_pz5",
- "core_pwr_req",
- "cpu_pwr_req",
- "pwr_int_n",
- "owr",
- "spdif_out_pk5",
- "gpio_x1_aud_px1",
- "sdmmc3_clk_pa6",
- "sdmmc3_dat0_pb7",
- "gpio_w2_aud_pw2",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "sdmmc3_clk_lb_out_pee4",
- "sdmmc3_clk_lb_in_pee5",
- "reset_out_n",
-};
-
-static const char * const rsvd3_groups[] = {
- "pv0",
- "pv1",
- "sdmmc1_clk_pz0",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "hdmi_int_pn7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
- "pu0",
- "pu1",
- "pu2",
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "dap4_din_pp5",
- "dap4_sclk_pp7",
- "clk3_out_pee0",
- "clk3_req_pee1",
- "pcc1",
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "pbb7",
- "pcc2",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row3_pr3",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "clk_32k_out_pa0",
- "sys_clk_req_pz5",
- "core_pwr_req",
- "cpu_pwr_req",
- "pwr_int_n",
- "owr",
- "clk1_req_pee2",
- "clk1_out_pw4",
- "spdif_out_pk5",
- "spdif_in_pk6",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dvfs_pwm_px0",
- "gpio_x1_aud_px1",
- "gpio_x3_aud_px3",
- "dvfs_clk_px2",
- "sdmmc3_clk_pa6",
- "sdmmc3_dat0_pb7",
- "hdmi_cec_pee3",
- "sdmmc3_cd_n_pv2",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "sdmmc3_clk_lb_out_pee4",
- "sdmmc3_clk_lb_in_pee5",
- "reset_out_n",
-};
-
-static const char * const rsvd4_groups[] = {
- "pv0",
- "pv1",
- "sdmmc1_clk_pz0",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "hdmi_int_pn7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
- "pu0",
- "pu1",
- "pu2",
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "dap4_fs_pp4",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_sclk_pp7",
- "clk3_out_pee0",
- "clk3_req_pee1",
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_rst_n_pi4",
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
- "cam_mclk_pcc0",
- "pcc1",
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "pbb7",
- "pcc2",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_col2_pq2",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "clk_32k_out_pa0",
- "sys_clk_req_pz5",
- "core_pwr_req",
- "cpu_pwr_req",
- "pwr_int_n",
- "owr",
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
- "clk1_req_pee2",
- "clk1_out_pw4",
- "spdif_in_pk6",
- "spdif_out_pk5",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dvfs_pwm_px0",
- "gpio_x1_aud_px1",
- "gpio_x3_aud_px3",
- "dvfs_clk_px2",
- "gpio_x5_aud_px5",
- "gpio_x6_aud_px6",
- "gpio_x7_aud_px7",
- "sdmmc3_cd_n_pv2",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "sdmmc3_clk_lb_in_pee5",
- "sdmmc3_clk_lb_out_pee4",
-};
-
-static const char * const sdmmc1_groups[] = {
-
- "sdmmc1_clk_pz0",
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat0_py7",
- "uart3_cts_n_pa1",
- "kb_col5_pq5",
- "sdmmc1_wp_n_pv3",
-};
-
-static const char * const sdmmc2_groups[] = {
- "gmi_iordy_pi5",
- "gmi_clk_pk1",
- "gmi_cs2_n_pk3",
- "gmi_cs3_n_pk4",
- "gmi_cs7_n_pi6",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_dqs_p_pj3",
-};
-
-static const char * const sdmmc3_groups[] = {
- "kb_col4_pq4",
- "sdmmc3_clk_pa6",
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
- "hdmi_cec_pee3",
- "sdmmc3_cd_n_pv2",
- "sdmmc3_clk_lb_in_pee5",
- "sdmmc3_clk_lb_out_pee4",
-};
-
-static const char * const sdmmc4_groups[] = {
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
-};
-
-static const char * const soc_groups[] = {
- "gmi_cs1_n_pj2",
- "gmi_oe_n_pi1",
- "clk_32k_out_pa0",
- "hdmi_cec_pee3",
-};
-
-static const char * const spdif_groups[] = {
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "spdif_in_pk6",
- "spdif_out_pk5",
-};
-
-static const char * const spi1_groups[] = {
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "gpio_x3_aud_px3",
- "gpio_x4_aud_px4",
- "gpio_x5_aud_px5",
- "gpio_x6_aud_px6",
- "gpio_x7_aud_px7",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const spi2_groups[] = {
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "gpio_x4_aud_px4",
- "gpio_x5_aud_px5",
- "gpio_x6_aud_px6",
- "gpio_x7_aud_px7",
- "gpio_w2_aud_pw2",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const spi3_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc3_clk_pa6",
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
-};
-
-static const char * const spi4_groups[] = {
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat0_py7",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
- "uart3_cts_n_pa1",
- "gmi_wait_pi7",
- "gmi_cs6_n_pi3",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_a19_pk7",
- "gmi_wr_n_pi0",
- "sdmmc1_wp_n_pv3",
-};
-
-static const char * const spi5_groups[] = {
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_sclk_pp3",
-};
-
-static const char * const spi6_groups[] = {
- "dvfs_pwm_px0",
- "gpio_x1_aud_px1",
- "gpio_x3_aud_px3",
- "dvfs_clk_px2",
- "gpio_x6_aud_px6",
- "gpio_w2_aud_pw2",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const sysclk_groups[] = {
- "sys_clk_req_pz5",
-};
-
-static const char * const trace_groups[] = {
- "gmi_iordy_pi5",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs2_n_pk3",
- "gmi_cs4_n_pk2",
- "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7",
- "gmi_dqs_p_pj3",
-};
-
-static const char * const uarta_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat0_py7",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
- "pu0",
- "pu1",
- "pu2",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat1_pb6",
- "sdmmc1_wp_n_pv3",
-};
-
-static const char * const uartb_groups[] = {
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
-};
-
-static const char * const uartc_groups[] = {
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
-};
-
-static const char * const uartd_groups[] = {
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7",
-};
-
-static const char * const ulpi_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
-};
-
-static const char * const usb_groups[] = {
- "pv0",
- "pu6",
- "gmi_cs0_n_pj0",
- "gmi_cs4_n_pk2",
- "gmi_ad11_ph3",
- "kb_col0_pq0",
- "spdif_in_pk6",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
-};
-
-static const char * const vgp1_groups[] = {
- "cam_i2c_scl_pbb1",
-};
-
-static const char * const vgp2_groups[] = {
- "cam_i2c_sda_pbb2",
-};
-
-static const char * const vgp3_groups[] = {
- "pbb3",
-};
-
-static const char * const vgp4_groups[] = {
- "pbb4",
-};
-
-static const char * const vgp5_groups[] = {
- "pbb5",
-};
-
-static const char * const vgp6_groups[] = {
- "pbb6",
-};
-
-static const char * const vi_groups[] = {
- "cam_mclk_pcc0",
- "pbb0",
-};
-
-static const char * const vi_alt1_groups[] = {
- "cam_mclk_pcc0",
- "pbb0",
-};
-
-static const char * const vi_alt3_groups[] = {
- "cam_mclk_pcc0",
- "pbb0",
-};
-
#define FUNCTION(fname) \
{ \
.name = #fname, \
- .groups = fname##_groups, \
- .ngroups = ARRAY_SIZE(fname##_groups), \
}
-static const struct tegra_function tegra114_functions[] = {
+static struct tegra_function tegra114_functions[] = {
FUNCTION(blink),
FUNCTION(cec),
FUNCTION(cldvfs),
+ FUNCTION(clk),
FUNCTION(clk12),
FUNCTION(cpu),
FUNCTION(dap),
@@ -2407,6 +1512,7 @@ static const struct tegra_function tegra114_functions[] = {
FUNCTION(rsvd2),
FUNCTION(rsvd3),
FUNCTION(rsvd4),
+ FUNCTION(rtck),
FUNCTION(sdmmc1),
FUNCTION(sdmmc2),
FUNCTION(sdmmc3),
@@ -2438,11 +1544,11 @@ static const struct tegra_function tegra114_functions[] = {
FUNCTION(vi_alt3),
};
-#define DRV_PINGROUP_REG_START 0x868 /* bank 0 */
-#define PINGROUP_REG_START 0x3000 /* bank 1 */
+#define DRV_PINGROUP_REG_A 0x868 /* bank 0 */
+#define PINGROUP_REG_A 0x3000 /* bank 1 */
-#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_START)
-#define PINGROUP_REG_N(r) -1
+#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A)
+#define PINGROUP_REG_N(r) -1
#define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior, rcv_sel) \
{ \
@@ -2484,13 +1590,14 @@ static const struct tegra_function tegra114_functions[] = {
.drvtype_reg = -1, \
}
-#define DRV_PINGROUP_DVRTYPE_Y(r) ((r) - DRV_PINGROUP_REG_START)
-#define DRV_PINGROUP_DVRTYPE_N(r) -1
+#define DRV_PINGROUP_REG_Y(r) ((r) - DRV_PINGROUP_REG_A)
+#define DRV_PINGROUP_REG_N(r) -1
+
#define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, \
- drvdn_b, drvdn_w, drvup_b, drvup_w, \
- slwr_b, slwr_w, slwf_b, slwf_w, \
- drvtype) \
+ drvdn_b, drvdn_w, drvup_b, drvup_w, \
+ slwr_b, slwr_w, slwf_b, slwf_w, \
+ drvtype) \
{ \
.name = "drive_" #pg_name, \
.pins = drive_##pg_name##_pins, \
@@ -2503,7 +1610,7 @@ static const struct tegra_function tegra114_functions[] = {
.lock_reg = -1, \
.ioreset_reg = -1, \
.rcv_sel_reg = -1, \
- .drv_reg = DRV_PINGROUP_DVRTYPE_Y(r), \
+ .drv_reg = DRV_PINGROUP_REG_Y(r), \
.drv_bank = 0, \
.hsm_bit = hsm_b, \
.schmitt_bit = schmitt_b, \
@@ -2516,14 +1623,13 @@ static const struct tegra_function tegra114_functions[] = {
.slwr_width = slwr_w, \
.slwf_bit = slwf_b, \
.slwf_width = slwf_w, \
- .drvtype_reg = DRV_PINGROUP_DVRTYPE_##drvtype(r), \
+ .drvtype_reg = DRV_PINGROUP_REG_##drvtype(r), \
.drvtype_bank = 0, \
.drvtype_bit = 6, \
}
static const struct tegra_pingroup tegra114_groups[] = {
/* pg_name, f0, f1, f2, f3, safe, r, od, ior, rcv_sel */
- /* FIXME: Fill in correct data in safe column */
PINGROUP(ulpi_data0_po1, SPI3, HSI, UARTA, ULPI, ULPI, 0x3000, N, N, N),
PINGROUP(ulpi_data1_po2, SPI3, HSI, UARTA, ULPI, ULPI, 0x3004, N, N, N),
PINGROUP(ulpi_data2_po3, SPI3, HSI, UARTA, ULPI, ULPI, 0x3008, N, N, N),
@@ -2635,6 +1741,7 @@ static const struct tegra_pingroup tegra114_groups[] = {
PINGROUP(pbb6, VGP6, DISPLAYA, DISPLAYB, RSVD4, RSVD4, 0x32a4, N, N, N),
PINGROUP(pbb7, I2S4, RSVD2, RSVD3, RSVD4, RSVD4, 0x32a8, N, N, N),
PINGROUP(pcc2, I2S4, RSVD2, RSVD3, RSVD4, RSVD4, 0x32ac, N, N, N),
+ PINGROUP(jtag_rtck, RTCK, RSVD2, RSVD3, RSVD4, RTCK, 0x32b0, N, N, N),
PINGROUP(pwr_i2c_scl_pz6, I2CPWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x32b4, Y, N, N),
PINGROUP(pwr_i2c_sda_pz7, I2CPWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x32b8, Y, N, N),
PINGROUP(kb_row0_pr0, KBC, RSVD2, RSVD3, RSVD4, RSVD4, 0x32bc, N, N, N),
@@ -2661,6 +1768,7 @@ static const struct tegra_pingroup tegra114_groups[] = {
PINGROUP(core_pwr_req, PWRON, RSVD2, RSVD3, RSVD4, RSVD4, 0x3324, N, N, N),
PINGROUP(cpu_pwr_req, CPU, RSVD2, RSVD3, RSVD4, RSVD4, 0x3328, N, N, N),
PINGROUP(pwr_int_n, PMI, RSVD2, RSVD3, RSVD4, RSVD4, 0x332c, N, N, N),
+ PINGROUP(clk_32k_in, CLK, RSVD2, RSVD3, RSVD4, CLK, 0x3330, N, N, N),
PINGROUP(owr, OWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x3334, N, N, Y),
PINGROUP(dap1_fs_pn0, I2S0, HDA, GMI, RSVD4, RSVD4, 0x3338, N, N, N),
PINGROUP(dap1_din_pn1, I2S0, HDA, GMI, RSVD4, RSVD4, 0x333c, N, N, N),
@@ -2697,38 +1805,48 @@ static const struct tegra_pingroup tegra114_groups[] = {
PINGROUP(usb_vbus_en1_pn5, USB, RSVD2, RSVD3, RSVD4, RSVD4, 0x33f8, Y, N, N),
PINGROUP(sdmmc3_clk_lb_in_pee5, SDMMC3, RSVD2, RSVD3, RSVD4, RSVD4, 0x33fc, N, N, N),
PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3, RSVD2, RSVD3, RSVD4, RSVD4, 0x3400, N, N, N),
+ PINGROUP(gmi_clk_lb, SDMMC2, NAND, GMI, RSVD4, GMI, 0x3404, N, N, N),
PINGROUP(reset_out_n, RSVD1, RSVD2, RSVD3, RESET_OUT_N, RSVD3, 0x3408, N, N, N),
/* pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w, drvtype */
- DRV_PINGROUP(ao1, 0x868, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(ao2, 0x86c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(at1, 0x870, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y),
- DRV_PINGROUP(at2, 0x874, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y),
- DRV_PINGROUP(at3, 0x878, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y),
- DRV_PINGROUP(at4, 0x87c, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y),
- DRV_PINGROUP(at5, 0x880, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(cdev1, 0x884, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(cdev2, 0x888, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(dap1, 0x890, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(dap2, 0x894, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(dap3, 0x898, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(dap4, 0x89c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(dbg, 0x8a0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(sdio3, 0x8b0, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N),
- DRV_PINGROUP(spi, 0x8b4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(uaa, 0x8b8, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(uab, 0x8bc, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(uart2, 0x8c0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(uart3, 0x8c4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(sdio1, 0x8ec, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N),
- DRV_PINGROUP(ddc, 0x8fc, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(gma, 0x900, 2, 3, 4, 14, 5, 20, 5, 28, 2, 30, 2, Y),
- DRV_PINGROUP(gme, 0x910, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(gmf, 0x914, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(gmg, 0x918, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(gmh, 0x91c, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(owr, 0x920, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
- DRV_PINGROUP(uda, 0x924, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(ao1, 0x868, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(ao2, 0x86c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(at1, 0x870, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(at2, 0x874, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(at3, 0x878, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(at4, 0x87c, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(at5, 0x880, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(cdev1, 0x884, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(cdev2, 0x888, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dap1, 0x890, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dap2, 0x894, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dap3, 0x898, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dap4, 0x89c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dbg, 0x8a0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(sdio3, 0x8b0, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N),
+ DRV_PINGROUP(spi, 0x8b4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uaa, 0x8b8, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uab, 0x8bc, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uart2, 0x8c0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uart3, 0x8c4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(sdio1, 0x8ec, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N),
+ DRV_PINGROUP(ddc, 0x8fc, 2, 3, -1, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gma, 0x900, 2, 3, -1, 14, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gme, 0x910, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gmf, 0x914, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gmg, 0x918, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gmh, 0x91c, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(owr, 0x920, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uda, 0x924, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dev3, 0x92c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(cec, 0x938, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(at6, 0x994, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(dap5, 0x998, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(usb_vbus_en, 0x99c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(ao3, 0x9a0, 2, 3, 4, 12, 5, -1, -1, 28, 2, -1, -1, N),
+ DRV_PINGROUP(hv0, 0x9a4, 2, 3, 4, 12, 5, -1, -1, 28, 2, -1, -1, N),
+ DRV_PINGROUP(sdio4, 0x9a8, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(ao0, 0x9ac, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
};
static const struct tegra_pinctrl_soc_data tegra114_pinctrl = {
diff --git a/drivers/pinctrl/pinctrl-tegra124.c b/drivers/pinctrl/pinctrl-tegra124.c
index c20e0e1dda83..73773706755b 100644
--- a/drivers/pinctrl/pinctrl-tegra124.c
+++ b/drivers/pinctrl/pinctrl-tegra124.c
@@ -1,7 +1,7 @@
/*
* Pinctrl data for the NVIDIA Tegra124 pinmux
*
- * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -212,8 +212,8 @@
#define TEGRA_PIN_PFF2 _GPIO(250)
/* All non-GPIO pins follow */
-#define NUM_GPIOS (TEGRA_PIN_PFF2 + 1)
-#define _PIN(offset) (NUM_GPIOS + (offset))
+#define NUM_GPIOS (TEGRA_PIN_PFF2 + 1)
+#define _PIN(offset) (NUM_GPIOS + (offset))
/* Non-GPIO pins */
#define TEGRA_PIN_CORE_PWR_REQ _PIN(0)
@@ -325,13 +325,13 @@ static const struct pinctrl_pin_desc tegra124_pins[] = {
PINCTRL_PIN(TEGRA_PIN_KB_ROW8_PS0, "KB_ROW8 PS0"),
PINCTRL_PIN(TEGRA_PIN_KB_ROW9_PS1, "KB_ROW9 PS1"),
PINCTRL_PIN(TEGRA_PIN_KB_ROW10_PS2, "KB_ROW10 PS2"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW11_PS3, "KB_ROW10 PS3"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW12_PS4, "KB_ROW10 PS4"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW13_PS5, "KB_ROW10 PS5"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW14_PS6, "KB_ROW10 PS6"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW15_PS7, "KB_ROW10 PS7"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW16_PT0, "KB_ROW10 PT0"),
- PINCTRL_PIN(TEGRA_PIN_KB_ROW17_PT1, "KB_ROW10 PT1"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW11_PS3, "KB_ROW11 PS3"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW12_PS4, "KB_ROW12 PS4"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW13_PS5, "KB_ROW13 PS5"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW14_PS6, "KB_ROW14 PS6"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW15_PS7, "KB_ROW15 PS7"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW16_PT0, "KB_ROW16 PT0"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW17_PT1, "KB_ROW17 PT1"),
PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SCL_PT5, "GEN2_I2C_SCL PT5"),
PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SDA_PT6, "GEN2_I2C_SDA PT6"),
PINCTRL_PIN(TEGRA_PIN_SDMMC4_CMD_PT7, "SDMMC4_CMD PT7"),
@@ -406,16 +406,16 @@ static const struct pinctrl_pin_desc tegra124_pins[] = {
PINCTRL_PIN(TEGRA_PIN_HDMI_CEC_PEE3, "HDMI_CEC PEE3"),
PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_LB_OUT_PEE4, "SDMMC3_CLK_LB_OUT PEE4"),
PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5, "SDMMC3_CLK_LB_IN PEE5"),
+ PINCTRL_PIN(TEGRA_PIN_DP_HPD_PFF0, "DP_HPD PFF0"),
+ PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN2_PFF1, "USB_VBUS_EN2 PFF1"),
+ PINCTRL_PIN(TEGRA_PIN_PFF2, "PFF2"),
PINCTRL_PIN(TEGRA_PIN_CORE_PWR_REQ, "CORE_PWR_REQ"),
PINCTRL_PIN(TEGRA_PIN_CPU_PWR_REQ, "CPU_PWR_REQ"),
- PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
PINCTRL_PIN(TEGRA_PIN_PWR_INT_N, "PWR_INT_N"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_CLK_LB, "GMI_CLK_LB"),
PINCTRL_PIN(TEGRA_PIN_RESET_OUT_N, "RESET_OUT_N"),
- PINCTRL_PIN(TEGRA_PIN_DP_HPD_PFF0, "DP_HPD PFF0"),
- PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN2_PFF1, "USB_VBUS_EN2 PFF1"),
- PINCTRL_PIN(TEGRA_PIN_PFF2, "PFF2"),
+ PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
PINCTRL_PIN(TEGRA_PIN_CLK_32K_IN, "CLK_32K_IN"),
- PINCTRL_PIN(TEGRA_PIN_GMI_CLK_LB, "GMI_CLK_LB"),
PINCTRL_PIN(TEGRA_PIN_JTAG_RTCK, "JTAG_RTCK"),
};
@@ -1138,6 +1138,7 @@ static const unsigned sdmmc3_clk_lb_out_pee4_pins[] = {
static const unsigned sdmmc3_clk_lb_in_pee5_pins[] = {
TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5,
};
+
static const unsigned dp_hpd_pff0_pins[] = {
TEGRA_PIN_DP_HPD_PFF0,
};
@@ -1158,24 +1159,24 @@ static const unsigned cpu_pwr_req_pins[] = {
TEGRA_PIN_CPU_PWR_REQ,
};
-static const unsigned owr_pins[] = {
- TEGRA_PIN_OWR,
-};
-
static const unsigned pwr_int_n_pins[] = {
TEGRA_PIN_PWR_INT_N,
};
+static const unsigned gmi_clk_lb_pins[] = {
+ TEGRA_PIN_GMI_CLK_LB,
+};
+
static const unsigned reset_out_n_pins[] = {
TEGRA_PIN_RESET_OUT_N,
};
-static const unsigned clk_32k_in_pins[] = {
- TEGRA_PIN_CLK_32K_IN,
+static const unsigned owr_pins[] = {
+ TEGRA_PIN_OWR,
};
-static const unsigned gmi_clk_lb_pins[] = {
- TEGRA_PIN_GMI_CLK_LB,
+static const unsigned clk_32k_in_pins[] = {
+ TEGRA_PIN_CLK_32K_IN,
};
static const unsigned jtag_rtck_pins[] = {
@@ -1441,15 +1442,15 @@ static const unsigned drive_gpv_pins[] = {
TEGRA_PIN_PFF2,
};
-static const unsigned drive_cec_pins[] = {
- TEGRA_PIN_HDMI_CEC_PEE3,
-};
-
static const unsigned drive_dev3_pins[] = {
TEGRA_PIN_CLK3_OUT_PEE0,
TEGRA_PIN_CLK3_REQ_PEE1,
};
+static const unsigned drive_cec_pins[] = {
+ TEGRA_PIN_HDMI_CEC_PEE3,
+};
+
static const unsigned drive_at6_pins[] = {
TEGRA_PIN_PK1,
TEGRA_PIN_PK3,
@@ -1496,8 +1497,10 @@ static const unsigned drive_ao4_pins[] = {
enum tegra_mux {
TEGRA_MUX_BLINK,
+ TEGRA_MUX_CCLA,
TEGRA_MUX_CEC,
TEGRA_MUX_CLDVFS,
+ TEGRA_MUX_CLK,
TEGRA_MUX_CLK12,
TEGRA_MUX_CPU,
TEGRA_MUX_DAP,
@@ -1507,6 +1510,7 @@ enum tegra_mux {
TEGRA_MUX_DISPLAYA,
TEGRA_MUX_DISPLAYA_ALT,
TEGRA_MUX_DISPLAYB,
+ TEGRA_MUX_DP,
TEGRA_MUX_DTV,
TEGRA_MUX_EXTPERIPH1,
TEGRA_MUX_EXTPERIPH2,
@@ -1528,6 +1532,9 @@ enum tegra_mux {
TEGRA_MUX_IRDA,
TEGRA_MUX_KBC,
TEGRA_MUX_OWR,
+ TEGRA_MUX_PE,
+ TEGRA_MUX_PE0,
+ TEGRA_MUX_PE1,
TEGRA_MUX_PMI,
TEGRA_MUX_PWM0,
TEGRA_MUX_PWM1,
@@ -1539,6 +1546,8 @@ enum tegra_mux {
TEGRA_MUX_RSVD2,
TEGRA_MUX_RSVD3,
TEGRA_MUX_RSVD4,
+ TEGRA_MUX_RTCK,
+ TEGRA_MUX_SATA,
TEGRA_MUX_SDMMC1,
TEGRA_MUX_SDMMC2,
TEGRA_MUX_SDMMC3,
@@ -1551,6 +1560,8 @@ enum tegra_mux {
TEGRA_MUX_SPI4,
TEGRA_MUX_SPI5,
TEGRA_MUX_SPI6,
+ TEGRA_MUX_SYS,
+ TEGRA_MUX_TMDS,
TEGRA_MUX_TRACE,
TEGRA_MUX_UARTA,
TEGRA_MUX_UARTB,
@@ -1569,1134 +1580,19 @@ enum tegra_mux {
TEGRA_MUX_VI_ALT3,
TEGRA_MUX_VIMCLK2,
TEGRA_MUX_VIMCLK2_ALT,
- TEGRA_MUX_SATA,
- TEGRA_MUX_CCLA,
- TEGRA_MUX_PE0,
- TEGRA_MUX_PE,
- TEGRA_MUX_PE1,
- TEGRA_MUX_DP,
- TEGRA_MUX_RTCK,
- TEGRA_MUX_SYS,
- TEGRA_MUX_CLK,
- TEGRA_MUX_TMDS,
-};
-
-static const char * const blink_groups[] = {
- "clk_32k_out_pa0",
-};
-
-static const char * const cec_groups[] = {
- "hdmi_cec_pee3",
-};
-
-static const char * const cldvfs_groups[] = {
- "ph2",
- "ph3",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "dvfs_pwm_px0",
- "dvfs_clk_px2",
-};
-
-static const char * const clk12_groups[] = {
- "sdmmc1_wp_n_pv3",
- "sdmmc1_clk_pz0",
-};
-
-static const char * const cpu_groups[] = {
- "cpu_pwr_req",
-};
-
-static const char * const dap_groups[] = {
- "dap_mclk1_pee2",
- "clk2_req_pcc5",
-};
-
-static const char * const dap1_groups[] = {
- "dap_mclk1_pee2",
-};
-
-static const char * const dap2_groups[] = {
- "dap_mclk1_pw4",
- "gpio_x4_aud_px4",
-};
-
-static const char * const dev3_groups[] = {
- "clk3_req_pee1",
-};
-
-static const char * const displaya_groups[] = {
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "ph1",
- "pi4",
- "pbb3",
- "pbb4",
- "pbb5",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "kb_col3_pq3",
- "sdmmc3_dat2_pb5",
-};
-
-static const char * const displaya_alt_groups[] = {
- "kb_row6_pr6",
-};
-
-static const char * const displayb_groups[] = {
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_sclk_pp3",
-
- "pu3",
- "pu4",
- "pu5",
-
- "pbb3",
- "pbb4",
- "pbb6",
-
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
-
- "sdmmc3_dat3_pb4",
-};
-
-static const char * const dtv_groups[] = {
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
- "dap4_fs_pp4",
- "dap4_dout_pp6",
- "pi7",
- "ph0",
- "ph6",
- "ph7",
-};
-
-static const char * const extperiph1_groups[] = {
- "dap_mclk1_pw4",
-};
-
-static const char * const extperiph2_groups[] = {
- "clk2_out_pw5",
-};
-
-static const char * const extperiph3_groups[] = {
- "clk3_out_pee0",
-};
-
-static const char * const gmi_groups[] = {
- "uart2_cts_n_pj5",
- "uart2_rts_n_pj6",
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
-
- "pu0",
- "pu1",
- "pu2",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
-
- "dap4_fs_pp4",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_sclk_pp7",
-
- "pc7",
-
- "pg0",
- "pg1",
- "pg2",
- "pg3",
- "pg4",
- "pg5",
- "pg6",
- "pg7",
-
- "ph0",
- "ph1",
- "ph2",
- "ph3",
- "ph4",
- "ph5",
- "ph6",
- "ph7",
-
- "pi0",
- "pi1",
- "pi2",
- "pi3",
- "pi4",
- "pi5",
- "pi6",
- "pi7",
-
- "pj0",
- "pj2",
-
- "pk0",
- "pk1",
- "pk2",
- "pk3",
- "pk4",
-
- "pj7",
- "pb0",
- "pb1",
- "pk7",
-
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
-
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "gmi_clk_lb",
-
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
-
- "dap2_fs_pa2",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dap2_sclk_pa3",
-
- "dvfs_pwm_px0",
- "dvfs_clk_px2",
- "gpio_x1_aud_px1",
- "gpio_x3_aud_px3",
- "gpio_x4_aud_px4",
- "gpio_x5_aud_px5",
- "gpio_x6_aud_px6",
-};
-
-static const char * const gmi_alt_groups[] = {
- "pc7",
- "pk4",
- "pj7",
-};
-
-static const char * const hda_groups[] = {
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
-};
-
-static const char * const hsi_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-};
-
-static const char * const i2c1_groups[] = {
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "gpio_w2_aud_pw2",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const i2c2_groups[] = {
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
-};
-
-static const char * const i2c3_groups[] = {
- "spdif_in_pk6",
- "spdif_out_pk5",
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
-};
-
-static const char * const i2c4_groups[] = {
- "ddc_scl_pv4",
- "ddc_sda_pv5",
-};
-
-static const char * const i2cpwr_groups[] = {
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
-};
-
-static const char * const i2s0_groups[] = {
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_sclk_pn3",
-};
-
-static const char * const i2s1_groups[] = {
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
-};
-
-static const char * const i2s2_groups[] = {
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_sclk_pp3",
-};
-
-static const char * const i2s3_groups[] = {
- "dap4_fs_pp4",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_sclk_pp7",
-};
-
-static const char * const i2s4_groups[] = {
- "pcc1",
- "pbb6",
- "pbb7",
- "pcc2",
-};
-
-static const char * const irda_groups[] = {
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "kb_row11_ps3",
- "kb_row12_ps4",
-};
-
-static const char * const kbc_groups[] = {
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
- "kb_row16_pt0",
- "kb_row17_pt1",
-
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
-};
-
-static const char * const owr_groups[] = {
- "pu0",
- "kb_col4_pq4",
- "owr",
- "sdmmc3_cd_n_pv2",
-};
-
-static const char * const pmi_groups[] = {
- "pwr_int_n",
-};
-
-static const char * const pwm0_groups[] = {
- "sdmmc1_dat2_py5",
- "uart3_rts_n_pc0",
- "pu3",
- "ph0",
- "sdmmc3_dat3_pb4",
-};
-
-static const char * const pwm1_groups[] = {
- "sdmmc1_dat1_py6",
- "pu4",
- "ph1",
- "sdmmc3_dat2_pb5",
-};
-
-static const char * const pwm2_groups[] = {
- "pu5",
- "ph2",
- "kb_col3_pq3",
- "sdmmc3_dat1_pb6",
-};
-
-static const char * const pwm3_groups[] = {
- "pu6",
- "ph3",
- "sdmmc3_cmd_pa7",
-};
-
-static const char * const pwron_groups[] = {
- "core_pwr_req",
-};
-
-static const char * const reset_out_n_groups[] = {
- "reset_out_n",
-};
-
-static const char * const rsvd1_groups[] = {
- "pv0",
- "pv1",
-
- "hdmi_int_pn7",
- "pu1",
- "pu2",
- "pc7",
- "pi7",
- "pk0",
- "pj0",
- "pj2",
- "pk2",
- "pi3",
- "pi6",
-
- "pg0",
- "pg1",
- "pg2",
- "pg3",
- "pg4",
- "pg5",
- "pg6",
- "pg7",
-
- "pi0",
- "pi1",
-
- "gpio_x7_aud_px7",
-
- "reset_out_n",
-};
-
-static const char * const rsvd2_groups[] = {
- "pv0",
- "pv1",
-
- "sdmmc1_dat0_py7",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "hdmi_int_pn7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
-
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
-
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
-
- "clk2_out_pee0",
- "clk2_req_pee1",
- "pc7",
- "pi5",
- "pj0",
- "pj2",
-
- "pk4",
- "pk2",
- "pi3",
- "pi6",
- "pg0",
- "pg1",
- "pg5",
- "pg6",
- "pg7",
-
- "ph4",
- "ph5",
- "pj7",
- "pb0",
- "pb1",
- "pk7",
- "pi0",
- "pi1",
-
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat7_paa7",
- "pcc1",
- "pbb6",
- "pbb7",
- "pcc2",
- "jtag_rtck",
-
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
-
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row13_ps5",
- "kb_row14_ps6",
-
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
-
- "core_pwr_req",
- "cpu_pwr_req",
- "pwr_int_n",
- "clk_32k_in",
- "owr",
-
- "spdif_in_pk6",
- "spdif_out_pk5",
- "gpio_x1_aud_px1",
-
- "sdmmc3_clk_pa6",
- "sdmmc3_dat0_pb7",
-
- "pex_l0_rst_n_pdd1",
- "pex_l0_clkreq_n_pdd2",
- "pex_wake_n_pdd3",
- "pex_l1_rst_n_pdd5",
- "pex_l1_clkreq_n_pdd6",
- "hdmi_cec_pee3",
-
- "gpio_w2_aud_pw2",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "sdmmc3_clk_lb_out_pee4",
- "sdmmc3_clk_lb_in_pee5",
- "gmi_clk_lb",
- "reset_out_n",
- "kb_row16_pt0",
- "kb_row17_pt1",
- "dp_hpd_pff0",
- "usb_vbus_en2_pff1",
- "pff2",
-};
-
-static const char * const rsvd3_groups[] = {
- "dap3_sclk_pp3",
- "pv0",
- "pv1",
- "sdmmc1_clk_pz0",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "hdmi_int_pn7",
-
- "ddc_scl_pv4",
- "ddc_sda_pv5",
-
- "pu6",
-
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
-
- "dap4_din_pp5",
- "dap4_sclk_pp7",
-
- "clk3_out_pee0",
- "clk3_req_pee1",
-
- "sdmmc4_dat5_paa5",
- "gpio_pcc1",
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "pbb5",
- "pbb7",
- "jtag_rtck",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
-
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row15_ps7",
-
- "clk_32k_out_pa0",
- "core_pwr_req",
- "cpu_pwr_req",
- "pwr_int_n",
- "clk_32k_in",
- "owr",
-
- "dap_mclk1_pw4",
- "spdif_in_pk6",
- "spdif_out_pk5",
- "sdmmc3_clk_pa6",
- "sdmmc3_dat0_pb7",
-
- "pex_l0_rst_n_pdd1",
- "pex_l0_clkreq_n_pdd2",
- "pex_wake_n_pdd3",
- "pex_l1_rst_n_pdd5",
- "pex_l1_clkreq_n_pdd6",
- "hdmi_cec_pee3",
-
- "sdmmc3_cd_n_pv2",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "sdmmc3_clk_lb_out_pee4",
- "sdmmc3_clk_lb_in_pee5",
- "reset_out_n",
- "kb_row16_pt0",
- "kb_row17_pt1",
- "dp_hpd_pff0",
- "usb_vbus_en2_pff1",
- "pff2",
-};
-
-static const char * const rsvd4_groups[] = {
- "dap3_dout_pp2",
- "pv0",
- "pv1",
- "sdmmc1_clk_pz0",
-
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "hdmi_int_pn7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
-
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
-
- "pu0",
- "pu1",
- "pu2",
-
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
-
- "dap4_fs_pp4",
- "dap4_dout_pp6",
- "dap4_din_pp5",
- "dap4_sclk_pp7",
-
- "clk3_out_pee0",
- "clk3_req_pee1",
-
- "pi5",
- "pk1",
- "pk2",
- "pg0",
- "pg1",
- "pg2",
- "pg3",
- "ph4",
- "ph5",
- "pb0",
- "pb1",
- "pk7",
- "pi0",
- "pi1",
- "pi2",
-
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
-
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
-
- "jtag_rtck",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
-
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
-
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col5_pq5",
-
- "clk_32k_out_pa0",
- "core_pwr_req",
- "cpu_pwr_req",
- "pwr_int_n",
- "clk_32k_in",
- "owr",
-
- "dap1_fs_pn0",
- "dap1_din_pn1",
- "dap1_sclk_pn3",
- "dap_mclk1_req_pee2",
- "dap_mclk1_pw5",
-
- "dap2_fs_pa2",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dap2_sclk_pa3",
-
- "dvfs_pwm_px0",
- "dvfs_clk_px2",
- "gpio_x1_aud_px1",
- "gpio_x3_aud_px3",
-
- "gpio_x5_aud_px5",
- "gpio_x7_aud_px7",
-
- "pex_l0_rst_n_pdd1",
- "pex_l0_clkreq_n_pdd2",
- "pex_wake_n_pdd3",
- "pex_l1_rst_n_pdd5",
- "pex_l1_clkreq_n_pdd6",
- "hdmi_cec_pee3",
-
- "sdmmc3_cd_n_pv2",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "sdmmc3_clk_lb_out_pee4",
- "sdmmc3_clk_lb_in_pee5",
- "gmi_clk_lb",
-
- "dp_hpd_pff0",
- "usb_vbus_en2_pff1",
- "pff2",
-};
-
-static const char * const sdmmc1_groups[] = {
- "sdmmc1_clk_pz0",
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat0_py7",
- "clk2_out_pw5",
- "clk2_req_pcc",
- "uart3_cts_n_pa1",
- "sdmmc1_wp_n_pv3",
-};
-
-static const char * const sdmmc2_groups[] = {
- "pi5",
- "pk1",
- "pk3",
- "pk4",
- "pi6",
- "ph4",
- "ph5",
- "ph6",
- "ph7",
- "pi2",
- "cam_mclk_pcc0",
- "pcc1",
- "pbb0",
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "pbb7",
- "pcc2",
- "gmi_clk_lb",
-};
-
-static const char * const sdmmc3_groups[] = {
- "pk0",
- "pcc2",
-
- "kb_col4_pq4",
- "kb_col5_pq5",
-
- "sdmmc3_clk_pa6",
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
-
- "sdmmc3_cd_n_pv2",
- "sdmmc3_clk_lb_in_pee5",
- "sdmmc3_clk_lb_out_pee4",
-};
-
-static const char * const sdmmc4_groups[] = {
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
-};
-
-static const char * const soc_groups[] = {
- "pk0",
- "pj2",
- "kb_row15_ps7",
- "clk_32k_out_pa0",
-};
-
-static const char * const spdif_groups[] = {
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "spdif_in_pk6",
- "spdif_out_pk5",
-};
-
-static const char * const spi1_groups[] = {
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "gpio_x3_aud_px3",
- "gpio_x4_aud_px4",
- "gpio_x5_aud_px5",
- "gpio_x6_aud_px6",
- "gpio_x7_aud_px7",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const spi2_groups[] = {
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "gpio_x4_aud_px4",
- "gpio_x5_aud_px5",
- "gpio_x6_aud_px6",
- "gpio_x7_aud_px7",
- "gpio_w2_aud_pw2",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const spi3_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc3_clk_pa6",
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
-};
-
-static const char * const spi4_groups[] = {
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat0_py7",
-
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
-
- "pi3",
- "pg4",
- "pg5",
- "pg6",
- "pg7",
- "ph3",
- "pi4",
- "sdmmc1_wp_n_pv3",
-};
-
-static const char * const spi5_groups[] = {
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "dap3_fs_pp0",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_sclk_pp3",
-};
-
-static const char * const spi6_groups[] = {
- "dvfs_pwm_px0",
- "gpio_x1_aud_px1",
- "gpio_x3_aud_px3",
- "dvfs_clk_px2",
- "gpio_x6_aud_px6",
- "gpio_w2_aud_pw2",
- "gpio_w3_aud_pw3",
-};
-
-static const char * const trace_groups[] = {
- "pi2",
- "pi4",
- "pi7",
- "ph0",
- "ph6",
- "ph7",
- "pg2",
- "pg3",
- "pk1",
- "pk3",
-};
-
-static const char * const uarta_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat3_py4",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat0_py7",
-
-
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
-
- "pu0",
- "pu1",
- "pu2",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
-
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "kb_row10_ps2",
- "kb_col3_pq3",
- "kb_col4_pq4",
-
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat1_pb6",
- "sdmmc1_wp_n_pv3",
-
-};
-
-static const char * const uartb_groups[] = {
- "uart2_rts_n_pj6",
- "uart2_cts_n_pj5",
-};
-
-static const char * const uartc_groups[] = {
- "uart3_txd_pw6",
- "uart3_rxd_pw7",
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
- "kb_row16_pt0",
- "kn_row17_pt1",
-};
-
-static const char * const uartd_groups[] = {
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "pj7",
- "pb0",
- "pb1",
- "pk7",
- "kb_col6_pq6",
- "kb_col7_pq7",
-};
-
-static const char * const ulpi_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
-};
-
-static const char * const usb_groups[] = {
- "pj0",
- "usb_vbus_en0_pn4",
- "usb_vbus_en1_pn5",
- "usb_vbus_en2_pff1",
-};
-
-static const char * const vgp1_groups[] = {
- "cam_i2c_scl_pbb1",
-};
-
-static const char * const vgp2_groups[] = {
- "cam_i2c_sda_pbb2",
-};
-
-static const char * const vgp3_groups[] = {
- "pbb3",
-};
-
-static const char * const vgp4_groups[] = {
- "pbb4",
-};
-
-static const char * const vgp5_groups[] = {
- "pbb5",
-};
-
-static const char * const vgp6_groups[] = {
- "pbb0",
-};
-
-static const char * const vi_groups[] = {
- "cam_mclk_pcc0",
-};
-
-static const char * const vi_alt1_groups[] = {
- "cam_mclk_pcc0",
-};
-
-static const char * const vi_alt3_groups[] = {
- "cam_mclk_pcc0",
-};
-
-static const char * const vimclk2_groups[] = {
- "pbb0",
-};
-
-static const char * const vimclk2_alt_groups[] = {
- "pbb0",
-};
-
-static const char * const sata_groups[] = {
- "dap_mclk1_req_pee2",
- "dap1_dout_pn2",
- "pff2",
-};
-
-static const char * const ccla_groups[] = {
- "pk3",
-};
-
-static const char * const rtck_groups[] = {
- "jtag_rtck",
-};
-
-static const char * const sys_groups[] = {
- "kb_row3_pr3",
-};
-
-static const char * const pe0_groups[] = {
- "pex_l0_rst_n_pdd1",
- "pex_l0_clkreq_n_pdd2",
-};
-
-static const char * const pe_groups[] = {
- "pex_wake_n_pdd3",
-};
-
-static const char * const pe1_groups[] = {
- "pex_l1_rst_n_pdd5",
- "pex_l1_clkreq_n_pdd6",
-};
-
-static const char * const dp_groups[] = {
- "dp_hpd_pff0",
-};
-
-static const char * const clk_groups[] = {
- "clk_32k_in",
-};
-
-static const char * const tmds_groups[] = {
- "pg4",
- "ph1",
- "ph2",
};
#define FUNCTION(fname) \
{ \
.name = #fname, \
- .groups = fname##_groups, \
- .ngroups = ARRAY_SIZE(fname##_groups), \
}
-static const struct tegra_function tegra124_functions[] = {
+static struct tegra_function tegra124_functions[] = {
FUNCTION(blink),
+ FUNCTION(ccla),
FUNCTION(cec),
FUNCTION(cldvfs),
+ FUNCTION(clk),
FUNCTION(clk12),
FUNCTION(cpu),
FUNCTION(dap),
@@ -2706,6 +1602,7 @@ static const struct tegra_function tegra124_functions[] = {
FUNCTION(displaya),
FUNCTION(displaya_alt),
FUNCTION(displayb),
+ FUNCTION(dp),
FUNCTION(dtv),
FUNCTION(extperiph1),
FUNCTION(extperiph2),
@@ -2727,6 +1624,9 @@ static const struct tegra_function tegra124_functions[] = {
FUNCTION(irda),
FUNCTION(kbc),
FUNCTION(owr),
+ FUNCTION(pe),
+ FUNCTION(pe0),
+ FUNCTION(pe1),
FUNCTION(pmi),
FUNCTION(pwm0),
FUNCTION(pwm1),
@@ -2738,6 +1638,8 @@ static const struct tegra_function tegra124_functions[] = {
FUNCTION(rsvd2),
FUNCTION(rsvd3),
FUNCTION(rsvd4),
+ FUNCTION(rtck),
+ FUNCTION(sata),
FUNCTION(sdmmc1),
FUNCTION(sdmmc2),
FUNCTION(sdmmc3),
@@ -2750,6 +1652,8 @@ static const struct tegra_function tegra124_functions[] = {
FUNCTION(spi4),
FUNCTION(spi5),
FUNCTION(spi6),
+ FUNCTION(sys),
+ FUNCTION(tmds),
FUNCTION(trace),
FUNCTION(uarta),
FUNCTION(uartb),
@@ -2768,23 +1672,13 @@ static const struct tegra_function tegra124_functions[] = {
FUNCTION(vi_alt3),
FUNCTION(vimclk2),
FUNCTION(vimclk2_alt),
- FUNCTION(sata),
- FUNCTION(ccla),
- FUNCTION(pe0),
- FUNCTION(pe),
- FUNCTION(pe1),
- FUNCTION(dp),
- FUNCTION(rtck),
- FUNCTION(sys),
- FUNCTION(clk),
- FUNCTION(tmds),
};
-#define DRV_PINGROUP_REG_A 0x868 /* bank 0 */
-#define PINGROUP_REG_A 0x3000 /* bank 1 */
+#define DRV_PINGROUP_REG_A 0x868 /* bank 0 */
+#define PINGROUP_REG_A 0x3000 /* bank 1 */
-#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A)
-#define PINGROUP_REG_N(r) -1
+#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A)
+#define PINGROUP_REG_N(r) -1
#define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior, rcv_sel) \
{ \
@@ -2792,12 +1686,12 @@ static const struct tegra_function tegra124_functions[] = {
.pins = pg_name##_pins, \
.npins = ARRAY_SIZE(pg_name##_pins), \
.funcs = { \
- TEGRA_MUX_ ## f0, \
- TEGRA_MUX_ ## f1, \
- TEGRA_MUX_ ## f2, \
- TEGRA_MUX_ ## f3, \
+ TEGRA_MUX_##f0, \
+ TEGRA_MUX_##f1, \
+ TEGRA_MUX_##f2, \
+ TEGRA_MUX_##f3, \
}, \
- .func_safe = TEGRA_MUX_ ## f_safe, \
+ .func_safe = TEGRA_MUX_##f_safe, \
.mux_reg = PINGROUP_REG_Y(r), \
.mux_bank = 1, \
.mux_bit = 0, \
@@ -2826,8 +1720,9 @@ static const struct tegra_function tegra124_functions[] = {
.drvtype_reg = -1, \
}
-#define DRV_PINGROUP_DVRTYPE_Y(r) ((r) - DRV_PINGROUP_REG_A)
-#define DRV_PINGROUP_DVRTYPE_N(r) -1
+#define DRV_PINGROUP_REG_Y(r) ((r) - DRV_PINGROUP_REG_A)
+#define DRV_PINGROUP_REG_N(r) -1
+
#define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, \
drvdn_b, drvdn_w, drvup_b, drvup_w, \
@@ -2845,7 +1740,7 @@ static const struct tegra_function tegra124_functions[] = {
.lock_reg = -1, \
.ioreset_reg = -1, \
.rcv_sel_reg = -1, \
- .drv_reg = DRV_PINGROUP_DVRTYPE_Y(r), \
+ .drv_reg = DRV_PINGROUP_REG_Y(r), \
.drv_bank = 0, \
.hsm_bit = hsm_b, \
.schmitt_bit = schmitt_b, \
@@ -2858,7 +1753,7 @@ static const struct tegra_function tegra124_functions[] = {
.slwr_width = slwr_w, \
.slwf_bit = slwf_b, \
.slwf_width = slwf_w, \
- .drvtype_reg = DRV_PINGROUP_DVRTYPE_##drvtype(r), \
+ .drvtype_reg = DRV_PINGROUP_REG_##drvtype(r), \
.drvtype_bank = 0, \
.drvtype_bit = 6, \
}
@@ -2909,8 +1804,8 @@ static const struct tegra_pingroup tegra124_groups[] = {
PINGROUP(pu4, PWM1, UARTA, GMI, DISPLAYB, PWM1, 0x3194, N, N, N),
PINGROUP(pu5, PWM2, UARTA, GMI, DISPLAYB, PWM2, 0x3198, N, N, N),
PINGROUP(pu6, PWM3, UARTA, RSVD3, GMI, RSVD3, 0x319c, N, N, N),
- PINGROUP(gen1_i2c_scl_pc4, I2C1, RSVD2, RSVD3, RSVD4, I2C1, 0x31a0, Y, N, N),
- PINGROUP(gen1_i2c_sda_pc5, I2C1, RSVD2, RSVD3, RSVD4, I2C1, 0x31a4, Y, N, N),
+ PINGROUP(gen1_i2c_sda_pc5, I2C1, RSVD2, RSVD3, RSVD4, I2C1, 0x31a0, Y, N, N),
+ PINGROUP(gen1_i2c_scl_pc4, I2C1, RSVD2, RSVD3, RSVD4, I2C1, 0x31a4, Y, N, N),
PINGROUP(dap4_fs_pp4, I2S3, GMI, DTV, RSVD4, I2S3, 0x31a8, N, N, N),
PINGROUP(dap4_din_pp5, I2S3, GMI, RSVD3, RSVD4, I2S3, 0x31ac, N, N, N),
PINGROUP(dap4_dout_pp6, I2S3, GMI, DTV, RSVD4, I2S3, 0x31b0, N, N, N),
@@ -2964,9 +1859,9 @@ static const struct tegra_pingroup tegra124_groups[] = {
PINGROUP(sdmmc4_dat4_paa4, SDMMC4, SPI3, GMI, RSVD4, SDMMC4, 0x3270, N, Y, N),
PINGROUP(sdmmc4_dat5_paa5, SDMMC4, SPI3, RSVD3, RSVD4, SDMMC4, 0x3274, N, Y, N),
PINGROUP(sdmmc4_dat6_paa6, SDMMC4, SPI3, GMI, RSVD4, SDMMC4, 0x3278, N, Y, N),
- PINGROUP(sdmmc4_dat7_paa7, SDMMC4, RSVD1, GMI, RSVD4, SDMMC4, 0x327c, N, Y, N),
+ PINGROUP(sdmmc4_dat7_paa7, SDMMC4, RSVD2, GMI, RSVD4, SDMMC4, 0x327c, N, Y, N),
PINGROUP(cam_mclk_pcc0, VI, VI_ALT1, VI_ALT3, SDMMC2, VI, 0x3284, N, N, N),
- PINGROUP(pcc1, I2S4, RSVD1, RSVD3, SDMMC2, I2S4, 0x3288, N, N, N),
+ PINGROUP(pcc1, I2S4, RSVD2, RSVD3, SDMMC2, I2S4, 0x3288, N, N, N),
PINGROUP(pbb0, VGP6, VIMCLK2, SDMMC2, VIMCLK2_ALT, VGP6, 0x328c, N, N, N),
PINGROUP(cam_i2c_scl_pbb1, VGP1, I2C3, RSVD3, SDMMC2, VGP1, 0x3290, Y, N, N),
PINGROUP(cam_i2c_sda_pbb2, VGP2, I2C3, RSVD3, SDMMC2, VGP2, 0x3294, Y, N, N),
@@ -3047,8 +1942,8 @@ static const struct tegra_pingroup tegra124_groups[] = {
PINGROUP(gpio_w3_aud_pw3, SPI6, SPI1, SPI2, I2C1, SPI1, 0x33f0, N, N, N),
PINGROUP(usb_vbus_en0_pn4, USB, RSVD2, RSVD3, RSVD4, USB, 0x33f4, Y, N, N),
PINGROUP(usb_vbus_en1_pn5, USB, RSVD2, RSVD3, RSVD4, USB, 0x33f8, Y, N, N),
- PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3, RSVD2, RSVD3, RSVD4, SDMMC3, 0x33fc, N, N, N),
- PINGROUP(sdmmc3_clk_lb_in_pee5, SDMMC3, RSVD2, RSVD3, RSVD4, SDMMC3, 0x3400, N, N, N),
+ PINGROUP(sdmmc3_clk_lb_in_pee5, SDMMC3, RSVD2, RSVD3, RSVD4, SDMMC3, 0x33fc, N, N, N),
+ PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3, RSVD2, RSVD3, RSVD4, SDMMC3, 0x3400, N, N, N),
PINGROUP(gmi_clk_lb, SDMMC2, RSVD2, GMI, RSVD4, SDMMC2, 0x3404, N, N, N),
PINGROUP(reset_out_n, RSVD1, RSVD2, RSVD3, RESET_OUT_N, RSVD1, 0x3408, N, N, N),
PINGROUP(kb_row16_pt0, KBC, RSVD2, RSVD3, UARTC, KBC, 0x340c, N, N, N),
diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/pinctrl-tegra20.c
index fcfb7d012c5b..e0b504088387 100644
--- a/drivers/pinctrl/pinctrl-tegra20.c
+++ b/drivers/pinctrl/pinctrl-tegra20.c
@@ -1894,637 +1894,12 @@ enum tegra_mux {
TEGRA_MUX_XIO,
};
-static const char * const ahb_clk_groups[] = {
- "cdev2",
-};
-
-static const char * const apb_clk_groups[] = {
- "cdev2",
-};
-
-static const char * const audio_sync_groups[] = {
- "cdev1",
-};
-
-static const char * const crt_groups[] = {
- "crtp",
- "lm1",
-};
-
-static const char * const dap1_groups[] = {
- "dap1",
-};
-
-static const char * const dap2_groups[] = {
- "dap2",
-};
-
-static const char * const dap3_groups[] = {
- "dap3",
-};
-
-static const char * const dap4_groups[] = {
- "dap4",
-};
-
-static const char * const dap5_groups[] = {
- "gme",
-};
-
-static const char * const displaya_groups[] = {
- "lcsn",
- "ld0",
- "ld1",
- "ld10",
- "ld11",
- "ld12",
- "ld13",
- "ld14",
- "ld15",
- "ld16",
- "ld17",
- "ld2",
- "ld3",
- "ld4",
- "ld5",
- "ld6",
- "ld7",
- "ld8",
- "ld9",
- "ldc",
- "ldi",
- "lhp0",
- "lhp1",
- "lhp2",
- "lhs",
- "lm0",
- "lm1",
- "lpp",
- "lpw0",
- "lpw1",
- "lpw2",
- "lsc0",
- "lsc1",
- "lsck",
- "lsda",
- "lsdi",
- "lspi",
- "lvp0",
- "lvp1",
- "lvs",
-};
-
-static const char * const displayb_groups[] = {
- "lcsn",
- "ld0",
- "ld1",
- "ld10",
- "ld11",
- "ld12",
- "ld13",
- "ld14",
- "ld15",
- "ld16",
- "ld17",
- "ld2",
- "ld3",
- "ld4",
- "ld5",
- "ld6",
- "ld7",
- "ld8",
- "ld9",
- "ldc",
- "ldi",
- "lhp0",
- "lhp1",
- "lhp2",
- "lhs",
- "lm0",
- "lm1",
- "lpp",
- "lpw0",
- "lpw1",
- "lpw2",
- "lsc0",
- "lsc1",
- "lsck",
- "lsda",
- "lsdi",
- "lspi",
- "lvp0",
- "lvp1",
- "lvs",
-};
-
-static const char * const emc_test0_dll_groups[] = {
- "kbca",
-};
-
-static const char * const emc_test1_dll_groups[] = {
- "kbcc",
-};
-
-static const char * const gmi_groups[] = {
- "ata",
- "atb",
- "atc",
- "atd",
- "ate",
- "dap1",
- "dap2",
- "dap4",
- "gma",
- "gmb",
- "gmc",
- "gmd",
- "gme",
- "gpu",
- "irrx",
- "irtx",
- "pta",
- "spia",
- "spib",
- "spic",
- "spid",
- "spie",
- "uca",
- "ucb",
-};
-
-static const char * const gmi_int_groups[] = {
- "gmb",
-};
-
-static const char * const hdmi_groups[] = {
- "hdint",
- "lpw0",
- "lpw2",
- "lsc1",
- "lsck",
- "lsda",
- "lspi",
- "pta",
-};
-
-static const char * const i2cp_groups[] = {
- "i2cp",
-};
-
-static const char * const i2c1_groups[] = {
- "rm",
- "spdi",
- "spdo",
- "spig",
- "spih",
-};
-
-static const char * const i2c2_groups[] = {
- "ddc",
- "pta",
-};
-
-static const char * const i2c3_groups[] = {
- "dtf",
-};
-
-static const char * const ide_groups[] = {
- "ata",
- "atb",
- "atc",
- "atd",
- "ate",
- "gmb",
-};
-
-static const char * const irda_groups[] = {
- "uad",
-};
-
-static const char * const kbc_groups[] = {
- "kbca",
- "kbcb",
- "kbcc",
- "kbcd",
- "kbce",
- "kbcf",
-};
-
-static const char * const mio_groups[] = {
- "kbcb",
- "kbcd",
- "kbcf",
-};
-
-static const char * const mipi_hs_groups[] = {
- "uaa",
- "uab",
-};
-
-static const char * const nand_groups[] = {
- "ata",
- "atb",
- "atc",
- "atd",
- "ate",
- "gmb",
- "gmd",
- "kbca",
- "kbcb",
- "kbcc",
- "kbcd",
- "kbce",
- "kbcf",
-};
-
-static const char * const osc_groups[] = {
- "cdev1",
- "cdev2",
-};
-
-static const char * const owr_groups[] = {
- "kbce",
- "owc",
- "uac",
-};
-
-static const char * const pcie_groups[] = {
- "gpv",
- "slxa",
- "slxk",
-};
-
-static const char * const plla_out_groups[] = {
- "cdev1",
-};
-
-static const char * const pllc_out1_groups[] = {
- "csus",
-};
-
-static const char * const pllm_out1_groups[] = {
- "cdev1",
-};
-
-static const char * const pllp_out2_groups[] = {
- "csus",
-};
-
-static const char * const pllp_out3_groups[] = {
- "csus",
-};
-
-static const char * const pllp_out4_groups[] = {
- "cdev2",
-};
-
-static const char * const pwm_groups[] = {
- "gpu",
- "sdb",
- "sdc",
- "sdd",
- "ucb",
-};
-
-static const char * const pwr_intr_groups[] = {
- "pmc",
-};
-
-static const char * const pwr_on_groups[] = {
- "pmc",
-};
-
-static const char * const rsvd1_groups[] = {
- "dta",
- "dtb",
- "dtc",
- "dtd",
- "dte",
- "gmd",
- "gme",
-};
-
-static const char * const rsvd2_groups[] = {
- "crtp",
- "dap1",
- "dap3",
- "dap4",
- "ddc",
- "dtb",
- "dtc",
- "dte",
- "dtf",
- "gpu7",
- "gpv",
- "hdint",
- "i2cp",
- "owc",
- "rm",
- "sdio1",
- "spdi",
- "spdo",
- "uac",
- "uca",
- "uda",
-};
-
-static const char * const rsvd3_groups[] = {
- "crtp",
- "dap2",
- "dap3",
- "ddc",
- "gpu7",
- "gpv",
- "hdint",
- "i2cp",
- "ld17",
- "ldc",
- "ldi",
- "lhp0",
- "lhp1",
- "lhp2",
- "lm1",
- "lpp",
- "lpw1",
- "lvp0",
- "lvp1",
- "owc",
- "pmc",
- "rm",
- "uac",
-};
-
-static const char * const rsvd4_groups[] = {
- "ata",
- "ate",
- "crtp",
- "dap3",
- "dap4",
- "ddc",
- "dta",
- "dtc",
- "dtd",
- "dtf",
- "gpu",
- "gpu7",
- "gpv",
- "hdint",
- "i2cp",
- "kbce",
- "lcsn",
- "ld0",
- "ld1",
- "ld2",
- "ld3",
- "ld4",
- "ld5",
- "ld6",
- "ld7",
- "ld8",
- "ld9",
- "ld10",
- "ld11",
- "ld12",
- "ld13",
- "ld14",
- "ld15",
- "ld16",
- "ld17",
- "ldc",
- "ldi",
- "lhp0",
- "lhp1",
- "lhp2",
- "lhs",
- "lm0",
- "lpp",
- "lpw1",
- "lsc0",
- "lsdi",
- "lvp0",
- "lvp1",
- "lvs",
- "owc",
- "pmc",
- "pta",
- "rm",
- "spif",
- "uac",
- "uca",
- "ucb",
-};
-
-static const char * const rtck_groups[] = {
- "gpu7",
-};
-
-static const char * const sdio1_groups[] = {
- "sdio1",
-};
-
-static const char * const sdio2_groups[] = {
- "dap1",
- "dta",
- "dtd",
- "kbca",
- "kbcb",
- "kbcd",
- "spdi",
- "spdo",
-};
-
-static const char * const sdio3_groups[] = {
- "sdb",
- "sdc",
- "sdd",
- "slxa",
- "slxc",
- "slxd",
- "slxk",
-};
-
-static const char * const sdio4_groups[] = {
- "atb",
- "atc",
- "atd",
- "gma",
- "gme",
-};
-
-static const char * const sflash_groups[] = {
- "gmc",
- "gmd",
-};
-
-static const char * const spdif_groups[] = {
- "slxc",
- "slxd",
- "spdi",
- "spdo",
- "uad",
-};
-
-static const char * const spi1_groups[] = {
- "dtb",
- "dte",
- "spia",
- "spib",
- "spic",
- "spid",
- "spie",
- "spif",
- "uda",
-};
-
-static const char * const spi2_groups[] = {
- "sdb",
- "slxa",
- "slxc",
- "slxd",
- "slxk",
- "spia",
- "spib",
- "spic",
- "spid",
- "spie",
- "spif",
- "spig",
- "spih",
- "uab",
-};
-
-static const char * const spi2_alt_groups[] = {
- "spid",
- "spie",
- "spig",
- "spih",
-};
-
-static const char * const spi3_groups[] = {
- "gma",
- "lcsn",
- "lm0",
- "lpw0",
- "lpw2",
- "lsc1",
- "lsck",
- "lsda",
- "lsdi",
- "sdc",
- "sdd",
- "spia",
- "spib",
- "spic",
- "spif",
- "spig",
- "spih",
- "uaa",
-};
-
-static const char * const spi4_groups[] = {
- "gmc",
- "irrx",
- "irtx",
- "slxa",
- "slxc",
- "slxd",
- "slxk",
- "uad",
-};
-
-static const char * const trace_groups[] = {
- "kbcc",
- "kbcf",
-};
-
-static const char * const twc_groups[] = {
- "dap2",
- "sdc",
-};
-
-static const char * const uarta_groups[] = {
- "gpu",
- "irrx",
- "irtx",
- "sdb",
- "sdd",
- "sdio1",
- "uaa",
- "uab",
- "uad",
-};
-
-static const char * const uartb_groups[] = {
- "irrx",
- "irtx",
-};
-
-static const char * const uartc_groups[] = {
- "uca",
- "ucb",
-};
-
-static const char * const uartd_groups[] = {
- "gmc",
- "uda",
-};
-
-static const char * const uarte_groups[] = {
- "gma",
- "sdio1",
-};
-
-static const char * const ulpi_groups[] = {
- "uaa",
- "uab",
- "uda",
-};
-
-static const char * const vi_groups[] = {
- "dta",
- "dtb",
- "dtc",
- "dtd",
- "dte",
- "dtf",
-};
-
-static const char * const vi_sensor_clk_groups[] = {
- "csus",
-};
-
-static const char * const xio_groups[] = {
- "ld0",
- "ld1",
- "ld10",
- "ld11",
- "ld12",
- "ld13",
- "ld14",
- "ld15",
- "ld16",
- "ld2",
- "ld3",
- "ld4",
- "ld5",
- "ld6",
- "ld7",
- "ld8",
- "ld9",
- "lhs",
- "lsc0",
- "lspi",
- "lvs",
-};
-
#define FUNCTION(fname) \
{ \
.name = #fname, \
- .groups = fname##_groups, \
- .ngroups = ARRAY_SIZE(fname##_groups), \
}
-static const struct tegra_function tegra20_functions[] = {
+static struct tegra_function tegra20_functions[] = {
FUNCTION(ahb_clk),
FUNCTION(apb_clk),
FUNCTION(audio_sync),
@@ -2881,18 +2256,7 @@ static struct platform_driver tegra20_pinctrl_driver = {
.probe = tegra20_pinctrl_probe,
.remove = tegra_pinctrl_remove,
};
-
-static int __init tegra20_pinctrl_init(void)
-{
- return platform_driver_register(&tegra20_pinctrl_driver);
-}
-arch_initcall(tegra20_pinctrl_init);
-
-static void __exit tegra20_pinctrl_exit(void)
-{
- platform_driver_unregister(&tegra20_pinctrl_driver);
-}
-module_exit(tegra20_pinctrl_exit);
+module_platform_driver(tegra20_pinctrl_driver);
MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
MODULE_DESCRIPTION("NVIDIA Tegra20 pinctrl driver");
diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c
index 2300deba25bd..41d24f5c2854 100644
--- a/drivers/pinctrl/pinctrl-tegra30.c
+++ b/drivers/pinctrl/pinctrl-tegra30.c
@@ -25,7 +25,7 @@
* Most pins affected by the pinmux can also be GPIOs. Define these first.
* These must match how the GPIO driver names/numbers its pins.
*/
-#define _GPIO(offset) (offset)
+#define _GPIO(offset) (offset)
#define TEGRA_PIN_CLK_32K_OUT_PA0 _GPIO(0)
#define TEGRA_PIN_UART3_CTS_N_PA1 _GPIO(1)
@@ -277,8 +277,8 @@
#define TEGRA_PIN_PEE7 _GPIO(247)
/* All non-GPIO pins follow */
-#define NUM_GPIOS (TEGRA_PIN_PEE7 + 1)
-#define _PIN(offset) (NUM_GPIOS + (offset))
+#define NUM_GPIOS (TEGRA_PIN_PEE7 + 1)
+#define _PIN(offset) (NUM_GPIOS + (offset))
/* Non-GPIO pins */
#define TEGRA_PIN_CLK_32K_IN _PIN(0)
@@ -2015,1253 +2015,13 @@ enum tegra_mux {
TEGRA_MUX_VI_ALT2,
TEGRA_MUX_VI_ALT3,
};
-static const char * const blink_groups[] = {
- "clk_32k_out_pa0",
-};
-
-static const char * const cec_groups[] = {
- "hdmi_cec_pee3",
- "owr",
-};
-
-static const char * const clk_12m_out_groups[] = {
- "pv3",
-};
-
-static const char * const clk_32k_in_groups[] = {
- "clk_32k_in",
-};
-
-static const char * const core_pwr_req_groups[] = {
- "core_pwr_req",
-};
-
-static const char * const cpu_pwr_req_groups[] = {
- "cpu_pwr_req",
-};
-
-static const char * const crt_groups[] = {
- "crt_hsync_pv6",
- "crt_vsync_pv7",
-};
-
-static const char * const dap_groups[] = {
- "clk1_req_pee2",
- "clk2_req_pcc5",
-};
-
-static const char * const ddr_groups[] = {
- "vi_d0_pt4",
- "vi_d1_pd5",
- "vi_d10_pt2",
- "vi_d11_pt3",
- "vi_d2_pl0",
- "vi_d3_pl1",
- "vi_d4_pl2",
- "vi_d5_pl3",
- "vi_d6_pl4",
- "vi_d7_pl5",
- "vi_d8_pl6",
- "vi_d9_pl7",
- "vi_hsync_pd7",
- "vi_vsync_pd6",
-};
-
-static const char * const dev3_groups[] = {
- "clk3_req_pee1",
-};
-
-static const char * const displaya_groups[] = {
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_fs_pp0",
- "dap3_sclk_pp3",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "lcd_cs0_n_pn4",
- "lcd_cs1_n_pw0",
- "lcd_d0_pe0",
- "lcd_d1_pe1",
- "lcd_d10_pf2",
- "lcd_d11_pf3",
- "lcd_d12_pf4",
- "lcd_d13_pf5",
- "lcd_d14_pf6",
- "lcd_d15_pf7",
- "lcd_d16_pm0",
- "lcd_d17_pm1",
- "lcd_d18_pm2",
- "lcd_d19_pm3",
- "lcd_d2_pe2",
- "lcd_d20_pm4",
- "lcd_d21_pm5",
- "lcd_d22_pm6",
- "lcd_d23_pm7",
- "lcd_d3_pe3",
- "lcd_d4_pe4",
- "lcd_d5_pe5",
- "lcd_d6_pe6",
- "lcd_d7_pe7",
- "lcd_d8_pf0",
- "lcd_d9_pf1",
- "lcd_dc0_pn6",
- "lcd_dc1_pd2",
- "lcd_de_pj1",
- "lcd_hsync_pj3",
- "lcd_m1_pw1",
- "lcd_pclk_pb3",
- "lcd_pwr0_pb2",
- "lcd_pwr1_pc1",
- "lcd_pwr2_pc6",
- "lcd_sck_pz4",
- "lcd_sdin_pz2",
- "lcd_sdout_pn5",
- "lcd_vsync_pj4",
- "lcd_wr_n_pz3",
-};
-
-static const char * const displayb_groups[] = {
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_fs_pp0",
- "dap3_sclk_pp3",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "lcd_cs0_n_pn4",
- "lcd_cs1_n_pw0",
- "lcd_d0_pe0",
- "lcd_d1_pe1",
- "lcd_d10_pf2",
- "lcd_d11_pf3",
- "lcd_d12_pf4",
- "lcd_d13_pf5",
- "lcd_d14_pf6",
- "lcd_d15_pf7",
- "lcd_d16_pm0",
- "lcd_d17_pm1",
- "lcd_d18_pm2",
- "lcd_d19_pm3",
- "lcd_d2_pe2",
- "lcd_d20_pm4",
- "lcd_d21_pm5",
- "lcd_d22_pm6",
- "lcd_d23_pm7",
- "lcd_d3_pe3",
- "lcd_d4_pe4",
- "lcd_d5_pe5",
- "lcd_d6_pe6",
- "lcd_d7_pe7",
- "lcd_d8_pf0",
- "lcd_d9_pf1",
- "lcd_dc0_pn6",
- "lcd_dc1_pd2",
- "lcd_de_pj1",
- "lcd_hsync_pj3",
- "lcd_m1_pw1",
- "lcd_pclk_pb3",
- "lcd_pwr0_pb2",
- "lcd_pwr1_pc1",
- "lcd_pwr2_pc6",
- "lcd_sck_pz4",
- "lcd_sdin_pz2",
- "lcd_sdout_pn5",
- "lcd_vsync_pj4",
- "lcd_wr_n_pz3",
-};
-
-static const char * const dtv_groups[] = {
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
-};
-
-static const char * const extperiph1_groups[] = {
- "clk1_out_pw4",
-};
-
-static const char * const extperiph2_groups[] = {
- "clk2_out_pw5",
-};
-
-static const char * const extperiph3_groups[] = {
- "clk3_out_pee0",
-};
-
-static const char * const gmi_groups[] = {
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_fs_pn0",
- "dap1_sclk_pn3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_fs_pp4",
- "dap4_sclk_pp7",
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7",
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad10_ph2",
- "gmi_ad11_ph3",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_ad8_ph0",
- "gmi_ad9_ph1",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
- "gmi_cs2_n_pk3",
- "gmi_cs3_n_pk4",
- "gmi_cs4_n_pk2",
- "gmi_cs6_n_pi3",
- "gmi_cs7_n_pi6",
- "gmi_dqs_pi2",
- "gmi_iordy_pi5",
- "gmi_oe_n_pi1",
- "gmi_rst_n_pi4",
- "gmi_wait_pi7",
- "gmi_wp_n_pc7",
- "gmi_wr_n_pi0",
- "pu0",
- "pu1",
- "pu2",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
- "spi1_cs0_n_px6",
- "spi1_mosi_px4",
- "spi1_sck_px5",
- "spi2_cs0_n_px3",
- "spi2_miso_px1",
- "spi2_mosi_px0",
- "spi2_sck_px2",
- "uart2_cts_n_pj5",
- "uart2_rts_n_pj6",
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
- "uart3_rxd_pw7",
- "uart3_txd_pw6",
-};
-
-static const char * const gmi_alt_groups[] = {
- "gmi_a16_pj7",
- "gmi_cs3_n_pk4",
- "gmi_cs7_n_pi6",
- "gmi_wp_n_pc7",
-};
-
-static const char * const hda_groups[] = {
- "clk1_req_pee2",
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_fs_pn0",
- "dap1_sclk_pn3",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "pex_l0_clkreq_n_pdd2",
- "pex_l0_prsnt_n_pdd0",
- "pex_l0_rst_n_pdd1",
- "pex_l1_clkreq_n_pdd6",
- "pex_l1_prsnt_n_pdd4",
- "pex_l1_rst_n_pdd5",
- "pex_l2_clkreq_n_pcc7",
- "pex_l2_prsnt_n_pdd7",
- "pex_l2_rst_n_pcc6",
- "pex_wake_n_pdd3",
- "spdif_in_pk6",
-};
-
-static const char * const hdcp_groups[] = {
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "lcd_pwr0_pb2",
- "lcd_pwr2_pc6",
- "lcd_sck_pz4",
- "lcd_sdout_pn5",
- "lcd_wr_n_pz3",
-};
-
-static const char * const hdmi_groups[] = {
- "hdmi_int_pn7",
-};
-
-static const char * const hsi_groups[] = {
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-};
-
-static const char * const i2c1_groups[] = {
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "spdif_in_pk6",
- "spdif_out_pk5",
- "spi2_cs1_n_pw2",
- "spi2_cs2_n_pw3",
-};
-
-static const char * const i2c2_groups[] = {
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
-};
-
-static const char * const i2c3_groups[] = {
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat4_paa4",
-};
-
-static const char * const i2c4_groups[] = {
- "ddc_scl_pv4",
- "ddc_sda_pv5",
-};
-
-static const char * const i2cpwr_groups[] = {
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
-};
-
-static const char * const i2s0_groups[] = {
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_fs_pn0",
- "dap1_sclk_pn3",
-};
-
-static const char * const i2s1_groups[] = {
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
-};
-
-static const char * const i2s2_groups[] = {
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_fs_pp0",
- "dap3_sclk_pp3",
-};
-
-static const char * const i2s3_groups[] = {
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_fs_pp4",
- "dap4_sclk_pp7",
-};
-
-static const char * const i2s4_groups[] = {
- "pbb0",
- "pbb7",
- "pcc1",
- "pcc2",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
-};
-
-static const char * const invalid_groups[] = {
- "kb_row3_pr3",
- "sdmmc4_clk_pcc4",
-};
-
-static const char * const kbc_groups[] = {
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
- "kb_row2_pr2",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
-};
-
-static const char * const mio_groups[] = {
- "kb_col6_pq6",
- "kb_col7_pq7",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
- "kb_row6_pr6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
-};
-
-static const char * const nand_groups[] = {
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad10_ph2",
- "gmi_ad11_ph3",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_ad8_ph0",
- "gmi_ad9_ph1",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
- "gmi_cs2_n_pk3",
- "gmi_cs3_n_pk4",
- "gmi_cs4_n_pk2",
- "gmi_cs6_n_pi3",
- "gmi_cs7_n_pi6",
- "gmi_dqs_pi2",
- "gmi_iordy_pi5",
- "gmi_oe_n_pi1",
- "gmi_rst_n_pi4",
- "gmi_wait_pi7",
- "gmi_wp_n_pc7",
- "gmi_wr_n_pi0",
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
- "kb_row2_pr2",
- "kb_row3_pr3",
- "kb_row4_pr4",
- "kb_row5_pr5",
- "kb_row6_pr6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
-};
-
-static const char * const nand_alt_groups[] = {
- "gmi_cs6_n_pi3",
- "gmi_cs7_n_pi6",
- "gmi_rst_n_pi4",
-};
-
-static const char * const owr_groups[] = {
- "pu0",
- "pv2",
- "kb_row5_pr5",
- "owr",
-};
-
-static const char * const pcie_groups[] = {
- "pex_l0_clkreq_n_pdd2",
- "pex_l0_prsnt_n_pdd0",
- "pex_l0_rst_n_pdd1",
- "pex_l1_clkreq_n_pdd6",
- "pex_l1_prsnt_n_pdd4",
- "pex_l1_rst_n_pdd5",
- "pex_l2_clkreq_n_pcc7",
- "pex_l2_prsnt_n_pdd7",
- "pex_l2_rst_n_pcc6",
- "pex_wake_n_pdd3",
-};
-
-static const char * const pwm0_groups[] = {
- "gmi_ad8_ph0",
- "pu3",
- "sdmmc3_dat3_pb4",
- "sdmmc3_dat5_pd0",
- "uart3_rts_n_pc0",
-};
-
-static const char * const pwm1_groups[] = {
- "gmi_ad9_ph1",
- "pu4",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat4_pd1",
-};
-
-static const char * const pwm2_groups[] = {
- "gmi_ad10_ph2",
- "pu5",
- "sdmmc3_clk_pa6",
-};
-
-static const char * const pwm3_groups[] = {
- "gmi_ad11_ph3",
- "pu6",
- "sdmmc3_cmd_pa7",
-};
-
-static const char * const pwr_int_n_groups[] = {
- "pwr_int_n",
-};
-
-static const char * const rsvd1_groups[] = {
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs0_n_pj0",
- "gmi_cs1_n_pj2",
- "gmi_cs2_n_pk3",
- "gmi_cs3_n_pk4",
- "gmi_cs4_n_pk2",
- "gmi_dqs_pi2",
- "gmi_iordy_pi5",
- "gmi_oe_n_pi1",
- "gmi_wait_pi7",
- "gmi_wp_n_pc7",
- "gmi_wr_n_pi0",
- "pu1",
- "pu2",
- "pv0",
- "pv1",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
- "vi_pclk_pt0",
-};
-
-static const char * const rsvd2_groups[] = {
- "clk1_out_pw4",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "clk3_out_pee0",
- "clk3_req_pee1",
- "clk_32k_in",
- "clk_32k_out_pa0",
- "core_pwr_req",
- "cpu_pwr_req",
- "crt_hsync_pv6",
- "crt_vsync_pv7",
- "dap3_din_pp1",
- "dap3_dout_pp2",
- "dap3_fs_pp0",
- "dap3_sclk_pp3",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_fs_pp4",
- "dap4_sclk_pp7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "pbb0",
- "pbb7",
- "pcc1",
- "pcc2",
- "pv0",
- "pv1",
- "pv2",
- "pv3",
- "hdmi_cec_pee3",
- "hdmi_int_pn7",
- "jtag_rtck_pu7",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
- "pwr_int_n",
- "sdmmc1_clk_pz0",
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat0_py7",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat3_py4",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc4_rst_n_pcc3",
- "spdif_out_pk5",
- "sys_clk_req_pz5",
- "uart3_cts_n_pa1",
- "uart3_rxd_pw7",
- "uart3_txd_pw6",
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
- "vi_d0_pt4",
- "vi_d10_pt2",
- "vi_d11_pt3",
- "vi_hsync_pd7",
- "vi_vsync_pd6",
-};
-
-static const char * const rsvd3_groups[] = {
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "clk1_out_pw4",
- "clk1_req_pee2",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "clk3_out_pee0",
- "clk3_req_pee1",
- "clk_32k_in",
- "clk_32k_out_pa0",
- "core_pwr_req",
- "cpu_pwr_req",
- "crt_hsync_pv6",
- "crt_vsync_pv7",
- "dap2_din_pa4",
- "dap2_dout_pa5",
- "dap2_fs_pa2",
- "dap2_sclk_pa3",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "pbb0",
- "pbb7",
- "pcc1",
- "pcc2",
- "pv0",
- "pv1",
- "pv2",
- "pv3",
- "hdmi_cec_pee3",
- "hdmi_int_pn7",
- "jtag_rtck_pu7",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row3_pr3",
- "lcd_d0_pe0",
- "lcd_d1_pe1",
- "lcd_d10_pf2",
- "lcd_d11_pf3",
- "lcd_d12_pf4",
- "lcd_d13_pf5",
- "lcd_d14_pf6",
- "lcd_d15_pf7",
- "lcd_d16_pm0",
- "lcd_d17_pm1",
- "lcd_d18_pm2",
- "lcd_d19_pm3",
- "lcd_d2_pe2",
- "lcd_d20_pm4",
- "lcd_d21_pm5",
- "lcd_d22_pm6",
- "lcd_d23_pm7",
- "lcd_d3_pe3",
- "lcd_d4_pe4",
- "lcd_d5_pe5",
- "lcd_d6_pe6",
- "lcd_d7_pe7",
- "lcd_d8_pf0",
- "lcd_d9_pf1",
- "lcd_dc0_pn6",
- "lcd_dc1_pd2",
- "lcd_de_pj1",
- "lcd_hsync_pj3",
- "lcd_m1_pw1",
- "lcd_pclk_pb3",
- "lcd_pwr1_pc1",
- "lcd_vsync_pj4",
- "owr",
- "pex_l0_clkreq_n_pdd2",
- "pex_l0_prsnt_n_pdd0",
- "pex_l0_rst_n_pdd1",
- "pex_l1_clkreq_n_pdd6",
- "pex_l1_prsnt_n_pdd4",
- "pex_l1_rst_n_pdd5",
- "pex_l2_clkreq_n_pcc7",
- "pex_l2_prsnt_n_pdd7",
- "pex_l2_rst_n_pcc6",
- "pex_wake_n_pdd3",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
- "pwr_int_n",
- "sdmmc1_clk_pz0",
- "sdmmc1_cmd_pz1",
- "sdmmc4_rst_n_pcc3",
- "sys_clk_req_pz5",
-};
-
-static const char * const rsvd4_groups[] = {
- "clk1_out_pw4",
- "clk1_req_pee2",
- "clk2_out_pw5",
- "clk2_req_pcc5",
- "clk3_out_pee0",
- "clk3_req_pee1",
- "clk_32k_in",
- "clk_32k_out_pa0",
- "core_pwr_req",
- "cpu_pwr_req",
- "crt_hsync_pv6",
- "crt_vsync_pv7",
- "dap4_din_pp5",
- "dap4_dout_pp6",
- "dap4_fs_pp4",
- "dap4_sclk_pp7",
- "ddc_scl_pv4",
- "ddc_sda_pv5",
- "gen1_i2c_scl_pc4",
- "gen1_i2c_sda_pc5",
- "gen2_i2c_scl_pt5",
- "gen2_i2c_sda_pt6",
- "gmi_a19_pk7",
- "gmi_ad0_pg0",
- "gmi_ad1_pg1",
- "gmi_ad10_ph2",
- "gmi_ad11_ph3",
- "gmi_ad12_ph4",
- "gmi_ad13_ph5",
- "gmi_ad14_ph6",
- "gmi_ad15_ph7",
- "gmi_ad2_pg2",
- "gmi_ad3_pg3",
- "gmi_ad4_pg4",
- "gmi_ad5_pg5",
- "gmi_ad6_pg6",
- "gmi_ad7_pg7",
- "gmi_ad8_ph0",
- "gmi_ad9_ph1",
- "gmi_adv_n_pk0",
- "gmi_clk_pk1",
- "gmi_cs2_n_pk3",
- "gmi_cs4_n_pk2",
- "gmi_dqs_pi2",
- "gmi_iordy_pi5",
- "gmi_oe_n_pi1",
- "gmi_rst_n_pi4",
- "gmi_wait_pi7",
- "gmi_wr_n_pi0",
- "pcc2",
- "pu0",
- "pu1",
- "pu2",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
- "pv0",
- "pv1",
- "pv2",
- "pv3",
- "hdmi_cec_pee3",
- "hdmi_int_pn7",
- "jtag_rtck_pu7",
- "kb_col2_pq2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "kb_col5_pq5",
- "kb_row0_pr0",
- "kb_row1_pr1",
- "kb_row2_pr2",
- "kb_row4_pr4",
- "lcd_cs0_n_pn4",
- "lcd_cs1_n_pw0",
- "lcd_d0_pe0",
- "lcd_d1_pe1",
- "lcd_d10_pf2",
- "lcd_d11_pf3",
- "lcd_d12_pf4",
- "lcd_d13_pf5",
- "lcd_d14_pf6",
- "lcd_d15_pf7",
- "lcd_d16_pm0",
- "lcd_d17_pm1",
- "lcd_d18_pm2",
- "lcd_d19_pm3",
- "lcd_d2_pe2",
- "lcd_d20_pm4",
- "lcd_d21_pm5",
- "lcd_d22_pm6",
- "lcd_d23_pm7",
- "lcd_d3_pe3",
- "lcd_d4_pe4",
- "lcd_d5_pe5",
- "lcd_d6_pe6",
- "lcd_d7_pe7",
- "lcd_d8_pf0",
- "lcd_d9_pf1",
- "lcd_dc0_pn6",
- "lcd_dc1_pd2",
- "lcd_de_pj1",
- "lcd_hsync_pj3",
- "lcd_m1_pw1",
- "lcd_pclk_pb3",
- "lcd_pwr1_pc1",
- "lcd_sdin_pz2",
- "lcd_vsync_pj4",
- "owr",
- "pex_l0_clkreq_n_pdd2",
- "pex_l0_prsnt_n_pdd0",
- "pex_l0_rst_n_pdd1",
- "pex_l1_clkreq_n_pdd6",
- "pex_l1_prsnt_n_pdd4",
- "pex_l1_rst_n_pdd5",
- "pex_l2_clkreq_n_pcc7",
- "pex_l2_prsnt_n_pdd7",
- "pex_l2_rst_n_pcc6",
- "pex_wake_n_pdd3",
- "pwr_i2c_scl_pz6",
- "pwr_i2c_sda_pz7",
- "pwr_int_n",
- "spi1_miso_px7",
- "sys_clk_req_pz5",
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
- "uart3_rxd_pw7",
- "uart3_txd_pw6",
- "vi_d0_pt4",
- "vi_d1_pd5",
- "vi_d10_pt2",
- "vi_d11_pt3",
- "vi_d2_pl0",
- "vi_d3_pl1",
- "vi_d4_pl2",
- "vi_d5_pl3",
- "vi_d6_pl4",
- "vi_d7_pl5",
- "vi_d8_pl6",
- "vi_d9_pl7",
- "vi_hsync_pd7",
- "vi_pclk_pt0",
- "vi_vsync_pd6",
-};
-
-static const char * const rtck_groups[] = {
- "jtag_rtck_pu7",
-};
-
-static const char * const sata_groups[] = {
- "gmi_cs6_n_pi3",
-};
-
-static const char * const sdmmc1_groups[] = {
- "sdmmc1_clk_pz0",
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat0_py7",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat3_py4",
-};
-
-static const char * const sdmmc2_groups[] = {
- "dap1_din_pn1",
- "dap1_dout_pn2",
- "dap1_fs_pn0",
- "dap1_sclk_pn3",
- "kb_row10_ps2",
- "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7",
- "kb_row6_pr6",
- "kb_row7_pr7",
- "kb_row8_ps0",
- "kb_row9_ps1",
- "spdif_in_pk6",
- "spdif_out_pk5",
- "vi_d1_pd5",
- "vi_d2_pl0",
- "vi_d3_pl1",
- "vi_d4_pl2",
- "vi_d5_pl3",
- "vi_d6_pl4",
- "vi_d7_pl5",
- "vi_d8_pl6",
- "vi_d9_pl7",
- "vi_pclk_pt0",
-};
-
-static const char * const sdmmc3_groups[] = {
- "sdmmc3_clk_pa6",
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
- "sdmmc3_dat4_pd1",
- "sdmmc3_dat5_pd0",
- "sdmmc3_dat6_pd3",
- "sdmmc3_dat7_pd4",
-};
-
-static const char * const sdmmc4_groups[] = {
- "cam_i2c_scl_pbb1",
- "cam_i2c_sda_pbb2",
- "cam_mclk_pcc0",
- "pbb0",
- "pbb3",
- "pbb4",
- "pbb5",
- "pbb6",
- "pbb7",
- "pcc1",
- "sdmmc4_clk_pcc4",
- "sdmmc4_cmd_pt7",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7",
- "sdmmc4_rst_n_pcc3",
-};
-
-static const char * const spdif_groups[] = {
- "sdmmc3_dat6_pd3",
- "sdmmc3_dat7_pd4",
- "spdif_in_pk6",
- "spdif_out_pk5",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
-};
-
-static const char * const spi1_groups[] = {
- "spi1_cs0_n_px6",
- "spi1_miso_px7",
- "spi1_mosi_px4",
- "spi1_sck_px5",
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
-};
-
-static const char * const spi2_groups[] = {
- "sdmmc3_cmd_pa7",
- "sdmmc3_dat4_pd1",
- "sdmmc3_dat5_pd0",
- "sdmmc3_dat6_pd3",
- "sdmmc3_dat7_pd4",
- "spi1_cs0_n_px6",
- "spi1_mosi_px4",
- "spi1_sck_px5",
- "spi2_cs0_n_px3",
- "spi2_cs1_n_pw2",
- "spi2_cs2_n_pw3",
- "spi2_miso_px1",
- "spi2_mosi_px0",
- "spi2_sck_px2",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-};
-
-static const char * const spi2_alt_groups[] = {
- "spi1_cs0_n_px6",
- "spi1_miso_px7",
- "spi1_mosi_px4",
- "spi1_sck_px5",
- "spi2_cs1_n_pw2",
- "spi2_cs2_n_pw3",
-};
-
-static const char * const spi3_groups[] = {
- "sdmmc3_clk_pa6",
- "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "spi1_miso_px7",
- "spi2_cs0_n_px3",
- "spi2_cs1_n_pw2",
- "spi2_cs2_n_pw3",
- "spi2_miso_px1",
- "spi2_mosi_px0",
- "spi2_sck_px2",
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
-};
-
-static const char * const spi4_groups[] = {
- "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7",
- "sdmmc3_dat4_pd1",
- "sdmmc3_dat5_pd0",
- "sdmmc3_dat6_pd3",
- "sdmmc3_dat7_pd4",
- "uart2_cts_n_pj5",
- "uart2_rts_n_pj6",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
-};
-
-static const char * const spi5_groups[] = {
- "lcd_cs0_n_pn4",
- "lcd_cs1_n_pw0",
- "lcd_pwr0_pb2",
- "lcd_pwr2_pc6",
- "lcd_sck_pz4",
- "lcd_sdin_pz2",
- "lcd_sdout_pn5",
- "lcd_wr_n_pz3",
-};
-
-static const char * const spi6_groups[] = {
- "spi2_cs0_n_px3",
- "spi2_miso_px1",
- "spi2_mosi_px0",
- "spi2_sck_px2",
-};
-
-static const char * const sysclk_groups[] = {
- "sys_clk_req_pz5",
-};
-
-static const char * const test_groups[] = {
- "kb_col0_pq0",
- "kb_col1_pq1",
-};
-
-static const char * const trace_groups[] = {
- "kb_col0_pq0",
- "kb_col1_pq1",
- "kb_col2_pq2",
- "kb_col3_pq3",
- "kb_col4_pq4",
- "kb_col5_pq5",
- "kb_col6_pq6",
- "kb_col7_pq7",
- "kb_row4_pr4",
- "kb_row5_pr5",
-};
-
-static const char * const uarta_groups[] = {
- "pu0",
- "pu1",
- "pu2",
- "pu3",
- "pu4",
- "pu5",
- "pu6",
- "sdmmc1_clk_pz0",
- "sdmmc1_cmd_pz1",
- "sdmmc1_dat0_py7",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat3_py4",
- "sdmmc3_clk_pa6",
- "sdmmc3_cmd_pa7",
- "uart2_cts_n_pj5",
- "uart2_rts_n_pj6",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
-};
-
-static const char * const uartb_groups[] = {
- "uart2_cts_n_pj5",
- "uart2_rts_n_pj6",
- "uart2_rxd_pc3",
- "uart2_txd_pc2",
-};
-
-static const char * const uartc_groups[] = {
- "uart3_cts_n_pa1",
- "uart3_rts_n_pc0",
- "uart3_rxd_pw7",
- "uart3_txd_pw6",
-};
-
-static const char * const uartd_groups[] = {
- "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7",
- "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
-};
-
-static const char * const uarte_groups[] = {
- "sdmmc1_dat0_py7",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat3_py4",
- "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
-};
-
-static const char * const ulpi_groups[] = {
- "ulpi_clk_py0",
- "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3",
-};
-
-static const char * const vgp1_groups[] = {
- "cam_i2c_scl_pbb1",
-};
-
-static const char * const vgp2_groups[] = {
- "cam_i2c_sda_pbb2",
-};
-
-static const char * const vgp3_groups[] = {
- "pbb3",
- "sdmmc4_dat5_paa5",
-};
-
-static const char * const vgp4_groups[] = {
- "pbb4",
- "sdmmc4_dat6_paa6",
-};
-
-static const char * const vgp5_groups[] = {
- "pbb5",
- "sdmmc4_dat7_paa7",
-};
-
-static const char * const vgp6_groups[] = {
- "pbb6",
- "sdmmc4_rst_n_pcc3",
-};
-
-static const char * const vi_groups[] = {
- "cam_mclk_pcc0",
- "vi_d0_pt4",
- "vi_d1_pd5",
- "vi_d10_pt2",
- "vi_d11_pt3",
- "vi_d2_pl0",
- "vi_d3_pl1",
- "vi_d4_pl2",
- "vi_d5_pl3",
- "vi_d6_pl4",
- "vi_d7_pl5",
- "vi_d8_pl6",
- "vi_d9_pl7",
- "vi_hsync_pd7",
- "vi_mclk_pt1",
- "vi_pclk_pt0",
- "vi_vsync_pd6",
-};
-
-static const char * const vi_alt1_groups[] = {
- "cam_mclk_pcc0",
- "vi_mclk_pt1",
-};
-
-static const char * const vi_alt2_groups[] = {
- "vi_mclk_pt1",
-};
-
-static const char * const vi_alt3_groups[] = {
- "cam_mclk_pcc0",
- "vi_mclk_pt1",
-};
#define FUNCTION(fname) \
{ \
.name = #fname, \
- .groups = fname##_groups, \
- .ngroups = ARRAY_SIZE(fname##_groups), \
}
-static const struct tegra_function tegra30_functions[] = {
+static struct tegra_function tegra30_functions[] = {
FUNCTION(blink),
FUNCTION(cec),
FUNCTION(clk_12m_out),
@@ -3345,11 +2105,11 @@ static const struct tegra_function tegra30_functions[] = {
FUNCTION(vi_alt3),
};
-#define DRV_PINGROUP_REG_A 0x868 /* bank 0 */
-#define PINGROUP_REG_A 0x3000 /* bank 1 */
+#define DRV_PINGROUP_REG_A 0x868 /* bank 0 */
+#define PINGROUP_REG_A 0x3000 /* bank 1 */
-#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A)
-#define PINGROUP_REG_N(r) -1
+#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_A)
+#define PINGROUP_REG_N(r) -1
#define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior) \
{ \
@@ -3357,12 +2117,12 @@ static const struct tegra_function tegra30_functions[] = {
.pins = pg_name##_pins, \
.npins = ARRAY_SIZE(pg_name##_pins), \
.funcs = { \
- TEGRA_MUX_ ## f0, \
- TEGRA_MUX_ ## f1, \
- TEGRA_MUX_ ## f2, \
- TEGRA_MUX_ ## f3, \
+ TEGRA_MUX_##f0, \
+ TEGRA_MUX_##f1, \
+ TEGRA_MUX_##f2, \
+ TEGRA_MUX_##f3, \
}, \
- .func_safe = TEGRA_MUX_ ## f_safe, \
+ .func_safe = TEGRA_MUX_##f_safe, \
.mux_reg = PINGROUP_REG_Y(r), \
.mux_bank = 1, \
.mux_bit = 0, \
@@ -3389,6 +2149,9 @@ static const struct tegra_function tegra30_functions[] = {
.drvtype_reg = -1, \
}
+#define DRV_PINGROUP_REG_Y(r) ((r) - DRV_PINGROUP_REG_A)
+#define DRV_PINGROUP_REG_N(r) -1
+
#define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, \
drvdn_b, drvdn_w, drvup_b, drvup_w, \
slwr_b, slwr_w, slwf_b, slwf_w) \
@@ -3404,7 +2167,7 @@ static const struct tegra_function tegra30_functions[] = {
.lock_reg = -1, \
.ioreset_reg = -1, \
.rcv_sel_reg = -1, \
- .drv_reg = ((r) - DRV_PINGROUP_REG_A), \
+ .drv_reg = DRV_PINGROUP_REG_Y(r), \
.drv_bank = 0, \
.hsm_bit = hsm_b, \
.schmitt_bit = schmitt_b, \
@@ -3422,7 +2185,6 @@ static const struct tegra_function tegra30_functions[] = {
static const struct tegra_pingroup tegra30_groups[] = {
/* pg_name, f0, f1, f2, f3, safe, r, od, ior */
- /* FIXME: Fill in correct data in safe column */
PINGROUP(clk_32k_out_pa0, BLINK, RSVD2, RSVD3, RSVD4, RSVD4, 0x331c, N, N),
PINGROUP(uart3_cts_n_pa1, UARTC, RSVD2, GMI, RSVD4, RSVD4, 0x317c, N, N),
PINGROUP(dap2_fs_pa2, I2S1, HDA, RSVD3, GMI, RSVD3, 0x3358, N, N),
@@ -3735,6 +2497,7 @@ static struct of_device_id tegra30_pinctrl_of_match[] = {
{ .compatible = "nvidia,tegra30-pinmux", },
{ },
};
+MODULE_DEVICE_TABLE(of, tegra30_pinctrl_of_match);
static struct platform_driver tegra30_pinctrl_driver = {
.driver = {
@@ -3745,20 +2508,8 @@ static struct platform_driver tegra30_pinctrl_driver = {
.probe = tegra30_pinctrl_probe,
.remove = tegra_pinctrl_remove,
};
-
-static int __init tegra30_pinctrl_init(void)
-{
- return platform_driver_register(&tegra30_pinctrl_driver);
-}
-arch_initcall(tegra30_pinctrl_init);
-
-static void __exit tegra30_pinctrl_exit(void)
-{
- platform_driver_unregister(&tegra30_pinctrl_driver);
-}
-module_exit(tegra30_pinctrl_exit);
+module_platform_driver(tegra30_pinctrl_driver);
MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
MODULE_DESCRIPTION("NVIDIA Tegra30 pinctrl driver");
MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, tegra30_pinctrl_of_match);
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
index c381ae63c508..48093719167a 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
@@ -2260,6 +2260,42 @@ static const unsigned int msiof0_tx_pins[] = {
static const unsigned int msiof0_tx_mux[] = {
MSIOF0_TXD_MARK,
};
+
+static const unsigned int msiof0_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 23),
+};
+static const unsigned int msiof0_clk_b_mux[] = {
+ MSIOF0_SCK_B_MARK,
+};
+static const unsigned int msiof0_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(1, 12),
+};
+static const unsigned int msiof0_ss1_b_mux[] = {
+ MSIOF0_SS1_B_MARK,
+};
+static const unsigned int msiof0_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(1, 10),
+};
+static const unsigned int msiof0_ss2_b_mux[] = {
+ MSIOF0_SS2_B_MARK,
+};
+static const unsigned int msiof0_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(1, 29),
+};
+static const unsigned int msiof0_rx_b_mux[] = {
+ MSIOF0_RXD_B_MARK,
+};
+static const unsigned int msiof0_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(1, 28),
+};
+static const unsigned int msiof0_tx_b_mux[] = {
+ MSIOF0_TXD_B_MARK,
+};
/* - MSIOF1 ----------------------------------------------------------------- */
static const unsigned int msiof1_clk_pins[] = {
/* SCK */
@@ -2303,6 +2339,42 @@ static const unsigned int msiof1_tx_pins[] = {
static const unsigned int msiof1_tx_mux[] = {
MSIOF1_TXD_MARK,
};
+
+static const unsigned int msiof1_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 16),
+};
+static const unsigned int msiof1_clk_b_mux[] = {
+ MSIOF1_SCK_B_MARK,
+};
+static const unsigned int msiof1_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(0, 18),
+};
+static const unsigned int msiof1_ss1_b_mux[] = {
+ MSIOF1_SS1_B_MARK,
+};
+static const unsigned int msiof1_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(0, 19),
+};
+static const unsigned int msiof1_ss2_b_mux[] = {
+ MSIOF1_SS2_B_MARK,
+};
+static const unsigned int msiof1_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(1, 17),
+};
+static const unsigned int msiof1_rx_b_mux[] = {
+ MSIOF1_RXD_B_MARK,
+};
+static const unsigned int msiof1_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 20),
+};
+static const unsigned int msiof1_tx_b_mux[] = {
+ MSIOF1_TXD_B_MARK,
+};
/* - MSIOF2 ----------------------------------------------------------------- */
static const unsigned int msiof2_clk_pins[] = {
/* SCK */
@@ -2389,6 +2461,58 @@ static const unsigned int msiof3_tx_pins[] = {
static const unsigned int msiof3_tx_mux[] = {
MSIOF3_TXD_MARK,
};
+
+static const unsigned int msiof3_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 0),
+};
+static const unsigned int msiof3_clk_b_mux[] = {
+ MSIOF3_SCK_B_MARK,
+};
+static const unsigned int msiof3_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 1),
+};
+static const unsigned int msiof3_sync_b_mux[] = {
+ MSIOF3_SYNC_B_MARK,
+};
+static const unsigned int msiof3_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 2),
+};
+static const unsigned int msiof3_rx_b_mux[] = {
+ MSIOF3_RXD_B_MARK,
+};
+static const unsigned int msiof3_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 3),
+};
+static const unsigned int msiof3_tx_b_mux[] = {
+ MSIOF3_TXD_B_MARK,
+};
+/* - QSPI ------------------------------------------------------------------- */
+static const unsigned int qspi_ctrl_pins[] = {
+ /* SPCLK, SSL */
+ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 9),
+};
+static const unsigned int qspi_ctrl_mux[] = {
+ SPCLK_MARK, SSL_MARK,
+};
+static const unsigned int qspi_data2_pins[] = {
+ /* MOSI_IO0, MISO_IO1 */
+ RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6),
+};
+static const unsigned int qspi_data2_mux[] = {
+ MOSI_IO0_MARK, MISO_IO1_MARK,
+};
+static const unsigned int qspi_data4_pins[] = {
+ /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+ RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
+ RCAR_GP_PIN(1, 8),
+};
+static const unsigned int qspi_data4_mux[] = {
+ MOSI_IO0_MARK, MISO_IO1_MARK, IO2_MARK, IO3_MARK,
+};
/* - SCIF0 ------------------------------------------------------------------ */
static const unsigned int scif0_data_pins[] = {
/* RX, TX */
@@ -3231,6 +3355,13 @@ static const unsigned int usb0_pins[] = {
static const unsigned int usb0_mux[] = {
USB0_PWEN_MARK, USB0_OVC_VBUS_MARK,
};
+static const unsigned int usb0_ovc_vbus_pins[] = {
+ /* OVC/VBUS */
+ RCAR_GP_PIN(5, 19),
+};
+static const unsigned int usb0_ovc_vbus_mux[] = {
+ USB0_OVC_VBUS_MARK,
+};
/* - USB1 ------------------------------------------------------------------- */
static const unsigned int usb1_pins[] = {
/* PWEN, OVC */
@@ -3653,12 +3784,22 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(msiof0_ss2),
SH_PFC_PIN_GROUP(msiof0_rx),
SH_PFC_PIN_GROUP(msiof0_tx),
+ SH_PFC_PIN_GROUP(msiof0_clk_b),
+ SH_PFC_PIN_GROUP(msiof0_ss1_b),
+ SH_PFC_PIN_GROUP(msiof0_ss2_b),
+ SH_PFC_PIN_GROUP(msiof0_rx_b),
+ SH_PFC_PIN_GROUP(msiof0_tx_b),
SH_PFC_PIN_GROUP(msiof1_clk),
SH_PFC_PIN_GROUP(msiof1_sync),
SH_PFC_PIN_GROUP(msiof1_ss1),
SH_PFC_PIN_GROUP(msiof1_ss2),
SH_PFC_PIN_GROUP(msiof1_rx),
SH_PFC_PIN_GROUP(msiof1_tx),
+ SH_PFC_PIN_GROUP(msiof1_clk_b),
+ SH_PFC_PIN_GROUP(msiof1_ss1_b),
+ SH_PFC_PIN_GROUP(msiof1_ss2_b),
+ SH_PFC_PIN_GROUP(msiof1_rx_b),
+ SH_PFC_PIN_GROUP(msiof1_tx_b),
SH_PFC_PIN_GROUP(msiof2_clk),
SH_PFC_PIN_GROUP(msiof2_sync),
SH_PFC_PIN_GROUP(msiof2_ss1),
@@ -3671,6 +3812,13 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(msiof3_ss2),
SH_PFC_PIN_GROUP(msiof3_rx),
SH_PFC_PIN_GROUP(msiof3_tx),
+ SH_PFC_PIN_GROUP(msiof3_clk_b),
+ SH_PFC_PIN_GROUP(msiof3_sync_b),
+ SH_PFC_PIN_GROUP(msiof3_rx_b),
+ SH_PFC_PIN_GROUP(msiof3_tx_b),
+ SH_PFC_PIN_GROUP(qspi_ctrl),
+ SH_PFC_PIN_GROUP(qspi_data2),
+ SH_PFC_PIN_GROUP(qspi_data4),
SH_PFC_PIN_GROUP(scif0_data),
SH_PFC_PIN_GROUP(scif0_clk),
SH_PFC_PIN_GROUP(scif0_ctrl),
@@ -3789,6 +3937,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(tpu0_to2),
SH_PFC_PIN_GROUP(tpu0_to3),
SH_PFC_PIN_GROUP(usb0),
+ SH_PFC_PIN_GROUP(usb0_ovc_vbus),
SH_PFC_PIN_GROUP(usb1),
SH_PFC_PIN_GROUP(usb2),
VIN_DATA_PIN_GROUP(vin0_data, 24),
@@ -3941,6 +4090,11 @@ static const char * const msiof0_groups[] = {
"msiof0_ss2",
"msiof0_rx",
"msiof0_tx",
+ "msiof0_clk_b",
+ "msiof0_ss1_b",
+ "msiof0_ss2_b",
+ "msiof0_rx_b",
+ "msiof0_tx_b",
};
static const char * const msiof1_groups[] = {
@@ -3950,6 +4104,11 @@ static const char * const msiof1_groups[] = {
"msiof1_ss2",
"msiof1_rx",
"msiof1_tx",
+ "msiof1_clk_b",
+ "msiof1_ss1_b",
+ "msiof1_ss2_b",
+ "msiof1_rx_b",
+ "msiof1_tx_b",
};
static const char * const msiof2_groups[] = {
@@ -3968,6 +4127,16 @@ static const char * const msiof3_groups[] = {
"msiof3_ss2",
"msiof3_rx",
"msiof3_tx",
+ "msiof3_clk_b",
+ "msiof3_sync_b",
+ "msiof3_rx_b",
+ "msiof3_tx_b",
+};
+
+static const char * const qspi_groups[] = {
+ "qspi_ctrl",
+ "qspi_data2",
+ "qspi_data4",
};
static const char * const scif0_groups[] = {
@@ -4134,6 +4303,7 @@ static const char * const tpu0_groups[] = {
static const char * const usb0_groups[] = {
"usb0",
+ "usb0_ovc_vbus",
};
static const char * const usb1_groups[] = {
@@ -4213,6 +4383,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(msiof1),
SH_PFC_FUNCTION(msiof2),
SH_PFC_FUNCTION(msiof3),
+ SH_PFC_FUNCTION(qspi),
SH_PFC_FUNCTION(scif0),
SH_PFC_FUNCTION(scif1),
SH_PFC_FUNCTION(scif2),
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
index 77d103fe39d9..5186d70c49d4 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
@@ -89,7 +89,8 @@ enum {
/* GPSR6 */
FN_IP13_10, FN_IP13_11, FN_IP13_12, FN_IP13_13, FN_IP13_14,
- FN_IP13_15, FN_IP13_18_16, FN_IP13_21_19, FN_IP13_22, FN_IP13_24_23,
+ FN_IP13_15, FN_IP13_18_16, FN_IP13_21_19,
+ FN_IP13_22, FN_IP13_24_23, FN_SD1_CLK,
FN_IP13_25, FN_IP13_26, FN_IP13_27, FN_IP13_30_28, FN_IP14_1_0,
FN_IP14_2, FN_IP14_3, FN_IP14_4, FN_IP14_5, FN_IP14_6, FN_IP14_7,
FN_IP14_10_8, FN_IP14_13_11, FN_IP14_16_14, FN_IP14_19_17,
@@ -788,6 +789,7 @@ static const u16 pinmux_data[] = {
PINMUX_DATA(USB1_PWEN_MARK, FN_USB1_PWEN),
PINMUX_DATA(USB1_OVC_MARK, FN_USB1_OVC),
PINMUX_DATA(DU0_DOTCLKIN_MARK, FN_DU0_DOTCLKIN),
+ PINMUX_DATA(SD1_CLK_MARK, FN_SD1_CLK),
/* IPSR0 */
PINMUX_IPSR_DATA(IP0_0, D0),
@@ -1943,6 +1945,50 @@ static const unsigned int i2c4_c_pins[] = {
static const unsigned int i2c4_c_mux[] = {
SCL4_C_MARK, SDA4_C_MARK,
};
+/* - I2C7 ------------------------------------------------------------------- */
+static const unsigned int i2c7_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 16),
+};
+static const unsigned int i2c7_mux[] = {
+ SCL7_MARK, SDA7_MARK,
+};
+static const unsigned int i2c7_b_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 3),
+};
+static const unsigned int i2c7_b_mux[] = {
+ SCL7_B_MARK, SDA7_B_MARK,
+};
+static const unsigned int i2c7_c_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(6, 28), RCAR_GP_PIN(6, 29),
+};
+static const unsigned int i2c7_c_mux[] = {
+ SCL7_C_MARK, SDA7_C_MARK,
+};
+/* - I2C8 ------------------------------------------------------------------- */
+static const unsigned int i2c8_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(4, 13), RCAR_GP_PIN(4, 14),
+};
+static const unsigned int i2c8_mux[] = {
+ SCL8_MARK, SDA8_MARK,
+};
+static const unsigned int i2c8_b_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 5),
+};
+static const unsigned int i2c8_b_mux[] = {
+ SCL8_B_MARK, SDA8_B_MARK,
+};
+static const unsigned int i2c8_c_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(6, 22), RCAR_GP_PIN(6, 23),
+};
+static const unsigned int i2c8_c_mux[] = {
+ SCL8_C_MARK, SDA8_C_MARK,
+};
/* - INTC ------------------------------------------------------------------- */
static const unsigned int intc_irq0_pins[] = {
/* IRQ */
@@ -2049,6 +2095,92 @@ static const unsigned int msiof0_tx_pins[] = {
static const unsigned int msiof0_tx_mux[] = {
MSIOF0_TXD_MARK,
};
+
+static const unsigned int msiof0_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 16),
+};
+static const unsigned int msiof0_clk_b_mux[] = {
+ MSIOF0_SCK_B_MARK,
+};
+static const unsigned int msiof0_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 17),
+};
+static const unsigned int msiof0_sync_b_mux[] = {
+ MSIOF0_SYNC_B_MARK,
+};
+static const unsigned int msiof0_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(0, 18),
+};
+static const unsigned int msiof0_ss1_b_mux[] = {
+ MSIOF0_SS1_B_MARK,
+};
+static const unsigned int msiof0_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(0, 19),
+};
+static const unsigned int msiof0_ss2_b_mux[] = {
+ MSIOF0_SS2_B_MARK,
+};
+static const unsigned int msiof0_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 21),
+};
+static const unsigned int msiof0_rx_b_mux[] = {
+ MSIOF0_RXD_B_MARK,
+};
+static const unsigned int msiof0_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 20),
+};
+static const unsigned int msiof0_tx_b_mux[] = {
+ MSIOF0_TXD_B_MARK,
+};
+
+static const unsigned int msiof0_clk_c_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 26),
+};
+static const unsigned int msiof0_clk_c_mux[] = {
+ MSIOF0_SCK_C_MARK,
+};
+static const unsigned int msiof0_sync_c_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(5, 25),
+};
+static const unsigned int msiof0_sync_c_mux[] = {
+ MSIOF0_SYNC_C_MARK,
+};
+static const unsigned int msiof0_ss1_c_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(5, 27),
+};
+static const unsigned int msiof0_ss1_c_mux[] = {
+ MSIOF0_SS1_C_MARK,
+};
+static const unsigned int msiof0_ss2_c_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(5, 28),
+};
+static const unsigned int msiof0_ss2_c_mux[] = {
+ MSIOF0_SS2_C_MARK,
+};
+static const unsigned int msiof0_rx_c_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(5, 29),
+};
+static const unsigned int msiof0_rx_c_mux[] = {
+ MSIOF0_RXD_C_MARK,
+};
+static const unsigned int msiof0_tx_c_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(5, 30),
+};
+static const unsigned int msiof0_tx_c_mux[] = {
+ MSIOF0_TXD_C_MARK,
+};
/* - MSIOF1 ----------------------------------------------------------------- */
static const unsigned int msiof1_clk_pins[] = {
/* SCK */
@@ -2092,6 +2224,143 @@ static const unsigned int msiof1_tx_pins[] = {
static const unsigned int msiof1_tx_mux[] = {
MSIOF1_TXD_MARK,
};
+
+static const unsigned int msiof1_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(2, 29),
+};
+static const unsigned int msiof1_clk_b_mux[] = {
+ MSIOF1_SCK_B_MARK,
+};
+static const unsigned int msiof1_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(2, 30),
+};
+static const unsigned int msiof1_sync_b_mux[] = {
+ MSIOF1_SYNC_B_MARK,
+};
+static const unsigned int msiof1_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(2, 31),
+};
+static const unsigned int msiof1_ss1_b_mux[] = {
+ MSIOF1_SS1_B_MARK,
+};
+static const unsigned int msiof1_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(7, 16),
+};
+static const unsigned int msiof1_ss2_b_mux[] = {
+ MSIOF1_SS2_B_MARK,
+};
+static const unsigned int msiof1_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(7, 18),
+};
+static const unsigned int msiof1_rx_b_mux[] = {
+ MSIOF1_RXD_B_MARK,
+};
+static const unsigned int msiof1_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(7, 17),
+};
+static const unsigned int msiof1_tx_b_mux[] = {
+ MSIOF1_TXD_B_MARK,
+};
+
+static const unsigned int msiof1_clk_c_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(2, 15),
+};
+static const unsigned int msiof1_clk_c_mux[] = {
+ MSIOF1_SCK_C_MARK,
+};
+static const unsigned int msiof1_sync_c_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(2, 16),
+};
+static const unsigned int msiof1_sync_c_mux[] = {
+ MSIOF1_SYNC_C_MARK,
+};
+static const unsigned int msiof1_rx_c_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(2, 18),
+};
+static const unsigned int msiof1_rx_c_mux[] = {
+ MSIOF1_RXD_C_MARK,
+};
+static const unsigned int msiof1_tx_c_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(2, 17),
+};
+static const unsigned int msiof1_tx_c_mux[] = {
+ MSIOF1_TXD_C_MARK,
+};
+
+static const unsigned int msiof1_clk_d_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 28),
+};
+static const unsigned int msiof1_clk_d_mux[] = {
+ MSIOF1_SCK_D_MARK,
+};
+static const unsigned int msiof1_sync_d_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 30),
+};
+static const unsigned int msiof1_sync_d_mux[] = {
+ MSIOF1_SYNC_D_MARK,
+};
+static const unsigned int msiof1_ss1_d_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(0, 29),
+};
+static const unsigned int msiof1_ss1_d_mux[] = {
+ MSIOF1_SS1_D_MARK,
+};
+static const unsigned int msiof1_rx_d_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 27),
+};
+static const unsigned int msiof1_rx_d_mux[] = {
+ MSIOF1_RXD_D_MARK,
+};
+static const unsigned int msiof1_tx_d_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 26),
+};
+static const unsigned int msiof1_tx_d_mux[] = {
+ MSIOF1_TXD_D_MARK,
+};
+
+static const unsigned int msiof1_clk_e_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 18),
+};
+static const unsigned int msiof1_clk_e_mux[] = {
+ MSIOF1_SCK_E_MARK,
+};
+static const unsigned int msiof1_sync_e_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(5, 19),
+};
+static const unsigned int msiof1_sync_e_mux[] = {
+ MSIOF1_SYNC_E_MARK,
+};
+static const unsigned int msiof1_rx_e_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(5, 17),
+};
+static const unsigned int msiof1_rx_e_mux[] = {
+ MSIOF1_RXD_E_MARK,
+};
+static const unsigned int msiof1_tx_e_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(5, 20),
+};
+static const unsigned int msiof1_tx_e_mux[] = {
+ MSIOF1_TXD_E_MARK,
+};
/* - MSIOF2 ----------------------------------------------------------------- */
static const unsigned int msiof2_clk_pins[] = {
/* SCK */
@@ -2135,6 +2404,197 @@ static const unsigned int msiof2_tx_pins[] = {
static const unsigned int msiof2_tx_mux[] = {
MSIOF2_TXD_MARK,
};
+
+static const unsigned int msiof2_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(3, 0),
+};
+static const unsigned int msiof2_clk_b_mux[] = {
+ MSIOF2_SCK_B_MARK,
+};
+static const unsigned int msiof2_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(3, 1),
+};
+static const unsigned int msiof2_sync_b_mux[] = {
+ MSIOF2_SYNC_B_MARK,
+};
+static const unsigned int msiof2_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(3, 8),
+};
+static const unsigned int msiof2_ss1_b_mux[] = {
+ MSIOF2_SS1_B_MARK,
+};
+static const unsigned int msiof2_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(3, 9),
+};
+static const unsigned int msiof2_ss2_b_mux[] = {
+ MSIOF2_SS2_B_MARK,
+};
+static const unsigned int msiof2_rx_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(3, 17),
+};
+static const unsigned int msiof2_rx_b_mux[] = {
+ MSIOF2_RXD_B_MARK,
+};
+static const unsigned int msiof2_tx_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(3, 16),
+};
+static const unsigned int msiof2_tx_b_mux[] = {
+ MSIOF2_TXD_B_MARK,
+};
+
+static const unsigned int msiof2_clk_c_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(2, 2),
+};
+static const unsigned int msiof2_clk_c_mux[] = {
+ MSIOF2_SCK_C_MARK,
+};
+static const unsigned int msiof2_sync_c_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(2, 3),
+};
+static const unsigned int msiof2_sync_c_mux[] = {
+ MSIOF2_SYNC_C_MARK,
+};
+static const unsigned int msiof2_rx_c_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(2, 5),
+};
+static const unsigned int msiof2_rx_c_mux[] = {
+ MSIOF2_RXD_C_MARK,
+};
+static const unsigned int msiof2_tx_c_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(2, 4),
+};
+static const unsigned int msiof2_tx_c_mux[] = {
+ MSIOF2_TXD_C_MARK,
+};
+
+static const unsigned int msiof2_clk_d_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(2, 14),
+};
+static const unsigned int msiof2_clk_d_mux[] = {
+ MSIOF2_SCK_D_MARK,
+};
+static const unsigned int msiof2_sync_d_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(2, 15),
+};
+static const unsigned int msiof2_sync_d_mux[] = {
+ MSIOF2_SYNC_D_MARK,
+};
+static const unsigned int msiof2_ss1_d_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(2, 17),
+};
+static const unsigned int msiof2_ss1_d_mux[] = {
+ MSIOF2_SS1_D_MARK,
+};
+static const unsigned int msiof2_ss2_d_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(2, 19),
+};
+static const unsigned int msiof2_ss2_d_mux[] = {
+ MSIOF2_SS2_D_MARK,
+};
+static const unsigned int msiof2_rx_d_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(2, 18),
+};
+static const unsigned int msiof2_rx_d_mux[] = {
+ MSIOF2_RXD_D_MARK,
+};
+static const unsigned int msiof2_tx_d_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(2, 16),
+};
+static const unsigned int msiof2_tx_d_mux[] = {
+ MSIOF2_TXD_D_MARK,
+};
+
+static const unsigned int msiof2_clk_e_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(7, 15),
+};
+static const unsigned int msiof2_clk_e_mux[] = {
+ MSIOF2_SCK_E_MARK,
+};
+static const unsigned int msiof2_sync_e_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(7, 16),
+};
+static const unsigned int msiof2_sync_e_mux[] = {
+ MSIOF2_SYNC_E_MARK,
+};
+static const unsigned int msiof2_rx_e_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(7, 14),
+};
+static const unsigned int msiof2_rx_e_mux[] = {
+ MSIOF2_RXD_E_MARK,
+};
+static const unsigned int msiof2_tx_e_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(7, 13),
+};
+static const unsigned int msiof2_tx_e_mux[] = {
+ MSIOF2_TXD_E_MARK,
+};
+/* - QSPI ------------------------------------------------------------------- */
+static const unsigned int qspi_ctrl_pins[] = {
+ /* SPCLK, SSL */
+ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 9),
+};
+static const unsigned int qspi_ctrl_mux[] = {
+ SPCLK_MARK, SSL_MARK,
+};
+static const unsigned int qspi_data2_pins[] = {
+ /* MOSI_IO0, MISO_IO1 */
+ RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6),
+};
+static const unsigned int qspi_data2_mux[] = {
+ MOSI_IO0_MARK, MISO_IO1_MARK,
+};
+static const unsigned int qspi_data4_pins[] = {
+ /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+ RCAR_GP_PIN(1, 5), RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
+ RCAR_GP_PIN(1, 8),
+};
+static const unsigned int qspi_data4_mux[] = {
+ MOSI_IO0_MARK, MISO_IO1_MARK, IO2_MARK, IO3_MARK,
+};
+
+static const unsigned int qspi_ctrl_b_pins[] = {
+ /* SPCLK, SSL */
+ RCAR_GP_PIN(6, 0), RCAR_GP_PIN(6, 5),
+};
+static const unsigned int qspi_ctrl_b_mux[] = {
+ SPCLK_B_MARK, SSL_B_MARK,
+};
+static const unsigned int qspi_data2_b_pins[] = {
+ /* MOSI_IO0, MISO_IO1 */
+ RCAR_GP_PIN(6, 1), RCAR_GP_PIN(6, 2),
+};
+static const unsigned int qspi_data2_b_mux[] = {
+ MOSI_IO0_B_MARK, MISO_IO1_B_MARK,
+};
+static const unsigned int qspi_data4_b_pins[] = {
+ /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+ RCAR_GP_PIN(6, 1), RCAR_GP_PIN(6, 2), RCAR_GP_PIN(6, 3),
+ RCAR_GP_PIN(6, 4),
+};
+static const unsigned int qspi_data4_b_mux[] = {
+ SPCLK_B_MARK, MOSI_IO0_B_MARK, MISO_IO1_B_MARK,
+ IO2_B_MARK, IO3_B_MARK, SSL_B_MARK,
+};
/* - SCIF0 ------------------------------------------------------------------ */
static const unsigned int scif0_data_pins[] = {
/* RX, TX */
@@ -3123,6 +3583,12 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(i2c4),
SH_PFC_PIN_GROUP(i2c4_b),
SH_PFC_PIN_GROUP(i2c4_c),
+ SH_PFC_PIN_GROUP(i2c7),
+ SH_PFC_PIN_GROUP(i2c7_b),
+ SH_PFC_PIN_GROUP(i2c7_c),
+ SH_PFC_PIN_GROUP(i2c8),
+ SH_PFC_PIN_GROUP(i2c8_b),
+ SH_PFC_PIN_GROUP(i2c8_c),
SH_PFC_PIN_GROUP(intc_irq0),
SH_PFC_PIN_GROUP(intc_irq1),
SH_PFC_PIN_GROUP(intc_irq2),
@@ -3137,18 +3603,75 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(msiof0_ss2),
SH_PFC_PIN_GROUP(msiof0_rx),
SH_PFC_PIN_GROUP(msiof0_tx),
+ SH_PFC_PIN_GROUP(msiof0_clk_b),
+ SH_PFC_PIN_GROUP(msiof0_sync_b),
+ SH_PFC_PIN_GROUP(msiof0_ss1_b),
+ SH_PFC_PIN_GROUP(msiof0_ss2_b),
+ SH_PFC_PIN_GROUP(msiof0_rx_b),
+ SH_PFC_PIN_GROUP(msiof0_tx_b),
+ SH_PFC_PIN_GROUP(msiof0_clk_c),
+ SH_PFC_PIN_GROUP(msiof0_sync_c),
+ SH_PFC_PIN_GROUP(msiof0_ss1_c),
+ SH_PFC_PIN_GROUP(msiof0_ss2_c),
+ SH_PFC_PIN_GROUP(msiof0_rx_c),
+ SH_PFC_PIN_GROUP(msiof0_tx_c),
SH_PFC_PIN_GROUP(msiof1_clk),
SH_PFC_PIN_GROUP(msiof1_sync),
SH_PFC_PIN_GROUP(msiof1_ss1),
SH_PFC_PIN_GROUP(msiof1_ss2),
SH_PFC_PIN_GROUP(msiof1_rx),
SH_PFC_PIN_GROUP(msiof1_tx),
+ SH_PFC_PIN_GROUP(msiof1_clk_b),
+ SH_PFC_PIN_GROUP(msiof1_sync_b),
+ SH_PFC_PIN_GROUP(msiof1_ss1_b),
+ SH_PFC_PIN_GROUP(msiof1_ss2_b),
+ SH_PFC_PIN_GROUP(msiof1_rx_b),
+ SH_PFC_PIN_GROUP(msiof1_tx_b),
+ SH_PFC_PIN_GROUP(msiof1_clk_c),
+ SH_PFC_PIN_GROUP(msiof1_sync_c),
+ SH_PFC_PIN_GROUP(msiof1_rx_c),
+ SH_PFC_PIN_GROUP(msiof1_tx_c),
+ SH_PFC_PIN_GROUP(msiof1_clk_d),
+ SH_PFC_PIN_GROUP(msiof1_sync_d),
+ SH_PFC_PIN_GROUP(msiof1_ss1_d),
+ SH_PFC_PIN_GROUP(msiof1_rx_d),
+ SH_PFC_PIN_GROUP(msiof1_tx_d),
+ SH_PFC_PIN_GROUP(msiof1_clk_e),
+ SH_PFC_PIN_GROUP(msiof1_sync_e),
+ SH_PFC_PIN_GROUP(msiof1_rx_e),
+ SH_PFC_PIN_GROUP(msiof1_tx_e),
SH_PFC_PIN_GROUP(msiof2_clk),
SH_PFC_PIN_GROUP(msiof2_sync),
SH_PFC_PIN_GROUP(msiof2_ss1),
SH_PFC_PIN_GROUP(msiof2_ss2),
SH_PFC_PIN_GROUP(msiof2_rx),
SH_PFC_PIN_GROUP(msiof2_tx),
+ SH_PFC_PIN_GROUP(msiof2_clk_b),
+ SH_PFC_PIN_GROUP(msiof2_sync_b),
+ SH_PFC_PIN_GROUP(msiof2_ss1_b),
+ SH_PFC_PIN_GROUP(msiof2_ss2_b),
+ SH_PFC_PIN_GROUP(msiof2_rx_b),
+ SH_PFC_PIN_GROUP(msiof2_tx_b),
+ SH_PFC_PIN_GROUP(msiof2_clk_c),
+ SH_PFC_PIN_GROUP(msiof2_sync_c),
+ SH_PFC_PIN_GROUP(msiof2_rx_c),
+ SH_PFC_PIN_GROUP(msiof2_tx_c),
+ SH_PFC_PIN_GROUP(msiof2_clk_d),
+ SH_PFC_PIN_GROUP(msiof2_sync_d),
+ SH_PFC_PIN_GROUP(msiof2_ss1_d),
+ SH_PFC_PIN_GROUP(msiof2_ss2_d),
+ SH_PFC_PIN_GROUP(msiof2_rx_d),
+ SH_PFC_PIN_GROUP(msiof2_tx_d),
+ SH_PFC_PIN_GROUP(msiof2_clk_e),
+ SH_PFC_PIN_GROUP(msiof2_sync_e),
+ SH_PFC_PIN_GROUP(msiof2_rx_e),
+ SH_PFC_PIN_GROUP(msiof2_tx_e),
+ SH_PFC_PIN_GROUP(qspi_ctrl),
+ SH_PFC_PIN_GROUP(qspi_data2),
+ SH_PFC_PIN_GROUP(qspi_data4),
+ SH_PFC_PIN_GROUP(qspi_ctrl_b),
+ SH_PFC_PIN_GROUP(qspi_data2_b),
+ SH_PFC_PIN_GROUP(qspi_data4_b),
SH_PFC_PIN_GROUP(scif0_data),
SH_PFC_PIN_GROUP(scif0_data_b),
SH_PFC_PIN_GROUP(scif0_data_c),
@@ -3335,6 +3858,18 @@ static const char * const i2c4_groups[] = {
"i2c4_c",
};
+static const char * const i2c7_groups[] = {
+ "i2c7",
+ "i2c7_b",
+ "i2c7_c",
+};
+
+static const char * const i2c8_groups[] = {
+ "i2c8",
+ "i2c8_b",
+ "i2c8_c",
+};
+
static const char * const intc_groups[] = {
"intc_irq0",
"intc_irq1",
@@ -3356,6 +3891,18 @@ static const char * const msiof0_groups[] = {
"msiof0_ss2",
"msiof0_rx",
"msiof0_tx",
+ "msiof0_clk_b",
+ "msiof0_sync_b",
+ "msiof0_ss1_b",
+ "msiof0_ss2_b",
+ "msiof0_rx_b",
+ "msiof0_tx_b",
+ "msiof0_clk_c",
+ "msiof0_sync_c",
+ "msiof0_ss1_c",
+ "msiof0_ss2_c",
+ "msiof0_rx_c",
+ "msiof0_tx_c",
};
static const char * const msiof1_groups[] = {
@@ -3365,6 +3912,25 @@ static const char * const msiof1_groups[] = {
"msiof1_ss2",
"msiof1_rx",
"msiof1_tx",
+ "msiof1_clk_b",
+ "msiof1_sync_b",
+ "msiof1_ss1_b",
+ "msiof1_ss2_b",
+ "msiof1_rx_b",
+ "msiof1_tx_b",
+ "msiof1_clk_c",
+ "msiof1_sync_c",
+ "msiof1_rx_c",
+ "msiof1_tx_c",
+ "msiof1_clk_d",
+ "msiof1_sync_d",
+ "msiof1_ss1_d",
+ "msiof1_rx_d",
+ "msiof1_tx_d",
+ "msiof1_clk_e",
+ "msiof1_sync_e",
+ "msiof1_rx_e",
+ "msiof1_tx_e",
};
static const char * const msiof2_groups[] = {
@@ -3374,6 +3940,35 @@ static const char * const msiof2_groups[] = {
"msiof2_ss2",
"msiof2_rx",
"msiof2_tx",
+ "msiof2_clk_b",
+ "msiof2_sync_b",
+ "msiof2_ss1_b",
+ "msiof2_ss2_b",
+ "msiof2_rx_b",
+ "msiof2_tx_b",
+ "msiof2_clk_c",
+ "msiof2_sync_c",
+ "msiof2_rx_c",
+ "msiof2_tx_c",
+ "msiof2_clk_d",
+ "msiof2_sync_d",
+ "msiof2_ss1_d",
+ "msiof2_ss2_d",
+ "msiof2_rx_d",
+ "msiof2_tx_d",
+ "msiof2_clk_e",
+ "msiof2_sync_e",
+ "msiof2_rx_e",
+ "msiof2_tx_e",
+};
+
+static const char * const qspi_groups[] = {
+ "qspi_ctrl",
+ "qspi_data2",
+ "qspi_data4",
+ "qspi_ctrl_b",
+ "qspi_data2_b",
+ "qspi_data4_b",
};
static const char * const scif0_groups[] = {
@@ -3566,11 +4161,14 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(i2c2),
SH_PFC_FUNCTION(i2c3),
SH_PFC_FUNCTION(i2c4),
+ SH_PFC_FUNCTION(i2c7),
+ SH_PFC_FUNCTION(i2c8),
SH_PFC_FUNCTION(intc),
SH_PFC_FUNCTION(mmc),
SH_PFC_FUNCTION(msiof0),
SH_PFC_FUNCTION(msiof1),
SH_PFC_FUNCTION(msiof2),
+ SH_PFC_FUNCTION(qspi),
SH_PFC_FUNCTION(scif0),
SH_PFC_FUNCTION(scif1),
SH_PFC_FUNCTION(scif2),
@@ -3825,7 +4423,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
GP_6_11_FN, FN_IP13_25,
GP_6_10_FN, FN_IP13_24_23,
GP_6_9_FN, FN_IP13_22,
- 0, 0,
+ GP_6_8_FN, FN_SD1_CLK,
GP_6_7_FN, FN_IP13_21_19,
GP_6_6_FN, FN_IP13_18_16,
GP_6_5_FN, FN_IP13_15,
diff --git a/drivers/pinctrl/sirf/pinctrl-atlas6.c b/drivers/pinctrl/sirf/pinctrl-atlas6.c
index 2b9f32065920..c4dd3d5cf9c3 100644
--- a/drivers/pinctrl/sirf/pinctrl-atlas6.c
+++ b/drivers/pinctrl/sirf/pinctrl-atlas6.c
@@ -1,7 +1,8 @@
/*
* pinctrl pads, groups, functions for CSR SiRFatlasVI
*
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
*
* Licensed under GPLv2 or later.
*/
@@ -529,6 +530,40 @@ static const struct sirfsoc_padmux usp0_padmux = {
static const unsigned usp0_pins[] = { 51, 52, 53, 54, 55 };
+static const struct sirfsoc_muxmask usp0_only_utfs_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(19) | BIT(20) | BIT(21) | BIT(22),
+ },
+};
+
+static const struct sirfsoc_padmux usp0_only_utfs_padmux = {
+ .muxmask_counts = ARRAY_SIZE(usp0_only_utfs_muxmask),
+ .muxmask = usp0_only_utfs_muxmask,
+ .ctrlreg = SIRFSOC_RSC_PIN_MUX,
+ .funcmask = BIT(1) | BIT(2) | BIT(6),
+ .funcval = 0,
+};
+
+static const unsigned usp0_only_utfs_pins[] = { 51, 52, 53, 54 };
+
+static const struct sirfsoc_muxmask usp0_only_urfs_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(19) | BIT(20) | BIT(21) | BIT(23),
+ },
+};
+
+static const struct sirfsoc_padmux usp0_only_urfs_padmux = {
+ .muxmask_counts = ARRAY_SIZE(usp0_only_urfs_muxmask),
+ .muxmask = usp0_only_urfs_muxmask,
+ .ctrlreg = SIRFSOC_RSC_PIN_MUX,
+ .funcmask = BIT(1) | BIT(2) | BIT(9),
+ .funcval = 0,
+};
+
+static const unsigned usp0_only_urfs_pins[] = { 51, 52, 53, 55 };
+
static const struct sirfsoc_muxmask usp0_uart_nostreamctrl_muxmask[] = {
{
.group = 1,
@@ -905,6 +940,8 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
SIRFSOC_PIN_GROUP("usp0grp", usp0_pins),
SIRFSOC_PIN_GROUP("usp0_uart_nostreamctrl_grp",
usp0_uart_nostreamctrl_pins),
+ SIRFSOC_PIN_GROUP("usp0_only_utfs_grp", usp0_only_utfs_pins),
+ SIRFSOC_PIN_GROUP("usp0_only_urfs_grp", usp0_only_urfs_pins),
SIRFSOC_PIN_GROUP("usp1grp", usp1_pins),
SIRFSOC_PIN_GROUP("usp1_uart_nostreamctrl_grp",
usp1_uart_nostreamctrl_pins),
@@ -953,6 +990,9 @@ static const char * const uart2_nostreamctrlgrp[] = { "uart2_nostreamctrlgrp" };
static const char * const usp0_uart_nostreamctrl_grp[] = {
"usp0_uart_nostreamctrl_grp" };
static const char * const usp0grp[] = { "usp0grp" };
+static const char * const usp0_only_utfs_grp[] = { "usp0_only_utfs_grp" };
+static const char * const usp0_only_urfs_grp[] = { "usp0_only_urfs_grp" };
+
static const char * const usp1grp[] = { "usp1grp" };
static const char * const usp1_uart_nostreamctrl_grp[] = {
"usp1_uart_nostreamctrl_grp" };
@@ -1003,6 +1043,10 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = {
SIRFSOC_PMX_FUNCTION("usp0_uart_nostreamctrl",
usp0_uart_nostreamctrl_grp,
usp0_uart_nostreamctrl_padmux),
+ SIRFSOC_PMX_FUNCTION("usp0_only_utfs", usp0_only_utfs_grp,
+ usp0_only_utfs_padmux),
+ SIRFSOC_PMX_FUNCTION("usp0_only_urfs", usp0_only_urfs_grp,
+ usp0_only_urfs_padmux),
SIRFSOC_PMX_FUNCTION("usp1", usp1grp, usp1_padmux),
SIRFSOC_PMX_FUNCTION("usp1_uart_nostreamctrl",
usp1_uart_nostreamctrl_grp,
diff --git a/drivers/pinctrl/sirf/pinctrl-prima2.c b/drivers/pinctrl/sirf/pinctrl-prima2.c
index dde0285544d6..8aa76f0776d7 100644
--- a/drivers/pinctrl/sirf/pinctrl-prima2.c
+++ b/drivers/pinctrl/sirf/pinctrl-prima2.c
@@ -1,7 +1,8 @@
/*
* pinctrl pads, groups, functions for CSR SiRFprimaII
*
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
*
* Licensed under GPLv2 or later.
*/
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c
index a0d6152701cd..5f3adb87c1ef 100644
--- a/drivers/pinctrl/sirf/pinctrl-sirf.c
+++ b/drivers/pinctrl/sirf/pinctrl-sirf.c
@@ -1,7 +1,8 @@
/*
* pinmux driver for CSR SiRFprimaII
*
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ * Copyright (c) 2011 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
+ * company.
*
* Licensed under GPLv2 or later.
*/
@@ -598,7 +599,7 @@ static unsigned int sirfsoc_gpio_irq_startup(struct irq_data *d)
{
struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
- if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq))
+ if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE))
dev_err(bank->chip.gc.dev,
"unable to lock HW IRQ %lu for IRQ\n",
d->hwirq);
@@ -611,7 +612,7 @@ static void sirfsoc_gpio_irq_shutdown(struct irq_data *d)
struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
sirfsoc_gpio_irq_mask(d);
- gpio_unlock_as_irq(&bank->chip.gc, d->hwirq);
+ gpio_unlock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE);
}
static struct irq_chip sirfsoc_irq_chip = {
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 5ae65c11d544..5f67843c7fb7 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -27,8 +27,6 @@ config ACER_WMI
depends on ACPI_WMI
select INPUT_SPARSEKMAP
# Acer WMI depends on ACPI_VIDEO when ACPI is enabled
- # but for select to work, need to select ACPI_VIDEO's dependencies, ick
- select VIDEO_OUTPUT_CONTROL if ACPI
select ACPI_VIDEO if ACPI
---help---
This is a driver for newer Acer (and Wistron) laptops. It adds
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index be02bcc346d3..e6f336270c21 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -66,7 +66,6 @@
#include <linux/backlight.h>
#include <linux/input.h>
#include <linux/kfifo.h>
-#include <linux/video_output.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index defb6afc1409..94bb6157c957 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -6776,8 +6776,9 @@ static int __init volume_create_alsa_mixer(void)
struct snd_kcontrol *ctl_mute;
int rc;
- rc = snd_card_create(alsa_index, alsa_id, THIS_MODULE,
- sizeof(struct tpacpi_alsa_data), &card);
+ rc = snd_card_new(&tpacpi_pdev->dev,
+ alsa_index, alsa_id, THIS_MODULE,
+ sizeof(struct tpacpi_alsa_data), &card);
if (rc < 0 || !card) {
pr_err("Failed to create ALSA card structures: %d\n", rc);
return 1;
@@ -6828,7 +6829,6 @@ static int __init volume_create_alsa_mixer(void)
}
data->ctl_mute_id = &ctl_mute->id;
- snd_card_set_dev(card, &tpacpi_pdev->dev);
rc = snd_card_register(card);
if (rc < 0) {
pr_err("Failed to register ALSA card: %d\n", rc);
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 167f3d00c916..66977ebf13b3 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -183,9 +183,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
struct resource r = {0};
int i, flags;
- if (acpi_dev_resource_memory(res, &r)
- || acpi_dev_resource_io(res, &r)
- || acpi_dev_resource_address_space(res, &r)
+ if (acpi_dev_resource_address_space(res, &r)
|| acpi_dev_resource_ext_address_space(res, &r)) {
pnp_add_resource(dev, &r);
return AE_OK;
@@ -217,6 +215,17 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
}
switch (res->type) {
+ case ACPI_RESOURCE_TYPE_MEMORY24:
+ case ACPI_RESOURCE_TYPE_MEMORY32:
+ case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+ if (acpi_dev_resource_memory(res, &r))
+ pnp_add_resource(dev, &r);
+ break;
+ case ACPI_RESOURCE_TYPE_IO:
+ case ACPI_RESOURCE_TYPE_FIXED_IO:
+ if (acpi_dev_resource_io(res, &r))
+ pnp_add_resource(dev, &r);
+ break;
case ACPI_RESOURCE_TYPE_DMA:
dma = &res->data.dma;
if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c
index 769d265b221b..deb7f4bcdb7b 100644
--- a/drivers/pnp/pnpbios/bioscalls.c
+++ b/drivers/pnp/pnpbios/bioscalls.c
@@ -21,7 +21,7 @@
#include "pnpbios.h"
-static struct {
+__visible struct {
u16 offset;
u16 segment;
} pnp_bios_callpoint;
@@ -41,6 +41,7 @@ asmlinkage void pnp_bios_callfunc(void);
__asm__(".text \n"
__ALIGN_STR "\n"
+ ".globl pnp_bios_callfunc\n"
"pnp_bios_callfunc:\n"
" pushl %edx \n"
" pushl %ecx \n"
@@ -66,9 +67,9 @@ static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092,
* after PnP BIOS oopses.
*/
-u32 pnp_bios_fault_esp;
-u32 pnp_bios_fault_eip;
-u32 pnp_bios_is_utter_crap = 0;
+__visible u32 pnp_bios_fault_esp;
+__visible u32 pnp_bios_fault_eip;
+__visible u32 pnp_bios_is_utter_crap = 0;
static spinlock_t pnp_bios_lock;
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index bacddd102ae9..01712cbfd92e 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -385,7 +385,7 @@ int pnp_check_irq(struct pnp_dev *dev, struct resource *res)
* device is active because it itself may be in use */
if (!dev->active) {
if (request_irq(*irq, pnp_test_handler,
- IRQF_DISABLED | IRQF_PROBE_SHARED, "pnp", NULL))
+ IRQF_PROBE_SHARED, "pnp", NULL))
return 0;
free_irq(*irq, NULL);
}
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index 3c6768378a94..61b51e17d932 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -834,7 +834,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
}
static const struct x86_cpu_id energy_unit_quirk_ids[] = {
- { X86_VENDOR_INTEL, 6, 0x37},/* VLV */
+ { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */
{}
};
@@ -947,11 +947,11 @@ static void package_power_limit_irq_restore(int package_id)
}
static const struct x86_cpu_id rapl_ids[] = {
- { X86_VENDOR_INTEL, 6, 0x2a},/* SNB */
- { X86_VENDOR_INTEL, 6, 0x2d},/* SNB EP */
- { X86_VENDOR_INTEL, 6, 0x37},/* VLV */
- { X86_VENDOR_INTEL, 6, 0x3a},/* IVB */
- { X86_VENDOR_INTEL, 6, 0x45},/* HSW */
+ { X86_VENDOR_INTEL, 6, 0x2a},/* Sandy Bridge */
+ { X86_VENDOR_INTEL, 6, 0x2d},/* Sandy Bridge EP */
+ { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */
+ { X86_VENDOR_INTEL, 6, 0x3a},/* Ivy Bridge */
+ { X86_VENDOR_INTEL, 6, 0x45},/* Haswell */
/* TODO: Add more CPU IDs after testing */
{}
};
@@ -1147,6 +1147,11 @@ static int rapl_check_domain(int cpu, int domain)
if (rdmsrl_safe_on_cpu(cpu, msr, &val1))
return -ENODEV;
+ /* PP1/uncore/graphics domain may not be active at the time of
+ * driver loading. So skip further checks.
+ */
+ if (domain == RAPL_DOMAIN_PP1)
+ return 0;
/* energy counters roll slowly on some domains */
while (++retry < 10) {
usleep_range(10000, 15000);
diff --git a/drivers/ps3/ps3-vuart.c b/drivers/ps3/ps3-vuart.c
index fb7300837fee..bc1e5139ba29 100644
--- a/drivers/ps3/ps3-vuart.c
+++ b/drivers/ps3/ps3-vuart.c
@@ -699,8 +699,6 @@ int ps3_vuart_read_async(struct ps3_system_bus_device *dev, unsigned int bytes)
BUG_ON(!bytes);
- PREPARE_WORK(&priv->rx_list.work.work, ps3_vuart_work);
-
spin_lock_irqsave(&priv->rx_list.lock, flags);
if (priv->rx_list.bytes_held >= bytes) {
dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n",
@@ -1052,7 +1050,7 @@ static int ps3_vuart_probe(struct ps3_system_bus_device *dev)
INIT_LIST_HEAD(&priv->rx_list.head);
spin_lock_init(&priv->rx_list.lock);
- INIT_WORK(&priv->rx_list.work.work, NULL);
+ INIT_WORK(&priv->rx_list.work.work, ps3_vuart_work);
priv->rx_list.work.trigger = 0;
priv->rx_list.work.dev = dev;
diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c
index 8a843a04c224..a40b9c34e9ff 100644
--- a/drivers/pwm/pwm-lp3943.c
+++ b/drivers/pwm/pwm-lp3943.c
@@ -52,8 +52,10 @@ lp3943_pwm_request_map(struct lp3943_pwm *lp3943_pwm, int hwpwm)
offset = pwm_map->output[i];
/* Return an error if the pin is already assigned */
- if (test_and_set_bit(offset, &lp3943->pin_used))
+ if (test_and_set_bit(offset, &lp3943->pin_used)) {
+ kfree(pwm_map);
return ERR_PTR(-EBUSY);
+ }
}
return pwm_map;
diff --git a/drivers/rapidio/devices/tsi721.h b/drivers/rapidio/devices/tsi721.h
index b4b0d83f9ef6..7061ac0ad428 100644
--- a/drivers/rapidio/devices/tsi721.h
+++ b/drivers/rapidio/devices/tsi721.h
@@ -678,6 +678,7 @@ struct tsi721_bdma_chan {
struct list_head free_list;
dma_cookie_t completed_cookie;
struct tasklet_struct tasklet;
+ bool active;
};
#endif /* CONFIG_RAPIDIO_DMA_ENGINE */
diff --git a/drivers/rapidio/devices/tsi721_dma.c b/drivers/rapidio/devices/tsi721_dma.c
index 502663f5f7c6..91245f5dbe81 100644
--- a/drivers/rapidio/devices/tsi721_dma.c
+++ b/drivers/rapidio/devices/tsi721_dma.c
@@ -206,8 +206,8 @@ void tsi721_bdma_handler(struct tsi721_bdma_chan *bdma_chan)
{
/* Disable BDMA channel interrupts */
iowrite32(0, bdma_chan->regs + TSI721_DMAC_INTE);
-
- tasklet_schedule(&bdma_chan->tasklet);
+ if (bdma_chan->active)
+ tasklet_schedule(&bdma_chan->tasklet);
}
#ifdef CONFIG_PCI_MSI
@@ -562,7 +562,7 @@ static int tsi721_alloc_chan_resources(struct dma_chan *dchan)
}
#endif /* CONFIG_PCI_MSI */
- tasklet_enable(&bdma_chan->tasklet);
+ bdma_chan->active = true;
tsi721_bdma_interrupt_enable(bdma_chan, 1);
return bdma_chan->bd_num - 1;
@@ -576,9 +576,7 @@ err_out:
static void tsi721_free_chan_resources(struct dma_chan *dchan)
{
struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan);
-#ifdef CONFIG_PCI_MSI
struct tsi721_device *priv = to_tsi721(dchan->device);
-#endif
LIST_HEAD(list);
dev_dbg(dchan->device->dev, "%s: Entry\n", __func__);
@@ -589,14 +587,25 @@ static void tsi721_free_chan_resources(struct dma_chan *dchan)
BUG_ON(!list_empty(&bdma_chan->active_list));
BUG_ON(!list_empty(&bdma_chan->queue));
- tasklet_disable(&bdma_chan->tasklet);
+ tsi721_bdma_interrupt_enable(bdma_chan, 0);
+ bdma_chan->active = false;
+
+#ifdef CONFIG_PCI_MSI
+ if (priv->flags & TSI721_USING_MSIX) {
+ synchronize_irq(priv->msix[TSI721_VECT_DMA0_DONE +
+ bdma_chan->id].vector);
+ synchronize_irq(priv->msix[TSI721_VECT_DMA0_INT +
+ bdma_chan->id].vector);
+ } else
+#endif
+ synchronize_irq(priv->pdev->irq);
+
+ tasklet_kill(&bdma_chan->tasklet);
spin_lock_bh(&bdma_chan->lock);
list_splice_init(&bdma_chan->free_list, &list);
spin_unlock_bh(&bdma_chan->lock);
- tsi721_bdma_interrupt_enable(bdma_chan, 0);
-
#ifdef CONFIG_PCI_MSI
if (priv->flags & TSI721_USING_MSIX) {
free_irq(priv->msix[TSI721_VECT_DMA0_DONE +
@@ -790,6 +799,7 @@ int tsi721_register_dma(struct tsi721_device *priv)
bdma_chan->dchan.cookie = 1;
bdma_chan->dchan.chan_id = i;
bdma_chan->id = i;
+ bdma_chan->active = false;
spin_lock_init(&bdma_chan->lock);
@@ -799,7 +809,6 @@ int tsi721_register_dma(struct tsi721_device *priv)
tasklet_init(&bdma_chan->tasklet, tsi721_dma_tasklet,
(unsigned long)bdma_chan);
- tasklet_disable(&bdma_chan->tasklet);
list_add_tail(&bdma_chan->dchan.device_node,
&mport->dma.channels);
}
diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c
index d333f7eac106..7a721d67e6ac 100644
--- a/drivers/regulator/88pm800.c
+++ b/drivers/regulator/88pm800.c
@@ -310,10 +310,8 @@ static int pm800_regulator_probe(struct platform_device *pdev)
pm800_data = devm_kzalloc(&pdev->dev, sizeof(*pm800_data),
GFP_KERNEL);
- if (!pm800_data) {
- dev_err(&pdev->dev, "Failed to allocate pm800_regualtors");
+ if (!pm800_data)
return -ENOMEM;
- }
pm800_data->map = chip->subchip->regmap_power;
pm800_data->chip = chip;
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index f704d83c93c4..337634ad0562 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -2,7 +2,7 @@
* Regulators driver for Marvell 88PM8607
*
* Copyright (C) 2009 Marvell International Ltd.
- * Haojian Zhuang <haojian.zhuang@marvell.com>
+ * Haojian Zhuang <haojian.zhuang@marvell.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -78,7 +78,7 @@ static const unsigned int BUCK2_suspend_table[] = {
};
static const unsigned int BUCK3_table[] = {
- 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
+ 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000,
400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000,
600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000,
@@ -89,7 +89,7 @@ static const unsigned int BUCK3_table[] = {
};
static const unsigned int BUCK3_suspend_table[] = {
- 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
+ 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000,
400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000,
600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000,
@@ -322,7 +322,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,
nproot = of_node_get(pdev->dev.parent->of_node);
if (!nproot)
return -ENODEV;
- nproot = of_find_node_by_name(nproot, "regulators");
+ nproot = of_get_child_by_name(nproot, "regulators");
if (!nproot) {
dev_err(&pdev->dev, "failed to find regulators node\n");
return -ENODEV;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 6a7932822e37..1cd8584a7b88 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -139,6 +139,14 @@ config REGULATOR_AS3722
AS3722 PMIC. This will enable support for all the software
controllable DCDC/LDO regulators.
+config REGULATOR_BCM590XX
+ tristate "Broadcom BCM590xx PMU Regulators"
+ depends on MFD_BCM590XX
+ help
+ This driver provides support for the voltage regulators on the
+ BCM590xx PMUs. This will enable support for the software
+ controllable LDO/Switching regulators.
+
config REGULATOR_DA903X
tristate "Dialog Semiconductor DA9030/DA9034 regulators"
depends on PMIC_DA903X
@@ -399,12 +407,12 @@ config REGULATOR_PCF50633
on PCF50633
config REGULATOR_PFUZE100
- tristate "Freescale PFUZE100 regulator driver"
+ tristate "Freescale PFUZE100/PFUZE200 regulator driver"
depends on I2C
select REGMAP_I2C
help
- Say y here to support the regulators found on the Freescale PFUZE100
- PMIC.
+ Say y here to support the regulators found on the Freescale
+ PFUZE100/PFUZE200 PMIC.
config REGULATOR_RC5T583
tristate "RICOH RC5T583 Power regulators"
@@ -416,13 +424,21 @@ config REGULATOR_RC5T583
through regulator interface. The device supports multiple DCDC/LDO
outputs which can be controlled by i2c communication.
+config REGULATOR_S2MPA01
+ tristate "Samsung S2MPA01 voltage regulator"
+ depends on MFD_SEC_CORE
+ help
+ This driver controls Samsung S2MPA01 voltage output regulator
+ via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs.
+
config REGULATOR_S2MPS11
- tristate "Samsung S2MPS11 voltage regulator"
+ tristate "Samsung S2MPS11/S2MPS14 voltage regulator"
depends on MFD_SEC_CORE
help
- This driver supports a Samsung S2MPS11 voltage output regulator
- via I2C bus. S2MPS11 is comprised of high efficient Buck converters
- including Dual-Phase Buck converter, Buck-Boost converter, various LDOs.
+ This driver supports a Samsung S2MPS11/S2MPS14 voltage output
+ regulator via I2C bus. The chip is comprised of high efficient Buck
+ converters including Dual-Phase Buck converter, Buck-Boost converter,
+ various LDOs.
config REGULATOR_S5M8767
tristate "Samsung S5M8767A voltage regulator"
@@ -432,6 +448,12 @@ config REGULATOR_S5M8767
via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
supports DVS mode with 8bits of output voltage control.
+config REGULATOR_ST_PWM
+ tristate "STMicroelectronics PWM voltage regulator"
+ depends on ARCH_STI
+ help
+ This driver supports ST's PWM controlled voltage regulators.
+
config REGULATOR_TI_ABB
tristate "TI Adaptive Body Bias on-chip LDO"
depends on ARCH_OMAP
@@ -513,6 +535,15 @@ config REGULATOR_TPS65217
voltage regulators. It supports software based voltage control
for different voltage domains
+config REGULATOR_TPS65218
+ tristate "TI TPS65218 Power regulators"
+ depends on MFD_TPS65218 && OF
+ help
+ This driver supports TPS65218 voltage regulator chips. TPS65218
+ provides six step-down converters and one general-purpose LDO
+ voltage regulators. It supports software based voltage control
+ for different voltage domains
+
config REGULATOR_TPS6524X
tristate "TI TPS6524X Power regulators"
depends on SPI
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 979f9ddcf259..f0fe0c50b59c 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
+obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o
@@ -57,8 +58,10 @@ obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
+obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
+obj-$(CONFIG_REGULATOR_ST_PWM) += st-pwm.o
obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
@@ -67,6 +70,7 @@ obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65090) += tps65090-regulator.o
obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65218) += tps65218-regulator.o
obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c
index f70a9bfa5ff2..c873ee0082cf 100644
--- a/drivers/regulator/aat2870-regulator.c
+++ b/drivers/regulator/aat2870-regulator.c
@@ -99,6 +99,7 @@ static int aat2870_ldo_is_enabled(struct regulator_dev *rdev)
static struct regulator_ops aat2870_ldo_ops = {
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = aat2870_ldo_set_voltage_sel,
.get_voltage_sel = aat2870_ldo_get_voltage_sel,
.enable = aat2870_ldo_enable,
diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c
index 084cc0819a52..b92d7dd01a18 100644
--- a/drivers/regulator/act8865-regulator.c
+++ b/drivers/regulator/act8865-regulator.c
@@ -62,7 +62,6 @@
#define ACT8865_VOLTAGE_NUM 64
struct act8865 {
- struct regulator_dev *rdev[ACT8865_REG_NUM];
struct regmap *regmap;
};
@@ -213,7 +212,7 @@ static int act8865_pdata_from_dt(struct device *dev,
struct device_node *np;
struct act8865_regulator_data *regulator;
- np = of_find_node_by_name(dev->of_node, "regulators");
+ np = of_get_child_by_name(dev->of_node, "regulators");
if (!np) {
dev_err(dev, "missing 'regulators' subnode in DT\n");
return -EINVAL;
@@ -221,17 +220,15 @@ static int act8865_pdata_from_dt(struct device *dev,
matched = of_regulator_match(dev, np,
act8865_matches, ARRAY_SIZE(act8865_matches));
+ of_node_put(np);
if (matched <= 0)
return matched;
pdata->regulators = devm_kzalloc(dev,
sizeof(struct act8865_regulator_data) *
ARRAY_SIZE(act8865_matches), GFP_KERNEL);
- if (!pdata->regulators) {
- dev_err(dev, "%s: failed to allocate act8865 registor\n",
- __func__);
+ if (!pdata->regulators)
return -ENOMEM;
- }
pdata->num_regulators = matched;
regulator = pdata->regulators;
@@ -258,7 +255,7 @@ static inline int act8865_pdata_from_dt(struct device *dev,
static int act8865_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
- struct regulator_dev **rdev;
+ struct regulator_dev *rdev;
struct device *dev = &client->dev;
struct act8865_platform_data *pdata = dev_get_platdata(dev);
struct regulator_config config = { };
@@ -292,8 +289,6 @@ static int act8865_pmic_probe(struct i2c_client *client,
if (!act8865)
return -ENOMEM;
- rdev = act8865->rdev;
-
act8865->regmap = devm_regmap_init_i2c(client, &act8865_regmap_config);
if (IS_ERR(act8865->regmap)) {
error = PTR_ERR(act8865->regmap);
@@ -313,12 +308,12 @@ static int act8865_pmic_probe(struct i2c_client *client,
config.driver_data = act8865;
config.regmap = act8865->regmap;
- rdev[i] = devm_regulator_register(&client->dev,
- &act8865_reg[i], &config);
- if (IS_ERR(rdev[i])) {
+ rdev = devm_regulator_register(&client->dev, &act8865_reg[i],
+ &config);
+ if (IS_ERR(rdev)) {
dev_err(dev, "failed to register %s\n",
act8865_reg[id].name);
- return PTR_ERR(rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index 862e63e451d0..7c397bb81e01 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -34,6 +34,9 @@
#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */
#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */
+#define LDO_POWER_GATE 0x00
+#define LDO_FET_FULL_ON 0x1f
+
struct anatop_regulator {
const char *name;
u32 control_reg;
@@ -48,19 +51,10 @@ struct anatop_regulator {
int max_voltage;
struct regulator_desc rdesc;
struct regulator_init_data *initdata;
+ bool bypass;
+ int sel;
};
-static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg,
- unsigned selector)
-{
- struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
-
- if (!anatop_reg->control_reg)
- return -ENOTSUPP;
-
- return regulator_set_voltage_sel_regmap(reg, selector);
-}
-
static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
unsigned int old_sel,
unsigned int new_sel)
@@ -87,22 +81,99 @@ static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
return ret;
}
-static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
+static int anatop_regmap_enable(struct regulator_dev *reg)
{
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+ int sel;
- if (!anatop_reg->control_reg)
- return -ENOTSUPP;
+ sel = anatop_reg->bypass ? LDO_FET_FULL_ON : anatop_reg->sel;
+ return regulator_set_voltage_sel_regmap(reg, sel);
+}
+
+static int anatop_regmap_disable(struct regulator_dev *reg)
+{
+ return regulator_set_voltage_sel_regmap(reg, LDO_POWER_GATE);
+}
+
+static int anatop_regmap_is_enabled(struct regulator_dev *reg)
+{
+ return regulator_get_voltage_sel_regmap(reg) != LDO_POWER_GATE;
+}
+
+static int anatop_regmap_core_set_voltage_sel(struct regulator_dev *reg,
+ unsigned selector)
+{
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+ int ret;
+
+ if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) {
+ anatop_reg->sel = selector;
+ return 0;
+ }
+
+ ret = regulator_set_voltage_sel_regmap(reg, selector);
+ if (!ret)
+ anatop_reg->sel = selector;
+ return ret;
+}
+
+static int anatop_regmap_core_get_voltage_sel(struct regulator_dev *reg)
+{
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+
+ if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg))
+ return anatop_reg->sel;
return regulator_get_voltage_sel_regmap(reg);
}
+static int anatop_regmap_get_bypass(struct regulator_dev *reg, bool *enable)
+{
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+ int sel;
+
+ sel = regulator_get_voltage_sel_regmap(reg);
+ if (sel == LDO_FET_FULL_ON)
+ WARN_ON(!anatop_reg->bypass);
+ else if (sel != LDO_POWER_GATE)
+ WARN_ON(anatop_reg->bypass);
+
+ *enable = anatop_reg->bypass;
+ return 0;
+}
+
+static int anatop_regmap_set_bypass(struct regulator_dev *reg, bool enable)
+{
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+ int sel;
+
+ if (enable == anatop_reg->bypass)
+ return 0;
+
+ sel = enable ? LDO_FET_FULL_ON : anatop_reg->sel;
+ anatop_reg->bypass = enable;
+
+ return regulator_set_voltage_sel_regmap(reg, sel);
+}
+
static struct regulator_ops anatop_rops = {
- .set_voltage_sel = anatop_regmap_set_voltage_sel,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+};
+
+static struct regulator_ops anatop_core_rops = {
+ .enable = anatop_regmap_enable,
+ .disable = anatop_regmap_disable,
+ .is_enabled = anatop_regmap_is_enabled,
+ .set_voltage_sel = anatop_regmap_core_set_voltage_sel,
.set_voltage_time_sel = anatop_regmap_set_voltage_time_sel,
- .get_voltage_sel = anatop_regmap_get_voltage_sel,
+ .get_voltage_sel = anatop_regmap_core_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
+ .get_bypass = anatop_regmap_get_bypass,
+ .set_bypass = anatop_regmap_set_bypass,
};
static int anatop_regulator_probe(struct platform_device *pdev)
@@ -116,6 +187,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
struct regulator_init_data *initdata;
struct regulator_config config = { };
int ret = 0;
+ u32 val;
initdata = of_get_regulator_init_data(dev, np);
sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
@@ -125,7 +197,6 @@ static int anatop_regulator_probe(struct platform_device *pdev)
sreg->name = of_get_property(np, "regulator-name", NULL);
rdesc = &sreg->rdesc;
rdesc->name = sreg->name;
- rdesc->ops = &anatop_rops;
rdesc->type = REGULATOR_VOLTAGE;
rdesc->owner = THIS_MODULE;
@@ -197,6 +268,25 @@ static int anatop_regulator_probe(struct platform_device *pdev)
config.of_node = pdev->dev.of_node;
config.regmap = sreg->anatop;
+ /* Only core regulators have the ramp up delay configuration. */
+ if (sreg->control_reg && sreg->delay_bit_width) {
+ rdesc->ops = &anatop_core_rops;
+
+ ret = regmap_read(config.regmap, rdesc->vsel_reg, &val);
+ if (ret) {
+ dev_err(dev, "failed to read initial state\n");
+ return ret;
+ }
+
+ sreg->sel = (val & rdesc->vsel_mask) >> sreg->vol_bit_shift;
+ if (sreg->sel == LDO_FET_FULL_ON) {
+ sreg->sel = 0;
+ sreg->bypass = true;
+ }
+ } else {
+ rdesc->ops = &anatop_rops;
+ }
+
/* register regulator */
rdev = devm_regulator_register(dev, rdesc, &config);
if (IS_ERR(rdev)) {
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
index 4f6c2055f6b2..b1033d30b504 100644
--- a/drivers/regulator/arizona-ldo1.c
+++ b/drivers/regulator/arizona-ldo1.c
@@ -153,11 +153,9 @@ static const struct regulator_desc arizona_ldo1 = {
.vsel_reg = ARIZONA_LDO1_CONTROL_1,
.vsel_mask = ARIZONA_LDO1_VSEL_MASK,
- .bypass_reg = ARIZONA_LDO1_CONTROL_1,
- .bypass_mask = ARIZONA_LDO1_BYPASS,
.min_uV = 900000,
- .uV_step = 50000,
- .n_voltages = 7,
+ .uV_step = 25000,
+ .n_voltages = 13,
.enable_time = 500,
.owner = THIS_MODULE,
@@ -189,10 +187,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
int ret;
ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
- if (ldo1 == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!ldo1)
return -ENOMEM;
- }
ldo1->arizona = arizona;
@@ -203,6 +199,7 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
*/
switch (arizona->type) {
case WM5102:
+ case WM8997:
desc = &arizona_ldo1_hc;
ldo1->init_data = arizona_ldo1_dvfs;
break;
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
index 034ece707083..6fdd9bf6927f 100644
--- a/drivers/regulator/arizona-micsupp.c
+++ b/drivers/regulator/arizona-micsupp.c
@@ -204,10 +204,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
int ret;
micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
- if (micsupp == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!micsupp)
return -ENOMEM;
- }
micsupp->arizona = arizona;
INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp);
diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c
index c77a58478cca..b47283f91e2d 100644
--- a/drivers/regulator/as3711-regulator.c
+++ b/drivers/regulator/as3711-regulator.c
@@ -191,7 +191,7 @@ static int as3711_regulator_parse_dt(struct device *dev,
{
struct as3711_regulator_pdata *pdata = dev_get_platdata(dev);
struct device_node *regulators =
- of_find_node_by_name(dev->parent->of_node, "regulators");
+ of_get_child_by_name(dev->parent->of_node, "regulators");
struct of_regulator_match *match;
int ret, i;
@@ -221,7 +221,6 @@ static int as3711_regulator_probe(struct platform_device *pdev)
{
struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev);
struct as3711 *as3711 = dev_get_drvdata(pdev->dev.parent);
- struct regulator_init_data *reg_data;
struct regulator_config config = {.dev = &pdev->dev,};
struct as3711_regulator *reg = NULL;
struct as3711_regulator *regs;
@@ -246,22 +245,14 @@ static int as3711_regulator_probe(struct platform_device *pdev)
regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM *
sizeof(struct as3711_regulator), GFP_KERNEL);
- if (!regs) {
- dev_err(&pdev->dev, "Memory allocation failed exiting..\n");
+ if (!regs)
return -ENOMEM;
- }
for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) {
- reg_data = pdata->init_data[id];
-
- /* No need to register if there is no regulator data */
- if (!reg_data)
- continue;
-
reg = &regs[id];
reg->reg_info = ri;
- config.init_data = reg_data;
+ config.init_data = pdata->init_data[id];
config.driver_data = reg;
config.regmap = as3711->regmap;
config.of_node = of_node[id];
diff --git a/drivers/regulator/as3722-regulator.c b/drivers/regulator/as3722-regulator.c
index 8b17d786cb71..85585219ce82 100644
--- a/drivers/regulator/as3722-regulator.c
+++ b/drivers/regulator/as3722-regulator.c
@@ -719,6 +719,7 @@ static int as3722_get_regulator_dt_data(struct platform_device *pdev,
ret = of_regulator_match(&pdev->dev, np, as3722_regulator_matches,
ARRAY_SIZE(as3722_regulator_matches));
+ of_node_put(np);
if (ret < 0) {
dev_err(&pdev->dev, "Parsing of regulator node failed: %d\n",
ret);
diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c
new file mode 100644
index 000000000000..ab08ca7cfb08
--- /dev/null
+++ b/drivers/regulator/bcm590xx-regulator.c
@@ -0,0 +1,403 @@
+/*
+ * Broadcom BCM590xx regulator driver
+ *
+ * Copyright 2014 Linaro Limited
+ * Author: Matt Porter <mporter@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.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mfd/bcm590xx.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
+
+/* Register defs */
+#define BCM590XX_RFLDOPMCTRL1 0x60
+#define BCM590XX_IOSR1PMCTRL1 0x7a
+#define BCM590XX_IOSR2PMCTRL1 0x7c
+#define BCM590XX_CSRPMCTRL1 0x7e
+#define BCM590XX_SDSR1PMCTRL1 0x82
+#define BCM590XX_SDSR2PMCTRL1 0x86
+#define BCM590XX_MSRPMCTRL1 0x8a
+#define BCM590XX_VSRPMCTRL1 0x8e
+#define BCM590XX_REG_ENABLE BIT(7)
+
+#define BCM590XX_RFLDOCTRL 0x96
+#define BCM590XX_CSRVOUT1 0xc0
+#define BCM590XX_LDO_VSEL_MASK GENMASK(5, 3)
+#define BCM590XX_SR_VSEL_MASK GENMASK(5, 0)
+
+/* LDO regulator IDs */
+#define BCM590XX_REG_RFLDO 0
+#define BCM590XX_REG_CAMLDO1 1
+#define BCM590XX_REG_CAMLDO2 2
+#define BCM590XX_REG_SIMLDO1 3
+#define BCM590XX_REG_SIMLDO2 4
+#define BCM590XX_REG_SDLDO 5
+#define BCM590XX_REG_SDXLDO 6
+#define BCM590XX_REG_MMCLDO1 7
+#define BCM590XX_REG_MMCLDO2 8
+#define BCM590XX_REG_AUDLDO 9
+#define BCM590XX_REG_MICLDO 10
+#define BCM590XX_REG_USBLDO 11
+#define BCM590XX_REG_VIBLDO 12
+
+/* DCDC regulator IDs */
+#define BCM590XX_REG_CSR 13
+#define BCM590XX_REG_IOSR1 14
+#define BCM590XX_REG_IOSR2 15
+#define BCM590XX_REG_MSR 16
+#define BCM590XX_REG_SDSR1 17
+#define BCM590XX_REG_SDSR2 18
+#define BCM590XX_REG_VSR 19
+
+#define BCM590XX_NUM_REGS 20
+
+#define BCM590XX_REG_IS_LDO(n) (n < BCM590XX_REG_CSR)
+
+struct bcm590xx_board {
+ struct regulator_init_data *bcm590xx_pmu_init_data[BCM590XX_NUM_REGS];
+};
+
+/* LDO group A: supported voltages in microvolts */
+static const unsigned int ldo_a_table[] = {
+ 1200000, 1800000, 2500000, 2700000, 2800000,
+ 2900000, 3000000, 3300000,
+};
+
+/* LDO group C: supported voltages in microvolts */
+static const unsigned int ldo_c_table[] = {
+ 3100000, 1800000, 2500000, 2700000, 2800000,
+ 2900000, 3000000, 3300000,
+};
+
+/* DCDC group CSR: supported voltages in microvolts */
+static const struct regulator_linear_range dcdc_csr_ranges[] = {
+ REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000),
+ REGULATOR_LINEAR_RANGE(1360000, 51, 55, 20000),
+ REGULATOR_LINEAR_RANGE(900000, 56, 63, 0),
+};
+
+/* DCDC group IOSR1: supported voltages in microvolts */
+static const struct regulator_linear_range dcdc_iosr1_ranges[] = {
+ REGULATOR_LINEAR_RANGE(860000, 2, 51, 10000),
+ REGULATOR_LINEAR_RANGE(1500000, 52, 52, 0),
+ REGULATOR_LINEAR_RANGE(1800000, 53, 53, 0),
+ REGULATOR_LINEAR_RANGE(900000, 54, 63, 0),
+};
+
+/* DCDC group SDSR1: supported voltages in microvolts */
+static const struct regulator_linear_range dcdc_sdsr1_ranges[] = {
+ REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000),
+ REGULATOR_LINEAR_RANGE(1340000, 51, 51, 0),
+ REGULATOR_LINEAR_RANGE(900000, 52, 63, 0),
+};
+
+struct bcm590xx_info {
+ const char *name;
+ const char *vin_name;
+ u8 n_voltages;
+ const unsigned int *volt_table;
+ u8 n_linear_ranges;
+ const struct regulator_linear_range *linear_ranges;
+};
+
+#define BCM590XX_REG_TABLE(_name, _table) \
+ { \
+ .name = #_name, \
+ .n_voltages = ARRAY_SIZE(_table), \
+ .volt_table = _table, \
+ }
+
+#define BCM590XX_REG_RANGES(_name, _ranges) \
+ { \
+ .name = #_name, \
+ .n_linear_ranges = ARRAY_SIZE(_ranges), \
+ .linear_ranges = _ranges, \
+ }
+
+static struct bcm590xx_info bcm590xx_regs[] = {
+ BCM590XX_REG_TABLE(rfldo, ldo_a_table),
+ BCM590XX_REG_TABLE(camldo1, ldo_c_table),
+ BCM590XX_REG_TABLE(camldo2, ldo_c_table),
+ BCM590XX_REG_TABLE(simldo1, ldo_a_table),
+ BCM590XX_REG_TABLE(simldo2, ldo_a_table),
+ BCM590XX_REG_TABLE(sdldo, ldo_c_table),
+ BCM590XX_REG_TABLE(sdxldo, ldo_a_table),
+ BCM590XX_REG_TABLE(mmcldo1, ldo_a_table),
+ BCM590XX_REG_TABLE(mmcldo2, ldo_a_table),
+ BCM590XX_REG_TABLE(audldo, ldo_a_table),
+ BCM590XX_REG_TABLE(micldo, ldo_a_table),
+ BCM590XX_REG_TABLE(usbldo, ldo_a_table),
+ BCM590XX_REG_TABLE(vibldo, ldo_c_table),
+ BCM590XX_REG_RANGES(csr, dcdc_csr_ranges),
+ BCM590XX_REG_RANGES(iosr1, dcdc_iosr1_ranges),
+ BCM590XX_REG_RANGES(iosr2, dcdc_iosr1_ranges),
+ BCM590XX_REG_RANGES(msr, dcdc_iosr1_ranges),
+ BCM590XX_REG_RANGES(sdsr1, dcdc_sdsr1_ranges),
+ BCM590XX_REG_RANGES(sdsr2, dcdc_iosr1_ranges),
+ BCM590XX_REG_RANGES(vsr, dcdc_iosr1_ranges),
+};
+
+struct bcm590xx_reg {
+ struct regulator_desc *desc;
+ struct bcm590xx *mfd;
+ struct bcm590xx_info **info;
+};
+
+static int bcm590xx_get_vsel_register(int id)
+{
+ if (BCM590XX_REG_IS_LDO(id))
+ return BCM590XX_RFLDOCTRL + id;
+ else
+ return BCM590XX_CSRVOUT1 + (id - BCM590XX_REG_CSR) * 3;
+}
+
+static int bcm590xx_get_enable_register(int id)
+{
+ int reg = 0;
+
+ if (BCM590XX_REG_IS_LDO(id))
+ reg = BCM590XX_RFLDOPMCTRL1 + id * 2;
+ else
+ switch (id) {
+ case BCM590XX_REG_CSR:
+ reg = BCM590XX_CSRPMCTRL1;
+ break;
+ case BCM590XX_REG_IOSR1:
+ reg = BCM590XX_IOSR1PMCTRL1;
+ break;
+ case BCM590XX_REG_IOSR2:
+ reg = BCM590XX_IOSR2PMCTRL1;
+ break;
+ case BCM590XX_REG_MSR:
+ reg = BCM590XX_MSRPMCTRL1;
+ break;
+ case BCM590XX_REG_SDSR1:
+ reg = BCM590XX_SDSR1PMCTRL1;
+ break;
+ case BCM590XX_REG_SDSR2:
+ reg = BCM590XX_SDSR2PMCTRL1;
+ break;
+ };
+
+ return reg;
+}
+
+static struct regulator_ops bcm590xx_ops_ldo = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_iterate,
+};
+
+static struct regulator_ops bcm590xx_ops_dcdc = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+};
+
+#define BCM590XX_MATCH(_name, _id) \
+ { \
+ .name = #_name, \
+ .driver_data = (void *)&bcm590xx_regs[BCM590XX_REG_##_id], \
+ }
+
+static struct of_regulator_match bcm590xx_matches[] = {
+ BCM590XX_MATCH(rfldo, RFLDO),
+ BCM590XX_MATCH(camldo1, CAMLDO1),
+ BCM590XX_MATCH(camldo2, CAMLDO2),
+ BCM590XX_MATCH(simldo1, SIMLDO1),
+ BCM590XX_MATCH(simldo2, SIMLDO2),
+ BCM590XX_MATCH(sdldo, SDLDO),
+ BCM590XX_MATCH(sdxldo, SDXLDO),
+ BCM590XX_MATCH(mmcldo1, MMCLDO1),
+ BCM590XX_MATCH(mmcldo2, MMCLDO2),
+ BCM590XX_MATCH(audldo, AUDLDO),
+ BCM590XX_MATCH(micldo, MICLDO),
+ BCM590XX_MATCH(usbldo, USBLDO),
+ BCM590XX_MATCH(vibldo, VIBLDO),
+ BCM590XX_MATCH(csr, CSR),
+ BCM590XX_MATCH(iosr1, IOSR1),
+ BCM590XX_MATCH(iosr2, IOSR2),
+ BCM590XX_MATCH(msr, MSR),
+ BCM590XX_MATCH(sdsr1, SDSR1),
+ BCM590XX_MATCH(sdsr2, SDSR2),
+ BCM590XX_MATCH(vsr, VSR),
+};
+
+static struct bcm590xx_board *bcm590xx_parse_dt_reg_data(
+ struct platform_device *pdev,
+ struct of_regulator_match **bcm590xx_reg_matches)
+{
+ struct bcm590xx_board *data;
+ struct device_node *np = pdev->dev.parent->of_node;
+ struct device_node *regulators;
+ struct of_regulator_match *matches = bcm590xx_matches;
+ int count = ARRAY_SIZE(bcm590xx_matches);
+ int idx = 0;
+ int ret;
+
+ if (!np) {
+ dev_err(&pdev->dev, "of node not found\n");
+ return NULL;
+ }
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "failed to allocate regulator board data\n");
+ return NULL;
+ }
+
+ np = of_node_get(np);
+ regulators = of_get_child_by_name(np, "regulators");
+ if (!regulators) {
+ dev_warn(&pdev->dev, "regulator node not found\n");
+ return NULL;
+ }
+
+ ret = of_regulator_match(&pdev->dev, regulators, matches, count);
+ of_node_put(regulators);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
+ ret);
+ return NULL;
+ }
+
+ *bcm590xx_reg_matches = matches;
+
+ for (idx = 0; idx < count; idx++) {
+ if (!matches[idx].init_data || !matches[idx].of_node)
+ continue;
+
+ data->bcm590xx_pmu_init_data[idx] = matches[idx].init_data;
+ }
+
+ return data;
+}
+
+static int bcm590xx_probe(struct platform_device *pdev)
+{
+ struct bcm590xx *bcm590xx = dev_get_drvdata(pdev->dev.parent);
+ struct bcm590xx_board *pmu_data = NULL;
+ struct bcm590xx_reg *pmu;
+ struct regulator_config config = { };
+ struct bcm590xx_info *info;
+ struct regulator_init_data *reg_data;
+ struct regulator_dev *rdev;
+ struct of_regulator_match *bcm590xx_reg_matches = NULL;
+ int i;
+
+ pmu_data = bcm590xx_parse_dt_reg_data(pdev,
+ &bcm590xx_reg_matches);
+
+ pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL);
+ if (!pmu) {
+ dev_err(&pdev->dev, "Memory allocation failed for pmu\n");
+ return -ENOMEM;
+ }
+
+ pmu->mfd = bcm590xx;
+
+ platform_set_drvdata(pdev, pmu);
+
+ pmu->desc = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS *
+ sizeof(struct regulator_desc), GFP_KERNEL);
+ if (!pmu->desc) {
+ dev_err(&pdev->dev, "Memory alloc fails for desc\n");
+ return -ENOMEM;
+ }
+
+ pmu->info = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS *
+ sizeof(struct bcm590xx_info *), GFP_KERNEL);
+ if (!pmu->info) {
+ dev_err(&pdev->dev, "Memory alloc fails for info\n");
+ return -ENOMEM;
+ }
+
+ info = bcm590xx_regs;
+
+ for (i = 0; i < BCM590XX_NUM_REGS; i++, info++) {
+ if (pmu_data)
+ reg_data = pmu_data->bcm590xx_pmu_init_data[i];
+ else
+ reg_data = NULL;
+
+ /* Register the regulators */
+ pmu->info[i] = info;
+
+ pmu->desc[i].name = info->name;
+ pmu->desc[i].supply_name = info->vin_name;
+ pmu->desc[i].id = i;
+ pmu->desc[i].volt_table = info->volt_table;
+ pmu->desc[i].n_voltages = info->n_voltages;
+ pmu->desc[i].linear_ranges = info->linear_ranges;
+ pmu->desc[i].n_linear_ranges = info->n_linear_ranges;
+
+ if (BCM590XX_REG_IS_LDO(i)) {
+ pmu->desc[i].ops = &bcm590xx_ops_ldo;
+ pmu->desc[i].vsel_mask = BCM590XX_LDO_VSEL_MASK;
+ } else {
+ pmu->desc[i].ops = &bcm590xx_ops_dcdc;
+ pmu->desc[i].vsel_mask = BCM590XX_SR_VSEL_MASK;
+ }
+
+ pmu->desc[i].vsel_reg = bcm590xx_get_vsel_register(i);
+ pmu->desc[i].enable_is_inverted = true;
+ pmu->desc[i].enable_mask = BCM590XX_REG_ENABLE;
+ pmu->desc[i].enable_reg = bcm590xx_get_enable_register(i);
+ pmu->desc[i].type = REGULATOR_VOLTAGE;
+ pmu->desc[i].owner = THIS_MODULE;
+
+ config.dev = bcm590xx->dev;
+ config.init_data = reg_data;
+ config.driver_data = pmu;
+ config.regmap = bcm590xx->regmap;
+
+ if (bcm590xx_reg_matches)
+ config.of_node = bcm590xx_reg_matches[i].of_node;
+
+ rdev = devm_regulator_register(&pdev->dev, &pmu->desc[i],
+ &config);
+ if (IS_ERR(rdev)) {
+ dev_err(bcm590xx->dev,
+ "failed to register %s regulator\n",
+ pdev->name);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+
+static struct platform_driver bcm590xx_regulator_driver = {
+ .driver = {
+ .name = "bcm590xx-vregs",
+ .owner = THIS_MODULE,
+ },
+ .probe = bcm590xx_probe,
+};
+module_platform_driver(bcm590xx_regulator_driver);
+
+MODULE_AUTHOR("Matt Porter <mporter@linaro.org>");
+MODULE_DESCRIPTION("BCM590xx voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bcm590xx-vregs");
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 8bd5cbf3aafb..9a09f3cdbabb 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -953,6 +953,8 @@ static int machine_constraints_current(struct regulator_dev *rdev,
return 0;
}
+static int _regulator_do_enable(struct regulator_dev *rdev);
+
/**
* set_machine_constraints - sets regulator constraints
* @rdev: regulator source
@@ -1013,10 +1015,9 @@ static int set_machine_constraints(struct regulator_dev *rdev,
/* If the constraints say the regulator should be on at this point
* and we have control then make sure it is enabled.
*/
- if ((rdev->constraints->always_on || rdev->constraints->boot_on) &&
- ops->enable) {
- ret = ops->enable(rdev);
- if (ret < 0) {
+ if (rdev->constraints->always_on || rdev->constraints->boot_on) {
+ ret = _regulator_do_enable(rdev);
+ if (ret < 0 && ret != -EINVAL) {
rdev_err(rdev, "failed to enable\n");
goto out;
}
@@ -1359,7 +1360,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
goto found;
/* Don't log an error when called from regulator_get_optional() */
} else if (!have_full_constraints() || exclusive) {
- dev_err(dev, "dummy supplies not allowed\n");
+ dev_warn(dev, "dummy supplies not allowed\n");
}
mutex_unlock(&regulator_list_mutex);
@@ -1907,8 +1908,6 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
trace_regulator_disable_complete(rdev_get_name(rdev));
- _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
- NULL);
return 0;
}
@@ -1932,6 +1931,8 @@ static int _regulator_disable(struct regulator_dev *rdev)
rdev_err(rdev, "failed to disable\n");
return ret;
}
+ _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
+ NULL);
}
rdev->use_count = 0;
@@ -1984,20 +1985,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
{
int ret = 0;
- /* force disable */
- if (rdev->desc->ops->disable) {
- /* ah well, who wants to live forever... */
- ret = rdev->desc->ops->disable(rdev);
- if (ret < 0) {
- rdev_err(rdev, "failed to force disable\n");
- return ret;
- }
- /* notify other consumers that power has been forced off */
- _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
- REGULATOR_EVENT_DISABLE, NULL);
+ ret = _regulator_do_disable(rdev);
+ if (ret < 0) {
+ rdev_err(rdev, "failed to force disable\n");
+ return ret;
}
- return ret;
+ _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
+ REGULATOR_EVENT_DISABLE, NULL);
+
+ return 0;
}
/**
@@ -2402,6 +2399,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
struct regulator_dev *rdev = regulator->rdev;
int ret = 0;
int old_min_uV, old_max_uV;
+ int current_uV;
mutex_lock(&rdev->mutex);
@@ -2412,6 +2410,19 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
if (regulator->min_uV == min_uV && regulator->max_uV == max_uV)
goto out;
+ /* If we're trying to set a range that overlaps the current voltage,
+ * return succesfully even though the regulator does not support
+ * changing the voltage.
+ */
+ if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
+ current_uV = _regulator_get_voltage(rdev);
+ if (min_uV <= current_uV && current_uV <= max_uV) {
+ regulator->min_uV = min_uV;
+ regulator->max_uV = max_uV;
+ goto out;
+ }
+ }
+
/* sanity check */
if (!rdev->desc->ops->set_voltage &&
!rdev->desc->ops->set_voltage_sel) {
@@ -3630,23 +3641,18 @@ int regulator_suspend_finish(void)
mutex_lock(&regulator_list_mutex);
list_for_each_entry(rdev, &regulator_list, list) {
- struct regulator_ops *ops = rdev->desc->ops;
-
mutex_lock(&rdev->mutex);
- if ((rdev->use_count > 0 || rdev->constraints->always_on) &&
- ops->enable) {
- error = ops->enable(rdev);
+ if (rdev->use_count > 0 || rdev->constraints->always_on) {
+ error = _regulator_do_enable(rdev);
if (error)
ret = error;
} else {
if (!have_full_constraints())
goto unlock;
- if (!ops->disable)
- goto unlock;
if (!_regulator_is_enabled(rdev))
goto unlock;
- error = ops->disable(rdev);
+ error = _regulator_do_disable(rdev);
if (error)
ret = error;
}
@@ -3820,7 +3826,7 @@ static int __init regulator_init_complete(void)
ops = rdev->desc->ops;
c = rdev->constraints;
- if (!ops->disable || (c && c->always_on))
+ if (c && c->always_on)
continue;
mutex_lock(&rdev->mutex);
@@ -3841,7 +3847,7 @@ static int __init regulator_init_complete(void)
/* We log since this may kill the system if it
* goes wrong. */
rdev_info(rdev, "disabling\n");
- ret = ops->disable(rdev);
+ ret = _regulator_do_disable(rdev);
if (ret != 0)
rdev_err(rdev, "couldn't disable: %d\n", ret);
} else {
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index 3adeaeffc485..fdb6ea8ae7e6 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -240,6 +240,31 @@ static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev,
return ret;
}
+static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_sel,
+ unsigned int new_sel)
+{
+ struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+ struct da9052_regulator_info *info = regulator->info;
+ int id = rdev_get_id(rdev);
+ int ret = 0;
+
+ /* The DVC controlled LDOs and DCDCs ramp with 6.25mV/µs after enabling
+ * the activate bit.
+ */
+ switch (id) {
+ case DA9052_ID_BUCK1:
+ case DA9052_ID_BUCK2:
+ case DA9052_ID_BUCK3:
+ case DA9052_ID_LDO2:
+ case DA9052_ID_LDO3:
+ ret = (new_sel - old_sel) * info->step_uV / 6250;
+ break;
+ }
+
+ return ret;
+}
+
static struct regulator_ops da9052_dcdc_ops = {
.get_current_limit = da9052_dcdc_get_current_limit,
.set_current_limit = da9052_dcdc_set_current_limit,
@@ -248,6 +273,7 @@ static struct regulator_ops da9052_dcdc_ops = {
.map_voltage = da9052_map_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = da9052_regulator_set_voltage_sel,
+ .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -258,6 +284,7 @@ static struct regulator_ops da9052_ldo_ops = {
.map_voltage = da9052_map_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = da9052_regulator_set_voltage_sel,
+ .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -401,7 +428,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
if (!nproot)
return -ENODEV;
- nproot = of_find_node_by_name(nproot, "regulators");
+ nproot = of_get_child_by_name(nproot, "regulators");
if (!nproot)
return -ENODEV;
diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c
index b14ebdad5dd2..9516317e1a9f 100644
--- a/drivers/regulator/da9055-regulator.c
+++ b/drivers/regulator/da9055-regulator.c
@@ -19,6 +19,8 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/mfd/da9055/core.h>
#include <linux/mfd/da9055/reg.h>
@@ -446,6 +448,9 @@ static int da9055_gpio_init(struct da9055_regulator *regulator,
struct da9055_regulator_info *info = regulator->info;
int ret = 0;
+ if (!pdata)
+ return 0;
+
if (pdata->gpio_ren && pdata->gpio_ren[id]) {
char name[18];
int gpio_mux = pdata->gpio_ren[id];
@@ -530,6 +535,59 @@ static inline struct da9055_regulator_info *find_regulator_info(int id)
return NULL;
}
+#ifdef CONFIG_OF
+static struct of_regulator_match da9055_reg_matches[] = {
+ { .name = "BUCK1", },
+ { .name = "BUCK2", },
+ { .name = "LDO1", },
+ { .name = "LDO2", },
+ { .name = "LDO3", },
+ { .name = "LDO4", },
+ { .name = "LDO5", },
+ { .name = "LDO6", },
+};
+
+static int da9055_regulator_dt_init(struct platform_device *pdev,
+ struct da9055_regulator *regulator,
+ struct regulator_config *config,
+ int regid)
+{
+ struct device_node *nproot, *np;
+ int ret;
+
+ nproot = of_node_get(pdev->dev.parent->of_node);
+ if (!nproot)
+ return -ENODEV;
+
+ np = of_get_child_by_name(nproot, "regulators");
+ if (!np)
+ return -ENODEV;
+
+ ret = of_regulator_match(&pdev->dev, np, &da9055_reg_matches[regid], 1);
+ of_node_put(nproot);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error matching regulator: %d\n", ret);
+ return ret;
+ }
+
+ config->init_data = da9055_reg_matches[regid].init_data;
+ config->of_node = da9055_reg_matches[regid].of_node;
+
+ if (!config->of_node)
+ return -ENODEV;
+
+ return 0;
+}
+#else
+static inline int da9055_regulator_dt_init(struct platform_device *pdev,
+ struct da9055_regulator *regulator,
+ struct regulator_config *config,
+ int regid)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_OF */
+
static int da9055_regulator_probe(struct platform_device *pdev)
{
struct regulator_config config = { };
@@ -538,9 +596,6 @@ static int da9055_regulator_probe(struct platform_device *pdev)
struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
int ret, irq;
- if (pdata == NULL || pdata->regulators[pdev->id] == NULL)
- return -ENODEV;
-
regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9055_regulator),
GFP_KERNEL);
if (!regulator)
@@ -557,8 +612,14 @@ static int da9055_regulator_probe(struct platform_device *pdev)
config.driver_data = regulator;
config.regmap = da9055->regmap;
- if (pdata && pdata->regulators)
+ if (pdata && pdata->regulators) {
config.init_data = pdata->regulators[pdev->id];
+ } else {
+ ret = da9055_regulator_dt_init(pdev, regulator, &config,
+ pdev->id);
+ if (ret < 0)
+ return ret;
+ }
ret = da9055_gpio_init(regulator, &config, pdata, pdev->id);
if (ret < 0)
diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c
index 56727eb745df..7c9461d13313 100644
--- a/drivers/regulator/da9063-regulator.c
+++ b/drivers/regulator/da9063-regulator.c
@@ -1,3 +1,4 @@
+
/*
* Regulator driver for DA9063 PMIC series
*
@@ -60,7 +61,8 @@ struct da9063_regulator_info {
.desc.ops = &da9063_ldo_ops, \
.desc.min_uV = (min_mV) * 1000, \
.desc.uV_step = (step_mV) * 1000, \
- .desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1), \
+ .desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1 \
+ + (DA9063_V##regl_name##_BIAS)), \
.desc.enable_reg = DA9063_REG_##regl_name##_CONT, \
.desc.enable_mask = DA9063_LDO_EN, \
.desc.vsel_reg = DA9063_REG_V##regl_name##_A, \
@@ -363,7 +365,7 @@ static int da9063_set_suspend_voltage(struct regulator_dev *rdev, int uV)
sel = regulator_map_voltage_linear(rdev, uV, uV);
if (sel < 0)
- return -EINVAL;
+ return sel;
sel <<= ffs(rdev->desc->vsel_mask) - 1;
@@ -664,7 +666,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
struct device_node *node;
int i, n, num;
- node = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
+ node = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
if (!node) {
dev_err(&pdev->dev, "Regulators device node not found\n");
return ERR_PTR(-ENODEV);
@@ -672,6 +674,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
num = of_regulator_match(&pdev->dev, node, da9063_matches,
ARRAY_SIZE(da9063_matches));
+ of_node_put(node);
if (num < 0) {
dev_err(&pdev->dev, "Failed to match regulators\n");
return ERR_PTR(-EINVAL);
@@ -708,7 +711,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
struct platform_device *pdev,
struct of_regulator_match **da9063_reg_matches)
{
- da9063_reg_matches = NULL;
+ *da9063_reg_matches = NULL;
return ERR_PTR(-ENODEV);
}
#endif
@@ -754,7 +757,7 @@ static int da9063_regulator_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev,
"Error while reading BUCKs configuration\n");
- return -EIO;
+ return ret;
}
bcores_merged = val & DA9063_BCORE_MERGE;
bmem_bio_merged = val & DA9063_BUCK_MERGE;
@@ -773,10 +776,8 @@ static int da9063_regulator_probe(struct platform_device *pdev)
size = sizeof(struct da9063_regulators) +
n_regulators * sizeof(struct da9063_regulator);
regulators = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
- if (!regulators) {
- dev_err(&pdev->dev, "No memory for regulators\n");
+ if (!regulators)
return -ENOMEM;
- }
regulators->n_regulators = n_regulators;
platform_set_drvdata(pdev, regulators);
diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c
index 6f5ecbe1132e..7a320dd11c46 100644
--- a/drivers/regulator/da9210-regulator.c
+++ b/drivers/regulator/da9210-regulator.c
@@ -134,11 +134,8 @@ static int da9210_i2c_probe(struct i2c_client *i2c,
int error;
chip = devm_kzalloc(&i2c->dev, sizeof(struct da9210), GFP_KERNEL);
- if (NULL == chip) {
- dev_err(&i2c->dev,
- "Cannot kzalloc memory for regulator structure\n");
+ if (!chip)
return -ENOMEM;
- }
chip->regmap = devm_regmap_init_i2c(i2c, &da9210_regmap_config);
if (IS_ERR(chip->regmap)) {
diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c
index 846acf240e48..617c1adca816 100644
--- a/drivers/regulator/db8500-prcmu.c
+++ b/drivers/regulator/db8500-prcmu.c
@@ -263,6 +263,8 @@ dbx500_regulator_info[DB8500_NUM_REGULATORS] = {
.ops = &db8500_regulator_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
+ .fixed_uV = 1800000,
+ .n_voltages = 1,
},
.exclude_from_power_state = true,
},
diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c
index ce89f7848a57..2d16b9f16de7 100644
--- a/drivers/regulator/dbx500-prcmu.c
+++ b/drivers/regulator/dbx500-prcmu.c
@@ -78,6 +78,7 @@ static struct ux500_regulator_debug {
void ux500_regulator_suspend_debug(void)
{
int i;
+
for (i = 0; i < rdebug.num_regulators; i++)
rdebug.state_before_suspend[i] =
rdebug.regulator_array[i].is_enabled;
@@ -86,6 +87,7 @@ void ux500_regulator_suspend_debug(void)
void ux500_regulator_resume_debug(void)
{
int i;
+
for (i = 0; i < rdebug.num_regulators; i++)
rdebug.state_after_suspend[i] =
rdebug.regulator_array[i].is_enabled;
@@ -127,9 +129,9 @@ static int ux500_regulator_status_print(struct seq_file *s, void *p)
int i;
/* print dump header */
- err = seq_printf(s, "ux500-regulator status:\n");
+ err = seq_puts(s, "ux500-regulator status:\n");
if (err < 0)
- dev_err(dev, "seq_printf overflow\n");
+ dev_err(dev, "seq_puts overflow\n");
err = seq_printf(s, "%31s : %8s : %8s\n", "current",
"before", "after");
@@ -202,18 +204,12 @@ ux500_regulator_debug_init(struct platform_device *pdev,
rdebug.num_regulators = num_regulators;
rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL);
- if (!rdebug.state_before_suspend) {
- dev_err(&pdev->dev,
- "could not allocate memory for saving state\n");
+ if (!rdebug.state_before_suspend)
goto exit_destroy_power_state;
- }
rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL);
- if (!rdebug.state_after_suspend) {
- dev_err(&pdev->dev,
- "could not allocate memory for saving state\n");
+ if (!rdebug.state_after_suspend)
goto exit_free;
- }
dbx500_regulator_testcase(regulator_info, num_regulators);
return 0;
diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c
index df9f42524abb..2436db9e2ca3 100644
--- a/drivers/regulator/dummy.c
+++ b/drivers/regulator/dummy.c
@@ -25,7 +25,11 @@
struct regulator_dev *dummy_regulator_rdev;
-static struct regulator_init_data dummy_initdata;
+static struct regulator_init_data dummy_initdata = {
+ .constraints = {
+ .always_on = 1,
+ },
+};
static struct regulator_ops dummy_ops;
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index 7ca3d9e3b0fe..714fd9a89aa1 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -90,11 +90,11 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
return 0;
ret = regulator_map_voltage_linear(rdev, uV, uV);
if (ret < 0)
- return -EINVAL;
+ return ret;
ret = regmap_update_bits(di->regmap, di->sleep_reg,
VSEL_NSEL_MASK, ret);
if (ret < 0)
- return -EINVAL;
+ return ret;
/* Cache the sleep voltage setting.
* Might not be the real voltage which is rounded */
di->sleep_vol_cache = uV;
@@ -244,10 +244,9 @@ static int fan53555_regulator_probe(struct i2c_client *client,
di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info),
GFP_KERNEL);
- if (!di) {
- dev_err(&client->dev, "Failed to allocate device info data!\n");
+ if (!di)
return -ENOMEM;
- }
+
di->regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config);
if (IS_ERR(di->regmap)) {
dev_err(&client->dev, "Failed to allocate regmap!\n");
@@ -260,14 +259,14 @@ static int fan53555_regulator_probe(struct i2c_client *client,
ret = regmap_read(di->regmap, FAN53555_ID1, &val);
if (ret < 0) {
dev_err(&client->dev, "Failed to get chip ID!\n");
- return -ENODEV;
+ return ret;
}
di->chip_id = val & DIE_ID;
/* Get chip revision */
ret = regmap_read(di->regmap, FAN53555_ID2, &val);
if (ret < 0) {
dev_err(&client->dev, "Failed to get chip Rev!\n");
- return -ENODEV;
+ return ret;
}
di->chip_rev = val & DIE_REV;
dev_info(&client->dev, "FAN53555 Option[%d] Rev[%d] Detected!\n",
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 5ea64b94341c..c61f7e97e4f8 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -130,17 +130,15 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),
GFP_KERNEL);
- if (drvdata == NULL) {
- dev_err(&pdev->dev, "Failed to allocate device data\n");
- ret = -ENOMEM;
- goto err;
- }
+ if (!drvdata)
+ return -ENOMEM;
- drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
+ drvdata->desc.name = devm_kstrdup(&pdev->dev,
+ config->supply_name,
+ GFP_KERNEL);
if (drvdata->desc.name == NULL) {
dev_err(&pdev->dev, "Failed to allocate supply name\n");
- ret = -ENOMEM;
- goto err;
+ return -ENOMEM;
}
drvdata->desc.type = REGULATOR_VOLTAGE;
drvdata->desc.owner = THIS_MODULE;
@@ -149,13 +147,13 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata->desc.enable_time = config->startup_delay;
if (config->input_supply) {
- drvdata->desc.supply_name = kstrdup(config->input_supply,
- GFP_KERNEL);
+ drvdata->desc.supply_name = devm_kstrdup(&pdev->dev,
+ config->input_supply,
+ GFP_KERNEL);
if (!drvdata->desc.supply_name) {
dev_err(&pdev->dev,
"Failed to allocate input supply\n");
- ret = -ENOMEM;
- goto err_name;
+ return -ENOMEM;
}
}
@@ -186,11 +184,12 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
cfg.driver_data = drvdata;
cfg.of_node = pdev->dev.of_node;
- drvdata->dev = regulator_register(&drvdata->desc, &cfg);
+ drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc,
+ &cfg);
if (IS_ERR(drvdata->dev)) {
ret = PTR_ERR(drvdata->dev);
dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
- goto err_input;
+ return ret;
}
platform_set_drvdata(pdev, drvdata);
@@ -199,24 +198,6 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata->desc.fixed_uV);
return 0;
-
-err_input:
- kfree(drvdata->desc.supply_name);
-err_name:
- kfree(drvdata->desc.name);
-err:
- return ret;
-}
-
-static int reg_fixed_voltage_remove(struct platform_device *pdev)
-{
- struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev);
-
- regulator_unregister(drvdata->dev);
- kfree(drvdata->desc.supply_name);
- kfree(drvdata->desc.name);
-
- return 0;
}
#if defined(CONFIG_OF)
@@ -229,7 +210,6 @@ MODULE_DEVICE_TABLE(of, fixed_of_match);
static struct platform_driver regulator_fixed_voltage_driver = {
.probe = reg_fixed_voltage_probe,
- .remove = reg_fixed_voltage_remove,
.driver = {
.name = "reg-fixed-voltage",
.owner = THIS_MODULE,
diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
index c0a1d00b78c9..989b23b377c0 100644
--- a/drivers/regulator/gpio-regulator.c
+++ b/drivers/regulator/gpio-regulator.c
@@ -136,7 +136,6 @@ static struct gpio_regulator_config *
of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
{
struct gpio_regulator_config *config;
- struct property *prop;
const char *regtype;
int proplen, gpio, i;
int ret;
@@ -172,22 +171,35 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
if (!config->gpios)
return ERR_PTR(-ENOMEM);
+ proplen = of_property_count_u32_elems(np, "gpios-states");
+ /* optional property */
+ if (proplen < 0)
+ proplen = 0;
+
+ if (proplen > 0 && proplen != config->nr_gpios) {
+ dev_warn(dev, "gpios <-> gpios-states mismatch\n");
+ proplen = 0;
+ }
+
for (i = 0; i < config->nr_gpios; i++) {
gpio = of_get_named_gpio(np, "gpios", i);
if (gpio < 0)
break;
config->gpios[i].gpio = gpio;
+ if (proplen > 0) {
+ of_property_read_u32_index(np, "gpios-states", i, &ret);
+ if (ret)
+ config->gpios[i].flags = GPIOF_OUT_INIT_HIGH;
+ }
}
/* Fetch states. */
- prop = of_find_property(np, "states", NULL);
- if (!prop) {
+ proplen = of_property_count_u32_elems(np, "states");
+ if (proplen < 0) {
dev_err(dev, "No 'states' property found\n");
return ERR_PTR(-EINVAL);
}
- proplen = prop->length / sizeof(int);
-
config->states = devm_kzalloc(dev,
sizeof(struct gpio_regulator_state)
* (proplen / 2),
@@ -196,10 +208,10 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
return ERR_PTR(-ENOMEM);
for (i = 0; i < proplen / 2; i++) {
- config->states[i].value =
- be32_to_cpup((int *)prop->value + (i * 2));
- config->states[i].gpios =
- be32_to_cpup((int *)prop->value + (i * 2 + 1));
+ of_property_read_u32_index(np, "states", i * 2,
+ &config->states[i].value);
+ of_property_read_u32_index(np, "states", i * 2 + 1,
+ &config->states[i].gpios);
}
config->nr_states = i;
@@ -239,10 +251,8 @@ static int gpio_regulator_probe(struct platform_device *pdev)
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data),
GFP_KERNEL);
- if (drvdata == NULL) {
- dev_err(&pdev->dev, "Failed to allocate device data\n");
+ if (drvdata == NULL)
return -ENOMEM;
- }
drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
if (drvdata->desc.name == NULL) {
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index e221a271ba56..cbc39096c78d 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -37,10 +37,17 @@ int regulator_is_enabled_regmap(struct regulator_dev *rdev)
if (ret != 0)
return ret;
- if (rdev->desc->enable_is_inverted)
- return (val & rdev->desc->enable_mask) == 0;
- else
- return (val & rdev->desc->enable_mask) != 0;
+ val &= rdev->desc->enable_mask;
+
+ if (rdev->desc->enable_is_inverted) {
+ if (rdev->desc->enable_val)
+ return val != rdev->desc->enable_val;
+ return val == 0;
+ } else {
+ if (rdev->desc->enable_val)
+ return val == rdev->desc->enable_val;
+ return val != 0;
+ }
}
EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap);
@@ -57,10 +64,13 @@ int regulator_enable_regmap(struct regulator_dev *rdev)
{
unsigned int val;
- if (rdev->desc->enable_is_inverted)
- val = 0;
- else
- val = rdev->desc->enable_mask;
+ if (rdev->desc->enable_is_inverted) {
+ val = rdev->desc->disable_val;
+ } else {
+ val = rdev->desc->enable_val;
+ if (!val)
+ val = rdev->desc->enable_mask;
+ }
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask, val);
@@ -80,10 +90,13 @@ int regulator_disable_regmap(struct regulator_dev *rdev)
{
unsigned int val;
- if (rdev->desc->enable_is_inverted)
- val = rdev->desc->enable_mask;
- else
- val = 0;
+ if (rdev->desc->enable_is_inverted) {
+ val = rdev->desc->enable_val;
+ if (!val)
+ val = rdev->desc->enable_mask;
+ } else {
+ val = rdev->desc->disable_val;
+ }
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask, val);
@@ -419,10 +432,13 @@ int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)
{
unsigned int val;
- if (enable)
- val = rdev->desc->bypass_mask;
- else
- val = 0;
+ if (enable) {
+ val = rdev->desc->bypass_val_on;
+ if (!val)
+ val = rdev->desc->bypass_mask;
+ } else {
+ val = rdev->desc->bypass_val_off;
+ }
return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg,
rdev->desc->bypass_mask, val);
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 3b1102b75071..66fd2330dca0 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -327,7 +327,7 @@ static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count,
return -EIO;
ret = i2c_smbus_read_byte_data(i2c, reg);
if (ret < 0)
- return -EIO;
+ return ret;
*dest = ret;
return 0;
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
index 2e4734ff79fc..2e022aabd951 100644
--- a/drivers/regulator/lp872x.c
+++ b/drivers/regulator/lp872x.c
@@ -211,7 +211,7 @@ static int lp872x_get_timestep_usec(struct lp872x *lp)
ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val);
if (ret)
- return -EINVAL;
+ return ret;
val = (val & mask) >> shift;
if (val >= size)
@@ -229,7 +229,7 @@ static int lp872x_regulator_enable_time(struct regulator_dev *rdev)
u8 addr, val;
if (time_step_us < 0)
- return -EINVAL;
+ return time_step_us;
switch (rid) {
case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c
index 186df8785a91..ed60baaeceec 100644
--- a/drivers/regulator/max14577.c
+++ b/drivers/regulator/max14577.c
@@ -1,7 +1,7 @@
/*
* max14577.c - Regulator driver for the Maxim 14577
*
- * Copyright (C) 2013 Samsung Electronics
+ * Copyright (C) 2013,2014 Samsung Electronics
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -22,12 +22,6 @@
#include <linux/mfd/max14577-private.h>
#include <linux/regulator/of_regulator.h>
-struct max14577_regulator {
- struct device *dev;
- struct max14577 *max14577;
- struct regulator_dev **regulators;
-};
-
static int max14577_reg_is_enabled(struct regulator_dev *rdev)
{
int rid = rdev_get_id(rdev);
@@ -166,9 +160,10 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
ret = of_regulator_match(&pdev->dev, np, max14577_regulator_matches,
MAX14577_REG_MAX);
- if (ret < 0) {
+ if (ret < 0)
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
- }
+ else
+ ret = 0;
of_node_put(np);
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index e242dd316d36..d23d0577754b 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -46,8 +46,6 @@ struct max1586_data {
unsigned int v3_curr_sel;
unsigned int v6_curr_sel;
-
- struct regulator_dev *rdev[0];
};
/*
@@ -162,14 +160,12 @@ static struct regulator_desc max1586_reg[] = {
static int max1586_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
- struct regulator_dev **rdev;
struct max1586_platform_data *pdata = dev_get_platdata(&client->dev);
struct regulator_config config = { };
struct max1586_data *max1586;
int i, id;
- max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data) +
- sizeof(struct regulator_dev *) * (MAX1586_V6 + 1),
+ max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data),
GFP_KERNEL);
if (!max1586)
return -ENOMEM;
@@ -186,8 +182,9 @@ static int max1586_pmic_probe(struct i2c_client *client,
max1586->v3_curr_sel = 24; /* 1.3V */
max1586->v6_curr_sel = 0;
- rdev = max1586->rdev;
for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) {
+ struct regulator_dev *rdev;
+
id = pdata->subdevs[i].id;
if (!pdata->subdevs[i].platform_data)
continue;
@@ -207,12 +204,12 @@ static int max1586_pmic_probe(struct i2c_client *client,
config.init_data = pdata->subdevs[i].platform_data;
config.driver_data = max1586;
- rdev[i] = devm_regulator_register(&client->dev,
+ rdev = devm_regulator_register(&client->dev,
&max1586_reg[id], &config);
- if (IS_ERR(rdev[i])) {
+ if (IS_ERR(rdev)) {
dev_err(&client->dev, "failed to register %s\n",
max1586_reg[id].name);
- return PTR_ERR(rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c
index ae001ccf26f4..ef1af2debbd2 100644
--- a/drivers/regulator/max77686.c
+++ b/drivers/regulator/max77686.c
@@ -65,7 +65,6 @@ enum max77686_ramp_rate {
};
struct max77686_data {
- struct regulator_dev *rdev[MAX77686_REGULATORS];
unsigned int opmode[MAX77686_REGULATORS];
};
@@ -400,7 +399,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
unsigned int i;
pmic_np = iodev->dev->of_node;
- regulators_np = of_find_node_by_name(pmic_np, "voltage-regulators");
+ regulators_np = of_get_child_by_name(pmic_np, "voltage-regulators");
if (!regulators_np) {
dev_err(&pdev->dev, "could not find regulators sub-node\n");
return -EINVAL;
@@ -410,8 +409,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
pdata->num_regulators, GFP_KERNEL);
if (!rdata) {
- dev_err(&pdev->dev,
- "could not allocate memory for regulator data\n");
+ of_node_put(regulators_np);
return -ENOMEM;
}
@@ -425,6 +423,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
}
pdata->regulators = rdata;
+ of_node_put(regulators_np);
return 0;
}
@@ -474,16 +473,18 @@ static int max77686_pmic_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, max77686);
for (i = 0; i < MAX77686_REGULATORS; i++) {
+ struct regulator_dev *rdev;
+
config.init_data = pdata->regulators[i].initdata;
config.of_node = pdata->regulators[i].of_node;
max77686->opmode[i] = regulators[i].enable_mask;
- max77686->rdev[i] = devm_regulator_register(&pdev->dev,
+ rdev = devm_regulator_register(&pdev->dev,
&regulators[i], &config);
- if (IS_ERR(max77686->rdev[i])) {
+ if (IS_ERR(rdev)) {
dev_err(&pdev->dev,
"regulator init failed for %d\n", i);
- return PTR_ERR(max77686->rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c
index 5fb899f461d0..653a58b49cdf 100644
--- a/drivers/regulator/max77693.c
+++ b/drivers/regulator/max77693.c
@@ -34,13 +34,6 @@
#define CHGIN_ILIM_STEP_20mA 20000
-struct max77693_pmic_dev {
- struct device *dev;
- struct max77693_dev *iodev;
- int num_regulators;
- struct regulator_dev **rdev;
-};
-
/* CHARGER regulator ops */
/* CHARGER regulator uses two bits for enabling */
static int max77693_chg_is_enabled(struct regulator_dev *rdev)
@@ -170,19 +163,22 @@ static int max77693_pmic_dt_parse_rdata(struct device *dev,
struct max77693_regulator_data *tmp;
int i, matched = 0;
- np = of_find_node_by_name(dev->parent->of_node, "regulators");
+ np = of_get_child_by_name(dev->parent->of_node, "regulators");
if (!np)
return -EINVAL;
rmatch = devm_kzalloc(dev,
sizeof(*rmatch) * ARRAY_SIZE(regulators), GFP_KERNEL);
- if (!rmatch)
+ if (!rmatch) {
+ of_node_put(np);
return -ENOMEM;
+ }
for (i = 0; i < ARRAY_SIZE(regulators); i++)
rmatch[i].name = regulators[i].name;
matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(regulators));
+ of_node_put(np);
if (matched <= 0)
return matched;
*rdata = devm_kzalloc(dev, sizeof(**rdata) * matched, GFP_KERNEL);
@@ -229,7 +225,6 @@ static int max77693_pmic_init_rdata(struct device *dev,
static int max77693_pmic_probe(struct platform_device *pdev)
{
struct max77693_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct max77693_pmic_dev *max77693_pmic;
struct max77693_regulator_data *rdata = NULL;
int num_rdata, i;
struct regulator_config config;
@@ -240,39 +235,22 @@ static int max77693_pmic_probe(struct platform_device *pdev)
return -ENODEV;
}
- max77693_pmic = devm_kzalloc(&pdev->dev,
- sizeof(struct max77693_pmic_dev),
- GFP_KERNEL);
- if (!max77693_pmic)
- return -ENOMEM;
-
- max77693_pmic->rdev = devm_kzalloc(&pdev->dev,
- sizeof(struct regulator_dev *) * num_rdata,
- GFP_KERNEL);
- if (!max77693_pmic->rdev)
- return -ENOMEM;
-
- max77693_pmic->dev = &pdev->dev;
- max77693_pmic->iodev = iodev;
- max77693_pmic->num_regulators = num_rdata;
-
config.dev = &pdev->dev;
config.regmap = iodev->regmap;
- config.driver_data = max77693_pmic;
- platform_set_drvdata(pdev, max77693_pmic);
- for (i = 0; i < max77693_pmic->num_regulators; i++) {
+ for (i = 0; i < num_rdata; i++) {
int id = rdata[i].id;
+ struct regulator_dev *rdev;
config.init_data = rdata[i].initdata;
config.of_node = rdata[i].of_node;
- max77693_pmic->rdev[i] = devm_regulator_register(&pdev->dev,
+ rdev = devm_regulator_register(&pdev->dev,
&regulators[id], &config);
- if (IS_ERR(max77693_pmic->rdev[i])) {
- dev_err(max77693_pmic->dev,
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev,
"Failed to initialize regulator-%d\n", id);
- return PTR_ERR(max77693_pmic->rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index 7f049c92ee52..3172da847d24 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -49,7 +49,6 @@
#define MAX8649_RAMP_DOWN (1 << 1)
struct max8649_regulator_info {
- struct regulator_dev *regulator;
struct device *dev;
struct regmap *regmap;
@@ -154,6 +153,7 @@ static int max8649_regulator_probe(struct i2c_client *client,
{
struct max8649_platform_data *pdata = dev_get_platdata(&client->dev);
struct max8649_regulator_info *info = NULL;
+ struct regulator_dev *regulator;
struct regulator_config config = { };
unsigned int val;
unsigned char data;
@@ -234,12 +234,12 @@ static int max8649_regulator_probe(struct i2c_client *client,
config.driver_data = info;
config.regmap = info->regmap;
- info->regulator = devm_regulator_register(&client->dev, &dcdc_desc,
+ regulator = devm_regulator_register(&client->dev, &dcdc_desc,
&config);
- if (IS_ERR(info->regulator)) {
+ if (IS_ERR(regulator)) {
dev_err(info->dev, "failed to register regulator %s\n",
dcdc_desc.name);
- return PTR_ERR(info->regulator);
+ return PTR_ERR(regulator);
}
return 0;
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
index 8d94d3d7f97f..2fc411188794 100644
--- a/drivers/regulator/max8660.c
+++ b/drivers/regulator/max8660.c
@@ -81,16 +81,17 @@ enum {
struct max8660 {
struct i2c_client *client;
u8 shadow_regs[MAX8660_N_REGS]; /* as chip is write only */
- struct regulator_dev *rdev[];
};
static int max8660_write(struct max8660 *max8660, u8 reg, u8 mask, u8 val)
{
- static const u8 max8660_addresses[MAX8660_N_REGS] =
- { 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80 };
+ static const u8 max8660_addresses[MAX8660_N_REGS] = {
+ 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80
+ };
int ret;
u8 reg_val = (max8660->shadow_regs[reg] & mask) | val;
+
dev_vdbg(&max8660->client->dev, "Writing reg %02x with %02x\n",
max8660_addresses[reg], reg_val);
@@ -112,6 +113,7 @@ static int max8660_dcdc_is_enabled(struct regulator_dev *rdev)
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 val = max8660->shadow_regs[MAX8660_OVER1];
u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+
return !!(val & mask);
}
@@ -119,6 +121,7 @@ static int max8660_dcdc_enable(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 bit = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+
return max8660_write(max8660, MAX8660_OVER1, 0xff, bit);
}
@@ -126,15 +129,16 @@ static int max8660_dcdc_disable(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? ~1 : ~4;
+
return max8660_write(max8660, MAX8660_OVER1, mask, 0);
}
static int max8660_dcdc_get_voltage_sel(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
-
u8 reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;
u8 selector = max8660->shadow_regs[reg];
+
return selector;
}
@@ -207,6 +211,7 @@ static int max8660_ldo67_is_enabled(struct regulator_dev *rdev)
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 val = max8660->shadow_regs[MAX8660_OVER2];
u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+
return !!(val & mask);
}
@@ -214,6 +219,7 @@ static int max8660_ldo67_enable(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 bit = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+
return max8660_write(max8660, MAX8660_OVER2, 0xff, bit);
}
@@ -221,15 +227,16 @@ static int max8660_ldo67_disable(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? ~2 : ~4;
+
return max8660_write(max8660, MAX8660_OVER2, mask, 0);
}
static int max8660_ldo67_get_voltage_sel(struct regulator_dev *rdev)
{
struct max8660 *max8660 = rdev_get_drvdata(rdev);
-
u8 shift = (rdev_get_id(rdev) == MAX8660_V6) ? 0 : 4;
u8 selector = (max8660->shadow_regs[MAX8660_L12VCR] >> shift) & 0xf;
+
return selector;
}
@@ -330,7 +337,7 @@ static int max8660_pdata_from_dt(struct device *dev,
struct max8660_subdev_data *sub;
struct of_regulator_match rmatch[ARRAY_SIZE(max8660_reg)];
- np = of_find_node_by_name(dev->of_node, "regulators");
+ np = of_get_child_by_name(dev->of_node, "regulators");
if (!np) {
dev_err(dev, "missing 'regulators' subnode in DT\n");
return -EINVAL;
@@ -340,6 +347,7 @@ static int max8660_pdata_from_dt(struct device *dev,
rmatch[i].name = max8660_reg[i].name;
matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(rmatch));
+ of_node_put(np);
if (matched <= 0)
return matched;
@@ -373,7 +381,6 @@ static inline int max8660_pdata_from_dt(struct device *dev,
static int max8660_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
- struct regulator_dev **rdev;
struct device *dev = &client->dev;
struct max8660_platform_data *pdata = dev_get_platdata(dev);
struct regulator_config config = { };
@@ -406,14 +413,11 @@ static int max8660_probe(struct i2c_client *client,
return -EINVAL;
}
- max8660 = devm_kzalloc(dev, sizeof(struct max8660) +
- sizeof(struct regulator_dev *) * MAX8660_V_END,
- GFP_KERNEL);
+ max8660 = devm_kzalloc(dev, sizeof(struct max8660), GFP_KERNEL);
if (!max8660)
return -ENOMEM;
max8660->client = client;
- rdev = max8660->rdev;
if (pdata->en34_is_high) {
/* Simulate always on */
@@ -481,6 +485,7 @@ static int max8660_probe(struct i2c_client *client,
/* Finally register devices */
for (i = 0; i < pdata->num_subdevs; i++) {
+ struct regulator_dev *rdev;
id = pdata->subdevs[i].id;
@@ -489,13 +494,13 @@ static int max8660_probe(struct i2c_client *client,
config.of_node = of_node[i];
config.driver_data = max8660;
- rdev[i] = devm_regulator_register(&client->dev,
+ rdev = devm_regulator_register(&client->dev,
&max8660_reg[id], &config);
- if (IS_ERR(rdev[i])) {
- ret = PTR_ERR(rdev[i]);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
dev_err(&client->dev, "failed to register %s\n",
max8660_reg[id].name);
- return PTR_ERR(rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c
index 0c5fe6c6ac26..9623e9e290bf 100644
--- a/drivers/regulator/max8907-regulator.c
+++ b/drivers/regulator/max8907-regulator.c
@@ -34,7 +34,6 @@
struct max8907_regulator {
struct regulator_desc desc[MAX8907_NUM_REGULATORS];
- struct regulator_dev *rdev[MAX8907_NUM_REGULATORS];
};
#define REG_MBATT() \
@@ -231,7 +230,7 @@ static int max8907_regulator_parse_dt(struct platform_device *pdev)
if (!np)
return 0;
- regulators = of_find_node_by_name(np, "regulators");
+ regulators = of_get_child_by_name(np, "regulators");
if (!regulators) {
dev_err(&pdev->dev, "regulators node not found\n");
return -EINVAL;
@@ -292,10 +291,9 @@ static int max8907_regulator_probe(struct platform_device *pdev)
return ret;
pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
- if (!pmic) {
- dev_err(&pdev->dev, "Failed to alloc pmic\n");
+ if (!pmic)
return -ENOMEM;
- }
+
platform_set_drvdata(pdev, pmic);
memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
@@ -311,6 +309,8 @@ static int max8907_regulator_probe(struct platform_device *pdev)
}
for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
+ struct regulator_dev *rdev;
+
config.dev = pdev->dev.parent;
if (pdata)
idata = pdata->init_data[i];
@@ -350,13 +350,13 @@ static int max8907_regulator_probe(struct platform_device *pdev)
pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
}
- pmic->rdev[i] = devm_regulator_register(&pdev->dev,
+ rdev = devm_regulator_register(&pdev->dev,
&pmic->desc[i], &config);
- if (IS_ERR(pmic->rdev[i])) {
+ if (IS_ERR(rdev)) {
dev_err(&pdev->dev,
"failed to register %s regulator\n",
pmic->desc[i].name);
- return PTR_ERR(pmic->rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
index 759510789e71..dad2bcd14e96 100644
--- a/drivers/regulator/max8925-regulator.c
+++ b/drivers/regulator/max8925-regulator.c
@@ -36,9 +36,7 @@
struct max8925_regulator_info {
struct regulator_desc desc;
- struct regulator_dev *regulator;
struct i2c_client *i2c;
- struct max8925_chip *chip;
int vol_reg;
int enable_reg;
@@ -251,10 +249,11 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
{
struct device_node *nproot, *np;
int rcount;
+
nproot = of_node_get(pdev->dev.parent->of_node);
if (!nproot)
return -ENODEV;
- np = of_find_node_by_name(nproot, "regulators");
+ np = of_get_child_by_name(nproot, "regulators");
if (!np) {
dev_err(&pdev->dev, "failed to find regulators node\n");
return -ENODEV;
@@ -264,7 +263,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
&max8925_regulator_matches[ridx], 1);
of_node_put(np);
if (rcount < 0)
- return -ENODEV;
+ return rcount;
config->init_data = max8925_regulator_matches[ridx].init_data;
config->of_node = max8925_regulator_matches[ridx].of_node;
@@ -303,7 +302,6 @@ static int max8925_regulator_probe(struct platform_device *pdev)
return -EINVAL;
}
ri->i2c = chip->i2c;
- ri->chip = chip;
config.dev = &pdev->dev;
config.driver_data = ri;
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index 788e5ae2af1b..d920f5a32ec8 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -48,9 +48,7 @@ enum {
struct max8952_data {
struct i2c_client *client;
- struct device *dev;
struct max8952_platform_data *pdata;
- struct regulator_dev *rdev;
bool vid0;
bool vid1;
@@ -59,6 +57,7 @@ struct max8952_data {
static int max8952_read_reg(struct max8952_data *max8952, u8 reg)
{
int ret = i2c_smbus_read_byte_data(max8952->client, reg);
+
if (ret > 0)
ret &= 0xff;
@@ -144,10 +143,8 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev)
int i;
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
- if (!pd) {
- dev_err(dev, "Failed to allocate platform data\n");
+ if (!pd)
return NULL;
- }
pd->gpio_vid0 = of_get_named_gpio(np, "max8952,vid-gpios", 0);
pd->gpio_vid1 = of_get_named_gpio(np, "max8952,vid-gpios", 1);
@@ -199,6 +196,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
struct max8952_platform_data *pdata = dev_get_platdata(&client->dev);
struct regulator_config config = { };
struct max8952_data *max8952;
+ struct regulator_dev *rdev;
int ret = 0, err = 0;
@@ -219,10 +217,9 @@ static int max8952_pmic_probe(struct i2c_client *client,
return -ENOMEM;
max8952->client = client;
- max8952->dev = &client->dev;
max8952->pdata = pdata;
- config.dev = max8952->dev;
+ config.dev = &client->dev;
config.init_data = pdata->reg_data;
config.driver_data = max8952;
config.of_node = client->dev.of_node;
@@ -231,11 +228,11 @@ static int max8952_pmic_probe(struct i2c_client *client,
if (pdata->reg_data->constraints.boot_on)
config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
- max8952->rdev = regulator_register(&regulator, &config);
+ rdev = devm_regulator_register(&client->dev, &regulator, &config);
- if (IS_ERR(max8952->rdev)) {
- ret = PTR_ERR(max8952->rdev);
- dev_err(max8952->dev, "regulator init failed (%d)\n", ret);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(&client->dev, "regulator init failed (%d)\n", ret);
return ret;
}
@@ -263,7 +260,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
err = 3;
if (err) {
- dev_warn(max8952->dev, "VID0/1 gpio invalid: "
+ dev_warn(&client->dev, "VID0/1 gpio invalid: "
"DVS not available.\n");
max8952->vid0 = 0;
max8952->vid1 = 0;
@@ -274,7 +271,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
/* Disable Pulldown of EN only */
max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60);
- dev_err(max8952->dev, "DVS modes disabled because VID0 and VID1"
+ dev_err(&client->dev, "DVS modes disabled because VID0 and VID1"
" do not have proper controls.\n");
} else {
/*
@@ -321,9 +318,6 @@ static int max8952_pmic_remove(struct i2c_client *client)
{
struct max8952_data *max8952 = i2c_get_clientdata(client);
struct max8952_platform_data *pdata = max8952->pdata;
- struct regulator_dev *rdev = max8952->rdev;
-
- regulator_unregister(rdev);
gpio_free(pdata->gpio_vid0);
gpio_free(pdata->gpio_vid1);
diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c
index 892aa1e5b96c..dbedf1768db0 100644
--- a/drivers/regulator/max8973-regulator.c
+++ b/drivers/regulator/max8973-regulator.c
@@ -93,7 +93,6 @@
struct max8973_chip {
struct device *dev;
struct regulator_desc desc;
- struct regulator_dev *rdev;
struct regmap *regmap;
bool enable_external_control;
int dvs_gpio;
@@ -379,10 +378,8 @@ static int max8973_probe(struct i2c_client *client,
}
max = devm_kzalloc(&client->dev, sizeof(*max), GFP_KERNEL);
- if (!max) {
- dev_err(&client->dev, "Memory allocation for max failed\n");
+ if (!max)
return -ENOMEM;
- }
max->regmap = devm_regmap_init_i2c(client, &max8973_regmap_config);
if (IS_ERR(max->regmap)) {
@@ -474,7 +471,6 @@ static int max8973_probe(struct i2c_client *client,
return ret;
}
- max->rdev = rdev;
return 0;
}
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
index 2d618fc9c1af..90b4c530dee5 100644
--- a/drivers/regulator/max8997.c
+++ b/drivers/regulator/max8997.c
@@ -38,7 +38,6 @@ struct max8997_data {
struct device *dev;
struct max8997_dev *iodev;
int num_regulators;
- struct regulator_dev **rdev;
int ramp_delay; /* in mV/us */
bool buck1_gpiodvs;
@@ -924,7 +923,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
return -ENODEV;
}
- regulators_np = of_find_node_by_name(pmic_np, "regulators");
+ regulators_np = of_get_child_by_name(pmic_np, "regulators");
if (!regulators_np) {
dev_err(&pdev->dev, "could not find regulators sub-node\n");
return -EINVAL;
@@ -937,7 +936,6 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
pdata->num_regulators, GFP_KERNEL);
if (!rdata) {
of_node_put(regulators_np);
- dev_err(&pdev->dev, "could not allocate memory for regulator data\n");
return -ENOMEM;
}
@@ -1030,10 +1028,10 @@ static int max8997_pmic_probe(struct platform_device *pdev)
struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct max8997_platform_data *pdata = iodev->pdata;
struct regulator_config config = { };
- struct regulator_dev **rdev;
+ struct regulator_dev *rdev;
struct max8997_data *max8997;
struct i2c_client *i2c;
- int i, ret, size, nr_dvs;
+ int i, ret, nr_dvs;
u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0;
if (!pdata) {
@@ -1052,12 +1050,6 @@ static int max8997_pmic_probe(struct platform_device *pdev)
if (!max8997)
return -ENOMEM;
- size = sizeof(struct regulator_dev *) * pdata->num_regulators;
- max8997->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
- if (!max8997->rdev)
- return -ENOMEM;
-
- rdev = max8997->rdev;
max8997->dev = &pdev->dev;
max8997->iodev = iodev;
max8997->num_regulators = pdata->num_regulators;
@@ -1205,12 +1197,12 @@ static int max8997_pmic_probe(struct platform_device *pdev)
config.driver_data = max8997;
config.of_node = pdata->regulators[i].reg_node;
- rdev[i] = devm_regulator_register(&pdev->dev, &regulators[id],
- &config);
- if (IS_ERR(rdev[i])) {
+ rdev = devm_regulator_register(&pdev->dev, &regulators[id],
+ &config);
+ if (IS_ERR(rdev)) {
dev_err(max8997->dev, "regulator init failed for %d\n",
id);
- return PTR_ERR(rdev[i]);
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index ae3f0656feb0..961091b46557 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -40,7 +40,6 @@ struct max8998_data {
struct device *dev;
struct max8998_dev *iodev;
int num_regulators;
- struct regulator_dev **rdev;
u8 buck1_vol[4]; /* voltages for selection */
u8 buck2_vol[2];
unsigned int buck1_idx; /* index to last changed voltage */
@@ -674,8 +673,10 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev,
rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
pdata->num_regulators, GFP_KERNEL);
- if (!rdata)
+ if (!rdata) {
+ of_node_put(regulators_np);
return -ENOMEM;
+ }
pdata->regulators = rdata;
for (i = 0; i < ARRAY_SIZE(regulators); ++i) {
@@ -692,6 +693,9 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev,
}
pdata->num_regulators = rdata - pdata->regulators;
+ of_node_put(reg_np);
+ of_node_put(regulators_np);
+
ret = max8998_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
if (ret)
return -EINVAL;
@@ -741,10 +745,10 @@ static int max8998_pmic_probe(struct platform_device *pdev)
struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct max8998_platform_data *pdata = iodev->pdata;
struct regulator_config config = { };
- struct regulator_dev **rdev;
+ struct regulator_dev *rdev;
struct max8998_data *max8998;
struct i2c_client *i2c;
- int i, ret, size;
+ int i, ret;
unsigned int v;
if (!pdata) {
@@ -763,12 +767,6 @@ static int max8998_pmic_probe(struct platform_device *pdev)
if (!max8998)
return -ENOMEM;
- size = sizeof(struct regulator_dev *) * pdata->num_regulators;
- max8998->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
- if (!max8998->rdev)
- return -ENOMEM;
-
- rdev = max8998->rdev;
max8998->dev = &pdev->dev;
max8998->iodev = iodev;
max8998->num_regulators = pdata->num_regulators;
@@ -872,13 +870,12 @@ static int max8998_pmic_probe(struct platform_device *pdev)
config.init_data = pdata->regulators[i].initdata;
config.driver_data = max8998;
- rdev[i] = devm_regulator_register(&pdev->dev,
- &regulators[index], &config);
- if (IS_ERR(rdev[i])) {
- ret = PTR_ERR(rdev[i]);
+ rdev = devm_regulator_register(&pdev->dev, &regulators[index],
+ &config);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
dev_err(max8998->dev, "regulator %s init failed (%d)\n",
regulators[index].name, ret);
- rdev[i] = NULL;
return ret;
}
}
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index da4859282302..05b971726ffa 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -167,8 +167,10 @@ int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
struct device_node *parent;
int num;
- of_node_get(pdev->dev.parent->of_node);
- parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
+ if (!pdev->dev.parent->of_node)
+ return -ENODEV;
+
+ parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
if (!parent)
return -ENODEV;
@@ -187,8 +189,10 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
struct device_node *parent, *child;
int i, parsed = 0;
- of_node_get(pdev->dev.parent->of_node);
- parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
+ if (!pdev->dev.parent->of_node)
+ return NULL;
+
+ parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
if (!parent)
return NULL;
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index ab174f20ca11..67e678c4301c 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -56,6 +56,8 @@
#define PFUZE100_VGEN5VOL 0x70
#define PFUZE100_VGEN6VOL 0x71
+enum chips { PFUZE100, PFUZE200 };
+
struct pfuze_regulator {
struct regulator_desc desc;
unsigned char stby_reg;
@@ -63,6 +65,7 @@ struct pfuze_regulator {
};
struct pfuze_chip {
+ int chip_id;
struct regmap *regmap;
struct device *dev;
struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
@@ -78,21 +81,23 @@ static const int pfuze100_vsnvs[] = {
};
static const struct i2c_device_id pfuze_device_id[] = {
- {.name = "pfuze100"},
- {},
+ {.name = "pfuze100", .driver_data = PFUZE100},
+ {.name = "pfuze200", .driver_data = PFUZE200},
+ { }
};
MODULE_DEVICE_TABLE(i2c, pfuze_device_id);
static const struct of_device_id pfuze_dt_ids[] = {
- { .compatible = "fsl,pfuze100" },
- {},
+ { .compatible = "fsl,pfuze100", .data = (void *)PFUZE100},
+ { .compatible = "fsl,pfuze200", .data = (void *)PFUZE200},
+ { }
};
MODULE_DEVICE_TABLE(of, pfuze_dt_ids);
static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
{
struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev);
- int id = rdev->desc->id;
+ int id = rdev_get_id(rdev);
unsigned int ramp_bits;
int ret;
@@ -139,14 +144,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
};
-#define PFUZE100_FIXED_REG(_name, base, voltage) \
- [PFUZE100_ ## _name] = { \
+#define PFUZE100_FIXED_REG(_chip, _name, base, voltage) \
+ [_chip ## _ ## _name] = { \
.desc = { \
.name = #_name, \
.n_voltages = 1, \
.ops = &pfuze100_fixed_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
- .id = PFUZE100_ ## _name, \
+ .id = _chip ## _ ## _name, \
.owner = THIS_MODULE, \
.min_uV = (voltage), \
.enable_reg = (base), \
@@ -154,14 +159,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
}, \
}
-#define PFUZE100_SW_REG(_name, base, min, max, step) \
- [PFUZE100_ ## _name] = { \
+#define PFUZE100_SW_REG(_chip, _name, base, min, max, step) \
+ [_chip ## _ ## _name] = { \
.desc = { \
.name = #_name,\
.n_voltages = ((max) - (min)) / (step) + 1, \
.ops = &pfuze100_sw_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
- .id = PFUZE100_ ## _name, \
+ .id = _chip ## _ ## _name, \
.owner = THIS_MODULE, \
.min_uV = (min), \
.uV_step = (step), \
@@ -172,14 +177,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
.stby_mask = 0x3f, \
}
-#define PFUZE100_SWB_REG(_name, base, mask, voltages) \
- [PFUZE100_ ## _name] = { \
+#define PFUZE100_SWB_REG(_chip, _name, base, mask, voltages) \
+ [_chip ## _ ## _name] = { \
.desc = { \
.name = #_name, \
.n_voltages = ARRAY_SIZE(voltages), \
.ops = &pfuze100_swb_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
- .id = PFUZE100_ ## _name, \
+ .id = _chip ## _ ## _name, \
.owner = THIS_MODULE, \
.volt_table = voltages, \
.vsel_reg = (base), \
@@ -187,14 +192,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
}, \
}
-#define PFUZE100_VGEN_REG(_name, base, min, max, step) \
- [PFUZE100_ ## _name] = { \
+#define PFUZE100_VGEN_REG(_chip, _name, base, min, max, step) \
+ [_chip ## _ ## _name] = { \
.desc = { \
.name = #_name, \
.n_voltages = ((max) - (min)) / (step) + 1, \
.ops = &pfuze100_ldo_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
- .id = PFUZE100_ ## _name, \
+ .id = _chip ## _ ## _name, \
.owner = THIS_MODULE, \
.min_uV = (min), \
.uV_step = (step), \
@@ -207,25 +212,45 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
.stby_mask = 0x20, \
}
+/* PFUZE100 */
static struct pfuze_regulator pfuze100_regulators[] = {
- PFUZE100_SW_REG(SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
- PFUZE100_SW_REG(SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000),
- PFUZE100_SW_REG(SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
- PFUZE100_SW_REG(SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
- PFUZE100_SW_REG(SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
- PFUZE100_SW_REG(SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000),
- PFUZE100_SWB_REG(SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
- PFUZE100_SWB_REG(VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
- PFUZE100_FIXED_REG(VREFDDR, PFUZE100_VREFDDRCON, 750000),
- PFUZE100_VGEN_REG(VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
- PFUZE100_VGEN_REG(VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
- PFUZE100_VGEN_REG(VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
- PFUZE100_VGEN_REG(VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
- PFUZE100_VGEN_REG(VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
- PFUZE100_VGEN_REG(VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
+ PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
+ PFUZE100_SW_REG(PFUZE100, SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000),
+ PFUZE100_SW_REG(PFUZE100, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
+ PFUZE100_SW_REG(PFUZE100, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
+ PFUZE100_SW_REG(PFUZE100, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
+ PFUZE100_SW_REG(PFUZE100, SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000),
+ PFUZE100_SWB_REG(PFUZE100, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
+ PFUZE100_SWB_REG(PFUZE100, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
+ PFUZE100_FIXED_REG(PFUZE100, VREFDDR, PFUZE100_VREFDDRCON, 750000),
+ PFUZE100_VGEN_REG(PFUZE100, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
+ PFUZE100_VGEN_REG(PFUZE100, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
+ PFUZE100_VGEN_REG(PFUZE100, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
+};
+
+static struct pfuze_regulator pfuze200_regulators[] = {
+ PFUZE100_SW_REG(PFUZE200, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
+ PFUZE100_SW_REG(PFUZE200, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
+ PFUZE100_SW_REG(PFUZE200, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
+ PFUZE100_SW_REG(PFUZE200, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
+ PFUZE100_SWB_REG(PFUZE200, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
+ PFUZE100_SWB_REG(PFUZE200, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
+ PFUZE100_FIXED_REG(PFUZE200, VREFDDR, PFUZE100_VREFDDRCON, 750000),
+ PFUZE100_VGEN_REG(PFUZE200, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
+ PFUZE100_VGEN_REG(PFUZE200, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
+ PFUZE100_VGEN_REG(PFUZE200, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE200, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE200, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
};
+static struct pfuze_regulator *pfuze_regulators;
+
#ifdef CONFIG_OF
+/* PFUZE100 */
static struct of_regulator_match pfuze100_matches[] = {
{ .name = "sw1ab", },
{ .name = "sw1c", },
@@ -244,24 +269,56 @@ static struct of_regulator_match pfuze100_matches[] = {
{ .name = "vgen6", },
};
+/* PFUZE200 */
+static struct of_regulator_match pfuze200_matches[] = {
+
+ { .name = "sw1ab", },
+ { .name = "sw2", },
+ { .name = "sw3a", },
+ { .name = "sw3b", },
+ { .name = "swbst", },
+ { .name = "vsnvs", },
+ { .name = "vrefddr", },
+ { .name = "vgen1", },
+ { .name = "vgen2", },
+ { .name = "vgen3", },
+ { .name = "vgen4", },
+ { .name = "vgen5", },
+ { .name = "vgen6", },
+};
+
+static struct of_regulator_match *pfuze_matches;
+
static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
{
struct device *dev = chip->dev;
struct device_node *np, *parent;
int ret;
- np = of_node_get(dev->parent->of_node);
+ np = of_node_get(dev->of_node);
if (!np)
- return 0;
+ return -EINVAL;
- parent = of_find_node_by_name(np, "regulators");
+ parent = of_get_child_by_name(np, "regulators");
if (!parent) {
dev_err(dev, "regulators node not found\n");
return -EINVAL;
}
- ret = of_regulator_match(dev, parent, pfuze100_matches,
- ARRAY_SIZE(pfuze100_matches));
+ switch (chip->chip_id) {
+ case PFUZE200:
+ pfuze_matches = pfuze200_matches;
+ ret = of_regulator_match(dev, parent, pfuze200_matches,
+ ARRAY_SIZE(pfuze200_matches));
+ break;
+
+ case PFUZE100:
+ default:
+ pfuze_matches = pfuze100_matches;
+ ret = of_regulator_match(dev, parent, pfuze100_matches,
+ ARRAY_SIZE(pfuze100_matches));
+ break;
+ }
of_node_put(parent);
if (ret < 0) {
@@ -275,12 +332,12 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
static inline struct regulator_init_data *match_init_data(int index)
{
- return pfuze100_matches[index].init_data;
+ return pfuze_matches[index].init_data;
}
static inline struct device_node *match_of_node(int index)
{
- return pfuze100_matches[index].of_node;
+ return pfuze_matches[index].of_node;
}
#else
static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
@@ -308,16 +365,14 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip)
if (ret)
return ret;
- switch (value & 0x0f) {
- /*
- * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013
- * as ID=8
- */
- case 0x8:
+ if (((value & 0x0f) == 0x8) && (pfuze_chip->chip_id == PFUZE100)) {
+ /*
+ * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013
+ * as ID=8 in PFUZE100
+ */
dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8");
- case 0x0:
- break;
- default:
+ } else if ((value & 0x0f) != pfuze_chip->chip_id) {
+ /* device id NOT match with your setting */
dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value);
return -ENODEV;
}
@@ -353,17 +408,31 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
dev_get_platdata(&client->dev);
struct regulator_config config = { };
int i, ret;
+ const struct of_device_id *match;
+ u32 regulator_num;
+ u32 sw_check_start, sw_check_end;
pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip),
GFP_KERNEL);
if (!pfuze_chip)
return -ENOMEM;
- i2c_set_clientdata(client, pfuze_chip);
-
- memcpy(pfuze_chip->regulator_descs, pfuze100_regulators,
- sizeof(pfuze_chip->regulator_descs));
+ if (client->dev.of_node) {
+ match = of_match_device(of_match_ptr(pfuze_dt_ids),
+ &client->dev);
+ if (!match) {
+ dev_err(&client->dev, "Error: No device match found\n");
+ return -ENODEV;
+ }
+ pfuze_chip->chip_id = (int)(long)match->data;
+ } else if (id) {
+ pfuze_chip->chip_id = id->driver_data;
+ } else {
+ dev_err(&client->dev, "No dts match or id table match found\n");
+ return -ENODEV;
+ }
+ i2c_set_clientdata(client, pfuze_chip);
pfuze_chip->dev = &client->dev;
pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config);
@@ -380,11 +449,34 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
return ret;
}
+ /* use the right regulators after identify the right device */
+ switch (pfuze_chip->chip_id) {
+ case PFUZE200:
+ pfuze_regulators = pfuze200_regulators;
+ regulator_num = ARRAY_SIZE(pfuze200_regulators);
+ sw_check_start = PFUZE200_SW2;
+ sw_check_end = PFUZE200_SW3B;
+ break;
+
+ case PFUZE100:
+ default:
+ pfuze_regulators = pfuze100_regulators;
+ regulator_num = ARRAY_SIZE(pfuze100_regulators);
+ sw_check_start = PFUZE100_SW2;
+ sw_check_end = PFUZE100_SW4;
+ break;
+ }
+ dev_info(&client->dev, "pfuze%s found.\n",
+ (pfuze_chip->chip_id == PFUZE100) ? "100" : "200");
+
+ memcpy(pfuze_chip->regulator_descs, pfuze_regulators,
+ sizeof(pfuze_chip->regulator_descs));
+
ret = pfuze_parse_regulators_dt(pfuze_chip);
if (ret)
return ret;
- for (i = 0; i < PFUZE100_MAX_REGULATOR; i++) {
+ for (i = 0; i < regulator_num; i++) {
struct regulator_init_data *init_data;
struct regulator_desc *desc;
int val;
@@ -397,7 +489,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
init_data = match_init_data(i);
/* SW2~SW4 high bit check and modify the voltage value table */
- if (i > PFUZE100_SW1C && i < PFUZE100_SWBST) {
+ if (i >= sw_check_start && i <= sw_check_end) {
regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val);
if (val & 0x40) {
desc->min_uV = 800000;
@@ -415,7 +507,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
devm_regulator_register(&client->dev, desc, &config);
if (IS_ERR(pfuze_chip->regulators[i])) {
dev_err(&client->dev, "register regulator%s failed\n",
- pfuze100_regulators[i].desc.name);
+ pfuze_regulators[i].desc.name);
return PTR_ERR(pfuze_chip->regulators[i]);
}
}
@@ -435,6 +527,6 @@ static struct i2c_driver pfuze_driver = {
module_i2c_driver(pfuze_driver);
MODULE_AUTHOR("Robin Gong <b38343@freescale.com>");
-MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100 PMIC");
+MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/PFUZE200 PMIC");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("i2c:pfuze100-regulator");
diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c
index b58affb33143..4c414ae109ae 100644
--- a/drivers/regulator/rc5t583-regulator.c
+++ b/drivers/regulator/rc5t583-regulator.c
@@ -119,7 +119,6 @@ static int rc5t583_regulator_probe(struct platform_device *pdev)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev);
- struct regulator_init_data *reg_data;
struct regulator_config config = { };
struct rc5t583_regulator *reg = NULL;
struct rc5t583_regulator *regs;
@@ -135,19 +134,11 @@ static int rc5t583_regulator_probe(struct platform_device *pdev)
regs = devm_kzalloc(&pdev->dev, RC5T583_REGULATOR_MAX *
sizeof(struct rc5t583_regulator), GFP_KERNEL);
- if (!regs) {
- dev_err(&pdev->dev, "Memory allocation failed exiting..\n");
+ if (!regs)
return -ENOMEM;
- }
for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) {
- reg_data = pdata->reg_init_data[id];
-
- /* No need to register if there is no regulator data */
- if (!reg_data)
- continue;
-
reg = &regs[id];
ri = &rc5t583_reg_info[id];
reg->reg_info = ri;
@@ -169,7 +160,7 @@ static int rc5t583_regulator_probe(struct platform_device *pdev)
skip_ext_pwr_config:
config.dev = &pdev->dev;
- config.init_data = reg_data;
+ config.init_data = pdata->reg_init_data[id];
config.driver_data = reg;
config.regmap = rc5t583->regmap;
diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c
new file mode 100644
index 000000000000..808b3aa7a42c
--- /dev/null
+++ b/drivers/regulator/s2mpa01.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd
+ * http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/samsung/core.h>
+#include <linux/mfd/samsung/s2mpa01.h>
+
+#define S2MPA01_REGULATOR_CNT ARRAY_SIZE(regulators)
+
+struct s2mpa01_info {
+ int ramp_delay24;
+ int ramp_delay3;
+ int ramp_delay5;
+ int ramp_delay16;
+ int ramp_delay7;
+ int ramp_delay8910;
+};
+
+static int get_ramp_delay(int ramp_delay)
+{
+ unsigned char cnt = 0;
+
+ ramp_delay /= 6250;
+
+ while (true) {
+ ramp_delay = ramp_delay >> 1;
+ if (ramp_delay == 0)
+ break;
+ cnt++;
+ }
+
+ if (cnt > 3)
+ cnt = 3;
+
+ return cnt;
+}
+
+static int s2mpa01_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector,
+ unsigned int new_selector)
+{
+ struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev);
+ unsigned int ramp_delay = 0;
+ int old_volt, new_volt;
+
+ switch (rdev->desc->id) {
+ case S2MPA01_BUCK2:
+ case S2MPA01_BUCK4:
+ ramp_delay = s2mpa01->ramp_delay24;
+ break;
+ case S2MPA01_BUCK3:
+ ramp_delay = s2mpa01->ramp_delay3;
+ break;
+ case S2MPA01_BUCK5:
+ ramp_delay = s2mpa01->ramp_delay5;
+ break;
+ case S2MPA01_BUCK1:
+ case S2MPA01_BUCK6:
+ ramp_delay = s2mpa01->ramp_delay16;
+ break;
+ case S2MPA01_BUCK7:
+ ramp_delay = s2mpa01->ramp_delay7;
+ break;
+ case S2MPA01_BUCK8:
+ case S2MPA01_BUCK9:
+ case S2MPA01_BUCK10:
+ ramp_delay = s2mpa01->ramp_delay8910;
+ break;
+ }
+
+ if (ramp_delay == 0)
+ ramp_delay = rdev->desc->ramp_delay;
+
+ old_volt = rdev->desc->min_uV + (rdev->desc->uV_step * old_selector);
+ new_volt = rdev->desc->min_uV + (rdev->desc->uV_step * new_selector);
+
+ return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
+}
+
+static int s2mpa01_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev);
+ unsigned int ramp_val, ramp_shift, ramp_reg = S2MPA01_REG_RAMP2;
+ unsigned int ramp_enable = 1, enable_shift = 0;
+ int ret;
+
+ switch (rdev->desc->id) {
+ case S2MPA01_BUCK1:
+ enable_shift = S2MPA01_BUCK1_RAMP_EN_SHIFT;
+ if (!ramp_delay) {
+ ramp_enable = 0;
+ break;
+ }
+
+ if (ramp_delay > s2mpa01->ramp_delay16)
+ s2mpa01->ramp_delay16 = ramp_delay;
+ else
+ ramp_delay = s2mpa01->ramp_delay16;
+
+ ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT;
+ ramp_reg = S2MPA01_REG_RAMP1;
+ break;
+ case S2MPA01_BUCK2:
+ enable_shift = S2MPA01_BUCK2_RAMP_EN_SHIFT;
+ if (!ramp_delay) {
+ ramp_enable = 0;
+ break;
+ }
+
+ if (ramp_delay > s2mpa01->ramp_delay24)
+ s2mpa01->ramp_delay24 = ramp_delay;
+ else
+ ramp_delay = s2mpa01->ramp_delay24;
+
+ ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT;
+ ramp_reg = S2MPA01_REG_RAMP1;
+ break;
+ case S2MPA01_BUCK3:
+ enable_shift = S2MPA01_BUCK3_RAMP_EN_SHIFT;
+ if (!ramp_delay) {
+ ramp_enable = 0;
+ break;
+ }
+
+ s2mpa01->ramp_delay3 = ramp_delay;
+ ramp_shift = S2MPA01_BUCK3_RAMP_SHIFT;
+ ramp_reg = S2MPA01_REG_RAMP1;
+ break;
+ case S2MPA01_BUCK4:
+ enable_shift = S2MPA01_BUCK4_RAMP_EN_SHIFT;
+ if (!ramp_delay) {
+ ramp_enable = 0;
+ break;
+ }
+
+ if (ramp_delay > s2mpa01->ramp_delay24)
+ s2mpa01->ramp_delay24 = ramp_delay;
+ else
+ ramp_delay = s2mpa01->ramp_delay24;
+
+ ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT;
+ ramp_reg = S2MPA01_REG_RAMP1;
+ break;
+ case S2MPA01_BUCK5:
+ s2mpa01->ramp_delay5 = ramp_delay;
+ ramp_shift = S2MPA01_BUCK5_RAMP_SHIFT;
+ break;
+ case S2MPA01_BUCK6:
+ if (ramp_delay > s2mpa01->ramp_delay16)
+ s2mpa01->ramp_delay16 = ramp_delay;
+ else
+ ramp_delay = s2mpa01->ramp_delay16;
+
+ ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT;
+ break;
+ case S2MPA01_BUCK7:
+ s2mpa01->ramp_delay7 = ramp_delay;
+ ramp_shift = S2MPA01_BUCK7_RAMP_SHIFT;
+ break;
+ case S2MPA01_BUCK8:
+ case S2MPA01_BUCK9:
+ case S2MPA01_BUCK10:
+ if (ramp_delay > s2mpa01->ramp_delay8910)
+ s2mpa01->ramp_delay8910 = ramp_delay;
+ else
+ ramp_delay = s2mpa01->ramp_delay8910;
+
+ ramp_shift = S2MPA01_BUCK8910_RAMP_SHIFT;
+ break;
+ default:
+ return 0;
+ }
+
+ if (!ramp_enable)
+ goto ramp_disable;
+
+ if (enable_shift) {
+ ret = regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,
+ 1 << enable_shift, 1 << enable_shift);
+ if (ret) {
+ dev_err(&rdev->dev, "failed to enable ramp rate\n");
+ return ret;
+ }
+ }
+
+ ramp_val = get_ramp_delay(ramp_delay);
+
+ return regmap_update_bits(rdev->regmap, ramp_reg, 0x3 << ramp_shift,
+ ramp_val << ramp_shift);
+
+ramp_disable:
+ return regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,
+ 1 << enable_shift, 0);
+}
+
+static struct regulator_ops s2mpa01_ldo_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops s2mpa01_buck_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = s2mpa01_regulator_set_voltage_time_sel,
+ .set_ramp_delay = s2mpa01_set_ramp_delay,
+};
+
+#define regulator_desc_ldo1(num) { \
+ .name = "LDO"#num, \
+ .id = S2MPA01_LDO##num, \
+ .ops = &s2mpa01_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_LDO_MIN, \
+ .uV_step = S2MPA01_LDO_STEP1, \
+ .n_voltages = S2MPA01_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPA01_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPA01_LDO_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+#define regulator_desc_ldo2(num) { \
+ .name = "LDO"#num, \
+ .id = S2MPA01_LDO##num, \
+ .ops = &s2mpa01_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_LDO_MIN, \
+ .uV_step = S2MPA01_LDO_STEP2, \
+ .n_voltages = S2MPA01_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPA01_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPA01_LDO_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+#define regulator_desc_buck1_4(num) { \
+ .name = "BUCK"#num, \
+ .id = S2MPA01_BUCK##num, \
+ .ops = &s2mpa01_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_BUCK_MIN1, \
+ .uV_step = S2MPA01_BUCK_STEP1, \
+ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
+ .ramp_delay = S2MPA01_RAMP_DELAY, \
+ .vsel_reg = S2MPA01_REG_B1CTRL2 + (num - 1) * 2, \
+ .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_B1CTRL1 + (num - 1) * 2, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+#define regulator_desc_buck5 { \
+ .name = "BUCK5", \
+ .id = S2MPA01_BUCK5, \
+ .ops = &s2mpa01_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_BUCK_MIN2, \
+ .uV_step = S2MPA01_BUCK_STEP1, \
+ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
+ .ramp_delay = S2MPA01_RAMP_DELAY, \
+ .vsel_reg = S2MPA01_REG_B5CTRL2, \
+ .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_B5CTRL1, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+#define regulator_desc_buck6_7(num) { \
+ .name = "BUCK"#num, \
+ .id = S2MPA01_BUCK##num, \
+ .ops = &s2mpa01_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_BUCK_MIN1, \
+ .uV_step = S2MPA01_BUCK_STEP1, \
+ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
+ .ramp_delay = S2MPA01_RAMP_DELAY, \
+ .vsel_reg = S2MPA01_REG_B6CTRL2 + (num - 6) * 2, \
+ .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_B6CTRL1 + (num - 6) * 2, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+#define regulator_desc_buck8 { \
+ .name = "BUCK8", \
+ .id = S2MPA01_BUCK8, \
+ .ops = &s2mpa01_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_BUCK_MIN2, \
+ .uV_step = S2MPA01_BUCK_STEP2, \
+ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
+ .ramp_delay = S2MPA01_RAMP_DELAY, \
+ .vsel_reg = S2MPA01_REG_B8CTRL2, \
+ .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_B8CTRL1, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+#define regulator_desc_buck9 { \
+ .name = "BUCK9", \
+ .id = S2MPA01_BUCK9, \
+ .ops = &s2mpa01_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_BUCK_MIN4, \
+ .uV_step = S2MPA01_BUCK_STEP2, \
+ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
+ .ramp_delay = S2MPA01_RAMP_DELAY, \
+ .vsel_reg = S2MPA01_REG_B9CTRL2, \
+ .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_B9CTRL1, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+#define regulator_desc_buck10 { \
+ .name = "BUCK10", \
+ .id = S2MPA01_BUCK10, \
+ .ops = &s2mpa01_buck_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPA01_BUCK_MIN3, \
+ .uV_step = S2MPA01_BUCK_STEP2, \
+ .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
+ .ramp_delay = S2MPA01_RAMP_DELAY, \
+ .vsel_reg = S2MPA01_REG_B10CTRL2, \
+ .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPA01_REG_B10CTRL1, \
+ .enable_mask = S2MPA01_ENABLE_MASK \
+}
+
+static struct regulator_desc regulators[] = {
+ regulator_desc_ldo2(1),
+ regulator_desc_ldo1(2),
+ regulator_desc_ldo1(3),
+ regulator_desc_ldo1(4),
+ regulator_desc_ldo1(5),
+ regulator_desc_ldo2(6),
+ regulator_desc_ldo1(7),
+ regulator_desc_ldo1(8),
+ regulator_desc_ldo1(9),
+ regulator_desc_ldo1(10),
+ regulator_desc_ldo2(11),
+ regulator_desc_ldo1(12),
+ regulator_desc_ldo1(13),
+ regulator_desc_ldo1(14),
+ regulator_desc_ldo1(15),
+ regulator_desc_ldo1(16),
+ regulator_desc_ldo1(17),
+ regulator_desc_ldo1(18),
+ regulator_desc_ldo1(19),
+ regulator_desc_ldo1(20),
+ regulator_desc_ldo1(21),
+ regulator_desc_ldo2(22),
+ regulator_desc_ldo2(23),
+ regulator_desc_ldo1(24),
+ regulator_desc_ldo1(25),
+ regulator_desc_ldo1(26),
+ regulator_desc_buck1_4(1),
+ regulator_desc_buck1_4(2),
+ regulator_desc_buck1_4(3),
+ regulator_desc_buck1_4(4),
+ regulator_desc_buck5,
+ regulator_desc_buck6_7(6),
+ regulator_desc_buck6_7(7),
+ regulator_desc_buck8,
+ regulator_desc_buck9,
+ regulator_desc_buck10,
+};
+
+static int s2mpa01_pmic_probe(struct platform_device *pdev)
+{
+ struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+ struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct of_regulator_match rdata[S2MPA01_REGULATOR_MAX];
+ struct device_node *reg_np = NULL;
+ struct regulator_config config = { };
+ struct s2mpa01_info *s2mpa01;
+ int i;
+
+ s2mpa01 = devm_kzalloc(&pdev->dev, sizeof(*s2mpa01), GFP_KERNEL);
+ if (!s2mpa01)
+ return -ENOMEM;
+
+ for (i = 0; i < S2MPA01_REGULATOR_CNT; i++)
+ rdata[i].name = regulators[i].name;
+
+ if (iodev->dev->of_node) {
+ reg_np = of_get_child_by_name(iodev->dev->of_node,
+ "regulators");
+ if (!reg_np) {
+ dev_err(&pdev->dev,
+ "could not find regulators sub-node\n");
+ return -EINVAL;
+ }
+
+ of_regulator_match(&pdev->dev, reg_np, rdata,
+ S2MPA01_REGULATOR_MAX);
+ of_node_put(reg_np);
+ }
+
+ platform_set_drvdata(pdev, s2mpa01);
+
+ config.dev = &pdev->dev;
+ config.regmap = iodev->regmap_pmic;
+ config.driver_data = s2mpa01;
+
+ for (i = 0; i < S2MPA01_REGULATOR_MAX; i++) {
+ struct regulator_dev *rdev;
+ if (pdata)
+ config.init_data = pdata->regulators[i].initdata;
+ else
+ config.init_data = rdata[i].init_data;
+
+ if (reg_np)
+ config.of_node = rdata[i].of_node;
+
+ rdev = devm_regulator_register(&pdev->dev,
+ &regulators[i], &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "regulator init failed for %d\n",
+ i);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id s2mpa01_pmic_id[] = {
+ { "s2mpa01-pmic", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(platform, s2mpa01_pmic_id);
+
+static struct platform_driver s2mpa01_pmic_driver = {
+ .driver = {
+ .name = "s2mpa01-pmic",
+ .owner = THIS_MODULE,
+ },
+ .probe = s2mpa01_pmic_probe,
+ .id_table = s2mpa01_pmic_id,
+};
+
+module_platform_driver(s2mpa01_pmic_driver);
+
+/* Module information */
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_AUTHOR("Sachin Kamat <sachin.kamat@samsung.com>");
+MODULE_DESCRIPTION("SAMSUNG S2MPA01 Regulator Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index cd0b9e35a56d..68fd54702edb 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -1,13 +1,18 @@
/*
* s2mps11.c
*
- * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ * Copyright (c) 2012-2014 Samsung Electronics Co., Ltd
* http://www.samsung.com
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * This program is free software; 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.
*
*/
@@ -24,18 +29,21 @@
#include <linux/regulator/of_regulator.h>
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/s2mps11.h>
-
-#define S2MPS11_REGULATOR_CNT ARRAY_SIZE(regulators)
+#include <linux/mfd/samsung/s2mps14.h>
struct s2mps11_info {
- struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX];
-
+ unsigned int rdev_num;
int ramp_delay2;
int ramp_delay34;
int ramp_delay5;
int ramp_delay16;
int ramp_delay7810;
int ramp_delay9;
+ /*
+ * One bit for each S2MPS14 regulator whether the suspend mode
+ * was enabled.
+ */
+ unsigned int s2mps14_suspend_state:30;
};
static int get_ramp_delay(int ramp_delay)
@@ -65,7 +73,7 @@ static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
unsigned int ramp_delay = 0;
int old_volt, new_volt;
- switch (rdev->desc->id) {
+ switch (rdev_get_id(rdev)) {
case S2MPS11_BUCK2:
ramp_delay = s2mps11->ramp_delay2;
break;
@@ -105,7 +113,7 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
unsigned int ramp_enable = 1, enable_shift = 0;
int ret;
- switch (rdev->desc->id) {
+ switch (rdev_get_id(rdev)) {
case S2MPS11_BUCK1:
if (ramp_delay > s2mps11->ramp_delay16)
s2mps11->ramp_delay16 = ramp_delay;
@@ -236,7 +244,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.set_ramp_delay = s2mps11_set_ramp_delay,
};
-#define regulator_desc_ldo1(num) { \
+#define regulator_desc_s2mps11_ldo1(num) { \
.name = "LDO"#num, \
.id = S2MPS11_LDO##num, \
.ops = &s2mps11_ldo_ops, \
@@ -250,7 +258,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_reg = S2MPS11_REG_L1CTRL + num - 1, \
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_ldo2(num) { \
+#define regulator_desc_s2mps11_ldo2(num) { \
.name = "LDO"#num, \
.id = S2MPS11_LDO##num, \
.ops = &s2mps11_ldo_ops, \
@@ -265,7 +273,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_buck1_4(num) { \
+#define regulator_desc_s2mps11_buck1_4(num) { \
.name = "BUCK"#num, \
.id = S2MPS11_BUCK##num, \
.ops = &s2mps11_buck_ops, \
@@ -281,7 +289,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_buck5 { \
+#define regulator_desc_s2mps11_buck5 { \
.name = "BUCK5", \
.id = S2MPS11_BUCK5, \
.ops = &s2mps11_buck_ops, \
@@ -297,7 +305,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_buck6_8(num) { \
+#define regulator_desc_s2mps11_buck6_8(num) { \
.name = "BUCK"#num, \
.id = S2MPS11_BUCK##num, \
.ops = &s2mps11_buck_ops, \
@@ -313,7 +321,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_buck9 { \
+#define regulator_desc_s2mps11_buck9 { \
.name = "BUCK9", \
.id = S2MPS11_BUCK9, \
.ops = &s2mps11_buck_ops, \
@@ -329,7 +337,7 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_buck10 { \
+#define regulator_desc_s2mps11_buck10 { \
.name = "BUCK10", \
.id = S2MPS11_BUCK10, \
.ops = &s2mps11_buck_ops, \
@@ -345,72 +353,252 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-static struct regulator_desc regulators[] = {
- regulator_desc_ldo2(1),
- regulator_desc_ldo1(2),
- regulator_desc_ldo1(3),
- regulator_desc_ldo1(4),
- regulator_desc_ldo1(5),
- regulator_desc_ldo2(6),
- regulator_desc_ldo1(7),
- regulator_desc_ldo1(8),
- regulator_desc_ldo1(9),
- regulator_desc_ldo1(10),
- regulator_desc_ldo2(11),
- regulator_desc_ldo1(12),
- regulator_desc_ldo1(13),
- regulator_desc_ldo1(14),
- regulator_desc_ldo1(15),
- regulator_desc_ldo1(16),
- regulator_desc_ldo1(17),
- regulator_desc_ldo1(18),
- regulator_desc_ldo1(19),
- regulator_desc_ldo1(20),
- regulator_desc_ldo1(21),
- regulator_desc_ldo2(22),
- regulator_desc_ldo2(23),
- regulator_desc_ldo1(24),
- regulator_desc_ldo1(25),
- regulator_desc_ldo1(26),
- regulator_desc_ldo2(27),
- regulator_desc_ldo1(28),
- regulator_desc_ldo1(29),
- regulator_desc_ldo1(30),
- regulator_desc_ldo1(31),
- regulator_desc_ldo1(32),
- regulator_desc_ldo1(33),
- regulator_desc_ldo1(34),
- regulator_desc_ldo1(35),
- regulator_desc_ldo1(36),
- regulator_desc_ldo1(37),
- regulator_desc_ldo1(38),
- regulator_desc_buck1_4(1),
- regulator_desc_buck1_4(2),
- regulator_desc_buck1_4(3),
- regulator_desc_buck1_4(4),
- regulator_desc_buck5,
- regulator_desc_buck6_8(6),
- regulator_desc_buck6_8(7),
- regulator_desc_buck6_8(8),
- regulator_desc_buck9,
- regulator_desc_buck10,
+static const struct regulator_desc s2mps11_regulators[] = {
+ regulator_desc_s2mps11_ldo2(1),
+ regulator_desc_s2mps11_ldo1(2),
+ regulator_desc_s2mps11_ldo1(3),
+ regulator_desc_s2mps11_ldo1(4),
+ regulator_desc_s2mps11_ldo1(5),
+ regulator_desc_s2mps11_ldo2(6),
+ regulator_desc_s2mps11_ldo1(7),
+ regulator_desc_s2mps11_ldo1(8),
+ regulator_desc_s2mps11_ldo1(9),
+ regulator_desc_s2mps11_ldo1(10),
+ regulator_desc_s2mps11_ldo2(11),
+ regulator_desc_s2mps11_ldo1(12),
+ regulator_desc_s2mps11_ldo1(13),
+ regulator_desc_s2mps11_ldo1(14),
+ regulator_desc_s2mps11_ldo1(15),
+ regulator_desc_s2mps11_ldo1(16),
+ regulator_desc_s2mps11_ldo1(17),
+ regulator_desc_s2mps11_ldo1(18),
+ regulator_desc_s2mps11_ldo1(19),
+ regulator_desc_s2mps11_ldo1(20),
+ regulator_desc_s2mps11_ldo1(21),
+ regulator_desc_s2mps11_ldo2(22),
+ regulator_desc_s2mps11_ldo2(23),
+ regulator_desc_s2mps11_ldo1(24),
+ regulator_desc_s2mps11_ldo1(25),
+ regulator_desc_s2mps11_ldo1(26),
+ regulator_desc_s2mps11_ldo2(27),
+ regulator_desc_s2mps11_ldo1(28),
+ regulator_desc_s2mps11_ldo1(29),
+ regulator_desc_s2mps11_ldo1(30),
+ regulator_desc_s2mps11_ldo1(31),
+ regulator_desc_s2mps11_ldo1(32),
+ regulator_desc_s2mps11_ldo1(33),
+ regulator_desc_s2mps11_ldo1(34),
+ regulator_desc_s2mps11_ldo1(35),
+ regulator_desc_s2mps11_ldo1(36),
+ regulator_desc_s2mps11_ldo1(37),
+ regulator_desc_s2mps11_ldo1(38),
+ regulator_desc_s2mps11_buck1_4(1),
+ regulator_desc_s2mps11_buck1_4(2),
+ regulator_desc_s2mps11_buck1_4(3),
+ regulator_desc_s2mps11_buck1_4(4),
+ regulator_desc_s2mps11_buck5,
+ regulator_desc_s2mps11_buck6_8(6),
+ regulator_desc_s2mps11_buck6_8(7),
+ regulator_desc_s2mps11_buck6_8(8),
+ regulator_desc_s2mps11_buck9,
+ regulator_desc_s2mps11_buck10,
+};
+
+static int s2mps14_regulator_enable(struct regulator_dev *rdev)
+{
+ struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+ unsigned int val;
+
+ if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev)))
+ val = S2MPS14_ENABLE_SUSPEND;
+ else
+ val = rdev->desc->enable_mask;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, val);
+}
+
+static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev)
+{
+ int ret;
+ unsigned int val;
+ struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+
+ /* LDO3 should be always on and does not support suspend mode */
+ if (rdev_get_id(rdev) == S2MPS14_LDO3)
+ return 0;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
+ if (ret < 0)
+ return ret;
+
+ s2mps11->s2mps14_suspend_state |= (1 << rdev_get_id(rdev));
+ /*
+ * Don't enable suspend mode if regulator is already disabled because
+ * this would effectively for a short time turn on the regulator after
+ * resuming.
+ * However we still want to toggle the suspend_state bit for regulator
+ * in case if it got enabled before suspending the system.
+ */
+ if (!(val & rdev->desc->enable_mask))
+ return 0;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, S2MPS14_ENABLE_SUSPEND);
+}
+
+static struct regulator_ops s2mps14_reg_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = s2mps14_regulator_enable,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_suspend_disable = s2mps14_regulator_set_suspend_disable,
+};
+
+#define regulator_desc_s2mps14_ldo1(num) { \
+ .name = "LDO"#num, \
+ .id = S2MPS14_LDO##num, \
+ .ops = &s2mps14_reg_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS14_LDO_MIN_800MV, \
+ .uV_step = S2MPS14_LDO_STEP_25MV, \
+ .n_voltages = S2MPS14_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPS14_LDO_VSEL_MASK, \
+ .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPS14_ENABLE_MASK \
+}
+#define regulator_desc_s2mps14_ldo2(num) { \
+ .name = "LDO"#num, \
+ .id = S2MPS14_LDO##num, \
+ .ops = &s2mps14_reg_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS14_LDO_MIN_1800MV, \
+ .uV_step = S2MPS14_LDO_STEP_25MV, \
+ .n_voltages = S2MPS14_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPS14_LDO_VSEL_MASK, \
+ .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPS14_ENABLE_MASK \
+}
+#define regulator_desc_s2mps14_ldo3(num) { \
+ .name = "LDO"#num, \
+ .id = S2MPS14_LDO##num, \
+ .ops = &s2mps14_reg_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS14_LDO_MIN_800MV, \
+ .uV_step = S2MPS14_LDO_STEP_12_5MV, \
+ .n_voltages = S2MPS14_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPS14_LDO_VSEL_MASK, \
+ .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPS14_ENABLE_MASK \
+}
+#define regulator_desc_s2mps14_buck1235(num) { \
+ .name = "BUCK"#num, \
+ .id = S2MPS14_BUCK##num, \
+ .ops = &s2mps14_reg_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS14_BUCK1235_MIN_600MV, \
+ .uV_step = S2MPS14_BUCK1235_STEP_6_25MV, \
+ .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \
+ .linear_min_sel = S2MPS14_BUCK1235_START_SEL, \
+ .ramp_delay = S2MPS14_BUCK_RAMP_DELAY, \
+ .vsel_reg = S2MPS14_REG_B1CTRL2 + (num - 1) * 2, \
+ .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPS14_REG_B1CTRL1 + (num - 1) * 2, \
+ .enable_mask = S2MPS14_ENABLE_MASK \
+}
+#define regulator_desc_s2mps14_buck4(num) { \
+ .name = "BUCK"#num, \
+ .id = S2MPS14_BUCK##num, \
+ .ops = &s2mps14_reg_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = S2MPS14_BUCK4_MIN_1400MV, \
+ .uV_step = S2MPS14_BUCK4_STEP_12_5MV, \
+ .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \
+ .linear_min_sel = S2MPS14_BUCK4_START_SEL, \
+ .ramp_delay = S2MPS14_BUCK_RAMP_DELAY, \
+ .vsel_reg = S2MPS14_REG_B1CTRL2 + (num - 1) * 2, \
+ .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPS14_REG_B1CTRL1 + (num - 1) * 2, \
+ .enable_mask = S2MPS14_ENABLE_MASK \
+}
+
+static const struct regulator_desc s2mps14_regulators[] = {
+ regulator_desc_s2mps14_ldo3(1),
+ regulator_desc_s2mps14_ldo3(2),
+ regulator_desc_s2mps14_ldo1(3),
+ regulator_desc_s2mps14_ldo1(4),
+ regulator_desc_s2mps14_ldo3(5),
+ regulator_desc_s2mps14_ldo3(6),
+ regulator_desc_s2mps14_ldo1(7),
+ regulator_desc_s2mps14_ldo2(8),
+ regulator_desc_s2mps14_ldo3(9),
+ regulator_desc_s2mps14_ldo3(10),
+ regulator_desc_s2mps14_ldo1(11),
+ regulator_desc_s2mps14_ldo2(12),
+ regulator_desc_s2mps14_ldo2(13),
+ regulator_desc_s2mps14_ldo2(14),
+ regulator_desc_s2mps14_ldo2(15),
+ regulator_desc_s2mps14_ldo2(16),
+ regulator_desc_s2mps14_ldo2(17),
+ regulator_desc_s2mps14_ldo2(18),
+ regulator_desc_s2mps14_ldo1(19),
+ regulator_desc_s2mps14_ldo1(20),
+ regulator_desc_s2mps14_ldo1(21),
+ regulator_desc_s2mps14_ldo3(22),
+ regulator_desc_s2mps14_ldo1(23),
+ regulator_desc_s2mps14_ldo2(24),
+ regulator_desc_s2mps14_ldo2(25),
+ regulator_desc_s2mps14_buck1235(1),
+ regulator_desc_s2mps14_buck1235(2),
+ regulator_desc_s2mps14_buck1235(3),
+ regulator_desc_s2mps14_buck4(4),
+ regulator_desc_s2mps14_buck1235(5),
};
static int s2mps11_pmic_probe(struct platform_device *pdev)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
- struct of_regulator_match rdata[S2MPS11_REGULATOR_MAX];
+ struct sec_platform_data *pdata = iodev->pdata;
+ struct of_regulator_match *rdata = NULL;
struct device_node *reg_np = NULL;
struct regulator_config config = { };
struct s2mps11_info *s2mps11;
- int i, ret;
+ int i, ret = 0;
+ const struct regulator_desc *regulators;
+ enum sec_device_type dev_type;
s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info),
GFP_KERNEL);
if (!s2mps11)
return -ENOMEM;
+ dev_type = platform_get_device_id(pdev)->driver_data;
+ switch (dev_type) {
+ case S2MPS11X:
+ s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators);
+ regulators = s2mps11_regulators;
+ break;
+ case S2MPS14X:
+ s2mps11->rdev_num = ARRAY_SIZE(s2mps14_regulators);
+ regulators = s2mps14_regulators;
+ break;
+ default:
+ dev_err(&pdev->dev, "Invalid device type: %u\n", dev_type);
+ return -EINVAL;
+ };
+
if (!iodev->dev->of_node) {
if (pdata) {
goto common_reg;
@@ -421,16 +609,22 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
}
}
- for (i = 0; i < S2MPS11_REGULATOR_CNT; i++)
+ rdata = kzalloc(sizeof(*rdata) * s2mps11->rdev_num, GFP_KERNEL);
+ if (!rdata)
+ return -ENOMEM;
+
+ for (i = 0; i < s2mps11->rdev_num; i++)
rdata[i].name = regulators[i].name;
- reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators");
+ reg_np = of_get_child_by_name(iodev->dev->of_node, "regulators");
if (!reg_np) {
dev_err(&pdev->dev, "could not find regulators sub-node\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
- of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX);
+ of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num);
+ of_node_put(reg_np);
common_reg:
platform_set_drvdata(pdev, s2mps11);
@@ -438,7 +632,9 @@ common_reg:
config.dev = &pdev->dev;
config.regmap = iodev->regmap_pmic;
config.driver_data = s2mps11;
- for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) {
+ for (i = 0; i < s2mps11->rdev_num; i++) {
+ struct regulator_dev *regulator;
+
if (!reg_np) {
config.init_data = pdata->regulators[i].initdata;
config.of_node = pdata->regulators[i].reg_node;
@@ -447,21 +643,25 @@ common_reg:
config.of_node = rdata[i].of_node;
}
- s2mps11->rdev[i] = devm_regulator_register(&pdev->dev,
+ regulator = devm_regulator_register(&pdev->dev,
&regulators[i], &config);
- if (IS_ERR(s2mps11->rdev[i])) {
- ret = PTR_ERR(s2mps11->rdev[i]);
+ if (IS_ERR(regulator)) {
+ ret = PTR_ERR(regulator);
dev_err(&pdev->dev, "regulator init failed for %d\n",
i);
- return ret;
+ goto out;
}
}
- return 0;
+out:
+ kfree(rdata);
+
+ return ret;
}
static const struct platform_device_id s2mps11_pmic_id[] = {
- { "s2mps11-pmic", 0},
+ { "s2mps11-pmic", S2MPS11X},
+ { "s2mps14-pmic", S2MPS14X},
{ },
};
MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id);
@@ -489,5 +689,5 @@ module_exit(s2mps11_pmic_exit);
/* Module information */
MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
-MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver");
+MODULE_DESCRIPTION("SAMSUNG S2MPS11/S2MPS14 Regulator Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index d7164bb75d3e..f05badabd69e 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -11,11 +11,8 @@
*
*/
-#include <linux/bug.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/of_gpio.h>
-#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
@@ -170,12 +167,11 @@ static unsigned int s5m8767_opmode_reg[][4] = {
{0x0, 0x3, 0x1, 0x1}, /* BUCK9 */
};
-static int s5m8767_get_register(struct regulator_dev *rdev, int *reg,
- int *enable_ctrl)
+static int s5m8767_get_register(struct s5m8767_info *s5m8767, int reg_id,
+ int *reg, int *enable_ctrl)
{
- int i, reg_id = rdev_get_id(rdev);
+ int i;
unsigned int mode;
- struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
switch (reg_id) {
case S5M8767_LDO1 ... S5M8767_LDO2:
@@ -214,53 +210,6 @@ static int s5m8767_get_register(struct regulator_dev *rdev, int *reg,
return 0;
}
-static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
-{
- struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
- int ret, reg;
- int enable_ctrl;
- unsigned int val;
-
- ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
- if (ret == -EINVAL)
- return 1;
- else if (ret)
- return ret;
-
- ret = regmap_read(s5m8767->iodev->regmap_pmic, reg, &val);
- if (ret)
- return ret;
-
- return (val & S5M8767_ENCTRL_MASK) == enable_ctrl;
-}
-
-static int s5m8767_reg_enable(struct regulator_dev *rdev)
-{
- struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
- int ret, reg;
- int enable_ctrl;
-
- ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
- if (ret)
- return ret;
-
- return regmap_update_bits(s5m8767->iodev->regmap_pmic, reg,
- S5M8767_ENCTRL_MASK, enable_ctrl);
-}
-
-static int s5m8767_reg_disable(struct regulator_dev *rdev)
-{
- struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
- int ret, reg, enable_ctrl;
-
- ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
- if (ret)
- return ret;
-
- return regmap_update_bits(s5m8767->iodev->regmap_pmic, reg,
- S5M8767_ENCTRL_MASK, ~S5M8767_ENCTRL_MASK);
-}
-
static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767)
{
int reg;
@@ -410,9 +359,9 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
static struct regulator_ops s5m8767_ops = {
.list_voltage = regulator_list_voltage_linear,
- .is_enabled = s5m8767_reg_is_enabled,
- .enable = s5m8767_reg_enable,
- .disable = s5m8767_reg_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = s5m8767_set_voltage_sel,
.set_voltage_time_sel = s5m8767_set_voltage_time_sel,
@@ -420,9 +369,9 @@ static struct regulator_ops s5m8767_ops = {
static struct regulator_ops s5m8767_buck78_ops = {
.list_voltage = regulator_list_voltage_linear,
- .is_enabled = s5m8767_reg_is_enabled,
- .enable = s5m8767_reg_enable,
- .disable = s5m8767_reg_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
@@ -483,6 +432,66 @@ static struct regulator_desc regulators[] = {
s5m8767_regulator_desc(BUCK9),
};
+/*
+ * Enable GPIO control over BUCK9 in regulator_config for that regulator.
+ */
+static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767,
+ struct sec_regulator_data *rdata,
+ struct regulator_config *config)
+{
+ int i, mode = 0;
+
+ if (rdata->id != S5M8767_BUCK9)
+ return;
+
+ /* Check if opmode for regulator matches S5M8767_ENCTRL_USE_GPIO */
+ for (i = 0; i < s5m8767->num_regulators; i++) {
+ const struct sec_opmode_data *opmode = &s5m8767->opmode[i];
+ if (opmode->id == rdata->id) {
+ mode = s5m8767_opmode_reg[rdata->id][opmode->mode];
+ break;
+ }
+ }
+ if (mode != S5M8767_ENCTRL_USE_GPIO) {
+ dev_warn(s5m8767->dev,
+ "ext-control for %s: mismatched op_mode (%x), ignoring\n",
+ rdata->reg_node->name, mode);
+ return;
+ }
+
+ if (!gpio_is_valid(rdata->ext_control_gpio)) {
+ dev_warn(s5m8767->dev,
+ "ext-control for %s: GPIO not valid, ignoring\n",
+ rdata->reg_node->name);
+ return;
+ }
+
+ config->ena_gpio = rdata->ext_control_gpio;
+ config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
+}
+
+/*
+ * Turn on GPIO control over BUCK9.
+ */
+static int s5m8767_enable_ext_control(struct s5m8767_info *s5m8767,
+ struct regulator_dev *rdev)
+{
+ int id = rdev_get_id(rdev);
+ int ret, reg, enable_ctrl;
+
+ if (id != S5M8767_BUCK9)
+ return -EINVAL;
+
+ ret = s5m8767_get_register(s5m8767, id, &reg, &enable_ctrl);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(s5m8767->iodev->regmap_pmic,
+ reg, S5M8767_ENCTRL_MASK,
+ S5M8767_ENCTRL_USE_GPIO << S5M8767_ENCTRL_SHIFT);
+}
+
+
#ifdef CONFIG_OF
static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev,
struct sec_platform_data *pdata,
@@ -520,6 +529,16 @@ static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
return 0;
}
+static void s5m8767_pmic_dt_parse_ext_control_gpio(struct sec_pmic_dev *iodev,
+ struct sec_regulator_data *rdata,
+ struct device_node *reg_np)
+{
+ rdata->ext_control_gpio = of_get_named_gpio(reg_np,
+ "s5m8767,pmic-ext-control-gpios", 0);
+ if (!gpio_is_valid(rdata->ext_control_gpio))
+ rdata->ext_control_gpio = 0;
+}
+
static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
struct sec_platform_data *pdata)
{
@@ -535,7 +554,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
return -ENODEV;
}
- regulators_np = of_find_node_by_name(pmic_np, "regulators");
+ regulators_np = of_get_child_by_name(pmic_np, "regulators");
if (!regulators_np) {
dev_err(iodev->dev, "could not find regulators sub-node\n");
return -EINVAL;
@@ -546,19 +565,13 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
pdata->num_regulators, GFP_KERNEL);
- if (!rdata) {
- dev_err(iodev->dev,
- "could not allocate memory for regulator data\n");
+ if (!rdata)
return -ENOMEM;
- }
rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) *
pdata->num_regulators, GFP_KERNEL);
- if (!rmode) {
- dev_err(iodev->dev,
- "could not allocate memory for regulator mode\n");
+ if (!rmode)
return -ENOMEM;
- }
pdata->regulators = rdata;
pdata->opmode = rmode;
@@ -574,6 +587,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
continue;
}
+ s5m8767_pmic_dt_parse_ext_control_gpio(iodev, rdata, reg_np);
+
rdata->id = i;
rdata->initdata = of_get_regulator_init_data(
&pdev->dev, reg_np);
@@ -591,6 +606,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
rmode++;
}
+ of_node_put(regulators_np);
+
if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) {
pdata->buck2_gpiodvs = true;
@@ -920,6 +937,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
for (i = 0; i < pdata->num_regulators; i++) {
const struct sec_voltage_desc *desc;
int id = pdata->regulators[i].id;
+ int enable_reg, enable_val;
desc = reg_voltage_map[id];
if (desc) {
@@ -933,6 +951,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
regulators[id].vsel_mask = 0x3f;
else
regulators[id].vsel_mask = 0xff;
+
+ s5m8767_get_register(s5m8767, id, &enable_reg,
+ &enable_val);
+ regulators[id].enable_reg = enable_reg;
+ regulators[id].enable_mask = S5M8767_ENCTRL_MASK;
+ regulators[id].enable_val = enable_val;
}
config.dev = s5m8767->dev;
@@ -940,6 +964,9 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
config.driver_data = s5m8767;
config.regmap = iodev->regmap_pmic;
config.of_node = pdata->regulators[i].reg_node;
+ if (pdata->regulators[i].ext_control_gpio)
+ s5m8767_regulator_config_ext_control(s5m8767,
+ &pdata->regulators[i], &config);
rdev[i] = devm_regulator_register(&pdev->dev, &regulators[id],
&config);
@@ -949,6 +976,16 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
id);
return ret;
}
+
+ if (pdata->regulators[i].ext_control_gpio) {
+ ret = s5m8767_enable_ext_control(s5m8767, rdev[i]);
+ if (ret < 0) {
+ dev_err(s5m8767->dev,
+ "failed to enable gpio control over %s: %d\n",
+ rdev[i]->desc->name, ret);
+ return ret;
+ }
+ }
}
return 0;
diff --git a/drivers/regulator/st-pwm.c b/drivers/regulator/st-pwm.c
new file mode 100644
index 000000000000..e367af1c5f9d
--- /dev/null
+++ b/drivers/regulator/st-pwm.c
@@ -0,0 +1,190 @@
+/*
+ * Regulator driver for ST's PWM Regulators
+ *
+ * Copyright (C) 2014 - STMicroelectronics Inc.
+ *
+ * Author: Lee Jones <lee.jones@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pwm.h>
+
+#define ST_PWM_REG_PERIOD 8448
+
+struct st_pwm_regulator_pdata {
+ const struct regulator_desc *desc;
+ struct st_pwm_voltages *duty_cycle_table;
+};
+
+struct st_pwm_regulator_data {
+ const struct st_pwm_regulator_pdata *pdata;
+ struct pwm_device *pwm;
+ bool enabled;
+ int state;
+};
+
+struct st_pwm_voltages {
+ unsigned int uV;
+ unsigned int dutycycle;
+};
+
+static int st_pwm_regulator_get_voltage_sel(struct regulator_dev *dev)
+{
+ struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+
+ return drvdata->state;
+}
+
+static int st_pwm_regulator_set_voltage_sel(struct regulator_dev *dev,
+ unsigned selector)
+{
+ struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+ int dutycycle;
+ int ret;
+
+ dutycycle = (ST_PWM_REG_PERIOD / 100) *
+ drvdata->pdata->duty_cycle_table[selector].dutycycle;
+
+ ret = pwm_config(drvdata->pwm, dutycycle, ST_PWM_REG_PERIOD);
+ if (ret) {
+ dev_err(&dev->dev, "Failed to configure PWM\n");
+ return ret;
+ }
+
+ drvdata->state = selector;
+
+ if (!drvdata->enabled) {
+ ret = pwm_enable(drvdata->pwm);
+ if (ret) {
+ dev_err(&dev->dev, "Failed to enable PWM\n");
+ return ret;
+ }
+ drvdata->enabled = true;
+ }
+
+ return 0;
+}
+
+static int st_pwm_regulator_list_voltage(struct regulator_dev *dev,
+ unsigned selector)
+{
+ struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+
+ if (selector >= dev->desc->n_voltages)
+ return -EINVAL;
+
+ return drvdata->pdata->duty_cycle_table[selector].uV;
+}
+
+static struct regulator_ops st_pwm_regulator_voltage_ops = {
+ .set_voltage_sel = st_pwm_regulator_set_voltage_sel,
+ .get_voltage_sel = st_pwm_regulator_get_voltage_sel,
+ .list_voltage = st_pwm_regulator_list_voltage,
+ .map_voltage = regulator_map_voltage_iterate,
+};
+
+static struct st_pwm_voltages b2105_duty_cycle_table[] = {
+ { .uV = 1114000, .dutycycle = 0, },
+ { .uV = 1095000, .dutycycle = 10, },
+ { .uV = 1076000, .dutycycle = 20, },
+ { .uV = 1056000, .dutycycle = 30, },
+ { .uV = 1036000, .dutycycle = 40, },
+ { .uV = 1016000, .dutycycle = 50, },
+ /* WARNING: Values above 50% duty-cycle cause boot failures. */
+};
+
+static const struct regulator_desc b2105_desc = {
+ .name = "b2105-pwm-regulator",
+ .ops = &st_pwm_regulator_voltage_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(b2105_duty_cycle_table),
+ .supply_name = "pwm",
+};
+
+static const struct st_pwm_regulator_pdata b2105_info = {
+ .desc = &b2105_desc,
+ .duty_cycle_table = b2105_duty_cycle_table,
+};
+
+static struct of_device_id st_pwm_of_match[] = {
+ { .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, },
+ { },
+};
+MODULE_DEVICE_TABLE(of, st_pwm_of_match);
+
+static int st_pwm_regulator_probe(struct platform_device *pdev)
+{
+ struct st_pwm_regulator_data *drvdata;
+ struct regulator_dev *regulator;
+ struct regulator_config config = { };
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_match;
+
+ if (!np) {
+ dev_err(&pdev->dev, "Device Tree node missing\n");
+ return -EINVAL;
+ }
+
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ of_match = of_match_device(st_pwm_of_match, &pdev->dev);
+ if (!of_match) {
+ dev_err(&pdev->dev, "failed to match of device\n");
+ return -ENODEV;
+ }
+ drvdata->pdata = of_match->data;
+
+ config.init_data = of_get_regulator_init_data(&pdev->dev, np);
+ if (!config.init_data)
+ return -ENOMEM;
+
+ config.of_node = np;
+ config.dev = &pdev->dev;
+ config.driver_data = drvdata;
+
+ drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
+ if (IS_ERR(drvdata->pwm)) {
+ dev_err(&pdev->dev, "Failed to get PWM\n");
+ return PTR_ERR(drvdata->pwm);
+ }
+
+ regulator = devm_regulator_register(&pdev->dev,
+ drvdata->pdata->desc, &config);
+ if (IS_ERR(regulator)) {
+ dev_err(&pdev->dev, "Failed to register regulator %s\n",
+ drvdata->pdata->desc->name);
+ return PTR_ERR(regulator);
+ }
+
+ return 0;
+}
+
+static struct platform_driver st_pwm_regulator_driver = {
+ .driver = {
+ .name = "st-pwm-regulator",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(st_pwm_of_match),
+ },
+ .probe = st_pwm_regulator_probe,
+};
+
+module_platform_driver(st_pwm_regulator_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
+MODULE_DESCRIPTION("ST PWM Regulator Driver");
+MODULE_ALIAS("platform:st_pwm-regulator");
diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c
index b187b6bba7ad..a2dabb575b97 100644
--- a/drivers/regulator/ti-abb-regulator.c
+++ b/drivers/regulator/ti-abb-regulator.c
@@ -54,8 +54,8 @@ struct ti_abb_info {
/**
* struct ti_abb_reg - Register description for ABB block
- * @setup_reg: setup register offset from base
- * @control_reg: control register offset from base
+ * @setup_off: setup register offset from base
+ * @control_off: control register offset from base
* @sr2_wtcnt_value_mask: setup register- sr2_wtcnt_value mask
* @fbb_sel_mask: setup register- FBB sel mask
* @rbb_sel_mask: setup register- RBB sel mask
@@ -64,8 +64,8 @@ struct ti_abb_info {
* @opp_sel_mask: control register - mask for mode to operate
*/
struct ti_abb_reg {
- u32 setup_reg;
- u32 control_reg;
+ u32 setup_off;
+ u32 control_off;
/* Setup register fields */
u32 sr2_wtcnt_value_mask;
@@ -83,6 +83,8 @@ struct ti_abb_reg {
* @rdesc: regulator descriptor
* @clk: clock(usually sysclk) supplying ABB block
* @base: base address of ABB block
+ * @setup_reg: setup register of ABB block
+ * @control_reg: control register of ABB block
* @int_base: interrupt register base address
* @efuse_base: (optional) efuse base address for ABB modes
* @ldo_base: (optional) LDOVBB vset override base address
@@ -99,6 +101,8 @@ struct ti_abb {
struct regulator_desc rdesc;
struct clk *clk;
void __iomem *base;
+ void __iomem *setup_reg;
+ void __iomem *control_reg;
void __iomem *int_base;
void __iomem *efuse_base;
void __iomem *ldo_base;
@@ -118,20 +122,18 @@ struct ti_abb {
* ti_abb_rmw() - handy wrapper to set specific register bits
* @mask: mask for register field
* @value: value shifted to mask location and written
- * @offset: offset of register
- * @base: base address
+ * @reg: register address
*
* Return: final register value (may be unused)
*/
-static inline u32 ti_abb_rmw(u32 mask, u32 value, u32 offset,
- void __iomem *base)
+static inline u32 ti_abb_rmw(u32 mask, u32 value, void __iomem *reg)
{
u32 val;
- val = readl(base + offset);
+ val = readl(reg);
val &= ~mask;
val |= (value << __ffs(mask)) & mask;
- writel(val, base + offset);
+ writel(val, reg);
return val;
}
@@ -263,21 +265,19 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,
if (ret)
goto out;
- ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, regs->setup_reg,
- abb->base);
+ ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, abb->setup_reg);
switch (info->opp_sel) {
case TI_ABB_SLOW_OPP:
- ti_abb_rmw(regs->rbb_sel_mask, 1, regs->setup_reg, abb->base);
+ ti_abb_rmw(regs->rbb_sel_mask, 1, abb->setup_reg);
break;
case TI_ABB_FAST_OPP:
- ti_abb_rmw(regs->fbb_sel_mask, 1, regs->setup_reg, abb->base);
+ ti_abb_rmw(regs->fbb_sel_mask, 1, abb->setup_reg);
break;
}
/* program next state of ABB ldo */
- ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, regs->control_reg,
- abb->base);
+ ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, abb->control_reg);
/*
* program LDO VBB vset override if needed for !bypass mode
@@ -288,7 +288,7 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,
ti_abb_program_ldovbb(dev, abb, info);
/* Initiate ABB ldo change */
- ti_abb_rmw(regs->opp_change_mask, 1, regs->control_reg, abb->base);
+ ti_abb_rmw(regs->opp_change_mask, 1, abb->control_reg);
/* Wait for ABB LDO to complete transition to new Bias setting */
ret = ti_abb_wait_txdone(dev, abb);
@@ -490,8 +490,7 @@ static int ti_abb_init_timings(struct device *dev, struct ti_abb *abb)
dev_dbg(dev, "%s: Clk_rate=%ld, sr2_cnt=0x%08x\n", __func__,
clk_get_rate(abb->clk), sr2_wt_cnt_val);
- ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, regs->setup_reg,
- abb->base);
+ ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, abb->setup_reg);
return 0;
}
@@ -508,32 +507,24 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb,
struct regulator_init_data *rinit_data)
{
struct ti_abb_info *info;
- const struct property *prop;
- const __be32 *abb_info;
const u32 num_values = 6;
char *pname = "ti,abb_info";
- u32 num_entries, i;
+ u32 i;
unsigned int *volt_table;
- int min_uV = INT_MAX, max_uV = 0;
+ int num_entries, min_uV = INT_MAX, max_uV = 0;
struct regulation_constraints *c = &rinit_data->constraints;
- prop = of_find_property(dev->of_node, pname, NULL);
- if (!prop) {
- dev_err(dev, "No '%s' property?\n", pname);
- return -ENODEV;
- }
-
- if (!prop->value) {
- dev_err(dev, "Empty '%s' property?\n", pname);
- return -ENODATA;
- }
-
/*
* Each abb_info is a set of n-tuple, where n is num_values, consisting
* of voltage and a set of detection logic for ABB information for that
* voltage to apply.
*/
- num_entries = prop->length / sizeof(u32);
+ num_entries = of_property_count_u32_elems(dev->of_node, pname);
+ if (num_entries < 0) {
+ dev_err(dev, "No '%s' property?\n", pname);
+ return num_entries;
+ }
+
if (!num_entries || (num_entries % num_values)) {
dev_err(dev, "All '%s' list entries need %d vals\n", pname,
num_values);
@@ -542,38 +533,38 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb,
num_entries /= num_values;
info = devm_kzalloc(dev, sizeof(*info) * num_entries, GFP_KERNEL);
- if (!info) {
- dev_err(dev, "Can't allocate info table for '%s' property\n",
- pname);
+ if (!info)
return -ENOMEM;
- }
+
abb->info = info;
volt_table = devm_kzalloc(dev, sizeof(unsigned int) * num_entries,
GFP_KERNEL);
- if (!volt_table) {
- dev_err(dev, "Can't allocate voltage table for '%s' property\n",
- pname);
+ if (!volt_table)
return -ENOMEM;
- }
abb->rdesc.n_voltages = num_entries;
abb->rdesc.volt_table = volt_table;
/* We do not know where the OPP voltage is at the moment */
abb->current_info_idx = -EINVAL;
- abb_info = prop->value;
for (i = 0; i < num_entries; i++, info++, volt_table++) {
u32 efuse_offset, rbb_mask, fbb_mask, vset_mask;
u32 efuse_val;
/* NOTE: num_values should equal to entries picked up here */
- *volt_table = be32_to_cpup(abb_info++);
- info->opp_sel = be32_to_cpup(abb_info++);
- efuse_offset = be32_to_cpup(abb_info++);
- rbb_mask = be32_to_cpup(abb_info++);
- fbb_mask = be32_to_cpup(abb_info++);
- vset_mask = be32_to_cpup(abb_info++);
+ of_property_read_u32_index(dev->of_node, pname, i * num_values,
+ volt_table);
+ of_property_read_u32_index(dev->of_node, pname,
+ i * num_values + 1, &info->opp_sel);
+ of_property_read_u32_index(dev->of_node, pname,
+ i * num_values + 2, &efuse_offset);
+ of_property_read_u32_index(dev->of_node, pname,
+ i * num_values + 3, &rbb_mask);
+ of_property_read_u32_index(dev->of_node, pname,
+ i * num_values + 4, &fbb_mask);
+ of_property_read_u32_index(dev->of_node, pname,
+ i * num_values + 5, &vset_mask);
dev_dbg(dev,
"[%d]v=%d ABB=%d ef=0x%x rbb=0x%x fbb=0x%x vset=0x%x\n",
@@ -648,8 +639,8 @@ static struct regulator_ops ti_abb_reg_ops = {
/* Default ABB block offsets, IF this changes in future, create new one */
static const struct ti_abb_reg abb_regs_v1 = {
/* WARNING: registers are wrongly documented in TRM */
- .setup_reg = 0x04,
- .control_reg = 0x00,
+ .setup_off = 0x04,
+ .control_off = 0x00,
.sr2_wtcnt_value_mask = (0xff << 8),
.fbb_sel_mask = (0x01 << 2),
@@ -661,8 +652,8 @@ static const struct ti_abb_reg abb_regs_v1 = {
};
static const struct ti_abb_reg abb_regs_v2 = {
- .setup_reg = 0x00,
- .control_reg = 0x04,
+ .setup_off = 0x00,
+ .control_off = 0x04,
.sr2_wtcnt_value_mask = (0xff << 8),
.fbb_sel_mask = (0x01 << 2),
@@ -673,9 +664,20 @@ static const struct ti_abb_reg abb_regs_v2 = {
.opp_sel_mask = (0x03 << 0),
};
+static const struct ti_abb_reg abb_regs_generic = {
+ .sr2_wtcnt_value_mask = (0xff << 8),
+ .fbb_sel_mask = (0x01 << 2),
+ .rbb_sel_mask = (0x01 << 1),
+ .sr2_en_mask = (0x01 << 0),
+
+ .opp_change_mask = (0x01 << 2),
+ .opp_sel_mask = (0x03 << 0),
+};
+
static const struct of_device_id ti_abb_of_match[] = {
{.compatible = "ti,abb-v1", .data = &abb_regs_v1},
{.compatible = "ti,abb-v2", .data = &abb_regs_v2},
+ {.compatible = "ti,abb-v3", .data = &abb_regs_generic},
{ },
};
@@ -722,11 +724,29 @@ static int ti_abb_probe(struct platform_device *pdev)
abb->regs = match->data;
/* Map ABB resources */
- pname = "base-address";
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
- abb->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(abb->base))
- return PTR_ERR(abb->base);
+ if (abb->regs->setup_off || abb->regs->control_off) {
+ pname = "base-address";
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+ abb->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(abb->base))
+ return PTR_ERR(abb->base);
+
+ abb->setup_reg = abb->base + abb->regs->setup_off;
+ abb->control_reg = abb->base + abb->regs->control_off;
+
+ } else {
+ pname = "control-address";
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+ abb->control_reg = devm_ioremap_resource(dev, res);
+ if (IS_ERR(abb->control_reg))
+ return PTR_ERR(abb->control_reg);
+
+ pname = "setup-address";
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+ abb->setup_reg = devm_ioremap_resource(dev, res);
+ if (IS_ERR(abb->setup_reg))
+ return PTR_ERR(abb->setup_reg);
+ }
pname = "int-address";
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
@@ -860,7 +880,7 @@ skip_opt:
platform_set_drvdata(pdev, rdev);
/* Enable the ldo if not already done by bootloader */
- ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->regs->setup_reg, abb->base);
+ ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->setup_reg);
return 0;
}
diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c
index b3764f594ee9..f31f22e3e1bd 100644
--- a/drivers/regulator/tps51632-regulator.c
+++ b/drivers/regulator/tps51632-regulator.c
@@ -227,10 +227,8 @@ static struct tps51632_regulator_platform_data *
struct device_node *np = dev->of_node;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(dev, "Memory alloc failed for platform data\n");
+ if (!pdata)
return NULL;
- }
pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
if (!pdata->reg_init_data) {
@@ -299,10 +297,8 @@ static int tps51632_probe(struct i2c_client *client,
}
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
- if (!tps) {
- dev_err(&client->dev, "Memory allocation failed\n");
+ if (!tps)
return -ENOMEM;
- }
tps->dev = &client->dev;
tps->desc.name = client->name;
diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c
index c3fa15a299b1..a1672044e519 100644
--- a/drivers/regulator/tps62360-regulator.c
+++ b/drivers/regulator/tps62360-regulator.c
@@ -299,10 +299,8 @@ static struct tps62360_regulator_platform_data *
struct device_node *np = dev->of_node;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(dev, "Memory alloc failed for platform data\n");
+ if (!pdata)
return NULL;
- }
pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
if (!pdata->reg_init_data) {
@@ -377,11 +375,8 @@ static int tps62360_probe(struct i2c_client *client,
}
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
- if (!tps) {
- dev_err(&client->dev, "%s(): Memory allocation failed\n",
- __func__);
+ if (!tps)
return -ENOMEM;
- }
tps->en_discharge = pdata->en_discharge;
tps->en_internal_pulldn = pdata->en_internal_pulldn;
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index 162a0fae20b3..98e66ce26723 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -359,7 +359,6 @@ static struct regulator_ops tps6507x_pmic_ops = {
.map_voltage = regulator_map_voltage_ascend,
};
-#ifdef CONFIG_OF
static struct of_regulator_match tps6507x_matches[] = {
{ .name = "VDCDC1"},
{ .name = "VDCDC2"},
@@ -381,12 +380,10 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
tps_board = devm_kzalloc(&pdev->dev, sizeof(*tps_board),
GFP_KERNEL);
- if (!tps_board) {
- dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n");
+ if (!tps_board)
return NULL;
- }
- regulators = of_find_node_by_name(np, "regulators");
+ regulators = of_get_child_by_name(np, "regulators");
if (!regulators) {
dev_err(&pdev->dev, "regulator node not found\n");
return NULL;
@@ -396,6 +393,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
matches = tps6507x_matches;
ret = of_regulator_match(&pdev->dev, regulators, matches, count);
+ of_node_put(regulators);
if (ret < 0) {
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
ret);
@@ -406,10 +404,8 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data)
* TPS6507X_NUM_REGULATOR), GFP_KERNEL);
- if (!reg_data) {
- dev_err(&pdev->dev, "Failure to alloc init data for regulators.\n");
+ if (!reg_data)
return NULL;
- }
tps_board->tps6507x_pmic_init_data = reg_data;
@@ -424,15 +420,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(
return tps_board;
}
-#else
-static inline struct tps6507x_board *tps6507x_parse_dt_reg_data(
- struct platform_device *pdev,
- struct of_regulator_match **tps6507x_reg_matches)
-{
- *tps6507x_reg_matches = NULL;
- return NULL;
-}
-#endif
+
static int tps6507x_pmic_probe(struct platform_device *pdev)
{
struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
@@ -453,9 +441,10 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
*/
tps_board = dev_get_platdata(tps6507x_dev->dev);
- if (!tps_board && tps6507x_dev->dev->of_node)
+ if (IS_ENABLED(CONFIG_OF) && !tps_board &&
+ tps6507x_dev->dev->of_node)
tps_board = tps6507x_parse_dt_reg_data(pdev,
- &tps6507x_reg_matches);
+ &tps6507x_reg_matches);
if (!tps_board)
return -EINVAL;
@@ -481,7 +470,7 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
tps->info[i] = info;
if (init_data->driver_data) {
struct tps6507x_reg_platform_data *data =
- init_data->driver_data;
+ init_data->driver_data;
tps->info[i]->defdcdc_default = data->defdcdc_default;
}
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c
index 676f75548f00..2e92ef68574d 100644
--- a/drivers/regulator/tps65090-regulator.c
+++ b/drivers/regulator/tps65090-regulator.c
@@ -168,17 +168,13 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata),
GFP_KERNEL);
- if (!tps65090_pdata) {
- dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n");
+ if (!tps65090_pdata)
return ERR_PTR(-ENOMEM);
- }
reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX *
sizeof(*reg_pdata), GFP_KERNEL);
- if (!reg_pdata) {
- dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n");
+ if (!reg_pdata)
return ERR_PTR(-ENOMEM);
- }
regulators = of_get_child_by_name(np, "regulators");
if (!regulators) {
@@ -188,6 +184,7 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches,
ARRAY_SIZE(tps65090_matches));
+ of_node_put(regulators);
if (ret < 0) {
dev_err(&pdev->dev,
"Error parsing regulator init data: %d\n", ret);
@@ -252,10 +249,8 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),
GFP_KERNEL);
- if (!pmic) {
- dev_err(&pdev->dev, "mem alloc for pmic failed\n");
+ if (!pmic)
return -ENOMEM;
- }
for (num = 0; num < TPS65090_REGULATOR_MAX; num++) {
tps_pdata = tps65090_pdata->reg_pdata[num];
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c
index 9ea1bf26bd13..10b78d2b766a 100644
--- a/drivers/regulator/tps65217-regulator.c
+++ b/drivers/regulator/tps65217-regulator.c
@@ -187,7 +187,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
struct device_node *regs;
int i, count;
- regs = of_find_node_by_name(node, "regulators");
+ regs = of_get_child_by_name(node, "regulators");
if (!regs)
return NULL;
@@ -202,7 +202,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
return NULL;
for (i = 0; i < count; i++) {
- if (!reg_matches[i].init_data || !reg_matches[i].of_node)
+ if (!reg_matches[i].of_node)
continue;
pdata->tps65217_init_data[i] = reg_matches[i].init_data;
@@ -222,7 +222,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
{
struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
struct tps65217_board *pdata = dev_get_platdata(tps->dev);
- struct regulator_init_data *reg_data;
struct regulator_dev *rdev;
struct regulator_config config = { };
int i;
@@ -243,19 +242,9 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, tps);
for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
-
- reg_data = pdata->tps65217_init_data[i];
-
- /*
- * Regulator API handles empty constraints but not NULL
- * constraints
- */
- if (!reg_data)
- continue;
-
/* Register the regulators */
config.dev = tps->dev;
- config.init_data = reg_data;
+ config.init_data = pdata->tps65217_init_data[i];
config.driver_data = tps;
config.regmap = tps->regmap;
if (tps->dev->of_node)
diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c
new file mode 100644
index 000000000000..cec72fa71d1d
--- /dev/null
+++ b/drivers/regulator/tps65218-regulator.c
@@ -0,0 +1,285 @@
+/*
+ * tps65218-regulator.c
+ *
+ * Regulator driver for TPS65218 PMIC
+ *
+ * Copyright (C) 2014 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether expressed or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License version 2 for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/tps65218.h>
+
+static unsigned int tps65218_ramp_delay = 4000;
+
+enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1 };
+
+#define TPS65218_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _er, _em, _t, \
+ _lr, _nlr) \
+ { \
+ .name = _name, \
+ .id = _id, \
+ .ops = &_ops, \
+ .n_voltages = _n, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = _vr, \
+ .vsel_mask = _vm, \
+ .enable_reg = _er, \
+ .enable_mask = _em, \
+ .volt_table = _t, \
+ .linear_ranges = _lr, \
+ .n_linear_ranges = _nlr, \
+ } \
+
+#define TPS65218_INFO(_id, _nm, _min, _max) \
+ { \
+ .id = _id, \
+ .name = _nm, \
+ .min_uV = _min, \
+ .max_uV = _max, \
+ }
+
+static const struct regulator_linear_range dcdc1_dcdc2_ranges[] = {
+ REGULATOR_LINEAR_RANGE(850000, 0x0, 0x32, 10000),
+ REGULATOR_LINEAR_RANGE(1375000, 0x33, 0x3f, 25000),
+};
+
+static const struct regulator_linear_range ldo1_dcdc3_ranges[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0x0, 0x1a, 25000),
+ REGULATOR_LINEAR_RANGE(1600000, 0x1b, 0x3f, 50000),
+};
+
+static const struct regulator_linear_range dcdc4_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1175000, 0x0, 0xf, 25000),
+ REGULATOR_LINEAR_RANGE(1550000, 0x10, 0x34, 50000),
+};
+
+static struct tps_info tps65218_pmic_regs[] = {
+ TPS65218_INFO(0, "DCDC1", 850000, 167500),
+ TPS65218_INFO(1, "DCDC2", 850000, 1675000),
+ TPS65218_INFO(2, "DCDC3", 900000, 3400000),
+ TPS65218_INFO(3, "DCDC4", 1175000, 3400000),
+ TPS65218_INFO(4, "DCDC5", 1000000, 1000000),
+ TPS65218_INFO(5, "DCDC6", 1800000, 1800000),
+ TPS65218_INFO(6, "LDO1", 900000, 3400000),
+};
+
+#define TPS65218_OF_MATCH(comp, label) \
+ { \
+ .compatible = comp, \
+ .data = &label, \
+ }
+
+static const struct of_device_id tps65218_of_match[] = {
+ TPS65218_OF_MATCH("ti,tps65218-dcdc1", tps65218_pmic_regs[DCDC1]),
+ TPS65218_OF_MATCH("ti,tps65218-dcdc2", tps65218_pmic_regs[DCDC2]),
+ TPS65218_OF_MATCH("ti,tps65218-dcdc3", tps65218_pmic_regs[DCDC3]),
+ TPS65218_OF_MATCH("ti,tps65218-dcdc4", tps65218_pmic_regs[DCDC4]),
+ TPS65218_OF_MATCH("ti,tps65218-dcdc5", tps65218_pmic_regs[DCDC5]),
+ TPS65218_OF_MATCH("ti,tps65218-dcdc6", tps65218_pmic_regs[DCDC6]),
+ TPS65218_OF_MATCH("ti,tps65218-ldo1", tps65218_pmic_regs[LDO1]),
+ { }
+};
+MODULE_DEVICE_TABLE(of, tps65218_of_match);
+
+static int tps65218_pmic_set_voltage_sel(struct regulator_dev *dev,
+ unsigned selector)
+{
+ int ret;
+ struct tps65218 *tps = rdev_get_drvdata(dev);
+ unsigned int rid = rdev_get_id(dev);
+
+ /* Set the voltage based on vsel value and write protect level is 2 */
+ ret = tps65218_set_bits(tps, dev->desc->vsel_reg, dev->desc->vsel_mask,
+ selector, TPS65218_PROTECT_L1);
+
+ /* Set GO bit for DCDC1/2 to initiate voltage transistion */
+ switch (rid) {
+ case TPS65218_DCDC_1:
+ case TPS65218_DCDC_2:
+ ret = tps65218_set_bits(tps, TPS65218_REG_CONTRL_SLEW_RATE,
+ TPS65218_SLEW_RATE_GO,
+ TPS65218_SLEW_RATE_GO,
+ TPS65218_PROTECT_L1);
+ break;
+ }
+
+ return ret;
+}
+
+static int tps65218_pmic_enable(struct regulator_dev *dev)
+{
+ struct tps65218 *tps = rdev_get_drvdata(dev);
+ unsigned int rid = rdev_get_id(dev);
+
+ if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1)
+ return -EINVAL;
+
+ /* Enable the regulator and password protection is level 1 */
+ return tps65218_set_bits(tps, dev->desc->enable_reg,
+ dev->desc->enable_mask, dev->desc->enable_mask,
+ TPS65218_PROTECT_L1);
+}
+
+static int tps65218_pmic_disable(struct regulator_dev *dev)
+{
+ struct tps65218 *tps = rdev_get_drvdata(dev);
+ unsigned int rid = rdev_get_id(dev);
+
+ if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1)
+ return -EINVAL;
+
+ /* Disable the regulator and password protection is level 1 */
+ return tps65218_clear_bits(tps, dev->desc->enable_reg,
+ dev->desc->enable_mask, TPS65218_PROTECT_L1);
+}
+
+static int tps65218_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector, unsigned int new_selector)
+{
+ int old_uv, new_uv;
+
+ old_uv = regulator_list_voltage_linear_range(rdev, old_selector);
+ if (old_uv < 0)
+ return old_uv;
+
+ new_uv = regulator_list_voltage_linear_range(rdev, new_selector);
+ if (new_uv < 0)
+ return new_uv;
+
+ return DIV_ROUND_UP(abs(old_uv - new_uv), tps65218_ramp_delay);
+}
+
+/* Operations permitted on DCDC1, DCDC2 */
+static struct regulator_ops tps65218_dcdc12_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = tps65218_pmic_enable,
+ .disable = tps65218_pmic_disable,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = tps65218_pmic_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .set_voltage_time_sel = tps65218_set_voltage_time_sel,
+};
+
+/* Operations permitted on DCDC3, DCDC4 and LDO1 */
+static struct regulator_ops tps65218_ldo1_dcdc34_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = tps65218_pmic_enable,
+ .disable = tps65218_pmic_disable,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = tps65218_pmic_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+};
+
+/* Operations permitted on DCDC5, DCDC6 */
+static struct regulator_ops tps65218_dcdc56_pmic_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = tps65218_pmic_enable,
+ .disable = tps65218_pmic_disable,
+};
+
+static const struct regulator_desc regulators[] = {
+ TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, tps65218_dcdc12_ops, 64,
+ TPS65218_REG_CONTROL_DCDC1,
+ TPS65218_CONTROL_DCDC1_MASK,
+ TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC1_EN, NULL,
+ dcdc1_dcdc2_ranges, 2),
+ TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, tps65218_dcdc12_ops, 64,
+ TPS65218_REG_CONTROL_DCDC2,
+ TPS65218_CONTROL_DCDC2_MASK,
+ TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC2_EN, NULL,
+ dcdc1_dcdc2_ranges, 2),
+ TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, tps65218_ldo1_dcdc34_ops,
+ 64, TPS65218_REG_CONTROL_DCDC3,
+ TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1,
+ TPS65218_ENABLE1_DC3_EN, NULL,
+ ldo1_dcdc3_ranges, 2),
+ TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, tps65218_ldo1_dcdc34_ops,
+ 53, TPS65218_REG_CONTROL_DCDC4,
+ TPS65218_CONTROL_DCDC4_MASK,
+ TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC4_EN, NULL,
+ dcdc4_ranges, 2),
+ TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, tps65218_dcdc56_pmic_ops,
+ 1, -1, -1, TPS65218_REG_ENABLE1,
+ TPS65218_ENABLE1_DC5_EN, NULL, NULL, 0),
+ TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, tps65218_dcdc56_pmic_ops,
+ 1, -1, -1, TPS65218_REG_ENABLE1,
+ TPS65218_ENABLE1_DC6_EN, NULL, NULL, 0),
+ TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, tps65218_ldo1_dcdc34_ops, 64,
+ TPS65218_REG_CONTROL_DCDC4,
+ TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2,
+ TPS65218_ENABLE2_LDO1_EN, NULL, ldo1_dcdc3_ranges,
+ 2),
+};
+
+static int tps65218_regulator_probe(struct platform_device *pdev)
+{
+ struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_init_data *init_data;
+ const struct tps_info *template;
+ struct regulator_dev *rdev;
+ const struct of_device_id *match;
+ struct regulator_config config = { };
+ int id;
+
+ match = of_match_device(tps65218_of_match, &pdev->dev);
+ if (!match)
+ return -ENODEV;
+
+ template = match->data;
+ id = template->id;
+ init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
+
+ platform_set_drvdata(pdev, tps);
+
+ tps->info[id] = &tps65218_pmic_regs[id];
+ config.dev = &pdev->dev;
+ config.init_data = init_data;
+ config.driver_data = tps;
+ config.regmap = tps->regmap;
+
+ rdev = devm_regulator_register(&pdev->dev, &regulators[id], &config);
+ if (IS_ERR(rdev)) {
+ dev_err(tps->dev, "failed to register %s regulator\n",
+ pdev->name);
+ return PTR_ERR(rdev);
+ }
+
+ return 0;
+}
+
+static struct platform_driver tps65218_regulator_driver = {
+ .driver = {
+ .name = "tps65218-pmic",
+ .owner = THIS_MODULE,
+ .of_match_table = tps65218_of_match,
+ },
+ .probe = tps65218_regulator_probe,
+};
+
+module_platform_driver(tps65218_regulator_driver);
+
+MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
+MODULE_DESCRIPTION("TPS65218 voltage regulator driver");
+MODULE_ALIAS("platform:tps65218-pmic");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
index 9f6bfda711b7..5b494db9f95c 100644
--- a/drivers/regulator/tps6524x-regulator.c
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -593,10 +593,9 @@ static int pmic_probe(struct spi_device *spi)
}
hw = devm_kzalloc(&spi->dev, sizeof(struct tps6524x), GFP_KERNEL);
- if (!hw) {
- dev_err(dev, "cannot allocate regulator private data\n");
+ if (!hw)
return -ENOMEM;
- }
+
spi_set_drvdata(spi, hw);
memset(hw, 0, sizeof(struct tps6524x));
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index 0485d47f0d8a..32f38a63d944 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -363,10 +363,8 @@ static struct tps6586x_platform_data *tps6586x_parse_regulator_dt(
}
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(&pdev->dev, "Memory alloction failed\n");
+ if (!pdata)
return NULL;
- }
for (i = 0; i < num; i++) {
int id;
@@ -398,7 +396,7 @@ static int tps6586x_regulator_probe(struct platform_device *pdev)
{
struct tps6586x_regulator *ri = NULL;
struct regulator_config config = { };
- struct regulator_dev **rdev;
+ struct regulator_dev *rdev;
struct regulator_init_data *reg_data;
struct tps6586x_platform_data *pdata;
struct of_regulator_match *tps6586x_reg_matches = NULL;
@@ -418,13 +416,6 @@ static int tps6586x_regulator_probe(struct platform_device *pdev)
return -ENODEV;
}
- rdev = devm_kzalloc(&pdev->dev, TPS6586X_ID_MAX_REGULATOR *
- sizeof(*rdev), GFP_KERNEL);
- if (!rdev) {
- dev_err(&pdev->dev, "Mmemory alloc failed\n");
- return -ENOMEM;
- }
-
version = tps6586x_get_version(pdev->dev.parent);
for (id = 0; id < TPS6586X_ID_MAX_REGULATOR; ++id) {
@@ -451,12 +442,11 @@ static int tps6586x_regulator_probe(struct platform_device *pdev)
if (tps6586x_reg_matches)
config.of_node = tps6586x_reg_matches[id].of_node;
- rdev[id] = devm_regulator_register(&pdev->dev, &ri->desc,
- &config);
- if (IS_ERR(rdev[id])) {
+ rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);
+ if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
ri->desc.name);
- return PTR_ERR(rdev[id]);
+ return PTR_ERR(rdev);
}
if (reg_data) {
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index f50dd847eebc..fa7db8847578 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -1011,11 +1011,8 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
pmic_plat_data = devm_kzalloc(&pdev->dev, sizeof(*pmic_plat_data),
GFP_KERNEL);
-
- if (!pmic_plat_data) {
- dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n");
+ if (!pmic_plat_data)
return NULL;
- }
np = of_node_get(pdev->dev.parent->of_node);
regulators = of_get_child_by_name(np, "regulators");
@@ -1098,10 +1095,8 @@ static int tps65910_probe(struct platform_device *pdev)
}
pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
- if (!pmic) {
- dev_err(&pdev->dev, "Memory allocation failed for pmic\n");
+ if (!pmic)
return -ENOMEM;
- }
pmic->mfd = tps65910;
platform_set_drvdata(pdev, pmic);
@@ -1130,24 +1125,18 @@ static int tps65910_probe(struct platform_device *pdev)
pmic->desc = devm_kzalloc(&pdev->dev, pmic->num_regulators *
sizeof(struct regulator_desc), GFP_KERNEL);
- if (!pmic->desc) {
- dev_err(&pdev->dev, "Memory alloc fails for desc\n");
+ if (!pmic->desc)
return -ENOMEM;
- }
pmic->info = devm_kzalloc(&pdev->dev, pmic->num_regulators *
sizeof(struct tps_info *), GFP_KERNEL);
- if (!pmic->info) {
- dev_err(&pdev->dev, "Memory alloc fails for info\n");
+ if (!pmic->info)
return -ENOMEM;
- }
pmic->rdev = devm_kzalloc(&pdev->dev, pmic->num_regulators *
sizeof(struct regulator_dev *), GFP_KERNEL);
- if (!pmic->rdev) {
- dev_err(&pdev->dev, "Memory alloc fails for rdev\n");
+ if (!pmic->rdev)
return -ENOMEM;
- }
for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS;
i++, info++) {
diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c
index 71f457a42623..26aa6d9c308f 100644
--- a/drivers/regulator/tps80031-regulator.c
+++ b/drivers/regulator/tps80031-regulator.c
@@ -115,7 +115,7 @@ static int tps80031_reg_is_enabled(struct regulator_dev *rdev)
ri->rinfo->state_reg, ret);
return ret;
}
- return ((reg_val & TPS80031_STATE_MASK) == TPS80031_STATE_ON);
+ return (reg_val & TPS80031_STATE_MASK) == TPS80031_STATE_ON;
}
static int tps80031_reg_enable(struct regulator_dev *rdev)
@@ -693,10 +693,8 @@ static int tps80031_regulator_probe(struct platform_device *pdev)
pmic = devm_kzalloc(&pdev->dev,
TPS80031_REGULATOR_MAX * sizeof(*pmic), GFP_KERNEL);
- if (!pmic) {
- dev_err(&pdev->dev, "mem alloc for pmic failed\n");
+ if (!pmic)
return -ENOMEM;
- }
for (num = 0; num < TPS80031_REGULATOR_MAX; ++num) {
tps_pdata = pdata->regulator_pdata[num];
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index 04cf9c16ef23..0d88a82ab2a2 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -469,10 +469,8 @@ static int wm831x_buckv_probe(struct platform_device *pdev)
dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc),
GFP_KERNEL);
- if (dcdc == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!dcdc)
return -ENOMEM;
- }
dcdc->wm831x = wm831x;
@@ -622,10 +620,8 @@ static int wm831x_buckp_probe(struct platform_device *pdev)
dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc),
GFP_KERNEL);
- if (dcdc == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!dcdc)
return -ENOMEM;
- }
dcdc->wm831x = wm831x;
@@ -752,10 +748,8 @@ static int wm831x_boostp_probe(struct platform_device *pdev)
return -ENODEV;
dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL);
- if (dcdc == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!dcdc)
return -ENOMEM;
- }
dcdc->wm831x = wm831x;
@@ -842,10 +836,8 @@ static int wm831x_epe_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing EPE%d\n", id + 1);
dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL);
- if (dcdc == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!dcdc)
return -ENOMEM;
- }
dcdc->wm831x = wm831x;
diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c
index 0339b886df5d..72e385e76a9d 100644
--- a/drivers/regulator/wm831x-isink.c
+++ b/drivers/regulator/wm831x-isink.c
@@ -165,10 +165,8 @@ static int wm831x_isink_probe(struct platform_device *pdev)
isink = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_isink),
GFP_KERNEL);
- if (isink == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!isink)
return -ENOMEM;
- }
isink->wm831x = wm831x;
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index 46d6700467b5..eca0eeb78acd 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -235,10 +235,8 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
- if (ldo == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!ldo)
return -ENOMEM;
- }
ldo->wm831x = wm831x;
@@ -447,10 +445,8 @@ static int wm831x_aldo_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
- if (ldo == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!ldo)
return -ENOMEM;
- }
ldo->wm831x = wm831x;
@@ -594,10 +590,8 @@ static int wm831x_alive_ldo_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
- if (ldo == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!ldo)
return -ENOMEM;
- }
ldo->wm831x = wm831x;
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index de7b9c73e3fa..7ec7c390eeda 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -361,7 +361,7 @@ static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
sel = regulator_map_voltage_linear(rdev, uV, uV);
if (sel < 0)
- return -EINVAL;
+ return sel;
/* all DCDCs have same mV bits */
val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
@@ -574,7 +574,7 @@ static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
sel = regulator_map_voltage_linear_range(rdev, uV, uV);
if (sel < 0)
- return -EINVAL;
+ return sel;
/* all LDOs have same mV bits */
val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index 71c5911f2e71..c24346db8a71 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -134,10 +134,8 @@ static int wm8994_ldo_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_ldo), GFP_KERNEL);
- if (ldo == NULL) {
- dev_err(&pdev->dev, "Unable to allocate private data\n");
+ if (!ldo)
return -ENOMEM;
- }
ldo->wm8994 = wm8994;
ldo->supply = wm8994_ldo_consumer[id];
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 7afd373b9595..c4cde9c08f1f 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -580,10 +580,12 @@ static int s3c_rtc_suspend(struct device *dev)
clk_enable(rtc_clk);
/* save TICNT for anyone using periodic interrupts */
- ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON);
ticnt_en_save &= S3C64XX_RTCCON_TICEN;
+ ticnt_save = readl(s3c_rtc_base + S3C2410_TICNT);
+ } else {
+ ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
}
s3c_rtc_enable(pdev, 0);
@@ -605,10 +607,15 @@ static int s3c_rtc_resume(struct device *dev)
clk_enable(rtc_clk);
s3c_rtc_enable(pdev, 1);
- writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
- if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
- tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
- writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
+ if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+ writel(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
+ if (ticnt_en_save) {
+ tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
+ writew(tmp | ticnt_en_save,
+ s3c_rtc_base + S3C2410_RTCCON);
+ }
+ } else {
+ writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
}
if (device_may_wakeup(dev) && wake_en) {
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index ebf41e228e55..ee0e85abe1fd 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -304,12 +304,6 @@ dcssblk_load_segment(char *name, struct segment_info **seg_info)
return rc;
}
-static void dcssblk_unregister_callback(struct device *dev)
-{
- device_unregister(dev);
- put_device(dev);
-}
-
/*
* device attribute for switching shared/nonshared (exclusive)
* operation (show + store)
@@ -397,7 +391,13 @@ removeseg:
blk_cleanup_queue(dev_info->dcssblk_queue);
dev_info->gd->queue = NULL;
put_disk(dev_info->gd);
- rc = device_schedule_callback(dev, dcssblk_unregister_callback);
+ up_write(&dcssblk_devices_sem);
+
+ if (device_remove_file_self(dev, attr)) {
+ device_unregister(dev);
+ put_device(dev);
+ }
+ return rc;
out:
up_write(&dcssblk_devices_sem);
return rc;
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index eb5d22795c47..5af7f0bd6125 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -922,7 +922,7 @@ static int __init con3215_init(void)
raw3215_freelist = req;
}
- cdev = ccw_device_probe_console();
+ cdev = ccw_device_create_console(&raw3215_ccw_driver);
if (IS_ERR(cdev))
return -ENODEV;
@@ -932,6 +932,12 @@ static int __init con3215_init(void)
cdev->handler = raw3215_irq;
raw->flags |= RAW3215_FIXED;
+ if (ccw_device_enable_console(cdev)) {
+ ccw_device_destroy_console(cdev);
+ raw3215_free_info(raw);
+ raw3215[0] = NULL;
+ return -ENODEV;
+ }
/* Request the console irq */
if (raw3215_startup(raw) != 0) {
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 699fd3e363df..75ffe9980c3e 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -7,6 +7,7 @@
* Copyright IBM Corp. 2003, 2009
*/
+#include <linux/module.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -30,6 +31,9 @@
static struct raw3270_fn con3270_fn;
+static bool auto_update = 1;
+module_param(auto_update, bool, 0);
+
/*
* Main 3270 console view data structure.
*/
@@ -204,6 +208,8 @@ con3270_update(struct con3270 *cp)
struct string *s, *n;
int rc;
+ if (!auto_update && !raw3270_view_active(&cp->view))
+ return;
if (cp->view.dev)
raw3270_activate_view(&cp->view);
@@ -529,6 +535,7 @@ con3270_flush(void)
if (!cp->view.dev)
return;
raw3270_pm_unfreeze(&cp->view);
+ raw3270_activate_view(&cp->view);
spin_lock_irqsave(&cp->view.lock, flags);
con3270_wait_write(cp);
cp->nr_up = 0;
@@ -576,7 +583,6 @@ static struct console con3270 = {
static int __init
con3270_init(void)
{
- struct ccw_device *cdev;
struct raw3270 *rp;
void *cbuf;
int i;
@@ -591,10 +597,7 @@ con3270_init(void)
cpcmd("TERM AUTOCR OFF", NULL, 0, NULL);
}
- cdev = ccw_device_probe_console();
- if (IS_ERR(cdev))
- return -ENODEV;
- rp = raw3270_setup_console(cdev);
+ rp = raw3270_setup_console();
if (IS_ERR(rp))
return PTR_ERR(rp);
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 2cdec21e8924..9f849df4381e 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -276,6 +276,15 @@ __raw3270_start(struct raw3270 *rp, struct raw3270_view *view,
}
int
+raw3270_view_active(struct raw3270_view *view)
+{
+ struct raw3270 *rp = view->dev;
+
+ return rp && rp->view == view &&
+ !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
+}
+
+int
raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
{
unsigned long flags;
@@ -776,22 +785,37 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
}
#ifdef CONFIG_TN3270_CONSOLE
+/* Tentative definition - see below for actual definition. */
+static struct ccw_driver raw3270_ccw_driver;
+
/*
* Setup 3270 device configured as console.
*/
-struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
+struct raw3270 __init *raw3270_setup_console(void)
{
+ struct ccw_device *cdev;
unsigned long flags;
struct raw3270 *rp;
char *ascebc;
int rc;
+ cdev = ccw_device_create_console(&raw3270_ccw_driver);
+ if (IS_ERR(cdev))
+ return ERR_CAST(cdev);
+
rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
ascebc = kzalloc(256, GFP_KERNEL);
rc = raw3270_setup_device(cdev, rp, ascebc);
if (rc)
return ERR_PTR(rc);
set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
+
+ rc = ccw_device_enable_console(cdev);
+ if (rc) {
+ ccw_device_destroy_console(cdev);
+ return ERR_PTR(rc);
+ }
+
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
do {
__raw3270_reset_device(rp);
diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h
index 7b73ff8c1bd7..e1e41c2861fb 100644
--- a/drivers/s390/char/raw3270.h
+++ b/drivers/s390/char/raw3270.h
@@ -173,6 +173,7 @@ int raw3270_start_locked(struct raw3270_view *, struct raw3270_request *);
int raw3270_start_irq(struct raw3270_view *, struct raw3270_request *);
int raw3270_reset(struct raw3270_view *);
struct raw3270_view *raw3270_view(struct raw3270_view *);
+int raw3270_view_active(struct raw3270_view *);
/* Reference count inliner for view structures. */
static inline void
@@ -190,7 +191,7 @@ raw3270_put_view(struct raw3270_view *view)
wake_up(&raw3270_wait_queue);
}
-struct raw3270 *raw3270_setup_console(struct ccw_device *cdev);
+struct raw3270 *raw3270_setup_console(void);
void raw3270_wait_cons_dev(struct raw3270 *);
/* Notifier for device addition/removal */
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index 82f2c389b4d1..14196ea0fdf3 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -20,7 +20,9 @@ struct read_info_sccb {
struct sccb_header header; /* 0-7 */
u16 rnmax; /* 8-9 */
u8 rnsize; /* 10 */
- u8 _reserved0[24 - 11]; /* 11-15 */
+ u8 _reserved0[16 - 11]; /* 11-15 */
+ u16 ncpurl; /* 16-17 */
+ u8 _reserved7[24 - 18]; /* 18-23 */
u8 loadparm[8]; /* 24-31 */
u8 _reserved1[48 - 32]; /* 32-47 */
u64 facilities; /* 48-55 */
@@ -32,13 +34,16 @@ struct read_info_sccb {
u8 _reserved4[100 - 92]; /* 92-99 */
u32 rnsize2; /* 100-103 */
u64 rnmax2; /* 104-111 */
- u8 _reserved5[4096 - 112]; /* 112-4095 */
+ u8 _reserved5[120 - 112]; /* 112-119 */
+ u16 hcpua; /* 120-121 */
+ u8 _reserved6[4096 - 122]; /* 122-4095 */
} __packed __aligned(PAGE_SIZE);
static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata;
static unsigned int sclp_con_has_vt220 __initdata;
static unsigned int sclp_con_has_linemode __initdata;
static unsigned long sclp_hsa_size;
+static unsigned int sclp_max_cpu;
static struct sclp_ipl_info sclp_ipl_info;
u64 sclp_facilities;
@@ -102,6 +107,15 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
sclp_rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
sclp_rzm <<= 20;
+ if (!sccb->hcpua) {
+ if (MACHINE_IS_VM)
+ sclp_max_cpu = 64;
+ else
+ sclp_max_cpu = sccb->ncpurl;
+ } else {
+ sclp_max_cpu = sccb->hcpua + 1;
+ }
+
/* Save IPL information */
sclp_ipl_info.is_valid = 1;
if (sccb->flags & 0x2)
@@ -129,6 +143,11 @@ unsigned long long sclp_get_rzm(void)
return sclp_rzm;
}
+unsigned int sclp_get_max_cpu(void)
+{
+ return sclp_max_cpu;
+}
+
/*
* This function will be called after sclp_facilities_detect(), which gets
* called from early.c code. The sclp_facilities_detect() function retrieves
@@ -184,9 +203,9 @@ static long __init sclp_hsa_size_init(struct sdias_sccb *sccb)
sccb_init_eq_size(sccb);
if (sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
return -EIO;
- if (sccb->evbuf.blk_cnt != 0)
- return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
- return 0;
+ if (sccb->evbuf.blk_cnt == 0)
+ return 0;
+ return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
}
static long __init sclp_hsa_copy_wait(struct sccb_header *sccb)
@@ -195,6 +214,8 @@ static long __init sclp_hsa_copy_wait(struct sccb_header *sccb)
sccb->length = PAGE_SIZE;
if (sclp_cmd_early(SCLP_CMDW_READ_EVENT_DATA, sccb))
return -EIO;
+ if (((struct sdias_sccb *) sccb)->evbuf.blk_cnt == 0)
+ return 0;
return (((struct sdias_sccb *) sccb)->evbuf.blk_cnt - 1) * PAGE_SIZE;
}
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index f055df0b167f..445564c790f6 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -186,55 +186,71 @@ void airq_iv_release(struct airq_iv *iv)
EXPORT_SYMBOL(airq_iv_release);
/**
- * airq_iv_alloc_bit - allocate an irq bit from an interrupt vector
+ * airq_iv_alloc - allocate irq bits from an interrupt vector
* @iv: pointer to an interrupt vector structure
+ * @num: number of consecutive irq bits to allocate
*
- * Returns the bit number of the allocated irq, or -1UL if no bit
- * is available or the AIRQ_IV_ALLOC flag has not been specified
+ * Returns the bit number of the first irq in the allocated block of irqs,
+ * or -1UL if no bit is available or the AIRQ_IV_ALLOC flag has not been
+ * specified
*/
-unsigned long airq_iv_alloc_bit(struct airq_iv *iv)
+unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num)
{
- unsigned long bit;
+ unsigned long bit, i;
- if (!iv->avail)
+ if (!iv->avail || num == 0)
return -1UL;
spin_lock(&iv->lock);
bit = find_first_bit_inv(iv->avail, iv->bits);
- if (bit < iv->bits) {
- clear_bit_inv(bit, iv->avail);
- if (bit >= iv->end)
- iv->end = bit + 1;
- } else
+ while (bit + num <= iv->bits) {
+ for (i = 1; i < num; i++)
+ if (!test_bit_inv(bit + i, iv->avail))
+ break;
+ if (i >= num) {
+ /* Found a suitable block of irqs */
+ for (i = 0; i < num; i++)
+ clear_bit_inv(bit + i, iv->avail);
+ if (bit + num >= iv->end)
+ iv->end = bit + num + 1;
+ break;
+ }
+ bit = find_next_bit_inv(iv->avail, iv->bits, bit + i + 1);
+ }
+ if (bit + num > iv->bits)
bit = -1UL;
spin_unlock(&iv->lock);
return bit;
}
-EXPORT_SYMBOL(airq_iv_alloc_bit);
+EXPORT_SYMBOL(airq_iv_alloc);
/**
- * airq_iv_free_bit - free an irq bit of an interrupt vector
+ * airq_iv_free - free irq bits of an interrupt vector
* @iv: pointer to interrupt vector structure
- * @bit: number of the irq bit to free
+ * @bit: number of the first irq bit to free
+ * @num: number of consecutive irq bits to free
*/
-void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit)
+void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num)
{
- if (!iv->avail)
+ unsigned long i;
+
+ if (!iv->avail || num == 0)
return;
spin_lock(&iv->lock);
- /* Clear (possibly left over) interrupt bit */
- clear_bit_inv(bit, iv->vector);
- /* Make the bit position available again */
- set_bit_inv(bit, iv->avail);
- if (bit == iv->end - 1) {
+ for (i = 0; i < num; i++) {
+ /* Clear (possibly left over) interrupt bit */
+ clear_bit_inv(bit + i, iv->vector);
+ /* Make the bit positions available again */
+ set_bit_inv(bit + i, iv->avail);
+ }
+ if (bit + num >= iv->end) {
/* Find new end of bit-field */
- while (--iv->end > 0)
- if (!test_bit_inv(iv->end - 1, iv->avail))
- break;
+ while (iv->end > 0 && !test_bit_inv(iv->end - 1, iv->avail))
+ iv->end--;
}
spin_unlock(&iv->lock);
}
-EXPORT_SYMBOL(airq_iv_free_bit);
+EXPORT_SYMBOL(airq_iv_free);
/**
* airq_iv_scan - scan interrupt vector for non-zero bits
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index fd3367a1dc7a..dfd7bc681c25 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -168,14 +168,12 @@ static ssize_t ccwgroup_online_show(struct device *dev,
* Provide an 'ungroup' attribute so the user can remove group devices no
* longer needed or accidentially created. Saves memory :)
*/
-static void ccwgroup_ungroup_callback(struct device *dev)
+static void ccwgroup_ungroup(struct ccwgroup_device *gdev)
{
- struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
-
mutex_lock(&gdev->reg_mutex);
if (device_is_registered(&gdev->dev)) {
__ccwgroup_remove_symlinks(gdev);
- device_unregister(dev);
+ device_unregister(&gdev->dev);
__ccwgroup_remove_cdev_refs(gdev);
}
mutex_unlock(&gdev->reg_mutex);
@@ -195,10 +193,9 @@ static ssize_t ccwgroup_ungroup_store(struct device *dev,
rc = -EINVAL;
goto out;
}
- /* Note that we cannot unregister the device from one of its
- * attribute methods, so we have to use this roundabout approach.
- */
- rc = device_schedule_callback(dev, ccwgroup_ungroup_callback);
+
+ if (device_remove_file_self(dev, attr))
+ ccwgroup_ungroup(gdev);
out:
if (rc) {
if (rc != -EAGAIN)
@@ -224,6 +221,14 @@ static const struct attribute_group *ccwgroup_attr_groups[] = {
NULL,
};
+static void ccwgroup_ungroup_workfn(struct work_struct *work)
+{
+ struct ccwgroup_device *gdev =
+ container_of(work, struct ccwgroup_device, ungroup_work);
+
+ ccwgroup_ungroup(gdev);
+}
+
static void ccwgroup_release(struct device *dev)
{
kfree(to_ccwgroupdev(dev));
@@ -323,6 +328,7 @@ int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv,
atomic_set(&gdev->onoff, 0);
mutex_init(&gdev->reg_mutex);
mutex_lock(&gdev->reg_mutex);
+ INIT_WORK(&gdev->ungroup_work, ccwgroup_ungroup_workfn);
gdev->count = num_devices;
gdev->dev.bus = &ccwgroup_bus_type;
gdev->dev.parent = parent;
@@ -404,10 +410,10 @@ EXPORT_SYMBOL(ccwgroup_create_dev);
static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
void *data)
{
- struct device *dev = data;
+ struct ccwgroup_device *gdev = to_ccwgroupdev(data);
if (action == BUS_NOTIFY_UNBIND_DRIVER)
- device_schedule_callback(dev, ccwgroup_ungroup_callback);
+ schedule_work(&gdev->ungroup_work);
return NOTIFY_OK;
}
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index f6b9188c5af5..9f0ea6cb6922 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -610,6 +610,7 @@ void chsc_chp_online(struct chp_id chpid)
css_wait_for_slow_path();
for_each_subchannel_staged(__s390_process_res_acc, NULL,
&link);
+ css_schedule_reprobe();
}
}
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index 7b29d0be0ca3..1d3661af7bd8 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -173,8 +173,7 @@ static struct css_driver chsc_subchannel_driver = {
static int __init chsc_init_dbfs(void)
{
- chsc_debug_msg_id = debug_register("chsc_msg", 16, 1,
- 16 * sizeof(long));
+ chsc_debug_msg_id = debug_register("chsc_msg", 8, 1, 4 * sizeof(long));
if (!chsc_debug_msg_id)
goto out;
debug_register_view(chsc_debug_msg_id, &debug_sprintf_view);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 8ee88c4ebd83..9e058c4657a3 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -18,6 +18,7 @@
#include <linux/device.h>
#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <asm/cio.h>
#include <asm/delay.h>
#include <asm/irq.h>
@@ -28,7 +29,7 @@
#include <asm/chpid.h>
#include <asm/airq.h>
#include <asm/isc.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
#include <asm/fcx.h>
#include <asm/nmi.h>
#include <asm/crw.h>
@@ -54,7 +55,7 @@ debug_info_t *cio_debug_crw_id;
*/
static int __init cio_debug_init(void)
{
- cio_debug_msg_id = debug_register("cio_msg", 16, 1, 16 * sizeof(long));
+ cio_debug_msg_id = debug_register("cio_msg", 16, 1, 11 * sizeof(long));
if (!cio_debug_msg_id)
goto out_unregister;
debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
@@ -64,7 +65,7 @@ static int __init cio_debug_init(void)
goto out_unregister;
debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
debug_set_level(cio_debug_trace_id, 2);
- cio_debug_crw_id = debug_register("cio_crw", 16, 1, 16 * sizeof(long));
+ cio_debug_crw_id = debug_register("cio_crw", 8, 1, 8 * sizeof(long));
if (!cio_debug_crw_id)
goto out_unregister;
debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
@@ -584,8 +585,6 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy)
return IRQ_HANDLED;
}
-static struct irq_desc *irq_desc_io;
-
static struct irqaction io_interrupt = {
.name = "IO",
.handler = do_cio_interrupt,
@@ -596,7 +595,6 @@ void __init init_cio_interrupts(void)
irq_set_chip_and_handler(IO_INTERRUPT,
&dummy_irq_chip, handle_percpu_irq);
setup_irq(IO_INTERRUPT, &io_interrupt);
- irq_desc_io = irq_to_desc(IO_INTERRUPT);
}
#ifdef CONFIG_CCW_CONSOLE
@@ -623,7 +621,7 @@ void cio_tsch(struct subchannel *sch)
local_bh_disable();
irq_enter();
}
- kstat_incr_irqs_this_cpu(IO_INTERRUPT, irq_desc_io);
+ kstat_incr_irq_this_cpu(IO_INTERRUPT);
if (sch->driver && sch->driver->irq)
sch->driver->irq(sch);
else
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e9d783563cbb..d8d9b5b5cc56 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1571,12 +1571,27 @@ out:
return rc;
}
+static void ccw_device_set_int_class(struct ccw_device *cdev)
+{
+ struct ccw_driver *cdrv = cdev->drv;
+
+ /* Note: we interpret class 0 in this context as an uninitialized
+ * field since it translates to a non-I/O interrupt class. */
+ if (cdrv->int_class != 0)
+ cdev->private->int_class = cdrv->int_class;
+ else
+ cdev->private->int_class = IRQIO_CIO;
+}
+
#ifdef CONFIG_CCW_CONSOLE
-static int ccw_device_console_enable(struct ccw_device *cdev,
- struct subchannel *sch)
+int __init ccw_device_enable_console(struct ccw_device *cdev)
{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
int rc;
+ if (!cdev->drv || !cdev->handler)
+ return -EINVAL;
+
io_subchannel_init_fields(sch);
rc = cio_commit_config(sch);
if (rc)
@@ -1609,12 +1624,11 @@ out_unlock:
return rc;
}
-struct ccw_device *ccw_device_probe_console(void)
+struct ccw_device * __init ccw_device_create_console(struct ccw_driver *drv)
{
struct io_subchannel_private *io_priv;
struct ccw_device *cdev;
struct subchannel *sch;
- int ret;
sch = cio_probe_console();
if (IS_ERR(sch))
@@ -1631,18 +1645,23 @@ struct ccw_device *ccw_device_probe_console(void)
kfree(io_priv);
return cdev;
}
+ cdev->drv = drv;
set_io_private(sch, io_priv);
- ret = ccw_device_console_enable(cdev, sch);
- if (ret) {
- set_io_private(sch, NULL);
- put_device(&sch->dev);
- put_device(&cdev->dev);
- kfree(io_priv);
- return ERR_PTR(ret);
- }
+ ccw_device_set_int_class(cdev);
return cdev;
}
+void __init ccw_device_destroy_console(struct ccw_device *cdev)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+ struct io_subchannel_private *io_priv = to_io_private(sch);
+
+ set_io_private(sch, NULL);
+ put_device(&sch->dev);
+ put_device(&cdev->dev);
+ kfree(io_priv);
+}
+
/**
* ccw_device_wait_idle() - busy wait for device to become idle
* @cdev: ccw device
@@ -1726,15 +1745,8 @@ ccw_device_probe (struct device *dev)
int ret;
cdev->drv = cdrv; /* to let the driver call _set_online */
- /* Note: we interpret class 0 in this context as an uninitialized
- * field since it translates to a non-I/O interrupt class. */
- if (cdrv->int_class != 0)
- cdev->private->int_class = cdrv->int_class;
- else
- cdev->private->int_class = IRQIO_CIO;
-
+ ccw_device_set_int_class(cdev);
ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV;
-
if (ret) {
cdev->drv = NULL;
cdev->private->int_class = IRQIO_CIO;
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index dc542e0a3055..0bc91e46395a 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -311,7 +311,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
} __packed * msg = ap_msg->message;
int rcblen = CEIL4(xcRB->request_control_blk_length);
- int replylen;
+ int replylen, req_sumlen, resp_sumlen;
char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
char *function_code;
@@ -321,12 +321,34 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
xcRB->request_data_length;
if (ap_msg->length > MSGTYPE06_MAX_MSG_SIZE)
return -EINVAL;
+
+ /* Overflow check
+ sum must be greater (or equal) than the largest operand */
+ req_sumlen = CEIL4(xcRB->request_control_blk_length) +
+ xcRB->request_data_length;
+ if ((CEIL4(xcRB->request_control_blk_length) <=
+ xcRB->request_data_length) ?
+ (req_sumlen < xcRB->request_data_length) :
+ (req_sumlen < CEIL4(xcRB->request_control_blk_length))) {
+ return -EINVAL;
+ }
+
replylen = sizeof(struct type86_fmt2_msg) +
CEIL4(xcRB->reply_control_blk_length) +
xcRB->reply_data_length;
if (replylen > MSGTYPE06_MAX_MSG_SIZE)
return -EINVAL;
+ /* Overflow check
+ sum must be greater (or equal) than the largest operand */
+ resp_sumlen = CEIL4(xcRB->reply_control_blk_length) +
+ xcRB->reply_data_length;
+ if ((CEIL4(xcRB->reply_control_blk_length) <= xcRB->reply_data_length) ?
+ (resp_sumlen < xcRB->reply_data_length) :
+ (resp_sumlen < CEIL4(xcRB->reply_control_blk_length))) {
+ return -EINVAL;
+ }
+
/* prepare type6 header */
msg->hdr = static_type6_hdrX;
memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID));
diff --git a/drivers/s390/kvm/virtio_ccw.c b/drivers/s390/kvm/virtio_ccw.c
index 0fc584832001..1e1fc671f89a 100644
--- a/drivers/s390/kvm/virtio_ccw.c
+++ b/drivers/s390/kvm/virtio_ccw.c
@@ -1,7 +1,7 @@
/*
* ccw based virtio transport
*
- * Copyright IBM Corp. 2012
+ * Copyright IBM Corp. 2012, 2014
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
@@ -32,6 +32,8 @@
#include <asm/cio.h>
#include <asm/ccwdev.h>
#include <asm/virtio-ccw.h>
+#include <asm/isc.h>
+#include <asm/airq.h>
/*
* virtio related functions
@@ -58,6 +60,9 @@ struct virtio_ccw_device {
unsigned long indicators;
unsigned long indicators2;
struct vq_config_block *config_block;
+ bool is_thinint;
+ bool going_away;
+ void *airq_info;
};
struct vq_info_block {
@@ -72,15 +77,38 @@ struct virtio_feature_desc {
__u8 index;
} __packed;
+struct virtio_thinint_area {
+ unsigned long summary_indicator;
+ unsigned long indicator;
+ u64 bit_nr;
+ u8 isc;
+} __packed;
+
struct virtio_ccw_vq_info {
struct virtqueue *vq;
int num;
void *queue;
struct vq_info_block *info_block;
+ int bit_nr;
struct list_head node;
long cookie;
};
+#define VIRTIO_AIRQ_ISC IO_SCH_ISC /* inherit from subchannel */
+
+#define VIRTIO_IV_BITS (L1_CACHE_BYTES * 8)
+#define MAX_AIRQ_AREAS 20
+
+static int virtio_ccw_use_airq = 1;
+
+struct airq_info {
+ rwlock_t lock;
+ u8 summary_indicator;
+ struct airq_struct airq;
+ struct airq_iv *aiv;
+};
+static struct airq_info *airq_areas[MAX_AIRQ_AREAS];
+
#define CCW_CMD_SET_VQ 0x13
#define CCW_CMD_VDEV_RESET 0x33
#define CCW_CMD_SET_IND 0x43
@@ -91,6 +119,7 @@ struct virtio_ccw_vq_info {
#define CCW_CMD_WRITE_CONF 0x21
#define CCW_CMD_WRITE_STATUS 0x31
#define CCW_CMD_READ_VQ_CONF 0x32
+#define CCW_CMD_SET_IND_ADAPTER 0x73
#define VIRTIO_CCW_DOING_SET_VQ 0x00010000
#define VIRTIO_CCW_DOING_RESET 0x00040000
@@ -102,6 +131,7 @@ struct virtio_ccw_vq_info {
#define VIRTIO_CCW_DOING_SET_IND 0x01000000
#define VIRTIO_CCW_DOING_READ_VQ_CONF 0x02000000
#define VIRTIO_CCW_DOING_SET_CONF_IND 0x04000000
+#define VIRTIO_CCW_DOING_SET_IND_ADAPTER 0x08000000
#define VIRTIO_CCW_INTPARM_MASK 0xffff0000
static struct virtio_ccw_device *to_vc_device(struct virtio_device *vdev)
@@ -109,6 +139,125 @@ static struct virtio_ccw_device *to_vc_device(struct virtio_device *vdev)
return container_of(vdev, struct virtio_ccw_device, vdev);
}
+static void drop_airq_indicator(struct virtqueue *vq, struct airq_info *info)
+{
+ unsigned long i, flags;
+
+ write_lock_irqsave(&info->lock, flags);
+ for (i = 0; i < airq_iv_end(info->aiv); i++) {
+ if (vq == (void *)airq_iv_get_ptr(info->aiv, i)) {
+ airq_iv_free_bit(info->aiv, i);
+ airq_iv_set_ptr(info->aiv, i, 0);
+ break;
+ }
+ }
+ write_unlock_irqrestore(&info->lock, flags);
+}
+
+static void virtio_airq_handler(struct airq_struct *airq)
+{
+ struct airq_info *info = container_of(airq, struct airq_info, airq);
+ unsigned long ai;
+
+ inc_irq_stat(IRQIO_VAI);
+ read_lock(&info->lock);
+ /* Walk through indicators field, summary indicator active. */
+ for (ai = 0;;) {
+ ai = airq_iv_scan(info->aiv, ai, airq_iv_end(info->aiv));
+ if (ai == -1UL)
+ break;
+ vring_interrupt(0, (void *)airq_iv_get_ptr(info->aiv, ai));
+ }
+ info->summary_indicator = 0;
+ smp_wmb();
+ /* Walk through indicators field, summary indicator not active. */
+ for (ai = 0;;) {
+ ai = airq_iv_scan(info->aiv, ai, airq_iv_end(info->aiv));
+ if (ai == -1UL)
+ break;
+ vring_interrupt(0, (void *)airq_iv_get_ptr(info->aiv, ai));
+ }
+ read_unlock(&info->lock);
+}
+
+static struct airq_info *new_airq_info(void)
+{
+ struct airq_info *info;
+ int rc;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return NULL;
+ rwlock_init(&info->lock);
+ info->aiv = airq_iv_create(VIRTIO_IV_BITS, AIRQ_IV_ALLOC | AIRQ_IV_PTR);
+ if (!info->aiv) {
+ kfree(info);
+ return NULL;
+ }
+ info->airq.handler = virtio_airq_handler;
+ info->airq.lsi_ptr = &info->summary_indicator;
+ info->airq.lsi_mask = 0xff;
+ info->airq.isc = VIRTIO_AIRQ_ISC;
+ rc = register_adapter_interrupt(&info->airq);
+ if (rc) {
+ airq_iv_release(info->aiv);
+ kfree(info);
+ return NULL;
+ }
+ return info;
+}
+
+static void destroy_airq_info(struct airq_info *info)
+{
+ if (!info)
+ return;
+
+ unregister_adapter_interrupt(&info->airq);
+ airq_iv_release(info->aiv);
+ kfree(info);
+}
+
+static unsigned long get_airq_indicator(struct virtqueue *vqs[], int nvqs,
+ u64 *first, void **airq_info)
+{
+ int i, j;
+ struct airq_info *info;
+ unsigned long indicator_addr = 0;
+ unsigned long bit, flags;
+
+ for (i = 0; i < MAX_AIRQ_AREAS && !indicator_addr; i++) {
+ if (!airq_areas[i])
+ airq_areas[i] = new_airq_info();
+ info = airq_areas[i];
+ if (!info)
+ return 0;
+ write_lock_irqsave(&info->lock, flags);
+ bit = airq_iv_alloc(info->aiv, nvqs);
+ if (bit == -1UL) {
+ /* Not enough vacancies. */
+ write_unlock_irqrestore(&info->lock, flags);
+ continue;
+ }
+ *first = bit;
+ *airq_info = info;
+ indicator_addr = (unsigned long)info->aiv->vector;
+ for (j = 0; j < nvqs; j++) {
+ airq_iv_set_ptr(info->aiv, bit + j,
+ (unsigned long)vqs[j]);
+ }
+ write_unlock_irqrestore(&info->lock, flags);
+ }
+ return indicator_addr;
+}
+
+static void virtio_ccw_drop_indicators(struct virtio_ccw_device *vcdev)
+{
+ struct virtio_ccw_vq_info *info;
+
+ list_for_each_entry(info, &vcdev->virtqueues, node)
+ drop_airq_indicator(info->vq, vcdev->airq_info);
+}
+
static int doing_io(struct virtio_ccw_device *vcdev, __u32 flag)
{
unsigned long flags;
@@ -145,6 +294,51 @@ static int ccw_io_helper(struct virtio_ccw_device *vcdev,
return ret ? ret : vcdev->err;
}
+static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
+ struct ccw1 *ccw)
+{
+ int ret;
+ unsigned long *indicatorp = NULL;
+ struct virtio_thinint_area *thinint_area = NULL;
+ struct airq_info *airq_info = vcdev->airq_info;
+
+ if (vcdev->is_thinint) {
+ thinint_area = kzalloc(sizeof(*thinint_area),
+ GFP_DMA | GFP_KERNEL);
+ if (!thinint_area)
+ return;
+ thinint_area->summary_indicator =
+ (unsigned long) &airq_info->summary_indicator;
+ thinint_area->isc = VIRTIO_AIRQ_ISC;
+ ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
+ ccw->count = sizeof(*thinint_area);
+ ccw->cda = (__u32)(unsigned long) thinint_area;
+ } else {
+ indicatorp = kmalloc(sizeof(&vcdev->indicators),
+ GFP_DMA | GFP_KERNEL);
+ if (!indicatorp)
+ return;
+ *indicatorp = 0;
+ ccw->cmd_code = CCW_CMD_SET_IND;
+ ccw->count = sizeof(vcdev->indicators);
+ ccw->cda = (__u32)(unsigned long) indicatorp;
+ }
+ /* Deregister indicators from host. */
+ vcdev->indicators = 0;
+ ccw->flags = 0;
+ ret = ccw_io_helper(vcdev, ccw,
+ vcdev->is_thinint ?
+ VIRTIO_CCW_DOING_SET_IND_ADAPTER :
+ VIRTIO_CCW_DOING_SET_IND);
+ if (ret && (ret != -ENODEV))
+ dev_info(&vcdev->cdev->dev,
+ "Failed to deregister indicators (%d)\n", ret);
+ else if (vcdev->is_thinint)
+ virtio_ccw_drop_indicators(vcdev);
+ kfree(indicatorp);
+ kfree(thinint_area);
+}
+
static inline long do_kvm_notify(struct subchannel_id schid,
unsigned long queue_index,
long cookie)
@@ -232,11 +426,13 @@ static void virtio_ccw_del_vqs(struct virtio_device *vdev)
{
struct virtqueue *vq, *n;
struct ccw1 *ccw;
+ struct virtio_ccw_device *vcdev = to_vc_device(vdev);
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
if (!ccw)
return;
+ virtio_ccw_drop_indicator(vcdev, ccw);
list_for_each_entry_safe(vq, n, &vdev->vqs, list)
virtio_ccw_del_vq(vq, ccw);
@@ -326,6 +522,54 @@ out_err:
return ERR_PTR(err);
}
+static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
+ struct virtqueue *vqs[], int nvqs,
+ struct ccw1 *ccw)
+{
+ int ret;
+ struct virtio_thinint_area *thinint_area = NULL;
+ struct airq_info *info;
+
+ thinint_area = kzalloc(sizeof(*thinint_area), GFP_DMA | GFP_KERNEL);
+ if (!thinint_area) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ /* Try to get an indicator. */
+ thinint_area->indicator = get_airq_indicator(vqs, nvqs,
+ &thinint_area->bit_nr,
+ &vcdev->airq_info);
+ if (!thinint_area->indicator) {
+ ret = -ENOSPC;
+ goto out;
+ }
+ info = vcdev->airq_info;
+ thinint_area->summary_indicator =
+ (unsigned long) &info->summary_indicator;
+ thinint_area->isc = VIRTIO_AIRQ_ISC;
+ ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
+ ccw->flags = CCW_FLAG_SLI;
+ ccw->count = sizeof(*thinint_area);
+ ccw->cda = (__u32)(unsigned long)thinint_area;
+ ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND_ADAPTER);
+ if (ret) {
+ if (ret == -EOPNOTSUPP) {
+ /*
+ * The host does not support adapter interrupts
+ * for virtio-ccw, stop trying.
+ */
+ virtio_ccw_use_airq = 0;
+ pr_info("Adapter interrupts unsupported on host\n");
+ } else
+ dev_warn(&vcdev->cdev->dev,
+ "enabling adapter interrupts = %d\n", ret);
+ virtio_ccw_drop_indicators(vcdev);
+ }
+out:
+ kfree(thinint_area);
+ return ret;
+}
+
static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
@@ -355,15 +599,23 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
if (!indicatorp)
goto out;
*indicatorp = (unsigned long) &vcdev->indicators;
- /* Register queue indicators with host. */
- vcdev->indicators = 0;
- ccw->cmd_code = CCW_CMD_SET_IND;
- ccw->flags = 0;
- ccw->count = sizeof(vcdev->indicators);
- ccw->cda = (__u32)(unsigned long) indicatorp;
- ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND);
- if (ret)
- goto out;
+ if (vcdev->is_thinint) {
+ ret = virtio_ccw_register_adapter_ind(vcdev, vqs, nvqs, ccw);
+ if (ret)
+ /* no error, just fall back to legacy interrupts */
+ vcdev->is_thinint = 0;
+ }
+ if (!vcdev->is_thinint) {
+ /* Register queue indicators with host. */
+ vcdev->indicators = 0;
+ ccw->cmd_code = CCW_CMD_SET_IND;
+ ccw->flags = 0;
+ ccw->count = sizeof(vcdev->indicators);
+ ccw->cda = (__u32)(unsigned long) indicatorp;
+ ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND);
+ if (ret)
+ goto out;
+ }
/* Register indicators2 with host for config changes */
*indicatorp = (unsigned long) &vcdev->indicators2;
vcdev->indicators2 = 0;
@@ -636,6 +888,8 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
struct virtqueue *vq;
struct virtio_driver *drv;
+ if (!vcdev)
+ return;
/* Check if it's a notification from the host. */
if ((intparm == 0) &&
(scsw_stctl(&irb->scsw) ==
@@ -663,6 +917,7 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
case VIRTIO_CCW_DOING_SET_CONF_IND:
case VIRTIO_CCW_DOING_RESET:
case VIRTIO_CCW_DOING_READ_VQ_CONF:
+ case VIRTIO_CCW_DOING_SET_IND_ADAPTER:
vcdev->curr_io &= ~activity;
wake_up(&vcdev->wait_q);
break;
@@ -734,23 +989,46 @@ static int virtio_ccw_probe(struct ccw_device *cdev)
return 0;
}
+static struct virtio_ccw_device *virtio_grab_drvdata(struct ccw_device *cdev)
+{
+ unsigned long flags;
+ struct virtio_ccw_device *vcdev;
+
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+ vcdev = dev_get_drvdata(&cdev->dev);
+ if (!vcdev || vcdev->going_away) {
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+ return NULL;
+ }
+ vcdev->going_away = true;
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+ return vcdev;
+}
+
static void virtio_ccw_remove(struct ccw_device *cdev)
{
- struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);
+ unsigned long flags;
+ struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);
- if (cdev->online) {
+ if (vcdev && cdev->online)
unregister_virtio_device(&vcdev->vdev);
- dev_set_drvdata(&cdev->dev, NULL);
- }
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+ dev_set_drvdata(&cdev->dev, NULL);
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
cdev->handler = NULL;
}
static int virtio_ccw_offline(struct ccw_device *cdev)
{
- struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);
+ unsigned long flags;
+ struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);
- unregister_virtio_device(&vcdev->vdev);
- dev_set_drvdata(&cdev->dev, NULL);
+ if (vcdev) {
+ unregister_virtio_device(&vcdev->vdev);
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+ dev_set_drvdata(&cdev->dev, NULL);
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+ }
return 0;
}
@@ -759,6 +1037,7 @@ static int virtio_ccw_online(struct ccw_device *cdev)
{
int ret;
struct virtio_ccw_device *vcdev;
+ unsigned long flags;
vcdev = kzalloc(sizeof(*vcdev), GFP_KERNEL);
if (!vcdev) {
@@ -778,6 +1057,8 @@ static int virtio_ccw_online(struct ccw_device *cdev)
goto out_free;
}
+ vcdev->is_thinint = virtio_ccw_use_airq; /* at least try */
+
vcdev->vdev.dev.parent = &cdev->dev;
vcdev->vdev.dev.release = virtio_ccw_release_dev;
vcdev->vdev.config = &virtio_ccw_config_ops;
@@ -786,7 +1067,9 @@ static int virtio_ccw_online(struct ccw_device *cdev)
INIT_LIST_HEAD(&vcdev->virtqueues);
spin_lock_init(&vcdev->lock);
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
dev_set_drvdata(&cdev->dev, vcdev);
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
vcdev->vdev.id.vendor = cdev->id.cu_type;
vcdev->vdev.id.device = cdev->id.cu_model;
ret = register_virtio_device(&vcdev->vdev);
@@ -797,7 +1080,9 @@ static int virtio_ccw_online(struct ccw_device *cdev)
}
return 0;
out_put:
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
dev_set_drvdata(&cdev->dev, NULL);
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
put_device(&vcdev->vdev.dev);
return ret;
out_free:
@@ -935,6 +1220,10 @@ module_init(virtio_ccw_init);
static void __exit virtio_ccw_exit(void)
{
+ int i;
+
ccw_driver_unregister(&virtio_ccw_driver);
+ for (i = 0; i < MAX_AIRQ_AREAS; i++)
+ destroy_airq_info(airq_areas[i]);
}
module_exit(virtio_ccw_exit);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index c3a83df07894..a0aff2eb247c 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -33,8 +33,8 @@ struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS] = {
/* N P A M L V H */
[QETH_DBF_SETUP] = {"qeth_setup",
8, 1, 8, 5, &debug_hex_ascii_view, NULL},
- [QETH_DBF_MSG] = {"qeth_msg",
- 8, 1, 128, 3, &debug_sprintf_view, NULL},
+ [QETH_DBF_MSG] = {"qeth_msg", 8, 1, 11 * sizeof(long), 3,
+ &debug_sprintf_view, NULL},
[QETH_DBF_CTRL] = {"qeth_control",
8, 1, QETH_DBF_CTRL_LEN, 5, &debug_hex_ascii_view, NULL},
};
@@ -1660,7 +1660,6 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
QDIO_FLAG_CLEANUP_USING_CLEAR);
if (rc)
QETH_CARD_TEXT_(card, 3, "1err%d", rc);
- qdio_free(CARD_DDEV(card));
atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
break;
case QETH_QDIO_CLEANING:
@@ -2605,6 +2604,7 @@ static int qeth_mpc_initialize(struct qeth_card *card)
return 0;
out_qdio:
qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
+ qdio_free(CARD_DDEV(card));
return rc;
}
@@ -4906,9 +4906,11 @@ retry:
if (retries < 3)
QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n",
dev_name(&card->gdev->dev));
+ rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
ccw_device_set_offline(CARD_DDEV(card));
ccw_device_set_offline(CARD_WDEV(card));
ccw_device_set_offline(CARD_RDEV(card));
+ qdio_free(CARD_DDEV(card));
rc = ccw_device_set_online(CARD_RDEV(card));
if (rc)
goto retriable;
@@ -4918,7 +4920,6 @@ retry:
rc = ccw_device_set_online(CARD_DDEV(card));
if (rc)
goto retriable;
- rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
retriable:
if (rc == -ERESTARTSYS) {
QETH_DBF_TEXT(SETUP, 2, "break1");
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 0710550093ce..908d82529ee9 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -1091,6 +1091,7 @@ out_remove:
ccw_device_set_offline(CARD_DDEV(card));
ccw_device_set_offline(CARD_WDEV(card));
ccw_device_set_offline(CARD_RDEV(card));
+ qdio_free(CARD_DDEV(card));
if (recover_flag == CARD_STATE_RECOVER)
card->state = CARD_STATE_RECOVER;
else
@@ -1132,6 +1133,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
rc = (rc2) ? rc2 : rc3;
if (rc)
QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+ qdio_free(CARD_DDEV(card));
if (recover_flag == CARD_STATE_UP)
card->state = CARD_STATE_RECOVER;
/* let user_space know that device is offline */
@@ -1194,6 +1196,7 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev)
qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
qeth_qdio_clear_card(card, 0);
qeth_clear_qdio_buffers(card);
+ qdio_free(CARD_DDEV(card));
}
static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev)
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 0f430424c3b8..3524d34ff694 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -3447,6 +3447,7 @@ out_remove:
ccw_device_set_offline(CARD_DDEV(card));
ccw_device_set_offline(CARD_WDEV(card));
ccw_device_set_offline(CARD_RDEV(card));
+ qdio_free(CARD_DDEV(card));
if (recover_flag == CARD_STATE_RECOVER)
card->state = CARD_STATE_RECOVER;
else
@@ -3493,6 +3494,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
rc = (rc2) ? rc2 : rc3;
if (rc)
QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+ qdio_free(CARD_DDEV(card));
if (recover_flag == CARD_STATE_UP)
card->state = CARD_STATE_RECOVER;
/* let user_space know that device is offline */
@@ -3545,6 +3547,7 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev)
qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
qeth_qdio_clear_card(card, 0);
qeth_clear_qdio_buffers(card);
+ qdio_free(CARD_DDEV(card));
}
static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
index 6b4678a7900a..4ccb5d869389 100644
--- a/drivers/sbus/char/jsflash.c
+++ b/drivers/sbus/char/jsflash.c
@@ -507,7 +507,6 @@ static int jsflash_init(void)
}
/* Let us be really paranoid for modifications to probing code. */
- /* extern enum sparc_cpu sparc_cpu_model; */ /* in <asm/system.h> */
if (sparc_cpu_model != sun4m) {
/* We must be on sun4m because we use MMU Bypass ASI. */
return -ENXIO;
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 1e9d6ad9302b..bcd223868227 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -584,7 +584,7 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
NCR5380_setup(instance);
for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1)
- if ((mask & possible) && (request_irq(i, &probe_intr, IRQF_DISABLED, "NCR-probe", NULL) == 0))
+ if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0))
trying_irqs |= mask;
timeout = jiffies + (250 * HZ / 1000);
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 9323d058706b..eaaf8705a5f4 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,7 +12,7 @@
*----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 30200
+# define AAC_DRIVER_BUILD 30300
# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index dada38aeacc0..5c6a8703f535 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -480,7 +480,7 @@ static int aac_rx_ioremap(struct aac_dev * dev, u32 size)
static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
{
- u32 var;
+ u32 var = 0;
if (!(dev->supplement_adapter_info.SupportedOptions2 &
AAC_OPTION_MU_RESET) || (bled >= 0) || (bled == -2)) {
@@ -500,13 +500,14 @@ static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
if (bled && (bled != -ETIMEDOUT))
return -EINVAL;
}
- if (bled || (var == 0x3803000F)) { /* USE_OTHER_METHOD */
+ if (bled && (var == 0x3803000F)) { /* USE_OTHER_METHOD */
rx_writel(dev, MUnit.reserved2, 3);
msleep(5000); /* Delay 5 seconds */
var = 0x00000001;
}
- if (var != 0x00000001)
+ if (bled && (var != 0x00000001))
return -EINVAL;
+ ssleep(5);
if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
return -ENODEV;
if (startup_timeout < 300)
@@ -646,7 +647,7 @@ int _aac_rx_init(struct aac_dev *dev)
dev->sync_mode = 0; /* sync. mode not supported */
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
- IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
+ IRQF_SHARED, "aacraid", dev) < 0) {
if (dev->msi)
pci_disable_msi(dev->pdev);
printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index 2244f315f33b..e66477c98240 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -387,8 +387,7 @@ int aac_sa_init(struct aac_dev *dev)
goto error_irq;
dev->sync_mode = 0; /* sync. mode not supported */
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
- IRQF_SHARED|IRQF_DISABLED,
- "aacraid", (void *)dev ) < 0) {
+ IRQF_SHARED, "aacraid", (void *)dev) < 0) {
printk(KERN_WARNING "%s%d: Interrupt unavailable.\n",
name, instance);
goto error_iounmap;
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index 7e17107643d4..9c65aed26212 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -647,7 +647,7 @@ int aac_src_init(struct aac_dev *dev)
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
- IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
+ IRQF_SHARED, "aacraid", dev) < 0) {
if (dev->msi)
pci_disable_msi(dev->pdev);
@@ -804,7 +804,7 @@ int aac_srcv_init(struct aac_dev *dev)
goto error_iounmap;
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
- IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
+ IRQF_SHARED, "aacraid", dev) < 0) {
if (dev->msi)
pci_disable_msi(dev->pdev);
printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 3f7b6fee0a74..e86eb6a921fc 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -857,7 +857,7 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
SETPORT(SIMODE0, 0);
SETPORT(SIMODE1, 0);
- if( request_irq(shpnt->irq, swintr, IRQF_DISABLED|IRQF_SHARED, "aha152x", shpnt) ) {
+ if (request_irq(shpnt->irq, swintr, IRQF_SHARED, "aha152x", shpnt)) {
printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq);
goto out_host_put;
}
@@ -891,7 +891,7 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
SETPORT(SSTAT0, 0x7f);
SETPORT(SSTAT1, 0xef);
- if ( request_irq(shpnt->irq, intr, IRQF_DISABLED|IRQF_SHARED, "aha152x", shpnt) ) {
+ if (request_irq(shpnt->irq, intr, IRQF_SHARED, "aha152x", shpnt)) {
printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq);
goto out_host_put;
}
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h b/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h
index 9df9e2ce3538..8373447bd7d3 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h
@@ -209,7 +209,6 @@ struct instruction {
#define AIC_OP_JC16 0x9105
#define AIC_OP_JNC16 0x9205
#define AIC_OP_CALL16 0x9305
-#define AIC_OP_CALL16 0x9305
/* Page extension is low three bits of second opcode byte. */
#define AIC_OP_JMPF 0xA005
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 4f6a30b8e5f9..652b41b4ddbd 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -2500,16 +2500,15 @@ static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
{
uint32_t cdb_phyaddr, cdb_phyaddr_hi32;
- dma_addr_t dma_coherent_handle;
+
/*
********************************************************************
** here we need to tell iop 331 our freeccb.HighPart
** if freeccb.HighPart is not zero
********************************************************************
*/
- dma_coherent_handle = acb->dma_coherent_handle;
- cdb_phyaddr = (uint32_t)(dma_coherent_handle);
- cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+ cdb_phyaddr = lower_32_bits(acb->dma_coherent_handle);
+ cdb_phyaddr_hi32 = upper_32_bits(acb->dma_coherent_handle);
acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32;
/*
***********************************************************************
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index 09ba1869d366..059ff477a398 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -2971,7 +2971,7 @@ static int acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
ec->irqaddr = ashost->fast + INT_REG;
ec->irqmask = 0x0a;
- ret = request_irq(host->irq, acornscsi_intr, IRQF_DISABLED, "acornscsi", ashost);
+ ret = request_irq(host->irq, acornscsi_intr, 0, "acornscsi", ashost);
if (ret) {
printk(KERN_CRIT "scsi%d: IRQ%d not free: %d\n",
host->host_no, ashost->scsi.irq, ret);
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index b679778376c5..f8e060900052 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -262,7 +262,7 @@ static int cumanascsi1_probe(struct expansion_card *ec,
goto out_unmap;
}
- ret = request_irq(host->irq, cumanascsi_intr, IRQF_DISABLED,
+ ret = request_irq(host->irq, cumanascsi_intr, 0,
"CumanaSCSI-1", host);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
index 58915f29055b..abc66f5263ec 100644
--- a/drivers/scsi/arm/cumana_2.c
+++ b/drivers/scsi/arm/cumana_2.c
@@ -431,7 +431,7 @@ static int cumanascsi2_probe(struct expansion_card *ec,
goto out_free;
ret = request_irq(ec->irq, cumanascsi_2_intr,
- IRQF_DISABLED, "cumanascsi2", info);
+ 0, "cumanascsi2", info);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
host->host_no, ec->irq, ret);
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
index abc9593615e9..5e1b73e1b743 100644
--- a/drivers/scsi/arm/powertec.c
+++ b/drivers/scsi/arm/powertec.c
@@ -358,7 +358,7 @@ static int powertecscsi_probe(struct expansion_card *ec,
goto out_free;
ret = request_irq(ec->irq, powertecscsi_intr,
- IRQF_DISABLED, "powertec", info);
+ 0, "powertec", info);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
host->host_no, ec->irq, ret);
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index a3e6c8a3ff0f..296c936cc03c 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -90,6 +90,7 @@
#include <linux/init.h>
#include <linux/nvram.h>
#include <linux/bitops.h>
+#include <linux/wait.h>
#include <asm/setup.h>
#include <asm/atarihw.h>
@@ -549,8 +550,10 @@ static void falcon_get_lock(void)
local_irq_save(flags);
- while (!in_irq() && falcon_got_lock && stdma_others_waiting())
- sleep_on(&falcon_fairness_wait);
+ wait_event_cmd(falcon_fairness_wait,
+ in_interrupt() || !falcon_got_lock || !stdma_others_waiting(),
+ local_irq_restore(flags),
+ local_irq_save(flags));
while (!falcon_got_lock) {
if (in_irq())
@@ -562,7 +565,10 @@ static void falcon_get_lock(void)
falcon_trying_lock = 0;
wake_up(&falcon_try_wait);
} else {
- sleep_on(&falcon_try_wait);
+ wait_event_cmd(falcon_try_wait,
+ falcon_got_lock && !falcon_trying_lock,
+ local_irq_restore(flags),
+ local_irq_save(flags));
}
}
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index 2e28f6c419fe..1bfb0bd01198 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -98,6 +98,14 @@ struct be_mcc_obj {
struct be_queue_info cq;
};
+struct beiscsi_mcc_tag_state {
+#define MCC_TAG_STATE_COMPLETED 0x00
+#define MCC_TAG_STATE_RUNNING 0x01
+#define MCC_TAG_STATE_TIMEOUT 0x02
+ uint8_t tag_state;
+ struct be_dma_mem tag_mem_state;
+};
+
struct be_ctrl_info {
u8 __iomem *csr;
u8 __iomem *db; /* Door Bell */
@@ -122,6 +130,8 @@ struct be_ctrl_info {
unsigned short mcc_alloc_index;
unsigned short mcc_free_index;
unsigned int mcc_tag_available;
+
+ struct beiscsi_mcc_tag_state ptag_state[MAX_MCC_CMD + 1];
};
#include "be_cmds.h"
@@ -129,6 +139,7 @@ struct be_ctrl_info {
#define PAGE_SHIFT_4K 12
#define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K)
#define mcc_timeout 120000 /* 12s timeout */
+#define BEISCSI_LOGOUT_SYNC_DELAY 250
/* Returns number of pages spanned by the data starting at the given addr */
#define PAGES_4K_SPANNED(_address, size) \
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index 3338391b64de..1432ed5e9fc6 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -138,7 +138,7 @@ unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
* @phba: Driver private structure
* @tag: Tag for the MBX Command
* @wrb: the WRB used for the MBX Command
- * @cmd_hdr: IOCTL Hdr for the MBX Cmd
+ * @mbx_cmd_mem: ptr to memory allocated for MBX Cmd
*
* Waits for MBX completion with the passed TAG.
*
@@ -148,21 +148,26 @@ unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
**/
int beiscsi_mccq_compl(struct beiscsi_hba *phba,
uint32_t tag, struct be_mcc_wrb **wrb,
- void *cmd_hdr)
+ struct be_dma_mem *mbx_cmd_mem)
{
int rc = 0;
uint32_t mcc_tag_response;
uint16_t status = 0, addl_status = 0, wrb_num = 0;
struct be_mcc_wrb *temp_wrb;
- struct be_cmd_req_hdr *ioctl_hdr;
- struct be_cmd_resp_hdr *ioctl_resp_hdr;
+ 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)) {
free_mcc_tag(&phba->ctrl, tag);
- return -EIO;
+ return -EPERM;
}
+ /* Set MBX Tag state to Active */
+ spin_lock(&phba->ctrl.mbox_lock);
+ phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_RUNNING;
+ spin_unlock(&phba->ctrl.mbox_lock);
+
/* wait for the mccq completion */
rc = wait_event_interruptible_timeout(
phba->ctrl.mcc_wait[tag],
@@ -171,56 +176,71 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
BEISCSI_HOST_MBX_TIMEOUT));
if (rc <= 0) {
+ struct be_dma_mem *tag_mem;
+ /* Set MBX Tag state to timeout */
+ spin_lock(&phba->ctrl.mbox_lock);
+ phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_TIMEOUT;
+ spin_unlock(&phba->ctrl.mbox_lock);
+
+ /* Store resource addr to be freed later */
+ tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state;
+ if (mbx_cmd_mem) {
+ tag_mem->size = mbx_cmd_mem->size;
+ tag_mem->va = mbx_cmd_mem->va;
+ tag_mem->dma = mbx_cmd_mem->dma;
+ } else
+ tag_mem->size = 0;
+
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
BEISCSI_LOG_CONFIG,
"BC_%d : MBX Cmd Completion timed out\n");
- rc = -EBUSY;
-
- /* decrement the mccq used count */
- atomic_dec(&phba->ctrl.mcc_obj.q.used);
-
- goto release_mcc_tag;
- } else
+ return -EBUSY;
+ } else {
rc = 0;
+ /* Set MBX Tag state to completed */
+ spin_lock(&phba->ctrl.mbox_lock);
+ phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_COMPLETED;
+ spin_unlock(&phba->ctrl.mbox_lock);
+ }
mcc_tag_response = phba->ctrl.mcc_numtag[tag];
status = (mcc_tag_response & CQE_STATUS_MASK);
addl_status = ((mcc_tag_response & CQE_STATUS_ADDL_MASK) >>
CQE_STATUS_ADDL_SHIFT);
- if (cmd_hdr) {
- ioctl_hdr = (struct be_cmd_req_hdr *)cmd_hdr;
+ if (mbx_cmd_mem) {
+ mbx_hdr = (struct be_cmd_req_hdr *)mbx_cmd_mem->va;
} else {
wrb_num = (mcc_tag_response & CQE_STATUS_WRB_MASK) >>
CQE_STATUS_WRB_SHIFT;
temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num);
- ioctl_hdr = embedded_payload(temp_wrb);
+ mbx_hdr = embedded_payload(temp_wrb);
if (wrb)
*wrb = temp_wrb;
}
if (status || addl_status) {
- beiscsi_log(phba, KERN_ERR,
+ 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",
- ioctl_hdr->subsystem,
- ioctl_hdr->opcode,
+ mbx_hdr->subsystem,
+ mbx_hdr->opcode,
status, addl_status);
if (status == MCC_STATUS_INSUFFICIENT_BUFFER) {
- ioctl_resp_hdr = (struct be_cmd_resp_hdr *) ioctl_hdr;
+ 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 : Insufficent Buffer Error "
"Resp_Len : %d Actual_Resp_Len : %d\n",
- ioctl_resp_hdr->response_length,
- ioctl_resp_hdr->actual_resp_len);
+ mbx_resp_hdr->response_length,
+ mbx_resp_hdr->actual_resp_len);
rc = -EAGAIN;
goto release_mcc_tag;
@@ -319,6 +339,7 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl,
struct be_mcc_compl *compl)
{
+ struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
u16 compl_status, extd_status;
unsigned short tag;
@@ -338,7 +359,32 @@ int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl,
ctrl->mcc_numtag[tag] |= (compl->tag0 & 0x00FF0000);
ctrl->mcc_numtag[tag] |= (extd_status & 0x000000FF) << 8;
ctrl->mcc_numtag[tag] |= (compl_status & 0x000000FF);
- wake_up_interruptible(&ctrl->mcc_wait[tag]);
+
+ if (ctrl->ptag_state[tag].tag_state == MCC_TAG_STATE_RUNNING) {
+ wake_up_interruptible(&ctrl->mcc_wait[tag]);
+ } else if (ctrl->ptag_state[tag].tag_state == MCC_TAG_STATE_TIMEOUT) {
+ struct be_dma_mem *tag_mem;
+ tag_mem = &ctrl->ptag_state[tag].tag_mem_state;
+
+ beiscsi_log(phba, KERN_WARNING,
+ BEISCSI_LOG_MBOX | BEISCSI_LOG_INIT |
+ BEISCSI_LOG_CONFIG,
+ "BC_%d : MBX Completion for timeout Command "
+ "from FW\n");
+ /* Check if memory needs to be freed */
+ if (tag_mem->size)
+ pci_free_consistent(ctrl->pdev, tag_mem->size,
+ tag_mem->va, tag_mem->dma);
+
+ /* Change tag state */
+ spin_lock(&phba->ctrl.mbox_lock);
+ ctrl->ptag_state[tag].tag_state = MCC_TAG_STATE_COMPLETED;
+ spin_unlock(&phba->ctrl.mbox_lock);
+
+ /* Free MCC Tag */
+ free_mcc_tag(ctrl, tag);
+ }
+
return 0;
}
@@ -354,8 +400,23 @@ static struct be_mcc_compl *be_mcc_compl_get(struct beiscsi_hba *phba)
return NULL;
}
-static void be2iscsi_fail_session(struct iscsi_cls_session *cls_session)
+/**
+ * be2iscsi_fail_session(): Closing session with appropriate error
+ * @cls_session: ptr to session
+ *
+ * Depending on adapter state appropriate error flag is passed.
+ **/
+void be2iscsi_fail_session(struct iscsi_cls_session *cls_session)
{
+ struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ uint32_t iscsi_err_flag;
+
+ if (phba->state & BE_ADAPTER_STATE_SHUTDOWN)
+ iscsi_err_flag = ISCSI_ERR_INVALID_HOST;
+ else
+ iscsi_err_flag = ISCSI_ERR_CONN_FAILED;
+
iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
}
@@ -386,18 +447,6 @@ void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
}
}
-static void beiscsi_cq_notify(struct beiscsi_hba *phba, u16 qid, bool arm,
- u16 num_popped)
-{
- u32 val = 0;
- val |= qid & DB_CQ_RING_ID_MASK;
- if (arm)
- val |= 1 << DB_CQ_REARM_SHIFT;
- val |= num_popped << DB_CQ_NUM_POPPED_SHIFT;
- iowrite32(val, phba->db_va + DB_CQ_OFFSET);
-}
-
-
int beiscsi_process_mcc(struct beiscsi_hba *phba)
{
struct be_mcc_compl *compl;
@@ -428,7 +477,7 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba)
}
if (num)
- beiscsi_cq_notify(phba, phba->ctrl.mcc_obj.cq.id, true, num);
+ hwi_ring_cq_db(phba, phba->ctrl.mcc_obj.cq.id, num, 1, 0);
spin_unlock_bh(&phba->ctrl.mcc_cq_lock);
return status;
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index 627ebbe0172c..7cf7f99ee442 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -103,7 +103,7 @@ struct be_mcc_compl {
/********** MCC door bell ************/
#define DB_MCCQ_OFFSET 0x140
-#define DB_MCCQ_RING_ID_MASK 0x7FF /* bits 0 - 10 */
+#define DB_MCCQ_RING_ID_MASK 0xFFFF /* bits 0 - 15 */
/* Number of entries posted */
#define DB_MCCQ_NUM_POSTED_SHIFT 16 /* bits 16 - 29 */
@@ -709,7 +709,8 @@ unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba);
void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag);
int beiscsi_mccq_compl(struct beiscsi_hba *phba,
- uint32_t tag, struct be_mcc_wrb **wrb, void *cmd_va);
+ uint32_t 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);
@@ -1017,8 +1018,8 @@ struct be_mcc_wrb_context {
int *users_final_status;
} __packed;
-#define DB_DEF_PDU_RING_ID_MASK 0x3FF /* bits 0 - 9 */
-#define DB_DEF_PDU_CQPROC_MASK 0x3FFF /* bits 0 - 9 */
+#define DB_DEF_PDU_RING_ID_MASK 0x3FFF /* bits 0 - 13 */
+#define DB_DEF_PDU_CQPROC_MASK 0x3FFF /* bits 16 - 29 */
#define DB_DEF_PDU_REARM_SHIFT 14
#define DB_DEF_PDU_EVENT_SHIFT 15
#define DB_DEF_PDU_CQPROC_SHIFT 16
@@ -1317,4 +1318,5 @@ void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
u8 subsystem, u8 opcode, int cmd_len);
+void be2iscsi_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 889066d9d6fb..a3df43324c98 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -793,7 +793,7 @@ static int beiscsi_get_port_speed(struct Scsi_Host *shost)
ihost->port_speed = ISCSI_PORT_SPEED_10MBPS;
break;
case BE2ISCSI_LINK_SPEED_100MBPS:
- ihost->port_speed = BE2ISCSI_LINK_SPEED_100MBPS;
+ ihost->port_speed = ISCSI_PORT_SPEED_100MBPS;
break;
case BE2ISCSI_LINK_SPEED_1GBPS:
ihost->port_speed = ISCSI_PORT_SPEED_1GBPS;
@@ -1153,16 +1153,18 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
return -EAGAIN;
}
- ret = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
+ ret = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
if (ret) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BS_%d : mgmt_open_connection Failed");
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
- nonemb_cmd.va, nonemb_cmd.dma);
+ if (ret != -EBUSY)
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+
beiscsi_free_ep(beiscsi_ep);
- return -EBUSY;
+ return ret;
}
ptcpcnct_out = (struct tcp_connect_and_offload_out *)nonemb_cmd.va;
@@ -1359,6 +1361,7 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
beiscsi_mccq_compl(phba, tag, NULL, NULL);
beiscsi_close_conn(beiscsi_ep, tcp_upload_flag);
free_ep:
+ msleep(BEISCSI_LOGOUT_SYNC_DELAY);
beiscsi_free_ep(beiscsi_ep);
beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 1f375051483a..0d822297aa80 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -228,24 +228,25 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
struct invalidate_command_table *inv_tbl;
struct be_dma_mem nonemb_cmd;
unsigned int cid, tag, num_invalidate;
+ int rc;
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (!aborted_task || !aborted_task->sc) {
/* we raced */
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return SUCCESS;
}
aborted_io_task = aborted_task->dd_data;
if (!aborted_io_task->scsi_cmnd) {
/* raced or invalid command */
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return SUCCESS;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
/* Invalidate WRB Posted for this Task */
AMAP_SET_BITS(struct amap_iscsi_wrb, invld,
aborted_io_task->pwrb_handle->pwrb,
@@ -285,9 +286,11 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
return FAILED;
}
- beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
- nonemb_cmd.va, nonemb_cmd.dma);
+ rc = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ if (rc != -EBUSY)
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+
return iscsi_eh_abort(sc);
}
@@ -303,13 +306,14 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
struct invalidate_command_table *inv_tbl;
struct be_dma_mem nonemb_cmd;
unsigned int cid, tag, i, num_invalidate;
+ int rc;
/* invalidate iocbs */
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return FAILED;
}
conn = session->leadconn;
@@ -325,7 +329,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
if (!abrt_task->sc || abrt_task->state == ISCSI_TASK_FREE)
continue;
- if (abrt_task->sc->device->lun != abrt_task->sc->device->lun)
+ if (sc->device->lun != abrt_task->sc->device->lun)
continue;
/* Invalidate WRB Posted for this Task */
@@ -338,7 +342,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
num_invalidate++;
inv_tbl++;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
inv_tbl = phba->inv_tbl;
nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
@@ -363,9 +367,10 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
return FAILED;
}
- beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
- nonemb_cmd.va, nonemb_cmd.dma);
+ rc = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ if (rc != -EBUSY)
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
return iscsi_eh_device_reset(sc);
}
@@ -674,8 +679,19 @@ static int beiscsi_enable_pci(struct pci_dev *pcidev)
}
pci_set_master(pcidev);
- if (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64))) {
- ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32));
+ ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(64));
+ if (ret) {
+ ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(&pcidev->dev, "Could not set PCI DMA Mask\n");
+ pci_disable_device(pcidev);
+ return ret;
+ } else {
+ ret = pci_set_consistent_dma_mask(pcidev,
+ DMA_BIT_MASK(32));
+ }
+ } else {
+ ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64));
if (ret) {
dev_err(&pcidev->dev, "Could not set PCI DMA Mask\n");
pci_disable_device(pcidev);
@@ -804,14 +820,23 @@ static void hwi_ring_eq_db(struct beiscsi_hba *phba,
unsigned char rearm, unsigned char event)
{
u32 val = 0;
- val |= id & DB_EQ_RING_ID_MASK;
+
if (rearm)
val |= 1 << DB_EQ_REARM_SHIFT;
if (clr_interrupt)
val |= 1 << DB_EQ_CLR_SHIFT;
if (event)
val |= 1 << DB_EQ_EVNT_SHIFT;
+
val |= num_processed << DB_EQ_NUM_POPPED_SHIFT;
+ /* Setting lower order EQ_ID Bits */
+ val |= (id & DB_EQ_RING_ID_LOW_MASK);
+
+ /* Setting Higher order EQ_ID Bits */
+ val |= (((id >> DB_EQ_HIGH_FEILD_SHIFT) &
+ DB_EQ_RING_ID_HIGH_MASK)
+ << DB_EQ_HIGH_SET_SHIFT);
+
iowrite32(val, phba->db_va + DB_EQ_OFFSET);
}
@@ -873,7 +898,6 @@ static irqreturn_t be_isr_msix(int irq, void *dev_id)
struct be_queue_info *cq;
unsigned int num_eq_processed;
struct be_eq_obj *pbe_eq;
- unsigned long flags;
pbe_eq = dev_id;
eq = &pbe_eq->q;
@@ -882,31 +906,15 @@ static irqreturn_t be_isr_msix(int irq, void *dev_id)
phba = pbe_eq->phba;
num_eq_processed = 0;
- if (blk_iopoll_enabled) {
- while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
- & EQE_VALID_MASK) {
- if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
- blk_iopoll_sched(&pbe_eq->iopoll);
-
- AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
- queue_tail_inc(eq);
- eqe = queue_tail_node(eq);
- num_eq_processed++;
- }
- } else {
- while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
- & EQE_VALID_MASK) {
- spin_lock_irqsave(&phba->isr_lock, flags);
- pbe_eq->todo_cq = true;
- spin_unlock_irqrestore(&phba->isr_lock, flags);
- AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
- queue_tail_inc(eq);
- eqe = queue_tail_node(eq);
- num_eq_processed++;
- }
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+ if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
+ blk_iopoll_sched(&pbe_eq->iopoll);
- if (pbe_eq->todo_cq)
- queue_work(phba->wq, &pbe_eq->work_cqs);
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ num_eq_processed++;
}
if (num_eq_processed)
@@ -927,7 +935,6 @@ static irqreturn_t be_isr(int irq, void *dev_id)
struct hwi_context_memory *phwi_context;
struct be_eq_entry *eqe = NULL;
struct be_queue_info *eq;
- struct be_queue_info *cq;
struct be_queue_info *mcc;
unsigned long flags, index;
unsigned int num_mcceq_processed, num_ioeq_processed;
@@ -953,72 +960,40 @@ static irqreturn_t be_isr(int irq, void *dev_id)
num_ioeq_processed = 0;
num_mcceq_processed = 0;
- if (blk_iopoll_enabled) {
- 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 {
- if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
- blk_iopoll_sched(&pbe_eq->iopoll);
- num_ioeq_processed++;
- }
- 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
- return IRQ_NONE;
- } else {
- cq = &phwi_context->be_cq[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) != cq->id) {
- spin_lock_irqsave(&phba->isr_lock, flags);
- pbe_eq->todo_mcc_cq = true;
- spin_unlock_irqrestore(&phba->isr_lock, flags);
- } else {
- spin_lock_irqsave(&phba->isr_lock, flags);
- pbe_eq->todo_cq = true;
- spin_unlock_irqrestore(&phba->isr_lock, flags);
- }
- AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
- queue_tail_inc(eq);
- eqe = queue_tail_node(eq);
+ 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 {
+ if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
+ blk_iopoll_sched(&pbe_eq->iopoll);
num_ioeq_processed++;
}
- if (pbe_eq->todo_cq || pbe_eq->todo_mcc_cq)
+ 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_ioeq_processed) {
+ if ((num_mcceq_processed) && (!num_ioeq_processed))
hwi_ring_eq_db(phba, eq->id, 0,
- num_ioeq_processed, 1, 1);
- return IRQ_HANDLED;
- } else
- return IRQ_NONE;
- }
+ (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
+ return IRQ_NONE;
}
static int beiscsi_init_irqs(struct beiscsi_hba *phba)
@@ -1093,15 +1068,25 @@ free_msix_irqs:
return ret;
}
-static void hwi_ring_cq_db(struct beiscsi_hba *phba,
+void hwi_ring_cq_db(struct beiscsi_hba *phba,
unsigned int id, unsigned int num_processed,
unsigned char rearm, unsigned char event)
{
u32 val = 0;
- val |= id & DB_CQ_RING_ID_MASK;
+
if (rearm)
val |= 1 << DB_CQ_REARM_SHIFT;
+
val |= num_processed << DB_CQ_NUM_POPPED_SHIFT;
+
+ /* Setting lower order CQ_ID Bits */
+ val |= (id & DB_CQ_RING_ID_LOW_MASK);
+
+ /* Setting Higher order CQ_ID Bits */
+ val |= (((id >> DB_CQ_HIGH_FEILD_SHIFT) &
+ DB_CQ_RING_ID_HIGH_MASK)
+ << DB_CQ_HIGH_SET_SHIFT);
+
iowrite32(val, phba->db_va + DB_CQ_OFFSET);
}
@@ -1150,9 +1135,9 @@ beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn,
return 1;
}
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->back_lock);
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)ppdu, pbuffer, buf_len);
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->back_lock);
return 0;
}
@@ -1342,8 +1327,10 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn,
resid = csol_cqe->res_cnt;
if (!task->sc) {
- if (io_task->scsi_cmnd)
+ if (io_task->scsi_cmnd) {
scsi_dma_unmap(io_task->scsi_cmnd);
+ io_task->scsi_cmnd = NULL;
+ }
return;
}
@@ -1380,6 +1367,7 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn,
conn->rxdata_octets += resid;
unmap:
scsi_dma_unmap(io_task->scsi_cmnd);
+ io_task->scsi_cmnd = NULL;
iscsi_complete_scsi_task(task, exp_cmdsn, max_cmdsn);
}
@@ -1568,7 +1556,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
pwrb = pwrb_handle->pwrb;
type = ((struct beiscsi_io_task *)task->dd_data)->wrb_type;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->back_lock);
switch (type) {
case HWH_TYPE_IO:
case HWH_TYPE_IO_RD:
@@ -1607,7 +1595,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
break;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->back_lock);
}
static struct list_head *hwi_get_async_busy_list(struct hwi_async_pdu_context
@@ -4360,12 +4348,16 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
goto boot_freemem;
}
- ret = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
+ ret = beiscsi_mccq_compl(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");
- goto boot_freemem;
+
+ if (ret != -EBUSY)
+ goto boot_freemem;
+ else
+ return ret;
}
session_resp = nonemb_cmd.va ;
@@ -4625,6 +4617,11 @@ static void beiscsi_cleanup_task(struct iscsi_task *task)
spin_unlock(&phba->io_sgl_lock);
io_task->psgl_handle = NULL;
}
+
+ if (io_task->scsi_cmnd) {
+ scsi_dma_unmap(io_task->scsi_cmnd);
+ io_task->scsi_cmnd = NULL;
+ }
} else {
if (!beiscsi_conn->login_in_progress)
beiscsi_free_mgmt_task_handles(beiscsi_conn, task);
@@ -4646,9 +4643,9 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
* login/startup related tasks.
*/
beiscsi_conn->login_in_progress = 0;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->back_lock);
beiscsi_cleanup_task(task);
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->back_lock);
pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid);
@@ -5216,11 +5213,10 @@ static void beiscsi_quiesce(struct beiscsi_hba *phba,
}
pci_disable_msix(phba->pcidev);
- if (blk_iopoll_enabled)
- for (i = 0; i < phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_disable(&pbe_eq->iopoll);
- }
+ for (i = 0; i < phba->num_cpus; i++) {
+ pbe_eq = &phwi_context->be_eq[i];
+ blk_iopoll_disable(&pbe_eq->iopoll);
+ }
if (unload_state == BEISCSI_CLEAN_UNLOAD) {
destroy_workqueue(phba->wq);
@@ -5273,6 +5269,8 @@ static void beiscsi_shutdown(struct pci_dev *pcidev)
return;
}
+ phba->state = BE_ADAPTER_STATE_SHUTDOWN;
+ iscsi_host_for_each_session(phba->shost, be2iscsi_fail_session);
beiscsi_quiesce(phba, BEISCSI_CLEAN_UNLOAD);
pci_disable_device(pcidev);
}
@@ -5429,32 +5427,18 @@ static void beiscsi_eeh_resume(struct pci_dev *pdev)
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
- if (blk_iopoll_enabled) {
- for (i = 0; i < phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget,
- be_iopoll);
- blk_iopoll_enable(&pbe_eq->iopoll);
- }
-
- i = (phba->msix_enabled) ? i : 0;
- /* Work item for MCC handling */
+ for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- INIT_WORK(&pbe_eq->work_cqs, beiscsi_process_all_cqs);
- } else {
- if (phba->msix_enabled) {
- for (i = 0; i <= phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- INIT_WORK(&pbe_eq->work_cqs,
- beiscsi_process_all_cqs);
- }
- } else {
- pbe_eq = &phwi_context->be_eq[0];
- INIT_WORK(&pbe_eq->work_cqs,
- beiscsi_process_all_cqs);
- }
+ blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget,
+ be_iopoll);
+ blk_iopoll_enable(&pbe_eq->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,
@@ -5594,6 +5578,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
phba->ctrl.mcc_tag[i] = i + 1;
phba->ctrl.mcc_numtag[i + 1] = 0;
phba->ctrl.mcc_tag_available++;
+ memset(&phba->ctrl.ptag_state[i].tag_mem_state, 0,
+ sizeof(struct beiscsi_mcc_tag_state));
}
phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0;
@@ -5614,32 +5600,18 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
- if (blk_iopoll_enabled) {
- for (i = 0; i < phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget,
- be_iopoll);
- blk_iopoll_enable(&pbe_eq->iopoll);
- }
-
- i = (phba->msix_enabled) ? i : 0;
- /* Work item for MCC handling */
+ for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- INIT_WORK(&pbe_eq->work_cqs, beiscsi_process_all_cqs);
- } else {
- if (phba->msix_enabled) {
- for (i = 0; i <= phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- INIT_WORK(&pbe_eq->work_cqs,
- beiscsi_process_all_cqs);
- }
- } else {
- pbe_eq = &phwi_context->be_eq[0];
- INIT_WORK(&pbe_eq->work_cqs,
- beiscsi_process_all_cqs);
- }
+ blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget,
+ be_iopoll);
+ blk_iopoll_enable(&pbe_eq->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,
@@ -5668,11 +5640,10 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
free_blkenbld:
destroy_workqueue(phba->wq);
- if (blk_iopoll_enabled)
- for (i = 0; i < phba->num_cpus; i++) {
- pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_disable(&pbe_eq->iopoll);
- }
+ for (i = 0; i < phba->num_cpus; i++) {
+ pbe_eq = &phwi_context->be_eq[i];
+ blk_iopoll_disable(&pbe_eq->iopoll);
+ }
free_twq:
beiscsi_clean_port(phba);
beiscsi_free_mem(phba);
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index 31fa27b4a9b2..9380b55bdeaf 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -36,7 +36,7 @@
#include <scsi/scsi_transport_iscsi.h>
#define DRV_NAME "be2iscsi"
-#define BUILD_STR "10.0.659.0"
+#define BUILD_STR "10.2.125.0"
#define BE_NAME "Emulex OneConnect" \
"Open-iSCSI Driver version" BUILD_STR
#define DRV_DESC BE_NAME " " "Driver"
@@ -97,9 +97,14 @@
#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_STATE_SHUTDOWN 0x008
+
#define BEISCSI_CLEAN_UNLOAD 0x01
#define BEISCSI_EEH_UNLOAD 0x02
@@ -135,11 +140,15 @@
#define DB_RXULP0_OFFSET 0xA0
/********* Event Q door bell *************/
#define DB_EQ_OFFSET DB_CQ_OFFSET
-#define DB_EQ_RING_ID_MASK 0x1FF /* bits 0 - 8 */
+#define DB_EQ_RING_ID_LOW_MASK 0x1FF /* bits 0 - 8 */
/* Clear the interrupt for this eq */
#define DB_EQ_CLR_SHIFT (9) /* bit 9 */
/* Must be 1 */
#define DB_EQ_EVNT_SHIFT (10) /* bit 10 */
+/* Higher Order EQ_ID bit */
+#define DB_EQ_RING_ID_HIGH_MASK 0x1F /* bits 11 - 15 */
+#define DB_EQ_HIGH_SET_SHIFT 11
+#define DB_EQ_HIGH_FEILD_SHIFT 9
/* Number of event entries processed */
#define DB_EQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
/* Rearm bit */
@@ -147,7 +156,12 @@
/********* Compl Q door bell *************/
#define DB_CQ_OFFSET 0x120
-#define DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */
+#define DB_CQ_RING_ID_LOW_MASK 0x3FF /* bits 0 - 9 */
+/* Higher Order CQ_ID bit */
+#define DB_CQ_RING_ID_HIGH_MASK 0x1F /* bits 11 - 15 */
+#define DB_CQ_HIGH_SET_SHIFT 11
+#define DB_CQ_HIGH_FEILD_SHIFT 10
+
/* Number of event entries processed */
#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
/* Rearm bit */
@@ -821,6 +835,9 @@ void beiscsi_process_all_cqs(struct work_struct *work);
void beiscsi_free_mgmt_task_handles(struct beiscsi_conn *beiscsi_conn,
struct iscsi_task *task);
+void hwi_ring_cq_db(struct beiscsi_hba *phba,
+ unsigned int id, unsigned int num_processed,
+ unsigned char rearm, unsigned char event);
static inline bool beiscsi_error(struct beiscsi_hba *phba)
{
return phba->ue_detected || phba->fw_timeout;
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index b2fcac78feaa..088bdf752cfa 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -828,22 +828,25 @@ static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba,
be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
- rc = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd->va);
+ rc = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd);
+
+ if (resp_buf)
+ memcpy(resp_buf, nonemb_cmd->va, resp_buf_len);
+
if (rc) {
- /* Check if the IOCTL needs to be re-issued */
+ /* Check if the MBX Cmd needs to be re-issued */
if (rc == -EAGAIN)
return rc;
- beiscsi_log(phba, KERN_ERR,
+ beiscsi_log(phba, KERN_WARNING,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : mgmt_exec_nonemb_cmd Failed status\n");
- goto free_cmd;
+ if (rc != -EBUSY)
+ goto free_cmd;
+ else
+ return rc;
}
-
- if (resp_buf)
- memcpy(resp_buf, nonemb_cmd->va, resp_buf_len);
-
free_cmd:
pci_free_consistent(ctrl->pdev, nonemb_cmd->size,
nonemb_cmd->va, nonemb_cmd->dma);
@@ -1348,7 +1351,6 @@ int mgmt_set_vlan(struct beiscsi_hba *phba,
{
int rc;
unsigned int tag;
- struct be_mcc_wrb *wrb = NULL;
tag = be_cmd_set_vlan(phba, vlan_tag);
if (!tag) {
@@ -1358,7 +1360,7 @@ int mgmt_set_vlan(struct beiscsi_hba *phba,
return -EBUSY;
}
- rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+ rc = beiscsi_mccq_compl(phba, tag, NULL, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
(BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX),
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index 65180e15de6e..315d6d6dcfc8 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -3878,7 +3878,7 @@ bfa_sfp_show_comp(struct bfa_sfp_s *sfp, struct bfi_mbmsg_s *msg)
bfa_trc(sfp, sfp->data_valid);
if (sfp->data_valid) {
u32 size = sizeof(struct sfp_mem_s);
- u8 *des = (u8 *) &(sfp->sfpmem->srlid_base);
+ u8 *des = (u8 *) &(sfp->sfpmem);
memcpy(des, sfp->dbuf_kva, size);
}
/*
@@ -6851,7 +6851,7 @@ static u32
bfa_flash_status_read(void __iomem *pci_bar)
{
union bfa_flash_dev_status_reg_u dev_status;
- u32 status;
+ int status;
u32 ret_status;
int i;
@@ -6899,7 +6899,7 @@ static u32
bfa_flash_read_start(void __iomem *pci_bar, u32 offset, u32 len,
char *buf)
{
- u32 status;
+ int status;
/*
* len must be mutiple of 4 and not exceeding fifo size
@@ -7006,7 +7006,7 @@ bfa_flash_sem_get(void __iomem *bar)
while (!bfa_raw_sem_get(bar)) {
if (--n <= 0)
return BFA_STATUS_BADFLASH;
- udelay(10000);
+ mdelay(10);
}
return BFA_STATUS_OK;
}
@@ -7021,7 +7021,8 @@ bfa_status_t
bfa_flash_raw_read(void __iomem *pci_bar, u32 offset, char *buf,
u32 len)
{
- u32 n, status;
+ u32 n;
+ int status;
u32 off, l, s, residue, fifo_sz;
residue = len;
diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c
index 157f6044a9bb..8994fb857ee9 100644
--- a/drivers/scsi/bfa/bfad_bsg.c
+++ b/drivers/scsi/bfa/bfad_bsg.c
@@ -2304,8 +2304,10 @@ bfad_iocmd_cfg_trunk(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
spin_lock_irqsave(&bfad->bfad_lock, flags);
- if (bfa_fcport_is_dport(&bfad->bfa))
+ if (bfa_fcport_is_dport(&bfad->bfa)) {
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
return BFA_STATUS_DPORT_ERR;
+ }
if ((fcport->cfg.topology == BFA_PORT_TOPOLOGY_LOOP) ||
(fcport->topology == BFA_PORT_TOPOLOGY_LOOP))
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index 9967f9c14851..f067332bf763 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -73,9 +73,14 @@ bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio,
break;
- case BFI_IOIM_STS_ABORTED:
case BFI_IOIM_STS_TIMEDOUT:
+ host_status = DID_TIME_OUT;
+ cmnd->result = ScsiResult(host_status, 0);
+ break;
case BFI_IOIM_STS_PATHTOV:
+ host_status = DID_TRANSPORT_DISRUPTED;
+ cmnd->result = ScsiResult(host_status, 0);
+ break;
default:
host_status = DID_ERROR;
cmnd->result = ScsiResult(host_status, 0);
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index 1ebf3fb683e6..6a976657b475 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -64,7 +64,7 @@
#include "bnx2fc_constants.h"
#define BNX2FC_NAME "bnx2fc"
-#define BNX2FC_VERSION "2.4.1"
+#define BNX2FC_VERSION "2.4.2"
#define PFX "bnx2fc: "
@@ -367,6 +367,7 @@ struct bnx2fc_rport {
atomic_t num_active_ios;
u32 flush_in_prog;
unsigned long timestamp;
+ unsigned long retry_delay_timestamp;
struct list_head free_task_list;
struct bnx2fc_cmd *pending_queue[BNX2FC_SQ_WQES_MAX+1];
struct list_head active_cmd_queue;
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index 9b948505d118..6287f6a8b79d 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -22,7 +22,7 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu);
#define DRV_MODULE_NAME "bnx2fc"
#define DRV_MODULE_VERSION BNX2FC_VERSION
-#define DRV_MODULE_RELDATE "Sep 17, 2013"
+#define DRV_MODULE_RELDATE "Dec 11, 2013"
static char version[] =
@@ -850,6 +850,9 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
__bnx2fc_destroy(interface);
}
mutex_unlock(&bnx2fc_dev_lock);
+
+ /* Ensure ALL destroy work has been completed before return */
+ flush_workqueue(bnx2fc_wq);
return;
default:
@@ -2389,6 +2392,9 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev)
__bnx2fc_destroy(interface);
mutex_unlock(&bnx2fc_dev_lock);
+ /* Ensure ALL destroy work has been completed before return */
+ flush_workqueue(bnx2fc_wq);
+
bnx2fc_ulp_stop(hba);
/* unregister cnic device */
if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic))
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index ed880891cb7c..32a5e0a2a669 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -594,13 +594,13 @@ static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req)
mp_req->mp_resp_bd = NULL;
}
if (mp_req->req_buf) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
mp_req->req_buf,
mp_req->req_buf_dma);
mp_req->req_buf = NULL;
}
if (mp_req->resp_buf) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
mp_req->resp_buf,
mp_req->resp_buf_dma);
mp_req->resp_buf = NULL;
@@ -622,7 +622,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
mp_req->req_len = sizeof(struct fcp_cmnd);
io_req->data_xfer_len = mp_req->req_len;
- mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&mp_req->req_buf_dma,
GFP_ATOMIC);
if (!mp_req->req_buf) {
@@ -631,7 +631,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
return FAILED;
}
- mp_req->resp_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ mp_req->resp_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&mp_req->resp_buf_dma,
GFP_ATOMIC);
if (!mp_req->resp_buf) {
@@ -639,8 +639,8 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
bnx2fc_free_mp_resc(io_req);
return FAILED;
}
- memset(mp_req->req_buf, 0, PAGE_SIZE);
- memset(mp_req->resp_buf, 0, PAGE_SIZE);
+ memset(mp_req->req_buf, 0, CNIC_PAGE_SIZE);
+ memset(mp_req->resp_buf, 0, CNIC_PAGE_SIZE);
/* Allocate and map mp_req_bd and mp_resp_bd */
sz = sizeof(struct fcoe_bd_ctx);
@@ -665,7 +665,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
mp_req_bd = mp_req->mp_req_bd;
mp_req_bd->buf_addr_lo = (u32)addr & 0xffffffff;
mp_req_bd->buf_addr_hi = (u32)((u64)addr >> 32);
- mp_req_bd->buf_len = PAGE_SIZE;
+ mp_req_bd->buf_len = CNIC_PAGE_SIZE;
mp_req_bd->flags = 0;
/*
@@ -677,7 +677,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
addr = mp_req->resp_buf_dma;
mp_resp_bd->buf_addr_lo = (u32)addr & 0xffffffff;
mp_resp_bd->buf_addr_hi = (u32)((u64)addr >> 32);
- mp_resp_bd->buf_len = PAGE_SIZE;
+ mp_resp_bd->buf_len = CNIC_PAGE_SIZE;
mp_resp_bd->flags = 0;
return SUCCESS;
@@ -1871,7 +1871,15 @@ int bnx2fc_queuecommand(struct Scsi_Host *host,
rc = SCSI_MLQUEUE_TARGET_BUSY;
goto exit_qcmd;
}
-
+ if (tgt->retry_delay_timestamp) {
+ if (time_after(jiffies, tgt->retry_delay_timestamp)) {
+ tgt->retry_delay_timestamp = 0;
+ } else {
+ /* If retry_delay timer is active, flow off the ML */
+ rc = SCSI_MLQUEUE_TARGET_BUSY;
+ goto exit_qcmd;
+ }
+ }
io_req = bnx2fc_cmd_alloc(tgt);
if (!io_req) {
rc = SCSI_MLQUEUE_HOST_BUSY;
@@ -1961,6 +1969,15 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
" fcp_resid = 0x%x\n",
io_req->cdb_status, io_req->fcp_resid);
sc_cmd->result = (DID_OK << 16) | io_req->cdb_status;
+
+ if (io_req->cdb_status == SAM_STAT_TASK_SET_FULL ||
+ io_req->cdb_status == SAM_STAT_BUSY) {
+ /* Set the jiffies + retry_delay_timer * 100ms
+ for the rport/tgt */
+ tgt->retry_delay_timestamp = jiffies +
+ fcp_rsp->retry_delay_timer * HZ / 10;
+ }
+
}
if (io_req->fcp_resid)
scsi_set_resid(sc_cmd, io_req->fcp_resid);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
index 4d93177dfb53..6870cf6781d9 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
@@ -386,6 +386,7 @@ static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt,
tgt->rq_prod_idx = 0x8000;
tgt->rq_cons_idx = 0;
atomic_set(&tgt->num_active_ios, 0);
+ tgt->retry_delay_timestamp = 0;
if (rdata->flags & FC_RP_FLAGS_RETRY &&
rdata->ids.roles & FC_RPORT_ROLE_FCP_TARGET &&
@@ -673,7 +674,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
/* Allocate and map SQ */
tgt->sq_mem_size = tgt->max_sqes * BNX2FC_SQ_WQE_SIZE;
- tgt->sq_mem_size = (tgt->sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ tgt->sq_mem_size = (tgt->sq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->sq = dma_alloc_coherent(&hba->pcidev->dev, tgt->sq_mem_size,
&tgt->sq_dma, GFP_KERNEL);
@@ -686,7 +688,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
/* Allocate and map CQ */
tgt->cq_mem_size = tgt->max_cqes * BNX2FC_CQ_WQE_SIZE;
- tgt->cq_mem_size = (tgt->cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ tgt->cq_mem_size = (tgt->cq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->cq = dma_alloc_coherent(&hba->pcidev->dev, tgt->cq_mem_size,
&tgt->cq_dma, GFP_KERNEL);
@@ -699,7 +702,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
/* Allocate and map RQ and RQ PBL */
tgt->rq_mem_size = tgt->max_rqes * BNX2FC_RQ_WQE_SIZE;
- tgt->rq_mem_size = (tgt->rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ tgt->rq_mem_size = (tgt->rq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->rq = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_mem_size,
&tgt->rq_dma, GFP_KERNEL);
@@ -710,8 +714,9 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
}
memset(tgt->rq, 0, tgt->rq_mem_size);
- tgt->rq_pbl_size = (tgt->rq_mem_size / PAGE_SIZE) * sizeof(void *);
- tgt->rq_pbl_size = (tgt->rq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ tgt->rq_pbl_size = (tgt->rq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
+ tgt->rq_pbl_size = (tgt->rq_pbl_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->rq_pbl = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_pbl_size,
&tgt->rq_pbl_dma, GFP_KERNEL);
@@ -722,7 +727,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
}
memset(tgt->rq_pbl, 0, tgt->rq_pbl_size);
- num_pages = tgt->rq_mem_size / PAGE_SIZE;
+ num_pages = tgt->rq_mem_size / CNIC_PAGE_SIZE;
page = tgt->rq_dma;
pbl = (u32 *)tgt->rq_pbl;
@@ -731,13 +736,13 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
pbl++;
*pbl = (u32)((u64)page >> 32);
pbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
}
/* Allocate and map XFERQ */
tgt->xferq_mem_size = tgt->max_sqes * BNX2FC_XFERQ_WQE_SIZE;
- tgt->xferq_mem_size = (tgt->xferq_mem_size + (PAGE_SIZE - 1)) &
- PAGE_MASK;
+ tgt->xferq_mem_size = (tgt->xferq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->xferq = dma_alloc_coherent(&hba->pcidev->dev, tgt->xferq_mem_size,
&tgt->xferq_dma, GFP_KERNEL);
@@ -750,8 +755,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
/* Allocate and map CONFQ & CONFQ PBL */
tgt->confq_mem_size = tgt->max_sqes * BNX2FC_CONFQ_WQE_SIZE;
- tgt->confq_mem_size = (tgt->confq_mem_size + (PAGE_SIZE - 1)) &
- PAGE_MASK;
+ tgt->confq_mem_size = (tgt->confq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->confq = dma_alloc_coherent(&hba->pcidev->dev, tgt->confq_mem_size,
&tgt->confq_dma, GFP_KERNEL);
@@ -763,9 +768,9 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
memset(tgt->confq, 0, tgt->confq_mem_size);
tgt->confq_pbl_size =
- (tgt->confq_mem_size / PAGE_SIZE) * sizeof(void *);
+ (tgt->confq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
tgt->confq_pbl_size =
- (tgt->confq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (tgt->confq_pbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
tgt->confq_pbl = dma_alloc_coherent(&hba->pcidev->dev,
tgt->confq_pbl_size,
@@ -777,7 +782,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
}
memset(tgt->confq_pbl, 0, tgt->confq_pbl_size);
- num_pages = tgt->confq_mem_size / PAGE_SIZE;
+ num_pages = tgt->confq_mem_size / CNIC_PAGE_SIZE;
page = tgt->confq_dma;
pbl = (u32 *)tgt->confq_pbl;
@@ -786,7 +791,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
pbl++;
*pbl = (u32)((u64)page >> 32);
pbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
}
/* Allocate and map ConnDB */
@@ -805,8 +810,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
/* Allocate and map LCQ */
tgt->lcq_mem_size = (tgt->max_sqes + 8) * BNX2FC_SQ_WQE_SIZE;
- tgt->lcq_mem_size = (tgt->lcq_mem_size + (PAGE_SIZE - 1)) &
- PAGE_MASK;
+ tgt->lcq_mem_size = (tgt->lcq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+ CNIC_PAGE_MASK;
tgt->lcq = dma_alloc_coherent(&hba->pcidev->dev, tgt->lcq_mem_size,
&tgt->lcq_dma, GFP_KERNEL);
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index e4cf23df4b4f..b5ffd280a1ae 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -61,7 +61,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
* yield integral num of page buffers
*/
/* adjust SQ */
- num_elements_per_pg = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+ num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
if (hba->max_sqes < num_elements_per_pg)
hba->max_sqes = num_elements_per_pg;
else if (hba->max_sqes % num_elements_per_pg)
@@ -69,7 +69,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
~(num_elements_per_pg - 1);
/* adjust CQ */
- num_elements_per_pg = PAGE_SIZE / BNX2I_CQE_SIZE;
+ num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_CQE_SIZE;
if (hba->max_cqes < num_elements_per_pg)
hba->max_cqes = num_elements_per_pg;
else if (hba->max_cqes % num_elements_per_pg)
@@ -77,7 +77,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
~(num_elements_per_pg - 1);
/* adjust RQ */
- num_elements_per_pg = PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
+ num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
if (hba->max_rqes < num_elements_per_pg)
hba->max_rqes = num_elements_per_pg;
else if (hba->max_rqes % num_elements_per_pg)
@@ -959,7 +959,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
/* SQ page table */
memset(ep->qp.sq_pgtbl_virt, 0, ep->qp.sq_pgtbl_size);
- num_pages = ep->qp.sq_mem_size / PAGE_SIZE;
+ num_pages = ep->qp.sq_mem_size / CNIC_PAGE_SIZE;
page = ep->qp.sq_phys;
if (cnic_dev_10g)
@@ -973,7 +973,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) ((u64) page >> 32);
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
} else {
/* PTE is written in big endian format for
* 5706/5708/5709 devices */
@@ -981,13 +981,13 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) page;
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
}
}
/* RQ page table */
memset(ep->qp.rq_pgtbl_virt, 0, ep->qp.rq_pgtbl_size);
- num_pages = ep->qp.rq_mem_size / PAGE_SIZE;
+ num_pages = ep->qp.rq_mem_size / CNIC_PAGE_SIZE;
page = ep->qp.rq_phys;
if (cnic_dev_10g)
@@ -1001,7 +1001,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) ((u64) page >> 32);
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
} else {
/* PTE is written in big endian format for
* 5706/5708/5709 devices */
@@ -1009,13 +1009,13 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) page;
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
}
}
/* CQ page table */
memset(ep->qp.cq_pgtbl_virt, 0, ep->qp.cq_pgtbl_size);
- num_pages = ep->qp.cq_mem_size / PAGE_SIZE;
+ num_pages = ep->qp.cq_mem_size / CNIC_PAGE_SIZE;
page = ep->qp.cq_phys;
if (cnic_dev_10g)
@@ -1029,7 +1029,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) ((u64) page >> 32);
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
} else {
/* PTE is written in big endian format for
* 5706/5708/5709 devices */
@@ -1037,7 +1037,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) page;
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
}
}
}
@@ -1064,11 +1064,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
/* Allocate page table memory for SQ which is page aligned */
ep->qp.sq_mem_size = hba->max_sqes * BNX2I_SQ_WQE_SIZE;
ep->qp.sq_mem_size =
- (ep->qp.sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.sq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.sq_pgtbl_size =
- (ep->qp.sq_mem_size / PAGE_SIZE) * sizeof(void *);
+ (ep->qp.sq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
ep->qp.sq_pgtbl_size =
- (ep->qp.sq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.sq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.sq_pgtbl_virt =
dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size,
@@ -1101,11 +1101,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
/* Allocate page table memory for CQ which is page aligned */
ep->qp.cq_mem_size = hba->max_cqes * BNX2I_CQE_SIZE;
ep->qp.cq_mem_size =
- (ep->qp.cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.cq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.cq_pgtbl_size =
- (ep->qp.cq_mem_size / PAGE_SIZE) * sizeof(void *);
+ (ep->qp.cq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
ep->qp.cq_pgtbl_size =
- (ep->qp.cq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.cq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.cq_pgtbl_virt =
dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size,
@@ -1144,11 +1144,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
/* Allocate page table memory for RQ which is page aligned */
ep->qp.rq_mem_size = hba->max_rqes * BNX2I_RQ_WQE_SIZE;
ep->qp.rq_mem_size =
- (ep->qp.rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.rq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.rq_pgtbl_size =
- (ep->qp.rq_mem_size / PAGE_SIZE) * sizeof(void *);
+ (ep->qp.rq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
ep->qp.rq_pgtbl_size =
- (ep->qp.rq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.rq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.rq_pgtbl_virt =
dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size,
@@ -1270,7 +1270,7 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
bnx2i_adjust_qp_size(hba);
iscsi_init.flags =
- ISCSI_PAGE_SIZE_4K << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
+ (CNIC_PAGE_BITS - 8) << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
if (en_tcp_dack)
iscsi_init.flags |= ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE;
iscsi_init.reserved0 = 0;
@@ -1288,15 +1288,15 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
((hba->num_ccell & 0xFFFF) | (hba->max_sqes << 16));
iscsi_init.num_ccells_per_conn = hba->num_ccell;
iscsi_init.num_tasks_per_conn = hba->max_sqes;
- iscsi_init.sq_wqes_per_page = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+ iscsi_init.sq_wqes_per_page = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
iscsi_init.sq_num_wqes = hba->max_sqes;
iscsi_init.cq_log_wqes_per_page =
- (u8) bnx2i_power_of2(PAGE_SIZE / BNX2I_CQE_SIZE);
+ (u8) bnx2i_power_of2(CNIC_PAGE_SIZE / BNX2I_CQE_SIZE);
iscsi_init.cq_num_wqes = hba->max_cqes;
iscsi_init.cq_num_pages = (hba->max_cqes * BNX2I_CQE_SIZE +
- (PAGE_SIZE - 1)) / PAGE_SIZE;
+ (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
iscsi_init.sq_num_pages = (hba->max_sqes * BNX2I_SQ_WQE_SIZE +
- (PAGE_SIZE - 1)) / PAGE_SIZE;
+ (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
iscsi_init.rq_buffer_size = BNX2I_RQ_WQE_SIZE;
iscsi_init.rq_num_wqes = hba->max_rqes;
@@ -1361,7 +1361,7 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
u32 datalen = 0;
resp_cqe = (struct bnx2i_cmd_response *)cqe;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->back_lock);
task = iscsi_itt_to_task(conn,
resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
if (!task)
@@ -1432,7 +1432,7 @@ done:
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
conn->data, datalen);
fail:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->back_lock);
return 0;
}
@@ -1457,7 +1457,7 @@ static int bnx2i_process_login_resp(struct iscsi_session *session,
int pad_len;
login = (struct bnx2i_login_response *) cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
login->itt & ISCSI_LOGIN_RESPONSE_INDEX);
if (!task)
@@ -1500,7 +1500,7 @@ static int bnx2i_process_login_resp(struct iscsi_session *session,
bnx2i_conn->gen_pdu.resp_buf,
bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf);
done:
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return 0;
}
@@ -1525,7 +1525,7 @@ static int bnx2i_process_text_resp(struct iscsi_session *session,
int pad_len;
text = (struct bnx2i_text_response *) cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn, text->itt & ISCSI_LOGIN_RESPONSE_INDEX);
if (!task)
goto done;
@@ -1561,7 +1561,7 @@ static int bnx2i_process_text_resp(struct iscsi_session *session,
bnx2i_conn->gen_pdu.resp_wr_ptr -
bnx2i_conn->gen_pdu.resp_buf);
done:
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return 0;
}
@@ -1584,7 +1584,7 @@ static int bnx2i_process_tmf_resp(struct iscsi_session *session,
struct iscsi_tm_rsp *resp_hdr;
tmf_cqe = (struct bnx2i_tmf_response *)cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
tmf_cqe->itt & ISCSI_TMF_RESPONSE_INDEX);
if (!task)
@@ -1600,7 +1600,7 @@ static int bnx2i_process_tmf_resp(struct iscsi_session *session,
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
done:
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return 0;
}
@@ -1623,7 +1623,7 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session,
struct iscsi_logout_rsp *resp_hdr;
logout = (struct bnx2i_logout_response *) cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
logout->itt & ISCSI_LOGOUT_RESPONSE_INDEX);
if (!task)
@@ -1647,7 +1647,7 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session,
bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD;
done:
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return 0;
}
@@ -1668,12 +1668,12 @@ static void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session,
struct iscsi_task *task;
nop_in = (struct bnx2i_nop_in_msg *)cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
nop_in->itt & ISCSI_NOP_IN_MSG_INDEX);
if (task)
__iscsi_put_task(task);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
}
/**
@@ -1712,7 +1712,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
nop_in = (struct bnx2i_nop_in_msg *)cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr;
memset(hdr, 0, sizeof(struct iscsi_hdr));
hdr->opcode = nop_in->op_code;
@@ -1738,7 +1738,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
}
done:
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return tgt_async_nop;
}
@@ -1771,7 +1771,7 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session,
return;
}
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
resp_hdr = (struct iscsi_async *) &bnx2i_conn->gen_pdu.resp_hdr;
memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
resp_hdr->opcode = async_cqe->op_code;
@@ -1790,7 +1790,7 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session,
__iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data,
(struct iscsi_hdr *)resp_hdr, NULL, 0);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
}
@@ -1817,7 +1817,7 @@ static void bnx2i_process_reject_mesg(struct iscsi_session *session,
} else
bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
hdr = (struct iscsi_reject *) &bnx2i_conn->gen_pdu.resp_hdr;
memset(hdr, 0, sizeof(struct iscsi_hdr));
hdr->opcode = reject->op_code;
@@ -1828,7 +1828,7 @@ static void bnx2i_process_reject_mesg(struct iscsi_session *session,
hdr->ffffffff = cpu_to_be32(RESERVED_ITT);
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data,
reject->data_length);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
}
/**
@@ -1848,13 +1848,13 @@ static void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session,
struct iscsi_task *task;
cmd_clean_rsp = (struct bnx2i_cleanup_response *)cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
if (!task)
printk(KERN_ALERT "bnx2i: cmd clean ITT %x not active\n",
cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
complete(&bnx2i_conn->cmd_cleanup_cmpl);
}
@@ -1921,11 +1921,11 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session,
int rc = 0;
int cpu;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data,
cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
if (!task || !task->sc) {
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return -EINVAL;
}
sc = task->sc;
@@ -1935,7 +1935,7 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session,
else
cpu = sc->request->cpu;
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
p = &per_cpu(bnx2i_percpu, cpu);
spin_lock(&p->p_work_lock);
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 854dad7d5b03..166543f7ef55 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -525,7 +525,7 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
struct iscsi_bd *mp_bdt;
u64 addr;
- hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&hba->mp_bd_dma, GFP_KERNEL);
if (!hba->mp_bd_tbl) {
printk(KERN_ERR "unable to allocate Middle Path BDT\n");
@@ -533,11 +533,12 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
goto out;
}
- hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev,
+ CNIC_PAGE_SIZE,
&hba->dummy_buf_dma, GFP_KERNEL);
if (!hba->dummy_buffer) {
printk(KERN_ERR "unable to alloc Middle Path Dummy Buffer\n");
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
hba->mp_bd_tbl, hba->mp_bd_dma);
hba->mp_bd_tbl = NULL;
rc = -1;
@@ -548,7 +549,7 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
addr = (unsigned long) hba->dummy_buf_dma;
mp_bdt->buffer_addr_lo = addr & 0xffffffff;
mp_bdt->buffer_addr_hi = addr >> 32;
- mp_bdt->buffer_length = PAGE_SIZE;
+ mp_bdt->buffer_length = CNIC_PAGE_SIZE;
mp_bdt->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
ISCSI_BD_FIRST_IN_BD_CHAIN;
out:
@@ -565,12 +566,12 @@ out:
static void bnx2i_free_mp_bdt(struct bnx2i_hba *hba)
{
if (hba->mp_bd_tbl) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
hba->mp_bd_tbl, hba->mp_bd_dma);
hba->mp_bd_tbl = NULL;
}
if (hba->dummy_buffer) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
hba->dummy_buffer, hba->dummy_buf_dma);
hba->dummy_buffer = NULL;
}
@@ -934,14 +935,14 @@ static void bnx2i_conn_free_login_resources(struct bnx2i_hba *hba,
struct bnx2i_conn *bnx2i_conn)
{
if (bnx2i_conn->gen_pdu.resp_bd_tbl) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
bnx2i_conn->gen_pdu.resp_bd_tbl,
bnx2i_conn->gen_pdu.resp_bd_dma);
bnx2i_conn->gen_pdu.resp_bd_tbl = NULL;
}
if (bnx2i_conn->gen_pdu.req_bd_tbl) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
bnx2i_conn->gen_pdu.req_bd_tbl,
bnx2i_conn->gen_pdu.req_bd_dma);
bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
@@ -998,13 +999,13 @@ static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba,
bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf;
bnx2i_conn->gen_pdu.req_bd_tbl =
- dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&bnx2i_conn->gen_pdu.req_bd_dma, GFP_KERNEL);
if (bnx2i_conn->gen_pdu.req_bd_tbl == NULL)
goto login_req_bd_tbl_failure;
bnx2i_conn->gen_pdu.resp_bd_tbl =
- dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&bnx2i_conn->gen_pdu.resp_bd_dma,
GFP_KERNEL);
if (bnx2i_conn->gen_pdu.resp_bd_tbl == NULL)
@@ -1013,7 +1014,7 @@ static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba,
return 0;
login_resp_bd_tbl_failure:
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
bnx2i_conn->gen_pdu.req_bd_tbl,
bnx2i_conn->gen_pdu.req_bd_dma);
bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
@@ -1169,10 +1170,10 @@ static void bnx2i_cleanup_task(struct iscsi_task *task)
if (task->state == ISCSI_TASK_ABRT_TMF) {
bnx2i_send_cmd_cleanup_req(hba, task->dd_data);
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->back_lock);
wait_for_completion_timeout(&bnx2i_conn->cmd_cleanup_cmpl,
msecs_to_jiffies(ISCSI_CMD_CLEANUP_TIMEOUT));
- spin_lock_bh(&conn->session->lock);
+ spin_lock_bh(&conn->session->back_lock);
}
bnx2i_iscsi_unmap_sg_list(task->dd_data);
}
@@ -2059,7 +2060,7 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
goto out;
if (session) {
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (bnx2i_ep->state != EP_STATE_TCP_FIN_RCVD) {
if (session->state == ISCSI_STATE_LOGGING_OUT) {
if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) {
@@ -2075,7 +2076,7 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
} else
close = 1;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
}
bnx2i_ep->state = EP_STATE_DISCONN_START;
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index 5a9f84238a53..e8ee5e5fe0ef 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -175,52 +175,6 @@ static inline int is_ofld_imm(const struct sk_buff *skb)
sizeof(struct fw_ofld_tx_data_wr));
}
-
-#define VLAN_NONE 0xfff
-#define FILTER_SEL_VLAN_NONE 0xffff
-#define FILTER_SEL_WIDTH_P_FC (3+1) /* port uses 3 bits, FCoE one bit */
-#define FILTER_SEL_WIDTH_VIN_P_FC \
- (6 + 7 + FILTER_SEL_WIDTH_P_FC) /* 6 bits are unused, VF uses 7 bits*/
-#define FILTER_SEL_WIDTH_TAG_P_FC \
- (3 + FILTER_SEL_WIDTH_VIN_P_FC) /* PF uses 3 bits */
-#define FILTER_SEL_WIDTH_VLD_TAG_P_FC (1 + FILTER_SEL_WIDTH_TAG_P_FC)
-
-static unsigned int select_ntuple(struct cxgbi_device *cdev,
- struct l2t_entry *l2t)
-{
- struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev);
- unsigned int ntuple = 0;
- u32 viid;
-
- switch (lldi->filt_mode) {
-
- /* default filter mode */
- case HW_TPL_FR_MT_PR_IV_P_FC:
- if (l2t->vlan == VLAN_NONE)
- ntuple |= FILTER_SEL_VLAN_NONE << FILTER_SEL_WIDTH_P_FC;
- else {
- ntuple |= l2t->vlan << FILTER_SEL_WIDTH_P_FC;
- ntuple |= 1 << FILTER_SEL_WIDTH_VLD_TAG_P_FC;
- }
- ntuple |= l2t->lport << S_PORT | IPPROTO_TCP <<
- FILTER_SEL_WIDTH_VLD_TAG_P_FC;
- break;
- case HW_TPL_FR_MT_PR_OV_P_FC: {
- viid = cxgb4_port_viid(l2t->neigh->dev);
-
- ntuple |= FW_VIID_VIN_GET(viid) << FILTER_SEL_WIDTH_P_FC;
- ntuple |= FW_VIID_PFN_GET(viid) << FILTER_SEL_WIDTH_VIN_P_FC;
- ntuple |= FW_VIID_VIVLD_GET(viid) << FILTER_SEL_WIDTH_TAG_P_FC;
- ntuple |= l2t->lport << S_PORT | IPPROTO_TCP <<
- FILTER_SEL_WIDTH_VLD_TAG_P_FC;
- break;
- }
- default:
- break;
- }
- return ntuple;
-}
-
static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb,
struct l2t_entry *e)
{
@@ -248,8 +202,6 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb,
struct cpl_act_open_req *req =
(struct cpl_act_open_req *)skb->head;
- req = (struct cpl_act_open_req *)skb->head;
-
INIT_TP_WR(req, 0);
OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ,
qid_atid));
@@ -258,7 +210,9 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb,
req->local_ip = csk->saddr.sin_addr.s_addr;
req->peer_ip = csk->daddr.sin_addr.s_addr;
req->opt0 = cpu_to_be64(opt0);
- req->params = cpu_to_be32(select_ntuple(csk->cdev, csk->l2t));
+ req->params = cpu_to_be32(cxgb4_select_ntuple(
+ csk->cdev->ports[csk->port_id],
+ csk->l2t));
opt2 |= 1 << 22;
req->opt2 = cpu_to_be32(opt2);
@@ -271,8 +225,6 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb,
struct cpl_t5_act_open_req *req =
(struct cpl_t5_act_open_req *)skb->head;
- req = (struct cpl_t5_act_open_req *)skb->head;
-
INIT_TP_WR(req, 0);
OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ,
qid_atid));
@@ -281,7 +233,10 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb,
req->local_ip = csk->saddr.sin_addr.s_addr;
req->peer_ip = csk->daddr.sin_addr.s_addr;
req->opt0 = cpu_to_be64(opt0);
- req->params = cpu_to_be32(select_ntuple(csk->cdev, csk->l2t));
+ req->params = cpu_to_be64(V_FILTER_TUPLE(
+ cxgb4_select_ntuple(
+ csk->cdev->ports[csk->port_id],
+ csk->l2t)));
opt2 |= 1 << 31;
req->opt2 = cpu_to_be32(opt2);
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index d01f01604140..eb29fe7eaf49 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -277,7 +277,7 @@ found:
/* With interrupts enabled, it will sometimes hang when doing heavy
* reads. So better not enable them until I finger it out. */
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, dtc_intr, IRQF_DISABLED,
+ 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 = SCSI_IRQ_NONE;
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index 94de88955a99..ebf57364df91 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -1221,7 +1221,7 @@ static int port_detect(unsigned long port_base, unsigned int j,
/* Board detected, allocate its IRQ */
if (request_irq(irq, do_interrupt_handler,
- IRQF_DISABLED | ((subversion == ESA) ? IRQF_SHARED : 0),
+ (subversion == ESA) ? IRQF_SHARED : 0,
driver_name, (void *)&sha[j])) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name,
irq);
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index 1663173cdb91..8319d2b417b8 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -687,7 +687,7 @@ static int register_pio_HBA(long base, struct get_conf *gc, struct pci_dev *pdev
return 0;
if (!reg_IRQ[gc->IRQ]) { /* Interrupt already registered ? */
- if (!request_irq(gc->IRQ, do_eata_pio_int_handler, IRQF_DISABLED, "EATA-PIO", sh)) {
+ if (!request_irq(gc->IRQ, do_eata_pio_int_handler, 0, "EATA-PIO", sh)) {
reg_IRQ[gc->IRQ]++;
if (!gc->IRQ_TR)
reg_IRQL[gc->IRQ] = 1; /* IRQ is edge triggered */
@@ -921,7 +921,7 @@ static int eata_pio_detect(struct scsi_host_template *tpnt)
for (i = 0; i < MAXIRQ; i++)
if (reg_IRQ[i])
- request_irq(i, do_eata_pio_int_handler, IRQF_DISABLED, "EATA-PIO", NULL);
+ request_irq(i, do_eata_pio_int_handler, 0, "EATA-PIO", NULL);
HBA_ptr = first_HBA;
diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c
index b9750e296d71..6776931e25d4 100644
--- a/drivers/scsi/esas2r/esas2r_init.c
+++ b/drivers/scsi/esas2r/esas2r_init.c
@@ -231,7 +231,7 @@ use_legacy_interrupts:
static void esas2r_claim_interrupts(struct esas2r_adapter *a)
{
- unsigned long flags = IRQF_DISABLED;
+ unsigned long flags = 0;
if (a->intr_mode == INTR_MODE_LEGACY)
flags |= IRQF_SHARED;
diff --git a/drivers/scsi/esas2r/esas2r_log.c b/drivers/scsi/esas2r/esas2r_log.c
index 9bf285df58dd..a82030aa8577 100644
--- a/drivers/scsi/esas2r/esas2r_log.c
+++ b/drivers/scsi/esas2r/esas2r_log.c
@@ -165,13 +165,9 @@ static int esas2r_log_master(const long level,
/*
* Put a line break at the end of the formatted string so that
- * we don't wind up with run-on messages. only append if there
- * is enough space in the buffer.
+ * we don't wind up with run-on messages.
*/
- if (strlen(event_buffer) < buflen)
- strcat(buffer, "\n");
-
- printk(event_buffer);
+ printk("%s\n", event_buffer);
spin_unlock_irqrestore(&event_buffer_lock, flags);
}
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 5cec6c60ca22..7176365e916b 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -461,7 +461,7 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt)
if (instance->irq != SCSI_IRQ_NONE)
if (request_irq(instance->irq, generic_NCR5380_intr,
- IRQF_DISABLED, "NCR5380", instance)) {
+ 0, "NCR5380", instance)) {
printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
}
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index ce5ef0190bad..0f1ae13ce7c7 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -4711,7 +4711,7 @@ static int __init gdth_isa_probe_one(u32 isa_bios)
printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
isa_bios, ha->irq, ha->drq);
- error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha);
+ error = request_irq(ha->irq, gdth_interrupt, 0, "gdth", ha);
if (error) {
printk("GDT-ISA: Unable to allocate IRQ\n");
goto out_host_put;
@@ -4843,7 +4843,7 @@ static int __init gdth_eisa_probe_one(u16 eisa_slot)
printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
eisa_slot >> 12, ha->irq);
- error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha);
+ error = request_irq(ha->irq, gdth_interrupt, 0, "gdth", ha);
if (error) {
printk("GDT-EISA: Unable to allocate IRQ\n");
goto out_host_put;
@@ -4979,7 +4979,7 @@ static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out)
ha->irq);
error = request_irq(ha->irq, gdth_interrupt,
- IRQF_DISABLED|IRQF_SHARED, "gdth", ha);
+ IRQF_SHARED, "gdth", ha);
if (error) {
printk("GDT-PCI: Unable to allocate IRQ\n");
goto out_host_put;
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index f28ea070d3df..3cbb57a8b846 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -398,7 +398,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost->ordered_tag = sht->ordered_tag;
shost->no_write_same = sht->no_write_same;
- if (shost_eh_deadline == -1)
+ if (shost_eh_deadline == -1 || !sht->eh_host_reset_handler)
shost->eh_deadline = -1;
else if ((ulong) shost_eh_deadline * HZ > INT_MAX) {
shost_printk(KERN_WARNING, shost,
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 868318a7067c..8cf4a0c69baf 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1,6 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
- * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P.
+ * Copyright 2000, 2014 Hewlett-Packard Development Company, L.P.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -47,13 +47,13 @@
#include <linux/string.h>
#include <linux/bitmap.h>
#include <linux/atomic.h>
-#include <linux/kthread.h>
#include <linux/jiffies.h>
+#include <asm/div64.h>
#include "hpsa_cmd.h"
#include "hpsa.h"
/* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */
-#define HPSA_DRIVER_VERSION "3.4.0-1"
+#define HPSA_DRIVER_VERSION "3.4.4-1"
#define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
#define HPSA "hpsa"
@@ -118,6 +118,11 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C7},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C8},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C9},
+ {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0076},
+ {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0087},
+ {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x007D},
+ {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0088},
+ {PCI_VENDOR_ID_HP, 0x333f, 0x103c, 0x333f},
{PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
{0,}
@@ -163,6 +168,11 @@ static struct board_type products[] = {
{0x21C7103C, "Smart Array", &SA5_access},
{0x21C8103C, "Smart Array", &SA5_access},
{0x21C9103C, "Smart Array", &SA5_access},
+ {0x00761590, "HP Storage P1224 Array Controller", &SA5_access},
+ {0x00871590, "HP Storage P1224e Array Controller", &SA5_access},
+ {0x007D1590, "HP Storage P1228 Array Controller", &SA5_access},
+ {0x00881590, "HP Storage P1228e Array Controller", &SA5_access},
+ {0x333f103c, "HP StorageWorks 1210m Array Controller", &SA5_access},
{0xFFFF103C, "Unknown Smart Array", &SA5_access},
};
@@ -182,8 +192,9 @@ static void cmd_special_free(struct ctlr_info *h, struct CommandList *c);
static struct CommandList *cmd_alloc(struct ctlr_info *h);
static struct CommandList *cmd_special_alloc(struct ctlr_info *h);
static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
- void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
+ void *buff, size_t size, u16 page_code, unsigned char *scsi3addr,
int cmd_type);
+#define VPD_PAGE (1 << 8)
static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static void hpsa_scan_start(struct Scsi_Host *);
@@ -204,7 +215,7 @@ static void check_ioctl_unit_attention(struct ctlr_info *h,
struct CommandList *c);
/* performant mode helper functions */
static void calc_bucket_map(int *bucket, int num_buckets,
- int nsgs, int *bucket_map);
+ int nsgs, int min_blocks, int *bucket_map);
static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
static inline u32 next_command(struct ctlr_info *h, u8 q);
static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr,
@@ -216,8 +227,14 @@ static int hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
static int hpsa_wait_for_board_state(struct pci_dev *pdev, void __iomem *vaddr,
int wait_for_ready);
static inline void finish_cmd(struct CommandList *c);
+static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h);
#define BOARD_NOT_READY 0
#define BOARD_READY 1
+static void hpsa_drain_accel_commands(struct ctlr_info *h);
+static void hpsa_flush_cache(struct ctlr_info *h);
+static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
+ struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
+ u8 *scsi3addr);
static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
{
@@ -280,6 +297,55 @@ static int check_for_busy(struct ctlr_info *h, struct CommandList *c)
return 1;
}
+static ssize_t host_store_hp_ssd_smart_path_status(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int status, len;
+ struct ctlr_info *h;
+ struct Scsi_Host *shost = class_to_shost(dev);
+ char tmpbuf[10];
+
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count;
+ strncpy(tmpbuf, buf, len);
+ tmpbuf[len] = '\0';
+ if (sscanf(tmpbuf, "%d", &status) != 1)
+ return -EINVAL;
+ h = shost_to_hba(shost);
+ h->acciopath_status = !!status;
+ dev_warn(&h->pdev->dev,
+ "hpsa: HP SSD Smart Path %s via sysfs update.\n",
+ h->acciopath_status ? "enabled" : "disabled");
+ return count;
+}
+
+static ssize_t host_store_raid_offload_debug(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int debug_level, len;
+ struct ctlr_info *h;
+ struct Scsi_Host *shost = class_to_shost(dev);
+ char tmpbuf[10];
+
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count;
+ strncpy(tmpbuf, buf, len);
+ tmpbuf[len] = '\0';
+ if (sscanf(tmpbuf, "%d", &debug_level) != 1)
+ return -EINVAL;
+ if (debug_level < 0)
+ debug_level = 0;
+ h = shost_to_hba(shost);
+ h->raid_offload_debug = debug_level;
+ dev_warn(&h->pdev->dev, "hpsa: Set raid_offload_debug level = %d\n",
+ h->raid_offload_debug);
+ return count;
+}
+
static ssize_t host_store_rescan(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -327,6 +393,17 @@ static ssize_t host_show_transport_mode(struct device *dev,
"performant" : "simple");
}
+static ssize_t host_show_hp_ssd_smart_path_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ctlr_info *h;
+ struct Scsi_Host *shost = class_to_shost(dev);
+
+ h = shost_to_hba(shost);
+ return snprintf(buf, 30, "HP SSD Smart Path %s\n",
+ (h->acciopath_status == 1) ? "enabled" : "disabled");
+}
+
/* List of controllers which cannot be hard reset on kexec with reset_devices */
static u32 unresettable_controller[] = {
0x324a103C, /* Smart Array P712m */
@@ -416,6 +493,13 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
"1(ADM)", "UNKNOWN"
};
+#define HPSA_RAID_0 0
+#define HPSA_RAID_4 1
+#define HPSA_RAID_1 2 /* also used for RAID 10 */
+#define HPSA_RAID_5 3 /* also used for RAID 50 */
+#define HPSA_RAID_51 4
+#define HPSA_RAID_6 5 /* also used for RAID 60 */
+#define HPSA_RAID_ADM 6 /* also used for RAID 1+0 ADM */
#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 1)
static ssize_t raid_level_show(struct device *dev,
@@ -504,10 +588,39 @@ static ssize_t unique_id_show(struct device *dev,
sn[12], sn[13], sn[14], sn[15]);
}
+static ssize_t host_show_hp_ssd_smart_path_enabled(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ctlr_info *h;
+ struct scsi_device *sdev;
+ struct hpsa_scsi_dev_t *hdev;
+ unsigned long flags;
+ int offload_enabled;
+
+ sdev = to_scsi_device(dev);
+ h = sdev_to_hba(sdev);
+ spin_lock_irqsave(&h->lock, flags);
+ hdev = sdev->hostdata;
+ if (!hdev) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ return -ENODEV;
+ }
+ offload_enabled = hdev->offload_enabled;
+ spin_unlock_irqrestore(&h->lock, flags);
+ return snprintf(buf, 20, "%d\n", offload_enabled);
+}
+
static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL);
static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
+static DEVICE_ATTR(hp_ssd_smart_path_enabled, S_IRUGO,
+ host_show_hp_ssd_smart_path_enabled, NULL);
+static DEVICE_ATTR(hp_ssd_smart_path_status, S_IWUSR|S_IRUGO|S_IROTH,
+ host_show_hp_ssd_smart_path_status,
+ host_store_hp_ssd_smart_path_status);
+static DEVICE_ATTR(raid_offload_debug, S_IWUSR, NULL,
+ host_store_raid_offload_debug);
static DEVICE_ATTR(firmware_revision, S_IRUGO,
host_show_firmware_revision, NULL);
static DEVICE_ATTR(commands_outstanding, S_IRUGO,
@@ -521,6 +634,7 @@ static struct device_attribute *hpsa_sdev_attrs[] = {
&dev_attr_raid_level,
&dev_attr_lunid,
&dev_attr_unique_id,
+ &dev_attr_hp_ssd_smart_path_enabled,
NULL,
};
@@ -530,6 +644,8 @@ static struct device_attribute *hpsa_shost_attrs[] = {
&dev_attr_commands_outstanding,
&dev_attr_transport_mode,
&dev_attr_resettable,
+ &dev_attr_hp_ssd_smart_path_status,
+ &dev_attr_raid_offload_debug,
NULL,
};
@@ -570,6 +686,9 @@ static inline u32 next_command(struct ctlr_info *h, u8 q)
struct reply_pool *rq = &h->reply_queue[q];
unsigned long flags;
+ if (h->transMethod & CFGTBL_Trans_io_accel1)
+ return h->access.command_completed(h, q);
+
if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
return h->access.command_completed(h, q);
@@ -590,6 +709,32 @@ static inline u32 next_command(struct ctlr_info *h, u8 q)
return a;
}
+/*
+ * There are some special bits in the bus address of the
+ * command that we have to set for the controller to know
+ * how to process the command:
+ *
+ * Normal performant mode:
+ * bit 0: 1 means performant mode, 0 means simple mode.
+ * bits 1-3 = block fetch table entry
+ * bits 4-6 = command type (== 0)
+ *
+ * ioaccel1 mode:
+ * bit 0 = "performant mode" bit.
+ * bits 1-3 = block fetch table entry
+ * bits 4-6 = command type (== 110)
+ * (command type is needed because ioaccel1 mode
+ * commands are submitted through the same register as normal
+ * mode commands, so this is how the controller knows whether
+ * the command is normal mode or ioaccel1 mode.)
+ *
+ * ioaccel2 mode:
+ * bit 0 = "performant mode" bit.
+ * bits 1-4 = block fetch table entry (note extra bit)
+ * bits 4-6 = not needed, because ioaccel2 mode has
+ * a separate special register for submitting commands.
+ */
+
/* set_performant_mode: Modify the tag for cciss performant
* set bit 0 for pull model, bits 3-1 for block fetch
* register number
@@ -598,12 +743,47 @@ static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
{
if (likely(h->transMethod & CFGTBL_Trans_Performant)) {
c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
- if (likely(h->msix_vector))
+ if (likely(h->msix_vector > 0))
c->Header.ReplyQueue =
raw_smp_processor_id() % h->nreply_queues;
}
}
+static void set_ioaccel1_performant_mode(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex];
+
+ /* Tell the controller to post the reply to the queue for this
+ * processor. This seems to give the best I/O throughput.
+ */
+ cp->ReplyQueue = smp_processor_id() % h->nreply_queues;
+ /* Set the bits in the address sent down to include:
+ * - performant mode bit (bit 0)
+ * - pull count (bits 1-3)
+ * - command type (bits 4-6)
+ */
+ c->busaddr |= 1 | (h->ioaccel1_blockFetchTable[c->Header.SGList] << 1) |
+ IOACCEL1_BUSADDR_CMDTYPE;
+}
+
+static void set_ioaccel2_performant_mode(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex];
+
+ /* Tell the controller to post the reply to the queue for this
+ * processor. This seems to give the best I/O throughput.
+ */
+ cp->reply_queue = smp_processor_id() % h->nreply_queues;
+ /* Set the bits in the address sent down to include:
+ * - performant mode bit not used in ioaccel mode 2
+ * - pull count (bits 0-3)
+ * - command type isn't needed for ioaccel2
+ */
+ c->busaddr |= (h->ioaccel2_blockFetchTable[cp->sg_count]);
+}
+
static int is_firmware_flash_cmd(u8 *cdb)
{
return cdb[0] == BMIC_WRITE && cdb[6] == BMIC_FLASH_FIRMWARE;
@@ -638,7 +818,16 @@ static void enqueue_cmd_and_start_io(struct ctlr_info *h,
{
unsigned long flags;
- set_performant_mode(h, c);
+ switch (c->cmd_type) {
+ case CMD_IOACCEL1:
+ set_ioaccel1_performant_mode(h, c);
+ break;
+ case CMD_IOACCEL2:
+ set_ioaccel2_performant_mode(h, c);
+ break;
+ default:
+ set_performant_mode(h, c);
+ }
dial_down_lockup_detection_during_fw_flash(h, c);
spin_lock_irqsave(&h->lock, flags);
addQ(&h->reqQ, c);
@@ -782,6 +971,14 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno,
/* Raid level changed. */
h->dev[entry]->raid_level = new_entry->raid_level;
+
+ /* Raid offload parameters changed. */
+ h->dev[entry]->offload_config = new_entry->offload_config;
+ h->dev[entry]->offload_enabled = new_entry->offload_enabled;
+ h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle;
+ h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror;
+ h->dev[entry]->raid_map = new_entry->raid_map;
+
dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d updated.\n",
scsi_device_type(new_entry->devtype), hostno, new_entry->bus,
new_entry->target, new_entry->lun);
@@ -902,6 +1099,10 @@ static inline int device_updated(struct hpsa_scsi_dev_t *dev1,
*/
if (dev1->raid_level != dev2->raid_level)
return 1;
+ if (dev1->offload_config != dev2->offload_config)
+ return 1;
+ if (dev1->offload_enabled != dev2->offload_enabled)
+ return 1;
return 0;
}
@@ -932,6 +1133,9 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
return DEVICE_UPDATED;
return DEVICE_SAME;
} else {
+ /* Keep offline devices offline */
+ if (needle->volume_offline)
+ return DEVICE_NOT_FOUND;
return DEVICE_CHANGED;
}
}
@@ -940,6 +1144,110 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
return DEVICE_NOT_FOUND;
}
+static void hpsa_monitor_offline_device(struct ctlr_info *h,
+ unsigned char scsi3addr[])
+{
+ struct offline_device_entry *device;
+ unsigned long flags;
+
+ /* Check to see if device is already on the list */
+ spin_lock_irqsave(&h->offline_device_lock, flags);
+ list_for_each_entry(device, &h->offline_device_list, offline_list) {
+ if (memcmp(device->scsi3addr, scsi3addr,
+ sizeof(device->scsi3addr)) == 0) {
+ spin_unlock_irqrestore(&h->offline_device_lock, flags);
+ return;
+ }
+ }
+ spin_unlock_irqrestore(&h->offline_device_lock, flags);
+
+ /* Device is not on the list, add it. */
+ device = kmalloc(sizeof(*device), GFP_KERNEL);
+ if (!device) {
+ dev_warn(&h->pdev->dev, "out of memory in %s\n", __func__);
+ return;
+ }
+ memcpy(device->scsi3addr, scsi3addr, sizeof(device->scsi3addr));
+ spin_lock_irqsave(&h->offline_device_lock, flags);
+ list_add_tail(&device->offline_list, &h->offline_device_list);
+ spin_unlock_irqrestore(&h->offline_device_lock, flags);
+}
+
+/* Print a message explaining various offline volume states */
+static void hpsa_show_volume_status(struct ctlr_info *h,
+ struct hpsa_scsi_dev_t *sd)
+{
+ if (sd->volume_offline == HPSA_VPD_LV_STATUS_UNSUPPORTED)
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume status is not available through vital product data pages.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ switch (sd->volume_offline) {
+ case HPSA_LV_OK:
+ break;
+ case HPSA_LV_UNDERGOING_ERASE:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is undergoing background erase process.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_UNDERGOING_RPI:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is undergoing rapid parity initialization process.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_PENDING_RPI:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is queued for rapid parity initialization process.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_ENCRYPTED_NO_KEY:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is encrypted and cannot be accessed because key is not present.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is not encrypted and cannot be accessed because controller is in encryption-only mode.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_UNDERGOING_ENCRYPTION:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is undergoing encryption process.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_UNDERGOING_ENCRYPTION_REKEYING:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is undergoing encryption re-keying process.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is encrypted and cannot be accessed because controller does not have encryption enabled.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_PENDING_ENCRYPTION:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is pending migration to encrypted state, but process has not started.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ case HPSA_LV_PENDING_ENCRYPTION_REKEYING:
+ dev_info(&h->pdev->dev,
+ "C%d:B%d:T%d:L%d Volume is encrypted and is pending encryption rekeying.\n",
+ h->scsi_host->host_no,
+ sd->bus, sd->target, sd->lun);
+ break;
+ }
+}
+
static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
struct hpsa_scsi_dev_t *sd[], int nsds)
{
@@ -1004,6 +1312,20 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
for (i = 0; i < nsds; i++) {
if (!sd[i]) /* if already added above. */
continue;
+
+ /* Don't add devices which are NOT READY, FORMAT IN PROGRESS
+ * as the SCSI mid-layer does not handle such devices well.
+ * It relentlessly loops sending TUR at 3Hz, then READ(10)
+ * at 160Hz, and prevents the system from coming up.
+ */
+ if (sd[i]->volume_offline) {
+ hpsa_show_volume_status(h, sd[i]);
+ dev_info(&h->pdev->dev, "c%db%dt%dl%d: temporarily offline\n",
+ h->scsi_host->host_no,
+ sd[i]->bus, sd[i]->target, sd[i]->lun);
+ continue;
+ }
+
device_change = hpsa_scsi_find_entry(sd[i], h->dev,
h->ndevices, &entry);
if (device_change == DEVICE_NOT_FOUND) {
@@ -1022,6 +1344,17 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
}
spin_unlock_irqrestore(&h->devlock, flags);
+ /* Monitor devices which are in one of several NOT READY states to be
+ * brought online later. This must be done without holding h->devlock,
+ * so don't touch h->dev[]
+ */
+ for (i = 0; i < nsds; i++) {
+ if (!sd[i]) /* if already added above. */
+ continue;
+ if (sd[i]->volume_offline)
+ hpsa_monitor_offline_device(h, sd[i]->scsi3addr);
+ }
+
/* Don't notify scsi mid layer of any changes the first time through
* (or if there are no changes) scsi_scan_host will do it later the
* first time through.
@@ -1187,11 +1520,163 @@ static void hpsa_unmap_sg_chain_block(struct ctlr_info *h,
pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE);
}
+
+/* Decode the various types of errors on ioaccel2 path.
+ * Return 1 for any error that should generate a RAID path retry.
+ * Return 0 for errors that don't require a RAID path retry.
+ */
+static int handle_ioaccel_mode2_error(struct ctlr_info *h,
+ struct CommandList *c,
+ struct scsi_cmnd *cmd,
+ struct io_accel2_cmd *c2)
+{
+ int data_len;
+ int retry = 0;
+
+ switch (c2->error_data.serv_response) {
+ case IOACCEL2_SERV_RESPONSE_COMPLETE:
+ switch (c2->error_data.status) {
+ case IOACCEL2_STATUS_SR_TASK_COMP_GOOD:
+ break;
+ case IOACCEL2_STATUS_SR_TASK_COMP_CHK_COND:
+ dev_warn(&h->pdev->dev,
+ "%s: task complete with check condition.\n",
+ "HP SSD Smart Path");
+ if (c2->error_data.data_present !=
+ IOACCEL2_SENSE_DATA_PRESENT)
+ break;
+ /* copy the sense data */
+ data_len = c2->error_data.sense_data_len;
+ if (data_len > SCSI_SENSE_BUFFERSIZE)
+ data_len = SCSI_SENSE_BUFFERSIZE;
+ if (data_len > sizeof(c2->error_data.sense_data_buff))
+ data_len =
+ sizeof(c2->error_data.sense_data_buff);
+ memcpy(cmd->sense_buffer,
+ c2->error_data.sense_data_buff, data_len);
+ cmd->result |= SAM_STAT_CHECK_CONDITION;
+ retry = 1;
+ break;
+ case IOACCEL2_STATUS_SR_TASK_COMP_BUSY:
+ dev_warn(&h->pdev->dev,
+ "%s: task complete with BUSY status.\n",
+ "HP SSD Smart Path");
+ retry = 1;
+ break;
+ case IOACCEL2_STATUS_SR_TASK_COMP_RES_CON:
+ dev_warn(&h->pdev->dev,
+ "%s: task complete with reservation conflict.\n",
+ "HP SSD Smart Path");
+ retry = 1;
+ break;
+ case IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL:
+ /* Make scsi midlayer do unlimited retries */
+ cmd->result = DID_IMM_RETRY << 16;
+ break;
+ case IOACCEL2_STATUS_SR_TASK_COMP_ABORTED:
+ dev_warn(&h->pdev->dev,
+ "%s: task complete with aborted status.\n",
+ "HP SSD Smart Path");
+ retry = 1;
+ break;
+ default:
+ dev_warn(&h->pdev->dev,
+ "%s: task complete with unrecognized status: 0x%02x\n",
+ "HP SSD Smart Path", c2->error_data.status);
+ retry = 1;
+ break;
+ }
+ break;
+ case IOACCEL2_SERV_RESPONSE_FAILURE:
+ /* don't expect to get here. */
+ dev_warn(&h->pdev->dev,
+ "unexpected delivery or target failure, status = 0x%02x\n",
+ c2->error_data.status);
+ retry = 1;
+ break;
+ case IOACCEL2_SERV_RESPONSE_TMF_COMPLETE:
+ break;
+ case IOACCEL2_SERV_RESPONSE_TMF_SUCCESS:
+ break;
+ case IOACCEL2_SERV_RESPONSE_TMF_REJECTED:
+ dev_warn(&h->pdev->dev, "task management function rejected.\n");
+ retry = 1;
+ break;
+ case IOACCEL2_SERV_RESPONSE_TMF_WRONG_LUN:
+ dev_warn(&h->pdev->dev, "task management function invalid LUN\n");
+ break;
+ default:
+ dev_warn(&h->pdev->dev,
+ "%s: Unrecognized server response: 0x%02x\n",
+ "HP SSD Smart Path",
+ c2->error_data.serv_response);
+ retry = 1;
+ break;
+ }
+
+ return retry; /* retry on raid path? */
+}
+
+static void process_ioaccel2_completion(struct ctlr_info *h,
+ struct CommandList *c, struct scsi_cmnd *cmd,
+ struct hpsa_scsi_dev_t *dev)
+{
+ struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
+ int raid_retry = 0;
+
+ /* check for good status */
+ if (likely(c2->error_data.serv_response == 0 &&
+ c2->error_data.status == 0)) {
+ cmd_free(h, c);
+ cmd->scsi_done(cmd);
+ return;
+ }
+
+ /* Any RAID offload error results in retry which will use
+ * the normal I/O path so the controller can handle whatever's
+ * wrong.
+ */
+ if (is_logical_dev_addr_mode(dev->scsi3addr) &&
+ c2->error_data.serv_response ==
+ IOACCEL2_SERV_RESPONSE_FAILURE) {
+ if (c2->error_data.status ==
+ IOACCEL2_STATUS_SR_IOACCEL_DISABLED)
+ dev_warn(&h->pdev->dev,
+ "%s: Path is unavailable, retrying on standard path.\n",
+ "HP SSD Smart Path");
+ else
+ dev_warn(&h->pdev->dev,
+ "%s: Error 0x%02x, retrying on standard path.\n",
+ "HP SSD Smart Path", c2->error_data.status);
+
+ dev->offload_enabled = 0;
+ h->drv_req_rescan = 1; /* schedule controller for a rescan */
+ cmd->result = DID_SOFT_ERROR << 16;
+ cmd_free(h, c);
+ cmd->scsi_done(cmd);
+ return;
+ }
+ raid_retry = handle_ioaccel_mode2_error(h, c, cmd, c2);
+ /* If error found, disable Smart Path, schedule a rescan,
+ * and force a retry on the standard path.
+ */
+ if (raid_retry) {
+ dev_warn(&h->pdev->dev, "%s: Retrying on standard path.\n",
+ "HP SSD Smart Path");
+ dev->offload_enabled = 0; /* Disable Smart Path */
+ h->drv_req_rescan = 1; /* schedule controller rescan */
+ cmd->result = DID_SOFT_ERROR << 16;
+ }
+ cmd_free(h, c);
+ cmd->scsi_done(cmd);
+}
+
static void complete_scsi_command(struct CommandList *cp)
{
struct scsi_cmnd *cmd;
struct ctlr_info *h;
struct ErrorInfo *ei;
+ struct hpsa_scsi_dev_t *dev;
unsigned char sense_key;
unsigned char asc; /* additional sense code */
@@ -1201,13 +1686,19 @@ static void complete_scsi_command(struct CommandList *cp)
ei = cp->err_info;
cmd = (struct scsi_cmnd *) cp->scsi_cmd;
h = cp->h;
+ dev = cmd->device->hostdata;
scsi_dma_unmap(cmd); /* undo the DMA mappings */
- if (cp->Header.SGTotal > h->max_cmd_sg_entries)
+ if ((cp->cmd_type == CMD_SCSI) &&
+ (cp->Header.SGTotal > h->max_cmd_sg_entries))
hpsa_unmap_sg_chain_block(h, cp);
cmd->result = (DID_OK << 16); /* host byte */
cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
+
+ if (cp->cmd_type == CMD_IOACCEL2)
+ return process_ioaccel2_completion(h, cp, cmd, dev);
+
cmd->result |= ei->ScsiStatus;
/* copy the sense data whether we need to or not. */
@@ -1227,6 +1718,32 @@ static void complete_scsi_command(struct CommandList *cp)
return;
}
+ /* For I/O accelerator commands, copy over some fields to the normal
+ * CISS header used below for error handling.
+ */
+ if (cp->cmd_type == CMD_IOACCEL1) {
+ struct io_accel1_cmd *c = &h->ioaccel_cmd_pool[cp->cmdindex];
+ cp->Header.SGList = cp->Header.SGTotal = scsi_sg_count(cmd);
+ cp->Request.CDBLen = c->io_flags & IOACCEL1_IOFLAGS_CDBLEN_MASK;
+ cp->Header.Tag.lower = c->Tag.lower;
+ cp->Header.Tag.upper = c->Tag.upper;
+ memcpy(cp->Header.LUN.LunAddrBytes, c->CISS_LUN, 8);
+ memcpy(cp->Request.CDB, c->CDB, cp->Request.CDBLen);
+
+ /* Any RAID offload error results in retry which will use
+ * the normal I/O path so the controller can handle whatever's
+ * wrong.
+ */
+ if (is_logical_dev_addr_mode(dev->scsi3addr)) {
+ if (ei->CommandStatus == CMD_IOACCEL_DISABLED)
+ dev->offload_enabled = 0;
+ cmd->result = DID_SOFT_ERROR << 16;
+ cmd_free(h, cp);
+ cmd->scsi_done(cmd);
+ return;
+ }
+ }
+
/* an error has occurred */
switch (ei->CommandStatus) {
@@ -1389,6 +1906,14 @@ static void complete_scsi_command(struct CommandList *cp)
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "Command unabortable\n");
break;
+ case CMD_IOACCEL_DISABLED:
+ /* This only handles the direct pass-through case since RAID
+ * offload is handled above. Just attempt a retry.
+ */
+ cmd->result = DID_SOFT_ERROR << 16;
+ dev_warn(&h->pdev->dev,
+ "cp %p had HP SSD Smart Path error\n", cp);
+ break;
default:
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n",
@@ -1438,6 +1963,7 @@ static int hpsa_map_one(struct pci_dev *pdev,
cp->SG[0].Addr.upper =
(u32) ((addr64 >> 32) & (u64) 0x00000000FFFFFFFF);
cp->SG[0].Len = buflen;
+ cp->SG[0].Ext = HPSA_SG_LAST; /* we are not chaining */
cp->Header.SGList = (u8) 1; /* no. SGs contig in this cmd */
cp->Header.SGTotal = (u16) 1; /* total sgs in this cmd list */
return 0;
@@ -1490,17 +2016,37 @@ static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h,
hpsa_pci_unmap(h->pdev, c, 1, data_direction);
}
-static void hpsa_scsi_interpret_error(struct CommandList *cp)
+static void hpsa_print_cmd(struct ctlr_info *h, char *txt,
+ struct CommandList *c)
{
- struct ErrorInfo *ei;
+ const u8 *cdb = c->Request.CDB;
+ const u8 *lun = c->Header.LUN.LunAddrBytes;
+
+ dev_warn(&h->pdev->dev, "%s: LUN:%02x%02x%02x%02x%02x%02x%02x%02x"
+ " CDB:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ txt, lun[0], lun[1], lun[2], lun[3],
+ lun[4], lun[5], lun[6], lun[7],
+ cdb[0], cdb[1], cdb[2], cdb[3],
+ cdb[4], cdb[5], cdb[6], cdb[7],
+ cdb[8], cdb[9], cdb[10], cdb[11],
+ cdb[12], cdb[13], cdb[14], cdb[15]);
+}
+
+static void hpsa_scsi_interpret_error(struct ctlr_info *h,
+ struct CommandList *cp)
+{
+ const struct ErrorInfo *ei = cp->err_info;
struct device *d = &cp->h->pdev->dev;
+ const u8 *sd = ei->SenseInfo;
- ei = cp->err_info;
switch (ei->CommandStatus) {
case CMD_TARGET_STATUS:
- dev_warn(d, "cmd %p has completed with errors\n", cp);
- dev_warn(d, "cmd %p has SCSI Status = %x\n", cp,
- ei->ScsiStatus);
+ hpsa_print_cmd(h, "SCSI status", cp);
+ if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION)
+ dev_warn(d, "SCSI Status = 02, Sense key = %02x, ASC = %02x, ASCQ = %02x\n",
+ sd[2] & 0x0f, sd[12], sd[13]);
+ else
+ dev_warn(d, "SCSI Status = %02x\n", ei->ScsiStatus);
if (ei->ScsiStatus == 0)
dev_warn(d, "SCSI status is abnormally zero. "
"(probably indicates selection timeout "
@@ -1508,54 +2054,51 @@ static void hpsa_scsi_interpret_error(struct CommandList *cp)
"firmware bug, circa July, 2001.)\n");
break;
case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
- dev_info(d, "UNDERRUN\n");
break;
case CMD_DATA_OVERRUN:
- dev_warn(d, "cp %p has completed with data overrun\n", cp);
+ hpsa_print_cmd(h, "overrun condition", cp);
break;
case CMD_INVALID: {
/* controller unfortunately reports SCSI passthru's
* to non-existent targets as invalid commands.
*/
- dev_warn(d, "cp %p is reported invalid (probably means "
- "target device no longer present)\n", cp);
- /* print_bytes((unsigned char *) cp, sizeof(*cp), 1, 0);
- print_cmd(cp); */
+ hpsa_print_cmd(h, "invalid command", cp);
+ dev_warn(d, "probably means device no longer present\n");
}
break;
case CMD_PROTOCOL_ERR:
- dev_warn(d, "cp %p has protocol error \n", cp);
+ hpsa_print_cmd(h, "protocol error", cp);
break;
case CMD_HARDWARE_ERR:
- /* cmd->result = DID_ERROR << 16; */
- dev_warn(d, "cp %p had hardware error\n", cp);
+ hpsa_print_cmd(h, "hardware error", cp);
break;
case CMD_CONNECTION_LOST:
- dev_warn(d, "cp %p had connection lost\n", cp);
+ hpsa_print_cmd(h, "connection lost", cp);
break;
case CMD_ABORTED:
- dev_warn(d, "cp %p was aborted\n", cp);
+ hpsa_print_cmd(h, "aborted", cp);
break;
case CMD_ABORT_FAILED:
- dev_warn(d, "cp %p reports abort failed\n", cp);
+ hpsa_print_cmd(h, "abort failed", cp);
break;
case CMD_UNSOLICITED_ABORT:
- dev_warn(d, "cp %p aborted due to an unsolicited abort\n", cp);
+ hpsa_print_cmd(h, "unsolicited abort", cp);
break;
case CMD_TIMEOUT:
- dev_warn(d, "cp %p timed out\n", cp);
+ hpsa_print_cmd(h, "timed out", cp);
break;
case CMD_UNABORTABLE:
- dev_warn(d, "Command unabortable\n");
+ hpsa_print_cmd(h, "unabortable", cp);
break;
default:
- dev_warn(d, "cp %p returned unknown status %x\n", cp,
+ hpsa_print_cmd(h, "unknown status", cp);
+ dev_warn(d, "Unknown command status %x\n",
ei->CommandStatus);
}
}
static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
- unsigned char page, unsigned char *buf,
+ u16 page, unsigned char *buf,
unsigned char bufsize)
{
int rc = IO_OK;
@@ -1577,7 +2120,7 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE);
ei = c->err_info;
if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
- hpsa_scsi_interpret_error(c);
+ hpsa_scsi_interpret_error(h, c);
rc = -1;
}
out:
@@ -1585,7 +2128,39 @@ out:
return rc;
}
-static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr)
+static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h,
+ unsigned char *scsi3addr, unsigned char page,
+ struct bmic_controller_parameters *buf, size_t bufsize)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_special_alloc(h);
+
+ if (c == NULL) { /* trouble... */
+ dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ return -ENOMEM;
+ }
+
+ if (fill_cmd(c, BMIC_SENSE_CONTROLLER_PARAMETERS, h, buf, bufsize,
+ page, scsi3addr, TYPE_CMD)) {
+ rc = -1;
+ goto out;
+ }
+ hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE);
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ hpsa_scsi_interpret_error(h, c);
+ rc = -1;
+ }
+out:
+ cmd_special_free(h, c);
+ return rc;
+ }
+
+static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
+ u8 reset_type)
{
int rc = IO_OK;
struct CommandList *c;
@@ -1599,14 +2174,15 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr)
}
/* fill_cmd can't fail here, no data buffer to map. */
- (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h,
- NULL, 0, 0, scsi3addr, TYPE_MSG);
+ (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0,
+ scsi3addr, TYPE_MSG);
+ c->Request.CDB[1] = reset_type; /* fill_cmd defaults to LUN reset */
hpsa_scsi_do_simple_cmd_core(h, c);
/* no unmap needed here because no data xfer. */
ei = c->err_info;
if (ei->CommandStatus != 0) {
- hpsa_scsi_interpret_error(c);
+ hpsa_scsi_interpret_error(h, c);
rc = -1;
}
cmd_special_free(h, c);
@@ -1623,7 +2199,7 @@ 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, 0xC1, buf, 64);
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0xC1, buf, 64);
if (rc == 0)
*raid_level = buf[8];
if (*raid_level > RAID_UNKNOWN)
@@ -1632,6 +2208,204 @@ static void hpsa_get_raid_level(struct ctlr_info *h,
return;
}
+#define HPSA_MAP_DEBUG
+#ifdef HPSA_MAP_DEBUG
+static void hpsa_debug_map_buff(struct ctlr_info *h, int rc,
+ struct raid_map_data *map_buff)
+{
+ struct raid_map_disk_data *dd = &map_buff->data[0];
+ int map, row, col;
+ u16 map_cnt, row_cnt, disks_per_row;
+
+ if (rc != 0)
+ return;
+
+ /* Show details only if debugging has been activated. */
+ if (h->raid_offload_debug < 2)
+ return;
+
+ dev_info(&h->pdev->dev, "structure_size = %u\n",
+ le32_to_cpu(map_buff->structure_size));
+ dev_info(&h->pdev->dev, "volume_blk_size = %u\n",
+ le32_to_cpu(map_buff->volume_blk_size));
+ dev_info(&h->pdev->dev, "volume_blk_cnt = 0x%llx\n",
+ le64_to_cpu(map_buff->volume_blk_cnt));
+ dev_info(&h->pdev->dev, "physicalBlockShift = %u\n",
+ map_buff->phys_blk_shift);
+ dev_info(&h->pdev->dev, "parity_rotation_shift = %u\n",
+ map_buff->parity_rotation_shift);
+ dev_info(&h->pdev->dev, "strip_size = %u\n",
+ le16_to_cpu(map_buff->strip_size));
+ dev_info(&h->pdev->dev, "disk_starting_blk = 0x%llx\n",
+ le64_to_cpu(map_buff->disk_starting_blk));
+ dev_info(&h->pdev->dev, "disk_blk_cnt = 0x%llx\n",
+ le64_to_cpu(map_buff->disk_blk_cnt));
+ dev_info(&h->pdev->dev, "data_disks_per_row = %u\n",
+ le16_to_cpu(map_buff->data_disks_per_row));
+ dev_info(&h->pdev->dev, "metadata_disks_per_row = %u\n",
+ le16_to_cpu(map_buff->metadata_disks_per_row));
+ dev_info(&h->pdev->dev, "row_cnt = %u\n",
+ le16_to_cpu(map_buff->row_cnt));
+ dev_info(&h->pdev->dev, "layout_map_count = %u\n",
+ le16_to_cpu(map_buff->layout_map_count));
+ dev_info(&h->pdev->dev, "flags = %u\n",
+ le16_to_cpu(map_buff->flags));
+ if (map_buff->flags & RAID_MAP_FLAG_ENCRYPT_ON)
+ dev_info(&h->pdev->dev, "encrypytion = ON\n");
+ else
+ dev_info(&h->pdev->dev, "encrypytion = OFF\n");
+ dev_info(&h->pdev->dev, "dekindex = %u\n",
+ le16_to_cpu(map_buff->dekindex));
+
+ map_cnt = le16_to_cpu(map_buff->layout_map_count);
+ for (map = 0; map < map_cnt; map++) {
+ dev_info(&h->pdev->dev, "Map%u:\n", map);
+ row_cnt = le16_to_cpu(map_buff->row_cnt);
+ for (row = 0; row < row_cnt; row++) {
+ dev_info(&h->pdev->dev, " Row%u:\n", row);
+ disks_per_row =
+ le16_to_cpu(map_buff->data_disks_per_row);
+ for (col = 0; col < disks_per_row; col++, dd++)
+ dev_info(&h->pdev->dev,
+ " D%02u: h=0x%04x xor=%u,%u\n",
+ col, dd->ioaccel_handle,
+ dd->xor_mult[0], dd->xor_mult[1]);
+ disks_per_row =
+ le16_to_cpu(map_buff->metadata_disks_per_row);
+ for (col = 0; col < disks_per_row; col++, dd++)
+ dev_info(&h->pdev->dev,
+ " M%02u: h=0x%04x xor=%u,%u\n",
+ col, dd->ioaccel_handle,
+ dd->xor_mult[0], dd->xor_mult[1]);
+ }
+ }
+}
+#else
+static void hpsa_debug_map_buff(__attribute__((unused)) struct ctlr_info *h,
+ __attribute__((unused)) int rc,
+ __attribute__((unused)) struct raid_map_data *map_buff)
+{
+}
+#endif
+
+static int hpsa_get_raid_map(struct ctlr_info *h,
+ unsigned char *scsi3addr, struct hpsa_scsi_dev_t *this_device)
+{
+ int rc = 0;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_special_alloc(h);
+ if (c == NULL) {
+ dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ return -ENOMEM;
+ }
+ if (fill_cmd(c, HPSA_GET_RAID_MAP, h, &this_device->raid_map,
+ sizeof(this_device->raid_map), 0,
+ scsi3addr, TYPE_CMD)) {
+ dev_warn(&h->pdev->dev, "Out of memory in hpsa_get_raid_map()\n");
+ cmd_special_free(h, c);
+ return -ENOMEM;
+ }
+ hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE);
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ hpsa_scsi_interpret_error(h, c);
+ cmd_special_free(h, c);
+ return -1;
+ }
+ cmd_special_free(h, c);
+
+ /* @todo in the future, dynamically allocate RAID map memory */
+ if (le32_to_cpu(this_device->raid_map.structure_size) >
+ sizeof(this_device->raid_map)) {
+ dev_warn(&h->pdev->dev, "RAID map size is too large!\n");
+ rc = -1;
+ }
+ hpsa_debug_map_buff(h, rc, &this_device->raid_map);
+ return rc;
+}
+
+static int hpsa_vpd_page_supported(struct ctlr_info *h,
+ unsigned char scsi3addr[], u8 page)
+{
+ int rc;
+ int i;
+ int pages;
+ unsigned char *buf, bufsize;
+
+ buf = kzalloc(256, GFP_KERNEL);
+ if (!buf)
+ return 0;
+
+ /* Get the size of the page list first */
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr,
+ VPD_PAGE | HPSA_VPD_SUPPORTED_PAGES,
+ buf, HPSA_VPD_HEADER_SZ);
+ if (rc != 0)
+ goto exit_unsupported;
+ pages = buf[3];
+ if ((pages + HPSA_VPD_HEADER_SZ) <= 255)
+ bufsize = pages + HPSA_VPD_HEADER_SZ;
+ else
+ bufsize = 255;
+
+ /* Get the whole VPD page list */
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr,
+ VPD_PAGE | HPSA_VPD_SUPPORTED_PAGES,
+ buf, bufsize);
+ if (rc != 0)
+ goto exit_unsupported;
+
+ pages = buf[3];
+ for (i = 1; i <= pages; i++)
+ if (buf[3 + i] == page)
+ goto exit_supported;
+exit_unsupported:
+ kfree(buf);
+ return 0;
+exit_supported:
+ kfree(buf);
+ return 1;
+}
+
+static void hpsa_get_ioaccel_status(struct ctlr_info *h,
+ unsigned char *scsi3addr, struct hpsa_scsi_dev_t *this_device)
+{
+ int rc;
+ unsigned char *buf;
+ u8 ioaccel_status;
+
+ this_device->offload_config = 0;
+ this_device->offload_enabled = 0;
+
+ buf = kzalloc(64, GFP_KERNEL);
+ if (!buf)
+ return;
+ if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_IOACCEL_STATUS))
+ goto out;
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr,
+ VPD_PAGE | HPSA_VPD_LV_IOACCEL_STATUS, buf, 64);
+ if (rc != 0)
+ goto out;
+
+#define IOACCEL_STATUS_BYTE 4
+#define OFFLOAD_CONFIGURED_BIT 0x01
+#define OFFLOAD_ENABLED_BIT 0x02
+ ioaccel_status = buf[IOACCEL_STATUS_BYTE];
+ this_device->offload_config =
+ !!(ioaccel_status & OFFLOAD_CONFIGURED_BIT);
+ if (this_device->offload_config) {
+ this_device->offload_enabled =
+ !!(ioaccel_status & OFFLOAD_ENABLED_BIT);
+ if (hpsa_get_raid_map(h, scsi3addr, this_device))
+ this_device->offload_enabled = 0;
+ }
+out:
+ kfree(buf);
+ return;
+}
+
/* Get the device id from inquiry page 0x83 */
static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
unsigned char *device_id, int buflen)
@@ -1644,7 +2418,7 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
buf = kzalloc(64, GFP_KERNEL);
if (!buf)
return -1;
- rc = hpsa_scsi_do_inquiry(h, scsi3addr, 0x83, buf, 64);
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0x83, buf, 64);
if (rc == 0)
memcpy(device_id, &buf[8], buflen);
kfree(buf);
@@ -1678,8 +2452,16 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
ei = c->err_info;
if (ei->CommandStatus != 0 &&
ei->CommandStatus != CMD_DATA_UNDERRUN) {
- hpsa_scsi_interpret_error(c);
+ hpsa_scsi_interpret_error(h, c);
rc = -1;
+ } else {
+ if (buf->extended_response_flag != extended_response) {
+ dev_err(&h->pdev->dev,
+ "report luns requested format %u, got %u\n",
+ extended_response,
+ buf->extended_response_flag);
+ rc = -1;
+ }
}
out:
cmd_special_free(h, c);
@@ -1707,6 +2489,117 @@ static inline void hpsa_set_bus_target_lun(struct hpsa_scsi_dev_t *device,
device->lun = lun;
}
+/* Use VPD inquiry to get details of volume status */
+static int hpsa_get_volume_status(struct ctlr_info *h,
+ unsigned char scsi3addr[])
+{
+ int rc;
+ int status;
+ int size;
+ unsigned char *buf;
+
+ buf = kzalloc(64, GFP_KERNEL);
+ if (!buf)
+ return HPSA_VPD_LV_STATUS_UNSUPPORTED;
+
+ /* Does controller have VPD for logical volume status? */
+ if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_STATUS)) {
+ dev_warn(&h->pdev->dev, "Logical volume status VPD page is unsupported.\n");
+ goto exit_failed;
+ }
+
+ /* Get the size of the VPD return buffer */
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | HPSA_VPD_LV_STATUS,
+ buf, HPSA_VPD_HEADER_SZ);
+ if (rc != 0) {
+ dev_warn(&h->pdev->dev, "Logical volume status VPD inquiry failed.\n");
+ goto exit_failed;
+ }
+ size = buf[3];
+
+ /* Now get the whole VPD buffer */
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | HPSA_VPD_LV_STATUS,
+ buf, size + HPSA_VPD_HEADER_SZ);
+ if (rc != 0) {
+ dev_warn(&h->pdev->dev, "Logical volume status VPD inquiry failed.\n");
+ goto exit_failed;
+ }
+ status = buf[4]; /* status byte */
+
+ kfree(buf);
+ return status;
+exit_failed:
+ kfree(buf);
+ return HPSA_VPD_LV_STATUS_UNSUPPORTED;
+}
+
+/* Determine offline status of a volume.
+ * Return either:
+ * 0 (not offline)
+ * -1 (offline for unknown reasons)
+ * # (integer code indicating one of several NOT READY states
+ * describing why a volume is to be kept offline)
+ */
+static unsigned char hpsa_volume_offline(struct ctlr_info *h,
+ unsigned char scsi3addr[])
+{
+ struct CommandList *c;
+ unsigned char *sense, sense_key, asc, ascq;
+ int ldstat = 0;
+ u16 cmd_status;
+ u8 scsi_status;
+#define ASC_LUN_NOT_READY 0x04
+#define ASCQ_LUN_NOT_READY_FORMAT_IN_PROGRESS 0x04
+#define ASCQ_LUN_NOT_READY_INITIALIZING_CMD_REQ 0x02
+
+ c = cmd_alloc(h);
+ if (!c)
+ return 0;
+ (void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, scsi3addr, TYPE_CMD);
+ hpsa_scsi_do_simple_cmd_core(h, c);
+ sense = c->err_info->SenseInfo;
+ sense_key = sense[2];
+ asc = sense[12];
+ ascq = sense[13];
+ cmd_status = c->err_info->CommandStatus;
+ scsi_status = c->err_info->ScsiStatus;
+ cmd_free(h, c);
+ /* Is the volume 'not ready'? */
+ if (cmd_status != CMD_TARGET_STATUS ||
+ scsi_status != SAM_STAT_CHECK_CONDITION ||
+ sense_key != NOT_READY ||
+ asc != ASC_LUN_NOT_READY) {
+ return 0;
+ }
+
+ /* Determine the reason for not ready state */
+ ldstat = hpsa_get_volume_status(h, scsi3addr);
+
+ /* Keep volume offline in certain cases: */
+ switch (ldstat) {
+ case HPSA_LV_UNDERGOING_ERASE:
+ case HPSA_LV_UNDERGOING_RPI:
+ case HPSA_LV_PENDING_RPI:
+ case HPSA_LV_ENCRYPTED_NO_KEY:
+ case HPSA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER:
+ case HPSA_LV_UNDERGOING_ENCRYPTION:
+ case HPSA_LV_UNDERGOING_ENCRYPTION_REKEYING:
+ case HPSA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
+ return ldstat;
+ case HPSA_VPD_LV_STATUS_UNSUPPORTED:
+ /* If VPD status page isn't available,
+ * use ASC/ASCQ to determine state
+ */
+ if ((ascq == ASCQ_LUN_NOT_READY_FORMAT_IN_PROGRESS) ||
+ (ascq == ASCQ_LUN_NOT_READY_INITIALIZING_CMD_REQ))
+ return ldstat;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
static int hpsa_update_device_info(struct ctlr_info *h,
unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device,
unsigned char *is_OBDR_device)
@@ -1745,10 +2638,18 @@ static int hpsa_update_device_info(struct ctlr_info *h,
sizeof(this_device->device_id));
if (this_device->devtype == TYPE_DISK &&
- is_logical_dev_addr_mode(scsi3addr))
+ is_logical_dev_addr_mode(scsi3addr)) {
hpsa_get_raid_level(h, scsi3addr, &this_device->raid_level);
- else
+ if (h->fw_support & MISC_FW_RAID_OFFLOAD_BASIC)
+ hpsa_get_ioaccel_status(h, scsi3addr, this_device);
+ this_device->volume_offline =
+ hpsa_volume_offline(h, scsi3addr);
+ } else {
this_device->raid_level = RAID_UNKNOWN;
+ this_device->offload_config = 0;
+ this_device->offload_enabled = 0;
+ this_device->volume_offline = 0;
+ }
if (is_OBDR_device) {
/* See if this is a One-Button-Disaster-Recovery device
@@ -1878,6 +2779,105 @@ static int add_ext_target_dev(struct ctlr_info *h,
}
/*
+ * Get address of physical disk used for an ioaccel2 mode command:
+ * 1. Extract ioaccel2 handle from the command.
+ * 2. Find a matching ioaccel2 handle from list of physical disks.
+ * 3. Return:
+ * 1 and set scsi3addr to address of matching physical
+ * 0 if no matching physical disk was found.
+ */
+static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
+ struct CommandList *ioaccel2_cmd_to_abort, unsigned char *scsi3addr)
+{
+ struct ReportExtendedLUNdata *physicals = NULL;
+ int responsesize = 24; /* size of physical extended response */
+ int extended = 2; /* flag forces reporting 'other dev info'. */
+ int reportsize = sizeof(*physicals) + HPSA_MAX_PHYS_LUN * responsesize;
+ u32 nphysicals = 0; /* number of reported physical devs */
+ int found = 0; /* found match (1) or not (0) */
+ u32 find; /* handle we need to match */
+ int i;
+ struct scsi_cmnd *scmd; /* scsi command within request being aborted */
+ struct hpsa_scsi_dev_t *d; /* device of request being aborted */
+ struct io_accel2_cmd *c2a; /* ioaccel2 command to abort */
+ u32 it_nexus; /* 4 byte device handle for the ioaccel2 cmd */
+ u32 scsi_nexus; /* 4 byte device handle for the ioaccel2 cmd */
+
+ if (ioaccel2_cmd_to_abort->cmd_type != CMD_IOACCEL2)
+ return 0; /* no match */
+
+ /* point to the ioaccel2 device handle */
+ c2a = &h->ioaccel2_cmd_pool[ioaccel2_cmd_to_abort->cmdindex];
+ if (c2a == NULL)
+ return 0; /* no match */
+
+ scmd = (struct scsi_cmnd *) ioaccel2_cmd_to_abort->scsi_cmd;
+ if (scmd == NULL)
+ return 0; /* no match */
+
+ d = scmd->device->hostdata;
+ if (d == NULL)
+ return 0; /* no match */
+
+ it_nexus = cpu_to_le32((u32) d->ioaccel_handle);
+ scsi_nexus = cpu_to_le32((u32) c2a->scsi_nexus);
+ find = c2a->scsi_nexus;
+
+ if (h->raid_offload_debug > 0)
+ dev_info(&h->pdev->dev,
+ "%s: scsi_nexus:0x%08x device id: 0x%02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n",
+ __func__, scsi_nexus,
+ d->device_id[0], d->device_id[1], d->device_id[2],
+ d->device_id[3], d->device_id[4], d->device_id[5],
+ d->device_id[6], d->device_id[7], d->device_id[8],
+ d->device_id[9], d->device_id[10], d->device_id[11],
+ d->device_id[12], d->device_id[13], d->device_id[14],
+ d->device_id[15]);
+
+ /* Get the list of physical devices */
+ physicals = kzalloc(reportsize, GFP_KERNEL);
+ if (hpsa_scsi_do_report_phys_luns(h, (struct ReportLUNdata *) physicals,
+ reportsize, extended)) {
+ dev_err(&h->pdev->dev,
+ "Can't lookup %s device handle: report physical LUNs failed.\n",
+ "HP SSD Smart Path");
+ kfree(physicals);
+ return 0;
+ }
+ nphysicals = be32_to_cpu(*((__be32 *)physicals->LUNListLength)) /
+ responsesize;
+
+
+ /* find ioaccel2 handle in list of physicals: */
+ for (i = 0; i < nphysicals; i++) {
+ /* handle is in bytes 28-31 of each lun */
+ if (memcmp(&((struct ReportExtendedLUNdata *)
+ physicals)->LUN[i][20], &find, 4) != 0) {
+ continue; /* didn't match */
+ }
+ found = 1;
+ memcpy(scsi3addr, &((struct ReportExtendedLUNdata *)
+ physicals)->LUN[i][0], 8);
+ if (h->raid_offload_debug > 0)
+ dev_info(&h->pdev->dev,
+ "%s: Searched h=0x%08x, Found h=0x%08x, scsiaddr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ __func__, find,
+ ((struct ReportExtendedLUNdata *)
+ physicals)->LUN[i][20],
+ scsi3addr[0], scsi3addr[1], scsi3addr[2],
+ scsi3addr[3], scsi3addr[4], scsi3addr[5],
+ scsi3addr[6], scsi3addr[7]);
+ break; /* found it */
+ }
+
+ kfree(physicals);
+ if (found)
+ return 1;
+ else
+ return 0;
+
+}
+/*
* Do CISS_REPORT_PHYS and CISS_REPORT_LOG. Data is returned in physdev,
* logdev. The number of luns in physdev and logdev are returned in
* *nphysicals and *nlogicals, respectively.
@@ -1885,14 +2885,26 @@ static int add_ext_target_dev(struct ctlr_info *h,
*/
static int hpsa_gather_lun_info(struct ctlr_info *h,
int reportlunsize,
- struct ReportLUNdata *physdev, u32 *nphysicals,
+ struct ReportLUNdata *physdev, u32 *nphysicals, int *physical_mode,
struct ReportLUNdata *logdev, u32 *nlogicals)
{
- if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize, 0)) {
+ int physical_entry_size = 8;
+
+ *physical_mode = 0;
+
+ /* For I/O accelerator mode we need to read physical device handles */
+ if (h->transMethod & CFGTBL_Trans_io_accel1 ||
+ h->transMethod & CFGTBL_Trans_io_accel2) {
+ *physical_mode = HPSA_REPORT_PHYS_EXTENDED;
+ physical_entry_size = 24;
+ }
+ if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize,
+ *physical_mode)) {
dev_err(&h->pdev->dev, "report physical LUNs failed.\n");
return -1;
}
- *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 8;
+ *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) /
+ physical_entry_size;
if (*nphysicals > HPSA_MAX_PHYS_LUN) {
dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded."
" %d LUNs ignored.\n", HPSA_MAX_PHYS_LUN,
@@ -1923,7 +2935,8 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
}
u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i,
- int nphysicals, int nlogicals, struct ReportLUNdata *physdev_list,
+ int nphysicals, int nlogicals,
+ struct ReportExtendedLUNdata *physdev_list,
struct ReportLUNdata *logdev_list)
{
/* Helper function, figure out where the LUN ID info is coming from
@@ -1947,6 +2960,24 @@ u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i,
return NULL;
}
+static int hpsa_hba_mode_enabled(struct ctlr_info *h)
+{
+ int rc;
+ struct bmic_controller_parameters *ctlr_params;
+ ctlr_params = kzalloc(sizeof(struct bmic_controller_parameters),
+ GFP_KERNEL);
+
+ if (!ctlr_params)
+ return 0;
+ rc = hpsa_bmic_ctrl_mode_sense(h, RAID_CTLR_LUNID, 0, ctlr_params,
+ sizeof(struct bmic_controller_parameters));
+ if (rc != 0) {
+ kfree(ctlr_params);
+ return 0;
+ }
+ return ctlr_params->nvram_flags & (1 << 3) ? 1 : 0;
+}
+
static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
{
/* the idea here is we could get notified
@@ -1959,16 +2990,18 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
* tell which devices we already know about, vs. new
* devices, vs. disappearing devices.
*/
- struct ReportLUNdata *physdev_list = NULL;
+ struct ReportExtendedLUNdata *physdev_list = NULL;
struct ReportLUNdata *logdev_list = NULL;
u32 nphysicals = 0;
u32 nlogicals = 0;
+ int physical_mode = 0;
u32 ndev_allocated = 0;
struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice;
int ncurrent = 0;
- int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 8;
+ int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 24;
int i, n_ext_target_devs, ndevs_to_allocate;
int raid_ctlr_position;
+ u8 rescan_hba_mode;
DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS);
currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL);
@@ -1982,8 +3015,18 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
}
memset(lunzerobits, 0, sizeof(lunzerobits));
- if (hpsa_gather_lun_info(h, reportlunsize, physdev_list, &nphysicals,
- logdev_list, &nlogicals))
+ rescan_hba_mode = hpsa_hba_mode_enabled(h);
+
+ if (!h->hba_mode_enabled && rescan_hba_mode)
+ dev_warn(&h->pdev->dev, "HBA mode enabled\n");
+ else if (h->hba_mode_enabled && !rescan_hba_mode)
+ dev_warn(&h->pdev->dev, "HBA mode disabled\n");
+
+ h->hba_mode_enabled = rescan_hba_mode;
+
+ if (hpsa_gather_lun_info(h, reportlunsize,
+ (struct ReportLUNdata *) physdev_list, &nphysicals,
+ &physical_mode, logdev_list, &nlogicals))
goto out;
/* We might see up to the maximum number of logical and physical disks
@@ -2064,9 +3107,28 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
ncurrent++;
break;
case TYPE_DISK:
- if (i < nphysicals)
+ if (h->hba_mode_enabled) {
+ /* never use raid mapper in HBA mode */
+ this_device->offload_enabled = 0;
+ ncurrent++;
break;
- ncurrent++;
+ } else if (h->acciopath_status) {
+ if (i >= nphysicals) {
+ ncurrent++;
+ break;
+ }
+ } else {
+ if (i < nphysicals)
+ break;
+ ncurrent++;
+ break;
+ }
+ if (physical_mode == HPSA_REPORT_PHYS_EXTENDED) {
+ memcpy(&this_device->ioaccel_handle,
+ &lunaddrbytes[20],
+ sizeof(this_device->ioaccel_handle));
+ ncurrent++;
+ }
break;
case TYPE_TAPE:
case TYPE_MEDIUM_CHANGER:
@@ -2136,7 +3198,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h,
curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL);
curr_sg->Addr.upper = (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL);
curr_sg->Len = len;
- curr_sg->Ext = 0; /* we are not chaining */
+ curr_sg->Ext = (i < scsi_sg_count(cmd) - 1) ? 0 : HPSA_SG_LAST;
curr_sg++;
}
@@ -2160,6 +3222,726 @@ sglist_finished:
return 0;
}
+#define IO_ACCEL_INELIGIBLE (1)
+static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
+{
+ int is_write = 0;
+ u32 block;
+ u32 block_cnt;
+
+ /* Perform some CDB fixups if needed using 10 byte reads/writes only */
+ switch (cdb[0]) {
+ case WRITE_6:
+ case WRITE_12:
+ is_write = 1;
+ case READ_6:
+ case READ_12:
+ if (*cdb_len == 6) {
+ block = (((u32) cdb[2]) << 8) | cdb[3];
+ block_cnt = cdb[4];
+ } else {
+ BUG_ON(*cdb_len != 12);
+ block = (((u32) cdb[2]) << 24) |
+ (((u32) cdb[3]) << 16) |
+ (((u32) cdb[4]) << 8) |
+ cdb[5];
+ block_cnt =
+ (((u32) cdb[6]) << 24) |
+ (((u32) cdb[7]) << 16) |
+ (((u32) cdb[8]) << 8) |
+ cdb[9];
+ }
+ if (block_cnt > 0xffff)
+ return IO_ACCEL_INELIGIBLE;
+
+ cdb[0] = is_write ? WRITE_10 : READ_10;
+ cdb[1] = 0;
+ cdb[2] = (u8) (block >> 24);
+ cdb[3] = (u8) (block >> 16);
+ cdb[4] = (u8) (block >> 8);
+ cdb[5] = (u8) (block);
+ cdb[6] = 0;
+ cdb[7] = (u8) (block_cnt >> 8);
+ cdb[8] = (u8) (block_cnt);
+ cdb[9] = 0;
+ *cdb_len = 10;
+ break;
+ }
+ return 0;
+}
+
+static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h,
+ struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
+ u8 *scsi3addr)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex];
+ unsigned int len;
+ unsigned int total_len = 0;
+ struct scatterlist *sg;
+ u64 addr64;
+ int use_sg, i;
+ struct SGDescriptor *curr_sg;
+ u32 control = IOACCEL1_CONTROL_SIMPLEQUEUE;
+
+ /* TODO: implement chaining support */
+ if (scsi_sg_count(cmd) > h->ioaccel_maxsg)
+ return IO_ACCEL_INELIGIBLE;
+
+ BUG_ON(cmd->cmd_len > IOACCEL1_IOFLAGS_CDBLEN_MAX);
+
+ if (fixup_ioaccel_cdb(cdb, &cdb_len))
+ return IO_ACCEL_INELIGIBLE;
+
+ c->cmd_type = CMD_IOACCEL1;
+
+ /* Adjust the DMA address to point to the accelerated command buffer */
+ c->busaddr = (u32) h->ioaccel_cmd_pool_dhandle +
+ (c->cmdindex * sizeof(*cp));
+ BUG_ON(c->busaddr & 0x0000007F);
+
+ use_sg = scsi_dma_map(cmd);
+ if (use_sg < 0)
+ return use_sg;
+
+ if (use_sg) {
+ curr_sg = cp->SG;
+ scsi_for_each_sg(cmd, sg, use_sg, i) {
+ addr64 = (u64) sg_dma_address(sg);
+ len = sg_dma_len(sg);
+ total_len += len;
+ curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL);
+ curr_sg->Addr.upper =
+ (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL);
+ curr_sg->Len = len;
+
+ if (i == (scsi_sg_count(cmd) - 1))
+ curr_sg->Ext = HPSA_SG_LAST;
+ else
+ curr_sg->Ext = 0; /* we are not chaining */
+ curr_sg++;
+ }
+
+ switch (cmd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ control |= IOACCEL1_CONTROL_DATA_OUT;
+ break;
+ case DMA_FROM_DEVICE:
+ control |= IOACCEL1_CONTROL_DATA_IN;
+ break;
+ case DMA_NONE:
+ control |= IOACCEL1_CONTROL_NODATAXFER;
+ break;
+ default:
+ dev_err(&h->pdev->dev, "unknown data direction: %d\n",
+ cmd->sc_data_direction);
+ BUG();
+ break;
+ }
+ } else {
+ control |= IOACCEL1_CONTROL_NODATAXFER;
+ }
+
+ c->Header.SGList = use_sg;
+ /* Fill out the command structure to submit */
+ cp->dev_handle = ioaccel_handle & 0xFFFF;
+ cp->transfer_len = total_len;
+ cp->io_flags = IOACCEL1_IOFLAGS_IO_REQ |
+ (cdb_len & IOACCEL1_IOFLAGS_CDBLEN_MASK);
+ cp->control = control;
+ memcpy(cp->CDB, cdb, cdb_len);
+ memcpy(cp->CISS_LUN, scsi3addr, 8);
+ /* Tag was already set at init time. */
+ enqueue_cmd_and_start_io(h, c);
+ return 0;
+}
+
+/*
+ * Queue a command directly to a device behind the controller using the
+ * I/O accelerator path.
+ */
+static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
+
+ return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle,
+ cmd->cmnd, cmd->cmd_len, dev->scsi3addr);
+}
+
+/*
+ * Set encryption parameters for the ioaccel2 request
+ */
+static void set_encrypt_ioaccel2(struct ctlr_info *h,
+ struct CommandList *c, struct io_accel2_cmd *cp)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
+ struct raid_map_data *map = &dev->raid_map;
+ u64 first_block;
+
+ BUG_ON(!(dev->offload_config && dev->offload_enabled));
+
+ /* Are we doing encryption on this device */
+ if (!(map->flags & RAID_MAP_FLAG_ENCRYPT_ON))
+ return;
+ /* Set the data encryption key index. */
+ cp->dekindex = map->dekindex;
+
+ /* Set the encryption enable flag, encoded into direction field. */
+ cp->direction |= IOACCEL2_DIRECTION_ENCRYPT_MASK;
+
+ /* Set encryption tweak values based on logical block address
+ * If block size is 512, tweak value is LBA.
+ * For other block sizes, tweak is (LBA * block size)/ 512)
+ */
+ switch (cmd->cmnd[0]) {
+ /* Required? 6-byte cdbs eliminated by fixup_ioaccel_cdb */
+ case WRITE_6:
+ case READ_6:
+ if (map->volume_blk_size == 512) {
+ cp->tweak_lower =
+ (((u32) cmd->cmnd[2]) << 8) |
+ cmd->cmnd[3];
+ cp->tweak_upper = 0;
+ } else {
+ first_block =
+ (((u64) cmd->cmnd[2]) << 8) |
+ cmd->cmnd[3];
+ first_block = (first_block * map->volume_blk_size)/512;
+ cp->tweak_lower = (u32)first_block;
+ cp->tweak_upper = (u32)(first_block >> 32);
+ }
+ break;
+ case WRITE_10:
+ case READ_10:
+ if (map->volume_blk_size == 512) {
+ cp->tweak_lower =
+ (((u32) cmd->cmnd[2]) << 24) |
+ (((u32) cmd->cmnd[3]) << 16) |
+ (((u32) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ cp->tweak_upper = 0;
+ } else {
+ first_block =
+ (((u64) cmd->cmnd[2]) << 24) |
+ (((u64) cmd->cmnd[3]) << 16) |
+ (((u64) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ first_block = (first_block * map->volume_blk_size)/512;
+ cp->tweak_lower = (u32)first_block;
+ cp->tweak_upper = (u32)(first_block >> 32);
+ }
+ break;
+ /* Required? 12-byte cdbs eliminated by fixup_ioaccel_cdb */
+ case WRITE_12:
+ case READ_12:
+ if (map->volume_blk_size == 512) {
+ cp->tweak_lower =
+ (((u32) cmd->cmnd[2]) << 24) |
+ (((u32) cmd->cmnd[3]) << 16) |
+ (((u32) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ cp->tweak_upper = 0;
+ } else {
+ first_block =
+ (((u64) cmd->cmnd[2]) << 24) |
+ (((u64) cmd->cmnd[3]) << 16) |
+ (((u64) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ first_block = (first_block * map->volume_blk_size)/512;
+ cp->tweak_lower = (u32)first_block;
+ cp->tweak_upper = (u32)(first_block >> 32);
+ }
+ break;
+ case WRITE_16:
+ case READ_16:
+ if (map->volume_blk_size == 512) {
+ cp->tweak_lower =
+ (((u32) cmd->cmnd[6]) << 24) |
+ (((u32) cmd->cmnd[7]) << 16) |
+ (((u32) cmd->cmnd[8]) << 8) |
+ cmd->cmnd[9];
+ cp->tweak_upper =
+ (((u32) cmd->cmnd[2]) << 24) |
+ (((u32) cmd->cmnd[3]) << 16) |
+ (((u32) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ } else {
+ first_block =
+ (((u64) cmd->cmnd[2]) << 56) |
+ (((u64) cmd->cmnd[3]) << 48) |
+ (((u64) cmd->cmnd[4]) << 40) |
+ (((u64) cmd->cmnd[5]) << 32) |
+ (((u64) cmd->cmnd[6]) << 24) |
+ (((u64) cmd->cmnd[7]) << 16) |
+ (((u64) cmd->cmnd[8]) << 8) |
+ cmd->cmnd[9];
+ first_block = (first_block * map->volume_blk_size)/512;
+ cp->tweak_lower = (u32)first_block;
+ cp->tweak_upper = (u32)(first_block >> 32);
+ }
+ break;
+ default:
+ dev_err(&h->pdev->dev,
+ "ERROR: %s: IOACCEL request CDB size not supported for encryption\n",
+ __func__);
+ BUG();
+ break;
+ }
+}
+
+static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
+ struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
+ u8 *scsi3addr)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex];
+ struct ioaccel2_sg_element *curr_sg;
+ int use_sg, i;
+ struct scatterlist *sg;
+ u64 addr64;
+ u32 len;
+ u32 total_len = 0;
+
+ if (scsi_sg_count(cmd) > h->ioaccel_maxsg)
+ return IO_ACCEL_INELIGIBLE;
+
+ if (fixup_ioaccel_cdb(cdb, &cdb_len))
+ return IO_ACCEL_INELIGIBLE;
+ c->cmd_type = CMD_IOACCEL2;
+ /* Adjust the DMA address to point to the accelerated command buffer */
+ c->busaddr = (u32) h->ioaccel2_cmd_pool_dhandle +
+ (c->cmdindex * sizeof(*cp));
+ BUG_ON(c->busaddr & 0x0000007F);
+
+ memset(cp, 0, sizeof(*cp));
+ cp->IU_type = IOACCEL2_IU_TYPE;
+
+ use_sg = scsi_dma_map(cmd);
+ if (use_sg < 0)
+ return use_sg;
+
+ if (use_sg) {
+ BUG_ON(use_sg > IOACCEL2_MAXSGENTRIES);
+ curr_sg = cp->sg;
+ scsi_for_each_sg(cmd, sg, use_sg, i) {
+ addr64 = (u64) sg_dma_address(sg);
+ len = sg_dma_len(sg);
+ total_len += len;
+ curr_sg->address = cpu_to_le64(addr64);
+ curr_sg->length = cpu_to_le32(len);
+ curr_sg->reserved[0] = 0;
+ curr_sg->reserved[1] = 0;
+ curr_sg->reserved[2] = 0;
+ curr_sg->chain_indicator = 0;
+ curr_sg++;
+ }
+
+ switch (cmd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ cp->direction &= ~IOACCEL2_DIRECTION_MASK;
+ cp->direction |= IOACCEL2_DIR_DATA_OUT;
+ break;
+ case DMA_FROM_DEVICE:
+ cp->direction &= ~IOACCEL2_DIRECTION_MASK;
+ cp->direction |= IOACCEL2_DIR_DATA_IN;
+ break;
+ case DMA_NONE:
+ cp->direction &= ~IOACCEL2_DIRECTION_MASK;
+ cp->direction |= IOACCEL2_DIR_NO_DATA;
+ break;
+ default:
+ dev_err(&h->pdev->dev, "unknown data direction: %d\n",
+ cmd->sc_data_direction);
+ BUG();
+ break;
+ }
+ } else {
+ cp->direction &= ~IOACCEL2_DIRECTION_MASK;
+ cp->direction |= IOACCEL2_DIR_NO_DATA;
+ }
+
+ /* Set encryption parameters, if necessary */
+ set_encrypt_ioaccel2(h, c, cp);
+
+ cp->scsi_nexus = ioaccel_handle;
+ cp->Tag = (c->cmdindex << DIRECT_LOOKUP_SHIFT) |
+ DIRECT_LOOKUP_BIT;
+ memcpy(cp->cdb, cdb, sizeof(cp->cdb));
+
+ /* fill in sg elements */
+ cp->sg_count = (u8) use_sg;
+
+ cp->data_len = cpu_to_le32(total_len);
+ cp->err_ptr = cpu_to_le64(c->busaddr +
+ offsetof(struct io_accel2_cmd, error_data));
+ cp->err_len = cpu_to_le32((u32) sizeof(cp->error_data));
+
+ enqueue_cmd_and_start_io(h, c);
+ return 0;
+}
+
+/*
+ * Queue a command to the correct I/O accelerator path.
+ */
+static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
+ struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
+ u8 *scsi3addr)
+{
+ if (h->transMethod & CFGTBL_Trans_io_accel1)
+ return hpsa_scsi_ioaccel1_queue_command(h, c, ioaccel_handle,
+ cdb, cdb_len, scsi3addr);
+ else
+ return hpsa_scsi_ioaccel2_queue_command(h, c, ioaccel_handle,
+ cdb, cdb_len, scsi3addr);
+}
+
+static void raid_map_helper(struct raid_map_data *map,
+ int offload_to_mirror, u32 *map_index, u32 *current_group)
+{
+ if (offload_to_mirror == 0) {
+ /* use physical disk in the first mirrored group. */
+ *map_index %= map->data_disks_per_row;
+ return;
+ }
+ do {
+ /* determine mirror group that *map_index indicates */
+ *current_group = *map_index / map->data_disks_per_row;
+ if (offload_to_mirror == *current_group)
+ continue;
+ if (*current_group < (map->layout_map_count - 1)) {
+ /* select map index from next group */
+ *map_index += map->data_disks_per_row;
+ (*current_group)++;
+ } else {
+ /* select map index from first group */
+ *map_index %= map->data_disks_per_row;
+ *current_group = 0;
+ }
+ } while (offload_to_mirror != *current_group);
+}
+
+/*
+ * Attempt to perform offload RAID mapping for a logical volume I/O.
+ */
+static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ struct scsi_cmnd *cmd = c->scsi_cmd;
+ struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
+ struct raid_map_data *map = &dev->raid_map;
+ struct raid_map_disk_data *dd = &map->data[0];
+ int is_write = 0;
+ u32 map_index;
+ u64 first_block, last_block;
+ u32 block_cnt;
+ u32 blocks_per_row;
+ u64 first_row, last_row;
+ u32 first_row_offset, last_row_offset;
+ u32 first_column, last_column;
+ u64 r0_first_row, r0_last_row;
+ u32 r5or6_blocks_per_row;
+ u64 r5or6_first_row, r5or6_last_row;
+ u32 r5or6_first_row_offset, r5or6_last_row_offset;
+ u32 r5or6_first_column, r5or6_last_column;
+ u32 total_disks_per_row;
+ u32 stripesize;
+ u32 first_group, last_group, current_group;
+ u32 map_row;
+ u32 disk_handle;
+ u64 disk_block;
+ u32 disk_block_cnt;
+ u8 cdb[16];
+ u8 cdb_len;
+#if BITS_PER_LONG == 32
+ u64 tmpdiv;
+#endif
+ int offload_to_mirror;
+
+ BUG_ON(!(dev->offload_config && dev->offload_enabled));
+
+ /* check for valid opcode, get LBA and block count */
+ switch (cmd->cmnd[0]) {
+ case WRITE_6:
+ is_write = 1;
+ case READ_6:
+ first_block =
+ (((u64) cmd->cmnd[2]) << 8) |
+ cmd->cmnd[3];
+ block_cnt = cmd->cmnd[4];
+ break;
+ case WRITE_10:
+ is_write = 1;
+ case READ_10:
+ first_block =
+ (((u64) cmd->cmnd[2]) << 24) |
+ (((u64) cmd->cmnd[3]) << 16) |
+ (((u64) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ block_cnt =
+ (((u32) cmd->cmnd[7]) << 8) |
+ cmd->cmnd[8];
+ break;
+ case WRITE_12:
+ is_write = 1;
+ case READ_12:
+ first_block =
+ (((u64) cmd->cmnd[2]) << 24) |
+ (((u64) cmd->cmnd[3]) << 16) |
+ (((u64) cmd->cmnd[4]) << 8) |
+ cmd->cmnd[5];
+ block_cnt =
+ (((u32) cmd->cmnd[6]) << 24) |
+ (((u32) cmd->cmnd[7]) << 16) |
+ (((u32) cmd->cmnd[8]) << 8) |
+ cmd->cmnd[9];
+ break;
+ case WRITE_16:
+ is_write = 1;
+ case READ_16:
+ first_block =
+ (((u64) cmd->cmnd[2]) << 56) |
+ (((u64) cmd->cmnd[3]) << 48) |
+ (((u64) cmd->cmnd[4]) << 40) |
+ (((u64) cmd->cmnd[5]) << 32) |
+ (((u64) cmd->cmnd[6]) << 24) |
+ (((u64) cmd->cmnd[7]) << 16) |
+ (((u64) cmd->cmnd[8]) << 8) |
+ cmd->cmnd[9];
+ block_cnt =
+ (((u32) cmd->cmnd[10]) << 24) |
+ (((u32) cmd->cmnd[11]) << 16) |
+ (((u32) cmd->cmnd[12]) << 8) |
+ cmd->cmnd[13];
+ break;
+ default:
+ return IO_ACCEL_INELIGIBLE; /* process via normal I/O path */
+ }
+ BUG_ON(block_cnt == 0);
+ last_block = first_block + block_cnt - 1;
+
+ /* check for write to non-RAID-0 */
+ if (is_write && dev->raid_level != 0)
+ return IO_ACCEL_INELIGIBLE;
+
+ /* check for invalid block or wraparound */
+ if (last_block >= map->volume_blk_cnt || last_block < first_block)
+ return IO_ACCEL_INELIGIBLE;
+
+ /* calculate stripe information for the request */
+ blocks_per_row = map->data_disks_per_row * map->strip_size;
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ (void) do_div(tmpdiv, blocks_per_row);
+ first_row = tmpdiv;
+ tmpdiv = last_block;
+ (void) 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;
+ (void) do_div(tmpdiv, map->strip_size);
+ first_column = tmpdiv;
+ tmpdiv = last_row_offset;
+ (void) do_div(tmpdiv, map->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 / map->strip_size;
+ last_column = last_row_offset / map->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 IO_ACCEL_INELIGIBLE;
+
+ /* proceeding with driver mapping */
+ total_disks_per_row = map->data_disks_per_row +
+ map->metadata_disks_per_row;
+ map_row = ((u32)(first_row >> map->parity_rotation_shift)) %
+ map->row_cnt;
+ map_index = (map_row * total_disks_per_row) + first_column;
+
+ switch (dev->raid_level) {
+ case HPSA_RAID_0:
+ break; /* nothing special to do */
+ case HPSA_RAID_1:
+ /* Handles load balance across RAID 1 members.
+ * (2-drive R1 and R10 with even # of drives.)
+ * Appropriate for SSDs, not optimal for HDDs
+ */
+ BUG_ON(map->layout_map_count != 2);
+ if (dev->offload_to_mirror)
+ map_index += map->data_disks_per_row;
+ dev->offload_to_mirror = !dev->offload_to_mirror;
+ break;
+ case HPSA_RAID_ADM:
+ /* Handles N-way mirrors (R1-ADM)
+ * and R10 with # of drives divisible by 3.)
+ */
+ BUG_ON(map->layout_map_count != 3);
+
+ offload_to_mirror = dev->offload_to_mirror;
+ raid_map_helper(map, offload_to_mirror,
+ &map_index, &current_group);
+ /* set mirror group to use next time */
+ offload_to_mirror =
+ (offload_to_mirror >= map->layout_map_count - 1)
+ ? 0 : offload_to_mirror + 1;
+ /* FIXME: remove after debug/dev */
+ BUG_ON(offload_to_mirror >= map->layout_map_count);
+ dev_warn(&h->pdev->dev,
+ "DEBUG: Using physical disk map index %d from mirror group %d\n",
+ map_index, offload_to_mirror);
+ dev->offload_to_mirror = offload_to_mirror;
+ /* Avoid direct use of dev->offload_to_mirror within this
+ * function since multiple threads might simultaneously
+ * increment it beyond the range of dev->layout_map_count -1.
+ */
+ break;
+ case HPSA_RAID_5:
+ case HPSA_RAID_6:
+ if (map->layout_map_count <= 1)
+ break;
+
+ /* Verify first and last block are in same RAID group */
+ r5or6_blocks_per_row =
+ map->strip_size * map->data_disks_per_row;
+ BUG_ON(r5or6_blocks_per_row == 0);
+ stripesize = r5or6_blocks_per_row * map->layout_map_count;
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ first_group = do_div(tmpdiv, stripesize);
+ tmpdiv = first_group;
+ (void) do_div(tmpdiv, r5or6_blocks_per_row);
+ first_group = tmpdiv;
+ tmpdiv = last_block;
+ last_group = do_div(tmpdiv, stripesize);
+ tmpdiv = last_group;
+ (void) 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 IO_ACCEL_INELIGIBLE;
+
+ /* Verify request is in a single row of RAID 5/6 */
+#if BITS_PER_LONG == 32
+ tmpdiv = first_block;
+ (void) do_div(tmpdiv, stripesize);
+ first_row = r5or6_first_row = r0_first_row = tmpdiv;
+ tmpdiv = last_block;
+ (void) 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 IO_ACCEL_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;
+ (void) do_div(tmpdiv, map->strip_size);
+ first_column = r5or6_first_column = tmpdiv;
+ tmpdiv = r5or6_last_row_offset;
+ (void) do_div(tmpdiv, map->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_column =
+ r5or6_first_row_offset / map->strip_size;
+ r5or6_last_column =
+ r5or6_last_row_offset / map->strip_size;
+#endif
+ if (r5or6_first_column != r5or6_last_column)
+ return IO_ACCEL_INELIGIBLE;
+
+ /* Request is eligible */
+ map_row = ((u32)(first_row >> map->parity_rotation_shift)) %
+ map->row_cnt;
+
+ map_index = (first_group *
+ (map->row_cnt * total_disks_per_row)) +
+ (map_row * total_disks_per_row) + first_column;
+ break;
+ default:
+ return IO_ACCEL_INELIGIBLE;
+ }
+
+ disk_handle = dd[map_index].ioaccel_handle;
+ disk_block = map->disk_starting_blk + (first_row * map->strip_size) +
+ (first_row_offset - (first_column * map->strip_size));
+ disk_block_cnt = block_cnt;
+
+ /* handle differing logical/physical block sizes */
+ if (map->phys_blk_shift) {
+ disk_block <<= map->phys_blk_shift;
+ disk_block_cnt <<= map->phys_blk_shift;
+ }
+ BUG_ON(disk_block_cnt > 0xffff);
+
+ /* 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;
+ cdb[2] = (u8) (disk_block >> 56);
+ cdb[3] = (u8) (disk_block >> 48);
+ cdb[4] = (u8) (disk_block >> 40);
+ cdb[5] = (u8) (disk_block >> 32);
+ cdb[6] = (u8) (disk_block >> 24);
+ cdb[7] = (u8) (disk_block >> 16);
+ cdb[8] = (u8) (disk_block >> 8);
+ cdb[9] = (u8) (disk_block);
+ cdb[10] = (u8) (disk_block_cnt >> 24);
+ cdb[11] = (u8) (disk_block_cnt >> 16);
+ cdb[12] = (u8) (disk_block_cnt >> 8);
+ cdb[13] = (u8) (disk_block_cnt);
+ cdb[14] = 0;
+ cdb[15] = 0;
+ cdb_len = 16;
+ } else {
+ cdb[0] = is_write ? WRITE_10 : READ_10;
+ cdb[1] = 0;
+ cdb[2] = (u8) (disk_block >> 24);
+ cdb[3] = (u8) (disk_block >> 16);
+ cdb[4] = (u8) (disk_block >> 8);
+ cdb[5] = (u8) (disk_block);
+ cdb[6] = 0;
+ cdb[7] = (u8) (disk_block_cnt >> 8);
+ cdb[8] = (u8) (disk_block_cnt);
+ cdb[9] = 0;
+ cdb_len = 10;
+ }
+ return hpsa_scsi_ioaccel_queue_command(h, c, disk_handle, cdb, cdb_len,
+ dev->scsi3addr);
+}
static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
@@ -2169,6 +3951,7 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
unsigned char scsi3addr[8];
struct CommandList *c;
unsigned long flags;
+ int rc = 0;
/* Get the ptr to our adapter structure out of cmd->host. */
h = sdev_to_hba(cmd->device);
@@ -2203,6 +3986,32 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
c->cmd_type = CMD_SCSI;
c->scsi_cmd = cmd;
+
+ /* Call alternate submit routine for I/O accelerated commands.
+ * Retries always go down the normal I/O path.
+ */
+ if (likely(cmd->retries == 0 &&
+ cmd->request->cmd_type == REQ_TYPE_FS &&
+ h->acciopath_status)) {
+ if (dev->offload_enabled) {
+ rc = hpsa_scsi_ioaccel_raid_map(h, c);
+ if (rc == 0)
+ return 0; /* Sent on ioaccel path */
+ if (rc < 0) { /* scsi_dma_map failed. */
+ cmd_free(h, c);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ } else if (dev->ioaccel_handle) {
+ rc = hpsa_scsi_ioaccel_direct_map(h, c);
+ if (rc == 0)
+ return 0; /* Sent on direct map path */
+ if (rc < 0) { /* scsi_dma_map failed. */
+ cmd_free(h, c);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ }
+ }
+
c->Header.ReplyQueue = 0; /* unused in simple mode */
memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
c->Header.Tag.lower = (c->cmdindex << DIRECT_LOOKUP_SHIFT);
@@ -2262,11 +4071,38 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
static DEF_SCSI_QCMD(hpsa_scsi_queue_command)
+static int do_not_scan_if_controller_locked_up(struct ctlr_info *h)
+{
+ unsigned long flags;
+
+ /*
+ * Don't let rescans be initiated on a controller known
+ * to be locked up. If the controller locks up *during*
+ * a rescan, that thread is probably hosed, but at least
+ * we can prevent new rescan threads from piling up on a
+ * locked up controller.
+ */
+ spin_lock_irqsave(&h->lock, flags);
+ if (unlikely(h->lockup_detected)) {
+ spin_unlock_irqrestore(&h->lock, flags);
+ spin_lock_irqsave(&h->scan_lock, flags);
+ h->scan_finished = 1;
+ wake_up_all(&h->scan_wait_queue);
+ spin_unlock_irqrestore(&h->scan_lock, flags);
+ return 1;
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ return 0;
+}
+
static void hpsa_scan_start(struct Scsi_Host *sh)
{
struct ctlr_info *h = shost_to_hba(sh);
unsigned long flags;
+ if (do_not_scan_if_controller_locked_up(h))
+ return;
+
/* wait until any scan already in progress is finished. */
while (1) {
spin_lock_irqsave(&h->scan_lock, flags);
@@ -2283,6 +4119,9 @@ static void hpsa_scan_start(struct Scsi_Host *sh)
h->scan_finished = 0; /* mark scan as in progress */
spin_unlock_irqrestore(&h->scan_lock, flags);
+ if (do_not_scan_if_controller_locked_up(h))
+ return;
+
hpsa_update_scsi_devices(h, h->scsi_host->host_no);
spin_lock_irqsave(&h->scan_lock, flags);
@@ -2346,7 +4185,10 @@ static int hpsa_register_scsi(struct ctlr_info *h)
sh->max_lun = HPSA_MAX_LUN;
sh->max_id = HPSA_MAX_LUN;
sh->can_queue = h->nr_cmds;
- sh->cmd_per_lun = h->nr_cmds;
+ if (h->hba_mode_enabled)
+ sh->cmd_per_lun = 7;
+ else
+ sh->cmd_per_lun = h->nr_cmds;
sh->sg_tablesize = h->maxsgentries;
h->scsi_host = sh;
sh->hostdata[0] = (unsigned long) h;
@@ -2372,7 +4214,7 @@ static int hpsa_register_scsi(struct ctlr_info *h)
static int wait_for_device_to_become_ready(struct ctlr_info *h,
unsigned char lunaddr[])
{
- int rc = 0;
+ int rc;
int count = 0;
int waittime = 1; /* seconds */
struct CommandList *c;
@@ -2392,6 +4234,7 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h,
*/
msleep(1000 * waittime);
count++;
+ rc = 0; /* Device ready. */
/* Increase wait time with each try, up to a point. */
if (waittime < HPSA_MAX_WAIT_INTERVAL_SECS)
@@ -2448,7 +4291,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
dev_warn(&h->pdev->dev, "resetting device %d:%d:%d:%d\n",
h->scsi_host->host_no, dev->bus, dev->target, dev->lun);
/* send a reset to the SCSI LUN which the command was sent to */
- rc = hpsa_send_reset(h, dev->scsi3addr);
+ rc = hpsa_send_reset(h, dev->scsi3addr, HPSA_RESET_TYPE_LUN);
if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0)
return SUCCESS;
@@ -2471,12 +4314,36 @@ static void swizzle_abort_tag(u8 *tag)
tag[7] = original_tag[4];
}
+static void hpsa_get_tag(struct ctlr_info *h,
+ struct CommandList *c, u32 *taglower, u32 *tagupper)
+{
+ if (c->cmd_type == CMD_IOACCEL1) {
+ struct io_accel1_cmd *cm1 = (struct io_accel1_cmd *)
+ &h->ioaccel_cmd_pool[c->cmdindex];
+ *tagupper = cm1->Tag.upper;
+ *taglower = cm1->Tag.lower;
+ return;
+ }
+ if (c->cmd_type == CMD_IOACCEL2) {
+ struct io_accel2_cmd *cm2 = (struct io_accel2_cmd *)
+ &h->ioaccel2_cmd_pool[c->cmdindex];
+ /* upper tag not used in ioaccel2 mode */
+ memset(tagupper, 0, sizeof(*tagupper));
+ *taglower = cm2->Tag;
+ return;
+ }
+ *tagupper = c->Header.Tag.upper;
+ *taglower = c->Header.Tag.lower;
+}
+
+
static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
struct CommandList *abort, int swizzle)
{
int rc = IO_OK;
struct CommandList *c;
struct ErrorInfo *ei;
+ u32 tagupper, taglower;
c = cmd_special_alloc(h);
if (c == NULL) { /* trouble... */
@@ -2490,8 +4357,9 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
if (swizzle)
swizzle_abort_tag(&c->Request.CDB[4]);
hpsa_scsi_do_simple_cmd_core(h, c);
+ hpsa_get_tag(h, abort, &taglower, &tagupper);
dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n",
- __func__, abort->Header.Tag.upper, abort->Header.Tag.lower);
+ __func__, tagupper, taglower);
/* no unmap needed here because no data xfer. */
ei = c->err_info;
@@ -2503,15 +4371,14 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
break;
default:
dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: interpreting error.\n",
- __func__, abort->Header.Tag.upper,
- abort->Header.Tag.lower);
- hpsa_scsi_interpret_error(c);
+ __func__, tagupper, taglower);
+ hpsa_scsi_interpret_error(h, c);
rc = -1;
break;
}
cmd_special_free(h, c);
- dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n", __func__,
- abort->Header.Tag.upper, abort->Header.Tag.lower);
+ dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n",
+ __func__, tagupper, taglower);
return rc;
}
@@ -2565,6 +4432,83 @@ static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h,
return NULL;
}
+/* ioaccel2 path firmware cannot handle abort task requests.
+ * Change abort requests to physical target reset, and send to the
+ * address of the physical disk used for the ioaccel 2 command.
+ * Return 0 on success (IO_OK)
+ * -1 on failure
+ */
+
+static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h,
+ unsigned char *scsi3addr, struct CommandList *abort)
+{
+ int rc = IO_OK;
+ struct scsi_cmnd *scmd; /* scsi command within request being aborted */
+ struct hpsa_scsi_dev_t *dev; /* device to which scsi cmd was sent */
+ unsigned char phys_scsi3addr[8]; /* addr of phys disk with volume */
+ unsigned char *psa = &phys_scsi3addr[0];
+
+ /* Get a pointer to the hpsa logical device. */
+ scmd = (struct scsi_cmnd *) abort->scsi_cmd;
+ dev = (struct hpsa_scsi_dev_t *)(scmd->device->hostdata);
+ if (dev == NULL) {
+ dev_warn(&h->pdev->dev,
+ "Cannot abort: no device pointer for command.\n");
+ return -1; /* not abortable */
+ }
+
+ if (h->raid_offload_debug > 0)
+ dev_info(&h->pdev->dev,
+ "Reset as abort: Abort requested on C%d:B%d:T%d:L%d scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ h->scsi_host->host_no, dev->bus, dev->target, dev->lun,
+ scsi3addr[0], scsi3addr[1], scsi3addr[2], scsi3addr[3],
+ scsi3addr[4], scsi3addr[5], scsi3addr[6], scsi3addr[7]);
+
+ if (!dev->offload_enabled) {
+ dev_warn(&h->pdev->dev,
+ "Can't abort: device is not operating in HP SSD Smart Path mode.\n");
+ return -1; /* not abortable */
+ }
+
+ /* Incoming scsi3addr is logical addr. We need physical disk addr. */
+ if (!hpsa_get_pdisk_of_ioaccel2(h, abort, psa)) {
+ dev_warn(&h->pdev->dev, "Can't abort: Failed lookup of physical address.\n");
+ return -1; /* not abortable */
+ }
+
+ /* send the reset */
+ if (h->raid_offload_debug > 0)
+ dev_info(&h->pdev->dev,
+ "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_send_reset(h, psa, HPSA_RESET_TYPE_TARGET);
+ 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",
+ psa[0], psa[1], psa[2], psa[3],
+ psa[4], psa[5], psa[6], psa[7]);
+ return rc; /* failed to reset */
+ }
+
+ /* wait for device to recover */
+ if (wait_for_device_to_become_ready(h, psa) != 0) {
+ dev_warn(&h->pdev->dev,
+ "Reset as abort: Failed: Device never recovered from reset: 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]);
+ return -1; /* failed to recover */
+ }
+
+ /* device recovered */
+ dev_info(&h->pdev->dev,
+ "Reset as abort: Device recovered from reset: 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]);
+
+ return rc; /* success */
+}
+
/* Some Smart Arrays need the abort tag swizzled, and some don't. It's hard to
* tell which kind we're dealing with, so we send the abort both ways. There
* shouldn't be any collisions between swizzled and unswizzled tags due to the
@@ -2578,6 +4522,14 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h,
struct CommandList *c;
int rc = 0, rc2 = 0;
+ /* ioccelerator mode 2 commands should be aborted via the
+ * accelerated path, since RAID path is unaware of these commands,
+ * but underlying firmware can't handle abort TMF.
+ * Change abort to physical device reset.
+ */
+ if (abort->cmd_type == CMD_IOACCEL2)
+ return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort);
+
/* we do not expect to find the swizzled tag in our queue, but
* check anyway just to be sure the assumptions which make this
* the case haven't become wrong.
@@ -2616,6 +4568,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
struct scsi_cmnd *as; /* ptr to scsi cmd inside aborted command. */
char msg[256]; /* For debug messaging. */
int ml = 0;
+ u32 tagupper, taglower;
/* Find the controller of the command to be aborted */
h = sdev_to_hba(sc->device);
@@ -2648,9 +4601,8 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
msg);
return FAILED;
}
-
- ml += sprintf(msg+ml, "Tag:0x%08x:%08x ",
- abort->Header.Tag.upper, abort->Header.Tag.lower);
+ hpsa_get_tag(h, abort, &taglower, &tagupper);
+ ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower);
as = (struct scsi_cmnd *) abort->scsi_cmd;
if (as != NULL)
ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ",
@@ -2776,6 +4728,7 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
return NULL;
memset(c, 0, sizeof(*c));
+ c->cmd_type = CMD_SCSI;
c->cmdindex = -1;
c->err_info = pci_alloc_consistent(h->pdev, sizeof(*c->err_info),
@@ -3038,7 +4991,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
c->SG[0].Addr.lower = temp64.val32.lower;
c->SG[0].Addr.upper = temp64.val32.upper;
c->SG[0].Len = iocommand.buf_size;
- c->SG[0].Ext = 0; /* we are not chaining*/
+ c->SG[0].Ext = HPSA_SG_LAST; /* we are not chaining*/
}
hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c);
if (iocommand.buf_size > 0)
@@ -3168,8 +5121,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
c->SG[i].Addr.lower = temp64.val32.lower;
c->SG[i].Addr.upper = temp64.val32.upper;
c->SG[i].Len = buff_size[i];
- /* we are not chaining */
- c->SG[i].Ext = 0;
+ c->SG[i].Ext = i < sg_used - 1 ? 0 : HPSA_SG_LAST;
}
}
hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c);
@@ -3304,7 +5256,7 @@ static int hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr,
}
static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
- void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
+ void *buff, size_t size, u16 page_code, unsigned char *scsi3addr,
int cmd_type)
{
int pci_dir = XFER_NONE;
@@ -3327,9 +5279,9 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
switch (cmd) {
case HPSA_INQUIRY:
/* are we trying to read a vital product page */
- if (page_code != 0) {
+ if (page_code & VPD_PAGE) {
c->Request.CDB[1] = 0x01;
- c->Request.CDB[2] = page_code;
+ c->Request.CDB[2] = (page_code & 0xff);
}
c->Request.CDBLen = 6;
c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -3369,6 +5321,28 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.Type.Direction = XFER_NONE;
c->Request.Timeout = 0;
break;
+ case HPSA_GET_RAID_MAP:
+ c->Request.CDBLen = 12;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_READ;
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = HPSA_CISS_READ;
+ c->Request.CDB[1] = cmd;
+ c->Request.CDB[6] = (size >> 24) & 0xFF; /* MSB */
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0xFF;
+ c->Request.CDB[9] = size & 0xFF;
+ break;
+ case BMIC_SENSE_CONTROLLER_PARAMETERS:
+ c->Request.CDBLen = 10;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_READ;
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_READ;
+ c->Request.CDB[6] = BMIC_SENSE_CONTROLLER_PARAMETERS;
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0xFF;
+ break;
default:
dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd);
BUG();
@@ -3562,7 +5536,8 @@ static inline void finish_cmd(struct CommandList *c)
spin_unlock_irqrestore(&h->lock, flags);
dial_up_lockup_detection_on_fw_flash_complete(c->h, c);
- if (likely(c->cmd_type == CMD_SCSI))
+ if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI
+ || c->cmd_type == CMD_IOACCEL2))
complete_scsi_command(c);
else if (c->cmd_type == CMD_IOCTL_PEND)
complete(c->waiting);
@@ -4169,21 +6144,24 @@ static void hpsa_interrupt_mode(struct ctlr_info *h)
goto default_int_mode;
if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
dev_info(&h->pdev->dev, "MSIX\n");
+ h->msix_vector = MAX_REPLY_QUEUES;
err = pci_enable_msix(h->pdev, hpsa_msix_entries,
- MAX_REPLY_QUEUES);
- if (!err) {
- for (i = 0; i < MAX_REPLY_QUEUES; i++)
- h->intr[i] = hpsa_msix_entries[i].vector;
- h->msix_vector = 1;
- return;
- }
+ h->msix_vector);
if (err > 0) {
dev_warn(&h->pdev->dev, "only %d MSI-X vectors "
"available\n", err);
- goto default_int_mode;
+ h->msix_vector = err;
+ err = pci_enable_msix(h->pdev, hpsa_msix_entries,
+ h->msix_vector);
+ }
+ if (!err) {
+ for (i = 0; i < h->msix_vector; i++)
+ h->intr[i] = hpsa_msix_entries[i].vector;
+ return;
} else {
dev_warn(&h->pdev->dev, "MSI-X init failed %d\n",
err);
+ h->msix_vector = 0;
goto default_int_mode;
}
}
@@ -4336,6 +6314,7 @@ static void hpsa_find_board_params(struct ctlr_info *h)
hpsa_get_max_perf_mode_cmds(h);
h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
+ h->fw_support = readl(&(h->cfgtable->misc_fw_support));
/*
* Limit in-command s/g elements to 32 save dma'able memory.
* Howvever spec says if 0, use 31
@@ -4352,6 +6331,10 @@ static void hpsa_find_board_params(struct ctlr_info *h)
/* Find out what task management functions are supported and cache */
h->TMFSupportFlags = readl(&(h->cfgtable->TMFSupportFlags));
+ if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags))
+ dev_warn(&h->pdev->dev, "Physical aborts not supported\n");
+ if (!(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags))
+ dev_warn(&h->pdev->dev, "Logical aborts not supported\n");
}
static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
@@ -4390,6 +6373,23 @@ static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h)
writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
}
+static void hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h)
+{
+ int i;
+ u32 doorbell_value;
+ unsigned long flags;
+ /* wait until the clear_event_notify bit 6 is cleared by controller. */
+ for (i = 0; i < MAX_CONFIG_WAIT; i++) {
+ spin_lock_irqsave(&h->lock, flags);
+ doorbell_value = readl(h->vaddr + SA5_DOORBELL);
+ spin_unlock_irqrestore(&h->lock, flags);
+ if (!(doorbell_value & DOORBELL_CLEAR_EVENTS))
+ break;
+ /* delay and try again */
+ msleep(20);
+ }
+}
+
static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
{
int i;
@@ -4420,18 +6420,20 @@ static int hpsa_enter_simple_mode(struct ctlr_info *h)
return -ENOTSUPP;
h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
+
/* Update the field, and then ring the doorbell */
writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
+ writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi);
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
hpsa_wait_for_mode_change_ack(h);
print_cfg_table(&h->pdev->dev, h->cfgtable);
- if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
- dev_warn(&h->pdev->dev,
- "unable to get board into simple mode\n");
- return -ENODEV;
- }
+ if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
+ goto error;
h->transMethod = CFGTBL_Trans_Simple;
return 0;
+error:
+ dev_warn(&h->pdev->dev, "unable to get board into simple mode\n");
+ return -ENODEV;
}
static int hpsa_pci_init(struct ctlr_info *h)
@@ -4577,11 +6579,19 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h)
pci_free_consistent(h->pdev,
h->nr_cmds * sizeof(struct CommandList),
h->cmd_pool, h->cmd_pool_dhandle);
+ if (h->ioaccel2_cmd_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool),
+ h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle);
if (h->errinfo_pool)
pci_free_consistent(h->pdev,
h->nr_cmds * sizeof(struct ErrorInfo),
h->errinfo_pool,
h->errinfo_pool_dhandle);
+ if (h->ioaccel_cmd_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(struct io_accel1_cmd),
+ h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle);
}
static int hpsa_request_irq(struct ctlr_info *h,
@@ -4597,15 +6607,15 @@ static int hpsa_request_irq(struct ctlr_info *h,
for (i = 0; i < MAX_REPLY_QUEUES; i++)
h->q[i] = (u8) i;
- if (h->intr_mode == PERF_MODE_INT && h->msix_vector) {
+ if (h->intr_mode == PERF_MODE_INT && h->msix_vector > 0) {
/* If performant mode and MSI-X, use multiple reply queues */
- for (i = 0; i < MAX_REPLY_QUEUES; i++)
+ for (i = 0; i < h->msix_vector; i++)
rc = request_irq(h->intr[i], msixhandler,
0, h->devname,
&h->q[i]);
} else {
/* Use single reply pool */
- if (h->msix_vector || h->msi_vector) {
+ if (h->msix_vector > 0 || h->msi_vector) {
rc = request_irq(h->intr[h->intr_mode],
msixhandler, 0, h->devname,
&h->q[h->intr_mode]);
@@ -4658,7 +6668,7 @@ static void free_irqs(struct ctlr_info *h)
return;
}
- for (i = 0; i < MAX_REPLY_QUEUES; i++)
+ for (i = 0; i < h->msix_vector; i++)
free_irq(h->intr[i], &h->q[i]);
}
@@ -4681,6 +6691,7 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
hpsa_free_irqs_and_disable_msix(h);
hpsa_free_sg_chain_blocks(h);
hpsa_free_cmd_pool(h);
+ kfree(h->ioaccel1_blockFetchTable);
kfree(h->blockFetchTable);
pci_free_consistent(h->pdev, h->reply_pool_size,
h->reply_pool, h->reply_pool_dhandle);
@@ -4760,6 +6771,92 @@ static void detect_controller_lockup(struct ctlr_info *h)
h->last_heartbeat_timestamp = now;
}
+static void hpsa_ack_ctlr_events(struct ctlr_info *h)
+{
+ int i;
+ char *event_type;
+
+ /* Clear the driver-requested rescan flag */
+ h->drv_req_rescan = 0;
+
+ /* Ask the controller to clear the events we're handling. */
+ if ((h->transMethod & (CFGTBL_Trans_io_accel1
+ | CFGTBL_Trans_io_accel2)) &&
+ (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE ||
+ h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE)) {
+
+ if (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE)
+ event_type = "state change";
+ if (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE)
+ event_type = "configuration change";
+ /* Stop sending new RAID offload reqs via the IO accelerator */
+ scsi_block_requests(h->scsi_host);
+ for (i = 0; i < h->ndevices; i++)
+ h->dev[i]->offload_enabled = 0;
+ hpsa_drain_accel_commands(h);
+ /* Set 'accelerator path config change' bit */
+ dev_warn(&h->pdev->dev,
+ "Acknowledging event: 0x%08x (HP SSD Smart Path %s)\n",
+ h->events, event_type);
+ writel(h->events, &(h->cfgtable->clear_event_notify));
+ /* Set the "clear event notify field update" bit 6 */
+ writel(DOORBELL_CLEAR_EVENTS, h->vaddr + SA5_DOORBELL);
+ /* Wait until ctlr clears 'clear event notify field', bit 6 */
+ hpsa_wait_for_clear_event_notify_ack(h);
+ scsi_unblock_requests(h->scsi_host);
+ } else {
+ /* Acknowledge controller notification events. */
+ writel(h->events, &(h->cfgtable->clear_event_notify));
+ writel(DOORBELL_CLEAR_EVENTS, h->vaddr + SA5_DOORBELL);
+ hpsa_wait_for_clear_event_notify_ack(h);
+#if 0
+ writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+ hpsa_wait_for_mode_change_ack(h);
+#endif
+ }
+ return;
+}
+
+/* Check a register on the controller to see if there are configuration
+ * changes (added/changed/removed logical drives, etc.) which mean that
+ * we should rescan the controller for devices.
+ * Also check flag for driver-initiated rescan.
+ */
+static int hpsa_ctlr_needs_rescan(struct ctlr_info *h)
+{
+ if (h->drv_req_rescan)
+ return 1;
+
+ if (!(h->fw_support & MISC_FW_EVENT_NOTIFY))
+ return 0;
+
+ h->events = readl(&(h->cfgtable->event_notify));
+ return h->events & RESCAN_REQUIRED_EVENT_BITS;
+}
+
+/*
+ * Check if any of the offline devices have become ready
+ */
+static int hpsa_offline_devices_ready(struct ctlr_info *h)
+{
+ unsigned long flags;
+ struct offline_device_entry *d;
+ struct list_head *this, *tmp;
+
+ spin_lock_irqsave(&h->offline_device_lock, flags);
+ list_for_each_safe(this, tmp, &h->offline_device_list) {
+ d = list_entry(this, struct offline_device_entry,
+ offline_list);
+ spin_unlock_irqrestore(&h->offline_device_lock, flags);
+ if (!hpsa_volume_offline(h, d->scsi3addr))
+ return 1;
+ spin_lock_irqsave(&h->offline_device_lock, flags);
+ }
+ spin_unlock_irqrestore(&h->offline_device_lock, flags);
+ return 0;
+}
+
+
static void hpsa_monitor_ctlr_worker(struct work_struct *work)
{
unsigned long flags;
@@ -4768,6 +6865,15 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work)
detect_controller_lockup(h);
if (h->lockup_detected)
return;
+
+ if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) {
+ scsi_host_get(h->scsi_host);
+ h->drv_req_rescan = 0;
+ hpsa_ack_ctlr_events(h);
+ hpsa_scan_start(h->scsi_host);
+ scsi_host_put(h->scsi_host);
+ }
+
spin_lock_irqsave(&h->lock, flags);
if (h->remove_in_progress) {
spin_unlock_irqrestore(&h->lock, flags);
@@ -4807,7 +6913,7 @@ reinit_after_soft_reset:
* the 5 lower bits of the address are used by the hardware. and by
* the driver. See comments in hpsa.h for more info.
*/
-#define COMMANDLIST_ALIGNMENT 32
+#define COMMANDLIST_ALIGNMENT 128
BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT);
h = kzalloc(sizeof(*h), GFP_KERNEL);
if (!h)
@@ -4817,7 +6923,9 @@ reinit_after_soft_reset:
h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT;
INIT_LIST_HEAD(&h->cmpQ);
INIT_LIST_HEAD(&h->reqQ);
+ INIT_LIST_HEAD(&h->offline_device_list);
spin_lock_init(&h->lock);
+ spin_lock_init(&h->offline_device_lock);
spin_lock_init(&h->scan_lock);
spin_lock_init(&h->passthru_count_lock);
rc = hpsa_pci_init(h);
@@ -4859,6 +6967,7 @@ reinit_after_soft_reset:
pci_set_drvdata(pdev, h);
h->ndevices = 0;
+ h->hba_mode_enabled = 0;
h->scsi_host = NULL;
spin_lock_init(&h->devlock);
hpsa_put_ctlr_into_performant_mode(h);
@@ -4918,6 +7027,11 @@ reinit_after_soft_reset:
goto reinit_after_soft_reset;
}
+ /* Enable Accelerated IO path at driver layer */
+ h->acciopath_status = 1;
+
+ h->drv_req_rescan = 0;
+
/* Turn the interrupts on so we can service requests */
h->access.set_intr_mask(h, HPSA_INTR_ON);
@@ -5034,6 +7148,8 @@ static void hpsa_remove_one(struct pci_dev *pdev)
h->reply_pool, h->reply_pool_dhandle);
kfree(h->cmd_pool_bits);
kfree(h->blockFetchTable);
+ kfree(h->ioaccel1_blockFetchTable);
+ kfree(h->ioaccel2_blockFetchTable);
kfree(h->hba_inquiry_data);
pci_disable_device(pdev);
pci_release_regions(pdev);
@@ -5074,20 +7190,17 @@ static struct pci_driver hpsa_pci_driver = {
* bits of the command address.
*/
static void calc_bucket_map(int bucket[], int num_buckets,
- int nsgs, int *bucket_map)
+ int nsgs, int min_blocks, int *bucket_map)
{
int i, j, b, size;
- /* even a command with 0 SGs requires 4 blocks */
-#define MINIMUM_TRANSFER_BLOCKS 4
-#define NUM_BUCKETS 8
/* Note, bucket_map must have nsgs+1 entries. */
for (i = 0; i <= nsgs; i++) {
/* Compute size of a command with i SG entries */
- size = i + MINIMUM_TRANSFER_BLOCKS;
+ size = i + min_blocks;
b = num_buckets; /* Assume the biggest bucket */
/* Find the bucket that is just big enough */
- for (j = 0; j < 8; j++) {
+ for (j = 0; j < num_buckets; j++) {
if (bucket[j] >= size) {
b = j;
break;
@@ -5098,10 +7211,16 @@ static void calc_bucket_map(int bucket[], int num_buckets,
}
}
-static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
+static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
{
int i;
unsigned long register_value;
+ unsigned long transMethod = CFGTBL_Trans_Performant |
+ (trans_support & CFGTBL_Trans_use_short_tags) |
+ CFGTBL_Trans_enable_directed_msix |
+ (trans_support & (CFGTBL_Trans_io_accel1 |
+ CFGTBL_Trans_io_accel2));
+ struct access_method access = SA5_performant_access;
/* This is a bit complicated. There are 8 registers on
* the controller which we write to to tell it 8 different
@@ -5121,6 +7240,16 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
* sizes for small commands, and fewer sizes for larger commands.
*/
int bft[8] = {5, 6, 8, 10, 12, 20, 28, SG_ENTRIES_IN_CMD + 4};
+#define MIN_IOACCEL2_BFT_ENTRY 5
+#define HPSA_IOACCEL2_HEADER_SZ 4
+ int bft2[16] = {MIN_IOACCEL2_BFT_ENTRY, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19,
+ HPSA_IOACCEL2_HEADER_SZ + IOACCEL2_MAXSGENTRIES};
+ BUILD_BUG_ON(ARRAY_SIZE(bft2) != 16);
+ BUILD_BUG_ON(ARRAY_SIZE(bft) != 8);
+ BUILD_BUG_ON(offsetof(struct io_accel2_cmd, sg) >
+ 16 * MIN_IOACCEL2_BFT_ENTRY);
+ BUILD_BUG_ON(sizeof(struct ioaccel2_sg_element) != 16);
BUILD_BUG_ON(28 > SG_ENTRIES_IN_CMD + 4);
/* 5 = 1 s/g entry or 4k
* 6 = 2 s/g entry or 8k
@@ -5133,7 +7262,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
bft[7] = SG_ENTRIES_IN_CMD + 4;
calc_bucket_map(bft, ARRAY_SIZE(bft),
- SG_ENTRIES_IN_CMD, h->blockFetchTable);
+ SG_ENTRIES_IN_CMD, 4, h->blockFetchTable);
for (i = 0; i < 8; i++)
writel(bft[i], &h->transtable->BlockFetch[i]);
@@ -5150,9 +7279,22 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
&h->transtable->RepQAddr[i].lower);
}
- writel(CFGTBL_Trans_Performant | use_short_tags |
- CFGTBL_Trans_enable_directed_msix,
- &(h->cfgtable->HostWrite.TransportRequest));
+ writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi);
+ writel(transMethod, &(h->cfgtable->HostWrite.TransportRequest));
+ /*
+ * enable outbound interrupt coalescing in accelerator mode;
+ */
+ if (trans_support & CFGTBL_Trans_io_accel1) {
+ access = SA5_ioaccel_mode1_access;
+ writel(10, &h->cfgtable->HostWrite.CoalIntDelay);
+ writel(4, &h->cfgtable->HostWrite.CoalIntCount);
+ } else {
+ if (trans_support & CFGTBL_Trans_io_accel2) {
+ access = SA5_ioaccel_mode2_access;
+ writel(10, &h->cfgtable->HostWrite.CoalIntDelay);
+ writel(4, &h->cfgtable->HostWrite.CoalIntCount);
+ }
+ }
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
hpsa_wait_for_mode_change_ack(h);
register_value = readl(&(h->cfgtable->TransportActive));
@@ -5162,23 +7304,186 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
return;
}
/* Change the access methods to the performant access methods */
- h->access = SA5_performant_access;
- h->transMethod = CFGTBL_Trans_Performant;
+ h->access = access;
+ h->transMethod = transMethod;
+
+ if (!((trans_support & CFGTBL_Trans_io_accel1) ||
+ (trans_support & CFGTBL_Trans_io_accel2)))
+ return;
+
+ if (trans_support & CFGTBL_Trans_io_accel1) {
+ /* Set up I/O accelerator mode */
+ for (i = 0; i < h->nreply_queues; i++) {
+ writel(i, h->vaddr + IOACCEL_MODE1_REPLY_QUEUE_INDEX);
+ h->reply_queue[i].current_entry =
+ readl(h->vaddr + IOACCEL_MODE1_PRODUCER_INDEX);
+ }
+ bft[7] = h->ioaccel_maxsg + 8;
+ calc_bucket_map(bft, ARRAY_SIZE(bft), h->ioaccel_maxsg, 8,
+ h->ioaccel1_blockFetchTable);
+
+ /* initialize all reply queue entries to unused */
+ memset(h->reply_pool, (u8) IOACCEL_MODE1_REPLY_UNUSED,
+ h->reply_pool_size);
+
+ /* set all the constant fields in the accelerator command
+ * frames once at init time to save CPU cycles later.
+ */
+ for (i = 0; i < h->nr_cmds; i++) {
+ struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[i];
+
+ cp->function = IOACCEL1_FUNCTION_SCSIIO;
+ cp->err_info = (u32) (h->errinfo_pool_dhandle +
+ (i * sizeof(struct ErrorInfo)));
+ cp->err_info_len = sizeof(struct ErrorInfo);
+ cp->sgl_offset = IOACCEL1_SGLOFFSET;
+ cp->host_context_flags = IOACCEL1_HCFLAGS_CISS_FORMAT;
+ cp->timeout_sec = 0;
+ cp->ReplyQueue = 0;
+ cp->Tag.lower = (i << DIRECT_LOOKUP_SHIFT) |
+ DIRECT_LOOKUP_BIT;
+ cp->Tag.upper = 0;
+ cp->host_addr.lower =
+ (u32) (h->ioaccel_cmd_pool_dhandle +
+ (i * sizeof(struct io_accel1_cmd)));
+ cp->host_addr.upper = 0;
+ }
+ } else if (trans_support & CFGTBL_Trans_io_accel2) {
+ u64 cfg_offset, cfg_base_addr_index;
+ u32 bft2_offset, cfg_base_addr;
+ int rc;
+
+ rc = hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr,
+ &cfg_base_addr_index, &cfg_offset);
+ BUILD_BUG_ON(offsetof(struct io_accel2_cmd, sg) != 64);
+ bft2[15] = h->ioaccel_maxsg + HPSA_IOACCEL2_HEADER_SZ;
+ calc_bucket_map(bft2, ARRAY_SIZE(bft2), h->ioaccel_maxsg,
+ 4, h->ioaccel2_blockFetchTable);
+ bft2_offset = readl(&h->cfgtable->io_accel_request_size_offset);
+ BUILD_BUG_ON(offsetof(struct CfgTable,
+ io_accel_request_size_offset) != 0xb8);
+ h->ioaccel2_bft2_regs =
+ remap_pci_mem(pci_resource_start(h->pdev,
+ cfg_base_addr_index) +
+ cfg_offset + bft2_offset,
+ ARRAY_SIZE(bft2) *
+ sizeof(*h->ioaccel2_bft2_regs));
+ for (i = 0; i < ARRAY_SIZE(bft2); i++)
+ writel(bft2[i], &h->ioaccel2_bft2_regs[i]);
+ }
+ writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+ hpsa_wait_for_mode_change_ack(h);
+}
+
+static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h)
+{
+ h->ioaccel_maxsg =
+ readl(&(h->cfgtable->io_accel_max_embedded_sg_count));
+ if (h->ioaccel_maxsg > IOACCEL1_MAXSGENTRIES)
+ h->ioaccel_maxsg = IOACCEL1_MAXSGENTRIES;
+
+ /* Command structures must be aligned on a 128-byte boundary
+ * because the 7 lower bits of the address are used by the
+ * hardware.
+ */
+#define IOACCEL1_COMMANDLIST_ALIGNMENT 128
+ BUILD_BUG_ON(sizeof(struct io_accel1_cmd) %
+ IOACCEL1_COMMANDLIST_ALIGNMENT);
+ h->ioaccel_cmd_pool =
+ pci_alloc_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->ioaccel_cmd_pool),
+ &(h->ioaccel_cmd_pool_dhandle));
+
+ h->ioaccel1_blockFetchTable =
+ kmalloc(((h->ioaccel_maxsg + 1) *
+ sizeof(u32)), GFP_KERNEL);
+
+ if ((h->ioaccel_cmd_pool == NULL) ||
+ (h->ioaccel1_blockFetchTable == NULL))
+ goto clean_up;
+
+ memset(h->ioaccel_cmd_pool, 0,
+ h->nr_cmds * sizeof(*h->ioaccel_cmd_pool));
+ return 0;
+
+clean_up:
+ if (h->ioaccel_cmd_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->ioaccel_cmd_pool),
+ h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle);
+ kfree(h->ioaccel1_blockFetchTable);
+ return 1;
+}
+
+static int ioaccel2_alloc_cmds_and_bft(struct ctlr_info *h)
+{
+ /* Allocate ioaccel2 mode command blocks and block fetch table */
+
+ h->ioaccel_maxsg =
+ readl(&(h->cfgtable->io_accel_max_embedded_sg_count));
+ if (h->ioaccel_maxsg > IOACCEL2_MAXSGENTRIES)
+ h->ioaccel_maxsg = IOACCEL2_MAXSGENTRIES;
+
+#define IOACCEL2_COMMANDLIST_ALIGNMENT 128
+ BUILD_BUG_ON(sizeof(struct io_accel2_cmd) %
+ IOACCEL2_COMMANDLIST_ALIGNMENT);
+ h->ioaccel2_cmd_pool =
+ pci_alloc_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool),
+ &(h->ioaccel2_cmd_pool_dhandle));
+
+ h->ioaccel2_blockFetchTable =
+ kmalloc(((h->ioaccel_maxsg + 1) *
+ sizeof(u32)), GFP_KERNEL);
+
+ if ((h->ioaccel2_cmd_pool == NULL) ||
+ (h->ioaccel2_blockFetchTable == NULL))
+ goto clean_up;
+
+ memset(h->ioaccel2_cmd_pool, 0,
+ h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool));
+ return 0;
+
+clean_up:
+ if (h->ioaccel2_cmd_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool),
+ h->ioaccel2_cmd_pool, h->ioaccel2_cmd_pool_dhandle);
+ kfree(h->ioaccel2_blockFetchTable);
+ return 1;
}
static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
{
u32 trans_support;
+ unsigned long transMethod = CFGTBL_Trans_Performant |
+ CFGTBL_Trans_use_short_tags;
int i;
if (hpsa_simple_mode)
return;
+ /* Check for I/O accelerator mode support */
+ if (trans_support & CFGTBL_Trans_io_accel1) {
+ transMethod |= CFGTBL_Trans_io_accel1 |
+ CFGTBL_Trans_enable_directed_msix;
+ if (hpsa_alloc_ioaccel_cmd_and_bft(h))
+ goto clean_up;
+ } else {
+ if (trans_support & CFGTBL_Trans_io_accel2) {
+ transMethod |= CFGTBL_Trans_io_accel2 |
+ CFGTBL_Trans_enable_directed_msix;
+ if (ioaccel2_alloc_cmds_and_bft(h))
+ goto clean_up;
+ }
+ }
+
+ /* TODO, check that this next line h->nreply_queues is correct */
trans_support = readl(&(h->cfgtable->TransportSupport));
if (!(trans_support & PERFORMANT_MODE))
return;
- h->nreply_queues = h->msix_vector ? MAX_REPLY_QUEUES : 1;
+ h->nreply_queues = h->msix_vector > 0 ? h->msix_vector : 1;
hpsa_get_max_perf_mode_cmds(h);
/* Performant mode ring buffer and supporting data structures */
h->reply_pool_size = h->max_commands * sizeof(u64) * h->nreply_queues;
@@ -5200,9 +7505,7 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
|| (h->blockFetchTable == NULL))
goto clean_up;
- hpsa_enter_performant_mode(h,
- trans_support & CFGTBL_Trans_use_short_tags);
-
+ hpsa_enter_performant_mode(h, trans_support);
return;
clean_up:
@@ -5212,6 +7515,31 @@ clean_up:
kfree(h->blockFetchTable);
}
+static int is_accelerated_cmd(struct CommandList *c)
+{
+ return c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_IOACCEL2;
+}
+
+static void hpsa_drain_accel_commands(struct ctlr_info *h)
+{
+ struct CommandList *c = NULL;
+ unsigned long flags;
+ int accel_cmds_out;
+
+ do { /* wait for all outstanding commands to drain out */
+ accel_cmds_out = 0;
+ spin_lock_irqsave(&h->lock, flags);
+ list_for_each_entry(c, &h->cmpQ, list)
+ accel_cmds_out += is_accelerated_cmd(c);
+ list_for_each_entry(c, &h->reqQ, list)
+ accel_cmds_out += is_accelerated_cmd(c);
+ spin_unlock_irqrestore(&h->lock, flags);
+ if (accel_cmds_out <= 0)
+ break;
+ msleep(100);
+ } while (1);
+}
+
/*
* This is it. Register the PCI driver information for the cards we control
* the OS will call our registered routines when it finds one of our cards.
@@ -5226,5 +7554,83 @@ static void __exit hpsa_cleanup(void)
pci_unregister_driver(&hpsa_pci_driver);
}
+static void __attribute__((unused)) verify_offsets(void)
+{
+#define VERIFY_OFFSET(member, offset) \
+ BUILD_BUG_ON(offsetof(struct raid_map_data, member) != offset)
+
+ VERIFY_OFFSET(structure_size, 0);
+ VERIFY_OFFSET(volume_blk_size, 4);
+ VERIFY_OFFSET(volume_blk_cnt, 8);
+ VERIFY_OFFSET(phys_blk_shift, 16);
+ VERIFY_OFFSET(parity_rotation_shift, 17);
+ VERIFY_OFFSET(strip_size, 18);
+ VERIFY_OFFSET(disk_starting_blk, 20);
+ VERIFY_OFFSET(disk_blk_cnt, 28);
+ VERIFY_OFFSET(data_disks_per_row, 36);
+ VERIFY_OFFSET(metadata_disks_per_row, 38);
+ VERIFY_OFFSET(row_cnt, 40);
+ VERIFY_OFFSET(layout_map_count, 42);
+ VERIFY_OFFSET(flags, 44);
+ VERIFY_OFFSET(dekindex, 46);
+ /* VERIFY_OFFSET(reserved, 48 */
+ VERIFY_OFFSET(data, 64);
+
+#undef VERIFY_OFFSET
+
+#define VERIFY_OFFSET(member, offset) \
+ BUILD_BUG_ON(offsetof(struct io_accel2_cmd, member) != offset)
+
+ VERIFY_OFFSET(IU_type, 0);
+ VERIFY_OFFSET(direction, 1);
+ VERIFY_OFFSET(reply_queue, 2);
+ /* VERIFY_OFFSET(reserved1, 3); */
+ VERIFY_OFFSET(scsi_nexus, 4);
+ VERIFY_OFFSET(Tag, 8);
+ VERIFY_OFFSET(cdb, 16);
+ VERIFY_OFFSET(cciss_lun, 32);
+ VERIFY_OFFSET(data_len, 40);
+ VERIFY_OFFSET(cmd_priority_task_attr, 44);
+ VERIFY_OFFSET(sg_count, 45);
+ /* VERIFY_OFFSET(reserved3 */
+ VERIFY_OFFSET(err_ptr, 48);
+ VERIFY_OFFSET(err_len, 56);
+ /* VERIFY_OFFSET(reserved4 */
+ VERIFY_OFFSET(sg, 64);
+
+#undef VERIFY_OFFSET
+
+#define VERIFY_OFFSET(member, offset) \
+ BUILD_BUG_ON(offsetof(struct io_accel1_cmd, member) != offset)
+
+ VERIFY_OFFSET(dev_handle, 0x00);
+ VERIFY_OFFSET(reserved1, 0x02);
+ VERIFY_OFFSET(function, 0x03);
+ VERIFY_OFFSET(reserved2, 0x04);
+ VERIFY_OFFSET(err_info, 0x0C);
+ VERIFY_OFFSET(reserved3, 0x10);
+ VERIFY_OFFSET(err_info_len, 0x12);
+ VERIFY_OFFSET(reserved4, 0x13);
+ VERIFY_OFFSET(sgl_offset, 0x14);
+ VERIFY_OFFSET(reserved5, 0x15);
+ VERIFY_OFFSET(transfer_len, 0x1C);
+ VERIFY_OFFSET(reserved6, 0x20);
+ VERIFY_OFFSET(io_flags, 0x24);
+ VERIFY_OFFSET(reserved7, 0x26);
+ VERIFY_OFFSET(LUN, 0x34);
+ VERIFY_OFFSET(control, 0x3C);
+ VERIFY_OFFSET(CDB, 0x40);
+ VERIFY_OFFSET(reserved8, 0x50);
+ VERIFY_OFFSET(host_context_flags, 0x60);
+ VERIFY_OFFSET(timeout_sec, 0x62);
+ VERIFY_OFFSET(ReplyQueue, 0x64);
+ VERIFY_OFFSET(reserved9, 0x65);
+ VERIFY_OFFSET(Tag, 0x68);
+ VERIFY_OFFSET(host_addr, 0x70);
+ VERIFY_OFFSET(CISS_LUN, 0x78);
+ VERIFY_OFFSET(SG, 0x78 + 8);
+#undef VERIFY_OFFSET
+}
+
module_init(hpsa_init);
module_exit(hpsa_cleanup);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 01c328349c83..44235a27e1b6 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -1,6 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
- * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P.
+ * Copyright 2000, 2014 Hewlett-Packard Development Company, L.P.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -46,6 +46,15 @@ struct hpsa_scsi_dev_t {
unsigned char vendor[8]; /* bytes 8-15 of inquiry data */
unsigned char model[16]; /* bytes 16-31 of inquiry data */
unsigned char raid_level; /* from inquiry page 0xC1 */
+ unsigned char volume_offline; /* discovered via TUR or VPD */
+ u32 ioaccel_handle;
+ int offload_config; /* I/O accel RAID offload configured */
+ int offload_enabled; /* I/O accel RAID offload enabled */
+ int offload_to_mirror; /* Send next I/O accelerator RAID
+ * offload request to mirror drive
+ */
+ struct raid_map_data raid_map; /* I/O accelerator RAID map */
+
};
struct reply_pool {
@@ -55,6 +64,46 @@ struct reply_pool {
u32 current_entry;
};
+#pragma pack(1)
+struct bmic_controller_parameters {
+ u8 led_flags;
+ u8 enable_command_list_verification;
+ u8 backed_out_write_drives;
+ u16 stripes_for_parity;
+ u8 parity_distribution_mode_flags;
+ u16 max_driver_requests;
+ u16 elevator_trend_count;
+ u8 disable_elevator;
+ u8 force_scan_complete;
+ u8 scsi_transfer_mode;
+ u8 force_narrow;
+ u8 rebuild_priority;
+ u8 expand_priority;
+ u8 host_sdb_asic_fix;
+ u8 pdpi_burst_from_host_disabled;
+ char software_name[64];
+ char hardware_name[32];
+ u8 bridge_revision;
+ u8 snapshot_priority;
+ u32 os_specific;
+ u8 post_prompt_timeout;
+ u8 automatic_drive_slamming;
+ u8 reserved1;
+ u8 nvram_flags;
+ u8 cache_nvram_flags;
+ u8 drive_config_flags;
+ u16 reserved2;
+ u8 temp_warning_level;
+ u8 temp_shutdown_level;
+ u8 temp_condition_reset;
+ u8 max_coalesce_commands;
+ u32 max_coalesce_delay;
+ u8 orca_password[4];
+ u8 access_id[16];
+ u8 reserved[356];
+};
+#pragma pack()
+
struct ctlr_info {
int ctlr;
char devname[8];
@@ -80,6 +129,7 @@ struct ctlr_info {
unsigned int msi_vector;
int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */
struct access_method access;
+ char hba_mode_enabled;
/* queue and queue Info */
struct list_head reqQ;
@@ -95,6 +145,10 @@ struct ctlr_info {
/* pointers to command and error info pool */
struct CommandList *cmd_pool;
dma_addr_t cmd_pool_dhandle;
+ struct io_accel1_cmd *ioaccel_cmd_pool;
+ dma_addr_t ioaccel_cmd_pool_dhandle;
+ struct io_accel2_cmd *ioaccel2_cmd_pool;
+ dma_addr_t ioaccel2_cmd_pool_dhandle;
struct ErrorInfo *errinfo_pool;
dma_addr_t errinfo_pool_dhandle;
unsigned long *cmd_pool_bits;
@@ -128,7 +182,14 @@ struct ctlr_info {
u8 nreply_queues;
dma_addr_t reply_pool_dhandle;
u32 *blockFetchTable;
+ u32 *ioaccel1_blockFetchTable;
+ u32 *ioaccel2_blockFetchTable;
+ u32 *ioaccel2_bft2_regs;
unsigned char *hba_inquiry_data;
+ u32 driver_support;
+ u32 fw_support;
+ int ioaccel_support;
+ int ioaccel_maxsg;
u64 last_intr_timestamp;
u32 last_heartbeat;
u64 last_heartbeat_timestamp;
@@ -161,7 +222,35 @@ struct ctlr_info {
#define HPSATMF_LOG_QRY_TASK (1 << 23)
#define HPSATMF_LOG_QRY_TSET (1 << 24)
#define HPSATMF_LOG_QRY_ASYNC (1 << 25)
+ u32 events;
+#define CTLR_STATE_CHANGE_EVENT (1 << 0)
+#define CTLR_ENCLOSURE_HOT_PLUG_EVENT (1 << 1)
+#define CTLR_STATE_CHANGE_EVENT_PHYSICAL_DRV (1 << 4)
+#define CTLR_STATE_CHANGE_EVENT_LOGICAL_DRV (1 << 5)
+#define CTLR_STATE_CHANGE_EVENT_REDUNDANT_CNTRL (1 << 6)
+#define CTLR_STATE_CHANGE_EVENT_AIO_ENABLED_DISABLED (1 << 30)
+#define CTLR_STATE_CHANGE_EVENT_AIO_CONFIG_CHANGE (1 << 31)
+
+#define RESCAN_REQUIRED_EVENT_BITS \
+ (CTLR_STATE_CHANGE_EVENT | \
+ CTLR_ENCLOSURE_HOT_PLUG_EVENT | \
+ CTLR_STATE_CHANGE_EVENT_PHYSICAL_DRV | \
+ CTLR_STATE_CHANGE_EVENT_LOGICAL_DRV | \
+ CTLR_STATE_CHANGE_EVENT_REDUNDANT_CNTRL | \
+ CTLR_STATE_CHANGE_EVENT_AIO_ENABLED_DISABLED | \
+ CTLR_STATE_CHANGE_EVENT_AIO_CONFIG_CHANGE)
+ spinlock_t offline_device_lock;
+ struct list_head offline_device_list;
+ int acciopath_status;
+ int drv_req_rescan; /* flag for driver to request rescan event */
+ int raid_offload_debug;
};
+
+struct offline_device_entry {
+ unsigned char scsi3addr[8];
+ struct list_head offline_list;
+};
+
#define HPSA_ABORT_MSG 0
#define HPSA_DEVICE_RESET_MSG 1
#define HPSA_RESET_TYPE_CONTROLLER 0x00
@@ -242,6 +331,14 @@ struct ctlr_info {
#define HPSA_INTR_ON 1
#define HPSA_INTR_OFF 0
+
+/*
+ * Inbound Post Queue offsets for IO Accelerator Mode 2
+ */
+#define IOACCEL2_INBOUND_POSTQ_32 0x48
+#define IOACCEL2_INBOUND_POSTQ_64_LOW 0xd0
+#define IOACCEL2_INBOUND_POSTQ_64_HI 0xd4
+
/*
Send the command to the hardware
*/
@@ -254,6 +351,18 @@ static void SA5_submit_command(struct ctlr_info *h,
(void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
}
+static void SA5_submit_command_ioaccel2(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr,
+ c->Header.Tag.lower);
+ if (c->cmd_type == CMD_IOACCEL2)
+ writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32);
+ else
+ writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
+ (void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
+}
+
/*
* This card is the opposite of the other cards.
* 0 turns interrupts on...
@@ -387,6 +496,50 @@ static bool SA5_performant_intr_pending(struct ctlr_info *h)
return register_value & SA5_OUTDB_STATUS_PERF_BIT;
}
+#define SA5_IOACCEL_MODE1_INTR_STATUS_CMP_BIT 0x100
+
+static bool SA5_ioaccel_mode1_intr_pending(struct ctlr_info *h)
+{
+ unsigned long register_value = readl(h->vaddr + SA5_INTR_STATUS);
+
+ return (register_value & SA5_IOACCEL_MODE1_INTR_STATUS_CMP_BIT) ?
+ true : false;
+}
+
+#define IOACCEL_MODE1_REPLY_QUEUE_INDEX 0x1A0
+#define IOACCEL_MODE1_PRODUCER_INDEX 0x1B8
+#define IOACCEL_MODE1_CONSUMER_INDEX 0x1BC
+#define IOACCEL_MODE1_REPLY_UNUSED 0xFFFFFFFFFFFFFFFFULL
+
+static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q)
+{
+ u64 register_value;
+ struct reply_pool *rq = &h->reply_queue[q];
+ unsigned long flags;
+
+ BUG_ON(q >= h->nreply_queues);
+
+ register_value = rq->head[rq->current_entry];
+ if (register_value != IOACCEL_MODE1_REPLY_UNUSED) {
+ rq->head[rq->current_entry] = IOACCEL_MODE1_REPLY_UNUSED;
+ if (++rq->current_entry == rq->size)
+ rq->current_entry = 0;
+ /*
+ * @todo
+ *
+ * Don't really need to write the new index after each command,
+ * but with current driver design this is easiest.
+ */
+ wmb();
+ writel((q << 24) | rq->current_entry, h->vaddr +
+ IOACCEL_MODE1_CONSUMER_INDEX);
+ spin_lock_irqsave(&h->lock, flags);
+ h->commands_outstanding--;
+ spin_unlock_irqrestore(&h->lock, flags);
+ }
+ return (unsigned long) register_value;
+}
+
static struct access_method SA5_access = {
SA5_submit_command,
SA5_intr_mask,
@@ -395,6 +548,22 @@ static struct access_method SA5_access = {
SA5_completed,
};
+static struct access_method SA5_ioaccel_mode1_access = {
+ SA5_submit_command,
+ SA5_performant_intr_mask,
+ SA5_fifo_full,
+ SA5_ioaccel_mode1_intr_pending,
+ SA5_ioaccel_mode1_completed,
+};
+
+static struct access_method SA5_ioaccel_mode2_access = {
+ SA5_submit_command_ioaccel2,
+ SA5_performant_intr_mask,
+ SA5_fifo_full,
+ SA5_performant_intr_pending,
+ SA5_performant_completed,
+};
+
static struct access_method SA5_performant_access = {
SA5_submit_command,
SA5_performant_intr_mask,
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index bfc8c4ea66f8..b5cc7052339f 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -1,6 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
- * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P.
+ * Copyright 2000, 2014 Hewlett-Packard Development Company, L.P.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
#define SENSEINFOBYTES 32 /* may vary between hbas */
#define SG_ENTRIES_IN_CMD 32 /* Max SG entries excluding chain blocks */
#define HPSA_SG_CHAIN 0x80000000
+#define HPSA_SG_LAST 0x40000000
#define MAXREPLYQS 256
/* Command Status value */
@@ -41,6 +42,8 @@
#define CMD_UNSOLICITED_ABORT 0x000A
#define CMD_TIMEOUT 0x000B
#define CMD_UNABORTABLE 0x000C
+#define CMD_IOACCEL_DISABLED 0x000E
+
/* Unit Attentions ASC's as defined for the MSA2012sa */
#define POWER_OR_RESET 0x29
@@ -79,8 +82,9 @@
#define ATTR_ACA 0x07
/* cdb type */
-#define TYPE_CMD 0x00
-#define TYPE_MSG 0x01
+#define TYPE_CMD 0x00
+#define TYPE_MSG 0x01
+#define TYPE_IOACCEL2_CMD 0x81 /* 0x81 is not used by hardware */
/* Message Types */
#define HPSA_TASK_MANAGEMENT 0x00
@@ -125,9 +129,12 @@
#define CFGTBL_AccCmds 0x00000001l
#define DOORBELL_CTLR_RESET 0x00000004l
#define DOORBELL_CTLR_RESET2 0x00000020l
+#define DOORBELL_CLEAR_EVENTS 0x00000040l
#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
+#define CFGTBL_Trans_io_accel1 0x00000080l
+#define CFGTBL_Trans_io_accel2 0x00000100l
#define CFGTBL_Trans_use_short_tags 0x20000000l
#define CFGTBL_Trans_enable_directed_msix (1 << 30)
@@ -135,6 +142,28 @@
#define CFGTBL_BusType_Ultra3 0x00000002l
#define CFGTBL_BusType_Fibre1G 0x00000100l
#define CFGTBL_BusType_Fibre2G 0x00000200l
+
+/* VPD Inquiry types */
+#define HPSA_VPD_SUPPORTED_PAGES 0x00
+#define HPSA_VPD_LV_DEVICE_GEOMETRY 0xC1
+#define HPSA_VPD_LV_IOACCEL_STATUS 0xC2
+#define HPSA_VPD_LV_STATUS 0xC3
+#define HPSA_VPD_HEADER_SZ 4
+
+/* Logical volume states */
+#define HPSA_VPD_LV_STATUS_UNSUPPORTED -1
+#define HPSA_LV_OK 0x0
+#define HPSA_LV_UNDERGOING_ERASE 0x0F
+#define HPSA_LV_UNDERGOING_RPI 0x12
+#define HPSA_LV_PENDING_RPI 0x13
+#define HPSA_LV_ENCRYPTED_NO_KEY 0x14
+#define HPSA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER 0x15
+#define HPSA_LV_UNDERGOING_ENCRYPTION 0x16
+#define HPSA_LV_UNDERGOING_ENCRYPTION_REKEYING 0x17
+#define HPSA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER 0x18
+#define HPSA_LV_PENDING_ENCRYPTION 0x19
+#define HPSA_LV_PENDING_ENCRYPTION_REKEYING 0x1A
+
struct vals32 {
u32 lower;
u32 upper;
@@ -162,9 +191,50 @@ struct InquiryData {
#define HPSA_REPORT_LOG 0xc2 /* Report Logical LUNs */
#define HPSA_REPORT_PHYS 0xc3 /* Report Physical LUNs */
+#define HPSA_REPORT_PHYS_EXTENDED 0x02
+#define HPSA_CISS_READ 0xc0 /* CISS Read */
+#define HPSA_GET_RAID_MAP 0xc8 /* CISS Get RAID Layout Map */
+
+#define RAID_MAP_MAX_ENTRIES 256
+
+struct raid_map_disk_data {
+ u32 ioaccel_handle; /**< Handle to access this disk via the
+ * I/O accelerator */
+ u8 xor_mult[2]; /**< XOR multipliers for this position,
+ * valid for data disks only */
+ u8 reserved[2];
+};
+
+struct raid_map_data {
+ u32 structure_size; /* Size of entire structure in bytes */
+ u32 volume_blk_size; /* bytes / block in the volume */
+ u64 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 */
+ u16 strip_size; /* blocks used on each disk / stripe */
+ u64 disk_starting_blk; /* First disk block used in volume */
+ u64 disk_blk_cnt; /* disk blocks used by volume / disk */
+ u16 data_disks_per_row; /* data disk entries / row in the map */
+ u16 metadata_disks_per_row; /* mirror/parity disk entries / row
+ * in the map */
+ u16 row_cnt; /* rows in each layout map */
+ u16 layout_map_count; /* layout maps (1 map per mirror/parity
+ * group) */
+ u16 flags; /* Bit 0 set if encryption enabled */
+#define RAID_MAP_FLAG_ENCRYPT_ON 0x01
+ u16 dekindex; /* Data encryption key index. */
+ u8 reserved[16];
+ struct raid_map_disk_data data[RAID_MAP_MAX_ENTRIES];
+};
+
struct ReportLUNdata {
u8 LUNListLength[4];
- u32 reserved;
+ u8 extended_response_flag;
+ u8 reserved[3];
u8 LUN[HPSA_MAX_LUN][8];
};
@@ -187,6 +257,7 @@ struct SenseSubsystem_info {
#define BMIC_CACHE_FLUSH 0xc2
#define HPSA_CACHE_FLUSH 0x01 /* C2 was already being used by HPSA */
#define BMIC_FLASH_FIRMWARE 0xF7
+#define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64
/* Command List Structure */
union SCSI3Addr {
@@ -283,6 +354,8 @@ struct ErrorInfo {
/* Command types */
#define CMD_IOCTL_PEND 0x01
#define CMD_SCSI 0x03
+#define CMD_IOACCEL1 0x04
+#define CMD_IOACCEL2 0x05
#define DIRECT_LOOKUP_SHIFT 5
#define DIRECT_LOOKUP_BIT 0x10
@@ -314,7 +387,6 @@ struct CommandList {
int cmd_type;
long cmdindex;
struct list_head list;
- struct request *rq;
struct completion *waiting;
void *scsi_cmd;
@@ -327,16 +399,183 @@ struct CommandList {
*/
#define IS_32_BIT ((8 - sizeof(long))/4)
#define IS_64_BIT (!IS_32_BIT)
-#define PAD_32 (4)
-#define PAD_64 (4)
+#define PAD_32 (40)
+#define PAD_64 (12)
#define COMMANDLIST_PAD (IS_32_BIT * PAD_32 + IS_64_BIT * PAD_64)
u8 pad[COMMANDLIST_PAD];
};
+/* Max S/G elements in I/O accelerator command */
+#define IOACCEL1_MAXSGENTRIES 24
+#define IOACCEL2_MAXSGENTRIES 28
+
+/*
+ * Structure for I/O accelerator (mode 1) commands.
+ * Note that this structure must be 128-byte aligned in size.
+ */
+struct io_accel1_cmd {
+ u16 dev_handle; /* 0x00 - 0x01 */
+ u8 reserved1; /* 0x02 */
+ u8 function; /* 0x03 */
+ u8 reserved2[8]; /* 0x04 - 0x0B */
+ u32 err_info; /* 0x0C - 0x0F */
+ u8 reserved3[2]; /* 0x10 - 0x11 */
+ u8 err_info_len; /* 0x12 */
+ u8 reserved4; /* 0x13 */
+ u8 sgl_offset; /* 0x14 */
+ u8 reserved5[7]; /* 0x15 - 0x1B */
+ u32 transfer_len; /* 0x1C - 0x1F */
+ u8 reserved6[4]; /* 0x20 - 0x23 */
+ u16 io_flags; /* 0x24 - 0x25 */
+ u8 reserved7[14]; /* 0x26 - 0x33 */
+ u8 LUN[8]; /* 0x34 - 0x3B */
+ u32 control; /* 0x3C - 0x3F */
+ u8 CDB[16]; /* 0x40 - 0x4F */
+ u8 reserved8[16]; /* 0x50 - 0x5F */
+ u16 host_context_flags; /* 0x60 - 0x61 */
+ u16 timeout_sec; /* 0x62 - 0x63 */
+ u8 ReplyQueue; /* 0x64 */
+ u8 reserved9[3]; /* 0x65 - 0x67 */
+ struct vals32 Tag; /* 0x68 - 0x6F */
+ struct vals32 host_addr; /* 0x70 - 0x77 */
+ u8 CISS_LUN[8]; /* 0x78 - 0x7F */
+ struct SGDescriptor SG[IOACCEL1_MAXSGENTRIES];
+#define IOACCEL1_PAD_64 0
+#define IOACCEL1_PAD_32 0
+#define IOACCEL1_PAD (IS_32_BIT * IOACCEL1_PAD_32 + \
+ IS_64_BIT * IOACCEL1_PAD_64)
+ u8 pad[IOACCEL1_PAD];
+};
+
+#define IOACCEL1_FUNCTION_SCSIIO 0x00
+#define IOACCEL1_SGLOFFSET 32
+
+#define IOACCEL1_IOFLAGS_IO_REQ 0x4000
+#define IOACCEL1_IOFLAGS_CDBLEN_MASK 0x001F
+#define IOACCEL1_IOFLAGS_CDBLEN_MAX 16
+
+#define IOACCEL1_CONTROL_NODATAXFER 0x00000000
+#define IOACCEL1_CONTROL_DATA_OUT 0x01000000
+#define IOACCEL1_CONTROL_DATA_IN 0x02000000
+#define IOACCEL1_CONTROL_TASKPRIO_MASK 0x00007800
+#define IOACCEL1_CONTROL_TASKPRIO_SHIFT 11
+#define IOACCEL1_CONTROL_SIMPLEQUEUE 0x00000000
+#define IOACCEL1_CONTROL_HEADOFQUEUE 0x00000100
+#define IOACCEL1_CONTROL_ORDEREDQUEUE 0x00000200
+#define IOACCEL1_CONTROL_ACA 0x00000400
+
+#define IOACCEL1_HCFLAGS_CISS_FORMAT 0x0013
+
+#define IOACCEL1_BUSADDR_CMDTYPE 0x00000060
+
+struct ioaccel2_sg_element {
+ u64 address;
+ u32 length;
+ u8 reserved[3];
+ u8 chain_indicator;
+#define IOACCEL2_CHAIN 0x80
+};
+
+/*
+ * SCSI Response Format structure for IO Accelerator Mode 2
+ */
+struct io_accel2_scsi_response {
+ u8 IU_type;
+#define IOACCEL2_IU_TYPE_SRF 0x60
+ u8 reserved1[3];
+ u8 req_id[4]; /* request identifier */
+ u8 reserved2[4];
+ u8 serv_response; /* service response */
+#define IOACCEL2_SERV_RESPONSE_COMPLETE 0x000
+#define IOACCEL2_SERV_RESPONSE_FAILURE 0x001
+#define IOACCEL2_SERV_RESPONSE_TMF_COMPLETE 0x002
+#define IOACCEL2_SERV_RESPONSE_TMF_SUCCESS 0x003
+#define IOACCEL2_SERV_RESPONSE_TMF_REJECTED 0x004
+#define IOACCEL2_SERV_RESPONSE_TMF_WRONG_LUN 0x005
+ u8 status; /* status */
+#define IOACCEL2_STATUS_SR_TASK_COMP_GOOD 0x00
+#define IOACCEL2_STATUS_SR_TASK_COMP_CHK_COND 0x02
+#define IOACCEL2_STATUS_SR_TASK_COMP_BUSY 0x08
+#define IOACCEL2_STATUS_SR_TASK_COMP_RES_CON 0x18
+#define IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL 0x28
+#define IOACCEL2_STATUS_SR_TASK_COMP_ABORTED 0x40
+#define IOACCEL2_STATUS_SR_IOACCEL_DISABLED 0x0E
+ u8 data_present; /* low 2 bits */
+#define IOACCEL2_NO_DATAPRESENT 0x000
+#define IOACCEL2_RESPONSE_DATAPRESENT 0x001
+#define IOACCEL2_SENSE_DATA_PRESENT 0x002
+#define IOACCEL2_RESERVED 0x003
+ u8 sense_data_len; /* sense/response data length */
+ u8 resid_cnt[4]; /* residual count */
+ u8 sense_data_buff[32]; /* sense/response data buffer */
+};
+
+#define IOACCEL2_64_PAD 76
+#define IOACCEL2_32_PAD 76
+#define IOACCEL2_PAD (IS_32_BIT * IOACCEL2_32_PAD + \
+ IS_64_BIT * IOACCEL2_64_PAD)
+/*
+ * Structure for I/O accelerator (mode 2 or m2) commands.
+ * Note that this structure must be 128-byte aligned in size.
+ */
+struct io_accel2_cmd {
+ u8 IU_type; /* IU Type */
+ u8 direction; /* direction, memtype, and encryption */
+#define IOACCEL2_DIRECTION_MASK 0x03 /* bits 0,1: direction */
+#define IOACCEL2_DIRECTION_MEMTYPE_MASK 0x04 /* bit 2: memtype source/dest */
+ /* 0b=PCIe, 1b=DDR */
+#define IOACCEL2_DIRECTION_ENCRYPT_MASK 0x08 /* bit 3: encryption flag */
+ /* 0=off, 1=on */
+ u8 reply_queue; /* Reply Queue ID */
+ u8 reserved1; /* Reserved */
+ u32 scsi_nexus; /* Device Handle */
+ u32 Tag; /* cciss tag, lower 4 bytes only */
+ u32 tweak_lower; /* Encryption tweak, lower 4 bytes */
+ u8 cdb[16]; /* SCSI Command Descriptor Block */
+ u8 cciss_lun[8]; /* 8 byte SCSI address */
+ u32 data_len; /* Total bytes to transfer */
+ u8 cmd_priority_task_attr; /* priority and task attrs */
+#define IOACCEL2_PRIORITY_MASK 0x78
+#define IOACCEL2_ATTR_MASK 0x07
+ u8 sg_count; /* Number of sg elements */
+ u16 dekindex; /* Data encryption key index */
+ u64 err_ptr; /* Error Pointer */
+ u32 err_len; /* Error Length*/
+ u32 tweak_upper; /* Encryption tweak, upper 4 bytes */
+ struct ioaccel2_sg_element sg[IOACCEL2_MAXSGENTRIES];
+ struct io_accel2_scsi_response error_data;
+ u8 pad[IOACCEL2_PAD];
+};
+
+/*
+ * defines for Mode 2 command struct
+ * FIXME: this can't be all I need mfm
+ */
+#define IOACCEL2_IU_TYPE 0x40
+#define IOACCEL2_IU_TMF_TYPE 0x41
+#define IOACCEL2_DIR_NO_DATA 0x00
+#define IOACCEL2_DIR_DATA_IN 0x01
+#define IOACCEL2_DIR_DATA_OUT 0x02
+/*
+ * SCSI Task Management Request format for Accelerator Mode 2
+ */
+struct hpsa_tmf_struct {
+ u8 iu_type; /* Information Unit Type */
+ u8 reply_queue; /* Reply Queue ID */
+ u8 tmf; /* Task Management Function */
+ u8 reserved1; /* byte 3 Reserved */
+ u32 it_nexus; /* SCSI I-T Nexus */
+ u8 lun_id[8]; /* LUN ID for TMF request */
+ struct vals32 Tag; /* cciss tag associated w/ request */
+ struct vals32 abort_tag;/* cciss tag of SCSI cmd or task to abort */
+ u64 error_ptr; /* Error Pointer */
+ u32 error_len; /* Error Length */
+};
+
/* Configuration Table Structure */
struct HostWrite {
u32 TransportRequest;
- u32 Reserved;
+ u32 command_pool_addr_hi;
u32 CoalIntDelay;
u32 CoalIntCount;
};
@@ -344,6 +583,9 @@ struct HostWrite {
#define SIMPLE_MODE 0x02
#define PERFORMANT_MODE 0x04
#define MEMQ_MODE 0x08
+#define IOACCEL_MODE_1 0x80
+
+#define DRIVER_SUPPORT_UA_ENABLE 0x00000001
struct CfgTable {
u8 Signature[4];
@@ -373,8 +615,18 @@ struct CfgTable {
u32 misc_fw_support; /* offset 0x78 */
#define MISC_FW_DOORBELL_RESET (0x02)
#define MISC_FW_DOORBELL_RESET2 (0x010)
+#define MISC_FW_RAID_OFFLOAD_BASIC (0x020)
+#define MISC_FW_EVENT_NOTIFY (0x080)
u8 driver_version[32];
-
+ u32 max_cached_write_size;
+ u8 driver_scratchpad[16];
+ u32 max_error_info_length;
+ u32 io_accel_max_embedded_sg_count;
+ u32 io_accel_request_size_offset;
+ u32 event_notify;
+#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE (1 << 30)
+#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE (1 << 31)
+ u32 clear_event_notify;
};
#define NUM_BLOCKFETCH_ENTRIES 8
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index bf9eca845166..56f8a861ed72 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -589,7 +589,7 @@ static int crq_queue_create(struct crq_queue *queue, struct srp_target *target)
}
err = request_irq(vport->dma_dev->irq, &ibmvstgt_interrupt,
- IRQF_DISABLED, "ibmvstgt", target);
+ 0, "ibmvstgt", target);
if (err)
goto req_irq_failed;
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index bf028218ac36..b1c4d831137d 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -2015,7 +2015,7 @@ static int __init in2000_detect(struct scsi_host_template * tpnt)
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, IRQF_DISABLED, "in2000", instance)) {
+ if (request_irq(x, in2000_intr, 0, "in2000", instance)) {
printk("in2000_detect: Unable to allocate IRQ.\n");
detect_count--;
continue;
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 280d5af113d1..e5dae7b54d9a 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -2931,7 +2931,7 @@ static int initio_probe_one(struct pci_dev *pdev,
shost->base = host->addr;
shost->sg_tablesize = TOTAL_SG_ENTRY;
- error = request_irq(pdev->irq, i91u_intr, IRQF_DISABLED|IRQF_SHARED, "i91u", shost);
+ error = request_irq(pdev->irq, i91u_intr, IRQF_SHARED, "i91u", shost);
if (error < 0) {
printk(KERN_WARNING "initio: Unable to request IRQ %d\n", pdev->irq);
goto out_free_scbs;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 3f5b56a99892..924b0ba74dfe 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -1143,6 +1143,7 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res,
res->add_to_ml = 0;
res->del_from_ml = 0;
res->resetting_device = 0;
+ res->reset_occurred = 0;
res->sdev = NULL;
res->sata_port = NULL;
@@ -2367,6 +2368,42 @@ static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg,
}
/**
+ * ipr_log_sis64_device_error - Log a cache error.
+ * @ioa_cfg: ioa config struct
+ * @hostrcb: hostrcb struct
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_log_sis64_device_error(struct ipr_ioa_cfg *ioa_cfg,
+ struct ipr_hostrcb *hostrcb)
+{
+ struct ipr_hostrcb_type_21_error *error;
+ char buffer[IPR_MAX_RES_PATH_LENGTH];
+
+ error = &hostrcb->hcam.u.error64.u.type_21_error;
+
+ ipr_err("-----Failing Device Information-----\n");
+ ipr_err("World Wide Unique ID: %08X%08X%08X%08X\n",
+ be32_to_cpu(error->wwn[0]), be32_to_cpu(error->wwn[1]),
+ be32_to_cpu(error->wwn[2]), be32_to_cpu(error->wwn[3]));
+ ipr_err("Device Resource Path: %s\n",
+ __ipr_format_res_path(error->res_path,
+ buffer, sizeof(buffer)));
+ error->primary_problem_desc[sizeof(error->primary_problem_desc) - 1] = '\0';
+ error->second_problem_desc[sizeof(error->second_problem_desc) - 1] = '\0';
+ ipr_err("Primary Problem Description: %s\n", error->primary_problem_desc);
+ ipr_err("Secondary Problem Description: %s\n", error->second_problem_desc);
+ ipr_err("SCSI Sense Data:\n");
+ ipr_log_hex_data(ioa_cfg, error->sense_data, sizeof(error->sense_data));
+ ipr_err("SCSI Command Descriptor Block: \n");
+ ipr_log_hex_data(ioa_cfg, error->cdb, sizeof(error->cdb));
+
+ ipr_err("Additional IOA Data:\n");
+ ipr_log_hex_data(ioa_cfg, error->ioa_data, be32_to_cpu(error->length_of_error));
+}
+
+/**
* ipr_get_error - Find the specfied IOASC in the ipr_error_table.
* @ioasc: IOASC
*
@@ -2467,6 +2504,9 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
case IPR_HOST_RCB_OVERLAY_ID_20:
ipr_log_fabric_error(ioa_cfg, hostrcb);
break;
+ case IPR_HOST_RCB_OVERLAY_ID_21:
+ ipr_log_sis64_device_error(ioa_cfg, hostrcb);
+ break;
case IPR_HOST_RCB_OVERLAY_ID_23:
ipr_log_sis64_config_error(ioa_cfg, hostrcb);
break;
@@ -3630,16 +3670,14 @@ static ssize_t ipr_store_iopoll_weight(struct device *dev,
return strlen(buf);
}
- if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
- ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+ if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
for (i = 1; i < ioa_cfg->hrrq_num; i++)
blk_iopoll_disable(&ioa_cfg->hrrq[i].iopoll);
}
spin_lock_irqsave(shost->host_lock, lock_flags);
ioa_cfg->iopoll_weight = user_iopoll_weight;
- if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
- ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+ if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
for (i = 1; i < ioa_cfg->hrrq_num; i++) {
blk_iopoll_init(&ioa_cfg->hrrq[i].iopoll,
ioa_cfg->iopoll_weight, ipr_iopoll);
@@ -5015,6 +5053,7 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd)
} else
rc = ipr_device_reset(ioa_cfg, res);
res->resetting_device = 0;
+ res->reset_occurred = 1;
LEAVE;
return rc ? FAILED : SUCCESS;
@@ -5484,8 +5523,7 @@ static irqreturn_t ipr_isr_mhrrq(int irq, void *devp)
return IRQ_NONE;
}
- if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
- ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+ if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
if ((be32_to_cpu(*hrrq->hrrq_curr) & IPR_HRRQ_TOGGLE_BIT) ==
hrrq->toggle_bit) {
if (!blk_iopoll_sched_prep(&hrrq->iopoll))
@@ -6183,8 +6221,10 @@ static int ipr_queuecommand(struct Scsi_Host *shost,
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
- if (ipr_is_gscsi(res))
+ if (ipr_is_gscsi(res) && res->reset_occurred) {
+ res->reset_occurred = 0;
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST;
+ }
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR;
ioarcb->cmd_pkt.flags_lo |= ipr_get_task_attributes(scsi_cmd);
}
@@ -8641,6 +8681,25 @@ static int ipr_reset_freeze(struct ipr_cmnd *ipr_cmd)
}
/**
+ * ipr_pci_mmio_enabled - Called when MMIO has been re-enabled
+ * @pdev: PCI device struct
+ *
+ * Description: This routine is called to tell us that the MMIO
+ * access to the IOA has been restored
+ */
+static pci_ers_result_t ipr_pci_mmio_enabled(struct pci_dev *pdev)
+{
+ unsigned long flags = 0;
+ struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
+
+ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+ if (!ioa_cfg->probe_done)
+ pci_save_state(pdev);
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
* ipr_pci_frozen - Called when slot has experienced a PCI bus error.
* @pdev: PCI device struct
*
@@ -8654,7 +8713,8 @@ static void ipr_pci_frozen(struct pci_dev *pdev)
struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
- _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_freeze, IPR_SHUTDOWN_NONE);
+ if (ioa_cfg->probe_done)
+ _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_freeze, IPR_SHUTDOWN_NONE);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
}
@@ -8672,11 +8732,14 @@ static pci_ers_result_t ipr_pci_slot_reset(struct pci_dev *pdev)
struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
- if (ioa_cfg->needs_warm_reset)
- ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
- else
- _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
- IPR_SHUTDOWN_NONE);
+ if (ioa_cfg->probe_done) {
+ if (ioa_cfg->needs_warm_reset)
+ ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+ else
+ _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
+ IPR_SHUTDOWN_NONE);
+ } else
+ wake_up_all(&ioa_cfg->eeh_wait_q);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
return PCI_ERS_RESULT_RECOVERED;
}
@@ -8695,17 +8758,20 @@ static void ipr_pci_perm_failure(struct pci_dev *pdev)
int i;
spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
- if (ioa_cfg->sdt_state == WAIT_FOR_DUMP)
- ioa_cfg->sdt_state = ABORT_DUMP;
- ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES - 1;
- ioa_cfg->in_ioa_bringdown = 1;
- for (i = 0; i < ioa_cfg->hrrq_num; i++) {
- spin_lock(&ioa_cfg->hrrq[i]._lock);
- ioa_cfg->hrrq[i].allow_cmds = 0;
- spin_unlock(&ioa_cfg->hrrq[i]._lock);
- }
- wmb();
- ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+ if (ioa_cfg->probe_done) {
+ if (ioa_cfg->sdt_state == WAIT_FOR_DUMP)
+ ioa_cfg->sdt_state = ABORT_DUMP;
+ ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES - 1;
+ ioa_cfg->in_ioa_bringdown = 1;
+ for (i = 0; i < ioa_cfg->hrrq_num; i++) {
+ spin_lock(&ioa_cfg->hrrq[i]._lock);
+ ioa_cfg->hrrq[i].allow_cmds = 0;
+ spin_unlock(&ioa_cfg->hrrq[i]._lock);
+ }
+ wmb();
+ ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+ } else
+ wake_up_all(&ioa_cfg->eeh_wait_q);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
}
@@ -8725,7 +8791,7 @@ static pci_ers_result_t ipr_pci_error_detected(struct pci_dev *pdev,
switch (state) {
case pci_channel_io_frozen:
ipr_pci_frozen(pdev);
- return PCI_ERS_RESULT_NEED_RESET;
+ return PCI_ERS_RESULT_CAN_RECOVER;
case pci_channel_io_perm_failure:
ipr_pci_perm_failure(pdev);
return PCI_ERS_RESULT_DISCONNECT;
@@ -8755,6 +8821,7 @@ static int ipr_probe_ioa_part2(struct ipr_ioa_cfg *ioa_cfg)
ENTER;
spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
dev_dbg(&ioa_cfg->pdev->dev, "ioa_cfg adx: 0x%p\n", ioa_cfg);
+ ioa_cfg->probe_done = 1;
if (ioa_cfg->needs_hard_reset) {
ioa_cfg->needs_hard_reset = 0;
ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
@@ -9030,16 +9097,6 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
if (!ioa_cfg->vpd_cbs)
goto out_free_res_entries;
- for (i = 0; i < ioa_cfg->hrrq_num; i++) {
- INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_free_q);
- INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_pending_q);
- spin_lock_init(&ioa_cfg->hrrq[i]._lock);
- if (i == 0)
- ioa_cfg->hrrq[i].lock = ioa_cfg->host->host_lock;
- else
- ioa_cfg->hrrq[i].lock = &ioa_cfg->hrrq[i]._lock;
- }
-
if (ipr_alloc_cmd_blks(ioa_cfg))
goto out_free_vpd_cbs;
@@ -9140,6 +9197,48 @@ static void ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg)
}
/**
+ * ipr_init_regs - Initialize IOA registers
+ * @ioa_cfg: ioa config struct
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_init_regs(struct ipr_ioa_cfg *ioa_cfg)
+{
+ const struct ipr_interrupt_offsets *p;
+ struct ipr_interrupts *t;
+ void __iomem *base;
+
+ p = &ioa_cfg->chip_cfg->regs;
+ t = &ioa_cfg->regs;
+ base = ioa_cfg->hdw_dma_regs;
+
+ t->set_interrupt_mask_reg = base + p->set_interrupt_mask_reg;
+ t->clr_interrupt_mask_reg = base + p->clr_interrupt_mask_reg;
+ t->clr_interrupt_mask_reg32 = base + p->clr_interrupt_mask_reg32;
+ t->sense_interrupt_mask_reg = base + p->sense_interrupt_mask_reg;
+ t->sense_interrupt_mask_reg32 = base + p->sense_interrupt_mask_reg32;
+ t->clr_interrupt_reg = base + p->clr_interrupt_reg;
+ t->clr_interrupt_reg32 = base + p->clr_interrupt_reg32;
+ t->sense_interrupt_reg = base + p->sense_interrupt_reg;
+ t->sense_interrupt_reg32 = base + p->sense_interrupt_reg32;
+ t->ioarrin_reg = base + p->ioarrin_reg;
+ t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg;
+ t->sense_uproc_interrupt_reg32 = base + p->sense_uproc_interrupt_reg32;
+ t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg;
+ t->set_uproc_interrupt_reg32 = base + p->set_uproc_interrupt_reg32;
+ t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg;
+ t->clr_uproc_interrupt_reg32 = base + p->clr_uproc_interrupt_reg32;
+
+ if (ioa_cfg->sis64) {
+ t->init_feedback_reg = base + p->init_feedback_reg;
+ t->dump_addr_reg = base + p->dump_addr_reg;
+ t->dump_data_reg = base + p->dump_data_reg;
+ t->endian_swap_reg = base + p->endian_swap_reg;
+ }
+}
+
+/**
* ipr_init_ioa_cfg - Initialize IOA config struct
* @ioa_cfg: ioa config struct
* @host: scsi host struct
@@ -9151,9 +9250,7 @@ static void ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg)
static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
struct Scsi_Host *host, struct pci_dev *pdev)
{
- const struct ipr_interrupt_offsets *p;
- struct ipr_interrupts *t;
- void __iomem *base;
+ int i;
ioa_cfg->host = host;
ioa_cfg->pdev = pdev;
@@ -9173,6 +9270,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
init_waitqueue_head(&ioa_cfg->reset_wait_q);
init_waitqueue_head(&ioa_cfg->msi_wait_q);
+ init_waitqueue_head(&ioa_cfg->eeh_wait_q);
ioa_cfg->sdt_state = INACTIVE;
ipr_initialize_bus_attr(ioa_cfg);
@@ -9183,44 +9281,33 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
host->max_lun = IPR_MAX_SIS64_LUNS_PER_TARGET;
if (ipr_max_devs > IPR_MAX_SIS64_DEVS)
ioa_cfg->max_devs_supported = IPR_MAX_SIS64_DEVS;
+ ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr64)
+ + ((sizeof(struct ipr_config_table_entry64)
+ * ioa_cfg->max_devs_supported)));
} else {
host->max_id = IPR_MAX_NUM_TARGETS_PER_BUS;
host->max_lun = IPR_MAX_NUM_LUNS_PER_TARGET;
if (ipr_max_devs > IPR_MAX_PHYSICAL_DEVS)
ioa_cfg->max_devs_supported = IPR_MAX_PHYSICAL_DEVS;
+ ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr)
+ + ((sizeof(struct ipr_config_table_entry)
+ * ioa_cfg->max_devs_supported)));
}
+
host->max_channel = IPR_MAX_BUS_TO_SCAN;
host->unique_id = host->host_no;
host->max_cmd_len = IPR_MAX_CDB_LEN;
host->can_queue = ioa_cfg->max_cmds;
pci_set_drvdata(pdev, ioa_cfg);
- p = &ioa_cfg->chip_cfg->regs;
- t = &ioa_cfg->regs;
- base = ioa_cfg->hdw_dma_regs;
-
- t->set_interrupt_mask_reg = base + p->set_interrupt_mask_reg;
- t->clr_interrupt_mask_reg = base + p->clr_interrupt_mask_reg;
- t->clr_interrupt_mask_reg32 = base + p->clr_interrupt_mask_reg32;
- t->sense_interrupt_mask_reg = base + p->sense_interrupt_mask_reg;
- t->sense_interrupt_mask_reg32 = base + p->sense_interrupt_mask_reg32;
- t->clr_interrupt_reg = base + p->clr_interrupt_reg;
- t->clr_interrupt_reg32 = base + p->clr_interrupt_reg32;
- t->sense_interrupt_reg = base + p->sense_interrupt_reg;
- t->sense_interrupt_reg32 = base + p->sense_interrupt_reg32;
- t->ioarrin_reg = base + p->ioarrin_reg;
- t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg;
- t->sense_uproc_interrupt_reg32 = base + p->sense_uproc_interrupt_reg32;
- t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg;
- t->set_uproc_interrupt_reg32 = base + p->set_uproc_interrupt_reg32;
- t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg;
- t->clr_uproc_interrupt_reg32 = base + p->clr_uproc_interrupt_reg32;
-
- if (ioa_cfg->sis64) {
- t->init_feedback_reg = base + p->init_feedback_reg;
- t->dump_addr_reg = base + p->dump_addr_reg;
- t->dump_data_reg = base + p->dump_data_reg;
- t->endian_swap_reg = base + p->endian_swap_reg;
+ for (i = 0; i < ARRAY_SIZE(ioa_cfg->hrrq); i++) {
+ INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_free_q);
+ INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_pending_q);
+ spin_lock_init(&ioa_cfg->hrrq[i]._lock);
+ if (i == 0)
+ ioa_cfg->hrrq[i].lock = ioa_cfg->host->host_lock;
+ else
+ ioa_cfg->hrrq[i].lock = &ioa_cfg->hrrq[i]._lock;
}
}
@@ -9243,54 +9330,63 @@ ipr_get_chip_info(const struct pci_device_id *dev_id)
return NULL;
}
+/**
+ * ipr_wait_for_pci_err_recovery - Wait for any PCI error recovery to complete
+ * during probe time
+ * @ioa_cfg: ioa config struct
+ *
+ * Return value:
+ * None
+ **/
+static void ipr_wait_for_pci_err_recovery(struct ipr_ioa_cfg *ioa_cfg)
+{
+ struct pci_dev *pdev = ioa_cfg->pdev;
+
+ if (pci_channel_offline(pdev)) {
+ wait_event_timeout(ioa_cfg->eeh_wait_q,
+ !pci_channel_offline(pdev),
+ IPR_PCI_ERROR_RECOVERY_TIMEOUT);
+ pci_restore_state(pdev);
+ }
+}
+
static int ipr_enable_msix(struct ipr_ioa_cfg *ioa_cfg)
{
struct msix_entry entries[IPR_MAX_MSIX_VECTORS];
- int i, err, vectors;
+ int i, vectors;
for (i = 0; i < ARRAY_SIZE(entries); ++i)
entries[i].entry = i;
- vectors = ipr_number_of_msix;
-
- while ((err = pci_enable_msix(ioa_cfg->pdev, entries, vectors)) > 0)
- vectors = err;
-
- if (err < 0) {
- pci_disable_msix(ioa_cfg->pdev);
- return err;
+ vectors = pci_enable_msix_range(ioa_cfg->pdev,
+ entries, 1, ipr_number_of_msix);
+ if (vectors < 0) {
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
+ return vectors;
}
- if (!err) {
- for (i = 0; i < vectors; i++)
- ioa_cfg->vectors_info[i].vec = entries[i].vector;
- ioa_cfg->nvectors = vectors;
- }
+ for (i = 0; i < vectors; i++)
+ ioa_cfg->vectors_info[i].vec = entries[i].vector;
+ ioa_cfg->nvectors = vectors;
- return err;
+ return 0;
}
static int ipr_enable_msi(struct ipr_ioa_cfg *ioa_cfg)
{
- int i, err, vectors;
-
- vectors = ipr_number_of_msix;
+ int i, vectors;
- while ((err = pci_enable_msi_block(ioa_cfg->pdev, vectors)) > 0)
- vectors = err;
-
- if (err < 0) {
- pci_disable_msi(ioa_cfg->pdev);
- return err;
+ vectors = pci_enable_msi_range(ioa_cfg->pdev, 1, ipr_number_of_msix);
+ if (vectors < 0) {
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
+ return vectors;
}
- if (!err) {
- for (i = 0; i < vectors; i++)
- ioa_cfg->vectors_info[i].vec = ioa_cfg->pdev->irq + i;
- ioa_cfg->nvectors = vectors;
- }
+ for (i = 0; i < vectors; i++)
+ ioa_cfg->vectors_info[i].vec = ioa_cfg->pdev->irq + i;
+ ioa_cfg->nvectors = vectors;
- return err;
+ return 0;
}
static void name_msi_vectors(struct ipr_ioa_cfg *ioa_cfg)
@@ -9355,7 +9451,7 @@ static irqreturn_t ipr_test_intr(int irq, void *devp)
* ipr_test_msi - Test for Message Signaled Interrupt (MSI) support.
* @pdev: PCI device struct
*
- * Description: The return value from pci_enable_msi() can not always be
+ * Description: The return value from pci_enable_msi_range() can not always be
* trusted. This routine sets up and initiates a test interrupt to determine
* if the interrupt is received via the ipr_test_intr() service routine.
* If the tests fails, the driver will fall back to LSI.
@@ -9434,19 +9530,13 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
ENTER;
- if ((rc = pci_enable_device(pdev))) {
- dev_err(&pdev->dev, "Cannot enable adapter\n");
- goto out;
- }
-
dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq);
-
host = scsi_host_alloc(&driver_template, sizeof(*ioa_cfg));
if (!host) {
dev_err(&pdev->dev, "call to scsi_host_alloc failed!\n");
rc = -ENOMEM;
- goto out_disable;
+ goto out;
}
ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata;
@@ -9476,6 +9566,8 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
ioa_cfg->revid = pdev->revision;
+ ipr_init_ioa_cfg(ioa_cfg, host, pdev);
+
ipr_regs_pci = pci_resource_start(pdev, 0);
rc = pci_request_regions(pdev, IPR_NAME);
@@ -9485,22 +9577,35 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
goto out_scsi_host_put;
}
+ rc = pci_enable_device(pdev);
+
+ if (rc || pci_channel_offline(pdev)) {
+ if (pci_channel_offline(pdev)) {
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
+ rc = pci_enable_device(pdev);
+ }
+
+ if (rc) {
+ dev_err(&pdev->dev, "Cannot enable adapter\n");
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
+ goto out_release_regions;
+ }
+ }
+
ipr_regs = pci_ioremap_bar(pdev, 0);
if (!ipr_regs) {
dev_err(&pdev->dev,
"Couldn't map memory range of registers\n");
rc = -ENOMEM;
- goto out_release_regions;
+ goto out_disable;
}
ioa_cfg->hdw_dma_regs = ipr_regs;
ioa_cfg->hdw_dma_regs_pci = ipr_regs_pci;
ioa_cfg->ioa_mailbox = ioa_cfg->chip_cfg->mailbox + ipr_regs;
- ipr_init_ioa_cfg(ioa_cfg, host, pdev);
-
- pci_set_master(pdev);
+ ipr_init_regs(ioa_cfg);
if (ioa_cfg->sis64) {
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -9508,7 +9613,6 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
dev_dbg(&pdev->dev, "Failed to set 64 bit PCI DMA mask\n");
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
}
-
} else
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
@@ -9522,10 +9626,15 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
if (rc != PCIBIOS_SUCCESSFUL) {
dev_err(&pdev->dev, "Write of cache line size failed\n");
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
rc = -EIO;
goto cleanup_nomem;
}
+ /* Issue MMIO read to ensure card is not in EEH */
+ interrupts = readl(ioa_cfg->regs.sense_interrupt_reg);
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
+
if (ipr_number_of_msix > IPR_MAX_MSIX_VECTORS) {
dev_err(&pdev->dev, "The max number of MSIX is %d\n",
IPR_MAX_MSIX_VECTORS);
@@ -9544,10 +9653,22 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
dev_info(&pdev->dev, "Cannot enable MSI.\n");
}
+ pci_set_master(pdev);
+
+ if (pci_channel_offline(pdev)) {
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
+ pci_set_master(pdev);
+ if (pci_channel_offline(pdev)) {
+ rc = -EIO;
+ goto out_msi_disable;
+ }
+ }
+
if (ioa_cfg->intr_flag == IPR_USE_MSI ||
ioa_cfg->intr_flag == IPR_USE_MSIX) {
rc = ipr_test_msi(ioa_cfg, pdev);
if (rc == -EOPNOTSUPP) {
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
if (ioa_cfg->intr_flag == IPR_USE_MSI) {
ioa_cfg->intr_flag &= ~IPR_USE_MSI;
pci_disable_msi(pdev);
@@ -9577,30 +9698,12 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
(unsigned int)num_online_cpus(),
(unsigned int)IPR_MAX_HRRQ_NUM);
- /* Save away PCI config space for use following IOA reset */
- rc = pci_save_state(pdev);
-
- if (rc != PCIBIOS_SUCCESSFUL) {
- dev_err(&pdev->dev, "Failed to save PCI config space\n");
- rc = -EIO;
- goto out_msi_disable;
- }
-
if ((rc = ipr_save_pcix_cmd_reg(ioa_cfg)))
goto out_msi_disable;
if ((rc = ipr_set_pcix_cmd_reg(ioa_cfg)))
goto out_msi_disable;
- if (ioa_cfg->sis64)
- ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr64)
- + ((sizeof(struct ipr_config_table_entry64)
- * ioa_cfg->max_devs_supported)));
- else
- ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr)
- + ((sizeof(struct ipr_config_table_entry)
- * ioa_cfg->max_devs_supported)));
-
rc = ipr_alloc_mem(ioa_cfg);
if (rc < 0) {
dev_err(&pdev->dev,
@@ -9608,6 +9711,15 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
goto out_msi_disable;
}
+ /* Save away PCI config space for use following IOA reset */
+ rc = pci_save_state(pdev);
+
+ if (rc != PCIBIOS_SUCCESSFUL) {
+ dev_err(&pdev->dev, "Failed to save PCI config space\n");
+ rc = -EIO;
+ goto cleanup_nolog;
+ }
+
/*
* If HRRQ updated interrupt is not masked, or reset alert is set,
* the card is in an unknown state and needs a hard reset
@@ -9664,18 +9776,19 @@ out:
cleanup_nolog:
ipr_free_mem(ioa_cfg);
out_msi_disable:
+ ipr_wait_for_pci_err_recovery(ioa_cfg);
if (ioa_cfg->intr_flag == IPR_USE_MSI)
pci_disable_msi(pdev);
else if (ioa_cfg->intr_flag == IPR_USE_MSIX)
pci_disable_msix(pdev);
cleanup_nomem:
iounmap(ipr_regs);
+out_disable:
+ pci_disable_device(pdev);
out_release_regions:
pci_release_regions(pdev);
out_scsi_host_put:
scsi_host_put(host);
-out_disable:
- pci_disable_device(pdev);
goto out;
}
@@ -9859,8 +9972,7 @@ static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
ioa_cfg->host->max_channel = IPR_VSET_BUS;
ioa_cfg->iopoll_weight = ioa_cfg->chip_cfg->iopoll_weight;
- if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
- ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+ if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
for (i = 1; i < ioa_cfg->hrrq_num; i++) {
blk_iopoll_init(&ioa_cfg->hrrq[i].iopoll,
ioa_cfg->iopoll_weight, ipr_iopoll);
@@ -9889,8 +10001,7 @@ static void ipr_shutdown(struct pci_dev *pdev)
int i;
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
- if (blk_iopoll_enabled && ioa_cfg->iopoll_weight &&
- ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
+ if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
ioa_cfg->iopoll_weight = 0;
for (i = 1; i < ioa_cfg->hrrq_num; i++)
blk_iopoll_disable(&ioa_cfg->hrrq[i].iopoll);
@@ -9994,6 +10105,8 @@ static struct pci_device_id ipr_pci_table[] = {
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57D9, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57DA, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EB, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EC, 0, 0, 0 },
@@ -10005,12 +10118,19 @@ static struct pci_device_id ipr_pci_table[] = {
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EF, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57F0, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2CCA, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2CD2, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2CCD, 0, 0, 0 },
{ }
};
MODULE_DEVICE_TABLE(pci, ipr_pci_table);
static const struct pci_error_handlers ipr_err_handler = {
.error_detected = ipr_pci_error_detected,
+ .mmio_enabled = ipr_pci_mmio_enabled,
.slot_reset = ipr_pci_slot_reset,
};
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 9ce38a22647e..31ed126f7143 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -101,12 +101,16 @@
#define IPR_SUBS_DEV_ID_57D7 0x03FF
#define IPR_SUBS_DEV_ID_57D8 0x03FE
#define IPR_SUBS_DEV_ID_57D9 0x046D
+#define IPR_SUBS_DEV_ID_57DA 0x04CA
#define IPR_SUBS_DEV_ID_57EB 0x0474
#define IPR_SUBS_DEV_ID_57EC 0x0475
#define IPR_SUBS_DEV_ID_57ED 0x0499
#define IPR_SUBS_DEV_ID_57EE 0x049A
#define IPR_SUBS_DEV_ID_57EF 0x049B
#define IPR_SUBS_DEV_ID_57F0 0x049C
+#define IPR_SUBS_DEV_ID_2CCA 0x04C7
+#define IPR_SUBS_DEV_ID_2CD2 0x04C8
+#define IPR_SUBS_DEV_ID_2CCD 0x04C9
#define IPR_NAME "ipr"
/*
@@ -230,6 +234,7 @@
#define IPR_WAIT_FOR_RESET_TIMEOUT (2 * HZ)
#define IPR_CHECK_FOR_RESET_TIMEOUT (HZ / 10)
#define IPR_WAIT_FOR_BIST_TIMEOUT (2 * HZ)
+#define IPR_PCI_ERROR_RECOVERY_TIMEOUT (120 * HZ)
#define IPR_PCI_RESET_TIMEOUT (HZ / 2)
#define IPR_SIS32_DUMP_TIMEOUT (15 * HZ)
#define IPR_SIS64_DUMP_TIMEOUT (40 * HZ)
@@ -897,6 +902,18 @@ struct ipr_hostrcb_type_01_error {
__be32 ioa_data[236];
}__attribute__((packed, aligned (4)));
+struct ipr_hostrcb_type_21_error {
+ __be32 wwn[4];
+ u8 res_path[8];
+ u8 primary_problem_desc[32];
+ u8 second_problem_desc[32];
+ __be32 sense_data[8];
+ __be32 cdb[4];
+ __be32 residual_trans_length;
+ __be32 length_of_error;
+ __be32 ioa_data[236];
+}__attribute__((packed, aligned (4)));
+
struct ipr_hostrcb_type_02_error {
struct ipr_vpd ioa_vpd;
struct ipr_vpd cfc_vpd;
@@ -1126,6 +1143,7 @@ struct ipr_hostrcb64_error {
struct ipr_hostrcb_type_ff_error type_ff_error;
struct ipr_hostrcb_type_12_error type_12_error;
struct ipr_hostrcb_type_17_error type_17_error;
+ struct ipr_hostrcb_type_21_error type_21_error;
struct ipr_hostrcb_type_23_error type_23_error;
struct ipr_hostrcb_type_24_error type_24_error;
struct ipr_hostrcb_type_30_error type_30_error;
@@ -1169,6 +1187,7 @@ struct ipr_hcam {
#define IPR_HOST_RCB_OVERLAY_ID_16 0x16
#define IPR_HOST_RCB_OVERLAY_ID_17 0x17
#define IPR_HOST_RCB_OVERLAY_ID_20 0x20
+#define IPR_HOST_RCB_OVERLAY_ID_21 0x21
#define IPR_HOST_RCB_OVERLAY_ID_23 0x23
#define IPR_HOST_RCB_OVERLAY_ID_24 0x24
#define IPR_HOST_RCB_OVERLAY_ID_26 0x26
@@ -1252,6 +1271,7 @@ struct ipr_resource_entry {
u8 add_to_ml:1;
u8 del_from_ml:1;
u8 resetting_device:1;
+ u8 reset_occurred:1;
u32 bus; /* AKA channel */
u32 target; /* AKA id */
@@ -1441,6 +1461,7 @@ struct ipr_ioa_cfg {
u8 dump_timeout:1;
u8 cfg_locked:1;
u8 clear_isr:1;
+ u8 probe_done:1;
u8 revid;
@@ -1519,6 +1540,7 @@ struct ipr_ioa_cfg {
wait_queue_head_t reset_wait_q;
wait_queue_head_t msi_wait_q;
+ wait_queue_head_t eeh_wait_q;
struct ipr_dump *dump;
enum ipr_sdt_state sdt_state;
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 4911310a38f5..22a9bb1abae1 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -311,9 +311,8 @@ static inline struct Scsi_Host *to_shost(struct isci_host *ihost)
}
#define for_each_isci_host(id, ihost, pdev) \
- for (id = 0, ihost = to_pci_info(pdev)->hosts[id]; \
- id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \
- ihost = to_pci_info(pdev)->hosts[++id])
+ for (id = 0; id < SCI_MAX_CONTROLLERS && \
+ (ihost = to_pci_info(pdev)->hosts[id]); id++)
static inline void wait_for_start(struct isci_host *ihost)
{
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index d25d0d859f05..695b34e9154e 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -66,7 +66,7 @@
#include "probe_roms.h"
#define MAJ 1
-#define MIN 1
+#define MIN 2
#define BUILD 0
#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
__stringify(BUILD)
diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c
index 85c77f6b802b..ac879745ef80 100644
--- a/drivers/scsi/isci/port_config.c
+++ b/drivers/scsi/isci/port_config.c
@@ -615,13 +615,6 @@ static void sci_apc_agent_link_up(struct isci_host *ihost,
SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION);
} else {
/* the phy is already the part of the port */
- u32 port_state = iport->sm.current_state_id;
-
- /* if the PORT'S state is resetting then the link up is from
- * port hard reset in this case, we need to tell the port
- * that link up is recieved
- */
- BUG_ON(port_state != SCI_PORT_RESETTING);
port_agent->phy_ready_mask |= 1 << phy_index;
sci_port_link_up(iport, iphy);
}
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 99d2930b18c8..56e38096f0c4 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2723,13 +2723,9 @@ static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_
memcpy(resp->ending_fis, fis, sizeof(*fis));
ts->buf_valid_size = sizeof(*resp);
- /* If the device fault bit is set in the status register, then
- * set the sense data and return.
- */
- if (fis->status & ATA_DF)
+ /* If an error is flagged let libata decode the fis */
+ if (ac_err_mask(fis->status))
ts->stat = SAS_PROTO_RESPONSE;
- else if (fis->status & ATA_ERR)
- ts->stat = SAM_STAT_CHECK_CONDITION;
else
ts->stat = SAM_STAT_GOOD;
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 0d30ca849e8f..5d6fda72d659 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -801,7 +801,7 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev)
/* XXX: need to cleanup any ireqs targeting this
* domain_device
*/
- ret = TMF_RESP_FUNC_COMPLETE;
+ ret = -ENODEV;
goto out;
}
diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c
index 14c1c8f6a95e..680bf6f0ce76 100644
--- a/drivers/scsi/iscsi_boot_sysfs.c
+++ b/drivers/scsi/iscsi_boot_sysfs.c
@@ -490,5 +490,6 @@ void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset)
iscsi_boot_remove_kobj(boot_kobj);
kset_unregister(boot_kset->kset);
+ kfree(boot_kset);
}
EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index add6d1566ec8..bfb6d07d87f0 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -593,9 +593,9 @@ static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn)
iscsi_sw_tcp_conn_restore_callbacks(conn);
sock_put(sock->sk);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
tcp_sw_conn->sock = NULL;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
sockfd_put(sock);
}
@@ -663,10 +663,10 @@ iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session,
if (err)
goto free_socket;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
/* bind iSCSI connection and socket */
tcp_sw_conn->sock = sock;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
/* setup Socket parameters */
sk = sock->sk;
@@ -726,14 +726,14 @@ static int iscsi_sw_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
switch(param) {
case ISCSI_PARAM_CONN_PORT:
case ISCSI_PARAM_CONN_ADDRESS:
- spin_lock_bh(&conn->session->lock);
+ spin_lock_bh(&conn->session->frwd_lock);
if (!tcp_sw_conn || !tcp_sw_conn->sock) {
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
return -ENOTCONN;
}
rc = kernel_getpeername(tcp_sw_conn->sock,
(struct sockaddr *)&addr, &len);
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
if (rc)
return rc;
@@ -759,23 +759,26 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
switch (param) {
case ISCSI_HOST_PARAM_IPADDRESS:
- spin_lock_bh(&session->lock);
+ if (!session)
+ return -ENOTCONN;
+
+ spin_lock_bh(&session->frwd_lock);
conn = session->leadconn;
if (!conn) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return -ENOTCONN;
}
tcp_conn = conn->dd_data;
tcp_sw_conn = tcp_conn->dd_data;
if (!tcp_sw_conn->sock) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return -ENOTCONN;
}
rc = kernel_getsockname(tcp_sw_conn->sock,
(struct sockaddr *)&addr, &len);
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
if (rc)
return rc;
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 40462415291e..5b8605ca42fa 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -110,16 +110,8 @@ static void __iscsi_update_cmdsn(struct iscsi_session *session,
session->exp_cmdsn = exp_cmdsn;
if (max_cmdsn != session->max_cmdsn &&
- !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) {
+ !iscsi_sna_lt(max_cmdsn, session->max_cmdsn))
session->max_cmdsn = max_cmdsn;
- /*
- * if the window closed with IO queued, then kick the
- * xmit thread
- */
- if (!list_empty(&session->leadconn->cmdqueue) ||
- !list_empty(&session->leadconn->mgmtqueue))
- iscsi_conn_queue_work(session->leadconn);
- }
}
void iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
@@ -481,7 +473,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
* iscsi_free_task - free a task
* @task: iscsi cmd task
*
- * Must be called with session lock.
+ * Must be called with session back_lock.
* This function returns the scsi command to scsi-ml or cleans
* up mgmt tasks then returns the task to the pool.
*/
@@ -535,9 +527,10 @@ void iscsi_put_task(struct iscsi_task *task)
{
struct iscsi_session *session = task->conn->session;
- spin_lock_bh(&session->lock);
+ /* regular RX path uses back_lock */
+ spin_lock_bh(&session->back_lock);
__iscsi_put_task(task);
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->back_lock);
}
EXPORT_SYMBOL_GPL(iscsi_put_task);
@@ -546,7 +539,7 @@ EXPORT_SYMBOL_GPL(iscsi_put_task);
* @task: iscsi cmd task
* @state: state to complete task with
*
- * Must be called with session lock.
+ * Must be called with session back_lock.
*/
static void iscsi_complete_task(struct iscsi_task *task, int state)
{
@@ -585,7 +578,7 @@ static void iscsi_complete_task(struct iscsi_task *task, int state)
* This is used when drivers do not need or cannot perform
* lower level pdu processing.
*
- * Called with session lock
+ * Called with session back_lock
*/
void iscsi_complete_scsi_task(struct iscsi_task *task,
uint32_t exp_cmdsn, uint32_t max_cmdsn)
@@ -602,7 +595,7 @@ EXPORT_SYMBOL_GPL(iscsi_complete_scsi_task);
/*
- * session lock must be held and if not called for a task that is
+ * session back_lock must be held and if not called for a task that is
* still pending or from the xmit thread, then xmit thread must
* be suspended.
*/
@@ -642,7 +635,10 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
scsi_in(sc)->resid = scsi_in(sc)->length;
}
+ /* regular RX path uses back_lock */
+ spin_lock_bh(&conn->session->back_lock);
iscsi_complete_task(task, state);
+ spin_unlock_bh(&conn->session->back_lock);
}
static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
@@ -780,7 +776,10 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
return task;
free_task:
+ /* regular RX path uses back_lock */
+ spin_lock_bh(&session->back_lock);
__iscsi_put_task(task);
+ spin_unlock_bh(&session->back_lock);
return NULL;
}
@@ -791,10 +790,10 @@ int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
struct iscsi_session *session = conn->session;
int err = 0;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
err = -EPERM;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return err;
}
EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
@@ -1013,13 +1012,13 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
iscsi_conn_printk(KERN_ERR, conn,
"pdu (op 0x%x itt 0x%x) rejected "
"due to DataDigest error.\n",
- rejected_pdu.itt, opcode);
+ opcode, rejected_pdu.itt);
break;
case ISCSI_REASON_IMM_CMD_REJECT:
iscsi_conn_printk(KERN_ERR, conn,
"pdu (op 0x%x itt 0x%x) rejected. Too many "
"immediate commands.\n",
- rejected_pdu.itt, opcode);
+ opcode, rejected_pdu.itt);
/*
* We only send one TMF at a time so if the target could not
* handle it, then it should get fixed (RFC mandates that
@@ -1031,14 +1030,19 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (opcode != ISCSI_OP_NOOP_OUT)
return 0;
- if (rejected_pdu.itt == cpu_to_be32(ISCSI_RESERVED_TAG))
+ if (rejected_pdu.itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
/*
* nop-out in response to target's nop-out rejected.
* Just resend.
*/
+ /* In RX path we are under back lock */
+ spin_unlock(&conn->session->back_lock);
+ spin_lock(&conn->session->frwd_lock);
iscsi_send_nopout(conn,
(struct iscsi_nopin*)&rejected_pdu);
- else {
+ spin_unlock(&conn->session->frwd_lock);
+ spin_lock(&conn->session->back_lock);
+ } else {
struct iscsi_task *task;
/*
* Our nop as ping got dropped. We know the target
@@ -1059,8 +1063,8 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
default:
iscsi_conn_printk(KERN_ERR, conn,
"pdu (op 0x%x itt 0x%x) rejected. Reason "
- "code 0x%x\n", rejected_pdu.itt,
- rejected_pdu.opcode, reject->reason);
+ "code 0x%x\n", rejected_pdu.opcode,
+ rejected_pdu.itt, reject->reason);
break;
}
return rc;
@@ -1074,7 +1078,7 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
* This should be used for mgmt tasks like login and nops, or if
* the LDD's itt space does not include the session age.
*
- * The session lock must be held.
+ * The session back_lock must be held.
*/
struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
{
@@ -1103,7 +1107,7 @@ EXPORT_SYMBOL_GPL(iscsi_itt_to_task);
* @datalen: len of data buffer
*
* Completes pdu processing by freeing any resources allocated at
- * queuecommand or send generic. session lock must be held and verify
+ * queuecommand or send generic. session back_lock must be held and verify
* itt must have been called.
*/
int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
@@ -1140,7 +1144,12 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
break;
+ /* In RX path we are under back lock */
+ spin_unlock(&session->back_lock);
+ spin_lock(&session->frwd_lock);
iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr);
+ spin_unlock(&session->frwd_lock);
+ spin_lock(&session->back_lock);
break;
case ISCSI_OP_REJECT:
rc = iscsi_handle_reject(conn, hdr, data, datalen);
@@ -1247,9 +1256,9 @@ int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
{
int rc;
- spin_lock(&conn->session->lock);
+ spin_lock(&conn->session->back_lock);
rc = __iscsi_complete_pdu(conn, hdr, data, datalen);
- spin_unlock(&conn->session->lock);
+ spin_unlock(&conn->session->back_lock);
return rc;
}
EXPORT_SYMBOL_GPL(iscsi_complete_pdu);
@@ -1293,7 +1302,7 @@ EXPORT_SYMBOL_GPL(iscsi_verify_itt);
*
* This should be used for cmd tasks.
*
- * The session lock must be held.
+ * The session back_lock must be held.
*/
struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
{
@@ -1323,15 +1332,15 @@ void iscsi_session_failure(struct iscsi_session *session,
struct iscsi_conn *conn;
struct device *dev;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
conn = session->leadconn;
if (session->state == ISCSI_STATE_TERMINATE || !conn) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return;
}
dev = get_device(&conn->cls_conn->dev);
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
if (!dev)
return;
/*
@@ -1351,15 +1360,15 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
{
struct iscsi_session *session = conn->session;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (session->state == ISCSI_STATE_FAILED) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return;
}
if (conn->stop_stage == 0)
session->state = ISCSI_STATE_FAILED;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
@@ -1393,15 +1402,18 @@ static int iscsi_xmit_task(struct iscsi_conn *conn)
return -ENODATA;
__iscsi_get_task(task);
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
rc = conn->session->tt->xmit_task(task);
- spin_lock_bh(&conn->session->lock);
+ spin_lock_bh(&conn->session->frwd_lock);
if (!rc) {
/* done with this task */
task->last_xfer = jiffies;
conn->task = NULL;
}
+ /* regular RX path uses back_lock */
+ spin_lock_bh(&conn->session->back_lock);
__iscsi_put_task(task);
+ spin_unlock_bh(&conn->session->back_lock);
return rc;
}
@@ -1410,7 +1422,7 @@ static int iscsi_xmit_task(struct iscsi_conn *conn)
* @task: task to requeue
*
* LLDs that need to run a task from the session workqueue should call
- * this. The session lock must be held. This should only be called
+ * this. The session frwd_lock must be held. This should only be called
* by software drivers.
*/
void iscsi_requeue_task(struct iscsi_task *task)
@@ -1441,10 +1453,10 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
struct iscsi_task *task;
int rc = 0;
- spin_lock_bh(&conn->session->lock);
+ spin_lock_bh(&conn->session->frwd_lock);
if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
ISCSI_DBG_SESSION(conn->session, "Tx suspended!\n");
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
return -ENODATA;
}
@@ -1465,7 +1477,10 @@ check_mgmt:
struct iscsi_task, running);
list_del_init(&conn->task->running);
if (iscsi_prep_mgmt_task(conn, conn->task)) {
+ /* regular RX path uses back_lock */
+ spin_lock_bh(&conn->session->back_lock);
__iscsi_put_task(conn->task);
+ spin_unlock_bh(&conn->session->back_lock);
conn->task = NULL;
continue;
}
@@ -1527,11 +1542,11 @@ check_mgmt:
if (!list_empty(&conn->mgmtqueue))
goto check_mgmt;
}
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
return -ENODATA;
done:
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
return rc;
}
@@ -1600,7 +1615,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
reason = iscsi_session_chkready(cls_session);
if (reason) {
@@ -1686,13 +1701,13 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
}
session->queued_cmdsn++;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
return 0;
prepd_reject:
iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
reject:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
sc->cmnd[0], reason);
return SCSI_MLQUEUE_TARGET_BUSY;
@@ -1700,7 +1715,7 @@ reject:
prepd_fault:
iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
fault:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
sc->cmnd[0], reason);
if (!scsi_bidi_cmnd(sc))
@@ -1748,14 +1763,14 @@ static void iscsi_tmf_timedout(unsigned long data)
struct iscsi_conn *conn = (struct iscsi_conn *)data;
struct iscsi_session *session = conn->session;
- spin_lock(&session->lock);
+ spin_lock(&session->frwd_lock);
if (conn->tmf_state == TMF_QUEUED) {
conn->tmf_state = TMF_TIMEDOUT;
ISCSI_DBG_EH(session, "tmf timedout\n");
/* unblock eh_abort() */
wake_up(&conn->ehwait);
}
- spin_unlock(&session->lock);
+ spin_unlock(&session->frwd_lock);
}
static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
@@ -1768,10 +1783,10 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
NULL, 0);
if (!task) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_conn_printk(KERN_ERR, conn, "Could not send TMF.\n");
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
return -EPERM;
}
conn->tmfcmd_pdus_cnt++;
@@ -1781,7 +1796,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
add_timer(&conn->tmf_timer);
ISCSI_DBG_EH(session, "tmf set timeout\n");
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
/*
@@ -1800,7 +1815,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
del_timer_sync(&conn->tmf_timer);
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
/* if the session drops it will clean up the task */
if (age != session->age ||
session->state != ISCSI_STATE_LOGGED_IN)
@@ -1837,7 +1852,7 @@ static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun,
* iscsi_suspend_queue - suspend iscsi_queuecommand
* @conn: iscsi conn to stop queueing IO on
*
- * This grabs the session lock to make sure no one is in
+ * This grabs the session frwd_lock to make sure no one is in
* xmit_task/queuecommand, and then sets suspend to prevent
* new commands from being queued. This only needs to be called
* by offload drivers that need to sync a path like ep disconnect
@@ -1846,9 +1861,9 @@ static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun,
*/
void iscsi_suspend_queue(struct iscsi_conn *conn)
{
- spin_lock_bh(&conn->session->lock);
+ spin_lock_bh(&conn->session->frwd_lock);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->frwd_lock);
}
EXPORT_SYMBOL_GPL(iscsi_suspend_queue);
@@ -1907,7 +1922,7 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc);
- spin_lock(&session->lock);
+ spin_lock(&session->frwd_lock);
task = (struct iscsi_task *)sc->SCp.ptr;
if (!task) {
/*
@@ -2021,7 +2036,7 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
done:
if (task)
task->last_timeout = jiffies;
- spin_unlock(&session->lock);
+ spin_unlock(&session->frwd_lock);
ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ?
"timer reset" : "nh");
return rc;
@@ -2033,7 +2048,7 @@ static void iscsi_check_transport_timeouts(unsigned long data)
struct iscsi_session *session = conn->session;
unsigned long recv_timeout, next_timeout = 0, last_recv;
- spin_lock(&session->lock);
+ spin_lock(&session->frwd_lock);
if (session->state != ISCSI_STATE_LOGGED_IN)
goto done;
@@ -2050,7 +2065,7 @@ static void iscsi_check_transport_timeouts(unsigned long data)
"last ping %lu, now %lu\n",
conn->ping_timeout, conn->recv_timeout,
last_recv, conn->last_ping, jiffies);
- spin_unlock(&session->lock);
+ spin_unlock(&session->frwd_lock);
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return;
}
@@ -2066,7 +2081,7 @@ static void iscsi_check_transport_timeouts(unsigned long data)
ISCSI_DBG_CONN(conn, "Setting next tmo %lu\n", next_timeout);
mod_timer(&conn->transport_timer, next_timeout);
done:
- spin_unlock(&session->lock);
+ spin_unlock(&session->frwd_lock);
}
static void iscsi_prep_abort_task_pdu(struct iscsi_task *task,
@@ -2096,7 +2111,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
ISCSI_DBG_EH(session, "aborting sc %p\n", sc);
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
/*
* if session was ISCSI_STATE_IN_RECOVERY then we may not have
* got the command.
@@ -2104,7 +2119,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
if (!sc->SCp.ptr) {
ISCSI_DBG_EH(session, "sc never reached iscsi layer or "
"it completed.\n");
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
return SUCCESS;
}
@@ -2115,7 +2130,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
*/
if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN ||
sc->SCp.phase != session->age) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
ISCSI_DBG_EH(session, "failing abort due to dropped "
"session.\n");
@@ -2156,7 +2171,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
switch (conn->tmf_state) {
case TMF_SUCCESS:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
/*
* stop tx side incase the target had sent a abort rsp but
* the initiator was still writing out data.
@@ -2167,15 +2182,15 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
* good and have never sent us a successful tmf response
* then sent more data for the cmd.
*/
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
fail_scsi_task(task, DID_ABORT);
conn->tmf_state = TMF_INITIAL;
memset(hdr, 0, sizeof(*hdr));
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_start_tx(conn);
goto success_unlocked;
case TMF_TIMEDOUT:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto failed_unlocked;
case TMF_NOT_FOUND:
@@ -2194,7 +2209,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
}
success:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
success_unlocked:
ISCSI_DBG_EH(session, "abort success [sc %p itt 0x%x]\n",
sc, task->itt);
@@ -2202,7 +2217,7 @@ success_unlocked:
return SUCCESS;
failed:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
failed_unlocked:
ISCSI_DBG_EH(session, "abort failed [sc %p itt 0x%x]\n", sc,
task ? task->itt : 0);
@@ -2235,7 +2250,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
ISCSI_DBG_EH(session, "LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
/*
* Just check if we are not logged in. We cannot check for
* the phase because the reset could come from a ioctl.
@@ -2262,7 +2277,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
case TMF_SUCCESS:
break;
case TMF_TIMEDOUT:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto done;
default:
@@ -2271,21 +2286,21 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
}
rc = SUCCESS;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_suspend_tx(conn);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
memset(hdr, 0, sizeof(*hdr));
fail_scsi_tasks(conn, sc->device->lun, DID_ERROR);
conn->tmf_state = TMF_INITIAL;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_start_tx(conn);
goto done;
unlock:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
done:
ISCSI_DBG_EH(session, "dev reset result = %s\n",
rc == SUCCESS ? "SUCCESS" : "FAILED");
@@ -2298,13 +2313,13 @@ void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
{
struct iscsi_session *session = cls_session->dd_data;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (session->state != ISCSI_STATE_LOGGED_IN) {
session->state = ISCSI_STATE_RECOVERY_FAILED;
if (session->leadconn)
wake_up(&session->leadconn->ehwait);
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
}
EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout);
@@ -2326,19 +2341,19 @@ int iscsi_eh_session_reset(struct scsi_cmnd *sc)
conn = session->leadconn;
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (session->state == ISCSI_STATE_TERMINATE) {
failed:
ISCSI_DBG_EH(session,
"failing session reset: Could not log back into "
"%s, %s [age %d]\n", session->targetname,
conn->persistent_address, session->age);
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
return FAILED;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
/*
* we drop the lock here but the leadconn cannot be destoyed while
@@ -2355,14 +2370,14 @@ failed:
flush_signals(current);
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (session->state == ISCSI_STATE_LOGGED_IN) {
ISCSI_DBG_EH(session,
"session reset succeeded for %s,%s\n",
session->targetname, conn->persistent_address);
} else
goto failed;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
return SUCCESS;
}
@@ -2398,7 +2413,7 @@ int iscsi_eh_target_reset(struct scsi_cmnd *sc)
session->targetname);
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
/*
* Just check if we are not logged in. We cannot check for
* the phase because the reset could come from a ioctl.
@@ -2425,7 +2440,7 @@ int iscsi_eh_target_reset(struct scsi_cmnd *sc)
case TMF_SUCCESS:
break;
case TMF_TIMEDOUT:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto done;
default:
@@ -2434,21 +2449,21 @@ int iscsi_eh_target_reset(struct scsi_cmnd *sc)
}
rc = SUCCESS;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_suspend_tx(conn);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
memset(hdr, 0, sizeof(*hdr));
fail_scsi_tasks(conn, -1, DID_ERROR);
conn->tmf_state = TMF_INITIAL;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_start_tx(conn);
goto done;
unlock:
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
done:
ISCSI_DBG_EH(session, "tgt %s reset result = %s\n", session->targetname,
rc == SUCCESS ? "SUCCESS" : "FAILED");
@@ -2746,8 +2761,10 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
session->max_r2t = 1;
session->tt = iscsit;
session->dd_data = cls_session->dd_data + sizeof(*session);
+
mutex_init(&session->eh_mutex);
- spin_lock_init(&session->lock);
+ spin_lock_init(&session->frwd_lock);
+ spin_lock_init(&session->back_lock);
/* initialize SCSI PDU commands pool */
if (iscsi_pool_init(&session->cmdpool, session->cmds_max,
@@ -2861,14 +2878,14 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
/* allocate login_task used for the login/text sequences */
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (!kfifo_out(&session->cmdpool.queue,
(void*)&conn->login_task,
sizeof(void*))) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
goto login_task_alloc_fail;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
data = (char *) __get_free_pages(GFP_KERNEL,
get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
@@ -2905,7 +2922,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
del_timer_sync(&conn->transport_timer);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
if (session->leadconn == conn) {
/*
@@ -2914,7 +2931,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
session->state = ISCSI_STATE_TERMINATE;
wake_up(&conn->ehwait);
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
/*
* Block until all in-progress commands for this connection
@@ -2941,16 +2958,19 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
/* flush queued up work because we free the connection below */
iscsi_suspend_tx(conn);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
free_pages((unsigned long) conn->data,
get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
kfree(conn->persistent_address);
kfree(conn->local_ipaddr);
+ /* regular RX path uses back_lock */
+ spin_lock_bh(&session->back_lock);
kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
sizeof(void*));
+ spin_unlock_bh(&session->back_lock);
if (session->leadconn == conn)
session->leadconn = NULL;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_destroy_conn(cls_conn);
}
@@ -2987,7 +3007,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
conn->ping_timeout = 5;
}
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
conn->c_stage = ISCSI_CONN_STARTED;
session->state = ISCSI_STATE_LOGGED_IN;
session->queued_cmdsn = session->cmdsn;
@@ -3016,7 +3036,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
default:
break;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
iscsi_unblock_session(session->cls_session);
wake_up(&conn->ehwait);
@@ -3055,9 +3075,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
int old_stop_stage;
mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (conn->stop_stage == STOP_CONN_TERM) {
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
return;
}
@@ -3074,14 +3094,14 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
old_stop_stage = conn->stop_stage;
conn->stop_stage = flag;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
del_timer_sync(&conn->transport_timer);
iscsi_suspend_tx(conn);
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
conn->c_stage = ISCSI_CONN_STOPPED;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
/*
* for connection level recovery we should not calculate
@@ -3102,11 +3122,11 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
/*
* flush queues.
*/
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED);
fail_mgmt_tasks(session, conn);
memset(&conn->tmhdr, 0, sizeof(conn->tmhdr));
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
}
@@ -3133,10 +3153,10 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
struct iscsi_session *session = cls_session->dd_data;
struct iscsi_conn *conn = cls_conn->dd_data;
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&session->frwd_lock);
if (is_leading)
session->leadconn = conn;
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&session->frwd_lock);
/*
* Unblock xmitworker(), Login Phase will pass through.
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index 1d58d5336018..60cb6dc3c6f0 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -446,7 +446,7 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
* iscsi_tcp_cleanup_task - free tcp_task resources
* @task: iscsi task
*
- * must be called with session lock
+ * must be called with session back_lock
*/
void iscsi_tcp_cleanup_task(struct iscsi_task *task)
{
@@ -457,6 +457,7 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
if (!task->sc)
return;
+ spin_lock_bh(&tcp_task->queue2pool);
/* flush task's r2t queues */
while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
@@ -470,6 +471,7 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
sizeof(void*));
tcp_task->r2t = NULL;
}
+ spin_unlock_bh(&tcp_task->queue2pool);
}
EXPORT_SYMBOL_GPL(iscsi_tcp_cleanup_task);
@@ -529,6 +531,8 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr;
struct iscsi_r2t_info *r2t;
int r2tsn = be32_to_cpu(rhdr->r2tsn);
+ u32 data_length;
+ u32 data_offset;
int rc;
if (tcp_conn->in.datalen) {
@@ -554,40 +558,41 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
return 0;
}
- rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
- if (!rc) {
- iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
- "Target has sent more R2Ts than it "
- "negotiated for or driver has leaked.\n");
- return ISCSI_ERR_PROTO;
- }
-
- r2t->exp_statsn = rhdr->statsn;
- r2t->data_length = be32_to_cpu(rhdr->data_length);
- if (r2t->data_length == 0) {
+ data_length = be32_to_cpu(rhdr->data_length);
+ if (data_length == 0) {
iscsi_conn_printk(KERN_ERR, conn,
"invalid R2T with zero data len\n");
- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
return ISCSI_ERR_DATALEN;
}
- if (r2t->data_length > session->max_burst)
+ if (data_length > session->max_burst)
ISCSI_DBG_TCP(conn, "invalid R2T with data len %u and max "
"burst %u. Attempting to execute request.\n",
- r2t->data_length, session->max_burst);
+ data_length, session->max_burst);
- r2t->data_offset = be32_to_cpu(rhdr->data_offset);
- if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) {
+ data_offset = be32_to_cpu(rhdr->data_offset);
+ if (data_offset + data_length > scsi_out(task->sc)->length) {
iscsi_conn_printk(KERN_ERR, conn,
"invalid R2T with data len %u at offset %u "
- "and total length %d\n", r2t->data_length,
- r2t->data_offset, scsi_out(task->sc)->length);
- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
+ "and total length %d\n", data_length,
+ data_offset, scsi_out(task->sc)->length);
return ISCSI_ERR_DATALEN;
}
+ spin_lock(&tcp_task->pool2queue);
+ rc = kfifo_out(&tcp_task->r2tpool.queue, (void *)&r2t, sizeof(void *));
+ if (!rc) {
+ iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
+ "Target has sent more R2Ts than it "
+ "negotiated for or driver has leaked.\n");
+ spin_unlock(&tcp_task->pool2queue);
+ return ISCSI_ERR_PROTO;
+ }
+
+ r2t->exp_statsn = rhdr->statsn;
+ r2t->data_length = data_length;
+ r2t->data_offset = data_offset;
+
r2t->ttt = rhdr->ttt; /* no flip */
r2t->datasn = 0;
r2t->sent = 0;
@@ -595,6 +600,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
tcp_task->exp_datasn = r2tsn + 1;
kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
conn->r2t_pdus_cnt++;
+ spin_unlock(&tcp_task->pool2queue);
iscsi_requeue_task(task);
return 0;
@@ -667,14 +673,14 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
switch(opcode) {
case ISCSI_OP_SCSI_DATA_IN:
- spin_lock(&conn->session->lock);
+ spin_lock(&conn->session->back_lock);
task = iscsi_itt_to_ctask(conn, hdr->itt);
if (!task)
rc = ISCSI_ERR_BAD_ITT;
else
rc = iscsi_tcp_data_in(conn, task);
if (rc) {
- spin_unlock(&conn->session->lock);
+ spin_unlock(&conn->session->back_lock);
break;
}
@@ -707,11 +713,11 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
tcp_conn->in.datalen,
iscsi_tcp_process_data_in,
rx_hash);
- spin_unlock(&conn->session->lock);
+ spin_unlock(&conn->session->back_lock);
return rc;
}
rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
- spin_unlock(&conn->session->lock);
+ spin_unlock(&conn->session->back_lock);
break;
case ISCSI_OP_SCSI_CMD_RSP:
if (tcp_conn->in.datalen) {
@@ -721,18 +727,20 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
break;
case ISCSI_OP_R2T:
- spin_lock(&conn->session->lock);
+ spin_lock(&conn->session->back_lock);
task = iscsi_itt_to_ctask(conn, hdr->itt);
+ spin_unlock(&conn->session->back_lock);
if (!task)
rc = ISCSI_ERR_BAD_ITT;
else if (ahslen)
rc = ISCSI_ERR_AHSLEN;
else if (task->sc->sc_data_direction == DMA_TO_DEVICE) {
task->last_xfer = jiffies;
+ spin_lock(&conn->session->frwd_lock);
rc = iscsi_tcp_r2t_rsp(conn, task);
+ spin_unlock(&conn->session->frwd_lock);
} else
rc = ISCSI_ERR_PROTO;
- spin_unlock(&conn->session->lock);
break;
case ISCSI_OP_LOGIN_RSP:
case ISCSI_OP_TEXT_RSP:
@@ -980,14 +988,13 @@ EXPORT_SYMBOL_GPL(iscsi_tcp_task_init);
static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
{
- struct iscsi_session *session = task->conn->session;
struct iscsi_tcp_task *tcp_task = task->dd_data;
struct iscsi_r2t_info *r2t = NULL;
if (iscsi_task_has_unsol_data(task))
r2t = &task->unsol_r2t;
else {
- spin_lock_bh(&session->lock);
+ spin_lock_bh(&tcp_task->queue2pool);
if (tcp_task->r2t) {
r2t = tcp_task->r2t;
/* Continue with this R2T? */
@@ -1009,7 +1016,7 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
else
r2t = tcp_task->r2t;
}
- spin_unlock_bh(&session->lock);
+ spin_unlock_bh(&tcp_task->queue2pool);
}
return r2t;
@@ -1139,6 +1146,8 @@ int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session)
iscsi_pool_free(&tcp_task->r2tpool);
goto r2t_alloc_fail;
}
+ spin_lock_init(&tcp_task->pool2queue);
+ spin_lock_init(&tcp_task->queue2pool);
}
return 0;
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index d2895836f9fa..766098af4eb7 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -700,46 +700,26 @@ void sas_probe_sata(struct asd_sas_port *port)
}
-static bool sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
+static void sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
{
struct domain_device *dev, *n;
- bool retry = false;
list_for_each_entry_safe(dev, n, &port->dev_list, dev_list_node) {
- int rc;
-
if (!dev_is_sata(dev))
continue;
sas_ata_wait_eh(dev);
- rc = dev->sata_dev.pm_result;
- if (rc == -EAGAIN)
- retry = true;
- else if (rc) {
- /* since we don't have a
- * ->port_{suspend|resume} routine in our
- * ata_port ops, and no entanglements with
- * acpi, suspend should just be mechanical trip
- * through eh, catch cases where these
- * assumptions are invalidated
- */
- WARN_ONCE(1, "failed %s %s error: %d\n", func,
- dev_name(&dev->rphy->dev), rc);
- }
/* if libata failed to power manage the device, tear it down */
if (ata_dev_disabled(sas_to_ata_dev(dev)))
sas_fail_probe(dev, func, -ENODEV);
}
-
- return retry;
}
void sas_suspend_sata(struct asd_sas_port *port)
{
struct domain_device *dev;
- retry:
mutex_lock(&port->ha->disco_mutex);
list_for_each_entry(dev, &port->dev_list, dev_list_node) {
struct sata_device *sata;
@@ -751,20 +731,17 @@ void sas_suspend_sata(struct asd_sas_port *port)
if (sata->ap->pm_mesg.event == PM_EVENT_SUSPEND)
continue;
- sata->pm_result = -EIO;
- ata_sas_port_async_suspend(sata->ap, &sata->pm_result);
+ ata_sas_port_suspend(sata->ap);
}
mutex_unlock(&port->ha->disco_mutex);
- if (sas_ata_flush_pm_eh(port, __func__))
- goto retry;
+ sas_ata_flush_pm_eh(port, __func__);
}
void sas_resume_sata(struct asd_sas_port *port)
{
struct domain_device *dev;
- retry:
mutex_lock(&port->ha->disco_mutex);
list_for_each_entry(dev, &port->dev_list, dev_list_node) {
struct sata_device *sata;
@@ -776,13 +753,11 @@ void sas_resume_sata(struct asd_sas_port *port)
if (sata->ap->pm_mesg.event == PM_EVENT_ON)
continue;
- sata->pm_result = -EIO;
- ata_sas_port_async_resume(sata->ap, &sata->pm_result);
+ ata_sas_port_resume(sata->ap);
}
mutex_unlock(&port->ha->disco_mutex);
- if (sas_ata_flush_pm_eh(port, __func__))
- goto retry;
+ sas_ata_flush_pm_eh(port, __func__);
}
/**
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index da3aee17faa5..25d0f127424d 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -862,7 +862,7 @@ out:
enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
{
- scmd_printk(KERN_DEBUG, cmd, "command %p timed out\n", cmd);
+ scmd_dbg(cmd, "command %p timed out\n", cmd);
return BLK_EH_NOT_HANDLED;
}
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 4e1b75ca7451..94a3cafe7197 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -73,8 +73,6 @@ struct lpfc_sli2_slim;
*/
/* 1 Second */
#define QUEUE_RAMP_DOWN_INTERVAL (msecs_to_jiffies(1000 * 1))
-/* 5 minutes */
-#define QUEUE_RAMP_UP_INTERVAL (msecs_to_jiffies(1000 * 300))
/* Number of exchanges reserved for discovery to complete */
#define LPFC_DISC_IOCB_BUFF_COUNT 20
@@ -722,6 +720,20 @@ struct lpfc_hba {
uint32_t cfg_hba_queue_depth;
uint32_t cfg_enable_hba_reset;
uint32_t cfg_enable_hba_heartbeat;
+ uint32_t cfg_fof;
+ uint32_t cfg_EnableXLane;
+ uint8_t cfg_oas_tgt_wwpn[8];
+ uint8_t cfg_oas_vpt_wwpn[8];
+ uint32_t cfg_oas_lun_state;
+#define OAS_LUN_ENABLE 1
+#define OAS_LUN_DISABLE 0
+ uint32_t cfg_oas_lun_status;
+#define OAS_LUN_STATUS_EXISTS 0x01
+ uint32_t cfg_oas_flags;
+#define OAS_FIND_ANY_VPORT 0x01
+#define OAS_FIND_ANY_TARGET 0x02
+#define OAS_LUN_VALID 0x04
+ uint32_t cfg_XLanePriority;
uint32_t cfg_enable_bg;
uint32_t cfg_hostmem_hgp;
uint32_t cfg_log_verbose;
@@ -730,6 +742,7 @@ struct lpfc_hba {
uint32_t cfg_request_firmware_upgrade;
uint32_t cfg_iocb_cnt;
uint32_t cfg_suppress_link_up;
+ uint32_t cfg_rrq_xri_bitmap_sz;
#define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */
#define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */
#define LPFC_DELAY_INIT_LINK_INDEFINITELY 2 /* wait, manual intervention */
@@ -835,6 +848,7 @@ struct lpfc_hba {
mempool_t *mbox_mem_pool;
mempool_t *nlp_mem_pool;
mempool_t *rrq_pool;
+ mempool_t *active_rrq_pool;
struct fc_host_statistics link_stats;
enum intr_type_t intr_type;
@@ -869,7 +883,6 @@ struct lpfc_hba {
atomic_t num_cmd_success;
unsigned long last_rsrc_error_time;
unsigned long last_ramp_down_time;
- unsigned long last_ramp_up_time;
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
struct dentry *hba_debugfs_root;
atomic_t debugfs_vport_count;
@@ -971,6 +984,9 @@ struct lpfc_hba {
atomic_t sdev_cnt;
uint8_t fips_spec_rev;
uint8_t fips_level;
+ spinlock_t devicelock; /* lock for luns list */
+ mempool_t *device_data_mem_pool;
+ struct list_head luns;
};
static inline struct Scsi_Host *
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 00656fc92b93..8d5b6ceec9c9 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -529,6 +529,27 @@ lpfc_sli4_protocol_show(struct device *dev, struct device_attribute *attr,
}
/**
+ * lpfc_oas_supported_show - Return whether or not Optimized Access Storage
+ * (OAS) is supported.
+ * @dev: class unused variable.
+ * @attr: device attribute, not used.
+ * @buf: on return contains the module description text.
+ *
+ * Returns: size of formatted string.
+ **/
+static ssize_t
+lpfc_oas_supported_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ phba->sli4_hba.pc_sli4_params.oas_supported);
+}
+
+/**
* lpfc_link_state_store - Transition the link_state on an HBA port
* @dev: class device that is converted into a Scsi_host.
* @attr: device attribute, not used.
@@ -2041,9 +2062,53 @@ static DEVICE_ATTR(lpfc_dss, S_IRUGO, lpfc_dss_show, NULL);
static DEVICE_ATTR(lpfc_sriov_hw_max_virtfn, S_IRUGO,
lpfc_sriov_hw_max_virtfn_show, NULL);
static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL);
+static DEVICE_ATTR(lpfc_xlane_supported, S_IRUGO, lpfc_oas_supported_show,
+ NULL);
static char *lpfc_soft_wwn_key = "C99G71SL8032A";
+#define WWN_SZ 8
+/**
+ * lpfc_wwn_set - Convert string to the 8 byte WWN value.
+ * @buf: WWN string.
+ * @cnt: Length of string.
+ * @wwn: Array to receive converted wwn value.
+ *
+ * Returns:
+ * -EINVAL if the buffer does not contain a valid wwn
+ * 0 success
+ **/
+static size_t
+lpfc_wwn_set(const char *buf, size_t cnt, char wwn[])
+{
+ unsigned int i, j;
+
+ /* Count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+ if ((cnt < 16) || (cnt > 18) || ((cnt == 17) && (*buf++ != 'x')) ||
+ ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
+ return -EINVAL;
+
+ memset(wwn, 0, WWN_SZ);
+
+ /* Validate and store the new name */
+ for (i = 0, j = 0; i < 16; i++) {
+ if ((*buf >= 'a') && (*buf <= 'f'))
+ j = ((j << 4) | ((*buf++ - 'a') + 10));
+ else if ((*buf >= 'A') && (*buf <= 'F'))
+ j = ((j << 4) | ((*buf++ - 'A') + 10));
+ else if ((*buf >= '0') && (*buf <= '9'))
+ j = ((j << 4) | (*buf++ - '0'));
+ else
+ return -EINVAL;
+ if (i % 2) {
+ wwn[i/2] = j & 0xff;
+ j = 0;
+ }
+ }
+ return 0;
+}
/**
* lpfc_soft_wwn_enable_store - Allows setting of the wwn if the key is valid
* @dev: class device that is converted into a Scsi_host.
@@ -2132,9 +2197,9 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct completion online_compl;
- int stat1=0, stat2=0;
- unsigned int i, j, cnt=count;
- u8 wwpn[8];
+ int stat1 = 0, stat2 = 0;
+ unsigned int cnt = count;
+ u8 wwpn[WWN_SZ];
int rc;
if (!phba->cfg_enable_hba_reset)
@@ -2149,29 +2214,19 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr,
if (buf[cnt-1] == '\n')
cnt--;
- if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) ||
- ((cnt == 17) && (*buf++ != 'x')) ||
- ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
+ if (!phba->soft_wwn_enable)
return -EINVAL;
+ /* lock setting wwpn, wwnn down */
phba->soft_wwn_enable = 0;
- memset(wwpn, 0, sizeof(wwpn));
-
- /* Validate and store the new name */
- for (i=0, j=0; i < 16; i++) {
- int value;
-
- value = hex_to_bin(*buf++);
- if (value >= 0)
- j = (j << 4) | value;
- else
- return -EINVAL;
- if (i % 2) {
- wwpn[i/2] = j & 0xff;
- j = 0;
- }
+ rc = lpfc_wwn_set(buf, cnt, wwpn);
+ if (!rc) {
+ /* not able to set wwpn, unlock it */
+ phba->soft_wwn_enable = 1;
+ return rc;
}
+
phba->cfg_soft_wwpn = wwn_to_u64(wwpn);
fc_host_port_name(shost) = phba->cfg_soft_wwpn;
if (phba->cfg_soft_wwnn)
@@ -2198,7 +2253,7 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr,
"reinit adapter - %d\n", stat2);
return (stat1 || stat2) ? -EIO : count;
}
-static DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\
+static DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,
lpfc_soft_wwpn_show, lpfc_soft_wwpn_store);
/**
@@ -2235,39 +2290,25 @@ lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr,
{
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
- unsigned int i, j, cnt=count;
- u8 wwnn[8];
+ unsigned int cnt = count;
+ u8 wwnn[WWN_SZ];
+ int rc;
/* count may include a LF at end of string */
if (buf[cnt-1] == '\n')
cnt--;
- if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) ||
- ((cnt == 17) && (*buf++ != 'x')) ||
- ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
+ if (!phba->soft_wwn_enable)
return -EINVAL;
- /*
- * Allow wwnn to be set many times, as long as the enable is set.
- * However, once the wwpn is set, everything locks.
- */
-
- memset(wwnn, 0, sizeof(wwnn));
-
- /* Validate and store the new name */
- for (i=0, j=0; i < 16; i++) {
- int value;
-
- value = hex_to_bin(*buf++);
- if (value >= 0)
- j = (j << 4) | value;
- else
- return -EINVAL;
- if (i % 2) {
- wwnn[i/2] = j & 0xff;
- j = 0;
- }
+ rc = lpfc_wwn_set(buf, cnt, wwnn);
+ if (!rc) {
+ /* Allow wwnn to be set many times, as long as the enable
+ * is set. However, once the wwpn is set, everything locks.
+ */
+ return rc;
}
+
phba->cfg_soft_wwnn = wwn_to_u64(wwnn);
dev_printk(KERN_NOTICE, &phba->pcidev->dev,
@@ -2276,9 +2317,438 @@ lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR,\
+static DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR,
lpfc_soft_wwnn_show, lpfc_soft_wwnn_store);
+/**
+ * lpfc_oas_tgt_show - Return wwpn of target whose luns maybe enabled for
+ * Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ *
+ * Returns:
+ * value of count
+ **/
+static ssize_t
+lpfc_oas_tgt_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "0x%llx\n",
+ wwn_to_u64(phba->cfg_oas_tgt_wwpn));
+}
+
+/**
+ * lpfc_oas_tgt_store - Store wwpn of target whose luns maybe enabled for
+ * Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ * @count: Size of the data buffer.
+ *
+ * Returns:
+ * -EINVAL count is invalid, invalid wwpn byte invalid
+ * -EPERM oas is not supported by hba
+ * value of count on success
+ **/
+static ssize_t
+lpfc_oas_tgt_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ unsigned int cnt = count;
+ uint8_t wwpn[WWN_SZ];
+ int rc;
+
+ if (!phba->cfg_EnableXLane)
+ return -EPERM;
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ rc = lpfc_wwn_set(buf, cnt, wwpn);
+ if (rc)
+ return rc;
+
+ memcpy(phba->cfg_oas_tgt_wwpn, wwpn, (8 * sizeof(uint8_t)));
+ memcpy(phba->sli4_hba.oas_next_tgt_wwpn, wwpn, (8 * sizeof(uint8_t)));
+ if (wwn_to_u64(wwpn) == 0)
+ phba->cfg_oas_flags |= OAS_FIND_ANY_TARGET;
+ else
+ phba->cfg_oas_flags &= ~OAS_FIND_ANY_TARGET;
+ phba->cfg_oas_flags &= ~OAS_LUN_VALID;
+ phba->sli4_hba.oas_next_lun = FIND_FIRST_OAS_LUN;
+ return count;
+}
+static DEVICE_ATTR(lpfc_xlane_tgt, S_IRUGO | S_IWUSR,
+ lpfc_oas_tgt_show, lpfc_oas_tgt_store);
+
+/**
+ * lpfc_oas_vpt_show - Return wwpn of vport whose targets maybe enabled
+ * for Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ *
+ * Returns:
+ * value of count on success
+ **/
+static ssize_t
+lpfc_oas_vpt_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "0x%llx\n",
+ wwn_to_u64(phba->cfg_oas_vpt_wwpn));
+}
+
+/**
+ * lpfc_oas_vpt_store - Store wwpn of vport whose targets maybe enabled
+ * for Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ * @count: Size of the data buffer.
+ *
+ * Returns:
+ * -EINVAL count is invalid, invalid wwpn byte invalid
+ * -EPERM oas is not supported by hba
+ * value of count on success
+ **/
+static ssize_t
+lpfc_oas_vpt_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ unsigned int cnt = count;
+ uint8_t wwpn[WWN_SZ];
+ int rc;
+
+ if (!phba->cfg_EnableXLane)
+ return -EPERM;
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ rc = lpfc_wwn_set(buf, cnt, wwpn);
+ if (rc)
+ return rc;
+
+ memcpy(phba->cfg_oas_vpt_wwpn, wwpn, (8 * sizeof(uint8_t)));
+ memcpy(phba->sli4_hba.oas_next_vpt_wwpn, wwpn, (8 * sizeof(uint8_t)));
+ if (wwn_to_u64(wwpn) == 0)
+ phba->cfg_oas_flags |= OAS_FIND_ANY_VPORT;
+ else
+ phba->cfg_oas_flags &= ~OAS_FIND_ANY_VPORT;
+ phba->cfg_oas_flags &= ~OAS_LUN_VALID;
+ phba->sli4_hba.oas_next_lun = FIND_FIRST_OAS_LUN;
+ return count;
+}
+static DEVICE_ATTR(lpfc_xlane_vpt, S_IRUGO | S_IWUSR,
+ lpfc_oas_vpt_show, lpfc_oas_vpt_store);
+
+/**
+ * lpfc_oas_lun_state_show - Return the current state (enabled or disabled)
+ * of whether luns will be enabled or disabled
+ * for Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ *
+ * Returns:
+ * size of formatted string.
+ **/
+static ssize_t
+lpfc_oas_lun_state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_state);
+}
+
+/**
+ * lpfc_oas_lun_state_store - Store the state (enabled or disabled)
+ * of whether luns will be enabled or disabled
+ * for Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ * @count: Size of the data buffer.
+ *
+ * Returns:
+ * -EINVAL count is invalid, invalid wwpn byte invalid
+ * -EPERM oas is not supported by hba
+ * value of count on success
+ **/
+static ssize_t
+lpfc_oas_lun_state_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ int val = 0;
+
+ if (!phba->cfg_EnableXLane)
+ return -EPERM;
+
+ if (!isdigit(buf[0]))
+ return -EINVAL;
+
+ if (sscanf(buf, "%i", &val) != 1)
+ return -EINVAL;
+
+ if ((val != 0) && (val != 1))
+ return -EINVAL;
+
+ phba->cfg_oas_lun_state = val;
+
+ return strlen(buf);
+}
+static DEVICE_ATTR(lpfc_xlane_lun_state, S_IRUGO | S_IWUSR,
+ lpfc_oas_lun_state_show, lpfc_oas_lun_state_store);
+
+/**
+ * lpfc_oas_lun_status_show - Return the status of the Optimized Access
+ * Storage (OAS) lun returned by the
+ * lpfc_oas_lun_show function.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ *
+ * Returns:
+ * size of formatted string.
+ **/
+static ssize_t
+lpfc_oas_lun_status_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ if (!(phba->cfg_oas_flags & OAS_LUN_VALID))
+ return -EFAULT;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_status);
+}
+static DEVICE_ATTR(lpfc_xlane_lun_status, S_IRUGO,
+ lpfc_oas_lun_status_show, NULL);
+
+
+/**
+ * lpfc_oas_lun_state_set - enable or disable a lun for Optimized Access Storage
+ * (OAS) operations.
+ * @phba: lpfc_hba pointer.
+ * @ndlp: pointer to fcp target node.
+ * @lun: the fc lun for setting oas state.
+ * @oas_state: the oas state to be set to the lun.
+ *
+ * Returns:
+ * SUCCESS : 0
+ * -EPERM OAS is not enabled or not supported by this port.
+ *
+ */
+static size_t
+lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
+ uint8_t tgt_wwpn[], uint64_t lun, uint32_t oas_state)
+{
+
+ int rc = 0;
+
+ if (!phba->cfg_EnableXLane)
+ return -EPERM;
+
+ if (oas_state) {
+ if (!lpfc_enable_oas_lun(phba, (struct lpfc_name *)vpt_wwpn,
+ (struct lpfc_name *)tgt_wwpn, lun))
+ rc = -ENOMEM;
+ } else {
+ lpfc_disable_oas_lun(phba, (struct lpfc_name *)vpt_wwpn,
+ (struct lpfc_name *)tgt_wwpn, lun);
+ }
+ return rc;
+
+}
+
+/**
+ * lpfc_oas_lun_get_next - get the next lun that has been enabled for Optimized
+ * Access Storage (OAS) operations.
+ * @phba: lpfc_hba pointer.
+ * @vpt_wwpn: wwpn of the vport associated with the returned lun
+ * @tgt_wwpn: wwpn of the target associated with the returned lun
+ * @lun_status: status of the lun returned lun
+ *
+ * Returns the first or next lun enabled for OAS operations for the vport/target
+ * specified. If a lun is found, its vport wwpn, target wwpn and status is
+ * returned. If the lun is not found, NOT_OAS_ENABLED_LUN is returned.
+ *
+ * Return:
+ * lun that is OAS enabled for the vport/target
+ * NOT_OAS_ENABLED_LUN when no oas enabled lun found.
+ */
+static uint64_t
+lpfc_oas_lun_get_next(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
+ uint8_t tgt_wwpn[], uint32_t *lun_status)
+{
+ uint64_t found_lun;
+
+ if (unlikely(!phba) || !vpt_wwpn || !tgt_wwpn)
+ return NOT_OAS_ENABLED_LUN;
+ if (lpfc_find_next_oas_lun(phba, (struct lpfc_name *)
+ phba->sli4_hba.oas_next_vpt_wwpn,
+ (struct lpfc_name *)
+ phba->sli4_hba.oas_next_tgt_wwpn,
+ &phba->sli4_hba.oas_next_lun,
+ (struct lpfc_name *)vpt_wwpn,
+ (struct lpfc_name *)tgt_wwpn,
+ &found_lun, lun_status))
+ return found_lun;
+ else
+ return NOT_OAS_ENABLED_LUN;
+}
+
+/**
+ * lpfc_oas_lun_state_change - enable/disable a lun for OAS operations
+ * @phba: lpfc_hba pointer.
+ * @vpt_wwpn: vport wwpn by reference.
+ * @tgt_wwpn: target wwpn by reference.
+ * @lun: the fc lun for setting oas state.
+ * @oas_state: the oas state to be set to the oas_lun.
+ *
+ * This routine enables (OAS_LUN_ENABLE) or disables (OAS_LUN_DISABLE)
+ * a lun for OAS operations.
+ *
+ * Return:
+ * SUCCESS: 0
+ * -ENOMEM: failed to enable an lun for OAS operations
+ * -EPERM: OAS is not enabled
+ */
+static ssize_t
+lpfc_oas_lun_state_change(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
+ uint8_t tgt_wwpn[], uint64_t lun,
+ uint32_t oas_state)
+{
+
+ int rc;
+
+ rc = lpfc_oas_lun_state_set(phba, vpt_wwpn, tgt_wwpn, lun,
+ oas_state);
+ return rc;
+}
+
+/**
+ * lpfc_oas_lun_show - Return oas enabled luns from a chosen target
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ *
+ * This routine returns a lun enabled for OAS each time the function
+ * is called.
+ *
+ * Returns:
+ * SUCCESS: size of formatted string.
+ * -EFAULT: target or vport wwpn was not set properly.
+ * -EPERM: oas is not enabled.
+ **/
+static ssize_t
+lpfc_oas_lun_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ uint64_t oas_lun;
+ int len = 0;
+
+ if (!phba->cfg_EnableXLane)
+ return -EPERM;
+
+ if (wwn_to_u64(phba->cfg_oas_vpt_wwpn) == 0)
+ if (!(phba->cfg_oas_flags & OAS_FIND_ANY_VPORT))
+ return -EFAULT;
+
+ if (wwn_to_u64(phba->cfg_oas_tgt_wwpn) == 0)
+ if (!(phba->cfg_oas_flags & OAS_FIND_ANY_TARGET))
+ return -EFAULT;
+
+ oas_lun = lpfc_oas_lun_get_next(phba, phba->cfg_oas_vpt_wwpn,
+ phba->cfg_oas_tgt_wwpn,
+ &phba->cfg_oas_lun_status);
+ if (oas_lun != NOT_OAS_ENABLED_LUN)
+ phba->cfg_oas_flags |= OAS_LUN_VALID;
+
+ len += snprintf(buf + len, PAGE_SIZE-len, "0x%llx", oas_lun);
+
+ return len;
+}
+
+/**
+ * lpfc_oas_lun_store - Sets the OAS state for lun
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ *
+ * This function sets the OAS state for lun. Before this function is called,
+ * the vport wwpn, target wwpn, and oas state need to be set.
+ *
+ * Returns:
+ * SUCCESS: size of formatted string.
+ * -EFAULT: target or vport wwpn was not set properly.
+ * -EPERM: oas is not enabled.
+ * size of formatted string.
+ **/
+static ssize_t
+lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ uint64_t scsi_lun;
+ ssize_t rc;
+
+ if (!phba->cfg_EnableXLane)
+ return -EPERM;
+
+ if (wwn_to_u64(phba->cfg_oas_vpt_wwpn) == 0)
+ return -EFAULT;
+
+ if (wwn_to_u64(phba->cfg_oas_tgt_wwpn) == 0)
+ return -EFAULT;
+
+ if (!isdigit(buf[0]))
+ return -EINVAL;
+
+ if (sscanf(buf, "0x%llx", &scsi_lun) != 1)
+ return -EINVAL;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "3372 Try to set vport 0x%llx target 0x%llx lun:%lld "
+ "with oas set to %d\n",
+ wwn_to_u64(phba->cfg_oas_vpt_wwpn),
+ wwn_to_u64(phba->cfg_oas_tgt_wwpn), scsi_lun,
+ phba->cfg_oas_lun_state);
+
+ rc = lpfc_oas_lun_state_change(phba, phba->cfg_oas_vpt_wwpn,
+ phba->cfg_oas_tgt_wwpn, scsi_lun,
+ phba->cfg_oas_lun_state);
+
+ if (rc)
+ return rc;
+
+ return count;
+}
+static DEVICE_ATTR(lpfc_xlane_lun, S_IRUGO | S_IWUSR,
+ lpfc_oas_lun_show, lpfc_oas_lun_store);
static int lpfc_poll = 0;
module_param(lpfc_poll, int, S_IRUGO);
@@ -3818,7 +4288,7 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct lpfc_vector_map_info *cpup;
- int idx, len = 0;
+ int len = 0;
if ((phba->sli_rev != LPFC_SLI_REV4) ||
(phba->intr_type != MSIX))
@@ -3846,23 +4316,39 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr,
break;
}
- cpup = phba->sli4_hba.cpu_map;
- for (idx = 0; idx < phba->sli4_hba.num_present_cpu; idx++) {
+ while (phba->sli4_hba.curr_disp_cpu < phba->sli4_hba.num_present_cpu) {
+ cpup = &phba->sli4_hba.cpu_map[phba->sli4_hba.curr_disp_cpu];
+
+ /* margin should fit in this and the truncated message */
if (cpup->irq == LPFC_VECTOR_MAP_EMPTY)
len += snprintf(buf + len, PAGE_SIZE-len,
"CPU %02d io_chan %02d "
"physid %d coreid %d\n",
- idx, cpup->channel_id, cpup->phys_id,
+ phba->sli4_hba.curr_disp_cpu,
+ cpup->channel_id, cpup->phys_id,
cpup->core_id);
else
len += snprintf(buf + len, PAGE_SIZE-len,
"CPU %02d io_chan %02d "
"physid %d coreid %d IRQ %d\n",
- idx, cpup->channel_id, cpup->phys_id,
+ phba->sli4_hba.curr_disp_cpu,
+ cpup->channel_id, cpup->phys_id,
cpup->core_id, cpup->irq);
- cpup++;
+ phba->sli4_hba.curr_disp_cpu++;
+
+ /* display max number of CPUs keeping some margin */
+ if (phba->sli4_hba.curr_disp_cpu <
+ phba->sli4_hba.num_present_cpu &&
+ (len >= (PAGE_SIZE - 64))) {
+ len += snprintf(buf + len, PAGE_SIZE-len, "more...\n");
+ break;
+ }
}
+
+ if (phba->sli4_hba.curr_disp_cpu == phba->sli4_hba.num_present_cpu)
+ phba->sli4_hba.curr_disp_cpu = 0;
+
return len;
}
@@ -4157,6 +4643,21 @@ LPFC_ATTR_R(enable_hba_reset, 1, 0, 1, "Enable HBA resets from the driver.");
LPFC_ATTR_R(enable_hba_heartbeat, 0, 0, 1, "Enable HBA Heartbeat.");
/*
+# lpfc_EnableXLane: Enable Express Lane Feature
+# 0x0 Express Lane Feature disabled
+# 0x1 Express Lane Feature enabled
+# Value range is [0,1]. Default value is 0.
+*/
+LPFC_ATTR_R(EnableXLane, 0, 0, 1, "Enable Express Lane Feature.");
+
+/*
+# lpfc_XLanePriority: Define CS_CTL priority for Express Lane Feature
+# 0x0 - 0x7f = CS_CTL field in FC header (high 7 bits)
+# Value range is [0x0,0x7f]. Default value is 0
+*/
+LPFC_ATTR_R(XLanePriority, 0, 0x0, 0x7f, "CS_CTL for Express Lane Feature.");
+
+/*
# lpfc_enable_bg: Enable BlockGuard (Emulex's Implementation of T10-DIF)
# 0 = BlockGuard disabled (default)
# 1 = BlockGuard enabled
@@ -4317,6 +4818,13 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_soft_wwn_enable,
&dev_attr_lpfc_enable_hba_reset,
&dev_attr_lpfc_enable_hba_heartbeat,
+ &dev_attr_lpfc_EnableXLane,
+ &dev_attr_lpfc_XLanePriority,
+ &dev_attr_lpfc_xlane_lun,
+ &dev_attr_lpfc_xlane_tgt,
+ &dev_attr_lpfc_xlane_vpt,
+ &dev_attr_lpfc_xlane_lun_state,
+ &dev_attr_lpfc_xlane_lun_status,
&dev_attr_lpfc_sg_seg_cnt,
&dev_attr_lpfc_max_scsicmpl_time,
&dev_attr_lpfc_stat_data_ctrl,
@@ -4335,6 +4843,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_dss,
&dev_attr_lpfc_sriov_hw_max_virtfn,
&dev_attr_protocol,
+ &dev_attr_lpfc_xlane_supported,
NULL,
};
@@ -5296,11 +5805,20 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel);
lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
+ lpfc_EnableXLane_init(phba, lpfc_EnableXLane);
+ if (phba->sli_rev != LPFC_SLI_REV4)
+ phba->cfg_EnableXLane = 0;
+ lpfc_XLanePriority_init(phba, lpfc_XLanePriority);
+ memset(phba->cfg_oas_tgt_wwpn, 0, (8 * sizeof(uint8_t)));
+ memset(phba->cfg_oas_vpt_wwpn, 0, (8 * sizeof(uint8_t)));
+ phba->cfg_oas_lun_state = 0;
+ phba->cfg_oas_lun_status = 0;
+ phba->cfg_oas_flags = 0;
lpfc_enable_bg_init(phba, lpfc_enable_bg);
if (phba->sli_rev == LPFC_SLI_REV4)
phba->cfg_poll = 0;
else
- phba->cfg_poll = lpfc_poll;
+ phba->cfg_poll = lpfc_poll;
phba->cfg_soft_wwnn = 0L;
phba->cfg_soft_wwpn = 0L;
lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index 82134d20e2d8..ca2f4ea7cdef 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -4153,6 +4153,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
if (subsys == SLI_CONFIG_SUBSYS_FCOE) {
switch (opcode) {
case FCOE_OPCODE_READ_FCF:
+ case FCOE_OPCODE_GET_DPORT_RESULTS:
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"2957 Handled SLI_CONFIG "
"subsys_fcoe, opcode:x%x\n",
@@ -4161,6 +4162,8 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
nemb_mse, dmabuf);
break;
case FCOE_OPCODE_ADD_FCF:
+ case FCOE_OPCODE_SET_DPORT_MODE:
+ case LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE:
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"2958 Handled SLI_CONFIG "
"subsys_fcoe, opcode:x%x\n",
diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h
index 67f7d0a160d1..a94d4c9dfaa5 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.h
+++ b/drivers/scsi/lpfc/lpfc_bsg.h
@@ -231,6 +231,8 @@ struct lpfc_sli_config_emb0_subsys {
#define SLI_CONFIG_SUBSYS_FCOE 0x0C
#define FCOE_OPCODE_READ_FCF 0x08
#define FCOE_OPCODE_ADD_FCF 0x09
+#define FCOE_OPCODE_SET_DPORT_MODE 0x27
+#define FCOE_OPCODE_GET_DPORT_RESULTS 0x28
};
struct lpfc_sli_config_emb1_subsys {
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index cda076a84239..adda0bf7a244 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -187,6 +187,11 @@ void lpfc_offline_prep(struct lpfc_hba *, int);
void lpfc_offline(struct lpfc_hba *);
void lpfc_reset_hba(struct lpfc_hba *);
+int lpfc_fof_queue_create(struct lpfc_hba *);
+int lpfc_fof_queue_setup(struct lpfc_hba *);
+int lpfc_fof_queue_destroy(struct lpfc_hba *);
+irqreturn_t lpfc_sli4_fof_intr_handler(int, void *);
+
int lpfc_sli_setup(struct lpfc_hba *);
int lpfc_sli_queue_setup(struct lpfc_hba *);
@@ -242,6 +247,7 @@ int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *, uint16_t);
void lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *);
int lpfc_mem_alloc(struct lpfc_hba *, int align);
+int lpfc_mem_alloc_active_rrq_pool_s4(struct lpfc_hba *);
void lpfc_mem_free(struct lpfc_hba *);
void lpfc_mem_free_all(struct lpfc_hba *);
void lpfc_stop_vport_timers(struct lpfc_vport *);
@@ -399,7 +405,6 @@ void lpfc_fabric_block_timeout(unsigned long);
void lpfc_unblock_fabric_iocbs(struct lpfc_hba *);
void lpfc_rampdown_queue_depth(struct lpfc_hba *);
void lpfc_ramp_down_queue_handler(struct lpfc_hba *);
-void lpfc_ramp_up_queue_handler(struct lpfc_hba *);
void lpfc_scsi_dev_block(struct lpfc_hba *);
void
@@ -471,3 +476,20 @@ void lpfc_free_sgl_list(struct lpfc_hba *, struct list_head *);
uint32_t lpfc_sli_port_speed_get(struct lpfc_hba *);
int lpfc_sli4_request_firmware_update(struct lpfc_hba *, uint8_t);
void lpfc_sli4_offline_eratt(struct lpfc_hba *);
+
+struct lpfc_device_data *lpfc_create_device_data(struct lpfc_hba *,
+ struct lpfc_name *,
+ struct lpfc_name *,
+ uint64_t, bool);
+void lpfc_delete_device_data(struct lpfc_hba *, struct lpfc_device_data*);
+struct lpfc_device_data *__lpfc_get_device_data(struct lpfc_hba *,
+ struct list_head *list,
+ struct lpfc_name *,
+ struct lpfc_name *, uint64_t);
+bool lpfc_enable_oas_lun(struct lpfc_hba *, struct lpfc_name *,
+ struct lpfc_name *, uint64_t);
+bool lpfc_disable_oas_lun(struct lpfc_hba *, struct lpfc_name *,
+ struct lpfc_name *, uint64_t);
+bool lpfc_find_next_oas_lun(struct lpfc_hba *, struct lpfc_name *,
+ struct lpfc_name *, uint64_t *, struct lpfc_name *,
+ struct lpfc_name *, uint64_t *, uint32_t *);
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index b800cc952ca6..828c08e9389e 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -2280,6 +2280,104 @@ proc_cq:
}
}
+ if (phba->cfg_fof) {
+ /* FOF EQ */
+ qp = phba->sli4_hba.fof_eq;
+ if (!qp)
+ goto out;
+
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\nFOF EQ info: "
+ "EQ-STAT[max:x%x noE:x%x "
+ "bs:x%x proc:x%llx]\n",
+ qp->q_cnt_1, qp->q_cnt_2,
+ qp->q_cnt_3, (unsigned long long)qp->q_cnt_4);
+
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "EQID[%02d], "
+ "QE-CNT[%04d], QE-SIZE[%04d], "
+ "HOST-IDX[%04d], PORT-IDX[%04d]",
+ qp->queue_id,
+ qp->entry_count,
+ qp->entry_size,
+ qp->host_index,
+ qp->hba_index);
+
+ /* Reset max counter */
+ qp->EQ_max_eqe = 0;
+
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n");
+ if (len >= max_cnt)
+ goto too_big;
+ }
+
+ if (phba->cfg_EnableXLane) {
+
+ /* OAS CQ */
+ qp = phba->sli4_hba.oas_cq;
+ if (qp) {
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tOAS CQ info: ");
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "AssocEQID[%02d]: "
+ "CQ STAT[max:x%x relw:x%x "
+ "xabt:x%x wq:x%llx]\n",
+ qp->assoc_qid,
+ qp->q_cnt_1, qp->q_cnt_2,
+ qp->q_cnt_3, (unsigned long long)qp->q_cnt_4);
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tCQID[%02d], "
+ "QE-CNT[%04d], QE-SIZE[%04d], "
+ "HOST-IDX[%04d], PORT-IDX[%04d]",
+ qp->queue_id, qp->entry_count,
+ qp->entry_size, qp->host_index,
+ qp->hba_index);
+
+ /* Reset max counter */
+ qp->CQ_max_cqe = 0;
+
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n");
+ if (len >= max_cnt)
+ goto too_big;
+ }
+
+ /* OAS WQ */
+ qp = phba->sli4_hba.oas_wq;
+ if (qp) {
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\t\tOAS WQ info: ");
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "AssocCQID[%02d]: "
+ "WQ-STAT[oflow:x%x posted:x%llx]\n",
+ qp->assoc_qid,
+ qp->q_cnt_1, (unsigned long long)qp->q_cnt_4);
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\t\tWQID[%02d], "
+ "QE-CNT[%04d], QE-SIZE[%04d], "
+ "HOST-IDX[%04d], PORT-IDX[%04d]",
+ qp->queue_id,
+ qp->entry_count,
+ qp->entry_size,
+ qp->host_index,
+ qp->hba_index);
+
+ len += snprintf(pbuffer+len,
+ LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n");
+ if (len >= max_cnt)
+ goto too_big;
+ }
+ }
+out:
spin_unlock_irq(&phba->hbalock);
return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
@@ -3927,6 +4025,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
struct lpfc_hba *phba = vport->phba;
char name[64];
uint32_t num, i;
+ bool pport_setup = false;
if (!lpfc_debugfs_enable)
return;
@@ -3947,6 +4046,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
/* Setup funcX directory for specific HBA PCI function */
snprintf(name, sizeof(name), "fn%d", phba->brd_no);
if (!phba->hba_debugfs_root) {
+ pport_setup = true;
phba->hba_debugfs_root =
debugfs_create_dir(name, lpfc_debugfs_root);
if (!phba->hba_debugfs_root) {
@@ -4239,6 +4339,14 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
}
/*
+ * The following section is for additional directories/files for the
+ * physical port.
+ */
+
+ if (!pport_setup)
+ goto debug_failed;
+
+ /*
* iDiag debugfs root entry points for SLI4 device only
*/
if (phba->sli_rev < LPFC_SLI_REV4)
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index e409ba5f728c..1a6fe524940d 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -116,7 +116,7 @@ struct lpfc_nodelist {
atomic_t cmd_pending;
uint32_t cmd_qdepth;
unsigned long last_change_time;
- struct lpfc_node_rrqs active_rrqs;
+ unsigned long *active_rrqs_xri_bitmap;
struct lpfc_scsicmd_bkt *lat_data; /* Latency data */
};
struct lpfc_node_rrq {
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 110445f0c58d..624fe0b3cc0b 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -1516,7 +1516,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
uint32_t rc, keepDID = 0;
int put_node;
int put_rport;
- struct lpfc_node_rrqs rrq;
+ unsigned long *active_rrqs_xri_bitmap = NULL;
/* Fabric nodes can have the same WWPN so we don't bother searching
* by WWPN. Just return the ndlp that was given to us.
@@ -1534,7 +1534,13 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
if (new_ndlp == ndlp && NLP_CHK_NODE_ACT(new_ndlp))
return ndlp;
- memset(&rrq.xri_bitmap, 0, sizeof(new_ndlp->active_rrqs.xri_bitmap));
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ active_rrqs_xri_bitmap = mempool_alloc(phba->active_rrq_pool,
+ GFP_KERNEL);
+ if (active_rrqs_xri_bitmap)
+ memset(active_rrqs_xri_bitmap, 0,
+ phba->cfg_rrq_xri_bitmap_sz);
+ }
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"3178 PLOGI confirm: ndlp %p x%x: new_ndlp %p\n",
@@ -1543,41 +1549,58 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
if (!new_ndlp) {
rc = memcmp(&ndlp->nlp_portname, name,
sizeof(struct lpfc_name));
- if (!rc)
+ if (!rc) {
+ if (active_rrqs_xri_bitmap)
+ mempool_free(active_rrqs_xri_bitmap,
+ phba->active_rrq_pool);
return ndlp;
+ }
new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
- if (!new_ndlp)
+ if (!new_ndlp) {
+ if (active_rrqs_xri_bitmap)
+ mempool_free(active_rrqs_xri_bitmap,
+ phba->active_rrq_pool);
return ndlp;
+ }
lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID);
} else if (!NLP_CHK_NODE_ACT(new_ndlp)) {
rc = memcmp(&ndlp->nlp_portname, name,
sizeof(struct lpfc_name));
- if (!rc)
+ if (!rc) {
+ if (active_rrqs_xri_bitmap)
+ mempool_free(active_rrqs_xri_bitmap,
+ phba->active_rrq_pool);
return ndlp;
+ }
new_ndlp = lpfc_enable_node(vport, new_ndlp,
NLP_STE_UNUSED_NODE);
- if (!new_ndlp)
+ if (!new_ndlp) {
+ if (active_rrqs_xri_bitmap)
+ mempool_free(active_rrqs_xri_bitmap,
+ phba->active_rrq_pool);
return ndlp;
+ }
keepDID = new_ndlp->nlp_DID;
- if (phba->sli_rev == LPFC_SLI_REV4)
- memcpy(&rrq.xri_bitmap,
- &new_ndlp->active_rrqs.xri_bitmap,
- sizeof(new_ndlp->active_rrqs.xri_bitmap));
+ if ((phba->sli_rev == LPFC_SLI_REV4) && active_rrqs_xri_bitmap)
+ memcpy(active_rrqs_xri_bitmap,
+ new_ndlp->active_rrqs_xri_bitmap,
+ phba->cfg_rrq_xri_bitmap_sz);
} else {
keepDID = new_ndlp->nlp_DID;
- if (phba->sli_rev == LPFC_SLI_REV4)
- memcpy(&rrq.xri_bitmap,
- &new_ndlp->active_rrqs.xri_bitmap,
- sizeof(new_ndlp->active_rrqs.xri_bitmap));
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ active_rrqs_xri_bitmap)
+ memcpy(active_rrqs_xri_bitmap,
+ new_ndlp->active_rrqs_xri_bitmap,
+ phba->cfg_rrq_xri_bitmap_sz);
}
lpfc_unreg_rpi(vport, new_ndlp);
new_ndlp->nlp_DID = ndlp->nlp_DID;
new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
if (phba->sli_rev == LPFC_SLI_REV4)
- memcpy(new_ndlp->active_rrqs.xri_bitmap,
- &ndlp->active_rrqs.xri_bitmap,
- sizeof(ndlp->active_rrqs.xri_bitmap));
+ memcpy(new_ndlp->active_rrqs_xri_bitmap,
+ ndlp->active_rrqs_xri_bitmap,
+ phba->cfg_rrq_xri_bitmap_sz);
if (ndlp->nlp_flag & NLP_NPR_2B_DISC)
new_ndlp->nlp_flag |= NLP_NPR_2B_DISC;
@@ -1619,10 +1642,11 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
/* Two ndlps cannot have the same did on the nodelist */
ndlp->nlp_DID = keepDID;
- if (phba->sli_rev == LPFC_SLI_REV4)
- memcpy(&ndlp->active_rrqs.xri_bitmap,
- &rrq.xri_bitmap,
- sizeof(ndlp->active_rrqs.xri_bitmap));
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ active_rrqs_xri_bitmap)
+ memcpy(ndlp->active_rrqs_xri_bitmap,
+ active_rrqs_xri_bitmap,
+ phba->cfg_rrq_xri_bitmap_sz);
lpfc_drop_node(vport, ndlp);
}
else {
@@ -1634,10 +1658,11 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
/* Two ndlps cannot have the same did */
ndlp->nlp_DID = keepDID;
- if (phba->sli_rev == LPFC_SLI_REV4)
- memcpy(&ndlp->active_rrqs.xri_bitmap,
- &rrq.xri_bitmap,
- sizeof(ndlp->active_rrqs.xri_bitmap));
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ active_rrqs_xri_bitmap)
+ memcpy(ndlp->active_rrqs_xri_bitmap,
+ active_rrqs_xri_bitmap,
+ phba->cfg_rrq_xri_bitmap_sz);
/* Since we are swapping the ndlp passed in with the new one
* and the did has already been swapped, copy over state.
@@ -1668,6 +1693,10 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
put_device(&rport->dev);
}
}
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ active_rrqs_xri_bitmap)
+ mempool_free(active_rrqs_xri_bitmap,
+ phba->active_rrq_pool);
return new_ndlp;
}
@@ -2772,6 +2801,7 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
/* This will cause the callback-function lpfc_cmpl_els_cmd to
* trigger the release of node.
*/
+
lpfc_nlp_put(ndlp);
return 0;
}
@@ -6193,11 +6223,11 @@ lpfc_els_timeout(unsigned long ptr)
spin_lock_irqsave(&vport->work_port_lock, iflag);
tmo_posted = vport->work_port_events & WORKER_ELS_TMO;
- if (!tmo_posted)
+ if ((!tmo_posted) && (!(vport->load_flag & FC_UNLOADING)))
vport->work_port_events |= WORKER_ELS_TMO;
spin_unlock_irqrestore(&vport->work_port_lock, iflag);
- if (!tmo_posted)
+ if ((!tmo_posted) && (!(vport->load_flag & FC_UNLOADING)))
lpfc_worker_wake_up(phba);
return;
}
@@ -6223,19 +6253,26 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
uint32_t els_command = 0;
uint32_t timeout;
uint32_t remote_ID = 0xffffffff;
- LIST_HEAD(txcmplq_completions);
LIST_HEAD(abort_list);
timeout = (uint32_t)(phba->fc_ratov << 1);
pring = &phba->sli.ring[LPFC_ELS_RING];
-
+ if ((phba->pport->load_flag & FC_UNLOADING))
+ return;
spin_lock_irq(&phba->hbalock);
- list_splice_init(&pring->txcmplq, &txcmplq_completions);
- spin_unlock_irq(&phba->hbalock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_lock(&pring->ring_lock);
+
+ if ((phba->pport->load_flag & FC_UNLOADING)) {
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_unlock(&pring->ring_lock);
+ spin_unlock_irq(&phba->hbalock);
+ return;
+ }
- list_for_each_entry_safe(piocb, tmp_iocb, &txcmplq_completions, list) {
+ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
cmd = &piocb->iocb;
if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
@@ -6274,11 +6311,12 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
}
list_add_tail(&piocb->dlist, &abort_list);
}
- spin_lock_irq(&phba->hbalock);
- list_splice(&txcmplq_completions, &pring->txcmplq);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_unlock(&pring->ring_lock);
spin_unlock_irq(&phba->hbalock);
list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) {
+ cmd = &piocb->iocb;
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"0127 ELS timeout Data: x%x x%x x%x "
"x%x\n", els_command,
@@ -6290,8 +6328,9 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
}
if (!list_empty(&phba->sli.ring[LPFC_ELS_RING].txcmplq))
- mod_timer(&vport->els_tmofunc,
- jiffies + msecs_to_jiffies(1000 * timeout));
+ if (!(phba->pport->load_flag & FC_UNLOADING))
+ mod_timer(&vport->els_tmofunc,
+ jiffies + msecs_to_jiffies(1000 * timeout));
}
/**
@@ -6317,15 +6356,50 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
void
lpfc_els_flush_cmd(struct lpfc_vport *vport)
{
- LIST_HEAD(completions);
+ LIST_HEAD(abort_list);
struct lpfc_hba *phba = vport->phba;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
struct lpfc_iocbq *tmp_iocb, *piocb;
IOCB_t *cmd = NULL;
lpfc_fabric_abort_vport(vport);
+ /*
+ * For SLI3, only the hbalock is required. But SLI4 needs to coordinate
+ * with the ring insert operation. Because lpfc_sli_issue_abort_iotag
+ * ultimately grabs the ring_lock, the driver must splice the list into
+ * a working list and release the locks before calling the abort.
+ */
+ spin_lock_irq(&phba->hbalock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_lock(&pring->ring_lock);
+
+ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
+ if (piocb->iocb_flag & LPFC_IO_LIBDFC)
+ continue;
+
+ if (piocb->vport != vport)
+ continue;
+ list_add_tail(&piocb->dlist, &abort_list);
+ }
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_unlock(&pring->ring_lock);
+ spin_unlock_irq(&phba->hbalock);
+ /* Abort each iocb on the aborted list and remove the dlist links. */
+ list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) {
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&piocb->dlist);
+ lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+ spin_unlock_irq(&phba->hbalock);
+ }
+ if (!list_empty(&abort_list))
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "3387 abort list for txq not empty\n");
+ INIT_LIST_HEAD(&abort_list);
spin_lock_irq(&phba->hbalock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_lock(&pring->ring_lock);
+
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
cmd = &piocb->iocb;
@@ -6343,24 +6417,16 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
if (piocb->vport != vport)
continue;
- list_move_tail(&piocb->list, &completions);
- }
-
- list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
- if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
- continue;
- }
-
- if (piocb->vport != vport)
- continue;
-
- lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+ list_del_init(&piocb->list);
+ list_add_tail(&piocb->list, &abort_list);
}
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_unlock(&pring->ring_lock);
spin_unlock_irq(&phba->hbalock);
/* Cancell all the IOCBs from the completions list */
- lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
- IOERR_SLI_ABORTED);
+ lpfc_sli_cancel_iocbs(phba, &abort_list,
+ IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED);
return;
}
@@ -6385,35 +6451,9 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
void
lpfc_els_flush_all_cmd(struct lpfc_hba *phba)
{
- LIST_HEAD(completions);
- struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
- struct lpfc_iocbq *tmp_iocb, *piocb;
- IOCB_t *cmd = NULL;
-
- lpfc_fabric_abort_hba(phba);
- spin_lock_irq(&phba->hbalock);
- list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
- cmd = &piocb->iocb;
- if (piocb->iocb_flag & LPFC_IO_LIBDFC)
- continue;
- /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
- if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
- cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
- cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
- cmd->ulpCommand == CMD_ABORT_XRI_CN)
- continue;
- list_move_tail(&piocb->list, &completions);
- }
- list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
- if (piocb->iocb_flag & LPFC_IO_LIBDFC)
- continue;
- lpfc_sli_issue_abort_iotag(phba, pring, piocb);
- }
- spin_unlock_irq(&phba->hbalock);
-
- /* Cancel all the IOCBs from the completions list */
- lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
- IOERR_SLI_ABORTED);
+ struct lpfc_vport *vport;
+ list_for_each_entry(vport, &phba->port_list, listentry)
+ lpfc_els_flush_cmd(vport);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 883ea2d9f237..59b51c529ba0 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -674,8 +674,6 @@ lpfc_work_done(struct lpfc_hba *phba)
lpfc_fdmi_timeout_handler(vport);
if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
lpfc_ramp_down_queue_handler(phba);
- if (work_port_events & WORKER_RAMP_UP_QUEUE)
- lpfc_ramp_up_queue_handler(phba);
if (work_port_events & WORKER_DELAYED_DISC_TMO)
lpfc_delayed_disc_timeout_handler(vport);
}
@@ -2545,8 +2543,11 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
if (!new_fcf_record) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
"2766 Mailbox command READ_FCF_RECORD "
- "failed to retrieve a FCF record.\n");
- goto error_out;
+ "failed to retrieve a FCF record. "
+ "hba_flg x%x fcf_flg x%x\n", phba->hba_flag,
+ phba->fcf.fcf_flag);
+ lpfc_unregister_fcf_rescan(phba);
+ goto out;
}
/* Get the needed parameters from FCF record */
@@ -3973,7 +3974,10 @@ lpfc_nlp_counters(struct lpfc_vport *vport, int state, int count)
vport->fc_map_cnt += count;
break;
case NLP_STE_NPR_NODE:
- vport->fc_npr_cnt += count;
+ if (vport->fc_npr_cnt == 0 && count == -1)
+ vport->fc_npr_cnt = 0;
+ else
+ vport->fc_npr_cnt += count;
break;
}
spin_unlock_irq(shost->host_lock);
@@ -4180,6 +4184,7 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct lpfc_hba *phba = vport->phba;
uint32_t did;
unsigned long flags;
+ unsigned long *active_rrqs_xri_bitmap = NULL;
if (!ndlp)
return NULL;
@@ -4208,12 +4213,17 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* Keep the original DID */
did = ndlp->nlp_DID;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ active_rrqs_xri_bitmap = ndlp->active_rrqs_xri_bitmap;
/* re-initialize ndlp except of ndlp linked list pointer */
memset((((char *)ndlp) + sizeof (struct list_head)), 0,
sizeof (struct lpfc_nodelist) - sizeof (struct list_head));
lpfc_initialize_node(vport, ndlp, did);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ ndlp->active_rrqs_xri_bitmap = active_rrqs_xri_bitmap;
+
spin_unlock_irqrestore(&phba->ndlp_lock, flags);
if (vport->phba->sli_rev == LPFC_SLI_REV4)
ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(vport->phba);
@@ -4799,9 +4809,10 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
((uint32_t) ndlp->nlp_rpi & 0xff));
lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
"0929 FIND node DID "
- "Data: x%p x%x x%x x%x\n",
+ "Data: x%p x%x x%x x%x %p\n",
ndlp, ndlp->nlp_DID,
- ndlp->nlp_flag, data1);
+ ndlp->nlp_flag, data1,
+ ndlp->active_rrqs_xri_bitmap);
return ndlp;
}
}
@@ -5618,8 +5629,13 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
lpfc_initialize_node(vport, ndlp, did);
INIT_LIST_HEAD(&ndlp->nlp_listp);
- if (vport->phba->sli_rev == LPFC_SLI_REV4)
+ if (vport->phba->sli_rev == LPFC_SLI_REV4) {
ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(vport->phba);
+ ndlp->active_rrqs_xri_bitmap =
+ mempool_alloc(vport->phba->active_rrq_pool,
+ GFP_KERNEL);
+ }
+
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
@@ -5664,6 +5680,9 @@ lpfc_nlp_release(struct kref *kref)
/* free ndlp memory for final ndlp release */
if (NLP_CHK_FREE_REQ(ndlp)) {
kfree(ndlp->lat_data);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ mempool_free(ndlp->active_rrqs_xri_bitmap,
+ ndlp->phba->active_rrq_pool);
mempool_free(ndlp, ndlp->phba->nlp_mem_pool);
}
}
@@ -6170,10 +6189,6 @@ lpfc_read_fcf_conn_tbl(struct lpfc_hba *phba,
memcpy(&conn_entry->conn_rec, &conn_rec[i],
sizeof(struct lpfc_fcf_conn_rec));
- conn_entry->conn_rec.vlan_tag =
- conn_entry->conn_rec.vlan_tag;
- conn_entry->conn_rec.flags =
- conn_entry->conn_rec.flags;
list_add_tail(&conn_entry->list,
&phba->fcf_conn_rec_list);
}
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 6f927d30ca69..3d9438ce59ab 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -45,6 +45,7 @@
#define LPFC_EXTRA_RING 1 /* ring 1 for other protocols */
#define LPFC_ELS_RING 2 /* ring 2 for ELS commands */
#define LPFC_FCP_NEXT_RING 3
+#define LPFC_FCP_OAS_RING 3
#define SLI2_IOCB_CMD_R0_ENTRIES 172 /* SLI-2 FCP command ring entries */
#define SLI2_IOCB_RSP_R0_ENTRIES 134 /* SLI-2 FCP response ring entries */
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 5464b116d328..fd79f7de7666 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -2616,6 +2616,9 @@ struct lpfc_sli4_parameters {
#define cfg_phwq_SHIFT 15
#define cfg_phwq_MASK 0x00000001
#define cfg_phwq_WORD word12
+#define cfg_oas_SHIFT 25
+#define cfg_oas_MASK 0x00000001
+#define cfg_oas_WORD word12
#define cfg_loopbk_scope_SHIFT 28
#define cfg_loopbk_scope_MASK 0x0000000f
#define cfg_loopbk_scope_WORD word12
@@ -3322,6 +3325,9 @@ struct wqe_common {
#define wqe_ebde_cnt_SHIFT 0
#define wqe_ebde_cnt_MASK 0x0000000f
#define wqe_ebde_cnt_WORD word10
+#define wqe_oas_SHIFT 6
+#define wqe_oas_MASK 0x00000001
+#define wqe_oas_WORD word10
#define wqe_lenloc_SHIFT 7
#define wqe_lenloc_MASK 0x00000003
#define wqe_lenloc_WORD word10
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 68c94cc85c35..635eeb3d6987 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -80,6 +80,7 @@ static void lpfc_sli4_cq_event_pool_destroy(struct lpfc_hba *);
static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *);
static void lpfc_sli4_disable_intr(struct lpfc_hba *);
static uint32_t lpfc_sli4_enable_intr(struct lpfc_hba *, uint32_t);
+static void lpfc_sli4_oas_verify(struct lpfc_hba *phba);
static struct scsi_transport_template *lpfc_transport_template = NULL;
static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
@@ -1005,9 +1006,14 @@ lpfc_rrq_timeout(unsigned long ptr)
phba = (struct lpfc_hba *)ptr;
spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
- phba->hba_flag |= HBA_RRQ_ACTIVE;
+ if (!(phba->pport->load_flag & FC_UNLOADING))
+ phba->hba_flag |= HBA_RRQ_ACTIVE;
+ else
+ phba->hba_flag &= ~HBA_RRQ_ACTIVE;
spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
- lpfc_worker_wake_up(phba);
+
+ if (!(phba->pport->load_flag & FC_UNLOADING))
+ lpfc_worker_wake_up(phba);
}
/**
@@ -1468,7 +1474,8 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba)
* for handling possible port resource change.
**/
static int
-lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action)
+lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action,
+ bool en_rn_msg)
{
int rc;
uint32_t intr_mode;
@@ -1480,9 +1487,10 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action)
rc = lpfc_sli4_pdev_status_reg_wait(phba);
if (!rc) {
/* need reset: attempt for port recovery */
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "2887 Reset Needed: Attempting Port "
- "Recovery...\n");
+ if (en_rn_msg)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2887 Reset Needed: Attempting Port "
+ "Recovery...\n");
lpfc_offline_prep(phba, mbx_action);
lpfc_offline(phba);
/* release interrupt for possible resource change */
@@ -1522,6 +1530,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
uint32_t reg_err1, reg_err2;
uint32_t uerrlo_reg, uemasklo_reg;
uint32_t pci_rd_rc1, pci_rd_rc2;
+ bool en_rn_msg = true;
int rc;
/* If the pci channel is offline, ignore possible errors, since
@@ -1572,10 +1581,12 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
break;
}
if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 &&
- reg_err2 == SLIPORT_ERR2_REG_FW_RESTART)
+ reg_err2 == SLIPORT_ERR2_REG_FW_RESTART) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "3143 Port Down: Firmware Restarted\n");
- else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 &&
+ "3143 Port Down: Firmware Update "
+ "Detected\n");
+ en_rn_msg = false;
+ } else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 &&
reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3144 Port Down: Debug Dump\n");
@@ -1585,7 +1596,8 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
"3145 Port Down: Provisioning\n");
/* Check port status register for function reset */
- rc = lpfc_sli4_port_sta_fn_reset(phba, LPFC_MBX_NO_WAIT);
+ rc = lpfc_sli4_port_sta_fn_reset(phba, LPFC_MBX_NO_WAIT,
+ en_rn_msg);
if (rc == 0) {
/* don't report event on forced debug dump */
if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 &&
@@ -4856,6 +4868,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0};
struct lpfc_mqe *mqe;
int longs;
+ int fof_vectors = 0;
/* Get all the module params for configuring this host */
lpfc_get_cfgparam(phba);
@@ -5061,6 +5074,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
rc = lpfc_sli4_read_config(phba);
if (unlikely(rc))
goto out_free_bsmbx;
+ rc = lpfc_mem_alloc_active_rrq_pool_s4(phba);
+ if (unlikely(rc))
+ goto out_free_bsmbx;
/* IF Type 0 ports get initialized now. */
if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
@@ -5118,6 +5134,12 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
}
}
mempool_free(mboxq, phba->mbox_mem_pool);
+
+ /* Verify OAS is supported */
+ lpfc_sli4_oas_verify(phba);
+ if (phba->cfg_fof)
+ fof_vectors = 1;
+
/* Verify all the SLI4 queues */
rc = lpfc_sli4_queue_verify(phba);
if (rc)
@@ -5159,7 +5181,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
phba->sli4_hba.fcp_eq_hdl =
kzalloc((sizeof(struct lpfc_fcp_eq_hdl) *
- phba->cfg_fcp_io_channel), GFP_KERNEL);
+ (fof_vectors + phba->cfg_fcp_io_channel)),
+ GFP_KERNEL);
if (!phba->sli4_hba.fcp_eq_hdl) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2572 Failed allocate memory for "
@@ -5169,7 +5192,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
}
phba->sli4_hba.msix_entries = kzalloc((sizeof(struct msix_entry) *
- phba->cfg_fcp_io_channel), GFP_KERNEL);
+ (fof_vectors +
+ phba->cfg_fcp_io_channel)), GFP_KERNEL);
if (!phba->sli4_hba.msix_entries) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2573 Failed allocate memory for msi-x "
@@ -5267,6 +5291,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
kfree(phba->sli4_hba.cpu_map);
phba->sli4_hba.num_present_cpu = 0;
phba->sli4_hba.num_online_cpu = 0;
+ phba->sli4_hba.curr_disp_cpu = 0;
/* Free memory allocated for msi-x interrupt vector entries */
kfree(phba->sli4_hba.msix_entries);
@@ -5390,6 +5415,10 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba)
/* Initialize FCF connection rec list */
INIT_LIST_HEAD(&phba->fcf_conn_rec_list);
+ /* Initialize OAS configuration list */
+ spin_lock_init(&phba->devicelock);
+ INIT_LIST_HEAD(&phba->luns);
+
return 0;
}
@@ -6816,6 +6845,7 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)
int cfg_fcp_io_channel;
uint32_t cpu;
uint32_t i = 0;
+ int fof_vectors = phba->cfg_fof ? 1 : 0;
/*
* Sanity check for configured queue parameters against the run-time
@@ -6832,6 +6862,7 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)
}
phba->sli4_hba.num_online_cpu = i;
phba->sli4_hba.num_present_cpu = lpfc_present_cpu;
+ phba->sli4_hba.curr_disp_cpu = 0;
if (i < cfg_fcp_io_channel) {
lpfc_printf_log(phba,
@@ -6842,7 +6873,7 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)
cfg_fcp_io_channel = i;
}
- if (cfg_fcp_io_channel >
+ if (cfg_fcp_io_channel + fof_vectors >
phba->sli4_hba.max_cfg_param.max_eq) {
if (phba->sli4_hba.max_cfg_param.max_eq <
LPFC_FCP_IO_CHAN_MIN) {
@@ -6859,7 +6890,8 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)
"available EQs: from %d to %d\n",
cfg_fcp_io_channel,
phba->sli4_hba.max_cfg_param.max_eq);
- cfg_fcp_io_channel = phba->sli4_hba.max_cfg_param.max_eq;
+ cfg_fcp_io_channel = phba->sli4_hba.max_cfg_param.max_eq -
+ fof_vectors;
}
/* The actual number of FCP event queues adopted */
@@ -7070,6 +7102,9 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
}
phba->sli4_hba.dat_rq = qdesc;
+ /* Create the Queues needed for Flash Optimized Fabric operations */
+ if (phba->cfg_fof)
+ lpfc_fof_queue_create(phba);
return 0;
out_error:
@@ -7094,6 +7129,9 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
{
int idx;
+ if (phba->cfg_fof)
+ lpfc_fof_queue_destroy(phba);
+
if (phba->sli4_hba.hba_eq != NULL) {
/* Release HBA event queue */
for (idx = 0; idx < phba->cfg_fcp_io_channel; idx++) {
@@ -7478,8 +7516,20 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
phba->sli4_hba.hdr_rq->queue_id,
phba->sli4_hba.dat_rq->queue_id,
phba->sli4_hba.els_cq->queue_id);
+
+ if (phba->cfg_fof) {
+ rc = lpfc_fof_queue_setup(phba);
+ if (rc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0549 Failed setup of FOF Queues: "
+ "rc = 0x%x\n", rc);
+ goto out_destroy_els_rq;
+ }
+ }
return 0;
+out_destroy_els_rq:
+ lpfc_rq_destroy(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq);
out_destroy_els_wq:
lpfc_wq_destroy(phba, phba->sli4_hba.els_wq);
out_destroy_mbx_wq:
@@ -7518,6 +7568,9 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba)
{
int fcp_qidx;
+ /* Unset the queues created for Flash Optimized Fabric operations */
+ if (phba->cfg_fof)
+ lpfc_fof_queue_destroy(phba);
/* Unset mailbox command work queue */
lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq);
/* Unset ELS work queue */
@@ -8635,6 +8688,10 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
/* Configure MSI-X capability structure */
vectors = phba->cfg_fcp_io_channel;
+ if (phba->cfg_fof) {
+ phba->sli4_hba.msix_entries[index].entry = index;
+ vectors++;
+ }
enable_msix_vectors:
rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries,
vectors);
@@ -8664,7 +8721,15 @@ enable_msix_vectors:
phba->sli4_hba.fcp_eq_hdl[index].idx = index;
phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
atomic_set(&phba->sli4_hba.fcp_eq_hdl[index].fcp_eq_in_use, 1);
- rc = request_irq(phba->sli4_hba.msix_entries[index].vector,
+ if (phba->cfg_fof && (index == (vectors - 1)))
+ rc = request_irq(
+ phba->sli4_hba.msix_entries[index].vector,
+ &lpfc_sli4_fof_intr_handler, IRQF_SHARED,
+ (char *)&phba->sli4_hba.handler_name[index],
+ &phba->sli4_hba.fcp_eq_hdl[index]);
+ else
+ rc = request_irq(
+ phba->sli4_hba.msix_entries[index].vector,
&lpfc_sli4_hba_intr_handler, IRQF_SHARED,
(char *)&phba->sli4_hba.handler_name[index],
&phba->sli4_hba.fcp_eq_hdl[index]);
@@ -8676,6 +8741,9 @@ enable_msix_vectors:
}
}
+ if (phba->cfg_fof)
+ vectors--;
+
if (vectors != phba->cfg_fcp_io_channel) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3238 Reducing IO channels to match number of "
@@ -8721,7 +8789,10 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba)
free_irq(phba->sli4_hba.msix_entries[index].vector,
&phba->sli4_hba.fcp_eq_hdl[index]);
}
-
+ if (phba->cfg_fof) {
+ free_irq(phba->sli4_hba.msix_entries[index].vector,
+ &phba->sli4_hba.fcp_eq_hdl[index]);
+ }
/* Disable MSI-X */
pci_disable_msix(phba->pcidev);
@@ -8771,6 +8842,10 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba)
phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
}
+ if (phba->cfg_fof) {
+ phba->sli4_hba.fcp_eq_hdl[index].idx = index;
+ phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
+ }
return 0;
}
@@ -8853,6 +8928,12 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
atomic_set(&phba->sli4_hba.fcp_eq_hdl[index].
fcp_eq_in_use, 1);
}
+ if (phba->cfg_fof) {
+ phba->sli4_hba.fcp_eq_hdl[index].idx = index;
+ phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
+ atomic_set(&phba->sli4_hba.fcp_eq_hdl[index].
+ fcp_eq_in_use, 1);
+ }
}
}
return intr_mode;
@@ -9163,6 +9244,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
phba->sli3_options &= ~LPFC_SLI4_PHWQ_ENABLED;
sli4_params->sge_supp_len = mbx_sli4_parameters->sge_supp_len;
sli4_params->loopbk_scope = bf_get(loopbk_scope, mbx_sli4_parameters);
+ sli4_params->oas_supported = bf_get(cfg_oas, mbx_sli4_parameters);
sli4_params->cqv = bf_get(cfg_cqv, mbx_sli4_parameters);
sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters);
sli4_params->wqv = bf_get(cfg_wqv, mbx_sli4_parameters);
@@ -10796,6 +10878,169 @@ lpfc_io_resume(struct pci_dev *pdev)
return;
}
+/**
+ * lpfc_sli4_oas_verify - Verify OAS is supported by this adapter
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine checks to see if OAS is supported for this adapter. If
+ * supported, the configure Flash Optimized Fabric flag is set. Otherwise,
+ * the enable oas flag is cleared and the pool created for OAS device data
+ * is destroyed.
+ *
+ **/
+void
+lpfc_sli4_oas_verify(struct lpfc_hba *phba)
+{
+
+ if (!phba->cfg_EnableXLane)
+ return;
+
+ if (phba->sli4_hba.pc_sli4_params.oas_supported) {
+ phba->cfg_fof = 1;
+ } else {
+ phba->cfg_EnableXLane = 0;
+ if (phba->device_data_mem_pool)
+ mempool_destroy(phba->device_data_mem_pool);
+ phba->device_data_mem_pool = NULL;
+ }
+
+ return;
+}
+
+/**
+ * lpfc_fof_queue_setup - Set up all the fof queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to set up all the fof queues for the FC HBA
+ * operation.
+ *
+ * Return codes
+ * 0 - successful
+ * -ENOMEM - No available memory
+ **/
+int
+lpfc_fof_queue_setup(struct lpfc_hba *phba)
+{
+ struct lpfc_sli *psli = &phba->sli;
+ int rc;
+
+ rc = lpfc_eq_create(phba, phba->sli4_hba.fof_eq, LPFC_MAX_IMAX);
+ if (rc)
+ return -ENOMEM;
+
+ if (phba->cfg_EnableXLane) {
+
+ rc = lpfc_cq_create(phba, phba->sli4_hba.oas_cq,
+ phba->sli4_hba.fof_eq, LPFC_WCQ, LPFC_FCP);
+ if (rc)
+ goto out_oas_cq;
+
+ rc = lpfc_wq_create(phba, phba->sli4_hba.oas_wq,
+ phba->sli4_hba.oas_cq, LPFC_FCP);
+ if (rc)
+ goto out_oas_wq;
+
+ phba->sli4_hba.oas_cq->pring = &psli->ring[LPFC_FCP_OAS_RING];
+ phba->sli4_hba.oas_ring = &psli->ring[LPFC_FCP_OAS_RING];
+ }
+
+ return 0;
+
+out_oas_wq:
+ if (phba->cfg_EnableXLane)
+ lpfc_cq_destroy(phba, phba->sli4_hba.oas_cq);
+out_oas_cq:
+ lpfc_eq_destroy(phba, phba->sli4_hba.fof_eq);
+ return rc;
+
+}
+
+/**
+ * lpfc_fof_queue_create - Create all the fof queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to allocate all the fof queues for the FC HBA
+ * operation. For each SLI4 queue type, the parameters such as queue entry
+ * count (queue depth) shall be taken from the module parameter. For now,
+ * we just use some constant number as place holder.
+ *
+ * Return codes
+ * 0 - successful
+ * -ENOMEM - No availble memory
+ * -EIO - The mailbox failed to complete successfully.
+ **/
+int
+lpfc_fof_queue_create(struct lpfc_hba *phba)
+{
+ struct lpfc_queue *qdesc;
+
+ /* Create FOF EQ */
+ qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize,
+ phba->sli4_hba.eq_ecount);
+ if (!qdesc)
+ goto out_error;
+
+ phba->sli4_hba.fof_eq = qdesc;
+
+ if (phba->cfg_EnableXLane) {
+
+ /* Create OAS CQ */
+ qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize,
+ phba->sli4_hba.cq_ecount);
+ if (!qdesc)
+ goto out_error;
+
+ phba->sli4_hba.oas_cq = qdesc;
+
+ /* Create OAS WQ */
+ qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize,
+ phba->sli4_hba.wq_ecount);
+ if (!qdesc)
+ goto out_error;
+
+ phba->sli4_hba.oas_wq = qdesc;
+
+ }
+ return 0;
+
+out_error:
+ lpfc_fof_queue_destroy(phba);
+ return -ENOMEM;
+}
+
+/**
+ * lpfc_fof_queue_destroy - Destroy all the fof queues
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release all the SLI4 queues with the FC HBA
+ * operation.
+ *
+ * Return codes
+ * 0 - successful
+ **/
+int
+lpfc_fof_queue_destroy(struct lpfc_hba *phba)
+{
+ /* Release FOF Event queue */
+ if (phba->sli4_hba.fof_eq != NULL) {
+ lpfc_sli4_queue_free(phba->sli4_hba.fof_eq);
+ phba->sli4_hba.fof_eq = NULL;
+ }
+
+ /* Release OAS Completion queue */
+ if (phba->sli4_hba.oas_cq != NULL) {
+ lpfc_sli4_queue_free(phba->sli4_hba.oas_cq);
+ phba->sli4_hba.oas_cq = NULL;
+ }
+
+ /* Release OAS Work queue */
+ if (phba->sli4_hba.oas_wq != NULL) {
+ lpfc_sli4_queue_free(phba->sli4_hba.oas_wq);
+ phba->sli4_hba.oas_wq = NULL;
+ }
+ return 0;
+}
+
static struct pci_device_id lpfc_id_table[] = {
{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER,
PCI_ANY_ID, PCI_ANY_ID, },
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 812d0cd7c86d..ed419aad2b1f 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -38,10 +38,29 @@
#include "lpfc_scsi.h"
#include "lpfc.h"
#include "lpfc_crtn.h"
+#include "lpfc_logmsg.h"
#define LPFC_MBUF_POOL_SIZE 64 /* max elements in MBUF safety pool */
#define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */
+#define LPFC_DEVICE_DATA_POOL_SIZE 64 /* max elements in device data pool */
+int
+lpfc_mem_alloc_active_rrq_pool_s4(struct lpfc_hba *phba) {
+ size_t bytes;
+ int max_xri = phba->sli4_hba.max_cfg_param.max_xri;
+
+ if (max_xri <= 0)
+ return -ENOMEM;
+ bytes = ((BITS_PER_LONG - 1 + max_xri) / BITS_PER_LONG) *
+ sizeof(unsigned long);
+ phba->cfg_rrq_xri_bitmap_sz = bytes;
+ phba->active_rrq_pool = mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE,
+ bytes);
+ if (!phba->active_rrq_pool)
+ return -ENOMEM;
+ else
+ return 0;
+}
/**
* lpfc_mem_alloc - create and allocate all PCI and memory pools
@@ -146,6 +165,16 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align)
phba->lpfc_drb_pool = NULL;
}
+ if (phba->cfg_EnableXLane) {
+ phba->device_data_mem_pool = mempool_create_kmalloc_pool(
+ LPFC_DEVICE_DATA_POOL_SIZE,
+ sizeof(struct lpfc_device_data));
+ if (!phba->device_data_mem_pool)
+ goto fail_free_hrb_pool;
+ } else {
+ phba->device_data_mem_pool = NULL;
+ }
+
return 0;
fail_free_hrb_pool:
pci_pool_destroy(phba->lpfc_hrb_pool);
@@ -188,6 +217,7 @@ lpfc_mem_free(struct lpfc_hba *phba)
{
int i;
struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+ struct lpfc_device_data *device_data;
/* Free HBQ pools */
lpfc_sli_hbqbuf_free_all(phba);
@@ -209,6 +239,10 @@ lpfc_mem_free(struct lpfc_hba *phba)
/* Free NLP memory pool */
mempool_destroy(phba->nlp_mem_pool);
phba->nlp_mem_pool = NULL;
+ if (phba->sli_rev == LPFC_SLI_REV4 && phba->active_rrq_pool) {
+ mempool_destroy(phba->active_rrq_pool);
+ phba->active_rrq_pool = NULL;
+ }
/* Free mbox memory pool */
mempool_destroy(phba->mbox_mem_pool);
@@ -227,6 +261,19 @@ lpfc_mem_free(struct lpfc_hba *phba)
pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
phba->lpfc_scsi_dma_buf_pool = NULL;
+ /* Free Device Data memory pool */
+ if (phba->device_data_mem_pool) {
+ /* Ensure all objects have been returned to the pool */
+ while (!list_empty(&phba->luns)) {
+ device_data = list_first_entry(&phba->luns,
+ struct lpfc_device_data,
+ listentry);
+ list_del(&device_data->listentry);
+ mempool_free(device_data, phba->device_data_mem_pool);
+ }
+ mempool_destroy(phba->device_data_mem_pool);
+ }
+ phba->device_data_mem_pool = NULL;
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index abc361259d6d..c342f6afd747 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -203,8 +203,6 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
int
lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
- LIST_HEAD(completions);
- LIST_HEAD(txcmplq_completions);
LIST_HEAD(abort_list);
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
@@ -216,32 +214,27 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
"Data: x%x x%x x%x\n",
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi);
-
+ /* Clean up all fabric IOs first.*/
lpfc_fabric_abort_nport(ndlp);
- /* First check the txq */
+ /*
+ * Lock the ELS ring txcmplq for SLI3/SLI4 and build a local list
+ * of all ELS IOs that need an ABTS. The IOs need to stay on the
+ * txcmplq so that the abort operation completes them successfully.
+ */
spin_lock_irq(&phba->hbalock);
- list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
- /* Check to see if iocb matches the nport we are looking for */
- if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
- /* It matches, so deque and call compl with anp error */
- list_move_tail(&iocb->list, &completions);
- }
- }
-
- /* Next check the txcmplq */
- list_splice_init(&pring->txcmplq, &txcmplq_completions);
- spin_unlock_irq(&phba->hbalock);
-
- list_for_each_entry_safe(iocb, next_iocb, &txcmplq_completions, list) {
- /* Check to see if iocb matches the nport we are looking for */
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_lock(&pring->ring_lock);
+ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+ /* Add to abort_list on on NDLP match. */
if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
list_add_tail(&iocb->dlist, &abort_list);
}
- spin_lock_irq(&phba->hbalock);
- list_splice(&txcmplq_completions, &pring->txcmplq);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_unlock(&pring->ring_lock);
spin_unlock_irq(&phba->hbalock);
+ /* Abort the targeted IOs and remove them from the abort list. */
list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) {
spin_lock_irq(&phba->hbalock);
list_del_init(&iocb->dlist);
@@ -249,9 +242,28 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
spin_unlock_irq(&phba->hbalock);
}
+ INIT_LIST_HEAD(&abort_list);
+
+ /* Now process the txq */
+ spin_lock_irq(&phba->hbalock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_lock(&pring->ring_lock);
+
+ list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
+ /* Check to see if iocb matches the nport we are looking for */
+ if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
+ list_del_init(&iocb->list);
+ list_add_tail(&iocb->list, &abort_list);
+ }
+ }
+
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_unlock(&pring->ring_lock);
+ spin_unlock_irq(&phba->hbalock);
+
/* Cancel all the IOCBs from the completions list */
- lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
- IOERR_SLI_ABORTED);
+ lpfc_sli_cancel_iocbs(phba, &abort_list,
+ IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED);
lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
return 0;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index b2ede05a5f0a..462453ee0bda 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -68,6 +68,17 @@ struct scsi_dif_tuple {
__be32 ref_tag; /* Target LBA or indirect LBA */
};
+static struct lpfc_rport_data *
+lpfc_rport_data_from_scsi_device(struct scsi_device *sdev)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *)sdev->host->hostdata;
+
+ if (vport->phba->cfg_EnableXLane)
+ return ((struct lpfc_device_data *)sdev->hostdata)->rport_data;
+ else
+ return (struct lpfc_rport_data *)sdev->hostdata;
+}
+
static void
lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
static void
@@ -304,9 +315,27 @@ lpfc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
unsigned long new_queue_depth, old_queue_depth;
old_queue_depth = sdev->queue_depth;
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+
+ switch (reason) {
+ case SCSI_QDEPTH_DEFAULT:
+ /* change request from sysfs, fall through */
+ case SCSI_QDEPTH_RAMP_UP:
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+ break;
+ case SCSI_QDEPTH_QFULL:
+ if (scsi_track_queue_full(sdev, qdepth) == 0)
+ return sdev->queue_depth;
+
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+ "0711 detected queue full - lun queue "
+ "depth adjusted to %d.\n", sdev->queue_depth);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
new_queue_depth = sdev->queue_depth;
- rdata = sdev->hostdata;
+ rdata = lpfc_rport_data_from_scsi_device(sdev);
if (rdata)
lpfc_send_sdev_queuedepth_change_event(phba, vport,
rdata->pnode, sdev->lun,
@@ -377,50 +406,6 @@ lpfc_rampdown_queue_depth(struct lpfc_hba *phba)
}
/**
- * lpfc_rampup_queue_depth - Post RAMP_UP_QUEUE event for worker thread
- * @phba: The Hba for which this call is being executed.
- *
- * This routine post WORKER_RAMP_UP_QUEUE event for @phba vport. This routine
- * post at most 1 event every 5 minute after last_ramp_up_time or
- * last_rsrc_error_time. This routine wakes up worker thread of @phba
- * to process WORKER_RAM_DOWN_EVENT event.
- *
- * This routine should be called with no lock held.
- **/
-static inline void
-lpfc_rampup_queue_depth(struct lpfc_vport *vport,
- uint32_t queue_depth)
-{
- unsigned long flags;
- struct lpfc_hba *phba = vport->phba;
- uint32_t evt_posted;
- atomic_inc(&phba->num_cmd_success);
-
- if (vport->cfg_lun_queue_depth <= queue_depth)
- return;
- spin_lock_irqsave(&phba->hbalock, flags);
- if (time_before(jiffies,
- phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) ||
- time_before(jiffies,
- phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL)) {
- spin_unlock_irqrestore(&phba->hbalock, flags);
- return;
- }
- phba->last_ramp_up_time = jiffies;
- spin_unlock_irqrestore(&phba->hbalock, flags);
-
- spin_lock_irqsave(&phba->pport->work_port_lock, flags);
- evt_posted = phba->pport->work_port_events & WORKER_RAMP_UP_QUEUE;
- if (!evt_posted)
- phba->pport->work_port_events |= WORKER_RAMP_UP_QUEUE;
- spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
-
- if (!evt_posted)
- lpfc_worker_wake_up(phba);
- return;
-}
-
-/**
* lpfc_ramp_down_queue_handler - WORKER_RAMP_DOWN_QUEUE event handler
* @phba: The Hba for which this call is being executed.
*
@@ -472,41 +457,6 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
}
/**
- * lpfc_ramp_up_queue_handler - WORKER_RAMP_UP_QUEUE event handler
- * @phba: The Hba for which this call is being executed.
- *
- * This routine is called to process WORKER_RAMP_UP_QUEUE event for worker
- * thread.This routine increases queue depth for all scsi device on each vport
- * associated with @phba by 1. This routine also sets @phba num_rsrc_err and
- * num_cmd_success to zero.
- **/
-void
-lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
-{
- struct lpfc_vport **vports;
- struct Scsi_Host *shost;
- struct scsi_device *sdev;
- int i;
-
- vports = lpfc_create_vport_work_array(phba);
- if (vports != NULL)
- for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
- shost = lpfc_shost_from_vport(vports[i]);
- shost_for_each_device(sdev, shost) {
- if (vports[i]->cfg_lun_queue_depth <=
- sdev->queue_depth)
- continue;
- lpfc_change_queue_depth(sdev,
- sdev->queue_depth+1,
- SCSI_QDEPTH_RAMP_UP);
- }
- }
- lpfc_destroy_vport_work_array(phba, vports);
- atomic_set(&phba->num_rsrc_err, 0);
- atomic_set(&phba->num_cmd_success, 0);
-}
-
-/**
* lpfc_scsi_dev_block - set all scsi hosts to block state
* @phba: Pointer to HBA context object.
*
@@ -1502,7 +1452,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc,
}
/* Next check if we need to match the remote NPortID or WWPN */
- rdata = sc->device->hostdata;
+ rdata = lpfc_rport_data_from_scsi_device(sc->device);
if (rdata && rdata->pnode) {
ndlp = rdata->pnode;
@@ -3507,6 +3457,14 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
* we need to set word 4 of IOCB here
*/
iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd);
+
+ /*
+ * If the OAS driver feature is enabled and the lun is enabled for
+ * OAS, set the oas iocb related flags.
+ */
+ if ((phba->cfg_EnableXLane) && ((struct lpfc_device_data *)
+ scsi_cmnd->device->hostdata)->oas_enabled)
+ lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_OAS;
return 0;
}
@@ -4021,7 +3979,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
struct lpfc_nodelist *pnode = rdata->pnode;
struct scsi_cmnd *cmd;
int result;
- struct scsi_device *tmp_sdev;
int depth;
unsigned long flags;
struct lpfc_fast_path_event *fast_path_evt;
@@ -4266,32 +4223,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
return;
}
- if (!result)
- lpfc_rampup_queue_depth(vport, queue_depth);
-
- /*
- * Check for queue full. If the lun is reporting queue full, then
- * back off the lun queue depth to prevent target overloads.
- */
- if (result == SAM_STAT_TASK_SET_FULL && pnode &&
- NLP_CHK_NODE_ACT(pnode)) {
- shost_for_each_device(tmp_sdev, shost) {
- if (tmp_sdev->id != scsi_id)
- continue;
- depth = scsi_track_queue_full(tmp_sdev,
- tmp_sdev->queue_depth-1);
- if (depth <= 0)
- continue;
- lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
- "0711 detected queue full - lun queue "
- "depth adjusted to %d.\n", depth);
- lpfc_send_sdev_queuedepth_change_event(phba, vport,
- pnode,
- tmp_sdev->lun,
- depth+1, depth);
- }
- }
-
spin_lock_irqsave(&phba->hbalock, flags);
lpfc_cmd->pCmd = NULL;
spin_unlock_irqrestore(&phba->hbalock, flags);
@@ -4492,6 +4423,8 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport,
}
piocb->ulpFCP2Rcvy = (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) ? 1 : 0;
piocb->ulpClass = (ndlp->nlp_fcp_info & 0x0f);
+ piocb->ulpPU = 0;
+ piocb->un.fcpi.fcpi_parm = 0;
/* ulpTimeout is only one byte */
if (lpfc_cmd->timeout > 0xff) {
@@ -4691,12 +4624,13 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
{
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- struct lpfc_rport_data *rdata = cmnd->device->hostdata;
+ struct lpfc_rport_data *rdata;
struct lpfc_nodelist *ndlp;
struct lpfc_scsi_buf *lpfc_cmd;
struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
int err;
+ rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
err = fc_remote_port_chkready(rport);
if (err) {
cmnd->result = err;
@@ -4782,6 +4716,24 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
&lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
if (err) {
atomic_dec(&ndlp->cmd_pending);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+ "3376 FCP could not issue IOCB err %x"
+ "FCP cmd x%x <%d/%d> "
+ "sid: x%x did: x%x oxid: x%x "
+ "Data: x%x x%x x%x x%x\n",
+ err, cmnd->cmnd[0],
+ cmnd->device ? cmnd->device->id : 0xffff,
+ cmnd->device ? cmnd->device->lun : 0xffff,
+ vport->fc_myDID, ndlp->nlp_DID,
+ phba->sli_rev == LPFC_SLI_REV4 ?
+ lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff,
+ lpfc_cmd->cur_iocbq.iocb.ulpContext,
+ lpfc_cmd->cur_iocbq.iocb.ulpIoTag,
+ lpfc_cmd->cur_iocbq.iocb.ulpTimeout,
+ (uint32_t)
+ (cmnd->request->timeout / 1000));
+
+
goto out_host_busy_free_buf;
}
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
@@ -5161,10 +5113,11 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
static int
lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd)
{
- struct lpfc_rport_data *rdata = cmnd->device->hostdata;
+ struct lpfc_rport_data *rdata;
struct lpfc_nodelist *pnode;
unsigned long later;
+ rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
if (!rdata) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
"0797 Tgt Map rport failure: rdata x%p\n", rdata);
@@ -5182,7 +5135,7 @@ lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd)
if (pnode->nlp_state == NLP_STE_MAPPED_NODE)
return SUCCESS;
schedule_timeout_uninterruptible(msecs_to_jiffies(500));
- rdata = cmnd->device->hostdata;
+ rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
if (!rdata)
return FAILED;
pnode = rdata->pnode;
@@ -5254,13 +5207,14 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
{
struct Scsi_Host *shost = cmnd->device->host;
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
- struct lpfc_rport_data *rdata = cmnd->device->hostdata;
+ struct lpfc_rport_data *rdata;
struct lpfc_nodelist *pnode;
unsigned tgt_id = cmnd->device->id;
unsigned int lun_id = cmnd->device->lun;
struct lpfc_scsi_event_header scsi_event;
int status;
+ rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
if (!rdata) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
"0798 Device Reset rport failure: rdata x%p\n", rdata);
@@ -5323,13 +5277,14 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
{
struct Scsi_Host *shost = cmnd->device->host;
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
- struct lpfc_rport_data *rdata = cmnd->device->hostdata;
+ struct lpfc_rport_data *rdata;
struct lpfc_nodelist *pnode;
unsigned tgt_id = cmnd->device->id;
unsigned int lun_id = cmnd->device->lun;
struct lpfc_scsi_event_header scsi_event;
int status;
+ rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
if (!rdata) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
"0799 Target Reset rport failure: rdata x%p\n", rdata);
@@ -5529,11 +5484,45 @@ lpfc_slave_alloc(struct scsi_device *sdev)
uint32_t num_to_alloc = 0;
int num_allocated = 0;
uint32_t sdev_cnt;
+ struct lpfc_device_data *device_data;
+ unsigned long flags;
+ struct lpfc_name target_wwpn;
if (!rport || fc_remote_port_chkready(rport))
return -ENXIO;
- sdev->hostdata = rport->dd_data;
+ if (phba->cfg_EnableXLane) {
+
+ /*
+ * Check to see if the device data structure for the lun
+ * exists. If not, create one.
+ */
+
+ u64_to_wwn(rport->port_name, target_wwpn.u.wwn);
+ spin_lock_irqsave(&phba->devicelock, flags);
+ device_data = __lpfc_get_device_data(phba,
+ &phba->luns,
+ &vport->fc_portname,
+ &target_wwpn,
+ sdev->lun);
+ if (!device_data) {
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ device_data = lpfc_create_device_data(phba,
+ &vport->fc_portname,
+ &target_wwpn,
+ sdev->lun, true);
+ if (!device_data)
+ return -ENOMEM;
+ spin_lock_irqsave(&phba->devicelock, flags);
+ list_add_tail(&device_data->listentry, &phba->luns);
+ }
+ device_data->rport_data = rport->dd_data;
+ device_data->available = true;
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ sdev->hostdata = device_data;
+ } else {
+ sdev->hostdata = rport->dd_data;
+ }
sdev_cnt = atomic_inc_return(&phba->sdev_cnt);
/*
@@ -5623,11 +5612,344 @@ lpfc_slave_destroy(struct scsi_device *sdev)
{
struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
struct lpfc_hba *phba = vport->phba;
+ unsigned long flags;
+ struct lpfc_device_data *device_data = sdev->hostdata;
+
atomic_dec(&phba->sdev_cnt);
+ if ((phba->cfg_EnableXLane) && (device_data)) {
+ spin_lock_irqsave(&phba->devicelock, flags);
+ device_data->available = false;
+ if (!device_data->oas_enabled)
+ lpfc_delete_device_data(phba, device_data);
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ }
sdev->hostdata = NULL;
return;
}
+/**
+ * lpfc_create_device_data - creates and initializes device data structure for OAS
+ * @pha: Pointer to host bus adapter structure.
+ * @vport_wwpn: Pointer to vport's wwpn information
+ * @target_wwpn: Pointer to target's wwpn information
+ * @lun: Lun on target
+ * @atomic_create: Flag to indicate if memory should be allocated using the
+ * GFP_ATOMIC flag or not.
+ *
+ * This routine creates a device data structure which will contain identifying
+ * information for the device (host wwpn, target wwpn, lun), state of OAS,
+ * whether or not the corresponding lun is available by the system,
+ * and pointer to the rport data.
+ *
+ * Return codes:
+ * NULL - Error
+ * Pointer to lpfc_device_data - Success
+ **/
+struct lpfc_device_data*
+lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
+ struct lpfc_name *target_wwpn, uint64_t lun,
+ bool atomic_create)
+{
+
+ struct lpfc_device_data *lun_info;
+ int memory_flags;
+
+ if (unlikely(!phba) || !vport_wwpn || !target_wwpn ||
+ !(phba->cfg_EnableXLane))
+ return NULL;
+
+ /* Attempt to create the device data to contain lun info */
+
+ if (atomic_create)
+ memory_flags = GFP_ATOMIC;
+ else
+ memory_flags = GFP_KERNEL;
+ lun_info = mempool_alloc(phba->device_data_mem_pool, memory_flags);
+ if (!lun_info)
+ return NULL;
+ INIT_LIST_HEAD(&lun_info->listentry);
+ lun_info->rport_data = NULL;
+ memcpy(&lun_info->device_id.vport_wwpn, vport_wwpn,
+ sizeof(struct lpfc_name));
+ memcpy(&lun_info->device_id.target_wwpn, target_wwpn,
+ sizeof(struct lpfc_name));
+ lun_info->device_id.lun = lun;
+ lun_info->oas_enabled = false;
+ lun_info->available = false;
+ return lun_info;
+}
+
+/**
+ * lpfc_delete_device_data - frees a device data structure for OAS
+ * @pha: Pointer to host bus adapter structure.
+ * @lun_info: Pointer to device data structure to free.
+ *
+ * This routine frees the previously allocated device data structure passed.
+ *
+ **/
+void
+lpfc_delete_device_data(struct lpfc_hba *phba,
+ struct lpfc_device_data *lun_info)
+{
+
+ if (unlikely(!phba) || !lun_info ||
+ !(phba->cfg_EnableXLane))
+ return;
+
+ if (!list_empty(&lun_info->listentry))
+ list_del(&lun_info->listentry);
+ mempool_free(lun_info, phba->device_data_mem_pool);
+ return;
+}
+
+/**
+ * __lpfc_get_device_data - returns the device data for the specified lun
+ * @pha: Pointer to host bus adapter structure.
+ * @list: Point to list to search.
+ * @vport_wwpn: Pointer to vport's wwpn information
+ * @target_wwpn: Pointer to target's wwpn information
+ * @lun: Lun on target
+ *
+ * This routine searches the list passed for the specified lun's device data.
+ * This function does not hold locks, it is the responsibility of the caller
+ * to ensure the proper lock is held before calling the function.
+ *
+ * Return codes:
+ * NULL - Error
+ * Pointer to lpfc_device_data - Success
+ **/
+struct lpfc_device_data*
+__lpfc_get_device_data(struct lpfc_hba *phba, struct list_head *list,
+ struct lpfc_name *vport_wwpn,
+ struct lpfc_name *target_wwpn, uint64_t lun)
+{
+
+ struct lpfc_device_data *lun_info;
+
+ if (unlikely(!phba) || !list || !vport_wwpn || !target_wwpn ||
+ !phba->cfg_EnableXLane)
+ return NULL;
+
+ /* Check to see if the lun is already enabled for OAS. */
+
+ list_for_each_entry(lun_info, list, listentry) {
+ if ((memcmp(&lun_info->device_id.vport_wwpn, vport_wwpn,
+ sizeof(struct lpfc_name)) == 0) &&
+ (memcmp(&lun_info->device_id.target_wwpn, target_wwpn,
+ sizeof(struct lpfc_name)) == 0) &&
+ (lun_info->device_id.lun == lun))
+ return lun_info;
+ }
+
+ return NULL;
+}
+
+/**
+ * lpfc_find_next_oas_lun - searches for the next oas lun
+ * @pha: Pointer to host bus adapter structure.
+ * @vport_wwpn: Pointer to vport's wwpn information
+ * @target_wwpn: Pointer to target's wwpn information
+ * @starting_lun: Pointer to the lun to start searching for
+ * @found_vport_wwpn: Pointer to the found lun's vport wwpn information
+ * @found_target_wwpn: Pointer to the found lun's target wwpn information
+ * @found_lun: Pointer to the found lun.
+ * @found_lun_status: Pointer to status of the found lun.
+ *
+ * This routine searches the luns list for the specified lun
+ * or the first lun for the vport/target. If the vport wwpn contains
+ * a zero value then a specific vport is not specified. In this case
+ * any vport which contains the lun will be considered a match. If the
+ * target wwpn contains a zero value then a specific target is not specified.
+ * In this case any target which contains the lun will be considered a
+ * match. If the lun is found, the lun, vport wwpn, target wwpn and lun status
+ * are returned. The function will also return the next lun if available.
+ * If the next lun is not found, starting_lun parameter will be set to
+ * NO_MORE_OAS_LUN.
+ *
+ * Return codes:
+ * non-0 - Error
+ * 0 - Success
+ **/
+bool
+lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
+ struct lpfc_name *target_wwpn, uint64_t *starting_lun,
+ struct lpfc_name *found_vport_wwpn,
+ struct lpfc_name *found_target_wwpn,
+ uint64_t *found_lun,
+ uint32_t *found_lun_status)
+{
+
+ unsigned long flags;
+ struct lpfc_device_data *lun_info;
+ struct lpfc_device_id *device_id;
+ uint64_t lun;
+ bool found = false;
+
+ if (unlikely(!phba) || !vport_wwpn || !target_wwpn ||
+ !starting_lun || !found_vport_wwpn ||
+ !found_target_wwpn || !found_lun || !found_lun_status ||
+ (*starting_lun == NO_MORE_OAS_LUN) ||
+ !phba->cfg_EnableXLane)
+ return false;
+
+ lun = *starting_lun;
+ *found_lun = NO_MORE_OAS_LUN;
+ *starting_lun = NO_MORE_OAS_LUN;
+
+ /* Search for lun or the lun closet in value */
+
+ spin_lock_irqsave(&phba->devicelock, flags);
+ list_for_each_entry(lun_info, &phba->luns, listentry) {
+ if (((wwn_to_u64(vport_wwpn->u.wwn) == 0) ||
+ (memcmp(&lun_info->device_id.vport_wwpn, vport_wwpn,
+ sizeof(struct lpfc_name)) == 0)) &&
+ ((wwn_to_u64(target_wwpn->u.wwn) == 0) ||
+ (memcmp(&lun_info->device_id.target_wwpn, target_wwpn,
+ sizeof(struct lpfc_name)) == 0)) &&
+ (lun_info->oas_enabled)) {
+ device_id = &lun_info->device_id;
+ if ((!found) &&
+ ((lun == FIND_FIRST_OAS_LUN) ||
+ (device_id->lun == lun))) {
+ *found_lun = device_id->lun;
+ memcpy(found_vport_wwpn,
+ &device_id->vport_wwpn,
+ sizeof(struct lpfc_name));
+ memcpy(found_target_wwpn,
+ &device_id->target_wwpn,
+ sizeof(struct lpfc_name));
+ if (lun_info->available)
+ *found_lun_status =
+ OAS_LUN_STATUS_EXISTS;
+ else
+ *found_lun_status = 0;
+ if (phba->cfg_oas_flags & OAS_FIND_ANY_VPORT)
+ memset(vport_wwpn, 0x0,
+ sizeof(struct lpfc_name));
+ if (phba->cfg_oas_flags & OAS_FIND_ANY_TARGET)
+ memset(target_wwpn, 0x0,
+ sizeof(struct lpfc_name));
+ found = true;
+ } else if (found) {
+ *starting_lun = device_id->lun;
+ memcpy(vport_wwpn, &device_id->vport_wwpn,
+ sizeof(struct lpfc_name));
+ memcpy(target_wwpn, &device_id->target_wwpn,
+ sizeof(struct lpfc_name));
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ return found;
+}
+
+/**
+ * lpfc_enable_oas_lun - enables a lun for OAS operations
+ * @pha: Pointer to host bus adapter structure.
+ * @vport_wwpn: Pointer to vport's wwpn information
+ * @target_wwpn: Pointer to target's wwpn information
+ * @lun: Lun
+ *
+ * This routine enables a lun for oas operations. The routines does so by
+ * doing the following :
+ *
+ * 1) Checks to see if the device data for the lun has been created.
+ * 2) If found, sets the OAS enabled flag if not set and returns.
+ * 3) Otherwise, creates a device data structure.
+ * 4) If successfully created, indicates the device data is for an OAS lun,
+ * indicates the lun is not available and add to the list of luns.
+ *
+ * Return codes:
+ * false - Error
+ * true - Success
+ **/
+bool
+lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
+ struct lpfc_name *target_wwpn, uint64_t lun)
+{
+
+ struct lpfc_device_data *lun_info;
+ unsigned long flags;
+
+ if (unlikely(!phba) || !vport_wwpn || !target_wwpn ||
+ !phba->cfg_EnableXLane)
+ return false;
+
+ spin_lock_irqsave(&phba->devicelock, flags);
+
+ /* Check to see if the device data for the lun has been created */
+ lun_info = __lpfc_get_device_data(phba, &phba->luns, vport_wwpn,
+ target_wwpn, lun);
+ if (lun_info) {
+ if (!lun_info->oas_enabled)
+ lun_info->oas_enabled = true;
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ return true;
+ }
+
+ /* Create an lun info structure and add to list of luns */
+ lun_info = lpfc_create_device_data(phba, vport_wwpn, target_wwpn, lun,
+ false);
+ if (lun_info) {
+ lun_info->oas_enabled = true;
+ lun_info->available = false;
+ list_add_tail(&lun_info->listentry, &phba->luns);
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ return true;
+ }
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ return false;
+}
+
+/**
+ * lpfc_disable_oas_lun - disables a lun for OAS operations
+ * @pha: Pointer to host bus adapter structure.
+ * @vport_wwpn: Pointer to vport's wwpn information
+ * @target_wwpn: Pointer to target's wwpn information
+ * @lun: Lun
+ *
+ * This routine disables a lun for oas operations. The routines does so by
+ * doing the following :
+ *
+ * 1) Checks to see if the device data for the lun is created.
+ * 2) If present, clears the flag indicating this lun is for OAS.
+ * 3) If the lun is not available by the system, the device data is
+ * freed.
+ *
+ * Return codes:
+ * false - Error
+ * true - Success
+ **/
+bool
+lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
+ struct lpfc_name *target_wwpn, uint64_t lun)
+{
+
+ struct lpfc_device_data *lun_info;
+ unsigned long flags;
+
+ if (unlikely(!phba) || !vport_wwpn || !target_wwpn ||
+ !phba->cfg_EnableXLane)
+ return false;
+
+ spin_lock_irqsave(&phba->devicelock, flags);
+
+ /* Check to see if the lun is available. */
+ lun_info = __lpfc_get_device_data(phba,
+ &phba->luns, vport_wwpn,
+ target_wwpn, lun);
+ if (lun_info) {
+ lun_info->oas_enabled = false;
+ if (!lun_info->available)
+ lpfc_delete_device_data(phba, lun_info);
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ return true;
+ }
+
+ spin_unlock_irqrestore(&phba->devicelock, flags);
+ return false;
+}
struct scsi_host_template lpfc_template = {
.module = THIS_MODULE,
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index 852ff7def493..0120bfccf50b 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -41,6 +41,20 @@ struct lpfc_rport_data {
struct lpfc_nodelist *pnode; /* Pointer to the node structure. */
};
+struct lpfc_device_id {
+ struct lpfc_name vport_wwpn;
+ struct lpfc_name target_wwpn;
+ uint64_t lun;
+};
+
+struct lpfc_device_data {
+ struct list_head listentry;
+ struct lpfc_rport_data *rport_data;
+ struct lpfc_device_id device_id;
+ bool oas_enabled;
+ bool available;
+};
+
struct fcp_rsp {
uint32_t rspRsvd1; /* FC Word 0, byte 0:3 */
uint32_t rspRsvd2; /* FC Word 1, byte 0:3 */
@@ -166,3 +180,7 @@ struct lpfc_scsi_buf {
#define LPFC_SCSI_DMA_EXT_SIZE 264
#define LPFC_BPL_SIZE 1024
#define MDAC_DIRECT_CMD 0x22
+
+#define FIND_FIRST_OAS_LUN 0
+#define NO_MORE_OAS_LUN -1
+#define NOT_OAS_ENABLED_LUN NO_MORE_OAS_LUN
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 8f580fda443f..6bb51f8e3c1b 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -635,7 +635,7 @@ lpfc_clr_rrq_active(struct lpfc_hba *phba,
if (!ndlp)
goto out;
- if (test_and_clear_bit(xritag, ndlp->active_rrqs.xri_bitmap)) {
+ if (test_and_clear_bit(xritag, ndlp->active_rrqs_xri_bitmap)) {
rrq->send_rrq = 0;
rrq->xritag = 0;
rrq->rrq_stop_time = 0;
@@ -678,7 +678,8 @@ lpfc_handle_rrq_active(struct lpfc_hba *phba)
next_time = rrq->rrq_stop_time;
}
spin_unlock_irqrestore(&phba->hbalock, iflags);
- if (!list_empty(&phba->active_rrq_list))
+ if ((!list_empty(&phba->active_rrq_list)) &&
+ (!(phba->pport->load_flag & FC_UNLOADING)))
mod_timer(&phba->rrq_tmr, next_time);
list_for_each_entry_safe(rrq, nextrrq, &send_rrq, list) {
list_del(&rrq->list);
@@ -792,7 +793,9 @@ lpfc_cleanup_wt_rrqs(struct lpfc_hba *phba)
list_del(&rrq->list);
lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
}
- if (!list_empty(&phba->active_rrq_list))
+ if ((!list_empty(&phba->active_rrq_list)) &&
+ (!(phba->pport->load_flag & FC_UNLOADING)))
+
mod_timer(&phba->rrq_tmr, next_time);
}
@@ -813,7 +816,9 @@ lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
{
if (!ndlp)
return 0;
- if (test_bit(xritag, ndlp->active_rrqs.xri_bitmap))
+ if (!ndlp->active_rrqs_xri_bitmap)
+ return 0;
+ if (test_bit(xritag, ndlp->active_rrqs_xri_bitmap))
return 1;
else
return 0;
@@ -863,7 +868,10 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING))
goto out;
- if (test_and_set_bit(xritag, ndlp->active_rrqs.xri_bitmap))
+ if (!ndlp->active_rrqs_xri_bitmap)
+ goto out;
+
+ if (test_and_set_bit(xritag, ndlp->active_rrqs_xri_bitmap))
goto out;
spin_unlock_irqrestore(&phba->hbalock, iflags);
@@ -1318,7 +1326,8 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
(piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
- (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
+ (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN) &&
+ (!(piocb->vport->load_flag & FC_UNLOADING))) {
if (!piocb->vport)
BUG();
else
@@ -4971,12 +4980,19 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
LPFC_QUEUE_REARM);
} while (++fcp_eqidx < phba->cfg_fcp_io_channel);
}
+
+ if (phba->cfg_EnableXLane)
+ lpfc_sli4_cq_release(phba->sli4_hba.oas_cq, LPFC_QUEUE_REARM);
+
if (phba->sli4_hba.hba_eq) {
for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_io_channel;
fcp_eqidx++)
lpfc_sli4_eq_release(phba->sli4_hba.hba_eq[fcp_eqidx],
LPFC_QUEUE_REARM);
}
+
+ if (phba->cfg_fof)
+ lpfc_sli4_eq_release(phba->sli4_hba.fof_eq, LPFC_QUEUE_REARM);
}
/**
@@ -8032,7 +8048,8 @@ lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba)
struct lpfc_vector_map_info *cpup;
int chann, cpu;
- if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_CPU) {
+ if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_CPU
+ && phba->cfg_fcp_io_channel > 1) {
cpu = smp_processor_id();
if (cpu < phba->sli4_hba.num_present_cpu) {
cpup = phba->sli4_hba.cpu_map;
@@ -8250,6 +8267,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0);
bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU);
bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1);
+ if (iocbq->iocb_flag & LPFC_IO_OAS) {
+ bf_set(wqe_oas, &wqe->fcp_iwrite.wqe_com, 1);
+ if (phba->cfg_XLanePriority) {
+ bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1);
+ bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com,
+ (phba->cfg_XLanePriority << 1));
+ }
+ }
break;
case CMD_FCP_IREAD64_CR:
/* word3 iocb=iotag wqe=payload_offset_len */
@@ -8271,6 +8296,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0);
bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU);
bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1);
+ if (iocbq->iocb_flag & LPFC_IO_OAS) {
+ bf_set(wqe_oas, &wqe->fcp_iread.wqe_com, 1);
+ if (phba->cfg_XLanePriority) {
+ bf_set(wqe_ccpe, &wqe->fcp_iread.wqe_com, 1);
+ bf_set(wqe_ccp, &wqe->fcp_iread.wqe_com,
+ (phba->cfg_XLanePriority << 1));
+ }
+ }
break;
case CMD_FCP_ICMND64_CR:
/* word3 iocb=iotag wqe=payload_offset_len */
@@ -8291,6 +8324,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0);
bf_set(wqe_erp, &wqe->fcp_icmd.wqe_com,
iocbq->iocb.ulpFCP2Rcvy);
+ if (iocbq->iocb_flag & LPFC_IO_OAS) {
+ bf_set(wqe_oas, &wqe->fcp_icmd.wqe_com, 1);
+ if (phba->cfg_XLanePriority) {
+ bf_set(wqe_ccpe, &wqe->fcp_icmd.wqe_com, 1);
+ bf_set(wqe_ccp, &wqe->fcp_icmd.wqe_com,
+ (phba->cfg_XLanePriority << 1));
+ }
+ }
break;
case CMD_GEN_REQUEST64_CR:
/* For this command calculate the xmit length of the
@@ -8523,6 +8564,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
{
struct lpfc_sglq *sglq;
union lpfc_wqe wqe;
+ struct lpfc_queue *wq;
struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
if (piocb->sli4_xritag == NO_XRI) {
@@ -8575,11 +8617,14 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
return IOCB_ERROR;
if ((piocb->iocb_flag & LPFC_IO_FCP) ||
- (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) {
- if (unlikely(!phba->sli4_hba.fcp_wq))
- return IOCB_ERROR;
- if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx],
- &wqe))
+ (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) {
+ if (!phba->cfg_EnableXLane || (!(piocb->iocb_flag &
+ LPFC_IO_OAS))) {
+ wq = phba->sli4_hba.fcp_wq[piocb->fcp_wqidx];
+ } else {
+ wq = phba->sli4_hba.oas_wq;
+ }
+ if (lpfc_sli4_wq_put(wq, &wqe))
return IOCB_ERROR;
} else {
if (unlikely(!phba->sli4_hba.els_wq))
@@ -8669,12 +8714,20 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
if (phba->sli_rev == LPFC_SLI_REV4) {
if (piocb->iocb_flag & LPFC_IO_FCP) {
- if (unlikely(!phba->sli4_hba.fcp_wq))
- return IOCB_ERROR;
- idx = lpfc_sli4_scmd_to_wqidx_distr(phba);
- piocb->fcp_wqidx = idx;
- ring_number = MAX_SLI3_CONFIGURED_RINGS + idx;
-
+ if (!phba->cfg_EnableXLane || (!(piocb->iocb_flag &
+ LPFC_IO_OAS))) {
+ if (unlikely(!phba->sli4_hba.fcp_wq))
+ return IOCB_ERROR;
+ idx = lpfc_sli4_scmd_to_wqidx_distr(phba);
+ piocb->fcp_wqidx = idx;
+ ring_number = MAX_SLI3_CONFIGURED_RINGS + idx;
+ } else {
+ if (unlikely(!phba->sli4_hba.oas_wq))
+ return IOCB_ERROR;
+ idx = 0;
+ piocb->fcp_wqidx = 0;
+ ring_number = LPFC_FCP_OAS_RING;
+ }
pring = &phba->sli.ring[ring_number];
spin_lock_irqsave(&pring->ring_lock, iflags);
rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb,
@@ -12132,6 +12185,175 @@ lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq)
lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM);
}
+
+/**
+ * lpfc_sli4_fof_handle_eqe - Process a Flash Optimized Fabric event queue
+ * entry
+ * @phba: Pointer to HBA context object.
+ * @eqe: Pointer to fast-path event queue entry.
+ *
+ * This routine process a event queue entry from the Flash Optimized Fabric
+ * event queue. It will check the MajorCode and MinorCode to determine this
+ * is for a completion event on a completion queue, if not, an error shall be
+ * logged and just return. Otherwise, it will get to the corresponding
+ * completion queue and process all the entries on the completion queue, rearm
+ * the completion queue, and then return.
+ **/
+static void
+lpfc_sli4_fof_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)
+{
+ struct lpfc_queue *cq;
+ struct lpfc_cqe *cqe;
+ bool workposted = false;
+ uint16_t cqid;
+ int ecount = 0;
+
+ if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "9147 Not a valid completion "
+ "event: majorcode=x%x, minorcode=x%x\n",
+ bf_get_le32(lpfc_eqe_major_code, eqe),
+ bf_get_le32(lpfc_eqe_minor_code, eqe));
+ return;
+ }
+
+ /* Get the reference to the corresponding CQ */
+ cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);
+
+ /* Next check for OAS */
+ cq = phba->sli4_hba.oas_cq;
+ if (unlikely(!cq)) {
+ if (phba->sli.sli_flag & LPFC_SLI_ACTIVE)
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "9148 OAS completion queue "
+ "does not exist\n");
+ return;
+ }
+
+ if (unlikely(cqid != cq->queue_id)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "9149 Miss-matched fast-path compl "
+ "queue id: eqcqid=%d, fcpcqid=%d\n",
+ cqid, cq->queue_id);
+ return;
+ }
+
+ /* Process all the entries to the OAS CQ */
+ while ((cqe = lpfc_sli4_cq_get(cq))) {
+ workposted |= lpfc_sli4_fp_handle_wcqe(phba, cq, cqe);
+ if (!(++ecount % cq->entry_repost))
+ lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM);
+ }
+
+ /* Track the max number of CQEs processed in 1 EQ */
+ if (ecount > cq->CQ_max_cqe)
+ cq->CQ_max_cqe = ecount;
+
+ /* Catch the no cq entry condition */
+ if (unlikely(ecount == 0))
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "9153 No entry from fast-path completion "
+ "queue fcpcqid=%d\n", cq->queue_id);
+
+ /* In any case, flash and re-arm the CQ */
+ lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM);
+
+ /* wake up worker thread if there are works to be done */
+ if (workposted)
+ lpfc_worker_wake_up(phba);
+}
+
+/**
+ * lpfc_sli4_fof_intr_handler - HBA interrupt handler to SLI-4 device
+ * @irq: Interrupt number.
+ * @dev_id: The device context pointer.
+ *
+ * This function is directly called from the PCI layer as an interrupt
+ * service routine when device with SLI-4 interface spec is enabled with
+ * MSI-X multi-message interrupt mode and there is a Flash Optimized Fabric
+ * IOCB ring event in the HBA. However, when the device is enabled with either
+ * MSI or Pin-IRQ interrupt mode, this function is called as part of the
+ * device-level interrupt handler. When the PCI slot is in error recovery
+ * or the HBA is undergoing initialization, the interrupt handler will not
+ * process the interrupt. The Flash Optimized Fabric ring event are handled in
+ * the intrrupt context. This function is called without any lock held.
+ * It gets the hbalock to access and update SLI data structures. Note that,
+ * the EQ to CQ are one-to-one map such that the EQ index is
+ * equal to that of CQ index.
+ *
+ * This function returns IRQ_HANDLED when interrupt is handled else it
+ * returns IRQ_NONE.
+ **/
+irqreturn_t
+lpfc_sli4_fof_intr_handler(int irq, void *dev_id)
+{
+ struct lpfc_hba *phba;
+ struct lpfc_fcp_eq_hdl *fcp_eq_hdl;
+ struct lpfc_queue *eq;
+ struct lpfc_eqe *eqe;
+ unsigned long iflag;
+ int ecount = 0;
+ uint32_t eqidx;
+
+ /* Get the driver's phba structure from the dev_id */
+ fcp_eq_hdl = (struct lpfc_fcp_eq_hdl *)dev_id;
+ phba = fcp_eq_hdl->phba;
+ eqidx = fcp_eq_hdl->idx;
+
+ if (unlikely(!phba))
+ return IRQ_NONE;
+
+ /* Get to the EQ struct associated with this vector */
+ eq = phba->sli4_hba.fof_eq;
+ if (unlikely(!eq))
+ return IRQ_NONE;
+
+ /* Check device state for handling interrupt */
+ if (unlikely(lpfc_intr_state_check(phba))) {
+ eq->EQ_badstate++;
+ /* Check again for link_state with lock held */
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ if (phba->link_state < LPFC_LINK_DOWN)
+ /* Flush, clear interrupt, and rearm the EQ */
+ lpfc_sli4_eq_flush(phba, eq);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ return IRQ_NONE;
+ }
+
+ /*
+ * Process all the event on FCP fast-path EQ
+ */
+ while ((eqe = lpfc_sli4_eq_get(eq))) {
+ lpfc_sli4_fof_handle_eqe(phba, eqe);
+ if (!(++ecount % eq->entry_repost))
+ lpfc_sli4_eq_release(eq, LPFC_QUEUE_NOARM);
+ eq->EQ_processed++;
+ }
+
+ /* Track the max number of EQEs processed in 1 intr */
+ if (ecount > eq->EQ_max_eqe)
+ eq->EQ_max_eqe = ecount;
+
+
+ if (unlikely(ecount == 0)) {
+ eq->EQ_no_entry++;
+
+ if (phba->intr_type == MSIX)
+ /* MSI-X treated interrupt served as no EQ share INT */
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+ "9145 MSI-X interrupt with no EQE\n");
+ else {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "9146 ISR interrupt with no EQE\n");
+ /* Non MSI-X treated on interrupt as EQ share INT */
+ return IRQ_NONE;
+ }
+ }
+ /* Always clear and re-arm the fast-path EQ */
+ lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM);
+ return IRQ_HANDLED;
+}
+
/**
* lpfc_sli4_hba_intr_handler - HBA interrupt handler to SLI-4 device
* @irq: Interrupt number.
@@ -12287,6 +12509,13 @@ lpfc_sli4_intr_handler(int irq, void *dev_id)
hba_handled |= true;
}
+ if (phba->cfg_fof) {
+ hba_irq_rc = lpfc_sli4_fof_intr_handler(irq,
+ &phba->sli4_hba.fcp_eq_hdl[0]);
+ if (hba_irq_rc == IRQ_HANDLED)
+ hba_handled |= true;
+ }
+
return (hba_handled == true) ? IRQ_HANDLED : IRQ_NONE;
} /* lpfc_sli4_intr_handler */
@@ -16544,7 +16773,7 @@ lpfc_drain_txq(struct lpfc_hba *phba)
{
LIST_HEAD(completions);
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
- struct lpfc_iocbq *piocbq = 0;
+ struct lpfc_iocbq *piocbq = NULL;
unsigned long iflags = 0;
char *fail_msg = NULL;
struct lpfc_sglq *sglq;
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 6b0f2478706e..6f04080f4ea8 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -78,6 +78,8 @@ struct lpfc_iocbq {
#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */
#define LPFC_FIP_ELS_ID_SHIFT 14
+#define LPFC_IO_OAS 0x10000 /* OAS FCP IO */
+
uint32_t drvrTimeout; /* driver timeout in seconds */
uint32_t fcp_wqidx; /* index to FCP work queue */
struct lpfc_vport *vport;/* virtual port pointer */
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 298c8cd1a89d..9b8cda866176 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -39,6 +39,10 @@
#define LPFC_FCP_IO_CHAN_MIN 1
#define LPFC_FCP_IO_CHAN_MAX 16
+/* Number of channels used for Flash Optimized Fabric (FOF) operations */
+
+#define LPFC_FOF_IO_CHAN_NUM 1
+
/*
* Provide the default FCF Record attributes used by the driver
* when nonFIP mode is configured and there is no other default
@@ -399,6 +403,7 @@ struct lpfc_pc_sli4_params {
uint32_t if_page_sz;
uint32_t rq_db_window;
uint32_t loopbk_scope;
+ uint32_t oas_supported;
uint32_t eq_pages_max;
uint32_t eqe_size;
uint32_t cq_pages_max;
@@ -439,6 +444,8 @@ struct lpfc_sli4_lnk_info {
uint8_t lnk_no;
};
+#define LPFC_SLI4_HANDLER_CNT (LPFC_FCP_IO_CHAN_MAX+ \
+ LPFC_FOF_IO_CHAN_NUM)
#define LPFC_SLI4_HANDLER_NAME_SZ 16
/* Used for IRQ vector to CPU mapping */
@@ -507,7 +514,7 @@ struct lpfc_sli4_hba {
struct lpfc_register sli_intf;
struct lpfc_pc_sli4_params pc_sli4_params;
struct msix_entry *msix_entries;
- uint8_t handler_name[LPFC_FCP_IO_CHAN_MAX][LPFC_SLI4_HANDLER_NAME_SZ];
+ uint8_t handler_name[LPFC_SLI4_HANDLER_CNT][LPFC_SLI4_HANDLER_NAME_SZ];
struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */
/* Pointers to the constructed SLI4 queues */
@@ -527,6 +534,17 @@ struct lpfc_sli4_hba {
uint32_t ulp0_mode; /* ULP0 protocol mode */
uint32_t ulp1_mode; /* ULP1 protocol mode */
+ struct lpfc_queue *fof_eq; /* Flash Optimized Fabric Event queue */
+
+ /* Optimized Access Storage specific queues/structures */
+
+ struct lpfc_queue *oas_cq; /* OAS completion queue */
+ struct lpfc_queue *oas_wq; /* OAS Work queue */
+ struct lpfc_sli_ring *oas_ring;
+ uint64_t oas_next_lun;
+ uint8_t oas_next_tgt_wwpn[8];
+ uint8_t oas_next_vpt_wwpn[8];
+
/* Setup information for various queue parameters */
int eq_esize;
int eq_ecount;
@@ -589,6 +607,7 @@ struct lpfc_sli4_hba {
struct lpfc_vector_map_info *cpu_map;
uint16_t num_online_cpu;
uint16_t num_present_cpu;
+ uint16_t curr_disp_cpu;
};
enum lpfc_sge_type {
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index e3094c4e143b..e32cbec70324 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.43"
+#define LPFC_DRIVER_VERSION "8.3.45"
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 816db12ef5d5..b7770516f4c2 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -531,13 +531,6 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy)
int target = 0;
int ldrv_num = 0; /* logical drive number */
-
- /*
- * filter the internal and ioctl commands
- */
- if((cmd->cmnd[0] == MEGA_INTERNAL_CMD))
- return (scb_t *)cmd->host_scribble;
-
/*
* We know what channels our logical drives are on - mega_find_card()
*/
@@ -1439,19 +1432,22 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
cmdid = completed[i];
- if( cmdid == CMDID_INT_CMDS ) { /* internal command */
+ /*
+ * Only free SCBs for the commands coming down from the
+ * mid-layer, not for which were issued internally
+ *
+ * For internal command, restore the status returned by the
+ * firmware so that user can interpret it.
+ */
+ if (cmdid == CMDID_INT_CMDS) {
scb = &adapter->int_scb;
- cmd = scb->cmd;
- mbox = (mbox_t *)scb->raw_mbox;
- /*
- * Internal command interface do not fire the extended
- * passthru or 64-bit passthru
- */
- pthru = scb->pthru;
+ list_del_init(&scb->list);
+ scb->state = SCB_FREE;
- }
- else {
+ adapter->int_status = status;
+ complete(&adapter->int_waitq);
+ } else {
scb = &adapter->scb_list[cmdid];
/*
@@ -1640,25 +1636,7 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
cmd->result |= (DID_BAD_TARGET << 16)|status;
}
- /*
- * Only free SCBs for the commands coming down from the
- * mid-layer, not for which were issued internally
- *
- * For internal command, restore the status returned by the
- * firmware so that user can interpret it.
- */
- if( cmdid == CMDID_INT_CMDS ) { /* internal command */
- cmd->result = status;
-
- /*
- * Remove the internal command from the pending list
- */
- list_del_init(&scb->list);
- scb->state = SCB_FREE;
- }
- else {
- mega_free_scb(adapter, scb);
- }
+ mega_free_scb(adapter, scb);
/* Add Scsi_Command to end of completed queue */
list_add_tail(SCSI_LIST(cmd), &adapter->completed_list);
@@ -4133,23 +4111,15 @@ mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt,
* The last argument is the address of the passthru structure if the command
* to be fired is a passthru command
*
- * lockscope specifies whether the caller has already acquired the lock. Of
- * course, the caller must know which lock we are talking about.
- *
* Note: parameter 'pthru' is null for non-passthru commands.
*/
static int
mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
{
- Scsi_Cmnd *scmd;
- struct scsi_device *sdev;
+ unsigned long flags;
scb_t *scb;
int rval;
- scmd = scsi_allocate_command(GFP_KERNEL);
- if (!scmd)
- return -ENOMEM;
-
/*
* The internal commands share one command id and hence are
* serialized. This is so because we want to reserve maximum number of
@@ -4160,73 +4130,45 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
scb = &adapter->int_scb;
memset(scb, 0, sizeof(scb_t));
- sdev = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
- scmd->device = sdev;
-
- memset(adapter->int_cdb, 0, sizeof(adapter->int_cdb));
- scmd->cmnd = adapter->int_cdb;
- scmd->device->host = adapter->host;
- scmd->host_scribble = (void *)scb;
- scmd->cmnd[0] = MEGA_INTERNAL_CMD;
-
- scb->state |= SCB_ACTIVE;
- scb->cmd = scmd;
+ scb->idx = CMDID_INT_CMDS;
+ scb->state |= SCB_ACTIVE | SCB_PENDQ;
memcpy(scb->raw_mbox, mc, sizeof(megacmd_t));
/*
* Is it a passthru command
*/
- if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) {
-
+ if (mc->cmd == MEGA_MBOXCMD_PASSTHRU)
scb->pthru = pthru;
- }
-
- scb->idx = CMDID_INT_CMDS;
- megaraid_queue_lck(scmd, mega_internal_done);
+ spin_lock_irqsave(&adapter->lock, flags);
+ list_add_tail(&scb->list, &adapter->pending_list);
+ /*
+ * Check if the HBA is in quiescent state, e.g., during a
+ * delete logical drive opertion. If it is, don't run
+ * the pending_list.
+ */
+ if (atomic_read(&adapter->quiescent) == 0)
+ mega_runpendq(adapter);
+ spin_unlock_irqrestore(&adapter->lock, flags);
wait_for_completion(&adapter->int_waitq);
- rval = scmd->result;
- mc->status = scmd->result;
- kfree(sdev);
+ mc->status = rval = adapter->int_status;
/*
* Print a debug message for all failed commands. Applications can use
* this information.
*/
- if( scmd->result && trace_level ) {
+ if (rval && trace_level) {
printk("megaraid: cmd [%x, %x, %x] status:[%x]\n",
- mc->cmd, mc->opcode, mc->subopcode, scmd->result);
+ mc->cmd, mc->opcode, mc->subopcode, rval);
}
mutex_unlock(&adapter->int_mtx);
-
- scsi_free_command(GFP_KERNEL, scmd);
-
return rval;
}
-
-/**
- * mega_internal_done()
- * @scmd - internal scsi command
- *
- * Callback routine for internal commands.
- */
-static void
-mega_internal_done(Scsi_Cmnd *scmd)
-{
- adapter_t *adapter;
-
- adapter = (adapter_t *)scmd->device->host->hostdata;
-
- complete(&adapter->int_waitq);
-
-}
-
-
static struct scsi_host_template megaraid_template = {
.module = THIS_MODULE,
.name = "MegaRAID",
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index 4d0ce4e78dfd..508d65e5a518 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -853,10 +853,10 @@ typedef struct {
u8 sglen; /* f/w supported scatter-gather list length */
- unsigned char int_cdb[MAX_COMMAND_SIZE];
scb_t int_scb;
struct mutex int_mtx; /* To synchronize the internal
commands */
+ int int_status; /* status of internal cmd */
struct completion int_waitq; /* wait queue for internal
cmds */
@@ -1004,7 +1004,6 @@ static int mega_del_logdrv(adapter_t *, int);
static int mega_do_del_logdrv(adapter_t *, int);
static void mega_get_max_sgl(adapter_t *);
static int mega_internal_command(adapter_t *, megacmd_t *, mega_passthru *);
-static void mega_internal_done(Scsi_Cmnd *);
static int mega_support_cluster(adapter_t *);
#endif
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index dfffd0f37916..a70692779a16 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -486,6 +486,8 @@ mimd_to_kioc(mimd_t __user *umimd, mraid_mmadp_t *adp, uioc_t *kioc)
pthru32->dataxferaddr = kioc->buf_paddr;
if (kioc->data_dir & UIOC_WR) {
+ if (pthru32->dataxferlen > kioc->xferlen)
+ return -EINVAL;
if (copy_from_user(kioc->buf_vaddr, kioc->user_data,
pthru32->dataxferlen)) {
return (-EFAULT);
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 34452ea386ac..32166c2c7854 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -33,9 +33,9 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "06.700.06.00-rc1"
-#define MEGASAS_RELDATE "Aug. 31, 2013"
-#define MEGASAS_EXT_VERSION "Sat. Aug. 31 17:00:00 PDT 2013"
+#define MEGASAS_VERSION "06.803.01.00-rc1"
+#define MEGASAS_RELDATE "Mar. 10, 2014"
+#define MEGASAS_EXT_VERSION "Mon. Mar. 10 17:00:00 PDT 2014"
/*
* Device IDs
@@ -48,6 +48,7 @@
#define PCI_DEVICE_ID_LSI_SAS0073SKINNY 0x0073
#define PCI_DEVICE_ID_LSI_SAS0071SKINNY 0x0071
#define PCI_DEVICE_ID_LSI_FUSION 0x005b
+#define PCI_DEVICE_ID_LSI_PLASMA 0x002f
#define PCI_DEVICE_ID_LSI_INVADER 0x005d
#define PCI_DEVICE_ID_LSI_FURY 0x005f
@@ -559,7 +560,8 @@ struct megasas_ctrl_info {
u8 PCIE:1;
u8 iSCSI:1;
u8 SAS_3G:1;
- u8 reserved_0:4;
+ u8 SRIOV:1;
+ u8 reserved_0:3;
u8 reserved_1[6];
u8 port_count;
u64 port_addr[8];
@@ -839,7 +841,12 @@ struct megasas_ctrl_info {
struct { /*7A4h */
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved:11;
+ u32 reserved:5;
+ u32 activePassive:2;
+ u32 supportConfigAutoBalance:1;
+ u32 mpio:1;
+ u32 supportDataLDonSSCArray:1;
+ u32 supportPointInTimeProgress:1;
u32 supportUnevenSpans:1;
u32 dedicatedHotSparesLimited:1;
u32 headlessMode:1;
@@ -886,7 +893,12 @@ struct megasas_ctrl_info {
u32 supportUnevenSpans:1;
- u32 reserved:11;
+ u32 supportPointInTimeProgress:1;
+ u32 supportDataLDonSSCArray:1;
+ u32 mpio:1;
+ u32 supportConfigAutoBalance:1;
+ u32 activePassive:2;
+ u32 reserved:5;
#endif
} adapterOperations2;
@@ -914,8 +926,14 @@ struct megasas_ctrl_info {
} cluster;
char clusterId[16]; /*7D4h */
+ struct {
+ u8 maxVFsSupported; /*0x7E4*/
+ u8 numVFsEnabled; /*0x7E5*/
+ u8 requestorId; /*0x7E6 0:PF, 1:VF1, 2:VF2*/
+ u8 reserved; /*0x7E7*/
+ } iov;
- u8 pad[0x800-0x7E4]; /*7E4 */
+ u8 pad[0x800-0x7E8]; /*0x7E8 pad to 2k */
} __packed;
/*
@@ -986,7 +1004,9 @@ struct megasas_ctrl_info {
#define MFI_OB_INTR_STATUS_MASK 0x00000002
#define MFI_POLL_TIMEOUT_SECS 60
-
+#define MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF (5 * HZ)
+#define MEGASAS_OCR_SETTLE_TIME_VF (1000 * 30)
+#define MEGASAS_ROUTINE_WAIT_TIME_VF 300
#define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000
#define MFI_REPLY_GEN2_MESSAGE_INTERRUPT 0x00000001
#define MFI_GEN2_ENABLE_INTERRUPT_MASK (0x00000001 | 0x00000004)
@@ -1347,9 +1367,15 @@ struct megasas_cmd;
union megasas_evt_class_locale {
struct {
+#ifndef __BIG_ENDIAN_BITFIELD
u16 locale;
u8 reserved;
s8 class;
+#else
+ s8 class;
+ u8 reserved;
+ u16 locale;
+#endif
} __attribute__ ((packed)) members;
u32 word;
@@ -1523,6 +1549,12 @@ struct megasas_instance {
dma_addr_t producer_h;
u32 *consumer;
dma_addr_t consumer_h;
+ struct MR_LD_VF_AFFILIATION *vf_affiliation;
+ dma_addr_t vf_affiliation_h;
+ struct MR_LD_VF_AFFILIATION_111 *vf_affiliation_111;
+ dma_addr_t vf_affiliation_111_h;
+ struct MR_CTRL_HB_HOST_MEM *hb_host_mem;
+ dma_addr_t hb_host_mem_h;
u32 *reply_queue;
dma_addr_t reply_queue_h;
@@ -1598,10 +1630,73 @@ struct megasas_instance {
unsigned long bar;
long reset_flags;
struct mutex reset_mutex;
+ struct timer_list sriov_heartbeat_timer;
+ char skip_heartbeat_timer_del;
+ u8 requestorId;
+ u64 initiator_sas_address;
+ u64 ld_sas_address[64];
+ char PlasmaFW111;
+ char mpio;
int throttlequeuedepth;
u8 mask_interrupts;
u8 is_imr;
};
+struct MR_LD_VF_MAP {
+ u32 size;
+ union MR_LD_REF ref;
+ u8 ldVfCount;
+ u8 reserved[6];
+ u8 policy[1];
+};
+
+struct MR_LD_VF_AFFILIATION {
+ u32 size;
+ u8 ldCount;
+ u8 vfCount;
+ u8 thisVf;
+ u8 reserved[9];
+ struct MR_LD_VF_MAP map[1];
+};
+
+/* Plasma 1.11 FW backward compatibility structures */
+#define IOV_111_OFFSET 0x7CE
+#define MAX_VIRTUAL_FUNCTIONS 8
+
+struct IOV_111 {
+ u8 maxVFsSupported;
+ u8 numVFsEnabled;
+ u8 requestorId;
+ u8 reserved[5];
+};
+
+struct MR_LD_VF_MAP_111 {
+ u8 targetId;
+ u8 reserved[3];
+ u8 policy[MAX_VIRTUAL_FUNCTIONS];
+};
+
+struct MR_LD_VF_AFFILIATION_111 {
+ u8 vdCount;
+ u8 vfCount;
+ u8 thisVf;
+ u8 reserved[5];
+ struct MR_LD_VF_MAP_111 map[MAX_LOGICAL_DRIVES];
+};
+
+struct MR_CTRL_HB_HOST_MEM {
+ struct {
+ u32 fwCounter; /* Firmware heart beat counter */
+ struct {
+ u32 debugmode:1; /* 1=Firmware is in debug mode.
+ Heart beat will not be updated. */
+ u32 reserved:31;
+ } debug;
+ u32 reserved_fw[6];
+ u32 driverCounter; /* Driver heart beat counter. 0x20 */
+ u32 reserved_driver[7];
+ } HB;
+ u8 pad[0x400-0x40];
+};
enum {
MEGASAS_HBA_OPERATIONAL = 0,
@@ -1609,6 +1704,7 @@ enum {
MEGASAS_ADPRESET_SM_FW_RESET_SUCCESS = 2,
MEGASAS_ADPRESET_SM_OPERATIONAL = 3,
MEGASAS_HW_CRITICAL_ERROR = 4,
+ MEGASAS_ADPRESET_SM_POLLING = 5,
MEGASAS_ADPRESET_INPROG_SIGN = 0xDEADDEAD,
};
@@ -1728,7 +1824,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
struct IO_REQUEST_INFO *io_info,
struct RAID_CONTEXT *pRAID_Context,
struct MR_FW_RAID_MAP_ALL *map, u8 **raidLUN);
-u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
+u8 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map);
u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map);
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 3b7ad10497fe..d84d02c2aad9 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -18,7 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* FILE: megaraid_sas_base.c
- * Version : 06.700.06.00-rc1
+ * Version : 06.803.01.00-rc1
*
* Authors: LSI Corporation
* Sreenivas Bagalkote
@@ -75,6 +75,10 @@ static unsigned int msix_vectors;
module_param(msix_vectors, int, S_IRUGO);
MODULE_PARM_DESC(msix_vectors, "MSI-X max vector count. Default: Set by FW");
+static int allow_vf_ioctls;
+module_param(allow_vf_ioctls, int, S_IRUGO);
+MODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0");
+
static int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH;
module_param(throttlequeuedepth, int, S_IRUGO);
MODULE_PARM_DESC(throttlequeuedepth,
@@ -122,6 +126,8 @@ static struct pci_device_id megasas_pci_table[] = {
/* xscale IOP */
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)},
/* Fusion */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_PLASMA)},
+ /* Plasma */
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INVADER)},
/* Invader */
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FURY)},
@@ -132,7 +138,7 @@ static struct pci_device_id megasas_pci_table[] = {
MODULE_DEVICE_TABLE(pci, megasas_pci_table);
static int megasas_mgmt_majorno;
-static struct megasas_mgmt_info megasas_mgmt_info;
+struct megasas_mgmt_info megasas_mgmt_info;
static struct fasync_struct *megasas_async_queue;
static DEFINE_MUTEX(megasas_async_queue_mutex);
@@ -171,10 +177,15 @@ 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);
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
+ int seconds);
void megasas_reset_reply_desc(struct megasas_instance *instance);
-int megasas_reset_fusion(struct Scsi_Host *shost);
+int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout);
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);
void
megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
@@ -224,6 +235,7 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
cmd->scmd = NULL;
cmd->frame_count = 0;
if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) &&
+ (instance->pdev->device != PCI_DEVICE_ID_LSI_PLASMA) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_FURY) &&
(reset_devices))
@@ -877,6 +889,7 @@ extern struct megasas_instance_template megasas_instance_template_fusion;
int
megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
+ int seconds;
struct megasas_header *frame_hdr = &cmd->frame->hdr;
@@ -891,13 +904,18 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
/*
* Wait for cmd_status to change
*/
- return wait_and_poll(instance, cmd);
+ if (instance->requestorId)
+ seconds = MEGASAS_ROUTINE_WAIT_TIME_VF;
+ else
+ seconds = MFI_POLL_TIMEOUT_SECS;
+ return wait_and_poll(instance, cmd, seconds);
}
/**
* megasas_issue_blocked_cmd - Synchronous wrapper around regular FW cmds
* @instance: Adapter soft state
* @cmd: Command to be issued
+ * @timeout: Timeout in seconds
*
* This function waits on an event for the command to be returned from ISR.
* Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
@@ -905,13 +923,20 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
*/
static int
megasas_issue_blocked_cmd(struct megasas_instance *instance,
- struct megasas_cmd *cmd)
+ struct megasas_cmd *cmd, int timeout)
{
+ int ret = 0;
cmd->cmd_status = ENODATA;
instance->instancet->issue_dcmd(instance, cmd);
-
- wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA);
+ if (timeout) {
+ ret = wait_event_timeout(instance->int_cmd_wait_q,
+ cmd->cmd_status != ENODATA, timeout * HZ);
+ if (!ret)
+ return 1;
+ } else
+ wait_event(instance->int_cmd_wait_q,
+ cmd->cmd_status != ENODATA);
return 0;
}
@@ -920,18 +945,20 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
* megasas_issue_blocked_abort_cmd - Aborts previously issued cmd
* @instance: Adapter soft state
* @cmd_to_abort: Previously issued cmd to be aborted
+ * @timeout: Timeout in seconds
*
- * MFI firmware can abort previously issued AEN command (automatic event
+ * MFI firmware can abort previously issued AEN comamnd (automatic event
* notification). The megasas_issue_blocked_abort_cmd() issues such abort
* cmd and waits for return status.
* Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
*/
static int
megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
- struct megasas_cmd *cmd_to_abort)
+ struct megasas_cmd *cmd_to_abort, int timeout)
{
struct megasas_cmd *cmd;
struct megasas_abort_frame *abort_fr;
+ int ret = 0;
cmd = megasas_get_cmd(instance);
@@ -957,10 +984,18 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
instance->instancet->issue_dcmd(instance, cmd);
- /*
- * Wait for this cmd to complete
- */
- wait_event(instance->abort_cmd_wait_q, cmd->cmd_status != 0xFF);
+ if (timeout) {
+ ret = wait_event_timeout(instance->abort_cmd_wait_q,
+ cmd->cmd_status != ENODATA, timeout * HZ);
+ if (!ret) {
+ dev_err(&instance->pdev->dev, "Command timedout"
+ "from %s\n", __func__);
+ return 1;
+ }
+ } else
+ wait_event(instance->abort_cmd_wait_q,
+ cmd->cmd_status != ENODATA);
+
cmd->sync_cmd = 0;
megasas_return_cmd(instance, cmd);
@@ -1514,9 +1549,23 @@ megasas_queue_command_lck(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd
spin_lock_irqsave(&instance->hba_lock, flags);
+ /* Check for an mpio path and adjust behavior */
+ if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+ if (megasas_check_mpio_paths(instance, scmd) ==
+ (DID_RESET << 16)) {
+ spin_unlock_irqrestore(&instance->hba_lock, flags);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ } else {
+ spin_unlock_irqrestore(&instance->hba_lock, flags);
+ scmd->result = DID_NO_CONNECT << 16;
+ done(scmd);
+ return 0;
+ }
+ }
+
if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
- scmd->result = DID_ERROR << 16;
+ scmd->result = DID_NO_CONNECT << 16;
done(scmd);
return 0;
}
@@ -1641,9 +1690,14 @@ void megaraid_sas_kill_hba(struct megasas_instance *instance)
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
+ /* Flush */
+ readl(&instance->reg_set->doorbell);
+ if (instance->mpio && instance->requestorId)
+ memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
} else {
writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell);
}
@@ -1730,6 +1784,25 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
megasas_check_and_restore_queue_depth(instance);
}
+/**
+ * megasas_start_timer - Initializes a timer object
+ * @instance: Adapter soft state
+ * @timer: timer object to be initialized
+ * @fn: timer function
+ * @interval: time interval between timer function call
+ *
+ */
+void megasas_start_timer(struct megasas_instance *instance,
+ struct timer_list *timer,
+ void *fn, unsigned long interval)
+{
+ init_timer(timer);
+ timer->expires = jiffies + interval;
+ timer->data = (unsigned long)instance;
+ timer->function = fn;
+ add_timer(timer);
+}
+
static void
megasas_internal_reset_defer_cmds(struct megasas_instance *instance);
@@ -1752,6 +1825,295 @@ void megasas_do_ocr(struct megasas_instance *instance)
process_fw_state_change_wq(&instance->work_init);
}
+/* This function will get the current SR-IOV LD/VF affiliation */
+static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
+ int initial)
+{
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+ struct MR_LD_VF_AFFILIATION *new_affiliation = NULL;
+ struct MR_LD_VF_AFFILIATION_111 *new_affiliation_111 = NULL;
+ struct MR_LD_VF_MAP *newmap = NULL, *savedmap = NULL;
+ dma_addr_t new_affiliation_h;
+ dma_addr_t new_affiliation_111_h;
+ int ld, retval = 0;
+ u8 thisVf;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ printk(KERN_DEBUG "megasas: megasas_get_ld_vf_"
+ "affiliation: Failed to get cmd for scsi%d.\n",
+ instance->host->host_no);
+ return -ENOMEM;
+ }
+
+ dcmd = &cmd->frame->dcmd;
+
+ if (!instance->vf_affiliation && !instance->vf_affiliation_111) {
+ printk(KERN_WARNING "megasas: SR-IOV: Couldn't get LD/VF "
+ "affiliation for scsi%d.\n", instance->host->host_no);
+ megasas_return_cmd(instance, cmd);
+ return -ENOMEM;
+ }
+
+ if (initial)
+ if (instance->PlasmaFW111)
+ memset(instance->vf_affiliation_111, 0,
+ sizeof(struct MR_LD_VF_AFFILIATION_111));
+ else
+ memset(instance->vf_affiliation, 0,
+ (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION));
+ else {
+ if (instance->PlasmaFW111)
+ new_affiliation_111 =
+ pci_alloc_consistent(instance->pdev,
+ sizeof(struct MR_LD_VF_AFFILIATION_111),
+ &new_affiliation_111_h);
+ else
+ new_affiliation =
+ pci_alloc_consistent(instance->pdev,
+ (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION),
+ &new_affiliation_h);
+ if (!new_affiliation && !new_affiliation_111) {
+ printk(KERN_DEBUG "megasas: SR-IOV: Couldn't allocate "
+ "memory for new affiliation for scsi%d.\n",
+ instance->host->host_no);
+ megasas_return_cmd(instance, cmd);
+ return -ENOMEM;
+ }
+ if (instance->PlasmaFW111)
+ memset(new_affiliation_111, 0,
+ sizeof(struct MR_LD_VF_AFFILIATION_111));
+ else
+ memset(new_affiliation, 0, (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION));
+ }
+
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_BOTH;
+ dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
+ if (instance->PlasmaFW111) {
+ dcmd->data_xfer_len = sizeof(struct MR_LD_VF_AFFILIATION_111);
+ dcmd->opcode = MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111;
+ } else {
+ dcmd->data_xfer_len = (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION);
+ dcmd->opcode = MR_DCMD_LD_VF_MAP_GET_ALL_LDS;
+ }
+
+ if (initial) {
+ if (instance->PlasmaFW111)
+ dcmd->sgl.sge32[0].phys_addr =
+ instance->vf_affiliation_111_h;
+ else
+ dcmd->sgl.sge32[0].phys_addr =
+ instance->vf_affiliation_h;
+ } else {
+ if (instance->PlasmaFW111)
+ dcmd->sgl.sge32[0].phys_addr = new_affiliation_111_h;
+ else
+ dcmd->sgl.sge32[0].phys_addr = new_affiliation_h;
+ }
+ if (instance->PlasmaFW111)
+ dcmd->sgl.sge32[0].length =
+ sizeof(struct MR_LD_VF_AFFILIATION_111);
+ else
+ dcmd->sgl.sge32[0].length = (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION);
+
+ printk(KERN_WARNING "megasas: SR-IOV: Getting LD/VF affiliation for "
+ "scsi%d\n", instance->host->host_no);
+
+ megasas_issue_blocked_cmd(instance, cmd, 0);
+
+ if (dcmd->cmd_status) {
+ printk(KERN_WARNING "megasas: SR-IOV: LD/VF affiliation DCMD"
+ " failed with status 0x%x for scsi%d.\n",
+ dcmd->cmd_status, instance->host->host_no);
+ retval = 1; /* Do a scan if we couldn't get affiliation */
+ goto out;
+ }
+
+ if (!initial) {
+ if (instance->PlasmaFW111) {
+ if (!new_affiliation_111->vdCount) {
+ printk(KERN_WARNING "megasas: SR-IOV: Got new "
+ "LD/VF affiliation for passive path "
+ "for scsi%d.\n",
+ instance->host->host_no);
+ retval = 1;
+ goto out;
+ }
+ thisVf = new_affiliation_111->thisVf;
+ for (ld = 0 ; ld < new_affiliation_111->vdCount; ld++)
+ if (instance->vf_affiliation_111->map[ld].policy[thisVf] != new_affiliation_111->map[ld].policy[thisVf]) {
+ printk(KERN_WARNING "megasas: SR-IOV: "
+ "Got new LD/VF affiliation "
+ "for scsi%d.\n",
+ instance->host->host_no);
+ memcpy(instance->vf_affiliation_111,
+ new_affiliation_111,
+ sizeof(struct MR_LD_VF_AFFILIATION_111));
+ retval = 1;
+ goto out;
+ }
+ } else {
+ if (!new_affiliation->ldCount) {
+ printk(KERN_WARNING "megasas: SR-IOV: Got new "
+ "LD/VF affiliation for passive "
+ "path for scsi%d.\n",
+ instance->host->host_no);
+ retval = 1;
+ goto out;
+ }
+ newmap = new_affiliation->map;
+ savedmap = instance->vf_affiliation->map;
+ thisVf = new_affiliation->thisVf;
+ for (ld = 0 ; ld < new_affiliation->ldCount; ld++) {
+ if (savedmap->policy[thisVf] !=
+ newmap->policy[thisVf]) {
+ printk(KERN_WARNING "megasas: SR-IOV: "
+ "Got new LD/VF affiliation "
+ "for scsi%d.\n",
+ instance->host->host_no);
+ memcpy(instance->vf_affiliation,
+ new_affiliation,
+ new_affiliation->size);
+ retval = 1;
+ goto out;
+ }
+ savedmap = (struct MR_LD_VF_MAP *)
+ ((unsigned char *)savedmap +
+ savedmap->size);
+ newmap = (struct MR_LD_VF_MAP *)
+ ((unsigned char *)newmap +
+ newmap->size);
+ }
+ }
+ }
+out:
+ if (new_affiliation) {
+ if (instance->PlasmaFW111)
+ pci_free_consistent(instance->pdev,
+ sizeof(struct MR_LD_VF_AFFILIATION_111),
+ new_affiliation_111,
+ new_affiliation_111_h);
+ else
+ pci_free_consistent(instance->pdev,
+ (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION),
+ new_affiliation, new_affiliation_h);
+ }
+ megasas_return_cmd(instance, cmd);
+
+ return retval;
+}
+
+/* This function will tell FW to start the SR-IOV heartbeat */
+int megasas_sriov_start_heartbeat(struct megasas_instance *instance,
+ int initial)
+{
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+ int retval = 0;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ printk(KERN_DEBUG "megasas: megasas_sriov_start_heartbeat: "
+ "Failed to get cmd for scsi%d.\n",
+ instance->host->host_no);
+ return -ENOMEM;
+ }
+
+ dcmd = &cmd->frame->dcmd;
+
+ if (initial) {
+ instance->hb_host_mem =
+ pci_alloc_consistent(instance->pdev,
+ sizeof(struct MR_CTRL_HB_HOST_MEM),
+ &instance->hb_host_mem_h);
+ if (!instance->hb_host_mem) {
+ printk(KERN_DEBUG "megasas: SR-IOV: Couldn't allocate"
+ " memory for heartbeat host memory for "
+ "scsi%d.\n", instance->host->host_no);
+ retval = -ENOMEM;
+ goto out;
+ }
+ memset(instance->hb_host_mem, 0,
+ sizeof(struct MR_CTRL_HB_HOST_MEM));
+ }
+
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+ dcmd->mbox.s[0] = sizeof(struct MR_CTRL_HB_HOST_MEM);
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_BOTH;
+ dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = sizeof(struct MR_CTRL_HB_HOST_MEM);
+ dcmd->opcode = MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC;
+ dcmd->sgl.sge32[0].phys_addr = instance->hb_host_mem_h;
+ dcmd->sgl.sge32[0].length = sizeof(struct MR_CTRL_HB_HOST_MEM);
+
+ printk(KERN_WARNING "megasas: SR-IOV: Starting heartbeat for scsi%d\n",
+ instance->host->host_no);
+
+ if (!megasas_issue_polled(instance, cmd)) {
+ retval = 0;
+ } else {
+ printk(KERN_WARNING "megasas: SR-IOV: MR_DCMD_CTRL_SHARED_HOST"
+ "_MEM_ALLOC DCMD timed out for scsi%d\n",
+ instance->host->host_no);
+ retval = 1;
+ goto out;
+ }
+
+
+ if (dcmd->cmd_status) {
+ printk(KERN_WARNING "megasas: SR-IOV: MR_DCMD_CTRL_SHARED_HOST"
+ "_MEM_ALLOC DCMD failed with status 0x%x for scsi%d\n",
+ dcmd->cmd_status,
+ instance->host->host_no);
+ retval = 1;
+ goto out;
+ }
+
+out:
+ megasas_return_cmd(instance, cmd);
+
+ return retval;
+}
+
+/* Handler for SR-IOV heartbeat */
+void megasas_sriov_heartbeat_handler(unsigned long instance_addr)
+{
+ struct megasas_instance *instance =
+ (struct megasas_instance *)instance_addr;
+
+ if (instance->hb_host_mem->HB.fwCounter !=
+ instance->hb_host_mem->HB.driverCounter) {
+ instance->hb_host_mem->HB.driverCounter =
+ instance->hb_host_mem->HB.fwCounter;
+ mod_timer(&instance->sriov_heartbeat_timer,
+ jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+ } else {
+ printk(KERN_WARNING "megasas: SR-IOV: Heartbeat never "
+ "completed for scsi%d\n", instance->host->host_no);
+ schedule_work(&instance->work_init);
+ }
+}
+
/**
* megasas_wait_for_outstanding - Wait for all outstanding cmds
* @instance: Adapter soft state
@@ -2014,9 +2376,10 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
* First wait for all commands to complete
*/
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
- ret = megasas_reset_fusion(scmd->device->host);
+ ret = megasas_reset_fusion(scmd->device->host, 1);
else
ret = megasas_generic_reset(scmd);
@@ -2731,6 +3094,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_PLASMA) ||
+ (instance->pdev->device ==
PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FURY)) {
@@ -2755,6 +3120,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_PLASMA) ||
+ (instance->pdev->device ==
PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FURY)) {
@@ -2780,6 +3147,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
(instance->pdev->device
== PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device
+ == PCI_DEVICE_ID_LSI_PLASMA) ||
+ (instance->pdev->device
== PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device
== PCI_DEVICE_ID_LSI_FURY)) {
@@ -2788,6 +3157,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
if ((instance->pdev->device ==
PCI_DEVICE_ID_LSI_FUSION) ||
(instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_PLASMA) ||
+ (instance->pdev->device ==
PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_FURY)) {
@@ -3014,6 +3385,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
cmd->frame->io.context = cpu_to_le32(cmd->index);
cmd->frame->io.pad_0 = 0;
if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) &&
+ (instance->pdev->device != PCI_DEVICE_ID_LSI_PLASMA) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_FURY) &&
(reset_devices))
@@ -3620,6 +3992,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
struct megasas_ctrl_info *ctrl_info;
unsigned long bar_list;
int i, loop, fw_msix_count = 0;
+ struct IOV_111 *iovPtr;
/* Find first memory bar */
bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
@@ -3642,6 +4015,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
switch (instance->pdev->device) {
case PCI_DEVICE_ID_LSI_FUSION:
+ case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
instance->instancet = &megasas_instance_template_fusion;
@@ -3696,7 +4070,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
scratch_pad_2 = readl
(&instance->reg_set->outbound_scratch_pad_2);
/* Check max MSI-X vectors */
- if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) {
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA)) {
instance->msix_vectors = (scratch_pad_2
& MR_MAX_REPLY_QUEUES_OFFSET) + 1;
fw_msix_count = instance->msix_vectors;
@@ -3763,7 +4138,10 @@ static int megasas_init_fw(struct megasas_instance *instance)
memset(instance->pd_list, 0 ,
(MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
- megasas_get_pd_list(instance);
+ if (megasas_get_pd_list(instance) < 0) {
+ printk(KERN_ERR "megasas: failed to get PD list\n");
+ goto fail_init_adapter;
+ }
memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
if (megasas_ld_list_query(instance,
@@ -3807,6 +4185,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
/* adapterOperations2 are converted into CPU arch*/
le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
+ instance->mpio = ctrl_info->adapterOperations2.mpio;
instance->UnevenSpanSupport =
ctrl_info->adapterOperations2.supportUnevenSpans;
if (instance->UnevenSpanSupport) {
@@ -3819,6 +4198,20 @@ static int megasas_init_fw(struct megasas_instance *instance)
fusion->fast_path_io = 0;
}
+ if (ctrl_info->host_interface.SRIOV) {
+ if (!ctrl_info->adapterOperations2.activePassive)
+ instance->PlasmaFW111 = 1;
+
+ if (!instance->PlasmaFW111)
+ instance->requestorId =
+ ctrl_info->iov.requestorId;
+ else {
+ iovPtr = (struct IOV_111 *)((unsigned char *)ctrl_info + IOV_111_OFFSET);
+ instance->requestorId = iovPtr->requestorId;
+ }
+ printk(KERN_WARNING "megaraid_sas: I am VF "
+ "requestorId %d\n", instance->requestorId);
+ }
}
instance->max_sectors_per_req = instance->max_num_sge *
PAGE_SIZE / 512;
@@ -3851,6 +4244,17 @@ static int megasas_init_fw(struct megasas_instance *instance)
tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
(unsigned long)instance);
+ /* Launch SR-IOV heartbeat timer */
+ if (instance->requestorId) {
+ if (!megasas_sriov_start_heartbeat(instance, 1))
+ megasas_start_timer(instance,
+ &instance->sriov_heartbeat_timer,
+ megasas_sriov_heartbeat_handler,
+ MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+ else
+ instance->skip_heartbeat_timer_del = 1;
+ }
+
return 0;
fail_init_adapter:
@@ -3933,16 +4337,19 @@ megasas_get_seq_num(struct megasas_instance *instance,
dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(el_info_h);
dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct megasas_evt_log_info));
- megasas_issue_blocked_cmd(instance, cmd);
-
- /*
- * Copy the data back into callers buffer
- */
- eli->newest_seq_num = le32_to_cpu(el_info->newest_seq_num);
- eli->oldest_seq_num = le32_to_cpu(el_info->oldest_seq_num);
- eli->clear_seq_num = le32_to_cpu(el_info->clear_seq_num);
- eli->shutdown_seq_num = le32_to_cpu(el_info->shutdown_seq_num);
- eli->boot_seq_num = le32_to_cpu(el_info->boot_seq_num);
+ if (megasas_issue_blocked_cmd(instance, cmd, 30))
+ dev_err(&instance->pdev->dev, "Command timedout"
+ "from %s\n", __func__);
+ else {
+ /*
+ * Copy the data back into callers buffer
+ */
+ eli->newest_seq_num = le32_to_cpu(el_info->newest_seq_num);
+ eli->oldest_seq_num = le32_to_cpu(el_info->oldest_seq_num);
+ eli->clear_seq_num = le32_to_cpu(el_info->clear_seq_num);
+ eli->shutdown_seq_num = le32_to_cpu(el_info->shutdown_seq_num);
+ eli->boot_seq_num = le32_to_cpu(el_info->boot_seq_num);
+ }
pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info),
el_info, el_info_h);
@@ -4018,7 +4425,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
instance->aen_cmd->abort_aen = 1;
ret_val = megasas_issue_blocked_abort_cmd(instance,
instance->
- aen_cmd);
+ aen_cmd, 30);
if (ret_val) {
printk(KERN_DEBUG "megasas: Failed to abort "
@@ -4160,6 +4567,7 @@ static int megasas_io_attach(struct megasas_instance *instance)
/* Fusion only supports host reset */
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
host->hostt->eh_device_reset_handler = NULL;
@@ -4197,6 +4605,19 @@ megasas_set_dma_mask(struct pci_dev *pdev)
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
goto fail_set_dma_mask;
}
+ /*
+ * Ensure that all data structures are allocated in 32-bit
+ * memory.
+ */
+ if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
+ /* Try 32bit DMA mask and 32 bit Consistent dma mask */
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
+ && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
+ dev_info(&pdev->dev, "set 32bit DMA mask"
+ "and 32 bit consistent mask\n");
+ else
+ goto fail_set_dma_mask;
+ }
return 0;
@@ -4212,7 +4633,7 @@ fail_set_dma_mask:
static int megasas_probe_one(struct pci_dev *pdev,
const struct pci_device_id *id)
{
- int rval, pos, i, j;
+ int rval, pos, i, j, cpu;
struct Scsi_Host *host;
struct megasas_instance *instance;
u16 control = 0;
@@ -4272,6 +4693,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
switch (instance->pdev->device) {
case PCI_DEVICE_ID_LSI_FUSION:
+ case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
{
@@ -4368,6 +4790,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
instance->UnevenSpanSupport = 0;
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
@@ -4380,12 +4803,33 @@ static int megasas_probe_one(struct pci_dev *pdev,
if (megasas_init_fw(instance))
goto fail_init_mfi;
+ if (instance->requestorId) {
+ if (instance->PlasmaFW111) {
+ instance->vf_affiliation_111 =
+ pci_alloc_consistent(pdev, sizeof(struct MR_LD_VF_AFFILIATION_111),
+ &instance->vf_affiliation_111_h);
+ if (!instance->vf_affiliation_111)
+ printk(KERN_WARNING "megasas: Can't allocate "
+ "memory for VF affiliation buffer\n");
+ } else {
+ instance->vf_affiliation =
+ pci_alloc_consistent(pdev,
+ (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION),
+ &instance->vf_affiliation_h);
+ if (!instance->vf_affiliation)
+ printk(KERN_WARNING "megasas: Can't allocate "
+ "memory for VF affiliation buffer\n");
+ }
+ }
+
retry_irq_register:
/*
* Register IRQ
*/
if (instance->msix_vectors) {
- for (i = 0 ; i < instance->msix_vectors; i++) {
+ cpu = cpumask_first(cpu_online_mask);
+ for (i = 0; i < instance->msix_vectors; i++) {
instance->irq_context[i].instance = instance;
instance->irq_context[i].MSIxIndex = i;
if (request_irq(instance->msixentry[i].vector,
@@ -4394,14 +4838,22 @@ retry_irq_register:
&instance->irq_context[i])) {
printk(KERN_DEBUG "megasas: Failed to "
"register IRQ for vector %d.\n", i);
- for (j = 0 ; j < i ; j++)
+ for (j = 0; j < i; j++) {
+ irq_set_affinity_hint(
+ instance->msixentry[j].vector, NULL);
free_irq(
instance->msixentry[j].vector,
&instance->irq_context[j]);
+ }
/* Retry irq register for IO_APIC */
instance->msix_vectors = 0;
goto retry_irq_register;
}
+ if (irq_set_affinity_hint(instance->msixentry[i].vector,
+ get_cpu_mask(cpu)))
+ dev_err(&instance->pdev->dev, "Error setting"
+ "affinity hint for cpu %d\n", cpu);
+ cpu = cpumask_next(cpu, cpu_online_mask);
}
} else {
instance->irq_context[0].instance = instance;
@@ -4455,13 +4907,17 @@ retry_irq_register:
instance->instancet->disable_intr(instance);
if (instance->msix_vectors)
- for (i = 0 ; i < instance->msix_vectors; i++)
+ for (i = 0; i < instance->msix_vectors; i++) {
+ irq_set_affinity_hint(
+ instance->msixentry[i].vector, NULL);
free_irq(instance->msixentry[i].vector,
&instance->irq_context[i]);
+ }
else
free_irq(instance->pdev->irq, &instance->irq_context[0]);
fail_irq:
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
megasas_release_fusion(instance);
@@ -4522,7 +4978,9 @@ static void megasas_flush_cache(struct megasas_instance *instance)
dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_CACHE_FLUSH);
dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
- megasas_issue_blocked_cmd(instance, cmd);
+ if (megasas_issue_blocked_cmd(instance, cmd, 30))
+ dev_err(&instance->pdev->dev, "Command timedout"
+ " from %s\n", __func__);
megasas_return_cmd(instance, cmd);
@@ -4549,10 +5007,11 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
return;
if (instance->aen_cmd)
- megasas_issue_blocked_abort_cmd(instance, instance->aen_cmd);
+ megasas_issue_blocked_abort_cmd(instance,
+ instance->aen_cmd, 30);
if (instance->map_update_cmd)
megasas_issue_blocked_abort_cmd(instance,
- instance->map_update_cmd);
+ instance->map_update_cmd, 30);
dcmd = &cmd->frame->dcmd;
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
@@ -4566,7 +5025,9 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
dcmd->data_xfer_len = 0;
dcmd->opcode = cpu_to_le32(opcode);
- megasas_issue_blocked_cmd(instance, cmd);
+ if (megasas_issue_blocked_cmd(instance, cmd, 30))
+ dev_err(&instance->pdev->dev, "Command timedout"
+ "from %s\n", __func__);
megasas_return_cmd(instance, cmd);
@@ -4590,6 +5051,10 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
host = instance->host;
instance->unload = 1;
+ /* Shutdown SR-IOV heartbeat timer */
+ if (instance->requestorId && !instance->skip_heartbeat_timer_del)
+ del_timer_sync(&instance->sriov_heartbeat_timer);
+
megasas_flush_cache(instance);
megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
@@ -4606,9 +5071,12 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
instance->instancet->disable_intr(instance);
if (instance->msix_vectors)
- for (i = 0 ; i < instance->msix_vectors; i++)
+ for (i = 0; i < instance->msix_vectors; i++) {
+ irq_set_affinity_hint(
+ instance->msixentry[i].vector, NULL);
free_irq(instance->msixentry[i].vector,
&instance->irq_context[i]);
+ }
else
free_irq(instance->pdev->irq, &instance->irq_context[0]);
if (instance->msix_vectors)
@@ -4629,7 +5097,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
static int
megasas_resume(struct pci_dev *pdev)
{
- int rval, i, j;
+ int rval, i, j, cpu;
struct Scsi_Host *host;
struct megasas_instance *instance;
@@ -4673,6 +5141,7 @@ megasas_resume(struct pci_dev *pdev)
switch (instance->pdev->device) {
case PCI_DEVICE_ID_LSI_FUSION:
+ case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
{
@@ -4701,6 +5170,7 @@ megasas_resume(struct pci_dev *pdev)
* Register IRQ
*/
if (instance->msix_vectors) {
+ cpu = cpumask_first(cpu_online_mask);
for (i = 0 ; i < instance->msix_vectors; i++) {
instance->irq_context[i].instance = instance;
instance->irq_context[i].MSIxIndex = i;
@@ -4710,12 +5180,21 @@ megasas_resume(struct pci_dev *pdev)
&instance->irq_context[i])) {
printk(KERN_DEBUG "megasas: Failed to "
"register IRQ for vector %d.\n", i);
- for (j = 0 ; j < i ; j++)
+ for (j = 0; j < i; j++) {
+ irq_set_affinity_hint(
+ instance->msixentry[j].vector, NULL);
free_irq(
instance->msixentry[j].vector,
&instance->irq_context[j]);
+ }
goto fail_irq;
}
+
+ if (irq_set_affinity_hint(instance->msixentry[i].vector,
+ get_cpu_mask(cpu)))
+ dev_err(&instance->pdev->dev, "Error setting"
+ "affinity hint for cpu %d\n", cpu);
+ cpu = cpumask_next(cpu, cpu_online_mask);
}
} else {
instance->irq_context[0].instance = instance;
@@ -4728,6 +5207,17 @@ megasas_resume(struct pci_dev *pdev)
}
}
+ /* Re-launch SR-IOV heartbeat timer */
+ if (instance->requestorId) {
+ if (!megasas_sriov_start_heartbeat(instance, 0))
+ megasas_start_timer(instance,
+ &instance->sriov_heartbeat_timer,
+ megasas_sriov_heartbeat_handler,
+ MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+ else
+ instance->skip_heartbeat_timer_del = 1;
+ }
+
instance->instancet->enable_intr(instance);
instance->unload = 0;
@@ -4782,6 +5272,10 @@ static void megasas_detach_one(struct pci_dev *pdev)
host = instance->host;
fusion = instance->ctrl_context;
+ /* Shutdown SR-IOV heartbeat timer */
+ if (instance->requestorId && !instance->skip_heartbeat_timer_del)
+ del_timer_sync(&instance->sriov_heartbeat_timer);
+
scsi_remove_host(instance->host);
megasas_flush_cache(instance);
megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
@@ -4793,6 +5287,9 @@ static void megasas_detach_one(struct pci_dev *pdev)
instance->ev = NULL;
}
+ /* cancel all wait events */
+ wake_up_all(&instance->int_cmd_wait_q);
+
tasklet_kill(&instance->isr_tasklet);
/*
@@ -4811,9 +5308,12 @@ static void megasas_detach_one(struct pci_dev *pdev)
instance->instancet->disable_intr(instance);
if (instance->msix_vectors)
- for (i = 0 ; i < instance->msix_vectors; i++)
+ for (i = 0; i < instance->msix_vectors; i++) {
+ irq_set_affinity_hint(
+ instance->msixentry[i].vector, NULL);
free_irq(instance->msixentry[i].vector,
&instance->irq_context[i]);
+ }
else
free_irq(instance->pdev->irq, &instance->irq_context[0]);
if (instance->msix_vectors)
@@ -4821,6 +5321,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
switch (instance->pdev->device) {
case PCI_DEVICE_ID_LSI_FUSION:
+ case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
megasas_release_fusion(instance);
@@ -4847,6 +5348,24 @@ static void megasas_detach_one(struct pci_dev *pdev)
if (instance->evt_detail)
pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
instance->evt_detail, instance->evt_detail_h);
+
+ if (instance->vf_affiliation)
+ pci_free_consistent(pdev, (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION),
+ instance->vf_affiliation,
+ instance->vf_affiliation_h);
+
+ if (instance->vf_affiliation_111)
+ pci_free_consistent(pdev,
+ sizeof(struct MR_LD_VF_AFFILIATION_111),
+ instance->vf_affiliation_111,
+ instance->vf_affiliation_111_h);
+
+ if (instance->hb_host_mem)
+ pci_free_consistent(pdev, sizeof(struct MR_CTRL_HB_HOST_MEM),
+ instance->hb_host_mem,
+ instance->hb_host_mem_h);
+
scsi_host_put(host);
pci_disable_device(pdev);
@@ -4868,9 +5387,12 @@ static void megasas_shutdown(struct pci_dev *pdev)
megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
instance->instancet->disable_intr(instance);
if (instance->msix_vectors)
- for (i = 0 ; i < instance->msix_vectors; i++)
+ for (i = 0; i < instance->msix_vectors; i++) {
+ irq_set_affinity_hint(
+ instance->msixentry[i].vector, NULL);
free_irq(instance->msixentry[i].vector,
&instance->irq_context[i]);
+ }
else
free_irq(instance->pdev->irq, &instance->irq_context[0]);
if (instance->msix_vectors)
@@ -5045,7 +5567,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
* cmd to the SCSI mid-layer
*/
cmd->sync_cmd = 1;
- megasas_issue_blocked_cmd(instance, cmd);
+ megasas_issue_blocked_cmd(instance, cmd, 0);
cmd->sync_cmd = 0;
/*
@@ -5132,6 +5654,16 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
goto out_kfree_ioc;
}
+ /* Adjust ioctl wait time for VF mode */
+ if (instance->requestorId)
+ wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
+
+ /* Block ioctls in VF mode */
+ if (instance->requestorId && !allow_vf_ioctls) {
+ error = -ENODEV;
+ goto out_kfree_ioc;
+ }
+
if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
printk(KERN_ERR "Controller in crit error\n");
error = -ENODEV;
@@ -5441,7 +5973,7 @@ megasas_aen_polling(struct work_struct *work)
u16 pd_index = 0;
u16 ld_index = 0;
int i, j, doscan = 0;
- u32 seq_num;
+ u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME;
int error;
if (!instance) {
@@ -5449,6 +5981,23 @@ megasas_aen_polling(struct work_struct *work)
kfree(ev);
return;
}
+
+ /* Adjust event workqueue thread wait time for VF mode */
+ if (instance->requestorId)
+ wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
+
+ /* Don't run the event workqueue thread if OCR is running */
+ for (i = 0; i < wait_time; i++) {
+ if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL)
+ break;
+ if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+ printk(KERN_NOTICE "megasas: %s waiting for "
+ "controller reset to finish for scsi%d\n",
+ __func__, instance->host->host_no);
+ }
+ msleep(1000);
+ }
+
instance->ev = NULL;
host = instance->host;
if (instance->evt_detail) {
@@ -5515,65 +6064,64 @@ megasas_aen_polling(struct work_struct *work)
case MR_EVT_LD_OFFLINE:
case MR_EVT_CFG_CLEARED:
case MR_EVT_LD_DELETED:
- if (megasas_ld_list_query(instance,
- MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
- megasas_get_ld_list(instance);
- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
- for (j = 0;
- j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
-
- ld_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host,
- MEGASAS_MAX_PD_CHANNELS + i,
- j,
- 0);
-
- if (instance->ld_ids[ld_index] != 0xff) {
- if (sdev1) {
- scsi_device_put(sdev1);
- }
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
+ if (!instance->requestorId ||
+ (instance->requestorId &&
+ megasas_get_ld_vf_affiliation(instance, 0))) {
+ if (megasas_ld_list_query(instance,
+ MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
+ megasas_get_ld_list(instance);
+ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+ for (j = 0;
+ j < MEGASAS_MAX_DEV_PER_CHANNEL;
+ j++) {
+
+ ld_index =
+ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+
+ sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+
+ if (instance->ld_ids[ld_index]
+ != 0xff) {
+ if (sdev1)
+ scsi_device_put(sdev1);
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
+ }
+ }
}
}
- }
+ doscan = 0;
}
- doscan = 0;
break;
case MR_EVT_LD_CREATED:
- if (megasas_ld_list_query(instance,
- MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
- megasas_get_ld_list(instance);
- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
- for (j = 0;
- j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
- ld_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host,
- MEGASAS_MAX_PD_CHANNELS + i,
- j, 0);
-
- if (instance->ld_ids[ld_index] !=
- 0xff) {
- if (!sdev1) {
- scsi_add_device(host,
- MEGASAS_MAX_PD_CHANNELS + i,
- j, 0);
+ if (!instance->requestorId ||
+ (instance->requestorId &&
+ megasas_get_ld_vf_affiliation(instance, 0))) {
+ if (megasas_ld_list_query(instance,
+ MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
+ megasas_get_ld_list(instance);
+ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+ for (j = 0;
+ j < MEGASAS_MAX_DEV_PER_CHANNEL;
+ j++) {
+ ld_index =
+ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+
+ sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+
+ if (instance->ld_ids[ld_index]
+ != 0xff) {
+ if (!sdev1)
+ scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
}
- }
- if (sdev1) {
- scsi_device_put(sdev1);
+ if (sdev1)
+ scsi_device_put(sdev1);
}
}
+ doscan = 0;
}
- doscan = 0;
break;
case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
case MR_EVT_FOREIGN_CFG_IMPORTED:
@@ -5591,50 +6139,55 @@ megasas_aen_polling(struct work_struct *work)
}
if (doscan) {
- printk(KERN_INFO "scanning ...\n");
- megasas_get_pd_list(instance);
- for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
- for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
- pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
- sdev1 = scsi_device_lookup(host, i, j, 0);
- if (instance->pd_list[pd_index].driveState ==
- MR_PD_STATE_SYSTEM) {
- if (!sdev1) {
- scsi_add_device(host, i, j, 0);
- }
- if (sdev1)
- scsi_device_put(sdev1);
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
+ printk(KERN_INFO "megaraid_sas: scanning for scsi%d...\n",
+ instance->host->host_no);
+ if (megasas_get_pd_list(instance) == 0) {
+ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+ pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
+ sdev1 = scsi_device_lookup(host, i, j, 0);
+ if (instance->pd_list[pd_index].driveState ==
+ MR_PD_STATE_SYSTEM) {
+ if (!sdev1) {
+ scsi_add_device(host, i, j, 0);
+ }
+ if (sdev1)
+ scsi_device_put(sdev1);
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
+ }
}
}
}
}
- if (megasas_ld_list_query(instance,
- MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
- megasas_get_ld_list(instance);
- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
- for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
- ld_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+ if (!instance->requestorId ||
+ (instance->requestorId &&
+ megasas_get_ld_vf_affiliation(instance, 0))) {
+ if (megasas_ld_list_query(instance,
+ MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
+ megasas_get_ld_list(instance);
+ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL;
+ j++) {
+ ld_index =
+ (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
- sdev1 = scsi_device_lookup(host,
- MEGASAS_MAX_PD_CHANNELS + i, j, 0);
- if (instance->ld_ids[ld_index] != 0xff) {
- if (!sdev1) {
- scsi_add_device(host,
- MEGASAS_MAX_PD_CHANNELS + i,
- j, 0);
+ sdev1 = scsi_device_lookup(host,
+ MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+ if (instance->ld_ids[ld_index]
+ != 0xff) {
+ if (!sdev1)
+ scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+ else
+ scsi_device_put(sdev1);
} else {
- scsi_device_put(sdev1);
- }
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
+ }
}
}
}
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index e24b6eb645b5..081bfff12d00 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -143,12 +143,12 @@ u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map)
u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map)
{
- return map->raidMap.ldSpanMap[ld].ldRaid.targetId;
+ return le16_to_cpu(map->raidMap.ldSpanMap[ld].ldRaid.targetId);
}
-u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map)
+u8 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map)
{
- return le16_to_cpu(map->raidMap.ldTgtIdToLd[ldTgtId]);
+ return map->raidMap.ldTgtIdToLd[ldTgtId];
}
static struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span,
@@ -975,7 +975,10 @@ MR_BuildRaidContext(struct megasas_instance *instance,
regSize += stripSize;
}
- pRAID_Context->timeoutValue = cpu_to_le16(map->raidMap.fpPdIoTimeoutSec);
+ pRAID_Context->timeoutValue =
+ cpu_to_le16(raid->fpIoTimeoutForLd ?
+ raid->fpIoTimeoutForLd :
+ map->raidMap.fpPdIoTimeoutSec);
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
pRAID_Context->regLockFlags = (isRead) ?
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index f6555921fd7a..22600419ae9f 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -62,7 +62,8 @@ megasas_complete_cmd(struct megasas_instance *instance,
struct megasas_cmd *cmd, u8 alt_status);
int megasas_is_ldio(struct scsi_cmnd *cmd);
int
-wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd);
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
+ int seconds);
void
megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd);
@@ -81,6 +82,13 @@ int megasas_transition_to_ready(struct megasas_instance *instance, int ocr);
void megaraid_sas_kill_hba(struct megasas_instance *instance);
extern u32 megasas_dbg_lvl;
+void megasas_sriov_heartbeat_handler(unsigned long instance_addr);
+int megasas_sriov_start_heartbeat(struct megasas_instance *instance,
+ int initial);
+void megasas_start_timer(struct megasas_instance *instance,
+ struct timer_list *timer,
+ void *fn, unsigned long interval);
+extern struct megasas_mgmt_info megasas_mgmt_info;
extern int resetwaittime;
/**
@@ -549,12 +557,13 @@ fail_req_desc:
* For polling, MFI requires the cmd_status to be set to 0xFF before posting.
*/
int
-wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd)
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
+ int seconds)
{
int i;
struct megasas_header *frame_hdr = &cmd->frame->hdr;
- u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;
+ u32 msecs = seconds * 1000;
/*
* Wait for cmd_status to change
@@ -585,7 +594,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
struct megasas_cmd *cmd;
u8 ret;
struct fusion_context *fusion;
- union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
int i;
struct megasas_header *frame_hdr;
@@ -644,18 +653,18 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
/* Convert capability to LE32 */
cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
- init_frame->queue_info_new_phys_addr_lo = cpu_to_le32((u32)ioc_init_handle);
+ init_frame->queue_info_new_phys_addr_hi =
+ cpu_to_le32(upper_32_bits(ioc_init_handle));
+ init_frame->queue_info_new_phys_addr_lo =
+ cpu_to_le32(lower_32_bits(ioc_init_handle));
init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST));
- req_desc =
- (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)fusion->req_frames_desc;
-
- req_desc->Words = 0;
- req_desc->MFAIo.RequestFlags =
+ req_desc.Words = 0;
+ req_desc.MFAIo.RequestFlags =
(MEGASAS_REQ_DESCRIPT_FLAGS_MFA <<
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
- cpu_to_le32s((u32 *)&req_desc->MFAIo);
- req_desc->Words |= cpu_to_le64(cmd->frame_phys_addr);
+ cpu_to_le32s((u32 *)&req_desc.MFAIo);
+ req_desc.Words |= cpu_to_le64(cmd->frame_phys_addr);
/*
* disable the intr before firing the init frame
@@ -669,10 +678,10 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
break;
}
- instance->instancet->fire_cmd(instance, req_desc->u.low,
- req_desc->u.high, instance->reg_set);
+ instance->instancet->fire_cmd(instance, req_desc.u.low,
+ req_desc.u.high, instance->reg_set);
- wait_and_poll(instance, cmd);
+ wait_and_poll(instance, cmd, MFI_POLL_TIMEOUT_SECS);
frame_hdr = &cmd->frame->hdr;
if (frame_hdr->cmd_status != 0) {
@@ -723,7 +732,7 @@ megasas_get_ld_map_info(struct megasas_instance *instance)
if (!fusion) {
megasas_return_cmd(instance, cmd);
- return 1;
+ return -ENXIO;
}
dcmd = &cmd->frame->dcmd;
@@ -1604,13 +1613,15 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
- io_request->IoFlags |=
- MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH;
+ io_request->IoFlags |= cpu_to_le16(
+ MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
cmd->request_desc->SCSIIO.RequestFlags =
(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
cmd->request_desc->SCSIIO.DevHandle =
local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ instance->msix_vectors ? smp_processor_id() % instance->msix_vectors : 0;
/*
* If the command is for the tape device, set the
* FP timeout to the os layer timeout value.
@@ -1770,7 +1781,8 @@ megasas_get_request_descriptor(struct megasas_instance *instance, u16 index)
if (index >= instance->max_fw_cmds) {
printk(KERN_ERR "megasas: Invalid SMID (0x%x)request for "
- "descriptor\n", index);
+ "descriptor for scsi%d\n", index,
+ instance->host->host_no);
return NULL;
}
fusion = instance->ctrl_context;
@@ -2038,8 +2050,11 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp)
/* If we didn't complete any commands, check for FW fault */
fw_state = instance->instancet->read_fw_status_reg(
instance->reg_set) & MFI_STATE_MASK;
- if (fw_state == MFI_STATE_FAULT)
+ if (fw_state == MFI_STATE_FAULT) {
+ printk(KERN_WARNING "megaraid_sas: Iop2SysDoorbellInt"
+ "for scsi%d\n", instance->host->host_no);
schedule_work(&instance->work_init);
+ }
}
return IRQ_HANDLED;
@@ -2210,9 +2225,10 @@ megasas_check_reset_fusion(struct megasas_instance *instance,
}
/* This function waits for outstanding commands on fusion to complete */
-int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
+int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
+ int iotimeout, int *convert)
{
- int i, outstanding, retval = 0;
+ int i, outstanding, retval = 0, hb_seconds_missed = 0;
u32 fw_state;
for (i = 0; i < resetwaittime; i++) {
@@ -2221,18 +2237,49 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
instance->reg_set) & MFI_STATE_MASK;
if (fw_state == MFI_STATE_FAULT) {
printk(KERN_WARNING "megasas: Found FW in FAULT state,"
- " will reset adapter.\n");
+ " will reset adapter scsi%d.\n",
+ instance->host->host_no);
+ retval = 1;
+ goto out;
+ }
+ /* If SR-IOV VF mode & heartbeat timeout, don't wait */
+ if (instance->requestorId && !iotimeout) {
retval = 1;
goto out;
}
+ /* If SR-IOV VF mode & I/O timeout, check for HB timeout */
+ if (instance->requestorId && iotimeout) {
+ if (instance->hb_host_mem->HB.fwCounter !=
+ instance->hb_host_mem->HB.driverCounter) {
+ instance->hb_host_mem->HB.driverCounter =
+ instance->hb_host_mem->HB.fwCounter;
+ hb_seconds_missed = 0;
+ } else {
+ hb_seconds_missed++;
+ if (hb_seconds_missed ==
+ (MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF/HZ)) {
+ printk(KERN_WARNING "megasas: SR-IOV:"
+ " Heartbeat never completed "
+ " while polling during I/O "
+ " timeout handling for "
+ "scsi%d.\n",
+ instance->host->host_no);
+ *convert = 1;
+ retval = 1;
+ goto out;
+ }
+ }
+ }
+
outstanding = atomic_read(&instance->fw_outstanding);
if (!outstanding)
goto out;
if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
- "commands to complete\n", i, outstanding);
+ "commands to complete for scsi%d\n", i,
+ outstanding, instance->host->host_no);
megasas_complete_cmd_dpc_fusion(
(unsigned long)instance);
}
@@ -2241,7 +2288,8 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
if (atomic_read(&instance->fw_outstanding)) {
printk("megaraid_sas: pending commands remain after waiting, "
- "will reset adapter.\n");
+ "will reset adapter scsi%d.\n",
+ instance->host->host_no);
retval = 1;
}
out:
@@ -2263,10 +2311,34 @@ void megasas_reset_reply_desc(struct megasas_instance *instance)
reply_desc->Words = ULLONG_MAX;
}
+/* Check for a second path that is currently UP */
+int megasas_check_mpio_paths(struct megasas_instance *instance,
+ struct scsi_cmnd *scmd)
+{
+ int i, j, retval = (DID_RESET << 16);
+
+ if (instance->mpio && instance->requestorId) {
+ for (i = 0 ; i < MAX_MGMT_ADAPTERS ; i++)
+ for (j = 0 ; j < MAX_LOGICAL_DRIVES; j++)
+ if (megasas_mgmt_info.instance[i] &&
+ (megasas_mgmt_info.instance[i] != instance) &&
+ megasas_mgmt_info.instance[i]->mpio &&
+ megasas_mgmt_info.instance[i]->requestorId
+ &&
+ (megasas_mgmt_info.instance[i]->ld_ids[j]
+ == scmd->device->id)) {
+ retval = (DID_NO_CONNECT << 16);
+ goto out;
+ }
+ }
+out:
+ return retval;
+}
+
/* Core fusion reset function */
-int megasas_reset_fusion(struct Scsi_Host *shost)
+int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
{
- int retval = SUCCESS, i, j, retry = 0;
+ int retval = SUCCESS, i, j, retry = 0, convert = 0;
struct megasas_instance *instance;
struct megasas_cmd_fusion *cmd_fusion;
struct fusion_context *fusion;
@@ -2277,28 +2349,39 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
instance = (struct megasas_instance *)shost->hostdata;
fusion = instance->ctrl_context;
+ mutex_lock(&instance->reset_mutex);
+
if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
printk(KERN_WARNING "megaraid_sas: Hardware critical error, "
- "returning FAILED.\n");
+ "returning FAILED for scsi%d.\n",
+ instance->host->host_no);
return FAILED;
}
- mutex_lock(&instance->reset_mutex);
+ if (instance->requestorId && !instance->skip_heartbeat_timer_del)
+ del_timer_sync(&instance->sriov_heartbeat_timer);
set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
- instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ instance->adprecovery = MEGASAS_ADPRESET_SM_POLLING;
instance->instancet->disable_intr(instance);
msleep(1000);
/* First try waiting for commands to complete */
- if (megasas_wait_for_outstanding_fusion(instance)) {
+ if (megasas_wait_for_outstanding_fusion(instance, iotimeout,
+ &convert)) {
+ instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
printk(KERN_WARNING "megaraid_sas: resetting fusion "
- "adapter.\n");
+ "adapter scsi%d.\n", instance->host->host_no);
+ if (convert)
+ iotimeout = 0;
+
/* Now return commands back to the OS */
for (i = 0 ; i < instance->max_fw_cmds; i++) {
cmd_fusion = fusion->cmd_list[i];
if (cmd_fusion->scmd) {
scsi_dma_unmap(cmd_fusion->scmd);
- cmd_fusion->scmd->result = (DID_RESET << 16);
+ cmd_fusion->scmd->result =
+ megasas_check_mpio_paths(instance,
+ cmd_fusion->scmd);
cmd_fusion->scmd->scsi_done(cmd_fusion->scmd);
megasas_return_cmd_fusion(instance, cmd_fusion);
atomic_dec(&instance->fw_outstanding);
@@ -2313,13 +2396,67 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
(abs_state == MFI_STATE_FAULT && !reset_adapter)) {
/* Reset not supported, kill adapter */
printk(KERN_WARNING "megaraid_sas: Reset not supported"
- ", killing adapter.\n");
+ ", killing adapter scsi%d.\n",
+ instance->host->host_no);
megaraid_sas_kill_hba(instance);
+ instance->skip_heartbeat_timer_del = 1;
instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
retval = FAILED;
goto out;
}
+ /* Let SR-IOV VF & PF sync up if there was a HB failure */
+ if (instance->requestorId && !iotimeout) {
+ msleep(MEGASAS_OCR_SETTLE_TIME_VF);
+ /* Look for a late HB update after VF settle time */
+ if (abs_state == MFI_STATE_OPERATIONAL &&
+ (instance->hb_host_mem->HB.fwCounter !=
+ instance->hb_host_mem->HB.driverCounter)) {
+ instance->hb_host_mem->HB.driverCounter =
+ instance->hb_host_mem->HB.fwCounter;
+ printk(KERN_WARNING "megasas: SR-IOV:"
+ "Late FW heartbeat update for "
+ "scsi%d.\n",
+ instance->host->host_no);
+ } else {
+ /* In VF mode, first poll for FW ready */
+ for (i = 0;
+ i < (MEGASAS_RESET_WAIT_TIME * 1000);
+ i += 20) {
+ status_reg =
+ instance->instancet->
+ read_fw_status_reg(
+ instance->reg_set);
+ abs_state = status_reg &
+ MFI_STATE_MASK;
+ if (abs_state == MFI_STATE_READY) {
+ printk(KERN_WARNING "megasas"
+ ": SR-IOV: FW was found"
+ "to be in ready state "
+ "for scsi%d.\n",
+ instance->host->host_no);
+ break;
+ }
+ msleep(20);
+ }
+ if (abs_state != MFI_STATE_READY) {
+ printk(KERN_WARNING "megasas: SR-IOV: "
+ "FW not in ready state after %d"
+ " seconds for scsi%d, status_reg = "
+ "0x%x.\n",
+ MEGASAS_RESET_WAIT_TIME,
+ instance->host->host_no,
+ status_reg);
+ megaraid_sas_kill_hba(instance);
+ instance->skip_heartbeat_timer_del = 1;
+ instance->adprecovery =
+ MEGASAS_HW_CRITICAL_ERROR;
+ retval = FAILED;
+ goto out;
+ }
+ }
+ }
+
/* Now try to reset the chip */
for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) {
writel(MPI2_WRSEQ_FLUSH_KEY_VALUE,
@@ -2346,7 +2483,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
readl(&instance->reg_set->fusion_host_diag);
if (retry++ == 100) {
printk(KERN_WARNING "megaraid_sas: "
- "Host diag unlock failed!\n");
+ "Host diag unlock failed! "
+ "for scsi%d\n",
+ instance->host->host_no);
break;
}
}
@@ -2368,7 +2507,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
if (retry++ == 1000) {
printk(KERN_WARNING "megaraid_sas: "
"Diag reset adapter never "
- "cleared!\n");
+ "cleared for scsi%d!\n",
+ instance->host->host_no);
break;
}
}
@@ -2390,29 +2530,29 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
if (abs_state <= MFI_STATE_FW_INIT) {
printk(KERN_WARNING "megaraid_sas: firmware "
"state < MFI_STATE_FW_INIT, state = "
- "0x%x\n", abs_state);
+ "0x%x for scsi%d\n", abs_state,
+ instance->host->host_no);
continue;
}
/* Wait for FW to become ready */
if (megasas_transition_to_ready(instance, 1)) {
printk(KERN_WARNING "megaraid_sas: Failed to "
- "transition controller to ready.\n");
+ "transition controller to ready "
+ "for scsi%d.\n",
+ instance->host->host_no);
continue;
}
megasas_reset_reply_desc(instance);
if (megasas_ioc_init_fusion(instance)) {
printk(KERN_WARNING "megaraid_sas: "
- "megasas_ioc_init_fusion() failed!\n");
+ "megasas_ioc_init_fusion() failed!"
+ " for scsi%d\n",
+ instance->host->host_no);
continue;
}
- clear_bit(MEGASAS_FUSION_IN_RESET,
- &instance->reset_flags);
- instance->instancet->enable_intr(instance);
- instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
-
/* Re-fire management commands */
for (j = 0 ; j < instance->max_fw_cmds; j++) {
cmd_fusion = fusion->cmd_list[j];
@@ -2422,7 +2562,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
instance->
cmd_list[cmd_fusion->sync_cmd_idx];
if (cmd_mfi->frame->dcmd.opcode ==
- MR_DCMD_LD_MAP_GET_INFO) {
+ cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO)) {
megasas_return_cmd(instance,
cmd_mfi);
megasas_return_cmd_fusion(
@@ -2433,11 +2573,15 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
instance,
cmd_mfi->context.smid
-1);
- if (!req_desc)
+ if (!req_desc) {
printk(KERN_WARNING
"req_desc NULL"
- "\n");
- else {
+ " for scsi%d\n",
+ instance->host->host_no);
+ /* Return leaked MPT
+ frame */
+ megasas_return_cmd_fusion(instance, cmd_fusion);
+ } else {
instance->instancet->
fire_cmd(instance,
req_desc->
@@ -2451,6 +2595,11 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
}
}
+ clear_bit(MEGASAS_FUSION_IN_RESET,
+ &instance->reset_flags);
+ instance->instancet->enable_intr(instance);
+ instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+
/* Reset load balance info */
memset(fusion->load_balance_info, 0,
sizeof(struct LD_LOAD_BALANCE_INFO)
@@ -2459,18 +2608,39 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
if (!megasas_get_map_info(instance))
megasas_sync_map_info(instance);
+ /* Restart SR-IOV heartbeat */
+ if (instance->requestorId) {
+ if (!megasas_sriov_start_heartbeat(instance, 0))
+ megasas_start_timer(instance,
+ &instance->sriov_heartbeat_timer,
+ megasas_sriov_heartbeat_handler,
+ MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+ else
+ instance->skip_heartbeat_timer_del = 1;
+ }
+
/* Adapter reset completed successfully */
printk(KERN_WARNING "megaraid_sas: Reset "
- "successful.\n");
+ "successful for scsi%d.\n",
+ instance->host->host_no);
retval = SUCCESS;
goto out;
}
/* Reset failed, kill the adapter */
printk(KERN_WARNING "megaraid_sas: Reset failed, killing "
- "adapter.\n");
+ "adapter scsi%d.\n", instance->host->host_no);
megaraid_sas_kill_hba(instance);
+ instance->skip_heartbeat_timer_del = 1;
+ instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
retval = FAILED;
} else {
+ /* For VF: Restart HB timer if we didn't OCR */
+ if (instance->requestorId) {
+ megasas_start_timer(instance,
+ &instance->sriov_heartbeat_timer,
+ megasas_sriov_heartbeat_handler,
+ MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+ }
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
instance->instancet->enable_intr(instance);
instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
@@ -2487,7 +2657,7 @@ void megasas_fusion_ocr_wq(struct work_struct *work)
struct megasas_instance *instance =
container_of(work, struct megasas_instance, work_init);
- megasas_reset_fusion(instance->host);
+ megasas_reset_fusion(instance->host, 0);
}
struct megasas_instance_template megasas_instance_template_fusion = {
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index 35a51397b364..e76af5459a09 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -485,6 +485,9 @@ struct MPI2_IOC_INIT_REQUEST {
#define MAX_PHYSICAL_DEVICES 256
#define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES)
#define MR_DCMD_LD_MAP_GET_INFO 0x0300e101
+#define MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC 0x010e8485 /* SR-IOV HB alloc*/
+#define MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111 0x03200200
+#define MR_DCMD_LD_VF_MAP_GET_ALL_LDS 0x03150200
struct MR_DEV_HANDLE_INFO {
u16 curDevHdl;
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index 62f1a6031765..0d78a4d5576c 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -453,7 +453,7 @@ int __init pas16_detect(struct scsi_host_template * tpnt)
instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, pas16_intr, IRQF_DISABLED,
+ 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);
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index a04b4ff8c7f6..28b4e8139153 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.c
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -323,24 +323,17 @@ static ssize_t pm8001_ctl_ib_queue_log_show(struct device *cdev,
int offset;
char *str = buf;
int start = 0;
-#define IB_MEMMAP(c) \
- (*(u32 *)((u8 *)pm8001_ha-> \
- memoryMap.region[IB].virt_ptr + \
+#define IB_MEMMAP(c) \
+ (*(u32 *)((u8 *)pm8001_ha-> \
+ memoryMap.region[IB].virt_ptr + \
pm8001_ha->evtlog_ib_offset + (c)))
for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
- if (pm8001_ha->chip_id != chip_8001)
- str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));
- else
- str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));
+ str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));
start = start + 4;
}
pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET;
- if ((((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
- && (pm8001_ha->chip_id != chip_8001))
- pm8001_ha->evtlog_ib_offset = 0;
- if ((((pm8001_ha->evtlog_ib_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0)
- && (pm8001_ha->chip_id == chip_8001))
+ if (((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
pm8001_ha->evtlog_ib_offset = 0;
return str - buf;
@@ -363,24 +356,17 @@ static ssize_t pm8001_ctl_ob_queue_log_show(struct device *cdev,
int offset;
char *str = buf;
int start = 0;
-#define OB_MEMMAP(c) \
- (*(u32 *)((u8 *)pm8001_ha-> \
- memoryMap.region[OB].virt_ptr + \
+#define OB_MEMMAP(c) \
+ (*(u32 *)((u8 *)pm8001_ha-> \
+ memoryMap.region[OB].virt_ptr + \
pm8001_ha->evtlog_ob_offset + (c)))
for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
- if (pm8001_ha->chip_id != chip_8001)
- str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));
- else
- str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));
+ str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));
start = start + 4;
}
pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET;
- if ((((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
- && (pm8001_ha->chip_id != chip_8001))
- pm8001_ha->evtlog_ob_offset = 0;
- if ((((pm8001_ha->evtlog_ob_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0)
- && (pm8001_ha->chip_id == chip_8001))
+ if (((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
pm8001_ha->evtlog_ob_offset = 0;
return str - buf;
@@ -466,7 +452,7 @@ static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
- u32 count;
+ ssize_t count;
count = pm80xx_get_fatal_dump(cdev, attr, buf);
return count;
@@ -484,7 +470,7 @@ static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL);
static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
- u32 count;
+ ssize_t count;
count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf);
return count;
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 0a1296a87d66..a97be015e52e 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -644,7 +644,7 @@ static int pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)
pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);
/* 8081 controllers need BAR shift to access MPI space
* as this is shared with BIOS data */
- if (deviceid == 0x8081) {
+ if (deviceid == 0x8081 || deviceid == 0x0042) {
if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) {
PM8001_FAIL_DBG(pm8001_ha,
pm8001_printk("Shift Bar4 to 0x%x failed\n",
@@ -673,7 +673,7 @@ static int pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)
for (i = 0; i < PM8001_MAX_OUTB_NUM; i++)
update_outbnd_queue_table(pm8001_ha, i);
/* 8081 controller donot require these operations */
- if (deviceid != 0x8081) {
+ if (deviceid != 0x8081 && deviceid != 0x0042) {
mpi_set_phys_g3_with_ssc(pm8001_ha, 0);
/* 7->130ms, 34->500ms, 119->1.5s */
mpi_set_open_retry_interval_reg(pm8001_ha, 119);
@@ -701,7 +701,7 @@ static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha)
u32 gst_len_mpistate;
u16 deviceid;
pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);
- if (deviceid == 0x8081) {
+ if (deviceid == 0x8081 || deviceid == 0x0042) {
if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) {
PM8001_FAIL_DBG(pm8001_ha,
pm8001_printk("Shift Bar4 to 0x%x failed\n",
@@ -2502,11 +2502,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*in order to force CPU ordering*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2522,11 +2518,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2550,11 +2542,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2617,11 +2605,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_DS_NON_OPERATIONAL);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2641,11 +2625,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_DS_IN_ERROR);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2674,20 +2654,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
t, status, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- } else if (t->uldd_task) {
- spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* ditto */
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
- } else if (!t->uldd_task) {
+ } else {
spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
}
}
@@ -2796,11 +2765,7 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2909,20 +2874,9 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
t, event, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- } else if (t->uldd_task) {
- spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* ditto */
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
- } else if (!t->uldd_task) {
+ } else {
spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
}
}
@@ -4467,23 +4421,11 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
" stat 0x%x but aborted by upper layer "
"\n", task, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
- } else if (task->uldd_task) {
- spin_unlock_irqrestore(&task->task_state_lock,
- flags);
- pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
- mb();/* ditto */
- spin_unlock_irq(&pm8001_ha->lock);
- task->task_done(task);
- spin_lock_irq(&pm8001_ha->lock);
- return 0;
- } else if (!task->uldd_task) {
+ } else {
spin_unlock_irqrestore(&task->task_state_lock,
flags);
- pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- task->task_done(task);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, task,
+ ccb, tag);
return 0;
}
}
@@ -5020,7 +4962,7 @@ pm8001_get_gsm_dump(struct device *cdev, u32 length, char *buf)
/* check max is 1 Mbytes */
if ((length > 0x100000) || (gsm_dump_offset & 3) ||
((gsm_dump_offset + length) > 0x1000000))
- return 1;
+ return -EINVAL;
if (pm8001_ha->chip_id == chip_8001)
bar = 2;
@@ -5048,12 +4990,12 @@ pm8001_get_gsm_dump(struct device *cdev, u32 length, char *buf)
gsm_base = GSM_BASE;
if (-1 == pm8001_bar4_shift(pm8001_ha,
(gsm_base + shift_value)))
- return 1;
+ return -EIO;
} else {
gsm_base = 0;
if (-1 == pm80xx_bar4_shift(pm8001_ha,
(gsm_base + shift_value)))
- return 1;
+ return -EIO;
}
gsm_dump_offset = (gsm_dump_offset + offset) &
0xFFFF0000;
@@ -5072,13 +5014,8 @@ pm8001_get_gsm_dump(struct device *cdev, u32 length, char *buf)
direct_data += sprintf(direct_data, "%08x ", value);
}
/* Shift back to BAR4 original address */
- if (pm8001_ha->chip_id == chip_8001) {
- if (-1 == pm8001_bar4_shift(pm8001_ha, 0))
- return 1;
- } else {
- if (-1 == pm80xx_bar4_shift(pm8001_ha, 0))
- return 1;
- }
+ if (-1 == pm8001_bar4_shift(pm8001_ha, 0))
+ return -EIO;
pm8001_ha->fatal_forensic_shift_offset += 1024;
if (pm8001_ha->fatal_forensic_shift_offset >= 0x100000)
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 73a120d81b4d..c4f31b21feb8 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -625,7 +625,7 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->nvmd_completion = &completion;
if (pm8001_ha->chip_id == chip_8001) {
- if (deviceid == 0x8081) {
+ if (deviceid == 0x8081 || deviceid == 0x0042) {
payload.minor_function = 4;
payload.length = 4096;
} else {
@@ -646,6 +646,9 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
if (deviceid == 0x8081)
pm8001_ha->sas_addr[j] =
payload.func_specific[0x704 + i];
+ else if (deviceid == 0x0042)
+ pm8001_ha->sas_addr[j] =
+ payload.func_specific[0x010 + i];
} else
pm8001_ha->sas_addr[j] =
payload.func_specific[0x804 + i];
@@ -713,11 +716,9 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
/* SPCv controllers supports 64 msi-x */
if (pm8001_ha->chip_id == chip_8001) {
number_of_intr = 1;
- flag |= IRQF_DISABLED;
} else {
number_of_intr = PM8001_MAX_MSIX_VEC;
flag &= ~IRQF_SHARED;
- flag |= IRQF_DISABLED;
}
max_entry = sizeof(pm8001_ha->msix_entries) /
@@ -1072,10 +1073,7 @@ err_out_enable:
*/
static struct pci_device_id pm8001_pci_table[] = {
{ PCI_VDEVICE(PMC_Sierra, 0x8001), chip_8001 },
- {
- PCI_DEVICE(0x117c, 0x0042),
- .driver_data = chip_8001
- },
+ { PCI_VDEVICE(ATTO, 0x0042), chip_8001 },
/* Support for SPC/SPCv/SPCve controllers */
{ PCI_VDEVICE(ADAPTEC2, 0x8001), chip_8001 },
{ PCI_VDEVICE(PMC_Sierra, 0x8008), chip_8008 },
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index f50ac44b950e..8a44bc92bc78 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -434,6 +434,7 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
ccb->n_elem = n_elem;
ccb->ccb_tag = tag;
ccb->task = t;
+ ccb->device = pm8001_dev;
switch (t->task_proto) {
case SAS_PROTOCOL_SMP:
rc = pm8001_task_prep_smp(pm8001_ha, ccb);
@@ -865,13 +866,11 @@ ex_err:
static void pm8001_dev_gone_notify(struct domain_device *dev)
{
unsigned long flags = 0;
- u32 tag;
struct pm8001_hba_info *pm8001_ha;
struct pm8001_device *pm8001_dev = dev->lldd_dev;
pm8001_ha = pm8001_find_ha_by_dev(dev);
spin_lock_irqsave(&pm8001_ha->lock, flags);
- pm8001_tag_alloc(pm8001_ha, &tag);
if (pm8001_dev) {
u32 device_id = pm8001_dev->device_id;
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 6c5fd5ee22d3..1ee06f21803b 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -708,5 +708,17 @@ ssize_t pm8001_get_gsm_dump(struct device *cdev, u32, char *buf);
/* ctl shared API */
extern struct device_attribute *pm8001_host_attrs[];
+static inline void
+pm8001_ccb_task_free_done(struct pm8001_hba_info *pm8001_ha,
+ struct sas_task *task, struct pm8001_ccb_info *ccb,
+ u32 ccb_idx)
+{
+ pm8001_ccb_task_free(pm8001_ha, task, ccb, ccb_idx);
+ smp_mb(); /*in order to force CPU ordering*/
+ spin_unlock(&pm8001_ha->lock);
+ task->task_done(task);
+ spin_lock(&pm8001_ha->lock);
+}
+
#endif
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index c950dc5c9943..d70587f96184 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -91,7 +91,6 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr;
- u32 status = 1;
u32 accum_len , reg_val, index, *temp;
unsigned long start;
u8 *direct_data;
@@ -111,13 +110,10 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
direct_data = (u8 *)fatal_error_data;
pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL;
pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET;
- pm8001_ha->forensic_info.data_buf.direct_offset = 0;
pm8001_ha->forensic_info.data_buf.read_len = 0;
pm8001_ha->forensic_info.data_buf.direct_data = direct_data;
- }
- if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) {
/* start to get data */
/* Program the MEMBASE II Shifting Register with 0x00.*/
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
@@ -126,6 +122,7 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
pm8001_ha->forensic_fatal_step = 0;
pm8001_ha->fatal_bar_loc = 0;
}
+
/* Read until accum_len is retrived */
accum_len = pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_ACCUM_LEN);
@@ -135,7 +132,7 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("Possible PCI issue 0x%x not expected\n",
accum_len));
- return status;
+ return -EIO;
}
if (accum_len == 0 || accum_len >= 0x100000) {
pm8001_ha->forensic_info.data_buf.direct_data +=
@@ -178,7 +175,6 @@ moreData:
pm8001_ha->forensic_fatal_step = 1;
pm8001_ha->fatal_forensic_shift_offset = 0;
pm8001_ha->forensic_last_offset = 0;
- status = 0;
return (char *)pm8001_ha->
forensic_info.data_buf.direct_data -
(char *)buf;
@@ -194,7 +190,6 @@ moreData:
forensic_info.data_buf.direct_data,
"%08x ", *(temp + index));
}
- status = 0;
return (char *)pm8001_ha->
forensic_info.data_buf.direct_data -
(char *)buf;
@@ -214,7 +209,6 @@ moreData:
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
pm8001_ha->fatal_forensic_shift_offset);
pm8001_ha->fatal_bar_loc = 0;
- status = 0;
return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
(char *)buf;
}
@@ -239,7 +233,7 @@ moreData:
PM8001_FAIL_DBG(pm8001_ha,
pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER"
" = 0x%x\n", reg_val));
- return -1;
+ return -EIO;
}
/* Read the next 64K of the debug data. */
@@ -259,7 +253,6 @@ moreData:
pm8001_ha->forensic_info.data_buf.direct_len = 0;
pm8001_ha->forensic_info.data_buf.direct_offset = 0;
pm8001_ha->forensic_info.data_buf.read_len = 0;
- status = 0;
}
}
@@ -2175,11 +2168,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*in order to force CPU ordering*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2195,11 +2184,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2221,11 +2206,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2288,11 +2269,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_DS_NON_OPERATIONAL);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2312,11 +2289,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
IO_DS_IN_ERROR);
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2345,20 +2318,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
t, status, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- } else if (t->uldd_task) {
- spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* ditto */
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
- } else if (!t->uldd_task) {
+ } else {
spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
}
}
@@ -2470,11 +2432,7 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_QUEUE_FULL;
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
return;
}
break;
@@ -2596,20 +2554,9 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
t, event, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- } else if (t->uldd_task) {
- spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* ditto */
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
- } else if (!t->uldd_task) {
+ } else {
spin_unlock_irqrestore(&t->task_state_lock, flags);
- pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- t->task_done(t);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
}
}
@@ -4304,23 +4251,11 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
"\n", task, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
return 0;
- } else if (task->uldd_task) {
- spin_unlock_irqrestore(&task->task_state_lock,
- flags);
- pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
- mb();/* ditto */
- spin_unlock_irq(&pm8001_ha->lock);
- task->task_done(task);
- spin_lock_irq(&pm8001_ha->lock);
- return 0;
- } else if (!task->uldd_task) {
+ } else {
spin_unlock_irqrestore(&task->task_state_lock,
flags);
- pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
- mb();/*ditto*/
- spin_unlock_irq(&pm8001_ha->lock);
- task->task_done(task);
- spin_lock_irq(&pm8001_ha->lock);
+ pm8001_ccb_task_free_done(pm8001_ha, task,
+ ccb, tag);
return 0;
}
}
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 97dabd39b092..158020522dfb 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -379,14 +379,7 @@
#define DEBUG_PRINT_NVRAM 0
#define DEBUG_QLA1280 0
-/*
- * The SGI VISWS is broken and doesn't support MMIO ;-(
- */
-#ifdef CONFIG_X86_VISWS
-#define MEMORY_MAPPED_IO 0
-#else
#define MEMORY_MAPPED_IO 1
-#endif
#include "qla1280.h"
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
index ff0fc7c7812f..44def6bb4bb0 100644
--- a/drivers/scsi/qla2xxx/Makefile
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -1,6 +1,6 @@
qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o \
- qla_nx.o qla_mr.o qla_nx2.o qla_target.o
+ qla_nx.o qla_mr.o qla_nx2.o qla_target.o qla_tmpl.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
obj-$(CONFIG_TCM_QLA2XXX) += tcm_qla2xxx.o
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 4a0d7c92181f..07befcf365b8 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -147,6 +147,92 @@ static struct bin_attribute sysfs_fw_dump_attr = {
};
static ssize_t
+qla2x00_sysfs_read_fw_dump_template(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+ struct device, kobj)));
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!ha->fw_dump_template || !ha->fw_dump_template_len)
+ return 0;
+
+ ql_dbg(ql_dbg_user, vha, 0x70e2,
+ "chunk <- off=%llx count=%zx\n", off, count);
+ return memory_read_from_buffer(buf, count, &off,
+ ha->fw_dump_template, ha->fw_dump_template_len);
+}
+
+static ssize_t
+qla2x00_sysfs_write_fw_dump_template(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+ struct device, kobj)));
+ struct qla_hw_data *ha = vha->hw;
+ uint32_t size;
+
+ if (off == 0) {
+ if (ha->fw_dump)
+ vfree(ha->fw_dump);
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+
+ ha->fw_dump = NULL;
+ ha->fw_dump_len = 0;
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
+
+ size = qla27xx_fwdt_template_size(buf);
+ ql_dbg(ql_dbg_user, vha, 0x70d1,
+ "-> allocating fwdt (%x bytes)...\n", size);
+ ha->fw_dump_template = vmalloc(size);
+ if (!ha->fw_dump_template) {
+ ql_log(ql_log_warn, vha, 0x70d2,
+ "Failed allocate fwdt (%x bytes).\n", size);
+ return -ENOMEM;
+ }
+ ha->fw_dump_template_len = size;
+ }
+
+ if (off + count > ha->fw_dump_template_len) {
+ count = ha->fw_dump_template_len - off;
+ ql_dbg(ql_dbg_user, vha, 0x70d3,
+ "chunk -> truncating to %zx bytes.\n", count);
+ }
+
+ ql_dbg(ql_dbg_user, vha, 0x70d4,
+ "chunk -> off=%llx count=%zx\n", off, count);
+ memcpy(ha->fw_dump_template + off, buf, count);
+
+ if (off + count == ha->fw_dump_template_len) {
+ size = qla27xx_fwdt_calculate_dump_size(vha);
+ ql_dbg(ql_dbg_user, vha, 0x70d5,
+ "-> allocating fwdump (%x bytes)...\n", size);
+ ha->fw_dump = vmalloc(size);
+ if (!ha->fw_dump) {
+ ql_log(ql_log_warn, vha, 0x70d6,
+ "Failed allocate fwdump (%x bytes).\n", size);
+ return -ENOMEM;
+ }
+ ha->fw_dump_len = size;
+ }
+
+ return count;
+}
+static struct bin_attribute sysfs_fw_dump_template_attr = {
+ .attr = {
+ .name = "fw_dump_template",
+ .mode = S_IRUSR | S_IWUSR,
+ },
+ .size = 0,
+ .read = qla2x00_sysfs_read_fw_dump_template,
+ .write = qla2x00_sysfs_write_fw_dump_template,
+};
+
+static ssize_t
qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
@@ -241,12 +327,17 @@ qla2x00_sysfs_read_optrom(struct file *filp, struct kobject *kobj,
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
struct qla_hw_data *ha = vha->hw;
+ ssize_t rval = 0;
if (ha->optrom_state != QLA_SREADING)
return 0;
- return memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
- ha->optrom_region_size);
+ mutex_lock(&ha->optrom_mutex);
+ rval = memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
+ ha->optrom_region_size);
+ mutex_unlock(&ha->optrom_mutex);
+
+ return rval;
}
static ssize_t
@@ -265,7 +356,9 @@ qla2x00_sysfs_write_optrom(struct file *filp, struct kobject *kobj,
if (off + count > ha->optrom_region_size)
count = ha->optrom_region_size - off;
+ mutex_lock(&ha->optrom_mutex);
memcpy(&ha->optrom_buffer[off], buf, count);
+ mutex_unlock(&ha->optrom_mutex);
return count;
}
@@ -288,10 +381,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
struct qla_hw_data *ha = vha->hw;
-
uint32_t start = 0;
uint32_t size = ha->optrom_size;
int val, valid;
+ ssize_t rval = count;
if (off)
return -EINVAL;
@@ -304,12 +397,14 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
if (start > ha->optrom_size)
return -EINVAL;
+ mutex_lock(&ha->optrom_mutex);
switch (val) {
case 0:
if (ha->optrom_state != QLA_SREADING &&
- ha->optrom_state != QLA_SWRITING)
- return -EINVAL;
-
+ ha->optrom_state != QLA_SWRITING) {
+ rval = -EINVAL;
+ goto out;
+ }
ha->optrom_state = QLA_SWAITING;
ql_dbg(ql_dbg_user, vha, 0x7061,
@@ -320,8 +415,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
ha->optrom_buffer = NULL;
break;
case 1:
- if (ha->optrom_state != QLA_SWAITING)
- return -EINVAL;
+ if (ha->optrom_state != QLA_SWAITING) {
+ rval = -EINVAL;
+ goto out;
+ }
ha->optrom_region_start = start;
ha->optrom_region_size = start + size > ha->optrom_size ?
@@ -335,13 +432,15 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
"(%x).\n", ha->optrom_region_size);
ha->optrom_state = QLA_SWAITING;
- return -ENOMEM;
+ rval = -ENOMEM;
+ goto out;
}
if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x7063,
"HBA not online, failing NVRAM update.\n");
- return -EAGAIN;
+ rval = -EAGAIN;
+ goto out;
}
ql_dbg(ql_dbg_user, vha, 0x7064,
@@ -353,8 +452,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
ha->optrom_region_start, ha->optrom_region_size);
break;
case 2:
- if (ha->optrom_state != QLA_SWAITING)
- return -EINVAL;
+ if (ha->optrom_state != QLA_SWAITING) {
+ rval = -EINVAL;
+ goto out;
+ }
/*
* We need to be more restrictive on which FLASH regions are
@@ -388,7 +489,8 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
if (!valid) {
ql_log(ql_log_warn, vha, 0x7065,
"Invalid start region 0x%x/0x%x.\n", start, size);
- return -EINVAL;
+ rval = -EINVAL;
+ goto out;
}
ha->optrom_region_start = start;
@@ -403,7 +505,8 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
"(%x)\n", ha->optrom_region_size);
ha->optrom_state = QLA_SWAITING;
- return -ENOMEM;
+ rval = -ENOMEM;
+ goto out;
}
ql_dbg(ql_dbg_user, vha, 0x7067,
@@ -413,13 +516,16 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
memset(ha->optrom_buffer, 0, ha->optrom_region_size);
break;
case 3:
- if (ha->optrom_state != QLA_SWRITING)
- return -EINVAL;
+ if (ha->optrom_state != QLA_SWRITING) {
+ rval = -EINVAL;
+ goto out;
+ }
if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x7068,
"HBA not online, failing flash update.\n");
- return -EAGAIN;
+ rval = -EAGAIN;
+ goto out;
}
ql_dbg(ql_dbg_user, vha, 0x7069,
@@ -430,9 +536,12 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
ha->optrom_region_start, ha->optrom_region_size);
break;
default:
- return -EINVAL;
+ rval = -EINVAL;
}
- return count;
+
+out:
+ mutex_unlock(&ha->optrom_mutex);
+ return rval;
}
static struct bin_attribute sysfs_optrom_ctl_attr = {
@@ -822,6 +931,7 @@ static struct sysfs_entry {
int is4GBp_only;
} bin_file_entries[] = {
{ "fw_dump", &sysfs_fw_dump_attr, },
+ { "fw_dump_template", &sysfs_fw_dump_template_attr, 0x27 },
{ "nvram", &sysfs_nvram_attr, },
{ "optrom", &sysfs_optrom_attr, },
{ "optrom_ctl", &sysfs_optrom_ctl_attr, },
@@ -847,6 +957,8 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha)
continue;
if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw)))
continue;
+ if (iter->is4GBp_only == 0x27 && !IS_QLA27XX(vha->hw))
+ continue;
ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
iter->attr);
@@ -1187,7 +1299,7 @@ qla2x00_optrom_gold_fw_version_show(struct device *dev,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
+ if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && !IS_QLA27XX(ha))
return scnprintf(buf, PAGE_SIZE, "\n");
return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%d)\n",
@@ -1391,6 +1503,37 @@ qla2x00_fw_dump_size_show(struct device *dev, struct device_attribute *attr,
return scnprintf(buf, PAGE_SIZE, "%d\n", size);
}
+static ssize_t
+qla2x00_allow_cna_fw_dump_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
+ if (!IS_P3P_TYPE(vha->hw))
+ return scnprintf(buf, PAGE_SIZE, "\n");
+ else
+ return scnprintf(buf, PAGE_SIZE, "%s\n",
+ vha->hw->allow_cna_fw_dump ? "true" : "false");
+}
+
+static ssize_t
+qla2x00_allow_cna_fw_dump_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int val = 0;
+
+ if (!IS_P3P_TYPE(vha->hw))
+ return -EINVAL;
+
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+
+ vha->hw->allow_cna_fw_dump = val != 0;
+
+ return strlen(buf);
+}
+
static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
@@ -1432,6 +1575,9 @@ static DEVICE_ATTR(thermal_temp, S_IRUGO, qla2x00_thermal_temp_show, NULL);
static DEVICE_ATTR(diag_requests, S_IRUGO, qla2x00_diag_requests_show, NULL);
static DEVICE_ATTR(diag_megabytes, S_IRUGO, qla2x00_diag_megabytes_show, NULL);
static DEVICE_ATTR(fw_dump_size, S_IRUGO, qla2x00_fw_dump_size_show, NULL);
+static DEVICE_ATTR(allow_cna_fw_dump, S_IRUGO | S_IWUSR,
+ qla2x00_allow_cna_fw_dump_show,
+ qla2x00_allow_cna_fw_dump_store);
struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_driver_version,
@@ -1464,6 +1610,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_diag_requests,
&dev_attr_diag_megabytes,
&dev_attr_fw_dump_size,
+ &dev_attr_allow_cna_fw_dump,
NULL,
};
@@ -1509,6 +1656,9 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
case PORT_SPEED_16GB:
speed = FC_PORTSPEED_16GBIT;
break;
+ case PORT_SPEED_32GB:
+ speed = FC_PORTSPEED_32GBIT;
+ break;
}
fc_host_speed(shost) = speed;
}
@@ -2160,6 +2310,9 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha)
else if (IS_QLAFX00(ha))
speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT |
FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
+ else if (IS_QLA27XX(ha))
+ speed = FC_PORTSPEED_32GBIT | FC_PORTSPEED_16GBIT |
+ FC_PORTSPEED_8GBIT;
else
speed = FC_PORTSPEED_1GBIT;
fc_host_supported_speeds(vha->host) = speed;
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index f15d03e6b7ee..71ff340f6de4 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -1437,9 +1437,12 @@ qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
if (ha->flags.nic_core_reset_hdlr_active)
return -EBUSY;
+ mutex_lock(&ha->optrom_mutex);
rval = qla2x00_optrom_setup(bsg_job, vha, 0);
- if (rval)
+ if (rval) {
+ mutex_unlock(&ha->optrom_mutex);
return rval;
+ }
ha->isp_ops->read_optrom(vha, ha->optrom_buffer,
ha->optrom_region_start, ha->optrom_region_size);
@@ -1453,6 +1456,7 @@ qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
vfree(ha->optrom_buffer);
ha->optrom_buffer = NULL;
ha->optrom_state = QLA_SWAITING;
+ mutex_unlock(&ha->optrom_mutex);
bsg_job->job_done(bsg_job);
return rval;
}
@@ -1465,9 +1469,12 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
struct qla_hw_data *ha = vha->hw;
int rval = 0;
+ mutex_lock(&ha->optrom_mutex);
rval = qla2x00_optrom_setup(bsg_job, vha, 1);
- if (rval)
+ if (rval) {
+ mutex_unlock(&ha->optrom_mutex);
return rval;
+ }
/* Set the isp82xx_no_md_cap not to capture minidump */
ha->flags.isp82xx_no_md_cap = 1;
@@ -1483,6 +1490,7 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
vfree(ha->optrom_buffer);
ha->optrom_buffer = NULL;
ha->optrom_state = QLA_SWAITING;
+ mutex_unlock(&ha->optrom_mutex);
bsg_job->job_done(bsg_job);
return rval;
}
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index f6103f553bb1..97255f7c3975 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -11,13 +11,15 @@
* ----------------------------------------------------------------------
* | Level | Last Value Used | Holes |
* ----------------------------------------------------------------------
- * | Module Init and Probe | 0x015b | 0x4b,0xba,0xfa |
- * | | | 0x0x015a |
- * | Mailbox commands | 0x1187 | 0x111a-0x111b |
- * | | | 0x1155-0x1158 |
- * | | | 0x1018-0x1019 |
+ * | Module Init and Probe | 0x017d | 0x004b,0x0141 |
+ * | | | 0x0144,0x0146 |
+ * | | | 0x015b-0x0160 |
+ * | | | 0x016e-0x0170 |
+ * | Mailbox commands | 0x1187 | 0x1018-0x1019 |
+ * | | | 0x10ca |
* | | | 0x1115-0x1116 |
- * | | | 0x10ca |
+ * | | | 0x111a-0x111b |
+ * | | | 0x1155-0x1158 |
* | Device Discovery | 0x2095 | 0x2020-0x2022, |
* | | | 0x2011-0x2012, |
* | | | 0x2016 |
@@ -32,18 +34,17 @@
* | | | 0x5047,0x5052 |
* | | | 0x5084,0x5075 |
* | | | 0x503d,0x5044 |
+ * | | | 0x507b |
* | Timer Routines | 0x6012 | |
- * | User Space Interactions | 0x70e1 | 0x7018,0x702e, |
- * | | | 0x7020,0x7024, |
- * | | | 0x7039,0x7045, |
- * | | | 0x7073-0x7075, |
- * | | | 0x707b,0x708c, |
- * | | | 0x70a5,0x70a6, |
- * | | | 0x70a8,0x70ab, |
- * | | | 0x70ad-0x70ae, |
- * | | | 0x70d1-0x70db, |
- * | | | 0x7047,0x703b |
- * | | | 0x70de-0x70df, |
+ * | User Space Interactions | 0x70e2 | 0x7018,0x702e |
+ * | | | 0x7020,0x7024 |
+ * | | | 0x7039,0x7045 |
+ * | | | 0x7073-0x7075 |
+ * | | | 0x70a5-0x70a6 |
+ * | | | 0x70a8,0x70ab |
+ * | | | 0x70ad-0x70ae |
+ * | | | 0x70d7-0x70db |
+ * | | | 0x70de-0x70df |
* | Task Management | 0x803d | 0x8025-0x8026 |
* | | | 0x800b,0x8039 |
* | AER/EEH | 0x9011 | |
@@ -59,7 +60,11 @@
* | | | 0xb13c-0xb140 |
* | | | 0xb149 |
* | MultiQ | 0xc00c | |
- * | Misc | 0xd010 | |
+ * | Misc | 0xd2ff | 0xd017-0xd019 |
+ * | | | 0xd020 |
+ * | | | 0xd02e-0xd0ff |
+ * | | | 0xd101-0xd1fe |
+ * | | | 0xd212-0xd2fe |
* | Target Mode | 0xe070 | 0xe021 |
* | Target Mode Management | 0xf072 | 0xf002-0xf003 |
* | | | 0xf046-0xf049 |
@@ -104,7 +109,87 @@ qla2xxx_copy_queues(struct qla_hw_data *ha, void *ptr)
return ptr + (rsp->length * sizeof(response_t));
}
-static int
+int
+qla27xx_dump_mpi_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
+ uint32_t ram_dwords, void **nxt)
+{
+ int rval;
+ uint32_t cnt, stat, timer, dwords, idx;
+ uint16_t mb0, mb1;
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ dma_addr_t dump_dma = ha->gid_list_dma;
+ uint32_t *dump = (uint32_t *)ha->gid_list;
+
+ rval = QLA_SUCCESS;
+ mb0 = 0;
+
+ WRT_REG_WORD(&reg->mailbox0, MBC_LOAD_DUMP_MPI_RAM);
+ clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+
+ dwords = qla2x00_gid_list_size(ha) / 4;
+ for (cnt = 0; cnt < ram_dwords && rval == QLA_SUCCESS;
+ cnt += dwords, addr += dwords) {
+ if (cnt + dwords > ram_dwords)
+ dwords = ram_dwords - cnt;
+
+ WRT_REG_WORD(&reg->mailbox1, LSW(addr));
+ WRT_REG_WORD(&reg->mailbox8, MSW(addr));
+
+ WRT_REG_WORD(&reg->mailbox2, MSW(dump_dma));
+ WRT_REG_WORD(&reg->mailbox3, LSW(dump_dma));
+ WRT_REG_WORD(&reg->mailbox6, MSW(MSD(dump_dma)));
+ WRT_REG_WORD(&reg->mailbox7, LSW(MSD(dump_dma)));
+
+ WRT_REG_WORD(&reg->mailbox4, MSW(dwords));
+ WRT_REG_WORD(&reg->mailbox5, LSW(dwords));
+
+ WRT_REG_WORD(&reg->mailbox9, 0);
+ WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
+
+ ha->flags.mbox_int = 0;
+ for (timer = 6000000; timer; timer--) {
+ /* Check for pending interrupts. */
+ stat = RD_REG_DWORD(&reg->host_status);
+ if (stat & HSRX_RISC_INT) {
+ stat &= 0xff;
+
+ if (stat == 0x1 || stat == 0x2 ||
+ stat == 0x10 || stat == 0x11) {
+ set_bit(MBX_INTERRUPT,
+ &ha->mbx_cmd_flags);
+
+ mb0 = RD_REG_WORD(&reg->mailbox0);
+ mb1 = RD_REG_WORD(&reg->mailbox1);
+
+ WRT_REG_DWORD(&reg->hccr,
+ HCCRX_CLR_RISC_INT);
+ RD_REG_DWORD(&reg->hccr);
+ break;
+ }
+
+ /* Clear this intr; it wasn't a mailbox intr */
+ WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+ RD_REG_DWORD(&reg->hccr);
+ }
+ udelay(5);
+ }
+ ha->flags.mbox_int = 1;
+
+ if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
+ rval = mb0 & MBS_MASK;
+ for (idx = 0; idx < dwords; idx++)
+ ram[cnt + idx] = IS_QLA27XX(ha) ?
+ le32_to_cpu(dump[idx]) : swab32(dump[idx]);
+ } else {
+ rval = QLA_FUNCTION_FAILED;
+ }
+ }
+
+ *nxt = rval == QLA_SUCCESS ? &ram[cnt] : NULL;
+ return rval;
+}
+
+int
qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
uint32_t ram_dwords, void **nxt)
{
@@ -139,6 +224,7 @@ qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
WRT_REG_WORD(&reg->mailbox5, LSW(dwords));
WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
+ ha->flags.mbox_int = 0;
for (timer = 6000000; timer; timer--) {
/* Check for pending interrupts. */
stat = RD_REG_DWORD(&reg->host_status);
@@ -164,11 +250,13 @@ qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
}
udelay(5);
}
+ ha->flags.mbox_int = 1;
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb0 & MBS_MASK;
for (idx = 0; idx < dwords; idx++)
- ram[cnt + idx] = swab32(dump[idx]);
+ ram[cnt + idx] = IS_QLA27XX(ha) ?
+ le32_to_cpu(dump[idx]) : swab32(dump[idx]);
} else {
rval = QLA_FUNCTION_FAILED;
}
@@ -208,7 +296,7 @@ qla24xx_read_window(struct device_reg_24xx __iomem *reg, uint32_t iobase,
return buf;
}
-static inline int
+int
qla24xx_pause_risc(struct device_reg_24xx __iomem *reg)
{
int rval = QLA_SUCCESS;
@@ -227,7 +315,7 @@ qla24xx_pause_risc(struct device_reg_24xx __iomem *reg)
return rval;
}
-static int
+int
qla24xx_soft_reset(struct qla_hw_data *ha)
{
int rval = QLA_SUCCESS;
@@ -537,7 +625,7 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
struct qla2xxx_mq_chain *mq = ptr;
device_reg_t __iomem *reg;
- if (!ha->mqenable || IS_QLA83XX(ha))
+ if (!ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha))
return ptr;
mq = ptr;
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index 35e20b4f8b6c..cc961040f8b1 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -348,3 +348,10 @@ ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...);
#define ql_dbg_tgt 0x00004000 /* Target mode */
#define ql_dbg_tgt_mgt 0x00002000 /* Target mode management */
#define ql_dbg_tgt_tmr 0x00001000 /* Target mode task management */
+
+extern int qla27xx_dump_mpi_ram(struct qla_hw_data *, uint32_t, uint32_t *,
+ uint32_t, void **);
+extern int qla24xx_dump_ram(struct qla_hw_data *, uint32_t, uint32_t *,
+ uint32_t, void **);
+extern int qla24xx_pause_risc(struct device_reg_24xx __iomem *);
+extern int qla24xx_soft_reset(struct qla_hw_data *);
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index e1fe95ef23e1..6a106136716c 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -654,7 +654,7 @@ typedef union {
struct device_reg_25xxmq isp25mq;
struct device_reg_82xx isp82;
struct device_reg_fx00 ispfx00;
-} device_reg_t;
+} __iomem device_reg_t;
#define ISP_REQ_Q_IN(ha, reg) \
(IS_QLA2100(ha) || IS_QLA2200(ha) ? \
@@ -808,7 +808,7 @@ struct mbx_cmd_32 {
Notification */
#define MBA_FW_POLL_STATE 0x8600 /* Firmware in poll diagnostic state */
#define MBA_FW_RESET_FCT 0x8502 /* Firmware reset factory defaults */
-
+#define MBA_FW_INIT_INPROGRESS 0x8500 /* Firmware boot in progress */
/* 83XX FCoE specific */
#define MBA_IDC_AEN 0x8200 /* FCoE: NIC Core state change AEN */
@@ -938,6 +938,7 @@ struct mbx_cmd_32 {
*/
#define MBC_WRITE_SERDES 0x3 /* Write serdes word. */
#define MBC_READ_SERDES 0x4 /* Read serdes word. */
+#define MBC_LOAD_DUMP_MPI_RAM 0x5 /* Load/Dump MPI RAM. */
#define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */
#define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */
#define MBC_PORT_PARAMS 0x1A /* Port iDMA Parameters. */
@@ -1197,30 +1198,6 @@ typedef struct {
uint8_t reserved_3[26];
} init_cb_t;
-
-struct init_cb_fx {
- uint16_t version;
- uint16_t reserved_1[13];
- __le16 request_q_outpointer;
- __le16 response_q_inpointer;
- uint16_t reserved_2[2];
- __le16 response_q_length;
- __le16 request_q_length;
- uint16_t reserved_3[2];
- __le32 request_q_address[2];
- __le32 response_q_address[2];
- uint16_t reserved_4[4];
- uint8_t response_q_msivec;
- uint8_t reserved_5[19];
- uint16_t interrupt_delay_timer;
- uint16_t reserved_6;
- uint32_t fwoptions1;
- uint32_t fwoptions2;
- uint32_t fwoptions3;
- uint8_t reserved_7[24];
-};
-
-
/*
* Get Link Status mailbox command return buffer.
*/
@@ -2172,6 +2149,7 @@ struct ct_fdmi_hba_attributes {
#define FDMI_PORT_SPEED_4GB 0x8
#define FDMI_PORT_SPEED_8GB 0x10
#define FDMI_PORT_SPEED_16GB 0x20
+#define FDMI_PORT_SPEED_32GB 0x40
#define FDMI_PORT_SPEED_UNKNOWN 0x8000
struct ct_fdmi_port_attr {
@@ -2680,7 +2658,7 @@ struct bidi_statistics {
#define QLA_MQ_SIZE 32
#define QLA_MAX_QUEUES 256
#define ISP_QUE_REG(ha, id) \
- ((ha->mqenable || IS_QLA83XX(ha)) ? \
+ ((ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) ? \
((void __iomem *)ha->mqiobase + (QLA_QUE_PAGE * id)) :\
((void __iomem *)ha->iobase))
#define QLA_REQ_QUE_ID(tag) \
@@ -2818,7 +2796,6 @@ struct qla_hw_data {
uint32_t fac_supported :1;
uint32_t chip_reset_done :1;
- uint32_t port0 :1;
uint32_t running_gold_fw :1;
uint32_t eeh_busy :1;
uint32_t cpu_affinity_enabled :1;
@@ -2849,7 +2826,7 @@ struct qla_hw_data {
spinlock_t hardware_lock ____cacheline_aligned;
int bars;
int mem_only;
- device_reg_t __iomem *iobase; /* Base I/O address */
+ device_reg_t *iobase; /* Base I/O address */
resource_size_t pio_address;
#define MIN_IOBASE_LEN 0x100
@@ -2868,8 +2845,8 @@ struct qla_hw_data {
uint32_t rsp_que_off;
/* Multi queue data structs */
- device_reg_t __iomem *mqiobase;
- device_reg_t __iomem *msixbase;
+ device_reg_t *mqiobase;
+ device_reg_t *msixbase;
uint16_t msix_count;
uint8_t mqenable;
struct req_que **req_q_map;
@@ -2905,6 +2882,7 @@ struct qla_hw_data {
#define PORT_SPEED_4GB 0x03
#define PORT_SPEED_8GB 0x04
#define PORT_SPEED_16GB 0x05
+#define PORT_SPEED_32GB 0x06
#define PORT_SPEED_10GB 0x13
uint16_t link_data_rate; /* F/W operating speed */
@@ -2928,6 +2906,7 @@ struct qla_hw_data {
#define PCI_DEVICE_ID_QLOGIC_ISP8001 0x8001
#define PCI_DEVICE_ID_QLOGIC_ISP8031 0x8031
#define PCI_DEVICE_ID_QLOGIC_ISP2031 0x2031
+#define PCI_DEVICE_ID_QLOGIC_ISP2071 0x2071
uint32_t device_type;
#define DT_ISP2100 BIT_0
#define DT_ISP2200 BIT_1
@@ -2948,7 +2927,8 @@ struct qla_hw_data {
#define DT_ISP8031 BIT_16
#define DT_ISPFX00 BIT_17
#define DT_ISP8044 BIT_18
-#define DT_ISP_LAST (DT_ISP8044 << 1)
+#define DT_ISP2071 BIT_19
+#define DT_ISP_LAST (DT_ISP2071 << 1)
#define DT_T10_PI BIT_25
#define DT_IIDMA BIT_26
@@ -2978,6 +2958,7 @@ struct qla_hw_data {
#define IS_QLA2031(ha) (DT_MASK(ha) & DT_ISP2031)
#define IS_QLA8031(ha) (DT_MASK(ha) & DT_ISP8031)
#define IS_QLAFX00(ha) (DT_MASK(ha) & DT_ISPFX00)
+#define IS_QLA2071(ha) (DT_MASK(ha) & DT_ISP2071)
#define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
IS_QLA6312(ha) || IS_QLA6322(ha))
@@ -2986,6 +2967,7 @@ struct qla_hw_data {
#define IS_QLA25XX(ha) (IS_QLA2532(ha))
#define IS_QLA83XX(ha) (IS_QLA2031(ha) || IS_QLA8031(ha))
#define IS_QLA84XX(ha) (IS_QLA8432(ha))
+#define IS_QLA27XX(ha) (IS_QLA2071(ha))
#define IS_QLA24XX_TYPE(ha) (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
IS_QLA84XX(ha))
#define IS_CNA_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA82XX(ha) || \
@@ -2994,12 +2976,13 @@ struct qla_hw_data {
#define IS_QLA2XXX_MIDTYPE(ha) (IS_QLA24XX(ha) || IS_QLA84XX(ha) || \
IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
IS_QLA82XX(ha) || IS_QLA83XX(ha) || \
- IS_QLA8044(ha))
+ IS_QLA8044(ha) || IS_QLA27XX(ha))
#define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha))
-#define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
- IS_QLA83XX(ha)) && (ha)->flags.msix_enabled)
-#define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha))
-#define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha))
+#define IS_NOPOLLING_TYPE(ha) (IS_QLA81XX(ha) && (ha)->flags.msix_enabled)
+#define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
+ IS_QLA27XX(ha))
+#define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
+ IS_QLA27XX(ha))
#define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha))
#define IS_T10_PI_CAPABLE(ha) ((ha)->device_type & DT_T10_PI)
@@ -3009,7 +2992,8 @@ struct qla_hw_data {
#define IS_OEM_001(ha) ((ha)->device_type & DT_OEM_001)
#define HAS_EXTENDED_IDS(ha) ((ha)->device_type & DT_EXTENDED_IDS)
#define IS_CT6_SUPPORTED(ha) ((ha)->device_type & DT_CT6_SUPPORTED)
-#define IS_MQUE_CAPABLE(ha) ((ha)->mqenable || IS_QLA83XX(ha))
+#define IS_MQUE_CAPABLE(ha) ((ha)->mqenable || IS_QLA83XX(ha) || \
+ IS_QLA27XX(ha))
#define IS_BIDI_CAPABLE(ha) ((IS_QLA25XX(ha) || IS_QLA2031(ha)))
/* Bit 21 of fw_attributes decides the MCTP capabilities */
#define IS_MCTP_CAPABLE(ha) (IS_QLA2031(ha) && \
@@ -3134,6 +3118,9 @@ struct qla_hw_data {
uint16_t fw_xcb_count;
uint16_t fw_iocb_count;
+ uint32_t fw_shared_ram_start;
+ uint32_t fw_shared_ram_end;
+
uint16_t fw_options[16]; /* slots: 1,2,3,10,11 */
uint8_t fw_seriallink_options[4];
uint16_t fw_seriallink_options24[4];
@@ -3142,6 +3129,9 @@ struct qla_hw_data {
uint32_t mpi_capabilities;
uint8_t phy_version[3];
+ /* Firmware dump template */
+ void *fw_dump_template;
+ uint32_t fw_dump_template_len;
/* Firmware dump information. */
struct qla2xxx_fw_dump *fw_dump;
uint32_t fw_dump_len;
@@ -3184,6 +3174,7 @@ struct qla_hw_data {
#define QLA_SWRITING 2
uint32_t optrom_region_start;
uint32_t optrom_region_size;
+ struct mutex optrom_mutex;
/* PCI expansion ROM image information. */
#define ROM_CODE_TYPE_BIOS 0
@@ -3310,6 +3301,7 @@ struct qla_hw_data {
struct mr_data_fx00 mr;
struct qlt_hw_data tgt;
+ int allow_cna_fw_dump;
};
/*
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 792a29294b62..32ab80957688 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -114,7 +114,8 @@ qla2x00_dfs_setup(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
+ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
+ !IS_QLA27XX(ha))
goto out;
if (!ha->fce)
goto out;
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 610d3aa905a0..3a7353eaccbd 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1378,6 +1378,10 @@ struct qla_flt_header {
#define FLT_REG_NVRAM_0 0x15
#define FLT_REG_VPD_1 0x16
#define FLT_REG_NVRAM_1 0x17
+#define FLT_REG_VPD_2 0xD4
+#define FLT_REG_NVRAM_2 0xD5
+#define FLT_REG_VPD_3 0xD6
+#define FLT_REG_NVRAM_3 0xD7
#define FLT_REG_FDT 0x1a
#define FLT_REG_FLT 0x1c
#define FLT_REG_HW_EVENT_0 0x1d
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 1f426628a0a5..e665e8109933 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -330,6 +330,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *,
dma_addr_t);
extern int qla24xx_abort_command(srb_t *);
+extern int qla24xx_async_abort_command(srb_t *);
extern int
qla24xx_abort_target(struct fc_port *, unsigned int, int);
extern int
@@ -511,6 +512,16 @@ extern void qla2300_fw_dump(scsi_qla_host_t *, int);
extern void qla24xx_fw_dump(scsi_qla_host_t *, int);
extern void qla25xx_fw_dump(scsi_qla_host_t *, int);
extern void qla81xx_fw_dump(scsi_qla_host_t *, int);
+extern void qla82xx_fw_dump(scsi_qla_host_t *, int);
+extern void qla8044_fw_dump(scsi_qla_host_t *, int);
+
+extern void qla27xx_fwdump(scsi_qla_host_t *, int);
+extern ulong qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *);
+extern int qla27xx_fwdt_template_valid(void *);
+extern ulong qla27xx_fwdt_template_size(void *);
+extern const void *qla27xx_fwdt_template_default(void);
+extern ulong qla27xx_fwdt_template_default_size(void);
+
extern void qla2x00_dump_regs(scsi_qla_host_t *);
extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t);
@@ -594,7 +605,6 @@ extern char *qlafx00_fw_version_str(struct scsi_qla_host *, char *);
extern irqreturn_t qlafx00_intr_handler(int, void *);
extern void qlafx00_enable_intrs(struct qla_hw_data *);
extern void qlafx00_disable_intrs(struct qla_hw_data *);
-extern int qlafx00_abort_command(srb_t *);
extern int qlafx00_abort_target(fc_port_t *, unsigned int, int);
extern int qlafx00_lun_reset(fc_port_t *, unsigned int, int);
extern int qlafx00_start_scsi(srb_t *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index cd47f1b32d9a..e377f9d2f92a 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1532,6 +1532,10 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
if (IS_CNA_CAPABLE(ha))
eiter->a.sup_speed = __constant_cpu_to_be32(
FDMI_PORT_SPEED_10GB);
+ else if (IS_QLA27XX(ha))
+ eiter->a.sup_speed = __constant_cpu_to_be32(
+ FDMI_PORT_SPEED_32GB|FDMI_PORT_SPEED_16GB|
+ FDMI_PORT_SPEED_8GB);
else if (IS_QLA25XX(ha))
eiter->a.sup_speed = __constant_cpu_to_be32(
FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB|
@@ -1580,6 +1584,10 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
eiter->a.cur_speed =
__constant_cpu_to_be32(FDMI_PORT_SPEED_16GB);
break;
+ case PORT_SPEED_32GB:
+ eiter->a.cur_speed =
+ __constant_cpu_to_be32(FDMI_PORT_SPEED_32GB);
+ break;
default:
eiter->a.cur_speed =
__constant_cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN);
@@ -1889,6 +1897,9 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
case BIT_10:
list[i].fp_speed = PORT_SPEED_16GB;
break;
+ case BIT_8:
+ list[i].fp_speed = PORT_SPEED_32GB;
+ break;
}
ql_dbg(ql_dbg_disc, vha, 0x205b,
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index e7e5f4facf7f..38aeb54cd9d8 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -271,56 +271,46 @@ done:
}
static void
-qla2x00_async_tm_cmd_done(void *data, void *ptr, int res)
+qla2x00_tmf_iocb_timeout(void *data)
{
- srb_t *sp = (srb_t *)ptr;
- struct srb_iocb *iocb = &sp->u.iocb_cmd;
- struct scsi_qla_host *vha = (scsi_qla_host_t *)data;
- uint32_t flags;
- uint16_t lun;
- int rval;
-
- if (!test_bit(UNLOADING, &vha->dpc_flags)) {
- flags = iocb->u.tmf.flags;
- lun = (uint16_t)iocb->u.tmf.lun;
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *tmf = &sp->u.iocb_cmd;
- /* Issue Marker IOCB */
- rval = qla2x00_marker(vha, vha->hw->req_q_map[0],
- vha->hw->rsp_q_map[0], sp->fcport->loop_id, lun,
- flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
+ tmf->u.tmf.comp_status = CS_TIMEOUT;
+ complete(&tmf->u.tmf.comp);
+}
- if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) {
- ql_dbg(ql_dbg_taskm, vha, 0x8030,
- "TM IOCB failed (%x).\n", rval);
- }
- }
- sp->free(sp->fcport->vha, sp);
+static void
+qla2x00_tmf_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ struct srb_iocb *tmf = &sp->u.iocb_cmd;
+ complete(&tmf->u.tmf.comp);
}
int
-qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t tm_flags, uint32_t lun,
+qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
uint32_t tag)
{
struct scsi_qla_host *vha = fcport->vha;
+ struct srb_iocb *tm_iocb;
srb_t *sp;
- struct srb_iocb *tcf;
- int rval;
+ int rval = QLA_FUNCTION_FAILED;
- rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
if (!sp)
goto done;
+ tm_iocb = &sp->u.iocb_cmd;
sp->type = SRB_TM_CMD;
sp->name = "tmf";
- qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
-
- tcf = &sp->u.iocb_cmd;
- tcf->u.tmf.flags = tm_flags;
- tcf->u.tmf.lun = lun;
- tcf->u.tmf.data = tag;
- tcf->timeout = qla2x00_async_iocb_timeout;
- sp->done = qla2x00_async_tm_cmd_done;
+ qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha));
+ tm_iocb->u.tmf.flags = flags;
+ tm_iocb->u.tmf.lun = lun;
+ tm_iocb->u.tmf.data = tag;
+ sp->done = qla2x00_tmf_sp_done;
+ tm_iocb->timeout = qla2x00_tmf_iocb_timeout;
+ init_completion(&tm_iocb->u.tmf.comp);
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS)
@@ -330,14 +320,121 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t tm_flags, uint32_t lun,
"Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n",
sp->handle, fcport->loop_id, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ wait_for_completion(&tm_iocb->u.tmf.comp);
+
+ rval = tm_iocb->u.tmf.comp_status == CS_COMPLETE ?
+ QLA_SUCCESS : QLA_FUNCTION_FAILED;
+
+ if ((rval != QLA_SUCCESS) || tm_iocb->u.tmf.data) {
+ ql_dbg(ql_dbg_taskm, vha, 0x8030,
+ "TM IOCB failed (%x).\n", rval);
+ }
+
+ if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) {
+ flags = tm_iocb->u.tmf.flags;
+ lun = (uint16_t)tm_iocb->u.tmf.lun;
+
+ /* Issue Marker IOCB */
+ qla2x00_marker(vha, vha->hw->req_q_map[0],
+ vha->hw->rsp_q_map[0], sp->fcport->loop_id, lun,
+ flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
+ }
+
+done_free_sp:
+ sp->free(vha, sp);
+done:
return rval;
+}
+
+static void
+qla24xx_abort_iocb_timeout(void *data)
+{
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *abt = &sp->u.iocb_cmd;
+
+ abt->u.abt.comp_status = CS_TIMEOUT;
+ complete(&abt->u.abt.comp);
+}
+
+static void
+qla24xx_abort_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ struct srb_iocb *abt = &sp->u.iocb_cmd;
+
+ complete(&abt->u.abt.comp);
+}
+
+static int
+qla24xx_async_abort_cmd(srb_t *cmd_sp)
+{
+ scsi_qla_host_t *vha = cmd_sp->fcport->vha;
+ fc_port_t *fcport = cmd_sp->fcport;
+ struct srb_iocb *abt_iocb;
+ srb_t *sp;
+ int rval = QLA_FUNCTION_FAILED;
+
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp)
+ goto done;
+
+ abt_iocb = &sp->u.iocb_cmd;
+ sp->type = SRB_ABT_CMD;
+ sp->name = "abort";
+ qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha));
+ abt_iocb->u.abt.cmd_hndl = cmd_sp->handle;
+ sp->done = qla24xx_abort_sp_done;
+ abt_iocb->timeout = qla24xx_abort_iocb_timeout;
+ init_completion(&abt_iocb->u.abt.comp);
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
+
+ ql_dbg(ql_dbg_async, vha, 0x507c,
+ "Abort command issued - hdl=%x, target_id=%x\n",
+ cmd_sp->handle, fcport->tgt_id);
+
+ wait_for_completion(&abt_iocb->u.abt.comp);
+
+ rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ?
+ QLA_SUCCESS : QLA_FUNCTION_FAILED;
done_free_sp:
- sp->free(fcport->vha, sp);
+ sp->free(vha, sp);
done:
return rval;
}
+int
+qla24xx_async_abort_command(srb_t *sp)
+{
+ unsigned long flags = 0;
+
+ uint32_t handle;
+ fc_port_t *fcport = sp->fcport;
+ struct scsi_qla_host *vha = fcport->vha;
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = vha->req;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (handle = 1; handle < req->num_outstanding_cmds; handle++) {
+ if (req->outstanding_cmds[handle] == sp)
+ break;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if (handle == req->num_outstanding_cmds) {
+ /* Command not found. */
+ return QLA_FUNCTION_FAILED;
+ }
+ if (sp->type == SRB_FXIOCB_DCMD)
+ return qlafx00_fx_disc(vha, &vha->hw->mr.fcport,
+ FXDISC_ABORT_IOCTL);
+
+ return qla24xx_async_abort_cmd(sp);
+}
+
void
qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
@@ -1379,7 +1476,12 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
}
ha->fw_dumped = 0;
- fixed_size = mem_size = eft_size = fce_size = mq_size = 0;
+ dump_size = fixed_size = mem_size = eft_size = fce_size = mq_size = 0;
+ req_q_size = rsp_q_size = 0;
+
+ if (IS_QLA27XX(ha))
+ goto try_fce;
+
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
fixed_size = sizeof(struct qla2100_fw_dump);
} else if (IS_QLA23XX(ha)) {
@@ -1395,6 +1497,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem);
else
fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
+
mem_size = (ha->fw_memory_size - 0x100000 + 1) *
sizeof(uint32_t);
if (ha->mqenable) {
@@ -1412,9 +1515,16 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
if (ha->tgt.atio_ring)
mq_size += ha->tgt.atio_q_length * sizeof(request_t);
/* Allocate memory for Fibre Channel Event Buffer. */
- if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
+ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
+ !IS_QLA27XX(ha))
goto try_eft;
+try_fce:
+ if (ha->fce)
+ dma_free_coherent(&ha->pdev->dev,
+ FCE_SIZE, ha->fce, ha->fce_dma);
+
+ /* Allocate memory for Fibre Channel Event Buffer. */
tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
GFP_KERNEL);
if (!tc) {
@@ -1442,7 +1552,12 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
ha->flags.fce_enabled = 1;
ha->fce_dma = tc_dma;
ha->fce = tc;
+
try_eft:
+ if (ha->eft)
+ dma_free_coherent(&ha->pdev->dev,
+ EFT_SIZE, ha->eft, ha->eft_dma);
+
/* Allocate memory for Extended Trace Buffer. */
tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
GFP_KERNEL);
@@ -1469,15 +1584,28 @@ try_eft:
ha->eft_dma = tc_dma;
ha->eft = tc;
}
+
cont_alloc:
+ if (IS_QLA27XX(ha)) {
+ if (!ha->fw_dump_template) {
+ ql_log(ql_log_warn, vha, 0x00ba,
+ "Failed missing fwdump template\n");
+ return;
+ }
+ dump_size = qla27xx_fwdt_calculate_dump_size(vha);
+ ql_dbg(ql_dbg_init, vha, 0x00fa,
+ "-> allocating fwdump (%x bytes)...\n", dump_size);
+ goto allocate;
+ }
+
req_q_size = req->length * sizeof(request_t);
rsp_q_size = rsp->length * sizeof(response_t);
-
dump_size = offsetof(struct qla2xxx_fw_dump, isp);
dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + eft_size;
ha->chain_offset = dump_size;
dump_size += mq_size + fce_size;
+allocate:
ha->fw_dump = vmalloc(dump_size);
if (!ha->fw_dump) {
ql_log(ql_log_warn, vha, 0x00c4,
@@ -1499,10 +1627,13 @@ cont_alloc:
}
return;
}
+ ha->fw_dump_len = dump_size;
ql_dbg(ql_dbg_init, vha, 0x00c5,
"Allocated (%d KB) for firmware dump.\n", dump_size / 1024);
- ha->fw_dump_len = dump_size;
+ if (IS_QLA27XX(ha))
+ return;
+
ha->fw_dump->signature[0] = 'Q';
ha->fw_dump->signature[1] = 'L';
ha->fw_dump->signature[2] = 'G';
@@ -1718,9 +1849,6 @@ enable_82xx_npiv:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
- if (IS_QLA83XX(ha))
- goto skip_fac_check;
-
if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) {
uint32_t size;
@@ -1733,8 +1861,8 @@ enable_82xx_npiv:
"Unsupported FAC firmware (%d.%02d.%02d).\n",
ha->fw_major_version, ha->fw_minor_version,
ha->fw_subminor_version);
-skip_fac_check:
- if (IS_QLA83XX(ha)) {
+
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
ha->flags.fac_supported = 0;
rval = QLA_SUCCESS;
}
@@ -1933,7 +2061,7 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
icb->atio_q_address[0] = cpu_to_le32(LSD(ha->tgt.atio_dma));
icb->atio_q_address[1] = cpu_to_le32(MSD(ha->tgt.atio_dma));
- if (ha->mqenable || IS_QLA83XX(ha)) {
+ if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS);
icb->rid = __constant_cpu_to_le16(rid);
if (ha->flags.msix_enabled) {
@@ -4792,13 +4920,14 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
nv = ha->nvram;
/* Determine NVRAM starting address. */
- if (ha->flags.port0) {
+ if (ha->port_no == 0) {
ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
ha->vpd_base = FA_NVRAM_VPD0_ADDR;
} else {
ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
ha->vpd_base = FA_NVRAM_VPD1_ADDR;
}
+
ha->nvram_size = sizeof(struct nvram_24xx);
ha->vpd_size = FA_NVRAM_VPD_SIZE;
@@ -4842,7 +4971,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
nv->exchange_count = __constant_cpu_to_le16(0);
nv->hard_address = __constant_cpu_to_le16(124);
nv->port_name[0] = 0x21;
- nv->port_name[1] = 0x00 + ha->port_no;
+ nv->port_name[1] = 0x00 + ha->port_no + 1;
nv->port_name[2] = 0x00;
nv->port_name[3] = 0xe0;
nv->port_name[4] = 0x8b;
@@ -5117,6 +5246,99 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
segments--;
}
+ if (!IS_QLA27XX(ha))
+ return rval;
+
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
+
+ ql_dbg(ql_dbg_init, vha, 0x0161,
+ "Loading fwdump template from %x\n", faddr);
+ qla24xx_read_flash_data(vha, dcode, faddr, 7);
+ risc_size = be32_to_cpu(dcode[2]);
+ ql_dbg(ql_dbg_init, vha, 0x0162,
+ "-> array size %x dwords\n", risc_size);
+ if (risc_size == 0 || risc_size == ~0)
+ goto default_template;
+
+ dlen = (risc_size - 8) * sizeof(*dcode);
+ ql_dbg(ql_dbg_init, vha, 0x0163,
+ "-> template allocating %x bytes...\n", dlen);
+ ha->fw_dump_template = vmalloc(dlen);
+ if (!ha->fw_dump_template) {
+ ql_log(ql_log_warn, vha, 0x0164,
+ "Failed fwdump template allocate %x bytes.\n", risc_size);
+ goto default_template;
+ }
+
+ faddr += 7;
+ risc_size -= 8;
+ dcode = ha->fw_dump_template;
+ qla24xx_read_flash_data(vha, dcode, faddr, risc_size);
+ for (i = 0; i < risc_size; i++)
+ dcode[i] = le32_to_cpu(dcode[i]);
+
+ if (!qla27xx_fwdt_template_valid(dcode)) {
+ ql_log(ql_log_warn, vha, 0x0165,
+ "Failed fwdump template validate\n");
+ goto default_template;
+ }
+
+ dlen = qla27xx_fwdt_template_size(dcode);
+ ql_dbg(ql_dbg_init, vha, 0x0166,
+ "-> template size %x bytes\n", dlen);
+ if (dlen > risc_size * sizeof(*dcode)) {
+ ql_log(ql_log_warn, vha, 0x0167,
+ "Failed fwdump template exceeds array by %x bytes\n",
+ (uint32_t)(dlen - risc_size * sizeof(*dcode)));
+ goto default_template;
+ }
+ ha->fw_dump_template_len = dlen;
+ return rval;
+
+default_template:
+ ql_log(ql_log_warn, vha, 0x0168, "Using default fwdump template\n");
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
+
+ dlen = qla27xx_fwdt_template_default_size();
+ ql_dbg(ql_dbg_init, vha, 0x0169,
+ "-> template allocating %x bytes...\n", dlen);
+ ha->fw_dump_template = vmalloc(dlen);
+ if (!ha->fw_dump_template) {
+ ql_log(ql_log_warn, vha, 0x016a,
+ "Failed fwdump template allocate %x bytes.\n", risc_size);
+ goto failed_template;
+ }
+
+ dcode = ha->fw_dump_template;
+ risc_size = dlen / sizeof(*dcode);
+ memcpy(dcode, qla27xx_fwdt_template_default(), dlen);
+ for (i = 0; i < risc_size; i++)
+ dcode[i] = be32_to_cpu(dcode[i]);
+
+ if (!qla27xx_fwdt_template_valid(ha->fw_dump_template)) {
+ ql_log(ql_log_warn, vha, 0x016b,
+ "Failed fwdump template validate\n");
+ goto failed_template;
+ }
+
+ dlen = qla27xx_fwdt_template_size(ha->fw_dump_template);
+ ql_dbg(ql_dbg_init, vha, 0x016c,
+ "-> template size %x bytes\n", dlen);
+ ha->fw_dump_template_len = dlen;
+ return rval;
+
+failed_template:
+ ql_log(ql_log_warn, vha, 0x016d, "Failed default fwdump template\n");
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
return rval;
}
@@ -5231,7 +5453,8 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
uint32_t risc_size;
uint32_t i;
struct fw_blob *blob;
- uint32_t *fwcode, fwclen;
+ const uint32_t *fwcode;
+ uint32_t fwclen;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
@@ -5263,7 +5486,7 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
ql_log(ql_log_fatal, vha, 0x0093,
"Unable to verify integrity of firmware image (%Zd).\n",
blob->fw->size);
- goto fail_fw_integrity;
+ return QLA_FUNCTION_FAILED;
}
for (i = 0; i < 4; i++)
dcode[i] = be32_to_cpu(fwcode[i + 4]);
@@ -5277,7 +5500,7 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
ql_log(ql_log_fatal, vha, 0x0095,
"Firmware data: %08x %08x %08x %08x.\n",
dcode[0], dcode[1], dcode[2], dcode[3]);
- goto fail_fw_integrity;
+ return QLA_FUNCTION_FAILED;
}
while (segments && rval == QLA_SUCCESS) {
@@ -5291,8 +5514,7 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
ql_log(ql_log_fatal, vha, 0x0096,
"Unable to verify integrity of firmware image "
"(%Zd).\n", blob->fw->size);
-
- goto fail_fw_integrity;
+ return QLA_FUNCTION_FAILED;
}
fragment = 0;
@@ -5326,10 +5548,100 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
/* Next segment. */
segments--;
}
+
+ if (!IS_QLA27XX(ha))
+ return rval;
+
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
+
+ ql_dbg(ql_dbg_init, vha, 0x171,
+ "Loading fwdump template from %x\n",
+ (uint32_t)((void *)fwcode - (void *)blob->fw->data));
+ risc_size = be32_to_cpu(fwcode[2]);
+ ql_dbg(ql_dbg_init, vha, 0x172,
+ "-> array size %x dwords\n", risc_size);
+ if (risc_size == 0 || risc_size == ~0)
+ goto default_template;
+
+ dlen = (risc_size - 8) * sizeof(*fwcode);
+ ql_dbg(ql_dbg_init, vha, 0x0173,
+ "-> template allocating %x bytes...\n", dlen);
+ ha->fw_dump_template = vmalloc(dlen);
+ if (!ha->fw_dump_template) {
+ ql_log(ql_log_warn, vha, 0x0174,
+ "Failed fwdump template allocate %x bytes.\n", risc_size);
+ goto default_template;
+ }
+
+ fwcode += 7;
+ risc_size -= 8;
+ dcode = ha->fw_dump_template;
+ for (i = 0; i < risc_size; i++)
+ dcode[i] = le32_to_cpu(fwcode[i]);
+
+ if (!qla27xx_fwdt_template_valid(dcode)) {
+ ql_log(ql_log_warn, vha, 0x0175,
+ "Failed fwdump template validate\n");
+ goto default_template;
+ }
+
+ dlen = qla27xx_fwdt_template_size(dcode);
+ ql_dbg(ql_dbg_init, vha, 0x0176,
+ "-> template size %x bytes\n", dlen);
+ if (dlen > risc_size * sizeof(*fwcode)) {
+ ql_log(ql_log_warn, vha, 0x0177,
+ "Failed fwdump template exceeds array by %x bytes\n",
+ (uint32_t)(dlen - risc_size * sizeof(*fwcode)));
+ goto default_template;
+ }
+ ha->fw_dump_template_len = dlen;
return rval;
-fail_fw_integrity:
- return QLA_FUNCTION_FAILED;
+default_template:
+ ql_log(ql_log_warn, vha, 0x0178, "Using default fwdump template\n");
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
+
+ dlen = qla27xx_fwdt_template_default_size();
+ ql_dbg(ql_dbg_init, vha, 0x0179,
+ "-> template allocating %x bytes...\n", dlen);
+ ha->fw_dump_template = vmalloc(dlen);
+ if (!ha->fw_dump_template) {
+ ql_log(ql_log_warn, vha, 0x017a,
+ "Failed fwdump template allocate %x bytes.\n", risc_size);
+ goto failed_template;
+ }
+
+ dcode = ha->fw_dump_template;
+ risc_size = dlen / sizeof(*fwcode);
+ fwcode = qla27xx_fwdt_template_default();
+ for (i = 0; i < risc_size; i++)
+ dcode[i] = be32_to_cpu(fwcode[i]);
+
+ if (!qla27xx_fwdt_template_valid(ha->fw_dump_template)) {
+ ql_log(ql_log_warn, vha, 0x017b,
+ "Failed fwdump template validate\n");
+ goto failed_template;
+ }
+
+ dlen = qla27xx_fwdt_template_size(ha->fw_dump_template);
+ ql_dbg(ql_dbg_init, vha, 0x017c,
+ "-> template size %x bytes\n", dlen);
+ ha->fw_dump_template_len = dlen;
+ return rval;
+
+failed_template:
+ ql_log(ql_log_warn, vha, 0x017d, "Failed default fwdump template\n");
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
+ return rval;
}
int
@@ -5605,7 +5917,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
nv->exchange_count = __constant_cpu_to_le16(0);
nv->port_name[0] = 0x21;
- nv->port_name[1] = 0x00 + ha->port_no;
+ nv->port_name[1] = 0x00 + ha->port_no + 1;
nv->port_name[2] = 0x00;
nv->port_name[3] = 0xe0;
nv->port_name[4] = 0x8b;
@@ -5639,7 +5951,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
nv->enode_mac[2] = 0xDD;
nv->enode_mac[3] = 0x04;
nv->enode_mac[4] = 0x05;
- nv->enode_mac[5] = 0x06 + ha->port_no;
+ nv->enode_mac[5] = 0x06 + ha->port_no + 1;
rval = 1;
}
@@ -5677,7 +5989,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
icb->enode_mac[2] = 0xDD;
icb->enode_mac[3] = 0x04;
icb->enode_mac[4] = 0x05;
- icb->enode_mac[5] = 0x06 + ha->port_no;
+ icb->enode_mac[5] = 0x06 + ha->port_no + 1;
}
/* Use extended-initialization control block. */
@@ -5780,7 +6092,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
ha->login_retry_count = ql2xloginretrycount;
/* if not running MSI-X we need handshaking on interrupts */
- if (!vha->hw->flags.msix_enabled && IS_QLA83XX(ha))
+ if (!vha->hw->flags.msix_enabled && (IS_QLA83XX(ha) || IS_QLA27XX(ha)))
icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_22);
/* Enable ZIO. */
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 46b9307e8be4..e607568bce49 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -488,7 +488,7 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
req->ring_ptr++;
/* Set chip new ring index. */
- if (ha->mqenable || IS_QLA83XX(ha)) {
+ if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
WRT_REG_DWORD(req->req_q_in, req->ring_index);
RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr);
} else if (IS_QLAFX00(ha)) {
@@ -524,7 +524,6 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
{
mrk_entry_t *mrk;
struct mrk_entry_24xx *mrk24 = NULL;
- struct mrk_entry_fx00 *mrkfx = NULL;
struct qla_hw_data *ha = vha->hw;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
@@ -541,15 +540,7 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
mrk->entry_type = MARKER_TYPE;
mrk->modifier = type;
if (type != MK_SYNC_ALL) {
- if (IS_QLAFX00(ha)) {
- mrkfx = (struct mrk_entry_fx00 *) mrk;
- mrkfx->handle = MAKE_HANDLE(req->id, mrkfx->handle);
- mrkfx->handle_hi = 0;
- mrkfx->tgt_id = cpu_to_le16(loop_id);
- mrkfx->lun[1] = LSB(lun);
- mrkfx->lun[2] = MSB(lun);
- host_to_fcp_swap(mrkfx->lun, sizeof(mrkfx->lun));
- } else if (IS_FWI2_CAPABLE(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mrk24 = (struct mrk_entry_24xx *) mrk;
mrk24->nport_handle = cpu_to_le16(loop_id);
mrk24->lun[1] = LSB(lun);
@@ -1823,7 +1814,7 @@ qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp)
/* Check for room in outstanding command list. */
handle = req->current_outstanding_cmd;
- for (index = 1; req->num_outstanding_cmds; index++) {
+ for (index = 1; index < req->num_outstanding_cmds; index++) {
handle++;
if (handle == req->num_outstanding_cmds)
handle = 1;
@@ -1848,7 +1839,7 @@ qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp)
skip_cmd_array:
/* Check for room on request queue. */
if (req->cnt < req_cnt) {
- if (ha->mqenable || IS_QLA83XX(ha))
+ if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha))
cnt = RD_REG_DWORD(&reg->isp25mq.req_q_out);
else if (IS_P3P_TYPE(ha))
cnt = RD_REG_DWORD(&reg->isp82.req_q_out);
@@ -2594,6 +2585,29 @@ queuing_error:
return QLA_FUNCTION_FAILED;
}
+void
+qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb)
+{
+ struct srb_iocb *aio = &sp->u.iocb_cmd;
+ scsi_qla_host_t *vha = sp->fcport->vha;
+ struct req_que *req = vha->req;
+
+ memset(abt_iocb, 0, sizeof(struct abort_entry_24xx));
+ abt_iocb->entry_type = ABORT_IOCB_TYPE;
+ abt_iocb->entry_count = 1;
+ abt_iocb->handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle));
+ abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+ abt_iocb->handle_to_abort =
+ cpu_to_le32(MAKE_HANDLE(req->id, aio->u.abt.cmd_hndl));
+ abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
+ abt_iocb->port_id[1] = sp->fcport->d_id.b.area;
+ abt_iocb->port_id[2] = sp->fcport->d_id.b.domain;
+ abt_iocb->vp_index = vha->vp_idx;
+ abt_iocb->req_que_no = cpu_to_le16(req->id);
+ /* Send the command to the firmware */
+ wmb();
+}
+
int
qla2x00_start_sp(srb_t *sp)
{
@@ -2647,7 +2661,9 @@ qla2x00_start_sp(srb_t *sp)
qlafx00_fxdisc_iocb(sp, pkt);
break;
case SRB_ABT_CMD:
- qlafx00_abort_iocb(sp, pkt);
+ IS_QLAFX00(ha) ?
+ qlafx00_abort_iocb(sp, pkt) :
+ qla24xx_abort_iocb(sp, pkt);
break;
default:
break;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 9bc86b9e86b1..95314ef2e505 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -356,15 +356,16 @@ qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
const char *
qla2x00_get_link_speed_str(struct qla_hw_data *ha, uint16_t speed)
{
- static const char * const link_speeds[] = {
- "1", "2", "?", "4", "8", "16", "10"
+ static const char *const link_speeds[] = {
+ "1", "2", "?", "4", "8", "16", "32", "10"
};
+#define QLA_LAST_SPEED 7
if (IS_QLA2100(ha) || IS_QLA2200(ha))
return link_speeds[0];
else if (speed == 0x13)
- return link_speeds[6];
- else if (speed < 6)
+ return link_speeds[QLA_LAST_SPEED];
+ else if (speed < QLA_LAST_SPEED)
return link_speeds[speed];
else
return link_speeds[LS_UNKNOWN];
@@ -649,7 +650,7 @@ skip_rio:
break;
case MBA_SYSTEM_ERR: /* System Error */
- mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha)) ?
+ mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) ?
RD_REG_WORD(&reg24->mailbox7) : 0;
ql_log(ql_log_warn, vha, 0x5003,
"ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh "
@@ -666,7 +667,7 @@ skip_rio:
vha->device_flags |= DFLG_DEV_FAILED;
} else {
/* Check to see if MPI timeout occurred */
- if ((mbx & MBX_3) && (ha->flags.port0))
+ if ((mbx & MBX_3) && (ha->port_no == 0))
set_bit(MPI_RESET_NEEDED,
&vha->dpc_flags);
@@ -1497,8 +1498,7 @@ logio_done:
}
static void
-qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
- struct tsk_mgmt_entry *tsk)
+qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
{
const char func[] = "TMF-IOCB";
const char *type;
@@ -1506,7 +1506,6 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
srb_t *sp;
struct srb_iocb *iocb;
struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
- int error = 1;
sp = qla2x00_get_sp_from_handle(vha, func, req, tsk);
if (!sp)
@@ -1515,37 +1514,35 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
iocb = &sp->u.iocb_cmd;
type = sp->name;
fcport = sp->fcport;
+ iocb->u.tmf.data = QLA_SUCCESS;
if (sts->entry_status) {
ql_log(ql_log_warn, fcport->vha, 0x5038,
"Async-%s error - hdl=%x entry-status(%x).\n",
type, sp->handle, sts->entry_status);
+ iocb->u.tmf.data = QLA_FUNCTION_FAILED;
} else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
ql_log(ql_log_warn, fcport->vha, 0x5039,
"Async-%s error - hdl=%x completion status(%x).\n",
type, sp->handle, sts->comp_status);
- } else if (!(le16_to_cpu(sts->scsi_status) &
+ iocb->u.tmf.data = QLA_FUNCTION_FAILED;
+ } else if ((le16_to_cpu(sts->scsi_status) &
SS_RESPONSE_INFO_LEN_VALID)) {
- ql_log(ql_log_warn, fcport->vha, 0x503a,
- "Async-%s error - hdl=%x no response info(%x).\n",
- type, sp->handle, sts->scsi_status);
- } else if (le32_to_cpu(sts->rsp_data_len) < 4) {
- ql_log(ql_log_warn, fcport->vha, 0x503b,
- "Async-%s error - hdl=%x not enough response(%d).\n",
- type, sp->handle, sts->rsp_data_len);
- } else if (sts->data[3]) {
- ql_log(ql_log_warn, fcport->vha, 0x503c,
- "Async-%s error - hdl=%x response(%x).\n",
- type, sp->handle, sts->data[3]);
- } else {
- error = 0;
+ if (le32_to_cpu(sts->rsp_data_len) < 4) {
+ ql_log(ql_log_warn, fcport->vha, 0x503b,
+ "Async-%s error - hdl=%x not enough response(%d).\n",
+ type, sp->handle, sts->rsp_data_len);
+ } else if (sts->data[3]) {
+ ql_log(ql_log_warn, fcport->vha, 0x503c,
+ "Async-%s error - hdl=%x response(%x).\n",
+ type, sp->handle, sts->data[3]);
+ iocb->u.tmf.data = QLA_FUNCTION_FAILED;
+ }
}
- if (error) {
- iocb->u.tmf.data = error;
+ if (iocb->u.tmf.data != QLA_SUCCESS)
ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5055,
(uint8_t *)sts, sizeof(*sts));
- }
sp->done(vha, sp, 0);
}
@@ -2025,6 +2022,12 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
return;
}
+ /* Task Management completion. */
+ if (sp->type == SRB_TM_CMD) {
+ qla24xx_tm_iocb_entry(vha, req, pkt);
+ return;
+ }
+
/* Fast path completion. */
if (comp_status == CS_COMPLETE && scsi_status == 0) {
qla2x00_process_completed_request(vha, req, handle);
@@ -2425,6 +2428,23 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
}
}
+static void
+qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
+ struct abort_entry_24xx *pkt)
+{
+ const char func[] = "ABT_IOCB";
+ srb_t *sp;
+ struct srb_iocb *abt;
+
+ sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
+ if (!sp)
+ return;
+
+ abt = &sp->u.iocb_cmd;
+ abt->u.abt.comp_status = le32_to_cpu(pkt->nport_handle);
+ sp->done(vha, sp, 0);
+}
+
/**
* qla24xx_process_response_queue() - Process response queue entries.
* @ha: SCSI driver HA context
@@ -2474,10 +2494,6 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
qla24xx_logio_entry(vha, rsp->req,
(struct logio_entry_24xx *)pkt);
break;
- case TSK_MGMT_IOCB_TYPE:
- qla24xx_tm_iocb_entry(vha, rsp->req,
- (struct tsk_mgmt_entry *)pkt);
- break;
case CT_IOCB_TYPE:
qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
break;
@@ -2497,6 +2513,10 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
* from falling into default case
*/
break;
+ case ABORT_IOCB_TYPE:
+ qla24xx_abort_iocb_entry(vha, rsp->req,
+ (struct abort_entry_24xx *)pkt);
+ break;
default:
/* Type Not Supported. */
ql_dbg(ql_dbg_async, vha, 0x5042,
@@ -2525,7 +2545,8 @@ qla2xxx_check_risc_status(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
- if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
+ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
+ !IS_QLA27XX(ha))
return;
rval = QLA_SUCCESS;
@@ -2880,6 +2901,7 @@ static int
qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
{
#define MIN_MSIX_COUNT 2
+#define ATIO_VECTOR 2
int i, ret;
struct msix_entry *entries;
struct qla_msix_entry *qentry;
@@ -2936,36 +2958,49 @@ msix_failed:
}
/* Enable MSI-X vectors for the base queue */
- for (i = 0; i < ha->msix_count; i++) {
+ for (i = 0; i < 2; i++) {
qentry = &ha->msix_entries[i];
- if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) {
- ret = request_irq(qentry->vector,
- qla83xx_msix_entries[i].handler,
- 0, qla83xx_msix_entries[i].name, rsp);
- } else if (IS_P3P_TYPE(ha)) {
+ if (IS_P3P_TYPE(ha))
ret = request_irq(qentry->vector,
qla82xx_msix_entries[i].handler,
0, qla82xx_msix_entries[i].name, rsp);
- } else {
+ else
ret = request_irq(qentry->vector,
msix_entries[i].handler,
0, msix_entries[i].name, rsp);
- }
- if (ret) {
- ql_log(ql_log_fatal, vha, 0x00cb,
- "MSI-X: unable to register handler -- %x/%d.\n",
- qentry->vector, ret);
- qla24xx_disable_msix(ha);
- ha->mqenable = 0;
- goto msix_out;
- }
+ if (ret)
+ goto msix_register_fail;
+ qentry->have_irq = 1;
+ qentry->rsp = rsp;
+ rsp->msix = qentry;
+ }
+
+ /*
+ * If target mode is enable, also request the vector for the ATIO
+ * queue.
+ */
+ if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) {
+ qentry = &ha->msix_entries[ATIO_VECTOR];
+ ret = request_irq(qentry->vector,
+ qla83xx_msix_entries[ATIO_VECTOR].handler,
+ 0, qla83xx_msix_entries[ATIO_VECTOR].name, rsp);
qentry->have_irq = 1;
qentry->rsp = rsp;
rsp->msix = qentry;
}
+msix_register_fail:
+ if (ret) {
+ ql_log(ql_log_fatal, vha, 0x00cb,
+ "MSI-X: unable to register handler -- %x/%d.\n",
+ qentry->vector, ret);
+ qla24xx_disable_msix(ha);
+ ha->mqenable = 0;
+ goto msix_out;
+ }
+
/* Enable MSI-X vector for response queue update for queue 0 */
- if (IS_QLA83XX(ha)) {
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
if (ha->msixbase && ha->mqiobase &&
(ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
ha->mqenable = 1;
@@ -2989,12 +3024,13 @@ int
qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
{
int ret = QLA_FUNCTION_FAILED;
- device_reg_t __iomem *reg = ha->iobase;
+ device_reg_t *reg = ha->iobase;
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
/* If possible, enable MSI-X. */
if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
- !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && !IS_QLAFX00(ha))
+ !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && !IS_QLAFX00(ha) &&
+ !IS_QLA27XX(ha))
goto skip_msi;
if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
@@ -3029,7 +3065,8 @@ skip_msix:
"Falling back-to MSI mode -%d.\n", ret);
if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
- !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha))
+ !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha) &&
+ !IS_QLA27XX(ha))
goto skip_msi;
ret = pci_enable_msi(ha->pdev);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index b94511ae0051..2528709c4add 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -35,7 +35,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
{
int rval;
unsigned long flags = 0;
- device_reg_t __iomem *reg;
+ device_reg_t *reg;
uint8_t abort_active;
uint8_t io_lock_on;
uint16_t command = 0;
@@ -468,7 +468,8 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
mcp->mb[1] = MSW(risc_addr);
mcp->mb[2] = LSW(risc_addr);
mcp->mb[3] = 0;
- if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha)) {
+ if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
+ IS_QLA27XX(ha)) {
struct nvram_81xx *nv = ha->nvram;
mcp->mb[4] = (nv->enhanced_features &
EXTENDED_BB_CREDITS);
@@ -539,6 +540,8 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8;
if (IS_FWI2_CAPABLE(ha))
mcp->in_mb |= MBX_17|MBX_16|MBX_15;
+ if (IS_QLA27XX(ha))
+ mcp->in_mb |= MBX_21|MBX_20|MBX_19|MBX_18;
mcp->flags = 0;
mcp->tov = MBX_TOV_SECONDS;
rval = qla2x00_mailbox_command(vha, mcp);
@@ -574,6 +577,10 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
"%s: Ext_FwAttributes Upper: 0x%x, Lower: 0x%x.\n",
__func__, mcp->mb[17], mcp->mb[16]);
}
+ if (IS_QLA27XX(ha)) {
+ ha->fw_shared_ram_start = (mcp->mb[19] << 16) | mcp->mb[18];
+ ha->fw_shared_ram_end = (mcp->mb[21] << 16) | mcp->mb[20];
+ }
failed:
if (rval != QLA_SUCCESS) {
@@ -1225,7 +1232,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
}
/* 1 and 2 should normally be captured. */
mcp->in_mb = MBX_2|MBX_1|MBX_0;
- if (IS_QLA83XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
/* mb3 is additional info about the installed SFP. */
mcp->in_mb |= MBX_3;
mcp->buf_size = size;
@@ -2349,7 +2356,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
mcp->mb[0] = MBC_GET_RESOURCE_COUNTS;
mcp->out_mb = MBX_0;
mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
- if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw))
+ if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw) || IS_QLA27XX(vha->hw))
mcp->in_mb |= MBX_12;
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
@@ -2590,6 +2597,9 @@ qla24xx_abort_command(srb_t *sp)
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x108c,
"Entered %s.\n", __func__);
+ if (ql2xasynctmfenable)
+ return qla24xx_async_abort_command(sp);
+
spin_lock_irqsave(&ha->hardware_lock, flags);
for (handle = 1; handle < req->num_outstanding_cmds; handle++) {
if (req->outstanding_cmds[handle] == sp)
@@ -3032,7 +3042,7 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma,
"Entered %s.\n", __func__);
if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw) &&
- !IS_QLA83XX(vha->hw))
+ !IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw))
return QLA_FUNCTION_FAILED;
if (unlikely(pci_channel_offline(vha->hw->pdev)))
@@ -3662,7 +3672,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
mcp->mb[12] = req->qos;
mcp->mb[11] = req->vp_idx;
mcp->mb[13] = req->rid;
- if (IS_QLA83XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
mcp->mb[15] = 0;
mcp->mb[4] = req->id;
@@ -3676,9 +3686,9 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
mcp->flags = MBX_DMA_OUT;
mcp->tov = MBX_TOV_SECONDS * 2;
- if (IS_QLA81XX(ha) || IS_QLA83XX(ha))
+ if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha))
mcp->in_mb |= MBX_1;
- if (IS_QLA83XX(ha)) {
+ if (IS_QLA83XX(ha) || !IS_QLA27XX(ha)) {
mcp->out_mb |= MBX_15;
/* debug q create issue in SR-IOV */
mcp->in_mb |= MBX_9 | MBX_8 | MBX_7;
@@ -3687,7 +3697,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
spin_lock_irqsave(&ha->hardware_lock, flags);
if (!(req->options & BIT_0)) {
WRT_REG_DWORD(req->req_q_in, 0);
- if (!IS_QLA83XX(ha))
+ if (!IS_QLA83XX(ha) || !IS_QLA27XX(ha))
WRT_REG_DWORD(req->req_q_out, 0);
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -3725,7 +3735,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
mcp->mb[5] = rsp->length;
mcp->mb[14] = rsp->msix->entry;
mcp->mb[13] = rsp->rid;
- if (IS_QLA83XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
mcp->mb[15] = 0;
mcp->mb[4] = rsp->id;
@@ -3742,7 +3752,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
if (IS_QLA81XX(ha)) {
mcp->out_mb |= MBX_12|MBX_11|MBX_10;
mcp->in_mb |= MBX_1;
- } else if (IS_QLA83XX(ha)) {
+ } else if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
mcp->out_mb |= MBX_15|MBX_12|MBX_11|MBX_10;
mcp->in_mb |= MBX_1;
/* debug q create issue in SR-IOV */
@@ -3809,7 +3819,8 @@ qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size)
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10dc,
"Entered %s.\n", __func__);
- if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw))
+ if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw) &&
+ !IS_QLA27XX(vha->hw))
return QLA_FUNCTION_FAILED;
mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
@@ -3840,7 +3851,8 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw))
+ if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw) &&
+ !IS_QLA27XX(vha->hw))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10df,
@@ -3874,7 +3886,8 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw))
+ if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw) &&
+ !IS_QLA27XX(vha->hw))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e2,
@@ -4545,7 +4558,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
mcp->mb[1] = 0;
mcp->out_mb = MBX_1|MBX_0;
mcp->in_mb = MBX_2|MBX_1|MBX_0;
- if (IS_QLA83XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
mcp->in_mb |= MBX_3;
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
@@ -4574,7 +4587,8 @@ qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb)
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1109,
"Entered %s.\n", __func__);
- if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && !IS_QLA8044(ha))
+ if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && !IS_QLA8044(ha) &&
+ !IS_QLA27XX(ha))
return QLA_FUNCTION_FAILED;
mcp->mb[0] = MBC_GET_PORT_CONFIG;
mcp->out_mb = MBX_0;
@@ -5070,7 +5084,7 @@ qla83xx_wr_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t data)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA83XX(ha))
+ if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1130,
@@ -5145,7 +5159,7 @@ qla83xx_rd_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t *data)
struct qla_hw_data *ha = vha->hw;
unsigned long retry_max_time = jiffies + (2 * HZ);
- if (!IS_QLA83XX(ha))
+ if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx, vha, 0x114b, "Entered %s.\n", __func__);
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index a72df701fb38..f0a852257f99 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -630,7 +630,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
struct req_que *req = NULL;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
uint16_t que_id = 0;
- device_reg_t __iomem *reg;
+ device_reg_t *reg;
uint32_t cnt;
req = kzalloc(sizeof(struct req_que), GFP_KERNEL);
@@ -754,7 +754,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
struct rsp_que *rsp = NULL;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
uint16_t que_id = 0;
- device_reg_t __iomem *reg;
+ device_reg_t *reg;
rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL);
if (rsp == NULL) {
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
index ba6f8b139c98..0aaf6a9c87d3 100644
--- a/drivers/scsi/qla2xxx/qla_mr.c
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -40,7 +40,7 @@ qlafx00_mailbox_command(scsi_qla_host_t *vha, struct mbx_cmd_32 *mcp)
{
int rval;
unsigned long flags = 0;
- device_reg_t __iomem *reg;
+ device_reg_t *reg;
uint8_t abort_active;
uint8_t io_lock_on;
uint16_t command = 0;
@@ -631,20 +631,6 @@ qlafx00_config_rings(struct scsi_qla_host *vha)
{
struct qla_hw_data *ha = vha->hw;
struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
- struct init_cb_fx *icb;
- struct req_que *req = ha->req_q_map[0];
- struct rsp_que *rsp = ha->rsp_q_map[0];
-
- /* Setup ring parameters in initialization control block. */
- icb = (struct init_cb_fx *)ha->init_cb;
- icb->request_q_outpointer = __constant_cpu_to_le16(0);
- icb->response_q_inpointer = __constant_cpu_to_le16(0);
- icb->request_q_length = cpu_to_le16(req->length);
- icb->response_q_length = cpu_to_le16(rsp->length);
- icb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
- icb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
- icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
- icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
WRT_REG_DWORD(&reg->req_q_in, 0);
WRT_REG_DWORD(&reg->req_q_out, 0);
@@ -699,78 +685,16 @@ qlafx00_disable_intrs(struct qla_hw_data *ha)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
-static void
-qlafx00_tmf_iocb_timeout(void *data)
-{
- srb_t *sp = (srb_t *)data;
- struct srb_iocb *tmf = &sp->u.iocb_cmd;
-
- tmf->u.tmf.comp_status = cpu_to_le16((uint16_t)CS_TIMEOUT);
- complete(&tmf->u.tmf.comp);
-}
-
-static void
-qlafx00_tmf_sp_done(void *data, void *ptr, int res)
-{
- srb_t *sp = (srb_t *)ptr;
- struct srb_iocb *tmf = &sp->u.iocb_cmd;
-
- complete(&tmf->u.tmf.comp);
-}
-
-static int
-qlafx00_async_tm_cmd(fc_port_t *fcport, uint32_t flags,
- uint32_t lun, uint32_t tag)
-{
- scsi_qla_host_t *vha = fcport->vha;
- struct srb_iocb *tm_iocb;
- srb_t *sp;
- int rval = QLA_FUNCTION_FAILED;
-
- sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
- if (!sp)
- goto done;
-
- tm_iocb = &sp->u.iocb_cmd;
- sp->type = SRB_TM_CMD;
- sp->name = "tmf";
- qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha));
- tm_iocb->u.tmf.flags = flags;
- tm_iocb->u.tmf.lun = lun;
- tm_iocb->u.tmf.data = tag;
- sp->done = qlafx00_tmf_sp_done;
- tm_iocb->timeout = qlafx00_tmf_iocb_timeout;
- init_completion(&tm_iocb->u.tmf.comp);
-
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
-
- ql_dbg(ql_dbg_async, vha, 0x507b,
- "Task management command issued target_id=%x\n",
- fcport->tgt_id);
-
- wait_for_completion(&tm_iocb->u.tmf.comp);
-
- rval = tm_iocb->u.tmf.comp_status == CS_COMPLETE ?
- QLA_SUCCESS : QLA_FUNCTION_FAILED;
-
-done_free_sp:
- sp->free(vha, sp);
-done:
- return rval;
-}
-
int
qlafx00_abort_target(fc_port_t *fcport, unsigned int l, int tag)
{
- return qlafx00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag);
+ return qla2x00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag);
}
int
qlafx00_lun_reset(fc_port_t *fcport, unsigned int l, int tag)
{
- return qlafx00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
+ return qla2x00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
}
int
@@ -997,6 +921,9 @@ qlafx00_init_fw_ready(scsi_qla_host_t *vha)
break;
default:
+ if ((aenmbx & 0xFF00) == MBA_FW_INIT_INPROGRESS)
+ break;
+
/* If fw is apparently not ready. In order to continue,
* we might need to issue Mbox cmd, but the problem is
* that the DoorBell vector values that come with the
@@ -2014,7 +1941,8 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
memcpy(vha->hw->gid_list, pinfo, QLAFX00_TGT_NODE_LIST_SIZE);
} else if (fx_type == FXDISC_ABORT_IOCTL)
fdisc->u.fxiocb.result =
- (fdisc->u.fxiocb.result == cpu_to_le32(0x68)) ?
+ (fdisc->u.fxiocb.result ==
+ cpu_to_le32(QLAFX00_IOCTL_ICOB_ABORT_SUCCESS)) ?
cpu_to_le32(QLA_SUCCESS) : cpu_to_le32(QLA_FUNCTION_FAILED);
rval = le32_to_cpu(fdisc->u.fxiocb.result);
@@ -2034,94 +1962,6 @@ done:
return rval;
}
-static void
-qlafx00_abort_iocb_timeout(void *data)
-{
- srb_t *sp = (srb_t *)data;
- struct srb_iocb *abt = &sp->u.iocb_cmd;
-
- abt->u.abt.comp_status = cpu_to_le16((uint16_t)CS_TIMEOUT);
- complete(&abt->u.abt.comp);
-}
-
-static void
-qlafx00_abort_sp_done(void *data, void *ptr, int res)
-{
- srb_t *sp = (srb_t *)ptr;
- struct srb_iocb *abt = &sp->u.iocb_cmd;
-
- complete(&abt->u.abt.comp);
-}
-
-static int
-qlafx00_async_abt_cmd(srb_t *cmd_sp)
-{
- scsi_qla_host_t *vha = cmd_sp->fcport->vha;
- fc_port_t *fcport = cmd_sp->fcport;
- struct srb_iocb *abt_iocb;
- srb_t *sp;
- int rval = QLA_FUNCTION_FAILED;
-
- sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
- if (!sp)
- goto done;
-
- abt_iocb = &sp->u.iocb_cmd;
- sp->type = SRB_ABT_CMD;
- sp->name = "abort";
- qla2x00_init_timer(sp, FXDISC_TIMEOUT);
- abt_iocb->u.abt.cmd_hndl = cmd_sp->handle;
- sp->done = qlafx00_abort_sp_done;
- abt_iocb->timeout = qlafx00_abort_iocb_timeout;
- init_completion(&abt_iocb->u.abt.comp);
-
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
-
- ql_dbg(ql_dbg_async, vha, 0x507c,
- "Abort command issued - hdl=%x, target_id=%x\n",
- cmd_sp->handle, fcport->tgt_id);
-
- wait_for_completion(&abt_iocb->u.abt.comp);
-
- rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ?
- QLA_SUCCESS : QLA_FUNCTION_FAILED;
-
-done_free_sp:
- sp->free(vha, sp);
-done:
- return rval;
-}
-
-int
-qlafx00_abort_command(srb_t *sp)
-{
- unsigned long flags = 0;
-
- uint32_t handle;
- fc_port_t *fcport = sp->fcport;
- struct scsi_qla_host *vha = fcport->vha;
- struct qla_hw_data *ha = vha->hw;
- struct req_que *req = vha->req;
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- for (handle = 1; handle < DEFAULT_OUTSTANDING_COMMANDS; handle++) {
- if (req->outstanding_cmds[handle] == sp)
- break;
- }
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (handle == DEFAULT_OUTSTANDING_COMMANDS) {
- /* Command not found. */
- return QLA_FUNCTION_FAILED;
- }
- if (sp->type == SRB_FXIOCB_DCMD)
- return qlafx00_fx_disc(vha, &vha->hw->mr.fcport,
- FXDISC_ABORT_IOCTL);
-
- return qlafx00_async_abt_cmd(sp);
-}
-
/*
* qlafx00_initialize_adapter
* Initialize board.
@@ -2150,7 +1990,6 @@ qlafx00_initialize_adapter(scsi_qla_host_t *vha)
vha->device_flags = DFLG_NO_CABLE;
vha->dpc_flags = 0;
vha->flags.management_server_logged_in = 0;
- vha->marker_needed = 0;
ha->isp_abort_cnt = 0;
ha->beacon_blink_led = 0;
@@ -2354,8 +2193,7 @@ qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req,
fstatus.ioctl_flags = pkt->fw_iotcl_flags;
fstatus.ioctl_data = pkt->dataword_r;
fstatus.adapid = pkt->adapid;
- fstatus.adapid_hi = pkt->adapid_hi;
- fstatus.reserved_2 = pkt->reserved_1;
+ fstatus.reserved_2 = pkt->dataword_r_extra;
fstatus.res_count = pkt->residuallen;
fstatus.status = pkt->status;
fstatus.seq_number = pkt->seq_no;
@@ -2804,7 +2642,7 @@ qlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp,
srb_t *sp;
struct qla_hw_data *ha = vha->hw;
const char func[] = "ERROR-IOCB";
- uint16_t que = MSW(pkt->handle);
+ uint16_t que = 0;
struct req_que *req = NULL;
int res = DID_ERROR << 16;
@@ -2833,16 +2671,22 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
{
struct sts_entry_fx00 *pkt;
response_t *lptr;
+ uint16_t lreq_q_in = 0;
+ uint16_t lreq_q_out = 0;
- while (RD_REG_DWORD((void __iomem *)&(rsp->ring_ptr->signature)) !=
- RESPONSE_PROCESSED) {
+ lreq_q_in = RD_REG_DWORD(rsp->rsp_q_in);
+ lreq_q_out = RD_REG_DWORD(rsp->rsp_q_out);
+
+ while (lreq_q_in != lreq_q_out) {
lptr = rsp->ring_ptr;
memcpy_fromio(rsp->rsp_pkt, (void __iomem *)lptr,
sizeof(rsp->rsp_pkt));
pkt = (struct sts_entry_fx00 *)rsp->rsp_pkt;
rsp->ring_index++;
+ lreq_q_out++;
if (rsp->ring_index == rsp->length) {
+ lreq_q_out = 0;
rsp->ring_index = 0;
rsp->ring_ptr = rsp->ring;
} else {
@@ -2854,7 +2698,6 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
qlafx00_error_entry(vha, rsp,
(struct sts_entry_fx00 *)pkt, pkt->entry_status,
pkt->entry_type);
- goto next_iter;
continue;
}
@@ -2888,10 +2731,6 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
pkt->entry_type, pkt->entry_status);
break;
}
-next_iter:
- WRT_REG_DWORD((void __iomem *)&lptr->signature,
- RESPONSE_PROCESSED);
- wmb();
}
/* Adjust ring index */
@@ -2926,9 +2765,9 @@ qlafx00_async_event(scsi_qla_host_t *vha)
break;
case QLAFX00_MBA_PORT_UPDATE: /* Port database update */
- ha->aenmb[1] = RD_REG_WORD(&reg->aenmailbox1);
- ha->aenmb[2] = RD_REG_WORD(&reg->aenmailbox2);
- ha->aenmb[3] = RD_REG_WORD(&reg->aenmailbox3);
+ ha->aenmb[1] = RD_REG_DWORD(&reg->aenmailbox1);
+ ha->aenmb[2] = RD_REG_DWORD(&reg->aenmailbox2);
+ ha->aenmb[3] = RD_REG_DWORD(&reg->aenmailbox3);
ql_dbg(ql_dbg_async, vha, 0x5077,
"Asynchronous port Update received "
"aenmb[0]: %x, aenmb[1]: %x, aenmb[2]: %x, aenmb[3]: %x\n",
@@ -2985,7 +2824,7 @@ static void
qlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0)
{
uint16_t cnt;
- uint16_t __iomem *wptr;
+ uint32_t __iomem *wptr;
struct qla_hw_data *ha = vha->hw;
struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
@@ -2995,10 +2834,10 @@ qlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0)
/* Load return mailbox registers. */
ha->flags.mbox_int = 1;
ha->mailbox_out32[0] = mb0;
- wptr = (uint16_t __iomem *)&reg->mailbox17;
+ wptr = (uint32_t __iomem *)&reg->mailbox17;
for (cnt = 1; cnt < ha->mbx_count; cnt++) {
- ha->mailbox_out32[cnt] = RD_REG_WORD(wptr);
+ ha->mailbox_out32[cnt] = RD_REG_DWORD(wptr);
wptr++;
}
}
@@ -3025,6 +2864,7 @@ qlafx00_intr_handler(int irq, void *dev_id)
struct rsp_que *rsp;
unsigned long flags;
uint32_t clr_intr = 0;
+ uint32_t intr_stat = 0;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -3046,34 +2886,26 @@ qlafx00_intr_handler(int irq, void *dev_id)
stat = QLAFX00_RD_INTR_REG(ha);
if (qla2x00_check_reg_for_disconnect(vha, stat))
break;
- if ((stat & QLAFX00_HST_INT_STS_BITS) == 0)
+ intr_stat = stat & QLAFX00_HST_INT_STS_BITS;
+ if (!intr_stat)
break;
- switch (stat & QLAFX00_HST_INT_STS_BITS) {
- case QLAFX00_INTR_MB_CMPLT:
- case QLAFX00_INTR_MB_RSP_CMPLT:
- case QLAFX00_INTR_MB_ASYNC_CMPLT:
- case QLAFX00_INTR_ALL_CMPLT:
+ if (stat & QLAFX00_INTR_MB_CMPLT) {
mb[0] = RD_REG_WORD(&reg->mailbox16);
qlafx00_mbx_completion(vha, mb[0]);
status |= MBX_INTERRUPT;
clr_intr |= QLAFX00_INTR_MB_CMPLT;
- break;
- case QLAFX00_INTR_ASYNC_CMPLT:
- case QLAFX00_INTR_RSP_ASYNC_CMPLT:
+ }
+ if (intr_stat & QLAFX00_INTR_ASYNC_CMPLT) {
ha->aenmb[0] = RD_REG_WORD(&reg->aenmailbox0);
qlafx00_async_event(vha);
clr_intr |= QLAFX00_INTR_ASYNC_CMPLT;
- break;
- case QLAFX00_INTR_RSP_CMPLT:
+ }
+ if (intr_stat & QLAFX00_INTR_RSP_CMPLT) {
qlafx00_process_response_queue(vha, rsp);
clr_intr |= QLAFX00_INTR_RSP_CMPLT;
- break;
- default:
- ql_dbg(ql_dbg_async, vha, 0x507a,
- "Unrecognized interrupt type (%d).\n", stat);
- break;
}
+
QLAFX00_CLR_INTR_REG(ha, clr_intr);
QLAFX00_RD_INTR_REG(ha);
}
@@ -3223,17 +3055,6 @@ qlafx00_start_scsi(srb_t *sp)
/* So we know we haven't pci_map'ed anything yet */
tot_dsds = 0;
- /* Forcing marker needed for now */
- vha->marker_needed = 0;
-
- /* Send marker if required */
- if (vha->marker_needed != 0) {
- if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) !=
- QLA_SUCCESS)
- return QLA_FUNCTION_FAILED;
- vha->marker_needed = 0;
- }
-
/* Acquire ring specific lock */
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -3284,7 +3105,9 @@ qlafx00_start_scsi(srb_t *sp)
memset(&lcmd_pkt, 0, REQUEST_ENTRY_SIZE);
lcmd_pkt.handle = MAKE_HANDLE(req->id, sp->handle);
- lcmd_pkt.handle_hi = 0;
+ lcmd_pkt.reserved_0 = 0;
+ lcmd_pkt.port_path_ctrl = 0;
+ lcmd_pkt.reserved_1 = 0;
lcmd_pkt.dseg_count = cpu_to_le16(tot_dsds);
lcmd_pkt.tgt_idx = cpu_to_le16(sp->fcport->tgt_id);
@@ -3364,8 +3187,7 @@ qlafx00_tm_iocb(srb_t *sp, struct tsk_mgmt_entry_fx00 *ptm_iocb)
tm_iocb.entry_type = TSK_MGMT_IOCB_TYPE_FX00;
tm_iocb.entry_count = 1;
tm_iocb.handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle));
- tm_iocb.handle_hi = 0;
- tm_iocb.timeout = cpu_to_le16(qla2x00_get_async_timeout(vha) + 2);
+ tm_iocb.reserved_0 = 0;
tm_iocb.tgt_id = cpu_to_le16(sp->fcport->tgt_id);
tm_iocb.control_flags = cpu_to_le32(fxio->u.tmf.flags);
if (tm_iocb.control_flags == cpu_to_le32((uint32_t)TCF_LUN_RESET)) {
diff --git a/drivers/scsi/qla2xxx/qla_mr.h b/drivers/scsi/qla2xxx/qla_mr.h
index 6cd7072cc0ff..e529dfaeb854 100644
--- a/drivers/scsi/qla2xxx/qla_mr.h
+++ b/drivers/scsi/qla2xxx/qla_mr.h
@@ -22,13 +22,16 @@ struct cmd_type_7_fx00 {
uint8_t entry_status; /* Entry Status. */
uint32_t handle; /* System handle. */
- uint32_t handle_hi;
+ uint8_t reserved_0;
+ uint8_t port_path_ctrl;
+ uint16_t reserved_1;
__le16 tgt_idx; /* Target Idx. */
uint16_t timeout; /* Command timeout. */
__le16 dseg_count; /* Data segment count. */
- uint16_t scsi_rsp_dsd_len;
+ uint8_t scsi_rsp_dsd_len;
+ uint8_t reserved_2;
struct scsi_lun lun; /* LUN (LE). */
@@ -47,30 +50,6 @@ struct cmd_type_7_fx00 {
uint32_t dseg_0_len; /* Data segment 0 length. */
};
-/*
- * ISP queue - marker entry structure definition.
- */
-struct mrk_entry_fx00 {
- uint8_t entry_type; /* Entry type. */
- uint8_t entry_count; /* Entry count. */
- uint8_t handle_count; /* Handle count. */
- uint8_t entry_status; /* Entry Status. */
-
- uint32_t handle; /* System handle. */
- uint32_t handle_hi; /* System handle. */
-
- uint16_t tgt_id; /* Target ID. */
-
- uint8_t modifier; /* Modifier (7-0). */
- uint8_t reserved_1;
-
- uint8_t reserved_2[5];
-
- uint8_t lun[8]; /* FCP LUN (BE). */
- uint8_t reserved_3[36];
-};
-
-
#define STATUS_TYPE_FX00 0x01 /* Status entry. */
struct sts_entry_fx00 {
uint8_t entry_type; /* Entry type. */
@@ -79,7 +58,7 @@ struct sts_entry_fx00 {
uint8_t entry_status; /* Entry Status. */
uint32_t handle; /* System handle. */
- uint32_t handle_hi; /* System handle. */
+ uint32_t reserved_3; /* System handle. */
__le16 comp_status; /* Completion status. */
uint16_t reserved_0; /* OX_ID used by the firmware. */
@@ -102,7 +81,7 @@ struct sts_entry_fx00 {
struct multi_sts_entry_fx00 {
uint8_t entry_type; /* Entry type. */
- uint8_t sys_define; /* System defined. */
+ uint8_t entry_count; /* Entry count. */
uint8_t handle_count;
uint8_t entry_status;
@@ -118,15 +97,13 @@ struct tsk_mgmt_entry_fx00 {
__le32 handle; /* System handle. */
- uint32_t handle_hi; /* System handle. */
+ uint32_t reserved_0;
__le16 tgt_id; /* Target Idx. */
uint16_t reserved_1;
-
- uint16_t delay; /* Activity delay in seconds. */
-
- __le16 timeout; /* Command timeout. */
+ uint16_t reserved_3;
+ uint16_t reserved_4;
struct scsi_lun lun; /* LUN (LE). */
@@ -144,13 +121,13 @@ struct abort_iocb_entry_fx00 {
uint8_t entry_status; /* Entry Status. */
__le32 handle; /* System handle. */
- __le32 handle_hi; /* System handle. */
+ __le32 reserved_0;
__le16 tgt_id_sts; /* Completion status. */
__le16 options;
__le32 abort_handle; /* System handle. */
- __le32 abort_handle_hi; /* System handle. */
+ __le32 reserved_2;
__le16 req_que_no;
uint8_t reserved_1[38];
@@ -171,8 +148,7 @@ struct ioctl_iocb_entry_fx00 {
__le32 dataword_r; /* Data word returned */
uint32_t adapid; /* Adapter ID */
- uint32_t adapid_hi; /* Adapter ID high */
- uint32_t reserved_1;
+ uint32_t dataword_r_extra;
__le32 seq_no;
uint8_t reserved_2[20];
@@ -360,11 +336,7 @@ struct config_info_data {
#define QLAFX00_INTR_MB_CMPLT 0x1
#define QLAFX00_INTR_RSP_CMPLT 0x2
-#define QLAFX00_INTR_MB_RSP_CMPLT 0x3
#define QLAFX00_INTR_ASYNC_CMPLT 0x4
-#define QLAFX00_INTR_MB_ASYNC_CMPLT 0x5
-#define QLAFX00_INTR_RSP_ASYNC_CMPLT 0x6
-#define QLAFX00_INTR_ALL_CMPLT 0x7
#define QLAFX00_MBA_SYSTEM_ERR 0x8002
#define QLAFX00_MBA_TEMP_OVER 0x8005
@@ -548,4 +520,7 @@ struct mr_data_fx00 {
/* Max conncurrent IOs that can be queued */
#define QLAFX00_MAX_CANQUEUE 1024
+/* IOCTL IOCB abort success */
+#define QLAFX00_IOCTL_ICOB_ABORT_SUCCESS 0x68
+
#endif
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index 1e6ba4a369e2..5511e24b1f11 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -1664,10 +1664,10 @@ qla82xx_iospace_config(struct qla_hw_data *ha)
/* Mapping of IO base pointer */
if (IS_QLA8044(ha)) {
ha->iobase =
- (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase);
+ (device_reg_t *)((uint8_t *)ha->nx_pcibase);
} else if (IS_QLA82XX(ha)) {
ha->iobase =
- (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase +
+ (device_reg_t *)((uint8_t *)ha->nx_pcibase +
0xbc000 + (ha->pdev->devfn << 11));
}
@@ -4502,3 +4502,20 @@ exit:
qla82xx_idc_unlock(ha);
return rval;
}
+
+void
+qla82xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!ha->allow_cna_fw_dump)
+ return;
+
+ scsi_block_requests(vha->host);
+ ha->flags.isp82xx_no_md_cap = 1;
+ qla82xx_idc_lock(ha);
+ qla82xx_set_reset_owner(vha);
+ qla82xx_idc_unlock(ha);
+ qla2x00_wait_for_chip_reset(vha);
+ scsi_unblock_requests(vha->host);
+}
diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c
index f60989d729a8..86cf10815db0 100644
--- a/drivers/scsi/qla2xxx/qla_nx2.c
+++ b/drivers/scsi/qla2xxx/qla_nx2.c
@@ -1578,8 +1578,8 @@ qla8044_need_reset_handler(struct scsi_qla_host *vha)
do {
if (time_after_eq(jiffies, dev_init_timeout)) {
ql_log(ql_log_info, vha, 0xb0c4,
- "%s: Non Reset owner DEV INIT "
- "TIMEOUT!\n", __func__);
+ "%s: Non Reset owner: Reset Ack Timeout!\n",
+ __func__);
break;
}
@@ -2014,8 +2014,6 @@ qla8044_watchdog(struct scsi_qla_host *vha)
/* don't poll if reset is going on or FW hang in quiescent state */
if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
- test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
- test_bit(ISP_ABORT_RETRY, &vha->dpc_flags) ||
test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags))) {
dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
@@ -3715,3 +3713,19 @@ exit_isp_reset:
return rval;
}
+void
+qla8044_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!ha->allow_cna_fw_dump)
+ return;
+
+ scsi_block_requests(vha->host);
+ ha->flags.isp82xx_no_md_cap = 1;
+ qla8044_idc_lock(ha);
+ qla82xx_set_reset_owner(vha);
+ qla8044_idc_unlock(ha);
+ qla2x00_wait_for_chip_reset(vha);
+ scsi_unblock_requests(vha->host);
+}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 89a53002b585..19e99cc33724 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -120,15 +120,17 @@ MODULE_PARM_DESC(ql2xmaxqdepth,
int ql2xenabledif = 2;
module_param(ql2xenabledif, int, S_IRUGO);
MODULE_PARM_DESC(ql2xenabledif,
- " Enable T10-CRC-DIF "
- " Default is 0 - No DIF Support. 1 - Enable it"
- ", 2 - Enable DIF for all types, except Type 0.");
+ " Enable T10-CRC-DIF:\n"
+ " Default is 2.\n"
+ " 0 -- No DIF Support\n"
+ " 1 -- Enable DIF for all types\n"
+ " 2 -- Enable DIF for all types, except Type 0.\n");
int ql2xenablehba_err_chk = 2;
module_param(ql2xenablehba_err_chk, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xenablehba_err_chk,
" Enable T10-CRC-DIF Error isolation by HBA:\n"
- " Default is 1.\n"
+ " Default is 2.\n"
" 0 -- Error isolation disabled\n"
" 1 -- Error isolation enabled only for DIX Type 0\n"
" 2 -- Error isolation enabled for all Types\n");
@@ -1975,7 +1977,7 @@ static struct isp_operations qla82xx_isp_ops = {
.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
.read_nvram = qla24xx_read_nvram_data,
.write_nvram = qla24xx_write_nvram_data,
- .fw_dump = qla24xx_fw_dump,
+ .fw_dump = qla82xx_fw_dump,
.beacon_on = qla82xx_beacon_on,
.beacon_off = qla82xx_beacon_off,
.beacon_blink = NULL,
@@ -2013,11 +2015,11 @@ static struct isp_operations qla8044_isp_ops = {
.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
.read_nvram = NULL,
.write_nvram = NULL,
- .fw_dump = qla24xx_fw_dump,
+ .fw_dump = qla8044_fw_dump,
.beacon_on = qla82xx_beacon_on,
.beacon_off = qla82xx_beacon_off,
.beacon_blink = NULL,
- .read_optrom = qla82xx_read_optrom_data,
+ .read_optrom = qla8044_read_optrom_data,
.write_optrom = qla8044_write_optrom_data,
.get_flash_version = qla82xx_get_flash_version,
.start_scsi = qla82xx_start_scsi,
@@ -2078,7 +2080,7 @@ static struct isp_operations qlafx00_isp_ops = {
.intr_handler = qlafx00_intr_handler,
.enable_intrs = qlafx00_enable_intrs,
.disable_intrs = qlafx00_disable_intrs,
- .abort_command = qlafx00_abort_command,
+ .abort_command = qla24xx_async_abort_command,
.target_reset = qlafx00_abort_target,
.lun_reset = qlafx00_lun_reset,
.fabric_login = NULL,
@@ -2102,6 +2104,44 @@ static struct isp_operations qlafx00_isp_ops = {
.initialize_adapter = qlafx00_initialize_adapter,
};
+static struct isp_operations qla27xx_isp_ops = {
+ .pci_config = qla25xx_pci_config,
+ .reset_chip = qla24xx_reset_chip,
+ .chip_diag = qla24xx_chip_diag,
+ .config_rings = qla24xx_config_rings,
+ .reset_adapter = qla24xx_reset_adapter,
+ .nvram_config = qla81xx_nvram_config,
+ .update_fw_options = qla81xx_update_fw_options,
+ .load_risc = qla81xx_load_risc,
+ .pci_info_str = qla24xx_pci_info_str,
+ .fw_version_str = qla24xx_fw_version_str,
+ .intr_handler = qla24xx_intr_handler,
+ .enable_intrs = qla24xx_enable_intrs,
+ .disable_intrs = qla24xx_disable_intrs,
+ .abort_command = qla24xx_abort_command,
+ .target_reset = qla24xx_abort_target,
+ .lun_reset = qla24xx_lun_reset,
+ .fabric_login = qla24xx_login_fabric,
+ .fabric_logout = qla24xx_fabric_logout,
+ .calc_req_entries = NULL,
+ .build_iocbs = NULL,
+ .prep_ms_iocb = qla24xx_prep_ms_iocb,
+ .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
+ .read_nvram = NULL,
+ .write_nvram = NULL,
+ .fw_dump = qla27xx_fwdump,
+ .beacon_on = qla24xx_beacon_on,
+ .beacon_off = qla24xx_beacon_off,
+ .beacon_blink = qla83xx_beacon_blink,
+ .read_optrom = qla25xx_read_optrom_data,
+ .write_optrom = qla24xx_write_optrom_data,
+ .get_flash_version = qla24xx_get_flash_version,
+ .start_scsi = qla24xx_dif_start_scsi,
+ .abort_isp = qla2x00_abort_isp,
+ .iospace_config = qla83xx_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
+};
+
static inline void
qla2x00_set_isp_flags(struct qla_hw_data *ha)
{
@@ -2223,21 +2263,29 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
case PCI_DEVICE_ID_QLOGIC_ISPF001:
ha->device_type |= DT_ISPFX00;
break;
+ case PCI_DEVICE_ID_QLOGIC_ISP2071:
+ ha->device_type |= DT_ISP2071;
+ ha->device_type |= DT_ZIO_SUPPORTED;
+ ha->device_type |= DT_FWI2;
+ ha->device_type |= DT_IIDMA;
+ ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+ break;
}
if (IS_QLA82XX(ha))
- ha->port_no = !(ha->portnum & 1);
- else
+ ha->port_no = ha->portnum & 1;
+ else {
/* Get adapter physical port no from interrupt pin register. */
pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no);
+ if (IS_QLA27XX(ha))
+ ha->port_no--;
+ else
+ ha->port_no = !(ha->port_no & 1);
+ }
- if (ha->port_no & 1)
- ha->flags.port0 = 1;
- else
- ha->flags.port0 = 0;
ql_dbg_pci(ql_dbg_init, ha->pdev, 0x000b,
"device_type=0x%x port=%d fw_srisc_address=0x%x.\n",
- ha->device_type, ha->flags.port0, ha->fw_srisc_address);
+ ha->device_type, ha->port_no, ha->fw_srisc_address);
}
static void
@@ -2297,7 +2345,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2031 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8031 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISPF001 ||
- pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8044) {
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8044 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2071) {
bars = pci_select_bars(pdev, IORESOURCE_MEM);
mem_only = 1;
ql_dbg_pci(ql_dbg_init, pdev, 0x0007,
@@ -2334,13 +2383,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&ha->hardware_lock);
spin_lock_init(&ha->vport_slock);
mutex_init(&ha->selflogin_lock);
+ mutex_init(&ha->optrom_mutex);
/* Set ISP-type information. */
qla2x00_set_isp_flags(ha);
/* Set EEH reset type to fundamental if required by hba */
if (IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha) ||
- IS_QLA83XX(ha))
+ IS_QLA83XX(ha) || IS_QLA27XX(ha))
pdev->needs_freset = 1;
ha->prev_topology = 0;
@@ -2488,7 +2538,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->aen_mbx_count = AEN_MAILBOX_REGISTER_COUNT_FX00;
req_length = REQUEST_ENTRY_CNT_FX00;
rsp_length = RESPONSE_ENTRY_CNT_FX00;
- ha->init_cb_size = sizeof(struct init_cb_fx);
ha->isp_ops = &qlafx00_isp_ops;
ha->port_down_retry_count = 30; /* default value */
ha->mr.fw_hbt_cnt = QLAFX00_HEARTBEAT_INTERVAL;
@@ -2497,6 +2546,22 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->mr.fw_hbt_en = 1;
ha->mr.host_info_resend = false;
ha->mr.hinfo_resend_timer_tick = QLAFX00_HINFO_RESEND_INTERVAL;
+ } else if (IS_QLA27XX(ha)) {
+ ha->portnum = PCI_FUNC(ha->pdev->devfn);
+ ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
+ ha->mbx_count = MAILBOX_REGISTER_COUNT;
+ req_length = REQUEST_ENTRY_CNT_24XX;
+ rsp_length = RESPONSE_ENTRY_CNT_2300;
+ ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
+ ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
+ ha->gid_list_info_size = 8;
+ ha->optrom_size = OPTROM_SIZE_83XX;
+ ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX;
+ ha->isp_ops = &qla27xx_isp_ops;
+ ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX;
+ ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX;
+ ha->nvram_conf_off = ~0;
+ ha->nvram_data_off = ~0;
}
ql_dbg_pci(ql_dbg_init, pdev, 0x001e,
@@ -2536,7 +2601,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->flags.enable_64bit_addressing ? "enable" :
"disable");
ret = qla2x00_mem_alloc(ha, req_length, rsp_length, &req, &rsp);
- if (!ret) {
+ if (ret) {
ql_log_pci(ql_log_fatal, pdev, 0x0031,
"Failed to allocate memory for adapter, aborting.\n");
@@ -2561,10 +2626,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
host = base_vha->host;
base_vha->req = req;
- if (IS_QLAFX00(ha))
- host->can_queue = QLAFX00_MAX_CANQUEUE;
- else
- host->can_queue = req->length + 128;
if (IS_QLA2XXX_MIDTYPE(ha))
base_vha->mgmt_svr_loop_id = 10 + base_vha->vp_idx;
else
@@ -2587,11 +2648,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (!IS_QLA82XX(ha))
host->sg_tablesize = QLA_SG_ALL;
}
- ql_dbg(ql_dbg_init, base_vha, 0x0032,
- "can_queue=%d, req=%p, "
- "mgmt_svr_loop_id=%d, sg_tablesize=%d.\n",
- host->can_queue, base_vha->req,
- base_vha->mgmt_svr_loop_id, host->sg_tablesize);
host->max_id = ha->max_fibre_devices;
host->cmd_per_lun = 3;
host->unique_id = host->host_no;
@@ -2646,7 +2702,7 @@ que_init:
req->req_q_out = &ha->iobase->isp24.req_q_out;
rsp->rsp_q_in = &ha->iobase->isp24.rsp_q_in;
rsp->rsp_q_out = &ha->iobase->isp24.rsp_q_out;
- if (ha->mqenable || IS_QLA83XX(ha)) {
+ if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
req->req_q_in = &ha->mqiobase->isp25mq.req_q_in;
req->req_q_out = &ha->mqiobase->isp25mq.req_q_out;
rsp->rsp_q_in = &ha->mqiobase->isp25mq.rsp_q_in;
@@ -2707,6 +2763,16 @@ que_init:
goto probe_failed;
}
+ if (IS_QLAFX00(ha))
+ host->can_queue = QLAFX00_MAX_CANQUEUE;
+ else
+ host->can_queue = req->num_outstanding_cmds - 10;
+
+ ql_dbg(ql_dbg_init, base_vha, 0x0032,
+ "can_queue=%d, req=%p, mgmt_svr_loop_id=%d, sg_tablesize=%d.\n",
+ host->can_queue, base_vha->req,
+ base_vha->mgmt_svr_loop_id, host->sg_tablesize);
+
if (ha->mqenable) {
if (qla25xx_setup_mode(base_vha)) {
ql_log(ql_log_warn, base_vha, 0x00ec,
@@ -2887,9 +2953,9 @@ probe_hw_failed:
iospace_config_failed:
if (IS_P3P_TYPE(ha)) {
if (!ha->nx_pcibase)
- iounmap((device_reg_t __iomem *)ha->nx_pcibase);
+ iounmap((device_reg_t *)ha->nx_pcibase);
if (!ql2xdbwr)
- iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr);
+ iounmap((device_reg_t *)ha->nxdb_wr_ptr);
} else {
if (ha->iobase)
iounmap(ha->iobase);
@@ -3020,9 +3086,9 @@ qla2x00_unmap_iobases(struct qla_hw_data *ha)
{
if (IS_QLA82XX(ha)) {
- iounmap((device_reg_t __iomem *)ha->nx_pcibase);
+ iounmap((device_reg_t *)ha->nx_pcibase);
if (!ql2xdbwr)
- iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr);
+ iounmap((device_reg_t *)ha->nxdb_wr_ptr);
} else {
if (ha->iobase)
iounmap(ha->iobase);
@@ -3033,7 +3099,7 @@ qla2x00_unmap_iobases(struct qla_hw_data *ha)
if (ha->mqiobase)
iounmap(ha->mqiobase);
- if (IS_QLA83XX(ha) && ha->msixbase)
+ if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) && ha->msixbase)
iounmap(ha->msixbase);
}
}
@@ -3447,7 +3513,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
ha->npiv_info = NULL;
/* Get consistent memory allocated for EX-INIT-CB. */
- if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)) {
+ if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha)) {
ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
&ha->ex_init_cb_dma);
if (!ha->ex_init_cb)
@@ -3478,10 +3544,10 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
else {
qla2x00_set_reserved_loop_ids(ha);
ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0123,
- "loop_id_map=%p. \n", ha->loop_id_map);
+ "loop_id_map=%p.\n", ha->loop_id_map);
}
- return 1;
+ return 0;
fail_async_pd:
dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma);
@@ -3562,22 +3628,28 @@ static void
qla2x00_free_fw_dump(struct qla_hw_data *ha)
{
if (ha->fce)
- dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
- ha->fce_dma);
+ dma_free_coherent(&ha->pdev->dev,
+ FCE_SIZE, ha->fce, ha->fce_dma);
- if (ha->fw_dump) {
- if (ha->eft)
- dma_free_coherent(&ha->pdev->dev,
- ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma);
+ if (ha->eft)
+ dma_free_coherent(&ha->pdev->dev,
+ EFT_SIZE, ha->eft, ha->eft_dma);
+
+ if (ha->fw_dump)
vfree(ha->fw_dump);
- }
+ if (ha->fw_dump_template)
+ vfree(ha->fw_dump_template);
+
ha->fce = NULL;
ha->fce_dma = 0;
ha->eft = NULL;
ha->eft_dma = 0;
- ha->fw_dump = NULL;
ha->fw_dumped = 0;
ha->fw_dump_reading = 0;
+ ha->fw_dump = NULL;
+ ha->fw_dump_len = 0;
+ ha->fw_dump_template = NULL;
+ ha->fw_dump_template_len = 0;
}
/*
@@ -5242,7 +5314,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
/* Firmware interface routines. */
-#define FW_BLOBS 10
+#define FW_BLOBS 11
#define FW_ISP21XX 0
#define FW_ISP22XX 1
#define FW_ISP2300 2
@@ -5253,6 +5325,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
#define FW_ISP82XX 7
#define FW_ISP2031 8
#define FW_ISP8031 9
+#define FW_ISP2071 10
#define FW_FILE_ISP21XX "ql2100_fw.bin"
#define FW_FILE_ISP22XX "ql2200_fw.bin"
@@ -5264,6 +5337,8 @@ qla2x00_timer(scsi_qla_host_t *vha)
#define FW_FILE_ISP82XX "ql8200_fw.bin"
#define FW_FILE_ISP2031 "ql2600_fw.bin"
#define FW_FILE_ISP8031 "ql8300_fw.bin"
+#define FW_FILE_ISP2071 "ql2700_fw.bin"
+
static DEFINE_MUTEX(qla_fw_lock);
@@ -5278,6 +5353,7 @@ static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
{ .name = FW_FILE_ISP82XX, },
{ .name = FW_FILE_ISP2031, },
{ .name = FW_FILE_ISP8031, },
+ { .name = FW_FILE_ISP2071, },
};
struct fw_blob *
@@ -5306,6 +5382,8 @@ qla2x00_request_firmware(scsi_qla_host_t *vha)
blob = &qla_fw_blobs[FW_ISP2031];
} else if (IS_QLA8031(ha)) {
blob = &qla_fw_blobs[FW_ISP8031];
+ } else if (IS_QLA2071(ha)) {
+ blob = &qla_fw_blobs[FW_ISP2071];
} else {
return NULL;
}
@@ -5635,6 +5713,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8031) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISPF001) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8044) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2071) },
{ 0 },
};
MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index bd56cde795fc..f28123e8ed65 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -568,7 +568,7 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
else if (IS_P3P_TYPE(ha)) {
*start = FA_FLASH_LAYOUT_ADDR_82;
goto end;
- } else if (IS_QLA83XX(ha)) {
+ } else if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
*start = FA_FLASH_LAYOUT_ADDR_83;
goto end;
}
@@ -682,7 +682,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
/* Assign FCP prio region since older adapters may not have FLT, or
FCP prio region in it's FLT.
*/
- ha->flt_region_fcp_prio = ha->flags.port0 ?
+ ha->flt_region_fcp_prio = (ha->port_no == 0) ?
fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
ha->flt_region_flt = flt_addr;
@@ -743,47 +743,71 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
ha->flt_region_vpd_nvram = start;
if (IS_P3P_TYPE(ha))
break;
- if (ha->flags.port0)
+ if (ha->port_no == 0)
ha->flt_region_vpd = start;
break;
case FLT_REG_VPD_1:
if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
break;
- if (!ha->flags.port0)
+ if (ha->port_no == 1)
+ ha->flt_region_vpd = start;
+ break;
+ case FLT_REG_VPD_2:
+ if (!IS_QLA27XX(ha))
+ break;
+ if (ha->port_no == 2)
+ ha->flt_region_vpd = start;
+ break;
+ case FLT_REG_VPD_3:
+ if (!IS_QLA27XX(ha))
+ break;
+ if (ha->port_no == 3)
ha->flt_region_vpd = start;
break;
case FLT_REG_NVRAM_0:
if (IS_QLA8031(ha))
break;
- if (ha->flags.port0)
+ if (ha->port_no == 0)
ha->flt_region_nvram = start;
break;
case FLT_REG_NVRAM_1:
if (IS_QLA8031(ha))
break;
- if (!ha->flags.port0)
+ if (ha->port_no == 1)
+ ha->flt_region_nvram = start;
+ break;
+ case FLT_REG_NVRAM_2:
+ if (!IS_QLA27XX(ha))
+ break;
+ if (ha->port_no == 2)
+ ha->flt_region_nvram = start;
+ break;
+ case FLT_REG_NVRAM_3:
+ if (!IS_QLA27XX(ha))
+ break;
+ if (ha->port_no == 3)
ha->flt_region_nvram = start;
break;
case FLT_REG_FDT:
ha->flt_region_fdt = start;
break;
case FLT_REG_NPIV_CONF_0:
- if (ha->flags.port0)
+ if (ha->port_no == 0)
ha->flt_region_npiv_conf = start;
break;
case FLT_REG_NPIV_CONF_1:
- if (!ha->flags.port0)
+ if (ha->port_no == 1)
ha->flt_region_npiv_conf = start;
break;
case FLT_REG_GOLD_FW:
ha->flt_region_gold_fw = start;
break;
case FLT_REG_FCP_PRIO_0:
- if (ha->flags.port0)
+ if (ha->port_no == 0)
ha->flt_region_fcp_prio = start;
break;
case FLT_REG_FCP_PRIO_1:
- if (!ha->flags.port0)
+ if (ha->port_no == 1)
ha->flt_region_fcp_prio = start;
break;
case FLT_REG_BOOT_CODE_82XX:
@@ -813,13 +837,13 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
case FLT_REG_FCOE_NVRAM_0:
if (!(IS_QLA8031(ha) || IS_QLA8044(ha)))
break;
- if (ha->flags.port0)
+ if (ha->port_no == 0)
ha->flt_region_nvram = start;
break;
case FLT_REG_FCOE_NVRAM_1:
if (!(IS_QLA8031(ha) || IS_QLA8044(ha)))
break;
- if (!ha->flags.port0)
+ if (ha->port_no == 1)
ha->flt_region_nvram = start;
break;
}
@@ -832,12 +856,12 @@ no_flash_data:
ha->flt_region_fw = def_fw[def];
ha->flt_region_boot = def_boot[def];
ha->flt_region_vpd_nvram = def_vpd_nvram[def];
- ha->flt_region_vpd = ha->flags.port0 ?
+ ha->flt_region_vpd = (ha->port_no == 0) ?
def_vpd0[def] : def_vpd1[def];
- ha->flt_region_nvram = ha->flags.port0 ?
+ ha->flt_region_nvram = (ha->port_no == 0) ?
def_nvram0[def] : def_nvram1[def];
ha->flt_region_fdt = def_fdt[def];
- ha->flt_region_npiv_conf = ha->flags.port0 ?
+ ha->flt_region_npiv_conf = (ha->port_no == 0) ?
def_npiv_conf0[def] : def_npiv_conf1[def];
done:
ql_dbg(ql_dbg_init, vha, 0x004a,
@@ -989,7 +1013,7 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
- !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha))
+ !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && !IS_QLA27XX(ha))
return QLA_SUCCESS;
ret = qla2xxx_find_flt_start(vha, &flt_addr);
@@ -1192,7 +1216,8 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
struct qla_hw_data *ha = vha->hw;
/* Prepare burst-capable write on supported ISPs. */
- if ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha)) &&
+ if ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
+ IS_QLA27XX(ha)) &&
!(faddr & 0xfff) && dwords > OPTROM_BURST_DWORDS) {
optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
&optrom_dma, GFP_KERNEL);
@@ -1675,7 +1700,7 @@ qla83xx_select_led_port(struct qla_hw_data *ha)
if (!IS_QLA83XX(ha))
goto out;
- if (ha->flags.port0)
+ if (ha->port_no == 0)
led_select_value = QLA83XX_LED_PORT0;
else
led_select_value = QLA83XX_LED_PORT1;
@@ -2332,7 +2357,7 @@ qla2x00_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
*/
rest_addr = 0xffff;
sec_mask = 0x10000;
- break;
+ break;
}
/*
* ST m29w010b part - 16kb sector size
@@ -2558,7 +2583,7 @@ qla25xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
uint32_t faddr, left, burst;
struct qla_hw_data *ha = vha->hw;
- if (IS_QLA25XX(ha) || IS_QLA81XX(ha))
+ if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA27XX(ha))
goto try_fast;
if (offset & 0xfff)
goto slow_read;
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 2eb97d7e8d12..0cb73074c199 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -790,17 +790,32 @@ static inline int test_tgt_sess_count(struct qla_tgt *tgt)
}
/* Called by tcm_qla2xxx configfs code */
-void qlt_stop_phase1(struct qla_tgt *tgt)
+int qlt_stop_phase1(struct qla_tgt *tgt)
{
struct scsi_qla_host *vha = tgt->vha;
struct qla_hw_data *ha = tgt->ha;
unsigned long flags;
+ mutex_lock(&qla_tgt_mutex);
+ if (!vha->fc_vport) {
+ struct Scsi_Host *sh = vha->host;
+ struct fc_host_attrs *fc_host = shost_to_fc_host(sh);
+ bool npiv_vports;
+
+ spin_lock_irqsave(sh->host_lock, flags);
+ npiv_vports = (fc_host->npiv_vports_inuse);
+ spin_unlock_irqrestore(sh->host_lock, flags);
+
+ if (npiv_vports) {
+ mutex_unlock(&qla_tgt_mutex);
+ return -EPERM;
+ }
+ }
if (tgt->tgt_stop || tgt->tgt_stopped) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04e,
"Already in tgt->tgt_stop or tgt_stopped state\n");
- dump_stack();
- return;
+ mutex_unlock(&qla_tgt_mutex);
+ return -EPERM;
}
ql_dbg(ql_dbg_tgt, vha, 0xe003, "Stopping target for host %ld(%p)\n",
@@ -815,6 +830,7 @@ void qlt_stop_phase1(struct qla_tgt *tgt)
qlt_clear_tgt_db(tgt, true);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
mutex_unlock(&vha->vha_tgt.tgt_mutex);
+ mutex_unlock(&qla_tgt_mutex);
flush_delayed_work(&tgt->sess_del_work);
@@ -841,6 +857,7 @@ void qlt_stop_phase1(struct qla_tgt *tgt)
/* Wait for sessions to clear out (just in case) */
wait_event(tgt->waitQ, test_tgt_sess_count(tgt));
+ return 0;
}
EXPORT_SYMBOL(qlt_stop_phase1);
@@ -3185,7 +3202,8 @@ restart:
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02c,
"SRR cmd %p (se_cmd %p, tag %d, op %x), "
"sg_cnt=%d, offset=%d", cmd, &cmd->se_cmd, cmd->tag,
- se_cmd->t_task_cdb[0], cmd->sg_cnt, cmd->offset);
+ se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0,
+ cmd->sg_cnt, cmd->offset);
qlt_handle_srr(vha, sctio, imm);
@@ -4181,6 +4199,9 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha)
tgt->datasegs_per_cmd = QLA_TGT_DATASEGS_PER_CMD_24XX;
tgt->datasegs_per_cont = QLA_TGT_DATASEGS_PER_CONT_24XX;
+ if (base_vha->fc_vport)
+ return 0;
+
mutex_lock(&qla_tgt_mutex);
list_add_tail(&tgt->tgt_list_entry, &qla_tgt_glist);
mutex_unlock(&qla_tgt_mutex);
@@ -4194,6 +4215,10 @@ int qlt_remove_target(struct qla_hw_data *ha, struct scsi_qla_host *vha)
if (!vha->vha_tgt.qla_tgt)
return 0;
+ if (vha->fc_vport) {
+ qlt_release(vha->vha_tgt.qla_tgt);
+ return 0;
+ }
mutex_lock(&qla_tgt_mutex);
list_del(&vha->vha_tgt.qla_tgt->tgt_list_entry);
mutex_unlock(&qla_tgt_mutex);
@@ -4265,6 +4290,12 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn,
spin_unlock_irqrestore(&ha->hardware_lock, flags);
continue;
}
+ if (tgt->tgt_stop) {
+ pr_debug("MODE_TARGET in shutdown on qla2xxx(%d)\n",
+ host->host_no);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ continue;
+ }
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (!scsi_host_get(host)) {
@@ -4279,12 +4310,11 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn,
scsi_host_put(host);
continue;
}
- mutex_unlock(&qla_tgt_mutex);
-
rc = (*callback)(vha, target_lport_ptr, npiv_wwpn, npiv_wwnn);
if (rc != 0)
scsi_host_put(host);
+ mutex_unlock(&qla_tgt_mutex);
return rc;
}
mutex_unlock(&qla_tgt_mutex);
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index 66e755cdde57..ce33d8c26406 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -1001,7 +1001,7 @@ extern void qlt_modify_vp_config(struct scsi_qla_host *,
extern void qlt_probe_one_stage1(struct scsi_qla_host *, struct qla_hw_data *);
extern int qlt_mem_alloc(struct qla_hw_data *);
extern void qlt_mem_free(struct qla_hw_data *);
-extern void qlt_stop_phase1(struct qla_tgt *);
+extern int qlt_stop_phase1(struct qla_tgt *);
extern void qlt_stop_phase2(struct qla_tgt *);
extern irqreturn_t qla83xx_msix_atio_q(int, void *);
extern void qlt_83xx_iospace_config(struct qla_hw_data *);
diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c
new file mode 100644
index 000000000000..a804e9b744bb
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_tmpl.c
@@ -0,0 +1,909 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c) 2003-2013 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#include "qla_def.h"
+#include "qla_tmpl.h"
+
+/* note default template is in big endian */
+static const uint32_t ql27xx_fwdt_default_template[] = {
+ 0x63000000, 0xa4000000, 0x7c050000, 0x00000000,
+ 0x30000000, 0x01000000, 0x00000000, 0xc0406eb4,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x04010000, 0x14000000, 0x00000000,
+ 0x02000000, 0x44000000, 0x09010000, 0x10000000,
+ 0x00000000, 0x02000000, 0x01010000, 0x1c000000,
+ 0x00000000, 0x02000000, 0x00600000, 0x00000000,
+ 0xc0000000, 0x01010000, 0x1c000000, 0x00000000,
+ 0x02000000, 0x00600000, 0x00000000, 0xcc000000,
+ 0x01010000, 0x1c000000, 0x00000000, 0x02000000,
+ 0x10600000, 0x00000000, 0xd4000000, 0x01010000,
+ 0x1c000000, 0x00000000, 0x02000000, 0x700f0000,
+ 0x00000060, 0xf0000000, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x00700000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x10700000, 0x041000c0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x40700000, 0x041000c0,
+ 0x01010000, 0x1c000000, 0x00000000, 0x02000000,
+ 0x007c0000, 0x01000000, 0xc0000000, 0x00010000,
+ 0x18000000, 0x00000000, 0x02000000, 0x007c0000,
+ 0x040300c4, 0x00010000, 0x18000000, 0x00000000,
+ 0x02000000, 0x007c0000, 0x040100c0, 0x01010000,
+ 0x1c000000, 0x00000000, 0x02000000, 0x007c0000,
+ 0x00000000, 0xc0000000, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x007c0000, 0x04200000,
+ 0x0b010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x0c000000, 0x00000000, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000000b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000010b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000020b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000030b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000040b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000050b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000060b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000070b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000080b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x000090b0, 0x02010000, 0x20000000,
+ 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
+ 0xf0000000, 0x0000a0b0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x0a000000, 0x040100c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x0a000000, 0x04200080, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x00be0000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x10be0000, 0x041000c0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x20be0000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x30be0000, 0x041000c0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x00b00000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x10b00000, 0x041000c0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x20b00000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x30b00000, 0x041000c0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x00300000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x10300000, 0x041000c0, 0x00010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x20300000, 0x041000c0,
+ 0x00010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x30300000, 0x041000c0, 0x0a010000, 0x10000000,
+ 0x00000000, 0x02000000, 0x06010000, 0x1c000000,
+ 0x00000000, 0x02000000, 0x01000000, 0x00000200,
+ 0xff230200, 0x06010000, 0x1c000000, 0x00000000,
+ 0x02000000, 0x02000000, 0x00001000, 0x00000000,
+ 0x07010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x00000000, 0x01000000, 0x07010000, 0x18000000,
+ 0x00000000, 0x02000000, 0x00000000, 0x02000000,
+ 0x07010000, 0x18000000, 0x00000000, 0x02000000,
+ 0x00000000, 0x03000000, 0x0d010000, 0x14000000,
+ 0x00000000, 0x02000000, 0x00000000, 0xff000000,
+ 0x10000000, 0x00000000, 0x00000080,
+};
+
+static inline void __iomem *
+qla27xx_isp_reg(struct scsi_qla_host *vha)
+{
+ return &vha->hw->iobase->isp24;
+}
+
+static inline void
+qla27xx_insert16(uint16_t value, void *buf, ulong *len)
+{
+ if (buf) {
+ buf += *len;
+ *(__le16 *)buf = cpu_to_le16(value);
+ }
+ *len += sizeof(value);
+}
+
+static inline void
+qla27xx_insert32(uint32_t value, void *buf, ulong *len)
+{
+ if (buf) {
+ buf += *len;
+ *(__le32 *)buf = cpu_to_le32(value);
+ }
+ *len += sizeof(value);
+}
+
+static inline void
+qla27xx_insertbuf(void *mem, ulong size, void *buf, ulong *len)
+{
+ ulong cnt = size;
+
+ if (buf && mem) {
+ buf += *len;
+ while (cnt >= sizeof(uint32_t)) {
+ *(__le32 *)buf = cpu_to_le32p(mem);
+ buf += sizeof(uint32_t);
+ mem += sizeof(uint32_t);
+ cnt -= sizeof(uint32_t);
+ }
+ if (cnt)
+ memcpy(buf, mem, cnt);
+ }
+ *len += size;
+}
+
+static inline void
+qla27xx_read8(void *window, void *buf, ulong *len)
+{
+ uint8_t value = ~0;
+
+ if (buf) {
+ value = RD_REG_BYTE((__iomem void *)window);
+ ql_dbg(ql_dbg_misc, NULL, 0xd011,
+ "%s: -> %x\n", __func__, value);
+ }
+ qla27xx_insert32(value, buf, len);
+}
+
+static inline void
+qla27xx_read16(void *window, void *buf, ulong *len)
+{
+ uint16_t value = ~0;
+
+ if (buf) {
+ value = RD_REG_WORD((__iomem void *)window);
+ ql_dbg(ql_dbg_misc, NULL, 0xd012,
+ "%s: -> %x\n", __func__, value);
+ }
+ qla27xx_insert32(value, buf, len);
+}
+
+static inline void
+qla27xx_read32(void *window, void *buf, ulong *len)
+{
+ uint32_t value = ~0;
+
+ if (buf) {
+ value = RD_REG_DWORD((__iomem void *)window);
+ ql_dbg(ql_dbg_misc, NULL, 0xd013,
+ "%s: -> %x\n", __func__, value);
+ }
+ qla27xx_insert32(value, buf, len);
+}
+
+static inline void (*qla27xx_read_vector(uint width))(void *, void *, ulong *)
+{
+ return
+ (width == 1) ? qla27xx_read8 :
+ (width == 2) ? qla27xx_read16 :
+ qla27xx_read32;
+}
+
+static inline void
+qla27xx_read_reg(__iomem struct device_reg_24xx *reg,
+ uint offset, void *buf, ulong *len)
+{
+ void *window = (void *)reg + offset;
+
+ if (buf) {
+ ql_dbg(ql_dbg_misc, NULL, 0xd014,
+ "%s: @%x\n", __func__, offset);
+ }
+ qla27xx_insert32(offset, buf, len);
+ qla27xx_read32(window, buf, len);
+}
+
+static inline void
+qla27xx_write_reg(__iomem struct device_reg_24xx *reg,
+ uint offset, uint32_t data, void *buf)
+{
+ __iomem void *window = reg + offset;
+
+ if (buf) {
+ ql_dbg(ql_dbg_misc, NULL, 0xd015,
+ "%s: @%x <- %x\n", __func__, offset, data);
+ WRT_REG_DWORD(window, data);
+ }
+}
+
+static inline void
+qla27xx_read_window(__iomem struct device_reg_24xx *reg,
+ uint32_t base, uint offset, uint count, uint width, void *buf,
+ ulong *len)
+{
+ void *window = (void *)reg + offset;
+ void (*readn)(void *, void *, ulong *) = qla27xx_read_vector(width);
+
+ if (buf) {
+ ql_dbg(ql_dbg_misc, NULL, 0xd016,
+ "%s: base=%x offset=%x count=%x width=%x\n",
+ __func__, base, offset, count, width);
+ }
+ qla27xx_write_reg(reg, IOBASE_ADDR, base, buf);
+ while (count--) {
+ qla27xx_insert32(base, buf, len);
+ readn(window, buf, len);
+ window += width;
+ base += width;
+ }
+}
+
+static inline void
+qla27xx_skip_entry(struct qla27xx_fwdt_entry *ent, void *buf)
+{
+ if (buf)
+ ent->hdr.driver_flags |= DRIVER_FLAG_SKIP_ENTRY;
+}
+
+static int
+qla27xx_fwdt_entry_t0(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd100,
+ "%s: nop [%lx]\n", __func__, *len);
+ qla27xx_skip_entry(ent, buf);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t255(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd1ff,
+ "%s: end [%lx]\n", __func__, *len);
+ qla27xx_skip_entry(ent, buf);
+
+ /* terminate */
+ return true;
+}
+
+static int
+qla27xx_fwdt_entry_t256(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd200,
+ "%s: rdio t1 [%lx]\n", __func__, *len);
+ qla27xx_read_window(reg, ent->t256.base_addr, ent->t256.pci_offset,
+ ent->t256.reg_count, ent->t256.reg_width, buf, len);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t257(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd201,
+ "%s: wrio t1 [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, IOBASE_ADDR, ent->t257.base_addr, buf);
+ qla27xx_write_reg(reg, ent->t257.pci_offset, ent->t257.write_data, buf);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t258(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd202,
+ "%s: rdio t2 [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, ent->t258.banksel_offset, ent->t258.bank, buf);
+ qla27xx_read_window(reg, ent->t258.base_addr, ent->t258.pci_offset,
+ ent->t258.reg_count, ent->t258.reg_width, buf, len);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t259(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd203,
+ "%s: wrio t2 [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, IOBASE_ADDR, ent->t259.base_addr, buf);
+ qla27xx_write_reg(reg, ent->t259.banksel_offset, ent->t259.bank, buf);
+ qla27xx_write_reg(reg, ent->t259.pci_offset, ent->t259.write_data, buf);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t260(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd204,
+ "%s: rdpci [%lx]\n", __func__, *len);
+ qla27xx_read_reg(reg, ent->t260.pci_addr, buf, len);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t261(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd205,
+ "%s: wrpci [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, ent->t261.pci_addr, ent->t261.write_data, buf);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ulong dwords;
+ ulong start;
+ ulong end;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd206,
+ "%s: rdram(%x) [%lx]\n", __func__, ent->t262.ram_area, *len);
+ start = ent->t262.start_addr;
+ end = ent->t262.end_addr;
+
+ if (ent->t262.ram_area == T262_RAM_AREA_CRITICAL_RAM) {
+ ;
+ } else if (ent->t262.ram_area == T262_RAM_AREA_EXTERNAL_RAM) {
+ end = vha->hw->fw_memory_size;
+ if (buf)
+ ent->t262.end_addr = end;
+ } else if (ent->t262.ram_area == T262_RAM_AREA_SHARED_RAM) {
+ start = vha->hw->fw_shared_ram_start;
+ end = vha->hw->fw_shared_ram_end;
+ if (buf) {
+ ent->t262.start_addr = start;
+ ent->t262.end_addr = end;
+ }
+ } else if (ent->t262.ram_area == T262_RAM_AREA_DDR_RAM) {
+ ql_dbg(ql_dbg_misc, vha, 0xd021,
+ "%s: unsupported ddr ram\n", __func__);
+ qla27xx_skip_entry(ent, buf);
+ goto done;
+ } else {
+ ql_dbg(ql_dbg_misc, vha, 0xd022,
+ "%s: unknown area %u\n", __func__, ent->t262.ram_area);
+ qla27xx_skip_entry(ent, buf);
+ goto done;
+ }
+
+ if (end < start) {
+ ql_dbg(ql_dbg_misc, vha, 0xd023,
+ "%s: bad range (start=%x end=%x)\n", __func__,
+ ent->t262.end_addr, ent->t262.start_addr);
+ qla27xx_skip_entry(ent, buf);
+ goto done;
+ }
+
+ dwords = end - start + 1;
+ if (buf) {
+ ql_dbg(ql_dbg_misc, vha, 0xd024,
+ "%s: @%lx -> (%lx dwords)\n", __func__, start, dwords);
+ buf += *len;
+ qla24xx_dump_ram(vha->hw, start, buf, dwords, &buf);
+ }
+ *len += dwords * sizeof(uint32_t);
+done:
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ uint count = 0;
+ uint i;
+ uint length;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd207,
+ "%s: getq(%x) [%lx]\n", __func__, ent->t263.queue_type, *len);
+ if (ent->t263.queue_type == T263_QUEUE_TYPE_REQ) {
+ for (i = 0; i < vha->hw->max_req_queues; i++) {
+ struct req_que *req = vha->hw->req_q_map[i];
+ if (req || !buf) {
+ length = req ?
+ req->length : REQUEST_ENTRY_CNT_24XX;
+ qla27xx_insert16(i, buf, len);
+ qla27xx_insert16(length, buf, len);
+ qla27xx_insertbuf(req ? req->ring : NULL,
+ length * sizeof(*req->ring), buf, len);
+ count++;
+ }
+ }
+ } else if (ent->t263.queue_type == T263_QUEUE_TYPE_RSP) {
+ for (i = 0; i < vha->hw->max_rsp_queues; i++) {
+ struct rsp_que *rsp = vha->hw->rsp_q_map[i];
+ if (rsp || !buf) {
+ length = rsp ?
+ rsp->length : RESPONSE_ENTRY_CNT_MQ;
+ qla27xx_insert16(i, buf, len);
+ qla27xx_insert16(length, buf, len);
+ qla27xx_insertbuf(rsp ? rsp->ring : NULL,
+ length * sizeof(*rsp->ring), buf, len);
+ count++;
+ }
+ }
+ } else if (ent->t263.queue_type == T263_QUEUE_TYPE_ATIO) {
+ ql_dbg(ql_dbg_misc, vha, 0xd025,
+ "%s: unsupported atio queue\n", __func__);
+ qla27xx_skip_entry(ent, buf);
+ goto done;
+ } else {
+ ql_dbg(ql_dbg_misc, vha, 0xd026,
+ "%s: unknown queue %u\n", __func__, ent->t263.queue_type);
+ qla27xx_skip_entry(ent, buf);
+ goto done;
+ }
+
+ if (buf)
+ ent->t263.num_queues = count;
+done:
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t264(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd208,
+ "%s: getfce [%lx]\n", __func__, *len);
+ if (vha->hw->fce) {
+ if (buf) {
+ ent->t264.fce_trace_size = FCE_SIZE;
+ ent->t264.write_pointer = vha->hw->fce_wr;
+ ent->t264.base_pointer = vha->hw->fce_dma;
+ ent->t264.fce_enable_mb0 = vha->hw->fce_mb[0];
+ ent->t264.fce_enable_mb2 = vha->hw->fce_mb[2];
+ ent->t264.fce_enable_mb3 = vha->hw->fce_mb[3];
+ ent->t264.fce_enable_mb4 = vha->hw->fce_mb[4];
+ ent->t264.fce_enable_mb5 = vha->hw->fce_mb[5];
+ ent->t264.fce_enable_mb6 = vha->hw->fce_mb[6];
+ }
+ qla27xx_insertbuf(vha->hw->fce, FCE_SIZE, buf, len);
+ } else {
+ ql_dbg(ql_dbg_misc, vha, 0xd027,
+ "%s: missing fce\n", __func__);
+ qla27xx_skip_entry(ent, buf);
+ }
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t265(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd209,
+ "%s: pause risc [%lx]\n", __func__, *len);
+ if (buf)
+ qla24xx_pause_risc(reg);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t266(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd20a,
+ "%s: reset risc [%lx]\n", __func__, *len);
+ if (buf)
+ qla24xx_soft_reset(vha->hw);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t267(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+
+ ql_dbg(ql_dbg_misc, vha, 0xd20b,
+ "%s: dis intr [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, ent->t267.pci_offset, ent->t267.data, buf);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t268(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd20c,
+ "%s: gethb(%x) [%lx]\n", __func__, ent->t268.buf_type, *len);
+ if (ent->t268.buf_type == T268_BUF_TYPE_EXTD_TRACE) {
+ if (vha->hw->eft) {
+ if (buf) {
+ ent->t268.buf_size = EFT_SIZE;
+ ent->t268.start_addr = vha->hw->eft_dma;
+ }
+ qla27xx_insertbuf(vha->hw->eft, EFT_SIZE, buf, len);
+ } else {
+ ql_dbg(ql_dbg_misc, vha, 0xd028,
+ "%s: missing eft\n", __func__);
+ qla27xx_skip_entry(ent, buf);
+ }
+ } else if (ent->t268.buf_type == T268_BUF_TYPE_EXCH_BUFOFF) {
+ ql_dbg(ql_dbg_misc, vha, 0xd029,
+ "%s: unsupported exchange offload buffer\n", __func__);
+ qla27xx_skip_entry(ent, buf);
+ } else if (ent->t268.buf_type == T268_BUF_TYPE_EXTD_LOGIN) {
+ ql_dbg(ql_dbg_misc, vha, 0xd02a,
+ "%s: unsupported extended login buffer\n", __func__);
+ qla27xx_skip_entry(ent, buf);
+ } else {
+ ql_dbg(ql_dbg_misc, vha, 0xd02b,
+ "%s: unknown buf %x\n", __func__, ent->t268.buf_type);
+ qla27xx_skip_entry(ent, buf);
+ }
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t269(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd20d,
+ "%s: scratch [%lx]\n", __func__, *len);
+ qla27xx_insert32(0xaaaaaaaa, buf, len);
+ qla27xx_insert32(0xbbbbbbbb, buf, len);
+ qla27xx_insert32(0xcccccccc, buf, len);
+ qla27xx_insert32(0xdddddddd, buf, len);
+ qla27xx_insert32(*len + sizeof(uint32_t), buf, len);
+ if (buf)
+ ent->t269.scratch_size = 5 * sizeof(uint32_t);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t270(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+ void *window = (void *)reg + 0xc4;
+ ulong dwords = ent->t270.count;
+ ulong addr = ent->t270.addr;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd20e,
+ "%s: rdremreg [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, IOBASE_ADDR, 0x40, buf);
+ while (dwords--) {
+ qla27xx_write_reg(reg, 0xc0, addr|0x80000000, buf);
+ qla27xx_read_reg(reg, 0xc4, buf, len);
+ qla27xx_insert32(addr, buf, len);
+ qla27xx_read32(window, buf, len);
+ addr++;
+ }
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t271(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+ ulong addr = ent->t271.addr;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd20f,
+ "%s: wrremreg [%lx]\n", __func__, *len);
+ qla27xx_write_reg(reg, IOBASE_ADDR, 0x40, buf);
+ qla27xx_read_reg(reg, 0xc4, buf, len);
+ qla27xx_insert32(addr, buf, len);
+ qla27xx_write_reg(reg, 0xc0, addr, buf);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t272(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ulong dwords = ent->t272.count;
+ ulong start = ent->t272.addr;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd210,
+ "%s: rdremram [%lx]\n", __func__, *len);
+ if (buf) {
+ ql_dbg(ql_dbg_misc, vha, 0xd02c,
+ "%s: @%lx -> (%lx dwords)\n", __func__, start, dwords);
+ buf += *len;
+ qla27xx_dump_mpi_ram(vha->hw, start, buf, dwords, &buf);
+ }
+ *len += dwords * sizeof(uint32_t);
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_t273(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ulong dwords = ent->t273.count;
+ ulong addr = ent->t273.addr;
+ uint32_t value;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd211,
+ "%s: pcicfg [%lx]\n", __func__, *len);
+ while (dwords--) {
+ value = ~0;
+ if (pci_read_config_dword(vha->hw->pdev, addr, &value))
+ ql_dbg(ql_dbg_misc, vha, 0xd02d,
+ "%s: failed pcicfg read at %lx\n", __func__, addr);
+ qla27xx_insert32(addr, buf, len);
+ qla27xx_insert32(value, buf, len);
+ addr += 4;
+ }
+
+ return false;
+}
+
+static int
+qla27xx_fwdt_entry_other(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
+{
+ ql_dbg(ql_dbg_misc, vha, 0xd2ff,
+ "%s: type %x [%lx]\n", __func__, ent->hdr.entry_type, *len);
+ qla27xx_skip_entry(ent, buf);
+
+ return false;
+}
+
+struct qla27xx_fwdt_entry_call {
+ int type;
+ int (*call)(
+ struct scsi_qla_host *,
+ struct qla27xx_fwdt_entry *,
+ void *,
+ ulong *);
+};
+
+static struct qla27xx_fwdt_entry_call ql27xx_fwdt_entry_call_list[] = {
+ { ENTRY_TYPE_NOP , qla27xx_fwdt_entry_t0 } ,
+ { ENTRY_TYPE_TMP_END , qla27xx_fwdt_entry_t255 } ,
+ { ENTRY_TYPE_RD_IOB_T1 , qla27xx_fwdt_entry_t256 } ,
+ { ENTRY_TYPE_WR_IOB_T1 , qla27xx_fwdt_entry_t257 } ,
+ { ENTRY_TYPE_RD_IOB_T2 , qla27xx_fwdt_entry_t258 } ,
+ { ENTRY_TYPE_WR_IOB_T2 , qla27xx_fwdt_entry_t259 } ,
+ { ENTRY_TYPE_RD_PCI , qla27xx_fwdt_entry_t260 } ,
+ { ENTRY_TYPE_WR_PCI , qla27xx_fwdt_entry_t261 } ,
+ { ENTRY_TYPE_RD_RAM , qla27xx_fwdt_entry_t262 } ,
+ { ENTRY_TYPE_GET_QUEUE , qla27xx_fwdt_entry_t263 } ,
+ { ENTRY_TYPE_GET_FCE , qla27xx_fwdt_entry_t264 } ,
+ { ENTRY_TYPE_PSE_RISC , qla27xx_fwdt_entry_t265 } ,
+ { ENTRY_TYPE_RST_RISC , qla27xx_fwdt_entry_t266 } ,
+ { ENTRY_TYPE_DIS_INTR , qla27xx_fwdt_entry_t267 } ,
+ { ENTRY_TYPE_GET_HBUF , qla27xx_fwdt_entry_t268 } ,
+ { ENTRY_TYPE_SCRATCH , qla27xx_fwdt_entry_t269 } ,
+ { ENTRY_TYPE_RDREMREG , qla27xx_fwdt_entry_t270 } ,
+ { ENTRY_TYPE_WRREMREG , qla27xx_fwdt_entry_t271 } ,
+ { ENTRY_TYPE_RDREMRAM , qla27xx_fwdt_entry_t272 } ,
+ { ENTRY_TYPE_PCICFG , qla27xx_fwdt_entry_t273 } ,
+ { -1 , qla27xx_fwdt_entry_other }
+};
+
+static inline int (*qla27xx_find_entry(int type))
+ (struct scsi_qla_host *, struct qla27xx_fwdt_entry *, void *, ulong *)
+{
+ struct qla27xx_fwdt_entry_call *list = ql27xx_fwdt_entry_call_list;
+
+ while (list->type != -1 && list->type != type)
+ list++;
+
+ return list->call;
+}
+
+static inline void *
+qla27xx_next_entry(void *p)
+{
+ struct qla27xx_fwdt_entry *ent = p;
+
+ return p + ent->hdr.entry_size;
+}
+
+static void
+qla27xx_walk_template(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_template *tmp, void *buf, ulong *len)
+{
+ struct qla27xx_fwdt_entry *ent = (void *)tmp + tmp->entry_offset;
+ ulong count = tmp->entry_count;
+
+ ql_dbg(ql_dbg_misc, vha, 0xd01a,
+ "%s: entry count %lx\n", __func__, count);
+ while (count--) {
+ if (qla27xx_find_entry(ent->hdr.entry_type)(vha, ent, buf, len))
+ break;
+ ent = qla27xx_next_entry(ent);
+ }
+ ql_dbg(ql_dbg_misc, vha, 0xd01b,
+ "%s: len=%lx\n", __func__, *len);
+}
+
+static void
+qla27xx_time_stamp(struct qla27xx_fwdt_template *tmp)
+{
+ tmp->capture_timestamp = jiffies;
+}
+
+static void
+qla27xx_driver_info(struct qla27xx_fwdt_template *tmp)
+{
+ uint8_t v[] = { 0, 0, 0, 0, 0, 0 };
+ int rval = 0;
+
+ rval = sscanf(qla2x00_version_str, "%hhu.%hhu.%hhu.%hhu.%hhu.%hhu",
+ v+0, v+1, v+2, v+3, v+4, v+5);
+
+ tmp->driver_info[0] = v[3] << 24 | v[2] << 16 | v[1] << 8 | v[0];
+ tmp->driver_info[1] = v[5] << 8 | v[4];
+ tmp->driver_info[2] = 0x12345678;
+}
+
+static void
+qla27xx_firmware_info(struct qla27xx_fwdt_template *tmp,
+ struct scsi_qla_host *vha)
+{
+ tmp->firmware_version[0] = vha->hw->fw_major_version;
+ tmp->firmware_version[1] = vha->hw->fw_minor_version;
+ tmp->firmware_version[2] = vha->hw->fw_subminor_version;
+ tmp->firmware_version[3] =
+ vha->hw->fw_attributes_h << 16 | vha->hw->fw_attributes;
+ tmp->firmware_version[4] =
+ vha->hw->fw_attributes_ext[1] << 16 | vha->hw->fw_attributes_ext[0];
+}
+
+static void
+ql27xx_edit_template(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_template *tmp)
+{
+ qla27xx_time_stamp(tmp);
+ qla27xx_driver_info(tmp);
+ qla27xx_firmware_info(tmp, vha);
+}
+
+static inline uint32_t
+qla27xx_template_checksum(void *p, ulong size)
+{
+ uint32_t *buf = p;
+ uint64_t sum = 0;
+
+ size /= sizeof(*buf);
+
+ while (size--)
+ sum += *buf++;
+
+ sum = (sum & 0xffffffff) + (sum >> 32);
+
+ return ~sum;
+}
+
+static inline int
+qla27xx_verify_template_checksum(struct qla27xx_fwdt_template *tmp)
+{
+ return qla27xx_template_checksum(tmp, tmp->template_size) == 0;
+}
+
+static inline int
+qla27xx_verify_template_header(struct qla27xx_fwdt_template *tmp)
+{
+ return tmp->template_type == TEMPLATE_TYPE_FWDUMP;
+}
+
+static void
+qla27xx_execute_fwdt_template(struct scsi_qla_host *vha)
+{
+ struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template;
+ ulong len;
+
+ if (qla27xx_fwdt_template_valid(tmp)) {
+ len = tmp->template_size;
+ tmp = memcpy(vha->hw->fw_dump, tmp, len);
+ ql27xx_edit_template(vha, tmp);
+ qla27xx_walk_template(vha, tmp, tmp, &len);
+ vha->hw->fw_dump_len = len;
+ vha->hw->fw_dumped = 1;
+ }
+}
+
+ulong
+qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *vha)
+{
+ struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template;
+ ulong len = 0;
+
+ if (qla27xx_fwdt_template_valid(tmp)) {
+ len = tmp->template_size;
+ qla27xx_walk_template(vha, tmp, NULL, &len);
+ }
+
+ return len;
+}
+
+ulong
+qla27xx_fwdt_template_size(void *p)
+{
+ struct qla27xx_fwdt_template *tmp = p;
+
+ return tmp->template_size;
+}
+
+ulong
+qla27xx_fwdt_template_default_size(void)
+{
+ return sizeof(ql27xx_fwdt_default_template);
+}
+
+const void *
+qla27xx_fwdt_template_default(void)
+{
+ return ql27xx_fwdt_default_template;
+}
+
+int
+qla27xx_fwdt_template_valid(void *p)
+{
+ struct qla27xx_fwdt_template *tmp = p;
+
+ if (!qla27xx_verify_template_header(tmp)) {
+ ql_log(ql_log_warn, NULL, 0xd01c,
+ "%s: template type %x\n", __func__, tmp->template_type);
+ return false;
+ }
+
+ if (!qla27xx_verify_template_checksum(tmp)) {
+ ql_log(ql_log_warn, NULL, 0xd01d,
+ "%s: failed template checksum\n", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+void
+qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked)
+{
+ ulong flags = 0;
+
+ if (!hardware_locked)
+ spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+
+ if (!vha->hw->fw_dump)
+ ql_log(ql_log_warn, vha, 0xd01e, "fwdump buffer missing.\n");
+ else if (!vha->hw->fw_dump_template)
+ ql_log(ql_log_warn, vha, 0xd01f, "fwdump template missing.\n");
+ else
+ qla27xx_execute_fwdt_template(vha);
+
+ if (!hardware_locked)
+ spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+}
diff --git a/drivers/scsi/qla2xxx/qla_tmpl.h b/drivers/scsi/qla2xxx/qla_tmpl.h
new file mode 100644
index 000000000000..c9d2fff4d964
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_tmpl.h
@@ -0,0 +1,205 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c) 2003-2013 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+
+#ifndef __QLA_DMP27_H__
+#define __QLA_DMP27_H__
+
+#define IOBASE_ADDR offsetof(struct device_reg_24xx, iobase_addr)
+
+struct __packed qla27xx_fwdt_template {
+ uint32_t template_type;
+ uint32_t entry_offset;
+ uint32_t template_size;
+ uint32_t reserved_1;
+
+ uint32_t entry_count;
+ uint32_t template_version;
+ uint32_t capture_timestamp;
+ uint32_t template_checksum;
+
+ uint32_t reserved_2;
+ uint32_t driver_info[3];
+
+ uint32_t saved_state[16];
+
+ uint32_t reserved_3[8];
+ uint32_t firmware_version[5];
+};
+
+#define TEMPLATE_TYPE_FWDUMP 99
+
+#define ENTRY_TYPE_NOP 0
+#define ENTRY_TYPE_TMP_END 255
+#define ENTRY_TYPE_RD_IOB_T1 256
+#define ENTRY_TYPE_WR_IOB_T1 257
+#define ENTRY_TYPE_RD_IOB_T2 258
+#define ENTRY_TYPE_WR_IOB_T2 259
+#define ENTRY_TYPE_RD_PCI 260
+#define ENTRY_TYPE_WR_PCI 261
+#define ENTRY_TYPE_RD_RAM 262
+#define ENTRY_TYPE_GET_QUEUE 263
+#define ENTRY_TYPE_GET_FCE 264
+#define ENTRY_TYPE_PSE_RISC 265
+#define ENTRY_TYPE_RST_RISC 266
+#define ENTRY_TYPE_DIS_INTR 267
+#define ENTRY_TYPE_GET_HBUF 268
+#define ENTRY_TYPE_SCRATCH 269
+#define ENTRY_TYPE_RDREMREG 270
+#define ENTRY_TYPE_WRREMREG 271
+#define ENTRY_TYPE_RDREMRAM 272
+#define ENTRY_TYPE_PCICFG 273
+
+#define CAPTURE_FLAG_PHYS_ONLY BIT_0
+#define CAPTURE_FLAG_PHYS_VIRT BIT_1
+
+#define DRIVER_FLAG_SKIP_ENTRY BIT_7
+
+struct __packed qla27xx_fwdt_entry {
+ struct __packed {
+ uint32_t entry_type;
+ uint32_t entry_size;
+ uint32_t reserved_1;
+
+ uint8_t capture_flags;
+ uint8_t reserved_2[2];
+ uint8_t driver_flags;
+ } hdr;
+ union __packed {
+ struct __packed {
+ } t0;
+
+ struct __packed {
+ } t255;
+
+ struct __packed {
+ uint32_t base_addr;
+ uint8_t reg_width;
+ uint16_t reg_count;
+ uint8_t pci_offset;
+ } t256;
+
+ struct __packed {
+ uint32_t base_addr;
+ uint32_t write_data;
+ uint8_t pci_offset;
+ uint8_t reserved[3];
+ } t257;
+
+ struct __packed {
+ uint32_t base_addr;
+ uint8_t reg_width;
+ uint16_t reg_count;
+ uint8_t pci_offset;
+ uint8_t banksel_offset;
+ uint8_t reserved[3];
+ uint32_t bank;
+ } t258;
+
+ struct __packed {
+ uint32_t base_addr;
+ uint32_t write_data;
+ uint8_t reserved[2];
+ uint8_t pci_offset;
+ uint8_t banksel_offset;
+ uint32_t bank;
+ } t259;
+
+ struct __packed {
+ uint8_t pci_addr;
+ uint8_t reserved[3];
+ } t260;
+
+ struct __packed {
+ uint8_t pci_addr;
+ uint8_t reserved[3];
+ uint32_t write_data;
+ } t261;
+
+ struct __packed {
+ uint8_t ram_area;
+ uint8_t reserved[3];
+ uint32_t start_addr;
+ uint32_t end_addr;
+ } t262;
+
+ struct __packed {
+ uint32_t num_queues;
+ uint8_t queue_type;
+ uint8_t reserved[3];
+ } t263;
+
+ struct __packed {
+ uint32_t fce_trace_size;
+ uint64_t write_pointer;
+ uint64_t base_pointer;
+ uint32_t fce_enable_mb0;
+ uint32_t fce_enable_mb2;
+ uint32_t fce_enable_mb3;
+ uint32_t fce_enable_mb4;
+ uint32_t fce_enable_mb5;
+ uint32_t fce_enable_mb6;
+ } t264;
+
+ struct __packed {
+ } t265;
+
+ struct __packed {
+ } t266;
+
+ struct __packed {
+ uint8_t pci_offset;
+ uint8_t reserved[3];
+ uint32_t data;
+ } t267;
+
+ struct __packed {
+ uint8_t buf_type;
+ uint8_t reserved[3];
+ uint32_t buf_size;
+ uint64_t start_addr;
+ } t268;
+
+ struct __packed {
+ uint32_t scratch_size;
+ } t269;
+
+ struct __packed {
+ uint32_t addr;
+ uint32_t count;
+ } t270;
+
+ struct __packed {
+ uint32_t addr;
+ uint32_t data;
+ } t271;
+
+ struct __packed {
+ uint32_t addr;
+ uint32_t count;
+ } t272;
+
+ struct __packed {
+ uint32_t addr;
+ uint32_t count;
+ } t273;
+ };
+};
+
+#define T262_RAM_AREA_CRITICAL_RAM 1
+#define T262_RAM_AREA_EXTERNAL_RAM 2
+#define T262_RAM_AREA_SHARED_RAM 3
+#define T262_RAM_AREA_DDR_RAM 4
+
+#define T263_QUEUE_TYPE_REQ 1
+#define T263_QUEUE_TYPE_RSP 2
+#define T263_QUEUE_TYPE_ATIO 3
+
+#define T268_BUF_TYPE_EXTD_TRACE 1
+#define T268_BUF_TYPE_EXCH_BUFOFF 2
+#define T268_BUF_TYPE_EXTD_LOGIN 3
+
+#endif
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 31d19535b015..e36b94712544 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.06.00.12-k"
+#define QLA2XXX_VERSION "8.07.00.02-k"
#define QLA_DRIVER_MAJOR_VER 8
-#define QLA_DRIVER_MINOR_VER 6
+#define QLA_DRIVER_MINOR_VER 7
#define QLA_DRIVER_PATCH_VER 0
#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 75a141bbe74d..788c4fe2b0c9 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -182,20 +182,6 @@ static int tcm_qla2xxx_npiv_parse_wwn(
return 0;
}
-static ssize_t tcm_qla2xxx_npiv_format_wwn(char *buf, size_t len,
- u64 wwpn, u64 wwnn)
-{
- u8 b[8], b2[8];
-
- put_unaligned_be64(wwpn, b);
- put_unaligned_be64(wwnn, b2);
- return snprintf(buf, len,
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x,"
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
- b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
- b2[0], b2[1], b2[2], b2[3], b2[4], b2[5], b2[6], b2[7]);
-}
-
static char *tcm_qla2xxx_npiv_get_fabric_name(void)
{
return "qla2xxx_npiv";
@@ -227,15 +213,6 @@ static char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg)
return lport->lport_naa_name;
}
-static char *tcm_qla2xxx_npiv_get_fabric_wwn(struct se_portal_group *se_tpg)
-{
- struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
- struct tcm_qla2xxx_tpg, se_tpg);
- struct tcm_qla2xxx_lport *lport = tpg->lport;
-
- return &lport->lport_npiv_name[0];
-}
-
static u16 tcm_qla2xxx_get_tag(struct se_portal_group *se_tpg)
{
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
@@ -941,15 +918,41 @@ static ssize_t tcm_qla2xxx_tpg_show_enable(
atomic_read(&tpg->lport_tpg_enabled));
}
+static void tcm_qla2xxx_depend_tpg(struct work_struct *work)
+{
+ struct tcm_qla2xxx_tpg *base_tpg = container_of(work,
+ struct tcm_qla2xxx_tpg, tpg_base_work);
+ struct se_portal_group *se_tpg = &base_tpg->se_tpg;
+ struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha;
+
+ if (!configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys,
+ &se_tpg->tpg_group.cg_item)) {
+ atomic_set(&base_tpg->lport_tpg_enabled, 1);
+ qlt_enable_vha(base_vha);
+ }
+ complete(&base_tpg->tpg_base_comp);
+}
+
+static void tcm_qla2xxx_undepend_tpg(struct work_struct *work)
+{
+ struct tcm_qla2xxx_tpg *base_tpg = container_of(work,
+ struct tcm_qla2xxx_tpg, tpg_base_work);
+ struct se_portal_group *se_tpg = &base_tpg->se_tpg;
+ struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha;
+
+ if (!qlt_stop_phase1(base_vha->vha_tgt.qla_tgt)) {
+ atomic_set(&base_tpg->lport_tpg_enabled, 0);
+ configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys,
+ &se_tpg->tpg_group.cg_item);
+ }
+ complete(&base_tpg->tpg_base_comp);
+}
+
static ssize_t tcm_qla2xxx_tpg_store_enable(
struct se_portal_group *se_tpg,
const char *page,
size_t count)
{
- struct se_wwn *se_wwn = se_tpg->se_tpg_wwn;
- struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
- struct tcm_qla2xxx_lport, lport_wwn);
- struct scsi_qla_host *vha = lport->qla_vha;
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
struct tcm_qla2xxx_tpg, se_tpg);
unsigned long op;
@@ -964,19 +967,28 @@ static ssize_t tcm_qla2xxx_tpg_store_enable(
pr_err("Illegal value for tpg_enable: %lu\n", op);
return -EINVAL;
}
-
if (op) {
- atomic_set(&tpg->lport_tpg_enabled, 1);
- qlt_enable_vha(vha);
+ if (atomic_read(&tpg->lport_tpg_enabled))
+ return -EEXIST;
+
+ INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_depend_tpg);
} else {
- if (!vha->vha_tgt.qla_tgt) {
- pr_err("struct qla_hw_data *vha->vha_tgt.qla_tgt is NULL\n");
- return -ENODEV;
- }
- atomic_set(&tpg->lport_tpg_enabled, 0);
- qlt_stop_phase1(vha->vha_tgt.qla_tgt);
+ if (!atomic_read(&tpg->lport_tpg_enabled))
+ return count;
+
+ INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_undepend_tpg);
}
+ init_completion(&tpg->tpg_base_comp);
+ schedule_work(&tpg->tpg_base_work);
+ wait_for_completion(&tpg->tpg_base_comp);
+ if (op) {
+ if (!atomic_read(&tpg->lport_tpg_enabled))
+ return -ENODEV;
+ } else {
+ if (atomic_read(&tpg->lport_tpg_enabled))
+ return -EPERM;
+ }
return count;
}
@@ -1053,11 +1065,64 @@ static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg)
/*
* Clear local TPG=1 pointer for non NPIV mode.
*/
- lport->tpg_1 = NULL;
-
+ lport->tpg_1 = NULL;
kfree(tpg);
}
+static ssize_t tcm_qla2xxx_npiv_tpg_show_enable(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ return tcm_qla2xxx_tpg_show_enable(se_tpg, page);
+}
+
+static ssize_t tcm_qla2xxx_npiv_tpg_store_enable(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct se_wwn *se_wwn = se_tpg->se_tpg_wwn;
+ struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
+ struct tcm_qla2xxx_lport, lport_wwn);
+ struct scsi_qla_host *vha = lport->qla_vha;
+ struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
+ struct tcm_qla2xxx_tpg, se_tpg);
+ unsigned long op;
+ int rc;
+
+ rc = kstrtoul(page, 0, &op);
+ if (rc < 0) {
+ pr_err("kstrtoul() returned %d\n", rc);
+ return -EINVAL;
+ }
+ if ((op != 1) && (op != 0)) {
+ pr_err("Illegal value for tpg_enable: %lu\n", op);
+ return -EINVAL;
+ }
+ if (op) {
+ if (atomic_read(&tpg->lport_tpg_enabled))
+ return -EEXIST;
+
+ atomic_set(&tpg->lport_tpg_enabled, 1);
+ qlt_enable_vha(vha);
+ } else {
+ if (!atomic_read(&tpg->lport_tpg_enabled))
+ return count;
+
+ atomic_set(&tpg->lport_tpg_enabled, 0);
+ qlt_stop_phase1(vha->vha_tgt.qla_tgt);
+ }
+
+ return count;
+}
+
+TF_TPG_BASE_ATTR(tcm_qla2xxx_npiv, enable, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *tcm_qla2xxx_npiv_tpg_attrs[] = {
+ &tcm_qla2xxx_npiv_tpg_enable.attr,
+ NULL,
+};
+
static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
struct se_wwn *wwn,
struct config_group *group,
@@ -1650,6 +1715,9 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
struct scsi_qla_host *npiv_vha;
struct tcm_qla2xxx_lport *lport =
(struct tcm_qla2xxx_lport *)target_lport_ptr;
+ struct tcm_qla2xxx_lport *base_lport =
+ (struct tcm_qla2xxx_lport *)base_vha->vha_tgt.target_lport_ptr;
+ struct tcm_qla2xxx_tpg *base_tpg;
struct fc_vport_identifiers vport_id;
if (!qla_tgt_mode_enabled(base_vha)) {
@@ -1657,6 +1725,13 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
return -EPERM;
}
+ if (!base_lport || !base_lport->tpg_1 ||
+ !atomic_read(&base_lport->tpg_1->lport_tpg_enabled)) {
+ pr_err("qla2xxx base_lport or tpg_1 not available\n");
+ return -EPERM;
+ }
+ base_tpg = base_lport->tpg_1;
+
memset(&vport_id, 0, sizeof(vport_id));
vport_id.port_name = npiv_wwpn;
vport_id.node_name = npiv_wwnn;
@@ -1675,7 +1750,6 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
npiv_vha = (struct scsi_qla_host *)vport->dd_data;
npiv_vha->vha_tgt.target_lport_ptr = target_lport_ptr;
lport->qla_vha = npiv_vha;
-
scsi_host_get(npiv_vha->host);
return 0;
}
@@ -1714,8 +1788,6 @@ static struct se_wwn *tcm_qla2xxx_npiv_make_lport(
}
lport->lport_npiv_wwpn = npiv_wwpn;
lport->lport_npiv_wwnn = npiv_wwnn;
- tcm_qla2xxx_npiv_format_wwn(&lport->lport_npiv_name[0],
- TCM_QLA2XXX_NAMELEN, npiv_wwpn, npiv_wwnn);
sprintf(lport->lport_naa_name, "naa.%016llx", (unsigned long long) npiv_wwpn);
ret = tcm_qla2xxx_init_lport(lport);
@@ -1824,7 +1896,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
.get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name,
.get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident,
- .tpg_get_wwn = tcm_qla2xxx_npiv_get_fabric_wwn,
+ .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn,
.tpg_get_tag = tcm_qla2xxx_get_tag,
.tpg_get_default_depth = tcm_qla2xxx_get_default_depth,
.tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id,
@@ -1935,7 +2007,7 @@ static int tcm_qla2xxx_register_configfs(void)
*/
npiv_fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs;
npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs =
- tcm_qla2xxx_tpg_attrs;
+ tcm_qla2xxx_npiv_tpg_attrs;
npiv_fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
npiv_fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
npiv_fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/drivers/scsi/qla2xxx/tcm_qla2xxx.h
index 275d8b9a7a34..33aaac8c7d59 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.h
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.h
@@ -4,8 +4,6 @@
#define TCM_QLA2XXX_VERSION "v0.1"
/* length of ASCII WWPNs including pad */
#define TCM_QLA2XXX_NAMELEN 32
-/* lenth of ASCII NPIV 'WWPN+WWNN' including pad */
-#define TCM_QLA2XXX_NPIV_NAMELEN 66
#include "qla_target.h"
@@ -43,6 +41,9 @@ struct tcm_qla2xxx_tpg {
struct tcm_qla2xxx_tpg_attrib tpg_attrib;
/* Returned by tcm_qla2xxx_make_tpg() */
struct se_portal_group se_tpg;
+ /* Items for dealing with configfs_depend_item */
+ struct completion tpg_base_comp;
+ struct work_struct tpg_base_work;
};
struct tcm_qla2xxx_fc_loopid {
@@ -62,8 +63,6 @@ struct tcm_qla2xxx_lport {
char lport_name[TCM_QLA2XXX_NAMELEN];
/* ASCII formatted naa WWPN for VPD page 83 etc */
char lport_naa_name[TCM_QLA2XXX_NAMELEN];
- /* ASCII formatted WWPN+WWNN for NPIV FC Target Lport */
- char lport_npiv_name[TCM_QLA2XXX_NPIV_NAMELEN];
/* map for fc_port pointers in 24-bit FC Port ID space */
struct btree_head32 lport_fcport_map;
/* vmalloc-ed memory for fc_port pointers for 16-bit FC loop ID */
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.c b/drivers/scsi/qla4xxx/ql4_83xx.c
index 919284834ad7..2eba35365920 100644
--- a/drivers/scsi/qla4xxx/ql4_83xx.c
+++ b/drivers/scsi/qla4xxx/ql4_83xx.c
@@ -1304,12 +1304,24 @@ static void qla4_83xx_process_init_seq(struct scsi_qla_host *ha)
static int qla4_83xx_restart(struct scsi_qla_host *ha)
{
int ret_val = QLA_SUCCESS;
+ uint32_t idc_ctrl;
qla4_83xx_process_stop_seq(ha);
- /* Collect minidump*/
- if (!test_and_clear_bit(AF_83XX_NO_FW_DUMP, &ha->flags))
+ /*
+ * Collect minidump.
+ * If IDC_CTRL BIT1 is set, clear it on going to INIT state and
+ * don't collect minidump
+ */
+ idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
+ if (idc_ctrl & GRACEFUL_RESET_BIT1) {
+ qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
+ (idc_ctrl & ~GRACEFUL_RESET_BIT1));
+ ql4_printk(KERN_INFO, ha, "%s: Graceful RESET: Not collecting minidump\n",
+ __func__);
+ } else {
qla4_8xxx_get_minidump(ha);
+ }
qla4_83xx_process_init_seq(ha);
@@ -1664,3 +1676,23 @@ void qla4_83xx_disable_pause(struct scsi_qla_host *ha)
__qla4_83xx_disable_pause(ha);
ha->isp_ops->idc_unlock(ha);
}
+
+/**
+ * qla4_83xx_is_detached - Check if we are marked invisible.
+ * @ha: Pointer to host adapter structure.
+ **/
+int qla4_83xx_is_detached(struct scsi_qla_host *ha)
+{
+ uint32_t drv_active;
+
+ drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
+
+ if (test_bit(AF_INIT_DONE, &ha->flags) &&
+ !(drv_active & (1 << ha->func_num))) {
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: drv_active = 0x%X\n",
+ __func__, drv_active));
+ return QLA_SUCCESS;
+ }
+
+ return QLA_ERROR;
+}
diff --git a/drivers/scsi/qla4xxx/ql4_bsg.c b/drivers/scsi/qla4xxx/ql4_bsg.c
index 04a0027dbca0..9f92cbf96477 100644
--- a/drivers/scsi/qla4xxx/ql4_bsg.c
+++ b/drivers/scsi/qla4xxx/ql4_bsg.c
@@ -517,7 +517,7 @@ static int qla4_83xx_wait_for_loopback_config_comp(struct scsi_qla_host *ha,
(ha->idc_extend_tmo * HZ))) {
ha->notify_idc_comp = 0;
ha->notify_link_up_comp = 0;
- ql4_printk(KERN_WARNING, ha, "%s: IDC Complete notification not received",
+ ql4_printk(KERN_WARNING, ha, "%s: Aborting: IDC Complete notification not received",
__func__);
status = QLA_ERROR;
goto exit_wait;
@@ -538,7 +538,7 @@ static int qla4_83xx_wait_for_loopback_config_comp(struct scsi_qla_host *ha,
if (!wait_for_completion_timeout(&ha->link_up_comp,
(IDC_COMP_TOV * HZ))) {
ha->notify_link_up_comp = 0;
- ql4_printk(KERN_WARNING, ha, "%s: LINK UP notification not received",
+ ql4_printk(KERN_WARNING, ha, "%s: Aborting: LINK UP notification not received",
__func__);
status = QLA_ERROR;
goto exit_wait;
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index aa67bb9a4426..73a502288bde 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -194,7 +194,7 @@
#define ADAPTER_INIT_TOV 30
#define ADAPTER_RESET_TOV 180
#define EXTEND_CMD_TOV 60
-#define WAIT_CMD_TOV 30
+#define WAIT_CMD_TOV 5
#define EH_WAIT_CMD_TOV 120
#define FIRMWARE_UP_TOV 60
#define RESET_FIRMWARE_TOV 30
@@ -297,6 +297,8 @@ struct ddb_entry {
/* Driver Re-login */
unsigned long flags; /* DDB Flags */
+#define DDB_CONN_CLOSE_FAILURE 0 /* 0x00000001 */
+
uint16_t default_relogin_timeout; /* Max time to wait for
* relogin to complete */
atomic_t retry_relogin_timer; /* Min Time between relogins
@@ -580,7 +582,6 @@ struct scsi_qla_host {
#define AF_82XX_FW_DUMPED 24 /* 0x01000000 */
#define AF_8XXX_RST_OWNER 25 /* 0x02000000 */
#define AF_82XX_DUMP_READING 26 /* 0x04000000 */
-#define AF_83XX_NO_FW_DUMP 27 /* 0x08000000 */
#define AF_83XX_IOCB_INTR_ON 28 /* 0x10000000 */
#define AF_83XX_MBOX_INTR_ON 29 /* 0x20000000 */
@@ -595,10 +596,10 @@ struct scsi_qla_host {
#define DPC_AEN 9 /* 0x00000200 */
#define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */
#define DPC_LINK_CHANGED 18 /* 0x00040000 */
-#define DPC_RESET_ACTIVE 20 /* 0x00040000 */
-#define DPC_HA_UNRECOVERABLE 21 /* 0x00080000 ISP-82xx only*/
-#define DPC_HA_NEED_QUIESCENT 22 /* 0x00100000 ISP-82xx only*/
-#define DPC_POST_IDC_ACK 23 /* 0x00200000 */
+#define DPC_RESET_ACTIVE 20 /* 0x00100000 */
+#define DPC_HA_UNRECOVERABLE 21 /* 0x00200000 ISP-82xx only*/
+#define DPC_HA_NEED_QUIESCENT 22 /* 0x00400000 ISP-82xx only*/
+#define DPC_POST_IDC_ACK 23 /* 0x00800000 */
#define DPC_RESTORE_ACB 24 /* 0x01000000 */
struct Scsi_Host *host; /* pointer to host data */
@@ -768,6 +769,7 @@ struct scsi_qla_host {
uint32_t fw_dump_capture_mask;
void *fw_dump_tmplt_hdr;
uint32_t fw_dump_tmplt_size;
+ uint32_t fw_dump_skip_size;
struct completion mbx_intr_comp;
@@ -910,7 +912,8 @@ static inline int is_qla80XX(struct scsi_qla_host *ha)
static inline int is_aer_supported(struct scsi_qla_host *ha)
{
return ((ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022) ||
- (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8324));
+ (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8324) ||
+ (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8042));
}
static inline int adapter_up(struct scsi_qla_host *ha)
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index 8d4092b33c07..209853ce0bbc 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -390,6 +390,7 @@ struct qla_flt_region {
#define MBOX_CMD_CLEAR_DATABASE_ENTRY 0x0031
#define MBOX_CMD_CONN_OPEN 0x0074
#define MBOX_CMD_CONN_CLOSE_SESS_LOGOUT 0x0056
+#define DDB_NOT_LOGGED_IN 0x09
#define LOGOUT_OPTION_CLOSE_SESSION 0x0002
#define LOGOUT_OPTION_RELOGIN 0x0004
#define LOGOUT_OPTION_FREE_DDB 0x0008
@@ -505,9 +506,9 @@ struct qla_flt_region {
#define MBOX_ASTS_RESPONSE_QUEUE_FULL 0x8028
#define MBOX_ASTS_IP_ADDR_STATE_CHANGED 0x8029
#define MBOX_ASTS_IPV6_DEFAULT_ROUTER_CHANGED 0x802A
-#define MBOX_ASTS_IPV6_PREFIX_EXPIRED 0x802B
-#define MBOX_ASTS_IPV6_ND_PREFIX_IGNORED 0x802C
-#define MBOX_ASTS_IPV6_LCL_PREFIX_IGNORED 0x802D
+#define MBOX_ASTS_IPV6_LINK_MTU_CHANGE 0x802B
+#define MBOX_ASTS_IPV6_AUTO_PREFIX_IGNORED 0x802C
+#define MBOX_ASTS_IPV6_ND_LOCAL_PREFIX_IGNORED 0x802D
#define MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD 0x802E
#define MBOX_ASTS_INITIALIZATION_FAILED 0x8031
#define MBOX_ASTS_SYSTEM_WARNING_EVENT 0x8036
@@ -528,14 +529,14 @@ struct qla_flt_region {
#define ACB_CONFIG_DISABLE 0x00
#define ACB_CONFIG_SET 0x01
-/* ACB State Defines */
-#define ACB_STATE_UNCONFIGURED 0x00
-#define ACB_STATE_INVALID 0x01
-#define ACB_STATE_ACQUIRING 0x02
-#define ACB_STATE_TENTATIVE 0x03
-#define ACB_STATE_DEPRICATED 0x04
-#define ACB_STATE_VALID 0x05
-#define ACB_STATE_DISABLING 0x06
+/* ACB/IP Address State Defines */
+#define IP_ADDRSTATE_UNCONFIGURED 0
+#define IP_ADDRSTATE_INVALID 1
+#define IP_ADDRSTATE_ACQUIRING 2
+#define IP_ADDRSTATE_TENTATIVE 3
+#define IP_ADDRSTATE_DEPRICATED 4
+#define IP_ADDRSTATE_PREFERRED 5
+#define IP_ADDRSTATE_DISABLING 6
/* FLASH offsets */
#define FLASH_SEGMENT_IFCB 0x04000000
@@ -698,14 +699,6 @@ struct addr_ctrl_blk {
uint8_t ipv6_lnk_lcl_addr_state;/* 222 */
uint8_t ipv6_addr0_state; /* 223 */
uint8_t ipv6_addr1_state; /* 224 */
-#define IP_ADDRSTATE_UNCONFIGURED 0
-#define IP_ADDRSTATE_INVALID 1
-#define IP_ADDRSTATE_ACQUIRING 2
-#define IP_ADDRSTATE_TENTATIVE 3
-#define IP_ADDRSTATE_DEPRICATED 4
-#define IP_ADDRSTATE_PREFERRED 5
-#define IP_ADDRSTATE_DISABLING 6
-
uint8_t ipv6_dflt_rtr_state; /* 225 */
#define IPV6_RTRSTATE_UNKNOWN 0
#define IPV6_RTRSTATE_MANUAL 1
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index d67c50e0b896..b1a19cd8d5b2 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -279,6 +279,8 @@ int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha,
uint8_t qla4xxx_set_ipaddr_state(uint8_t fw_ipaddr_state);
int qla4_83xx_get_port_config(struct scsi_qla_host *ha, uint32_t *config);
int qla4_83xx_set_port_config(struct scsi_qla_host *ha, uint32_t *config);
+int qla4_8xxx_check_init_adapter_retry(struct scsi_qla_host *ha);
+int qla4_83xx_is_detached(struct scsi_qla_host *ha);
extern int ql4xextended_error_logging;
extern int ql4xdontresethba;
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 7456eeb2e58a..28fbece7e08f 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -959,13 +959,8 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset)
qla4xxx_build_ddb_list(ha, is_reset);
set_bit(AF_ONLINE, &ha->flags);
-exit_init_hba:
- if (is_qla80XX(ha) && (status == QLA_ERROR)) {
- /* Since interrupts are registered in start_firmware for
- * 80XX, release them here if initialize_adapter fails */
- qla4xxx_free_irqs(ha);
- }
+exit_init_hba:
DEBUG2(printk("scsi%ld: initialize adapter: %s\n", ha->host_no,
status == QLA_ERROR ? "FAILED" : "SUCCEEDED"));
return status;
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index a3c8bc7706c2..b1925d195f41 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -385,9 +385,9 @@ static void qla4xxx_passthru_status_entry(struct scsi_qla_host *ha,
cls_conn = ddb_entry->conn;
conn = cls_conn->dd_data;
- spin_lock(&conn->session->lock);
+ spin_lock(&conn->session->back_lock);
task = iscsi_itt_to_task(conn, itt);
- spin_unlock(&conn->session->lock);
+ spin_unlock(&conn->session->back_lock);
if (task == NULL) {
ql4_printk(KERN_ERR, ha, "%s: Task is NULL\n", __func__);
@@ -635,6 +635,18 @@ static void qla4xxx_update_ipaddr_state(struct scsi_qla_host *ha,
}
}
+static void qla4xxx_default_router_changed(struct scsi_qla_host *ha,
+ uint32_t *mbox_sts)
+{
+ memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[0],
+ &mbox_sts[2], sizeof(uint32_t));
+ memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[1],
+ &mbox_sts[3], sizeof(uint32_t));
+ memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[2],
+ &mbox_sts[4], sizeof(uint32_t));
+ memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[3],
+ &mbox_sts[5], sizeof(uint32_t));
+}
/**
* qla4xxx_isr_decode_mailbox - decodes mailbox status
@@ -781,27 +793,44 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
mbox_sts[3]);
/* mbox_sts[2] = Old ACB state
* mbox_sts[3] = new ACB state */
- if ((mbox_sts[3] == ACB_STATE_VALID) &&
- ((mbox_sts[2] == ACB_STATE_TENTATIVE) ||
- (mbox_sts[2] == ACB_STATE_ACQUIRING))) {
+ if ((mbox_sts[3] == IP_ADDRSTATE_PREFERRED) &&
+ ((mbox_sts[2] == IP_ADDRSTATE_TENTATIVE) ||
+ (mbox_sts[2] == IP_ADDRSTATE_ACQUIRING))) {
set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
- } else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) &&
- (mbox_sts[2] == ACB_STATE_VALID)) {
+ } else if ((mbox_sts[3] == IP_ADDRSTATE_ACQUIRING) &&
+ (mbox_sts[2] == IP_ADDRSTATE_PREFERRED)) {
if (is_qla80XX(ha))
set_bit(DPC_RESET_HA_FW_CONTEXT,
&ha->dpc_flags);
else
set_bit(DPC_RESET_HA, &ha->dpc_flags);
- } else if (mbox_sts[3] == ACB_STATE_DISABLING) {
+ } else if (mbox_sts[3] == IP_ADDRSTATE_DISABLING) {
ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ACB in disabling state\n",
ha->host_no, __func__);
- } else if ((mbox_sts[3] == ACB_STATE_UNCONFIGURED)) {
+ } else if (mbox_sts[3] == IP_ADDRSTATE_UNCONFIGURED) {
complete(&ha->disable_acb_comp);
ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ACB state unconfigured\n",
ha->host_no, __func__);
}
break;
+ case MBOX_ASTS_IPV6_LINK_MTU_CHANGE:
+ case MBOX_ASTS_IPV6_AUTO_PREFIX_IGNORED:
+ case MBOX_ASTS_IPV6_ND_LOCAL_PREFIX_IGNORED:
+ /* No action */
+ DEBUG2(ql4_printk(KERN_INFO, ha, "scsi%ld: AEN %04x\n",
+ ha->host_no, mbox_status));
+ break;
+
+ case MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD:
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x, IPv6 ERROR, "
+ "mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3}=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
+ ha->host_no, mbox_sts[0], mbox_sts[1],
+ mbox_sts[2], mbox_sts[3], mbox_sts[4],
+ mbox_sts[5]));
+ break;
+
case MBOX_ASTS_MAC_ADDRESS_CHANGED:
case MBOX_ASTS_DNS:
/* No action */
@@ -939,6 +968,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
DEBUG2(ql4_printk(KERN_INFO, ha,
"scsi%ld: AEN %04x Received IPv6 default router changed notification\n",
ha->host_no, mbox_sts[0]));
+ qla4xxx_default_router_changed(ha, mbox_sts);
break;
case MBOX_ASTS_IDC_TIME_EXTEND_NOTIFICATION:
@@ -1022,7 +1052,8 @@ void qla4_82xx_interrupt_service_routine(struct scsi_qla_host *ha,
uint32_t intr_status)
{
/* Process response queue interrupt. */
- if (intr_status & HSRX_RISC_IOCB_INT)
+ if ((intr_status & HSRX_RISC_IOCB_INT) &&
+ test_bit(AF_INIT_DONE, &ha->flags))
qla4xxx_process_response_queue(ha);
/* Process mailbox/asynch event interrupt.*/
@@ -1399,6 +1430,7 @@ qla4_8xxx_msix_rsp_q(int irq, void *dev_id)
{
struct scsi_qla_host *ha = dev_id;
unsigned long flags;
+ int intr_status;
uint32_t ival = 0;
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1412,8 +1444,15 @@ qla4_8xxx_msix_rsp_q(int irq, void *dev_id)
qla4xxx_process_response_queue(ha);
writel(0, &ha->qla4_83xx_reg->iocb_int_mask);
} else {
- qla4xxx_process_response_queue(ha);
- writel(0, &ha->qla4_82xx_reg->host_int);
+ intr_status = readl(&ha->qla4_82xx_reg->host_status);
+ if (intr_status & HSRX_RISC_IOCB_INT) {
+ qla4xxx_process_response_queue(ha);
+ writel(0, &ha->qla4_82xx_reg->host_int);
+ } else {
+ ql4_printk(KERN_INFO, ha, "%s: spurious iocb interrupt...\n",
+ __func__);
+ goto exit_msix_rsp_q;
+ }
}
ha->isr_count++;
exit_msix_rsp_q:
@@ -1488,6 +1527,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
int qla4xxx_request_irqs(struct scsi_qla_host *ha)
{
int ret;
+ int rval = QLA_ERROR;
if (is_qla40XX(ha))
goto try_intx;
@@ -1568,9 +1608,10 @@ irq_attached:
set_bit(AF_IRQ_ATTACHED, &ha->flags);
ha->host->irq = ha->pdev->irq;
ql4_printk(KERN_INFO, ha, "%s: irq %d attached\n",
- __func__, ha->pdev->irq);
+ __func__, ha->pdev->irq);
+ rval = QLA_SUCCESS;
irq_not_attached:
- return ret;
+ return rval;
}
void qla4xxx_free_irqs(struct scsi_qla_host *ha)
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 9ae8ca3b69f9..0a6b782d6fdb 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -212,9 +212,8 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
ha->host_no, __func__));
goto mbox_exit;
}
- DEBUG2(printk("scsi%ld: Mailbox Cmd 0x%08X timed out ...,"
- " Scheduling Adapter Reset\n", ha->host_no,
- mbx_cmd[0]));
+ ql4_printk(KERN_WARNING, ha, "scsi%ld: Mailbox Cmd 0x%08X timed out, Scheduling Adapter Reset\n",
+ ha->host_no, mbx_cmd[0]);
ha->mailbox_timeout_count++;
mbx_sts[0] = (-1);
set_bit(DPC_RESET_HA, &ha->dpc_flags);
@@ -251,15 +250,16 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
break;
case MBOX_STS_BUSY:
- DEBUG2( printk("scsi%ld: %s: Cmd = %08X, ISP BUSY\n",
- ha->host_no, __func__, mbx_cmd[0]));
+ ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Cmd = %08X, ISP BUSY\n",
+ ha->host_no, __func__, mbx_cmd[0]);
ha->mailbox_timeout_count++;
break;
default:
- DEBUG2(printk("scsi%ld: %s: **** FAILED, cmd = %08X, "
- "sts = %08X ****\n", ha->host_no, __func__,
- mbx_cmd[0], mbx_sts[0]));
+ ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: FAILED, MBOX CMD = %08X, MBOX STS = %08X %08X %08X %08X %08X %08X %08X %08X\n",
+ ha->host_no, __func__, mbx_cmd[0], mbx_sts[0],
+ mbx_sts[1], mbx_sts[2], mbx_sts[3], mbx_sts[4],
+ mbx_sts[5], mbx_sts[6], mbx_sts[7]);
break;
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -383,7 +383,6 @@ qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
mbox_cmd[2] = LSDW(init_fw_cb_dma);
mbox_cmd[3] = MSDW(init_fw_cb_dma);
mbox_cmd[4] = sizeof(struct addr_ctrl_blk);
- mbox_cmd[5] = (IFCB_VER_MAX << 8) | IFCB_VER_MIN;
if (qla4xxx_mailbox_command(ha, 6, 6, mbox_cmd, mbox_sts) !=
QLA_SUCCESS) {
@@ -648,9 +647,6 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
goto exit_init_fw_cb;
}
- /* Initialize request and response queues. */
- qla4xxx_init_rings(ha);
-
/* Fill in the request and response queue information. */
init_fw_cb->rqq_consumer_idx = cpu_to_le16(ha->request_out);
init_fw_cb->compq_producer_idx = cpu_to_le16(ha->response_in);
@@ -1002,6 +998,10 @@ int qla4xxx_session_logout_ddb(struct scsi_qla_host *ha,
"%s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT "
"failed sts %04X %04X", __func__,
mbox_sts[0], mbox_sts[1]));
+ if ((mbox_sts[0] == MBOX_STS_COMMAND_ERROR) &&
+ (mbox_sts[1] == DDB_NOT_LOGGED_IN)) {
+ set_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags);
+ }
}
return status;
@@ -1918,6 +1918,7 @@ int qla4xxx_disable_acb(struct scsi_qla_host *ha)
mbox_sts[0], mbox_sts[1], mbox_sts[2]));
} else {
if (is_qla8042(ha) &&
+ test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags) &&
(mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE)) {
/*
* Disable ACB mailbox command takes time to complete
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
index d001202d3565..63328c812b70 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.c
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -2383,6 +2383,11 @@ static void qla4_8xxx_mark_entry_skipped(struct scsi_qla_host *ha,
"scsi(%ld): Skipping entry[%d]: ETYPE[0x%x]-ELEVEL[0x%x]\n",
ha->host_no, index, entry_hdr->entry_type,
entry_hdr->d_ctrl.entry_capture_mask));
+ /* If driver encounters a new entry type that it cannot process,
+ * it should just skip the entry and adjust the total buffer size by
+ * from subtracting the skipped bytes from it
+ */
+ ha->fw_dump_skip_size += entry_hdr->entry_capture_size;
}
/* ISP83xx functions to process new minidump entries... */
@@ -2590,6 +2595,7 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
uint64_t now;
uint32_t timestamp;
+ ha->fw_dump_skip_size = 0;
if (!ha->fw_dump) {
ql4_printk(KERN_INFO, ha, "%s(%ld) No buffer to dump\n",
__func__, ha->host_no);
@@ -2761,7 +2767,7 @@ skip_nxt_entry:
entry_hdr->entry_size);
}
- if (data_collected != ha->fw_dump_size) {
+ if ((data_collected + ha->fw_dump_skip_size) != ha->fw_dump_size) {
ql4_printk(KERN_INFO, ha,
"Dump data mismatch: Data collected: [0x%x], total_data_size:[0x%x]\n",
data_collected, ha->fw_dump_size);
@@ -2820,63 +2826,35 @@ void qla4_8xxx_get_minidump(struct scsi_qla_host *ha)
int qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha)
{
int rval = QLA_ERROR;
- int i, timeout;
- uint32_t old_count, count, idc_ctrl;
- int need_reset = 0, peg_stuck = 1;
+ int i;
+ uint32_t old_count, count;
+ int need_reset = 0;
need_reset = ha->isp_ops->need_reset(ha);
- old_count = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER);
-
- for (i = 0; i < 10; i++) {
- timeout = msleep_interruptible(200);
- if (timeout) {
- qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
- QLA8XXX_DEV_FAILED);
- return rval;
- }
-
- count = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER);
- if (count != old_count)
- peg_stuck = 0;
- }
if (need_reset) {
/* We are trying to perform a recovery here. */
- if (peg_stuck)
+ if (test_bit(AF_FW_RECOVERY, &ha->flags))
ha->isp_ops->rom_lock_recovery(ha);
- goto dev_initialize;
} else {
- /* Start of day for this ha context. */
- if (peg_stuck) {
- /* Either we are the first or recovery in progress. */
- ha->isp_ops->rom_lock_recovery(ha);
- goto dev_initialize;
- } else {
- /* Firmware already running. */
- rval = QLA_SUCCESS;
- goto dev_ready;
+ old_count = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER);
+ for (i = 0; i < 10; i++) {
+ msleep(200);
+ count = qla4_8xxx_rd_direct(ha,
+ QLA8XXX_PEG_ALIVE_COUNTER);
+ if (count != old_count) {
+ rval = QLA_SUCCESS;
+ goto dev_ready;
+ }
}
+ ha->isp_ops->rom_lock_recovery(ha);
}
-dev_initialize:
/* set to DEV_INITIALIZING */
ql4_printk(KERN_INFO, ha, "HW State: INITIALIZING\n");
qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
QLA8XXX_DEV_INITIALIZING);
- /*
- * For ISP8324 and ISP8042, if IDC_CTRL GRACEFUL_RESET_BIT1 is set,
- * reset it after device goes to INIT state.
- */
- if (is_qla8032(ha) || is_qla8042(ha)) {
- idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
- if (idc_ctrl & GRACEFUL_RESET_BIT1) {
- qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
- (idc_ctrl & ~GRACEFUL_RESET_BIT1));
- set_bit(AF_83XX_NO_FW_DUMP, &ha->flags);
- }
- }
-
ha->isp_ops->idc_unlock(ha);
if (is_qla8022(ha))
@@ -3209,6 +3187,10 @@ int qla4_8xxx_load_risc(struct scsi_qla_host *ha)
retval = qla4_8xxx_device_state_handler(ha);
+ /* Initialize request and response queues. */
+ if (retval == QLA_SUCCESS)
+ qla4xxx_init_rings(ha);
+
if (retval == QLA_SUCCESS && !test_bit(AF_IRQ_ATTACHED, &ha->flags))
retval = qla4xxx_request_irqs(ha);
@@ -3836,3 +3818,24 @@ qla4_8xxx_enable_msix(struct scsi_qla_host *ha)
msix_out:
return ret;
}
+
+int qla4_8xxx_check_init_adapter_retry(struct scsi_qla_host *ha)
+{
+ int status = QLA_SUCCESS;
+
+ /* Dont retry adapter initialization if IRQ allocation failed */
+ if (!test_bit(AF_IRQ_ATTACHED, &ha->flags)) {
+ ql4_printk(KERN_WARNING, ha, "%s: Skipping retry of adapter initialization as IRQs are not attached\n",
+ __func__);
+ status = QLA_ERROR;
+ goto exit_init_adapter_failure;
+ }
+
+ /* Since interrupts are registered in start_firmware for
+ * 8xxx, release them here if initialize_adapter fails
+ * and retry adapter initialization */
+ qla4xxx_free_irqs(ha);
+
+exit_init_adapter_failure:
+ return status;
+}
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index c21adc338cf1..459b9f7186fd 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -1670,16 +1670,13 @@ qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
struct sockaddr_in *addr;
struct sockaddr_in6 *addr6;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
if (!shost) {
ret = -ENXIO;
- printk(KERN_ERR "%s: shost is NULL\n",
- __func__);
+ pr_err("%s: shost is NULL\n", __func__);
return ERR_PTR(ret);
}
ha = iscsi_host_priv(shost);
-
ep = iscsi_create_endpoint(sizeof(struct qla_endpoint));
if (!ep) {
ret = -ENOMEM;
@@ -1699,6 +1696,9 @@ qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
addr6 = (struct sockaddr_in6 *)&qla_ep->dst_addr;
DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI6\n", __func__,
(char *)&addr6->sin6_addr));
+ } else {
+ ql4_printk(KERN_WARNING, ha, "%s: Invalid endpoint\n",
+ __func__);
}
qla_ep->host = shost;
@@ -1712,9 +1712,9 @@ static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
struct scsi_qla_host *ha;
int ret = 0;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
qla_ep = ep->dd_data;
ha = to_qla_host(qla_ep->host);
+ DEBUG2(pr_info_ratelimited("%s: host: %ld\n", __func__, ha->host_no));
if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags))
ret = 1;
@@ -1724,7 +1724,13 @@ static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep)
{
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
+ struct qla_endpoint *qla_ep;
+ struct scsi_qla_host *ha;
+
+ qla_ep = ep->dd_data;
+ ha = to_qla_host(qla_ep->host);
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
+ ha->host_no));
iscsi_destroy_endpoint(ep);
}
@@ -1734,8 +1740,11 @@ static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep,
{
struct qla_endpoint *qla_ep = ep->dd_data;
struct sockaddr *dst_addr;
+ struct scsi_qla_host *ha;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
+ ha = to_qla_host(qla_ep->host);
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
+ ha->host_no));
switch (param) {
case ISCSI_PARAM_CONN_PORT:
@@ -1766,13 +1775,13 @@ static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
int ret;
dma_addr_t iscsi_stats_dma;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
-
cls_sess = iscsi_conn_to_session(cls_conn);
sess = cls_sess->dd_data;
ddb_entry = sess->dd_data;
ha = ddb_entry->ha;
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
+ ha->host_no));
stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats));
/* Allocate memory */
ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size,
@@ -2100,7 +2109,8 @@ static void qla4xxx_set_ipv6(struct scsi_qla_host *ha,
cpu_to_le16(IPV6_TCPOPT_DELAYED_ACK_DISABLE);
else
init_fw_cb->ipv6_tcp_opts &=
- cpu_to_le16(~IPV6_TCPOPT_DELAYED_ACK_DISABLE);
+ cpu_to_le16(~IPV6_TCPOPT_DELAYED_ACK_DISABLE &
+ 0xFFFF);
break;
case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
if (iface_param->iface_num & 0x1)
@@ -2297,7 +2307,8 @@ static void qla4xxx_set_ipv4(struct scsi_qla_host *ha,
cpu_to_le16(TCPOPT_DELAYED_ACK_DISABLE);
else
init_fw_cb->ipv4_tcp_opts &=
- cpu_to_le16(~TCPOPT_DELAYED_ACK_DISABLE);
+ cpu_to_le16(~TCPOPT_DELAYED_ACK_DISABLE &
+ 0xFFFF);
break;
case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
if (iface_param->iface_num & 0x1)
@@ -3045,7 +3056,6 @@ qla4xxx_session_create(struct iscsi_endpoint *ep,
struct sockaddr *dst_addr;
int ret;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
if (!ep) {
printk(KERN_ERR "qla4xxx: missing ep.\n");
return NULL;
@@ -3054,6 +3064,8 @@ qla4xxx_session_create(struct iscsi_endpoint *ep,
qla_ep = ep->dd_data;
dst_addr = (struct sockaddr *)&qla_ep->dst_addr;
ha = to_qla_host(qla_ep->host);
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
+ ha->host_no));
ret = qla4xxx_get_ddb_index(ha, &ddb_index);
if (ret == QLA_ERROR)
@@ -3074,6 +3086,7 @@ qla4xxx_session_create(struct iscsi_endpoint *ep,
ddb_entry->sess = cls_sess;
ddb_entry->unblock_sess = qla4xxx_unblock_ddb;
ddb_entry->ddb_change = qla4xxx_ddb_change;
+ clear_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags);
cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry;
ha->tot_ddbs++;
@@ -3092,10 +3105,11 @@ static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess)
uint32_t ddb_state;
int ret;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
sess = cls_sess->dd_data;
ddb_entry = sess->dd_data;
ha = ddb_entry->ha;
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
+ ha->host_no));
fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
&fw_ddb_entry_dma, GFP_KERNEL);
@@ -3123,7 +3137,8 @@ static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess)
destroy_session:
qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
-
+ if (test_and_clear_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags))
+ clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map);
spin_lock_irqsave(&ha->hardware_lock, flags);
qla4xxx_free_ddb(ha, ddb_entry);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -3141,17 +3156,23 @@ qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx)
struct iscsi_cls_conn *cls_conn;
struct iscsi_session *sess;
struct ddb_entry *ddb_entry;
+ struct scsi_qla_host *ha;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn),
conn_idx);
- if (!cls_conn)
+ if (!cls_conn) {
+ pr_info("%s: Can not create connection for conn_idx = %u\n",
+ __func__, conn_idx);
return NULL;
+ }
sess = cls_sess->dd_data;
ddb_entry = sess->dd_data;
ddb_entry->conn = cls_conn;
+ ha = ddb_entry->ha;
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: conn_idx = %u\n", __func__,
+ conn_idx));
return cls_conn;
}
@@ -3162,8 +3183,16 @@ static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
struct iscsi_conn *conn;
struct qla_conn *qla_conn;
struct iscsi_endpoint *ep;
+ struct ddb_entry *ddb_entry;
+ struct scsi_qla_host *ha;
+ struct iscsi_session *sess;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
+ sess = cls_session->dd_data;
+ ddb_entry = sess->dd_data;
+ ha = ddb_entry->ha;
+
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: sid = %d, cid = %d\n", __func__,
+ cls_session->sid, cls_conn->cid));
if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
return -EINVAL;
@@ -3186,10 +3215,11 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn)
int ret = 0;
int status = QLA_SUCCESS;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
sess = cls_sess->dd_data;
ddb_entry = sess->dd_data;
ha = ddb_entry->ha;
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: sid = %d, cid = %d\n", __func__,
+ cls_sess->sid, cls_conn->cid));
/* Check if we have matching FW DDB, if yes then do not
* login to this target. This could cause target to logout previous
@@ -3263,10 +3293,11 @@ static void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn)
struct ddb_entry *ddb_entry;
int options;
- DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
sess = cls_sess->dd_data;
ddb_entry = sess->dd_data;
ha = ddb_entry->ha;
+ DEBUG2(ql4_printk(KERN_INFO, ha, "%s: cid = %d\n", __func__,
+ cls_conn->cid));
options = LOGOUT_OPTION_CLOSE_SESSION;
if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR)
@@ -4372,6 +4403,11 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
uint32_t dev_state;
uint32_t idc_ctrl;
+ if (is_qla8032(ha) &&
+ (qla4_83xx_is_detached(ha) == QLA_SUCCESS))
+ WARN_ONCE(1, "%s: iSCSI function %d marked invisible\n",
+ __func__, ha->func_num);
+
/* don't poll if reset is going on */
if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
@@ -4554,11 +4590,19 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
uint32_t index = 0;
unsigned long flags;
struct scsi_cmnd *cmd;
+ unsigned long wtime;
+ uint32_t wtmo;
+
+ if (is_qla40XX(ha))
+ wtmo = WAIT_CMD_TOV;
+ else
+ wtmo = ha->nx_reset_timeout / 2;
- unsigned long wtime = jiffies + (WAIT_CMD_TOV * HZ);
+ wtime = jiffies + (wtmo * HZ);
- DEBUG2(ql4_printk(KERN_INFO, ha, "Wait up to %d seconds for cmds to "
- "complete\n", WAIT_CMD_TOV));
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "Wait up to %u seconds for cmds to complete\n",
+ wtmo));
while (!time_after_eq(jiffies, wtime)) {
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -4861,11 +4905,11 @@ chip_reset:
qla4xxx_cmd_wait(ha);
qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
- qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
DEBUG2(ql4_printk(KERN_INFO, ha,
"scsi%ld: %s - Performing chip reset..\n",
ha->host_no, __func__));
status = ha->isp_ops->reset_chip(ha);
+ qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
}
/* Flush any pending ddb changed AENs */
@@ -4881,8 +4925,21 @@ recover_ha_init_adapter:
ssleep(6);
/* NOTE: AF_ONLINE flag set upon successful completion of
- * qla4xxx_initialize_adapter */
+ * qla4xxx_initialize_adapter */
status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
+ if (is_qla80XX(ha) && (status == QLA_ERROR)) {
+ status = qla4_8xxx_check_init_adapter_retry(ha);
+ if (status == QLA_ERROR) {
+ ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Don't retry recover adapter\n",
+ ha->host_no, __func__);
+ qla4xxx_dead_adapter_cleanup(ha);
+ clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
+ clear_bit(DPC_RESET_HA, &ha->dpc_flags);
+ clear_bit(DPC_RESET_HA_FW_CONTEXT,
+ &ha->dpc_flags);
+ goto exit_recover;
+ }
+ }
}
/* Retry failed adapter initialization, if necessary
@@ -5228,9 +5285,9 @@ static void qla4xxx_do_dpc(struct work_struct *work)
container_of(work, struct scsi_qla_host, dpc_work);
int status = QLA_ERROR;
- DEBUG2(printk("scsi%ld: %s: DPC handler waking up."
- "flags = 0x%08lx, dpc_flags = 0x%08lx\n",
- ha->host_no, __func__, ha->flags, ha->dpc_flags))
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: %s: DPC handler waking up. flags = 0x%08lx, dpc_flags = 0x%08lx\n",
+ ha->host_no, __func__, ha->flags, ha->dpc_flags));
/* Initialization not yet finished. Don't do anything yet. */
if (!test_bit(AF_INIT_DONE, &ha->flags))
@@ -8681,11 +8738,8 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev,
status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
/* Dont retry adapter initialization if IRQ allocation failed */
- if (is_qla80XX(ha) && !test_bit(AF_IRQ_ATTACHED, &ha->flags)) {
- ql4_printk(KERN_WARNING, ha, "%s: Skipping retry of adapter initialization\n",
- __func__);
+ if (is_qla80XX(ha) && (status == QLA_ERROR))
goto skip_retry_init;
- }
while ((!test_bit(AF_ONLINE, &ha->flags)) &&
init_retry_count++ < MAX_INIT_RETRIES) {
@@ -8709,6 +8763,10 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev,
continue;
status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
+ if (is_qla80XX(ha) && (status == QLA_ERROR)) {
+ if (qla4_8xxx_check_init_adapter_retry(ha) == QLA_ERROR)
+ goto skip_retry_init;
+ }
}
skip_retry_init:
@@ -8857,10 +8915,56 @@ static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha)
}
}
+static void qla4xxx_destroy_ddb(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry)
+{
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ unsigned long wtime;
+ uint32_t ddb_state;
+ int options;
+ int status;
+
+ options = LOGOUT_OPTION_CLOSE_SESSION;
+ if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) {
+ ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
+ goto clear_ddb;
+ }
+
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n", __func__);
+ goto clear_ddb;
+ }
+
+ wtime = jiffies + (HZ * LOGOUT_TOV);
+ do {
+ status = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
+ fw_ddb_entry, fw_ddb_entry_dma,
+ NULL, NULL, &ddb_state, NULL,
+ NULL, NULL);
+ if (status == QLA_ERROR)
+ goto free_ddb;
+
+ if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
+ (ddb_state == DDB_DS_SESSION_FAILED))
+ goto free_ddb;
+
+ schedule_timeout_uninterruptible(HZ);
+ } while ((time_after(wtime, jiffies)));
+
+free_ddb:
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+clear_ddb:
+ qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
+}
+
static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha)
{
struct ddb_entry *ddb_entry;
- int options;
int idx;
for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
@@ -8869,13 +8973,7 @@ static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha)
if ((ddb_entry != NULL) &&
(ddb_entry->ddb_type == FLASH_DDB)) {
- options = LOGOUT_OPTION_CLOSE_SESSION;
- if (qla4xxx_session_logout_ddb(ha, ddb_entry, options)
- == QLA_ERROR)
- ql4_printk(KERN_ERR, ha, "%s: Logout failed\n",
- __func__);
-
- qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
+ qla4xxx_destroy_ddb(ha, ddb_entry);
/*
* we have decremented the reference count of the driver
* when we setup the session to have the driver unload
@@ -9136,14 +9234,15 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
int ret = SUCCESS;
int wait = 0;
- ql4_printk(KERN_INFO, ha,
- "scsi%ld:%d:%d: Abort command issued cmd=%p\n",
- ha->host_no, id, lun, cmd);
+ ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%d: Abort command issued cmd=%p, cdb=0x%x\n",
+ ha->host_no, id, lun, cmd, cmd->cmnd[0]);
spin_lock_irqsave(&ha->hardware_lock, flags);
srb = (struct srb *) CMD_SP(cmd);
if (!srb) {
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%d: Specified command has already completed.\n",
+ ha->host_no, id, lun);
return SUCCESS;
}
kref_get(&srb->srb_ref);
@@ -9560,28 +9659,36 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
}
fn = PCI_FUNC(ha->pdev->devfn);
- while (fn > 0) {
- fn--;
- ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at "
- "func %x\n", ha->host_no, __func__, fn);
- /* Get the pci device given the domain, bus,
- * slot/function number */
- other_pdev =
- pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
- ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
- fn));
-
- if (!other_pdev)
- continue;
+ if (is_qla8022(ha)) {
+ while (fn > 0) {
+ fn--;
+ ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at func %x\n",
+ ha->host_no, __func__, fn);
+ /* Get the pci device given the domain, bus,
+ * slot/function number */
+ other_pdev = pci_get_domain_bus_and_slot(
+ pci_domain_nr(ha->pdev->bus),
+ ha->pdev->bus->number,
+ PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
+ fn));
+
+ if (!other_pdev)
+ continue;
- if (atomic_read(&other_pdev->enable_cnt)) {
- ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI "
- "func in enabled state%x\n", ha->host_no,
- __func__, fn);
+ if (atomic_read(&other_pdev->enable_cnt)) {
+ ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI func in enabled state%x\n",
+ ha->host_no, __func__, fn);
+ pci_dev_put(other_pdev);
+ break;
+ }
pci_dev_put(other_pdev);
- break;
}
- pci_dev_put(other_pdev);
+ } else {
+ /* this case is meant for ISP83xx/ISP84xx only */
+ if (qla4_83xx_can_perform_reset(ha)) {
+ /* reset fn as iSCSI is going to perform the reset */
+ fn = 0;
+ }
}
/* The first function on the card, the reset owner will
@@ -9615,6 +9722,7 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
if (rval != QLA_SUCCESS) {
ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
"FAILED\n", ha->host_no, __func__);
+ qla4xxx_free_irqs(ha);
ha->isp_ops->idc_lock(ha);
qla4_8xxx_clear_drv_active(ha);
qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
@@ -9642,6 +9750,8 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
if (rval == QLA_SUCCESS)
ha->isp_ops->enable_intrs(ha);
+ else
+ qla4xxx_free_irqs(ha);
ha->isp_ops->idc_lock(ha);
qla4_8xxx_set_drv_active(ha);
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index 9b2946658683..c6ba0a6b8458 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -5,4 +5,4 @@
* See LICENSE.qla4xxx for copyright and licensing details.
*/
-#define QLA4XXX_DRIVER_VERSION "5.04.00-k3"
+#define QLA4XXX_DRIVER_VERSION "5.04.00-k4"
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index d8afec8317cf..c4d632c27a3e 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -161,47 +161,20 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
static DEFINE_MUTEX(host_cmd_pool_mutex);
/**
- * scsi_pool_alloc_command - internal function to get a fully allocated command
- * @pool: slab pool to allocate the command from
- * @gfp_mask: mask for the allocation
- *
- * Returns a fully allocated command (with the allied sense buffer) or
- * NULL on failure
- */
-static struct scsi_cmnd *
-scsi_pool_alloc_command(struct scsi_host_cmd_pool *pool, gfp_t gfp_mask)
-{
- struct scsi_cmnd *cmd;
-
- cmd = kmem_cache_zalloc(pool->cmd_slab, gfp_mask | pool->gfp_mask);
- if (!cmd)
- return NULL;
-
- cmd->sense_buffer = kmem_cache_alloc(pool->sense_slab,
- gfp_mask | pool->gfp_mask);
- if (!cmd->sense_buffer) {
- kmem_cache_free(pool->cmd_slab, cmd);
- return NULL;
- }
-
- return cmd;
-}
-
-/**
- * scsi_pool_free_command - internal function to release a command
- * @pool: slab pool to allocate the command from
+ * scsi_host_free_command - internal function to release a command
+ * @shost: host to free the command for
* @cmd: command to release
*
* the command must previously have been allocated by
- * scsi_pool_alloc_command.
+ * scsi_host_alloc_command.
*/
static void
-scsi_pool_free_command(struct scsi_host_cmd_pool *pool,
- struct scsi_cmnd *cmd)
+scsi_host_free_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
{
+ struct scsi_host_cmd_pool *pool = shost->cmd_pool;
+
if (cmd->prot_sdb)
kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb);
-
kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
kmem_cache_free(pool->cmd_slab, cmd);
}
@@ -217,22 +190,32 @@ scsi_pool_free_command(struct scsi_host_cmd_pool *pool,
static struct scsi_cmnd *
scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask)
{
+ struct scsi_host_cmd_pool *pool = shost->cmd_pool;
struct scsi_cmnd *cmd;
- cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
+ cmd = kmem_cache_zalloc(pool->cmd_slab, gfp_mask | pool->gfp_mask);
if (!cmd)
- return NULL;
+ goto fail;
+
+ cmd->sense_buffer = kmem_cache_alloc(pool->sense_slab,
+ gfp_mask | pool->gfp_mask);
+ if (!cmd->sense_buffer)
+ goto fail_free_cmd;
if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) {
cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask);
-
- if (!cmd->prot_sdb) {
- scsi_pool_free_command(shost->cmd_pool, cmd);
- return NULL;
- }
+ if (!cmd->prot_sdb)
+ goto fail_free_sense;
}
return cmd;
+
+fail_free_sense:
+ kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
+fail_free_cmd:
+ kmem_cache_free(pool->cmd_slab, cmd);
+fail:
+ return NULL;
}
/**
@@ -284,27 +267,19 @@ EXPORT_SYMBOL_GPL(__scsi_get_command);
*/
struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
{
- struct scsi_cmnd *cmd;
+ struct scsi_cmnd *cmd = __scsi_get_command(dev->host, gfp_mask);
+ unsigned long flags;
- /* Bail if we can't get a reference to the device */
- if (!get_device(&dev->sdev_gendev))
+ if (unlikely(cmd == NULL))
return NULL;
- cmd = __scsi_get_command(dev->host, gfp_mask);
-
- if (likely(cmd != NULL)) {
- unsigned long flags;
-
- cmd->device = dev;
- INIT_LIST_HEAD(&cmd->list);
- INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
- spin_lock_irqsave(&dev->list_lock, flags);
- list_add_tail(&cmd->list, &dev->cmd_list);
- spin_unlock_irqrestore(&dev->list_lock, flags);
- cmd->jiffies_at_alloc = jiffies;
- } else
- put_device(&dev->sdev_gendev);
-
+ cmd->device = dev;
+ INIT_LIST_HEAD(&cmd->list);
+ INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
+ spin_lock_irqsave(&dev->list_lock, flags);
+ list_add_tail(&cmd->list, &dev->cmd_list);
+ spin_unlock_irqrestore(&dev->list_lock, flags);
+ cmd->jiffies_at_alloc = jiffies;
return cmd;
}
EXPORT_SYMBOL(scsi_get_command);
@@ -313,25 +288,22 @@ EXPORT_SYMBOL(scsi_get_command);
* __scsi_put_command - Free a struct scsi_cmnd
* @shost: dev->host
* @cmd: Command to free
- * @dev: parent scsi device
*/
-void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
- struct device *dev)
+void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
{
unsigned long flags;
- /* changing locks here, don't need to restore the irq state */
- spin_lock_irqsave(&shost->free_list_lock, flags);
if (unlikely(list_empty(&shost->free_list))) {
- list_add(&cmd->list, &shost->free_list);
- cmd = NULL;
+ spin_lock_irqsave(&shost->free_list_lock, flags);
+ if (list_empty(&shost->free_list)) {
+ list_add(&cmd->list, &shost->free_list);
+ cmd = NULL;
+ }
+ spin_unlock_irqrestore(&shost->free_list_lock, flags);
}
- spin_unlock_irqrestore(&shost->free_list_lock, flags);
if (likely(cmd != NULL))
- scsi_pool_free_command(shost->cmd_pool, cmd);
-
- put_device(dev);
+ scsi_host_free_command(shost, cmd);
}
EXPORT_SYMBOL(__scsi_put_command);
@@ -345,7 +317,6 @@ EXPORT_SYMBOL(__scsi_put_command);
*/
void scsi_put_command(struct scsi_cmnd *cmd)
{
- struct scsi_device *sdev = cmd->device;
unsigned long flags;
/* serious error if the command hasn't come from a device list */
@@ -356,50 +327,107 @@ void scsi_put_command(struct scsi_cmnd *cmd)
cancel_delayed_work(&cmd->abort_work);
- __scsi_put_command(cmd->device->host, cmd, &sdev->sdev_gendev);
+ __scsi_put_command(cmd->device->host, cmd);
}
EXPORT_SYMBOL(scsi_put_command);
-static struct scsi_host_cmd_pool *scsi_get_host_cmd_pool(gfp_t gfp_mask)
+static struct scsi_host_cmd_pool *
+scsi_find_host_cmd_pool(struct Scsi_Host *shost)
+{
+ if (shost->hostt->cmd_size)
+ return shost->hostt->cmd_pool;
+ if (shost->unchecked_isa_dma)
+ return &scsi_cmd_dma_pool;
+ return &scsi_cmd_pool;
+}
+
+static void
+scsi_free_host_cmd_pool(struct scsi_host_cmd_pool *pool)
{
+ kfree(pool->sense_name);
+ kfree(pool->cmd_name);
+ kfree(pool);
+}
+
+static struct scsi_host_cmd_pool *
+scsi_alloc_host_cmd_pool(struct Scsi_Host *shost)
+{
+ struct scsi_host_template *hostt = shost->hostt;
+ struct scsi_host_cmd_pool *pool;
+
+ pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+ if (!pool)
+ return NULL;
+
+ pool->cmd_name = kasprintf(GFP_KERNEL, "%s_cmd", hostt->name);
+ pool->sense_name = kasprintf(GFP_KERNEL, "%s_sense", hostt->name);
+ if (!pool->cmd_name || !pool->sense_name) {
+ scsi_free_host_cmd_pool(pool);
+ return NULL;
+ }
+
+ pool->slab_flags = SLAB_HWCACHE_ALIGN;
+ if (shost->unchecked_isa_dma) {
+ pool->slab_flags |= SLAB_CACHE_DMA;
+ pool->gfp_mask = __GFP_DMA;
+ }
+ return pool;
+}
+
+static struct scsi_host_cmd_pool *
+scsi_get_host_cmd_pool(struct Scsi_Host *shost)
+{
+ struct scsi_host_template *hostt = shost->hostt;
struct scsi_host_cmd_pool *retval = NULL, *pool;
+ size_t cmd_size = sizeof(struct scsi_cmnd) + hostt->cmd_size;
+
/*
* Select a command slab for this host and create it if not
* yet existent.
*/
mutex_lock(&host_cmd_pool_mutex);
- pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool :
- &scsi_cmd_pool;
+ pool = scsi_find_host_cmd_pool(shost);
+ if (!pool) {
+ pool = scsi_alloc_host_cmd_pool(shost);
+ if (!pool)
+ goto out;
+ }
+
if (!pool->users) {
- pool->cmd_slab = kmem_cache_create(pool->cmd_name,
- sizeof(struct scsi_cmnd), 0,
+ pool->cmd_slab = kmem_cache_create(pool->cmd_name, cmd_size, 0,
pool->slab_flags, NULL);
if (!pool->cmd_slab)
- goto fail;
+ goto out_free_pool;
pool->sense_slab = kmem_cache_create(pool->sense_name,
SCSI_SENSE_BUFFERSIZE, 0,
pool->slab_flags, NULL);
- if (!pool->sense_slab) {
- kmem_cache_destroy(pool->cmd_slab);
- goto fail;
- }
+ if (!pool->sense_slab)
+ goto out_free_slab;
}
pool->users++;
retval = pool;
- fail:
+out:
mutex_unlock(&host_cmd_pool_mutex);
return retval;
+
+out_free_slab:
+ kmem_cache_destroy(pool->cmd_slab);
+out_free_pool:
+ if (hostt->cmd_size)
+ scsi_free_host_cmd_pool(pool);
+ goto out;
}
-static void scsi_put_host_cmd_pool(gfp_t gfp_mask)
+static void scsi_put_host_cmd_pool(struct Scsi_Host *shost)
{
+ struct scsi_host_template *hostt = shost->hostt;
struct scsi_host_cmd_pool *pool;
mutex_lock(&host_cmd_pool_mutex);
- pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool :
- &scsi_cmd_pool;
+ pool = scsi_find_host_cmd_pool(shost);
+
/*
* This may happen if a driver has a mismatched get and put
* of the command pool; the driver should be implicated in
@@ -410,67 +438,13 @@ static void scsi_put_host_cmd_pool(gfp_t gfp_mask)
if (!--pool->users) {
kmem_cache_destroy(pool->cmd_slab);
kmem_cache_destroy(pool->sense_slab);
+ if (hostt->cmd_size)
+ scsi_free_host_cmd_pool(pool);
}
mutex_unlock(&host_cmd_pool_mutex);
}
/**
- * scsi_allocate_command - get a fully allocated SCSI command
- * @gfp_mask: allocation mask
- *
- * This function is for use outside of the normal host based pools.
- * It allocates the relevant command and takes an additional reference
- * on the pool it used. This function *must* be paired with
- * scsi_free_command which also has the identical mask, otherwise the
- * free pool counts will eventually go wrong and you'll trigger a bug.
- *
- * This function should *only* be used by drivers that need a static
- * command allocation at start of day for internal functions.
- */
-struct scsi_cmnd *scsi_allocate_command(gfp_t gfp_mask)
-{
- struct scsi_host_cmd_pool *pool = scsi_get_host_cmd_pool(gfp_mask);
-
- if (!pool)
- return NULL;
-
- return scsi_pool_alloc_command(pool, gfp_mask);
-}
-EXPORT_SYMBOL(scsi_allocate_command);
-
-/**
- * scsi_free_command - free a command allocated by scsi_allocate_command
- * @gfp_mask: mask used in the original allocation
- * @cmd: command to free
- *
- * Note: using the original allocation mask is vital because that's
- * what determines which command pool we use to free the command. Any
- * mismatch will cause the system to BUG eventually.
- */
-void scsi_free_command(gfp_t gfp_mask, struct scsi_cmnd *cmd)
-{
- struct scsi_host_cmd_pool *pool = scsi_get_host_cmd_pool(gfp_mask);
-
- /*
- * this could trigger if the mask to scsi_allocate_command
- * doesn't match this mask. Otherwise we're guaranteed that this
- * succeeds because scsi_allocate_command must have taken a reference
- * on the pool
- */
- BUG_ON(!pool);
-
- scsi_pool_free_command(pool, cmd);
- /*
- * scsi_put_host_cmd_pool is called twice; once to release the
- * reference we took above, and once to release the reference
- * originally taken by scsi_allocate_command
- */
- scsi_put_host_cmd_pool(gfp_mask);
- scsi_put_host_cmd_pool(gfp_mask);
-}
-EXPORT_SYMBOL(scsi_free_command);
-
-/**
* scsi_setup_command_freelist - Setup the command freelist for a scsi host.
* @shost: host to allocate the freelist for.
*
@@ -482,14 +456,13 @@ EXPORT_SYMBOL(scsi_free_command);
*/
int scsi_setup_command_freelist(struct Scsi_Host *shost)
{
- struct scsi_cmnd *cmd;
const gfp_t gfp_mask = shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL;
+ struct scsi_cmnd *cmd;
spin_lock_init(&shost->free_list_lock);
INIT_LIST_HEAD(&shost->free_list);
- shost->cmd_pool = scsi_get_host_cmd_pool(gfp_mask);
-
+ shost->cmd_pool = scsi_get_host_cmd_pool(shost);
if (!shost->cmd_pool)
return -ENOMEM;
@@ -498,7 +471,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
*/
cmd = scsi_host_alloc_command(shost, gfp_mask);
if (!cmd) {
- scsi_put_host_cmd_pool(gfp_mask);
+ scsi_put_host_cmd_pool(shost);
shost->cmd_pool = NULL;
return -ENOMEM;
}
@@ -524,10 +497,10 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list);
list_del_init(&cmd->list);
- scsi_pool_free_command(shost->cmd_pool, cmd);
+ scsi_host_free_command(shost, cmd);
}
shost->cmd_pool = NULL;
- scsi_put_host_cmd_pool(shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL);
+ scsi_put_host_cmd_pool(shost);
}
#ifdef CONFIG_SCSI_LOGGING
@@ -954,7 +927,7 @@ EXPORT_SYMBOL(scsi_track_queue_full);
* This is an internal helper function. You probably want to use
* scsi_get_vpd_page instead.
*
- * Returns 0 on success or a negative error number.
+ * Returns size of the vpd page on success or a negative error number.
*/
static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
u8 page, unsigned len)
@@ -962,6 +935,9 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
int result;
unsigned char cmd[16];
+ if (len < 4)
+ return -EINVAL;
+
cmd[0] = INQUIRY;
cmd[1] = 1; /* EVPD */
cmd[2] = page;
@@ -976,13 +952,13 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer,
len, NULL, 30 * HZ, 3, NULL);
if (result)
- return result;
+ return -EIO;
/* Sanity check that we got the page back that we asked for */
if (buffer[1] != page)
return -EIO;
- return 0;
+ return get_unaligned_be16(&buffer[2]) + 4;
}
/**
@@ -1009,18 +985,18 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
/* Ask for all the pages supported by this device */
result = scsi_vpd_inquiry(sdev, buf, 0, buf_len);
- if (result)
+ if (result < 4)
goto fail;
/* If the user actually wanted this page, we can skip the rest */
if (page == 0)
return 0;
- for (i = 0; i < min((int)buf[3], buf_len - 4); i++)
- if (buf[i + 4] == page)
+ for (i = 4; i < min(result, buf_len); i++)
+ if (buf[i] == page)
goto found;
- if (i < buf[3] && i >= buf_len - 4)
+ if (i < result && i >= buf_len)
/* ran off the end of the buffer, give us benefit of doubt */
goto found;
/* The device claims it doesn't support the requested page */
@@ -1028,7 +1004,7 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
found:
result = scsi_vpd_inquiry(sdev, buf, page, buf_len);
- if (result)
+ if (result < 0)
goto fail;
return 0;
@@ -1039,6 +1015,93 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
/**
+ * scsi_attach_vpd - Attach Vital Product Data to a SCSI device structure
+ * @sdev: The device to ask
+ *
+ * Attach the 'Device Identification' VPD page (0x83) and the
+ * 'Unit Serial Number' VPD page (0x80) to a SCSI device
+ * structure. This information can be used to identify the device
+ * uniquely.
+ */
+void scsi_attach_vpd(struct scsi_device *sdev)
+{
+ int result, i;
+ int vpd_len = SCSI_VPD_PG_LEN;
+ int pg80_supported = 0;
+ int pg83_supported = 0;
+ unsigned char *vpd_buf;
+
+ if (sdev->skip_vpd_pages)
+ return;
+retry_pg0:
+ vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
+ if (!vpd_buf)
+ return;
+
+ /* Ask for all the pages supported by this device */
+ result = scsi_vpd_inquiry(sdev, vpd_buf, 0, vpd_len);
+ if (result < 0) {
+ kfree(vpd_buf);
+ return;
+ }
+ if (result > vpd_len) {
+ vpd_len = result;
+ kfree(vpd_buf);
+ goto retry_pg0;
+ }
+
+ for (i = 4; i < result; i++) {
+ if (vpd_buf[i] == 0x80)
+ pg80_supported = 1;
+ if (vpd_buf[i] == 0x83)
+ pg83_supported = 1;
+ }
+ kfree(vpd_buf);
+ vpd_len = SCSI_VPD_PG_LEN;
+
+ if (pg80_supported) {
+retry_pg80:
+ vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
+ if (!vpd_buf)
+ return;
+
+ result = scsi_vpd_inquiry(sdev, vpd_buf, 0x80, vpd_len);
+ if (result < 0) {
+ kfree(vpd_buf);
+ return;
+ }
+ if (result > vpd_len) {
+ vpd_len = result;
+ kfree(vpd_buf);
+ goto retry_pg80;
+ }
+ sdev->vpd_pg80_len = result;
+ sdev->vpd_pg80 = vpd_buf;
+ vpd_len = SCSI_VPD_PG_LEN;
+ }
+
+ if (pg83_supported) {
+retry_pg83:
+ vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
+ if (!vpd_buf)
+ return;
+
+ result = scsi_vpd_inquiry(sdev, vpd_buf, 0x83, vpd_len);
+ if (result < 0) {
+ kfree(vpd_buf);
+ return;
+ }
+ if (result > vpd_len) {
+ vpd_len = result;
+ kfree(vpd_buf);
+ goto retry_pg83;
+ }
+ sdev->vpd_pg83_len = result;
+ sdev->vpd_pg83 = vpd_buf;
+ }
+}
+
+/**
* scsi_report_opcode - Find out if a given command opcode is supported
* @sdev: scsi device to query
* @buffer: scratch buffer (must be at least 20 bytes long)
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 2decc6417518..f3e9cc038d1d 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -64,6 +64,7 @@ static const char * scsi_debug_version_date = "20100324";
/* Additional Sense Code (ASC) */
#define NO_ADDITIONAL_SENSE 0x0
#define LOGICAL_UNIT_NOT_READY 0x4
+#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
#define UNRECOVERED_READ_ERR 0x11
#define PARAMETER_LIST_LENGTH_ERR 0x1a
#define INVALID_OPCODE 0x20
@@ -195,6 +196,7 @@ static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
static bool scsi_debug_removable = DEF_REMOVABLE;
+static bool scsi_debug_clustering;
static int scsi_debug_cmnd_count = 0;
@@ -1780,7 +1782,6 @@ static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
be32_to_cpu(sdt->ref_tag) != ei_lba) {
pr_err("%s: REF check failed on sector %lu\n",
__func__, (unsigned long)sector);
- dif_errors++;
return 0x03;
}
return 0;
@@ -1789,23 +1790,27 @@ static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
unsigned int sectors, bool read)
{
- unsigned int i, resid;
- struct scatterlist *psgl;
+ size_t resid;
void *paddr;
const void *dif_store_end = dif_storep + sdebug_store_sectors;
+ struct sg_mapping_iter miter;
/* Bytes of protection data to copy into sgl */
resid = sectors * sizeof(*dif_storep);
- scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
- int len = min(psgl->length, resid);
+ sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
+ scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
+ (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
+
+ while (sg_miter_next(&miter) && resid > 0) {
+ size_t len = min(miter.length, resid);
void *start = dif_store(sector);
- int rest = 0;
+ size_t rest = 0;
if (dif_store_end < start + len)
rest = start + len - dif_store_end;
- paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
+ paddr = miter.addr;
if (read)
memcpy(paddr, start, len - rest);
@@ -1821,8 +1826,8 @@ static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
sector += len / sizeof(*dif_storep);
resid -= len;
- kunmap_atomic(paddr);
}
+ sg_miter_stop(&miter);
}
static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
@@ -1832,7 +1837,7 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
struct sd_dif_tuple *sdt;
sector_t sector;
- for (i = 0; i < sectors; i++) {
+ for (i = 0; i < sectors; i++, ei_lba++) {
int ret;
sector = start_sec + i;
@@ -1846,8 +1851,6 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
dif_errors++;
return ret;
}
-
- ei_lba++;
}
dif_copy_prot(SCpnt, start_sec, sectors, true);
@@ -1886,17 +1889,19 @@ static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
return check_condition_result;
}
+ read_lock_irqsave(&atomic_rw, iflags);
+
/* DIX + T10 DIF */
if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
if (prot_ret) {
+ read_unlock_irqrestore(&atomic_rw, iflags);
mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
return illegal_condition_result;
}
}
- read_lock_irqsave(&atomic_rw, iflags);
ret = do_device_access(SCpnt, devip, lba, num, 0);
read_unlock_irqrestore(&atomic_rw, iflags);
if (ret == -1)
@@ -1931,55 +1936,62 @@ void dump_sector(unsigned char *buf, int len)
static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
unsigned int sectors, u32 ei_lba)
{
- int i, j, ret;
+ int ret;
struct sd_dif_tuple *sdt;
- struct scatterlist *dsgl;
- struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
- void *daddr, *paddr;
+ void *daddr;
sector_t sector = start_sec;
int ppage_offset;
+ int dpage_offset;
+ struct sg_mapping_iter diter;
+ struct sg_mapping_iter piter;
BUG_ON(scsi_sg_count(SCpnt) == 0);
BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
- ppage_offset = 0;
-
- /* For each data page */
- scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
- daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset;
- paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
-
- /* For each sector-sized chunk in data page */
- for (j = 0; j < dsgl->length; j += scsi_debug_sector_size) {
+ sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
+ scsi_prot_sg_count(SCpnt),
+ SG_MITER_ATOMIC | SG_MITER_FROM_SG);
+ sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
+ SG_MITER_ATOMIC | SG_MITER_FROM_SG);
+
+ /* For each protection page */
+ while (sg_miter_next(&piter)) {
+ dpage_offset = 0;
+ if (WARN_ON(!sg_miter_next(&diter))) {
+ ret = 0x01;
+ goto out;
+ }
+ for (ppage_offset = 0; ppage_offset < piter.length;
+ ppage_offset += sizeof(struct sd_dif_tuple)) {
/* If we're at the end of the current
- * protection page advance to the next one
+ * data page advance to the next one
*/
- if (ppage_offset >= psgl->length) {
- kunmap_atomic(paddr);
- psgl = sg_next(psgl);
- BUG_ON(psgl == NULL);
- paddr = kmap_atomic(sg_page(psgl))
- + psgl->offset;
- ppage_offset = 0;
+ if (dpage_offset >= diter.length) {
+ if (WARN_ON(!sg_miter_next(&diter))) {
+ ret = 0x01;
+ goto out;
+ }
+ dpage_offset = 0;
}
- sdt = paddr + ppage_offset;
+ sdt = piter.addr + ppage_offset;
+ daddr = diter.addr + dpage_offset;
- ret = dif_verify(sdt, daddr + j, sector, ei_lba);
+ ret = dif_verify(sdt, daddr, sector, ei_lba);
if (ret) {
- dump_sector(daddr + j, scsi_debug_sector_size);
+ dump_sector(daddr, scsi_debug_sector_size);
goto out;
}
sector++;
ei_lba++;
- ppage_offset += sizeof(struct sd_dif_tuple);
+ dpage_offset += scsi_debug_sector_size;
}
-
- kunmap_atomic(paddr);
- kunmap_atomic(daddr);
+ diter.consumed = dpage_offset;
+ sg_miter_stop(&diter);
}
+ sg_miter_stop(&piter);
dif_copy_prot(SCpnt, start_sec, sectors, false);
dix_writes++;
@@ -1988,8 +2000,8 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
out:
dif_errors++;
- kunmap_atomic(paddr);
- kunmap_atomic(daddr);
+ sg_miter_stop(&diter);
+ sg_miter_stop(&piter);
return ret;
}
@@ -2089,17 +2101,19 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
if (ret)
return ret;
+ write_lock_irqsave(&atomic_rw, iflags);
+
/* DIX + T10 DIF */
if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
if (prot_ret) {
+ write_unlock_irqrestore(&atomic_rw, iflags);
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
return illegal_condition_result;
}
}
- write_lock_irqsave(&atomic_rw, iflags);
ret = do_device_access(SCpnt, devip, lba, num, 1);
if (scsi_debug_lbp())
map_region(lba, num);
@@ -2178,6 +2192,7 @@ static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
struct unmap_block_desc *desc;
unsigned int i, payload_len, descriptors;
int ret;
+ unsigned long iflags;
ret = check_readiness(scmd, 1, devip);
if (ret)
@@ -2199,6 +2214,8 @@ static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
desc = (void *)&buf[8];
+ write_lock_irqsave(&atomic_rw, iflags);
+
for (i = 0 ; i < descriptors ; i++) {
unsigned long long lba = get_unaligned_be64(&desc[i].lba);
unsigned int num = get_unaligned_be32(&desc[i].blocks);
@@ -2213,6 +2230,7 @@ static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
ret = 0;
out:
+ write_unlock_irqrestore(&atomic_rw, iflags);
kfree(buf);
return ret;
@@ -2313,36 +2331,37 @@ static int resp_report_luns(struct scsi_cmnd * scp,
static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
unsigned int num, struct sdebug_dev_info *devip)
{
- int i, j, ret = -1;
+ int j;
unsigned char *kaddr, *buf;
unsigned int offset;
- struct scatterlist *sg;
struct scsi_data_buffer *sdb = scsi_in(scp);
+ struct sg_mapping_iter miter;
/* better not to use temporary buffer. */
buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
- if (!buf)
- return ret;
+ if (!buf) {
+ mk_sense_buffer(devip, NOT_READY,
+ LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
+ return check_condition_result;
+ }
scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
offset = 0;
- for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
- kaddr = (unsigned char *)kmap_atomic(sg_page(sg));
- if (!kaddr)
- goto out;
+ sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
+ SG_MITER_ATOMIC | SG_MITER_TO_SG);
- for (j = 0; j < sg->length; j++)
- *(kaddr + sg->offset + j) ^= *(buf + offset + j);
+ while (sg_miter_next(&miter)) {
+ kaddr = miter.addr;
+ for (j = 0; j < miter.length; j++)
+ *(kaddr + j) ^= *(buf + offset + j);
- offset += sg->length;
- kunmap_atomic(kaddr);
+ offset += miter.length;
}
- ret = 0;
-out:
+ sg_miter_stop(&miter);
kfree(buf);
- return ret;
+ return 0;
}
/* When timer goes off this function is called. */
@@ -2744,6 +2763,7 @@ static int schedule_resp(struct scsi_cmnd * cmnd,
*/
module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
+module_param_named(clustering, scsi_debug_clustering, bool, S_IRUGO | S_IWUSR);
module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
@@ -2787,6 +2807,7 @@ MODULE_VERSION(SCSI_DEBUG_VERSION);
MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
+MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
@@ -3248,7 +3269,7 @@ static struct attribute *sdebug_drv_attrs[] = {
};
ATTRIBUTE_GROUPS(sdebug_drv);
-struct device *pseudo_primary;
+static struct device *pseudo_primary;
static int __init scsi_debug_init(void)
{
@@ -3934,6 +3955,8 @@ static int sdebug_driver_probe(struct device * dev)
sdbg_host = to_sdebug_host(dev);
sdebug_driver_template.can_queue = scsi_debug_max_queue;
+ if (scsi_debug_clustering)
+ sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
if (NULL == hpnt) {
printk(KERN_ERR "%s: scsi_register failed\n", __func__);
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 78b004da2885..771c16bfdbac 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -2288,6 +2288,11 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
if (scsi_autopm_get_host(shost) < 0)
return FAILED;
+ if (!get_device(&dev->sdev_gendev)) {
+ rtn = FAILED;
+ goto out_put_autopm_host;
+ }
+
scmd = scsi_get_command(dev, GFP_KERNEL);
blk_rq_init(NULL, &req);
scmd->request = &req;
@@ -2345,6 +2350,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
scsi_run_host_queues(shost);
scsi_next_command(scmd);
+out_put_autopm_host:
scsi_autopm_put_host(shost);
return rtn;
}
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 7bd7f0d5f050..5681c05ac506 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -75,28 +75,6 @@ struct kmem_cache *scsi_sdb_cache;
*/
#define SCSI_QUEUE_DELAY 3
-/*
- * Function: scsi_unprep_request()
- *
- * Purpose: Remove all preparation done for a request, including its
- * associated scsi_cmnd, so that it can be requeued.
- *
- * Arguments: req - request to unprepare
- *
- * Lock status: Assumed that no locks are held upon entry.
- *
- * Returns: Nothing.
- */
-static void scsi_unprep_request(struct request *req)
-{
- struct scsi_cmnd *cmd = req->special;
-
- blk_unprep_request(req);
- req->special = NULL;
-
- scsi_put_command(cmd);
-}
-
/**
* __scsi_queue_insert - private queue insertion
* @cmd: The SCSI command being requeued
@@ -385,29 +363,12 @@ static inline int scsi_host_is_busy(struct Scsi_Host *shost)
return 0;
}
-/*
- * Function: scsi_run_queue()
- *
- * Purpose: Select a proper request queue to serve next
- *
- * Arguments: q - last request's queue
- *
- * Returns: Nothing
- *
- * Notes: The previous command was completely finished, start
- * a new one if possible.
- */
-static void scsi_run_queue(struct request_queue *q)
+static void scsi_starved_list_run(struct Scsi_Host *shost)
{
- struct scsi_device *sdev = q->queuedata;
- struct Scsi_Host *shost;
LIST_HEAD(starved_list);
+ struct scsi_device *sdev;
unsigned long flags;
- shost = sdev->host;
- if (scsi_target(sdev)->single_lun)
- scsi_single_lun_run(sdev);
-
spin_lock_irqsave(shost->host_lock, flags);
list_splice_init(&shost->starved_list, &starved_list);
@@ -459,6 +420,28 @@ static void scsi_run_queue(struct request_queue *q)
/* put any unprocessed entries back */
list_splice(&starved_list, &shost->starved_list);
spin_unlock_irqrestore(shost->host_lock, flags);
+}
+
+/*
+ * Function: scsi_run_queue()
+ *
+ * Purpose: Select a proper request queue to serve next
+ *
+ * Arguments: q - last request's queue
+ *
+ * Returns: Nothing
+ *
+ * Notes: The previous command was completely finished, start
+ * a new one if possible.
+ */
+static void scsi_run_queue(struct request_queue *q)
+{
+ struct scsi_device *sdev = q->queuedata;
+
+ if (scsi_target(sdev)->single_lun)
+ scsi_single_lun_run(sdev);
+ if (!list_empty(&sdev->host->starved_list))
+ scsi_starved_list_run(sdev->host);
blk_run_queue(q);
}
@@ -497,16 +480,10 @@ static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd)
struct request *req = cmd->request;
unsigned long flags;
- /*
- * We need to hold a reference on the device to avoid the queue being
- * killed after the unlock and before scsi_run_queue is invoked which
- * may happen because scsi_unprep_request() puts the command which
- * releases its reference on the device.
- */
- get_device(&sdev->sdev_gendev);
-
spin_lock_irqsave(q->queue_lock, flags);
- scsi_unprep_request(req);
+ blk_unprep_request(req);
+ req->special = NULL;
+ scsi_put_command(cmd);
blk_requeue_request(q, req);
spin_unlock_irqrestore(q->queue_lock, flags);
@@ -520,13 +497,9 @@ void scsi_next_command(struct scsi_cmnd *cmd)
struct scsi_device *sdev = cmd->device;
struct request_queue *q = sdev->request_queue;
- /* need to hold a reference on the device before we let go of the cmd */
- get_device(&sdev->sdev_gendev);
-
scsi_put_command(cmd);
scsi_run_queue(q);
- /* ok to remove device now */
put_device(&sdev->sdev_gendev);
}
@@ -788,6 +761,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
enum {ACTION_FAIL, ACTION_REPREP, ACTION_RETRY,
ACTION_DELAYED_RETRY} action;
char *description = NULL;
+ unsigned long wait_for = (cmd->allowed + 1) * req->timeout;
if (result) {
sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
@@ -989,6 +963,12 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
action = ACTION_FAIL;
}
+ if (action != ACTION_FAIL &&
+ time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
+ action = ACTION_FAIL;
+ description = "Command timed out";
+ }
+
switch (action) {
case ACTION_FAIL:
/* Give up and fail the remainder of the request */
@@ -1111,6 +1091,7 @@ err_exit:
scsi_release_buffers(cmd);
cmd->request->special = NULL;
scsi_put_command(cmd);
+ put_device(&cmd->device->sdev_gendev);
return error;
}
EXPORT_SYMBOL(scsi_init_io);
@@ -1121,9 +1102,15 @@ static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
struct scsi_cmnd *cmd;
if (!req->special) {
+ /* Bail if we can't get a reference to the device */
+ if (!get_device(&sdev->sdev_gendev))
+ return NULL;
+
cmd = scsi_get_command(sdev, GFP_ATOMIC);
- if (unlikely(!cmd))
+ if (unlikely(!cmd)) {
+ put_device(&sdev->sdev_gendev);
return NULL;
+ }
req->special = cmd;
} else {
cmd = req->special;
@@ -1286,6 +1273,7 @@ int scsi_prep_return(struct request_queue *q, struct request *req, int ret)
struct scsi_cmnd *cmd = req->special;
scsi_release_buffers(cmd);
scsi_put_command(cmd);
+ put_device(&cmd->device->sdev_gendev);
req->special = NULL;
}
break;
@@ -1543,16 +1531,14 @@ static void scsi_softirq_done(struct request *rq)
* Lock status: IO request lock assumed to be held when called.
*/
static void scsi_request_fn(struct request_queue *q)
+ __releases(q->queue_lock)
+ __acquires(q->queue_lock)
{
struct scsi_device *sdev = q->queuedata;
struct Scsi_Host *shost;
struct scsi_cmnd *cmd;
struct request *req;
- if(!get_device(&sdev->sdev_gendev))
- /* We must be tearing the block queue down already */
- return;
-
/*
* To start with, we keep looping until the queue is empty, or until
* the host is no longer able to accept any more requests.
@@ -1641,7 +1627,7 @@ static void scsi_request_fn(struct request_queue *q)
goto out_delay;
}
- goto out;
+ return;
not_ready:
spin_unlock_irq(shost->host_lock);
@@ -1660,12 +1646,6 @@ static void scsi_request_fn(struct request_queue *q)
out_delay:
if (sdev->device_busy == 0)
blk_delay_queue(q, SCSI_QUEUE_DELAY);
-out:
- /* must be careful here...if we trigger the ->remove() function
- * we cannot be holding the q lock */
- spin_unlock_irq(q->queue_lock);
- put_device(&sdev->sdev_gendev);
- spin_lock_irq(q->queue_lock);
}
u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost)
@@ -1684,7 +1664,7 @@ u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost)
host_dev = scsi_get_device(shost);
if (host_dev && host_dev->dma_mask)
- bounce_limit = dma_max_pfn(host_dev) << PAGE_SHIFT;
+ bounce_limit = (u64)dma_max_pfn(host_dev) << PAGE_SHIFT;
return bounce_limit;
}
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 307a81137607..27f96d5b7680 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -320,6 +320,7 @@ static void scsi_target_destroy(struct scsi_target *starget)
struct Scsi_Host *shost = dev_to_shost(dev->parent);
unsigned long flags;
+ starget->state = STARGET_DEL;
transport_destroy_device(dev);
spin_lock_irqsave(shost->host_lock, flags);
if (shost->hostt->target_destroy)
@@ -371,6 +372,37 @@ static struct scsi_target *__scsi_find_target(struct device *parent,
}
/**
+ * scsi_target_reap_ref_release - remove target from visibility
+ * @kref: the reap_ref in the target being released
+ *
+ * Called on last put of reap_ref, which is the indication that no device
+ * under this target is visible anymore, so render the target invisible in
+ * sysfs. Note: we have to be in user context here because the target reaps
+ * should be done in places where the scsi device visibility is being removed.
+ */
+static void scsi_target_reap_ref_release(struct kref *kref)
+{
+ struct scsi_target *starget
+ = container_of(kref, struct scsi_target, reap_ref);
+
+ /*
+ * if we get here and the target is still in the CREATED state that
+ * means it was allocated but never made visible (because a scan
+ * turned up no LUNs), so don't call device_del() on it.
+ */
+ if (starget->state != STARGET_CREATED) {
+ transport_remove_device(&starget->dev);
+ device_del(&starget->dev);
+ }
+ scsi_target_destroy(starget);
+}
+
+static void scsi_target_reap_ref_put(struct scsi_target *starget)
+{
+ kref_put(&starget->reap_ref, scsi_target_reap_ref_release);
+}
+
+/**
* scsi_alloc_target - allocate a new or find an existing target
* @parent: parent of the target (need not be a scsi host)
* @channel: target channel number (zero if no channels)
@@ -392,7 +424,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
+ shost->transportt->target_size;
struct scsi_target *starget;
struct scsi_target *found_target;
- int error;
+ int error, ref_got;
starget = kzalloc(size, GFP_KERNEL);
if (!starget) {
@@ -401,7 +433,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
}
dev = &starget->dev;
device_initialize(dev);
- starget->reap_ref = 1;
+ kref_init(&starget->reap_ref);
dev->parent = get_device(parent);
dev_set_name(dev, "target%d:%d:%d", shost->host_no, channel, id);
dev->bus = &scsi_bus_type;
@@ -441,29 +473,36 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
return starget;
found:
- found_target->reap_ref++;
+ /*
+ * release routine already fired if kref is zero, so if we can still
+ * take the reference, the target must be alive. If we can't, it must
+ * be dying and we need to wait for a new target
+ */
+ ref_got = kref_get_unless_zero(&found_target->reap_ref);
+
spin_unlock_irqrestore(shost->host_lock, flags);
- if (found_target->state != STARGET_DEL) {
+ if (ref_got) {
put_device(dev);
return found_target;
}
- /* Unfortunately, we found a dying target; need to
- * wait until it's dead before we can get a new one */
+ /*
+ * Unfortunately, we found a dying target; need to wait until it's
+ * dead before we can get a new one. There is an anomaly here. We
+ * *should* call scsi_target_reap() to balance the kref_get() of the
+ * reap_ref above. However, since the target being released, it's
+ * already invisible and the reap_ref is irrelevant. If we call
+ * scsi_target_reap() we might spuriously do another device_del() on
+ * an already invisible target.
+ */
put_device(&found_target->dev);
- flush_scheduled_work();
+ /*
+ * length of time is irrelevant here, we just want to yield the CPU
+ * for a tick to avoid busy waiting for the target to die.
+ */
+ msleep(1);
goto retry;
}
-static void scsi_target_reap_usercontext(struct work_struct *work)
-{
- struct scsi_target *starget =
- container_of(work, struct scsi_target, ew.work);
-
- transport_remove_device(&starget->dev);
- device_del(&starget->dev);
- scsi_target_destroy(starget);
-}
-
/**
* scsi_target_reap - check to see if target is in use and destroy if not
* @starget: target to be checked
@@ -474,28 +513,13 @@ static void scsi_target_reap_usercontext(struct work_struct *work)
*/
void scsi_target_reap(struct scsi_target *starget)
{
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
- unsigned long flags;
- enum scsi_target_state state;
- int empty = 0;
-
- spin_lock_irqsave(shost->host_lock, flags);
- state = starget->state;
- if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
- empty = 1;
- starget->state = STARGET_DEL;
- }
- spin_unlock_irqrestore(shost->host_lock, flags);
-
- if (!empty)
- return;
-
- BUG_ON(state == STARGET_DEL);
- if (state == STARGET_CREATED)
- scsi_target_destroy(starget);
- else
- execute_in_process_context(scsi_target_reap_usercontext,
- &starget->ew);
+ /*
+ * serious problem if this triggers: STARGET_DEL is only set in the if
+ * the reap_ref drops to zero, so we're trying to do another final put
+ * on an already released kref
+ */
+ BUG_ON(starget->state == STARGET_DEL);
+ scsi_target_reap_ref_put(starget);
}
/**
@@ -946,6 +970,9 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
}
}
+ if (sdev->scsi_level >= SCSI_3)
+ scsi_attach_vpd(sdev);
+
sdev->max_queue_depth = sdev->queue_depth;
/*
@@ -1532,6 +1559,10 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
}
mutex_unlock(&shost->scan_mutex);
scsi_autopm_put_target(starget);
+ /*
+ * paired with scsi_alloc_target(). Target will be destroyed unless
+ * scsi_probe_and_add_lun made an underlying device visible
+ */
scsi_target_reap(starget);
put_device(&starget->dev);
@@ -1612,8 +1643,10 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
out_reap:
scsi_autopm_put_target(starget);
- /* now determine if the target has any children at all
- * and if not, nuke it */
+ /*
+ * paired with scsi_alloc_target(): determine if the target has
+ * any children at all and if not, nuke it
+ */
scsi_target_reap(starget);
put_device(&starget->dev);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 9117d0bf408e..074e8cc30955 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -300,7 +300,9 @@ store_shost_eh_deadline(struct device *dev, struct device_attribute *attr,
int ret = -EINVAL;
unsigned long deadline, flags;
- if (shost->transportt && shost->transportt->eh_strategy_handler)
+ if (shost->transportt &&
+ (shost->transportt->eh_strategy_handler ||
+ !shost->hostt->eh_host_reset_handler))
return ret;
if (!strncmp(buf, "off", strlen("off")))
@@ -383,17 +385,14 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
{
struct scsi_device *sdev;
struct device *parent;
- struct scsi_target *starget;
struct list_head *this, *tmp;
unsigned long flags;
sdev = container_of(work, struct scsi_device, ew.work);
parent = sdev->sdev_gendev.parent;
- starget = to_scsi_target(parent);
spin_lock_irqsave(sdev->host->host_lock, flags);
- starget->reap_ref++;
list_del(&sdev->siblings);
list_del(&sdev->same_target_siblings);
list_del(&sdev->starved_entry);
@@ -413,8 +412,8 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
/* NULL queue means the device can't be used */
sdev->request_queue = NULL;
- scsi_target_reap(scsi_target(sdev));
-
+ kfree(sdev->vpd_pg83);
+ kfree(sdev->vpd_pg80);
kfree(sdev->inquiry);
kfree(sdev);
@@ -579,7 +578,6 @@ static int scsi_sdev_check_buf_bit(const char *buf)
* Create the actual show/store functions and data structures.
*/
sdev_rd_attr (device_blocked, "%d\n");
-sdev_rd_attr (queue_depth, "%d\n");
sdev_rd_attr (device_busy, "%d\n");
sdev_rd_attr (type, "%d\n");
sdev_rd_attr (scsi_level, "%d\n");
@@ -649,23 +647,12 @@ store_rescan_field (struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field);
-static void sdev_store_delete_callback(struct device *dev)
-{
- scsi_remove_device(to_scsi_device(dev));
-}
-
static ssize_t
sdev_store_delete(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- int rc;
-
- /* An attribute cannot be unregistered by one of its own methods,
- * so we have to use this roundabout approach.
- */
- rc = device_schedule_callback(dev, sdev_store_delete_callback);
- if (rc)
- count = rc;
+ if (device_remove_file_self(dev, attr))
+ scsi_remove_device(to_scsi_device(dev));
return count;
};
static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
@@ -723,10 +710,64 @@ show_queue_type_field(struct device *dev, struct device_attribute *attr,
return snprintf(buf, 20, "%s\n", name);
}
-static DEVICE_ATTR(queue_type, S_IRUGO, show_queue_type_field, NULL);
+static ssize_t
+store_queue_type_field(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct scsi_host_template *sht = sdev->host->hostt;
+ int tag_type = 0, retval;
+ int prev_tag_type = scsi_get_tag_type(sdev);
+
+ if (!sdev->tagged_supported || !sht->change_queue_type)
+ return -EINVAL;
+
+ if (strncmp(buf, "ordered", 7) == 0)
+ tag_type = MSG_ORDERED_TAG;
+ else if (strncmp(buf, "simple", 6) == 0)
+ tag_type = MSG_SIMPLE_TAG;
+ else if (strncmp(buf, "none", 4) != 0)
+ return -EINVAL;
+
+ if (tag_type == prev_tag_type)
+ return count;
+
+ retval = sht->change_queue_type(sdev, tag_type);
+ if (retval < 0)
+ return retval;
+
+ return count;
+}
+
+static DEVICE_ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
+ store_queue_type_field);
+
+#define sdev_vpd_pg_attr(_page) \
+static ssize_t \
+show_vpd_##_page(struct file *filp, struct kobject *kobj, \
+ struct bin_attribute *bin_attr, \
+ char *buf, loff_t off, size_t count) \
+{ \
+ struct device *dev = container_of(kobj, struct device, kobj); \
+ struct scsi_device *sdev = to_scsi_device(dev); \
+ if (!sdev->vpd_##_page) \
+ return -EINVAL; \
+ return memory_read_from_buffer(buf, count, &off, \
+ sdev->vpd_##_page, \
+ sdev->vpd_##_page##_len); \
+} \
+static struct bin_attribute dev_attr_vpd_##_page = { \
+ .attr = {.name = __stringify(vpd_##_page), .mode = S_IRUGO }, \
+ .size = 0, \
+ .read = show_vpd_##_page, \
+};
+
+sdev_vpd_pg_attr(pg83);
+sdev_vpd_pg_attr(pg80);
static ssize_t
-show_iostat_counterbits(struct device *dev, struct device_attribute *attr, char *buf)
+show_iostat_counterbits(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8);
}
@@ -797,46 +838,9 @@ DECLARE_EVT(soft_threshold_reached, SOFT_THRESHOLD_REACHED_REPORTED)
DECLARE_EVT(mode_parameter_change_reported, MODE_PARAMETER_CHANGE_REPORTED)
DECLARE_EVT(lun_change_reported, LUN_CHANGE_REPORTED)
-/* Default template for device attributes. May NOT be modified */
-static struct attribute *scsi_sdev_attrs[] = {
- &dev_attr_device_blocked.attr,
- &dev_attr_type.attr,
- &dev_attr_scsi_level.attr,
- &dev_attr_device_busy.attr,
- &dev_attr_vendor.attr,
- &dev_attr_model.attr,
- &dev_attr_rev.attr,
- &dev_attr_rescan.attr,
- &dev_attr_delete.attr,
- &dev_attr_state.attr,
- &dev_attr_timeout.attr,
- &dev_attr_eh_timeout.attr,
- &dev_attr_iocounterbits.attr,
- &dev_attr_iorequest_cnt.attr,
- &dev_attr_iodone_cnt.attr,
- &dev_attr_ioerr_cnt.attr,
- &dev_attr_modalias.attr,
- REF_EVT(media_change),
- REF_EVT(inquiry_change_reported),
- REF_EVT(capacity_change_reported),
- REF_EVT(soft_threshold_reached),
- REF_EVT(mode_parameter_change_reported),
- REF_EVT(lun_change_reported),
- NULL
-};
-
-static struct attribute_group scsi_sdev_attr_group = {
- .attrs = scsi_sdev_attrs,
-};
-
-static const struct attribute_group *scsi_sdev_attr_groups[] = {
- &scsi_sdev_attr_group,
- NULL
-};
-
static ssize_t
-sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+sdev_store_queue_depth(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
int depth, retval;
struct scsi_device *sdev = to_scsi_device(dev);
@@ -859,10 +863,10 @@ sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr,
return count;
}
+sdev_show_function(queue_depth, "%d\n");
-static struct device_attribute sdev_attr_queue_depth_rw =
- __ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
- sdev_store_queue_depth_rw);
+static DEVICE_ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
+ sdev_store_queue_depth);
static ssize_t
sdev_show_queue_ramp_up_period(struct device *dev,
@@ -890,40 +894,79 @@ sdev_store_queue_ramp_up_period(struct device *dev,
return period;
}
-static struct device_attribute sdev_attr_queue_ramp_up_period =
- __ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR,
- sdev_show_queue_ramp_up_period,
- sdev_store_queue_ramp_up_period);
+static DEVICE_ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR,
+ sdev_show_queue_ramp_up_period,
+ sdev_store_queue_ramp_up_period);
-static ssize_t
-sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
{
+ struct device *dev = container_of(kobj, struct device, kobj);
struct scsi_device *sdev = to_scsi_device(dev);
- struct scsi_host_template *sht = sdev->host->hostt;
- int tag_type = 0, retval;
- int prev_tag_type = scsi_get_tag_type(sdev);
- if (!sdev->tagged_supported || !sht->change_queue_type)
- return -EINVAL;
- if (strncmp(buf, "ordered", 7) == 0)
- tag_type = MSG_ORDERED_TAG;
- else if (strncmp(buf, "simple", 6) == 0)
- tag_type = MSG_SIMPLE_TAG;
- else if (strncmp(buf, "none", 4) != 0)
- return -EINVAL;
+ if (attr == &dev_attr_queue_depth.attr &&
+ !sdev->host->hostt->change_queue_depth)
+ return S_IRUGO;
- if (tag_type == prev_tag_type)
- return count;
+ if (attr == &dev_attr_queue_ramp_up_period.attr &&
+ !sdev->host->hostt->change_queue_depth)
+ return 0;
- retval = sht->change_queue_type(sdev, tag_type);
- if (retval < 0)
- return retval;
+ if (attr == &dev_attr_queue_type.attr &&
+ !sdev->host->hostt->change_queue_type)
+ return S_IRUGO;
- return count;
+ return attr->mode;
}
+/* Default template for device attributes. May NOT be modified */
+static struct attribute *scsi_sdev_attrs[] = {
+ &dev_attr_device_blocked.attr,
+ &dev_attr_type.attr,
+ &dev_attr_scsi_level.attr,
+ &dev_attr_device_busy.attr,
+ &dev_attr_vendor.attr,
+ &dev_attr_model.attr,
+ &dev_attr_rev.attr,
+ &dev_attr_rescan.attr,
+ &dev_attr_delete.attr,
+ &dev_attr_state.attr,
+ &dev_attr_timeout.attr,
+ &dev_attr_eh_timeout.attr,
+ &dev_attr_iocounterbits.attr,
+ &dev_attr_iorequest_cnt.attr,
+ &dev_attr_iodone_cnt.attr,
+ &dev_attr_ioerr_cnt.attr,
+ &dev_attr_modalias.attr,
+ &dev_attr_queue_depth.attr,
+ &dev_attr_queue_type.attr,
+ &dev_attr_queue_ramp_up_period.attr,
+ REF_EVT(media_change),
+ REF_EVT(inquiry_change_reported),
+ REF_EVT(capacity_change_reported),
+ REF_EVT(soft_threshold_reached),
+ REF_EVT(mode_parameter_change_reported),
+ REF_EVT(lun_change_reported),
+ NULL
+};
+
+static struct bin_attribute *scsi_sdev_bin_attrs[] = {
+ &dev_attr_vpd_pg83,
+ &dev_attr_vpd_pg80,
+ NULL
+};
+static struct attribute_group scsi_sdev_attr_group = {
+ .attrs = scsi_sdev_attrs,
+ .bin_attrs = scsi_sdev_bin_attrs,
+ .is_visible = scsi_sdev_attr_is_visible,
+};
+
+static const struct attribute_group *scsi_sdev_attr_groups[] = {
+ &scsi_sdev_attr_group,
+ NULL
+};
+
static int scsi_target_add(struct scsi_target *starget)
{
int error;
@@ -946,10 +989,6 @@ static int scsi_target_add(struct scsi_target *starget)
return 0;
}
-static struct device_attribute sdev_attr_queue_type_rw =
- __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
- sdev_store_queue_type_rw);
-
/**
* scsi_sysfs_add_sdev - add scsi device to sysfs
* @sdev: scsi_device to add
@@ -1003,25 +1042,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
transport_add_device(&sdev->sdev_gendev);
sdev->is_visible = 1;
- /* create queue files, which may be writable, depending on the host */
- if (sdev->host->hostt->change_queue_depth) {
- error = device_create_file(&sdev->sdev_gendev,
- &sdev_attr_queue_depth_rw);
- error = device_create_file(&sdev->sdev_gendev,
- &sdev_attr_queue_ramp_up_period);
- }
- else
- error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth);
- if (error)
- return error;
-
- if (sdev->host->hostt->change_queue_type)
- error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw);
- else
- error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type);
- if (error)
- return error;
-
error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL);
if (error)
@@ -1071,6 +1091,13 @@ void __scsi_remove_device(struct scsi_device *sdev)
sdev->host->hostt->slave_destroy(sdev);
transport_destroy_device(dev);
+ /*
+ * Paired with the kref_get() in scsi_sysfs_initialize(). We have
+ * remoed sysfs visibility from the device, so make the target
+ * invisible if this was the last device underneath it.
+ */
+ scsi_target_reap(scsi_target(sdev));
+
put_device(dev);
}
@@ -1133,7 +1160,7 @@ void scsi_remove_target(struct device *dev)
continue;
if (starget->dev.parent == dev || &starget->dev == dev) {
/* assuming new targets arrive at the end */
- starget->reap_ref++;
+ kref_get(&starget->reap_ref);
spin_unlock_irqrestore(shost->host_lock, flags);
if (last)
scsi_target_reap(last);
@@ -1217,6 +1244,12 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
list_add_tail(&sdev->same_target_siblings, &starget->devices);
list_add_tail(&sdev->siblings, &shost->__devices);
spin_unlock_irqrestore(shost->host_lock, flags);
+ /*
+ * device can now only be removed via __scsi_remove_device() so hold
+ * the target. Target will be held in CREATED state until something
+ * beneath it becomes visible (in which case it moves to RUNNING)
+ */
+ kref_get(&starget->reap_ref);
}
int scsi_is_sdev_device(const struct device *dev)
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 84a1fdf67864..e51add05fb8d 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -155,7 +155,8 @@ void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
__blk_put_request(q, rq);
spin_unlock_irqrestore(q->queue_lock, flags);
- __scsi_put_command(shost, cmd, &shost->shost_gendev);
+ __scsi_put_command(shost, cmd);
+ put_device(&shost->shost_gendev);
}
EXPORT_SYMBOL_GPL(scsi_host_put_command);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 4628fd5e0688..f80908f74ca9 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -261,6 +261,7 @@ static const struct {
{ FC_PORTSPEED_10GBIT, "10 Gbit" },
{ FC_PORTSPEED_8GBIT, "8 Gbit" },
{ FC_PORTSPEED_16GBIT, "16 Gbit" },
+ { FC_PORTSPEED_32GBIT, "32 Gbit" },
{ FC_PORTSPEED_NOT_NEGOTIATED, "Not Negotiated" },
};
fc_bitfield_name_search(port_speed, fc_port_speed_names)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 470954aba728..89e6c04ac595 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1463,8 +1463,8 @@ static int sd_sync_cache(struct scsi_disk *sdkp)
sd_print_sense_hdr(sdkp, &sshdr);
/* we need to evaluate the error return */
if (scsi_sense_valid(&sshdr) &&
- /* 0x3a is medium not present */
- sshdr.asc == 0x3a)
+ (sshdr.asc == 0x3a || /* medium not present */
+ sshdr.asc == 0x20)) /* invalid command */
/* this is no error here */
return 0;
@@ -2281,7 +2281,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
set_disk_ro(sdkp->disk, 0);
if (sdp->skip_ms_page_3f) {
- sd_printk(KERN_NOTICE, sdkp, "Assuming Write Enabled\n");
+ sd_first_printk(KERN_NOTICE, sdkp, "Assuming Write Enabled\n");
return;
}
@@ -2313,7 +2313,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
}
if (!scsi_status_is_good(res)) {
- sd_printk(KERN_WARNING, sdkp,
+ sd_first_printk(KERN_WARNING, sdkp,
"Test WP failed, assume Write Enabled\n");
} else {
sdkp->write_prot = ((data.device_specific & 0x80) != 0);
@@ -2381,7 +2381,8 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
if (!data.header_length) {
modepage = 6;
first_len = 0;
- sd_printk(KERN_ERR, sdkp, "Missing header in MODE_SENSE response\n");
+ sd_first_printk(KERN_ERR, sdkp,
+ "Missing header in MODE_SENSE response\n");
}
/* that went OK, now ask for the proper length */
@@ -2394,7 +2395,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
if (len < 3)
goto bad_sense;
else if (len > SD_BUF_SIZE) {
- sd_printk(KERN_NOTICE, sdkp, "Truncating mode parameter "
+ sd_first_printk(KERN_NOTICE, sdkp, "Truncating mode parameter "
"data from %d to %d bytes\n", len, SD_BUF_SIZE);
len = SD_BUF_SIZE;
}
@@ -2417,8 +2418,9 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
/* We're interested only in the first 3 bytes.
*/
if (len - offset <= 2) {
- sd_printk(KERN_ERR, sdkp, "Incomplete "
- "mode parameter data\n");
+ sd_first_printk(KERN_ERR, sdkp,
+ "Incomplete mode parameter "
+ "data\n");
goto defaults;
} else {
modepage = page_code;
@@ -2432,14 +2434,15 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
else if (!spf && len - offset > 1)
offset += 2 + buffer[offset+1];
else {
- sd_printk(KERN_ERR, sdkp, "Incomplete "
- "mode parameter data\n");
+ sd_first_printk(KERN_ERR, sdkp,
+ "Incomplete mode "
+ "parameter data\n");
goto defaults;
}
}
}
- sd_printk(KERN_ERR, sdkp, "No Caching mode page found\n");
+ sd_first_printk(KERN_ERR, sdkp, "No Caching mode page found\n");
goto defaults;
Page_found:
@@ -2453,7 +2456,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
sdkp->DPOFUA = (data.device_specific & 0x10) != 0;
if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) {
- sd_printk(KERN_NOTICE, sdkp,
+ sd_first_printk(KERN_NOTICE, sdkp,
"Uses READ/WRITE(6), disabling FUA\n");
sdkp->DPOFUA = 0;
}
@@ -2475,16 +2478,19 @@ bad_sense:
sshdr.sense_key == ILLEGAL_REQUEST &&
sshdr.asc == 0x24 && sshdr.ascq == 0x0)
/* Invalid field in CDB */
- sd_printk(KERN_NOTICE, sdkp, "Cache data unavailable\n");
+ sd_first_printk(KERN_NOTICE, sdkp, "Cache data unavailable\n");
else
- sd_printk(KERN_ERR, sdkp, "Asking for cache data failed\n");
+ sd_first_printk(KERN_ERR, sdkp,
+ "Asking for cache data failed\n");
defaults:
if (sdp->wce_default_on) {
- sd_printk(KERN_NOTICE, sdkp, "Assuming drive cache: write back\n");
+ sd_first_printk(KERN_NOTICE, sdkp,
+ "Assuming drive cache: write back\n");
sdkp->WCE = 1;
} else {
- sd_printk(KERN_ERR, sdkp, "Assuming drive cache: write through\n");
+ sd_first_printk(KERN_ERR, sdkp,
+ "Assuming drive cache: write through\n");
sdkp->WCE = 0;
}
sdkp->RCD = 0;
@@ -2513,7 +2519,7 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
if (!scsi_status_is_good(res) || !data.header_length ||
data.length < 6) {
- sd_printk(KERN_WARNING, sdkp,
+ sd_first_printk(KERN_WARNING, sdkp,
"getting Control mode page failed, assume no ATO\n");
if (scsi_sense_valid(&sshdr))
@@ -2525,7 +2531,7 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
offset = data.header_length + data.block_descriptor_length;
if ((buffer[offset] & 0x3f) != 0x0a) {
- sd_printk(KERN_ERR, sdkp, "ATO Got wrong page\n");
+ sd_first_printk(KERN_ERR, sdkp, "ATO Got wrong page\n");
return;
}
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 26895ff247c5..620871efbf0a 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -104,6 +104,12 @@ static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
(sdsk)->disk->disk_name, ##a) : \
sdev_printk(prefix, (sdsk)->device, fmt, ##a)
+#define sd_first_printk(prefix, sdsk, fmt, a...) \
+ do { \
+ if ((sdkp)->first_scan) \
+ sd_printk(prefix, sdsk, fmt, ##a); \
+ } while (0)
+
static inline int scsi_medium_access_command(struct scsi_cmnd *scmd)
{
switch (scmd->cmnd[0]) {
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index eba183c428cf..80bfece1a2de 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/enclosure.h>
+#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -448,27 +449,18 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
static void ses_match_to_enclosure(struct enclosure_device *edev,
struct scsi_device *sdev)
{
- unsigned char *buf;
unsigned char *desc;
- unsigned int vpd_len;
struct efd efd = {
.addr = 0,
};
- buf = kmalloc(INIT_ALLOC_SIZE, GFP_KERNEL);
- if (!buf || scsi_get_vpd_page(sdev, 0x83, buf, INIT_ALLOC_SIZE))
- goto free;
-
ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
- vpd_len = ((buf[2] << 8) | buf[3]) + 4;
- kfree(buf);
- buf = kmalloc(vpd_len, GFP_KERNEL);
- if (!buf ||scsi_get_vpd_page(sdev, 0x83, buf, vpd_len))
- goto free;
+ if (!sdev->vpd_pg83_len)
+ return;
- desc = buf + 4;
- while (desc < buf + vpd_len) {
+ desc = sdev->vpd_pg83 + 4;
+ while (desc < sdev->vpd_pg83 + sdev->vpd_pg83_len) {
enum scsi_protocol proto = desc[0] >> 4;
u8 code_set = desc[0] & 0x0f;
u8 piv = desc[1] & 0x80;
@@ -478,25 +470,15 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
if (piv && code_set == 1 && assoc == 1
&& proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8)
- efd.addr = (u64)desc[4] << 56 |
- (u64)desc[5] << 48 |
- (u64)desc[6] << 40 |
- (u64)desc[7] << 32 |
- (u64)desc[8] << 24 |
- (u64)desc[9] << 16 |
- (u64)desc[10] << 8 |
- (u64)desc[11];
+ efd.addr = get_unaligned_be64(&desc[4]);
desc += len + 4;
}
- if (!efd.addr)
- goto free;
+ if (efd.addr) {
+ efd.dev = &sdev->sdev_gendev;
- efd.dev = &sdev->sdev_gendev;
-
- enclosure_for_each_device(ses_enclosure_find_by_addr, &efd);
- free:
- kfree(buf);
+ enclosure_for_each_device(ses_enclosure_find_by_addr, &efd);
+ }
}
static int ses_intf_add(struct device *cdev,
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index a1d6986261a3..afc834e172c6 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -2198,12 +2198,19 @@ static int st_set_options(struct scsi_tape *STp, long options)
struct st_modedef *STm;
char *name = tape_name(STp);
struct cdev *cd0, *cd1;
+ struct device *d0, *d1;
STm = &(STp->modes[STp->current_mode]);
if (!STm->defined) {
- cd0 = STm->cdevs[0]; cd1 = STm->cdevs[1];
+ cd0 = STm->cdevs[0];
+ cd1 = STm->cdevs[1];
+ d0 = STm->devs[0];
+ d1 = STm->devs[1];
memcpy(STm, &(STp->modes[0]), sizeof(struct st_modedef));
- STm->cdevs[0] = cd0; STm->cdevs[1] = cd1;
+ STm->cdevs[0] = cd0;
+ STm->cdevs[1] = cd1;
+ STm->devs[0] = d0;
+ STm->devs[1] = d1;
modes_defined = 1;
DEBC(printk(ST_DEB_MSG
"%s: Initialized mode %d definition from mode 0\n",
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 17d740427240..9969fa1ef7c4 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1419,6 +1419,9 @@ static void storvsc_device_destroy(struct scsi_device *sdevice)
{
struct stor_mem_pools *memp = sdevice->hostdata;
+ if (!memp)
+ return;
+
mempool_destroy(memp->request_mempool);
kmem_cache_destroy(memp->request_pool);
kfree(memp);
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index f1e4b4148c75..a4abce9d526e 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -259,7 +259,7 @@ found:
instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, t128_intr, IRQF_DISABLED, "t128",
+ 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);
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 9c216e563568..5a03bb3bcfef 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -873,7 +873,7 @@ static int port_detect \
/* Board detected, allocate its IRQ */
if (request_irq(irq, do_interrupt_handler,
- IRQF_DISABLED | ((subversion == ESA) ? IRQF_SHARED : 0),
+ (subversion == ESA) ? IRQF_SHARED : 0,
driver_name, (void *) &sha[j])) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
goto freelock;
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index b9755ec0e812..c88e1468aad7 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -1,7 +1,7 @@
/*
* Linux driver for VMware's para-virtualized SCSI HBA.
*
- * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2014, VMware, 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
@@ -32,6 +32,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
#include "vmw_pvscsi.h"
@@ -44,7 +45,7 @@ MODULE_VERSION(PVSCSI_DRIVER_VERSION_STRING);
#define PVSCSI_DEFAULT_NUM_PAGES_PER_RING 8
#define PVSCSI_DEFAULT_NUM_PAGES_MSG_RING 1
-#define PVSCSI_DEFAULT_QUEUE_DEPTH 64
+#define PVSCSI_DEFAULT_QUEUE_DEPTH 254
#define SGL_SIZE PAGE_SIZE
struct pvscsi_sg_list {
@@ -62,6 +63,7 @@ struct pvscsi_ctx {
dma_addr_t dataPA;
dma_addr_t sensePA;
dma_addr_t sglPA;
+ struct completion *abort_cmp;
};
struct pvscsi_adapter {
@@ -71,6 +73,7 @@ struct pvscsi_adapter {
bool use_msi;
bool use_msix;
bool use_msg;
+ bool use_req_threshold;
spinlock_t hw_lock;
@@ -102,18 +105,22 @@ struct pvscsi_adapter {
/* Command line parameters */
-static int pvscsi_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_PER_RING;
+static int pvscsi_ring_pages;
static int pvscsi_msg_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_MSG_RING;
static int pvscsi_cmd_per_lun = PVSCSI_DEFAULT_QUEUE_DEPTH;
static bool pvscsi_disable_msi;
static bool pvscsi_disable_msix;
static bool pvscsi_use_msg = true;
+static bool pvscsi_use_req_threshold = true;
#define PVSCSI_RW (S_IRUSR | S_IWUSR)
module_param_named(ring_pages, pvscsi_ring_pages, int, PVSCSI_RW);
MODULE_PARM_DESC(ring_pages, "Number of pages per req/cmp ring - (default="
- __stringify(PVSCSI_DEFAULT_NUM_PAGES_PER_RING) ")");
+ __stringify(PVSCSI_DEFAULT_NUM_PAGES_PER_RING)
+ "[up to 16 targets],"
+ __stringify(PVSCSI_SETUP_RINGS_MAX_NUM_PAGES)
+ "[for 16+ targets])");
module_param_named(msg_ring_pages, pvscsi_msg_ring_pages, int, PVSCSI_RW);
MODULE_PARM_DESC(msg_ring_pages, "Number of pages for the msg ring - (default="
@@ -121,7 +128,7 @@ MODULE_PARM_DESC(msg_ring_pages, "Number of pages for the msg ring - (default="
module_param_named(cmd_per_lun, pvscsi_cmd_per_lun, int, PVSCSI_RW);
MODULE_PARM_DESC(cmd_per_lun, "Maximum commands per lun - (default="
- __stringify(PVSCSI_MAX_REQ_QUEUE_DEPTH) ")");
+ __stringify(PVSCSI_DEFAULT_QUEUE_DEPTH) ")");
module_param_named(disable_msi, pvscsi_disable_msi, bool, PVSCSI_RW);
MODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)");
@@ -132,6 +139,10 @@ MODULE_PARM_DESC(disable_msix, "Disable MSI-X use in driver - (default=0)");
module_param_named(use_msg, pvscsi_use_msg, bool, PVSCSI_RW);
MODULE_PARM_DESC(use_msg, "Use msg ring when available - (default=1)");
+module_param_named(use_req_threshold, pvscsi_use_req_threshold,
+ bool, PVSCSI_RW);
+MODULE_PARM_DESC(use_req_threshold, "Use driver-based request coalescing if configured - (default=1)");
+
static const struct pci_device_id pvscsi_pci_tbl[] = {
{ PCI_VDEVICE(VMWARE, PCI_DEVICE_ID_VMWARE_PVSCSI) },
{ 0 }
@@ -177,6 +188,7 @@ static void pvscsi_release_context(struct pvscsi_adapter *adapter,
struct pvscsi_ctx *ctx)
{
ctx->cmd = NULL;
+ ctx->abort_cmp = NULL;
list_add(&ctx->list, &adapter->cmd_pool);
}
@@ -280,10 +292,15 @@ static int scsi_is_rw(unsigned char op)
static void pvscsi_kick_io(const struct pvscsi_adapter *adapter,
unsigned char op)
{
- if (scsi_is_rw(op))
- pvscsi_kick_rw_io(adapter);
- else
+ if (scsi_is_rw(op)) {
+ struct PVSCSIRingsState *s = adapter->rings_state;
+
+ if (!adapter->use_req_threshold ||
+ s->reqProdIdx - s->reqConsIdx >= s->reqCallThreshold)
+ pvscsi_kick_rw_io(adapter);
+ } else {
pvscsi_process_request_ring(adapter);
+ }
}
static void ll_adapter_reset(const struct pvscsi_adapter *adapter)
@@ -487,6 +504,35 @@ static void pvscsi_setup_all_rings(const struct pvscsi_adapter *adapter)
}
}
+static int pvscsi_change_queue_depth(struct scsi_device *sdev,
+ int qdepth,
+ int reason)
+{
+ int max_depth;
+ struct Scsi_Host *shost = sdev->host;
+
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ /*
+ * We support only changing default.
+ */
+ return -EOPNOTSUPP;
+
+ max_depth = shost->can_queue;
+ if (!sdev->tagged_supported)
+ max_depth = 1;
+ if (qdepth > max_depth)
+ qdepth = max_depth;
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+
+ if (sdev->inquiry_len > 7)
+ sdev_printk(KERN_INFO, sdev,
+ "qdepth(%d), tagged(%d), simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
+ sdev->queue_depth, sdev->tagged_supported,
+ sdev->simple_tags, sdev->ordered_tags,
+ sdev->scsi_level, (sdev->inquiry[7] & 2) >> 1);
+ return sdev->queue_depth;
+}
+
/*
* Pull a completion descriptor off and pass the completion back
* to the SCSI mid layer.
@@ -496,15 +542,27 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter,
{
struct pvscsi_ctx *ctx;
struct scsi_cmnd *cmd;
+ struct completion *abort_cmp;
u32 btstat = e->hostStatus;
u32 sdstat = e->scsiStatus;
ctx = pvscsi_get_context(adapter, e->context);
cmd = ctx->cmd;
+ abort_cmp = ctx->abort_cmp;
pvscsi_unmap_buffers(adapter, ctx);
pvscsi_release_context(adapter, ctx);
- cmd->result = 0;
+ if (abort_cmp) {
+ /*
+ * The command was requested to be aborted. Just signal that
+ * the request completed and swallow the actual cmd completion
+ * here. The abort handler will post a completion for this
+ * command indicating that it got successfully aborted.
+ */
+ complete(abort_cmp);
+ return;
+ }
+ cmd->result = 0;
if (sdstat != SAM_STAT_GOOD &&
(btstat == BTSTAT_SUCCESS ||
btstat == BTSTAT_LINKED_COMMAND_COMPLETED ||
@@ -726,6 +784,8 @@ static int pvscsi_abort(struct scsi_cmnd *cmd)
struct pvscsi_adapter *adapter = shost_priv(cmd->device->host);
struct pvscsi_ctx *ctx;
unsigned long flags;
+ int result = SUCCESS;
+ DECLARE_COMPLETION_ONSTACK(abort_cmp);
scmd_printk(KERN_DEBUG, cmd, "task abort on host %u, %p\n",
adapter->host->host_no, cmd);
@@ -748,13 +808,40 @@ static int pvscsi_abort(struct scsi_cmnd *cmd)
goto out;
}
+ /*
+ * Mark that the command has been requested to be aborted and issue
+ * the abort.
+ */
+ ctx->abort_cmp = &abort_cmp;
+
pvscsi_abort_cmd(adapter, ctx);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ /* Wait for 2 secs for the completion. */
+ wait_for_completion_timeout(&abort_cmp, msecs_to_jiffies(2000));
+ spin_lock_irqsave(&adapter->hw_lock, flags);
- pvscsi_process_completion_ring(adapter);
+ if (!completion_done(&abort_cmp)) {
+ /*
+ * Failed to abort the command, unmark the fact that it
+ * was requested to be aborted.
+ */
+ ctx->abort_cmp = NULL;
+ result = FAILED;
+ scmd_printk(KERN_DEBUG, cmd,
+ "Failed to get completion for aborted cmd %p\n",
+ cmd);
+ goto out;
+ }
+
+ /*
+ * Successfully aborted the command.
+ */
+ cmd->result = (DID_ABORT << 16);
+ cmd->scsi_done(cmd);
out:
spin_unlock_irqrestore(&adapter->hw_lock, flags);
- return SUCCESS;
+ return result;
}
/*
@@ -911,6 +998,7 @@ static struct scsi_host_template pvscsi_template = {
.dma_boundary = UINT_MAX,
.max_sectors = 0xffff,
.use_clustering = ENABLE_CLUSTERING,
+ .change_queue_depth = pvscsi_change_queue_depth,
.eh_abort_handler = pvscsi_abort,
.eh_device_reset_handler = pvscsi_device_reset,
.eh_bus_reset_handler = pvscsi_bus_reset,
@@ -1034,6 +1122,34 @@ static int pvscsi_setup_msg_workqueue(struct pvscsi_adapter *adapter)
return 1;
}
+static bool pvscsi_setup_req_threshold(struct pvscsi_adapter *adapter,
+ bool enable)
+{
+ u32 val;
+
+ if (!pvscsi_use_req_threshold)
+ return false;
+
+ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND,
+ PVSCSI_CMD_SETUP_REQCALLTHRESHOLD);
+ val = pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_COMMAND_STATUS);
+ if (val == -1) {
+ printk(KERN_INFO "vmw_pvscsi: device does not support req_threshold\n");
+ return false;
+ } else {
+ struct PVSCSICmdDescSetupReqCall cmd_msg = { 0 };
+ cmd_msg.enable = enable;
+ printk(KERN_INFO
+ "vmw_pvscsi: %sabling reqCallThreshold\n",
+ enable ? "en" : "dis");
+ pvscsi_write_cmd_desc(adapter,
+ PVSCSI_CMD_SETUP_REQCALLTHRESHOLD,
+ &cmd_msg, sizeof(cmd_msg));
+ return pvscsi_reg_read(adapter,
+ PVSCSI_REG_OFFSET_COMMAND_STATUS) != 0;
+ }
+}
+
static irqreturn_t pvscsi_isr(int irq, void *devp)
{
struct pvscsi_adapter *adapter = devp;
@@ -1236,11 +1352,12 @@ exit:
static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct pvscsi_adapter *adapter;
- struct Scsi_Host *host;
- struct device *dev;
+ struct pvscsi_adapter adapter_temp;
+ struct Scsi_Host *host = NULL;
unsigned int i;
unsigned long flags = 0;
int error;
+ u32 max_id;
error = -ENODEV;
@@ -1258,34 +1375,19 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_disable_device;
}
- pvscsi_template.can_queue =
- min(PVSCSI_MAX_NUM_PAGES_REQ_RING, pvscsi_ring_pages) *
- PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
- pvscsi_template.cmd_per_lun =
- min(pvscsi_template.can_queue, pvscsi_cmd_per_lun);
- host = scsi_host_alloc(&pvscsi_template, sizeof(struct pvscsi_adapter));
- if (!host) {
- printk(KERN_ERR "vmw_pvscsi: failed to allocate host\n");
- goto out_disable_device;
- }
-
- adapter = shost_priv(host);
+ /*
+ * Let's use a temp pvscsi_adapter struct until we find the number of
+ * targets on the adapter, after that we will switch to the real
+ * allocated struct.
+ */
+ adapter = &adapter_temp;
memset(adapter, 0, sizeof(*adapter));
adapter->dev = pdev;
- adapter->host = host;
-
- spin_lock_init(&adapter->hw_lock);
-
- host->max_channel = 0;
- host->max_id = 16;
- host->max_lun = 1;
- host->max_cmd_len = 16;
-
adapter->rev = pdev->revision;
if (pci_request_regions(pdev, "vmw_pvscsi")) {
printk(KERN_ERR "vmw_pvscsi: pci memory selection failed\n");
- goto out_free_host;
+ goto out_disable_device;
}
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
@@ -1301,7 +1403,7 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (i == DEVICE_COUNT_RESOURCE) {
printk(KERN_ERR
"vmw_pvscsi: adapter has no suitable MMIO region\n");
- goto out_release_resources;
+ goto out_release_resources_and_disable;
}
adapter->mmioBase = pci_iomap(pdev, i, PVSCSI_MEM_SPACE_SIZE);
@@ -1310,10 +1412,60 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
printk(KERN_ERR
"vmw_pvscsi: can't iomap for BAR %d memsize %lu\n",
i, PVSCSI_MEM_SPACE_SIZE);
- goto out_release_resources;
+ goto out_release_resources_and_disable;
}
pci_set_master(pdev);
+
+ /*
+ * Ask the device for max number of targets before deciding the
+ * default pvscsi_ring_pages value.
+ */
+ max_id = pvscsi_get_max_targets(adapter);
+ printk(KERN_INFO "vmw_pvscsi: max_id: %u\n", max_id);
+
+ if (pvscsi_ring_pages == 0)
+ /*
+ * Set the right default value. Up to 16 it is 8, above it is
+ * max.
+ */
+ pvscsi_ring_pages = (max_id > 16) ?
+ PVSCSI_SETUP_RINGS_MAX_NUM_PAGES :
+ PVSCSI_DEFAULT_NUM_PAGES_PER_RING;
+ printk(KERN_INFO
+ "vmw_pvscsi: setting ring_pages to %d\n",
+ pvscsi_ring_pages);
+
+ pvscsi_template.can_queue =
+ min(PVSCSI_MAX_NUM_PAGES_REQ_RING, pvscsi_ring_pages) *
+ PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
+ pvscsi_template.cmd_per_lun =
+ min(pvscsi_template.can_queue, pvscsi_cmd_per_lun);
+ host = scsi_host_alloc(&pvscsi_template, sizeof(struct pvscsi_adapter));
+ if (!host) {
+ printk(KERN_ERR "vmw_pvscsi: failed to allocate host\n");
+ goto out_release_resources_and_disable;
+ }
+
+ /*
+ * Let's use the real pvscsi_adapter struct here onwards.
+ */
+ adapter = shost_priv(host);
+ memset(adapter, 0, sizeof(*adapter));
+ adapter->dev = pdev;
+ adapter->host = host;
+ /*
+ * Copy back what we already have to the allocated adapter struct.
+ */
+ adapter->rev = adapter_temp.rev;
+ adapter->mmioBase = adapter_temp.mmioBase;
+
+ spin_lock_init(&adapter->hw_lock);
+ host->max_channel = 0;
+ host->max_lun = 1;
+ host->max_cmd_len = 16;
+ host->max_id = max_id;
+
pci_set_drvdata(pdev, host);
ll_adapter_reset(adapter);
@@ -1327,13 +1479,6 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/*
- * Ask the device for max number of targets.
- */
- host->max_id = pvscsi_get_max_targets(adapter);
- dev = pvscsi_dev(adapter);
- dev_info(dev, "vmw_pvscsi: host->max_id: %u\n", host->max_id);
-
- /*
* From this point on we should reset the adapter if anything goes
* wrong.
*/
@@ -1373,6 +1518,10 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
flags = IRQF_SHARED;
}
+ adapter->use_req_threshold = pvscsi_setup_req_threshold(adapter, true);
+ printk(KERN_DEBUG "vmw_pvscsi: driver-based request coalescing %sabled\n",
+ adapter->use_req_threshold ? "en" : "dis");
+
error = request_irq(adapter->irq, pvscsi_isr, flags,
"vmw_pvscsi", adapter);
if (error) {
@@ -1402,12 +1551,15 @@ out_reset_adapter:
ll_adapter_reset(adapter);
out_release_resources:
pvscsi_release_resources(adapter);
-out_free_host:
scsi_host_put(host);
out_disable_device:
pci_disable_device(pdev);
return error;
+
+out_release_resources_and_disable:
+ pvscsi_release_resources(adapter);
+ goto out_disable_device;
}
static void __pvscsi_shutdown(struct pvscsi_adapter *adapter)
diff --git a/drivers/scsi/vmw_pvscsi.h b/drivers/scsi/vmw_pvscsi.h
index 3546e8662e30..ce4588851274 100644
--- a/drivers/scsi/vmw_pvscsi.h
+++ b/drivers/scsi/vmw_pvscsi.h
@@ -1,7 +1,7 @@
/*
* VMware PVSCSI header file
*
- * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2014, VMware, 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
@@ -26,7 +26,7 @@
#include <linux/types.h>
-#define PVSCSI_DRIVER_VERSION_STRING "1.0.2.0-k"
+#define PVSCSI_DRIVER_VERSION_STRING "1.0.5.0-k"
#define PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT 128
@@ -117,8 +117,9 @@ enum PVSCSICommands {
PVSCSI_CMD_CONFIG = 7,
PVSCSI_CMD_SETUP_MSG_RING = 8,
PVSCSI_CMD_DEVICE_UNPLUG = 9,
+ PVSCSI_CMD_SETUP_REQCALLTHRESHOLD = 10,
- PVSCSI_CMD_LAST = 10 /* has to be last */
+ PVSCSI_CMD_LAST = 11 /* has to be last */
};
/*
@@ -141,6 +142,14 @@ struct PVSCSICmdDescConfigCmd {
u32 _pad;
} __packed;
+/*
+ * Command descriptor for PVSCSI_CMD_SETUP_REQCALLTHRESHOLD --
+ */
+
+struct PVSCSICmdDescSetupReqCall {
+ u32 enable;
+} __packed;
+
enum PVSCSIConfigPageType {
PVSCSI_CONFIG_PAGE_CONTROLLER = 0x1958,
PVSCSI_CONFIG_PAGE_PHY = 0x1959,
@@ -261,7 +270,9 @@ struct PVSCSIRingsState {
u32 cmpConsIdx;
u32 cmpNumEntriesLog2;
- u8 _pad[104];
+ u32 reqCallThreshold;
+
+ u8 _pad[100];
u32 msgProdIdx;
u32 msgConsIdx;
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index f9a6e4b0affe..32674236fec7 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1252,7 +1252,7 @@ static int wd7000_init(Adapter * host)
return 0;
- if (request_irq(host->irq, wd7000_intr, IRQF_DISABLED, "wd7000", host)) {
+ if (request_irq(host->irq, wd7000_intr, 0, "wd7000", host)) {
printk("wd7000_init: can't get IRQ %d.\n", host->irq);
return (0);
}
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 581ee2a8856b..efe1960af2b3 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -150,7 +150,7 @@ config SPI_BUTTERFLY
config SPI_CLPS711X
tristate "CLPS711X host SPI controller"
- depends on ARCH_CLPS711X
+ depends on ARCH_CLPS711X || COMPILE_TEST
help
This enables dedicated general purpose SPI/Microwire1-compatible
master mode interface (SSI1) for CLPS711X-based CPUs.
@@ -212,7 +212,6 @@ config SPI_IMX
tristate "Freescale i.MX SPI controllers"
depends on ARCH_MXC || COMPILE_TEST
select SPI_BITBANG
- default m if IMX_HAVE_PLATFORM_SPI_IMX
help
This enables using the Freescale i.MX SPI controllers in master
mode.
@@ -270,6 +269,7 @@ config SPI_FSL_SPI
config SPI_FSL_DSPI
tristate "Freescale DSPI controller"
select SPI_BITBANG
+ select REGMAP_MMIO
depends on SOC_VF610 || COMPILE_TEST
help
This enables support for the Freescale DSPI controller in master
@@ -307,7 +307,7 @@ config SPI_OMAP_UWIRE
config SPI_OMAP24XX
tristate "McSPI driver for OMAP"
- depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SH
+ depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SUPERH
depends on ARCH_OMAP2PLUS || COMPILE_TEST
help
SPI master controller for OMAP24XX and later Multichannel SPI
@@ -381,6 +381,19 @@ config SPI_RSPI
help
SPI driver for Renesas RSPI and QSPI blocks.
+config SPI_QUP
+ tristate "Qualcomm SPI controller with QUP interface"
+ depends on ARCH_MSM_DT || (ARM && COMPILE_TEST)
+ help
+ Qualcomm Universal Peripheral (QUP) core is an AHB slave that
+ provides a common data path (an output FIFO and an input FIFO)
+ for serial peripheral interface (SPI) mini-core. SPI in master
+ mode supports up to 50MHz, up to four chip selects, programmable
+ data path from 4 bits to 32 bits and numerous protocol variants.
+
+ This driver can also be built as a module. If so, the module
+ will be called spi_qup.
+
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
depends on ARCH_S3C24XX
@@ -416,7 +429,6 @@ config SPI_SH_MSIOF
tristate "SuperH MSIOF SPI controller"
depends on HAVE_CLK
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
- select SPI_BITBANG
help
SPI driver for SuperH and SH Mobile MSIOF blocks.
@@ -446,6 +458,19 @@ config SPI_SIRF
help
SPI driver for CSR SiRFprimaII SoCs
+config SPI_SUN4I
+ tristate "Allwinner A10 SoCs SPI controller"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ help
+ SPI driver for Allwinner sun4i, sun5i and sun7i SoCs
+
+config SPI_SUN6I
+ tristate "Allwinner A31 SPI controller"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ depends on RESET_CONTROLLER
+ help
+ This enables using the SPI controller on the Allwinner A31 SoCs.
+
config SPI_MXS
tristate "Freescale MXS SPI controller"
depends on ARCH_MXS
@@ -478,13 +503,6 @@ config SPI_TEGRA20_SLINK
help
SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
-config SPI_TI_SSP
- tristate "TI Sequencer Serial Port - SPI Support"
- depends on MFD_TI_SSP
- help
- This selects an SPI master implementation using a TI sequencer
- serial port.
-
config SPI_TOPCLIFF_PCH
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI"
depends on PCI
@@ -520,6 +538,19 @@ config SPI_XILINX
Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
+config SPI_XTENSA_XTFPGA
+ tristate "Xtensa SPI controller for xtfpga"
+ depends on (XTENSA && XTENSA_PLATFORM_XTFPGA) || COMPILE_TEST
+ select SPI_BITBANG
+ help
+ SPI driver for xtfpga SPI master controller.
+
+ This simple SPI master controller is built into xtfpga bitstreams
+ and is used to control daughterboard audio codec. It always transfers
+ 16 bit words in SPI mode 0, automatically asserting CS on transfer
+ start and deasserting on end.
+
+
config SPI_NUC900
tristate "Nuvoton NUC900 series SPI"
depends on ARCH_W90X900
@@ -546,7 +577,7 @@ config SPI_DW_MID_DMA
config SPI_DW_MMIO
tristate "Memory-mapped io interface driver for DW SPI core"
- depends on SPI_DESIGNWARE && HAVE_CLK
+ depends on SPI_DESIGNWARE
#
# There are lots of SPI device types, with sensors and memory
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 95af48d2d360..bd792669e563 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -59,6 +59,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA) += spi-pxa2xx-pxadma.o
spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
+obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
spi-s3c24xx-hw-y := spi-s3c24xx.o
@@ -70,12 +71,14 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
+obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
+obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
-obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o
obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
+obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o
diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c
index 5d7deaf62867..5b5709a5c957 100644
--- a/drivers/spi/spi-altera.c
+++ b/drivers/spi/spi-altera.c
@@ -13,7 +13,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -200,7 +199,6 @@ static irqreturn_t altera_spi_irq(int irq, void *dev)
static int altera_spi_probe(struct platform_device *pdev)
{
- struct altera_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
struct altera_spi *hw;
struct spi_master *master;
struct resource *res;
@@ -214,6 +212,8 @@ static int altera_spi_probe(struct platform_device *pdev)
master->bus_num = pdev->id;
master->num_chipselect = 16;
master->mode_bits = SPI_CS_HIGH;
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
+ master->dev.of_node = pdev->dev.of_node;
hw = spi_master_get_devdata(master);
platform_set_drvdata(pdev, hw);
@@ -245,9 +245,6 @@ static int altera_spi_probe(struct platform_device *pdev)
if (err)
goto exit;
}
- /* find platform data */
- if (!platp)
- hw->bitbang.master->dev.of_node = pdev->dev.of_node;
/* register our spi controller */
err = spi_bitbang_start(&hw->bitbang);
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index 31534b51715a..3898b0b9ee77 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
@@ -132,9 +131,9 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
flags = GPIOF_DIR_OUT;
if (spi->mode & SPI_CS_HIGH)
- flags |= GPIOF_INIT_HIGH;
- else
flags |= GPIOF_INIT_LOW;
+ else
+ flags |= GPIOF_INIT_HIGH;
status = gpio_request_one(cdata->gpio, flags,
dev_name(&spi->dev));
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index b0842f751016..8005f9869481 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -9,7 +9,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -26,6 +25,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
/* SPI register offsets */
#define SPI_CR 0x0000
@@ -993,13 +993,6 @@ static int atmel_spi_setup(struct spi_device *spi)
as = spi_master_get_devdata(spi->master);
- if (spi->chip_select > spi->master->num_chipselect) {
- dev_dbg(&spi->dev,
- "setup: invalid chipselect %u (%u defined)\n",
- spi->chip_select, spi->master->num_chipselect);
- return -EINVAL;
- }
-
/* see notes above re chipselect */
if (!atmel_spi_is_v2(as)
&& spi->chip_select == 0
@@ -1087,14 +1080,6 @@ static int atmel_spi_one_transfer(struct spi_master *master,
}
}
- if (xfer->bits_per_word > 8) {
- if (xfer->len % 2) {
- dev_dbg(&spi->dev,
- "buffer len should be 16 bits aligned\n");
- return -EINVAL;
- }
- }
-
/*
* DMA map early, for performance (empties dcache ASAP) and
* better fault reporting.
@@ -1221,9 +1206,6 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
dev_dbg(&spi->dev, "new message %p submitted for %s\n",
msg, dev_name(&spi->dev));
- if (unlikely(list_empty(&msg->transfers)))
- return -EINVAL;
-
atmel_spi_lock(as);
cs_activate(as, spi);
@@ -1244,10 +1226,10 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
dev_dbg(&spi->dev,
- " xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+ " xfer %p: len %u tx %p/%pad rx %p/%pad\n",
xfer, xfer->len,
- xfer->tx_buf, xfer->tx_dma,
- xfer->rx_buf, xfer->rx_dma);
+ xfer->tx_buf, &xfer->tx_dma,
+ xfer->rx_buf, &xfer->rx_dma);
}
msg_done:
@@ -1303,6 +1285,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
struct spi_master *master;
struct atmel_spi *as;
+ /* Select default pin state */
+ pinctrl_pm_select_default_state(&pdev->dev);
+
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
return -ENXIO;
@@ -1455,8 +1440,19 @@ static int atmel_spi_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct atmel_spi *as = spi_master_get_devdata(master);
+ int ret;
+
+ /* Stop the queue running */
+ ret = spi_master_suspend(master);
+ if (ret) {
+ dev_warn(dev, "cannot suspend master\n");
+ return ret;
+ }
clk_disable_unprepare(as->clk);
+
+ pinctrl_pm_select_sleep_state(dev);
+
return 0;
}
@@ -1464,9 +1460,18 @@ static int atmel_spi_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct atmel_spi *as = spi_master_get_devdata(master);
+ int ret;
+
+ pinctrl_pm_select_default_state(dev);
clk_prepare_enable(as->clk);
- return 0;
+
+ /* Start the queue running */
+ ret = spi_master_resume(master);
+ if (ret)
+ dev_err(dev, "problem starting queue (%d)\n", ret);
+
+ return ret;
}
static SIMPLE_DEV_PM_OPS(atmel_spi_pm_ops, atmel_spi_suspend, atmel_spi_resume);
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c
index c4141c92bcff..67375a11d4bd 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -55,8 +55,6 @@ struct au1550_spi {
volatile psc_spi_t __iomem *regs;
int irq;
- unsigned freq_max;
- unsigned freq_min;
unsigned len;
unsigned tx_count;
@@ -248,11 +246,8 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
hz = t->speed_hz;
}
- if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
- dev_err(&spi->dev, "setupxfer: clock rate=%d out of range\n",
- hz);
+ if (!hz)
return -EINVAL;
- }
au1550_spi_bits_handlers_set(hw, spi->bits_per_word);
@@ -287,23 +282,6 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
return 0;
}
-static int au1550_spi_setup(struct spi_device *spi)
-{
- struct au1550_spi *hw = spi_master_get_devdata(spi->master);
-
- if (spi->max_speed_hz == 0)
- spi->max_speed_hz = hw->freq_max;
- if (spi->max_speed_hz > hw->freq_max
- || spi->max_speed_hz < hw->freq_min)
- return -EINVAL;
- /*
- * NOTE: cannot change speed and other hw settings immediately,
- * otherwise sharing of spi bus is not possible,
- * so do not call setupxfer(spi, NULL) here
- */
- return 0;
-}
-
/*
* for dma spi transfers, we have to setup rx channel, otherwise there is
* no reliable way how to recognize that spi transfer is done
@@ -838,7 +816,6 @@ static int au1550_spi_probe(struct platform_device *pdev)
hw->bitbang.master = hw->master;
hw->bitbang.setup_transfer = au1550_spi_setupxfer;
hw->bitbang.chipselect = au1550_spi_chipsel;
- hw->bitbang.master->setup = au1550_spi_setup;
hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs;
if (hw->usedma) {
@@ -909,8 +886,9 @@ static int au1550_spi_probe(struct platform_device *pdev)
{
int min_div = (2 << 0) * (2 * (4 + 1));
int max_div = (2 << 3) * (2 * (63 + 1));
- hw->freq_max = hw->pdata->mainclk_hz / min_div;
- hw->freq_min = hw->pdata->mainclk_hz / (max_div + 1) + 1;
+ master->max_speed_hz = hw->pdata->mainclk_hz / min_div;
+ master->min_speed_hz =
+ hw->pdata->mainclk_hz / (max_div + 1) + 1;
}
au1550_spi_setup_psc_as_spi(hw);
@@ -999,6 +977,15 @@ static int __init au1550_spi_init(void)
* create memory device with 8 bits dev_devwidth
* needed for proper byte ordering to spi fifo
*/
+ switch (alchemy_get_cputype()) {
+ case ALCHEMY_CPU_AU1550:
+ case ALCHEMY_CPU_AU1200:
+ case ALCHEMY_CPU_AU1300:
+ break;
+ default:
+ return -ENODEV;
+ }
+
if (usedma) {
ddma_memid = au1xxx_ddma_add_device(&au1550_spi_mem_dbdev);
if (!ddma_memid)
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 8a89dd1f2654..69167456ec1e 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -315,7 +315,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
master->mode_bits = BCM2835_SPI_MODE_BITS;
master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->bus_num = -1;
master->num_chipselect = 3;
master->transfer_one_message = bcm2835_spi_transfer_one;
master->dev.of_node = pdev->dev.of_node;
diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c
index b528f9fc8bc0..5a211e98383b 100644
--- a/drivers/spi/spi-bcm63xx-hsspi.c
+++ b/drivers/spi/spi-bcm63xx-hsspi.c
@@ -180,7 +180,7 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
while (pending > 0) {
int curr_step = min_t(int, step_size, pending);
- init_completion(&bs->done);
+ reinit_completion(&bs->done);
if (tx) {
memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, tx, curr_step);
tx += curr_step;
@@ -369,6 +369,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0));
mutex_init(&bs->bus_mutex);
+ init_completion(&bs->done);
master->bus_num = HSSPI_BUS_NUM;
master->num_chipselect = 8;
@@ -453,9 +454,8 @@ static int bcm63xx_hsspi_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops bcm63xx_hsspi_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(bcm63xx_hsspi_suspend, bcm63xx_hsspi_resume)
-};
+static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend,
+ bcm63xx_hsspi_resume);
static struct platform_driver bcm63xx_hsspi_driver = {
.driver = {
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 77286aef2adf..0250fa721cea 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -20,7 +20,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -35,8 +34,6 @@
#include <bcm63xx_dev_spi.h>
-#define PFX KBUILD_MODNAME
-
#define BCM63XX_SPI_MAX_PREPEND 15
struct bcm63xx_spi {
@@ -169,7 +166,7 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
transfer_list);
}
- init_completion(&bs->done);
+ reinit_completion(&bs->done);
/* Fill in the Message control register */
msg_ctl = (len << SPI_BYTE_CNT_SHIFT);
@@ -353,6 +350,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
}
bs = spi_master_get_devdata(master);
+ init_completion(&bs->done);
platform_set_drvdata(pdev, master);
bs->pdev = pdev;
diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c
index 38941e5920b5..f515c5e9db57 100644
--- a/drivers/spi/spi-bfin-sport.c
+++ b/drivers/spi/spi-bfin-sport.c
@@ -8,7 +8,6 @@
* Licensed under the GPL-2 or later.
*/
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/spi/spi-bfin-v3.c b/drivers/spi/spi-bfin-v3.c
index 8f8598834b30..4089d0e0d84e 100644
--- a/drivers/spi/spi-bfin-v3.c
+++ b/drivers/spi/spi-bfin-v3.c
@@ -822,7 +822,8 @@ static int bfin_spi_probe(struct platform_device *pdev)
master->cleanup = bfin_spi_cleanup;
master->setup = bfin_spi_setup;
master->transfer_one_message = bfin_spi_transfer_one_message;
- master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
+ master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(8);
drv_data = spi_master_get_devdata(master);
drv_data->master = master;
diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c
index f0f195af75d4..55e57c3eb9bd 100644
--- a/drivers/spi/spi-bfin5xx.c
+++ b/drivers/spi/spi-bfin5xx.c
@@ -350,7 +350,6 @@ static void *bfin_spi_next_transfer(struct bfin_spi_master_data *drv_data)
static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
{
struct bfin_spi_slave_data *chip = drv_data->cur_chip;
- struct spi_transfer *last_transfer;
unsigned long flags;
struct spi_message *msg;
@@ -362,9 +361,6 @@ static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
queue_work(drv_data->workqueue, &drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags);
- last_transfer = list_entry(msg->transfers.prev,
- struct spi_transfer, transfer_list);
-
msg->state = NULL;
if (!drv_data->cs_change)
@@ -1030,10 +1026,6 @@ static int bfin_spi_setup(struct spi_device *spi)
}
/* translate common spi framework into our register */
- if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
- dev_err(&spi->dev, "unsupported spi modes detected\n");
- goto error;
- }
if (spi->mode & SPI_CPOL)
chip->ctl_reg |= BIT_CTL_CPOL;
if (spi->mode & SPI_CPHA)
diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c
index bd222f6b677d..dc7d2c2d643e 100644
--- a/drivers/spi/spi-bitbang.c
+++ b/drivers/spi/spi-bitbang.c
@@ -16,7 +16,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
@@ -467,11 +466,9 @@ EXPORT_SYMBOL_GPL(spi_bitbang_start);
/**
* spi_bitbang_stop - stops the task providing spi communication
*/
-int spi_bitbang_stop(struct spi_bitbang *bitbang)
+void spi_bitbang_stop(struct spi_bitbang *bitbang)
{
spi_unregister_master(bitbang->master);
-
- return 0;
}
EXPORT_SYMBOL_GPL(spi_bitbang_stop);
diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c
index 8081f96bd1d5..ee4f91ccd8fd 100644
--- a/drivers/spi/spi-butterfly.c
+++ b/drivers/spi/spi-butterfly.c
@@ -309,7 +309,6 @@ done:
static void butterfly_detach(struct parport *p)
{
struct butterfly *pp;
- int status;
/* FIXME this global is ugly ... but, how to quickly get from
* the parport to the "struct butterfly" associated with it?
@@ -321,7 +320,7 @@ static void butterfly_detach(struct parport *p)
butterfly = NULL;
/* stop() unregisters child devices too */
- status = spi_bitbang_stop(&pp->bitbang);
+ spi_bitbang_stop(&pp->bitbang);
/* turn off VCC */
parport_write_data(pp->port, 0);
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c
index 374ba4a48a9e..4cd62f636547 100644
--- a/drivers/spi/spi-clps711x.c
+++ b/drivers/spi/spi-clps711x.c
@@ -11,158 +11,125 @@
#include <linux/io.h>
#include <linux/clk.h>
-#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/clps711x.h>
#include <linux/spi/spi.h>
#include <linux/platform_data/spi-clps711x.h>
-#include <mach/hardware.h>
-
#define DRIVER_NAME "spi-clps711x"
-struct spi_clps711x_data {
- struct completion done;
+#define SYNCIO_FRMLEN(x) ((x) << 8)
+#define SYNCIO_TXFRMEN (1 << 14)
+struct spi_clps711x_data {
+ void __iomem *syncio;
+ struct regmap *syscon;
+ struct regmap *syscon1;
struct clk *spi_clk;
- u32 max_speed_hz;
u8 *tx_buf;
u8 *rx_buf;
- int count;
+ unsigned int bpw;
int len;
-
- int chipselect[0];
};
static int spi_clps711x_setup(struct spi_device *spi)
{
- struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
-
/* We are expect that SPI-device is not selected */
- gpio_direction_output(hw->chipselect[spi->chip_select],
- !(spi->mode & SPI_CS_HIGH));
+ gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
return 0;
}
-static void spi_clps711x_setup_mode(struct spi_device *spi)
-{
- /* Setup edge for transfer */
- if (spi->mode & SPI_CPHA)
- clps_writew(clps_readw(SYSCON3) | SYSCON3_ADCCKNSEN, SYSCON3);
- else
- clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3);
-}
-
-static int spi_clps711x_setup_xfer(struct spi_device *spi,
- struct spi_transfer *xfer)
+static void spi_clps711x_setup_xfer(struct spi_device *spi,
+ struct spi_transfer *xfer)
{
- u32 speed = xfer->speed_hz ? : spi->max_speed_hz;
- u8 bpw = xfer->bits_per_word;
- struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
-
- if (bpw != 8) {
- dev_err(&spi->dev, "Unsupported master bus width %i\n", bpw);
- return -EINVAL;
- }
+ struct spi_master *master = spi->master;
+ struct spi_clps711x_data *hw = spi_master_get_devdata(master);
/* Setup SPI frequency divider */
- if (!speed || (speed >= hw->max_speed_hz))
- clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
- SYSCON1_ADCKSEL(3), SYSCON1);
- else if (speed >= (hw->max_speed_hz / 2))
- clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
- SYSCON1_ADCKSEL(2), SYSCON1);
- else if (speed >= (hw->max_speed_hz / 8))
- clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
- SYSCON1_ADCKSEL(1), SYSCON1);
+ if (xfer->speed_hz >= master->max_speed_hz)
+ regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+ SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(3));
+ else if (xfer->speed_hz >= (master->max_speed_hz / 2))
+ regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+ SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(2));
+ else if (xfer->speed_hz >= (master->max_speed_hz / 8))
+ regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+ SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(1));
else
- clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
- SYSCON1_ADCKSEL(0), SYSCON1);
-
- return 0;
+ regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+ SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(0));
}
-static int spi_clps711x_transfer_one_message(struct spi_master *master,
- struct spi_message *msg)
+static int spi_clps711x_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
{
struct spi_clps711x_data *hw = spi_master_get_devdata(master);
- struct spi_transfer *xfer;
- int status = 0, cs = hw->chipselect[msg->spi->chip_select];
- u32 data;
-
- spi_clps711x_setup_mode(msg->spi);
-
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- if (spi_clps711x_setup_xfer(msg->spi, xfer)) {
- status = -EINVAL;
- goto out_xfr;
- }
+ struct spi_device *spi = msg->spi;
- gpio_set_value(cs, !!(msg->spi->mode & SPI_CS_HIGH));
-
- reinit_completion(&hw->done);
-
- hw->count = 0;
- hw->len = xfer->len;
- hw->tx_buf = (u8 *)xfer->tx_buf;
- hw->rx_buf = (u8 *)xfer->rx_buf;
-
- /* Initiate transfer */
- data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
- clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
-
- wait_for_completion(&hw->done);
+ /* Setup mode for transfer */
+ return regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCKNSEN,
+ (spi->mode & SPI_CPHA) ?
+ SYSCON3_ADCCKNSEN : 0);
+}
- if (xfer->delay_usecs)
- udelay(xfer->delay_usecs);
+static int spi_clps711x_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+ u8 data;
- if (xfer->cs_change ||
- list_is_last(&xfer->transfer_list, &msg->transfers))
- gpio_set_value(cs, !(msg->spi->mode & SPI_CS_HIGH));
+ spi_clps711x_setup_xfer(spi, xfer);
- msg->actual_length += xfer->len;
- }
+ hw->len = xfer->len;
+ hw->bpw = xfer->bits_per_word;
+ hw->tx_buf = (u8 *)xfer->tx_buf;
+ hw->rx_buf = (u8 *)xfer->rx_buf;
-out_xfr:
- msg->status = status;
- spi_finalize_current_message(master);
+ /* Initiate transfer */
+ data = hw->tx_buf ? *hw->tx_buf++ : 0;
+ writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, hw->syncio);
- return 0;
+ return 1;
}
static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
{
- struct spi_clps711x_data *hw = (struct spi_clps711x_data *)dev_id;
- u32 data;
+ struct spi_master *master = dev_id;
+ struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+ u8 data;
/* Handle RX */
- data = clps_readb(SYNCIO);
+ data = readb(hw->syncio);
if (hw->rx_buf)
- hw->rx_buf[hw->count] = (u8)data;
-
- hw->count++;
+ *hw->rx_buf++ = data;
/* Handle TX */
- if (hw->count < hw->len) {
- data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
- clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
+ if (--hw->len > 0) {
+ data = hw->tx_buf ? *hw->tx_buf++ : 0;
+ writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN,
+ hw->syncio);
} else
- complete(&hw->done);
+ spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
static int spi_clps711x_probe(struct platform_device *pdev)
{
- int i, ret;
- struct spi_master *master;
struct spi_clps711x_data *hw;
struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev);
+ struct spi_master *master;
+ struct resource *res;
+ int i, irq, ret;
if (!pdata) {
dev_err(&pdev->dev, "No platform data supplied\n");
@@ -174,33 +141,37 @@ static int spi_clps711x_probe(struct platform_device *pdev)
return -EINVAL;
}
- master = spi_alloc_master(&pdev->dev,
- sizeof(struct spi_clps711x_data) +
- sizeof(int) * pdata->num_chipselect);
- if (!master) {
- dev_err(&pdev->dev, "SPI allocating memory error\n");
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*hw));
+ if (!master)
return -ENOMEM;
+
+ master->cs_gpios = devm_kzalloc(&pdev->dev, sizeof(int) *
+ pdata->num_chipselect, GFP_KERNEL);
+ if (!master->cs_gpios) {
+ ret = -ENOMEM;
+ goto err_out;
}
master->bus_num = pdev->id;
master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8);
master->num_chipselect = pdata->num_chipselect;
master->setup = spi_clps711x_setup;
- master->transfer_one_message = spi_clps711x_transfer_one_message;
+ master->prepare_message = spi_clps711x_prepare_message;
+ master->transfer_one = spi_clps711x_transfer_one;
hw = spi_master_get_devdata(master);
for (i = 0; i < master->num_chipselect; i++) {
- hw->chipselect[i] = pdata->chipselect[i];
- if (!gpio_is_valid(hw->chipselect[i])) {
- dev_err(&pdev->dev, "Invalid CS GPIO %i\n", i);
- ret = -EINVAL;
- goto err_out;
- }
- if (devm_gpio_request(&pdev->dev, hw->chipselect[i], NULL)) {
+ master->cs_gpios[i] = pdata->chipselect[i];
+ ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i],
+ DRIVER_NAME);
+ if (ret) {
dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i);
- ret = -EINVAL;
goto err_out;
}
}
@@ -211,29 +182,45 @@ static int spi_clps711x_probe(struct platform_device *pdev)
ret = PTR_ERR(hw->spi_clk);
goto err_out;
}
- hw->max_speed_hz = clk_get_rate(hw->spi_clk);
+ master->max_speed_hz = clk_get_rate(hw->spi_clk);
- init_completion(&hw->done);
platform_set_drvdata(pdev, master);
+ hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3");
+ if (IS_ERR(hw->syscon)) {
+ ret = PTR_ERR(hw->syscon);
+ goto err_out;
+ }
+
+ hw->syscon1 = syscon_regmap_lookup_by_pdevname("syscon.1");
+ if (IS_ERR(hw->syscon1)) {
+ ret = PTR_ERR(hw->syscon1);
+ goto err_out;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hw->syncio = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hw->syncio)) {
+ ret = PTR_ERR(hw->syncio);
+ goto err_out;
+ }
+
/* Disable extended mode due hardware problems */
- clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCON, SYSCON3);
+ regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCON, 0);
/* Clear possible pending interrupt */
- clps_readl(SYNCIO);
+ readl(hw->syncio);
- ret = devm_request_irq(&pdev->dev, IRQ_SSEOTI, spi_clps711x_isr, 0,
- dev_name(&pdev->dev), hw);
- if (ret) {
- dev_err(&pdev->dev, "Can't request IRQ\n");
+ ret = devm_request_irq(&pdev->dev, irq, spi_clps711x_isr, 0,
+ dev_name(&pdev->dev), master);
+ if (ret)
goto err_out;
- }
ret = devm_spi_register_master(&pdev->dev, master);
if (!ret) {
dev_info(&pdev->dev,
"SPI bus driver initialized. Master clock %u Hz\n",
- hw->max_speed_hz);
+ master->max_speed_hz);
return 0;
}
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
index cabed8f9119e..e2fa628e55e7 100644
--- a/drivers/spi/spi-coldfire-qspi.c
+++ b/drivers/spi/spi-coldfire-qspi.c
@@ -77,8 +77,6 @@ struct mcfqspi {
struct mcfqspi_cs_control *cs_control;
wait_queue_head_t waitq;
-
- struct device *dev;
};
static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val)
@@ -135,13 +133,13 @@ static void mcfqspi_cs_deselect(struct mcfqspi *mcfqspi, u8 chip_select,
static int mcfqspi_cs_setup(struct mcfqspi *mcfqspi)
{
- return (mcfqspi->cs_control && mcfqspi->cs_control->setup) ?
+ return (mcfqspi->cs_control->setup) ?
mcfqspi->cs_control->setup(mcfqspi->cs_control) : 0;
}
static void mcfqspi_cs_teardown(struct mcfqspi *mcfqspi)
{
- if (mcfqspi->cs_control && mcfqspi->cs_control->teardown)
+ if (mcfqspi->cs_control->teardown)
mcfqspi->cs_control->teardown(mcfqspi->cs_control);
}
@@ -300,68 +298,45 @@ static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count,
}
}
-static int mcfqspi_transfer_one_message(struct spi_master *master,
- struct spi_message *msg)
+static void mcfqspi_set_cs(struct spi_device *spi, bool enable)
{
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
- struct spi_device *spi = msg->spi;
- struct spi_transfer *t;
- int status = 0;
-
- list_for_each_entry(t, &msg->transfers, transfer_list) {
- bool cs_high = spi->mode & SPI_CS_HIGH;
- u16 qmr = MCFQSPI_QMR_MSTR;
-
- qmr |= t->bits_per_word << 10;
- if (spi->mode & SPI_CPHA)
- qmr |= MCFQSPI_QMR_CPHA;
- if (spi->mode & SPI_CPOL)
- qmr |= MCFQSPI_QMR_CPOL;
- if (t->speed_hz)
- qmr |= mcfqspi_qmr_baud(t->speed_hz);
- else
- qmr |= mcfqspi_qmr_baud(spi->max_speed_hz);
- mcfqspi_wr_qmr(mcfqspi, qmr);
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(spi->master);
+ bool cs_high = spi->mode & SPI_CS_HIGH;
+ if (enable)
mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
+ else
+ mcfqspi_cs_deselect(mcfqspi, spi->chip_select, cs_high);
+}
- mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
- if (t->bits_per_word == 8)
- mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf,
- t->rx_buf);
- else
- mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
- t->rx_buf);
- mcfqspi_wr_qir(mcfqspi, 0);
-
- if (t->delay_usecs)
- udelay(t->delay_usecs);
- if (t->cs_change) {
- if (!list_is_last(&t->transfer_list, &msg->transfers))
- mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
- cs_high);
- } else {
- if (list_is_last(&t->transfer_list, &msg->transfers))
- mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
- cs_high);
- }
- msg->actual_length += t->len;
- }
- msg->status = status;
- spi_finalize_current_message(master);
-
- return status;
+static int mcfqspi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ u16 qmr = MCFQSPI_QMR_MSTR;
+
+ qmr |= t->bits_per_word << 10;
+ if (spi->mode & SPI_CPHA)
+ qmr |= MCFQSPI_QMR_CPHA;
+ if (spi->mode & SPI_CPOL)
+ qmr |= MCFQSPI_QMR_CPOL;
+ qmr |= mcfqspi_qmr_baud(t->speed_hz);
+ mcfqspi_wr_qmr(mcfqspi, qmr);
+
+ mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
+ if (t->bits_per_word == 8)
+ mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf, t->rx_buf);
+ else
+ mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
+ t->rx_buf);
+ mcfqspi_wr_qir(mcfqspi, 0);
+ return 0;
}
static int mcfqspi_setup(struct spi_device *spi)
{
- if (spi->chip_select >= spi->master->num_chipselect) {
- dev_dbg(&spi->dev, "%d chip select is out of range\n",
- spi->chip_select);
- return -EINVAL;
- }
-
mcfqspi_cs_deselect(spi_master_get_devdata(spi->master),
spi->chip_select, spi->mode & SPI_CS_HIGH);
@@ -388,6 +363,11 @@ static int mcfqspi_probe(struct platform_device *pdev)
return -ENOENT;
}
+ if (!pdata->cs_control) {
+ dev_dbg(&pdev->dev, "pdata->cs_control is NULL\n");
+ return -EINVAL;
+ }
+
master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
if (master == NULL) {
dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
@@ -436,12 +416,12 @@ static int mcfqspi_probe(struct platform_device *pdev)
}
init_waitqueue_head(&mcfqspi->waitq);
- mcfqspi->dev = &pdev->dev;
master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
master->setup = mcfqspi_setup;
- master->transfer_one_message = mcfqspi_transfer_one_message;
+ master->set_cs = mcfqspi_set_cs;
+ master->transfer_one = mcfqspi_transfer_one;
master->auto_runtime_pm = true;
platform_set_drvdata(pdev, master);
@@ -451,7 +431,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "spi_register_master failed\n");
goto fail2;
}
- pm_runtime_enable(mcfqspi->dev);
+ pm_runtime_enable(&pdev->dev);
dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");
@@ -473,9 +453,8 @@ static int mcfqspi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- pm_runtime_disable(mcfqspi->dev);
+ pm_runtime_disable(&pdev->dev);
/* disable the hardware (set the baud rate to 0) */
mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
@@ -490,8 +469,11 @@ static int mcfqspi_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ int ret;
- spi_master_suspend(master);
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
clk_disable(mcfqspi->clk);
@@ -503,18 +485,17 @@ static int mcfqspi_resume(struct device *dev)
struct spi_master *master = dev_get_drvdata(dev);
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
- spi_master_resume(master);
-
clk_enable(mcfqspi->clk);
- return 0;
+ return spi_master_resume(master);
}
#endif
#ifdef CONFIG_PM_RUNTIME
static int mcfqspi_runtime_suspend(struct device *dev)
{
- struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
clk_disable(mcfqspi->clk);
@@ -523,7 +504,8 @@ static int mcfqspi_runtime_suspend(struct device *dev)
static int mcfqspi_runtime_resume(struct device *dev)
{
- struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
clk_enable(mcfqspi->clk);
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 5e7389faa2a0..50f750989258 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -802,8 +802,7 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
pdata = &dspi->pdata;
pdata->version = SPI_VERSION_1;
- match = of_match_device(of_match_ptr(davinci_spi_of_match),
- &pdev->dev);
+ match = of_match_device(davinci_spi_of_match, &pdev->dev);
if (!match)
return -ENODEV;
@@ -824,7 +823,6 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
return 0;
}
#else
-#define davinci_spi_of_match NULL
static struct davinci_spi_platform_data
*spi_davinci_get_pdata(struct platform_device *pdev,
struct davinci_spi *dspi)
@@ -864,10 +862,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
dspi = spi_master_get_devdata(master);
- if (dspi == NULL) {
- ret = -ENOENT;
- goto free_master;
- }
if (dev_get_platdata(&pdev->dev)) {
pdata = dev_get_platdata(&pdev->dev);
@@ -908,10 +902,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
goto free_master;
dspi->bitbang.master = master;
- if (dspi->bitbang.master == NULL) {
- ret = -ENODEV;
- goto free_master;
- }
dspi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dspi->clk)) {
@@ -1040,7 +1030,7 @@ static struct platform_driver davinci_spi_driver = {
.driver = {
.name = "spi_davinci",
.owner = THIS_MODULE,
- .of_match_table = davinci_spi_of_match,
+ .of_match_table = of_match_ptr(davinci_spi_of_match),
},
.probe = davinci_spi_probe,
.remove = davinci_spi_remove,
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index 9af56cdf1540..1492f5ee9aaa 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -66,7 +66,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
if (ret)
return ret;
- dws->bus_num = 0;
+ dws->bus_num = pdev->id;
dws->num_cs = 4;
dws->max_freq = clk_get_rate(dwsmmio->clk);
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index bf98d63d92b3..712ac5629cd4 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -276,8 +276,7 @@ static void giveback(struct dw_spi *dws)
queue_work(dws->workqueue, &dws->pump_messages);
spin_unlock_irqrestore(&dws->lock, flags);
- last_transfer = list_entry(msg->transfers.prev,
- struct spi_transfer,
+ last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
transfer_list);
if (!last_transfer->cs_change && dws->cs_control)
@@ -439,12 +438,6 @@ static void pump_transfers(unsigned long data)
if (transfer->speed_hz != speed) {
speed = transfer->speed_hz;
- if (speed > dws->max_freq) {
- printk(KERN_ERR "MRST SPI0: unsupported"
- "freq: %dHz\n", speed);
- message->status = -EIO;
- goto early_exit;
- }
/* clk_div doesn't support odd number */
clk_div = dws->max_freq / speed;
@@ -671,12 +664,6 @@ static int dw_spi_setup(struct spi_device *spi)
return 0;
}
-static void dw_spi_cleanup(struct spi_device *spi)
-{
- struct chip_data *chip = spi_get_ctldata(spi);
- kfree(chip);
-}
-
static int init_queue(struct dw_spi *dws)
{
INIT_LIST_HEAD(&dws->queue);
@@ -806,9 +793,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->bus_num = dws->bus_num;
master->num_chipselect = dws->num_cs;
- master->cleanup = dw_spi_cleanup;
master->setup = dw_spi_setup;
master->transfer = dw_spi_transfer;
+ master->max_speed_hz = dws->max_freq;
/* Basic HW init */
spi_hw_init(dws);
diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c
index d4d3cc534792..be44a3eeb5e8 100644
--- a/drivers/spi/spi-efm32.c
+++ b/drivers/spi/spi-efm32.c
@@ -198,7 +198,7 @@ static int efm32_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
efm32_spi_filltx(ddata);
- init_completion(&ddata->done);
+ reinit_completion(&ddata->done);
efm32_spi_write32(ddata, REG_IF_TXBL | REG_IF_RXDATAV, REG_IEN);
@@ -287,17 +287,17 @@ static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata)
return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK);
}
-static int efm32_spi_probe_dt(struct platform_device *pdev,
+static void efm32_spi_probe_dt(struct platform_device *pdev,
struct spi_master *master, struct efm32_spi_ddata *ddata)
{
struct device_node *np = pdev->dev.of_node;
u32 location;
int ret;
- if (!np)
- return 1;
-
- ret = of_property_read_u32(np, "location", &location);
+ ret = of_property_read_u32(np, "efm32,location", &location);
+ if (ret)
+ /* fall back to old and (wrongly) generic property "location" */
+ ret = of_property_read_u32(np, "location", &location);
if (!ret) {
dev_dbg(&pdev->dev, "using location %u\n", location);
} else {
@@ -308,11 +308,6 @@ static int efm32_spi_probe_dt(struct platform_device *pdev,
}
ddata->pdata.location = location;
-
- /* spi core takes care about the bus number using an alias */
- master->bus_num = -1;
-
- return 0;
}
static int efm32_spi_probe(struct platform_device *pdev)
@@ -322,9 +317,14 @@ static int efm32_spi_probe(struct platform_device *pdev)
int ret;
struct spi_master *master;
struct device_node *np = pdev->dev.of_node;
- unsigned int num_cs, i;
+ int num_cs, i;
+
+ if (!np)
+ return -EINVAL;
num_cs = of_gpio_named_count(np, "cs-gpios");
+ if (num_cs < 0)
+ return num_cs;
master = spi_alloc_master(&pdev->dev,
sizeof(*ddata) + num_cs * sizeof(unsigned));
@@ -349,6 +349,7 @@ static int efm32_spi_probe(struct platform_device *pdev)
ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs;
spin_lock_init(&ddata->lock);
+ init_completion(&ddata->done);
ddata->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ddata->clk)) {
@@ -415,23 +416,7 @@ static int efm32_spi_probe(struct platform_device *pdev)
goto err;
}
- ret = efm32_spi_probe_dt(pdev, master, ddata);
- if (ret > 0) {
- /* not created by device tree */
- const struct efm32_spi_pdata *pdata =
- dev_get_platdata(&pdev->dev);
-
- if (pdata)
- ddata->pdata = *pdata;
- else
- ddata->pdata.location =
- efm32_spi_get_configured_location(ddata);
-
- master->bus_num = pdev->id;
-
- } else if (ret < 0) {
- goto err_disable_clk;
- }
+ efm32_spi_probe_dt(pdev, master, ddata);
efm32_spi_write32(ddata, 0, REG_IEN);
efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN |
@@ -487,6 +472,9 @@ static int efm32_spi_remove(struct platform_device *pdev)
static const struct of_device_id efm32_spi_dt_ids[] = {
{
+ .compatible = "energymicro,efm32-spi",
+ }, {
+ /* doesn't follow the "vendor,device" scheme, don't use */
.compatible = "efm32,spi",
}, {
/* sentinel */
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index 1bfaed6e4073..2f675d32df0e 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -73,8 +73,6 @@
* @clk: clock for the controller
* @regs_base: pointer to ioremap()'d registers
* @sspdr_phys: physical address of the SSPDR register
- * @min_rate: minimum clock rate (in Hz) supported by the controller
- * @max_rate: maximum clock rate (in Hz) supported by the controller
* @wait: wait here until given transfer is completed
* @current_msg: message that is currently processed (or %NULL if none)
* @tx: current byte in transfer to transmit
@@ -95,8 +93,6 @@ struct ep93xx_spi {
struct clk *clk;
void __iomem *regs_base;
unsigned long sspdr_phys;
- unsigned long min_rate;
- unsigned long max_rate;
struct completion wait;
struct spi_message *current_msg;
size_t tx;
@@ -199,9 +195,9 @@ static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
* @div_scr: pointer to return the scr divider
*/
static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
- unsigned long rate,
- u8 *div_cpsr, u8 *div_scr)
+ u32 rate, u8 *div_cpsr, u8 *div_scr)
{
+ struct spi_master *master = platform_get_drvdata(espi->pdev);
unsigned long spi_clk_rate = clk_get_rate(espi->clk);
int cpsr, scr;
@@ -210,7 +206,7 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
* controller. Note that minimum value is already checked in
* ep93xx_spi_transfer_one_message().
*/
- rate = clamp(rate, espi->min_rate, espi->max_rate);
+ rate = clamp(rate, master->min_speed_hz, master->max_speed_hz);
/*
* Calculate divisors so that we can get speed according the
@@ -735,13 +731,6 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
struct ep93xx_spi *espi = spi_master_get_devdata(master);
- struct spi_transfer *t;
-
- /* first validate each transfer */
- list_for_each_entry(t, &msg->transfers, transfer_list) {
- if (t->speed_hz < espi->min_rate)
- return -EINVAL;
- }
msg->state = NULL;
msg->status = 0;
@@ -917,8 +906,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
* Calculate maximum and minimum supported clock rates
* for the controller.
*/
- espi->max_rate = clk_get_rate(espi->clk) / 2;
- espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
+ master->max_speed_hz = clk_get_rate(espi->clk) / 2;
+ master->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256);
espi->pdev = pdev;
espi->sspdr_phys = res->start + SSPDR;
diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c
index dd5bd468e962..09965f069a1c 100644
--- a/drivers/spi/spi-falcon.c
+++ b/drivers/spi/spi-falcon.c
@@ -312,9 +312,6 @@ static int falcon_sflash_setup(struct spi_device *spi)
unsigned int i;
unsigned long flags;
- if (spi->chip_select > 0)
- return -ENODEV;
-
spin_lock_irqsave(&ebu_lock, flags);
if (spi->max_speed_hz >= CLOCK_100M) {
@@ -422,9 +419,7 @@ static int falcon_sflash_probe(struct platform_device *pdev)
priv->master = master;
master->mode_bits = SPI_MODE_3;
- master->num_chipselect = 1;
master->flags = SPI_MASTER_HALF_DUPLEX;
- master->bus_num = -1;
master->setup = falcon_sflash_setup;
master->prepare_transfer_hardware = falcon_sflash_prepare_xfer;
master->transfer_one_message = falcon_sflash_xfer_one;
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index ec79f726672a..d565eeee3bd8 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/io.h>
@@ -108,11 +109,11 @@ struct fsl_dspi {
struct spi_bitbang bitbang;
struct platform_device *pdev;
- void __iomem *base;
+ struct regmap *regmap;
int irq;
- struct clk *clk;
+ struct clk *clk;
- struct spi_transfer *cur_transfer;
+ struct spi_transfer *cur_transfer;
struct chip_data *cur_chip;
size_t len;
void *tx;
@@ -123,24 +124,17 @@ struct fsl_dspi {
u8 cs;
u16 void_write_data;
- wait_queue_head_t waitq;
- u32 waitflags;
+ wait_queue_head_t waitq;
+ u32 waitflags;
};
static inline int is_double_byte_mode(struct fsl_dspi *dspi)
{
- return ((readl(dspi->base + SPI_CTAR(dspi->cs)) & SPI_FRAME_BITS_MASK)
- == SPI_FRAME_BITS(8)) ? 0 : 1;
-}
+ unsigned int val;
-static void set_bit_mode(struct fsl_dspi *dspi, unsigned char bits)
-{
- u32 temp;
+ regmap_read(dspi->regmap, SPI_CTAR(dspi->cs), &val);
- temp = readl(dspi->base + SPI_CTAR(dspi->cs));
- temp &= ~SPI_FRAME_BITS_MASK;
- temp |= SPI_FRAME_BITS(bits);
- writel(temp, dspi->base + SPI_CTAR(dspi->cs));
+ return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
}
static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
@@ -188,7 +182,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
*/
if (tx_word && (dspi->len == 1)) {
dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
- set_bit_mode(dspi, 8);
+ regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
+ SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
tx_word = 0;
}
@@ -238,7 +233,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */
}
- writel(dspi_pushr, dspi->base + SPI_PUSHR);
+ regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
+
tx_count++;
}
@@ -253,17 +249,23 @@ static int dspi_transfer_read(struct fsl_dspi *dspi)
while ((dspi->rx < dspi->rx_end)
&& (rx_count < DSPI_FIFO_SIZE)) {
if (rx_word) {
+ unsigned int val;
+
if ((dspi->rx_end - dspi->rx) == 1)
break;
- d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
+ regmap_read(dspi->regmap, SPI_POPR, &val);
+ d = SPI_POPR_RXDATA(val);
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
*(u16 *)dspi->rx = d;
dspi->rx += 2;
} else {
- d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
+ unsigned int val;
+
+ regmap_read(dspi->regmap, SPI_POPR, &val);
+ d = SPI_POPR_RXDATA(val);
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
*(u8 *)dspi->rx = d;
dspi->rx++;
@@ -295,13 +297,13 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
if (!dspi->tx)
dspi->dataflags |= TRAN_STATE_TX_VOID;
- writel(dspi->cur_chip->mcr_val, dspi->base + SPI_MCR);
- writel(dspi->cur_chip->ctar_val, dspi->base + SPI_CTAR(dspi->cs));
- writel(SPI_RSER_EOQFE, dspi->base + SPI_RSER);
+ regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
+ regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val);
+ regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE);
if (t->speed_hz)
- writel(dspi->cur_chip->ctar_val,
- dspi->base + SPI_CTAR(dspi->cs));
+ regmap_write(dspi->regmap, SPI_CTAR(dspi->cs),
+ dspi->cur_chip->ctar_val);
dspi_transfer_write(dspi);
@@ -315,7 +317,9 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
static void dspi_chipselect(struct spi_device *spi, int value)
{
struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
- u32 pushr = readl(dspi->base + SPI_PUSHR);
+ unsigned int pushr;
+
+ regmap_read(dspi->regmap, SPI_PUSHR, &pushr);
switch (value) {
case BITBANG_CS_ACTIVE:
@@ -326,7 +330,7 @@ static void dspi_chipselect(struct spi_device *spi, int value)
break;
}
- writel(pushr, dspi->base + SPI_PUSHR);
+ regmap_write(dspi->regmap, SPI_PUSHR, pushr);
}
static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
@@ -338,7 +342,8 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
/* Only alloc on first setup */
chip = spi_get_ctldata(spi);
if (chip == NULL) {
- chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL);
+ chip = devm_kzalloc(&spi->dev, sizeof(struct chip_data),
+ GFP_KERNEL);
if (!chip)
return -ENOMEM;
}
@@ -349,7 +354,6 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
fmsz = spi->bits_per_word - 1;
} else {
pr_err("Invalid wordsize\n");
- kfree(chip);
return -ENODEV;
}
@@ -382,13 +386,15 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
{
struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
- writel(SPI_SR_EOQF, dspi->base + SPI_SR);
+ regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF);
dspi_transfer_read(dspi);
if (!dspi->len) {
if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
- set_bit_mode(dspi, 16);
+ regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
+ SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16));
+
dspi->waitflags = 1;
wake_up_interruptible(&dspi->waitq);
} else {
@@ -420,7 +426,6 @@ static int dspi_suspend(struct device *dev)
static int dspi_resume(struct device *dev)
{
-
struct spi_master *master = dev_get_drvdata(dev);
struct fsl_dspi *dspi = spi_master_get_devdata(master);
@@ -431,8 +436,13 @@ static int dspi_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-static const struct dev_pm_ops dspi_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume)
+static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
+
+static struct regmap_config dspi_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x88,
};
static int dspi_probe(struct platform_device *pdev)
@@ -441,6 +451,7 @@ static int dspi_probe(struct platform_device *pdev)
struct spi_master *master;
struct fsl_dspi *dspi;
struct resource *res;
+ void __iomem *base;
int ret = 0, cs_num, bus_num;
master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
@@ -475,12 +486,24 @@ static int dspi_probe(struct platform_device *pdev)
master->bus_num = bus_num;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dspi->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(dspi->base)) {
- ret = PTR_ERR(dspi->base);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base)) {
+ ret = PTR_ERR(base);
goto out_master_put;
}
+ dspi_regmap_config.lock_arg = dspi;
+ dspi_regmap_config.val_format_endian =
+ of_property_read_bool(np, "big-endian")
+ ? REGMAP_ENDIAN_BIG : REGMAP_ENDIAN_DEFAULT;
+ dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base,
+ &dspi_regmap_config);
+ if (IS_ERR(dspi->regmap)) {
+ dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+ PTR_ERR(dspi->regmap));
+ return PTR_ERR(dspi->regmap);
+ }
+
dspi->irq = platform_get_irq(pdev, 0);
if (dspi->irq < 0) {
dev_err(&pdev->dev, "can't get platform irq\n");
@@ -504,7 +527,7 @@ static int dspi_probe(struct platform_device *pdev)
clk_prepare_enable(dspi->clk);
init_waitqueue_head(&dspi->waitq);
- platform_set_drvdata(pdev, dspi);
+ platform_set_drvdata(pdev, master);
ret = spi_bitbang_start(&dspi->bitbang);
if (ret != 0) {
@@ -525,7 +548,8 @@ out_master_put:
static int dspi_remove(struct platform_device *pdev)
{
- struct fsl_dspi *dspi = platform_get_drvdata(pdev);
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct fsl_dspi *dspi = spi_master_get_devdata(master);
/* Disconnect from the SPI framework */
spi_bitbang_stop(&dspi->bitbang);
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 428dc7a6b62e..6fb2b75df821 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -219,13 +219,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
unsigned int len = t->len;
- u8 bits_per_word;
int ret;
- bits_per_word = spi->bits_per_word;
- if (t->bits_per_word)
- bits_per_word = t->bits_per_word;
-
mpc8xxx_spi->len = t->len;
len = roundup(len, 4) / 4;
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c
index 0b75f26158ab..e5d45fca3551 100644
--- a/drivers/spi/spi-fsl-lib.c
+++ b/drivers/spi/spi-fsl-lib.c
@@ -200,7 +200,7 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
const void *prop;
int ret = -ENOMEM;
- pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
+ pinfo = devm_kzalloc(&ofdev->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
return -ENOMEM;
@@ -215,15 +215,13 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
pdata->sysclk = get_brgfreq();
if (pdata->sysclk == -1) {
pdata->sysclk = fsl_get_sys_freq();
- if (pdata->sysclk == -1) {
- ret = -ENODEV;
- goto err;
- }
+ if (pdata->sysclk == -1)
+ return -ENODEV;
}
#else
ret = of_property_read_u32(np, "clock-frequency", &pdata->sysclk);
if (ret)
- goto err;
+ return ret;
#endif
prop = of_get_property(np, "mode", NULL);
@@ -237,8 +235,4 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
pdata->flags = SPI_CPM_MODE | SPI_CPM1;
return 0;
-
-err:
- kfree(pinfo);
- return ret;
}
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 119f7af94537..f35488ed62a9 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -239,12 +239,6 @@ static int fsl_spi_setup_transfer(struct spi_device *spi,
if (!bits_per_word)
bits_per_word = spi->bits_per_word;
- /* Make sure its a bit width we support [4..16, 32] */
- if ((bits_per_word < 4)
- || ((bits_per_word > 16) && (bits_per_word != 32))
- || (bits_per_word > mpc8xxx_spi->max_bits_per_word))
- return -EINVAL;
-
if (!hz)
hz = spi->max_speed_hz;
@@ -362,18 +356,28 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
static void fsl_spi_do_one_msg(struct spi_message *m)
{
struct spi_device *spi = m->spi;
- struct spi_transfer *t;
+ struct spi_transfer *t, *first;
unsigned int cs_change;
const int nsecs = 50;
int status;
- cs_change = 1;
- status = 0;
+ /* Don't allow changes if CS is active */
+ first = list_first_entry(&m->transfers, struct spi_transfer,
+ transfer_list);
list_for_each_entry(t, &m->transfers, transfer_list) {
- if (t->bits_per_word || t->speed_hz) {
- /* Don't allow changes if CS is active */
+ if ((first->bits_per_word != t->bits_per_word) ||
+ (first->speed_hz != t->speed_hz)) {
status = -EINVAL;
+ dev_err(&spi->dev,
+ "bits_per_word/speed_hz should be same for the same SPI transfer\n");
+ return;
+ }
+ }
+ cs_change = 1;
+ status = -EINVAL;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->bits_per_word || t->speed_hz) {
if (cs_change)
status = fsl_spi_setup_transfer(spi, t);
if (status < 0)
@@ -641,6 +645,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
if (mpc8xxx_spi->type == TYPE_GRLIB)
fsl_spi_grlib_probe(dev);
+ master->bits_per_word_mask =
+ (SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32)) &
+ SPI_BPW_RANGE_MASK(1, mpc8xxx_spi->max_bits_per_word);
+
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts;
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index 7beeb29472ac..09823076df88 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -19,7 +19,6 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
@@ -250,7 +249,7 @@ static int spi_gpio_setup(struct spi_device *spi)
/*
* ... otherwise, take it from spi->controller_data
*/
- cs = (unsigned int) spi->controller_data;
+ cs = (unsigned int)(uintptr_t) spi->controller_data;
}
if (!spi->controller_state) {
@@ -503,13 +502,12 @@ static int spi_gpio_remove(struct platform_device *pdev)
{
struct spi_gpio *spi_gpio;
struct spi_gpio_platform_data *pdata;
- int status;
spi_gpio = platform_get_drvdata(pdev);
pdata = dev_get_platdata(&pdev->dev);
/* stop() unregisters child devices too */
- status = spi_bitbang_stop(&spi_gpio->bitbang);
+ spi_bitbang_stop(&spi_gpio->bitbang);
if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
gpio_free(SPI_MISO_GPIO);
@@ -518,7 +516,7 @@ static int spi_gpio_remove(struct platform_device *pdev)
gpio_free(SPI_SCK_GPIO);
spi_master_put(spi_gpio->bitbang.master);
- return status;
+ return 0;
}
MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index a5474ef9d2a0..5daff2054ae4 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -23,7 +23,6 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -741,7 +740,7 @@ static int spi_imx_transfer(struct spi_device *spi,
spi_imx->count = transfer->len;
spi_imx->txfifo = 0;
- init_completion(&spi_imx->xfer_done);
+ reinit_completion(&spi_imx->xfer_done);
spi_imx_push(spi_imx);
@@ -880,12 +879,12 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->irq = platform_get_irq(pdev, 0);
if (spi_imx->irq < 0) {
- ret = -EINVAL;
+ ret = spi_imx->irq;
goto out_master_put;
}
ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0,
- DRIVER_NAME, spi_imx);
+ dev_name(&pdev->dev), spi_imx);
if (ret) {
dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret);
goto out_master_put;
@@ -948,8 +947,8 @@ static int spi_imx_remove(struct platform_device *pdev)
spi_bitbang_stop(&spi_imx->bitbang);
writel(0, spi_imx->base + MXC_CSPICTRL);
- clk_disable_unprepare(spi_imx->clk_ipg);
- clk_disable_unprepare(spi_imx->clk_per);
+ clk_unprepare(spi_imx->clk_ipg);
+ clk_unprepare(spi_imx->clk_per);
spi_master_put(master);
return 0;
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 5032141eeeec..3822eef2ef9d 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/of_address.h>
@@ -466,10 +465,8 @@ static void mpc512x_spi_cs_control(struct spi_device *spi, bool onoff)
gpio_set_value(spi->cs_gpio, onoff);
}
-/* bus_num is used only for the case dev->platform_data == NULL */
static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
- u32 size, unsigned int irq,
- s16 bus_num)
+ u32 size, unsigned int irq)
{
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct mpc512x_psc_spi *mps;
@@ -488,7 +485,6 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
if (pdata == NULL) {
mps->cs_control = mpc512x_spi_cs_control;
- master->bus_num = bus_num;
} else {
mps->cs_control = pdata->cs_control;
master->bus_num = pdata->bus_num;
@@ -574,7 +570,6 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op)
{
const u32 *regaddr_p;
u64 regaddr64, size64;
- s16 id = -1;
regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL);
if (!regaddr_p) {
@@ -583,16 +578,8 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op)
}
regaddr64 = of_translate_address(op->dev.of_node, regaddr_p);
- /* get PSC id (0..11, used by port_config) */
- id = of_alias_get_id(op->dev.of_node, "spi");
- if (id < 0) {
- dev_err(&op->dev, "no alias id for %s\n",
- op->dev.of_node->full_name);
- return id;
- }
-
return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64,
- irq_of_parse_and_map(op->dev.of_node, 0), id);
+ irq_of_parse_and_map(op->dev.of_node, 0));
}
static int mpc512x_psc_spi_of_remove(struct platform_device *op)
diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c
index 00ba910ab302..3d18d9351185 100644
--- a/drivers/spi/spi-mpc52xx-psc.c
+++ b/drivers/spi/spi-mpc52xx-psc.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c
index 7c675fe83101..aac2a5ddd964 100644
--- a/drivers/spi/spi-mpc52xx.c
+++ b/drivers/spi/spi-mpc52xx.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/errno.h>
#include <linux/of_platform.h>
#include <linux/interrupt.h>
@@ -357,20 +356,6 @@ static void mpc52xx_spi_wq(struct work_struct *work)
* spi_master ops
*/
-static int mpc52xx_spi_setup(struct spi_device *spi)
-{
- if (spi->bits_per_word % 8)
- return -EINVAL;
-
- if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST))
- return -EINVAL;
-
- if (spi->chip_select >= spi->master->num_chipselect)
- return -EINVAL;
-
- return 0;
-}
-
static int mpc52xx_spi_transfer(struct spi_device *spi, struct spi_message *m)
{
struct mpc52xx_spi *ms = spi_master_get_devdata(spi->master);
@@ -433,9 +418,9 @@ static int mpc52xx_spi_probe(struct platform_device *op)
goto err_alloc;
}
- master->setup = mpc52xx_spi_setup;
master->transfer = mpc52xx_spi_transfer;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
master->dev.of_node = op->dev.of_node;
platform_set_drvdata(op, master);
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index 79e5aa2250c8..2884f0c2f5f0 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -29,7 +29,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -371,7 +370,7 @@ static int mxs_spi_transfer_one(struct spi_master *master,
{
struct mxs_spi *spi = spi_master_get_devdata(master);
struct mxs_ssp *ssp = &spi->ssp;
- struct spi_transfer *t, *tmp_t;
+ struct spi_transfer *t;
unsigned int flag;
int status = 0;
@@ -381,7 +380,7 @@ static int mxs_spi_transfer_one(struct spi_master *master,
writel(mxs_spi_cs_to_reg(m->spi->chip_select),
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
- list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) {
+ list_for_each_entry(t, &m->transfers, transfer_list) {
status = mxs_spi_setup_transfer(m->spi, t);
if (status)
@@ -473,7 +472,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq_err = platform_get_irq(pdev, 0);
if (irq_err < 0)
- return -EINVAL;
+ return irq_err;
base = devm_ioremap_resource(&pdev->dev, iores);
if (IS_ERR(base))
diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c
index bae97ffec4b9..16e30de650b0 100644
--- a/drivers/spi/spi-nuc900.c
+++ b/drivers/spi/spi-nuc900.c
@@ -9,7 +9,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
@@ -38,7 +37,9 @@
/* usi register bit */
#define ENINT (0x01 << 17)
#define ENFLG (0x01 << 16)
+#define SLEEP (0x0f << 12)
#define TXNUM (0x03 << 8)
+#define TXBITLEN (0x1f << 3)
#define TXNEG (0x01 << 2)
#define RXNEG (0x01 << 1)
#define LSB (0x01 << 10)
@@ -58,11 +59,8 @@ struct nuc900_spi {
unsigned char *rx;
struct clk *clk;
struct spi_master *master;
- struct spi_device *curdev;
- struct device *dev;
struct nuc900_spi_info *pdata;
spinlock_t lock;
- struct resource *res;
};
static inline struct nuc900_spi *to_hw(struct spi_device *sdev)
@@ -119,19 +117,16 @@ static void nuc900_spi_chipsel(struct spi_device *spi, int value)
}
}
-static void nuc900_spi_setup_txnum(struct nuc900_spi *hw,
- unsigned int txnum)
+static void nuc900_spi_setup_txnum(struct nuc900_spi *hw, unsigned int txnum)
{
unsigned int val;
unsigned long flags;
spin_lock_irqsave(&hw->lock, flags);
- val = __raw_readl(hw->regs + USI_CNT);
+ val = __raw_readl(hw->regs + USI_CNT) & ~TXNUM;
- if (!txnum)
- val &= ~TXNUM;
- else
+ if (txnum)
val |= txnum << 0x08;
__raw_writel(val, hw->regs + USI_CNT);
@@ -148,7 +143,7 @@ static void nuc900_spi_setup_txbitlen(struct nuc900_spi *hw,
spin_lock_irqsave(&hw->lock, flags);
- val = __raw_readl(hw->regs + USI_CNT);
+ val = __raw_readl(hw->regs + USI_CNT) & ~TXBITLEN;
val |= (txbitlen << 0x03);
@@ -287,12 +282,11 @@ static void nuc900_set_sleep(struct nuc900_spi *hw, unsigned int sleep)
spin_lock_irqsave(&hw->lock, flags);
- val = __raw_readl(hw->regs + USI_CNT);
+ val = __raw_readl(hw->regs + USI_CNT) & ~SLEEP;
if (sleep)
val |= (sleep << 12);
- else
- val &= ~(0x0f << 12);
+
__raw_writel(val, hw->regs + USI_CNT);
spin_unlock_irqrestore(&hw->lock, flags);
@@ -338,6 +332,7 @@ static int nuc900_spi_probe(struct platform_device *pdev)
{
struct nuc900_spi *hw;
struct spi_master *master;
+ struct resource *res;
int err = 0;
master = spi_alloc_master(&pdev->dev, sizeof(struct nuc900_spi));
@@ -349,7 +344,6 @@ static int nuc900_spi_probe(struct platform_device *pdev)
hw = spi_master_get_devdata(master);
hw->master = master;
hw->pdata = dev_get_platdata(&pdev->dev);
- hw->dev = &pdev->dev;
if (hw->pdata == NULL) {
dev_err(&pdev->dev, "No platform data supplied\n");
@@ -369,8 +363,8 @@ static int nuc900_spi_probe(struct platform_device *pdev)
hw->bitbang.chipselect = nuc900_spi_chipsel;
hw->bitbang.txrx_bufs = nuc900_spi_txrx;
- hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hw->regs = devm_ioremap_resource(&pdev->dev, hw->res);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hw->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hw->regs)) {
err = PTR_ERR(hw->regs);
goto err_pdata;
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index f7c896e2981e..8998d11c7238 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -15,7 +15,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -267,8 +266,6 @@ static int tiny_spi_probe(struct platform_device *pdev)
/* setup the state for the bitbang driver */
hw->bitbang.master = master;
- if (!hw->bitbang.master)
- return err;
hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
hw->bitbang.chipselect = tiny_spi_chipselect;
hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c
index 67249a48b391..c5e2f718eebd 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-octeon.c
@@ -11,7 +11,6 @@
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -33,13 +32,6 @@ struct octeon_spi {
u64 cs_enax;
};
-struct octeon_spi_setup {
- u32 max_speed_hz;
- u8 chip_select;
- u8 mode;
- u8 bits_per_word;
-};
-
static void octeon_spi_wait_ready(struct octeon_spi *p)
{
union cvmx_mpi_sts mpi_sts;
@@ -57,6 +49,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
struct spi_transfer *xfer,
bool last_xfer)
{
+ struct spi_device *spi = msg->spi;
union cvmx_mpi_cfg mpi_cfg;
union cvmx_mpi_tx mpi_tx;
unsigned int clkdiv;
@@ -68,18 +61,11 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
int len;
int i;
- struct octeon_spi_setup *msg_setup = spi_get_ctldata(msg->spi);
-
- speed_hz = msg_setup->max_speed_hz;
- mode = msg_setup->mode;
+ mode = spi->mode;
cpha = mode & SPI_CPHA;
cpol = mode & SPI_CPOL;
- if (xfer->speed_hz)
- speed_hz = xfer->speed_hz;
-
- if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ)
- speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+ speed_hz = xfer->speed_hz ? : spi->max_speed_hz;
clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz);
@@ -93,8 +79,8 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
mpi_cfg.s.cslate = cpha ? 1 : 0;
mpi_cfg.s.enable = 1;
- if (msg_setup->chip_select < 4)
- p->cs_enax |= 1ull << (12 + msg_setup->chip_select);
+ if (spi->chip_select < 4)
+ p->cs_enax |= 1ull << (12 + spi->chip_select);
mpi_cfg.u64 |= p->cs_enax;
if (mpi_cfg.u64 != p->last_cfg) {
@@ -114,7 +100,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d);
}
mpi_tx.u64 = 0;
- mpi_tx.s.csid = msg_setup->chip_select;
+ mpi_tx.s.csid = spi->chip_select;
mpi_tx.s.leavecs = 1;
mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0;
mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES;
@@ -139,7 +125,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
}
mpi_tx.u64 = 0;
- mpi_tx.s.csid = msg_setup->chip_select;
+ mpi_tx.s.csid = spi->chip_select;
if (last_xfer)
mpi_tx.s.leavecs = xfer->cs_change;
else
@@ -169,17 +155,9 @@ static int octeon_spi_transfer_one_message(struct spi_master *master,
int status = 0;
struct spi_transfer *xfer;
- /*
- * We better have set the configuration via a call to .setup
- * before we get here.
- */
- if (spi_get_ctldata(msg->spi) == NULL) {
- status = -EINVAL;
- goto err;
- }
-
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- bool last_xfer = &xfer->transfer_list == msg->transfers.prev;
+ bool last_xfer = list_is_last(&xfer->transfer_list,
+ &msg->transfers);
int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer);
if (r < 0) {
status = r;
@@ -194,41 +172,6 @@ err:
return status;
}
-static struct octeon_spi_setup *octeon_spi_new_setup(struct spi_device *spi)
-{
- struct octeon_spi_setup *setup = kzalloc(sizeof(*setup), GFP_KERNEL);
- if (!setup)
- return NULL;
-
- setup->max_speed_hz = spi->max_speed_hz;
- setup->chip_select = spi->chip_select;
- setup->mode = spi->mode;
- setup->bits_per_word = spi->bits_per_word;
- return setup;
-}
-
-static int octeon_spi_setup(struct spi_device *spi)
-{
- struct octeon_spi_setup *new_setup;
- struct octeon_spi_setup *old_setup = spi_get_ctldata(spi);
-
- new_setup = octeon_spi_new_setup(spi);
- if (!new_setup)
- return -ENOMEM;
-
- spi_set_ctldata(spi, new_setup);
- kfree(old_setup);
-
- return 0;
-}
-
-static void octeon_spi_cleanup(struct spi_device *spi)
-{
- struct octeon_spi_setup *old_setup = spi_get_ctldata(spi);
- spi_set_ctldata(spi, NULL);
- kfree(old_setup);
-}
-
static int octeon_spi_probe(struct platform_device *pdev)
{
struct resource *res_mem;
@@ -257,8 +200,6 @@ static int octeon_spi_probe(struct platform_device *pdev)
p->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start,
resource_size(res_mem));
- /* Dynamic bus numbering */
- master->bus_num = -1;
master->num_chipselect = 4;
master->mode_bits = SPI_CPHA |
SPI_CPOL |
@@ -266,10 +207,9 @@ static int octeon_spi_probe(struct platform_device *pdev)
SPI_LSB_FIRST |
SPI_3WIRE;
- master->setup = octeon_spi_setup;
- master->cleanup = octeon_spi_cleanup;
master->transfer_one_message = octeon_spi_transfer_one_message;
master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
master->dev.of_node = pdev->dev.of_node;
err = devm_spi_register_master(&pdev->dev, master);
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c
index 0d32054bfc0d..e7ffcded4e14 100644
--- a/drivers/spi/spi-omap-100k.c
+++ b/drivers/spi/spi-omap-100k.c
@@ -83,15 +83,11 @@
#define SPI_SHUTDOWN 1
struct omap1_spi100k {
- struct spi_master *master;
struct clk *ick;
struct clk *fck;
/* Virtual base address of the controller */
void __iomem *base;
-
- /* State of the SPI */
- unsigned int state;
};
struct omap1_spi100k_cs {
@@ -99,13 +95,6 @@ struct omap1_spi100k_cs {
int word_len;
};
-#define MOD_REG_BIT(val, mask, set) do { \
- if (set) \
- val |= mask; \
- else \
- val &= ~mask; \
-} while (0)
-
static void spi100k_enable_clock(struct spi_master *master)
{
unsigned int val;
@@ -139,7 +128,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
}
spi100k_enable_clock(master);
- writew( data , spi100k->base + SPI_TX_MSB);
+ writew(data , spi100k->base + SPI_TX_MSB);
writew(SPI_CTRL_SEN(0) |
SPI_CTRL_WORD_SIZE(len) |
@@ -147,7 +136,8 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
spi100k->base + SPI_CTRL);
/* Wait for bit ack send change */
- while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE);
+ while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE)
+ ;
udelay(1000);
spi100k_disable_clock(master);
@@ -155,7 +145,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
static int spi100k_read_data(struct spi_master *master, int len)
{
- int dataH,dataL;
+ int dataH, dataL;
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
/* Always do at least 16 bits */
@@ -168,7 +158,8 @@ static int spi100k_read_data(struct spi_master *master, int len)
SPI_CTRL_RD,
spi100k->base + SPI_CTRL);
- while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD);
+ while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD)
+ ;
udelay(1000);
dataL = readw(spi100k->base + SPI_RX_LSB);
@@ -204,12 +195,10 @@ static void omap1_spi100k_force_cs(struct omap1_spi100k *spi100k, int enable)
static unsigned
omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
{
- struct omap1_spi100k *spi100k;
struct omap1_spi100k_cs *cs = spi->controller_state;
unsigned int count, c;
int word_len;
- spi100k = spi_master_get_devdata(spi->master);
count = xfer->len;
c = count;
word_len = cs->word_len;
@@ -221,12 +210,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
- c-=1;
+ c -= 1;
if (xfer->tx_buf != NULL)
spi100k_write_data(spi->master, word_len, *tx++);
if (xfer->rx_buf != NULL)
*rx++ = spi100k_read_data(spi->master, word_len);
- } while(c);
+ } while (c);
} else if (word_len <= 16) {
u16 *rx;
const u16 *tx;
@@ -234,12 +223,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
- c-=2;
+ c -= 2;
if (xfer->tx_buf != NULL)
- spi100k_write_data(spi->master,word_len, *tx++);
+ spi100k_write_data(spi->master, word_len, *tx++);
if (xfer->rx_buf != NULL)
- *rx++ = spi100k_read_data(spi->master,word_len);
- } while(c);
+ *rx++ = spi100k_read_data(spi->master, word_len);
+ } while (c);
} else if (word_len <= 32) {
u32 *rx;
const u32 *tx;
@@ -247,12 +236,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
- c-=4;
+ c -= 4;
if (xfer->tx_buf != NULL)
- spi100k_write_data(spi->master,word_len, *tx);
+ spi100k_write_data(spi->master, word_len, *tx);
if (xfer->rx_buf != NULL)
- *rx = spi100k_read_data(spi->master,word_len);
- } while(c);
+ *rx = spi100k_read_data(spi->master, word_len);
+ } while (c);
}
return count - c;
}
@@ -294,7 +283,7 @@ static int omap1_spi100k_setup(struct spi_device *spi)
spi100k = spi_master_get_devdata(spi->master);
if (!cs) {
- cs = kzalloc(sizeof *cs, GFP_KERNEL);
+ cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL);
if (!cs)
return -ENOMEM;
cs->base = spi100k->base + spi->chip_select * 0x14;
@@ -411,14 +400,14 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
if (!pdev->id)
return -EINVAL;
- master = spi_alloc_master(&pdev->dev, sizeof *spi100k);
+ master = spi_alloc_master(&pdev->dev, sizeof(*spi100k));
if (master == NULL) {
dev_dbg(&pdev->dev, "master allocation failed\n");
return -ENOMEM;
}
if (pdev->id != -1)
- master->bus_num = pdev->id;
+ master->bus_num = pdev->id;
master->setup = omap1_spi100k_setup;
master->transfer_one_message = omap1_spi100k_transfer_one_message;
@@ -434,7 +423,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
spi100k = spi_master_get_devdata(master);
- spi100k->master = master;
/*
* The memory region base address is taken as the platform_data.
@@ -461,8 +449,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
if (status < 0)
goto err;
- spi100k->state = SPI_RUNNING;
-
return status;
err:
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index 9313fd3b413d..be2a2e108e2f 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -99,7 +99,6 @@ struct uwire_spi {
};
struct uwire_state {
- unsigned bits_per_word;
unsigned div1_idx;
};
@@ -210,9 +209,8 @@ static void uwire_chipselect(struct spi_device *spi, int value)
static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
{
- struct uwire_state *ust = spi->controller_state;
unsigned len = t->len;
- unsigned bits = ust->bits_per_word;
+ unsigned bits = t->bits_per_word ? : spi->bits_per_word;
unsigned bytes;
u16 val, w;
int status = 0;
@@ -220,10 +218,6 @@ static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
if (!t->tx_buf && !t->rx_buf)
return 0;
- /* Microwire doesn't read and write concurrently */
- if (t->tx_buf && t->rx_buf)
- return -EPERM;
-
w = spi->chip_select << 10;
w |= CS_CMD;
@@ -322,7 +316,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
struct uwire_state *ust = spi->controller_state;
struct uwire_spi *uwire;
unsigned flags = 0;
- unsigned bits;
unsigned hz;
unsigned long rate;
int div1_idx;
@@ -332,23 +325,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
uwire = spi_master_get_devdata(spi->master);
- if (spi->chip_select > 3) {
- pr_debug("%s: cs%d?\n", dev_name(&spi->dev), spi->chip_select);
- status = -ENODEV;
- goto done;
- }
-
- bits = spi->bits_per_word;
- if (t != NULL && t->bits_per_word)
- bits = t->bits_per_word;
-
- if (bits > 16) {
- pr_debug("%s: wordsize %d?\n", dev_name(&spi->dev), bits);
- status = -ENODEV;
- goto done;
- }
- ust->bits_per_word = bits;
-
/* mode 0..3, clock inverted separately;
* standard nCS signaling;
* don't treat DI=high as "not ready"
@@ -502,6 +478,7 @@ static int uwire_probe(struct platform_device *pdev)
status = PTR_ERR(uwire->ck);
dev_dbg(&pdev->dev, "no functional clock?\n");
spi_master_put(master);
+ iounmap(uwire_base);
return status;
}
clk_enable(uwire->ck);
@@ -515,7 +492,7 @@ static int uwire_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
-
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
master->flags = SPI_MASTER_HALF_DUPLEX;
master->bus_num = 2; /* "official" */
@@ -539,14 +516,13 @@ static int uwire_probe(struct platform_device *pdev)
static int uwire_remove(struct platform_device *pdev)
{
struct uwire_spi *uwire = platform_get_drvdata(pdev);
- int status;
// FIXME remove all child devices, somewhere ...
- status = spi_bitbang_stop(&uwire->bitbang);
+ spi_bitbang_stop(&uwire->bitbang);
uwire_off(uwire);
iounmap(uwire_base);
- return status;
+ return 0;
}
/* work with hotplug and coldplug */
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index a72127f08e39..2941c5b96ebc 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -22,7 +22,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -45,6 +44,7 @@
#include <linux/platform_data/spi-omap2-mcspi.h>
#define OMAP2_MCSPI_MAX_FREQ 48000000
+#define OMAP2_MCSPI_MAX_DIVIDER 4096
#define OMAP2_MCSPI_MAX_FIFODEPTH 64
#define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF
#define SPI_AUTOSUSPEND_TIMEOUT 2000
@@ -89,6 +89,7 @@
#define OMAP2_MCSPI_CHCONF_FORCE BIT(20)
#define OMAP2_MCSPI_CHCONF_FFET BIT(27)
#define OMAP2_MCSPI_CHCONF_FFER BIT(28)
+#define OMAP2_MCSPI_CHCONF_CLKG BIT(29)
#define OMAP2_MCSPI_CHSTAT_RXS BIT(0)
#define OMAP2_MCSPI_CHSTAT_TXS BIT(1)
@@ -96,6 +97,7 @@
#define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3)
#define OMAP2_MCSPI_CHCTRL_EN BIT(0)
+#define OMAP2_MCSPI_CHCTRL_EXTCLK_MASK (0xff << 8)
#define OMAP2_MCSPI_WAKEUPENABLE_WKEN BIT(0)
@@ -149,7 +151,7 @@ struct omap2_mcspi_cs {
int word_len;
struct list_head node;
/* Context save and restore shadow register */
- u32 chconf0;
+ u32 chconf0, chctrl0;
};
static inline void mcspi_write_reg(struct spi_master *master,
@@ -230,10 +232,16 @@ static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
{
+ struct omap2_mcspi_cs *cs = spi->controller_state;
u32 l;
- l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0;
- mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
+ l = cs->chctrl0;
+ if (enable)
+ l |= OMAP2_MCSPI_CHCTRL_EN;
+ else
+ l &= ~OMAP2_MCSPI_CHCTRL_EN;
+ cs->chctrl0 = l;
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
/* Flash post-writes */
mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
}
@@ -840,7 +848,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
struct omap2_mcspi_cs *cs = spi->controller_state;
struct omap2_mcspi *mcspi;
struct spi_master *spi_cntrl;
- u32 l = 0, div = 0;
+ u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0;
u8 word_len = spi->bits_per_word;
u32 speed_hz = spi->max_speed_hz;
@@ -856,7 +864,17 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
speed_hz = t->speed_hz;
speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ);
- div = omap2_mcspi_calc_divisor(speed_hz);
+ if (speed_hz < (OMAP2_MCSPI_MAX_FREQ / OMAP2_MCSPI_MAX_DIVIDER)) {
+ clkd = omap2_mcspi_calc_divisor(speed_hz);
+ speed_hz = OMAP2_MCSPI_MAX_FREQ >> clkd;
+ clkg = 0;
+ } else {
+ div = (OMAP2_MCSPI_MAX_FREQ + speed_hz - 1) / speed_hz;
+ speed_hz = OMAP2_MCSPI_MAX_FREQ / div;
+ clkd = (div - 1) & 0xf;
+ extclk = (div - 1) >> 4;
+ clkg = OMAP2_MCSPI_CHCONF_CLKG;
+ }
l = mcspi_cached_chconf0(spi);
@@ -885,7 +903,16 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
/* set clock divisor */
l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
- l |= div << 2;
+ l |= clkd << 2;
+
+ /* set clock granularity */
+ l &= ~OMAP2_MCSPI_CHCONF_CLKG;
+ l |= clkg;
+ if (clkg) {
+ cs->chctrl0 &= ~OMAP2_MCSPI_CHCTRL_EXTCLK_MASK;
+ cs->chctrl0 |= extclk << 8;
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
+ }
/* set SPI mode 0..3 */
if (spi->mode & SPI_CPOL)
@@ -900,7 +927,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
mcspi_write_chconf0(spi, l);
dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n",
- OMAP2_MCSPI_MAX_FREQ >> div,
+ speed_hz,
(spi->mode & SPI_CPHA) ? "trailing" : "leading",
(spi->mode & SPI_CPOL) ? "inverted" : "normal");
@@ -972,6 +999,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
cs->base = mcspi->base + spi->chip_select * 0x14;
cs->phys = mcspi->phys + spi->chip_select * 0x14;
cs->chconf0 = 0;
+ cs->chctrl0 = 0;
spi->controller_state = cs;
/* Link this to context save list */
list_add_tail(&cs->node, &ctx->cs);
@@ -1057,12 +1085,15 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
status = -EINVAL;
break;
}
- if (par_override || t->speed_hz || t->bits_per_word) {
+ if (par_override ||
+ (t->speed_hz != spi->max_speed_hz) ||
+ (t->bits_per_word != spi->bits_per_word)) {
par_override = 1;
status = omap2_mcspi_setup_transfer(spi, t);
if (status < 0)
break;
- if (!t->speed_hz && !t->bits_per_word)
+ if (t->speed_hz == spi->max_speed_hz &&
+ t->bits_per_word == spi->bits_per_word)
par_override = 0;
}
if (cd && cd->cs_per_word) {
@@ -1176,16 +1207,12 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
m->actual_length = 0;
m->status = 0;
- /* reject invalid messages and transfers */
- if (list_empty(&m->transfers))
- return -EINVAL;
list_for_each_entry(t, &m->transfers, transfer_list) {
const void *tx_buf = t->tx_buf;
void *rx_buf = t->rx_buf;
unsigned len = t->len;
- if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ
- || (len && !(rx_buf || tx_buf))) {
+ if ((len && !(rx_buf || tx_buf))) {
dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
t->speed_hz,
len,
@@ -1194,12 +1221,6 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
t->bits_per_word);
return -EINVAL;
}
- if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) {
- dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n",
- t->speed_hz,
- OMAP2_MCSPI_MAX_FREQ >> 15);
- return -EINVAL;
- }
if (m->is_dma_mapped || len < DMA_MIN_BYTES)
continue;
@@ -1311,6 +1332,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
master->transfer_one_message = omap2_mcspi_transfer_one_message;
master->cleanup = omap2_mcspi_cleanup;
master->dev.of_node = node;
+ master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
+ master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15;
platform_set_drvdata(pdev, master);
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 7f2121fe2622..d018a4aac3a1 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -9,7 +9,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
@@ -43,8 +42,6 @@
struct orion_spi {
struct spi_master *master;
void __iomem *base;
- unsigned int max_speed;
- unsigned int min_speed;
struct clk *clk;
};
@@ -75,23 +72,6 @@ orion_spi_clrbits(struct orion_spi *orion_spi, u32 reg, u32 mask)
writel(val, reg_addr);
}
-static int orion_spi_set_transfer_size(struct orion_spi *orion_spi, int size)
-{
- if (size == 16) {
- orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
- ORION_SPI_IF_8_16_BIT_MODE);
- } else if (size == 8) {
- orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
- ORION_SPI_IF_8_16_BIT_MODE);
- } else {
- pr_debug("Bad bits per word value %d (only 8 or 16 are allowed).\n",
- size);
- return -EINVAL;
- }
-
- return 0;
-}
-
static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
{
u32 tclk_hz;
@@ -170,7 +150,14 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
if (rc)
return rc;
- return orion_spi_set_transfer_size(orion_spi, bits_per_word);
+ if (bits_per_word == 16)
+ orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
+ ORION_SPI_IF_8_16_BIT_MODE);
+ else
+ orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
+ ORION_SPI_IF_8_16_BIT_MODE);
+
+ return 0;
}
static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable)
@@ -260,11 +247,9 @@ orion_spi_write_read_16bit(struct spi_device *spi,
static unsigned int
orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
{
- struct orion_spi *orion_spi;
unsigned int count;
int word_len;
- orion_spi = spi_master_get_devdata(spi->master);
word_len = spi->bits_per_word;
count = xfer->len;
@@ -310,27 +295,6 @@ static int orion_spi_transfer_one_message(struct spi_master *master,
goto msg_done;
list_for_each_entry(t, &m->transfers, transfer_list) {
- /* make sure buffer length is even when working in 16
- * bit mode*/
- if ((t->bits_per_word == 16) && (t->len & 1)) {
- dev_err(&spi->dev,
- "message rejected : "
- "odd data length %d while in 16 bit mode\n",
- t->len);
- status = -EIO;
- goto msg_done;
- }
-
- if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
- dev_err(&spi->dev,
- "message rejected : "
- "device min speed (%d Hz) exceeds "
- "required transfer speed (%d Hz)\n",
- orion_spi->min_speed, t->speed_hz);
- status = -EIO;
- goto msg_done;
- }
-
if (par_override || t->speed_hz || t->bits_per_word) {
par_override = 1;
status = orion_spi_setup_transfer(spi, t);
@@ -375,28 +339,6 @@ static int orion_spi_reset(struct orion_spi *orion_spi)
return 0;
}
-static int orion_spi_setup(struct spi_device *spi)
-{
- struct orion_spi *orion_spi;
-
- orion_spi = spi_master_get_devdata(spi->master);
-
- if ((spi->max_speed_hz == 0)
- || (spi->max_speed_hz > orion_spi->max_speed))
- spi->max_speed_hz = orion_spi->max_speed;
-
- if (spi->max_speed_hz < orion_spi->min_speed) {
- dev_err(&spi->dev, "setup: requested speed too low %d Hz\n",
- spi->max_speed_hz);
- return -EINVAL;
- }
-
- /*
- * baudrate & width will be set orion_spi_setup_transfer
- */
- return 0;
-}
-
static int orion_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
@@ -425,9 +367,9 @@ static int orion_spi_probe(struct platform_device *pdev)
/* we support only mode 0, and no options */
master->mode_bits = SPI_CPHA | SPI_CPOL;
- master->setup = orion_spi_setup;
master->transfer_one_message = orion_spi_transfer_one_message;
master->num_chipselect = ORION_NUM_CHIPSELECTS;
+ master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
platform_set_drvdata(pdev, master);
@@ -443,8 +385,8 @@ static int orion_spi_probe(struct platform_device *pdev)
clk_prepare(spi->clk);
clk_enable(spi->clk);
tclk_hz = clk_get_rate(spi->clk);
- spi->max_speed = DIV_ROUND_UP(tclk_hz, 4);
- spi->min_speed = DIV_ROUND_UP(tclk_hz, 30);
+ master->max_speed_hz = DIV_ROUND_UP(tclk_hz, 4);
+ master->min_speed_hz = DIV_ROUND_UP(tclk_hz, 30);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
spi->base = devm_ioremap_resource(&pdev->dev, r);
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 2789b452e711..51d99779682f 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -459,9 +459,8 @@ static void giveback(struct pl022 *pl022)
struct spi_transfer *last_transfer;
pl022->next_msg_cs_active = false;
- last_transfer = list_entry(pl022->cur_msg->transfers.prev,
- struct spi_transfer,
- transfer_list);
+ last_transfer = list_last_entry(&pl022->cur_msg->transfers,
+ struct spi_transfer, transfer_list);
/* Delay if requested before any change in chip select */
if (last_transfer->delay_usecs)
@@ -2109,8 +2108,6 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int),
GFP_KERNEL);
- pinctrl_pm_select_default_state(dev);
-
/*
* Bus Number Which has been Assigned to this SSP controller
* on this board
@@ -2183,13 +2180,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
goto err_no_clk;
}
- status = clk_prepare(pl022->clk);
- if (status) {
- dev_err(&adev->dev, "could not prepare SSP/SPI bus clock\n");
- goto err_clk_prep;
- }
-
- status = clk_enable(pl022->clk);
+ status = clk_prepare_enable(pl022->clk);
if (status) {
dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n");
goto err_no_clk_en;
@@ -2250,10 +2241,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
if (platform_info->enable_dma)
pl022_dma_remove(pl022);
err_no_irq:
- clk_disable(pl022->clk);
+ clk_disable_unprepare(pl022->clk);
err_no_clk_en:
- clk_unprepare(pl022->clk);
- err_clk_prep:
err_no_clk:
err_no_ioremap:
amba_release_regions(adev);
@@ -2281,42 +2270,13 @@ pl022_remove(struct amba_device *adev)
if (pl022->master_info->enable_dma)
pl022_dma_remove(pl022);
- clk_disable(pl022->clk);
- clk_unprepare(pl022->clk);
+ clk_disable_unprepare(pl022->clk);
amba_release_regions(adev);
tasklet_disable(&pl022->pump_transfers);
return 0;
}
-#if defined(CONFIG_SUSPEND) || defined(CONFIG_PM_RUNTIME)
-/*
- * These two functions are used from both suspend/resume and
- * the runtime counterparts to handle external resources like
- * clocks, pins and regulators when going to sleep.
- */
-static void pl022_suspend_resources(struct pl022 *pl022, bool runtime)
-{
- clk_disable(pl022->clk);
-
- if (runtime)
- pinctrl_pm_select_idle_state(&pl022->adev->dev);
- else
- pinctrl_pm_select_sleep_state(&pl022->adev->dev);
-}
-
-static void pl022_resume_resources(struct pl022 *pl022, bool runtime)
-{
- /* First go to the default state */
- pinctrl_pm_select_default_state(&pl022->adev->dev);
- if (!runtime)
- /* Then let's idle the pins until the next transfer happens */
- pinctrl_pm_select_idle_state(&pl022->adev->dev);
-
- clk_enable(pl022->clk);
-}
-#endif
-
-#ifdef CONFIG_SUSPEND
+#ifdef CONFIG_PM_SLEEP
static int pl022_suspend(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
@@ -2328,8 +2288,13 @@ static int pl022_suspend(struct device *dev)
return ret;
}
- pm_runtime_get_sync(dev);
- pl022_suspend_resources(pl022, false);
+ ret = pm_runtime_force_suspend(dev);
+ if (ret) {
+ spi_master_resume(pl022->master);
+ return ret;
+ }
+
+ pinctrl_pm_select_sleep_state(dev);
dev_dbg(dev, "suspended\n");
return 0;
@@ -2340,8 +2305,9 @@ static int pl022_resume(struct device *dev)
struct pl022 *pl022 = dev_get_drvdata(dev);
int ret;
- pl022_resume_resources(pl022, false);
- pm_runtime_put(dev);
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ dev_err(dev, "problem resuming\n");
/* Start the queue running */
ret = spi_master_resume(pl022->master);
@@ -2352,14 +2318,16 @@ static int pl022_resume(struct device *dev)
return ret;
}
-#endif /* CONFIG_PM */
+#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int pl022_runtime_suspend(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
- pl022_suspend_resources(pl022, true);
+ clk_disable_unprepare(pl022->clk);
+ pinctrl_pm_select_idle_state(dev);
+
return 0;
}
@@ -2367,14 +2335,16 @@ static int pl022_runtime_resume(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
- pl022_resume_resources(pl022, true);
+ pinctrl_pm_select_default_state(dev);
+ clk_prepare_enable(pl022->clk);
+
return 0;
}
#endif
static const struct dev_pm_ops pl022_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume)
- SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
+ SET_PM_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
};
static struct vendor_data vendor_arm = {
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c
index 5ee56726f8d0..80b8408ac3e3 100644
--- a/drivers/spi/spi-ppc4xx.c
+++ b/drivers/spi/spi-ppc4xx.c
@@ -24,7 +24,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c
index 3c0b55125f1e..713af4806f26 100644
--- a/drivers/spi/spi-pxa2xx-dma.c
+++ b/drivers/spi/spi-pxa2xx-dma.c
@@ -9,7 +9,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
diff --git a/drivers/spi/spi-pxa2xx-pxadma.c b/drivers/spi/spi-pxa2xx-pxadma.c
index 2916efc7cfe5..e8a26f25d5c0 100644
--- a/drivers/spi/spi-pxa2xx-pxadma.c
+++ b/drivers/spi/spi-pxa2xx-pxadma.c
@@ -18,7 +18,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index c702fc536a77..41185d0557fa 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -362,8 +362,7 @@ static void giveback(struct driver_data *drv_data)
drv_data->cur_msg = NULL;
drv_data->cur_transfer = NULL;
- last_transfer = list_entry(msg->transfers.prev,
- struct spi_transfer,
+ last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
transfer_list);
/* Delay if requested before any change in chip select */
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
new file mode 100644
index 000000000000..b032e8885e24
--- /dev/null
+++ b/drivers/spi/spi-qup.c
@@ -0,0 +1,779 @@
+/*
+ * Copyright (c) 2008-2014, 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 rev 2 and
+ * only rev 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/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+
+#define QUP_CONFIG 0x0000
+#define QUP_STATE 0x0004
+#define QUP_IO_M_MODES 0x0008
+#define QUP_SW_RESET 0x000c
+#define QUP_OPERATIONAL 0x0018
+#define QUP_ERROR_FLAGS 0x001c
+#define QUP_ERROR_FLAGS_EN 0x0020
+#define QUP_OPERATIONAL_MASK 0x0028
+#define QUP_HW_VERSION 0x0030
+#define QUP_MX_OUTPUT_CNT 0x0100
+#define QUP_OUTPUT_FIFO 0x0110
+#define QUP_MX_WRITE_CNT 0x0150
+#define QUP_MX_INPUT_CNT 0x0200
+#define QUP_MX_READ_CNT 0x0208
+#define QUP_INPUT_FIFO 0x0218
+
+#define SPI_CONFIG 0x0300
+#define SPI_IO_CONTROL 0x0304
+#define SPI_ERROR_FLAGS 0x0308
+#define SPI_ERROR_FLAGS_EN 0x030c
+
+/* QUP_CONFIG fields */
+#define QUP_CONFIG_SPI_MODE (1 << 8)
+#define QUP_CONFIG_CLOCK_AUTO_GATE BIT(13)
+#define QUP_CONFIG_NO_INPUT BIT(7)
+#define QUP_CONFIG_NO_OUTPUT BIT(6)
+#define QUP_CONFIG_N 0x001f
+
+/* QUP_STATE fields */
+#define QUP_STATE_VALID BIT(2)
+#define QUP_STATE_RESET 0
+#define QUP_STATE_RUN 1
+#define QUP_STATE_PAUSE 3
+#define QUP_STATE_MASK 3
+#define QUP_STATE_CLEAR 2
+
+#define QUP_HW_VERSION_2_1_1 0x20010001
+
+/* QUP_IO_M_MODES fields */
+#define QUP_IO_M_PACK_EN BIT(15)
+#define QUP_IO_M_UNPACK_EN BIT(14)
+#define QUP_IO_M_INPUT_MODE_MASK_SHIFT 12
+#define QUP_IO_M_OUTPUT_MODE_MASK_SHIFT 10
+#define QUP_IO_M_INPUT_MODE_MASK (3 << QUP_IO_M_INPUT_MODE_MASK_SHIFT)
+#define QUP_IO_M_OUTPUT_MODE_MASK (3 << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT)
+
+#define QUP_IO_M_OUTPUT_BLOCK_SIZE(x) (((x) & (0x03 << 0)) >> 0)
+#define QUP_IO_M_OUTPUT_FIFO_SIZE(x) (((x) & (0x07 << 2)) >> 2)
+#define QUP_IO_M_INPUT_BLOCK_SIZE(x) (((x) & (0x03 << 5)) >> 5)
+#define QUP_IO_M_INPUT_FIFO_SIZE(x) (((x) & (0x07 << 7)) >> 7)
+
+#define QUP_IO_M_MODE_FIFO 0
+#define QUP_IO_M_MODE_BLOCK 1
+#define QUP_IO_M_MODE_DMOV 2
+#define QUP_IO_M_MODE_BAM 3
+
+/* QUP_OPERATIONAL fields */
+#define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11)
+#define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10)
+#define QUP_OP_IN_SERVICE_FLAG BIT(9)
+#define QUP_OP_OUT_SERVICE_FLAG BIT(8)
+#define QUP_OP_IN_FIFO_FULL BIT(7)
+#define QUP_OP_OUT_FIFO_FULL BIT(6)
+#define QUP_OP_IN_FIFO_NOT_EMPTY BIT(5)
+#define QUP_OP_OUT_FIFO_NOT_EMPTY BIT(4)
+
+/* QUP_ERROR_FLAGS and QUP_ERROR_FLAGS_EN fields */
+#define QUP_ERROR_OUTPUT_OVER_RUN BIT(5)
+#define QUP_ERROR_INPUT_UNDER_RUN BIT(4)
+#define QUP_ERROR_OUTPUT_UNDER_RUN BIT(3)
+#define QUP_ERROR_INPUT_OVER_RUN BIT(2)
+
+/* SPI_CONFIG fields */
+#define SPI_CONFIG_HS_MODE BIT(10)
+#define SPI_CONFIG_INPUT_FIRST BIT(9)
+#define SPI_CONFIG_LOOPBACK BIT(8)
+
+/* SPI_IO_CONTROL fields */
+#define SPI_IO_C_FORCE_CS BIT(11)
+#define SPI_IO_C_CLK_IDLE_HIGH BIT(10)
+#define SPI_IO_C_MX_CS_MODE BIT(8)
+#define SPI_IO_C_CS_N_POLARITY_0 BIT(4)
+#define SPI_IO_C_CS_SELECT(x) (((x) & 3) << 2)
+#define SPI_IO_C_CS_SELECT_MASK 0x000c
+#define SPI_IO_C_TRISTATE_CS BIT(1)
+#define SPI_IO_C_NO_TRI_STATE BIT(0)
+
+/* SPI_ERROR_FLAGS and SPI_ERROR_FLAGS_EN fields */
+#define SPI_ERROR_CLK_OVER_RUN BIT(1)
+#define SPI_ERROR_CLK_UNDER_RUN BIT(0)
+
+#define SPI_NUM_CHIPSELECTS 4
+
+/* high speed mode is when bus rate is greater then 26MHz */
+#define SPI_HS_MIN_RATE 26000000
+#define SPI_MAX_RATE 50000000
+
+#define SPI_DELAY_THRESHOLD 1
+#define SPI_DELAY_RETRY 10
+
+struct spi_qup {
+ void __iomem *base;
+ struct device *dev;
+ struct clk *cclk; /* core clock */
+ struct clk *iclk; /* interface clock */
+ int irq;
+ spinlock_t lock;
+
+ int in_fifo_sz;
+ int out_fifo_sz;
+ int in_blk_sz;
+ int out_blk_sz;
+
+ struct spi_transfer *xfer;
+ struct completion done;
+ int error;
+ int w_size; /* bytes per SPI word */
+ int tx_bytes;
+ int rx_bytes;
+};
+
+
+static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
+{
+ u32 opstate = readl_relaxed(controller->base + QUP_STATE);
+
+ return opstate & QUP_STATE_VALID;
+}
+
+static int spi_qup_set_state(struct spi_qup *controller, u32 state)
+{
+ unsigned long loop;
+ u32 cur_state;
+
+ loop = 0;
+ while (!spi_qup_is_valid_state(controller)) {
+
+ usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2);
+
+ if (++loop > SPI_DELAY_RETRY)
+ return -EIO;
+ }
+
+ if (loop)
+ dev_dbg(controller->dev, "invalid state for %ld,us %d\n",
+ loop, state);
+
+ cur_state = readl_relaxed(controller->base + QUP_STATE);
+ /*
+ * Per spec: for PAUSE_STATE to RESET_STATE, two writes
+ * of (b10) are required
+ */
+ if (((cur_state & QUP_STATE_MASK) == QUP_STATE_PAUSE) &&
+ (state == QUP_STATE_RESET)) {
+ writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE);
+ writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE);
+ } else {
+ cur_state &= ~QUP_STATE_MASK;
+ cur_state |= state;
+ writel_relaxed(cur_state, controller->base + QUP_STATE);
+ }
+
+ loop = 0;
+ while (!spi_qup_is_valid_state(controller)) {
+
+ usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2);
+
+ if (++loop > SPI_DELAY_RETRY)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+
+static void spi_qup_fifo_read(struct spi_qup *controller,
+ struct spi_transfer *xfer)
+{
+ u8 *rx_buf = xfer->rx_buf;
+ u32 word, state;
+ int idx, shift, w_size;
+
+ w_size = controller->w_size;
+
+ while (controller->rx_bytes < xfer->len) {
+
+ state = readl_relaxed(controller->base + QUP_OPERATIONAL);
+ if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
+ break;
+
+ word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
+
+ if (!rx_buf) {
+ controller->rx_bytes += w_size;
+ continue;
+ }
+
+ for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) {
+ /*
+ * The data format depends on bytes per SPI word:
+ * 4 bytes: 0x12345678
+ * 2 bytes: 0x00001234
+ * 1 byte : 0x00000012
+ */
+ shift = BITS_PER_BYTE;
+ shift *= (w_size - idx - 1);
+ rx_buf[controller->rx_bytes] = word >> shift;
+ }
+ }
+}
+
+static void spi_qup_fifo_write(struct spi_qup *controller,
+ struct spi_transfer *xfer)
+{
+ const u8 *tx_buf = xfer->tx_buf;
+ u32 word, state, data;
+ int idx, w_size;
+
+ w_size = controller->w_size;
+
+ while (controller->tx_bytes < xfer->len) {
+
+ state = readl_relaxed(controller->base + QUP_OPERATIONAL);
+ if (state & QUP_OP_OUT_FIFO_FULL)
+ break;
+
+ word = 0;
+ for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
+
+ if (!tx_buf) {
+ controller->tx_bytes += w_size;
+ break;
+ }
+
+ data = tx_buf[controller->tx_bytes];
+ word |= data << (BITS_PER_BYTE * (3 - idx));
+ }
+
+ writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
+ }
+}
+
+static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
+{
+ struct spi_qup *controller = dev_id;
+ struct spi_transfer *xfer;
+ u32 opflags, qup_err, spi_err;
+ unsigned long flags;
+ int error = 0;
+
+ spin_lock_irqsave(&controller->lock, flags);
+ xfer = controller->xfer;
+ controller->xfer = NULL;
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
+ spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS);
+ opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
+
+ writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
+ writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
+ writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
+
+ if (!xfer) {
+ dev_err_ratelimited(controller->dev, "unexpected irq %x08 %x08 %x08\n",
+ qup_err, spi_err, opflags);
+ return IRQ_HANDLED;
+ }
+
+ if (qup_err) {
+ if (qup_err & QUP_ERROR_OUTPUT_OVER_RUN)
+ dev_warn(controller->dev, "OUTPUT_OVER_RUN\n");
+ if (qup_err & QUP_ERROR_INPUT_UNDER_RUN)
+ dev_warn(controller->dev, "INPUT_UNDER_RUN\n");
+ if (qup_err & QUP_ERROR_OUTPUT_UNDER_RUN)
+ dev_warn(controller->dev, "OUTPUT_UNDER_RUN\n");
+ if (qup_err & QUP_ERROR_INPUT_OVER_RUN)
+ dev_warn(controller->dev, "INPUT_OVER_RUN\n");
+
+ error = -EIO;
+ }
+
+ if (spi_err) {
+ if (spi_err & SPI_ERROR_CLK_OVER_RUN)
+ dev_warn(controller->dev, "CLK_OVER_RUN\n");
+ if (spi_err & SPI_ERROR_CLK_UNDER_RUN)
+ dev_warn(controller->dev, "CLK_UNDER_RUN\n");
+
+ error = -EIO;
+ }
+
+ if (opflags & QUP_OP_IN_SERVICE_FLAG)
+ spi_qup_fifo_read(controller, xfer);
+
+ if (opflags & QUP_OP_OUT_SERVICE_FLAG)
+ spi_qup_fifo_write(controller, xfer);
+
+ spin_lock_irqsave(&controller->lock, flags);
+ controller->error = error;
+ controller->xfer = xfer;
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ if (controller->rx_bytes == xfer->len || error)
+ complete(&controller->done);
+
+ return IRQ_HANDLED;
+}
+
+
+/* set clock freq ... bits per word */
+static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
+{
+ struct spi_qup *controller = spi_master_get_devdata(spi->master);
+ u32 config, iomode, mode;
+ int ret, n_words, w_size;
+
+ if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
+ dev_err(controller->dev, "too big size for loopback %d > %d\n",
+ xfer->len, controller->in_fifo_sz);
+ return -EIO;
+ }
+
+ ret = clk_set_rate(controller->cclk, xfer->speed_hz);
+ if (ret) {
+ dev_err(controller->dev, "fail to set frequency %d",
+ xfer->speed_hz);
+ return -EIO;
+ }
+
+ if (spi_qup_set_state(controller, QUP_STATE_RESET)) {
+ dev_err(controller->dev, "cannot set RESET state\n");
+ return -EIO;
+ }
+
+ w_size = 4;
+ if (xfer->bits_per_word <= 8)
+ w_size = 1;
+ else if (xfer->bits_per_word <= 16)
+ w_size = 2;
+
+ n_words = xfer->len / w_size;
+ controller->w_size = w_size;
+
+ if (n_words <= controller->in_fifo_sz) {
+ mode = QUP_IO_M_MODE_FIFO;
+ writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
+ writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
+ /* must be zero for FIFO */
+ writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
+ writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
+ } else {
+ mode = QUP_IO_M_MODE_BLOCK;
+ writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
+ writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
+ /* must be zero for BLOCK and BAM */
+ writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
+ writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
+ }
+
+ iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
+ /* Set input and output transfer mode */
+ iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
+ iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
+ iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
+ iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
+
+ writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
+
+ config = readl_relaxed(controller->base + SPI_CONFIG);
+
+ if (spi->mode & SPI_LOOP)
+ config |= SPI_CONFIG_LOOPBACK;
+ else
+ config &= ~SPI_CONFIG_LOOPBACK;
+
+ if (spi->mode & SPI_CPHA)
+ config &= ~SPI_CONFIG_INPUT_FIRST;
+ else
+ config |= SPI_CONFIG_INPUT_FIRST;
+
+ /*
+ * HS_MODE improves signal stability for spi-clk high rates,
+ * but is invalid in loop back mode.
+ */
+ if ((xfer->speed_hz >= SPI_HS_MIN_RATE) && !(spi->mode & SPI_LOOP))
+ config |= SPI_CONFIG_HS_MODE;
+ else
+ config &= ~SPI_CONFIG_HS_MODE;
+
+ writel_relaxed(config, controller->base + SPI_CONFIG);
+
+ config = readl_relaxed(controller->base + QUP_CONFIG);
+ config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N);
+ config |= xfer->bits_per_word - 1;
+ config |= QUP_CONFIG_SPI_MODE;
+ writel_relaxed(config, controller->base + QUP_CONFIG);
+
+ writel_relaxed(0, controller->base + QUP_OPERATIONAL_MASK);
+ return 0;
+}
+
+static void spi_qup_set_cs(struct spi_device *spi, bool enable)
+{
+ struct spi_qup *controller = spi_master_get_devdata(spi->master);
+
+ u32 iocontol, mask;
+
+ iocontol = readl_relaxed(controller->base + SPI_IO_CONTROL);
+
+ /* Disable auto CS toggle and use manual */
+ iocontol &= ~SPI_IO_C_MX_CS_MODE;
+ iocontol |= SPI_IO_C_FORCE_CS;
+
+ iocontol &= ~SPI_IO_C_CS_SELECT_MASK;
+ iocontol |= SPI_IO_C_CS_SELECT(spi->chip_select);
+
+ mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select;
+
+ if (enable)
+ iocontol |= mask;
+ else
+ iocontol &= ~mask;
+
+ writel_relaxed(iocontol, controller->base + SPI_IO_CONTROL);
+}
+
+static int spi_qup_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ unsigned long timeout, flags;
+ int ret = -EIO;
+
+ ret = spi_qup_io_config(spi, xfer);
+ if (ret)
+ return ret;
+
+ timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
+ timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
+ timeout = 100 * msecs_to_jiffies(timeout);
+
+ reinit_completion(&controller->done);
+
+ spin_lock_irqsave(&controller->lock, flags);
+ controller->xfer = xfer;
+ controller->error = 0;
+ controller->rx_bytes = 0;
+ controller->tx_bytes = 0;
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
+ dev_warn(controller->dev, "cannot set RUN state\n");
+ goto exit;
+ }
+
+ if (spi_qup_set_state(controller, QUP_STATE_PAUSE)) {
+ dev_warn(controller->dev, "cannot set PAUSE state\n");
+ goto exit;
+ }
+
+ spi_qup_fifo_write(controller, xfer);
+
+ if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
+ dev_warn(controller->dev, "cannot set EXECUTE state\n");
+ goto exit;
+ }
+
+ if (!wait_for_completion_timeout(&controller->done, timeout))
+ ret = -ETIMEDOUT;
+exit:
+ spi_qup_set_state(controller, QUP_STATE_RESET);
+ spin_lock_irqsave(&controller->lock, flags);
+ controller->xfer = NULL;
+ if (!ret)
+ ret = controller->error;
+ spin_unlock_irqrestore(&controller->lock, flags);
+ return ret;
+}
+
+static int spi_qup_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct clk *iclk, *cclk;
+ struct spi_qup *controller;
+ struct resource *res;
+ struct device *dev;
+ void __iomem *base;
+ u32 data, max_freq, iomode;
+ int ret, irq, size;
+
+ dev = &pdev->dev;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ cclk = devm_clk_get(dev, "core");
+ if (IS_ERR(cclk))
+ return PTR_ERR(cclk);
+
+ iclk = devm_clk_get(dev, "iface");
+ if (IS_ERR(iclk))
+ return PTR_ERR(iclk);
+
+ /* This is optional parameter */
+ if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq))
+ max_freq = SPI_MAX_RATE;
+
+ if (!max_freq || max_freq > SPI_MAX_RATE) {
+ dev_err(dev, "invalid clock frequency %d\n", max_freq);
+ return -ENXIO;
+ }
+
+ ret = clk_prepare_enable(cclk);
+ if (ret) {
+ dev_err(dev, "cannot enable core clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(iclk);
+ if (ret) {
+ clk_disable_unprepare(cclk);
+ dev_err(dev, "cannot enable iface clock\n");
+ return ret;
+ }
+
+ data = readl_relaxed(base + QUP_HW_VERSION);
+
+ if (data < QUP_HW_VERSION_2_1_1) {
+ clk_disable_unprepare(cclk);
+ clk_disable_unprepare(iclk);
+ dev_err(dev, "v.%08x is not supported\n", data);
+ return -ENXIO;
+ }
+
+ master = spi_alloc_master(dev, sizeof(struct spi_qup));
+ if (!master) {
+ clk_disable_unprepare(cclk);
+ clk_disable_unprepare(iclk);
+ dev_err(dev, "cannot allocate master\n");
+ return -ENOMEM;
+ }
+
+ master->bus_num = pdev->id;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+ master->num_chipselect = SPI_NUM_CHIPSELECTS;
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ master->max_speed_hz = max_freq;
+ master->set_cs = spi_qup_set_cs;
+ master->transfer_one = spi_qup_transfer_one;
+ master->dev.of_node = pdev->dev.of_node;
+ master->auto_runtime_pm = true;
+
+ platform_set_drvdata(pdev, master);
+
+ controller = spi_master_get_devdata(master);
+
+ controller->dev = dev;
+ controller->base = base;
+ controller->iclk = iclk;
+ controller->cclk = cclk;
+ controller->irq = irq;
+
+ spin_lock_init(&controller->lock);
+ init_completion(&controller->done);
+
+ iomode = readl_relaxed(base + QUP_IO_M_MODES);
+
+ size = QUP_IO_M_OUTPUT_BLOCK_SIZE(iomode);
+ if (size)
+ controller->out_blk_sz = size * 16;
+ else
+ controller->out_blk_sz = 4;
+
+ size = QUP_IO_M_INPUT_BLOCK_SIZE(iomode);
+ if (size)
+ controller->in_blk_sz = size * 16;
+ else
+ controller->in_blk_sz = 4;
+
+ size = QUP_IO_M_OUTPUT_FIFO_SIZE(iomode);
+ controller->out_fifo_sz = controller->out_blk_sz * (2 << size);
+
+ size = QUP_IO_M_INPUT_FIFO_SIZE(iomode);
+ controller->in_fifo_sz = controller->in_blk_sz * (2 << size);
+
+ dev_info(dev, "v.%08x IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
+ data, controller->in_blk_sz, controller->in_fifo_sz,
+ controller->out_blk_sz, controller->out_fifo_sz);
+
+ writel_relaxed(1, base + QUP_SW_RESET);
+
+ ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+ if (ret) {
+ dev_err(dev, "cannot set RESET state\n");
+ goto error;
+ }
+
+ writel_relaxed(0, base + QUP_OPERATIONAL);
+ writel_relaxed(0, base + QUP_IO_M_MODES);
+ writel_relaxed(0, base + QUP_OPERATIONAL_MASK);
+ writel_relaxed(SPI_ERROR_CLK_UNDER_RUN | SPI_ERROR_CLK_OVER_RUN,
+ base + SPI_ERROR_FLAGS_EN);
+
+ writel_relaxed(0, base + SPI_CONFIG);
+ writel_relaxed(SPI_IO_C_NO_TRI_STATE, base + SPI_IO_CONTROL);
+
+ ret = devm_request_irq(dev, irq, spi_qup_qup_irq,
+ IRQF_TRIGGER_HIGH, pdev->name, controller);
+ if (ret)
+ goto error;
+
+ ret = devm_spi_register_master(dev, master);
+ if (ret)
+ goto error;
+
+ pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ return 0;
+
+error:
+ clk_disable_unprepare(cclk);
+ clk_disable_unprepare(iclk);
+ spi_master_put(master);
+ return ret;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int spi_qup_pm_suspend_runtime(struct device *device)
+{
+ struct spi_master *master = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ u32 config;
+
+ /* Enable clocks auto gaiting */
+ config = readl(controller->base + QUP_CONFIG);
+ config |= QUP_CONFIG_CLOCK_AUTO_GATE;
+ writel_relaxed(config, controller->base + QUP_CONFIG);
+ return 0;
+}
+
+static int spi_qup_pm_resume_runtime(struct device *device)
+{
+ struct spi_master *master = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ u32 config;
+
+ /* Disable clocks auto gaiting */
+ config = readl_relaxed(controller->base + QUP_CONFIG);
+ config &= ~QUP_CONFIG_CLOCK_AUTO_GATE;
+ writel_relaxed(config, controller->base + QUP_CONFIG);
+ return 0;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+#ifdef CONFIG_PM_SLEEP
+static int spi_qup_suspend(struct device *device)
+{
+ struct spi_master *master = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ int ret;
+
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
+
+ ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+ if (ret)
+ return ret;
+
+ clk_disable_unprepare(controller->cclk);
+ clk_disable_unprepare(controller->iclk);
+ return 0;
+}
+
+static int spi_qup_resume(struct device *device)
+{
+ struct spi_master *master = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(controller->iclk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(controller->cclk);
+ if (ret)
+ return ret;
+
+ ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+ if (ret)
+ return ret;
+
+ return spi_master_resume(master);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static int spi_qup_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = dev_get_drvdata(&pdev->dev);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ int ret;
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret)
+ return ret;
+
+ ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+ if (ret)
+ return ret;
+
+ clk_disable_unprepare(controller->cclk);
+ clk_disable_unprepare(controller->iclk);
+
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static struct of_device_id spi_qup_dt_match[] = {
+ { .compatible = "qcom,spi-qup-v2.1.1", },
+ { .compatible = "qcom,spi-qup-v2.2.1", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, spi_qup_dt_match);
+
+static const struct dev_pm_ops spi_qup_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(spi_qup_suspend, spi_qup_resume)
+ SET_RUNTIME_PM_OPS(spi_qup_pm_suspend_runtime,
+ spi_qup_pm_resume_runtime,
+ NULL)
+};
+
+static struct platform_driver spi_qup_driver = {
+ .driver = {
+ .name = "spi_qup",
+ .owner = THIS_MODULE,
+ .pm = &spi_qup_dev_pm_ops,
+ .of_match_table = spi_qup_dt_match,
+ },
+ .probe = spi_qup_probe,
+ .remove = spi_qup_remove,
+};
+module_platform_driver(spi_qup_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:spi_qup");
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 28987d9fcfe5..1fb0ad213324 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -1,7 +1,8 @@
/*
* SH RSPI driver
*
- * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2012, 2013 Renesas Solutions Corp.
+ * Copyright (C) 2014 Glider bvba
*
* Based on spi-sh.c:
* Copyright (C) 2011 Renesas Solutions Corp.
@@ -25,14 +26,14 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
#include <linux/sh_dma.h>
#include <linux/spi/spi.h>
#include <linux/spi/rspi.h>
@@ -49,7 +50,7 @@
#define RSPI_SPCKD 0x0c /* Clock Delay Register */
#define RSPI_SSLND 0x0d /* Slave Select Negation Delay Register */
#define RSPI_SPND 0x0e /* Next-Access Delay Register */
-#define RSPI_SPCR2 0x0f /* Control Register 2 */
+#define RSPI_SPCR2 0x0f /* Control Register 2 (SH only) */
#define RSPI_SPCMD0 0x10 /* Command Register 0 */
#define RSPI_SPCMD1 0x12 /* Command Register 1 */
#define RSPI_SPCMD2 0x14 /* Command Register 2 */
@@ -58,16 +59,23 @@
#define RSPI_SPCMD5 0x1a /* Command Register 5 */
#define RSPI_SPCMD6 0x1c /* Command Register 6 */
#define RSPI_SPCMD7 0x1e /* Command Register 7 */
+#define RSPI_SPCMD(i) (RSPI_SPCMD0 + (i) * 2)
+#define RSPI_NUM_SPCMD 8
+#define RSPI_RZ_NUM_SPCMD 4
+#define QSPI_NUM_SPCMD 4
+
+/* RSPI on RZ only */
#define RSPI_SPBFCR 0x20 /* Buffer Control Register */
#define RSPI_SPBFDR 0x22 /* Buffer Data Count Setting Register */
-/*qspi only */
+/* QSPI only */
#define QSPI_SPBFCR 0x18 /* Buffer Control Register */
#define QSPI_SPBDCR 0x1a /* Buffer Data Count Register */
#define QSPI_SPBMUL0 0x1c /* Transfer Data Length Multiplier Setting Register 0 */
#define QSPI_SPBMUL1 0x20 /* Transfer Data Length Multiplier Setting Register 1 */
#define QSPI_SPBMUL2 0x24 /* Transfer Data Length Multiplier Setting Register 2 */
#define QSPI_SPBMUL3 0x28 /* Transfer Data Length Multiplier Setting Register 3 */
+#define QSPI_SPBMUL(i) (QSPI_SPBMUL0 + (i) * 4)
/* SPCR - Control Register */
#define SPCR_SPRIE 0x80 /* Receive Interrupt Enable */
@@ -104,7 +112,7 @@
#define SPSR_PERF 0x08 /* Parity Error Flag */
#define SPSR_MODF 0x04 /* Mode Fault Error Flag */
#define SPSR_IDLNF 0x02 /* RSPI Idle Flag */
-#define SPSR_OVRF 0x01 /* Overrun Error Flag */
+#define SPSR_OVRF 0x01 /* Overrun Error Flag (RSPI only) */
/* SPSCR - Sequence Control Register */
#define SPSCR_SPSLN_MASK 0x07 /* Sequence Length Specification */
@@ -121,13 +129,13 @@
#define SPDCR_SPLWORD SPDCR_SPLW1
#define SPDCR_SPLBYTE SPDCR_SPLW0
#define SPDCR_SPLW 0x20 /* Access Width Specification (SH) */
-#define SPDCR_SPRDTD 0x10 /* Receive Transmit Data Select */
+#define SPDCR_SPRDTD 0x10 /* Receive Transmit Data Select (SH) */
#define SPDCR_SLSEL1 0x08
#define SPDCR_SLSEL0 0x04
-#define SPDCR_SLSEL_MASK 0x0c /* SSL1 Output Select */
+#define SPDCR_SLSEL_MASK 0x0c /* SSL1 Output Select (SH) */
#define SPDCR_SPFC1 0x02
#define SPDCR_SPFC0 0x01
-#define SPDCR_SPFC_MASK 0x03 /* Frame Count Setting (1-4) */
+#define SPDCR_SPFC_MASK 0x03 /* Frame Count Setting (1-4) (SH) */
/* SPCKD - Clock Delay Register */
#define SPCKD_SCKDL_MASK 0x07 /* Clock Delay Setting (1-8) */
@@ -151,7 +159,7 @@
#define SPCMD_LSBF 0x1000 /* LSB First */
#define SPCMD_SPB_MASK 0x0f00 /* Data Length Setting */
#define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK)
-#define SPCMD_SPB_8BIT 0x0000 /* qspi only */
+#define SPCMD_SPB_8BIT 0x0000 /* QSPI only */
#define SPCMD_SPB_16BIT 0x0100
#define SPCMD_SPB_20BIT 0x0000
#define SPCMD_SPB_24BIT 0x0100
@@ -170,8 +178,8 @@
#define SPCMD_CPHA 0x0001 /* Clock Phase Setting */
/* SPBFCR - Buffer Control Register */
-#define SPBFCR_TXRST 0x80 /* Transmit Buffer Data Reset (qspi only) */
-#define SPBFCR_RXRST 0x40 /* Receive Buffer Data Reset (qspi only) */
+#define SPBFCR_TXRST 0x80 /* Transmit Buffer Data Reset */
+#define SPBFCR_RXRST 0x40 /* Receive Buffer Data Reset */
#define SPBFCR_TXTRG_MASK 0x30 /* Transmit Buffer Data Triggering Number */
#define SPBFCR_RXTRG_MASK 0x07 /* Receive Buffer Data Triggering Number */
@@ -181,22 +189,21 @@ struct rspi_data {
void __iomem *addr;
u32 max_speed_hz;
struct spi_master *master;
- struct list_head queue;
- struct work_struct ws;
wait_queue_head_t wait;
- spinlock_t lock;
struct clk *clk;
- u8 spsr;
u16 spcmd;
+ u8 spsr;
+ u8 sppcr;
+ int rx_irq, tx_irq;
const struct spi_ops *ops;
/* for dmaengine */
struct dma_chan *chan_tx;
struct dma_chan *chan_rx;
- int irq;
unsigned dma_width_16bit:1;
unsigned dma_callbacked:1;
+ unsigned byte_access:1;
};
static void rspi_write8(const struct rspi_data *rspi, u8 data, u16 offset)
@@ -224,34 +231,47 @@ static u16 rspi_read16(const struct rspi_data *rspi, u16 offset)
return ioread16(rspi->addr + offset);
}
+static void rspi_write_data(const struct rspi_data *rspi, u16 data)
+{
+ if (rspi->byte_access)
+ rspi_write8(rspi, data, RSPI_SPDR);
+ else /* 16 bit */
+ rspi_write16(rspi, data, RSPI_SPDR);
+}
+
+static u16 rspi_read_data(const struct rspi_data *rspi)
+{
+ if (rspi->byte_access)
+ return rspi_read8(rspi, RSPI_SPDR);
+ else /* 16 bit */
+ return rspi_read16(rspi, RSPI_SPDR);
+}
+
/* optional functions */
struct spi_ops {
- int (*set_config_register)(const struct rspi_data *rspi,
- int access_size);
- int (*send_pio)(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t);
- int (*receive_pio)(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t);
-
+ int (*set_config_register)(struct rspi_data *rspi, int access_size);
+ int (*transfer_one)(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer);
+ u16 mode_bits;
};
/*
- * functions for RSPI
+ * functions for RSPI on legacy SH
*/
-static int rspi_set_config_register(const struct rspi_data *rspi,
- int access_size)
+static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
{
int spbr;
- /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
- rspi_write8(rspi, 0x00, RSPI_SPPCR);
+ /* Sets output mode, MOSI signal, and (optionally) loopback */
+ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
/* Sets transfer bit rate */
spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
- /* Sets number of frames to be used: 1 frame */
- rspi_write8(rspi, 0x00, RSPI_SPDCR);
+ /* Disable dummy transmission, set 16-bit word access, 1 frame */
+ rspi_write8(rspi, 0, RSPI_SPDCR);
+ rspi->byte_access = 0;
/* Sets RSPCK, SSL, next-access delay value */
rspi_write8(rspi, 0x00, RSPI_SPCKD);
@@ -262,8 +282,41 @@ static int rspi_set_config_register(const struct rspi_data *rspi,
rspi_write8(rspi, 0x00, RSPI_SPCR2);
/* Sets SPCMD */
- rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | rspi->spcmd,
- RSPI_SPCMD0);
+ rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
+
+ /* Sets RSPI mode */
+ rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
+
+ return 0;
+}
+
+/*
+ * functions for RSPI on RZ
+ */
+static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size)
+{
+ int spbr;
+
+ /* Sets output mode, MOSI signal, and (optionally) loopback */
+ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
+
+ /* Sets transfer bit rate */
+ spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
+ rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
+
+ /* Disable dummy transmission, set byte access */
+ rspi_write8(rspi, SPDCR_SPLBYTE, RSPI_SPDCR);
+ rspi->byte_access = 1;
+
+ /* Sets RSPCK, SSL, next-access delay value */
+ rspi_write8(rspi, 0x00, RSPI_SPCKD);
+ rspi_write8(rspi, 0x00, RSPI_SSLND);
+ rspi_write8(rspi, 0x00, RSPI_SPND);
+
+ /* Sets SPCMD */
+ rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
/* Sets RSPI mode */
rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
@@ -274,21 +327,20 @@ static int rspi_set_config_register(const struct rspi_data *rspi,
/*
* functions for QSPI
*/
-static int qspi_set_config_register(const struct rspi_data *rspi,
- int access_size)
+static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
{
- u16 spcmd;
int spbr;
- /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
- rspi_write8(rspi, 0x00, RSPI_SPPCR);
+ /* Sets output mode, MOSI signal, and (optionally) loopback */
+ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
/* Sets transfer bit rate */
spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz);
rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
- /* Sets number of frames to be used: 1 frame */
- rspi_write8(rspi, 0x00, RSPI_SPDCR);
+ /* Disable dummy transmission, set byte access */
+ rspi_write8(rspi, 0, RSPI_SPDCR);
+ rspi->byte_access = 1;
/* Sets RSPCK, SSL, next-access delay value */
rspi_write8(rspi, 0x00, RSPI_SPCKD);
@@ -297,13 +349,13 @@ static int qspi_set_config_register(const struct rspi_data *rspi,
/* Data Length Setting */
if (access_size == 8)
- spcmd = SPCMD_SPB_8BIT;
+ rspi->spcmd |= SPCMD_SPB_8BIT;
else if (access_size == 16)
- spcmd = SPCMD_SPB_16BIT;
+ rspi->spcmd |= SPCMD_SPB_16BIT;
else
- spcmd = SPCMD_SPB_32BIT;
+ rspi->spcmd |= SPCMD_SPB_32BIT;
- spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | rspi->spcmd | SPCMD_SPNDEN;
+ rspi->spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SPNDEN;
/* Resets transfer data length */
rspi_write32(rspi, 0, QSPI_SPBMUL0);
@@ -314,9 +366,9 @@ static int qspi_set_config_register(const struct rspi_data *rspi,
rspi_write8(rspi, 0x00, QSPI_SPBFCR);
/* Sets SPCMD */
- rspi_write16(rspi, spcmd, RSPI_SPCMD0);
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
- /* Enables SPI function in a master mode */
+ /* Enables SPI function in master mode */
rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR);
return 0;
@@ -340,6 +392,9 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask,
int ret;
rspi->spsr = rspi_read8(rspi, RSPI_SPSR);
+ if (rspi->spsr & wait_mask)
+ return 0;
+
rspi_enable_irq(rspi, enable_bit);
ret = wait_event_timeout(rspi->wait, rspi->spsr & wait_mask, HZ);
if (ret == 0 && !(rspi->spsr & wait_mask))
@@ -348,78 +403,39 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask,
return 0;
}
-static void rspi_assert_ssl(const struct rspi_data *rspi)
-{
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR);
-}
-
-static void rspi_negate_ssl(const struct rspi_data *rspi)
+static int rspi_data_out(struct rspi_data *rspi, u8 data)
{
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
+ if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
+ dev_err(&rspi->master->dev, "transmit timeout\n");
+ return -ETIMEDOUT;
+ }
+ rspi_write_data(rspi, data);
+ return 0;
}
-static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static int rspi_data_in(struct rspi_data *rspi)
{
- int remain = t->len;
- const u8 *data = t->tx_buf;
- while (remain > 0) {
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD,
- RSPI_SPCR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
+ u8 data;
- rspi_write16(rspi, *data, RSPI_SPDR);
- data++;
- remain--;
+ if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
+ dev_err(&rspi->master->dev, "receive timeout\n");
+ return -ETIMEDOUT;
}
-
- /* Waiting for the last transmission */
- rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
-
- return 0;
+ data = rspi_read_data(rspi);
+ return data;
}
-static int qspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static int rspi_data_out_in(struct rspi_data *rspi, u8 data)
{
- int remain = t->len;
- const u8 *data = t->tx_buf;
-
- rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR);
- rspi_write8(rspi, 0x00, QSPI_SPBFCR);
-
- while (remain > 0) {
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
- rspi_write8(rspi, *data++, RSPI_SPDR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: receive timeout\n", __func__);
- return -ETIMEDOUT;
- }
- rspi_read8(rspi, RSPI_SPDR);
-
- remain--;
- }
+ int ret;
- /* Waiting for the last transmission */
- rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+ ret = rspi_data_out(rspi, data);
+ if (ret < 0)
+ return ret;
- return 0;
+ return rspi_data_in(rspi);
}
-#define send_pio(spi, mesg, t) spi->ops->send_pio(spi, mesg, t)
-
static void rspi_dma_complete(void *arg)
{
struct rspi_data *rspi = arg;
@@ -471,7 +487,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
struct scatterlist sg;
const void *buf = NULL;
struct dma_async_tx_descriptor *desc;
- unsigned len;
+ unsigned int len;
int ret = 0;
if (rspi->dma_width_16bit) {
@@ -509,7 +525,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
* DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
* called. So, this driver disables the IRQ while DMA transfer.
*/
- disable_irq(rspi->irq);
+ disable_irq(rspi->tx_irq);
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR);
rspi_enable_irq(rspi, SPCR_SPTIE);
@@ -528,7 +544,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
ret = -ETIMEDOUT;
rspi_disable_irq(rspi, SPCR_SPTIE);
- enable_irq(rspi->irq);
+ enable_irq(rspi->tx_irq);
end:
rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE);
@@ -545,46 +561,17 @@ static void rspi_receive_init(const struct rspi_data *rspi)
spsr = rspi_read8(rspi, RSPI_SPSR);
if (spsr & SPSR_SPRF)
- rspi_read16(rspi, RSPI_SPDR); /* dummy read */
+ rspi_read_data(rspi); /* dummy read */
if (spsr & SPSR_OVRF)
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF,
RSPI_SPSR);
}
-static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static void rspi_rz_receive_init(const struct rspi_data *rspi)
{
- int remain = t->len;
- u8 *data;
-
rspi_receive_init(rspi);
-
- data = t->rx_buf;
- while (remain > 0) {
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD,
- RSPI_SPCR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
- /* dummy write for generate clock */
- rspi_write16(rspi, DUMMY_DATA, RSPI_SPDR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: receive timeout\n", __func__);
- return -ETIMEDOUT;
- }
- /* SPDR allows 16 or 32-bit access only */
- *data = (u8)rspi_read16(rspi, RSPI_SPDR);
-
- data++;
- remain--;
- }
-
- return 0;
+ rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, RSPI_SPBFCR);
+ rspi_write8(rspi, 0, RSPI_SPBFCR);
}
static void qspi_receive_init(const struct rspi_data *rspi)
@@ -593,51 +580,17 @@ static void qspi_receive_init(const struct rspi_data *rspi)
spsr = rspi_read8(rspi, RSPI_SPSR);
if (spsr & SPSR_SPRF)
- rspi_read8(rspi, RSPI_SPDR); /* dummy read */
+ rspi_read_data(rspi); /* dummy read */
rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
- rspi_write8(rspi, 0x00, QSPI_SPBFCR);
+ rspi_write8(rspi, 0, QSPI_SPBFCR);
}
-static int qspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
-{
- int remain = t->len;
- u8 *data;
-
- qspi_receive_init(rspi);
-
- data = t->rx_buf;
- while (remain > 0) {
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
- /* dummy write for generate clock */
- rspi_write8(rspi, DUMMY_DATA, RSPI_SPDR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: receive timeout\n", __func__);
- return -ETIMEDOUT;
- }
- /* SPDR allows 8, 16 or 32-bit access */
- *data++ = rspi_read8(rspi, RSPI_SPDR);
- remain--;
- }
-
- return 0;
-}
-
-#define receive_pio(spi, mesg, t) spi->ops->receive_pio(spi, mesg, t)
-
static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
{
struct scatterlist sg, sg_dummy;
void *dummy = NULL, *rx_buf = NULL;
struct dma_async_tx_descriptor *desc, *desc_dummy;
- unsigned len;
+ unsigned int len;
int ret = 0;
if (rspi->dma_width_16bit) {
@@ -695,7 +648,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
* DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
* called. So, this driver disables the IRQ while DMA transfer.
*/
- disable_irq(rspi->irq);
+ disable_irq(rspi->tx_irq);
+ if (rspi->rx_irq != rspi->tx_irq)
+ disable_irq(rspi->rx_irq);
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR);
rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
@@ -718,7 +673,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
ret = -ETIMEDOUT;
rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
- enable_irq(rspi->irq);
+ enable_irq(rspi->tx_irq);
+ if (rspi->rx_irq != rspi->tx_irq)
+ enable_irq(rspi->rx_irq);
end:
rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE);
@@ -746,56 +703,175 @@ static int rspi_is_dma(const struct rspi_data *rspi, struct spi_transfer *t)
return 0;
}
-static void rspi_work(struct work_struct *work)
+static int rspi_transfer_out_in(struct rspi_data *rspi,
+ struct spi_transfer *xfer)
{
- struct rspi_data *rspi = container_of(work, struct rspi_data, ws);
- struct spi_message *mesg;
- struct spi_transfer *t;
- unsigned long flags;
- int ret;
+ int remain = xfer->len, ret;
+ const u8 *tx_buf = xfer->tx_buf;
+ u8 *rx_buf = xfer->rx_buf;
+ u8 spcr, data;
- while (1) {
- spin_lock_irqsave(&rspi->lock, flags);
- if (list_empty(&rspi->queue)) {
- spin_unlock_irqrestore(&rspi->lock, flags);
- break;
- }
- mesg = list_entry(rspi->queue.next, struct spi_message, queue);
- list_del_init(&mesg->queue);
- spin_unlock_irqrestore(&rspi->lock, flags);
-
- rspi_assert_ssl(rspi);
-
- list_for_each_entry(t, &mesg->transfers, transfer_list) {
- if (t->tx_buf) {
- if (rspi_is_dma(rspi, t))
- ret = rspi_send_dma(rspi, t);
- else
- ret = send_pio(rspi, mesg, t);
- if (ret < 0)
- goto error;
- }
- if (t->rx_buf) {
- if (rspi_is_dma(rspi, t))
- ret = rspi_receive_dma(rspi, t);
- else
- ret = receive_pio(rspi, mesg, t);
- if (ret < 0)
- goto error;
- }
- mesg->actual_length += t->len;
+ rspi_receive_init(rspi);
+
+ spcr = rspi_read8(rspi, RSPI_SPCR);
+ if (rx_buf)
+ spcr &= ~SPCR_TXMD;
+ else
+ spcr |= SPCR_TXMD;
+ rspi_write8(rspi, spcr, RSPI_SPCR);
+
+ while (remain > 0) {
+ data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+ ret = rspi_data_out(rspi, data);
+ if (ret < 0)
+ return ret;
+ if (rx_buf) {
+ ret = rspi_data_in(rspi);
+ if (ret < 0)
+ return ret;
+ *rx_buf++ = ret;
}
- rspi_negate_ssl(rspi);
+ remain--;
+ }
+
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+ return 0;
+}
+
+static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+ int ret;
+
+ if (!rspi_is_dma(rspi, xfer))
+ return rspi_transfer_out_in(rspi, xfer);
+
+ if (xfer->tx_buf) {
+ ret = rspi_send_dma(rspi, xfer);
+ if (ret < 0)
+ return ret;
+ }
+ if (xfer->rx_buf)
+ return rspi_receive_dma(rspi, xfer);
+
+ return 0;
+}
+
+static int rspi_rz_transfer_out_in(struct rspi_data *rspi,
+ struct spi_transfer *xfer)
+{
+ int remain = xfer->len, ret;
+ const u8 *tx_buf = xfer->tx_buf;
+ u8 *rx_buf = xfer->rx_buf;
+ u8 data;
+
+ rspi_rz_receive_init(rspi);
+
+ while (remain > 0) {
+ data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+ ret = rspi_data_out_in(rspi, data);
+ if (ret < 0)
+ return ret;
+ if (rx_buf)
+ *rx_buf++ = ret;
+ remain--;
+ }
+
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+ return 0;
+}
+
+static int rspi_rz_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+
+ return rspi_rz_transfer_out_in(rspi, xfer);
+}
+
+static int qspi_transfer_out_in(struct rspi_data *rspi,
+ struct spi_transfer *xfer)
+{
+ int remain = xfer->len, ret;
+ const u8 *tx_buf = xfer->tx_buf;
+ u8 *rx_buf = xfer->rx_buf;
+ u8 data;
- mesg->status = 0;
- mesg->complete(mesg->context);
+ qspi_receive_init(rspi);
+
+ while (remain > 0) {
+ data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+ ret = rspi_data_out_in(rspi, data);
+ if (ret < 0)
+ return ret;
+ if (rx_buf)
+ *rx_buf++ = ret;
+ remain--;
+ }
+
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+ return 0;
+}
+
+static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer)
+{
+ const u8 *buf = xfer->tx_buf;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < xfer->len; i++) {
+ ret = rspi_data_out(rspi, *buf++);
+ if (ret < 0)
+ return ret;
}
- return;
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
-error:
- mesg->status = ret;
- mesg->complete(mesg->context);
+ return 0;
+}
+
+static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer)
+{
+ u8 *buf = xfer->rx_buf;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < xfer->len; i++) {
+ ret = rspi_data_in(rspi);
+ if (ret < 0)
+ return ret;
+ *buf++ = ret;
+ }
+
+ return 0;
+}
+
+static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+
+ if (spi->mode & SPI_LOOP) {
+ return qspi_transfer_out_in(rspi, xfer);
+ } else if (xfer->tx_buf && xfer->tx_nbits > SPI_NBITS_SINGLE) {
+ /* Quad or Dual SPI Write */
+ return qspi_transfer_out(rspi, xfer);
+ } else if (xfer->rx_buf && xfer->rx_nbits > SPI_NBITS_SINGLE) {
+ /* Quad or Dual SPI Read */
+ return qspi_transfer_in(rspi, xfer);
+ } else {
+ /* Single SPI Transfer */
+ return qspi_transfer_out_in(rspi, xfer);
+ }
}
static int rspi_setup(struct spi_device *spi)
@@ -810,32 +886,115 @@ static int rspi_setup(struct spi_device *spi)
if (spi->mode & SPI_CPHA)
rspi->spcmd |= SPCMD_CPHA;
+ /* CMOS output mode and MOSI signal from previous transfer */
+ rspi->sppcr = 0;
+ if (spi->mode & SPI_LOOP)
+ rspi->sppcr |= SPPCR_SPLP;
+
set_config_register(rspi, 8);
return 0;
}
-static int rspi_transfer(struct spi_device *spi, struct spi_message *mesg)
+static u16 qspi_transfer_mode(const struct spi_transfer *xfer)
{
- struct rspi_data *rspi = spi_master_get_devdata(spi->master);
- unsigned long flags;
+ if (xfer->tx_buf)
+ switch (xfer->tx_nbits) {
+ case SPI_NBITS_QUAD:
+ return SPCMD_SPIMOD_QUAD;
+ case SPI_NBITS_DUAL:
+ return SPCMD_SPIMOD_DUAL;
+ default:
+ return 0;
+ }
+ if (xfer->rx_buf)
+ switch (xfer->rx_nbits) {
+ case SPI_NBITS_QUAD:
+ return SPCMD_SPIMOD_QUAD | SPCMD_SPRW;
+ case SPI_NBITS_DUAL:
+ return SPCMD_SPIMOD_DUAL | SPCMD_SPRW;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
- mesg->actual_length = 0;
- mesg->status = -EINPROGRESS;
+static int qspi_setup_sequencer(struct rspi_data *rspi,
+ const struct spi_message *msg)
+{
+ const struct spi_transfer *xfer;
+ unsigned int i = 0, len = 0;
+ u16 current_mode = 0xffff, mode;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ mode = qspi_transfer_mode(xfer);
+ if (mode == current_mode) {
+ len += xfer->len;
+ continue;
+ }
+
+ /* Transfer mode change */
+ if (i) {
+ /* Set transfer data length of previous transfer */
+ rspi_write32(rspi, len, QSPI_SPBMUL(i - 1));
+ }
- spin_lock_irqsave(&rspi->lock, flags);
- list_add_tail(&mesg->queue, &rspi->queue);
- schedule_work(&rspi->ws);
- spin_unlock_irqrestore(&rspi->lock, flags);
+ if (i >= QSPI_NUM_SPCMD) {
+ dev_err(&msg->spi->dev,
+ "Too many different transfer modes");
+ return -EINVAL;
+ }
+
+ /* Program transfer mode for this transfer */
+ rspi_write16(rspi, rspi->spcmd | mode, RSPI_SPCMD(i));
+ current_mode = mode;
+ len = xfer->len;
+ i++;
+ }
+ if (i) {
+ /* Set final transfer data length and sequence length */
+ rspi_write32(rspi, len, QSPI_SPBMUL(i - 1));
+ rspi_write8(rspi, i - 1, RSPI_SPSCR);
+ }
return 0;
}
-static void rspi_cleanup(struct spi_device *spi)
+static int rspi_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+ int ret;
+
+ if (msg->spi->mode &
+ (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)) {
+ /* Setup sequencer for messages with multiple transfer modes */
+ ret = qspi_setup_sequencer(rspi, msg);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Enable SPI function in master mode */
+ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR);
+ return 0;
}
-static irqreturn_t rspi_irq(int irq, void *_sr)
+static int rspi_unprepare_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+
+ /* Disable SPI function */
+ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
+
+ /* Reset sequencer for Single SPI Transfers */
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
+ rspi_write8(rspi, 0, RSPI_SPSCR);
+ return 0;
+}
+
+static irqreturn_t rspi_irq_mux(int irq, void *_sr)
{
struct rspi_data *rspi = _sr;
u8 spsr;
@@ -857,6 +1016,36 @@ static irqreturn_t rspi_irq(int irq, void *_sr)
return ret;
}
+static irqreturn_t rspi_irq_rx(int irq, void *_sr)
+{
+ struct rspi_data *rspi = _sr;
+ u8 spsr;
+
+ rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
+ if (spsr & SPSR_SPRF) {
+ rspi_disable_irq(rspi, SPCR_SPRIE);
+ wake_up(&rspi->wait);
+ return IRQ_HANDLED;
+ }
+
+ return 0;
+}
+
+static irqreturn_t rspi_irq_tx(int irq, void *_sr)
+{
+ struct rspi_data *rspi = _sr;
+ u8 spsr;
+
+ rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
+ if (spsr & SPSR_SPTEF) {
+ rspi_disable_irq(rspi, SPCR_SPTIE);
+ wake_up(&rspi->wait);
+ return IRQ_HANDLED;
+ }
+
+ return 0;
+}
+
static int rspi_request_dma(struct rspi_data *rspi,
struct platform_device *pdev)
{
@@ -923,34 +1112,89 @@ static int rspi_remove(struct platform_device *pdev)
struct rspi_data *rspi = platform_get_drvdata(pdev);
rspi_release_dma(rspi);
- clk_disable(rspi->clk);
+ pm_runtime_disable(&pdev->dev);
return 0;
}
+static const struct spi_ops rspi_ops = {
+ .set_config_register = rspi_set_config_register,
+ .transfer_one = rspi_transfer_one,
+ .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP,
+};
+
+static const struct spi_ops rspi_rz_ops = {
+ .set_config_register = rspi_rz_set_config_register,
+ .transfer_one = rspi_rz_transfer_one,
+ .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP,
+};
+
+static const struct spi_ops qspi_ops = {
+ .set_config_register = qspi_set_config_register,
+ .transfer_one = qspi_transfer_one,
+ .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP |
+ SPI_TX_DUAL | SPI_TX_QUAD |
+ SPI_RX_DUAL | SPI_RX_QUAD,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id rspi_of_match[] = {
+ /* RSPI on legacy SH */
+ { .compatible = "renesas,rspi", .data = &rspi_ops },
+ /* RSPI on RZ/A1H */
+ { .compatible = "renesas,rspi-rz", .data = &rspi_rz_ops },
+ /* QSPI on R-Car Gen2 */
+ { .compatible = "renesas,qspi", .data = &qspi_ops },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, rspi_of_match);
+
+static int rspi_parse_dt(struct device *dev, struct spi_master *master)
+{
+ u32 num_cs;
+ int error;
+
+ /* Parse DT properties */
+ error = of_property_read_u32(dev->of_node, "num-cs", &num_cs);
+ if (error) {
+ dev_err(dev, "of_property_read_u32 num-cs failed %d\n", error);
+ return error;
+ }
+
+ master->num_chipselect = num_cs;
+ return 0;
+}
+#else
+#define rspi_of_match NULL
+static inline int rspi_parse_dt(struct device *dev, struct spi_master *master)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_OF */
+
+static int rspi_request_irq(struct device *dev, unsigned int irq,
+ irq_handler_t handler, const char *suffix,
+ void *dev_id)
+{
+ const char *base = dev_name(dev);
+ size_t len = strlen(base) + strlen(suffix) + 2;
+ char *name = devm_kzalloc(dev, len, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+ snprintf(name, len, "%s:%s", base, suffix);
+ return devm_request_irq(dev, irq, handler, 0, name, dev_id);
+}
+
static int rspi_probe(struct platform_device *pdev)
{
struct resource *res;
struct spi_master *master;
struct rspi_data *rspi;
- int ret, irq;
- char clk_name[16];
- const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev);
+ int ret;
+ const struct of_device_id *of_id;
+ const struct rspi_plat_data *rspi_pd;
const struct spi_ops *ops;
- const struct platform_device_id *id_entry = pdev->id_entry;
-
- ops = (struct spi_ops *)id_entry->driver_data;
- /* ops parameter check */
- if (!ops->set_config_register) {
- dev_err(&pdev->dev, "there is no set_config_register\n");
- return -ENODEV;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "platform_get_irq error\n");
- return -ENODEV;
- }
master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data));
if (master == NULL) {
@@ -958,6 +1202,28 @@ static int rspi_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ of_id = of_match_device(rspi_of_match, &pdev->dev);
+ if (of_id) {
+ ops = of_id->data;
+ ret = rspi_parse_dt(&pdev->dev, master);
+ if (ret)
+ goto error1;
+ } else {
+ ops = (struct spi_ops *)pdev->id_entry->driver_data;
+ rspi_pd = dev_get_platdata(&pdev->dev);
+ if (rspi_pd && rspi_pd->num_chipselect)
+ master->num_chipselect = rspi_pd->num_chipselect;
+ else
+ master->num_chipselect = 2; /* default */
+ };
+
+ /* ops parameter check */
+ if (!ops->set_config_register) {
+ dev_err(&pdev->dev, "there is no set_config_register\n");
+ ret = -ENODEV;
+ goto error1;
+ }
+
rspi = spi_master_get_devdata(master);
platform_set_drvdata(pdev, rspi);
rspi->ops = ops;
@@ -970,39 +1236,61 @@ static int rspi_probe(struct platform_device *pdev)
goto error1;
}
- snprintf(clk_name, sizeof(clk_name), "%s%d", id_entry->name, pdev->id);
- rspi->clk = devm_clk_get(&pdev->dev, clk_name);
+ rspi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(rspi->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
ret = PTR_ERR(rspi->clk);
goto error1;
}
- clk_enable(rspi->clk);
- INIT_LIST_HEAD(&rspi->queue);
- spin_lock_init(&rspi->lock);
- INIT_WORK(&rspi->ws, rspi_work);
- init_waitqueue_head(&rspi->wait);
+ pm_runtime_enable(&pdev->dev);
- if (rspi_pd && rspi_pd->num_chipselect)
- master->num_chipselect = rspi_pd->num_chipselect;
- else
- master->num_chipselect = 2; /* default */
+ init_waitqueue_head(&rspi->wait);
master->bus_num = pdev->id;
master->setup = rspi_setup;
- master->transfer = rspi_transfer;
- master->cleanup = rspi_cleanup;
- master->mode_bits = SPI_CPHA | SPI_CPOL;
+ master->auto_runtime_pm = true;
+ master->transfer_one = ops->transfer_one;
+ master->prepare_message = rspi_prepare_message;
+ master->unprepare_message = rspi_unprepare_message;
+ master->mode_bits = ops->mode_bits;
+ master->dev.of_node = pdev->dev.of_node;
+
+ ret = platform_get_irq_byname(pdev, "rx");
+ if (ret < 0) {
+ ret = platform_get_irq_byname(pdev, "mux");
+ if (ret < 0)
+ ret = platform_get_irq(pdev, 0);
+ if (ret >= 0)
+ rspi->rx_irq = rspi->tx_irq = ret;
+ } else {
+ rspi->rx_irq = ret;
+ ret = platform_get_irq_byname(pdev, "tx");
+ if (ret >= 0)
+ rspi->tx_irq = ret;
+ }
+ if (ret < 0) {
+ dev_err(&pdev->dev, "platform_get_irq error\n");
+ goto error2;
+ }
- ret = devm_request_irq(&pdev->dev, irq, rspi_irq, 0,
- dev_name(&pdev->dev), rspi);
+ if (rspi->rx_irq == rspi->tx_irq) {
+ /* Single multiplexed interrupt */
+ ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_mux,
+ "mux", rspi);
+ } else {
+ /* Multi-interrupt mode, only SPRI and SPTI are used */
+ ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_rx,
+ "rx", rspi);
+ if (!ret)
+ ret = rspi_request_irq(&pdev->dev, rspi->tx_irq,
+ rspi_irq_tx, "tx", rspi);
+ }
if (ret < 0) {
dev_err(&pdev->dev, "request_irq error\n");
goto error2;
}
- rspi->irq = irq;
ret = rspi_request_dma(rspi, pdev);
if (ret < 0) {
dev_err(&pdev->dev, "rspi_request_dma failed.\n");
@@ -1022,27 +1310,16 @@ static int rspi_probe(struct platform_device *pdev)
error3:
rspi_release_dma(rspi);
error2:
- clk_disable(rspi->clk);
+ pm_runtime_disable(&pdev->dev);
error1:
spi_master_put(master);
return ret;
}
-static struct spi_ops rspi_ops = {
- .set_config_register = rspi_set_config_register,
- .send_pio = rspi_send_pio,
- .receive_pio = rspi_receive_pio,
-};
-
-static struct spi_ops qspi_ops = {
- .set_config_register = qspi_set_config_register,
- .send_pio = qspi_send_pio,
- .receive_pio = qspi_receive_pio,
-};
-
static struct platform_device_id spi_driver_ids[] = {
{ "rspi", (kernel_ulong_t)&rspi_ops },
+ { "rspi-rz", (kernel_ulong_t)&rspi_rz_ops },
{ "qspi", (kernel_ulong_t)&qspi_ops },
{},
};
@@ -1056,6 +1333,7 @@ static struct platform_driver rspi_driver = {
.driver = {
.name = "renesas_spi",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rspi_of_match),
},
};
module_platform_driver(rspi_driver);
diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c
index 746424aa5353..bed23384dfab 100644
--- a/drivers/spi/spi-s3c24xx.c
+++ b/drivers/spi/spi-s3c24xx.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
@@ -123,25 +122,15 @@ static int s3c24xx_spi_update_state(struct spi_device *spi,
{
struct s3c24xx_spi *hw = to_hw(spi);
struct s3c24xx_spi_devstate *cs = spi->controller_state;
- unsigned int bpw;
unsigned int hz;
unsigned int div;
unsigned long clk;
- bpw = t ? t->bits_per_word : spi->bits_per_word;
hz = t ? t->speed_hz : spi->max_speed_hz;
- if (!bpw)
- bpw = 8;
-
if (!hz)
hz = spi->max_speed_hz;
- if (bpw != 8) {
- dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
- return -EINVAL;
- }
-
if (spi->mode != cs->mode) {
u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK;
@@ -544,6 +533,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
master->num_chipselect = hw->pdata->num_cs;
master->bus_num = pdata->bus_num;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
/* setup the state for the bitbang driver */
@@ -643,6 +633,11 @@ static int s3c24xx_spi_remove(struct platform_device *dev)
static int s3c24xx_spi_suspend(struct device *dev)
{
struct s3c24xx_spi *hw = dev_get_drvdata(dev);
+ int ret;
+
+ ret = spi_master_suspend(hw->master);
+ if (ret)
+ return ret;
if (hw->pdata && hw->pdata->gpio_setup)
hw->pdata->gpio_setup(hw->pdata, 0);
@@ -656,7 +651,7 @@ static int s3c24xx_spi_resume(struct device *dev)
struct s3c24xx_spi *hw = dev_get_drvdata(dev);
s3c24xx_spi_initialsetup(hw);
- return 0;
+ return spi_master_resume(hw->master);
}
static const struct dev_pm_ops s3c24xx_spi_pmops = {
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index ae907dde1371..f19cd97855e8 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -34,10 +34,6 @@
#include <linux/platform_data/spi-s3c64xx.h>
-#ifdef CONFIG_S3C_DMA
-#include <mach/dma.h>
-#endif
-
#define MAX_SPI_PORTS 3
#define S3C64XX_SPI_QUIRK_POLL (1 << 0)
@@ -200,9 +196,6 @@ struct s3c64xx_spi_driver_data {
unsigned cur_speed;
struct s3c64xx_spi_dma_data rx_dma;
struct s3c64xx_spi_dma_data tx_dma;
-#ifdef CONFIG_S3C_DMA
- struct samsung_dma_ops *ops;
-#endif
struct s3c64xx_spi_port_config *port_conf;
unsigned int port_id;
bool cs_gpio;
@@ -284,104 +277,8 @@ static void s3c64xx_spi_dmacb(void *data)
spin_unlock_irqrestore(&sdd->lock, flags);
}
-#ifdef CONFIG_S3C_DMA
-/* FIXME: remove this section once arch/arm/mach-s3c64xx uses dmaengine */
-
-static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
- .name = "samsung-spi-dma",
-};
-
-static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
- unsigned len, dma_addr_t buf)
-{
- struct s3c64xx_spi_driver_data *sdd;
- struct samsung_dma_prep info;
- struct samsung_dma_config config;
-
- if (dma->direction == DMA_DEV_TO_MEM) {
- sdd = container_of((void *)dma,
- struct s3c64xx_spi_driver_data, rx_dma);
- config.direction = sdd->rx_dma.direction;
- config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
- config.width = sdd->cur_bpw / 8;
- sdd->ops->config((enum dma_ch)sdd->rx_dma.ch, &config);
- } else {
- sdd = container_of((void *)dma,
- struct s3c64xx_spi_driver_data, tx_dma);
- config.direction = sdd->tx_dma.direction;
- config.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
- config.width = sdd->cur_bpw / 8;
- sdd->ops->config((enum dma_ch)sdd->tx_dma.ch, &config);
- }
-
- info.cap = DMA_SLAVE;
- info.len = len;
- info.fp = s3c64xx_spi_dmacb;
- info.fp_param = dma;
- info.direction = dma->direction;
- info.buf = buf;
-
- sdd->ops->prepare((enum dma_ch)dma->ch, &info);
- sdd->ops->trigger((enum dma_ch)dma->ch);
-}
-
-static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
-{
- struct samsung_dma_req req;
- struct device *dev = &sdd->pdev->dev;
-
- sdd->ops = samsung_dma_get_ops();
-
- req.cap = DMA_SLAVE;
- req.client = &s3c64xx_spi_dma_client;
-
- sdd->rx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
- sdd->rx_dma.dmach, &req, dev, "rx");
- sdd->tx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
- sdd->tx_dma.dmach, &req, dev, "tx");
-
- return 1;
-}
-
-static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
-{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-
- /*
- * If DMA resource was not available during
- * probe, no need to continue with dma requests
- * else Acquire DMA channels
- */
- while (!is_polling(sdd) && !acquire_dma(sdd))
- usleep_range(10000, 11000);
-
- return 0;
-}
-
-static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
-{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-
- /* Free DMA channels */
- if (!is_polling(sdd)) {
- sdd->ops->release((enum dma_ch)sdd->rx_dma.ch,
- &s3c64xx_spi_dma_client);
- sdd->ops->release((enum dma_ch)sdd->tx_dma.ch,
- &s3c64xx_spi_dma_client);
- }
-
- return 0;
-}
-
-static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
- struct s3c64xx_spi_dma_data *dma)
-{
- sdd->ops->stop((enum dma_ch)dma->ch);
-}
-#else
-
static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
- unsigned len, dma_addr_t buf)
+ struct sg_table *sgt)
{
struct s3c64xx_spi_driver_data *sdd;
struct dma_slave_config config;
@@ -407,8 +304,8 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
dmaengine_slave_config(dma->ch, &config);
}
- desc = dmaengine_prep_slave_single(dma->ch, buf, len,
- dma->direction, DMA_PREP_INTERRUPT);
+ desc = dmaengine_prep_slave_sg(dma->ch, sgt->sgl, sgt->nents,
+ dma->direction, DMA_PREP_INTERRUPT);
desc->callback = s3c64xx_spi_dmacb;
desc->callback_param = dma;
@@ -437,6 +334,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
ret = -EBUSY;
goto out;
}
+ spi->dma_rx = sdd->rx_dma.ch;
sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
(void *)sdd->tx_dma.dmach, dev, "tx");
@@ -445,6 +343,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
ret = -EBUSY;
goto out_rx;
}
+ spi->dma_tx = sdd->tx_dma.ch;
}
ret = pm_runtime_get_sync(&sdd->pdev->dev);
@@ -477,12 +376,14 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
return 0;
}
-static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
- struct s3c64xx_spi_dma_data *dma)
+static bool s3c64xx_spi_can_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
{
- dmaengine_terminate_all(dma->ch);
+ struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+
+ return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1;
}
-#endif
static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
struct spi_device *spi,
@@ -515,7 +416,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
chcfg |= S3C64XX_SPI_CH_TXCH_ON;
if (dma_mode) {
modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
- prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma);
+ prepare_dma(&sdd->tx_dma, &xfer->tx_sg);
} else {
switch (sdd->cur_bpw) {
case 32:
@@ -547,7 +448,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
| S3C64XX_SPI_PACKET_CNT_EN,
regs + S3C64XX_SPI_PACKET_CNT);
- prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma);
+ prepare_dma(&sdd->rx_dma, &xfer->rx_sg);
}
}
@@ -555,23 +456,6 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
writel(chcfg, regs + S3C64XX_SPI_CH_CFG);
}
-static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
- struct spi_device *spi)
-{
- if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */
- if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
- /* Deselect the last toggled device */
- if (spi->cs_gpio >= 0)
- gpio_set_value(spi->cs_gpio,
- spi->mode & SPI_CS_HIGH ? 0 : 1);
- }
- sdd->tgl_spi = NULL;
- }
-
- if (spi->cs_gpio >= 0)
- gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0);
-}
-
static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
int timeout_ms)
{
@@ -593,112 +477,111 @@ static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
return RX_FIFO_LVL(status, sdd);
}
-static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
- struct spi_transfer *xfer, int dma_mode)
+static int wait_for_dma(struct s3c64xx_spi_driver_data *sdd,
+ struct spi_transfer *xfer)
{
void __iomem *regs = sdd->regs;
unsigned long val;
+ u32 status;
int ms;
/* millisecs to xfer 'len' bytes @ 'cur_speed' */
ms = xfer->len * 8 * 1000 / sdd->cur_speed;
ms += 10; /* some tolerance */
- if (dma_mode) {
- val = msecs_to_jiffies(ms) + 10;
- val = wait_for_completion_timeout(&sdd->xfer_completion, val);
- } else {
- u32 status;
- val = msecs_to_loops(ms);
- do {
+ val = msecs_to_jiffies(ms) + 10;
+ val = wait_for_completion_timeout(&sdd->xfer_completion, val);
+
+ /*
+ * If the previous xfer was completed within timeout, then
+ * proceed further else return -EIO.
+ * DmaTx returns after simply writing data in the FIFO,
+ * w/o waiting for real transmission on the bus to finish.
+ * DmaRx returns only after Dma read data from FIFO which
+ * needs bus transmission to finish, so we don't worry if
+ * Xfer involved Rx(with or without Tx).
+ */
+ if (val && !xfer->rx_buf) {
+ val = msecs_to_loops(10);
+ status = readl(regs + S3C64XX_SPI_STATUS);
+ while ((TX_FIFO_LVL(status, sdd)
+ || !S3C64XX_SPI_ST_TX_DONE(status, sdd))
+ && --val) {
+ cpu_relax();
status = readl(regs + S3C64XX_SPI_STATUS);
- } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
+ }
+
}
- if (dma_mode) {
- u32 status;
-
- /*
- * If the previous xfer was completed within timeout, then
- * proceed further else return -EIO.
- * DmaTx returns after simply writing data in the FIFO,
- * w/o waiting for real transmission on the bus to finish.
- * DmaRx returns only after Dma read data from FIFO which
- * needs bus transmission to finish, so we don't worry if
- * Xfer involved Rx(with or without Tx).
- */
- if (val && !xfer->rx_buf) {
- val = msecs_to_loops(10);
- status = readl(regs + S3C64XX_SPI_STATUS);
- while ((TX_FIFO_LVL(status, sdd)
- || !S3C64XX_SPI_ST_TX_DONE(status, sdd))
- && --val) {
- cpu_relax();
- status = readl(regs + S3C64XX_SPI_STATUS);
- }
+ /* If timed out while checking rx/tx status return error */
+ if (!val)
+ return -EIO;
- }
+ return 0;
+}
- /* If timed out while checking rx/tx status return error */
- if (!val)
- return -EIO;
- } else {
- int loops;
- u32 cpy_len;
- u8 *buf;
-
- /* If it was only Tx */
- if (!xfer->rx_buf) {
- sdd->state &= ~TXBUSY;
- return 0;
- }
+static int wait_for_pio(struct s3c64xx_spi_driver_data *sdd,
+ struct spi_transfer *xfer)
+{
+ void __iomem *regs = sdd->regs;
+ unsigned long val;
+ u32 status;
+ int loops;
+ u32 cpy_len;
+ u8 *buf;
+ int ms;
- /*
- * If the receive length is bigger than the controller fifo
- * size, calculate the loops and read the fifo as many times.
- * loops = length / max fifo size (calculated by using the
- * fifo mask).
- * For any size less than the fifo size the below code is
- * executed atleast once.
- */
- loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
- buf = xfer->rx_buf;
- do {
- /* wait for data to be received in the fifo */
- cpy_len = s3c64xx_spi_wait_for_timeout(sdd,
- (loops ? ms : 0));
+ /* millisecs to xfer 'len' bytes @ 'cur_speed' */
+ ms = xfer->len * 8 * 1000 / sdd->cur_speed;
+ ms += 10; /* some tolerance */
- switch (sdd->cur_bpw) {
- case 32:
- ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
- buf, cpy_len / 4);
- break;
- case 16:
- ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
- buf, cpy_len / 2);
- break;
- default:
- ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
- buf, cpy_len);
- break;
- }
+ val = msecs_to_loops(ms);
+ do {
+ status = readl(regs + S3C64XX_SPI_STATUS);
+ } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
- buf = buf + cpy_len;
- } while (loops--);
- sdd->state &= ~RXBUSY;
+
+ /* If it was only Tx */
+ if (!xfer->rx_buf) {
+ sdd->state &= ~TXBUSY;
+ return 0;
}
- return 0;
-}
+ /*
+ * If the receive length is bigger than the controller fifo
+ * size, calculate the loops and read the fifo as many times.
+ * loops = length / max fifo size (calculated by using the
+ * fifo mask).
+ * For any size less than the fifo size the below code is
+ * executed atleast once.
+ */
+ loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
+ buf = xfer->rx_buf;
+ do {
+ /* wait for data to be received in the fifo */
+ cpy_len = s3c64xx_spi_wait_for_timeout(sdd,
+ (loops ? ms : 0));
+
+ switch (sdd->cur_bpw) {
+ case 32:
+ ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
+ buf, cpy_len / 4);
+ break;
+ case 16:
+ ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
+ buf, cpy_len / 2);
+ break;
+ default:
+ ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
+ buf, cpy_len);
+ break;
+ }
-static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
- struct spi_device *spi)
-{
- if (sdd->tgl_spi == spi)
- sdd->tgl_spi = NULL;
+ buf = buf + cpy_len;
+ } while (loops--);
+ sdd->state &= ~RXBUSY;
- if (spi->cs_gpio >= 0)
- gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1);
+ return 0;
}
static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
@@ -774,81 +657,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
#define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
-static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
- struct spi_message *msg)
-{
- struct device *dev = &sdd->pdev->dev;
- struct spi_transfer *xfer;
-
- if (is_polling(sdd) || msg->is_dma_mapped)
- return 0;
-
- /* First mark all xfer unmapped */
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- xfer->rx_dma = XFER_DMAADDR_INVALID;
- xfer->tx_dma = XFER_DMAADDR_INVALID;
- }
-
- /* Map until end or first fail */
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-
- if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
- continue;
-
- if (xfer->tx_buf != NULL) {
- xfer->tx_dma = dma_map_single(dev,
- (void *)xfer->tx_buf, xfer->len,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dev, xfer->tx_dma)) {
- dev_err(dev, "dma_map_single Tx failed\n");
- xfer->tx_dma = XFER_DMAADDR_INVALID;
- return -ENOMEM;
- }
- }
-
- if (xfer->rx_buf != NULL) {
- xfer->rx_dma = dma_map_single(dev, xfer->rx_buf,
- xfer->len, DMA_FROM_DEVICE);
- if (dma_mapping_error(dev, xfer->rx_dma)) {
- dev_err(dev, "dma_map_single Rx failed\n");
- dma_unmap_single(dev, xfer->tx_dma,
- xfer->len, DMA_TO_DEVICE);
- xfer->tx_dma = XFER_DMAADDR_INVALID;
- xfer->rx_dma = XFER_DMAADDR_INVALID;
- return -ENOMEM;
- }
- }
- }
-
- return 0;
-}
-
-static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
- struct spi_message *msg)
-{
- struct device *dev = &sdd->pdev->dev;
- struct spi_transfer *xfer;
-
- if (is_polling(sdd) || msg->is_dma_mapped)
- return;
-
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-
- if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
- continue;
-
- if (xfer->rx_buf != NULL
- && xfer->rx_dma != XFER_DMAADDR_INVALID)
- dma_unmap_single(dev, xfer->rx_dma,
- xfer->len, DMA_FROM_DEVICE);
-
- if (xfer->tx_buf != NULL
- && xfer->tx_dma != XFER_DMAADDR_INVALID)
- dma_unmap_single(dev, xfer->tx_dma,
- xfer->len, DMA_TO_DEVICE);
- }
-}
-
static int s3c64xx_spi_prepare_message(struct spi_master *master,
struct spi_message *msg)
{
@@ -866,13 +674,6 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master,
s3c64xx_spi_config(sdd);
}
- /* Map all the transfers if needed */
- if (s3c64xx_spi_map_mssg(sdd, msg)) {
- dev_err(&spi->dev,
- "Xfer: Unable to map message buffers!\n");
- return -ENOMEM;
- }
-
/* Configure feedback delay */
writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
@@ -896,13 +697,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
bpw = xfer->bits_per_word;
speed = xfer->speed_hz ? : spi->max_speed_hz;
- if (xfer->len % (bpw / 8)) {
- dev_err(&spi->dev,
- "Xfer length(%u) not a multiple of word size(%u)\n",
- xfer->len, bpw / 8);
- return -EIO;
- }
-
if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
sdd->cur_bpw = bpw;
sdd->cur_speed = speed;
@@ -929,7 +723,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
spin_unlock_irqrestore(&sdd->lock, flags);
- status = wait_for_xfer(sdd, xfer, use_dma);
+ if (use_dma)
+ status = wait_for_dma(sdd, xfer);
+ else
+ status = wait_for_pio(sdd, xfer);
if (status) {
dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
@@ -941,10 +738,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
if (use_dma) {
if (xfer->tx_buf != NULL
&& (sdd->state & TXBUSY))
- s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma);
+ dmaengine_terminate_all(sdd->tx_dma.ch);
if (xfer->rx_buf != NULL
&& (sdd->state & RXBUSY))
- s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma);
+ dmaengine_terminate_all(sdd->rx_dma.ch);
}
} else {
flush_fifo(sdd);
@@ -953,16 +750,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
return status;
}
-static int s3c64xx_spi_unprepare_message(struct spi_master *master,
- struct spi_message *msg)
-{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
-
- s3c64xx_spi_unmap_mssg(sdd, msg);
-
- return 0;
-}
-
static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
struct spi_device *spi)
{
@@ -1092,14 +879,12 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
pm_runtime_put(&sdd->pdev->dev);
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
- disable_cs(sdd, spi);
return 0;
setup_exit:
pm_runtime_put(&sdd->pdev->dev);
/* setup() returns with device de-selected */
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
- disable_cs(sdd, spi);
gpio_free(cs->line);
spi_set_ctldata(spi, NULL);
@@ -1338,7 +1123,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
master->prepare_message = s3c64xx_spi_prepare_message;
master->transfer_one = s3c64xx_spi_transfer_one;
- master->unprepare_message = s3c64xx_spi_unprepare_message;
master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
master->num_chipselect = sci->num_cs;
master->dma_alignment = 8;
@@ -1347,6 +1131,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->auto_runtime_pm = true;
+ if (!is_polling(sdd))
+ master->can_dma = s3c64xx_spi_can_dma;
sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(sdd->regs)) {
diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c
index 121c2e1dea36..237f2e7a7179 100644
--- a/drivers/spi/spi-sc18is602.c
+++ b/drivers/spi/spi-sc18is602.c
@@ -183,17 +183,9 @@ static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode)
static int sc18is602_check_transfer(struct spi_device *spi,
struct spi_transfer *t, int tlen)
{
- uint32_t hz;
-
if (t && t->len + tlen > SC18IS602_BUFSIZ)
return -EINVAL;
- hz = spi->max_speed_hz;
- if (t && t->speed_hz)
- hz = t->speed_hz;
- if (hz == 0)
- return -EINVAL;
-
return 0;
}
@@ -205,22 +197,15 @@ static int sc18is602_transfer_one(struct spi_master *master,
struct spi_transfer *t;
int status = 0;
- /* SC18IS602 does not support CS2 */
- if (hw->id == sc18is602 && spi->chip_select == 2) {
- status = -ENXIO;
- goto error;
- }
-
hw->tlen = 0;
list_for_each_entry(t, &m->transfers, transfer_list) {
- u32 hz = t->speed_hz ? : spi->max_speed_hz;
bool do_transfer;
status = sc18is602_check_transfer(spi, t, hw->tlen);
if (status < 0)
break;
- status = sc18is602_setup_transfer(hw, hz, spi->mode);
+ status = sc18is602_setup_transfer(hw, t->speed_hz, spi->mode);
if (status < 0)
break;
@@ -238,7 +223,6 @@ static int sc18is602_transfer_one(struct spi_master *master,
if (t->delay_usecs)
udelay(t->delay_usecs);
}
-error:
m->status = status;
spi_finalize_current_message(master);
@@ -247,10 +231,13 @@ error:
static int sc18is602_setup(struct spi_device *spi)
{
- if (spi->mode & ~(SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST))
- return -EINVAL;
+ struct sc18is602 *hw = spi_master_get_devdata(spi->master);
- return sc18is602_check_transfer(spi, NULL, 0);
+ /* SC18IS602 does not support CS2 */
+ if (hw->id == sc18is602 && spi->chip_select == 2)
+ return -ENXIO;
+
+ return 0;
}
static int sc18is602_probe(struct i2c_client *client,
@@ -309,6 +296,8 @@ static int sc18is602_probe(struct i2c_client *client,
master->setup = sc18is602_setup;
master->transfer_one_message = sc18is602_transfer_one;
master->dev.of_node = np;
+ master->min_speed_hz = hw->freq / 128;
+ master->max_speed_hz = hw->freq / 4;
error = devm_spi_register_master(dev, master);
if (error)
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index 82d2f922ffa0..9009456bdf4d 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -46,8 +46,6 @@
/* SPSR */
#define RXFL (1 << 2)
-#define hspi2info(h) (h->dev->platform_data)
-
struct hspi_priv {
void __iomem *addr;
struct spi_master *master;
@@ -113,14 +111,9 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
{
struct spi_device *spi = msg->spi;
struct device *dev = hspi->dev;
- u32 target_rate;
u32 spcr, idiv_clk;
u32 rate, best_rate, min, tmp;
- target_rate = t ? t->speed_hz : 0;
- if (!target_rate)
- target_rate = spi->max_speed_hz;
-
/*
* find best IDIV/CLKCx settings
*/
@@ -140,7 +133,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
rate /= (((idiv_clk & 0x1F) + 1) * 2);
/* save best settings */
- tmp = abs(target_rate - rate);
+ tmp = abs(t->speed_hz - rate);
if (tmp < min) {
min = tmp;
spcr = idiv_clk;
@@ -153,7 +146,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
if (spi->mode & SPI_CPOL)
spcr |= 1 << 6;
- dev_dbg(dev, "speed %d/%d\n", target_rate, best_rate);
+ dev_dbg(dev, "speed %d/%d\n", t->speed_hz, best_rate);
hspi_write(hspi, SPCR, spcr);
hspi_write(hspi, SPSR, 0x0);
@@ -230,29 +223,6 @@ static int hspi_transfer_one_message(struct spi_master *master,
return ret;
}
-static int hspi_setup(struct spi_device *spi)
-{
- struct hspi_priv *hspi = spi_master_get_devdata(spi->master);
- struct device *dev = hspi->dev;
-
- if (8 != spi->bits_per_word) {
- dev_err(dev, "bits_per_word should be 8\n");
- return -EIO;
- }
-
- dev_dbg(dev, "%s setup\n", spi->modalias);
-
- return 0;
-}
-
-static void hspi_cleanup(struct spi_device *spi)
-{
- struct hspi_priv *hspi = spi_master_get_devdata(spi->master);
- struct device *dev = hspi->dev;
-
- dev_dbg(dev, "%s cleanup\n", spi->modalias);
-}
-
static int hspi_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -298,22 +268,23 @@ static int hspi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
- master->num_chipselect = 1;
master->bus_num = pdev->id;
- master->setup = hspi_setup;
- master->cleanup = hspi_cleanup;
master->mode_bits = SPI_CPOL | SPI_CPHA;
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
master->transfer_one_message = hspi_transfer_one_message;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+
ret = devm_spi_register_master(&pdev->dev, master);
if (ret < 0) {
dev_err(&pdev->dev, "spi_register_master error.\n");
- goto error1;
+ goto error2;
}
return 0;
+ error2:
+ pm_runtime_disable(&pdev->dev);
error1:
clk_put(clk);
error0:
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 81cc02f5f9b0..e850d03e7190 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -15,59 +15,108 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.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/pm_runtime.h>
#include <linux/spi/sh_msiof.h>
#include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
#include <asm/unaligned.h>
+
+struct sh_msiof_chipdata {
+ u16 tx_fifo_size;
+ u16 rx_fifo_size;
+ u16 master_flags;
+};
+
struct sh_msiof_spi_priv {
- struct spi_bitbang bitbang; /* must be first for spi_bitbang.c */
void __iomem *mapbase;
struct clk *clk;
struct platform_device *pdev;
+ const struct sh_msiof_chipdata *chipdata;
struct sh_msiof_spi_info *info;
struct completion done;
- unsigned long flags;
int tx_fifo_size;
int rx_fifo_size;
};
-#define TMDR1 0x00
-#define TMDR2 0x04
-#define TMDR3 0x08
-#define RMDR1 0x10
-#define RMDR2 0x14
-#define RMDR3 0x18
-#define TSCR 0x20
-#define RSCR 0x22
-#define CTR 0x28
-#define FCTR 0x30
-#define STR 0x40
-#define IER 0x44
-#define TDR1 0x48
-#define TDR2 0x4c
-#define TFDR 0x50
-#define RDR1 0x58
-#define RDR2 0x5c
-#define RFDR 0x60
-
-#define CTR_TSCKE (1 << 15)
-#define CTR_TFSE (1 << 14)
-#define CTR_TXE (1 << 9)
-#define CTR_RXE (1 << 8)
-
-#define STR_TEOF (1 << 23)
-#define STR_REOF (1 << 7)
+#define TMDR1 0x00 /* Transmit Mode Register 1 */
+#define TMDR2 0x04 /* Transmit Mode Register 2 */
+#define TMDR3 0x08 /* Transmit Mode Register 3 */
+#define RMDR1 0x10 /* Receive Mode Register 1 */
+#define RMDR2 0x14 /* Receive Mode Register 2 */
+#define RMDR3 0x18 /* Receive Mode Register 3 */
+#define TSCR 0x20 /* Transmit Clock Select Register */
+#define RSCR 0x22 /* Receive Clock Select Register (SH, A1, APE6) */
+#define CTR 0x28 /* Control Register */
+#define FCTR 0x30 /* FIFO Control Register */
+#define STR 0x40 /* Status Register */
+#define IER 0x44 /* Interrupt Enable Register */
+#define TDR1 0x48 /* Transmit Control Data Register 1 (SH, A1) */
+#define TDR2 0x4c /* Transmit Control Data Register 2 (SH, A1) */
+#define TFDR 0x50 /* Transmit FIFO Data Register */
+#define RDR1 0x58 /* Receive Control Data Register 1 (SH, A1) */
+#define RDR2 0x5c /* Receive Control Data Register 2 (SH, A1) */
+#define RFDR 0x60 /* Receive FIFO Data Register */
+
+/* TMDR1 and RMDR1 */
+#define MDR1_TRMD 0x80000000 /* Transfer Mode (1 = Master mode) */
+#define MDR1_SYNCMD_MASK 0x30000000 /* SYNC Mode */
+#define MDR1_SYNCMD_SPI 0x20000000 /* Level mode/SPI */
+#define MDR1_SYNCMD_LR 0x30000000 /* L/R mode */
+#define MDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */
+#define MDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */
+#define MDR1_FLD_MASK 0x000000c0 /* Frame Sync Signal Interval (0-3) */
+#define MDR1_FLD_SHIFT 2
+#define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */
+/* TMDR1 */
+#define TMDR1_PCON 0x40000000 /* Transfer Signal Connection */
+
+/* TMDR2 and RMDR2 */
+#define MDR2_BITLEN1(i) (((i) - 1) << 24) /* Data Size (8-32 bits) */
+#define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */
+#define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */
+
+/* TSCR and RSCR */
+#define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */
+#define SCR_BRPS(i) (((i) - 1) << 8)
+#define SCR_BRDV_MASK 0x0007 /* Baud Rate Generator's Division Ratio */
+#define SCR_BRDV_DIV_2 0x0000
+#define SCR_BRDV_DIV_4 0x0001
+#define SCR_BRDV_DIV_8 0x0002
+#define SCR_BRDV_DIV_16 0x0003
+#define SCR_BRDV_DIV_32 0x0004
+#define SCR_BRDV_DIV_1 0x0007
+
+/* CTR */
+#define CTR_TSCKIZ_MASK 0xc0000000 /* Transmit Clock I/O Polarity Select */
+#define CTR_TSCKIZ_SCK 0x80000000 /* Disable SCK when TX disabled */
+#define CTR_TSCKIZ_POL_SHIFT 30 /* Transmit Clock Polarity */
+#define CTR_RSCKIZ_MASK 0x30000000 /* Receive Clock Polarity Select */
+#define CTR_RSCKIZ_SCK 0x20000000 /* Must match CTR_TSCKIZ_SCK */
+#define CTR_RSCKIZ_POL_SHIFT 28 /* Receive Clock Polarity */
+#define CTR_TEDG_SHIFT 27 /* Transmit Timing (1 = falling edge) */
+#define CTR_REDG_SHIFT 26 /* Receive Timing (1 = falling edge) */
+#define CTR_TXDIZ_MASK 0x00c00000 /* Pin Output When TX is Disabled */
+#define CTR_TXDIZ_LOW 0x00000000 /* 0 */
+#define CTR_TXDIZ_HIGH 0x00400000 /* 1 */
+#define CTR_TXDIZ_HIZ 0x00800000 /* High-impedance */
+#define CTR_TSCKE 0x00008000 /* Transmit Serial Clock Output Enable */
+#define CTR_TFSE 0x00004000 /* Transmit Frame Sync Signal Output Enable */
+#define CTR_TXE 0x00000200 /* Transmit Enable */
+#define CTR_RXE 0x00000100 /* Receive Enable */
+
+/* STR and IER */
+#define STR_TEOF 0x00800000 /* Frame Transmission End */
+#define STR_REOF 0x00000080 /* Frame Reception End */
+
static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs)
{
@@ -131,22 +180,21 @@ static struct {
unsigned short div;
unsigned short scr;
} const sh_msiof_spi_clk_table[] = {
- { 1, 0x0007 },
- { 2, 0x0000 },
- { 4, 0x0001 },
- { 8, 0x0002 },
- { 16, 0x0003 },
- { 32, 0x0004 },
- { 64, 0x1f00 },
- { 128, 0x1f01 },
- { 256, 0x1f02 },
- { 512, 0x1f03 },
- { 1024, 0x1f04 },
+ { 1, SCR_BRPS( 1) | SCR_BRDV_DIV_1 },
+ { 2, SCR_BRPS( 1) | SCR_BRDV_DIV_2 },
+ { 4, SCR_BRPS( 1) | SCR_BRDV_DIV_4 },
+ { 8, SCR_BRPS( 1) | SCR_BRDV_DIV_8 },
+ { 16, SCR_BRPS( 1) | SCR_BRDV_DIV_16 },
+ { 32, SCR_BRPS( 1) | SCR_BRDV_DIV_32 },
+ { 64, SCR_BRPS(32) | SCR_BRDV_DIV_2 },
+ { 128, SCR_BRPS(32) | SCR_BRDV_DIV_4 },
+ { 256, SCR_BRPS(32) | SCR_BRDV_DIV_8 },
+ { 512, SCR_BRPS(32) | SCR_BRDV_DIV_16 },
+ { 1024, SCR_BRPS(32) | SCR_BRDV_DIV_32 },
};
static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
- unsigned long parent_rate,
- unsigned long spi_hz)
+ unsigned long parent_rate, u32 spi_hz)
{
unsigned long div = 1024;
size_t k;
@@ -164,7 +212,8 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1);
sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr);
- sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr);
+ if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX))
+ sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr);
}
static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
@@ -183,21 +232,25 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
*/
sh_msiof_write(p, FCTR, 0);
- tmp = 0;
- tmp |= !cs_high << 25;
- tmp |= lsb_first << 24;
- sh_msiof_write(p, TMDR1, 0xe0000005 | tmp);
- sh_msiof_write(p, RMDR1, 0x20000005 | tmp);
+ tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP;
+ tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
+ tmp |= lsb_first << MDR1_BITLSB_SHIFT;
+ sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
+ if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) {
+ /* These bits are reserved if RX needs TX */
+ tmp &= ~0x0000ffff;
+ }
+ sh_msiof_write(p, RMDR1, tmp);
- tmp = 0xa0000000;
- tmp |= cpol << 30; /* TSCKIZ */
- tmp |= cpol << 28; /* RSCKIZ */
+ tmp = 0;
+ tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT;
+ tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT;
edge = cpol ^ !cpha;
- tmp |= edge << 27; /* TEDG */
- tmp |= edge << 26; /* REDG */
- tmp |= (tx_hi_z ? 2 : 0) << 22; /* TXDIZ */
+ tmp |= edge << CTR_TEDG_SHIFT;
+ tmp |= edge << CTR_REDG_SHIFT;
+ tmp |= tx_hi_z ? CTR_TXDIZ_HIZ : CTR_TXDIZ_LOW;
sh_msiof_write(p, CTR, tmp);
}
@@ -205,12 +258,12 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
const void *tx_buf, void *rx_buf,
u32 bits, u32 words)
{
- u32 dr2 = ((bits - 1) << 24) | ((words - 1) << 16);
+ u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words);
- if (tx_buf)
+ if (tx_buf || (p->chipdata->master_flags & SPI_MASTER_MUST_TX))
sh_msiof_write(p, TMDR2, dr2);
else
- sh_msiof_write(p, TMDR2, dr2 | 1);
+ sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1);
if (rx_buf)
sh_msiof_write(p, RMDR2, dr2);
@@ -363,77 +416,45 @@ static void sh_msiof_spi_read_fifo_s32u(struct sh_msiof_spi_priv *p,
put_unaligned(swab32(sh_msiof_read(p, RFDR) >> fs), &buf_32[k]);
}
-static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t)
+static int sh_msiof_spi_setup(struct spi_device *spi)
{
- int bits;
-
- bits = t ? t->bits_per_word : 0;
- if (!bits)
- bits = spi->bits_per_word;
- return bits;
-}
-
-static unsigned long sh_msiof_spi_hz(struct spi_device *spi,
- struct spi_transfer *t)
-{
- unsigned long hz;
-
- hz = t ? t->speed_hz : 0;
- if (!hz)
- hz = spi->max_speed_hz;
- return hz;
-}
+ struct device_node *np = spi->master->dev.of_node;
+ struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
-static int sh_msiof_spi_setup_transfer(struct spi_device *spi,
- struct spi_transfer *t)
-{
- int bits;
+ if (!np) {
+ /*
+ * Use spi->controller_data for CS (same strategy as spi_gpio),
+ * if any. otherwise let HW control CS
+ */
+ spi->cs_gpio = (uintptr_t)spi->controller_data;
+ }
- /* noting to check hz values against since parent clock is disabled */
+ /* Configure pins before deasserting CS */
+ sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
+ !!(spi->mode & SPI_CPHA),
+ !!(spi->mode & SPI_3WIRE),
+ !!(spi->mode & SPI_LSB_FIRST),
+ !!(spi->mode & SPI_CS_HIGH));
- bits = sh_msiof_spi_bits(spi, t);
- if (bits < 8)
- return -EINVAL;
- if (bits > 32)
- return -EINVAL;
+ if (spi->cs_gpio >= 0)
+ gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
- return spi_bitbang_setup_transfer(spi, t);
+ return 0;
}
-static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on)
+static int sh_msiof_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
{
- struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
- int value;
-
- /* chip select is active low unless SPI_CS_HIGH is set */
- if (spi->mode & SPI_CS_HIGH)
- value = (is_on == BITBANG_CS_ACTIVE) ? 1 : 0;
- else
- value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1;
-
- if (is_on == BITBANG_CS_ACTIVE) {
- if (!test_and_set_bit(0, &p->flags)) {
- pm_runtime_get_sync(&p->pdev->dev);
- clk_enable(p->clk);
- }
-
- /* Configure pins before asserting CS */
- sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
- !!(spi->mode & SPI_CPHA),
- !!(spi->mode & SPI_3WIRE),
- !!(spi->mode & SPI_LSB_FIRST),
- !!(spi->mode & SPI_CS_HIGH));
- }
+ struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
+ const struct spi_device *spi = msg->spi;
- /* use spi->controller data for CS (same strategy as spi_gpio) */
- gpio_set_value((uintptr_t)spi->controller_data, value);
-
- if (is_on == BITBANG_CS_INACTIVE) {
- if (test_and_clear_bit(0, &p->flags)) {
- clk_disable(p->clk);
- pm_runtime_put(&p->pdev->dev);
- }
- }
+ /* Configure pins before asserting CS */
+ sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
+ !!(spi->mode & SPI_CPHA),
+ !!(spi->mode & SPI_3WIRE),
+ !!(spi->mode & SPI_LSB_FIRST),
+ !!(spi->mode & SPI_CS_HIGH));
+ return 0;
}
static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
@@ -487,7 +508,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
/* clear status bits */
sh_msiof_reset_str(p);
- /* shut down frame, tx/tx and clock signals */
+ /* shut down frame, rx/tx and clock signals */
ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0);
ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0);
if (rx_buf)
@@ -505,9 +526,11 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
return ret;
}
-static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
+static int sh_msiof_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *t)
{
- struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
+ struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int);
void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int);
int bits;
@@ -517,7 +540,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
int n;
bool swab;
- bits = sh_msiof_spi_bits(spi, t);
+ bits = t->bits_per_word;
if (bits <= 8 && t->len > 15 && !(t->len & 3)) {
bits = 32;
@@ -567,8 +590,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
}
/* setup clocks (clock already enabled in chipselect()) */
- sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk),
- sh_msiof_spi_hz(spi, t));
+ sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz);
/* transfer in fifo sized chunks */
words = t->len / bytes_per_word;
@@ -588,22 +610,36 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
words -= n;
}
- return bytes_done;
-}
-
-static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
- u32 word, u8 bits)
-{
- BUG(); /* unused but needed by bitbang code */
return 0;
}
+static const struct sh_msiof_chipdata sh_data = {
+ .tx_fifo_size = 64,
+ .rx_fifo_size = 64,
+ .master_flags = 0,
+};
+
+static const struct sh_msiof_chipdata r8a779x_data = {
+ .tx_fifo_size = 64,
+ .rx_fifo_size = 256,
+ .master_flags = SPI_MASTER_MUST_TX,
+};
+
+static const struct of_device_id sh_msiof_match[] = {
+ { .compatible = "renesas,sh-msiof", .data = &sh_data },
+ { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data },
+ { .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data },
+ { .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sh_msiof_match);
+
#ifdef CONFIG_OF
static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
{
struct sh_msiof_spi_info *info;
struct device_node *np = dev->of_node;
- u32 num_cs = 0;
+ u32 num_cs = 1;
info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL);
if (!info) {
@@ -633,6 +669,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
{
struct resource *r;
struct spi_master *master;
+ const struct of_device_id *of_id;
struct sh_msiof_spi_priv *p;
int i;
int ret;
@@ -646,10 +683,15 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
p = spi_master_get_devdata(master);
platform_set_drvdata(pdev, p);
- if (pdev->dev.of_node)
+
+ of_id = of_match_device(sh_msiof_match, &pdev->dev);
+ if (of_id) {
+ p->chipdata = of_id->data;
p->info = sh_msiof_spi_parse_dt(&pdev->dev);
- else
+ } else {
+ p->chipdata = (const void *)pdev->id_entry->driver_data;
p->info = dev_get_platdata(&pdev->dev);
+ }
if (!p->info) {
dev_err(&pdev->dev, "failed to obtain device info\n");
@@ -687,49 +729,40 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
goto err1;
}
- ret = clk_prepare(p->clk);
- if (ret < 0) {
- dev_err(&pdev->dev, "unable to prepare clock\n");
- goto err1;
- }
-
p->pdev = pdev;
pm_runtime_enable(&pdev->dev);
- /* The standard version of MSIOF use 64 word FIFOs */
- p->tx_fifo_size = 64;
- p->rx_fifo_size = 64;
-
/* Platform data may override FIFO sizes */
+ p->tx_fifo_size = p->chipdata->tx_fifo_size;
+ p->rx_fifo_size = p->chipdata->rx_fifo_size;
if (p->info->tx_fifo_override)
p->tx_fifo_size = p->info->tx_fifo_override;
if (p->info->rx_fifo_override)
p->rx_fifo_size = p->info->rx_fifo_override;
- /* init master and bitbang code */
+ /* init master code */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
- master->flags = 0;
+ master->flags = p->chipdata->master_flags;
master->bus_num = pdev->id;
+ master->dev.of_node = pdev->dev.of_node;
master->num_chipselect = p->info->num_chipselect;
- master->setup = spi_bitbang_setup;
- master->cleanup = spi_bitbang_cleanup;
-
- p->bitbang.master = master;
- p->bitbang.chipselect = sh_msiof_spi_chipselect;
- p->bitbang.setup_transfer = sh_msiof_spi_setup_transfer;
- p->bitbang.txrx_bufs = sh_msiof_spi_txrx;
- p->bitbang.txrx_word[SPI_MODE_0] = sh_msiof_spi_txrx_word;
- p->bitbang.txrx_word[SPI_MODE_1] = sh_msiof_spi_txrx_word;
- p->bitbang.txrx_word[SPI_MODE_2] = sh_msiof_spi_txrx_word;
- p->bitbang.txrx_word[SPI_MODE_3] = sh_msiof_spi_txrx_word;
-
- ret = spi_bitbang_start(&p->bitbang);
- if (ret == 0)
- return 0;
+ master->setup = sh_msiof_spi_setup;
+ master->prepare_message = sh_msiof_prepare_message;
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
+ master->auto_runtime_pm = true;
+ master->transfer_one = sh_msiof_transfer_one;
+
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "spi_register_master error.\n");
+ goto err2;
+ }
+ return 0;
+
+ err2:
pm_runtime_disable(&pdev->dev);
- clk_unprepare(p->clk);
err1:
spi_master_put(master);
return ret;
@@ -737,30 +770,22 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
static int sh_msiof_spi_remove(struct platform_device *pdev)
{
- struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
- int ret;
-
- ret = spi_bitbang_stop(&p->bitbang);
- if (!ret) {
- pm_runtime_disable(&pdev->dev);
- clk_unprepare(p->clk);
- spi_master_put(p->bitbang.master);
- }
- return ret;
+ pm_runtime_disable(&pdev->dev);
+ return 0;
}
-#ifdef CONFIG_OF
-static const struct of_device_id sh_msiof_match[] = {
- { .compatible = "renesas,sh-msiof", },
- { .compatible = "renesas,sh-mobile-msiof", },
+static struct platform_device_id spi_driver_ids[] = {
+ { "spi_sh_msiof", (kernel_ulong_t)&sh_data },
+ { "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data },
+ { "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data },
{},
};
-MODULE_DEVICE_TABLE(of, sh_msiof_match);
-#endif
+MODULE_DEVICE_TABLE(platform, spi_driver_ids);
static struct platform_driver sh_msiof_spi_drv = {
.probe = sh_msiof_spi_probe,
.remove = sh_msiof_spi_remove,
+ .id_table = spi_driver_ids,
.driver = {
.name = "spi_sh_msiof",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c
index 38eb24df796c..8b44b71f5024 100644
--- a/drivers/spi/spi-sh-sci.c
+++ b/drivers/spi/spi-sh-sci.c
@@ -14,7 +14,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
@@ -109,7 +108,7 @@ static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
{
struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
- if (sp->info && sp->info->chip_select)
+ if (sp->info->chip_select)
(sp->info->chip_select)(sp->info, dev->chip_select, value);
}
@@ -131,6 +130,11 @@ static int sh_sci_spi_probe(struct platform_device *dev)
platform_set_drvdata(dev, sp);
sp->info = dev_get_platdata(&dev->dev);
+ if (!sp->info) {
+ dev_err(&dev->dev, "platform data is missing\n");
+ ret = -ENOENT;
+ goto err1;
+ }
/* setup spi bitbang adaptor */
sp->bitbang.master = master;
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index e430689c3837..1a77ad52812f 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -22,7 +22,6 @@
#include <linux/dmaengine.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
-#include <linux/sirfsoc_dma.h>
#define DRIVER_NAME "sirfsoc_spi"
@@ -132,6 +131,8 @@
#define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \
ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE))
+#define SIRFSOC_MAX_CMD_BYTES 4
+
struct sirfsoc_spi {
struct spi_bitbang bitbang;
struct completion rx_done;
@@ -162,6 +163,12 @@ struct sirfsoc_spi {
void *dummypage;
int word_width; /* in bytes */
+ /*
+ * if tx size is not more than 4 and rx size is NULL, use
+ * command model
+ */
+ bool tx_by_cmd;
+
int chipselect[0];
};
@@ -260,6 +267,12 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS);
+ if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) {
+ complete(&sspi->tx_done);
+ writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
+ return IRQ_HANDLED;
+ }
+
/* Error Conditions */
if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
spi_stat & SIRFSOC_SPI_TX_UFLOW) {
@@ -310,6 +323,34 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS);
+ /*
+ * fill tx_buf into command register and wait for its completion
+ */
+ if (sspi->tx_by_cmd) {
+ u32 cmd;
+ memcpy(&cmd, sspi->tx, t->len);
+
+ if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST))
+ cmd = cpu_to_be32(cmd) >>
+ ((SIRFSOC_MAX_CMD_BYTES - t->len) * 8);
+ if (sspi->word_width == 2 && t->len == 4 &&
+ (!(spi->mode & SPI_LSB_FIRST)))
+ cmd = ((cmd & 0xffff) << 16) | (cmd >> 16);
+
+ writel(cmd, sspi->base + SIRFSOC_SPI_CMD);
+ writel(SIRFSOC_SPI_FRM_END_INT_EN,
+ sspi->base + SIRFSOC_SPI_INT_EN);
+ writel(SIRFSOC_SPI_CMD_TX_EN,
+ sspi->base + SIRFSOC_SPI_TX_RX_EN);
+
+ if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) {
+ dev_err(&spi->dev, "transfer timeout\n");
+ return 0;
+ }
+
+ return t->len;
+ }
+
if (sspi->left_tx_word == 1) {
writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
SIRFSOC_SPI_ENA_AUTO_CLR,
@@ -459,11 +500,6 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_8;
sspi->rx_word = spi_sirfsoc_rx_word_u8;
sspi->tx_word = spi_sirfsoc_tx_word_u8;
- txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_BYTE;
- rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_BYTE;
- sspi->word_width = 1;
break;
case 12:
case 16:
@@ -471,26 +507,22 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
SIRFSOC_SPI_TRAN_DAT_FORMAT_16;
sspi->rx_word = spi_sirfsoc_rx_word_u16;
sspi->tx_word = spi_sirfsoc_tx_word_u16;
- txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_WORD;
- rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_WORD;
- sspi->word_width = 2;
break;
case 32:
regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32;
sspi->rx_word = spi_sirfsoc_rx_word_u32;
sspi->tx_word = spi_sirfsoc_tx_word_u32;
- txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_DWORD;
- rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_DWORD;
- sspi->word_width = 4;
break;
default:
BUG();
}
+ sspi->word_width = DIV_ROUND_UP(bits_per_word, 8);
+ txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
+ sspi->word_width;
+ rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
+ sspi->word_width;
+
if (!(spi->mode & SPI_CS_HIGH))
regval |= SIRFSOC_SPI_CS_IDLE_STAT;
if (!(spi->mode & SPI_LSB_FIRST))
@@ -519,6 +551,14 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL);
writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL);
+ if (t && t->tx_buf && !t->rx_buf && (t->len <= SIRFSOC_MAX_CMD_BYTES)) {
+ regval |= (SIRFSOC_SPI_CMD_BYTE_NUM((t->len - 1)) |
+ SIRFSOC_SPI_CMD_MODE);
+ sspi->tx_by_cmd = true;
+ } else {
+ regval &= ~SIRFSOC_SPI_CMD_MODE;
+ sspi->tx_by_cmd = false;
+ }
writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
if (IS_DMA_VALID(t)) {
@@ -548,8 +588,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
struct spi_master *master;
struct resource *mem_res;
int num_cs, cs_gpio, irq;
- u32 rx_dma_ch, tx_dma_ch;
- dma_cap_mask_t dma_cap_mask;
int i;
int ret;
@@ -560,20 +598,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
goto err_cs;
}
- ret = of_property_read_u32(pdev->dev.of_node,
- "sirf,spi-dma-rx-channel", &rx_dma_ch);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to get rx dma channel\n");
- goto err_cs;
- }
-
- ret = of_property_read_u32(pdev->dev.of_node,
- "sirf,spi-dma-tx-channel", &tx_dma_ch);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to get tx dma channel\n");
- goto err_cs;
- }
-
master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs);
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI master\n");
@@ -637,18 +661,13 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
/* request DMA channels */
- dma_cap_zero(dma_cap_mask);
- dma_cap_set(DMA_INTERLEAVE, dma_cap_mask);
-
- sspi->rx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
- (void *)rx_dma_ch);
+ sspi->rx_chan = dma_request_slave_channel(&pdev->dev, "rx");
if (!sspi->rx_chan) {
dev_err(&pdev->dev, "can not allocate rx dma channel\n");
ret = -ENODEV;
goto free_master;
}
- sspi->tx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
- (void *)tx_dma_ch);
+ sspi->tx_chan = dma_request_slave_channel(&pdev->dev, "tx");
if (!sspi->tx_chan) {
dev_err(&pdev->dev, "can not allocate tx dma channel\n");
ret = -ENODEV;
@@ -724,11 +743,16 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int spi_sirfsoc_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct sirfsoc_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
clk_disable(sspi->clk);
return 0;
@@ -745,15 +769,13 @@ static int spi_sirfsoc_resume(struct device *dev)
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
- return 0;
+ return spi_master_resume(master);
}
-
-static const struct dev_pm_ops spi_sirfsoc_pm_ops = {
- .suspend = spi_sirfsoc_suspend,
- .resume = spi_sirfsoc_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(spi_sirfsoc_pm_ops, spi_sirfsoc_suspend,
+ spi_sirfsoc_resume);
+
static const struct of_device_id spi_sirfsoc_of_match[] = {
{ .compatible = "sirf,prima2-spi", },
{ .compatible = "sirf,marco-spi", },
@@ -765,9 +787,7 @@ static struct platform_driver spi_sirfsoc_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &spi_sirfsoc_pm_ops,
-#endif
.of_match_table = spi_sirfsoc_of_match,
},
.probe = spi_sirfsoc_probe,
diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
new file mode 100644
index 000000000000..d266a8702067
--- /dev/null
+++ b/drivers/spi/spi-sun4i.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2012 - 2014 Allwinner Tech
+ * Pan Nan <pannan@allwinnertech.com>
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/workqueue.h>
+
+#include <linux/spi/spi.h>
+
+#define SUN4I_FIFO_DEPTH 64
+
+#define SUN4I_RXDATA_REG 0x00
+
+#define SUN4I_TXDATA_REG 0x04
+
+#define SUN4I_CTL_REG 0x08
+#define SUN4I_CTL_ENABLE BIT(0)
+#define SUN4I_CTL_MASTER BIT(1)
+#define SUN4I_CTL_CPHA BIT(2)
+#define SUN4I_CTL_CPOL BIT(3)
+#define SUN4I_CTL_CS_ACTIVE_LOW BIT(4)
+#define SUN4I_CTL_LMTF BIT(6)
+#define SUN4I_CTL_TF_RST BIT(8)
+#define SUN4I_CTL_RF_RST BIT(9)
+#define SUN4I_CTL_XCH BIT(10)
+#define SUN4I_CTL_CS_MASK 0x3000
+#define SUN4I_CTL_CS(cs) (((cs) << 12) & SUN4I_CTL_CS_MASK)
+#define SUN4I_CTL_DHB BIT(15)
+#define SUN4I_CTL_CS_MANUAL BIT(16)
+#define SUN4I_CTL_CS_LEVEL BIT(17)
+#define SUN4I_CTL_TP BIT(18)
+
+#define SUN4I_INT_CTL_REG 0x0c
+#define SUN4I_INT_CTL_TC BIT(16)
+
+#define SUN4I_INT_STA_REG 0x10
+
+#define SUN4I_DMA_CTL_REG 0x14
+
+#define SUN4I_WAIT_REG 0x18
+
+#define SUN4I_CLK_CTL_REG 0x1c
+#define SUN4I_CLK_CTL_CDR2_MASK 0xff
+#define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK)
+#define SUN4I_CLK_CTL_CDR1_MASK 0xf
+#define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8)
+#define SUN4I_CLK_CTL_DRS BIT(12)
+
+#define SUN4I_BURST_CNT_REG 0x20
+#define SUN4I_BURST_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN4I_XMIT_CNT_REG 0x24
+#define SUN4I_XMIT_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN4I_FIFO_STA_REG 0x28
+#define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f
+#define SUN4I_FIFO_STA_RF_CNT_BITS 0
+#define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f
+#define SUN4I_FIFO_STA_TF_CNT_BITS 16
+
+struct sun4i_spi {
+ struct spi_master *master;
+ void __iomem *base_addr;
+ struct clk *hclk;
+ struct clk *mclk;
+
+ struct completion done;
+
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ int len;
+};
+
+static inline u32 sun4i_spi_read(struct sun4i_spi *sspi, u32 reg)
+{
+ return readl(sspi->base_addr + reg);
+}
+
+static inline void sun4i_spi_write(struct sun4i_spi *sspi, u32 reg, u32 value)
+{
+ writel(value, sspi->base_addr + reg);
+}
+
+static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len)
+{
+ u32 reg, cnt;
+ u8 byte;
+
+ /* See how much data is available */
+ reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
+ reg &= SUN4I_FIFO_STA_RF_CNT_MASK;
+ cnt = reg >> SUN4I_FIFO_STA_RF_CNT_BITS;
+
+ if (len > cnt)
+ len = cnt;
+
+ while (len--) {
+ byte = readb(sspi->base_addr + SUN4I_RXDATA_REG);
+ if (sspi->rx_buf)
+ *sspi->rx_buf++ = byte;
+ }
+}
+
+static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len)
+{
+ u8 byte;
+
+ if (len > sspi->len)
+ len = sspi->len;
+
+ while (len--) {
+ byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
+ writeb(byte, sspi->base_addr + SUN4I_TXDATA_REG);
+ sspi->len--;
+ }
+}
+
+static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
+ u32 reg;
+
+ reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+
+ reg &= ~SUN4I_CTL_CS_MASK;
+ reg |= SUN4I_CTL_CS(spi->chip_select);
+
+ if (enable)
+ reg |= SUN4I_CTL_CS_LEVEL;
+ else
+ reg &= ~SUN4I_CTL_CS_LEVEL;
+
+ /*
+ * Even though this looks irrelevant since we are supposed to
+ * be controlling the chip select manually, this bit also
+ * controls the levels of the chip select for inactive
+ * devices.
+ *
+ * If we don't set it, the chip select level will go low by
+ * default when the device is idle, which is not really
+ * expected in the common case where the chip select is active
+ * low.
+ */
+ if (spi->mode & SPI_CS_HIGH)
+ reg &= ~SUN4I_CTL_CS_ACTIVE_LOW;
+ else
+ reg |= SUN4I_CTL_CS_ACTIVE_LOW;
+
+ sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
+}
+
+static int sun4i_spi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct sun4i_spi *sspi = spi_master_get_devdata(master);
+ unsigned int mclk_rate, div, timeout;
+ unsigned int tx_len = 0;
+ int ret = 0;
+ u32 reg;
+
+ /* We don't support transfer larger than the FIFO */
+ if (tfr->len > SUN4I_FIFO_DEPTH)
+ return -EINVAL;
+
+ reinit_completion(&sspi->done);
+ sspi->tx_buf = tfr->tx_buf;
+ sspi->rx_buf = tfr->rx_buf;
+ sspi->len = tfr->len;
+
+ /* Clear pending interrupts */
+ sun4i_spi_write(sspi, SUN4I_INT_STA_REG, ~0);
+
+
+ reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+
+ /* Reset FIFOs */
+ sun4i_spi_write(sspi, SUN4I_CTL_REG,
+ reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST);
+
+ /*
+ * Setup the transfer control register: Chip Select,
+ * polarities, etc.
+ */
+ if (spi->mode & SPI_CPOL)
+ reg |= SUN4I_CTL_CPOL;
+ else
+ reg &= ~SUN4I_CTL_CPOL;
+
+ if (spi->mode & SPI_CPHA)
+ reg |= SUN4I_CTL_CPHA;
+ else
+ reg &= ~SUN4I_CTL_CPHA;
+
+ if (spi->mode & SPI_LSB_FIRST)
+ reg |= SUN4I_CTL_LMTF;
+ else
+ reg &= ~SUN4I_CTL_LMTF;
+
+
+ /*
+ * If it's a TX only transfer, we don't want to fill the RX
+ * FIFO with bogus data
+ */
+ if (sspi->rx_buf)
+ reg &= ~SUN4I_CTL_DHB;
+ else
+ reg |= SUN4I_CTL_DHB;
+
+ /* We want to control the chip select manually */
+ reg |= SUN4I_CTL_CS_MANUAL;
+
+ sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
+
+ /* Ensure that we have a parent clock fast enough */
+ mclk_rate = clk_get_rate(sspi->mclk);
+ if (mclk_rate < (2 * spi->max_speed_hz)) {
+ clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
+ mclk_rate = clk_get_rate(sspi->mclk);
+ }
+
+ /*
+ * Setup clock divider.
+ *
+ * We have two choices there. Either we can use the clock
+ * divide rate 1, which is calculated thanks to this formula:
+ * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
+ * Or we can use CDR2, which is calculated with the formula:
+ * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+ * Wether we use the former or the latter is set through the
+ * DRS bit.
+ *
+ * First try CDR2, and if we can't reach the expected
+ * frequency, fall back to CDR1.
+ */
+ div = mclk_rate / (2 * spi->max_speed_hz);
+ if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
+ if (div > 0)
+ div--;
+
+ reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
+ } else {
+ div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
+ reg = SUN4I_CLK_CTL_CDR1(div);
+ }
+
+ sun4i_spi_write(sspi, SUN4I_CLK_CTL_REG, reg);
+
+ /* Setup the transfer now... */
+ if (sspi->tx_buf)
+ tx_len = tfr->len;
+
+ /* Setup the counters */
+ sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len));
+ sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
+
+ /* Fill the TX FIFO */
+ sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
+
+ /* Enable the interrupts */
+ sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
+
+ /* Start the transfer */
+ reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+ sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
+
+ timeout = wait_for_completion_timeout(&sspi->done,
+ msecs_to_jiffies(1000));
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
+
+out:
+ sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0);
+
+ return ret;
+}
+
+static irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
+{
+ struct sun4i_spi *sspi = dev_id;
+ u32 status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG);
+
+ /* Transfer complete */
+ if (status & SUN4I_INT_CTL_TC) {
+ sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC);
+ complete(&sspi->done);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int sun4i_spi_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun4i_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(sspi->hclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable AHB clock\n");
+ goto out;
+ }
+
+ ret = clk_prepare_enable(sspi->mclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable module clock\n");
+ goto err;
+ }
+
+ sun4i_spi_write(sspi, SUN4I_CTL_REG,
+ SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP);
+
+ return 0;
+
+err:
+ clk_disable_unprepare(sspi->hclk);
+out:
+ return ret;
+}
+
+static int sun4i_spi_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun4i_spi *sspi = spi_master_get_devdata(master);
+
+ clk_disable_unprepare(sspi->mclk);
+ clk_disable_unprepare(sspi->hclk);
+
+ return 0;
+}
+
+static int sun4i_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct sun4i_spi *sspi;
+ struct resource *res;
+ int ret = 0, irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi));
+ if (!master) {
+ dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, master);
+ sspi = spi_master_get_devdata(master);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(sspi->base_addr)) {
+ ret = PTR_ERR(sspi->base_addr);
+ goto err_free_master;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No spi IRQ specified\n");
+ ret = -ENXIO;
+ goto err_free_master;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
+ 0, "sun4i-spi", sspi);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot request IRQ\n");
+ goto err_free_master;
+ }
+
+ sspi->master = master;
+ master->set_cs = sun4i_spi_set_cs;
+ master->transfer_one = sun4i_spi_transfer_one;
+ master->num_chipselect = 4;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->dev.of_node = pdev->dev.of_node;
+ master->auto_runtime_pm = true;
+
+ sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(sspi->hclk)) {
+ dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
+ ret = PTR_ERR(sspi->hclk);
+ goto err_free_master;
+ }
+
+ sspi->mclk = devm_clk_get(&pdev->dev, "mod");
+ if (IS_ERR(sspi->mclk)) {
+ dev_err(&pdev->dev, "Unable to acquire module clock\n");
+ ret = PTR_ERR(sspi->mclk);
+ goto err_free_master;
+ }
+
+ init_completion(&sspi->done);
+
+ /*
+ * This wake-up/shutdown pattern is to be able to have the
+ * device woken up, even if runtime_pm is disabled
+ */
+ ret = sun4i_spi_runtime_resume(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't resume the device\n");
+ goto err_free_master;
+ }
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_idle(&pdev->dev);
+
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot register SPI master\n");
+ goto err_pm_disable;
+ }
+
+ return 0;
+
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ sun4i_spi_runtime_suspend(&pdev->dev);
+err_free_master:
+ spi_master_put(master);
+ return ret;
+}
+
+static int sun4i_spi_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id sun4i_spi_match[] = {
+ { .compatible = "allwinner,sun4i-a10-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun4i_spi_match);
+
+static const struct dev_pm_ops sun4i_spi_pm_ops = {
+ .runtime_resume = sun4i_spi_runtime_resume,
+ .runtime_suspend = sun4i_spi_runtime_suspend,
+};
+
+static struct platform_driver sun4i_spi_driver = {
+ .probe = sun4i_spi_probe,
+ .remove = sun4i_spi_remove,
+ .driver = {
+ .name = "sun4i-spi",
+ .owner = THIS_MODULE,
+ .of_match_table = sun4i_spi_match,
+ .pm = &sun4i_spi_pm_ops,
+ },
+};
+module_platform_driver(sun4i_spi_driver);
+
+MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A1X/A20 SPI controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
new file mode 100644
index 000000000000..b3e3498a7e6f
--- /dev/null
+++ b/drivers/spi/spi-sun6i.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2012 - 2014 Allwinner Tech
+ * Pan Nan <pannan@allwinnertech.com>
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/workqueue.h>
+
+#include <linux/spi/spi.h>
+
+#define SUN6I_FIFO_DEPTH 128
+
+#define SUN6I_GBL_CTL_REG 0x04
+#define SUN6I_GBL_CTL_BUS_ENABLE BIT(0)
+#define SUN6I_GBL_CTL_MASTER BIT(1)
+#define SUN6I_GBL_CTL_TP BIT(7)
+#define SUN6I_GBL_CTL_RST BIT(31)
+
+#define SUN6I_TFR_CTL_REG 0x08
+#define SUN6I_TFR_CTL_CPHA BIT(0)
+#define SUN6I_TFR_CTL_CPOL BIT(1)
+#define SUN6I_TFR_CTL_SPOL BIT(2)
+#define SUN6I_TFR_CTL_CS_MASK 0x30
+#define SUN6I_TFR_CTL_CS(cs) (((cs) << 4) & SUN6I_TFR_CTL_CS_MASK)
+#define SUN6I_TFR_CTL_CS_MANUAL BIT(6)
+#define SUN6I_TFR_CTL_CS_LEVEL BIT(7)
+#define SUN6I_TFR_CTL_DHB BIT(8)
+#define SUN6I_TFR_CTL_FBS BIT(12)
+#define SUN6I_TFR_CTL_XCH BIT(31)
+
+#define SUN6I_INT_CTL_REG 0x10
+#define SUN6I_INT_CTL_RF_OVF BIT(8)
+#define SUN6I_INT_CTL_TC BIT(12)
+
+#define SUN6I_INT_STA_REG 0x14
+
+#define SUN6I_FIFO_CTL_REG 0x18
+#define SUN6I_FIFO_CTL_RF_RST BIT(15)
+#define SUN6I_FIFO_CTL_TF_RST BIT(31)
+
+#define SUN6I_FIFO_STA_REG 0x1c
+#define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f
+#define SUN6I_FIFO_STA_RF_CNT_BITS 0
+#define SUN6I_FIFO_STA_TF_CNT_MASK 0x7f
+#define SUN6I_FIFO_STA_TF_CNT_BITS 16
+
+#define SUN6I_CLK_CTL_REG 0x24
+#define SUN6I_CLK_CTL_CDR2_MASK 0xff
+#define SUN6I_CLK_CTL_CDR2(div) (((div) & SUN6I_CLK_CTL_CDR2_MASK) << 0)
+#define SUN6I_CLK_CTL_CDR1_MASK 0xf
+#define SUN6I_CLK_CTL_CDR1(div) (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8)
+#define SUN6I_CLK_CTL_DRS BIT(12)
+
+#define SUN6I_BURST_CNT_REG 0x30
+#define SUN6I_BURST_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN6I_XMIT_CNT_REG 0x34
+#define SUN6I_XMIT_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN6I_BURST_CTL_CNT_REG 0x38
+#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & 0xffffff)
+
+#define SUN6I_TXDATA_REG 0x200
+#define SUN6I_RXDATA_REG 0x300
+
+struct sun6i_spi {
+ struct spi_master *master;
+ void __iomem *base_addr;
+ struct clk *hclk;
+ struct clk *mclk;
+ struct reset_control *rstc;
+
+ struct completion done;
+
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ int len;
+};
+
+static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg)
+{
+ return readl(sspi->base_addr + reg);
+}
+
+static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value)
+{
+ writel(value, sspi->base_addr + reg);
+}
+
+static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
+{
+ u32 reg, cnt;
+ u8 byte;
+
+ /* See how much data is available */
+ reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
+ reg &= SUN6I_FIFO_STA_RF_CNT_MASK;
+ cnt = reg >> SUN6I_FIFO_STA_RF_CNT_BITS;
+
+ if (len > cnt)
+ len = cnt;
+
+ while (len--) {
+ byte = readb(sspi->base_addr + SUN6I_RXDATA_REG);
+ if (sspi->rx_buf)
+ *sspi->rx_buf++ = byte;
+ }
+}
+
+static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len)
+{
+ u8 byte;
+
+ if (len > sspi->len)
+ len = sspi->len;
+
+ while (len--) {
+ byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
+ writeb(byte, sspi->base_addr + SUN6I_TXDATA_REG);
+ sspi->len--;
+ }
+}
+
+static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
+ u32 reg;
+
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+ reg &= ~SUN6I_TFR_CTL_CS_MASK;
+ reg |= SUN6I_TFR_CTL_CS(spi->chip_select);
+
+ if (enable)
+ reg |= SUN6I_TFR_CTL_CS_LEVEL;
+ else
+ reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
+
+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+}
+
+
+static int sun6i_spi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ unsigned int mclk_rate, div, timeout;
+ unsigned int tx_len = 0;
+ int ret = 0;
+ u32 reg;
+
+ /* We don't support transfer larger than the FIFO */
+ if (tfr->len > SUN6I_FIFO_DEPTH)
+ return -EINVAL;
+
+ reinit_completion(&sspi->done);
+ sspi->tx_buf = tfr->tx_buf;
+ sspi->rx_buf = tfr->rx_buf;
+ sspi->len = tfr->len;
+
+ /* Clear pending interrupts */
+ sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0);
+
+ /* Reset FIFO */
+ sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
+ SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
+
+ /*
+ * Setup the transfer control register: Chip Select,
+ * polarities, etc.
+ */
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+
+ if (spi->mode & SPI_CPOL)
+ reg |= SUN6I_TFR_CTL_CPOL;
+ else
+ reg &= ~SUN6I_TFR_CTL_CPOL;
+
+ if (spi->mode & SPI_CPHA)
+ reg |= SUN6I_TFR_CTL_CPHA;
+ else
+ reg &= ~SUN6I_TFR_CTL_CPHA;
+
+ if (spi->mode & SPI_LSB_FIRST)
+ reg |= SUN6I_TFR_CTL_FBS;
+ else
+ reg &= ~SUN6I_TFR_CTL_FBS;
+
+ /*
+ * If it's a TX only transfer, we don't want to fill the RX
+ * FIFO with bogus data
+ */
+ if (sspi->rx_buf)
+ reg &= ~SUN6I_TFR_CTL_DHB;
+ else
+ reg |= SUN6I_TFR_CTL_DHB;
+
+ /* We want to control the chip select manually */
+ reg |= SUN6I_TFR_CTL_CS_MANUAL;
+
+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+
+ /* Ensure that we have a parent clock fast enough */
+ mclk_rate = clk_get_rate(sspi->mclk);
+ if (mclk_rate < (2 * spi->max_speed_hz)) {
+ clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
+ mclk_rate = clk_get_rate(sspi->mclk);
+ }
+
+ /*
+ * Setup clock divider.
+ *
+ * We have two choices there. Either we can use the clock
+ * divide rate 1, which is calculated thanks to this formula:
+ * SPI_CLK = MOD_CLK / (2 ^ cdr)
+ * Or we can use CDR2, which is calculated with the formula:
+ * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+ * Wether we use the former or the latter is set through the
+ * DRS bit.
+ *
+ * First try CDR2, and if we can't reach the expected
+ * frequency, fall back to CDR1.
+ */
+ div = mclk_rate / (2 * spi->max_speed_hz);
+ if (div <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
+ if (div > 0)
+ div--;
+
+ reg = SUN6I_CLK_CTL_CDR2(div) | SUN6I_CLK_CTL_DRS;
+ } else {
+ div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
+ reg = SUN6I_CLK_CTL_CDR1(div);
+ }
+
+ sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
+
+ /* Setup the transfer now... */
+ if (sspi->tx_buf)
+ tx_len = tfr->len;
+
+ /* Setup the counters */
+ sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, SUN6I_BURST_CNT(tfr->len));
+ sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, SUN6I_XMIT_CNT(tx_len));
+ sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG,
+ SUN6I_BURST_CTL_CNT_STC(tx_len));
+
+ /* Fill the TX FIFO */
+ sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
+
+ /* Enable the interrupts */
+ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
+
+ /* Start the transfer */
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
+
+ timeout = wait_for_completion_timeout(&sspi->done,
+ msecs_to_jiffies(1000));
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
+
+out:
+ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
+
+ return ret;
+}
+
+static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
+{
+ struct sun6i_spi *sspi = dev_id;
+ u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
+
+ /* Transfer complete */
+ if (status & SUN6I_INT_CTL_TC) {
+ sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
+ complete(&sspi->done);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int sun6i_spi_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(sspi->hclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable AHB clock\n");
+ goto out;
+ }
+
+ ret = clk_prepare_enable(sspi->mclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable module clock\n");
+ goto err;
+ }
+
+ ret = reset_control_deassert(sspi->rstc);
+ if (ret) {
+ dev_err(dev, "Couldn't deassert the device from reset\n");
+ goto err2;
+ }
+
+ sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG,
+ SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
+
+ return 0;
+
+err2:
+ clk_disable_unprepare(sspi->mclk);
+err:
+ clk_disable_unprepare(sspi->hclk);
+out:
+ return ret;
+}
+
+static int sun6i_spi_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+ reset_control_assert(sspi->rstc);
+ clk_disable_unprepare(sspi->mclk);
+ clk_disable_unprepare(sspi->hclk);
+
+ return 0;
+}
+
+static int sun6i_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct sun6i_spi *sspi;
+ struct resource *res;
+ int ret = 0, irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
+ if (!master) {
+ dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, master);
+ sspi = spi_master_get_devdata(master);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(sspi->base_addr)) {
+ ret = PTR_ERR(sspi->base_addr);
+ goto err_free_master;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No spi IRQ specified\n");
+ ret = -ENXIO;
+ goto err_free_master;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
+ 0, "sun6i-spi", sspi);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot request IRQ\n");
+ goto err_free_master;
+ }
+
+ sspi->master = master;
+ master->set_cs = sun6i_spi_set_cs;
+ master->transfer_one = sun6i_spi_transfer_one;
+ master->num_chipselect = 4;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->dev.of_node = pdev->dev.of_node;
+ master->auto_runtime_pm = true;
+
+ sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(sspi->hclk)) {
+ dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
+ ret = PTR_ERR(sspi->hclk);
+ goto err_free_master;
+ }
+
+ sspi->mclk = devm_clk_get(&pdev->dev, "mod");
+ if (IS_ERR(sspi->mclk)) {
+ dev_err(&pdev->dev, "Unable to acquire module clock\n");
+ ret = PTR_ERR(sspi->mclk);
+ goto err_free_master;
+ }
+
+ init_completion(&sspi->done);
+
+ sspi->rstc = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(sspi->rstc)) {
+ dev_err(&pdev->dev, "Couldn't get reset controller\n");
+ ret = PTR_ERR(sspi->rstc);
+ goto err_free_master;
+ }
+
+ /*
+ * This wake-up/shutdown pattern is to be able to have the
+ * device woken up, even if runtime_pm is disabled
+ */
+ ret = sun6i_spi_runtime_resume(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't resume the device\n");
+ goto err_free_master;
+ }
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_idle(&pdev->dev);
+
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot register SPI master\n");
+ goto err_pm_disable;
+ }
+
+ return 0;
+
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ sun6i_spi_runtime_suspend(&pdev->dev);
+err_free_master:
+ spi_master_put(master);
+ return ret;
+}
+
+static int sun6i_spi_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id sun6i_spi_match[] = {
+ { .compatible = "allwinner,sun6i-a31-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun6i_spi_match);
+
+static const struct dev_pm_ops sun6i_spi_pm_ops = {
+ .runtime_resume = sun6i_spi_runtime_resume,
+ .runtime_suspend = sun6i_spi_runtime_suspend,
+};
+
+static struct platform_driver sun6i_spi_driver = {
+ .probe = sun6i_spi_probe,
+ .remove = sun6i_spi_remove,
+ .driver = {
+ .name = "sun6i-spi",
+ .owner = THIS_MODULE,
+ .of_match_table = sun6i_spi_match,
+ .pm = &sun6i_spi_pm_ops,
+ },
+};
+module_platform_driver(sun6i_spi_driver);
+
+MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A31 SPI controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 413c71843492..400649595505 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -23,7 +23,6 @@
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -172,7 +171,6 @@ struct tegra_spi_data {
void __iomem *base;
phys_addr_t phys;
unsigned irq;
- u32 spi_max_frequency;
u32 cur_speed;
struct spi_device *cur_spi;
@@ -761,11 +759,6 @@ static int tegra_spi_setup(struct spi_device *spi)
spi->mode & SPI_CPHA ? "" : "~",
spi->max_speed_hz);
- BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
-
- /* Set speed to the spi max fequency if spi device has not set */
- spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
-
ret = pm_runtime_get_sync(tspi->dev);
if (ret < 0) {
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
@@ -853,8 +846,8 @@ complete_xfer:
SPI_COMMAND1);
tegra_spi_transfer_delay(xfer->delay_usecs);
goto exit;
- } else if (msg->transfers.prev == &xfer->transfer_list) {
- /* This is the last transfer in message */
+ } else if (list_is_last(&xfer->transfer_list,
+ &msg->transfers)) {
if (xfer->cs_change)
tspi->cs_control = spi;
else {
@@ -1019,16 +1012,6 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data)
return IRQ_WAKE_THREAD;
}
-static void tegra_spi_parse_dt(struct platform_device *pdev,
- struct tegra_spi_data *tspi)
-{
- struct device_node *np = pdev->dev.of_node;
-
- if (of_property_read_u32(np, "spi-max-frequency",
- &tspi->spi_max_frequency))
- tspi->spi_max_frequency = 25000000; /* 25MHz */
-}
-
static struct of_device_id tegra_spi_of_match[] = {
{ .compatible = "nvidia,tegra114-spi", },
{}
@@ -1050,15 +1033,15 @@ static int tegra_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
tspi = spi_master_get_devdata(master);
- /* Parse DT */
- tegra_spi_parse_dt(pdev, tspi);
+ if (of_property_read_u32(pdev->dev.of_node, "spi-max-frequency",
+ &master->max_speed_hz))
+ master->max_speed_hz = 25000000; /* 25MHz */
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->setup = tegra_spi_setup;
master->transfer_one_message = tegra_spi_transfer_one_message;
master->num_chipselect = MAX_CHIP_SELECT;
- master->bus_num = -1;
master->auto_runtime_pm = true;
tspi->master = master;
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
index 08794977f21a..47869ea636e1 100644
--- a/drivers/spi/spi-tegra20-sflash.c
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -22,7 +22,6 @@
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -121,7 +120,6 @@ struct tegra_sflash_data {
struct reset_control *rst;
void __iomem *base;
unsigned irq;
- u32 spi_max_frequency;
u32 cur_speed;
struct spi_device *cur_spi;
@@ -315,15 +313,6 @@ static int tegra_sflash_start_transfer_one(struct spi_device *spi,
return tegra_sflash_start_cpu_based_transfer(tsd, t);
}
-static int tegra_sflash_setup(struct spi_device *spi)
-{
- struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master);
-
- /* Set speed to the spi max fequency if spi device has not set */
- spi->max_speed_hz = spi->max_speed_hz ? : tsd->spi_max_frequency;
- return 0;
-}
-
static int tegra_sflash_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
@@ -430,15 +419,6 @@ static irqreturn_t tegra_sflash_isr(int irq, void *context_data)
return handle_cpu_based_xfer(tsd);
}
-static void tegra_sflash_parse_dt(struct tegra_sflash_data *tsd)
-{
- struct device_node *np = tsd->dev->of_node;
-
- if (of_property_read_u32(np, "spi-max-frequency",
- &tsd->spi_max_frequency))
- tsd->spi_max_frequency = 25000000; /* 25MHz */
-}
-
static struct of_device_id tegra_sflash_of_match[] = {
{ .compatible = "nvidia,tegra20-sflash", },
{}
@@ -467,11 +447,9 @@ static int tegra_sflash_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA;
- master->setup = tegra_sflash_setup;
master->transfer_one_message = tegra_sflash_transfer_one_message;
master->auto_runtime_pm = true;
master->num_chipselect = MAX_CHIP_SELECT;
- master->bus_num = -1;
platform_set_drvdata(pdev, master);
tsd = spi_master_get_devdata(master);
@@ -479,7 +457,9 @@ static int tegra_sflash_probe(struct platform_device *pdev)
tsd->dev = &pdev->dev;
spin_lock_init(&tsd->lock);
- tegra_sflash_parse_dt(tsd);
+ if (of_property_read_u32(tsd->dev->of_node, "spi-max-frequency",
+ &master->max_speed_hz))
+ master->max_speed_hz = 25000000; /* 25MHz */
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tsd->base = devm_ioremap_resource(&pdev->dev, r);
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
index be3a069879c3..e3c1b93e45d1 100644
--- a/drivers/spi/spi-tegra20-slink.c
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -23,7 +23,6 @@
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -171,7 +170,6 @@ struct tegra_slink_data {
void __iomem *base;
phys_addr_t phys;
unsigned irq;
- u32 spi_max_frequency;
u32 cur_speed;
struct spi_device *cur_spi;
@@ -761,10 +759,6 @@ static int tegra_slink_setup(struct spi_device *spi)
spi->mode & SPI_CPHA ? "" : "~",
spi->max_speed_hz);
- BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
-
- /* Set speed to the spi max fequency if spi device has not set */
- spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
ret = pm_runtime_get_sync(tspi->dev);
if (ret < 0) {
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
@@ -999,15 +993,6 @@ static irqreturn_t tegra_slink_isr(int irq, void *context_data)
return IRQ_WAKE_THREAD;
}
-static void tegra_slink_parse_dt(struct tegra_slink_data *tspi)
-{
- struct device_node *np = tspi->dev->of_node;
-
- if (of_property_read_u32(np, "spi-max-frequency",
- &tspi->spi_max_frequency))
- tspi->spi_max_frequency = 25000000; /* 25MHz */
-}
-
static const struct tegra_slink_chip_data tegra30_spi_cdata = {
.cs_hold_time = true,
};
@@ -1053,7 +1038,6 @@ static int tegra_slink_probe(struct platform_device *pdev)
master->unprepare_message = tegra_slink_unprepare_message;
master->auto_runtime_pm = true;
master->num_chipselect = MAX_CHIP_SELECT;
- master->bus_num = -1;
platform_set_drvdata(pdev, master);
tspi = spi_master_get_devdata(master);
@@ -1062,7 +1046,9 @@ static int tegra_slink_probe(struct platform_device *pdev)
tspi->chip_data = cdata;
spin_lock_init(&tspi->lock);
- tegra_slink_parse_dt(tspi);
+ if (of_property_read_u32(tspi->dev->of_node, "spi-max-frequency",
+ &master->max_speed_hz))
+ master->max_speed_hz = 25000000; /* 25MHz */
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
index 3d09265b5133..6c211d1910b0 100644
--- a/drivers/spi/spi-ti-qspi.c
+++ b/drivers/spi/spi-ti-qspi.c
@@ -429,13 +429,13 @@ static int ti_qspi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
- master->bus_num = -1;
master->flags = SPI_MASTER_HALF_DUPLEX;
master->setup = ti_qspi_setup;
master->auto_runtime_pm = true;
master->transfer_one_message = ti_qspi_start_transfer_one;
master->dev.of_node = pdev->dev.of_node;
- master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
+ master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(8);
if (!of_property_read_u32(np, "num-cs", &num_cs))
master->num_chipselect = num_cs;
@@ -461,7 +461,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
if (res_mmap == NULL) {
dev_err(&pdev->dev,
"memory mapped resource not required\n");
- return -ENODEV;
}
}
diff --git a/drivers/spi/spi-ti-ssp.c b/drivers/spi/spi-ti-ssp.c
deleted file mode 100644
index 7d20e121e4c1..000000000000
--- a/drivers/spi/spi-ti-ssp.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Sequencer Serial Port (SSP) based SPI master driver
- *
- * Copyright (C) 2010 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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/err.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/mfd/ti_ssp.h>
-
-#define MODE_BITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
-
-struct ti_ssp_spi {
- struct spi_master *master;
- struct device *dev;
- spinlock_t lock;
- struct list_head msg_queue;
- struct completion complete;
- bool shutdown;
- struct workqueue_struct *workqueue;
- struct work_struct work;
- u8 mode, bpw;
- int cs_active;
- u32 pc_en, pc_dis, pc_wr, pc_rd;
- void (*select)(int cs);
-};
-
-static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw)
-{
- u32 ret;
-
- ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret);
- return ret;
-}
-
-static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data)
-{
- ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL);
-}
-
-static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg,
- struct spi_transfer *t)
-{
- int count;
-
- if (hw->bpw <= 8) {
- u8 *rx = t->rx_buf;
- const u8 *tx = t->tx_buf;
-
- for (count = 0; count < t->len; count += 1) {
- if (t->tx_buf)
- ti_ssp_spi_tx(hw, *tx++);
- if (t->rx_buf)
- *rx++ = ti_ssp_spi_rx(hw);
- }
- } else if (hw->bpw <= 16) {
- u16 *rx = t->rx_buf;
- const u16 *tx = t->tx_buf;
-
- for (count = 0; count < t->len; count += 2) {
- if (t->tx_buf)
- ti_ssp_spi_tx(hw, *tx++);
- if (t->rx_buf)
- *rx++ = ti_ssp_spi_rx(hw);
- }
- } else {
- u32 *rx = t->rx_buf;
- const u32 *tx = t->tx_buf;
-
- for (count = 0; count < t->len; count += 4) {
- if (t->tx_buf)
- ti_ssp_spi_tx(hw, *tx++);
- if (t->rx_buf)
- *rx++ = ti_ssp_spi_rx(hw);
- }
- }
-
- msg->actual_length += count; /* bytes transferred */
-
- dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n",
- t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len,
- hw->bpw, count, (count < t->len) ? " (under)" : "");
-
- return (count < t->len) ? -EIO : 0; /* left over data */
-}
-
-static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active)
-{
- cs_active = !!cs_active;
- if (cs_active == hw->cs_active)
- return;
- ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL);
- hw->cs_active = cs_active;
-}
-
-#define __SHIFT_OUT(bits) (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \
- cs_en | clk | SSP_COUNT((bits) * 2 - 1))
-#define __SHIFT_IN(bits) (SSP_OPCODE_SHIFT | SSP_IN_MODE | \
- cs_en | clk | SSP_COUNT((bits) * 2 - 1))
-
-static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode)
-{
- int error, idx = 0;
- u32 seqram[16];
- u32 cs_en, cs_dis, clk;
- u32 topbits, botbits;
-
- mode &= MODE_BITS;
- if (mode == hw->mode && bpw == hw->bpw)
- return 0;
-
- cs_en = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW;
- cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW : SSP_CS_HIGH;
- clk = (mode & SPI_CPOL) ? SSP_CLK_HIGH : SSP_CLK_LOW;
-
- /* Construct instructions */
-
- /* Disable Chip Select */
- hw->pc_dis = idx;
- seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk;
- seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_dis | clk;
-
- /* Enable Chip Select */
- hw->pc_en = idx;
- seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk;
- seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
-
- /* Reads and writes need to be split for bpw > 16 */
- topbits = (bpw > 16) ? 16 : bpw;
- botbits = bpw - topbits;
-
- /* Write */
- hw->pc_wr = idx;
- seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG;
- if (botbits)
- seqram[idx++] = __SHIFT_OUT(botbits) | SSP_DATA_REG;
- seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
-
- /* Read */
- hw->pc_rd = idx;
- if (botbits)
- seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG;
- seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG;
- seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
-
- error = ti_ssp_load(hw->dev, 0, seqram, idx);
- if (error < 0)
- return error;
-
- error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ?
- 0 : SSP_EARLY_DIN));
- if (error < 0)
- return error;
-
- hw->bpw = bpw;
- hw->mode = mode;
-
- return error;
-}
-
-static void ti_ssp_spi_work(struct work_struct *work)
-{
- struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work);
-
- spin_lock(&hw->lock);
-
- while (!list_empty(&hw->msg_queue)) {
- struct spi_message *m;
- struct spi_device *spi;
- struct spi_transfer *t = NULL;
- int status = 0;
-
- m = container_of(hw->msg_queue.next, struct spi_message,
- queue);
-
- list_del_init(&m->queue);
-
- spin_unlock(&hw->lock);
-
- spi = m->spi;
-
- if (hw->select)
- hw->select(spi->chip_select);
-
- list_for_each_entry(t, &m->transfers, transfer_list) {
- int bpw = spi->bits_per_word;
- int xfer_status;
-
- if (t->bits_per_word)
- bpw = t->bits_per_word;
-
- if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0)
- break;
-
- ti_ssp_spi_chip_select(hw, 1);
-
- xfer_status = ti_ssp_spi_txrx(hw, m, t);
- if (xfer_status < 0)
- status = xfer_status;
-
- if (t->delay_usecs)
- udelay(t->delay_usecs);
-
- if (t->cs_change)
- ti_ssp_spi_chip_select(hw, 0);
- }
-
- ti_ssp_spi_chip_select(hw, 0);
- m->status = status;
- m->complete(m->context);
-
- spin_lock(&hw->lock);
- }
-
- if (hw->shutdown)
- complete(&hw->complete);
-
- spin_unlock(&hw->lock);
-}
-
-static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
-{
- struct ti_ssp_spi *hw;
- struct spi_transfer *t;
- int error = 0;
-
- m->actual_length = 0;
- m->status = -EINPROGRESS;
-
- hw = spi_master_get_devdata(spi->master);
-
- if (list_empty(&m->transfers) || !m->complete)
- return -EINVAL;
-
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (t->len && !(t->rx_buf || t->tx_buf)) {
- dev_err(&spi->dev, "invalid xfer, no buffer\n");
- return -EINVAL;
- }
-
- if (t->len && t->rx_buf && t->tx_buf) {
- dev_err(&spi->dev, "invalid xfer, full duplex\n");
- return -EINVAL;
- }
- }
-
- spin_lock(&hw->lock);
- if (hw->shutdown) {
- error = -ESHUTDOWN;
- goto error_unlock;
- }
- list_add_tail(&m->queue, &hw->msg_queue);
- queue_work(hw->workqueue, &hw->work);
-error_unlock:
- spin_unlock(&hw->lock);
- return error;
-}
-
-static int ti_ssp_spi_probe(struct platform_device *pdev)
-{
- const struct ti_ssp_spi_data *pdata;
- struct ti_ssp_spi *hw;
- struct spi_master *master;
- struct device *dev = &pdev->dev;
- int error = 0;
-
- pdata = dev_get_platdata(dev);
- if (!pdata) {
- dev_err(dev, "platform data not found\n");
- return -EINVAL;
- }
-
- master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi));
- if (!master) {
- dev_err(dev, "cannot allocate SPI master\n");
- return -ENOMEM;
- }
-
- hw = spi_master_get_devdata(master);
- platform_set_drvdata(pdev, hw);
-
- hw->master = master;
- hw->dev = dev;
- hw->select = pdata->select;
-
- spin_lock_init(&hw->lock);
- init_completion(&hw->complete);
- INIT_LIST_HEAD(&hw->msg_queue);
- INIT_WORK(&hw->work, ti_ssp_spi_work);
-
- hw->workqueue = create_singlethread_workqueue(dev_name(dev));
- if (!hw->workqueue) {
- error = -ENOMEM;
- dev_err(dev, "work queue creation failed\n");
- goto error_wq;
- }
-
- error = ti_ssp_set_iosel(hw->dev, pdata->iosel);
- if (error < 0) {
- dev_err(dev, "io setup failed\n");
- goto error_iosel;
- }
-
- master->bus_num = pdev->id;
- master->num_chipselect = pdata->num_cs;
- master->mode_bits = MODE_BITS;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->transfer = ti_ssp_spi_transfer;
-
- error = spi_register_master(master);
- if (error) {
- dev_err(dev, "master registration failed\n");
- goto error_reg;
- }
-
- return 0;
-
-error_reg:
-error_iosel:
- destroy_workqueue(hw->workqueue);
-error_wq:
- spi_master_put(master);
- return error;
-}
-
-static int ti_ssp_spi_remove(struct platform_device *pdev)
-{
- struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
- int error;
-
- hw->shutdown = 1;
- while (!list_empty(&hw->msg_queue)) {
- error = wait_for_completion_interruptible(&hw->complete);
- if (error < 0) {
- hw->shutdown = 0;
- return error;
- }
- }
- destroy_workqueue(hw->workqueue);
- spi_unregister_master(hw->master);
-
- return 0;
-}
-
-static struct platform_driver ti_ssp_spi_driver = {
- .probe = ti_ssp_spi_probe,
- .remove = ti_ssp_spi_remove,
- .driver = {
- .name = "ti-ssp-spi",
- .owner = THIS_MODULE,
- },
-};
-module_platform_driver(ti_ssp_spi_driver);
-
-MODULE_DESCRIPTION("SSP SPI Master");
-MODULE_AUTHOR("Cyril Chemparathy");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:ti-ssp-spi");
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index 2e7f38c7a961..f406b30af961 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -332,7 +332,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
data->transfer_active = false;
wake_up(&data->wait);
} else {
- dev_err(&data->master->dev,
+ dev_vdbg(&data->master->dev,
"%s : Transfer is not completed",
__func__);
}
@@ -464,20 +464,6 @@ static void pch_spi_reset(struct spi_master *master)
pch_spi_writereg(master, PCH_SRST, 0x0);
}
-static int pch_spi_setup(struct spi_device *pspi)
-{
- /* Check baud rate setting */
- /* if baud rate of chip is greater than
- max we can support,return error */
- if ((pspi->max_speed_hz) > PCH_MAX_BAUDRATE)
- pspi->max_speed_hz = PCH_MAX_BAUDRATE;
-
- dev_dbg(&pspi->dev, "%s MODE = %x\n", __func__,
- (pspi->mode) & (SPI_CPOL | SPI_CPHA));
-
- return 0;
-}
-
static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
{
@@ -486,23 +472,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
int retval;
unsigned long flags;
- /* validate spi message and baud rate */
- if (unlikely(list_empty(&pmsg->transfers) == 1)) {
- dev_err(&pspi->dev, "%s list empty\n", __func__);
- retval = -EINVAL;
- goto err_out;
- }
-
- if (unlikely(pspi->max_speed_hz == 0)) {
- dev_err(&pspi->dev, "%s pch_spi_transfer maxspeed=%d\n",
- __func__, pspi->max_speed_hz);
- retval = -EINVAL;
- goto err_out;
- }
-
- dev_dbg(&pspi->dev,
- "%s Transfer List not empty. Transfer Speed is set.\n", __func__);
-
spin_lock_irqsave(&data->lock, flags);
/* validate Tx/Rx buffers and Transfer length */
list_for_each_entry(transfer, &pmsg->transfers, transfer_list) {
@@ -523,10 +492,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
dev_dbg(&pspi->dev,
"%s Tx/Rx buffer valid. Transfer length valid\n",
__func__);
-
- /* if baud rate has been specified validate the same */
- if (transfer->speed_hz > PCH_MAX_BAUDRATE)
- transfer->speed_hz = PCH_MAX_BAUDRATE;
}
spin_unlock_irqrestore(&data->lock, flags);
@@ -915,7 +880,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw)
/* Set Tx DMA */
param = &dma->param_tx;
param->dma_dev = &dma_dev->dev;
- param->chan_id = data->master->bus_num * 2; /* Tx = 0, 2 */
+ param->chan_id = data->ch * 2; /* Tx = 0, 2 */;
param->tx_reg = data->io_base_addr + PCH_SPDWR;
param->width = width;
chan = dma_request_channel(mask, pch_spi_filter, param);
@@ -930,7 +895,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw)
/* Set Rx DMA */
param = &dma->param_rx;
param->dma_dev = &dma_dev->dev;
- param->chan_id = data->master->bus_num * 2 + 1; /* Rx = Tx + 1 */
+ param->chan_id = data->ch * 2 + 1; /* Rx = Tx + 1 */;
param->rx_reg = data->io_base_addr + PCH_SPDRR;
param->width = width;
chan = dma_request_channel(mask, pch_spi_filter, param);
@@ -1151,8 +1116,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
dma->nent = num;
dma->desc_tx = desc_tx;
- dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing "
- "0x2 to SSNXCR\n", __func__);
+ dev_dbg(&data->master->dev, "%s:Pulling down SSN low - writing 0x2 to SSNXCR\n", __func__);
spin_lock_irqsave(&data->lock, flags);
pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW);
@@ -1418,10 +1382,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
/* initialize members of SPI master */
master->num_chipselect = PCH_MAX_CS;
- master->setup = pch_spi_setup;
master->transfer = pch_spi_transfer;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
+ master->max_speed_hz = PCH_MAX_BAUDRATE;
data->board_dat = board_dat;
data->plat_dev = plat_dev;
@@ -1452,6 +1416,11 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
pch_spi_set_master_mode(master);
+ if (use_dma) {
+ dev_info(&plat_dev->dev, "Use DMA for data transfers\n");
+ pch_alloc_dma_buf(board_dat, data);
+ }
+
ret = spi_register_master(master);
if (ret != 0) {
dev_err(&plat_dev->dev,
@@ -1459,14 +1428,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
goto err_spi_register_master;
}
- if (use_dma) {
- dev_info(&plat_dev->dev, "Use DMA for data transfers\n");
- pch_alloc_dma_buf(board_dat, data);
- }
-
return 0;
err_spi_register_master:
+ pch_free_dma_buf(board_dat, data);
free_irq(board_dat->pdev->irq, data);
err_request_irq:
pch_spi_free_resources(board_dat, data);
@@ -1604,8 +1569,7 @@ static struct platform_driver pch_spi_pd_driver = {
.resume = pch_spi_pd_resume
};
-static int pch_spi_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
+static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct pch_spi_board_data *board_dat;
struct platform_device *pd_dev = NULL;
@@ -1675,6 +1639,8 @@ static int pch_spi_probe(struct pci_dev *pdev,
return 0;
err_platform_device:
+ while (--i >= 0)
+ platform_device_unregister(pd_dev_save->pd_save[i]);
pci_disable_device(pdev);
pci_enable_device:
pci_release_regions(pdev);
diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c
index 6191ced514b2..820b499816f8 100644
--- a/drivers/spi/spi-txx9.c
+++ b/drivers/spi/spi-txx9.c
@@ -80,7 +80,6 @@ struct txx9spi {
void __iomem *membase;
int baseclk;
struct clk *clk;
- u32 max_speed_hz, min_speed_hz;
int last_chipselect;
int last_chipselect_val;
};
@@ -117,9 +116,7 @@ static int txx9spi_setup(struct spi_device *spi)
{
struct txx9spi *c = spi_master_get_devdata(spi->master);
- if (!spi->max_speed_hz
- || spi->max_speed_hz > c->max_speed_hz
- || spi->max_speed_hz < c->min_speed_hz)
+ if (!spi->max_speed_hz)
return -EINVAL;
if (gpio_direction_output(spi->chip_select,
@@ -309,15 +306,8 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
/* check each transfer's parameters */
list_for_each_entry(t, &m->transfers, transfer_list) {
- u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
- u8 bits_per_word = t->bits_per_word;
-
if (!t->tx_buf && !t->rx_buf && t->len)
return -EINVAL;
- if (t->len & ((bits_per_word >> 3) - 1))
- return -EINVAL;
- if (speed_hz < c->min_speed_hz || speed_hz > c->max_speed_hz)
- return -EINVAL;
}
spin_lock_irqsave(&c->lock, flags);
@@ -360,17 +350,12 @@ static int txx9spi_probe(struct platform_device *dev)
goto exit;
}
c->baseclk = clk_get_rate(c->clk);
- c->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1);
- c->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1);
+ master->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1);
+ master->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1);
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!res)
- goto exit_busy;
- if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res),
- "spi_txx9"))
- goto exit_busy;
- c->membase = devm_ioremap(&dev->dev, res->start, resource_size(res));
- if (!c->membase)
+ c->membase = devm_ioremap_resource(&dev->dev, res);
+ if (IS_ERR(c->membase))
goto exit_busy;
/* enter config mode */
diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c
index 24c40b13dab1..bb478dccf1d8 100644
--- a/drivers/spi/spi-xcomm.c
+++ b/drivers/spi/spi-xcomm.c
@@ -8,7 +8,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -74,15 +73,13 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm,
static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
struct spi_device *spi, struct spi_transfer *t, unsigned int *settings)
{
- unsigned int speed;
-
if (t->len > 62)
return -EINVAL;
- speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
+ if (t->speed_hz != spi_xcomm->current_speed) {
+ unsigned int divider;
- if (speed != spi_xcomm->current_speed) {
- unsigned int divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, speed);
+ divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, t->speed_hz);
if (divider >= 64)
*settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_64;
else if (divider >= 16)
@@ -90,7 +87,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
else
*settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_4;
- spi_xcomm->current_speed = speed;
+ spi_xcomm->current_speed = t->speed_hz;
}
if (spi->mode & SPI_CPOL)
@@ -148,8 +145,6 @@ static int spi_xcomm_transfer_one(struct spi_master *master,
int status = 0;
bool is_last;
- is_first = true;
-
spi_xcomm_chipselect(spi_xcomm, spi, true);
list_for_each_entry(t, &msg->transfers, transfer_list) {
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 6d4ce4615163..a3b0b9944bf0 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -14,7 +14,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -88,10 +87,10 @@ struct xilinx_spi {
const u8 *tx_ptr; /* pointer in the Rx buffer */
int remaining_bytes; /* the number of bytes left to transfer */
u8 bits_per_word;
- unsigned int (*read_fn) (void __iomem *);
- void (*write_fn) (u32, void __iomem *);
- void (*tx_fn) (struct xilinx_spi *);
- void (*rx_fn) (struct xilinx_spi *);
+ unsigned int (*read_fn)(void __iomem *);
+ void (*write_fn)(u32, void __iomem *);
+ void (*tx_fn)(struct xilinx_spi *);
+ void (*rx_fn)(struct xilinx_spi *);
};
static void xspi_write32(u32 val, void __iomem *addr)
@@ -209,26 +208,11 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
}
/* spi_bitbang requires custom setup_transfer() to be defined if there is a
- * custom txrx_bufs(). We have nothing to setup here as the SPI IP block
- * supports 8 or 16 bits per word which cannot be changed in software.
- * SPI clock can't be changed in software either.
- * Check for correct bits per word. Chip select delay calculations could be
- * added here as soon as bitbang_work() can be made aware of the delay value.
+ * custom txrx_bufs().
*/
static int xilinx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
- struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
- u8 bits_per_word;
-
- bits_per_word = (t && t->bits_per_word)
- ? t->bits_per_word : spi->bits_per_word;
- if (bits_per_word != xspi->bits_per_word) {
- dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
- __func__, bits_per_word);
- return -EINVAL;
- }
-
return 0;
}
@@ -407,6 +391,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
xspi->write_fn = xspi_write32_be;
}
+ master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word);
xspi->bits_per_word = bits_per_word;
if (xspi->bits_per_word == 8) {
xspi->tx_fn = xspi_tx8;
diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c
new file mode 100644
index 000000000000..41e158187f9d
--- /dev/null
+++ b/drivers/spi/spi-xtensa-xtfpga.c
@@ -0,0 +1,170 @@
+/*
+ * Xtensa xtfpga SPI controller driver
+ *
+ * Copyright (c) 2014 Cadence Design Systems 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/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#define XTFPGA_SPI_NAME "xtfpga_spi"
+
+#define XTFPGA_SPI_START 0x0
+#define XTFPGA_SPI_BUSY 0x4
+#define XTFPGA_SPI_DATA 0x8
+
+#define BUSY_WAIT_US 100
+
+struct xtfpga_spi {
+ struct spi_bitbang bitbang;
+ void __iomem *regs;
+ u32 data;
+ unsigned data_sz;
+};
+
+static inline void xtfpga_spi_write32(const struct xtfpga_spi *spi,
+ unsigned addr, u32 val)
+{
+ iowrite32(val, spi->regs + addr);
+}
+
+static inline unsigned int xtfpga_spi_read32(const struct xtfpga_spi *spi,
+ unsigned addr)
+{
+ return ioread32(spi->regs + addr);
+}
+
+static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi)
+{
+ unsigned i;
+ for (i = 0; xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY) &&
+ i < BUSY_WAIT_US; ++i)
+ udelay(1);
+ WARN_ON_ONCE(i == BUSY_WAIT_US);
+}
+
+static u32 xtfpga_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
+ u32 v, u8 bits)
+{
+ struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
+
+ xspi->data = (xspi->data << bits) | (v & GENMASK(bits - 1, 0));
+ xspi->data_sz += bits;
+ if (xspi->data_sz >= 16) {
+ xtfpga_spi_write32(xspi, XTFPGA_SPI_DATA,
+ xspi->data >> (xspi->data_sz - 16));
+ xspi->data_sz -= 16;
+ xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 1);
+ xtfpga_spi_wait_busy(xspi);
+ xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0);
+ }
+
+ return 0;
+}
+
+static void xtfpga_spi_chipselect(struct spi_device *spi, int is_on)
+{
+ struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
+
+ WARN_ON(xspi->data_sz != 0);
+ xspi->data_sz = 0;
+}
+
+static int xtfpga_spi_probe(struct platform_device *pdev)
+{
+ struct xtfpga_spi *xspi;
+ struct resource *mem;
+ int ret;
+ struct spi_master *master;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct xtfpga_spi));
+ if (!master)
+ return -ENOMEM;
+
+ master->flags = SPI_MASTER_NO_RX;
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
+ master->bus_num = pdev->dev.id;
+ master->dev.of_node = pdev->dev.of_node;
+
+ xspi = spi_master_get_devdata(master);
+ xspi->bitbang.master = master;
+ xspi->bitbang.chipselect = xtfpga_spi_chipselect;
+ xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "No memory resource\n");
+ ret = -ENODEV;
+ goto err;
+ }
+ xspi->regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(xspi->regs)) {
+ ret = PTR_ERR(xspi->regs);
+ goto err;
+ }
+
+ xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0);
+ usleep_range(1000, 2000);
+ if (xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY)) {
+ dev_err(&pdev->dev, "Device stuck in busy state\n");
+ ret = -EBUSY;
+ goto err;
+ }
+
+ ret = spi_bitbang_start(&xspi->bitbang);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "spi_bitbang_start failed\n");
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, master);
+ return 0;
+err:
+ spi_master_put(master);
+ return ret;
+}
+
+static int xtfpga_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct xtfpga_spi *xspi = spi_master_get_devdata(master);
+
+ spi_bitbang_stop(&xspi->bitbang);
+ spi_master_put(master);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:" XTFPGA_SPI_NAME);
+
+#ifdef CONFIG_OF
+static const struct of_device_id xtfpga_spi_of_match[] = {
+ { .compatible = "cdns,xtfpga-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, xtfpga_spi_of_match);
+#endif
+
+static struct platform_driver xtfpga_spi_driver = {
+ .probe = xtfpga_spi_probe,
+ .remove = xtfpga_spi_remove,
+ .driver = {
+ .name = XTFPGA_SPI_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(xtfpga_spi_of_match),
+ },
+};
+module_platform_driver(xtfpga_spi_driver);
+
+MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
+MODULE_DESCRIPTION("xtensa xtfpga SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index d0b28bba38be..4eb9bf02996c 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -24,6 +24,8 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/cache.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
@@ -255,13 +257,12 @@ EXPORT_SYMBOL_GPL(spi_bus_type);
static int spi_drv_probe(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
- struct spi_device *spi = to_spi_device(dev);
int ret;
- acpi_dev_pm_attach(&spi->dev, true);
- ret = sdrv->probe(spi);
+ acpi_dev_pm_attach(dev, true);
+ ret = sdrv->probe(to_spi_device(dev));
if (ret)
- acpi_dev_pm_detach(&spi->dev, true);
+ acpi_dev_pm_detach(dev, true);
return ret;
}
@@ -269,11 +270,10 @@ static int spi_drv_probe(struct device *dev)
static int spi_drv_remove(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
- struct spi_device *spi = to_spi_device(dev);
int ret;
- ret = sdrv->remove(spi);
- acpi_dev_pm_detach(&spi->dev, true);
+ ret = sdrv->remove(to_spi_device(dev));
+ acpi_dev_pm_detach(dev, true);
return ret;
}
@@ -580,6 +580,169 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
spi->master->set_cs(spi, !enable);
}
+static int spi_map_buf(struct spi_master *master, struct device *dev,
+ struct sg_table *sgt, void *buf, size_t len,
+ enum dma_data_direction dir)
+{
+ const bool vmalloced_buf = is_vmalloc_addr(buf);
+ const int desc_len = vmalloced_buf ? PAGE_SIZE : master->max_dma_len;
+ const int sgs = DIV_ROUND_UP(len, desc_len);
+ struct page *vm_page;
+ void *sg_buf;
+ size_t min;
+ int i, ret;
+
+ ret = sg_alloc_table(sgt, sgs, GFP_KERNEL);
+ if (ret != 0)
+ return ret;
+
+ for (i = 0; i < sgs; i++) {
+ min = min_t(size_t, len, desc_len);
+
+ if (vmalloced_buf) {
+ vm_page = vmalloc_to_page(buf);
+ if (!vm_page) {
+ sg_free_table(sgt);
+ return -ENOMEM;
+ }
+ sg_buf = page_address(vm_page) +
+ ((size_t)buf & ~PAGE_MASK);
+ } else {
+ sg_buf = buf;
+ }
+
+ sg_set_buf(&sgt->sgl[i], sg_buf, min);
+
+ buf += min;
+ len -= min;
+ }
+
+ ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir);
+ if (ret < 0) {
+ sg_free_table(sgt);
+ return ret;
+ }
+
+ sgt->nents = ret;
+
+ return 0;
+}
+
+static void spi_unmap_buf(struct spi_master *master, struct device *dev,
+ struct sg_table *sgt, enum dma_data_direction dir)
+{
+ if (sgt->orig_nents) {
+ dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir);
+ sg_free_table(sgt);
+ }
+}
+
+static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
+{
+ struct device *tx_dev, *rx_dev;
+ struct spi_transfer *xfer;
+ void *tmp;
+ unsigned int max_tx, max_rx;
+ int ret;
+
+ if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) {
+ max_tx = 0;
+ max_rx = 0;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if ((master->flags & SPI_MASTER_MUST_TX) &&
+ !xfer->tx_buf)
+ max_tx = max(xfer->len, max_tx);
+ if ((master->flags & SPI_MASTER_MUST_RX) &&
+ !xfer->rx_buf)
+ max_rx = max(xfer->len, max_rx);
+ }
+
+ if (max_tx) {
+ tmp = krealloc(master->dummy_tx, max_tx,
+ GFP_KERNEL | GFP_DMA);
+ if (!tmp)
+ return -ENOMEM;
+ master->dummy_tx = tmp;
+ memset(tmp, 0, max_tx);
+ }
+
+ if (max_rx) {
+ tmp = krealloc(master->dummy_rx, max_rx,
+ GFP_KERNEL | GFP_DMA);
+ if (!tmp)
+ return -ENOMEM;
+ master->dummy_rx = tmp;
+ }
+
+ if (max_tx || max_rx) {
+ list_for_each_entry(xfer, &msg->transfers,
+ transfer_list) {
+ if (!xfer->tx_buf)
+ xfer->tx_buf = master->dummy_tx;
+ if (!xfer->rx_buf)
+ xfer->rx_buf = master->dummy_rx;
+ }
+ }
+ }
+
+ if (!master->can_dma)
+ return 0;
+
+ tx_dev = &master->dma_tx->dev->device;
+ rx_dev = &master->dma_rx->dev->device;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (!master->can_dma(master, msg->spi, xfer))
+ continue;
+
+ if (xfer->tx_buf != NULL) {
+ ret = spi_map_buf(master, tx_dev, &xfer->tx_sg,
+ (void *)xfer->tx_buf, xfer->len,
+ DMA_TO_DEVICE);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (xfer->rx_buf != NULL) {
+ ret = spi_map_buf(master, rx_dev, &xfer->rx_sg,
+ xfer->rx_buf, xfer->len,
+ DMA_FROM_DEVICE);
+ if (ret != 0) {
+ spi_unmap_buf(master, tx_dev, &xfer->tx_sg,
+ DMA_TO_DEVICE);
+ return ret;
+ }
+ }
+ }
+
+ master->cur_msg_mapped = true;
+
+ return 0;
+}
+
+static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
+{
+ struct spi_transfer *xfer;
+ struct device *tx_dev, *rx_dev;
+
+ if (!master->cur_msg_mapped || !master->can_dma)
+ return 0;
+
+ tx_dev = &master->dma_tx->dev->device;
+ rx_dev = &master->dma_rx->dev->device;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (!master->can_dma(master, msg->spi, xfer))
+ continue;
+
+ spi_unmap_buf(master, rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
+ spi_unmap_buf(master, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
+ }
+
+ return 0;
+}
+
/*
* spi_transfer_one_message - Default implementation of transfer_one_message()
*
@@ -591,9 +754,9 @@ static int spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
struct spi_transfer *xfer;
- bool cur_cs = true;
bool keep_cs = false;
int ret = 0;
+ int ms = 1;
spi_set_cs(msg->spi, true);
@@ -611,7 +774,16 @@ static int spi_transfer_one_message(struct spi_master *master,
if (ret > 0) {
ret = 0;
- wait_for_completion(&master->xfer_completion);
+ ms = xfer->len * 8 * 1000 / xfer->speed_hz;
+ ms += 10; /* some tolerance */
+
+ ms = wait_for_completion_timeout(&master->xfer_completion,
+ msecs_to_jiffies(ms));
+ }
+
+ if (ms == 0) {
+ dev_err(&msg->spi->dev, "SPI transfer timed out\n");
+ msg->status = -ETIMEDOUT;
}
trace_spi_transfer_stop(msg, xfer);
@@ -627,8 +799,9 @@ static int spi_transfer_one_message(struct spi_master *master,
&msg->transfers)) {
keep_cs = true;
} else {
- cur_cs = !cur_cs;
- spi_set_cs(msg->spi, cur_cs);
+ spi_set_cs(msg->spi, false);
+ udelay(10);
+ spi_set_cs(msg->spi, true);
}
}
@@ -686,6 +859,10 @@ static void spi_pump_messages(struct kthread_work *work)
}
master->busy = false;
spin_unlock_irqrestore(&master->queue_lock, flags);
+ kfree(master->dummy_rx);
+ master->dummy_rx = NULL;
+ kfree(master->dummy_tx);
+ master->dummy_tx = NULL;
if (master->unprepare_transfer_hardware &&
master->unprepare_transfer_hardware(master))
dev_err(&master->dev,
@@ -752,6 +929,13 @@ static void spi_pump_messages(struct kthread_work *work)
master->cur_msg_prepared = true;
}
+ ret = spi_map_msg(master, master->cur_msg);
+ if (ret) {
+ master->cur_msg->status = ret;
+ spi_finalize_current_message(master);
+ return;
+ }
+
ret = master->transfer_one_message(master, master->cur_msg);
if (ret) {
dev_err(&master->dev,
@@ -839,6 +1023,8 @@ void spi_finalize_current_message(struct spi_master *master)
queue_kthread_work(&master->kworker, &master->pump_messages);
spin_unlock_irqrestore(&master->queue_lock, flags);
+ spi_unmap_msg(master, mesg);
+
if (master->cur_msg_prepared && master->unprepare_message) {
ret = master->unprepare_message(master, mesg);
if (ret) {
@@ -892,7 +1078,7 @@ static int spi_stop_queue(struct spi_master *master)
*/
while ((!list_empty(&master->queue) || master->busy) && limit--) {
spin_unlock_irqrestore(&master->queue_lock, flags);
- msleep(10);
+ usleep_range(10000, 11000);
spin_lock_irqsave(&master->queue_lock, flags);
}
@@ -1372,6 +1558,8 @@ int spi_register_master(struct spi_master *master)
mutex_init(&master->bus_lock_mutex);
master->bus_lock_flag = 0;
init_completion(&master->xfer_completion);
+ if (!master->max_dma_len)
+ master->max_dma_len = INT_MAX;
/* register the device, then userspace will see it.
* registration fails if the bus ID is in use.
@@ -1597,6 +1785,9 @@ int spi_setup(struct spi_device *spi)
if (!spi->bits_per_word)
spi->bits_per_word = 8;
+ if (!spi->max_speed_hz)
+ spi->max_speed_hz = spi->master->max_speed_hz;
+
if (spi->master->setup)
status = spi->master->setup(spi);
@@ -1617,11 +1808,10 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
{
struct spi_master *master = spi->master;
struct spi_transfer *xfer;
+ int w_size;
if (list_empty(&message->transfers))
return -EINVAL;
- if (!message->complete)
- return -EINVAL;
/* Half-duplex links include original MicroWire, and ones with
* only one data pin like SPI_3WIRE (switches direction) or where
@@ -1652,12 +1842,13 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
message->frame_length += xfer->len;
if (!xfer->bits_per_word)
xfer->bits_per_word = spi->bits_per_word;
- if (!xfer->speed_hz) {
+
+ if (!xfer->speed_hz)
xfer->speed_hz = spi->max_speed_hz;
- if (master->max_speed_hz &&
- xfer->speed_hz > master->max_speed_hz)
- xfer->speed_hz = master->max_speed_hz;
- }
+
+ if (master->max_speed_hz &&
+ xfer->speed_hz > master->max_speed_hz)
+ xfer->speed_hz = master->max_speed_hz;
if (master->bits_per_word_mask) {
/* Only 32 bits fit in the mask */
@@ -1668,12 +1859,24 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
return -EINVAL;
}
+ /*
+ * SPI transfer length should be multiple of SPI word size
+ * where SPI word size should be power-of-two multiple
+ */
+ if (xfer->bits_per_word <= 8)
+ w_size = 1;
+ else if (xfer->bits_per_word <= 16)
+ w_size = 2;
+ else
+ w_size = 4;
+
+ /* No partial transfers accepted */
+ if (xfer->len % w_size)
+ return -EINVAL;
+
if (xfer->speed_hz && master->min_speed_hz &&
xfer->speed_hz < master->min_speed_hz)
return -EINVAL;
- if (xfer->speed_hz && master->max_speed_hz &&
- xfer->speed_hz > master->max_speed_hz)
- return -EINVAL;
if (xfer->tx_buf && !xfer->tx_nbits)
xfer->tx_nbits = SPI_NBITS_SINGLE;
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index d7c6e36021e8..e3bc23bb5883 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -73,7 +73,8 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS);
*/
#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
- | SPI_NO_CS | SPI_READY)
+ | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
+ | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)
struct spidev_data {
dev_t devt;
@@ -265,6 +266,8 @@ static int spidev_message(struct spidev_data *spidev,
buf += k_tmp->len;
k_tmp->cs_change = !!u_tmp->cs_change;
+ k_tmp->tx_nbits = u_tmp->tx_nbits;
+ k_tmp->rx_nbits = u_tmp->rx_nbits;
k_tmp->bits_per_word = u_tmp->bits_per_word;
k_tmp->delay_usecs = u_tmp->delay_usecs;
k_tmp->speed_hz = u_tmp->speed_hz;
@@ -359,6 +362,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = __put_user(spi->mode & SPI_MODE_MASK,
(__u8 __user *)arg);
break;
+ case SPI_IOC_RD_MODE32:
+ retval = __put_user(spi->mode & SPI_MODE_MASK,
+ (__u32 __user *)arg);
+ break;
case SPI_IOC_RD_LSB_FIRST:
retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,
(__u8 __user *)arg);
@@ -372,9 +379,13 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
/* write requests */
case SPI_IOC_WR_MODE:
- retval = __get_user(tmp, (u8 __user *)arg);
+ case SPI_IOC_WR_MODE32:
+ if (cmd == SPI_IOC_WR_MODE)
+ retval = __get_user(tmp, (u8 __user *)arg);
+ else
+ retval = __get_user(tmp, (u32 __user *)arg);
if (retval == 0) {
- u8 save = spi->mode;
+ u32 save = spi->mode;
if (tmp & ~SPI_MODE_MASK) {
retval = -EINVAL;
@@ -382,18 +393,18 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
tmp |= spi->mode & ~SPI_MODE_MASK;
- spi->mode = (u8)tmp;
+ spi->mode = (u16)tmp;
retval = spi_setup(spi);
if (retval < 0)
spi->mode = save;
else
- dev_dbg(&spi->dev, "spi mode %02x\n", tmp);
+ dev_dbg(&spi->dev, "spi mode %x\n", tmp);
}
break;
case SPI_IOC_WR_LSB_FIRST:
retval = __get_user(tmp, (__u8 __user *)arg);
if (retval == 0) {
- u8 save = spi->mode;
+ u32 save = spi->mode;
if (tmp)
spi->mode |= SPI_LSB_FIRST;
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
new file mode 100644
index 000000000000..bf1295e19f89
--- /dev/null
+++ b/drivers/spmi/Kconfig
@@ -0,0 +1,27 @@
+#
+# SPMI driver configuration
+#
+menuconfig SPMI
+ tristate "SPMI support"
+ help
+ SPMI (System Power Management Interface) is a two-wire
+ serial interface between baseband and application processors
+ and Power Management Integrated Circuits (PMIC).
+
+if SPMI
+
+config SPMI_MSM_PMIC_ARB
+ tristate "Qualcomm MSM SPMI Controller (PMIC Arbiter)"
+ depends on ARM
+ depends on IRQ_DOMAIN
+ depends on ARCH_QCOM || COMPILE_TEST
+ default ARCH_QCOM
+ help
+ If you say yes to this option, support will be included for the
+ built-in SPMI PMIC Arbiter interface on Qualcomm MSM family
+ processors.
+
+ This is required for communicating with Qualcomm PMICs and
+ other devices that have the SPMI interface.
+
+endif
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
new file mode 100644
index 000000000000..fc75104a5aab
--- /dev/null
+++ b/drivers/spmi/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for kernel SPMI framework.
+#
+obj-$(CONFIG_SPMI) += spmi.o
+
+obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
new file mode 100644
index 000000000000..246e03a18c94
--- /dev/null
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -0,0 +1,778 @@
+/* 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/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+
+/* PMIC Arbiter configuration registers */
+#define PMIC_ARB_VERSION 0x0000
+#define PMIC_ARB_INT_EN 0x0004
+
+/* PMIC Arbiter channel registers */
+#define PMIC_ARB_CMD(N) (0x0800 + (0x80 * (N)))
+#define PMIC_ARB_CONFIG(N) (0x0804 + (0x80 * (N)))
+#define PMIC_ARB_STATUS(N) (0x0808 + (0x80 * (N)))
+#define PMIC_ARB_WDATA0(N) (0x0810 + (0x80 * (N)))
+#define PMIC_ARB_WDATA1(N) (0x0814 + (0x80 * (N)))
+#define PMIC_ARB_RDATA0(N) (0x0818 + (0x80 * (N)))
+#define PMIC_ARB_RDATA1(N) (0x081C + (0x80 * (N)))
+
+/* Interrupt Controller */
+#define SPMI_PIC_OWNER_ACC_STATUS(M, N) (0x0000 + ((32 * (M)) + (4 * (N))))
+#define SPMI_PIC_ACC_ENABLE(N) (0x0200 + (4 * (N)))
+#define SPMI_PIC_IRQ_STATUS(N) (0x0600 + (4 * (N)))
+#define SPMI_PIC_IRQ_CLEAR(N) (0x0A00 + (4 * (N)))
+
+/* Mapping Table */
+#define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N)))
+#define SPMI_MAPPING_BIT_INDEX(X) (((X) >> 18) & 0xF)
+#define SPMI_MAPPING_BIT_IS_0_FLAG(X) (((X) >> 17) & 0x1)
+#define SPMI_MAPPING_BIT_IS_0_RESULT(X) (((X) >> 9) & 0xFF)
+#define SPMI_MAPPING_BIT_IS_1_FLAG(X) (((X) >> 8) & 0x1)
+#define SPMI_MAPPING_BIT_IS_1_RESULT(X) (((X) >> 0) & 0xFF)
+
+#define SPMI_MAPPING_TABLE_LEN 255
+#define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */
+
+/* Ownership Table */
+#define SPMI_OWNERSHIP_TABLE_REG(N) (0x0700 + (4 * (N)))
+#define SPMI_OWNERSHIP_PERIPH2OWNER(X) ((X) & 0x7)
+
+/* Channel Status fields */
+enum pmic_arb_chnl_status {
+ PMIC_ARB_STATUS_DONE = (1 << 0),
+ PMIC_ARB_STATUS_FAILURE = (1 << 1),
+ PMIC_ARB_STATUS_DENIED = (1 << 2),
+ PMIC_ARB_STATUS_DROPPED = (1 << 3),
+};
+
+/* Command register fields */
+#define PMIC_ARB_CMD_MAX_BYTE_COUNT 8
+
+/* Command Opcodes */
+enum pmic_arb_cmd_op_code {
+ PMIC_ARB_OP_EXT_WRITEL = 0,
+ PMIC_ARB_OP_EXT_READL = 1,
+ PMIC_ARB_OP_EXT_WRITE = 2,
+ PMIC_ARB_OP_RESET = 3,
+ PMIC_ARB_OP_SLEEP = 4,
+ PMIC_ARB_OP_SHUTDOWN = 5,
+ PMIC_ARB_OP_WAKEUP = 6,
+ PMIC_ARB_OP_AUTHENTICATE = 7,
+ PMIC_ARB_OP_MSTR_READ = 8,
+ PMIC_ARB_OP_MSTR_WRITE = 9,
+ PMIC_ARB_OP_EXT_READ = 13,
+ PMIC_ARB_OP_WRITE = 14,
+ PMIC_ARB_OP_READ = 15,
+ PMIC_ARB_OP_ZERO_WRITE = 16,
+};
+
+/* Maximum number of support PMIC peripherals */
+#define PMIC_ARB_MAX_PERIPHS 256
+#define PMIC_ARB_PERIPH_ID_VALID (1 << 15)
+#define PMIC_ARB_TIMEOUT_US 100
+#define PMIC_ARB_MAX_TRANS_BYTES (8)
+
+#define PMIC_ARB_APID_MASK 0xFF
+#define PMIC_ARB_PPID_MASK 0xFFF
+
+/* interrupt enable bit */
+#define SPMI_PIC_ACC_ENABLE_BIT BIT(0)
+
+/**
+ * spmi_pmic_arb_dev - SPMI PMIC Arbiter object
+ *
+ * @base: address of the PMIC Arbiter core registers.
+ * @intr: address of the SPMI interrupt control registers.
+ * @cnfg: address of the PMIC Arbiter configuration registers.
+ * @lock: lock to synchronize accesses.
+ * @channel: which channel to use for accesses.
+ * @irq: PMIC ARB interrupt.
+ * @ee: the current Execution Environment
+ * @min_apid: minimum APID (used for bounding IRQ search)
+ * @max_apid: maximum APID
+ * @mapping_table: in-memory copy of PPID -> APID mapping table.
+ * @domain: irq domain object for PMIC IRQ domain
+ * @spmic: SPMI controller object
+ * @apid_to_ppid: cached mapping from APID to PPID
+ */
+struct spmi_pmic_arb_dev {
+ void __iomem *base;
+ void __iomem *intr;
+ void __iomem *cnfg;
+ raw_spinlock_t lock;
+ u8 channel;
+ int irq;
+ u8 ee;
+ u8 min_apid;
+ u8 max_apid;
+ u32 mapping_table[SPMI_MAPPING_TABLE_LEN];
+ struct irq_domain *domain;
+ struct spmi_controller *spmic;
+ u16 apid_to_ppid[256];
+};
+
+static inline u32 pmic_arb_base_read(struct spmi_pmic_arb_dev *dev, u32 offset)
+{
+ return readl_relaxed(dev->base + offset);
+}
+
+static inline void pmic_arb_base_write(struct spmi_pmic_arb_dev *dev,
+ u32 offset, u32 val)
+{
+ writel_relaxed(val, dev->base + offset);
+}
+
+/**
+ * pa_read_data: reads pmic-arb's register and copy 1..4 bytes to buf
+ * @bc: byte count -1. range: 0..3
+ * @reg: register's address
+ * @buf: output parameter, length must be bc + 1
+ */
+static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
+{
+ u32 data = pmic_arb_base_read(dev, reg);
+ memcpy(buf, &data, (bc & 3) + 1);
+}
+
+/**
+ * pa_write_data: write 1..4 bytes from buf to pmic-arb's register
+ * @bc: byte-count -1. range: 0..3.
+ * @reg: register's address.
+ * @buf: buffer to write. length must be bc + 1.
+ */
+static void
+pa_write_data(struct spmi_pmic_arb_dev *dev, const u8 *buf, u32 reg, u8 bc)
+{
+ u32 data = 0;
+ memcpy(&data, buf, (bc & 3) + 1);
+ pmic_arb_base_write(dev, reg, data);
+}
+
+static int pmic_arb_wait_for_done(struct spmi_controller *ctrl)
+{
+ struct spmi_pmic_arb_dev *dev = spmi_controller_get_drvdata(ctrl);
+ u32 status = 0;
+ u32 timeout = PMIC_ARB_TIMEOUT_US;
+ u32 offset = PMIC_ARB_STATUS(dev->channel);
+
+ while (timeout--) {
+ status = pmic_arb_base_read(dev, offset);
+
+ if (status & PMIC_ARB_STATUS_DONE) {
+ if (status & PMIC_ARB_STATUS_DENIED) {
+ dev_err(&ctrl->dev,
+ "%s: transaction denied (0x%x)\n",
+ __func__, status);
+ return -EPERM;
+ }
+
+ if (status & PMIC_ARB_STATUS_FAILURE) {
+ dev_err(&ctrl->dev,
+ "%s: transaction failed (0x%x)\n",
+ __func__, status);
+ return -EIO;
+ }
+
+ if (status & PMIC_ARB_STATUS_DROPPED) {
+ dev_err(&ctrl->dev,
+ "%s: transaction dropped (0x%x)\n",
+ __func__, status);
+ return -EIO;
+ }
+
+ return 0;
+ }
+ udelay(1);
+ }
+
+ dev_err(&ctrl->dev,
+ "%s: timeout, status 0x%x\n",
+ __func__, status);
+ return -ETIMEDOUT;
+}
+
+/* Non-data command */
+static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
+{
+ struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+ unsigned long flags;
+ u32 cmd;
+ int rc;
+
+ /* Check for valid non-data command */
+ if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)
+ return -EINVAL;
+
+ cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20);
+
+ raw_spin_lock_irqsave(&pmic_arb->lock, flags);
+ pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
+ rc = pmic_arb_wait_for_done(ctrl);
+ raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+
+ return rc;
+}
+
+static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
+ u16 addr, u8 *buf, size_t len)
+{
+ struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+ unsigned long flags;
+ u8 bc = len - 1;
+ u32 cmd;
+ int rc;
+
+ if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
+ dev_err(&ctrl->dev,
+ "pmic-arb supports 1..%d bytes per trans, but %d requested",
+ PMIC_ARB_MAX_TRANS_BYTES, len);
+ return -EINVAL;
+ }
+
+ /* Check the opcode */
+ if (opc >= 0x60 && opc <= 0x7F)
+ opc = PMIC_ARB_OP_READ;
+ else if (opc >= 0x20 && opc <= 0x2F)
+ opc = PMIC_ARB_OP_EXT_READ;
+ else if (opc >= 0x38 && opc <= 0x3F)
+ opc = PMIC_ARB_OP_EXT_READL;
+ else
+ return -EINVAL;
+
+ cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
+
+ raw_spin_lock_irqsave(&pmic_arb->lock, flags);
+ pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
+ rc = pmic_arb_wait_for_done(ctrl);
+ if (rc)
+ goto done;
+
+ pa_read_data(pmic_arb, buf, PMIC_ARB_RDATA0(pmic_arb->channel),
+ min_t(u8, bc, 3));
+
+ if (bc > 3)
+ pa_read_data(pmic_arb, buf + 4,
+ PMIC_ARB_RDATA1(pmic_arb->channel), bc - 4);
+
+done:
+ raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+ return rc;
+}
+
+static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
+ u16 addr, const u8 *buf, size_t len)
+{
+ struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+ unsigned long flags;
+ u8 bc = len - 1;
+ u32 cmd;
+ int rc;
+
+ if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
+ dev_err(&ctrl->dev,
+ "pmic-arb supports 1..%d bytes per trans, but:%d requested",
+ PMIC_ARB_MAX_TRANS_BYTES, len);
+ return -EINVAL;
+ }
+
+ /* Check the opcode */
+ if (opc >= 0x40 && opc <= 0x5F)
+ opc = PMIC_ARB_OP_WRITE;
+ else if (opc >= 0x00 && opc <= 0x0F)
+ opc = PMIC_ARB_OP_EXT_WRITE;
+ else if (opc >= 0x30 && opc <= 0x37)
+ opc = PMIC_ARB_OP_EXT_WRITEL;
+ else if (opc >= 0x80 && opc <= 0xFF)
+ opc = PMIC_ARB_OP_ZERO_WRITE;
+ else
+ return -EINVAL;
+
+ cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
+
+ /* Write data to FIFOs */
+ raw_spin_lock_irqsave(&pmic_arb->lock, flags);
+ pa_write_data(pmic_arb, buf, PMIC_ARB_WDATA0(pmic_arb->channel)
+ , min_t(u8, bc, 3));
+ if (bc > 3)
+ pa_write_data(pmic_arb, buf + 4,
+ PMIC_ARB_WDATA1(pmic_arb->channel), bc - 4);
+
+ /* Start the transaction */
+ pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
+ rc = pmic_arb_wait_for_done(ctrl);
+ raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+
+ return rc;
+}
+
+enum qpnpint_regs {
+ QPNPINT_REG_RT_STS = 0x10,
+ QPNPINT_REG_SET_TYPE = 0x11,
+ QPNPINT_REG_POLARITY_HIGH = 0x12,
+ QPNPINT_REG_POLARITY_LOW = 0x13,
+ QPNPINT_REG_LATCHED_CLR = 0x14,
+ QPNPINT_REG_EN_SET = 0x15,
+ QPNPINT_REG_EN_CLR = 0x16,
+ QPNPINT_REG_LATCHED_STS = 0x18,
+};
+
+struct spmi_pmic_arb_qpnpint_type {
+ u8 type; /* 1 -> edge */
+ u8 polarity_high;
+ u8 polarity_low;
+} __packed;
+
+/* Simplified accessor functions for irqchip callbacks */
+static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
+ size_t len)
+{
+ struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+ u8 sid = d->hwirq >> 24;
+ u8 per = d->hwirq >> 16;
+
+ if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid,
+ (per << 8) + reg, buf, len))
+ dev_err_ratelimited(&pa->spmic->dev,
+ "failed irqchip transaction on %x\n",
+ d->irq);
+}
+
+static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
+{
+ struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+ u8 sid = d->hwirq >> 24;
+ u8 per = d->hwirq >> 16;
+
+ if (pmic_arb_read_cmd(pa->spmic, SPMI_CMD_EXT_READL, sid,
+ (per << 8) + reg, buf, len))
+ dev_err_ratelimited(&pa->spmic->dev,
+ "failed irqchip transaction on %x\n",
+ d->irq);
+}
+
+static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid)
+{
+ unsigned int irq;
+ u32 status;
+ int id;
+
+ status = readl_relaxed(pa->intr + SPMI_PIC_IRQ_STATUS(apid));
+ while (status) {
+ id = ffs(status) - 1;
+ status &= ~(1 << id);
+ irq = irq_find_mapping(pa->domain,
+ pa->apid_to_ppid[apid] << 16
+ | id << 8
+ | apid);
+ generic_handle_irq(irq);
+ }
+}
+
+static void pmic_arb_chained_irq(unsigned int irq, struct irq_desc *desc)
+{
+ struct spmi_pmic_arb_dev *pa = irq_get_handler_data(irq);
+ struct irq_chip *chip = irq_get_chip(irq);
+ void __iomem *intr = pa->intr;
+ int first = pa->min_apid >> 5;
+ int last = pa->max_apid >> 5;
+ u32 status;
+ int i, id;
+
+ chained_irq_enter(chip, desc);
+
+ for (i = first; i <= last; ++i) {
+ status = readl_relaxed(intr +
+ SPMI_PIC_OWNER_ACC_STATUS(pa->ee, i));
+ while (status) {
+ id = ffs(status) - 1;
+ status &= ~(1 << id);
+ periph_interrupt(pa, id + i * 32);
+ }
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void qpnpint_irq_ack(struct irq_data *d)
+{
+ struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+ u8 irq = d->hwirq >> 8;
+ u8 apid = d->hwirq;
+ unsigned long flags;
+ u8 data;
+
+ raw_spin_lock_irqsave(&pa->lock, flags);
+ writel_relaxed(1 << irq, pa->intr + SPMI_PIC_IRQ_CLEAR(apid));
+ raw_spin_unlock_irqrestore(&pa->lock, flags);
+
+ data = 1 << irq;
+ qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
+}
+
+static void qpnpint_irq_mask(struct irq_data *d)
+{
+ struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+ u8 irq = d->hwirq >> 8;
+ u8 apid = d->hwirq;
+ unsigned long flags;
+ u32 status;
+ u8 data;
+
+ raw_spin_lock_irqsave(&pa->lock, flags);
+ status = readl_relaxed(pa->intr + SPMI_PIC_ACC_ENABLE(apid));
+ if (status & SPMI_PIC_ACC_ENABLE_BIT) {
+ status = status & ~SPMI_PIC_ACC_ENABLE_BIT;
+ writel_relaxed(status, pa->intr + SPMI_PIC_ACC_ENABLE(apid));
+ }
+ raw_spin_unlock_irqrestore(&pa->lock, flags);
+
+ data = 1 << irq;
+ qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
+}
+
+static void qpnpint_irq_unmask(struct irq_data *d)
+{
+ struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+ u8 irq = d->hwirq >> 8;
+ u8 apid = d->hwirq;
+ unsigned long flags;
+ u32 status;
+ u8 data;
+
+ raw_spin_lock_irqsave(&pa->lock, flags);
+ status = readl_relaxed(pa->intr + SPMI_PIC_ACC_ENABLE(apid));
+ if (!(status & SPMI_PIC_ACC_ENABLE_BIT)) {
+ writel_relaxed(status | SPMI_PIC_ACC_ENABLE_BIT,
+ pa->intr + SPMI_PIC_ACC_ENABLE(apid));
+ }
+ raw_spin_unlock_irqrestore(&pa->lock, flags);
+
+ data = 1 << irq;
+ qpnpint_spmi_write(d, QPNPINT_REG_EN_SET, &data, 1);
+}
+
+static void qpnpint_irq_enable(struct irq_data *d)
+{
+ u8 irq = d->hwirq >> 8;
+ u8 data;
+
+ qpnpint_irq_unmask(d);
+
+ data = 1 << irq;
+ qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
+}
+
+static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+ struct spmi_pmic_arb_qpnpint_type type;
+ u8 irq = d->hwirq >> 8;
+
+ qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
+
+ if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+ type.type |= 1 << irq;
+ if (flow_type & IRQF_TRIGGER_RISING)
+ type.polarity_high |= 1 << irq;
+ if (flow_type & IRQF_TRIGGER_FALLING)
+ type.polarity_low |= 1 << irq;
+ } else {
+ if ((flow_type & (IRQF_TRIGGER_HIGH)) &&
+ (flow_type & (IRQF_TRIGGER_LOW)))
+ return -EINVAL;
+
+ type.type &= ~(1 << irq); /* level trig */
+ if (flow_type & IRQF_TRIGGER_HIGH)
+ type.polarity_high |= 1 << irq;
+ else
+ type.polarity_low |= 1 << irq;
+ }
+
+ qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type));
+ return 0;
+}
+
+static struct irq_chip pmic_arb_irqchip = {
+ .name = "pmic_arb",
+ .irq_enable = qpnpint_irq_enable,
+ .irq_ack = qpnpint_irq_ack,
+ .irq_mask = qpnpint_irq_mask,
+ .irq_unmask = qpnpint_irq_unmask,
+ .irq_set_type = qpnpint_irq_set_type,
+ .flags = IRQCHIP_MASK_ON_SUSPEND
+ | IRQCHIP_SKIP_SET_WAKE,
+};
+
+struct spmi_pmic_arb_irq_spec {
+ unsigned slave:4;
+ unsigned per:8;
+ unsigned irq:3;
+};
+
+static int search_mapping_table(struct spmi_pmic_arb_dev *pa,
+ struct spmi_pmic_arb_irq_spec *spec,
+ u8 *apid)
+{
+ u16 ppid = spec->slave << 8 | spec->per;
+ u32 *mapping_table = pa->mapping_table;
+ int index = 0, i;
+ u32 data;
+
+ for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
+ data = mapping_table[index];
+
+ if (ppid & (1 << SPMI_MAPPING_BIT_INDEX(data))) {
+ if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) {
+ index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
+ } else {
+ *apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
+ return 0;
+ }
+ } else {
+ if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) {
+ index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
+ } else {
+ *apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
+ return 0;
+ }
+ }
+ }
+
+ return -ENODEV;
+}
+
+static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
+ struct device_node *controller,
+ const u32 *intspec,
+ unsigned int intsize,
+ unsigned long *out_hwirq,
+ unsigned int *out_type)
+{
+ struct spmi_pmic_arb_dev *pa = d->host_data;
+ struct spmi_pmic_arb_irq_spec spec;
+ int err;
+ u8 apid;
+
+ dev_dbg(&pa->spmic->dev,
+ "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n",
+ intspec[0], intspec[1], intspec[2]);
+
+ if (d->of_node != controller)
+ return -EINVAL;
+ if (intsize != 4)
+ return -EINVAL;
+ if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7)
+ return -EINVAL;
+
+ spec.slave = intspec[0];
+ spec.per = intspec[1];
+ spec.irq = intspec[2];
+
+ err = search_mapping_table(pa, &spec, &apid);
+ if (err)
+ return err;
+
+ pa->apid_to_ppid[apid] = spec.slave << 8 | spec.per;
+
+ /* Keep track of {max,min}_apid for bounding search during interrupt */
+ if (apid > pa->max_apid)
+ pa->max_apid = apid;
+ if (apid < pa->min_apid)
+ pa->min_apid = apid;
+
+ *out_hwirq = spec.slave << 24
+ | spec.per << 16
+ | spec.irq << 8
+ | apid;
+ *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK;
+
+ dev_dbg(&pa->spmic->dev, "out_hwirq = %lu\n", *out_hwirq);
+
+ return 0;
+}
+
+static int qpnpint_irq_domain_map(struct irq_domain *d,
+ unsigned int virq,
+ irq_hw_number_t hwirq)
+{
+ struct spmi_pmic_arb_dev *pa = d->host_data;
+
+ dev_dbg(&pa->spmic->dev, "virq = %u, hwirq = %lu\n", virq, hwirq);
+
+ irq_set_chip_and_handler(virq, &pmic_arb_irqchip, handle_level_irq);
+ irq_set_chip_data(virq, d->host_data);
+ irq_set_noprobe(virq);
+ return 0;
+}
+
+static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
+ .map = qpnpint_irq_domain_map,
+ .xlate = qpnpint_irq_domain_dt_translate,
+};
+
+static int spmi_pmic_arb_probe(struct platform_device *pdev)
+{
+ struct spmi_pmic_arb_dev *pa;
+ struct spmi_controller *ctrl;
+ struct resource *res;
+ u32 channel, ee;
+ int err, i;
+
+ ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa));
+ if (!ctrl)
+ return -ENOMEM;
+
+ pa = spmi_controller_get_drvdata(ctrl);
+ pa->spmic = ctrl;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+ pa->base = devm_ioremap_resource(&ctrl->dev, res);
+ if (IS_ERR(pa->base)) {
+ err = PTR_ERR(pa->base);
+ goto err_put_ctrl;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
+ pa->intr = devm_ioremap_resource(&ctrl->dev, res);
+ if (IS_ERR(pa->intr)) {
+ err = PTR_ERR(pa->intr);
+ goto err_put_ctrl;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg");
+ pa->cnfg = devm_ioremap_resource(&ctrl->dev, res);
+ if (IS_ERR(pa->cnfg)) {
+ err = PTR_ERR(pa->cnfg);
+ goto err_put_ctrl;
+ }
+
+ pa->irq = platform_get_irq_byname(pdev, "periph_irq");
+ if (pa->irq < 0) {
+ err = pa->irq;
+ goto err_put_ctrl;
+ }
+
+ err = of_property_read_u32(pdev->dev.of_node, "qcom,channel", &channel);
+ if (err) {
+ dev_err(&pdev->dev, "channel unspecified.\n");
+ goto err_put_ctrl;
+ }
+
+ if (channel > 5) {
+ dev_err(&pdev->dev, "invalid channel (%u) specified.\n",
+ channel);
+ goto err_put_ctrl;
+ }
+
+ pa->channel = channel;
+
+ err = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &ee);
+ if (err) {
+ dev_err(&pdev->dev, "EE unspecified.\n");
+ goto err_put_ctrl;
+ }
+
+ if (ee > 5) {
+ dev_err(&pdev->dev, "invalid EE (%u) specified\n", ee);
+ err = -EINVAL;
+ goto err_put_ctrl;
+ }
+
+ pa->ee = ee;
+
+ for (i = 0; i < ARRAY_SIZE(pa->mapping_table); ++i)
+ pa->mapping_table[i] = readl_relaxed(
+ pa->cnfg + SPMI_MAPPING_TABLE_REG(i));
+
+ /* Initialize max_apid/min_apid to the opposite bounds, during
+ * the irq domain translation, we are sure to update these */
+ pa->max_apid = 0;
+ pa->min_apid = PMIC_ARB_MAX_PERIPHS - 1;
+
+ platform_set_drvdata(pdev, ctrl);
+ raw_spin_lock_init(&pa->lock);
+
+ ctrl->cmd = pmic_arb_cmd;
+ ctrl->read_cmd = pmic_arb_read_cmd;
+ ctrl->write_cmd = pmic_arb_write_cmd;
+
+ dev_dbg(&pdev->dev, "adding irq domain\n");
+ pa->domain = irq_domain_add_tree(pdev->dev.of_node,
+ &pmic_arb_irq_domain_ops, pa);
+ if (!pa->domain) {
+ dev_err(&pdev->dev, "unable to create irq_domain\n");
+ err = -ENOMEM;
+ goto err_put_ctrl;
+ }
+
+ irq_set_handler_data(pa->irq, pa);
+ irq_set_chained_handler(pa->irq, pmic_arb_chained_irq);
+
+ err = spmi_controller_add(ctrl);
+ if (err)
+ goto err_domain_remove;
+
+ dev_dbg(&ctrl->dev, "PMIC Arb Version 0x%x\n",
+ pmic_arb_base_read(pa, PMIC_ARB_VERSION));
+
+ return 0;
+
+err_domain_remove:
+ irq_set_chained_handler(pa->irq, NULL);
+ irq_set_handler_data(pa->irq, NULL);
+ irq_domain_remove(pa->domain);
+err_put_ctrl:
+ spmi_controller_put(ctrl);
+ return err;
+}
+
+static int spmi_pmic_arb_remove(struct platform_device *pdev)
+{
+ struct spmi_controller *ctrl = platform_get_drvdata(pdev);
+ struct spmi_pmic_arb_dev *pa = spmi_controller_get_drvdata(ctrl);
+ spmi_controller_remove(ctrl);
+ irq_set_chained_handler(pa->irq, NULL);
+ irq_set_handler_data(pa->irq, NULL);
+ irq_domain_remove(pa->domain);
+ spmi_controller_put(ctrl);
+ return 0;
+}
+
+static const struct of_device_id spmi_pmic_arb_match_table[] = {
+ { .compatible = "qcom,spmi-pmic-arb", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table);
+
+static struct platform_driver spmi_pmic_arb_driver = {
+ .probe = spmi_pmic_arb_probe,
+ .remove = spmi_pmic_arb_remove,
+ .driver = {
+ .name = "spmi_pmic_arb",
+ .owner = THIS_MODULE,
+ .of_match_table = spmi_pmic_arb_match_table,
+ },
+};
+module_platform_driver(spmi_pmic_arb_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:spmi_pmic_arb");
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
new file mode 100644
index 000000000000..3b5780710d50
--- /dev/null
+++ b/drivers/spmi/spmi.c
@@ -0,0 +1,574 @@
+/* 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/idr.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/spmi.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#include <dt-bindings/spmi/spmi.h>
+
+static DEFINE_IDA(ctrl_ida);
+
+static void spmi_dev_release(struct device *dev)
+{
+ struct spmi_device *sdev = to_spmi_device(dev);
+ kfree(sdev);
+}
+
+static const struct device_type spmi_dev_type = {
+ .release = spmi_dev_release,
+};
+
+static void spmi_ctrl_release(struct device *dev)
+{
+ struct spmi_controller *ctrl = to_spmi_controller(dev);
+ ida_simple_remove(&ctrl_ida, ctrl->nr);
+ kfree(ctrl);
+}
+
+static const struct device_type spmi_ctrl_type = {
+ .release = spmi_ctrl_release,
+};
+
+static int spmi_device_match(struct device *dev, struct device_driver *drv)
+{
+ if (of_driver_match_device(dev, drv))
+ return 1;
+
+ if (drv->name)
+ return strncmp(dev_name(dev), drv->name,
+ SPMI_NAME_SIZE) == 0;
+
+ return 0;
+}
+
+/**
+ * spmi_device_add() - add a device previously constructed via spmi_device_alloc()
+ * @sdev: spmi_device to be added
+ */
+int spmi_device_add(struct spmi_device *sdev)
+{
+ struct spmi_controller *ctrl = sdev->ctrl;
+ int err;
+
+ dev_set_name(&sdev->dev, "%d-%02x", ctrl->nr, sdev->usid);
+
+ err = device_add(&sdev->dev);
+ if (err < 0) {
+ dev_err(&sdev->dev, "Can't add %s, status %d\n",
+ dev_name(&sdev->dev), err);
+ goto err_device_add;
+ }
+
+ dev_dbg(&sdev->dev, "device %s registered\n", dev_name(&sdev->dev));
+
+err_device_add:
+ return err;
+}
+EXPORT_SYMBOL_GPL(spmi_device_add);
+
+/**
+ * spmi_device_remove(): remove an SPMI device
+ * @sdev: spmi_device to be removed
+ */
+void spmi_device_remove(struct spmi_device *sdev)
+{
+ device_unregister(&sdev->dev);
+}
+EXPORT_SYMBOL_GPL(spmi_device_remove);
+
+static inline int
+spmi_cmd(struct spmi_controller *ctrl, u8 opcode, u8 sid)
+{
+ if (!ctrl || !ctrl->cmd || ctrl->dev.type != &spmi_ctrl_type)
+ return -EINVAL;
+
+ return ctrl->cmd(ctrl, opcode, sid);
+}
+
+static inline int spmi_read_cmd(struct spmi_controller *ctrl, u8 opcode,
+ u8 sid, u16 addr, u8 *buf, size_t len)
+{
+ if (!ctrl || !ctrl->read_cmd || ctrl->dev.type != &spmi_ctrl_type)
+ return -EINVAL;
+
+ return ctrl->read_cmd(ctrl, opcode, sid, addr, buf, len);
+}
+
+static inline int spmi_write_cmd(struct spmi_controller *ctrl, u8 opcode,
+ u8 sid, u16 addr, const u8 *buf, size_t len)
+{
+ if (!ctrl || !ctrl->write_cmd || ctrl->dev.type != &spmi_ctrl_type)
+ return -EINVAL;
+
+ return ctrl->write_cmd(ctrl, opcode, sid, addr, buf, len);
+}
+
+/**
+ * spmi_register_read() - register read
+ * @sdev: SPMI device.
+ * @addr: slave register address (5-bit address).
+ * @buf: buffer to be populated with data from the Slave.
+ *
+ * Reads 1 byte of data from a Slave device register.
+ */
+int spmi_register_read(struct spmi_device *sdev, u8 addr, u8 *buf)
+{
+ /* 5-bit register address */
+ if (addr > 0x1F)
+ return -EINVAL;
+
+ return spmi_read_cmd(sdev->ctrl, SPMI_CMD_READ, sdev->usid, addr,
+ buf, 1);
+}
+EXPORT_SYMBOL_GPL(spmi_register_read);
+
+/**
+ * spmi_ext_register_read() - extended register read
+ * @sdev: SPMI device.
+ * @addr: slave register address (8-bit address).
+ * @buf: buffer to be populated with data from the Slave.
+ * @len: the request number of bytes to read (up to 16 bytes).
+ *
+ * Reads up to 16 bytes of data from the extended register space on a
+ * Slave device.
+ */
+int spmi_ext_register_read(struct spmi_device *sdev, u8 addr, u8 *buf,
+ size_t len)
+{
+ /* 8-bit register address, up to 16 bytes */
+ if (len == 0 || len > 16)
+ return -EINVAL;
+
+ return spmi_read_cmd(sdev->ctrl, SPMI_CMD_EXT_READ, sdev->usid, addr,
+ buf, len);
+}
+EXPORT_SYMBOL_GPL(spmi_ext_register_read);
+
+/**
+ * spmi_ext_register_readl() - extended register read long
+ * @sdev: SPMI device.
+ * @addr: slave register address (16-bit address).
+ * @buf: buffer to be populated with data from the Slave.
+ * @len: the request number of bytes to read (up to 8 bytes).
+ *
+ * Reads up to 8 bytes of data from the extended register space on a
+ * Slave device using 16-bit address.
+ */
+int spmi_ext_register_readl(struct spmi_device *sdev, u16 addr, u8 *buf,
+ size_t len)
+{
+ /* 16-bit register address, up to 8 bytes */
+ if (len == 0 || len > 8)
+ return -EINVAL;
+
+ return spmi_read_cmd(sdev->ctrl, SPMI_CMD_EXT_READL, sdev->usid, addr,
+ buf, len);
+}
+EXPORT_SYMBOL_GPL(spmi_ext_register_readl);
+
+/**
+ * spmi_register_write() - register write
+ * @sdev: SPMI device
+ * @addr: slave register address (5-bit address).
+ * @data: buffer containing the data to be transferred to the Slave.
+ *
+ * Writes 1 byte of data to a Slave device register.
+ */
+int spmi_register_write(struct spmi_device *sdev, u8 addr, u8 data)
+{
+ /* 5-bit register address */
+ if (addr > 0x1F)
+ return -EINVAL;
+
+ return spmi_write_cmd(sdev->ctrl, SPMI_CMD_WRITE, sdev->usid, addr,
+ &data, 1);
+}
+EXPORT_SYMBOL_GPL(spmi_register_write);
+
+/**
+ * spmi_register_zero_write() - register zero write
+ * @sdev: SPMI device.
+ * @data: the data to be written to register 0 (7-bits).
+ *
+ * Writes data to register 0 of the Slave device.
+ */
+int spmi_register_zero_write(struct spmi_device *sdev, u8 data)
+{
+ return spmi_write_cmd(sdev->ctrl, SPMI_CMD_ZERO_WRITE, sdev->usid, 0,
+ &data, 1);
+}
+EXPORT_SYMBOL_GPL(spmi_register_zero_write);
+
+/**
+ * spmi_ext_register_write() - extended register write
+ * @sdev: SPMI device.
+ * @addr: slave register address (8-bit address).
+ * @buf: buffer containing the data to be transferred to the Slave.
+ * @len: the request number of bytes to read (up to 16 bytes).
+ *
+ * Writes up to 16 bytes of data to the extended register space of a
+ * Slave device.
+ */
+int spmi_ext_register_write(struct spmi_device *sdev, u8 addr, const u8 *buf,
+ size_t len)
+{
+ /* 8-bit register address, up to 16 bytes */
+ if (len == 0 || len > 16)
+ return -EINVAL;
+
+ return spmi_write_cmd(sdev->ctrl, SPMI_CMD_EXT_WRITE, sdev->usid, addr,
+ buf, len);
+}
+EXPORT_SYMBOL_GPL(spmi_ext_register_write);
+
+/**
+ * spmi_ext_register_writel() - extended register write long
+ * @sdev: SPMI device.
+ * @addr: slave register address (16-bit address).
+ * @buf: buffer containing the data to be transferred to the Slave.
+ * @len: the request number of bytes to read (up to 8 bytes).
+ *
+ * Writes up to 8 bytes of data to the extended register space of a
+ * Slave device using 16-bit address.
+ */
+int spmi_ext_register_writel(struct spmi_device *sdev, u16 addr, const u8 *buf,
+ size_t len)
+{
+ /* 4-bit Slave Identifier, 16-bit register address, up to 8 bytes */
+ if (len == 0 || len > 8)
+ return -EINVAL;
+
+ return spmi_write_cmd(sdev->ctrl, SPMI_CMD_EXT_WRITEL, sdev->usid,
+ addr, buf, len);
+}
+EXPORT_SYMBOL_GPL(spmi_ext_register_writel);
+
+/**
+ * spmi_command_reset() - sends RESET command to the specified slave
+ * @sdev: SPMI device.
+ *
+ * The Reset command initializes the Slave and forces all registers to
+ * their reset values. The Slave shall enter the STARTUP state after
+ * receiving a Reset command.
+ */
+int spmi_command_reset(struct spmi_device *sdev)
+{
+ return spmi_cmd(sdev->ctrl, SPMI_CMD_RESET, sdev->usid);
+}
+EXPORT_SYMBOL_GPL(spmi_command_reset);
+
+/**
+ * spmi_command_sleep() - sends SLEEP command to the specified SPMI device
+ * @sdev: SPMI device.
+ *
+ * The Sleep command causes the Slave to enter the user defined SLEEP state.
+ */
+int spmi_command_sleep(struct spmi_device *sdev)
+{
+ return spmi_cmd(sdev->ctrl, SPMI_CMD_SLEEP, sdev->usid);
+}
+EXPORT_SYMBOL_GPL(spmi_command_sleep);
+
+/**
+ * spmi_command_wakeup() - sends WAKEUP command to the specified SPMI device
+ * @sdev: SPMI device.
+ *
+ * The Wakeup command causes the Slave to move from the SLEEP state to
+ * the ACTIVE state.
+ */
+int spmi_command_wakeup(struct spmi_device *sdev)
+{
+ return spmi_cmd(sdev->ctrl, SPMI_CMD_WAKEUP, sdev->usid);
+}
+EXPORT_SYMBOL_GPL(spmi_command_wakeup);
+
+/**
+ * spmi_command_shutdown() - sends SHUTDOWN command to the specified SPMI device
+ * @sdev: SPMI device.
+ *
+ * The Shutdown command causes the Slave to enter the SHUTDOWN state.
+ */
+int spmi_command_shutdown(struct spmi_device *sdev)
+{
+ return spmi_cmd(sdev->ctrl, SPMI_CMD_SHUTDOWN, sdev->usid);
+}
+EXPORT_SYMBOL_GPL(spmi_command_shutdown);
+
+static int spmi_drv_probe(struct device *dev)
+{
+ const struct spmi_driver *sdrv = to_spmi_driver(dev->driver);
+ struct spmi_device *sdev = to_spmi_device(dev);
+ int err;
+
+ /* Ensure the slave is in ACTIVE state */
+ err = spmi_command_wakeup(sdev);
+ if (err)
+ goto fail_wakeup;
+
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ err = sdrv->probe(sdev);
+ if (err)
+ goto fail_probe;
+
+ return 0;
+
+fail_probe:
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
+fail_wakeup:
+ return err;
+}
+
+static int spmi_drv_remove(struct device *dev)
+{
+ const struct spmi_driver *sdrv = to_spmi_driver(dev->driver);
+
+ pm_runtime_get_sync(dev);
+ sdrv->remove(to_spmi_device(dev));
+ pm_runtime_put_noidle(dev);
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
+ return 0;
+}
+
+static struct bus_type spmi_bus_type = {
+ .name = "spmi",
+ .match = spmi_device_match,
+ .probe = spmi_drv_probe,
+ .remove = spmi_drv_remove,
+};
+
+/**
+ * spmi_controller_alloc() - Allocate a new SPMI device
+ * @ctrl: associated controller
+ *
+ * Caller is responsible for either calling spmi_device_add() to add the
+ * newly allocated controller, or calling spmi_device_put() to discard it.
+ */
+struct spmi_device *spmi_device_alloc(struct spmi_controller *ctrl)
+{
+ struct spmi_device *sdev;
+
+ sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
+ if (!sdev)
+ return NULL;
+
+ sdev->ctrl = ctrl;
+ device_initialize(&sdev->dev);
+ sdev->dev.parent = &ctrl->dev;
+ sdev->dev.bus = &spmi_bus_type;
+ sdev->dev.type = &spmi_dev_type;
+ return sdev;
+}
+EXPORT_SYMBOL_GPL(spmi_device_alloc);
+
+/**
+ * spmi_controller_alloc() - Allocate a new SPMI controller
+ * @parent: parent device
+ * @size: size of private data
+ *
+ * Caller is responsible for either calling spmi_controller_add() to add the
+ * newly allocated controller, or calling spmi_controller_put() to discard it.
+ * The allocated private data region may be accessed via
+ * spmi_controller_get_drvdata()
+ */
+struct spmi_controller *spmi_controller_alloc(struct device *parent,
+ size_t size)
+{
+ struct spmi_controller *ctrl;
+ int id;
+
+ if (WARN_ON(!parent))
+ return NULL;
+
+ ctrl = kzalloc(sizeof(*ctrl) + size, GFP_KERNEL);
+ if (!ctrl)
+ return NULL;
+
+ device_initialize(&ctrl->dev);
+ ctrl->dev.type = &spmi_ctrl_type;
+ ctrl->dev.bus = &spmi_bus_type;
+ ctrl->dev.parent = parent;
+ ctrl->dev.of_node = parent->of_node;
+ spmi_controller_set_drvdata(ctrl, &ctrl[1]);
+
+ id = ida_simple_get(&ctrl_ida, 0, 0, GFP_KERNEL);
+ if (id < 0) {
+ dev_err(parent,
+ "unable to allocate SPMI controller identifier.\n");
+ spmi_controller_put(ctrl);
+ return NULL;
+ }
+
+ ctrl->nr = id;
+ dev_set_name(&ctrl->dev, "spmi-%d", id);
+
+ dev_dbg(&ctrl->dev, "allocated controller 0x%p id %d\n", ctrl, id);
+ return ctrl;
+}
+EXPORT_SYMBOL_GPL(spmi_controller_alloc);
+
+static void of_spmi_register_devices(struct spmi_controller *ctrl)
+{
+ struct device_node *node;
+ int err;
+
+ if (!ctrl->dev.of_node)
+ return;
+
+ for_each_available_child_of_node(ctrl->dev.of_node, node) {
+ struct spmi_device *sdev;
+ u32 reg[2];
+
+ dev_dbg(&ctrl->dev, "adding child %s\n", node->full_name);
+
+ err = of_property_read_u32_array(node, "reg", reg, 2);
+ if (err) {
+ dev_err(&ctrl->dev,
+ "node %s err (%d) does not have 'reg' property\n",
+ node->full_name, err);
+ continue;
+ }
+
+ if (reg[1] != SPMI_USID) {
+ dev_err(&ctrl->dev,
+ "node %s contains unsupported 'reg' entry\n",
+ node->full_name);
+ continue;
+ }
+
+ if (reg[0] >= SPMI_MAX_SLAVE_ID) {
+ dev_err(&ctrl->dev,
+ "invalid usid on node %s\n",
+ node->full_name);
+ continue;
+ }
+
+ dev_dbg(&ctrl->dev, "read usid %02x\n", reg[0]);
+
+ sdev = spmi_device_alloc(ctrl);
+ if (!sdev)
+ continue;
+
+ sdev->dev.of_node = node;
+ sdev->usid = (u8) reg[0];
+
+ err = spmi_device_add(sdev);
+ if (err) {
+ dev_err(&sdev->dev,
+ "failure adding device. status %d\n", err);
+ spmi_device_put(sdev);
+ }
+ }
+}
+
+/**
+ * spmi_controller_add() - Add an SPMI controller
+ * @ctrl: controller to be registered.
+ *
+ * Register a controller previously allocated via spmi_controller_alloc() with
+ * the SPMI core.
+ */
+int spmi_controller_add(struct spmi_controller *ctrl)
+{
+ int ret;
+
+ /* Can't register until after driver model init */
+ if (WARN_ON(!spmi_bus_type.p))
+ return -EAGAIN;
+
+ ret = device_add(&ctrl->dev);
+ if (ret)
+ return ret;
+
+ if (IS_ENABLED(CONFIG_OF))
+ of_spmi_register_devices(ctrl);
+
+ dev_dbg(&ctrl->dev, "spmi-%d registered: dev:%p\n",
+ ctrl->nr, &ctrl->dev);
+
+ return 0;
+};
+EXPORT_SYMBOL_GPL(spmi_controller_add);
+
+/* Remove a device associated with a controller */
+static int spmi_ctrl_remove_device(struct device *dev, void *data)
+{
+ struct spmi_device *spmidev = to_spmi_device(dev);
+ if (dev->type == &spmi_dev_type)
+ spmi_device_remove(spmidev);
+ return 0;
+}
+
+/**
+ * spmi_controller_remove(): remove an SPMI controller
+ * @ctrl: controller to remove
+ *
+ * Remove a SPMI controller. Caller is responsible for calling
+ * spmi_controller_put() to discard the allocated controller.
+ */
+void spmi_controller_remove(struct spmi_controller *ctrl)
+{
+ int dummy;
+
+ if (!ctrl)
+ return;
+
+ dummy = device_for_each_child(&ctrl->dev, NULL,
+ spmi_ctrl_remove_device);
+ device_del(&ctrl->dev);
+}
+EXPORT_SYMBOL_GPL(spmi_controller_remove);
+
+/**
+ * spmi_driver_register() - Register client driver with SPMI core
+ * @sdrv: client driver to be associated with client-device.
+ *
+ * This API will register the client driver with the SPMI framework.
+ * It is typically called from the driver's module-init function.
+ */
+int spmi_driver_register(struct spmi_driver *sdrv)
+{
+ sdrv->driver.bus = &spmi_bus_type;
+ return driver_register(&sdrv->driver);
+}
+EXPORT_SYMBOL_GPL(spmi_driver_register);
+
+static void __exit spmi_exit(void)
+{
+ bus_unregister(&spmi_bus_type);
+}
+module_exit(spmi_exit);
+
+static int __init spmi_init(void)
+{
+ return bus_register(&spmi_bus_type);
+}
+postcore_initcall(spmi_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SPMI module");
+MODULE_ALIAS("platform:spmi");
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 99375f0a9440..47cf17543008 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -34,8 +34,6 @@ source "drivers/staging/winbond/Kconfig"
source "drivers/staging/wlan-ng/Kconfig"
-source "drivers/staging/echo/Kconfig"
-
source "drivers/staging/comedi/Kconfig"
source "drivers/staging/olpc_dcon/Kconfig"
@@ -82,8 +80,6 @@ source "drivers/staging/wlags49_h2/Kconfig"
source "drivers/staging/wlags49_h25/Kconfig"
-source "drivers/staging/sm7xxfb/Kconfig"
-
source "drivers/staging/crystalhd/Kconfig"
source "drivers/staging/cxt1e1/Kconfig"
@@ -128,8 +124,6 @@ source "drivers/staging/imx-drm/Kconfig"
source "drivers/staging/dgrp/Kconfig"
-source "drivers/staging/sb105x/Kconfig"
-
source "drivers/staging/fwserial/Kconfig"
source "drivers/staging/goldfish/Kconfig"
@@ -146,4 +140,10 @@ source "drivers/staging/dgnc/Kconfig"
source "drivers/staging/dgap/Kconfig"
+source "drivers/staging/gs_fpgaboot/Kconfig"
+
+source "drivers/staging/nokia_h4p/Kconfig"
+
+source "drivers/staging/unisys/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index ddc3c4a5d39d..d12f6189db46 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_USBIP_CORE) += usbip/
obj-$(CONFIG_W35UND) += winbond/
obj-$(CONFIG_PRISM2_USB) += wlan-ng/
-obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_COMEDI) += comedi/
obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/
obj-$(CONFIG_PANEL) += panel/
@@ -35,7 +34,6 @@ obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
-obj-$(CONFIG_FB_SM7XX) += sm7xxfb/
obj-$(CONFIG_CRYSTALHD) += crystalhd/
obj-$(CONFIG_CXT1E1) += cxt1e1/
obj-$(CONFIG_FB_XGI) += xgifb/
@@ -57,7 +55,6 @@ obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/
obj-$(CONFIG_CED1401) += ced1401/
obj-$(CONFIG_DRM_IMX) += imx-drm/
obj-$(CONFIG_DGRP) += dgrp/
-obj-$(CONFIG_SB105X) += sb105x/
obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/
obj-$(CONFIG_GOLDFISH) += goldfish/
obj-$(CONFIG_LUSTRE_FS) += lustre/
@@ -65,3 +62,6 @@ obj-$(CONFIG_XILLYBUS) += xillybus/
obj-$(CONFIG_DGNC) += dgnc/
obj-$(CONFIG_DGAP) += dgap/
obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/
+obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/
+obj-$(CONFIG_BT_NOKIA_H4P) += nokia_h4p/
+obj-$(CONFIG_UNISYSSPAR) += unisys/
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index b6b869261f32..99e484f845f2 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -19,6 +19,19 @@ config ANDROID_BINDER_IPC
Android process, using Binder to identify, invoke and pass arguments
between said processes.
+config ANDROID_BINDER_IPC_32BIT
+ bool
+ depends on !64BIT && ANDROID_BINDER_IPC
+ default y
+ ---help---
+ The Binder API has been changed to support both 32 and 64bit
+ applications in a mixed environment.
+
+ Enable this to support an old 32-bit Android user-space (v4.4 and
+ earlier).
+
+ Note that enabling this will break newer Android user-space.
+
config ASHMEM
bool "Enable the Anonymous Shared Memory Subsystem"
default n
diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h
index 4fd32f337f9c..495b20cf3bf6 100644
--- a/drivers/staging/android/android_alarm.h
+++ b/drivers/staging/android/android_alarm.h
@@ -16,50 +16,10 @@
#ifndef _LINUX_ANDROID_ALARM_H
#define _LINUX_ANDROID_ALARM_H
-#include <linux/ioctl.h>
-#include <linux/time.h>
#include <linux/compat.h>
+#include <linux/ioctl.h>
-enum android_alarm_type {
- /* return code bit numbers or set alarm arg */
- ANDROID_ALARM_RTC_WAKEUP,
- ANDROID_ALARM_RTC,
- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
- ANDROID_ALARM_ELAPSED_REALTIME,
- ANDROID_ALARM_SYSTEMTIME,
-
- ANDROID_ALARM_TYPE_COUNT,
-
- /* return code bit numbers */
- /* ANDROID_ALARM_TIME_CHANGE = 16 */
-};
-
-enum android_alarm_return_flags {
- ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
- ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
- 1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
- ANDROID_ALARM_ELAPSED_REALTIME_MASK =
- 1U << ANDROID_ALARM_ELAPSED_REALTIME,
- ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
- ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
-};
-
-/* Disable alarm */
-#define ANDROID_ALARM_CLEAR(type) _IO('a', 0 | ((type) << 4))
-
-/* Ack last alarm and wait for next */
-#define ANDROID_ALARM_WAIT _IO('a', 1)
-
-#define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size)
-/* Set alarm */
-#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec)
-#define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec)
-#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec)
-#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec)
-#define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0)))
-#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4)
-
+#include "uapi/android_alarm.h"
#ifdef CONFIG_COMPAT
#define ANDROID_ALARM_SET_COMPAT(type) ALARM_IOW(2, type, \
diff --git a/drivers/staging/android/ashmem.h b/drivers/staging/android/ashmem.h
index 8dc0f0d3adf3..5abcfd7aa706 100644
--- a/drivers/staging/android/ashmem.h
+++ b/drivers/staging/android/ashmem.h
@@ -16,35 +16,7 @@
#include <linux/ioctl.h>
#include <linux/compat.h>
-#define ASHMEM_NAME_LEN 256
-
-#define ASHMEM_NAME_DEF "dev/ashmem"
-
-/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
-#define ASHMEM_NOT_PURGED 0
-#define ASHMEM_WAS_PURGED 1
-
-/* Return values from ASHMEM_GET_PIN_STATUS: Is the mapping pinned? */
-#define ASHMEM_IS_UNPINNED 0
-#define ASHMEM_IS_PINNED 1
-
-struct ashmem_pin {
- __u32 offset; /* offset into region, in bytes, page-aligned */
- __u32 len; /* length forward from offset, in bytes, page-aligned */
-};
-
-#define __ASHMEMIOC 0x77
-
-#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
-#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
-#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t)
-#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4)
-#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long)
-#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6)
-#define ASHMEM_PIN _IOW(__ASHMEMIOC, 7, struct ashmem_pin)
-#define ASHMEM_UNPIN _IOW(__ASHMEMIOC, 8, struct ashmem_pin)
-#define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9)
-#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10)
+#include "uapi/ashmem.h"
/* support of 32bit userspace on 64bit platforms */
#ifdef CONFIG_COMPAT
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index eaec1dab7fe4..cfe4bc8f05cb 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -228,8 +228,8 @@ struct binder_node {
int internal_strong_refs;
int local_weak_refs;
int local_strong_refs;
- void __user *ptr;
- void __user *cookie;
+ binder_uintptr_t ptr;
+ binder_uintptr_t cookie;
unsigned has_strong_ref:1;
unsigned pending_strong_ref:1;
unsigned has_weak_ref:1;
@@ -242,7 +242,7 @@ struct binder_node {
struct binder_ref_death {
struct binder_work work;
- void __user *cookie;
+ binder_uintptr_t cookie;
};
struct binder_ref {
@@ -515,14 +515,14 @@ static void binder_insert_allocated_buffer(struct binder_proc *proc,
}
static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc,
- void __user *user_ptr)
+ uintptr_t user_ptr)
{
struct rb_node *n = proc->allocated_buffers.rb_node;
struct binder_buffer *buffer;
struct binder_buffer *kern_ptr;
- kern_ptr = user_ptr - proc->user_buffer_offset
- - offsetof(struct binder_buffer, data);
+ kern_ptr = (struct binder_buffer *)(user_ptr - proc->user_buffer_offset
+ - offsetof(struct binder_buffer, data));
while (n) {
buffer = rb_entry(n, struct binder_buffer, rb_node);
@@ -856,7 +856,7 @@ static void binder_free_buf(struct binder_proc *proc,
}
static struct binder_node *binder_get_node(struct binder_proc *proc,
- void __user *ptr)
+ binder_uintptr_t ptr)
{
struct rb_node *n = proc->nodes.rb_node;
struct binder_node *node;
@@ -875,8 +875,8 @@ static struct binder_node *binder_get_node(struct binder_proc *proc,
}
static struct binder_node *binder_new_node(struct binder_proc *proc,
- void __user *ptr,
- void __user *cookie)
+ binder_uintptr_t ptr,
+ binder_uintptr_t cookie)
{
struct rb_node **p = &proc->nodes.rb_node;
struct rb_node *parent = NULL;
@@ -908,9 +908,9 @@ static struct binder_node *binder_new_node(struct binder_proc *proc,
INIT_LIST_HEAD(&node->work.entry);
INIT_LIST_HEAD(&node->async_todo);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
- "%d:%d node %d u%p c%p created\n",
+ "%d:%d node %d u%016llx c%016llx created\n",
proc->pid, current->pid, node->debug_id,
- node->ptr, node->cookie);
+ (u64)node->ptr, (u64)node->cookie);
return node;
}
@@ -1226,9 +1226,9 @@ static void binder_send_failed_reply(struct binder_transaction *t,
static void binder_transaction_buffer_release(struct binder_proc *proc,
struct binder_buffer *buffer,
- size_t *failed_at)
+ binder_size_t *failed_at)
{
- size_t *offp, *off_end;
+ binder_size_t *offp, *off_end;
int debug_id = buffer->debug_id;
binder_debug(BINDER_DEBUG_TRANSACTION,
@@ -1239,7 +1239,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
if (buffer->target_node)
binder_dec_node(buffer->target_node, 1, 0);
- offp = (size_t *)(buffer->data + ALIGN(buffer->data_size, sizeof(void *)));
+ offp = (binder_size_t *)(buffer->data +
+ ALIGN(buffer->data_size, sizeof(void *)));
if (failed_at)
off_end = failed_at;
else
@@ -1249,8 +1250,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
if (*offp > buffer->data_size - sizeof(*fp) ||
buffer->data_size < sizeof(*fp) ||
!IS_ALIGNED(*offp, sizeof(u32))) {
- pr_err("transaction release %d bad offset %zd, size %zd\n",
- debug_id, *offp, buffer->data_size);
+ pr_err("transaction release %d bad offset %lld, size %zd\n",
+ debug_id, (u64)*offp, buffer->data_size);
continue;
}
fp = (struct flat_binder_object *)(buffer->data + *offp);
@@ -1259,13 +1260,13 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
case BINDER_TYPE_WEAK_BINDER: {
struct binder_node *node = binder_get_node(proc, fp->binder);
if (node == NULL) {
- pr_err("transaction release %d bad node %p\n",
- debug_id, fp->binder);
+ pr_err("transaction release %d bad node %016llx\n",
+ debug_id, (u64)fp->binder);
break;
}
binder_debug(BINDER_DEBUG_TRANSACTION,
- " node %d u%p\n",
- node->debug_id, node->ptr);
+ " node %d u%016llx\n",
+ node->debug_id, (u64)node->ptr);
binder_dec_node(node, fp->type == BINDER_TYPE_BINDER, 0);
} break;
case BINDER_TYPE_HANDLE:
@@ -1303,7 +1304,7 @@ static void binder_transaction(struct binder_proc *proc,
{
struct binder_transaction *t;
struct binder_work *tcomplete;
- size_t *offp, *off_end;
+ binder_size_t *offp, *off_end;
struct binder_proc *target_proc;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
@@ -1432,18 +1433,20 @@ static void binder_transaction(struct binder_proc *proc,
if (reply)
binder_debug(BINDER_DEBUG_TRANSACTION,
- "%d:%d BC_REPLY %d -> %d:%d, data %p-%p size %zd-%zd\n",
+ "%d:%d BC_REPLY %d -> %d:%d, data %016llx-%016llx size %lld-%lld\n",
proc->pid, thread->pid, t->debug_id,
target_proc->pid, target_thread->pid,
- tr->data.ptr.buffer, tr->data.ptr.offsets,
- tr->data_size, tr->offsets_size);
+ (u64)tr->data.ptr.buffer,
+ (u64)tr->data.ptr.offsets,
+ (u64)tr->data_size, (u64)tr->offsets_size);
else
binder_debug(BINDER_DEBUG_TRANSACTION,
- "%d:%d BC_TRANSACTION %d -> %d - node %d, data %p-%p size %zd-%zd\n",
+ "%d:%d BC_TRANSACTION %d -> %d - node %d, data %016llx-%016llx size %lld-%lld\n",
proc->pid, thread->pid, t->debug_id,
target_proc->pid, target_node->debug_id,
- tr->data.ptr.buffer, tr->data.ptr.offsets,
- tr->data_size, tr->offsets_size);
+ (u64)tr->data.ptr.buffer,
+ (u64)tr->data.ptr.offsets,
+ (u64)tr->data_size, (u64)tr->offsets_size);
if (!reply && !(tr->flags & TF_ONE_WAY))
t->from = thread;
@@ -1472,23 +1475,26 @@ static void binder_transaction(struct binder_proc *proc,
if (target_node)
binder_inc_node(target_node, 1, 0, NULL);
- offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
+ offp = (binder_size_t *)(t->buffer->data +
+ ALIGN(tr->data_size, sizeof(void *)));
- if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {
+ if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
+ tr->data.ptr.buffer, tr->data_size)) {
binder_user_error("%d:%d got transaction with invalid data ptr\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
- if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {
+ if (copy_from_user(offp, (const void __user *)(uintptr_t)
+ tr->data.ptr.offsets, tr->offsets_size)) {
binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
- if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) {
- binder_user_error("%d:%d got transaction with invalid offsets size, %zd\n",
- proc->pid, thread->pid, tr->offsets_size);
+ if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) {
+ binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n",
+ proc->pid, thread->pid, (u64)tr->offsets_size);
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
@@ -1498,8 +1504,8 @@ static void binder_transaction(struct binder_proc *proc,
if (*offp > t->buffer->data_size - sizeof(*fp) ||
t->buffer->data_size < sizeof(*fp) ||
!IS_ALIGNED(*offp, sizeof(u32))) {
- binder_user_error("%d:%d got transaction with invalid offset, %zd\n",
- proc->pid, thread->pid, *offp);
+ binder_user_error("%d:%d got transaction with invalid offset, %lld\n",
+ proc->pid, thread->pid, (u64)*offp);
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
@@ -1519,10 +1525,10 @@ static void binder_transaction(struct binder_proc *proc,
node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
}
if (fp->cookie != node->cookie) {
- binder_user_error("%d:%d sending u%p node %d, cookie mismatch %p != %p\n",
+ binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n",
proc->pid, thread->pid,
- fp->binder, node->debug_id,
- fp->cookie, node->cookie);
+ (u64)fp->binder, node->debug_id,
+ (u64)fp->cookie, (u64)node->cookie);
goto err_binder_get_ref_for_node_failed;
}
ref = binder_get_ref_for_node(target_proc, node);
@@ -1540,9 +1546,9 @@ static void binder_transaction(struct binder_proc *proc,
trace_binder_transaction_node_to_ref(t, node, ref);
binder_debug(BINDER_DEBUG_TRANSACTION,
- " node %d u%p -> ref %d desc %d\n",
- node->debug_id, node->ptr, ref->debug_id,
- ref->desc);
+ " node %d u%016llx -> ref %d desc %d\n",
+ node->debug_id, (u64)node->ptr,
+ ref->debug_id, ref->desc);
} break;
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
@@ -1564,9 +1570,9 @@ static void binder_transaction(struct binder_proc *proc,
binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
trace_binder_transaction_ref_to_node(t, ref);
binder_debug(BINDER_DEBUG_TRANSACTION,
- " ref %d desc %d -> node %d u%p\n",
+ " ref %d desc %d -> node %d u%016llx\n",
ref->debug_id, ref->desc, ref->node->debug_id,
- ref->node->ptr);
+ (u64)ref->node->ptr);
} else {
struct binder_ref *new_ref;
new_ref = binder_get_ref_for_node(target_proc, ref->node);
@@ -1682,9 +1688,9 @@ err_dead_binder:
err_invalid_target_handle:
err_no_context_mgr_node:
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
- "%d:%d transaction failed %d, size %zd-%zd\n",
+ "%d:%d transaction failed %d, size %lld-%lld\n",
proc->pid, thread->pid, return_error,
- tr->data_size, tr->offsets_size);
+ (u64)tr->data_size, (u64)tr->offsets_size);
{
struct binder_transaction_log_entry *fe;
@@ -1702,9 +1708,11 @@ err_no_context_mgr_node:
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
- void __user *buffer, size_t size, size_t *consumed)
+ binder_uintptr_t binder_buffer, size_t size,
+ binder_size_t *consumed)
{
uint32_t cmd;
+ void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
@@ -1773,33 +1781,33 @@ static int binder_thread_write(struct binder_proc *proc,
}
case BC_INCREFS_DONE:
case BC_ACQUIRE_DONE: {
- void __user *node_ptr;
- void __user *cookie;
+ binder_uintptr_t node_ptr;
+ binder_uintptr_t cookie;
struct binder_node *node;
- if (get_user(node_ptr, (void * __user *)ptr))
+ if (get_user(node_ptr, (binder_uintptr_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
- if (get_user(cookie, (void * __user *)ptr))
+ ptr += sizeof(binder_uintptr_t);
+ if (get_user(cookie, (binder_uintptr_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
+ ptr += sizeof(binder_uintptr_t);
node = binder_get_node(proc, node_ptr);
if (node == NULL) {
- binder_user_error("%d:%d %s u%p no match\n",
+ binder_user_error("%d:%d %s u%016llx no match\n",
proc->pid, thread->pid,
cmd == BC_INCREFS_DONE ?
"BC_INCREFS_DONE" :
"BC_ACQUIRE_DONE",
- node_ptr);
+ (u64)node_ptr);
break;
}
if (cookie != node->cookie) {
- binder_user_error("%d:%d %s u%p node %d cookie mismatch %p != %p\n",
+ binder_user_error("%d:%d %s u%016llx node %d cookie mismatch %016llx != %016llx\n",
proc->pid, thread->pid,
cmd == BC_INCREFS_DONE ?
"BC_INCREFS_DONE" : "BC_ACQUIRE_DONE",
- node_ptr, node->debug_id,
- cookie, node->cookie);
+ (u64)node_ptr, node->debug_id,
+ (u64)cookie, (u64)node->cookie);
break;
}
if (cmd == BC_ACQUIRE_DONE) {
@@ -1835,27 +1843,28 @@ static int binder_thread_write(struct binder_proc *proc,
return -EINVAL;
case BC_FREE_BUFFER: {
- void __user *data_ptr;
+ binder_uintptr_t data_ptr;
struct binder_buffer *buffer;
- if (get_user(data_ptr, (void * __user *)ptr))
+ if (get_user(data_ptr, (binder_uintptr_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
+ ptr += sizeof(binder_uintptr_t);
buffer = binder_buffer_lookup(proc, data_ptr);
if (buffer == NULL) {
- binder_user_error("%d:%d BC_FREE_BUFFER u%p no match\n",
- proc->pid, thread->pid, data_ptr);
+ binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n",
+ proc->pid, thread->pid, (u64)data_ptr);
break;
}
if (!buffer->allow_user_free) {
- binder_user_error("%d:%d BC_FREE_BUFFER u%p matched unreturned buffer\n",
- proc->pid, thread->pid, data_ptr);
+ binder_user_error("%d:%d BC_FREE_BUFFER u%016llx matched unreturned buffer\n",
+ proc->pid, thread->pid, (u64)data_ptr);
break;
}
binder_debug(BINDER_DEBUG_FREE_BUFFER,
- "%d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n",
- proc->pid, thread->pid, data_ptr, buffer->debug_id,
+ "%d:%d BC_FREE_BUFFER u%016llx found buffer %d for %s transaction\n",
+ proc->pid, thread->pid, (u64)data_ptr,
+ buffer->debug_id,
buffer->transaction ? "active" : "finished");
if (buffer->transaction) {
@@ -1925,16 +1934,16 @@ static int binder_thread_write(struct binder_proc *proc,
case BC_REQUEST_DEATH_NOTIFICATION:
case BC_CLEAR_DEATH_NOTIFICATION: {
uint32_t target;
- void __user *cookie;
+ binder_uintptr_t cookie;
struct binder_ref *ref;
struct binder_ref_death *death;
if (get_user(target, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
- if (get_user(cookie, (void __user * __user *)ptr))
+ if (get_user(cookie, (binder_uintptr_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
+ ptr += sizeof(binder_uintptr_t);
ref = binder_get_ref(proc, target);
if (ref == NULL) {
binder_user_error("%d:%d %s invalid ref %d\n",
@@ -1947,12 +1956,12 @@ static int binder_thread_write(struct binder_proc *proc,
}
binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,
- "%d:%d %s %p ref %d desc %d s %d w %d for node %d\n",
+ "%d:%d %s %016llx ref %d desc %d s %d w %d for node %d\n",
proc->pid, thread->pid,
cmd == BC_REQUEST_DEATH_NOTIFICATION ?
"BC_REQUEST_DEATH_NOTIFICATION" :
"BC_CLEAR_DEATH_NOTIFICATION",
- cookie, ref->debug_id, ref->desc,
+ (u64)cookie, ref->debug_id, ref->desc,
ref->strong, ref->weak, ref->node->debug_id);
if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
@@ -1990,9 +1999,10 @@ static int binder_thread_write(struct binder_proc *proc,
}
death = ref->death;
if (death->cookie != cookie) {
- binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %p != %p\n",
+ binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %016llx != %016llx\n",
proc->pid, thread->pid,
- death->cookie, cookie);
+ (u64)death->cookie,
+ (u64)cookie);
break;
}
ref->death = NULL;
@@ -2012,9 +2022,9 @@ static int binder_thread_write(struct binder_proc *proc,
} break;
case BC_DEAD_BINDER_DONE: {
struct binder_work *w;
- void __user *cookie;
+ binder_uintptr_t cookie;
struct binder_ref_death *death = NULL;
- if (get_user(cookie, (void __user * __user *)ptr))
+ if (get_user(cookie, (binder_uintptr_t __user *)ptr))
return -EFAULT;
ptr += sizeof(void *);
@@ -2026,11 +2036,12 @@ static int binder_thread_write(struct binder_proc *proc,
}
}
binder_debug(BINDER_DEBUG_DEAD_BINDER,
- "%d:%d BC_DEAD_BINDER_DONE %p found %p\n",
- proc->pid, thread->pid, cookie, death);
+ "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n",
+ proc->pid, thread->pid, (u64)cookie,
+ death);
if (death == NULL) {
- binder_user_error("%d:%d BC_DEAD_BINDER_DONE %p not found\n",
- proc->pid, thread->pid, cookie);
+ binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n",
+ proc->pid, thread->pid, (u64)cookie);
break;
}
@@ -2082,9 +2093,10 @@ static int binder_has_thread_work(struct binder_thread *thread)
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
- void __user *buffer, size_t size,
- size_t *consumed, int non_block)
+ binder_uintptr_t binder_buffer, size_t size,
+ binder_size_t *consumed, int non_block)
{
+ void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
@@ -2229,32 +2241,40 @@ retry:
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
- if (put_user(node->ptr, (void * __user *)ptr))
+ if (put_user(node->ptr,
+ (binder_uintptr_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
- if (put_user(node->cookie, (void * __user *)ptr))
+ ptr += sizeof(binder_uintptr_t);
+ if (put_user(node->cookie,
+ (binder_uintptr_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
+ ptr += sizeof(binder_uintptr_t);
binder_stat_br(proc, thread, cmd);
binder_debug(BINDER_DEBUG_USER_REFS,
- "%d:%d %s %d u%p c%p\n",
- proc->pid, thread->pid, cmd_name, node->debug_id, node->ptr, node->cookie);
+ "%d:%d %s %d u%016llx c%016llx\n",
+ proc->pid, thread->pid, cmd_name,
+ node->debug_id,
+ (u64)node->ptr, (u64)node->cookie);
} else {
list_del_init(&w->entry);
if (!weak && !strong) {
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
- "%d:%d node %d u%p c%p deleted\n",
- proc->pid, thread->pid, node->debug_id,
- node->ptr, node->cookie);
+ "%d:%d node %d u%016llx c%016llx deleted\n",
+ proc->pid, thread->pid,
+ node->debug_id,
+ (u64)node->ptr,
+ (u64)node->cookie);
rb_erase(&node->rb_node, &proc->nodes);
kfree(node);
binder_stats_deleted(BINDER_STAT_NODE);
} else {
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
- "%d:%d node %d u%p c%p state unchanged\n",
- proc->pid, thread->pid, node->debug_id, node->ptr,
- node->cookie);
+ "%d:%d node %d u%016llx c%016llx state unchanged\n",
+ proc->pid, thread->pid,
+ node->debug_id,
+ (u64)node->ptr,
+ (u64)node->cookie);
}
}
} break;
@@ -2272,17 +2292,18 @@ retry:
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
- if (put_user(death->cookie, (void * __user *)ptr))
+ if (put_user(death->cookie,
+ (binder_uintptr_t __user *)ptr))
return -EFAULT;
- ptr += sizeof(void *);
+ ptr += sizeof(binder_uintptr_t);
binder_stat_br(proc, thread, cmd);
binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,
- "%d:%d %s %p\n",
+ "%d:%d %s %016llx\n",
proc->pid, thread->pid,
cmd == BR_DEAD_BINDER ?
"BR_DEAD_BINDER" :
"BR_CLEAR_DEATH_NOTIFICATION_DONE",
- death->cookie);
+ (u64)death->cookie);
if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
list_del(&w->entry);
@@ -2312,8 +2333,8 @@ retry:
binder_set_nice(target_node->min_priority);
cmd = BR_TRANSACTION;
} else {
- tr.target.ptr = NULL;
- tr.cookie = NULL;
+ tr.target.ptr = 0;
+ tr.cookie = 0;
cmd = BR_REPLY;
}
tr.code = t->code;
@@ -2330,8 +2351,9 @@ retry:
tr.data_size = t->buffer->data_size;
tr.offsets_size = t->buffer->offsets_size;
- tr.data.ptr.buffer = (void *)t->buffer->data +
- proc->user_buffer_offset;
+ tr.data.ptr.buffer = (binder_uintptr_t)(
+ (uintptr_t)t->buffer->data +
+ proc->user_buffer_offset);
tr.data.ptr.offsets = tr.data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *));
@@ -2346,14 +2368,14 @@ retry:
trace_binder_transaction_received(t);
binder_stat_br(proc, thread, cmd);
binder_debug(BINDER_DEBUG_TRANSACTION,
- "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %p-%p\n",
+ "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n",
proc->pid, thread->pid,
(cmd == BR_TRANSACTION) ? "BR_TRANSACTION" :
"BR_REPLY",
t->debug_id, t->from ? t->from->proc->pid : 0,
t->from ? t->from->pid : 0, cmd,
t->buffer->data_size, t->buffer->offsets_size,
- tr.data.ptr.buffer, tr.data.ptr.offsets);
+ (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets);
list_del(&t->work.entry);
t->buffer->allow_user_free = 1;
@@ -2423,8 +2445,8 @@ static void binder_release_work(struct list_head *list)
death = container_of(w, struct binder_ref_death, work);
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
- "undelivered death notification, %p\n",
- death->cookie);
+ "undelivered death notification, %016llx\n",
+ (u64)death->cookie);
kfree(death);
binder_stats_deleted(BINDER_STAT_DEATH);
} break;
@@ -2580,12 +2602,16 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
goto err;
}
binder_debug(BINDER_DEBUG_READ_WRITE,
- "%d:%d write %zd at %016lx, read %zd at %016lx\n",
- proc->pid, thread->pid, bwr.write_size,
- bwr.write_buffer, bwr.read_size, bwr.read_buffer);
+ "%d:%d write %lld at %016llx, read %lld at %016llx\n",
+ proc->pid, thread->pid,
+ (u64)bwr.write_size, (u64)bwr.write_buffer,
+ (u64)bwr.read_size, (u64)bwr.read_buffer);
if (bwr.write_size > 0) {
- ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
+ ret = binder_thread_write(proc, thread,
+ bwr.write_buffer,
+ bwr.write_size,
+ &bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
@@ -2595,7 +2621,10 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
}
if (bwr.read_size > 0) {
- ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
+ ret = binder_thread_read(proc, thread, bwr.read_buffer,
+ bwr.read_size,
+ &bwr.read_consumed,
+ filp->f_flags & O_NONBLOCK);
trace_binder_read_done(ret);
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
@@ -2606,9 +2635,10 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
}
binder_debug(BINDER_DEBUG_READ_WRITE,
- "%d:%d wrote %zd of %zd, read return %zd of %zd\n",
- proc->pid, thread->pid, bwr.write_consumed, bwr.write_size,
- bwr.read_consumed, bwr.read_size);
+ "%d:%d wrote %lld of %lld, read return %lld of %lld\n",
+ proc->pid, thread->pid,
+ (u64)bwr.write_consumed, (u64)bwr.write_size,
+ (u64)bwr.read_consumed, (u64)bwr.read_size);
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto err;
@@ -2637,7 +2667,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
} else
binder_context_mgr_uid = current->cred->euid;
- binder_context_mgr_node = binder_new_node(proc, NULL, NULL);
+ binder_context_mgr_node = binder_new_node(proc, 0, 0);
if (binder_context_mgr_node == NULL) {
ret = -ENOMEM;
goto err;
@@ -2904,7 +2934,7 @@ static int binder_node_release(struct binder_node *node, int refs)
refs++;
if (!ref->death)
- goto out;
+ continue;
death++;
@@ -2917,7 +2947,6 @@ static int binder_node_release(struct binder_node *node, int refs)
BUG();
}
-out:
binder_debug(BINDER_DEBUG_DEAD_BINDER,
"node %d now dead, refs %d, death %d\n",
node->debug_id, refs, death);
@@ -3133,8 +3162,9 @@ static void print_binder_work(struct seq_file *m, const char *prefix,
break;
case BINDER_WORK_NODE:
node = container_of(w, struct binder_node, work);
- seq_printf(m, "%snode work %d: u%p c%p\n",
- prefix, node->debug_id, node->ptr, node->cookie);
+ seq_printf(m, "%snode work %d: u%016llx c%016llx\n",
+ prefix, node->debug_id,
+ (u64)node->ptr, (u64)node->cookie);
break;
case BINDER_WORK_DEAD_BINDER:
seq_printf(m, "%shas dead binder\n", prefix);
@@ -3194,8 +3224,8 @@ static void print_binder_node(struct seq_file *m, struct binder_node *node)
hlist_for_each_entry(ref, &node->refs, node_entry)
count++;
- seq_printf(m, " node %d: u%p c%p hs %d hw %d ls %d lw %d is %d iw %d",
- node->debug_id, node->ptr, node->cookie,
+ seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d",
+ node->debug_id, (u64)node->ptr, (u64)node->cookie,
node->has_strong_ref, node->has_weak_ref,
node->local_strong_refs, node->local_weak_refs,
node->internal_strong_refs, count);
@@ -3497,6 +3527,7 @@ static const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
+ .compat_ioctl = binder_ioctl,
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
diff --git a/drivers/staging/android/binder.h b/drivers/staging/android/binder.h
index cbe345168067..eb0834656dfe 100644
--- a/drivers/staging/android/binder.h
+++ b/drivers/staging/android/binder.h
@@ -20,311 +20,11 @@
#ifndef _LINUX_BINDER_H
#define _LINUX_BINDER_H
-#include <linux/ioctl.h>
+#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT
+#define BINDER_IPC_32BIT 1
+#endif
-#define B_PACK_CHARS(c1, c2, c3, c4) \
- ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
-#define B_TYPE_LARGE 0x85
-
-enum {
- BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
- BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
- BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
- BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
- BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
-};
-
-enum {
- FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
- FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
-};
-
-/*
- * This is the flattened representation of a Binder object for transfer
- * between processes. The 'offsets' supplied as part of a binder transaction
- * contains offsets into the data where these structures occur. The Binder
- * driver takes care of re-writing the structure type and data as it moves
- * between processes.
- */
-struct flat_binder_object {
- /* 8 bytes for large_flat_header. */
- __u32 type;
- __u32 flags;
-
- /* 8 bytes of data. */
- union {
- void __user *binder; /* local object */
- __u32 handle; /* remote object */
- };
-
- /* extra data associated with local object */
- void __user *cookie;
-};
-
-/*
- * On 64-bit platforms where user code may run in 32-bits the driver must
- * translate the buffer (and local binder) addresses appropriately.
- */
-
-struct binder_write_read {
- size_t write_size; /* bytes to write */
- size_t write_consumed; /* bytes consumed by driver */
- unsigned long write_buffer;
- size_t read_size; /* bytes to read */
- size_t read_consumed; /* bytes consumed by driver */
- unsigned long read_buffer;
-};
-
-/* Use with BINDER_VERSION, driver fills in fields. */
-struct binder_version {
- /* driver protocol version -- increment with incompatible change */
- __s32 protocol_version;
-};
-
-/* This is the current protocol version. */
-#define BINDER_CURRENT_PROTOCOL_VERSION 7
-
-#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
-#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
-#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32)
-#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32)
-#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
-#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
-#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
-
-/*
- * NOTE: Two special error codes you should check for when calling
- * in to the driver are:
- *
- * EINTR -- The operation has been interupted. This should be
- * handled by retrying the ioctl() until a different error code
- * is returned.
- *
- * ECONNREFUSED -- The driver is no longer accepting operations
- * from your process. That is, the process is being destroyed.
- * You should handle this by exiting from your process. Note
- * that once this error code is returned, all further calls to
- * the driver from any thread will return this same code.
- */
-
-enum transaction_flags {
- TF_ONE_WAY = 0x01, /* this is a one-way call: async, no return */
- TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */
- TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */
- TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */
-};
-
-struct binder_transaction_data {
- /* The first two are only used for bcTRANSACTION and brTRANSACTION,
- * identifying the target and contents of the transaction.
- */
- union {
- __u32 handle; /* target descriptor of command transaction */
- void *ptr; /* target descriptor of return transaction */
- } target;
- void *cookie; /* target object cookie */
- __u32 code; /* transaction command */
-
- /* General information about the transaction. */
- __u32 flags;
- pid_t sender_pid;
- uid_t sender_euid;
- size_t data_size; /* number of bytes of data */
- size_t offsets_size; /* number of bytes of offsets */
-
- /* If this transaction is inline, the data immediately
- * follows here; otherwise, it ends with a pointer to
- * the data buffer.
- */
- union {
- struct {
- /* transaction data */
- const void __user *buffer;
- /* offsets from buffer to flat_binder_object structs */
- const void __user *offsets;
- } ptr;
- __u8 buf[8];
- } data;
-};
-
-struct binder_ptr_cookie {
- void *ptr;
- void *cookie;
-};
-
-struct binder_pri_desc {
- __s32 priority;
- __u32 desc;
-};
-
-struct binder_pri_ptr_cookie {
- __s32 priority;
- void *ptr;
- void *cookie;
-};
-
-enum binder_driver_return_protocol {
- BR_ERROR = _IOR('r', 0, __s32),
- /*
- * int: error code
- */
-
- BR_OK = _IO('r', 1),
- /* No parameters! */
-
- BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
- BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
- /*
- * binder_transaction_data: the received command.
- */
-
- BR_ACQUIRE_RESULT = _IOR('r', 4, __s32),
- /*
- * not currently supported
- * int: 0 if the last bcATTEMPT_ACQUIRE was not successful.
- * Else the remote object has acquired a primary reference.
- */
-
- BR_DEAD_REPLY = _IO('r', 5),
- /*
- * The target of the last transaction (either a bcTRANSACTION or
- * a bcATTEMPT_ACQUIRE) is no longer with us. No parameters.
- */
-
- BR_TRANSACTION_COMPLETE = _IO('r', 6),
- /*
- * No parameters... always refers to the last transaction requested
- * (including replies). Note that this will be sent even for
- * asynchronous transactions.
- */
-
- BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),
- BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),
- BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),
- BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie),
- /*
- * void *: ptr to binder
- * void *: cookie for binder
- */
-
- BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie),
- /*
- * not currently supported
- * int: priority
- * void *: ptr to binder
- * void *: cookie for binder
- */
-
- BR_NOOP = _IO('r', 12),
- /*
- * No parameters. Do nothing and examine the next command. It exists
- * primarily so that we can replace it with a BR_SPAWN_LOOPER command.
- */
-
- BR_SPAWN_LOOPER = _IO('r', 13),
- /*
- * No parameters. The driver has determined that a process has no
- * threads waiting to service incoming transactions. When a process
- * receives this command, it must spawn a new service thread and
- * register it via bcENTER_LOOPER.
- */
-
- BR_FINISHED = _IO('r', 14),
- /*
- * not currently supported
- * stop threadpool thread
- */
-
- BR_DEAD_BINDER = _IOR('r', 15, void *),
- /*
- * void *: cookie
- */
- BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, void *),
- /*
- * void *: cookie
- */
-
- BR_FAILED_REPLY = _IO('r', 17),
- /*
- * The the last transaction (either a bcTRANSACTION or
- * a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters.
- */
-};
-
-enum binder_driver_command_protocol {
- BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),
- BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
- /*
- * binder_transaction_data: the sent command.
- */
-
- BC_ACQUIRE_RESULT = _IOW('c', 2, __s32),
- /*
- * not currently supported
- * int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful.
- * Else you have acquired a primary reference on the object.
- */
-
- BC_FREE_BUFFER = _IOW('c', 3, void *),
- /*
- * void *: ptr to transaction data received on a read
- */
-
- BC_INCREFS = _IOW('c', 4, __u32),
- BC_ACQUIRE = _IOW('c', 5, __u32),
- BC_RELEASE = _IOW('c', 6, __u32),
- BC_DECREFS = _IOW('c', 7, __u32),
- /*
- * int: descriptor
- */
-
- BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
- BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
- /*
- * void *: ptr to binder
- * void *: cookie for binder
- */
-
- BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
- /*
- * not currently supported
- * int: priority
- * int: descriptor
- */
-
- BC_REGISTER_LOOPER = _IO('c', 11),
- /*
- * No parameters.
- * Register a spawned looper thread with the device.
- */
-
- BC_ENTER_LOOPER = _IO('c', 12),
- BC_EXIT_LOOPER = _IO('c', 13),
- /*
- * No parameters.
- * These two commands are sent as an application-level thread
- * enters and exits the binder loop, respectively. They are
- * used so the binder can have an accurate count of the number
- * of looping threads it has available.
- */
-
- BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_ptr_cookie),
- /*
- * void *: ptr to binder
- * void *: cookie
- */
-
- BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie),
- /*
- * void *: ptr to binder
- * void *: cookie
- */
-
- BC_DEAD_BINDER_DONE = _IOW('c', 16, void *),
- /*
- * void *: cookie
- */
-};
+#include "uapi/binder.h"
#endif /* _LINUX_BINDER_H */
diff --git a/drivers/staging/android/binder_trace.h b/drivers/staging/android/binder_trace.h
index 82a567c2af67..7f20f3dc8369 100644
--- a/drivers/staging/android/binder_trace.h
+++ b/drivers/staging/android/binder_trace.h
@@ -152,7 +152,7 @@ TRACE_EVENT(binder_transaction_node_to_ref,
TP_STRUCT__entry(
__field(int, debug_id)
__field(int, node_debug_id)
- __field(void __user *, node_ptr)
+ __field(binder_uintptr_t, node_ptr)
__field(int, ref_debug_id)
__field(uint32_t, ref_desc)
),
@@ -163,8 +163,9 @@ TRACE_EVENT(binder_transaction_node_to_ref,
__entry->ref_debug_id = ref->debug_id;
__entry->ref_desc = ref->desc;
),
- TP_printk("transaction=%d node=%d src_ptr=0x%p ==> dest_ref=%d dest_desc=%d",
- __entry->debug_id, __entry->node_debug_id, __entry->node_ptr,
+ TP_printk("transaction=%d node=%d src_ptr=0x%016llx ==> dest_ref=%d dest_desc=%d",
+ __entry->debug_id, __entry->node_debug_id,
+ (u64)__entry->node_ptr,
__entry->ref_debug_id, __entry->ref_desc)
);
@@ -177,7 +178,7 @@ TRACE_EVENT(binder_transaction_ref_to_node,
__field(int, ref_debug_id)
__field(uint32_t, ref_desc)
__field(int, node_debug_id)
- __field(void __user *, node_ptr)
+ __field(binder_uintptr_t, node_ptr)
),
TP_fast_assign(
__entry->debug_id = t->debug_id;
@@ -186,9 +187,10 @@ TRACE_EVENT(binder_transaction_ref_to_node,
__entry->node_debug_id = ref->node->debug_id;
__entry->node_ptr = ref->node->ptr;
),
- TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%p",
+ TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%016llx",
__entry->debug_id, __entry->node_debug_id,
- __entry->ref_debug_id, __entry->ref_desc, __entry->node_ptr)
+ __entry->ref_debug_id, __entry->ref_desc,
+ (u64)__entry->node_ptr)
);
TRACE_EVENT(binder_transaction_ref_to_ref,
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 574066ff73f8..3d5bf1472236 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -16,6 +16,7 @@
*/
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/file.h>
#include <linux/freezer.h>
#include <linux/fs.h>
@@ -55,10 +56,12 @@ struct ion_device {
struct mutex buffer_lock;
struct rw_semaphore lock;
struct plist_head heaps;
- long (*custom_ioctl) (struct ion_client *client, unsigned int cmd,
- unsigned long arg);
+ long (*custom_ioctl)(struct ion_client *client, unsigned int cmd,
+ unsigned long arg);
struct rb_root clients;
struct dentry *debug_root;
+ struct dentry *heaps_debug_root;
+ struct dentry *clients_debug_root;
};
/**
@@ -69,6 +72,8 @@ struct ion_device {
* @idr: an idr space for allocating handle ids
* @lock: lock protecting the tree of handles
* @name: used for debugging
+ * @display_name: used for debugging (unique version of @name)
+ * @display_serial: used for debugging (to make display_name unique)
* @task: used for debugging
*
* A client represents a list of buffers this client may access.
@@ -82,6 +87,8 @@ struct ion_client {
struct idr idr;
struct mutex lock;
const char *name;
+ char *display_name;
+ int display_serial;
struct task_struct *task;
pid_t pid;
struct dentry *debug_root;
@@ -208,7 +215,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
if (IS_ERR(table)) {
heap->ops->free(buffer);
kfree(buffer);
- return ERR_PTR(PTR_ERR(table));
+ return ERR_CAST(table);
}
buffer->sg_table = table;
if (ion_buffer_fault_user_mappings(buffer)) {
@@ -429,7 +436,7 @@ static bool ion_handle_validate(struct ion_client *client,
struct ion_handle *handle)
{
WARN_ON(!mutex_is_locked(&client->lock));
- return (idr_find(&client->idr, handle->id) == handle);
+ return idr_find(&client->idr, handle->id) == handle;
}
static int ion_handle_add(struct ion_client *client, struct ion_handle *handle)
@@ -501,7 +508,7 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
return ERR_PTR(-ENODEV);
if (IS_ERR(buffer))
- return ERR_PTR(PTR_ERR(buffer));
+ return ERR_CAST(buffer);
handle = ion_handle_create(client, buffer);
@@ -708,6 +715,21 @@ static const struct file_operations debug_client_fops = {
.release = single_release,
};
+static int ion_get_client_serial(const struct rb_root *root,
+ const unsigned char *name)
+{
+ int serial = -1;
+ struct rb_node *node;
+ for (node = rb_first(root); node; node = rb_next(node)) {
+ struct ion_client *client = rb_entry(node, struct ion_client,
+ node);
+ if (strcmp(client->name, name))
+ continue;
+ serial = max(serial, client->display_serial);
+ }
+ return serial + 1;
+}
+
struct ion_client *ion_client_create(struct ion_device *dev,
const char *name)
{
@@ -716,9 +738,13 @@ struct ion_client *ion_client_create(struct ion_device *dev,
struct rb_node **p;
struct rb_node *parent = NULL;
struct ion_client *entry;
- char debug_name[64];
pid_t pid;
+ if (!name) {
+ pr_err("%s: Name cannot be null\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+
get_task_struct(current->group_leader);
task_lock(current->group_leader);
pid = task_pid_nr(current->group_leader);
@@ -733,21 +759,27 @@ struct ion_client *ion_client_create(struct ion_device *dev,
task_unlock(current->group_leader);
client = kzalloc(sizeof(struct ion_client), GFP_KERNEL);
- if (!client) {
- if (task)
- put_task_struct(current->group_leader);
- return ERR_PTR(-ENOMEM);
- }
+ if (!client)
+ goto err_put_task_struct;
client->dev = dev;
client->handles = RB_ROOT;
idr_init(&client->idr);
mutex_init(&client->lock);
- client->name = name;
client->task = task;
client->pid = pid;
+ client->name = kstrdup(name, GFP_KERNEL);
+ if (!client->name)
+ goto err_free_client;
down_write(&dev->lock);
+ client->display_serial = ion_get_client_serial(&dev->clients, name);
+ client->display_name = kasprintf(
+ GFP_KERNEL, "%s-%d", name, client->display_serial);
+ if (!client->display_name) {
+ up_write(&dev->lock);
+ goto err_free_client_name;
+ }
p = &dev->clients.rb_node;
while (*p) {
parent = *p;
@@ -761,13 +793,28 @@ struct ion_client *ion_client_create(struct ion_device *dev,
rb_link_node(&client->node, parent, p);
rb_insert_color(&client->node, &dev->clients);
- snprintf(debug_name, 64, "%u", client->pid);
- client->debug_root = debugfs_create_file(debug_name, 0664,
- dev->debug_root, client,
- &debug_client_fops);
+ client->debug_root = debugfs_create_file(client->display_name, 0664,
+ dev->clients_debug_root,
+ client, &debug_client_fops);
+ if (!client->debug_root) {
+ char buf[256], *path;
+ path = dentry_path(dev->clients_debug_root, buf, 256);
+ pr_err("Failed to create client debugfs at %s/%s\n",
+ path, client->display_name);
+ }
+
up_write(&dev->lock);
return client;
+
+err_free_client_name:
+ kfree(client->name);
+err_free_client:
+ kfree(client);
+err_put_task_struct:
+ if (task)
+ put_task_struct(current->group_leader);
+ return ERR_PTR(-ENOMEM);
}
EXPORT_SYMBOL(ion_client_create);
@@ -792,6 +839,8 @@ void ion_client_destroy(struct ion_client *client)
debugfs_remove_recursive(client->debug_root);
up_write(&dev->lock);
+ kfree(client->display_name);
+ kfree(client->name);
kfree(client);
}
EXPORT_SYMBOL(ion_client_destroy);
@@ -954,8 +1003,8 @@ static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
int ret = 0;
if (!buffer->heap->ops->map_user) {
- pr_err("%s: this heap does not define a method for mapping "
- "to userspace\n", __func__);
+ pr_err("%s: this heap does not define a method for mapping to userspace\n",
+ __func__);
return -EINVAL;
}
@@ -1017,9 +1066,7 @@ static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start,
mutex_lock(&buffer->lock);
vaddr = ion_buffer_kmap_get(buffer);
mutex_unlock(&buffer->lock);
- if (IS_ERR(vaddr))
- return PTR_ERR(vaddr);
- return 0;
+ return PTR_ERR_OR_ZERO(vaddr);
}
static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start,
@@ -1100,7 +1147,7 @@ struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd)
dmabuf = dma_buf_get(fd);
if (IS_ERR(dmabuf))
- return ERR_PTR(PTR_ERR(dmabuf));
+ return ERR_CAST(dmabuf);
/* if this memory came from ion */
if (dmabuf->ops != &dma_buf_ops) {
@@ -1293,9 +1340,11 @@ static int ion_open(struct inode *inode, struct file *file)
struct miscdevice *miscdev = file->private_data;
struct ion_device *dev = container_of(miscdev, struct ion_device, dev);
struct ion_client *client;
+ char debug_name[64];
pr_debug("%s: %d\n", __func__, __LINE__);
- client = ion_client_create(dev, "user");
+ snprintf(debug_name, 64, "%u", task_pid_nr(current->group_leader));
+ client = ion_client_create(dev, debug_name);
if (IS_ERR(client))
return PTR_ERR(client);
file->private_data = client;
@@ -1338,7 +1387,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
size_t total_orphaned_size = 0;
seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size");
- seq_printf(s, "----------------------------------------------------\n");
+ seq_puts(s, "----------------------------------------------------\n");
for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
struct ion_client *client = rb_entry(n, struct ion_client,
@@ -1357,9 +1406,8 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
client->pid, size);
}
}
- seq_printf(s, "----------------------------------------------------\n");
- seq_printf(s, "orphaned allocations (info is from last known client):"
- "\n");
+ seq_puts(s, "----------------------------------------------------\n");
+ seq_puts(s, "orphaned allocations (info is from last known client):\n");
mutex_lock(&dev->buffer_lock);
for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
struct ion_buffer *buffer = rb_entry(n, struct ion_buffer,
@@ -1376,14 +1424,14 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
}
}
mutex_unlock(&dev->buffer_lock);
- seq_printf(s, "----------------------------------------------------\n");
+ seq_puts(s, "----------------------------------------------------\n");
seq_printf(s, "%16.s %16zu\n", "total orphaned",
total_orphaned_size);
seq_printf(s, "%16.s %16zu\n", "total ", total_size);
if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
seq_printf(s, "%16.s %16zu\n", "deferred free",
heap->free_list_size);
- seq_printf(s, "----------------------------------------------------\n");
+ seq_puts(s, "----------------------------------------------------\n");
if (heap->debug_show)
heap->debug_show(heap, s, unused);
@@ -1443,6 +1491,8 @@ DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get,
void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
{
+ struct dentry *debug_file;
+
if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma ||
!heap->ops->unmap_dma)
pr_err("%s: can not add heap with invalid ops struct.\n",
@@ -1451,21 +1501,40 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
ion_heap_init_deferred_free(heap);
+ if ((heap->flags & ION_HEAP_FLAG_DEFER_FREE) || heap->ops->shrink)
+ ion_heap_init_shrinker(heap);
+
heap->dev = dev;
down_write(&dev->lock);
/* use negative heap->id to reverse the priority -- when traversing
the list later attempt higher id numbers first */
plist_node_init(&heap->node, -heap->id);
plist_add(&heap->node, &dev->heaps);
- debugfs_create_file(heap->name, 0664, dev->debug_root, heap,
- &debug_heap_fops);
+ debug_file = debugfs_create_file(heap->name, 0664,
+ dev->heaps_debug_root, heap,
+ &debug_heap_fops);
+
+ if (!debug_file) {
+ char buf[256], *path;
+ path = dentry_path(dev->heaps_debug_root, buf, 256);
+ pr_err("Failed to create heap debugfs at %s/%s\n",
+ path, heap->name);
+ }
+
#ifdef DEBUG_HEAP_SHRINKER
if (heap->shrinker.shrink) {
char debug_name[64];
snprintf(debug_name, 64, "%s_shrink", heap->name);
- debugfs_create_file(debug_name, 0644, dev->debug_root, heap,
- &debug_shrink_fops);
+ debug_file = debugfs_create_file(
+ debug_name, 0644, dev->heaps_debug_root, heap,
+ &debug_shrink_fops);
+ if (!debug_file) {
+ char buf[256], *path;
+ path = dentry_path(dev->heaps_debug_root, buf, 256);
+ pr_err("Failed to create heap shrinker debugfs at %s/%s\n",
+ path, debug_name);
+ }
}
#endif
up_write(&dev->lock);
@@ -1494,8 +1563,21 @@ struct ion_device *ion_device_create(long (*custom_ioctl)
}
idev->debug_root = debugfs_create_dir("ion", NULL);
- if (!idev->debug_root)
- pr_err("ion: failed to create debug files.\n");
+ if (!idev->debug_root) {
+ pr_err("ion: failed to create debugfs root directory.\n");
+ goto debugfs_done;
+ }
+ idev->heaps_debug_root = debugfs_create_dir("heaps", idev->debug_root);
+ if (!idev->heaps_debug_root) {
+ pr_err("ion: failed to create debugfs heaps directory.\n");
+ goto debugfs_done;
+ }
+ idev->clients_debug_root = debugfs_create_dir("clients",
+ idev->debug_root);
+ if (!idev->clients_debug_root)
+ pr_err("ion: failed to create debugfs clients directory.\n");
+
+debugfs_done:
idev->custom_ioctl = custom_ioctl;
idev->buffers = RB_ROOT;
@@ -1509,6 +1591,7 @@ struct ion_device *ion_device_create(long (*custom_ioctl)
void ion_device_destroy(struct ion_device *dev)
{
misc_deregister(&dev->dev);
+ debugfs_remove_recursive(dev->debug_root);
/* XXX need to free the heaps and clients ? */
kfree(dev);
}
@@ -1527,8 +1610,7 @@ void __init ion_reserve(struct ion_platform_data *data)
data->heaps[i].align,
MEMBLOCK_ALLOC_ANYWHERE);
if (!paddr) {
- pr_err("%s: error allocating memblock for "
- "heap %d\n",
+ pr_err("%s: error allocating memblock for heap %d\n",
__func__, i);
continue;
}
diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c
index f0f98897e4b9..ce68ecfed31f 100644
--- a/drivers/staging/android/ion/ion_cma_heap.c
+++ b/drivers/staging/android/ion/ion_cma_heap.c
@@ -135,7 +135,7 @@ static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer,
struct device *dev = cma_heap->dev;
struct ion_cma_buffer_info *info = buffer->priv_virt;
- dev_dbg(dev, "Return buffer %p physical address 0x%pa\n", buffer,
+ dev_dbg(dev, "Return buffer %p physical address %pa\n", buffer,
&info->handle);
*addr = info->handle;
diff --git a/drivers/staging/android/ion/ion_dummy_driver.c b/drivers/staging/android/ion/ion_dummy_driver.c
index 01cdc8aee898..3a45e79fe444 100644
--- a/drivers/staging/android/ion/ion_dummy_driver.c
+++ b/drivers/staging/android/ion/ion_dummy_driver.c
@@ -25,13 +25,13 @@
#include "ion.h"
#include "ion_priv.h"
-struct ion_device *idev;
-struct ion_heap **heaps;
+static struct ion_device *idev;
+static struct ion_heap **heaps;
-void *carveout_ptr;
-void *chunk_ptr;
+static void *carveout_ptr;
+static void *chunk_ptr;
-struct ion_platform_heap dummy_heaps[] = {
+static struct ion_platform_heap dummy_heaps[] = {
{
.id = ION_HEAP_TYPE_SYSTEM,
.type = ION_HEAP_TYPE_SYSTEM,
@@ -58,7 +58,7 @@ struct ion_platform_heap dummy_heaps[] = {
},
};
-struct ion_platform_data dummy_ion_pdata = {
+static struct ion_platform_data dummy_ion_pdata = {
.nr = ARRAY_SIZE(dummy_heaps),
.heaps = dummy_heaps,
};
diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c
index 37e64d51394c..bdc6a28ba8c9 100644
--- a/drivers/staging/android/ion/ion_heap.c
+++ b/drivers/staging/android/ion/ion_heap.c
@@ -178,7 +178,8 @@ size_t ion_heap_freelist_size(struct ion_heap *heap)
return size;
}
-size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size)
+static size_t _ion_heap_freelist_drain(struct ion_heap *heap, size_t size,
+ bool skip_pools)
{
struct ion_buffer *buffer;
size_t total_drained = 0;
@@ -197,6 +198,8 @@ size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size)
list);
list_del(&buffer->list);
heap->free_list_size -= buffer->size;
+ if (skip_pools)
+ buffer->private_flags |= ION_PRIV_FLAG_SHRINKER_FREE;
total_drained += buffer->size;
spin_unlock(&heap->free_lock);
ion_buffer_destroy(buffer);
@@ -207,6 +210,16 @@ size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size)
return total_drained;
}
+size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size)
+{
+ return _ion_heap_freelist_drain(heap, size, false);
+}
+
+size_t ion_heap_freelist_shrink(struct ion_heap *heap, size_t size)
+{
+ return _ion_heap_freelist_drain(heap, size, true);
+}
+
static int ion_heap_deferred_free(void *data)
{
struct ion_heap *heap = data;
@@ -246,12 +259,62 @@ int ion_heap_init_deferred_free(struct ion_heap *heap)
if (IS_ERR(heap->task)) {
pr_err("%s: creating thread for deferred free failed\n",
__func__);
- return PTR_RET(heap->task);
+ return PTR_ERR_OR_ZERO(heap->task);
}
sched_setscheduler(heap->task, SCHED_IDLE, &param);
return 0;
}
+static unsigned long ion_heap_shrink_count(struct shrinker *shrinker,
+ struct shrink_control *sc)
+{
+ struct ion_heap *heap = container_of(shrinker, struct ion_heap,
+ shrinker);
+ int total = 0;
+
+ total = ion_heap_freelist_size(heap) / PAGE_SIZE;
+ if (heap->ops->shrink)
+ total += heap->ops->shrink(heap, sc->gfp_mask, 0);
+ return total;
+}
+
+static unsigned long ion_heap_shrink_scan(struct shrinker *shrinker,
+ struct shrink_control *sc)
+{
+ struct ion_heap *heap = container_of(shrinker, struct ion_heap,
+ shrinker);
+ int freed = 0;
+ int to_scan = sc->nr_to_scan;
+
+ if (to_scan == 0)
+ return 0;
+
+ /*
+ * shrink the free list first, no point in zeroing the memory if we're
+ * just going to reclaim it. Also, skip any possible page pooling.
+ */
+ if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
+ freed = ion_heap_freelist_shrink(heap, to_scan * PAGE_SIZE) /
+ PAGE_SIZE;
+
+ to_scan -= freed;
+ if (to_scan <= 0)
+ return freed;
+
+ if (heap->ops->shrink)
+ freed += heap->ops->shrink(heap, sc->gfp_mask, to_scan);
+ return freed;
+}
+
+void ion_heap_init_shrinker(struct ion_heap *heap)
+{
+ heap->shrinker.count_objects = ion_heap_shrink_count;
+ heap->shrinker.scan_objects = ion_heap_shrink_scan;
+ heap->shrinker.seeks = DEFAULT_SEEKS;
+ heap->shrinker.batch = 0;
+ register_shrinker(&heap->shrinker);
+}
+
struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
{
struct ion_heap *heap = NULL;
diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c
index fa693c23681a..ecb5fc34ec5c 100644
--- a/drivers/staging/android/ion/ion_page_pool.c
+++ b/drivers/staging/android/ion/ion_page_pool.c
@@ -130,8 +130,7 @@ static int ion_page_pool_total(struct ion_page_pool *pool, bool high)
int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
int nr_to_scan)
{
- int nr_freed = 0;
- int i;
+ int freed;
bool high;
high = !!(gfp_mask & __GFP_HIGHMEM);
@@ -139,7 +138,7 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
if (nr_to_scan == 0)
return ion_page_pool_total(pool, high);
- for (i = 0; i < nr_to_scan; i++) {
+ for (freed = 0; freed < nr_to_scan; freed++) {
struct page *page;
mutex_lock(&pool->mutex);
@@ -153,10 +152,9 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
}
mutex_unlock(&pool->mutex);
ion_page_pool_free_pages(pool, page);
- nr_freed += (1 << pool->order);
}
- return nr_freed;
+ return freed;
}
struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h
index fc2e4fccf69d..1eba3f2076a9 100644
--- a/drivers/staging/android/ion/ion_priv.h
+++ b/drivers/staging/android/ion/ion_priv.h
@@ -38,6 +38,7 @@ struct ion_buffer *ion_handle_buffer(struct ion_handle *handle);
* @dev: back pointer to the ion_device
* @heap: back pointer to the heap the buffer came from
* @flags: buffer specific flags
+ * @private_flags: internal buffer specific flags
* @size: size of the buffer
* @priv_virt: private data to the buffer representable as
* a void *
@@ -66,6 +67,7 @@ struct ion_buffer {
struct ion_device *dev;
struct ion_heap *heap;
unsigned long flags;
+ unsigned long private_flags;
size_t size;
union {
void *priv_virt;
@@ -98,22 +100,27 @@ void ion_buffer_destroy(struct ion_buffer *buffer);
* @map_user map memory to userspace
*
* allocate, phys, and map_user return 0 on success, -errno on error.
- * map_dma and map_kernel return pointer on success, ERR_PTR on error.
+ * map_dma and map_kernel return pointer on success, ERR_PTR on
+ * error. @free will be called with ION_PRIV_FLAG_SHRINKER_FREE set in
+ * the buffer's private_flags when called from a shrinker. In that
+ * case, the pages being free'd must be truly free'd back to the
+ * system, not put in a page pool or otherwise cached.
*/
struct ion_heap_ops {
- int (*allocate) (struct ion_heap *heap,
- struct ion_buffer *buffer, unsigned long len,
- unsigned long align, unsigned long flags);
- void (*free) (struct ion_buffer *buffer);
- int (*phys) (struct ion_heap *heap, struct ion_buffer *buffer,
- ion_phys_addr_t *addr, size_t *len);
- struct sg_table *(*map_dma) (struct ion_heap *heap,
- struct ion_buffer *buffer);
- void (*unmap_dma) (struct ion_heap *heap, struct ion_buffer *buffer);
- void * (*map_kernel) (struct ion_heap *heap, struct ion_buffer *buffer);
- void (*unmap_kernel) (struct ion_heap *heap, struct ion_buffer *buffer);
- int (*map_user) (struct ion_heap *mapper, struct ion_buffer *buffer,
- struct vm_area_struct *vma);
+ int (*allocate)(struct ion_heap *heap,
+ struct ion_buffer *buffer, unsigned long len,
+ unsigned long align, unsigned long flags);
+ void (*free)(struct ion_buffer *buffer);
+ int (*phys)(struct ion_heap *heap, struct ion_buffer *buffer,
+ ion_phys_addr_t *addr, size_t *len);
+ struct sg_table * (*map_dma)(struct ion_heap *heap,
+ struct ion_buffer *buffer);
+ void (*unmap_dma)(struct ion_heap *heap, struct ion_buffer *buffer);
+ void * (*map_kernel)(struct ion_heap *heap, struct ion_buffer *buffer);
+ void (*unmap_kernel)(struct ion_heap *heap, struct ion_buffer *buffer);
+ int (*map_user)(struct ion_heap *mapper, struct ion_buffer *buffer,
+ struct vm_area_struct *vma);
+ int (*shrink)(struct ion_heap *heap, gfp_t gfp_mask, int nr_to_scan);
};
/**
@@ -122,6 +129,17 @@ struct ion_heap_ops {
#define ION_HEAP_FLAG_DEFER_FREE (1 << 0)
/**
+ * private flags - flags internal to ion
+ */
+/*
+ * Buffer is being freed from a shrinker function. Skip any possible
+ * heap-specific caching mechanism (e.g. page pools). Guarantees that
+ * any buffer storage that came from the system allocator will be
+ * returned to the system allocator.
+ */
+#define ION_PRIV_FLAG_SHRINKER_FREE (1 << 0)
+
+/**
* struct ion_heap - represents a heap in the system
* @node: rb node to put the heap on the device's tree of heaps
* @dev: back pointer to the ion_device
@@ -132,10 +150,7 @@ struct ion_heap_ops {
* allocating. These are specified by platform data and
* MUST be unique
* @name: used for debugging
- * @shrinker: a shrinker for the heap, if the heap caches system
- * memory, it must define a shrinker to return it on low
- * memory conditions, this includes system memory cached
- * in the deferred free lists for heaps that support it
+ * @shrinker: a shrinker for the heap
* @free_list: free list head if deferred free is used
* @free_list_size size of the deferred free list in bytes
* @lock: protects the free list
@@ -219,6 +234,16 @@ int ion_heap_buffer_zero(struct ion_buffer *buffer);
int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot);
/**
+ * ion_heap_init_shrinker
+ * @heap: the heap
+ *
+ * If a heap sets the ION_HEAP_FLAG_DEFER_FREE flag or defines the shrink op
+ * this function will be called to setup a shrinker to shrink the freelists
+ * and call the heap's shrink op.
+ */
+void ion_heap_init_shrinker(struct ion_heap *heap);
+
+/**
* ion_heap_init_deferred_free -- initialize deferred free functionality
* @heap: the heap
*
@@ -250,6 +275,29 @@ void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer);
size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size);
/**
+ * ion_heap_freelist_shrink - drain the deferred free
+ * list, skipping any heap-specific
+ * pooling or caching mechanisms
+ *
+ * @heap: the heap
+ * @size: amount of memory to drain in bytes
+ *
+ * Drains the indicated amount of memory from the deferred freelist immediately.
+ * Returns the total amount freed. The total freed may be higher depending
+ * on the size of the items in the list, or lower if there is insufficient
+ * total memory on the freelist.
+ *
+ * Unlike with @ion_heap_freelist_drain, don't put any pages back into
+ * page pools or otherwise cache the pages. Everything must be
+ * genuinely free'd back to the system. If you're free'ing from a
+ * shrinker you probably want to use this. Note that this relies on
+ * the heap.ops.free callback honoring the ION_PRIV_FLAG_SHRINKER_FREE
+ * flag.
+ */
+size_t ion_heap_freelist_shrink(struct ion_heap *heap,
+ size_t size);
+
+/**
* ion_heap_freelist_size - returns the size of the freelist in bytes
* @heap: the heap
*/
@@ -305,13 +353,8 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
* @low_count: number of lowmem items in the pool
* @high_items: list of highmem items
* @low_items: list of lowmem items
- * @shrinker: a shrinker for the items
* @mutex: lock protecting this struct and especially the count
* item list
- * @alloc: function to be used to allocate pageory when the pool
- * is empty
- * @free: function to be used to free pageory back to the system
- * when the shrinker fires
* @gfp_mask: gfp_mask to use from alloc
* @order: order of pages in the pool
* @list: plist node for list of pools
diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c
index 9849f3963e75..c92363356ae1 100644
--- a/drivers/staging/android/ion/ion_system_heap.c
+++ b/drivers/staging/android/ion/ion_system_heap.c
@@ -90,7 +90,7 @@ static void free_buffer_page(struct ion_system_heap *heap,
{
bool cached = ion_buffer_cached(buffer);
- if (!cached) {
+ if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) {
struct ion_page_pool *pool = heap->pools[order_to_index(order)];
ion_page_pool_free(pool, page);
} else {
@@ -209,7 +209,7 @@ static void ion_system_heap_free(struct ion_buffer *buffer)
/* uncached pages come from the page pools, zero them before returning
for security purposes (other allocations are zerod at alloc time */
- if (!cached)
+ if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE))
ion_heap_buffer_zero(buffer);
for_each_sg(table->sgl, sg, table->nents, i)
@@ -231,75 +231,34 @@ static void ion_system_heap_unmap_dma(struct ion_heap *heap,
return;
}
-static struct ion_heap_ops system_heap_ops = {
- .allocate = ion_system_heap_allocate,
- .free = ion_system_heap_free,
- .map_dma = ion_system_heap_map_dma,
- .unmap_dma = ion_system_heap_unmap_dma,
- .map_kernel = ion_heap_map_kernel,
- .unmap_kernel = ion_heap_unmap_kernel,
- .map_user = ion_heap_map_user,
-};
-
-static unsigned long ion_system_heap_shrink_count(struct shrinker *shrinker,
- struct shrink_control *sc)
+static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask,
+ int nr_to_scan)
{
- struct ion_heap *heap = container_of(shrinker, struct ion_heap,
- shrinker);
- struct ion_system_heap *sys_heap = container_of(heap,
- struct ion_system_heap,
- heap);
+ struct ion_system_heap *sys_heap;
int nr_total = 0;
int i;
- /* total number of items is whatever the page pools are holding
- plus whatever's in the freelist */
- for (i = 0; i < num_orders; i++) {
- struct ion_page_pool *pool = sys_heap->pools[i];
- nr_total += ion_page_pool_shrink(pool, sc->gfp_mask, 0);
- }
- nr_total += ion_heap_freelist_size(heap) / PAGE_SIZE;
- return nr_total;
-
-}
-
-static unsigned long ion_system_heap_shrink_scan(struct shrinker *shrinker,
- struct shrink_control *sc)
-{
-
- struct ion_heap *heap = container_of(shrinker, struct ion_heap,
- shrinker);
- struct ion_system_heap *sys_heap = container_of(heap,
- struct ion_system_heap,
- heap);
- int nr_freed = 0;
- int i;
-
- if (sc->nr_to_scan == 0)
- goto end;
-
- /* shrink the free list first, no point in zeroing the memory if
- we're just going to reclaim it */
- nr_freed += ion_heap_freelist_drain(heap, sc->nr_to_scan * PAGE_SIZE) /
- PAGE_SIZE;
-
- if (nr_freed >= sc->nr_to_scan)
- goto end;
+ sys_heap = container_of(heap, struct ion_system_heap, heap);
for (i = 0; i < num_orders; i++) {
struct ion_page_pool *pool = sys_heap->pools[i];
-
- nr_freed += ion_page_pool_shrink(pool, sc->gfp_mask,
- sc->nr_to_scan);
- if (nr_freed >= sc->nr_to_scan)
- break;
+ nr_total += ion_page_pool_shrink(pool, gfp_mask, nr_to_scan);
}
-end:
- return nr_freed;
-
+ return nr_total;
}
+static struct ion_heap_ops system_heap_ops = {
+ .allocate = ion_system_heap_allocate,
+ .free = ion_system_heap_free,
+ .map_dma = ion_system_heap_map_dma,
+ .unmap_dma = ion_system_heap_unmap_dma,
+ .map_kernel = ion_heap_map_kernel,
+ .unmap_kernel = ion_heap_unmap_kernel,
+ .map_user = ion_heap_map_user,
+ .shrink = ion_system_heap_shrink,
+};
+
static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
void *unused)
{
@@ -347,11 +306,6 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
heap->pools[i] = pool;
}
- heap->heap.shrinker.scan_objects = ion_system_heap_shrink_scan;
- heap->heap.shrinker.count_objects = ion_system_heap_shrink_count;
- heap->heap.shrinker.seeks = DEFAULT_SEEKS;
- heap->heap.shrinker.batch = 0;
- register_shrinker(&heap->heap.shrinker);
heap->heap.debug_show = ion_system_heap_debug_show;
return &heap->heap;
err_create_pool:
diff --git a/drivers/staging/android/ion/tegra/tegra_ion.c b/drivers/staging/android/ion/tegra/tegra_ion.c
index 3474c65f87fa..11c7cceb3c7d 100644
--- a/drivers/staging/android/ion/tegra/tegra_ion.c
+++ b/drivers/staging/android/ion/tegra/tegra_ion.c
@@ -32,13 +32,13 @@ static int tegra_ion_probe(struct platform_device *pdev)
num_heaps = pdata->nr;
- heaps = kzalloc(sizeof(struct ion_heap *) * pdata->nr, GFP_KERNEL);
+ heaps = devm_kzalloc(&pdev->dev,
+ sizeof(struct ion_heap *) * pdata->nr,
+ GFP_KERNEL);
idev = ion_device_create(NULL);
- if (IS_ERR_OR_NULL(idev)) {
- kfree(heaps);
+ if (IS_ERR_OR_NULL(idev))
return PTR_ERR(idev);
- }
/* create the heaps as specified in the board file */
for (i = 0; i < num_heaps; i++) {
@@ -58,7 +58,6 @@ err:
if (heaps[i])
ion_heap_destroy(heaps[i]);
}
- kfree(heaps);
return err;
}
@@ -70,7 +69,6 @@ static int tegra_ion_remove(struct platform_device *pdev)
ion_device_destroy(idev);
for (i = 0; i < num_heaps; i++)
ion_heap_destroy(heaps[i]);
- kfree(heaps);
return 0;
}
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 6f094b37f1f1..b545d3d1da3e 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -88,7 +88,8 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
int array_size = ARRAY_SIZE(lowmem_adj);
int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
int other_file = global_page_state(NR_FILE_PAGES) -
- global_page_state(NR_SHMEM);
+ global_page_state(NR_SHMEM) -
+ total_swapcache_pages();
if (lowmem_adj_size < array_size)
array_size = lowmem_adj_size;
@@ -159,8 +160,8 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
selected->pid, selected->comm,
selected_oom_score_adj, selected_tasksize);
lowmem_deathpending_timeout = jiffies + HZ;
- send_sig(SIGKILL, selected, 0);
set_tsk_thread_flag(selected, TIF_MEMDIE);
+ send_sig(SIGKILL, selected, 0);
rem += selected_tasksize;
}
diff --git a/drivers/staging/android/sw_sync.h b/drivers/staging/android/sw_sync.h
index 5aaf71d6974b..1a50669ec8a9 100644
--- a/drivers/staging/android/sw_sync.h
+++ b/drivers/staging/android/sw_sync.h
@@ -18,10 +18,9 @@
#define _LINUX_SW_SYNC_H
#include <linux/types.h>
-
-#ifdef __KERNEL__
-
+#include <linux/kconfig.h>
#include "sync.h"
+#include "uapi/sw_sync.h"
struct sw_sync_timeline {
struct sync_timeline obj;
@@ -57,19 +56,4 @@ static inline struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj,
}
#endif /* IS_ENABLED(CONFIG_SW_SYNC) */
-#endif /* __KERNEL __ */
-
-struct sw_sync_create_fence_data {
- __u32 value;
- char name[32];
- __s32 fence; /* fd of new fence */
-};
-
-#define SW_SYNC_IOC_MAGIC 'W'
-
-#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\
- struct sw_sync_create_fence_data)
-#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
-
-
#endif /* _LINUX_SW_SYNC_H */
diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h
index 62e2255b1c1e..eaf57cccf626 100644
--- a/drivers/staging/android/sync.h
+++ b/drivers/staging/android/sync.h
@@ -14,14 +14,14 @@
#define _LINUX_SYNC_H
#include <linux/types.h>
-#ifdef __KERNEL__
-
#include <linux/kref.h>
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
+#include "uapi/sync.h"
+
struct sync_timeline;
struct sync_pt;
struct sync_fence;
@@ -53,7 +53,7 @@ struct sync_timeline_ops {
const char *driver_name;
/* required */
- struct sync_pt *(*dup)(struct sync_pt *pt);
+ struct sync_pt * (*dup)(struct sync_pt *pt);
/* required */
int (*has_signaled)(struct sync_pt *pt);
@@ -341,86 +341,4 @@ int sync_fence_cancel_async(struct sync_fence *fence,
*/
int sync_fence_wait(struct sync_fence *fence, long timeout);
-#endif /* __KERNEL__ */
-
-/**
- * struct sync_merge_data - data passed to merge ioctl
- * @fd2: file descriptor of second fence
- * @name: name of new fence
- * @fence: returns the fd of the new fence to userspace
- */
-struct sync_merge_data {
- __s32 fd2; /* fd of second fence */
- char name[32]; /* name of new fence */
- __s32 fence; /* fd on newly created fence */
-};
-
-/**
- * struct sync_pt_info - detailed sync_pt information
- * @len: length of sync_pt_info including any driver_data
- * @obj_name: name of parent sync_timeline
- * @driver_name: name of driver implementing the parent
- * @status: status of the sync_pt 0:active 1:signaled <0:error
- * @timestamp_ns: timestamp of status change in nanoseconds
- * @driver_data: any driver dependent data
- */
-struct sync_pt_info {
- __u32 len;
- char obj_name[32];
- char driver_name[32];
- __s32 status;
- __u64 timestamp_ns;
-
- __u8 driver_data[0];
-};
-
-/**
- * struct sync_fence_info_data - data returned from fence info ioctl
- * @len: ioctl caller writes the size of the buffer its passing in.
- * ioctl returns length of sync_fence_data returned to userspace
- * including pt_info.
- * @name: name of fence
- * @status: status of fence. 1: signaled 0:active <0:error
- * @pt_info: a sync_pt_info struct for every sync_pt in the fence
- */
-struct sync_fence_info_data {
- __u32 len;
- char name[32];
- __s32 status;
-
- __u8 pt_info[0];
-};
-
-#define SYNC_IOC_MAGIC '>'
-
-/**
- * DOC: SYNC_IOC_WAIT - wait for a fence to signal
- *
- * pass timeout in milliseconds. Waits indefinitely timeout < 0.
- */
-#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32)
-
-/**
- * DOC: SYNC_IOC_MERGE - merge two fences
- *
- * Takes a struct sync_merge_data. Creates a new fence containing copies of
- * the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the
- * new fence's fd in sync_merge_data.fence
- */
-#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
-
-/**
- * DOC: SYNC_IOC_FENCE_INFO - get detailed information on a fence
- *
- * Takes a struct sync_fence_info_data with extra space allocated for pt_info.
- * Caller should write the size of the buffer into len. On return, len is
- * updated to reflect the total size of the sync_fence_info_data including
- * pt_info.
- *
- * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence.
- * To iterate over the sync_pt_infos, use the sync_pt_info.len field.
- */
-#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\
- struct sync_fence_info_data)
-
#endif /* _LINUX_SYNC_H */
diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c
index e81451425c01..0c7fdc83b336 100644
--- a/drivers/staging/android/timed_gpio.c
+++ b/drivers/staging/android/timed_gpio.c
@@ -90,8 +90,9 @@ static int timed_gpio_probe(struct platform_device *pdev)
if (!pdata)
return -EBUSY;
- gpio_data = kzalloc(sizeof(struct timed_gpio_data) * pdata->num_gpios,
- GFP_KERNEL);
+ gpio_data = devm_kzalloc(&pdev->dev,
+ sizeof(struct timed_gpio_data) * pdata->num_gpios,
+ GFP_KERNEL);
if (!gpio_data)
return -ENOMEM;
@@ -131,7 +132,6 @@ err_out:
timed_output_dev_unregister(&gpio_data[i].dev);
gpio_free(gpio_data[i].gpio);
}
- kfree(gpio_data);
return ret;
}
@@ -147,8 +147,6 @@ static int timed_gpio_remove(struct platform_device *pdev)
gpio_free(gpio_data[i].gpio);
}
- kfree(gpio_data);
-
return 0;
}
diff --git a/drivers/staging/android/timed_output.h b/drivers/staging/android/timed_output.h
index 905c7cc9588e..13d2ca51cbe8 100644
--- a/drivers/staging/android/timed_output.h
+++ b/drivers/staging/android/timed_output.h
@@ -20,10 +20,10 @@ struct timed_output_dev {
const char *name;
/* enable the output and set the timer */
- void (*enable)(struct timed_output_dev *sdev, int timeout);
+ void (*enable)(struct timed_output_dev *sdev, int timeout);
/* returns the current number of milliseconds remaining on the timer */
- int (*get_time)(struct timed_output_dev *sdev);
+ int (*get_time)(struct timed_output_dev *sdev);
/* private data */
struct device *dev;
diff --git a/drivers/staging/android/uapi/android_alarm.h b/drivers/staging/android/uapi/android_alarm.h
new file mode 100644
index 000000000000..aa013f6f5f3a
--- /dev/null
+++ b/drivers/staging/android/uapi/android_alarm.h
@@ -0,0 +1,62 @@
+/* drivers/staging/android/uapi/android_alarm.h
+ *
+ * Copyright (C) 2006-2007 Google, Inc.
+ *
+ * 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 _UAPI_LINUX_ANDROID_ALARM_H
+#define _UAPI_LINUX_ANDROID_ALARM_H
+
+#include <linux/ioctl.h>
+#include <linux/time.h>
+
+enum android_alarm_type {
+ /* return code bit numbers or set alarm arg */
+ ANDROID_ALARM_RTC_WAKEUP,
+ ANDROID_ALARM_RTC,
+ ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+ ANDROID_ALARM_ELAPSED_REALTIME,
+ ANDROID_ALARM_SYSTEMTIME,
+
+ ANDROID_ALARM_TYPE_COUNT,
+
+ /* return code bit numbers */
+ /* ANDROID_ALARM_TIME_CHANGE = 16 */
+};
+
+enum android_alarm_return_flags {
+ ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
+ ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
+ ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
+ 1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+ ANDROID_ALARM_ELAPSED_REALTIME_MASK =
+ 1U << ANDROID_ALARM_ELAPSED_REALTIME,
+ ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
+ ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
+};
+
+/* Disable alarm */
+#define ANDROID_ALARM_CLEAR(type) _IO('a', 0 | ((type) << 4))
+
+/* Ack last alarm and wait for next */
+#define ANDROID_ALARM_WAIT _IO('a', 1)
+
+#define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size)
+/* Set alarm */
+#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec)
+#define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec)
+#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec)
+#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec)
+#define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0)))
+#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4)
+
+#endif
diff --git a/drivers/staging/android/uapi/ashmem.h b/drivers/staging/android/uapi/ashmem.h
new file mode 100644
index 000000000000..ba4743c71d6b
--- /dev/null
+++ b/drivers/staging/android/uapi/ashmem.h
@@ -0,0 +1,47 @@
+/*
+ * drivers/staging/android/uapi/ashmem.h
+ *
+ * Copyright 2008 Google Inc.
+ * Author: Robert Love
+ *
+ * This file is dual licensed. It may be redistributed and/or modified
+ * under the terms of the Apache 2.0 License OR version 2 of the GNU
+ * General Public License.
+ */
+
+#ifndef _UAPI_LINUX_ASHMEM_H
+#define _UAPI_LINUX_ASHMEM_H
+
+#include <linux/ioctl.h>
+
+#define ASHMEM_NAME_LEN 256
+
+#define ASHMEM_NAME_DEF "dev/ashmem"
+
+/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
+#define ASHMEM_NOT_PURGED 0
+#define ASHMEM_WAS_PURGED 1
+
+/* Return values from ASHMEM_GET_PIN_STATUS: Is the mapping pinned? */
+#define ASHMEM_IS_UNPINNED 0
+#define ASHMEM_IS_PINNED 1
+
+struct ashmem_pin {
+ __u32 offset; /* offset into region, in bytes, page-aligned */
+ __u32 len; /* length forward from offset, in bytes, page-aligned */
+};
+
+#define __ASHMEMIOC 0x77
+
+#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
+#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
+#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t)
+#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4)
+#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long)
+#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6)
+#define ASHMEM_PIN _IOW(__ASHMEMIOC, 7, struct ashmem_pin)
+#define ASHMEM_UNPIN _IOW(__ASHMEMIOC, 8, struct ashmem_pin)
+#define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9)
+#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10)
+
+#endif /* _UAPI_LINUX_ASHMEM_H */
diff --git a/drivers/staging/android/uapi/binder.h b/drivers/staging/android/uapi/binder.h
new file mode 100644
index 000000000000..904adb7600cf
--- /dev/null
+++ b/drivers/staging/android/uapi/binder.h
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * Based on, but no longer compatible with, the original
+ * OpenBinder.org binder driver interface, which is:
+ *
+ * Copyright (c) 2005 Palmsource, Inc.
+ *
+ * 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 _UAPI_LINUX_BINDER_H
+#define _UAPI_LINUX_BINDER_H
+
+#include <linux/ioctl.h>
+
+#define B_PACK_CHARS(c1, c2, c3, c4) \
+ ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
+#define B_TYPE_LARGE 0x85
+
+enum {
+ BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
+ BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
+ BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
+ BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
+ BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
+};
+
+enum {
+ FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
+ FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
+};
+
+#ifdef BINDER_IPC_32BIT
+typedef __u32 binder_size_t;
+typedef __u32 binder_uintptr_t;
+#else
+typedef __u64 binder_size_t;
+typedef __u64 binder_uintptr_t;
+#endif
+
+/*
+ * This is the flattened representation of a Binder object for transfer
+ * between processes. The 'offsets' supplied as part of a binder transaction
+ * contains offsets into the data where these structures occur. The Binder
+ * driver takes care of re-writing the structure type and data as it moves
+ * between processes.
+ */
+struct flat_binder_object {
+ /* 8 bytes for large_flat_header. */
+ __u32 type;
+ __u32 flags;
+
+ /* 8 bytes of data. */
+ union {
+ binder_uintptr_t binder; /* local object */
+ __u32 handle; /* remote object */
+ };
+
+ /* extra data associated with local object */
+ binder_uintptr_t cookie;
+};
+
+/*
+ * On 64-bit platforms where user code may run in 32-bits the driver must
+ * translate the buffer (and local binder) addresses appropriately.
+ */
+
+struct binder_write_read {
+ binder_size_t write_size; /* bytes to write */
+ binder_size_t write_consumed; /* bytes consumed by driver */
+ binder_uintptr_t write_buffer;
+ binder_size_t read_size; /* bytes to read */
+ binder_size_t read_consumed; /* bytes consumed by driver */
+ binder_uintptr_t read_buffer;
+};
+
+/* Use with BINDER_VERSION, driver fills in fields. */
+struct binder_version {
+ /* driver protocol version -- increment with incompatible change */
+ __s32 protocol_version;
+};
+
+/* This is the current protocol version. */
+#ifdef BINDER_IPC_32BIT
+#define BINDER_CURRENT_PROTOCOL_VERSION 7
+#else
+#define BINDER_CURRENT_PROTOCOL_VERSION 8
+#endif
+
+#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
+#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
+#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32)
+#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32)
+#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
+#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
+#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
+
+/*
+ * NOTE: Two special error codes you should check for when calling
+ * in to the driver are:
+ *
+ * EINTR -- The operation has been interupted. This should be
+ * handled by retrying the ioctl() until a different error code
+ * is returned.
+ *
+ * ECONNREFUSED -- The driver is no longer accepting operations
+ * from your process. That is, the process is being destroyed.
+ * You should handle this by exiting from your process. Note
+ * that once this error code is returned, all further calls to
+ * the driver from any thread will return this same code.
+ */
+
+enum transaction_flags {
+ TF_ONE_WAY = 0x01, /* this is a one-way call: async, no return */
+ TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */
+ TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */
+ TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */
+};
+
+struct binder_transaction_data {
+ /* The first two are only used for bcTRANSACTION and brTRANSACTION,
+ * identifying the target and contents of the transaction.
+ */
+ union {
+ /* target descriptor of command transaction */
+ __u32 handle;
+ /* target descriptor of return transaction */
+ binder_uintptr_t ptr;
+ } target;
+ binder_uintptr_t cookie; /* target object cookie */
+ __u32 code; /* transaction command */
+
+ /* General information about the transaction. */
+ __u32 flags;
+ pid_t sender_pid;
+ uid_t sender_euid;
+ binder_size_t data_size; /* number of bytes of data */
+ binder_size_t offsets_size; /* number of bytes of offsets */
+
+ /* If this transaction is inline, the data immediately
+ * follows here; otherwise, it ends with a pointer to
+ * the data buffer.
+ */
+ union {
+ struct {
+ /* transaction data */
+ binder_uintptr_t buffer;
+ /* offsets from buffer to flat_binder_object structs */
+ binder_uintptr_t offsets;
+ } ptr;
+ __u8 buf[8];
+ } data;
+};
+
+struct binder_ptr_cookie {
+ binder_uintptr_t ptr;
+ binder_uintptr_t cookie;
+};
+
+struct binder_handle_cookie {
+ __u32 handle;
+ binder_uintptr_t cookie;
+} __attribute__((packed));
+
+struct binder_pri_desc {
+ __s32 priority;
+ __u32 desc;
+};
+
+struct binder_pri_ptr_cookie {
+ __s32 priority;
+ binder_uintptr_t ptr;
+ binder_uintptr_t cookie;
+};
+
+enum binder_driver_return_protocol {
+ BR_ERROR = _IOR('r', 0, __s32),
+ /*
+ * int: error code
+ */
+
+ BR_OK = _IO('r', 1),
+ /* No parameters! */
+
+ BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
+ BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
+ /*
+ * binder_transaction_data: the received command.
+ */
+
+ BR_ACQUIRE_RESULT = _IOR('r', 4, __s32),
+ /*
+ * not currently supported
+ * int: 0 if the last bcATTEMPT_ACQUIRE was not successful.
+ * Else the remote object has acquired a primary reference.
+ */
+
+ BR_DEAD_REPLY = _IO('r', 5),
+ /*
+ * The target of the last transaction (either a bcTRANSACTION or
+ * a bcATTEMPT_ACQUIRE) is no longer with us. No parameters.
+ */
+
+ BR_TRANSACTION_COMPLETE = _IO('r', 6),
+ /*
+ * No parameters... always refers to the last transaction requested
+ * (including replies). Note that this will be sent even for
+ * asynchronous transactions.
+ */
+
+ BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),
+ BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),
+ BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),
+ BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie),
+ /*
+ * void *: ptr to binder
+ * void *: cookie for binder
+ */
+
+ BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie),
+ /*
+ * not currently supported
+ * int: priority
+ * void *: ptr to binder
+ * void *: cookie for binder
+ */
+
+ BR_NOOP = _IO('r', 12),
+ /*
+ * No parameters. Do nothing and examine the next command. It exists
+ * primarily so that we can replace it with a BR_SPAWN_LOOPER command.
+ */
+
+ BR_SPAWN_LOOPER = _IO('r', 13),
+ /*
+ * No parameters. The driver has determined that a process has no
+ * threads waiting to service incoming transactions. When a process
+ * receives this command, it must spawn a new service thread and
+ * register it via bcENTER_LOOPER.
+ */
+
+ BR_FINISHED = _IO('r', 14),
+ /*
+ * not currently supported
+ * stop threadpool thread
+ */
+
+ BR_DEAD_BINDER = _IOR('r', 15, binder_uintptr_t),
+ /*
+ * void *: cookie
+ */
+ BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, binder_uintptr_t),
+ /*
+ * void *: cookie
+ */
+
+ BR_FAILED_REPLY = _IO('r', 17),
+ /*
+ * The the last transaction (either a bcTRANSACTION or
+ * a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters.
+ */
+};
+
+enum binder_driver_command_protocol {
+ BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),
+ BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
+ /*
+ * binder_transaction_data: the sent command.
+ */
+
+ BC_ACQUIRE_RESULT = _IOW('c', 2, __s32),
+ /*
+ * not currently supported
+ * int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful.
+ * Else you have acquired a primary reference on the object.
+ */
+
+ BC_FREE_BUFFER = _IOW('c', 3, binder_uintptr_t),
+ /*
+ * void *: ptr to transaction data received on a read
+ */
+
+ BC_INCREFS = _IOW('c', 4, __u32),
+ BC_ACQUIRE = _IOW('c', 5, __u32),
+ BC_RELEASE = _IOW('c', 6, __u32),
+ BC_DECREFS = _IOW('c', 7, __u32),
+ /*
+ * int: descriptor
+ */
+
+ BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
+ BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
+ /*
+ * void *: ptr to binder
+ * void *: cookie for binder
+ */
+
+ BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
+ /*
+ * not currently supported
+ * int: priority
+ * int: descriptor
+ */
+
+ BC_REGISTER_LOOPER = _IO('c', 11),
+ /*
+ * No parameters.
+ * Register a spawned looper thread with the device.
+ */
+
+ BC_ENTER_LOOPER = _IO('c', 12),
+ BC_EXIT_LOOPER = _IO('c', 13),
+ /*
+ * No parameters.
+ * These two commands are sent as an application-level thread
+ * enters and exits the binder loop, respectively. They are
+ * used so the binder can have an accurate count of the number
+ * of looping threads it has available.
+ */
+
+ BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14,
+ struct binder_handle_cookie),
+ /*
+ * int: handle
+ * void *: cookie
+ */
+
+ BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15,
+ struct binder_handle_cookie),
+ /*
+ * int: handle
+ * void *: cookie
+ */
+
+ BC_DEAD_BINDER_DONE = _IOW('c', 16, binder_uintptr_t),
+ /*
+ * void *: cookie
+ */
+};
+
+#endif /* _UAPI_LINUX_BINDER_H */
+
diff --git a/drivers/staging/android/uapi/sw_sync.h b/drivers/staging/android/uapi/sw_sync.h
new file mode 100644
index 000000000000..9b5d4869505c
--- /dev/null
+++ b/drivers/staging/android/uapi/sw_sync.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * 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 _UAPI_LINUX_SW_SYNC_H
+#define _UAPI_LINUX_SW_SYNC_H
+
+#include <linux/types.h>
+
+struct sw_sync_create_fence_data {
+ __u32 value;
+ char name[32];
+ __s32 fence; /* fd of new fence */
+};
+
+#define SW_SYNC_IOC_MAGIC 'W'
+
+#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\
+ struct sw_sync_create_fence_data)
+#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
+
+#endif /* _UAPI_LINUX_SW_SYNC_H */
diff --git a/drivers/staging/android/uapi/sync.h b/drivers/staging/android/uapi/sync.h
new file mode 100644
index 000000000000..e964c751f6b8
--- /dev/null
+++ b/drivers/staging/android/uapi/sync.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * 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 _UAPI_LINUX_SYNC_H
+#define _UAPI_LINUX_SYNC_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/**
+ * struct sync_merge_data - data passed to merge ioctl
+ * @fd2: file descriptor of second fence
+ * @name: name of new fence
+ * @fence: returns the fd of the new fence to userspace
+ */
+struct sync_merge_data {
+ __s32 fd2; /* fd of second fence */
+ char name[32]; /* name of new fence */
+ __s32 fence; /* fd on newly created fence */
+};
+
+/**
+ * struct sync_pt_info - detailed sync_pt information
+ * @len: length of sync_pt_info including any driver_data
+ * @obj_name: name of parent sync_timeline
+ * @driver_name: name of driver implementing the parent
+ * @status: status of the sync_pt 0:active 1:signaled <0:error
+ * @timestamp_ns: timestamp of status change in nanoseconds
+ * @driver_data: any driver dependent data
+ */
+struct sync_pt_info {
+ __u32 len;
+ char obj_name[32];
+ char driver_name[32];
+ __s32 status;
+ __u64 timestamp_ns;
+
+ __u8 driver_data[0];
+};
+
+/**
+ * struct sync_fence_info_data - data returned from fence info ioctl
+ * @len: ioctl caller writes the size of the buffer its passing in.
+ * ioctl returns length of sync_fence_data returned to userspace
+ * including pt_info.
+ * @name: name of fence
+ * @status: status of fence. 1: signaled 0:active <0:error
+ * @pt_info: a sync_pt_info struct for every sync_pt in the fence
+ */
+struct sync_fence_info_data {
+ __u32 len;
+ char name[32];
+ __s32 status;
+
+ __u8 pt_info[0];
+};
+
+#define SYNC_IOC_MAGIC '>'
+
+/**
+ * DOC: SYNC_IOC_WAIT - wait for a fence to signal
+ *
+ * pass timeout in milliseconds. Waits indefinitely timeout < 0.
+ */
+#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32)
+
+/**
+ * DOC: SYNC_IOC_MERGE - merge two fences
+ *
+ * Takes a struct sync_merge_data. Creates a new fence containing copies of
+ * the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the
+ * new fence's fd in sync_merge_data.fence
+ */
+#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
+
+/**
+ * DOC: SYNC_IOC_FENCE_INFO - get detailed information on a fence
+ *
+ * Takes a struct sync_fence_info_data with extra space allocated for pt_info.
+ * Caller should write the size of the buffer into len. On return, len is
+ * updated to reflect the total size of the sync_fence_info_data including
+ * pt_info.
+ *
+ * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence.
+ * To iterate over the sync_pt_infos, use the sync_pt_info.len field.
+ */
+#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\
+ struct sync_fence_info_data)
+
+#endif /* _UAPI_LINUX_SYNC_H */
diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h
index f0d6f0c38207..1b2d9f3bd55a 100644
--- a/drivers/staging/bcm/Adapter.h
+++ b/drivers/staging/bcm/Adapter.h
@@ -37,8 +37,10 @@ struct bcm_link_request {
union u_ip_address {
struct {
- ULONG ulIpv4Addr[MAX_IP_RANGE_LENGTH]; /* Source Ip Address Range */
- ULONG ulIpv4Mask[MAX_IP_RANGE_LENGTH]; /* Source Ip Mask Address Range */
+ /* Source Ip Address Range */
+ ULONG ulIpv4Addr[MAX_IP_RANGE_LENGTH];
+ /* Source Ip Mask Address Range */
+ ULONG ulIpv4Mask[MAX_IP_RANGE_LENGTH];
};
struct {
ULONG ulIpv6Addr[MAX_IP_RANGE_LENGTH * 4]; /* Source Ip Address Range */
diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c
index f1b6de0293c8..ae7490b4d70e 100644
--- a/drivers/staging/bcm/Bcmchar.c
+++ b/drivers/staging/bcm/Bcmchar.c
@@ -150,1903 +150,2392 @@ static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size,
return PktLen;
}
-static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
+static int bcm_char_ioctl_reg_read_private(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
{
- struct bcm_tarang_data *pTarang = filp->private_data;
- void __user *argp = (void __user *)arg;
- struct bcm_mini_adapter *Adapter = pTarang->Adapter;
- INT Status = STATUS_FAILURE;
- int timeout = 0;
+ struct bcm_rdm_buffer sRdmBuffer = {0};
struct bcm_ioctl_buffer IoBuffer;
+ PCHAR temp_buff;
+ INT Status = STATUS_FAILURE;
+ UINT Bufflen;
+ u16 temp_value;
int bytes;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
- "Parameters Passed to control IOCTL cmd=0x%X arg=0x%lX",
- cmd, arg);
-
- if (_IOC_TYPE(cmd) != BCM_IOCTL)
+ /* Copy Ioctl Buffer structure */
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
return -EFAULT;
- if (_IOC_DIR(cmd) & _IOC_READ)
- Status = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
- else if (_IOC_DIR(cmd) & _IOC_WRITE)
- Status = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
- else if (_IOC_NONE == (_IOC_DIR(cmd) & _IOC_NONE))
- Status = STATUS_SUCCESS;
- if (Status)
- return -EFAULT;
+ if (IoBuffer.InputLength > sizeof(sRdmBuffer))
+ return -EINVAL;
- if (Adapter->device_removed)
+ if (copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer,
+ IoBuffer.InputLength))
return -EFAULT;
- if (false == Adapter->fw_download_done) {
- switch (cmd) {
- case IOCTL_MAC_ADDR_REQ:
- case IOCTL_LINK_REQ:
- case IOCTL_CM_REQUEST:
- case IOCTL_SS_INFO_REQ:
- case IOCTL_SEND_CONTROL_MESSAGE:
- case IOCTL_IDLE_REQ:
- case IOCTL_BCM_GPIO_SET_REQUEST:
- case IOCTL_BCM_GPIO_STATUS_REQUEST:
- return -EACCES;
- default:
- break;
- }
+ if (IoBuffer.OutputLength > USHRT_MAX ||
+ IoBuffer.OutputLength == 0) {
+ return -EINVAL;
}
- Status = vendorextnIoctl(Adapter, cmd, arg);
- if (Status != CONTINUE_COMMON_PATH)
- return Status;
+ Bufflen = IoBuffer.OutputLength;
+ temp_value = 4 - (Bufflen % 4);
+ Bufflen += temp_value % 4;
- switch (cmd) {
- /* Rdms for Swin Idle... */
- case IOCTL_BCM_REGISTER_READ_PRIVATE: {
- struct bcm_rdm_buffer sRdmBuffer = {0};
- PCHAR temp_buff;
- UINT Bufflen;
- u16 temp_value;
-
- /* Copy Ioctl Buffer structure */
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
-
- if (IoBuffer.InputLength > sizeof(sRdmBuffer))
- return -EINVAL;
+ temp_buff = kmalloc(Bufflen, GFP_KERNEL);
+ if (!temp_buff)
+ return -ENOMEM;
- if (copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
+ bytes = rdmalt(Adapter, (UINT)sRdmBuffer.Register,
+ (PUINT)temp_buff, Bufflen);
+ if (bytes > 0) {
+ Status = STATUS_SUCCESS;
+ if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) {
+ kfree(temp_buff);
return -EFAULT;
-
- if (IoBuffer.OutputLength > USHRT_MAX ||
- IoBuffer.OutputLength == 0) {
- return -EINVAL;
}
+ } else {
+ Status = bytes;
+ }
- Bufflen = IoBuffer.OutputLength;
- temp_value = 4 - (Bufflen % 4);
- Bufflen += temp_value % 4;
+ kfree(temp_buff);
+ return Status;
+}
- temp_buff = kmalloc(Bufflen, GFP_KERNEL);
- if (!temp_buff)
- return -ENOMEM;
+static int bcm_char_ioctl_reg_write_private(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_wrm_buffer sWrmBuffer = {0};
+ struct bcm_ioctl_buffer IoBuffer;
+ UINT uiTempVar = 0;
+ INT Status;
- bytes = rdmalt(Adapter, (UINT)sRdmBuffer.Register,
- (PUINT)temp_buff, Bufflen);
- if (bytes > 0) {
- Status = STATUS_SUCCESS;
- if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) {
- kfree(temp_buff);
- return -EFAULT;
- }
- } else {
- Status = bytes;
- }
+ /* Copy Ioctl Buffer structure */
- kfree(temp_buff);
- break;
- }
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- case IOCTL_BCM_REGISTER_WRITE_PRIVATE: {
- struct bcm_wrm_buffer sWrmBuffer = {0};
- UINT uiTempVar = 0;
- /* Copy Ioctl Buffer structure */
+ if (IoBuffer.InputLength > sizeof(sWrmBuffer))
+ return -EINVAL;
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ /* Get WrmBuffer structure */
+ if (copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer,
+ IoBuffer.InputLength))
+ return -EFAULT;
- if (IoBuffer.InputLength > sizeof(sWrmBuffer))
- return -EINVAL;
+ uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK;
+ if (!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) &&
+ ((uiTempVar == EEPROM_REJECT_REG_1) ||
+ (uiTempVar == EEPROM_REJECT_REG_2) ||
+ (uiTempVar == EEPROM_REJECT_REG_3) ||
+ (uiTempVar == EEPROM_REJECT_REG_4))) {
- /* Get WrmBuffer structure */
- if (copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
- return -EFAULT;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "EEPROM Access Denied, not in VSG Mode\n");
+ return -EFAULT;
+ }
- uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK;
- if (!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) &&
- ((uiTempVar == EEPROM_REJECT_REG_1) ||
- (uiTempVar == EEPROM_REJECT_REG_2) ||
- (uiTempVar == EEPROM_REJECT_REG_3) ||
- (uiTempVar == EEPROM_REJECT_REG_4))) {
+ Status = wrmalt(Adapter, (UINT)sWrmBuffer.Register,
+ (PUINT)sWrmBuffer.Data, sizeof(ULONG));
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "EEPROM Access Denied, not in VSG Mode\n");
- return -EFAULT;
- }
+ if (Status == STATUS_SUCCESS) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL, "WRM Done\n");
+ } else {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL, "WRM Failed\n");
+ Status = -EFAULT;
+ }
+ return Status;
+}
- Status = wrmalt(Adapter, (UINT)sWrmBuffer.Register,
- (PUINT)sWrmBuffer.Data, sizeof(ULONG));
+static int bcm_char_ioctl_eeprom_reg_read(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_rdm_buffer sRdmBuffer = {0};
+ struct bcm_ioctl_buffer IoBuffer;
+ PCHAR temp_buff = NULL;
+ UINT uiTempVar = 0;
+ INT Status;
+ int bytes;
- if (Status == STATUS_SUCCESS) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
- DBG_LVL_ALL, "WRM Done\n");
- } else {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
- DBG_LVL_ALL, "WRM Failed\n");
- Status = -EFAULT;
- }
- break;
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE)) {
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Device in Idle Mode, Blocking Rdms\n");
+ return -EACCES;
}
- case IOCTL_BCM_REGISTER_READ:
- case IOCTL_BCM_EEPROM_REGISTER_READ: {
- struct bcm_rdm_buffer sRdmBuffer = {0};
- PCHAR temp_buff = NULL;
- UINT uiTempVar = 0;
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE)) {
+ /* Copy Ioctl Buffer structure */
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "Device in Idle Mode, Blocking Rdms\n");
- return -EACCES;
- }
+ if (IoBuffer.InputLength > sizeof(sRdmBuffer))
+ return -EINVAL;
- /* Copy Ioctl Buffer structure */
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ if (copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer,
+ IoBuffer.InputLength))
+ return -EFAULT;
- if (IoBuffer.InputLength > sizeof(sRdmBuffer))
- return -EINVAL;
+ if (IoBuffer.OutputLength > USHRT_MAX ||
+ IoBuffer.OutputLength == 0) {
+ return -EINVAL;
+ }
- if (copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
- return -EFAULT;
+ temp_buff = kmalloc(IoBuffer.OutputLength, GFP_KERNEL);
+ if (!temp_buff)
+ return STATUS_FAILURE;
- if (IoBuffer.OutputLength > USHRT_MAX ||
- IoBuffer.OutputLength == 0) {
- return -EINVAL;
- }
+ if ((((ULONG)sRdmBuffer.Register & 0x0F000000) != 0x0F000000) ||
+ ((ULONG)sRdmBuffer.Register & 0x3)) {
- temp_buff = kmalloc(IoBuffer.OutputLength, GFP_KERNEL);
- if (!temp_buff)
- return STATUS_FAILURE;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "RDM Done On invalid Address : %x Access Denied.\n",
+ (int)sRdmBuffer.Register);
- if ((((ULONG)sRdmBuffer.Register & 0x0F000000) != 0x0F000000) ||
- ((ULONG)sRdmBuffer.Register & 0x3)) {
+ kfree(temp_buff);
+ return -EINVAL;
+ }
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "RDM Done On invalid Address : %x Access Denied.\n",
- (int)sRdmBuffer.Register);
+ uiTempVar = sRdmBuffer.Register & EEPROM_REJECT_MASK;
+ bytes = rdmaltWithLock(Adapter, (UINT)sRdmBuffer.Register,
+ (PUINT)temp_buff, IoBuffer.OutputLength);
+ if (bytes > 0) {
+ Status = STATUS_SUCCESS;
+ if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) {
kfree(temp_buff);
- return -EINVAL;
+ return -EFAULT;
}
+ } else {
+ Status = bytes;
+ }
- uiTempVar = sRdmBuffer.Register & EEPROM_REJECT_MASK;
- bytes = rdmaltWithLock(Adapter, (UINT)sRdmBuffer.Register,
- (PUINT)temp_buff, IoBuffer.OutputLength);
+ kfree(temp_buff);
+ return Status;
+}
- if (bytes > 0) {
- Status = STATUS_SUCCESS;
- if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) {
- kfree(temp_buff);
- return -EFAULT;
- }
- } else {
- Status = bytes;
- }
+static int bcm_char_ioctl_eeprom_reg_write(void __user *argp,
+ struct bcm_mini_adapter *Adapter, UINT cmd)
+{
+ struct bcm_wrm_buffer sWrmBuffer = {0};
+ struct bcm_ioctl_buffer IoBuffer;
+ UINT uiTempVar = 0;
+ INT Status;
- kfree(temp_buff);
- break;
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE)) {
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Device in Idle Mode, Blocking Wrms\n");
+ return -EACCES;
}
- case IOCTL_BCM_REGISTER_WRITE:
- case IOCTL_BCM_EEPROM_REGISTER_WRITE: {
- struct bcm_wrm_buffer sWrmBuffer = {0};
- UINT uiTempVar = 0;
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE)) {
+ /* Copy Ioctl Buffer structure */
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "Device in Idle Mode, Blocking Wrms\n");
- return -EACCES;
- }
+ if (IoBuffer.InputLength > sizeof(sWrmBuffer))
+ return -EINVAL;
- /* Copy Ioctl Buffer structure */
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ /* Get WrmBuffer structure */
+ if (copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer,
+ IoBuffer.InputLength))
+ return -EFAULT;
- if (IoBuffer.InputLength > sizeof(sWrmBuffer))
- return -EINVAL;
+ if ((((ULONG)sWrmBuffer.Register & 0x0F000000) != 0x0F000000) ||
+ ((ULONG)sWrmBuffer.Register & 0x3)) {
- /* Get WrmBuffer structure */
- if (copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
- return -EFAULT;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "WRM Done On invalid Address : %x Access Denied.\n",
+ (int)sWrmBuffer.Register);
+ return -EINVAL;
+ }
- if ((((ULONG)sWrmBuffer.Register & 0x0F000000) != 0x0F000000) ||
- ((ULONG)sWrmBuffer.Register & 0x3)) {
+ uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK;
+ if (!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) &&
+ ((uiTempVar == EEPROM_REJECT_REG_1) ||
+ (uiTempVar == EEPROM_REJECT_REG_2) ||
+ (uiTempVar == EEPROM_REJECT_REG_3) ||
+ (uiTempVar == EEPROM_REJECT_REG_4)) &&
+ (cmd == IOCTL_BCM_REGISTER_WRITE)) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "WRM Done On invalid Address : %x Access Denied.\n",
- (int)sWrmBuffer.Register);
- return -EINVAL;
- }
-
- uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK;
- if (!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) &&
- ((uiTempVar == EEPROM_REJECT_REG_1) ||
- (uiTempVar == EEPROM_REJECT_REG_2) ||
- (uiTempVar == EEPROM_REJECT_REG_3) ||
- (uiTempVar == EEPROM_REJECT_REG_4)) &&
- (cmd == IOCTL_BCM_REGISTER_WRITE)) {
-
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "EEPROM Access Denied, not in VSG Mode\n");
- return -EFAULT;
- }
+ "EEPROM Access Denied, not in VSG Mode\n");
+ return -EFAULT;
+ }
- Status = wrmaltWithLock(Adapter, (UINT)sWrmBuffer.Register,
- (PUINT)sWrmBuffer.Data,
- sWrmBuffer.Length);
+ Status = wrmaltWithLock(Adapter, (UINT)sWrmBuffer.Register,
+ (PUINT)sWrmBuffer.Data,
+ sWrmBuffer.Length);
- if (Status == STATUS_SUCCESS) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, OSAL_DBG,
- DBG_LVL_ALL, "WRM Done\n");
- } else {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
- DBG_LVL_ALL, "WRM Failed\n");
- Status = -EFAULT;
- }
- break;
+ if (Status == STATUS_SUCCESS) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, OSAL_DBG,
+ DBG_LVL_ALL, "WRM Done\n");
+ } else {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL, "WRM Failed\n");
+ Status = -EFAULT;
}
- case IOCTL_BCM_GPIO_SET_REQUEST: {
- UCHAR ucResetValue[4];
- UINT value = 0;
- UINT uiBit = 0;
- UINT uiOperation = 0;
- struct bcm_gpio_info gpio_info = {0};
-
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE)) {
+ return Status;
+}
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
- DBG_LVL_ALL,
- "GPIO Can't be set/clear in Low power Mode");
- return -EACCES;
- }
+static int bcm_char_ioctl_gpio_set_request(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_gpio_info gpio_info = {0};
+ struct bcm_ioctl_buffer IoBuffer;
+ UCHAR ucResetValue[4];
+ UINT value = 0;
+ UINT uiBit = 0;
+ UINT uiOperation = 0;
+ INT Status;
+ int bytes;
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE)) {
- if (IoBuffer.InputLength > sizeof(gpio_info))
- return -EINVAL;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL,
+ "GPIO Can't be set/clear in Low power Mode");
+ return -EACCES;
+ }
- if (copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
- return -EFAULT;
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- uiBit = gpio_info.uiGpioNumber;
- uiOperation = gpio_info.uiGpioValue;
- value = (1<<uiBit);
+ if (IoBuffer.InputLength > sizeof(gpio_info))
+ return -EINVAL;
- if (IsReqGpioIsLedInNVM(Adapter, value) == false) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
- DBG_LVL_ALL,
- "Sorry, Requested GPIO<0x%X> is not correspond to LED !!!",
- value);
- Status = -EINVAL;
- break;
- }
+ if (copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
+ return -EFAULT;
- /* Set - setting 1 */
- if (uiOperation) {
- /* Set the gpio output register */
- Status = wrmaltWithLock(Adapter,
- BCM_GPIO_OUTPUT_SET_REG,
- (PUINT)(&value), sizeof(UINT));
+ uiBit = gpio_info.uiGpioNumber;
+ uiOperation = gpio_info.uiGpioValue;
+ value = (1<<uiBit);
- if (Status == STATUS_SUCCESS) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
- OSAL_DBG, DBG_LVL_ALL,
- "Set the GPIO bit\n");
- } else {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
- OSAL_DBG, DBG_LVL_ALL,
- "Failed to set the %dth GPIO\n",
- uiBit);
- break;
- }
- } else {
- /* Set the gpio output register */
- Status = wrmaltWithLock(Adapter,
- BCM_GPIO_OUTPUT_CLR_REG,
- (PUINT)(&value), sizeof(UINT));
+ if (IsReqGpioIsLedInNVM(Adapter, value) == false) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL,
+ "Sorry, Requested GPIO<0x%X> is not correspond to LED !!!",
+ value);
+ return -EINVAL;
+ }
- if (Status == STATUS_SUCCESS) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
- OSAL_DBG, DBG_LVL_ALL,
- "Set the GPIO bit\n");
- } else {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
- OSAL_DBG, DBG_LVL_ALL,
- "Failed to clear the %dth GPIO\n",
- uiBit);
- break;
- }
- }
+ /* Set - setting 1 */
+ if (uiOperation) {
+ /* Set the gpio output register */
+ Status = wrmaltWithLock(Adapter,
+ BCM_GPIO_OUTPUT_SET_REG,
+ (PUINT)(&value), sizeof(UINT));
- bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER,
- (PUINT)ucResetValue, sizeof(UINT));
- if (bytes < 0) {
- Status = bytes;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
- "GPIO_MODE_REGISTER read failed");
- break;
+ if (Status == STATUS_SUCCESS) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
+ OSAL_DBG, DBG_LVL_ALL,
+ "Set the GPIO bit\n");
} else {
- Status = STATUS_SUCCESS;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
+ OSAL_DBG, DBG_LVL_ALL,
+ "Failed to set the %dth GPIO\n",
+ uiBit);
+ return Status;
}
-
- /* Set the gpio mode register to output */
- *(UINT *)ucResetValue |= (1<<uiBit);
- Status = wrmaltWithLock(Adapter, GPIO_MODE_REGISTER,
- (PUINT)ucResetValue, sizeof(UINT));
+ } else {
+ /* Set the gpio output register */
+ Status = wrmaltWithLock(Adapter,
+ BCM_GPIO_OUTPUT_CLR_REG,
+ (PUINT)(&value), sizeof(UINT));
if (Status == STATUS_SUCCESS) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
- DBG_LVL_ALL,
- "Set the GPIO to output Mode\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
+ OSAL_DBG, DBG_LVL_ALL,
+ "Set the GPIO bit\n");
} else {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
- DBG_LVL_ALL,
- "Failed to put GPIO in Output Mode\n");
- break;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
+ OSAL_DBG, DBG_LVL_ALL,
+ "Failed to clear the %dth GPIO\n",
+ uiBit);
+ return Status;
}
}
- break;
- case BCM_LED_THREAD_STATE_CHANGE_REQ: {
- struct bcm_user_thread_req threadReq = {0};
+ bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER,
+ (PUINT)ucResetValue, sizeof(UINT));
+ if (bytes < 0) {
+ Status = bytes;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
- "User made LED thread InActive");
+ "GPIO_MODE_REGISTER read failed");
+ return Status;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE)) {
+ /* Set the gpio mode register to output */
+ *(UINT *)ucResetValue |= (1<<uiBit);
+ Status = wrmaltWithLock(Adapter, GPIO_MODE_REGISTER,
+ (PUINT)ucResetValue, sizeof(UINT));
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
- DBG_LVL_ALL,
- "GPIO Can't be set/clear in Low power Mode");
- Status = -EACCES;
- break;
- }
+ if (Status == STATUS_SUCCESS) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL,
+ "Set the GPIO to output Mode\n");
+ } else {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL,
+ "Failed to put GPIO in Output Mode\n");
+ }
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ return Status;
+}
- if (IoBuffer.InputLength > sizeof(threadReq))
- return -EINVAL;
+static int bcm_char_ioctl_led_thread_state_change_req(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_user_thread_req threadReq = {0};
+ struct bcm_ioctl_buffer IoBuffer;
- if (copy_from_user(&threadReq, IoBuffer.InputBuffer, IoBuffer.InputLength))
- return -EFAULT;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "User made LED thread InActive");
- /* if LED thread is running(Actively or Inactively) set it state to make inactive */
- if (Adapter->LEDInfo.led_thread_running) {
- if (threadReq.ThreadState == LED_THREAD_ACTIVATION_REQ) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
- OSAL_DBG, DBG_LVL_ALL,
- "Activating thread req");
- Adapter->DriverState = LED_THREAD_ACTIVE;
- } else {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
- OSAL_DBG, DBG_LVL_ALL,
- "DeActivating Thread req.....");
- Adapter->DriverState = LED_THREAD_INACTIVE;
- }
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE)) {
- /* signal thread. */
- wake_up(&Adapter->LEDInfo.notify_led_event);
- }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL,
+ "GPIO Can't be set/clear in Low power Mode");
+ return -EACCES;
}
- break;
-
- case IOCTL_BCM_GPIO_STATUS_REQUEST: {
- ULONG uiBit = 0;
- UCHAR ucRead[4];
- struct bcm_gpio_info gpio_info = {0};
-
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE))
- return -EACCES;
-
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
- if (IoBuffer.InputLength > sizeof(gpio_info))
- return -EINVAL;
-
- if (copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
- return -EFAULT;
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- uiBit = gpio_info.uiGpioNumber;
+ if (IoBuffer.InputLength > sizeof(threadReq))
+ return -EINVAL;
- /* Set the gpio output register */
- bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER,
- (PUINT)ucRead, sizeof(UINT));
+ if (copy_from_user(&threadReq, IoBuffer.InputBuffer, IoBuffer.InputLength))
+ return -EFAULT;
- if (bytes < 0) {
- Status = bytes;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "RDM Failed\n");
- return Status;
+ /* if LED thread is running(Actively or Inactively)
+ * set it state to make inactive
+ */
+ if (Adapter->LEDInfo.led_thread_running) {
+ if (threadReq.ThreadState == LED_THREAD_ACTIVATION_REQ) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
+ OSAL_DBG, DBG_LVL_ALL,
+ "Activating thread req");
+ Adapter->DriverState = LED_THREAD_ACTIVE;
} else {
- Status = STATUS_SUCCESS;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
+ OSAL_DBG, DBG_LVL_ALL,
+ "DeActivating Thread req.....");
+ Adapter->DriverState = LED_THREAD_INACTIVE;
}
+
+ /* signal thread. */
+ wake_up(&Adapter->LEDInfo.notify_led_event);
}
- break;
+ return STATUS_SUCCESS;
+}
- case IOCTL_BCM_GPIO_MULTI_REQUEST: {
- UCHAR ucResetValue[4];
- struct bcm_gpio_multi_info gpio_multi_info[MAX_IDX];
- struct bcm_gpio_multi_info *pgpio_multi_info = (struct bcm_gpio_multi_info *)gpio_multi_info;
+static int bcm_char_ioctl_gpio_status_request(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_gpio_info gpio_info = {0};
+ struct bcm_ioctl_buffer IoBuffer;
+ ULONG uiBit = 0;
+ UCHAR ucRead[4];
+ INT Status;
+ int bytes;
- memset(pgpio_multi_info, 0, MAX_IDX * sizeof(struct bcm_gpio_multi_info));
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE))
+ return -EACCES;
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE))
- return -EINVAL;
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ if (IoBuffer.InputLength > sizeof(gpio_info))
+ return -EINVAL;
- if (IoBuffer.InputLength > sizeof(gpio_multi_info))
- return -EINVAL;
+ if (copy_from_user(&gpio_info, IoBuffer.InputBuffer,
+ IoBuffer.InputLength))
+ return -EFAULT;
- if (copy_from_user(&gpio_multi_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
- return -EFAULT;
+ uiBit = gpio_info.uiGpioNumber;
- if (IsReqGpioIsLedInNVM(Adapter, pgpio_multi_info[WIMAX_IDX].uiGPIOMask) == false) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
- DBG_LVL_ALL,
- "Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!",
- pgpio_multi_info[WIMAX_IDX].uiGPIOMask,
- Adapter->gpioBitMap);
- Status = -EINVAL;
- break;
- }
+ /* Set the gpio output register */
+ bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER,
+ (PUINT)ucRead, sizeof(UINT));
- /* Set the gpio output register */
- if ((pgpio_multi_info[WIMAX_IDX].uiGPIOMask) &
- (pgpio_multi_info[WIMAX_IDX].uiGPIOCommand)) {
- /* Set 1's in GPIO OUTPUT REGISTER */
- *(UINT *)ucResetValue = pgpio_multi_info[WIMAX_IDX].uiGPIOMask &
- pgpio_multi_info[WIMAX_IDX].uiGPIOCommand &
- pgpio_multi_info[WIMAX_IDX].uiGPIOValue;
+ if (bytes < 0) {
+ Status = bytes;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "RDM Failed\n");
+ return Status;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+ return Status;
+}
+
+static int bcm_char_ioctl_gpio_multi_request(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_gpio_multi_info gpio_multi_info[MAX_IDX];
+ struct bcm_gpio_multi_info *pgpio_multi_info =
+ (struct bcm_gpio_multi_info *)gpio_multi_info;
+ struct bcm_ioctl_buffer IoBuffer;
+ UCHAR ucResetValue[4];
+ INT Status = STATUS_FAILURE;
+ int bytes;
- if (*(UINT *) ucResetValue)
- Status = wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_SET_REG,
- (PUINT)ucResetValue, sizeof(ULONG));
+ memset(pgpio_multi_info, 0, MAX_IDX * sizeof(struct bcm_gpio_multi_info));
- if (Status != STATUS_SUCCESS) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "WRM to BCM_GPIO_OUTPUT_SET_REG Failed.");
- return Status;
- }
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE))
+ return -EINVAL;
- /* Clear to 0's in GPIO OUTPUT REGISTER */
- *(UINT *)ucResetValue = (pgpio_multi_info[WIMAX_IDX].uiGPIOMask &
- pgpio_multi_info[WIMAX_IDX].uiGPIOCommand &
- (~(pgpio_multi_info[WIMAX_IDX].uiGPIOValue)));
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- if (*(UINT *) ucResetValue)
- Status = wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_CLR_REG, (PUINT)ucResetValue, sizeof(ULONG));
+ if (IoBuffer.InputLength > sizeof(gpio_multi_info))
+ return -EINVAL;
+ if (IoBuffer.OutputLength > sizeof(gpio_multi_info))
+ IoBuffer.OutputLength = sizeof(gpio_multi_info);
- if (Status != STATUS_SUCCESS) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "WRM to BCM_GPIO_OUTPUT_CLR_REG Failed.");
- return Status;
- }
- }
+ if (copy_from_user(&gpio_multi_info, IoBuffer.InputBuffer,
+ IoBuffer.InputLength))
+ return -EFAULT;
- if (pgpio_multi_info[WIMAX_IDX].uiGPIOMask) {
- bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER, (PUINT)ucResetValue, sizeof(UINT));
+ if (IsReqGpioIsLedInNVM(Adapter,
+ pgpio_multi_info[WIMAX_IDX].uiGPIOMask) == false) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL,
+ "Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!",
+ pgpio_multi_info[WIMAX_IDX].uiGPIOMask,
+ Adapter->gpioBitMap);
+ return -EINVAL;
+ }
- if (bytes < 0) {
- Status = bytes;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "RDM to GPIO_PIN_STATE_REGISTER Failed.");
- return Status;
- } else {
- Status = STATUS_SUCCESS;
- }
+ /* Set the gpio output register */
+ if ((pgpio_multi_info[WIMAX_IDX].uiGPIOMask) &
+ (pgpio_multi_info[WIMAX_IDX].uiGPIOCommand)) {
+ /* Set 1's in GPIO OUTPUT REGISTER */
+ *(UINT *)ucResetValue = pgpio_multi_info[WIMAX_IDX].uiGPIOMask &
+ pgpio_multi_info[WIMAX_IDX].uiGPIOCommand &
+ pgpio_multi_info[WIMAX_IDX].uiGPIOValue;
- pgpio_multi_info[WIMAX_IDX].uiGPIOValue = (*(UINT *)ucResetValue &
- pgpio_multi_info[WIMAX_IDX].uiGPIOMask);
- }
+ if (*(UINT *) ucResetValue)
+ Status = wrmaltWithLock(Adapter,
+ BCM_GPIO_OUTPUT_SET_REG,
+ (PUINT)ucResetValue, sizeof(ULONG));
- Status = copy_to_user(IoBuffer.OutputBuffer, &gpio_multi_info, IoBuffer.OutputLength);
- if (Status) {
+ if (Status != STATUS_SUCCESS) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "Failed while copying Content to IOBufer for user space err:%d", Status);
- return -EFAULT;
+ "WRM to BCM_GPIO_OUTPUT_SET_REG Failed.");
+ return Status;
}
- }
- break;
-
- case IOCTL_BCM_GPIO_MODE_REQUEST: {
- UCHAR ucResetValue[4];
- struct bcm_gpio_multi_mode gpio_multi_mode[MAX_IDX];
- struct bcm_gpio_multi_mode *pgpio_multi_mode = (struct bcm_gpio_multi_mode *)gpio_multi_mode;
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE))
- return -EINVAL;
-
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ /* Clear to 0's in GPIO OUTPUT REGISTER */
+ *(UINT *)ucResetValue = (pgpio_multi_info[WIMAX_IDX].uiGPIOMask &
+ pgpio_multi_info[WIMAX_IDX].uiGPIOCommand &
+ (~(pgpio_multi_info[WIMAX_IDX].uiGPIOValue)));
- if (IoBuffer.InputLength > sizeof(gpio_multi_mode))
- return -EINVAL;
+ if (*(UINT *) ucResetValue)
+ Status = wrmaltWithLock(Adapter,
+ BCM_GPIO_OUTPUT_CLR_REG, (PUINT)ucResetValue,
+ sizeof(ULONG));
- if (copy_from_user(&gpio_multi_mode, IoBuffer.InputBuffer, IoBuffer.InputLength))
- return -EFAULT;
+ if (Status != STATUS_SUCCESS) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "WRM to BCM_GPIO_OUTPUT_CLR_REG Failed.");
+ return Status;
+ }
+ }
- bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER, (PUINT)ucResetValue, sizeof(UINT));
+ if (pgpio_multi_info[WIMAX_IDX].uiGPIOMask) {
+ bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER,
+ (PUINT)ucResetValue, sizeof(UINT));
if (bytes < 0) {
Status = bytes;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Read of GPIO_MODE_REGISTER failed");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "RDM to GPIO_PIN_STATE_REGISTER Failed.");
return Status;
} else {
Status = STATUS_SUCCESS;
}
- /* Validating the request */
- if (IsReqGpioIsLedInNVM(Adapter, pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) == false) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
- "Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!",
- pgpio_multi_mode[WIMAX_IDX].uiGPIOMask, Adapter->gpioBitMap);
- Status = -EINVAL;
- break;
- }
+ pgpio_multi_info[WIMAX_IDX].uiGPIOValue = (*(UINT *)ucResetValue &
+ pgpio_multi_info[WIMAX_IDX].uiGPIOMask);
+ }
- if (pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) {
- /* write all OUT's (1's) */
- *(UINT *) ucResetValue |= (pgpio_multi_mode[WIMAX_IDX].uiGPIOMode &
- pgpio_multi_mode[WIMAX_IDX].uiGPIOMask);
+ Status = copy_to_user(IoBuffer.OutputBuffer, &gpio_multi_info,
+ IoBuffer.OutputLength);
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Failed while copying Content to IOBufer for user space err:%d",
+ Status);
+ return -EFAULT;
+ }
+ return Status;
+}
- /* write all IN's (0's) */
- *(UINT *) ucResetValue &= ~((~pgpio_multi_mode[WIMAX_IDX].uiGPIOMode) &
- pgpio_multi_mode[WIMAX_IDX].uiGPIOMask);
+static int bcm_char_ioctl_gpio_mode_request(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_gpio_multi_mode gpio_multi_mode[MAX_IDX];
+ struct bcm_gpio_multi_mode *pgpio_multi_mode =
+ (struct bcm_gpio_multi_mode *)gpio_multi_mode;
+ struct bcm_ioctl_buffer IoBuffer;
+ UCHAR ucResetValue[4];
+ INT Status;
+ int bytes;
- /* Currently implemented return the modes of all GPIO's
- * else needs to bit AND with mask
- */
- pgpio_multi_mode[WIMAX_IDX].uiGPIOMode = *(UINT *)ucResetValue;
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE))
+ return -EINVAL;
- Status = wrmaltWithLock(Adapter, GPIO_MODE_REGISTER, (PUINT)ucResetValue, sizeof(ULONG));
- if (Status == STATUS_SUCCESS) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
- "WRM to GPIO_MODE_REGISTER Done");
- } else {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "WRM to GPIO_MODE_REGISTER Failed");
- Status = -EFAULT;
- break;
- }
- } else {
-/* if uiGPIOMask is 0 then return mode register configuration */
- pgpio_multi_mode[WIMAX_IDX].uiGPIOMode = *(UINT *)ucResetValue;
- }
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- Status = copy_to_user(IoBuffer.OutputBuffer, &gpio_multi_mode, IoBuffer.OutputLength);
- if (Status) {
+ if (IoBuffer.InputLength > sizeof(gpio_multi_mode))
+ return -EINVAL;
+ if (IoBuffer.OutputLength > sizeof(gpio_multi_mode))
+ IoBuffer.OutputLength = sizeof(gpio_multi_mode);
+
+ if (copy_from_user(&gpio_multi_mode, IoBuffer.InputBuffer,
+ IoBuffer.InputLength))
+ return -EFAULT;
+
+ bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER,
+ (PUINT)ucResetValue, sizeof(UINT));
+
+ if (bytes < 0) {
+ Status = bytes;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Read of GPIO_MODE_REGISTER failed");
+ return Status;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+
+ /* Validating the request */
+ if (IsReqGpioIsLedInNVM(Adapter,
+ pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) == false) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!",
+ pgpio_multi_mode[WIMAX_IDX].uiGPIOMask,
+ Adapter->gpioBitMap);
+ return -EINVAL;
+ }
+
+ if (pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) {
+ /* write all OUT's (1's) */
+ *(UINT *) ucResetValue |= (pgpio_multi_mode[WIMAX_IDX].uiGPIOMode &
+ pgpio_multi_mode[WIMAX_IDX].uiGPIOMask);
+
+ /* write all IN's (0's) */
+ *(UINT *) ucResetValue &= ~((~pgpio_multi_mode[WIMAX_IDX].uiGPIOMode) &
+ pgpio_multi_mode[WIMAX_IDX].uiGPIOMask);
+
+ /* Currently implemented return the modes of all GPIO's
+ * else needs to bit AND with mask
+ */
+ pgpio_multi_mode[WIMAX_IDX].uiGPIOMode = *(UINT *)ucResetValue;
+
+ Status = wrmaltWithLock(Adapter, GPIO_MODE_REGISTER,
+ (PUINT)ucResetValue, sizeof(ULONG));
+ if (Status == STATUS_SUCCESS) {
+ BCM_DEBUG_PRINT(Adapter,
+ DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "WRM to GPIO_MODE_REGISTER Done");
+ } else {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "Failed while copying Content to IOBufer for user space err:%d", Status);
+ "WRM to GPIO_MODE_REGISTER Failed");
return -EFAULT;
}
+ } else {
+ /* if uiGPIOMask is 0 then return mode register configuration */
+ pgpio_multi_mode[WIMAX_IDX].uiGPIOMode = *(UINT *)ucResetValue;
}
- break;
- case IOCTL_MAC_ADDR_REQ:
- case IOCTL_LINK_REQ:
- case IOCTL_CM_REQUEST:
- case IOCTL_SS_INFO_REQ:
- case IOCTL_SEND_CONTROL_MESSAGE:
- case IOCTL_IDLE_REQ: {
- PVOID pvBuffer = NULL;
+ Status = copy_to_user(IoBuffer.OutputBuffer, &gpio_multi_mode,
+ IoBuffer.OutputLength);
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Failed while copying Content to IOBufer for user space err:%d",
+ Status);
+ return -EFAULT;
+ }
+ return Status;
+}
- /* Copy Ioctl Buffer structure */
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+static int bcm_char_ioctl_misc_request(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_ioctl_buffer IoBuffer;
+ PVOID pvBuffer = NULL;
+ INT Status;
- if (IoBuffer.InputLength < sizeof(struct bcm_link_request))
- return -EINVAL;
+ /* Copy Ioctl Buffer structure */
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- if (IoBuffer.InputLength > MAX_CNTL_PKT_SIZE)
- return -EINVAL;
+ if (IoBuffer.InputLength < sizeof(struct bcm_link_request))
+ return -EINVAL;
- pvBuffer = memdup_user(IoBuffer.InputBuffer,
- IoBuffer.InputLength);
- if (IS_ERR(pvBuffer))
- return PTR_ERR(pvBuffer);
-
- down(&Adapter->LowPowerModeSync);
- Status = wait_event_interruptible_timeout(Adapter->lowpower_mode_wait_queue,
- !Adapter->bPreparingForLowPowerMode,
- (1 * HZ));
- if (Status == -ERESTARTSYS)
- goto cntrlEnd;
-
- if (Adapter->bPreparingForLowPowerMode) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
- "Preparing Idle Mode is still True - Hence Rejecting control message\n");
- Status = STATUS_FAILURE;
- goto cntrlEnd;
- }
- Status = CopyBufferToControlPacket(Adapter, (PVOID)pvBuffer);
+ if (IoBuffer.InputLength > MAX_CNTL_PKT_SIZE)
+ return -EINVAL;
-cntrlEnd:
- up(&Adapter->LowPowerModeSync);
- kfree(pvBuffer);
- break;
+ pvBuffer = memdup_user(IoBuffer.InputBuffer,
+ IoBuffer.InputLength);
+ if (IS_ERR(pvBuffer))
+ return PTR_ERR(pvBuffer);
+
+ down(&Adapter->LowPowerModeSync);
+ Status = wait_event_interruptible_timeout(Adapter->lowpower_mode_wait_queue,
+ !Adapter->bPreparingForLowPowerMode,
+ (1 * HZ));
+ if (Status == -ERESTARTSYS)
+ goto cntrlEnd;
+
+ if (Adapter->bPreparingForLowPowerMode) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Preparing Idle Mode is still True - Hence Rejecting control message\n");
+ Status = STATUS_FAILURE;
+ goto cntrlEnd;
}
+ Status = CopyBufferToControlPacket(Adapter, (PVOID)pvBuffer);
- case IOCTL_BCM_BUFFER_DOWNLOAD_START: {
- if (down_trylock(&Adapter->NVMRdmWrmLock)) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
- "IOCTL_BCM_CHIP_RESET not allowed as EEPROM Read/Write is in progress\n");
- return -EACCES;
- }
+cntrlEnd:
+ up(&Adapter->LowPowerModeSync);
+ kfree(pvBuffer);
+ return Status;
+}
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "Starting the firmware download PID =0x%x!!!!\n", current->pid);
-
- if (down_trylock(&Adapter->fw_download_sema))
- return -EBUSY;
-
- Adapter->bBinDownloaded = false;
- Adapter->fw_download_process_pid = current->pid;
- Adapter->bCfgDownloaded = false;
- Adapter->fw_download_done = false;
- netif_carrier_off(Adapter->dev);
- netif_stop_queue(Adapter->dev);
- Status = reset_card_proc(Adapter);
- if (Status) {
- pr_err(PFX "%s: reset_card_proc Failed!\n", Adapter->dev->name);
- up(&Adapter->fw_download_sema);
- up(&Adapter->NVMRdmWrmLock);
- return Status;
- }
- mdelay(10);
+static int bcm_char_ioctl_buffer_download_start(
+ struct bcm_mini_adapter *Adapter)
+{
+ INT Status;
+ if (down_trylock(&Adapter->NVMRdmWrmLock)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "IOCTL_BCM_CHIP_RESET not allowed as EEPROM Read/Write is in progress\n");
+ return -EACCES;
+ }
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Starting the firmware download PID =0x%x!!!!\n", current->pid);
+
+ if (down_trylock(&Adapter->fw_download_sema))
+ return -EBUSY;
+
+ Adapter->bBinDownloaded = false;
+ Adapter->fw_download_process_pid = current->pid;
+ Adapter->bCfgDownloaded = false;
+ Adapter->fw_download_done = false;
+ netif_carrier_off(Adapter->dev);
+ netif_stop_queue(Adapter->dev);
+ Status = reset_card_proc(Adapter);
+ if (Status) {
+ pr_err(PFX "%s: reset_card_proc Failed!\n", Adapter->dev->name);
+ up(&Adapter->fw_download_sema);
up(&Adapter->NVMRdmWrmLock);
return Status;
}
+ mdelay(10);
- case IOCTL_BCM_BUFFER_DOWNLOAD: {
- struct bcm_firmware_info *psFwInfo = NULL;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Starting the firmware download PID =0x%x!!!!\n", current->pid);
+ up(&Adapter->NVMRdmWrmLock);
+ return Status;
+}
- if (!down_trylock(&Adapter->fw_download_sema)) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "Invalid way to download buffer. Use Start and then call this!!!\n");
- up(&Adapter->fw_download_sema);
- Status = -EINVAL;
- return Status;
- }
+static int bcm_char_ioctl_buffer_download(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_firmware_info *psFwInfo = NULL;
+ struct bcm_ioctl_buffer IoBuffer;
+ INT Status;
- /* Copy Ioctl Buffer structure */
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) {
- up(&Adapter->fw_download_sema);
- return -EFAULT;
- }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Starting the firmware download PID =0x%x!!!!\n", current->pid);
+ if (!down_trylock(&Adapter->fw_download_sema)) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "Length for FW DLD is : %lx\n", IoBuffer.InputLength);
-
- if (IoBuffer.InputLength > sizeof(struct bcm_firmware_info)) {
- up(&Adapter->fw_download_sema);
- return -EINVAL;
- }
-
- psFwInfo = kmalloc(sizeof(*psFwInfo), GFP_KERNEL);
- if (!psFwInfo) {
- up(&Adapter->fw_download_sema);
- return -ENOMEM;
- }
-
- if (copy_from_user(psFwInfo, IoBuffer.InputBuffer, IoBuffer.InputLength)) {
- up(&Adapter->fw_download_sema);
- kfree(psFwInfo);
- return -EFAULT;
- }
-
- if (!psFwInfo->pvMappedFirmwareAddress ||
- (psFwInfo->u32FirmwareLength == 0)) {
+ "Invalid way to download buffer. Use Start and then call this!!!\n");
+ up(&Adapter->fw_download_sema);
+ return -EINVAL;
+ }
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Something else is wrong %lu\n",
- psFwInfo->u32FirmwareLength);
- up(&Adapter->fw_download_sema);
- kfree(psFwInfo);
- Status = -EINVAL;
- return Status;
- }
+ /* Copy Ioctl Buffer structure */
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) {
+ up(&Adapter->fw_download_sema);
+ return -EFAULT;
+ }
- Status = bcm_ioctl_fw_download(Adapter, psFwInfo);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Length for FW DLD is : %lx\n", IoBuffer.InputLength);
- if (Status != STATUS_SUCCESS) {
- if (psFwInfo->u32StartingAddress == CONFIG_BEGIN_ADDR)
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL: Configuration File Upload Failed\n");
- else
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL: Firmware File Upload Failed\n");
+ if (IoBuffer.InputLength > sizeof(struct bcm_firmware_info)) {
+ up(&Adapter->fw_download_sema);
+ return -EINVAL;
+ }
- /* up(&Adapter->fw_download_sema); */
+ psFwInfo = kmalloc(sizeof(*psFwInfo), GFP_KERNEL);
+ if (!psFwInfo) {
+ up(&Adapter->fw_download_sema);
+ return -ENOMEM;
+ }
- if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) {
- Adapter->DriverState = DRIVER_INIT;
- Adapter->LEDInfo.bLedInitDone = false;
- wake_up(&Adapter->LEDInfo.notify_led_event);
- }
- }
+ if (copy_from_user(psFwInfo, IoBuffer.InputBuffer,
+ IoBuffer.InputLength)) {
+ up(&Adapter->fw_download_sema);
+ kfree(psFwInfo);
+ return -EFAULT;
+ }
- if (Status != STATUS_SUCCESS)
- up(&Adapter->fw_download_sema);
+ if (!psFwInfo->pvMappedFirmwareAddress ||
+ (psFwInfo->u32FirmwareLength == 0)) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, OSAL_DBG, DBG_LVL_ALL, "IOCTL: Firmware File Uploaded\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Something else is wrong %lu\n",
+ psFwInfo->u32FirmwareLength);
+ up(&Adapter->fw_download_sema);
kfree(psFwInfo);
+ Status = -EINVAL;
return Status;
}
- case IOCTL_BCM_BUFFER_DOWNLOAD_STOP: {
- if (!down_trylock(&Adapter->fw_download_sema)) {
- up(&Adapter->fw_download_sema);
- return -EINVAL;
- }
+ Status = bcm_ioctl_fw_download(Adapter, psFwInfo);
- if (down_trylock(&Adapter->NVMRdmWrmLock)) {
+ if (Status != STATUS_SUCCESS) {
+ if (psFwInfo->u32StartingAddress == CONFIG_BEGIN_ADDR)
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "FW download blocked as EEPROM Read/Write is in progress\n");
- up(&Adapter->fw_download_sema);
- return -EACCES;
- }
-
- Adapter->bBinDownloaded = TRUE;
- Adapter->bCfgDownloaded = TRUE;
- atomic_set(&Adapter->CurrNumFreeTxDesc, 0);
- Adapter->CurrNumRecvDescs = 0;
- Adapter->downloadDDR = 0;
-
- /* setting the Mips to Run */
- Status = run_card_proc(Adapter);
+ "IOCTL: Configuration File Upload Failed\n");
+ else
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "IOCTL: Firmware File Upload Failed\n");
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Firm Download Failed\n");
- up(&Adapter->fw_download_sema);
- up(&Adapter->NVMRdmWrmLock);
- return Status;
- } else {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
- DBG_LVL_ALL, "Firm Download Over...\n");
- }
+ /* up(&Adapter->fw_download_sema); */
- mdelay(10);
-
- /* Wait for MailBox Interrupt */
- if (StartInterruptUrb((struct bcm_interface_adapter *)Adapter->pvInterfaceAdapter))
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Unable to send interrupt...\n");
-
- timeout = 5*HZ;
- Adapter->waiting_to_fw_download_done = false;
- wait_event_timeout(Adapter->ioctl_fw_dnld_wait_queue,
- Adapter->waiting_to_fw_download_done, timeout);
- Adapter->fw_download_process_pid = INVALID_PID;
- Adapter->fw_download_done = TRUE;
- atomic_set(&Adapter->CurrNumFreeTxDesc, 0);
- Adapter->CurrNumRecvDescs = 0;
- Adapter->PrevNumRecvDescs = 0;
- atomic_set(&Adapter->cntrlpktCnt, 0);
- Adapter->LinkUpStatus = 0;
- Adapter->LinkStatus = 0;
-
- if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) {
- Adapter->DriverState = FW_DOWNLOAD_DONE;
+ if (Adapter->LEDInfo.led_thread_running &
+ BCM_LED_THREAD_RUNNING_ACTIVELY) {
+ Adapter->DriverState = DRIVER_INIT;
+ Adapter->LEDInfo.bLedInitDone = false;
wake_up(&Adapter->LEDInfo.notify_led_event);
}
+ }
+
+ if (Status != STATUS_SUCCESS)
+ up(&Adapter->fw_download_sema);
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, OSAL_DBG, DBG_LVL_ALL,
+ "IOCTL: Firmware File Uploaded\n");
+ kfree(psFwInfo);
+ return Status;
+}
- if (!timeout)
- Status = -ENODEV;
+static int bcm_char_ioctl_buffer_download_stop(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ INT Status;
+ int timeout = 0;
+ if (!down_trylock(&Adapter->fw_download_sema)) {
up(&Adapter->fw_download_sema);
- up(&Adapter->NVMRdmWrmLock);
- return Status;
+ return -EINVAL;
}
- case IOCTL_BE_BUCKET_SIZE:
- Status = 0;
- if (get_user(Adapter->BEBucketSize, (unsigned long __user *)arg))
- Status = -EFAULT;
- break;
+ if (down_trylock(&Adapter->NVMRdmWrmLock)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "FW download blocked as EEPROM Read/Write is in progress\n");
+ up(&Adapter->fw_download_sema);
+ return -EACCES;
+ }
- case IOCTL_RTPS_BUCKET_SIZE:
- Status = 0;
- if (get_user(Adapter->rtPSBucketSize, (unsigned long __user *)arg))
- Status = -EFAULT;
- break;
+ Adapter->bBinDownloaded = TRUE;
+ Adapter->bCfgDownloaded = TRUE;
+ atomic_set(&Adapter->CurrNumFreeTxDesc, 0);
+ Adapter->CurrNumRecvDescs = 0;
+ Adapter->downloadDDR = 0;
- case IOCTL_CHIP_RESET: {
- INT NVMAccess = down_trylock(&Adapter->NVMRdmWrmLock);
- if (NVMAccess) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, " IOCTL_BCM_CHIP_RESET not allowed as EEPROM Read/Write is in progress\n");
- return -EACCES;
- }
+ /* setting the Mips to Run */
+ Status = run_card_proc(Adapter);
- down(&Adapter->RxAppControlQueuelock);
- Status = reset_card_proc(Adapter);
- flushAllAppQ();
- up(&Adapter->RxAppControlQueuelock);
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Firm Download Failed\n");
+ up(&Adapter->fw_download_sema);
up(&Adapter->NVMRdmWrmLock);
- ResetCounters(Adapter);
- break;
+ return Status;
+ } else {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL, "Firm Download Over...\n");
}
- case IOCTL_QOS_THRESHOLD: {
- USHORT uiLoopIndex;
+ mdelay(10);
- Status = 0;
- for (uiLoopIndex = 0; uiLoopIndex < NO_OF_QUEUES; uiLoopIndex++) {
- if (get_user(Adapter->PackInfo[uiLoopIndex].uiThreshold,
- (unsigned long __user *)arg)) {
- Status = -EFAULT;
- break;
- }
- }
- break;
+ /* Wait for MailBox Interrupt */
+ if (StartInterruptUrb((struct bcm_interface_adapter *)Adapter->pvInterfaceAdapter))
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Unable to send interrupt...\n");
+
+ timeout = 5*HZ;
+ Adapter->waiting_to_fw_download_done = false;
+ wait_event_timeout(Adapter->ioctl_fw_dnld_wait_queue,
+ Adapter->waiting_to_fw_download_done, timeout);
+ Adapter->fw_download_process_pid = INVALID_PID;
+ Adapter->fw_download_done = TRUE;
+ atomic_set(&Adapter->CurrNumFreeTxDesc, 0);
+ Adapter->CurrNumRecvDescs = 0;
+ Adapter->PrevNumRecvDescs = 0;
+ atomic_set(&Adapter->cntrlpktCnt, 0);
+ Adapter->LinkUpStatus = 0;
+ Adapter->LinkStatus = 0;
+
+ if (Adapter->LEDInfo.led_thread_running &
+ BCM_LED_THREAD_RUNNING_ACTIVELY) {
+ Adapter->DriverState = FW_DOWNLOAD_DONE;
+ wake_up(&Adapter->LEDInfo.notify_led_event);
}
- case IOCTL_DUMP_PACKET_INFO:
- DumpPackInfo(Adapter);
- DumpPhsRules(&Adapter->stBCMPhsContext);
- Status = STATUS_SUCCESS;
- break;
+ if (!timeout)
+ Status = -ENODEV;
- case IOCTL_GET_PACK_INFO:
- if (copy_to_user(argp, &Adapter->PackInfo, sizeof(struct bcm_packet_info)*NO_OF_QUEUES))
- return -EFAULT;
- Status = STATUS_SUCCESS;
- break;
+ up(&Adapter->fw_download_sema);
+ up(&Adapter->NVMRdmWrmLock);
+ return Status;
+}
- case IOCTL_BCM_SWITCH_TRANSFER_MODE: {
- UINT uiData = 0;
- if (copy_from_user(&uiData, argp, sizeof(UINT)))
- return -EFAULT;
+static int bcm_char_ioctl_chip_reset(struct bcm_mini_adapter *Adapter)
+{
+ INT Status;
+ INT NVMAccess;
- if (uiData) {
- /* Allow All Packets */
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SWITCH_TRANSFER_MODE: ETH_PACKET_TUNNELING_MODE\n");
- Adapter->TransferMode = ETH_PACKET_TUNNELING_MODE;
- } else {
- /* Allow IP only Packets */
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SWITCH_TRANSFER_MODE: IP_PACKET_ONLY_MODE\n");
- Adapter->TransferMode = IP_PACKET_ONLY_MODE;
- }
- Status = STATUS_SUCCESS;
- break;
+ NVMAccess = down_trylock(&Adapter->NVMRdmWrmLock);
+ if (NVMAccess) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ " IOCTL_BCM_CHIP_RESET not allowed as EEPROM Read/Write is in progress\n");
+ return -EACCES;
}
- case IOCTL_BCM_GET_DRIVER_VERSION: {
- ulong len;
-
- /* Copy Ioctl Buffer structure */
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ down(&Adapter->RxAppControlQueuelock);
+ Status = reset_card_proc(Adapter);
+ flushAllAppQ();
+ up(&Adapter->RxAppControlQueuelock);
+ up(&Adapter->NVMRdmWrmLock);
+ ResetCounters(Adapter);
+ return Status;
+}
- len = min_t(ulong, IoBuffer.OutputLength, strlen(DRV_VERSION) + 1);
+static int bcm_char_ioctl_qos_threshold(ULONG arg,
+ struct bcm_mini_adapter *Adapter)
+{
+ USHORT uiLoopIndex;
- if (copy_to_user(IoBuffer.OutputBuffer, DRV_VERSION, len))
+ for (uiLoopIndex = 0; uiLoopIndex < NO_OF_QUEUES; uiLoopIndex++) {
+ if (get_user(Adapter->PackInfo[uiLoopIndex].uiThreshold,
+ (unsigned long __user *)arg)) {
return -EFAULT;
- Status = STATUS_SUCCESS;
- break;
+ }
}
+ return 0;
+}
- case IOCTL_BCM_GET_CURRENT_STATUS: {
- struct bcm_link_state link_state;
+static int bcm_char_ioctl_switch_transfer_mode(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ UINT uiData = 0;
- /* Copy Ioctl Buffer structure */
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "copy_from_user failed..\n");
- return -EFAULT;
- }
+ if (copy_from_user(&uiData, argp, sizeof(UINT)))
+ return -EFAULT;
- if (IoBuffer.OutputLength != sizeof(link_state)) {
- Status = -EINVAL;
- break;
- }
+ if (uiData) {
+ /* Allow All Packets */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "IOCTL_BCM_SWITCH_TRANSFER_MODE: ETH_PACKET_TUNNELING_MODE\n");
+ Adapter->TransferMode = ETH_PACKET_TUNNELING_MODE;
+ } else {
+ /* Allow IP only Packets */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "IOCTL_BCM_SWITCH_TRANSFER_MODE: IP_PACKET_ONLY_MODE\n");
+ Adapter->TransferMode = IP_PACKET_ONLY_MODE;
+ }
+ return STATUS_SUCCESS;
+}
- memset(&link_state, 0, sizeof(link_state));
- link_state.bIdleMode = Adapter->IdleMode;
- link_state.bShutdownMode = Adapter->bShutStatus;
- link_state.ucLinkStatus = Adapter->LinkStatus;
+static int bcm_char_ioctl_get_driver_version(void __user *argp)
+{
+ struct bcm_ioctl_buffer IoBuffer;
+ ulong len;
- if (copy_to_user(IoBuffer.OutputBuffer, &link_state, min_t(size_t, sizeof(link_state), IoBuffer.OutputLength))) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy_to_user Failed..\n");
- return -EFAULT;
- }
- Status = STATUS_SUCCESS;
- break;
- }
+ /* Copy Ioctl Buffer structure */
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- case IOCTL_BCM_SET_MAC_TRACING: {
- UINT tracing_flag;
+ len = min_t(ulong, IoBuffer.OutputLength, strlen(DRV_VERSION) + 1);
- /* copy ioctl Buffer structure */
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ if (copy_to_user(IoBuffer.OutputBuffer, DRV_VERSION, len))
+ return -EFAULT;
- if (copy_from_user(&tracing_flag, IoBuffer.InputBuffer, sizeof(UINT)))
- return -EFAULT;
+ return STATUS_SUCCESS;
+}
- if (tracing_flag)
- Adapter->pTarangs->MacTracingEnabled = TRUE;
- else
- Adapter->pTarangs->MacTracingEnabled = false;
- break;
- }
+static int bcm_char_ioctl_get_current_status(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_link_state link_state;
+ struct bcm_ioctl_buffer IoBuffer;
- case IOCTL_BCM_GET_DSX_INDICATION: {
- ULONG ulSFId = 0;
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ /* Copy Ioctl Buffer structure */
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "copy_from_user failed..\n");
+ return -EFAULT;
+ }
- if (IoBuffer.OutputLength < sizeof(struct bcm_add_indication_alt)) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "Mismatch req: %lx needed is =0x%zx!!!",
- IoBuffer.OutputLength, sizeof(struct bcm_add_indication_alt));
- return -EINVAL;
- }
+ if (IoBuffer.OutputLength != sizeof(link_state))
+ return -EINVAL;
- if (copy_from_user(&ulSFId, IoBuffer.InputBuffer, sizeof(ulSFId)))
- return -EFAULT;
+ memset(&link_state, 0, sizeof(link_state));
+ link_state.bIdleMode = Adapter->IdleMode;
+ link_state.bShutdownMode = Adapter->bShutStatus;
+ link_state.ucLinkStatus = Adapter->LinkStatus;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Get DSX Data SF ID is =%lx\n", ulSFId);
- get_dsx_sf_data_to_application(Adapter, ulSFId, IoBuffer.OutputBuffer);
- Status = STATUS_SUCCESS;
+ if (copy_to_user(IoBuffer.OutputBuffer, &link_state, min_t(size_t,
+ sizeof(link_state), IoBuffer.OutputLength))) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Copy_to_user Failed..\n");
+ return -EFAULT;
}
- break;
+ return STATUS_SUCCESS;
+}
- case IOCTL_BCM_GET_HOST_MIBS: {
- PVOID temp_buff;
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+static int bcm_char_ioctl_set_mac_tracing(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_ioctl_buffer IoBuffer;
+ UINT tracing_flag;
- if (IoBuffer.OutputLength != sizeof(struct bcm_host_stats_mibs)) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
- "Length Check failed %lu %zd\n",
- IoBuffer.OutputLength, sizeof(struct bcm_host_stats_mibs));
- return -EINVAL;
- }
+ /* copy ioctl Buffer structure */
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- /* FIXME: HOST_STATS are too big for kmalloc (122048)! */
- temp_buff = kzalloc(sizeof(struct bcm_host_stats_mibs), GFP_KERNEL);
- if (!temp_buff)
- return STATUS_FAILURE;
+ if (copy_from_user(&tracing_flag, IoBuffer.InputBuffer, sizeof(UINT)))
+ return -EFAULT;
- Status = ProcessGetHostMibs(Adapter, temp_buff);
- GetDroppedAppCntrlPktMibs(temp_buff, pTarang);
+ if (tracing_flag)
+ Adapter->pTarangs->MacTracingEnabled = TRUE;
+ else
+ Adapter->pTarangs->MacTracingEnabled = false;
- if (Status != STATUS_FAILURE)
- if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, sizeof(struct bcm_host_stats_mibs))) {
- kfree(temp_buff);
- return -EFAULT;
- }
+ return STATUS_SUCCESS;
+}
- kfree(temp_buff);
- break;
+static int bcm_char_ioctl_get_dsx_indication(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_ioctl_buffer IoBuffer;
+ ULONG ulSFId = 0;
+
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
+
+ if (IoBuffer.OutputLength < sizeof(struct bcm_add_indication_alt)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Mismatch req: %lx needed is =0x%zx!!!",
+ IoBuffer.OutputLength,
+ sizeof(struct bcm_add_indication_alt));
+ return -EINVAL;
}
- case IOCTL_BCM_WAKE_UP_DEVICE_FROM_IDLE:
- if ((false == Adapter->bTriedToWakeUpFromlowPowerMode) && (TRUE == Adapter->IdleMode)) {
- Adapter->usIdleModePattern = ABORT_IDLE_MODE;
- Adapter->bWakeUpDevice = TRUE;
- wake_up(&Adapter->process_rx_cntrlpkt);
- }
+ if (copy_from_user(&ulSFId, IoBuffer.InputBuffer, sizeof(ulSFId)))
+ return -EFAULT;
- Status = STATUS_SUCCESS;
- break;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Get DSX Data SF ID is =%lx\n", ulSFId);
+ get_dsx_sf_data_to_application(Adapter, ulSFId, IoBuffer.OutputBuffer);
+ return STATUS_SUCCESS;
+}
- case IOCTL_BCM_BULK_WRM: {
- struct bcm_bulk_wrm_buffer *pBulkBuffer;
- UINT uiTempVar = 0;
- PCHAR pvBuffer = NULL;
+static int bcm_char_ioctl_get_host_mibs(void __user *argp,
+ struct bcm_mini_adapter *Adapter, struct bcm_tarang_data *pTarang)
+{
+ struct bcm_ioctl_buffer IoBuffer;
+ INT Status = STATUS_FAILURE;
+ PVOID temp_buff;
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE)) {
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "Device in Idle/Shutdown Mode, Blocking Wrms\n");
- Status = -EACCES;
- break;
- }
+ if (IoBuffer.OutputLength != sizeof(struct bcm_host_stats_mibs)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Length Check failed %lu %zd\n", IoBuffer.OutputLength,
+ sizeof(struct bcm_host_stats_mibs));
+ return -EINVAL;
+ }
- /* Copy Ioctl Buffer structure */
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ /* FIXME: HOST_STATS are too big for kmalloc (122048)! */
+ temp_buff = kzalloc(sizeof(struct bcm_host_stats_mibs), GFP_KERNEL);
+ if (!temp_buff)
+ return STATUS_FAILURE;
+
+ Status = ProcessGetHostMibs(Adapter, temp_buff);
+ GetDroppedAppCntrlPktMibs(temp_buff, pTarang);
+
+ if (Status != STATUS_FAILURE) {
+ if (copy_to_user(IoBuffer.OutputBuffer, temp_buff,
+ sizeof(struct bcm_host_stats_mibs))) {
+ kfree(temp_buff);
return -EFAULT;
+ }
+ }
- if (IoBuffer.InputLength < sizeof(ULONG) * 2)
- return -EINVAL;
+ kfree(temp_buff);
+ return Status;
+}
- pvBuffer = memdup_user(IoBuffer.InputBuffer,
- IoBuffer.InputLength);
- if (IS_ERR(pvBuffer))
- return PTR_ERR(pvBuffer);
+static int bcm_char_ioctl_bulk_wrm(void __user *argp,
+ struct bcm_mini_adapter *Adapter, UINT cmd)
+{
+ struct bcm_bulk_wrm_buffer *pBulkBuffer;
+ struct bcm_ioctl_buffer IoBuffer;
+ UINT uiTempVar = 0;
+ INT Status = STATUS_FAILURE;
+ PCHAR pvBuffer = NULL;
- pBulkBuffer = (struct bcm_bulk_wrm_buffer *)pvBuffer;
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE)) {
- if (((ULONG)pBulkBuffer->Register & 0x0F000000) != 0x0F000000 ||
- ((ULONG)pBulkBuffer->Register & 0x3)) {
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM Done On invalid Address : %x Access Denied.\n", (int)pBulkBuffer->Register);
- kfree(pvBuffer);
- Status = -EINVAL;
- break;
- }
+ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Device in Idle/Shutdown Mode, Blocking Wrms\n");
+ return -EACCES;
+ }
- uiTempVar = pBulkBuffer->Register & EEPROM_REJECT_MASK;
- if (!((Adapter->pstargetparams->m_u32Customize)&VSG_MODE) &&
- ((uiTempVar == EEPROM_REJECT_REG_1) ||
- (uiTempVar == EEPROM_REJECT_REG_2) ||
- (uiTempVar == EEPROM_REJECT_REG_3) ||
- (uiTempVar == EEPROM_REJECT_REG_4)) &&
- (cmd == IOCTL_BCM_REGISTER_WRITE)) {
+ /* Copy Ioctl Buffer structure */
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- kfree(pvBuffer);
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "EEPROM Access Denied, not in VSG Mode\n");
- Status = -EFAULT;
- break;
- }
+ if (IoBuffer.InputLength < sizeof(ULONG) * 2)
+ return -EINVAL;
- if (pBulkBuffer->SwapEndian == false)
- Status = wrmWithLock(Adapter, (UINT)pBulkBuffer->Register, (PCHAR)pBulkBuffer->Values, IoBuffer.InputLength - 2*sizeof(ULONG));
- else
- Status = wrmaltWithLock(Adapter, (UINT)pBulkBuffer->Register, (PUINT)pBulkBuffer->Values, IoBuffer.InputLength - 2*sizeof(ULONG));
+ pvBuffer = memdup_user(IoBuffer.InputBuffer,
+ IoBuffer.InputLength);
+ if (IS_ERR(pvBuffer))
+ return PTR_ERR(pvBuffer);
- if (Status != STATUS_SUCCESS)
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM Failed\n");
+ pBulkBuffer = (struct bcm_bulk_wrm_buffer *)pvBuffer;
+ if (((ULONG)pBulkBuffer->Register & 0x0F000000) != 0x0F000000 ||
+ ((ULONG)pBulkBuffer->Register & 0x3)) {
+ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "WRM Done On invalid Address : %x Access Denied.\n",
+ (int)pBulkBuffer->Register);
kfree(pvBuffer);
- break;
+ return -EINVAL;
}
- case IOCTL_BCM_GET_NVM_SIZE:
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ uiTempVar = pBulkBuffer->Register & EEPROM_REJECT_MASK;
+ if (!((Adapter->pstargetparams->m_u32Customize)&VSG_MODE) &&
+ ((uiTempVar == EEPROM_REJECT_REG_1) ||
+ (uiTempVar == EEPROM_REJECT_REG_2) ||
+ (uiTempVar == EEPROM_REJECT_REG_3) ||
+ (uiTempVar == EEPROM_REJECT_REG_4)) &&
+ (cmd == IOCTL_BCM_REGISTER_WRITE)) {
+
+ kfree(pvBuffer);
+ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "EEPROM Access Denied, not in VSG Mode\n");
+ return -EFAULT;
+ }
+
+ if (pBulkBuffer->SwapEndian == false)
+ Status = wrmWithLock(Adapter, (UINT)pBulkBuffer->Register,
+ (PCHAR)pBulkBuffer->Values,
+ IoBuffer.InputLength - 2*sizeof(ULONG));
+ else
+ Status = wrmaltWithLock(Adapter, (UINT)pBulkBuffer->Register,
+ (PUINT)pBulkBuffer->Values,
+ IoBuffer.InputLength - 2*sizeof(ULONG));
+
+ if (Status != STATUS_SUCCESS)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM Failed\n");
+
+ kfree(pvBuffer);
+ return Status;
+}
+
+static int bcm_char_ioctl_get_nvm_size(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_ioctl_buffer IoBuffer;
+
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
+
+ if (Adapter->eNVMType == NVM_EEPROM || Adapter->eNVMType == NVM_FLASH) {
+ if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiNVMDSDSize,
+ sizeof(UINT)))
return -EFAULT;
+ }
- if (Adapter->eNVMType == NVM_EEPROM || Adapter->eNVMType == NVM_FLASH) {
- if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiNVMDSDSize, sizeof(UINT)))
- return -EFAULT;
- }
+ return STATUS_SUCCESS;
+}
- Status = STATUS_SUCCESS;
- break;
+static int bcm_char_ioctl_cal_init(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_ioctl_buffer IoBuffer;
+ UINT uiSectorSize = 0;
+ INT Status = STATUS_FAILURE;
- case IOCTL_BCM_CAL_INIT: {
- UINT uiSectorSize = 0;
- if (Adapter->eNVMType == NVM_FLASH) {
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ if (Adapter->eNVMType == NVM_FLASH) {
+ if (copy_from_user(&IoBuffer, argp,
+ sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- if (copy_from_user(&uiSectorSize, IoBuffer.InputBuffer, sizeof(UINT)))
- return -EFAULT;
+ if (copy_from_user(&uiSectorSize, IoBuffer.InputBuffer,
+ sizeof(UINT)))
+ return -EFAULT;
- if ((uiSectorSize < MIN_SECTOR_SIZE) || (uiSectorSize > MAX_SECTOR_SIZE)) {
- if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiSectorSize,
- sizeof(UINT)))
+ if ((uiSectorSize < MIN_SECTOR_SIZE) ||
+ (uiSectorSize > MAX_SECTOR_SIZE)) {
+ if (copy_to_user(IoBuffer.OutputBuffer,
+ &Adapter->uiSectorSize, sizeof(UINT)))
+ return -EFAULT;
+ } else {
+ if (IsFlash2x(Adapter)) {
+ if (copy_to_user(IoBuffer.OutputBuffer,
+ &Adapter->uiSectorSize, sizeof(UINT)))
return -EFAULT;
} else {
- if (IsFlash2x(Adapter)) {
- if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiSectorSize, sizeof(UINT)))
- return -EFAULT;
- } else {
- if ((TRUE == Adapter->bShutStatus) || (TRUE == Adapter->IdleMode)) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device is in Idle/Shutdown Mode\n");
- return -EACCES;
- }
-
- Adapter->uiSectorSize = uiSectorSize;
- BcmUpdateSectorSize(Adapter, Adapter->uiSectorSize);
+ if ((TRUE == Adapter->bShutStatus) ||
+ (TRUE == Adapter->IdleMode)) {
+ BCM_DEBUG_PRINT(Adapter,
+ DBG_TYPE_PRINTK, 0, 0,
+ "Device is in Idle/Shutdown Mode\n");
+ return -EACCES;
}
+
+ Adapter->uiSectorSize = uiSectorSize;
+ BcmUpdateSectorSize(Adapter,
+ Adapter->uiSectorSize);
}
- Status = STATUS_SUCCESS;
- } else {
- Status = STATUS_FAILURE;
}
+ Status = STATUS_SUCCESS;
+ } else {
+ Status = STATUS_FAILURE;
}
- break;
+ return Status;
+}
- case IOCTL_BCM_SET_DEBUG:
+static int bcm_char_ioctl_set_debug(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
#ifdef DEBUG
- {
- struct bcm_user_debug_state sUserDebugState;
+ struct bcm_ioctl_buffer IoBuffer;
+ struct bcm_user_debug_state sUserDebugState;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "In SET_DEBUG ioctl\n");
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "In SET_DEBUG ioctl\n");
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- if (copy_from_user(&sUserDebugState, IoBuffer.InputBuffer, sizeof(struct bcm_user_debug_state)))
- return -EFAULT;
+ if (copy_from_user(&sUserDebugState, IoBuffer.InputBuffer,
+ sizeof(struct bcm_user_debug_state)))
+ return -EFAULT;
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL_BCM_SET_DEBUG: OnOff=%d Type = 0x%x ",
- sUserDebugState.OnOff, sUserDebugState.Type);
- /* sUserDebugState.Subtype <<= 1; */
- sUserDebugState.Subtype = 1 << sUserDebugState.Subtype;
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "actual Subtype=0x%x\n", sUserDebugState.Subtype);
-
- /* Update new 'DebugState' in the Adapter */
- Adapter->stDebugState.type |= sUserDebugState.Type;
- /* Subtype: A bitmap of 32 bits for Subtype per Type.
- * Valid indexes in 'subtype' array: 1,2,4,8
- * corresponding to valid Type values. Hence we can use the 'Type' field
- * as the index value, ignoring the array entries 0,3,5,6,7 !
- */
- if (sUserDebugState.OnOff)
- Adapter->stDebugState.subtype[sUserDebugState.Type] |= sUserDebugState.Subtype;
- else
- Adapter->stDebugState.subtype[sUserDebugState.Type] &= ~sUserDebugState.Subtype;
+ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "IOCTL_BCM_SET_DEBUG: OnOff=%d Type = 0x%x ",
+ sUserDebugState.OnOff, sUserDebugState.Type);
+ /* sUserDebugState.Subtype <<= 1; */
+ sUserDebugState.Subtype = 1 << sUserDebugState.Subtype;
+ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "actual Subtype=0x%x\n", sUserDebugState.Subtype);
+
+ /* Update new 'DebugState' in the Adapter */
+ Adapter->stDebugState.type |= sUserDebugState.Type;
+ /* Subtype: A bitmap of 32 bits for Subtype per Type.
+ * Valid indexes in 'subtype' array: 1,2,4,8
+ * corresponding to valid Type values. Hence we can use the 'Type' field
+ * as the index value, ignoring the array entries 0,3,5,6,7 !
+ */
+ if (sUserDebugState.OnOff)
+ Adapter->stDebugState.subtype[sUserDebugState.Type] |=
+ sUserDebugState.Subtype;
+ else
+ Adapter->stDebugState.subtype[sUserDebugState.Type] &=
+ ~sUserDebugState.Subtype;
+
+ BCM_SHOW_DEBUG_BITMAP(Adapter);
+#endif
+ return STATUS_SUCCESS;
+}
+
+static int bcm_char_ioctl_nvm_rw(void __user *argp,
+ struct bcm_mini_adapter *Adapter, UINT cmd)
+{
+ struct bcm_nvm_readwrite stNVMReadWrite;
+ struct timeval tv0, tv1;
+ struct bcm_ioctl_buffer IoBuffer;
+ PUCHAR pReadData = NULL;
+ ULONG ulDSDMagicNumInUsrBuff = 0;
+ INT Status = STATUS_FAILURE;
- BCM_SHOW_DEBUG_BITMAP(Adapter);
+ memset(&tv0, 0, sizeof(struct timeval));
+ memset(&tv1, 0, sizeof(struct timeval));
+ if ((Adapter->eNVMType == NVM_FLASH) &&
+ (Adapter->uiFlashLayoutMajorVersion == 0)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "The Flash Control Section is Corrupted. Hence Rejection on NVM Read/Write\n");
+ return -EFAULT;
}
-#endif
- break;
- case IOCTL_BCM_NVM_READ:
- case IOCTL_BCM_NVM_WRITE: {
- struct bcm_nvm_readwrite stNVMReadWrite;
- PUCHAR pReadData = NULL;
- ULONG ulDSDMagicNumInUsrBuff = 0;
- struct timeval tv0, tv1;
- memset(&tv0, 0, sizeof(struct timeval));
- memset(&tv1, 0, sizeof(struct timeval));
- if ((Adapter->eNVMType == NVM_FLASH) && (Adapter->uiFlashLayoutMajorVersion == 0)) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "The Flash Control Section is Corrupted. Hence Rejection on NVM Read/Write\n");
- return -EFAULT;
+ if (IsFlash2x(Adapter)) {
+ if ((Adapter->eActiveDSD != DSD0) &&
+ (Adapter->eActiveDSD != DSD1) &&
+ (Adapter->eActiveDSD != DSD2)) {
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "No DSD is active..hence NVM Command is blocked");
+ return STATUS_FAILURE;
}
+ }
- if (IsFlash2x(Adapter)) {
- if ((Adapter->eActiveDSD != DSD0) &&
- (Adapter->eActiveDSD != DSD1) &&
- (Adapter->eActiveDSD != DSD2)) {
+ /* Copy Ioctl Buffer structure */
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "No DSD is active..hence NVM Command is blocked");
- return STATUS_FAILURE;
- }
- }
+ if (copy_from_user(&stNVMReadWrite,
+ (IOCTL_BCM_NVM_READ == cmd) ?
+ IoBuffer.OutputBuffer : IoBuffer.InputBuffer,
+ sizeof(struct bcm_nvm_readwrite)))
+ return -EFAULT;
- /* Copy Ioctl Buffer structure */
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ /*
+ * Deny the access if the offset crosses the cal area limit.
+ */
+ if (stNVMReadWrite.uiNumBytes > Adapter->uiNVMDSDSize)
+ return STATUS_FAILURE;
- if (copy_from_user(&stNVMReadWrite,
- (IOCTL_BCM_NVM_READ == cmd) ? IoBuffer.OutputBuffer : IoBuffer.InputBuffer,
- sizeof(struct bcm_nvm_readwrite)))
- return -EFAULT;
+ if (stNVMReadWrite.uiOffset >
+ Adapter->uiNVMDSDSize - stNVMReadWrite.uiNumBytes)
+ return STATUS_FAILURE;
- /*
- * Deny the access if the offset crosses the cal area limit.
- */
- if (stNVMReadWrite.uiNumBytes > Adapter->uiNVMDSDSize)
- return STATUS_FAILURE;
+ pReadData = memdup_user(stNVMReadWrite.pBuffer,
+ stNVMReadWrite.uiNumBytes);
+ if (IS_ERR(pReadData))
+ return PTR_ERR(pReadData);
- if (stNVMReadWrite.uiOffset > Adapter->uiNVMDSDSize - stNVMReadWrite.uiNumBytes) {
- /* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Can't allow access beyond NVM Size: 0x%x 0x%x\n", stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes); */
- return STATUS_FAILURE;
+ do_gettimeofday(&tv0);
+ if (IOCTL_BCM_NVM_READ == cmd) {
+ down(&Adapter->NVMRdmWrmLock);
+
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE)) {
+
+ BCM_DEBUG_PRINT(Adapter,
+ DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Device is in Idle/Shutdown Mode\n");
+ up(&Adapter->NVMRdmWrmLock);
+ kfree(pReadData);
+ return -EACCES;
}
- pReadData = memdup_user(stNVMReadWrite.pBuffer,
- stNVMReadWrite.uiNumBytes);
- if (IS_ERR(pReadData))
- return PTR_ERR(pReadData);
+ Status = BeceemNVMRead(Adapter, (PUINT)pReadData,
+ stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes);
+ up(&Adapter->NVMRdmWrmLock);
- do_gettimeofday(&tv0);
- if (IOCTL_BCM_NVM_READ == cmd) {
- down(&Adapter->NVMRdmWrmLock);
+ if (Status != STATUS_SUCCESS) {
+ kfree(pReadData);
+ return Status;
+ }
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE)) {
+ if (copy_to_user(stNVMReadWrite.pBuffer, pReadData,
+ stNVMReadWrite.uiNumBytes)) {
+ kfree(pReadData);
+ return -EFAULT;
+ }
+ } else {
+ down(&Adapter->NVMRdmWrmLock);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
- up(&Adapter->NVMRdmWrmLock);
- kfree(pReadData);
- return -EACCES;
- }
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE)) {
- Status = BeceemNVMRead(Adapter, (PUINT)pReadData, stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes);
+ BCM_DEBUG_PRINT(Adapter,
+ DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Device is in Idle/Shutdown Mode\n");
up(&Adapter->NVMRdmWrmLock);
+ kfree(pReadData);
+ return -EACCES;
+ }
- if (Status != STATUS_SUCCESS) {
- kfree(pReadData);
- return Status;
- }
-
- if (copy_to_user(stNVMReadWrite.pBuffer, pReadData, stNVMReadWrite.uiNumBytes)) {
- kfree(pReadData);
- return -EFAULT;
- }
- } else {
- down(&Adapter->NVMRdmWrmLock);
+ Adapter->bHeaderChangeAllowed = TRUE;
+ if (IsFlash2x(Adapter)) {
+ /*
+ * New Requirement:-
+ * DSD section updation will be allowed in two case:-
+ * 1. if DSD sig is present in DSD header means dongle
+ * is ok and updation is fruitfull
+ * 2. if point 1 failes then user buff should have
+ * DSD sig. this point ensures that if dongle is
+ * corrupted then user space program first modify
+ * the DSD header with valid DSD sig so that this
+ * as well as further write may be worthwhile.
+ *
+ * This restriction has been put assuming that
+ * if DSD sig is corrupted, DSD data won't be
+ * considered valid.
+ */
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE)) {
+ Status = BcmFlash2xCorruptSig(Adapter,
+ Adapter->eActiveDSD);
+ if (Status != STATUS_SUCCESS) {
+ if (((stNVMReadWrite.uiOffset + stNVMReadWrite.uiNumBytes) !=
+ Adapter->uiNVMDSDSize) ||
+ (stNVMReadWrite.uiNumBytes < SIGNATURE_SIZE)) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
- up(&Adapter->NVMRdmWrmLock);
- kfree(pReadData);
- return -EACCES;
- }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
+ OSAL_DBG, DBG_LVL_ALL,
+ "DSD Sig is present neither in Flash nor User provided Input..");
+ up(&Adapter->NVMRdmWrmLock);
+ kfree(pReadData);
+ return Status;
+ }
- Adapter->bHeaderChangeAllowed = TRUE;
- if (IsFlash2x(Adapter)) {
- /*
- * New Requirement:-
- * DSD section updation will be allowed in two case:-
- * 1. if DSD sig is present in DSD header means dongle is ok and updation is fruitfull
- * 2. if point 1 failes then user buff should have DSD sig. this point ensures that if dongle is
- * corrupted then user space program first modify the DSD header with valid DSD sig so
- * that this as well as further write may be worthwhile.
- *
- * This restriction has been put assuming that if DSD sig is corrupted, DSD
- * data won't be considered valid.
- */
-
- Status = BcmFlash2xCorruptSig(Adapter, Adapter->eActiveDSD);
- if (Status != STATUS_SUCCESS) {
- if (((stNVMReadWrite.uiOffset + stNVMReadWrite.uiNumBytes) != Adapter->uiNVMDSDSize) ||
- (stNVMReadWrite.uiNumBytes < SIGNATURE_SIZE)) {
-
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "DSD Sig is present neither in Flash nor User provided Input..");
- up(&Adapter->NVMRdmWrmLock);
- kfree(pReadData);
- return Status;
- }
-
- ulDSDMagicNumInUsrBuff = ntohl(*(PUINT)(pReadData + stNVMReadWrite.uiNumBytes - SIGNATURE_SIZE));
- if (ulDSDMagicNumInUsrBuff != DSD_IMAGE_MAGIC_NUMBER) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "DSD Sig is present neither in Flash nor User provided Input..");
- up(&Adapter->NVMRdmWrmLock);
- kfree(pReadData);
- return Status;
- }
+ ulDSDMagicNumInUsrBuff = ntohl(*(PUINT)(pReadData + stNVMReadWrite.uiNumBytes - SIGNATURE_SIZE));
+ if (ulDSDMagicNumInUsrBuff !=
+ DSD_IMAGE_MAGIC_NUMBER) {
+ BCM_DEBUG_PRINT(Adapter,
+ DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "DSD Sig is present neither in Flash nor User provided Input..");
+ up(&Adapter->NVMRdmWrmLock);
+ kfree(pReadData);
+ return Status;
}
}
+ }
- Status = BeceemNVMWrite(Adapter, (PUINT)pReadData, stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes, stNVMReadWrite.bVerify);
- if (IsFlash2x(Adapter))
- BcmFlash2xWriteSig(Adapter, Adapter->eActiveDSD);
+ Status = BeceemNVMWrite(Adapter, (PUINT)pReadData,
+ stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes,
+ stNVMReadWrite.bVerify);
+ if (IsFlash2x(Adapter))
+ BcmFlash2xWriteSig(Adapter, Adapter->eActiveDSD);
- Adapter->bHeaderChangeAllowed = false;
+ Adapter->bHeaderChangeAllowed = false;
- up(&Adapter->NVMRdmWrmLock);
+ up(&Adapter->NVMRdmWrmLock);
- if (Status != STATUS_SUCCESS) {
- kfree(pReadData);
- return Status;
- }
+ if (Status != STATUS_SUCCESS) {
+ kfree(pReadData);
+ return Status;
}
+ }
+
+ do_gettimeofday(&tv1);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ " timetaken by Write/read :%ld msec\n",
+ (tv1.tv_sec - tv0.tv_sec)*1000 + (tv1.tv_usec - tv0.tv_usec)/1000);
+
+ kfree(pReadData);
+ return STATUS_SUCCESS;
+}
- do_gettimeofday(&tv1);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, " timetaken by Write/read :%ld msec\n", (tv1.tv_sec - tv0.tv_sec)*1000 + (tv1.tv_usec - tv0.tv_usec)/1000);
+static int bcm_char_ioctl_flash2x_section_read(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_flash2x_readwrite sFlash2xRead = {0};
+ struct bcm_ioctl_buffer IoBuffer;
+ PUCHAR pReadBuff = NULL;
+ UINT NOB = 0;
+ UINT BuffSize = 0;
+ UINT ReadBytes = 0;
+ UINT ReadOffset = 0;
+ INT Status = STATUS_FAILURE;
+ void __user *OutPutBuff;
- kfree(pReadData);
- return STATUS_SUCCESS;
+ if (IsFlash2x(Adapter) != TRUE) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Flash Does not have 2.x map");
+ return -EINVAL;
}
- case IOCTL_BCM_FLASH2X_SECTION_READ: {
- struct bcm_flash2x_readwrite sFlash2xRead = {0};
- PUCHAR pReadBuff = NULL;
- UINT NOB = 0;
- UINT BuffSize = 0;
- UINT ReadBytes = 0;
- UINT ReadOffset = 0;
- void __user *OutPutBuff;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL, "IOCTL_BCM_FLASH2X_SECTION_READ Called");
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- if (IsFlash2x(Adapter) != TRUE) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map");
- return -EINVAL;
- }
+ /* Reading FLASH 2.x READ structure */
+ if (copy_from_user(&sFlash2xRead, IoBuffer.InputBuffer,
+ sizeof(struct bcm_flash2x_readwrite)))
+ return -EFAULT;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_FLASH2X_SECTION_READ Called");
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "\nsFlash2xRead.Section :%x", sFlash2xRead.Section);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "\nsFlash2xRead.offset :%x", sFlash2xRead.offset);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "\nsFlash2xRead.numOfBytes :%x", sFlash2xRead.numOfBytes);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "\nsFlash2xRead.bVerify :%x\n", sFlash2xRead.bVerify);
- /* Reading FLASH 2.x READ structure */
- if (copy_from_user(&sFlash2xRead, IoBuffer.InputBuffer, sizeof(struct bcm_flash2x_readwrite)))
- return -EFAULT;
+ /* This was internal to driver for raw read.
+ * now it has ben exposed to user space app.
+ */
+ if (validateFlash2xReadWrite(Adapter, &sFlash2xRead) == false)
+ return STATUS_FAILURE;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.Section :%x", sFlash2xRead.Section);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.offset :%x", sFlash2xRead.offset);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.numOfBytes :%x", sFlash2xRead.numOfBytes);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.bVerify :%x\n", sFlash2xRead.bVerify);
+ NOB = sFlash2xRead.numOfBytes;
+ if (NOB > Adapter->uiSectorSize)
+ BuffSize = Adapter->uiSectorSize;
+ else
+ BuffSize = NOB;
- /* This was internal to driver for raw read. now it has ben exposed to user space app. */
- if (validateFlash2xReadWrite(Adapter, &sFlash2xRead) == false)
- return STATUS_FAILURE;
+ ReadOffset = sFlash2xRead.offset;
+ OutPutBuff = IoBuffer.OutputBuffer;
+ pReadBuff = (PCHAR)kzalloc(BuffSize , GFP_KERNEL);
+
+ if (pReadBuff == NULL) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Memory allocation failed for Flash 2.x Read Structure");
+ return -ENOMEM;
+ }
+ down(&Adapter->NVMRdmWrmLock);
+
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE)) {
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
+ up(&Adapter->NVMRdmWrmLock);
+ kfree(pReadBuff);
+ return -EACCES;
+ }
- NOB = sFlash2xRead.numOfBytes;
+ while (NOB) {
if (NOB > Adapter->uiSectorSize)
- BuffSize = Adapter->uiSectorSize;
+ ReadBytes = Adapter->uiSectorSize;
else
- BuffSize = NOB;
-
- ReadOffset = sFlash2xRead.offset;
- OutPutBuff = IoBuffer.OutputBuffer;
- pReadBuff = (PCHAR)kzalloc(BuffSize , GFP_KERNEL);
+ ReadBytes = NOB;
- if (pReadBuff == NULL) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed for Flash 2.x Read Structure");
- return -ENOMEM;
+ /* Reading the data from Flash 2.x */
+ Status = BcmFlash2xBulkRead(Adapter, (PUINT)pReadBuff,
+ sFlash2xRead.Section, ReadOffset, ReadBytes);
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter,
+ DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Flash 2x read err with Status :%d",
+ Status);
+ break;
}
- down(&Adapter->NVMRdmWrmLock);
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE)) {
+ BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL, pReadBuff, ReadBytes);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
+ Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes);
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter,
+ DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Copy to use failed with status :%d", Status);
up(&Adapter->NVMRdmWrmLock);
kfree(pReadBuff);
- return -EACCES;
+ return -EFAULT;
}
+ NOB = NOB - ReadBytes;
+ if (NOB) {
+ ReadOffset = ReadOffset + ReadBytes;
+ OutPutBuff = OutPutBuff + ReadBytes;
+ }
+ }
- while (NOB) {
- if (NOB > Adapter->uiSectorSize)
- ReadBytes = Adapter->uiSectorSize;
- else
- ReadBytes = NOB;
-
- /* Reading the data from Flash 2.x */
- Status = BcmFlash2xBulkRead(Adapter, (PUINT)pReadBuff, sFlash2xRead.Section, ReadOffset, ReadBytes);
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Flash 2x read err with Status :%d", Status);
- break;
- }
-
- BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, pReadBuff, ReadBytes);
+ up(&Adapter->NVMRdmWrmLock);
+ kfree(pReadBuff);
+ return Status;
+}
- Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes);
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Copy to use failed with status :%d", Status);
- up(&Adapter->NVMRdmWrmLock);
- kfree(pReadBuff);
- return -EFAULT;
- }
- NOB = NOB - ReadBytes;
- if (NOB) {
- ReadOffset = ReadOffset + ReadBytes;
- OutPutBuff = OutPutBuff + ReadBytes;
- }
- }
+static int bcm_char_ioctl_flash2x_section_write(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_flash2x_readwrite sFlash2xWrite = {0};
+ struct bcm_ioctl_buffer IoBuffer;
+ PUCHAR pWriteBuff;
+ void __user *InputAddr;
+ UINT NOB = 0;
+ UINT BuffSize = 0;
+ UINT WriteOffset = 0;
+ UINT WriteBytes = 0;
+ INT Status = STATUS_FAILURE;
- up(&Adapter->NVMRdmWrmLock);
- kfree(pReadBuff);
+ if (IsFlash2x(Adapter) != TRUE) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Flash Does not have 2.x map");
+ return -EINVAL;
}
- break;
- case IOCTL_BCM_FLASH2X_SECTION_WRITE: {
- struct bcm_flash2x_readwrite sFlash2xWrite = {0};
- PUCHAR pWriteBuff;
- void __user *InputAddr;
- UINT NOB = 0;
- UINT BuffSize = 0;
- UINT WriteOffset = 0;
- UINT WriteBytes = 0;
+ /* First make this False so that we can enable the Sector
+ * Permission Check in BeceemFlashBulkWrite
+ */
+ Adapter->bAllDSDWriteAllow = false;
- if (IsFlash2x(Adapter) != TRUE) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map");
- return -EINVAL;
- }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "IOCTL_BCM_FLASH2X_SECTION_WRITE Called");
- /* First make this False so that we can enable the Sector Permission Check in BeceemFlashBulkWrite */
- Adapter->bAllDSDWriteAllow = false;
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_FLASH2X_SECTION_WRITE Called");
+ /* Reading FLASH 2.x READ structure */
+ if (copy_from_user(&sFlash2xWrite, IoBuffer.InputBuffer,
+ sizeof(struct bcm_flash2x_readwrite)))
+ return -EFAULT;
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "\nsFlash2xRead.Section :%x", sFlash2xWrite.Section);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "\nsFlash2xRead.offset :%d", sFlash2xWrite.offset);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "\nsFlash2xRead.numOfBytes :%x", sFlash2xWrite.numOfBytes);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "\nsFlash2xRead.bVerify :%x\n", sFlash2xWrite.bVerify);
- /* Reading FLASH 2.x READ structure */
- if (copy_from_user(&sFlash2xWrite, IoBuffer.InputBuffer, sizeof(struct bcm_flash2x_readwrite)))
- return -EFAULT;
+ if ((sFlash2xWrite.Section != VSA0) && (sFlash2xWrite.Section != VSA1)
+ && (sFlash2xWrite.Section != VSA2)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Only VSA write is allowed");
+ return -EINVAL;
+ }
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.Section :%x", sFlash2xWrite.Section);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.offset :%d", sFlash2xWrite.offset);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.numOfBytes :%x", sFlash2xWrite.numOfBytes);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.bVerify :%x\n", sFlash2xWrite.bVerify);
+ if (validateFlash2xReadWrite(Adapter, &sFlash2xWrite) == false)
+ return STATUS_FAILURE;
- if ((sFlash2xWrite.Section != VSA0) && (sFlash2xWrite.Section != VSA1) && (sFlash2xWrite.Section != VSA2)) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Only VSA write is allowed");
- return -EINVAL;
- }
+ InputAddr = sFlash2xWrite.pDataBuff;
+ WriteOffset = sFlash2xWrite.offset;
+ NOB = sFlash2xWrite.numOfBytes;
- if (validateFlash2xReadWrite(Adapter, &sFlash2xWrite) == false)
- return STATUS_FAILURE;
+ if (NOB > Adapter->uiSectorSize)
+ BuffSize = Adapter->uiSectorSize;
+ else
+ BuffSize = NOB;
- InputAddr = sFlash2xWrite.pDataBuff;
- WriteOffset = sFlash2xWrite.offset;
- NOB = sFlash2xWrite.numOfBytes;
+ pWriteBuff = kmalloc(BuffSize, GFP_KERNEL);
- if (NOB > Adapter->uiSectorSize)
- BuffSize = Adapter->uiSectorSize;
- else
- BuffSize = NOB;
+ if (pWriteBuff == NULL)
+ return -ENOMEM;
- pWriteBuff = kmalloc(BuffSize, GFP_KERNEL);
+ /* extracting the remainder of the given offset. */
+ WriteBytes = Adapter->uiSectorSize;
+ if (WriteOffset % Adapter->uiSectorSize)
+ WriteBytes = Adapter->uiSectorSize - (WriteOffset % Adapter->uiSectorSize);
- if (pWriteBuff == NULL)
- return -ENOMEM;
+ if (NOB < WriteBytes)
+ WriteBytes = NOB;
- /* extracting the remainder of the given offset. */
- WriteBytes = Adapter->uiSectorSize;
- if (WriteOffset % Adapter->uiSectorSize)
- WriteBytes = Adapter->uiSectorSize - (WriteOffset % Adapter->uiSectorSize);
+ down(&Adapter->NVMRdmWrmLock);
- if (NOB < WriteBytes)
- WriteBytes = NOB;
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE)) {
- down(&Adapter->NVMRdmWrmLock);
-
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Device is in Idle/Shutdown Mode\n");
+ up(&Adapter->NVMRdmWrmLock);
+ kfree(pWriteBuff);
+ return -EACCES;
+ }
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
+ BcmFlash2xCorruptSig(Adapter, sFlash2xWrite.Section);
+ do {
+ Status = copy_from_user(pWriteBuff, InputAddr, WriteBytes);
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Copy to user failed with status :%d", Status);
up(&Adapter->NVMRdmWrmLock);
kfree(pWriteBuff);
- return -EACCES;
+ return -EFAULT;
}
+ BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS,
+ OSAL_DBG, DBG_LVL_ALL, pWriteBuff, WriteBytes);
- BcmFlash2xCorruptSig(Adapter, sFlash2xWrite.Section);
- do {
- Status = copy_from_user(pWriteBuff, InputAddr, WriteBytes);
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy to user failed with status :%d", Status);
- up(&Adapter->NVMRdmWrmLock);
- kfree(pWriteBuff);
- return -EFAULT;
- }
- BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, pWriteBuff, WriteBytes);
+ /* Writing the data from Flash 2.x */
+ Status = BcmFlash2xBulkWrite(Adapter, (PUINT)pWriteBuff,
+ sFlash2xWrite.Section, WriteOffset, WriteBytes,
+ sFlash2xWrite.bVerify);
- /* Writing the data from Flash 2.x */
- Status = BcmFlash2xBulkWrite(Adapter, (PUINT)pWriteBuff, sFlash2xWrite.Section, WriteOffset, WriteBytes, sFlash2xWrite.bVerify);
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Flash 2x read err with Status :%d", Status);
+ break;
+ }
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash 2x read err with Status :%d", Status);
- break;
- }
+ NOB = NOB - WriteBytes;
+ if (NOB) {
+ WriteOffset = WriteOffset + WriteBytes;
+ InputAddr = InputAddr + WriteBytes;
+ if (NOB > Adapter->uiSectorSize)
+ WriteBytes = Adapter->uiSectorSize;
+ else
+ WriteBytes = NOB;
+ }
+ } while (NOB > 0);
- NOB = NOB - WriteBytes;
- if (NOB) {
- WriteOffset = WriteOffset + WriteBytes;
- InputAddr = InputAddr + WriteBytes;
- if (NOB > Adapter->uiSectorSize)
- WriteBytes = Adapter->uiSectorSize;
- else
- WriteBytes = NOB;
- }
- } while (NOB > 0);
+ BcmFlash2xWriteSig(Adapter, sFlash2xWrite.Section);
+ up(&Adapter->NVMRdmWrmLock);
+ kfree(pWriteBuff);
+ return Status;
+}
+
+static int bcm_char_ioctl_flash2x_section_bitmap(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_flash2x_bitmap *psFlash2xBitMap;
+ struct bcm_ioctl_buffer IoBuffer;
+ INT Status = STATUS_FAILURE;
+
+BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP Called");
+
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
+
+ if (IoBuffer.OutputLength != sizeof(struct bcm_flash2x_bitmap))
+ return -EINVAL;
+
+ psFlash2xBitMap = kzalloc(sizeof(struct bcm_flash2x_bitmap), GFP_KERNEL);
+ if (psFlash2xBitMap == NULL) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Memory is not available");
+ return -ENOMEM;
+ }
+
+ /* Reading the Flash Sectio Bit map */
+ down(&Adapter->NVMRdmWrmLock);
+
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE)) {
- BcmFlash2xWriteSig(Adapter, sFlash2xWrite.Section);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Device is in Idle/Shutdown Mode\n");
up(&Adapter->NVMRdmWrmLock);
- kfree(pWriteBuff);
+ kfree(psFlash2xBitMap);
+ return -EACCES;
}
- break;
- case IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP: {
- struct bcm_flash2x_bitmap *psFlash2xBitMap;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP Called");
+ BcmGetFlash2xSectionalBitMap(Adapter, psFlash2xBitMap);
+ up(&Adapter->NVMRdmWrmLock);
+ if (copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap,
+ sizeof(struct bcm_flash2x_bitmap))) {
+ kfree(psFlash2xBitMap);
+ return -EFAULT;
+ }
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ kfree(psFlash2xBitMap);
+ return Status;
+}
- if (IoBuffer.OutputLength != sizeof(struct bcm_flash2x_bitmap))
- return -EINVAL;
+static int bcm_char_ioctl_set_active_section(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ enum bcm_flash2x_section_val eFlash2xSectionVal = 0;
+ INT Status = STATUS_FAILURE;
+ struct bcm_ioctl_buffer IoBuffer;
- psFlash2xBitMap = kzalloc(sizeof(struct bcm_flash2x_bitmap), GFP_KERNEL);
- if (psFlash2xBitMap == NULL) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory is not available");
- return -ENOMEM;
- }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "IOCTL_BCM_SET_ACTIVE_SECTION Called");
- /* Reading the Flash Sectio Bit map */
- down(&Adapter->NVMRdmWrmLock);
+ if (IsFlash2x(Adapter) != TRUE) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Flash Does not have 2.x map");
+ return -EINVAL;
+ }
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE)) {
+ Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Copy of IOCTL BUFFER failed");
+ return -EFAULT;
+ }
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
- up(&Adapter->NVMRdmWrmLock);
- kfree(psFlash2xBitMap);
- return -EACCES;
- }
+ Status = copy_from_user(&eFlash2xSectionVal,
+ IoBuffer.InputBuffer, sizeof(INT));
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Copy of flash section val failed");
+ return -EFAULT;
+ }
+
+ down(&Adapter->NVMRdmWrmLock);
+
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE)) {
- BcmGetFlash2xSectionalBitMap(Adapter, psFlash2xBitMap);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Device is in Idle/Shutdown Mode\n");
up(&Adapter->NVMRdmWrmLock);
- if (copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap, sizeof(struct bcm_flash2x_bitmap))) {
- kfree(psFlash2xBitMap);
- return -EFAULT;
- }
+ return -EACCES;
+ }
- kfree(psFlash2xBitMap);
+ Status = BcmSetActiveSection(Adapter, eFlash2xSectionVal);
+ if (Status)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Failed to make it's priority Highest. Status %d",
+ Status);
+
+ up(&Adapter->NVMRdmWrmLock);
+
+ return Status;
+}
+
+static int bcm_char_ioctl_copy_section(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_flash2x_copy_section sCopySectStrut = {0};
+ struct bcm_ioctl_buffer IoBuffer;
+ INT Status = STATUS_SUCCESS;
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "IOCTL_BCM_COPY_SECTION Called");
+
+ Adapter->bAllDSDWriteAllow = false;
+ if (IsFlash2x(Adapter) != TRUE) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Flash Does not have 2.x map");
+ return -EINVAL;
}
- break;
- case IOCTL_BCM_SET_ACTIVE_SECTION: {
- enum bcm_flash2x_section_val eFlash2xSectionVal = 0;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SET_ACTIVE_SECTION Called");
+ Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Copy of IOCTL BUFFER failed Status :%d", Status);
+ return -EFAULT;
+ }
- if (IsFlash2x(Adapter) != TRUE) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map");
- return -EINVAL;
- }
+ Status = copy_from_user(&sCopySectStrut, IoBuffer.InputBuffer,
+ sizeof(struct bcm_flash2x_copy_section));
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Copy of Copy_Section_Struct failed with Status :%d",
+ Status);
+ return -EFAULT;
+ }
- Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
- return -EFAULT;
- }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Source SEction :%x", sCopySectStrut.SrcSection);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Destination SEction :%x", sCopySectStrut.DstSection);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "offset :%x", sCopySectStrut.offset);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "NOB :%x", sCopySectStrut.numOfBytes);
- Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer, sizeof(INT));
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed");
- return -EFAULT;
- }
+ if (IsSectionExistInFlash(Adapter, sCopySectStrut.SrcSection) == false) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Source Section<%x> does not exist in Flash ",
+ sCopySectStrut.SrcSection);
+ return -EINVAL;
+ }
- down(&Adapter->NVMRdmWrmLock);
+ if (IsSectionExistInFlash(Adapter, sCopySectStrut.DstSection) == false) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Destinatio Section<%x> does not exist in Flash ",
+ sCopySectStrut.DstSection);
+ return -EINVAL;
+ }
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE)) {
+ if (sCopySectStrut.SrcSection == sCopySectStrut.DstSection) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Source and Destination section should be different");
+ return -EINVAL;
+ }
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
- up(&Adapter->NVMRdmWrmLock);
- return -EACCES;
- }
+ down(&Adapter->NVMRdmWrmLock);
- Status = BcmSetActiveSection(Adapter, eFlash2xSectionVal);
- if (Status)
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Failed to make it's priority Highest. Status %d", Status);
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Device is in Idle/Shutdown Mode\n");
up(&Adapter->NVMRdmWrmLock);
+ return -EACCES;
}
- break;
- case IOCTL_BCM_IDENTIFY_ACTIVE_SECTION: {
- /* Right Now we are taking care of only DSD */
- Adapter->bAllDSDWriteAllow = false;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_IDENTIFY_ACTIVE_SECTION called");
- Status = STATUS_SUCCESS;
+ if (sCopySectStrut.SrcSection == ISO_IMAGE1 ||
+ sCopySectStrut.SrcSection == ISO_IMAGE2) {
+ if (IsNonCDLessDevice(Adapter)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Device is Non-CDLess hence won't have ISO !!");
+ Status = -EINVAL;
+ } else if (sCopySectStrut.numOfBytes == 0) {
+ Status = BcmCopyISO(Adapter, sCopySectStrut);
+ } else {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Partial Copy of ISO section is not Allowed..");
+ Status = STATUS_FAILURE;
+ }
+ up(&Adapter->NVMRdmWrmLock);
+ return Status;
}
- break;
- case IOCTL_BCM_COPY_SECTION: {
- struct bcm_flash2x_copy_section sCopySectStrut = {0};
- Status = STATUS_SUCCESS;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_COPY_SECTION Called");
+ Status = BcmCopySection(Adapter, sCopySectStrut.SrcSection,
+ sCopySectStrut.DstSection,
+ sCopySectStrut.offset,
+ sCopySectStrut.numOfBytes);
+ up(&Adapter->NVMRdmWrmLock);
+ return Status;
+}
- Adapter->bAllDSDWriteAllow = false;
- if (IsFlash2x(Adapter) != TRUE) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map");
+static int bcm_char_ioctl_get_flash_cs_info(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_ioctl_buffer IoBuffer;
+ INT Status = STATUS_SUCCESS;
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ " IOCTL_BCM_GET_FLASH_CS_INFO Called");
+
+ Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Copy of IOCTL BUFFER failed");
+ return -EFAULT;
+ }
+
+ if (Adapter->eNVMType != NVM_FLASH) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Connected device does not have flash");
+ return -EINVAL;
+ }
+
+ if (IsFlash2x(Adapter) == TRUE) {
+ if (IoBuffer.OutputLength < sizeof(struct bcm_flash2x_cs_info))
return -EINVAL;
- }
- Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed Status :%d", Status);
+ if (copy_to_user(IoBuffer.OutputBuffer,
+ Adapter->psFlash2xCSInfo,
+ sizeof(struct bcm_flash2x_cs_info)))
return -EFAULT;
- }
+ } else {
+ if (IoBuffer.OutputLength < sizeof(struct bcm_flash_cs_info))
+ return -EINVAL;
- Status = copy_from_user(&sCopySectStrut, IoBuffer.InputBuffer, sizeof(struct bcm_flash2x_copy_section));
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of Copy_Section_Struct failed with Status :%d", Status);
+ if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlashCSInfo,
+ sizeof(struct bcm_flash_cs_info)))
return -EFAULT;
- }
+ }
+ return Status;
+}
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Source SEction :%x", sCopySectStrut.SrcSection);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Destination SEction :%x", sCopySectStrut.DstSection);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "offset :%x", sCopySectStrut.offset);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "NOB :%x", sCopySectStrut.numOfBytes);
+static int bcm_char_ioctl_select_dsd(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_ioctl_buffer IoBuffer;
+ INT Status = STATUS_FAILURE;
+ UINT SectOfset = 0;
+ enum bcm_flash2x_section_val eFlash2xSectionVal;
- if (IsSectionExistInFlash(Adapter, sCopySectStrut.SrcSection) == false) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Source Section<%x> does not exist in Flash ", sCopySectStrut.SrcSection);
- return -EINVAL;
- }
+ eFlash2xSectionVal = NO_SECTION_VAL;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "IOCTL_BCM_SELECT_DSD Called");
- if (IsSectionExistInFlash(Adapter, sCopySectStrut.DstSection) == false) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Destinatio Section<%x> does not exist in Flash ", sCopySectStrut.DstSection);
- return -EINVAL;
- }
+ if (IsFlash2x(Adapter) != TRUE) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Flash Does not have 2.x map");
+ return -EINVAL;
+ }
- if (sCopySectStrut.SrcSection == sCopySectStrut.DstSection) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Source and Destination section should be different");
- return -EINVAL;
- }
+ Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Copy of IOCTL BUFFER failed");
+ return -EFAULT;
+ }
+ Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer,
+ sizeof(INT));
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Copy of flash section val failed");
+ return -EFAULT;
+ }
- down(&Adapter->NVMRdmWrmLock);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Read Section :%d", eFlash2xSectionVal);
+ if ((eFlash2xSectionVal != DSD0) &&
+ (eFlash2xSectionVal != DSD1) &&
+ (eFlash2xSectionVal != DSD2)) {
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Passed section<%x> is not DSD section",
+ eFlash2xSectionVal);
+ return STATUS_FAILURE;
+ }
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
- up(&Adapter->NVMRdmWrmLock);
- return -EACCES;
- }
+ SectOfset = BcmGetSectionValStartOffset(Adapter, eFlash2xSectionVal);
+ if (SectOfset == INVALID_OFFSET) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Provided Section val <%d> does not exist in Flash 2.x",
+ eFlash2xSectionVal);
+ return -EINVAL;
+ }
- if (sCopySectStrut.SrcSection == ISO_IMAGE1 || sCopySectStrut.SrcSection == ISO_IMAGE2) {
- if (IsNonCDLessDevice(Adapter)) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device is Non-CDLess hence won't have ISO !!");
- Status = -EINVAL;
- } else if (sCopySectStrut.numOfBytes == 0) {
- Status = BcmCopyISO(Adapter, sCopySectStrut);
- } else {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Partial Copy of ISO section is not Allowed..");
- Status = STATUS_FAILURE;
- }
- up(&Adapter->NVMRdmWrmLock);
- return Status;
- }
+ Adapter->bAllDSDWriteAllow = TRUE;
+ Adapter->ulFlashCalStart = SectOfset;
+ Adapter->eActiveDSD = eFlash2xSectionVal;
- Status = BcmCopySection(Adapter, sCopySectStrut.SrcSection,
- sCopySectStrut.DstSection, sCopySectStrut.offset, sCopySectStrut.numOfBytes);
- up(&Adapter->NVMRdmWrmLock);
+ return STATUS_SUCCESS;
+}
+
+static int bcm_char_ioctl_nvm_raw_read(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_nvm_readwrite stNVMRead;
+ struct bcm_ioctl_buffer IoBuffer;
+ unsigned int NOB;
+ INT BuffSize;
+ INT ReadOffset = 0;
+ UINT ReadBytes = 0;
+ PUCHAR pReadBuff;
+ void __user *OutPutBuff;
+ INT Status = STATUS_FAILURE;
+
+ if (Adapter->eNVMType != NVM_FLASH) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "NVM TYPE is not Flash");
+ return -EINVAL;
}
- break;
- case IOCTL_BCM_GET_FLASH_CS_INFO: {
- Status = STATUS_SUCCESS;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, " IOCTL_BCM_GET_FLASH_CS_INFO Called");
+ /* Copy Ioctl Buffer structure */
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "copy_from_user 1 failed\n");
+ return -EFAULT;
+ }
- Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
- return -EFAULT;
- }
+ if (copy_from_user(&stNVMRead, IoBuffer.OutputBuffer,
+ sizeof(struct bcm_nvm_readwrite)))
+ return -EFAULT;
- if (Adapter->eNVMType != NVM_FLASH) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Connected device does not have flash");
- Status = -EINVAL;
- break;
- }
+ NOB = stNVMRead.uiNumBytes;
+ /* In Raw-Read max Buff size : 64MB */
- if (IsFlash2x(Adapter) == TRUE) {
- if (IoBuffer.OutputLength < sizeof(struct bcm_flash2x_cs_info))
- return -EINVAL;
+ if (NOB > DEFAULT_BUFF_SIZE)
+ BuffSize = DEFAULT_BUFF_SIZE;
+ else
+ BuffSize = NOB;
- if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlash2xCSInfo, sizeof(struct bcm_flash2x_cs_info)))
- return -EFAULT;
- } else {
- if (IoBuffer.OutputLength < sizeof(struct bcm_flash_cs_info))
- return -EINVAL;
+ ReadOffset = stNVMRead.uiOffset;
+ OutPutBuff = stNVMRead.pBuffer;
- if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlashCSInfo, sizeof(struct bcm_flash_cs_info)))
- return -EFAULT;
- }
+ pReadBuff = kzalloc(BuffSize , GFP_KERNEL);
+ if (pReadBuff == NULL) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Memory allocation failed for Flash 2.x Read Structure");
+ return -ENOMEM;
}
- break;
+ down(&Adapter->NVMRdmWrmLock);
- case IOCTL_BCM_SELECT_DSD: {
- UINT SectOfset = 0;
- enum bcm_flash2x_section_val eFlash2xSectionVal;
- eFlash2xSectionVal = NO_SECTION_VAL;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SELECT_DSD Called");
+ if ((Adapter->IdleMode == TRUE) ||
+ (Adapter->bShutStatus == TRUE) ||
+ (Adapter->bPreparingForLowPowerMode == TRUE)) {
- if (IsFlash2x(Adapter) != TRUE) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map");
- return -EINVAL;
- }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
+ kfree(pReadBuff);
+ up(&Adapter->NVMRdmWrmLock);
+ return -EACCES;
+ }
+
+ Adapter->bFlashRawRead = TRUE;
+
+ while (NOB) {
+ if (NOB > DEFAULT_BUFF_SIZE)
+ ReadBytes = DEFAULT_BUFF_SIZE;
+ else
+ ReadBytes = NOB;
- Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
+ /* Reading the data from Flash 2.x */
+ Status = BeceemNVMRead(Adapter, (PUINT)pReadBuff,
+ ReadOffset, ReadBytes);
if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
- return -EFAULT;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Flash 2x read err with Status :%d", Status);
+ break;
}
- Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer, sizeof(INT));
+
+ BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL, pReadBuff, ReadBytes);
+
+ Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes);
if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
+ "Copy to use failed with status :%d", Status);
+ up(&Adapter->NVMRdmWrmLock);
+ kfree(pReadBuff);
return -EFAULT;
}
+ NOB = NOB - ReadBytes;
+ if (NOB) {
+ ReadOffset = ReadOffset + ReadBytes;
+ OutPutBuff = OutPutBuff + ReadBytes;
+ }
+ }
+ Adapter->bFlashRawRead = false;
+ up(&Adapter->NVMRdmWrmLock);
+ kfree(pReadBuff);
+ return Status;
+}
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Read Section :%d", eFlash2xSectionVal);
- if ((eFlash2xSectionVal != DSD0) &&
- (eFlash2xSectionVal != DSD1) &&
- (eFlash2xSectionVal != DSD2)) {
+static int bcm_char_ioctl_cntrlmsg_mask(void __user *argp,
+ struct bcm_mini_adapter *Adapter, struct bcm_tarang_data *pTarang)
+{
+ struct bcm_ioctl_buffer IoBuffer;
+ INT Status = STATUS_FAILURE;
+ ULONG RxCntrlMsgBitMask = 0;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Passed section<%x> is not DSD section", eFlash2xSectionVal);
- return STATUS_FAILURE;
- }
+ /* Copy Ioctl Buffer structure */
+ Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "copy of Ioctl buffer is failed from user space");
+ return -EFAULT;
+ }
- SectOfset = BcmGetSectionValStartOffset(Adapter, eFlash2xSectionVal);
- if (SectOfset == INVALID_OFFSET) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Provided Section val <%d> does not exist in Flash 2.x", eFlash2xSectionVal);
- return -EINVAL;
- }
+ if (IoBuffer.InputLength != sizeof(unsigned long))
+ return -EINVAL;
- Adapter->bAllDSDWriteAllow = TRUE;
- Adapter->ulFlashCalStart = SectOfset;
- Adapter->eActiveDSD = eFlash2xSectionVal;
+ Status = copy_from_user(&RxCntrlMsgBitMask,
+ IoBuffer.InputBuffer, IoBuffer.InputLength);
+ if (Status) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "copy of control bit mask failed from user space");
+ return -EFAULT;
}
- Status = STATUS_SUCCESS;
- break;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "\n Got user defined cntrl msg bit mask :%lx",
+ RxCntrlMsgBitMask);
+ pTarang->RxCntrlMsgBitMask = RxCntrlMsgBitMask;
- case IOCTL_BCM_NVM_RAW_READ: {
- struct bcm_nvm_readwrite stNVMRead;
- INT NOB;
- INT BuffSize;
- INT ReadOffset = 0;
- UINT ReadBytes = 0;
- PUCHAR pReadBuff;
- void __user *OutPutBuff;
+ return Status;
+}
- if (Adapter->eNVMType != NVM_FLASH) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "NVM TYPE is not Flash");
- return -EINVAL;
- }
+static int bcm_char_ioctl_get_device_driver_info(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_driver_info DevInfo;
+ struct bcm_ioctl_buffer IoBuffer;
- /* Copy Ioctl Buffer structure */
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "copy_from_user 1 failed\n");
- return -EFAULT;
- }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL, "Called IOCTL_BCM_GET_DEVICE_DRIVER_INFO\n");
- if (copy_from_user(&stNVMRead, IoBuffer.OutputBuffer, sizeof(struct bcm_nvm_readwrite)))
- return -EFAULT;
+ memset(&DevInfo, 0, sizeof(DevInfo));
+ DevInfo.MaxRDMBufferSize = BUFFER_4K;
+ DevInfo.u32DSDStartOffset = EEPROM_CALPARAM_START;
+ DevInfo.u32RxAlignmentCorrection = 0;
+ DevInfo.u32NVMType = Adapter->eNVMType;
+ DevInfo.u32InterfaceType = BCM_USB;
- NOB = stNVMRead.uiNumBytes;
- /* In Raw-Read max Buff size : 64MB */
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
- if (NOB > DEFAULT_BUFF_SIZE)
- BuffSize = DEFAULT_BUFF_SIZE;
- else
- BuffSize = NOB;
+ if (IoBuffer.OutputLength < sizeof(DevInfo))
+ return -EINVAL;
- ReadOffset = stNVMRead.uiOffset;
- OutPutBuff = stNVMRead.pBuffer;
+ if (copy_to_user(IoBuffer.OutputBuffer, &DevInfo, sizeof(DevInfo)))
+ return -EFAULT;
- pReadBuff = kzalloc(BuffSize , GFP_KERNEL);
- if (pReadBuff == NULL) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed for Flash 2.x Read Structure");
- Status = -ENOMEM;
- break;
- }
- down(&Adapter->NVMRdmWrmLock);
+ return STATUS_SUCCESS;
+}
- if ((Adapter->IdleMode == TRUE) ||
- (Adapter->bShutStatus == TRUE) ||
- (Adapter->bPreparingForLowPowerMode == TRUE)) {
+static int bcm_char_ioctl_time_since_net_entry(void __user *argp,
+ struct bcm_mini_adapter *Adapter)
+{
+ struct bcm_time_elapsed stTimeElapsedSinceNetEntry = {0};
+ struct bcm_ioctl_buffer IoBuffer;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n");
- kfree(pReadBuff);
- up(&Adapter->NVMRdmWrmLock);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "IOCTL_BCM_TIME_SINCE_NET_ENTRY called");
+
+ if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
+ return -EFAULT;
+
+ if (IoBuffer.OutputLength < sizeof(struct bcm_time_elapsed))
+ return -EINVAL;
+
+ stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry =
+ get_seconds() - Adapter->liTimeSinceLastNetEntry;
+
+ if (copy_to_user(IoBuffer.OutputBuffer, &stTimeElapsedSinceNetEntry,
+ sizeof(struct bcm_time_elapsed)))
+ return -EFAULT;
+
+ return STATUS_SUCCESS;
+}
+
+
+static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
+{
+ struct bcm_tarang_data *pTarang = filp->private_data;
+ void __user *argp = (void __user *)arg;
+ struct bcm_mini_adapter *Adapter = pTarang->Adapter;
+ INT Status = STATUS_FAILURE;
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "Parameters Passed to control IOCTL cmd=0x%X arg=0x%lX",
+ cmd, arg);
+
+ if (_IOC_TYPE(cmd) != BCM_IOCTL)
+ return -EFAULT;
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ Status = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ Status = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
+ else if (_IOC_NONE == (_IOC_DIR(cmd) & _IOC_NONE))
+ Status = STATUS_SUCCESS;
+
+ if (Status)
+ return -EFAULT;
+
+ if (Adapter->device_removed)
+ return -EFAULT;
+
+ if (false == Adapter->fw_download_done) {
+ switch (cmd) {
+ case IOCTL_MAC_ADDR_REQ:
+ case IOCTL_LINK_REQ:
+ case IOCTL_CM_REQUEST:
+ case IOCTL_SS_INFO_REQ:
+ case IOCTL_SEND_CONTROL_MESSAGE:
+ case IOCTL_IDLE_REQ:
+ case IOCTL_BCM_GPIO_SET_REQUEST:
+ case IOCTL_BCM_GPIO_STATUS_REQUEST:
return -EACCES;
+ default:
+ break;
}
+ }
- Adapter->bFlashRawRead = TRUE;
+ Status = vendorextnIoctl(Adapter, cmd, arg);
+ if (Status != CONTINUE_COMMON_PATH)
+ return Status;
- while (NOB) {
- if (NOB > DEFAULT_BUFF_SIZE)
- ReadBytes = DEFAULT_BUFF_SIZE;
- else
- ReadBytes = NOB;
+ switch (cmd) {
+ /* Rdms for Swin Idle... */
+ case IOCTL_BCM_REGISTER_READ_PRIVATE:
+ Status = bcm_char_ioctl_reg_read_private(argp, Adapter);
+ return Status;
- /* Reading the data from Flash 2.x */
- Status = BeceemNVMRead(Adapter, (PUINT)pReadBuff, ReadOffset, ReadBytes);
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash 2x read err with Status :%d", Status);
- break;
- }
+ case IOCTL_BCM_REGISTER_WRITE_PRIVATE:
+ Status = bcm_char_ioctl_reg_write_private(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_REGISTER_READ:
+ case IOCTL_BCM_EEPROM_REGISTER_READ:
+ Status = bcm_char_ioctl_eeprom_reg_read(argp, Adapter);
+ return Status;
- BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, pReadBuff, ReadBytes);
+ case IOCTL_BCM_REGISTER_WRITE:
+ case IOCTL_BCM_EEPROM_REGISTER_WRITE:
+ Status = bcm_char_ioctl_eeprom_reg_write(argp, Adapter, cmd);
+ return Status;
- Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes);
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy to use failed with status :%d", Status);
- up(&Adapter->NVMRdmWrmLock);
- kfree(pReadBuff);
- return -EFAULT;
- }
- NOB = NOB - ReadBytes;
- if (NOB) {
- ReadOffset = ReadOffset + ReadBytes;
- OutPutBuff = OutPutBuff + ReadBytes;
- }
- }
- Adapter->bFlashRawRead = false;
- up(&Adapter->NVMRdmWrmLock);
- kfree(pReadBuff);
+ case IOCTL_BCM_GPIO_SET_REQUEST:
+ Status = bcm_char_ioctl_gpio_set_request(argp, Adapter);
+ return Status;
+
+ case BCM_LED_THREAD_STATE_CHANGE_REQ:
+ Status = bcm_char_ioctl_led_thread_state_change_req(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_GPIO_STATUS_REQUEST:
+ Status = bcm_char_ioctl_gpio_status_request(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_GPIO_MULTI_REQUEST:
+ Status = bcm_char_ioctl_gpio_multi_request(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_GPIO_MODE_REQUEST:
+ Status = bcm_char_ioctl_gpio_mode_request(argp, Adapter);
+ return Status;
+
+ case IOCTL_MAC_ADDR_REQ:
+ case IOCTL_LINK_REQ:
+ case IOCTL_CM_REQUEST:
+ case IOCTL_SS_INFO_REQ:
+ case IOCTL_SEND_CONTROL_MESSAGE:
+ case IOCTL_IDLE_REQ:
+ Status = bcm_char_ioctl_misc_request(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_BUFFER_DOWNLOAD_START:
+ Status = bcm_char_ioctl_buffer_download_start(Adapter);
+ return Status;
+
+ case IOCTL_BCM_BUFFER_DOWNLOAD:
+ Status = bcm_char_ioctl_buffer_download(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_BUFFER_DOWNLOAD_STOP:
+ Status = bcm_char_ioctl_buffer_download_stop(argp, Adapter);
+ return Status;
+
+
+ case IOCTL_BE_BUCKET_SIZE:
+ Status = 0;
+ if (get_user(Adapter->BEBucketSize, (unsigned long __user *)arg))
+ Status = -EFAULT;
+ break;
+
+ case IOCTL_RTPS_BUCKET_SIZE:
+ Status = 0;
+ if (get_user(Adapter->rtPSBucketSize, (unsigned long __user *)arg))
+ Status = -EFAULT;
break;
- }
- case IOCTL_BCM_CNTRLMSG_MASK: {
- ULONG RxCntrlMsgBitMask = 0;
+ case IOCTL_CHIP_RESET:
+ Status = bcm_char_ioctl_chip_reset(Adapter);
+ return Status;
- /* Copy Ioctl Buffer structure */
- Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer));
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "copy of Ioctl buffer is failed from user space");
- return -EFAULT;
- }
+ case IOCTL_QOS_THRESHOLD:
+ Status = bcm_char_ioctl_qos_threshold(arg, Adapter);
+ return Status;
- if (IoBuffer.InputLength != sizeof(unsigned long)) {
- Status = -EINVAL;
- break;
- }
+ case IOCTL_DUMP_PACKET_INFO:
+ DumpPackInfo(Adapter);
+ DumpPhsRules(&Adapter->stBCMPhsContext);
+ Status = STATUS_SUCCESS;
+ break;
- Status = copy_from_user(&RxCntrlMsgBitMask, IoBuffer.InputBuffer, IoBuffer.InputLength);
- if (Status) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "copy of control bit mask failed from user space");
+ case IOCTL_GET_PACK_INFO:
+ if (copy_to_user(argp, &Adapter->PackInfo,
+ sizeof(struct bcm_packet_info)*NO_OF_QUEUES))
return -EFAULT;
+ Status = STATUS_SUCCESS;
+ break;
+
+ case IOCTL_BCM_SWITCH_TRANSFER_MODE:
+ Status = bcm_char_ioctl_switch_transfer_mode(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_GET_DRIVER_VERSION:
+ Status = bcm_char_ioctl_get_driver_version(argp);
+ return Status;
+
+ case IOCTL_BCM_GET_CURRENT_STATUS:
+ Status = bcm_char_ioctl_get_current_status(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_SET_MAC_TRACING:
+ Status = bcm_char_ioctl_set_mac_tracing(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_GET_DSX_INDICATION:
+ Status = bcm_char_ioctl_get_dsx_indication(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_GET_HOST_MIBS:
+ Status = bcm_char_ioctl_get_host_mibs(argp, Adapter, pTarang);
+ return Status;
+
+ case IOCTL_BCM_WAKE_UP_DEVICE_FROM_IDLE:
+ if ((false == Adapter->bTriedToWakeUpFromlowPowerMode) &&
+ (TRUE == Adapter->IdleMode)) {
+ Adapter->usIdleModePattern = ABORT_IDLE_MODE;
+ Adapter->bWakeUpDevice = TRUE;
+ wake_up(&Adapter->process_rx_cntrlpkt);
}
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\n Got user defined cntrl msg bit mask :%lx", RxCntrlMsgBitMask);
- pTarang->RxCntrlMsgBitMask = RxCntrlMsgBitMask;
- }
- break;
- case IOCTL_BCM_GET_DEVICE_DRIVER_INFO: {
- struct bcm_driver_info DevInfo;
+ Status = STATUS_SUCCESS;
+ break;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Called IOCTL_BCM_GET_DEVICE_DRIVER_INFO\n");
+ case IOCTL_BCM_BULK_WRM:
+ Status = bcm_char_ioctl_bulk_wrm(argp, Adapter, cmd);
+ return Status;
- memset(&DevInfo, 0, sizeof(DevInfo));
- DevInfo.MaxRDMBufferSize = BUFFER_4K;
- DevInfo.u32DSDStartOffset = EEPROM_CALPARAM_START;
- DevInfo.u32RxAlignmentCorrection = 0;
- DevInfo.u32NVMType = Adapter->eNVMType;
- DevInfo.u32InterfaceType = BCM_USB;
+ case IOCTL_BCM_GET_NVM_SIZE:
+ Status = bcm_char_ioctl_get_nvm_size(argp, Adapter);
+ return Status;
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ case IOCTL_BCM_CAL_INIT:
+ Status = bcm_char_ioctl_cal_init(argp, Adapter);
+ return Status;
- if (IoBuffer.OutputLength < sizeof(DevInfo))
- return -EINVAL;
+ case IOCTL_BCM_SET_DEBUG:
+ Status = bcm_char_ioctl_set_debug(argp, Adapter);
+ return Status;
- if (copy_to_user(IoBuffer.OutputBuffer, &DevInfo, sizeof(DevInfo)))
- return -EFAULT;
- }
- break;
+ case IOCTL_BCM_NVM_READ:
+ case IOCTL_BCM_NVM_WRITE:
+ Status = bcm_char_ioctl_nvm_rw(argp, Adapter, cmd);
+ return Status;
- case IOCTL_BCM_TIME_SINCE_NET_ENTRY: {
- struct bcm_time_elapsed stTimeElapsedSinceNetEntry = {0};
+ case IOCTL_BCM_FLASH2X_SECTION_READ:
+ Status = bcm_char_ioctl_flash2x_section_read(argp, Adapter);
+ return Status;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_TIME_SINCE_NET_ENTRY called");
+ case IOCTL_BCM_FLASH2X_SECTION_WRITE:
+ Status = bcm_char_ioctl_flash2x_section_write(argp, Adapter);
+ return Status;
- if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
- return -EFAULT;
+ case IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP:
+ Status = bcm_char_ioctl_flash2x_section_bitmap(argp, Adapter);
+ return Status;
- if (IoBuffer.OutputLength < sizeof(struct bcm_time_elapsed))
- return -EINVAL;
+ case IOCTL_BCM_SET_ACTIVE_SECTION:
+ Status = bcm_char_ioctl_set_active_section(argp, Adapter);
+ return Status;
- stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = get_seconds() - Adapter->liTimeSinceLastNetEntry;
+ case IOCTL_BCM_IDENTIFY_ACTIVE_SECTION:
+ /* Right Now we are taking care of only DSD */
+ Adapter->bAllDSDWriteAllow = false;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+ "IOCTL_BCM_IDENTIFY_ACTIVE_SECTION called");
+ Status = STATUS_SUCCESS;
+ break;
- if (copy_to_user(IoBuffer.OutputBuffer, &stTimeElapsedSinceNetEntry, sizeof(struct bcm_time_elapsed)))
- return -EFAULT;
- }
- break;
+ case IOCTL_BCM_COPY_SECTION:
+ Status = bcm_char_ioctl_copy_section(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_GET_FLASH_CS_INFO:
+ Status = bcm_char_ioctl_get_flash_cs_info(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_SELECT_DSD:
+ Status = bcm_char_ioctl_select_dsd(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_NVM_RAW_READ:
+ Status = bcm_char_ioctl_nvm_raw_read(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_CNTRLMSG_MASK:
+ Status = bcm_char_ioctl_cntrlmsg_mask(argp, Adapter, pTarang);
+ return Status;
+
+ case IOCTL_BCM_GET_DEVICE_DRIVER_INFO:
+ Status = bcm_char_ioctl_get_device_driver_info(argp, Adapter);
+ return Status;
+
+ case IOCTL_BCM_TIME_SINCE_NET_ENTRY:
+ Status = bcm_char_ioctl_time_since_net_entry(argp, Adapter);
+ return Status;
case IOCTL_CLOSE_NOTIFICATION:
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_CLOSE_NOTIFICATION");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG,
+ DBG_LVL_ALL, "IOCTL_CLOSE_NOTIFICATION");
break;
default:
diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c
index 8dfdd2732bdc..95a2358267ba 100644
--- a/drivers/staging/bcm/Bcmnet.c
+++ b/drivers/staging/bcm/Bcmnet.c
@@ -40,7 +40,7 @@ static INT bcm_close(struct net_device *dev)
}
static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
return ClassifyPacket(netdev_priv(dev), skb);
}
diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c
index cc91b5e934aa..632f81a7c63f 100644
--- a/drivers/staging/bcm/CmHost.c
+++ b/drivers/staging/bcm/CmHost.c
@@ -975,8 +975,8 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
- DBG_LVL_ALL, "u8EthernetSourceMACAddress[6]: "
- "%pM", psfCSType->cCPacketClassificationRule.
+ DBG_LVL_ALL, "u8EthernetSourceMACAddress[6]: %pM",
+ psfCSType->cCPacketClassificationRule.
u8EthernetSourceMACAddress);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthertypeLength: 0x%02X ",
@@ -1092,18 +1092,16 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
- DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: "
- "0x%*ph ", 4, psfCSType->
- cCPacketClassificationRule.
+ DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: 0x%*ph ",
+ 4, psfCSType->cCPacketClassificationRule.
u8ProtocolSourcePortRange);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRangeLength: 0x%02X ",
psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
- DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: "
- "0x%*ph ", 4, psfCSType->
- cCPacketClassificationRule.
+ DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: 0x%*ph ",
+ 4, psfCSType->cCPacketClassificationRule.
u8ProtocolDestPortRange);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetDestMacAddressLength: 0x%02X ",
@@ -1118,8 +1116,8 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
- DBG_LVL_ALL, "u8EthernetSourceMACAddress[6]: "
- "%pM", psfCSType->cCPacketClassificationRule.
+ DBG_LVL_ALL, "u8EthernetSourceMACAddress[6]: %pM",
+ psfCSType->cCPacketClassificationRule.
u8EthernetSourceMACAddress);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthertypeLength: 0x%02X ", psfCSType->cCPacketClassificationRule.u8EthertypeLength);
@@ -1637,6 +1635,8 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* <Pointer to
struct bcm_add_indication_alt *pstAddIndication = NULL;
struct bcm_change_indication *pstChangeIndication = NULL;
struct bcm_leader *pLeader = NULL;
+ INT uiSearchRuleIndex = 0;
+ ULONG ulSFID;
/*
* Otherwise the message contains a target address from where we need to
@@ -1660,7 +1660,6 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* <Pointer to
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "### TID RECEIVED %d\n", pstAddIndication->u16TID);
switch (pstAddIndication->u8Type) {
case DSA_REQ:
- {
pLeader->PLength = sizeof(struct bcm_add_indication_alt);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Sending DSA Response....\n");
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSA RESPONSE TO MAC %d", pLeader->PLength);
@@ -1671,22 +1670,16 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* <Pointer to
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " VCID = %x", ntohs(pstAddIndication->u16VCID));
CopyBufferToControlPacket(Adapter, (PVOID)Adapter->caDsxReqResp);
kfree(pstAddIndication);
- }
- break;
+ break;
case DSA_RSP:
- {
pLeader->PLength = sizeof(struct bcm_add_indication_alt);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSA ACK TO MAC %d",
pLeader->PLength);
*((struct bcm_add_indication_alt *)&(Adapter->caDsxReqResp[LEADER_SIZE]))
= *pstAddIndication;
((struct bcm_add_indication_alt *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSA_ACK;
-
- } /* no break here..we should go down. */
+ /* FALLTHROUGH */
case DSA_ACK:
- {
- UINT uiSearchRuleIndex = 0;
-
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "VCID:0x%X",
ntohs(pstAddIndication->u16VCID));
uiSearchRuleIndex = SearchFreeSfid(Adapter);
@@ -1694,7 +1687,7 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* <Pointer to
uiSearchRuleIndex);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Direction:0x%X ",
pstAddIndication->u8Direction);
- if ((uiSearchRuleIndex < NO_OF_QUEUES)) {
+ if (uiSearchRuleIndex < NO_OF_QUEUES) {
Adapter->PackInfo[uiSearchRuleIndex].ucDirection =
pstAddIndication->u8Direction;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "bValid:0x%X ",
@@ -1769,10 +1762,8 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* <Pointer to
kfree(pstAddIndication);
return false;
}
- }
- break;
+ break;
case DSC_REQ:
- {
pLeader->PLength = sizeof(struct bcm_change_indication);
pstChangeIndication = (struct bcm_change_indication *)pstAddIndication;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSC RESPONSE TO MAC %d", pLeader->PLength);
@@ -1782,26 +1773,21 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* <Pointer to
CopyBufferToControlPacket(Adapter, (PVOID)Adapter->caDsxReqResp);
kfree(pstAddIndication);
- }
- break;
+ break;
case DSC_RSP:
- {
pLeader->PLength = sizeof(struct bcm_change_indication);
pstChangeIndication = (struct bcm_change_indication *)pstAddIndication;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSC ACK TO MAC %d", pLeader->PLength);
*((struct bcm_change_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *pstChangeIndication;
((struct bcm_change_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSC_ACK;
- }
+ /* FALLTHROUGH */
case DSC_ACK:
- {
- UINT uiSearchRuleIndex = 0;
-
pstChangeIndication = (struct bcm_change_indication *)pstAddIndication;
uiSearchRuleIndex = SearchSfid(Adapter, ntohl(pstChangeIndication->sfActiveSet.u32SFID));
if (uiSearchRuleIndex > NO_OF_QUEUES-1)
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "SF doesn't exist for which DSC_ACK is received");
- if ((uiSearchRuleIndex < NO_OF_QUEUES)) {
+ if (uiSearchRuleIndex < NO_OF_QUEUES) {
Adapter->PackInfo[uiSearchRuleIndex].ucDirection = pstChangeIndication->u8Direction;
if (pstChangeIndication->sfActiveSet.bValid == TRUE)
Adapter->PackInfo[uiSearchRuleIndex].bActiveSet = TRUE;
@@ -1849,13 +1835,8 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* <Pointer to
kfree(pstAddIndication);
return false;
}
- }
- break;
+ break;
case DSD_REQ:
- {
- UINT uiSearchRuleIndex;
- ULONG ulSFID;
-
pLeader->PLength = sizeof(struct bcm_del_indication);
*((struct bcm_del_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *((struct bcm_del_indication *)pstAddIndication);
@@ -1872,12 +1853,10 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* <Pointer to
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSD RESPONSE TO MAC");
((struct bcm_del_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSD_RSP;
CopyBufferToControlPacket(Adapter, (PVOID)Adapter->caDsxReqResp);
- }
+ /* FALLTHROUGH */
case DSD_RSP:
- {
/* Do nothing as SF has already got Deleted */
- }
- break;
+ break;
case DSD_ACK:
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSD ACK Rcd, let App handle it\n");
break;
diff --git a/drivers/staging/bcm/DDRInit.c b/drivers/staging/bcm/DDRInit.c
index ed285b2d892d..f1d7cb82fd7e 100644
--- a/drivers/staging/bcm/DDRInit.c
+++ b/drivers/staging/bcm/DDRInit.c
@@ -3,7 +3,7 @@
#define DDR_DUMP_INTERNAL_DEVICE_MEMORY 0xBFC02B00
-#define MIPS_CLOCK_REG 0x0f000820
+#define MIPS_CLOCK_REG 0x0f000820
/* DDR INIT-133Mhz */
#define T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 12 /* index for 0x0F007000 */
@@ -818,13 +818,13 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
if ((Adapter->chip_id != BCS220_2) &&
(Adapter->chip_id != BCS220_2BC) &&
(Adapter->chip_id != BCS220_3)) {
- retval = rdmalt(Adapter,(UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue));
+ retval = rdmalt(Adapter, (UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue));
if (retval < 0) {
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
uiResetValue |= 0x44;
- retval = wrmalt(Adapter,(UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue));
+ retval = wrmalt(Adapter, (UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue));
if (retval < 0) {
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
@@ -871,7 +871,7 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
case 0xbece0121:
case 0xbece0130:
case 0xbece0300:
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "DDR Setting: %x\n", Adapter->DDRSetting);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "DDR Setting: %x\n", Adapter->DDRSetting);
switch (Adapter->DDRSetting) {
case DDR_80_MHZ:
psDDRSetting = asT3_DDRSetting80MHz;
@@ -933,7 +933,7 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
}
value = 0;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Register Count is =%lu\n", RegCount);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Register Count is =%lu\n", RegCount);
while (RegCount && !retval) {
if (uiClockSetting && psDDRSetting->ulRegAddress == MIPS_CLOCK_REG)
value = uiClockSetting;
@@ -990,12 +990,12 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
* we will change this when we will have internal PMU.
*/
if (Adapter->PmuMode == HYBRID_MODE_7C) {
- retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
+ retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if (retval < 0) {
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
- retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
+ retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if (retval < 0) {
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
@@ -1006,12 +1006,12 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
- retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
+ retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if (retval < 0) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
- retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
+ retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if (retval < 0) {
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
@@ -1024,12 +1024,12 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
}
} else if (Adapter->PmuMode == HYBRID_MODE_6) {
- retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
+ retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if (retval < 0) {
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
- retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
+ retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if (retval < 0) {
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
@@ -1040,12 +1040,12 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
- retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
+ retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if (retval < 0) {
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
- retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
+ retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if (retval < 0) {
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
@@ -1094,8 +1094,8 @@ int download_ddr_settings(struct bcm_mini_adapter *Adapter)
RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ;
psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ;
break;
- default:
- return -EINVAL;
+ default:
+ return -EINVAL;
}
break;
@@ -1215,7 +1215,7 @@ int download_ddr_settings(struct bcm_mini_adapter *Adapter)
ul_ddr_setting_load_addr += sizeof(ULONG);
if (!retval) {
if (bOverrideSelfRefresh && (psDDRSetting->ulRegAddress == 0x0F007018)) {
- value = (psDDRSetting->ulRegValue |(1<<8));
+ value = (psDDRSetting->ulRegValue | (1<<8));
if (STATUS_SUCCESS != wrmalt(Adapter, ul_ddr_setting_load_addr,
&value, sizeof(value))) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c
index 94f32728f7c8..7c04c73e3bc8 100644
--- a/drivers/staging/bcm/InterfaceInit.c
+++ b/drivers/staging/bcm/InterfaceInit.c
@@ -1,5 +1,5 @@
#include "headers.h"
-
+#include <linux/usb/ch9.h>
static struct usb_device_id InterfaceUsbtable[] = {
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) },
@@ -30,19 +30,22 @@ static void InterfaceAdapterFree(struct bcm_interface_adapter *psIntfAdapter)
int i = 0;
/* Wake up the wait_queue... */
- if (psIntfAdapter->psAdapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) {
+ if (psIntfAdapter->psAdapter->LEDInfo.led_thread_running &
+ BCM_LED_THREAD_RUNNING_ACTIVELY) {
psIntfAdapter->psAdapter->DriverState = DRIVER_HALT;
wake_up(&psIntfAdapter->psAdapter->LEDInfo.notify_led_event);
}
reset_card_proc(psIntfAdapter->psAdapter);
/*
- * worst case time taken by the RDM/WRM will be 5 sec. will check after every 100 ms
- * to accertain the device is not being accessed. After this No RDM/WRM should be made.
+ * worst case time taken by the RDM/WRM will be 5 sec. will check after
+ * every 100 ms to accertain the device is not being accessed. After
+ * this No RDM/WRM should be made.
*/
while (psIntfAdapter->psAdapter->DeviceAccess) {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "Device is being accessed.\n");
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT,
+ DRV_ENTRY, DBG_LVL_ALL,
+ "Device is being accessed.\n");
msleep(100);
}
/* Free interrupt URB */
@@ -71,6 +74,7 @@ static void ConfigureEndPointTypesThroughEEPROM(struct bcm_mini_adapter *Adapter
{
u32 ulReg;
int bytes;
+ struct bcm_interface_adapter *interfaceAdapter;
/* Program EP2 MAX_PKT_SIZE */
ulReg = ntohl(EP2_MPS_REG);
@@ -80,7 +84,9 @@ static void ConfigureEndPointTypesThroughEEPROM(struct bcm_mini_adapter *Adapter
ulReg = ntohl(EP2_CFG_REG);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x132, 4, TRUE);
- if (((struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter))->bHighSpeedDevice == TRUE) {
+ interfaceAdapter =
+ (struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter);
+ if (interfaceAdapter->bHighSpeedDevice) {
ulReg = ntohl(EP2_CFG_INT);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);
} else {
@@ -98,8 +104,8 @@ static void ConfigureEndPointTypesThroughEEPROM(struct bcm_mini_adapter *Adapter
/* Program TX EP as interrupt(Alternate Setting) */
bytes = rdmalt(Adapter, 0x0F0110F8, &ulReg, sizeof(u32));
if (bytes < 0) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "reading of Tx EP failed\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY,
+ DBG_LVL_ALL, "reading of Tx EP failed\n");
return;
}
ulReg |= 0x6;
@@ -150,7 +156,8 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi
struct net_device *ndev;
/* Reserve one extra queue for the bit-bucket */
- ndev = alloc_etherdev_mq(sizeof(struct bcm_mini_adapter), NO_OF_QUEUES+1);
+ ndev = alloc_etherdev_mq(sizeof(struct bcm_mini_adapter),
+ NO_OF_QUEUES + 1);
if (ndev == NULL) {
dev_err(&udev->dev, DRV_NAME ": no memory for device\n");
return -ENOMEM;
@@ -169,13 +176,14 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi
/*
* Technically, one can start using BCM_DEBUG_PRINT after this point.
- * However, realize that by default the Type/Subtype bitmaps are all zero now;
- * so no prints will actually appear until the TestApp turns on debug paths via
- * the ioctl(); so practically speaking, in early init, no logging happens.
+ * However, realize that by default the Type/Subtype bitmaps are all
+ * zero now; so no prints will actually appear until the TestApp turns
+ * on debug paths via the ioctl(); so practically speaking, in early
+ * init, no logging happens.
*
- * A solution (used below): we explicitly set the bitmaps to 1 for Type=DBG_TYPE_INITEXIT
- * and ALL subtype's of the same. Now all bcm debug statements get logged, enabling debug
- * during early init.
+ * A solution (used below): we explicitly set the bitmaps to 1 for
+ * Type=DBG_TYPE_INITEXIT and ALL subtype's of the same. Now all bcm
+ * debug statements get logged, enabling debug during early init.
* Further, we turn this OFF once init_module() completes.
*/
@@ -191,7 +199,7 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi
/* Allocate interface adapter structure */
psIntfAdapter = kzalloc(sizeof(struct bcm_interface_adapter),
- GFP_KERNEL);
+ GFP_KERNEL);
if (psIntfAdapter == NULL) {
AdapterFree(psAdapter);
return -ENOMEM;
@@ -205,7 +213,7 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi
usb_set_intfdata(intf, psIntfAdapter);
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "psIntfAdapter 0x%p\n", psIntfAdapter);
+ "psIntfAdapter 0x%p\n", psIntfAdapter);
retval = InterfaceAdapterInit(psIntfAdapter);
if (retval) {
/* If the Firmware/Cfg File is not present
@@ -213,12 +221,13 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi
* download the files.
*/
if (-ENOENT == retval) {
- BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "File Not Found. Use app to download.\n");
+ BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY,
+ DBG_LVL_ALL,
+ "File Not Found. Use app to download.\n");
return STATUS_SUCCESS;
}
- BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "InterfaceAdapterInit failed.\n");
+ BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY,
+ DBG_LVL_ALL, "InterfaceAdapterInit failed.\n");
usb_set_intfdata(intf, NULL);
udev = interface_to_usbdev(intf);
usb_put_dev(udev);
@@ -228,7 +237,10 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi
if (psAdapter->chip_id > T3) {
uint32_t uiNackZeroLengthInt = 4;
- retval = wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, &uiNackZeroLengthInt, sizeof(uiNackZeroLengthInt));
+ retval =
+ wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT,
+ &uiNackZeroLengthInt,
+ sizeof(uiNackZeroLengthInt));
if (retval)
return retval;
}
@@ -242,9 +254,11 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi
intf->needs_remote_wakeup = 1;
usb_enable_autosuspend(udev);
device_init_wakeup(&intf->dev, 1);
- INIT_WORK(&psIntfAdapter->usbSuspendWork, putUsbSuspend);
- BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "Enabling USB Auto-Suspend\n");
+ INIT_WORK(&psIntfAdapter->usbSuspendWork,
+ putUsbSuspend);
+ BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY,
+ DBG_LVL_ALL,
+ "Enabling USB Auto-Suspend\n");
#endif
} else {
intf->needs_remote_wakeup = 0;
@@ -271,7 +285,7 @@ static void usbbcm_disconnect(struct usb_interface *intf)
if (psAdapter->bDoSuspend)
intf->needs_remote_wakeup = 0;
- psAdapter->device_removed = TRUE ;
+ psAdapter->device_removed = TRUE;
usb_set_intfdata(intf, NULL);
InterfaceAdapterFree(psIntfAdapter);
usb_put_dev(udev);
@@ -285,8 +299,10 @@ static int AllocUsbCb(struct bcm_interface_adapter *psIntfAdapter)
psIntfAdapter->asUsbTcb[i].urb = usb_alloc_urb(0, GFP_KERNEL);
if (psIntfAdapter->asUsbTcb[i].urb == NULL) {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
- "Can't allocate Tx urb for index %d\n", i);
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_PRINTK, 0, 0,
+ "Can't allocate Tx urb for index %d\n",
+ i);
return -ENOMEM;
}
}
@@ -295,19 +311,25 @@ static int AllocUsbCb(struct bcm_interface_adapter *psIntfAdapter)
psIntfAdapter->asUsbRcb[i].urb = usb_alloc_urb(0, GFP_KERNEL);
if (psIntfAdapter->asUsbRcb[i].urb == NULL) {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
- "Can't allocate Rx urb for index %d\n", i);
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_PRINTK, 0, 0,
+ "Can't allocate Rx urb for index %d\n",
+ i);
return -ENOMEM;
}
- psIntfAdapter->asUsbRcb[i].urb->transfer_buffer = kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL);
+ psIntfAdapter->asUsbRcb[i].urb->transfer_buffer =
+ kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL);
if (psIntfAdapter->asUsbRcb[i].urb->transfer_buffer == NULL) {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
- "Can't allocate Rx buffer for index %d\n", i);
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_PRINTK, 0, 0,
+ "Can't allocate Rx buffer for index %d\n",
+ i);
return -ENOMEM;
}
- psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length = MAX_DATA_BUFFER_SIZE;
+ psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length =
+ MAX_DATA_BUFFER_SIZE;
}
return 0;
}
@@ -322,24 +344,29 @@ static int device_run(struct bcm_interface_adapter *psIntfAdapter)
pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n");
return status;
}
- if (TRUE == psIntfAdapter->psAdapter->fw_download_done) {
+ if (psIntfAdapter->psAdapter->fw_download_done) {
if (StartInterruptUrb(psIntfAdapter)) {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "Cannot send interrupt in URB\n");
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_INITEXIT, DRV_ENTRY,
+ DBG_LVL_ALL,
+ "Cannot send interrupt in URB\n");
}
/*
- * now register the cntrl interface.
- * after downloading the f/w waiting for 5 sec to get the mailbox interrupt.
+ * now register the cntrl interface. after downloading the f/w
+ * waiting for 5 sec to get the mailbox interrupt.
*/
psIntfAdapter->psAdapter->waiting_to_fw_download_done = false;
- value = wait_event_timeout(psIntfAdapter->psAdapter->ioctl_fw_dnld_wait_queue,
- psIntfAdapter->psAdapter->waiting_to_fw_download_done, 5*HZ);
+ value = wait_event_timeout(
+ psIntfAdapter->psAdapter->ioctl_fw_dnld_wait_queue,
+ psIntfAdapter->psAdapter->waiting_to_fw_download_done,
+ 5 * HZ);
if (value == 0)
pr_err(DRV_NAME ": Timeout waiting for mailbox interrupt.\n");
- if (register_control_device_interface(psIntfAdapter->psAdapter) < 0) {
+ if (register_control_device_interface(
+ psIntfAdapter->psAdapter) < 0) {
pr_err(DRV_NAME ": Register Control Device failed.\n");
return -EIO;
}
@@ -347,81 +374,6 @@ static int device_run(struct bcm_interface_adapter *psIntfAdapter)
return 0;
}
-
-static inline int bcm_usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
-{
- return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-}
-
-static inline int bcm_usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
-{
- return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
-}
-
-static inline int bcm_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
-{
- return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
-}
-
-static inline int bcm_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
-{
- return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
-}
-
-static inline int bcm_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
-{
- return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
- USB_ENDPOINT_XFER_BULK);
-}
-
-static inline int bcm_usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
-{
- return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
- USB_ENDPOINT_XFER_CONTROL);
-}
-
-static inline int bcm_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
-{
- return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
- USB_ENDPOINT_XFER_INT);
-}
-
-static inline int bcm_usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
-{
- return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
- USB_ENDPOINT_XFER_ISOC);
-}
-
-static inline int bcm_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
-{
- return bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_in(epd);
-}
-
-static inline int bcm_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
-{
- return bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_out(epd);
-}
-
-static inline int bcm_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
-{
- return bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_in(epd);
-}
-
-static inline int bcm_usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
-{
- return bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_out(epd);
-}
-
-static inline int bcm_usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
-{
- return bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_in(epd);
-}
-
-static inline int bcm_usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
-{
- return bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_out(epd);
-}
-
static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter)
{
struct usb_host_interface *iface_desc;
@@ -429,23 +381,27 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter)
size_t buffer_size;
unsigned long value;
int retval = 0;
- int usedIntOutForBulkTransfer = 0 ;
+ int usedIntOutForBulkTransfer = 0;
bool bBcm16 = false;
UINT uiData = 0;
int bytes;
/* Store the usb dev into interface adapter */
- psIntfAdapter->udev = usb_get_dev(interface_to_usbdev(psIntfAdapter->interface));
+ psIntfAdapter->udev =
+ usb_get_dev(interface_to_usbdev(psIntfAdapter->interface));
- psIntfAdapter->bHighSpeedDevice = (psIntfAdapter->udev->speed == USB_SPEED_HIGH);
+ psIntfAdapter->bHighSpeedDevice =
+ (psIntfAdapter->udev->speed == USB_SPEED_HIGH);
psIntfAdapter->psAdapter->interface_rdm = BcmRDM;
psIntfAdapter->psAdapter->interface_wrm = BcmWRM;
bytes = rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG,
- (u32 *)&(psIntfAdapter->psAdapter->chip_id), sizeof(u32));
+ (u32 *) &(psIntfAdapter->psAdapter->chip_id),
+ sizeof(u32));
if (bytes < 0) {
retval = bytes;
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n");
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
+ "CHIP ID Read Failed\n");
return retval;
}
@@ -453,81 +409,119 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter)
psIntfAdapter->psAdapter->chip_id &= ~0xF0;
dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n",
- psIntfAdapter->psAdapter->chip_id);
+ psIntfAdapter->psAdapter->chip_id);
iface_desc = psIntfAdapter->interface->cur_altsetting;
if (psIntfAdapter->psAdapter->chip_id == T3B) {
- /* T3B device will have EEPROM, check if EEPROM is proper and BCM16 can be done or not. */
+ /* T3B device will have EEPROM, check if EEPROM is proper and
+ * BCM16 can be done or not. */
BeceemEEPROMBulkRead(psIntfAdapter->psAdapter, &uiData, 0x0, 4);
if (uiData == BECM)
bBcm16 = TRUE;
- dev_info(&psIntfAdapter->udev->dev, "number of alternate setting %d\n",
- psIntfAdapter->interface->num_altsetting);
+ dev_info(&psIntfAdapter->udev->dev,
+ "number of alternate setting %d\n",
+ psIntfAdapter->interface->num_altsetting);
if (bBcm16 == TRUE) {
- /* selecting alternate setting one as a default setting for High Speed modem. */
+ /* selecting alternate setting one as a default setting
+ * for High Speed modem. */
if (psIntfAdapter->bHighSpeedDevice)
- retval = usb_set_interface(psIntfAdapter->udev, DEFAULT_SETTING_0, ALTERNATE_SETTING_1);
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "BCM16 is applicable on this dongle\n");
- if (retval || (psIntfAdapter->bHighSpeedDevice == false)) {
- usedIntOutForBulkTransfer = EP2 ;
+ retval = usb_set_interface(psIntfAdapter->udev,
+ DEFAULT_SETTING_0,
+ ALTERNATE_SETTING_1);
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_INITEXIT, DRV_ENTRY,
+ DBG_LVL_ALL,
+ "BCM16 is applicable on this dongle\n");
+ if (retval || !psIntfAdapter->bHighSpeedDevice) {
+ usedIntOutForBulkTransfer = EP2;
endpoint = &iface_desc->endpoint[EP2].desc;
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n");
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_INITEXIT, DRV_ENTRY,
+ DBG_LVL_ALL,
+ "Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n");
/*
- * If Modem is high speed device EP2 should be INT OUT End point
- * If Mode is FS then EP2 should be bulk end point
+ * If Modem is high speed device EP2 should be
+ * INT OUT End point
+ *
+ * If Mode is FS then EP2 should be bulk end
+ * point
*/
- if (((psIntfAdapter->bHighSpeedDevice == TRUE) && (bcm_usb_endpoint_is_int_out(endpoint) == false))
- || ((psIntfAdapter->bHighSpeedDevice == false) && (bcm_usb_endpoint_is_bulk_out(endpoint) == false))) {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "Configuring the EEPROM\n");
+ if ((psIntfAdapter->bHighSpeedDevice &&
+ !usb_endpoint_is_int_out(endpoint)) ||
+ (!psIntfAdapter->bHighSpeedDevice &&
+ !usb_endpoint_is_bulk_out(endpoint))) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_INITEXIT,
+ DRV_ENTRY, DBG_LVL_ALL,
+ "Configuring the EEPROM\n");
/* change the EP2, EP4 to INT OUT end point */
- ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter);
+ ConfigureEndPointTypesThroughEEPROM(
+ psIntfAdapter->psAdapter);
/*
- * It resets the device and if any thing gets changed
- * in USB descriptor it will show fail and re-enumerate
- * the device
+ * It resets the device and if any thing
+ * gets changed in USB descriptor it
+ * will show fail and re-enumerate the
+ * device
*/
- retval = usb_reset_device(psIntfAdapter->udev);
+ retval = usb_reset_device(
+ psIntfAdapter->udev);
if (retval) {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "reset failed. Re-enumerating the device.\n");
- return retval ;
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_INITEXIT,
+ DRV_ENTRY,
+ DBG_LVL_ALL,
+ "reset failed. Re-enumerating the device.\n");
+ return retval;
}
}
- if ((psIntfAdapter->bHighSpeedDevice == false) && bcm_usb_endpoint_is_bulk_out(endpoint)) {
+ if (!psIntfAdapter->bHighSpeedDevice &&
+ usb_endpoint_is_bulk_out(endpoint)) {
/* Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail. */
UINT _uiData = ntohl(EP2_CFG_INT);
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "Reverting Bulk to INT as it is in Full Speed mode.\n");
- BeceemEEPROMBulkWrite(psIntfAdapter->psAdapter, (PUCHAR)&_uiData, 0x136, 4, TRUE);
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_INITEXIT,
+ DRV_ENTRY, DBG_LVL_ALL,
+ "Reverting Bulk to INT as it is in Full Speed mode.\n");
+ BeceemEEPROMBulkWrite(
+ psIntfAdapter->psAdapter,
+ (PUCHAR) & _uiData,
+ 0x136, 4, TRUE);
}
} else {
- usedIntOutForBulkTransfer = EP4 ;
+ usedIntOutForBulkTransfer = EP4;
endpoint = &iface_desc->endpoint[EP4].desc;
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "Choosing AltSetting as a default setting.\n");
- if (bcm_usb_endpoint_is_int_out(endpoint) == false) {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "Dongle does not have BCM16 Fix.\n");
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_INITEXIT, DRV_ENTRY,
+ DBG_LVL_ALL,
+ "Choosing AltSetting as a default setting.\n");
+ if (!usb_endpoint_is_int_out(endpoint)) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_INITEXIT,
+ DRV_ENTRY, DBG_LVL_ALL,
+ "Dongle does not have BCM16 Fix.\n");
/* change the EP2, EP4 to INT OUT end point and use EP4 in altsetting */
- ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter);
+ ConfigureEndPointTypesThroughEEPROM(
+ psIntfAdapter->psAdapter);
/*
- * It resets the device and if any thing gets changed in
- * USB descriptor it will show fail and re-enumerate the
+ * It resets the device and if any thing
+ * gets changed in USB descriptor it
+ * will show fail and re-enumerate the
* device
*/
- retval = usb_reset_device(psIntfAdapter->udev);
+ retval = usb_reset_device(
+ psIntfAdapter->udev);
if (retval) {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "reset failed. Re-enumerating the device.\n");
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_INITEXIT,
+ DRV_ENTRY,
+ DBG_LVL_ALL,
+ "reset failed. Re-enumerating the device.\n");
return retval;
}
@@ -541,49 +535,69 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter)
for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) {
endpoint = &iface_desc->endpoint[value].desc;
- if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && bcm_usb_endpoint_is_bulk_in(endpoint)) {
+ if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr &&
+ usb_endpoint_is_bulk_in(endpoint)) {
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
psIntfAdapter->sBulkIn.bulk_in_size = buffer_size;
- psIntfAdapter->sBulkIn.bulk_in_endpointAddr = endpoint->bEndpointAddress;
- psIntfAdapter->sBulkIn.bulk_in_pipe =
- usb_rcvbulkpipe(psIntfAdapter->udev,
- psIntfAdapter->sBulkIn.bulk_in_endpointAddr);
+ psIntfAdapter->sBulkIn.bulk_in_endpointAddr =
+ endpoint->bEndpointAddress;
+ psIntfAdapter->sBulkIn.bulk_in_pipe = usb_rcvbulkpipe(
+ psIntfAdapter->udev,
+ psIntfAdapter->sBulkIn.bulk_in_endpointAddr);
}
- if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && bcm_usb_endpoint_is_bulk_out(endpoint)) {
- psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress;
- psIntfAdapter->sBulkOut.bulk_out_pipe =
- usb_sndbulkpipe(psIntfAdapter->udev,
+ if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr &&
+ usb_endpoint_is_bulk_out(endpoint)) {
+ psIntfAdapter->sBulkOut.bulk_out_endpointAddr =
+ endpoint->bEndpointAddress;
+ psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndbulkpipe(
+ psIntfAdapter->udev,
psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
}
- if (!psIntfAdapter->sIntrIn.int_in_endpointAddr && bcm_usb_endpoint_is_int_in(endpoint)) {
+ if (!psIntfAdapter->sIntrIn.int_in_endpointAddr &&
+ usb_endpoint_is_int_in(endpoint)) {
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
psIntfAdapter->sIntrIn.int_in_size = buffer_size;
- psIntfAdapter->sIntrIn.int_in_endpointAddr = endpoint->bEndpointAddress;
- psIntfAdapter->sIntrIn.int_in_interval = endpoint->bInterval;
+ psIntfAdapter->sIntrIn.int_in_endpointAddr =
+ endpoint->bEndpointAddress;
+ psIntfAdapter->sIntrIn.int_in_interval =
+ endpoint->bInterval;
psIntfAdapter->sIntrIn.int_in_buffer =
- kmalloc(buffer_size, GFP_KERNEL);
+ kmalloc(buffer_size, GFP_KERNEL);
if (!psIntfAdapter->sIntrIn.int_in_buffer)
return -EINVAL;
}
- if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && bcm_usb_endpoint_is_int_out(endpoint)) {
+ if (!psIntfAdapter->sIntrOut.int_out_endpointAddr &&
+ usb_endpoint_is_int_out(endpoint)) {
if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr &&
- (psIntfAdapter->psAdapter->chip_id == T3B) && (value == usedIntOutForBulkTransfer)) {
+ (psIntfAdapter->psAdapter->chip_id == T3B) &&
+ (value == usedIntOutForBulkTransfer)) {
/* use first intout end point as a bulk out end point */
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
- psIntfAdapter->sBulkOut.bulk_out_size = buffer_size;
- psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress;
- psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndintpipe(psIntfAdapter->udev,
- psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
- psIntfAdapter->sBulkOut.int_out_interval = endpoint->bInterval;
+ buffer_size =
+ le16_to_cpu(endpoint->wMaxPacketSize);
+ psIntfAdapter->sBulkOut.bulk_out_size =
+ buffer_size;
+ psIntfAdapter->sBulkOut.bulk_out_endpointAddr =
+ endpoint->bEndpointAddress;
+ psIntfAdapter->sBulkOut.bulk_out_pipe =
+ usb_sndintpipe(psIntfAdapter->udev,
+ psIntfAdapter->sBulkOut
+ .bulk_out_endpointAddr);
+ psIntfAdapter->sBulkOut.int_out_interval =
+ endpoint->bInterval;
} else if (value == EP6) {
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
- psIntfAdapter->sIntrOut.int_out_size = buffer_size;
- psIntfAdapter->sIntrOut.int_out_endpointAddr = endpoint->bEndpointAddress;
- psIntfAdapter->sIntrOut.int_out_interval = endpoint->bInterval;
- psIntfAdapter->sIntrOut.int_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
+ buffer_size =
+ le16_to_cpu(endpoint->wMaxPacketSize);
+ psIntfAdapter->sIntrOut.int_out_size =
+ buffer_size;
+ psIntfAdapter->sIntrOut.int_out_endpointAddr =
+ endpoint->bEndpointAddress;
+ psIntfAdapter->sIntrOut.int_out_interval =
+ endpoint->bInterval;
+ psIntfAdapter->sIntrOut.int_out_buffer =
+ kmalloc(buffer_size, GFP_KERNEL);
if (!psIntfAdapter->sIntrOut.int_out_buffer)
return -EINVAL;
}
@@ -594,14 +608,14 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter)
psIntfAdapter->psAdapter->bcm_file_download = InterfaceFileDownload;
psIntfAdapter->psAdapter->bcm_file_readback_from_chip =
- InterfaceFileReadbackFromChip;
+ InterfaceFileReadbackFromChip;
psIntfAdapter->psAdapter->interface_transmit = InterfaceTransmitPacket;
retval = CreateInterruptUrb(psIntfAdapter);
if (retval) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
- "Cannot create interrupt urb\n");
+ "Cannot create interrupt urb\n");
return retval;
}
@@ -618,17 +632,21 @@ static int InterfaceSuspend(struct usb_interface *intf, pm_message_t message)
psIntfAdapter->bSuspended = TRUE;
- if (TRUE == psIntfAdapter->bPreparingForBusSuspend) {
+ if (psIntfAdapter->bPreparingForBusSuspend) {
psIntfAdapter->bPreparingForBusSuspend = false;
if (psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE) {
- psIntfAdapter->psAdapter->IdleMode = TRUE ;
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "Host Entered in PMU Idle Mode.\n");
+ psIntfAdapter->psAdapter->IdleMode = TRUE;
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_INITEXIT, DRV_ENTRY,
+ DBG_LVL_ALL,
+ "Host Entered in PMU Idle Mode.\n");
} else {
psIntfAdapter->psAdapter->bShutStatus = TRUE;
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
- "Host Entered in PMU Shutdown Mode.\n");
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_INITEXIT, DRV_ENTRY,
+ DBG_LVL_ALL,
+ "Host Entered in PMU Shutdown Mode.\n");
}
}
psIntfAdapter->psAdapter->bPreparingForLowPowerMode = false;
diff --git a/drivers/staging/bcm/InterfaceIsr.c b/drivers/staging/bcm/InterfaceIsr.c
index 7b39f4f5f1ab..b9f8a7aa24fe 100644
--- a/drivers/staging/bcm/InterfaceIsr.c
+++ b/drivers/staging/bcm/InterfaceIsr.c
@@ -4,108 +4,126 @@
static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/)
{
int status = urb->status;
- struct bcm_interface_adapter *psIntfAdapter = (struct bcm_interface_adapter *)urb->context;
- struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter ;
+ struct bcm_interface_adapter *psIntfAdapter =
+ (struct bcm_interface_adapter *)urb->context;
+ struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter;
if (netif_msg_intr(Adapter))
pr_info(PFX "%s: interrupt status %d\n",
- Adapter->dev->name, status);
+ Adapter->dev->name, status);
- if(Adapter->device_removed == TRUE)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Device has Got Removed.");
- return ;
+ if (Adapter->device_removed) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
+ DBG_LVL_ALL, "Device has Got Removed.");
+ return;
}
- if(((Adapter->bPreparingForLowPowerMode == TRUE) && (Adapter->bDoSuspend == TRUE)) ||
- psIntfAdapter->bSuspended ||
- psIntfAdapter->bPreparingForBusSuspend)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Interrupt call back is called while suspending the device");
- return ;
+ if ((Adapter->bPreparingForLowPowerMode && Adapter->bDoSuspend) ||
+ psIntfAdapter->bSuspended ||
+ psIntfAdapter->bPreparingForBusSuspend) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
+ DBG_LVL_ALL,
+ "Interrupt call back is called while suspending the device");
+ return;
}
- //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "interrupt urb status %d", status);
switch (status) {
- /* success */
- case STATUS_SUCCESS:
- if ( urb->actual_length )
- {
-
- if(psIntfAdapter->ulInterruptData[1] & 0xFF)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL, "Got USIM interrupt");
+ /* success */
+ case STATUS_SUCCESS:
+ if (urb->actual_length) {
+
+ if (psIntfAdapter->ulInterruptData[1] & 0xFF) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
+ INTF_INIT, DBG_LVL_ALL,
+ "Got USIM interrupt");
}
- if(psIntfAdapter->ulInterruptData[1] & 0xFF00)
- {
+ if (psIntfAdapter->ulInterruptData[1] & 0xFF00) {
atomic_set(&Adapter->CurrNumFreeTxDesc,
- (psIntfAdapter->ulInterruptData[1] & 0xFF00) >> 8);
- atomic_set (&Adapter->uiMBupdate, TRUE);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL, "TX mailbox contains %d",
+ (psIntfAdapter->ulInterruptData[1] &
+ 0xFF00) >> 8);
+ atomic_set(&Adapter->uiMBupdate, TRUE);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
+ INTF_INIT, DBG_LVL_ALL,
+ "TX mailbox contains %d",
atomic_read(&Adapter->CurrNumFreeTxDesc));
}
- if(psIntfAdapter->ulInterruptData[1] >> 16)
- {
- Adapter->CurrNumRecvDescs=
+ if (psIntfAdapter->ulInterruptData[1] >> 16) {
+ Adapter->CurrNumRecvDescs =
(psIntfAdapter->ulInterruptData[1] >> 16);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"RX mailbox contains %d",
- Adapter->CurrNumRecvDescs);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
+ INTF_INIT, DBG_LVL_ALL,
+ "RX mailbox contains %d",
+ Adapter->CurrNumRecvDescs);
InterfaceRx(psIntfAdapter);
}
- if(Adapter->fw_download_done &&
+ if (Adapter->fw_download_done &&
!Adapter->downloadDDR &&
- atomic_read(&Adapter->CurrNumFreeTxDesc))
- {
- psIntfAdapter->psAdapter->downloadDDR +=1;
+ atomic_read(&Adapter->CurrNumFreeTxDesc)) {
+
+ psIntfAdapter->psAdapter->downloadDDR += 1;
wake_up(&Adapter->tx_packet_wait_queue);
}
- if(false == Adapter->waiting_to_fw_download_done)
- {
+ if (!Adapter->waiting_to_fw_download_done) {
Adapter->waiting_to_fw_download_done = TRUE;
wake_up(&Adapter->ioctl_fw_dnld_wait_queue);
}
- if(!atomic_read(&Adapter->TxPktAvail))
- {
+ if (!atomic_read(&Adapter->TxPktAvail)) {
atomic_set(&Adapter->TxPktAvail, 1);
wake_up(&Adapter->tx_packet_wait_queue);
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Firing interrupt in URB");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
+ DBG_LVL_ALL, "Firing interrupt in URB");
}
break;
- case -ENOENT :
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"URB has got disconnected ....");
- return ;
- }
- case -EINPROGRESS:
- {
- //This situation may happened when URBunlink is used. for detail check usb_unlink_urb documentation.
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Impossibe condition has occurred... something very bad is going on");
- break ;
- //return;
- }
- case -EPIPE:
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Interrupt IN endPoint has got halted/stalled...need to clear this");
- Adapter->bEndPointHalted = TRUE ;
- wake_up(&Adapter->tx_packet_wait_queue);
- urb->status = STATUS_SUCCESS ;
- return;
- }
- /* software-driven interface shutdown */
- case -ECONNRESET: //URB got unlinked.
- case -ESHUTDOWN: // hardware gone. this is the serious problem.
- //Occurs only when something happens with the host controller device
- case -ENODEV : //Device got removed
- case -EINVAL : //Some thing very bad happened with the URB. No description is available.
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"interrupt urb error %d", status);
- urb->status = STATUS_SUCCESS ;
- break ;
- //return;
- default:
- //This is required to check what is the defaults conditions when it occurs..
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"GOT DEFAULT INTERRUPT URB STATUS :%d..Please Analyze it...", status);
+ case -ENOENT:
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
+ DBG_LVL_ALL, "URB has got disconnected....");
+ return;
+ case -EINPROGRESS:
+ /*
+ * This situation may happened when URBunlink is used. for
+ * detail check usb_unlink_urb documentation.
+ */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
+ DBG_LVL_ALL,
+ "Impossibe condition has occurred... something very bad is going on");
+ break;
+ /* return; */
+ case -EPIPE:
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
+ DBG_LVL_ALL,
+ "Interrupt IN endPoint has got halted/stalled...need to clear this");
+ Adapter->bEndPointHalted = TRUE;
+ wake_up(&Adapter->tx_packet_wait_queue);
+ urb->status = STATUS_SUCCESS;
+ return;
+ /* software-driven interface shutdown */
+ case -ECONNRESET: /* URB got unlinked */
+ case -ESHUTDOWN: /* hardware gone. this is the serious problem */
+ /*
+ * Occurs only when something happens with the
+ * host controller device
+ */
+ case -ENODEV: /* Device got removed */
+ case -EINVAL:
+ /*
+ * Some thing very bad happened with the URB. No
+ * description is available.
+ */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT,
+ DBG_LVL_ALL, "interrupt urb error %d", status);
+ urb->status = STATUS_SUCCESS;
+ break;
+ /* return; */
+ default:
+ /*
+ * This is required to check what is the defaults conditions
+ * when it occurs..
+ */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,
+ "GOT DEFAULT INTERRUPT URB STATUS :%d..Please Analyze it...",
+ status);
break;
}
@@ -117,28 +135,30 @@ static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/)
int CreateInterruptUrb(struct bcm_interface_adapter *psIntfAdapter)
{
psIntfAdapter->psInterruptUrb = usb_alloc_urb(0, GFP_KERNEL);
- if (!psIntfAdapter->psInterruptUrb)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Cannot allocate interrupt urb");
+ if (!psIntfAdapter->psInterruptUrb) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS,
+ INTF_INIT, DBG_LVL_ALL,
+ "Cannot allocate interrupt urb");
return -ENOMEM;
}
psIntfAdapter->psInterruptUrb->transfer_buffer =
- psIntfAdapter->ulInterruptData;
+ psIntfAdapter->ulInterruptData;
psIntfAdapter->psInterruptUrb->transfer_buffer_length =
- sizeof(psIntfAdapter->ulInterruptData);
+ sizeof(psIntfAdapter->ulInterruptData);
psIntfAdapter->sIntrIn.int_in_pipe = usb_rcvintpipe(psIntfAdapter->udev,
- psIntfAdapter->sIntrIn.int_in_endpointAddr);
+ psIntfAdapter->sIntrIn.int_in_endpointAddr);
usb_fill_int_urb(psIntfAdapter->psInterruptUrb, psIntfAdapter->udev,
- psIntfAdapter->sIntrIn.int_in_pipe,
- psIntfAdapter->psInterruptUrb->transfer_buffer,
- psIntfAdapter->psInterruptUrb->transfer_buffer_length,
- read_int_callback, psIntfAdapter,
- psIntfAdapter->sIntrIn.int_in_interval);
-
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Interrupt Interval: %d\n",
- psIntfAdapter->sIntrIn.int_in_interval);
+ psIntfAdapter->sIntrIn.int_in_pipe,
+ psIntfAdapter->psInterruptUrb->transfer_buffer,
+ psIntfAdapter->psInterruptUrb->transfer_buffer_length,
+ read_int_callback, psIntfAdapter,
+ psIntfAdapter->sIntrIn.int_in_interval);
+
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, INTF_INIT,
+ DBG_LVL_ALL, "Interrupt Interval: %d\n",
+ psIntfAdapter->sIntrIn.int_in_interval);
return 0;
}
@@ -147,19 +167,20 @@ INT StartInterruptUrb(struct bcm_interface_adapter *psIntfAdapter)
{
INT status = 0;
- if( false == psIntfAdapter->psAdapter->device_removed &&
- false == psIntfAdapter->psAdapter->bEndPointHalted &&
- false == psIntfAdapter->bSuspended &&
- false == psIntfAdapter->bPreparingForBusSuspend &&
- false == psIntfAdapter->psAdapter->StopAllXaction)
- {
- status = usb_submit_urb(psIntfAdapter->psInterruptUrb, GFP_ATOMIC);
- if (status)
- {
- BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Cannot send int urb %d\n", status);
- if(status == -EPIPE)
- {
- psIntfAdapter->psAdapter->bEndPointHalted = TRUE ;
+ if (!(psIntfAdapter->psAdapter->device_removed ||
+ psIntfAdapter->psAdapter->bEndPointHalted ||
+ psIntfAdapter->bSuspended ||
+ psIntfAdapter->bPreparingForBusSuspend ||
+ psIntfAdapter->psAdapter->StopAllXaction)) {
+ status =
+ usb_submit_urb(psIntfAdapter->psInterruptUrb, GFP_ATOMIC);
+ if (status) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
+ DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,
+ "Cannot send inturb %d\n", status);
+ if (status == -EPIPE) {
+ psIntfAdapter->psAdapter->bEndPointHalted =
+ TRUE;
wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue);
}
}
diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c
index 0727599bf5fa..4f315835ddfc 100644
--- a/drivers/staging/bcm/Qos.c
+++ b/drivers/staging/bcm/Qos.c
@@ -222,10 +222,7 @@ static USHORT IpVersion4(struct bcm_mini_adapter *Adapter,
//Checking classifier validity
if (!pstClassifierRule->bUsed || pstClassifierRule->ucDirection == DOWNLINK_DIR)
- {
- bClassificationSucceed = false;
break;
- }
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "is IPv6 check!");
if (pstClassifierRule->bIpv6Protocol)
@@ -233,51 +230,47 @@ static USHORT IpVersion4(struct bcm_mini_adapter *Adapter,
//**************Checking IP header parameter**************************//
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Trying to match Source IP Address");
- if (false == (bClassificationSucceed =
- MatchSrcIpAddress(pstClassifierRule, iphd->saddr)))
+ if (!MatchSrcIpAddress(pstClassifierRule, iphd->saddr))
break;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source IP Address Matched");
- if (false == (bClassificationSucceed =
- MatchDestIpAddress(pstClassifierRule, iphd->daddr)))
+ if (!MatchDestIpAddress(pstClassifierRule, iphd->daddr))
break;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination IP Address Matched");
- if (false == (bClassificationSucceed =
- MatchTos(pstClassifierRule, iphd->tos)))
- {
+ if (!MatchTos(pstClassifierRule, iphd->tos)) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Match failed\n");
break;
}
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Matched");
- if (false == (bClassificationSucceed =
- MatchProtocol(pstClassifierRule, iphd->protocol)))
+ if (!MatchProtocol(pstClassifierRule, iphd->protocol))
break;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Matched");
//if protocol is not TCP or UDP then no need of comparing source port and destination port
- if (iphd->protocol != TCP && iphd->protocol != UDP)
+ if (iphd->protocol != TCP && iphd->protocol != UDP) {
+ bClassificationSucceed = TRUE;
break;
+ }
//******************Checking Transport Layer Header field if present *****************//
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source Port %04x",
(iphd->protocol == UDP) ? xprt_hdr->uhdr.source : xprt_hdr->thdr.source);
- if (false == (bClassificationSucceed =
- MatchSrcPort(pstClassifierRule,
- ntohs((iphd->protocol == UDP) ?
- xprt_hdr->uhdr.source : xprt_hdr->thdr.source))))
+ if (!MatchSrcPort(pstClassifierRule,
+ ntohs((iphd->protocol == UDP) ?
+ xprt_hdr->uhdr.source : xprt_hdr->thdr.source)))
break;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port Matched");
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Port %04x",
(iphd->protocol == UDP) ? xprt_hdr->uhdr.dest :
xprt_hdr->thdr.dest);
- if (false == (bClassificationSucceed =
- MatchDestPort(pstClassifierRule,
- ntohs((iphd->protocol == UDP) ?
- xprt_hdr->uhdr.dest : xprt_hdr->thdr.dest))))
+ if (!MatchDestPort(pstClassifierRule,
+ ntohs((iphd->protocol == UDP) ?
+ xprt_hdr->uhdr.dest : xprt_hdr->thdr.dest)))
break;
+ bClassificationSucceed = TRUE;
} while (0);
if (TRUE == bClassificationSucceed)
diff --git a/drivers/staging/bcm/Typedefs.h b/drivers/staging/bcm/Typedefs.h
index 832adcfd1e3a..90b3b25dd606 100644
--- a/drivers/staging/bcm/Typedefs.h
+++ b/drivers/staging/bcm/Typedefs.h
@@ -25,16 +25,16 @@ typedef unsigned int B_UINT32;
typedef unsigned long ULONG;
typedef unsigned long DWORD;
-typedef char* PCHAR;
-typedef short* PSHORT;
-typedef int* PINT;
-typedef long* PLONG;
-typedef void* PVOID;
-
-typedef unsigned char* PUCHAR;
-typedef unsigned short* PUSHORT;
-typedef unsigned int* PUINT;
-typedef unsigned long* PULONG;
+typedef char *PCHAR;
+typedef short *PSHORT;
+typedef int *PINT;
+typedef long *PLONG;
+typedef void *PVOID;
+
+typedef unsigned char *PUCHAR;
+typedef unsigned short *PUSHORT;
+typedef unsigned int *PUINT;
+typedef unsigned long *PULONG;
typedef unsigned long long ULONG64;
typedef unsigned long long LARGE_INTEGER;
typedef unsigned int UINT32;
@@ -43,5 +43,5 @@ typedef unsigned int UINT32;
#endif
-#endif //__TYPEDEFS_H__
+#endif /* __TYPEDEFS_H__ */
diff --git a/drivers/staging/bcm/headers.h b/drivers/staging/bcm/headers.h
index 7fd21c6923cb..6f3270cc4176 100644
--- a/drivers/staging/bcm/headers.h
+++ b/drivers/staging/bcm/headers.h
@@ -34,7 +34,7 @@
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/usb.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <net/ip.h>
#include "Typedefs.h"
diff --git a/drivers/staging/bcm/hostmibs.c b/drivers/staging/bcm/hostmibs.c
index f55300db1d48..39ace5510c43 100644
--- a/drivers/staging/bcm/hostmibs.c
+++ b/drivers/staging/bcm/hostmibs.c
@@ -27,9 +27,9 @@ INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, struct bcm_host_stats_m
/* Copy the classifier Table */
for (nClassifierIndex = 0; nClassifierIndex < MAX_CLASSIFIERS; nClassifierIndex++) {
if (Adapter->astClassifierTable[nClassifierIndex].bUsed == TRUE)
- memcpy((PVOID) & pstHostMibs->
+ memcpy((PVOID) &pstHostMibs->
astClassifierTable[nClassifierIndex],
- (PVOID) & Adapter->
+ (PVOID) &Adapter->
astClassifierTable[nClassifierIndex],
sizeof(struct bcm_mibs_classifier_rule));
}
@@ -37,8 +37,8 @@ INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, struct bcm_host_stats_m
/* Copy the SF Table */
for (nSfIndex = 0; nSfIndex < NO_OF_QUEUES; nSfIndex++) {
if (Adapter->PackInfo[nSfIndex].bValid) {
- memcpy((PVOID) & pstHostMibs->astSFtable[nSfIndex],
- (PVOID) & Adapter->PackInfo[nSfIndex],
+ memcpy((PVOID) &pstHostMibs->astSFtable[nSfIndex],
+ (PVOID) &Adapter->PackInfo[nSfIndex],
sizeof(struct bcm_mibs_table));
} else {
/* If index in not valid,
diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c
index fca164f51f4b..63be3be62ebd 100644
--- a/drivers/staging/bcm/nvm.c
+++ b/drivers/staging/bcm/nvm.c
@@ -122,7 +122,7 @@ static UCHAR ReadEEPROMStatusRegister(struct bcm_mini_adapter *Adapter)
* OSAL_STATUS_CODE:
*/
-int ReadBeceemEEPROMBulk(struct bcm_mini_adapter *Adapter,
+static int ReadBeceemEEPROMBulk(struct bcm_mini_adapter *Adapter,
DWORD dwAddress,
DWORD *pdwData,
DWORD dwNumWords)
@@ -2698,7 +2698,7 @@ int BcmGetSectionValStartOffset(struct bcm_mini_adapter *Adapter, enum bcm_flash
* On Failure -returns STATUS_FAILURE
*/
-int BcmGetSectionValEndOffset(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectionVal)
+static int BcmGetSectionValEndOffset(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectionVal)
{
int SectEndOffset = 0;
@@ -2980,7 +2980,7 @@ static int BcmGetActiveISO(struct bcm_mini_adapter *Adapter)
*
*/
-B_UINT8 IsOffsetWritable(struct bcm_mini_adapter *Adapter, unsigned int uiOffset)
+static B_UINT8 IsOffsetWritable(struct bcm_mini_adapter *Adapter, unsigned int uiOffset)
{
unsigned int uiSectorNum = 0;
unsigned int uiWordOfSectorPermission = 0;
@@ -3374,7 +3374,7 @@ int BcmSetActiveSection(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_secti
case DSD2:
if (ReadDSDSignature(Adapter, eFlash2xSectVal) == DSD_IMAGE_MAGIC_NUMBER) {
HighestPriDSD = getHighestPriDSD(Adapter);
- if ((HighestPriDSD == eFlash2xSectVal)) {
+ if (HighestPriDSD == eFlash2xSectVal) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Given DSD<%x> already has highest priority", eFlash2xSectVal);
Status = STATUS_SUCCESS;
break;
@@ -3402,7 +3402,7 @@ int BcmSetActiveSection(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_secti
HighestPriDSD = getHighestPriDSD(Adapter);
- if ((HighestPriDSD == eFlash2xSectVal)) {
+ if (HighestPriDSD == eFlash2xSectVal) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Made the DSD: %x highest by reducing priority of other\n", eFlash2xSectVal);
Status = STATUS_SUCCESS;
break;
@@ -3421,7 +3421,7 @@ int BcmSetActiveSection(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_secti
}
HighestPriDSD = getHighestPriDSD(Adapter);
- if ((HighestPriDSD == eFlash2xSectVal)) {
+ if (HighestPriDSD == eFlash2xSectVal) {
Status = STATUS_SUCCESS;
break;
}
@@ -4074,7 +4074,7 @@ int BcmCopySection(struct bcm_mini_adapter *Adapter,
* Faillure :- Return negative error code
*/
-int SaveHeaderIfPresent(struct bcm_mini_adapter *Adapter, PUCHAR pBuff, unsigned int uiOffset)
+static int SaveHeaderIfPresent(struct bcm_mini_adapter *Adapter, PUCHAR pBuff, unsigned int uiOffset)
{
unsigned int offsetToProtect = 0, HeaderSizeToProtect = 0;
bool bHasHeader = false;
@@ -4213,7 +4213,7 @@ static int BcmDoChipSelect(struct bcm_mini_adapter *Adapter, unsigned int offset
return STATUS_SUCCESS;
}
-int ReadDSDSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val dsd)
+static int ReadDSDSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val dsd)
{
unsigned int uiDSDsig = 0;
/* unsigned int sigoffsetInMap = 0;
@@ -4238,7 +4238,7 @@ int ReadDSDSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_
return uiDSDsig;
}
-int ReadDSDPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val dsd)
+static int ReadDSDPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val dsd)
{
/* unsigned int priOffsetInMap = 0 ; */
unsigned int uiDSDPri = STATUS_FAILURE;
@@ -4261,7 +4261,7 @@ int ReadDSDPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_v
return uiDSDPri;
}
-enum bcm_flash2x_section_val getHighestPriDSD(struct bcm_mini_adapter *Adapter)
+static enum bcm_flash2x_section_val getHighestPriDSD(struct bcm_mini_adapter *Adapter)
{
int DSDHighestPri = STATUS_FAILURE;
int DsdPri = 0;
@@ -4293,7 +4293,7 @@ enum bcm_flash2x_section_val getHighestPriDSD(struct bcm_mini_adapter *Adapter)
return HighestPriDSD;
}
-int ReadISOSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val iso)
+static int ReadISOSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val iso)
{
unsigned int uiISOsig = 0;
/* unsigned int sigoffsetInMap = 0;
@@ -4316,7 +4316,7 @@ int ReadISOSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_
return uiISOsig;
}
-int ReadISOPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val iso)
+static int ReadISOPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val iso)
{
unsigned int ISOPri = STATUS_FAILURE;
if (IsSectionWritable(Adapter, iso)) {
@@ -4335,7 +4335,7 @@ int ReadISOPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_v
return ISOPri;
}
-enum bcm_flash2x_section_val getHighestPriISO(struct bcm_mini_adapter *Adapter)
+static enum bcm_flash2x_section_val getHighestPriISO(struct bcm_mini_adapter *Adapter)
{
int ISOHighestPri = STATUS_FAILURE;
int ISOPri = 0;
@@ -4359,7 +4359,7 @@ enum bcm_flash2x_section_val getHighestPriISO(struct bcm_mini_adapter *Adapter)
return HighestPriISO;
}
-int WriteToFlashWithoutSectorErase(struct bcm_mini_adapter *Adapter,
+static int WriteToFlashWithoutSectorErase(struct bcm_mini_adapter *Adapter,
PUINT pBuff,
enum bcm_flash2x_section_val eFlash2xSectionVal,
unsigned int uiOffset,
@@ -4472,7 +4472,7 @@ bool IsSectionExistInFlash(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_se
return SectionPresent;
}
-int IsSectionWritable(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val Section)
+static int IsSectionWritable(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val Section)
{
int offset = STATUS_FAILURE;
int Status = false;
diff --git a/drivers/staging/ced1401/ced_ioc.c b/drivers/staging/ced1401/ced_ioc.c
index bf532b1bd345..ebbc5090f219 100644
--- a/drivers/staging/ced1401/ced_ioc.c
+++ b/drivers/staging/ced1401/ced_ioc.c
@@ -38,8 +38,8 @@
****************************************************************************/
static void FlushOutBuff(DEVICE_EXTENSION *pdx)
{
- dev_dbg(&pdx->interface->dev, "%s currentState=%d", __func__,
- pdx->sCurrentState);
+ dev_dbg(&pdx->interface->dev, "%s: currentState=%d\n",
+ __func__, pdx->sCurrentState);
if (pdx->sCurrentState == U14ERR_TIME) /* Do nothing if hardware in trouble */
return;
/* Kill off any pending I/O */
@@ -59,8 +59,8 @@ static void FlushOutBuff(DEVICE_EXTENSION *pdx)
****************************************************************************/
static void FlushInBuff(DEVICE_EXTENSION *pdx)
{
- dev_dbg(&pdx->interface->dev, "%s currentState=%d", __func__,
- pdx->sCurrentState);
+ dev_dbg(&pdx->interface->dev, "%s: currentState=%d\n",
+ __func__, pdx->sCurrentState);
if (pdx->sCurrentState == U14ERR_TIME) /* Do nothing if hardware in trouble */
return;
/* Kill off any pending I/O */
@@ -118,8 +118,8 @@ int SendString(DEVICE_EXTENSION *pdx, const char __user *pData,
mutex_lock(&pdx->io_mutex); /* Protect disconnect from new i/o */
if (n > 0) { /* do nothing if nowt to do! */
- dev_dbg(&pdx->interface->dev, "%s n=%d>%s<", __func__, n,
- buffer);
+ dev_dbg(&pdx->interface->dev, "%s: n=%d>%s<\n",
+ __func__, n, buffer);
iReturn = PutChars(pdx, buffer, n);
}
@@ -139,7 +139,7 @@ int SendChar(DEVICE_EXTENSION *pdx, char c)
int iReturn;
mutex_lock(&pdx->io_mutex); /* Protect disconnect from new i/o */
iReturn = PutChars(pdx, &c, 1);
- dev_dbg(&pdx->interface->dev, "SendChar >%c< (0x%02x)", c, c);
+ dev_dbg(&pdx->interface->dev, "SendChar >%c< (0x%02x)\n", c, c);
Allowi(pdx); /* Make sure char reads are running */
mutex_unlock(&pdx->io_mutex);
return iReturn;
@@ -174,7 +174,7 @@ int SendChar(DEVICE_EXTENSION *pdx, char c)
int Get1401State(DEVICE_EXTENSION *pdx, __u32 *state, __u32 *error)
{
int nGot;
- dev_dbg(&pdx->interface->dev, "Get1401State() entry");
+ dev_dbg(&pdx->interface->dev, "%s: entry\n", __func__);
*state = 0xFFFFFFFF; /* Start off with invalid state */
nGot = usb_control_msg(pdx->udev, usb_rcvctrlpipe(pdx->udev, 0),
@@ -182,15 +182,15 @@ int Get1401State(DEVICE_EXTENSION *pdx, __u32 *state, __u32 *error)
pdx->statBuf, sizeof(pdx->statBuf), HZ);
if (nGot != sizeof(pdx->statBuf)) {
dev_err(&pdx->interface->dev,
- "Get1401State() FAILED, return code %d", nGot);
+ "%s: FAILED, return code %d\n", __func__, nGot);
pdx->sCurrentState = U14ERR_TIME; /* Indicate that things are very wrong indeed */
*state = 0; /* Force status values to a known state */
*error = 0;
} else {
int nDevice;
dev_dbg(&pdx->interface->dev,
- "Get1401State() Success, state: 0x%x, 0x%x",
- pdx->statBuf[0], pdx->statBuf[1]);
+ "%s: Success, state: 0x%x, 0x%x\n",
+ __func__, pdx->statBuf[0], pdx->statBuf[1]);
*state = pdx->statBuf[0]; /* Return the state values to the calling code */
*error = pdx->statBuf[1];
@@ -220,8 +220,8 @@ int Get1401State(DEVICE_EXTENSION *pdx, __u32 *state, __u32 *error)
****************************************************************************/
int ReadWrite_Cancel(DEVICE_EXTENSION *pdx)
{
- dev_dbg(&pdx->interface->dev, "ReadWrite_Cancel entry %d",
- pdx->bStagedUrbPending);
+ dev_dbg(&pdx->interface->dev, "%s: entry %d\n",
+ __func__, pdx->bStagedUrbPending);
#ifdef NOT_WRITTEN_YET
int ntStatus = STATUS_SUCCESS;
bool bResult = false;
@@ -231,7 +231,7 @@ int ReadWrite_Cancel(DEVICE_EXTENSION *pdx)
if (pdx->bStagedUrbPending) { /* anything to be cancelled? May need more... */
dev_info(&pdx->interface - dev,
- "ReadWrite_Cancel about to cancel Urb");
+ "ReadWrite_Cancel about to cancel Urb\n");
/* Clear the staging done flag */
/* KeClearEvent(&pdx->StagingDoneEvent); */
USB_ASSERT(pdx->pStagedIrp != NULL);
@@ -244,14 +244,14 @@ int ReadWrite_Cancel(DEVICE_EXTENSION *pdx)
LARGE_INTEGER timeout;
timeout.QuadPart = -10000000; /* Use a timeout of 1 second */
dev_info(&pdx->interface - dev,
- "ReadWrite_Cancel about to wait till done");
+ "%s: about to wait till done\n", __func__);
ntStatus =
KeWaitForSingleObject(&pdx->StagingDoneEvent,
Executive, KernelMode, FALSE,
&timeout);
} else {
dev_info(&pdx->interface - dev,
- "ReadWrite_Cancel, cancellation failed");
+ "%s: cancellation failed\n", __func__);
ntStatus = U14ERR_FAIL;
}
USB_KdPrint(DBGLVL_DEFAULT,
@@ -260,7 +260,7 @@ int ReadWrite_Cancel(DEVICE_EXTENSION *pdx)
} else
spin_unlock_irq(&pdx->stagedLock);
- dev_info(&pdx->interface - dev, "ReadWrite_Cancel done");
+ dev_info(&pdx->interface - dev, "%s: done\n", __func__);
return ntStatus;
#else
return U14ERR_NOERROR;
@@ -304,7 +304,7 @@ static int InSelfTest(DEVICE_EXTENSION *pdx, unsigned int *pState)
bool Is1401(DEVICE_EXTENSION *pdx)
{
int iReturn;
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
ced_draw_down(pdx); /* wait for, then kill outstanding Urbs */
FlushInBuff(pdx); /* Clear out input buffer & pipe */
@@ -368,7 +368,7 @@ bool QuickCheck(DEVICE_EXTENSION *pdx, bool bTestBuff, bool bCanReset)
(pdx->sCurrentState >= U14ERR_STD)); /* No 1401 errors stored */
dev_dbg(&pdx->interface->dev,
- "%s DMAFlag:%d, state:%d, force:%d, testBuff:%d, short:%d",
+ "%s: DMAFlag:%d, state:%d, force:%d, testBuff:%d, short:%d\n",
__func__, pdx->dwDMAFlag, pdx->sCurrentState, pdx->bForceReset,
bTestBuff, bShortTest);
@@ -376,13 +376,13 @@ bool QuickCheck(DEVICE_EXTENSION *pdx, bool bTestBuff, bool bCanReset)
(pdx->dwNumInput || pdx->dwNumOutput)) { /* ...characters were in the buffer? */
bShortTest = false; /* Then do the full test */
dev_dbg(&pdx->interface->dev,
- "%s will reset as buffers not empty", __func__);
+ "%s: will reset as buffers not empty\n", __func__);
}
if (bShortTest || !bCanReset) { /* Still OK to try the short test? */
/* Always test if no reset - we want state update */
unsigned int state, error;
- dev_dbg(&pdx->interface->dev, "%s->Get1401State", __func__);
+ dev_dbg(&pdx->interface->dev, "%s: Get1401State\n", __func__);
if (Get1401State(pdx, &state, &error) == U14ERR_NOERROR) { /* Check on the 1401 state */
if ((state & 0xFF) == 0) /* If call worked, check the status value */
bRet = true; /* If that was zero, all is OK, no reset needed */
@@ -390,7 +390,7 @@ bool QuickCheck(DEVICE_EXTENSION *pdx, bool bTestBuff, bool bCanReset)
}
if (!bRet && bCanReset) { /* If all not OK, then */
- dev_info(&pdx->interface->dev, "%s->Is1401 %d %d %d %d",
+ dev_info(&pdx->interface->dev, "%s: Is1401 %d %d %d %d\n",
__func__, bShortTest, pdx->sCurrentState, bTestBuff,
pdx->bForceReset);
bRet = Is1401(pdx); /* do full test */
@@ -407,7 +407,8 @@ bool QuickCheck(DEVICE_EXTENSION *pdx, bool bTestBuff, bool bCanReset)
int Reset1401(DEVICE_EXTENSION *pdx)
{
mutex_lock(&pdx->io_mutex); /* Protect disconnect from new i/o */
- dev_dbg(&pdx->interface->dev, "ABout to call QuickCheck");
+ dev_dbg(&pdx->interface->dev, "%s: About to call QuickCheck\n",
+ __func__);
QuickCheck(pdx, true, true); /* Check 1401, reset if not OK */
mutex_unlock(&pdx->io_mutex);
return U14ERR_NOERROR;
@@ -423,7 +424,7 @@ int GetChar(DEVICE_EXTENSION *pdx)
int iReturn = U14ERR_NOIN; /* assume we will get nothing */
mutex_lock(&pdx->io_mutex); /* Protect disconnect from new i/o */
- dev_dbg(&pdx->interface->dev, "GetChar");
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
Allowi(pdx); /* Make sure char reads are running */
SendChars(pdx); /* and send any buffered chars */
@@ -497,8 +498,8 @@ int GetString(DEVICE_EXTENSION *pdx, char __user *pUser, int n)
pdx->dwNumInput -= nGot;
spin_unlock_irq(&pdx->charInLock);
- dev_dbg(&pdx->interface->dev,
- "GetString read %d characters >%s<", nGot, buffer);
+ dev_dbg(&pdx->interface->dev, "%s: read %d characters >%s<\n",
+ __func__, nGot, buffer);
if (copy_to_user(pUser, buffer, nCopyToUser))
iReturn = -EFAULT;
else
@@ -555,7 +556,7 @@ int LineCount(DEVICE_EXTENSION *pdx)
}
spin_unlock_irq(&pdx->charInLock);
- dev_dbg(&pdx->interface->dev, "LineCount returned %d", iReturn);
+ dev_dbg(&pdx->interface->dev, "%s: returned %d\n", __func__, iReturn);
mutex_unlock(&pdx->io_mutex); /* Protect disconnect from new i/o */
return iReturn;
}
@@ -571,7 +572,7 @@ int GetOutBufSpace(DEVICE_EXTENSION *pdx)
mutex_lock(&pdx->io_mutex); /* Protect disconnect from new i/o */
SendChars(pdx); /* send any buffered chars */
iReturn = (int)(OUTBUF_SZ - pdx->dwNumOutput); /* no lock needed for single read */
- dev_dbg(&pdx->interface->dev, "OutBufSpace %d", iReturn);
+ dev_dbg(&pdx->interface->dev, "%s: %d\n", __func__, iReturn);
mutex_unlock(&pdx->io_mutex); /* Protect disconnect from new i/o */
return iReturn;
}
@@ -589,7 +590,7 @@ int ClearArea(DEVICE_EXTENSION *pdx, int nArea)
if ((nArea < 0) || (nArea >= MAX_TRANSAREAS)) {
iReturn = U14ERR_BADAREA;
- dev_err(&pdx->interface->dev, "%s Attempt to clear area %d",
+ dev_err(&pdx->interface->dev, "%s: Attempt to clear area %d\n",
__func__, nArea);
} else {
TRANSAREA *pTA = &pdx->rTransDef[nArea]; /* to save typing */
@@ -602,14 +603,14 @@ int ClearArea(DEVICE_EXTENSION *pdx, int nArea)
int nPages = 0; /* and number of pages */
int np;
- dev_dbg(&pdx->interface->dev, "%s area %d", __func__,
- nArea);
+ dev_dbg(&pdx->interface->dev, "%s: area %d\n",
+ __func__, nArea);
spin_lock_irq(&pdx->stagedLock);
if ((pdx->StagedId == nArea)
&& (pdx->dwDMAFlag > MODE_CHAR)) {
iReturn = U14ERR_UNLOCKFAIL; /* cannot delete as in use */
dev_err(&pdx->interface->dev,
- "%s call on area %d while active",
+ "%s: call on area %d while active\n",
__func__, nArea);
} else {
pPages = pTA->pPages; /* save page address list */
@@ -633,7 +634,7 @@ int ClearArea(DEVICE_EXTENSION *pdx, int nArea)
/* Now we must undo the pinning down of the pages. We will assume the worst and mark */
/* all the pages as dirty. Don't be tempted to move this up above as you must not be */
/* holding a spin lock to do this stuff as it is not atomic. */
- dev_dbg(&pdx->interface->dev, "%s nPages=%d",
+ dev_dbg(&pdx->interface->dev, "%s: nPages=%d\n",
__func__, nPages);
for (np = 0; np < nPages; ++np) {
@@ -645,7 +646,7 @@ int ClearArea(DEVICE_EXTENSION *pdx, int nArea)
kfree(pPages);
dev_dbg(&pdx->interface->dev,
- "%s kfree(pPages) done", __func__);
+ "%s: kfree(pPages) done\n", __func__);
}
}
}
@@ -687,12 +688,12 @@ static int SetArea(DEVICE_EXTENSION *pdx, int nArea, char __user *puBuf,
iReturn = U14ERR_NOMEMORY;
goto error;
}
- dev_dbg(&pdx->interface->dev, "%s %p, length=%06x, circular %d",
+ dev_dbg(&pdx->interface->dev, "%s: %p, length=%06x, circular %d\n",
__func__, puBuf, dwLength, bCircular);
/* To pin down user pages we must first acquire the mapping semaphore. */
nPages = get_user_pages_fast(ulStart, len, 1, pPages);
- dev_dbg(&pdx->interface->dev, "%s nPages = %d", __func__, nPages);
+ dev_dbg(&pdx->interface->dev, "%s: nPages = %d\n", __func__, nPages);
if (nPages > 0) { /* if we succeeded */
/* If you are tempted to use page_address (form LDD3), forget it. You MUST use */
@@ -735,17 +736,17 @@ error:
** unset it. Unsetting will fail if the area is booked, and a transfer to that
** area is in progress. Otherwise, we will release the area and re-assign it.
****************************************************************************/
-int SetTransfer(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD)
+int SetTransfer(DEVICE_EXTENSION *pdx, struct transfer_area_desc __user *pTD)
{
int iReturn;
- TRANSFERDESC td;
+ struct transfer_area_desc td;
if (copy_from_user(&td, pTD, sizeof(td)))
return -EFAULT;
mutex_lock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s area:%d, size:%08x", __func__,
- td.wAreaNum, td.dwLength);
+ dev_dbg(&pdx->interface->dev, "%s: area:%d, size:%08x\n",
+ __func__, td.wAreaNum, td.dwLength);
/* The strange cast is done so that we don't get warnings in 32-bit linux about the size of the */
/* pointer. The pointer is always passed as a 64-bit object so that we don't have problems using */
/* a 32-bit program on a 64-bit system. unsigned long is 64-bits on a 64-bit system. */
@@ -778,10 +779,10 @@ int UnsetTransfer(DEVICE_EXTENSION *pdx, int nArea)
** pretend that whatever the user asked for was achieved, so we return 1 if
** try to create one, and 0 if they ask to remove (assuming all else was OK).
****************************************************************************/
-int SetEvent(DEVICE_EXTENSION *pdx, TRANSFEREVENT __user *pTE)
+int SetEvent(DEVICE_EXTENSION *pdx, struct transfer_event __user *pTE)
{
int iReturn = U14ERR_NOERROR;
- TRANSFEREVENT te;
+ struct transfer_event te;
/* get a local copy of the data */
if (copy_from_user(&te, pTE, sizeof(te)))
@@ -922,7 +923,7 @@ int GetTransfer(DEVICE_EXTENSION *pdx, TGET_TX_BLOCK __user *pTX)
****************************************************************************/
int KillIO1401(DEVICE_EXTENSION *pdx)
{
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
mutex_lock(&pdx->io_mutex);
FlushOutBuff(pdx);
FlushInBuff(pdx);
@@ -938,7 +939,7 @@ int KillIO1401(DEVICE_EXTENSION *pdx)
int BlkTransState(DEVICE_EXTENSION *pdx)
{
int iReturn = pdx->dwDMAFlag != MODE_CHAR;
- dev_dbg(&pdx->interface->dev, "%s = %d", __func__, iReturn);
+ dev_dbg(&pdx->interface->dev, "%s: %d\n", __func__, iReturn);
return iReturn;
}
@@ -956,7 +957,7 @@ int StateOf1401(DEVICE_EXTENSION *pdx)
iReturn = pdx->sCurrentState;
mutex_unlock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s = %d", __func__, iReturn);
+ dev_dbg(&pdx->interface->dev, "%s: %d\n", __func__, iReturn);
return iReturn;
}
@@ -971,7 +972,7 @@ int StartSelfTest(DEVICE_EXTENSION *pdx)
{
int nGot;
mutex_lock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
ced_draw_down(pdx); /* wait for, then kill outstanding Urbs */
FlushInBuff(pdx); /* Clear out input buffer & pipe */
@@ -987,7 +988,7 @@ int StartSelfTest(DEVICE_EXTENSION *pdx)
mutex_unlock(&pdx->io_mutex);
if (nGot < 0)
- dev_err(&pdx->interface->dev, "%s err=%d", __func__, nGot);
+ dev_err(&pdx->interface->dev, "%s: err=%d\n", __func__, nGot);
return nGot < 0 ? U14ERR_FAIL : U14ERR_NOERROR;
}
@@ -1005,7 +1006,7 @@ int CheckSelfTest(DEVICE_EXTENSION *pdx, TGET_SELFTEST __user *pGST)
mutex_lock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
iReturn = Get1401State(pdx, &state, &error);
if (iReturn == U14ERR_NOERROR) /* Only accept zero if it happens twice */
iReturn = Get1401State(pdx, &state, &error);
@@ -1013,8 +1014,8 @@ int CheckSelfTest(DEVICE_EXTENSION *pdx, TGET_SELFTEST __user *pGST)
if (iReturn != U14ERR_NOERROR) { /* Self-test can cause comms errors */
/* so we assume still testing */
dev_err(&pdx->interface->dev,
- "%s Get1401State=%d, assuming still testing", __func__,
- iReturn);
+ "%s: Get1401State=%d, assuming still testing\n",
+ __func__, iReturn);
state = 0x80; /* Force still-testing, no error */
error = 0;
iReturn = U14ERR_NOERROR;
@@ -1022,7 +1023,7 @@ int CheckSelfTest(DEVICE_EXTENSION *pdx, TGET_SELFTEST __user *pGST)
if ((state == -1) && (error == -1)) { /* If Get1401State had problems */
dev_err(&pdx->interface->dev,
- "%s Get1401State failed, assuming still testing",
+ "%s: Get1401State failed, assuming still testing\n",
__func__);
state = 0x80; /* Force still-testing, no error */
error = 0;
@@ -1033,21 +1034,21 @@ int CheckSelfTest(DEVICE_EXTENSION *pdx, TGET_SELFTEST __user *pGST)
gst.code = (state & 0x00FF0000) >> 16; /* read the error code */
gst.x = error & 0x0000FFFF; /* Error data X */
gst.y = (error & 0xFFFF0000) >> 16; /* and data Y */
- dev_dbg(&pdx->interface->dev, "Self-test error code %d",
- gst.code);
+ dev_dbg(&pdx->interface->dev,
+ "Self-test error code %d\n", gst.code);
} else { /* No error, check for timeout */
unsigned long ulNow = jiffies; /* get current time */
if (time_after(ulNow, pdx->ulSelfTestTime)) {
gst.code = -2; /* Flag the timeout */
dev_dbg(&pdx->interface->dev,
- "Self-test timed-out");
+ "Self-test timed-out\n");
} else
dev_dbg(&pdx->interface->dev,
- "Self-test on-going");
+ "Self-test on-going\n");
}
} else {
gst.code = -1; /* Flag the test is done */
- dev_dbg(&pdx->interface->dev, "Self-test done");
+ dev_dbg(&pdx->interface->dev, "Self-test done\n");
}
if (gst.code < 0) { /* If we have a problem or finished */
@@ -1074,7 +1075,7 @@ int TypeOf1401(DEVICE_EXTENSION *pdx)
{
int iReturn = TYPEUNKNOWN;
mutex_lock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
switch (pdx->s1401Type) {
case TYPE1401:
@@ -1092,7 +1093,7 @@ int TypeOf1401(DEVICE_EXTENSION *pdx)
else /* for up-coming 1401 designs */
iReturn = TYPEUNKNOWN; /* Don't know or not there */
}
- dev_dbg(&pdx->interface->dev, "%s %d", __func__, iReturn);
+ dev_dbg(&pdx->interface->dev, "%s %d\n", __func__, iReturn);
mutex_unlock(&pdx->io_mutex);
return iReturn;
@@ -1107,7 +1108,7 @@ int TransferFlags(DEVICE_EXTENSION *pdx)
{
int iReturn = U14TF_MULTIA | U14TF_DIAG | /* we always have multiple DMA area */
U14TF_NOTIFY | U14TF_CIRCTH; /* diagnostics, notify and circular */
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
mutex_lock(&pdx->io_mutex);
if (pdx->bIsUSB2) /* Set flag for USB2 if appropriate */
iReturn |= U14TF_USB2;
@@ -1125,15 +1126,15 @@ static int DbgCmd1401(DEVICE_EXTENSION *pdx, unsigned char cmd,
unsigned int data)
{
int iReturn;
- dev_dbg(&pdx->interface->dev, "%s entry", __func__);
+ dev_dbg(&pdx->interface->dev, "%s: entry\n", __func__);
iReturn = usb_control_msg(pdx->udev, usb_sndctrlpipe(pdx->udev, 0), cmd,
(H_TO_D | VENDOR | DEVREQ),
(unsigned short)data,
(unsigned short)(data >> 16), NULL, 0, HZ);
/* allow 1 second timeout */
if (iReturn < 0)
- dev_err(&pdx->interface->dev, "%s fail code=%d", __func__,
- iReturn);
+ dev_err(&pdx->interface->dev, "%s: fail code=%d\n",
+ __func__, iReturn);
return iReturn;
}
@@ -1152,7 +1153,7 @@ int DbgPeek(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB)
return -EFAULT;
mutex_lock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s @ %08x", __func__, db.iAddr);
+ dev_dbg(&pdx->interface->dev, "%s: @ %08x\n", __func__, db.iAddr);
iReturn = DbgCmd1401(pdx, DB_SETADD, db.iAddr);
if (iReturn == U14ERR_NOERROR)
@@ -1181,7 +1182,7 @@ int DbgPoke(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB)
return -EFAULT;
mutex_lock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s @ %08x", __func__, db.iAddr);
+ dev_dbg(&pdx->interface->dev, "%s: @ %08x\n", __func__, db.iAddr);
iReturn = DbgCmd1401(pdx, DB_SETADD, db.iAddr);
if (iReturn == U14ERR_NOERROR)
@@ -1210,7 +1211,7 @@ int DbgRampData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB)
return -EFAULT;
mutex_lock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s @ %08x", __func__, db.iAddr);
+ dev_dbg(&pdx->interface->dev, "%s: @ %08x\n", __func__, db.iAddr);
iReturn = DbgCmd1401(pdx, DB_SETADD, db.iAddr);
if (iReturn == U14ERR_NOERROR)
@@ -1242,7 +1243,7 @@ int DbgRampAddr(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB)
return -EFAULT;
mutex_lock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
iReturn = DbgCmd1401(pdx, DB_SETDEF, db.iDefault);
if (iReturn == U14ERR_NOERROR)
@@ -1270,7 +1271,7 @@ int DbgGetData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB)
memset(&db, 0, sizeof(db)); /* fill returned block with 0s */
mutex_lock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
/* Read back the last peeked value from the 1401. */
iReturn = usb_control_msg(pdx->udev, usb_rcvctrlpipe(pdx->udev, 0),
@@ -1282,8 +1283,8 @@ int DbgGetData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB)
else
iReturn = U14ERR_NOERROR;
} else
- dev_err(&pdx->interface->dev, "%s failed, code %d", __func__,
- iReturn);
+ dev_err(&pdx->interface->dev, "%s: failed, code %d\n",
+ __func__, iReturn);
mutex_unlock(&pdx->io_mutex);
@@ -1302,7 +1303,7 @@ int DbgStopLoop(DEVICE_EXTENSION *pdx)
unsigned int uState, uErr;
mutex_lock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
iReturn = Get1401State(pdx, &uState, &uErr);
mutex_unlock(&pdx->io_mutex);
@@ -1317,18 +1318,18 @@ int DbgStopLoop(DEVICE_EXTENSION *pdx)
** booked and a transfer to that area is in progress. Otherwise, we will
** release the area and re-assign it.
****************************************************************************/
-int SetCircular(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD)
+int SetCircular(DEVICE_EXTENSION *pdx, struct transfer_area_desc __user *pTD)
{
int iReturn;
bool bToHost;
- TRANSFERDESC td;
+ struct transfer_area_desc td;
if (copy_from_user(&td, pTD, sizeof(td)))
return -EFAULT;
mutex_lock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s area:%d, size:%08x", __func__,
- td.wAreaNum, td.dwLength);
+ dev_dbg(&pdx->interface->dev, "%s: area:%d, size:%08x\n",
+ __func__, td.wAreaNum, td.dwLength);
bToHost = td.eSize != 0; /* this is used as the tohost flag */
/* The strange cast is done so that we don't get warnings in 32-bit linux about the size of the */
@@ -1353,7 +1354,7 @@ int GetCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB)
unsigned int nArea;
TCIRCBLOCK cb;
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
if (copy_from_user(&cb, pCB, sizeof(cb)))
return -EFAULT;
@@ -1374,7 +1375,7 @@ int GetCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB)
cb.dwOffset = pArea->aBlocks[0].dwOffset;
cb.dwSize = pArea->aBlocks[0].dwSize;
dev_dbg(&pdx->interface->dev,
- "%s return block 0: %d bytes at %d",
+ "%s: return block 0: %d bytes at %d\n",
__func__, cb.dwSize, cb.dwOffset);
}
} else
@@ -1402,7 +1403,7 @@ int FreeCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB)
unsigned int nArea, uStart, uSize;
TCIRCBLOCK cb;
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
if (copy_from_user(&cb, pCB, sizeof(cb)))
return -EFAULT;
@@ -1437,7 +1438,7 @@ int FreeCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB)
}
dev_dbg(&pdx->interface->dev,
- "%s free %d bytes at %d, return %d bytes at %d, wait=%d",
+ "%s: free %d bytes at %d, return %d bytes at %d, wait=%d\n",
__func__, uSize, uStart,
pArea->aBlocks[0].dwSize,
pArea->aBlocks[0].dwOffset,
@@ -1453,13 +1454,13 @@ int FreeCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB)
bWaiting = pdx->bXFerWaiting;
if (bWaiting && pdx->bStagedUrbPending) {
dev_err(&pdx->interface->dev,
- "%s ERROR: waiting xfer and staged Urb pending!",
+ "%s: ERROR: waiting xfer and staged Urb pending!\n",
__func__);
bWaiting = false;
}
} else {
dev_err(&pdx->interface->dev,
- "%s ERROR: freeing %d bytes at %d, block 0 is %d bytes at %d",
+ "%s: ERROR: freeing %d bytes at %d, block 0 is %d bytes at %d\n",
__func__, uSize, uStart,
pArea->aBlocks[0].dwSize,
pArea->aBlocks[0].dwOffset);
@@ -1475,7 +1476,7 @@ int FreeCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB)
pdx->rDMAInfo.dwSize);
if (RWMStat != U14ERR_NOERROR)
dev_err(&pdx->interface->dev,
- "%s rw setup failed %d",
+ "%s: rw setup failed %d\n",
__func__, RWMStat);
}
} else
diff --git a/drivers/staging/ced1401/ced_ioctl.h b/drivers/staging/ced1401/ced_ioctl.h
index aa68878bd251..4b6c9dedb21e 100644
--- a/drivers/staging/ced1401/ced_ioctl.h
+++ b/drivers/staging/ced1401/ced_ioctl.h
@@ -26,24 +26,21 @@
** TypeDefs
*****************************************************************************/
-typedef unsigned short TBLOCKENTRY; /* index the blk transfer table 0-7 */
-
-typedef struct TransferDesc {
+struct transfer_area_desc {
long long lpvBuff; /* address of transfer area (for 64 or 32 bit) */
unsigned int dwLength; /* length of the area */
- TBLOCKENTRY wAreaNum; /* number of transfer area to set up */
+ unsigned short wAreaNum; /* number of transfer area to set up */
short eSize; /* element size - is tohost flag for circular */
-} TRANSFERDESC;
+};
-typedef TRANSFERDESC *LPTRANSFERDESC;
-typedef struct TransferEvent {
+struct transfer_event {
unsigned int dwStart; /* offset into the area */
unsigned int dwLength; /* length of the region */
unsigned short wAreaNum; /* the area number */
unsigned short wFlags; /* bit 0 set for toHost */
int iSetEvent; /* could be dummy in LINUX */
-} TRANSFEREVENT;
+};
#define MAX_TRANSFER_SIZE 0x4000 /* Maximum data bytes per IRP */
#define MAX_AREA_LENGTH 0x100000 /* Maximum size of transfer area */
@@ -85,12 +82,6 @@ typedef struct TCSBlock {
*/
#define CED_MAGIC_IOC 0xce
-/* NBNB: READ and WRITE are from the point of view of the device, not user. */
-typedef struct ced_ioc_string {
- int nChars;
- char buffer[256];
-} CED_IOC_STRING;
-
#define IOCTL_CED_SENDSTRING(n) _IOC(_IOC_WRITE, CED_MAGIC_IOC, 2, n)
#define IOCTL_CED_RESET1401 _IO(CED_MAGIC_IOC, 3)
@@ -100,9 +91,9 @@ typedef struct ced_ioc_string {
#define IOCTL_CED_LINECOUNT _IO(CED_MAGIC_IOC, 7)
#define IOCTL_CED_GETSTRING(nMax) _IOC(_IOC_READ, CED_MAGIC_IOC, 8, nMax)
-#define IOCTL_CED_SETTRANSFER _IOW(CED_MAGIC_IOC, 11, TRANSFERDESC)
+#define IOCTL_CED_SETTRANSFER _IOW(CED_MAGIC_IOC, 11, struct transfer_area_desc)
#define IOCTL_CED_UNSETTRANSFER _IO(CED_MAGIC_IOC, 12)
-#define IOCTL_CED_SETEVENT _IOW(CED_MAGIC_IOC, 13, TRANSFEREVENT)
+#define IOCTL_CED_SETEVENT _IOW(CED_MAGIC_IOC, 13, struct transfer_event)
#define IOCTL_CED_GETOUTBUFSPACE _IO(CED_MAGIC_IOC, 14)
#define IOCTL_CED_GETBASEADDRESS _IO(CED_MAGIC_IOC, 15)
#define IOCTL_CED_GETDRIVERREVISION _IO(CED_MAGIC_IOC, 16)
@@ -126,7 +117,7 @@ typedef struct ced_ioc_string {
#define IOCTL_CED_DBGGETDATA _IOR(CED_MAGIC_IOC, 39, TDBGBLOCK)
#define IOCTL_CED_DBGSTOPLOOP _IO(CED_MAGIC_IOC, 40)
#define IOCTL_CED_FULLRESET _IO(CED_MAGIC_IOC, 41)
-#define IOCTL_CED_SETCIRCULAR _IOW(CED_MAGIC_IOC, 42, TRANSFERDESC)
+#define IOCTL_CED_SETCIRCULAR _IOW(CED_MAGIC_IOC, 42, struct transfer_area_desc)
#define IOCTL_CED_GETCIRCBLOCK _IOWR(CED_MAGIC_IOC, 43, TCIRCBLOCK)
#define IOCTL_CED_FREECIRCBLOCK _IOWR(CED_MAGIC_IOC, 44, TCIRCBLOCK)
#define IOCTL_CED_WAITEVENT _IO(CED_MAGIC_IOC, 45)
@@ -198,7 +189,7 @@ inline int CED_GetDriverRevision(int fh)
return ioctl(fh, IOCTL_CED_GETDRIVERREVISION);
}
-inline int CED_SetTransfer(int fh, TRANSFERDESC *pTD)
+inline int CED_SetTransfer(int fh, struct transfer_area_desc *pTD)
{
return ioctl(fh, IOCTL_CED_SETTRANSFER, pTD);
}
@@ -208,7 +199,7 @@ inline int CED_UnsetTransfer(int fh, int nArea)
return ioctl(fh, IOCTL_CED_UNSETTRANSFER, nArea);
}
-inline int CED_SetEvent(int fh, TRANSFEREVENT *pTE)
+inline int CED_SetEvent(int fh, struct transfer_event *pTE)
{
return ioctl(fh, IOCTL_CED_SETEVENT, pTE);
}
@@ -299,7 +290,7 @@ inline int CED_FullReset(int fh)
return ioctl(fh, IOCTL_CED_FULLRESET);
}
-inline int CED_SetCircular(int fh, TRANSFERDESC *pTD)
+inline int CED_SetCircular(int fh, struct transfer_area_desc *pTD)
{
return ioctl(fh, IOCTL_CED_SETCIRCULAR, pTD);
}
diff --git a/drivers/staging/ced1401/usb1401.c b/drivers/staging/ced1401/usb1401.c
index efc310ca789e..284abc08922c 100644
--- a/drivers/staging/ced1401/usb1401.c
+++ b/drivers/staging/ced1401/usb1401.c
@@ -166,7 +166,7 @@ static int ced_open(struct inode *inode, struct file *file)
goto exit;
}
- dev_dbg(&interface->dev, "%s got pdx", __func__);
+ dev_dbg(&interface->dev, "%s: got pdx\n", __func__);
/* increment our usage count for the device */
kref_get(&pdx->kref);
@@ -184,7 +184,7 @@ static int ced_open(struct inode *inode, struct file *file)
goto exit;
}
} else { /* uncomment this block if you want exclusive open */
- dev_err(&interface->dev, "%s fail: already open", __func__);
+ dev_err(&interface->dev, "%s: fail: already open\n", __func__);
retval = -EBUSY;
pdx->open_count--;
mutex_unlock(&pdx->io_mutex);
@@ -207,7 +207,7 @@ static int ced_release(struct inode *inode, struct file *file)
if (pdx == NULL)
return -ENODEV;
- dev_dbg(&pdx->interface->dev, "%s called", __func__);
+ dev_dbg(&pdx->interface->dev, "%s: called\n", __func__);
mutex_lock(&pdx->io_mutex);
if (!--pdx->open_count && pdx->interface) /* Allow autosuspend */
usb_autopm_put_interface(pdx->interface);
@@ -224,12 +224,12 @@ static int ced_flush(struct file *file, fl_owner_t id)
if (pdx == NULL)
return -ENODEV;
- dev_dbg(&pdx->interface->dev, "%s char in pend=%d", __func__,
- pdx->bReadCharsPending);
+ dev_dbg(&pdx->interface->dev, "%s: char in pend=%d\n",
+ __func__, pdx->bReadCharsPending);
/* wait for io to stop */
mutex_lock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s got io_mutex", __func__);
+ dev_dbg(&pdx->interface->dev, "%s: got io_mutex\n", __func__);
ced_draw_down(pdx);
/* read out errors, leave subsequent opens a clean slate */
@@ -239,7 +239,7 @@ static int ced_flush(struct file *file, fl_owner_t id)
spin_unlock_irq(&pdx->err_lock);
mutex_unlock(&pdx->io_mutex);
- dev_dbg(&pdx->interface->dev, "%s exit reached", __func__);
+ dev_dbg(&pdx->interface->dev, "%s: exit reached\n", __func__);
return res;
}
@@ -270,7 +270,7 @@ static void ced_writechar_callback(struct urb *pUrb)
(pUrb->status == -ENOENT || pUrb->status == -ECONNRESET
|| pUrb->status == -ESHUTDOWN)) {
dev_err(&pdx->interface->dev,
- "%s - nonzero write bulk status received: %d",
+ "%s: nonzero write bulk status received: %d\n",
__func__, pUrb->status);
}
@@ -287,10 +287,10 @@ static void ced_writechar_callback(struct urb *pUrb)
pdx->bSendCharsPending = false; /* Allow other threads again */
spin_unlock(&pdx->charOutLock); /* already at irq level */
dev_dbg(&pdx->interface->dev,
- "%s - char out done, 0 chars sent", __func__);
+ "%s: char out done, 0 chars sent\n", __func__);
} else {
dev_dbg(&pdx->interface->dev,
- "%s - char out done, %d chars sent", __func__, nGot);
+ "%s: char out done, %d chars sent\n", __func__, nGot);
spin_lock(&pdx->charOutLock); /* already at irq level */
pdx->dwNumOutput -= nGot; /* Now adjust the char send buffer */
pdx->dwOutBuffGet += nGot; /* to match what we did */
@@ -315,15 +315,15 @@ static void ced_writechar_callback(struct urb *pUrb)
URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(pdx->pUrbCharOut, &pdx->submitted); /* in case we need to kill it */
iReturn = usb_submit_urb(pdx->pUrbCharOut, GFP_ATOMIC);
- dev_dbg(&pdx->interface->dev, "%s n=%d>%s<", __func__,
- dwCount, pDat);
+ dev_dbg(&pdx->interface->dev, "%s: n=%d>%s<\n",
+ __func__, dwCount, pDat);
spin_lock(&pdx->charOutLock); /* grab lock for errors */
if (iReturn) {
pdx->bPipeError[nPipe] = 1; /* Flag an error to be handled later */
pdx->bSendCharsPending = false; /* Allow other threads again */
usb_unanchor_urb(pdx->pUrbCharOut);
dev_err(&pdx->interface->dev,
- "%s usb_submit_urb() returned %d",
+ "%s: usb_submit_urb() returned %d\n",
__func__, iReturn);
}
} else
@@ -350,8 +350,8 @@ int SendChars(DEVICE_EXTENSION *pdx)
pdx->bSendCharsPending = true; /* Set flag to lock out other threads */
dev_dbg(&pdx->interface->dev,
- "Send %d chars to 1401, EP0 flag %d\n", dwCount,
- pdx->nPipes == 3);
+ "Send %d chars to 1401, EP0 flag %d\n",
+ dwCount, pdx->nPipes == 3);
/* If we have only 3 end points we must send the characters to the 1401 using EP0. */
if (pdx->nPipes == 3) {
/* For EP0 character transmissions to the 1401, we have to hang about until they */
@@ -375,11 +375,11 @@ int SendChars(DEVICE_EXTENSION *pdx)
if (nSent <= 0) {
iReturn = nSent ? nSent : -ETIMEDOUT; /* if 0 chars says we timed out */
dev_err(&pdx->interface->dev,
- "Send %d chars by EP0 failed: %d",
+ "Send %d chars by EP0 failed: %d\n",
n, iReturn);
} else {
dev_dbg(&pdx->interface->dev,
- "Sent %d chars by EP0", n);
+ "Sent %d chars by EP0\n", n);
count -= nSent;
index += nSent;
}
@@ -416,9 +416,9 @@ int SendChars(DEVICE_EXTENSION *pdx)
}
} else if (pdx->bSendCharsPending && (pdx->dwNumOutput > 0))
dev_dbg(&pdx->interface->dev,
- "SendChars bSendCharsPending:true");
+ "%s: bSendCharsPending:true\n", __func__);
- dev_dbg(&pdx->interface->dev, "SendChars exit code: %d", iReturn);
+ dev_dbg(&pdx->interface->dev, "%s: exit code: %d\n", __func__, iReturn);
spin_unlock_irq(&pdx->charOutLock); /* Now let go of the spinlock */
return iReturn;
}
@@ -446,7 +446,7 @@ static void CopyUserSpace(DEVICE_EXTENSION *pdx, int n)
pdx->StagedDone + pdx->StagedOffset + pArea->dwBaseOffset;
char *pCoherBuf = pdx->pCoherStagedIO; /* coherent buffer */
if (!pArea->bUsed) {
- dev_err(&pdx->interface->dev, "%s area %d unused",
+ dev_err(&pdx->interface->dev, "%s: area %d unused\n",
__func__, nArea);
return;
}
@@ -474,21 +474,21 @@ static void CopyUserSpace(DEVICE_EXTENSION *pdx, int n)
n -= uiXfer;
} else {
dev_err(&pdx->interface->dev,
- "%s did not map page %d",
+ "%s: did not map page %d\n",
__func__, nPage);
return;
}
} else {
dev_err(&pdx->interface->dev,
- "%s exceeded pages %d", __func__,
- nPage);
+ "%s: exceeded pages %d\n",
+ __func__, nPage);
return;
}
}
} else
- dev_err(&pdx->interface->dev, "%s bad area %d", __func__,
- nArea);
+ dev_err(&pdx->interface->dev, "%s: bad area %d\n",
+ __func__, nArea);
}
/* Forward declarations for stuff used circularly */
@@ -513,11 +513,11 @@ static void staged_callback(struct urb *pUrb)
(pUrb->status == -ENOENT || pUrb->status == -ECONNRESET
|| pUrb->status == -ESHUTDOWN)) {
dev_err(&pdx->interface->dev,
- "%s - nonzero write bulk status received: %d",
+ "%s: nonzero write bulk status received: %d\n",
__func__, pUrb->status);
} else
dev_info(&pdx->interface->dev,
- "%s - staged xfer cancelled", __func__);
+ "%s: staged xfer cancelled\n", __func__);
spin_lock(&pdx->err_lock);
pdx->errors = pUrb->status;
@@ -525,26 +525,26 @@ static void staged_callback(struct urb *pUrb)
nGot = 0; /* and tidy up again if so */
bCancel = true;
} else {
- dev_dbg(&pdx->interface->dev, "%s %d chars xferred", __func__,
- nGot);
+ dev_dbg(&pdx->interface->dev, "%s: %d chars xferred\n",
+ __func__, nGot);
if (pdx->StagedRead) /* if reading, save to user space */
CopyUserSpace(pdx, nGot); /* copy from buffer to user */
if (nGot == 0)
- dev_dbg(&pdx->interface->dev, "%s ZLP", __func__);
+ dev_dbg(&pdx->interface->dev, "%s: ZLP\n", __func__);
}
/* Update the transfer length based on the TransferBufferLength value in the URB */
pdx->StagedDone += nGot;
- dev_dbg(&pdx->interface->dev, "%s, done %d bytes of %d", __func__,
- pdx->StagedDone, pdx->StagedLength);
+ dev_dbg(&pdx->interface->dev, "%s: done %d bytes of %d\n",
+ __func__, pdx->StagedDone, pdx->StagedLength);
if ((pdx->StagedDone == pdx->StagedLength) || /* If no more to do */
(bCancel)) { /* or this IRP was cancelled */
TRANSAREA *pArea = &pdx->rTransDef[pdx->StagedId]; /* Transfer area info */
dev_dbg(&pdx->interface->dev,
- "%s transfer done, bytes %d, cancel %d", __func__,
- pdx->StagedDone, bCancel);
+ "%s: transfer done, bytes %d, cancel %d\n",
+ __func__, pdx->StagedDone, bCancel);
/* Here is where we sort out what to do with this transfer if using a circular buffer. We have */
/* a completed transfer that can be assumed to fit into the transfer area. We should be able to */
@@ -559,7 +559,7 @@ static void staged_callback(struct urb *pUrb)
pArea->aBlocks[1].dwSize +=
pdx->StagedLength;
dev_dbg(&pdx->interface->dev,
- "RWM_Complete, circ block 1 now %d bytes at %d",
+ "RWM_Complete, circ block 1 now %d bytes at %d\n",
pArea->aBlocks[1].dwSize,
pArea->aBlocks[1].dwOffset);
} else {
@@ -569,7 +569,7 @@ static void staged_callback(struct urb *pUrb)
pArea->aBlocks[1].dwSize =
pdx->StagedLength;
dev_err(&pdx->interface->dev,
- "%s ERROR, circ block 1 re-started %d bytes at %d",
+ "%s: ERROR, circ block 1 re-started %d bytes at %d\n",
__func__,
pArea->aBlocks[1].dwSize,
pArea->aBlocks[1].dwOffset);
@@ -582,7 +582,7 @@ static void staged_callback(struct urb *pUrb)
pArea->aBlocks[0].dwSize)) {
pArea->aBlocks[0].dwSize += pdx->StagedLength; /* Just add this transfer in */
dev_dbg(&pdx->interface->dev,
- "RWM_Complete, circ block 0 now %d bytes at %d",
+ "RWM_Complete, circ block 0 now %d bytes at %d\n",
pArea->aBlocks[0].
dwSize,
pArea->aBlocks[0].
@@ -593,7 +593,7 @@ static void staged_callback(struct urb *pUrb)
pArea->aBlocks[1].dwSize =
pdx->StagedLength;
dev_dbg(&pdx->interface->dev,
- "RWM_Complete, circ block 1 started %d bytes at %d",
+ "RWM_Complete, circ block 1 started %d bytes at %d\n",
pArea->aBlocks[1].
dwSize,
pArea->aBlocks[1].
@@ -605,7 +605,7 @@ static void staged_callback(struct urb *pUrb)
pArea->aBlocks[0].dwSize =
pdx->StagedLength;
dev_dbg(&pdx->interface->dev,
- "RWM_Complete, circ block 0 started %d bytes at %d",
+ "RWM_Complete, circ block 0 started %d bytes at %d\n",
pArea->aBlocks[0].dwSize,
pArea->aBlocks[0].dwOffset);
}
@@ -614,7 +614,7 @@ static void staged_callback(struct urb *pUrb)
if (!bCancel) { /* Don't generate an event if cancelled */
dev_dbg(&pdx->interface->dev,
- "RWM_Complete, bCircular %d, bToHost %d, eStart %d, eSize %d",
+ "RWM_Complete, bCircular %d, bToHost %d, eStart %d, eSize %d\n",
pArea->bCircular, pArea->bEventToHost,
pArea->dwEventSt, pArea->dwEventSz);
if ((pArea->dwEventSz) && /* Set a user-mode event... */
@@ -641,7 +641,7 @@ static void staged_callback(struct urb *pUrb)
if (iWakeUp) {
dev_dbg(&pdx->interface->dev,
- "About to set event to notify app");
+ "About to set event to notify app\n");
wake_up_interruptible(&pArea->wqEvent); /* wake up waiting processes */
++pArea->iWakeUp; /* increment wakeup count */
}
@@ -655,7 +655,7 @@ static void staged_callback(struct urb *pUrb)
if (pdx->bXFerWaiting) { /* Got a block xfer waiting? */
int iReturn;
dev_info(&pdx->interface->dev,
- "*** RWM_Complete *** pending transfer will now be set up!!!");
+ "*** RWM_Complete *** pending transfer will now be set up!!!\n");
iReturn =
ReadWriteMem(pdx, !pdx->rDMAInfo.bOutWard,
pdx->rDMAInfo.wIdent,
@@ -664,7 +664,7 @@ static void staged_callback(struct urb *pUrb)
if (iReturn)
dev_err(&pdx->interface->dev,
- "RWM_Complete rw setup failed %d",
+ "RWM_Complete rw setup failed %d\n",
iReturn);
}
}
@@ -685,7 +685,7 @@ static void staged_callback(struct urb *pUrb)
/* not be upset by char input during DMA... sigh. Needs sorting out. */
if (bRestartCharInput) /* may be out of date, but... */
Allowi(pdx); /* ...Allowi tests a lock too. */
- dev_dbg(&pdx->interface->dev, "%s done", __func__);
+ dev_dbg(&pdx->interface->dev, "%s: done\n", __func__);
}
/****************************************************************************
@@ -707,7 +707,7 @@ static int StageChunk(DEVICE_EXTENSION *pdx)
return U14ERR_FAIL;
if (!CanAcceptIoRequests(pdx)) { /* got sudden remove? */
- dev_info(&pdx->interface->dev, "%s sudden remove, giving up",
+ dev_info(&pdx->interface->dev, "%s: sudden remove, giving up\n",
__func__);
return U14ERR_FAIL; /* could do with a better error */
}
@@ -731,11 +731,11 @@ static int StageChunk(DEVICE_EXTENSION *pdx)
if (iReturn) {
usb_unanchor_urb(pdx->pStagedUrb); /* kill it */
pdx->bPipeError[nPipe] = 1; /* Flag an error to be handled later */
- dev_err(&pdx->interface->dev, "%s submit urb failed, code %d",
+ dev_err(&pdx->interface->dev, "%s: submit urb failed, code %d\n",
__func__, iReturn);
} else
pdx->bStagedUrbPending = true; /* Set the flag for staged URB pending */
- dev_dbg(&pdx->interface->dev, "%s done so far:%d, this size:%d",
+ dev_dbg(&pdx->interface->dev, "%s: done so far:%d, this size:%d\n",
__func__, pdx->StagedDone, ChunkSize);
return iReturn;
@@ -764,28 +764,28 @@ int ReadWriteMem(DEVICE_EXTENSION *pdx, bool Read, unsigned short wIdent,
TRANSAREA *pArea = &pdx->rTransDef[wIdent]; /* Transfer area info */
if (!CanAcceptIoRequests(pdx)) { /* Are we in a state to accept new requests? */
- dev_err(&pdx->interface->dev, "%s can't accept requests",
+ dev_err(&pdx->interface->dev, "%s: can't accept requests\n",
__func__);
return U14ERR_FAIL;
}
dev_dbg(&pdx->interface->dev,
- "%s xfer %d bytes to %s, offset %d, area %d", __func__, dwLen,
- Read ? "host" : "1401", dwOffs, wIdent);
+ "%s: xfer %d bytes to %s, offset %d, area %d\n",
+ __func__, dwLen, Read ? "host" : "1401", dwOffs, wIdent);
/* Amazingly, we can get an escape sequence back before the current staged Urb is done, so we */
/* have to check for this situation and, if so, wait until all is OK. */
if (pdx->bStagedUrbPending) {
pdx->bXFerWaiting = true; /* Flag we are waiting */
dev_info(&pdx->interface->dev,
- "%s xfer is waiting, as previous staged pending",
+ "%s: xfer is waiting, as previous staged pending\n",
__func__);
return U14ERR_NOERROR;
}
if (dwLen == 0) { /* allow 0-len read or write; just return success */
dev_dbg(&pdx->interface->dev,
- "%s OK; zero-len read/write request", __func__);
+ "%s: OK; zero-len read/write request\n", __func__);
return U14ERR_NOERROR;
}
@@ -795,7 +795,7 @@ int ReadWriteMem(DEVICE_EXTENSION *pdx, bool Read, unsigned short wIdent,
bool bWait = false; /* Flag for transfer having to wait */
dev_dbg(&pdx->interface->dev,
- "Circular buffers are %d at %d and %d at %d",
+ "Circular buffers are %d at %d and %d at %d\n",
pArea->aBlocks[0].dwSize, pArea->aBlocks[0].dwOffset,
pArea->aBlocks[1].dwSize, pArea->aBlocks[1].dwOffset);
if (pArea->aBlocks[1].dwSize > 0) { /* Using the second block already? */
@@ -819,14 +819,14 @@ int ReadWriteMem(DEVICE_EXTENSION *pdx, bool Read, unsigned short wIdent,
if (bWait) { /* This transfer will have to wait? */
pdx->bXFerWaiting = true; /* Flag we are waiting */
dev_dbg(&pdx->interface->dev,
- "%s xfer waiting for circular buffer space",
+ "%s: xfer waiting for circular buffer space\n",
__func__);
return U14ERR_NOERROR;
}
dev_dbg(&pdx->interface->dev,
- "%s circular xfer, %d bytes starting at %d", __func__,
- dwLen, dwOffs);
+ "%s: circular xfer, %d bytes starting at %d\n",
+ __func__, dwLen, dwOffs);
}
/* Save the parameters for the read\write transfer */
pdx->StagedRead = Read; /* Save the parameters for this read */
@@ -948,7 +948,7 @@ static bool ReadDMAInfo(volatile DMADESC *pDmaDesc, DEVICE_EXTENSION *pdx,
unsigned char ucData;
unsigned int dDone = 0; /* We haven't parsed anything so far */
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
if (ReadChar(&ucData, pBuf, &dDone, dwCount)) {
unsigned char ucTransCode = (ucData & 0x0F); /* get code for transfer type */
@@ -960,8 +960,8 @@ static bool ReadDMAInfo(volatile DMADESC *pDmaDesc, DEVICE_EXTENSION *pdx,
pDmaDesc->dwSize = 0; /* initialise other bits */
pDmaDesc->dwOffset = 0;
- dev_dbg(&pdx->interface->dev, "%s type: %d ident: %d", __func__,
- pDmaDesc->wTransType, pDmaDesc->wIdent);
+ dev_dbg(&pdx->interface->dev, "%s: type: %d ident: %d\n",
+ __func__, pDmaDesc->wTransType, pDmaDesc->wIdent);
pDmaDesc->bOutWard = (ucTransCode != TM_EXTTOHOST); /* set transfer direction */
@@ -976,7 +976,7 @@ static bool ReadDMAInfo(volatile DMADESC *pDmaDesc, DEVICE_EXTENSION *pdx,
&dDone, dwCount);
if (bResult) {
dev_dbg(&pdx->interface->dev,
- "%s xfer offset & size %d %d",
+ "%s: xfer offset & size %d %d\n",
__func__, pDmaDesc->dwOffset,
pDmaDesc->dwSize);
@@ -989,7 +989,7 @@ static bool ReadDMAInfo(volatile DMADESC *pDmaDesc, DEVICE_EXTENSION *pdx,
dwLength))) {
bResult = false; /* bad parameter(s) */
dev_dbg(&pdx->interface->dev,
- "%s bad param - id %d, bUsed %d, offset %d, size %d, area length %d",
+ "%s: bad param - id %d, bUsed %d, offset %d, size %d, area length %d\n",
__func__, wIdent,
pdx->rTransDef[wIdent].
bUsed,
@@ -1008,7 +1008,7 @@ static bool ReadDMAInfo(volatile DMADESC *pDmaDesc, DEVICE_EXTENSION *pdx,
bResult = false;
if (!bResult) /* now check parameters for validity */
- dev_err(&pdx->interface->dev, "%s error reading Esc sequence",
+ dev_err(&pdx->interface->dev, "%s: error reading Esc sequence\n",
__func__);
return bResult;
@@ -1045,15 +1045,15 @@ static int Handle1401Esc(DEVICE_EXTENSION *pdx, char *pCh,
unsigned short wTransType = pdx->rDMAInfo.wTransType; /* check transfer type */
dev_dbg(&pdx->interface->dev,
- "%s xfer to %s, offset %d, length %d", __func__,
+ "%s: xfer to %s, offset %d, length %d\n",
+ __func__,
pdx->rDMAInfo.bOutWard ? "1401" : "host",
pdx->rDMAInfo.dwOffset, pdx->rDMAInfo.dwSize);
if (pdx->bXFerWaiting) { /* Check here for badly out of kilter... */
/* This can never happen, really */
dev_err(&pdx->interface->dev,
- "ERROR: DMA setup while transfer still waiting");
- spin_unlock(&pdx->stagedLock);
+ "ERROR: DMA setup while transfer still waiting\n");
} else {
if ((wTransType == TM_EXTTOHOST)
|| (wTransType == TM_EXTTO1401)) {
@@ -1066,21 +1066,21 @@ static int Handle1401Esc(DEVICE_EXTENSION *pdx, char *pCh,
pdx->rDMAInfo.dwSize);
if (iReturn != U14ERR_NOERROR)
dev_err(&pdx->interface->dev,
- "%s ReadWriteMem() failed %d",
+ "%s: ReadWriteMem() failed %d\n",
__func__, iReturn);
} else /* This covers non-linear transfer setup */
dev_err(&pdx->interface->dev,
- "%s Unknown block xfer type %d",
+ "%s: Unknown block xfer type %d\n",
__func__, wTransType);
}
} else /* Failed to read parameters */
- dev_err(&pdx->interface->dev, "%s ReadDMAInfo() fail",
+ dev_err(&pdx->interface->dev, "%s: ReadDMAInfo() fail\n",
__func__);
spin_unlock(&pdx->stagedLock); /* OK here */
}
- dev_dbg(&pdx->interface->dev, "%s returns %d", __func__, iReturn);
+ dev_dbg(&pdx->interface->dev, "%s: returns %d\n", __func__, iReturn);
return iReturn;
}
@@ -1100,11 +1100,11 @@ static void ced_readchar_callback(struct urb *pUrb)
(pUrb->status == -ENOENT || pUrb->status == -ECONNRESET
|| pUrb->status == -ESHUTDOWN)) {
dev_err(&pdx->interface->dev,
- "%s - nonzero write bulk status received: %d",
+ "%s: nonzero write bulk status received: %d\n",
__func__, pUrb->status);
} else
dev_dbg(&pdx->interface->dev,
- "%s - 0 chars pUrb->status=%d (shutdown?)",
+ "%s: 0 chars pUrb->status=%d (shutdown?)\n",
__func__, pUrb->status);
spin_lock(&pdx->err_lock);
@@ -1125,7 +1125,7 @@ static void ced_readchar_callback(struct urb *pUrb)
if (nGot < INBUF_SZ) {
pdx->pCoherCharIn[nGot] = 0; /* tidy the string */
dev_dbg(&pdx->interface->dev,
- "%s got %d chars >%s<",
+ "%s: got %d chars >%s<\n",
__func__, nGot,
pdx->pCoherCharIn);
}
@@ -1140,7 +1140,7 @@ static void ced_readchar_callback(struct urb *pUrb)
if ((pdx->dwNumInput + nGot) <= INBUF_SZ)
pdx->dwNumInput += nGot; /* Adjust the buffer count accordingly */
} else
- dev_dbg(&pdx->interface->dev, "%s read ZLP",
+ dev_dbg(&pdx->interface->dev, "%s: read ZLP\n",
__func__);
}
}
@@ -1178,7 +1178,7 @@ int Allowi(DEVICE_EXTENSION *pdx)
unsigned int nMax = INBUF_SZ - pdx->dwNumInput; /* max we could read */
int nPipe = pdx->nPipes == 4 ? 1 : 0; /* The pipe number to use */
- dev_dbg(&pdx->interface->dev, "%s %d chars in input buffer",
+ dev_dbg(&pdx->interface->dev, "%s: %d chars in input buffer\n",
__func__, pdx->dwNumInput);
usb_fill_int_urb(pdx->pUrbCharIn, pdx->udev,
@@ -1192,7 +1192,8 @@ int Allowi(DEVICE_EXTENSION *pdx)
usb_unanchor_urb(pdx->pUrbCharIn); /* remove from list of active Urbs */
pdx->bPipeError[nPipe] = 1; /* Flag an error to be handled later */
dev_err(&pdx->interface->dev,
- "%s submit urb failed: %d", __func__, iReturn);
+ "%s: submit urb failed: %d\n",
+ __func__, iReturn);
} else
pdx->bReadCharsPending = true; /* Flag that we are active here */
}
@@ -1250,13 +1251,13 @@ static long ced_ioctl(struct file *file, unsigned int cmd, unsigned long ulArg)
return GetString(pdx, (char __user *)ulArg, _IOC_SIZE(cmd));
case _IOC_NR(IOCTL_CED_SETTRANSFER):
- return SetTransfer(pdx, (TRANSFERDESC __user *) ulArg);
+ return SetTransfer(pdx, (struct transfer_area_desc __user *) ulArg);
case _IOC_NR(IOCTL_CED_UNSETTRANSFER):
return UnsetTransfer(pdx, (int)ulArg);
case _IOC_NR(IOCTL_CED_SETEVENT):
- return SetEvent(pdx, (TRANSFEREVENT __user *) ulArg);
+ return SetEvent(pdx, (struct transfer_event __user *) ulArg);
case _IOC_NR(IOCTL_CED_GETOUTBUFSPACE):
return GetOutBufSpace(pdx);
@@ -1315,7 +1316,7 @@ static long ced_ioctl(struct file *file, unsigned int cmd, unsigned long ulArg)
break;
case _IOC_NR(IOCTL_CED_SETCIRCULAR):
- return SetCircular(pdx, (TRANSFERDESC __user *) ulArg);
+ return SetCircular(pdx, (struct transfer_area_desc __user *) ulArg);
case _IOC_NR(IOCTL_CED_GETCIRCBLOCK):
return GetCircBlock(pdx, (TCIRCBLOCK __user *) ulArg);
@@ -1397,7 +1398,7 @@ static int ced_probe(struct usb_interface *interface,
else if ((i >= 1) && (i <= 23))
pdx->s1401Type = i + 2;
else {
- dev_err(&interface->dev, "%s Unknown device. bcdDevice = %d",
+ dev_err(&interface->dev, "%s: Unknown device. bcdDevice = %d\n",
__func__, bcdDevice);
goto error;
}
@@ -1405,7 +1406,7 @@ static int ced_probe(struct usb_interface *interface,
/* we know that we are dealing with a 1401 device. */
iface_desc = interface->cur_altsetting;
pdx->nPipes = iface_desc->desc.bNumEndpoints;
- dev_info(&interface->dev, "1401Type=%d with %d End Points",
+ dev_info(&interface->dev, "1401Type=%d with %d End Points\n",
pdx->s1401Type, pdx->nPipes);
if ((pdx->nPipes < 3) || (pdx->nPipes > 4))
goto error;
@@ -1415,7 +1416,7 @@ static int ced_probe(struct usb_interface *interface,
pdx->pUrbCharIn = usb_alloc_urb(0, GFP_KERNEL); /* character input URB */
pdx->pStagedUrb = usb_alloc_urb(0, GFP_KERNEL); /* block transfer URB */
if (!pdx->pUrbCharOut || !pdx->pUrbCharIn || !pdx->pStagedUrb) {
- dev_err(&interface->dev, "%s URB alloc failed", __func__);
+ dev_err(&interface->dev, "%s: URB alloc failed\n", __func__);
goto error;
}
@@ -1429,7 +1430,7 @@ static int ced_probe(struct usb_interface *interface,
usb_alloc_coherent(pdx->udev, INBUF_SZ, GFP_KERNEL,
&pdx->pUrbCharIn->transfer_dma);
if (!pdx->pCoherCharOut || !pdx->pCoherCharIn || !pdx->pCoherStagedIO) {
- dev_err(&interface->dev, "%s Coherent buffer alloc failed",
+ dev_err(&interface->dev, "%s: Coherent buffer alloc failed\n",
__func__);
goto error;
}
@@ -1437,19 +1438,19 @@ static int ced_probe(struct usb_interface *interface,
for (i = 0; i < pdx->nPipes; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
pdx->epAddr[i] = endpoint->bEndpointAddress;
- dev_info(&interface->dev, "Pipe %d, ep address %02x", i,
- pdx->epAddr[i]);
+ dev_info(&interface->dev, "Pipe %d, ep address %02x\n",
+ i, pdx->epAddr[i]);
if (((pdx->nPipes == 3) && (i == 0)) || /* if char input end point */
((pdx->nPipes == 4) && (i == 1))) {
pdx->bInterval = endpoint->bInterval; /* save the endpoint interrupt interval */
- dev_info(&interface->dev, "Pipe %d, bInterval = %d", i,
- pdx->bInterval);
+ dev_info(&interface->dev, "Pipe %d, bInterval = %d\n",
+ i, pdx->bInterval);
}
/* Detect USB2 by checking last ep size (64 if USB1) */
if (i == pdx->nPipes - 1) { /* if this is the last ep (bulk) */
pdx->bIsUSB2 =
le16_to_cpu(endpoint->wMaxPacketSize) > 64;
- dev_info(&pdx->interface->dev, "USB%d",
+ dev_info(&pdx->interface->dev, "USB%d\n",
pdx->bIsUSB2 + 1);
}
}
@@ -1462,14 +1463,14 @@ static int ced_probe(struct usb_interface *interface,
if (retval) {
/* something prevented us from registering this driver */
dev_err(&interface->dev,
- "Not able to get a minor for this device.\n");
+ "Not able to get a minor for this device\n");
usb_set_intfdata(interface, NULL);
goto error;
}
/* let the user know what node this device is now attached to */
dev_info(&interface->dev,
- "USB CEDUSB device now attached to cedusb #%d",
+ "USB CEDUSB device now attached to cedusb #%d\n",
interface->minor);
return 0;
@@ -1493,7 +1494,7 @@ static void ced_disconnect(struct usb_interface *interface)
for (i = 0; i < MAX_TRANSAREAS; ++i) {
int iErr = ClearArea(pdx, i); /* ...release any used memory */
if (iErr == U14ERR_UNLOCKFAIL)
- dev_err(&pdx->interface->dev, "%s Area %d was in used",
+ dev_err(&pdx->interface->dev, "%s: Area %d was in used\n",
__func__, i);
}
pdx->interface = NULL; /* ...we kill off link to interface */
@@ -1503,7 +1504,7 @@ static void ced_disconnect(struct usb_interface *interface)
kref_put(&pdx->kref, ced_delete); /* decrement our usage count */
- dev_info(&interface->dev, "USB cedusb #%d now disconnected", minor);
+ dev_info(&interface->dev, "USB cedusb #%d now disconnected\n", minor);
}
/* Wait for all the urbs we know of to be done with, then kill off any that */
@@ -1513,13 +1514,13 @@ static void ced_disconnect(struct usb_interface *interface)
void ced_draw_down(DEVICE_EXTENSION *pdx)
{
int time;
- dev_dbg(&pdx->interface->dev, "%s called", __func__);
+ dev_dbg(&pdx->interface->dev, "%s: called\n", __func__);
pdx->bInDrawDown = true;
time = usb_wait_anchor_empty_timeout(&pdx->submitted, 3000);
if (!time) { /* if we timed out we kill the urbs */
usb_kill_anchored_urbs(&pdx->submitted);
- dev_err(&pdx->interface->dev, "%s timed out", __func__);
+ dev_err(&pdx->interface->dev, "%s: timed out\n", __func__);
}
pdx->bInDrawDown = false;
}
@@ -1531,7 +1532,7 @@ static int ced_suspend(struct usb_interface *intf, pm_message_t message)
return 0;
ced_draw_down(pdx);
- dev_dbg(&pdx->interface->dev, "%s called", __func__);
+ dev_dbg(&pdx->interface->dev, "%s: called\n", __func__);
return 0;
}
@@ -1540,14 +1541,14 @@ static int ced_resume(struct usb_interface *intf)
DEVICE_EXTENSION *pdx = usb_get_intfdata(intf);
if (!pdx)
return 0;
- dev_dbg(&pdx->interface->dev, "%s called", __func__);
+ dev_dbg(&pdx->interface->dev, "%s: called\n", __func__);
return 0;
}
static int ced_pre_reset(struct usb_interface *intf)
{
DEVICE_EXTENSION *pdx = usb_get_intfdata(intf);
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
mutex_lock(&pdx->io_mutex);
ced_draw_down(pdx);
return 0;
@@ -1556,7 +1557,7 @@ static int ced_pre_reset(struct usb_interface *intf)
static int ced_post_reset(struct usb_interface *intf)
{
DEVICE_EXTENSION *pdx = usb_get_intfdata(intf);
- dev_dbg(&pdx->interface->dev, "%s", __func__);
+ dev_dbg(&pdx->interface->dev, "%s\n", __func__);
/* we are sure no URBs are active - no locking needed */
pdx->errors = -EPIPE;
diff --git a/drivers/staging/ced1401/usb1401.h b/drivers/staging/ced1401/usb1401.h
index f031e3a2c7cf..ea0fe6398a01 100644
--- a/drivers/staging/ced1401/usb1401.h
+++ b/drivers/staging/ced1401/usb1401.h
@@ -218,9 +218,9 @@ extern bool QuickCheck(DEVICE_EXTENSION *pdx, bool bTestBuff, bool bCanReset);
extern int Reset1401(DEVICE_EXTENSION *pdx);
extern int GetChar(DEVICE_EXTENSION *pdx);
extern int GetString(DEVICE_EXTENSION *pdx, char __user *pUser, int n);
-extern int SetTransfer(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD);
+extern int SetTransfer(DEVICE_EXTENSION *pdx, struct transfer_area_desc __user *pTD);
extern int UnsetTransfer(DEVICE_EXTENSION *pdx, int nArea);
-extern int SetEvent(DEVICE_EXTENSION *pdx, TRANSFEREVENT __user *pTE);
+extern int SetEvent(DEVICE_EXTENSION *pdx, struct transfer_event __user *pTE);
extern int Stat1401(DEVICE_EXTENSION *pdx);
extern int LineCount(DEVICE_EXTENSION *pdx);
extern int GetOutBufSpace(DEVICE_EXTENSION *pdx);
@@ -238,7 +238,7 @@ extern int DbgRampData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB);
extern int DbgRampAddr(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB);
extern int DbgGetData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB);
extern int DbgStopLoop(DEVICE_EXTENSION *pdx);
-extern int SetCircular(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD);
+extern int SetCircular(DEVICE_EXTENSION *pdx, struct transfer_area_desc __user *pTD);
extern int GetCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB);
extern int FreeCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB);
extern int WaitEvent(DEVICE_EXTENSION *pdx, int nArea, int msTimeOut);
diff --git a/drivers/staging/ced1401/use14_ioc.h b/drivers/staging/ced1401/use14_ioc.h
index 97d7913840dc..42d2e4e6e9a9 100644
--- a/drivers/staging/ced1401/use14_ioc.h
+++ b/drivers/staging/ced1401/use14_ioc.h
@@ -276,15 +276,14 @@ typedef struct paramBlk {
typedef PARAMBLK* PPARAMBLK;
-typedef struct TransferDesc /* Structure and type for SetTransArea */
+struct transfer_area_desc /* Structure and type for SetTransArea */
{
unsigned short wArea; /* number of transfer area to set up */
void FAR *lpvBuff; /* address of transfer area */
unsigned int dwLength; /* length of area to set up */
short eSize; /* size to move (for swapping on MAC) */
-} TRANSFERDESC;
+};
-typedef TRANSFERDESC FAR *LPTRANSFERDESC;
/* This is the structure used to set up a transfer area */
typedef struct VXTransferDesc /* use1401.c and use1432x.x use only */
diff --git a/drivers/staging/ced1401/userspace/use1401.c b/drivers/staging/ced1401/userspace/use1401.c
index c9bc2ebfef1a..7b8a2227fe5b 100644
--- a/drivers/staging/ced1401/userspace/use1401.c
+++ b/drivers/staging/ced1401/userspace/use1401.c
@@ -2231,7 +2231,7 @@ U14API(short) U14UnSetTransfer(short hand, unsigned short wArea)
U14API(short) U14SetTransArea(short hand, unsigned short wArea, void *pvBuff,
unsigned int dwLength, short eSz)
{
- TRANSFERDESC td;
+ struct transfer_area_desc td;
short sErr = CheckHandle(hand);
if (sErr != U14ERR_NOERROR)
return sErr;
@@ -2292,7 +2292,7 @@ U14API(short) U14SetTransArea(short hand, unsigned short wArea, void *pvBuff,
td.eSize = 0; // Dummy element size
if (DeviceIoControl(aHand1401[hand],(unsigned int)U14_SETTRANSFER,
- &td,sizeof(TRANSFERDESC),
+ &td,sizeof(struct transfer_area_desc),
&rWork,sizeof(PARAMBLK),&dwBytes,NULL))
{
if (dwBytes >= sizeof(PARAMBLK)) // maybe error from driver?
@@ -2496,14 +2496,14 @@ U14API(short) U14SetCircular(short hand, unsigned short wArea, BOOL bToHost,
{
PARAMBLK rWork;
unsigned int dwBytes;
- TRANSFERDESC txDesc;
+ struct transfer_area_desc txDesc;
txDesc.wArea = wArea; /* Pure NT - put data into struct */
txDesc.lpvBuff = pvBuff;
txDesc.dwLength = dwLength;
txDesc.eSize = (short)bToHost; /* Use this for direction flag */
if (DeviceIoControl(aHand1401[hand],(unsigned int)U14_SETCIRCULAR,
- &txDesc, sizeof(TRANSFERDESC),
+ &txDesc, sizeof(struct transfer_area_desc),
&rWork, sizeof(PARAMBLK),&dwBytes,NULL))
{
if (dwBytes >= sizeof(PARAMBLK)) /* error from driver? */
@@ -2528,7 +2528,7 @@ U14API(short) U14SetCircular(short hand, unsigned short wArea, BOOL bToHost,
#ifdef LINUX
else
{
- TRANSFERDESC td;
+ struct transfer_area_desc td;
td.lpvBuff = (long long)((unsigned long)pvBuff);
td.wAreaNum = wArea;
td.dwLength = dwLength;
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 89e25b4203ad..703c5d40ae5c 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -177,6 +177,7 @@ config COMEDI_PCL730
config COMEDI_PCL812
tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216"
depends on VIRT_TO_BUS && ISA_DMA_API
+ select COMEDI_FC
---help---
Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink
ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA,
@@ -188,6 +189,7 @@ config COMEDI_PCL812
config COMEDI_PCL816
tristate "Advantech PCL-814 and PCL-816 ISA card support"
depends on VIRT_TO_BUS && ISA_DMA_API
+ select COMEDI_FC
---help---
Enable support for Advantech PCL-814 and PCL-816 ISA cards
@@ -197,6 +199,7 @@ config COMEDI_PCL816
config COMEDI_PCL818
tristate "Advantech PCL-718 and PCL-818 ISA card support"
depends on VIRT_TO_BUS && ISA_DMA_API
+ select COMEDI_FC
---help---
Enable support for Advantech PCL-818 ISA cards
PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718
@@ -257,6 +260,14 @@ config COMEDI_RTI802
To compile this driver as a module, choose M here: the module will be
called rti802.
+config COMEDI_DAC02
+ tristate "Keithley Metrabyte DAC02 compatible ISA card support"
+ ---help---
+ Enable support for Keithley Metrabyte DAC02 compatible ISA cards.
+
+ To compile this driver as a module, choose M here: the module will be
+ called dac02.
+
config COMEDI_DAS16M1
tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support"
select COMEDI_8255
@@ -559,15 +570,6 @@ config COMEDI_MULTIQ3
To compile this driver as a module, choose M here: the module will be
called multiq3.
-config COMEDI_POC
- tristate "Generic driver for very simple devices"
- ---help---
- Enable generic support for very simple / POC (Piece of Crap) boards,
- Keithley Metrabyte DAC-02 (dac02).
-
- To compile this driver as a module, choose M here: the module will be
- called poc.
-
config COMEDI_S526
tristate "Sensoray s526 support"
---help---
@@ -753,6 +755,7 @@ config COMEDI_ADL_PCI9118
config COMEDI_ADV_PCI1710
tristate "Advantech PCI-171x, PCI-1720 and PCI-1731 support"
+ select COMEDI_FC
---help---
Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711,
PCI-1713, PCI-1720 and PCI-1731
@@ -856,6 +859,7 @@ config COMEDI_DAS08_PCI
config COMEDI_DT3000
tristate "Data Translation DT3000 series support"
+ select COMEDI_FC
---help---
Enable support for Data Translation DT3000 series
DT3001, DT3001-PGL, DT3002, DT3003, DT3003-PGL, DT3004, DT3005 and
@@ -1101,6 +1105,7 @@ config COMEDI_S626
config COMEDI_MITE
depends on HAS_DMA
+ select COMEDI_FC
tristate
config COMEDI_NI_TIOCMD
@@ -1179,6 +1184,7 @@ config COMEDI_NI_MIO_CS
config COMEDI_QUATECH_DAQP_CS
tristate "Quatech DAQP PCMCIA data capture card support"
+ select COMEDI_FC
---help---
Enable support for the Quatech DAQP PCMCIA data capture cards
DAQP-208 and DAQP-308
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index c22c617b0da1..ea6dc36d753b 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -297,7 +297,7 @@ static ssize_t max_read_buffer_kb_show(struct device *csdev,
mutex_unlock(&dev->mutex);
comedi_dev_put(dev);
- return snprintf(buf, PAGE_SIZE, "%i\n", size);
+ return snprintf(buf, PAGE_SIZE, "%u\n", size);
}
static ssize_t max_read_buffer_kb_store(struct device *csdev,
@@ -353,7 +353,7 @@ static ssize_t read_buffer_kb_show(struct device *csdev,
mutex_unlock(&dev->mutex);
comedi_dev_put(dev);
- return snprintf(buf, PAGE_SIZE, "%i\n", size);
+ return snprintf(buf, PAGE_SIZE, "%u\n", size);
}
static ssize_t read_buffer_kb_store(struct device *csdev,
@@ -410,7 +410,7 @@ static ssize_t max_write_buffer_kb_show(struct device *csdev,
mutex_unlock(&dev->mutex);
comedi_dev_put(dev);
- return snprintf(buf, PAGE_SIZE, "%i\n", size);
+ return snprintf(buf, PAGE_SIZE, "%u\n", size);
}
static ssize_t max_write_buffer_kb_store(struct device *csdev,
@@ -466,7 +466,7 @@ static ssize_t write_buffer_kb_show(struct device *csdev,
mutex_unlock(&dev->mutex);
comedi_dev_put(dev);
- return snprintf(buf, PAGE_SIZE, "%i\n", size);
+ return snprintf(buf, PAGE_SIZE, "%u\n", size);
}
static ssize_t write_buffer_kb_store(struct device *csdev,
@@ -1194,6 +1194,11 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
switch (insn->insn) {
case INSN_READ:
ret = s->insn_read(dev, s, insn, data);
+ if (ret == -ETIMEDOUT) {
+ dev_dbg(dev->class_dev,
+ "subdevice %d read instruction timed out\n",
+ s->index);
+ }
break;
case INSN_WRITE:
maxdata = s->maxdata_list
@@ -1207,8 +1212,14 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
break;
}
}
- if (ret == 0)
+ if (ret == 0) {
ret = s->insn_write(dev, s, insn, data);
+ if (ret == -ETIMEDOUT) {
+ dev_dbg(dev->class_dev,
+ "subdevice %d write instruction timed out\n",
+ s->index);
+ }
+ }
break;
case INSN_BITS:
if (insn->n != 2) {
@@ -1405,41 +1416,94 @@ error:
return ret;
}
-static int do_cmd_ioctl(struct comedi_device *dev,
- struct comedi_cmd __user *arg, void *file)
+static int __comedi_get_user_cmd(struct comedi_device *dev,
+ struct comedi_cmd __user *arg,
+ struct comedi_cmd *cmd)
{
- struct comedi_cmd cmd;
struct comedi_subdevice *s;
- struct comedi_async *async;
- int ret = 0;
- unsigned int __user *user_chanlist;
- if (copy_from_user(&cmd, arg, sizeof(cmd))) {
+ if (copy_from_user(cmd, arg, sizeof(*cmd))) {
dev_dbg(dev->class_dev, "bad cmd address\n");
return -EFAULT;
}
- /* save user's chanlist pointer so it can be restored later */
- user_chanlist = (unsigned int __user *)cmd.chanlist;
- if (cmd.subdev >= dev->n_subdevices) {
- dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd.subdev);
+ if (cmd->subdev >= dev->n_subdevices) {
+ dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd->subdev);
return -ENODEV;
}
- s = &dev->subdevices[cmd.subdev];
- async = s->async;
+ s = &dev->subdevices[cmd->subdev];
if (s->type == COMEDI_SUBD_UNUSED) {
- dev_dbg(dev->class_dev, "%d not valid subdevice\n", cmd.subdev);
+ dev_dbg(dev->class_dev, "%d not valid subdevice\n", cmd->subdev);
return -EIO;
}
if (!s->do_cmd || !s->do_cmdtest || !s->async) {
dev_dbg(dev->class_dev,
- "subdevice %i does not support commands\n", cmd.subdev);
+ "subdevice %d does not support commands\n", cmd->subdev);
return -EIO;
}
+ /* make sure channel/gain list isn't too long */
+ if (cmd->chanlist_len > s->len_chanlist) {
+ dev_dbg(dev->class_dev, "channel/gain list too long %d > %d\n",
+ cmd->chanlist_len, s->len_chanlist);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int __comedi_get_user_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int __user *user_chanlist,
+ struct comedi_cmd *cmd)
+{
+ unsigned int *chanlist;
+ int ret;
+
+ /* user_chanlist could be NULL for do_cmdtest ioctls */
+ if (!user_chanlist)
+ return 0;
+
+ chanlist = memdup_user(user_chanlist,
+ cmd->chanlist_len * sizeof(unsigned int));
+ if (IS_ERR(chanlist))
+ return PTR_ERR(chanlist);
+
+ /* make sure each element in channel/gain list is valid */
+ ret = comedi_check_chanlist(s, cmd->chanlist_len, chanlist);
+ if (ret < 0) {
+ kfree(chanlist);
+ return ret;
+ }
+
+ cmd->chanlist = chanlist;
+
+ return 0;
+}
+
+static int do_cmd_ioctl(struct comedi_device *dev,
+ struct comedi_cmd __user *arg, void *file)
+{
+ struct comedi_cmd cmd;
+ struct comedi_subdevice *s;
+ struct comedi_async *async;
+ unsigned int __user *user_chanlist;
+ int ret;
+
+ /* get the user's cmd and do some simple validation */
+ ret = __comedi_get_user_cmd(dev, arg, &cmd);
+ if (ret)
+ return ret;
+
+ /* save user's chanlist pointer so it can be restored later */
+ user_chanlist = (unsigned int __user *)cmd.chanlist;
+
+ s = &dev->subdevices[cmd.subdev];
+ async = s->async;
+
/* are we locked? (ioctl lock) */
if (s->lock && s->lock != file) {
dev_dbg(dev->class_dev, "subdevice locked\n");
@@ -1452,13 +1516,6 @@ static int do_cmd_ioctl(struct comedi_device *dev,
return -EBUSY;
}
- /* make sure channel/gain list isn't too long */
- if (cmd.chanlist_len > s->len_chanlist) {
- dev_dbg(dev->class_dev, "channel/gain list too long %u > %d\n",
- cmd.chanlist_len, s->len_chanlist);
- return -EINVAL;
- }
-
/* make sure channel/gain list isn't too short */
if (cmd.chanlist_len < 1) {
dev_dbg(dev->class_dev, "channel/gain list too short %u < 1\n",
@@ -1468,25 +1525,11 @@ static int do_cmd_ioctl(struct comedi_device *dev,
async->cmd = cmd;
async->cmd.data = NULL;
- /* load channel/gain list */
- async->cmd.chanlist = memdup_user(user_chanlist,
- async->cmd.chanlist_len * sizeof(int));
- if (IS_ERR(async->cmd.chanlist)) {
- ret = PTR_ERR(async->cmd.chanlist);
- async->cmd.chanlist = NULL;
- dev_dbg(dev->class_dev, "memdup_user failed with code %d\n",
- ret);
- goto cleanup;
- }
- /* make sure each element in channel/gain list is valid */
- ret = comedi_check_chanlist(s,
- async->cmd.chanlist_len,
- async->cmd.chanlist);
- if (ret < 0) {
- dev_dbg(dev->class_dev, "bad chanlist\n");
+ /* load channel/gain list */
+ ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &async->cmd);
+ if (ret)
goto cleanup;
- }
ret = s->do_cmdtest(dev, s, &async->cmd);
@@ -1554,63 +1597,24 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
{
struct comedi_cmd cmd;
struct comedi_subdevice *s;
- int ret = 0;
unsigned int *chanlist = NULL;
unsigned int __user *user_chanlist;
+ int ret;
+
+ /* get the user's cmd and do some simple validation */
+ ret = __comedi_get_user_cmd(dev, arg, &cmd);
+ if (ret)
+ return ret;
- if (copy_from_user(&cmd, arg, sizeof(cmd))) {
- dev_dbg(dev->class_dev, "bad cmd address\n");
- return -EFAULT;
- }
/* save user's chanlist pointer so it can be restored later */
user_chanlist = (unsigned int __user *)cmd.chanlist;
- if (cmd.subdev >= dev->n_subdevices) {
- dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd.subdev);
- return -ENODEV;
- }
-
s = &dev->subdevices[cmd.subdev];
- if (s->type == COMEDI_SUBD_UNUSED) {
- dev_dbg(dev->class_dev, "%d not valid subdevice\n", cmd.subdev);
- return -EIO;
- }
-
- if (!s->do_cmd || !s->do_cmdtest) {
- dev_dbg(dev->class_dev,
- "subdevice %i does not support commands\n", cmd.subdev);
- return -EIO;
- }
-
- /* make sure channel/gain list isn't too long */
- if (cmd.chanlist_len > s->len_chanlist) {
- dev_dbg(dev->class_dev, "channel/gain list too long %d > %d\n",
- cmd.chanlist_len, s->len_chanlist);
- ret = -EINVAL;
- goto cleanup;
- }
/* load channel/gain list */
- if (cmd.chanlist) {
- chanlist = memdup_user(user_chanlist,
- cmd.chanlist_len * sizeof(int));
- if (IS_ERR(chanlist)) {
- ret = PTR_ERR(chanlist);
- chanlist = NULL;
- dev_dbg(dev->class_dev,
- "memdup_user exited with code %d", ret);
- goto cleanup;
- }
-
- /* make sure each element in channel/gain list is valid */
- ret = comedi_check_chanlist(s, cmd.chanlist_len, chanlist);
- if (ret < 0) {
- dev_dbg(dev->class_dev, "bad chanlist\n");
- goto cleanup;
- }
-
- cmd.chanlist = chanlist;
- }
+ ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd);
+ if (ret)
+ return ret;
ret = s->do_cmdtest(dev, s, &cmd);
@@ -1620,9 +1624,8 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
dev_dbg(dev->class_dev, "bad cmd address\n");
ret = -EFAULT;
- goto cleanup;
}
-cleanup:
+
kfree(chanlist);
return ret;
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index f82bd4256d51..d46123a97582 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -61,31 +61,31 @@ struct comedi_subdevice {
unsigned int *chanlist; /* driver-owned chanlist (not used) */
- int (*insn_read) (struct comedi_device *, struct comedi_subdevice *,
+ int (*insn_read)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*insn_write)(struct comedi_device *, struct comedi_subdevice *,
struct comedi_insn *, unsigned int *);
- int (*insn_write) (struct comedi_device *, struct comedi_subdevice *,
+ int (*insn_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*insn_config)(struct comedi_device *, struct comedi_subdevice *,
struct comedi_insn *, unsigned int *);
- int (*insn_bits) (struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
- int (*insn_config) (struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
-
- int (*do_cmd) (struct comedi_device *, struct comedi_subdevice *);
- int (*do_cmdtest) (struct comedi_device *, struct comedi_subdevice *,
- struct comedi_cmd *);
- int (*poll) (struct comedi_device *, struct comedi_subdevice *);
- int (*cancel) (struct comedi_device *, struct comedi_subdevice *);
+
+ int (*do_cmd)(struct comedi_device *, struct comedi_subdevice *);
+ int (*do_cmdtest)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_cmd *);
+ int (*poll)(struct comedi_device *, struct comedi_subdevice *);
+ int (*cancel)(struct comedi_device *, struct comedi_subdevice *);
/* int (*do_lock)(struct comedi_device *, struct comedi_subdevice *); */
/* int (*do_unlock)(struct comedi_device *, \
struct comedi_subdevice *); */
/* called when the buffer changes */
- int (*buf_change) (struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned long new_size);
+ int (*buf_change)(struct comedi_device *dev,
+ struct comedi_subdevice *s, unsigned long new_size);
- void (*munge) (struct comedi_device *dev, struct comedi_subdevice *s,
- void *data, unsigned int num_bytes,
- unsigned int start_chan_index);
+ void (*munge)(struct comedi_device *dev, struct comedi_subdevice *s,
+ void *data, unsigned int num_bytes,
+ unsigned int start_chan_index);
enum dma_data_direction async_dma_dir;
unsigned int state;
@@ -146,8 +146,8 @@ struct comedi_async {
unsigned int cb_mask;
- int (*inttrig) (struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int x);
+ int (*inttrig)(struct comedi_device *dev, struct comedi_subdevice *s,
+ unsigned int x);
};
struct comedi_driver {
@@ -155,9 +155,9 @@ struct comedi_driver {
const char *driver_name;
struct module *module;
- int (*attach) (struct comedi_device *, struct comedi_devconfig *);
- void (*detach) (struct comedi_device *);
- int (*auto_attach) (struct comedi_device *, unsigned long);
+ int (*attach)(struct comedi_device *, struct comedi_devconfig *);
+ void (*detach)(struct comedi_device *);
+ int (*auto_attach)(struct comedi_device *, unsigned long);
/* number of elements in board_name and board_id arrays */
unsigned int num_names;
@@ -202,8 +202,8 @@ struct comedi_device {
struct fasync_struct *async_queue;
- int (*open) (struct comedi_device *dev);
- void (*close) (struct comedi_device *dev);
+ int (*open)(struct comedi_device *dev);
+ void (*close)(struct comedi_device *dev);
};
static inline const void *comedi_board(const struct comedi_device *dev)
@@ -353,6 +353,14 @@ void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset,
/* drivers.c - general comedi driver functions */
+#define COMEDI_TIMEOUT_MS 1000
+
+int comedi_timeout(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *,
+ int (*cb)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned long context),
+ unsigned long context);
+
int comedi_dio_insn_config(struct comedi_device *, struct comedi_subdevice *,
struct comedi_insn *, unsigned int *data,
unsigned int mask);
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index 5b15033a94bf..ab0e8ed47291 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -155,6 +155,36 @@ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
}
/**
+ * comedi_timeout() - busy-wait for a driver condition to occur.
+ * @dev: comedi_device struct
+ * @s: comedi_subdevice struct
+ * @insn: comedi_insn struct
+ * @cb: callback to check for the condition
+ * @context: private context from the driver
+ */
+int comedi_timeout(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ int (*cb)(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context),
+ unsigned long context)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(COMEDI_TIMEOUT_MS);
+ int ret;
+
+ while (time_before(jiffies, timeout)) {
+ ret = cb(dev, s, insn, context);
+ if (ret != -EBUSY)
+ return ret; /* success (0) or non EBUSY errno */
+ cpu_relax();
+ }
+ return -ETIMEDOUT;
+}
+EXPORT_SYMBOL_GPL(comedi_timeout);
+
+/**
* comedi_dio_insn_config() - boilerplate (*insn_config) for DIO subdevices.
* @dev: comedi_device struct
* @s: comedi_subdevice struct
diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c
index 8a57c3c1ade0..46a385c29ba8 100644
--- a/drivers/staging/comedi/drivers/8255_pci.c
+++ b/drivers/staging/comedi/drivers/8255_pci.c
@@ -56,6 +56,7 @@ Configuration Options: not applicable, uses PCI auto config
#include "../comedidev.h"
#include "8255.h"
+#include "mite.h"
enum pci_8255_boardid {
BOARD_ADLINK_PCI7224,
@@ -79,6 +80,7 @@ struct pci_8255_boardinfo {
const char *name;
int dio_badr;
int n_8255;
+ unsigned int has_mite:1;
};
static const struct pci_8255_boardinfo pci_8255_boards[] = {
@@ -126,36 +128,43 @@ static const struct pci_8255_boardinfo pci_8255_boards[] = {
.name = "ni_pci-dio-96",
.dio_badr = 1,
.n_8255 = 4,
+ .has_mite = 1,
},
[BOARD_NI_PCIDIO96B] = {
.name = "ni_pci-dio-96b",
.dio_badr = 1,
.n_8255 = 4,
+ .has_mite = 1,
},
[BOARD_NI_PXI6508] = {
.name = "ni_pxi-6508",
.dio_badr = 1,
.n_8255 = 4,
+ .has_mite = 1,
},
[BOARD_NI_PCI6503] = {
.name = "ni_pci-6503",
.dio_badr = 1,
.n_8255 = 1,
+ .has_mite = 1,
},
[BOARD_NI_PCI6503B] = {
.name = "ni_pci-6503b",
.dio_badr = 1,
.n_8255 = 1,
+ .has_mite = 1,
},
[BOARD_NI_PCI6503X] = {
.name = "ni_pci-6503x",
.dio_badr = 1,
.n_8255 = 1,
+ .has_mite = 1,
},
[BOARD_NI_PXI_6503] = {
.name = "ni_pxi-6503",
.dio_badr = 1,
.n_8255 = 1,
+ .has_mite = 1,
},
};
@@ -163,6 +172,25 @@ struct pci_8255_private {
void __iomem *mmio_base;
};
+static int pci_8255_mite_init(struct pci_dev *pcidev)
+{
+ void __iomem *mite_base;
+ u32 main_phys_addr;
+
+ /* ioremap the MITE registers (BAR 0) temporarily */
+ mite_base = pci_ioremap_bar(pcidev, 0);
+ if (!mite_base)
+ return -ENOMEM;
+
+ /* set data window to main registers (BAR 1) */
+ main_phys_addr = pci_resource_start(pcidev, 1);
+ writel(main_phys_addr | WENAB, mite_base + MITE_IODWBSR);
+
+ /* finished with MITE registers */
+ iounmap(mite_base);
+ return 0;
+}
+
static int pci_8255_mmio(int dir, int port, int data, unsigned long iobase)
{
void __iomem *mmio_base = (void __iomem *)iobase;
@@ -201,6 +229,12 @@ static int pci_8255_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
+ if (board->has_mite) {
+ ret = pci_8255_mite_init(pcidev);
+ if (ret)
+ return ret;
+ }
+
is_mmio = (pci_resource_flags(pcidev, board->dio_badr) &
IORESOURCE_MEM) != 0;
if (is_mmio) {
@@ -235,9 +269,6 @@ static int pci_8255_auto_attach(struct comedi_device *dev,
return ret;
}
- dev_info(dev->class_dev, "%s attached (%d digital i/o channels)\n",
- dev->board_name, board->n_8255 * 24);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index 2706f583d8f0..0757a82ddcfa 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_COMEDI_PCL818) += pcl818.o
obj-$(CONFIG_COMEDI_PCM3724) += pcm3724.o
obj-$(CONFIG_COMEDI_RTI800) += rti800.o
obj-$(CONFIG_COMEDI_RTI802) += rti802.o
+obj-$(CONFIG_COMEDI_DAC02) += dac02.o
obj-$(CONFIG_COMEDI_DAS16M1) += das16m1.o
obj-$(CONFIG_COMEDI_DAS08_ISA) += das08_isa.o
obj-$(CONFIG_COMEDI_DAS16) += das16.o
@@ -53,7 +54,6 @@ obj-$(CONFIG_COMEDI_PCMDA12) += pcmda12.o
obj-$(CONFIG_COMEDI_PCMMIO) += pcmmio.o
obj-$(CONFIG_COMEDI_PCMUIO) += pcmuio.o
obj-$(CONFIG_COMEDI_MULTIQ3) += multiq3.o
-obj-$(CONFIG_COMEDI_POC) += poc.o
obj-$(CONFIG_COMEDI_S526) += s526.o
# Comedi PCI drivers
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c
index 1128c22e7517..28450f65a134 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c
@@ -1,46 +1,24 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.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.
-
-@endverbatim
-*/
/*
-
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-------------------------------+---------------------------------------+
- | Project : APCI-035 | Compiler : GCC |
- | Module name : hwdrv_apci035.c | Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-------------------------------+---------------------------------------+
- | Description : Hardware Layer Access For APCI-035 |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +----------+-----------+------------------------------------------------+
- | Date | Author | Description of updates |
- +----------+-----------+------------------------------------------------+
- | | | |
- | | | |
- | | | |
- +----------+-----------+------------------------------------------------+
-*/
+ * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
+ *
+ * ADDI-DATA GmbH
+ * Dieselstrasse 3
+ * D-77833 Ottersweier
+ * Tel: +19(0)7223/9493-0
+ * Fax: +49(0)7223/9493-92
+ * http://www.addi-data.com
+ * info@addi-data.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.
+ */
/* Card Specific information */
#define APCI035_ADDRESS_RANGE 255
@@ -106,99 +84,66 @@ static struct comedi_lrange range_apci035_ai = {
}
};
-static int i_WatchdogNbr = 0;
-static int i_Temp = 0;
+static int i_WatchdogNbr;
+static int i_Temp;
static int i_Flag = 1;
+
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI035_ConfigTimerWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Configures The Timer , Counter or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[0] : 0 Configure As Timer |
-| 1 Configure As Watchdog |
-| data[1] : Watchdog number
-| data[2] : Time base Unit |
-| data[3] : Reload Value |
-| data[4] : External Trigger |
-| 1:Enable
-| 0:Disable
-| data[5] :External Trigger Level
-| 00 Trigger Disabled
-| 01 Trigger Enabled (Low level)
-| 10 Trigger Enabled (High Level)
-| 11 Trigger Enabled (High/Low level)
-| data[6] : External Gate |
-| 1:Enable
-| 0:Disable
-| data[7] : External Gate level
-| 00 Gate Disabled
-| 01 Gate Enabled (Low level)
-| 10 Gate Enabled (High Level)
-| data[8] :Warning Relay
-| 1: ENABLE
-| 0: DISABLE
-| data[9] :Warning Delay available
-| data[10] :Warning Relay Time unit
-| data[11] :Warning Relay Time Reload value
-| data[12] :Reset Relay
-| 1 : ENABLE
-| 0 : DISABLE
-| data[13] :Interrupt
-| 1 : ENABLE
-| 0 : DISABLE
-|
-|
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures The Timer , Counter or Watchdog
+ *
+ * data[0] 0 = Configure As Timer, 1 = Configure As Watchdog
+ * data[1] Watchdog number
+ * data[2] Time base Unit
+ * data[3] Reload Value
+ * data[4] External Trigger, 1 = Enable, 0 = Disable
+ * data[5] External Trigger Level
+ * 00 = Trigger Disabled
+ * 01 = Trigger Enabled (Low level)
+ * 10 = Trigger Enabled (High Level)
+ * 11 = Trigger Enabled (High/Low level)
+ * data[6] External Gate, 1 = Enable, 0 = Disable
+ * data[7] External Gate level
+ * 00 = Gate Disabled
+ * 01 = Gate Enabled (Low level)
+ * 10 = Gate Enabled (High Level)
+ * data[8] Warning Relay, 1 = Enable, 0 = Disable
+ * data[9] Warning Delay available
+ * data[10] Warning Relay Time unit
+ * data[11] Warning Relay Time Reload value
+ * data[12] Reset Relay, 1 = Enable, 0 = Disable
+ * data[13] Interrupt, 1 = Enable, 0 = Disable
+ */
+static int apci035_timer_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
- unsigned int ui_Status = 0;
- unsigned int ui_Command = 0;
- unsigned int ui_Mode = 0;
+ unsigned int ui_Status;
+ unsigned int ui_Command;
+ unsigned int ui_Mode;
i_Temp = 0;
devpriv->tsk_Current = current;
devpriv->b_TimerSelectMode = data[0];
i_WatchdogNbr = data[1];
- if (data[0] == 0) {
+ if (data[0] == 0)
ui_Mode = 2;
- } else {
+ else
ui_Mode = 0;
- }
-/* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); */
+
ui_Command = 0;
-/* ui_Command = ui_Command & 0xFFFFF9FEUL; */
outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- ui_Command = 0;
+
ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
-/************************/
-/* Set the reload value */
-/************************/
+
+ /* Set the reload value */
outl(data[3], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 4);
-/*********************/
-/* Set the time unit */
-/*********************/
+
+ /* Set the time unit */
outl(data[2], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 8);
if (data[0] == ADDIDATA_TIMER) {
- /******************************/
/* Set the mode : */
/* - Disable the hardware */
/* - Disable the counter mode */
@@ -206,101 +151,82 @@ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev,
/* - Disable the reset */
/* - Enable the timer mode */
/* - Set the timer mode */
- /******************************/
ui_Command =
(ui_Command & 0xFFF719E2UL) | ui_Mode << 13UL | 0x10UL;
- } /* if (data[0] == ADDIDATA_TIMER) */
- else {
- if (data[0] == ADDIDATA_WATCHDOG) {
+ } else if (data[0] == ADDIDATA_WATCHDOG) {
- /******************************/
- /* Set the mode : */
- /* - Disable the hardware */
- /* - Disable the counter mode */
- /* - Disable the warning */
- /* - Disable the reset */
- /* - Disable the timer mode */
- /******************************/
+ /* Set the mode : */
+ /* - Disable the hardware */
+ /* - Disable the counter mode */
+ /* - Disable the warning */
+ /* - Disable the reset */
+ /* - Disable the timer mode */
- ui_Command = ui_Command & 0xFFF819E2UL;
+ ui_Command = ui_Command & 0xFFF819E2UL;
- } else {
- printk("\n The parameter for Timer/watchdog selection is in error\n");
- return -EINVAL;
- }
+ } else {
+ dev_err(dev->class_dev, "The parameter for Timer/watchdog selection is in error\n");
+ return -EINVAL;
}
+
outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- ui_Command = 0;
+
ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
-/********************************/
-/* Disable the hardware trigger */
-/********************************/
+
+ /* Disable the hardware trigger */
ui_Command = ui_Command & 0xFFFFF89FUL;
if (data[4] == ADDIDATA_ENABLE) {
- /**********************************/
+
/* Set the hardware trigger level */
- /**********************************/
ui_Command = ui_Command | (data[5] << 5);
}
outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- ui_Command = 0;
+
ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
-/*****************************/
-/* Disable the hardware gate */
-/*****************************/
+
+ /* Disable the hardware gate */
ui_Command = ui_Command & 0xFFFFF87FUL;
if (data[6] == ADDIDATA_ENABLE) {
-/*******************************/
-/* Set the hardware gate level */
-/*******************************/
+
+ /* Set the hardware gate level */
ui_Command = ui_Command | (data[7] << 7);
}
outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- ui_Command = 0;
+
ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
-/*******************************/
-/* Disable the hardware output */
-/*******************************/
+
+ /* Disable the hardware output */
ui_Command = ui_Command & 0xFFFFF9FBUL;
-/*********************************/
-/* Set the hardware output level */
-/*********************************/
+
+ /* Set the hardware output level */
ui_Command = ui_Command | (data[8] << 2);
outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
if (data[9] == ADDIDATA_ENABLE) {
- /************************/
+
/* Set the reload value */
- /************************/
outl(data[11],
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 24);
- /**********************/
+
/* Set the time unite */
- /**********************/
outl(data[10],
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 28);
}
- ui_Command = 0;
ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- /*******************************/
+
/* Disable the hardware output */
- /*******************************/
ui_Command = ui_Command & 0xFFFFF9F7UL;
- /*********************************/
+
/* Set the hardware output level */
- /*********************************/
ui_Command = ui_Command | (data[12] << 3);
outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- /*************************************/
- /** Enable the watchdog interrupt **/
- /*************************************/
- ui_Command = 0;
+
+ /* Enable the watchdog interrupt */
ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
-/*******************************/
-/* Set the interrupt selection */
-/*******************************/
+
+ /* Set the interrupt selection */
ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16);
ui_Command = (ui_Command & 0xFFFFF9FDUL) | (data[13] << 1);
@@ -310,82 +236,63 @@ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI035_StartStopWriteTimerWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Start / Stop The Selected Timer , or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[0] : 0 - Stop Selected Timer/Watchdog |
-| 1 - Start Selected Timer/Watchdog |
-| 2 - Trigger Selected Timer/Watchdog |
-| 3 - Stop All Timer/Watchdog |
-| 4 - Start All Timer/Watchdog |
-| 5 - Trigger All Timer/Watchdog |
-| |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Start / Stop The Selected Timer , or Watchdog
+ *
+ * data[0]
+ * 0 - Stop Selected Timer/Watchdog
+ * 1 - Start Selected Timer/Watch*dog
+ * 2 - Trigger Selected Timer/Watchdog
+ * 3 - Stop All Timer/Watchdog
+ * 4 - Start All Timer/Watchdog
+ * 5 - Trigger All Timer/Watchdog
+ */
+static int apci035_timer_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
- unsigned int ui_Command = 0;
- int i_Count = 0;
+ unsigned int ui_Command;
+ int i_Count;
if (data[0] == 1) {
ui_Command =
inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- /**********************/
+
/* Start the hardware */
- /**********************/
ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x1UL;
outl(ui_Command,
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- } /* if (data[0]==1) */
+ }
if (data[0] == 2) {
ui_Command =
inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- /***************************/
+
/* Set the trigger command */
- /***************************/
ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x200UL;
outl(ui_Command,
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
}
- if (data[0] == 0) /* Stop The Watchdog */
- {
+ if (data[0] == 0) {
/* Stop The Watchdog */
ui_Command = 0;
-/*
-* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12);
-* ui_Command = ui_Command & 0xFFFFF9FEUL;
-*/
+ /*
+ * ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12);
+ * ui_Command = ui_Command & 0xFFFFF9FEUL;
+ */
outl(ui_Command,
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- } /* if (data[1]==0) */
- if (data[0] == 3) /* stop all Watchdogs */
- {
+ }
+ if (data[0] == 3) {
+ /* stop all Watchdogs */
ui_Command = 0;
for (i_Count = 1; i_Count <= 4; i_Count++) {
- if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
+ if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG)
ui_Command = 0x2UL;
- } else {
+ else
ui_Command = 0x10UL;
- }
+
i_WatchdogNbr = i_Count;
outl(ui_Command,
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) +
@@ -393,30 +300,29 @@ static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev,
}
}
- if (data[0] == 4) /* start all Watchdogs */
- {
+ if (data[0] == 4) {
+ /* start all Watchdogs */
ui_Command = 0;
for (i_Count = 1; i_Count <= 4; i_Count++) {
- if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
+ if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG)
ui_Command = 0x1UL;
- } else {
+ else
ui_Command = 0x8UL;
- }
+
i_WatchdogNbr = i_Count;
outl(ui_Command,
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) +
0);
}
}
- if (data[0] == 5) /* trigger all Watchdogs */
- {
+ if (data[0] == 5) {
+ /* trigger all Watchdogs */
ui_Command = 0;
for (i_Count = 1; i_Count <= 4; i_Count++) {
- if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
+ if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG)
ui_Command = 0x4UL;
- } else {
+ else
ui_Command = 0x20UL;
- }
i_WatchdogNbr = i_Count;
outl(ui_Command,
@@ -429,109 +335,61 @@ static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI035_ReadTimerWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Read The Selected Timer , Counter or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| |
-+----------------------------------------------------------------------------+
-| Output Parameters : data[0] : software trigger status
-| data[1] : hardware trigger status
-| data[2] : Software clear status
-| data[3] : Overflow status
-| data[4] : Timer actual value
-|
-
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI035_ReadTimerWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Read The Selected Timer , Counter or Watchdog
+ *
+ * data[0] software trigger status
+ * data[1] hardware trigger status
+ * data[2] Software clear status
+ * data[3] Overflow status
+ * data[4] Timer actual value
+ */
+static int apci035_timer_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
- unsigned int ui_Status = 0; /* Status register */
+ unsigned int ui_Status; /* Status register */
i_WatchdogNbr = insn->unused[0];
- /******************/
/* Get the status */
- /******************/
-
ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16);
- /***********************************/
/* Get the software trigger status */
- /***********************************/
-
data[0] = ((ui_Status >> 1) & 1);
- /***********************************/
+
/* Get the hardware trigger status */
- /***********************************/
data[1] = ((ui_Status >> 2) & 1);
- /*********************************/
+
/* Get the software clear status */
- /*********************************/
data[2] = ((ui_Status >> 3) & 1);
- /***************************/
+
/* Get the overflow status */
- /***************************/
data[3] = ((ui_Status >> 0) & 1);
- if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) {
+ if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER)
data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0);
- } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */
-
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI035_ConfigAnalogInput |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Configures The Analog Input Subdevice |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| struct comedi_subdevice *s : Subdevice Pointer |
-| struct comedi_insn *insn : Insn Structure Pointer |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| data[0] : Warning delay value
-| |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI035_ConfigAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures The Analog Input Subdevice
+ *
+ * data[0] Warning delay value
+ */
+static int apci035_ai_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
devpriv->tsk_Current = current;
outl(0x200 | 0, devpriv->iobase + 128 + 0x4);
outl(0, devpriv->iobase + 128 + 0);
-/********************************/
-/* Initialise the warning value */
-/********************************/
+
+ /* Initialise the warning value */
outl(0x300 | 0, devpriv->iobase + 128 + 0x4);
outl((data[0] << 8), devpriv->iobase + 128 + 0);
outl(0x200000UL, devpriv->iobase + 128 + 12);
@@ -540,145 +398,88 @@ static int i_APCI035_ConfigAnalogInput(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI035_ReadAnalogInput |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Read value of the selected channel |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int ui_NoOfChannels : No Of Channels To read |
-| unsigned int *data : Data Pointer to read status |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-| data[0] : Digital Value Of Input |
-| |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI035_ReadAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Read value of the selected channel
+ *
+ * data[0] Digital Value Of Input
+ */
+static int apci035_ai_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
- unsigned int ui_CommandRegister = 0;
+ unsigned int ui_CommandRegister;
-/******************/
-/* Set the start */
-/******************/
+ /* Set the start */
ui_CommandRegister = 0x80000;
- /******************************/
+
/* Write the command register */
- /******************************/
outl(ui_CommandRegister, devpriv->iobase + 128 + 8);
-/***************************************/
-/* Read the digital value of the input */
-/***************************************/
+ /* Read the digital value of the input */
data[0] = inl(devpriv->iobase + 128 + 28);
return insn->n;
}
-/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI035_Reset(struct comedi_device *dev) |
-| |
-+----------------------------------------------------------------------------+
-| Task :Resets the registers of the card |
-+----------------------------------------------------------------------------+
-| Input Parameters : |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI035_Reset(struct comedi_device *dev)
+static int apci035_reset(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
- int i_Count = 0;
+ int i_Count;
for (i_Count = 1; i_Count <= 4; i_Count++) {
i_WatchdogNbr = i_Count;
- outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); /* stop all timers */
+
+ /* stop all timers */
+ outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0);
}
outl(0x0, devpriv->iobase + 128 + 12); /* Disable the warning delay */
return 0;
}
-/*
-+----------------------------------------------------------------------------+
-| Function Name : static void v_APCI035_Interrupt |
-| (int irq , void *d) |
-+----------------------------------------------------------------------------+
-| Task : Interrupt processing Routine |
-+----------------------------------------------------------------------------+
-| Input Parameters : int irq : irq number |
-| void *d : void pointer |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static void v_APCI035_Interrupt(int irq, void *d)
+static void apci035_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct addi_private *devpriv = dev->private;
- unsigned int ui_StatusRegister1 = 0;
- unsigned int ui_StatusRegister2 = 0;
- unsigned int ui_ReadCommand = 0;
- unsigned int ui_ChannelNumber = 0;
- unsigned int ui_DigitalTemperature = 0;
+ unsigned int ui_StatusRegister1;
+ unsigned int ui_StatusRegister2;
+ unsigned int ui_ReadCommand;
+ unsigned int ui_ChannelNumber;
+ unsigned int ui_DigitalTemperature;
if (i_Temp == 1) {
i_WatchdogNbr = i_Flag;
i_Flag = i_Flag + 1;
}
- /**************************************/
+
/* Read the interrupt status register of temperature Warning */
- /**************************************/
ui_StatusRegister1 = inl(devpriv->iobase + 128 + 16);
- /**************************************/
- /* Read the interrupt status register for Watchdog/timer */
- /**************************************/
+ /* Read the interrupt status register for Watchdog/timer */
ui_StatusRegister2 =
inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 20);
- if ((((ui_StatusRegister1) & 0x8) == 0x8)) /* Test if warning relay interrupt */
- {
- /**********************************/
+ /* Test if warning relay interrupt */
+ if ((((ui_StatusRegister1) & 0x8) == 0x8)) {
+
/* Disable the temperature warning */
- /**********************************/
ui_ReadCommand = inl(devpriv->iobase + 128 + 12);
ui_ReadCommand = ui_ReadCommand & 0xFFDF0000UL;
outl(ui_ReadCommand, devpriv->iobase + 128 + 12);
- /***************************/
+
/* Read the channel number */
- /***************************/
ui_ChannelNumber = inl(devpriv->iobase + 128 + 60);
- /**************************************/
+
/* Read the digital temperature value */
- /**************************************/
ui_DigitalTemperature = inl(devpriv->iobase + 128 + 60);
- send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
- } /* if (((ui_StatusRegister1 & 0x8) == 0x8)) */
- else {
- if ((ui_StatusRegister2 & 0x1) == 0x1) {
- send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
- }
- } /* else if (((ui_StatusRegister1 & 0x8) == 0x8)) */
+ /* send signal to the sample */
+ send_sig(SIGIO, devpriv->tsk_Current, 0);
+
+ } else if ((ui_StatusRegister2 & 0x1) == 0x1) {
+ /* send signal to the sample */
+ send_sig(SIGIO, devpriv->tsk_Current, 0);
+ }
return;
}
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
index 054910511e9e..a633957890d7 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
@@ -1,48 +1,25 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.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.
-
-@endverbatim
-*/
/*
-
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-------------------------------+---------------------------------------+
- | Project : APCI-1500 | Compiler : GCC |
- | Module name : hwdrv_apci1500.c| Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-------------------------------+---------------------------------------+
- | Description : Hardware Layer Access For APCI-1500 |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +----------+-----------+------------------------------------------------+
- | Date | Author | Description of updates |
- +----------+-----------+------------------------------------------------+
- | | | |
- | | | |
- | | | |
- +----------+-----------+------------------------------------------------+
-*/
-
-/********* Definitions for APCI-1500 card *****/
+ * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
+ *
+ * ADDI-DATA GmbH
+ * Dieselstrasse 3
+ * D-77833 Ottersweier
+ * Tel: +19(0)7223/9493-0
+ * Fax: +49(0)7223/9493-92
+ * http://www.addi-data.com
+ * info@addi-data.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.
+ *
+ */
/* Card Specific information */
#define APCI1500_ADDRESS_RANGE 4
@@ -141,99 +118,45 @@ enum {
APCI1500_RW_PORT_B_PATTERN_MASK
};
-static int i_TimerCounter1Init = 0;
-static int i_TimerCounter2Init = 0;
-static int i_WatchdogCounter3Init = 0;
-static int i_Event1Status = 0, i_Event2Status = 0;
-static int i_TimerCounterWatchdogInterrupt = 0;
-static int i_Logic = 0, i_CounterLogic = 0;
-static int i_InterruptMask = 0;
-static int i_InputChannel = 0;
-static int i_TimerCounter1Enabled = 0, i_TimerCounter2Enabled = 0,
- i_WatchdogCounter3Enabled = 0;
+static int i_TimerCounter1Init;
+static int i_TimerCounter2Init;
+static int i_WatchdogCounter3Init;
+static int i_Event1Status, i_Event2Status;
+static int i_TimerCounterWatchdogInterrupt;
+static int i_Logic, i_CounterLogic;
+static int i_InterruptMask;
+static int i_InputChannel;
+static int i_TimerCounter1Enabled, i_TimerCounter2Enabled,
+ i_WatchdogCounter3Enabled;
/*
- +----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_ConfigDigitalInputEvent |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : An event can be generated for each port. |
-| The first event is related to the first 8 channels |
-| (port 1) and the second to the following 6 channels |
-| (port 2). An interrupt is generated when one or both |
-| events have occurred |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[0] :Number of the input port on |
-| which the event will take place |
-| (1 or 2)
-| data[1] : The event logic for port 1 has |
-| three possibilities |
-| :0 APCI1500_AND :This logic |
-| links |
-| the inputs |
-| with an AND |
-| logic. |
-| 1 APCI1500_OR :This logic |
-| links |
-| the inputs |
-| with a |
-| OR logic. |
-| 2 APCI1500_OR_PRIORITY |
-| :This logic |
-| links |
-| the inputs |
-| with a |
-| priority |
-| OR logic. |
-| Input 1 |
-| has the |
-| highest |
-| priority |
-| level and |
-| input 8 |
-| the smallest|
-| For the second port the user has|
-| 1 possibility: |
-| APCI1500_OR :This logic |
-| links |
-| the inputs |
-| with a |
-| polarity |
-| OR logic |
-| data[2] : These 8-character word for port1|
-| and 6-character word for port 2 |
-| give the mask of the event. |
-| Each place gives the state |
-| of the input channels and can |
-| have one of these six characters|
-| |
-| 0 : This input must be on 0 |
-| 1 : This input must be on 1 |
-| 2 : This input reacts to |
-| a falling edge |
-| 3 : This input reacts to a |
-| rising edge |
-| 4 : This input reacts to both edges |
-|
-| 5 : This input is not |
-| used for event |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * An event can be generated for each port. The first event is related to the
+ * first 8 channels (port 1) and the second to the following 6 channels (port 2)
+ * An interrupt is generated when one or both events have occurred.
+ *
+ * data[0] Number of the input port on which the event will take place (1 or 2)
+ * data[1] The event logic for port 1 has three possibilities:
+ * APCI1500_AND This logic links the inputs with an AND logic.
+ * APCI1500_OR This logic links the inputs with a OR logic.
+ * APCI1500_OR_PRIORITY This logic links the inputs with a priority OR
+ * logic. Input 1 has the highest priority level
+ * and input 8 the smallest.
+ * For the second port the user has 1 possibility:
+ * APCI1500_OR This logic links the inputs with a polarity OR logic
+ * data[2] These 8-character word for port1 and 6-character word for port 2
+ * give the mask of the event. Each place gives the state of the input
+ * channels and can have one of these six characters
+ * 0 This input must be on 0
+ * 1 This input must be on 1
+ * 2 This input reacts to a falling edge
+ * 3 This input reacts to a rising edge
+ * 4 This input reacts to both edges
+ * 5 This input is not used for event
+ */
+static int apci1500_di_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
int i_PatternPolarity = 0, i_PatternTransition = 0, i_PatternMask = 0;
@@ -241,14 +164,10 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
int i_PatternTransitionCount = 0, i_RegValue;
int i;
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Disables the main interrupt on the board */
- /**********************************************/
outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
if (data[0] == 1) {
@@ -259,7 +178,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
i_MaxChannel = 6;
} /* if(data[0]==2) */
else {
- printk("\nThe specified port event does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified port event does not exist\n");
return -EINVAL;
} /* else if(data[0]==2) */
} /* else if (data[0] == 1) */
@@ -274,7 +194,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
data[1] = APCI1500_OR_PRIORITY;
break;
default:
- printk("\nThe specified interrupt logic does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified interrupt logic does not exist\n");
return -EINVAL;
} /* switch(data[1]); */
@@ -318,37 +239,30 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
case 5:
break;
default:
- printk("\nThe option indicated in the event mask does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The option indicated in the event mask does not exist\n");
return -EINVAL;
} /* switch(i_EventMask) */
} /* for (i_Count = i_MaxChannel; i_Count >0;i_Count --) */
if (data[0] == 1) {
- /****************************/
/* Test the interrupt logic */
- /****************************/
if (data[1] == APCI1500_AND ||
data[1] == APCI1500_OR ||
data[1] == APCI1500_OR_PRIORITY) {
- /**************************************/
/* Tests if a transition was declared */
/* for a OR PRIORITY logic */
- /**************************************/
if (data[1] == APCI1500_OR_PRIORITY
&& i_PatternTransition != 0) {
- /********************************************/
- /* Transition error on an OR PRIORITY logic */
- /********************************************/
- printk("\nTransition error on an OR PRIORITY logic\n");
+ dev_warn(dev->hw_dev,
+ "Transition error on an OR PRIORITY logic\n");
return -EINVAL;
} /* if (data[1]== APCI1500_OR_PRIORITY && i_PatternTransition != 0) */
- /*************************************/
/* Tests if more than one transition */
/* was declared for an AND logic */
- /*************************************/
if (data[1] == APCI1500_AND) {
for (i_Count = 0; i_Count < 8; i_Count++) {
@@ -360,29 +274,21 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
} /* for (i_Count = 0; i_Count < 8; i_Count++) */
if (i_PatternTransitionCount > 1) {
- /****************************************/
- /* Transition error on an AND logic */
- /****************************************/
- printk("\n Transition error on an AND logic\n");
+ dev_warn(dev->hw_dev,
+ "Transition error on an AND logic\n");
return -EINVAL;
} /* if (i_PatternTransitionCount > 1) */
} /* if (data[1]== APCI1500_AND) */
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************/
/* Disable Port A */
- /******************/
outb(0xF0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Selects the polarity register of port 1 */
- /**********************************************/
outb(APCI1500_RW_PORT_A_PATTERN_POLARITY,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -390,20 +296,16 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*********************************************/
/* Selects the pattern mask register of */
/* port 1 */
- /*********************************************/
outb(APCI1500_RW_PORT_A_PATTERN_MASK,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
outb(i_PatternMask,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************************/
/* Selects the pattern transition register */
/* of port 1 */
- /********************************************/
outb(APCI1500_RW_PORT_A_PATTERN_TRANSITION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -411,10 +313,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************/
/* Selects the mode specification mask */
/* register of port 1 */
- /******************************************/
outb(APCI1500_RW_PORT_A_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -422,17 +322,13 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************/
/* Selects the mode specification mask */
/* register of port 1 */
- /******************************************/
outb(APCI1500_RW_PORT_A_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************/
/* Port A new mode */
- /**********************/
i_RegValue = (i_RegValue & 0xF9) | data[1] | 0x9;
outb(i_RegValue,
@@ -441,53 +337,40 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
i_Event1Status = 1;
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*****************/
/* Enable Port A */
- /*****************/
outb(0xF4,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
} /* if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */
else {
- printk("\nThe choice for interrupt logic does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The choice for interrupt logic does not exist\n");
return -EINVAL;
} /* else }// if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */
} /* if (data[0]== 1) */
- /************************************/
/* Test if event setting for port 2 */
- /************************************/
if (data[0] == 2) {
- /************************/
/* Test the event logic */
- /************************/
if (data[1] == APCI1500_OR) {
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************/
/* Disable Port B */
- /******************/
outb(0x74,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************/
/* Selects the mode specification mask */
/* register of port B */
- /****************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -495,10 +378,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************/
/* Selects the mode specification mask */
/* register of port B */
- /******************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -507,37 +388,29 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************/
/* Selects error channels 1 and 2 */
- /**********************************/
i_PatternMask = (i_PatternMask | 0xC0);
i_PatternPolarity = (i_PatternPolarity | 0xC0);
i_PatternTransition = (i_PatternTransition | 0xC0);
- /**********************************************/
/* Selects the polarity register of port 2 */
- /**********************************************/
outb(APCI1500_RW_PORT_B_PATTERN_POLARITY,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
outb(i_PatternPolarity,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Selects the pattern transition register */
/* of port 2 */
- /**********************************************/
outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
outb(i_PatternTransition,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Selects the pattern Mask register */
/* of port 2 */
- /**********************************************/
outb(APCI1500_RW_PORT_B_PATTERN_MASK,
devpriv->iobase +
@@ -546,20 +419,16 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************/
/* Selects the mode specification mask */
/* register of port 2 */
- /******************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue =
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************/
/* Selects the mode specification mask */
/* register of port 2 */
- /******************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -569,23 +438,20 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
APCI1500_Z8536_CONTROL_REGISTER);
i_Event2Status = 1;
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*****************/
/* Enable Port B */
- /*****************/
outb(0xF4,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
} /* if (data[1] == APCI1500_OR) */
else {
- printk("\nThe choice for interrupt logic does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The choice for interrupt logic does not exist\n");
return -EINVAL;
} /* elseif (data[1] == APCI1500_OR) */
} /* if(data[0]==2) */
@@ -594,31 +460,15 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_StartStopInputEvent |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Allows or disallows a port event |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int ui_Channel : Channel number to read |
-| unsigned int *data : Data Pointer to read status |
-| data[0] :0 Start input event
-| 1 Stop input event
-| data[1] :No of port (1 or 2)
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Allows or disallows a port event
+ *
+ * data[0] 0 = Start input event, 1 = Stop input event
+ * data[1] Number of port (1 or 2)
+ */
+static int apci1500_di_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
int i_Event1InterruptStatus = 0, i_Event2InterruptStatus =
@@ -626,48 +476,30 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev,
switch (data[0]) {
case START:
- /*************************/
/* Tests the port number */
- /*************************/
if (data[1] == 1 || data[1] == 2) {
- /***************************/
/* Test if port 1 selected */
- /***************************/
if (data[1] == 1) {
- /*****************************/
/* Test if event initialised */
- /*****************************/
if (i_Event1Status == 1) {
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************/
/* Disable Port A */
- /******************/
outb(0xF0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************************/
/* Selects the command and status register of */
/* port 1 */
- /***************************************************/
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************/
/* Allows the pattern interrupt */
- /*************************************/
outb(0xC0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************/
/* Enable Port A */
- /*****************/
outb(0xF4,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -680,185 +512,142 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev,
APCI1500_Z8536_CONTROL_REGISTER);
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Authorizes the main interrupt on the board */
- /**********************************************/
outb(0xD0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
} /* if(i_Event1Status==1) */
else {
- printk("\nEvent 1 not initialised\n");
+ dev_warn(dev->hw_dev,
+ "Event 1 not initialised\n");
return -EINVAL;
} /* else if(i_Event1Status==1) */
} /* if (data[1]==1) */
if (data[1] == 2) {
if (i_Event2Status == 1) {
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************/
/* Disable Port B */
- /******************/
outb(0x74,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************************/
/* Selects the command and status register of */
/* port 2 */
- /***************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************/
/* Allows the pattern interrupt */
- /*************************************/
outb(0xC0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************/
/* Enable Port B */
- /*****************/
outb(0xF4,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Authorizes the main interrupt on the board */
- /**********************************************/
outb(0xD0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
i_Event2InterruptStatus = 1;
} /* if(i_Event2Status==1) */
else {
- printk("\nEvent 2 not initialised\n");
+ dev_warn(dev->hw_dev,
+ "Event 2 not initialised\n");
return -EINVAL;
} /* else if(i_Event2Status==1) */
} /* if(data[1]==2) */
} /* if (data[1] == 1 || data[0] == 2) */
else {
- printk("\nThe port parameter is in error\n");
+ dev_warn(dev->hw_dev,
+ "The port parameter is in error\n");
return -EINVAL;
} /* else if (data[1] == 1 || data[0] == 2) */
break;
case STOP:
- /*************************/
/* Tests the port number */
- /*************************/
if (data[1] == 1 || data[1] == 2) {
- /***************************/
/* Test if port 1 selected */
- /***************************/
if (data[1] == 1) {
- /*****************************/
/* Test if event initialised */
- /*****************************/
if (i_Event1Status == 1) {
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************/
/* Disable Port A */
- /******************/
outb(0xF0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************************/
/* Selects the command and status register of */
/* port 1 */
- /***************************************************/
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************/
/* Inhibits the pattern interrupt */
- /*************************************/
outb(0xE0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************/
/* Enable Port A */
- /*****************/
outb(0xF4,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
i_Event1InterruptStatus = 0;
} /* if(i_Event1Status==1) */
else {
- printk("\nEvent 1 not initialised\n");
+ dev_warn(dev->hw_dev,
+ "Event 1 not initialised\n");
return -EINVAL;
} /* else if(i_Event1Status==1) */
} /* if (data[1]==1) */
if (data[1] == 2) {
- /*****************************/
/* Test if event initialised */
- /*****************************/
if (i_Event2Status == 1) {
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************/
/* Disable Port B */
- /******************/
outb(0x74,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************************/
/* Selects the command and status register of */
/* port 2 */
- /***************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************/
/* Inhibits the pattern interrupt */
- /*************************************/
outb(0xE0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************/
/* Enable Port B */
- /*****************/
outb(0xF4,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
i_Event2InterruptStatus = 0;
} /* if(i_Event2Status==1) */
else {
- printk("\nEvent 2 not initialised\n");
+ dev_warn(dev->hw_dev,
+ "Event 2 not initialised\n");
return -EINVAL;
} /* else if(i_Event2Status==1) */
} /* if(data[1]==2) */
} /* if (data[1] == 1 || data[1] == 2) */
else {
- printk("\nThe port parameter is in error\n");
+ dev_warn(dev->hw_dev,
+ "The port parameter is in error\n");
return -EINVAL;
} /* else if (data[1] == 1 || data[1] == 2) */
break;
default:
- printk("\nThe option of START/STOP logic does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The option of START/STOP logic does not exist\n");
return -EINVAL;
} /* switch(data[0]) */
@@ -866,35 +655,17 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_Initialisation |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Return the status of the digital input |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int ui_Channel : Channel number to read |
-| unsigned int *data : Data Pointer to read status |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_Initialisation(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Return the status of the digital input
+ */
+static int apci1500_di_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
int i_DummyRead = 0;
- /******************/
/* Software reset */
- /******************/
i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
@@ -902,16 +673,12 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the master configuration control register */
- /*****************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the mode specification register of port A */
- /*****************************************************/
outb(APCI1500_RW_PORT_A_SPECIFICATION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
@@ -943,9 +710,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
/* Deletes the register */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the mode specification register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
@@ -975,9 +740,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
/* Deletes the register */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the data path polarity register of port C */
- /*****************************************************/
outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* High level of port C means 1 */
@@ -992,9 +755,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes it */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************************/
/* Selects the command and status register of timer 1 */
- /******************************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes IP and IUS */
@@ -1004,9 +765,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deactivates the interrupt management of timer 1 */
outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************************/
/* Selects the command and status register of timer 2 */
- /******************************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes IP and IUS */
@@ -1016,9 +775,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deactivates Timer 2 interrupt management: */
outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************************/
/* Selects the command and status register of timer 3 */
- /******************************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes IP and IUS */
@@ -1028,9 +785,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deactivates interrupt management of timer 3: */
outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes all interrupts */
@@ -1051,37 +806,15 @@ static int apci1500_di_insn_bits(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_ConfigDigitalOutputErrorInterrupt
-| (struct comedi_device *dev,struct comedi_subdevice *s struct comedi_insn
-| *insn,unsigned int *data) |
-| |
-+----------------------------------------------------------------------------+
-| Task : Configures the digital output memory and the digital
-| output error interrupt |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| struct comedi_subdevice *s, :pointer to subdevice structure
-| struct comedi_insn *insn :pointer to insn structure |
-| data[0] :1:Memory on |
-| 0:Memory off |
-| data[1] :1 Enable the voltage error interrupt
-| :0 Disable the voltage error interrupt |
-| |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures the digital output memory and the digital output error interrupt
+ *
+ * data[1] 1 = Enable the voltage error interrupt
+ * 2 = Disable the voltage error interrupt
+ */
+static int apci1500_do_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
@@ -1090,31 +823,15 @@ static int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *de
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_WriteDigitalOutput |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Writes port value To the selected port |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int ui_NoOfChannels : No Of Channels To Write |
-| unsigned int *data : Data Pointer to read status |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Writes port value to the selected port
+ */
+static int apci1500_do_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
- static unsigned int ui_Temp = 0;
+ static unsigned int ui_Temp;
unsigned int ui_Temp1;
unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */
@@ -1165,7 +882,9 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev,
APCI1500_DIGITAL_OP);
} /* if(data[1]==1) */
else {
- printk("\nSpecified channel not supported\n");
+ dev_warn(dev->hw_dev,
+ "Specified channel not supported\n");
+ return -EINVAL;
} /* else if(data[1]==1) */
} /* elseif(data[1]==0) */
} /* if(data[3]==0) */
@@ -1242,12 +961,15 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev,
APCI1500_DIGITAL_OP);
} /* if(data[1]==1) */
else {
- printk("\nSpecified channel not supported\n");
+ dev_warn(dev->hw_dev,
+ "Specified channel not supported\n");
+ return -EINVAL;
} /* else if(data[1]==1) */
} /* elseif(data[1]==0) */
} /* if(data[3]==1); */
else {
- printk("\nSpecified functionality does not exist\n");
+ dev_warn(dev->hw_dev,
+ "Specified functionality does not exist\n");
return -EINVAL;
} /* if else data[3]==1) */
} /* if else data[3]==0) */
@@ -1256,57 +978,23 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_ConfigCounterTimerWatchdog(comedi_device
-| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)|
-| |
-+----------------------------------------------------------------------------+
-| Task : Configures The Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| struct comedi_subdevice *s, :pointer to subdevice structure
-| struct comedi_insn *insn :pointer to insn structure |
-| unsigned int *data : Data Pointer to read status data[0] : 2 APCI1500_1_8_KHZ
-| 1 APCI1500_3_6_KHZ |
-| 0 APCI1500_115_KHZ
-| data[1] : 0 Counter1/Timer1
-| 1 Counter2/Timer2
-| 2 Counter3/Watchdog
-| data[2] : 0 Counter
-| 1 Timer/Watchdog
-| data[3] : This parameter has |
-| two meanings. |
-| - If the counter/timer |
-| is used as a counter |
-| the limit value of |
-| the counter is given |
-| |
-| - If the counter/timer |
-| is used as a timer, |
-| the divider factor |
-| for the output is |
-| given.
-| data[4] : 0 APCI1500_CONTINUOUS
-| 1 APCI1500_SINGLE
-| data[5] : 0 Software Trigger
-| 1 Hardware Trigger
-|
-| data[6] :0 Software gate
-| 1 Hardware gate
-| data[7] :0 Interrupt Disable
-| 1 Interrupt Enable
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures The Watchdog
+ *
+ * data[0] 0 = APCI1500_115_KHZ, 1 = APCI1500_3_6_KHZ, 2 = APCI1500_1_8_KHZ
+ * data[1] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog
+ * data[2] 0 = Counter, 1 = Timer/Watchdog
+ * data[3] This parameter has two meanings. If the counter/timer is used as
+ * a counter the limit value of the counter is given. If the counter/timer
+ * is used as a timer, the divider factor for the output is given.
+ * data[4] 0 = APCI1500_CONTINUOUS, 1 = APCI1500_SINGLE
+ * data[5] 0 = Software Trigger, 1 = Hardware Trigger
+ * data[6] 0 = Software gate, 1 = Hardware gate
+ * data[7] 0 = Interrupt Disable, 1 = Interrupt Enable
+ */
+static int apci1500_timer_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
int i_TimerCounterMode, i_MasterConfiguration;
@@ -1319,7 +1007,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
} /* if(data[0]==0||data[0]==1||data[0]==2) */
else {
if (data[0] != 3) {
- printk("\nThe option for input clock selection does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The option for input clock selection does not exist\n");
return -EINVAL;
} /* if(data[0]!=3) */
} /* elseif(data[0]==0||data[0]==1||data[0]==2) */
@@ -1335,7 +1024,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[2] = APCI1500_TIMER;
break;
default:
- printk("\nThis choice is not a timer nor a counter\n");
+ dev_warn(dev->hw_dev,
+ "This choice is not a timer nor a counter\n");
return -EINVAL;
} /* switch(data[2]) */
@@ -1348,139 +1038,110 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[4] = APCI1500_SINGLE;
break;
default:
- printk("\nThis option for single/continuous mode does not exist\n");
+ dev_warn(dev->hw_dev,
+ "This option for single/continuous mode does not exist\n");
return -EINVAL;
} /* switch(data[4]) */
i_TimerCounterMode = data[2] | data[4] | 7;
- /*************************/
/* Test the reload value */
- /*************************/
if ((data[3] >= 0) && (data[3] <= 65535)) {
if (data[7] == APCI1500_ENABLE
|| data[7] == APCI1500_DISABLE) {
- /************************************************/
/* Selects the mode register of timer/counter 1 */
- /************************************************/
outb(APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************/
/* Writes the new mode */
- /***********************/
outb(i_TimerCounterMode,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************************/
/* Selects the constant register of timer/counter 1 */
- /****************************************************/
outb(APCI1500_RW_CPT_TMR1_TIME_CST_LOW,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*************************/
/* Writes the low value */
- /*************************/
outb(data[3],
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************************/
/* Selects the constant register of timer/counter 1 */
- /****************************************************/
outb(APCI1500_RW_CPT_TMR1_TIME_CST_HIGH,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**************************/
/* Writes the high value */
- /**************************/
data[3] = data[3] >> 8;
outb(data[3],
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*********************************************/
/* Selects the master configuration register */
- /*********************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************/
/* Reads the register */
- /**********************/
i_MasterConfiguration =
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************************************/
/* Enables timer/counter 1 and triggers timer/counter 1 */
- /********************************************************/
i_MasterConfiguration =
i_MasterConfiguration | 0x40;
- /*********************************************/
/* Selects the master configuration register */
- /*********************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************/
/* Writes the new configuration */
- /********************************/
outb(i_MasterConfiguration,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************/
/* Selects the commands register of */
/* timer/counter 1 */
- /****************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************/
/* Disable timer/counter 1 */
- /***************************/
outb(0x0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************/
/* Selects the commands register of */
/* timer/counter 1 */
- /****************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************/
/* Trigger timer/counter 1 */
- /***************************/
outb(0x2,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
} /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
else {
- printk("\nError in selection of interrupt enable or disable\n");
+ dev_warn(dev->hw_dev,
+ "Error in selection of interrupt enable or disable\n");
return -EINVAL;
} /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
} /* if ((data[3]>= 0) && (data[3] <= 65535)) */
else {
- printk("\nError in selection of reload value\n");
+ dev_warn(dev->hw_dev,
+ "Error in selection of reload value\n");
return -EINVAL;
} /* else if ((data[3]>= 0) && (data[3] <= 65535)) */
i_TimerCounterWatchdogInterrupt = data[7];
@@ -1496,7 +1157,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[2] = APCI1500_TIMER;
break;
default:
- printk("\nThis choice is not a timer nor a counter\n");
+ dev_warn(dev->hw_dev,
+ "This choice is not a timer nor a counter\n");
return -EINVAL;
} /* switch(data[2]) */
@@ -1509,7 +1171,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[4] = APCI1500_SINGLE;
break;
default:
- printk("\nThis option for single/continuous mode does not exist\n");
+ dev_warn(dev->hw_dev,
+ "This option for single/continuous mode does not exist\n");
return -EINVAL;
} /* switch(data[4]) */
@@ -1522,7 +1185,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[5] = APCI1500_HARDWARE_TRIGGER;
break;
default:
- printk("\nThis choice for software or hardware trigger does not exist\n");
+ dev_warn(dev->hw_dev,
+ "This choice for software or hardware trigger does not exist\n");
return -EINVAL;
} /* switch(data[5]) */
@@ -1535,140 +1199,111 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[6] = APCI1500_HARDWARE_GATE;
break;
default:
- printk("\nThis choice for software or hardware gate does not exist\n");
+ dev_warn(dev->hw_dev,
+ "This choice for software or hardware gate does not exist\n");
return -EINVAL;
} /* switch(data[6]) */
i_TimerCounterMode = data[2] | data[4] | data[5] | data[6] | 7;
- /*************************/
/* Test the reload value */
- /*************************/
if ((data[3] >= 0) && (data[3] <= 65535)) {
if (data[7] == APCI1500_ENABLE
|| data[7] == APCI1500_DISABLE) {
- /************************************************/
/* Selects the mode register of timer/counter 2 */
- /************************************************/
outb(APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************/
/* Writes the new mode */
- /***********************/
outb(i_TimerCounterMode,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************************/
/* Selects the constant register of timer/counter 2 */
- /****************************************************/
outb(APCI1500_RW_CPT_TMR2_TIME_CST_LOW,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*************************/
/* Writes the low value */
- /*************************/
outb(data[3],
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************************/
/* Selects the constant register of timer/counter 2 */
- /****************************************************/
outb(APCI1500_RW_CPT_TMR2_TIME_CST_HIGH,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**************************/
/* Writes the high value */
- /**************************/
data[3] = data[3] >> 8;
outb(data[3],
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*********************************************/
/* Selects the master configuration register */
- /*********************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************/
/* Reads the register */
- /**********************/
i_MasterConfiguration =
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************************************/
/* Enables timer/counter 2 and triggers timer/counter 2 */
- /********************************************************/
i_MasterConfiguration =
i_MasterConfiguration | 0x20;
- /*********************************************/
/* Selects the master configuration register */
- /*********************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************/
/* Writes the new configuration */
- /********************************/
outb(i_MasterConfiguration,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************/
/* Selects the commands register of */
/* timer/counter 2 */
- /****************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************/
/* Disable timer/counter 2 */
- /***************************/
outb(0x0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************/
/* Selects the commands register of */
/* timer/counter 2 */
- /****************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************/
/* Trigger timer/counter 1 */
- /***************************/
outb(0x2,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
} /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
else {
- printk("\nError in selection of interrupt enable or disable\n");
+ dev_warn(dev->hw_dev,
+ "Error in selection of interrupt enable or disable\n");
return -EINVAL;
} /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
} /* if ((data[3]>= 0) && (data[3] <= 65535)) */
else {
- printk("\nError in selection of reload value\n");
+ dev_warn(dev->hw_dev,
+ "Error in selection of reload value\n");
return -EINVAL;
} /* else if ((data[3]>= 0) && (data[3] <= 65535)) */
i_TimerCounterWatchdogInterrupt = data[7];
@@ -1684,7 +1319,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[2] = APCI1500_WATCHDOG;
break;
default:
- printk("\nThis choice is not a watchdog nor a counter\n");
+ dev_warn(dev->hw_dev,
+ "This choice is not a watchdog nor a counter\n");
return -EINVAL;
} /* switch(data[2]) */
@@ -1697,7 +1333,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[4] = APCI1500_SINGLE;
break;
default:
- printk("\nThis option for single/continuous mode does not exist\n");
+ dev_warn(dev->hw_dev,
+ "This option for single/continuous mode does not exist\n");
return -EINVAL;
} /* switch(data[4]) */
@@ -1710,146 +1347,109 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[6] = APCI1500_HARDWARE_GATE;
break;
default:
- printk("\nThis choice for software or hardware gate does not exist\n");
+ dev_warn(dev->hw_dev,
+ "This choice for software or hardware gate does not exist\n");
return -EINVAL;
} /* switch(data[6]) */
- /*****************************/
/* Test if used for watchdog */
- /*****************************/
if (data[2] == APCI1500_WATCHDOG) {
- /*****************************/
/* - Enables the output line */
/* - Enables retrigger */
/* - Pulses output */
- /*****************************/
i_TimerCounterMode = data[2] | data[4] | 0x54;
} /* if (data[2] == APCI1500_WATCHDOG) */
else {
i_TimerCounterMode = data[2] | data[4] | data[6] | 7;
} /* elseif (data[2] == APCI1500_WATCHDOG) */
- /*************************/
/* Test the reload value */
- /*************************/
if ((data[3] >= 0) && (data[3] <= 65535)) {
if (data[7] == APCI1500_ENABLE
|| data[7] == APCI1500_DISABLE) {
- /************************************************/
/* Selects the mode register of watchdog/counter 3 */
- /************************************************/
outb(APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************/
/* Writes the new mode */
- /***********************/
outb(i_TimerCounterMode,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************************/
/* Selects the constant register of watchdog/counter 3 */
- /****************************************************/
outb(APCI1500_RW_CPT_TMR3_TIME_CST_LOW,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*************************/
/* Writes the low value */
- /*************************/
outb(data[3],
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************************/
/* Selects the constant register of watchdog/counter 3 */
- /****************************************************/
outb(APCI1500_RW_CPT_TMR3_TIME_CST_HIGH,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**************************/
/* Writes the high value */
- /**************************/
data[3] = data[3] >> 8;
outb(data[3],
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*********************************************/
/* Selects the master configuration register */
- /*********************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************/
/* Reads the register */
- /**********************/
i_MasterConfiguration =
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************************************/
/* Enables watchdog/counter 3 and triggers watchdog/counter 3 */
- /********************************************************/
i_MasterConfiguration =
i_MasterConfiguration | 0x10;
- /*********************************************/
/* Selects the master configuration register */
- /*********************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************/
/* Writes the new configuration */
- /********************************/
outb(i_MasterConfiguration,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************/
/* Test if COUNTER */
- /********************/
if (data[2] == APCI1500_COUNTER) {
- /*************************************/
/* Selects the command register of */
/* watchdog/counter 3 */
- /*************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************************/
/* Disable the watchdog/counter 3 and starts it */
- /*************************************************/
outb(0x0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************/
/* Selects the command register of */
/* watchdog/counter 3 */
- /*************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************************/
/* Trigger the watchdog/counter 3 and starts it */
- /*************************************************/
outb(0x2,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -1858,12 +1458,14 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
} /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
else {
- printk("\nError in selection of interrupt enable or disable\n");
+ dev_warn(dev->hw_dev,
+ "Error in selection of interrupt enable or disable\n");
return -EINVAL;
} /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
} /* if ((data[3]>= 0) && (data[3] <= 65535)) */
else {
- printk("\nError in selection of reload value\n");
+ dev_warn(dev->hw_dev,
+ "Error in selection of reload value\n");
return -EINVAL;
} /* else if ((data[3]>= 0) && (data[3] <= 65535)) */
i_TimerCounterWatchdogInterrupt = data[7];
@@ -1871,44 +1473,25 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
break;
default:
- printk("\nThe specified counter\timer option does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified counter/timer option does not exist\n");
+ return -EINVAL;
} /* switch(data[1]) */
i_CounterLogic = data[2];
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_StartStopTriggerTimerCounterWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s,
-| struct comedi_insn *insn,unsigned int *data); |
-+----------------------------------------------------------------------------+
-| Task : Start / Stop or trigger the timer counter or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| struct comedi_subdevice *s, :pointer to subdevice structure
-| struct comedi_insn *insn :pointer to insn structure |
-| unsigned int *data : Data Pointer to read status |
-| data[0] : 0 Counter1/Timer1
-| 1 Counter2/Timer2
-| 2 Counter3/Watchdog
-| data[1] : 0 start
-| 1 stop
-| 2 Trigger
-| data[2] : 0 Counter
-| 1 Timer/Watchdog
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Start / Stop or trigger the timer counter or Watchdog
+ *
+ * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog
+ * data[1] 0 = Start, 1 = Stop, 2 = Trigger
+ * data[2] 0 = Counter, 1 = Timer/Watchdog
+ */
+static int apci1500_timer_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
int i_CommandAndStatusValue;
@@ -1924,13 +1507,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
else {
i_CommandAndStatusValue = 0xE4; /* disable the interrupt */
} /* elseif(i_TimerCounterWatchdogInterrupt==1) */
- /**************************/
/* Starts timer/counter 1 */
- /**************************/
i_TimerCounter1Enabled = 1;
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -1939,20 +1518,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_TimerCounter1Init==1) */
else {
- printk("\nCounter/Timer1 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Counter/Timer1 not configured\n");
return -EINVAL;
}
break;
case STOP:
- /**************************/
/* Stop timer/counter 1 */
- /**************************/
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -1965,23 +1541,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
case TRIGGER:
if (i_TimerCounter1Init == 1) {
if (i_TimerCounter1Enabled == 1) {
- /************************/
/* Set Trigger and gate */
- /************************/
i_CommandAndStatusValue = 0x6;
} /* if( i_TimerCounter1Enabled==1) */
else {
- /***************/
/* Set Trigger */
- /***************/
i_CommandAndStatusValue = 0x2;
} /* elseif(i_TimerCounter1Enabled==1) */
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -1990,13 +1560,15 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_TimerCounter1Init==1) */
else {
- printk("\nCounter/Timer1 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Counter/Timer1 not configured\n");
return -EINVAL;
}
break;
default:
- printk("\nThe specified option for start/stop/trigger does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified option for start/stop/trigger does not exist\n");
return -EINVAL;
} /* switch(data[1]) */
break;
@@ -2011,13 +1583,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
else {
i_CommandAndStatusValue = 0xE4; /* disable the interrupt */
} /* elseif(i_TimerCounterWatchdogInterrupt==1) */
- /**************************/
/* Starts timer/counter 2 */
- /**************************/
i_TimerCounter2Enabled = 1;
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2026,20 +1594,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_TimerCounter2Init==1) */
else {
- printk("\nCounter/Timer2 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Counter/Timer2 not configured\n");
return -EINVAL;
}
break;
case STOP:
- /**************************/
/* Stop timer/counter 2 */
- /**************************/
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2051,23 +1616,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
case TRIGGER:
if (i_TimerCounter2Init == 1) {
if (i_TimerCounter2Enabled == 1) {
- /************************/
/* Set Trigger and gate */
- /************************/
i_CommandAndStatusValue = 0x6;
} /* if( i_TimerCounter2Enabled==1) */
else {
- /***************/
/* Set Trigger */
- /***************/
i_CommandAndStatusValue = 0x2;
} /* elseif(i_TimerCounter2Enabled==1) */
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2076,12 +1635,14 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_TimerCounter2Init==1) */
else {
- printk("\nCounter/Timer2 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Counter/Timer2 not configured\n");
return -EINVAL;
}
break;
default:
- printk("\nThe specified option for start/stop/trigger does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified option for start/stop/trigger does not exist\n");
return -EINVAL;
} /* switch(data[1]) */
break;
@@ -2096,13 +1657,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
else {
i_CommandAndStatusValue = 0xE4; /* disable the interrupt */
} /* elseif(i_TimerCounterWatchdogInterrupt==1) */
- /**************************/
/* Starts Watchdog/counter 3 */
- /**************************/
i_WatchdogCounter3Enabled = 1;
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2112,20 +1669,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
} /* if( i_WatchdogCounter3init==1) */
else {
- printk("\nWatchdog/Counter3 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Watchdog/Counter3 not configured\n");
return -EINVAL;
}
break;
case STOP:
- /**************************/
/* Stop Watchdog/counter 3 */
- /**************************/
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2140,23 +1694,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
case 0: /* triggering counter 3 */
if (i_WatchdogCounter3Init == 1) {
if (i_WatchdogCounter3Enabled == 1) {
- /************************/
/* Set Trigger and gate */
- /************************/
i_CommandAndStatusValue = 0x6;
} /* if( i_WatchdogCounter3Enabled==1) */
else {
- /***************/
/* Set Trigger */
- /***************/
i_CommandAndStatusValue = 0x2;
} /* elseif(i_WatchdogCounter3Enabled==1) */
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2165,7 +1713,8 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_WatchdogCounter3Init==1) */
else {
- printk("\nCounter3 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Counter3 not configured\n");
return -EINVAL;
}
break;
@@ -2173,9 +1722,7 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
/* triggering Watchdog 3 */
if (i_WatchdogCounter3Init == 1) {
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2184,55 +1731,40 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_WatchdogCounter3Init==1) */
else {
- printk("\nWatchdog 3 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Watchdog 3 not configured\n");
return -EINVAL;
}
break;
default:
- printk("\nWrong choice of watchdog/counter3\n");
+ dev_warn(dev->hw_dev,
+ "Wrong choice of watchdog/counter3\n");
return -EINVAL;
} /* switch(data[2]) */
break;
default:
- printk("\nThe specified option for start/stop/trigger does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified option for start/stop/trigger does not exist\n");
return -EINVAL;
} /* switch(data[1]) */
break;
default:
- printk("\nThe specified choice for counter/watchdog/timer does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified choice for counter/watchdog/timer does not exist\n");
return -EINVAL;
} /* switch(data[0]) */
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_ReadCounterTimerWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
-| unsigned int *data); |
-+----------------------------------------------------------------------------+
-| Task : Read The Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| struct comedi_subdevice *s, :pointer to subdevice structure
-| struct comedi_insn *insn :pointer to insn structure |
-| unsigned int *data : Data Pointer to read status |
-| data[0] : 0 Counter1/Timer1
-| 1 Counter2/Timer2
-| 2 Counter3/Watchdog
-|
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Read The Watchdog
+ *
+ * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog
+ */
+static int apci1500_timer_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
int i_CommandAndStatusValue;
@@ -2242,23 +1774,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
/* Read counter/timer1 */
if (i_TimerCounter1Init == 1) {
if (i_TimerCounter1Enabled == 1) {
- /************************/
/* Set RCC and gate */
- /************************/
i_CommandAndStatusValue = 0xC;
} /* if( i_TimerCounter1Init==1) */
else {
- /***************/
/* Set RCC */
- /***************/
i_CommandAndStatusValue = 0x8;
} /* elseif(i_TimerCounter1Init==1) */
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2266,9 +1792,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************/
/* Selects the counter register (high) */
- /***************************************/
outb(APCI1500_R_CPT_TMR1_VALUE_HIGH,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2285,7 +1809,8 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_TimerCounter1Init==1) */
else {
- printk("\nTimer/Counter1 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Timer/Counter1 not configured\n");
return -EINVAL;
} /* elseif( i_TimerCounter1Init==1) */
break;
@@ -2293,23 +1818,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
/* Read counter/timer2 */
if (i_TimerCounter2Init == 1) {
if (i_TimerCounter2Enabled == 1) {
- /************************/
/* Set RCC and gate */
- /************************/
i_CommandAndStatusValue = 0xC;
} /* if( i_TimerCounter2Init==1) */
else {
- /***************/
/* Set RCC */
- /***************/
i_CommandAndStatusValue = 0x8;
} /* elseif(i_TimerCounter2Init==1) */
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2317,9 +1836,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************/
/* Selects the counter register (high) */
- /***************************************/
outb(APCI1500_R_CPT_TMR2_VALUE_HIGH,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2336,7 +1853,8 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_TimerCounter2Init==1) */
else {
- printk("\nTimer/Counter2 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Timer/Counter2 not configured\n");
return -EINVAL;
} /* elseif( i_TimerCounter2Init==1) */
break;
@@ -2344,23 +1862,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
/* Read counter/watchdog2 */
if (i_WatchdogCounter3Init == 1) {
if (i_WatchdogCounter3Enabled == 1) {
- /************************/
/* Set RCC and gate */
- /************************/
i_CommandAndStatusValue = 0xC;
} /* if( i_TimerCounter2Init==1) */
else {
- /***************/
/* Set RCC */
- /***************/
i_CommandAndStatusValue = 0x8;
} /* elseif(i_WatchdogCounter3Init==1) */
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2368,9 +1880,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************/
/* Selects the counter register (high) */
- /***************************************/
outb(APCI1500_R_CPT_TMR3_VALUE_HIGH,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2387,12 +1897,14 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_WatchdogCounter3Init==1) */
else {
- printk("\nWatchdogCounter3 not configured\n");
+ dev_warn(dev->hw_dev,
+ "WatchdogCounter3 not configured\n");
return -EINVAL;
} /* elseif( i_WatchdogCounter3Init==1) */
break;
default:
- printk("\nThe choice of timer/counter/watchdog does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The choice of timer/counter/watchdog does not exist\n");
return -EINVAL;
} /* switch(data[0]) */
@@ -2400,31 +1912,15 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_ReadInterruptMask |
-| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
-| unsigned int *data); |
-+----------------------------------------------------------------------------+
-| Task : Read the interrupt mask |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| struct comedi_subdevice *s, :pointer to subdevice structure
-| struct comedi_insn *insn :pointer to insn structure |
-| unsigned int *data : Data Pointer to read status |
-
-
-+----------------------------------------------------------------------------+
-| Output Parameters : -- data[0]:The interrupt mask value data[1]:Channel no
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Read the interrupt mask
+ *
+ * data[0] The interrupt mask value
+ * data[1] Channel Number
+ */
+static int apci1500_timer_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
data[0] = i_InterruptMask;
data[1] = i_InputChannel;
@@ -2433,31 +1929,12 @@ static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_ConfigureInterrupt |
-| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
-| unsigned int *data); |
-+----------------------------------------------------------------------------+
-| Task : Configures the interrupt registers |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| struct comedi_subdevice *s, :pointer to subdevice structure
-| struct comedi_insn *insn :pointer to insn structure |
-| unsigned int *data : Data Pointer |
-|
-
-+----------------------------------------------------------------------------+
-| Output Parameters : --
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures the interrupt registers
+ */
+static int apci1500_do_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ui_Status;
@@ -2474,140 +1951,101 @@ static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev,
i_Constant = 0x00;
} /* if{data[0]==0) */
else {
- printk("\nThe parameter passed to driver is in error for enabling the voltage interrupt\n");
+ dev_warn(dev->hw_dev,
+ "The parameter passed to driver is in error for enabling the voltage interrupt\n");
return -EINVAL;
} /* else if(data[0]==0) */
} /* elseif(data[0]==1) */
- /*****************************************************/
/* Selects the mode specification register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*********************************************/
/* Writes the new configuration (APCI1500_OR) */
- /*********************************************/
i_RegValue = (i_RegValue & 0xF9) | APCI1500_OR;
outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************/
/* Authorises the interrupt on the board */
- /*****************************************/
outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************************/
/* Selects the pattern polarity register of port B */
- /***************************************************/
outb(APCI1500_RW_PORT_B_PATTERN_POLARITY,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the pattern transition register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************************/
/* Selects the pattern mask register of port B */
- /***********************************************/
outb(APCI1500_RW_PORT_B_PATTERN_MASK,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of port A */
- /*****************************************************/
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of port A */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of port B */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of timer 1 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of timer 1 */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of timer 2 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of timer 2 */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of timer 3 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of timer 3 */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Authorizes the main interrupt on the board */
- /**********************************************/
outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***************************/
/* Enables the PCI interrupt */
- /*****************************/
outl(0x3000, devpriv->i_IobaseAmcc + 0x38);
ui_Status = inl(devpriv->i_IobaseAmcc + 0x10);
ui_Status = inl(devpriv->i_IobaseAmcc + 0x38);
@@ -2616,24 +2054,7 @@ static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev,
return insn->n;
}
-/*
-+----------------------------------------------------------------------------+
-| Function Name : static void v_APCI1500_Interrupt |
-| (int irq , void *d) |
-+----------------------------------------------------------------------------+
-| Task : Interrupt handler |
-+----------------------------------------------------------------------------+
-| Input Parameters : int irq : irq number |
-| void *d : void pointer |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static void v_APCI1500_Interrupt(int irq, void *d)
+static void apci1500_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
@@ -2642,44 +2063,28 @@ static void v_APCI1500_Interrupt(int irq, void *d)
int i_RegValue = 0;
i_InterruptMask = 0;
- /***********************************/
/* Read the board interrupt status */
- /***********************************/
ui_InterruptStatus = inl(devpriv->i_IobaseAmcc + 0x38);
- /***************************************/
/* Test if board generated a interrupt */
- /***************************************/
if ((ui_InterruptStatus & 0x800000) == 0x800000) {
- /************************/
/* Disable all Interrupt */
- /************************/
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
/* outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */
- /**********************************************/
/* Disables the main interrupt on the board */
- /**********************************************/
/* outb(0x00,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */
- /*****************************************************/
/* Selects the command and status register of port A */
- /*****************************************************/
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue =
inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
if ((i_RegValue & 0x60) == 0x60) {
- /*****************************************************/
/* Selects the command and status register of port A */
- /*****************************************************/
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of port A */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue,
devpriv->iobase +
@@ -2693,9 +2098,7 @@ static void v_APCI1500_Interrupt(int irq, void *d)
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************************/
/* Selects the interrupt vector register of port A */
- /***************************************************/
outb(APCI1500_RW_PORT_A_INTERRUPT_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2711,45 +2114,32 @@ static void v_APCI1500_Interrupt(int irq, void *d)
} /* elseif(i_Logic==APCI1500_OR_PRIORITY) */
} /* if ((i_RegValue & 0x60) == 0x60) */
- /*****************************************************/
/* Selects the command and status register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue =
inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
if ((i_RegValue & 0x60) == 0x60) {
- /*****************************************************/
/* Selects the command and status register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of port B */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- printk("\n\n\n");
- /****************/
/* Reads port B */
- /****************/
i_RegValue =
inb((unsigned int) devpriv->iobase +
APCI1500_Z8536_PORT_B);
i_RegValue = i_RegValue & 0xC0;
- /**************************************/
/* Tests if this is an external error */
- /**************************************/
if (i_RegValue) {
/* Disable the interrupt */
- /*****************************************************/
/* Selects the command and status register of port B */
- /*****************************************************/
outl(0x0, devpriv->i_IobaseAmcc + 0x38);
if (i_RegValue & 0x80) {
@@ -2767,46 +2157,34 @@ static void v_APCI1500_Interrupt(int irq, void *d)
} /* if (i_RegValue) */
} /* if ((i_RegValue & 0x60) == 0x60) */
- /*****************************************************/
/* Selects the command and status register of timer 1 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue =
inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
if ((i_RegValue & 0x60) == 0x60) {
- /*****************************************************/
/* Selects the command and status register of timer 1 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of timer 1 */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
i_InterruptMask = i_InterruptMask | 4;
} /* if ((i_RegValue & 0x60) == 0x60) */
- /*****************************************************/
/* Selects the command and status register of timer 2 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue =
inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
if ((i_RegValue & 0x60) == 0x60) {
- /*****************************************************/
/* Selects the command and status register of timer 2 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of timer 2 */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue,
devpriv->iobase +
@@ -2814,23 +2192,17 @@ static void v_APCI1500_Interrupt(int irq, void *d)
i_InterruptMask = i_InterruptMask | 8;
} /* if ((i_RegValue & 0x60) == 0x60) */
- /*****************************************************/
/* Selects the command and status register of timer 3 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue =
inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
if ((i_RegValue & 0x60) == 0x60) {
- /*****************************************************/
/* Selects the command and status register of timer 3 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of timer 3 */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue,
devpriv->iobase +
@@ -2844,42 +2216,23 @@ static void v_APCI1500_Interrupt(int irq, void *d)
} /* if ((i_RegValue & 0x60) == 0x60) */
send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
- /***********************/
/* Enable all Interrupts */
- /***********************/
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Authorizes the main interrupt on the board */
- /**********************************************/
outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
} /* if ((ui_InterruptStatus & 0x800000) == 0x800000) */
else {
- printk("\nInterrupt from unknown source\n");
+ dev_warn(dev->hw_dev,
+ "Interrupt from unknown source\n");
} /* else if ((ui_InterruptStatus & 0x800000) == 0x800000) */
return;
}
-/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_Reset(struct comedi_device *dev) | |
-+----------------------------------------------------------------------------+
-| Task :resets all the registers |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_Reset(struct comedi_device *dev)
+static int apci1500_reset(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
int i_DummyRead = 0;
@@ -2898,9 +2251,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
i_TimerCounter2Enabled = 0;
i_WatchdogCounter3Enabled = 0;
- /******************/
/* Software reset */
- /******************/
i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
@@ -2908,16 +2259,12 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the master configuration control register */
- /*****************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the mode specification register of port A */
- /*****************************************************/
outb(APCI1500_RW_PORT_A_SPECIFICATION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
@@ -2949,9 +2296,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
/* Deletes the register */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the mode specification register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
@@ -2981,9 +2326,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
/* Deletes the register */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the data path polarity register of port C */
- /*****************************************************/
outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* High level of port C means 1 */
@@ -2998,9 +2341,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes it */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************************/
/* Selects the command and status register of timer 1 */
- /******************************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes IP and IUS */
@@ -3010,9 +2351,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deactivates the interrupt management of timer 1 */
outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************************/
/* Selects the command and status register of timer 2 */
- /******************************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes IP and IUS */
@@ -3022,9 +2361,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deactivates Timer 2 interrupt management: */
outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************************/
/* Selects the command and status register of timer 3 */
- /******************************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes IP and IUS */
@@ -3034,71 +2371,43 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deactivates interrupt management of timer 3: */
outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes all interrupts */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* reset all the digital outputs */
outw(0x0, devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP);
-/*******************************/
/* Disable the board interrupt */
-/*******************************/
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/****************************/
/* Deactivates all interrupts */
-/******************************/
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of port A */
- /*****************************************************/
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/****************************/
/* Deactivates all interrupts */
-/******************************/
outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/*****************************************************/
/* Selects the command and status register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/****************************/
/* Deactivates all interrupts */
-/******************************/
outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/*****************************************************/
/* Selects the command and status register of timer 1 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/****************************/
/* Deactivates all interrupts */
-/******************************/
outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/*****************************************************/
/* Selects the command and status register of timer 2 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/****************************/
/* Deactivates all interrupts */
-/******************************/
outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/*****************************************************/
/* Selects the command and status register of timer 3*/
-/*****************************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/****************************/
/* Deactivates all interrupts */
-/******************************/
outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
return 0;
}
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c
index 84668544f52d..9c86b02eb6da 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c
@@ -1,74 +1,32 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.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.
-
-@endverbatim
-*/
/*
-
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-------------------------------+---------------------------------------+
- | Project : APCI-1564 | Compiler : GCC |
- | Module name : hwdrv_apci1564.c| Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-------------------------------+---------------------------------------+
- | Description : Hardware Layer Access For APCI-1564 |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +----------+-----------+------------------------------------------------+
- | Date | Author | Description of updates |
- +----------+-----------+------------------------------------------------+
- | | | |
- | | | |
- | | | |
- +----------+-----------+------------------------------------------------+
-*/
-
-/********* Definitions for APCI-1564 card *****/
+ * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
+ *
+ * ADDI-DATA GmbH
+ * Dieselstrasse 3
+ * D-77833 Ottersweier
+ * Tel: +19(0)7223/9493-0
+ * Fax: +49(0)7223/9493-92
+ * http://www.addi-data.com
+ * info@addi-data.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 APCI1564_ADDRESS_RANGE 128
-/* DIGITAL INPUT-OUTPUT DEFINE */
-/* Input defines */
-#define APCI1564_DIGITAL_IP 0x04
-#define APCI1564_DIGITAL_IP_INTERRUPT_MODE1 4
-#define APCI1564_DIGITAL_IP_INTERRUPT_MODE2 8
-#define APCI1564_DIGITAL_IP_IRQ 16
-
-/* Output defines */
-#define APCI1564_DIGITAL_OP 0x18
-#define APCI1564_DIGITAL_OP_RW 0
-#define APCI1564_DIGITAL_OP_INTERRUPT 4
-#define APCI1564_DIGITAL_OP_IRQ 12
-
/* Digital Input IRQ Function Selection */
#define ADDIDATA_OR 0
#define ADDIDATA_AND 1
-/* Digital Input Interrupt Status */
-#define APCI1564_DIGITAL_IP_INTERRUPT_STATUS 12
-
-/* Digital Output Interrupt Status */
-#define APCI1564_DIGITAL_OP_INTERRUPT_STATUS 8
-
/* Digital Input Interrupt Enable Disable. */
#define APCI1564_DIGITAL_IP_INTERRUPT_ENABLE 0x4
#define APCI1564_DIGITAL_IP_INTERRUPT_DISABLE 0xfffffffb
@@ -80,98 +38,91 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
#define APCI1564_DIGITAL_OP_CC_INTERRUPT_DISABLE 0xfffffffd
/* TIMER COUNTER WATCHDOG DEFINES */
-
#define ADDIDATA_TIMER 0
#define ADDIDATA_COUNTER 1
#define ADDIDATA_WATCHDOG 2
-#define APCI1564_DIGITAL_OP_WATCHDOG 0x28
-#define APCI1564_TIMER 0x48
-#define APCI1564_COUNTER1 0x0
-#define APCI1564_COUNTER2 0x20
-#define APCI1564_COUNTER3 0x40
-#define APCI1564_COUNTER4 0x60
-#define APCI1564_TCW_SYNC_ENABLEDISABLE 0
-#define APCI1564_TCW_RELOAD_VALUE 4
-#define APCI1564_TCW_TIMEBASE 8
-#define APCI1564_TCW_PROG 12
-#define APCI1564_TCW_TRIG_STATUS 16
-#define APCI1564_TCW_IRQ 20
-#define APCI1564_TCW_WARN_TIMEVAL 24
-#define APCI1564_TCW_WARN_TIMEBASE 28
+#define APCI1564_COUNTER1 0
+#define APCI1564_COUNTER2 1
+#define APCI1564_COUNTER3 2
+#define APCI1564_COUNTER4 3
+
+/*
+ * devpriv->i_IobaseAmcc Register Map
+ */
+#define APCI1564_DI_REG 0x04
+#define APCI1564_DI_INT_MODE1_REG 0x08
+#define APCI1564_DI_INT_MODE2_REG 0x0c
+#define APCI1564_DI_INT_STATUS_REG 0x10
+#define APCI1564_DI_IRQ_REG 0x14
+#define APCI1564_DO_REG 0x18
+#define APCI1564_DO_INT_CTRL_REG 0x1c
+#define APCI1564_DO_INT_STATUS_REG 0x20
+#define APCI1564_DO_IRQ_REG 0x24
+#define APCI1564_WDOG_REG 0x28
+#define APCI1564_WDOG_RELOAD_REG 0x2c
+#define APCI1564_WDOG_TIMEBASE_REG 0x30
+#define APCI1564_WDOG_CTRL_REG 0x34
+#define APCI1564_WDOG_STATUS_REG 0x38
+#define APCI1564_WDOG_IRQ_REG 0x3c
+#define APCI1564_WDOG_WARN_TIMEVAL_REG 0x40
+#define APCI1564_WDOG_WARN_TIMEBASE_REG 0x44
+#define APCI1564_TIMER_REG 0x48
+#define APCI1564_TIMER_RELOAD_REG 0x4c
+#define APCI1564_TIMER_TIMEBASE_REG 0x50
+#define APCI1564_TIMER_CTRL_REG 0x54
+#define APCI1564_TIMER_STATUS_REG 0x58
+#define APCI1564_TIMER_IRQ_REG 0x5c
+#define APCI1564_TIMER_WARN_TIMEVAL_REG 0x60
+#define APCI1564_TIMER_WARN_TIMEBASE_REG 0x64
+
+/*
+ * devpriv->iobase Register Map
+ */
+#define APCI1564_TCW_REG(x) (0x00 + ((x) * 0x20))
+#define APCI1564_TCW_RELOAD_REG(x) (0x04 + ((x) * 0x20))
+#define APCI1564_TCW_TIMEBASE_REG(x) (0x08 + ((x) * 0x20))
+#define APCI1564_TCW_CTRL_REG(x) (0x0c + ((x) * 0x20))
+#define APCI1564_TCW_STATUS_REG(x) (0x10 + ((x) * 0x20))
+#define APCI1564_TCW_IRQ_REG(x) (0x14 + ((x) * 0x20))
+#define APCI1564_TCW_WARN_TIMEVAL_REG(x) (0x18 + ((x) * 0x20))
+#define APCI1564_TCW_WARN_TIMEBASE_REG(x) (0x1c + ((x) * 0x20))
/* Global variables */
-static unsigned int ui_InterruptStatus_1564 = 0;
+static unsigned int ui_InterruptStatus_1564;
static unsigned int ui_InterruptData, ui_Type;
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_ConfigDigitalInput |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Configures the digital input Subdevice |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[0] : 1 Enable Digital Input Interrupt |
-| 0 Disable Digital Input Interrupt |
-| data[1] : 0 ADDIDATA Interrupt OR LOGIC |
-| : 1 ADDIDATA Interrupt AND LOGIC |
-| data[2] : Interrupt mask for the mode 1 |
-| data[3] : Interrupt mask for the mode 2 |
-| |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1564_ConfigDigitalInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures the digital input Subdevice
+ *
+ * data[0] 1 = Enable interrupt, 0 = Disable interrupt
+ * data[1] 0 = ADDIDATA Interrupt OR LOGIC, 1 = ADDIDATA Interrupt AND LOGIC
+ * data[2] Interrupt mask for the mode 1
+ * data[3] Interrupt mask for the mode 2
+ */
+static int apci1564_di_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
devpriv->tsk_Current = current;
- /*******************************/
+
/* Set the digital input logic */
- /*******************************/
if (data[0] == ADDIDATA_ENABLE) {
data[2] = data[2] << 4;
data[3] = data[3] << 4;
- outl(data[2],
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_INTERRUPT_MODE1);
- outl(data[3],
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_INTERRUPT_MODE2);
- if (data[1] == ADDIDATA_OR) {
- outl(0x4,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ);
- } /* if (data[1] == ADDIDATA_OR) */
- else {
- outl(0x6,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ);
- } /* else if (data[1] == ADDIDATA_OR) */
- } /* if (data[0] == ADDIDATA_ENABLE) */
- else {
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_INTERRUPT_MODE1);
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_INTERRUPT_MODE2);
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ);
- } /* else if (data[0] == ADDIDATA_ENABLE) */
+ outl(data[2], devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG);
+ outl(data[3], devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG);
+ if (data[1] == ADDIDATA_OR)
+ outl(0x4, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
+ else
+ outl(0x6, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
+ } else {
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
+ }
return insn->n;
}
@@ -183,40 +134,21 @@ static int apci1564_di_insn_bits(struct comedi_device *dev,
{
struct addi_private *devpriv = dev->private;
- data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP);
+ data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_DI_REG);
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_ConfigDigitalOutput |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Configures The Digital Output Subdevice. |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[1] : 1 Enable VCC Interrupt |
-| 0 Disable VCC Interrupt |
-| data[2] : 1 Enable CC Interrupt |
-| 0 Disable CC Interrupt |
-| |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures The Digital Output Subdevice.
+ *
+ * data[1] 0 = Disable VCC Interrupt, 1 = Enable VCC Interrupt
+ * data[2] 0 = Disable CC Interrupt, 1 = Enable CC Interrupt
+ */
+static int apci1564_do_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ul_Command = 0;
@@ -225,31 +157,25 @@ static int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev,
comedi_error(dev,
"Not a valid Data !!! ,Data should be 1 or 0\n");
return -EINVAL;
- } /* if ((data[0]!=0) && (data[0]!=1)) */
- if (data[0]) {
+ }
+
+ if (data[0])
devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE;
- } /* if (data[0]) */
- else {
+ else
devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE;
- } /* else if (data[0]) */
- if (data[1] == ADDIDATA_ENABLE) {
+
+ if (data[1] == ADDIDATA_ENABLE)
ul_Command = ul_Command | 0x1;
- } /* if (data[1] == ADDIDATA_ENABLE) */
- else {
+ else
ul_Command = ul_Command & 0xFFFFFFFE;
- } /* else if (data[1] == ADDIDATA_ENABLE) */
- if (data[2] == ADDIDATA_ENABLE) {
+
+ if (data[2] == ADDIDATA_ENABLE)
ul_Command = ul_Command | 0x2;
- } /* if (data[2] == ADDIDATA_ENABLE) */
- else {
+ else
ul_Command = ul_Command & 0xFFFFFFFD;
- } /* else if (data[2] == ADDIDATA_ENABLE) */
- outl(ul_Command,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_INTERRUPT);
- ui_InterruptData =
- inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_INTERRUPT);
+
+ outl(ul_Command, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG);
+ ui_InterruptData = inl(devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG);
devpriv->tsk_Current = current;
return insn->n;
}
@@ -261,12 +187,10 @@ static int apci1564_do_insn_bits(struct comedi_device *dev,
{
struct addi_private *devpriv = dev->private;
- s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_RW);
+ s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DO_REG);
if (comedi_dio_update_state(s, data))
- outl(s->state, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_RW);
+ outl(s->state, devpriv->i_IobaseAmcc + APCI1564_DO_REG);
data[1] = s->state;
@@ -274,39 +198,20 @@ static int apci1564_do_insn_bits(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_ConfigTimerCounterWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Configures The Timer , Counter or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[0] : 0 Configure As Timer |
-| 1 Configure As Counter |
-| 2 Configure As Watchdog |
-| data[1] : 1 Enable Interrupt |
-| 0 Disable Interrupt |
-| data[2] : Time Unit |
-| data[3] : Reload Value |
-| data[4] : Timer Mode |
-| data[5] : Timer Counter Watchdog Number|
- data[6] : Counter Direction
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures The Timer, Counter or Watchdog
+ *
+ * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog
+ * data[1] 1 = Enable Interrupt, 0 = Disable Interrupt
+ * data[2] Time Unit
+ * data[3] Reload Value
+ * data[4] Timer Mode
+ * data[5] Timer Counter Watchdog Number
+ * data[6] Counter Direction
+ */
+static int apci1564_timer_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ul_Command1 = 0;
@@ -316,89 +221,59 @@ static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev,
devpriv->b_TimerSelectMode = ADDIDATA_WATCHDOG;
/* Disable the watchdog */
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_PROG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG);
/* Loading the Reload value */
- outl(data[3],
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_RELOAD_VALUE);
- } /* if (data[0]==ADDIDATA_WATCHDOG) */
- else if (data[0] == ADDIDATA_TIMER) {
+ outl(data[3], devpriv->i_IobaseAmcc + APCI1564_WDOG_RELOAD_REG);
+ } else if (data[0] == ADDIDATA_TIMER) {
/* First Stop The Timer */
- ul_Command1 =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
+ ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
- outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Stop The Timer */
+ /* Stop The Timer */
+ outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
devpriv->b_TimerSelectMode = ADDIDATA_TIMER;
if (data[1] == 1) {
- outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ);
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_IRQ);
+ /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */
+ outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_IRQ_REG);
outl(0x0,
- devpriv->i_IobaseAmcc +
- APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_IRQ);
+ devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER1 +
- APCI1564_TCW_IRQ);
+ devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER2 +
- APCI1564_TCW_IRQ);
+ devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER3 +
- APCI1564_TCW_IRQ);
- outl(0x0,
- devpriv->iobase + APCI1564_COUNTER4 +
- APCI1564_TCW_IRQ);
- } /* if (data[1]==1) */
- else {
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* disable Timer interrupt */
- } /* else if (data[1]==1) */
+ devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4));
+ } else {
+ /* disable Timer interrupt */
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ }
/* Loading Timebase */
-
- outl(data[2],
- devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_TIMEBASE);
+ outl(data[2], devpriv->i_IobaseAmcc + APCI1564_TIMER_TIMEBASE_REG);
/* Loading the Reload value */
- outl(data[3],
- devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_RELOAD_VALUE);
+ outl(data[3], devpriv->i_IobaseAmcc + APCI1564_TIMER_RELOAD_REG);
- ul_Command1 =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
- ul_Command1 =
- (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL;
- outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* mode 2 */
- } /* else if (data[0]==ADDIDATA_TIMER) */
- else if (data[0] == ADDIDATA_COUNTER) {
+ ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ ul_Command1 = (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL;
+ /* mode 2 */
+ outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ } else if (data[0] == ADDIDATA_COUNTER) {
devpriv->b_TimerSelectMode = ADDIDATA_COUNTER;
devpriv->b_ModeSelectRegister = data[5];
/* First Stop The Counter */
- ul_Command1 =
- inl(devpriv->iobase + ((data[5] - 1) * 0x20) +
- APCI1564_TCW_PROG);
+ ul_Command1 = inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
- outl(ul_Command1, devpriv->iobase + ((data[5] - 1) * 0x20) + APCI1564_TCW_PROG); /* Stop The Timer */
+ /* Stop The Timer */
+ outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
- /************************/
/* Set the reload value */
- /************************/
- outl(data[3],
- devpriv->iobase + ((data[5] - 1) * 0x20) +
- APCI1564_TCW_RELOAD_VALUE);
+ outl(data[3], devpriv->iobase + APCI1564_TCW_RELOAD_REG(data[5] - 1));
- /******************************/
/* Set the mode : */
/* - Disable the hardware */
/* - Disable the counter mode */
@@ -406,65 +281,36 @@ static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev,
/* - Disable the reset */
/* - Disable the timer mode */
/* - Enable the counter mode */
- /******************************/
+
ul_Command1 =
(ul_Command1 & 0xFFFC19E2UL) | 0x80000UL |
(unsigned int) ((unsigned int) data[4] << 16UL);
- outl(ul_Command1,
- devpriv->iobase + ((data[5] - 1) * 0x20) +
- APCI1564_TCW_PROG);
+ outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
/* Enable or Disable Interrupt */
ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1);
- outl(ul_Command1,
- devpriv->iobase + ((data[5] - 1) * 0x20) +
- APCI1564_TCW_PROG);
+ outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
- /*****************************/
/* Set the Up/Down selection */
- /*****************************/
ul_Command1 = (ul_Command1 & 0xFFFBF9FFUL) | (data[6] << 18);
- outl(ul_Command1,
- devpriv->iobase + ((data[5] - 1) * 0x20) +
- APCI1564_TCW_PROG);
- } /* else if (data[0]==ADDIDATA_COUNTER) */
- else {
- printk(" Invalid subdevice.");
- } /* else if (data[0]==ADDIDATA_WATCHDOG) */
+ outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
+ } else {
+ dev_err(dev->class_dev, "Invalid subdevice.\n");
+ }
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_StartStopWriteTimerCounterWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Start / Stop The Selected Timer , Counter or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[0] : 0 Timer |
-| 1 Counter |
-| 2 Watchdog | | data[1] : 1 Start |
-| 0 Stop |
-| 2 Trigger |
-| Clear (Only Counter) |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Start / Stop The Selected Timer, Counter or Watchdog
+ *
+ * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog
+ * data[1] 0 = Stop, 1 = Start, 2 = Trigger Clear (Only Counter)
+ */
+static int apci1564_timer_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ul_Command1 = 0;
@@ -472,203 +318,122 @@ static int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *d
if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
switch (data[1]) {
case 0: /* stop the watchdog */
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + APCI1564_TCW_PROG); /* disable the watchdog */
+ /* disable the watchdog */
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG);
break;
case 1: /* start the watchdog */
- outl(0x0001,
- devpriv->i_IobaseAmcc +
- APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_PROG);
+ outl(0x0001, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG);
break;
case 2: /* Software trigger */
- outl(0x0201,
- devpriv->i_IobaseAmcc +
- APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_PROG);
+ outl(0x0201, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG);
break;
default:
- printk("\nSpecified functionality does not exist\n");
+ dev_err(dev->class_dev, "Specified functionality does not exist.\n");
return -EINVAL;
- } /* switch (data[1]) */
- } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */
+ }
+ }
if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) {
if (data[1] == 1) {
- ul_Command1 =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
+ ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL;
/* Enable the Timer */
- outl(ul_Command1,
- devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
- } /* if (data[1]==1) */
- else if (data[1] == 0) {
+ outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ } else if (data[1] == 0) {
/* Stop The Timer */
- ul_Command1 =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
+ ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
- outl(ul_Command1,
- devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
- } /* else if(data[1]==0) */
- } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */
+ outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ }
+ }
if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) {
ul_Command1 =
- inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister -
- 1) * 0x20) + APCI1564_TCW_PROG);
+ inl(devpriv->iobase +
+ APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1));
if (data[1] == 1) {
/* Start the Counter subdevice */
ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL;
- } /* if (data[1] == 1) */
- else if (data[1] == 0) {
+ } else if (data[1] == 0) {
/* Stops the Counter subdevice */
ul_Command1 = 0;
- } /* else if (data[1] == 0) */
- else if (data[1] == 2) {
+ } else if (data[1] == 2) {
/* Clears the Counter subdevice */
ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400;
- } /* else if (data[1] == 3) */
+ }
outl(ul_Command1,
- devpriv->iobase + ((devpriv->b_ModeSelectRegister -
- 1) * 0x20) + APCI1564_TCW_PROG);
- } /* if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) */
+ devpriv->iobase +
+ APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1));
+ }
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_ReadTimerCounterWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Read The Selected Timer , Counter or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Read The Selected Timer, Counter or Watchdog
+ */
+static int apci1564_timer_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ul_Command1 = 0;
if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
/* Stores the status of the Watchdog */
- data[0] =
- inl(devpriv->i_IobaseAmcc +
- APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_TRIG_STATUS) & 0x1;
- data[1] =
- inl(devpriv->i_IobaseAmcc +
- APCI1564_DIGITAL_OP_WATCHDOG);
- } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */
- else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) {
+ data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_WDOG_STATUS_REG) & 0x1;
+ data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_WDOG_REG);
+ } else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) {
/* Stores the status of the Timer */
- data[0] =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_TRIG_STATUS) & 0x1;
+ data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_STATUS_REG) & 0x1;
/* Stores the Actual value of the Timer */
- data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER);
- } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */
- else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) {
+ data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_REG);
+ } else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) {
/* Read the Counter Actual Value. */
data[0] =
- inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister -
- 1) * 0x20) +
- APCI1564_TCW_SYNC_ENABLEDISABLE);
+ inl(devpriv->iobase +
+ APCI1564_TCW_REG(devpriv->b_ModeSelectRegister - 1));
ul_Command1 =
- inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister -
- 1) * 0x20) + APCI1564_TCW_TRIG_STATUS);
+ inl(devpriv->iobase +
+ APCI1564_TCW_STATUS_REG(devpriv->b_ModeSelectRegister - 1));
- /***********************************/
/* Get the software trigger status */
- /***********************************/
data[1] = (unsigned char) ((ul_Command1 >> 1) & 1);
- /***********************************/
/* Get the hardware trigger status */
- /***********************************/
data[2] = (unsigned char) ((ul_Command1 >> 2) & 1);
- /*********************************/
/* Get the software clear status */
- /*********************************/
data[3] = (unsigned char) ((ul_Command1 >> 3) & 1);
- /***************************/
/* Get the overflow status */
- /***************************/
data[4] = (unsigned char) ((ul_Command1 >> 0) & 1);
- } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) */
- else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER)
+ } else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER)
&& (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG)
&& (devpriv->b_TimerSelectMode != ADDIDATA_COUNTER)) {
- printk("\n Invalid Subdevice !!!\n");
- } /* else if ((devpriv->b_TimerSelectMode!=ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode!=ADDIDATA_WATCHDOG)&& (devpriv->b_TimerSelectMode!=ADDIDATA_COUNTER)) */
+ dev_err(dev->class_dev, "Invalid Subdevice!\n");
+ }
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_ReadInterruptStatus |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task :Reads the interrupt status register |
-+----------------------------------------------------------------------------+
-| Input Parameters : |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : |
-| |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1564_ReadInterruptStatus(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Reads the interrupt status register
+ */
+static int apci1564_do_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
*data = ui_Type;
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : static void v_APCI1564_Interrupt |
-| (int irq , void *d) |
-+----------------------------------------------------------------------------+
-| Task : Interrupt handler for the interruptible digital inputs |
-+----------------------------------------------------------------------------+
-| Input Parameters : int irq : irq number |
-| void *d : void pointer |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static void v_APCI1564_Interrupt(int irq, void *d)
+ * Interrupt handler for the interruptible digital inputs
+ */
+static void apci1564_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct addi_private *devpriv = dev->private;
@@ -677,79 +442,63 @@ static void v_APCI1564_Interrupt(int irq, void *d)
unsigned int ui_C1, ui_C2, ui_C3, ui_C4;
unsigned int ul_Command2 = 0;
- ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ) & 0x01;
- ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_IRQ) & 0x01;
- ui_Timer =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_IRQ) & 0x01;
- ui_C1 = inl(devpriv->iobase + APCI1564_COUNTER1 +
- APCI1564_TCW_IRQ) & 0x1;
- ui_C2 = inl(devpriv->iobase + APCI1564_COUNTER2 +
- APCI1564_TCW_IRQ) & 0x1;
- ui_C3 = inl(devpriv->iobase + APCI1564_COUNTER3 +
- APCI1564_TCW_IRQ) & 0x1;
- ui_C4 = inl(devpriv->iobase + APCI1564_COUNTER4 +
- APCI1564_TCW_IRQ) & 0x1;
+ ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG) & 0x01;
+ ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG) & 0x01;
+ ui_Timer = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_IRQ_REG) & 0x01;
+ ui_C1 =
+ inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)) & 0x1;
+ ui_C2 =
+ inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)) & 0x1;
+ ui_C3 =
+ inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)) & 0x1;
+ ui_C4 =
+ inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)) & 0x1;
if (ui_DI == 0 && ui_DO == 0 && ui_Timer == 0 && ui_C1 == 0
&& ui_C2 == 0 && ui_C3 == 0 && ui_C4 == 0) {
- printk("\nInterrupt from unknown source\n");
- } /* if(ui_DI==0 && ui_DO==0 && ui_Timer==0 && ui_C1==0 && ui_C2==0 && ui_C3==0 && ui_C4==0) */
+ dev_err(dev->class_dev, "Interrupt from unknown source.\n");
+ }
if (ui_DI == 1) {
- ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ);
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ);
+ ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
ui_InterruptStatus_1564 =
- inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_INTERRUPT_STATUS);
+ inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG);
ui_InterruptStatus_1564 = ui_InterruptStatus_1564 & 0X000FFFF0;
- send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
- outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ); /* enable the interrupt */
+ /* send signal to the sample */
+ send_sig(SIGIO, devpriv->tsk_Current, 0);
+ /* enable the interrupt */
+ outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
return;
}
if (ui_DO == 1) {
- /* Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt. */
- ui_Type =
- inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_INTERRUPT_STATUS) & 0x3;
+ /* Check for Digital Output interrupt Type */
+ /* 1: VCC interrupt */
+ /* 2: CC interrupt */
+ ui_Type = inl(devpriv->i_IobaseAmcc + APCI1564_DO_INT_STATUS_REG) & 0x3;
/* Disable the Interrupt */
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_INTERRUPT);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG);
/* Sends signal to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
-
- } /* if (ui_DO) */
+ }
if (ui_Timer == 1) {
devpriv->b_TimerSelectMode = ADDIDATA_TIMER;
if (devpriv->b_TimerSelectMode) {
/* Disable Timer Interrupt */
- ul_Command2 =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
+ ul_Command2 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
/* Send a signal to from kernel to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
/* Enable Timer Interrupt */
- outl(ul_Command2,
- devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
+ outl(ul_Command2, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
}
- }/* if (ui_Timer == 1) */
-
+ }
if (ui_C1 == 1) {
devpriv->b_TimerSelectMode = ADDIDATA_COUNTER;
@@ -757,21 +506,18 @@ static void v_APCI1564_Interrupt(int irq, void *d)
/* Disable Counter Interrupt */
ul_Command2 =
- inl(devpriv->iobase + APCI1564_COUNTER1 +
- APCI1564_TCW_PROG);
+ inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER1 +
- APCI1564_TCW_PROG);
+ devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
/* Send a signal to from kernel to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
/* Enable Counter Interrupt */
outl(ul_Command2,
- devpriv->iobase + APCI1564_COUNTER1 +
- APCI1564_TCW_PROG);
+ devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
}
- } /* if (ui_C1 == 1) */
+ }
if (ui_C2 == 1) {
devpriv->b_TimerSelectMode = ADDIDATA_COUNTER;
@@ -779,21 +525,18 @@ static void v_APCI1564_Interrupt(int irq, void *d)
/* Disable Counter Interrupt */
ul_Command2 =
- inl(devpriv->iobase + APCI1564_COUNTER2 +
- APCI1564_TCW_PROG);
+ inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER2 +
- APCI1564_TCW_PROG);
+ devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
/* Send a signal to from kernel to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
/* Enable Counter Interrupt */
outl(ul_Command2,
- devpriv->iobase + APCI1564_COUNTER2 +
- APCI1564_TCW_PROG);
+ devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
}
- } /* if ((ui_C2 == 1) */
+ }
if (ui_C3 == 1) {
devpriv->b_TimerSelectMode = ADDIDATA_COUNTER;
@@ -801,21 +544,18 @@ static void v_APCI1564_Interrupt(int irq, void *d)
/* Disable Counter Interrupt */
ul_Command2 =
- inl(devpriv->iobase + APCI1564_COUNTER3 +
- APCI1564_TCW_PROG);
+ inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER3 +
- APCI1564_TCW_PROG);
+ devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
/* Send a signal to from kernel to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
/* Enable Counter Interrupt */
outl(ul_Command2,
- devpriv->iobase + APCI1564_COUNTER3 +
- APCI1564_TCW_PROG);
+ devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
}
- } /* if ((ui_C3 == 1) */
+ }
if (ui_C4 == 1) {
devpriv->b_TimerSelectMode = ADDIDATA_COUNTER;
@@ -823,60 +563,45 @@ static void v_APCI1564_Interrupt(int irq, void *d)
/* Disable Counter Interrupt */
ul_Command2 =
- inl(devpriv->iobase + APCI1564_COUNTER4 +
- APCI1564_TCW_PROG);
+ inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER4 +
- APCI1564_TCW_PROG);
+ devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
/* Send a signal to from kernel to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
/* Enable Counter Interrupt */
outl(ul_Command2,
- devpriv->iobase + APCI1564_COUNTER4 +
- APCI1564_TCW_PROG);
+ devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
}
- } /* if (ui_C4 == 1) */
+ }
return;
}
-/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_Reset(struct comedi_device *dev) | |
-+----------------------------------------------------------------------------+
-| Task :resets all the registers |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : |
-| |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1564_Reset(struct comedi_device *dev)
+static int apci1564_reset(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_IRQ); /* disable the interrupts */
- inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_STATUS); /* Reset the interrupt status register */
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE1); /* Disable the and/or interrupt */
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE2);
+ /* disable the interrupts */
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
+ /* Reset the interrupt status register */
+ inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG);
+ /* Disable the and/or interrupt */
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG);
devpriv->b_DigitalOutputRegister = 0;
ui_Type = 0;
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP); /* Resets the output channels */
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_INTERRUPT); /* Disables the interrupt. */
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_RELOAD_VALUE);
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER);
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG);
-
- outl(0x0, devpriv->iobase + APCI1564_COUNTER1 + APCI1564_TCW_PROG);
- outl(0x0, devpriv->iobase + APCI1564_COUNTER2 + APCI1564_TCW_PROG);
- outl(0x0, devpriv->iobase + APCI1564_COUNTER3 + APCI1564_TCW_PROG);
- outl(0x0, devpriv->iobase + APCI1564_COUNTER4 + APCI1564_TCW_PROG);
+ /* Resets the output channels */
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_REG);
+ /* Disables the interrupt. */
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_RELOAD_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+
+ outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
+ outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
+ outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
+ outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
return 0;
}
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
index bd05857b82f2..70e8f426285c 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
@@ -248,10 +248,10 @@ static const struct comedi_lrange range_apci3120_ao = {
+----------------------------------------------------------------------------+
*/
-static int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3120_ai_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
const struct addi_board *this_board = comedi_board(dev);
struct addi_private *devpriv = dev->private;
@@ -304,11 +304,11 @@ static int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,
* If the last argument of function "check"is 1 then it only checks
* the channel list is ok or not.
*/
-static int i_APCI3120_SetupChannelList(struct comedi_device *dev,
- struct comedi_subdevice *s,
- int n_chan,
- unsigned int *chanlist,
- char check)
+static int apci3120_setup_chan_list(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ int n_chan,
+ unsigned int *chanlist,
+ char check)
{
struct addi_private *devpriv = dev->private;
unsigned int i; /* , differencial=0, bipolar=0; */
@@ -358,10 +358,10 @@ static int i_APCI3120_SetupChannelList(struct comedi_device *dev,
* as per configured if no conversion time is set uses default
* conversion time 10 microsec.
*/
-static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3120_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
const struct addi_board *this_board = comedi_board(dev);
struct addi_private *devpriv = dev->private;
@@ -417,10 +417,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev,
inw(devpriv->iobase + APCI3120_RESET_FIFO);
/* Initialize the sequence array */
-
- /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */
-
- if (!i_APCI3120_SetupChannelList(dev, s, 1,
+ if (!apci3120_setup_chan_list(dev, s, 1,
&insn->chanspec, 0))
return -EINVAL;
@@ -512,7 +509,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev,
outw(devpriv->us_OutputRegister,
devpriv->iobase + APCI3120_WR_ADDRESS);
- if (!i_APCI3120_SetupChannelList(dev, s,
+ if (!apci3120_setup_chan_list(dev, s,
devpriv->ui_AiNbrofChannels,
devpriv->ui_AiChannelList, 0))
return -EINVAL;
@@ -606,7 +603,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev,
}
-static int i_APCI3120_Reset(struct comedi_device *dev)
+static int apci3120_reset(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
unsigned int i;
@@ -663,7 +660,7 @@ static int i_APCI3120_Reset(struct comedi_device *dev)
return 0;
}
-static int i_APCI3120_ExttrigEnable(struct comedi_device *dev)
+static int apci3120_exttrig_enable(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
@@ -672,7 +669,7 @@ static int i_APCI3120_ExttrigEnable(struct comedi_device *dev)
return 0;
}
-static int i_APCI3120_ExttrigDisable(struct comedi_device *dev)
+static int apci3120_exttrig_disable(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
@@ -681,8 +678,8 @@ static int i_APCI3120_ExttrigDisable(struct comedi_device *dev)
return 0;
}
-static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int apci3120_cancel(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct addi_private *devpriv = dev->private;
@@ -705,7 +702,7 @@ static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,
* devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */
/* Disable ext trigger */
- i_APCI3120_ExttrigDisable(dev);
+ apci3120_exttrig_disable(dev);
devpriv->us_OutputRegister = 0;
/* stop counters */
@@ -729,13 +726,13 @@ static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,
devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
devpriv->b_InterruptMode = APCI3120_EOC_MODE;
devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
- i_APCI3120_Reset(dev);
+ apci3120_reset(dev);
return 0;
}
-static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
+static int apci3120_ai_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
{
const struct addi_board *this_board = comedi_board(dev);
int err = 0;
@@ -818,9 +815,9 @@ static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev,
* If DMA is configured does DMA initialization otherwise does the
* acquisition with EOS interrupt.
*/
-static int i_APCI3120_CyclicAnalogInput(int mode,
- struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int apci3120_cyclic_ai(int mode,
+ struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
const struct addi_board *this_board = comedi_board(dev);
struct addi_private *devpriv = dev->private;
@@ -904,7 +901,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode,
/**********************************/
/* Initializes the sequence array */
/**********************************/
- if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels,
+ if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels,
devpriv->pui_AiChannelList, 0))
return -EINVAL;
@@ -957,7 +954,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode,
/*** EL241003 End ******************************************************************************/
if (devpriv->b_ExttrigEnable == APCI3120_ENABLE)
- i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */
+ apci3120_exttrig_enable(dev); /* activate EXT trigger */
switch (mode) {
case 1:
/* init timer0 in mode 2 */
@@ -1333,8 +1330,8 @@ static int i_APCI3120_CyclicAnalogInput(int mode,
* Does asynchronous acquisition.
* Determines the mode 1 or 2.
*/
-static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int apci3120_ai_cmd(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct addi_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
@@ -1371,7 +1368,7 @@ static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev,
devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */
/* return this_board->ai_cmd(1,dev,s); */
- return i_APCI3120_CyclicAnalogInput(1, dev, s);
+ return apci3120_cyclic_ai(1, dev, s);
}
}
@@ -1381,7 +1378,7 @@ static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev,
devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */
/* return this_board->ai_cmd(2,dev,s); */
- return i_APCI3120_CyclicAnalogInput(2, dev, s);
+ return apci3120_cyclic_ai(2, dev, s);
}
return -1;
}
@@ -1410,7 +1407,7 @@ static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,
* For continuous DMA it reinitializes the DMA operation.
* For single mode DMA it stop the acquisition.
*/
-static void v_APCI3120_InterruptDma(int irq, void *d)
+static void apci3120_interrupt_dma(int irq, void *d)
{
struct comedi_device *dev = d;
struct addi_private *devpriv = dev->private;
@@ -1429,7 +1426,7 @@ static void v_APCI3120_InterruptDma(int irq, void *d)
}
if (samplesinbuf & 1) {
comedi_error(dev, "Odd count of bytes in DMA ring!");
- i_APCI3120_StopCyclicAcquisition(dev, s);
+ apci3120_cancel(dev, s);
devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
return;
@@ -1500,7 +1497,7 @@ static void v_APCI3120_InterruptDma(int irq, void *d)
if (!devpriv->b_AiContinuous)
if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
/* all data sampled */
- i_APCI3120_StopCyclicAcquisition(dev, s);
+ apci3120_cancel(dev, s);
devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
s->async->events |= COMEDI_CB_EOA;
comedi_event(dev, s);
@@ -1565,7 +1562,7 @@ static void v_APCI3120_InterruptDma(int irq, void *d)
* This function handles EOS interrupt.
* This function copies the acquired data(from FIFO) to Comedi buffer.
*/
-static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
+static int apci3120_interrupt_handle_eos(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
@@ -1574,8 +1571,6 @@ static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
n_chan = devpriv->ui_AiNbrofChannels;
- s->async->events = 0;
-
for (i = 0; i < n_chan; i++)
err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
@@ -1589,7 +1584,7 @@ static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
return 0;
}
-static void v_APCI3120_Interrupt(int irq, void *d)
+static void apci3120_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct addi_private *devpriv = dev->private;
@@ -1615,7 +1610,7 @@ static void v_APCI3120_Interrupt(int irq, void *d)
if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
/* Disable ext trigger */
- i_APCI3120_ExttrigDisable(dev);
+ apci3120_exttrig_disable(dev);
devpriv->b_ExttrigEnable = APCI3120_DISABLE;
}
/* clear the timer 2 interrupt */
@@ -1655,7 +1650,7 @@ static void v_APCI3120_Interrupt(int irq, void *d)
if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
ui_Check = 0;
- i_APCI3120_InterruptHandleEos(dev);
+ apci3120_interrupt_handle_eos(dev);
devpriv->ui_AiActualScan++;
devpriv->b_ModeSelectRegister =
devpriv->
@@ -1711,7 +1706,7 @@ static void v_APCI3120_Interrupt(int irq, void *d)
dev->iobase + APCI3120_WR_ADDRESS);
/* stop timer 0 and timer 1 */
- i_APCI3120_StopCyclicAcquisition(dev, s);
+ apci3120_cancel(dev, s);
devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
/* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
@@ -1765,7 +1760,8 @@ static void v_APCI3120_Interrupt(int irq, void *d)
/* Clears the timer status register */
/************************************/
inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
- v_APCI3120_InterruptDma(irq, d); /* do some data transfer */
+ /* do some data transfer */
+ apci3120_interrupt_dma(irq, d);
} else {
/* Stops the Timer */
outw(devpriv->
@@ -1787,7 +1783,7 @@ static void v_APCI3120_Interrupt(int irq, void *d)
* data[1] = Timer constant
* data[2] = Timer2 interrupt (1)enable or(0) disable
*/
-static int i_APCI3120_InsnConfigTimer(struct comedi_device *dev,
+static int apci3120_config_insn_timer(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
@@ -1932,7 +1928,7 @@ static int i_APCI3120_InsnConfigTimer(struct comedi_device *dev,
* = 1 Timer
* = 2 Watch dog
*/
-static int i_APCI3120_InsnWriteTimer(struct comedi_device *dev,
+static int apci3120_write_insn_timer(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
@@ -2104,7 +2100,7 @@ static int i_APCI3120_InsnWriteTimer(struct comedi_device *dev,
* for watchdog: data[0] = 0 (still running)
* = 1 (run down)
*/
-static int i_APCI3120_InsnReadTimer(struct comedi_device *dev,
+static int apci3120_read_insn_timer(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
@@ -2189,10 +2185,10 @@ static int apci3120_do_insn_bits(struct comedi_device *dev,
return insn->n;
}
-static int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3120_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ui_Range, ui_Channel;
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
index 8c85a09d1c66..0536d8373861 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
@@ -1268,7 +1268,7 @@ static int i_APCI3200_ReadCJCCalGain(struct comedi_device *dev,
return 0;
}
-static int i_APCI3200_Reset(struct comedi_device *dev)
+static int apci3200_reset(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
int i_Temp;
@@ -1322,10 +1322,10 @@ static int i_APCI3200_Reset(struct comedi_device *dev)
* data[7] : Channel current source from eeprom
* data[8] : Channle gain factor from eeprom
*/
-static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3200_ai_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
unsigned int ui_DummyValue = 0;
int i_ConvertCJCCalibration;
@@ -1336,7 +1336,7 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev,
if (s_BoardInfos[dev->minor].i_Initialised == 0)
/* END JK 06.07.04: Management of sevrals boards */
{
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return -EINVAL;
} /* if(i_Initialised==0); */
@@ -1586,7 +1586,7 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev,
break;
default:
printk("\nThe parameters passed are in error\n");
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return -EINVAL;
} /* switch(insn->unused[0]) */
@@ -1626,10 +1626,10 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev,
* = 2 RTD 3 wire connection
* = 3 RTD 4 wire connection
*/
-static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3200_ai_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ul_Config = 0, ul_Temp = 0;
@@ -1970,7 +1970,7 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev,
} /* switch(data[11]) */
} /* elseif(data[12]==0 || data[12]==1) */
if (i_err) {
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return -EINVAL;
}
/* if(i_ScanType!=1) */
@@ -2079,7 +2079,7 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev,
/* END JK 06.07.04: Management of sevrals boards */
insn->unused[0] = 0;
- i_APCI3200_ReadAnalogInput(dev, s, insn, &ui_Dummy);
+ apci3200_ai_read(dev, s, insn, &ui_Dummy);
}
return insn->n;
@@ -2095,10 +2095,10 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev,
* data[1] : calibration offset
* data[2] : calibration gain
*/
-static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3200_ai_bits_test(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ui_Configuration = 0;
@@ -2107,12 +2107,12 @@ static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev,
/* if(i_Initialised==0) */
if (s_BoardInfos[dev->minor].i_Initialised == 0) {
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return -EINVAL;
} /* if(i_Initialised==0); */
if (data[0] != 0 && data[0] != 1) {
printk("\nError in selection of functionality\n");
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return -EINVAL;
} /* if(data[0]!=0 && data[0]!=1) */
@@ -2202,18 +2202,18 @@ static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev,
return insn->n;
}
-static int i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3200_ai_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return insn->n;
}
-static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
+static int apci3200_ai_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
{
int err = 0;
@@ -2241,7 +2241,7 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev,
err |= -EINVAL;
if (err) {
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return 1;
}
@@ -2267,7 +2267,7 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev,
}
if (err) {
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return 2;
}
/* i_FirstChannel=cmd->chanlist[0]; */
@@ -2308,7 +2308,7 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev,
printk("\nThe Delay time value is in error\n");
}
if (err) {
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return 3;
}
fpu_begin();
@@ -2366,15 +2366,15 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev,
} /* else if(cmd->scan_begin_src==TRIG_FOLLOW) */
if (err) {
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return 4;
}
return 0;
}
-static int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int apci3200_cancel(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct addi_private *devpriv = dev->private;
unsigned int ui_Configuration = 0;
@@ -2410,8 +2410,8 @@ static int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev,
* Does asynchronous acquisition
* Determines the mode 1 or 2.
*/
-static int i_APCI3200_CommandAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int apci3200_ai_cmd(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct addi_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
@@ -2619,7 +2619,6 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev)
/* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */
/* This value is not used */
/* ui_ChannelNumber = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 24); */
- s->async->events = 0;
/* END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */
/*************************************/
@@ -2730,7 +2729,7 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev)
return 0;
}
-static void v_APCI3200_Interrupt(int irq, void *d)
+static void apci3200_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct addi_private *devpriv = dev->private;
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
index ebc1534a8df8..20e89b0bdc4d 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
@@ -16,10 +16,10 @@
* data[2] : Time Unit
* data[3] : Reload Value
*/
-static int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3501_config_insn_timer(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct apci3501_private *devpriv = dev->private;
unsigned int ul_Command1 = 0;
@@ -86,10 +86,10 @@ static int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev,
* 0 Stop
* 2 Trigger
*/
-static int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3501_write_insn_timer(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct apci3501_private *devpriv = dev->private;
unsigned int ul_Command1 = 0;
@@ -153,10 +153,10 @@ static int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *d
* 2 Watchdog
* data[1] : Timer Counter Watchdog Number
*/
-static int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3501_read_insn_timer(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct apci3501_private *devpriv = dev->private;
diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c
index ccd49211ea17..4da9db35b8e2 100644
--- a/drivers/staging/comedi/drivers/addi_apci_035.c
+++ b/drivers/staging/comedi/drivers/addi_apci_035.c
@@ -27,13 +27,13 @@ static const struct addi_board apci035_boardtypes[] = {
.i_Timer = 1,
.ui_MinAcquisitiontimeNs = 10000,
.ui_MinDelaytimeNs = 100000,
- .interrupt = v_APCI035_Interrupt,
- .reset = i_APCI035_Reset,
- .ai_config = i_APCI035_ConfigAnalogInput,
- .ai_read = i_APCI035_ReadAnalogInput,
- .timer_config = i_APCI035_ConfigTimerWatchdog,
- .timer_write = i_APCI035_StartStopWriteTimerWatchdog,
- .timer_read = i_APCI035_ReadTimerWatchdog,
+ .interrupt = apci035_interrupt,
+ .reset = apci035_reset,
+ .ai_config = apci035_ai_config,
+ .ai_read = apci035_ai_read,
+ .timer_config = apci035_timer_config,
+ .timer_write = apci035_timer_write,
+ .timer_read = apci035_timer_read,
},
};
diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c
index 74f7ace8adbc..bd8e08ca14c0 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1500.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1500.c
@@ -20,19 +20,19 @@ static const struct addi_board apci1500_boardtypes[] = {
.i_NbrDoChannel = 16,
.i_DoMaxdata = 0xffff,
.i_Timer = 1,
- .interrupt = v_APCI1500_Interrupt,
- .reset = i_APCI1500_Reset,
- .di_config = i_APCI1500_ConfigDigitalInputEvent,
- .di_read = i_APCI1500_Initialisation,
- .di_write = i_APCI1500_StartStopInputEvent,
+ .interrupt = apci1500_interrupt,
+ .reset = apci1500_reset,
+ .di_config = apci1500_di_config,
+ .di_read = apci1500_di_read,
+ .di_write = apci1500_di_write,
.di_bits = apci1500_di_insn_bits,
- .do_config = i_APCI1500_ConfigDigitalOutputErrorInterrupt,
- .do_write = i_APCI1500_WriteDigitalOutput,
- .do_bits = i_APCI1500_ConfigureInterrupt,
- .timer_config = i_APCI1500_ConfigCounterTimerWatchdog,
- .timer_write = i_APCI1500_StartStopTriggerTimerCounterWatchdog,
- .timer_read = i_APCI1500_ReadInterruptMask,
- .timer_bits = i_APCI1500_ReadCounterTimerWatchdog,
+ .do_config = apci1500_do_config,
+ .do_write = apci1500_do_write,
+ .do_bits = apci1500_do_bits,
+ .timer_config = apci1500_timer_config,
+ .timer_write = apci1500_timer_write,
+ .timer_read = apci1500_timer_read,
+ .timer_bits = apci1500_timer_bits,
},
};
diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c
index 6248284caaf5..27aa9ae1bdd9 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1564.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1564.c
@@ -21,16 +21,16 @@ static const struct addi_board apci1564_boardtypes[] = {
.i_NbrDoChannel = 32,
.i_DoMaxdata = 0xffffffff,
.i_Timer = 1,
- .interrupt = v_APCI1564_Interrupt,
- .reset = i_APCI1564_Reset,
- .di_config = i_APCI1564_ConfigDigitalInput,
+ .interrupt = apci1564_interrupt,
+ .reset = apci1564_reset,
+ .di_config = apci1564_di_config,
.di_bits = apci1564_di_insn_bits,
- .do_config = i_APCI1564_ConfigDigitalOutput,
+ .do_config = apci1564_do_config,
.do_bits = apci1564_do_insn_bits,
- .do_read = i_APCI1564_ReadInterruptStatus,
- .timer_config = i_APCI1564_ConfigTimerCounterWatchdog,
- .timer_write = i_APCI1564_StartStopWriteTimerCounterWatchdog,
- .timer_read = i_APCI1564_ReadTimerCounterWatchdog,
+ .do_read = apci1564_do_read,
+ .timer_config = apci1564_timer_config,
+ .timer_write = apci1564_timer_write,
+ .timer_read = apci1564_timer_read,
},
};
diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c
index 1e6fa56c516e..57ee6e5c7635 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3120.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3120.c
@@ -26,7 +26,7 @@ static const struct addi_board apci3120_boardtypes[] = {
.i_NbrDiChannel = 4,
.i_NbrDoChannel = 4,
.i_DoMaxdata = 0x0f,
- .interrupt = v_APCI3120_Interrupt,
+ .interrupt = apci3120_interrupt,
},
[BOARD_APCI3001] = {
.pc_DriverName = "apci3001",
@@ -37,7 +37,7 @@ static const struct addi_board apci3120_boardtypes[] = {
.i_NbrDiChannel = 4,
.i_NbrDoChannel = 4,
.i_DoMaxdata = 0x0f,
- .interrupt = v_APCI3120_Interrupt,
+ .interrupt = apci3120_interrupt,
},
};
@@ -136,11 +136,11 @@ static int apci3120_auto_attach(struct comedi_device *dev,
s->len_chanlist = this_board->i_AiChannelList;
s->range_table = &range_apci3120_ai;
- s->insn_config = i_APCI3120_InsnConfigAnalogInput;
- s->insn_read = i_APCI3120_InsnReadAnalogInput;
- s->do_cmdtest = i_APCI3120_CommandTestAnalogInput;
- s->do_cmd = i_APCI3120_CommandAnalogInput;
- s->cancel = i_APCI3120_StopCyclicAcquisition;
+ s->insn_config = apci3120_ai_insn_config;
+ s->insn_read = apci3120_ai_insn_read;
+ s->do_cmdtest = apci3120_ai_cmdtest;
+ s->do_cmd = apci3120_ai_cmd;
+ s->cancel = apci3120_cancel;
/* Allocate and Initialise AO Subdevice Structures */
s = &dev->subdevices[1];
@@ -151,7 +151,7 @@ static int apci3120_auto_attach(struct comedi_device *dev,
s->maxdata = this_board->i_AoMaxdata;
s->len_chanlist = this_board->i_NbrAoChannel;
s->range_table = &range_apci3120_ao;
- s->insn_write = i_APCI3120_InsnWriteAnalogOutput;
+ s->insn_write = apci3120_ao_insn_write;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -186,11 +186,11 @@ static int apci3120_auto_attach(struct comedi_device *dev,
s->len_chanlist = 1;
s->range_table = &range_digital;
- s->insn_write = i_APCI3120_InsnWriteTimer;
- s->insn_read = i_APCI3120_InsnReadTimer;
- s->insn_config = i_APCI3120_InsnConfigTimer;
+ s->insn_write = apci3120_write_insn_timer;
+ s->insn_read = apci3120_read_insn_timer;
+ s->insn_config = apci3120_config_insn_timer;
- i_APCI3120_Reset(dev);
+ apci3120_reset(dev);
return 0;
}
@@ -200,7 +200,7 @@ static void apci3120_detach(struct comedi_device *dev)
if (devpriv) {
if (dev->iobase)
- i_APCI3120_Reset(dev);
+ apci3120_reset(dev);
if (dev->irq)
free_irq(dev->irq, dev);
if (devpriv->ul_DmaBufferVirtual[0]) {
diff --git a/drivers/staging/comedi/drivers/addi_apci_3200.c b/drivers/staging/comedi/drivers/addi_apci_3200.c
index 9868a5369aff..f0f891a482a3 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3200.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3200.c
@@ -43,15 +43,15 @@ static const struct addi_board apci3200_boardtypes[] = {
.i_NbrDoChannel = 4,
.ui_MinAcquisitiontimeNs = 10000,
.ui_MinDelaytimeNs = 100000,
- .interrupt = v_APCI3200_Interrupt,
- .reset = i_APCI3200_Reset,
- .ai_config = i_APCI3200_ConfigAnalogInput,
- .ai_read = i_APCI3200_ReadAnalogInput,
- .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput,
- .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test,
- .ai_cmdtest = i_APCI3200_CommandTestAnalogInput,
- .ai_cmd = i_APCI3200_CommandAnalogInput,
- .ai_cancel = i_APCI3200_StopCyclicAcquisition,
+ .interrupt = apci3200_interrupt,
+ .reset = apci3200_reset,
+ .ai_config = apci3200_ai_config,
+ .ai_read = apci3200_ai_read,
+ .ai_write = apci3200_ai_write,
+ .ai_bits = apci3200_ai_bits_test,
+ .ai_cmdtest = apci3200_ai_cmdtest,
+ .ai_cmd = apci3200_ai_cmd,
+ .ai_cancel = apci3200_cancel,
.di_bits = apci3200_di_insn_bits,
.do_bits = apci3200_do_insn_bits,
},
@@ -68,15 +68,15 @@ static const struct addi_board apci3200_boardtypes[] = {
.i_NbrDoChannel = 4,
.ui_MinAcquisitiontimeNs = 10000,
.ui_MinDelaytimeNs = 100000,
- .interrupt = v_APCI3200_Interrupt,
- .reset = i_APCI3200_Reset,
- .ai_config = i_APCI3200_ConfigAnalogInput,
- .ai_read = i_APCI3200_ReadAnalogInput,
- .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput,
- .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test,
- .ai_cmdtest = i_APCI3200_CommandTestAnalogInput,
- .ai_cmd = i_APCI3200_CommandAnalogInput,
- .ai_cancel = i_APCI3200_StopCyclicAcquisition,
+ .interrupt = apci3200_interrupt,
+ .reset = apci3200_reset,
+ .ai_config = apci3200_ai_config,
+ .ai_read = apci3200_ai_read,
+ .ai_write = apci3200_ai_write,
+ .ai_bits = apci3200_ai_bits_test,
+ .ai_cmdtest = apci3200_ai_cmdtest,
+ .ai_cmd = apci3200_ai_cmd,
+ .ai_cancel = apci3200_cancel,
.di_bits = apci3200_di_insn_bits,
.do_bits = apci3200_do_insn_bits,
},
diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c
index 4cb69ec54c9b..49bf1fb840f6 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3501.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3501.c
@@ -390,9 +390,9 @@ static int apci3501_auto_attach(struct comedi_device *dev,
s->maxdata = 0;
s->len_chanlist = 1;
s->range_table = &range_digital;
- s->insn_write = i_APCI3501_StartStopWriteTimerCounterWatchdog;
- s->insn_read = i_APCI3501_ReadTimerCounterWatchdog;
- s->insn_config = i_APCI3501_ConfigTimerCounterWatchdog;
+ s->insn_write = apci3501_write_insn_timer;
+ s->insn_read = apci3501_read_insn_timer;
+ s->insn_config = apci3501_config_insn_timer;
/* Initialize the eeprom subdevice */
s = &dev->subdevices[4];
diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
index ceadf8eff47f..6dc11c407f57 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
@@ -434,13 +434,26 @@ static int apci3xxx_ai_setup(struct comedi_device *dev, unsigned int chanspec)
return 0;
}
+static int apci3xxx_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct apci3xxx_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readl(devpriv->mmio + 20);
+ if (status & 0x1)
+ return 0;
+ return -EBUSY;
+}
+
static int apci3xxx_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
struct apci3xxx_private *devpriv = dev->private;
- unsigned int val;
int ret;
int i;
@@ -453,10 +466,9 @@ static int apci3xxx_ai_insn_read(struct comedi_device *dev,
writel(0x80000, devpriv->mmio + 8);
/* Wait the EOS */
- do {
- val = readl(devpriv->mmio + 20);
- val &= 0x1;
- } while (!val);
+ ret = comedi_timeout(dev, s, insn, apci3xxx_ai_eoc, 0);
+ if (ret)
+ return ret;
/* Read the analog value */
data[i] = readl(devpriv->mmio + 28);
@@ -622,6 +634,20 @@ static int apci3xxx_ai_cancel(struct comedi_device *dev,
return 0;
}
+static int apci3xxx_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct apci3xxx_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readl(devpriv->mmio + 96);
+ if (status & 0x100)
+ return 0;
+ return -EBUSY;
+}
+
static int apci3xxx_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -630,7 +656,7 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev,
struct apci3xxx_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int range = CR_RANGE(insn->chanspec);
- unsigned int status;
+ int ret;
int i;
for (i = 0; i < insn->n; i++) {
@@ -641,9 +667,9 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev,
writel((data[i] << 8) | chan, devpriv->mmio + 100);
/* Wait the end of transfer */
- do {
- status = readl(devpriv->mmio + 96);
- } while ((status & 0x100) != 0x100);
+ ret = comedi_timeout(dev, s, insn, apci3xxx_ao_eoc, 0);
+ if (ret)
+ return ret;
}
return insn->n;
@@ -680,7 +706,7 @@ static int apci3xxx_dio_insn_config(struct comedi_device *dev,
unsigned int *data)
{
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int mask;
+ unsigned int mask = 0;
int ret;
/*
@@ -688,12 +714,13 @@ static int apci3xxx_dio_insn_config(struct comedi_device *dev,
* Port 1 (channels 8-15) are always outputs
* Port 2 (channels 16-23) are programmable i/o
*/
- if (chan < 16) {
- if (data[0] != INSN_CONFIG_DIO_QUERY)
+ if (data[0] != INSN_CONFIG_DIO_QUERY) {
+ /* ignore all other instructions for ports 0 and 1 */
+ if (chan < 16)
return -EINVAL;
- } else {
- /* changing any channel in port 2 changes the entire port */
- mask = 0xff0000;
+ else
+ /* changing any channel in port 2 changes the entire port */
+ mask = 0xff0000;
}
ret = comedi_dio_insn_config(dev, s, insn, data, mask);
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index 5c1413abc52d..921f6942dfce 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -73,19 +73,17 @@ struct pci6208_private {
unsigned int ao_readback[PCI6208_MAX_AO_CHANNELS];
};
-static int pci6208_ao_wait_for_data_send(struct comedi_device *dev,
- unsigned int timeout)
+static int pci6208_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
unsigned int status;
- while (timeout--) {
- status = inw(dev->iobase + PCI6208_AO_STATUS);
- if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0)
- return 0;
- udelay(1);
- }
-
- return -ETIME;
+ status = inw(dev->iobase + PCI6208_AO_STATUS);
+ if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0)
+ return 0;
+ return -EBUSY;
}
static int pci6208_ao_insn_write(struct comedi_device *dev,
@@ -102,8 +100,8 @@ static int pci6208_ao_insn_write(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
val = data[i];
- /* D/A transfer rate is 2.2us, wait up to 10us */
- ret = pci6208_ao_wait_for_data_send(dev, 10);
+ /* D/A transfer rate is 2.2us */
+ ret = comedi_timeout(dev, s, insn, pci6208_ao_eoc, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c
index 6f622b4de698..5e3cc77a8a0c 100644
--- a/drivers/staging/comedi/drivers/adl_pci7x3x.c
+++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c
@@ -239,9 +239,6 @@ static int adl_pci7x3x_auto_attach(struct comedi_device *dev,
}
}
- dev_info(dev->class_dev, "%s attached (%d inputs/%d outputs)\n",
- dev->board_name, board->di_nchan, board->do_nchan);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index 363f2e42a27f..a29ceacb966d 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -84,7 +84,6 @@ TODO:
#define PCI9111_RANGE_SETTING_DELAY 10
#define PCI9111_AI_INSTANT_READ_UDELAY_US 2
-#define PCI9111_AI_INSTANT_READ_TIMEOUT 100
/*
* IO address map and bit defines
@@ -490,29 +489,18 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev,
dev->iobase + PCI9111_AI_RANGE_STAT_REG);
/* Set counter */
-
- switch (async_cmd->stop_src) {
- case TRIG_COUNT:
+ if (async_cmd->stop_src == TRIG_COUNT) {
dev_private->stop_counter =
async_cmd->stop_arg * async_cmd->chanlist_len;
dev_private->stop_is_none = 0;
- break;
-
- case TRIG_NONE:
+ } else { /* TRIG_NONE */
dev_private->stop_counter = 0;
dev_private->stop_is_none = 1;
- break;
-
- default:
- comedi_error(dev, "Invalid stop trigger");
- return -1;
}
/* Set timer pacer */
-
dev_private->scan_delay = 0;
- switch (async_cmd->convert_src) {
- case TRIG_TIMER:
+ if (async_cmd->convert_src == TRIG_TIMER) {
pci9111_trigger_source_set(dev, software);
pci9111_timer_set(dev);
pci9111_fifo_reset(dev);
@@ -528,11 +516,7 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev,
(async_cmd->convert_arg *
async_cmd->chanlist_len)) - 1;
}
-
- break;
-
- case TRIG_EXT:
-
+ } else { /* TRIG_EXT */
pci9111_trigger_source_set(dev, external);
pci9111_fifo_reset(dev);
pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
@@ -540,11 +524,6 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev,
plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
false, true, true);
- break;
-
- default:
- comedi_error(dev, "Invalid convert trigger");
- return -1;
}
dev_private->stop_counter *= (1 + dev_private->scan_delay);
@@ -613,9 +592,8 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device)
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
outb(0, dev->iobase + PCI9111_INT_CLR_REG);
- pci9111_ai_cancel(dev, s);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
@@ -693,20 +671,31 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device)
}
}
- if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) {
+ if (dev_private->stop_counter == 0 && !dev_private->stop_is_none)
async->events |= COMEDI_CB_EOA;
- pci9111_ai_cancel(dev, s);
- }
outb(0, dev->iobase + PCI9111_INT_CLR_REG);
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
+static int pci9111_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
+ if (status & PCI9111_AI_STAT_FF_EF)
+ return 0;
+ return -EBUSY;
+}
+
static int pci9111_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -717,7 +706,7 @@ static int pci9111_ai_insn_read(struct comedi_device *dev,
unsigned int invert = (maxdata + 1) >> 1;
unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
unsigned int status;
- int timeout;
+ int ret;
int i;
outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG);
@@ -734,22 +723,12 @@ static int pci9111_ai_insn_read(struct comedi_device *dev,
/* Generate a software trigger */
outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG);
- timeout = PCI9111_AI_INSTANT_READ_TIMEOUT;
-
- while (timeout--) {
- status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
- /* '1' means FIFO is not empty */
- if (status & PCI9111_AI_STAT_FF_EF)
- goto conversion_done;
+ ret = comedi_timeout(dev, s, insn, pci9111_ai_eoc, 0);
+ if (ret) {
+ pci9111_fifo_reset(dev);
+ return ret;
}
- comedi_error(dev, "A/D read timeout");
- data[i] = 0;
- pci9111_fifo_reset(dev);
- return -ETIME;
-
-conversion_done:
-
data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG);
data[i] = ((data[i] >> shift) & maxdata) ^ invert;
}
@@ -906,8 +885,6 @@ static int pci9111_auto_attach(struct comedi_device *dev,
s->range_table = &range_digital;
s->insn_bits = pci9111_do_insn_bits;
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index 4bdd9720e9eb..3cfa1756fa6a 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -571,12 +571,26 @@ static int setup_channel_list(struct comedi_device *dev,
return 1; /* we can serve this with scan logic */
}
+static int pci9118_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inl(dev->iobase + PCI9118_ADSTAT);
+ if (status & AdStatus_ADrdy)
+ return 0;
+ return -EBUSY;
+}
+
static int pci9118_insn_read_ai(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct pci9118_private *devpriv = dev->private;
- int n, timeout;
+ int ret;
+ int n;
devpriv->AdControlReg = AdControl_Int & 0xff;
devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg;
@@ -597,19 +611,13 @@ static int pci9118_insn_read_ai(struct comedi_device *dev,
for (n = 0; n < insn->n; n++) {
outw(0, dev->iobase + PCI9118_SOFTTRG); /* start conversion */
udelay(2);
- timeout = 100;
- while (timeout--) {
- if (inl(dev->iobase + PCI9118_ADSTAT) & AdStatus_ADrdy)
- goto conv_finish;
- udelay(1);
- }
- comedi_error(dev, "A/D insn timeout");
- data[n] = 0;
- outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
- return -ETIME;
+ ret = comedi_timeout(dev, s, insn, pci9118_ai_eoc, 0);
+ if (ret) {
+ outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
+ return ret;
+ }
-conv_finish:
if (devpriv->ai16bits) {
data[n] =
(inl(dev->iobase +
@@ -911,8 +919,7 @@ static char pci9118_decode_error_status(struct comedi_device *dev,
}
if (m & devpriv->ai_maskharderr) {
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- pci9118_ai_cancel(dev, s);
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return 1;
}
@@ -948,8 +955,6 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev,
struct pci9118_private *devpriv = dev->private;
unsigned short sampl;
- s->async->events = 0;
-
if (int_adstat & devpriv->ai_maskerr)
if (pci9118_decode_error_status(dev, s, int_adstat))
return;
@@ -965,8 +970,7 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev,
sampl & 0x000f,
devpriv->chanlist[s->async->cur_chan]);
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- pci9118_ai_cancel(dev, s);
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
}
@@ -977,16 +981,14 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev,
/* one scan done */
s->async->cur_chan %= devpriv->ai_n_scanlen;
devpriv->ai_act_scan++;
- if (!(devpriv->ai_neverending))
- if (devpriv->ai_act_scan >= devpriv->ai_scans) {
- /* all data sampled */
- pci9118_ai_cancel(dev, s);
+ if (!devpriv->ai_neverending) {
+ /* all data sampled? */
+ if (devpriv->ai_act_scan >= devpriv->ai_scans)
s->async->events |= COMEDI_CB_EOA;
- }
+ }
}
- if (s->async->events)
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
@@ -1001,16 +1003,14 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
if (int_amcc & MASTER_ABORT_INT) {
comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- pci9118_ai_cancel(dev, s);
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
if (int_amcc & TARGET_ABORT_INT) {
comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- pci9118_ai_cancel(dev, s);
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
if (int_adstat & devpriv->ai_maskerr)
@@ -1048,12 +1048,11 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
m = m - sampls; /* m= how many samples was transferred */
}
- if (!devpriv->ai_neverending)
- if (devpriv->ai_act_scan >= devpriv->ai_scans) {
- /* all data sampled */
- pci9118_ai_cancel(dev, s);
+ if (!devpriv->ai_neverending) {
+ /* all data sampled? */
+ if (devpriv->ai_act_scan >= devpriv->ai_scans)
s->async->events |= COMEDI_CB_EOA;
- }
+ }
if (devpriv->dma_doublebuf) { /* switch dma buffers */
devpriv->dma_actbuf = 1 - devpriv->dma_actbuf;
@@ -1066,7 +1065,7 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
interrupt_pci9118_ai_mode4_switch(dev);
}
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
static irqreturn_t interrupt_pci9118(int irq, void *d)
@@ -1936,28 +1935,6 @@ static struct pci_dev *pci9118_find_pci(struct comedi_device *dev,
return NULL;
}
-static void pci9118_report_attach(struct comedi_device *dev, unsigned int irq)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- struct pci9118_private *devpriv = dev->private;
- char irqbuf[30];
- char muxbuf[30];
-
- if (irq)
- snprintf(irqbuf, sizeof(irqbuf), "irq %u%s", irq,
- (dev->irq ? "" : " UNAVAILABLE"));
- else
- snprintf(irqbuf, sizeof(irqbuf), "irq DISABLED");
- if (devpriv->usemux)
- snprintf(muxbuf, sizeof(muxbuf), "ext mux %u chans",
- devpriv->usemux);
- else
- snprintf(muxbuf, sizeof(muxbuf), "no ext mux");
- dev_info(dev->class_dev, "%s (pci %s, %s, %sbus master, %s) attached\n",
- dev->board_name, pci_name(pcidev), irqbuf,
- (devpriv->master ? "" : "no "), muxbuf);
-}
-
static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
int master, int ext_mux, int softsshdelay,
int hw_err_mask)
@@ -2113,7 +2090,6 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
break;
}
- pci9118_report_attach(dev, dev->irq);
return 0;
}
diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c
index 3190ef7d285e..b4ea37704eaf 100644
--- a/drivers/staging/comedi/drivers/adq12b.c
+++ b/drivers/staging/comedi/drivers/adq12b.c
@@ -94,8 +94,6 @@ If you do not specify any options, they will default to
/* mask of the bit at STINR to check end of conversion */
#define ADQ12B_EOC 0x20
-#define TIMEOUT 20
-
/* available ranges through the PGA gains */
static const struct comedi_lrange range_adq12b_ai_bipolar = {
4, {
@@ -122,19 +120,28 @@ struct adq12b_private {
int last_range;
};
-/*
- * "instructions" read/write data in "one-shot" or "software-triggered"
- * mode.
- */
+static int adq12b_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned char status;
+
+ status = inb(dev->iobase + ADQ12B_STINR);
+ if (status & ADQ12B_EOC)
+ return 0;
+ return -EBUSY;
+}
static int adq12b_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
struct adq12b_private *devpriv = dev->private;
- int n, i;
+ int n;
int range, channel;
unsigned char hi, lo, status;
+ int ret;
/* change channel and range only if it is different from the previous */
range = CR_RANGE(insn->chanspec);
@@ -151,13 +158,9 @@ static int adq12b_ai_rinsn(struct comedi_device *dev,
for (n = 0; n < insn->n; n++) {
/* wait for end of conversion */
- i = 0;
- do {
- /* udelay(1); */
- status = inb(dev->iobase + ADQ12B_STINR);
- status = status & ADQ12B_EOC;
- } while (status == 0 && ++i < TIMEOUT);
- /* } while (++i < 10); */
+ ret = comedi_timeout(dev, s, insn, adq12b_ai_eoc, 0);
+ if (ret)
+ return ret;
/* read data */
hi = inb(dev->iobase + ADQ12B_ADHIG);
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index d9ad2c0fdda2..28ec48548317 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -429,15 +429,26 @@ static void setup_channel_list(struct comedi_device *dev,
outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
}
-/*
-==============================================================================
-*/
+static int pci171x_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + PCI171x_STATUS);
+ if ((status & Status_FE) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int pci171x_insn_read_ai(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct pci1710_private *devpriv = dev->private;
- int n, timeout;
+ int ret;
+ int n;
#ifdef PCI171x_PARANOIDCHECK
const struct boardtype *this_board = comedi_board(dev);
unsigned int idata;
@@ -453,19 +464,14 @@ static int pci171x_insn_read_ai(struct comedi_device *dev,
for (n = 0; n < insn->n; n++) {
outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
- /* udelay(1); */
- timeout = 100;
- while (timeout--) {
- if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
- goto conv_finish;
+
+ ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
+ if (ret) {
+ outb(0, dev->iobase + PCI171x_CLRFIFO);
+ outb(0, dev->iobase + PCI171x_CLRINT);
+ return ret;
}
- comedi_error(dev, "A/D insn timeout");
- outb(0, dev->iobase + PCI171x_CLRFIFO);
- outb(0, dev->iobase + PCI171x_CLRINT);
- data[n] = 0;
- return -ETIME;
-conv_finish:
#ifdef PCI171x_PARANOIDCHECK
idata = inw(dev->iobase + PCI171x_AD_DATA);
if (this_board->cardtype != TYPE_PCI1713)
@@ -753,17 +759,15 @@ static void interrupt_pci1710_every_sample(void *d)
m = inw(dev->iobase + PCI171x_STATUS);
if (m & Status_FE) {
dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", m);
- pci171x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
if (m & Status_FF) {
dev_dbg(dev->class_dev,
"A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
- pci171x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
@@ -782,10 +786,9 @@ static void interrupt_pci1710_every_sample(void *d)
act_chanlist[s->
async->cur_chan] & 0xf000) >>
12);
- pci171x_ai_cancel(dev, s);
s->async->events |=
COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
comedi_buf_put(s->async, sampl & 0x0fff);
@@ -804,9 +807,8 @@ static void interrupt_pci1710_every_sample(void *d)
if ((!devpriv->neverending_ai) &&
(devpriv->ai_act_scan >= devpriv->ai_scans)) {
/* all data sampled */
- pci171x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
}
@@ -814,7 +816,7 @@ static void interrupt_pci1710_every_sample(void *d)
outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
/*
@@ -842,10 +844,9 @@ static int move_block_from_fifo(struct comedi_device *dev,
(devpriv->act_chanlist[j] & 0xf000) >> 12,
i, j, devpriv->ai_act_scan, n, turn,
sampl);
- pci171x_ai_cancel(dev, s);
s->async->events |=
COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return 1;
}
comedi_buf_put(s->async, sampl & 0x0fff);
@@ -877,17 +878,15 @@ static void interrupt_pci1710_half_fifo(void *d)
m = inw(dev->iobase + PCI171x_STATUS);
if (!(m & Status_FH)) {
dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
- pci171x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
if (m & Status_FF) {
dev_dbg(dev->class_dev,
"A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
- pci171x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
@@ -907,14 +906,13 @@ static void interrupt_pci1710_half_fifo(void *d)
if (!devpriv->neverending_ai)
if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
sampled */
- pci171x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
/*
@@ -1354,9 +1352,6 @@ static int pci1710_auto_attach(struct comedi_device *dev,
subdev++;
}
- dev_info(dev->class_dev, "%s attached, irq %sabled\n",
- dev->board_name, dev->irq ? "en" : "dis");
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index 72394267ddfe..07b107d1ab33 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -280,8 +280,6 @@ static int pci1723_auto_attach(struct comedi_device *dev,
pci1723_reset(dev);
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index d4bd61d84daf..2d966a87f2e8 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -1130,10 +1130,12 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
for (i = 0; i < MAX_DIO_SUBDEVG; i++)
for (j = 0; j < this_board->sdio[i].regs; j++) {
s = &dev->subdevices[subdev];
- subdev_8255_init(dev, s, NULL,
- dev->iobase +
- this_board->sdio[i].addr +
- SIZE_8255 * j);
+ ret = subdev_8255_init(dev, s, NULL,
+ dev->iobase +
+ this_board->sdio[i].addr +
+ SIZE_8255 * j);
+ if (ret)
+ return ret;
subdev++;
}
diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c
index 68c3fb3226ca..324746b14931 100644
--- a/drivers/staging/comedi/drivers/aio_aio12_8.c
+++ b/drivers/staging/comedi/drivers/aio_aio12_8.c
@@ -101,14 +101,27 @@ struct aio12_8_private {
unsigned int ao_readback[4];
};
+static int aio_aio12_8_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + AIO12_8_STATUS_REG);
+ if (status & AIO12_8_STATUS_ADC_EOC)
+ return 0;
+ return -EBUSY;
+}
+
static int aio_aio12_8_ai_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int range = CR_RANGE(insn->chanspec);
- unsigned int val;
unsigned char control;
+ int ret;
int n;
/*
@@ -122,20 +135,13 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev,
inb(dev->iobase + AIO12_8_STATUS_REG);
for (n = 0; n < insn->n; n++) {
- int timeout = 5;
-
/* Setup and start conversion */
outb(control, dev->iobase + AIO12_8_ADC_REG);
/* Wait for conversion to complete */
- do {
- val = inb(dev->iobase + AIO12_8_STATUS_REG);
- timeout--;
- if (timeout == 0) {
- dev_err(dev->class_dev, "ADC timeout\n");
- return -ETIMEDOUT;
- }
- } while (!(val & AIO12_8_STATUS_ADC_EOC));
+ ret = comedi_timeout(dev, s, insn, aio_aio12_8_ai_eoc, 0);
+ if (ret)
+ return ret;
data[n] = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata;
}
@@ -247,9 +253,6 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
/* 8254 counter/timer subdevice */
s->type = COMEDI_SUBD_UNUSED;
- dev_info(dev->class_dev, "%s: %s attached\n",
- dev->driver->driver_name, dev->board_name);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index 22b3dda135ff..781104aa533e 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -98,7 +98,7 @@ static int aio_iiro_16_attach(struct comedi_device *dev,
s->range_table = &range_digital;
s->insn_bits = aio_iiro_16_dio_insn_bits_read;
- return 1;
+ return 0;
}
static struct comedi_driver aio_iiro_16_driver = {
diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c
index 9c9559ffc643..818a0d7e3d58 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200_common.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c
@@ -1208,7 +1208,7 @@ int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq,
"warning! irq %u unavailable!\n", irq);
}
}
- dev_info(dev->class_dev, "attached\n");
+
return 0;
}
EXPORT_SYMBOL_GPL(amplc_dio200_common_attach);
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index 31734e1142fd..b21d7b48f1da 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236.c
@@ -368,32 +368,6 @@ static irqreturn_t pc236_interrupt(int irq, void *d)
return IRQ_RETVAL(handled);
}
-static void pc236_report_attach(struct comedi_device *dev, unsigned int irq)
-{
- const struct pc236_board *thisboard = comedi_board(dev);
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- char tmpbuf[60];
- int tmplen;
-
- if (is_isa_board(thisboard))
- tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
- "(base %#lx) ", dev->iobase);
- else if (is_pci_board(thisboard))
- tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
- "(pci %s) ", pci_name(pcidev));
- else
- tmplen = 0;
- if (irq)
- tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
- "(irq %u%s) ", irq,
- (dev->irq ? "" : " UNAVAILABLE"));
- else
- tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
- "(no irq) ");
- dev_info(dev->class_dev, "%s %sattached\n",
- dev->board_name, tmpbuf);
-}
-
static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase,
unsigned int irq, unsigned long req_irq_flags)
{
@@ -411,10 +385,9 @@ static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase,
s = &dev->subdevices[0];
/* digital i/o subdevice (8255) */
ret = subdev_8255_init(dev, s, NULL, iobase);
- if (ret < 0) {
- dev_err(dev->class_dev, "error! out of memory!\n");
+ if (ret)
return ret;
- }
+
s = &dev->subdevices[1];
dev->read_subdev = s;
s->type = COMEDI_SUBD_UNUSED;
@@ -434,8 +407,8 @@ static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase,
s->cancel = pc236_intr_cancel;
}
}
- pc236_report_attach(dev, irq);
- return 1;
+
+ return 0;
}
static int pc236_pci_common_attach(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c
index 5b4b5ab34e2e..7c10d28d2784 100644
--- a/drivers/staging/comedi/drivers/amplc_pc263.c
+++ b/drivers/staging/comedi/drivers/amplc_pc263.c
@@ -94,8 +94,6 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* read initial relay state */
s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8);
- dev_info(dev->class_dev, "%s (base %#lx) attached\n", dev->board_name,
- dev->iobase);
return 0;
}
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index ae4048a624fa..29e01e280039 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -533,9 +533,8 @@ static void pci224_ao_start(struct comedi_device *dev,
set_bit(AO_CMD_STARTED, &devpriv->state);
if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) {
/* An empty acquisition! */
- pci224_ao_stop(dev, s);
s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
} else {
/* Enable interrupts. */
spin_lock_irqsave(&devpriv->ao_spinlock, flags);
@@ -585,9 +584,8 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev,
room = PCI224_FIFO_ROOM_EMPTY;
if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) {
/* FIFO empty at end of counted acquisition. */
- pci224_ao_stop(dev, s);
s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
break;
@@ -605,9 +603,8 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev,
/* FIFO is less than half-full. */
if (num_scans == 0) {
/* Nothing left to put in the FIFO. */
- pci224_ao_stop(dev, s);
- s->async->events |= COMEDI_CB_OVERFLOW;
dev_err(dev->class_dev, "AO buffer underrun\n");
+ s->async->events |= COMEDI_CB_OVERFLOW;
}
}
/* Determine how many new scans can be put in the FIFO. */
@@ -670,9 +667,8 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev,
PCI224_DACCON_TRIG_MASK);
outw(devpriv->daccon, dev->iobase + PCI224_DACCON);
}
- if (s->async->events)
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
/*
@@ -1237,20 +1233,6 @@ static struct pci_dev *pci224_find_pci_dev(struct comedi_device *dev,
return NULL;
}
-static void pci224_report_attach(struct comedi_device *dev, unsigned int irq)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- char tmpbuf[30];
-
- if (irq)
- snprintf(tmpbuf, sizeof(tmpbuf), "irq %u%s", irq,
- (dev->irq ? "" : " UNAVAILABLE"));
- else
- snprintf(tmpbuf, sizeof(tmpbuf), "no irq");
- dev_info(dev->class_dev, "%s (pci %s) (%s) attached\n",
- dev->board_name, pci_name(pcidev), tmpbuf);
-}
-
/*
* Common part of attach and auto_attach.
*/
@@ -1399,8 +1381,7 @@ static int pci224_attach_common(struct comedi_device *dev,
}
}
- pci224_report_attach(dev, irq);
- return 1;
+ return 0;
}
static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index c08dfbbe4062..99e60835dc4a 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -799,19 +799,29 @@ static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct)
/* Counter ct, 8254 mode 1, initial count not written. */
}
-/*
- * COMEDI_SUBD_AI instruction;
- */
+static int pci230_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + PCI230_ADCCON);
+ if ((status & PCI230_ADC_FIFO_EMPTY) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int pci230_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
struct pci230_private *devpriv = dev->private;
- unsigned int n, i;
+ unsigned int n;
unsigned int chan, range, aref;
unsigned int gainshift;
- unsigned int status;
unsigned short adccon, adcen;
+ int ret;
/* Unpack channel and range. */
chan = CR_CHAN(insn->chanspec);
@@ -883,18 +893,10 @@ static int pci230_ai_rinsn(struct comedi_device *dev,
i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
I8254_MODE1);
-#define TIMEOUT 100
/* wait for conversion to end */
- for (i = 0; i < TIMEOUT; i++) {
- status = inw(dev->iobase + PCI230_ADCCON);
- if (!(status & PCI230_ADC_FIFO_EMPTY))
- break;
- udelay(1);
- }
- if (i == TIMEOUT) {
- dev_err(dev->class_dev, "timeout\n");
- return -ETIMEDOUT;
- }
+ ret = comedi_timeout(dev, s, insn, pci230_ai_eoc, 0);
+ if (ret)
+ return ret;
/* read data */
data[n] = pci230_ai_read(dev);
@@ -2762,14 +2764,14 @@ static int pci230_attach_common(struct comedi_device *dev,
/* digital i/o subdevice */
if (thisboard->have_dio) {
rc = subdev_8255_init(dev, s, NULL,
- (devpriv->iobase1 + PCI230_PPI_X_BASE));
- if (rc < 0)
+ devpriv->iobase1 + PCI230_PPI_X_BASE);
+ if (rc)
return rc;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
- dev_info(dev->class_dev, "attached\n");
- return 1;
+
+ return 0;
}
static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it)
diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c
index be28e6cbea20..93ed03ee416a 100644
--- a/drivers/staging/comedi/drivers/amplc_pci263.c
+++ b/drivers/staging/comedi/drivers/amplc_pci263.c
@@ -84,8 +84,6 @@ static int pci263_auto_attach(struct comedi_device *dev,
/* read initial relay state */
s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8);
- dev_info(dev->class_dev, "%s (pci %s) attached\n", dev->board_name,
- pci_name(pci_dev));
return 0;
}
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index 5034f663eec9..e03dd6e71415 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -1,34 +1,33 @@
/*
- comedi/drivers/c6xdigio.c
-
- Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card.
- (http://robot0.ge.uiuc.edu/~spong/mecha/)
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1999 Dan Block
-
- This program is free software; 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.
+ * c6xdigio.c
+ * Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card.
+ * http://web.archive.org/web/%2A/http://robot0.ge.uiuc.edu/~spong/mecha/
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1999 Dan Block
+ *
+ * This program is free software; 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.
*/
-/*
-Driver: c6xdigio
-Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card
-Author: Dan Block
-Status: unknown
-Devices: [Mechatronic Systems Inc.] C6x_DIGIO DSP daughter card (c6xdigio)
-Updated: Sun Nov 20 20:18:34 EST 2005
-
-This driver will not work with a 2.4 kernel.
-http://robot0.ge.uiuc.edu/~spong/mecha/
-*/
+/*
+ * Driver: c6xdigio
+ * Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card
+ * Author: Dan Block
+ * Status: unknown
+ * Devices: (Mechatronic Systems Inc.) C6x_DIGIO DSP daughter card [c6xdigio]
+ * Updated: Sun Nov 20 20:18:34 EST 2005
+ *
+ * Configuration Options:
+ * [0] - base address
+ */
#include <linux/kernel.h>
#include <linux/module.h>
@@ -43,309 +42,194 @@ http://robot0.ge.uiuc.edu/~spong/mecha/
#include "../comedidev.h"
-static u8 ReadByteFromHwPort(unsigned long addr)
-{
- u8 result = inb(addr);
- return result;
-}
-
-static void WriteByteToHwPort(unsigned long addr, u8 val)
-{
- outb_p(val, addr);
-}
-
-#define C6XDIGIO_SIZE 3
-
/*
- * port offsets
+ * Register I/O map
*/
-#define C6XDIGIO_PARALLEL_DATA 0
-#define C6XDIGIO_PARALLEL_STATUS 1
-#define C6XDIGIO_PARALLEL_CONTROL 2
-struct pwmbitstype {
- unsigned sb0:2;
- unsigned sb1:2;
- unsigned sb2:2;
- unsigned sb3:2;
- unsigned sb4:2;
-};
-union pwmcmdtype {
- unsigned cmd; /* assuming here that int is 32bit */
- struct pwmbitstype bits;
-};
-struct encbitstype {
- unsigned sb0:3;
- unsigned sb1:3;
- unsigned sb2:3;
- unsigned sb3:3;
- unsigned sb4:3;
- unsigned sb5:3;
- unsigned sb6:3;
- unsigned sb7:3;
-};
-union encvaluetype {
- unsigned value;
- struct encbitstype bits;
-};
+#define C6XDIGIO_DATA_REG 0x00
+#define C6XDIGIO_DATA_CHAN(x) (((x) + 1) << 4)
+#define C6XDIGIO_DATA_PWM (1 << 5)
+#define C6XDIGIO_DATA_ENCODER (1 << 6)
+#define C6XDIGIO_STATUS_REG 0x01
+#define C6XDIGIO_CTRL_REG 0x02
#define C6XDIGIO_TIME_OUT 20
-static void C6X_pwmInit(unsigned long baseAddr)
+static int c6xdigio_chk_status(struct comedi_device *dev, unsigned long context)
{
+ unsigned int status;
int timeout = 0;
- WriteByteToHwPort(baseAddr, 0x70);
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0)
- && (timeout < C6XDIGIO_TIME_OUT)) {
+ do {
+ status = inb(dev->iobase + C6XDIGIO_STATUS_REG);
+ if ((status & 0x80) != context)
+ return 0;
timeout++;
- }
+ } while (timeout < C6XDIGIO_TIME_OUT);
- WriteByteToHwPort(baseAddr, 0x74);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
+ return -EBUSY;
+}
- WriteByteToHwPort(baseAddr, 0x70);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
+static int c6xdigio_write_data(struct comedi_device *dev,
+ unsigned int val, unsigned int status)
+{
+ outb_p(val, dev->iobase + C6XDIGIO_DATA_REG);
+ return c6xdigio_chk_status(dev, status);
+}
- WriteByteToHwPort(baseAddr, 0x0);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
+static int c6xdigio_get_encoder_bits(struct comedi_device *dev,
+ unsigned int *bits,
+ unsigned int cmd,
+ unsigned int status)
+{
+ unsigned int val;
+
+ val = inb(dev->iobase + C6XDIGIO_STATUS_REG);
+ val >>= 3;
+ val &= 0x07;
+
+ *bits = val;
+ return c6xdigio_write_data(dev, cmd, status);
}
-static void C6X_pwmOutput(unsigned long baseAddr, unsigned channel, int value)
+static void c6xdigio_pwm_write(struct comedi_device *dev,
+ unsigned int chan, unsigned int val)
{
- unsigned ppcmd;
- union pwmcmdtype pwm;
- int timeout = 0;
- unsigned tmp;
-
- pwm.cmd = value;
- if (pwm.cmd > 498)
- pwm.cmd = 498;
- if (pwm.cmd < 2)
- pwm.cmd = 2;
-
- if (channel == 0) {
- ppcmd = 0x28;
- } else { /* if channel == 1 */
- ppcmd = 0x30;
- } /* endif */
-
- WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb0);
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ unsigned int cmd = C6XDIGIO_DATA_PWM | C6XDIGIO_DATA_CHAN(chan);
+ unsigned int bits;
+
+ if (val > 498)
+ val = 498;
+ if (val < 2)
+ val = 2;
+
+ bits = (val >> 0) & 0x03;
+ c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00);
+ bits = (val >> 2) & 0x03;
+ c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80);
+ bits = (val >> 4) & 0x03;
+ c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00);
+ bits = (val >> 6) & 0x03;
+ c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80);
+ bits = (val >> 8) & 0x03;
+ c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00);
+
+ c6xdigio_write_data(dev, 0x00, 0x80);
+}
- WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb1 + 0x4);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+static int c6xdigio_encoder_read(struct comedi_device *dev,
+ unsigned int chan)
+{
+ unsigned int cmd = C6XDIGIO_DATA_ENCODER | C6XDIGIO_DATA_CHAN(chan);
+ unsigned int val = 0;
+ unsigned int bits;
- WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb2);
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ c6xdigio_write_data(dev, cmd, 0x00);
- WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb3 + 0x4);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80);
+ val |= (bits << 0);
- WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb4);
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
+ val |= (bits << 3);
- WriteByteToHwPort(baseAddr, 0x0);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80);
+ val |= (bits << 6);
-}
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
+ val |= (bits << 9);
-static int C6X_encInput(unsigned long baseAddr, unsigned channel)
-{
- unsigned ppcmd;
- union encvaluetype enc;
- int timeout = 0;
- int tmp;
-
- enc.value = 0;
- if (channel == 0)
- ppcmd = 0x48;
- else
- ppcmd = 0x50;
-
- WriteByteToHwPort(baseAddr, ppcmd);
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80);
+ val |= (bits << 12);
- enc.bits.sb0 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd + 0x4);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb1 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb2 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd + 0x4);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb3 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb4 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd + 0x4);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb5 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb6 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd + 0x4);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb7 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
+ val |= (bits << 15);
- WriteByteToHwPort(baseAddr, 0x0);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80);
+ val |= (bits << 18);
+
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
+ val |= (bits << 21);
+
+ c6xdigio_write_data(dev, 0x00, 0x80);
- return enc.value ^ 0x800000;
+ return val;
}
-static void C6X_encResetAll(unsigned long baseAddr)
+static int c6xdigio_pwm_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- unsigned timeout = 0;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = (s->state >> (16 * chan)) & 0xffff;
+ int i;
- WriteByteToHwPort(baseAddr, 0x68);
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
- WriteByteToHwPort(baseAddr, 0x6C);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
- WriteByteToHwPort(baseAddr, 0x68);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
- WriteByteToHwPort(baseAddr, 0x0);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+ c6xdigio_pwm_write(dev, chan, val);
}
+
+ /*
+ * There are only 2 PWM channels and they have a maxdata of 500.
+ * Instead of allocating private data to save the values in for
+ * readback this driver just packs the values for the two channels
+ * in the s->state.
+ */
+ s->state &= (0xffff << (16 * chan));
+ s->state |= (val << (16 * chan));
+
+ return insn->n;
}
-static int c6xdigio_pwmo_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int c6xdigio_pwm_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
int i;
- int chan = CR_CHAN(insn->chanspec);
- for (i = 0; i < insn->n; i++) {
- C6X_pwmOutput(dev->iobase, chan, data[i]);
- /* devpriv->ao_readback[chan] = data[i]; */
- }
- return i;
+ val = (s->state >> (16 * chan)) & 0xffff;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = val;
+
+ return insn->n;
}
-static int c6xdigio_ei_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int c6xdigio_encoder_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int n;
- int chan = CR_CHAN(insn->chanspec);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
+ int i;
- for (n = 0; n < insn->n; n++)
- data[n] = (C6X_encInput(dev->iobase, chan) & 0xffffff);
+ for (i = 0; i < insn->n; i++) {
+ val = c6xdigio_encoder_read(dev, chan);
+
+ /* munge two's complement value to offset binary */
+ data[i] = comedi_offset_munge(s, val);
+ }
- return n;
+ return insn->n;
}
-static void board_init(struct comedi_device *dev)
+static void c6xdigio_init(struct comedi_device *dev)
{
- C6X_pwmInit(dev->iobase);
- C6X_encResetAll(dev->iobase);
+ /* Initialize the PWM */
+ c6xdigio_write_data(dev, 0x70, 0x00);
+ c6xdigio_write_data(dev, 0x74, 0x80);
+ c6xdigio_write_data(dev, 0x70, 0x00);
+ c6xdigio_write_data(dev, 0x00, 0x80);
+
+ /* Reset the encoders */
+ c6xdigio_write_data(dev, 0x68, 0x00);
+ c6xdigio_write_data(dev, 0x6c, 0x80);
+ c6xdigio_write_data(dev, 0x68, 0x00);
+ c6xdigio_write_data(dev, 0x00, 0x80);
}
static const struct pnp_device_id c6xdigio_pnp_tbl[] = {
@@ -367,7 +251,7 @@ static int c6xdigio_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- ret = comedi_request_region(dev, it->options[0], C6XDIGIO_SIZE);
+ ret = comedi_request_region(dev, it->options[0], 0x03);
if (ret)
return ret;
@@ -380,27 +264,26 @@ static int c6xdigio_attach(struct comedi_device *dev,
s = &dev->subdevices[0];
/* pwm output subdevice */
- s->type = COMEDI_SUBD_AO; /* Not sure what to put here */
- s->subdev_flags = SDF_WRITEABLE;
- s->n_chan = 2;
- /* s->trig[0] = c6xdigio_pwmo; */
- s->insn_write = c6xdigio_pwmo_insn_write;
- s->maxdata = 500;
- s->range_table = &range_bipolar10; /* A suitable lie */
+ s->type = COMEDI_SUBD_PWM;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 2;
+ s->maxdata = 500;
+ s->range_table = &range_unknown;
+ s->insn_write = c6xdigio_pwm_insn_write;
+ s->insn_read = c6xdigio_pwm_insn_read;
s = &dev->subdevices[1];
/* encoder (counter) subdevice */
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
- s->n_chan = 2;
- /* s->trig[0] = c6xdigio_ei; */
- s->insn_read = c6xdigio_ei_insn_read;
- s->maxdata = 0xffffff;
- s->range_table = &range_unknown;
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
+ s->n_chan = 2;
+ s->maxdata = 0xffffff;
+ s->range_table = &range_unknown;
+ s->insn_read = c6xdigio_encoder_insn_read;
/* I will call this init anyway but more than likely the DSP board */
/* will not be connected when device driver is loaded. */
- board_init(dev);
+ c6xdigio_init(dev);
return 0;
}
@@ -420,5 +303,5 @@ static struct comedi_driver c6xdigio_driver = {
module_comedi_driver(c6xdigio_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for the C6x_DIGIO DSP daughter card");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index 64d5f291553f..645fcb0cf17d 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -95,10 +95,17 @@ static const struct comedi_lrange das16cs_ai_range = {
}
};
-static irqreturn_t das16cs_interrupt(int irq, void *d)
+static int das16cs_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- /* struct comedi_device *dev = d; */
- return IRQ_HANDLED;
+ unsigned int status;
+
+ status = inw(dev->iobase + DAS16CS_MISC1);
+ if (status & 0x0080)
+ return 0;
+ return -EBUSY;
}
static int das16cs_ai_rinsn(struct comedi_device *dev,
@@ -109,8 +116,8 @@ static int das16cs_ai_rinsn(struct comedi_device *dev,
int chan = CR_CHAN(insn->chanspec);
int range = CR_RANGE(insn->chanspec);
int aref = CR_AREF(insn->chanspec);
+ int ret;
int i;
- int to;
outw(chan, dev->iobase + DAS16CS_DIO_MUX);
@@ -138,132 +145,16 @@ static int das16cs_ai_rinsn(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
outw(0, dev->iobase + DAS16CS_ADC_DATA);
-#define TIMEOUT 1000
- for (to = 0; to < TIMEOUT; to++) {
- if (inw(dev->iobase + DAS16CS_MISC1) & 0x0080)
- break;
- }
- if (to == TIMEOUT) {
- dev_dbg(dev->class_dev, "cb_das16_cs: ai timeout\n");
- return -ETIME;
- }
+ ret = comedi_timeout(dev, s, insn, das16cs_ai_eoc, 0);
+ if (ret)
+ return ret;
+
data[i] = inw(dev->iobase + DAS16CS_ADC_DATA);
}
return i;
}
-static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- return -EINVAL;
-}
-
-static int das16cs_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
-{
- int err = 0;
- int tmp;
-
- /* Step 1 : check if triggers are trivially valid */
-
- err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
- err |= cfc_check_trigger_src(&cmd->scan_begin_src,
- TRIG_TIMER | TRIG_EXT);
- err |= cfc_check_trigger_src(&cmd->convert_src,
- TRIG_TIMER | TRIG_EXT);
- err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
- err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
-
- if (err)
- return 1;
-
- /* Step 2a : make sure trigger sources are unique */
-
- err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
- err |= cfc_check_trigger_is_unique(cmd->convert_src);
- err |= cfc_check_trigger_is_unique(cmd->stop_src);
-
- /* Step 2b : and mutually compatible */
-
- if (err)
- return 2;
-
- /* Step 3: check if arguments are trivially valid */
-
- err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
-
-#define MAX_SPEED 10000 /* in nanoseconds */
-#define MIN_SPEED 1000000000 /* in nanoseconds */
-
- if (cmd->scan_begin_src == TRIG_TIMER) {
- err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
- MAX_SPEED);
- err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
- MIN_SPEED);
- } else {
- /* external trigger */
- /* should be level/edge, hi/lo specification here */
- /* should specify multiple external triggers */
- err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9);
- }
- if (cmd->convert_src == TRIG_TIMER) {
- err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
- MAX_SPEED);
- err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
- MIN_SPEED);
- } else {
- /* external trigger */
- /* see above */
- err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 9);
- }
-
- err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
-
- if (cmd->stop_src == TRIG_COUNT)
- err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
- else /* TRIG_NONE */
- err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
-
- if (err)
- return 3;
-
- /* step 4: fix up any arguments */
-
- if (cmd->scan_begin_src == TRIG_TIMER) {
- unsigned int div1 = 0, div2 = 0;
-
- tmp = cmd->scan_begin_arg;
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
- &div1, &div2,
- &cmd->scan_begin_arg, cmd->flags);
- if (tmp != cmd->scan_begin_arg)
- err++;
- }
- if (cmd->convert_src == TRIG_TIMER) {
- unsigned int div1 = 0, div2 = 0;
-
- tmp = cmd->convert_arg;
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
- &div1, &div2,
- &cmd->scan_begin_arg, cmd->flags);
- if (tmp != cmd->convert_arg)
- err++;
- if (cmd->scan_begin_src == TRIG_TIMER &&
- cmd->scan_begin_arg <
- cmd->convert_arg * cmd->scan_end_arg) {
- cmd->scan_begin_arg =
- cmd->convert_arg * cmd->scan_end_arg;
- err++;
- }
- }
-
- if (err)
- return 4;
-
- return 0;
-}
-
static int das16cs_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -401,10 +292,6 @@ static int das16cs_auto_attach(struct comedi_device *dev,
dev->iobase = link->resource[0]->start;
link->priv = dev;
- ret = pcmcia_request_irq(link, das16cs_interrupt);
- if (ret)
- return ret;
- dev->irq = link->irq;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
@@ -415,7 +302,6 @@ static int das16cs_auto_attach(struct comedi_device *dev,
return ret;
s = &dev->subdevices[0];
- dev->read_subdev = s;
/* analog input subdevice */
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
@@ -424,8 +310,6 @@ static int das16cs_auto_attach(struct comedi_device *dev,
s->range_table = &das16cs_ai_range;
s->len_chanlist = 16;
s->insn_read = das16cs_ai_rinsn;
- s->do_cmd = das16cs_ai_cmd;
- s->do_cmdtest = das16cs_ai_cmdtest;
s = &dev->subdevices[1];
/* analog output subdevice */
@@ -451,10 +335,6 @@ static int das16cs_auto_attach(struct comedi_device *dev,
s->insn_bits = das16cs_dio_insn_bits;
s->insn_config = das16cs_dio_insn_config;
- dev_info(dev->class_dev, "%s: %s, I/O base=0x%04lx, irq=%u\n",
- dev->driver->driver_name, dev->board_name,
- dev->iobase, dev->irq);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index 9819be092f8d..83a265f3408c 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -376,6 +376,20 @@ static inline unsigned int cal_enable_bits(struct comedi_device *dev)
return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source);
}
+static int cb_pcidas_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct cb_pcidas_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = inw(devpriv->control_status + ADCMUX_CONT);
+ if (status & EOC)
+ return 0;
+ return -EBUSY;
+}
+
static int cb_pcidas_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -385,7 +399,8 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev,
unsigned int range = CR_RANGE(insn->chanspec);
unsigned int aref = CR_AREF(insn->chanspec);
unsigned int bits;
- int n, i;
+ int ret;
+ int n;
/* enable calibration input if appropriate */
if (insn->chanspec & CR_ALT_SOURCE) {
@@ -415,13 +430,9 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev,
outw(0, devpriv->adc_fifo + ADCDATA);
/* wait for conversion to end */
- /* return -ETIMEDOUT if there is a timeout */
- for (i = 0; i < 10000; i++) {
- if (inw(devpriv->control_status + ADCMUX_CONT) & EOC)
- break;
- }
- if (i == 10000)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, cb_pcidas_ai_eoc, 0);
+ if (ret)
+ return ret;
/* read data */
data[n] = inw(devpriv->adc_fifo + ADCDATA);
@@ -1006,9 +1017,9 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev,
/* set start trigger and burst mode */
bits = 0;
- if (cmd->start_src == TRIG_NOW)
+ if (cmd->start_src == TRIG_NOW) {
bits |= SW_TRIGGER;
- else if (cmd->start_src == TRIG_EXT) {
+ } else { /* TRIG_EXT */
bits |= EXT_TRIGGER | TGEN | XTRCL;
if (thisboard->is_1602) {
if (cmd->start_arg & CR_INVERT)
@@ -1016,9 +1027,6 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev,
if (cmd->start_arg & CR_EDGE)
bits |= TGSEL;
}
- } else {
- comedi_error(dev, "bug!");
- return -1;
}
if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1)
bits |= BURSTE;
@@ -1269,8 +1277,6 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
unsigned int num_points;
unsigned long flags;
- async->events = 0;
-
if (status & DAEMI) {
/* clear dac empty interrupt latch */
spin_lock_irqsave(&dev->spinlock, flags);
@@ -1282,7 +1288,6 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
(cmd->stop_src == TRIG_COUNT
&& devpriv->ao_count)) {
comedi_error(dev, "dac fifo underflow");
- cb_pcidas_ao_cancel(dev, s);
async->events |= COMEDI_CB_ERROR;
}
async->events |= COMEDI_CB_EOA;
@@ -1312,7 +1317,7 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
spin_unlock_irqrestore(&dev->spinlock, flags);
}
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
@@ -1332,7 +1337,6 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
return IRQ_NONE;
async = s->async;
- async->events = 0;
s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR);
@@ -1364,10 +1368,8 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
cfc_write_array_to_buffer(s, devpriv->ai_buffer,
num_samples * sizeof(short));
devpriv->count -= num_samples;
- if (async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0) {
+ if (async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0)
async->events |= COMEDI_CB_EOA;
- cb_pcidas_cancel(dev, s);
- }
/* clear half-full interrupt latch */
spin_lock_irqsave(&dev->spinlock, flags);
outw(devpriv->adc_fifo_bits | INT,
@@ -1384,7 +1386,6 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
if (async->cmd.stop_src == TRIG_COUNT &&
--devpriv->count == 0) {
/* end of acquisition */
- cb_pcidas_cancel(dev, s);
async->events |= COMEDI_CB_EOA;
break;
}
@@ -1411,11 +1412,10 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
outw(devpriv->adc_fifo_bits | LADFUL,
devpriv->control_status + INT_ADCFIFO);
spin_unlock_irqrestore(&dev->spinlock, flags);
- cb_pcidas_cancel(dev, s);
async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
}
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
@@ -1576,9 +1576,6 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
devpriv->s5933_config + AMCC_OP_REG_INTCSR);
- dev_info(dev->class_dev, "%s: %s attached\n",
- dev->driver->driver_name, dev->board_name);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index 4fff1738e3f8..f9afcbe1da54 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -1664,15 +1664,36 @@ static void i2c_write(struct comedi_device *dev, unsigned int address,
i2c_stop(dev);
}
+static int cb_pcidas64_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readw(devpriv->main_iobase + HW_STATUS_REG);
+ if (thisboard->layout == LAYOUT_4020) {
+ status = readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG);
+ if (status)
+ return 0;
+ } else {
+ if (pipe_full_bits(status))
+ return 0;
+ }
+ return -EBUSY;
+}
+
static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
const struct pcidas64_board *thisboard = comedi_board(dev);
struct pcidas64_private *devpriv = dev->private;
- unsigned int bits = 0, n, i;
+ unsigned int bits = 0, n;
unsigned int channel, range, aref;
unsigned long flags;
- static const int timeout = 100;
+ int ret;
channel = CR_CHAN(insn->chanspec);
range = CR_RANGE(insn->chanspec);
@@ -1770,23 +1791,10 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
devpriv->main_iobase + ADC_CONVERT_REG);
/* wait for data */
- for (i = 0; i < timeout; i++) {
- bits = readw(devpriv->main_iobase + HW_STATUS_REG);
- if (thisboard->layout == LAYOUT_4020) {
- if (readw(devpriv->main_iobase +
- ADC_WRITE_PNTR_REG))
- break;
- } else {
- if (pipe_full_bits(bits))
- break;
- }
- udelay(1);
- }
- if (i == timeout) {
- comedi_error(dev, " analog input read insn timed out");
- dev_info(dev->class_dev, "status 0x%x\n", bits);
- return -ETIME;
- }
+ ret = comedi_timeout(dev, s, insn, cb_pcidas64_ai_eoc, 0);
+ if (ret)
+ return ret;
+
if (thisboard->layout == LAYOUT_4020)
data[n] = readl(devpriv->dio_counter_iobase +
ADC_FIFO_REG) & 0xffff;
@@ -3816,16 +3824,19 @@ static int setup_subdevices(struct comedi_device *dev)
if (thisboard->has_8255) {
if (thisboard->layout == LAYOUT_4020) {
dio_8255_iobase = devpriv->main_iobase + I8255_4020_REG;
- subdev_8255_init(dev, s, dio_callback_4020,
- (unsigned long)dio_8255_iobase);
+ ret = subdev_8255_init(dev, s, dio_callback_4020,
+ (unsigned long)dio_8255_iobase);
} else {
dio_8255_iobase =
devpriv->dio_counter_iobase + DIO_8255_OFFSET;
- subdev_8255_init(dev, s, dio_callback,
- (unsigned long)dio_8255_iobase);
+ ret = subdev_8255_init(dev, s, dio_callback,
+ (unsigned long)dio_8255_iobase);
}
- } else
+ if (ret)
+ return ret;
+ } else {
s->type = COMEDI_SUBD_UNUSED;
+ }
/* 8 channel dio for 60xx */
s = &dev->subdevices[5];
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index 8cca0518cfda..901dc5d1bb72 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -388,8 +388,6 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev,
for (i = 0; i < thisboard->ao_chans; i++)
cb_pcidda_calibrate(dev, i, devpriv->ao_range[i]);
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index 57295d189ff6..d3141c865fe7 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -85,21 +85,31 @@ struct cb_pcimdas_private {
unsigned int ao_readback[2];
};
-/*
- * "instructions" read/write data in "one-shot" or "software-triggered"
- * mode.
- */
+static int cb_pcimdas_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct cb_pcimdas_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = inb(devpriv->BADR3 + 2);
+ if ((status & 0x80) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct cb_pcimdas_private *devpriv = dev->private;
- int n, i;
+ int n;
unsigned int d;
- unsigned int busy;
int chan = CR_CHAN(insn->chanspec);
unsigned short chanlims;
int maxchans;
+ int ret;
/* only support sw initiated reads from a single channel */
@@ -133,17 +143,10 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
/* trigger conversion */
outw(0, dev->iobase + 0);
-#define TIMEOUT 1000 /* typically takes 5 loops on a lightly loaded Pentium 100MHz, */
- /* this is likely to be 100 loops on a 2GHz machine, so set 1000 as the limit. */
-
/* wait for conversion to end */
- for (i = 0; i < TIMEOUT; i++) {
- busy = inb(devpriv->BADR3 + 2) & 0x80;
- if (!busy)
- break;
- }
- if (i == TIMEOUT)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, cb_pcimdas_ai_eoc, 0);
+ if (ret)
+ return ret;
/* read data */
data[n] = inw(dev->iobase + 0);
@@ -247,9 +250,9 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev,
s = &dev->subdevices[2];
/* digital i/o subdevice */
- subdev_8255_init(dev, s, NULL, iobase_8255);
-
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
+ ret = subdev_8255_init(dev, s, NULL, iobase_8255);
+ if (ret)
+ return ret;
return 0;
}
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index 43a86630a66e..4a2b200de01b 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdda.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdda.c
@@ -187,9 +187,7 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
- return 1;
+ return 0;
}
static struct comedi_driver cb_pcimdda_driver = {
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index 51a59e5b8ec5..8450c99af8b0 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -211,7 +211,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it)
return -EINVAL;
}
- snprintf(file, sizeof(file), "/dev/comedi%u", minor);
+ snprintf(file, sizeof(file), "/dev/comedi%d", minor);
file[sizeof(file) - 1] = 0;
d = comedi_open(file);
@@ -254,6 +254,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it)
if (!devs) {
dev_err(dev->class_dev,
"Could not allocate memory. Out of memory?\n");
+ kfree(bdev);
return -ENOMEM;
}
devpriv->devs = devs;
@@ -263,7 +264,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it)
char buf[20];
int left =
MAX_BOARD_NAME - strlen(devpriv->name) - 1;
- snprintf(buf, sizeof(buf), "%d:%d ",
+ snprintf(buf, sizeof(buf), "%u:%u ",
bdev->minor, bdev->subdev);
buf[sizeof(buf) - 1] = 0;
strncat(devpriv->name, buf, left);
diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c
index 26d9dbcf8bd4..9d9b1469e89a 100644
--- a/drivers/staging/comedi/drivers/comedi_fc.c
+++ b/drivers/staging/comedi/drivers/comedi_fc.c
@@ -1,34 +1,53 @@
/*
- comedi/drivers/comedi_fc.c
-
- This is a place for code driver writers wish to share between
- two or more drivers. fc is short
- for frank-common.
-
- Author: Frank Mori Hess <fmhess@users.sourceforge.net>
- Copyright (C) 2002 Frank Mori Hess
-
- This program is free software; 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.
-*/
+ * comedi_fc.c
+ * This is a place for code driver writers wish to share between
+ * two or more drivers. fc is short for frank-common.
+ *
+ * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Copyright (C) 2002 Frank Mori Hess
+ *
+ * This program is free software; 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/module.h>
#include "../comedidev.h"
#include "comedi_fc.h"
-static void increment_scan_progress(struct comedi_subdevice *subd,
- unsigned int num_bytes)
+unsigned int cfc_bytes_per_scan(struct comedi_subdevice *s)
+{
+ unsigned int chanlist_len = s->async->cmd.chanlist_len;
+ unsigned int num_samples;
+ unsigned int bits_per_sample;
+
+ switch (s->type) {
+ case COMEDI_SUBD_DI:
+ case COMEDI_SUBD_DO:
+ case COMEDI_SUBD_DIO:
+ bits_per_sample = 8 * bytes_per_sample(s);
+ num_samples = (chanlist_len + bits_per_sample - 1) /
+ bits_per_sample;
+ break;
+ default:
+ num_samples = chanlist_len;
+ break;
+ }
+ return num_samples * bytes_per_sample(s);
+}
+EXPORT_SYMBOL_GPL(cfc_bytes_per_scan);
+
+void cfc_inc_scan_progress(struct comedi_subdevice *s, unsigned int num_bytes)
{
- struct comedi_async *async = subd->async;
- unsigned int scan_length = cfc_bytes_per_scan(subd);
+ struct comedi_async *async = s->async;
+ unsigned int scan_length = cfc_bytes_per_scan(s);
async->scan_progress += num_bytes;
if (async->scan_progress >= scan_length) {
@@ -36,12 +55,13 @@ static void increment_scan_progress(struct comedi_subdevice *subd,
async->events |= COMEDI_CB_EOS;
}
}
+EXPORT_SYMBOL_GPL(cfc_inc_scan_progress);
/* Writes an array of data points to comedi's buffer */
-unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd,
+unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *s,
void *data, unsigned int num_bytes)
{
- struct comedi_async *async = subd->async;
+ struct comedi_async *async = s->async;
unsigned int retval;
if (num_bytes == 0)
@@ -49,24 +69,24 @@ unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd,
retval = comedi_buf_write_alloc(async, num_bytes);
if (retval != num_bytes) {
- dev_warn(subd->device->class_dev, "comedi: buffer overrun\n");
+ dev_warn(s->device->class_dev, "buffer overrun\n");
async->events |= COMEDI_CB_OVERFLOW;
return 0;
}
comedi_buf_memcpy_to(async, 0, data, num_bytes);
comedi_buf_write_free(async, num_bytes);
- increment_scan_progress(subd, num_bytes);
+ cfc_inc_scan_progress(s, num_bytes);
async->events |= COMEDI_CB_BLOCK;
return num_bytes;
}
EXPORT_SYMBOL_GPL(cfc_write_array_to_buffer);
-unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd,
+unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *s,
void *data, unsigned int num_bytes)
{
- struct comedi_async *async = subd->async;
+ struct comedi_async *async = s->async;
if (num_bytes == 0)
return 0;
@@ -74,7 +94,7 @@ unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd,
num_bytes = comedi_buf_read_alloc(async, num_bytes);
comedi_buf_memcpy_from(async, 0, data, num_bytes);
comedi_buf_read_free(async, num_bytes);
- increment_scan_progress(subd, num_bytes);
+ cfc_inc_scan_progress(s, num_bytes);
async->events |= COMEDI_CB_BLOCK;
return num_bytes;
@@ -82,34 +102,33 @@ unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd,
EXPORT_SYMBOL_GPL(cfc_read_array_from_buffer);
unsigned int cfc_handle_events(struct comedi_device *dev,
- struct comedi_subdevice *subd)
+ struct comedi_subdevice *s)
{
- unsigned int events = subd->async->events;
+ unsigned int events = s->async->events;
if (events == 0)
return events;
if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW))
- subd->cancel(dev, subd);
+ s->cancel(dev, s);
- comedi_event(dev, subd);
+ comedi_event(dev, s);
return events;
}
EXPORT_SYMBOL_GPL(cfc_handle_events);
-MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>");
-MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers");
-MODULE_LICENSE("GPL");
-
static int __init comedi_fc_init_module(void)
{
return 0;
}
+module_init(comedi_fc_init_module);
static void __exit comedi_fc_cleanup_module(void)
{
}
-
-module_init(comedi_fc_init_module);
module_exit(comedi_fc_cleanup_module);
+
+MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>");
+MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_fc.h b/drivers/staging/comedi/drivers/comedi_fc.h
index 8558b07f8df3..541b9371d3da 100644
--- a/drivers/staging/comedi/drivers/comedi_fc.h
+++ b/drivers/staging/comedi/drivers/comedi_fc.h
@@ -1,72 +1,52 @@
/*
- comedi_fc.h
-
- This is a place for code driver writers wish to share between
- two or more drivers. These functions are meant to be used only
- by drivers, they are NOT part of the kcomedilib API!
-
- Author: Frank Mori Hess <fmhess@users.sourceforge.net>
- Copyright (C) 2002 Frank Mori Hess
-
- This program is free software; 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.
-*/
+ * comedi_fc.h
+ * This is a place for code driver writers wish to share between
+ * two or more drivers. These functions are meant to be used only
+ * by drivers, they are NOT part of the kcomedilib API!
+ *
+ * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Copyright (C) 2002 Frank Mori Hess
+ *
+ * This program is free software; 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.
+ */
#ifndef _COMEDI_FC_H
#define _COMEDI_FC_H
#include "../comedidev.h"
+unsigned int cfc_bytes_per_scan(struct comedi_subdevice *);
+void cfc_inc_scan_progress(struct comedi_subdevice *, unsigned int num_bytes);
+
/* Writes an array of data points to comedi's buffer */
-extern unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd,
- void *data,
- unsigned int num_bytes);
+unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *,
+ void *data, unsigned int num_bytes);
-static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *subd,
+static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *s,
unsigned short data)
{
- return cfc_write_array_to_buffer(subd, &data, sizeof(data));
+ return cfc_write_array_to_buffer(s, &data, sizeof(data));
};
-static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice
- *subd, unsigned int data)
+static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice *s,
+ unsigned int data)
{
- return cfc_write_array_to_buffer(subd, &data, sizeof(data));
+ return cfc_write_array_to_buffer(s, &data, sizeof(data));
};
-extern unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd,
- void *data,
- unsigned int num_bytes);
+unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *,
+ void *data, unsigned int num_bytes);
-extern unsigned int cfc_handle_events(struct comedi_device *dev,
- struct comedi_subdevice *subd);
-
-static inline unsigned int cfc_bytes_per_scan(struct comedi_subdevice *subd)
-{
- int num_samples;
- int bits_per_sample;
-
- switch (subd->type) {
- case COMEDI_SUBD_DI:
- case COMEDI_SUBD_DO:
- case COMEDI_SUBD_DIO:
- bits_per_sample = 8 * bytes_per_sample(subd);
- num_samples = (subd->async->cmd.chanlist_len +
- bits_per_sample - 1) / bits_per_sample;
- break;
- default:
- num_samples = subd->async->cmd.chanlist_len;
- break;
- }
- return num_samples * bytes_per_sample(subd);
-}
+unsigned int cfc_handle_events(struct comedi_device *,
+ struct comedi_subdevice *);
/**
* cfc_check_trigger_src() - trivially validate a comedi_cmd trigger source
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c
index d539eaf53b63..cd9562556d2c 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -185,7 +185,6 @@ static void waveform_ai_interrupt(unsigned long arg)
(devpriv->usec_remainder + elapsed_time) / devpriv->scan_period;
devpriv->usec_remainder =
(devpriv->usec_remainder + elapsed_time) % devpriv->scan_period;
- async->events = 0;
if (cmd->stop_src == TRIG_COUNT) {
unsigned int remaining = cmd->stop_arg - devpriv->ai_count;
@@ -318,12 +317,8 @@ static int waveform_ai_cmd(struct comedi_device *dev,
if (cmd->convert_src == TRIG_NOW)
devpriv->convert_period = 0;
- else if (cmd->convert_src == TRIG_TIMER)
+ else /* TRIG_TIMER */
devpriv->convert_period = cmd->convert_arg / nano_per_micro;
- else {
- comedi_error(dev, "bug setting conversion period");
- return -1;
- }
do_gettimeofday(&devpriv->last);
devpriv->usec_current = devpriv->last.tv_usec % devpriv->usec_period;
diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c
index 323a7f39cd97..0a9c32e9db4a 100644
--- a/drivers/staging/comedi/drivers/contec_pci_dio.c
+++ b/drivers/staging/comedi/drivers/contec_pci_dio.c
@@ -92,8 +92,6 @@ static int contec_auto_attach(struct comedi_device *dev,
s->range_table = &range_digital;
s->insn_bits = contec_do_insn_bits;
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c
new file mode 100644
index 000000000000..df46e0a5bade
--- /dev/null
+++ b/drivers/staging/comedi/drivers/dac02.c
@@ -0,0 +1,172 @@
+/*
+ * dac02.c
+ * Comedi driver for DAC02 compatible boards
+ * Copyright (C) 2014 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *
+ * Based on the poc driver
+ * Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Copyright (C) 2001 David A. Schleef <ds@schleef.org>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1998 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Driver: dac02
+ * Description: Comedi driver for DAC02 compatible boards
+ * Devices: (Keithley Metrabyte) DAC-02 [dac02]
+ * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
+ * Updated: Tue, 11 Mar 2014 11:27:19 -0700
+ * Status: unknown
+ *
+ * Configuration options:
+ * [0] - I/O port base
+ */
+
+#include <linux/module.h>
+
+#include "../comedidev.h"
+
+/*
+ * The output range is selected by jumpering pins on the I/O connector.
+ *
+ * Range Chan # Jumper pins Output
+ * ------------- ------ ------------- -----------------
+ * 0 to 5V 0 21 to 22 24
+ * 1 15 to 16 18
+ * 0 to 10V 0 20 to 22 24
+ * 1 14 to 16 18
+ * +/-5V 0 21 to 22 23
+ * 1 15 to 16 17
+ * +/-10V 0 20 to 22 23
+ * 1 14 to 16 17
+ * 4 to 20mA 0 21 to 22 25
+ * 1 15 to 16 19
+ * AC reference 0 In on pin 22 24 (2-quadrant)
+ * In on pin 22 23 (4-quadrant)
+ * 1 In on pin 16 18 (2-quadrant)
+ * In on pin 16 17 (4-quadrant)
+ */
+static const struct comedi_lrange das02_ao_ranges = {
+ 6, {
+ UNI_RANGE(5),
+ UNI_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ RANGE_mA(4, 20),
+ RANGE_ext(0, 1)
+ }
+};
+
+struct dac02_private {
+ unsigned int ao_readback[2];
+};
+
+/*
+ * Register I/O map
+ */
+#define DAC02_AO_LSB(x) (0x00 + ((x) * 2))
+#define DAC02_AO_MSB(x) (0x01 + ((x) * 2))
+
+static int dac02_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct dac02_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int val;
+ int i;
+
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+
+ devpriv->ao_readback[chan] = val;
+
+ /*
+ * Unipolar outputs are true binary encoding.
+ * Bipolar outputs are complementary offset binary
+ * (that is, 0 = +full scale, maxdata = -full scale).
+ */
+ if (comedi_range_is_bipolar(s, range))
+ val = s->maxdata - val;
+
+ /*
+ * DACs are double-buffered.
+ * Write LSB then MSB to latch output.
+ */
+ outb((val << 4) & 0xf0, dev->iobase + DAC02_AO_LSB(chan));
+ outb((val >> 4) & 0xff, dev->iobase + DAC02_AO_MSB(chan));
+ }
+
+ return insn->n;
+}
+
+static int dac02_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct dac02_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
+
+ return insn->n;
+}
+
+static int dac02_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct dac02_private *devpriv;
+ struct comedi_subdevice *s;
+ int ret;
+
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+ if (!devpriv)
+ return -ENOMEM;
+
+ ret = comedi_request_region(dev, it->options[0], 0x08);
+ if (ret)
+ return ret;
+
+ ret = comedi_alloc_subdevices(dev, 1);
+ if (ret)
+ return ret;
+
+ /* Analog Output subdevice */
+ s = &dev->subdevices[0];
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 2;
+ s->maxdata = 0x0fff;
+ s->range_table = &das02_ao_ranges;
+ s->insn_write = dac02_ao_insn_write;
+ s->insn_read = dac02_ao_insn_read;
+
+ return 0;
+}
+
+static struct comedi_driver dac02_driver = {
+ .driver_name = "dac02",
+ .module = THIS_MODULE,
+ .attach = dac02_attach,
+ .detach = comedi_legacy_detach,
+};
+module_comedi_driver(dac02_driver);
+
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_DESCRIPTION("Comedi driver for DAC02 compatible boards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index ce153fcb8b2a..a8f6036ad82b 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -333,14 +333,28 @@ static void setup_sampling(struct comedi_device *dev, int chan, int gain)
writeAcqScanListEntry(dev, word3);
}
+static int daqboard2000_ai_status(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct daqboard2000_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readw(devpriv->daq + acqControl);
+ if (status & context)
+ return 0;
+ return -EBUSY;
+}
+
static int daqboard2000_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
struct daqboard2000_private *devpriv = dev->private;
- unsigned int val;
- int gain, chan, timeout;
+ int gain, chan;
+ int ret;
int i;
writew(DAQBOARD2000_AcqResetScanListFifo |
@@ -367,25 +381,24 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev,
/* Enable reading from the scanlist FIFO */
writew(DAQBOARD2000_SeqStartScanList,
devpriv->daq + acqControl);
- for (timeout = 0; timeout < 20; timeout++) {
- val = readw(devpriv->daq + acqControl);
- if (val & DAQBOARD2000_AcqConfigPipeFull)
- break;
- /* udelay(2); */
- }
+
+ ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status,
+ DAQBOARD2000_AcqConfigPipeFull);
+ if (ret)
+ return ret;
+
writew(DAQBOARD2000_AdcPacerEnable, devpriv->daq + acqControl);
- for (timeout = 0; timeout < 20; timeout++) {
- val = readw(devpriv->daq + acqControl);
- if (val & DAQBOARD2000_AcqLogicScanning)
- break;
- /* udelay(2); */
- }
- for (timeout = 0; timeout < 20; timeout++) {
- val = readw(devpriv->daq + acqControl);
- if (val & DAQBOARD2000_AcqResultsFIFOHasValidData)
- break;
- /* udelay(2); */
- }
+
+ ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status,
+ DAQBOARD2000_AcqLogicScanning);
+ if (ret)
+ return ret;
+
+ ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status,
+ DAQBOARD2000_AcqResultsFIFOHasValidData);
+ if (ret)
+ return ret;
+
data[i] = readw(devpriv->daq + acqResultsFIFO);
writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl);
writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl);
@@ -409,6 +422,21 @@ static int daqboard2000_ao_insn_read(struct comedi_device *dev,
return i;
}
+static int daqboard2000_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct daqboard2000_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int status;
+
+ status = readw(devpriv->daq + dacControl);
+ if ((status & ((chan + 1) * 0x0010)) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int daqboard2000_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -416,8 +444,7 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev,
{
struct daqboard2000_private *devpriv = dev->private;
int chan = CR_CHAN(insn->chanspec);
- unsigned int val;
- int timeout;
+ int ret;
int i;
for (i = 0; i < insn->n; i++) {
@@ -431,12 +458,11 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev,
udelay(1000);
#endif
writew(data[i], devpriv->daq + dacSetting(chan));
- for (timeout = 0; timeout < 20; timeout++) {
- val = readw(devpriv->daq + dacControl);
- if ((val & ((chan + 1) * 0x0010)) == 0)
- break;
- /* udelay(2); */
- }
+
+ ret = comedi_timeout(dev, s, insn, daqboard2000_ao_eoc, 0);
+ if (ret)
+ return ret;
+
devpriv->ao_readback[chan] = data[i];
#if 0
/*
@@ -737,9 +763,6 @@ static int daqboard2000_auto_attach(struct comedi_device *dev,
if (result)
return result;
- dev_info(dev->class_dev, "%s: %s attached\n",
- dev->driver->driver_name, dev->board_name);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index e5c0ee9a09c2..c5e352fb5555 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -201,17 +201,29 @@ static const int *const das08_gainlists[] = {
das08_pgm_gainlist,
};
-#define TIMEOUT 100000
+static int das08_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + DAS08_STATUS);
+ if ((status & DAS08_EOC) == 0)
+ return 0;
+ return -EBUSY;
+}
static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
const struct das08_board_struct *thisboard = comedi_board(dev);
struct das08_private_struct *devpriv = dev->private;
- int i, n;
+ int n;
int chan;
int range;
int lsb, msb;
+ int ret;
chan = CR_CHAN(insn->chanspec);
range = CR_RANGE(insn->chanspec);
@@ -244,14 +256,10 @@ static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
/* trigger conversion */
outb_p(0, dev->iobase + DAS08_TRIG_12BIT);
- for (i = 0; i < TIMEOUT; i++) {
- if (!(inb(dev->iobase + DAS08_STATUS) & DAS08_EOC))
- break;
- }
- if (i == TIMEOUT) {
- dev_err(dev->class_dev, "timeout\n");
- return -ETIME;
- }
+ ret = comedi_timeout(dev, s, insn, das08_ai_eoc, 0);
+ if (ret)
+ return ret;
+
msb = inb(dev->iobase + DAS08_MSB);
lsb = inb(dev->iobase + DAS08_LSB);
if (thisboard->ai_encoding == das08_encode12) {
@@ -529,9 +537,10 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
s = &dev->subdevices[4];
/* 8255 */
if (thisboard->i8255_offset != 0) {
- subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase +
- thisboard->
- i8255_offset));
+ ret = subdev_8255_init(dev, s, NULL,
+ dev->iobase + thisboard->i8255_offset);
+ if (ret)
+ return ret;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index a8446ca04110..6a7d652ff564 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -856,18 +856,17 @@ static void das16_ai_munge(struct comedi_device *dev,
}
}
-static int das16_ai_wait_for_conv(struct comedi_device *dev,
- unsigned int timeout)
+static int das16_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
unsigned int status;
- int i;
- for (i = 0; i < timeout; i++) {
- status = inb(dev->iobase + DAS16_STATUS_REG);
- if (!(status & DAS16_STATUS_BUSY))
- return 0;
- }
- return -ETIME;
+ status = inb(dev->iobase + DAS16_STATUS_REG);
+ if ((status & DAS16_STATUS_BUSY) == 0)
+ return 0;
+ return -EBUSY;
}
static int das16_ai_insn_read(struct comedi_device *dev,
@@ -897,7 +896,7 @@ static int das16_ai_insn_read(struct comedi_device *dev,
/* trigger conversion */
outb_p(0, dev->iobase + DAS16_TRIG_REG);
- ret = das16_ai_wait_for_conv(dev, 1000);
+ ret = comedi_timeout(dev, s, insn, das16_ai_eoc, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index fee5facff8dd..779225831dc0 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -331,14 +331,27 @@ static int das16m1_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
+static int das16m1_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + DAS16M1_CS);
+ if (status & IRQDATA)
+ return 0;
+ return -EBUSY;
+}
+
static int das16m1_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct das16m1_private_struct *devpriv = dev->private;
- int i, n;
+ int ret;
+ int n;
int byte;
- const int timeout = 1000;
/* disable interrupts and internal pacer */
devpriv->control_state &= ~INTE & ~PACER_MASK;
@@ -356,14 +369,10 @@ static int das16m1_ai_rinsn(struct comedi_device *dev,
/* trigger conversion */
outb(0, dev->iobase);
- for (i = 0; i < timeout; i++) {
- if (inb(dev->iobase + DAS16M1_CS) & IRQDATA)
- break;
- }
- if (i == timeout) {
- comedi_error(dev, "timeout");
- return -ETIME;
- }
+ ret = comedi_timeout(dev, s, insn, das16m1_ai_eoc, 0);
+ if (ret)
+ return ret;
+
data[n] = munge_sample(inw(dev->iobase));
}
@@ -407,7 +416,6 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status)
s = dev->read_subdev;
async = s->async;
- async->events = 0;
cmd = &async->cmd;
/* figure out how many samples are in fifo */
@@ -440,8 +448,8 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status)
devpriv->adc_count += num_samples;
if (cmd->stop_src == TRIG_COUNT) {
- if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) { /* end of acquisition */
- das16m1_cancel(dev, s);
+ if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) {
+ /* end of acquisition */
async->events |= COMEDI_CB_EOA;
}
}
@@ -449,13 +457,11 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status)
/* this probably won't catch overruns since the card doesn't generate
* overrun interrupts, but we might as well try */
if (status & OVRUN) {
- das16m1_cancel(dev, s);
async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
comedi_error(dev, "fifo overflow");
}
- comedi_event(dev, s);
-
+ cfc_handle_events(dev, s);
}
static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s)
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index 320d95a5f47b..8e975d6b06db 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -646,7 +646,6 @@ static void das1800_ai_handler(struct comedi_device *dev)
struct comedi_cmd *cmd = &async->cmd;
unsigned int status = inb(dev->iobase + DAS1800_STATUS);
- async->events = 0;
/* select adc for base address + 0 */
outb(ADC, dev->iobase + DAS1800_SELECT);
/* dma buffer full */
@@ -665,9 +664,8 @@ static void das1800_ai_handler(struct comedi_device *dev)
/* clear OVF interrupt bit */
outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS);
comedi_error(dev, "DAS1800 FIFO overflow");
- das1800_cancel(dev, s);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
/* stop taking data if appropriate */
@@ -680,16 +678,12 @@ static void das1800_ai_handler(struct comedi_device *dev)
das1800_flush_dma(dev, s);
else
das1800_handle_fifo_not_empty(dev, s);
- das1800_cancel(dev, s); /* disable hardware conversions */
async->events |= COMEDI_CB_EOA;
} else if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) { /* stop_src TRIG_COUNT */
- das1800_cancel(dev, s); /* disable hardware conversions */
async->events |= COMEDI_CB_EOA;
}
- comedi_event(dev, s);
-
- return;
+ cfc_handle_events(dev, s);
}
static int das1800_ai_poll(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index 43027ee500e3..e0cfb6cb547b 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -1,309 +1,532 @@
/*
- Some comments on the code..
-
- - it shouldn't be necessary to use outb_p().
-
- - ignoreirq creates a race condition. It needs to be fixed.
-
+ * das6402.c
+ * Comedi driver for DAS6402 compatible boards
+ * Copyright(c) 2014 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *
+ * Rewrite of an experimental driver by:
+ * Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
/*
- comedi/drivers/das6402.c
- An experimental driver for Computerboards' DAS6402 I/O card
+ * Driver: das6402
+ * Description: Keithley Metrabyte DAS6402 (& compatibles)
+ * Devices: (Keithley Metrabyte) DAS6402-12 (das6402-12)
+ * (Keithley Metrabyte) DAS6402-16 (das6402-16)
+ * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
+ * Updated: Fri, 14 Mar 2014 10:18:43 -0700
+ * Status: unknown
+ *
+ * Configuration Options:
+ * [0] - I/O base address
+ * [1] - IRQ (optional, needed for async command support)
+ */
- Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org>
+#include <linux/module.h>
+#include <linux/interrupt.h>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+#include "../comedidev.h"
+#include "8253.h"
- 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.
- */
/*
-Driver: das6402
-Description: Keithley Metrabyte DAS6402 (& compatibles)
-Author: Oystein Svendsen <svendsen@pvv.org>
-Status: bitrotten
-Devices: [Keithley Metrabyte] DAS6402 (das6402)
+ * Register I/O map
+ */
+#define DAS6402_AI_DATA_REG 0x00
+#define DAS6402_AI_MUX_REG 0x02
+#define DAS6402_AI_MUX_LO(x) (((x) & 0x3f) << 0)
+#define DAS6402_AI_MUX_HI(x) (((x) & 0x3f) << 8)
+#define DAS6402_DI_DO_REG 0x03
+#define DAS6402_AO_DATA_REG(x) (0x04 + ((x) * 2))
+#define DAS6402_AO_LSB_REG(x) (0x04 + ((x) * 2))
+#define DAS6402_AO_MSB_REG(x) (0x05 + ((x) * 2))
+#define DAS6402_STATUS_REG 0x08
+#define DAS6402_STATUS_FFNE (1 << 0)
+#define DAS6402_STATUS_FHALF (1 << 1)
+#define DAS6402_STATUS_FFULL (1 << 2)
+#define DAS6402_STATUS_XINT (1 << 3)
+#define DAS6402_STATUS_INT (1 << 4)
+#define DAS6402_STATUS_XTRIG (1 << 5)
+#define DAS6402_STATUS_INDGT (1 << 6)
+#define DAS6402_STATUS_10MHZ (1 << 7)
+#define DAS6402_STATUS_W_CLRINT (1 << 0)
+#define DAS6402_STATUS_W_CLRXTR (1 << 1)
+#define DAS6402_STATUS_W_CLRXIN (1 << 2)
+#define DAS6402_STATUS_W_EXTEND (1 << 4)
+#define DAS6402_STATUS_W_ARMED (1 << 5)
+#define DAS6402_STATUS_W_POSTMODE (1 << 6)
+#define DAS6402_STATUS_W_10MHZ (1 << 7)
+#define DAS6402_CTRL_REG 0x09
+#define DAS6402_CTRL_SOFT_TRIG (0 << 0)
+#define DAS6402_CTRL_EXT_FALL_TRIG (1 << 0)
+#define DAS6402_CTRL_EXT_RISE_TRIG (2 << 0)
+#define DAS6402_CTRL_PACER_TRIG (3 << 0)
+#define DAS6402_CTRL_BURSTEN (1 << 2)
+#define DAS6402_CTRL_XINTE (1 << 3)
+#define DAS6402_CTRL_IRQ(x) ((x) << 4)
+#define DAS6402_CTRL_INTE (1 << 7)
+#define DAS6402_TRIG_REG 0x0a
+#define DAS6402_TRIG_TGEN (1 << 0)
+#define DAS6402_TRIG_TGSEL (1 << 1)
+#define DAS6402_TRIG_TGPOL (1 << 2)
+#define DAS6402_TRIG_PRETRIG (1 << 3)
+#define DAS6402_AO_RANGE(_chan, _range) ((_range) << ((_chan) ? 6 : 4))
+#define DAS6402_AO_RANGE_MASK(_chan) (3 << ((_chan) ? 6 : 4))
+#define DAS6402_MODE_REG 0x0b
+#define DAS6402_MODE_RANGE(x) ((x) << 0)
+#define DAS6402_MODE_POLLED (0 << 2)
+#define DAS6402_MODE_FIFONEPTY (1 << 2)
+#define DAS6402_MODE_FIFOHFULL (2 << 2)
+#define DAS6402_MODE_EOB (3 << 2)
+#define DAS6402_MODE_ENHANCED (1 << 4)
+#define DAS6402_MODE_SE (1 << 5)
+#define DAS6402_MODE_UNI (1 << 6)
+#define DAS6402_MODE_DMA1 (0 << 7)
+#define DAS6402_MODE_DMA3 (1 << 7)
+#define DAS6402_TIMER_BASE 0x0c
+
+static const struct comedi_lrange das6402_ai_ranges = {
+ 8, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
+};
-This driver has suffered bitrot.
-*/
+/*
+ * Analog output ranges are programmable on the DAS6402/12.
+ * For the DAS6402/16 the range bits have no function, the
+ * DAC ranges are selected by switches on the board.
+ */
+static const struct comedi_lrange das6402_ao_ranges = {
+ 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(10)
+ }
+};
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include "../comedidev.h"
+struct das6402_boardinfo {
+ const char *name;
+ unsigned int maxdata;
+};
-#define DAS6402_SIZE 16
-
-#define N_WORDS (3000*64)
-
-#define STOP 0
-#define START 1
-
-#define SCANL 0x3f00
-#define BYTE unsigned char
-#define WORD unsigned short
-
-/*----- register 8 ----*/
-#define CLRINT 0x01
-#define CLRXTR 0x02
-#define CLRXIN 0x04
-#define EXTEND 0x10
-#define ARMED 0x20 /* enable conting of post sample conv */
-#define POSTMODE 0x40
-#define MHZ 0x80 /* 10 MHz clock */
-/*---------------------*/
-
-/*----- register 9 ----*/
-#define IRQ (0x04 << 4) /* these two are */
-#define IRQV 10 /* dependent on each other */
-
-#define CONVSRC 0x03 /* trig src is Intarnal pacer */
-#define BURSTEN 0x04 /* enable burst */
-#define XINTE 0x08 /* use external int. trig */
-#define INTE 0x80 /* enable analog interrupts */
-/*---------------------*/
-
-/*----- register 10 ---*/
-#define TGEN 0x01 /* Use pin DI1 for externl trigging? */
-#define TGSEL 0x02 /* Use edge triggering */
-#define TGPOL 0x04 /* active edge is falling */
-#define PRETRIG 0x08 /* pretrig */
-/*---------------------*/
-
-/*----- register 11 ---*/
-#define EOB 0x0c
-#define FIFOHFULL 0x08
-#define GAIN 0x01
-#define FIFONEPTY 0x04
-#define MODE 0x10
-#define SEM 0x20
-#define BIP 0x40
-/*---------------------*/
-
-#define M0 0x00
-#define M2 0x04
-
-#define C0 0x00
-#define C1 0x40
-#define C2 0x80
-#define RWLH 0x30
+struct das6402_boardinfo das6402_boards[] = {
+ {
+ .name = "das6402-12",
+ .maxdata = 0x0fff,
+ }, {
+ .name = "das6402-16",
+ .maxdata = 0xffff,
+ },
+};
struct das6402_private {
- int ai_bytes_to_read;
+ unsigned int irq;
+
+ unsigned int count;
+ unsigned int divider1;
+ unsigned int divider2;
- int das6402_ignoreirq;
+ unsigned int ao_range;
+ unsigned int ao_readback[2];
};
-static void das6402_ai_fifo_dregs(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static void das6402_set_mode(struct comedi_device *dev,
+ unsigned int mode)
{
- while (1) {
- if (!(inb(dev->iobase + 8) & 0x01))
- return;
- comedi_buf_put(s->async, inw(dev->iobase));
- }
+ outb(DAS6402_MODE_ENHANCED | mode, dev->iobase + DAS6402_MODE_REG);
}
-static void das6402_setcounter(struct comedi_device *dev)
+static void das6402_set_extended(struct comedi_device *dev,
+ unsigned int val)
{
- BYTE p;
- unsigned short ctrlwrd;
-
- /* set up counter0 first, mode 0 */
- p = M0 | C0 | RWLH;
- outb_p(p, dev->iobase + 15);
- ctrlwrd = 2000;
- p = (BYTE) (0xff & ctrlwrd);
- outb_p(p, dev->iobase + 12);
- p = (BYTE) (0xff & (ctrlwrd >> 8));
- outb_p(p, dev->iobase + 12);
-
- /* set up counter1, mode 2 */
- p = M2 | C1 | RWLH;
- outb_p(p, dev->iobase + 15);
- ctrlwrd = 10;
- p = (BYTE) (0xff & ctrlwrd);
- outb_p(p, dev->iobase + 13);
- p = (BYTE) (0xff & (ctrlwrd >> 8));
- outb_p(p, dev->iobase + 13);
-
- /* set up counter1, mode 2 */
- p = M2 | C2 | RWLH;
- outb_p(p, dev->iobase + 15);
- ctrlwrd = 1000;
- p = (BYTE) (0xff & ctrlwrd);
- outb_p(p, dev->iobase + 14);
- p = (BYTE) (0xff & (ctrlwrd >> 8));
- outb_p(p, dev->iobase + 14);
+ outb(DAS6402_STATUS_W_EXTEND, dev->iobase + DAS6402_STATUS_REG);
+ outb(DAS6402_STATUS_W_EXTEND | val, dev->iobase + DAS6402_STATUS_REG);
+ outb(val, dev->iobase + DAS6402_STATUS_REG);
}
-static irqreturn_t intr_handler(int irq, void *d)
+static void das6402_clear_all_interrupts(struct comedi_device *dev)
+{
+ outb(DAS6402_STATUS_W_CLRINT |
+ DAS6402_STATUS_W_CLRXTR |
+ DAS6402_STATUS_W_CLRXIN, dev->iobase + DAS6402_STATUS_REG);
+}
+
+static void das6402_ai_clear_eoc(struct comedi_device *dev)
+{
+ outb(DAS6402_STATUS_W_CLRINT, dev->iobase + DAS6402_STATUS_REG);
+}
+
+static void das6402_enable_counter(struct comedi_device *dev, bool load)
{
- struct comedi_device *dev = d;
struct das6402_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
+ unsigned long timer_iobase = dev->iobase + DAS6402_TIMER_BASE;
- if (!dev->attached || devpriv->das6402_ignoreirq) {
- dev_warn(dev->class_dev, "BUG: spurious interrupt\n");
- return IRQ_HANDLED;
- }
+ if (load) {
+ i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_iobase, 0, 1, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_iobase, 0, 2, I8254_MODE2 | I8254_BINARY);
- das6402_ai_fifo_dregs(dev, s);
+ i8254_write(timer_iobase, 0, 0, devpriv->count);
+ i8254_write(timer_iobase, 0, 1, devpriv->divider1);
+ i8254_write(timer_iobase, 0, 2, devpriv->divider2);
- if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) {
- outw_p(SCANL, dev->iobase + 2); /* clears the fifo */
- outb(0x07, dev->iobase + 8); /* clears all flip-flops */
- s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
+ } else {
+ i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_iobase, 0, 1, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_iobase, 0, 2, I8254_MODE0 | I8254_BINARY);
}
+}
- outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */
+static irqreturn_t das6402_interrupt(int irq, void *d)
+{
+ struct comedi_device *dev = d;
+
+ das6402_clear_all_interrupts(dev);
- comedi_event(dev, s);
return IRQ_HANDLED;
}
-#if 0
-static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
+static int das6402_ai_cmd(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- int i;
+ return -EINVAL;
+}
- for (i = 0; i < n; i++)
- data[i] = inw(dev->iobase);
+static int das6402_ai_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ return -EINVAL;
}
-#endif
static int das6402_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
+ outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG);
+
+ return 0;
+}
+
+static void das6402_ai_soft_trig(struct comedi_device *dev)
+{
+ outw(0, dev->iobase + DAS6402_AI_DATA_REG);
+}
+
+static int das6402_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + DAS6402_STATUS_REG);
+ if (status & DAS6402_STATUS_FFNE)
+ return 0;
+ return -EBUSY;
+}
+
+static int das6402_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int aref = CR_AREF(insn->chanspec);
+ unsigned int val;
+ int ret;
+ int i;
+
+ val = DAS6402_MODE_RANGE(range) | DAS6402_MODE_POLLED;
+ if (aref == AREF_DIFF) {
+ if (chan > s->n_chan / 2)
+ return -EINVAL;
+ } else {
+ val |= DAS6402_MODE_SE;
+ }
+ if (comedi_range_is_unipolar(s, range))
+ val |= DAS6402_MODE_UNI;
+
+ /* enable software conversion trigger */
+ outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG);
+
+ das6402_set_mode(dev, val);
+
+ /* load the mux for single channel conversion */
+ outw(DAS6402_AI_MUX_HI(chan) | DAS6402_AI_MUX_LO(chan),
+ dev->iobase + DAS6402_AI_MUX_REG);
+
+ for (i = 0; i < insn->n; i++) {
+ das6402_ai_clear_eoc(dev);
+ das6402_ai_soft_trig(dev);
+
+ ret = comedi_timeout(dev, s, insn, das6402_ai_eoc, 0);
+ if (ret)
+ break;
+
+ val = inw(dev->iobase + DAS6402_AI_DATA_REG);
+
+ if (s->maxdata == 0x0fff)
+ val >>= 4;
+
+ data[i] = val;
+ }
+
+ das6402_ai_clear_eoc(dev);
+
+ return insn->n;
+}
+
+static int das6402_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
struct das6402_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int val;
+ int i;
+
+ /* set the range for this channel */
+ val = devpriv->ao_range;
+ val &= ~DAS6402_AO_RANGE_MASK(chan);
+ val |= DAS6402_AO_RANGE(chan, range);
+ if (val != devpriv->ao_range) {
+ devpriv->ao_range = val;
+ outb(val, dev->iobase + DAS6402_TRIG_REG);
+ }
/*
- * This function should reset the board from whatever condition it
- * is in (i.e., acquiring data), to a non-active state.
+ * The DAS6402/16 has a jumper to select either individual
+ * update (UPDATE) or simultaneous updating (XFER) of both
+ * DAC's. In UPDATE mode, when the MSB is written, that DAC
+ * is updated. In XFER mode, after both DAC's are loaded,
+ * a read cycle of any DAC register will update both DAC's
+ * simultaneously.
+ *
+ * If you have XFER mode enabled a (*insn_read) will need
+ * to be performed in order to update the DAC's with the
+ * last value written.
*/
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+
+ devpriv->ao_readback[chan] = val;
+
+ if (s->maxdata == 0x0fff) {
+ /*
+ * DAS6402/12 has the two 8-bit DAC registers, left
+ * justified (the 4 LSB bits are don't care). Data
+ * can be written as one word.
+ */
+ val <<= 4;
+ outw(val, dev->iobase + DAS6402_AO_DATA_REG(chan));
+ } else {
+ /*
+ * DAS6402/16 uses both 8-bit DAC registers and needs
+ * to be written LSB then MSB.
+ */
+ outb(val & 0xff,
+ dev->iobase + DAS6402_AO_LSB_REG(chan));
+ outb((val >> 8) & 0xff,
+ dev->iobase + DAS6402_AO_LSB_REG(chan));
+ }
+ }
- devpriv->das6402_ignoreirq = 1;
- dev_dbg(dev->class_dev, "Stopping acquisition\n");
- devpriv->das6402_ignoreirq = 1;
- outb_p(0x02, dev->iobase + 10); /* disable external trigging */
- outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
- outb_p(0, dev->iobase + 9); /* disables interrupts */
-
- outw_p(SCANL, dev->iobase + 2);
-
- return 0;
+ return insn->n;
}
-#ifdef unused
-static int das6402_ai_mode2(struct comedi_device *dev,
- struct comedi_subdevice *s, comedi_trig *it)
+static int das6402_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct das6402_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
- devpriv->das6402_ignoreirq = 1;
- dev_dbg(dev->class_dev, "Starting acquisition\n");
- outb_p(0x03, dev->iobase + 10); /* enable external trigging */
- outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
- outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
+ /*
+ * If XFER mode is enabled, reading any DAC register
+ * will update both DAC's simultaneously.
+ */
+ inw(dev->iobase + DAS6402_AO_LSB_REG(chan));
- devpriv->ai_bytes_to_read = it->n * sizeof(short);
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
- /* um... ignoreirq is a nasty race condition */
- devpriv->das6402_ignoreirq = 0;
+ return insn->n;
+}
- outw_p(SCANL, dev->iobase + 2);
+static int das6402_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ data[1] = inb(dev->iobase + DAS6402_DI_DO_REG);
- return 0;
+ return insn->n;
}
-#endif
-static int board_init(struct comedi_device *dev)
+static int das6402_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct das6402_private *devpriv = dev->private;
- BYTE b;
+ if (comedi_dio_update_state(s, data))
+ outb(s->state, dev->iobase + DAS6402_DI_DO_REG);
- devpriv->das6402_ignoreirq = 1;
+ data[1] = s->state;
- outb(0x07, dev->iobase + 8);
+ return insn->n;
+}
- /* register 11 */
- outb_p(MODE, dev->iobase + 11);
- b = BIP | SEM | MODE | GAIN | FIFOHFULL;
- outb_p(b, dev->iobase + 11);
+static void das6402_reset(struct comedi_device *dev)
+{
+ struct das6402_private *devpriv = dev->private;
- /* register 8 */
- outb_p(EXTEND, dev->iobase + 8);
- b = EXTEND | MHZ;
- outb_p(b, dev->iobase + 8);
- b = MHZ | CLRINT | CLRXTR | CLRXIN;
- outb_p(b, dev->iobase + 8);
+ /* enable "Enhanced" mode */
+ outb(DAS6402_MODE_ENHANCED, dev->iobase + DAS6402_MODE_REG);
- /* register 9 */
- b = IRQ | CONVSRC | BURSTEN | INTE;
- outb_p(b, dev->iobase + 9);
+ /* enable 10MHz pacer clock */
+ das6402_set_extended(dev, DAS6402_STATUS_W_10MHZ);
- /* register 10 */
- b = TGSEL | TGEN;
- outb_p(b, dev->iobase + 10);
+ /* enable software conversion trigger */
+ outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG);
- b = 0x07;
- outb_p(b, dev->iobase + 8);
+ /* default ADC to single-ended unipolar 10V inputs */
+ das6402_set_mode(dev, DAS6402_MODE_RANGE(0) |
+ DAS6402_MODE_POLLED |
+ DAS6402_MODE_SE |
+ DAS6402_MODE_UNI);
- das6402_setcounter(dev);
+ /* default mux for single channel conversion (channel 0) */
+ outw(DAS6402_AI_MUX_HI(0) | DAS6402_AI_MUX_LO(0),
+ dev->iobase + DAS6402_AI_MUX_REG);
- outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
+ /* set both DAC's for unipolar 5V output range */
+ devpriv->ao_range = DAS6402_AO_RANGE(0, 2) | DAS6402_AO_RANGE(1, 2);
+ outb(devpriv->ao_range, dev->iobase + DAS6402_TRIG_REG);
- devpriv->das6402_ignoreirq = 0;
+ /* set both DAC's to 0V */
+ outw(0, dev->iobase + DAS6402_AO_DATA_REG(0));
+ outw(0, dev->iobase + DAS6402_AO_DATA_REG(0));
+ inw(dev->iobase + DAS6402_AO_LSB_REG(0));
- return 0;
+ das6402_enable_counter(dev, false);
+
+ /* set all digital outputs low */
+ outb(0, dev->iobase + DAS6402_DI_DO_REG);
+
+ das6402_clear_all_interrupts(dev);
}
static int das6402_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
+ const struct das6402_boardinfo *board = comedi_board(dev);
struct das6402_private *devpriv;
- unsigned int irq;
- int ret;
struct comedi_subdevice *s;
-
- ret = comedi_request_region(dev, it->options[0], DAS6402_SIZE);
- if (ret)
- return ret;
-
- irq = it->options[0];
- dev_dbg(dev->class_dev, "( irq = %u )\n", irq);
- ret = request_irq(irq, intr_handler, 0, "das6402", dev);
- if (ret < 0)
- return ret;
-
- dev->irq = irq;
+ int ret;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- ret = comedi_alloc_subdevices(dev, 1);
+ ret = comedi_request_region(dev, it->options[0], 0x10);
if (ret)
return ret;
- /* ai subdevice */
+ das6402_reset(dev);
+
+ /* IRQs 2,3,5,6,7, 10,11,15 are valid for "enhanced" mode */
+ if ((1 << it->options[1]) & 0x8cec) {
+ ret = request_irq(it->options[1], das6402_interrupt, 0,
+ dev->board_name, dev);
+ if (ret == 0) {
+ dev->irq = it->options[1];
+
+ switch (dev->irq) {
+ case 10:
+ devpriv->irq = 4;
+ break;
+ case 11:
+ devpriv->irq = 1;
+ break;
+ case 15:
+ devpriv->irq = 6;
+ break;
+ default:
+ devpriv->irq = dev->irq;
+ break;
+ }
+ }
+ }
+
+ ret = comedi_alloc_subdevices(dev, 4);
+ if (ret)
+ return ret;
+
+ /* Analog Input subdevice */
s = &dev->subdevices[0];
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND;
- s->n_chan = 8;
- /* s->trig[2]=das6402_ai_mode2; */
- s->cancel = das6402_ai_cancel;
- s->maxdata = (1 << 12) - 1;
- s->len_chanlist = 16; /* ? */
- s->range_table = &range_unknown;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
+ s->n_chan = 64;
+ s->maxdata = board->maxdata;
+ s->range_table = &das6402_ai_ranges;
+ s->insn_read = das6402_ai_insn_read;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = s->n_chan;
+ s->do_cmdtest = das6402_ai_cmdtest;
+ s->do_cmd = das6402_ai_cmd;
+ s->cancel = das6402_ai_cancel;
+ }
- board_init(dev);
+ /* Analog Output subdevice */
+ s = &dev->subdevices[1];
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 2;
+ s->maxdata = board->maxdata;
+ s->range_table = &das6402_ao_ranges;
+ s->insn_write = das6402_ao_insn_write;
+ s->insn_read = das6402_ao_insn_read;
+
+ /* Digital Input subdevice */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = das6402_di_insn_bits;
+
+ /* Digital Input subdevice */
+ s = &dev->subdevices[3];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = das6402_do_insn_bits;
return 0;
}
@@ -313,9 +536,12 @@ static struct comedi_driver das6402_driver = {
.module = THIS_MODULE,
.attach = das6402_attach,
.detach = comedi_legacy_detach,
+ .board_name = &das6402_boards[0].name,
+ .num_names = ARRAY_SIZE(das6402_boards),
+ .offset = sizeof(struct das6402_boardinfo),
};
module_comedi_driver(das6402_driver)
-MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_DESCRIPTION("Comedi driver for DAS6402 compatible boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index 5af0a5764a8c..3e408370dcf3 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -420,17 +420,12 @@ static int das800_ai_do_cmd(struct comedi_device *dev,
gain &= 0xf;
outb(gain, dev->iobase + DAS800_GAIN);
- switch (async->cmd.stop_src) {
- case TRIG_COUNT:
+ if (async->cmd.stop_src == TRIG_COUNT) {
devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len;
devpriv->forever = false;
- break;
- case TRIG_NONE:
+ } else { /* TRIG_NONE */
devpriv->forever = true;
devpriv->count = 0;
- break;
- default:
- break;
}
/* enable auto channel scan, send interrupts on end of conversion
@@ -440,26 +435,19 @@ static int das800_ai_do_cmd(struct comedi_device *dev,
conv_bits |= EACS | IEOC;
if (async->cmd.start_src == TRIG_EXT)
conv_bits |= DTEN;
- switch (async->cmd.convert_src) {
- case TRIG_TIMER:
+ if (async->cmd.convert_src == TRIG_TIMER) {
conv_bits |= CASC | ITE;
/* set conversion frequency */
if (das800_set_frequency(dev) < 0) {
comedi_error(dev, "Error setting up counters");
return -1;
}
- break;
- case TRIG_EXT:
- break;
- default:
- break;
}
spin_lock_irqsave(&dev->spinlock, irq_flags);
das800_ind_write(dev, conv_bits, CONV_CONTROL);
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
- async->events = 0;
das800_enable(dev);
return 0;
}
@@ -532,10 +520,8 @@ static irqreturn_t das800_interrupt(int irq, void *d)
if (fifo_overflow) {
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
- das800_cancel(dev, s);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
- async->events = 0;
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
@@ -551,20 +537,21 @@ static irqreturn_t das800_interrupt(int irq, void *d)
das800_disable(dev);
async->events |= COMEDI_CB_EOA;
}
- comedi_event(dev, s);
- async->events = 0;
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
-static int das800_wait_for_conv(struct comedi_device *dev, int timeout)
+static int das800_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- int i;
+ unsigned int status;
- for (i = 0; i < timeout; i++) {
- if (!(inb(dev->iobase + DAS800_STATUS) & BUSY))
- return 0;
- }
- return -ETIME;
+ status = inb(dev->iobase + DAS800_STATUS);
+ if ((status & BUSY) == 0)
+ return 0;
+ return -EBUSY;
}
static int das800_ai_insn_read(struct comedi_device *dev,
@@ -599,7 +586,7 @@ static int das800_ai_insn_read(struct comedi_device *dev,
/* trigger conversion */
outb_p(0, dev->iobase + DAS800_MSB);
- ret = das800_wait_for_conv(dev, 1000);
+ ret = comedi_timeout(dev, s, insn, das800_ai_eoc, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index 78a19629ff56..c8a36eb5f015 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -164,16 +164,29 @@ struct dmm32at_private {
};
+static int dmm32at_ai_status(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned char status;
+
+ status = inb(dev->iobase + context);
+ if ((status & DMM32AT_STATUS) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int dmm32at_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- int n, i;
+ int n;
unsigned int d;
- unsigned char status;
unsigned short msb, lsb;
unsigned char chan;
int range;
+ int ret;
/* get the channel and range number */
@@ -190,26 +203,20 @@ static int dmm32at_ai_rinsn(struct comedi_device *dev,
outb(dmm32at_rangebits[range], dev->iobase + DMM32AT_AICONF);
/* wait for circuit to settle */
- for (i = 0; i < 40000; i++) {
- status = inb(dev->iobase + DMM32AT_AIRBACK);
- if ((status & DMM32AT_STATUS) == 0)
- break;
- }
- if (i == 40000)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, DMM32AT_AIRBACK);
+ if (ret)
+ return ret;
/* convert n samples */
for (n = 0; n < insn->n; n++) {
/* trigger conversion */
outb(0xff, dev->iobase + DMM32AT_CONV);
+
/* wait for conversion to end */
- for (i = 0; i < 40000; i++) {
- status = inb(dev->iobase + DMM32AT_AISTAT);
- if ((status & DMM32AT_STATUS) == 0)
- break;
- }
- if (i == 40000)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, dmm32at_ai_status,
+ DMM32AT_AISTAT);
+ if (ret)
+ return ret;
/* read data */
lsb = inb(dev->iobase + DMM32AT_AILSB);
@@ -403,8 +410,9 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct dmm32at_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
- int i, range;
- unsigned char chanlo, chanhi, status;
+ int range;
+ unsigned char chanlo, chanhi;
+ int ret;
if (!cmd->chanlist)
return -EINVAL;
@@ -439,14 +447,13 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* isr */
}
- /* wait for circuit to settle */
- for (i = 0; i < 40000; i++) {
- status = inb(dev->iobase + DMM32AT_AIRBACK);
- if ((status & DMM32AT_STATUS) == 0)
- break;
- }
- if (i == 40000)
- return -ETIMEDOUT;
+ /*
+ * wait for circuit to settle
+ * we don't have the 'insn' here but it's not needed
+ */
+ ret = comedi_timeout(dev, s, NULL, dmm32at_ai_status, DMM32AT_AIRBACK);
+ if (ret)
+ return ret;
if (devpriv->ai_scans_left > 1) {
/* start the clock and enable the interrupts */
@@ -525,6 +532,19 @@ static irqreturn_t dmm32at_isr(int irq, void *d)
return IRQ_HANDLED;
}
+static int dmm32at_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned char status;
+
+ status = inb(dev->iobase + DMM32AT_DACSTAT);
+ if ((status & DMM32AT_DACBUSY) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int dmm32at_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -533,6 +553,7 @@ static int dmm32at_ao_winsn(struct comedi_device *dev,
int i;
int chan = CR_CHAN(insn->chanspec);
unsigned char hi, lo, status;
+ int ret;
/* Writing a list of values to an AO channel is probably not
* very useful, but that's how the interface is defined. */
@@ -549,13 +570,9 @@ static int dmm32at_ao_winsn(struct comedi_device *dev,
outb(hi, dev->iobase + DMM32AT_DACMSB);
/* wait for circuit to settle */
- for (i = 0; i < 40000; i++) {
- status = inb(dev->iobase + DMM32AT_DACSTAT);
- if ((status & DMM32AT_DACBUSY) == 0)
- break;
- }
- if (i == 40000)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, dmm32at_ao_eoc, 0);
+ if (ret)
+ return ret;
/* dummy read to update trigger the output */
status = inb(dev->iobase + DMM32AT_DACMSB);
diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c
index 4271903facd7..ba7c2ba618e6 100644
--- a/drivers/staging/comedi/drivers/dt2811.c
+++ b/drivers/staging/comedi/drivers/dt2811.c
@@ -224,23 +224,32 @@ static const struct comedi_lrange *dac_range_types[] = {
&range_unipolar5
};
-#define DT2811_TIMEOUT 5
+static int dt2811_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + DT2811_ADCSR);
+ if ((status & DT2811_ADBUSY) == 0)
+ return 0;
+ return -EBUSY;
+}
static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
int chan = CR_CHAN(insn->chanspec);
- int timeout = DT2811_TIMEOUT;
+ int ret;
int i;
for (i = 0; i < insn->n; i++) {
outb(chan, dev->iobase + DT2811_ADGCR);
- while (timeout
- && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
- timeout--;
- if (!timeout)
- return -ETIME;
+ ret = comedi_timeout(dev, s, insn, dt2811_ai_eoc, 0);
+ if (ret)
+ return ret;
data[i] = inb(dev->iobase + DT2811_ADDATLO);
data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c
index abad6e49c1c1..3794b7e52091 100644
--- a/drivers/staging/comedi/drivers/dt2814.c
+++ b/drivers/staging/comedi/drivers/dt2814.c
@@ -66,26 +66,35 @@ struct dt2814_private {
#define DT2814_TIMEOUT 10
#define DT2814_MAX_SPEED 100000 /* Arbitrary 10 khz limit */
+static int dt2814_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + DT2814_CSR);
+ if (status & DT2814_FINISH)
+ return 0;
+ return -EBUSY;
+}
+
static int dt2814_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- int n, i, hi, lo;
+ int n, hi, lo;
int chan;
- int status = 0;
+ int ret;
for (n = 0; n < insn->n; n++) {
chan = CR_CHAN(insn->chanspec);
outb(chan, dev->iobase + DT2814_CSR);
- for (i = 0; i < DT2814_TIMEOUT; i++) {
- status = inb(dev->iobase + DT2814_CSR);
- udelay(10);
- if (status & DT2814_FINISH)
- break;
- }
- if (i >= DT2814_TIMEOUT)
- return -ETIMEDOUT;
+
+ ret = comedi_timeout(dev, s, insn, dt2814_ai_eoc, 0);
+ if (ret)
+ return ret;
hi = inb(dev->iobase + DT2814_DATA);
lo = inb(dev->iobase + DT2814_DATA);
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index ee24717821e1..b9ac4ed8babb 100644
--- a/drivers/staging/comedi/drivers/dt2815.c
+++ b/drivers/staging/comedi/drivers/dt2815.c
@@ -67,15 +67,17 @@ struct dt2815_private {
unsigned int ao_readback[8];
};
-static int dt2815_wait_for_status(struct comedi_device *dev, int status)
+static int dt2815_ao_status(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- int i;
+ unsigned int status;
- for (i = 0; i < 100; i++) {
- if (inb(dev->iobase + DT2815_STATUS) == status)
- break;
- }
- return status;
+ status = inb(dev->iobase + DT2815_STATUS);
+ if (status == context)
+ return 0;
+ return -EBUSY;
}
static int dt2815_ao_insn_read(struct comedi_device *dev,
@@ -98,30 +100,23 @@ static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct dt2815_private *devpriv = dev->private;
int i;
int chan = CR_CHAN(insn->chanspec);
- unsigned int status;
unsigned int lo, hi;
+ int ret;
for (i = 0; i < insn->n; i++) {
lo = ((data[i] & 0x0f) << 4) | (chan << 1) | 0x01;
hi = (data[i] & 0xff0) >> 4;
- status = dt2815_wait_for_status(dev, 0x00);
- if (status != 0) {
- dev_dbg(dev->class_dev,
- "failed to write low byte on %d reason %x\n",
- chan, status);
- return -EBUSY;
- }
+ ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x00);
+ if (ret)
+ return ret;
outb(lo, dev->iobase + DT2815_DATA);
- status = dt2815_wait_for_status(dev, 0x10);
- if (status != 0x10) {
- dev_dbg(dev->class_dev,
- "failed to write high byte on %d reason %x\n",
- chan, status);
- return -EBUSY;
- }
+ ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x10);
+ if (ret)
+ return ret;
+
devpriv->ao_readback[chan] = data[i];
}
return i;
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 895f73a19023..16cc100531e5 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -63,7 +63,6 @@ Notes:
#include "comedi_fc.h"
-#define DT2821_TIMEOUT 100 /* 500 us */
#define DT2821_SIZE 0x10
/*
@@ -248,27 +247,6 @@ struct dt282x_private {
* Some useless abstractions
*/
#define chan_to_DAC(a) ((a)&1)
-#define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
-#define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
-
-/*
- * danger! macro abuse... a is the expression to wait on, and b is
- * the statement(s) to execute if it doesn't happen.
- */
-#define wait_for(a, b) \
- do { \
- int _i; \
- for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \
- if (a) { \
- _i = 0; \
- break; \
- } \
- udelay(5); \
- } \
- if (_i) { \
- b \
- } \
- } while (0)
static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
@@ -328,7 +306,6 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
if (size == 0) {
dev_err(dev->class_dev, "AO underrun\n");
- dt282x_ao_cancel(dev, s);
s->async->events |= COMEDI_CB_OVERFLOW;
return;
}
@@ -363,7 +340,7 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
dt282x_munge(dev, ptr, size);
ret = cfc_write_array_to_buffer(s, ptr, size);
if (ret != size) {
- dt282x_ai_cancel(dev, s);
+ s->async->events |= COMEDI_CB_OVERFLOW;
return;
}
devpriv->nread -= size / 2;
@@ -373,7 +350,6 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
devpriv->nread = 0;
}
if (!devpriv->nread) {
- dt282x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
return;
}
@@ -471,15 +447,13 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
if (adcsr & DT2821_ADERR) {
if (devpriv->nread != 0) {
comedi_error(dev, "A/D error");
- dt282x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_ERROR;
}
handled = 1;
}
if (dacsr & DT2821_DAERR) {
comedi_error(dev, "D/A error");
- dt282x_ao_cancel(dev, s_ao);
- s->async->events |= COMEDI_CB_ERROR;
+ s_ao->async->events |= COMEDI_CB_ERROR;
handled = 1;
}
#if 0
@@ -508,7 +482,8 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
handled = 1;
}
#endif
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
+ cfc_handle_events(dev, s_ao);
return IRQ_RETVAL(handled);
}
@@ -530,6 +505,29 @@ static void dt282x_load_changain(struct comedi_device *dev, int n,
outw(n - 1, dev->iobase + DT2821_CHANCSR);
}
+static int dt282x_ai_timeout(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + DT2821_ADCSR);
+ switch (context) {
+ case DT2821_MUXBUSY:
+ if ((status & DT2821_MUXBUSY) == 0)
+ return 0;
+ break;
+ case DT2821_ADDONE:
+ if (status & DT2821_ADDONE)
+ return 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return -EBUSY;
+}
+
/*
* Performs a single A/D conversion.
* - Put channel/gain into channel-gain list
@@ -542,6 +540,7 @@ static int dt282x_ai_insn_read(struct comedi_device *dev,
{
const struct dt282x_board *board = comedi_board(dev);
struct dt282x_private *devpriv = dev->private;
+ int ret;
int i;
/* XXX should we really be enabling the ad clock here? */
@@ -551,13 +550,18 @@ static int dt282x_ai_insn_read(struct comedi_device *dev,
dt282x_load_changain(dev, 1, &insn->chanspec);
outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
- wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
+ ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, DT2821_MUXBUSY);
+ if (ret)
+ return ret;
for (i = 0; i < insn->n; i++) {
outw(devpriv->supcsr | DT2821_STRIG,
dev->iobase + DT2821_SUPCSR);
- wait_for(ad_done(), comedi_error(dev, "timeout\n");
- return -ETIME;);
+
+ ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout,
+ DT2821_ADDONE);
+ if (ret)
+ return ret;
data[i] =
inw(dev->iobase +
@@ -646,6 +650,7 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
struct dt282x_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
int timer;
+ int ret;
if (devpriv->usedma == 0) {
comedi_error(dev,
@@ -691,7 +696,9 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
- wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
+ ret = comedi_timeout(dev, s, NULL, dt282x_ai_timeout, DT2821_MUXBUSY);
+ if (ret)
+ return ret;
if (cmd->scan_begin_src == TRIG_FOLLOW) {
outw(devpriv->supcsr | DT2821_STRIG,
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index f52a4476cb73..436e451cadf5 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -369,12 +369,10 @@ static irqreturn_t dt3k_interrupt(int irq, void *d)
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
debug_n_ints++;
- if (debug_n_ints >= 10) {
- dt3k_ai_cancel(dev, s);
+ if (debug_n_ints >= 10)
s->async->events |= COMEDI_CB_EOA;
- }
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
@@ -767,8 +765,6 @@ static int dt3000_auto_attach(struct comedi_device *dev,
s->type = COMEDI_SUBD_PROC;
#endif
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index f224825830ba..e5593f8c7406 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -57,18 +57,27 @@ struct dyna_pci10xx_private {
unsigned long BADR3;
};
-/******************************************************************************/
-/************************** READ WRITE FUNCTIONS ******************************/
-/******************************************************************************/
+static int dyna_pci10xx_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw_p(dev->iobase);
+ if (status & (1 << 15))
+ return 0;
+ return -EBUSY;
+}
-/* analog input callback */
static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct dyna_pci10xx_private *devpriv = dev->private;
- int n, counter;
+ int n;
u16 d = 0;
+ int ret = 0;
unsigned int chan, range;
/* get the channel number and range */
@@ -82,18 +91,13 @@ static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev,
smp_mb();
outw_p(0x0000 + range + chan, dev->iobase + 2);
udelay(10);
+
+ ret = comedi_timeout(dev, s, insn, dyna_pci10xx_ai_eoc, 0);
+ if (ret)
+ break;
+
/* read data */
- for (counter = 0; counter < READ_TIMEOUT; counter++) {
- d = inw_p(dev->iobase);
-
- /* check if read is successful if the EOC bit is set */
- if (d & (1 << 15))
- goto conv_finish;
- }
- data[n] = 0;
- dev_dbg(dev->class_dev, "timeout reading analog input\n");
- continue;
-conv_finish:
+ d = inw_p(dev->iobase);
/* mask the first 4 bits - EOC bits */
d &= 0x0FFF;
data[n] = d;
@@ -101,7 +105,7 @@ conv_finish:
mutex_unlock(&devpriv->mutex);
/* return the number of samples read/written */
- return n;
+ return ret ? ret : n;
}
/* analog output callback */
@@ -232,8 +236,6 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev,
s->state = 0;
s->insn_bits = dyna_pci10xx_do_insn_bits;
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index a99ddf00ddc4..4e410f3b0e24 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -1,27 +1,49 @@
/*
- comedi/drivers/fl512.c
- Anders Gnistrup <ex18@kalman.iau.dtu.dk>
-*/
+ * fl512.c
+ * Anders Gnistrup <ex18@kalman.iau.dtu.dk>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
/*
-Driver: fl512
-Description: unknown
-Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk>
-Devices: [unknown] FL512 (fl512)
-Status: unknown
-
-Digital I/O is not supported.
-
-Configuration options:
- [0] - I/O port base address
-*/
+ * Driver: fl512
+ * Description: unknown
+ * Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk>
+ * Devices: [unknown] FL512 (fl512)
+ * Status: unknown
+ *
+ * Digital I/O is not supported.
+ *
+ * Configuration options:
+ * [0] - I/O port base address
+ */
#include <linux/module.h>
#include "../comedidev.h"
#include <linux/delay.h>
-#define FL512_SIZE 16 /* the size of the used memory */
+/*
+ * Register I/O map
+ */
+#define FL512_AI_LSB_REG 0x02
+#define FL512_AI_MSB_REG 0x03
+#define FL512_AI_MUX_REG 0x02
+#define FL512_AI_START_CONV_REG 0x03
+#define FL512_AO_DATA_REG(x) (0x04 + ((x) * 2))
+#define FL512_AO_TRIG_REG(x) (0x04 + ((x) * 2))
+
struct fl512_private {
unsigned short ao_readback[2];
};
@@ -38,72 +60,69 @@ static const struct comedi_lrange range_fl512 = {
}
};
-/*
- * fl512_ai_insn : this is the analog input function
- */
-static int fl512_ai_insn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
+static int fl512_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int n;
- unsigned int lo_byte, hi_byte;
- char chan = CR_CHAN(insn->chanspec);
- unsigned long iobase = dev->iobase;
-
- for (n = 0; n < insn->n; n++) { /* sample n times on selected channel */
- /* XXX probably can move next step out of for() loop -- will
- * make AI a little bit faster. */
- outb(chan, iobase + 2); /* select chan */
- outb(0, iobase + 3); /* start conversion */
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
+ int i;
+
+ outb(chan, dev->iobase + FL512_AI_MUX_REG);
+
+ for (i = 0; i < insn->n; i++) {
+ outb(0, dev->iobase + FL512_AI_START_CONV_REG);
+
/* XXX should test "done" flag instead of delay */
- udelay(30); /* sleep 30 usec */
- lo_byte = inb(iobase + 2); /* low 8 byte */
- hi_byte = inb(iobase + 3) & 0xf; /* high 4 bit and mask */
- data[n] = lo_byte + (hi_byte << 8);
+ udelay(30);
+
+ val = inb(dev->iobase + FL512_AI_LSB_REG);
+ val |= (inb(dev->iobase + FL512_AI_MSB_REG) << 8);
+ val &= s->maxdata;
+
+ data[i] = val;
}
- return n;
+
+ return insn->n;
}
-/*
- * fl512_ao_insn : used to write to a DA port n times
- */
-static int fl512_ao_insn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
+static int fl512_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct fl512_private *devpriv = dev->private;
- int n;
- int chan = CR_CHAN(insn->chanspec); /* get chan to write */
- unsigned long iobase = dev->iobase; /* get base address */
-
- for (n = 0; n < insn->n; n++) { /* write n data set */
- /* write low byte */
- outb(data[n] & 0x0ff, iobase + 4 + 2 * chan);
- /* write high byte */
- outb((data[n] & 0xf00) >> 8, iobase + 4 + 2 * chan);
- inb(iobase + 4 + 2 * chan); /* trig */
-
- devpriv->ao_readback[chan] = data[n];
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = devpriv->ao_readback[chan];
+ int i;
+
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+
+ /* write LSB, MSB then trigger conversion */
+ outb(val & 0x0ff, dev->iobase + FL512_AO_DATA_REG(chan));
+ outb((val >> 8) & 0xf, dev->iobase + FL512_AO_DATA_REG(chan));
+ inb(dev->iobase + FL512_AO_TRIG_REG(chan));
}
- return n;
+ devpriv->ao_readback[chan] = val;
+
+ return insn->n;
}
-/*
- * fl512_ao_insn_readback : used to read previous values written to
- * DA port
- */
-static int fl512_ao_insn_readback(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int fl512_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct fl512_private *devpriv = dev->private;
- int n;
- int chan = CR_CHAN(insn->chanspec);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
- for (n = 0; n < insn->n; n++)
- data[n] = devpriv->ao_readback[chan];
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
- return n;
+ return insn->n;
}
static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -112,7 +131,7 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
int ret;
- ret = comedi_request_region(dev, it->options[0], FL512_SIZE);
+ ret = comedi_request_region(dev, it->options[0], 0x10);
if (ret)
return ret;
@@ -124,42 +143,26 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- /*
- * this if the definitions of the supdevices, 2 have been defined
- */
- /* Analog indput */
+ /* Analog Input subdevice */
s = &dev->subdevices[0];
- /* define subdevice as Analog In */
- s->type = COMEDI_SUBD_AI;
- /* you can read it from userspace */
- s->subdev_flags = SDF_READABLE | SDF_GROUND;
- /* Number of Analog input channels */
- s->n_chan = 16;
- /* accept only 12 bits of data */
- s->maxdata = 0x0fff;
- /* device use one of the ranges */
- s->range_table = &range_fl512;
- /* function to call when read AD */
- s->insn_read = fl512_ai_insn;
-
- /* Analog output */
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND;
+ s->n_chan = 16;
+ s->maxdata = 0x0fff;
+ s->range_table = &range_fl512;
+ s->insn_read = fl512_ai_insn_read;
+
+ /* Analog Output subdevice */
s = &dev->subdevices[1];
- /* define subdevice as Analog OUT */
- s->type = COMEDI_SUBD_AO;
- /* you can write it from userspace */
- s->subdev_flags = SDF_WRITABLE;
- /* Number of Analog output channels */
- s->n_chan = 2;
- /* accept only 12 bits of data */
- s->maxdata = 0x0fff;
- /* device use one of the ranges */
- s->range_table = &range_fl512;
- /* function to call when write DA */
- s->insn_write = fl512_ao_insn;
- /* function to call when reading DA */
- s->insn_read = fl512_ao_insn_readback;
-
- return 1;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 2;
+ s->maxdata = 0x0fff;
+ s->range_table = &range_fl512;
+ s->insn_write = fl512_ao_insn_write;
+ s->insn_read = fl512_ao_insn_read;
+
+ return 0;
}
static struct comedi_driver fl512_driver = {
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index de60a2871d70..08d7655e24e7 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -1,24 +1,24 @@
/*
- comedi/drivers/gsc_hpdi.c
- This is a driver for the General Standards Corporation High
- Speed Parallel Digital Interface rs485 boards.
-
- Author: Frank Mori Hess <fmhess@users.sourceforge.net>
- Copyright (C) 2003 Coherent Imaging Systems
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * gsc_hpdi.c
+ * Comedi driver the General Standards Corporation
+ * High Speed Parallel Digital Interface rs485 boards.
+ *
+ * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Copyright (C) 2003 Coherent Imaging Systems
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
/*
* Driver: gsc_hpdi
@@ -40,8 +40,6 @@
* support could be added to this driver.
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
@@ -52,149 +50,105 @@
#include "plx9080.h"
#include "comedi_fc.h"
-static void abort_dma(struct comedi_device *dev, unsigned int channel);
-static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static irqreturn_t handle_interrupt(int irq, void *d);
-static int dio_config_block_size(struct comedi_device *dev, unsigned int *data);
-
-#define TIMER_BASE 50 /* 20MHz master clock */
-#define DMA_BUFFER_SIZE 0x10000
-#define NUM_DMA_BUFFERS 4
-#define NUM_DMA_DESCRIPTORS 256
-
-enum hpdi_registers {
- FIRMWARE_REV_REG = 0x0,
- BOARD_CONTROL_REG = 0x4,
- BOARD_STATUS_REG = 0x8,
- TX_PROG_ALMOST_REG = 0xc,
- RX_PROG_ALMOST_REG = 0x10,
- FEATURES_REG = 0x14,
- FIFO_REG = 0x18,
- TX_STATUS_COUNT_REG = 0x1c,
- TX_LINE_VALID_COUNT_REG = 0x20,
- TX_LINE_INVALID_COUNT_REG = 0x24,
- RX_STATUS_COUNT_REG = 0x28,
- RX_LINE_COUNT_REG = 0x2c,
- INTERRUPT_CONTROL_REG = 0x30,
- INTERRUPT_STATUS_REG = 0x34,
- TX_CLOCK_DIVIDER_REG = 0x38,
- TX_FIFO_SIZE_REG = 0x40,
- RX_FIFO_SIZE_REG = 0x44,
- TX_FIFO_WORDS_REG = 0x48,
- RX_FIFO_WORDS_REG = 0x4c,
- INTERRUPT_EDGE_LEVEL_REG = 0x50,
- INTERRUPT_POLARITY_REG = 0x54,
-};
-
-/* bit definitions */
-
-enum firmware_revision_bits {
- FEATURES_REG_PRESENT_BIT = 0x8000,
-};
-
-enum board_control_bits {
- BOARD_RESET_BIT = 0x1, /* wait 10usec before accessing fifos */
- TX_FIFO_RESET_BIT = 0x2,
- RX_FIFO_RESET_BIT = 0x4,
- TX_ENABLE_BIT = 0x10,
- RX_ENABLE_BIT = 0x20,
- DEMAND_DMA_DIRECTION_TX_BIT = 0x40,
- /* for ch 0, ch 1 can only transmit (when present) */
- LINE_VALID_ON_STATUS_VALID_BIT = 0x80,
- START_TX_BIT = 0x10,
- CABLE_THROTTLE_ENABLE_BIT = 0x20,
- TEST_MODE_ENABLE_BIT = 0x80000000,
-};
-
-enum board_status_bits {
- COMMAND_LINE_STATUS_MASK = 0x7f,
- TX_IN_PROGRESS_BIT = 0x80,
- TX_NOT_EMPTY_BIT = 0x100,
- TX_NOT_ALMOST_EMPTY_BIT = 0x200,
- TX_NOT_ALMOST_FULL_BIT = 0x400,
- TX_NOT_FULL_BIT = 0x800,
- RX_NOT_EMPTY_BIT = 0x1000,
- RX_NOT_ALMOST_EMPTY_BIT = 0x2000,
- RX_NOT_ALMOST_FULL_BIT = 0x4000,
- RX_NOT_FULL_BIT = 0x8000,
- BOARD_JUMPER0_INSTALLED_BIT = 0x10000,
- BOARD_JUMPER1_INSTALLED_BIT = 0x20000,
- TX_OVERRUN_BIT = 0x200000,
- RX_UNDERRUN_BIT = 0x400000,
- RX_OVERRUN_BIT = 0x800000,
-};
-
-static uint32_t almost_full_bits(unsigned int num_words)
-{
- /* XXX need to add or subtract one? */
- return (num_words << 16) & 0xff0000;
-}
-
-static uint32_t almost_empty_bits(unsigned int num_words)
-{
- return num_words & 0xffff;
-}
-
-enum features_bits {
- FIFO_SIZE_PRESENT_BIT = 0x1,
- FIFO_WORDS_PRESENT_BIT = 0x2,
- LEVEL_EDGE_INTERRUPTS_PRESENT_BIT = 0x4,
- GPIO_SUPPORTED_BIT = 0x8,
- PLX_DMA_CH1_SUPPORTED_BIT = 0x10,
- OVERRUN_UNDERRUN_SUPPORTED_BIT = 0x20,
-};
-
-enum interrupt_sources {
- FRAME_VALID_START_INTR = 0,
- FRAME_VALID_END_INTR = 1,
- TX_FIFO_EMPTY_INTR = 8,
- TX_FIFO_ALMOST_EMPTY_INTR = 9,
- TX_FIFO_ALMOST_FULL_INTR = 10,
- TX_FIFO_FULL_INTR = 11,
- RX_EMPTY_INTR = 12,
- RX_ALMOST_EMPTY_INTR = 13,
- RX_ALMOST_FULL_INTR = 14,
- RX_FULL_INTR = 15,
-};
-
-static uint32_t intr_bit(int interrupt_source)
-{
- return 0x1 << interrupt_source;
-}
-
-static unsigned int fifo_size(uint32_t fifo_size_bits)
-{
- return fifo_size_bits & 0xfffff;
-}
+/*
+ * PCI BAR2 Register map (devpriv->mmio)
+ */
+#define FIRMWARE_REV_REG 0x00
+#define FEATURES_REG_PRESENT_BIT (1 << 15)
+#define BOARD_CONTROL_REG 0x04
+#define BOARD_RESET_BIT (1 << 0)
+#define TX_FIFO_RESET_BIT (1 << 1)
+#define RX_FIFO_RESET_BIT (1 << 2)
+#define TX_ENABLE_BIT (1 << 4)
+#define RX_ENABLE_BIT (1 << 5)
+#define DEMAND_DMA_DIRECTION_TX_BIT (1 << 6) /* ch 0 only */
+#define LINE_VALID_ON_STATUS_VALID_BIT (1 << 7)
+#define START_TX_BIT (1 << 8)
+#define CABLE_THROTTLE_ENABLE_BIT (1 << 9)
+#define TEST_MODE_ENABLE_BIT (1 << 31)
+#define BOARD_STATUS_REG 0x08
+#define COMMAND_LINE_STATUS_MASK (0x7f << 0)
+#define TX_IN_PROGRESS_BIT (1 << 7)
+#define TX_NOT_EMPTY_BIT (1 << 8)
+#define TX_NOT_ALMOST_EMPTY_BIT (1 << 9)
+#define TX_NOT_ALMOST_FULL_BIT (1 << 10)
+#define TX_NOT_FULL_BIT (1 << 11)
+#define RX_NOT_EMPTY_BIT (1 << 12)
+#define RX_NOT_ALMOST_EMPTY_BIT (1 << 13)
+#define RX_NOT_ALMOST_FULL_BIT (1 << 14)
+#define RX_NOT_FULL_BIT (1 << 15)
+#define BOARD_JUMPER0_INSTALLED_BIT (1 << 16)
+#define BOARD_JUMPER1_INSTALLED_BIT (1 << 17)
+#define TX_OVERRUN_BIT (1 << 21)
+#define RX_UNDERRUN_BIT (1 << 22)
+#define RX_OVERRUN_BIT (1 << 23)
+#define TX_PROG_ALMOST_REG 0x0c
+#define RX_PROG_ALMOST_REG 0x10
+#define ALMOST_EMPTY_BITS(x) (((x) & 0xffff) << 0)
+#define ALMOST_FULL_BITS(x) (((x) & 0xff) << 16)
+#define FEATURES_REG 0x14
+#define FIFO_SIZE_PRESENT_BIT (1 << 0)
+#define FIFO_WORDS_PRESENT_BIT (1 << 1)
+#define LEVEL_EDGE_INTERRUPTS_PRESENT_BIT (1 << 2)
+#define GPIO_SUPPORTED_BIT (1 << 3)
+#define PLX_DMA_CH1_SUPPORTED_BIT (1 << 4)
+#define OVERRUN_UNDERRUN_SUPPORTED_BIT (1 << 5)
+#define FIFO_REG 0x18
+#define TX_STATUS_COUNT_REG 0x1c
+#define TX_LINE_VALID_COUNT_REG 0x20,
+#define TX_LINE_INVALID_COUNT_REG 0x24
+#define RX_STATUS_COUNT_REG 0x28
+#define RX_LINE_COUNT_REG 0x2c
+#define INTERRUPT_CONTROL_REG 0x30
+#define FRAME_VALID_START_INTR (1 << 0)
+#define FRAME_VALID_END_INTR (1 << 1)
+#define TX_FIFO_EMPTY_INTR (1 << 8)
+#define TX_FIFO_ALMOST_EMPTY_INTR (1 << 9)
+#define TX_FIFO_ALMOST_FULL_INTR (1 << 10)
+#define TX_FIFO_FULL_INTR (1 << 11)
+#define RX_EMPTY_INTR (1 << 12)
+#define RX_ALMOST_EMPTY_INTR (1 << 13)
+#define RX_ALMOST_FULL_INTR (1 << 14)
+#define RX_FULL_INTR (1 << 15)
+#define INTERRUPT_STATUS_REG 0x34
+#define TX_CLOCK_DIVIDER_REG 0x38
+#define TX_FIFO_SIZE_REG 0x40
+#define RX_FIFO_SIZE_REG 0x44
+#define FIFO_SIZE_MASK (0xfffff << 0)
+#define TX_FIFO_WORDS_REG 0x48
+#define RX_FIFO_WORDS_REG 0x4c
+#define INTERRUPT_EDGE_LEVEL_REG 0x50
+#define INTERRUPT_POLARITY_REG 0x54
+
+#define TIMER_BASE 50 /* 20MHz master clock */
+#define DMA_BUFFER_SIZE 0x10000
+#define NUM_DMA_BUFFERS 4
+#define NUM_DMA_DESCRIPTORS 256
struct hpdi_board {
- const char *name; /* board name */
- int device_id; /* pci device id */
- int subdevice_id; /* pci subdevice id */
+ const char *name;
+ int device_id;
+ int subdevice_id;
};
static const struct hpdi_board hpdi_boards[] = {
{
- .name = "pci-hpdi32",
- .device_id = PCI_DEVICE_ID_PLX_9080,
- .subdevice_id = 0x2400,
+ .name = "pci-hpdi32",
+ .device_id = PCI_DEVICE_ID_PLX_9080,
+ .subdevice_id = 0x2400,
},
#if 0
{
- .name = "pxi-hpdi32",
- .device_id = 0x9656,
- .subdevice_id = 0x2705,
+ .name = "pxi-hpdi32",
+ .device_id = 0x9656,
+ .subdevice_id = 0x2705,
},
#endif
};
struct hpdi_private {
- /* base addresses (ioremapped) */
- void __iomem *plx9080_iobase;
- void __iomem *hpdi_iobase;
+ void __iomem *plx9080_mmio;
+ void __iomem *mmio;
uint32_t *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */
/* physical addresses of dma buffers */
dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS];
@@ -207,26 +161,334 @@ struct hpdi_private {
/* pointer to start of buffers indexed by descriptor */
uint32_t *desc_dio_buffer[NUM_DMA_DESCRIPTORS];
/* index of the dma descriptor that is currently being used */
- volatile unsigned int dma_desc_index;
+ unsigned int dma_desc_index;
unsigned int tx_fifo_size;
unsigned int rx_fifo_size;
- volatile unsigned long dio_count;
- /* software copies of values written to hpdi registers */
- volatile uint32_t bits[24];
+ unsigned long dio_count;
/* number of bytes at which to generate COMEDI_CB_BLOCK events */
- volatile unsigned int block_size;
+ unsigned int block_size;
};
-static int dio_config_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static void gsc_hpdi_drain_dma(struct comedi_device *dev, unsigned int channel)
+{
+ struct hpdi_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int idx;
+ unsigned int start;
+ unsigned int desc;
+ unsigned int size;
+ unsigned int next;
+
+ if (channel)
+ next = readl(devpriv->plx9080_mmio + PLX_DMA1_PCI_ADDRESS_REG);
+ else
+ next = readl(devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG);
+
+ idx = devpriv->dma_desc_index;
+ start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr);
+ /* loop until we have read all the full buffers */
+ for (desc = 0; (next < start || next >= start + devpriv->block_size) &&
+ desc < devpriv->num_dma_descriptors; desc++) {
+ /* transfer data from dma buffer to comedi buffer */
+ size = devpriv->block_size / sizeof(uint32_t);
+ if (cmd->stop_src == TRIG_COUNT) {
+ if (size > devpriv->dio_count)
+ size = devpriv->dio_count;
+ devpriv->dio_count -= size;
+ }
+ cfc_write_array_to_buffer(s, devpriv->desc_dio_buffer[idx],
+ size * sizeof(uint32_t));
+ idx++;
+ idx %= devpriv->num_dma_descriptors;
+ start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr);
+
+ devpriv->dma_desc_index = idx;
+ }
+ /* XXX check for buffer overrun somehow */
+}
+
+static irqreturn_t gsc_hpdi_interrupt(int irq, void *d)
+{
+ struct comedi_device *dev = d;
+ struct hpdi_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_async *async = s->async;
+ uint32_t hpdi_intr_status, hpdi_board_status;
+ uint32_t plx_status;
+ uint32_t plx_bits;
+ uint8_t dma0_status, dma1_status;
+ unsigned long flags;
+
+ if (!dev->attached)
+ return IRQ_NONE;
+
+ plx_status = readl(devpriv->plx9080_mmio + PLX_INTRCS_REG);
+ if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0)
+ return IRQ_NONE;
+
+ hpdi_intr_status = readl(devpriv->mmio + INTERRUPT_STATUS_REG);
+ hpdi_board_status = readl(devpriv->mmio + BOARD_STATUS_REG);
+
+ if (hpdi_intr_status)
+ writel(hpdi_intr_status, devpriv->mmio + INTERRUPT_STATUS_REG);
+
+ /* spin lock makes sure no one else changes plx dma control reg */
+ spin_lock_irqsave(&dev->spinlock, flags);
+ dma0_status = readb(devpriv->plx9080_mmio + PLX_DMA0_CS_REG);
+ if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */
+ writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT,
+ devpriv->plx9080_mmio + PLX_DMA0_CS_REG);
+
+ if (dma0_status & PLX_DMA_EN_BIT)
+ gsc_hpdi_drain_dma(dev, 0);
+ }
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+
+ /* spin lock makes sure no one else changes plx dma control reg */
+ spin_lock_irqsave(&dev->spinlock, flags);
+ dma1_status = readb(devpriv->plx9080_mmio + PLX_DMA1_CS_REG);
+ if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */
+ writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT,
+ devpriv->plx9080_mmio + PLX_DMA1_CS_REG);
+ }
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+
+ /* clear possible plx9080 interrupt sources */
+ if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */
+ plx_bits = readl(devpriv->plx9080_mmio + PLX_DBR_OUT_REG);
+ writel(plx_bits, devpriv->plx9080_mmio + PLX_DBR_OUT_REG);
+ }
+
+ if (hpdi_board_status & RX_OVERRUN_BIT) {
+ dev_err(dev->class_dev, "rx fifo overrun\n");
+ async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ }
+
+ if (hpdi_board_status & RX_UNDERRUN_BIT) {
+ dev_err(dev->class_dev, "rx fifo underrun\n");
+ async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ }
+
+ if (devpriv->dio_count == 0)
+ async->events |= COMEDI_CB_EOA;
+
+ cfc_handle_events(dev, s);
+
+ return IRQ_HANDLED;
+}
+
+static void gsc_hpdi_abort_dma(struct comedi_device *dev, unsigned int channel)
+{
+ struct hpdi_private *devpriv = dev->private;
+ unsigned long flags;
+
+ /* spinlock for plx dma control/status reg */
+ spin_lock_irqsave(&dev->spinlock, flags);
+
+ plx9080_abort_dma(devpriv->plx9080_mmio, channel);
+
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+}
+
+static int gsc_hpdi_cancel(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct hpdi_private *devpriv = dev->private;
+
+ writel(0, devpriv->mmio + BOARD_CONTROL_REG);
+ writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG);
+
+ gsc_hpdi_abort_dma(dev, 0);
+
+ return 0;
+}
+
+static int gsc_hpdi_cmd(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct hpdi_private *devpriv = dev->private;
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ unsigned long flags;
+ uint32_t bits;
+
+ if (s->io_bits)
+ return -EINVAL;
+
+ writel(RX_FIFO_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG);
+
+ gsc_hpdi_abort_dma(dev, 0);
+
+ devpriv->dma_desc_index = 0;
+
+ /*
+ * These register are supposedly unused during chained dma,
+ * but I have found that left over values from last operation
+ * occasionally cause problems with transfer of first dma
+ * block. Initializing them to zero seems to fix the problem.
+ */
+ writel(0, devpriv->plx9080_mmio + PLX_DMA0_TRANSFER_SIZE_REG);
+ writel(0, devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG);
+ writel(0, devpriv->plx9080_mmio + PLX_DMA0_LOCAL_ADDRESS_REG);
+
+ /* give location of first dma descriptor */
+ bits = devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT |
+ PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI;
+ writel(bits, devpriv->plx9080_mmio + PLX_DMA0_DESCRIPTOR_REG);
+
+ /* enable dma transfer */
+ spin_lock_irqsave(&dev->spinlock, flags);
+ writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT,
+ devpriv->plx9080_mmio + PLX_DMA0_CS_REG);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+
+ if (cmd->stop_src == TRIG_COUNT)
+ devpriv->dio_count = cmd->stop_arg;
+ else
+ devpriv->dio_count = 1;
+
+ /* clear over/under run status flags */
+ writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT,
+ devpriv->mmio + BOARD_STATUS_REG);
+
+ /* enable interrupts */
+ writel(RX_FULL_INTR, devpriv->mmio + INTERRUPT_CONTROL_REG);
+
+ writel(RX_ENABLE_BIT, devpriv->mmio + BOARD_CONTROL_REG);
+
+ return 0;
+}
+
+static int gsc_hpdi_cmd_test(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ int err = 0;
+ int i;
+
+ if (s->io_bits)
+ return -EINVAL;
+
+ /* Step 1 : check if triggers are trivially valid */
+
+ err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+ err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+ err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+ err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+ err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
+
+ if (err)
+ return 1;
+
+ /* Step 2a : make sure trigger sources are unique */
+
+ err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+ /* Step 2b : and mutually compatible */
+
+ if (err)
+ return 2;
+
+ /* Step 3: check if arguments are trivially valid */
+
+ if (!cmd->chanlist_len || !cmd->chanlist) {
+ cmd->chanlist_len = 32;
+ err |= -EINVAL;
+ }
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+
+ if (cmd->stop_src == TRIG_COUNT)
+ err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
+ else /* TRIG_NONE */
+ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
+
+ if (err)
+ return 3;
+
+ /* step 4: fix up any arguments */
+
+ if (err)
+ return 4;
+
+ /* step 5: complain about special chanlist considerations */
+
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ if (CR_CHAN(cmd->chanlist[i]) != i) {
+ /* XXX could support 8 or 16 channels */
+ dev_err(dev->class_dev,
+ "chanlist must be ch 0 to 31 in order");
+ err |= -EINVAL;
+ break;
+ }
+ }
+
+ if (err)
+ return 5;
+
+ return 0;
+
+}
+
+/* setup dma descriptors so a link completes every 'len' bytes */
+static int gsc_hpdi_setup_dma_descriptors(struct comedi_device *dev,
+ unsigned int len)
+{
+ struct hpdi_private *devpriv = dev->private;
+ dma_addr_t phys_addr = devpriv->dma_desc_phys_addr;
+ uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT |
+ PLX_XFER_LOCAL_TO_PCI;
+ unsigned int offset = 0;
+ unsigned int idx = 0;
+ unsigned int i;
+
+ if (len > DMA_BUFFER_SIZE)
+ len = DMA_BUFFER_SIZE;
+ len -= len % sizeof(uint32_t);
+ if (len == 0)
+ return -EINVAL;
+
+ for (i = 0; i < NUM_DMA_DESCRIPTORS && idx < NUM_DMA_BUFFERS; i++) {
+ devpriv->dma_desc[i].pci_start_addr =
+ cpu_to_le32(devpriv->dio_buffer_phys_addr[idx] + offset);
+ devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG);
+ devpriv->dma_desc[i].transfer_size = cpu_to_le32(len);
+ devpriv->dma_desc[i].next = cpu_to_le32((phys_addr +
+ (i + 1) * sizeof(devpriv->dma_desc[0])) | next_bits);
+
+ devpriv->desc_dio_buffer[i] = devpriv->dio_buffer[idx] +
+ (offset / sizeof(uint32_t));
+
+ offset += len;
+ if (len + offset > DMA_BUFFER_SIZE) {
+ offset = 0;
+ idx++;
+ }
+ }
+ devpriv->num_dma_descriptors = i;
+ /* fix last descriptor to point back to first */
+ devpriv->dma_desc[i - 1].next = cpu_to_le32(phys_addr | next_bits);
+
+ devpriv->block_size = len;
+
+ return len;
+}
+
+static int gsc_hpdi_dio_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
int ret;
switch (data[0]) {
case INSN_CONFIG_BLOCK_SIZE:
- return dio_config_block_size(dev, data);
+ ret = gsc_hpdi_setup_dma_descriptors(dev, data[1]);
+ if (ret)
+ return ret;
+
+ data[1] = ret;
+ break;
default:
ret = comedi_dio_insn_config(dev, s, insn, data, 0xffffffff);
if (ret)
@@ -237,31 +499,53 @@ static int dio_config_insn(struct comedi_device *dev,
return insn->n;
}
-static void disable_plx_interrupts(struct comedi_device *dev)
+static int gsc_hpdi_init(struct comedi_device *dev)
{
struct hpdi_private *devpriv = dev->private;
+ uint32_t plx_intcsr_bits;
+
+ /* wait 10usec after reset before accessing fifos */
+ writel(BOARD_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG);
+ udelay(10);
+
+ writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32),
+ devpriv->mmio + RX_PROG_ALMOST_REG);
+ writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32),
+ devpriv->mmio + TX_PROG_ALMOST_REG);
- writel(0, devpriv->plx9080_iobase + PLX_INTRCS_REG);
+ devpriv->tx_fifo_size = readl(devpriv->mmio + TX_FIFO_SIZE_REG) &
+ FIFO_SIZE_MASK;
+ devpriv->rx_fifo_size = readl(devpriv->mmio + RX_FIFO_SIZE_REG) &
+ FIFO_SIZE_MASK;
+
+ writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG);
+
+ /* enable interrupts */
+ plx_intcsr_bits =
+ ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE |
+ ICS_DMA0_E;
+ writel(plx_intcsr_bits, devpriv->plx9080_mmio + PLX_INTRCS_REG);
+
+ return 0;
}
-/* initialize plx9080 chip */
-static void init_plx9080(struct comedi_device *dev)
+static void gsc_hpdi_init_plx9080(struct comedi_device *dev)
{
struct hpdi_private *devpriv = dev->private;
uint32_t bits;
- void __iomem *plx_iobase = devpriv->plx9080_iobase;
+ void __iomem *plx_iobase = devpriv->plx9080_mmio;
#ifdef __BIG_ENDIAN
bits = BIGEND_DMA0 | BIGEND_DMA1;
#else
bits = 0;
#endif
- writel(bits, devpriv->plx9080_iobase + PLX_BIGEND_REG);
+ writel(bits, devpriv->plx9080_mmio + PLX_BIGEND_REG);
- disable_plx_interrupts(dev);
+ writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG);
- abort_dma(dev, 0);
- abort_dma(dev, 1);
+ gsc_hpdi_abort_dma(dev, 0);
+ gsc_hpdi_abort_dma(dev, 1);
/* configure dma0 mode */
bits = 0;
@@ -285,117 +569,7 @@ static void init_plx9080(struct comedi_device *dev)
writel(bits, plx_iobase + PLX_DMA0_MODE_REG);
}
-/* Allocate and initialize the subdevice structures.
- */
-static int setup_subdevices(struct comedi_device *dev)
-{
- struct comedi_subdevice *s;
- int ret;
-
- ret = comedi_alloc_subdevices(dev, 1);
- if (ret)
- return ret;
-
- s = &dev->subdevices[0];
- /* analog input subdevice */
- dev->read_subdev = s;
-/* dev->write_subdev = s; */
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags =
- SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL | SDF_CMD_READ;
- s->n_chan = 32;
- s->len_chanlist = 32;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_config = dio_config_insn;
- s->do_cmd = hpdi_cmd;
- s->do_cmdtest = hpdi_cmd_test;
- s->cancel = hpdi_cancel;
-
- return 0;
-}
-
-static int init_hpdi(struct comedi_device *dev)
-{
- struct hpdi_private *devpriv = dev->private;
- uint32_t plx_intcsr_bits;
-
- writel(BOARD_RESET_BIT, devpriv->hpdi_iobase + BOARD_CONTROL_REG);
- udelay(10);
-
- writel(almost_empty_bits(32) | almost_full_bits(32),
- devpriv->hpdi_iobase + RX_PROG_ALMOST_REG);
- writel(almost_empty_bits(32) | almost_full_bits(32),
- devpriv->hpdi_iobase + TX_PROG_ALMOST_REG);
-
- devpriv->tx_fifo_size = fifo_size(readl(devpriv->hpdi_iobase +
- TX_FIFO_SIZE_REG));
- devpriv->rx_fifo_size = fifo_size(readl(devpriv->hpdi_iobase +
- RX_FIFO_SIZE_REG));
-
- writel(0, devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG);
-
- /* enable interrupts */
- plx_intcsr_bits =
- ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE |
- ICS_DMA0_E;
- writel(plx_intcsr_bits, devpriv->plx9080_iobase + PLX_INTRCS_REG);
-
- return 0;
-}
-
-/* setup dma descriptors so a link completes every 'transfer_size' bytes */
-static int setup_dma_descriptors(struct comedi_device *dev,
- unsigned int transfer_size)
-{
- struct hpdi_private *devpriv = dev->private;
- unsigned int buffer_index, buffer_offset;
- uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT |
- PLX_XFER_LOCAL_TO_PCI;
- unsigned int i;
-
- if (transfer_size > DMA_BUFFER_SIZE)
- transfer_size = DMA_BUFFER_SIZE;
- transfer_size -= transfer_size % sizeof(uint32_t);
- if (transfer_size == 0)
- return -1;
-
- buffer_offset = 0;
- buffer_index = 0;
- for (i = 0; i < NUM_DMA_DESCRIPTORS &&
- buffer_index < NUM_DMA_BUFFERS; i++) {
- devpriv->dma_desc[i].pci_start_addr =
- cpu_to_le32(devpriv->dio_buffer_phys_addr[buffer_index] +
- buffer_offset);
- devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG);
- devpriv->dma_desc[i].transfer_size =
- cpu_to_le32(transfer_size);
- devpriv->dma_desc[i].next =
- cpu_to_le32((devpriv->dma_desc_phys_addr + (i +
- 1) *
- sizeof(devpriv->dma_desc[0])) | next_bits);
-
- devpriv->desc_dio_buffer[i] =
- devpriv->dio_buffer[buffer_index] +
- (buffer_offset / sizeof(uint32_t));
-
- buffer_offset += transfer_size;
- if (transfer_size + buffer_offset > DMA_BUFFER_SIZE) {
- buffer_offset = 0;
- buffer_index++;
- }
- }
- devpriv->num_dma_descriptors = i;
- /* fix last descriptor to point back to first */
- devpriv->dma_desc[i - 1].next =
- cpu_to_le32(devpriv->dma_desc_phys_addr | next_bits);
-
- devpriv->block_size = transfer_size;
-
- return transfer_size;
-}
-
-static const struct hpdi_board *hpdi_find_board(struct pci_dev *pcidev)
+static const struct hpdi_board *gsc_hpdi_find_board(struct pci_dev *pcidev)
{
unsigned int i;
@@ -406,16 +580,17 @@ static const struct hpdi_board *hpdi_find_board(struct pci_dev *pcidev)
return NULL;
}
-static int hpdi_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+static int gsc_hpdi_auto_attach(struct comedi_device *dev,
+ unsigned long context_unused)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
const struct hpdi_board *thisboard;
struct hpdi_private *devpriv;
+ struct comedi_subdevice *s;
int i;
int retval;
- thisboard = hpdi_find_board(pcidev);
+ thisboard = gsc_hpdi_find_board(pcidev);
if (!thisboard) {
dev_err(dev->class_dev, "gsc_hpdi: pci %s not supported\n",
pci_name(pcidev));
@@ -433,17 +608,17 @@ static int hpdi_auto_attach(struct comedi_device *dev,
return retval;
pci_set_master(pcidev);
- devpriv->plx9080_iobase = pci_ioremap_bar(pcidev, 0);
- devpriv->hpdi_iobase = pci_ioremap_bar(pcidev, 2);
- if (!devpriv->plx9080_iobase || !devpriv->hpdi_iobase) {
+ devpriv->plx9080_mmio = pci_ioremap_bar(pcidev, 0);
+ devpriv->mmio = pci_ioremap_bar(pcidev, 2);
+ if (!devpriv->plx9080_mmio || !devpriv->mmio) {
dev_warn(dev->class_dev, "failed to remap io memory\n");
return -ENOMEM;
}
- init_plx9080(dev);
+ gsc_hpdi_init_plx9080(dev);
/* get irq */
- if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED,
+ if (request_irq(pcidev->irq, gsc_hpdi_interrupt, IRQF_SHARED,
dev->board_name, dev)) {
dev_warn(dev->class_dev,
"unable to allocate irq %u\n", pcidev->irq);
@@ -470,18 +645,33 @@ static int hpdi_auto_attach(struct comedi_device *dev,
return -EIO;
}
- retval = setup_dma_descriptors(dev, 0x1000);
+ retval = gsc_hpdi_setup_dma_descriptors(dev, 0x1000);
if (retval < 0)
return retval;
- retval = setup_subdevices(dev);
- if (retval < 0)
+ retval = comedi_alloc_subdevices(dev, 1);
+ if (retval)
return retval;
- return init_hpdi(dev);
+ /* Digital I/O subdevice */
+ s = &dev->subdevices[0];
+ dev->read_subdev = s;
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL |
+ SDF_CMD_READ;
+ s->n_chan = 32;
+ s->len_chanlist = 32;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_config = gsc_hpdi_dio_insn_config;
+ s->do_cmd = gsc_hpdi_cmd;
+ s->do_cmdtest = gsc_hpdi_cmd_test;
+ s->cancel = gsc_hpdi_cancel;
+
+ return gsc_hpdi_init(dev);
}
-static void hpdi_detach(struct comedi_device *dev)
+static void gsc_hpdi_detach(struct comedi_device *dev)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct hpdi_private *devpriv = dev->private;
@@ -490,12 +680,12 @@ static void hpdi_detach(struct comedi_device *dev)
if (dev->irq)
free_irq(dev->irq, dev);
if (devpriv) {
- if (devpriv->plx9080_iobase) {
- disable_plx_interrupts(dev);
- iounmap(devpriv->plx9080_iobase);
+ if (devpriv->plx9080_mmio) {
+ writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG);
+ iounmap(devpriv->plx9080_mmio);
}
- if (devpriv->hpdi_iobase)
- iounmap(devpriv->hpdi_iobase);
+ if (devpriv->mmio)
+ iounmap(devpriv->mmio);
/* free pci dma buffers */
for (i = 0; i < NUM_DMA_BUFFERS; i++) {
if (devpriv->dio_buffer[i])
@@ -516,318 +706,11 @@ static void hpdi_detach(struct comedi_device *dev)
comedi_pci_disable(dev);
}
-static int dio_config_block_size(struct comedi_device *dev, unsigned int *data)
-{
- unsigned int requested_block_size;
- int retval;
-
- requested_block_size = data[1];
-
- retval = setup_dma_descriptors(dev, requested_block_size);
- if (retval < 0)
- return retval;
-
- data[1] = retval;
-
- return 2;
-}
-
-static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
-{
- int err = 0;
- int i;
-
- /* Step 1 : check if triggers are trivially valid */
-
- err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
- err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
- err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
- err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
- err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
-
- if (err)
- return 1;
-
- /* Step 2a : make sure trigger sources are unique */
-
- err |= cfc_check_trigger_is_unique(cmd->stop_src);
-
- /* Step 2b : and mutually compatible */
-
- if (err)
- return 2;
-
- /* Step 3: check if arguments are trivially valid */
-
- if (!cmd->chanlist_len) {
- cmd->chanlist_len = 32;
- err |= -EINVAL;
- }
- err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
-
- switch (cmd->stop_src) {
- case TRIG_COUNT:
- err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
- break;
- case TRIG_NONE:
- err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
- break;
- default:
- break;
- }
-
- if (err)
- return 3;
-
- /* step 4: fix up any arguments */
-
- if (err)
- return 4;
-
- if (!cmd->chanlist)
- return 0;
-
- for (i = 1; i < cmd->chanlist_len; i++) {
- if (CR_CHAN(cmd->chanlist[i]) != i) {
- /* XXX could support 8 or 16 channels */
- comedi_error(dev,
- "chanlist must be ch 0 to 31 in order");
- err++;
- break;
- }
- }
-
- if (err)
- return 5;
-
- return 0;
-}
-
-static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
-{
- if (s->io_bits)
- return -EINVAL;
- else
- return di_cmd_test(dev, s, cmd);
-}
-
-static inline void hpdi_writel(struct comedi_device *dev, uint32_t bits,
- unsigned int offset)
-{
- struct hpdi_private *devpriv = dev->private;
-
- writel(bits | devpriv->bits[offset / sizeof(uint32_t)],
- devpriv->hpdi_iobase + offset);
-}
-
-static int di_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- struct hpdi_private *devpriv = dev->private;
- uint32_t bits;
- unsigned long flags;
- struct comedi_async *async = s->async;
- struct comedi_cmd *cmd = &async->cmd;
-
- hpdi_writel(dev, RX_FIFO_RESET_BIT, BOARD_CONTROL_REG);
-
- abort_dma(dev, 0);
-
- devpriv->dma_desc_index = 0;
-
- /* These register are supposedly unused during chained dma,
- * but I have found that left over values from last operation
- * occasionally cause problems with transfer of first dma
- * block. Initializing them to zero seems to fix the problem. */
- writel(0, devpriv->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG);
- writel(0, devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG);
- writel(0, devpriv->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG);
- /* give location of first dma descriptor */
- bits =
- devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT |
- PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI;
- writel(bits, devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG);
-
- /* spinlock for plx dma control/status reg */
- spin_lock_irqsave(&dev->spinlock, flags);
- /* enable dma transfer */
- writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT,
- devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- if (cmd->stop_src == TRIG_COUNT)
- devpriv->dio_count = cmd->stop_arg;
- else
- devpriv->dio_count = 1;
-
- /* clear over/under run status flags */
- writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT,
- devpriv->hpdi_iobase + BOARD_STATUS_REG);
- /* enable interrupts */
- writel(intr_bit(RX_FULL_INTR),
- devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG);
-
- hpdi_writel(dev, RX_ENABLE_BIT, BOARD_CONTROL_REG);
-
- return 0;
-}
-
-static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- if (s->io_bits)
- return -EINVAL;
- else
- return di_cmd(dev, s);
-}
-
-static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel)
-{
- struct hpdi_private *devpriv = dev->private;
- struct comedi_async *async = dev->read_subdev->async;
- uint32_t next_transfer_addr;
- int j;
- int num_samples = 0;
- void __iomem *pci_addr_reg;
-
- if (channel)
- pci_addr_reg =
- devpriv->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG;
- else
- pci_addr_reg =
- devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG;
-
- /* loop until we have read all the full buffers */
- j = 0;
- for (next_transfer_addr = readl(pci_addr_reg);
- (next_transfer_addr <
- le32_to_cpu(devpriv->dma_desc[devpriv->dma_desc_index].
- pci_start_addr)
- || next_transfer_addr >=
- le32_to_cpu(devpriv->dma_desc[devpriv->dma_desc_index].
- pci_start_addr) + devpriv->block_size)
- && j < devpriv->num_dma_descriptors; j++) {
- /* transfer data from dma buffer to comedi buffer */
- num_samples = devpriv->block_size / sizeof(uint32_t);
- if (async->cmd.stop_src == TRIG_COUNT) {
- if (num_samples > devpriv->dio_count)
- num_samples = devpriv->dio_count;
- devpriv->dio_count -= num_samples;
- }
- cfc_write_array_to_buffer(dev->read_subdev,
- devpriv->desc_dio_buffer[devpriv->
- dma_desc_index],
- num_samples * sizeof(uint32_t));
- devpriv->dma_desc_index++;
- devpriv->dma_desc_index %= devpriv->num_dma_descriptors;
- }
- /* XXX check for buffer overrun somehow */
-}
-
-static irqreturn_t handle_interrupt(int irq, void *d)
-{
- struct comedi_device *dev = d;
- struct hpdi_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
- struct comedi_async *async = s->async;
- uint32_t hpdi_intr_status, hpdi_board_status;
- uint32_t plx_status;
- uint32_t plx_bits;
- uint8_t dma0_status, dma1_status;
- unsigned long flags;
-
- if (!dev->attached)
- return IRQ_NONE;
-
- plx_status = readl(devpriv->plx9080_iobase + PLX_INTRCS_REG);
- if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0)
- return IRQ_NONE;
-
- hpdi_intr_status = readl(devpriv->hpdi_iobase + INTERRUPT_STATUS_REG);
- hpdi_board_status = readl(devpriv->hpdi_iobase + BOARD_STATUS_REG);
-
- async->events = 0;
-
- if (hpdi_intr_status) {
- writel(hpdi_intr_status,
- devpriv->hpdi_iobase + INTERRUPT_STATUS_REG);
- }
- /* spin lock makes sure no one else changes plx dma control reg */
- spin_lock_irqsave(&dev->spinlock, flags);
- dma0_status = readb(devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
- if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */
- writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT,
- devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
-
- if (dma0_status & PLX_DMA_EN_BIT)
- drain_dma_buffers(dev, 0);
- }
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- /* spin lock makes sure no one else changes plx dma control reg */
- spin_lock_irqsave(&dev->spinlock, flags);
- dma1_status = readb(devpriv->plx9080_iobase + PLX_DMA1_CS_REG);
- if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */
- writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT,
- devpriv->plx9080_iobase + PLX_DMA1_CS_REG);
- }
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- /* clear possible plx9080 interrupt sources */
- if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */
- plx_bits = readl(devpriv->plx9080_iobase + PLX_DBR_OUT_REG);
- writel(plx_bits, devpriv->plx9080_iobase + PLX_DBR_OUT_REG);
- }
-
- if (hpdi_board_status & RX_OVERRUN_BIT) {
- comedi_error(dev, "rx fifo overrun");
- async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- }
-
- if (hpdi_board_status & RX_UNDERRUN_BIT) {
- comedi_error(dev, "rx fifo underrun");
- async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- }
-
- if (devpriv->dio_count == 0)
- async->events |= COMEDI_CB_EOA;
-
- cfc_handle_events(dev, s);
-
- return IRQ_HANDLED;
-}
-
-static void abort_dma(struct comedi_device *dev, unsigned int channel)
-{
- struct hpdi_private *devpriv = dev->private;
- unsigned long flags;
-
- /* spinlock for plx dma control/status reg */
- spin_lock_irqsave(&dev->spinlock, flags);
-
- plx9080_abort_dma(devpriv->plx9080_iobase, channel);
-
- spin_unlock_irqrestore(&dev->spinlock, flags);
-}
-
-static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- struct hpdi_private *devpriv = dev->private;
-
- hpdi_writel(dev, 0, BOARD_CONTROL_REG);
-
- writel(0, devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG);
-
- abort_dma(dev, 0);
-
- return 0;
-}
-
static struct comedi_driver gsc_hpdi_driver = {
.driver_name = "gsc_hpdi",
.module = THIS_MODULE,
- .auto_attach = hpdi_auto_attach,
- .detach = hpdi_detach,
+ .auto_attach = gsc_hpdi_auto_attach,
+ .detach = gsc_hpdi_detach,
};
static int gsc_hpdi_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c
index 80539b2bea1a..0b8b2162b76b 100644
--- a/drivers/staging/comedi/drivers/icp_multi.c
+++ b/drivers/staging/comedi/drivers/icp_multi.c
@@ -171,12 +171,27 @@ static void setup_channel_list(struct comedi_device *dev,
}
}
+static int icp_multi_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct icp_multi_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readw(devpriv->io_addr + ICP_MULTI_ADC_CSR);
+ if ((status & ADC_BSY) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int icp_multi_insn_read_ai(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct icp_multi_private *devpriv = dev->private;
- int n, timeout;
+ int ret = 0;
+ int n;
/* Disable A/D conversion ready interrupt */
devpriv->IntEnable &= ~ADC_READY;
@@ -199,33 +214,10 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev,
udelay(1);
/* Wait for conversion to complete, or get fed up waiting */
- timeout = 100;
- while (timeout--) {
- if (!(readw(devpriv->io_addr +
- ICP_MULTI_ADC_CSR) & ADC_BSY))
- goto conv_finish;
-
- udelay(1);
- }
-
- /* If we reach here, a timeout has occurred */
- comedi_error(dev, "A/D insn timeout");
-
- /* Disable interrupt */
- devpriv->IntEnable &= ~ADC_READY;
- writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN);
-
- /* Clear interrupt status */
- devpriv->IntStatus |= ADC_READY;
- writew(devpriv->IntStatus,
- devpriv->io_addr + ICP_MULTI_INT_STAT);
+ ret = comedi_timeout(dev, s, insn, icp_multi_ai_eoc, 0);
+ if (ret)
+ break;
- /* Clear data received */
- data[n] = 0;
-
- return -ETIME;
-
-conv_finish:
data[n] =
(readw(devpriv->io_addr + ICP_MULTI_AI) >> 4) & 0x0fff;
}
@@ -238,7 +230,21 @@ conv_finish:
devpriv->IntStatus |= ADC_READY;
writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT);
- return n;
+ return ret ? ret : n;
+}
+
+static int icp_multi_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct icp_multi_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readw(devpriv->io_addr + ICP_MULTI_DAC_CSR);
+ if ((status & DAC_BSY) == 0)
+ return 0;
+ return -EBUSY;
}
static int icp_multi_insn_write_ao(struct comedi_device *dev,
@@ -246,7 +252,8 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev,
struct comedi_insn *insn, unsigned int *data)
{
struct icp_multi_private *devpriv = dev->private;
- int n, chan, range, timeout;
+ int n, chan, range;
+ int ret;
/* Disable D/A conversion ready interrupt */
devpriv->IntEnable &= ~DAC_READY;
@@ -274,33 +281,24 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev,
for (n = 0; n < insn->n; n++) {
/* Wait for analogue output data register to be
* ready for new data, or get fed up waiting */
- timeout = 100;
- while (timeout--) {
- if (!(readw(devpriv->io_addr +
- ICP_MULTI_DAC_CSR) & DAC_BSY))
- goto dac_ready;
-
- udelay(1);
+ ret = comedi_timeout(dev, s, insn, icp_multi_ao_eoc, 0);
+ if (ret) {
+ /* Disable interrupt */
+ devpriv->IntEnable &= ~DAC_READY;
+ writew(devpriv->IntEnable,
+ devpriv->io_addr + ICP_MULTI_INT_EN);
+
+ /* Clear interrupt status */
+ devpriv->IntStatus |= DAC_READY;
+ writew(devpriv->IntStatus,
+ devpriv->io_addr + ICP_MULTI_INT_STAT);
+
+ /* Clear data received */
+ devpriv->ao_data[chan] = 0;
+
+ return ret;
}
- /* If we reach here, a timeout has occurred */
- comedi_error(dev, "D/A insn timeout");
-
- /* Disable interrupt */
- devpriv->IntEnable &= ~DAC_READY;
- writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN);
-
- /* Clear interrupt status */
- devpriv->IntStatus |= DAC_READY;
- writew(devpriv->IntStatus,
- devpriv->io_addr + ICP_MULTI_INT_STAT);
-
- /* Clear data received */
- devpriv->ao_data[chan] = 0;
-
- return -ETIME;
-
-dac_ready:
/* Write data to analogue output data register */
writew(data[n], devpriv->io_addr + ICP_MULTI_AO);
@@ -565,9 +563,6 @@ static int icp_multi_auto_attach(struct comedi_device *dev,
devpriv->valid = 1;
- dev_info(dev->class_dev, "%s attached, irq %sabled\n",
- dev->board_name, dev->irq ? "en" : "dis");
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index 8577778441fa..3558ab3b6e1f 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -190,20 +190,18 @@ static int ii20k_ao_insn_write(struct comedi_device *dev,
return insn->n;
}
-static int ii20k_ai_wait_eoc(struct comedi_device *dev,
- struct comedi_subdevice *s,
- int timeout)
+static int ii20k_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
void __iomem *iobase = ii20k_module_iobase(dev, s);
unsigned char status;
- do {
- status = readb(iobase + II20K_AI_STATUS_REG);
- if ((status & II20K_AI_STATUS_INT) == 0)
- return 0;
- } while (timeout--);
-
- return -ETIME;
+ status = readb(iobase + II20K_AI_STATUS_REG);
+ if ((status & II20K_AI_STATUS_INT) == 0)
+ return 0;
+ return -EBUSY;
}
static void ii20k_ai_setup(struct comedi_device *dev,
@@ -263,7 +261,7 @@ static int ii20k_ai_insn_read(struct comedi_device *dev,
/* generate a software start convert signal */
readb(iobase + II20K_AI_PACER_RESET_REG);
- ret = ii20k_ai_wait_eoc(dev, s, 100);
+ ret = comedi_timeout(dev, s, insn, ii20k_ai_eoc, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 6100c12c164f..a8db9d86aadc 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -51,23 +51,55 @@
#include "jr3_pci.h"
#define PCI_VENDOR_ID_JR3 0x1762
-#define PCI_DEVICE_ID_JR3_1_CHANNEL 0x3111
-#define PCI_DEVICE_ID_JR3_1_CHANNEL_NEW 0x1111
-#define PCI_DEVICE_ID_JR3_2_CHANNEL 0x3112
-#define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113
-#define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114
-struct jr3_pci_dev_private {
- struct jr3_t __iomem *iobase;
- int n_channels;
- struct timer_list timer;
+enum jr3_pci_boardid {
+ BOARD_JR3_1,
+ BOARD_JR3_2,
+ BOARD_JR3_3,
+ BOARD_JR3_4,
};
-struct poll_delay_t {
+struct jr3_pci_board {
+ const char *name;
+ int n_subdevs;
+};
+
+static const struct jr3_pci_board jr3_pci_boards[] = {
+ [BOARD_JR3_1] = {
+ .name = "jr3_pci_1",
+ .n_subdevs = 1,
+ },
+ [BOARD_JR3_2] = {
+ .name = "jr3_pci_2",
+ .n_subdevs = 2,
+ },
+ [BOARD_JR3_3] = {
+ .name = "jr3_pci_3",
+ .n_subdevs = 3,
+ },
+ [BOARD_JR3_4] = {
+ .name = "jr3_pci_4",
+ .n_subdevs = 4,
+ },
+};
+
+struct jr3_pci_transform {
+ struct {
+ u16 link_type;
+ s16 link_amount;
+ } link[8];
+};
+
+struct jr3_pci_poll_delay {
int min;
int max;
};
+struct jr3_pci_dev_private {
+ struct jr3_t __iomem *iobase;
+ struct timer_list timer;
+};
+
struct jr3_pci_subdev_private {
struct jr3_channel __iomem *channel;
unsigned long next_time_min;
@@ -79,7 +111,6 @@ struct jr3_pci_subdev_private {
state_jr3_init_use_offset_complete,
state_jr3_done
} state;
- int channel_no;
int serial_no;
int model_no;
struct {
@@ -92,9 +123,9 @@ struct jr3_pci_subdev_private {
int retries;
};
-static struct poll_delay_t poll_delay_min_max(int min, int max)
+static struct jr3_pci_poll_delay poll_delay_min_max(int min, int max)
{
- struct poll_delay_t result;
+ struct jr3_pci_poll_delay result;
result.min = min;
result.max = max;
@@ -106,15 +137,8 @@ static int is_complete(struct jr3_channel __iomem *channel)
return get_s16(&channel->command_word0) == 0;
}
-struct transform_t {
- struct {
- u16 link_type;
- s16 link_amount;
- } link[8];
-};
-
static void set_transforms(struct jr3_channel __iomem *channel,
- struct transform_t transf, short num)
+ struct jr3_pci_transform transf, short num)
{
int i;
@@ -194,110 +218,99 @@ static struct six_axis_t get_max_full_scales(struct jr3_channel __iomem
return result;
}
+static unsigned int jr3_pci_ai_read_chan(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int chan)
+{
+ struct jr3_pci_subdev_private *spriv = s->private;
+ unsigned int val = 0;
+
+ if (spriv->state != state_jr3_done)
+ return 0;
+
+ if (chan < 56) {
+ unsigned int axis = chan % 8;
+ unsigned filter = chan / 8;
+
+ switch (axis) {
+ case 0:
+ val = get_s16(&spriv->channel->filter[filter].fx);
+ break;
+ case 1:
+ val = get_s16(&spriv->channel->filter[filter].fy);
+ break;
+ case 2:
+ val = get_s16(&spriv->channel->filter[filter].fz);
+ break;
+ case 3:
+ val = get_s16(&spriv->channel->filter[filter].mx);
+ break;
+ case 4:
+ val = get_s16(&spriv->channel->filter[filter].my);
+ break;
+ case 5:
+ val = get_s16(&spriv->channel->filter[filter].mz);
+ break;
+ case 6:
+ val = get_s16(&spriv->channel->filter[filter].v1);
+ break;
+ case 7:
+ val = get_s16(&spriv->channel->filter[filter].v2);
+ break;
+ }
+ val += 0x4000;
+ } else if (chan == 56) {
+ val = get_u16(&spriv->channel->model_no);
+ } else if (chan == 57) {
+ val = get_u16(&spriv->channel->serial_no);
+ }
+
+ return val;
+}
+
static int jr3_pci_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int result;
- struct jr3_pci_subdev_private *p;
- int channel;
-
- p = s->private;
- channel = CR_CHAN(insn->chanspec);
- if (p == NULL || channel > 57) {
- result = -EINVAL;
- } else {
- int i;
-
- result = insn->n;
- if (p->state != state_jr3_done ||
- (get_u16(&p->channel->errors) & (watch_dog | watch_dog2 |
- sensor_change))) {
- /* No sensor or sensor changed */
- if (p->state == state_jr3_done) {
- /* Restart polling */
- p->state = state_jr3_poll;
- }
- result = -EAGAIN;
- }
- for (i = 0; i < insn->n; i++) {
- if (channel < 56) {
- int axis, filter;
-
- axis = channel % 8;
- filter = channel / 8;
- if (p->state != state_jr3_done) {
- data[i] = 0;
- } else {
- int F = 0;
- switch (axis) {
- case 0:
- F = get_s16(&p->channel->
- filter[filter].fx);
- break;
- case 1:
- F = get_s16(&p->channel->
- filter[filter].fy);
- break;
- case 2:
- F = get_s16(&p->channel->
- filter[filter].fz);
- break;
- case 3:
- F = get_s16(&p->channel->
- filter[filter].mx);
- break;
- case 4:
- F = get_s16(&p->channel->
- filter[filter].my);
- break;
- case 5:
- F = get_s16(&p->channel->
- filter[filter].mz);
- break;
- case 6:
- F = get_s16(&p->channel->
- filter[filter].v1);
- break;
- case 7:
- F = get_s16(&p->channel->
- filter[filter].v2);
- break;
- }
- data[i] = F + 0x4000;
- }
- } else if (channel == 56) {
- if (p->state != state_jr3_done)
- data[i] = 0;
- else
- data[i] =
- get_u16(&p->channel->model_no);
- } else if (channel == 57) {
- if (p->state != state_jr3_done)
- data[i] = 0;
- else
- data[i] =
- get_u16(&p->channel->serial_no);
- }
+ struct jr3_pci_subdev_private *spriv = s->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ u16 errors;
+ int i;
+
+ if (!spriv)
+ return -EINVAL;
+
+ errors = get_u16(&spriv->channel->errors);
+ if (spriv->state != state_jr3_done ||
+ (errors & (watch_dog | watch_dog2 | sensor_change))) {
+ /* No sensor or sensor changed */
+ if (spriv->state == state_jr3_done) {
+ /* Restart polling */
+ spriv->state = state_jr3_poll;
}
+ return -EAGAIN;
}
- return result;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = jr3_pci_ai_read_chan(dev, s, chan);
+
+ return insn->n;
}
static int jr3_pci_open(struct comedi_device *dev)
{
+ struct jr3_pci_subdev_private *spriv;
+ struct comedi_subdevice *s;
int i;
- struct jr3_pci_dev_private *devpriv = dev->private;
dev_dbg(dev->class_dev, "jr3_pci_open\n");
- for (i = 0; i < devpriv->n_channels; i++) {
- struct jr3_pci_subdev_private *p;
-
- p = dev->subdevices[i].private;
- if (p) {
- dev_dbg(dev->class_dev, "serial: %p %d (%d)\n", p,
- p->serial_no, p->channel_no);
- }
+ for (i = 0; i < dev->n_subdevices; i++) {
+ s = &dev->subdevices[i];
+ spriv = s->private;
+ if (spriv)
+ dev_dbg(dev->class_dev, "serial: %p %d (%d)\n",
+ spriv, spriv->serial_no, s->index);
}
return 0;
}
@@ -326,271 +339,262 @@ static int read_idm_word(const u8 *data, size_t size, int *pos,
return result;
}
-static int jr3_download_firmware(struct comedi_device *dev,
- const u8 *data, size_t size,
- unsigned long context)
+static int jr3_check_firmware(struct comedi_device *dev,
+ const u8 *data, size_t size)
{
+ int more = 1;
+ int pos = 0;
+
/*
* IDM file format is:
* { count, address, data <count> } *
* ffff
*/
- int result, more, pos, OK;
-
- result = 0;
- more = 1;
- pos = 0;
- OK = 0;
while (more) {
- unsigned int count, addr;
+ unsigned int count = 0;
+ unsigned int addr = 0;
more = more && read_idm_word(data, size, &pos, &count);
- if (more && count == 0xffff) {
- OK = 1;
- break;
- }
+ if (more && count == 0xffff)
+ return 0;
+
more = more && read_idm_word(data, size, &pos, &addr);
while (more && count > 0) {
- unsigned int dummy;
+ unsigned int dummy = 0;
+
more = more && read_idm_word(data, size, &pos, &dummy);
count--;
}
}
- if (!OK) {
- result = -ENODATA;
- } else {
- int i;
- struct jr3_pci_dev_private *p = dev->private;
+ return -ENODATA;
+}
+
+static void jr3_write_firmware(struct comedi_device *dev,
+ int subdev, const u8 *data, size_t size)
+{
+ struct jr3_pci_dev_private *devpriv = dev->private;
+ struct jr3_t __iomem *iobase = devpriv->iobase;
+ u32 __iomem *lo;
+ u32 __iomem *hi;
+ int more = 1;
+ int pos = 0;
+
+ while (more) {
+ unsigned int count = 0;
+ unsigned int addr = 0;
+
+ more = more && read_idm_word(data, size, &pos, &count);
+ if (more && count == 0xffff)
+ return;
+
+ more = more && read_idm_word(data, size, &pos, &addr);
+
+ dev_dbg(dev->class_dev, "Loading#%d %4.4x bytes at %4.4x\n",
+ subdev, count, addr);
+
+ while (more && count > 0) {
+ if (addr & 0x4000) {
+ /* 16 bit data, never seen in real life!! */
+ unsigned int data1 = 0;
- for (i = 0; i < p->n_channels; i++) {
- struct jr3_pci_subdev_private *sp;
+ more = more &&
+ read_idm_word(data, size, &pos, &data1);
+ count--;
+ /* jr3[addr + 0x20000 * pnum] = data1; */
+ } else {
+ /* Download 24 bit program */
+ unsigned int data1 = 0;
+ unsigned int data2 = 0;
+
+ lo = &iobase->channel[subdev].program_lo[addr];
+ hi = &iobase->channel[subdev].program_hi[addr];
- sp = dev->subdevices[i].private;
- more = 1;
- pos = 0;
- while (more) {
- unsigned int count, addr;
more = more &&
- read_idm_word(data, size, &pos, &count);
- if (more && count == 0xffff)
- break;
+ read_idm_word(data, size, &pos, &data1);
more = more &&
- read_idm_word(data, size, &pos, &addr);
- dev_dbg(dev->class_dev,
- "Loading#%d %4.4x bytes at %4.4x\n",
- i, count, addr);
- while (more && count > 0) {
- if (addr & 0x4000) {
- /* 16 bit data, never seen
- * in real life!! */
- unsigned int data1;
-
- more = more &&
- read_idm_word(data,
- size, &pos,
- &data1);
- count--;
- /* jr3[addr + 0x20000 * pnum] =
- data1; */
- } else {
- /* Download 24 bit program */
- unsigned int data1, data2;
-
- more = more &&
- read_idm_word(data,
- size, &pos,
- &data1);
- more = more &&
- read_idm_word(data, size,
- &pos,
- &data2);
- count -= 2;
- if (more) {
- set_u16(&p->
- iobase->channel
- [i].program_low
- [addr], data1);
- udelay(1);
- set_u16(&p->
- iobase->channel
- [i].program_high
- [addr], data2);
- udelay(1);
- }
- }
- addr++;
+ read_idm_word(data, size, &pos, &data2);
+ count -= 2;
+ if (more) {
+ set_u16(lo, data1);
+ udelay(1);
+ set_u16(hi, data2);
+ udelay(1);
}
}
+ addr++;
}
}
- return result;
}
-static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice *s)
+static int jr3_download_firmware(struct comedi_device *dev,
+ const u8 *data, size_t size,
+ unsigned long context)
{
- struct poll_delay_t result = poll_delay_min_max(1000, 2000);
- struct jr3_pci_subdev_private *p = s->private;
- int i;
+ int subdev;
+ int ret;
- if (p) {
- struct jr3_channel __iomem *channel = p->channel;
- int errors = get_u16(&channel->errors);
-
- if (errors != p->errors)
- p->errors = errors;
-
- if (errors & (watch_dog | watch_dog2 | sensor_change))
- /* Sensor communication lost, force poll mode */
- p->state = state_jr3_poll;
-
- switch (p->state) {
- case state_jr3_poll: {
- u16 model_no = get_u16(&channel->model_no);
- u16 serial_no = get_u16(&channel->serial_no);
- if ((errors & (watch_dog | watch_dog2)) ||
- model_no == 0 || serial_no == 0) {
- /*
- * Still no sensor, keep on polling.
- * Since it takes up to 10 seconds
- * for offsets to stabilize, polling
- * each second should suffice.
- */
- result = poll_delay_min_max(1000, 2000);
- } else {
- p->retries = 0;
- p->state =
- state_jr3_init_wait_for_offset;
- result = poll_delay_min_max(1000, 2000);
- }
- }
- break;
- case state_jr3_init_wait_for_offset:
- p->retries++;
- if (p->retries < 10) {
- /* Wait for offeset to stabilize
- * (< 10 s according to manual) */
- result = poll_delay_min_max(1000, 2000);
- } else {
- struct transform_t transf;
+ /* verify IDM file format */
+ ret = jr3_check_firmware(dev, data, size);
+ if (ret)
+ return ret;
- p->model_no = get_u16(&channel->model_no);
- p->serial_no = get_u16(&channel->serial_no);
+ /* write firmware to each subdevice */
+ for (subdev = 0; subdev < dev->n_subdevices; subdev++)
+ jr3_write_firmware(dev, subdev, data, size);
- /* Transformation all zeros */
- for (i = 0; i < ARRAY_SIZE(transf.link); i++) {
- transf.link[i].link_type =
- (enum link_types)0;
- transf.link[i].link_amount = 0;
- }
+ return 0;
+}
- set_transforms(channel, transf, 0);
- use_transform(channel, 0);
- p->state = state_jr3_init_transform_complete;
- /* Allow 20 ms for completion */
- result = poll_delay_min_max(20, 100);
- }
- break;
- case state_jr3_init_transform_complete:
- if (!is_complete(channel)) {
- result = poll_delay_min_max(20, 100);
- } else {
- /* Set full scale */
- struct six_axis_t min_full_scale;
- struct six_axis_t max_full_scale;
-
- min_full_scale = get_min_full_scales(channel);
- max_full_scale = get_max_full_scales(channel);
- set_full_scales(channel, max_full_scale);
-
- p->state =
- state_jr3_init_set_full_scale_complete;
- /* Allow 20 ms for completion */
- result = poll_delay_min_max(20, 100);
- }
- break;
- case state_jr3_init_set_full_scale_complete:
- if (!is_complete(channel)) {
- result = poll_delay_min_max(20, 100);
- } else {
- struct force_array __iomem *full_scale;
-
- /* Use ranges in kN or we will
- * overflow around 2000N! */
- full_scale = &channel->full_scale;
- p->range[0].range.min =
- -get_s16(&full_scale->fx) * 1000;
- p->range[0].range.max =
- get_s16(&full_scale->fx) * 1000;
- p->range[1].range.min =
- -get_s16(&full_scale->fy) * 1000;
- p->range[1].range.max =
- get_s16(&full_scale->fy) * 1000;
- p->range[2].range.min =
- -get_s16(&full_scale->fz) * 1000;
- p->range[2].range.max =
- get_s16(&full_scale->fz) * 1000;
- p->range[3].range.min =
- -get_s16(&full_scale->mx) * 100;
- p->range[3].range.max =
- get_s16(&full_scale->mx) * 100;
- p->range[4].range.min =
- -get_s16(&full_scale->my) * 100;
- p->range[4].range.max =
- get_s16(&full_scale->my) * 100;
- p->range[5].range.min =
- -get_s16(&full_scale->mz) * 100;
- p->range[5].range.max =
- get_s16(&full_scale->mz) * 100; /* ?? */
- p->range[6].range.min =
- -get_s16(&full_scale->v1) * 100;/* ?? */
- p->range[6].range.max =
- get_s16(&full_scale->v1) * 100; /* ?? */
- p->range[7].range.min =
- -get_s16(&full_scale->v2) * 100;/* ?? */
- p->range[7].range.max =
- get_s16(&full_scale->v2) * 100; /* ?? */
- p->range[8].range.min = 0;
- p->range[8].range.max = 65535;
-
- use_offset(channel, 0);
- p->state = state_jr3_init_use_offset_complete;
- /* Allow 40 ms for completion */
- result = poll_delay_min_max(40, 100);
- }
- break;
- case state_jr3_init_use_offset_complete:
- if (!is_complete(channel)) {
- result = poll_delay_min_max(20, 100);
- } else {
- set_s16(&channel->offsets.fx, 0);
- set_s16(&channel->offsets.fy, 0);
- set_s16(&channel->offsets.fz, 0);
- set_s16(&channel->offsets.mx, 0);
- set_s16(&channel->offsets.my, 0);
- set_s16(&channel->offsets.mz, 0);
+static struct jr3_pci_poll_delay jr3_pci_poll_subdevice(struct comedi_subdevice *s)
+{
+ struct jr3_pci_subdev_private *spriv = s->private;
+ struct jr3_pci_poll_delay result = poll_delay_min_max(1000, 2000);
+ struct jr3_channel __iomem *channel;
+ u16 model_no;
+ u16 serial_no;
+ int errors;
+ int i;
- set_offset(channel);
+ if (!spriv)
+ return result;
- p->state = state_jr3_done;
+ channel = spriv->channel;
+ errors = get_u16(&channel->errors);
+
+ if (errors != spriv->errors)
+ spriv->errors = errors;
+
+ /* Sensor communication lost? force poll mode */
+ if (errors & (watch_dog | watch_dog2 | sensor_change))
+ spriv->state = state_jr3_poll;
+
+ switch (spriv->state) {
+ case state_jr3_poll:
+ model_no = get_u16(&channel->model_no);
+ serial_no = get_u16(&channel->serial_no);
+
+ if ((errors & (watch_dog | watch_dog2)) ||
+ model_no == 0 || serial_no == 0) {
+ /*
+ * Still no sensor, keep on polling.
+ * Since it takes up to 10 seconds for offsets to
+ * stabilize, polling each second should suffice.
+ */
+ } else {
+ spriv->retries = 0;
+ spriv->state = state_jr3_init_wait_for_offset;
+ }
+ break;
+ case state_jr3_init_wait_for_offset:
+ spriv->retries++;
+ if (spriv->retries < 10) {
+ /*
+ * Wait for offeset to stabilize
+ * (< 10 s according to manual)
+ */
+ } else {
+ struct jr3_pci_transform transf;
+
+ spriv->model_no = get_u16(&channel->model_no);
+ spriv->serial_no = get_u16(&channel->serial_no);
+
+ /* Transformation all zeros */
+ for (i = 0; i < ARRAY_SIZE(transf.link); i++) {
+ transf.link[i].link_type = (enum link_types)0;
+ transf.link[i].link_amount = 0;
}
- break;
- case state_jr3_done:
- poll_delay_min_max(10000, 20000);
- break;
- default:
- poll_delay_min_max(1000, 2000);
- break;
+
+ set_transforms(channel, transf, 0);
+ use_transform(channel, 0);
+ spriv->state = state_jr3_init_transform_complete;
+ /* Allow 20 ms for completion */
+ result = poll_delay_min_max(20, 100);
+ }
+ break;
+ case state_jr3_init_transform_complete:
+ if (!is_complete(channel)) {
+ result = poll_delay_min_max(20, 100);
+ } else {
+ /* Set full scale */
+ struct six_axis_t min_full_scale;
+ struct six_axis_t max_full_scale;
+
+ min_full_scale = get_min_full_scales(channel);
+ max_full_scale = get_max_full_scales(channel);
+ set_full_scales(channel, max_full_scale);
+
+ spriv->state = state_jr3_init_set_full_scale_complete;
+ /* Allow 20 ms for completion */
+ result = poll_delay_min_max(20, 100);
+ }
+ break;
+ case state_jr3_init_set_full_scale_complete:
+ if (!is_complete(channel)) {
+ result = poll_delay_min_max(20, 100);
+ } else {
+ struct force_array __iomem *fs = &channel->full_scale;
+
+ /* Use ranges in kN or we will overflow around 2000N! */
+ spriv->range[0].range.min = -get_s16(&fs->fx) * 1000;
+ spriv->range[0].range.max = get_s16(&fs->fx) * 1000;
+ spriv->range[1].range.min = -get_s16(&fs->fy) * 1000;
+ spriv->range[1].range.max = get_s16(&fs->fy) * 1000;
+ spriv->range[2].range.min = -get_s16(&fs->fz) * 1000;
+ spriv->range[2].range.max = get_s16(&fs->fz) * 1000;
+ spriv->range[3].range.min = -get_s16(&fs->mx) * 100;
+ spriv->range[3].range.max = get_s16(&fs->mx) * 100;
+ spriv->range[4].range.min = -get_s16(&fs->my) * 100;
+ spriv->range[4].range.max = get_s16(&fs->my) * 100;
+ spriv->range[5].range.min = -get_s16(&fs->mz) * 100;
+ /* the next five are questionable */
+ spriv->range[5].range.max = get_s16(&fs->mz) * 100;
+ spriv->range[6].range.min = -get_s16(&fs->v1) * 100;
+ spriv->range[6].range.max = get_s16(&fs->v1) * 100;
+ spriv->range[7].range.min = -get_s16(&fs->v2) * 100;
+ spriv->range[7].range.max = get_s16(&fs->v2) * 100;
+ spriv->range[8].range.min = 0;
+ spriv->range[8].range.max = 65535;
+
+ use_offset(channel, 0);
+ spriv->state = state_jr3_init_use_offset_complete;
+ /* Allow 40 ms for completion */
+ result = poll_delay_min_max(40, 100);
+ }
+ break;
+ case state_jr3_init_use_offset_complete:
+ if (!is_complete(channel)) {
+ result = poll_delay_min_max(20, 100);
+ } else {
+ set_s16(&channel->offsets.fx, 0);
+ set_s16(&channel->offsets.fy, 0);
+ set_s16(&channel->offsets.fz, 0);
+ set_s16(&channel->offsets.mx, 0);
+ set_s16(&channel->offsets.my, 0);
+ set_s16(&channel->offsets.mz, 0);
+
+ set_offset(channel);
+
+ spriv->state = state_jr3_done;
}
+ break;
+ case state_jr3_done:
+ result = poll_delay_min_max(10000, 20000);
+ break;
+ default:
+ break;
}
+
return result;
}
static void jr3_pci_poll_dev(unsigned long data)
{
- unsigned long flags;
struct comedi_device *dev = (struct comedi_device *)data;
struct jr3_pci_dev_private *devpriv = dev->private;
+ struct jr3_pci_subdev_private *spriv;
+ struct comedi_subdevice *s;
+ unsigned long flags;
unsigned long now;
int delay;
int i;
@@ -598,18 +602,22 @@ static void jr3_pci_poll_dev(unsigned long data)
spin_lock_irqsave(&dev->spinlock, flags);
delay = 1000;
now = jiffies;
- /* Poll all channels that are ready to be polled */
- for (i = 0; i < devpriv->n_channels; i++) {
- struct jr3_pci_subdev_private *subdevpriv =
- dev->subdevices[i].private;
- if (now > subdevpriv->next_time_min) {
- struct poll_delay_t sub_delay;
-
- sub_delay = jr3_pci_poll_subdevice(&dev->subdevices[i]);
- subdevpriv->next_time_min =
- jiffies + msecs_to_jiffies(sub_delay.min);
- subdevpriv->next_time_max =
- jiffies + msecs_to_jiffies(sub_delay.max);
+
+ /* Poll all channels that are ready to be polled */
+ for (i = 0; i < dev->n_subdevices; i++) {
+ s = &dev->subdevices[i];
+ spriv = s->private;
+
+ if (now > spriv->next_time_min) {
+ struct jr3_pci_poll_delay sub_delay;
+
+ sub_delay = jr3_pci_poll_subdevice(s);
+
+ spriv->next_time_min = jiffies +
+ msecs_to_jiffies(sub_delay.min);
+ spriv->next_time_max = jiffies +
+ msecs_to_jiffies(sub_delay.max);
+
if (sub_delay.max && sub_delay.max < delay)
/*
* Wake up as late as possible ->
@@ -624,13 +632,58 @@ static void jr3_pci_poll_dev(unsigned long data)
add_timer(&devpriv->timer);
}
+static struct jr3_pci_subdev_private *
+jr3_pci_alloc_spriv(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+ struct jr3_pci_dev_private *devpriv = dev->private;
+ struct jr3_pci_subdev_private *spriv;
+ int j;
+ int k;
+
+ spriv = comedi_alloc_spriv(s, sizeof(*spriv));
+ if (!spriv)
+ return NULL;
+
+ spriv->channel = &devpriv->iobase->channel[s->index].data;
+
+ for (j = 0; j < 8; j++) {
+ spriv->range[j].length = 1;
+ spriv->range[j].range.min = -1000000;
+ spriv->range[j].range.max = 1000000;
+
+ for (k = 0; k < 7; k++) {
+ spriv->range_table_list[j + k * 8] =
+ (struct comedi_lrange *)&spriv->range[j];
+ spriv->maxdata_list[j + k * 8] = 0x7fff;
+ }
+ }
+ spriv->range[8].length = 1;
+ spriv->range[8].range.min = 0;
+ spriv->range[8].range.max = 65536;
+
+ spriv->range_table_list[56] = (struct comedi_lrange *)&spriv->range[8];
+ spriv->range_table_list[57] = (struct comedi_lrange *)&spriv->range[8];
+ spriv->maxdata_list[56] = 0xffff;
+ spriv->maxdata_list[57] = 0xffff;
+
+ dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n",
+ spriv->channel, devpriv->iobase,
+ ((char __iomem *)spriv->channel -
+ (char __iomem *)devpriv->iobase));
+
+ return spriv;
+}
+
static int jr3_pci_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
- int result;
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- int i;
+ static const struct jr3_pci_board *board = NULL;
struct jr3_pci_dev_private *devpriv;
+ struct jr3_pci_subdev_private *spriv;
+ struct comedi_subdevice *s;
+ int ret;
+ int i;
if (sizeof(struct jr3_channel) != 0xc00) {
dev_err(dev->class_dev,
@@ -639,106 +692,56 @@ static int jr3_pci_auto_attach(struct comedi_device *dev,
return -EINVAL;
}
+ if (context < ARRAY_SIZE(jr3_pci_boards))
+ board = &jr3_pci_boards[context];
+ if (!board)
+ return -ENODEV;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
+
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
init_timer(&devpriv->timer);
- switch (pcidev->device) {
- case PCI_DEVICE_ID_JR3_1_CHANNEL:
- case PCI_DEVICE_ID_JR3_1_CHANNEL_NEW:
- devpriv->n_channels = 1;
- break;
- case PCI_DEVICE_ID_JR3_2_CHANNEL:
- devpriv->n_channels = 2;
- break;
- case PCI_DEVICE_ID_JR3_3_CHANNEL:
- devpriv->n_channels = 3;
- break;
- case PCI_DEVICE_ID_JR3_4_CHANNEL:
- devpriv->n_channels = 4;
- break;
- default:
- dev_err(dev->class_dev, "jr3_pci: pci %s not supported\n",
- pci_name(pcidev));
- return -EINVAL;
- break;
- }
- result = comedi_pci_enable(dev);
- if (result)
- return result;
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
devpriv->iobase = pci_ioremap_bar(pcidev, 0);
if (!devpriv->iobase)
return -ENOMEM;
- result = comedi_alloc_subdevices(dev, devpriv->n_channels);
- if (result)
- return result;
+ ret = comedi_alloc_subdevices(dev, board->n_subdevs);
+ if (ret)
+ return ret;
dev->open = jr3_pci_open;
- for (i = 0; i < devpriv->n_channels; i++) {
- dev->subdevices[i].type = COMEDI_SUBD_AI;
- dev->subdevices[i].subdev_flags = SDF_READABLE | SDF_GROUND;
- dev->subdevices[i].n_chan = 8 * 7 + 2;
- dev->subdevices[i].insn_read = jr3_pci_ai_insn_read;
- dev->subdevices[i].private =
- kzalloc(sizeof(struct jr3_pci_subdev_private),
- GFP_KERNEL);
- if (dev->subdevices[i].private) {
- struct jr3_pci_subdev_private *p;
- int j;
-
- p = dev->subdevices[i].private;
- p->channel = &devpriv->iobase->channel[i].data;
- dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n",
- p->channel, devpriv->iobase,
- ((char __iomem *)p->channel -
- (char __iomem *)devpriv->iobase));
- p->channel_no = i;
- for (j = 0; j < 8; j++) {
- int k;
-
- p->range[j].length = 1;
- p->range[j].range.min = -1000000;
- p->range[j].range.max = 1000000;
- for (k = 0; k < 7; k++) {
- p->range_table_list[j + k * 8] =
- (struct comedi_lrange *)&p->
- range[j];
- p->maxdata_list[j + k * 8] = 0x7fff;
- }
- }
- p->range[8].length = 1;
- p->range[8].range.min = 0;
- p->range[8].range.max = 65536;
-
- p->range_table_list[56] =
- (struct comedi_lrange *)&p->range[8];
- p->range_table_list[57] =
- (struct comedi_lrange *)&p->range[8];
- p->maxdata_list[56] = 0xffff;
- p->maxdata_list[57] = 0xffff;
- /* Channel specific range and maxdata */
- dev->subdevices[i].range_table = NULL;
- dev->subdevices[i].range_table_list =
- p->range_table_list;
- dev->subdevices[i].maxdata = 0;
- dev->subdevices[i].maxdata_list = p->maxdata_list;
+ for (i = 0; i < dev->n_subdevices; i++) {
+ s = &dev->subdevices[i];
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND;
+ s->n_chan = 8 * 7 + 2;
+ s->insn_read = jr3_pci_ai_insn_read;
+
+ spriv = jr3_pci_alloc_spriv(dev, s);
+ if (spriv) {
+ /* Channel specific range and maxdata */
+ s->range_table_list = spriv->range_table_list;
+ s->maxdata_list = spriv->maxdata_list;
}
}
/* Reset DSP card */
writel(0, &devpriv->iobase->channel[0].reset);
- result = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev,
- "comedi/jr3pci.idm",
- jr3_download_firmware, 0);
- dev_dbg(dev->class_dev, "Firmare load %d\n", result);
-
- if (result < 0)
- return result;
+ ret = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev,
+ "comedi/jr3pci.idm",
+ jr3_download_firmware, 0);
+ dev_dbg(dev->class_dev, "Firmare load %d\n", ret);
+ if (ret < 0)
+ return ret;
/*
* TODO: use firmware to load preferred offset tables. Suggested
* format:
@@ -761,11 +764,12 @@ static int jr3_pci_auto_attach(struct comedi_device *dev,
}
/* Start card timer */
- for (i = 0; i < devpriv->n_channels; i++) {
- struct jr3_pci_subdev_private *p = dev->subdevices[i].private;
+ for (i = 0; i < dev->n_subdevices; i++) {
+ s = &dev->subdevices[i];
+ spriv = s->private;
- p->next_time_min = jiffies + msecs_to_jiffies(500);
- p->next_time_max = jiffies + msecs_to_jiffies(2000);
+ spriv->next_time_min = jiffies + msecs_to_jiffies(500);
+ spriv->next_time_max = jiffies + msecs_to_jiffies(2000);
}
devpriv->timer.data = (unsigned long)dev;
@@ -773,21 +777,16 @@ static int jr3_pci_auto_attach(struct comedi_device *dev,
devpriv->timer.expires = jiffies + msecs_to_jiffies(1000);
add_timer(&devpriv->timer);
- return result;
+ return 0;
}
static void jr3_pci_detach(struct comedi_device *dev)
{
- int i;
struct jr3_pci_dev_private *devpriv = dev->private;
if (devpriv) {
del_timer_sync(&devpriv->timer);
- if (dev->subdevices) {
- for (i = 0; i < devpriv->n_channels; i++)
- kfree(dev->subdevices[i].private);
- }
if (devpriv->iobase)
iounmap(devpriv->iobase);
}
@@ -808,11 +807,11 @@ static int jr3_pci_pci_probe(struct pci_dev *dev,
}
static const struct pci_device_id jr3_pci_pci_table[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) },
+ { PCI_VDEVICE(JR3, 0x1111), BOARD_JR3_1 },
+ { PCI_VDEVICE(JR3, 0x3111), BOARD_JR3_1 },
+ { PCI_VDEVICE(JR3, 0x3112), BOARD_JR3_2 },
+ { PCI_VDEVICE(JR3, 0x3113), BOARD_JR3_3 },
+ { PCI_VDEVICE(JR3, 0x3114), BOARD_JR3_4 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table);
diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/staging/comedi/drivers/jr3_pci.h
index 3317f7a04c48..20478ae8fad6 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.h
+++ b/drivers/staging/comedi/drivers/jr3_pci.h
@@ -671,11 +671,11 @@ struct jr3_channel {
struct jr3_t {
struct {
- u32 program_low[0x4000]; /* 0x00000 - 0x10000 */
+ u32 program_lo[0x4000]; /* 0x00000 - 0x10000 */
struct jr3_channel data; /* 0x10000 - 0x10c00 */
char pad2[0x30000 - 0x00c00]; /* 0x10c00 - 0x40000 */
- u32 program_high[0x8000]; /* 0x40000 - 0x60000 */
- u32 reset; /* 0x60000 - 0x60004 */
+ u32 program_hi[0x8000]; /* 0x40000 - 0x60000 */
+ u32 reset; /* 0x60000 - 0x60004 */
char pad3[0x20000 - 0x00004]; /* 0x60004 - 0x80000 */
} channel[4];
};
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index 6b9846fd8c48..ec43c38958de 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -1,92 +1,113 @@
/*
- comedi/drivers/ke_counter.c
- Comedi driver for Kolter-Electronic PCI Counter 1 Card
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 2000 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
-/*
-Driver: ke_counter
-Description: Driver for Kolter Electronic Counter Card
-Devices: [Kolter Electronic] PCI Counter Card (ke_counter)
-Author: Michael Hillmann
-Updated: Mon, 14 Apr 2008 15:42:42 +0100
-Status: tested
-
-Configuration Options: not applicable, uses PCI auto config
+ * ke_counter.c
+ * Comedi driver for Kolter-Electronic PCI Counter 1 Card
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
-This driver is a simple driver to read the counter values from
-Kolter Electronic PCI Counter Card.
-*/
+/*
+ * Driver: ke_counter
+ * Description: Driver for Kolter Electronic Counter Card
+ * Devices: (Kolter Electronic) PCI Counter Card [ke_counter]
+ * Author: Michael Hillmann
+ * Updated: Mon, 14 Apr 2008 15:42:42 +0100
+ * Status: tested
+ *
+ * Configuration Options: not applicable, uses PCI auto config
+ */
#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
-#define CNT_CARD_DEVICE_ID 0x0014
+/*
+ * PCI BAR 0 Register I/O map
+ */
+#define KE_RESET_REG(x) (0x00 + ((x) * 0x20))
+#define KE_LATCH_REG(x) (0x00 + ((x) * 0x20))
+#define KE_LSB_REG(x) (0x04 + ((x) * 0x20))
+#define KE_MID_REG(x) (0x08 + ((x) * 0x20))
+#define KE_MSB_REG(x) (0x0c + ((x) * 0x20))
+#define KE_SIGN_REG(x) (0x10 + ((x) * 0x20))
+#define KE_OSC_SEL_REG 0xf8
+#define KE_OSC_SEL_EXT (1 << 0)
+#define KE_OSC_SEL_4MHZ (2 << 0)
+#define KE_OSC_SEL_20MHZ (3 << 0)
+#define KE_DO_REG 0xfc
+
+static int ke_counter_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
+ int i;
-/*-- counter write ----------------------------------------------------------*/
+ for (i = 0; i < insn->n; i++) {
+ val = data[0];
-/* This should be used only for resetting the counters; maybe it is better
- to make a special command 'reset'. */
-static int cnt_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
-{
- int chan = CR_CHAN(insn->chanspec);
-
- outb((unsigned char)((data[0] >> 24) & 0xff),
- dev->iobase + chan * 0x20 + 0x10);
- outb((unsigned char)((data[0] >> 16) & 0xff),
- dev->iobase + chan * 0x20 + 0x0c);
- outb((unsigned char)((data[0] >> 8) & 0xff),
- dev->iobase + chan * 0x20 + 0x08);
- outb((unsigned char)((data[0] >> 0) & 0xff),
- dev->iobase + chan * 0x20 + 0x04);
-
- /* return the number of samples written */
- return 1;
-}
+ /* Order matters */
+ outb((val >> 24) & 0xff, dev->iobase + KE_SIGN_REG(chan));
+ outb((val >> 16) & 0xff, dev->iobase + KE_MSB_REG(chan));
+ outb((val >> 8) & 0xff, dev->iobase + KE_MID_REG(chan));
+ outb((val >> 0) & 0xff, dev->iobase + KE_LSB_REG(chan));
+ }
-/*-- counter read -----------------------------------------------------------*/
+ return insn->n;
+}
-static int cnt_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
+static int ke_counter_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- unsigned char a0, a1, a2, a3, a4;
- int chan = CR_CHAN(insn->chanspec);
- int result;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
+ int i;
- a0 = inb(dev->iobase + chan * 0x20);
- a1 = inb(dev->iobase + chan * 0x20 + 0x04);
- a2 = inb(dev->iobase + chan * 0x20 + 0x08);
- a3 = inb(dev->iobase + chan * 0x20 + 0x0c);
- a4 = inb(dev->iobase + chan * 0x20 + 0x10);
+ for (i = 0; i < insn->n; i++) {
+ /* Order matters */
+ inb(dev->iobase + KE_LATCH_REG(chan));
- result = (a1 + (a2 * 256) + (a3 * 65536));
- if (a4 > 0)
- result = result - s->maxdata;
+ val = inb(dev->iobase + KE_LSB_REG(chan));
+ val |= (inb(dev->iobase + KE_MID_REG(chan)) << 8);
+ val |= (inb(dev->iobase + KE_MSB_REG(chan)) << 16);
+ val |= (inb(dev->iobase + KE_SIGN_REG(chan)) << 24);
- *data = (unsigned int)result;
+ data[i] = val;
+ }
- /* return the number of samples read */
- return 1;
+ return insn->n;
}
-static int cnt_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+static int ke_counter_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (comedi_dio_update_state(s, data))
+ outb(s->state, dev->iobase + KE_DO_REG);
+
+ data[1] = s->state;
+
+ return insn->n;
+}
+
+static int ke_counter_auto_attach(struct comedi_device *dev,
+ unsigned long context_unused)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct comedi_subdevice *s;
@@ -97,30 +118,32 @@ static int cnt_auto_attach(struct comedi_device *dev,
return ret;
dev->iobase = pci_resource_start(pcidev, 0);
- ret = comedi_alloc_subdevices(dev, 1);
+ ret = comedi_alloc_subdevices(dev, 2);
if (ret)
return ret;
s = &dev->subdevices[0];
- dev->read_subdev = s;
-
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ;
- s->n_chan = 3;
- s->maxdata = 0x00ffffff;
- s->insn_read = cnt_rinsn;
- s->insn_write = cnt_winsn;
-
- /* select 20MHz clock */
- outb(3, dev->iobase + 248);
-
- /* reset all counters */
- outb(0, dev->iobase);
- outb(0, dev->iobase + 0x20);
- outb(0, dev->iobase + 0x40);
-
- dev_info(dev->class_dev, "%s: %s attached\n",
- dev->driver->driver_name, dev->board_name);
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 3;
+ s->maxdata = 0x01ffffff;
+ s->range_table = &range_unknown;
+ s->insn_read = ke_counter_insn_read;
+ s->insn_write = ke_counter_insn_write;
+
+ s = &dev->subdevices[1];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 3;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = ke_counter_do_insn_bits;
+
+ outb(KE_OSC_SEL_20MHZ, dev->iobase + KE_OSC_SEL_REG);
+
+ outb(0, dev->iobase + KE_RESET_REG(0));
+ outb(0, dev->iobase + KE_RESET_REG(1));
+ outb(0, dev->iobase + KE_RESET_REG(2));
return 0;
}
@@ -128,7 +151,7 @@ static int cnt_auto_attach(struct comedi_device *dev,
static struct comedi_driver ke_counter_driver = {
.driver_name = "ke_counter",
.module = THIS_MODULE,
- .auto_attach = cnt_auto_attach,
+ .auto_attach = ke_counter_auto_attach,
.detach = comedi_pci_disable,
};
@@ -140,7 +163,7 @@ static int ke_counter_pci_probe(struct pci_dev *dev,
}
static const struct pci_device_id ke_counter_pci_table[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) },
+ { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, 0x0014) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, ke_counter_pci_table);
@@ -154,5 +177,5 @@ static struct pci_driver ke_counter_pci_driver = {
module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for Kolter Electronic Counter Card");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index e739bcd66a04..f02b31b317ec 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -1112,9 +1112,6 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
if (!dev->attached)
return IRQ_NONE;
- /* Reset all events */
- s->async->events = 0;
-
if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) &
ME4000_IRQ_STATUS_BIT_AI_HF) {
/* Read status register to find out what happened */
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index 7f6687896401..0ff126b1fdfd 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -248,6 +248,20 @@ static int me_dio_insn_bits(struct comedi_device *dev,
return insn->n;
}
+static int me_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct me_private_data *dev_private = dev->private;
+ unsigned int status;
+
+ status = readw(dev_private->me_regbase + ME_STATUS);
+ if ((status & 0x0004) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int me_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -258,7 +272,7 @@ static int me_ai_insn_read(struct comedi_device *dev,
unsigned int rang = CR_RANGE(insn->chanspec);
unsigned int aref = CR_AREF(insn->chanspec);
unsigned short val;
- int i;
+ int ret;
/* stop any running conversion */
dev_private->control_1 &= 0xFFFC;
@@ -290,19 +304,14 @@ static int me_ai_insn_read(struct comedi_device *dev,
readw(dev_private->me_regbase + ME_ADC_START);
/* wait for ADC fifo not empty flag */
- for (i = 100000; i > 0; i--)
- if (!(readw(dev_private->me_regbase + ME_STATUS) & 0x0004))
- break;
+ ret = comedi_timeout(dev, s, insn, me_ai_eoc, 0);
+ if (ret)
+ return ret;
/* get value from ADC fifo */
- if (i) {
- val = readw(dev_private->me_regbase + ME_READ_AD_FIFO);
- val = (val ^ 0x800) & 0x0fff;
- data[0] = val;
- } else {
- dev_err(dev->class_dev, "Cannot get single value\n");
- return -EIO;
- }
+ val = readw(dev_private->me_regbase + ME_READ_AD_FIFO);
+ val = (val ^ 0x800) & 0x0fff;
+ data[0] = val;
/* stop any running conversion */
dev_private->control_1 &= 0xFFFC;
@@ -542,9 +551,6 @@ static int me_auto_attach(struct comedi_device *dev,
s->insn_bits = me_dio_insn_bits;
s->insn_config = me_dio_insn_config;
- dev_info(dev->class_dev, "%s: %s attached\n",
- dev->driver->driver_name, dev->board_name);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c
index 81b78e053f4e..a4f7d6f138df 100644
--- a/drivers/staging/comedi/drivers/mf6x4.c
+++ b/drivers/staging/comedi/drivers/mf6x4.c
@@ -133,21 +133,18 @@ static int mf6x4_do_insn_bits(struct comedi_device *dev,
return insn->n;
}
-static int mf6x4_ai_wait_for_eoc(struct comedi_device *dev,
- unsigned int timeout)
+static int mf6x4_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
struct mf6x4_private *devpriv = dev->private;
- unsigned int eolc;
+ unsigned int status;
- while (timeout--) {
- eolc = ioread32(devpriv->gpioc_R) & MF6X4_GPIOC_EOLC;
- if (eolc)
- return 0;
-
- udelay(1);
- }
-
- return -ETIME;
+ status = ioread32(devpriv->gpioc_R);
+ if (status & MF6X4_GPIOC_EOLC)
+ return 0;
+ return -EBUSY;
}
static int mf6x4_ai_insn_read(struct comedi_device *dev,
@@ -168,7 +165,7 @@ static int mf6x4_ai_insn_read(struct comedi_device *dev,
/* Trigger ADC conversion by reading ADSTART */
ioread16(devpriv->bar1_mem + MF6X4_ADSTART_R);
- ret = mf6x4_ai_wait_for_eoc(dev, 100);
+ ret = comedi_timeout(dev, s, insn, mf6x4_ai_eoc, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index 9c9a0ee432cf..1a572c83f996 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -527,9 +527,9 @@ EXPORT_SYMBOL_GPL(mite_dma_disarm);
int mite_sync_input_dma(struct mite_channel *mite_chan,
struct comedi_async *async)
{
+ struct comedi_subdevice *s = async->subdevice;
int count;
unsigned int nbytes, old_alloc_count;
- const unsigned bytes_per_scan = cfc_bytes_per_scan(async->subdevice);
old_alloc_count = async->buf_write_alloc_count;
/* write alloc as much as we can */
@@ -538,7 +538,7 @@ int mite_sync_input_dma(struct mite_channel *mite_chan,
nbytes = mite_bytes_written_to_memory_lb(mite_chan);
if ((int)(mite_bytes_written_to_memory_ub(mite_chan) -
old_alloc_count) > 0) {
- dev_warn(async->subdevice->device->class_dev,
+ dev_warn(s->device->class_dev,
"mite: DMA overwrite of free area\n");
async->events |= COMEDI_CB_OVERFLOW;
return -1;
@@ -551,12 +551,7 @@ int mite_sync_input_dma(struct mite_channel *mite_chan,
return 0;
comedi_buf_write_free(async, count);
-
- async->scan_progress += count;
- if (async->scan_progress >= bytes_per_scan) {
- async->scan_progress %= bytes_per_scan;
- async->events |= COMEDI_CB_EOS;
- }
+ cfc_inc_scan_progress(s, count);
async->events |= COMEDI_CB_BLOCK;
return 0;
}
diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h
index bcf2f972376e..78f235747991 100644
--- a/drivers/staging/comedi/drivers/mite.h
+++ b/drivers/staging/comedi/drivers/mite.h
@@ -29,9 +29,9 @@
#define MAX_MITE_DMA_CHANNELS 8
struct mite_dma_descriptor {
- u32 count;
- u32 addr;
- u32 next;
+ __le32 count;
+ __le32 addr;
+ __le32 next;
u32 dar;
};
diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c
index fe4621ea65c3..f770400a0e81 100644
--- a/drivers/staging/comedi/drivers/mpc624.c
+++ b/drivers/staging/comedi/drivers/mpc624.c
@@ -142,8 +142,18 @@ static const struct comedi_lrange range_mpc624_bipolar10 = {
}
};
-/* Timeout 200ms */
-#define TIMEOUT 200
+static int mpc624_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned char status;
+
+ status = inb(dev->iobase + MPC624_ADC);
+ if ((status & MPC624_ADBUSY) == 0)
+ return 0;
+ return -EBUSY;
+}
static int mpc624_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
@@ -152,7 +162,7 @@ static int mpc624_ai_rinsn(struct comedi_device *dev,
struct mpc624_private *devpriv = dev->private;
int n, i;
unsigned long int data_in, data_out;
- unsigned char ucPort;
+ int ret;
/*
* WARNING:
@@ -170,15 +180,9 @@ static int mpc624_ai_rinsn(struct comedi_device *dev,
udelay(1);
/* Wait for the conversion to end */
- for (i = 0; i < TIMEOUT; i++) {
- ucPort = inb(dev->iobase + MPC624_ADC);
- if (ucPort & MPC624_ADBUSY)
- udelay(1000);
- else
- break;
- }
- if (i == TIMEOUT)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, mpc624_ai_eoc, 0);
+ if (ret)
+ return ret;
/* Start reading data */
data_in = 0;
@@ -341,7 +345,7 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->len_chanlist = 1;
s->insn_read = mpc624_ai_rinsn;
- return 1;
+ return 0;
}
static struct comedi_driver mpc624_driver = {
diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c
index 3ca755eca285..b74b9e9bfd4a 100644
--- a/drivers/staging/comedi/drivers/multiq3.c
+++ b/drivers/staging/comedi/drivers/multiq3.c
@@ -81,34 +81,44 @@ struct multiq3_private {
unsigned int ao_readback[2];
};
+static int multiq3_ai_status(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + MULTIQ3_STATUS);
+ if (status & context)
+ return 0;
+ return -EBUSY;
+}
+
static int multiq3_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- int i, n;
+ int n;
int chan;
unsigned int hi, lo;
+ int ret;
chan = CR_CHAN(insn->chanspec);
outw(MULTIQ3_CONTROL_MUST | MULTIQ3_AD_MUX_EN | (chan << 3),
dev->iobase + MULTIQ3_CONTROL);
- for (i = 0; i < MULTIQ3_TIMEOUT; i++) {
- if (inw(dev->iobase + MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC)
- break;
- }
- if (i == MULTIQ3_TIMEOUT)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, multiq3_ai_status,
+ MULTIQ3_STATUS_EOC);
+ if (ret)
+ return ret;
for (n = 0; n < insn->n; n++) {
outw(0, dev->iobase + MULTIQ3_AD_CS);
- for (i = 0; i < MULTIQ3_TIMEOUT; i++) {
- if (inw(dev->iobase +
- MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC_I)
- break;
- }
- if (i == MULTIQ3_TIMEOUT)
- return -ETIMEDOUT;
+
+ ret = comedi_timeout(dev, s, insn, multiq3_ai_status,
+ MULTIQ3_STATUS_EOC_I);
+ if (ret)
+ return ret;
hi = inb(dev->iobase + MULTIQ3_AD_CS);
lo = inb(dev->iobase + MULTIQ3_AD_CS);
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index df42e3906171..0d4b9019f76a 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -40,6 +40,7 @@
#include "../comedidev.h"
+#include "comedi_fc.h"
#include "mite.h"
#include "ni_tio.h"
@@ -789,13 +790,7 @@ static void ni_660x_handle_gpct_interrupt(struct comedi_device *dev,
struct ni_gpct *counter = s->private;
ni_tio_handle_interrupt(counter, s);
- if (s->async->events) {
- if (s->async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
- COMEDI_CB_OVERFLOW)) {
- ni_660x_cancel(dev, s);
- }
- comedi_event(dev, s);
- }
+ cfc_handle_events(dev, s);
}
static irqreturn_t ni_660x_interrupt(int irq, void *d)
@@ -1187,7 +1182,7 @@ static int ni_660x_auto_attach(struct comedi_device *dev,
global_interrupt_config_bits |= Cascade_Int_Enable_Bit;
ni_660x_write_register(dev, 0, global_interrupt_config_bits,
NI660X_GLOBAL_INT_CFG);
- dev_info(dev->class_dev, "ni_660x: %s attached\n", dev->board_name);
+
return 0;
}
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index 8550fdc4ccd3..1002ceacfdcc 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -246,9 +246,6 @@ static int ni_670x_auto_attach(struct comedi_device *dev,
/* Config of ao registers */
writel(0x00, devpriv->mite->daq_io_addr + AO_CONTROL_OFFSET);
- dev_info(dev->class_dev, "%s: %s attached\n",
- dev->driver->driver_name, dev->board_name);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index f83eb9ebe278..4e39b1f63d81 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -184,7 +184,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
}
/* initialize async here to make sure s is not NULL */
async = s->async;
- async->events = 0;
cmd = &async->cmd;
status = inw(dev->iobase + STATUS_REG);
@@ -196,15 +195,14 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
if (status & OVFL_BIT) {
comedi_error(dev, "fifo overflow");
- a2150_cancel(dev, s);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ cfc_handle_events(dev, s);
}
if ((status & DMA_TC_BIT) == 0) {
comedi_error(dev, "caught non-dma interrupt? Aborting.");
- a2150_cancel(dev, s);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
@@ -249,7 +247,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
cfc_write_to_buffer(s, dpnt);
if (cmd->stop_src == TRIG_COUNT) {
if (--devpriv->count == 0) { /* end of acquisition */
- a2150_cancel(dev, s);
async->events |= COMEDI_CB_EOA;
break;
}
@@ -265,7 +262,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
async->events |= COMEDI_CB_BLOCK;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
/* clear interrupt */
outw(0x00, dev->iobase + DMA_TC_CLEAR_REG);
@@ -488,13 +485,25 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
+static int a2150_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + STATUS_REG);
+ if (status & FNE_BIT)
+ return 0;
+ return -EBUSY;
+}
+
static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct a2150_private *devpriv = dev->private;
- unsigned int i, n;
- static const int timeout = 100000;
- static const int filter_delay = 36;
+ unsigned int n;
+ int ret;
/* clear fifo and reset triggering circuitry */
outw(0, dev->iobase + FIFO_RESET_REG);
@@ -524,30 +533,20 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
* there is a 35.6 sample delay for data to get through the
* antialias filter
*/
- for (n = 0; n < filter_delay; n++) {
- for (i = 0; i < timeout; i++) {
- if (inw(dev->iobase + STATUS_REG) & FNE_BIT)
- break;
- udelay(1);
- }
- if (i == timeout) {
- comedi_error(dev, "timeout");
- return -ETIME;
- }
+ for (n = 0; n < 36; n++) {
+ ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0);
+ if (ret)
+ return ret;
+
inw(dev->iobase + FIFO_DATA_REG);
}
/* read data */
for (n = 0; n < insn->n; n++) {
- for (i = 0; i < timeout; i++) {
- if (inw(dev->iobase + STATUS_REG) & FNE_BIT)
- break;
- udelay(1);
- }
- if (i == timeout) {
- comedi_error(dev, "timeout");
- return -ETIME;
- }
+ ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0);
+ if (ret)
+ return ret;
+
data[n] = inw(dev->iobase + FIFO_DATA_REG);
data[n] ^= 0x8000;
}
diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index e8cd5ddb85c5..4262385e4f46 100644
--- a/drivers/staging/comedi/drivers/ni_atmio16d.c
+++ b/drivers/staging/comedi/drivers/ni_atmio16d.c
@@ -96,7 +96,6 @@ Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d)
#define CLOCK_100_HZ 0x8F25
/* Other miscellaneous defines */
#define ATMIO16D_SIZE 32 /* bus address range */
-#define ATMIO16D_TIMEOUT 10
struct atmio16_board_t {
@@ -448,16 +447,32 @@ static int atmio16d_ai_cancel(struct comedi_device *dev,
return 0;
}
-/* Mode 0 is used to get a single conversion on demand */
+static int atmio16d_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + STAT_REG);
+ if (status & STAT_AD_CONVAVAIL)
+ return 0;
+ if (status & STAT_AD_OVERFLOW) {
+ outw(0, dev->iobase + AD_CLEAR_REG);
+ return -EOVERFLOW;
+ }
+ return -EBUSY;
+}
+
static int atmio16d_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct atmio16d_private *devpriv = dev->private;
- int i, t;
+ int i;
int chan;
int gain;
- int status;
+ int ret;
chan = CR_CHAN(insn->chanspec);
gain = CR_RANGE(insn->chanspec);
@@ -473,26 +488,17 @@ static int atmio16d_ai_insn_read(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
/* start the conversion */
outw(0, dev->iobase + START_CONVERT_REG);
+
/* wait for it to finish */
- for (t = 0; t < ATMIO16D_TIMEOUT; t++) {
- /* check conversion status */
- status = inw(dev->iobase + STAT_REG);
- if (status & STAT_AD_CONVAVAIL) {
- /* read the data now */
- data[i] = inw(dev->iobase + AD_FIFO_REG);
- /* change to two's complement if need be */
- if (devpriv->adc_coding == adc_2comp)
- data[i] ^= 0x800;
- break;
- }
- if (status & STAT_AD_OVERFLOW) {
- outw(0, dev->iobase + AD_CLEAR_REG);
- return -ETIME;
- }
- }
- /* end waiting, now check if it timed out */
- if (t == ATMIO16D_TIMEOUT)
- return -ETIME;
+ ret = comedi_timeout(dev, s, insn, atmio16d_ai_eoc, 0);
+ if (ret)
+ return ret;
+
+ /* read the data now */
+ data[i] = inw(dev->iobase + AD_FIFO_REG);
+ /* change to two's complement if need be */
+ if (devpriv->adc_coding == adc_2comp)
+ data[i] ^= 0x800;
}
return i;
@@ -723,10 +729,13 @@ static int atmio16d_attach(struct comedi_device *dev,
/* 8255 subdevice */
s = &dev->subdevices[3];
- if (board->has_8255)
- subdev_8255_init(dev, s, NULL, dev->iobase);
- else
+ if (board->has_8255) {
+ ret = subdev_8255_init(dev, s, NULL, dev->iobase);
+ if (ret)
+ return ret;
+ } else {
s->type = COMEDI_SUBD_UNUSED;
+ }
/* don't yet know how to deal with counter/timers */
#if 0
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index e4cdca349157..171a71d20c88 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -109,14 +109,31 @@ static int daq700_dio_insn_config(struct comedi_device *dev,
return insn->n;
}
+static int daq700_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + STA_R2);
+ if ((status & 0x03))
+ return -EOVERFLOW;
+ status = inb(dev->iobase + STA_R1);
+ if ((status & 0x02))
+ return -ENODATA;
+ if ((status & 0x11) == 0x01)
+ return 0;
+ return -EBUSY;
+}
+
static int daq700_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- int n, i, chan;
+ int n, chan;
int d;
- unsigned int status;
- enum { TIMEOUT = 100 };
+ int ret;
chan = CR_CHAN(insn->chanspec);
/* write channel to multiplexer */
@@ -130,30 +147,12 @@ static int daq700_ai_rinsn(struct comedi_device *dev,
outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */
/* mode 1 out0 H, L to H, start conversion */
outb(0x32, dev->iobase + CMO_R);
+
/* wait for conversion to end */
- for (i = 0; i < TIMEOUT; i++) {
- status = inb(dev->iobase + STA_R2);
- if ((status & 0x03) != 0) {
- dev_info(dev->class_dev,
- "Overflow/run Error\n");
- return -EOVERFLOW;
- }
- status = inb(dev->iobase + STA_R1);
- if ((status & 0x02) != 0) {
- dev_info(dev->class_dev, "Data Error\n");
- return -ENODATA;
- }
- if ((status & 0x11) == 0x01) {
- /* ADC conversion complete */
- break;
- }
- udelay(1);
- }
- if (i == TIMEOUT) {
- dev_info(dev->class_dev,
- "timeout during ADC conversion\n");
- return -ETIMEDOUT;
- }
+ ret = comedi_timeout(dev, s, insn, daq700_ai_eoc, 0);
+ if (ret)
+ return ret;
+
/* read data */
d = inw(dev->iobase + ADFIFO_R);
/* mangle the data as necessary */
@@ -229,11 +228,6 @@ static int daq700_auto_attach(struct comedi_device *dev,
s->insn_read = daq700_ai_rinsn;
daq700_ai_config(dev, s);
- dev_info(dev->class_dev, "%s: %s, io 0x%lx\n",
- dev->driver->driver_name,
- dev->board_name,
- dev->iobase);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index 335ea34fa57c..925e82c65b2d 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -3,8 +3,8 @@
Driver for National Instruments PCMCIA DAQ-Card DIO-24
Copyright (C) 2002 Daniel Vecino Castel <dvecino@able.es>
- PCMCIA crap at end of file is adapted from dummy_cs.c 1.31 2001/08/24 12:13:13
- from the pcmcia package.
+ PCMCIA crap at end of file is adapted from dummy_cs.c 1.31
+ 2001/08/24 12:13:13 from the pcmcia package.
The initial developer of the pcmcia dummy_cs.c code is David A. Hinds
<dahinds@users.sourceforge.net>. Portions created by David A. Hinds
are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 0512445df08e..f4216e825f03 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -73,7 +73,6 @@
#include "ni_labpc_isadma.h"
#define LABPC_SIZE 0x20 /* size of ISA io region */
-#define LABPC_ADC_TIMEOUT 1000
enum scan_mode {
MODE_SINGLE_CHAN,
@@ -308,19 +307,17 @@ static void labpc_clear_adc_fifo(struct comedi_device *dev)
labpc_read_adc_fifo(dev);
}
-static int labpc_ai_wait_for_data(struct comedi_device *dev,
- int timeout)
+static int labpc_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
struct labpc_private *devpriv = dev->private;
- int i;
- for (i = 0; i < timeout; i++) {
- devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
- if (devpriv->stat1 & STAT1_DAVAIL)
- return 0;
- udelay(1);
- }
- return -ETIME;
+ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
+ if (devpriv->stat1 & STAT1_DAVAIL)
+ return 0;
+ return -EBUSY;
}
static int labpc_ai_insn_read(struct comedi_device *dev,
@@ -363,7 +360,7 @@ static int labpc_ai_insn_read(struct comedi_device *dev,
/* trigger conversion */
devpriv->write_byte(0x1, dev->iobase + ADC_START_CONVERT_REG);
- ret = labpc_ai_wait_for_data(dev, LABPC_ADC_TIMEOUT);
+ ret = comedi_timeout(dev, s, insn, labpc_ai_eoc, 0);
if (ret)
return ret;
@@ -950,7 +947,6 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
async = s->async;
cmd = &async->cmd;
- async->events = 0;
/* read board status */
devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
@@ -968,7 +964,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
/* clear error interrupt */
devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
comedi_error(dev, "overrun");
return IRQ_HANDLED;
}
@@ -988,7 +984,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
/* clear error interrupt */
devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
comedi_error(dev, "overflow");
return IRQ_HANDLED;
}
@@ -996,20 +992,17 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
if (cmd->stop_src == TRIG_EXT) {
if (devpriv->stat2 & STAT2_OUTA1) {
labpc_drain_dregs(dev);
- labpc_cancel(dev, s);
async->events |= COMEDI_CB_EOA;
}
}
/* TRIG_COUNT end of acquisition */
if (cmd->stop_src == TRIG_COUNT) {
- if (devpriv->count == 0) {
- labpc_cancel(dev, s);
+ if (devpriv->count == 0)
async->events |= COMEDI_CB_EOA;
- }
}
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index 457b88481db0..8a0e3b7236ad 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -256,7 +256,6 @@ static int ni_rtsi_insn_config(struct comedi_device *dev,
static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s);
static int ni_read_eeprom(struct comedi_device *dev, int addr);
-static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s);
#ifndef PCIDMA
static void ni_handle_fifo_half_full(struct comedi_device *dev);
static int ni_ao_fifo_half_empty(struct comedi_device *dev,
@@ -272,15 +271,12 @@ static void shutdown_ai_command(struct comedi_device *dev);
static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned int trignum);
-static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s);
-
static int ni_8255_callback(int dir, int port, int data, unsigned long arg);
#ifdef PCIDMA
static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
+static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
#endif
-static int ni_gpct_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
static void handle_gpct_interrupt(struct comedi_device *dev,
unsigned short counter_index);
@@ -687,12 +683,22 @@ static void ni_clear_ai_fifo(struct comedi_device *dev)
{
const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
+ static const int timeout = 10000;
+ int i;
if (board->reg_type == ni_reg_6143) {
/* Flush the 6143 data FIFO */
ni_writel(0x10, AIFIFO_Control_6143); /* Flush fifo */
ni_writel(0x00, AIFIFO_Control_6143); /* Flush fifo */
- while (ni_readl(AIFIFO_Status_6143) & 0x10) ; /* Wait for complete */
+ /* Wait for complete */
+ for (i = 0; i < timeout; i++) {
+ if (!(ni_readl(AIFIFO_Status_6143) & 0x10))
+ break;
+ udelay(1);
+ }
+ if (i == timeout) {
+ comedi_error(dev, "FIFO flush timeout.");
+ }
} else {
devpriv->stc_writew(dev, 1, ADC_FIFO_Clear);
if (board->reg_type == ni_reg_625x) {
@@ -937,32 +943,6 @@ static void shutdown_ai_command(struct comedi_device *dev)
s->async->events |= COMEDI_CB_EOA;
}
-static void ni_event(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- if (s->
- async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW |
- COMEDI_CB_EOA)) {
- switch (s->index) {
- case NI_AI_SUBDEV:
- ni_ai_reset(dev, s);
- break;
- case NI_AO_SUBDEV:
- ni_ao_reset(dev, s);
- break;
- case NI_GPCT0_SUBDEV:
- case NI_GPCT1_SUBDEV:
- ni_gpct_cancel(dev, s);
- break;
- case NI_DIO_SUBDEV:
- ni_cdio_cancel(dev, s);
- break;
- default:
- break;
- }
- }
- comedi_event(dev, s);
-}
-
static void handle_gpct_interrupt(struct comedi_device *dev,
unsigned short counter_index)
{
@@ -974,8 +954,7 @@ static void handle_gpct_interrupt(struct comedi_device *dev,
ni_tio_handle_interrupt(&devpriv->counter_dev->counters[counter_index],
s);
- if (s->async->events)
- ni_event(dev, s);
+ cfc_handle_events(dev, s);
#endif
}
@@ -1033,7 +1012,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
if (comedi_is_subdevice_running(s)) {
s->async->events |=
COMEDI_CB_ERROR | COMEDI_CB_EOA;
- ni_event(dev, s);
+ cfc_handle_events(dev, s);
}
return;
}
@@ -1048,8 +1027,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
if (status & (AI_Overrun_St | AI_Overflow_St))
s->async->events |= COMEDI_CB_OVERFLOW;
- ni_event(dev, s);
-
+ cfc_handle_events(dev, s);
return;
}
if (status & AI_SC_TC_St) {
@@ -1076,7 +1054,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
if ((status & AI_STOP_St))
ni_handle_eos(dev, s);
- ni_event(dev, s);
+ cfc_handle_events(dev, s);
}
static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status)
@@ -1151,7 +1129,7 @@ static void handle_b_interrupt(struct comedi_device *dev,
}
#endif
- ni_event(dev, s);
+ cfc_handle_events(dev, s);
}
#ifndef PCIDMA
@@ -3662,7 +3640,7 @@ static void handle_cdio_interrupt(struct comedi_device *dev)
M_Offset_CDIO_Command);
/* s->async->events |= COMEDI_CB_EOA; */
}
- ni_event(dev, s);
+ cfc_handle_events(dev, s);
}
static int ni_serial_insn_config(struct comedi_device *dev,
@@ -4282,10 +4260,14 @@ static int ni_E_init(struct comedi_device *dev)
/* 8255 device */
s = &dev->subdevices[NI_8255_DIO_SUBDEV];
- if (board->has_8255)
- subdev_8255_init(dev, s, ni_8255_callback, (unsigned long)dev);
- else
+ if (board->has_8255) {
+ ret = subdev_8255_init(dev, s, ni_8255_callback,
+ (unsigned long)dev);
+ if (ret)
+ return ret;
+ } else {
s->type = COMEDI_SUBD_UNUSED;
+ }
/* formerly general purpose counter/timer device, but no longer used */
s = &dev->subdevices[NI_UNUSED_SUBDEV];
@@ -4393,6 +4375,9 @@ static int ni_E_init(struct comedi_device *dev)
&ni_gpct_read_register,
counter_variant,
NUM_GPCT);
+ if (!devpriv->counter_dev)
+ return -ENOMEM;
+
/* General purpose counters */
for (j = 0; j < NUM_GPCT; ++j) {
s = &dev->subdevices[NI_GPCT_SUBDEV(j)];
@@ -4483,7 +4468,6 @@ static int ni_E_init(struct comedi_device *dev)
ni_writeb(0x0, M_Offset_AO_Calibration);
}
- printk("\n");
return 0;
}
@@ -4992,9 +4976,9 @@ static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
#endif
+#ifdef PCIDMA
static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
-#ifdef PCIDMA
struct ni_gpct *counter = s->private;
int retval;
@@ -5002,10 +4986,8 @@ static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
ni_e_series_enable_second_irq(dev, counter->counter_index, 0);
ni_release_gpct_mite_channel(dev, counter->counter_index);
return retval;
-#else
- return 0;
-#endif
}
+#endif
/*
*
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 30c46a3c1767..85ac2d964f5c 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -263,9 +263,6 @@ enum FPGA_Control_Bits {
#define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC)
#endif
-static int ni_pcidio_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-
enum nidio_boardid {
BOARD_PCIDIO_32HS,
BOARD_PXI6533,
@@ -353,17 +350,6 @@ static void ni_pcidio_release_di_mite_channel(struct comedi_device *dev)
spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
}
-static void ni_pcidio_event(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- if (s->
- async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
- COMEDI_CB_OVERFLOW)) {
- ni_pcidio_cancel(dev, s);
- }
- comedi_event(dev, s);
-}
-
static int ni_pcidio_poll(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct nidio96_private *devpriv = dev->private;
@@ -501,7 +487,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
}
out:
- ni_pcidio_event(dev, s);
+ cfc_handle_events(dev, s);
#if 0
if (!tag) {
writeb(0x03,
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 0ed980455875..d40df072583c 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -1551,7 +1551,7 @@ static int pcimio_auto_attach(struct comedi_device *dev,
dev->subdevices[NI_GPCT_SUBDEV(1)].buf_change = &pcimio_gpct1_change;
dev->subdevices[NI_DIO_SUBDEV].buf_change = &pcimio_dio_change;
- return ret;
+ return 0;
}
static int pcimio_ai_change(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/ni_tio.h b/drivers/staging/comedi/drivers/ni_tio.h
index 68378dab4e70..1056bf001e5e 100644
--- a/drivers/staging/comedi/drivers/ni_tio.h
+++ b/drivers/staging/comedi/drivers/ni_tio.h
@@ -115,10 +115,10 @@ struct ni_gpct {
struct ni_gpct_device {
struct comedi_device *dev;
- void (*write_register) (struct ni_gpct *counter, unsigned bits,
- enum ni_gpct_register reg);
- unsigned (*read_register) (struct ni_gpct *counter,
- enum ni_gpct_register reg);
+ void (*write_register)(struct ni_gpct *counter, unsigned bits,
+ enum ni_gpct_register reg);
+ unsigned (*read_register)(struct ni_gpct *counter,
+ enum ni_gpct_register reg);
enum ni_gpct_variant variant;
struct ni_gpct *counters;
unsigned num_counters;
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index f0fc123ef566..7c03a5d17b1b 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -253,18 +253,17 @@ static void pcl711_set_changain(struct comedi_device *dev,
outb(mux | PCL711_MUX_CHAN(chan), dev->iobase + PCL711_MUX_REG);
}
-static int pcl711_ai_wait_for_eoc(struct comedi_device *dev,
- unsigned int timeout)
+static int pcl711_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- unsigned int msb;
+ unsigned int status;
- while (timeout--) {
- msb = inb(dev->iobase + PCL711_AI_MSB_REG);
- if ((msb & PCL711_AI_MSB_DRDY) == 0)
- return 0;
- udelay(1);
- }
- return -ETIME;
+ status = inb(dev->iobase + PCL711_AI_MSB_REG);
+ if ((status & PCL711_AI_MSB_DRDY) == 0)
+ return 0;
+ return -EBUSY;
}
static int pcl711_ai_insn_read(struct comedi_device *dev,
@@ -282,7 +281,7 @@ static int pcl711_ai_insn_read(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
outb(PCL711_SOFTTRIG, dev->iobase + PCL711_SOFTTRIG_REG);
- ret = pcl711_ai_wait_for_eoc(dev, 100);
+ ret = comedi_timeout(dev, s, insn, pcl711_ai_eoc, 0);
if (ret)
return ret;
@@ -336,11 +335,8 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_NONE) {
+ if (cmd->stop_src == TRIG_NONE)
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
- } else {
- /* ignore */
- }
if (err)
return 3;
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index 53613b385f35..160eac8083db 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -131,34 +131,32 @@
#define boardACL8216 8 /* and ICP DAS A-826PG */
#define boardA821 9 /* PGH, PGL, PGL/NDA versions */
-#define PCLx1x_IORANGE 16
-
-#define PCL812_CTR0 0
-#define PCL812_CTR1 1
-#define PCL812_CTR2 2
-#define PCL812_CTRCTL 3
-#define PCL812_AD_LO 4
-#define PCL812_DA1_LO 4
-#define PCL812_AD_HI 5
-#define PCL812_DA1_HI 5
-#define PCL812_DA2_LO 6
-#define PCL812_DI_LO 6
-#define PCL812_DA2_HI 7
-#define PCL812_DI_HI 7
-#define PCL812_CLRINT 8
-#define PCL812_GAIN 9
-#define PCL812_MUX 10
-#define PCL812_MODE 11
-#define PCL812_CNTENABLE 10
-#define PCL812_SOFTTRIG 12
-#define PCL812_DO_LO 13
-#define PCL812_DO_HI 14
-
-#define PCL812_DRDY 0x10 /* =0 data ready */
-
-#define ACL8216_STATUS 8 /* 5. bit signalize data ready */
-
-#define ACL8216_DRDY 0x20 /* =0 data ready */
+/*
+ * Register I/O map
+ */
+#define PCL812_TIMER_BASE 0x00
+#define PCL812_AI_LSB_REG 0x04
+#define PCL812_AI_MSB_REG 0x05
+#define PCL812_AI_MSB_DRDY (1 << 4)
+#define PCL812_AO_LSB_REG(x) (0x04 + ((x) * 2))
+#define PCL812_AO_MSB_REG(x) (0x05 + ((x) * 2))
+#define PCL812_DI_LSB_REG 0x06
+#define PCL812_DI_MSB_REG 0x07
+#define PCL812_STATUS_REG 0x08
+#define PCL812_STATUS_DRDY (1 << 5)
+#define PCL812_RANGE_REG 0x09
+#define PCL812_MUX_REG 0x0a
+#define PCL812_MUX_CHAN(x) ((x) << 0)
+#define PCL812_MUX_CS0 (1 << 4)
+#define PCL812_MUX_CS1 (1 << 5)
+#define PCL812_CTRL_REG 0x0b
+#define PCL812_CTRL_DISABLE_TRIG (0 << 0)
+#define PCL812_CTRL_SOFT_TRIG (1 << 0)
+#define PCL812_CTRL_PACER_DMA_TRIG (2 << 0)
+#define PCL812_CTRL_PACER_EOC_TRIG (6 << 0)
+#define PCL812_SOFTTRIG_REG 0x0c
+#define PCL812_DO_LSB_REG 0x0d
+#define PCL812_DO_MSB_REG 0x0e
#define MAX_CHANLIST_LEN 256 /* length of scan list */
@@ -331,213 +329,391 @@ static const struct comedi_lrange range_a821pgh_ai = {
};
struct pcl812_board {
+ const char *name;
+ int board_type;
+ int n_aichan;
+ int n_aochan;
+ unsigned int ai_ns_min;
+ const struct comedi_lrange *rangelist_ai;
+ unsigned int IRQbits;
+ unsigned int has_dma:1;
+ unsigned int has_16bit_ai:1;
+ unsigned int has_mpc508_mux:1;
+ unsigned int has_dio:1;
+};
- const char *name; /* board name */
- int board_type; /* type of this board */
- int n_aichan; /* num of AI chans in S.E. */
- int n_aichan_diff; /* DIFF num of chans */
- int n_aochan; /* num of DA chans */
- int n_dichan; /* DI and DO chans */
- int n_dochan;
- int ai_maxdata; /* AI resolution */
- unsigned int ai_ns_min; /* max sample speed of card v ns */
- unsigned int i8254_osc_base; /* clock base */
- const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
- const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
- unsigned int IRQbits; /* allowed IRQ */
- unsigned char DMAbits; /* allowed DMA chans */
- unsigned char io_range; /* iorange for this board */
- unsigned char haveMPC508; /* 1=board use MPC508A multiplexor */
+static const struct pcl812_board boardtypes[] = {
+ {
+ .name = "pcl812",
+ .board_type = boardPCL812,
+ .n_aichan = 16,
+ .n_aochan = 2,
+ .ai_ns_min = 33000,
+ .rangelist_ai = &range_bipolar10,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "pcl812pg",
+ .board_type = boardPCL812PG,
+ .n_aichan = 16,
+ .n_aochan = 2,
+ .ai_ns_min = 33000,
+ .rangelist_ai = &range_pcl812pg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "acl8112pg",
+ .board_type = boardPCL812PG,
+ .n_aichan = 16,
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_pcl812pg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "acl8112dg",
+ .board_type = boardACL8112,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_acl8112dg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_mpc508_mux = 1,
+ .has_dio = 1,
+ }, {
+ .name = "acl8112hg",
+ .board_type = boardACL8112,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_acl8112hg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_mpc508_mux = 1,
+ .has_dio = 1,
+ }, {
+ .name = "a821pgl",
+ .board_type = boardA821,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 1,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_pcl813b_ai,
+ .IRQbits = 0x000c,
+ .has_dio = 1,
+ }, {
+ .name = "a821pglnda",
+ .board_type = boardA821,
+ .n_aichan = 16, /* 8 differential */
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_pcl813b_ai,
+ .IRQbits = 0x000c,
+ }, {
+ .name = "a821pgh",
+ .board_type = boardA821,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 1,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_a821pgh_ai,
+ .IRQbits = 0x000c,
+ .has_dio = 1,
+ }, {
+ .name = "a822pgl",
+ .board_type = boardACL8112,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_acl8112dg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "a822pgh",
+ .board_type = boardACL8112,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_acl8112hg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "a823pgl",
+ .board_type = boardACL8112,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 8000,
+ .rangelist_ai = &range_acl8112dg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "a823pgh",
+ .board_type = boardACL8112,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 8000,
+ .rangelist_ai = &range_acl8112hg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "pcl813",
+ .board_type = boardPCL813,
+ .n_aichan = 32,
+ .rangelist_ai = &range_pcl813b_ai,
+ }, {
+ .name = "pcl813b",
+ .board_type = boardPCL813B,
+ .n_aichan = 32,
+ .rangelist_ai = &range_pcl813b_ai,
+ }, {
+ .name = "acl8113",
+ .board_type = boardACL8113,
+ .n_aichan = 32,
+ .rangelist_ai = &range_acl8113_1_ai,
+ }, {
+ .name = "iso813",
+ .board_type = boardISO813,
+ .n_aichan = 32,
+ .rangelist_ai = &range_iso813_1_ai,
+ }, {
+ .name = "acl8216",
+ .board_type = boardACL8216,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_pcl813b2_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_16bit_ai = 1,
+ .has_mpc508_mux = 1,
+ .has_dio = 1,
+ }, {
+ .name = "a826pg",
+ .board_type = boardACL8216,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_pcl813b2_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_16bit_ai = 1,
+ .has_dio = 1,
+ },
};
struct pcl812_private {
-
- unsigned char valid; /* =1 device is OK */
unsigned char dma; /* >0 use dma ( usedDMA channel) */
- unsigned char use_diff; /* =1 diff inputs */
- unsigned char use_MPC; /* 1=board uses MPC508A multiplexor */
- unsigned char use_ext_trg; /* 1=board uses external trigger */
unsigned char range_correction; /* =1 we must add 1 to range number */
- unsigned char old_chan_reg; /* lastly used chan/gain pair */
- unsigned char old_gain_reg;
+ unsigned int last_ai_chanspec;
unsigned char mode_reg_int; /* there is stored INT number for some card */
- unsigned char ai_neverending; /* =1 we do unlimited AI */
- unsigned char ai_eos; /* 1=EOS wake up */
- unsigned char ai_dma; /* =1 we use DMA */
unsigned int ai_poll_ptr; /* how many sampes transfer poll */
- unsigned int ai_scans; /* len of scanlist */
unsigned int ai_act_scan; /* how many scans we finished */
- unsigned int ai_chanlist[MAX_CHANLIST_LEN]; /* our copy of channel/range list */
- unsigned int ai_n_chan; /* how many channels is measured */
- unsigned int ai_flags; /* flaglist */
- unsigned int ai_data_len; /* len of data buffer */
- unsigned int ai_is16b; /* =1 we have 16 bit card */
+ unsigned int dmapages;
+ unsigned int hwdmasize;
unsigned long dmabuf[2]; /* PTR to DMA buf */
- unsigned int dmapages[2]; /* how many pages we have allocated */
unsigned int hwdmaptr[2]; /* HW PTR to DMA buf */
- unsigned int hwdmasize[2]; /* DMA buf size in bytes */
unsigned int dmabytestomove[2]; /* how many bytes DMA transfer */
int next_dma_buf; /* which buffer is next to use */
unsigned int dma_runs_to_end; /* how many times we must switch DMA buffers */
unsigned int last_dma_run; /* how many bytes to transfer on last DMA buffer */
unsigned int max_812_ai_mode0_rangewait; /* setling time for gain */
unsigned int ao_readback[2]; /* data for AO readback */
+ unsigned int divisor1;
+ unsigned int divisor2;
+ unsigned int use_diff:1;
+ unsigned int use_mpc508:1;
+ unsigned int use_ext_trg:1;
+ unsigned int ai_dma:1;
+ unsigned int ai_eos:1;
};
-/*
-==============================================================================
-*/
-static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2);
-static void setup_range_channel(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int rangechan, char wait);
-static int pcl812_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-/*
-==============================================================================
-*/
-static int pcl812_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl812_start_pacer(struct comedi_device *dev, bool load_timers)
{
struct pcl812_private *devpriv = dev->private;
- int n;
- int timeout, hi;
-
- /* select software trigger */
- outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE);
- /* select channel and renge */
- setup_range_channel(dev, s, insn->chanspec, 1);
- for (n = 0; n < insn->n; n++) {
- /* start conversion */
- outb(255, dev->iobase + PCL812_SOFTTRIG);
- udelay(5);
- timeout = 50; /* wait max 50us, it must finish under 33us */
- while (timeout--) {
- hi = inb(dev->iobase + PCL812_AD_HI);
- if (!(hi & PCL812_DRDY))
- goto conv_finish;
- udelay(1);
- }
- dev_dbg(dev->class_dev, "A/D insn read timeout\n");
- outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
- return -ETIME;
+ unsigned long timer_base = dev->iobase + PCL812_TIMER_BASE;
+
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ udelay(1);
-conv_finish:
- data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO);
+ if (load_timers) {
+ i8254_write(timer_base, 0, 2, devpriv->divisor2);
+ i8254_write(timer_base, 0, 1, devpriv->divisor1);
}
- outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
- return n;
}
-/*
-==============================================================================
-*/
-static int acl8216_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl812_ai_setup_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- int n;
- int timeout;
-
- /* select software trigger */
- outb(1, dev->iobase + PCL812_MODE);
- /* select channel and renge */
- setup_range_channel(dev, s, insn->chanspec, 1);
- for (n = 0; n < insn->n; n++) {
- /* start conversion */
- outb(255, dev->iobase + PCL812_SOFTTRIG);
- udelay(5);
- timeout = 50; /* wait max 50us, it must finish under 33us */
- while (timeout--) {
- if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY))
- goto conv_finish;
- udelay(1);
+ struct pcl812_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int dma_flags;
+ unsigned int bytes;
+
+ /* we use EOS, so adapt DMA buffer to one scan */
+ if (devpriv->ai_eos) {
+ devpriv->dmabytestomove[0] =
+ cmd->chanlist_len * sizeof(short);
+ devpriv->dmabytestomove[1] =
+ cmd->chanlist_len * sizeof(short);
+ devpriv->dma_runs_to_end = 1;
+ } else {
+ devpriv->dmabytestomove[0] = devpriv->hwdmasize;
+ devpriv->dmabytestomove[1] = devpriv->hwdmasize;
+ if (s->async->prealloc_bufsz < devpriv->hwdmasize) {
+ devpriv->dmabytestomove[0] =
+ s->async->prealloc_bufsz;
+ devpriv->dmabytestomove[1] =
+ s->async->prealloc_bufsz;
}
- dev_dbg(dev->class_dev, "A/D insn read timeout\n");
- outb(0, dev->iobase + PCL812_MODE);
- return -ETIME;
-
-conv_finish:
- data[n] =
- (inb(dev->iobase +
- PCL812_AD_HI) << 8) | inb(dev->iobase + PCL812_AD_LO);
+ if (cmd->stop_src == TRIG_NONE) {
+ devpriv->dma_runs_to_end = 1;
+ } else {
+ /* how many samples we must transfer? */
+ bytes = cmd->chanlist_len *
+ cmd->stop_arg * sizeof(short);
+
+ /* how many DMA pages we must fill */
+ devpriv->dma_runs_to_end =
+ bytes / devpriv->dmabytestomove[0];
+
+ /* on last dma transfer must be moved */
+ devpriv->last_dma_run =
+ bytes % devpriv->dmabytestomove[0];
+ if (devpriv->dma_runs_to_end == 0)
+ devpriv->dmabytestomove[0] =
+ devpriv->last_dma_run;
+ devpriv->dma_runs_to_end--;
+ }
+ }
+ if (devpriv->dmabytestomove[0] > devpriv->hwdmasize) {
+ devpriv->dmabytestomove[0] = devpriv->hwdmasize;
+ devpriv->ai_eos = 0;
}
- outb(0, dev->iobase + PCL812_MODE);
- return n;
+ if (devpriv->dmabytestomove[1] > devpriv->hwdmasize) {
+ devpriv->dmabytestomove[1] = devpriv->hwdmasize;
+ devpriv->ai_eos = 0;
+ }
+ devpriv->next_dma_buf = 0;
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ dma_flags = claim_dma_lock();
+ clear_dma_ff(devpriv->dma);
+ set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
+ set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]);
+ release_dma_lock(dma_flags);
+ enable_dma(devpriv->dma);
}
-/*
-==============================================================================
-*/
-static int pcl812_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl812_ai_setup_next_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct pcl812_private *devpriv = dev->private;
- int chan = CR_CHAN(insn->chanspec);
- int i;
+ unsigned long dma_flags;
- for (i = 0; i < insn->n; i++) {
- outb((data[i] & 0xff),
- dev->iobase + (chan ? PCL812_DA2_LO : PCL812_DA1_LO));
- outb((data[i] >> 8) & 0x0f,
- dev->iobase + (chan ? PCL812_DA2_HI : PCL812_DA1_HI));
- devpriv->ao_readback[chan] = data[i];
+ devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
+ disable_dma(devpriv->dma);
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ dma_flags = claim_dma_lock();
+ set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
+ if (devpriv->ai_eos) {
+ set_dma_count(devpriv->dma,
+ devpriv->dmabytestomove[devpriv->next_dma_buf]);
+ } else {
+ if (devpriv->dma_runs_to_end) {
+ set_dma_count(devpriv->dma,
+ devpriv->dmabytestomove[devpriv->
+ next_dma_buf]);
+ } else {
+ set_dma_count(devpriv->dma, devpriv->last_dma_run);
+ }
+ devpriv->dma_runs_to_end--;
}
-
- return i;
+ release_dma_lock(dma_flags);
+ enable_dma(devpriv->dma);
}
-/*
-==============================================================================
-*/
-static int pcl812_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl812_ai_set_chan_range(struct comedi_device *dev,
+ unsigned int chanspec, char wait)
{
struct pcl812_private *devpriv = dev->private;
- int chan = CR_CHAN(insn->chanspec);
- int i;
+ unsigned int chan = CR_CHAN(chanspec);
+ unsigned int range = CR_RANGE(chanspec);
+ unsigned int mux = 0;
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
+ if (chanspec == devpriv->last_ai_chanspec)
+ return;
+
+ devpriv->last_ai_chanspec = chanspec;
+
+ if (devpriv->use_mpc508) {
+ if (devpriv->use_diff) {
+ mux |= PCL812_MUX_CS0 | PCL812_MUX_CS1;
+ } else {
+ if (chan < 8)
+ mux |= PCL812_MUX_CS0;
+ else
+ mux |= PCL812_MUX_CS1;
+ }
+ }
+
+ outb(mux | PCL812_MUX_CHAN(chan), dev->iobase + PCL812_MUX_REG);
+ outb(range + devpriv->range_correction, dev->iobase + PCL812_RANGE_REG);
- return i;
+ if (wait)
+ /*
+ * XXX this depends on selected range and can be very long for
+ * some high gain ranges!
+ */
+ udelay(devpriv->max_812_ai_mode0_rangewait);
}
-/*
-==============================================================================
-*/
-static int pcl812_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl812_ai_clear_eoc(struct comedi_device *dev)
{
- data[1] = inb(dev->iobase + PCL812_DI_LO);
- data[1] |= inb(dev->iobase + PCL812_DI_HI) << 8;
+ /* writing any value clears the interrupt request */
+ outb(0, dev->iobase + PCL812_STATUS_REG);
+}
- return insn->n;
+static void pcl812_ai_soft_trig(struct comedi_device *dev)
+{
+ /* writing any value triggers a software conversion */
+ outb(255, dev->iobase + PCL812_SOFTTRIG_REG);
}
-static int pcl812_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static unsigned int pcl812_ai_get_sample(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- if (comedi_dio_update_state(s, data)) {
- outb(s->state & 0xff, dev->iobase + PCL812_DO_LO);
- outb((s->state >> 8), dev->iobase + PCL812_DO_HI);
- }
+ unsigned int val;
- data[1] = s->state;
+ val = inb(dev->iobase + PCL812_AI_MSB_REG) << 8;
+ val |= inb(dev->iobase + PCL812_AI_LSB_REG);
- return insn->n;
+ return val & s->maxdata;
+}
+
+static int pcl812_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ if (s->maxdata > 0x0fff) {
+ status = inb(dev->iobase + PCL812_STATUS_REG);
+ if ((status & PCL812_STATUS_DRDY) == 0)
+ return 0;
+ } else {
+ status = inb(dev->iobase + PCL812_AI_MSB_REG);
+ if ((status & PCL812_AI_MSB_DRDY) == 0)
+ return 0;
+ }
+ return -EBUSY;
}
-/*
-==============================================================================
-*/
static int pcl812_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
@@ -545,7 +721,7 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
struct pcl812_private *devpriv = dev->private;
int err = 0;
unsigned int flags;
- int tmp, divisor1, divisor2;
+ int tmp;
/* Step 1 : check if triggers are trivially valid */
@@ -600,8 +776,9 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
if (cmd->convert_src == TRIG_TIMER) {
tmp = cmd->convert_arg;
- i8253_cascade_ns_to_timer(board->i8254_osc_base,
- &divisor1, &divisor2,
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ,
+ &devpriv->divisor1,
+ &devpriv->divisor2,
&cmd->convert_arg, cmd->flags);
if (cmd->convert_arg < board->ai_ns_min)
cmd->convert_arg = board->ai_ns_min;
@@ -615,54 +792,21 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
return 0;
}
-/*
-==============================================================================
-*/
static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
- const struct pcl812_board *board = comedi_board(dev);
struct pcl812_private *devpriv = dev->private;
- unsigned int divisor1 = 0, divisor2 = 0, i, dma_flags, bytes;
struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int ctrl = 0;
+ unsigned int i;
- if (cmd->start_src != TRIG_NOW)
- return -EINVAL;
- if (cmd->scan_begin_src != TRIG_FOLLOW)
- return -EINVAL;
- if (devpriv->use_ext_trg) {
- if (cmd->convert_src != TRIG_EXT)
- return -EINVAL;
- } else {
- if (cmd->convert_src != TRIG_TIMER)
- return -EINVAL;
- }
- if (cmd->scan_end_src != TRIG_COUNT)
- return -EINVAL;
- if (cmd->scan_end_arg != cmd->chanlist_len)
- return -EINVAL;
- if (cmd->chanlist_len > MAX_CHANLIST_LEN)
- return -EINVAL;
-
- if (cmd->convert_src == TRIG_TIMER) {
- if (cmd->convert_arg < board->ai_ns_min)
- cmd->convert_arg = board->ai_ns_min;
- i8253_cascade_ns_to_timer(board->i8254_osc_base,
- &divisor1, &divisor2,
- &cmd->convert_arg, cmd->flags);
- }
-
- start_pacer(dev, -1, 0, 0); /* stop pacer */
+ pcl812_start_pacer(dev, false);
- devpriv->ai_n_chan = cmd->chanlist_len;
- memcpy(devpriv->ai_chanlist, cmd->chanlist,
- sizeof(unsigned int) * cmd->scan_end_arg);
- /* select first channel and range */
- setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1);
+ pcl812_ai_set_chan_range(dev, cmd->chanlist[0], 1);
if (devpriv->dma) { /* check if we can use DMA transfer */
devpriv->ai_dma = 1;
- for (i = 1; i < devpriv->ai_n_chan; i++)
- if (devpriv->ai_chanlist[0] != devpriv->ai_chanlist[i]) {
+ for (i = 1; i < cmd->chanlist_len; i++)
+ if (cmd->chanlist[0] != cmd->chanlist[i]) {
/* we cann't use DMA :-( */
devpriv->ai_dma = 0;
break;
@@ -670,212 +814,105 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
} else
devpriv->ai_dma = 0;
- devpriv->ai_flags = cmd->flags;
- devpriv->ai_data_len = s->async->prealloc_bufsz;
- if (cmd->stop_src == TRIG_COUNT) {
- devpriv->ai_scans = cmd->stop_arg;
- devpriv->ai_neverending = 0;
- } else {
- devpriv->ai_scans = 0;
- devpriv->ai_neverending = 1;
- }
-
devpriv->ai_act_scan = 0;
devpriv->ai_poll_ptr = 0;
s->async->cur_chan = 0;
/* don't we want wake up every scan? */
- if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
+ if (cmd->flags & TRIG_WAKE_EOS) {
devpriv->ai_eos = 1;
/* DMA is useless for this situation */
- if (devpriv->ai_n_chan == 1)
+ if (cmd->chanlist_len == 1)
devpriv->ai_dma = 0;
}
- if (devpriv->ai_dma) {
- /* we use EOS, so adapt DMA buffer to one scan */
- if (devpriv->ai_eos) {
- devpriv->dmabytestomove[0] =
- devpriv->ai_n_chan * sizeof(short);
- devpriv->dmabytestomove[1] =
- devpriv->ai_n_chan * sizeof(short);
- devpriv->dma_runs_to_end = 1;
- } else {
- devpriv->dmabytestomove[0] = devpriv->hwdmasize[0];
- devpriv->dmabytestomove[1] = devpriv->hwdmasize[1];
- if (devpriv->ai_data_len < devpriv->hwdmasize[0])
- devpriv->dmabytestomove[0] =
- devpriv->ai_data_len;
- if (devpriv->ai_data_len < devpriv->hwdmasize[1])
- devpriv->dmabytestomove[1] =
- devpriv->ai_data_len;
- if (devpriv->ai_neverending) {
- devpriv->dma_runs_to_end = 1;
- } else {
- /* how many samples we must transfer? */
- bytes = devpriv->ai_n_chan *
- devpriv->ai_scans * sizeof(short);
-
- /* how many DMA pages we must fill */
- devpriv->dma_runs_to_end =
- bytes / devpriv->dmabytestomove[0];
-
- /* on last dma transfer must be moved */
- devpriv->last_dma_run =
- bytes % devpriv->dmabytestomove[0];
- if (devpriv->dma_runs_to_end == 0)
- devpriv->dmabytestomove[0] =
- devpriv->last_dma_run;
- devpriv->dma_runs_to_end--;
- }
- }
- if (devpriv->dmabytestomove[0] > devpriv->hwdmasize[0]) {
- devpriv->dmabytestomove[0] = devpriv->hwdmasize[0];
- devpriv->ai_eos = 0;
- }
- if (devpriv->dmabytestomove[1] > devpriv->hwdmasize[1]) {
- devpriv->dmabytestomove[1] = devpriv->hwdmasize[1];
- devpriv->ai_eos = 0;
- }
- devpriv->next_dma_buf = 0;
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- dma_flags = claim_dma_lock();
- clear_dma_ff(devpriv->dma);
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
- set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]);
- release_dma_lock(dma_flags);
- enable_dma(devpriv->dma);
- }
+ if (devpriv->ai_dma)
+ pcl812_ai_setup_dma(dev, s);
switch (cmd->convert_src) {
case TRIG_TIMER:
- start_pacer(dev, 1, divisor1, divisor2);
+ pcl812_start_pacer(dev, true);
break;
}
- if (devpriv->ai_dma) /* let's go! */
- outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE);
- else /* let's go! */
- outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE);
+ if (devpriv->ai_dma)
+ ctrl |= PCL812_CTRL_PACER_DMA_TRIG;
+ else
+ ctrl |= PCL812_CTRL_PACER_EOC_TRIG;
+ outb(devpriv->mode_reg_int | ctrl, dev->iobase + PCL812_CTRL_REG);
return 0;
}
-/*
-==============================================================================
-*/
-static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d)
+static bool pcl812_ai_next_chan(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- char err = 1;
- unsigned int mask, timeout;
- struct comedi_device *dev = d;
struct pcl812_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
- unsigned int next_chan;
+ struct comedi_cmd *cmd = &s->async->cmd;
- s->async->events = 0;
+ s->async->events |= COMEDI_CB_BLOCK;
- timeout = 50; /* wait max 50us, it must finish under 33us */
- if (devpriv->ai_is16b) {
- mask = 0xffff;
- while (timeout--) {
- if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) {
- err = 0;
- break;
- }
- udelay(1);
- }
- } else {
- mask = 0x0fff;
- while (timeout--) {
- if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) {
- err = 0;
- break;
- }
- udelay(1);
- }
+ s->async->cur_chan++;
+ if (s->async->cur_chan >= cmd->chanlist_len) {
+ s->async->cur_chan = 0;
+ devpriv->ai_act_scan++;
+ s->async->events |= COMEDI_CB_EOS;
+ }
+
+ if (cmd->stop_src == TRIG_COUNT &&
+ devpriv->ai_act_scan >= cmd->stop_arg) {
+ /* all data sampled */
+ s->async->events |= COMEDI_CB_EOA;
+ return false;
}
- if (err) {
+ return true;
+}
+
+static void pcl812_handle_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int next_chan;
+
+ if (pcl812_ai_eoc(dev, s, NULL, 0)) {
dev_dbg(dev->class_dev, "A/D cmd IRQ without DRDY!\n");
- pcl812_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ return;
}
- comedi_buf_put(s->async,
- ((inb(dev->iobase + PCL812_AD_HI) << 8) |
- inb(dev->iobase + PCL812_AD_LO)) & mask);
+ comedi_buf_put(s->async, pcl812_ai_get_sample(dev, s));
/* Set up next channel. Added by abbotti 2010-01-20, but untested. */
next_chan = s->async->cur_chan + 1;
- if (next_chan >= devpriv->ai_n_chan)
+ if (next_chan >= cmd->chanlist_len)
next_chan = 0;
- if (devpriv->ai_chanlist[s->async->cur_chan] !=
- devpriv->ai_chanlist[next_chan])
- setup_range_channel(dev, s, devpriv->ai_chanlist[next_chan], 0);
-
- outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
+ if (cmd->chanlist[s->async->cur_chan] != cmd->chanlist[next_chan])
+ pcl812_ai_set_chan_range(dev, cmd->chanlist[next_chan], 0);
- s->async->cur_chan = next_chan;
- if (next_chan == 0) { /* one scan done */
- devpriv->ai_act_scan++;
- if (!(devpriv->ai_neverending))
- /* all data sampled */
- if (devpriv->ai_act_scan >= devpriv->ai_scans) {
- pcl812_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- }
- }
-
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ pcl812_ai_next_chan(dev, s);
}
-/*
-==============================================================================
-*/
static void transfer_from_dma_buf(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned short *ptr,
unsigned int bufptr, unsigned int len)
{
- struct pcl812_private *devpriv = dev->private;
unsigned int i;
- s->async->events = 0;
for (i = len; i; i--) {
- /* get one sample */
comedi_buf_put(s->async, ptr[bufptr++]);
- s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
- s->async->cur_chan = 0;
- devpriv->ai_act_scan++;
- if (!devpriv->ai_neverending)
- /* all data sampled */
- if (devpriv->ai_act_scan >= devpriv->ai_scans) {
- pcl812_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- break;
- }
- }
+ if (!pcl812_ai_next_chan(dev, s))
+ break;
}
-
- comedi_event(dev, s);
}
-/*
-==============================================================================
-*/
-static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d)
+static void pcl812_handle_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- struct comedi_device *dev = d;
struct pcl812_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
- unsigned long dma_flags;
int len, bufptr;
unsigned short *ptr;
@@ -883,58 +920,36 @@ static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d)
len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) -
devpriv->ai_poll_ptr;
- devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
- disable_dma(devpriv->dma);
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- dma_flags = claim_dma_lock();
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
- if (devpriv->ai_eos) {
- set_dma_count(devpriv->dma,
- devpriv->dmabytestomove[devpriv->next_dma_buf]);
- } else {
- if (devpriv->dma_runs_to_end) {
- set_dma_count(devpriv->dma,
- devpriv->dmabytestomove[devpriv->
- next_dma_buf]);
- } else {
- set_dma_count(devpriv->dma, devpriv->last_dma_run);
- }
- devpriv->dma_runs_to_end--;
- }
- release_dma_lock(dma_flags);
- enable_dma(devpriv->dma);
-
- outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
+ pcl812_ai_setup_next_dma(dev, s);
bufptr = devpriv->ai_poll_ptr;
devpriv->ai_poll_ptr = 0;
transfer_from_dma_buf(dev, s, ptr, bufptr, len);
-
- return IRQ_HANDLED;
}
-/*
-==============================================================================
-*/
-static irqreturn_t interrupt_pcl812(int irq, void *d)
+static irqreturn_t pcl812_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
+ struct comedi_subdevice *s = dev->read_subdev;
struct pcl812_private *devpriv = dev->private;
if (!dev->attached) {
- comedi_error(dev, "spurious interrupt");
+ pcl812_ai_clear_eoc(dev);
return IRQ_HANDLED;
}
+
if (devpriv->ai_dma)
- return interrupt_pcl812_ai_dma(irq, d);
+ pcl812_handle_dma(dev, s);
else
- return interrupt_pcl812_ai_int(irq, d);
+ pcl812_handle_eoc(dev, s);
+
+ pcl812_ai_clear_eoc(dev);
+
+ cfc_handle_events(dev, s);
+ return IRQ_HANDLED;
}
-/*
-==============================================================================
-*/
static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct pcl812_private *devpriv = dev->private;
@@ -979,204 +994,308 @@ static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
return s->async->buf_write_count - s->async->buf_read_count;
}
-/*
-==============================================================================
-*/
-static void setup_range_channel(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int rangechan, char wait)
+static int pcl812_ai_cancel(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct pcl812_private *devpriv = dev->private;
- unsigned char chan_reg = CR_CHAN(rangechan); /* normal board */
- /* gain index */
- unsigned char gain_reg = CR_RANGE(rangechan) +
- devpriv->range_correction;
- if ((chan_reg == devpriv->old_chan_reg)
- && (gain_reg == devpriv->old_gain_reg))
- return; /* we can return, no change */
+ if (devpriv->ai_dma)
+ disable_dma(devpriv->dma);
- devpriv->old_chan_reg = chan_reg;
- devpriv->old_gain_reg = gain_reg;
+ outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG,
+ dev->iobase + PCL812_CTRL_REG);
+ pcl812_start_pacer(dev, false);
+ pcl812_ai_clear_eoc(dev);
+ return 0;
+}
- if (devpriv->use_MPC) {
- if (devpriv->use_diff) {
- chan_reg = chan_reg | 0x30; /* DIFF inputs */
- } else {
- if (chan_reg & 0x80)
- /* SE inputs 8-15 */
- chan_reg = chan_reg | 0x20;
- else
- /* SE inputs 0-7 */
- chan_reg = chan_reg | 0x10;
- }
- }
+static int pcl812_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct pcl812_private *devpriv = dev->private;
+ int ret = 0;
+ int i;
- outb(chan_reg, dev->iobase + PCL812_MUX); /* select channel */
- outb(gain_reg, dev->iobase + PCL812_GAIN); /* select gain */
+ outb(devpriv->mode_reg_int | PCL812_CTRL_SOFT_TRIG,
+ dev->iobase + PCL812_CTRL_REG);
+ pcl812_ai_set_chan_range(dev, insn->chanspec, 1);
- if (wait)
- /*
- * XXX this depends on selected range and can be very long for
- * some high gain ranges!
- */
- udelay(devpriv->max_812_ai_mode0_rangewait);
+ for (i = 0; i < insn->n; i++) {
+ pcl812_ai_clear_eoc(dev);
+ pcl812_ai_soft_trig(dev);
+
+ ret = comedi_timeout(dev, s, insn, pcl812_ai_eoc, 0);
+ if (ret)
+ break;
+
+ data[i] = pcl812_ai_get_sample(dev, s);
+ }
+ outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG,
+ dev->iobase + PCL812_CTRL_REG);
+ pcl812_ai_clear_eoc(dev);
+
+ return ret ? ret : insn->n;
}
-/*
-==============================================================================
-*/
-static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2)
+static int pcl812_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- outb(0xb4, dev->iobase + PCL812_CTRCTL);
- outb(0x74, dev->iobase + PCL812_CTRCTL);
- udelay(1);
+ struct pcl812_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
- if (mode == 1) {
- outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2);
- outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2);
- outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1);
- outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1);
+ for (i = 0; i < insn->n; i++) {
+ outb((data[i] & 0xff),
+ dev->iobase + PCL812_AO_LSB_REG(chan));
+ outb((data[i] >> 8) & 0x0f,
+ dev->iobase + PCL812_AO_MSB_REG(chan));
+ devpriv->ao_readback[chan] = data[i];
}
+
+ return insn->n;
}
-/*
-==============================================================================
-*/
-static int pcl812_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int pcl812_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct pcl812_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
- if (devpriv->ai_dma)
- disable_dma(devpriv->dma);
- outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
- /* Stop A/D */
- outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
- start_pacer(dev, -1, 0, 0); /* stop 8254 */
- outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
- return 0;
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
+
+ return insn->n;
+}
+
+static int pcl812_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ data[1] = inb(dev->iobase + PCL812_DI_LSB_REG) |
+ (inb(dev->iobase + PCL812_DI_MSB_REG) << 8);
+
+ return insn->n;
+}
+
+static int pcl812_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (comedi_dio_update_state(s, data)) {
+ outb(s->state & 0xff, dev->iobase + PCL812_DO_LSB_REG);
+ outb((s->state >> 8), dev->iobase + PCL812_DO_MSB_REG);
+ }
+
+ data[1] = s->state;
+
+ return insn->n;
}
-/*
-==============================================================================
-*/
static void pcl812_reset(struct comedi_device *dev)
{
const struct pcl812_board *board = comedi_board(dev);
struct pcl812_private *devpriv = dev->private;
+ unsigned int chan;
+
+ /* disable analog input trigger */
+ outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG,
+ dev->iobase + PCL812_CTRL_REG);
+ pcl812_ai_clear_eoc(dev);
+
+ /* stop pacer */
+ if (board->IRQbits)
+ pcl812_start_pacer(dev, false);
+
+ /*
+ * Invalidate last_ai_chanspec then set analog input to
+ * known channel/range.
+ */
+ devpriv->last_ai_chanspec = CR_PACK(16, 0, 0);
+ pcl812_ai_set_chan_range(dev, CR_PACK(0, 0, 0), 0);
+
+ /* set analog output channels to 0V */
+ for (chan = 0; chan < board->n_aochan; chan++) {
+ outb(0, dev->iobase + PCL812_AO_LSB_REG(chan));
+ outb(0, dev->iobase + PCL812_AO_MSB_REG(chan));
+ }
- outb(0, dev->iobase + PCL812_MUX);
- outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN);
- devpriv->old_chan_reg = -1; /* invalidate chain/gain memory */
- devpriv->old_gain_reg = -1;
+ /* set all digital outputs low */
+ if (board->has_dio) {
+ outb(0, dev->iobase + PCL812_DO_MSB_REG);
+ outb(0, dev->iobase + PCL812_DO_LSB_REG);
+ }
+}
+static void pcl812_set_ai_range_table(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_devconfig *it)
+{
+ const struct pcl812_board *board = comedi_board(dev);
+ struct pcl812_private *devpriv = dev->private;
+
+ /* default to the range table from the boardinfo */
+ s->range_table = board->rangelist_ai;
+
+ /* now check the user config option based on the boardtype */
switch (board->board_type) {
case boardPCL812PG:
+ if (it->options[4] == 1)
+ s->range_table = &range_pcl812pg2_ai;
+ break;
case boardPCL812:
- case boardACL8112:
- case boardACL8216:
- outb(0, dev->iobase + PCL812_DA2_LO);
- outb(0, dev->iobase + PCL812_DA2_HI);
- case boardA821:
- outb(0, dev->iobase + PCL812_DA1_LO);
- outb(0, dev->iobase + PCL812_DA1_HI);
- start_pacer(dev, -1, 0, 0); /* stop 8254 */
- outb(0, dev->iobase + PCL812_DO_HI);
- outb(0, dev->iobase + PCL812_DO_LO);
- outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
- outb(0, dev->iobase + PCL812_CLRINT);
+ switch (it->options[4]) {
+ case 0:
+ s->range_table = &range_bipolar10;
+ break;
+ case 1:
+ s->range_table = &range_bipolar5;
+ break;
+ case 2:
+ s->range_table = &range_bipolar2_5;
+ break;
+ case 3:
+ s->range_table = &range812_bipolar1_25;
+ break;
+ case 4:
+ s->range_table = &range812_bipolar0_625;
+ break;
+ case 5:
+ s->range_table = &range812_bipolar0_3125;
+ break;
+ default:
+ s->range_table = &range_bipolar10;
+ break;
+ }
break;
case boardPCL813B:
- case boardPCL813:
+ if (it->options[1] == 1)
+ s->range_table = &range_pcl813b2_ai;
+ break;
case boardISO813:
+ switch (it->options[1]) {
+ case 0:
+ s->range_table = &range_iso813_1_ai;
+ break;
+ case 1:
+ s->range_table = &range_iso813_1_2_ai;
+ break;
+ case 2:
+ s->range_table = &range_iso813_2_ai;
+ devpriv->range_correction = 1;
+ break;
+ case 3:
+ s->range_table = &range_iso813_2_2_ai;
+ devpriv->range_correction = 1;
+ break;
+ default:
+ s->range_table = &range_iso813_1_ai;
+ break;
+ }
+ break;
case boardACL8113:
- udelay(5);
+ switch (it->options[1]) {
+ case 0:
+ s->range_table = &range_acl8113_1_ai;
+ break;
+ case 1:
+ s->range_table = &range_acl8113_1_2_ai;
+ break;
+ case 2:
+ s->range_table = &range_acl8113_2_ai;
+ devpriv->range_correction = 1;
+ break;
+ case 3:
+ s->range_table = &range_acl8113_2_2_ai;
+ devpriv->range_correction = 1;
+ break;
+ default:
+ s->range_table = &range_acl8113_1_ai;
+ break;
+ }
break;
}
- udelay(5);
}
static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl812_board *board = comedi_board(dev);
struct pcl812_private *devpriv;
- int ret, subdev;
- unsigned int dma;
- unsigned long pages;
struct comedi_subdevice *s;
int n_subdevices;
-
- ret = comedi_request_region(dev, it->options[0], board->io_range);
- if (ret)
- return ret;
+ int subdev;
+ int ret;
+ int i;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
+ ret = comedi_request_region(dev, it->options[0], 0x10);
+ if (ret)
+ return ret;
+
if ((1 << it->options[1]) & board->IRQbits) {
- ret = request_irq(it->options[1], interrupt_pcl812, 0,
+ ret = request_irq(it->options[1], pcl812_interrupt, 0,
dev->board_name, dev);
if (ret == 0)
dev->irq = it->options[1];
}
- dma = 0;
- devpriv->dma = dma;
- if (!dev->irq)
- goto no_dma; /* if we haven't IRQ, we can't use DMA */
- if (board->DMAbits != 0) { /* board support DMA */
- dma = it->options[2];
- if (((1 << dma) & board->DMAbits) == 0) {
- dev_err(dev->class_dev,
- "DMA is out of allowed range, FAIL!\n");
- return -EINVAL; /* Bad DMA */
- }
- ret = request_dma(dma, dev->board_name);
+ /* we need an IRQ to do DMA on channel 3 or 1 */
+ if (dev->irq && board->has_dma &&
+ (it->options[2] == 3 || it->options[2] == 1)) {
+ ret = request_dma(it->options[2], dev->board_name);
if (ret) {
dev_err(dev->class_dev,
- "unable to allocate DMA %u, FAIL!\n", dma);
- return -EBUSY; /* DMA isn't free */
- }
- devpriv->dma = dma;
- pages = 1; /* we want 8KB */
- devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[0]) {
- dev_err(dev->class_dev,
- "unable to allocate DMA buffer, FAIL!\n");
- /*
- * maybe experiment with try_to_free_pages()
- * will help ....
- */
- return -EBUSY; /* no buffer :-( */
- }
- devpriv->dmapages[0] = pages;
- devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
- devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages);
- devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[1]) {
- dev_err(dev->class_dev,
- "unable to allocate DMA buffer, FAIL!\n");
+ "unable to request DMA channel %d\n",
+ it->options[2]);
return -EBUSY;
}
- devpriv->dmapages[1] = pages;
- devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
- devpriv->hwdmasize[1] = PAGE_SIZE * (1 << pages);
+ devpriv->dma = it->options[2];
+
+ devpriv->dmapages = 1; /* we want 8KB */
+ devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
+
+ for (i = 0; i < 2; i++) {
+ unsigned long dmabuf;
+
+ dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
+ if (!dmabuf)
+ return -ENOMEM;
+
+ devpriv->dmabuf[i] = dmabuf;
+ devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
+ }
}
-no_dma:
- n_subdevices = 0;
- if (board->n_aichan > 0)
- n_subdevices++;
+ /* differential analog inputs? */
+ switch (board->board_type) {
+ case boardA821:
+ if (it->options[2] == 1)
+ devpriv->use_diff = 1;
+ break;
+ case boardACL8112:
+ case boardACL8216:
+ if (it->options[4] == 1)
+ devpriv->use_diff = 1;
+ break;
+ }
+
+ n_subdevices = 1; /* all boardtypes have analog inputs */
if (board->n_aochan > 0)
n_subdevices++;
- if (board->n_dichan > 0)
- n_subdevices++;
- if (board->n_dochan > 0)
- n_subdevices++;
+ if (board->has_dio)
+ n_subdevices += 2;
ret = comedi_alloc_subdevices(dev, n_subdevices);
if (ret)
@@ -1184,146 +1303,47 @@ no_dma:
subdev = 0;
- /* analog input */
- if (board->n_aichan > 0) {
- s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE;
- switch (board->board_type) {
- case boardA821:
- if (it->options[2] == 1) {
- s->n_chan = board->n_aichan_diff;
- s->subdev_flags |= SDF_DIFF;
- devpriv->use_diff = 1;
- } else {
- s->n_chan = board->n_aichan;
- s->subdev_flags |= SDF_GROUND;
- }
- break;
- case boardACL8112:
- case boardACL8216:
- if (it->options[4] == 1) {
- s->n_chan = board->n_aichan_diff;
- s->subdev_flags |= SDF_DIFF;
- devpriv->use_diff = 1;
- } else {
- s->n_chan = board->n_aichan;
- s->subdev_flags |= SDF_GROUND;
- }
- break;
- default:
- s->n_chan = board->n_aichan;
- s->subdev_flags |= SDF_GROUND;
- break;
- }
- s->maxdata = board->ai_maxdata;
- s->range_table = board->rangelist_ai;
- if (board->board_type == boardACL8216)
- s->insn_read = acl8216_ai_insn_read;
- else
- s->insn_read = pcl812_ai_insn_read;
-
- devpriv->use_MPC = board->haveMPC508;
- if (dev->irq) {
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->len_chanlist = MAX_CHANLIST_LEN;
- s->do_cmdtest = pcl812_ai_cmdtest;
- s->do_cmd = pcl812_ai_cmd;
- s->poll = pcl812_ai_poll;
- s->cancel = pcl812_ai_cancel;
- }
- switch (board->board_type) {
- case boardPCL812PG:
- if (it->options[4] == 1)
- s->range_table = &range_pcl812pg2_ai;
- break;
- case boardPCL812:
- switch (it->options[4]) {
- case 0:
- s->range_table = &range_bipolar10;
- break;
- case 1:
- s->range_table = &range_bipolar5;
- break;
- case 2:
- s->range_table = &range_bipolar2_5;
- break;
- case 3:
- s->range_table = &range812_bipolar1_25;
- break;
- case 4:
- s->range_table = &range812_bipolar0_625;
- break;
- case 5:
- s->range_table = &range812_bipolar0_3125;
- break;
- default:
- s->range_table = &range_bipolar10;
- break;
- }
- break;
- break;
- case boardPCL813B:
- if (it->options[1] == 1)
- s->range_table = &range_pcl813b2_ai;
- break;
- case boardISO813:
- switch (it->options[1]) {
- case 0:
- s->range_table = &range_iso813_1_ai;
- break;
- case 1:
- s->range_table = &range_iso813_1_2_ai;
- break;
- case 2:
- s->range_table = &range_iso813_2_ai;
- devpriv->range_correction = 1;
- break;
- case 3:
- s->range_table = &range_iso813_2_2_ai;
- devpriv->range_correction = 1;
- break;
- default:
- s->range_table = &range_iso813_1_ai;
- break;
- }
- break;
- case boardACL8113:
- switch (it->options[1]) {
- case 0:
- s->range_table = &range_acl8113_1_ai;
- break;
- case 1:
- s->range_table = &range_acl8113_1_2_ai;
- break;
- case 2:
- s->range_table = &range_acl8113_2_ai;
- devpriv->range_correction = 1;
- break;
- case 3:
- s->range_table = &range_acl8113_2_2_ai;
- devpriv->range_correction = 1;
- break;
- default:
- s->range_table = &range_acl8113_1_ai;
- break;
- }
- break;
- }
- subdev++;
+ /* Analog Input subdevice */
+ s = &dev->subdevices[subdev];
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE;
+ if (devpriv->use_diff) {
+ s->subdev_flags |= SDF_DIFF;
+ s->n_chan = board->n_aichan / 2;
+ } else {
+ s->subdev_flags |= SDF_GROUND;
+ s->n_chan = board->n_aichan;
+ }
+ s->maxdata = board->has_16bit_ai ? 0xffff : 0x0fff;
+
+ pcl812_set_ai_range_table(dev, s, it);
+
+ s->insn_read = pcl812_ai_insn_read;
+
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = MAX_CHANLIST_LEN;
+ s->do_cmdtest = pcl812_ai_cmdtest;
+ s->do_cmd = pcl812_ai_cmd;
+ s->poll = pcl812_ai_poll;
+ s->cancel = pcl812_ai_cancel;
}
+ devpriv->use_mpc508 = board->has_mpc508_mux;
+
+ subdev++;
+
/* analog output */
if (board->n_aochan > 0) {
s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
- s->n_chan = board->n_aochan;
- s->maxdata = 0xfff;
- s->range_table = board->rangelist_ao;
- s->insn_read = pcl812_ao_insn_read;
- s->insn_write = pcl812_ao_insn_write;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
+ s->n_chan = board->n_aochan;
+ s->maxdata = 0xfff;
+ s->range_table = &range_unipolar5;
+ s->insn_read = pcl812_ao_insn_read;
+ s->insn_write = pcl812_ao_insn_write;
switch (board->board_type) {
case boardA821:
if (it->options[3] == 1)
@@ -1342,33 +1362,30 @@ no_dma:
subdev++;
}
- /* digital input */
- if (board->n_dichan > 0) {
+ if (board->has_dio) {
+ /* Digital Input subdevice */
s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = board->n_dichan;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = pcl812_di_insn_bits;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcl812_di_insn_bits;
subdev++;
- }
- /* digital output */
- if (board->n_dochan > 0) {
+ /* Digital Output subdevice */
s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = board->n_dochan;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = pcl812_do_insn_bits;
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcl812_do_insn_bits;
subdev++;
}
switch (board->board_type) {
case boardACL8216:
- devpriv->ai_is16b = 1;
case boardPCL812PG:
case boardPCL812:
case boardACL8112:
@@ -1390,8 +1407,6 @@ no_dma:
break;
}
- devpriv->valid = 1;
-
pcl812_reset(dev);
return 0;
@@ -1403,72 +1418,15 @@ static void pcl812_detach(struct comedi_device *dev)
if (devpriv) {
if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
+ free_pages(devpriv->dmabuf[0], devpriv->dmapages);
if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
+ free_pages(devpriv->dmabuf[1], devpriv->dmapages);
if (devpriv->dma)
free_dma(devpriv->dma);
}
comedi_legacy_detach(dev);
}
-static const struct pcl812_board boardtypes[] = {
- {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff,
- 33000, I8254_OSC_BASE_2MHZ, &range_bipolar10, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
- 33000, I8254_OSC_BASE_2MHZ, &range_pcl812pg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_pcl812pg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
- {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
- {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b_ai, &range_unipolar5,
- 0x000c, 0x00, PCLx1x_IORANGE, 0},
- {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b_ai, NULL,
- 0x000c, 0x00, PCLx1x_IORANGE, 0},
- {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_a821pgh_ai, &range_unipolar5,
- 0x000c, 0x00, PCLx1x_IORANGE, 0},
- {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 8000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 8000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_pcl813b_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_pcl813b_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_acl8113_1_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_iso813_1_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
- 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b2_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
- {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
- 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b2_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
-};
-
static struct comedi_driver pcl812_driver = {
.driver_name = "pcl812",
.module = THIS_MODULE,
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index e9d470459933..6f276f23fabe 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -44,40 +44,38 @@ Configuration Options:
#include "comedi_fc.h"
#include "8253.h"
-/* boards constants */
-/* IO space len */
-#define PCLx1x_RANGE 16
-
-/* INTEL 8254 counters */
-#define PCL816_CTR0 4
-#define PCL816_CTR1 5
-#define PCL816_CTR2 6
-/* R: counter read-back register W: counter control */
-#define PCL816_CTRCTL 7
-
-/* R: A/D high byte W: A/D range control */
-#define PCL816_RANGE 9
-/* W: clear INT request */
-#define PCL816_CLRINT 10
-/* R: next mux scan channel W: mux scan channel & range control pointer */
-#define PCL816_MUX 11
-/* R/W: operation control register */
-#define PCL816_CONTROL 12
-
-/* R: return status byte W: set DMA/IRQ */
-#define PCL816_STATUS 13
-#define PCL816_STATUS_DRDY_MASK 0x80
-
-/* R: low byte of A/D W: soft A/D trigger */
-#define PCL816_AD_LO 8
-/* R: high byte of A/D W: A/D range control */
-#define PCL816_AD_HI 9
-
-/* type of interrupt handler */
-#define INT_TYPE_AI1_INT 1
-#define INT_TYPE_AI1_DMA 2
-#define INT_TYPE_AI3_INT 4
-#define INT_TYPE_AI3_DMA 5
+/*
+ * Register I/O map
+ */
+#define PCL816_DO_DI_LSB_REG 0x00
+#define PCL816_DO_DI_MSB_REG 0x01
+#define PCL816_TIMER_BASE 0x04
+#define PCL816_AI_LSB_REG 0x08
+#define PCL816_AI_MSB_REG 0x09
+#define PCL816_RANGE_REG 0x09
+#define PCL816_CLRINT_REG 0x0a
+#define PCL816_MUX_REG 0x0b
+#define PCL816_MUX_SCAN(_first, _last) (((_last) << 4) | (_first))
+#define PCL816_CTRL_REG 0x0c
+#define PCL816_CTRL_DISABLE_TRIG (0 << 0)
+#define PCL816_CTRL_SOFT_TRIG (1 << 0)
+#define PCL816_CTRL_PACER_TRIG (1 << 1)
+#define PCL816_CTRL_EXT_TRIG (1 << 2)
+#define PCL816_CTRL_POE (1 << 3)
+#define PCL816_CTRL_DMAEN (1 << 4)
+#define PCL816_CTRL_INTEN (1 << 5)
+#define PCL816_CTRL_DMASRC_SLOT0 (0 << 6)
+#define PCL816_CTRL_DMASRC_SLOT1 (1 << 6)
+#define PCL816_CTRL_DMASRC_SLOT2 (2 << 6)
+#define PCL816_STATUS_REG 0x0d
+#define PCL816_STATUS_NEXT_CHAN_MASK (0xf << 0)
+#define PCL816_STATUS_INTSRC_MASK (3 << 4)
+#define PCL816_STATUS_INTSRC_SLOT0 (0 << 4)
+#define PCL816_STATUS_INTSRC_SLOT1 (1 << 4)
+#define PCL816_STATUS_INTSRC_SLOT2 (2 << 4)
+#define PCL816_STATUS_INTSRC_DMA (3 << 4)
+#define PCL816_STATUS_INTACT (1 << 6)
+#define PCL816_STATUS_DRDY (1 << 7)
#define MAGIC_DMA_WORD 0x5a5a
@@ -95,314 +93,284 @@ static const struct comedi_lrange range_pcl816 = {
};
struct pcl816_board {
+ const char *name;
+ int ai_maxdata;
+ int ao_maxdata;
+ int ai_chanlist;
+};
- const char *name; /* board name */
- int n_ranges; /* len of range list */
- int n_aichan; /* num of A/D chans in diferencial mode */
- unsigned int ai_ns_min; /* minimal allowed delay between samples (in ns) */
- int n_aochan; /* num of D/A chans */
- int n_dichan; /* num of DI chans */
- int n_dochan; /* num of DO chans */
- const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
- const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
- unsigned int io_range; /* len of IO space */
- unsigned int IRQbits; /* allowed interrupts */
- unsigned int DMAbits; /* allowed DMA chans */
- int ai_maxdata; /* maxdata for A/D */
- int ao_maxdata; /* maxdata for D/A */
- int ai_chanlist; /* allowed len of channel list A/D */
- int ao_chanlist; /* allowed len of channel list D/A */
- int i8254_osc_base; /* 1/frequency of on board oscilator in ns */
+static const struct pcl816_board boardtypes[] = {
+ {
+ .name = "pcl816",
+ .ai_maxdata = 0xffff,
+ .ao_maxdata = 0xffff,
+ .ai_chanlist = 1024,
+ }, {
+ .name = "pcl814b",
+ .ai_maxdata = 0x3fff,
+ .ao_maxdata = 0x3fff,
+ .ai_chanlist = 1024,
+ },
};
struct pcl816_private {
-
unsigned int dma; /* used DMA, 0=don't use DMA */
+ unsigned int dmapages;
+ unsigned int hwdmasize;
unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
- unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
- unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
- unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
int next_dma_buf; /* which DMA buffer will be used next round */
long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
-
- unsigned int ai_scans; /* len of scanlist */
- unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */
- int irq_blocked; /* 1=IRQ now uses any subdev */
- int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */
- int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
- struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
int ai_act_scan; /* how many scans we finished */
- unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */
- unsigned int ai_act_chanlist_len; /* how long is actual MUX list */
- unsigned int ai_act_chanlist_pos; /* actual position in MUX list */
- unsigned int ai_n_chan; /* how many channels per scan */
unsigned int ai_poll_ptr; /* how many sampes transfer poll */
+ unsigned int divisor1;
+ unsigned int divisor2;
+ unsigned int ai_cmd_running:1;
+ unsigned int ai_cmd_canceled:1;
};
-/*
-==============================================================================
-*/
static int check_channel_list(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int *chanlist, unsigned int chanlen);
-static void setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int seglen);
-static int pcl816_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2);
-static int pcl816_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-
-/*
-==============================================================================
- ANALOG INPUT MODE0, 816 cards, slow version
-*/
-static int pcl816_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl816_start_pacer(struct comedi_device *dev, bool load_counters)
{
- int n;
- int timeout;
-
- /* software trigger, DMA and INT off */
- outb(0, dev->iobase + PCL816_CONTROL);
- /* clear INT (conversion end) flag */
- outb(0, dev->iobase + PCL816_CLRINT);
-
- /* Set the input channel */
- outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX);
- /* select gain */
- outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE);
-
- for (n = 0; n < insn->n; n++) {
-
- outb(0, dev->iobase + PCL816_AD_LO); /* start conversion */
-
- timeout = 100;
- while (timeout--) {
- if (!(inb(dev->iobase + PCL816_STATUS) &
- PCL816_STATUS_DRDY_MASK)) {
- /* return read value */
- data[n] =
- ((inb(dev->iobase +
- PCL816_AD_HI) << 8) |
- (inb(dev->iobase + PCL816_AD_LO)));
- /* clear INT (conversion end) flag */
- outb(0, dev->iobase + PCL816_CLRINT);
- break;
- }
- udelay(1);
- }
- /* Return timeout error */
- if (!timeout) {
- comedi_error(dev, "A/D insn timeout\n");
- data[0] = 0;
- /* clear INT (conversion end) flag */
- outb(0, dev->iobase + PCL816_CLRINT);
- return -EIO;
- }
+ struct pcl816_private *devpriv = dev->private;
+ unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE;
+
+ i8254_set_mode(timer_base, 0, 0, I8254_MODE1 | I8254_BINARY);
+ i8254_write(timer_base, 0, 0, 0x00ff);
+ udelay(1);
+
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ udelay(1);
+ if (load_counters) {
+ i8254_write(timer_base, 0, 2, devpriv->divisor2);
+ i8254_write(timer_base, 0, 1, devpriv->divisor1);
}
- return n;
}
-/*
-==============================================================================
- analog input interrupt mode 1 & 3, 818 cards
- one sample per interrupt version
-*/
-static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d)
+static void pcl816_ai_setup_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- struct comedi_device *dev = d;
struct pcl816_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
- unsigned char low, hi;
- int timeout = 50; /* wait max 50us */
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int dma_flags;
+ unsigned int bytes;
- while (timeout--) {
- if (!(inb(dev->iobase + PCL816_STATUS) &
- PCL816_STATUS_DRDY_MASK))
- break;
- udelay(1);
+ bytes = devpriv->hwdmasize;
+ if (cmd->stop_src == TRIG_COUNT) {
+ /* how many */
+ bytes = s->async->cmd.chanlist_len *
+ s->async->cmd.chanlist_len *
+ sizeof(short);
+
+ /* how many DMA pages we must fill */
+ devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize;
+
+ /* on last dma transfer must be moved */
+ devpriv->last_dma_run = bytes % devpriv->hwdmasize;
+ devpriv->dma_runs_to_end--;
+ if (devpriv->dma_runs_to_end >= 0)
+ bytes = devpriv->hwdmasize;
+ } else
+ devpriv->dma_runs_to_end = -1;
+
+ devpriv->next_dma_buf = 0;
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ dma_flags = claim_dma_lock();
+ clear_dma_ff(devpriv->dma);
+ set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
+ set_dma_count(devpriv->dma, bytes);
+ release_dma_lock(dma_flags);
+ enable_dma(devpriv->dma);
+}
+
+static void pcl816_ai_setup_next_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct pcl816_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned long dma_flags;
+
+ disable_dma(devpriv->dma);
+ if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) {
+ /* switch dma bufs */
+ devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ dma_flags = claim_dma_lock();
+ set_dma_addr(devpriv->dma,
+ devpriv->hwdmaptr[devpriv->next_dma_buf]);
+ if (devpriv->dma_runs_to_end)
+ set_dma_count(devpriv->dma, devpriv->hwdmasize);
+ else
+ set_dma_count(devpriv->dma, devpriv->last_dma_run);
+ release_dma_lock(dma_flags);
+ enable_dma(devpriv->dma);
}
- if (!timeout) { /* timeout, bail error */
- outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
- comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
- pcl816_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ devpriv->dma_runs_to_end--;
+}
+
+static void pcl816_ai_set_chan_range(struct comedi_device *dev,
+ unsigned int chan,
+ unsigned int range)
+{
+ outb(chan, dev->iobase + PCL816_MUX_REG);
+ outb(range, dev->iobase + PCL816_RANGE_REG);
+}
+
+static void pcl816_ai_set_chan_scan(struct comedi_device *dev,
+ unsigned int first_chan,
+ unsigned int last_chan)
+{
+ outb(PCL816_MUX_SCAN(first_chan, last_chan),
+ dev->iobase + PCL816_MUX_REG);
+}
+
+static void pcl816_ai_setup_chanlist(struct comedi_device *dev,
+ unsigned int *chanlist,
+ unsigned int seglen)
+{
+ unsigned int first_chan = CR_CHAN(chanlist[0]);
+ unsigned int last_chan;
+ unsigned int range;
+ unsigned int i;
+
+ /* store range list to card */
+ for (i = 0; i < seglen; i++) {
+ last_chan = CR_CHAN(chanlist[i]);
+ range = CR_RANGE(chanlist[i]);
+
+ pcl816_ai_set_chan_range(dev, last_chan, range);
}
- /* get the sample */
- low = inb(dev->iobase + PCL816_AD_LO);
- hi = inb(dev->iobase + PCL816_AD_HI);
+ udelay(1);
+
+ pcl816_ai_set_chan_scan(dev, first_chan, last_chan);
+}
+
+static void pcl816_ai_clear_eoc(struct comedi_device *dev)
+{
+ /* writing any value clears the interrupt request */
+ outb(0, dev->iobase + PCL816_CLRINT_REG);
+}
+
+static void pcl816_ai_soft_trig(struct comedi_device *dev)
+{
+ /* writing any value triggers a software conversion */
+ outb(0, dev->iobase + PCL816_AI_LSB_REG);
+}
- comedi_buf_put(s->async, (hi << 8) | low);
+static unsigned int pcl816_ai_get_sample(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ unsigned int val;
- outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
+ val = inb(dev->iobase + PCL816_AI_MSB_REG) << 8;
+ val |= inb(dev->iobase + PCL816_AI_LSB_REG);
- if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len)
- devpriv->ai_act_chanlist_pos = 0;
+ return val & s->maxdata;
+}
+
+static int pcl816_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + PCL816_STATUS_REG);
+ if ((status & PCL816_STATUS_DRDY) == 0)
+ return 0;
+ return -EBUSY;
+}
+
+static bool pcl816_ai_next_chan(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct pcl816_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+
+ s->async->events |= COMEDI_CB_BLOCK;
s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
+ if (s->async->cur_chan >= cmd->chanlist_len) {
s->async->cur_chan = 0;
devpriv->ai_act_scan++;
+ s->async->events |= COMEDI_CB_EOS;
}
- if (!devpriv->ai_neverending)
- /* all data sampled */
- if (devpriv->ai_act_scan >= devpriv->ai_scans) {
- /* all data sampled */
- pcl816_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- }
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ if (cmd->stop_src == TRIG_COUNT &&
+ devpriv->ai_act_scan >= cmd->stop_arg) {
+ /* all data sampled */
+ s->async->events |= COMEDI_CB_EOA;
+ return false;
+ }
+
+ return true;
}
-/*
-==============================================================================
- analog input dma mode 1 & 3, 816 cards
-*/
static void transfer_from_dma_buf(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned short *ptr,
unsigned int bufptr, unsigned int len)
{
- struct pcl816_private *devpriv = dev->private;
int i;
- s->async->events = 0;
-
for (i = 0; i < len; i++) {
-
comedi_buf_put(s->async, ptr[bufptr++]);
- if (++devpriv->ai_act_chanlist_pos >=
- devpriv->ai_act_chanlist_len) {
- devpriv->ai_act_chanlist_pos = 0;
- }
-
- s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
- s->async->cur_chan = 0;
- devpriv->ai_act_scan++;
- }
-
- if (!devpriv->ai_neverending)
- /* all data sampled */
- if (devpriv->ai_act_scan >= devpriv->ai_scans) {
- pcl816_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- s->async->events |= COMEDI_CB_BLOCK;
- break;
- }
+ if (!pcl816_ai_next_chan(dev, s))
+ return;
}
-
- comedi_event(dev, s);
}
-static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d)
+static irqreturn_t pcl816_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
- struct pcl816_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
- int len, bufptr, this_dma_buf;
- unsigned long dma_flags;
+ struct pcl816_private *devpriv = dev->private;
unsigned short *ptr;
+ unsigned int bufptr;
+ unsigned int len;
- disable_dma(devpriv->dma);
- this_dma_buf = devpriv->next_dma_buf;
-
- /* switch dma bufs */
- if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) {
+ if (!dev->attached || !devpriv->ai_cmd_running) {
+ pcl816_ai_clear_eoc(dev);
+ return IRQ_HANDLED;
+ }
- devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- dma_flags = claim_dma_lock();
-/* clear_dma_ff (devpriv->dma); */
- set_dma_addr(devpriv->dma,
- devpriv->hwdmaptr[devpriv->next_dma_buf]);
- if (devpriv->dma_runs_to_end) {
- set_dma_count(devpriv->dma,
- devpriv->hwdmasize[devpriv->
- next_dma_buf]);
- } else {
- set_dma_count(devpriv->dma, devpriv->last_dma_run);
- }
- release_dma_lock(dma_flags);
- enable_dma(devpriv->dma);
+ if (devpriv->ai_cmd_canceled) {
+ devpriv->ai_cmd_canceled = 0;
+ pcl816_ai_clear_eoc(dev);
+ return IRQ_HANDLED;
}
- devpriv->dma_runs_to_end--;
- outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
+ ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf];
- ptr = (unsigned short *)devpriv->dmabuf[this_dma_buf];
+ pcl816_ai_setup_next_dma(dev, s);
- len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr;
+ len = (devpriv->hwdmasize >> 1) - devpriv->ai_poll_ptr;
bufptr = devpriv->ai_poll_ptr;
devpriv->ai_poll_ptr = 0;
transfer_from_dma_buf(dev, s, ptr, bufptr, len);
- return IRQ_HANDLED;
-}
-
-/*
-==============================================================================
- INT procedure
-*/
-static irqreturn_t interrupt_pcl816(int irq, void *d)
-{
- struct comedi_device *dev = d;
- struct pcl816_private *devpriv = dev->private;
- if (!dev->attached) {
- comedi_error(dev, "premature interrupt");
- return IRQ_HANDLED;
- }
-
- switch (devpriv->int816_mode) {
- case INT_TYPE_AI1_DMA:
- case INT_TYPE_AI3_DMA:
- return interrupt_pcl816_ai_mode13_dma(irq, d);
- case INT_TYPE_AI1_INT:
- case INT_TYPE_AI3_INT:
- return interrupt_pcl816_ai_mode13_int(irq, d);
- }
+ pcl816_ai_clear_eoc(dev);
- outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
- if (!dev->irq || !devpriv->irq_blocked || !devpriv->int816_mode) {
- if (devpriv->irq_was_now_closed) {
- devpriv->irq_was_now_closed = 0;
- /* comedi_error(dev,"last IRQ.."); */
- return IRQ_HANDLED;
- }
- comedi_error(dev, "bad IRQ!");
- return IRQ_NONE;
- }
- comedi_error(dev, "IRQ from unknown source!");
- return IRQ_NONE;
+ cfc_handle_events(dev, s);
+ return IRQ_HANDLED;
}
-/*
-==============================================================================
-*/
static int pcl816_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
- const struct pcl816_board *board = comedi_board(dev);
+ struct pcl816_private *devpriv = dev->private;
int err = 0;
- int tmp, divisor1 = 0, divisor2 = 0;
+ int tmp;
/* Step 1 : check if triggers are trivially valid */
@@ -432,8 +400,7 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
if (cmd->convert_src == TRIG_TIMER)
- err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
- board->ai_ns_min);
+ err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
else /* TRIG_EXT */
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
@@ -451,11 +418,12 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->convert_src == TRIG_TIMER) {
tmp = cmd->convert_arg;
- i8253_cascade_ns_to_timer(board->i8254_osc_base,
- &divisor1, &divisor2,
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
+ &devpriv->divisor1,
+ &devpriv->divisor2,
&cmd->convert_arg, cmd->flags);
- if (cmd->convert_arg < board->ai_ns_min)
- cmd->convert_arg = board->ai_ns_min;
+ if (cmd->convert_arg < 10000)
+ cmd->convert_arg = 10000;
if (tmp != cmd->convert_arg)
err++;
}
@@ -477,120 +445,40 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
- const struct pcl816_board *board = comedi_board(dev);
struct pcl816_private *devpriv = dev->private;
- unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq;
struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int ctrl;
unsigned int seglen;
- if (cmd->start_src != TRIG_NOW)
- return -EINVAL;
- if (cmd->scan_begin_src != TRIG_FOLLOW)
- return -EINVAL;
- if (cmd->scan_end_src != TRIG_COUNT)
- return -EINVAL;
- if (cmd->scan_end_arg != cmd->chanlist_len)
- return -EINVAL;
-/* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */
- if (devpriv->irq_blocked)
+ if (devpriv->ai_cmd_running)
return -EBUSY;
- if (cmd->convert_src == TRIG_TIMER) {
- if (cmd->convert_arg < board->ai_ns_min)
- cmd->convert_arg = board->ai_ns_min;
-
- i8253_cascade_ns_to_timer(board->i8254_osc_base,
- &divisor1, &divisor2,
- &cmd->convert_arg, cmd->flags);
-
- /* PCL816 crash if any divisor is set to 1 */
- if (divisor1 == 1) {
- divisor1 = 2;
- divisor2 /= 2;
- }
- if (divisor2 == 1) {
- divisor2 = 2;
- divisor1 /= 2;
- }
- }
-
- start_pacer(dev, -1, 0, 0); /* stop pacer */
+ pcl816_start_pacer(dev, false);
seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
if (seglen < 1)
return -EINVAL;
- setup_channel_list(dev, s, cmd->chanlist, seglen);
+ pcl816_ai_setup_chanlist(dev, cmd->chanlist, seglen);
udelay(1);
- devpriv->ai_n_chan = cmd->chanlist_len;
devpriv->ai_act_scan = 0;
s->async->cur_chan = 0;
- devpriv->irq_blocked = 1;
+ devpriv->ai_cmd_running = 1;
devpriv->ai_poll_ptr = 0;
- devpriv->irq_was_now_closed = 0;
+ devpriv->ai_cmd_canceled = 0;
- if (cmd->stop_src == TRIG_COUNT) {
- devpriv->ai_scans = cmd->stop_arg;
- devpriv->ai_neverending = 0;
- } else {
- devpriv->ai_scans = 0;
- devpriv->ai_neverending = 1;
- }
-
- if (devpriv->dma) {
- bytes = devpriv->hwdmasize[0];
- if (!devpriv->ai_neverending) {
- /* how many */
- bytes = s->async->cmd.chanlist_len *
- s->async->cmd.chanlist_len *
- sizeof(short);
-
- /* how many DMA pages we must fill */
- devpriv->dma_runs_to_end = bytes /
- devpriv->hwdmasize[0];
-
- /* on last dma transfer must be moved */
- devpriv->last_dma_run = bytes % devpriv->hwdmasize[0];
- devpriv->dma_runs_to_end--;
- if (devpriv->dma_runs_to_end >= 0)
- bytes = devpriv->hwdmasize[0];
- } else
- devpriv->dma_runs_to_end = -1;
-
- devpriv->next_dma_buf = 0;
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- dma_flags = claim_dma_lock();
- clear_dma_ff(devpriv->dma);
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
- set_dma_count(devpriv->dma, bytes);
- release_dma_lock(dma_flags);
- enable_dma(devpriv->dma);
- }
-
- start_pacer(dev, 1, divisor1, divisor2);
- dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7);
-
- switch (cmd->convert_src) {
- case TRIG_TIMER:
- devpriv->int816_mode = INT_TYPE_AI1_DMA;
-
- /* Pacer+IRQ+DMA */
- outb(0x32, dev->iobase + PCL816_CONTROL);
+ pcl816_ai_setup_dma(dev, s);
- /* write irq and DMA to card */
- outb(dmairq, dev->iobase + PCL816_STATUS);
- break;
+ pcl816_start_pacer(dev, true);
- default:
- devpriv->int816_mode = INT_TYPE_AI3_DMA;
-
- /* Ext trig+IRQ+DMA */
- outb(0x34, dev->iobase + PCL816_CONTROL);
+ ctrl = PCL816_CTRL_INTEN | PCL816_CTRL_DMAEN | PCL816_CTRL_DMASRC_SLOT0;
+ if (cmd->convert_src == TRIG_TIMER)
+ ctrl |= PCL816_CTRL_PACER_TRIG;
+ else /* TRIG_EXT */
+ ctrl |= PCL816_CTRL_EXT_TRIG;
- /* write irq to card */
- outb(dmairq, dev->iobase + PCL816_STATUS);
- break;
- }
+ outb(ctrl, dev->iobase + PCL816_CTRL_REG);
+ outb((devpriv->dma << 4) | dev->irq, dev->iobase + PCL816_STATUS_REG);
return 0;
}
@@ -601,9 +489,6 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
unsigned long flags;
unsigned int top1, top2, i;
- if (!devpriv->dma)
- return 0; /* poll is valid only for DMA transfer */
-
spin_lock_irqsave(&dev->spinlock, flags);
for (i = 0; i < 20; i++) {
@@ -618,7 +503,7 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
}
/* where is now DMA in buffer */
- top1 = devpriv->hwdmasize[0] - top1;
+ top1 = devpriv->hwdmasize - top1;
top1 >>= 1; /* sample position */
top2 = top1 - devpriv->ai_poll_ptr;
if (top2 < 1) { /* no new samples */
@@ -634,134 +519,34 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_poll_ptr = top1; /* new buffer position */
spin_unlock_irqrestore(&dev->spinlock, flags);
+ cfc_handle_events(dev, s);
+
return s->async->buf_write_count - s->async->buf_read_count;
}
-/*
-==============================================================================
- cancel any mode 1-4 AI
-*/
static int pcl816_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct pcl816_private *devpriv = dev->private;
- if (devpriv->irq_blocked > 0) {
- switch (devpriv->int816_mode) {
- case INT_TYPE_AI1_DMA:
- case INT_TYPE_AI3_DMA:
- disable_dma(devpriv->dma);
- case INT_TYPE_AI1_INT:
- case INT_TYPE_AI3_INT:
- outb(inb(dev->iobase + PCL816_CONTROL) & 0x73,
- dev->iobase + PCL816_CONTROL); /* Stop A/D */
- udelay(1);
- outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */
-
- /* Stop pacer */
- outb(0xb0, dev->iobase + PCL816_CTRCTL);
- outb(0x70, dev->iobase + PCL816_CTRCTL);
- outb(0, dev->iobase + PCL816_AD_LO);
- inb(dev->iobase + PCL816_AD_LO);
- inb(dev->iobase + PCL816_AD_HI);
-
- /* clear INT request */
- outb(0, dev->iobase + PCL816_CLRINT);
-
- /* Stop A/D */
- outb(0, dev->iobase + PCL816_CONTROL);
- devpriv->irq_blocked = 0;
- devpriv->irq_was_now_closed = devpriv->int816_mode;
- devpriv->int816_mode = 0;
- devpriv->last_int_sub = s;
-/* s->busy = 0; */
- break;
- }
- }
- return 0;
-}
-
-/*
-==============================================================================
- chech for PCL816
-*/
-static int pcl816_check(unsigned long iobase)
-{
- outb(0x00, iobase + PCL816_MUX);
- udelay(1);
- if (inb(iobase + PCL816_MUX) != 0x00)
- return 1; /* there isn't card */
- outb(0x55, iobase + PCL816_MUX);
- udelay(1);
- if (inb(iobase + PCL816_MUX) != 0x55)
- return 1; /* there isn't card */
- outb(0x00, iobase + PCL816_MUX);
- udelay(1);
- outb(0x18, iobase + PCL816_CONTROL);
- udelay(1);
- if (inb(iobase + PCL816_CONTROL) != 0x18)
- return 1; /* there isn't card */
- return 0; /* ok, card exist */
-}
-
-/*
-==============================================================================
- reset whole PCL-816 cards
-*/
-static void pcl816_reset(struct comedi_device *dev)
-{
-/* outb (0, dev->iobase + PCL818_DA_LO); DAC=0V */
-/* outb (0, dev->iobase + PCL818_DA_HI); */
-/* udelay (1); */
-/* outb (0, dev->iobase + PCL818_DO_HI); DO=$0000 */
-/* outb (0, dev->iobase + PCL818_DO_LO); */
-/* udelay (1); */
- outb(0, dev->iobase + PCL816_CONTROL);
- outb(0, dev->iobase + PCL816_MUX);
- outb(0, dev->iobase + PCL816_CLRINT);
- outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */
- outb(0x70, dev->iobase + PCL816_CTRCTL);
- outb(0x30, dev->iobase + PCL816_CTRCTL);
- outb(0, dev->iobase + PCL816_RANGE);
-}
+ if (!devpriv->ai_cmd_running)
+ return 0;
-/*
-==============================================================================
- Start/stop pacer onboard pacer
-*/
-static void
-start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
- unsigned int divisor2)
-{
- outb(0x32, dev->iobase + PCL816_CTRCTL);
- outb(0xff, dev->iobase + PCL816_CTR0);
- outb(0x00, dev->iobase + PCL816_CTR0);
- udelay(1);
+ outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG);
+ pcl816_ai_clear_eoc(dev);
- /* set counter 2 as mode 3 */
- outb(0xb4, dev->iobase + PCL816_CTRCTL);
- /* set counter 1 as mode 3 */
- outb(0x74, dev->iobase + PCL816_CTRCTL);
- udelay(1);
+ /* Stop pacer */
+ i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0,
+ 2, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0,
+ 1, I8254_MODE0 | I8254_BINARY);
- if (mode == 1) {
- dev_dbg(dev->class_dev, "mode %d, divisor1 %d, divisor2 %d\n",
- mode, divisor1, divisor2);
- outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2);
- outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2);
- outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1);
- outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1);
- }
+ devpriv->ai_cmd_running = 0;
+ devpriv->ai_cmd_canceled = 1;
- /* clear pending interrupts (just in case) */
-/* outb(0, dev->iobase + PCL816_CLRINT); */
+ return 0;
}
-/*
-==============================================================================
- Check if channel list from user is built correctly
- If it's ok, then return non-zero length of repeated segment of channel list
-*/
static int
check_channel_list(struct comedi_device *dev,
struct comedi_subdevice *s, unsigned int *chanlist,
@@ -818,180 +603,181 @@ check_channel_list(struct comedi_device *dev,
return seglen; /* we can serve this with MUX logic */
}
-/*
-==============================================================================
- Program scan/gain logic with channel list.
-*/
-static void
-setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int *chanlist,
- unsigned int seglen)
+static int pcl816_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct pcl816_private *devpriv = dev->private;
- unsigned int i;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ int ret = 0;
+ int i;
- devpriv->ai_act_chanlist_len = seglen;
- devpriv->ai_act_chanlist_pos = 0;
+ outb(PCL816_CTRL_SOFT_TRIG, dev->iobase + PCL816_CTRL_REG);
- for (i = 0; i < seglen; i++) { /* store range list to card */
- devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]);
- outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX);
- /* select gain */
- outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE);
+ pcl816_ai_set_chan_range(dev, chan, range);
+ pcl816_ai_set_chan_scan(dev, chan, chan);
+
+ for (i = 0; i < insn->n; i++) {
+ pcl816_ai_clear_eoc(dev);
+ pcl816_ai_soft_trig(dev);
+
+ ret = comedi_timeout(dev, s, insn, pcl816_ai_eoc, 0);
+ if (ret)
+ break;
+
+ data[i] = pcl816_ai_get_sample(dev, s);
}
+ outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG);
+ pcl816_ai_clear_eoc(dev);
- udelay(1);
- /* select channel interval to scan */
- outb(devpriv->ai_act_chanlist[0] |
- (devpriv->ai_act_chanlist[seglen - 1] << 4),
- dev->iobase + PCL816_MUX);
+ return ret ? ret : insn->n;
+}
+
+static int pcl816_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ data[1] = inb(dev->iobase + PCL816_DO_DI_LSB_REG) |
+ (inb(dev->iobase + PCL816_DO_DI_MSB_REG) << 8);
+
+ return insn->n;
+}
+
+static int pcl816_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (comedi_dio_update_state(s, data)) {
+ outb(s->state & 0xff, dev->iobase + PCL816_DO_DI_LSB_REG);
+ outb((s->state >> 8), dev->iobase + PCL816_DO_DI_MSB_REG);
+ }
+
+ data[1] = s->state;
+
+ return insn->n;
+}
+
+static void pcl816_reset(struct comedi_device *dev)
+{
+ unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE;
+
+ outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG);
+ pcl816_ai_set_chan_range(dev, 0, 0);
+ pcl816_ai_clear_eoc(dev);
+
+ /* Stop pacer */
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY);
+
+ /* set all digital outputs low */
+ outb(0, dev->iobase + PCL816_DO_DI_LSB_REG);
+ outb(0, dev->iobase + PCL816_DO_DI_MSB_REG);
}
static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl816_board *board = comedi_board(dev);
struct pcl816_private *devpriv;
- int ret;
- unsigned int dma;
- unsigned long pages;
- /* int i; */
struct comedi_subdevice *s;
-
- ret = comedi_request_region(dev, it->options[0], board->io_range);
- if (ret)
- return ret;
-
- if (pcl816_check(dev->iobase)) {
- dev_err(dev->class_dev, "I can't detect board. FAIL!\n");
- return -EIO;
- }
+ int ret;
+ int i;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- if ((1 << it->options[1]) & board->IRQbits) {
- ret = request_irq(it->options[1], interrupt_pcl816, 0,
+ ret = comedi_request_region(dev, it->options[0], 0x10);
+ if (ret)
+ return ret;
+
+ /* we can use IRQ 2-7 for async command support */
+ if (it->options[1] >= 2 && it->options[1] <= 7) {
+ ret = request_irq(it->options[1], pcl816_interrupt, 0,
dev->board_name, dev);
if (ret == 0)
dev->irq = it->options[1];
}
- devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
- devpriv->int816_mode = 0; /* mode of irq */
-
- /* grab our DMA */
- dma = 0;
- devpriv->dma = dma;
- if (!dev->irq)
- goto no_dma; /* if we haven't IRQ, we can't use DMA */
-
- if (board->DMAbits != 0) { /* board support DMA */
- dma = it->options[2];
- if (dma < 1)
- goto no_dma; /* DMA disabled */
-
- if (((1 << dma) & board->DMAbits) == 0) {
- dev_err(dev->class_dev,
- "DMA is out of allowed range, FAIL!\n");
- return -EINVAL; /* Bad DMA */
- }
- ret = request_dma(dma, dev->board_name);
+ /* we need an IRQ to do DMA on channel 3 or 1 */
+ if (dev->irq && (it->options[2] == 3 || it->options[2] == 1)) {
+ ret = request_dma(it->options[2], dev->board_name);
if (ret) {
dev_err(dev->class_dev,
- "unable to allocate DMA %u, FAIL!\n", dma);
- return -EBUSY; /* DMA isn't free */
+ "unable to request DMA channel %d\n",
+ it->options[2]);
+ return -EBUSY;
}
+ devpriv->dma = it->options[2];
- devpriv->dma = dma;
- pages = 2; /* we need 16KB */
- devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
+ devpriv->dmapages = 2; /* we need 16KB */
+ devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
- if (!devpriv->dmabuf[0]) {
- dev_err(dev->class_dev,
- "unable to allocate DMA buffer, FAIL!\n");
- /*
- * maybe experiment with try_to_free_pages()
- * will help ....
- */
- return -EBUSY; /* no buffer :-( */
- }
- devpriv->dmapages[0] = pages;
- devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
- devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
+ for (i = 0; i < 2; i++) {
+ unsigned long dmabuf;
- devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[1]) {
- dev_err(dev->class_dev,
- "unable to allocate DMA buffer, FAIL!\n");
- return -EBUSY;
+ dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
+ if (!dmabuf)
+ return -ENOMEM;
+
+ devpriv->dmabuf[i] = dmabuf;
+ devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
}
- devpriv->dmapages[1] = pages;
- devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
- devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
}
-no_dma:
-
-/* if (board->n_aochan > 0)
- subdevs[1] = COMEDI_SUBD_AO;
- if (board->n_dichan > 0)
- subdevs[2] = COMEDI_SUBD_DI;
- if (board->n_dochan > 0)
- subdevs[3] = COMEDI_SUBD_DO;
-*/
-
- ret = comedi_alloc_subdevices(dev, 1);
+ ret = comedi_alloc_subdevices(dev, 4);
if (ret)
return ret;
s = &dev->subdevices[0];
- if (board->n_aichan > 0) {
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_CMD_READ | SDF_DIFF;
- s->n_chan = board->n_aichan;
- s->maxdata = board->ai_maxdata;
- s->range_table = board->ai_range_type;
- s->insn_read = pcl816_ai_insn_read;
- if (dev->irq) {
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->len_chanlist = board->ai_chanlist;
- s->do_cmdtest = pcl816_ai_cmdtest;
- s->do_cmd = pcl816_ai_cmd;
- s->poll = pcl816_ai_poll;
- s->cancel = pcl816_ai_cancel;
- }
- } else {
- s->type = COMEDI_SUBD_UNUSED;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_CMD_READ | SDF_DIFF;
+ s->n_chan = 16;
+ s->maxdata = board->ai_maxdata;
+ s->range_table = &range_pcl816;
+ s->insn_read = pcl816_ai_insn_read;
+ if (devpriv->dma) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = board->ai_chanlist;
+ s->do_cmdtest = pcl816_ai_cmdtest;
+ s->do_cmd = pcl816_ai_cmd;
+ s->poll = pcl816_ai_poll;
+ s->cancel = pcl816_ai_cancel;
}
+ /* Analog OUtput subdevice */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_UNUSED;
#if 0
-case COMEDI_SUBD_AO:
+ subdevs[1] = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
- s->n_chan = board->n_aochan;
+ s->n_chan = 1;
s->maxdata = board->ao_maxdata;
- s->len_chanlist = board->ao_chanlist;
- s->range_table = board->ao_range_type;
- break;
-
-case COMEDI_SUBD_DI:
- s->subdev_flags = SDF_READABLE;
- s->n_chan = board->n_dichan;
- s->maxdata = 1;
- s->len_chanlist = board->n_dichan;
- s->range_table = &range_digital;
- break;
-
-case COMEDI_SUBD_DO:
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = board->n_dochan;
- s->maxdata = 1;
- s->len_chanlist = board->n_dochan;
- s->range_table = &range_digital;
- break;
+ s->range_table = &range_pcl816;
#endif
+ /* Digital Input subdevice */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcl816_di_insn_bits;
+
+ /* Digital Output subdevice */
+ s = &dev->subdevices[3];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcl816_do_insn_bits;
+
pcl816_reset(dev);
return 0;
@@ -1007,34 +793,13 @@ static void pcl816_detach(struct comedi_device *dev)
if (devpriv->dma)
free_dma(devpriv->dma);
if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
+ free_pages(devpriv->dmabuf[0], devpriv->dmapages);
if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
+ free_pages(devpriv->dmabuf[1], devpriv->dmapages);
}
comedi_legacy_detach(dev);
}
-static const struct pcl816_board boardtypes[] = {
- {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
- &range_pcl816, PCLx1x_RANGE,
- 0x00fc, /* IRQ mask */
- 0x0a, /* DMA mask */
- 0xffff, /* 16-bit card */
- 0xffff, /* D/A maxdata */
- 1024,
- 1, /* ao chan list */
- I8254_OSC_BASE_10MHZ},
- {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
- &range_pcl816, PCLx1x_RANGE,
- 0x00fc,
- 0x0a,
- 0x3fff, /* 14 bit card */
- 0x3fff,
- 1024,
- 1,
- I8254_OSC_BASE_10MHZ},
-};
-
static struct comedi_driver pcl816_driver = {
.driver_name = "pcl816",
.module = THIS_MODULE,
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index fa1758ad49d5..6463476ce45a 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -110,8 +110,6 @@ A word or two about DMA. Driver support DMA operations at two ways:
#include "comedi_fc.h"
#include "8253.h"
-/* #define PCL818_MODE13_AO 1 */
-
/* boards constants */
#define boardPCL818L 0
@@ -121,46 +119,38 @@ A word or two about DMA. Driver support DMA operations at two ways:
#define boardPCL818 4
#define boardPCL718 5
-/* IO space len */
-#define PCLx1x_RANGE 16
-/* IO space len if we use FIFO */
-#define PCLx1xFIFO_RANGE 32
-
-/* W: clear INT request */
-#define PCL818_CLRINT 8
-/* R: return status byte */
-#define PCL818_STATUS 8
-/* R: A/D high byte W: A/D range control */
-#define PCL818_RANGE 1
-/* R: next mux scan channel W: mux scan channel & range control pointer */
-#define PCL818_MUX 2
-/* R/W: operation control register */
-#define PCL818_CONTROL 9
-/* W: counter enable */
-#define PCL818_CNTENABLE 10
-
-/* R: low byte of A/D W: soft A/D trigger */
-#define PCL818_AD_LO 0
-/* R: high byte of A/D W: A/D range control */
-#define PCL818_AD_HI 1
-/* W: D/A low&high byte */
-#define PCL818_DA_LO 4
-#define PCL818_DA_HI 5
-/* R: low&high byte of DI */
-#define PCL818_DI_LO 3
-#define PCL818_DI_HI 11
-/* W: low&high byte of DO */
-#define PCL818_DO_LO 3
-#define PCL818_DO_HI 11
-/* W: PCL718 second D/A */
-#define PCL718_DA2_LO 6
-#define PCL718_DA2_HI 7
-/* counters */
-#define PCL818_CTR0 12
-#define PCL818_CTR1 13
-#define PCL818_CTR2 14
-/* W: counter control */
-#define PCL818_CTRCTL 15
+/*
+ * Register I/O map
+ */
+#define PCL818_AI_LSB_REG 0x00
+#define PCL818_AI_MSB_REG 0x01
+#define PCL818_RANGE_REG 0x01
+#define PCL818_MUX_REG 0x02
+#define PCL818_MUX_SCAN(_first, _last) (((_last) << 4) | (_first))
+#define PCL818_DO_DI_LSB_REG 0x03
+#define PCL818_AO_LSB_REG(x) (0x04 + ((x) * 2))
+#define PCL818_AO_MSB_REG(x) (0x05 + ((x) * 2))
+#define PCL818_STATUS_REG 0x08
+#define PCL818_STATUS_NEXT_CHAN_MASK (0xf << 0)
+#define PCL818_STATUS_INT (1 << 4)
+#define PCL818_STATUS_MUX (1 << 5)
+#define PCL818_STATUS_UNI (1 << 6)
+#define PCL818_STATUS_EOC (1 << 7)
+#define PCL818_CTRL_REG 0x09
+#define PCL818_CTRL_DISABLE_TRIG (0 << 0)
+#define PCL818_CTRL_SOFT_TRIG (1 << 0)
+#define PCL818_CTRL_EXT_TRIG (2 << 0)
+#define PCL818_CTRL_PACER_TRIG (3 << 0)
+#define PCL818_CTRL_DMAE (1 << 2)
+#define PCL818_CTRL_IRQ(x) ((x) << 4)
+#define PCL818_CTRL_INTE (1 << 7)
+#define PCL818_CNTENABLE_REG 0x0a
+#define PCL818_CNTENABLE_PACER_ENA (0 << 0)
+#define PCL818_CNTENABLE_PACER_TRIG0 (1 << 0)
+#define PCL818_CNTENABLE_CNT0_EXT_CLK (0 << 1)
+#define PCL818_CNTENABLE_CNT0_INT_CLK (1 << 1)
+#define PCL818_DO_DI_MSB_REG 0x0b
+#define PCL818_TIMER_BASE 0x0c
/* W: fifo enable/disable */
#define PCL818_FI_ENABLE 6
@@ -172,19 +162,7 @@ A word or two about DMA. Driver support DMA operations at two ways:
#define PCL818_FI_STATUS 25
/* R: one record from FIFO */
#define PCL818_FI_DATALO 23
-#define PCL818_FI_DATAHI 23
-
-/* type of interrupt handler */
-#define INT_TYPE_AI1_INT 1
-#define INT_TYPE_AI1_DMA 2
-#define INT_TYPE_AI1_FIFO 3
-#define INT_TYPE_AI3_INT 4
-#define INT_TYPE_AI3_DMA 5
-#define INT_TYPE_AI3_FIFO 6
-#ifdef PCL818_MODE13_AO
-#define INT_TYPE_AO1_INT 7
-#define INT_TYPE_AO3_INT 8
-#endif
+#define PCL818_FI_DATAHI 24
#define MAGIC_DMA_WORD 0x5a5a
@@ -262,630 +240,439 @@ static const struct comedi_lrange range718_unipolar1 = {
};
struct pcl818_board {
+ const char *name;
+ unsigned int ns_min;
+ int n_aochan;
+ const struct comedi_lrange *ai_range_type;
+ unsigned int has_dma:1;
+ unsigned int has_fifo:1;
+ unsigned int is_818:1;
+};
- const char *name; /* driver name */
- int n_ranges; /* len of range list */
- int n_aichan_se; /* num of A/D chans in single ended mode */
- int n_aichan_diff; /* num of A/D chans in diferencial mode */
- unsigned int ns_min; /* minimal allowed delay between samples (in ns) */
- int n_aochan; /* num of D/A chans */
- int n_dichan; /* num of DI chans */
- int n_dochan; /* num of DO chans */
- const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
- const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
- unsigned int io_range; /* len of IO space */
- unsigned int IRQbits; /* allowed interrupts */
- unsigned int DMAbits; /* allowed DMA chans */
- int ai_maxdata; /* maxdata for A/D */
- int ao_maxdata; /* maxdata for D/A */
- unsigned char fifo; /* 1=board has FIFO */
- int is_818;
+static const struct pcl818_board boardtypes[] = {
+ {
+ .name = "pcl818l",
+ .ns_min = 25000,
+ .n_aochan = 1,
+ .ai_range_type = &range_pcl818l_l_ai,
+ .has_dma = 1,
+ .is_818 = 1,
+ }, {
+ .name = "pcl818h",
+ .ns_min = 10000,
+ .n_aochan = 1,
+ .ai_range_type = &range_pcl818h_ai,
+ .has_dma = 1,
+ .is_818 = 1,
+ }, {
+ .name = "pcl818hd",
+ .ns_min = 10000,
+ .n_aochan = 1,
+ .ai_range_type = &range_pcl818h_ai,
+ .has_dma = 1,
+ .has_fifo = 1,
+ .is_818 = 1,
+ }, {
+ .name = "pcl818hg",
+ .ns_min = 10000,
+ .n_aochan = 1,
+ .ai_range_type = &range_pcl818hg_ai,
+ .has_dma = 1,
+ .has_fifo = 1,
+ .is_818 = 1,
+ }, {
+ .name = "pcl818",
+ .ns_min = 10000,
+ .n_aochan = 2,
+ .ai_range_type = &range_pcl818h_ai,
+ .has_dma = 1,
+ .is_818 = 1,
+ }, {
+ .name = "pcl718",
+ .ns_min = 16000,
+ .n_aochan = 2,
+ .ai_range_type = &range_unipolar5,
+ .has_dma = 1,
+ }, {
+ .name = "pcm3718",
+ .ns_min = 10000,
+ .ai_range_type = &range_pcl818h_ai,
+ .has_dma = 1,
+ .is_818 = 1,
+ },
};
struct pcl818_private {
-
unsigned int dma; /* used DMA, 0=don't use DMA */
- unsigned int io_range;
+ unsigned int dmapages;
+ unsigned int hwdmasize;
unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
- unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
- unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
int next_dma_buf; /* which DMA buffer will be used next round */
long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
- unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */
unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */
int i8253_osc_base; /* 1/frequency of on board oscilator in ns */
- int irq_blocked; /* 1=IRQ now uses any subdev */
- int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */
- int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
- struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
int ai_act_scan; /* how many scans we finished */
int ai_act_chan; /* actual position in actual scan */
unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */
unsigned int act_chanlist_len; /* how long is actual MUX list */
unsigned int act_chanlist_pos; /* actual position in MUX list */
- unsigned int ai_scans; /* len of scanlist */
- unsigned int ai_n_chan; /* how many channels is measured */
- unsigned int *ai_chanlist; /* actaul chanlist */
- unsigned int ai_flags; /* flaglist */
unsigned int ai_data_len; /* len of data buffer */
- unsigned int ai_timer1; /* timers */
- unsigned int ai_timer2;
- unsigned char usefifo; /* 1=use fifo */
unsigned int ao_readback[2];
+ unsigned int divisor1;
+ unsigned int divisor2;
+ unsigned int usefifo:1;
+ unsigned int ai_cmd_running:1;
+ unsigned int ai_cmd_canceled:1;
};
-static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */
- 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
-};
-
-/*
-==============================================================================
-*/
-static void setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan,
- unsigned int seglen);
-static int check_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan);
-
-static int pcl818_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2);
-
-/*
-==============================================================================
- ANALOG INPUT MODE0, 818 cards, slow version
-*/
-static int pcl818_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl818_start_pacer(struct comedi_device *dev, bool load_counters)
{
- int n;
- int timeout;
+ struct pcl818_private *devpriv = dev->private;
+ unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE;
- /* software trigger, DMA and INT off */
- outb(0, dev->iobase + PCL818_CONTROL);
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ udelay(1);
- /* select channel */
- outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
+ if (load_counters) {
+ i8254_write(timer_base, 0, 2, devpriv->divisor2);
+ i8254_write(timer_base, 0, 1, devpriv->divisor1);
+ }
+}
- /* select gain */
- outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
+static void pcl818_ai_setup_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct pcl818_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int flags;
+ unsigned int bytes;
- for (n = 0; n < insn->n; n++) {
+ disable_dma(devpriv->dma); /* disable dma */
+ bytes = devpriv->hwdmasize;
+ if (cmd->stop_src == TRIG_COUNT) {
+ bytes = cmd->chanlist_len * cmd->stop_arg * sizeof(short);
+ devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize;
+ devpriv->last_dma_run = bytes % devpriv->hwdmasize;
+ devpriv->dma_runs_to_end--;
+ if (devpriv->dma_runs_to_end >= 0)
+ bytes = devpriv->hwdmasize;
+ }
- /* clear INT (conversion end) flag */
- outb(0, dev->iobase + PCL818_CLRINT);
+ devpriv->next_dma_buf = 0;
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ flags = claim_dma_lock();
+ clear_dma_ff(devpriv->dma);
+ set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
+ set_dma_count(devpriv->dma, bytes);
+ release_dma_lock(flags);
+ enable_dma(devpriv->dma);
+}
- /* start conversion */
- outb(0, dev->iobase + PCL818_AD_LO);
+static void pcl818_ai_setup_next_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct pcl818_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned long flags;
- timeout = 100;
- while (timeout--) {
- if (inb(dev->iobase + PCL818_STATUS) & 0x10)
- goto conv_finish;
- udelay(1);
- }
- comedi_error(dev, "A/D insn timeout");
- /* clear INT (conversion end) flag */
- outb(0, dev->iobase + PCL818_CLRINT);
- return -EIO;
-
-conv_finish:
- data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
- (inb(dev->iobase + PCL818_AD_LO) >> 4));
+ disable_dma(devpriv->dma);
+ devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
+ if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) {
+ /* switch dma bufs */
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ flags = claim_dma_lock();
+ set_dma_addr(devpriv->dma,
+ devpriv->hwdmaptr[devpriv->next_dma_buf]);
+ if (devpriv->dma_runs_to_end || cmd->stop_src == TRIG_NONE)
+ set_dma_count(devpriv->dma, devpriv->hwdmasize);
+ else
+ set_dma_count(devpriv->dma, devpriv->last_dma_run);
+ release_dma_lock(flags);
+ enable_dma(devpriv->dma);
}
- return n;
+ devpriv->dma_runs_to_end--;
}
-/*
-==============================================================================
- ANALOG OUTPUT MODE0, 818 cards
- only one sample per call is supported
-*/
-static int pcl818_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl818_ai_set_chan_range(struct comedi_device *dev,
+ unsigned int chan,
+ unsigned int range)
{
- struct pcl818_private *devpriv = dev->private;
- int n;
- int chan = CR_CHAN(insn->chanspec);
-
- for (n = 0; n < insn->n; n++)
- data[n] = devpriv->ao_readback[chan];
+ outb(chan, dev->iobase + PCL818_MUX_REG);
+ outb(range, dev->iobase + PCL818_RANGE_REG);
+}
- return n;
+static void pcl818_ai_set_chan_scan(struct comedi_device *dev,
+ unsigned int first_chan,
+ unsigned int last_chan)
+{
+ outb(PCL818_MUX_SCAN(first_chan, last_chan),
+ dev->iobase + PCL818_MUX_REG);
}
-static int pcl818_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl818_ai_setup_chanlist(struct comedi_device *dev,
+ unsigned int *chanlist,
+ unsigned int seglen)
{
struct pcl818_private *devpriv = dev->private;
- int n;
- int chan = CR_CHAN(insn->chanspec);
-
- for (n = 0; n < insn->n; n++) {
- devpriv->ao_readback[chan] = data[n];
- outb((data[n] & 0x000f) << 4, dev->iobase +
- (chan ? PCL718_DA2_LO : PCL818_DA_LO));
- outb((data[n] & 0x0ff0) >> 4, dev->iobase +
- (chan ? PCL718_DA2_HI : PCL818_DA_HI));
+ unsigned int first_chan = CR_CHAN(chanlist[0]);
+ unsigned int last_chan;
+ unsigned int range;
+ int i;
+
+ devpriv->act_chanlist_len = seglen;
+ devpriv->act_chanlist_pos = 0;
+
+ /* store range list to card */
+ for (i = 0; i < seglen; i++) {
+ last_chan = CR_CHAN(chanlist[i]);
+ range = CR_RANGE(chanlist[i]);
+
+ devpriv->act_chanlist[i] = last_chan;
+
+ pcl818_ai_set_chan_range(dev, last_chan, range);
}
- return n;
+ udelay(1);
+
+ pcl818_ai_set_chan_scan(dev, first_chan, last_chan);
}
-/*
-==============================================================================
- DIGITAL INPUT MODE0, 818 cards
+static void pcl818_ai_clear_eoc(struct comedi_device *dev)
+{
+ /* writing any value clears the interrupt request */
+ outb(0, dev->iobase + PCL818_STATUS_REG);
+}
- only one sample per call is supported
-*/
-static int pcl818_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl818_ai_soft_trig(struct comedi_device *dev)
{
- data[1] = inb(dev->iobase + PCL818_DI_LO) |
- (inb(dev->iobase + PCL818_DI_HI) << 8);
+ /* writing any value triggers a software conversion */
+ outb(0, dev->iobase + PCL818_AI_LSB_REG);
+}
- return insn->n;
+static unsigned int pcl818_ai_get_fifo_sample(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int *chan)
+{
+ unsigned int val;
+
+ val = inb(dev->iobase + PCL818_FI_DATALO);
+ val |= (inb(dev->iobase + PCL818_FI_DATAHI) << 8);
+
+ if (chan)
+ *chan = val & 0xf;
+
+ return (val >> 4) & s->maxdata;
}
-static int pcl818_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static unsigned int pcl818_ai_get_sample(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int *chan)
{
- if (comedi_dio_update_state(s, data)) {
- outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
- outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
- }
+ unsigned int val;
- data[1] = s->state;
+ val = inb(dev->iobase + PCL818_AI_MSB_REG) << 8;
+ val |= inb(dev->iobase + PCL818_AI_LSB_REG);
- return insn->n;
+ if (chan)
+ *chan = val & 0xf;
+
+ return (val >> 4) & s->maxdata;
}
-/*
-==============================================================================
- analog input interrupt mode 1 & 3, 818 cards
- one sample per interrupt version
-*/
-static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
+static int pcl818_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- struct comedi_device *dev = d;
- struct pcl818_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
- unsigned char low;
- int timeout = 50; /* wait max 50us */
+ unsigned int status;
- while (timeout--) {
- if (inb(dev->iobase + PCL818_STATUS) & 0x10)
- goto conv_finish;
- udelay(1);
- }
- outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
- comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ status = inb(dev->iobase + PCL818_STATUS_REG);
+ if (status & PCL818_STATUS_INT)
+ return 0;
+ return -EBUSY;
+}
-conv_finish:
- low = inb(dev->iobase + PCL818_AD_LO);
- comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */
- outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
+static bool pcl818_ai_dropout(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int chan)
+{
+ struct pcl818_private *devpriv = dev->private;
+ unsigned int expected_chan;
- if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
+ expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos];
+ if (chan != expected_chan) {
dev_dbg(dev->class_dev,
- "A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
- (low & 0xf),
- devpriv->act_chanlist[devpriv->act_chanlist_pos]);
- pcl818_ai_cancel(dev, s);
+ "A/D mode1/3 %s - channel dropout %d!=%d !\n",
+ (devpriv->dma) ? "DMA" :
+ (devpriv->usefifo) ? "FIFO" : "IRQ",
+ chan, expected_chan);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ return true;
}
+ return false;
+}
+
+static bool pcl818_ai_next_chan(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct pcl818_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+
+ s->async->events |= COMEDI_CB_BLOCK;
+
devpriv->act_chanlist_pos++;
if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
devpriv->act_chanlist_pos = 0;
s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
+ if (s->async->cur_chan >= cmd->chanlist_len) {
s->async->cur_chan = 0;
devpriv->ai_act_scan--;
+ s->async->events |= COMEDI_CB_EOS;
}
- if (!devpriv->neverending_ai) {
- if (devpriv->ai_act_scan == 0) { /* all data sampled */
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- }
+ if (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan == 0) {
+ /* all data sampled */
+ s->async->events |= COMEDI_CB_EOA;
+ return false;
}
- comedi_event(dev, s);
- return IRQ_HANDLED;
+
+ return true;
}
-/*
-==============================================================================
- analog input dma mode 1 & 3, 818 cards
-*/
-static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
+static void pcl818_handle_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ unsigned int chan;
+ unsigned int val;
+
+ if (pcl818_ai_eoc(dev, s, NULL, 0)) {
+ comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
+ s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ return;
+ }
+
+ val = pcl818_ai_get_sample(dev, s, &chan);
+
+ if (pcl818_ai_dropout(dev, s, chan))
+ return;
+
+ comedi_buf_put(s->async, val);
+
+ pcl818_ai_next_chan(dev, s);
+}
+
+static void pcl818_handle_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- struct comedi_device *dev = d;
struct pcl818_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
- int i, len, bufptr;
- unsigned long flags;
unsigned short *ptr;
+ unsigned int chan;
+ unsigned int val;
+ int i, len, bufptr;
- disable_dma(devpriv->dma);
- devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
- if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- flags = claim_dma_lock();
- set_dma_addr(devpriv->dma,
- devpriv->hwdmaptr[devpriv->next_dma_buf]);
- if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
- set_dma_count(devpriv->dma,
- devpriv->hwdmasize[devpriv->
- next_dma_buf]);
- } else {
- set_dma_count(devpriv->dma, devpriv->last_dma_run);
- }
- release_dma_lock(flags);
- enable_dma(devpriv->dma);
- }
+ pcl818_ai_setup_next_dma(dev, s);
- devpriv->dma_runs_to_end--;
- outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
- len = devpriv->hwdmasize[0] >> 1;
+ len = devpriv->hwdmasize >> 1;
bufptr = 0;
for (i = 0; i < len; i++) {
- if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
- dev_dbg(dev->class_dev,
- "A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
- (ptr[bufptr] & 0xf),
- devpriv->act_chanlist[devpriv->act_chanlist_pos],
- devpriv->act_chanlist_pos);
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
- }
+ val = ptr[bufptr++];
+ chan = val & 0xf;
+ val = (val >> 4) & s->maxdata;
- comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */
+ if (pcl818_ai_dropout(dev, s, chan))
+ break;
- devpriv->act_chanlist_pos++;
- if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
- devpriv->act_chanlist_pos = 0;
+ comedi_buf_put(s->async, val);
- s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
- s->async->cur_chan = 0;
- devpriv->ai_act_scan--;
- }
-
- if (!devpriv->neverending_ai)
- if (devpriv->ai_act_scan == 0) { /* all data sampled */
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
- return IRQ_HANDLED;
- }
+ if (!pcl818_ai_next_chan(dev, s))
+ break;
}
-
- if (len > 0)
- comedi_event(dev, s);
- return IRQ_HANDLED;
}
-/*
-==============================================================================
- analog input interrupt mode 1 & 3, 818HD/HG cards
-*/
-static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
+static void pcl818_handle_fifo(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- struct comedi_device *dev = d;
- struct pcl818_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
+ unsigned int status;
+ unsigned int chan;
+ unsigned int val;
int i, len;
- unsigned char lo;
- outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */
+ status = inb(dev->iobase + PCL818_FI_STATUS);
- lo = inb(dev->iobase + PCL818_FI_STATUS);
-
- if (lo & 4) {
+ if (status & 4) {
comedi_error(dev, "A/D mode1/3 FIFO overflow!");
- pcl818_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ return;
}
- if (lo & 1) {
+ if (status & 1) {
comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
- pcl818_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ return;
}
- if (lo & 2)
+ if (status & 2)
len = 512;
else
len = 0;
for (i = 0; i < len; i++) {
- lo = inb(dev->iobase + PCL818_FI_DATALO);
- if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
- dev_dbg(dev->class_dev,
- "A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
- (lo & 0xf),
- devpriv->act_chanlist[devpriv->act_chanlist_pos]);
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
- }
+ val = pcl818_ai_get_fifo_sample(dev, s, &chan);
- comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */
-
- devpriv->act_chanlist_pos++;
- if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
- devpriv->act_chanlist_pos = 0;
+ if (pcl818_ai_dropout(dev, s, chan))
+ break;
- s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
- s->async->cur_chan = 0;
- devpriv->ai_act_scan--;
- }
+ comedi_buf_put(s->async, val);
- if (!devpriv->neverending_ai)
- if (devpriv->ai_act_scan == 0) { /* all data sampled */
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
- return IRQ_HANDLED;
- }
+ if (!pcl818_ai_next_chan(dev, s))
+ break;
}
-
- if (len > 0)
- comedi_event(dev, s);
- return IRQ_HANDLED;
}
-/*
-==============================================================================
- INT procedure
-*/
-static irqreturn_t interrupt_pcl818(int irq, void *d)
+static irqreturn_t pcl818_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct pcl818_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
- if (!dev->attached) {
- comedi_error(dev, "premature interrupt");
+ if (!dev->attached || !devpriv->ai_cmd_running) {
+ pcl818_ai_clear_eoc(dev);
return IRQ_HANDLED;
}
- if (devpriv->irq_blocked && devpriv->irq_was_now_closed) {
- if ((devpriv->neverending_ai || (!devpriv->neverending_ai &&
- devpriv->ai_act_scan > 0)) &&
- (devpriv->ai_mode == INT_TYPE_AI1_DMA ||
- devpriv->ai_mode == INT_TYPE_AI3_DMA)) {
- /* The cleanup from ai_cancel() has been delayed
- until now because the card doesn't seem to like
- being reprogrammed while a DMA transfer is in
- progress.
- */
- devpriv->ai_act_scan = 0;
- devpriv->neverending_ai = 0;
- pcl818_ai_cancel(dev, dev->read_subdev);
- }
-
- outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
-
+ if (devpriv->ai_cmd_canceled) {
+ /*
+ * The cleanup from ai_cancel() has been delayed
+ * until now because the card doesn't seem to like
+ * being reprogrammed while a DMA transfer is in
+ * progress.
+ */
+ devpriv->ai_act_scan = 0;
+ s->cancel(dev, s);
return IRQ_HANDLED;
}
- switch (devpriv->ai_mode) {
- case INT_TYPE_AI1_DMA:
- case INT_TYPE_AI3_DMA:
- return interrupt_pcl818_ai_mode13_dma(irq, d);
- case INT_TYPE_AI1_INT:
- case INT_TYPE_AI3_INT:
- return interrupt_pcl818_ai_mode13_int(irq, d);
- case INT_TYPE_AI1_FIFO:
- case INT_TYPE_AI3_FIFO:
- return interrupt_pcl818_ai_mode13_fifo(irq, d);
-#ifdef PCL818_MODE13_AO
- case INT_TYPE_AO1_INT:
- case INT_TYPE_AO3_INT:
- return interrupt_pcl818_ao_mode13_int(irq, d);
-#endif
- default:
- break;
- }
-
- outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
-
- if (!devpriv->irq_blocked || !devpriv->ai_mode) {
- comedi_error(dev, "bad IRQ!");
- return IRQ_NONE;
- }
-
- comedi_error(dev, "IRQ from unknown source!");
- return IRQ_NONE;
-}
-
-/*
-==============================================================================
- ANALOG INPUT MODE 1 or 3 DMA , 818 cards
-*/
-static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pcl818_private *devpriv = dev->private;
- unsigned int flags;
- unsigned int bytes;
-
- disable_dma(devpriv->dma); /* disable dma */
- bytes = devpriv->hwdmasize[0];
- if (!devpriv->neverending_ai) {
- bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */
- devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */
- devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */
- devpriv->dma_runs_to_end--;
- if (devpriv->dma_runs_to_end >= 0)
- bytes = devpriv->hwdmasize[0];
- }
-
- devpriv->next_dma_buf = 0;
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- flags = claim_dma_lock();
- clear_dma_ff(devpriv->dma);
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
- set_dma_count(devpriv->dma, bytes);
- release_dma_lock(flags);
- enable_dma(devpriv->dma);
-
- if (mode == 1) {
- devpriv->ai_mode = INT_TYPE_AI1_DMA;
- outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
- } else {
- devpriv->ai_mode = INT_TYPE_AI3_DMA;
- outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
- }
-}
-
-/*
-==============================================================================
- ANALOG INPUT MODE 1 or 3, 818 cards
-*/
-static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pcl818_private *devpriv = dev->private;
- struct comedi_cmd *cmd = &s->async->cmd;
- int divisor1 = 0, divisor2 = 0;
- unsigned int seglen;
-
- if (devpriv->irq_blocked)
- return -EBUSY;
-
- start_pacer(dev, -1, 0, 0); /* stop pacer */
-
- seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
- devpriv->ai_n_chan);
- if (seglen < 1)
- return -EINVAL;
- setup_channel_list(dev, s, devpriv->ai_chanlist,
- devpriv->ai_n_chan, seglen);
-
- udelay(1);
-
- devpriv->ai_act_scan = devpriv->ai_scans;
- devpriv->ai_act_chan = 0;
- devpriv->irq_blocked = 1;
- devpriv->irq_was_now_closed = 0;
- devpriv->neverending_ai = 0;
- devpriv->act_chanlist_pos = 0;
- devpriv->dma_runs_to_end = 0;
-
- if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
- devpriv->neverending_ai = 1; /* well, user want neverending */
-
- if (mode == 1) {
- i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,
- &divisor1, &divisor2,
- &cmd->convert_arg,
- TRIG_ROUND_NEAREST);
- if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */
- divisor1 = 2;
- divisor2 /= 2;
- }
- if (divisor2 == 1) {
- divisor2 = 2;
- divisor1 /= 2;
- }
- }
-
- outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
-
- switch (devpriv->dma) {
- case 1: /* DMA */
- case 3:
- pcl818_ai_mode13dma_int(mode, dev, s);
- break;
- case 0:
- if (!devpriv->usefifo) {
- /* IRQ */
- if (mode == 1) {
- devpriv->ai_mode = INT_TYPE_AI1_INT;
- /* Pacer+IRQ */
- outb(0x83 | (dev->irq << 4),
- dev->iobase + PCL818_CONTROL);
- } else {
- devpriv->ai_mode = INT_TYPE_AI3_INT;
- /* Ext trig+IRQ */
- outb(0x82 | (dev->irq << 4),
- dev->iobase + PCL818_CONTROL);
- }
- } else {
- /* FIFO */
- /* enable FIFO */
- outb(1, dev->iobase + PCL818_FI_ENABLE);
- if (mode == 1) {
- devpriv->ai_mode = INT_TYPE_AI1_FIFO;
- /* Pacer */
- outb(0x03, dev->iobase + PCL818_CONTROL);
- } else {
- devpriv->ai_mode = INT_TYPE_AI3_FIFO;
- outb(0x02, dev->iobase + PCL818_CONTROL);
- }
- }
- }
-
- start_pacer(dev, mode, divisor1, divisor2);
-
- return 0;
-}
+ if (devpriv->dma)
+ pcl818_handle_dma(dev, s);
+ else if (devpriv->usefifo)
+ pcl818_handle_fifo(dev, s);
+ else
+ pcl818_handle_eoc(dev, s);
-/*
-==============================================================================
- Start/stop pacer onboard pacer
-*/
-static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2)
-{
- outb(0xb4, dev->iobase + PCL818_CTRCTL);
- outb(0x74, dev->iobase + PCL818_CTRCTL);
- udelay(1);
+ pcl818_ai_clear_eoc(dev);
- if (mode == 1) {
- outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
- outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
- outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
- outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
- }
+ cfc_handle_events(dev, s);
+ return IRQ_HANDLED;
}
-/*
-==============================================================================
- Check if channel list from user is builded correctly
- If it's ok, then program scan/gain logic
-*/
static int check_channel_list(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int *chanlist, unsigned int n_chan)
@@ -941,52 +728,20 @@ static int check_channel_list(struct comedi_device *dev,
return seglen;
}
-static void setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan,
- unsigned int seglen)
-{
- struct pcl818_private *devpriv = dev->private;
- int i;
-
- devpriv->act_chanlist_len = seglen;
- devpriv->act_chanlist_pos = 0;
-
- for (i = 0; i < seglen; i++) { /* store range list to card */
- devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
- outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
- outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
- }
-
- udelay(1);
-
- /* select channel interval to scan */
- outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
- 1] << 4),
- dev->iobase + PCL818_MUX);
-}
-
-/*
-==============================================================================
- Check if board is switched to SE (1) or DIFF(0) mode
-*/
static int check_single_ended(unsigned int port)
{
- if (inb(port + PCL818_STATUS) & 0x20)
+ if (inb(port + PCL818_STATUS_REG) & PCL818_STATUS_MUX)
return 1;
return 0;
}
-/*
-==============================================================================
-*/
static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
const struct pcl818_board *board = comedi_board(dev);
struct pcl818_private *devpriv = dev->private;
int err = 0;
- int tmp, divisor1 = 0, divisor2 = 0;
+ int tmp;
/* Step 1 : check if triggers are trivially valid */
@@ -1035,7 +790,8 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
if (cmd->convert_src == TRIG_TIMER) {
tmp = cmd->convert_arg;
i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,
- &divisor1, &divisor2,
+ &devpriv->divisor1,
+ &devpriv->divisor2,
&cmd->convert_arg, cmd->flags);
if (cmd->convert_arg < board->ns_min)
cmd->convert_arg = board->ns_min;
@@ -1057,152 +813,272 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
-/*
-==============================================================================
-*/
-static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
+static int pcl818_ai_cmd(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct pcl818_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
- int retval;
+ unsigned int ctrl = 0;
+ unsigned int seglen;
+
+ if (devpriv->ai_cmd_running)
+ return -EBUSY;
+
+ pcl818_start_pacer(dev, false);
+
+ seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
+ if (seglen < 1)
+ return -EINVAL;
+ pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen);
- devpriv->ai_n_chan = cmd->chanlist_len;
- devpriv->ai_chanlist = cmd->chanlist;
- devpriv->ai_flags = cmd->flags;
devpriv->ai_data_len = s->async->prealloc_bufsz;
- devpriv->ai_timer1 = 0;
- devpriv->ai_timer2 = 0;
+ devpriv->ai_act_scan = cmd->stop_arg;
+ devpriv->ai_act_chan = 0;
+ devpriv->ai_cmd_running = 1;
+ devpriv->ai_cmd_canceled = 0;
+ devpriv->act_chanlist_pos = 0;
+ devpriv->dma_runs_to_end = 0;
- if (cmd->stop_src == TRIG_COUNT)
- devpriv->ai_scans = cmd->stop_arg;
+ if (cmd->convert_src == TRIG_TIMER)
+ ctrl |= PCL818_CTRL_PACER_TRIG;
else
- devpriv->ai_scans = 0;
+ ctrl |= PCL818_CTRL_EXT_TRIG;
- if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */
- if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */
- devpriv->ai_timer1 = cmd->convert_arg;
- retval = pcl818_ai_cmd_mode(1, dev, s);
- return retval;
- }
- if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
- return pcl818_ai_cmd_mode(3, dev, s);
- }
+ outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG);
+
+ if (devpriv->dma) {
+ pcl818_ai_setup_dma(dev, s);
+
+ ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq) |
+ PCL818_CTRL_DMAE;
+ } else if (devpriv->usefifo) {
+ /* enable FIFO */
+ outb(1, dev->iobase + PCL818_FI_ENABLE);
+ } else {
+ ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq);
}
+ outb(ctrl, dev->iobase + PCL818_CTRL_REG);
+
+ if (cmd->convert_src == TRIG_TIMER)
+ pcl818_start_pacer(dev, true);
- return -1;
+ return 0;
}
-/*
-==============================================================================
- cancel any mode 1-4 AI
-*/
static int pcl818_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct pcl818_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
- if (devpriv->irq_blocked > 0) {
- devpriv->irq_was_now_closed = 1;
-
- switch (devpriv->ai_mode) {
- case INT_TYPE_AI1_DMA:
- case INT_TYPE_AI3_DMA:
- if (devpriv->neverending_ai ||
- (!devpriv->neverending_ai &&
- devpriv->ai_act_scan > 0)) {
- /* wait for running dma transfer to end, do cleanup in interrupt */
- goto end;
- }
- disable_dma(devpriv->dma);
- case INT_TYPE_AI1_INT:
- case INT_TYPE_AI3_INT:
- case INT_TYPE_AI1_FIFO:
- case INT_TYPE_AI3_FIFO:
-#ifdef PCL818_MODE13_AO
- case INT_TYPE_AO1_INT:
- case INT_TYPE_AO3_INT:
-#endif
- outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */
- udelay(1);
- start_pacer(dev, -1, 0, 0);
- outb(0, dev->iobase + PCL818_AD_LO);
- inb(dev->iobase + PCL818_AD_LO);
- inb(dev->iobase + PCL818_AD_HI);
- outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
- outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */
- if (devpriv->usefifo) { /* FIFO shutdown */
- outb(0, dev->iobase + PCL818_FI_INTCLR);
- outb(0, dev->iobase + PCL818_FI_FLUSH);
- outb(0, dev->iobase + PCL818_FI_ENABLE);
+ if (!devpriv->ai_cmd_running)
+ return 0;
+
+ if (devpriv->dma) {
+ if (cmd->stop_src == TRIG_NONE ||
+ (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan > 0)) {
+ if (!devpriv->ai_cmd_canceled) {
+ /*
+ * Wait for running dma transfer to end,
+ * do cleanup in interrupt.
+ */
+ devpriv->ai_cmd_canceled = 1;
+ return 0;
}
- devpriv->irq_blocked = 0;
- devpriv->last_int_sub = s;
- devpriv->neverending_ai = 0;
- devpriv->ai_mode = 0;
- devpriv->irq_was_now_closed = 0;
- break;
}
+ disable_dma(devpriv->dma);
+ }
+
+ outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG);
+ pcl818_start_pacer(dev, false);
+ pcl818_ai_clear_eoc(dev);
+
+ if (devpriv->usefifo) { /* FIFO shutdown */
+ outb(0, dev->iobase + PCL818_FI_INTCLR);
+ outb(0, dev->iobase + PCL818_FI_FLUSH);
+ outb(0, dev->iobase + PCL818_FI_ENABLE);
}
+ devpriv->ai_cmd_running = 0;
+ devpriv->ai_cmd_canceled = 0;
-end:
return 0;
}
-/*
-==============================================================================
- chech for PCL818
-*/
-static int pcl818_check(unsigned long iobase)
+static int pcl818_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- outb(0x00, iobase + PCL818_MUX);
- udelay(1);
- if (inb(iobase + PCL818_MUX) != 0x00)
- return 1; /* there isn't card */
- outb(0x55, iobase + PCL818_MUX);
- udelay(1);
- if (inb(iobase + PCL818_MUX) != 0x55)
- return 1; /* there isn't card */
- outb(0x00, iobase + PCL818_MUX);
- udelay(1);
- outb(0x18, iobase + PCL818_CONTROL);
- udelay(1);
- if (inb(iobase + PCL818_CONTROL) != 0x18)
- return 1; /* there isn't card */
- return 0; /* ok, card exist */
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ int ret = 0;
+ int i;
+
+ outb(PCL818_CTRL_SOFT_TRIG, dev->iobase + PCL818_CTRL_REG);
+
+ pcl818_ai_set_chan_range(dev, chan, range);
+ pcl818_ai_set_chan_scan(dev, chan, chan);
+
+ for (i = 0; i < insn->n; i++) {
+ pcl818_ai_clear_eoc(dev);
+ pcl818_ai_soft_trig(dev);
+
+ ret = comedi_timeout(dev, s, insn, pcl818_ai_eoc, 0);
+ if (ret)
+ break;
+
+ data[i] = pcl818_ai_get_sample(dev, s, NULL);
+ }
+ pcl818_ai_clear_eoc(dev);
+
+ return ret ? ret : insn->n;
+}
+
+static int pcl818_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct pcl818_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++) {
+ devpriv->ao_readback[chan] = data[i];
+ outb((data[i] & 0x000f) << 4,
+ dev->iobase + PCL818_AO_LSB_REG(chan));
+ outb((data[i] & 0x0ff0) >> 4,
+ dev->iobase + PCL818_AO_MSB_REG(chan));
+ }
+
+ return insn->n;
+}
+
+static int pcl818_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct pcl818_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
+
+ return insn->n;
+}
+
+static int pcl818_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ data[1] = inb(dev->iobase + PCL818_DO_DI_LSB_REG) |
+ (inb(dev->iobase + PCL818_DO_DI_MSB_REG) << 8);
+
+ return insn->n;
+}
+
+static int pcl818_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (comedi_dio_update_state(s, data)) {
+ outb(s->state & 0xff, dev->iobase + PCL818_DO_DI_LSB_REG);
+ outb((s->state >> 8), dev->iobase + PCL818_DO_DI_MSB_REG);
+ }
+
+ data[1] = s->state;
+
+ return insn->n;
}
-/*
-==============================================================================
- reset whole PCL-818 cards
-*/
static void pcl818_reset(struct comedi_device *dev)
{
const struct pcl818_board *board = comedi_board(dev);
- struct pcl818_private *devpriv = dev->private;
+ unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE;
+ unsigned int chan;
- if (devpriv->usefifo) { /* FIFO shutdown */
+ /* flush and disable the FIFO */
+ if (board->has_fifo) {
outb(0, dev->iobase + PCL818_FI_INTCLR);
outb(0, dev->iobase + PCL818_FI_FLUSH);
outb(0, dev->iobase + PCL818_FI_ENABLE);
}
- outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */
- outb(0, dev->iobase + PCL818_DA_HI);
- udelay(1);
- outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */
- outb(0, dev->iobase + PCL818_DO_LO);
- udelay(1);
- outb(0, dev->iobase + PCL818_CONTROL);
- outb(0, dev->iobase + PCL818_CNTENABLE);
- outb(0, dev->iobase + PCL818_MUX);
- outb(0, dev->iobase + PCL818_CLRINT);
- outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */
- outb(0x70, dev->iobase + PCL818_CTRCTL);
- outb(0x30, dev->iobase + PCL818_CTRCTL);
+
+ /* disable analog input trigger */
+ outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG);
+ pcl818_ai_clear_eoc(dev);
+
+ pcl818_ai_set_chan_range(dev, 0, 0);
+
+ /* stop pacer */
+ outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG);
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY);
+
+ /* set analog output channels to 0V */
+ for (chan = 0; chan < board->n_aochan; chan++) {
+ outb(0, dev->iobase + PCL818_AO_LSB_REG(chan));
+ outb(0, dev->iobase + PCL818_AO_MSB_REG(chan));
+ }
+
+ /* set all digital outputs low */
+ outb(0, dev->iobase + PCL818_DO_DI_MSB_REG);
+ outb(0, dev->iobase + PCL818_DO_DI_LSB_REG);
+}
+
+static void pcl818_set_ai_range_table(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_devconfig *it)
+{
+ const struct pcl818_board *board = comedi_board(dev);
+
+ /* default to the range table from the boardinfo */
+ s->range_table = board->ai_range_type;
+
+ /* now check the user config option based on the boardtype */
if (board->is_818) {
- outb(0, dev->iobase + PCL818_RANGE);
+ if (it->options[4] == 1 || it->options[4] == 10) {
+ /* secondary range list jumper selectable */
+ s->range_table = &range_pcl818l_h_ai;
+ }
} else {
- outb(0, dev->iobase + PCL718_DA2_LO);
- outb(0, dev->iobase + PCL718_DA2_HI);
+ switch (it->options[4]) {
+ case 0:
+ s->range_table = &range_bipolar10;
+ break;
+ case 1:
+ s->range_table = &range_bipolar5;
+ break;
+ case 2:
+ s->range_table = &range_bipolar2_5;
+ break;
+ case 3:
+ s->range_table = &range718_bipolar1;
+ break;
+ case 4:
+ s->range_table = &range718_bipolar0_5;
+ break;
+ case 6:
+ s->range_table = &range_unipolar10;
+ break;
+ case 7:
+ s->range_table = &range_unipolar5;
+ break;
+ case 8:
+ s->range_table = &range718_unipolar2;
+ break;
+ case 9:
+ s->range_table = &range718_unipolar1;
+ break;
+ default:
+ s->range_table = &range_unknown;
+ break;
+ }
}
}
@@ -1210,154 +1086,96 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl818_board *board = comedi_board(dev);
struct pcl818_private *devpriv;
- int ret;
- int dma;
- unsigned long pages;
struct comedi_subdevice *s;
+ int ret;
+ int i;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- devpriv->io_range = board->io_range;
- if ((board->fifo) && (it->options[2] == -1)) {
- /* we've board with FIFO and we want to use FIFO */
- devpriv->io_range = PCLx1xFIFO_RANGE;
- devpriv->usefifo = 1;
- }
- ret = comedi_request_region(dev, it->options[0], devpriv->io_range);
+ ret = comedi_request_region(dev, it->options[0],
+ board->has_fifo ? 0x20 : 0x10);
if (ret)
return ret;
- if (pcl818_check(dev->iobase)) {
- comedi_error(dev, "I can't detect board. FAIL!\n");
- return -EIO;
- }
-
- if ((1 << it->options[1]) & board->IRQbits) {
- ret = request_irq(it->options[1], interrupt_pcl818, 0,
+ /* we can use IRQ 2-7 for async command support */
+ if (it->options[1] >= 2 && it->options[1] <= 7) {
+ ret = request_irq(it->options[1], pcl818_interrupt, 0,
dev->board_name, dev);
if (ret == 0)
dev->irq = it->options[1];
}
- devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
- devpriv->ai_mode = 0; /* mode of irq */
-
- /* grab our DMA */
- dma = 0;
- devpriv->dma = dma;
- if (!dev->irq)
- goto no_dma; /* if we haven't IRQ, we can't use DMA */
- if (board->DMAbits != 0) { /* board support DMA */
- dma = it->options[2];
- if (dma < 1)
- goto no_dma; /* DMA disabled */
- if (((1 << dma) & board->DMAbits) == 0) {
+ /* should we use the FIFO? */
+ if (dev->irq && board->has_fifo && it->options[2] == -1)
+ devpriv->usefifo = 1;
+
+ /* we need an IRQ to do DMA on channel 3 or 1 */
+ if (dev->irq && board->has_dma &&
+ (it->options[2] == 3 || it->options[2] == 1)) {
+ ret = request_dma(it->options[2], dev->board_name);
+ if (ret) {
dev_err(dev->class_dev,
- "DMA is out of allowed range, FAIL!\n");
- return -EINVAL; /* Bad DMA */
- }
- ret = request_dma(dma, dev->board_name);
- if (ret)
- return -EBUSY; /* DMA isn't free */
- devpriv->dma = dma;
- pages = 2; /* we need 16KB */
- devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[0])
- /* maybe experiment with try_to_free_pages() will help .... */
- return -EBUSY; /* no buffer :-( */
- devpriv->dmapages[0] = pages;
- devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
- devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
- devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[1])
+ "unable to request DMA channel %d\n",
+ it->options[2]);
return -EBUSY;
- devpriv->dmapages[1] = pages;
- devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
- devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
- }
+ }
+ devpriv->dma = it->options[2];
+
+ devpriv->dmapages = 2; /* we need 16KB */
+ devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
-no_dma:
+ for (i = 0; i < 2; i++) {
+ unsigned long dmabuf;
+
+ dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
+ if (!dmabuf)
+ return -ENOMEM;
+
+ devpriv->dmabuf[i] = dmabuf;
+ devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
+ }
+ }
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
return ret;
s = &dev->subdevices[0];
- if (!board->n_aichan_se) {
- s->type = COMEDI_SUBD_UNUSED;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE;
+ if (check_single_ended(dev->iobase)) {
+ s->n_chan = 16;
+ s->subdev_flags |= SDF_COMMON | SDF_GROUND;
} else {
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE;
- if (check_single_ended(dev->iobase)) {
- s->n_chan = board->n_aichan_se;
- s->subdev_flags |= SDF_COMMON | SDF_GROUND;
- } else {
- s->n_chan = board->n_aichan_diff;
- s->subdev_flags |= SDF_DIFF;
- }
- s->maxdata = board->ai_maxdata;
- s->range_table = board->ai_range_type;
- s->insn_read = pcl818_ai_insn_read;
- if (dev->irq) {
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->len_chanlist = s->n_chan;
- s->do_cmdtest = ai_cmdtest;
- s->do_cmd = ai_cmd;
- s->cancel = pcl818_ai_cancel;
- }
- if (board->is_818) {
- if ((it->options[4] == 1) || (it->options[4] == 10))
- s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */
- } else {
- switch (it->options[4]) {
- case 0:
- s->range_table = &range_bipolar10;
- break;
- case 1:
- s->range_table = &range_bipolar5;
- break;
- case 2:
- s->range_table = &range_bipolar2_5;
- break;
- case 3:
- s->range_table = &range718_bipolar1;
- break;
- case 4:
- s->range_table = &range718_bipolar0_5;
- break;
- case 6:
- s->range_table = &range_unipolar10;
- break;
- case 7:
- s->range_table = &range_unipolar5;
- break;
- case 8:
- s->range_table = &range718_unipolar2;
- break;
- case 9:
- s->range_table = &range718_unipolar1;
- break;
- default:
- s->range_table = &range_unknown;
- break;
- }
- }
+ s->n_chan = 8;
+ s->subdev_flags |= SDF_DIFF;
+ }
+ s->maxdata = 0x0fff;
+
+ pcl818_set_ai_range_table(dev, s, it);
+
+ s->insn_read = pcl818_ai_insn_read;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = s->n_chan;
+ s->do_cmdtest = ai_cmdtest;
+ s->do_cmd = pcl818_ai_cmd;
+ s->cancel = pcl818_ai_cancel;
}
+ /* Analog Output subdevice */
s = &dev->subdevices[1];
- if (!board->n_aochan) {
- s->type = COMEDI_SUBD_UNUSED;
- } else {
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
- s->n_chan = board->n_aochan;
- s->maxdata = board->ao_maxdata;
- s->range_table = board->ao_range_type;
- s->insn_read = pcl818_ao_insn_read;
- s->insn_write = pcl818_ao_insn_write;
+ if (board->n_aochan) {
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
+ s->n_chan = board->n_aochan;
+ s->maxdata = 0x0fff;
+ s->range_table = &range_unipolar5;
+ s->insn_read = pcl818_ao_insn_read;
+ s->insn_write = pcl818_ao_insn_write;
if (board->is_818) {
if ((it->options[4] == 1) || (it->options[4] == 10))
s->range_table = &range_unipolar10;
@@ -1369,31 +1187,27 @@ no_dma:
if (it->options[5] == 2)
s->range_table = &range_unknown;
}
- }
-
- s = &dev->subdevices[2];
- if (!board->n_dichan) {
- s->type = COMEDI_SUBD_UNUSED;
} else {
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = board->n_dichan;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = pcl818_di_insn_bits;
+ s->type = COMEDI_SUBD_UNUSED;
}
+ /* Digital Input subdevice */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcl818_di_insn_bits;
+
+ /* Digital Output subdevice */
s = &dev->subdevices[3];
- if (!board->n_dochan) {
- s->type = COMEDI_SUBD_UNUSED;
- } else {
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = board->n_dochan;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = pcl818_do_insn_bits;
- }
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcl818_do_insn_bits;
/* select 1/10MHz oscilator */
if ((it->options[3] == 0) || (it->options[3] == 10))
@@ -1424,38 +1238,13 @@ static void pcl818_detach(struct comedi_device *dev)
if (devpriv->dma)
free_dma(devpriv->dma);
if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
+ free_pages(devpriv->dmabuf[0], devpriv->dmapages);
if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
+ free_pages(devpriv->dmabuf[1], devpriv->dmapages);
}
comedi_legacy_detach(dev);
}
-static const struct pcl818_board boardtypes[] = {
- {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1},
- {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1},
- {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 1, 1},
- {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 1, 1},
- {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1},
- {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 0},
- /* pcm3718 */
- {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
-};
-
static struct comedi_driver pcl818_driver = {
.driver_name = "pcl818",
.module = THIS_MODULE,
diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c
index f4a49bd649f0..53e73737a906 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -225,8 +225,10 @@ static int pcm3724_attach(struct comedi_device *dev,
for (i = 0; i < dev->n_subdevices; i++) {
s = &dev->subdevices[i];
- subdev_8255_init(dev, s, subdev_8255_cb,
- (unsigned long)(dev->iobase + SIZE_8255 * i));
+ ret = subdev_8255_init(dev, s, subdev_8255_cb,
+ dev->iobase + SIZE_8255 * i);
+ if (ret)
+ return ret;
s->insn_config = subdev_3724_insn_config;
}
return 0;
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index fe482fdd512e..87c61d9b11da 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -61,18 +61,17 @@ static const struct pcmad_board_struct pcmad_boards[] = {
},
};
-#define TIMEOUT 100
-
-static int pcmad_ai_wait_for_eoc(struct comedi_device *dev,
- int timeout)
+static int pcmad_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- int i;
+ unsigned int status;
- for (i = 0; i < timeout; i++) {
- if ((inb(dev->iobase + PCMAD_STATUS) & 0x3) == 0x3)
- return 0;
- }
- return -ETIME;
+ status = inb(dev->iobase + PCMAD_STATUS);
+ if ((status & 0x3) == 0x3)
+ return 0;
+ return -EBUSY;
}
static int pcmad_ai_insn_read(struct comedi_device *dev,
@@ -89,7 +88,7 @@ static int pcmad_ai_insn_read(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
outb(chan, dev->iobase + PCMAD_CONVERT);
- ret = pcmad_ai_wait_for_eoc(dev, TIMEOUT);
+ ret = comedi_timeout(dev, s, insn, pcmad_ai_eoc, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index c388f7f32227..e89bca845349 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -589,16 +589,17 @@ static int pcmmio_cmdtest(struct comedi_device *dev,
return 0;
}
-static int pcmmio_ai_wait_for_eoc(unsigned long iobase, unsigned int timeout)
+static int pcmmio_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
unsigned char status;
- while (timeout--) {
- status = inb(iobase + PCMMIO_AI_STATUS_REG);
- if (status & PCMMIO_AI_STATUS_DATA_READY)
- return 0;
- }
- return -ETIME;
+ status = inb(dev->iobase + PCMMIO_AI_STATUS_REG);
+ if (status & PCMMIO_AI_STATUS_DATA_READY)
+ return 0;
+ return -EBUSY;
}
static int pcmmio_ai_insn_read(struct comedi_device *dev,
@@ -643,7 +644,8 @@ static int pcmmio_ai_insn_read(struct comedi_device *dev,
cmd |= PCMMIO_AI_CMD_RANGE(range);
outb(cmd, iobase + PCMMIO_AI_CMD_REG);
- ret = pcmmio_ai_wait_for_eoc(iobase, 100000);
+
+ ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0);
if (ret)
return ret;
@@ -652,7 +654,8 @@ static int pcmmio_ai_insn_read(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
outb(cmd, iobase + PCMMIO_AI_CMD_REG);
- ret = pcmmio_ai_wait_for_eoc(iobase, 100000);
+
+ ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0);
if (ret)
return ret;
@@ -684,16 +687,17 @@ static int pcmmio_ao_insn_read(struct comedi_device *dev,
return insn->n;
}
-static int pcmmio_ao_wait_for_eoc(unsigned long iobase, unsigned int timeout)
+static int pcmmio_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
unsigned char status;
- while (timeout--) {
- status = inb(iobase + PCMMIO_AO_STATUS_REG);
- if (status & PCMMIO_AO_STATUS_DATA_READY)
- return 0;
- }
- return -ETIME;
+ status = inb(dev->iobase + PCMMIO_AO_STATUS_REG);
+ if (status & PCMMIO_AO_STATUS_DATA_READY)
+ return 0;
+ return -EBUSY;
}
static int pcmmio_ao_insn_write(struct comedi_device *dev,
@@ -726,7 +730,8 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev,
outb(PCMMIO_AO_LSB_SPAN(range), iobase + PCMMIO_AO_LSB_REG);
outb(0, iobase + PCMMIO_AO_MSB_REG);
outb(cmd | PCMMIO_AO_CMD_WR_SPAN_UPDATE, iobase + PCMMIO_AO_CMD_REG);
- ret = pcmmio_ao_wait_for_eoc(iobase, 100000);
+
+ ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0);
if (ret)
return ret;
@@ -738,7 +743,8 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev,
outb((val >> 8) & 0xff, iobase + PCMMIO_AO_MSB_REG);
outb(cmd | PCMMIO_AO_CMD_WR_CODE_UPDATE,
iobase + PCMMIO_AO_CMD_REG);
- ret = pcmmio_ao_wait_for_eoc(iobase, 100000);
+
+ ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h
index 55e3c2e2bc52..25706531b885 100644
--- a/drivers/staging/comedi/drivers/plx9080.h
+++ b/drivers/staging/comedi/drivers/plx9080.h
@@ -29,13 +29,13 @@
/* descriptor block used for chained dma transfers */
struct plx_dma_desc {
- volatile uint32_t pci_start_addr;
- volatile uint32_t local_start_addr;
+ __le32 pci_start_addr;
+ __le32 local_start_addr;
/* transfer_size is in bytes, only first 23 bits of register are used */
- volatile uint32_t transfer_size;
+ __le32 transfer_size;
/* address of next descriptor (quad word aligned), plus some
* additional bits (see PLX_DMA0_DESCRIPTOR_REG) */
- volatile uint32_t next;
+ __le32 next;
};
/**********************************************************************
diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c
deleted file mode 100644
index 2ae4ee15704c..000000000000
--- a/drivers/staging/comedi/drivers/poc.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- comedi/drivers/poc.c
- Mini-drivers for POC (Piece of Crap) boards
- Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>
- Copyright (C) 2001 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
-/*
-Driver: poc
-Description: Generic driver for very simple devices
-Author: ds
-Devices: [Keithley Metrabyte] DAC-02 (dac02)
-Updated: Sat, 16 Mar 2002 17:34:48 -0800
-Status: unknown
-
-This driver is indended to support very simple ISA-based devices,
-including:
- dac02 - Keithley DAC-02 analog output board
-
-Configuration options:
- [0] - I/O port base
-*/
-
-#include <linux/module.h>
-#include "../comedidev.h"
-
-struct boarddef_struct {
- const char *name;
- unsigned int iosize;
- int (*setup) (struct comedi_device *);
- int type;
- int n_chan;
- int n_bits;
- int (*winsn) (struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
- int (*rinsn) (struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
- int (*insnbits) (struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
- const struct comedi_lrange *range;
-};
-
-struct poc_private {
- unsigned int ao_readback[32];
-};
-
-static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct poc_private *devpriv = dev->private;
- int chan;
-
- chan = CR_CHAN(insn->chanspec);
- data[0] = devpriv->ao_readback[chan];
-
- return 1;
-}
-
-/* DAC-02 registers */
-#define DAC02_LSB(a) (2 * a)
-#define DAC02_MSB(a) (2 * a + 1)
-
-static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct poc_private *devpriv = dev->private;
- int temp;
- int chan;
- int output;
-
- chan = CR_CHAN(insn->chanspec);
- devpriv->ao_readback[chan] = data[0];
- output = data[0];
-#ifdef wrong
- /* convert to complementary binary if range is bipolar */
- if ((CR_RANGE(insn->chanspec) & 0x2) == 0)
- output = ~output;
-#endif
- temp = (output << 4) & 0xf0;
- outb(temp, dev->iobase + DAC02_LSB(chan));
- temp = (output >> 4) & 0xff;
- outb(temp, dev->iobase + DAC02_MSB(chan));
-
- return 1;
-}
-
-static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- const struct boarddef_struct *board = comedi_board(dev);
- struct poc_private *devpriv;
- struct comedi_subdevice *s;
- int ret;
-
- ret = comedi_request_region(dev, it->options[0], board->iosize);
- if (ret)
- return ret;
-
- ret = comedi_alloc_subdevices(dev, 1);
- if (ret)
- return ret;
-
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
- /* analog output subdevice */
- s = &dev->subdevices[0];
- s->type = board->type;
- s->n_chan = board->n_chan;
- s->maxdata = (1 << board->n_bits) - 1;
- s->range_table = board->range;
- s->insn_write = board->winsn;
- s->insn_read = board->rinsn;
- s->insn_bits = board->insnbits;
- if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO)
- s->subdev_flags = SDF_WRITABLE;
-
- return 0;
-}
-
-static const struct boarddef_struct boards[] = {
- {
- .name = "dac02",
- .iosize = 8,
- /* .setup = dac02_setup, */
- .type = COMEDI_SUBD_AO,
- .n_chan = 2,
- .n_bits = 12,
- .winsn = dac02_ao_winsn,
- .rinsn = readback_insn,
- .range = &range_unknown,
- },
-};
-
-static struct comedi_driver poc_driver = {
- .driver_name = "poc",
- .module = THIS_MODULE,
- .attach = poc_attach,
- .detach = comedi_legacy_detach,
- .board_name = &boards[0].name,
- .num_names = ARRAY_SIZE(boards),
- .offset = sizeof(boards[0]),
-};
-module_comedi_driver(poc_driver);
-
-MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index 96a46954b3c0..298dba03f902 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -214,7 +214,6 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id)
s->async->events |=
COMEDI_CB_EOA | COMEDI_CB_OVERFLOW;
dev_warn(dev->class_dev, "data lost\n");
- daqp_ai_cancel(dev, s);
break;
}
@@ -231,7 +230,6 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id)
if (devpriv->count > 0) {
devpriv->count--;
if (devpriv->count == 0) {
- daqp_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
break;
}
@@ -244,13 +242,12 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id)
if (loop_limit <= 0) {
dev_warn(dev->class_dev,
"loop_limit reached in daqp_interrupt()\n");
- daqp_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
}
s->async->events |= COMEDI_CB_BLOCK;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
return IRQ_HANDLED;
}
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 0f026afde9be..cd3fdf973bdd 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -237,20 +237,6 @@
/* The board support a channel list up to the FIFO length (1K or 8K) */
#define RTD_MAX_CHANLIST 128 /* max channel list that we allow */
-/* tuning for ai/ao instruction done polling */
-#ifdef FAST_SPIN
-#define WAIT_QUIETLY /* as nothing, spin on done bit */
-#define RTD_ADC_TIMEOUT 66000 /* 2 msec at 33mhz bus rate */
-#define RTD_DAC_TIMEOUT 66000
-#define RTD_DMA_TIMEOUT 33000 /* 1 msec */
-#else
-/* by delaying, power and electrical noise are reduced somewhat */
-#define WAIT_QUIETLY udelay(1)
-#define RTD_ADC_TIMEOUT 2000 /* in usec */
-#define RTD_DAC_TIMEOUT 2000 /* in usec */
-#define RTD_DMA_TIMEOUT 1000 /* in usec */
-#endif
-
/*======================================================================
Board specific stuff
======================================================================*/
@@ -562,21 +548,27 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev)
return fifo_size;
}
-/*
- "instructions" read/write data in "one-shot" or "software-triggered"
- mode (simplest case).
- This doesn't use interrupts.
+static int rtd_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct rtd_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readl(devpriv->las0 + LAS0_ADC);
+ if (status & FS_ADC_NOT_EMPTY)
+ return 0;
+ return -EBUSY;
+}
- Note, we don't do any settling delays. Use a instruction list to
- select, delay, then read.
- */
static int rtd_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
struct rtd_private *devpriv = dev->private;
- int n, ii;
- int stat;
+ int ret;
+ int n;
/* clear any old fifo data */
writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
@@ -593,14 +585,9 @@ static int rtd_ai_rinsn(struct comedi_device *dev,
/* trigger conversion */
writew(0, devpriv->las0 + LAS0_ADC);
- for (ii = 0; ii < RTD_ADC_TIMEOUT; ++ii) {
- stat = readl(devpriv->las0 + LAS0_ADC);
- if (stat & FS_ADC_NOT_EMPTY) /* 1 -> not empty */
- break;
- WAIT_QUIETLY;
- }
- if (ii >= RTD_ADC_TIMEOUT)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, rtd_ai_eoc, 0);
+ if (ret)
+ return ret;
/* read data */
d = readw(devpriv->las1 + LAS1_ADC_FIFO);
@@ -1116,9 +1103,22 @@ static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
-/*
- Output one (or more) analog values to a single port as fast as possible.
-*/
+static int rtd_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct rtd_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int bit = (chan == 0) ? FS_DAC1_NOT_EMPTY : FS_DAC2_NOT_EMPTY;
+ unsigned int status;
+
+ status = readl(devpriv->las0 + LAS0_ADC);
+ if (status & bit)
+ return 0;
+ return -EBUSY;
+}
+
static int rtd_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
@@ -1127,6 +1127,7 @@ static int rtd_ao_winsn(struct comedi_device *dev,
int i;
int chan = CR_CHAN(insn->chanspec);
int range = CR_RANGE(insn->chanspec);
+ int ret;
/* Configure the output range (table index matches the range values) */
writew(range & 7, devpriv->las0 +
@@ -1136,8 +1137,6 @@ static int rtd_ao_winsn(struct comedi_device *dev,
* very useful, but that's how the interface is defined. */
for (i = 0; i < insn->n; ++i) {
int val = data[i] << 3;
- int stat = 0; /* initialize to avoid bogus warning */
- int ii;
/* VERIFY: comedi range and offset conversions */
@@ -1157,16 +1156,9 @@ static int rtd_ao_winsn(struct comedi_device *dev,
devpriv->ao_readback[chan] = data[i];
- for (ii = 0; ii < RTD_DAC_TIMEOUT; ++ii) {
- stat = readl(devpriv->las0 + LAS0_ADC);
- /* 1 -> not empty */
- if (stat & ((0 == chan) ? FS_DAC1_NOT_EMPTY :
- FS_DAC2_NOT_EMPTY))
- break;
- WAIT_QUIETLY;
- }
- if (ii >= RTD_DAC_TIMEOUT)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, rtd_ao_eoc, 0);
+ if (ret)
+ return ret;
}
/* return the number of samples read/written */
@@ -1382,8 +1374,6 @@ static int rtd_auto_attach(struct comedi_device *dev,
if (dev->irq)
writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + PLX_INTRCS_REG);
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index e1f3671ac056..bd447b2add7b 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -83,8 +83,6 @@
#define RTI800_IOSIZE 0x10
-#define RTI800_AI_TIMEOUT 100
-
static const struct comedi_lrange range_rti800_ai_10_bipolar = {
4, {
BIP_RANGE(10),
@@ -145,23 +143,21 @@ struct rti800_private {
unsigned char muxgain_bits;
};
-static int rti800_ai_wait_for_conversion(struct comedi_device *dev,
- int timeout)
+static int rti800_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
unsigned char status;
- int i;
- for (i = 0; i < timeout; i++) {
- status = inb(dev->iobase + RTI800_CSR);
- if (status & RTI800_CSR_OVERRUN) {
- outb(0, dev->iobase + RTI800_CLRFLAGS);
- return -EIO;
- }
- if (status & RTI800_CSR_DONE)
- return 0;
- udelay(1);
+ status = inb(dev->iobase + RTI800_CSR);
+ if (status & RTI800_CSR_OVERRUN) {
+ outb(0, dev->iobase + RTI800_CLRFLAGS);
+ return -EOVERFLOW;
}
- return -ETIME;
+ if (status & RTI800_CSR_DONE)
+ return 0;
+ return -EBUSY;
}
static int rti800_ai_insn_read(struct comedi_device *dev,
@@ -198,7 +194,8 @@ static int rti800_ai_insn_read(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
outb(0, dev->iobase + RTI800_CONVERT);
- ret = rti800_ai_wait_for_conversion(dev, RTI800_AI_TIMEOUT);
+
+ ret = comedi_timeout(dev, s, insn, rti800_ai_eoc, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index a3fa2a4baef4..605a31d702e0 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -1,45 +1,44 @@
/*
- comedi/drivers/rti802.c
- Hardware driver for Analog Devices RTI-802 board
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se>
-
- This program is free software; 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.
+ * rti802.c
+ * Comedi driver for Analog Devices RTI-802 board
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se>
+ *
+ * This program is free software; 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.
*/
+
/*
-Driver: rti802
-Description: Analog Devices RTI-802
-Author: Anders Blomdell <anders.blomdell@control.lth.se>
-Devices: [Analog Devices] RTI-802 (rti802)
-Status: works
-
-Configuration Options:
- [0] - i/o base
- [1] - unused
- [2] - dac#0 0=two's comp, 1=straight
- [3] - dac#0 0=bipolar, 1=unipolar
- [4] - dac#1 ...
- ...
- [17] - dac#7 ...
-*/
+ * Driver: rti802
+ * Description: Analog Devices RTI-802
+ * Author: Anders Blomdell <anders.blomdell@control.lth.se>
+ * Devices: (Analog Devices) RTI-802 [rti802]
+ * Status: works
+ *
+ * Configuration Options:
+ * [0] - i/o base
+ * [1] - unused
+ * [2,4,6,8,10,12,14,16] - dac#[0-7] 0=two's comp, 1=straight
+ * [3,5,7,9,11,13,15,17] - dac#[0-7] 0=bipolar, 1=unipolar
+ */
#include <linux/module.h>
#include "../comedidev.h"
-#define RTI802_SIZE 4
-
-#define RTI802_SELECT 0
-#define RTI802_DATALOW 1
-#define RTI802_DATAHIGH 2
+/*
+ * Register I/O map
+ */
+#define RTI802_SELECT 0x00
+#define RTI802_DATALOW 0x01
+#define RTI802_DATAHIGH 0x02
struct rti802_private {
enum {
@@ -51,34 +50,45 @@ struct rti802_private {
static int rti802_ao_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct rti802_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
int i;
for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
+ data[i] = devpriv->ao_readback[chan];
- return i;
+ return insn->n;
}
static int rti802_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct rti802_private *devpriv = dev->private;
- int i, d;
- int chan = CR_CHAN(insn->chanspec);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
+ int i;
+
+ outb(chan, dev->iobase + RTI802_SELECT);
for (i = 0; i < insn->n; i++) {
- d = devpriv->ao_readback[chan] = data[i];
+ val = data[i];
+
+ devpriv->ao_readback[chan] = val;
+
+ /* munge offset binary to two's complement if needed */
if (devpriv->dac_coding[chan] == dac_2comp)
- d ^= 0x800;
- outb(chan, dev->iobase + RTI802_SELECT);
- outb(d & 0xff, dev->iobase + RTI802_DATALOW);
- outb(d >> 8, dev->iobase + RTI802_DATAHIGH);
+ val = comedi_offset_munge(s, val);
+
+ outb(val & 0xff, dev->iobase + RTI802_DATALOW);
+ outb((val >> 8) & 0xff, dev->iobase + RTI802_DATAHIGH);
}
- return i;
+
+ return insn->n;
}
static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -88,7 +98,7 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
int i;
int ret;
- ret = comedi_request_region(dev, it->options[0], RTI802_SIZE);
+ ret = comedi_request_region(dev, it->options[0], 0x04);
if (ret)
return ret;
@@ -100,22 +110,21 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
+ /* Analog Output subdevice */
s = &dev->subdevices[0];
- /* ao subdevice */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE;
- s->maxdata = 0xfff;
- s->n_chan = 8;
- s->insn_read = rti802_ao_insn_read;
- s->insn_write = rti802_ao_insn_write;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->maxdata = 0xfff;
+ s->n_chan = 8;
+ s->insn_read = rti802_ao_insn_read;
+ s->insn_write = rti802_ao_insn_write;
s->range_table_list = devpriv->range_type_list;
for (i = 0; i < 8; i++) {
devpriv->dac_coding[i] = (it->options[3 + 2 * i])
- ? (dac_straight)
- : (dac_2comp);
+ ? (dac_straight) : (dac_2comp);
devpriv->range_type_list[i] = (it->options[2 + 2 * i])
- ? &range_unipolar10 : &range_bipolar10;
+ ? &range_unipolar10 : &range_bipolar10;
}
return 0;
@@ -130,5 +139,5 @@ static struct comedi_driver rti802_driver = {
module_comedi_driver(rti802_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for Analog Devices RTI-802 board");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index 9950f59b1192..85d2b7a3c125 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -420,15 +420,28 @@ static int s526_ai_insn_config(struct comedi_device *dev,
return result;
}
+static int s526_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + REG_ISR);
+ if (status & ISR_ADC_DONE)
+ return 0;
+ return -EBUSY;
+}
+
static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct s526_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
- int n, i;
+ int n;
unsigned short value;
unsigned int d;
- unsigned int status;
+ int ret;
/* Set configured delay, enable channel for this channel only,
* select "ADC read" channel, set "ADC start" bit. */
@@ -440,17 +453,12 @@ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
/* trigger conversion */
outw(value, dev->iobase + REG_ADC);
-#define TIMEOUT 100
/* wait for conversion to end */
- for (i = 0; i < TIMEOUT; i++) {
- status = inw(dev->iobase + REG_ISR);
- if (status & ISR_ADC_DONE) {
- outw(ISR_ADC_DONE, dev->iobase + REG_ISR);
- break;
- }
- }
- if (i == TIMEOUT)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, s526_ai_eoc, 0);
+ if (ret)
+ return ret;
+
+ outw(ISR_ADC_DONE, dev->iobase + REG_ISR);
/* read data */
d = inw(dev->iobase + REG_ADD);
@@ -604,7 +612,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->insn_bits = s526_dio_insn_bits;
s->insn_config = s526_dio_insn_config;
- return 1;
+ return 0;
}
static struct comedi_driver s526_driver = {
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index 19da1dbea494..95fadf343f27 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -106,16 +106,16 @@ struct s626_private {
struct s626_enc_info {
/* Pointers to functions that differ for A and B counters: */
/* Return clock enable. */
- uint16_t(*get_enable)(struct comedi_device *dev,
+ uint16_t (*get_enable)(struct comedi_device *dev,
const struct s626_enc_info *k);
/* Return interrupt source. */
- uint16_t(*get_int_src)(struct comedi_device *dev,
+ uint16_t (*get_int_src)(struct comedi_device *dev,
const struct s626_enc_info *k);
/* Return preload trigger source. */
- uint16_t(*get_load_trig)(struct comedi_device *dev,
+ uint16_t (*get_load_trig)(struct comedi_device *dev,
const struct s626_enc_info *k);
/* Return standardized operating mode. */
- uint16_t(*get_mode)(struct comedi_device *dev,
+ uint16_t (*get_mode)(struct comedi_device *dev,
const struct s626_enc_info *k);
/* Generate soft index strobe. */
void (*pulse_index)(struct comedi_device *dev,
@@ -209,6 +209,8 @@ static const struct comedi_lrange s626_range_table = {
static void s626_debi_transfer(struct comedi_device *dev)
{
struct s626_private *devpriv = dev->private;
+ static const int timeout = 10000;
+ int i;
/* Initiate upload of shadow RAM to DEBI control register */
s626_mc_enable(dev, S626_MC2_UPLD_DEBI, S626_P_MC2);
@@ -217,12 +219,23 @@ static void s626_debi_transfer(struct comedi_device *dev)
* Wait for completion of upload from shadow RAM to
* DEBI control register.
*/
- while (!s626_mc_test(dev, S626_MC2_UPLD_DEBI, S626_P_MC2))
- ;
+ for (i = 0; i < timeout; i++) {
+ if (s626_mc_test(dev, S626_MC2_UPLD_DEBI, S626_P_MC2))
+ break;
+ udelay(1);
+ }
+ if (i == timeout)
+ comedi_error(dev,
+ "Timeout while uploading to DEBI control register.");
/* Wait until DEBI transfer is done */
- while (readl(devpriv->mmio + S626_P_PSR) & S626_PSR_DEBI_S)
- ;
+ for (i = 0; i < timeout; i++) {
+ if (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_DEBI_S))
+ break;
+ udelay(1);
+ }
+ if (i == timeout)
+ comedi_error(dev, "DEBI transfer timeout.");
}
/*
@@ -351,14 +364,57 @@ static const uint8_t s626_trimadrs[] = {
0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63
};
+enum {
+ s626_send_dac_wait_not_mc1_a2out,
+ s626_send_dac_wait_ssr_af2_out,
+ s626_send_dac_wait_fb_buffer2_msb_00,
+ s626_send_dac_wait_fb_buffer2_msb_ff
+};
+
+static int s626_send_dac_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct s626_private *devpriv = dev->private;
+ unsigned int status;
+
+ switch (context) {
+ case s626_send_dac_wait_not_mc1_a2out:
+ status = readl(devpriv->mmio + S626_P_MC1);
+ if (!(status & S626_MC1_A2OUT))
+ return 0;
+ break;
+ case s626_send_dac_wait_ssr_af2_out:
+ status = readl(devpriv->mmio + S626_P_SSR);
+ if (status & S626_SSR_AF2_OUT)
+ return 0;
+ break;
+ case s626_send_dac_wait_fb_buffer2_msb_00:
+ status = readl(devpriv->mmio + S626_P_FB_BUFFER2);
+ if (!(status & 0xff000000))
+ return 0;
+ break;
+ case s626_send_dac_wait_fb_buffer2_msb_ff:
+ status = readl(devpriv->mmio + S626_P_FB_BUFFER2);
+ if (status & 0xff000000)
+ return 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return -EBUSY;
+}
+
/*
* Private helper function: Transmit serial data to DAC via Audio
* channel 2. Assumes: (1) TSL2 slot records initialized, and (2)
* dacpol contains valid target image.
*/
-static void s626_send_dac(struct comedi_device *dev, uint32_t val)
+static int s626_send_dac(struct comedi_device *dev, uint32_t val)
{
struct s626_private *devpriv = dev->private;
+ int ret;
/* START THE SERIAL CLOCK RUNNING ------------- */
@@ -404,8 +460,12 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val)
* Done by polling the DMAC enable flag; this flag is automatically
* cleared when the transfer has finished.
*/
- while (readl(devpriv->mmio + S626_P_MC1) & S626_MC1_A2OUT)
- ;
+ ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc,
+ s626_send_dac_wait_not_mc1_a2out);
+ if (ret) {
+ comedi_error(dev, "DMA transfer timeout.");
+ return ret;
+ }
/* START THE OUTPUT STREAM TO THE TARGET DAC -------------------- */
@@ -425,8 +485,12 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val)
* finished transferring the DAC's data DWORD from the output FIFO
* to the output buffer register.
*/
- while (!(readl(devpriv->mmio + S626_P_SSR) & S626_SSR_AF2_OUT))
- ;
+ ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc,
+ s626_send_dac_wait_ssr_af2_out);
+ if (ret) {
+ comedi_error(dev, "TSL timeout waiting for slot 1 to execute.");
+ return ret;
+ }
/*
* Set up to trap execution at slot 0 when the TSL sequencer cycles
@@ -466,8 +530,13 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val)
* from 0xFF to 0x00, which slot 0 causes to happen by shifting
* out/in on SD2 the 0x00 that is always referenced by slot 5.
*/
- while (readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000)
- ;
+ ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc,
+ s626_send_dac_wait_fb_buffer2_msb_00);
+ if (ret) {
+ comedi_error(dev,
+ "TSL timeout waiting for slot 0 to execute.");
+ return ret;
+ }
}
/*
* Either (1) we were too late setting the slot 0 trap; the TSL
@@ -486,14 +555,19 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val)
* the next DAC write. This is detected when FB_BUFFER2 MSB changes
* from 0x00 to 0xFF.
*/
- while (!(readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000))
- ;
+ ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc,
+ s626_send_dac_wait_fb_buffer2_msb_ff);
+ if (ret) {
+ comedi_error(dev, "TSL timeout waiting for slot 0 to execute.");
+ return ret;
+ }
+ return 0;
}
/*
* Private helper function: Write setpoint to an application DAC channel.
*/
-static void s626_set_dac(struct comedi_device *dev, uint16_t chan,
+static int s626_set_dac(struct comedi_device *dev, uint16_t chan,
int16_t dacdata)
{
struct s626_private *devpriv = dev->private;
@@ -556,10 +630,10 @@ static void s626_set_dac(struct comedi_device *dev, uint16_t chan,
val |= ((uint32_t)(chan & 1) << 15); /* Address the DAC channel
* within the device. */
val |= (uint32_t)dacdata; /* Include DAC setpoint data. */
- s626_send_dac(dev, val);
+ return s626_send_dac(dev, val);
}
-static void s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan,
+static int s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan,
uint8_t dac_data)
{
struct s626_private *devpriv = dev->private;
@@ -606,17 +680,22 @@ static void s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan,
* Address the DAC channel within the trimdac device.
* Include DAC setpoint data.
*/
- s626_send_dac(dev, (chan << 8) | dac_data);
+ return s626_send_dac(dev, (chan << 8) | dac_data);
}
-static void s626_load_trim_dacs(struct comedi_device *dev)
+static int s626_load_trim_dacs(struct comedi_device *dev)
{
uint8_t i;
+ int ret;
/* Copy TrimDac setpoint values from EEPROM to TrimDacs. */
- for (i = 0; i < ARRAY_SIZE(s626_trimchan); i++)
- s626_write_trim_dac(dev, i,
+ for (i = 0; i < ARRAY_SIZE(s626_trimchan); i++) {
+ ret = s626_write_trim_dac(dev, i,
s626_i2c_read(dev, s626_trimadrs[i]));
+ if (ret)
+ return ret;
+ }
+ return 0;
}
/* ****** COUNTER FUNCTIONS ******* */
@@ -1846,6 +1925,20 @@ static int s626_ai_rinsn(struct comedi_device *dev,
}
#endif
+static int s626_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct s626_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readl(devpriv->mmio + S626_P_PSR);
+ if (status & S626_PSR_GPIO2)
+ return 0;
+ return -EBUSY;
+}
+
static int s626_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -1856,6 +1949,7 @@ static int s626_ai_insn_read(struct comedi_device *dev,
uint16_t adc_spec = 0;
uint32_t gpio_image;
uint32_t tmp;
+ int ret;
int n;
/*
@@ -1897,8 +1991,9 @@ static int s626_ai_insn_read(struct comedi_device *dev,
*/
/* Wait for ADC done */
- while (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_GPIO2))
- ;
+ ret = comedi_timeout(dev, s, insn, s626_ai_eoc, 0);
+ if (ret)
+ return ret;
/* Fetch ADC data */
if (n != 0) {
@@ -2299,6 +2394,7 @@ static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
{
struct s626_private *devpriv = dev->private;
int i;
+ int ret;
uint16_t chan = CR_CHAN(insn->chanspec);
int16_t dacdata;
@@ -2307,7 +2403,9 @@ static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[i];
dacdata -= (0x1fff);
- s626_set_dac(dev, chan, dacdata);
+ ret = s626_set_dac(dev, chan, dacdata);
+ if (ret)
+ return ret;
}
return i;
@@ -2543,12 +2641,13 @@ static int s626_allocate_dma_buffers(struct comedi_device *dev)
return 0;
}
-static void s626_initialize(struct comedi_device *dev)
+static int s626_initialize(struct comedi_device *dev)
{
struct s626_private *devpriv = dev->private;
dma_addr_t phys_buf;
uint16_t chan;
int i;
+ int ret;
/* Enable DEBI and audio pins, enable I2C interface */
s626_mc_enable(dev, S626_MC1_DEBI | S626_MC1_AUDIO | S626_MC1_I2C,
@@ -2749,7 +2848,9 @@ static void s626_initialize(struct comedi_device *dev)
* sometimes causes the first few TrimDAC writes to malfunction.
*/
s626_load_trim_dacs(dev);
- s626_load_trim_dacs(dev);
+ ret = s626_load_trim_dacs(dev);
+ if (ret)
+ return ret;
/*
* Manually init all gate array hardware in case this is a soft
@@ -2763,8 +2864,11 @@ static void s626_initialize(struct comedi_device *dev)
* Init all DAC outputs to 0V and init all DAC setpoint and
* polarity images.
*/
- for (chan = 0; chan < S626_DAC_CHANNELS; chan++)
- s626_set_dac(dev, chan, 0);
+ for (chan = 0; chan < S626_DAC_CHANNELS; chan++) {
+ ret = s626_set_dac(dev, chan, 0);
+ if (ret)
+ return ret;
+ }
/* Init counters */
s626_counters_init(dev);
@@ -2780,6 +2884,8 @@ static void s626_initialize(struct comedi_device *dev)
/* Initialize the digital I/O subsystem */
s626_dio_init(dev);
+
+ return 0;
}
static int s626_auto_attach(struct comedi_device *dev,
@@ -2900,9 +3006,9 @@ static int s626_auto_attach(struct comedi_device *dev,
s->insn_read = s626_enc_insn_read;
s->insn_write = s626_enc_insn_write;
- s626_initialize(dev);
-
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
+ ret = s626_initialize(dev);
+ if (ret)
+ return ret;
return 0;
}
diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c
index 77e2059ff62e..39008cf30ecb 100644
--- a/drivers/staging/comedi/drivers/skel.c
+++ b/drivers/staging/comedi/drivers/skel.c
@@ -142,6 +142,29 @@ static int skel_ns_to_timer(unsigned int *ns, int round)
}
/*
+ * This function doesn't require a particular form, this is just
+ * what happens to be used in some of the drivers. The comedi_timeout()
+ * helper uses this callback to check for the end-of-conversion while
+ * waiting for up to 1 second. This function should return 0 when the
+ * conversion is finished and -EBUSY to keep waiting. Any other errno
+ * will terminate comedi_timeout() and return that errno to the caller.
+ * If the timeout occurs, comedi_timeout() will return -ETIMEDOUT.
+ */
+static int skel_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ /* status = inb(dev->iobase + SKEL_STATUS); */
+ status = 1;
+ if (status)
+ return 0;
+ return -EBUSY;
+}
+
+/*
* "instructions" read/write data in "one-shot" or "software-triggered"
* mode.
*/
@@ -149,9 +172,9 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
const struct skel_board *thisboard = comedi_board(dev);
- int n, i;
+ int n;
unsigned int d;
- unsigned int status;
+ int ret;
/* a typical programming sequence */
@@ -165,18 +188,10 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
/* trigger conversion */
/* outw(0,dev->iobase + SKEL_CONVERT); */
-#define TIMEOUT 100
/* wait for conversion to end */
- for (i = 0; i < TIMEOUT; i++) {
- status = 1;
- /* status = inb(dev->iobase + SKEL_STATUS); */
- if (status)
- break;
- }
- if (i == TIMEOUT) {
- dev_warn(dev->class_dev, "ai timeout\n");
- return -ETIMEDOUT;
- }
+ ret = comedi_timeout(dev, s, insn, skel_ai_eoc, 0);
+ if (ret)
+ return ret;
/* read data */
/* d = inw(dev->iobase + SKEL_AI_DATA); */
@@ -456,8 +471,6 @@ static int skel_common_attach(struct comedi_device *dev)
s->type = COMEDI_SUBD_UNUSED;
}
- dev_info(dev->class_dev, "skel: attached\n");
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c
index df22a78d2b7e..848c30801580 100644
--- a/drivers/staging/comedi/drivers/ssv_dnp.c
+++ b/drivers/staging/comedi/drivers/ssv_dnp.c
@@ -161,8 +161,7 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
outb(PCMR, CSCIR);
outb((inb(CSCDR) & 0xAA), CSCDR);
- dev_info(dev->class_dev, "%s: attached\n", dev->board_name);
- return 1;
+ return 0;
}
static void dnp_detach(struct comedi_device *dev)
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index 5f85c55c1109..d6fae11ee4e0 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -372,7 +372,7 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_src(&cmd->start_src,
TRIG_NOW | TRIG_EXT | TRIG_INT);
err |= cfc_check_trigger_src(&cmd->scan_begin_src,
- TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
+ TRIG_FOLLOW | TRIG_EXT);
err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
@@ -424,9 +424,6 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, tmp);
}
- if (cmd->scan_begin_src == TRIG_TIMER)
- err |= -EINVAL;
-
/* stop source */
switch (cmd->stop_src) {
case TRIG_COUNT:
@@ -514,36 +511,28 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev,
*/
devpriv->ignore = PACKETS_TO_IGNORE;
- if (cmd->chanlist_len > 0) {
- gain = CR_RANGE(cmd->chanlist[0]);
- for (i = 0; i < cmd->chanlist_len; ++i) {
- chan = CR_CHAN(cmd->chanlist[i]);
- if (chan != i) {
- dev_err(dev->class_dev,
- "channels are not consecutive\n");
- up(&devpriv->sem);
- return -EINVAL;
- }
- if ((gain != CR_RANGE(cmd->chanlist[i]))
- && (cmd->chanlist_len > 3)) {
- dev_err(dev->class_dev,
- "gain must be the same for all channels\n");
- up(&devpriv->sem);
- return -EINVAL;
- }
- if (i >= NUMCHANNELS) {
- dev_err(dev->class_dev, "chanlist too long\n");
- break;
- }
+ gain = CR_RANGE(cmd->chanlist[0]);
+ for (i = 0; i < cmd->chanlist_len; ++i) {
+ chan = CR_CHAN(cmd->chanlist[i]);
+ if (chan != i) {
+ dev_err(dev->class_dev,
+ "channels are not consecutive\n");
+ up(&devpriv->sem);
+ return -EINVAL;
+ }
+ if ((gain != CR_RANGE(cmd->chanlist[i]))
+ && (cmd->chanlist_len > 3)) {
+ dev_err(dev->class_dev,
+ "gain must be the same for all channels\n");
+ up(&devpriv->sem);
+ return -EINVAL;
+ }
+ if (i >= NUMCHANNELS) {
+ dev_err(dev->class_dev, "chanlist too long\n");
+ break;
}
}
steps = 0;
- if (cmd->scan_begin_src == TRIG_TIMER) {
- dev_err(dev->class_dev,
- "scan_begin_src==TRIG_TIMER not valid\n");
- up(&devpriv->sem);
- return -EINVAL;
- }
if (cmd->convert_src == TRIG_TIMER)
steps = (cmd->convert_arg * 30) / 1000;
diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
index 7dc5a18e69d4..8777f958c041 100644
--- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
+++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
@@ -41,7 +41,8 @@ struct comedi_device *comedi_open(const char *filename)
if (strncmp(filename, "/dev/comedi", 11) != 0)
return NULL;
- minor = simple_strtoul(filename + 11, NULL, 0);
+ if (kstrtouint(filename + 11, 0, &minor))
+ return NULL;
if (minor >= COMEDI_NUM_BOARD_MINORS)
return NULL;
diff --git a/drivers/staging/comedi/proc.c b/drivers/staging/comedi/proc.c
index da6bc5855ebc..91dea25b5724 100644
--- a/drivers/staging/comedi/proc.c
+++ b/drivers/staging/comedi/proc.c
@@ -1,27 +1,26 @@
/*
- module/proc.c
- /proc interface for comedi
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1998 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * /proc interface for comedi
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1998 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
/*
- This is some serious bloatware.
-
- Taken from Dave A.'s PCL-711 driver, 'cuz I thought it
- was cool.
-*/
+ * This is some serious bloatware.
+ *
+ * Taken from Dave A.'s PCL-711 driver, 'cuz I thought it
+ * was cool.
+ */
#include "comedidev.h"
#include "comedi_internal.h"
@@ -34,11 +33,8 @@ static int comedi_read(struct seq_file *m, void *v)
int devices_q = 0;
struct comedi_driver *driv;
- seq_printf(m,
- "comedi version " COMEDI_RELEASE "\n"
- "format string: %s\n",
- "\"%2d: %-20s %-20s %4d\", i, "
- "driver_name, board_name, n_subdevices");
+ seq_printf(m, "comedi version " COMEDI_RELEASE "\nformat string: %s\n",
+ "\"%2d: %-20s %-20s %4d\", i, driver_name, board_name, n_subdevices");
for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
struct comedi_device *dev = comedi_dev_get_from_minor(i);
diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c
index 46b3da686384..b6849545b810 100644
--- a/drivers/staging/comedi/range.c
+++ b/drivers/staging/comedi/range.c
@@ -143,28 +143,23 @@ int comedi_check_chanlist(struct comedi_subdevice *s, int n,
unsigned int chanspec;
int chan, range_len, i;
- if (s->range_table || s->range_table_list) {
- for (i = 0; i < n; i++) {
- chanspec = chanlist[i];
- chan = CR_CHAN(chanspec);
- if (s->range_table)
- range_len = s->range_table->length;
- else if (s->range_table_list && chan < s->n_chan)
- range_len = s->range_table_list[chan]->length;
- else
- range_len = 0;
- if (chan >= s->n_chan ||
- CR_RANGE(chanspec) >= range_len ||
- aref_invalid(s, chanspec)) {
- dev_warn(dev->class_dev,
- "bad chanlist[%d]=0x%08x chan=%d range length=%d\n",
- i, chanspec, chan, range_len);
- return -EINVAL;
- }
+ for (i = 0; i < n; i++) {
+ chanspec = chanlist[i];
+ chan = CR_CHAN(chanspec);
+ if (s->range_table)
+ range_len = s->range_table->length;
+ else if (s->range_table_list && chan < s->n_chan)
+ range_len = s->range_table_list[chan]->length;
+ else
+ range_len = 0;
+ if (chan >= s->n_chan ||
+ CR_RANGE(chanspec) >= range_len ||
+ aref_invalid(s, chanspec)) {
+ dev_warn(dev->class_dev,
+ "bad chanlist[%d]=0x%08x chan=%d range length=%d\n",
+ i, chanspec, chan, range_len);
+ return -EINVAL;
}
- } else {
- dev_err(dev->class_dev, "(bug) no range type list!\n");
- return -EINVAL;
}
return 0;
}
diff --git a/drivers/staging/crystalhd/bcm_70012_regs.h b/drivers/staging/crystalhd/bcm_70012_regs.h
index f3ab3146cd90..da199ad8e27e 100644
--- a/drivers/staging/crystalhd/bcm_70012_regs.h
+++ b/drivers/staging/crystalhd/bcm_70012_regs.h
@@ -31,7 +31,8 @@
#define BRCM_SHIFT(c, r, f) c##_##r##_##f##_SHIFT
#define GET_FIELD(m, c, r, f) \
- ((((m) & BRCM_MASK(c, r, f)) >> BRCM_SHIFT(c, r, f)) << BRCM_ALIGN(c, r, f))
+ ((((m) & BRCM_MASK(c, r, f)) >> BRCM_SHIFT(c, r, f)) << \
+ BRCM_ALIGN(c, r, f))
#define SET_FIELD(m, c, r, f, d) \
((m) = (((m) & ~BRCM_MASK(c, r, f)) | ((((d) >> BRCM_ALIGN(c, r, f)) << \
diff --git a/drivers/staging/crystalhd/crystalhd_hw.c b/drivers/staging/crystalhd/crystalhd_hw.c
index 8d0680d93684..4765d528279b 100644
--- a/drivers/staging/crystalhd/crystalhd_hw.c
+++ b/drivers/staging/crystalhd/crystalhd_hw.c
@@ -433,10 +433,12 @@ static void crystalhd_rx_pkt_rel_call_back(void *context, void *data)
}
#define crystalhd_hw_delete_ioq(adp, q) \
+do { \
if (q) { \
crystalhd_delete_dioq(adp, q); \
q = NULL; \
- }
+ } \
+} while (0)
static void crystalhd_hw_delete_ioqs(struct crystalhd_hw *hw)
{
@@ -1437,7 +1439,7 @@ static bool crystalhd_rx_list0_handler(struct crystalhd_hw *hw,
crystalhd_reg_wr(hw->adp, MISC1_UV_RX_ERROR_STATUS, tmp);
}
- return (tmp_lsts != hw->rx_list_sts[0]);
+ return tmp_lsts != hw->rx_list_sts[0];
}
static bool crystalhd_rx_list1_handler(struct crystalhd_hw *hw,
@@ -1507,7 +1509,7 @@ static bool crystalhd_rx_list1_handler(struct crystalhd_hw *hw,
crystalhd_reg_wr(hw->adp, MISC1_UV_RX_ERROR_STATUS, tmp);
}
- return (tmp_lsts != hw->rx_list_sts[1]);
+ return tmp_lsts != hw->rx_list_sts[1];
}
diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c
index 99eefd0291c3..20be9571990a 100644
--- a/drivers/staging/crystalhd/crystalhd_lnx.c
+++ b/drivers/staging/crystalhd/crystalhd_lnx.c
@@ -111,7 +111,7 @@ static void chd_dec_free_iodata(struct crystalhd_adp *adp,
spin_unlock_irqrestore(&adp->lock, flags);
}
-static inline int crystalhd_user_data(unsigned long ud, void *dr,
+static inline int crystalhd_user_data(void __user *ud, void *dr,
int size, int set)
{
int rc;
@@ -122,9 +122,9 @@ static inline int crystalhd_user_data(unsigned long ud, void *dr,
}
if (set)
- rc = copy_to_user((void *)ud, dr, size);
+ rc = copy_to_user(ud, dr, size);
else
- rc = copy_from_user(dr, (void *)ud, size);
+ rc = copy_from_user(dr, ud, size);
if (rc) {
BCMLOG_ERR("Invalid args for command\n");
@@ -153,7 +153,8 @@ static int chd_dec_fetch_cdata(struct crystalhd_adp *adp,
io->add_cdata_sz = m_sz;
ua_off = ua + sizeof(io->udata);
- rc = crystalhd_user_data(ua_off, io->add_cdata, io->add_cdata_sz, 0);
+ rc = crystalhd_user_data((void __user *)ua_off, io->add_cdata,
+ io->add_cdata_sz, 0);
if (rc) {
BCMLOG_ERR("failed to pull add_cdata sz:%x ua_off:%x\n",
io->add_cdata_sz, (unsigned int)ua_off);
@@ -178,7 +179,7 @@ static int chd_dec_release_cdata(struct crystalhd_adp *adp,
if (io->cmd != BCM_IOC_FW_DOWNLOAD) {
ua_off = ua + sizeof(io->udata);
- rc = crystalhd_user_data(ua_off, io->add_cdata,
+ rc = crystalhd_user_data((void __user *)ua_off, io->add_cdata,
io->add_cdata_sz, 1);
if (rc) {
BCMLOG_ERR(
@@ -208,7 +209,8 @@ static int chd_dec_proc_user_data(struct crystalhd_adp *adp,
return -EINVAL;
}
- rc = crystalhd_user_data(ua, &io->udata, sizeof(io->udata), set);
+ rc = crystalhd_user_data((void __user *)ua, &io->udata,
+ sizeof(io->udata), set);
if (rc) {
BCMLOG_ERR("failed to %s iodata\n", (set ? "set" : "get"));
return rc;
@@ -546,9 +548,10 @@ static int chd_dec_pci_probe(struct pci_dev *pdev,
int rc;
enum BC_STATUS sts = BC_STS_SUCCESS;
- BCMLOG(BCMLOG_DBG, "PCI_INFO: Vendor:0x%04x Device:0x%04x s_vendor:0x%04x s_device: 0x%04x\n",
- pdev->vendor, pdev->device, pdev->subsystem_vendor,
- pdev->subsystem_device);
+ BCMLOG(BCMLOG_DBG,
+ "PCI_INFO: Vendor:0x%04x Device:0x%04x s_vendor:0x%04x s_device: 0x%04x\n",
+ pdev->vendor, pdev->device, pdev->subsystem_vendor,
+ pdev->subsystem_device);
pinfo = kzalloc(sizeof(struct crystalhd_adp), GFP_KERNEL);
if (!pinfo) {
diff --git a/drivers/staging/crystalhd/crystalhd_lnx.h b/drivers/staging/crystalhd/crystalhd_lnx.h
index 816e1cd5db62..49e1ef3a19af 100644
--- a/drivers/staging/crystalhd/crystalhd_lnx.h
+++ b/drivers/staging/crystalhd/crystalhd_lnx.h
@@ -58,11 +58,11 @@ struct crystalhd_adp {
unsigned long pci_mem_start;
uint32_t pci_mem_len;
- void *addr;
+ void __iomem *addr;
unsigned long pci_i2o_start;
uint32_t pci_i2o_len;
- void *i2o_addr;
+ void __iomem *i2o_addr;
unsigned int drv_data;
unsigned int dmabits; /* 32 | 64 */
diff --git a/drivers/staging/crystalhd/crystalhd_misc.c b/drivers/staging/crystalhd/crystalhd_misc.c
index c3d024406337..3aabf75b7d97 100644
--- a/drivers/staging/crystalhd/crystalhd_misc.c
+++ b/drivers/staging/crystalhd/crystalhd_misc.c
@@ -740,7 +740,7 @@ enum BC_STATUS crystalhd_map_dio(struct crystalhd_adp *adp, void *ubuff,
dio->fb_size = ubuff_sz & 0x03;
if (dio->fb_size) {
res = copy_from_user(dio->fb_va,
- (void *)(uaddr + count - dio->fb_size),
+ (void __user *)(uaddr + count - dio->fb_size),
dio->fb_size);
if (res) {
BCMLOG_ERR("failed %d to copy %u fill bytes from %p\n",
diff --git a/drivers/staging/crystalhd/crystalhd_misc.h b/drivers/staging/crystalhd/crystalhd_misc.h
index 77ab72a2a061..0f63827acfb4 100644
--- a/drivers/staging/crystalhd/crystalhd_misc.h
+++ b/drivers/staging/crystalhd/crystalhd_misc.h
@@ -225,7 +225,7 @@ do { \
#define BCMLOG_ERR(fmt, args...) \
do { \
if (g_linklog_level & BCMLOG_ERROR) \
- printk(KERN_ERR "*ERR*:%s:%d: "fmt, \
+ pr_err("*ERR*:%s:%d: "fmt, \
__FILE__, __LINE__, ##args); \
} while (0)
diff --git a/drivers/staging/cxt1e1/Makefile b/drivers/staging/cxt1e1/Makefile
index 2f217e9daac1..b879e7b553c2 100644
--- a/drivers/staging/cxt1e1/Makefile
+++ b/drivers/staging/cxt1e1/Makefile
@@ -4,7 +4,6 @@ ccflags-y := -DSBE_PMCC4_ENABLE
ccflags-y += -DSBE_ISR_TASKLET
cxt1e1-y := \
- ossiRelease.o \
musycc.o \
pmcc4_drv.o \
comet.o \
diff --git a/drivers/staging/cxt1e1/comet.c b/drivers/staging/cxt1e1/comet.c
index c4c8c0f9c959..7005ad022339 100644
--- a/drivers/staging/cxt1e1/comet.c
+++ b/drivers/staging/cxt1e1/comet.c
@@ -22,18 +22,20 @@
#include "comet.h"
#include "comet_tables.h"
-extern int cxt1e1_log_level;
#define COMET_NUM_SAMPLES 24 /* Number of entries in the waveform table */
#define COMET_NUM_UNITS 5 /* Number of points per entry in table */
/* forward references */
static void SetPwrLevel(struct s_comet_reg *comet);
-static void WrtRcvEqualizerTbl(ci_t *ci, struct s_comet_reg *comet, u_int32_t *table);
-static void WrtXmtWaveformTbl(ci_t *ci, struct s_comet_reg *comet, u_int8_t table[COMET_NUM_SAMPLES][COMET_NUM_UNITS]);
+static void WrtRcvEqualizerTbl(ci_t *ci, struct s_comet_reg *comet,
+ u_int32_t *table);
+static void WrtXmtWaveformTbl(ci_t *ci, struct s_comet_reg *comet,
+ u_int8_t table[COMET_NUM_SAMPLES]
+ [COMET_NUM_UNITS]);
-void *TWV_table[12] = {
+static void *TWV_table[12] = {
TWVLongHaul0DB, TWVLongHaul7_5DB, TWVLongHaul15DB, TWVLongHaul22_5DB,
TWVShortHaul0, TWVShortHaul1, TWVShortHaul2, TWVShortHaul3,
TWVShortHaul4, TWVShortHaul5,
@@ -50,6 +52,7 @@ lbo_tbl_lkup(int t1, int lbo) {
if (t1)
/* default T1 waveform table */
lbo = CFG_LBO_LH0;
+
else
/* default E1 waveform table */
lbo = CFG_LBO_E120;
@@ -58,8 +61,8 @@ lbo_tbl_lkup(int t1, int lbo) {
return lbo - 1;
}
-void init_comet(void *ci, struct s_comet_reg *comet, u_int32_t port_mode, int clockmaster,
- u_int8_t moreParams)
+void init_comet(void *ci, struct s_comet_reg *comet, u_int32_t port_mode,
+ int clockmaster, u_int8_t moreParams)
{
u_int8_t isT1mode;
/* T1 default */
@@ -146,7 +149,9 @@ void init_comet(void *ci, struct s_comet_reg *comet, u_int32_t port_mode, int cl
/* t1RBOC enable(BOC:BitOriented Code) */
pci_write_32((u_int32_t *) &comet->t1_rboc_ena, 0x00);
if (isT1mode) {
- /* IBCD cfg: aka Inband Code Detection ** loopback code length set to */
+ /* IBCD cfg: aka Inband Code Detection ** loopback code length
+ * set to
+ */
/* 6 bit down, 5 bit up (assert) */
pci_write_32((u_int32_t *) &comet->ibcd_cfg, 0x04);
/* line loopback activate pattern */
@@ -286,7 +291,9 @@ void init_comet(void *ci, struct s_comet_reg *comet, u_int32_t port_mode, int cl
/* 0x30: "BRIF cfg"; 0x20 is 'CMODE', 0x03 is (bit) rate */
/* note "rate bits can only be set once after reset" */
if (clockmaster) {
- /* CMODE == clockMode, 0=clock master (so all 3 others should be slave) */
+ /* CMODE == clockMode, 0=clock master
+ * (so all 3 others should be slave)
+ */
/* rate = 1.544 Mb/s */
if (isT1mode)
/* Comet 0 Master Mode(CMODE=0) */
@@ -398,7 +405,8 @@ void init_comet(void *ci, struct s_comet_reg *comet, u_int32_t port_mode, int cl
** Returns: Nothing
*/
static void
-WrtXmtWaveform(ci_t *ci, struct s_comet_reg *comet, u_int32_t sample, u_int32_t unit, u_int8_t data)
+WrtXmtWaveform(ci_t *ci, struct s_comet_reg *comet, u_int32_t sample,
+ u_int32_t unit, u_int8_t data)
{
u_int8_t WaveformAddr;
@@ -447,7 +455,7 @@ static void
WrtRcvEqualizerTbl(ci_t *ci, struct s_comet_reg *comet, u_int32_t *table)
{
u_int32_t ramaddr;
- volatile u_int32_t value;
+ u_int32_t value;
for (ramaddr = 0; ramaddr < 256; ramaddr++) {
/*** the following lines are per Errata 7, 2.5 ***/
@@ -515,7 +523,7 @@ WrtRcvEqualizerTbl(ci_t *ci, struct s_comet_reg *comet, u_int32_t *table)
static void
SetPwrLevel(struct s_comet_reg *comet)
{
- volatile u_int32_t temp;
+ u_int32_t temp;
/*
** Algorithm to Balance the Power Distribution of Ttip Tring
@@ -557,17 +565,21 @@ SetPwrLevel(struct s_comet_reg *comet)
static void
SetCometOps(struct s_comet_reg *comet)
{
- volatile u_int8_t rd_value;
+ u_int8_t rd_value;
if (comet == mConfig.C4Func1Base + (COMET0_OFFSET >> 2)) {
/* read the BRIF Configuration */
- rd_value = (u_int8_t) pci_read_32((u_int32_t *) &comet->brif_cfg);
+ rd_value = (u_int8_t) pci_read_32((u_int32_t *)
+ &comet->brif_cfg);
rd_value &= ~0x20;
- pci_write_32((u_int32_t *) &comet->brif_cfg, (u_int32_t) rd_value);
+ pci_write_32((u_int32_t *) &comet->brif_cfg,
+ (u_int32_t) rd_value);
/* read the BRIF Frame Pulse Configuration */
- rd_value = (u_int8_t) pci_read_32((u_int32_t *) &comet->brif_fpcfg);
+ rd_value = (u_int8_t) pci_read_32((u_int32_t *)
+ &comet->brif_fpcfg);
rd_value &= ~0x20;
- pci_write_32((u_int32_t *) &comet->brif_fpcfg, (u_int8_t) rd_value);
+ pci_write_32((u_int32_t *) &comet->brif_fpcfg,
+ (u_int8_t) rd_value);
} else {
/* read the BRIF Configuration */
rd_value = (u_int8_t) pci_read_32((u_int32_t *) &comet->brif_cfg);
diff --git a/drivers/staging/cxt1e1/comet_tables.c b/drivers/staging/cxt1e1/comet_tables.c
index 84931117da35..e96665ea3662 100644
--- a/drivers/staging/cxt1e1/comet_tables.c
+++ b/drivers/staging/cxt1e1/comet_tables.c
@@ -19,6 +19,7 @@
*/
#include <linux/types.h>
+#include "comet_tables.h"
/*****************************************************************************
*
diff --git a/drivers/staging/cxt1e1/functions.c b/drivers/staging/cxt1e1/functions.c
index 95218e283966..ee9d39bbd251 100644
--- a/drivers/staging/cxt1e1/functions.c
+++ b/drivers/staging/cxt1e1/functions.c
@@ -25,7 +25,8 @@
#include "pmcc4.h"
#if defined(CONFIG_SBE_HDLC_V7) || defined(CONFIG_SBE_WAN256T3_HDLC_V7) || \
- defined(CONFIG_SBE_HDLC_V7_MODULE) || defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE)
+defined(CONFIG_SBE_HDLC_V7_MODULE) || \
+defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE)
#define _v7_hdlc_ 1
#else
#define _v7_hdlc_ 0
@@ -33,9 +34,9 @@
#if _v7_hdlc_
#define V7(x) (x ## _v7)
-extern int hdlc_netif_rx_v7 (hdlc_device *, struct sk_buff *);
-extern int register_hdlc_device_v7 (hdlc_device *);
-extern int unregister_hdlc_device_v7 (hdlc_device *);
+extern int hdlc_netif_rx_v7(hdlc_device *, struct sk_buff *);
+extern int register_hdlc_device_v7(hdlc_device *);
+extern int unregister_hdlc_device_v7(hdlc_device *);
#else
#define V7(x) x
@@ -47,55 +48,54 @@ static int dummy = 0;
#endif
-extern int cxt1e1_log_level;
extern int drvr_state;
#if 1
u_int32_t
-pci_read_32 (u_int32_t *p)
+pci_read_32(u_int32_t *p)
{
#ifdef FLOW_DEBUG
- u_int32_t v;
+ u_int32_t v;
- FLUSH_PCI_READ ();
- v = le32_to_cpu (*p);
- if (cxt1e1_log_level >= LOG_DEBUG)
- pr_info("pci_read : %x = %x\n", (u_int32_t) p, v);
- return v;
+ FLUSH_PCI_READ();
+ v = le32_to_cpu(*p);
+ if (cxt1e1_log_level >= LOG_DEBUG)
+ pr_info("pci_read : %x = %x\n", (u_int32_t) p, v);
+ return v;
#else
- FLUSH_PCI_READ (); /* */
- return le32_to_cpu (*p);
+ FLUSH_PCI_READ(); /* */
+ return le32_to_cpu(*p);
#endif
}
void
-pci_write_32 (u_int32_t *p, u_int32_t v)
+pci_write_32(u_int32_t *p, u_int32_t v)
{
#ifdef FLOW_DEBUG
- if (cxt1e1_log_level >= LOG_DEBUG)
- pr_info("pci_write: %x = %x\n", (u_int32_t) p, v);
+ if (cxt1e1_log_level >= LOG_DEBUG)
+ pr_info("pci_write: %x = %x\n", (u_int32_t) p, v);
#endif
- *p = cpu_to_le32 (v);
- FLUSH_PCI_WRITE (); /* This routine is called from routines
- * which do multiple register writes
- * which themselves need flushing between
- * writes in order to guarantee write
- * ordering. It is less code-cumbersome
- * to flush here-in then to investigate
- * and code the many other register
- * writing routines. */
+ *p = cpu_to_le32 (v);
+ FLUSH_PCI_WRITE(); /* This routine is called from routines
+ * which do multiple register writes
+ * which themselves need flushing between
+ * writes in order to guarantee write
+ * ordering. It is less code-cumbersome
+ * to flush here-in then to investigate
+ * and code the many other register
+ * writing routines. */
}
#endif
void
-pci_flush_write (ci_t *ci)
+pci_flush_write(ci_t *ci)
{
- volatile u_int32_t v;
+ volatile u_int32_t v;
/* issue a PCI read to flush PCI write thru bridge */
- v = *(u_int32_t *) &ci->reg->glcd; /* any address would do */
+ v = *(u_int32_t *) &ci->reg->glcd; /* any address would do */
/*
* return nothing, this just reads PCI bridge interface to flush
@@ -105,55 +105,53 @@ pci_flush_write (ci_t *ci)
static void
-watchdog_func (unsigned long arg)
+watchdog_func(unsigned long arg)
{
- struct watchdog *wd = (void *) arg;
-
- if (drvr_state != SBE_DRVR_AVAILABLE)
- {
- if (cxt1e1_log_level >= LOG_MONITOR)
- pr_warning("%s: drvr not available (%x)\n", __func__, drvr_state);
- return;
- }
- schedule_work (&wd->work);
- mod_timer (&wd->h, jiffies + wd->ticks);
+ struct watchdog *wd = (void *) arg;
+
+ if (drvr_state != SBE_DRVR_AVAILABLE) {
+ if (cxt1e1_log_level >= LOG_MONITOR)
+ pr_warning("%s: drvr not available (%x)\n",
+ __func__, drvr_state);
+ return;
+ }
+ schedule_work(&wd->work);
+ mod_timer(&wd->h, jiffies + wd->ticks);
}
-int OS_init_watchdog(struct watchdog *wdp, void (*f) (void *), void *c, int usec)
+int OS_init_watchdog(struct watchdog *wdp, void (*f) (void *),
+ void *c, int usec)
{
- wdp->func = f;
- wdp->softc = c;
- wdp->ticks = (HZ) * (usec / 1000) / 1000;
- INIT_WORK(&wdp->work, (void *)f);
- init_timer (&wdp->h);
- {
- ci_t *ci = (ci_t *) c;
-
- wdp->h.data = (unsigned long) &ci->wd;
- }
- wdp->h.function = watchdog_func;
- return 0;
+ wdp->func = f;
+ wdp->softc = c;
+ wdp->ticks = (HZ) * (usec / 1000) / 1000;
+ INIT_WORK(&wdp->work, (void *)f);
+ init_timer(&wdp->h);
+ {
+ ci_t *ci = (ci_t *) c;
+
+ wdp->h.data = (unsigned long) &ci->wd;
+ }
+ wdp->h.function = watchdog_func;
+ return 0;
}
void
-OS_uwait (int usec, char *description)
+OS_uwait(int usec, char *description)
{
- int tmp;
-
- if (usec >= 1000)
- {
- mdelay (usec / 1000);
- /* now delay residual */
- tmp = (usec / 1000) * 1000; /* round */
- tmp = usec - tmp; /* residual */
- if (tmp)
- { /* wait on residual */
- udelay (tmp);
- }
- } else
- {
- udelay (usec);
- }
+ int tmp;
+
+ if (usec >= 1000) {
+ mdelay(usec / 1000);
+ /* now delay residual */
+ tmp = (usec / 1000) * 1000; /* round */
+ tmp = usec - tmp; /* residual */
+ if (tmp) { /* wait on residual */
+ udelay(tmp);
+ }
+ } else {
+ udelay(usec);
+ }
}
/* dummy short delay routine called as a subroutine so that compiler
@@ -161,96 +159,95 @@ OS_uwait (int usec, char *description)
*/
void
-OS_uwait_dummy (void)
+OS_uwait_dummy(void)
{
#ifndef USE_MAX_INT_DELAY
- dummy++;
+ dummy++;
#else
- udelay (1);
+ udelay(1);
#endif
}
void
-OS_sem_init (void *sem, int state)
+OS_sem_init(void *sem, int state)
{
- switch (state)
- {
- case SEM_TAKEN:
- sema_init((struct semaphore *) sem, 0);
- break;
- case SEM_AVAILABLE:
+ switch (state) {
+ case SEM_TAKEN:
+ sema_init((struct semaphore *) sem, 0);
+ break;
+ case SEM_AVAILABLE:
sema_init((struct semaphore *) sem, 1);
- break;
- default: /* otherwise, set sem.count to state's
- * value */
- sema_init (sem, state);
- break;
- }
+ break;
+ default: /* otherwise, set sem.count to state's
+ * value */
+ sema_init(sem, state);
+ break;
+ }
}
int
-sd_line_is_ok (void *user)
+sd_line_is_ok(void *user)
{
- struct net_device *ndev = (struct net_device *) user;
+ struct net_device *ndev = (struct net_device *) user;
- return netif_carrier_ok (ndev);
+ return netif_carrier_ok(ndev);
}
void
-sd_line_is_up (void *user)
+sd_line_is_up(void *user)
{
- struct net_device *ndev = (struct net_device *) user;
+ struct net_device *ndev = (struct net_device *) user;
- netif_carrier_on (ndev);
- return;
+ netif_carrier_on(ndev);
+ return;
}
void
-sd_line_is_down (void *user)
+sd_line_is_down(void *user)
{
- struct net_device *ndev = (struct net_device *) user;
+ struct net_device *ndev = (struct net_device *) user;
- netif_carrier_off (ndev);
- return;
+ netif_carrier_off(ndev);
+ return;
}
void
-sd_disable_xmit (void *user)
+sd_disable_xmit(void *user)
{
- struct net_device *dev = (struct net_device *) user;
+ struct net_device *dev = (struct net_device *) user;
- netif_stop_queue (dev);
- return;
+ netif_stop_queue(dev);
+ return;
}
void
-sd_enable_xmit (void *user)
+sd_enable_xmit(void *user)
{
- struct net_device *dev = (struct net_device *) user;
+ struct net_device *dev = (struct net_device *) user;
- netif_wake_queue (dev);
- return;
+ netif_wake_queue(dev);
+ return;
}
int
-sd_queue_stopped (void *user)
+sd_queue_stopped(void *user)
{
- struct net_device *ndev = (struct net_device *) user;
+ struct net_device *ndev = (struct net_device *) user;
- return netif_queue_stopped (ndev);
+ return netif_queue_stopped(ndev);
}
void sd_recv_consume(void *token, size_t len, void *user)
{
- struct net_device *ndev = user;
- struct sk_buff *skb = token;
+ struct net_device *ndev = user;
+ struct sk_buff *skb = token;
- skb->dev = ndev;
- skb_put (skb, len);
- skb->protocol = hdlc_type_trans(skb, ndev);
- netif_rx(skb);
+ skb->dev = ndev;
+ skb_put(skb, len);
+ skb->protocol = hdlc_type_trans(skb, ndev);
+ netif_rx(skb);
}
@@ -263,86 +260,76 @@ void sd_recv_consume(void *token, size_t len, void *user)
extern ci_t *CI; /* dummy pointer to board ZERO's data */
void
-VMETRO_TRACE (void *x)
+VMETRO_TRIGGER(ci_t *ci, int x)
{
- u_int32_t y = (u_int32_t) x;
-
- pci_write_32 ((u_int32_t *) &CI->cpldbase->leds, y);
-}
-
-
-void
-VMETRO_TRIGGER (ci_t *ci, int x)
-{
- struct s_comet_reg *comet;
- volatile u_int32_t data;
-
- comet = ci->port[0].cometbase; /* default to COMET # 0 */
-
- switch (x)
- {
- default:
- case 0:
- data = pci_read_32 ((u_int32_t *) &comet->__res24); /* 0x90 */
- break;
- case 1:
- data = pci_read_32 ((u_int32_t *) &comet->__res25); /* 0x94 */
- break;
- case 2:
- data = pci_read_32 ((u_int32_t *) &comet->__res26); /* 0x98 */
- break;
- case 3:
- data = pci_read_32 ((u_int32_t *) &comet->__res27); /* 0x9C */
- break;
- case 4:
- data = pci_read_32 ((u_int32_t *) &comet->__res88); /* 0x220 */
- break;
- case 5:
- data = pci_read_32 ((u_int32_t *) &comet->__res89); /* 0x224 */
- break;
- case 6:
- data = pci_read_32 ((u_int32_t *) &comet->__res8A); /* 0x228 */
- break;
- case 7:
- data = pci_read_32 ((u_int32_t *) &comet->__res8B); /* 0x22C */
- break;
- case 8:
- data = pci_read_32 ((u_int32_t *) &comet->__resA0); /* 0x280 */
- break;
- case 9:
- data = pci_read_32 ((u_int32_t *) &comet->__resA1); /* 0x284 */
- break;
- case 10:
- data = pci_read_32 ((u_int32_t *) &comet->__resA2); /* 0x288 */
- break;
- case 11:
- data = pci_read_32 ((u_int32_t *) &comet->__resA3); /* 0x28C */
- break;
- case 12:
- data = pci_read_32 ((u_int32_t *) &comet->__resA4); /* 0x290 */
- break;
- case 13:
- data = pci_read_32 ((u_int32_t *) &comet->__resA5); /* 0x294 */
- break;
- case 14:
- data = pci_read_32 ((u_int32_t *) &comet->__resA6); /* 0x298 */
- break;
- case 15:
- data = pci_read_32 ((u_int32_t *) &comet->__resA7); /* 0x29C */
- break;
- case 16:
- data = pci_read_32 ((u_int32_t *) &comet->__res74); /* 0x1D0 */
- break;
- case 17:
- data = pci_read_32 ((u_int32_t *) &comet->__res75); /* 0x1D4 */
- break;
- case 18:
- data = pci_read_32 ((u_int32_t *) &comet->__res76); /* 0x1D8 */
- break;
- case 19:
- data = pci_read_32 ((u_int32_t *) &comet->__res77); /* 0x1DC */
- break;
- }
+ struct s_comet_reg *comet;
+ volatile u_int32_t data;
+
+ comet = ci->port[0].cometbase; /* default to COMET # 0 */
+
+ switch (x) {
+ default:
+ case 0:
+ data = pci_read_32((u_int32_t *) &comet->__res24); /* 0x90 */
+ break;
+ case 1:
+ data = pci_read_32((u_int32_t *) &comet->__res25); /* 0x94 */
+ break;
+ case 2:
+ data = pci_read_32((u_int32_t *) &comet->__res26); /* 0x98 */
+ break;
+ case 3:
+ data = pci_read_32((u_int32_t *) &comet->__res27); /* 0x9C */
+ break;
+ case 4:
+ data = pci_read_32((u_int32_t *) &comet->__res88); /* 0x220 */
+ break;
+ case 5:
+ data = pci_read_32((u_int32_t *) &comet->__res89); /* 0x224 */
+ break;
+ case 6:
+ data = pci_read_32((u_int32_t *) &comet->__res8A); /* 0x228 */
+ break;
+ case 7:
+ data = pci_read_32((u_int32_t *) &comet->__res8B); /* 0x22C */
+ break;
+ case 8:
+ data = pci_read_32((u_int32_t *) &comet->__resA0); /* 0x280 */
+ break;
+ case 9:
+ data = pci_read_32((u_int32_t *) &comet->__resA1); /* 0x284 */
+ break;
+ case 10:
+ data = pci_read_32((u_int32_t *) &comet->__resA2); /* 0x288 */
+ break;
+ case 11:
+ data = pci_read_32((u_int32_t *) &comet->__resA3); /* 0x28C */
+ break;
+ case 12:
+ data = pci_read_32((u_int32_t *) &comet->__resA4); /* 0x290 */
+ break;
+ case 13:
+ data = pci_read_32((u_int32_t *) &comet->__resA5); /* 0x294 */
+ break;
+ case 14:
+ data = pci_read_32((u_int32_t *) &comet->__resA6); /* 0x298 */
+ break;
+ case 15:
+ data = pci_read_32((u_int32_t *) &comet->__resA7); /* 0x29C */
+ break;
+ case 16:
+ data = pci_read_32((u_int32_t *) &comet->__res74); /* 0x1D0 */
+ break;
+ case 17:
+ data = pci_read_32((u_int32_t *) &comet->__res75); /* 0x1D4 */
+ break;
+ case 18:
+ data = pci_read_32((u_int32_t *) &comet->__res76); /* 0x1D8 */
+ break;
+ case 19:
+ data = pci_read_32((u_int32_t *) &comet->__res77); /* 0x1DC */
+ break;
+ }
}
diff --git a/drivers/staging/cxt1e1/hwprobe.c b/drivers/staging/cxt1e1/hwprobe.c
index 02b4f8f1aca5..9b4198b1e634 100644
--- a/drivers/staging/cxt1e1/hwprobe.c
+++ b/drivers/staging/cxt1e1/hwprobe.c
@@ -31,360 +31,352 @@
#include "sbeproc.h"
#endif
-extern int cxt1e1_log_level;
extern int error_flag;
extern int drvr_state;
/* forward references */
-void c4_stopwd (ci_t *);
-struct net_device * __init c4_add_dev (hdw_info_t *, int, unsigned long, unsigned long, int, int);
+void c4_stopwd(ci_t *);
+struct net_device * __init c4_add_dev(hdw_info_t *, int, unsigned long,
+ unsigned long, int, int);
struct s_hdw_info hdw_info[MAX_BOARDS];
-void __init
-show_two (hdw_info_t *hi, int brdno)
+void __init
+show_two(hdw_info_t *hi, int brdno)
{
- ci_t *ci;
- struct pci_dev *pdev;
- char *bid;
- char *bp, banner[80];
- char sn[6];
-
- bp = banner;
- memset (banner, 0, 80); /* clear print buffer */
-
- ci = (ci_t *)(netdev_priv(hi->ndev));
- bid = sbeid_get_bdname (ci);
- switch (hi->promfmt)
- {
- case PROM_FORMAT_TYPE1:
- memcpy (sn, (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6);
- break;
- case PROM_FORMAT_TYPE2:
- memcpy (sn, (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6);
- break;
- default:
- memset (sn, 0, 6);
- break;
- }
-
- sprintf (banner, "%s: %s S/N %06X, MUSYCC Rev %02X",
- hi->devname, bid,
- ((sn[3] << 16) & 0xff0000) |
- ((sn[4] << 8) & 0x00ff00) |
- (sn[5] & 0x0000ff),
- (u_int8_t) hi->revid[0]);
-
- pr_info("%s\n", banner);
-
- pdev = hi->pdev[0];
- pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n",
- hi->devname, "MUSYCC",
- (unsigned long) hi->addr_mapped[0], hi->addr[0],
- hi->pci_busno, (u_int8_t) PCI_SLOT (pdev->devfn),
- (u_int8_t) PCI_FUNC (pdev->devfn), pdev->irq);
-
- pdev = hi->pdev[1];
- pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n",
- hi->devname, "EBUS ",
- (unsigned long) hi->addr_mapped[1], hi->addr[1],
- hi->pci_busno, (u_int8_t) PCI_SLOT (pdev->devfn),
- (u_int8_t) PCI_FUNC (pdev->devfn), pdev->irq);
+ ci_t *ci;
+ struct pci_dev *pdev;
+ char *bid;
+ char banner[80];
+ char sn[6] = {0,};
+
+ ci = (ci_t *)(netdev_priv(hi->ndev));
+ bid = sbeid_get_bdname(ci);
+ switch (hi->promfmt) {
+ case PROM_FORMAT_TYPE1:
+ memcpy(sn, hi->mfg_info.pft1.Serial, 6);
+ break;
+ case PROM_FORMAT_TYPE2:
+ memcpy(sn, hi->mfg_info.pft2.Serial, 6);
+ break;
+ }
+
+ sprintf(banner, "%s: %s S/N %06X, MUSYCC Rev %02X",
+ hi->devname, bid,
+ ((sn[3] << 16) & 0xff0000) |
+ ((sn[4] << 8) & 0x00ff00) |
+ (sn[5] & 0x0000ff),
+ (u_int8_t) hi->revid[0]);
+
+ pr_info("%s\n", banner);
+
+ pdev = hi->pdev[0];
+ pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n",
+ hi->devname, "MUSYCC",
+ (unsigned long) hi->addr_mapped[0], hi->addr[0],
+ hi->pci_busno, (u_int8_t) PCI_SLOT(pdev->devfn),
+ (u_int8_t) PCI_FUNC(pdev->devfn), pdev->irq);
+
+ pdev = hi->pdev[1];
+ pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n",
+ hi->devname, "EBUS ",
+ (unsigned long) hi->addr_mapped[1], hi->addr[1],
+ hi->pci_busno, (u_int8_t) PCI_SLOT(pdev->devfn),
+ (u_int8_t) PCI_FUNC(pdev->devfn), pdev->irq);
}
-void __init
-hdw_sn_get (hdw_info_t *hi, int brdno)
+void __init
+hdw_sn_get(hdw_info_t *hi, int brdno)
{
- /* obtain hardware EEPROM information */
- long addr;
+ /* obtain hardware EEPROM information */
+ long addr;
- addr = (long) hi->addr_mapped[1] + EEPROM_OFFSET;
+ addr = (long) hi->addr_mapped[1] + EEPROM_OFFSET;
- /* read EEPROM with largest known format size... */
- pmc_eeprom_read_buffer (addr, 0, (char *) hi->mfg_info.data, sizeof (FLD_TYPE2));
+ /* read EEPROM with largest known format size... */
+ pmc_eeprom_read_buffer(addr, 0, (char *)hi->mfg_info.data,
+ sizeof(FLD_TYPE2));
#if 0
- {
- unsigned char *ucp = (unsigned char *) &hi->mfg_info.data;
-
- pr_info("eeprom[00]: %02x %02x %02x %02x %02x %02x %02x %02x\n",
- *(ucp + 0), *(ucp + 1), *(ucp + 2), *(ucp + 3), *(ucp + 4), *(ucp + 5), *(ucp + 6), *(ucp + 7));
- pr_info("eeprom[08]: %02x %02x %02x %02x %02x %02x %02x %02x\n",
- *(ucp + 8), *(ucp + 9), *(ucp + 10), *(ucp + 11), *(ucp + 12), *(ucp + 13), *(ucp + 14), *(ucp + 15));
- pr_info("eeprom[16]: %02x %02x %02x %02x %02x %02x %02x %02x\n",
- *(ucp + 16), *(ucp + 17), *(ucp + 18), *(ucp + 19), *(ucp + 20), *(ucp + 21), *(ucp + 22), *(ucp + 23));
- pr_info("eeprom[24]: %02x %02x %02x %02x %02x %02x %02x %02x\n",
- *(ucp + 24), *(ucp + 25), *(ucp + 26), *(ucp + 27), *(ucp + 28), *(ucp + 29), *(ucp + 30), *(ucp + 31));
- pr_info("eeprom[32]: %02x %02x %02x %02x %02x %02x %02x %02x\n",
- *(ucp + 32), *(ucp + 33), *(ucp + 34), *(ucp + 35), *(ucp + 36), *(ucp + 37), *(ucp + 38), *(ucp + 39));
- pr_info("eeprom[40]: %02x %02x %02x %02x %02x %02x %02x %02x\n",
- *(ucp + 40), *(ucp + 41), *(ucp + 42), *(ucp + 43), *(ucp + 44), *(ucp + 45), *(ucp + 46), *(ucp + 47));
- }
+ {
+ unsigned char *ucp = (unsigned char *) &hi->mfg_info.data;
+
+ pr_info("eeprom[00]: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ *(ucp + 0), *(ucp + 1), *(ucp + 2), *(ucp + 3),
+ *(ucp + 4), *(ucp + 5), *(ucp + 6), *(ucp + 7));
+ pr_info("eeprom[08]: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ *(ucp + 8), *(ucp + 9), *(ucp + 10), *(ucp + 11),
+ *(ucp + 12), *(ucp + 13), *(ucp + 14), *(ucp + 15));
+ pr_info("eeprom[16]: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ *(ucp + 16), *(ucp + 17), *(ucp + 18), *(ucp + 19),
+ *(ucp + 20), *(ucp + 21), *(ucp + 22), *(ucp + 23));
+ pr_info("eeprom[24]: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ *(ucp + 24), *(ucp + 25), *(ucp + 26), *(ucp + 27),
+ *(ucp + 28), *(ucp + 29), *(ucp + 30), *(ucp + 31));
+ pr_info("eeprom[32]: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ *(ucp + 32), *(ucp + 33), *(ucp + 34), *(ucp + 35),
+ *(ucp + 36), *(ucp + 37), *(ucp + 38), *(ucp + 39));
+ pr_info("eeprom[40]: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ *(ucp + 40), *(ucp + 41), *(ucp + 42), *(ucp + 43),
+ *(ucp + 44), *(ucp + 45), *(ucp + 46), *(ucp + 47));
+ }
#endif
#if 0
- pr_info("sn: %x %x %x %x %x %x\n",
- hi->mfg_info.Serial[0],
- hi->mfg_info.Serial[1],
- hi->mfg_info.Serial[2],
- hi->mfg_info.Serial[3],
- hi->mfg_info.Serial[4],
- hi->mfg_info.Serial[5]);
+ pr_info("sn: %x %x %x %x %x %x\n",
+ hi->mfg_info.Serial[0],
+ hi->mfg_info.Serial[1],
+ hi->mfg_info.Serial[2],
+ hi->mfg_info.Serial[3],
+ hi->mfg_info.Serial[4],
+ hi->mfg_info.Serial[5]);
#endif
- if ((hi->promfmt = pmc_verify_cksum (&hi->mfg_info.data)) == PROM_FORMAT_Unk)
- {
- /* bad crc, data is suspect */
- if (cxt1e1_log_level >= LOG_WARN)
- pr_info("%s: EEPROM cksum error\n", hi->devname);
- hi->mfg_info_sts = EEPROM_CRCERR;
- } else
- hi->mfg_info_sts = EEPROM_OK;
+ hi->promfmt = pmc_verify_cksum(&hi->mfg_info.data);
+ if (hi->promfmt == PROM_FORMAT_Unk) {
+ /* bad crc, data is suspect */
+ if (cxt1e1_log_level >= LOG_WARN)
+ pr_info("%s: EEPROM cksum error\n", hi->devname);
+ hi->mfg_info_sts = EEPROM_CRCERR;
+ } else
+ hi->mfg_info_sts = EEPROM_OK;
}
-void __init
-prep_hdw_info (void)
+ void __init
+prep_hdw_info(void)
{
- hdw_info_t *hi;
- int i;
-
- for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
- {
- hi->pci_busno = 0xff;
- hi->pci_slot = 0xff;
- hi->pci_pin[0] = 0;
- hi->pci_pin[1] = 0;
- hi->ndev = NULL;
- hi->addr[0] = 0L;
- hi->addr[1] = 0L;
- hi->addr_mapped[0] = 0L;
- hi->addr_mapped[1] = 0L;
- }
+ hdw_info_t *hi;
+ int i;
+
+ for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) {
+ hi->pci_busno = 0xff;
+ hi->pci_slot = 0xff;
+ hi->pci_pin[0] = 0;
+ hi->pci_pin[1] = 0;
+ hi->ndev = NULL;
+ hi->addr[0] = 0L;
+ hi->addr[1] = 0L;
+ hi->addr_mapped[0] = 0L;
+ hi->addr_mapped[1] = 0L;
+ }
}
void
-cleanup_ioremap (void)
+cleanup_ioremap(void)
{
- hdw_info_t *hi;
- int i;
-
- for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
- {
- if (hi->pci_slot == 0xff)
- break;
- if (hi->addr_mapped[0])
- {
- iounmap ((void *) (hi->addr_mapped[0]));
- release_mem_region ((long) hi->addr[0], hi->len[0]);
- hi->addr_mapped[0] = 0;
- }
- if (hi->addr_mapped[1])
- {
- iounmap ((void *) (hi->addr_mapped[1]));
- release_mem_region ((long) hi->addr[1], hi->len[1]);
- hi->addr_mapped[1] = 0;
- }
- }
+ hdw_info_t *hi;
+ int i;
+
+ for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) {
+ if (hi->pci_slot == 0xff)
+ break;
+ if (hi->addr_mapped[0]) {
+ iounmap((void *)(hi->addr_mapped[0]));
+ release_mem_region((long) hi->addr[0], hi->len[0]);
+ hi->addr_mapped[0] = 0;
+ }
+ if (hi->addr_mapped[1]) {
+ iounmap((void *)(hi->addr_mapped[1]));
+ release_mem_region((long) hi->addr[1], hi->len[1]);
+ hi->addr_mapped[1] = 0;
+ }
+ }
}
void
-cleanup_devs (void)
+cleanup_devs(void)
{
- hdw_info_t *hi;
- int i;
-
- for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
- {
- if (hi->pci_slot == 0xff || !hi->ndev)
- break;
- c4_stopwd(netdev_priv(hi->ndev));
+ hdw_info_t *hi;
+ int i;
+
+ for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) {
+ if (hi->pci_slot == 0xff || !hi->ndev)
+ break;
+ c4_stopwd(netdev_priv(hi->ndev));
#ifdef CONFIG_PROC_FS
- sbecom_proc_brd_cleanup(netdev_priv(hi->ndev));
+ sbecom_proc_brd_cleanup(netdev_priv(hi->ndev));
#endif
- unregister_netdev (hi->ndev);
- free_irq (hi->pdev[0]->irq, hi->ndev);
+ unregister_netdev(hi->ndev);
+ free_irq(hi->pdev[0]->irq, hi->ndev);
#ifdef CONFIG_SBE_PMCC4_NCOMM
- free_irq (hi->pdev[1]->irq, hi->ndev);
+ free_irq(hi->pdev[1]->irq, hi->ndev);
#endif
- OS_kfree (hi->ndev);
- }
+ OS_kfree(hi->ndev);
+ }
}
static int __init
-c4_hdw_init (struct pci_dev *pdev, int found)
+c4_hdw_init(struct pci_dev *pdev, int found)
{
- hdw_info_t *hi;
- int i;
- int fun, slot;
- unsigned char busno = 0xff;
-
- /* our MUSYCC chip supports two functions, 0 & 1 */
- if ((fun = PCI_FUNC (pdev->devfn)) > 1)
- {
- pr_warning("unexpected devfun: 0x%x\n", pdev->devfn);
- return 0;
- }
- if (pdev->bus) /* obtain bus number */
- busno = pdev->bus->number;
- else
- busno = 0; /* default for system PCI inconsistency */
- slot = pdev->devfn & ~0x07;
-
- /*
- * Functions 0 & 1 for a given board (identified by same bus(busno) and
- * slot(slot)) are placed into the same 'hardware' structure. The first
- * part of the board's functionality will be placed into an unpopulated
- * element, identified by "slot==(0xff)". The second part of a board's
- * functionality will match the previously loaded slot/busno.
- */
- for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
- {
- /*
- * match with board's first found interface, otherwise this is first
- * found
- */
- if ((hi->pci_slot == 0xff) || /* new board */
- ((hi->pci_slot == slot) && (hi->bus == pdev->bus)))
- break; /* found for-loop exit */
- }
- if (i == MAX_BOARDS) /* no match in above loop means MAX
- * exceeded */
- {
- pr_warning("exceeded number of allowed devices (>%d)?\n", MAX_BOARDS);
- return 0;
- }
- if (pdev->bus)
- hi->pci_busno = pdev->bus->number;
- else
- hi->pci_busno = 0; /* default for system PCI inconsistency */
- hi->pci_slot = slot;
- pci_read_config_byte (pdev, PCI_INTERRUPT_PIN, &hi->pci_pin[fun]);
- pci_read_config_byte (pdev, PCI_REVISION_ID, &hi->revid[fun]);
- hi->bus = pdev->bus;
- hi->addr[fun] = pci_resource_start (pdev, 0);
- hi->len[fun] = pci_resource_end (pdev, 0) - hi->addr[fun] + 1;
- hi->pdev[fun] = pdev;
-
- {
- /*
- * create device name from module name, plus add the appropriate
- * board number
- */
- char *cp = hi->devname;
-
- strcpy (cp, KBUILD_MODNAME);
- cp += strlen (cp); /* reposition */
- *cp++ = '-';
- *cp++ = '0' + (found / 2); /* there are two found interfaces per
- * board */
- *cp = 0; /* termination */
- }
-
- return 1;
+ hdw_info_t *hi;
+ int i;
+ int fun, slot;
+ unsigned char busno = 0xff;
+
+ /* our MUSYCC chip supports two functions, 0 & 1 */
+ fun = PCI_FUNC(pdev->devfn);
+ if (fun > 1) {
+ pr_warning("unexpected devfun: 0x%x\n", pdev->devfn);
+ return 0;
+ }
+
+ /* obtain bus number */
+ if (pdev->bus)
+ busno = pdev->bus->number;
+ else
+ busno = 0; /* default for system PCI inconsistency */
+ slot = pdev->devfn & ~0x07;
+
+ /*
+ * Functions 0 & 1 for a given board (identified by same bus(busno) and
+ * slot(slot)) are placed into the same 'hardware' structure. The first
+ * part of the board's functionality will be placed into an unpopulated
+ * element, identified by "slot==(0xff)". The second part of a board's
+ * functionality will match the previously loaded slot/busno.
+ */
+ for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) {
+ /*
+ * match with board's first found interface, otherwise this is
+ * fisrt found
+ */
+ if ((hi->pci_slot == 0xff) || /* new board */
+ ((hi->pci_slot == slot) && (hi->bus == pdev->bus)))
+ break; /* found for-loop exit */
+ }
+
+ /* no match in above loop means MAX exceeded */
+ if (i == MAX_BOARDS) {
+ pr_warning("exceeded number of allowed devices (>%d)?\n",
+ MAX_BOARDS);
+ return 0;
+ }
+
+ if (pdev->bus)
+ hi->pci_busno = pdev->bus->number;
+ else
+ hi->pci_busno = 0; /* default for system PCI inconsistency */
+
+ hi->pci_slot = slot;
+ pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &hi->pci_pin[fun]);
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &hi->revid[fun]);
+ hi->bus = pdev->bus;
+ hi->addr[fun] = pci_resource_start(pdev, 0);
+ hi->len[fun] = pci_resource_end(pdev, 0) - hi->addr[fun] + 1;
+ hi->pdev[fun] = pdev;
+
+ {
+ /*
+ * create device name from module name, plus add the appropriate
+ * board number
+ */
+ char *cp = hi->devname;
+
+ strcpy(cp, KBUILD_MODNAME);
+ cp += strlen(cp); /* reposition */
+ *cp++ = '-';
+ *cp++ = '0' + (found / 2); /* there are two found interfaces per
+ * board */
+ *cp = 0; /* termination */
+ }
+
+ return 1;
}
-
-status_t __init
-c4hw_attach_all (void)
+status_t __init
+c4hw_attach_all(void)
{
- hdw_info_t *hi;
- struct pci_dev *pdev = NULL;
- int found = 0, i, j;
-
- error_flag = 0;
- prep_hdw_info ();
- /*** scan PCI bus for all possible boards */
- while ((pdev = pci_get_device (PCI_VENDOR_ID_CONEXANT,
- PCI_DEVICE_ID_CN8474,
- pdev)))
- {
- if (c4_hdw_init (pdev, found))
- found++;
- }
- if (!found)
- {
- pr_warning("No boards found\n");
- return -ENODEV;
- }
- /* sanity check for consistent hardware found */
- for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
- {
- if (hi->pci_slot != 0xff && (!hi->addr[0] || !hi->addr[1]))
- {
- pr_warning("%s: something very wrong with pci_get_device\n",
- hi->devname);
- return -EIO;
- }
- }
- /* bring board's memory regions on/line */
- for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
- {
- if (hi->pci_slot == 0xff)
- break;
- for (j = 0; j < 2; j++)
- {
- if (!request_mem_region (hi->addr[j], hi->len[j], hi->devname))
- {
- pr_warning("%s: memory in use, addr=0x%lx, len=0x%lx ?\n",
- hi->devname, hi->addr[j], hi->len[j]);
- cleanup_ioremap ();
- return -ENOMEM;
- }
- hi->addr_mapped[j] = (unsigned long) ioremap (hi->addr[j], hi->len[j]);
- if (!hi->addr_mapped[j])
- {
- pr_warning("%s: ioremap fails, addr=0x%lx, len=0x%lx ?\n",
- hi->devname, hi->addr[j], hi->len[j]);
- cleanup_ioremap ();
- return -ENOMEM;
- }
+ hdw_info_t *hi;
+ struct pci_dev *pdev = NULL;
+ int found = 0, i, j;
+
+ error_flag = 0;
+ prep_hdw_info();
+ /*** scan PCI bus for all possible boards */
+ while ((pdev = pci_get_device(PCI_VENDOR_ID_CONEXANT,
+ PCI_DEVICE_ID_CN8474,
+ pdev))) {
+ if (c4_hdw_init(pdev, found))
+ found++;
+ }
+
+ if (!found) {
+ pr_warning("No boards found\n");
+ return -ENODEV;
+ }
+
+ /* sanity check for consistent hardware found */
+ for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) {
+ if (hi->pci_slot != 0xff && (!hi->addr[0] || !hi->addr[1])) {
+ pr_warning("%s: something very wrong with pci_get_device\n",
+ hi->devname);
+ return -EIO;
+ }
+ }
+ /* bring board's memory regions on/line */
+ for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) {
+ if (hi->pci_slot == 0xff)
+ break;
+ for (j = 0; j < 2; j++) {
+ if (!request_mem_region(hi->addr[j], hi->len[j], hi->devname)) {
+ pr_warning("%s: memory in use, addr=0x%lx, len=0x%lx ?\n",
+ hi->devname, hi->addr[j], hi->len[j]);
+ cleanup_ioremap();
+ return -ENOMEM;
+ }
+
+ hi->addr_mapped[j] = (unsigned long)ioremap(hi->addr[j], hi->len[j]);
+ if (!hi->addr_mapped[j]) {
+ pr_warning("%s: ioremap fails, addr=0x%lx, len=0x%lx ?\n",
+ hi->devname, hi->addr[j], hi->len[j]);
+ cleanup_ioremap();
+ return -ENOMEM;
+ }
#ifdef SBE_MAP_DEBUG
- pr_warning("%s: io remapped from phys %x to virt %x\n",
- hi->devname, (u_int32_t) hi->addr[j], (u_int32_t) hi->addr_mapped[j]);
+ pr_warning("%s: io remapped from phys %x to virt %x\n",
+ hi->devname, (u_int32_t) hi->addr[j],
+ (u_int32_t) hi->addr_mapped[j]);
#endif
- }
- }
-
- drvr_state = SBE_DRVR_AVAILABLE;
-
- /* Have now memory mapped all boards. Now allow board's access to system */
- for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
- {
- if (hi->pci_slot == 0xff)
- break;
- if (pci_enable_device (hi->pdev[0]) ||
- pci_enable_device (hi->pdev[1]))
- {
- drvr_state = SBE_DRVR_DOWN;
- pr_warning("%s: failed to enable card %d slot %d\n",
- hi->devname, i, hi->pci_slot);
- cleanup_devs ();
- cleanup_ioremap ();
- return -EIO;
- }
- pci_set_master (hi->pdev[0]);
- pci_set_master (hi->pdev[1]);
- if (!(hi->ndev = c4_add_dev (hi, i, (long) hi->addr_mapped[0],
- (long) hi->addr_mapped[1],
- hi->pdev[0]->irq,
- hi->pdev[1]->irq)))
- {
- drvr_state = SBE_DRVR_DOWN;
- cleanup_ioremap ();
- /* NOTE: c4_add_dev() does its own device cleanup */
+ }
+ }
+
+ drvr_state = SBE_DRVR_AVAILABLE;
+
+ /* Have now memory mapped all boards. Now allow board's access to system */
+ for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) {
+ if (hi->pci_slot == 0xff)
+ break;
+ if (pci_enable_device(hi->pdev[0]) ||
+ pci_enable_device(hi->pdev[1])) {
+ drvr_state = SBE_DRVR_DOWN;
+ pr_warning("%s: failed to enable card %d slot %d\n",
+ hi->devname, i, hi->pci_slot);
+ cleanup_devs();
+ cleanup_ioremap();
+ return -EIO;
+ }
+ pci_set_master(hi->pdev[0]);
+ pci_set_master(hi->pdev[1]);
+ hi->ndev = c4_add_dev(hi, i, (long) hi->addr_mapped[0],
+ (long) hi->addr_mapped[1],
+ hi->pdev[0]->irq,
+ hi->pdev[1]->irq);
+ if (!hi->ndev) {
+ drvr_state = SBE_DRVR_DOWN;
+ cleanup_ioremap();
+ /* NOTE: c4_add_dev() does its own device cleanup */
#if 0
- cleanup_devs ();
+ cleanup_devs();
#endif
- return error_flag; /* error_flag set w/in add_dev() */
- }
- show_two (hi, i); /* displays found information */
- }
- return 0;
+ return error_flag; /* error_flag set w/in add_dev() */
+ }
+ show_two(hi, i); /* displays found information */
+ }
+ return 0;
}
/*** End-of-File ***/
diff --git a/drivers/staging/cxt1e1/libsbew.h b/drivers/staging/cxt1e1/libsbew.h
index 4254c0426db9..bd2bfba604b3 100644
--- a/drivers/staging/cxt1e1/libsbew.h
+++ b/drivers/staging/cxt1e1/libsbew.h
@@ -514,36 +514,36 @@ struct sbecom_port_param
};
typedef struct wancfg wcfg_t;
- extern wcfg_t *wancfg_init (char *, char *);
- extern int wancfg_card_blink (wcfg_t *, int);
- extern int wancfg_ctl (wcfg_t *, int, void *, int, void *, int);
- extern int wancfg_del_card_stats (wcfg_t *);
- extern int wancfg_del_chan_stats (wcfg_t *, int);
- extern int wancfg_enable_ports (wcfg_t *, int);
- extern int wancfg_free (wcfg_t *);
- extern int wancfg_get_brdaddr (wcfg_t *, struct sbe_brd_addr *);
- extern int wancfg_get_brdinfo (wcfg_t *, struct sbe_brd_info *);
- extern int wancfg_get_card (wcfg_t *, struct sbecom_card_param *);
- extern int wancfg_get_card_chan_stats (wcfg_t *, struct sbecom_chan_stats *);
- extern int wancfg_get_card_sn (wcfg_t *);
- extern int wancfg_get_card_stats (wcfg_t *, struct temux_card_stats *);
- extern int wancfg_get_chan (wcfg_t *, int, struct sbecom_chan_param *);
- extern int wancfg_get_chan_stats (wcfg_t *, int, struct sbecom_chan_stats *);
- extern int wancfg_get_drvinfo (wcfg_t *, int, struct sbe_drv_info *);
- extern int wancfg_get_framer (wcfg_t *, int, struct sbecom_framer_param *);
- extern int wancfg_get_iid (wcfg_t *, int, struct sbe_iid_info *);
- extern int wancfg_get_sn (wcfg_t *, unsigned int *);
- extern int wancfg_read (wcfg_t *, int, struct sbecom_wrt_vec *);
- extern int wancfg_reset_device (wcfg_t *, int);
- extern int wancfg_set_card (wcfg_t *, struct sbecom_card_param *);
- extern int wancfg_set_chan (wcfg_t *, int, struct sbecom_chan_param *);
- extern int wancfg_set_framer (wcfg_t *, int, struct sbecom_framer_param *);
- extern int wancfg_set_loglevel (wcfg_t *, uint);
- extern int wancfg_write (wcfg_t *, int, struct sbecom_wrt_vec *);
+ extern wcfg_t *wancfg_init(char *, char *);
+ extern int wancfg_card_blink(wcfg_t *, int);
+ extern int wancfg_ctl(wcfg_t *, int, void *, int, void *, int);
+ extern int wancfg_del_card_stats(wcfg_t *);
+ extern int wancfg_del_chan_stats(wcfg_t *, int);
+ extern int wancfg_enable_ports(wcfg_t *, int);
+ extern int wancfg_free(wcfg_t *);
+ extern int wancfg_get_brdaddr(wcfg_t *, struct sbe_brd_addr *);
+ extern int wancfg_get_brdinfo(wcfg_t *, struct sbe_brd_info *);
+ extern int wancfg_get_card(wcfg_t *, struct sbecom_card_param *);
+ extern int wancfg_get_card_chan_stats(wcfg_t *, struct sbecom_chan_stats *);
+ extern int wancfg_get_card_sn(wcfg_t *);
+ extern int wancfg_get_card_stats(wcfg_t *, struct temux_card_stats *);
+ extern int wancfg_get_chan(wcfg_t *, int, struct sbecom_chan_param *);
+ extern int wancfg_get_chan_stats(wcfg_t *, int, struct sbecom_chan_stats *);
+ extern int wancfg_get_drvinfo(wcfg_t *, int, struct sbe_drv_info *);
+ extern int wancfg_get_framer(wcfg_t *, int, struct sbecom_framer_param *);
+ extern int wancfg_get_iid(wcfg_t *, int, struct sbe_iid_info *);
+ extern int wancfg_get_sn(wcfg_t *, unsigned int *);
+ extern int wancfg_read(wcfg_t *, int, struct sbecom_wrt_vec *);
+ extern int wancfg_reset_device(wcfg_t *, int);
+ extern int wancfg_set_card(wcfg_t *, struct sbecom_card_param *);
+ extern int wancfg_set_chan(wcfg_t *, int, struct sbecom_chan_param *);
+ extern int wancfg_set_framer(wcfg_t *, int, struct sbecom_framer_param *);
+ extern int wancfg_set_loglevel(wcfg_t *, uint);
+ extern int wancfg_write(wcfg_t *, int, struct sbecom_wrt_vec *);
#ifdef NOT_YET_COMMON
- extern int wancfg_get_tsioc (wcfg_t *, struct wanc1t3_ts_hdr *, struct wanc1t3_ts_param *);
- extern int wancfg_set_tsioc (wcfg_t *, struct wanc1t3_ts_param *);
+ extern int wancfg_get_tsioc(wcfg_t *, struct wanc1t3_ts_hdr *, struct wanc1t3_ts_param *);
+ extern int wancfg_set_tsioc(wcfg_t *, struct wanc1t3_ts_param *);
#endif
#endif /*** _INC_LIBSBEW_H_ ***/
diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c
index 4a08e16e42f7..b02f5ade6661 100644
--- a/drivers/staging/cxt1e1/linux.c
+++ b/drivers/staging/cxt1e1/linux.c
@@ -31,7 +31,7 @@
#include "pmcc4_private.h"
#include "sbeproc.h"
-/*****************************************************************************************
+/*******************************************************************************
* Error out early if we have compiler trouble.
*
* (This section is included from the kernel's init/main.c as a friendly
@@ -50,43 +50,42 @@
#warning gcc-4.1.0 is known to miscompile the kernel. A different compiler version is recommended.
#endif
-/*****************************************************************************************/
+/*******************************************************************************/
#define CHANNAME "hdlc"
/*******************************************************************/
/* forward references */
-status_t c4_chan_work_init (mpi_t *, mch_t *);
-void musycc_wq_chan_restart (void *);
-status_t __init c4_init (ci_t *, u_char *, u_char *);
-status_t __init c4_init2 (ci_t *);
-ci_t *__init c4_new (void *);
-int __init c4hw_attach_all (void);
-void __init hdw_sn_get (hdw_info_t *, int);
+status_t c4_chan_work_init(mpi_t *, mch_t *);
+void musycc_wq_chan_restart(void *);
+status_t __init c4_init(ci_t *, u_char *, u_char *);
+status_t __init c4_init2(ci_t *);
+ci_t *__init c4_new(void *);
+int __init c4hw_attach_all(void);
+void __init hdw_sn_get(hdw_info_t *, int);
#ifdef CONFIG_SBE_PMCC4_NCOMM
-irqreturn_t c4_ebus_intr_th_handler (void *);
+irqreturn_t c4_ebus_intr_th_handler(void *);
#endif
-int c4_frame_rw (ci_t *, struct sbecom_port_param *);
-status_t c4_get_port (ci_t *, int);
-int c4_loop_port (ci_t *, int, u_int8_t);
-int c4_musycc_rw (ci_t *, struct c4_musycc_param *);
-int c4_new_chan (ci_t *, int, int, void *);
-status_t c4_set_port (ci_t *, int);
-int c4_pld_rw (ci_t *, struct sbecom_port_param *);
-void cleanup_devs (void);
-void cleanup_ioremap (void);
-status_t musycc_chan_down (ci_t *, int);
-irqreturn_t musycc_intr_th_handler (void *);
-int musycc_start_xmit (ci_t *, int, void *);
-
-extern char pmcc4_OSSI_release[];
+int c4_frame_rw(ci_t *, struct sbecom_port_param *);
+status_t c4_get_port(ci_t *, int);
+int c4_loop_port(ci_t *, int, u_int8_t);
+int c4_musycc_rw(ci_t *, struct c4_musycc_param *);
+int c4_new_chan(ci_t *, int, int, void *);
+status_t c4_set_port(ci_t *, int);
+int c4_pld_rw(ci_t *, struct sbecom_port_param *);
+void cleanup_devs(void);
+void cleanup_ioremap(void);
+status_t musycc_chan_down(ci_t *, int);
+irqreturn_t musycc_intr_th_handler(void *);
+int musycc_start_xmit(ci_t *, int, void *);
+
extern ci_t *CI;
extern struct s_hdw_info hdw_info[];
#if defined(CONFIG_SBE_HDLC_V7) || defined(CONFIG_SBE_WAN256T3_HDLC_V7) || \
- defined(CONFIG_SBE_HDLC_V7_MODULE) || defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE)
+ defined(CONFIG_SBE_HDLC_V7_MODULE) || defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE)
#define _v7_hdlc_ 1
#else
#define _v7_hdlc_ 0
@@ -94,9 +93,9 @@ extern struct s_hdw_info hdw_info[];
#if _v7_hdlc_
#define V7(x) (x ## _v7)
-extern int hdlc_netif_rx_v7 (hdlc_device *, struct sk_buff *);
-extern int register_hdlc_device_v7 (hdlc_device *);
-extern int unregister_hdlc_device_v7 (hdlc_device *);
+extern int hdlc_netif_rx_v7(hdlc_device *, struct sk_buff *);
+extern int register_hdlc_device_v7(hdlc_device *);
+extern int unregister_hdlc_device_v7(hdlc_device *);
#else
#define V7(x) x
@@ -104,11 +103,11 @@ extern int unregister_hdlc_device_v7 (hdlc_device *);
int error_flag; /* module load error reporting */
int cxt1e1_log_level = LOG_ERROR;
-int log_level_default = LOG_ERROR;
+static int log_level_default = LOG_ERROR;
module_param(cxt1e1_log_level, int, 0444);
int cxt1e1_max_mru = MUSYCC_MRU;
-int max_mru_default = MUSYCC_MRU;
+static int max_mru_default = MUSYCC_MRU;
module_param(cxt1e1_max_mru, int, 0444);
int cxt1e1_max_mtu = MUSYCC_MTU;
@@ -127,33 +126,23 @@ module_param(max_rxdesc_used, int, 0444);
/****************************************************************************/
/****************************************************************************/
-void *
-getuserbychan (int channum)
+void *
+getuserbychan(int channum)
{
- mch_t *ch;
+ mch_t *ch;
- ch = c4_find_chan (channum);
- return ch ? ch->user : NULL;
+ ch = c4_find_chan(channum);
+ return ch ? ch->user : NULL;
}
-char *
-get_hdlc_name (hdlc_device *hdlc)
+char *
+get_hdlc_name(hdlc_device *hdlc)
{
- struct c4_priv *priv = hdlc->priv;
- struct net_device *dev = getuserbychan (priv->channum);
-
- return dev->name;
-}
+ struct c4_priv *priv = hdlc->priv;
+ struct net_device *dev = getuserbychan(priv->channum);
-
-static status_t
-mkret (int bsd)
-{
- if (bsd > 0)
- return -bsd;
- else
- return bsd;
+ return dev->name;
}
/***************************************************************************/
@@ -179,956 +168,946 @@ mkret (int bsd)
* within a port's group.
*/
void
-c4_wk_chan_restart (mch_t *ch)
+c4_wk_chan_restart(mch_t *ch)
{
- mpi_t *pi = ch->up;
+ mpi_t *pi = ch->up;
#ifdef RLD_RESTART_DEBUG
- pr_info(">> %s: queueing Port %d Chan %d, mch_t @ %p\n",
- __func__, pi->portnum, ch->channum, ch);
+ pr_info(">> %s: queueing Port %d Chan %d, mch_t @ %p\n",
+ __func__, pi->portnum, ch->channum, ch);
#endif
- /* create new entry w/in workqueue for this channel and let'er rip */
+ /* create new entry w/in workqueue for this channel and let'er rip */
- /** queue_work (struct workqueue_struct *queue,
- ** struct work_struct *work);
- **/
- queue_work (pi->wq_port, &ch->ch_work);
+ /** queue_work(struct workqueue_struct *queue,
+ ** struct work_struct *work);
+ **/
+ queue_work(pi->wq_port, &ch->ch_work);
}
status_t
-c4_wk_chan_init (mpi_t *pi, mch_t *ch)
+c4_wk_chan_init(mpi_t *pi, mch_t *ch)
{
- /*
- * this will be used to restart a stopped channel
- */
-
- /** INIT_WORK (struct work_struct *work,
- ** void (*function)(void *),
- ** void *data);
- **/
- INIT_WORK(&ch->ch_work, (void *)musycc_wq_chan_restart);
- return 0; /* success */
+ /*
+ * this will be used to restart a stopped channel
+ */
+
+ /** INIT_WORK(struct work_struct *work,
+ ** void (*function)(void *),
+ ** void *data);
+ **/
+ INIT_WORK(&ch->ch_work, (void *)musycc_wq_chan_restart);
+ return 0; /* success */
}
status_t
-c4_wq_port_init (mpi_t *pi)
+c4_wq_port_init(mpi_t *pi)
{
- char name[16], *np; /* NOTE: name of the queue limited by system
- * to 10 characters */
+ char name[16]; /* NOTE: name of the queue limited by system
+ * to 10 characters */
+ if (pi->wq_port)
+ return 0; /* already initialized */
- if (pi->wq_port)
- return 0; /* already initialized */
-
- np = name;
- memset (name, 0, 16);
- sprintf (np, "%s%d", pi->up->devname, pi->portnum); /* IE pmcc4-01) */
+ /* IE pmcc4-01 */
+ snprintf(name, sizeof(name), "%s%d", pi->up->devname, pi->portnum);
#ifdef RLD_RESTART_DEBUG
- pr_info(">> %s: creating workqueue <%s> for Port %d.\n",
- __func__, name, pi->portnum); /* RLD DEBUG */
+ pr_info(">> %s: creating workqueue <%s> for Port %d.\n",
+ __func__, name, pi->portnum); /* RLD DEBUG */
#endif
- if (!(pi->wq_port = create_singlethread_workqueue (name)))
- return -ENOMEM;
- return 0; /* success */
+ pi->wq_port = create_singlethread_workqueue(name);
+ if (!pi->wq_port)
+ return -ENOMEM;
+ return 0; /* success */
}
void
-c4_wq_port_cleanup (mpi_t *pi)
+c4_wq_port_cleanup(mpi_t *pi)
{
- /*
- * PORT POINT: cannot call this if WQ is statically allocated w/in
- * structure since it calls kfree(wq);
- */
- if (pi->wq_port)
- {
- destroy_workqueue (pi->wq_port); /* this also calls
- * flush_workqueue() */
- pi->wq_port = NULL;
- }
+ /*
+ * PORT POINT: cannot call this if WQ is statically allocated w/in
+ * structure since it calls kfree(wq);
+ */
+ if (pi->wq_port) {
+ destroy_workqueue(pi->wq_port); /* this also calls
+ * flush_workqueue() */
+ pi->wq_port = NULL;
+ }
}
/***************************************************************************/
-irqreturn_t
-c4_linux_interrupt (int irq, void *dev_instance)
+static irqreturn_t
+c4_linux_interrupt(int irq, void *dev_instance)
{
- struct net_device *ndev = dev_instance;
+ struct net_device *ndev = dev_instance;
- return musycc_intr_th_handler(netdev_priv(ndev));
+ return musycc_intr_th_handler(netdev_priv(ndev));
}
#ifdef CONFIG_SBE_PMCC4_NCOMM
-irqreturn_t
-c4_ebus_interrupt (int irq, void *dev_instance)
+static irqreturn_t
+c4_ebus_interrupt(int irq, void *dev_instance)
{
- struct net_device *ndev = dev_instance;
+ struct net_device *ndev = dev_instance;
- return c4_ebus_intr_th_handler(netdev_priv(ndev));
+ return c4_ebus_intr_th_handler(netdev_priv(ndev));
}
#endif
static int
-void_open (struct net_device *ndev)
+void_open(struct net_device *ndev)
{
- pr_info("%s: trying to open master device !\n", ndev->name);
- return -1;
+ pr_info("%s: trying to open master device !\n", ndev->name);
+ return -1;
}
static int
-chan_open (struct net_device *ndev)
+chan_open(struct net_device *ndev)
{
- hdlc_device *hdlc = dev_to_hdlc (ndev);
- const struct c4_priv *priv = hdlc->priv;
- int ret;
-
- if ((ret = hdlc_open (ndev)))
- {
- pr_info("hdlc_open failure, err %d.\n", ret);
- return ret;
- }
- if ((ret = c4_chan_up (priv->ci, priv->channum)))
- return -ret;
- try_module_get (THIS_MODULE);
- netif_start_queue (ndev);
- return 0; /* no error = success */
+ hdlc_device *hdlc = dev_to_hdlc(ndev);
+ const struct c4_priv *priv = hdlc->priv;
+ int ret;
+
+ ret = hdlc_open(ndev);
+ if (ret) {
+ pr_info("hdlc_open failure, err %d.\n", ret);
+ return ret;
+ }
+
+ ret = c4_chan_up(priv->ci, priv->channum);
+ if (ret < 0)
+ return ret;
+ try_module_get(THIS_MODULE);
+ netif_start_queue(ndev);
+ return 0; /* no error = success */
}
static int
-chan_close (struct net_device *ndev)
+chan_close(struct net_device *ndev)
{
- hdlc_device *hdlc = dev_to_hdlc (ndev);
- const struct c4_priv *priv = hdlc->priv;
-
- netif_stop_queue (ndev);
- musycc_chan_down ((ci_t *) 0, priv->channum);
- hdlc_close (ndev);
- module_put (THIS_MODULE);
- return 0;
+ hdlc_device *hdlc = dev_to_hdlc(ndev);
+ const struct c4_priv *priv = hdlc->priv;
+
+ netif_stop_queue(ndev);
+ musycc_chan_down((ci_t *) 0, priv->channum);
+ hdlc_close(ndev);
+ module_put(THIS_MODULE);
+ return 0;
}
static int
-chan_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
+chan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- return hdlc_ioctl (dev, ifr, cmd);
+ return hdlc_ioctl(dev, ifr, cmd);
}
static int
-chan_attach_noop (struct net_device *ndev, unsigned short foo_1, unsigned short foo_2)
+chan_attach_noop(struct net_device *ndev, unsigned short foo_1,
+ unsigned short foo_2)
{
- return 0; /* our driver has nothing to do here, show's
- * over, go home */
+ /* our driver has nothing to do here, show's
+ * over, go home
+ */
+ return 0;
}
static struct net_device_stats *
-chan_get_stats (struct net_device *ndev)
+chan_get_stats(struct net_device *ndev)
{
- mch_t *ch;
- struct net_device_stats *nstats;
- struct sbecom_chan_stats *stats;
- int channum;
-
- {
- struct c4_priv *priv;
-
- priv = (struct c4_priv *) dev_to_hdlc (ndev)->priv;
- channum = priv->channum;
- }
-
- ch = c4_find_chan (channum);
- if (ch == NULL)
- return NULL;
-
- nstats = &ndev->stats;
- stats = &ch->s;
-
- memset (nstats, 0, sizeof (struct net_device_stats));
- nstats->rx_packets = stats->rx_packets;
- nstats->tx_packets = stats->tx_packets;
- nstats->rx_bytes = stats->rx_bytes;
- nstats->tx_bytes = stats->tx_bytes;
- nstats->rx_errors = stats->rx_length_errors +
- stats->rx_over_errors +
- stats->rx_crc_errors +
- stats->rx_frame_errors +
- stats->rx_fifo_errors +
- stats->rx_missed_errors;
- nstats->tx_errors = stats->tx_dropped +
- stats->tx_aborted_errors +
- stats->tx_fifo_errors;
- nstats->rx_dropped = stats->rx_dropped;
- nstats->tx_dropped = stats->tx_dropped;
-
- nstats->rx_length_errors = stats->rx_length_errors;
- nstats->rx_over_errors = stats->rx_over_errors;
- nstats->rx_crc_errors = stats->rx_crc_errors;
- nstats->rx_frame_errors = stats->rx_frame_errors;
- nstats->rx_fifo_errors = stats->rx_fifo_errors;
- nstats->rx_missed_errors = stats->rx_missed_errors;
-
- nstats->tx_aborted_errors = stats->tx_aborted_errors;
- nstats->tx_fifo_errors = stats->tx_fifo_errors;
-
- return nstats;
+ mch_t *ch;
+ struct net_device_stats *nstats;
+ struct sbecom_chan_stats *stats;
+ int channum;
+
+ {
+ struct c4_priv *priv;
+
+ priv = (struct c4_priv *)dev_to_hdlc(ndev)->priv;
+ channum = priv->channum;
+ }
+
+ ch = c4_find_chan(channum);
+ if (ch == NULL)
+ return NULL;
+
+ nstats = &ndev->stats;
+ stats = &ch->s;
+
+ memset(nstats, 0, sizeof(struct net_device_stats));
+ nstats->rx_packets = stats->rx_packets;
+ nstats->tx_packets = stats->tx_packets;
+ nstats->rx_bytes = stats->rx_bytes;
+ nstats->tx_bytes = stats->tx_bytes;
+ nstats->rx_errors = stats->rx_length_errors +
+ stats->rx_over_errors +
+ stats->rx_crc_errors +
+ stats->rx_frame_errors +
+ stats->rx_fifo_errors +
+ stats->rx_missed_errors;
+ nstats->tx_errors = stats->tx_dropped +
+ stats->tx_aborted_errors +
+ stats->tx_fifo_errors;
+ nstats->rx_dropped = stats->rx_dropped;
+ nstats->tx_dropped = stats->tx_dropped;
+
+ nstats->rx_length_errors = stats->rx_length_errors;
+ nstats->rx_over_errors = stats->rx_over_errors;
+ nstats->rx_crc_errors = stats->rx_crc_errors;
+ nstats->rx_frame_errors = stats->rx_frame_errors;
+ nstats->rx_fifo_errors = stats->rx_fifo_errors;
+ nstats->rx_missed_errors = stats->rx_missed_errors;
+
+ nstats->tx_aborted_errors = stats->tx_aborted_errors;
+ nstats->tx_fifo_errors = stats->tx_fifo_errors;
+
+ return nstats;
}
static ci_t *
-get_ci_by_dev (struct net_device *ndev)
+get_ci_by_dev(struct net_device *ndev)
{
- return (ci_t *)(netdev_priv(ndev));
+ return (ci_t *)(netdev_priv(ndev));
}
static int
-c4_linux_xmit (struct sk_buff *skb, struct net_device *ndev)
+c4_linux_xmit(struct sk_buff *skb, struct net_device *ndev)
{
- const struct c4_priv *priv;
- int rval;
+ const struct c4_priv *priv;
+ int rval;
- hdlc_device *hdlc = dev_to_hdlc (ndev);
+ hdlc_device *hdlc = dev_to_hdlc(ndev);
- priv = hdlc->priv;
+ priv = hdlc->priv;
- rval = musycc_start_xmit (priv->ci, priv->channum, skb);
- return rval;
+ rval = musycc_start_xmit(priv->ci, priv->channum, skb);
+ return rval;
}
static const struct net_device_ops chan_ops = {
- .ndo_open = chan_open,
- .ndo_stop = chan_close,
- .ndo_start_xmit = c4_linux_xmit,
- .ndo_do_ioctl = chan_dev_ioctl,
- .ndo_get_stats = chan_get_stats,
+ .ndo_open = chan_open,
+ .ndo_stop = chan_close,
+ .ndo_start_xmit = c4_linux_xmit,
+ .ndo_do_ioctl = chan_dev_ioctl,
+ .ndo_get_stats = chan_get_stats,
};
static struct net_device *
-create_chan (struct net_device *ndev, ci_t *ci,
- struct sbecom_chan_param *cp)
+create_chan(struct net_device *ndev, ci_t *ci,
+ struct sbecom_chan_param *cp)
{
- hdlc_device *hdlc;
- struct net_device *dev;
- hdw_info_t *hi;
- int ret;
-
- if (c4_find_chan (cp->channum))
- return NULL; /* channel already exists */
-
- {
- struct c4_priv *priv;
-
- /* allocate then fill in private data structure */
- priv = OS_kmalloc (sizeof (struct c4_priv));
- if (!priv)
- {
- pr_warning("%s: no memory for net_device !\n", ci->devname);
- return NULL;
- }
- dev = alloc_hdlcdev (priv);
- if (!dev)
- {
- pr_warning("%s: no memory for hdlc_device !\n", ci->devname);
- OS_kfree (priv);
- return NULL;
- }
- priv->ci = ci;
- priv->channum = cp->channum;
- }
-
- hdlc = dev_to_hdlc (dev);
-
- dev->base_addr = 0; /* not I/O mapped */
- dev->irq = ndev->irq;
- dev->type = ARPHRD_RAWHDLC;
- *dev->name = 0; /* default ifconfig name = "hdlc" */
-
- hi = (hdw_info_t *) ci->hdw_info;
- if (hi->mfg_info_sts == EEPROM_OK)
- {
- switch (hi->promfmt)
- {
- case PROM_FORMAT_TYPE1:
- memcpy (dev->dev_addr, (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6);
- break;
- case PROM_FORMAT_TYPE2:
- memcpy (dev->dev_addr, (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6);
- break;
- default:
- memset (dev->dev_addr, 0, 6);
- break;
- }
- } else
- {
- memset (dev->dev_addr, 0, 6);
- }
-
- hdlc->xmit = c4_linux_xmit;
-
- dev->netdev_ops = &chan_ops;
- /*
- * The native hdlc stack calls this 'attach' routine during
- * hdlc_raw_ioctl(), passing parameters for line encoding and parity.
- * Since hdlc_raw_ioctl() stack does not interrogate whether an 'attach'
- * routine is actually registered or not, we supply a dummy routine which
- * does nothing (since encoding and parity are setup for our driver via a
- * special configuration application).
- */
-
- hdlc->attach = chan_attach_noop;
-
- rtnl_unlock (); /* needed due to Ioctl calling sequence */
- ret = register_hdlc_device (dev);
- /* NOTE: <stats> setting must occur AFTER registration in order to "take" */
- dev->tx_queue_len = MAX_DEFAULT_IFQLEN;
-
- rtnl_lock (); /* needed due to Ioctl calling sequence */
- if (ret)
- {
- if (cxt1e1_log_level >= LOG_WARN)
- pr_info("%s: create_chan[%d] registration error = %d.\n",
- ci->devname, cp->channum, ret);
- free_netdev (dev); /* cleanup */
- return NULL; /* failed to register */
- }
- return dev;
+ hdlc_device *hdlc;
+ struct net_device *dev;
+ hdw_info_t *hi;
+ int ret;
+
+ if (c4_find_chan(cp->channum))
+ return NULL; /* channel already exists */
+
+ {
+ struct c4_priv *priv;
+
+ /* allocate then fill in private data structure */
+ priv = OS_kmalloc(sizeof(struct c4_priv));
+ if (!priv) {
+ pr_warning("%s: no memory for net_device !\n",
+ ci->devname);
+ return NULL;
+ }
+ dev = alloc_hdlcdev(priv);
+ if (!dev) {
+ pr_warning("%s: no memory for hdlc_device !\n",
+ ci->devname);
+ OS_kfree(priv);
+ return NULL;
+ }
+ priv->ci = ci;
+ priv->channum = cp->channum;
+ }
+
+ hdlc = dev_to_hdlc(dev);
+
+ dev->base_addr = 0; /* not I/O mapped */
+ dev->irq = ndev->irq;
+ dev->type = ARPHRD_RAWHDLC;
+ *dev->name = 0; /* default ifconfig name = "hdlc" */
+
+ hi = (hdw_info_t *)ci->hdw_info;
+ if (hi->mfg_info_sts == EEPROM_OK) {
+ switch (hi->promfmt) {
+ case PROM_FORMAT_TYPE1:
+ memcpy(dev->dev_addr,
+ (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6);
+ break;
+ case PROM_FORMAT_TYPE2:
+ memcpy(dev->dev_addr,
+ (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6);
+ break;
+ default:
+ memset(dev->dev_addr, 0, 6);
+ break;
+ }
+ } else
+ memset(dev->dev_addr, 0, 6);
+
+ hdlc->xmit = c4_linux_xmit;
+
+ dev->netdev_ops = &chan_ops;
+ /*
+ * The native hdlc stack calls this 'attach' routine during
+ * hdlc_raw_ioctl(), passing parameters for line encoding and parity.
+ * Since hdlc_raw_ioctl() stack does not interrogate whether an 'attach'
+ * routine is actually registered or not, we supply a dummy routine which
+ * does nothing (since encoding and parity are setup for our driver via a
+ * special configuration application).
+ */
+
+ hdlc->attach = chan_attach_noop;
+
+ /* needed due to Ioctl calling sequence */
+ rtnl_unlock();
+ ret = register_hdlc_device(dev);
+ /* NOTE: <stats> setting must occur AFTER registration in order to "take" */
+ dev->tx_queue_len = MAX_DEFAULT_IFQLEN;
+
+ /* needed due to Ioctl calling sequence */
+ rtnl_lock();
+ if (ret) {
+ if (cxt1e1_log_level >= LOG_WARN)
+ pr_info("%s: create_chan[%d] registration error = %d.\n",
+ ci->devname, cp->channum, ret);
+ /* cleanup */
+ free_netdev(dev);
+ /* failed to register */
+ return NULL;
+ }
+ return dev;
}
/* the idea here is to get port information and pass it back (using pointer) */
-static status_t
-do_get_port (struct net_device *ndev, void *data)
+static status_t
+do_get_port(struct net_device *ndev, void *data)
{
- int ret;
- ci_t *ci; /* ci stands for card information */
- struct sbecom_port_param pp;/* copy data to kernel land */
-
- if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param)))
- return -EFAULT;
- if (pp.portnum >= MUSYCC_NPORTS)
- return -EFAULT;
- ci = get_ci_by_dev (ndev);
- if (!ci)
- return -EINVAL; /* get card info */
-
- ret = mkret (c4_get_port (ci, pp.portnum));
- if (ret)
- return ret;
- if (copy_to_user (data, &ci->port[pp.portnum].p,
- sizeof (struct sbecom_port_param)))
- return -EFAULT;
- return 0;
+ int ret;
+ ci_t *ci; /* ci stands for card information */
+ struct sbecom_port_param pp;/* copy data to kernel land */
+
+ if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param)))
+ return -EFAULT;
+ if (pp.portnum >= MUSYCC_NPORTS)
+ return -EFAULT;
+ ci = get_ci_by_dev(ndev);
+ if (!ci)
+ return -EINVAL; /* get card info */
+
+ ret = c4_get_port(ci, pp.portnum);
+ if (ret < 0)
+ return ret;
+ if (copy_to_user(data, &ci->port[pp.portnum].p,
+ sizeof(struct sbecom_port_param)))
+ return -EFAULT;
+ return 0;
}
/* this function copys the user data and then calls the real action function */
-static status_t
-do_set_port (struct net_device *ndev, void *data)
+static status_t
+do_set_port(struct net_device *ndev, void *data)
{
- ci_t *ci; /* ci stands for card information */
- struct sbecom_port_param pp;/* copy data to kernel land */
-
- if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param)))
- return -EFAULT;
- if (pp.portnum >= MUSYCC_NPORTS)
- return -EFAULT;
- ci = get_ci_by_dev (ndev);
- if (!ci)
- return -EINVAL; /* get card info */
-
- if (pp.portnum >= ci->max_port) /* sanity check */
- return -ENXIO;
-
- memcpy (&ci->port[pp.portnum].p, &pp, sizeof (struct sbecom_port_param));
- return mkret (c4_set_port (ci, pp.portnum));
+ ci_t *ci; /* ci stands for card information */
+ struct sbecom_port_param pp;/* copy data to kernel land */
+
+ if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param)))
+ return -EFAULT;
+ if (pp.portnum >= MUSYCC_NPORTS)
+ return -EFAULT;
+ ci = get_ci_by_dev(ndev);
+ if (!ci)
+ return -EINVAL; /* get card info */
+
+ if (pp.portnum >= ci->max_port) /* sanity check */
+ return -ENXIO;
+
+ memcpy(&ci->port[pp.portnum].p, &pp, sizeof(struct sbecom_port_param));
+ return c4_set_port(ci, pp.portnum);
}
/* work the port loopback mode as per directed */
-static status_t
-do_port_loop (struct net_device *ndev, void *data)
+static status_t
+do_port_loop(struct net_device *ndev, void *data)
{
- struct sbecom_port_param pp;
- ci_t *ci;
-
- if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param)))
- return -EFAULT;
- ci = get_ci_by_dev (ndev);
- if (!ci)
- return -EINVAL;
- return mkret (c4_loop_port (ci, pp.portnum, pp.port_mode));
+ struct sbecom_port_param pp;
+ ci_t *ci;
+
+ if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param)))
+ return -EFAULT;
+ ci = get_ci_by_dev(ndev);
+ if (!ci)
+ return -EINVAL;
+ return c4_loop_port(ci, pp.portnum, pp.port_mode);
}
/* set the specified register with the given value / or just read it */
-static status_t
-do_framer_rw (struct net_device *ndev, void *data)
+static status_t
+do_framer_rw(struct net_device *ndev, void *data)
{
- struct sbecom_port_param pp;
- ci_t *ci;
- int ret;
-
- if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param)))
- return -EFAULT;
- ci = get_ci_by_dev (ndev);
- if (!ci)
- return -EINVAL;
- ret = mkret (c4_frame_rw (ci, &pp));
- if (ret)
- return ret;
- if (copy_to_user (data, &pp, sizeof (struct sbecom_port_param)))
- return -EFAULT;
- return 0;
+ struct sbecom_port_param pp;
+ ci_t *ci;
+ int ret;
+
+ if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param)))
+ return -EFAULT;
+ ci = get_ci_by_dev(ndev);
+ if (!ci)
+ return -EINVAL;
+ ret = c4_frame_rw(ci, &pp);
+ if (ret < 0)
+ return ret;
+ if (copy_to_user(data, &pp, sizeof(struct sbecom_port_param)))
+ return -EFAULT;
+ return 0;
}
/* set the specified register with the given value / or just read it */
-static status_t
-do_pld_rw (struct net_device *ndev, void *data)
+static status_t
+do_pld_rw(struct net_device *ndev, void *data)
{
- struct sbecom_port_param pp;
- ci_t *ci;
- int ret;
-
- if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param)))
- return -EFAULT;
- ci = get_ci_by_dev (ndev);
- if (!ci)
- return -EINVAL;
- ret = mkret (c4_pld_rw (ci, &pp));
- if (ret)
- return ret;
- if (copy_to_user (data, &pp, sizeof (struct sbecom_port_param)))
- return -EFAULT;
- return 0;
+ struct sbecom_port_param pp;
+ ci_t *ci;
+ int ret;
+
+ if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param)))
+ return -EFAULT;
+ ci = get_ci_by_dev(ndev);
+ if (!ci)
+ return -EINVAL;
+
+ ret = c4_pld_rw(ci, &pp);
+ if (ret)
+ return ret;
+ if (copy_to_user(data, &pp, sizeof(struct sbecom_port_param)))
+ return -EFAULT;
+ return 0;
}
/* set the specified register with the given value / or just read it */
-static status_t
-do_musycc_rw (struct net_device *ndev, void *data)
+static status_t
+do_musycc_rw(struct net_device *ndev, void *data)
{
- struct c4_musycc_param mp;
- ci_t *ci;
- int ret;
-
- if (copy_from_user (&mp, data, sizeof (struct c4_musycc_param)))
- return -EFAULT;
- ci = get_ci_by_dev (ndev);
- if (!ci)
- return -EINVAL;
- ret = mkret (c4_musycc_rw (ci, &mp));
- if (ret)
- return ret;
- if (copy_to_user (data, &mp, sizeof (struct c4_musycc_param)))
- return -EFAULT;
- return 0;
+ struct c4_musycc_param mp;
+ ci_t *ci;
+ int ret;
+
+ if (copy_from_user(&mp, data, sizeof(struct c4_musycc_param)))
+ return -EFAULT;
+ ci = get_ci_by_dev(ndev);
+ if (!ci)
+ return -EINVAL;
+ ret = c4_musycc_rw(ci, &mp);
+ if (ret < 0)
+ return ret;
+ if (copy_to_user(data, &mp, sizeof(struct c4_musycc_param)))
+ return -EFAULT;
+ return 0;
}
-static status_t
-do_get_chan (struct net_device *ndev, void *data)
+static status_t
+do_get_chan(struct net_device *ndev, void *data)
{
- struct sbecom_chan_param cp;
- int ret;
+ struct sbecom_chan_param cp;
+ int ret;
- if (copy_from_user (&cp, data,
- sizeof (struct sbecom_chan_param)))
- return -EFAULT;
+ if (copy_from_user(&cp, data,
+ sizeof(struct sbecom_chan_param)))
+ return -EFAULT;
- if ((ret = mkret (c4_get_chan (cp.channum, &cp))))
- return ret;
+ ret = c4_get_chan(cp.channum, &cp);
+ if (ret < 0)
+ return ret;
- if (copy_to_user (data, &cp, sizeof (struct sbecom_chan_param)))
- return -EFAULT;
- return 0;
+ if (copy_to_user(data, &cp, sizeof(struct sbecom_chan_param)))
+ return -EFAULT;
+ return 0;
}
-static status_t
-do_set_chan (struct net_device *ndev, void *data)
+static status_t
+do_set_chan(struct net_device *ndev, void *data)
{
- struct sbecom_chan_param cp;
- int ret;
- ci_t *ci;
-
- if (copy_from_user (&cp, data, sizeof (struct sbecom_chan_param)))
- return -EFAULT;
- ci = get_ci_by_dev (ndev);
- if (!ci)
- return -EINVAL;
- switch (ret = mkret (c4_set_chan (cp.channum, &cp)))
- {
- case 0:
- return 0;
- default:
- return ret;
- }
+ struct sbecom_chan_param cp;
+ ci_t *ci;
+
+ if (copy_from_user(&cp, data, sizeof(struct sbecom_chan_param)))
+ return -EFAULT;
+ ci = get_ci_by_dev(ndev);
+ if (!ci)
+ return -EINVAL;
+ return c4_set_chan(cp.channum, &cp);
}
-static status_t
-do_create_chan (struct net_device *ndev, void *data)
+static status_t
+do_create_chan(struct net_device *ndev, void *data)
{
- ci_t *ci;
- struct net_device *dev;
- struct sbecom_chan_param cp;
- int ret;
-
- if (copy_from_user (&cp, data, sizeof (struct sbecom_chan_param)))
- return -EFAULT;
- ci = get_ci_by_dev (ndev);
- if (!ci)
- return -EINVAL;
- dev = create_chan (ndev, ci, &cp);
- if (!dev)
- return -EBUSY;
- ret = mkret (c4_new_chan (ci, cp.port, cp.channum, dev));
- if (ret)
- {
- rtnl_unlock (); /* needed due to Ioctl calling sequence */
- unregister_hdlc_device (dev);
- rtnl_lock (); /* needed due to Ioctl calling sequence */
- free_netdev (dev);
- }
- return ret;
+ ci_t *ci;
+ struct net_device *dev;
+ struct sbecom_chan_param cp;
+ int ret;
+
+ if (copy_from_user(&cp, data, sizeof(struct sbecom_chan_param)))
+ return -EFAULT;
+ ci = get_ci_by_dev(ndev);
+ if (!ci)
+ return -EINVAL;
+ dev = create_chan(ndev, ci, &cp);
+ if (!dev)
+ return -EBUSY;
+ ret = c4_new_chan(ci, cp.port, cp.channum, dev);
+ if (ret < 0) {
+ /* needed due to Ioctl calling sequence */
+ rtnl_unlock();
+ unregister_hdlc_device(dev);
+ /* needed due to Ioctl calling sequence */
+ rtnl_lock();
+ free_netdev(dev);
+ }
+ return ret;
}
-static status_t
-do_get_chan_stats (struct net_device *ndev, void *data)
+static status_t
+do_get_chan_stats(struct net_device *ndev, void *data)
{
- struct c4_chan_stats_wrap ccs;
- int ret;
-
- if (copy_from_user (&ccs, data,
- sizeof (struct c4_chan_stats_wrap)))
- return -EFAULT;
- switch (ret = mkret (c4_get_chan_stats (ccs.channum, &ccs.stats)))
- {
- case 0:
- break;
- default:
- return ret;
- }
- if (copy_to_user (data, &ccs,
- sizeof (struct c4_chan_stats_wrap)))
- return -EFAULT;
- return 0;
+ struct c4_chan_stats_wrap ccs;
+ int ret;
+
+ if (copy_from_user(&ccs, data,
+ sizeof(struct c4_chan_stats_wrap)))
+ return -EFAULT;
+
+ ret = c4_get_chan_stats(ccs.channum, &ccs.stats);
+ if (ret < 0)
+ return ret;
+
+ if (copy_to_user(data, &ccs,
+ sizeof(struct c4_chan_stats_wrap)))
+ return -EFAULT;
+ return 0;
}
-static status_t
-do_set_loglevel (struct net_device *ndev, void *data)
+static status_t
+do_set_loglevel(struct net_device *ndev, void *data)
{
- unsigned int cxt1e1_log_level;
+ unsigned int cxt1e1_log_level;
- if (copy_from_user (&cxt1e1_log_level, data, sizeof (int)))
- return -EFAULT;
- sbecom_set_loglevel (cxt1e1_log_level);
- return 0;
+ if (copy_from_user(&cxt1e1_log_level, data, sizeof(int)))
+ return -EFAULT;
+ sbecom_set_loglevel(cxt1e1_log_level);
+ return 0;
}
-static status_t
-do_deluser (struct net_device *ndev, int lockit)
+static status_t
+do_deluser(struct net_device *ndev, int lockit)
{
- if (ndev->flags & IFF_UP)
- return -EBUSY;
-
- {
- ci_t *ci;
- mch_t *ch;
- const struct c4_priv *priv;
- int channum;
-
- priv = (struct c4_priv *) dev_to_hdlc (ndev)->priv;
- ci = priv->ci;
- channum = priv->channum;
-
- ch = c4_find_chan (channum);
- if (ch == NULL)
- return -ENOENT;
- ch->user = NULL; /* will be freed, below */
- }
-
- if (lockit)
- rtnl_unlock (); /* needed if Ioctl calling sequence */
- unregister_hdlc_device (ndev);
- if (lockit)
- rtnl_lock (); /* needed if Ioctl calling sequence */
- free_netdev (ndev);
- return 0;
+ if (ndev->flags & IFF_UP)
+ return -EBUSY;
+
+ {
+ ci_t *ci;
+ mch_t *ch;
+ const struct c4_priv *priv;
+ int channum;
+
+ priv = (struct c4_priv *)dev_to_hdlc(ndev)->priv;
+ ci = priv->ci;
+ channum = priv->channum;
+
+ ch = c4_find_chan(channum);
+ if (ch == NULL)
+ return -ENOENT;
+ ch->user = NULL; /* will be freed, below */
+ }
+
+ /* needed if Ioctl calling sequence */
+ if (lockit)
+ rtnl_unlock();
+ unregister_hdlc_device(ndev);
+ /* needed if Ioctl calling sequence */
+ if (lockit)
+ rtnl_lock();
+ free_netdev(ndev);
+ return 0;
}
int
-do_del_chan (struct net_device *musycc_dev, void *data)
+do_del_chan(struct net_device *musycc_dev, void *data)
{
- struct sbecom_chan_param cp;
- char buf[sizeof (CHANNAME) + 3];
- struct net_device *dev;
- int ret;
-
- if (copy_from_user (&cp, data,
- sizeof (struct sbecom_chan_param)))
- return -EFAULT;
- if (cp.channum > 999)
- return -EINVAL;
- snprintf (buf, sizeof(buf), CHANNAME "%d", cp.channum);
+ struct sbecom_chan_param cp;
+ char buf[sizeof(CHANNAME) + 3];
+ struct net_device *dev;
+ int ret;
+
+ if (copy_from_user(&cp, data,
+ sizeof(struct sbecom_chan_param)))
+ return -EFAULT;
+ if (cp.channum > 999)
+ return -EINVAL;
+ snprintf(buf, sizeof(buf), CHANNAME "%d", cp.channum);
dev = __dev_get_by_name(&init_net, buf);
if (!dev)
return -ENODEV;
- ret = do_deluser (dev, 1);
- if (ret)
- return ret;
- return c4_del_chan (cp.channum);
+ ret = do_deluser(dev, 1);
+ if (ret)
+ return ret;
+ return c4_del_chan(cp.channum);
}
-int c4_reset_board (void *);
+int c4_reset_board(void *);
int
-do_reset (struct net_device *musycc_dev, void *data)
+do_reset(struct net_device *musycc_dev, void *data)
{
- const struct c4_priv *priv;
- int i;
-
- for (i = 0; i < 128; i++)
- {
- struct net_device *ndev;
- char buf[sizeof (CHANNAME) + 3];
-
- sprintf (buf, CHANNAME "%d", i);
- ndev = __dev_get_by_name(&init_net, buf);
- if (!ndev)
- continue;
- priv = dev_to_hdlc (ndev)->priv;
-
- if ((unsigned long) (priv->ci) ==
- (unsigned long) (netdev_priv(musycc_dev)))
- {
- ndev->flags &= ~IFF_UP;
- netif_stop_queue (ndev);
- do_deluser (ndev, 1);
+ const struct c4_priv *priv;
+ int i;
+
+ for (i = 0; i < 128; i++) {
+ struct net_device *ndev;
+ char buf[sizeof(CHANNAME) + 3];
+
+ sprintf(buf, CHANNAME "%d", i);
+ ndev = __dev_get_by_name(&init_net, buf);
+ if (!ndev)
+ continue;
+ priv = dev_to_hdlc(ndev)->priv;
+
+ if ((unsigned long) (priv->ci) ==
+ (unsigned long) (netdev_priv(musycc_dev))) {
+ ndev->flags &= ~IFF_UP;
+ netif_stop_queue(ndev);
+ do_deluser(ndev, 1);
+ }
}
- }
- return 0;
+ return 0;
}
int
-do_reset_chan_stats (struct net_device *musycc_dev, void *data)
+do_reset_chan_stats(struct net_device *musycc_dev, void *data)
{
- struct sbecom_chan_param cp;
+ struct sbecom_chan_param cp;
- if (copy_from_user (&cp, data,
- sizeof (struct sbecom_chan_param)))
- return -EFAULT;
- return mkret (c4_del_chan_stats (cp.channum));
+ if (copy_from_user(&cp, data,
+ sizeof(struct sbecom_chan_param)))
+ return -EFAULT;
+ return c4_del_chan_stats(cp.channum);
}
-static status_t
-c4_ioctl (struct net_device *ndev, struct ifreq *ifr, int cmd)
+static status_t
+c4_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
{
- ci_t *ci;
- void *data;
- int iocmd, iolen;
- status_t ret;
- static struct data
- {
- union
- {
- u_int8_t c;
- u_int32_t i;
- struct sbe_brd_info bip;
- struct sbe_drv_info dip;
- struct sbe_iid_info iip;
- struct sbe_brd_addr bap;
- struct sbecom_chan_stats stats;
- struct sbecom_chan_param param;
- struct temux_card_stats cards;
- struct sbecom_card_param cardp;
- struct sbecom_framer_param frp;
- } u;
- } arg;
-
-
- if (!capable (CAP_SYS_ADMIN))
- return -EPERM;
- if (cmd != SIOCDEVPRIVATE + 15)
- return -EINVAL;
- if (!(ci = get_ci_by_dev (ndev)))
- return -EINVAL;
- if (ci->state != C_RUNNING)
- return -ENODEV;
- if (copy_from_user (&iocmd, ifr->ifr_data, sizeof (iocmd)))
- return -EFAULT;
+ ci_t *ci;
+ void *data;
+ int iocmd, iolen;
+ status_t ret;
+ static struct data {
+ union {
+ u_int8_t c;
+ u_int32_t i;
+ struct sbe_brd_info bip;
+ struct sbe_drv_info dip;
+ struct sbe_iid_info iip;
+ struct sbe_brd_addr bap;
+ struct sbecom_chan_stats stats;
+ struct sbecom_chan_param param;
+ struct temux_card_stats cards;
+ struct sbecom_card_param cardp;
+ struct sbecom_framer_param frp;
+ } u;
+ } arg;
+
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (cmd != SIOCDEVPRIVATE + 15)
+ return -EINVAL;
+ ci = get_ci_by_dev(ndev);
+ if (!ci)
+ return -EINVAL;
+ if (ci->state != C_RUNNING)
+ return -ENODEV;
+ if (copy_from_user(&iocmd, ifr->ifr_data, sizeof(iocmd)))
+ return -EFAULT;
#if 0
- if (copy_from_user (&len, ifr->ifr_data + sizeof (iocmd), sizeof (len)))
- return -EFAULT;
+ if (copy_from_user(&len, ifr->ifr_data + sizeof(iocmd), sizeof(len)))
+ return -EFAULT;
#endif
#if 0
- pr_info("c4_ioctl: iocmd %x, dir %x type %x nr %x iolen %d.\n", iocmd,
- _IOC_DIR (iocmd), _IOC_TYPE (iocmd), _IOC_NR (iocmd),
- _IOC_SIZE (iocmd));
+ pr_info("c4_ioctl: iocmd %x, dir %x type %x nr %x iolen %d.\n", iocmd,
+ _IOC_DIR(iocmd), _IOC_TYPE(iocmd), _IOC_NR(iocmd),
+ _IOC_SIZE(iocmd));
#endif
- iolen = _IOC_SIZE (iocmd);
- data = ifr->ifr_data + sizeof (iocmd);
- if (copy_from_user (&arg, data, iolen))
- return -EFAULT;
-
- ret = 0;
- switch (iocmd)
- {
- case SBE_IOC_PORT_GET:
- //pr_info(">> SBE_IOC_PORT_GET Ioctl...\n");
- ret = do_get_port (ndev, data);
- break;
- case SBE_IOC_PORT_SET:
- //pr_info(">> SBE_IOC_PORT_SET Ioctl...\n");
- ret = do_set_port (ndev, data);
- break;
- case SBE_IOC_CHAN_GET:
- //pr_info(">> SBE_IOC_CHAN_GET Ioctl...\n");
- ret = do_get_chan (ndev, data);
- break;
- case SBE_IOC_CHAN_SET:
- //pr_info(">> SBE_IOC_CHAN_SET Ioctl...\n");
- ret = do_set_chan (ndev, data);
- break;
- case C4_DEL_CHAN:
- //pr_info(">> C4_DEL_CHAN Ioctl...\n");
- ret = do_del_chan (ndev, data);
- break;
- case SBE_IOC_CHAN_NEW:
- ret = do_create_chan (ndev, data);
- break;
- case SBE_IOC_CHAN_GET_STAT:
- ret = do_get_chan_stats (ndev, data);
- break;
- case SBE_IOC_LOGLEVEL:
- ret = do_set_loglevel (ndev, data);
- break;
- case SBE_IOC_RESET_DEV:
- ret = do_reset (ndev, data);
- break;
- case SBE_IOC_CHAN_DEL_STAT:
- ret = do_reset_chan_stats (ndev, data);
- break;
- case C4_LOOP_PORT:
- ret = do_port_loop (ndev, data);
- break;
- case C4_RW_FRMR:
- ret = do_framer_rw (ndev, data);
- break;
- case C4_RW_MSYC:
- ret = do_musycc_rw (ndev, data);
- break;
- case C4_RW_PLD:
- ret = do_pld_rw (ndev, data);
- break;
- case SBE_IOC_IID_GET:
- ret = (iolen == sizeof (struct sbe_iid_info)) ? c4_get_iidinfo (ci, &arg.u.iip) : -EFAULT;
- if (ret == 0) /* no error, copy data */
- if (copy_to_user (data, &arg, iolen))
- return -EFAULT;
- break;
- default:
- //pr_info(">> c4_ioctl: EINVAL - unknown iocmd <%x>\n", iocmd);
- ret = -EINVAL;
- break;
- }
- return mkret (ret);
+ iolen = _IOC_SIZE(iocmd);
+ if (iolen > sizeof(arg))
+ return -EFAULT;
+ data = ifr->ifr_data + sizeof(iocmd);
+ if (copy_from_user(&arg, data, iolen))
+ return -EFAULT;
+
+ ret = 0;
+ switch (iocmd) {
+ case SBE_IOC_PORT_GET:
+ ret = do_get_port(ndev, data);
+ break;
+ case SBE_IOC_PORT_SET:
+ ret = do_set_port(ndev, data);
+ break;
+ case SBE_IOC_CHAN_GET:
+ ret = do_get_chan(ndev, data);
+ break;
+ case SBE_IOC_CHAN_SET:
+ ret = do_set_chan(ndev, data);
+ break;
+ case C4_DEL_CHAN:
+ ret = do_del_chan(ndev, data);
+ break;
+ case SBE_IOC_CHAN_NEW:
+ ret = do_create_chan(ndev, data);
+ break;
+ case SBE_IOC_CHAN_GET_STAT:
+ ret = do_get_chan_stats(ndev, data);
+ break;
+ case SBE_IOC_LOGLEVEL:
+ ret = do_set_loglevel(ndev, data);
+ break;
+ case SBE_IOC_RESET_DEV:
+ ret = do_reset(ndev, data);
+ break;
+ case SBE_IOC_CHAN_DEL_STAT:
+ ret = do_reset_chan_stats(ndev, data);
+ break;
+ case C4_LOOP_PORT:
+ ret = do_port_loop(ndev, data);
+ break;
+ case C4_RW_FRMR:
+ ret = do_framer_rw(ndev, data);
+ break;
+ case C4_RW_MSYC:
+ ret = do_musycc_rw(ndev, data);
+ break;
+ case C4_RW_PLD:
+ ret = do_pld_rw(ndev, data);
+ break;
+ case SBE_IOC_IID_GET:
+ ret = (iolen == sizeof(struct sbe_iid_info)) ?
+ c4_get_iidinfo(ci, &arg.u.iip) : -EFAULT;
+ if (ret == 0) /* no error, copy data */
+ if (copy_to_user(data, &arg, iolen))
+ return -EFAULT;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
}
static const struct net_device_ops c4_ops = {
- .ndo_open = void_open,
- .ndo_start_xmit = c4_linux_xmit,
- .ndo_do_ioctl = c4_ioctl,
+ .ndo_open = void_open,
+ .ndo_start_xmit = c4_linux_xmit,
+ .ndo_do_ioctl = c4_ioctl,
};
static void c4_setup(struct net_device *dev)
{
- dev->type = ARPHRD_VOID;
- dev->netdev_ops = &c4_ops;
+ dev->type = ARPHRD_VOID;
+ dev->netdev_ops = &c4_ops;
}
struct net_device *__init
-c4_add_dev (hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1,
- int irq0, int irq1)
+c4_add_dev(hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1,
+ int irq0, int irq1)
{
- struct net_device *ndev;
- ci_t *ci;
-
- ndev = alloc_netdev(sizeof(ci_t), SBE_IFACETMPL, c4_setup);
- if (!ndev)
- {
- pr_warning("%s: no memory for struct net_device !\n", hi->devname);
- error_flag = ENOMEM;
- return NULL;
- }
- ci = (ci_t *)(netdev_priv(ndev));
- ndev->irq = irq0;
-
- ci->hdw_info = hi;
- ci->state = C_INIT; /* mark as hardware not available */
- ci->next = c4_list;
- c4_list = ci;
- ci->brdno = ci->next ? ci->next->brdno + 1 : 0;
-
- if (!CI)
- CI = ci; /* DEBUG, only board 0 usage */
-
- strcpy (ci->devname, hi->devname);
- ci->release = &pmcc4_OSSI_release[0];
-
- /* tasklet */
+ struct net_device *ndev;
+ ci_t *ci;
+
+ ndev = alloc_netdev(sizeof(ci_t), SBE_IFACETMPL, c4_setup);
+ if (!ndev) {
+ pr_warning("%s: no memory for struct net_device !\n",
+ hi->devname);
+ error_flag = -ENOMEM;
+ return NULL;
+ }
+ ci = (ci_t *)(netdev_priv(ndev));
+ ndev->irq = irq0;
+
+ ci->hdw_info = hi;
+ ci->state = C_INIT; /* mark as hardware not available */
+ ci->next = c4_list;
+ c4_list = ci;
+ ci->brdno = ci->next ? ci->next->brdno + 1 : 0;
+
+ if (!CI)
+ CI = ci; /* DEBUG, only board 0 usage */
+
+ strcpy(ci->devname, hi->devname);
+
+ /* tasklet */
#if defined(SBE_ISR_TASKLET)
- tasklet_init (&ci->ci_musycc_isr_tasklet,
- (void (*) (unsigned long)) musycc_intr_bh_tasklet,
- (unsigned long) ci);
+ tasklet_init(&ci->ci_musycc_isr_tasklet,
+ (void (*) (unsigned long)) musycc_intr_bh_tasklet,
+ (unsigned long) ci);
- if (atomic_read (&ci->ci_musycc_isr_tasklet.count) == 0)
- tasklet_disable_nosync (&ci->ci_musycc_isr_tasklet);
+ if (atomic_read(&ci->ci_musycc_isr_tasklet.count) == 0)
+ tasklet_disable_nosync(&ci->ci_musycc_isr_tasklet);
#elif defined(SBE_ISR_IMMEDIATE)
- ci->ci_musycc_isr_tq.routine = (void *) (unsigned long) musycc_intr_bh_tasklet;
- ci->ci_musycc_isr_tq.data = ci;
+ ci->ci_musycc_isr_tq.routine = (void *)(unsigned long)musycc_intr_bh_tasklet;
+ ci->ci_musycc_isr_tq.data = ci;
#endif
- if (register_netdev (ndev) ||
- (c4_init (ci, (u_char *) f0, (u_char *) f1) != SBE_DRVR_SUCCESS))
- {
- OS_kfree (netdev_priv(ndev));
- OS_kfree (ndev);
- error_flag = ENODEV;
- return NULL;
- }
- /*************************************************************
- * int request_irq(unsigned int irq,
- * void (*handler)(int, void *, struct pt_regs *),
- * unsigned long flags, const char *dev_name, void *dev_id);
- * wherein:
- * irq -> The interrupt number that is being requested.
- * handler -> Pointer to handling function being installed.
- * flags -> A bit mask of options related to interrupt management.
- * dev_name -> String used in /proc/interrupts to show owner of interrupt.
- * dev_id -> Pointer (for shared interrupt lines) to point to its own
- * private data area (to identify which device is interrupting).
- *
- * extern void free_irq(unsigned int irq, void *dev_id);
- **************************************************************/
-
- if (request_irq (irq0, &c4_linux_interrupt,
- IRQF_SHARED,
- ndev->name, ndev))
- {
- pr_warning("%s: MUSYCC could not get irq: %d\n", ndev->name, irq0);
- unregister_netdev (ndev);
- OS_kfree (netdev_priv(ndev));
- OS_kfree (ndev);
- error_flag = EIO;
- return NULL;
- }
+ if (register_netdev(ndev) ||
+ (c4_init(ci, (u_char *) f0, (u_char *) f1) != SBE_DRVR_SUCCESS)) {
+ OS_kfree(netdev_priv(ndev));
+ OS_kfree(ndev);
+ error_flag = -ENODEV;
+ return NULL;
+ }
+ /*************************************************************
+ * int request_irq(unsigned int irq,
+ * void (*handler)(int, void *, struct pt_regs *),
+ * unsigned long flags, const char *dev_name, void *dev_id);
+ * wherein:
+ * irq -> The interrupt number that is being requested.
+ * handler -> Pointer to handling function being installed.
+ * flags -> A bit mask of options related to interrupt management.
+ * dev_name -> String used in /proc/interrupts to show owner of interrupt.
+ * dev_id -> Pointer (for shared interrupt lines) to point to its own
+ * private data area (to identify which device is interrupting).
+ *
+ * extern void free_irq(unsigned int irq, void *dev_id);
+ **************************************************************/
+
+ if (request_irq(irq0, &c4_linux_interrupt,
+ IRQF_SHARED,
+ ndev->name, ndev)) {
+ pr_warning("%s: MUSYCC could not get irq: %d\n",
+ ndev->name, irq0);
+ unregister_netdev(ndev);
+ OS_kfree(netdev_priv(ndev));
+ OS_kfree(ndev);
+ error_flag = -EIO;
+ return NULL;
+ }
#ifdef CONFIG_SBE_PMCC4_NCOMM
- if (request_irq (irq1, &c4_ebus_interrupt, IRQF_SHARED, ndev->name, ndev))
- {
- pr_warning("%s: EBUS could not get irq: %d\n", hi->devname, irq1);
- unregister_netdev (ndev);
- free_irq (irq0, ndev);
- OS_kfree (netdev_priv(ndev));
- OS_kfree (ndev);
- error_flag = EIO;
- return NULL;
- }
+ if (request_irq(irq1, &c4_ebus_interrupt, IRQF_SHARED, ndev->name, ndev)) {
+ pr_warning("%s: EBUS could not get irq: %d\n", hi->devname, irq1);
+ unregister_netdev(ndev);
+ free_irq(irq0, ndev);
+ OS_kfree(netdev_priv(ndev));
+ OS_kfree(ndev);
+ error_flag = -EIO;
+ return NULL;
+ }
#endif
- /* setup board identification information */
-
- {
- u_int32_t tmp;
-
- hdw_sn_get (hi, brdno); /* also sets PROM format type (promfmt)
- * for later usage */
-
- switch (hi->promfmt)
- {
- case PROM_FORMAT_TYPE1:
- memcpy (ndev->dev_addr, (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6);
- memcpy (&tmp, (FLD_TYPE1 *) (hi->mfg_info.pft1.Id), 4); /* unaligned data
- * acquisition */
- ci->brd_id = cpu_to_be32 (tmp);
- break;
- case PROM_FORMAT_TYPE2:
- memcpy (ndev->dev_addr, (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6);
- memcpy (&tmp, (FLD_TYPE2 *) (hi->mfg_info.pft2.Id), 4); /* unaligned data
- * acquisition */
- ci->brd_id = cpu_to_be32 (tmp);
- break;
- default:
- ci->brd_id = 0;
- memset (ndev->dev_addr, 0, 6);
- break;
- }
+ /* setup board identification information */
+
+ {
+ u_int32_t tmp;
+
+ /* also sets PROM format type (promfmt) for later usage */
+ hdw_sn_get(hi, brdno);
+
+ switch (hi->promfmt) {
+ case PROM_FORMAT_TYPE1:
+ memcpy(ndev->dev_addr,
+ (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6);
+ /* unaligned data acquisition */
+ memcpy(&tmp, (FLD_TYPE1 *) (hi->mfg_info.pft1.Id), 4);
+ ci->brd_id = cpu_to_be32(tmp);
+ break;
+ case PROM_FORMAT_TYPE2:
+ memcpy(ndev->dev_addr,
+ (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6);
+ /* unaligned data acquisition */
+ memcpy(&tmp, (FLD_TYPE2 *) (hi->mfg_info.pft2.Id), 4);
+ ci->brd_id = cpu_to_be32(tmp);
+ break;
+ default:
+ ci->brd_id = 0;
+ memset(ndev->dev_addr, 0, 6);
+ break;
+ }
#if 1
- sbeid_set_hdwbid (ci); /* requires bid to be preset */
+ /* requires bid to be preset */
+ sbeid_set_hdwbid(ci);
#else
- sbeid_set_bdtype (ci); /* requires hdw_bid to be preset */
+ /* requires hdw_bid to be preset */
+ sbeid_set_bdtype(ci);
#endif
-
- }
+ }
#ifdef CONFIG_PROC_FS
- sbecom_proc_brd_init (ci);
+ sbecom_proc_brd_init(ci);
#endif
#if defined(SBE_ISR_TASKLET)
- tasklet_enable (&ci->ci_musycc_isr_tasklet);
+ tasklet_enable(&ci->ci_musycc_isr_tasklet);
#endif
-
- if ((error_flag = c4_init2 (ci)) != SBE_DRVR_SUCCESS)
- {
+ error_flag = c4_init2(ci);
+ if (error_flag != SBE_DRVR_SUCCESS) {
#ifdef CONFIG_PROC_FS
- sbecom_proc_brd_cleanup (ci);
+ sbecom_proc_brd_cleanup(ci);
#endif
- unregister_netdev (ndev);
- free_irq (irq1, ndev);
- free_irq (irq0, ndev);
- OS_kfree (netdev_priv(ndev));
- OS_kfree (ndev);
- return NULL; /* failure, error_flag is set */
- }
- return ndev;
+ unregister_netdev(ndev);
+ free_irq(irq1, ndev);
+ free_irq(irq0, ndev);
+ OS_kfree(netdev_priv(ndev));
+ OS_kfree(ndev);
+ /* failure, error_flag is set */
+ return NULL;
+ }
+ return ndev;
}
static int __init
-c4_mod_init (void)
+c4_mod_init(void)
{
- int rtn;
-
- pr_warning("%s\n", pmcc4_OSSI_release);
- if ((rtn = c4hw_attach_all ()))
- return -rtn; /* installation failure - see system log */
-
- /* housekeeping notifications */
- if (cxt1e1_log_level != log_level_default)
- pr_info("NOTE: driver parameter <cxt1e1_log_level> changed from default %d to %d.\n",
- log_level_default, cxt1e1_log_level);
- if (cxt1e1_max_mru != max_mru_default)
- pr_info("NOTE: driver parameter <cxt1e1_max_mru> changed from default %d to %d.\n",
- max_mru_default, cxt1e1_max_mru);
- if (cxt1e1_max_mtu != max_mtu_default)
- pr_info("NOTE: driver parameter <cxt1e1_max_mtu> changed from default %d to %d.\n",
- max_mtu_default, cxt1e1_max_mtu);
- if (max_rxdesc_used != max_rxdesc_default)
- {
- if (max_rxdesc_used > 2000)
- max_rxdesc_used = 2000; /* out-of-bounds reset */
- pr_info("NOTE: driver parameter <max_rxdesc_used> changed from default %d to %d.\n",
- max_rxdesc_default, max_rxdesc_used);
- }
- if (max_txdesc_used != max_txdesc_default)
- {
- if (max_txdesc_used > 1000)
- max_txdesc_used = 1000; /* out-of-bounds reset */
- pr_info("NOTE: driver parameter <max_txdesc_used> changed from default %d to %d.\n",
- max_txdesc_default, max_txdesc_used);
- }
- return 0; /* installation success */
+ int rtn;
+
+ rtn = c4hw_attach_all();
+ if (rtn)
+ return -rtn; /* installation failure - see system log */
+
+ /* housekeeping notifications */
+ if (cxt1e1_log_level != log_level_default)
+ pr_info("NOTE: driver parameter <cxt1e1_log_level> changed from default %d to %d.\n",
+ log_level_default, cxt1e1_log_level);
+ if (cxt1e1_max_mru != max_mru_default)
+ pr_info("NOTE: driver parameter <cxt1e1_max_mru> changed from default %d to %d.\n",
+ max_mru_default, cxt1e1_max_mru);
+ if (cxt1e1_max_mtu != max_mtu_default)
+ pr_info("NOTE: driver parameter <cxt1e1_max_mtu> changed from default %d to %d.\n",
+ max_mtu_default, cxt1e1_max_mtu);
+ if (max_rxdesc_used != max_rxdesc_default) {
+ if (max_rxdesc_used > 2000)
+ max_rxdesc_used = 2000; /* out-of-bounds reset */
+ pr_info("NOTE: driver parameter <max_rxdesc_used> changed from default %d to %d.\n",
+ max_rxdesc_default, max_rxdesc_used);
+ }
+ if (max_txdesc_used != max_txdesc_default) {
+ if (max_txdesc_used > 1000)
+ max_txdesc_used = 1000; /* out-of-bounds reset */
+ pr_info("NOTE: driver parameter <max_txdesc_used> changed from default %d to %d.\n",
+ max_txdesc_default, max_txdesc_used);
+ }
+ return 0; /* installation success */
}
@@ -1138,31 +1117,29 @@ c4_mod_init (void)
*/
static void __exit
-cleanup_hdlc (void)
+cleanup_hdlc(void)
{
- hdw_info_t *hi;
- ci_t *ci;
- struct net_device *ndev;
- int i, j, k;
-
- for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
- {
- if (hi->ndev) /* a board has been attached */
- {
- ci = (ci_t *)(netdev_priv(hi->ndev));
- for (j = 0; j < ci->max_port; j++)
- for (k = 0; k < MUSYCC_NCHANS; k++)
- if ((ndev = ci->port[j].chan[k]->user))
- {
- do_deluser (ndev, 0);
- }
- }
- }
+ hdw_info_t *hi;
+ ci_t *ci;
+ struct net_device *ndev;
+ int i, j, k;
+
+ for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) {
+ if (hi->ndev) { /* a board has been attached */
+ ci = (ci_t *)(netdev_priv(hi->ndev));
+ for (j = 0; j < ci->max_port; j++)
+ for (k = 0; k < MUSYCC_NCHANS; k++) {
+ ndev = ci->port[j].chan[k]->user;
+ if (ndev)
+ do_deluser(ndev, 0);
+ }
+ }
+ }
}
static void __exit
-c4_mod_remove (void)
+c4_mod_remove(void)
{
cleanup_hdlc(); /* delete any missed channels */
cleanup_devs();
@@ -1171,13 +1148,13 @@ c4_mod_remove (void)
pr_info("SBE - driver removed.\n");
}
-module_init (c4_mod_init);
-module_exit (c4_mod_remove);
+module_init(c4_mod_init);
+module_exit(c4_mod_remove);
-MODULE_AUTHOR ("SBE Technical Services <support@sbei.com>");
-MODULE_DESCRIPTION ("wanPCI-CxT1E1 Generic HDLC WAN Driver module");
+MODULE_AUTHOR("SBE Technical Services <support@sbei.com>");
+MODULE_DESCRIPTION("wanPCI-CxT1E1 Generic HDLC WAN Driver module");
#ifdef MODULE_LICENSE
-MODULE_LICENSE ("GPL");
+MODULE_LICENSE("GPL");
#endif
/*** End-of-File ***/
diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c
index 7a3a30cd0f7f..7b4f6f2108e3 100644
--- a/drivers/staging/cxt1e1/musycc.c
+++ b/drivers/staging/cxt1e1/musycc.c
@@ -42,7 +42,6 @@ static unsigned int max_bh = 0;
/* global driver variables */
extern ci_t *c4_list;
extern int drvr_state;
-extern int cxt1e1_log_level;
extern int cxt1e1_max_mru;
extern int cxt1e1_max_mtu;
@@ -217,7 +216,8 @@ musycc_dump_ring(ci_t *ci, unsigned int chan)
max_intcnt = 0; /* reset counter */
}
- if (!(ch = sd_find_chan(dummy, chan))) {
+ ch = sd_find_chan(dummy, chan);
+ if (!ch) {
pr_info(">> musycc_dump_ring: channel %d not up.\n", chan);
return ENOENT;
}
@@ -1044,17 +1044,19 @@ musycc_bh_rx_eom(mpi_t *pi, int gchan)
#endif /*** CONFIG_SBE_WAN256T3_NCOMM ***/
{
- if ((m2 = OS_mem_token_alloc(cxt1e1_max_mru))) {
- /* substitute the mbuf+cluster */
- md->mem_token = m2;
- md->data = cpu_to_le32(OS_vtophys(OS_mem_token_data(m2)));
-
- /* pass the received mbuf upward */
- sd_recv_consume(m, status & LENGTH_MASK, ch->user);
- ch->s.rx_packets++;
- ch->s.rx_bytes += status & LENGTH_MASK;
+ m2 = OS_mem_token_alloc(cxt1e1_max_mru);
+ if (m2) {
+ /* substitute the mbuf+cluster */
+ md->mem_token = m2;
+ md->data = cpu_to_le32(OS_vtophys(
+ OS_mem_token_data(m2)));
+
+ /* pass the received mbuf upward */
+ sd_recv_consume(m, status & LENGTH_MASK, ch->user);
+ ch->s.rx_packets++;
+ ch->s.rx_bytes += status & LENGTH_MASK;
} else
- ch->s.rx_dropped++;
+ ch->s.rx_dropped++;
}
} else if (error == ERR_FCS)
ch->s.rx_crc_errors++;
@@ -1545,8 +1547,9 @@ musycc_chan_down(ci_t *dummy, int channum)
mch_t *ch;
int i, gchan;
- if (!(ch = sd_find_chan(dummy, channum)))
- return EINVAL;
+ ch = sd_find_chan(dummy, channum);
+ if (!ch)
+ return -EINVAL;
pi = ch->up;
gchan = ch->gchan;
@@ -1589,6 +1592,8 @@ musycc_chan_down(ci_t *dummy, int channum)
#endif
+#if 0
+/* TODO: determine if these functions will not be needed and can be removed */
int
musycc_del_chan(ci_t *ci, int channum)
{
@@ -1596,7 +1601,8 @@ musycc_del_chan(ci_t *ci, int channum)
if ((channum < 0) || (channum >= (MUSYCC_NPORTS * MUSYCC_NCHANS))) /* sanity chk param */
return ECHRNG;
- if (!(ch = sd_find_chan(ci, channum)))
+ ch = sd_find_chan(ci, channum);
+ if (!ch)
return ENOENT;
if (ch->state == UP)
musycc_chan_down(ci, channum);
@@ -1612,12 +1618,14 @@ musycc_del_chan_stats(ci_t *ci, int channum)
if (channum < 0 || channum >= (MUSYCC_NPORTS * MUSYCC_NCHANS)) /* sanity chk param */
return ECHRNG;
- if (!(ch = sd_find_chan(ci, channum)))
+ ch = sd_find_chan(ci, channum);
+ if (!ch)
return ENOENT;
memset(&ch->s, 0, sizeof(struct sbecom_chan_stats));
return 0;
}
+#endif
int
@@ -1632,7 +1640,8 @@ musycc_start_xmit(ci_t *ci, int channum, void *mem_token)
int txd_need_cnt;
u_int32_t len;
- if (!(ch = sd_find_chan(ci, channum)))
+ ch = sd_find_chan(ci, channum);
+ if (!ch)
return -ENOENT;
if (ci->state != C_RUNNING) /* full interrupt processing available */
diff --git a/drivers/staging/cxt1e1/ossiRelease.c b/drivers/staging/cxt1e1/ossiRelease.c
deleted file mode 100644
index f17a902e95e3..000000000000
--- a/drivers/staging/cxt1e1/ossiRelease.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*-----------------------------------------------------------------------------
- * ossiRelease.c -
- *
- * This string will be embedded into the executable and will track the
- * release. The embedded string may be displayed using the following:
- *
- * strings <filename> | grep \$Rel
- *
- * Copyright (C) 2002-2008 One Stop Systems, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 further information, contact via email: support@onestopsystems.com
- * One Stop Systems, Inc. Escondido, California U.S.A.
- *
- *-----------------------------------------------------------------------------
- */
-
-char pmcc4_OSSI_release[] = "$Release: PMCC4_3_1B, Copyright (c) 2008 One Stop Systems$";
-
-/*** End-of-File ***/
diff --git a/drivers/staging/cxt1e1/pmc93x6_eeprom.c b/drivers/staging/cxt1e1/pmc93x6_eeprom.c
index 137b63cb5537..78cc1709ebdb 100644
--- a/drivers/staging/cxt1e1/pmc93x6_eeprom.c
+++ b/drivers/staging/cxt1e1/pmc93x6_eeprom.c
@@ -90,7 +90,7 @@ static int ByteReverseBuilt = FALSE;
*------------------------------------------------------------------------
*/
-short mfg_template[sizeof (FLD_TYPE2)] =
+static u8 mfg_template[sizeof(FLD_TYPE2)] =
{
PROM_FORMAT_TYPE2, /* type; */
0x00, 0x1A, /* length[2]; */
@@ -491,13 +491,11 @@ pmc_init_seeprom (u_int32_t addr, u_int32_t serialNum)
PROMFORMAT buffer; /* Memory image of structure */
u_int32_t crc; /* CRC of structure */
time_t createTime;
- int i;
createTime = get_seconds ();
/* use template data */
- for (i = 0; i < sizeof (FLD_TYPE2); ++i)
- buffer.bytes[i] = mfg_template[i];
+ memcpy(&buffer.fldType2, mfg_template, sizeof(buffer.fldType2));
/* Update serial number field in buffer */
pmcSetBuffValue (&buffer.fldType2.Serial[3], serialNum, 3);
diff --git a/drivers/staging/cxt1e1/pmcc4.h b/drivers/staging/cxt1e1/pmcc4.h
index 003eb8690190..b4b5e5ad791b 100644
--- a/drivers/staging/cxt1e1/pmcc4.h
+++ b/drivers/staging/cxt1e1/pmcc4.h
@@ -96,7 +96,6 @@ void sbeid_set_bdtype (ci_t *ci);
void sbeid_set_hdwbid (ci_t *ci);
u_int32_t sbeCrc (u_int8_t *, u_int32_t, u_int32_t, u_int32_t *);
-void VMETRO_TRACE (void *); /* put data into 8 LEDs */
void VMETRO_TRIGGER (ci_t *, int); /* Note: int = 0(default)
* thru 15 */
diff --git a/drivers/staging/cxt1e1/pmcc4_drv.c b/drivers/staging/cxt1e1/pmcc4_drv.c
index a9d95753be20..621a72926475 100644
--- a/drivers/staging/cxt1e1/pmcc4_drv.c
+++ b/drivers/staging/cxt1e1/pmcc4_drv.c
@@ -112,12 +112,12 @@ c4_find_chan (int channum)
for (portnum = 0; portnum < ci->max_port; portnum++)
for (gchan = 0; gchan < MUSYCC_NCHANS; gchan++)
{
- if ((ch = ci->port[portnum].chan[gchan]))
- {
- if ((ch->state != UNASSIGNED) &&
- (ch->channum == channum))
- return ch;
- }
+ ch = ci->port[portnum].chan[gchan];
+ if (ch) {
+ if ((ch->state != UNASSIGNED) &&
+ (ch->channum == channum))
+ return ch;
+ }
}
return NULL;
}
@@ -668,8 +668,9 @@ c4_init2 (ci_t *ci)
status_t ret;
/* PORT POINT: this routine generates first interrupt */
- if ((ret = musycc_init (ci)) != SBE_DRVR_SUCCESS)
- return ret;
+ ret = musycc_init(ci);
+ if (ret != SBE_DRVR_SUCCESS)
+ return ret;
#if 0
ci->p.framing_type = FRAMING_CBP;
@@ -756,7 +757,7 @@ c4_frame_rw (ci_t *ci, struct sbecom_port_param *pp)
volatile u_int32_t data;
if (pp->portnum >= ci->max_port)/* sanity check */
- return ENXIO;
+ return -ENXIO;
comet = ci->port[pp->portnum].cometbase;
data = pci_read_32 ((u_int32_t *) comet + pp->port_mode) & 0xff;
@@ -845,7 +846,7 @@ c4_musycc_rw (ci_t *ci, struct c4_musycc_param *mcp)
*/
portnum = (mcp->offset % 0x6000) / 0x800;
if (portnum >= ci->max_port)
- return ENXIO;
+ return -ENXIO;
pi = &ci->port[portnum];
if (mcp->offset >= 0x6000)
offset += 0x6000; /* put back in MsgCfgDesc address offset */
@@ -894,7 +895,7 @@ status_t
c4_get_port (ci_t *ci, int portnum)
{
if (portnum >= ci->max_port) /* sanity check */
- return ENXIO;
+ return -ENXIO;
SD_SEM_TAKE (&ci->sem_wdbusy, "_wd_"); /* only 1 thru here, per
* board */
@@ -915,7 +916,7 @@ c4_set_port (ci_t *ci, int portnum)
int i;
if (portnum >= ci->max_port) /* sanity check */
- return ENXIO;
+ return -ENXIO;
pi = &ci->port[portnum];
pp = &ci->port[portnum].p;
@@ -927,15 +928,15 @@ c4_set_port (ci_t *ci, int portnum)
portnum, e1mode, pi->openchans);
}
if (pi->openchans)
- return EBUSY; /* group needs initialization only for
+ return -EBUSY; /* group needs initialization only for
* first channel of a group */
{
status_t ret;
- if ((ret = c4_wq_port_init (pi))) /* create/init
- * workqueue_struct */
- return ret;
+ ret = c4_wq_port_init(pi);
+ if (ret) /* create/init workqueue_struct */
+ return ret;
}
init_comet (ci, pi->cometbase, pp->port_mode, 1 /* clockmaster == true */ , pp->portP);
@@ -1018,10 +1019,10 @@ c4_new_chan (ci_t *ci, int portnum, int channum, void *user)
int gchan;
if (c4_find_chan (channum)) /* a new channel shouldn't already exist */
- return EEXIST;
+ return -EEXIST;
if (portnum >= ci->max_port) /* sanity check */
- return ENXIO;
+ return -ENXIO;
pi = &(ci->port[portnum]);
/* find any available channel within this port */
@@ -1032,7 +1033,7 @@ c4_new_chan (ci_t *ci, int portnum, int channum, void *user)
break;
}
if (gchan == MUSYCC_NCHANS) /* exhausted table, all were assigned */
- return ENFILE;
+ return -ENFILE;
ch->up = pi;
@@ -1055,8 +1056,9 @@ c4_new_chan (ci_t *ci, int portnum, int channum, void *user)
{
status_t ret;
- if ((ret = c4_wk_chan_init (pi, ch)))
- return ret;
+ ret = c4_wk_chan_init(pi, ch);
+ if (ret)
+ return ret;
}
/* save off interface assignments which bound a board */
@@ -1079,8 +1081,10 @@ c4_del_chan (int channum)
{
mch_t *ch;
- if (!(ch = c4_find_chan (channum)))
- return ENOENT;
+ ch = c4_find_chan(channum);
+ if (!ch)
+ return -ENOENT;
+
if (ch->state == UP)
musycc_chan_down ((ci_t *) 0, channum);
ch->state = UNASSIGNED;
@@ -1095,8 +1099,9 @@ c4_del_chan_stats (int channum)
{
mch_t *ch;
- if (!(ch = c4_find_chan (channum)))
- return ENOENT;
+ ch = c4_find_chan(channum);
+ if (!ch)
+ return -ENOENT;
memset (&ch->s, 0, sizeof (struct sbecom_chan_stats));
return 0;
@@ -1109,19 +1114,20 @@ c4_set_chan (int channum, struct sbecom_chan_param *p)
mch_t *ch;
int i, x = 0;
- if (!(ch = c4_find_chan (channum)))
- return ENOENT;
+ ch = c4_find_chan(channum);
+ if (!ch)
+ return -ENOENT;
#if 1
if (ch->p.card != p->card ||
ch->p.port != p->port ||
ch->p.channum != p->channum)
- return EINVAL;
+ return -EINVAL;
#endif
if (!(ch->up->group_is_set))
{
- return EIO; /* out of order, SET_PORT command
+ return -EIO; /* out of order, SET_PORT command
* required prior to first group's
* SET_CHAN command */
}
@@ -1143,10 +1149,12 @@ c4_set_chan (int channum, struct sbecom_chan_param *p)
{
status_t ret;
- if ((ret = musycc_chan_down ((ci_t *) 0, channum)))
- return ret;
- if ((ret = c4_chan_up (ch->up->up, channum)))
- return ret;
+ ret = musycc_chan_down((ci_t *)0, channum);
+ if (ret)
+ return ret;
+ ret = c4_chan_up(ch->up->up, channum);
+ if (ret)
+ return ret;
sd_enable_xmit (ch->user); /* re-enable to catch flow controlled
* channel */
}
@@ -1159,8 +1167,10 @@ c4_get_chan (int channum, struct sbecom_chan_param *p)
{
mch_t *ch;
- if (!(ch = c4_find_chan (channum)))
- return ENOENT;
+ ch = c4_find_chan(channum);
+ if (!ch)
+ return -ENOENT;
+
*p = ch->p;
return 0;
}
@@ -1170,8 +1180,10 @@ c4_get_chan_stats (int channum, struct sbecom_chan_stats *p)
{
mch_t *ch;
- if (!(ch = c4_find_chan (channum)))
- return ENOENT;
+ ch = c4_find_chan(channum);
+ if (!ch)
+ return -ENOENT;
+
*p = ch->s;
p->tx_pending = atomic_read (&ch->tx_pending);
return 0;
@@ -1240,8 +1252,10 @@ c4_chan_up (ci_t *ci, int channum)
u_int32_t tmp; /* for optimizing conversion across BE
* platform */
- if (!(ch = c4_find_chan (channum)))
- return ENOENT;
+ ch = c4_find_chan(channum);
+ if (!ch)
+ return -ENOENT;
+
if (ch->state == UP)
{
if (cxt1e1_log_level >= LOG_MONITOR)
@@ -1264,7 +1278,7 @@ c4_chan_up (ci_t *ci, int channum)
pr_info("+ ask4 %x, currently %x\n",
ch->p.bitmask[i], pi->tsm[i]);
}
- return EINVAL;
+ return -EINVAL;
}
for (j = 0; j < 8; j++)
if (ch->p.bitmask[i] & (1 << j))
@@ -1277,7 +1291,7 @@ c4_chan_up (ci_t *ci, int channum)
/* if( cxt1e1_log_level >= LOG_WARN) */
pr_info("%s: c4_chan_up[%d] ENOBUFS (no TimeSlots assigned)\n",
ci->devname, channum);
- return ENOBUFS; /* this should not happen */
+ return -ENOBUFS; /* this should not happen */
}
addr = c4_fifo_alloc (pi, gchan, &nbuf);
ch->state = UP;
@@ -1372,12 +1386,13 @@ c4_chan_up (ci_t *ci, int channum)
}
md->next = cpu_to_le32 (OS_vtophys (md->snext));
- if (!(m = OS_mem_token_alloc (cxt1e1_max_mru)))
- {
- if (cxt1e1_log_level >= LOG_MONITOR)
- pr_info("%s: c4_chan_up[%d] - token alloc failure, size = %d.\n",
- ci->devname, channum, cxt1e1_max_mru);
- goto errfree;
+ m = OS_mem_token_alloc(cxt1e1_max_mru);
+ if (!m) {
+ if (cxt1e1_log_level >= LOG_MONITOR)
+ pr_info(
+ "%s: c4_chan_up[%d] - token alloc failure, size = %d.\n",
+ ci->devname, channum, cxt1e1_max_mru);
+ goto errfree;
}
md->mem_token = m;
md->data = cpu_to_le32 (OS_vtophys (OS_mem_token_data (m)));
@@ -1454,7 +1469,7 @@ errfree:
ch->mdr = NULL;
ch->rxd_num = 0;
ch->state = DOWN;
- return ENOBUFS;
+ return -ENOBUFS;
}
/* stop the hardware from servicing & interrupting */
@@ -1533,8 +1548,9 @@ c4_get_iidinfo (ci_t *ci, struct sbe_iid_info *iip)
struct net_device *dev;
char *np;
- if (!(dev = getuserbychan (iip->channum)))
- return ENOENT;
+ dev = getuserbychan(iip->channum);
+ if (!dev)
+ return -ENOENT;
np = dev->name;
strncpy (iip->iname, np, CHNM_STRLEN - 1);
diff --git a/drivers/staging/cxt1e1/pmcc4_private.h b/drivers/staging/cxt1e1/pmcc4_private.h
index 7edbd4e492e3..eb28f095ff8c 100644
--- a/drivers/staging/cxt1e1/pmcc4_private.h
+++ b/drivers/staging/cxt1e1/pmcc4_private.h
@@ -213,7 +213,6 @@ struct sbe_card_info
struct sbe_card_info *next;
u_int32_t *eeprombase; /* mapped address of board's EEPROM */
c4cpld_t *cpldbase; /* mapped address of board's CPLD hardware */
- char *release; /* SBE ID string w/in sbeRelease.c */
void *hdw_info;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir_dev;
diff --git a/drivers/staging/cxt1e1/pmcc4_sysdep.h b/drivers/staging/cxt1e1/pmcc4_sysdep.h
index 697f1943670f..2916c2cb13f9 100644
--- a/drivers/staging/cxt1e1/pmcc4_sysdep.h
+++ b/drivers/staging/cxt1e1/pmcc4_sysdep.h
@@ -60,3 +60,4 @@ void sd_line_is_down (void *user);
int sd_queue_stopped (void *user);
#endif /*** _INC_PMCC4_SYSDEP_H_ ***/
+extern int cxt1e1_log_level;
diff --git a/drivers/staging/cxt1e1/sbeproc.c b/drivers/staging/cxt1e1/sbeproc.c
index 353c001d3fbe..840c647fbf41 100644
--- a/drivers/staging/cxt1e1/sbeproc.c
+++ b/drivers/staging/cxt1e1/sbeproc.c
@@ -72,7 +72,8 @@ static int sbecom_proc_get_sbe_info(struct seq_file *m, void *v)
char *spd;
struct sbe_brd_info *bip;
- if (!(bip = OS_kmalloc(sizeof(struct sbe_brd_info))))
+ bip = OS_kmalloc(sizeof(struct sbe_brd_info));
+ if (!bip)
return -ENOMEM;
pr_devel(">> sbecom_proc_get_sbe_info: entered\n");
@@ -150,7 +151,6 @@ static int sbecom_proc_get_sbe_info(struct seq_file *m, void *v)
break;
}
seq_printf(m, "PCI Bus Speed: %s\n", spd);
- seq_printf(m, "Release: %s\n", ci->release);
#ifdef SBE_PMCC4_ENABLE
{
diff --git a/drivers/staging/dgap/Makefile b/drivers/staging/dgap/Makefile
index 3abe8d2bb748..0063d044ca71 100644
--- a/drivers/staging/dgap/Makefile
+++ b/drivers/staging/dgap/Makefile
@@ -1,7 +1 @@
obj-$(CONFIG_DGAP) += dgap.o
-
-
-dgap-objs := dgap_driver.o dgap_fep5.o \
- dgap_parse.o dgap_trace.o \
- dgap_tty.o dgap_sysfs.o
-
diff --git a/drivers/staging/dgap/dgap.c b/drivers/staging/dgap/dgap.c
new file mode 100644
index 000000000000..a5fc3c75ed4e
--- /dev/null
+++ b/drivers/staging/dgap/dgap.c
@@ -0,0 +1,7675 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ *
+ */
+
+/*
+ * In the original out of kernel Digi dgap driver, firmware
+ * loading was done via user land to driver handshaking.
+ *
+ * For cards that support a concentrator (port expander),
+ * I believe the concentrator its self told the card which
+ * concentrator is actually attached and then that info
+ * was used to tell user land which concentrator firmware
+ * image was to be downloaded. I think even the BIOS or
+ * FEP images required could change with the connection
+ * of a particular concentrator.
+ *
+ * Since I have no access to any of these cards or
+ * concentrators, I cannot put the correct concentrator
+ * firmware file names into the firmware_info structure
+ * as is now done for the BIOS and FEP images.
+ *
+ * I think, but am not certain, that the cards supporting
+ * concentrators will function without them. So support
+ * of these cards has been left in this driver.
+ *
+ * In order to fully support those cards, they would
+ * either have to be acquired for dissection or maybe
+ * Digi International could provide some assistance.
+ */
+#undef DIGI_CONCENTRATORS_SUPPORTED
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h> /* For udelay */
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+
+#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
+#include <linux/ctype.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/io.h> /* For read[bwl]/write[bwl] */
+
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/kdev_t.h>
+#include <linux/firmware.h>
+
+#include "dgap.h"
+
+#define init_MUTEX(sem) sema_init(sem, 1)
+#define DECLARE_MUTEX(name) \
+ struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Digi International, http://www.digi.com");
+MODULE_DESCRIPTION("Driver for the Digi International EPCA PCI based product line");
+MODULE_SUPPORTED_DEVICE("dgap");
+
+/**************************************************************************
+ *
+ * protos for this file
+ *
+ */
+
+static int dgap_start(void);
+static void dgap_init_globals(void);
+static int dgap_found_board(struct pci_dev *pdev, int id);
+static void dgap_cleanup_board(struct board_t *brd);
+static void dgap_poll_handler(ulong dummy);
+static int dgap_init_pci(void);
+static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void dgap_remove_one(struct pci_dev *dev);
+static int dgap_probe1(struct pci_dev *pdev, int card_type);
+static int dgap_do_remap(struct board_t *brd);
+static irqreturn_t dgap_intr(int irq, void *voidbrd);
+
+/* Our function prototypes */
+static int dgap_tty_open(struct tty_struct *tty, struct file *file);
+static void dgap_tty_close(struct tty_struct *tty, struct file *file);
+static int dgap_block_til_ready(struct tty_struct *tty, struct file *file,
+ struct channel_t *ch);
+static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
+ unsigned long arg);
+static int dgap_tty_digigeta(struct tty_struct *tty,
+ struct digi_t __user *retinfo);
+static int dgap_tty_digiseta(struct tty_struct *tty,
+ struct digi_t __user *new_info);
+static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo);
+static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info);
+static int dgap_tty_write_room(struct tty_struct *tty);
+static int dgap_tty_chars_in_buffer(struct tty_struct *tty);
+static void dgap_tty_start(struct tty_struct *tty);
+static void dgap_tty_stop(struct tty_struct *tty);
+static void dgap_tty_throttle(struct tty_struct *tty);
+static void dgap_tty_unthrottle(struct tty_struct *tty);
+static void dgap_tty_flush_chars(struct tty_struct *tty);
+static void dgap_tty_flush_buffer(struct tty_struct *tty);
+static void dgap_tty_hangup(struct tty_struct *tty);
+static int dgap_wait_for_drain(struct tty_struct *tty);
+static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command,
+ unsigned int __user *value);
+static int dgap_get_modem_info(struct channel_t *ch,
+ unsigned int __user *value);
+static int dgap_tty_digisetcustombaud(struct tty_struct *tty,
+ int __user *new_info);
+static int dgap_tty_digigetcustombaud(struct tty_struct *tty,
+ int __user *retinfo);
+static int dgap_tty_tiocmget(struct tty_struct *tty);
+static int dgap_tty_tiocmset(struct tty_struct *tty, unsigned int set,
+ unsigned int clear);
+static int dgap_tty_send_break(struct tty_struct *tty, int msec);
+static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout);
+static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf,
+ int count);
+static void dgap_tty_set_termios(struct tty_struct *tty,
+ struct ktermios *old_termios);
+static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c);
+static void dgap_tty_send_xchar(struct tty_struct *tty, char ch);
+
+static int dgap_tty_register(struct board_t *brd);
+static int dgap_tty_init(struct board_t *);
+static void dgap_tty_uninit(struct board_t *);
+static void dgap_carrier(struct channel_t *ch);
+static void dgap_input(struct channel_t *ch);
+
+/*
+ * Our function prototypes from dgap_fep5
+ */
+static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds);
+static int dgap_event(struct board_t *bd);
+
+static void dgap_poll_tasklet(unsigned long data);
+static void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1,
+ uchar byte2, uint ncmds);
+static void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds);
+static void dgap_wmove(struct channel_t *ch, char *buf, uint cnt);
+static int dgap_param(struct tty_struct *tty);
+static void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf,
+ unsigned char *fbuf, int *len);
+static uint dgap_get_custom_baud(struct channel_t *ch);
+static void dgap_firmware_reset_port(struct channel_t *ch);
+
+/*
+ * Function prototypes from dgap_parse.c.
+ */
+static int dgap_gettok(char **in, struct cnode *p);
+static char *dgap_getword(char **in);
+static char *dgap_savestring(char *s);
+static struct cnode *dgap_newnode(int t);
+static int dgap_checknode(struct cnode *p);
+static void dgap_err(char *s);
+
+/*
+ * Function prototypes from dgap_sysfs.h
+ */
+struct board_t;
+struct channel_t;
+struct un_t;
+struct pci_driver;
+struct class_device;
+
+static void dgap_create_ports_sysfiles(struct board_t *bd);
+static void dgap_remove_ports_sysfiles(struct board_t *bd);
+
+static int dgap_create_driver_sysfiles(struct pci_driver *);
+static void dgap_remove_driver_sysfiles(struct pci_driver *);
+
+static void dgap_create_tty_sysfs(struct un_t *un, struct device *c);
+static void dgap_remove_tty_sysfs(struct device *c);
+
+/*
+ * Function prototypes from dgap_parse.h
+ */
+static int dgap_parsefile(char **in, int Remove);
+static struct cnode *dgap_find_config(int type, int bus, int slot);
+static uint dgap_config_get_num_prts(struct board_t *bd);
+static char *dgap_create_config_string(struct board_t *bd, char *string);
+static uint dgap_config_get_useintr(struct board_t *bd);
+static uint dgap_config_get_altpin(struct board_t *bd);
+
+static int dgap_ms_sleep(ulong ms);
+static void dgap_do_bios_load(struct board_t *brd, const uchar *ubios, int len);
+static void dgap_do_fep_load(struct board_t *brd, const uchar *ufep, int len);
+#ifdef DIGI_CONCENTRATORS_SUPPORTED
+static void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len);
+#endif
+static int dgap_after_config_loaded(int board);
+static int dgap_finalize_board_init(struct board_t *brd);
+
+static void dgap_get_vpd(struct board_t *brd);
+static void dgap_do_reset_board(struct board_t *brd);
+static int dgap_do_wait_for_bios(struct board_t *brd);
+static int dgap_do_wait_for_fep(struct board_t *brd);
+static int dgap_tty_register_ports(struct board_t *brd);
+static int dgap_firmware_load(struct pci_dev *pdev, int card_type);
+
+/* Driver unload function */
+static void dgap_cleanup_module(void);
+
+module_exit(dgap_cleanup_module);
+
+/*
+ * File operations permitted on Control/Management major.
+ */
+static const struct file_operations DgapBoardFops = {
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Globals
+ */
+static uint dgap_NumBoards;
+static struct board_t *dgap_Board[MAXBOARDS];
+static ulong dgap_poll_counter;
+static char *dgap_config_buf;
+static int dgap_driver_state = DRIVER_INITIALIZED;
+DEFINE_SPINLOCK(dgap_dl_lock);
+static wait_queue_head_t dgap_dl_wait;
+static int dgap_dl_action;
+static int dgap_poll_tick = 20; /* Poll interval - 20 ms */
+
+/*
+ * Static vars.
+ */
+static struct class *dgap_class;
+
+static struct board_t *dgap_BoardsByMajor[256];
+static uint dgap_count = 500;
+
+/*
+ * Poller stuff
+ */
+DEFINE_SPINLOCK(dgap_poll_lock); /* Poll scheduling lock */
+static ulong dgap_poll_time; /* Time of next poll */
+static uint dgap_poll_stop; /* Used to tell poller to stop */
+static struct timer_list dgap_poll_timer;
+
+/*
+ SUPPORTED PRODUCTS
+
+ Card Model Number of Ports Interface
+ ----------------------------------------------------------------
+ Acceleport Xem 4 - 64 (EIA232 & EIA422)
+ Acceleport Xr 4 & 8 (EIA232)
+ Acceleport Xr 920 4 & 8 (EIA232)
+ Acceleport C/X 8 - 128 (EIA232)
+ Acceleport EPC/X 8 - 224 (EIA232)
+ Acceleport Xr/422 4 & 8 (EIA422)
+ Acceleport 2r/920 2 (EIA232)
+ Acceleport 4r/920 4 (EIA232)
+ Acceleport 8r/920 8 (EIA232)
+
+ IBM 8-Port Asynchronous PCI Adapter (EIA232)
+ IBM 128-Port Asynchronous PCI Adapter (EIA232 & EIA422)
+*/
+
+static struct pci_device_id dgap_pci_tbl[] = {
+ { DIGI_VID, PCI_DEV_XEM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { DIGI_VID, PCI_DEV_CX_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+ { DIGI_VID, PCI_DEV_CX_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
+ { DIGI_VID, PCI_DEV_EPCJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+ { DIGI_VID, PCI_DEV_920_2_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { DIGI_VID, PCI_DEV_920_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
+ { DIGI_VID, PCI_DEV_920_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
+ { DIGI_VID, PCI_DEV_XR_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
+ { DIGI_VID, PCI_DEV_XRJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { DIGI_VID, PCI_DEV_XR_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
+ { DIGI_VID, PCI_DEV_XR_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 },
+ { DIGI_VID, PCI_DEV_XR_SAIP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 },
+ { DIGI_VID, PCI_DEV_XR_BULL_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
+ { DIGI_VID, PCI_DEV_920_8_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
+ { DIGI_VID, PCI_DEV_XEM_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
+ {0,} /* 0 terminated list. */
+};
+MODULE_DEVICE_TABLE(pci, dgap_pci_tbl);
+
+/*
+ * A generic list of Product names, PCI Vendor ID, and PCI Device ID.
+ */
+struct board_id {
+ uint config_type;
+ uchar *name;
+ uint maxports;
+ uint dpatype;
+};
+
+static struct board_id dgap_Ids[] = {
+ { PPCM, PCI_DEV_XEM_NAME, 64, (T_PCXM|T_PCLITE|T_PCIBUS) },
+ { PCX, PCI_DEV_CX_NAME, 128, (T_CX|T_PCIBUS) },
+ { PCX, PCI_DEV_CX_IBM_NAME, 128, (T_CX|T_PCIBUS) },
+ { PEPC, PCI_DEV_EPCJ_NAME, 224, (T_EPC|T_PCIBUS) },
+ { APORT2_920P, PCI_DEV_920_2_NAME, 2, (T_PCXR|T_PCLITE|T_PCIBUS) },
+ { APORT4_920P, PCI_DEV_920_4_NAME, 4, (T_PCXR|T_PCLITE|T_PCIBUS) },
+ { APORT8_920P, PCI_DEV_920_8_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
+ { PAPORT8, PCI_DEV_XR_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
+ { PAPORT8, PCI_DEV_XRJ_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
+ { PAPORT8, PCI_DEV_XR_422_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
+ { PAPORT8, PCI_DEV_XR_IBM_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
+ { PAPORT8, PCI_DEV_XR_SAIP_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
+ { PAPORT8, PCI_DEV_XR_BULL_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
+ { APORT8_920P, PCI_DEV_920_8_HP_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
+ { PPCM, PCI_DEV_XEM_HP_NAME, 64, (T_PCXM|T_PCLITE|T_PCIBUS) },
+ {0,} /* 0 terminated list. */
+};
+
+static struct pci_driver dgap_driver = {
+ .name = "dgap",
+ .probe = dgap_init_one,
+ .id_table = dgap_pci_tbl,
+ .remove = dgap_remove_one,
+};
+
+struct firmware_info {
+ uchar *conf_name; /* dgap.conf */
+ uchar *bios_name; /* BIOS filename */
+ uchar *fep_name; /* FEP filename */
+ uchar *con_name; /* Concentrator filename FIXME*/
+ int num; /* sequence number */
+};
+
+/*
+ * Firmware - BIOS, FEP, and CONC filenames
+ */
+static struct firmware_info fw_info[] = {
+ { "dgap/dgap.conf", "dgap/sxbios.bin", "dgap/sxfep.bin", 0, 0 },
+ { "dgap/dgap.conf", "dgap/cxpbios.bin", "dgap/cxpfep.bin", 0, 1 },
+ { "dgap/dgap.conf", "dgap/cxpbios.bin", "dgap/cxpfep.bin", 0, 2 },
+ { "dgap/dgap.conf", "dgap/pcibios.bin", "dgap/pcifep.bin", 0, 3 },
+ { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 4 },
+ { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 5 },
+ { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 6 },
+ { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 7 },
+ { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 8 },
+ { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 9 },
+ { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 10 },
+ { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 11 },
+ { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 12 },
+ { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 13 },
+ { "dgap/dgap.conf", "dgap/sxbios.bin", "dgap/sxfep.bin", 0, 14 },
+ {0,}
+};
+
+/*
+ * Default transparent print information.
+ */
+static struct digi_t dgap_digi_init = {
+ .digi_flags = DIGI_COOK, /* Flags */
+ .digi_maxcps = 100, /* Max CPS */
+ .digi_maxchar = 50, /* Max chars in print queue */
+ .digi_bufsize = 100, /* Printer buffer size */
+ .digi_onlen = 4, /* size of printer on string */
+ .digi_offlen = 4, /* size of printer off string */
+ .digi_onstr = "\033[5i", /* ANSI printer on string ] */
+ .digi_offstr = "\033[4i", /* ANSI printer off string ] */
+ .digi_term = "ansi" /* default terminal type */
+};
+
+/*
+ * Define a local default termios struct. All ports will be created
+ * with this termios initially.
+ *
+ * This defines a raw port at 9600 baud, 8 data bits, no parity,
+ * 1 stop bit.
+ */
+
+static struct ktermios DgapDefaultTermios = {
+ .c_iflag = (DEFAULT_IFLAGS), /* iflags */
+ .c_oflag = (DEFAULT_OFLAGS), /* oflags */
+ .c_cflag = (DEFAULT_CFLAGS), /* cflags */
+ .c_lflag = (DEFAULT_LFLAGS), /* lflags */
+ .c_cc = INIT_C_CC,
+ .c_line = 0,
+};
+
+static const struct tty_operations dgap_tty_ops = {
+ .open = dgap_tty_open,
+ .close = dgap_tty_close,
+ .write = dgap_tty_write,
+ .write_room = dgap_tty_write_room,
+ .flush_buffer = dgap_tty_flush_buffer,
+ .chars_in_buffer = dgap_tty_chars_in_buffer,
+ .flush_chars = dgap_tty_flush_chars,
+ .ioctl = dgap_tty_ioctl,
+ .set_termios = dgap_tty_set_termios,
+ .stop = dgap_tty_stop,
+ .start = dgap_tty_start,
+ .throttle = dgap_tty_throttle,
+ .unthrottle = dgap_tty_unthrottle,
+ .hangup = dgap_tty_hangup,
+ .put_char = dgap_tty_put_char,
+ .tiocmget = dgap_tty_tiocmget,
+ .tiocmset = dgap_tty_tiocmset,
+ .break_ctl = dgap_tty_send_break,
+ .wait_until_sent = dgap_tty_wait_until_sent,
+ .send_xchar = dgap_tty_send_xchar
+};
+
+/*
+ * Our needed internal static variables from dgap_parse.c
+ */
+static struct cnode dgap_head;
+#define MAXCWORD 200
+static char dgap_cword[MAXCWORD];
+
+struct toklist {
+ int token;
+ char *string;
+};
+
+static struct toklist dgap_tlist[] = {
+ { BEGIN, "config_begin" },
+ { END, "config_end" },
+ { BOARD, "board" },
+ { PCX, "Digi_AccelePort_C/X_PCI" },
+ { PEPC, "Digi_AccelePort_EPC/X_PCI" },
+ { PPCM, "Digi_AccelePort_Xem_PCI" },
+ { APORT2_920P, "Digi_AccelePort_2r_920_PCI" },
+ { APORT4_920P, "Digi_AccelePort_4r_920_PCI" },
+ { APORT8_920P, "Digi_AccelePort_8r_920_PCI" },
+ { PAPORT4, "Digi_AccelePort_4r_PCI(EIA-232/RS-422)" },
+ { PAPORT8, "Digi_AccelePort_8r_PCI(EIA-232/RS-422)" },
+ { IO, "io" },
+ { PCIINFO, "pciinfo" },
+ { LINE, "line" },
+ { CONC, "conc" },
+ { CONC, "concentrator" },
+ { CX, "cx" },
+ { CX, "ccon" },
+ { EPC, "epccon" },
+ { EPC, "epc" },
+ { MOD, "module" },
+ { ID, "id" },
+ { STARTO, "start" },
+ { SPEED, "speed" },
+ { CABLE, "cable" },
+ { CONNECT, "connect" },
+ { METHOD, "method" },
+ { STATUS, "status" },
+ { CUSTOM, "Custom" },
+ { BASIC, "Basic" },
+ { MEM, "mem" },
+ { MEM, "memory" },
+ { PORTS, "ports" },
+ { MODEM, "modem" },
+ { NPORTS, "nports" },
+ { TTYN, "ttyname" },
+ { CU, "cuname" },
+ { PRINT, "prname" },
+ { CMAJOR, "major" },
+ { ALTPIN, "altpin" },
+ { USEINTR, "useintr" },
+ { TTSIZ, "ttysize" },
+ { CHSIZ, "chsize" },
+ { BSSIZ, "boardsize" },
+ { UNTSIZ, "schedsize" },
+ { F2SIZ, "f2200size" },
+ { VPSIZ, "vpixsize" },
+ { 0, NULL }
+};
+
+/************************************************************************
+ *
+ * Driver load/unload functions
+ *
+ ************************************************************************/
+
+/*
+ * init_module()
+ *
+ * Module load. This is where it all starts.
+ */
+static int dgap_init_module(void)
+{
+ int rc = 0;
+
+ pr_info("%s, Digi International Part Number %s\n", DG_NAME, DG_PART);
+
+ rc = dgap_start();
+ if (rc)
+ return rc;
+
+ rc = dgap_init_pci();
+ if (rc)
+ goto err_cleanup;
+
+ rc = dgap_create_driver_sysfiles(&dgap_driver);
+ if (rc)
+ goto err_cleanup;
+
+ dgap_driver_state = DRIVER_READY;
+
+ return 0;
+
+err_cleanup:
+
+ dgap_cleanup_module();
+
+ return rc;
+}
+module_init(dgap_init_module);
+
+/*
+ * Start of driver.
+ */
+static int dgap_start(void)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct device *device;
+
+ /*
+ * make sure that the globals are
+ * init'd before we do anything else
+ */
+ dgap_init_globals();
+
+ dgap_NumBoards = 0;
+
+ pr_info("For the tools package please visit http://www.digi.com\n");
+
+ /*
+ * Register our base character device into the kernel.
+ */
+
+ /*
+ * Register management/dpa devices
+ */
+ rc = register_chrdev(DIGI_DGAP_MAJOR, "dgap", &DgapBoardFops);
+ if (rc < 0)
+ return rc;
+
+ dgap_class = class_create(THIS_MODULE, "dgap_mgmt");
+ if (IS_ERR(dgap_class)) {
+ rc = PTR_ERR(dgap_class);
+ goto failed_class;
+ }
+
+ device = device_create(dgap_class, NULL,
+ MKDEV(DIGI_DGAP_MAJOR, 0),
+ NULL, "dgap_mgmt");
+ if (IS_ERR(device)) {
+ rc = PTR_ERR(device);
+ goto failed_device;
+ }
+
+ /* Start the poller */
+ spin_lock_irqsave(&dgap_poll_lock, flags);
+ init_timer(&dgap_poll_timer);
+ dgap_poll_timer.function = dgap_poll_handler;
+ dgap_poll_timer.data = 0;
+ dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick);
+ dgap_poll_timer.expires = dgap_poll_time;
+ spin_unlock_irqrestore(&dgap_poll_lock, flags);
+
+ add_timer(&dgap_poll_timer);
+
+ return rc;
+
+failed_device:
+ class_destroy(dgap_class);
+failed_class:
+ unregister_chrdev(DIGI_DGAP_MAJOR, "dgap");
+ return rc;
+}
+
+/*
+ * Register pci driver, and return how many boards we have.
+ */
+static int dgap_init_pci(void)
+{
+ return pci_register_driver(&dgap_driver);
+}
+
+/* returns count (>= 0), or negative on error */
+static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int rc;
+
+ /* wake up and enable device */
+ rc = pci_enable_device(pdev);
+
+ if (rc < 0) {
+ rc = -EIO;
+ } else {
+ rc = dgap_probe1(pdev, ent->driver_data);
+ if (rc == 0) {
+ dgap_NumBoards++;
+ rc = dgap_firmware_load(pdev, ent->driver_data);
+ }
+ }
+ return rc;
+}
+
+static int dgap_probe1(struct pci_dev *pdev, int card_type)
+{
+ return dgap_found_board(pdev, card_type);
+}
+
+static void dgap_remove_one(struct pci_dev *dev)
+{
+ /* Do Nothing */
+}
+
+/*
+ * dgap_cleanup_module()
+ *
+ * Module unload. This is where it all ends.
+ */
+static void dgap_cleanup_module(void)
+{
+ int i;
+ ulong lock_flags;
+
+ spin_lock_irqsave(&dgap_poll_lock, lock_flags);
+ dgap_poll_stop = 1;
+ spin_unlock_irqrestore(&dgap_poll_lock, lock_flags);
+
+ /* Turn off poller right away. */
+ del_timer_sync(&dgap_poll_timer);
+
+ dgap_remove_driver_sysfiles(&dgap_driver);
+
+ device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 0));
+ class_destroy(dgap_class);
+ unregister_chrdev(DIGI_DGAP_MAJOR, "dgap");
+
+ kfree(dgap_config_buf);
+
+ for (i = 0; i < dgap_NumBoards; ++i) {
+ dgap_remove_ports_sysfiles(dgap_Board[i]);
+ dgap_tty_uninit(dgap_Board[i]);
+ dgap_cleanup_board(dgap_Board[i]);
+ }
+
+ if (dgap_NumBoards)
+ pci_unregister_driver(&dgap_driver);
+}
+
+/*
+ * dgap_cleanup_board()
+ *
+ * Free all the memory associated with a board
+ */
+static void dgap_cleanup_board(struct board_t *brd)
+{
+ int i = 0;
+
+ if (!brd || brd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ if (brd->intr_used && brd->irq)
+ free_irq(brd->irq, brd);
+
+ tasklet_kill(&brd->helper_tasklet);
+
+ if (brd->re_map_port) {
+ release_mem_region(brd->membase + 0x200000, 0x200000);
+ iounmap(brd->re_map_port);
+ brd->re_map_port = NULL;
+ }
+
+ if (brd->re_map_membase) {
+ release_mem_region(brd->membase, 0x200000);
+ iounmap(brd->re_map_membase);
+ brd->re_map_membase = NULL;
+ }
+
+ /* Free all allocated channels structs */
+ for (i = 0; i < MAXPORTS ; i++)
+ kfree(brd->channels[i]);
+
+ kfree(brd->flipbuf);
+ kfree(brd->flipflagbuf);
+
+ dgap_Board[brd->boardnum] = NULL;
+
+ kfree(brd);
+}
+
+/*
+ * dgap_found_board()
+ *
+ * A board has been found, init it.
+ */
+static int dgap_found_board(struct pci_dev *pdev, int id)
+{
+ struct board_t *brd;
+ unsigned int pci_irq;
+ int i = 0;
+
+ /* get the board structure and prep it */
+ brd = kzalloc(sizeof(struct board_t), GFP_KERNEL);
+ if (!brd)
+ return -ENOMEM;
+
+ dgap_Board[dgap_NumBoards] = brd;
+
+ /* store the info for the board we've found */
+ brd->magic = DGAP_BOARD_MAGIC;
+ brd->boardnum = dgap_NumBoards;
+ brd->firstminor = 0;
+ brd->vendor = dgap_pci_tbl[id].vendor;
+ brd->device = dgap_pci_tbl[id].device;
+ brd->pdev = pdev;
+ brd->pci_bus = pdev->bus->number;
+ brd->pci_slot = PCI_SLOT(pdev->devfn);
+ brd->name = dgap_Ids[id].name;
+ brd->maxports = dgap_Ids[id].maxports;
+ brd->type = dgap_Ids[id].config_type;
+ brd->dpatype = dgap_Ids[id].dpatype;
+ brd->dpastatus = BD_NOFEP;
+ init_waitqueue_head(&brd->state_wait);
+
+ spin_lock_init(&brd->bd_lock);
+
+ brd->runwait = 0;
+ brd->inhibit_poller = FALSE;
+ brd->wait_for_bios = 0;
+ brd->wait_for_fep = 0;
+
+ for (i = 0; i < MAXPORTS; i++)
+ brd->channels[i] = NULL;
+
+ /* store which card & revision we have */
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor);
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice);
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev);
+
+ pci_irq = pdev->irq;
+ brd->irq = pci_irq;
+
+ /* get the PCI Base Address Registers */
+
+ /* Xr Jupiter and EPC use BAR 2 */
+ if (brd->device == PCI_DEV_XRJ_DID || brd->device == PCI_DEV_EPCJ_DID) {
+ brd->membase = pci_resource_start(pdev, 2);
+ brd->membase_end = pci_resource_end(pdev, 2);
+ }
+ /* Everyone else uses BAR 0 */
+ else {
+ brd->membase = pci_resource_start(pdev, 0);
+ brd->membase_end = pci_resource_end(pdev, 0);
+ }
+
+ if (!brd->membase)
+ return -ENODEV;
+
+ if (brd->membase & 1)
+ brd->membase &= ~3;
+ else
+ brd->membase &= ~15;
+
+ /*
+ * On the PCI boards, there is no IO space allocated
+ * The I/O registers will be in the first 3 bytes of the
+ * upper 2MB of the 4MB memory space. The board memory
+ * will be mapped into the low 2MB of the 4MB memory space
+ */
+ brd->port = brd->membase + PCI_IO_OFFSET;
+ brd->port_end = brd->port + PCI_IO_SIZE;
+
+ /*
+ * Special initialization for non-PLX boards
+ */
+ if (brd->device != PCI_DEV_XRJ_DID && brd->device != PCI_DEV_EPCJ_DID) {
+ unsigned short cmd;
+
+ pci_write_config_byte(pdev, 0x40, 0);
+ pci_write_config_byte(pdev, 0x46, 0);
+
+ /* Limit burst length to 2 doubleword transactions */
+ pci_write_config_byte(pdev, 0x42, 1);
+
+ /*
+ * Enable IO and mem if not already done.
+ * This was needed for support on Itanium.
+ */
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
+ }
+
+ /* init our poll helper tasklet */
+ tasklet_init(&brd->helper_tasklet, dgap_poll_tasklet,
+ (unsigned long) brd);
+
+ i = dgap_do_remap(brd);
+ if (i)
+ brd->state = BOARD_FAILED;
+
+ pr_info("dgap: board %d: %s (rev %d), irq %ld, %s\n",
+ dgap_NumBoards, brd->name, brd->rev, brd->irq,
+ brd->state ? "NOT READY\0" : "READY\0");
+
+ return 0;
+}
+
+
+static int dgap_finalize_board_init(struct board_t *brd)
+{
+ int rc;
+
+ if (!brd || brd->magic != DGAP_BOARD_MAGIC)
+ return -ENODEV;
+
+ brd->use_interrupts = dgap_config_get_useintr(brd);
+
+ /*
+ * Set up our interrupt handler if we are set to do interrupts.
+ */
+ if (brd->use_interrupts && brd->irq) {
+
+ rc = request_irq(brd->irq, dgap_intr, IRQF_SHARED, "DGAP", brd);
+
+ if (rc)
+ brd->intr_used = 0;
+ else
+ brd->intr_used = 1;
+ } else {
+ brd->intr_used = 0;
+ }
+
+ return 0;
+}
+
+static int dgap_firmware_load(struct pci_dev *pdev, int card_type)
+{
+ struct board_t *brd = dgap_Board[dgap_NumBoards - 1];
+ const struct firmware *fw;
+ int ret;
+
+ dgap_get_vpd(brd);
+ dgap_do_reset_board(brd);
+
+ if (fw_info[card_type].conf_name) {
+ ret = request_firmware(&fw, fw_info[card_type].conf_name,
+ &pdev->dev);
+ if (ret) {
+ pr_err("dgap: config file %s not found\n",
+ fw_info[card_type].conf_name);
+ return ret;
+ }
+ if (!dgap_config_buf) {
+ dgap_config_buf = kmalloc(fw->size + 1, GFP_ATOMIC);
+ if (!dgap_config_buf) {
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+ }
+
+ memcpy(dgap_config_buf, fw->data, fw->size);
+ release_firmware(fw);
+ dgap_config_buf[fw->size + 1] = '\0';
+
+ if (dgap_parsefile(&dgap_config_buf, TRUE) != 0)
+ return -EINVAL;
+ }
+
+ ret = dgap_after_config_loaded(brd->boardnum);
+ if (ret)
+ return ret;
+ /*
+ * Match this board to a config the user created for us.
+ */
+ brd->bd_config =
+ dgap_find_config(brd->type, brd->pci_bus, brd->pci_slot);
+
+ /*
+ * Because the 4 port Xr products share the same PCI ID
+ * as the 8 port Xr products, if we receive a NULL config
+ * back, and this is a PAPORT8 board, retry with a
+ * PAPORT4 attempt as well.
+ */
+ if (brd->type == PAPORT8 && !brd->bd_config)
+ brd->bd_config =
+ dgap_find_config(PAPORT4, brd->pci_bus, brd->pci_slot);
+
+ if (!brd->bd_config) {
+ pr_err("dgap: No valid configuration found\n");
+ return -EINVAL;
+ }
+
+ dgap_tty_register(brd);
+ dgap_finalize_board_init(brd);
+
+ if (fw_info[card_type].bios_name) {
+ ret = request_firmware(&fw, fw_info[card_type].bios_name,
+ &pdev->dev);
+ if (ret) {
+ pr_err("dgap: bios file %s not found\n",
+ fw_info[card_type].bios_name);
+ return ret;
+ }
+ dgap_do_bios_load(brd, fw->data, fw->size);
+ release_firmware(fw);
+
+ /* Wait for BIOS to test board... */
+ if (!dgap_do_wait_for_bios(brd))
+ return -ENXIO;
+ }
+
+ if (fw_info[card_type].fep_name) {
+ ret = request_firmware(&fw, fw_info[card_type].fep_name,
+ &pdev->dev);
+ if (ret) {
+ pr_err("dgap: fep file %s not found\n",
+ fw_info[card_type].fep_name);
+ return ret;
+ }
+ dgap_do_fep_load(brd, fw->data, fw->size);
+ release_firmware(fw);
+
+ /* Wait for FEP to load on board... */
+ if (!dgap_do_wait_for_fep(brd))
+ return -ENXIO;
+ }
+
+#ifdef DIGI_CONCENTRATORS_SUPPORTED
+ /*
+ * If this is a CX or EPCX, we need to see if the firmware
+ * is requesting a concentrator image from us.
+ */
+ if ((bd->type == PCX) || (bd->type == PEPC)) {
+ chk_addr = (u16 *) (vaddr + DOWNREQ);
+ /* Nonzero if FEP is requesting concentrator image. */
+ check = readw(chk_addr);
+ vaddr = brd->re_map_membase;
+ }
+
+ if (fw_info[card_type].con_name && check && vaddr) {
+ ret = request_firmware(&fw, fw_info[card_type].con_name,
+ &pdev->dev);
+ if (ret) {
+ pr_err("dgap: conc file %s not found\n",
+ fw_info[card_type].con_name);
+ return ret;
+ }
+ /* Put concentrator firmware loading code here */
+ offset = readw((u16 *) (vaddr + DOWNREQ));
+ memcpy_toio(offset, fw->data, fw->size);
+
+ dgap_do_conc_load(brd, (char *)fw->data, fw->size)
+ release_firmware(fw);
+ }
+#endif
+ /*
+ * Do tty device initialization.
+ */
+ ret = dgap_tty_init(brd);
+ if (ret < 0) {
+ dgap_tty_uninit(brd);
+ return ret;
+ }
+
+ ret = dgap_tty_register_ports(brd);
+ if (ret)
+ return ret;
+
+ brd->state = BOARD_READY;
+ brd->dpastatus = BD_RUNNING;
+
+ return 0;
+}
+
+/*
+ * Remap PCI memory.
+ */
+static int dgap_do_remap(struct board_t *brd)
+{
+ if (!brd || brd->magic != DGAP_BOARD_MAGIC)
+ return -ENXIO;
+
+ if (!request_mem_region(brd->membase, 0x200000, "dgap"))
+ return -ENOMEM;
+
+ if (!request_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000,
+ "dgap")) {
+ release_mem_region(brd->membase, 0x200000);
+ return -ENOMEM;
+ }
+
+ brd->re_map_membase = ioremap(brd->membase, 0x200000);
+ if (!brd->re_map_membase) {
+ release_mem_region(brd->membase, 0x200000);
+ release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
+ return -ENOMEM;
+ }
+
+ brd->re_map_port = ioremap((brd->membase + PCI_IO_OFFSET), 0x200000);
+ if (!brd->re_map_port) {
+ release_mem_region(brd->membase, 0x200000);
+ release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
+ iounmap(brd->re_map_membase);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+*
+* Function:
+*
+* dgap_poll_handler
+*
+* Author:
+*
+* Scott H Kilau
+*
+* Parameters:
+*
+* dummy -- ignored
+*
+* Return Values:
+*
+* none
+*
+* Description:
+*
+* As each timer expires, it determines (a) whether the "transmit"
+* waiter needs to be woken up, and (b) whether the poller needs to
+* be rescheduled.
+*
+******************************************************************************/
+
+static void dgap_poll_handler(ulong dummy)
+{
+ int i;
+ struct board_t *brd;
+ unsigned long lock_flags;
+ ulong new_time;
+
+ dgap_poll_counter++;
+
+ /*
+ * Do not start the board state machine until
+ * driver tells us its up and running, and has
+ * everything it needs.
+ */
+ if (dgap_driver_state != DRIVER_READY)
+ goto schedule_poller;
+
+ /*
+ * If we have just 1 board, or the system is not SMP,
+ * then use the typical old style poller.
+ * Otherwise, use our new tasklet based poller, which should
+ * speed things up for multiple boards.
+ */
+ if ((dgap_NumBoards == 1) || (num_online_cpus() <= 1)) {
+ for (i = 0; i < dgap_NumBoards; i++) {
+
+ brd = dgap_Board[i];
+
+ if (brd->state == BOARD_FAILED)
+ continue;
+ if (!brd->intr_running)
+ /* Call the real board poller directly */
+ dgap_poll_tasklet((unsigned long) brd);
+ }
+ } else {
+ /*
+ * Go thru each board, kicking off a
+ * tasklet for each if needed
+ */
+ for (i = 0; i < dgap_NumBoards; i++) {
+ brd = dgap_Board[i];
+
+ /*
+ * Attempt to grab the board lock.
+ *
+ * If we can't get it, no big deal, the next poll
+ * will get it. Basically, I just really don't want
+ * to spin in here, because I want to kick off my
+ * tasklets as fast as I can, and then get out the
+ * poller.
+ */
+ if (!spin_trylock(&brd->bd_lock))
+ continue;
+
+ /*
+ * If board is in a failed state, don't bother
+ * scheduling a tasklet
+ */
+ if (brd->state == BOARD_FAILED) {
+ spin_unlock(&brd->bd_lock);
+ continue;
+ }
+
+ /* Schedule a poll helper task */
+ if (!brd->intr_running)
+ tasklet_schedule(&brd->helper_tasklet);
+
+ /*
+ * Can't do DGAP_UNLOCK here, as we don't have
+ * lock_flags because we did a trylock above.
+ */
+ spin_unlock(&brd->bd_lock);
+ }
+ }
+
+schedule_poller:
+
+ /*
+ * Schedule ourself back at the nominal wakeup interval.
+ */
+ spin_lock_irqsave(&dgap_poll_lock, lock_flags);
+ dgap_poll_time += dgap_jiffies_from_ms(dgap_poll_tick);
+
+ new_time = dgap_poll_time - jiffies;
+
+ if ((ulong) new_time >= 2 * dgap_poll_tick) {
+ dgap_poll_time =
+ jiffies + dgap_jiffies_from_ms(dgap_poll_tick);
+ }
+
+ dgap_poll_timer.function = dgap_poll_handler;
+ dgap_poll_timer.data = 0;
+ dgap_poll_timer.expires = dgap_poll_time;
+ spin_unlock_irqrestore(&dgap_poll_lock, lock_flags);
+
+ if (!dgap_poll_stop)
+ add_timer(&dgap_poll_timer);
+}
+
+/*
+ * dgap_intr()
+ *
+ * Driver interrupt handler.
+ */
+static irqreturn_t dgap_intr(int irq, void *voidbrd)
+{
+ struct board_t *brd = (struct board_t *) voidbrd;
+
+ if (!brd)
+ return IRQ_NONE;
+
+ /*
+ * Check to make sure its for us.
+ */
+ if (brd->magic != DGAP_BOARD_MAGIC)
+ return IRQ_NONE;
+
+ brd->intr_count++;
+
+ /*
+ * Schedule tasklet to run at a better time.
+ */
+ tasklet_schedule(&brd->helper_tasklet);
+ return IRQ_HANDLED;
+}
+
+/*
+ * dgap_init_globals()
+ *
+ * This is where we initialize the globals from the static insmod
+ * configuration variables. These are declared near the head of
+ * this file.
+ */
+static void dgap_init_globals(void)
+{
+ int i = 0;
+
+ for (i = 0; i < MAXBOARDS; i++)
+ dgap_Board[i] = NULL;
+
+ init_timer(&dgap_poll_timer);
+
+ init_waitqueue_head(&dgap_dl_wait);
+ dgap_dl_action = 0;
+}
+
+/************************************************************************
+ *
+ * Utility functions
+ *
+ ************************************************************************/
+
+/*
+ * dgap_ms_sleep()
+ *
+ * Put the driver to sleep for x ms's
+ *
+ * Returns 0 if timed out, !0 (showing signal) if interrupted by a signal.
+ */
+static int dgap_ms_sleep(ulong ms)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((ms * HZ) / 1000);
+ return signal_pending(current);
+}
+
+/************************************************************************
+ *
+ * TTY Initialization/Cleanup Functions
+ *
+ ************************************************************************/
+
+/*
+ * dgap_tty_register()
+ *
+ * Init the tty subsystem for this board.
+ */
+static int dgap_tty_register(struct board_t *brd)
+{
+ int rc = 0;
+
+ brd->SerialDriver = alloc_tty_driver(MAXPORTS);
+
+ snprintf(brd->SerialName, MAXTTYNAMELEN, "tty_dgap_%d_", brd->boardnum);
+ brd->SerialDriver->name = brd->SerialName;
+ brd->SerialDriver->name_base = 0;
+ brd->SerialDriver->major = 0;
+ brd->SerialDriver->minor_start = 0;
+ brd->SerialDriver->type = TTY_DRIVER_TYPE_SERIAL;
+ brd->SerialDriver->subtype = SERIAL_TYPE_NORMAL;
+ brd->SerialDriver->init_termios = DgapDefaultTermios;
+ brd->SerialDriver->driver_name = DRVSTR;
+ brd->SerialDriver->flags = (TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_HARDWARE_BREAK);
+
+ /* The kernel wants space to store pointers to tty_structs */
+ brd->SerialDriver->ttys =
+ kzalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL);
+ if (!brd->SerialDriver->ttys)
+ return -ENOMEM;
+
+ /*
+ * Entry points for driver. Called by the kernel from
+ * tty_io.c and n_tty.c.
+ */
+ tty_set_operations(brd->SerialDriver, &dgap_tty_ops);
+
+ /*
+ * If we're doing transparent print, we have to do all of the above
+ * again, separately so we don't get the LD confused about what major
+ * we are when we get into the dgap_tty_open() routine.
+ */
+ brd->PrintDriver = alloc_tty_driver(MAXPORTS);
+
+ snprintf(brd->PrintName, MAXTTYNAMELEN, "pr_dgap_%d_", brd->boardnum);
+ brd->PrintDriver->name = brd->PrintName;
+ brd->PrintDriver->name_base = 0;
+ brd->PrintDriver->major = 0;
+ brd->PrintDriver->minor_start = 0;
+ brd->PrintDriver->type = TTY_DRIVER_TYPE_SERIAL;
+ brd->PrintDriver->subtype = SERIAL_TYPE_NORMAL;
+ brd->PrintDriver->init_termios = DgapDefaultTermios;
+ brd->PrintDriver->driver_name = DRVSTR;
+ brd->PrintDriver->flags = (TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_HARDWARE_BREAK);
+
+ /* The kernel wants space to store pointers to tty_structs */
+ brd->PrintDriver->ttys =
+ kzalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL);
+ if (!brd->PrintDriver->ttys)
+ return -ENOMEM;
+
+ /*
+ * Entry points for driver. Called by the kernel from
+ * tty_io.c and n_tty.c.
+ */
+ tty_set_operations(brd->PrintDriver, &dgap_tty_ops);
+
+ if (!brd->dgap_Major_Serial_Registered) {
+ /* Register tty devices */
+ rc = tty_register_driver(brd->SerialDriver);
+ if (rc < 0)
+ return rc;
+ brd->dgap_Major_Serial_Registered = TRUE;
+ dgap_BoardsByMajor[brd->SerialDriver->major] = brd;
+ brd->dgap_Serial_Major = brd->SerialDriver->major;
+ }
+
+ if (!brd->dgap_Major_TransparentPrint_Registered) {
+ /* Register Transparent Print devices */
+ rc = tty_register_driver(brd->PrintDriver);
+ if (rc < 0)
+ return rc;
+ brd->dgap_Major_TransparentPrint_Registered = TRUE;
+ dgap_BoardsByMajor[brd->PrintDriver->major] = brd;
+ brd->dgap_TransparentPrint_Major = brd->PrintDriver->major;
+ }
+
+ return rc;
+}
+
+/*
+ * dgap_tty_init()
+ *
+ * Init the tty subsystem. Called once per board after board has been
+ * downloaded and init'ed.
+ */
+static int dgap_tty_init(struct board_t *brd)
+{
+ int i;
+ int tlw;
+ uint true_count = 0;
+ uchar *vaddr;
+ uchar modem = 0;
+ struct channel_t *ch;
+ struct bs_t *bs;
+ struct cm_t *cm;
+
+ if (!brd)
+ return -ENXIO;
+
+ /*
+ * Initialize board structure elements.
+ */
+
+ vaddr = brd->re_map_membase;
+ true_count = readw((vaddr + NCHAN));
+
+ brd->nasync = dgap_config_get_num_prts(brd);
+
+ if (!brd->nasync)
+ brd->nasync = brd->maxports;
+
+ if (brd->nasync > brd->maxports)
+ brd->nasync = brd->maxports;
+
+ if (true_count != brd->nasync) {
+ if ((brd->type == PPCM) && (true_count == 64)) {
+ pr_warn("dgap: %s configured for %d ports, has %d ports.\n",
+ brd->name, brd->nasync, true_count);
+ pr_warn("dgap: Please make SURE the EBI cable running from the card\n");
+ pr_warn("dgap: to each EM module is plugged into EBI IN!\n");
+ } else if ((brd->type == PPCM) && (true_count == 0)) {
+ pr_warn("dgap: %s configured for %d ports, has %d ports.\n",
+ brd->name, brd->nasync, true_count);
+ pr_warn("dgap: Please make SURE the EBI cable running from the card\n");
+ pr_warn("dgap: to each EM module is plugged into EBI IN!\n");
+ } else
+ pr_warn("dgap: %s configured for %d ports, has %d ports.\n",
+ brd->name, brd->nasync, true_count);
+
+ brd->nasync = true_count;
+
+ /* If no ports, don't bother going any further */
+ if (!brd->nasync) {
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+ return -ENXIO;
+ }
+ }
+
+ /*
+ * Allocate channel memory that might not have been allocated
+ * when the driver was first loaded.
+ */
+ for (i = 0; i < brd->nasync; i++) {
+ if (!brd->channels[i]) {
+ brd->channels[i] =
+ kzalloc(sizeof(struct channel_t), GFP_ATOMIC);
+ if (!brd->channels[i])
+ return -ENOMEM;
+ }
+ }
+
+ ch = brd->channels[0];
+ vaddr = brd->re_map_membase;
+
+ bs = (struct bs_t *) ((ulong) vaddr + CHANBUF);
+ cm = (struct cm_t *) ((ulong) vaddr + CMDBUF);
+
+ brd->bd_bs = bs;
+
+ /* Set up channel variables */
+ for (i = 0; i < brd->nasync; i++, ch = brd->channels[i], bs++) {
+
+ if (!brd->channels[i])
+ continue;
+
+ spin_lock_init(&ch->ch_lock);
+
+ /* Store all our magic numbers */
+ ch->magic = DGAP_CHANNEL_MAGIC;
+ ch->ch_tun.magic = DGAP_UNIT_MAGIC;
+ ch->ch_tun.un_type = DGAP_SERIAL;
+ ch->ch_tun.un_ch = ch;
+ ch->ch_tun.un_dev = i;
+
+ ch->ch_pun.magic = DGAP_UNIT_MAGIC;
+ ch->ch_pun.un_type = DGAP_PRINT;
+ ch->ch_pun.un_ch = ch;
+ ch->ch_pun.un_dev = i;
+
+ ch->ch_vaddr = vaddr;
+ ch->ch_bs = bs;
+ ch->ch_cm = cm;
+ ch->ch_bd = brd;
+ ch->ch_portnum = i;
+ ch->ch_digi = dgap_digi_init;
+
+ /*
+ * Set up digi dsr and dcd bits based on altpin flag.
+ */
+ if (dgap_config_get_altpin(brd)) {
+ ch->ch_dsr = DM_CD;
+ ch->ch_cd = DM_DSR;
+ ch->ch_digi.digi_flags |= DIGI_ALTPIN;
+ } else {
+ ch->ch_cd = DM_CD;
+ ch->ch_dsr = DM_DSR;
+ }
+
+ ch->ch_taddr = vaddr + ((ch->ch_bs->tx_seg) << 4);
+ ch->ch_raddr = vaddr + ((ch->ch_bs->rx_seg) << 4);
+ ch->ch_tx_win = 0;
+ ch->ch_rx_win = 0;
+ ch->ch_tsize = readw(&(ch->ch_bs->tx_max)) + 1;
+ ch->ch_rsize = readw(&(ch->ch_bs->rx_max)) + 1;
+ ch->ch_tstart = 0;
+ ch->ch_rstart = 0;
+
+ /* .25 second delay */
+ ch->ch_close_delay = 250;
+
+ /*
+ * Set queue water marks, interrupt mask,
+ * and general tty parameters.
+ */
+ tlw = ch->ch_tsize >= 2000 ? ((ch->ch_tsize * 5) / 8) :
+ ch->ch_tsize / 2;
+ ch->ch_tlw = tlw;
+
+ dgap_cmdw(ch, STLOW, tlw, 0);
+
+ dgap_cmdw(ch, SRLOW, ch->ch_rsize / 2, 0);
+
+ dgap_cmdw(ch, SRHIGH, 7 * ch->ch_rsize / 8, 0);
+
+ ch->ch_mistat = readb(&(ch->ch_bs->m_stat));
+
+ init_waitqueue_head(&ch->ch_flags_wait);
+ init_waitqueue_head(&ch->ch_tun.un_flags_wait);
+ init_waitqueue_head(&ch->ch_pun.un_flags_wait);
+ init_waitqueue_head(&ch->ch_sniff_wait);
+
+ /* Turn on all modem interrupts for now */
+ modem = (DM_CD | DM_DSR | DM_CTS | DM_RI);
+ writeb(modem, &(ch->ch_bs->m_int));
+
+ /*
+ * Set edelay to 0 if interrupts are turned on,
+ * otherwise set edelay to the usual 100.
+ */
+ if (brd->intr_used)
+ writew(0, &(ch->ch_bs->edelay));
+ else
+ writew(100, &(ch->ch_bs->edelay));
+
+ writeb(1, &(ch->ch_bs->idata));
+ }
+
+ return 0;
+}
+
+/*
+ * dgap_tty_uninit()
+ *
+ * Uninitialize the TTY portion of this driver. Free all memory and
+ * resources.
+ */
+static void dgap_tty_uninit(struct board_t *brd)
+{
+ struct device *dev;
+ int i = 0;
+
+ if (brd->dgap_Major_Serial_Registered) {
+ dgap_BoardsByMajor[brd->SerialDriver->major] = NULL;
+ brd->dgap_Serial_Major = 0;
+ for (i = 0; i < brd->nasync; i++) {
+ tty_port_destroy(&brd->SerialPorts[i]);
+ dev = brd->channels[i]->ch_tun.un_sysfs;
+ dgap_remove_tty_sysfs(dev);
+ tty_unregister_device(brd->SerialDriver, i);
+ }
+ tty_unregister_driver(brd->SerialDriver);
+ kfree(brd->SerialDriver->ttys);
+ brd->SerialDriver->ttys = NULL;
+ put_tty_driver(brd->SerialDriver);
+ kfree(brd->SerialPorts);
+ brd->dgap_Major_Serial_Registered = FALSE;
+ }
+
+ if (brd->dgap_Major_TransparentPrint_Registered) {
+ dgap_BoardsByMajor[brd->PrintDriver->major] = NULL;
+ brd->dgap_TransparentPrint_Major = 0;
+ for (i = 0; i < brd->nasync; i++) {
+ tty_port_destroy(&brd->PrinterPorts[i]);
+ dev = brd->channels[i]->ch_pun.un_sysfs;
+ dgap_remove_tty_sysfs(dev);
+ tty_unregister_device(brd->PrintDriver, i);
+ }
+ tty_unregister_driver(brd->PrintDriver);
+ kfree(brd->PrintDriver->ttys);
+ brd->PrintDriver->ttys = NULL;
+ put_tty_driver(brd->PrintDriver);
+ kfree(brd->PrinterPorts);
+ brd->dgap_Major_TransparentPrint_Registered = FALSE;
+ }
+}
+
+#define TMPBUFLEN (1024)
+/*
+ * dgap_sniff - Dump data out to the "sniff" buffer if the
+ * proc sniff file is opened...
+ */
+static void dgap_sniff_nowait_nolock(struct channel_t *ch, uchar *text,
+ uchar *buf, int len)
+{
+ struct timeval tv;
+ int n;
+ int r;
+ int nbuf;
+ int i;
+ int tmpbuflen;
+ char tmpbuf[TMPBUFLEN];
+ char *p = tmpbuf;
+ int too_much_data;
+
+ /* Leave if sniff not open */
+ if (!(ch->ch_sniff_flags & SNIFF_OPEN))
+ return;
+
+ do_gettimeofday(&tv);
+
+ /* Create our header for data dump */
+ p += sprintf(p, "<%ld %ld><%s><", tv.tv_sec, tv.tv_usec, text);
+ tmpbuflen = p - tmpbuf;
+
+ do {
+ too_much_data = 0;
+
+ for (i = 0; i < len && tmpbuflen < (TMPBUFLEN - 4); i++) {
+ p += sprintf(p, "%02x ", *buf);
+ buf++;
+ tmpbuflen = p - tmpbuf;
+ }
+
+ if (tmpbuflen < (TMPBUFLEN - 4)) {
+ if (i > 0)
+ p += sprintf(p - 1, "%s\n", ">");
+ else
+ p += sprintf(p, "%s\n", ">");
+ } else {
+ too_much_data = 1;
+ len -= i;
+ }
+
+ nbuf = strlen(tmpbuf);
+ p = tmpbuf;
+
+ /*
+ * Loop while data remains.
+ */
+ while (nbuf > 0 && ch->ch_sniff_buf) {
+ /*
+ * Determine the amount of available space left in the
+ * buffer. If there's none, wait until some appears.
+ */
+ n = (ch->ch_sniff_out - ch->ch_sniff_in - 1) &
+ SNIFF_MASK;
+
+ /*
+ * If there is no space left to write to in our sniff
+ * buffer, we have no choice but to drop the data.
+ * We *cannot* sleep here waiting for space, because
+ * this function was probably called by the
+ * interrupt/timer routines!
+ */
+ if (n == 0)
+ return;
+
+ /*
+ * Copy as much data as will fit.
+ */
+
+ if (n > nbuf)
+ n = nbuf;
+
+ r = SNIFF_MAX - ch->ch_sniff_in;
+
+ if (r <= n) {
+ memcpy(ch->ch_sniff_buf +
+ ch->ch_sniff_in, p, r);
+
+ n -= r;
+ ch->ch_sniff_in = 0;
+ p += r;
+ nbuf -= r;
+ }
+
+ memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, n);
+
+ ch->ch_sniff_in += n;
+ p += n;
+ nbuf -= n;
+
+ /*
+ * Wakeup any thread waiting for data
+ */
+ if (ch->ch_sniff_flags & SNIFF_WAIT_DATA) {
+ ch->ch_sniff_flags &= ~SNIFF_WAIT_DATA;
+ wake_up_interruptible(&ch->ch_sniff_wait);
+ }
+ }
+
+ /*
+ * If the user sent us too much data to push into our tmpbuf,
+ * we need to keep looping around on all the data.
+ */
+ if (too_much_data) {
+ p = tmpbuf;
+ tmpbuflen = 0;
+ }
+
+ } while (too_much_data);
+}
+
+/*=======================================================================
+ *
+ * dgap_input - Process received data.
+ *
+ * ch - Pointer to channel structure.
+ *
+ *=======================================================================*/
+
+static void dgap_input(struct channel_t *ch)
+{
+ struct board_t *bd;
+ struct bs_t *bs;
+ struct tty_struct *tp;
+ struct tty_ldisc *ld;
+ uint rmask;
+ uint head;
+ uint tail;
+ int data_len;
+ ulong lock_flags;
+ ulong lock_flags2;
+ int flip_len;
+ int len = 0;
+ int n = 0;
+ uchar *buf;
+ uchar tmpchar;
+ int s = 0;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ tp = ch->ch_tun.un_tty;
+
+ bs = ch->ch_bs;
+ if (!bs)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ /*
+ * Figure the number of characters in the buffer.
+ * Exit immediately if none.
+ */
+
+ rmask = ch->ch_rsize - 1;
+
+ head = readw(&(bs->rx_head));
+ head &= rmask;
+ tail = readw(&(bs->rx_tail));
+ tail &= rmask;
+
+ data_len = (head - tail) & rmask;
+
+ if (data_len == 0) {
+ writeb(1, &(bs->idata));
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return;
+ }
+
+ /*
+ * If the device is not open, or CREAD is off, flush
+ * input data and return immediately.
+ */
+ if ((bd->state != BOARD_READY) || !tp ||
+ (tp->magic != TTY_MAGIC) ||
+ !(ch->ch_tun.un_flags & UN_ISOPEN) ||
+ !(tp->termios.c_cflag & CREAD) ||
+ (ch->ch_tun.un_flags & UN_CLOSING)) {
+
+ writew(head, &(bs->rx_tail));
+ writeb(1, &(bs->idata));
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return;
+ }
+
+ /*
+ * If we are throttled, simply don't read any data.
+ */
+ if (ch->ch_flags & CH_RXBLOCK) {
+ writeb(1, &(bs->idata));
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return;
+ }
+
+ /*
+ * Ignore oruns.
+ */
+ tmpchar = readb(&(bs->orun));
+ if (tmpchar) {
+ ch->ch_err_overrun++;
+ writeb(0, &(bs->orun));
+ }
+
+ /* Decide how much data we can send into the tty layer */
+ flip_len = TTY_FLIPBUF_SIZE;
+
+ /* Chop down the length, if needed */
+ len = min(data_len, flip_len);
+ len = min(len, (N_TTY_BUF_SIZE - 1));
+
+ ld = tty_ldisc_ref(tp);
+
+#ifdef TTY_DONT_FLIP
+ /*
+ * If the DONT_FLIP flag is on, don't flush our buffer, and act
+ * like the ld doesn't have any space to put the data right now.
+ */
+ if (test_bit(TTY_DONT_FLIP, &tp->flags))
+ len = 0;
+#endif
+
+ /*
+ * If we were unable to get a reference to the ld,
+ * don't flush our buffer, and act like the ld doesn't
+ * have any space to put the data right now.
+ */
+ if (!ld) {
+ len = 0;
+ } else {
+ /*
+ * If ld doesn't have a pointer to a receive_buf function,
+ * flush the data, then act like the ld doesn't have any
+ * space to put the data right now.
+ */
+ if (!ld->ops->receive_buf) {
+ writew(head, &(bs->rx_tail));
+ len = 0;
+ }
+ }
+
+ if (len <= 0) {
+ writeb(1, &(bs->idata));
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ if (ld)
+ tty_ldisc_deref(ld);
+ return;
+ }
+
+ buf = ch->ch_bd->flipbuf;
+ n = len;
+
+ /*
+ * n now contains the most amount of data we can copy,
+ * bounded either by our buffer size or the amount
+ * of data the card actually has pending...
+ */
+ while (n) {
+
+ s = ((head >= tail) ? head : ch->ch_rsize) - tail;
+ s = min(s, n);
+
+ if (s <= 0)
+ break;
+
+ memcpy_fromio(buf, (char *) ch->ch_raddr + tail, s);
+ dgap_sniff_nowait_nolock(ch, "USER READ", buf, s);
+
+ tail += s;
+ buf += s;
+
+ n -= s;
+ /* Flip queue if needed */
+ tail &= rmask;
+ }
+
+ writew(tail, &(bs->rx_tail));
+ writeb(1, &(bs->idata));
+ ch->ch_rxcount += len;
+
+ /*
+ * If we are completely raw, we don't need to go through a lot
+ * of the tty layers that exist.
+ * In this case, we take the shortest and fastest route we
+ * can to relay the data to the user.
+ *
+ * On the other hand, if we are not raw, we need to go through
+ * the tty layer, which has its API more well defined.
+ */
+ if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+ dgap_parity_scan(ch, ch->ch_bd->flipbuf,
+ ch->ch_bd->flipflagbuf, &len);
+
+ len = tty_buffer_request_room(tp->port, len);
+ tty_insert_flip_string_flags(tp->port, ch->ch_bd->flipbuf,
+ ch->ch_bd->flipflagbuf, len);
+ } else {
+ len = tty_buffer_request_room(tp->port, len);
+ tty_insert_flip_string(tp->port, ch->ch_bd->flipbuf, len);
+ }
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ /* Tell the tty layer its okay to "eat" the data now */
+ tty_flip_buffer_push(tp->port);
+
+ if (ld)
+ tty_ldisc_deref(ld);
+
+}
+
+/************************************************************************
+ * Determines when CARRIER changes state and takes appropriate
+ * action.
+ ************************************************************************/
+static void dgap_carrier(struct channel_t *ch)
+{
+ struct board_t *bd;
+
+ int virt_carrier = 0;
+ int phys_carrier = 0;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ /* Make sure altpin is always set correctly */
+ if (ch->ch_digi.digi_flags & DIGI_ALTPIN) {
+ ch->ch_dsr = DM_CD;
+ ch->ch_cd = DM_DSR;
+ } else {
+ ch->ch_dsr = DM_DSR;
+ ch->ch_cd = DM_CD;
+ }
+
+ if (ch->ch_mistat & D_CD(ch))
+ phys_carrier = 1;
+
+ if (ch->ch_digi.digi_flags & DIGI_FORCEDCD)
+ virt_carrier = 1;
+
+ if (ch->ch_c_cflag & CLOCAL)
+ virt_carrier = 1;
+
+ /*
+ * Test for a VIRTUAL carrier transition to HIGH.
+ */
+ if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
+
+ /*
+ * When carrier rises, wake any threads waiting
+ * for carrier in the open routine.
+ */
+
+ if (waitqueue_active(&(ch->ch_flags_wait)))
+ wake_up_interruptible(&ch->ch_flags_wait);
+ }
+
+ /*
+ * Test for a PHYSICAL carrier transition to HIGH.
+ */
+ if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
+
+ /*
+ * When carrier rises, wake any threads waiting
+ * for carrier in the open routine.
+ */
+
+ if (waitqueue_active(&(ch->ch_flags_wait)))
+ wake_up_interruptible(&ch->ch_flags_wait);
+ }
+
+ /*
+ * Test for a PHYSICAL transition to low, so long as we aren't
+ * currently ignoring physical transitions (which is what "virtual
+ * carrier" indicates).
+ *
+ * The transition of the virtual carrier to low really doesn't
+ * matter... it really only means "ignore carrier state", not
+ * "make pretend that carrier is there".
+ */
+ if ((virt_carrier == 0) &&
+ ((ch->ch_flags & CH_CD) != 0) &&
+ (phys_carrier == 0)) {
+
+ /*
+ * When carrier drops:
+ *
+ * Drop carrier on all open units.
+ *
+ * Flush queues, waking up any task waiting in the
+ * line discipline.
+ *
+ * Send a hangup to the control terminal.
+ *
+ * Enable all select calls.
+ */
+ if (waitqueue_active(&(ch->ch_flags_wait)))
+ wake_up_interruptible(&ch->ch_flags_wait);
+
+ if (ch->ch_tun.un_open_count > 0)
+ tty_hangup(ch->ch_tun.un_tty);
+
+ if (ch->ch_pun.un_open_count > 0)
+ tty_hangup(ch->ch_pun.un_tty);
+ }
+
+ /*
+ * Make sure that our cached values reflect the current reality.
+ */
+ if (virt_carrier == 1)
+ ch->ch_flags |= CH_FCAR;
+ else
+ ch->ch_flags &= ~CH_FCAR;
+
+ if (phys_carrier == 1)
+ ch->ch_flags |= CH_CD;
+ else
+ ch->ch_flags &= ~CH_CD;
+}
+
+/************************************************************************
+ *
+ * TTY Entry points and helper functions
+ *
+ ************************************************************************/
+
+/*
+ * dgap_tty_open()
+ *
+ */
+static int dgap_tty_open(struct tty_struct *tty, struct file *file)
+{
+ struct board_t *brd;
+ struct channel_t *ch;
+ struct un_t *un;
+ struct bs_t *bs;
+ uint major = 0;
+ uint minor = 0;
+ int rc = 0;
+ ulong lock_flags;
+ ulong lock_flags2;
+ u16 head;
+
+ rc = 0;
+
+ major = MAJOR(tty_devnum(tty));
+ minor = MINOR(tty_devnum(tty));
+
+ if (major > 255)
+ return -ENXIO;
+
+ /* Get board pointer from our array of majors we have allocated */
+ brd = dgap_BoardsByMajor[major];
+ if (!brd)
+ return -ENXIO;
+
+ /*
+ * If board is not yet up to a state of READY, go to
+ * sleep waiting for it to happen or they cancel the open.
+ */
+ rc = wait_event_interruptible(brd->state_wait,
+ (brd->state & BOARD_READY));
+
+ if (rc)
+ return rc;
+
+ spin_lock_irqsave(&brd->bd_lock, lock_flags);
+
+ /* The wait above should guarantee this cannot happen */
+ if (brd->state != BOARD_READY) {
+ spin_unlock_irqrestore(&brd->bd_lock, lock_flags);
+ return -ENXIO;
+ }
+
+ /* If opened device is greater than our number of ports, bail. */
+ if (MINOR(tty_devnum(tty)) > brd->nasync) {
+ spin_unlock_irqrestore(&brd->bd_lock, lock_flags);
+ return -ENXIO;
+ }
+
+ ch = brd->channels[minor];
+ if (!ch) {
+ spin_unlock_irqrestore(&brd->bd_lock, lock_flags);
+ return -ENXIO;
+ }
+
+ /* Grab channel lock */
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ /* Figure out our type */
+ if (major == brd->dgap_Serial_Major) {
+ un = &brd->channels[minor]->ch_tun;
+ un->un_type = DGAP_SERIAL;
+ } else if (major == brd->dgap_TransparentPrint_Major) {
+ un = &brd->channels[minor]->ch_pun;
+ un->un_type = DGAP_PRINT;
+ } else {
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&brd->bd_lock, lock_flags);
+ return -ENXIO;
+ }
+
+ /* Store our unit into driver_data, so we always have it available. */
+ tty->driver_data = un;
+
+ /*
+ * Error if channel info pointer is NULL.
+ */
+ bs = ch->ch_bs;
+ if (!bs) {
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&brd->bd_lock, lock_flags);
+ return -ENXIO;
+ }
+
+ /*
+ * Initialize tty's
+ */
+ if (!(un->un_flags & UN_ISOPEN)) {
+ /* Store important variables. */
+ un->un_tty = tty;
+
+ /* Maybe do something here to the TTY struct as well? */
+ }
+
+ /*
+ * Initialize if neither terminal or printer is open.
+ */
+ if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) {
+
+ ch->ch_mforce = 0;
+ ch->ch_mval = 0;
+
+ /*
+ * Flush input queue.
+ */
+ head = readw(&(bs->rx_head));
+ writew(head, &(bs->rx_tail));
+
+ ch->ch_flags = 0;
+ ch->pscan_state = 0;
+ ch->pscan_savechar = 0;
+
+ ch->ch_c_cflag = tty->termios.c_cflag;
+ ch->ch_c_iflag = tty->termios.c_iflag;
+ ch->ch_c_oflag = tty->termios.c_oflag;
+ ch->ch_c_lflag = tty->termios.c_lflag;
+ ch->ch_startc = tty->termios.c_cc[VSTART];
+ ch->ch_stopc = tty->termios.c_cc[VSTOP];
+
+ /* TODO: flush our TTY struct here? */
+ }
+
+ dgap_carrier(ch);
+ /*
+ * Run param in case we changed anything
+ */
+ dgap_param(tty);
+
+ /*
+ * follow protocol for opening port
+ */
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&brd->bd_lock, lock_flags);
+
+ rc = dgap_block_til_ready(tty, file, ch);
+
+ if (!un->un_tty)
+ return -ENODEV;
+
+ /* No going back now, increment our unit and channel counters */
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+ ch->ch_open_count++;
+ un->un_open_count++;
+ un->un_flags |= (UN_ISOPEN);
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ return rc;
+}
+
+/*
+ * dgap_block_til_ready()
+ *
+ * Wait for DCD, if needed.
+ */
+static int dgap_block_til_ready(struct tty_struct *tty, struct file *file,
+ struct channel_t *ch)
+{
+ int retval = 0;
+ struct un_t *un = NULL;
+ ulong lock_flags;
+ uint old_flags = 0;
+ int sleep_on_un_flags = 0;
+
+ if (!tty || tty->magic != TTY_MAGIC || !file || !ch ||
+ ch->magic != DGAP_CHANNEL_MAGIC)
+ return -ENXIO;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return -ENXIO;
+
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+ ch->ch_wopen++;
+
+ /* Loop forever */
+ while (1) {
+
+ sleep_on_un_flags = 0;
+
+ /*
+ * If board has failed somehow during our sleep,
+ * bail with error.
+ */
+ if (ch->ch_bd->state == BOARD_FAILED) {
+ retval = -ENXIO;
+ break;
+ }
+
+ /* If tty was hung up, break out of loop and set error. */
+ if (tty_hung_up_p(file)) {
+ retval = -EAGAIN;
+ break;
+ }
+
+ /*
+ * If either unit is in the middle of the fragile part of close,
+ * we just cannot touch the channel safely.
+ * Go back to sleep, knowing that when the channel can be
+ * touched safely, the close routine will signal the
+ * ch_wait_flags to wake us back up.
+ */
+ if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) &
+ UN_CLOSING)) {
+
+ /*
+ * Our conditions to leave cleanly and happily:
+ * 1) NONBLOCKING on the tty is set.
+ * 2) CLOCAL is set.
+ * 3) DCD (fake or real) is active.
+ */
+
+ if (file->f_flags & O_NONBLOCK)
+ break;
+
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ break;
+
+ if (ch->ch_flags & CH_CD)
+ break;
+
+ if (ch->ch_flags & CH_FCAR)
+ break;
+ } else {
+ sleep_on_un_flags = 1;
+ }
+
+ /*
+ * If there is a signal pending, the user probably
+ * interrupted (ctrl-c) us.
+ * Leave loop with error set.
+ */
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+
+ /*
+ * Store the flags before we let go of channel lock
+ */
+ if (sleep_on_un_flags)
+ old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags;
+ else
+ old_flags = ch->ch_flags;
+
+ /*
+ * Let go of channel lock before calling schedule.
+ * Our poller will get any FEP events and wake us up when DCD
+ * eventually goes active.
+ */
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ /*
+ * Wait for something in the flags to change
+ * from the current value.
+ */
+ if (sleep_on_un_flags) {
+ retval = wait_event_interruptible(un->un_flags_wait,
+ (old_flags != (ch->ch_tun.un_flags |
+ ch->ch_pun.un_flags)));
+ } else {
+ retval = wait_event_interruptible(ch->ch_flags_wait,
+ (old_flags != ch->ch_flags));
+ }
+
+ /*
+ * We got woken up for some reason.
+ * Before looping around, grab our channel lock.
+ */
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+ }
+
+ ch->ch_wopen--;
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
+/*
+ * dgap_tty_hangup()
+ *
+ * Hangup the port. Like a close, but don't wait for output to drain.
+ */
+static void dgap_tty_hangup(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ /* flush the transmit queues */
+ dgap_tty_flush_buffer(tty);
+
+}
+
+/*
+ * dgap_tty_close()
+ *
+ */
+static void dgap_tty_close(struct tty_struct *tty, struct file *file)
+{
+ struct ktermios *ts;
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ int rc = 0;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ ts = &tty->termios;
+
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+ /*
+ * Determine if this is the last close or not - and if we agree about
+ * which type of close it is with the Line Discipline
+ */
+ if ((tty->count == 1) && (un->un_open_count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. un_open_count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ un->un_open_count = 1;
+ }
+
+ if (--un->un_open_count < 0)
+ un->un_open_count = 0;
+
+ ch->ch_open_count--;
+
+ if (ch->ch_open_count && un->un_open_count) {
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+ return;
+ }
+
+ /* OK, its the last close on the unit */
+
+ un->un_flags |= UN_CLOSING;
+
+ tty->closing = 1;
+
+ /*
+ * Only officially close channel if count is 0 and
+ * DIGI_PRINTER bit is not set.
+ */
+ if ((ch->ch_open_count == 0) &&
+ !(ch->ch_digi.digi_flags & DIGI_PRINTER)) {
+
+ ch->ch_flags &= ~(CH_RXBLOCK);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ /* wait for output to drain */
+ /* This will also return if we take an interrupt */
+
+ rc = dgap_wait_for_drain(tty);
+
+ dgap_tty_flush_buffer(tty);
+ tty_ldisc_flush(tty);
+
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+ tty->closing = 0;
+
+ /*
+ * If we have HUPCL set, lower DTR and RTS
+ */
+ if (ch->ch_c_cflag & HUPCL) {
+ ch->ch_mostat &= ~(D_RTS(ch)|D_DTR(ch));
+ dgap_cmdb(ch, SMODEM, 0, D_DTR(ch)|D_RTS(ch), 0);
+
+ /*
+ * Go to sleep to ensure RTS/DTR
+ * have been dropped for modems to see it.
+ */
+ if (ch->ch_close_delay) {
+ spin_unlock_irqrestore(&ch->ch_lock,
+ lock_flags);
+ dgap_ms_sleep(ch->ch_close_delay);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+ }
+ }
+
+ ch->pscan_state = 0;
+ ch->pscan_savechar = 0;
+ ch->ch_baud_info = 0;
+
+ }
+
+ /*
+ * turn off print device when closing print device.
+ */
+ if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON)) {
+ dgap_wmove(ch, ch->ch_digi.digi_offstr,
+ (int) ch->ch_digi.digi_offlen);
+ ch->ch_flags &= ~CH_PRON;
+ }
+
+ un->un_tty = NULL;
+ un->un_flags &= ~(UN_ISOPEN | UN_CLOSING);
+ tty->driver_data = NULL;
+
+ wake_up_interruptible(&ch->ch_flags_wait);
+ wake_up_interruptible(&un->un_flags_wait);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+}
+
+/*
+ * dgap_tty_chars_in_buffer()
+ *
+ * Return number of characters that have not been transmitted yet.
+ *
+ * This routine is used by the line discipline to determine if there
+ * is data waiting to be transmitted/drained/flushed or not.
+ */
+static int dgap_tty_chars_in_buffer(struct tty_struct *tty)
+{
+ struct board_t *bd = NULL;
+ struct channel_t *ch = NULL;
+ struct un_t *un = NULL;
+ struct bs_t *bs = NULL;
+ uchar tbusy;
+ uint chars = 0;
+ u16 thead, ttail, tmask, chead, ctail;
+ ulong lock_flags = 0;
+ ulong lock_flags2 = 0;
+
+ if (tty == NULL)
+ return 0;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return 0;
+
+ bs = ch->ch_bs;
+ if (!bs)
+ return 0;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ tmask = (ch->ch_tsize - 1);
+
+ /* Get Transmit queue pointers */
+ thead = readw(&(bs->tx_head)) & tmask;
+ ttail = readw(&(bs->tx_tail)) & tmask;
+
+ /* Get tbusy flag */
+ tbusy = readb(&(bs->tbusy));
+
+ /* Get Command queue pointers */
+ chead = readw(&(ch->ch_cm->cm_head));
+ ctail = readw(&(ch->ch_cm->cm_tail));
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ /*
+ * The only way we know for sure if there is no pending
+ * data left to be transferred, is if:
+ * 1) Transmit head and tail are equal (empty).
+ * 2) Command queue head and tail are equal (empty).
+ * 3) The "TBUSY" flag is 0. (Transmitter not busy).
+ */
+
+ if ((ttail == thead) && (tbusy == 0) && (chead == ctail)) {
+ chars = 0;
+ } else {
+ if (thead >= ttail)
+ chars = thead - ttail;
+ else
+ chars = thead - ttail + ch->ch_tsize;
+ /*
+ * Fudge factor here.
+ * If chars is zero, we know that the command queue had
+ * something in it or tbusy was set. Because we cannot
+ * be sure if there is still some data to be transmitted,
+ * lets lie, and tell ld we have 1 byte left.
+ */
+ if (chars == 0) {
+ /*
+ * If TBUSY is still set, and our tx buffers are empty,
+ * force the firmware to send me another wakeup after
+ * TBUSY has been cleared.
+ */
+ if (tbusy != 0) {
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+ un->un_flags |= UN_EMPTY;
+ writeb(1, &(bs->iempty));
+ spin_unlock_irqrestore(&ch->ch_lock,
+ lock_flags);
+ }
+ chars = 1;
+ }
+ }
+
+ return chars;
+}
+
+static int dgap_wait_for_drain(struct tty_struct *tty)
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ struct bs_t *bs;
+ int ret = -EIO;
+ uint count = 1;
+ ulong lock_flags = 0;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return ret;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return ret;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return ret;
+
+ bs = ch->ch_bs;
+ if (!bs)
+ return ret;
+
+ ret = 0;
+
+ /* Loop until data is drained */
+ while (count != 0) {
+
+ count = dgap_tty_chars_in_buffer(tty);
+
+ if (count == 0)
+ break;
+
+ /* Set flag waiting for drain */
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+ un->un_flags |= UN_EMPTY;
+ writeb(1, &(bs->iempty));
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ /* Go to sleep till we get woken up */
+ ret = wait_event_interruptible(un->un_flags_wait,
+ ((un->un_flags & UN_EMPTY) == 0));
+ /* If ret is non-zero, user ctrl-c'ed us */
+ if (ret)
+ break;
+ }
+
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+ un->un_flags &= ~(UN_EMPTY);
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ return ret;
+}
+
+/*
+ * dgap_maxcps_room
+ *
+ * Reduces bytes_available to the max number of characters
+ * that can be sent currently given the maxcps value, and
+ * returns the new bytes_available. This only affects printer
+ * output.
+ */
+static int dgap_maxcps_room(struct tty_struct *tty, int bytes_available)
+{
+ struct channel_t *ch = NULL;
+ struct un_t *un = NULL;
+
+ if (tty == NULL)
+ return bytes_available;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return bytes_available;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return bytes_available;
+
+ /*
+ * If its not the Transparent print device, return
+ * the full data amount.
+ */
+ if (un->un_type != DGAP_PRINT)
+ return bytes_available;
+
+ if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0) {
+ int cps_limit = 0;
+ unsigned long current_time = jiffies;
+ unsigned long buffer_time = current_time +
+ (HZ * ch->ch_digi.digi_bufsize) /
+ ch->ch_digi.digi_maxcps;
+
+ if (ch->ch_cpstime < current_time) {
+ /* buffer is empty */
+ ch->ch_cpstime = current_time; /* reset ch_cpstime */
+ cps_limit = ch->ch_digi.digi_bufsize;
+ } else if (ch->ch_cpstime < buffer_time) {
+ /* still room in the buffer */
+ cps_limit = ((buffer_time - ch->ch_cpstime) *
+ ch->ch_digi.digi_maxcps) / HZ;
+ } else {
+ /* no room in the buffer */
+ cps_limit = 0;
+ }
+
+ bytes_available = min(cps_limit, bytes_available);
+ }
+
+ return bytes_available;
+}
+
+static inline void dgap_set_firmware_event(struct un_t *un, unsigned int event)
+{
+ struct channel_t *ch = NULL;
+ struct bs_t *bs = NULL;
+
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+ bs = ch->ch_bs;
+ if (!bs)
+ return;
+
+ if ((event & UN_LOW) != 0) {
+ if ((un->un_flags & UN_LOW) == 0) {
+ un->un_flags |= UN_LOW;
+ writeb(1, &(bs->ilow));
+ }
+ }
+ if ((event & UN_LOW) != 0) {
+ if ((un->un_flags & UN_EMPTY) == 0) {
+ un->un_flags |= UN_EMPTY;
+ writeb(1, &(bs->iempty));
+ }
+ }
+}
+
+/*
+ * dgap_tty_write_room()
+ *
+ * Return space available in Tx buffer
+ */
+static int dgap_tty_write_room(struct tty_struct *tty)
+{
+ struct channel_t *ch = NULL;
+ struct un_t *un = NULL;
+ struct bs_t *bs = NULL;
+ u16 head, tail, tmask;
+ int ret = 0;
+ ulong lock_flags = 0;
+
+ if (!tty)
+ return 0;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+
+ bs = ch->ch_bs;
+ if (!bs)
+ return 0;
+
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+ tmask = ch->ch_tsize - 1;
+ head = readw(&(bs->tx_head)) & tmask;
+ tail = readw(&(bs->tx_tail)) & tmask;
+
+ ret = tail - head - 1;
+ if (ret < 0)
+ ret += ch->ch_tsize;
+
+ /* Limit printer to maxcps */
+ ret = dgap_maxcps_room(tty, ret);
+
+ /*
+ * If we are printer device, leave space for
+ * possibly both the on and off strings.
+ */
+ if (un->un_type == DGAP_PRINT) {
+ if (!(ch->ch_flags & CH_PRON))
+ ret -= ch->ch_digi.digi_onlen;
+ ret -= ch->ch_digi.digi_offlen;
+ } else {
+ if (ch->ch_flags & CH_PRON)
+ ret -= ch->ch_digi.digi_offlen;
+ }
+
+ if (ret < 0)
+ ret = 0;
+
+ /*
+ * Schedule FEP to wake us up if needed.
+ *
+ * TODO: This might be overkill...
+ * Do we really need to schedule callbacks from the FEP
+ * in every case? Can we get smarter based on ret?
+ */
+ dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ return ret;
+}
+
+/*
+ * dgap_tty_put_char()
+ *
+ * Put a character into ch->ch_buf
+ *
+ * - used by the line discipline for OPOST processing
+ */
+static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c)
+{
+ /*
+ * Simply call tty_write.
+ */
+ dgap_tty_write(tty, &c, 1);
+ return 1;
+}
+
+/*
+ * dgap_tty_write()
+ *
+ * Take data from the user or kernel and send it out to the FEP.
+ * In here exists all the Transparent Print magic as well.
+ */
+static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf,
+ int count)
+{
+ struct channel_t *ch = NULL;
+ struct un_t *un = NULL;
+ struct bs_t *bs = NULL;
+ char *vaddr = NULL;
+ u16 head, tail, tmask, remain;
+ int bufcount = 0, n = 0;
+ int orig_count = 0;
+ ulong lock_flags;
+
+ if (!tty)
+ return 0;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+
+ bs = ch->ch_bs;
+ if (!bs)
+ return 0;
+
+ if (!count)
+ return 0;
+
+ /*
+ * Store original amount of characters passed in.
+ * This helps to figure out if we should ask the FEP
+ * to send us an event when it has more space available.
+ */
+ orig_count = count;
+
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+ /* Get our space available for the channel from the board */
+ tmask = ch->ch_tsize - 1;
+ head = readw(&(bs->tx_head)) & tmask;
+ tail = readw(&(bs->tx_tail)) & tmask;
+
+ bufcount = tail - head - 1;
+ if (bufcount < 0)
+ bufcount += ch->ch_tsize;
+
+ /*
+ * Limit printer output to maxcps overall, with bursts allowed
+ * up to bufsize characters.
+ */
+ bufcount = dgap_maxcps_room(tty, bufcount);
+
+ /*
+ * Take minimum of what the user wants to send, and the
+ * space available in the FEP buffer.
+ */
+ count = min(count, bufcount);
+
+ /*
+ * Bail if no space left.
+ */
+ if (count <= 0) {
+ dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+ return 0;
+ }
+
+ /*
+ * Output the printer ON string, if we are in terminal mode, but
+ * need to be in printer mode.
+ */
+ if ((un->un_type == DGAP_PRINT) && !(ch->ch_flags & CH_PRON)) {
+ dgap_wmove(ch, ch->ch_digi.digi_onstr,
+ (int) ch->ch_digi.digi_onlen);
+ head = readw(&(bs->tx_head)) & tmask;
+ ch->ch_flags |= CH_PRON;
+ }
+
+ /*
+ * On the other hand, output the printer OFF string, if we are
+ * currently in printer mode, but need to output to the terminal.
+ */
+ if ((un->un_type != DGAP_PRINT) && (ch->ch_flags & CH_PRON)) {
+ dgap_wmove(ch, ch->ch_digi.digi_offstr,
+ (int) ch->ch_digi.digi_offlen);
+ head = readw(&(bs->tx_head)) & tmask;
+ ch->ch_flags &= ~CH_PRON;
+ }
+
+ /*
+ * If there is nothing left to copy, or
+ * I can't handle any more data, leave.
+ */
+ if (count <= 0) {
+ dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+ return 0;
+ }
+
+ n = count;
+
+ /*
+ * If the write wraps over the top of the circular buffer,
+ * move the portion up to the wrap point, and reset the
+ * pointers to the bottom.
+ */
+ remain = ch->ch_tstart + ch->ch_tsize - head;
+
+ if (n >= remain) {
+ n -= remain;
+ vaddr = ch->ch_taddr + head;
+
+ memcpy_toio(vaddr, (uchar *) buf, remain);
+ dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf,
+ remain);
+
+ head = ch->ch_tstart;
+ buf += remain;
+ }
+
+ if (n > 0) {
+
+ /*
+ * Move rest of data.
+ */
+ vaddr = ch->ch_taddr + head;
+ remain = n;
+
+ memcpy_toio(vaddr, (uchar *) buf, remain);
+ dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *)buf,
+ remain);
+
+ head += remain;
+
+ }
+
+ if (count) {
+ ch->ch_txcount += count;
+ head &= tmask;
+ writew(head, &(bs->tx_head));
+ }
+
+ dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
+
+ /*
+ * If this is the print device, and the
+ * printer is still on, we need to turn it
+ * off before going idle. If the buffer is
+ * non-empty, wait until it goes empty.
+ * Otherwise turn it off right now.
+ */
+ if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON)) {
+ tail = readw(&(bs->tx_tail)) & tmask;
+
+ if (tail != head) {
+ un->un_flags |= UN_EMPTY;
+ writeb(1, &(bs->iempty));
+ } else {
+ dgap_wmove(ch, ch->ch_digi.digi_offstr,
+ (int) ch->ch_digi.digi_offlen);
+ head = readw(&(bs->tx_head)) & tmask;
+ ch->ch_flags &= ~CH_PRON;
+ }
+ }
+
+ /* Update printer buffer empty time. */
+ if ((un->un_type == DGAP_PRINT) && (ch->ch_digi.digi_maxcps > 0)
+ && (ch->ch_digi.digi_bufsize > 0)) {
+ ch->ch_cpstime += (HZ * count) / ch->ch_digi.digi_maxcps;
+ }
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ return count;
+}
+
+/*
+ * Return modem signals to ld.
+ */
+static int dgap_tty_tiocmget(struct tty_struct *tty)
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ int result = -EIO;
+ uchar mstat = 0;
+ ulong lock_flags;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return result;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return result;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return result;
+
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+ mstat = readb(&(ch->ch_bs->m_stat));
+ /* Append any outbound signals that might be pending... */
+ mstat |= ch->ch_mostat;
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ result = 0;
+
+ if (mstat & D_DTR(ch))
+ result |= TIOCM_DTR;
+ if (mstat & D_RTS(ch))
+ result |= TIOCM_RTS;
+ if (mstat & D_CTS(ch))
+ result |= TIOCM_CTS;
+ if (mstat & D_DSR(ch))
+ result |= TIOCM_DSR;
+ if (mstat & D_RI(ch))
+ result |= TIOCM_RI;
+ if (mstat & D_CD(ch))
+ result |= TIOCM_CD;
+
+ return result;
+}
+
+/*
+ * dgap_tty_tiocmset()
+ *
+ * Set modem signals, called by ld.
+ */
+static int dgap_tty_tiocmset(struct tty_struct *tty,
+ unsigned int set, unsigned int clear)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int ret = -EIO;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return ret;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return ret;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return ret;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return ret;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ if (set & TIOCM_RTS) {
+ ch->ch_mforce |= D_RTS(ch);
+ ch->ch_mval |= D_RTS(ch);
+ }
+
+ if (set & TIOCM_DTR) {
+ ch->ch_mforce |= D_DTR(ch);
+ ch->ch_mval |= D_DTR(ch);
+ }
+
+ if (clear & TIOCM_RTS) {
+ ch->ch_mforce |= D_RTS(ch);
+ ch->ch_mval &= ~(D_RTS(ch));
+ }
+
+ if (clear & TIOCM_DTR) {
+ ch->ch_mforce |= D_DTR(ch);
+ ch->ch_mval &= ~(D_DTR(ch));
+ }
+
+ dgap_param(tty);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ return 0;
+}
+
+/*
+ * dgap_tty_send_break()
+ *
+ * Send a Break, called by ld.
+ */
+static int dgap_tty_send_break(struct tty_struct *tty, int msec)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int ret = -EIO;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return ret;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return ret;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return ret;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return ret;
+
+ switch (msec) {
+ case -1:
+ msec = 0xFFFF;
+ break;
+ case 0:
+ msec = 1;
+ break;
+ default:
+ msec /= 10;
+ break;
+ }
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+#if 0
+ dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
+#endif
+ dgap_cmdw(ch, SBREAK, (u16) msec, 0);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ return 0;
+}
+
+/*
+ * dgap_tty_wait_until_sent()
+ *
+ * wait until data has been transmitted, called by ld.
+ */
+static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ dgap_wait_for_drain(tty);
+}
+
+/*
+ * dgap_send_xchar()
+ *
+ * send a high priority character, called by ld.
+ */
+static void dgap_tty_send_xchar(struct tty_struct *tty, char c)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ /*
+ * This is technically what we should do.
+ * However, the NIST tests specifically want
+ * to see each XON or XOFF character that it
+ * sends, so lets just send each character
+ * by hand...
+ */
+#if 0
+ if (c == STOP_CHAR(tty))
+ dgap_cmdw(ch, RPAUSE, 0, 0);
+ else if (c == START_CHAR(tty))
+ dgap_cmdw(ch, RRESUME, 0, 0);
+ else
+ dgap_wmove(ch, &c, 1);
+#else
+ dgap_wmove(ch, &c, 1);
+#endif
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ return;
+}
+
+/*
+ * Return modem signals to ld.
+ */
+static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value)
+{
+ int result = 0;
+ uchar mstat = 0;
+ ulong lock_flags;
+ int rc = 0;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return -ENXIO;
+
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+ mstat = readb(&(ch->ch_bs->m_stat));
+ /* Append any outbound signals that might be pending... */
+ mstat |= ch->ch_mostat;
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ result = 0;
+
+ if (mstat & D_DTR(ch))
+ result |= TIOCM_DTR;
+ if (mstat & D_RTS(ch))
+ result |= TIOCM_RTS;
+ if (mstat & D_CTS(ch))
+ result |= TIOCM_CTS;
+ if (mstat & D_DSR(ch))
+ result |= TIOCM_DSR;
+ if (mstat & D_RI(ch))
+ result |= TIOCM_RI;
+ if (mstat & D_CD(ch))
+ result |= TIOCM_CD;
+
+ rc = put_user(result, value);
+
+ return rc;
+}
+
+/*
+ * dgap_set_modem_info()
+ *
+ * Set modem signals, called by ld.
+ */
+static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command,
+ unsigned int __user *value)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int ret = -ENXIO;
+ unsigned int arg = 0;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return ret;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return ret;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return ret;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return ret;
+
+ ret = get_user(arg, value);
+ if (ret)
+ return ret;
+
+ switch (command) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS) {
+ ch->ch_mforce |= D_RTS(ch);
+ ch->ch_mval |= D_RTS(ch);
+ }
+
+ if (arg & TIOCM_DTR) {
+ ch->ch_mforce |= D_DTR(ch);
+ ch->ch_mval |= D_DTR(ch);
+ }
+
+ break;
+
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS) {
+ ch->ch_mforce |= D_RTS(ch);
+ ch->ch_mval &= ~(D_RTS(ch));
+ }
+
+ if (arg & TIOCM_DTR) {
+ ch->ch_mforce |= D_DTR(ch);
+ ch->ch_mval &= ~(D_DTR(ch));
+ }
+
+ break;
+
+ case TIOCMSET:
+ ch->ch_mforce = D_DTR(ch)|D_RTS(ch);
+
+ if (arg & TIOCM_RTS)
+ ch->ch_mval |= D_RTS(ch);
+ else
+ ch->ch_mval &= ~(D_RTS(ch));
+
+ if (arg & TIOCM_DTR)
+ ch->ch_mval |= (D_DTR(ch));
+ else
+ ch->ch_mval &= ~(D_DTR(ch));
+
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ dgap_param(tty);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ return 0;
+}
+
+/*
+ * dgap_tty_digigeta()
+ *
+ * Ioctl to get the information for ditty.
+ *
+ *
+ *
+ */
+static int dgap_tty_digigeta(struct tty_struct *tty,
+ struct digi_t __user *retinfo)
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ struct digi_t tmp;
+ ulong lock_flags;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return -EFAULT;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return -EFAULT;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+ memcpy(&tmp, &ch->ch_digi, sizeof(tmp));
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * dgap_tty_digiseta()
+ *
+ * Ioctl to set the information for ditty.
+ *
+ *
+ *
+ */
+static int dgap_tty_digiseta(struct tty_struct *tty,
+ struct digi_t __user *new_info)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ struct digi_t new_digi;
+ ulong lock_flags = 0;
+ unsigned long lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return -EFAULT;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return -EFAULT;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return -EFAULT;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return -EFAULT;
+
+ if (copy_from_user(&new_digi, new_info, sizeof(struct digi_t)))
+ return -EFAULT;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ memcpy(&ch->ch_digi, &new_digi, sizeof(struct digi_t));
+
+ if (ch->ch_digi.digi_maxcps < 1)
+ ch->ch_digi.digi_maxcps = 1;
+
+ if (ch->ch_digi.digi_maxcps > 10000)
+ ch->ch_digi.digi_maxcps = 10000;
+
+ if (ch->ch_digi.digi_bufsize < 10)
+ ch->ch_digi.digi_bufsize = 10;
+
+ if (ch->ch_digi.digi_maxchar < 1)
+ ch->ch_digi.digi_maxchar = 1;
+
+ if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize)
+ ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize;
+
+ if (ch->ch_digi.digi_onlen > DIGI_PLEN)
+ ch->ch_digi.digi_onlen = DIGI_PLEN;
+
+ if (ch->ch_digi.digi_offlen > DIGI_PLEN)
+ ch->ch_digi.digi_offlen = DIGI_PLEN;
+
+ dgap_param(tty);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ return 0;
+}
+
+/*
+ * dgap_tty_digigetedelay()
+ *
+ * Ioctl to get the current edelay setting.
+ *
+ *
+ *
+ */
+static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo)
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ int tmp;
+ ulong lock_flags;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return -EFAULT;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return -EFAULT;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+ tmp = readw(&(ch->ch_bs->edelay));
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * dgap_tty_digisetedelay()
+ *
+ * Ioctl to set the EDELAY setting
+ *
+ */
+static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int new_digi;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return -EFAULT;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return -EFAULT;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return -EFAULT;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return -EFAULT;
+
+ if (copy_from_user(&new_digi, new_info, sizeof(int)))
+ return -EFAULT;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ writew((u16) new_digi, &(ch->ch_bs->edelay));
+
+ dgap_param(tty);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ return 0;
+}
+
+/*
+ * dgap_tty_digigetcustombaud()
+ *
+ * Ioctl to get the current custom baud rate setting.
+ */
+static int dgap_tty_digigetcustombaud(struct tty_struct *tty,
+ int __user *retinfo)
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ int tmp;
+ ulong lock_flags;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return -EFAULT;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return -EFAULT;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+
+ spin_lock_irqsave(&ch->ch_lock, lock_flags);
+ tmp = dgap_get_custom_baud(ch);
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * dgap_tty_digisetcustombaud()
+ *
+ * Ioctl to set the custom baud rate setting
+ */
+static int dgap_tty_digisetcustombaud(struct tty_struct *tty,
+ int __user *new_info)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ uint new_rate;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return -EFAULT;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return -EFAULT;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return -EFAULT;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return -EFAULT;
+
+
+ if (copy_from_user(&new_rate, new_info, sizeof(unsigned int)))
+ return -EFAULT;
+
+ if (bd->bd_flags & BD_FEP5PLUS) {
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ ch->ch_custom_speed = new_rate;
+
+ dgap_param(tty);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ }
+
+ return 0;
+}
+
+/*
+ * dgap_set_termios()
+ */
+static void dgap_tty_set_termios(struct tty_struct *tty,
+ struct ktermios *old_termios)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ unsigned long lock_flags;
+ unsigned long lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ ch->ch_c_cflag = tty->termios.c_cflag;
+ ch->ch_c_iflag = tty->termios.c_iflag;
+ ch->ch_c_oflag = tty->termios.c_oflag;
+ ch->ch_c_lflag = tty->termios.c_lflag;
+ ch->ch_startc = tty->termios.c_cc[VSTART];
+ ch->ch_stopc = tty->termios.c_cc[VSTOP];
+
+ dgap_carrier(ch);
+ dgap_param(tty);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+}
+
+static void dgap_tty_throttle(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ ch->ch_flags |= (CH_RXBLOCK);
+#if 1
+ dgap_cmdw(ch, RPAUSE, 0, 0);
+#endif
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+}
+
+static void dgap_tty_unthrottle(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ ch->ch_flags &= ~(CH_RXBLOCK);
+
+#if 1
+ dgap_cmdw(ch, RRESUME, 0, 0);
+#endif
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+}
+
+static void dgap_tty_start(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ dgap_cmdw(ch, RESUMETX, 0, 0);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+}
+
+static void dgap_tty_stop(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ dgap_cmdw(ch, PAUSETX, 0, 0);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+}
+
+/*
+ * dgap_tty_flush_chars()
+ *
+ * Flush the cook buffer
+ *
+ * Note to self, and any other poor souls who venture here:
+ *
+ * flush in this case DOES NOT mean dispose of the data.
+ * instead, it means "stop buffering and send it if you
+ * haven't already." Just guess how I figured that out... SRW 2-Jun-98
+ *
+ * It is also always called in interrupt context - JAR 8-Sept-99
+ */
+static void dgap_tty_flush_chars(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ /* TODO: Do something here */
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+}
+
+/*
+ * dgap_tty_flush_buffer()
+ *
+ * Flush Tx buffer (make in == out)
+ */
+static void dgap_tty_flush_buffer(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+ u16 head = 0;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ ch->ch_flags &= ~CH_STOP;
+ head = readw(&(ch->ch_bs->tx_head));
+ dgap_cmdw(ch, FLUSHTX, (u16) head, 0);
+ dgap_cmdw(ch, RESUMETX, 0, 0);
+ if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
+ ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
+ wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+ }
+ if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
+ ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
+ wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+ }
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ if (waitqueue_active(&tty->write_wait))
+ wake_up_interruptible(&tty->write_wait);
+ tty_wakeup(tty);
+}
+
+/*****************************************************************************
+ *
+ * The IOCTL function and all of its helpers
+ *
+ *****************************************************************************/
+
+/*
+ * dgap_tty_ioctl()
+ *
+ * The usual assortment of ioctl's
+ */
+static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
+ unsigned long arg)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int rc;
+ u16 head = 0;
+ ulong lock_flags = 0;
+ ulong lock_flags2 = 0;
+ void __user *uarg = (void __user *) arg;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return -ENODEV;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return -ENODEV;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return -ENODEV;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return -ENODEV;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ if (un->un_open_count <= 0) {
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return -EIO;
+ }
+
+ switch (cmd) {
+
+ /* Here are all the standard ioctl's that we MUST implement */
+
+ case TCSBRK:
+ /*
+ * TCSBRK is SVID version: non-zero arg --> no break
+ * this behaviour is exploited by tcdrain().
+ *
+ * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+ * between 0.25 and 0.5 seconds so we'll ask for something
+ * in the middle: 0.375 seconds.
+ */
+ rc = tty_check_change(tty);
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ if (rc)
+ return rc;
+
+ rc = dgap_wait_for_drain(tty);
+
+ if (rc)
+ return -EINTR;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ if (((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP))
+ dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ return 0;
+
+ case TCSBRKP:
+ /* support for POSIX tcsendbreak()
+
+ * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+ * between 0.25 and 0.5 seconds so we'll ask for something
+ * in the middle: 0.375 seconds.
+ */
+ rc = tty_check_change(tty);
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ if (rc)
+ return rc;
+
+ rc = dgap_wait_for_drain(tty);
+ if (rc)
+ return -EINTR;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ return 0;
+
+ case TIOCSBRK:
+ /*
+ * FEP5 doesn't support turning on a break unconditionally.
+ * The FEP5 device will stop sending a break automatically
+ * after the specified time value that was sent when turning on
+ * the break.
+ */
+ rc = tty_check_change(tty);
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ if (rc)
+ return rc;
+
+ rc = dgap_wait_for_drain(tty);
+ if (rc)
+ return -EINTR;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ return 0;
+
+ case TIOCCBRK:
+ /*
+ * FEP5 doesn't support turning off a break unconditionally.
+ * The FEP5 device will stop sending a break automatically
+ * after the specified time value that was sent when turning on
+ * the break.
+ */
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return 0;
+
+ case TIOCGSOFTCAR:
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ rc = put_user(C_CLOCAL(tty) ? 1 : 0,
+ (unsigned long __user *) arg);
+ return rc;
+
+ case TIOCSSOFTCAR:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ rc = get_user(arg, (unsigned long __user *) arg);
+ if (rc)
+ return rc;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+ tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
+ dgap_param(tty);
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ return 0;
+
+ case TIOCMGET:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return dgap_get_modem_info(ch, uarg);
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return dgap_set_modem_info(tty, cmd, uarg);
+
+ /*
+ * Here are any additional ioctl's that we want to implement
+ */
+
+ case TCFLSH:
+ /*
+ * The linux tty driver doesn't have a flush
+ * input routine for the driver, assuming all backed
+ * up data is in the line disc. buffers. However,
+ * we all know that's not the case. Here, we
+ * act on the ioctl, but then lie and say we didn't
+ * so the line discipline will process the flush
+ * also.
+ */
+ rc = tty_check_change(tty);
+ if (rc) {
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return rc;
+ }
+
+ if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) {
+ if (!(un->un_type == DGAP_PRINT)) {
+ head = readw(&(ch->ch_bs->rx_head));
+ writew(head, &(ch->ch_bs->rx_tail));
+ writeb(0, &(ch->ch_bs->orun));
+ }
+ }
+
+ if ((arg != TCOFLUSH) && (arg != TCIOFLUSH)) {
+ /* pretend we didn't recognize this IOCTL */
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ return -ENOIOCTLCMD;
+ }
+
+ ch->ch_flags &= ~CH_STOP;
+ head = readw(&(ch->ch_bs->tx_head));
+ dgap_cmdw(ch, FLUSHTX, (u16) head, 0);
+ dgap_cmdw(ch, RESUMETX, 0, 0);
+ if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
+ ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
+ wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+ }
+ if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
+ ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
+ wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+ }
+ if (waitqueue_active(&tty->write_wait))
+ wake_up_interruptible(&tty->write_wait);
+
+ /* Can't hold any locks when calling tty_wakeup! */
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ tty_wakeup(tty);
+
+ /* pretend we didn't recognize this IOCTL */
+ return -ENOIOCTLCMD;
+
+ case TCSETSF:
+ case TCSETSW:
+ /*
+ * The linux tty driver doesn't have a flush
+ * input routine for the driver, assuming all backed
+ * up data is in the line disc. buffers. However,
+ * we all know that's not the case. Here, we
+ * act on the ioctl, but then lie and say we didn't
+ * so the line discipline will process the flush
+ * also.
+ */
+ if (cmd == TCSETSF) {
+ /* flush rx */
+ ch->ch_flags &= ~CH_STOP;
+ head = readw(&(ch->ch_bs->rx_head));
+ writew(head, &(ch->ch_bs->rx_tail));
+ }
+
+ /* now wait for all the output to drain */
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ rc = dgap_wait_for_drain(tty);
+ if (rc)
+ return -EINTR;
+
+ /* pretend we didn't recognize this */
+ return -ENOIOCTLCMD;
+
+ case TCSETAW:
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ rc = dgap_wait_for_drain(tty);
+ if (rc)
+ return -EINTR;
+
+ /* pretend we didn't recognize this */
+ return -ENOIOCTLCMD;
+
+ case TCXONC:
+ /*
+ * The Linux Line Discipline (LD) would do this for us if we
+ * let it, but we have the special firmware options to do this
+ * the "right way" regardless of hardware or software flow
+ * control so we'll do it outselves instead of letting the LD
+ * do it.
+ */
+ rc = tty_check_change(tty);
+ if (rc) {
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return rc;
+ }
+
+ switch (arg) {
+
+ case TCOON:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ dgap_tty_start(tty);
+ return 0;
+ case TCOOFF:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ dgap_tty_stop(tty);
+ return 0;
+ case TCION:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ /* Make the ld do it */
+ return -ENOIOCTLCMD;
+ case TCIOFF:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ /* Make the ld do it */
+ return -ENOIOCTLCMD;
+ default:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return -EINVAL;
+ }
+
+ case DIGI_GETA:
+ /* get information for ditty */
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return dgap_tty_digigeta(tty, uarg);
+
+ case DIGI_SETAW:
+ case DIGI_SETAF:
+
+ /* set information for ditty */
+ if (cmd == (DIGI_SETAW)) {
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ rc = dgap_wait_for_drain(tty);
+ if (rc)
+ return -EINTR;
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+ } else
+ tty_ldisc_flush(tty);
+ /* fall thru */
+
+ case DIGI_SETA:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return dgap_tty_digiseta(tty, uarg);
+
+ case DIGI_GEDELAY:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return dgap_tty_digigetedelay(tty, uarg);
+
+ case DIGI_SEDELAY:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return dgap_tty_digisetedelay(tty, uarg);
+
+ case DIGI_GETCUSTOMBAUD:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return dgap_tty_digigetcustombaud(tty, uarg);
+
+ case DIGI_SETCUSTOMBAUD:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return dgap_tty_digisetcustombaud(tty, uarg);
+
+ case DIGI_RESET_PORT:
+ dgap_firmware_reset_port(ch);
+ dgap_param(tty);
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return 0;
+
+ default:
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int dgap_after_config_loaded(int board)
+{
+ /*
+ * Initialize KME waitqueues...
+ */
+ init_waitqueue_head(&(dgap_Board[board]->kme_wait));
+
+ /*
+ * allocate flip buffer for board.
+ */
+ dgap_Board[board]->flipbuf = kmalloc(MYFLIPLEN, GFP_ATOMIC);
+ if (!dgap_Board[board]->flipbuf)
+ return -ENOMEM;
+
+ dgap_Board[board]->flipflagbuf = kmalloc(MYFLIPLEN, GFP_ATOMIC);
+ if (!dgap_Board[board]->flipflagbuf) {
+ kfree(dgap_Board[board]->flipbuf);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/*
+ * Create pr and tty device entries
+ */
+static int dgap_tty_register_ports(struct board_t *brd)
+{
+ struct channel_t *ch;
+ int i;
+
+ brd->SerialPorts = kcalloc(brd->nasync, sizeof(*brd->SerialPorts),
+ GFP_KERNEL);
+ if (brd->SerialPorts == NULL)
+ return -ENOMEM;
+ for (i = 0; i < brd->nasync; i++)
+ tty_port_init(&brd->SerialPorts[i]);
+
+ brd->PrinterPorts = kcalloc(brd->nasync, sizeof(*brd->PrinterPorts),
+ GFP_KERNEL);
+ if (brd->PrinterPorts == NULL) {
+ kfree(brd->SerialPorts);
+ return -ENOMEM;
+ }
+ for (i = 0; i < brd->nasync; i++)
+ tty_port_init(&brd->PrinterPorts[i]);
+
+ ch = brd->channels[0];
+ for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
+
+ struct device *classp;
+
+ classp = tty_port_register_device(&brd->SerialPorts[i],
+ brd->SerialDriver,
+ brd->firstminor + i, NULL);
+
+ dgap_create_tty_sysfs(&ch->ch_tun, classp);
+ ch->ch_tun.un_sysfs = classp;
+
+ classp = tty_port_register_device(&brd->PrinterPorts[i],
+ brd->PrintDriver,
+ brd->firstminor + i, NULL);
+
+ dgap_create_tty_sysfs(&ch->ch_pun, classp);
+ ch->ch_pun.un_sysfs = classp;
+ }
+ dgap_create_ports_sysfiles(brd);
+
+ return 0;
+}
+
+/*
+ * Copies the BIOS code from the user to the board,
+ * and starts the BIOS running.
+ */
+static void dgap_do_bios_load(struct board_t *brd, const uchar *ubios, int len)
+{
+ uchar *addr;
+ uint offset;
+ int i;
+
+ if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+ return;
+
+ addr = brd->re_map_membase;
+
+ /*
+ * clear POST area
+ */
+ for (i = 0; i < 16; i++)
+ writeb(0, addr + POSTAREA + i);
+
+ /*
+ * Download bios
+ */
+ offset = 0x1000;
+ memcpy_toio(addr + offset, ubios, len);
+
+ writel(0x0bf00401, addr);
+ writel(0, (addr + 4));
+
+ /* Clear the reset, and change states. */
+ writeb(FEPCLR, brd->re_map_port);
+}
+
+/*
+ * Checks to see if the BIOS completed running on the card.
+ */
+static int dgap_do_wait_for_bios(struct board_t *brd)
+{
+ uchar *addr;
+ u16 word;
+ u16 err1;
+ u16 err2;
+ int ret = 0;
+
+ if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+ return ret;
+
+ addr = brd->re_map_membase;
+ word = readw(addr + POSTAREA);
+
+ /*
+ * It can take 5-6 seconds for a board to
+ * pass the bios self test and post results.
+ * Give it 10 seconds.
+ */
+ brd->wait_for_bios = 0;
+ while (brd->wait_for_bios < 1000) {
+ /* Check to see if BIOS thinks board is good. (GD). */
+ if (word == *(u16 *) "GD")
+ return 1;
+ msleep_interruptible(10);
+ brd->wait_for_bios++;
+ word = readw(addr + POSTAREA);
+ }
+
+ /* Gave up on board after too long of time taken */
+ err1 = readw(addr + SEQUENCE);
+ err2 = readw(addr + ERROR);
+ pr_warn("dgap: %s failed diagnostics. Error #(%x,%x).\n",
+ brd->name, err1, err2);
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOBIOS;
+
+ return ret;
+}
+
+/*
+ * Copies the FEP code from the user to the board,
+ * and starts the FEP running.
+ */
+static void dgap_do_fep_load(struct board_t *brd, const uchar *ufep, int len)
+{
+ uchar *addr;
+ uint offset;
+
+ if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+ return;
+
+ addr = brd->re_map_membase;
+
+ /*
+ * Download FEP
+ */
+ offset = 0x1000;
+ memcpy_toio(addr + offset, ufep, len);
+
+ /*
+ * If board is a concentrator product, we need to give
+ * it its config string describing how the concentrators look.
+ */
+ if ((brd->type == PCX) || (brd->type == PEPC)) {
+ uchar string[100];
+ uchar *config, *xconfig;
+ int i = 0;
+
+ xconfig = dgap_create_config_string(brd, string);
+
+ /* Write string to board memory */
+ config = addr + CONFIG;
+ for (; i < CONFIGSIZE; i++, config++, xconfig++) {
+ writeb(*xconfig, config);
+ if ((*xconfig & 0xff) == 0xff)
+ break;
+ }
+ }
+
+ writel(0xbfc01004, (addr + 0xc34));
+ writel(0x3, (addr + 0xc30));
+
+}
+
+/*
+ * Waits for the FEP to report thats its ready for us to use.
+ */
+static int dgap_do_wait_for_fep(struct board_t *brd)
+{
+ uchar *addr;
+ u16 word;
+ u16 err1;
+ u16 err2;
+ int ret = 0;
+
+ if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+ return ret;
+
+ addr = brd->re_map_membase;
+ word = readw(addr + FEPSTAT);
+
+ /*
+ * It can take 2-3 seconds for the FEP to
+ * be up and running. Give it 5 secs.
+ */
+ brd->wait_for_fep = 0;
+ while (brd->wait_for_fep < 500) {
+ /* Check to see if FEP is up and running now. */
+ if (word == *(u16 *) "OS") {
+ /*
+ * Check to see if the board can support FEP5+ commands.
+ */
+ word = readw(addr + FEP5_PLUS);
+ if (word == *(u16 *) "5A")
+ brd->bd_flags |= BD_FEP5PLUS;
+
+ return 1;
+ }
+ msleep_interruptible(10);
+ brd->wait_for_fep++;
+ word = readw(addr + FEPSTAT);
+ }
+
+ /* Gave up on board after too long of time taken */
+ err1 = readw(addr + SEQUENCE);
+ err2 = readw(addr + ERROR);
+ pr_warn("dgap: FEPOS for %s not functioning. Error #(%x,%x).\n",
+ brd->name, err1, err2);
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+
+ return ret;
+}
+
+/*
+ * Physically forces the FEP5 card to reset itself.
+ */
+static void dgap_do_reset_board(struct board_t *brd)
+{
+ uchar check;
+ u32 check1;
+ u32 check2;
+ int i = 0;
+
+ if (!brd || (brd->magic != DGAP_BOARD_MAGIC) ||
+ !brd->re_map_membase || !brd->re_map_port)
+ return;
+
+ /* FEPRST does not vary among supported boards */
+ writeb(FEPRST, brd->re_map_port);
+
+ for (i = 0; i <= 1000; i++) {
+ check = readb(brd->re_map_port) & 0xe;
+ if (check == FEPRST)
+ break;
+ udelay(10);
+
+ }
+ if (i > 1000) {
+ pr_warn("dgap: Board not resetting... Failing board.\n");
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+ return;
+ }
+
+ /*
+ * Make sure there really is memory out there.
+ */
+ writel(0xa55a3cc3, (brd->re_map_membase + LOWMEM));
+ writel(0x5aa5c33c, (brd->re_map_membase + HIGHMEM));
+ check1 = readl(brd->re_map_membase + LOWMEM);
+ check2 = readl(brd->re_map_membase + HIGHMEM);
+
+ if ((check1 != 0xa55a3cc3) || (check2 != 0x5aa5c33c)) {
+ pr_warn("dgap: No memory at %p for board.\n",
+ brd->re_map_membase);
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+ return;
+ }
+
+}
+
+#ifdef DIGI_CONCENTRATORS_SUPPORTED
+/*
+ * Sends a concentrator image into the FEP5 board.
+ */
+static void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len)
+{
+ char *vaddr;
+ u16 offset = 0;
+ struct downld_t *to_dp;
+
+ if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+ return;
+
+ vaddr = brd->re_map_membase;
+
+ offset = readw((u16 *) (vaddr + DOWNREQ));
+ to_dp = (struct downld_t *) (vaddr + (int) offset);
+ memcpy_toio(to_dp, uaddr, len);
+
+ /* Tell card we have data for it */
+ writew(0, vaddr + (DOWNREQ));
+
+ brd->conc_dl_status = NO_PENDING_CONCENTRATOR_REQUESTS;
+}
+#endif
+
+#define EXPANSION_ROM_SIZE (64 * 1024)
+#define FEP5_ROM_MAGIC (0xFEFFFFFF)
+
+static void dgap_get_vpd(struct board_t *brd)
+{
+ u32 magic;
+ u32 base_offset;
+ u16 rom_offset;
+ u16 vpd_offset;
+ u16 image_length;
+ u16 i;
+ uchar byte1;
+ uchar byte2;
+
+ /*
+ * Poke the magic number at the PCI Rom Address location.
+ * If VPD is supported, the value read from that address
+ * will be non-zero.
+ */
+ magic = FEP5_ROM_MAGIC;
+ pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
+ pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic);
+
+ /* VPD not supported, bail */
+ if (!magic)
+ return;
+
+ /*
+ * To get to the OTPROM memory, we have to send the boards base
+ * address or'ed with 1 into the PCI Rom Address location.
+ */
+ magic = brd->membase | 0x01;
+ pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
+ pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic);
+
+ byte1 = readb(brd->re_map_membase);
+ byte2 = readb(brd->re_map_membase + 1);
+
+ /*
+ * If the board correctly swapped to the OTPROM memory,
+ * the first 2 bytes (header) should be 0x55, 0xAA
+ */
+ if (byte1 == 0x55 && byte2 == 0xAA) {
+
+ base_offset = 0;
+
+ /*
+ * We have to run through all the OTPROM memory looking
+ * for the VPD offset.
+ */
+ while (base_offset <= EXPANSION_ROM_SIZE) {
+
+ /*
+ * Lots of magic numbers here.
+ *
+ * The VPD offset is located inside the ROM Data
+ * Structure.
+ *
+ * We also have to remember the length of each
+ * ROM Data Structure, so we can "hop" to the next
+ * entry if the VPD isn't in the current
+ * ROM Data Structure.
+ */
+ rom_offset = readw(brd->re_map_membase +
+ base_offset + 0x18);
+ image_length = readw(brd->re_map_membase +
+ rom_offset + 0x10) * 512;
+ vpd_offset = readw(brd->re_map_membase +
+ rom_offset + 0x08);
+
+ /* Found the VPD entry */
+ if (vpd_offset)
+ break;
+
+ /* We didn't find a VPD entry, go to next ROM entry. */
+ base_offset += image_length;
+
+ byte1 = readb(brd->re_map_membase + base_offset);
+ byte2 = readb(brd->re_map_membase + base_offset + 1);
+
+ /*
+ * If the new ROM offset doesn't have 0x55, 0xAA
+ * as its header, we have run out of ROM.
+ */
+ if (byte1 != 0x55 || byte2 != 0xAA)
+ break;
+ }
+
+ /*
+ * If we have a VPD offset, then mark the board
+ * as having a valid VPD, and copy VPDSIZE (512) bytes of
+ * that VPD to the buffer we have in our board structure.
+ */
+ if (vpd_offset) {
+ brd->bd_flags |= BD_HAS_VPD;
+ for (i = 0; i < VPDSIZE; i++) {
+ brd->vpd[i] = readb(brd->re_map_membase +
+ vpd_offset + i);
+ }
+ }
+ }
+
+ /*
+ * We MUST poke the magic number at the PCI Rom Address location again.
+ * This makes the card report the regular board memory back to us,
+ * rather than the OTPROM memory.
+ */
+ magic = FEP5_ROM_MAGIC;
+ pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
+}
+
+/*
+ * Our board poller function.
+ */
+static void dgap_poll_tasklet(unsigned long data)
+{
+ struct board_t *bd = (struct board_t *) data;
+ ulong lock_flags;
+ char *vaddr;
+ u16 head, tail;
+
+ if (!bd || (bd->magic != DGAP_BOARD_MAGIC))
+ return;
+
+ if (bd->inhibit_poller)
+ return;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+
+ vaddr = bd->re_map_membase;
+
+ /*
+ * If board is ready, parse deeper to see if there is anything to do.
+ */
+ if (bd->state == BOARD_READY) {
+
+ struct ev_t *eaddr = NULL;
+
+ if (!bd->re_map_membase) {
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return;
+ }
+ if (!bd->re_map_port) {
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return;
+ }
+
+ if (!bd->nasync)
+ goto out;
+
+ eaddr = (struct ev_t *) (vaddr + EVBUF);
+
+ /* Get our head and tail */
+ head = readw(&(eaddr->ev_head));
+ tail = readw(&(eaddr->ev_tail));
+
+ /*
+ * If there is an event pending. Go service it.
+ */
+ if (head != tail) {
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ dgap_event(bd);
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ }
+
+out:
+ /*
+ * If board is doing interrupts, ACK the interrupt.
+ */
+ if (bd && bd->intr_running)
+ readb(bd->re_map_port + 2);
+
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return;
+ }
+
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+}
+
+/*=======================================================================
+ *
+ * dgap_cmdb - Sends a 2 byte command to the FEP.
+ *
+ * ch - Pointer to channel structure.
+ * cmd - Command to be sent.
+ * byte1 - Integer containing first byte to be sent.
+ * byte2 - Integer containing second byte to be sent.
+ * ncmds - Wait until ncmds or fewer cmds are left
+ * in the cmd buffer before returning.
+ *
+ *=======================================================================*/
+static void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1,
+ uchar byte2, uint ncmds)
+{
+ char *vaddr = NULL;
+ struct cm_t *cm_addr = NULL;
+ uint count;
+ uint n;
+ u16 head;
+ u16 tail;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ /*
+ * Check if board is still alive.
+ */
+ if (ch->ch_bd->state == BOARD_FAILED)
+ return;
+
+ /*
+ * Make sure the pointers are in range before
+ * writing to the FEP memory.
+ */
+ vaddr = ch->ch_bd->re_map_membase;
+
+ if (!vaddr)
+ return;
+
+ cm_addr = (struct cm_t *) (vaddr + CMDBUF);
+ head = readw(&(cm_addr->cm_head));
+
+ /*
+ * Forget it if pointers out of range.
+ */
+ if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
+ ch->ch_bd->state = BOARD_FAILED;
+ return;
+ }
+
+ /*
+ * Put the data in the circular command buffer.
+ */
+ writeb(cmd, (char *) (vaddr + head + CMDSTART + 0));
+ writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1));
+ writeb(byte1, (char *) (vaddr + head + CMDSTART + 2));
+ writeb(byte2, (char *) (vaddr + head + CMDSTART + 3));
+
+ head = (head + 4) & (CMDMAX - CMDSTART - 4);
+
+ writew(head, &(cm_addr->cm_head));
+
+ /*
+ * Wait if necessary before updating the head
+ * pointer to limit the number of outstanding
+ * commands to the FEP. If the time spent waiting
+ * is outlandish, declare the FEP dead.
+ */
+ for (count = dgap_count ;;) {
+
+ head = readw(&(cm_addr->cm_head));
+ tail = readw(&(cm_addr->cm_tail));
+
+ n = (head - tail) & (CMDMAX - CMDSTART - 4);
+
+ if (n <= ncmds * sizeof(struct cm_t))
+ break;
+
+ if (--count == 0) {
+ ch->ch_bd->state = BOARD_FAILED;
+ return;
+ }
+ udelay(10);
+ }
+}
+
+/*=======================================================================
+ *
+ * dgap_cmdw - Sends a 1 word command to the FEP.
+ *
+ * ch - Pointer to channel structure.
+ * cmd - Command to be sent.
+ * word - Integer containing word to be sent.
+ * ncmds - Wait until ncmds or fewer cmds are left
+ * in the cmd buffer before returning.
+ *
+ *=======================================================================*/
+static void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds)
+{
+ char *vaddr = NULL;
+ struct cm_t *cm_addr = NULL;
+ uint count;
+ uint n;
+ u16 head;
+ u16 tail;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ /*
+ * Check if board is still alive.
+ */
+ if (ch->ch_bd->state == BOARD_FAILED)
+ return;
+
+ /*
+ * Make sure the pointers are in range before
+ * writing to the FEP memory.
+ */
+ vaddr = ch->ch_bd->re_map_membase;
+ if (!vaddr)
+ return;
+
+ cm_addr = (struct cm_t *) (vaddr + CMDBUF);
+ head = readw(&(cm_addr->cm_head));
+
+ /*
+ * Forget it if pointers out of range.
+ */
+ if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
+ ch->ch_bd->state = BOARD_FAILED;
+ return;
+ }
+
+ /*
+ * Put the data in the circular command buffer.
+ */
+ writeb(cmd, (char *) (vaddr + head + CMDSTART + 0));
+ writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1));
+ writew((u16) word, (char *) (vaddr + head + CMDSTART + 2));
+
+ head = (head + 4) & (CMDMAX - CMDSTART - 4);
+
+ writew(head, &(cm_addr->cm_head));
+
+ /*
+ * Wait if necessary before updating the head
+ * pointer to limit the number of outstanding
+ * commands to the FEP. If the time spent waiting
+ * is outlandish, declare the FEP dead.
+ */
+ for (count = dgap_count ;;) {
+
+ head = readw(&(cm_addr->cm_head));
+ tail = readw(&(cm_addr->cm_tail));
+
+ n = (head - tail) & (CMDMAX - CMDSTART - 4);
+
+ if (n <= ncmds * sizeof(struct cm_t))
+ break;
+
+ if (--count == 0) {
+ ch->ch_bd->state = BOARD_FAILED;
+ return;
+ }
+ udelay(10);
+ }
+}
+
+/*=======================================================================
+ *
+ * dgap_cmdw_ext - Sends a extended word command to the FEP.
+ *
+ * ch - Pointer to channel structure.
+ * cmd - Command to be sent.
+ * word - Integer containing word to be sent.
+ * ncmds - Wait until ncmds or fewer cmds are left
+ * in the cmd buffer before returning.
+ *
+ *=======================================================================*/
+static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds)
+{
+ char *vaddr = NULL;
+ struct cm_t *cm_addr = NULL;
+ uint count;
+ uint n;
+ u16 head;
+ u16 tail;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ /*
+ * Check if board is still alive.
+ */
+ if (ch->ch_bd->state == BOARD_FAILED)
+ return;
+
+ /*
+ * Make sure the pointers are in range before
+ * writing to the FEP memory.
+ */
+ vaddr = ch->ch_bd->re_map_membase;
+ if (!vaddr)
+ return;
+
+ cm_addr = (struct cm_t *) (vaddr + CMDBUF);
+ head = readw(&(cm_addr->cm_head));
+
+ /*
+ * Forget it if pointers out of range.
+ */
+ if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
+ ch->ch_bd->state = BOARD_FAILED;
+ return;
+ }
+
+ /*
+ * Put the data in the circular command buffer.
+ */
+
+ /* Write an FF to tell the FEP that we want an extended command */
+ writeb((uchar) 0xff, (char *) (vaddr + head + CMDSTART + 0));
+
+ writeb((uchar) ch->ch_portnum, (uchar *) (vaddr + head + CMDSTART + 1));
+ writew((u16) cmd, (char *) (vaddr + head + CMDSTART + 2));
+
+ /*
+ * If the second part of the command won't fit,
+ * put it at the beginning of the circular buffer.
+ */
+ if (((head + 4) >= ((CMDMAX - CMDSTART)) || (head & 03)))
+ writew((u16) word, (char *) (vaddr + CMDSTART));
+ else
+ writew((u16) word, (char *) (vaddr + head + CMDSTART + 4));
+
+ head = (head + 8) & (CMDMAX - CMDSTART - 4);
+
+ writew(head, &(cm_addr->cm_head));
+
+ /*
+ * Wait if necessary before updating the head
+ * pointer to limit the number of outstanding
+ * commands to the FEP. If the time spent waiting
+ * is outlandish, declare the FEP dead.
+ */
+ for (count = dgap_count ;;) {
+
+ head = readw(&(cm_addr->cm_head));
+ tail = readw(&(cm_addr->cm_tail));
+
+ n = (head - tail) & (CMDMAX - CMDSTART - 4);
+
+ if (n <= ncmds * sizeof(struct cm_t))
+ break;
+
+ if (--count == 0) {
+ ch->ch_bd->state = BOARD_FAILED;
+ return;
+ }
+ udelay(10);
+ }
+}
+
+/*=======================================================================
+ *
+ * dgap_wmove - Write data to FEP buffer.
+ *
+ * ch - Pointer to channel structure.
+ * buf - Poiter to characters to be moved.
+ * cnt - Number of characters to move.
+ *
+ *=======================================================================*/
+static void dgap_wmove(struct channel_t *ch, char *buf, uint cnt)
+{
+ int n;
+ char *taddr;
+ struct bs_t *bs;
+ u16 head;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ /*
+ * Check parameters.
+ */
+ bs = ch->ch_bs;
+ head = readw(&(bs->tx_head));
+
+ /*
+ * If pointers are out of range, just return.
+ */
+ if ((cnt > ch->ch_tsize) ||
+ (unsigned)(head - ch->ch_tstart) >= ch->ch_tsize)
+ return;
+
+ /*
+ * If the write wraps over the top of the circular buffer,
+ * move the portion up to the wrap point, and reset the
+ * pointers to the bottom.
+ */
+ n = ch->ch_tstart + ch->ch_tsize - head;
+
+ if (cnt >= n) {
+ cnt -= n;
+ taddr = ch->ch_taddr + head;
+ memcpy_toio(taddr, buf, n);
+ head = ch->ch_tstart;
+ buf += n;
+ }
+
+ /*
+ * Move rest of data.
+ */
+ taddr = ch->ch_taddr + head;
+ n = cnt;
+ memcpy_toio(taddr, buf, n);
+ head += cnt;
+
+ writew(head, &(bs->tx_head));
+}
+
+/*
+ * Retrives the current custom baud rate from FEP memory,
+ * and returns it back to the user.
+ * Returns 0 on error.
+ */
+static uint dgap_get_custom_baud(struct channel_t *ch)
+{
+ uchar *vaddr;
+ ulong offset = 0;
+ uint value = 0;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+
+ if (!ch->ch_bd || ch->ch_bd->magic != DGAP_BOARD_MAGIC)
+ return 0;
+
+ if (!(ch->ch_bd->bd_flags & BD_FEP5PLUS))
+ return 0;
+
+ vaddr = ch->ch_bd->re_map_membase;
+
+ if (!vaddr)
+ return 0;
+
+ /*
+ * Go get from fep mem, what the fep
+ * believes the custom baud rate is.
+ */
+ offset = ((((*(unsigned short *)(vaddr + ECS_SEG)) << 4) +
+ (ch->ch_portnum * 0x28) + LINE_SPEED));
+
+ value = readw(vaddr + offset);
+ return value;
+}
+
+/*
+ * Calls the firmware to reset this channel.
+ */
+static void dgap_firmware_reset_port(struct channel_t *ch)
+{
+ dgap_cmdb(ch, CHRESET, 0, 0, 0);
+
+ /*
+ * Now that the channel is reset, we need to make sure
+ * all the current settings get reapplied to the port
+ * in the firmware.
+ *
+ * So we will set the driver's cache of firmware
+ * settings all to 0, and then call param.
+ */
+ ch->ch_fepiflag = 0;
+ ch->ch_fepcflag = 0;
+ ch->ch_fepoflag = 0;
+ ch->ch_fepstartc = 0;
+ ch->ch_fepstopc = 0;
+ ch->ch_fepastartc = 0;
+ ch->ch_fepastopc = 0;
+ ch->ch_mostat = 0;
+ ch->ch_hflow = 0;
+}
+
+/*=======================================================================
+ *
+ * dgap_param - Set Digi parameters.
+ *
+ * struct tty_struct * - TTY for port.
+ *
+ *=======================================================================*/
+static int dgap_param(struct tty_struct *tty)
+{
+ struct ktermios *ts;
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct bs_t *bs;
+ struct un_t *un;
+ u16 head;
+ u16 cflag;
+ u16 iflag;
+ uchar mval;
+ uchar hflow;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return -ENXIO;
+
+ un = (struct un_t *) tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return -ENXIO;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return -ENXIO;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return -ENXIO;
+
+ bs = ch->ch_bs;
+ if (!bs)
+ return -ENXIO;
+
+ ts = &tty->termios;
+
+ /*
+ * If baud rate is zero, flush queues, and set mval to drop DTR.
+ */
+ if ((ch->ch_c_cflag & (CBAUD)) == 0) {
+
+ /* flush rx */
+ head = readw(&(ch->ch_bs->rx_head));
+ writew(head, &(ch->ch_bs->rx_tail));
+
+ /* flush tx */
+ head = readw(&(ch->ch_bs->tx_head));
+ writew(head, &(ch->ch_bs->tx_tail));
+
+ ch->ch_flags |= (CH_BAUD0);
+
+ /* Drop RTS and DTR */
+ ch->ch_mval &= ~(D_RTS(ch)|D_DTR(ch));
+ mval = D_DTR(ch) | D_RTS(ch);
+ ch->ch_baud_info = 0;
+
+ } else if (ch->ch_custom_speed && (bd->bd_flags & BD_FEP5PLUS)) {
+ /*
+ * Tell the fep to do the command
+ */
+
+ dgap_cmdw_ext(ch, 0xff01, ch->ch_custom_speed, 0);
+
+ /*
+ * Now go get from fep mem, what the fep
+ * believes the custom baud rate is.
+ */
+ ch->ch_custom_speed = dgap_get_custom_baud(ch);
+ ch->ch_baud_info = ch->ch_custom_speed;
+
+ /* Handle transition from B0 */
+ if (ch->ch_flags & CH_BAUD0) {
+ ch->ch_flags &= ~(CH_BAUD0);
+ ch->ch_mval |= (D_RTS(ch)|D_DTR(ch));
+ }
+ mval = D_DTR(ch) | D_RTS(ch);
+
+ } else {
+ /*
+ * Set baud rate, character size, and parity.
+ */
+
+
+ int iindex = 0;
+ int jindex = 0;
+ int baud = 0;
+
+ ulong bauds[4][16] = {
+ { /* slowbaud */
+ 0, 50, 75, 110,
+ 134, 150, 200, 300,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ { /* slowbaud & CBAUDEX */
+ 0, 57600, 115200, 230400,
+ 460800, 150, 200, 921600,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ { /* fastbaud */
+ 0, 57600, 76800, 115200,
+ 14400, 57600, 230400, 76800,
+ 115200, 230400, 28800, 460800,
+ 921600, 9600, 19200, 38400 },
+ { /* fastbaud & CBAUDEX */
+ 0, 57600, 115200, 230400,
+ 460800, 150, 200, 921600,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 }
+ };
+
+ /*
+ * Only use the TXPrint baud rate if the
+ * terminal unit is NOT open
+ */
+ if (!(ch->ch_tun.un_flags & UN_ISOPEN) &&
+ (un->un_type == DGAP_PRINT))
+ baud = C_BAUD(ch->ch_pun.un_tty) & 0xff;
+ else
+ baud = C_BAUD(ch->ch_tun.un_tty) & 0xff;
+
+ if (ch->ch_c_cflag & CBAUDEX)
+ iindex = 1;
+
+ if (ch->ch_digi.digi_flags & DIGI_FAST)
+ iindex += 2;
+
+ jindex = baud;
+
+ if ((iindex >= 0) && (iindex < 4) &&
+ (jindex >= 0) && (jindex < 16))
+ baud = bauds[iindex][jindex];
+ else
+ baud = 0;
+
+ if (baud == 0)
+ baud = 9600;
+
+ ch->ch_baud_info = baud;
+
+ /*
+ * CBAUD has bit position 0x1000 set these days to
+ * indicate Linux baud rate remap.
+ * We use a different bit assignment for high speed.
+ * Clear this bit out while grabbing the parts of
+ * "cflag" we want.
+ */
+ cflag = ch->ch_c_cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB |
+ CSTOPB | CSIZE);
+
+ /*
+ * HUPCL bit is used by FEP to indicate fast baud
+ * table is to be used.
+ */
+ if ((ch->ch_digi.digi_flags & DIGI_FAST) ||
+ (ch->ch_c_cflag & CBAUDEX))
+ cflag |= HUPCL;
+
+ if ((ch->ch_c_cflag & CBAUDEX) &&
+ !(ch->ch_digi.digi_flags & DIGI_FAST)) {
+ /*
+ * The below code is trying to guarantee that only
+ * baud rates 115200, 230400, 460800, 921600 are
+ * remapped. We use exclusive or because the various
+ * baud rates share common bit positions and therefore
+ * can't be tested for easily.
+ */
+ tcflag_t tcflag = (ch->ch_c_cflag & CBAUD) | CBAUDEX;
+ int baudpart = 0;
+
+ /*
+ * Map high speed requests to index
+ * into FEP's baud table
+ */
+ switch (tcflag) {
+ case B57600:
+ baudpart = 1;
+ break;
+#ifdef B76800
+ case B76800:
+ baudpart = 2;
+ break;
+#endif
+ case B115200:
+ baudpart = 3;
+ break;
+ case B230400:
+ baudpart = 9;
+ break;
+ case B460800:
+ baudpart = 11;
+ break;
+#ifdef B921600
+ case B921600:
+ baudpart = 12;
+ break;
+#endif
+ default:
+ baudpart = 0;
+ }
+
+ if (baudpart)
+ cflag = (cflag & ~(CBAUD | CBAUDEX)) | baudpart;
+ }
+
+ cflag &= 0xffff;
+
+ if (cflag != ch->ch_fepcflag) {
+ ch->ch_fepcflag = (u16) (cflag & 0xffff);
+
+ /*
+ * Okay to have channel and board
+ * locks held calling this
+ */
+ dgap_cmdw(ch, SCFLAG, (u16) cflag, 0);
+ }
+
+ /* Handle transition from B0 */
+ if (ch->ch_flags & CH_BAUD0) {
+ ch->ch_flags &= ~(CH_BAUD0);
+ ch->ch_mval |= (D_RTS(ch)|D_DTR(ch));
+ }
+ mval = D_DTR(ch) | D_RTS(ch);
+ }
+
+ /*
+ * Get input flags.
+ */
+ iflag = ch->ch_c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
+ INPCK | ISTRIP | IXON | IXANY | IXOFF);
+
+ if ((ch->ch_startc == _POSIX_VDISABLE) ||
+ (ch->ch_stopc == _POSIX_VDISABLE)) {
+ iflag &= ~(IXON | IXOFF);
+ ch->ch_c_iflag &= ~(IXON | IXOFF);
+ }
+
+ /*
+ * Only the IBM Xr card can switch between
+ * 232 and 422 modes on the fly
+ */
+ if (bd->device == PCI_DEV_XR_IBM_DID) {
+ if (ch->ch_digi.digi_flags & DIGI_422)
+ dgap_cmdb(ch, SCOMMODE, MODE_422, 0, 0);
+ else
+ dgap_cmdb(ch, SCOMMODE, MODE_232, 0, 0);
+ }
+
+ if (ch->ch_digi.digi_flags & DIGI_ALTPIN)
+ iflag |= IALTPIN;
+
+ if (iflag != ch->ch_fepiflag) {
+ ch->ch_fepiflag = iflag;
+
+ /* Okay to have channel and board locks held calling this */
+ dgap_cmdw(ch, SIFLAG, (u16) ch->ch_fepiflag, 0);
+ }
+
+ /*
+ * Select hardware handshaking.
+ */
+ hflow = 0;
+
+ if (ch->ch_c_cflag & CRTSCTS)
+ hflow |= (D_RTS(ch) | D_CTS(ch));
+ if (ch->ch_digi.digi_flags & RTSPACE)
+ hflow |= D_RTS(ch);
+ if (ch->ch_digi.digi_flags & DTRPACE)
+ hflow |= D_DTR(ch);
+ if (ch->ch_digi.digi_flags & CTSPACE)
+ hflow |= D_CTS(ch);
+ if (ch->ch_digi.digi_flags & DSRPACE)
+ hflow |= D_DSR(ch);
+ if (ch->ch_digi.digi_flags & DCDPACE)
+ hflow |= D_CD(ch);
+
+ if (hflow != ch->ch_hflow) {
+ ch->ch_hflow = hflow;
+
+ /* Okay to have channel and board locks held calling this */
+ dgap_cmdb(ch, SHFLOW, (uchar) hflow, 0xff, 0);
+ }
+
+
+ /*
+ * Set RTS and/or DTR Toggle if needed,
+ * but only if product is FEP5+ based.
+ */
+ if (bd->bd_flags & BD_FEP5PLUS) {
+ u16 hflow2 = 0;
+ if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE)
+ hflow2 |= (D_RTS(ch));
+ if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE)
+ hflow2 |= (D_DTR(ch));
+
+ dgap_cmdw_ext(ch, 0xff03, hflow2, 0);
+ }
+
+ /*
+ * Set modem control lines.
+ */
+
+ mval ^= ch->ch_mforce & (mval ^ ch->ch_mval);
+
+ if (ch->ch_mostat ^ mval) {
+ ch->ch_mostat = mval;
+
+ /* Okay to have channel and board locks held calling this */
+ dgap_cmdb(ch, SMODEM, (uchar) mval, D_RTS(ch)|D_DTR(ch), 0);
+ }
+
+ /*
+ * Read modem signals, and then call carrier function.
+ */
+ ch->ch_mistat = readb(&(bs->m_stat));
+ dgap_carrier(ch);
+
+ /*
+ * Set the start and stop characters.
+ */
+ if (ch->ch_startc != ch->ch_fepstartc ||
+ ch->ch_stopc != ch->ch_fepstopc) {
+ ch->ch_fepstartc = ch->ch_startc;
+ ch->ch_fepstopc = ch->ch_stopc;
+
+ /* Okay to have channel and board locks held calling this */
+ dgap_cmdb(ch, SFLOWC, ch->ch_fepstartc, ch->ch_fepstopc, 0);
+ }
+
+ /*
+ * Set the Auxiliary start and stop characters.
+ */
+ if (ch->ch_astartc != ch->ch_fepastartc ||
+ ch->ch_astopc != ch->ch_fepastopc) {
+ ch->ch_fepastartc = ch->ch_astartc;
+ ch->ch_fepastopc = ch->ch_astopc;
+
+ /* Okay to have channel and board locks held calling this */
+ dgap_cmdb(ch, SAFLOWC, ch->ch_fepastartc, ch->ch_fepastopc, 0);
+ }
+
+ return 0;
+}
+
+/*
+ * dgap_parity_scan()
+ *
+ * Convert the FEP5 way of reporting parity errors and breaks into
+ * the Linux line discipline way.
+ */
+static void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf,
+ unsigned char *fbuf, int *len)
+{
+ int l = *len;
+ int count = 0;
+ unsigned char *in, *cout, *fout;
+ unsigned char c;
+
+ in = cbuf;
+ cout = cbuf;
+ fout = fbuf;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ while (l--) {
+ c = *in++;
+ switch (ch->pscan_state) {
+ default:
+ /* reset to sanity and fall through */
+ ch->pscan_state = 0;
+
+ case 0:
+ /* No FF seen yet */
+ if (c == (unsigned char) '\377')
+ /* delete this character from stream */
+ ch->pscan_state = 1;
+ else {
+ *cout++ = c;
+ *fout++ = TTY_NORMAL;
+ count += 1;
+ }
+ break;
+
+ case 1:
+ /* first FF seen */
+ if (c == (unsigned char) '\377') {
+ /* doubled ff, transform to single ff */
+ *cout++ = c;
+ *fout++ = TTY_NORMAL;
+ count += 1;
+ ch->pscan_state = 0;
+ } else {
+ /* save value examination in next state */
+ ch->pscan_savechar = c;
+ ch->pscan_state = 2;
+ }
+ break;
+
+ case 2:
+ /* third character of ff sequence */
+
+ *cout++ = c;
+
+ if (ch->pscan_savechar == 0x0) {
+
+ if (c == 0x0) {
+ ch->ch_err_break++;
+ *fout++ = TTY_BREAK;
+ } else {
+ ch->ch_err_parity++;
+ *fout++ = TTY_PARITY;
+ }
+ }
+
+ count += 1;
+ ch->pscan_state = 0;
+ }
+ }
+ *len = count;
+}
+
+static void dgap_write_wakeup(struct board_t *bd, struct channel_t *ch,
+ struct un_t *un, u32 mask,
+ unsigned long *irq_flags1,
+ unsigned long *irq_flags2)
+{
+ if (!(un->un_flags & mask))
+ return;
+
+ un->un_flags &= ~mask;
+
+ if (!(un->un_flags & UN_ISOPEN))
+ return;
+
+ if ((un->un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ un->un_tty->ldisc->ops->write_wakeup) {
+ spin_unlock_irqrestore(&ch->ch_lock, *irq_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, *irq_flags1);
+
+ (un->un_tty->ldisc->ops->write_wakeup)(un->un_tty);
+
+ spin_lock_irqsave(&bd->bd_lock, *irq_flags1);
+ spin_lock_irqsave(&ch->ch_lock, *irq_flags2);
+ }
+ wake_up_interruptible(&un->un_tty->write_wait);
+ wake_up_interruptible(&un->un_flags_wait);
+}
+
+/*=======================================================================
+ *
+ * dgap_event - FEP to host event processing routine.
+ *
+ * bd - Board of current event.
+ *
+ *=======================================================================*/
+static int dgap_event(struct board_t *bd)
+{
+ struct channel_t *ch;
+ ulong lock_flags;
+ ulong lock_flags2;
+ struct bs_t *bs;
+ uchar *event;
+ uchar *vaddr = NULL;
+ struct ev_t *eaddr = NULL;
+ uint head;
+ uint tail;
+ int port;
+ int reason;
+ int modem;
+ int b1;
+
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return -ENXIO;
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+
+ vaddr = bd->re_map_membase;
+
+ if (!vaddr) {
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return -ENXIO;
+ }
+
+ eaddr = (struct ev_t *) (vaddr + EVBUF);
+
+ /* Get our head and tail */
+ head = readw(&(eaddr->ev_head));
+ tail = readw(&(eaddr->ev_tail));
+
+ /*
+ * Forget it if pointers out of range.
+ */
+
+ if (head >= EVMAX - EVSTART || tail >= EVMAX - EVSTART ||
+ (head | tail) & 03) {
+ /* Let go of board lock */
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+ return -ENXIO;
+ }
+
+ /*
+ * Loop to process all the events in the buffer.
+ */
+ while (tail != head) {
+
+ /*
+ * Get interrupt information.
+ */
+
+ event = bd->re_map_membase + tail + EVSTART;
+
+ port = event[0];
+ reason = event[1];
+ modem = event[2];
+ b1 = event[3];
+
+ /*
+ * Make sure the interrupt is valid.
+ */
+ if (port >= bd->nasync)
+ goto next;
+
+ if (!(reason & (IFMODEM | IFBREAK | IFTLW | IFTEM | IFDATA)))
+ goto next;
+
+ ch = bd->channels[port];
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ goto next;
+
+ /*
+ * If we have made it here, the event was valid.
+ * Lock down the channel.
+ */
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ bs = ch->ch_bs;
+
+ if (!bs) {
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ goto next;
+ }
+
+ /*
+ * Process received data.
+ */
+ if (reason & IFDATA) {
+
+ /*
+ * ALL LOCKS *MUST* BE DROPPED BEFORE CALLING INPUT!
+ * input could send some data to ld, which in turn
+ * could do a callback to one of our other functions.
+ */
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ dgap_input(ch);
+
+ spin_lock_irqsave(&bd->bd_lock, lock_flags);
+ spin_lock_irqsave(&ch->ch_lock, lock_flags2);
+
+ if (ch->ch_flags & CH_RACTIVE)
+ ch->ch_flags |= CH_RENABLE;
+ else
+ writeb(1, &(bs->idata));
+
+ if (ch->ch_flags & CH_RWAIT) {
+ ch->ch_flags &= ~CH_RWAIT;
+
+ wake_up_interruptible
+ (&ch->ch_tun.un_flags_wait);
+ }
+ }
+
+ /*
+ * Process Modem change signals.
+ */
+ if (reason & IFMODEM) {
+ ch->ch_mistat = modem;
+ dgap_carrier(ch);
+ }
+
+ /*
+ * Process break.
+ */
+ if (reason & IFBREAK) {
+
+ if (ch->ch_tun.un_tty) {
+ /* A break has been indicated */
+ ch->ch_err_break++;
+ tty_buffer_request_room
+ (ch->ch_tun.un_tty->port, 1);
+ tty_insert_flip_char(ch->ch_tun.un_tty->port,
+ 0, TTY_BREAK);
+ tty_flip_buffer_push(ch->ch_tun.un_tty->port);
+ }
+ }
+
+ /*
+ * Process Transmit low.
+ */
+ if (reason & IFTLW) {
+ dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_LOW,
+ &lock_flags, &lock_flags2);
+ dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_LOW,
+ &lock_flags, &lock_flags2);
+ if (ch->ch_flags & CH_WLOW) {
+ ch->ch_flags &= ~CH_WLOW;
+ wake_up_interruptible(&ch->ch_flags_wait);
+ }
+ }
+
+ /*
+ * Process Transmit empty.
+ */
+ if (reason & IFTEM) {
+ dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_EMPTY,
+ &lock_flags, &lock_flags2);
+ dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_EMPTY,
+ &lock_flags, &lock_flags2);
+ if (ch->ch_flags & CH_WEMPTY) {
+ ch->ch_flags &= ~CH_WEMPTY;
+ wake_up_interruptible(&ch->ch_flags_wait);
+ }
+ }
+
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
+
+next:
+ tail = (tail + 4) & (EVMAX - EVSTART - 4);
+ }
+
+ writew(tail, &(eaddr->ev_tail));
+ spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
+
+ return 0;
+}
+
+static ssize_t dgap_driver_version_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART);
+}
+static DRIVER_ATTR(version, S_IRUSR, dgap_driver_version_show, NULL);
+
+
+static ssize_t dgap_driver_boards_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", dgap_NumBoards);
+}
+static DRIVER_ATTR(boards, S_IRUSR, dgap_driver_boards_show, NULL);
+
+
+static ssize_t dgap_driver_maxboards_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS);
+}
+static DRIVER_ATTR(maxboards, S_IRUSR, dgap_driver_maxboards_show, NULL);
+
+
+static ssize_t dgap_driver_pollcounter_show(struct device_driver *ddp,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%ld\n", dgap_poll_counter);
+}
+static DRIVER_ATTR(pollcounter, S_IRUSR, dgap_driver_pollcounter_show, NULL);
+
+static ssize_t dgap_driver_pollrate_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%dms\n", dgap_poll_tick);
+}
+
+static ssize_t dgap_driver_pollrate_store(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ if (sscanf(buf, "%d\n", &dgap_poll_tick) != 1)
+ return -EINVAL;
+ return count;
+}
+static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgap_driver_pollrate_show,
+ dgap_driver_pollrate_store);
+
+static int dgap_create_driver_sysfiles(struct pci_driver *dgap_driver)
+{
+ int rc = 0;
+ struct device_driver *driverfs = &dgap_driver->driver;
+
+ rc |= driver_create_file(driverfs, &driver_attr_version);
+ rc |= driver_create_file(driverfs, &driver_attr_boards);
+ rc |= driver_create_file(driverfs, &driver_attr_maxboards);
+ rc |= driver_create_file(driverfs, &driver_attr_pollrate);
+ rc |= driver_create_file(driverfs, &driver_attr_pollcounter);
+
+ return rc;
+}
+
+static void dgap_remove_driver_sysfiles(struct pci_driver *dgap_driver)
+{
+ struct device_driver *driverfs = &dgap_driver->driver;
+ driver_remove_file(driverfs, &driver_attr_version);
+ driver_remove_file(driverfs, &driver_attr_boards);
+ driver_remove_file(driverfs, &driver_attr_maxboards);
+ driver_remove_file(driverfs, &driver_attr_pollrate);
+ driver_remove_file(driverfs, &driver_attr_pollcounter);
+}
+
+static struct board_t *dgap_verify_board(struct device *p)
+{
+ struct board_t *bd;
+
+ if (!p)
+ return NULL;
+
+ bd = dev_get_drvdata(p);
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC || bd->state != BOARD_READY)
+ return NULL;
+
+ return bd;
+}
+
+static ssize_t dgap_ports_state_show(struct device *p,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ bd = dgap_verify_board(p);
+ if (!bd)
+ return 0;
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d %s\n", bd->channels[i]->ch_portnum,
+ bd->channels[i]->ch_open_count ? "Open" : "Closed");
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_state, S_IRUSR, dgap_ports_state_show, NULL);
+
+static ssize_t dgap_ports_baud_show(struct device *p,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ bd = dgap_verify_board(p);
+ if (!bd)
+ return 0;
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %d\n",
+ bd->channels[i]->ch_portnum,
+ bd->channels[i]->ch_baud_info);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_baud, S_IRUSR, dgap_ports_baud_show, NULL);
+
+static ssize_t dgap_ports_msignals_show(struct device *p,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ bd = dgap_verify_board(p);
+ if (!bd)
+ return 0;
+
+ for (i = 0; i < bd->nasync; i++) {
+ if (bd->channels[i]->ch_open_count)
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d %s %s %s %s %s %s\n",
+ bd->channels[i]->ch_portnum,
+ (bd->channels[i]->ch_mostat &
+ UART_MCR_RTS) ? "RTS" : "",
+ (bd->channels[i]->ch_mistat &
+ UART_MSR_CTS) ? "CTS" : "",
+ (bd->channels[i]->ch_mostat &
+ UART_MCR_DTR) ? "DTR" : "",
+ (bd->channels[i]->ch_mistat &
+ UART_MSR_DSR) ? "DSR" : "",
+ (bd->channels[i]->ch_mistat &
+ UART_MSR_DCD) ? "DCD" : "",
+ (bd->channels[i]->ch_mistat &
+ UART_MSR_RI) ? "RI" : "");
+ else
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d\n", bd->channels[i]->ch_portnum);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_msignals, S_IRUSR, dgap_ports_msignals_show, NULL);
+
+static ssize_t dgap_ports_iflag_show(struct device *p,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ bd = dgap_verify_board(p);
+ if (!bd)
+ return 0;
+
+ for (i = 0; i < bd->nasync; i++)
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum,
+ bd->channels[i]->ch_c_iflag);
+ return count;
+}
+static DEVICE_ATTR(ports_iflag, S_IRUSR, dgap_ports_iflag_show, NULL);
+
+static ssize_t dgap_ports_cflag_show(struct device *p,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ bd = dgap_verify_board(p);
+ if (!bd)
+ return 0;
+
+ for (i = 0; i < bd->nasync; i++)
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum,
+ bd->channels[i]->ch_c_cflag);
+ return count;
+}
+static DEVICE_ATTR(ports_cflag, S_IRUSR, dgap_ports_cflag_show, NULL);
+
+static ssize_t dgap_ports_oflag_show(struct device *p,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ bd = dgap_verify_board(p);
+ if (!bd)
+ return 0;
+
+ for (i = 0; i < bd->nasync; i++)
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum,
+ bd->channels[i]->ch_c_oflag);
+ return count;
+}
+static DEVICE_ATTR(ports_oflag, S_IRUSR, dgap_ports_oflag_show, NULL);
+
+static ssize_t dgap_ports_lflag_show(struct device *p,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ bd = dgap_verify_board(p);
+ if (!bd)
+ return 0;
+
+ for (i = 0; i < bd->nasync; i++)
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum,
+ bd->channels[i]->ch_c_lflag);
+ return count;
+}
+static DEVICE_ATTR(ports_lflag, S_IRUSR, dgap_ports_lflag_show, NULL);
+
+static ssize_t dgap_ports_digi_flag_show(struct device *p,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ bd = dgap_verify_board(p);
+ if (!bd)
+ return 0;
+
+ for (i = 0; i < bd->nasync; i++)
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum,
+ bd->channels[i]->ch_digi.digi_flags);
+ return count;
+}
+static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgap_ports_digi_flag_show, NULL);
+
+static ssize_t dgap_ports_rxcount_show(struct device *p,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ bd = dgap_verify_board(p);
+ if (!bd)
+ return 0;
+
+ for (i = 0; i < bd->nasync; i++)
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
+ bd->channels[i]->ch_portnum,
+ bd->channels[i]->ch_rxcount);
+ return count;
+}
+static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgap_ports_rxcount_show, NULL);
+
+static ssize_t dgap_ports_txcount_show(struct device *p,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ bd = dgap_verify_board(p);
+ if (!bd)
+ return 0;
+
+ for (i = 0; i < bd->nasync; i++)
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
+ bd->channels[i]->ch_portnum,
+ bd->channels[i]->ch_txcount);
+ return count;
+}
+static DEVICE_ATTR(ports_txcount, S_IRUSR, dgap_ports_txcount_show, NULL);
+
+/* this function creates the sys files that will export each signal status
+ * to sysfs each value will be put in a separate filename
+ */
+static void dgap_create_ports_sysfiles(struct board_t *bd)
+{
+ dev_set_drvdata(&bd->pdev->dev, bd);
+ device_create_file(&(bd->pdev->dev), &dev_attr_ports_state);
+ device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud);
+ device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
+ device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
+ device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
+ device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
+ device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
+ device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
+ device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
+ device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
+}
+
+/* removes all the sys files created for that port */
+static void dgap_remove_ports_sysfiles(struct board_t *bd)
+{
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
+}
+
+static ssize_t dgap_tty_state_show(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return 0;
+ un = dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return 0;
+ if (bd->state != BOARD_READY)
+ return 0;
+
+ return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ?
+ "Open" : "Closed");
+}
+static DEVICE_ATTR(state, S_IRUSR, dgap_tty_state_show, NULL);
+
+static ssize_t dgap_tty_baud_show(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return 0;
+ un = dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return 0;
+ if (bd->state != BOARD_READY)
+ return 0;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_baud_info);
+}
+static DEVICE_ATTR(baud, S_IRUSR, dgap_tty_baud_show, NULL);
+
+static ssize_t dgap_tty_msignals_show(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return 0;
+ un = dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return 0;
+ if (bd->state != BOARD_READY)
+ return 0;
+
+ if (ch->ch_open_count) {
+ return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n",
+ (ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
+ (ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
+ (ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
+ (ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
+ (ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
+ (ch->ch_mistat & UART_MSR_RI) ? "RI" : "");
+ }
+ return 0;
+}
+static DEVICE_ATTR(msignals, S_IRUSR, dgap_tty_msignals_show, NULL);
+
+static ssize_t dgap_tty_iflag_show(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return 0;
+ un = dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return 0;
+ if (bd->state != BOARD_READY)
+ return 0;
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag);
+}
+static DEVICE_ATTR(iflag, S_IRUSR, dgap_tty_iflag_show, NULL);
+
+static ssize_t dgap_tty_cflag_show(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return 0;
+ un = dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return 0;
+ if (bd->state != BOARD_READY)
+ return 0;
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag);
+}
+static DEVICE_ATTR(cflag, S_IRUSR, dgap_tty_cflag_show, NULL);
+
+static ssize_t dgap_tty_oflag_show(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return 0;
+ un = dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return 0;
+ if (bd->state != BOARD_READY)
+ return 0;
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag);
+}
+static DEVICE_ATTR(oflag, S_IRUSR, dgap_tty_oflag_show, NULL);
+
+static ssize_t dgap_tty_lflag_show(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return 0;
+ un = dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return 0;
+ if (bd->state != BOARD_READY)
+ return 0;
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag);
+}
+static DEVICE_ATTR(lflag, S_IRUSR, dgap_tty_lflag_show, NULL);
+
+static ssize_t dgap_tty_digi_flag_show(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return 0;
+ un = dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return 0;
+ if (bd->state != BOARD_READY)
+ return 0;
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags);
+}
+static DEVICE_ATTR(digi_flag, S_IRUSR, dgap_tty_digi_flag_show, NULL);
+
+static ssize_t dgap_tty_rxcount_show(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return 0;
+ un = dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return 0;
+ if (bd->state != BOARD_READY)
+ return 0;
+
+ return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount);
+}
+static DEVICE_ATTR(rxcount, S_IRUSR, dgap_tty_rxcount_show, NULL);
+
+static ssize_t dgap_tty_txcount_show(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return 0;
+ un = dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return 0;
+ if (bd->state != BOARD_READY)
+ return 0;
+
+ return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount);
+}
+static DEVICE_ATTR(txcount, S_IRUSR, dgap_tty_txcount_show, NULL);
+
+static ssize_t dgap_tty_name_show(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int cn;
+ int bn;
+ struct cnode *cptr = NULL;
+ int found = FALSE;
+ int ncount = 0;
+ int starto = 0;
+ int i = 0;
+
+ if (!d)
+ return 0;
+ un = dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return 0;
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return 0;
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return 0;
+ if (bd->state != BOARD_READY)
+ return 0;
+
+ bn = bd->boardnum;
+ cn = ch->ch_portnum;
+
+ for (cptr = bd->bd_config; cptr; cptr = cptr->next) {
+
+ if ((cptr->type == BNODE) &&
+ ((cptr->u.board.type == APORT2_920P) ||
+ (cptr->u.board.type == APORT4_920P) ||
+ (cptr->u.board.type == APORT8_920P) ||
+ (cptr->u.board.type == PAPORT4) ||
+ (cptr->u.board.type == PAPORT8))) {
+
+ found = TRUE;
+ if (cptr->u.board.v_start)
+ starto = cptr->u.board.start;
+ else
+ starto = 1;
+ }
+
+ if (cptr->type == TNODE && found == TRUE) {
+ char *ptr1;
+ if (strstr(cptr->u.ttyname, "tty")) {
+ ptr1 = cptr->u.ttyname;
+ ptr1 += 3;
+ } else
+ ptr1 = cptr->u.ttyname;
+
+ for (i = 0; i < dgap_config_get_num_prts(bd); i++) {
+ if (cn != i)
+ continue;
+
+ return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
+ (un->un_type == DGAP_PRINT) ?
+ "pr" : "tty",
+ ptr1, i + starto);
+ }
+ }
+
+ if (cptr->type == CNODE) {
+
+ for (i = 0; i < cptr->u.conc.nport; i++) {
+ if (cn != (i + ncount))
+ continue;
+
+ return snprintf(buf, PAGE_SIZE, "%s%s%02ld\n",
+ (un->un_type == DGAP_PRINT) ?
+ "pr" : "tty",
+ cptr->u.conc.id,
+ i + (cptr->u.conc.v_start ?
+ cptr->u.conc.start : 1));
+ }
+
+ ncount += cptr->u.conc.nport;
+ }
+
+ if (cptr->type == MNODE) {
+
+ for (i = 0; i < cptr->u.module.nport; i++) {
+ if (cn != (i + ncount))
+ continue;
+
+ return snprintf(buf, PAGE_SIZE, "%s%s%02ld\n",
+ (un->un_type == DGAP_PRINT) ?
+ "pr" : "tty",
+ cptr->u.module.id,
+ i + (cptr->u.module.v_start ?
+ cptr->u.module.start : 1));
+ }
+
+ ncount += cptr->u.module.nport;
+
+ }
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%s_dgap_%d_%d\n",
+ (un->un_type == DGAP_PRINT) ? "pr" : "tty", bn, cn);
+
+}
+static DEVICE_ATTR(custom_name, S_IRUSR, dgap_tty_name_show, NULL);
+
+static struct attribute *dgap_sysfs_tty_entries[] = {
+ &dev_attr_state.attr,
+ &dev_attr_baud.attr,
+ &dev_attr_msignals.attr,
+ &dev_attr_iflag.attr,
+ &dev_attr_cflag.attr,
+ &dev_attr_oflag.attr,
+ &dev_attr_lflag.attr,
+ &dev_attr_digi_flag.attr,
+ &dev_attr_rxcount.attr,
+ &dev_attr_txcount.attr,
+ &dev_attr_custom_name.attr,
+ NULL
+};
+
+static struct attribute_group dgap_tty_attribute_group = {
+ .name = NULL,
+ .attrs = dgap_sysfs_tty_entries,
+};
+
+static void dgap_create_tty_sysfs(struct un_t *un, struct device *c)
+{
+ int ret;
+
+ ret = sysfs_create_group(&c->kobj, &dgap_tty_attribute_group);
+ if (ret)
+ return;
+
+ dev_set_drvdata(c, un);
+
+}
+
+static void dgap_remove_tty_sysfs(struct device *c)
+{
+ sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group);
+}
+
+/*
+ * Parse a configuration file read into memory as a string.
+ */
+static int dgap_parsefile(char **in, int Remove)
+{
+ struct cnode *p, *brd, *line, *conc;
+ int rc;
+ char *s = NULL;
+ int linecnt = 0;
+
+ p = &dgap_head;
+ brd = line = conc = NULL;
+
+ /* perhaps we are adding to an existing list? */
+ while (p->next != NULL)
+ p = p->next;
+
+ /* file must start with a BEGIN */
+ while ((rc = dgap_gettok(in, p)) != BEGIN) {
+ if (rc == 0) {
+ dgap_err("unexpected EOF");
+ return -1;
+ }
+ }
+
+ for (; ;) {
+ rc = dgap_gettok(in, p);
+ if (rc == 0) {
+ dgap_err("unexpected EOF");
+ return -1;
+ }
+
+ switch (rc) {
+ case 0:
+ dgap_err("unexpected end of file");
+ return -1;
+
+ case BEGIN: /* should only be 1 begin */
+ dgap_err("unexpected config_begin\n");
+ return -1;
+
+ case END:
+ return 0;
+
+ case BOARD: /* board info */
+ if (dgap_checknode(p))
+ return -1;
+ p->next = dgap_newnode(BNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+
+ p->u.board.status = dgap_savestring("No");
+ line = conc = NULL;
+ brd = p;
+ linecnt = -1;
+ break;
+
+ case APORT2_920P: /* AccelePort_4 */
+ if (p->type != BNODE) {
+ dgap_err("unexpected Digi_2r_920 string");
+ return -1;
+ }
+ p->u.board.type = APORT2_920P;
+ p->u.board.v_type = 1;
+ break;
+
+ case APORT4_920P: /* AccelePort_4 */
+ if (p->type != BNODE) {
+ dgap_err("unexpected Digi_4r_920 string");
+ return -1;
+ }
+ p->u.board.type = APORT4_920P;
+ p->u.board.v_type = 1;
+ break;
+
+ case APORT8_920P: /* AccelePort_8 */
+ if (p->type != BNODE) {
+ dgap_err("unexpected Digi_8r_920 string");
+ return -1;
+ }
+ p->u.board.type = APORT8_920P;
+ p->u.board.v_type = 1;
+ break;
+
+ case PAPORT4: /* AccelePort_4 PCI */
+ if (p->type != BNODE) {
+ dgap_err("unexpected Digi_4r(PCI) string");
+ return -1;
+ }
+ p->u.board.type = PAPORT4;
+ p->u.board.v_type = 1;
+ break;
+
+ case PAPORT8: /* AccelePort_8 PCI */
+ if (p->type != BNODE) {
+ dgap_err("unexpected Digi_8r string");
+ return -1;
+ }
+ p->u.board.type = PAPORT8;
+ p->u.board.v_type = 1;
+ break;
+
+ case PCX: /* PCI C/X */
+ if (p->type != BNODE) {
+ dgap_err("unexpected Digi_C/X_(PCI) string");
+ return -1;
+ }
+ p->u.board.type = PCX;
+ p->u.board.v_type = 1;
+ p->u.board.conc1 = 0;
+ p->u.board.conc2 = 0;
+ p->u.board.module1 = 0;
+ p->u.board.module2 = 0;
+ break;
+
+ case PEPC: /* PCI EPC/X */
+ if (p->type != BNODE) {
+ dgap_err("unexpected \"Digi_EPC/X_(PCI)\" string");
+ return -1;
+ }
+ p->u.board.type = PEPC;
+ p->u.board.v_type = 1;
+ p->u.board.conc1 = 0;
+ p->u.board.conc2 = 0;
+ p->u.board.module1 = 0;
+ p->u.board.module2 = 0;
+ break;
+
+ case PPCM: /* PCI/Xem */
+ if (p->type != BNODE) {
+ dgap_err("unexpected PCI/Xem string");
+ return -1;
+ }
+ p->u.board.type = PPCM;
+ p->u.board.v_type = 1;
+ p->u.board.conc1 = 0;
+ p->u.board.conc2 = 0;
+ break;
+
+ case IO: /* i/o port */
+ if (p->type != BNODE) {
+ dgap_err("IO port only vaild for boards");
+ return -1;
+ }
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ p->u.board.portstr = dgap_savestring(s);
+ if (kstrtol(s, 0, &p->u.board.port)) {
+ dgap_err("bad number for IO port");
+ return -1;
+ }
+ p->u.board.v_port = 1;
+ break;
+
+ case MEM: /* memory address */
+ if (p->type != BNODE) {
+ dgap_err("memory address only vaild for boards");
+ return -1;
+ }
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ p->u.board.addrstr = dgap_savestring(s);
+ if (kstrtoul(s, 0, &p->u.board.addr)) {
+ dgap_err("bad number for memory address");
+ return -1;
+ }
+ p->u.board.v_addr = 1;
+ break;
+
+ case PCIINFO: /* pci information */
+ if (p->type != BNODE) {
+ dgap_err("memory address only vaild for boards");
+ return -1;
+ }
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ p->u.board.pcibusstr = dgap_savestring(s);
+ if (kstrtoul(s, 0, &p->u.board.pcibus)) {
+ dgap_err("bad number for pci bus");
+ return -1;
+ }
+ p->u.board.v_pcibus = 1;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ p->u.board.pcislotstr = dgap_savestring(s);
+ if (kstrtoul(s, 0, &p->u.board.pcislot)) {
+ dgap_err("bad number for pci slot");
+ return -1;
+ }
+ p->u.board.v_pcislot = 1;
+ break;
+
+ case METHOD:
+ if (p->type != BNODE) {
+ dgap_err("install method only vaild for boards");
+ return -1;
+ }
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ p->u.board.method = dgap_savestring(s);
+ p->u.board.v_method = 1;
+ break;
+
+ case STATUS:
+ if (p->type != BNODE) {
+ dgap_err("config status only vaild for boards");
+ return -1;
+ }
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ p->u.board.status = dgap_savestring(s);
+ break;
+
+ case NPORTS: /* number of ports */
+ if (p->type == BNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.board.nport)) {
+ dgap_err("bad number for number of ports");
+ return -1;
+ }
+ p->u.board.v_nport = 1;
+ } else if (p->type == CNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.conc.nport)) {
+ dgap_err("bad number for number of ports");
+ return -1;
+ }
+ p->u.conc.v_nport = 1;
+ } else if (p->type == MNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.module.nport)) {
+ dgap_err("bad number for number of ports");
+ return -1;
+ }
+ p->u.module.v_nport = 1;
+ } else {
+ dgap_err("nports only valid for concentrators or modules");
+ return -1;
+ }
+ break;
+
+ case ID: /* letter ID used in tty name */
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+
+ p->u.board.status = dgap_savestring(s);
+
+ if (p->type == CNODE) {
+ p->u.conc.id = dgap_savestring(s);
+ p->u.conc.v_id = 1;
+ } else if (p->type == MNODE) {
+ p->u.module.id = dgap_savestring(s);
+ p->u.module.v_id = 1;
+ } else {
+ dgap_err("id only valid for concentrators or modules");
+ return -1;
+ }
+ break;
+
+ case STARTO: /* start offset of ID */
+ if (p->type == BNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.board.start)) {
+ dgap_err("bad number for start of tty count");
+ return -1;
+ }
+ p->u.board.v_start = 1;
+ } else if (p->type == CNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.conc.start)) {
+ dgap_err("bad number for start of tty count");
+ return -1;
+ }
+ p->u.conc.v_start = 1;
+ } else if (p->type == MNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.module.start)) {
+ dgap_err("bad number for start of tty count");
+ return -1;
+ }
+ p->u.module.v_start = 1;
+ } else {
+ dgap_err("start only valid for concentrators or modules");
+ return -1;
+ }
+ break;
+
+ case TTYN: /* tty name prefix */
+ if (dgap_checknode(p))
+ return -1;
+ p->next = dgap_newnode(TNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (!s) {
+ dgap_err("unexpeced end of file");
+ return -1;
+ }
+ p->u.ttyname = dgap_savestring(s);
+ if (!p->u.ttyname) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ break;
+
+ case CU: /* cu name prefix */
+ if (dgap_checknode(p))
+ return -1;
+ p->next = dgap_newnode(CUNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (!s) {
+ dgap_err("unexpeced end of file");
+ return -1;
+ }
+ p->u.cuname = dgap_savestring(s);
+ if (!p->u.cuname) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ break;
+
+ case LINE: /* line information */
+ if (dgap_checknode(p))
+ return -1;
+ if (brd == NULL) {
+ dgap_err("must specify board before line info");
+ return -1;
+ }
+ switch (brd->u.board.type) {
+ case PPCM:
+ dgap_err("line not vaild for PC/em");
+ return -1;
+ }
+ p->next = dgap_newnode(LNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ conc = NULL;
+ line = p;
+ linecnt++;
+ break;
+
+ case CONC: /* concentrator information */
+ if (dgap_checknode(p))
+ return -1;
+ if (line == NULL) {
+ dgap_err("must specify line info before concentrator");
+ return -1;
+ }
+ p->next = dgap_newnode(CNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ conc = p;
+ if (linecnt)
+ brd->u.board.conc2++;
+ else
+ brd->u.board.conc1++;
+
+ break;
+
+ case CX: /* c/x type concentrator */
+ if (p->type != CNODE) {
+ dgap_err("cx only valid for concentrators");
+ return -1;
+ }
+ p->u.conc.type = CX;
+ p->u.conc.v_type = 1;
+ break;
+
+ case EPC: /* epc type concentrator */
+ if (p->type != CNODE) {
+ dgap_err("cx only valid for concentrators");
+ return -1;
+ }
+ p->u.conc.type = EPC;
+ p->u.conc.v_type = 1;
+ break;
+
+ case MOD: /* EBI module */
+ if (dgap_checknode(p))
+ return -1;
+ if (brd == NULL) {
+ dgap_err("must specify board info before EBI modules");
+ return -1;
+ }
+ switch (brd->u.board.type) {
+ case PPCM:
+ linecnt = 0;
+ break;
+ default:
+ if (conc == NULL) {
+ dgap_err("must specify concentrator info before EBI module");
+ return -1;
+ }
+ }
+ p->next = dgap_newnode(MNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ if (linecnt)
+ brd->u.board.module2++;
+ else
+ brd->u.board.module1++;
+
+ break;
+
+ case PORTS: /* ports type EBI module */
+ if (p->type != MNODE) {
+ dgap_err("ports only valid for EBI modules");
+ return -1;
+ }
+ p->u.module.type = PORTS;
+ p->u.module.v_type = 1;
+ break;
+
+ case MODEM: /* ports type EBI module */
+ if (p->type != MNODE) {
+ dgap_err("modem only valid for modem modules");
+ return -1;
+ }
+ p->u.module.type = MODEM;
+ p->u.module.v_type = 1;
+ break;
+
+ case CABLE:
+ if (p->type == LNODE) {
+ s = dgap_getword(in);
+ if (!s) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ p->u.line.cable = dgap_savestring(s);
+ p->u.line.v_cable = 1;
+ }
+ break;
+
+ case SPEED: /* sync line speed indication */
+ if (p->type == LNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.line.speed)) {
+ dgap_err("bad number for line speed");
+ return -1;
+ }
+ p->u.line.v_speed = 1;
+ } else if (p->type == CNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.conc.speed)) {
+ dgap_err("bad number for line speed");
+ return -1;
+ }
+ p->u.conc.v_speed = 1;
+ } else {
+ dgap_err("speed valid only for lines or concentrators.");
+ return -1;
+ }
+ break;
+
+ case CONNECT:
+ if (p->type == CNODE) {
+ s = dgap_getword(in);
+ if (!s) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ p->u.conc.connect = dgap_savestring(s);
+ p->u.conc.v_connect = 1;
+ }
+ break;
+ case PRINT: /* transparent print name prefix */
+ if (dgap_checknode(p))
+ return -1;
+ p->next = dgap_newnode(PNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (!s) {
+ dgap_err("unexpeced end of file");
+ return -1;
+ }
+ p->u.printname = dgap_savestring(s);
+ if (!p->u.printname) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ break;
+
+ case CMAJOR: /* major number */
+ if (dgap_checknode(p))
+ return -1;
+ p->next = dgap_newnode(JNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.majornumber)) {
+ dgap_err("bad number for major number");
+ return -1;
+ }
+ break;
+
+ case ALTPIN: /* altpin setting */
+ if (dgap_checknode(p))
+ return -1;
+ p->next = dgap_newnode(ANODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.altpin)) {
+ dgap_err("bad number for altpin");
+ return -1;
+ }
+ break;
+
+ case USEINTR: /* enable interrupt setting */
+ if (dgap_checknode(p))
+ return -1;
+ p->next = dgap_newnode(INTRNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.useintr)) {
+ dgap_err("bad number for useintr");
+ return -1;
+ }
+ break;
+
+ case TTSIZ: /* size of tty structure */
+ if (dgap_checknode(p))
+ return -1;
+ p->next = dgap_newnode(TSNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.ttysize)) {
+ dgap_err("bad number for ttysize");
+ return -1;
+ }
+ break;
+
+ case CHSIZ: /* channel structure size */
+ if (dgap_checknode(p))
+ return -1;
+ p->next = dgap_newnode(CSNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.chsize)) {
+ dgap_err("bad number for chsize");
+ return -1;
+ }
+ break;
+
+ case BSSIZ: /* board structure size */
+ if (dgap_checknode(p))
+ return -1;
+ p->next = dgap_newnode(BSNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.bssize)) {
+ dgap_err("bad number for bssize");
+ return -1;
+ }
+ break;
+
+ case UNTSIZ: /* sched structure size */
+ if (dgap_checknode(p))
+ return -1;
+ p->next = dgap_newnode(USNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.unsize)) {
+ dgap_err("bad number for schedsize");
+ return -1;
+ }
+ break;
+
+ case F2SIZ: /* f2200 structure size */
+ if (dgap_checknode(p))
+ return -1;
+ p->next = dgap_newnode(FSNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.f2size)) {
+ dgap_err("bad number for f2200size");
+ return -1;
+ }
+ break;
+
+ case VPSIZ: /* vpix structure size */
+ if (dgap_checknode(p))
+ return -1;
+ p->next = dgap_newnode(VSNODE);
+ if (!p->next) {
+ dgap_err("out of memory");
+ return -1;
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return -1;
+ }
+ if (kstrtol(s, 0, &p->u.vpixsize)) {
+ dgap_err("bad number for vpixsize");
+ return -1;
+ }
+ break;
+ }
+ }
+}
+
+/*
+ * dgap_sindex: much like index(), but it looks for a match of any character in
+ * the group, and returns that position. If the first character is a ^, then
+ * this will match the first occurrence not in that group.
+ */
+static char *dgap_sindex(char *string, char *group)
+{
+ char *ptr;
+
+ if (!string || !group)
+ return (char *) NULL;
+
+ if (*group == '^') {
+ group++;
+ for (; *string; string++) {
+ for (ptr = group; *ptr; ptr++) {
+ if (*ptr == *string)
+ break;
+ }
+ if (*ptr == '\0')
+ return string;
+ }
+ } else {
+ for (; *string; string++) {
+ for (ptr = group; *ptr; ptr++) {
+ if (*ptr == *string)
+ return string;
+ }
+ }
+ }
+
+ return (char *) NULL;
+}
+
+/*
+ * Get a token from the input file; return 0 if end of file is reached
+ */
+static int dgap_gettok(char **in, struct cnode *p)
+{
+ char *w;
+ struct toklist *t;
+
+ if (strstr(dgap_cword, "boar")) {
+ w = dgap_getword(in);
+ snprintf(dgap_cword, MAXCWORD, "%s", w);
+ for (t = dgap_tlist; t->token != 0; t++) {
+ if (!strcmp(w, t->string))
+ return t->token;
+ }
+ dgap_err("board !!type not specified");
+ return 1;
+ } else {
+ while ((w = dgap_getword(in))) {
+ snprintf(dgap_cword, MAXCWORD, "%s", w);
+ for (t = dgap_tlist; t->token != 0; t++) {
+ if (!strcmp(w, t->string))
+ return t->token;
+ }
+ }
+ return 0;
+ }
+}
+
+/*
+ * get a word from the input stream, also keep track of current line number.
+ * words are separated by whitespace.
+ */
+static char *dgap_getword(char **in)
+{
+ char *ret_ptr = *in;
+
+ char *ptr = dgap_sindex(*in, " \t\n");
+
+ /* If no word found, return null */
+ if (!ptr)
+ return NULL;
+
+ /* Mark new location for our buffer */
+ *ptr = '\0';
+ *in = ptr + 1;
+
+ /* Eat any extra spaces/tabs/newlines that might be present */
+ while (*in && **in && ((**in == ' ') ||
+ (**in == '\t') ||
+ (**in == '\n'))) {
+ **in = '\0';
+ *in = *in + 1;
+ }
+
+ return ret_ptr;
+}
+
+/*
+ * print an error message, giving the line number in the file where
+ * the error occurred.
+ */
+static void dgap_err(char *s)
+{
+ pr_err("dgap: parse: %s\n", s);
+}
+
+/*
+ * allocate a new configuration node of type t
+ */
+static struct cnode *dgap_newnode(int t)
+{
+ struct cnode *n;
+
+ n = kmalloc(sizeof(struct cnode), GFP_ATOMIC);
+ if (n != NULL) {
+ memset((char *)n, 0, sizeof(struct cnode));
+ n->type = t;
+ }
+ return n;
+}
+
+/*
+ * dgap_checknode: see if all the necessary info has been supplied for a node
+ * before creating the next node.
+ */
+static int dgap_checknode(struct cnode *p)
+{
+ switch (p->type) {
+ case BNODE:
+ if (p->u.board.v_type == 0) {
+ dgap_err("board type !not specified");
+ return 1;
+ }
+
+ return 0;
+
+ case LNODE:
+ if (p->u.line.v_speed == 0) {
+ dgap_err("line speed not specified");
+ return 1;
+ }
+ return 0;
+
+ case CNODE:
+ if (p->u.conc.v_type == 0) {
+ dgap_err("concentrator type not specified");
+ return 1;
+ }
+ if (p->u.conc.v_speed == 0) {
+ dgap_err("concentrator line speed not specified");
+ return 1;
+ }
+ if (p->u.conc.v_nport == 0) {
+ dgap_err("number of ports on concentrator not specified");
+ return 1;
+ }
+ if (p->u.conc.v_id == 0) {
+ dgap_err("concentrator id letter not specified");
+ return 1;
+ }
+ return 0;
+
+ case MNODE:
+ if (p->u.module.v_type == 0) {
+ dgap_err("EBI module type not specified");
+ return 1;
+ }
+ if (p->u.module.v_nport == 0) {
+ dgap_err("number of ports on EBI module not specified");
+ return 1;
+ }
+ if (p->u.module.v_id == 0) {
+ dgap_err("EBI module id letter not specified");
+ return 1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * save a string somewhere
+ */
+static char *dgap_savestring(char *s)
+{
+ char *p;
+
+ p = kmalloc(strlen(s) + 1, GFP_ATOMIC);
+ if (p)
+ strcpy(p, s);
+ return p;
+}
+
+/*
+ * Given a board pointer, returns whether we should use interrupts or not.
+ */
+static uint dgap_config_get_useintr(struct board_t *bd)
+{
+ struct cnode *p = NULL;
+
+ if (!bd)
+ return 0;
+
+ for (p = bd->bd_config; p; p = p->next) {
+ switch (p->type) {
+ case INTRNODE:
+ /*
+ * check for pcxr types.
+ */
+ return p->u.useintr;
+ default:
+ break;
+ }
+ }
+
+ /* If not found, then don't turn on interrupts. */
+ return 0;
+}
+
+/*
+ * Given a board pointer, returns whether we turn on altpin or not.
+ */
+static uint dgap_config_get_altpin(struct board_t *bd)
+{
+ struct cnode *p = NULL;
+
+ if (!bd)
+ return 0;
+
+ for (p = bd->bd_config; p; p = p->next) {
+ switch (p->type) {
+ case ANODE:
+ /*
+ * check for pcxr types.
+ */
+ return p->u.altpin;
+ default:
+ break;
+ }
+ }
+
+ /* If not found, then don't turn on interrupts. */
+ return 0;
+}
+
+/*
+ * Given a specific type of board, if found, detached link and
+ * returns the first occurrence in the list.
+ */
+static struct cnode *dgap_find_config(int type, int bus, int slot)
+{
+ struct cnode *p, *prev = NULL, *prev2 = NULL, *found = NULL;
+
+ p = &dgap_head;
+
+ while (p->next != NULL) {
+ prev = p;
+ p = p->next;
+
+ if (p->type == BNODE) {
+
+ if (p->u.board.type == type) {
+
+ if (p->u.board.v_pcibus &&
+ p->u.board.pcibus != bus)
+ continue;
+ if (p->u.board.v_pcislot &&
+ p->u.board.pcislot != slot)
+ continue;
+
+ found = p;
+ /*
+ * Keep walking thru the list till we
+ * find the next board.
+ */
+ while (p->next != NULL) {
+ prev2 = p;
+ p = p->next;
+ if (p->type == BNODE) {
+
+ /*
+ * Mark the end of our 1 board
+ * chain of configs.
+ */
+ prev2->next = NULL;
+
+ /*
+ * Link the "next" board to the
+ * previous board, effectively
+ * "unlinking" our board from
+ * the main config.
+ */
+ prev->next = p;
+
+ return found;
+ }
+ }
+ /*
+ * It must be the last board in the list.
+ */
+ prev->next = NULL;
+ return found;
+ }
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Given a board pointer, walks the config link, counting up
+ * all ports user specified should be on the board.
+ * (This does NOT mean they are all actually present right now tho)
+ */
+static uint dgap_config_get_num_prts(struct board_t *bd)
+{
+ int count = 0;
+ struct cnode *p = NULL;
+
+ if (!bd)
+ return 0;
+
+ for (p = bd->bd_config; p; p = p->next) {
+
+ switch (p->type) {
+ case BNODE:
+ /*
+ * check for pcxr types.
+ */
+ if (p->u.board.type > EPCFE)
+ count += p->u.board.nport;
+ break;
+ case CNODE:
+ count += p->u.conc.nport;
+ break;
+ case MNODE:
+ count += p->u.module.nport;
+ break;
+ }
+ }
+ return count;
+}
+
+static char *dgap_create_config_string(struct board_t *bd, char *string)
+{
+ char *ptr = string;
+ struct cnode *p = NULL;
+ struct cnode *q = NULL;
+ int speed;
+
+ if (!bd) {
+ *ptr = 0xff;
+ return string;
+ }
+
+ for (p = bd->bd_config; p; p = p->next) {
+
+ switch (p->type) {
+ case LNODE:
+ *ptr = '\0';
+ ptr++;
+ *ptr = p->u.line.speed;
+ ptr++;
+ break;
+ case CNODE:
+ /*
+ * Because the EPC/con concentrators can have EM modules
+ * hanging off of them, we have to walk ahead in the
+ * list and keep adding the number of ports on each EM
+ * to the config. UGH!
+ */
+ speed = p->u.conc.speed;
+ q = p->next;
+ if ((q != NULL) && (q->type == MNODE)) {
+ *ptr = (p->u.conc.nport + 0x80);
+ ptr++;
+ p = q;
+ while ((q->next != NULL) &&
+ (q->next->type) == MNODE) {
+
+ *ptr = (q->u.module.nport + 0x80);
+ ptr++;
+ p = q;
+ q = q->next;
+ }
+ *ptr = q->u.module.nport;
+ ptr++;
+ } else {
+ *ptr = p->u.conc.nport;
+ ptr++;
+ }
+
+ *ptr = speed;
+ ptr++;
+ break;
+ }
+ }
+
+ *ptr = 0xff;
+ return string;
+}
diff --git a/drivers/staging/dgap/dgap.h b/drivers/staging/dgap/dgap.h
new file mode 100644
index 000000000000..6b8f5f858327
--- /dev/null
+++ b/drivers/staging/dgap/dgap.h
@@ -0,0 +1,1322 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ *************************************************************************
+ *
+ * Driver includes
+ *
+ *************************************************************************/
+
+#ifndef __DGAP_DRIVER_H
+#define __DGAP_DRIVER_H
+
+#include <linux/types.h> /* To pick up the varions Linux types */
+#include <linux/tty.h> /* To pick up the various tty structs/defines */
+#include <linux/interrupt.h> /* For irqreturn_t type */
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+/* Required for our shared headers! */
+typedef unsigned char uchar;
+
+#if !defined(TTY_FLIPBUF_SIZE)
+# define TTY_FLIPBUF_SIZE 512
+#endif
+
+/*************************************************************************
+ *
+ * Driver defines
+ *
+ *************************************************************************/
+
+/*
+ * Driver identification
+ */
+#define DG_NAME "dgap-1.3-16"
+#define DG_PART "40002347_C"
+#define DRVSTR "dgap"
+
+/*
+ * defines from dgap_pci.h
+ */
+#define PCIMAX 32 /* maximum number of PCI boards */
+
+#define DIGI_VID 0x114F
+
+#define PCI_DEV_EPC_DID 0x0002
+#define PCI_DEV_XEM_DID 0x0004
+#define PCI_DEV_XR_DID 0x0005
+#define PCI_DEV_CX_DID 0x0006
+#define PCI_DEV_XRJ_DID 0x0009 /* PLX-based Xr adapter */
+#define PCI_DEV_XR_IBM_DID 0x0011 /* IBM 8-port Async Adapter */
+#define PCI_DEV_XR_BULL_DID 0x0013 /* BULL 8-port Async Adapter */
+#define PCI_DEV_XR_SAIP_DID 0x001c /* SAIP card - Xr adapter */
+#define PCI_DEV_XR_422_DID 0x0012 /* Xr-422 */
+#define PCI_DEV_920_2_DID 0x0034 /* XR-Plus 920 K, 2 port */
+#define PCI_DEV_920_4_DID 0x0026 /* XR-Plus 920 K, 4 port */
+#define PCI_DEV_920_8_DID 0x0027 /* XR-Plus 920 K, 8 port */
+#define PCI_DEV_EPCJ_DID 0x000a /* PLX 9060 chip for PCI */
+#define PCI_DEV_CX_IBM_DID 0x001b /* IBM 128-port Async Adapter */
+#define PCI_DEV_920_8_HP_DID 0x0058 /* HP XR-Plus 920 K, 8 port */
+#define PCI_DEV_XEM_HP_DID 0x0059 /* HP Xem PCI */
+
+#define PCI_DEV_XEM_NAME "AccelePort XEM"
+#define PCI_DEV_CX_NAME "AccelePort CX"
+#define PCI_DEV_XR_NAME "AccelePort Xr"
+#define PCI_DEV_XRJ_NAME "AccelePort Xr (PLX)"
+#define PCI_DEV_XR_SAIP_NAME "AccelePort Xr (SAIP)"
+#define PCI_DEV_920_2_NAME "AccelePort Xr920 2 port"
+#define PCI_DEV_920_4_NAME "AccelePort Xr920 4 port"
+#define PCI_DEV_920_8_NAME "AccelePort Xr920 8 port"
+#define PCI_DEV_XR_422_NAME "AccelePort Xr 422"
+#define PCI_DEV_EPCJ_NAME "AccelePort EPC (PLX)"
+#define PCI_DEV_XR_BULL_NAME "AccelePort Xr (BULL)"
+#define PCI_DEV_XR_IBM_NAME "AccelePort Xr (IBM)"
+#define PCI_DEV_CX_IBM_NAME "AccelePort CX (IBM)"
+#define PCI_DEV_920_8_HP_NAME "AccelePort Xr920 8 port (HP)"
+#define PCI_DEV_XEM_HP_NAME "AccelePort XEM (HP)"
+
+/*
+ * On the PCI boards, there is no IO space allocated
+ * The I/O registers will be in the first 3 bytes of the
+ * upper 2MB of the 4MB memory space. The board memory
+ * will be mapped into the low 2MB of the 4MB memory space
+ */
+
+/* Potential location of PCI Bios from E0000 to FFFFF*/
+#define PCI_BIOS_SIZE 0x00020000
+
+/* Size of Memory and I/O for PCI (4MB) */
+#define PCI_RAM_SIZE 0x00400000
+
+/* Size of Memory (2MB) */
+#define PCI_MEM_SIZE 0x00200000
+
+/* Max PCI Window Size (2MB) */
+#define PCI_WIN_SIZE 0x00200000
+
+#define PCI_WIN_SHIFT 21 /* 21 bits max */
+
+/* Offset of I/0 in Memory (2MB) */
+#define PCI_IO_OFFSET 0x00200000
+
+/* Size of IO (2MB) */
+#define PCI_IO_SIZE 0x00200000
+
+/* Number of boards we support at once. */
+#define MAXBOARDS 32
+#define MAXPORTS 224
+#define MAXTTYNAMELEN 200
+
+/* Our 3 magic numbers for our board, channel and unit structs */
+#define DGAP_BOARD_MAGIC 0x5c6df104
+#define DGAP_CHANNEL_MAGIC 0x6c6df104
+#define DGAP_UNIT_MAGIC 0x7c6df104
+
+/* Serial port types */
+#define DGAP_SERIAL 0
+#define DGAP_PRINT 1
+
+#define SERIAL_TYPE_NORMAL 1
+
+/* 4 extra for alignment play space */
+#define WRITEBUFLEN ((4096) + 4)
+#define MYFLIPLEN N_TTY_BUF_SIZE
+
+#define SBREAK_TIME 0x25
+#define U2BSIZE 0x400
+
+#define dgap_jiffies_from_ms(a) (((a) * HZ) / 1000)
+
+/*
+ * Our major for the mgmt devices.
+ *
+ * We can use 22, because Digi was allocated 22 and 23 for the epca driver.
+ * 22 has now become obsolete now that the "cu" devices have
+ * been removed from 2.6.
+ * Also, this *IS* the epca driver, just PCI only now.
+ */
+#ifndef DIGI_DGAP_MAJOR
+# define DIGI_DGAP_MAJOR 22
+#endif
+
+/*
+ * The parameters we use to define the periods of the moving averages.
+ */
+#define MA_PERIOD (HZ / 10)
+#define SMA_DUR (1 * HZ)
+#define EMA_DUR (1 * HZ)
+#define SMA_NPERIODS (SMA_DUR / MA_PERIOD)
+#define EMA_NPERIODS (EMA_DUR / MA_PERIOD)
+
+/*
+ * Define a local default termios struct. All ports will be created
+ * with this termios initially. This is the same structure that is defined
+ * as the default in tty_io.c with the same settings overriden as in serial.c
+ *
+ * In short, this should match the internal serial ports' defaults.
+ */
+#define DEFAULT_IFLAGS (ICRNL | IXON)
+#define DEFAULT_OFLAGS (OPOST | ONLCR)
+#define DEFAULT_CFLAGS (B9600 | CS8 | CREAD | HUPCL | CLOCAL)
+#define DEFAULT_LFLAGS (ISIG | ICANON | ECHO | ECHOE | ECHOK | \
+ ECHOCTL | ECHOKE | IEXTEN)
+
+#ifndef _POSIX_VDISABLE
+#define _POSIX_VDISABLE '\0'
+#endif
+
+#define SNIFF_MAX 65536 /* Sniff buffer size (2^n) */
+#define SNIFF_MASK (SNIFF_MAX - 1) /* Sniff wrap mask */
+
+#define VPDSIZE (512)
+
+/************************************************************************
+ * FEP memory offsets
+ ************************************************************************/
+#define START 0x0004L /* Execution start address */
+
+#define CMDBUF 0x0d10L /* Command (cm_t) structure offset */
+#define CMDSTART 0x0400L /* Start of command buffer */
+#define CMDMAX 0x0800L /* End of command buffer */
+
+#define EVBUF 0x0d18L /* Event (ev_t) structure */
+#define EVSTART 0x0800L /* Start of event buffer */
+#define EVMAX 0x0c00L /* End of event buffer */
+#define FEP5_PLUS 0x0E40 /* ASCII '5' and ASCII 'A' is here */
+#define ECS_SEG 0x0E44 /* Segment of the extended channel structure */
+#define LINE_SPEED 0x10 /* Offset into ECS_SEG for line speed */
+ /* if the fep has extended capabilities */
+
+/* BIOS MAGIC SPOTS */
+#define ERROR 0x0C14L /* BIOS error code */
+#define SEQUENCE 0x0C12L /* BIOS sequence indicator */
+#define POSTAREA 0x0C00L /* POST complete message area */
+
+/* FEP MAGIC SPOTS */
+#define FEPSTAT POSTAREA /* OS here when FEP comes up */
+#define NCHAN 0x0C02L /* number of ports FEP sees */
+#define PANIC 0x0C10L /* PANIC area for FEP */
+#define KMEMEM 0x0C30L /* Memory for KME use */
+#define CONFIG 0x0CD0L /* Concentrator configuration info */
+#define CONFIGSIZE 0x0030 /* configuration info size */
+#define DOWNREQ 0x0D00 /* Download request buffer pointer */
+
+#define CHANBUF 0x1000L /* Async channel (bs_t) structs */
+#define FEPOSSIZE 0x1FFF /* 8K FEPOS */
+
+#define XEMPORTS 0xC02 /*
+ * Offset in board memory where FEP5 stores
+ * how many ports it has detected.
+ * NOTE: FEP5 reports 64 ports when the user
+ * has the cable in EBI OUT instead of EBI IN.
+ */
+
+#define FEPCLR 0x00
+#define FEPMEM 0x02
+#define FEPRST 0x04
+#define FEPINT 0x08
+#define FEPMASK 0x0e
+#define FEPWIN 0x80
+
+#define LOWMEM 0x0100
+#define HIGHMEM 0x7f00
+
+#define FEPTIMEOUT 200000
+
+#define ENABLE_INTR 0x0e04 /* Enable interrupts flag */
+#define FEPPOLL_MIN 1 /* minimum of 1 millisecond */
+#define FEPPOLL_MAX 20 /* maximum of 20 milliseconds */
+#define FEPPOLL 0x0c26 /* Fep event poll interval */
+
+#define IALTPIN 0x0080 /* Input flag to swap DSR <-> DCD */
+
+/************************************************************************
+ * FEP supported functions
+ ************************************************************************/
+#define SRLOW 0xe0 /* Set receive low water */
+#define SRHIGH 0xe1 /* Set receive high water */
+#define FLUSHTX 0xe2 /* Flush transmit buffer */
+#define PAUSETX 0xe3 /* Pause data transmission */
+#define RESUMETX 0xe4 /* Resume data transmission */
+#define SMINT 0xe5 /* Set Modem Interrupt */
+#define SAFLOWC 0xe6 /* Set Aux. flow control chars */
+#define SBREAK 0xe8 /* Send break */
+#define SMODEM 0xe9 /* Set 8530 modem control lines */
+#define SIFLAG 0xea /* Set UNIX iflags */
+#define SFLOWC 0xeb /* Set flow control characters */
+#define STLOW 0xec /* Set transmit low water mark */
+#define RPAUSE 0xee /* Pause receive */
+#define RRESUME 0xef /* Resume receive */
+#define CHRESET 0xf0 /* Reset Channel */
+#define BUFSETALL 0xf2 /* Set Tx & Rx buffer size avail*/
+#define SOFLAG 0xf3 /* Set UNIX oflags */
+#define SHFLOW 0xf4 /* Set hardware handshake */
+#define SCFLAG 0xf5 /* Set UNIX cflags */
+#define SVNEXT 0xf6 /* Set VNEXT character */
+#define SPINTFC 0xfc /* Reserved */
+#define SCOMMODE 0xfd /* Set RS232/422 mode */
+
+
+/************************************************************************
+ * Modes for SCOMMODE
+ ************************************************************************/
+#define MODE_232 0x00
+#define MODE_422 0x01
+
+
+/************************************************************************
+ * Event flags.
+ ************************************************************************/
+#define IFBREAK 0x01 /* Break received */
+#define IFTLW 0x02 /* Transmit low water */
+#define IFTEM 0x04 /* Transmitter empty */
+#define IFDATA 0x08 /* Receive data present */
+#define IFMODEM 0x20 /* Modem status change */
+
+/************************************************************************
+ * Modem flags
+ ************************************************************************/
+# define DM_RTS 0x02 /* Request to send */
+# define DM_CD 0x80 /* Carrier detect */
+# define DM_DSR 0x20 /* Data set ready */
+# define DM_CTS 0x10 /* Clear to send */
+# define DM_RI 0x40 /* Ring indicator */
+# define DM_DTR 0x01 /* Data terminal ready */
+
+/*
+ * defines from dgap_conf.h
+ */
+#define NULLNODE 0 /* header node, not used */
+#define BNODE 1 /* Board node */
+#define LNODE 2 /* Line node */
+#define CNODE 3 /* Concentrator node */
+#define MNODE 4 /* EBI Module node */
+#define TNODE 5 /* tty name prefix node */
+#define CUNODE 6 /* cu name prefix (non-SCO) */
+#define PNODE 7 /* trans. print prefix node */
+#define JNODE 8 /* maJor number node */
+#define ANODE 9 /* altpin */
+#define TSNODE 10 /* tty structure size */
+#define CSNODE 11 /* channel structure size */
+#define BSNODE 12 /* board structure size */
+#define USNODE 13 /* unit schedule structure size */
+#define FSNODE 14 /* f2200 structure size */
+#define VSNODE 15 /* size of VPIX structures */
+#define INTRNODE 16 /* enable interrupt */
+
+/* Enumeration of tokens */
+#define BEGIN 1
+#define END 2
+#define BOARD 10
+
+#define EPCFS 11 /* start of EPC family definitions */
+#define ICX 11
+#define MCX 13
+#define PCX 14
+#define IEPC 15
+#define EEPC 16
+#define MEPC 17
+#define IPCM 18
+#define EPCM 19
+#define MPCM 20
+#define PEPC 21
+#define PPCM 22
+#ifdef CP
+#define ICP 23
+#define ECP 24
+#define MCP 25
+#endif
+#define EPCFE 25 /* end of EPC family definitions */
+#define PC2E 26
+#define PC4E 27
+#define PC4E8K 28
+#define PC8E 29
+#define PC8E8K 30
+#define PC16E 31
+#define MC2E8K 34
+#define MC4E8K 35
+#define MC8E8K 36
+
+#define AVANFS 42 /* start of Avanstar family definitions */
+#define A8P 42
+#define A16P 43
+#define AVANFE 43 /* end of Avanstar family definitions */
+
+#define DA2000FS 44 /* start of AccelePort 2000 family definitions */
+#define DA22 44 /* AccelePort 2002 */
+#define DA24 45 /* AccelePort 2004 */
+#define DA28 46 /* AccelePort 2008 */
+#define DA216 47 /* AccelePort 2016 */
+#define DAR4 48 /* AccelePort RAS 4 port */
+#define DAR8 49 /* AccelePort RAS 8 port */
+#define DDR24 50 /* DataFire RAS 24 port */
+#define DDR30 51 /* DataFire RAS 30 port */
+#define DDR48 52 /* DataFire RAS 48 port */
+#define DDR60 53 /* DataFire RAS 60 port */
+#define DA2000FE 53 /* end of AccelePort 2000/RAS family definitions */
+
+#define PCXRFS 106 /* start of PCXR family definitions */
+#define APORT4 106
+#define APORT8 107
+#define PAPORT4 108
+#define PAPORT8 109
+#define APORT4_920I 110
+#define APORT8_920I 111
+#define APORT4_920P 112
+#define APORT8_920P 113
+#define APORT2_920P 114
+#define PCXRFE 117 /* end of PCXR family definitions */
+
+#define LINE 82
+#ifdef T1
+#define T1M 83
+#define E1M 84
+#endif
+#define CONC 64
+#define CX 65
+#define EPC 66
+#define MOD 67
+#define PORTS 68
+#define METHOD 69
+#define CUSTOM 70
+#define BASIC 71
+#define STATUS 72
+#define MODEM 73
+/* The following tokens can appear in multiple places */
+#define SPEED 74
+#define NPORTS 75
+#define ID 76
+#define CABLE 77
+#define CONNECT 78
+#define IO 79
+#define MEM 80
+#define DPSZ 81
+
+#define TTYN 90
+#define CU 91
+#define PRINT 92
+#define XPRINT 93
+#define CMAJOR 94
+#define ALTPIN 95
+#define STARTO 96
+#define USEINTR 97
+#define PCIINFO 98
+
+#define TTSIZ 100
+#define CHSIZ 101
+#define BSSIZ 102
+#define UNTSIZ 103
+#define F2SIZ 104
+#define VPSIZ 105
+
+#define TOTAL_BOARD 2
+#define CURRENT_BRD 4
+#define BOARD_TYPE 6
+#define IO_ADDRESS 8
+#define MEM_ADDRESS 10
+
+#define FIELDS_PER_PAGE 18
+
+#define TB_FIELD 1
+#define CB_FIELD 3
+#define BT_FIELD 5
+#define IO_FIELD 7
+#define ID_FIELD 8
+#define ME_FIELD 9
+#define TTY_FIELD 11
+#define CU_FIELD 13
+#define PR_FIELD 15
+#define MPR_FIELD 17
+
+#define MAX_FIELD 512
+
+#define INIT 0
+#define NITEMS 128
+#define MAX_ITEM 512
+
+#define DSCRINST 1
+#define DSCRNUM 3
+#define ALTPINQ 5
+#define SSAVE 7
+
+#define DSCR "32"
+#define ONETONINE "123456789"
+#define ALL "1234567890"
+
+/*
+ * All the possible states the driver can be while being loaded.
+ */
+enum {
+ DRIVER_INITIALIZED = 0,
+ DRIVER_READY
+};
+
+/*
+ * All the possible states the board can be while booting up.
+ */
+enum {
+ BOARD_FAILED = 0,
+ BOARD_READY
+};
+
+/*
+ * All the possible states that a requested concentrator image can be in.
+ */
+enum {
+ NO_PENDING_CONCENTRATOR_REQUESTS = 0,
+ NEED_CONCENTRATOR,
+ REQUESTED_CONCENTRATOR
+};
+
+
+
+/*
+ * Modem line constants are defined as macros because DSR and
+ * DCD are swapable using the ditty altpin option.
+ */
+#define D_CD(ch) ch->ch_cd /* Carrier detect */
+#define D_DSR(ch) ch->ch_dsr /* Data set ready */
+#define D_RTS(ch) DM_RTS /* Request to send */
+#define D_CTS(ch) DM_CTS /* Clear to send */
+#define D_RI(ch) DM_RI /* Ring indicator */
+#define D_DTR(ch) DM_DTR /* Data terminal ready */
+
+
+/*************************************************************************
+ *
+ * Structures and closely related defines.
+ *
+ *************************************************************************/
+
+
+/*
+ * A structure to hold a statistics counter. We also
+ * compute moving averages for this counter.
+ */
+struct macounter {
+ u32 cnt; /* Total count */
+ ulong accum; /* Acuumulator per period */
+ ulong sma; /* Simple moving average */
+ ulong ema; /* Exponential moving average */
+};
+
+
+/************************************************************************
+ * Device flag definitions for bd_flags.
+ ************************************************************************/
+#define BD_FEP5PLUS 0x0001 /* Supports FEP5 Plus commands */
+#define BD_HAS_VPD 0x0002 /* Board has VPD info available */
+
+/*
+ * Per-board information
+ */
+struct board_t {
+ int magic; /* Board Magic number. */
+ int boardnum; /* Board number: 0-3 */
+ int firstminor; /* First minor, e.g. 0, 30, 60 */
+
+ int type; /* Type of board */
+ char *name; /* Product Name */
+ struct pci_dev *pdev; /* Pointer to the pci_dev struct */
+ u16 vendor; /* PCI vendor ID */
+ u16 device; /* PCI device ID */
+ u16 subvendor; /* PCI subsystem vendor ID */
+ u16 subdevice; /* PCI subsystem device ID */
+ uchar rev; /* PCI revision ID */
+ uint pci_bus; /* PCI bus value */
+ uint pci_slot; /* PCI slot value */
+ u16 maxports; /* MAX ports this board can handle */
+ uchar vpd[VPDSIZE]; /* VPD of board, if found */
+ u32 bd_flags; /* Board flags */
+
+ spinlock_t bd_lock; /* Used to protect board */
+
+ u32 state; /* State of card. */
+ wait_queue_head_t state_wait; /* Place to sleep on for state change */
+
+ struct tasklet_struct helper_tasklet; /* Poll helper tasklet */
+
+ u32 wait_for_bios;
+ u32 wait_for_fep;
+
+ struct cnode *bd_config; /* Config of board */
+
+ u16 nasync; /* Number of ports on card */
+
+ u32 use_interrupts; /* Should we be interrupt driven? */
+ ulong irq; /* Interrupt request number */
+ ulong intr_count; /* Count of interrupts */
+ u32 intr_used; /* Non-zero if using interrupts */
+ u32 intr_running; /* Non-zero if FEP knows its doing interrupts */
+
+ ulong port; /* Start of base io port of the card */
+ ulong port_end; /* End of base io port of the card */
+ ulong membase; /* Start of base memory of the card */
+ ulong membase_end; /* End of base memory of the card */
+
+ uchar *re_map_port; /* Remapped io port of the card */
+ uchar *re_map_membase;/* Remapped memory of the card */
+
+ uchar runwait; /* # Processes waiting for FEP */
+ uchar inhibit_poller; /* Tells the poller to leave us alone */
+
+ struct channel_t *channels[MAXPORTS]; /* array of pointers to our channels. */
+
+ struct tty_driver *SerialDriver;
+ struct tty_port *SerialPorts;
+ char SerialName[200];
+ struct tty_driver *PrintDriver;
+ struct tty_port *PrinterPorts;
+ char PrintName[200];
+
+ u32 dgap_Major_Serial_Registered;
+ u32 dgap_Major_TransparentPrint_Registered;
+
+ u32 dgap_Serial_Major;
+ u32 dgap_TransparentPrint_Major;
+
+ struct bs_t *bd_bs; /* Base structure pointer */
+
+ char *flipbuf; /* Our flip buffer, alloced if board is found */
+ char *flipflagbuf; /* Our flip flag buffer, alloced if board is found */
+
+ u16 dpatype; /* The board "type", as defined by DPA */
+ u16 dpastatus; /* The board "status", as defined by DPA */
+ wait_queue_head_t kme_wait; /* Needed for DPA support */
+
+ u32 conc_dl_status; /* Status of any pending conc download */
+};
+
+
+
+/************************************************************************
+ * Unit flag definitions for un_flags.
+ ************************************************************************/
+#define UN_ISOPEN 0x0001 /* Device is open */
+#define UN_CLOSING 0x0002 /* Line is being closed */
+#define UN_IMM 0x0004 /* Service immediately */
+#define UN_BUSY 0x0008 /* Some work this channel */
+#define UN_BREAKI 0x0010 /* Input break received */
+#define UN_PWAIT 0x0020 /* Printer waiting for terminal */
+#define UN_TIME 0x0040 /* Waiting on time */
+#define UN_EMPTY 0x0080 /* Waiting output queue empty */
+#define UN_LOW 0x0100 /* Waiting output low water mark*/
+#define UN_EXCL_OPEN 0x0200 /* Open for exclusive use */
+#define UN_WOPEN 0x0400 /* Device waiting for open */
+#define UN_WIOCTL 0x0800 /* Device waiting for open */
+#define UN_HANGUP 0x8000 /* Carrier lost */
+
+struct device;
+
+/************************************************************************
+ * Structure for terminal or printer unit.
+ ************************************************************************/
+struct un_t {
+ int magic; /* Unit Magic Number. */
+ struct channel_t *un_ch;
+ u32 un_time;
+ u32 un_type;
+ u32 un_open_count; /* Counter of opens to port */
+ struct tty_struct *un_tty;/* Pointer to unit tty structure */
+ u32 un_flags; /* Unit flags */
+ wait_queue_head_t un_flags_wait; /* Place to sleep to wait on unit */
+ u32 un_dev; /* Minor device number */
+ tcflag_t un_oflag; /* oflags being done on board */
+ tcflag_t un_lflag; /* lflags being done on board */
+ struct device *un_sysfs;
+};
+
+
+/************************************************************************
+ * Device flag definitions for ch_flags.
+ ************************************************************************/
+#define CH_PRON 0x0001 /* Printer on string */
+#define CH_OUT 0x0002 /* Dial-out device open */
+#define CH_STOP 0x0004 /* Output is stopped */
+#define CH_STOPI 0x0008 /* Input is stopped */
+#define CH_CD 0x0010 /* Carrier is present */
+#define CH_FCAR 0x0020 /* Carrier forced on */
+
+#define CH_RXBLOCK 0x0080 /* Enable rx blocked flag */
+#define CH_WLOW 0x0100 /* Term waiting low event */
+#define CH_WEMPTY 0x0200 /* Term waiting empty event */
+#define CH_RENABLE 0x0400 /* Buffer just emptied */
+#define CH_RACTIVE 0x0800 /* Process active in xxread() */
+#define CH_RWAIT 0x1000 /* Process waiting in xxread() */
+#define CH_BAUD0 0x2000 /* Used for checking B0 transitions */
+#define CH_HANGUP 0x8000 /* Hangup received */
+
+/*
+ * Definitions for ch_sniff_flags
+ */
+#define SNIFF_OPEN 0x1
+#define SNIFF_WAIT_DATA 0x2
+#define SNIFF_WAIT_SPACE 0x4
+
+
+/************************************************************************
+ *** Definitions for Digi ditty(1) command.
+ ************************************************************************/
+
+/************************************************************************
+ * This module provides application access to special Digi
+ * serial line enhancements which are not standard UNIX(tm) features.
+ ************************************************************************/
+
+#if !defined(TIOCMODG)
+
+#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */
+#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */
+
+#ifndef TIOCM_LE
+#define TIOCM_LE 0x01 /* line enable */
+#define TIOCM_DTR 0x02 /* data terminal ready */
+#define TIOCM_RTS 0x04 /* request to send */
+#define TIOCM_ST 0x08 /* secondary transmit */
+#define TIOCM_SR 0x10 /* secondary receive */
+#define TIOCM_CTS 0x20 /* clear to send */
+#define TIOCM_CAR 0x40 /* carrier detect */
+#define TIOCM_RNG 0x80 /* ring indicator */
+#define TIOCM_DSR 0x100 /* data set ready */
+#define TIOCM_RI TIOCM_RNG /* ring (alternate) */
+#define TIOCM_CD TIOCM_CAR /* carrier detect (alt) */
+#endif
+
+#endif
+
+#if !defined(TIOCMSET)
+#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */
+#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */
+#endif
+
+#if !defined(TIOCMBIC)
+#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */
+#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */
+#endif
+
+
+#if !defined(TIOCSDTR)
+#define TIOCSDTR (('e'<<8) | 0) /* set DTR */
+#define TIOCCDTR (('e'<<8) | 1) /* clear DTR */
+#endif
+
+/************************************************************************
+ * Ioctl command arguments for DIGI parameters.
+ ************************************************************************/
+#define DIGI_GETA (('e'<<8) | 94) /* Read params */
+
+#define DIGI_SETA (('e'<<8) | 95) /* Set params */
+#define DIGI_SETAW (('e'<<8) | 96) /* Drain & set params */
+#define DIGI_SETAF (('e'<<8) | 97) /* Drain, flush & set params */
+
+#define DIGI_KME (('e'<<8) | 98) /* Read/Write Host */
+ /* Adapter Memory */
+
+#define DIGI_GETFLOW (('e'<<8) | 99) /* Get startc/stopc flow */
+ /* control characters */
+#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */
+ /* control characters */
+#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */
+ /* flow control chars */
+#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */
+ /* flow control chars */
+
+#define DIGI_GEDELAY (('d'<<8) | 246) /* Get edelay */
+#define DIGI_SEDELAY (('d'<<8) | 247) /* Set edelay */
+
+struct digiflow_t {
+ unsigned char startc; /* flow cntl start char */
+ unsigned char stopc; /* flow cntl stop char */
+};
+
+
+#ifdef FLOW_2200
+#define F2200_GETA (('e'<<8) | 104) /* Get 2x36 flow cntl flags */
+#define F2200_SETAW (('e'<<8) | 105) /* Set 2x36 flow cntl flags */
+#define F2200_MASK 0x03 /* 2200 flow cntl bit mask */
+#define FCNTL_2200 0x01 /* 2x36 terminal flow cntl */
+#define PCNTL_2200 0x02 /* 2x36 printer flow cntl */
+#define F2200_XON 0xf8
+#define P2200_XON 0xf9
+#define F2200_XOFF 0xfa
+#define P2200_XOFF 0xfb
+
+#define FXOFF_MASK 0x03 /* 2200 flow status mask */
+#define RCVD_FXOFF 0x01 /* 2x36 Terminal XOFF rcvd */
+#define RCVD_PXOFF 0x02 /* 2x36 Printer XOFF rcvd */
+#endif
+
+/************************************************************************
+ * Values for digi_flags
+ ************************************************************************/
+#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */
+#define DIGI_FAST 0x0002 /* Fast baud rates */
+#define RTSPACE 0x0004 /* RTS input flow control */
+#define CTSPACE 0x0008 /* CTS output flow control */
+#define DSRPACE 0x0010 /* DSR output flow control */
+#define DCDPACE 0x0020 /* DCD output flow control */
+#define DTRPACE 0x0040 /* DTR input flow control */
+#define DIGI_COOK 0x0080 /* Cooked processing done in FEP */
+#define DIGI_FORCEDCD 0x0100 /* Force carrier */
+#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */
+#define DIGI_AIXON 0x0400 /* Aux flow control in fep */
+#define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl*/
+#define DIGI_PP_INPUT 0x1000 /* Change parallel port to input*/
+#define DIGI_DTR_TOGGLE 0x2000 /* Support DTR Toggle */
+#define DIGI_422 0x4000 /* for 422/232 selectable panel */
+#define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */
+
+/************************************************************************
+ * These options are not supported on the comxi.
+ ************************************************************************/
+#define DIGI_COMXI (DIGI_FAST|DIGI_COOK|DSRPACE|DCDPACE|DTRPACE)
+
+#define DIGI_PLEN 28 /* String length */
+#define DIGI_TSIZ 10 /* Terminal string len */
+
+/************************************************************************
+ * Structure used with ioctl commands for DIGI parameters.
+ ************************************************************************/
+struct digi_t {
+ unsigned short digi_flags; /* Flags (see above) */
+ unsigned short digi_maxcps; /* Max printer CPS */
+ unsigned short digi_maxchar; /* Max chars in print queue */
+ unsigned short digi_bufsize; /* Buffer size */
+ unsigned char digi_onlen; /* Length of ON string */
+ unsigned char digi_offlen; /* Length of OFF string */
+ char digi_onstr[DIGI_PLEN]; /* Printer on string */
+ char digi_offstr[DIGI_PLEN]; /* Printer off string */
+ char digi_term[DIGI_TSIZ]; /* terminal string */
+};
+
+/************************************************************************
+ * KME definitions and structures.
+ ************************************************************************/
+#define RW_IDLE 0 /* Operation complete */
+#define RW_READ 1 /* Read Concentrator Memory */
+#define RW_WRITE 2 /* Write Concentrator Memory */
+
+struct rw_t {
+ unsigned char rw_req; /* Request type */
+ unsigned char rw_board; /* Host Adapter board number */
+ unsigned char rw_conc; /* Concentrator number */
+ unsigned char rw_reserved; /* Reserved for expansion */
+ unsigned long rw_addr; /* Address in concentrator */
+ unsigned short rw_size; /* Read/write request length */
+ unsigned char rw_data[128]; /* Data to read/write */
+};
+
+/***********************************************************************
+ * Shrink Buffer and Board Information definitions and structures.
+
+ ************************************************************************/
+ /* Board type return codes */
+#define PCXI_TYPE 1 /* Board type at the designated port is a PC/Xi */
+#define PCXM_TYPE 2 /* Board type at the designated port is a PC/Xm */
+#define PCXE_TYPE 3 /* Board type at the designated port is a PC/Xe */
+#define MCXI_TYPE 4 /* Board type at the designated port is a MC/Xi */
+#define COMXI_TYPE 5 /* Board type at the designated port is a COM/Xi */
+
+ /* Non-Zero Result codes. */
+#define RESULT_NOBDFND 1 /* A Digi product at that port is not config installed */
+#define RESULT_NODESCT 2 /* A memory descriptor was not obtainable */
+#define RESULT_NOOSSIG 3 /* FEP/OS signature was not detected on the board */
+#define RESULT_TOOSML 4 /* Too small an area to shrink. */
+#define RESULT_NOCHAN 5 /* Channel structure for the board was not found */
+
+struct shrink_buf_struct {
+ unsigned long shrink_buf_vaddr; /* Virtual address of board */
+ unsigned long shrink_buf_phys; /* Physical address of board */
+ unsigned long shrink_buf_bseg; /* Amount of board memory */
+ unsigned long shrink_buf_hseg; /* '186 Beginning of Dual-Port */
+
+ unsigned long shrink_buf_lseg; /* '186 Beginning of freed memory */
+ unsigned long shrink_buf_mseg; /* Linear address from start of
+ dual-port were freed memory
+ begins, host viewpoint. */
+
+ unsigned long shrink_buf_bdparam; /* Parameter for xxmemon and
+ xxmemoff */
+
+ unsigned long shrink_buf_reserva; /* Reserved */
+ unsigned long shrink_buf_reservb; /* Reserved */
+ unsigned long shrink_buf_reservc; /* Reserved */
+ unsigned long shrink_buf_reservd; /* Reserved */
+
+ unsigned char shrink_buf_result; /* Reason for call failing
+ Zero is Good return */
+ unsigned char shrink_buf_init; /* Non-Zero if it caused an
+ xxinit call. */
+
+ unsigned char shrink_buf_anports; /* Number of async ports */
+ unsigned char shrink_buf_snports; /* Number of sync ports */
+ unsigned char shrink_buf_type; /* Board type 1 = PC/Xi,
+ 2 = PC/Xm,
+ 3 = PC/Xe
+ 4 = MC/Xi
+ 5 = COMX/i */
+ unsigned char shrink_buf_card; /* Card number */
+
+};
+
+/************************************************************************
+ * Structure to get driver status information
+ ************************************************************************/
+struct digi_dinfo {
+ unsigned long dinfo_nboards; /* # boards configured */
+ char dinfo_reserved[12]; /* for future expansion */
+ char dinfo_version[16]; /* driver version */
+};
+
+#define DIGI_GETDD (('d'<<8) | 248) /* get driver info */
+
+/************************************************************************
+ * Structure used with ioctl commands for per-board information
+ *
+ * physsize and memsize differ when board has "windowed" memory
+ ************************************************************************/
+struct digi_info {
+ unsigned long info_bdnum; /* Board number (0 based) */
+ unsigned long info_ioport; /* io port address */
+ unsigned long info_physaddr; /* memory address */
+ unsigned long info_physsize; /* Size of host mem window */
+ unsigned long info_memsize; /* Amount of dual-port mem */
+ /* on board */
+ unsigned short info_bdtype; /* Board type */
+ unsigned short info_nports; /* number of ports */
+ char info_bdstate; /* board state */
+ char info_reserved[7]; /* for future expansion */
+};
+
+#define DIGI_GETBD (('d'<<8) | 249) /* get board info */
+
+struct digi_stat {
+ unsigned int info_chan; /* Channel number (0 based) */
+ unsigned int info_brd; /* Board number (0 based) */
+ unsigned long info_cflag; /* cflag for channel */
+ unsigned long info_iflag; /* iflag for channel */
+ unsigned long info_oflag; /* oflag for channel */
+ unsigned long info_mstat; /* mstat for channel */
+ unsigned long info_tx_data; /* tx_data for channel */
+ unsigned long info_rx_data; /* rx_data for channel */
+ unsigned long info_hflow; /* hflow for channel */
+ unsigned long info_reserved[8]; /* for future expansion */
+};
+
+#define DIGI_GETSTAT (('d'<<8) | 244) /* get board info */
+/************************************************************************
+ *
+ * Structure used with ioctl commands for per-channel information
+ *
+ ************************************************************************/
+struct digi_ch {
+ unsigned long info_bdnum; /* Board number (0 based) */
+ unsigned long info_channel; /* Channel index number */
+ unsigned long info_ch_cflag; /* Channel cflag */
+ unsigned long info_ch_iflag; /* Channel iflag */
+ unsigned long info_ch_oflag; /* Channel oflag */
+ unsigned long info_chsize; /* Channel structure size */
+ unsigned long info_sleep_stat; /* sleep status */
+ dev_t info_dev; /* device number */
+ unsigned char info_initstate; /* Channel init state */
+ unsigned char info_running; /* Channel running state */
+ long reserved[8]; /* reserved for future use */
+};
+
+/*
+* This structure is used with the DIGI_FEPCMD ioctl to
+* tell the driver which port to send the command for.
+*/
+struct digi_cmd {
+ int cmd;
+ int word;
+ int ncmds;
+ int chan; /* channel index (zero based) */
+ int bdid; /* board index (zero based) */
+};
+
+/*
+* info_sleep_stat defines
+*/
+#define INFO_RUNWAIT 0x0001
+#define INFO_WOPEN 0x0002
+#define INFO_TTIOW 0x0004
+#define INFO_CH_RWAIT 0x0008
+#define INFO_CH_WEMPTY 0x0010
+#define INFO_CH_WLOW 0x0020
+#define INFO_XXBUF_BUSY 0x0040
+
+#define DIGI_GETCH (('d'<<8) | 245) /* get board info */
+
+/* Board type definitions */
+
+#define SUBTYPE 0007
+#define T_PCXI 0000
+#define T_PCXM 0001
+#define T_PCXE 0002
+#define T_PCXR 0003
+#define T_SP 0004
+#define T_SP_PLUS 0005
+# define T_HERC 0000
+# define T_HOU 0001
+# define T_LON 0002
+# define T_CHA 0003
+#define FAMILY 0070
+#define T_COMXI 0000
+#define T_PCXX 0010
+#define T_CX 0020
+#define T_EPC 0030
+#define T_PCLITE 0040
+#define T_SPXX 0050
+#define T_AVXX 0060
+#define T_DXB 0070
+#define T_A2K_4_8 0070
+#define BUSTYPE 0700
+#define T_ISABUS 0000
+#define T_MCBUS 0100
+#define T_EISABUS 0200
+#define T_PCIBUS 0400
+
+/* Board State Definitions */
+
+#define BD_RUNNING 0x0
+#define BD_REASON 0x7f
+#define BD_NOTFOUND 0x1
+#define BD_NOIOPORT 0x2
+#define BD_NOMEM 0x3
+#define BD_NOBIOS 0x4
+#define BD_NOFEP 0x5
+#define BD_FAILED 0x6
+#define BD_ALLOCATED 0x7
+#define BD_TRIBOOT 0x8
+#define BD_BADKME 0x80
+
+#define DIGI_LOOPBACK (('d'<<8) | 252) /* Enable/disable UART internal loopback */
+#define DIGI_SPOLL (('d'<<8) | 254) /* change poller rate */
+
+#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) /* Set integer baud rate */
+#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) /* Get integer baud rate */
+#define DIGI_RESET_PORT (('e'<<8) | 93) /* Reset port */
+
+/************************************************************************
+ * Channel information structure.
+ ************************************************************************/
+struct channel_t {
+ int magic; /* Channel Magic Number */
+ struct bs_t *ch_bs; /* Base structure pointer */
+ struct cm_t *ch_cm; /* Command queue pointer */
+ struct board_t *ch_bd; /* Board structure pointer */
+ unsigned char *ch_vaddr; /* FEP memory origin */
+ unsigned char *ch_taddr; /* Write buffer origin */
+ unsigned char *ch_raddr; /* Read buffer origin */
+ struct digi_t ch_digi; /* Transparent Print structure */
+ struct un_t ch_tun; /* Terminal unit info */
+ struct un_t ch_pun; /* Printer unit info */
+
+ spinlock_t ch_lock; /* provide for serialization */
+ wait_queue_head_t ch_flags_wait;
+
+ u32 pscan_state;
+ uchar pscan_savechar;
+
+ u32 ch_portnum; /* Port number, 0 offset. */
+ u32 ch_open_count; /* open count */
+ u32 ch_flags; /* Channel flags */
+
+
+ u32 ch_close_delay; /* How long we should drop RTS/DTR for */
+
+ u32 ch_cpstime; /* Time for CPS calculations */
+
+ tcflag_t ch_c_iflag; /* channel iflags */
+ tcflag_t ch_c_cflag; /* channel cflags */
+ tcflag_t ch_c_oflag; /* channel oflags */
+ tcflag_t ch_c_lflag; /* channel lflags */
+
+ u16 ch_fepiflag; /* FEP tty iflags */
+ u16 ch_fepcflag; /* FEP tty cflags */
+ u16 ch_fepoflag; /* FEP tty oflags */
+ u16 ch_wopen; /* Waiting for open process cnt */
+ u16 ch_tstart; /* Transmit buffer start */
+ u16 ch_tsize; /* Transmit buffer size */
+ u16 ch_rstart; /* Receive buffer start */
+ u16 ch_rsize; /* Receive buffer size */
+ u16 ch_rdelay; /* Receive delay time */
+
+ u16 ch_tlw; /* Our currently set low water mark */
+
+ u16 ch_cook; /* Output character mask */
+
+ uchar ch_card; /* Card channel is on */
+ uchar ch_stopc; /* Stop character */
+ uchar ch_startc; /* Start character */
+
+ uchar ch_mostat; /* FEP output modem status */
+ uchar ch_mistat; /* FEP input modem status */
+ uchar ch_mforce; /* Modem values to be forced */
+ uchar ch_mval; /* Force values */
+ uchar ch_fepstopc; /* FEP stop character */
+ uchar ch_fepstartc; /* FEP start character */
+
+ uchar ch_astopc; /* Auxiliary Stop character */
+ uchar ch_astartc; /* Auxiliary Start character */
+ uchar ch_fepastopc; /* Auxiliary FEP stop char */
+ uchar ch_fepastartc; /* Auxiliary FEP start char */
+
+ uchar ch_hflow; /* FEP hardware handshake */
+ uchar ch_dsr; /* stores real dsr value */
+ uchar ch_cd; /* stores real cd value */
+ uchar ch_tx_win; /* channel tx buffer window */
+ uchar ch_rx_win; /* channel rx buffer window */
+ uint ch_custom_speed; /* Custom baud, if set */
+ uint ch_baud_info; /* Current baud info for /proc output */
+ ulong ch_rxcount; /* total of data received so far */
+ ulong ch_txcount; /* total of data transmitted so far */
+ ulong ch_err_parity; /* Count of parity errors on channel */
+ ulong ch_err_frame; /* Count of framing errors on channel */
+ ulong ch_err_break; /* Count of breaks on channel */
+ ulong ch_err_overrun; /* Count of overruns on channel */
+
+ uint ch_sniff_in;
+ uint ch_sniff_out;
+ char *ch_sniff_buf; /* Sniff buffer for proc */
+ ulong ch_sniff_flags; /* Channel flags */
+ wait_queue_head_t ch_sniff_wait;
+};
+
+/************************************************************************
+ * Command structure definition.
+ ************************************************************************/
+struct cm_t {
+ volatile unsigned short cm_head; /* Command buffer head offset */
+ volatile unsigned short cm_tail; /* Command buffer tail offset */
+ volatile unsigned short cm_start; /* start offset of buffer */
+ volatile unsigned short cm_max; /* last offset of buffer */
+};
+
+/************************************************************************
+ * Event structure definition.
+ ************************************************************************/
+struct ev_t {
+ volatile unsigned short ev_head; /* Command buffer head offset */
+ volatile unsigned short ev_tail; /* Command buffer tail offset */
+ volatile unsigned short ev_start; /* start offset of buffer */
+ volatile unsigned short ev_max; /* last offset of buffer */
+};
+
+/************************************************************************
+ * Download buffer structure.
+ ************************************************************************/
+struct downld_t {
+ uchar dl_type; /* Header */
+ uchar dl_seq; /* Download sequence */
+ ushort dl_srev; /* Software revision number */
+ ushort dl_lrev; /* Low revision number */
+ ushort dl_hrev; /* High revision number */
+ ushort dl_seg; /* Start segment address */
+ ushort dl_size; /* Number of bytes to download */
+ uchar dl_data[1024]; /* Download data */
+};
+
+/************************************************************************
+ * Per channel buffer structure
+ ************************************************************************
+ * Base Structure Entries Usage Meanings to Host *
+ * *
+ * W = read write R = read only *
+ * C = changed by commands only *
+ * U = unknown (may be changed w/o notice) *
+ ************************************************************************/
+struct bs_t {
+ volatile unsigned short tp_jmp; /* Transmit poll jump */
+ volatile unsigned short tc_jmp; /* Cooked procedure jump */
+ volatile unsigned short ri_jmp; /* Not currently used */
+ volatile unsigned short rp_jmp; /* Receive poll jump */
+
+ volatile unsigned short tx_seg; /* W Tx segment */
+ volatile unsigned short tx_head; /* W Tx buffer head offset */
+ volatile unsigned short tx_tail; /* R Tx buffer tail offset */
+ volatile unsigned short tx_max; /* W Tx buffer size - 1 */
+
+ volatile unsigned short rx_seg; /* W Rx segment */
+ volatile unsigned short rx_head; /* W Rx buffer head offset */
+ volatile unsigned short rx_tail; /* R Rx buffer tail offset */
+ volatile unsigned short rx_max; /* W Rx buffer size - 1 */
+
+ volatile unsigned short tx_lw; /* W Tx buffer low water mark */
+ volatile unsigned short rx_lw; /* W Rx buffer low water mark */
+ volatile unsigned short rx_hw; /* W Rx buffer high water mark */
+ volatile unsigned short incr; /* W Increment to next channel */
+
+ volatile unsigned short fepdev; /* U SCC device base address */
+ volatile unsigned short edelay; /* W Exception delay */
+ volatile unsigned short blen; /* W Break length */
+ volatile unsigned short btime; /* U Break complete time */
+
+ volatile unsigned short iflag; /* C UNIX input flags */
+ volatile unsigned short oflag; /* C UNIX output flags */
+ volatile unsigned short cflag; /* C UNIX control flags */
+ volatile unsigned short wfill[13]; /* U Reserved for expansion */
+
+ volatile unsigned char num; /* U Channel number */
+ volatile unsigned char ract; /* U Receiver active counter */
+ volatile unsigned char bstat; /* U Break status bits */
+ volatile unsigned char tbusy; /* W Transmit busy */
+ volatile unsigned char iempty; /* W Transmit empty event enable */
+ volatile unsigned char ilow; /* W Transmit low-water event enable */
+ volatile unsigned char idata; /* W Receive data interrupt enable */
+ volatile unsigned char eflag; /* U Host event flags */
+
+ volatile unsigned char tflag; /* U Transmit flags */
+ volatile unsigned char rflag; /* U Receive flags */
+ volatile unsigned char xmask; /* U Transmit ready flags */
+ volatile unsigned char xval; /* U Transmit ready value */
+ volatile unsigned char m_stat; /* RC Modem status bits */
+ volatile unsigned char m_change; /* U Modem bits which changed */
+ volatile unsigned char m_int; /* W Modem interrupt enable bits */
+ volatile unsigned char m_last; /* U Last modem status */
+
+ volatile unsigned char mtran; /* C Unreported modem trans */
+ volatile unsigned char orun; /* C Buffer overrun occurred */
+ volatile unsigned char astartc; /* W Auxiliary Xon char */
+ volatile unsigned char astopc; /* W Auxiliary Xoff char */
+ volatile unsigned char startc; /* W Xon character */
+ volatile unsigned char stopc; /* W Xoff character */
+ volatile unsigned char vnextc; /* W Vnext character */
+ volatile unsigned char hflow; /* C Software flow control */
+
+ volatile unsigned char fillc; /* U Delay Fill character */
+ volatile unsigned char ochar; /* U Saved output character */
+ volatile unsigned char omask; /* U Output character mask */
+
+ volatile unsigned char bfill[13]; /* U Reserved for expansion */
+
+ volatile unsigned char scc[16]; /* U SCC registers */
+};
+
+struct cnode {
+ struct cnode *next;
+ int type;
+ int numbrd;
+
+ union {
+ struct {
+ char type; /* Board Type */
+ long port; /* I/O Address */
+ char *portstr; /* I/O Address in string */
+ long addr; /* Memory Address */
+ char *addrstr; /* Memory Address in string */
+ long pcibus; /* PCI BUS */
+ char *pcibusstr; /* PCI BUS in string */
+ long pcislot; /* PCI SLOT */
+ char *pcislotstr; /* PCI SLOT in string */
+ long nport; /* Number of Ports */
+ char *id; /* tty id */
+ long start; /* start of tty counting */
+ char *method; /* Install method */
+ char v_type;
+ char v_port;
+ char v_addr;
+ char v_pcibus;
+ char v_pcislot;
+ char v_nport;
+ char v_id;
+ char v_start;
+ char v_method;
+ char line1;
+ char line2;
+ char conc1; /* total concs in line1 */
+ char conc2; /* total concs in line2 */
+ char module1; /* total modules for line1 */
+ char module2; /* total modules for line2 */
+ char *status; /* config status */
+ char *dimstatus; /* Y/N */
+ int status_index; /* field pointer */
+ } board;
+
+ struct {
+ char *cable;
+ char v_cable;
+ long speed;
+ char v_speed;
+ } line;
+
+ struct {
+ char type;
+ char *connect;
+ long speed;
+ long nport;
+ char *id;
+ char *idstr;
+ long start;
+ char v_type;
+ char v_connect;
+ char v_speed;
+ char v_nport;
+ char v_id;
+ char v_start;
+ } conc;
+
+ struct {
+ char type;
+ long nport;
+ char *id;
+ char *idstr;
+ long start;
+ char v_type;
+ char v_nport;
+ char v_id;
+ char v_start;
+ } module;
+
+ char *ttyname;
+
+ char *cuname;
+
+ char *printname;
+
+ long majornumber;
+
+ long altpin;
+
+ long ttysize;
+
+ long chsize;
+
+ long bssize;
+
+ long unsize;
+
+ long f2size;
+
+ long vpixsize;
+
+ long useintr;
+ } u;
+};
+
+#endif
diff --git a/drivers/staging/dgap/dgap_conf.h b/drivers/staging/dgap/dgap_conf.h
deleted file mode 100644
index 484ed726a4d6..000000000000
--- a/drivers/staging/dgap/dgap_conf.h
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *****************************************************************************
- *
- * dgap_conf.h - Header file for installations and parse files.
- *
- * $Id: dgap_conf.h,v 1.1 2009/10/23 14:01:57 markh Exp $
- *
- * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
- */
-
-#ifndef _DGAP_CONF_H
-#define _DGAP_CONF_H
-
-#define NULLNODE 0 /* header node, not used */
-#define BNODE 1 /* Board node */
-#define LNODE 2 /* Line node */
-#define CNODE 3 /* Concentrator node */
-#define MNODE 4 /* EBI Module node */
-#define TNODE 5 /* tty name prefix node */
-#define CUNODE 6 /* cu name prefix (non-SCO) */
-#define PNODE 7 /* trans. print prefix node */
-#define JNODE 8 /* maJor number node */
-#define ANODE 9 /* altpin */
-#define TSNODE 10 /* tty structure size */
-#define CSNODE 11 /* channel structure size */
-#define BSNODE 12 /* board structure size */
-#define USNODE 13 /* unit schedule structure size */
-#define FSNODE 14 /* f2200 structure size */
-#define VSNODE 15 /* size of VPIX structures */
-#define INTRNODE 16 /* enable interrupt */
-
-/* Enumeration of tokens */
-#define BEGIN 1
-#define END 2
-#define BOARD 10
-
-#define EPCFS 11 /* start of EPC family definitions */
-#define ICX 11
-#define MCX 13
-#define PCX 14
-#define IEPC 15
-#define EEPC 16
-#define MEPC 17
-#define IPCM 18
-#define EPCM 19
-#define MPCM 20
-#define PEPC 21
-#define PPCM 22
-#ifdef CP
-#define ICP 23
-#define ECP 24
-#define MCP 25
-#endif
-#define EPCFE 25 /* end of EPC family definitions */
-#define PC2E 26
-#define PC4E 27
-#define PC4E8K 28
-#define PC8E 29
-#define PC8E8K 30
-#define PC16E 31
-#define MC2E8K 34
-#define MC4E8K 35
-#define MC8E8K 36
-
-#define AVANFS 42 /* start of Avanstar family definitions */
-#define A8P 42
-#define A16P 43
-#define AVANFE 43 /* end of Avanstar family definitions */
-
-#define DA2000FS 44 /* start of AccelePort 2000 family definitions */
-#define DA22 44 /* AccelePort 2002 */
-#define DA24 45 /* AccelePort 2004 */
-#define DA28 46 /* AccelePort 2008 */
-#define DA216 47 /* AccelePort 2016 */
-#define DAR4 48 /* AccelePort RAS 4 port */
-#define DAR8 49 /* AccelePort RAS 8 port */
-#define DDR24 50 /* DataFire RAS 24 port */
-#define DDR30 51 /* DataFire RAS 30 port */
-#define DDR48 52 /* DataFire RAS 48 port */
-#define DDR60 53 /* DataFire RAS 60 port */
-#define DA2000FE 53 /* end of AccelePort 2000/RAS family definitions */
-
-#define PCXRFS 106 /* start of PCXR family definitions */
-#define APORT4 106
-#define APORT8 107
-#define PAPORT4 108
-#define PAPORT8 109
-#define APORT4_920I 110
-#define APORT8_920I 111
-#define APORT4_920P 112
-#define APORT8_920P 113
-#define APORT2_920P 114
-#define PCXRFE 117 /* end of PCXR family definitions */
-
-#define LINE 82
-#ifdef T1
-#define T1M 83
-#define E1M 84
-#endif
-#define CONC 64
-#define CX 65
-#define EPC 66
-#define MOD 67
-#define PORTS 68
-#define METHOD 69
-#define CUSTOM 70
-#define BASIC 71
-#define STATUS 72
-#define MODEM 73
-/* The following tokens can appear in multiple places */
-#define SPEED 74
-#define NPORTS 75
-#define ID 76
-#define CABLE 77
-#define CONNECT 78
-#define IO 79
-#define MEM 80
-#define DPSZ 81
-
-#define TTYN 90
-#define CU 91
-#define PRINT 92
-#define XPRINT 93
-#define CMAJOR 94
-#define ALTPIN 95
-#define STARTO 96
-#define USEINTR 97
-#define PCIINFO 98
-
-#define TTSIZ 100
-#define CHSIZ 101
-#define BSSIZ 102
-#define UNTSIZ 103
-#define F2SIZ 104
-#define VPSIZ 105
-
-#define TOTAL_BOARD 2
-#define CURRENT_BRD 4
-#define BOARD_TYPE 6
-#define IO_ADDRESS 8
-#define MEM_ADDRESS 10
-
-#define FIELDS_PER_PAGE 18
-
-#define TB_FIELD 1
-#define CB_FIELD 3
-#define BT_FIELD 5
-#define IO_FIELD 7
-#define ID_FIELD 8
-#define ME_FIELD 9
-#define TTY_FIELD 11
-#define CU_FIELD 13
-#define PR_FIELD 15
-#define MPR_FIELD 17
-
-#define MAX_FIELD 512
-
-#define INIT 0
-#define NITEMS 128
-#define MAX_ITEM 512
-
-#define DSCRINST 1
-#define DSCRNUM 3
-#define ALTPINQ 5
-#define SSAVE 7
-
-#define DSCR "32"
-#define ONETONINE "123456789"
-#define ALL "1234567890"
-
-
-struct cnode {
- struct cnode *next;
- int type;
- int numbrd;
-
- union {
- struct {
- char type; /* Board Type */
- short port; /* I/O Address */
- char *portstr; /* I/O Address in string */
- long addr; /* Memory Address */
- char *addrstr; /* Memory Address in string */
- long pcibus; /* PCI BUS */
- char *pcibusstr; /* PCI BUS in string */
- long pcislot; /* PCI SLOT */
- char *pcislotstr; /* PCI SLOT in string */
- char nport; /* Number of Ports */
- char *id; /* tty id */
- int start; /* start of tty counting */
- char *method; /* Install method */
- char v_type;
- char v_port;
- char v_addr;
- char v_pcibus;
- char v_pcislot;
- char v_nport;
- char v_id;
- char v_start;
- char v_method;
- char line1;
- char line2;
- char conc1; /* total concs in line1 */
- char conc2; /* total concs in line2 */
- char module1; /* total modules for line1 */
- char module2; /* total modules for line2 */
- char *status; /* config status */
- char *dimstatus; /* Y/N */
- int status_index; /* field pointer */
- } board;
-
- struct {
- char *cable;
- char v_cable;
- char speed;
- char v_speed;
- } line;
-
- struct {
- char type;
- char *connect;
- char speed;
- char nport;
- char *id;
- char *idstr;
- int start;
- char v_type;
- char v_connect;
- char v_speed;
- char v_nport;
- char v_id;
- char v_start;
- } conc;
-
- struct {
- char type;
- char nport;
- char *id;
- char *idstr;
- int start;
- char v_type;
- char v_nport;
- char v_id;
- char v_start;
- } module;
-
- char *ttyname;
-
- char *cuname;
-
- char *printname;
-
- int majornumber;
-
- int altpin;
-
- int ttysize;
-
- int chsize;
-
- int bssize;
-
- int unsize;
-
- int f2size;
-
- int vpixsize;
-
- int useintr;
- } u;
-};
-
-#endif
diff --git a/drivers/staging/dgap/dgap_downld.h b/drivers/staging/dgap/dgap_downld.h
deleted file mode 100644
index 271ac19257f9..000000000000
--- a/drivers/staging/dgap/dgap_downld.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: dgap_downld.h,v 1.1 2009/10/23 14:01:57 markh Exp $
- *
- * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
- *
- */
-
-/*
-** downld.h
-** - describes the interface between the user level download process
-** and the concentrator download driver.
-*/
-
-#ifndef _DGAP_DOWNLD_H_
-#define _DGAP_DOWNLD_H_
-
-
-struct fepimg {
- int type; /* board type */
- int len; /* length of image */
- char fepimage[1]; /* beginning of image */
-};
-
-struct downldio {
- unsigned int req_type; /* FEP or concentrator */
- unsigned int bdid; /* opaque board identifier */
- union {
- struct downld_t dl; /* download structure */
- struct fepimg fi; /* fep/bios image structure */
- } image;
-};
-
-#define DIGI_DLREQ_GET (('d'<<8) | 220)
-#define DIGI_DLREQ_SET (('d'<<8) | 221)
-
-#define DIGI_DL_NUKE (('d'<<8) | 222) /* Not really a dl request, but
- dangerous enuff to not put in
- digi.h */
-/* Packed bits of intarg for DIGI_DL_NUKE */
-#define DIGI_NUKE_RESET_ALL (1 << 31)
-#define DIGI_NUKE_INHIBIT_POLLER (1 << 30)
-#define DIGI_NUKE_BRD_NUMB 0x0f
-
-
-
-#define DLREQ_BIOS 0
-#define DLREQ_FEP 1
-#define DLREQ_CONC 2
-#define DLREQ_CONFIG 3
-#define DLREQ_DEVCREATE 4
-
-#endif
diff --git a/drivers/staging/dgap/dgap_driver.c b/drivers/staging/dgap/dgap_driver.c
deleted file mode 100644
index 089d017fc291..000000000000
--- a/drivers/staging/dgap/dgap_driver.c
+++ /dev/null
@@ -1,1030 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
- *
- * This is shared code between Digi's CVS archive and the
- * Linux Kernel sources.
- * Changing the source just for reformatting needlessly breaks
- * our CVS diff history.
- *
- * Send any bug fixes/changes to: Eng.Linux at digi dot com.
- * Thank you.
- *
- * $Id: dgap_driver.c,v 1.3 2011/06/21 10:35:16 markh Exp $
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/delay.h> /* For udelay */
-#include <linux/slab.h>
-#include <asm/uaccess.h> /* For copy_from_user/copy_to_user */
-#include <linux/sched.h>
-
-#include "dgap_driver.h"
-#include "dgap_pci.h"
-#include "dgap_fep5.h"
-#include "dgap_tty.h"
-#include "dgap_conf.h"
-#include "dgap_parse.h"
-#include "dgap_trace.h"
-#include "dgap_sysfs.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Digi International, http://www.digi.com");
-MODULE_DESCRIPTION("Driver for the Digi International EPCA PCI based product line");
-MODULE_SUPPORTED_DEVICE("dgap");
-
-/*
- * insmod command line overrideable parameters
- *
- * NOTE: we use a set of macros to create the variables, which allows
- * us to specify the variable type, name, initial value, and description.
- */
-PARM_INT(debug, 0x00, 0644, "Driver debugging level");
-PARM_INT(rawreadok, 1, 0644, "Bypass flip buffers on input");
-PARM_INT(trcbuf_size, 0x100000, 0644, "Debugging trace buffer size.");
-
-
-/**************************************************************************
- *
- * protos for this file
- *
- */
-
-static int dgap_start(void);
-static void dgap_init_globals(void);
-static int dgap_found_board(struct pci_dev *pdev, int id);
-static void dgap_cleanup_board(struct board_t *brd);
-static void dgap_poll_handler(ulong dummy);
-static int dgap_init_pci(void);
-static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static void dgap_remove_one(struct pci_dev *dev);
-static int dgap_probe1(struct pci_dev *pdev, int card_type);
-static void dgap_mbuf(struct board_t *brd, const char *fmt, ...);
-static int dgap_do_remap(struct board_t *brd);
-static irqreturn_t dgap_intr(int irq, void *voidbrd);
-
-/* Driver load/unload functions */
-int dgap_init_module(void);
-void dgap_cleanup_module(void);
-
-module_init(dgap_init_module);
-module_exit(dgap_cleanup_module);
-
-
-/*
- * File operations permitted on Control/Management major.
- */
-static struct file_operations DgapBoardFops =
-{
- .owner = THIS_MODULE,
-};
-
-
-/*
- * Globals
- */
-uint dgap_NumBoards;
-struct board_t *dgap_Board[MAXBOARDS];
-DEFINE_SPINLOCK(dgap_global_lock);
-ulong dgap_poll_counter;
-char *dgap_config_buf;
-int dgap_driver_state = DRIVER_INITIALIZED;
-DEFINE_SPINLOCK(dgap_dl_lock);
-wait_queue_head_t dgap_dl_wait;
-int dgap_dl_action;
-int dgap_poll_tick = 20; /* Poll interval - 20 ms */
-
-/*
- * Static vars.
- */
-static int dgap_Major_Control_Registered = FALSE;
-static uint dgap_driver_start = FALSE;
-
-static struct class * dgap_class;
-
-/*
- * Poller stuff
- */
-static DEFINE_SPINLOCK(dgap_poll_lock); /* Poll scheduling lock */
-static ulong dgap_poll_time; /* Time of next poll */
-static uint dgap_poll_stop; /* Used to tell poller to stop */
-static struct timer_list dgap_poll_timer;
-
-
-static struct pci_device_id dgap_pci_tbl[] = {
- { DIGI_VID, PCI_DEVICE_XEM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { DIGI_VID, PCI_DEVICE_CX_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
- { DIGI_VID, PCI_DEVICE_CX_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
- { DIGI_VID, PCI_DEVICE_EPCJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
- { DIGI_VID, PCI_DEVICE_920_2_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { DIGI_VID, PCI_DEVICE_920_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
- { DIGI_VID, PCI_DEVICE_920_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
- { DIGI_VID, PCI_DEVICE_XR_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
- { DIGI_VID, PCI_DEVICE_XRJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { DIGI_VID, PCI_DEVICE_XR_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
- { DIGI_VID, PCI_DEVICE_XR_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 },
- { DIGI_VID, PCI_DEVICE_XR_SAIP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 },
- { DIGI_VID, PCI_DEVICE_XR_BULL_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
- { DIGI_VID, PCI_DEVICE_920_8_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
- { DIGI_VID, PCI_DEVICE_XEM_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
- {0,} /* 0 terminated list. */
-};
-MODULE_DEVICE_TABLE(pci, dgap_pci_tbl);
-
-
-/*
- * A generic list of Product names, PCI Vendor ID, and PCI Device ID.
- */
-struct board_id {
- uint config_type;
- uchar *name;
- uint maxports;
- uint dpatype;
-};
-
-static struct board_id dgap_Ids[] =
-{
- { PPCM, PCI_DEVICE_XEM_NAME, 64, (T_PCXM | T_PCLITE | T_PCIBUS) },
- { PCX, PCI_DEVICE_CX_NAME, 128, (T_CX | T_PCIBUS) },
- { PCX, PCI_DEVICE_CX_IBM_NAME, 128, (T_CX | T_PCIBUS) },
- { PEPC, PCI_DEVICE_EPCJ_NAME, 224, (T_EPC | T_PCIBUS) },
- { APORT2_920P, PCI_DEVICE_920_2_NAME, 2, (T_PCXR | T_PCLITE | T_PCIBUS) },
- { APORT4_920P, PCI_DEVICE_920_4_NAME, 4, (T_PCXR | T_PCLITE | T_PCIBUS) },
- { APORT8_920P, PCI_DEVICE_920_8_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
- { PAPORT8, PCI_DEVICE_XR_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
- { PAPORT8, PCI_DEVICE_XRJ_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
- { PAPORT8, PCI_DEVICE_XR_422_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
- { PAPORT8, PCI_DEVICE_XR_IBM_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
- { PAPORT8, PCI_DEVICE_XR_SAIP_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
- { PAPORT8, PCI_DEVICE_XR_BULL_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
- { APORT8_920P, PCI_DEVICE_920_8_HP_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
- { PPCM, PCI_DEVICE_XEM_HP_NAME, 64, (T_PCXM | T_PCLITE | T_PCIBUS) },
- {0,} /* 0 terminated list. */
-};
-
-static struct pci_driver dgap_driver = {
- .name = "dgap",
- .probe = dgap_init_one,
- .id_table = dgap_pci_tbl,
- .remove = dgap_remove_one,
-};
-
-
-char *dgap_state_text[] = {
- "Board Failed",
- "Configuration for board not found.\n\t\t\tRun mpi to configure board.",
- "Board Found",
- "Need Reset",
- "Finished Reset",
- "Need Config",
- "Finished Config",
- "Need Device Creation",
- "Requested Device Creation",
- "Finished Device Creation",
- "Need BIOS Load",
- "Requested BIOS",
- "Doing BIOS Load",
- "Finished BIOS Load",
- "Need FEP Load",
- "Requested FEP",
- "Doing FEP Load",
- "Finished FEP Load",
- "Requested PROC creation",
- "Finished PROC creation",
- "Board READY",
-};
-
-char *dgap_driver_state_text[] = {
- "Driver Initialized",
- "Driver needs configuration load.",
- "Driver requested configuration from download daemon.",
- "Driver Ready."
-};
-
-
-
-/************************************************************************
- *
- * Driver load/unload functions
- *
- ************************************************************************/
-
-/*
- * init_module()
- *
- * Module load. This is where it all starts.
- */
-int dgap_init_module(void)
-{
- int rc = 0;
-
- APR(("%s, Digi International Part Number %s\n", DG_NAME, DG_PART));
-
- /*
- * Initialize global stuff
- */
- rc = dgap_start();
-
- if (rc < 0) {
- return(rc);
- }
-
- /*
- * Find and configure all the cards
- */
- rc = dgap_init_pci();
-
- /*
- * If something went wrong in the scan, bail out of driver.
- */
- if (rc < 0) {
- /* Only unregister the pci driver if it was actually registered. */
- if (dgap_NumBoards)
- pci_unregister_driver(&dgap_driver);
- else
- printk("WARNING: dgap driver load failed. No DGAP boards found.\n");
-
- dgap_cleanup_module();
- }
- else {
- dgap_create_driver_sysfiles(&dgap_driver);
- }
-
- DPR_INIT(("Finished init_module. Returning %d\n", rc));
- return (rc);
-}
-
-
-/*
- * Start of driver.
- */
-static int dgap_start(void)
-{
- int rc = 0;
- unsigned long flags;
-
- if (dgap_driver_start == FALSE) {
-
- dgap_driver_start = TRUE;
-
- /* make sure that the globals are init'd before we do anything else */
- dgap_init_globals();
-
- dgap_NumBoards = 0;
-
- APR(("For the tools package or updated drivers please visit http://www.digi.com\n"));
-
- /*
- * Register our base character device into the kernel.
- * This allows the download daemon to connect to the downld device
- * before any of the boards are init'ed.
- */
- if (!dgap_Major_Control_Registered) {
- /*
- * Register management/dpa devices
- */
- rc = register_chrdev(DIGI_DGAP_MAJOR, "dgap", &DgapBoardFops);
- if (rc < 0) {
- APR(("Can't register dgap driver device (%d)\n", rc));
- return (rc);
- }
-
- dgap_class = class_create(THIS_MODULE, "dgap_mgmt");
- device_create(dgap_class, NULL,
- MKDEV(DIGI_DGAP_MAJOR, 0),
- NULL, "dgap_mgmt");
- device_create(dgap_class, NULL,
- MKDEV(DIGI_DGAP_MAJOR, 1),
- NULL, "dgap_downld");
- dgap_Major_Control_Registered = TRUE;
- }
-
- /*
- * Init any global tty stuff.
- */
- rc = dgap_tty_preinit();
-
- if (rc < 0) {
- APR(("tty preinit - not enough memory (%d)\n", rc));
- return(rc);
- }
-
- /* Start the poller */
- DGAP_LOCK(dgap_poll_lock, flags);
- init_timer(&dgap_poll_timer);
- dgap_poll_timer.function = dgap_poll_handler;
- dgap_poll_timer.data = 0;
- dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick);
- dgap_poll_timer.expires = dgap_poll_time;
- DGAP_UNLOCK(dgap_poll_lock, flags);
-
- add_timer(&dgap_poll_timer);
-
- dgap_driver_state = DRIVER_NEED_CONFIG_LOAD;
- }
-
- return (rc);
-}
-
-
-/*
- * Register pci driver, and return how many boards we have.
- */
-static int dgap_init_pci(void)
-{
- return pci_register_driver(&dgap_driver);
-}
-
-
-/* returns count (>= 0), or negative on error */
-static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int rc;
-
- /* wake up and enable device */
- rc = pci_enable_device(pdev);
-
- if (rc < 0) {
- rc = -EIO;
- } else {
- rc = dgap_probe1(pdev, ent->driver_data);
- if (rc == 0) {
- dgap_NumBoards++;
- DPR_INIT(("Incrementing numboards to %d\n", dgap_NumBoards));
- }
- }
- return rc;
-}
-
-
-static int dgap_probe1(struct pci_dev *pdev, int card_type)
-{
- return dgap_found_board(pdev, card_type);
-}
-
-
-static void dgap_remove_one(struct pci_dev *dev)
-{
- /* Do Nothing */
-}
-
-
-/*
- * dgap_cleanup_module()
- *
- * Module unload. This is where it all ends.
- */
-void dgap_cleanup_module(void)
-{
- int i;
- ulong lock_flags;
-
- DGAP_LOCK(dgap_poll_lock, lock_flags);
- dgap_poll_stop = 1;
- DGAP_UNLOCK(dgap_poll_lock, lock_flags);
-
- /* Turn off poller right away. */
- del_timer_sync( &dgap_poll_timer);
-
- dgap_remove_driver_sysfiles(&dgap_driver);
-
-
- if (dgap_Major_Control_Registered) {
- device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 0));
- device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 1));
- class_destroy(dgap_class);
- unregister_chrdev(DIGI_DGAP_MAJOR, "dgap");
- }
-
- kfree(dgap_config_buf);
-
- for (i = 0; i < dgap_NumBoards; ++i) {
- dgap_remove_ports_sysfiles(dgap_Board[i]);
- dgap_tty_uninit(dgap_Board[i]);
- dgap_cleanup_board(dgap_Board[i]);
- }
-
- dgap_tty_post_uninit();
-
-#if defined(DGAP_TRACER)
- /* last thing, make sure we release the tracebuffer */
- dgap_tracer_free();
-#endif
- if (dgap_NumBoards)
- pci_unregister_driver(&dgap_driver);
-}
-
-
-/*
- * dgap_cleanup_board()
- *
- * Free all the memory associated with a board
- */
-static void dgap_cleanup_board(struct board_t *brd)
-{
- int i = 0;
-
- if(!brd || brd->magic != DGAP_BOARD_MAGIC)
- return;
-
- if (brd->intr_used && brd->irq)
- free_irq(brd->irq, brd);
-
- tasklet_kill(&brd->helper_tasklet);
-
- if (brd->re_map_port) {
- release_mem_region(brd->membase + 0x200000, 0x200000);
- iounmap(brd->re_map_port);
- brd->re_map_port = NULL;
- }
-
- if (brd->re_map_membase) {
- release_mem_region(brd->membase, 0x200000);
- iounmap(brd->re_map_membase);
- brd->re_map_membase = NULL;
- }
-
- if (brd->msgbuf_head) {
- unsigned long flags;
-
- DGAP_LOCK(dgap_global_lock, flags);
- brd->msgbuf = NULL;
- printk("%s", brd->msgbuf_head);
- kfree(brd->msgbuf_head);
- brd->msgbuf_head = NULL;
- DGAP_UNLOCK(dgap_global_lock, flags);
- }
-
- /* Free all allocated channels structs */
- for (i = 0; i < MAXPORTS ; i++) {
- if (brd->channels[i]) {
- kfree(brd->channels[i]);
- brd->channels[i] = NULL;
- }
- }
-
- kfree(brd->flipbuf);
- kfree(brd->flipflagbuf);
-
- dgap_Board[brd->boardnum] = NULL;
-
- kfree(brd);
-}
-
-
-/*
- * dgap_found_board()
- *
- * A board has been found, init it.
- */
-static int dgap_found_board(struct pci_dev *pdev, int id)
-{
- struct board_t *brd;
- unsigned int pci_irq;
- int i = 0;
- unsigned long flags;
-
- /* get the board structure and prep it */
- brd = dgap_Board[dgap_NumBoards] =
- (struct board_t *) kzalloc(sizeof(struct board_t), GFP_KERNEL);
- if (!brd) {
- APR(("memory allocation for board structure failed\n"));
- return(-ENOMEM);
- }
-
- /* make a temporary message buffer for the boot messages */
- brd->msgbuf = brd->msgbuf_head =
- (char *) kzalloc(sizeof(char) * 8192, GFP_KERNEL);
- if(!brd->msgbuf) {
- kfree(brd);
- APR(("memory allocation for board msgbuf failed\n"));
- return(-ENOMEM);
- }
-
- /* store the info for the board we've found */
- brd->magic = DGAP_BOARD_MAGIC;
- brd->boardnum = dgap_NumBoards;
- brd->firstminor = 0;
- brd->vendor = dgap_pci_tbl[id].vendor;
- brd->device = dgap_pci_tbl[id].device;
- brd->pdev = pdev;
- brd->pci_bus = pdev->bus->number;
- brd->pci_slot = PCI_SLOT(pdev->devfn);
- brd->name = dgap_Ids[id].name;
- brd->maxports = dgap_Ids[id].maxports;
- brd->type = dgap_Ids[id].config_type;
- brd->dpatype = dgap_Ids[id].dpatype;
- brd->dpastatus = BD_NOFEP;
- init_waitqueue_head(&brd->state_wait);
-
- DGAP_SPINLOCK_INIT(brd->bd_lock);
-
- brd->state = BOARD_FOUND;
- brd->runwait = 0;
- brd->inhibit_poller = FALSE;
- brd->wait_for_bios = 0;
- brd->wait_for_fep = 0;
-
- for (i = 0; i < MAXPORTS; i++) {
- brd->channels[i] = NULL;
- }
-
- /* store which card & revision we have */
- pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor);
- pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice);
- pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev);
-
- pci_irq = pdev->irq;
- brd->irq = pci_irq;
-
- /* get the PCI Base Address Registers */
-
- /* Xr Jupiter and EPC use BAR 2 */
- if (brd->device == PCI_DEVICE_XRJ_DID || brd->device == PCI_DEVICE_EPCJ_DID) {
- brd->membase = pci_resource_start(pdev, 2);
- brd->membase_end = pci_resource_end(pdev, 2);
- }
- /* Everyone else uses BAR 0 */
- else {
- brd->membase = pci_resource_start(pdev, 0);
- brd->membase_end = pci_resource_end(pdev, 0);
- }
-
- if (!brd->membase) {
- APR(("card has no PCI IO resources, failing board.\n"));
- return -ENODEV;
- }
-
- if (brd->membase & 1)
- brd->membase &= ~3;
- else
- brd->membase &= ~15;
-
- /*
- * On the PCI boards, there is no IO space allocated
- * The I/O registers will be in the first 3 bytes of the
- * upper 2MB of the 4MB memory space. The board memory
- * will be mapped into the low 2MB of the 4MB memory space
- */
- brd->port = brd->membase + PCI_IO_OFFSET;
- brd->port_end = brd->port + PCI_IO_SIZE;
-
-
- /*
- * Special initialization for non-PLX boards
- */
- if (brd->device != PCI_DEVICE_XRJ_DID && brd->device != PCI_DEVICE_EPCJ_DID) {
- unsigned short cmd;
-
- pci_write_config_byte(pdev, 0x40, 0);
- pci_write_config_byte(pdev, 0x46, 0);
-
- /* Limit burst length to 2 doubleword transactions */
- pci_write_config_byte(pdev, 0x42, 1);
-
- /*
- * Enable IO and mem if not already done.
- * This was needed for support on Itanium.
- */
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
- pci_write_config_word(pdev, PCI_COMMAND, cmd);
- }
-
- /* init our poll helper tasklet */
- tasklet_init(&brd->helper_tasklet, dgap_poll_tasklet, (unsigned long) brd);
-
- /* Log the information about the board */
- dgap_mbuf(brd, DRVSTR": board %d: %s (rev %d), irq %d\n",
- dgap_NumBoards, brd->name, brd->rev, brd->irq);
-
- DPR_INIT(("dgap_scan(%d) - printing out the msgbuf\n", i));
- DGAP_LOCK(dgap_global_lock, flags);
- brd->msgbuf = NULL;
- printk("%s", brd->msgbuf_head);
- kfree(brd->msgbuf_head);
- brd->msgbuf_head = NULL;
- DGAP_UNLOCK(dgap_global_lock, flags);
-
- i = dgap_do_remap(brd);
- if (i)
- brd->state = BOARD_FAILED;
- else
- brd->state = NEED_RESET;
-
- return(0);
-}
-
-
-int dgap_finalize_board_init(struct board_t *brd) {
-
- int rc;
-
- DPR_INIT(("dgap_finalize_board_init() - start\n"));
-
- if (!brd || brd->magic != DGAP_BOARD_MAGIC)
- return(-ENODEV);
-
- DPR_INIT(("dgap_finalize_board_init() - start #2\n"));
-
- brd->use_interrupts = dgap_config_get_useintr(brd);
-
- /*
- * Set up our interrupt handler if we are set to do interrupts.
- */
- if (brd->use_interrupts && brd->irq) {
-
- rc = request_irq(brd->irq, dgap_intr, IRQF_SHARED, "DGAP", brd);
-
- if (rc) {
- dgap_mbuf(brd, DRVSTR": Failed to hook IRQ %d. Board will work in poll mode.\n",
- brd->irq);
- brd->intr_used = 0;
- }
- else
- brd->intr_used = 1;
- } else {
- brd->intr_used = 0;
- }
-
- return(0);
-}
-
-
-/*
- * Remap PCI memory.
- */
-static int dgap_do_remap(struct board_t *brd)
-{
- if (!brd || brd->magic != DGAP_BOARD_MAGIC)
- return -ENXIO;
-
- if (!request_mem_region(brd->membase, 0x200000, "dgap")) {
- APR(("dgap: mem_region %lx already in use.\n", brd->membase));
- return -ENOMEM;
- }
-
- if (!request_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000, "dgap")) {
- APR(("dgap: mem_region IO %lx already in use.\n",
- brd->membase + PCI_IO_OFFSET));
- release_mem_region(brd->membase, 0x200000);
- return -ENOMEM;
- }
-
- brd->re_map_membase = ioremap(brd->membase, 0x200000);
- if (!brd->re_map_membase) {
- APR(("dgap: ioremap mem %lx cannot be mapped.\n", brd->membase));
- release_mem_region(brd->membase, 0x200000);
- release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
- return -ENOMEM;
- }
-
- brd->re_map_port = ioremap((brd->membase + PCI_IO_OFFSET), 0x200000);
- if (!brd->re_map_port) {
- release_mem_region(brd->membase, 0x200000);
- release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
- iounmap(brd->re_map_membase);
- APR(("dgap: ioremap IO mem %lx cannot be mapped.\n",
- brd->membase + PCI_IO_OFFSET));
- return -ENOMEM;
- }
-
- DPR_INIT(("remapped io: 0x%p remapped mem: 0x%p\n",
- brd->re_map_port, brd->re_map_membase));
- return 0;
-}
-
-
-/*****************************************************************************
-*
-* Function:
-*
-* dgap_poll_handler
-*
-* Author:
-*
-* Scott H Kilau
-*
-* Parameters:
-*
-* dummy -- ignored
-*
-* Return Values:
-*
-* none
-*
-* Description:
-*
-* As each timer expires, it determines (a) whether the "transmit"
-* waiter needs to be woken up, and (b) whether the poller needs to
-* be rescheduled.
-*
-******************************************************************************/
-
-static void dgap_poll_handler(ulong dummy)
-{
- int i;
- struct board_t *brd;
- unsigned long lock_flags;
- unsigned long lock_flags2;
- ulong new_time;
-
- dgap_poll_counter++;
-
-
- /*
- * If driver needs the config file still,
- * keep trying to wake up the downloader to
- * send us the file.
- */
- if (dgap_driver_state == DRIVER_NEED_CONFIG_LOAD) {
- /*
- * Signal downloader, its got some work to do.
- */
- DGAP_LOCK(dgap_dl_lock, lock_flags2);
- if (dgap_dl_action != 1) {
- dgap_dl_action = 1;
- wake_up_interruptible(&dgap_dl_wait);
- }
- DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
- goto schedule_poller;
- }
- /*
- * Do not start the board state machine until
- * driver tells us its up and running, and has
- * everything it needs.
- */
- else if (dgap_driver_state != DRIVER_READY) {
- goto schedule_poller;
- }
-
- /*
- * If we have just 1 board, or the system is not SMP,
- * then use the typical old style poller.
- * Otherwise, use our new tasklet based poller, which should
- * speed things up for multiple boards.
- */
- if ( (dgap_NumBoards == 1) || (num_online_cpus() <= 1) ) {
- for (i = 0; i < dgap_NumBoards; i++) {
-
- brd = dgap_Board[i];
-
- if (brd->state == BOARD_FAILED) {
- continue;
- }
- if (!brd->intr_running) {
- /* Call the real board poller directly */
- dgap_poll_tasklet((unsigned long) brd);
- }
- }
- }
- else {
- /* Go thru each board, kicking off a tasklet for each if needed */
- for (i = 0; i < dgap_NumBoards; i++) {
- brd = dgap_Board[i];
-
- /*
- * Attempt to grab the board lock.
- *
- * If we can't get it, no big deal, the next poll will get it.
- * Basically, I just really don't want to spin in here, because I want
- * to kick off my tasklets as fast as I can, and then get out the poller.
- */
- if (!spin_trylock(&brd->bd_lock)) {
- continue;
- }
-
- /* If board is in a failed state, don't bother scheduling a tasklet */
- if (brd->state == BOARD_FAILED) {
- spin_unlock(&brd->bd_lock);
- continue;
- }
-
- /* Schedule a poll helper task */
- if (!brd->intr_running) {
- tasklet_schedule(&brd->helper_tasklet);
- }
-
- /*
- * Can't do DGAP_UNLOCK here, as we don't have
- * lock_flags because we did a trylock above.
- */
- spin_unlock(&brd->bd_lock);
- }
- }
-
-schedule_poller:
-
- /*
- * Schedule ourself back at the nominal wakeup interval.
- */
- DGAP_LOCK(dgap_poll_lock, lock_flags );
- dgap_poll_time += dgap_jiffies_from_ms(dgap_poll_tick);
-
- new_time = dgap_poll_time - jiffies;
-
- if ((ulong) new_time >= 2 * dgap_poll_tick) {
- dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick);
- }
-
- dgap_poll_timer.function = dgap_poll_handler;
- dgap_poll_timer.data = 0;
- dgap_poll_timer.expires = dgap_poll_time;
- DGAP_UNLOCK(dgap_poll_lock, lock_flags );
-
- if (!dgap_poll_stop)
- add_timer(&dgap_poll_timer);
-}
-
-
-
-
-/*
- * dgap_intr()
- *
- * Driver interrupt handler.
- */
-static irqreturn_t dgap_intr(int irq, void *voidbrd)
-{
- struct board_t *brd = (struct board_t *) voidbrd;
-
- if (!brd) {
- APR(("Received interrupt (%d) with null board associated\n", irq));
- return IRQ_NONE;
- }
-
- /*
- * Check to make sure its for us.
- */
- if (brd->magic != DGAP_BOARD_MAGIC) {
- APR(("Received interrupt (%d) with a board pointer that wasn't ours!\n", irq));
- return IRQ_NONE;
- }
-
- brd->intr_count++;
-
- /*
- * Schedule tasklet to run at a better time.
- */
- tasklet_schedule(&brd->helper_tasklet);
- return IRQ_HANDLED;
-}
-
-
-/*
- * dgap_init_globals()
- *
- * This is where we initialize the globals from the static insmod
- * configuration variables. These are declared near the head of
- * this file.
- */
-static void dgap_init_globals(void)
-{
- int i = 0;
-
- dgap_rawreadok = rawreadok;
- dgap_trcbuf_size = trcbuf_size;
- dgap_debug = debug;
-
- for (i = 0; i < MAXBOARDS; i++) {
- dgap_Board[i] = NULL;
- }
-
- init_timer( &dgap_poll_timer );
-
- init_waitqueue_head(&dgap_dl_wait);
- dgap_dl_action = 0;
-}
-
-
-/************************************************************************
- *
- * Utility functions
- *
- ************************************************************************/
-
-
-/*
- * dgap_mbuf()
- *
- * Used to print to the message buffer during board init.
- */
-static void dgap_mbuf(struct board_t *brd, const char *fmt, ...) {
- va_list ap;
- char buf[1024];
- int i;
- unsigned long flags;
- size_t length;
-
- DGAP_LOCK(dgap_global_lock, flags);
-
- /* Format buf using fmt and arguments contained in ap. */
- va_start(ap, fmt);
- i = vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
-
- DPR((buf));
-
- if (!brd || !brd->msgbuf) {
- printk("%s", buf);
- DGAP_UNLOCK(dgap_global_lock, flags);
- return;
- }
-
- length = strlen(buf) + 1;
- if (brd->msgbuf - brd->msgbuf_head < length)
- length = brd->msgbuf - brd->msgbuf_head;
- memcpy(brd->msgbuf, buf, length);
- brd->msgbuf += length;
-
- DGAP_UNLOCK(dgap_global_lock, flags);
-}
-
-
-/*
- * dgap_ms_sleep()
- *
- * Put the driver to sleep for x ms's
- *
- * Returns 0 if timed out, !0 (showing signal) if interrupted by a signal.
- */
-int dgap_ms_sleep(ulong ms)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout((ms * HZ) / 1000);
- return (signal_pending(current));
-}
-
-
-
-/*
- * dgap_ioctl_name() : Returns a text version of each ioctl value.
- */
-char *dgap_ioctl_name(int cmd)
-{
- switch(cmd) {
-
- case TCGETA: return("TCGETA");
- case TCGETS: return("TCGETS");
- case TCSETA: return("TCSETA");
- case TCSETS: return("TCSETS");
- case TCSETAW: return("TCSETAW");
- case TCSETSW: return("TCSETSW");
- case TCSETAF: return("TCSETAF");
- case TCSETSF: return("TCSETSF");
- case TCSBRK: return("TCSBRK");
- case TCXONC: return("TCXONC");
- case TCFLSH: return("TCFLSH");
- case TIOCGSID: return("TIOCGSID");
-
- case TIOCGETD: return("TIOCGETD");
- case TIOCSETD: return("TIOCSETD");
- case TIOCGWINSZ: return("TIOCGWINSZ");
- case TIOCSWINSZ: return("TIOCSWINSZ");
-
- case TIOCMGET: return("TIOCMGET");
- case TIOCMSET: return("TIOCMSET");
- case TIOCMBIS: return("TIOCMBIS");
- case TIOCMBIC: return("TIOCMBIC");
-
- /* from digi.h */
- case DIGI_SETA: return("DIGI_SETA");
- case DIGI_SETAW: return("DIGI_SETAW");
- case DIGI_SETAF: return("DIGI_SETAF");
- case DIGI_SETFLOW: return("DIGI_SETFLOW");
- case DIGI_SETAFLOW: return("DIGI_SETAFLOW");
- case DIGI_GETFLOW: return("DIGI_GETFLOW");
- case DIGI_GETAFLOW: return("DIGI_GETAFLOW");
- case DIGI_GETA: return("DIGI_GETA");
- case DIGI_GEDELAY: return("DIGI_GEDELAY");
- case DIGI_SEDELAY: return("DIGI_SEDELAY");
- case DIGI_GETCUSTOMBAUD: return("DIGI_GETCUSTOMBAUD");
- case DIGI_SETCUSTOMBAUD: return("DIGI_SETCUSTOMBAUD");
- case TIOCMODG: return("TIOCMODG");
- case TIOCMODS: return("TIOCMODS");
- case TIOCSDTR: return("TIOCSDTR");
- case TIOCCDTR: return("TIOCCDTR");
-
- default: return("unknown");
- }
-}
diff --git a/drivers/staging/dgap/dgap_driver.h b/drivers/staging/dgap/dgap_driver.h
deleted file mode 100644
index 2f7a55a7e40d..000000000000
--- a/drivers/staging/dgap/dgap_driver.h
+++ /dev/null
@@ -1,620 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
- *
- *************************************************************************
- *
- * Driver includes
- *
- *************************************************************************/
-
-#ifndef __DGAP_DRIVER_H
-#define __DGAP_DRIVER_H
-
-#include <linux/version.h> /* To get the current Linux version */
-#include <linux/types.h> /* To pick up the varions Linux types */
-#include <linux/tty.h> /* To pick up the various tty structs/defines */
-#include <linux/interrupt.h> /* For irqreturn_t type */
-
-#include "dgap_types.h" /* Additional types needed by the Digi header files */
-#include "digi.h" /* Digi specific ioctl header */
-#include "dgap_kcompat.h" /* Kernel 2.4/2.6 compat includes */
-#include "dgap_sysfs.h" /* Support for SYSFS */
-
-/*************************************************************************
- *
- * Driver defines
- *
- *************************************************************************/
-
-/*
- * Driver identification, error and debugging statments
- *
- * In theory, you can change all occurrences of "digi" in the next
- * three lines, and the driver printk's will all automagically change.
- *
- * APR((fmt, args, ...)); Always prints message
- * DPR((fmt, args, ...)); Only prints if DGAP_TRACER is defined at
- * compile time and dgap_debug!=0
- */
-#define DG_NAME "dgap-1.3-16"
-#define DG_PART "40002347_C"
-
-#define PROCSTR "dgap" /* /proc entries */
-#define DEVSTR "/dev/dg/dgap" /* /dev entries */
-#define DRVSTR "dgap" /* Driver name string
- * displayed by APR */
-#define APR(args) do { PRINTF_TO_KMEM(args); printk(DRVSTR": "); printk args; \
- } while (0)
-#define RAPR(args) do { PRINTF_TO_KMEM(args); printk args; } while (0)
-
-#define TRC_TO_CONSOLE 1
-
-/*
- * Debugging levels can be set using debug insmod variable
- * They can also be compiled out completely.
- */
-
-#define DBG_INIT (dgap_debug & 0x01)
-#define DBG_BASIC (dgap_debug & 0x02)
-#define DBG_CORE (dgap_debug & 0x04)
-
-#define DBG_OPEN (dgap_debug & 0x08)
-#define DBG_CLOSE (dgap_debug & 0x10)
-#define DBG_READ (dgap_debug & 0x20)
-#define DBG_WRITE (dgap_debug & 0x40)
-
-#define DBG_IOCTL (dgap_debug & 0x80)
-
-#define DBG_PROC (dgap_debug & 0x100)
-#define DBG_PARAM (dgap_debug & 0x200)
-#define DBG_PSCAN (dgap_debug & 0x400)
-#define DBG_EVENT (dgap_debug & 0x800)
-
-#define DBG_DRAIN (dgap_debug & 0x1000)
-#define DBG_CARR (dgap_debug & 0x2000)
-
-#define DBG_MGMT (dgap_debug & 0x4000)
-
-
-#if defined(DGAP_TRACER)
-
-# if defined(TRC_TO_KMEM)
-/* Choose one: */
-# define TRC_ON_OVERFLOW_WRAP_AROUND
-# undef TRC_ON_OVERFLOW_SHIFT_BUFFER
-# endif //TRC_TO_KMEM
-
-# define TRC_MAXMSG 1024
-# define TRC_OVERFLOW "(OVERFLOW)"
-# define TRC_DTRC "/usr/bin/dtrc"
-
-#if defined TRC_TO_CONSOLE
-#define PRINTF_TO_CONSOLE(args) { printk(DRVSTR": "); printk args; }
-#else //!defined TRACE_TO_CONSOLE
-#define PRINTF_TO_CONSOLE(args)
-#endif
-
-#if defined TRC_TO_KMEM
-#define PRINTF_TO_KMEM(args) dgap_tracef args
-#else //!defined TRC_TO_KMEM
-#define PRINTF_TO_KMEM(args)
-#endif
-
-#define TRC(args) { PRINTF_TO_KMEM(args); PRINTF_TO_CONSOLE(args) }
-
-# define DPR_INIT(ARGS) if (DBG_INIT) TRC(ARGS)
-# define DPR_BASIC(ARGS) if (DBG_BASIC) TRC(ARGS)
-# define DPR_CORE(ARGS) if (DBG_CORE) TRC(ARGS)
-# define DPR_OPEN(ARGS) if (DBG_OPEN) TRC(ARGS)
-# define DPR_CLOSE(ARGS) if (DBG_CLOSE) TRC(ARGS)
-# define DPR_READ(ARGS) if (DBG_READ) TRC(ARGS)
-# define DPR_WRITE(ARGS) if (DBG_WRITE) TRC(ARGS)
-# define DPR_IOCTL(ARGS) if (DBG_IOCTL) TRC(ARGS)
-# define DPR_PROC(ARGS) if (DBG_PROC) TRC(ARGS)
-# define DPR_PARAM(ARGS) if (DBG_PARAM) TRC(ARGS)
-# define DPR_PSCAN(ARGS) if (DBG_PSCAN) TRC(ARGS)
-# define DPR_EVENT(ARGS) if (DBG_EVENT) TRC(ARGS)
-# define DPR_DRAIN(ARGS) if (DBG_DRAIN) TRC(ARGS)
-# define DPR_CARR(ARGS) if (DBG_CARR) TRC(ARGS)
-# define DPR_MGMT(ARGS) if (DBG_MGMT) TRC(ARGS)
-
-# define DPR(ARGS) if (dgap_debug) TRC(ARGS)
-# define P(X) dgap_tracef(#X "=%p\n", X)
-# define X(X) dgap_tracef(#X "=%x\n", X)
-
-#else//!defined DGAP_TRACER
-
-#define PRINTF_TO_KMEM(args)
-# define TRC(ARGS)
-# define DPR_INIT(ARGS)
-# define DPR_BASIC(ARGS)
-# define DPR_CORE(ARGS)
-# define DPR_OPEN(ARGS)
-# define DPR_CLOSE(ARGS)
-# define DPR_READ(ARGS)
-# define DPR_WRITE(ARGS)
-# define DPR_IOCTL(ARGS)
-# define DPR_PROC(ARGS)
-# define DPR_PARAM(ARGS)
-# define DPR_PSCAN(ARGS)
-# define DPR_EVENT(ARGS)
-# define DPR_DRAIN(ARGS)
-# define DPR_CARR(ARGS)
-# define DPR_MGMT(ARGS)
-
-# define DPR(args)
-
-#endif//DGAP_TRACER
-
-/* Number of boards we support at once. */
-#define MAXBOARDS 32
-#define MAXPORTS 224
-#define MAXTTYNAMELEN 200
-
-/* Our 3 magic numbers for our board, channel and unit structs */
-#define DGAP_BOARD_MAGIC 0x5c6df104
-#define DGAP_CHANNEL_MAGIC 0x6c6df104
-#define DGAP_UNIT_MAGIC 0x7c6df104
-
-/* Serial port types */
-#define DGAP_SERIAL 0
-#define DGAP_PRINT 1
-
-#define SERIAL_TYPE_NORMAL 1
-
-/* 4 extra for alignment play space */
-#define WRITEBUFLEN ((4096) + 4)
-#define MYFLIPLEN N_TTY_BUF_SIZE
-
-#define SBREAK_TIME 0x25
-#define U2BSIZE 0x400
-
-#define dgap_jiffies_from_ms(a) (((a) * HZ) / 1000)
-
-/*
- * Our major for the mgmt devices.
- *
- * We can use 22, because Digi was allocated 22 and 23 for the epca driver.
- * 22 has now become obsolete now that the "cu" devices have
- * been removed from 2.6.
- * Also, this *IS* the epca driver, just PCI only now.
- */
-#ifndef DIGI_DGAP_MAJOR
-# define DIGI_DGAP_MAJOR 22
-#endif
-
-/*
- * The parameters we use to define the periods of the moving averages.
- */
-#define MA_PERIOD (HZ / 10)
-#define SMA_DUR (1 * HZ)
-#define EMA_DUR (1 * HZ)
-#define SMA_NPERIODS (SMA_DUR / MA_PERIOD)
-#define EMA_NPERIODS (EMA_DUR / MA_PERIOD)
-
-/*
- * Define a local default termios struct. All ports will be created
- * with this termios initially. This is the same structure that is defined
- * as the default in tty_io.c with the same settings overriden as in serial.c
- *
- * In short, this should match the internal serial ports' defaults.
- */
-#define DEFAULT_IFLAGS (ICRNL | IXON)
-#define DEFAULT_OFLAGS (OPOST | ONLCR)
-#define DEFAULT_CFLAGS (B9600 | CS8 | CREAD | HUPCL | CLOCAL)
-#define DEFAULT_LFLAGS (ISIG | ICANON | ECHO | ECHOE | ECHOK | \
- ECHOCTL | ECHOKE | IEXTEN)
-
-#ifndef _POSIX_VDISABLE
-#define _POSIX_VDISABLE '\0'
-#endif
-
-#define SNIFF_MAX 65536 /* Sniff buffer size (2^n) */
-#define SNIFF_MASK (SNIFF_MAX - 1) /* Sniff wrap mask */
-
-#define VPDSIZE (512)
-
-/*
- * Lock function/defines.
- * Makes spotting lock/unlock locations easier.
- */
-# define DGAP_SPINLOCK_INIT(x) spin_lock_init(&(x))
-# define DGAP_LOCK(x,y) spin_lock_irqsave(&(x), y)
-# define DGAP_UNLOCK(x,y) spin_unlock_irqrestore(&(x), y)
-# define DGAP_TRYLOCK(x,y) spin_trylock(&(x))
-
-/*
- * All the possible states the driver can be while being loaded.
- */
-enum {
- DRIVER_INITIALIZED = 0,
- DRIVER_NEED_CONFIG_LOAD,
- DRIVER_REQUESTED_CONFIG,
- DRIVER_READY
-};
-
-/*
- * All the possible states the board can be while booting up.
- */
-enum {
- BOARD_FAILED = 0,
- CONFIG_NOT_FOUND,
- BOARD_FOUND,
- NEED_RESET,
- FINISHED_RESET,
- NEED_CONFIG,
- FINISHED_CONFIG,
- NEED_DEVICE_CREATION,
- REQUESTED_DEVICE_CREATION,
- FINISHED_DEVICE_CREATION,
- NEED_BIOS_LOAD,
- REQUESTED_BIOS,
- WAIT_BIOS_LOAD,
- FINISHED_BIOS_LOAD,
- NEED_FEP_LOAD,
- REQUESTED_FEP,
- WAIT_FEP_LOAD,
- FINISHED_FEP_LOAD,
- NEED_PROC_CREATION,
- FINISHED_PROC_CREATION,
- BOARD_READY
-};
-
-/*
- * All the possible states that a requested concentrator image can be in.
- */
-enum {
- NO_PENDING_CONCENTRATOR_REQUESTS = 0,
- NEED_CONCENTRATOR,
- REQUESTED_CONCENTRATOR
-};
-
-extern char *dgap_state_text[];
-extern char *dgap_driver_state_text[];
-
-
-/*
- * Modem line constants are defined as macros because DSR and
- * DCD are swapable using the ditty altpin option.
- */
-#define D_CD(ch) ch->ch_cd /* Carrier detect */
-#define D_DSR(ch) ch->ch_dsr /* Data set ready */
-#define D_RTS(ch) DM_RTS /* Request to send */
-#define D_CTS(ch) DM_CTS /* Clear to send */
-#define D_RI(ch) DM_RI /* Ring indicator */
-#define D_DTR(ch) DM_DTR /* Data terminal ready */
-
-
-/*************************************************************************
- *
- * Structures and closely related defines.
- *
- *************************************************************************/
-
-
-/*
- * A structure to hold a statistics counter. We also
- * compute moving averages for this counter.
- */
-struct macounter
-{
- u32 cnt; /* Total count */
- ulong accum; /* Acuumulator per period */
- ulong sma; /* Simple moving average */
- ulong ema; /* Exponential moving average */
-};
-
-
-/************************************************************************
- * Device flag definitions for bd_flags.
- ************************************************************************/
-#define BD_FEP5PLUS 0x0001 /* Supports FEP5 Plus commands */
-#define BD_HAS_VPD 0x0002 /* Board has VPD info available */
-
-
-/*
- * Per-board information
- */
-struct board_t
-{
- int magic; /* Board Magic number. */
- int boardnum; /* Board number: 0-3 */
- int firstminor; /* First minor, e.g. 0, 30, 60 */
-
- int type; /* Type of board */
- char *name; /* Product Name */
- struct pci_dev *pdev; /* Pointer to the pci_dev struct */
- u16 vendor; /* PCI vendor ID */
- u16 device; /* PCI device ID */
- u16 subvendor; /* PCI subsystem vendor ID */
- u16 subdevice; /* PCI subsystem device ID */
- uchar rev; /* PCI revision ID */
- uint pci_bus; /* PCI bus value */
- uint pci_slot; /* PCI slot value */
- u16 maxports; /* MAX ports this board can handle */
- uchar vpd[VPDSIZE]; /* VPD of board, if found */
- u32 bd_flags; /* Board flags */
-
- spinlock_t bd_lock; /* Used to protect board */
-
- u32 state; /* State of card. */
- wait_queue_head_t state_wait; /* Place to sleep on for state change */
-
- struct tasklet_struct helper_tasklet; /* Poll helper tasklet */
-
- u32 wait_for_bios;
- u32 wait_for_fep;
-
- struct cnode * bd_config; /* Config of board */
-
- u16 nasync; /* Number of ports on card */
-
- u32 use_interrupts; /* Should we be interrupt driven? */
- ulong irq; /* Interrupt request number */
- ulong intr_count; /* Count of interrupts */
- u32 intr_used; /* Non-zero if using interrupts */
- u32 intr_running; /* Non-zero if FEP knows its doing interrupts */
-
- ulong port; /* Start of base io port of the card */
- ulong port_end; /* End of base io port of the card */
- ulong membase; /* Start of base memory of the card */
- ulong membase_end; /* End of base memory of the card */
-
- uchar *re_map_port; /* Remapped io port of the card */
- uchar *re_map_membase;/* Remapped memory of the card */
-
- uchar runwait; /* # Processes waiting for FEP */
- uchar inhibit_poller; /* Tells the poller to leave us alone */
-
- struct channel_t *channels[MAXPORTS]; /* array of pointers to our channels. */
-
- struct tty_driver *SerialDriver;
- char SerialName[200];
- struct tty_driver *PrintDriver;
- char PrintName[200];
-
- u32 dgap_Major_Serial_Registered;
- u32 dgap_Major_TransparentPrint_Registered;
-
- u32 dgap_Serial_Major;
- u32 dgap_TransparentPrint_Major;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
- u32 TtyRefCnt;
-#endif
-
- struct bs_t *bd_bs; /* Base structure pointer */
-
- char *flipbuf; /* Our flip buffer, alloced if board is found */
- char *flipflagbuf; /* Our flip flag buffer, alloced if board is found */
-
- u16 dpatype; /* The board "type", as defined by DPA */
- u16 dpastatus; /* The board "status", as defined by DPA */
- wait_queue_head_t kme_wait; /* Needed for DPA support */
-
- u32 conc_dl_status; /* Status of any pending conc download */
- /*
- * Mgmt data.
- */
- char *msgbuf_head;
- char *msgbuf;
-};
-
-
-
-/************************************************************************
- * Unit flag definitions for un_flags.
- ************************************************************************/
-#define UN_ISOPEN 0x0001 /* Device is open */
-#define UN_CLOSING 0x0002 /* Line is being closed */
-#define UN_IMM 0x0004 /* Service immediately */
-#define UN_BUSY 0x0008 /* Some work this channel */
-#define UN_BREAKI 0x0010 /* Input break received */
-#define UN_PWAIT 0x0020 /* Printer waiting for terminal */
-#define UN_TIME 0x0040 /* Waiting on time */
-#define UN_EMPTY 0x0080 /* Waiting output queue empty */
-#define UN_LOW 0x0100 /* Waiting output low water mark*/
-#define UN_EXCL_OPEN 0x0200 /* Open for exclusive use */
-#define UN_WOPEN 0x0400 /* Device waiting for open */
-#define UN_WIOCTL 0x0800 /* Device waiting for open */
-#define UN_HANGUP 0x8000 /* Carrier lost */
-
-struct device;
-
-/************************************************************************
- * Structure for terminal or printer unit.
- ************************************************************************/
-struct un_t {
- int magic; /* Unit Magic Number. */
- struct channel_t *un_ch;
- u32 un_time;
- u32 un_type;
- u32 un_open_count; /* Counter of opens to port */
- struct tty_struct *un_tty;/* Pointer to unit tty structure */
- u32 un_flags; /* Unit flags */
- wait_queue_head_t un_flags_wait; /* Place to sleep to wait on unit */
- u32 un_dev; /* Minor device number */
- tcflag_t un_oflag; /* oflags being done on board */
- tcflag_t un_lflag; /* lflags being done on board */
- struct device *un_sysfs;
-};
-
-
-/************************************************************************
- * Device flag definitions for ch_flags.
- ************************************************************************/
-#define CH_PRON 0x0001 /* Printer on string */
-#define CH_OUT 0x0002 /* Dial-out device open */
-#define CH_STOP 0x0004 /* Output is stopped */
-#define CH_STOPI 0x0008 /* Input is stopped */
-#define CH_CD 0x0010 /* Carrier is present */
-#define CH_FCAR 0x0020 /* Carrier forced on */
-
-#define CH_RXBLOCK 0x0080 /* Enable rx blocked flag */
-#define CH_WLOW 0x0100 /* Term waiting low event */
-#define CH_WEMPTY 0x0200 /* Term waiting empty event */
-#define CH_RENABLE 0x0400 /* Buffer just emptied */
-#define CH_RACTIVE 0x0800 /* Process active in xxread() */
-#define CH_RWAIT 0x1000 /* Process waiting in xxread() */
-#define CH_BAUD0 0x2000 /* Used for checking B0 transitions */
-#define CH_HANGUP 0x8000 /* Hangup received */
-
-/*
- * Definitions for ch_sniff_flags
- */
-#define SNIFF_OPEN 0x1
-#define SNIFF_WAIT_DATA 0x2
-#define SNIFF_WAIT_SPACE 0x4
-
-
-/************************************************************************
- * Channel information structure.
- ************************************************************************/
-struct channel_t {
- int magic; /* Channel Magic Number */
- struct bs_t *ch_bs; /* Base structure pointer */
- struct cm_t *ch_cm; /* Command queue pointer */
- struct board_t *ch_bd; /* Board structure pointer */
- unsigned char *ch_vaddr; /* FEP memory origin */
- unsigned char *ch_taddr; /* Write buffer origin */
- unsigned char *ch_raddr; /* Read buffer origin */
- struct digi_t ch_digi; /* Transparent Print structure */
- struct un_t ch_tun; /* Terminal unit info */
- struct un_t ch_pun; /* Printer unit info */
-
- spinlock_t ch_lock; /* provide for serialization */
- wait_queue_head_t ch_flags_wait;
-
- u32 pscan_state;
- uchar pscan_savechar;
-
- u32 ch_portnum; /* Port number, 0 offset. */
- u32 ch_open_count; /* open count */
- u32 ch_flags; /* Channel flags */
-
-
- u32 ch_close_delay; /* How long we should drop RTS/DTR for */
-
- u32 ch_cpstime; /* Time for CPS calculations */
-
- tcflag_t ch_c_iflag; /* channel iflags */
- tcflag_t ch_c_cflag; /* channel cflags */
- tcflag_t ch_c_oflag; /* channel oflags */
- tcflag_t ch_c_lflag; /* channel lflags */
-
- u16 ch_fepiflag; /* FEP tty iflags */
- u16 ch_fepcflag; /* FEP tty cflags */
- u16 ch_fepoflag; /* FEP tty oflags */
- u16 ch_wopen; /* Waiting for open process cnt */
- u16 ch_tstart; /* Transmit buffer start */
- u16 ch_tsize; /* Transmit buffer size */
- u16 ch_rstart; /* Receive buffer start */
- u16 ch_rsize; /* Receive buffer size */
- u16 ch_rdelay; /* Receive delay time */
-
- u16 ch_tlw; /* Our currently set low water mark */
-
- u16 ch_cook; /* Output character mask */
-
- uchar ch_card; /* Card channel is on */
- uchar ch_stopc; /* Stop character */
- uchar ch_startc; /* Start character */
-
- uchar ch_mostat; /* FEP output modem status */
- uchar ch_mistat; /* FEP input modem status */
- uchar ch_mforce; /* Modem values to be forced */
- uchar ch_mval; /* Force values */
- uchar ch_fepstopc; /* FEP stop character */
- uchar ch_fepstartc; /* FEP start character */
-
- uchar ch_astopc; /* Auxiliary Stop character */
- uchar ch_astartc; /* Auxiliary Start character */
- uchar ch_fepastopc; /* Auxiliary FEP stop char */
- uchar ch_fepastartc; /* Auxiliary FEP start char */
-
- uchar ch_hflow; /* FEP hardware handshake */
- uchar ch_dsr; /* stores real dsr value */
- uchar ch_cd; /* stores real cd value */
- uchar ch_tx_win; /* channel tx buffer window */
- uchar ch_rx_win; /* channel rx buffer window */
- uint ch_custom_speed; /* Custom baud, if set */
- uint ch_baud_info; /* Current baud info for /proc output */
- ulong ch_rxcount; /* total of data received so far */
- ulong ch_txcount; /* total of data transmitted so far */
- ulong ch_err_parity; /* Count of parity errors on channel */
- ulong ch_err_frame; /* Count of framing errors on channel */
- ulong ch_err_break; /* Count of breaks on channel */
- ulong ch_err_overrun; /* Count of overruns on channel */
-
- uint ch_sniff_in;
- uint ch_sniff_out;
- char *ch_sniff_buf; /* Sniff buffer for proc */
- ulong ch_sniff_flags; /* Channel flags */
- wait_queue_head_t ch_sniff_wait;
-};
-
-
-/*************************************************************************
- *
- * Prototypes for non-static functions used in more than one module
- *
- *************************************************************************/
-
-extern int dgap_ms_sleep(ulong ms);
-extern char *dgap_ioctl_name(int cmd);
-extern void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len);
-extern void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len);
-extern void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len);
-extern void dgap_do_config_load(uchar __user *uaddr, int len);
-extern int dgap_after_config_loaded(void);
-extern int dgap_finalize_board_init(struct board_t *brd);
-
-/*
- * Our Global Variables.
- */
-extern int dgap_driver_state; /* The state of the driver */
-extern int dgap_debug; /* Debug variable */
-extern int dgap_rawreadok; /* Set if user wants rawreads */
-extern int dgap_poll_tick; /* Poll interval - 20 ms */
-extern spinlock_t dgap_global_lock; /* Driver global spinlock */
-extern uint dgap_NumBoards; /* Total number of boards */
-extern struct board_t *dgap_Board[MAXBOARDS]; /* Array of board structs */
-extern ulong dgap_poll_counter; /* Times the poller has run */
-extern char *dgap_config_buf; /* The config file buffer */
-extern spinlock_t dgap_dl_lock; /* Downloader spinlock */
-extern wait_queue_head_t dgap_dl_wait; /* Wait queue for downloader */
-extern int dgap_dl_action; /* Action flag for downloader */
-extern int dgap_registerttyswithsysfs; /* Should we register the */
- /* ttys with sysfs or not */
-
-/*
- * Global functions declared in dgap_fep5.c, but must be hidden from
- * user space programs.
- */
-extern void dgap_poll_tasklet(unsigned long data);
-extern void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, uchar byte2, uint ncmds);
-extern void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds);
-extern void dgap_wmove(struct channel_t *ch, char *buf, uint cnt);
-extern int dgap_param(struct tty_struct *tty);
-extern void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, unsigned char *fbuf, int *len);
-extern uint dgap_get_custom_baud(struct channel_t *ch);
-extern void dgap_firmware_reset_port(struct channel_t *ch);
-
-#endif
diff --git a/drivers/staging/dgap/dgap_fep5.c b/drivers/staging/dgap/dgap_fep5.c
deleted file mode 100644
index f75831a422e8..000000000000
--- a/drivers/staging/dgap/dgap_fep5.c
+++ /dev/null
@@ -1,1938 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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.
- *
- * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
- *
- * This is shared code between Digi's CVS archive and the
- * Linux Kernel sources.
- * Changing the source just for reformatting needlessly breaks
- * our CVS diff history.
- *
- * Send any bug fixes/changes to: Eng.Linux at digi dot com.
- * Thank you.
- *
- * $Id: dgap_fep5.c,v 1.2 2011/06/21 10:35:40 markh Exp $
- */
-
-
-#include <linux/kernel.h>
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/delay.h> /* For udelay */
-#include <asm/uaccess.h> /* For copy_from_user/copy_to_user */
-#include <linux/tty.h>
-#include <linux/tty_flip.h> /* For tty_schedule_flip */
-#include <linux/slab.h>
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
-#include <linux/sched.h>
-#endif
-
-#include "dgap_driver.h"
-#include "dgap_pci.h"
-#include "dgap_fep5.h"
-#include "dgap_tty.h"
-#include "dgap_conf.h"
-#include "dgap_parse.h"
-#include "dgap_trace.h"
-
-/*
- * Our function prototypes
- */
-static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds);
-static int dgap_event(struct board_t *bd);
-
-/*
- * internal variables
- */
-static uint dgap_count = 500;
-
-
-/*
- * Loads the dgap.conf config file from the user.
- */
-void dgap_do_config_load(uchar __user *uaddr, int len)
-{
- int orig_len = len;
- char *to_addr;
- uchar __user *from_addr = uaddr;
- char buf[U2BSIZE];
- int n;
-
- to_addr = dgap_config_buf = kzalloc(len + 1, GFP_ATOMIC);
- if (!dgap_config_buf) {
- DPR_INIT(("dgap_do_config_load - unable to allocate memory for file\n"));
- dgap_driver_state = DRIVER_NEED_CONFIG_LOAD;
- return;
- }
-
- n = U2BSIZE;
- while (len) {
-
- if (n > len)
- n = len;
-
- if (copy_from_user((char *) &buf, from_addr, n) == -1 )
- return;
-
- /* Copy data from buffer to kernel memory */
- memcpy(to_addr, buf, n);
-
- /* increment counts */
- len -= n;
- to_addr += n;
- from_addr += n;
- n = U2BSIZE;
- }
-
- dgap_config_buf[orig_len] = '\0';
-
- to_addr = dgap_config_buf;
- dgap_parsefile(&to_addr, TRUE);
-
- DPR_INIT(("dgap_config_load() finish\n"));
-
- return;
-}
-
-
-int dgap_after_config_loaded(void)
-{
- int i = 0;
- int rc = 0;
-
- /*
- * Register our ttys, now that we have the config loaded.
- */
- for (i = 0; i < dgap_NumBoards; ++i) {
-
- /*
- * Initialize KME waitqueues...
- */
- init_waitqueue_head(&(dgap_Board[i]->kme_wait));
-
- /*
- * allocate flip buffer for board.
- */
- dgap_Board[i]->flipbuf = kzalloc(MYFLIPLEN, GFP_ATOMIC);
- dgap_Board[i]->flipflagbuf = kzalloc(MYFLIPLEN, GFP_ATOMIC);
- }
-
- return rc;
-}
-
-
-
-/*=======================================================================
- *
- * usertoboard - copy from user space to board space.
- *
- *=======================================================================*/
-static int dgap_usertoboard(struct board_t *brd, char *to_addr, char __user *from_addr, int len)
-{
- char buf[U2BSIZE];
- int n = U2BSIZE;
-
- if (!brd || brd->magic != DGAP_BOARD_MAGIC)
- return -EFAULT;
-
- while (len) {
- if (n > len)
- n = len;
-
- if (copy_from_user((char *) &buf, from_addr, n) == -1 ) {
- return -EFAULT;
- }
-
- /* Copy data from buffer to card memory */
- memcpy_toio(to_addr, buf, n);
-
- /* increment counts */
- len -= n;
- to_addr += n;
- from_addr += n;
- n = U2BSIZE;
- }
- return 0;
-}
-
-
-/*
- * Copies the BIOS code from the user to the board,
- * and starts the BIOS running.
- */
-void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len)
-{
- uchar *addr;
- uint offset;
- int i;
-
- if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
- return;
-
- DPR_INIT(("dgap_do_bios_load() start\n"));
-
- addr = brd->re_map_membase;
-
- /*
- * clear POST area
- */
- for (i = 0; i < 16; i++)
- writeb(0, addr + POSTAREA + i);
-
- /*
- * Download bios
- */
- offset = 0x1000;
- if (dgap_usertoboard(brd, addr + offset, ubios, len) == -1 ) {
- brd->state = BOARD_FAILED;
- brd->dpastatus = BD_NOFEP;
- return;
- }
-
- writel(0x0bf00401, addr);
- writel(0, (addr + 4));
-
- /* Clear the reset, and change states. */
- writeb(FEPCLR, brd->re_map_port);
- brd->state = WAIT_BIOS_LOAD;
-}
-
-
-/*
- * Checks to see if the BIOS completed running on the card.
- */
-static void dgap_do_wait_for_bios(struct board_t *brd)
-{
- uchar *addr;
- u16 word;
-
- if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
- return;
-
- addr = brd->re_map_membase;
- word = readw(addr + POSTAREA);
-
- /* Check to see if BIOS thinks board is good. (GD). */
- if (word == *(u16 *) "GD") {
- DPR_INIT(("GOT GD in memory, moving states.\n"));
- brd->state = FINISHED_BIOS_LOAD;
- return;
- }
-
- /* Give up on board after too long of time taken */
- if (brd->wait_for_bios++ > 5000) {
- u16 err1 = readw(addr + SEQUENCE);
- u16 err2 = readw(addr + ERROR);
- APR(("***WARNING*** %s failed diagnostics. Error #(%x,%x).\n",
- brd->name, err1, err2));
- brd->state = BOARD_FAILED;
- brd->dpastatus = BD_NOFEP;
- }
-}
-
-
-/*
- * Copies the FEP code from the user to the board,
- * and starts the FEP running.
- */
-void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len)
-{
- uchar *addr;
- uint offset;
-
- if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
- return;
-
- addr = brd->re_map_membase;
-
- DPR_INIT(("dgap_do_fep_load() for board %s : start\n", brd->name));
-
- /*
- * Download FEP
- */
- offset = 0x1000;
- if (dgap_usertoboard(brd, addr + offset, ufep, len) == -1 ) {
- brd->state = BOARD_FAILED;
- brd->dpastatus = BD_NOFEP;
- return;
- }
-
- /*
- * If board is a concentrator product, we need to give
- * it its config string describing how the concentrators look.
- */
- if ((brd->type == PCX) || (brd->type == PEPC)) {
- uchar string[100];
- uchar *config, *xconfig;
- int i = 0;
-
- xconfig = dgap_create_config_string(brd, string);
-
- /* Write string to board memory */
- config = addr + CONFIG;
- for (; i < CONFIGSIZE; i++, config++, xconfig++) {
- writeb(*xconfig, config);
- if ((*xconfig & 0xff) == 0xff)
- break;
- }
- }
-
- writel(0xbfc01004, (addr + 0xc34));
- writel(0x3, (addr + 0xc30));
-
- /* change states. */
- brd->state = WAIT_FEP_LOAD;
-
- DPR_INIT(("dgap_do_fep_load() for board %s : finish\n", brd->name));
-
-}
-
-
-/*
- * Waits for the FEP to report thats its ready for us to use.
- */
-static void dgap_do_wait_for_fep(struct board_t *brd)
-{
- uchar *addr;
- u16 word;
-
- if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
- return;
-
- addr = brd->re_map_membase;
-
- DPR_INIT(("dgap_do_wait_for_fep() for board %s : start. addr: %p\n", brd->name, addr));
-
- word = readw(addr + FEPSTAT);
-
- /* Check to see if FEP is up and running now. */
- if (word == *(u16 *) "OS") {
- DPR_INIT(("GOT OS in memory for board %s, moving states.\n", brd->name));
- brd->state = FINISHED_FEP_LOAD;
-
- /*
- * Check to see if the board can support FEP5+ commands.
- */
- word = readw(addr + FEP5_PLUS);
- if (word == *(u16 *) "5A") {
- DPR_INIT(("GOT 5A in memory for board %s, board supports extended FEP5 commands.\n", brd->name));
- brd->bd_flags |= BD_FEP5PLUS;
- }
-
- return;
- }
-
- /* Give up on board after too long of time taken */
- if (brd->wait_for_fep++ > 5000) {
- u16 err1 = readw(addr + SEQUENCE);
- u16 err2 = readw(addr + ERROR);
- APR(("***WARNING*** FEPOS for %s not functioning. Error #(%x,%x).\n",
- brd->name, err1, err2));
- brd->state = BOARD_FAILED;
- brd->dpastatus = BD_NOFEP;
- }
-
- DPR_INIT(("dgap_do_wait_for_fep() for board %s : finish\n", brd->name));
-}
-
-
-/*
- * Physically forces the FEP5 card to reset itself.
- */
-static void dgap_do_reset_board(struct board_t *brd)
-{
- uchar check;
- u32 check1;
- u32 check2;
- int i = 0;
-
- if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase || !brd->re_map_port) {
- DPR_INIT(("dgap_do_reset_board() start. bad values. brd: %p mem: %p io: %p\n",
- brd, brd ? brd->re_map_membase : 0, brd ? brd->re_map_port : 0));
- return;
- }
-
- DPR_INIT(("dgap_do_reset_board() start. io: %p\n", brd->re_map_port));
-
- /* FEPRST does not vary among supported boards */
- writeb(FEPRST, brd->re_map_port);
-
- for (i = 0; i <= 1000; i++) {
- check = readb(brd->re_map_port) & 0xe;
- if (check == FEPRST)
- break;
- udelay(10);
-
- }
- if (i > 1000) {
- APR(("*** WARNING *** Board not resetting... Failing board.\n"));
- brd->state = BOARD_FAILED;
- brd->dpastatus = BD_NOFEP;
- goto failed;
- }
-
- /*
- * Make sure there really is memory out there.
- */
- writel(0xa55a3cc3, (brd->re_map_membase + LOWMEM));
- writel(0x5aa5c33c, (brd->re_map_membase + HIGHMEM));
- check1 = readl(brd->re_map_membase + LOWMEM);
- check2 = readl(brd->re_map_membase + HIGHMEM);
-
- if ((check1 != 0xa55a3cc3) || (check2 != 0x5aa5c33c)) {
- APR(("*** Warning *** No memory at %p for board.\n", brd->re_map_membase));
- brd->state = BOARD_FAILED;
- brd->dpastatus = BD_NOFEP;
- goto failed;
- }
-
- if (brd->state != BOARD_FAILED)
- brd->state = FINISHED_RESET;
-
-failed:
- DPR_INIT(("dgap_do_reset_board() finish\n"));
-}
-
-
-/*
- * Sends a concentrator image into the FEP5 board.
- */
-void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len)
-{
- char *vaddr;
- u16 offset = 0;
- struct downld_t *to_dp;
-
- if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
- return;
-
- vaddr = brd->re_map_membase;
-
- offset = readw((u16 *) (vaddr + DOWNREQ));
- to_dp = (struct downld_t *) (vaddr + (int) offset);
-
- /*
- * The image was already read into kernel space,
- * we do NOT need a user space read here
- */
- memcpy_toio((char *) to_dp, uaddr, sizeof(struct downld_t));
-
- /* Tell card we have data for it */
- writew(0, vaddr + (DOWNREQ));
-
- brd->conc_dl_status = NO_PENDING_CONCENTRATOR_REQUESTS;
-}
-
-
-#define EXPANSION_ROM_SIZE (64 * 1024)
-#define FEP5_ROM_MAGIC (0xFEFFFFFF)
-
-static void dgap_get_vpd(struct board_t *brd)
-{
- u32 magic;
- u32 base_offset;
- u16 rom_offset;
- u16 vpd_offset;
- u16 image_length;
- u16 i;
- uchar byte1;
- uchar byte2;
-
- /*
- * Poke the magic number at the PCI Rom Address location.
- * If VPD is supported, the value read from that address
- * will be non-zero.
- */
- magic = FEP5_ROM_MAGIC;
- pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
- pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic);
-
- /* VPD not supported, bail */
- if (!magic)
- return;
-
- /*
- * To get to the OTPROM memory, we have to send the boards base
- * address or'ed with 1 into the PCI Rom Address location.
- */
- magic = brd->membase | 0x01;
- pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
- pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic);
-
- byte1 = readb(brd->re_map_membase);
- byte2 = readb(brd->re_map_membase + 1);
-
- /*
- * If the board correctly swapped to the OTPROM memory,
- * the first 2 bytes (header) should be 0x55, 0xAA
- */
- if (byte1 == 0x55 && byte2 == 0xAA) {
-
- base_offset = 0;
-
- /*
- * We have to run through all the OTPROM memory looking
- * for the VPD offset.
- */
- while (base_offset <= EXPANSION_ROM_SIZE) {
-
- /*
- * Lots of magic numbers here.
- *
- * The VPD offset is located inside the ROM Data Structure.
- * We also have to remember the length of each
- * ROM Data Structure, so we can "hop" to the next
- * entry if the VPD isn't in the current
- * ROM Data Structure.
- */
- rom_offset = readw(brd->re_map_membase + base_offset + 0x18);
- image_length = readw(brd->re_map_membase + rom_offset + 0x10) * 512;
- vpd_offset = readw(brd->re_map_membase + rom_offset + 0x08);
-
- /* Found the VPD entry */
- if (vpd_offset)
- break;
-
- /* We didn't find a VPD entry, go to next ROM entry. */
- base_offset += image_length;
-
- byte1 = readb(brd->re_map_membase + base_offset);
- byte2 = readb(brd->re_map_membase + base_offset + 1);
-
- /*
- * If the new ROM offset doesn't have 0x55, 0xAA
- * as its header, we have run out of ROM.
- */
- if (byte1 != 0x55 || byte2 != 0xAA)
- break;
- }
-
- /*
- * If we have a VPD offset, then mark the board
- * as having a valid VPD, and copy VPDSIZE (512) bytes of
- * that VPD to the buffer we have in our board structure.
- */
- if (vpd_offset) {
- brd->bd_flags |= BD_HAS_VPD;
- for (i = 0; i < VPDSIZE; i++)
- brd->vpd[i] = readb(brd->re_map_membase + vpd_offset + i);
- }
- }
-
- /*
- * We MUST poke the magic number at the PCI Rom Address location again.
- * This makes the card report the regular board memory back to us,
- * rather than the OTPROM memory.
- */
- magic = FEP5_ROM_MAGIC;
- pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
-}
-
-
-/*
- * Our board poller function.
- */
-void dgap_poll_tasklet(unsigned long data)
-{
- struct board_t *bd = (struct board_t *) data;
- ulong lock_flags;
- ulong lock_flags2;
- char *vaddr;
- u16 head, tail;
- u16 *chk_addr;
- u16 check = 0;
-
- if (!bd || (bd->magic != DGAP_BOARD_MAGIC)) {
- APR(("dgap_poll_tasklet() - NULL or bad bd.\n"));
- return;
- }
-
- if (bd->inhibit_poller)
- return;
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
-
- vaddr = bd->re_map_membase;
-
- /*
- * If board is ready, parse deeper to see if there is anything to do.
- */
- if (bd->state == BOARD_READY) {
-
- struct ev_t *eaddr = NULL;
-
- if (!bd->re_map_membase) {
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return;
- }
- if (!bd->re_map_port) {
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return;
- }
-
- if (!bd->nasync) {
- goto out;
- }
-
- /*
- * If this is a CX or EPCX, we need to see if the firmware
- * is requesting a concentrator image from us.
- */
- if ((bd->type == PCX) || (bd->type == PEPC)) {
- chk_addr = (u16 *) (vaddr + DOWNREQ);
- check = readw(chk_addr);
- /* Nonzero if FEP is requesting concentrator image. */
- if (check) {
- if (bd->conc_dl_status == NO_PENDING_CONCENTRATOR_REQUESTS)
- bd->conc_dl_status = NEED_CONCENTRATOR;
- /*
- * Signal downloader, its got some work to do.
- */
- DGAP_LOCK(dgap_dl_lock, lock_flags2);
- if (dgap_dl_action != 1) {
- dgap_dl_action = 1;
- wake_up_interruptible(&dgap_dl_wait);
- }
- DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
-
- }
- }
-
- eaddr = (struct ev_t *) (vaddr + EVBUF);
-
- /* Get our head and tail */
- head = readw(&(eaddr->ev_head));
- tail = readw(&(eaddr->ev_tail));
-
- /*
- * If there is an event pending. Go service it.
- */
- if (head != tail) {
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- dgap_event(bd);
- DGAP_LOCK(bd->bd_lock, lock_flags);
- }
-
-out:
- /*
- * If board is doing interrupts, ACK the interrupt.
- */
- if (bd && bd->intr_running) {
- readb(bd->re_map_port + 2);
- }
-
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return;
- }
-
- /* Our state machine to get the board up and running */
-
- /* Reset board */
- if (bd->state == NEED_RESET) {
-
- /* Get VPD info */
- dgap_get_vpd(bd);
-
- dgap_do_reset_board(bd);
- }
-
- /* Move to next state */
- if (bd->state == FINISHED_RESET) {
- bd->state = NEED_CONFIG;
- }
-
- if (bd->state == NEED_CONFIG) {
- /*
- * Match this board to a config the user created for us.
- */
- bd->bd_config = dgap_find_config(bd->type, bd->pci_bus, bd->pci_slot);
-
- /*
- * Because the 4 port Xr products share the same PCI ID
- * as the 8 port Xr products, if we receive a NULL config
- * back, and this is a PAPORT8 board, retry with a
- * PAPORT4 attempt as well.
- */
- if (bd->type == PAPORT8 && !bd->bd_config) {
- bd->bd_config = dgap_find_config(PAPORT4, bd->pci_bus, bd->pci_slot);
- }
-
- /*
- * Register the ttys (if any) into the kernel.
- */
- if (bd->bd_config) {
- bd->state = FINISHED_CONFIG;
- }
- else {
- bd->state = CONFIG_NOT_FOUND;
- }
- }
-
- /* Move to next state */
- if (bd->state == FINISHED_CONFIG) {
- bd->state = NEED_DEVICE_CREATION;
- }
-
- /* Move to next state */
- if (bd->state == NEED_DEVICE_CREATION) {
- /*
- * Signal downloader, its got some work to do.
- */
- DGAP_LOCK(dgap_dl_lock, lock_flags2);
- if (dgap_dl_action != 1) {
- dgap_dl_action = 1;
- wake_up_interruptible(&dgap_dl_wait);
- }
- DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
- }
-
- /* Move to next state */
- if (bd->state == FINISHED_DEVICE_CREATION) {
- bd->state = NEED_BIOS_LOAD;
- }
-
- /* Move to next state */
- if (bd->state == NEED_BIOS_LOAD) {
- /*
- * Signal downloader, its got some work to do.
- */
- DGAP_LOCK(dgap_dl_lock, lock_flags2);
- if (dgap_dl_action != 1) {
- dgap_dl_action = 1;
- wake_up_interruptible(&dgap_dl_wait);
- }
- DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
- }
-
- /* Wait for BIOS to test board... */
- if (bd->state == WAIT_BIOS_LOAD) {
- dgap_do_wait_for_bios(bd);
- }
-
- /* Move to next state */
- if (bd->state == FINISHED_BIOS_LOAD) {
- bd->state = NEED_FEP_LOAD;
-
- /*
- * Signal downloader, its got some work to do.
- */
- DGAP_LOCK(dgap_dl_lock, lock_flags2);
- if (dgap_dl_action != 1) {
- dgap_dl_action = 1;
- wake_up_interruptible(&dgap_dl_wait);
- }
- DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
- }
-
- /* Wait for FEP to load on board... */
- if (bd->state == WAIT_FEP_LOAD) {
- dgap_do_wait_for_fep(bd);
- }
-
-
- /* Move to next state */
- if (bd->state == FINISHED_FEP_LOAD) {
-
- /*
- * Do tty device initialization.
- */
- int rc = dgap_tty_init(bd);
-
- if (rc < 0) {
- dgap_tty_uninit(bd);
- APR(("Can't init tty devices (%d)\n", rc));
- bd->state = BOARD_FAILED;
- bd->dpastatus = BD_NOFEP;
- }
- else {
- bd->state = NEED_PROC_CREATION;
-
- /*
- * Signal downloader, its got some work to do.
- */
- DGAP_LOCK(dgap_dl_lock, lock_flags2);
- if (dgap_dl_action != 1) {
- dgap_dl_action = 1;
- wake_up_interruptible(&dgap_dl_wait);
- }
- DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
- }
- }
-
- /* Move to next state */
- if (bd->state == FINISHED_PROC_CREATION) {
-
- bd->state = BOARD_READY;
- bd->dpastatus = BD_RUNNING;
-
- /*
- * If user requested the board to run in interrupt mode,
- * go and set it up on the board.
- */
- if (bd->intr_used) {
- writew(1, (bd->re_map_membase + ENABLE_INTR));
- /*
- * Tell the board to poll the UARTS as fast as possible.
- */
- writew(FEPPOLL_MIN, (bd->re_map_membase + FEPPOLL));
- bd->intr_running = 1;
- }
-
- /* Wake up anyone waiting for board state to change to ready */
- wake_up_interruptible(&bd->state_wait);
- }
-
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-}
-
-
-/*=======================================================================
- *
- * dgap_cmdb - Sends a 2 byte command to the FEP.
- *
- * ch - Pointer to channel structure.
- * cmd - Command to be sent.
- * byte1 - Integer containing first byte to be sent.
- * byte2 - Integer containing second byte to be sent.
- * ncmds - Wait until ncmds or fewer cmds are left
- * in the cmd buffer before returning.
- *
- *=======================================================================*/
-void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, uchar byte2, uint ncmds)
-{
- char *vaddr = NULL;
- struct cm_t *cm_addr = NULL;
- uint count;
- uint n;
- u16 head;
- u16 tail;
-
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- /*
- * Check if board is still alive.
- */
- if (ch->ch_bd->state == BOARD_FAILED) {
- DPR_CORE(("%s:%d board is in failed state.\n", __FILE__, __LINE__));
- return;
- }
-
- /*
- * Make sure the pointers are in range before
- * writing to the FEP memory.
- */
- vaddr = ch->ch_bd->re_map_membase;
-
- if (!vaddr)
- return;
-
- cm_addr = (struct cm_t *) (vaddr + CMDBUF);
- head = readw(&(cm_addr->cm_head));
-
- /*
- * Forget it if pointers out of range.
- */
- if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
- DPR_CORE(("%s:%d pointers out of range, failing board!\n", __FILE__, __LINE__));
- ch->ch_bd->state = BOARD_FAILED;
- return;
- }
-
- /*
- * Put the data in the circular command buffer.
- */
- writeb(cmd, (char *) (vaddr + head + CMDSTART + 0));
- writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1));
- writeb(byte1, (char *) (vaddr + head + CMDSTART + 2));
- writeb(byte2, (char *) (vaddr + head + CMDSTART + 3));
-
- head = (head + 4) & (CMDMAX - CMDSTART - 4);
-
- writew(head, &(cm_addr->cm_head));
-
- /*
- * Wait if necessary before updating the head
- * pointer to limit the number of outstanding
- * commands to the FEP. If the time spent waiting
- * is outlandish, declare the FEP dead.
- */
- for (count = dgap_count ;;) {
-
- head = readw(&(cm_addr->cm_head));
- tail = readw(&(cm_addr->cm_tail));
-
- n = (head - tail) & (CMDMAX - CMDSTART - 4);
-
- if (n <= ncmds * sizeof(struct cm_t))
- break;
-
- if (--count == 0) {
- DPR_CORE(("%s:%d failing board.\n",__FILE__, __LINE__));
- ch->ch_bd->state = BOARD_FAILED;
- return;
- }
- udelay(10);
- }
-}
-
-
-/*=======================================================================
- *
- * dgap_cmdw - Sends a 1 word command to the FEP.
- *
- * ch - Pointer to channel structure.
- * cmd - Command to be sent.
- * word - Integer containing word to be sent.
- * ncmds - Wait until ncmds or fewer cmds are left
- * in the cmd buffer before returning.
- *
- *=======================================================================*/
-void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds)
-{
- char *vaddr = NULL;
- struct cm_t *cm_addr = NULL;
- uint count;
- uint n;
- u16 head;
- u16 tail;
-
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- /*
- * Check if board is still alive.
- */
- if (ch->ch_bd->state == BOARD_FAILED) {
- DPR_CORE(("%s:%d board is failed!\n", __FILE__, __LINE__));
- return;
- }
-
- /*
- * Make sure the pointers are in range before
- * writing to the FEP memory.
- */
- vaddr = ch->ch_bd->re_map_membase;
- if (!vaddr)
- return;
-
- cm_addr = (struct cm_t *) (vaddr + CMDBUF);
- head = readw(&(cm_addr->cm_head));
-
- /*
- * Forget it if pointers out of range.
- */
- if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
- DPR_CORE(("%s:%d Pointers out of range. Failing board.\n",__FILE__, __LINE__));
- ch->ch_bd->state = BOARD_FAILED;
- return;
- }
-
- /*
- * Put the data in the circular command buffer.
- */
- writeb(cmd, (char *) (vaddr + head + CMDSTART + 0));
- writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1));
- writew((u16) word, (char *) (vaddr + head + CMDSTART + 2));
-
- head = (head + 4) & (CMDMAX - CMDSTART - 4);
-
- writew(head, &(cm_addr->cm_head));
-
- /*
- * Wait if necessary before updating the head
- * pointer to limit the number of outstanding
- * commands to the FEP. If the time spent waiting
- * is outlandish, declare the FEP dead.
- */
- for (count = dgap_count ;;) {
-
- head = readw(&(cm_addr->cm_head));
- tail = readw(&(cm_addr->cm_tail));
-
- n = (head - tail) & (CMDMAX - CMDSTART - 4);
-
- if (n <= ncmds * sizeof(struct cm_t))
- break;
-
- if (--count == 0) {
- DPR_CORE(("%s:%d Failing board.\n",__FILE__, __LINE__));
- ch->ch_bd->state = BOARD_FAILED;
- return;
- }
- udelay(10);
- }
-}
-
-
-
-/*=======================================================================
- *
- * dgap_cmdw_ext - Sends a extended word command to the FEP.
- *
- * ch - Pointer to channel structure.
- * cmd - Command to be sent.
- * word - Integer containing word to be sent.
- * ncmds - Wait until ncmds or fewer cmds are left
- * in the cmd buffer before returning.
- *
- *=======================================================================*/
-static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds)
-{
- char *vaddr = NULL;
- struct cm_t *cm_addr = NULL;
- uint count;
- uint n;
- u16 head;
- u16 tail;
-
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- /*
- * Check if board is still alive.
- */
- if (ch->ch_bd->state == BOARD_FAILED) {
- DPR_CORE(("%s:%d board is failed!\n", __FILE__, __LINE__));
- return;
- }
-
- /*
- * Make sure the pointers are in range before
- * writing to the FEP memory.
- */
- vaddr = ch->ch_bd->re_map_membase;
- if (!vaddr)
- return;
-
- cm_addr = (struct cm_t *) (vaddr + CMDBUF);
- head = readw(&(cm_addr->cm_head));
-
- /*
- * Forget it if pointers out of range.
- */
- if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
- DPR_CORE(("%s:%d Pointers out of range. Failing board.\n",__FILE__, __LINE__));
- ch->ch_bd->state = BOARD_FAILED;
- return;
- }
-
- /*
- * Put the data in the circular command buffer.
- */
-
- /* Write an FF to tell the FEP that we want an extended command */
- writeb((uchar) 0xff, (char *) (vaddr + head + CMDSTART + 0));
-
- writeb((uchar) ch->ch_portnum, (uchar *) (vaddr + head + CMDSTART + 1));
- writew((u16) cmd, (char *) (vaddr + head + CMDSTART + 2));
-
- /*
- * If the second part of the command won't fit,
- * put it at the beginning of the circular buffer.
- */
- if (((head + 4) >= ((CMDMAX - CMDSTART)) || (head & 03))) {
- writew((u16) word, (char *) (vaddr + CMDSTART));
- } else {
- writew((u16) word, (char *) (vaddr + head + CMDSTART + 4));
- }
-
- head = (head + 8) & (CMDMAX - CMDSTART - 4);
-
- writew(head, &(cm_addr->cm_head));
-
- /*
- * Wait if necessary before updating the head
- * pointer to limit the number of outstanding
- * commands to the FEP. If the time spent waiting
- * is outlandish, declare the FEP dead.
- */
- for (count = dgap_count ;;) {
-
- head = readw(&(cm_addr->cm_head));
- tail = readw(&(cm_addr->cm_tail));
-
- n = (head - tail) & (CMDMAX - CMDSTART - 4);
-
- if (n <= ncmds * sizeof(struct cm_t))
- break;
-
- if (--count == 0) {
- DPR_CORE(("%s:%d Failing board.\n",__FILE__, __LINE__));
- ch->ch_bd->state = BOARD_FAILED;
- return;
- }
- udelay(10);
- }
-}
-
-
-/*=======================================================================
- *
- * dgap_wmove - Write data to FEP buffer.
- *
- * ch - Pointer to channel structure.
- * buf - Poiter to characters to be moved.
- * cnt - Number of characters to move.
- *
- *=======================================================================*/
-void dgap_wmove(struct channel_t *ch, char *buf, uint cnt)
-{
- int n;
- char *taddr;
- struct bs_t *bs;
- u16 head;
-
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- /*
- * Check parameters.
- */
- bs = ch->ch_bs;
- head = readw(&(bs->tx_head));
-
- /*
- * If pointers are out of range, just return.
- */
- if ((cnt > ch->ch_tsize) || (unsigned)(head - ch->ch_tstart) >= ch->ch_tsize) {
- DPR_CORE(("%s:%d pointer out of range", __FILE__, __LINE__));
- return;
- }
-
- /*
- * If the write wraps over the top of the circular buffer,
- * move the portion up to the wrap point, and reset the
- * pointers to the bottom.
- */
- n = ch->ch_tstart + ch->ch_tsize - head;
-
- if (cnt >= n) {
- cnt -= n;
- taddr = ch->ch_taddr + head;
- memcpy_toio(taddr, buf, n);
- head = ch->ch_tstart;
- buf += n;
- }
-
- /*
- * Move rest of data.
- */
- taddr = ch->ch_taddr + head;
- n = cnt;
- memcpy_toio(taddr, buf, n);
- head += cnt;
-
- writew(head, &(bs->tx_head));
-}
-
-/*
- * Retrives the current custom baud rate from FEP memory,
- * and returns it back to the user.
- * Returns 0 on error.
- */
-uint dgap_get_custom_baud(struct channel_t *ch)
-{
- uchar *vaddr;
- ulong offset = 0;
- uint value = 0;
-
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) {
- return 0;
- }
-
- if (!ch->ch_bd || ch->ch_bd->magic != DGAP_BOARD_MAGIC) {
- return 0;
- }
-
- if (!(ch->ch_bd->bd_flags & BD_FEP5PLUS))
- return 0;
-
- vaddr = ch->ch_bd->re_map_membase;
-
- if (!vaddr)
- return 0;
-
- /*
- * Go get from fep mem, what the fep
- * believes the custom baud rate is.
- */
- offset = ((((*(unsigned short *)(vaddr + ECS_SEG)) << 4) +
- (ch->ch_portnum * 0x28) + LINE_SPEED));
-
- value = readw(vaddr + offset);
- return value;
-}
-
-
-/*
- * Calls the firmware to reset this channel.
- */
-void dgap_firmware_reset_port(struct channel_t *ch)
-{
- dgap_cmdb(ch, CHRESET, 0, 0, 0);
-
- /*
- * Now that the channel is reset, we need to make sure
- * all the current settings get reapplied to the port
- * in the firmware.
- *
- * So we will set the driver's cache of firmware
- * settings all to 0, and then call param.
- */
- ch->ch_fepiflag = 0;
- ch->ch_fepcflag = 0;
- ch->ch_fepoflag = 0;
- ch->ch_fepstartc = 0;
- ch->ch_fepstopc = 0;
- ch->ch_fepastartc = 0;
- ch->ch_fepastopc = 0;
- ch->ch_mostat = 0;
- ch->ch_hflow = 0;
-}
-
-
-/*=======================================================================
- *
- * dgap_param - Set Digi parameters.
- *
- * struct tty_struct * - TTY for port.
- *
- *=======================================================================*/
-int dgap_param(struct tty_struct *tty)
-{
- struct ktermios *ts;
- struct board_t *bd;
- struct channel_t *ch;
- struct bs_t *bs;
- struct un_t *un;
- u16 head;
- u16 cflag;
- u16 iflag;
- uchar mval;
- uchar hflow;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return -ENXIO;
-
- un = (struct un_t *) tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return -ENXIO;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return -ENXIO;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return -ENXIO;
-
- bs = ch->ch_bs;
- if (!bs)
- return -ENXIO;
-
- DPR_PARAM(("param start: tdev: %x cflags: %x oflags: %x iflags: %x\n",
- ch->ch_tun.un_dev, ch->ch_c_cflag, ch->ch_c_oflag, ch->ch_c_iflag));
-
- ts = &tty->termios;
-
- /*
- * If baud rate is zero, flush queues, and set mval to drop DTR.
- */
- if ((ch->ch_c_cflag & (CBAUD)) == 0) {
-
- /* flush rx */
- head = readw(&(ch->ch_bs->rx_head));
- writew(head, &(ch->ch_bs->rx_tail));
-
- /* flush tx */
- head = readw(&(ch->ch_bs->tx_head));
- writew(head, &(ch->ch_bs->tx_tail));
-
- ch->ch_flags |= (CH_BAUD0);
-
- /* Drop RTS and DTR */
- ch->ch_mval &= ~(D_RTS(ch)|D_DTR(ch));
- mval = D_DTR(ch) | D_RTS(ch);
- ch->ch_baud_info = 0;
-
- } else if (ch->ch_custom_speed && (bd->bd_flags & BD_FEP5PLUS)) {
- /*
- * Tell the fep to do the command
- */
-
- DPR_PARAM(("param: Want %d speed\n", ch->ch_custom_speed));
-
- dgap_cmdw_ext(ch, 0xff01, ch->ch_custom_speed, 0);
-
- /*
- * Now go get from fep mem, what the fep
- * believes the custom baud rate is.
- */
- ch->ch_baud_info = ch->ch_custom_speed = dgap_get_custom_baud(ch);
-
- DPR_PARAM(("param: Got %d speed\n", ch->ch_custom_speed));
-
- /* Handle transition from B0 */
- if (ch->ch_flags & CH_BAUD0) {
- ch->ch_flags &= ~(CH_BAUD0);
- ch->ch_mval |= (D_RTS(ch)|D_DTR(ch));
- }
- mval = D_DTR(ch) | D_RTS(ch);
-
- } else {
- /*
- * Set baud rate, character size, and parity.
- */
-
-
- int iindex = 0;
- int jindex = 0;
- int baud = 0;
-
- ulong bauds[4][16] = {
- { /* slowbaud */
- 0, 50, 75, 110,
- 134, 150, 200, 300,
- 600, 1200, 1800, 2400,
- 4800, 9600, 19200, 38400 },
- { /* slowbaud & CBAUDEX */
- 0, 57600, 115200, 230400,
- 460800, 150, 200, 921600,
- 600, 1200, 1800, 2400,
- 4800, 9600, 19200, 38400 },
- { /* fastbaud */
- 0, 57600, 76800, 115200,
- 14400, 57600, 230400, 76800,
- 115200, 230400, 28800, 460800,
- 921600, 9600, 19200, 38400 },
- { /* fastbaud & CBAUDEX */
- 0, 57600, 115200, 230400,
- 460800, 150, 200, 921600,
- 600, 1200, 1800, 2400,
- 4800, 9600, 19200, 38400 }
- };
-
- /* Only use the TXPrint baud rate if the terminal unit is NOT open */
- if (!(ch->ch_tun.un_flags & UN_ISOPEN) && (un->un_type == DGAP_PRINT))
- baud = C_BAUD(ch->ch_pun.un_tty) & 0xff;
- else
- baud = C_BAUD(ch->ch_tun.un_tty) & 0xff;
-
- if (ch->ch_c_cflag & CBAUDEX)
- iindex = 1;
-
- if (ch->ch_digi.digi_flags & DIGI_FAST)
- iindex += 2;
-
- jindex = baud;
-
- if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) && (jindex < 16)) {
- baud = bauds[iindex][jindex];
- } else {
- DPR_IOCTL(("baud indices were out of range (%d)(%d)",
- iindex, jindex));
- baud = 0;
- }
-
- if (baud == 0)
- baud = 9600;
-
- ch->ch_baud_info = baud;
-
-
- /*
- * CBAUD has bit position 0x1000 set these days to indicate Linux
- * baud rate remap.
- * We use a different bit assignment for high speed. Clear this
- * bit out while grabbing the parts of "cflag" we want.
- */
- cflag = ch->ch_c_cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
-
- /*
- * HUPCL bit is used by FEP to indicate fast baud
- * table is to be used.
- */
- if ((ch->ch_digi.digi_flags & DIGI_FAST) || (ch->ch_c_cflag & CBAUDEX))
- cflag |= HUPCL;
-
-
- if ((ch->ch_c_cflag & CBAUDEX) && !(ch->ch_digi.digi_flags & DIGI_FAST)) {
- /*
- * The below code is trying to guarantee that only baud rates
- * 115200, 230400, 460800, 921600 are remapped. We use exclusive or
- * because the various baud rates share common bit positions
- * and therefore can't be tested for easily.
- */
- tcflag_t tcflag = (ch->ch_c_cflag & CBAUD) | CBAUDEX;
- int baudpart = 0;
-
- /* Map high speed requests to index into FEP's baud table */
- switch (tcflag) {
- case B57600 :
- baudpart = 1;
- break;
-#ifdef B76800
- case B76800 :
- baudpart = 2;
- break;
-#endif
- case B115200 :
- baudpart = 3;
- break;
- case B230400 :
- baudpart = 9;
- break;
- case B460800 :
- baudpart = 11;
- break;
-#ifdef B921600
- case B921600 :
- baudpart = 12;
- break;
-#endif
- default:
- baudpart = 0;
- }
-
- if (baudpart)
- cflag = (cflag & ~(CBAUD | CBAUDEX)) | baudpart;
- }
-
- cflag &= 0xffff;
-
- if (cflag != ch->ch_fepcflag) {
- ch->ch_fepcflag = (u16) (cflag & 0xffff);
-
- /* Okay to have channel and board locks held calling this */
- dgap_cmdw(ch, SCFLAG, (u16) cflag, 0);
- }
-
- /* Handle transition from B0 */
- if (ch->ch_flags & CH_BAUD0) {
- ch->ch_flags &= ~(CH_BAUD0);
- ch->ch_mval |= (D_RTS(ch)|D_DTR(ch));
- }
- mval = D_DTR(ch) | D_RTS(ch);
- }
-
- /*
- * Get input flags.
- */
- iflag = ch->ch_c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | IXON | IXANY | IXOFF);
-
- if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE)) {
- iflag &= ~(IXON | IXOFF);
- ch->ch_c_iflag &= ~(IXON | IXOFF);
- }
-
- /*
- * Only the IBM Xr card can switch between
- * 232 and 422 modes on the fly
- */
- if (bd->device == PCI_DEVICE_XR_IBM_DID) {
- if (ch->ch_digi.digi_flags & DIGI_422)
- dgap_cmdb(ch, SCOMMODE, MODE_422, 0, 0);
- else
- dgap_cmdb(ch, SCOMMODE, MODE_232, 0, 0);
- }
-
- if (ch->ch_digi.digi_flags & DIGI_ALTPIN)
- iflag |= IALTPIN ;
-
- if (iflag != ch->ch_fepiflag) {
- ch->ch_fepiflag = iflag;
-
- /* Okay to have channel and board locks held calling this */
- dgap_cmdw(ch, SIFLAG, (u16) ch->ch_fepiflag, 0);
- }
-
- /*
- * Select hardware handshaking.
- */
- hflow = 0;
-
- if (ch->ch_c_cflag & CRTSCTS) {
- hflow |= (D_RTS(ch) | D_CTS(ch));
- }
- if (ch->ch_digi.digi_flags & RTSPACE)
- hflow |= D_RTS(ch);
- if (ch->ch_digi.digi_flags & DTRPACE)
- hflow |= D_DTR(ch);
- if (ch->ch_digi.digi_flags & CTSPACE)
- hflow |= D_CTS(ch);
- if (ch->ch_digi.digi_flags & DSRPACE)
- hflow |= D_DSR(ch);
- if (ch->ch_digi.digi_flags & DCDPACE)
- hflow |= D_CD(ch);
-
- if (hflow != ch->ch_hflow) {
- ch->ch_hflow = hflow;
-
- /* Okay to have channel and board locks held calling this */
- dgap_cmdb(ch, SHFLOW, (uchar) hflow, 0xff, 0);
- }
-
-
- /*
- * Set RTS and/or DTR Toggle if needed, but only if product is FEP5+ based.
- */
- if (bd->bd_flags & BD_FEP5PLUS) {
- u16 hflow2 = 0;
- if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
- hflow2 |= (D_RTS(ch));
- }
- if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
- hflow2 |= (D_DTR(ch));
- }
-
- dgap_cmdw_ext(ch, 0xff03, hflow2, 0);
- }
-
- /*
- * Set modem control lines.
- */
-
- mval ^= ch->ch_mforce & (mval ^ ch->ch_mval);
-
- DPR_PARAM(("dgap_param: mval: %x ch_mforce: %x ch_mval: %x ch_mostat: %x\n",
- mval, ch->ch_mforce, ch->ch_mval, ch->ch_mostat));
-
- if (ch->ch_mostat ^ mval) {
- ch->ch_mostat = mval;
-
- /* Okay to have channel and board locks held calling this */
- DPR_PARAM(("dgap_param: Sending SMODEM mval: %x\n", mval));
- dgap_cmdb(ch, SMODEM, (uchar) mval, D_RTS(ch)|D_DTR(ch), 0);
- }
-
- /*
- * Read modem signals, and then call carrier function.
- */
- ch->ch_mistat = readb(&(bs->m_stat));
- dgap_carrier(ch);
-
- /*
- * Set the start and stop characters.
- */
- if (ch->ch_startc != ch->ch_fepstartc || ch->ch_stopc != ch->ch_fepstopc) {
- ch->ch_fepstartc = ch->ch_startc;
- ch->ch_fepstopc = ch->ch_stopc;
-
- /* Okay to have channel and board locks held calling this */
- dgap_cmdb(ch, SFLOWC, ch->ch_fepstartc, ch->ch_fepstopc, 0);
- }
-
- /*
- * Set the Auxiliary start and stop characters.
- */
- if (ch->ch_astartc != ch->ch_fepastartc || ch->ch_astopc != ch->ch_fepastopc) {
- ch->ch_fepastartc = ch->ch_astartc;
- ch->ch_fepastopc = ch->ch_astopc;
-
- /* Okay to have channel and board locks held calling this */
- dgap_cmdb(ch, SAFLOWC, ch->ch_fepastartc, ch->ch_fepastopc, 0);
- }
-
- DPR_PARAM(("param finish\n"));
-
- return 0;
-}
-
-
-/*
- * dgap_parity_scan()
- *
- * Convert the FEP5 way of reporting parity errors and breaks into
- * the Linux line discipline way.
- */
-void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, unsigned char *fbuf, int *len)
-{
- int l = *len;
- int count = 0;
- unsigned char *in, *cout, *fout;
- unsigned char c;
-
- in = cbuf;
- cout = cbuf;
- fout = fbuf;
-
- DPR_PSCAN(("dgap_parity_scan start\n"));
-
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- while (l--) {
- c = *in++;
- switch (ch->pscan_state) {
- default:
- /* reset to sanity and fall through */
- ch->pscan_state = 0;
-
- case 0:
- /* No FF seen yet */
- if (c == (unsigned char) '\377') {
- /* delete this character from stream */
- ch->pscan_state = 1;
- } else {
- *cout++ = c;
- *fout++ = TTY_NORMAL;
- count += 1;
- }
- break;
-
- case 1:
- /* first FF seen */
- if (c == (unsigned char) '\377') {
- /* doubled ff, transform to single ff */
- *cout++ = c;
- *fout++ = TTY_NORMAL;
- count += 1;
- ch->pscan_state = 0;
- } else {
- /* save value examination in next state */
- ch->pscan_savechar = c;
- ch->pscan_state = 2;
- }
- break;
-
- case 2:
- /* third character of ff sequence */
-
- *cout++ = c;
-
- if (ch->pscan_savechar == 0x0) {
-
- if (c == 0x0) {
- DPR_PSCAN(("dgap_parity_scan in 3rd char of ff seq. c: %x setting break.\n", c));
- ch->ch_err_break++;
- *fout++ = TTY_BREAK;
- }
- else {
- DPR_PSCAN(("dgap_parity_scan in 3rd char of ff seq. c: %x setting parity.\n", c));
- ch->ch_err_parity++;
- *fout++ = TTY_PARITY;
- }
- }
- else {
- DPR_PSCAN(("%s:%d Logic Error.\n", __FILE__, __LINE__));
- }
-
- count += 1;
- ch->pscan_state = 0;
- }
- }
- *len = count;
- DPR_PSCAN(("dgap_parity_scan finish\n"));
-}
-
-
-
-
-/*=======================================================================
- *
- * dgap_event - FEP to host event processing routine.
- *
- * bd - Board of current event.
- *
- *=======================================================================*/
-static int dgap_event(struct board_t *bd)
-{
- struct channel_t *ch;
- ulong lock_flags;
- ulong lock_flags2;
- struct bs_t *bs;
- uchar *event;
- uchar *vaddr = NULL;
- struct ev_t *eaddr = NULL;
- uint head;
- uint tail;
- int port;
- int reason;
- int modem;
- int b1;
-
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return -ENXIO;
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
-
- vaddr = bd->re_map_membase;
-
- if (!vaddr) {
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return -ENXIO;
- }
-
- eaddr = (struct ev_t *) (vaddr + EVBUF);
-
- /* Get our head and tail */
- head = readw(&(eaddr->ev_head));
- tail = readw(&(eaddr->ev_tail));
-
- /*
- * Forget it if pointers out of range.
- */
-
- if (head >= EVMAX - EVSTART || tail >= EVMAX - EVSTART ||
- (head | tail) & 03) {
- DPR_EVENT(("should be calling xxfail %d\n", __LINE__));
- /* Let go of board lock */
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return -ENXIO;
- }
-
- /*
- * Loop to process all the events in the buffer.
- */
- while (tail != head) {
-
- /*
- * Get interrupt information.
- */
-
- event = bd->re_map_membase + tail + EVSTART;
-
- port = event[0];
- reason = event[1];
- modem = event[2];
- b1 = event[3];
-
- DPR_EVENT(("event: jiffies: %ld port: %d reason: %x modem: %x\n",
- jiffies, port, reason, modem));
-
- /*
- * Make sure the interrupt is valid.
- */
- if (port >= bd->nasync)
- goto next;
-
- if (!(reason & (IFMODEM | IFBREAK | IFTLW | IFTEM | IFDATA))) {
- goto next;
- }
-
- ch = bd->channels[port];
-
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) {
- goto next;
- }
-
- /*
- * If we have made it here, the event was valid.
- * Lock down the channel.
- */
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- bs = ch->ch_bs;
-
- if (!bs) {
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- goto next;
- }
-
- /*
- * Process received data.
- */
- if (reason & IFDATA) {
-
- /*
- * ALL LOCKS *MUST* BE DROPPED BEFORE CALLING INPUT!
- * input could send some data to ld, which in turn
- * could do a callback to one of our other functions.
- */
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- dgap_input(ch);
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- if (ch->ch_flags & CH_RACTIVE)
- ch->ch_flags |= CH_RENABLE;
- else
- writeb(1, &(bs->idata));
-
- if (ch->ch_flags & CH_RWAIT) {
- ch->ch_flags &= ~CH_RWAIT;
-
- wake_up_interruptible(&ch->ch_tun.un_flags_wait);
- }
- }
-
- /*
- * Process Modem change signals.
- */
- if (reason & IFMODEM) {
- ch->ch_mistat = modem;
- dgap_carrier(ch);
- }
-
- /*
- * Process break.
- */
- if (reason & IFBREAK) {
-
- DPR_EVENT(("got IFBREAK\n"));
-
- if (ch->ch_tun.un_tty) {
- /* A break has been indicated */
- ch->ch_err_break++;
- tty_buffer_request_room(ch->ch_tun.un_tty->port, 1);
- tty_insert_flip_char(ch->ch_tun.un_tty->port, 0, TTY_BREAK);
- tty_flip_buffer_push(ch->ch_tun.un_tty->port);
- }
- }
-
- /*
- * Process Transmit low.
- */
- if (reason & IFTLW) {
-
- DPR_EVENT(("event: got low event\n"));
-
- if (ch->ch_tun.un_flags & UN_LOW) {
- ch->ch_tun.un_flags &= ~UN_LOW;
-
- if (ch->ch_tun.un_flags & UN_ISOPEN) {
- if ((ch->ch_tun.un_tty->flags &
- (1 << TTY_DO_WRITE_WAKEUP)) &&
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
- ch->ch_tun.un_tty->ldisc->ops->write_wakeup)
-#else
- ch->ch_tun.un_tty->ldisc.ops->write_wakeup)
-#endif
- {
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
- (ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty);
-#else
- (ch->ch_tun.un_tty->ldisc.ops->write_wakeup)(ch->ch_tun.un_tty);
-#endif
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
- }
- wake_up_interruptible(&ch->ch_tun.un_tty->write_wait);
- wake_up_interruptible(&ch->ch_tun.un_flags_wait);
-
- DPR_EVENT(("event: Got low event. jiffies: %lu\n", jiffies));
- }
- }
-
- if (ch->ch_pun.un_flags & UN_LOW) {
- ch->ch_pun.un_flags &= ~UN_LOW;
- if (ch->ch_pun.un_flags & UN_ISOPEN) {
- if ((ch->ch_pun.un_tty->flags &
- (1 << TTY_DO_WRITE_WAKEUP)) &&
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
- ch->ch_pun.un_tty->ldisc->ops->write_wakeup)
-#else
- ch->ch_pun.un_tty->ldisc.ops->write_wakeup)
-#endif
- {
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
- (ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty);
-#else
- (ch->ch_pun.un_tty->ldisc.ops->write_wakeup)(ch->ch_pun.un_tty);
-#endif
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
- }
- wake_up_interruptible(&ch->ch_pun.un_tty->write_wait);
- wake_up_interruptible(&ch->ch_pun.un_flags_wait);
- }
- }
-
- if (ch->ch_flags & CH_WLOW) {
- ch->ch_flags &= ~CH_WLOW;
- wake_up_interruptible(&ch->ch_flags_wait);
- }
- }
-
- /*
- * Process Transmit empty.
- */
- if (reason & IFTEM) {
- DPR_EVENT(("event: got empty event\n"));
-
- if (ch->ch_tun.un_flags & UN_EMPTY) {
- ch->ch_tun.un_flags &= ~UN_EMPTY;
- if (ch->ch_tun.un_flags & UN_ISOPEN) {
- if ((ch->ch_tun.un_tty->flags &
- (1 << TTY_DO_WRITE_WAKEUP)) &&
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
- ch->ch_tun.un_tty->ldisc->ops->write_wakeup)
-#else
- ch->ch_tun.un_tty->ldisc.ops->write_wakeup)
-#endif
- {
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
- (ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty);
-#else
- (ch->ch_tun.un_tty->ldisc.ops->write_wakeup)(ch->ch_tun.un_tty);
-#endif
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
- }
- wake_up_interruptible(&ch->ch_tun.un_tty->write_wait);
- wake_up_interruptible(&ch->ch_tun.un_flags_wait);
- }
- }
-
- if (ch->ch_pun.un_flags & UN_EMPTY) {
- ch->ch_pun.un_flags &= ~UN_EMPTY;
- if (ch->ch_pun.un_flags & UN_ISOPEN) {
- if ((ch->ch_pun.un_tty->flags &
- (1 << TTY_DO_WRITE_WAKEUP)) &&
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
- ch->ch_pun.un_tty->ldisc->ops->write_wakeup)
-#else
- ch->ch_pun.un_tty->ldisc.ops->write_wakeup)
-#endif
- {
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
- (ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty);
-#else
- (ch->ch_pun.un_tty->ldisc.ops->write_wakeup)(ch->ch_pun.un_tty);
-#endif
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
- }
- wake_up_interruptible(&ch->ch_pun.un_tty->write_wait);
- wake_up_interruptible(&ch->ch_pun.un_flags_wait);
- }
- }
-
-
- if (ch->ch_flags & CH_WEMPTY) {
- ch->ch_flags &= ~CH_WEMPTY;
- wake_up_interruptible(&ch->ch_flags_wait);
- }
- }
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
-
-next:
- tail = (tail + 4) & (EVMAX - EVSTART - 4);
- }
-
- writew(tail, &(eaddr->ev_tail));
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- return 0;
-}
diff --git a/drivers/staging/dgap/dgap_fep5.h b/drivers/staging/dgap/dgap_fep5.h
deleted file mode 100644
index c9abc406a1e0..000000000000
--- a/drivers/staging/dgap/dgap_fep5.h
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
- *
- ************************************************************************
- *** FEP Version 5 dependent definitions
- ************************************************************************/
-
-#ifndef __DGAP_FEP5_H
-#define __DGAP_FEP5_H
-
-/************************************************************************
- * FEP memory offsets
- ************************************************************************/
-#define START 0x0004L /* Execution start address */
-
-#define CMDBUF 0x0d10L /* Command (cm_t) structure offset */
-#define CMDSTART 0x0400L /* Start of command buffer */
-#define CMDMAX 0x0800L /* End of command buffer */
-
-#define EVBUF 0x0d18L /* Event (ev_t) structure */
-#define EVSTART 0x0800L /* Start of event buffer */
-#define EVMAX 0x0c00L /* End of event buffer */
-#define FEP5_PLUS 0x0E40 /* ASCII '5' and ASCII 'A' is here */
-#define ECS_SEG 0x0E44 /* Segment of the extended channel structure */
-#define LINE_SPEED 0x10 /* Offset into ECS_SEG for line speed */
- /* if the fep has extended capabilities */
-
-/* BIOS MAGIC SPOTS */
-#define ERROR 0x0C14L /* BIOS error code */
-#define SEQUENCE 0x0C12L /* BIOS sequence indicator */
-#define POSTAREA 0x0C00L /* POST complete message area */
-
-/* FEP MAGIC SPOTS */
-#define FEPSTAT POSTAREA /* OS here when FEP comes up */
-#define NCHAN 0x0C02L /* number of ports FEP sees */
-#define PANIC 0x0C10L /* PANIC area for FEP */
-#define KMEMEM 0x0C30L /* Memory for KME use */
-#define CONFIG 0x0CD0L /* Concentrator configuration info */
-#define CONFIGSIZE 0x0030 /* configuration info size */
-#define DOWNREQ 0x0D00 /* Download request buffer pointer */
-
-#define CHANBUF 0x1000L /* Async channel (bs_t) structs */
-#define FEPOSSIZE 0x1FFF /* 8K FEPOS */
-
-#define XEMPORTS 0xC02 /*
- * Offset in board memory where FEP5 stores
- * how many ports it has detected.
- * NOTE: FEP5 reports 64 ports when the user
- * has the cable in EBI OUT instead of EBI IN.
- */
-
-#define FEPCLR 0x00
-#define FEPMEM 0x02
-#define FEPRST 0x04
-#define FEPINT 0x08
-#define FEPMASK 0x0e
-#define FEPWIN 0x80
-
-#define LOWMEM 0x0100
-#define HIGHMEM 0x7f00
-
-#define FEPTIMEOUT 200000
-
-#define ENABLE_INTR 0x0e04 /* Enable interrupts flag */
-#define FEPPOLL_MIN 1 /* minimum of 1 millisecond */
-#define FEPPOLL_MAX 20 /* maximum of 20 milliseconds */
-#define FEPPOLL 0x0c26 /* Fep event poll interval */
-
-#define IALTPIN 0x0080 /* Input flag to swap DSR <-> DCD */
-
-/************************************************************************
- * Command structure definition.
- ************************************************************************/
-struct cm_t {
- volatile unsigned short cm_head; /* Command buffer head offset */
- volatile unsigned short cm_tail; /* Command buffer tail offset */
- volatile unsigned short cm_start; /* start offset of buffer */
- volatile unsigned short cm_max; /* last offset of buffer */
-};
-
-/************************************************************************
- * Event structure definition.
- ************************************************************************/
-struct ev_t {
- volatile unsigned short ev_head; /* Command buffer head offset */
- volatile unsigned short ev_tail; /* Command buffer tail offset */
- volatile unsigned short ev_start; /* start offset of buffer */
- volatile unsigned short ev_max; /* last offset of buffer */
-};
-
-/************************************************************************
- * Download buffer structure.
- ************************************************************************/
-struct downld_t {
- uchar dl_type; /* Header */
- uchar dl_seq; /* Download sequence */
- ushort dl_srev; /* Software revision number */
- ushort dl_lrev; /* Low revision number */
- ushort dl_hrev; /* High revision number */
- ushort dl_seg; /* Start segment address */
- ushort dl_size; /* Number of bytes to download */
- uchar dl_data[1024]; /* Download data */
-};
-
-/************************************************************************
- * Per channel buffer structure
- ************************************************************************
- * Base Structure Entries Usage Meanings to Host *
- * *
- * W = read write R = read only *
- * C = changed by commands only *
- * U = unknown (may be changed w/o notice) *
- ************************************************************************/
-struct bs_t {
- volatile unsigned short tp_jmp; /* Transmit poll jump */
- volatile unsigned short tc_jmp; /* Cooked procedure jump */
- volatile unsigned short ri_jmp; /* Not currently used */
- volatile unsigned short rp_jmp; /* Receive poll jump */
-
- volatile unsigned short tx_seg; /* W Tx segment */
- volatile unsigned short tx_head; /* W Tx buffer head offset */
- volatile unsigned short tx_tail; /* R Tx buffer tail offset */
- volatile unsigned short tx_max; /* W Tx buffer size - 1 */
-
- volatile unsigned short rx_seg; /* W Rx segment */
- volatile unsigned short rx_head; /* W Rx buffer head offset */
- volatile unsigned short rx_tail; /* R Rx buffer tail offset */
- volatile unsigned short rx_max; /* W Rx buffer size - 1 */
-
- volatile unsigned short tx_lw; /* W Tx buffer low water mark */
- volatile unsigned short rx_lw; /* W Rx buffer low water mark */
- volatile unsigned short rx_hw; /* W Rx buffer high water mark */
- volatile unsigned short incr; /* W Increment to next channel */
-
- volatile unsigned short fepdev; /* U SCC device base address */
- volatile unsigned short edelay; /* W Exception delay */
- volatile unsigned short blen; /* W Break length */
- volatile unsigned short btime; /* U Break complete time */
-
- volatile unsigned short iflag; /* C UNIX input flags */
- volatile unsigned short oflag; /* C UNIX output flags */
- volatile unsigned short cflag; /* C UNIX control flags */
- volatile unsigned short wfill[13]; /* U Reserved for expansion */
-
- volatile unsigned char num; /* U Channel number */
- volatile unsigned char ract; /* U Receiver active counter */
- volatile unsigned char bstat; /* U Break status bits */
- volatile unsigned char tbusy; /* W Transmit busy */
- volatile unsigned char iempty; /* W Transmit empty event enable */
- volatile unsigned char ilow; /* W Transmit low-water event enable */
- volatile unsigned char idata; /* W Receive data interrupt enable */
- volatile unsigned char eflag; /* U Host event flags */
-
- volatile unsigned char tflag; /* U Transmit flags */
- volatile unsigned char rflag; /* U Receive flags */
- volatile unsigned char xmask; /* U Transmit ready flags */
- volatile unsigned char xval; /* U Transmit ready value */
- volatile unsigned char m_stat; /* RC Modem status bits */
- volatile unsigned char m_change; /* U Modem bits which changed */
- volatile unsigned char m_int; /* W Modem interrupt enable bits */
- volatile unsigned char m_last; /* U Last modem status */
-
- volatile unsigned char mtran; /* C Unreported modem trans */
- volatile unsigned char orun; /* C Buffer overrun occurred */
- volatile unsigned char astartc; /* W Auxiliary Xon char */
- volatile unsigned char astopc; /* W Auxiliary Xoff char */
- volatile unsigned char startc; /* W Xon character */
- volatile unsigned char stopc; /* W Xoff character */
- volatile unsigned char vnextc; /* W Vnext character */
- volatile unsigned char hflow; /* C Software flow control */
-
- volatile unsigned char fillc; /* U Delay Fill character */
- volatile unsigned char ochar; /* U Saved output character */
- volatile unsigned char omask; /* U Output character mask */
-
- volatile unsigned char bfill[13]; /* U Reserved for expansion */
-
- volatile unsigned char scc[16]; /* U SCC registers */
-};
-
-
-/************************************************************************
- * FEP supported functions
- ************************************************************************/
-#define SRLOW 0xe0 /* Set receive low water */
-#define SRHIGH 0xe1 /* Set receive high water */
-#define FLUSHTX 0xe2 /* Flush transmit buffer */
-#define PAUSETX 0xe3 /* Pause data transmission */
-#define RESUMETX 0xe4 /* Resume data transmission */
-#define SMINT 0xe5 /* Set Modem Interrupt */
-#define SAFLOWC 0xe6 /* Set Aux. flow control chars */
-#define SBREAK 0xe8 /* Send break */
-#define SMODEM 0xe9 /* Set 8530 modem control lines */
-#define SIFLAG 0xea /* Set UNIX iflags */
-#define SFLOWC 0xeb /* Set flow control characters */
-#define STLOW 0xec /* Set transmit low water mark */
-#define RPAUSE 0xee /* Pause receive */
-#define RRESUME 0xef /* Resume receive */
-#define CHRESET 0xf0 /* Reset Channel */
-#define BUFSETALL 0xf2 /* Set Tx & Rx buffer size avail*/
-#define SOFLAG 0xf3 /* Set UNIX oflags */
-#define SHFLOW 0xf4 /* Set hardware handshake */
-#define SCFLAG 0xf5 /* Set UNIX cflags */
-#define SVNEXT 0xf6 /* Set VNEXT character */
-#define SPINTFC 0xfc /* Reserved */
-#define SCOMMODE 0xfd /* Set RS232/422 mode */
-
-
-/************************************************************************
- * Modes for SCOMMODE
- ************************************************************************/
-#define MODE_232 0x00
-#define MODE_422 0x01
-
-
-/************************************************************************
- * Event flags.
- ************************************************************************/
-#define IFBREAK 0x01 /* Break received */
-#define IFTLW 0x02 /* Transmit low water */
-#define IFTEM 0x04 /* Transmitter empty */
-#define IFDATA 0x08 /* Receive data present */
-#define IFMODEM 0x20 /* Modem status change */
-
-/************************************************************************
- * Modem flags
- ************************************************************************/
-# define DM_RTS 0x02 /* Request to send */
-# define DM_CD 0x80 /* Carrier detect */
-# define DM_DSR 0x20 /* Data set ready */
-# define DM_CTS 0x10 /* Clear to send */
-# define DM_RI 0x40 /* Ring indicator */
-# define DM_DTR 0x01 /* Data terminal ready */
-
-
-#endif
diff --git a/drivers/staging/dgap/dgap_kcompat.h b/drivers/staging/dgap/dgap_kcompat.h
deleted file mode 100644
index 0dc2404922ff..000000000000
--- a/drivers/staging/dgap/dgap_kcompat.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2004 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
- *
- *************************************************************************
- *
- * This file is intended to contain all the kernel "differences" between the
- * various kernels that we support.
- *
- *************************************************************************/
-
-#ifndef __DGAP_KCOMPAT_H
-#define __DGAP_KCOMPAT_H
-
-#if !defined(TTY_FLIPBUF_SIZE)
-# define TTY_FLIPBUF_SIZE 512
-#endif
-
-
-/* Sparse stuff */
-# ifndef __user
-# define __user
-# define __kernel
-# define __safe
-# define __force
-# define __chk_user_ptr(x) (void)0
-# endif
-
-
-# define PARM_STR(VAR, INIT, PERM, DESC) \
- static char *VAR = INIT; \
- char *dgap_##VAR; \
- module_param(VAR, charp, PERM); \
- MODULE_PARM_DESC(VAR, DESC);
-
-# define PARM_INT(VAR, INIT, PERM, DESC) \
- static int VAR = INIT; \
- int dgap_##VAR; \
- module_param(VAR, int, PERM); \
- MODULE_PARM_DESC(VAR, DESC);
-
-# define PARM_ULONG(VAR, INIT, PERM, DESC) \
- static ulong VAR = INIT; \
- ulong dgap_##VAR; \
- module_param(VAR, long, PERM); \
- MODULE_PARM_DESC(VAR, DESC);
-
-#endif /* ! __DGAP_KCOMPAT_H */
diff --git a/drivers/staging/dgap/dgap_parse.c b/drivers/staging/dgap/dgap_parse.c
deleted file mode 100644
index 36fd93d3f5f6..000000000000
--- a/drivers/staging/dgap/dgap_parse.c
+++ /dev/null
@@ -1,1374 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
- *
- * This is shared code between Digi's CVS archive and the
- * Linux Kernel sources.
- * Changing the source just for reformatting needlessly breaks
- * our CVS diff history.
- *
- * Send any bug fixes/changes to: Eng.Linux at digi dot com.
- * Thank you.
- *
- *
- *****************************************************************************
- *
- * dgap_parse.c - Parses the configuration information from the input file.
- *
- * $Id: dgap_parse.c,v 1.1 2009/10/23 14:01:57 markh Exp $
- *
- */
-#include <linux/kernel.h>
-#include <linux/ctype.h>
-#include <linux/slab.h>
-
-#include "dgap_types.h"
-#include "dgap_fep5.h"
-#include "dgap_driver.h"
-#include "dgap_parse.h"
-#include "dgap_conf.h"
-
-
-/*
- * Function prototypes.
- */
-static int dgap_gettok(char **in, struct cnode *p);
-static char *dgap_getword(char **in);
-static char *dgap_savestring(char *s);
-static struct cnode *dgap_newnode(int t);
-static int dgap_checknode(struct cnode *p);
-static void dgap_err(char *s);
-
-/*
- * Our needed internal static variables...
- */
-static struct cnode dgap_head;
-#define MAXCWORD 200
-static char dgap_cword[MAXCWORD];
-
-struct toklist {
- int token;
- char *string;
-};
-
-static struct toklist dgap_tlist[] = {
- { BEGIN, "config_begin" },
- { END, "config_end" },
- { BOARD, "board" },
- { PCX, "Digi_AccelePort_C/X_PCI" }, /* C/X_PCI */
- { PEPC, "Digi_AccelePort_EPC/X_PCI" }, /* EPC/X_PCI */
- { PPCM, "Digi_AccelePort_Xem_PCI" }, /* PCI/Xem */
- { APORT2_920P, "Digi_AccelePort_2r_920_PCI" },
- { APORT4_920P, "Digi_AccelePort_4r_920_PCI" },
- { APORT8_920P, "Digi_AccelePort_8r_920_PCI" },
- { PAPORT4, "Digi_AccelePort_4r_PCI(EIA-232/RS-422)" },
- { PAPORT8, "Digi_AccelePort_8r_PCI(EIA-232/RS-422)" },
- { IO, "io" },
- { PCIINFO, "pciinfo" },
- { LINE, "line" },
- { CONC, "conc" },
- { CONC, "concentrator" },
- { CX, "cx" },
- { CX, "ccon" },
- { EPC, "epccon" },
- { EPC, "epc" },
- { MOD, "module" },
- { ID, "id" },
- { STARTO, "start" },
- { SPEED, "speed" },
- { CABLE, "cable" },
- { CONNECT, "connect" },
- { METHOD, "method" },
- { STATUS, "status" },
- { CUSTOM, "Custom" },
- { BASIC, "Basic" },
- { MEM, "mem" },
- { MEM, "memory" },
- { PORTS, "ports" },
- { MODEM, "modem" },
- { NPORTS, "nports" },
- { TTYN, "ttyname" },
- { CU, "cuname" },
- { PRINT, "prname" },
- { CMAJOR, "major" },
- { ALTPIN, "altpin" },
- { USEINTR, "useintr" },
- { TTSIZ, "ttysize" },
- { CHSIZ, "chsize" },
- { BSSIZ, "boardsize" },
- { UNTSIZ, "schedsize" },
- { F2SIZ, "f2200size" },
- { VPSIZ, "vpixsize" },
- { 0, NULL }
-};
-
-
-/*
- * Parse a configuration file read into memory as a string.
- */
-int dgap_parsefile(char **in, int Remove)
-{
- struct cnode *p, *brd, *line, *conc;
- int rc;
- char *s = NULL, *s2 = NULL;
- int linecnt = 0;
-
- p = &dgap_head;
- brd = line = conc = NULL;
-
- /* perhaps we are adding to an existing list? */
- while (p->next != NULL) {
- p = p->next;
- }
-
- /* file must start with a BEGIN */
- while ( (rc = dgap_gettok(in,p)) != BEGIN ) {
- if (rc == 0) {
- dgap_err("unexpected EOF");
- return(-1);
- }
- }
-
- for (; ; ) {
- rc = dgap_gettok(in,p);
- if (rc == 0) {
- dgap_err("unexpected EOF");
- return(-1);
- }
-
- switch (rc) {
- case 0:
- dgap_err("unexpected end of file");
- return(-1);
-
- case BEGIN: /* should only be 1 begin */
- dgap_err("unexpected config_begin\n");
- return(-1);
-
- case END:
- return(0);
-
- case BOARD: /* board info */
- if (dgap_checknode(p))
- return(-1);
- if ( (p->next = dgap_newnode(BNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
-
- p->u.board.status = dgap_savestring("No");
- line = conc = NULL;
- brd = p;
- linecnt = -1;
- break;
-
- case APORT2_920P: /* AccelePort_4 */
- if (p->type != BNODE) {
- dgap_err("unexpected Digi_2r_920 string");
- return(-1);
- }
- p->u.board.type = APORT2_920P;
- p->u.board.v_type = 1;
- DPR_INIT(("Adding Digi_2r_920 PCI to config...\n"));
- break;
-
- case APORT4_920P: /* AccelePort_4 */
- if (p->type != BNODE) {
- dgap_err("unexpected Digi_4r_920 string");
- return(-1);
- }
- p->u.board.type = APORT4_920P;
- p->u.board.v_type = 1;
- DPR_INIT(("Adding Digi_4r_920 PCI to config...\n"));
- break;
-
- case APORT8_920P: /* AccelePort_8 */
- if (p->type != BNODE) {
- dgap_err("unexpected Digi_8r_920 string");
- return(-1);
- }
- p->u.board.type = APORT8_920P;
- p->u.board.v_type = 1;
- DPR_INIT(("Adding Digi_8r_920 PCI to config...\n"));
- break;
-
- case PAPORT4: /* AccelePort_4 PCI */
- if (p->type != BNODE) {
- dgap_err("unexpected Digi_4r(PCI) string");
- return(-1);
- }
- p->u.board.type = PAPORT4;
- p->u.board.v_type = 1;
- DPR_INIT(("Adding Digi_4r PCI to config...\n"));
- break;
-
- case PAPORT8: /* AccelePort_8 PCI */
- if (p->type != BNODE) {
- dgap_err("unexpected Digi_8r string");
- return(-1);
- }
- p->u.board.type = PAPORT8;
- p->u.board.v_type = 1;
- DPR_INIT(("Adding Digi_8r PCI to config...\n"));
- break;
-
- case PCX: /* PCI C/X */
- if (p->type != BNODE) {
- dgap_err("unexpected Digi_C/X_(PCI) string");
- return(-1);
- }
- p->u.board.type = PCX;
- p->u.board.v_type = 1;
- p->u.board.conc1 = 0;
- p->u.board.conc2 = 0;
- p->u.board.module1 = 0;
- p->u.board.module2 = 0;
- DPR_INIT(("Adding PCI C/X to config...\n"));
- break;
-
- case PEPC: /* PCI EPC/X */
- if (p->type != BNODE) {
- dgap_err("unexpected \"Digi_EPC/X_(PCI)\" string");
- return(-1);
- }
- p->u.board.type = PEPC;
- p->u.board.v_type = 1;
- p->u.board.conc1 = 0;
- p->u.board.conc2 = 0;
- p->u.board.module1 = 0;
- p->u.board.module2 = 0;
- DPR_INIT(("Adding PCI EPC/X to config...\n"));
- break;
-
- case PPCM: /* PCI/Xem */
- if (p->type != BNODE) {
- dgap_err("unexpected PCI/Xem string");
- return(-1);
- }
- p->u.board.type = PPCM;
- p->u.board.v_type = 1;
- p->u.board.conc1 = 0;
- p->u.board.conc2 = 0;
- DPR_INIT(("Adding PCI XEM to config...\n"));
- break;
-
- case IO: /* i/o port */
- if (p->type != BNODE) {
- dgap_err("IO port only vaild for boards");
- return(-1);
- }
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.board.portstr = dgap_savestring(s);
- p->u.board.port = (short)simple_strtol(s, &s2, 0);
- if ((short)strlen(s) > (short)(s2 - s)) {
- dgap_err("bad number for IO port");
- return(-1);
- }
- p->u.board.v_port = 1;
- DPR_INIT(("Adding IO (%s) to config...\n", s));
- break;
-
- case MEM: /* memory address */
- if (p->type != BNODE) {
- dgap_err("memory address only vaild for boards");
- return(-1);
- }
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.board.addrstr = dgap_savestring(s);
- p->u.board.addr = simple_strtoul(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for memory address");
- return(-1);
- }
- p->u.board.v_addr = 1;
- DPR_INIT(("Adding MEM (%s) to config...\n", s));
- break;
-
- case PCIINFO: /* pci information */
- if (p->type != BNODE) {
- dgap_err("memory address only vaild for boards");
- return(-1);
- }
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.board.pcibusstr = dgap_savestring(s);
- p->u.board.pcibus = simple_strtoul(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for pci bus");
- return(-1);
- }
- p->u.board.v_pcibus = 1;
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.board.pcislotstr = dgap_savestring(s);
- p->u.board.pcislot = simple_strtoul(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for pci slot");
- return(-1);
- }
- p->u.board.v_pcislot = 1;
-
- DPR_INIT(("Adding PCIINFO (%s %s) to config...\n", p->u.board.pcibusstr,
- p->u.board.pcislotstr));
- break;
-
- case METHOD:
- if (p->type != BNODE) {
- dgap_err("install method only vaild for boards");
- return(-1);
- }
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.board.method = dgap_savestring(s);
- p->u.board.v_method = 1;
- DPR_INIT(("Adding METHOD (%s) to config...\n", s));
- break;
-
- case STATUS:
- if (p->type != BNODE) {
- dgap_err("config status only vaild for boards");
- return(-1);
- }
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.board.status = dgap_savestring(s);
- DPR_INIT(("Adding STATUS (%s) to config...\n", s));
- break;
-
- case NPORTS: /* number of ports */
- if (p->type == BNODE) {
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.board.nport = (char)simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for number of ports");
- return(-1);
- }
- p->u.board.v_nport = 1;
- } else if (p->type == CNODE) {
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.conc.nport = (char)simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for number of ports");
- return(-1);
- }
- p->u.conc.v_nport = 1;
- } else if (p->type == MNODE) {
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.module.nport = (char)simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for number of ports");
- return(-1);
- }
- p->u.module.v_nport = 1;
- } else {
- dgap_err("nports only valid for concentrators or modules");
- return(-1);
- }
- DPR_INIT(("Adding NPORTS (%s) to config...\n", s));
- break;
-
- case ID: /* letter ID used in tty name */
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
-
- p->u.board.status = dgap_savestring(s);
-
- if (p->type == CNODE) {
- p->u.conc.id = dgap_savestring(s);
- p->u.conc.v_id = 1;
- } else if (p->type == MNODE) {
- p->u.module.id = dgap_savestring(s);
- p->u.module.v_id = 1;
- } else {
- dgap_err("id only valid for concentrators or modules");
- return(-1);
- }
- DPR_INIT(("Adding ID (%s) to config...\n", s));
- break;
-
- case STARTO: /* start offset of ID */
- if (p->type == BNODE) {
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.board.start = simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for start of tty count");
- return(-1);
- }
- p->u.board.v_start = 1;
- } else if (p->type == CNODE) {
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.conc.start = simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for start of tty count");
- return(-1);
- }
- p->u.conc.v_start = 1;
- } else if (p->type == MNODE) {
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.module.start = simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for start of tty count");
- return(-1);
- }
- p->u.module.v_start = 1;
- } else {
- dgap_err("start only valid for concentrators or modules");
- return(-1);
- }
- DPR_INIT(("Adding START (%s) to config...\n", s));
- break;
-
- case TTYN: /* tty name prefix */
- if (dgap_checknode(p))
- return(-1);
- if ( (p->next = dgap_newnode(TNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- if ( (s = dgap_getword(in)) == NULL ) {
- dgap_err("unexpeced end of file");
- return(-1);
- }
- if ( (p->u.ttyname = dgap_savestring(s)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- DPR_INIT(("Adding TTY (%s) to config...\n", s));
- break;
-
- case CU: /* cu name prefix */
- if (dgap_checknode(p))
- return(-1);
- if ( (p->next = dgap_newnode(CUNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- if ( (s = dgap_getword(in)) == NULL ) {
- dgap_err("unexpeced end of file");
- return(-1);
- }
- if ( (p->u.cuname = dgap_savestring(s)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- DPR_INIT(("Adding CU (%s) to config...\n", s));
- break;
-
- case LINE: /* line information */
- if (dgap_checknode(p))
- return(-1);
- if (brd == NULL) {
- dgap_err("must specify board before line info");
- return(-1);
- }
- switch (brd->u.board.type) {
- case PPCM:
- dgap_err("line not vaild for PC/em");
- return(-1);
- }
- if ( (p->next = dgap_newnode(LNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- conc = NULL;
- line = p;
- linecnt++;
- DPR_INIT(("Adding LINE to config...\n"));
- break;
-
- case CONC: /* concentrator information */
- if (dgap_checknode(p))
- return(-1);
- if (line == NULL) {
- dgap_err("must specify line info before concentrator");
- return(-1);
- }
- if ( (p->next = dgap_newnode(CNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- conc = p;
- if (linecnt)
- brd->u.board.conc2++;
- else
- brd->u.board.conc1++;
-
- DPR_INIT(("Adding CONC to config...\n"));
- break;
-
- case CX: /* c/x type concentrator */
- if (p->type != CNODE) {
- dgap_err("cx only valid for concentrators");
- return(-1);
- }
- p->u.conc.type = CX;
- p->u.conc.v_type = 1;
- DPR_INIT(("Adding CX to config...\n"));
- break;
-
- case EPC: /* epc type concentrator */
- if (p->type != CNODE) {
- dgap_err("cx only valid for concentrators");
- return(-1);
- }
- p->u.conc.type = EPC;
- p->u.conc.v_type = 1;
- DPR_INIT(("Adding EPC to config...\n"));
- break;
-
- case MOD: /* EBI module */
- if (dgap_checknode(p))
- return(-1);
- if (brd == NULL) {
- dgap_err("must specify board info before EBI modules");
- return(-1);
- }
- switch (brd->u.board.type) {
- case PPCM:
- linecnt = 0;
- break;
- default:
- if (conc == NULL) {
- dgap_err("must specify concentrator info before EBI module");
- return(-1);
- }
- }
- if ( (p->next = dgap_newnode(MNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- if (linecnt)
- brd->u.board.module2++;
- else
- brd->u.board.module1++;
-
- DPR_INIT(("Adding MOD to config...\n"));
- break;
-
- case PORTS: /* ports type EBI module */
- if (p->type != MNODE) {
- dgap_err("ports only valid for EBI modules");
- return(-1);
- }
- p->u.module.type = PORTS;
- p->u.module.v_type = 1;
- DPR_INIT(("Adding PORTS to config...\n"));
- break;
-
- case MODEM: /* ports type EBI module */
- if (p->type != MNODE) {
- dgap_err("modem only valid for modem modules");
- return(-1);
- }
- p->u.module.type = MODEM;
- p->u.module.v_type = 1;
- DPR_INIT(("Adding MODEM to config...\n"));
- break;
-
- case CABLE:
- if (p->type == LNODE) {
- if ((s = dgap_getword(in)) == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.line.cable = dgap_savestring(s);
- p->u.line.v_cable = 1;
- }
- DPR_INIT(("Adding CABLE (%s) to config...\n", s));
- break;
-
- case SPEED: /* sync line speed indication */
- if (p->type == LNODE) {
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.line.speed = (char)simple_strtol(s, &s2, 0);
- if ((short)strlen(s) > (short)(s2 - s)) {
- dgap_err("bad number for line speed");
- return(-1);
- }
- p->u.line.v_speed = 1;
- } else if (p->type == CNODE) {
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.conc.speed = (char)simple_strtol(s, &s2, 0);
- if ((short)strlen(s) > (short)(s2 - s)) {
- dgap_err("bad number for line speed");
- return(-1);
- }
- p->u.conc.v_speed = 1;
- } else {
- dgap_err("speed valid only for lines or concentrators.");
- return(-1);
- }
- DPR_INIT(("Adding SPEED (%s) to config...\n", s));
- break;
-
- case CONNECT:
- if (p->type == CNODE) {
- if ((s = dgap_getword(in)) == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.conc.connect = dgap_savestring(s);
- p->u.conc.v_connect = 1;
- }
- DPR_INIT(("Adding CONNECT (%s) to config...\n", s));
- break;
- case PRINT: /* transparent print name prefix */
- if (dgap_checknode(p))
- return(-1);
- if ( (p->next = dgap_newnode(PNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- if ( (s = dgap_getword(in)) == NULL ) {
- dgap_err("unexpeced end of file");
- return(-1);
- }
- if ( (p->u.printname = dgap_savestring(s)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- DPR_INIT(("Adding PRINT (%s) to config...\n", s));
- break;
-
- case CMAJOR: /* major number */
- if (dgap_checknode(p))
- return(-1);
- if ( (p->next = dgap_newnode(JNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.majornumber = simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for major number");
- return(-1);
- }
- DPR_INIT(("Adding CMAJOR (%s) to config...\n", s));
- break;
-
- case ALTPIN: /* altpin setting */
- if (dgap_checknode(p))
- return(-1);
- if ( (p->next = dgap_newnode(ANODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.altpin = simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for altpin");
- return(-1);
- }
- DPR_INIT(("Adding ALTPIN (%s) to config...\n", s));
- break;
-
- case USEINTR: /* enable interrupt setting */
- if (dgap_checknode(p))
- return(-1);
- if ( (p->next = dgap_newnode(INTRNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.useintr = simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for useintr");
- return(-1);
- }
- DPR_INIT(("Adding USEINTR (%s) to config...\n", s));
- break;
-
- case TTSIZ: /* size of tty structure */
- if (dgap_checknode(p))
- return(-1);
- if ( (p->next = dgap_newnode(TSNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.ttysize = simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for ttysize");
- return(-1);
- }
- DPR_INIT(("Adding TTSIZ (%s) to config...\n", s));
- break;
-
- case CHSIZ: /* channel structure size */
- if (dgap_checknode(p))
- return(-1);
- if ( (p->next = dgap_newnode(CSNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.chsize = simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for chsize");
- return(-1);
- }
- DPR_INIT(("Adding CHSIZE (%s) to config...\n", s));
- break;
-
- case BSSIZ: /* board structure size */
- if (dgap_checknode(p))
- return(-1);
- if ( (p->next = dgap_newnode(BSNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.bssize = simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for bssize");
- return(-1);
- }
- DPR_INIT(("Adding BSSIZ (%s) to config...\n", s));
- break;
-
- case UNTSIZ: /* sched structure size */
- if (dgap_checknode(p))
- return(-1);
- if ( (p->next = dgap_newnode(USNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.unsize = simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for schedsize");
- return(-1);
- }
- DPR_INIT(("Adding UNTSIZ (%s) to config...\n", s));
- break;
-
- case F2SIZ: /* f2200 structure size */
- if (dgap_checknode(p))
- return(-1);
- if ( (p->next = dgap_newnode(FSNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.f2size = simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for f2200size");
- return(-1);
- }
- DPR_INIT(("Adding F2SIZ (%s) to config...\n", s));
- break;
-
- case VPSIZ: /* vpix structure size */
- if (dgap_checknode(p))
- return(-1);
- if ( (p->next = dgap_newnode(VSNODE)) == NULL ) {
- dgap_err("out of memory");
- return(-1);
- }
- p = p->next;
- s = dgap_getword(in);
- if (s == NULL) {
- dgap_err("unexpected end of file");
- return(-1);
- }
- p->u.vpixsize = simple_strtol(s, &s2, 0);
- if ((int)strlen(s) > (int)(s2 - s)) {
- dgap_err("bad number for vpixsize");
- return(-1);
- }
- DPR_INIT(("Adding VPSIZ (%s) to config...\n", s));
- break;
- }
- }
-}
-
-
-/*
- * dgap_sindex: much like index(), but it looks for a match of any character in
- * the group, and returns that position. If the first character is a ^, then
- * this will match the first occurrence not in that group.
- */
-static char *dgap_sindex (char *string, char *group)
-{
- char *ptr;
-
- if (!string || !group)
- return (char *) NULL;
-
- if (*group == '^') {
- group++;
- for (; *string; string++) {
- for (ptr = group; *ptr; ptr++) {
- if (*ptr == *string)
- break;
- }
- if (*ptr == '\0')
- return string;
- }
- }
- else {
- for (; *string; string++) {
- for (ptr = group; *ptr; ptr++) {
- if (*ptr == *string)
- return string;
- }
- }
- }
-
- return (char *) NULL;
-}
-
-
-/*
- * Get a token from the input file; return 0 if end of file is reached
- */
-static int dgap_gettok(char **in, struct cnode *p)
-{
- char *w;
- struct toklist *t;
-
- if (strstr(dgap_cword, "boar")) {
- w = dgap_getword(in);
- snprintf(dgap_cword, MAXCWORD, "%s", w);
- for (t = dgap_tlist; t->token != 0; t++) {
- if ( !strcmp(w, t->string)) {
- return(t->token);
- }
- }
- dgap_err("board !!type not specified");
- return(1);
- }
- else {
- while ( (w = dgap_getword(in)) != NULL ) {
- snprintf(dgap_cword, MAXCWORD, "%s", w);
- for (t = dgap_tlist; t->token != 0; t++) {
- if ( !strcmp(w, t->string) )
- return(t->token);
- }
- }
- return(0);
- }
-}
-
-
-/*
- * get a word from the input stream, also keep track of current line number.
- * words are separated by whitespace.
- */
-static char *dgap_getword(char **in)
-{
- char *ret_ptr = *in;
-
- char *ptr = dgap_sindex(*in, " \t\n");
-
- /* If no word found, return null */
- if (!ptr)
- return NULL;
-
- /* Mark new location for our buffer */
- *ptr = '\0';
- *in = ptr + 1;
-
- /* Eat any extra spaces/tabs/newlines that might be present */
- while (*in && **in && ((**in == ' ') || (**in == '\t') || (**in == '\n'))) {
- **in = '\0';
- *in = *in + 1;
- }
-
- return ret_ptr;
-}
-
-
-/*
- * print an error message, giving the line number in the file where
- * the error occurred.
- */
-static void dgap_err(char *s)
-{
- printk("DGAP: parse: %s\n", s);
-}
-
-
-/*
- * allocate a new configuration node of type t
- */
-static struct cnode *dgap_newnode(int t)
-{
- struct cnode *n;
-
- n = kmalloc(sizeof(struct cnode), GFP_ATOMIC);
- if (n != NULL) {
- memset((char *)n, 0, sizeof(struct cnode));
- n->type = t;
- }
- return(n);
-}
-
-
-/*
- * dgap_checknode: see if all the necessary info has been supplied for a node
- * before creating the next node.
- */
-static int dgap_checknode(struct cnode *p)
-{
- switch (p->type) {
- case BNODE:
- if (p->u.board.v_type == 0) {
- dgap_err("board type !not specified");
- return(1);
- }
-
- return(0);
-
- case LNODE:
- if (p->u.line.v_speed == 0) {
- dgap_err("line speed not specified");
- return(1);
- }
- return(0);
-
- case CNODE:
- if (p->u.conc.v_type == 0) {
- dgap_err("concentrator type not specified");
- return(1);
- }
- if (p->u.conc.v_speed == 0) {
- dgap_err("concentrator line speed not specified");
- return(1);
- }
- if (p->u.conc.v_nport == 0) {
- dgap_err("number of ports on concentrator not specified");
- return(1);
- }
- if (p->u.conc.v_id == 0) {
- dgap_err("concentrator id letter not specified");
- return(1);
- }
- return(0);
-
- case MNODE:
- if (p->u.module.v_type == 0) {
- dgap_err("EBI module type not specified");
- return(1);
- }
- if (p->u.module.v_nport == 0) {
- dgap_err("number of ports on EBI module not specified");
- return(1);
- }
- if (p->u.module.v_id == 0) {
- dgap_err("EBI module id letter not specified");
- return(1);
- }
- return(0);
- }
- return(0);
-}
-
-/*
- * save a string somewhere
- */
-static char *dgap_savestring(char *s)
-{
- char *p;
- if ( (p = kmalloc(strlen(s) + 1, GFP_ATOMIC) ) != NULL) {
- strcpy(p, s);
- }
- return(p);
-}
-
-
-/*
- * Given a board pointer, returns whether we should use interrupts or not.
- */
-uint dgap_config_get_useintr(struct board_t *bd)
-{
- struct cnode *p = NULL;
-
- if (!bd)
- return(0);
-
- for (p = bd->bd_config; p; p = p->next) {
- switch (p->type) {
- case INTRNODE:
- /*
- * check for pcxr types.
- */
- return p->u.useintr;
- default:
- break;
- }
- }
-
- /* If not found, then don't turn on interrupts. */
- return 0;
-}
-
-
-/*
- * Given a board pointer, returns whether we turn on altpin or not.
- */
-uint dgap_config_get_altpin(struct board_t *bd)
-{
- struct cnode *p = NULL;
-
- if (!bd)
- return(0);
-
- for (p = bd->bd_config; p; p = p->next) {
- switch (p->type) {
- case ANODE:
- /*
- * check for pcxr types.
- */
- return p->u.altpin;
- default:
- break;
- }
- }
-
- /* If not found, then don't turn on interrupts. */
- return 0;
-}
-
-
-
-/*
- * Given a specific type of board, if found, detached link and
- * returns the first occurrence in the list.
- */
-struct cnode *dgap_find_config(int type, int bus, int slot)
-{
- struct cnode *p, *prev = NULL, *prev2 = NULL, *found = NULL;
-
- p = &dgap_head;
-
- while (p->next != NULL) {
- prev = p;
- p = p->next;
-
- if (p->type == BNODE) {
-
- if (p->u.board.type == type) {
-
- if (p->u.board.v_pcibus && p->u.board.pcibus != bus) {
- DPR(("Found matching board, but wrong bus position. System says bus %d, we want bus %ld\n",
- bus, p->u.board.pcibus));
- continue;
- }
- if (p->u.board.v_pcislot && p->u.board.pcislot != slot) {
- DPR_INIT(("Found matching board, but wrong slot position. System says slot %d, we want slot %ld\n",
- slot, p->u.board.pcislot));
- continue;
- }
-
- DPR_INIT(("Matched type in config file\n"));
-
- found = p;
- /*
- * Keep walking thru the list till we find the next board.
- */
- while (p->next != NULL) {
- prev2 = p;
- p = p->next;
- if (p->type == BNODE) {
-
- /*
- * Mark the end of our 1 board chain of configs.
- */
- prev2->next = NULL;
-
- /*
- * Link the "next" board to the previous board,
- * effectively "unlinking" our board from the main config.
- */
- prev->next = p;
-
- return found;
- }
- }
- /*
- * It must be the last board in the list.
- */
- prev->next = NULL;
- return found;
- }
- }
- }
- return NULL;
-}
-
-/*
- * Given a board pointer, walks the config link, counting up
- * all ports user specified should be on the board.
- * (This does NOT mean they are all actually present right now tho)
- */
-uint dgap_config_get_number_of_ports(struct board_t *bd)
-{
- int count = 0;
- struct cnode *p = NULL;
-
- if (!bd)
- return(0);
-
- for (p = bd->bd_config; p; p = p->next) {
-
- switch (p->type) {
- case BNODE:
- /*
- * check for pcxr types.
- */
- if (p->u.board.type > EPCFE)
- count += p->u.board.nport;
- break;
- case CNODE:
- count += p->u.conc.nport;
- break;
- case MNODE:
- count += p->u.module.nport;
- break;
- }
- }
- return (count);
-}
-
-char *dgap_create_config_string(struct board_t *bd, char *string)
-{
- char *ptr = string;
- struct cnode *p = NULL;
- struct cnode *q = NULL;
- int speed;
-
- if (!bd) {
- *ptr = 0xff;
- return string;
- }
-
- for (p = bd->bd_config; p; p = p->next) {
-
- switch (p->type) {
- case LNODE:
- *ptr = '\0';
- ptr++;
- *ptr = p->u.line.speed;
- ptr++;
- break;
- case CNODE:
- /*
- * Because the EPC/con concentrators can have EM modules
- * hanging off of them, we have to walk ahead in the list
- * and keep adding the number of ports on each EM to the config.
- * UGH!
- */
- speed = p->u.conc.speed;
- q = p->next;
- if ((q != NULL) && (q->type == MNODE) ) {
- *ptr = (p->u.conc.nport + 0x80);
- ptr++;
- p = q;
- while ((q->next != NULL) && (q->next->type) == MNODE) {
- *ptr = (q->u.module.nport + 0x80);
- ptr++;
- p = q;
- q = q->next;
- }
- *ptr = q->u.module.nport;
- ptr++;
- } else {
- *ptr = p->u.conc.nport;
- ptr++;
- }
-
- *ptr = speed;
- ptr++;
- break;
- }
- }
-
- *ptr = 0xff;
- return string;
-}
-
-
-
-char *dgap_get_config_letters(struct board_t *bd, char *string)
-{
- int found = FALSE;
- char *ptr = string;
- struct cnode *cptr = NULL;
- int len = 0;
- int left = MAXTTYNAMELEN;
-
- if (!bd) {
- return "<NULL>";
- }
-
- for (cptr = bd->bd_config; cptr; cptr = cptr->next) {
-
- if ((cptr->type == BNODE) &&
- ((cptr->u.board.type == APORT2_920P) || (cptr->u.board.type == APORT4_920P) ||
- (cptr->u.board.type == APORT8_920P) || (cptr->u.board.type == PAPORT4) ||
- (cptr->u.board.type == PAPORT8))) {
-
- found = TRUE;
- }
-
- if (cptr->type == TNODE && found == TRUE) {
- char *ptr1;
- if (strstr(cptr->u.ttyname, "tty")) {
- ptr1 = cptr->u.ttyname;
- ptr1 += 3;
- }
- else {
- ptr1 = cptr->u.ttyname;
- }
- if (ptr1) {
- len = snprintf(ptr, left, "%s", ptr1);
- left -= len;
- ptr += len;
- if (left <= 0)
- break;
- }
- }
-
- if (cptr->type == CNODE) {
- if (cptr->u.conc.id) {
- len = snprintf(ptr, left, "%s", cptr->u.conc.id);
- left -= len;
- ptr += len;
- if (left <= 0)
- break;
- }
- }
-
- if (cptr->type == MNODE) {
- if (cptr->u.module.id) {
- len = snprintf(ptr, left, "%s", cptr->u.module.id);
- left -= len;
- ptr += len;
- if (left <= 0)
- break;
- }
- }
- }
-
- return string;
-}
diff --git a/drivers/staging/dgap/dgap_parse.h b/drivers/staging/dgap/dgap_parse.h
deleted file mode 100644
index 8128c47343cb..000000000000
--- a/drivers/staging/dgap/dgap_parse.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
- */
-
-#ifndef _DGAP_PARSE_H
-#define _DGAP_PARSE_H
-
-#include "dgap_driver.h"
-
-extern int dgap_parsefile(char **in, int Remove);
-extern struct cnode *dgap_find_config(int type, int bus, int slot);
-extern uint dgap_config_get_number_of_ports(struct board_t *bd);
-extern char *dgap_create_config_string(struct board_t *bd, char *string);
-extern char *dgap_get_config_letters(struct board_t *bd, char *string);
-extern uint dgap_config_get_useintr(struct board_t *bd);
-extern uint dgap_config_get_altpin(struct board_t *bd);
-
-#endif
diff --git a/drivers/staging/dgap/dgap_pci.h b/drivers/staging/dgap/dgap_pci.h
deleted file mode 100644
index 05ed374f08e1..000000000000
--- a/drivers/staging/dgap/dgap_pci.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
- */
-
-/* $Id: dgap_pci.h,v 1.1 2009/10/23 14:01:57 markh Exp $ */
-
-#ifndef __DGAP_PCI_H
-#define __DGAP_PCI_H
-
-#define PCIMAX 32 /* maximum number of PCI boards */
-
-#define DIGI_VID 0x114F
-
-#define PCI_DEVICE_EPC_DID 0x0002
-#define PCI_DEVICE_XEM_DID 0x0004
-#define PCI_DEVICE_XR_DID 0x0005
-#define PCI_DEVICE_CX_DID 0x0006
-#define PCI_DEVICE_XRJ_DID 0x0009 /* PLX-based Xr adapter */
-#define PCI_DEVICE_XR_IBM_DID 0x0011 /* IBM 8-port Async Adapter */
-#define PCI_DEVICE_XR_BULL_DID 0x0013 /* BULL 8-port Async Adapter */
-#define PCI_DEVICE_XR_SAIP_DID 0x001c /* SAIP card - Xr adapter */
-#define PCI_DEVICE_XR_422_DID 0x0012 /* Xr-422 */
-#define PCI_DEVICE_920_2_DID 0x0034 /* XR-Plus 920 K, 2 port */
-#define PCI_DEVICE_920_4_DID 0x0026 /* XR-Plus 920 K, 4 port */
-#define PCI_DEVICE_920_8_DID 0x0027 /* XR-Plus 920 K, 8 port */
-#define PCI_DEVICE_EPCJ_DID 0x000a /* PLX 9060 chip for PCI */
-#define PCI_DEVICE_CX_IBM_DID 0x001b /* IBM 128-port Async Adapter */
-#define PCI_DEVICE_920_8_HP_DID 0x0058 /* HP XR-Plus 920 K, 8 port */
-#define PCI_DEVICE_XEM_HP_DID 0x0059 /* HP Xem PCI */
-
-#define PCI_DEVICE_XEM_NAME "AccelePort XEM"
-#define PCI_DEVICE_CX_NAME "AccelePort CX"
-#define PCI_DEVICE_XR_NAME "AccelePort Xr"
-#define PCI_DEVICE_XRJ_NAME "AccelePort Xr (PLX)"
-#define PCI_DEVICE_XR_SAIP_NAME "AccelePort Xr (SAIP)"
-#define PCI_DEVICE_920_2_NAME "AccelePort Xr920 2 port"
-#define PCI_DEVICE_920_4_NAME "AccelePort Xr920 4 port"
-#define PCI_DEVICE_920_8_NAME "AccelePort Xr920 8 port"
-#define PCI_DEVICE_XR_422_NAME "AccelePort Xr 422"
-#define PCI_DEVICE_EPCJ_NAME "AccelePort EPC (PLX)"
-#define PCI_DEVICE_XR_BULL_NAME "AccelePort Xr (BULL)"
-#define PCI_DEVICE_XR_IBM_NAME "AccelePort Xr (IBM)"
-#define PCI_DEVICE_CX_IBM_NAME "AccelePort CX (IBM)"
-#define PCI_DEVICE_920_8_HP_NAME "AccelePort Xr920 8 port (HP)"
-#define PCI_DEVICE_XEM_HP_NAME "AccelePort XEM (HP)"
-
-
-/*
- * On the PCI boards, there is no IO space allocated
- * The I/O registers will be in the first 3 bytes of the
- * upper 2MB of the 4MB memory space. The board memory
- * will be mapped into the low 2MB of the 4MB memory space
- */
-
-/* Potential location of PCI Bios from E0000 to FFFFF*/
-#define PCI_BIOS_SIZE 0x00020000
-
-/* Size of Memory and I/O for PCI (4MB) */
-#define PCI_RAM_SIZE 0x00400000
-
-/* Size of Memory (2MB) */
-#define PCI_MEM_SIZE 0x00200000
-
-/* Max PCI Window Size (2MB) */
-#define PCI_WIN_SIZE 0x00200000
-
-#define PCI_WIN_SHIFT 21 /* 21 bits max */
-
-/* Offset of I/0 in Memory (2MB) */
-#define PCI_IO_OFFSET 0x00200000
-
-/* Size of IO (2MB) */
-#define PCI_IO_SIZE 0x00200000
-
-#endif
diff --git a/drivers/staging/dgap/dgap_sysfs.c b/drivers/staging/dgap/dgap_sysfs.c
deleted file mode 100644
index 7f4ec9a18293..000000000000
--- a/drivers/staging/dgap/dgap_sysfs.c
+++ /dev/null
@@ -1,793 +0,0 @@
-/*
- * Copyright 2004 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
- *
- * This is shared code between Digi's CVS archive and the
- * Linux Kernel sources.
- * Changing the source just for reformatting needlessly breaks
- * our CVS diff history.
- *
- * Send any bug fixes/changes to: Eng.Linux at digi dot com.
- * Thank you.
- *
- *
- *
- * $Id: dgap_sysfs.c,v 1.1 2009/10/23 14:01:57 markh Exp $
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/serial_reg.h>
-#include <linux/device.h>
-#include <linux/pci.h>
-#include <linux/kdev_t.h>
-
-#include "dgap_driver.h"
-#include "dgap_conf.h"
-#include "dgap_parse.h"
-
-
-static ssize_t dgap_driver_version_show(struct device_driver *ddp, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART);
-}
-static DRIVER_ATTR(version, S_IRUSR, dgap_driver_version_show, NULL);
-
-
-static ssize_t dgap_driver_boards_show(struct device_driver *ddp, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%d\n", dgap_NumBoards);
-}
-static DRIVER_ATTR(boards, S_IRUSR, dgap_driver_boards_show, NULL);
-
-
-static ssize_t dgap_driver_maxboards_show(struct device_driver *ddp, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS);
-}
-static DRIVER_ATTR(maxboards, S_IRUSR, dgap_driver_maxboards_show, NULL);
-
-
-static ssize_t dgap_driver_pollcounter_show(struct device_driver *ddp, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%ld\n", dgap_poll_counter);
-}
-static DRIVER_ATTR(pollcounter, S_IRUSR, dgap_driver_pollcounter_show, NULL);
-
-
-static ssize_t dgap_driver_state_show(struct device_driver *ddp, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%s\n", dgap_driver_state_text[dgap_driver_state]);
-}
-static DRIVER_ATTR(state, S_IRUSR, dgap_driver_state_show, NULL);
-
-
-static ssize_t dgap_driver_debug_show(struct device_driver *ddp, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "0x%x\n", dgap_debug);
-}
-
-static ssize_t dgap_driver_debug_store(struct device_driver *ddp, const char *buf, size_t count)
-{
- sscanf(buf, "0x%x\n", &dgap_debug);
- return count;
-}
-static DRIVER_ATTR(debug, (S_IRUSR | S_IWUSR), dgap_driver_debug_show, dgap_driver_debug_store);
-
-
-static ssize_t dgap_driver_rawreadok_show(struct device_driver *ddp, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "0x%x\n", dgap_rawreadok);
-}
-
-static ssize_t dgap_driver_rawreadok_store(struct device_driver *ddp, const char *buf, size_t count)
-{
- sscanf(buf, "0x%x\n", &dgap_rawreadok);
- return count;
-}
-static DRIVER_ATTR(rawreadok, (S_IRUSR | S_IWUSR), dgap_driver_rawreadok_show, dgap_driver_rawreadok_store);
-
-
-static ssize_t dgap_driver_pollrate_show(struct device_driver *ddp, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%dms\n", dgap_poll_tick);
-}
-
-static ssize_t dgap_driver_pollrate_store(struct device_driver *ddp, const char *buf, size_t count)
-{
- sscanf(buf, "%d\n", &dgap_poll_tick);
- return count;
-}
-static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgap_driver_pollrate_show, dgap_driver_pollrate_store);
-
-
-void dgap_create_driver_sysfiles(struct pci_driver *dgap_driver)
-{
- int rc = 0;
- struct device_driver *driverfs = &dgap_driver->driver;
-
- rc |= driver_create_file(driverfs, &driver_attr_version);
- rc |= driver_create_file(driverfs, &driver_attr_boards);
- rc |= driver_create_file(driverfs, &driver_attr_maxboards);
- rc |= driver_create_file(driverfs, &driver_attr_debug);
- rc |= driver_create_file(driverfs, &driver_attr_rawreadok);
- rc |= driver_create_file(driverfs, &driver_attr_pollrate);
- rc |= driver_create_file(driverfs, &driver_attr_pollcounter);
- rc |= driver_create_file(driverfs, &driver_attr_state);
- if (rc) {
- printk(KERN_ERR "DGAP: sysfs driver_create_file failed!\n");
- }
-}
-
-
-void dgap_remove_driver_sysfiles(struct pci_driver *dgap_driver)
-{
- struct device_driver *driverfs = &dgap_driver->driver;
- driver_remove_file(driverfs, &driver_attr_version);
- driver_remove_file(driverfs, &driver_attr_boards);
- driver_remove_file(driverfs, &driver_attr_maxboards);
- driver_remove_file(driverfs, &driver_attr_debug);
- driver_remove_file(driverfs, &driver_attr_rawreadok);
- driver_remove_file(driverfs, &driver_attr_pollrate);
- driver_remove_file(driverfs, &driver_attr_pollcounter);
- driver_remove_file(driverfs, &driver_attr_state);
-}
-
-
-#define DGAP_VERIFY_BOARD(p, bd) \
- if (!p) \
- return (0); \
- \
- bd = dev_get_drvdata(p); \
- if (!bd || bd->magic != DGAP_BOARD_MAGIC) \
- return (0); \
- if (bd->state != BOARD_READY) \
- return (0); \
-
-
-static ssize_t dgap_ports_state_show(struct device *p, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- int count = 0;
- int i = 0;
-
- DGAP_VERIFY_BOARD(p, bd);
-
- for (i = 0; i < bd->nasync; i++) {
- count += snprintf(buf + count, PAGE_SIZE - count,
- "%d %s\n", bd->channels[i]->ch_portnum,
- bd->channels[i]->ch_open_count ? "Open" : "Closed");
- }
- return count;
-}
-static DEVICE_ATTR(ports_state, S_IRUSR, dgap_ports_state_show, NULL);
-
-
-static ssize_t dgap_ports_baud_show(struct device *p, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- int count = 0;
- int i = 0;
-
- DGAP_VERIFY_BOARD(p, bd);
-
- for (i = 0; i < bd->nasync; i++) {
- count += snprintf(buf + count, PAGE_SIZE - count,
- "%d %d\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_baud_info);
- }
- return count;
-}
-static DEVICE_ATTR(ports_baud, S_IRUSR, dgap_ports_baud_show, NULL);
-
-
-static ssize_t dgap_ports_msignals_show(struct device *p, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- int count = 0;
- int i = 0;
-
- DGAP_VERIFY_BOARD(p, bd);
-
- for (i = 0; i < bd->nasync; i++) {
- if (bd->channels[i]->ch_open_count) {
- count += snprintf(buf + count, PAGE_SIZE - count,
- "%d %s %s %s %s %s %s\n", bd->channels[i]->ch_portnum,
- (bd->channels[i]->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
- (bd->channels[i]->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
- (bd->channels[i]->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
- (bd->channels[i]->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
- (bd->channels[i]->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
- (bd->channels[i]->ch_mistat & UART_MSR_RI) ? "RI" : "");
- } else {
- count += snprintf(buf + count, PAGE_SIZE - count,
- "%d\n", bd->channels[i]->ch_portnum);
- }
- }
- return count;
-}
-static DEVICE_ATTR(ports_msignals, S_IRUSR, dgap_ports_msignals_show, NULL);
-
-
-static ssize_t dgap_ports_iflag_show(struct device *p, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- int count = 0;
- int i = 0;
-
- DGAP_VERIFY_BOARD(p, bd);
-
- for (i = 0; i < bd->nasync; i++) {
- count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
- bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_iflag);
- }
- return count;
-}
-static DEVICE_ATTR(ports_iflag, S_IRUSR, dgap_ports_iflag_show, NULL);
-
-
-static ssize_t dgap_ports_cflag_show(struct device *p, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- int count = 0;
- int i = 0;
-
- DGAP_VERIFY_BOARD(p, bd);
-
- for (i = 0; i < bd->nasync; i++) {
- count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
- bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_cflag);
- }
- return count;
-}
-static DEVICE_ATTR(ports_cflag, S_IRUSR, dgap_ports_cflag_show, NULL);
-
-
-static ssize_t dgap_ports_oflag_show(struct device *p, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- int count = 0;
- int i = 0;
-
- DGAP_VERIFY_BOARD(p, bd);
-
- for (i = 0; i < bd->nasync; i++) {
- count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
- bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_oflag);
- }
- return count;
-}
-static DEVICE_ATTR(ports_oflag, S_IRUSR, dgap_ports_oflag_show, NULL);
-
-
-static ssize_t dgap_ports_lflag_show(struct device *p, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- int count = 0;
- int i = 0;
-
- DGAP_VERIFY_BOARD(p, bd);
-
- for (i = 0; i < bd->nasync; i++) {
- count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
- bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_lflag);
- }
- return count;
-}
-static DEVICE_ATTR(ports_lflag, S_IRUSR, dgap_ports_lflag_show, NULL);
-
-
-static ssize_t dgap_ports_digi_flag_show(struct device *p, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- int count = 0;
- int i = 0;
-
- DGAP_VERIFY_BOARD(p, bd);
-
- for (i = 0; i < bd->nasync; i++) {
- count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
- bd->channels[i]->ch_portnum, bd->channels[i]->ch_digi.digi_flags);
- }
- return count;
-}
-static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgap_ports_digi_flag_show, NULL);
-
-
-static ssize_t dgap_ports_rxcount_show(struct device *p, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- int count = 0;
- int i = 0;
-
- DGAP_VERIFY_BOARD(p, bd);
-
- for (i = 0; i < bd->nasync; i++) {
- count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
- bd->channels[i]->ch_portnum, bd->channels[i]->ch_rxcount);
- }
- return count;
-}
-static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgap_ports_rxcount_show, NULL);
-
-
-static ssize_t dgap_ports_txcount_show(struct device *p, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- int count = 0;
- int i = 0;
-
- DGAP_VERIFY_BOARD(p, bd);
-
- for (i = 0; i < bd->nasync; i++) {
- count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
- bd->channels[i]->ch_portnum, bd->channels[i]->ch_txcount);
- }
- return count;
-}
-static DEVICE_ATTR(ports_txcount, S_IRUSR, dgap_ports_txcount_show, NULL);
-
-
-/* this function creates the sys files that will export each signal status
- * to sysfs each value will be put in a separate filename
- */
-void dgap_create_ports_sysfiles(struct board_t *bd)
-{
- int rc = 0;
-
- dev_set_drvdata(&bd->pdev->dev, bd);
- rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_state);
- rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud);
- rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
- rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
- rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
- rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
- rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
- rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
- rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
- rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
- if (rc) {
- printk(KERN_ERR "DGAP: sysfs device_create_file failed!\n");
- }
-}
-
-
-/* removes all the sys files created for that port */
-void dgap_remove_ports_sysfiles(struct board_t *bd)
-{
- device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state);
- device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud);
- device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
- device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
- device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
- device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
- device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
- device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
- device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
- device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
-}
-
-
-static ssize_t dgap_tty_state_show(struct device *d, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!d)
- return (0);
- un = dev_get_drvdata(d);
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (0);
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (0);
- if (bd->state != BOARD_READY)
- return (0);
-
- return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ? "Open" : "Closed");
-}
-static DEVICE_ATTR(state, S_IRUSR, dgap_tty_state_show, NULL);
-
-
-static ssize_t dgap_tty_baud_show(struct device *d, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!d)
- return (0);
- un = dev_get_drvdata(d);
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (0);
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (0);
- if (bd->state != BOARD_READY)
- return (0);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_baud_info);
-}
-static DEVICE_ATTR(baud, S_IRUSR, dgap_tty_baud_show, NULL);
-
-
-static ssize_t dgap_tty_msignals_show(struct device *d, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!d)
- return (0);
- un = dev_get_drvdata(d);
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (0);
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (0);
- if (bd->state != BOARD_READY)
- return (0);
-
- if (ch->ch_open_count) {
- return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n",
- (ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
- (ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
- (ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
- (ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
- (ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
- (ch->ch_mistat & UART_MSR_RI) ? "RI" : "");
- }
- return 0;
-}
-static DEVICE_ATTR(msignals, S_IRUSR, dgap_tty_msignals_show, NULL);
-
-
-static ssize_t dgap_tty_iflag_show(struct device *d, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!d)
- return (0);
- un = dev_get_drvdata(d);
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (0);
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (0);
- if (bd->state != BOARD_READY)
- return (0);
-
- return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag);
-}
-static DEVICE_ATTR(iflag, S_IRUSR, dgap_tty_iflag_show, NULL);
-
-
-static ssize_t dgap_tty_cflag_show(struct device *d, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!d)
- return (0);
- un = dev_get_drvdata(d);
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (0);
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (0);
- if (bd->state != BOARD_READY)
- return (0);
-
- return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag);
-}
-static DEVICE_ATTR(cflag, S_IRUSR, dgap_tty_cflag_show, NULL);
-
-
-static ssize_t dgap_tty_oflag_show(struct device *d, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!d)
- return (0);
- un = dev_get_drvdata(d);
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (0);
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (0);
- if (bd->state != BOARD_READY)
- return (0);
-
- return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag);
-}
-static DEVICE_ATTR(oflag, S_IRUSR, dgap_tty_oflag_show, NULL);
-
-
-static ssize_t dgap_tty_lflag_show(struct device *d, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!d)
- return (0);
- un = dev_get_drvdata(d);
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (0);
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (0);
- if (bd->state != BOARD_READY)
- return (0);
-
- return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag);
-}
-static DEVICE_ATTR(lflag, S_IRUSR, dgap_tty_lflag_show, NULL);
-
-
-static ssize_t dgap_tty_digi_flag_show(struct device *d, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!d)
- return (0);
- un = dev_get_drvdata(d);
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (0);
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (0);
- if (bd->state != BOARD_READY)
- return (0);
-
- return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags);
-}
-static DEVICE_ATTR(digi_flag, S_IRUSR, dgap_tty_digi_flag_show, NULL);
-
-
-static ssize_t dgap_tty_rxcount_show(struct device *d, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!d)
- return (0);
- un = dev_get_drvdata(d);
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (0);
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (0);
- if (bd->state != BOARD_READY)
- return (0);
-
- return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount);
-}
-static DEVICE_ATTR(rxcount, S_IRUSR, dgap_tty_rxcount_show, NULL);
-
-
-static ssize_t dgap_tty_txcount_show(struct device *d, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!d)
- return (0);
- un = dev_get_drvdata(d);
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (0);
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (0);
- if (bd->state != BOARD_READY)
- return (0);
-
- return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount);
-}
-static DEVICE_ATTR(txcount, S_IRUSR, dgap_tty_txcount_show, NULL);
-
-
-static ssize_t dgap_tty_name_show(struct device *d, struct device_attribute *attr, char *buf)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- int cn;
- int bn;
- struct cnode *cptr = NULL;
- int found = FALSE;
- int ncount = 0;
- int starto = 0;
- int i = 0;
-
- if (!d)
- return (0);
- un = dev_get_drvdata(d);
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (0);
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (0);
- if (bd->state != BOARD_READY)
- return (0);
-
- bn = bd->boardnum;
- cn = ch->ch_portnum;
-
- for (cptr = bd->bd_config; cptr; cptr = cptr->next) {
-
- if ((cptr->type == BNODE) &&
- ((cptr->u.board.type == APORT2_920P) || (cptr->u.board.type == APORT4_920P) ||
- (cptr->u.board.type == APORT8_920P) || (cptr->u.board.type == PAPORT4) ||
- (cptr->u.board.type == PAPORT8))) {
-
- found = TRUE;
- if (cptr->u.board.v_start)
- starto = cptr->u.board.start;
- else
- starto = 1;
- }
-
- if (cptr->type == TNODE && found == TRUE) {
- char *ptr1;
- if (strstr(cptr->u.ttyname, "tty")) {
- ptr1 = cptr->u.ttyname;
- ptr1 += 3;
- }
- else {
- ptr1 = cptr->u.ttyname;
- }
-
- for (i = 0; i < dgap_config_get_number_of_ports(bd); i++) {
- if (cn == i) {
- return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
- (un->un_type == DGAP_PRINT) ? "pr" : "tty",
- ptr1, i + starto);
- }
- }
- }
-
- if (cptr->type == CNODE) {
-
- for (i = 0; i < cptr->u.conc.nport; i++) {
- if (cn == (i + ncount)) {
-
- return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
- (un->un_type == DGAP_PRINT) ? "pr" : "tty",
- cptr->u.conc.id,
- i + (cptr->u.conc.v_start ? cptr->u.conc.start : 1));
- }
- }
-
- ncount += cptr->u.conc.nport;
- }
-
- if (cptr->type == MNODE) {
-
- for (i = 0; i < cptr->u.module.nport; i++) {
- if (cn == (i + ncount)) {
- return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
- (un->un_type == DGAP_PRINT) ? "pr" : "tty",
- cptr->u.module.id,
- i + (cptr->u.module.v_start ? cptr->u.module.start : 1));
- }
- }
-
- ncount += cptr->u.module.nport;
-
- }
- }
-
- return snprintf(buf, PAGE_SIZE, "%s_dgap_%d_%d\n",
- (un->un_type == DGAP_PRINT) ? "pr" : "tty", bn, cn);
-
-}
-static DEVICE_ATTR(custom_name, S_IRUSR, dgap_tty_name_show, NULL);
-
-
-static struct attribute *dgap_sysfs_tty_entries[] = {
- &dev_attr_state.attr,
- &dev_attr_baud.attr,
- &dev_attr_msignals.attr,
- &dev_attr_iflag.attr,
- &dev_attr_cflag.attr,
- &dev_attr_oflag.attr,
- &dev_attr_lflag.attr,
- &dev_attr_digi_flag.attr,
- &dev_attr_rxcount.attr,
- &dev_attr_txcount.attr,
- &dev_attr_custom_name.attr,
- NULL
-};
-
-
-static struct attribute_group dgap_tty_attribute_group = {
- .name = NULL,
- .attrs = dgap_sysfs_tty_entries,
-};
-
-
-
-
-void dgap_create_tty_sysfs(struct un_t *un, struct device *c)
-{
- int ret;
-
- ret = sysfs_create_group(&c->kobj, &dgap_tty_attribute_group);
- if (ret) {
- printk(KERN_ERR "dgap: failed to create sysfs tty device attributes.\n");
- sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group);
- return;
- }
-
- dev_set_drvdata(c, un);
-
-}
-
-
-void dgap_remove_tty_sysfs(struct device *c)
-{
- sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group);
-}
diff --git a/drivers/staging/dgap/dgap_sysfs.h b/drivers/staging/dgap/dgap_sysfs.h
deleted file mode 100644
index dde690eec5cf..000000000000
--- a/drivers/staging/dgap/dgap_sysfs.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
- */
-
-#ifndef __DGAP_SYSFS_H
-#define __DGAP_SYSFS_H
-
-#include "dgap_driver.h"
-
-#include <linux/device.h>
-
-struct board_t;
-struct channel_t;
-struct un_t;
-struct pci_driver;
-struct class_device;
-
-extern void dgap_create_ports_sysfiles(struct board_t *bd);
-extern void dgap_remove_ports_sysfiles(struct board_t *bd);
-
-extern void dgap_create_driver_sysfiles(struct pci_driver *);
-extern void dgap_remove_driver_sysfiles(struct pci_driver *);
-
-extern int dgap_tty_class_init(void);
-extern int dgap_tty_class_destroy(void);
-
-extern void dgap_create_tty_sysfs(struct un_t *un, struct device *c);
-extern void dgap_remove_tty_sysfs(struct device *c);
-
-
-#endif
diff --git a/drivers/staging/dgap/dgap_trace.c b/drivers/staging/dgap/dgap_trace.c
deleted file mode 100644
index a53db9e0a577..000000000000
--- a/drivers/staging/dgap/dgap_trace.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
- *
- * This is shared code between Digi's CVS archive and the
- * Linux Kernel sources.
- * Changing the source just for reformatting needlessly breaks
- * our CVS diff history.
- *
- * Send any bug fixes/changes to: Eng.Linux at digi dot com.
- * Thank you.
- *
- */
-
-/* $Id: dgap_trace.c,v 1.1 2009/10/23 14:01:57 markh Exp $ */
-
-#include <linux/kernel.h>
-#include <linux/sched.h> /* For jiffies, task states */
-#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
-#include <linux/vmalloc.h>
-
-#include "dgap_driver.h"
-#include "dgap_trace.h"
-
-#define TRC_TO_CONSOLE 1
-
-/* file level globals */
-static char *dgap_trcbuf; /* the ringbuffer */
-
-#if defined(TRC_TO_KMEM)
-static int dgap_trcbufi = 0; /* index of the tilde at the end of */
-#endif
-
-extern int dgap_trcbuf_size; /* size of the ringbuffer */
-
-#if defined(TRC_TO_KMEM)
-static DEFINE_SPINLOCK(dgap_tracef_lock);
-#endif
-
-#if 0
-
-#if !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE)
-void dgap_tracef(const char *fmt, ...)
-{
- return;
-}
-
-#else /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
-
-void dgap_tracef(const char *fmt, ...)
-{
- va_list ap;
- char buf[TRC_MAXMSG+1];
- size_t lenbuf;
- int i;
- static int failed = FALSE;
-# if defined(TRC_TO_KMEM)
- unsigned long flags;
-#endif
-
- if(failed)
- return;
-# if defined(TRC_TO_KMEM)
- DGAP_LOCK(dgap_tracef_lock, flags);
-#endif
-
- /* Format buf using fmt and arguments contained in ap. */
- va_start(ap, fmt);
- i = vsprintf(buf, fmt, ap);
- va_end(ap);
- lenbuf = strlen(buf);
-
-# if defined(TRC_TO_KMEM)
- {
- static int initd=0;
-
- /*
- * Now, in addition to (or instead of) printing this stuff out
- * (which is a buffered operation), also tuck it away into a
- * corner of memory which can be examined post-crash in kdb.
- */
- if (!initd) {
- dgap_trcbuf = (char *) vmalloc(dgap_trcbuf_size);
- if(!dgap_trcbuf) {
- failed = TRUE;
- printk("dgap: tracing init failed!\n");
- return;
- }
-
- memset(dgap_trcbuf, '\0', dgap_trcbuf_size);
- dgap_trcbufi = 0;
- initd++;
-
- printk("dgap: tracing enabled - " TRC_DTRC
- " 0x%lx 0x%x\n",
- (unsigned long)dgap_trcbuf,
- dgap_trcbuf_size);
- }
-
-# if defined(TRC_ON_OVERFLOW_WRAP_AROUND)
- /*
- * This is the less CPU-intensive way to do things. We simply
- * wrap around before we fall off the end of the buffer. A
- * tilde (~) demarcates the current end of the trace.
- *
- * This method should be used if you are concerned about race
- * conditions as it is less likely to affect the timing of
- * things.
- */
-
- if (dgap_trcbufi + lenbuf >= dgap_trcbuf_size) {
- /* We are wrapping, so wipe out the last tilde. */
- dgap_trcbuf[dgap_trcbufi] = '\0';
- /* put the new string at the beginning of the buffer */
- dgap_trcbufi = 0;
- }
-
- strcpy(&dgap_trcbuf[dgap_trcbufi], buf);
- dgap_trcbufi += lenbuf;
- dgap_trcbuf[dgap_trcbufi] = '~';
-
-# elif defined(TRC_ON_OVERFLOW_SHIFT_BUFFER)
- /*
- * This is the more CPU-intensive way to do things. If we
- * venture into the last 1/8 of the buffer, we shift the
- * last 7/8 of the buffer forward, wiping out the first 1/8.
- * Advantage: No wrap-around, only truncation from the
- * beginning.
- *
- * This method should not be used if you are concerned about
- * timing changes affecting the behaviour of the driver (ie,
- * race conditions).
- */
- strcpy(&dgap_trcbuf[dgap_trcbufi], buf);
- dgap_trcbufi += lenbuf;
- dgap_trcbuf[dgap_trcbufi] = '~';
- dgap_trcbuf[dgap_trcbufi+1] = '\0';
-
- /* If we're near the end of the trace buffer... */
- if (dgap_trcbufi > (dgap_trcbuf_size/8)*7) {
- /* Wipe out the first eighth to make some more room. */
- strcpy(dgap_trcbuf, &dgap_trcbuf[dgap_trcbuf_size/8]);
- dgap_trcbufi = strlen(dgap_trcbuf)-1;
- /* Plop overflow message at the top of the buffer. */
- bcopy(TRC_OVERFLOW, dgap_trcbuf, strlen(TRC_OVERFLOW));
- }
-# else
-# error "TRC_ON_OVERFLOW_WRAP_AROUND or TRC_ON_OVERFLOW_SHIFT_BUFFER?"
-# endif
- }
- DGAP_UNLOCK(dgap_tracef_lock, flags);
-
-# endif /* defined(TRC_TO_KMEM) */
-}
-
-#endif /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
-
-#endif
-
-/*
- * dgap_tracer_free()
- *
- *
- */
-void dgap_tracer_free(void)
-{
- if(dgap_trcbuf)
- vfree(dgap_trcbuf);
-}
diff --git a/drivers/staging/dgap/dgap_trace.h b/drivers/staging/dgap/dgap_trace.h
deleted file mode 100644
index b21f46198e71..000000000000
--- a/drivers/staging/dgap/dgap_trace.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
- *
- *****************************************************************************
- * Header file for dgap_trace.c
- *
- * $Id: dgap_trace.h,v 1.1 2009/10/23 14:01:57 markh Exp $
- */
-
-#ifndef __DGAP_TRACE_H
-#define __DGAP_TRACE_H
-
-#include "dgap_driver.h"
-
-void dgap_tracef(const char *fmt, ...);
-void dgap_tracer_free(void);
-
-#endif
-
diff --git a/drivers/staging/dgap/dgap_tty.c b/drivers/staging/dgap/dgap_tty.c
deleted file mode 100644
index 39fb4dfb8b7e..000000000000
--- a/drivers/staging/dgap/dgap_tty.c
+++ /dev/null
@@ -1,3580 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
- *
- * This is shared code between Digi's CVS archive and the
- * Linux Kernel sources.
- * Changing the source just for reformatting needlessly breaks
- * our CVS diff history.
- *
- * Send any bug fixes/changes to: Eng.Linux at digi dot com.
- * Thank you.
- */
-
-/************************************************************************
- *
- * This file implements the tty driver functionality for the
- * FEP5 based product lines.
- *
- ************************************************************************
- *
- * $Id: dgap_tty.c,v 1.3 2011/06/23 12:11:31 markh Exp $
- */
-
-#include <linux/kernel.h>
-#include <linux/version.h>
-#include <linux/sched.h> /* For jiffies, task states */
-#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
-#include <linux/module.h>
-#include <linux/ctype.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_reg.h>
-#include <linux/slab.h>
-#include <linux/delay.h> /* For udelay */
-#include <asm/uaccess.h> /* For copy_from_user/copy_to_user */
-#include <asm/io.h> /* For read[bwl]/write[bwl] */
-#include <linux/pci.h>
-
-#include "dgap_driver.h"
-#include "dgap_tty.h"
-#include "dgap_types.h"
-#include "dgap_fep5.h"
-#include "dgap_parse.h"
-#include "dgap_conf.h"
-#include "dgap_sysfs.h"
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
-#define init_MUTEX(sem) sema_init(sem, 1)
-#define DECLARE_MUTEX(name) \
- struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
-#endif
-
-/*
- * internal variables
- */
-static struct board_t *dgap_BoardsByMajor[256];
-static uchar *dgap_TmpWriteBuf = NULL;
-static DECLARE_MUTEX(dgap_TmpWriteSem);
-
-/*
- * Default transparent print information.
- */
-static struct digi_t dgap_digi_init = {
- .digi_flags = DIGI_COOK, /* Flags */
- .digi_maxcps = 100, /* Max CPS */
- .digi_maxchar = 50, /* Max chars in print queue */
- .digi_bufsize = 100, /* Printer buffer size */
- .digi_onlen = 4, /* size of printer on string */
- .digi_offlen = 4, /* size of printer off string */
- .digi_onstr = "\033[5i", /* ANSI printer on string ] */
- .digi_offstr = "\033[4i", /* ANSI printer off string ] */
- .digi_term = "ansi" /* default terminal type */
-};
-
-
-/*
- * Define a local default termios struct. All ports will be created
- * with this termios initially.
- *
- * This defines a raw port at 9600 baud, 8 data bits, no parity,
- * 1 stop bit.
- */
-
-static struct ktermios DgapDefaultTermios =
-{
- .c_iflag = (DEFAULT_IFLAGS), /* iflags */
- .c_oflag = (DEFAULT_OFLAGS), /* oflags */
- .c_cflag = (DEFAULT_CFLAGS), /* cflags */
- .c_lflag = (DEFAULT_LFLAGS), /* lflags */
- .c_cc = INIT_C_CC,
- .c_line = 0,
-};
-
-/* Our function prototypes */
-static int dgap_tty_open(struct tty_struct *tty, struct file *file);
-static void dgap_tty_close(struct tty_struct *tty, struct file *file);
-static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch);
-static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
-static int dgap_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo);
-static int dgap_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info);
-static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo);
-static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info);
-static int dgap_tty_write_room(struct tty_struct* tty);
-static int dgap_tty_chars_in_buffer(struct tty_struct* tty);
-static void dgap_tty_start(struct tty_struct *tty);
-static void dgap_tty_stop(struct tty_struct *tty);
-static void dgap_tty_throttle(struct tty_struct *tty);
-static void dgap_tty_unthrottle(struct tty_struct *tty);
-static void dgap_tty_flush_chars(struct tty_struct *tty);
-static void dgap_tty_flush_buffer(struct tty_struct *tty);
-static void dgap_tty_hangup(struct tty_struct *tty);
-static int dgap_wait_for_drain(struct tty_struct *tty);
-static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value);
-static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value);
-static int dgap_tty_digisetcustombaud(struct tty_struct *tty, int __user *new_info);
-static int dgap_tty_digigetcustombaud(struct tty_struct *tty, int __user *retinfo);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
-static int dgap_tty_tiocmget(struct tty_struct *tty);
-static int dgap_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear);
-#else
-static int dgap_tty_tiocmget(struct tty_struct *tty, struct file *file);
-static int dgap_tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear);
-#endif
-static int dgap_tty_send_break(struct tty_struct *tty, int msec);
-static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout);
-static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, int count);
-static void dgap_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios);
-static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c);
-static void dgap_tty_send_xchar(struct tty_struct *tty, char ch);
-
-static const struct tty_operations dgap_tty_ops = {
- .open = dgap_tty_open,
- .close = dgap_tty_close,
- .write = dgap_tty_write,
- .write_room = dgap_tty_write_room,
- .flush_buffer = dgap_tty_flush_buffer,
- .chars_in_buffer = dgap_tty_chars_in_buffer,
- .flush_chars = dgap_tty_flush_chars,
- .ioctl = dgap_tty_ioctl,
- .set_termios = dgap_tty_set_termios,
- .stop = dgap_tty_stop,
- .start = dgap_tty_start,
- .throttle = dgap_tty_throttle,
- .unthrottle = dgap_tty_unthrottle,
- .hangup = dgap_tty_hangup,
- .put_char = dgap_tty_put_char,
- .tiocmget = dgap_tty_tiocmget,
- .tiocmset = dgap_tty_tiocmset,
- .break_ctl = dgap_tty_send_break,
- .wait_until_sent = dgap_tty_wait_until_sent,
- .send_xchar = dgap_tty_send_xchar
-};
-
-
-
-
-
-/************************************************************************
- *
- * TTY Initialization/Cleanup Functions
- *
- ************************************************************************/
-
-/*
- * dgap_tty_preinit()
- *
- * Initialize any global tty related data before we download any boards.
- */
-int dgap_tty_preinit(void)
-{
- unsigned long flags;
-
- DGAP_LOCK(dgap_global_lock, flags);
-
- /*
- * Allocate a buffer for doing the copy from user space to
- * kernel space in dgap_input(). We only use one buffer and
- * control access to it with a semaphore. If we are paging, we
- * are already in trouble so one buffer won't hurt much anyway.
- */
- dgap_TmpWriteBuf = kmalloc(WRITEBUFLEN, GFP_ATOMIC);
-
- if (!dgap_TmpWriteBuf) {
- DGAP_UNLOCK(dgap_global_lock, flags);
- DPR_INIT(("unable to allocate tmp write buf"));
- return (-ENOMEM);
- }
-
- DGAP_UNLOCK(dgap_global_lock, flags);
- return(0);
-}
-
-
-/*
- * dgap_tty_register()
- *
- * Init the tty subsystem for this board.
- */
-int dgap_tty_register(struct board_t *brd)
-{
- int rc = 0;
-
- DPR_INIT(("tty_register start"));
-
- brd->SerialDriver = alloc_tty_driver(MAXPORTS);
-
- snprintf(brd->SerialName, MAXTTYNAMELEN, "tty_dgap_%d_", brd->boardnum);
- brd->SerialDriver->name = brd->SerialName;
- brd->SerialDriver->name_base = 0;
- brd->SerialDriver->major = 0;
- brd->SerialDriver->minor_start = 0;
- brd->SerialDriver->type = TTY_DRIVER_TYPE_SERIAL;
- brd->SerialDriver->subtype = SERIAL_TYPE_NORMAL;
- brd->SerialDriver->init_termios = DgapDefaultTermios;
- brd->SerialDriver->driver_name = DRVSTR;
- brd->SerialDriver->flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK);
-
- /* The kernel wants space to store pointers to tty_structs */
- brd->SerialDriver->ttys = kzalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL);
- if (!brd->SerialDriver->ttys)
- return(-ENOMEM);
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
- brd->SerialDriver->refcount = brd->TtyRefCnt;
-#endif
-
- /*
- * Entry points for driver. Called by the kernel from
- * tty_io.c and n_tty.c.
- */
- tty_set_operations(brd->SerialDriver, &dgap_tty_ops);
-
- /*
- * If we're doing transparent print, we have to do all of the above
- * again, separately so we don't get the LD confused about what major
- * we are when we get into the dgap_tty_open() routine.
- */
- brd->PrintDriver = alloc_tty_driver(MAXPORTS);
-
- snprintf(brd->PrintName, MAXTTYNAMELEN, "pr_dgap_%d_", brd->boardnum);
- brd->PrintDriver->name = brd->PrintName;
- brd->PrintDriver->name_base = 0;
- brd->PrintDriver->major = 0;
- brd->PrintDriver->minor_start = 0;
- brd->PrintDriver->type = TTY_DRIVER_TYPE_SERIAL;
- brd->PrintDriver->subtype = SERIAL_TYPE_NORMAL;
- brd->PrintDriver->init_termios = DgapDefaultTermios;
- brd->PrintDriver->driver_name = DRVSTR;
- brd->PrintDriver->flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK);
-
- /* The kernel wants space to store pointers to tty_structs */
- brd->PrintDriver->ttys = kzalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL);
- if (!brd->PrintDriver->ttys)
- return(-ENOMEM);
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
- brd->PrintDriver->refcount = brd->TtyRefCnt;
-#endif
-
- /*
- * Entry points for driver. Called by the kernel from
- * tty_io.c and n_tty.c.
- */
- tty_set_operations(brd->PrintDriver, &dgap_tty_ops);
-
- if (!brd->dgap_Major_Serial_Registered) {
- /* Register tty devices */
- rc = tty_register_driver(brd->SerialDriver);
- if (rc < 0) {
- APR(("Can't register tty device (%d)\n", rc));
- return(rc);
- }
- brd->dgap_Major_Serial_Registered = TRUE;
- dgap_BoardsByMajor[brd->SerialDriver->major] = brd;
- brd->dgap_Serial_Major = brd->SerialDriver->major;
- }
-
- if (!brd->dgap_Major_TransparentPrint_Registered) {
- /* Register Transparent Print devices */
- rc = tty_register_driver(brd->PrintDriver);
- if (rc < 0) {
- APR(("Can't register Transparent Print device (%d)\n", rc));
- return(rc);
- }
- brd->dgap_Major_TransparentPrint_Registered = TRUE;
- dgap_BoardsByMajor[brd->PrintDriver->major] = brd;
- brd->dgap_TransparentPrint_Major = brd->PrintDriver->major;
- }
-
- DPR_INIT(("DGAP REGISTER TTY: MAJORS: %d %d\n", brd->SerialDriver->major,
- brd->PrintDriver->major));
-
- return (rc);
-}
-
-
-/*
- * dgap_tty_init()
- *
- * Init the tty subsystem. Called once per board after board has been
- * downloaded and init'ed.
- */
-int dgap_tty_init(struct board_t *brd)
-{
- int i;
- int tlw;
- uint true_count = 0;
- uchar *vaddr;
- uchar modem = 0;
- struct channel_t *ch;
- struct bs_t *bs;
- struct cm_t *cm;
-
- if (!brd)
- return (-ENXIO);
-
- DPR_INIT(("dgap_tty_init start\n"));
-
- /*
- * Initialize board structure elements.
- */
-
- vaddr = brd->re_map_membase;
- true_count = readw((vaddr + NCHAN));
-
- brd->nasync = dgap_config_get_number_of_ports(brd);
-
- if (!brd->nasync) {
- brd->nasync = brd->maxports;
- }
-
- if (brd->nasync > brd->maxports) {
- brd->nasync = brd->maxports;
- }
-
- if (true_count != brd->nasync) {
- if ((brd->type == PPCM) && (true_count == 64)) {
- APR(("***WARNING**** %s configured for %d ports, has %d ports.\nPlease make SURE the EBI cable running from the card\nto each EM module is plugged into EBI IN!\n",
- brd->name, brd->nasync, true_count));
- }
- else if ((brd->type == PPCM) && (true_count == 0)) {
- APR(("***WARNING**** %s configured for %d ports, has %d ports.\nPlease make SURE the EBI cable running from the card\nto each EM module is plugged into EBI IN!\n",
- brd->name, brd->nasync, true_count));
- }
- else {
- APR(("***WARNING**** %s configured for %d ports, has %d ports.\n",
- brd->name, brd->nasync, true_count));
- }
-
- brd->nasync = true_count;
-
- /* If no ports, don't bother going any further */
- if (!brd->nasync) {
- brd->state = BOARD_FAILED;
- brd->dpastatus = BD_NOFEP;
- return(-ENXIO);
- }
- }
-
- /*
- * Allocate channel memory that might not have been allocated
- * when the driver was first loaded.
- */
- for (i = 0; i < brd->nasync; i++) {
- if (!brd->channels[i]) {
- brd->channels[i] = kzalloc(sizeof(struct channel_t), GFP_ATOMIC);
- if (!brd->channels[i]) {
- DPR_CORE(("%s:%d Unable to allocate memory for channel struct\n",
- __FILE__, __LINE__));
- }
- }
- }
-
- ch = brd->channels[0];
- vaddr = brd->re_map_membase;
-
- bs = (struct bs_t *) ((ulong) vaddr + CHANBUF);
- cm = (struct cm_t *) ((ulong) vaddr + CMDBUF);
-
- brd->bd_bs = bs;
-
- /* Set up channel variables */
- for (i = 0; i < brd->nasync; i++, ch = brd->channels[i], bs++) {
-
- if (!brd->channels[i])
- continue;
-
- DGAP_SPINLOCK_INIT(ch->ch_lock);
-
- /* Store all our magic numbers */
- ch->magic = DGAP_CHANNEL_MAGIC;
- ch->ch_tun.magic = DGAP_UNIT_MAGIC;
- ch->ch_tun.un_type = DGAP_SERIAL;
- ch->ch_tun.un_ch = ch;
- ch->ch_tun.un_dev = i;
-
- ch->ch_pun.magic = DGAP_UNIT_MAGIC;
- ch->ch_pun.un_type = DGAP_PRINT;
- ch->ch_pun.un_ch = ch;
- ch->ch_pun.un_dev = i;
-
- ch->ch_vaddr = vaddr;
- ch->ch_bs = bs;
- ch->ch_cm = cm;
- ch->ch_bd = brd;
- ch->ch_portnum = i;
- ch->ch_digi = dgap_digi_init;
-
- /*
- * Set up digi dsr and dcd bits based on altpin flag.
- */
- if (dgap_config_get_altpin(brd)) {
- ch->ch_dsr = DM_CD;
- ch->ch_cd = DM_DSR;
- ch->ch_digi.digi_flags |= DIGI_ALTPIN;
- }
- else {
- ch->ch_cd = DM_CD;
- ch->ch_dsr = DM_DSR;
- }
-
- ch->ch_taddr = vaddr + ((ch->ch_bs->tx_seg) << 4);
- ch->ch_raddr = vaddr + ((ch->ch_bs->rx_seg) << 4);
- ch->ch_tx_win = 0;
- ch->ch_rx_win = 0;
- ch->ch_tsize = readw(&(ch->ch_bs->tx_max)) + 1;
- ch->ch_rsize = readw(&(ch->ch_bs->rx_max)) + 1;
- ch->ch_tstart = 0;
- ch->ch_rstart = 0;
-
- /* .25 second delay */
- ch->ch_close_delay = 250;
-
- /*
- * Set queue water marks, interrupt mask,
- * and general tty parameters.
- */
- ch->ch_tlw = tlw = ch->ch_tsize >= 2000 ? ((ch->ch_tsize * 5) / 8) : ch->ch_tsize / 2;
-
- dgap_cmdw(ch, STLOW, tlw, 0);
-
- dgap_cmdw(ch, SRLOW, ch->ch_rsize / 2, 0);
-
- dgap_cmdw(ch, SRHIGH, 7 * ch->ch_rsize / 8, 0);
-
- ch->ch_mistat = readb(&(ch->ch_bs->m_stat));
-
- init_waitqueue_head(&ch->ch_flags_wait);
- init_waitqueue_head(&ch->ch_tun.un_flags_wait);
- init_waitqueue_head(&ch->ch_pun.un_flags_wait);
- init_waitqueue_head(&ch->ch_sniff_wait);
-
- /* Turn on all modem interrupts for now */
- modem = (DM_CD | DM_DSR | DM_CTS | DM_RI);
- writeb(modem, &(ch->ch_bs->m_int));
-
- /*
- * Set edelay to 0 if interrupts are turned on,
- * otherwise set edelay to the usual 100.
- */
- if (brd->intr_used)
- writew(0, &(ch->ch_bs->edelay));
- else
- writew(100, &(ch->ch_bs->edelay));
-
- writeb(1, &(ch->ch_bs->idata));
- }
-
-
- DPR_INIT(("dgap_tty_init finish\n"));
-
- return (0);
-}
-
-
-/*
- * dgap_tty_post_uninit()
- *
- * UnInitialize any global tty related data.
- */
-void dgap_tty_post_uninit(void)
-{
- kfree(dgap_TmpWriteBuf);
- dgap_TmpWriteBuf = NULL;
-}
-
-
-/*
- * dgap_tty_uninit()
- *
- * Uninitialize the TTY portion of this driver. Free all memory and
- * resources.
- */
-void dgap_tty_uninit(struct board_t *brd)
-{
- int i = 0;
-
- if (brd->dgap_Major_Serial_Registered) {
- dgap_BoardsByMajor[brd->SerialDriver->major] = NULL;
- brd->dgap_Serial_Major = 0;
- for (i = 0; i < brd->nasync; i++) {
- dgap_remove_tty_sysfs(brd->channels[i]->ch_tun.un_sysfs);
- tty_unregister_device(brd->SerialDriver, i);
- }
- tty_unregister_driver(brd->SerialDriver);
- kfree(brd->SerialDriver->ttys);
- brd->SerialDriver->ttys = NULL;
- put_tty_driver(brd->SerialDriver);
- brd->dgap_Major_Serial_Registered = FALSE;
- }
-
- if (brd->dgap_Major_TransparentPrint_Registered) {
- dgap_BoardsByMajor[brd->PrintDriver->major] = NULL;
- brd->dgap_TransparentPrint_Major = 0;
- for (i = 0; i < brd->nasync; i++) {
- dgap_remove_tty_sysfs(brd->channels[i]->ch_pun.un_sysfs);
- tty_unregister_device(brd->PrintDriver, i);
- }
- tty_unregister_driver(brd->PrintDriver);
- kfree(brd->PrintDriver->ttys);
- brd->PrintDriver->ttys = NULL;
- put_tty_driver(brd->PrintDriver);
- brd->dgap_Major_TransparentPrint_Registered = FALSE;
- }
-}
-
-
-#define TMPBUFLEN (1024)
-
-/*
- * dgap_sniff - Dump data out to the "sniff" buffer if the
- * proc sniff file is opened...
- */
-static void dgap_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *buf, int len)
-{
- struct timeval tv;
- int n;
- int r;
- int nbuf;
- int i;
- int tmpbuflen;
- char tmpbuf[TMPBUFLEN];
- char *p = tmpbuf;
- int too_much_data;
-
- /* Leave if sniff not open */
- if (!(ch->ch_sniff_flags & SNIFF_OPEN))
- return;
-
- do_gettimeofday(&tv);
-
- /* Create our header for data dump */
- p += sprintf(p, "<%ld %ld><%s><", tv.tv_sec, tv.tv_usec, text);
- tmpbuflen = p - tmpbuf;
-
- do {
- too_much_data = 0;
-
- for (i = 0; i < len && tmpbuflen < (TMPBUFLEN - 4); i++) {
- p += sprintf(p, "%02x ", *buf);
- buf++;
- tmpbuflen = p - tmpbuf;
- }
-
- if (tmpbuflen < (TMPBUFLEN - 4)) {
- if (i > 0)
- p += sprintf(p - 1, "%s\n", ">");
- else
- p += sprintf(p, "%s\n", ">");
- } else {
- too_much_data = 1;
- len -= i;
- }
-
- nbuf = strlen(tmpbuf);
- p = tmpbuf;
-
- /*
- * Loop while data remains.
- */
- while (nbuf > 0 && ch->ch_sniff_buf) {
- /*
- * Determine the amount of available space left in the
- * buffer. If there's none, wait until some appears.
- */
- n = (ch->ch_sniff_out - ch->ch_sniff_in - 1) & SNIFF_MASK;
-
- /*
- * If there is no space left to write to in our sniff buffer,
- * we have no choice but to drop the data.
- * We *cannot* sleep here waiting for space, because this
- * function was probably called by the interrupt/timer routines!
- */
- if (n == 0) {
- return;
- }
-
- /*
- * Copy as much data as will fit.
- */
-
- if (n > nbuf)
- n = nbuf;
-
- r = SNIFF_MAX - ch->ch_sniff_in;
-
- if (r <= n) {
- memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, r);
-
- n -= r;
- ch->ch_sniff_in = 0;
- p += r;
- nbuf -= r;
- }
-
- memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, n);
-
- ch->ch_sniff_in += n;
- p += n;
- nbuf -= n;
-
- /*
- * Wakeup any thread waiting for data
- */
- if (ch->ch_sniff_flags & SNIFF_WAIT_DATA) {
- ch->ch_sniff_flags &= ~SNIFF_WAIT_DATA;
- wake_up_interruptible(&ch->ch_sniff_wait);
- }
- }
-
- /*
- * If the user sent us too much data to push into our tmpbuf,
- * we need to keep looping around on all the data.
- */
- if (too_much_data) {
- p = tmpbuf;
- tmpbuflen = 0;
- }
-
- } while (too_much_data);
-}
-
-
-/*=======================================================================
- *
- * dgap_input - Process received data.
- *
- * ch - Pointer to channel structure.
- *
- *=======================================================================*/
-
-void dgap_input(struct channel_t *ch)
-{
- struct board_t *bd;
- struct bs_t *bs;
- struct tty_struct *tp;
- struct tty_ldisc *ld;
- uint rmask;
- uint head;
- uint tail;
- int data_len;
- ulong lock_flags;
- ulong lock_flags2;
- int flip_len;
- int len = 0;
- int n = 0;
- uchar *buf;
- uchar tmpchar;
- int s = 0;
-
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- tp = ch->ch_tun.un_tty;
-
- bs = ch->ch_bs;
- if (!bs) {
- return;
- }
-
- bd = ch->ch_bd;
- if(!bd || bd->magic != DGAP_BOARD_MAGIC)
- return;
-
- DPR_READ(("dgap_input start\n"));
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- /*
- * Figure the number of characters in the buffer.
- * Exit immediately if none.
- */
-
- rmask = ch->ch_rsize - 1;
-
- head = readw(&(bs->rx_head));
- head &= rmask;
- tail = readw(&(bs->rx_tail));
- tail &= rmask;
-
- data_len = (head - tail) & rmask;
-
- if (data_len == 0) {
- writeb(1, &(bs->idata));
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- DPR_READ(("No data on port %d\n", ch->ch_portnum));
- return;
- }
-
- /*
- * If the device is not open, or CREAD is off, flush
- * input data and return immediately.
- */
- if ((bd->state != BOARD_READY) || !tp || (tp->magic != TTY_MAGIC) ||
- !(ch->ch_tun.un_flags & UN_ISOPEN) || !(tp->termios.c_cflag & CREAD) ||
- (ch->ch_tun.un_flags & UN_CLOSING)) {
-
- DPR_READ(("input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum));
- DPR_READ(("input. tp: %p tp->magic: %x MAGIC:%x ch flags: %x\n",
- tp, tp ? tp->magic : 0, TTY_MAGIC, ch->ch_tun.un_flags));
- writew(head, &(bs->rx_tail));
- writeb(1, &(bs->idata));
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return;
- }
-
- /*
- * If we are throttled, simply don't read any data.
- */
- if (ch->ch_flags & CH_RXBLOCK) {
- writeb(1, &(bs->idata));
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- DPR_READ(("Port %d throttled, not reading any data. head: %x tail: %x\n",
- ch->ch_portnum, head, tail));
- return;
- }
-
- /*
- * Ignore oruns.
- */
- tmpchar = readb(&(bs->orun));
- if (tmpchar) {
- ch->ch_err_overrun++;
- writeb(0, &(bs->orun));
- }
-
- DPR_READ(("dgap_input start 2\n"));
-
- /* Decide how much data we can send into the tty layer */
- flip_len = TTY_FLIPBUF_SIZE;
-
- /* Chop down the length, if needed */
- len = min(data_len, flip_len);
- len = min(len, (N_TTY_BUF_SIZE - 1));
-
- ld = tty_ldisc_ref(tp);
-
-#ifdef TTY_DONT_FLIP
- /*
- * If the DONT_FLIP flag is on, don't flush our buffer, and act
- * like the ld doesn't have any space to put the data right now.
- */
- if (test_bit(TTY_DONT_FLIP, &tp->flags))
- len = 0;
-#endif
-
- /*
- * If we were unable to get a reference to the ld,
- * don't flush our buffer, and act like the ld doesn't
- * have any space to put the data right now.
- */
- if (!ld) {
- len = 0;
- } else {
- /*
- * If ld doesn't have a pointer to a receive_buf function,
- * flush the data, then act like the ld doesn't have any
- * space to put the data right now.
- */
- if (!ld->ops->receive_buf) {
- writew(head, &(bs->rx_tail));
- len = 0;
- }
- }
-
- if (len <= 0) {
- writeb(1, &(bs->idata));
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- DPR_READ(("dgap_input 1 - finish\n"));
- if (ld)
- tty_ldisc_deref(ld);
- return;
- }
-
- buf = ch->ch_bd->flipbuf;
- n = len;
-
- /*
- * n now contains the most amount of data we can copy,
- * bounded either by our buffer size or the amount
- * of data the card actually has pending...
- */
- while (n) {
-
- s = ((head >= tail) ? head : ch->ch_rsize) - tail;
- s = min(s, n);
-
- if (s <= 0)
- break;
-
- memcpy_fromio(buf, (char *) ch->ch_raddr + tail, s);
- dgap_sniff_nowait_nolock(ch, "USER READ", buf, s);
-
- tail += s;
- buf += s;
-
- n -= s;
- /* Flip queue if needed */
- tail &= rmask;
- }
-
- writew(tail, &(bs->rx_tail));
- writeb(1, &(bs->idata));
- ch->ch_rxcount += len;
-
- /*
- * If we are completely raw, we don't need to go through a lot
- * of the tty layers that exist.
- * In this case, we take the shortest and fastest route we
- * can to relay the data to the user.
- *
- * On the other hand, if we are not raw, we need to go through
- * the tty layer, which has its API more well defined.
- */
- if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
- dgap_parity_scan(ch, ch->ch_bd->flipbuf, ch->ch_bd->flipflagbuf, &len);
-
- len = tty_buffer_request_room(tp->port, len);
- tty_insert_flip_string_flags(tp->port, ch->ch_bd->flipbuf,
- ch->ch_bd->flipflagbuf, len);
- }
- else {
- len = tty_buffer_request_room(tp->port, len);
- tty_insert_flip_string(tp->port, ch->ch_bd->flipbuf, len);
- }
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- /* Tell the tty layer its okay to "eat" the data now */
- tty_flip_buffer_push(tp->port);
-
- if (ld)
- tty_ldisc_deref(ld);
-
- DPR_READ(("dgap_input - finish\n"));
-}
-
-
-/************************************************************************
- * Determines when CARRIER changes state and takes appropriate
- * action.
- ************************************************************************/
-void dgap_carrier(struct channel_t *ch)
-{
- struct board_t *bd;
-
- int virt_carrier = 0;
- int phys_carrier = 0;
-
- DPR_CARR(("dgap_carrier called...\n"));
-
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- bd = ch->ch_bd;
-
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return;
-
- /* Make sure altpin is always set correctly */
- if (ch->ch_digi.digi_flags & DIGI_ALTPIN) {
- ch->ch_dsr = DM_CD;
- ch->ch_cd = DM_DSR;
- }
- else {
- ch->ch_dsr = DM_DSR;
- ch->ch_cd = DM_CD;
- }
-
- if (ch->ch_mistat & D_CD(ch)) {
- DPR_CARR(("mistat: %x D_CD: %x\n", ch->ch_mistat, D_CD(ch)));
- phys_carrier = 1;
- }
-
- if (ch->ch_digi.digi_flags & DIGI_FORCEDCD) {
- virt_carrier = 1;
- }
-
- if (ch->ch_c_cflag & CLOCAL) {
- virt_carrier = 1;
- }
-
-
- DPR_CARR(("DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier));
-
- /*
- * Test for a VIRTUAL carrier transition to HIGH.
- */
- if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
-
- /*
- * When carrier rises, wake any threads waiting
- * for carrier in the open routine.
- */
-
- DPR_CARR(("carrier: virt DCD rose\n"));
-
- if (waitqueue_active(&(ch->ch_flags_wait)))
- wake_up_interruptible(&ch->ch_flags_wait);
- }
-
- /*
- * Test for a PHYSICAL carrier transition to HIGH.
- */
- if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
-
- /*
- * When carrier rises, wake any threads waiting
- * for carrier in the open routine.
- */
-
- DPR_CARR(("carrier: physical DCD rose\n"));
-
- if (waitqueue_active(&(ch->ch_flags_wait)))
- wake_up_interruptible(&ch->ch_flags_wait);
- }
-
- /*
- * Test for a PHYSICAL transition to low, so long as we aren't
- * currently ignoring physical transitions (which is what "virtual
- * carrier" indicates).
- *
- * The transition of the virtual carrier to low really doesn't
- * matter... it really only means "ignore carrier state", not
- * "make pretend that carrier is there".
- */
- if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0) &&
- (phys_carrier == 0))
- {
-
- /*
- * When carrier drops:
- *
- * Drop carrier on all open units.
- *
- * Flush queues, waking up any task waiting in the
- * line discipline.
- *
- * Send a hangup to the control terminal.
- *
- * Enable all select calls.
- */
- if (waitqueue_active(&(ch->ch_flags_wait)))
- wake_up_interruptible(&ch->ch_flags_wait);
-
- if (ch->ch_tun.un_open_count > 0) {
- DPR_CARR(("Sending tty hangup\n"));
- tty_hangup(ch->ch_tun.un_tty);
- }
-
- if (ch->ch_pun.un_open_count > 0) {
- DPR_CARR(("Sending pr hangup\n"));
- tty_hangup(ch->ch_pun.un_tty);
- }
- }
-
- /*
- * Make sure that our cached values reflect the current reality.
- */
- if (virt_carrier == 1)
- ch->ch_flags |= CH_FCAR;
- else
- ch->ch_flags &= ~CH_FCAR;
-
- if (phys_carrier == 1)
- ch->ch_flags |= CH_CD;
- else
- ch->ch_flags &= ~CH_CD;
-}
-
-
-/************************************************************************
- *
- * TTY Entry points and helper functions
- *
- ************************************************************************/
-
-/*
- * dgap_tty_open()
- *
- */
-static int dgap_tty_open(struct tty_struct *tty, struct file *file)
-{
- struct board_t *brd;
- struct channel_t *ch;
- struct un_t *un;
- struct bs_t *bs;
- uint major = 0;
- uint minor = 0;
- int rc = 0;
- ulong lock_flags;
- ulong lock_flags2;
- u16 head;
-
- rc = 0;
-
- major = MAJOR(tty_devnum(tty));
- minor = MINOR(tty_devnum(tty));
-
- if (major > 255) {
- return -ENXIO;
- }
-
- /* Get board pointer from our array of majors we have allocated */
- brd = dgap_BoardsByMajor[major];
- if (!brd) {
- return -ENXIO;
- }
-
- /*
- * If board is not yet up to a state of READY, go to
- * sleep waiting for it to happen or they cancel the open.
- */
- rc = wait_event_interruptible(brd->state_wait,
- (brd->state & BOARD_READY));
-
- if (rc) {
- return rc;
- }
-
- DGAP_LOCK(brd->bd_lock, lock_flags);
-
- /* The wait above should guarantee this cannot happen */
- if (brd->state != BOARD_READY) {
- DGAP_UNLOCK(brd->bd_lock, lock_flags);
- return -ENXIO;
- }
-
- /* If opened device is greater than our number of ports, bail. */
- if (MINOR(tty_devnum(tty)) > brd->nasync) {
- DGAP_UNLOCK(brd->bd_lock, lock_flags);
- return -ENXIO;
- }
-
- ch = brd->channels[minor];
- if (!ch) {
- DGAP_UNLOCK(brd->bd_lock, lock_flags);
- return -ENXIO;
- }
-
- /* Grab channel lock */
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- /* Figure out our type */
- if (major == brd->dgap_Serial_Major) {
- un = &brd->channels[minor]->ch_tun;
- un->un_type = DGAP_SERIAL;
- }
- else if (major == brd->dgap_TransparentPrint_Major) {
- un = &brd->channels[minor]->ch_pun;
- un->un_type = DGAP_PRINT;
- }
- else {
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(brd->bd_lock, lock_flags);
- DPR_OPEN(("%d Unknown TYPE!\n", __LINE__));
- return -ENXIO;
- }
-
- /* Store our unit into driver_data, so we always have it available. */
- tty->driver_data = un;
-
- DPR_OPEN(("Open called. MAJOR: %d MINOR:%d unit: %p NAME: %s\n",
- MAJOR(tty_devnum(tty)), MINOR(tty_devnum(tty)), un, brd->name));
-
- /*
- * Error if channel info pointer is NULL.
- */
- bs = ch->ch_bs;
- if (!bs) {
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(brd->bd_lock, lock_flags);
- DPR_OPEN(("%d BS is 0!\n", __LINE__));
- return -ENXIO;
- }
-
- DPR_OPEN(("%d: tflag=%x pflag=%x\n", __LINE__, ch->ch_tun.un_flags, ch->ch_pun.un_flags));
-
- /*
- * Initialize tty's
- */
- if (!(un->un_flags & UN_ISOPEN)) {
- /* Store important variables. */
- un->un_tty = tty;
-
- /* Maybe do something here to the TTY struct as well? */
- }
-
- /*
- * Initialize if neither terminal or printer is open.
- */
- if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) {
-
- DPR_OPEN(("dgap_open: initializing channel in open...\n"));
-
- ch->ch_mforce = 0;
- ch->ch_mval = 0;
-
- /*
- * Flush input queue.
- */
- head = readw(&(bs->rx_head));
- writew(head, &(bs->rx_tail));
-
- ch->ch_flags = 0;
- ch->pscan_state = 0;
- ch->pscan_savechar = 0;
-
- ch->ch_c_cflag = tty->termios.c_cflag;
- ch->ch_c_iflag = tty->termios.c_iflag;
- ch->ch_c_oflag = tty->termios.c_oflag;
- ch->ch_c_lflag = tty->termios.c_lflag;
- ch->ch_startc = tty->termios.c_cc[VSTART];
- ch->ch_stopc = tty->termios.c_cc[VSTOP];
-
- /* TODO: flush our TTY struct here? */
- }
-
- dgap_carrier(ch);
- /*
- * Run param in case we changed anything
- */
- dgap_param(tty);
-
- /*
- * follow protocol for opening port
- */
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(brd->bd_lock, lock_flags);
-
- rc = dgap_block_til_ready(tty, file, ch);
-
- if (!un->un_tty) {
- return -ENODEV;
- }
-
- if (rc) {
- DPR_OPEN(("dgap_tty_open returning after dgap_block_til_ready "
- "with %d\n", rc));
- }
-
- /* No going back now, increment our unit and channel counters */
- DGAP_LOCK(ch->ch_lock, lock_flags);
- ch->ch_open_count++;
- un->un_open_count++;
- un->un_flags |= (UN_ISOPEN);
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- DPR_OPEN(("dgap_tty_open finished\n"));
- return (rc);
-}
-
-
-/*
- * dgap_block_til_ready()
- *
- * Wait for DCD, if needed.
- */
-static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch)
-{
- int retval = 0;
- struct un_t *un = NULL;
- ulong lock_flags;
- uint old_flags = 0;
- int sleep_on_un_flags = 0;
-
- if (!tty || tty->magic != TTY_MAGIC || !file || !ch || ch->magic != DGAP_CHANNEL_MAGIC) {
- return (-ENXIO);
- }
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC) {
- return (-ENXIO);
- }
-
- DPR_OPEN(("dgap_block_til_ready - before block.\n"));
-
- DGAP_LOCK(ch->ch_lock, lock_flags);
-
- ch->ch_wopen++;
-
- /* Loop forever */
- while (1) {
-
- sleep_on_un_flags = 0;
-
- /*
- * If board has failed somehow during our sleep, bail with error.
- */
- if (ch->ch_bd->state == BOARD_FAILED) {
- retval = -ENXIO;
- break;
- }
-
- /* If tty was hung up, break out of loop and set error. */
- if (tty_hung_up_p(file)) {
- retval = -EAGAIN;
- break;
- }
-
- /*
- * If either unit is in the middle of the fragile part of close,
- * we just cannot touch the channel safely.
- * Go back to sleep, knowing that when the channel can be
- * touched safely, the close routine will signal the
- * ch_wait_flags to wake us back up.
- */
- if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_CLOSING)) {
-
- /*
- * Our conditions to leave cleanly and happily:
- * 1) NONBLOCKING on the tty is set.
- * 2) CLOCAL is set.
- * 3) DCD (fake or real) is active.
- */
-
- if (file->f_flags & O_NONBLOCK) {
- break;
- }
-
- if (tty->flags & (1 << TTY_IO_ERROR)) {
- break;
- }
-
- if (ch->ch_flags & CH_CD) {
- DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags));
- break;
- }
-
- if (ch->ch_flags & CH_FCAR) {
- DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags));
- break;
- }
- }
- else {
- sleep_on_un_flags = 1;
- }
-
- /*
- * If there is a signal pending, the user probably
- * interrupted (ctrl-c) us.
- * Leave loop with error set.
- */
- if (signal_pending(current)) {
- DPR_OPEN(("%d: signal pending...\n", __LINE__));
- retval = -ERESTARTSYS;
- break;
- }
-
- DPR_OPEN(("dgap_block_til_ready - blocking.\n"));
-
- /*
- * Store the flags before we let go of channel lock
- */
- if (sleep_on_un_flags)
- old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags;
- else
- old_flags = ch->ch_flags;
-
- /*
- * Let go of channel lock before calling schedule.
- * Our poller will get any FEP events and wake us up when DCD
- * eventually goes active.
- */
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- DPR_OPEN(("Going to sleep on %s flags...\n",
- (sleep_on_un_flags ? "un" : "ch")));
-
- /*
- * Wait for something in the flags to change from the current value.
- */
- if (sleep_on_un_flags) {
- retval = wait_event_interruptible(un->un_flags_wait,
- (old_flags != (ch->ch_tun.un_flags | ch->ch_pun.un_flags)));
- }
- else {
- retval = wait_event_interruptible(ch->ch_flags_wait,
- (old_flags != ch->ch_flags));
- }
-
- DPR_OPEN(("After sleep... retval: %x\n", retval));
-
- /*
- * We got woken up for some reason.
- * Before looping around, grab our channel lock.
- */
- DGAP_LOCK(ch->ch_lock, lock_flags);
- }
-
- ch->ch_wopen--;
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- DPR_OPEN(("dgap_block_til_ready - after blocking.\n"));
-
- if (retval) {
- DPR_OPEN(("dgap_block_til_ready - done. error. retval: %x\n", retval));
- return(retval);
- }
-
- DPR_OPEN(("dgap_block_til_ready - done no error. jiffies: %lu\n", jiffies));
-
- return(0);
-}
-
-
-/*
- * dgap_tty_hangup()
- *
- * Hangup the port. Like a close, but don't wait for output to drain.
- */
-static void dgap_tty_hangup(struct tty_struct *tty)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return;
-
- DPR_CLOSE(("dgap_hangup called. ch->ch_open_count: %d un->un_open_count: %d\n",
- ch->ch_open_count, un->un_open_count));
-
- /* flush the transmit queues */
- dgap_tty_flush_buffer(tty);
-
- DPR_CLOSE(("dgap_hangup finished. ch->ch_open_count: %d un->un_open_count: %d\n",
- ch->ch_open_count, un->un_open_count));
-}
-
-
-
-/*
- * dgap_tty_close()
- *
- */
-static void dgap_tty_close(struct tty_struct *tty, struct file *file)
-{
- struct ktermios *ts;
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- ulong lock_flags;
- int rc = 0;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return;
-
- ts = &tty->termios;
-
- DPR_CLOSE(("Close called\n"));
-
- DGAP_LOCK(ch->ch_lock, lock_flags);
-
- /*
- * Determine if this is the last close or not - and if we agree about
- * which type of close it is with the Line Discipline
- */
- if ((tty->count == 1) && (un->un_open_count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. un_open_count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- APR(("tty->count is 1, un open count is %d\n", un->un_open_count));
- un->un_open_count = 1;
- }
-
- if (--un->un_open_count < 0) {
- APR(("bad serial port open count of %d\n", un->un_open_count));
- un->un_open_count = 0;
- }
-
- ch->ch_open_count--;
-
- if (ch->ch_open_count && un->un_open_count) {
- DPR_CLOSE(("dgap_tty_close: not last close ch: %d un:%d\n",
- ch->ch_open_count, un->un_open_count));
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
- return;
- }
-
- /* OK, its the last close on the unit */
- DPR_CLOSE(("dgap_tty_close - last close on unit procedures\n"));
-
- un->un_flags |= UN_CLOSING;
-
- tty->closing = 1;
-
- /*
- * Only officially close channel if count is 0 and
- * DIGI_PRINTER bit is not set.
- */
- if ((ch->ch_open_count == 0) && !(ch->ch_digi.digi_flags & DIGI_PRINTER)) {
-
- ch->ch_flags &= ~(CH_RXBLOCK);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- /* wait for output to drain */
- /* This will also return if we take an interrupt */
-
- DPR_CLOSE(("Calling wait_for_drain\n"));
- rc = dgap_wait_for_drain(tty);
- DPR_CLOSE(("After calling wait_for_drain\n"));
-
- if (rc) {
- DPR_BASIC(("dgap_tty_close - bad return: %d ", rc));
- }
-
- dgap_tty_flush_buffer(tty);
- tty_ldisc_flush(tty);
-
- DGAP_LOCK(ch->ch_lock, lock_flags);
-
- tty->closing = 0;
-
- /*
- * If we have HUPCL set, lower DTR and RTS
- */
- if (ch->ch_c_cflag & HUPCL ) {
- DPR_CLOSE(("Close. HUPCL set, dropping DTR/RTS\n"));
- ch->ch_mostat &= ~(D_RTS(ch)|D_DTR(ch));
- dgap_cmdb( ch, SMODEM, 0, D_DTR(ch)|D_RTS(ch), 0 );
-
- /*
- * Go to sleep to ensure RTS/DTR
- * have been dropped for modems to see it.
- */
- if (ch->ch_close_delay) {
- DPR_CLOSE(("Close. Sleeping for RTS/DTR drop\n"));
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
- dgap_ms_sleep(ch->ch_close_delay);
- DGAP_LOCK(ch->ch_lock, lock_flags);
-
- DPR_CLOSE(("Close. After sleeping for RTS/DTR drop\n"));
- }
- }
-
- ch->pscan_state = 0;
- ch->pscan_savechar = 0;
- ch->ch_baud_info = 0;
-
- }
-
- /*
- * turn off print device when closing print device.
- */
- if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON) ) {
- dgap_wmove(ch, ch->ch_digi.digi_offstr,
- (int) ch->ch_digi.digi_offlen);
- ch->ch_flags &= ~CH_PRON;
- }
-
- un->un_tty = NULL;
- un->un_flags &= ~(UN_ISOPEN | UN_CLOSING);
- tty->driver_data = NULL;
-
- DPR_CLOSE(("Close. Doing wakeups\n"));
- wake_up_interruptible(&ch->ch_flags_wait);
- wake_up_interruptible(&un->un_flags_wait);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- DPR_BASIC(("dgap_tty_close - complete\n"));
-}
-
-
-/*
- * dgap_tty_chars_in_buffer()
- *
- * Return number of characters that have not been transmitted yet.
- *
- * This routine is used by the line discipline to determine if there
- * is data waiting to be transmitted/drained/flushed or not.
- */
-static int dgap_tty_chars_in_buffer(struct tty_struct *tty)
-{
- struct board_t *bd = NULL;
- struct channel_t *ch = NULL;
- struct un_t *un = NULL;
- struct bs_t *bs = NULL;
- uchar tbusy;
- uint chars = 0;
- u16 thead, ttail, tmask, chead, ctail;
- ulong lock_flags = 0;
- ulong lock_flags2 = 0;
-
- if (tty == NULL)
- return(0);
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (0);
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (0);
-
- bs = ch->ch_bs;
- if (!bs)
- return (0);
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- tmask = (ch->ch_tsize - 1);
-
- /* Get Transmit queue pointers */
- thead = readw(&(bs->tx_head)) & tmask;
- ttail = readw(&(bs->tx_tail)) & tmask;
-
- /* Get tbusy flag */
- tbusy = readb(&(bs->tbusy));
-
- /* Get Command queue pointers */
- chead = readw(&(ch->ch_cm->cm_head));
- ctail = readw(&(ch->ch_cm->cm_tail));
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- /*
- * The only way we know for sure if there is no pending
- * data left to be transferred, is if:
- * 1) Transmit head and tail are equal (empty).
- * 2) Command queue head and tail are equal (empty).
- * 3) The "TBUSY" flag is 0. (Transmitter not busy).
- */
-
- if ((ttail == thead) && (tbusy == 0) && (chead == ctail)) {
- chars = 0;
- }
- else {
- if (thead >= ttail)
- chars = thead - ttail;
- else
- chars = thead - ttail + ch->ch_tsize;
- /*
- * Fudge factor here.
- * If chars is zero, we know that the command queue had
- * something in it or tbusy was set. Because we cannot
- * be sure if there is still some data to be transmitted,
- * lets lie, and tell ld we have 1 byte left.
- */
- if (chars == 0) {
- /*
- * If TBUSY is still set, and our tx buffers are empty,
- * force the firmware to send me another wakeup after
- * TBUSY has been cleared.
- */
- if (tbusy != 0) {
- DGAP_LOCK(ch->ch_lock, lock_flags);
- un->un_flags |= UN_EMPTY;
- writeb(1, &(bs->iempty));
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
- }
- chars = 1;
- }
- }
-
- DPR_WRITE(("dgap_tty_chars_in_buffer. Port: %x - %d (head: %d tail: %d tsize: %d)\n",
- ch->ch_portnum, chars, thead, ttail, ch->ch_tsize));
- return(chars);
-}
-
-
-static int dgap_wait_for_drain(struct tty_struct *tty)
-{
- struct channel_t *ch;
- struct un_t *un;
- struct bs_t *bs;
- int ret = -EIO;
- uint count = 1;
- ulong lock_flags = 0;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return ret;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return ret;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return ret;
-
- bs = ch->ch_bs;
- if (!bs)
- return ret;
-
- ret = 0;
-
- DPR_DRAIN(("dgap_wait_for_drain start\n"));
-
- /* Loop until data is drained */
- while (count != 0) {
-
- count = dgap_tty_chars_in_buffer(tty);
-
- if (count == 0)
- break;
-
- /* Set flag waiting for drain */
- DGAP_LOCK(ch->ch_lock, lock_flags);
- un->un_flags |= UN_EMPTY;
- writeb(1, &(bs->iempty));
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- /* Go to sleep till we get woken up */
- ret = wait_event_interruptible(un->un_flags_wait, ((un->un_flags & UN_EMPTY) == 0));
- /* If ret is non-zero, user ctrl-c'ed us */
- if (ret) {
- break;
- }
- }
-
- DGAP_LOCK(ch->ch_lock, lock_flags);
- un->un_flags &= ~(UN_EMPTY);
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- DPR_DRAIN(("dgap_wait_for_drain finish\n"));
- return (ret);
-}
-
-
-/*
- * dgap_maxcps_room
- *
- * Reduces bytes_available to the max number of characters
- * that can be sent currently given the maxcps value, and
- * returns the new bytes_available. This only affects printer
- * output.
- */
-static int dgap_maxcps_room(struct tty_struct *tty, int bytes_available)
-{
- struct channel_t *ch = NULL;
- struct un_t *un = NULL;
-
- if (tty == NULL)
- return (bytes_available);
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (bytes_available);
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (bytes_available);
-
- /*
- * If its not the Transparent print device, return
- * the full data amount.
- */
- if (un->un_type != DGAP_PRINT)
- return (bytes_available);
-
- if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0 ) {
- int cps_limit = 0;
- unsigned long current_time = jiffies;
- unsigned long buffer_time = current_time +
- (HZ * ch->ch_digi.digi_bufsize) / ch->ch_digi.digi_maxcps;
-
- if (ch->ch_cpstime < current_time) {
- /* buffer is empty */
- ch->ch_cpstime = current_time; /* reset ch_cpstime */
- cps_limit = ch->ch_digi.digi_bufsize;
- }
- else if (ch->ch_cpstime < buffer_time) {
- /* still room in the buffer */
- cps_limit = ((buffer_time - ch->ch_cpstime) * ch->ch_digi.digi_maxcps) / HZ;
- }
- else {
- /* no room in the buffer */
- cps_limit = 0;
- }
-
- bytes_available = min(cps_limit, bytes_available);
- }
-
- return (bytes_available);
-}
-
-
-static inline void dgap_set_firmware_event(struct un_t *un, unsigned int event)
-{
- struct channel_t *ch = NULL;
- struct bs_t *bs = NULL;
-
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return;
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
- bs = ch->ch_bs;
- if (!bs)
- return;
-
- if ((event & UN_LOW) != 0) {
- if ((un->un_flags & UN_LOW) == 0) {
- un->un_flags |= UN_LOW;
- writeb(1, &(bs->ilow));
- }
- }
- if ((event & UN_LOW) != 0) {
- if ((un->un_flags & UN_EMPTY) == 0) {
- un->un_flags |= UN_EMPTY;
- writeb(1, &(bs->iempty));
- }
- }
-}
-
-
-/*
- * dgap_tty_write_room()
- *
- * Return space available in Tx buffer
- */
-static int dgap_tty_write_room(struct tty_struct *tty)
-{
- struct channel_t *ch = NULL;
- struct un_t *un = NULL;
- struct bs_t *bs = NULL;
- u16 head, tail, tmask;
- int ret = 0;
- ulong lock_flags = 0;
-
- if (tty == NULL || dgap_TmpWriteBuf == NULL)
- return(0);
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (0);
-
- bs = ch->ch_bs;
- if (!bs)
- return (0);
-
- DGAP_LOCK(ch->ch_lock, lock_flags);
-
- tmask = ch->ch_tsize - 1;
- head = readw(&(bs->tx_head)) & tmask;
- tail = readw(&(bs->tx_tail)) & tmask;
-
- if ((ret = tail - head - 1) < 0)
- ret += ch->ch_tsize;
-
- /* Limit printer to maxcps */
- ret = dgap_maxcps_room(tty, ret);
-
- /*
- * If we are printer device, leave space for
- * possibly both the on and off strings.
- */
- if (un->un_type == DGAP_PRINT) {
- if (!(ch->ch_flags & CH_PRON))
- ret -= ch->ch_digi.digi_onlen;
- ret -= ch->ch_digi.digi_offlen;
- }
- else {
- if (ch->ch_flags & CH_PRON)
- ret -= ch->ch_digi.digi_offlen;
- }
-
- if (ret < 0)
- ret = 0;
-
- /*
- * Schedule FEP to wake us up if needed.
- *
- * TODO: This might be overkill...
- * Do we really need to schedule callbacks from the FEP
- * in every case? Can we get smarter based on ret?
- */
- dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- DPR_WRITE(("dgap_tty_write_room - %d tail: %d head: %d\n", ret, tail, head));
-
- return(ret);
-}
-
-
-/*
- * dgap_tty_put_char()
- *
- * Put a character into ch->ch_buf
- *
- * - used by the line discipline for OPOST processing
- */
-static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c)
-{
- /*
- * Simply call tty_write.
- */
- DPR_WRITE(("dgap_tty_put_char called\n"));
- dgap_tty_write(tty, &c, 1);
- return 1;
-}
-
-
-/*
- * dgap_tty_write()
- *
- * Take data from the user or kernel and send it out to the FEP.
- * In here exists all the Transparent Print magic as well.
- */
-static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
- struct channel_t *ch = NULL;
- struct un_t *un = NULL;
- struct bs_t *bs = NULL;
- char *vaddr = NULL;
- u16 head, tail, tmask, remain;
- int bufcount = 0, n = 0;
- int orig_count = 0;
- ulong lock_flags;
- int from_user = 0;
-
- if (tty == NULL || dgap_TmpWriteBuf == NULL)
- return(0);
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (0);
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return(0);
-
- bs = ch->ch_bs;
- if (!bs)
- return(0);
-
- if (!count)
- return(0);
-
- DPR_WRITE(("dgap_tty_write: Port: %x tty=%p user=%d len=%d\n",
- ch->ch_portnum, tty, from_user, count));
-
- /*
- * Store original amount of characters passed in.
- * This helps to figure out if we should ask the FEP
- * to send us an event when it has more space available.
- */
- orig_count = count;
-
- DGAP_LOCK(ch->ch_lock, lock_flags);
-
- /* Get our space available for the channel from the board */
- tmask = ch->ch_tsize - 1;
- head = readw(&(bs->tx_head)) & tmask;
- tail = readw(&(bs->tx_tail)) & tmask;
-
- if ((bufcount = tail - head - 1) < 0)
- bufcount += ch->ch_tsize;
-
- DPR_WRITE(("%d: bufcount: %x count: %x tail: %x head: %x tmask: %x\n",
- __LINE__, bufcount, count, tail, head, tmask));
-
- /*
- * Limit printer output to maxcps overall, with bursts allowed
- * up to bufsize characters.
- */
- bufcount = dgap_maxcps_room(tty, bufcount);
-
- /*
- * Take minimum of what the user wants to send, and the
- * space available in the FEP buffer.
- */
- count = min(count, bufcount);
-
- /*
- * Bail if no space left.
- */
- if (count <= 0) {
- dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
- return(0);
- }
-
- /*
- * Output the printer ON string, if we are in terminal mode, but
- * need to be in printer mode.
- */
- if ((un->un_type == DGAP_PRINT) && !(ch->ch_flags & CH_PRON)) {
- dgap_wmove(ch, ch->ch_digi.digi_onstr,
- (int) ch->ch_digi.digi_onlen);
- head = readw(&(bs->tx_head)) & tmask;
- ch->ch_flags |= CH_PRON;
- }
-
- /*
- * On the other hand, output the printer OFF string, if we are
- * currently in printer mode, but need to output to the terminal.
- */
- if ((un->un_type != DGAP_PRINT) && (ch->ch_flags & CH_PRON)) {
- dgap_wmove(ch, ch->ch_digi.digi_offstr,
- (int) ch->ch_digi.digi_offlen);
- head = readw(&(bs->tx_head)) & tmask;
- ch->ch_flags &= ~CH_PRON;
- }
-
- /*
- * If there is nothing left to copy, or I can't handle any more data, leave.
- */
- if (count <= 0) {
- dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
- return(0);
- }
-
- if (from_user) {
-
- count = min(count, WRITEBUFLEN);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- /*
- * If data is coming from user space, copy it into a temporary
- * buffer so we don't get swapped out while doing the copy to
- * the board.
- */
- /* we're allowed to block if it's from_user */
- if (down_interruptible(&dgap_TmpWriteSem)) {
- return (-EINTR);
- }
-
- if (copy_from_user(dgap_TmpWriteBuf, (const uchar __user *) buf, count)) {
- up(&dgap_TmpWriteSem);
- printk("Write: Copy from user failed!\n");
- return -EFAULT;
- }
-
- DGAP_LOCK(ch->ch_lock, lock_flags);
-
- buf = dgap_TmpWriteBuf;
- }
-
- n = count;
-
- /*
- * If the write wraps over the top of the circular buffer,
- * move the portion up to the wrap point, and reset the
- * pointers to the bottom.
- */
- remain = ch->ch_tstart + ch->ch_tsize - head;
-
- if (n >= remain) {
- n -= remain;
- vaddr = ch->ch_taddr + head;
-
- memcpy_toio(vaddr, (uchar *) buf, remain);
- dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, remain);
-
- head = ch->ch_tstart;
- buf += remain;
- }
-
- if (n > 0) {
-
- /*
- * Move rest of data.
- */
- vaddr = ch->ch_taddr + head;
- remain = n;
-
- memcpy_toio(vaddr, (uchar *) buf, remain);
- dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, remain);
-
- head += remain;
-
- }
-
- if (count) {
- ch->ch_txcount += count;
- head &= tmask;
- writew(head, &(bs->tx_head));
- }
-
-
- dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
-
- /*
- * If this is the print device, and the
- * printer is still on, we need to turn it
- * off before going idle. If the buffer is
- * non-empty, wait until it goes empty.
- * Otherwise turn it off right now.
- */
- if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON)) {
- tail = readw(&(bs->tx_tail)) & tmask;
-
- if (tail != head) {
- un->un_flags |= UN_EMPTY;
- writeb(1, &(bs->iempty));
- }
- else {
- dgap_wmove(ch, ch->ch_digi.digi_offstr,
- (int) ch->ch_digi.digi_offlen);
- head = readw(&(bs->tx_head)) & tmask;
- ch->ch_flags &= ~CH_PRON;
- }
- }
-
- /* Update printer buffer empty time. */
- if ((un->un_type == DGAP_PRINT) && (ch->ch_digi.digi_maxcps > 0)
- && (ch->ch_digi.digi_bufsize > 0)) {
- ch->ch_cpstime += (HZ * count) / ch->ch_digi.digi_maxcps;
- }
-
- if (from_user) {
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
- up(&dgap_TmpWriteSem);
- }
- else {
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
- }
-
- DPR_WRITE(("Write finished - Write %d bytes of %d.\n", count, orig_count));
-
- return (count);
-}
-
-
-
-/*
- * Return modem signals to ld.
- */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
-static int dgap_tty_tiocmget(struct tty_struct *tty)
-#else
-static int dgap_tty_tiocmget(struct tty_struct *tty, struct file *file)
-#endif
-{
- struct channel_t *ch;
- struct un_t *un;
- int result = -EIO;
- uchar mstat = 0;
- ulong lock_flags;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return result;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return result;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return result;
-
- DPR_IOCTL(("dgap_tty_tiocmget start\n"));
-
- DGAP_LOCK(ch->ch_lock, lock_flags);
-
- mstat = readb(&(ch->ch_bs->m_stat));
- /* Append any outbound signals that might be pending... */
- mstat |= ch->ch_mostat;
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- result = 0;
-
- if (mstat & D_DTR(ch))
- result |= TIOCM_DTR;
- if (mstat & D_RTS(ch))
- result |= TIOCM_RTS;
- if (mstat & D_CTS(ch))
- result |= TIOCM_CTS;
- if (mstat & D_DSR(ch))
- result |= TIOCM_DSR;
- if (mstat & D_RI(ch))
- result |= TIOCM_RI;
- if (mstat & D_CD(ch))
- result |= TIOCM_CD;
-
- DPR_IOCTL(("dgap_tty_tiocmget finish\n"));
-
- return result;
-}
-
-
-/*
- * dgap_tty_tiocmset()
- *
- * Set modem signals, called by ld.
- */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
-static int dgap_tty_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-#else
-static int dgap_tty_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
-#endif
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- int ret = -EIO;
- ulong lock_flags;
- ulong lock_flags2;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return ret;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return ret;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return ret;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return ret;
-
- DPR_IOCTL(("dgap_tty_tiocmset start\n"));
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- if (set & TIOCM_RTS) {
- ch->ch_mforce |= D_RTS(ch);
- ch->ch_mval |= D_RTS(ch);
- }
-
- if (set & TIOCM_DTR) {
- ch->ch_mforce |= D_DTR(ch);
- ch->ch_mval |= D_DTR(ch);
- }
-
- if (clear & TIOCM_RTS) {
- ch->ch_mforce |= D_RTS(ch);
- ch->ch_mval &= ~(D_RTS(ch));
- }
-
- if (clear & TIOCM_DTR) {
- ch->ch_mforce |= D_DTR(ch);
- ch->ch_mval &= ~(D_DTR(ch));
- }
-
- dgap_param(tty);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_tty_tiocmset finish\n"));
-
- return (0);
-}
-
-
-
-/*
- * dgap_tty_send_break()
- *
- * Send a Break, called by ld.
- */
-static int dgap_tty_send_break(struct tty_struct *tty, int msec)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- int ret = -EIO;
- ulong lock_flags;
- ulong lock_flags2;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return ret;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return ret;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return ret;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return ret;
-
- switch (msec) {
- case -1:
- msec = 0xFFFF;
- break;
- case 0:
- msec = 1;
- break;
- default:
- msec /= 10;
- break;
- }
-
- DPR_IOCTL(("dgap_tty_send_break start 1. %lx\n", jiffies));
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-#if 0
- dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
-#endif
- dgap_cmdw(ch, SBREAK, (u16) msec, 0);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_tty_send_break finish\n"));
-
- return (0);
-}
-
-
-
-
-/*
- * dgap_tty_wait_until_sent()
- *
- * wait until data has been transmitted, called by ld.
- */
-static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- int rc;
- rc = dgap_wait_for_drain(tty);
- if (rc) {
- DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
- return;
- }
- return;
-}
-
-
-
-/*
- * dgap_send_xchar()
- *
- * send a high priority character, called by ld.
- */
-static void dgap_tty_send_xchar(struct tty_struct *tty, char c)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- ulong lock_flags;
- ulong lock_flags2;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return;
-
- DPR_IOCTL(("dgap_tty_send_xchar start 1. %lx\n", jiffies));
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- /*
- * This is technically what we should do.
- * However, the NIST tests specifically want
- * to see each XON or XOFF character that it
- * sends, so lets just send each character
- * by hand...
- */
-#if 0
- if (c == STOP_CHAR(tty)) {
- dgap_cmdw(ch, RPAUSE, 0, 0);
- }
- else if (c == START_CHAR(tty)) {
- dgap_cmdw(ch, RRESUME, 0, 0);
- }
- else {
- dgap_wmove(ch, &c, 1);
- }
-#else
- dgap_wmove(ch, &c, 1);
-#endif
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_tty_send_xchar finish\n"));
-
- return;
-}
-
-
-
-
-/*
- * Return modem signals to ld.
- */
-static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value)
-{
- int result = 0;
- uchar mstat = 0;
- ulong lock_flags;
- int rc = 0;
-
- DPR_IOCTL(("dgap_get_modem_info start\n"));
-
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return(-ENXIO);
-
- DGAP_LOCK(ch->ch_lock, lock_flags);
-
- mstat = readb(&(ch->ch_bs->m_stat));
- /* Append any outbound signals that might be pending... */
- mstat |= ch->ch_mostat;
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- result = 0;
-
- if (mstat & D_DTR(ch))
- result |= TIOCM_DTR;
- if (mstat & D_RTS(ch))
- result |= TIOCM_RTS;
- if (mstat & D_CTS(ch))
- result |= TIOCM_CTS;
- if (mstat & D_DSR(ch))
- result |= TIOCM_DSR;
- if (mstat & D_RI(ch))
- result |= TIOCM_RI;
- if (mstat & D_CD(ch))
- result |= TIOCM_CD;
-
- rc = put_user(result, value);
-
- DPR_IOCTL(("dgap_get_modem_info finish\n"));
- return(rc);
-}
-
-
-/*
- * dgap_set_modem_info()
- *
- * Set modem signals, called by ld.
- */
-static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- int ret = -ENXIO;
- unsigned int arg = 0;
- ulong lock_flags;
- ulong lock_flags2;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return ret;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return ret;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return ret;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return ret;
-
- DPR_IOCTL(("dgap_set_modem_info() start\n"));
-
- ret = get_user(arg, value);
- if (ret) {
- DPR_IOCTL(("dgap_set_modem_info %d ret: %x. finished.\n", __LINE__, ret));
- return(ret);
- }
-
- DPR_IOCTL(("dgap_set_modem_info: command: %x arg: %x\n", command, arg));
-
- switch (command) {
- case TIOCMBIS:
- if (arg & TIOCM_RTS) {
- ch->ch_mforce |= D_RTS(ch);
- ch->ch_mval |= D_RTS(ch);
- }
-
- if (arg & TIOCM_DTR) {
- ch->ch_mforce |= D_DTR(ch);
- ch->ch_mval |= D_DTR(ch);
- }
-
- break;
-
- case TIOCMBIC:
- if (arg & TIOCM_RTS) {
- ch->ch_mforce |= D_RTS(ch);
- ch->ch_mval &= ~(D_RTS(ch));
- }
-
- if (arg & TIOCM_DTR) {
- ch->ch_mforce |= D_DTR(ch);
- ch->ch_mval &= ~(D_DTR(ch));
- }
-
- break;
-
- case TIOCMSET:
- ch->ch_mforce = D_DTR(ch)|D_RTS(ch);
-
- if (arg & TIOCM_RTS) {
- ch->ch_mval |= D_RTS(ch);
- }
- else {
- ch->ch_mval &= ~(D_RTS(ch));
- }
-
- if (arg & TIOCM_DTR) {
- ch->ch_mval |= (D_DTR(ch));
- }
- else {
- ch->ch_mval &= ~(D_DTR(ch));
- }
-
- break;
-
- default:
- return(-EINVAL);
- }
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- dgap_param(tty);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_set_modem_info finish\n"));
-
- return (0);
-}
-
-
-/*
- * dgap_tty_digigeta()
- *
- * Ioctl to get the information for ditty.
- *
- *
- *
- */
-static int dgap_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo)
-{
- struct channel_t *ch;
- struct un_t *un;
- struct digi_t tmp;
- ulong lock_flags;
-
- if (!retinfo)
- return (-EFAULT);
-
- if (!tty || tty->magic != TTY_MAGIC)
- return (-EFAULT);
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (-EFAULT);
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (-EFAULT);
-
- memset(&tmp, 0, sizeof(tmp));
-
- DGAP_LOCK(ch->ch_lock, lock_flags);
- memcpy(&tmp, &ch->ch_digi, sizeof(tmp));
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return (-EFAULT);
-
- return (0);
-}
-
-
-/*
- * dgap_tty_digiseta()
- *
- * Ioctl to set the information for ditty.
- *
- *
- *
- */
-static int dgap_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- struct digi_t new_digi;
- ulong lock_flags = 0;
- unsigned long lock_flags2;
-
- DPR_IOCTL(("DIGI_SETA start\n"));
-
- if (!tty || tty->magic != TTY_MAGIC)
- return (-EFAULT);
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (-EFAULT);
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (-EFAULT);
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (-EFAULT);
-
- if (copy_from_user(&new_digi, new_info, sizeof(struct digi_t))) {
- DPR_IOCTL(("DIGI_SETA failed copy_from_user\n"));
- return(-EFAULT);
- }
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- memcpy(&ch->ch_digi, &new_digi, sizeof(struct digi_t));
-
- if (ch->ch_digi.digi_maxcps < 1)
- ch->ch_digi.digi_maxcps = 1;
-
- if (ch->ch_digi.digi_maxcps > 10000)
- ch->ch_digi.digi_maxcps = 10000;
-
- if (ch->ch_digi.digi_bufsize < 10)
- ch->ch_digi.digi_bufsize = 10;
-
- if (ch->ch_digi.digi_maxchar < 1)
- ch->ch_digi.digi_maxchar = 1;
-
- if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize)
- ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize;
-
- if (ch->ch_digi.digi_onlen > DIGI_PLEN)
- ch->ch_digi.digi_onlen = DIGI_PLEN;
-
- if (ch->ch_digi.digi_offlen > DIGI_PLEN)
- ch->ch_digi.digi_offlen = DIGI_PLEN;
-
- dgap_param(tty);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("DIGI_SETA finish\n"));
-
- return(0);
-}
-
-
-/*
- * dgap_tty_digigetedelay()
- *
- * Ioctl to get the current edelay setting.
- *
- *
- *
- */
-static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo)
-{
- struct channel_t *ch;
- struct un_t *un;
- int tmp;
- ulong lock_flags;
-
- if (!retinfo)
- return (-EFAULT);
-
- if (!tty || tty->magic != TTY_MAGIC)
- return (-EFAULT);
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (-EFAULT);
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (-EFAULT);
-
- memset(&tmp, 0, sizeof(tmp));
-
- DGAP_LOCK(ch->ch_lock, lock_flags);
- tmp = readw(&(ch->ch_bs->edelay));
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return (-EFAULT);
-
- return (0);
-}
-
-
-/*
- * dgap_tty_digisetedelay()
- *
- * Ioctl to set the EDELAY setting
- *
- */
-static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- int new_digi;
- ulong lock_flags;
- ulong lock_flags2;
-
- DPR_IOCTL(("DIGI_SETA start\n"));
-
- if (!tty || tty->magic != TTY_MAGIC)
- return (-EFAULT);
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (-EFAULT);
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (-EFAULT);
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (-EFAULT);
-
- if (copy_from_user(&new_digi, new_info, sizeof(int))) {
- DPR_IOCTL(("DIGI_SETEDELAY failed copy_from_user\n"));
- return(-EFAULT);
- }
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- writew((u16) new_digi, &(ch->ch_bs->edelay));
-
- dgap_param(tty);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("DIGI_SETA finish\n"));
-
- return(0);
-}
-
-
-/*
- * dgap_tty_digigetcustombaud()
- *
- * Ioctl to get the current custom baud rate setting.
- */
-static int dgap_tty_digigetcustombaud(struct tty_struct *tty, int __user *retinfo)
-{
- struct channel_t *ch;
- struct un_t *un;
- int tmp;
- ulong lock_flags;
-
- if (!retinfo)
- return (-EFAULT);
-
- if (!tty || tty->magic != TTY_MAGIC)
- return (-EFAULT);
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (-EFAULT);
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (-EFAULT);
-
- memset(&tmp, 0, sizeof(tmp));
-
- DGAP_LOCK(ch->ch_lock, lock_flags);
- tmp = dgap_get_custom_baud(ch);
- DGAP_UNLOCK(ch->ch_lock, lock_flags);
-
- DPR_IOCTL(("DIGI_GETCUSTOMBAUD. Returning %d\n", tmp));
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return (-EFAULT);
-
- return (0);
-}
-
-
-/*
- * dgap_tty_digisetcustombaud()
- *
- * Ioctl to set the custom baud rate setting
- */
-static int dgap_tty_digisetcustombaud(struct tty_struct *tty, int __user *new_info)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- uint new_rate;
- ulong lock_flags;
- ulong lock_flags2;
-
- DPR_IOCTL(("DIGI_SETCUSTOMBAUD start\n"));
-
- if (!tty || tty->magic != TTY_MAGIC)
- return (-EFAULT);
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (-EFAULT);
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (-EFAULT);
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (-EFAULT);
-
-
- if (copy_from_user(&new_rate, new_info, sizeof(unsigned int))) {
- DPR_IOCTL(("DIGI_SETCUSTOMBAUD failed copy_from_user\n"));
- return(-EFAULT);
- }
-
- if (bd->bd_flags & BD_FEP5PLUS) {
-
- DPR_IOCTL(("DIGI_SETCUSTOMBAUD. Setting %d\n", new_rate));
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- ch->ch_custom_speed = new_rate;
-
- dgap_param(tty);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- }
-
- DPR_IOCTL(("DIGI_SETCUSTOMBAUD finish\n"));
-
- return(0);
-}
-
-
-/*
- * dgap_set_termios()
- */
-static void dgap_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- unsigned long lock_flags;
- unsigned long lock_flags2;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return;
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- ch->ch_c_cflag = tty->termios.c_cflag;
- ch->ch_c_iflag = tty->termios.c_iflag;
- ch->ch_c_oflag = tty->termios.c_oflag;
- ch->ch_c_lflag = tty->termios.c_lflag;
- ch->ch_startc = tty->termios.c_cc[VSTART];
- ch->ch_stopc = tty->termios.c_cc[VSTOP];
-
- dgap_carrier(ch);
- dgap_param(tty);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-}
-
-
-static void dgap_tty_throttle(struct tty_struct *tty)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- ulong lock_flags;
- ulong lock_flags2;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return;
-
- DPR_IOCTL(("dgap_tty_throttle start\n"));
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- ch->ch_flags |= (CH_RXBLOCK);
-#if 1
- dgap_cmdw(ch, RPAUSE, 0, 0);
-#endif
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_tty_throttle finish\n"));
-}
-
-
-static void dgap_tty_unthrottle(struct tty_struct *tty)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- ulong lock_flags;
- ulong lock_flags2;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return;
-
- DPR_IOCTL(("dgap_tty_unthrottle start\n"));
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- ch->ch_flags &= ~(CH_RXBLOCK);
-
-#if 1
- dgap_cmdw(ch, RRESUME, 0, 0);
-#endif
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_tty_unthrottle finish\n"));
-}
-
-
-static void dgap_tty_start(struct tty_struct *tty)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- ulong lock_flags;
- ulong lock_flags2;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return;
-
- DPR_IOCTL(("dgap_tty_start start\n"));
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- dgap_cmdw(ch, RESUMETX, 0, 0);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_tty_start finish\n"));
-}
-
-
-static void dgap_tty_stop(struct tty_struct *tty)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- ulong lock_flags;
- ulong lock_flags2;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return;
-
- DPR_IOCTL(("dgap_tty_stop start\n"));
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- dgap_cmdw(ch, PAUSETX, 0, 0);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_tty_stop finish\n"));
-}
-
-
-/*
- * dgap_tty_flush_chars()
- *
- * Flush the cook buffer
- *
- * Note to self, and any other poor souls who venture here:
- *
- * flush in this case DOES NOT mean dispose of the data.
- * instead, it means "stop buffering and send it if you
- * haven't already." Just guess how I figured that out... SRW 2-Jun-98
- *
- * It is also always called in interrupt context - JAR 8-Sept-99
- */
-static void dgap_tty_flush_chars(struct tty_struct *tty)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- ulong lock_flags;
- ulong lock_flags2;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return;
-
- DPR_IOCTL(("dgap_tty_flush_chars start\n"));
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- /* TODO: Do something here */
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_tty_flush_chars finish\n"));
-}
-
-
-
-/*
- * dgap_tty_flush_buffer()
- *
- * Flush Tx buffer (make in == out)
- */
-static void dgap_tty_flush_buffer(struct tty_struct *tty)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- ulong lock_flags;
- ulong lock_flags2;
- u16 head = 0;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return;
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return;
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return;
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return;
-
- DPR_IOCTL(("dgap_tty_flush_buffer on port: %d start\n", ch->ch_portnum));
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- ch->ch_flags &= ~CH_STOP;
- head = readw(&(ch->ch_bs->tx_head));
- dgap_cmdw(ch, FLUSHTX, (u16) head, 0);
- dgap_cmdw(ch, RESUMETX, 0, 0);
- if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
- ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
- wake_up_interruptible(&ch->ch_tun.un_flags_wait);
- }
- if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
- ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
- wake_up_interruptible(&ch->ch_pun.un_flags_wait);
- }
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- if (waitqueue_active(&tty->write_wait))
- wake_up_interruptible(&tty->write_wait);
- tty_wakeup(tty);
-
- DPR_IOCTL(("dgap_tty_flush_buffer finish\n"));
-}
-
-
-
-/*****************************************************************************
- *
- * The IOCTL function and all of its helpers
- *
- *****************************************************************************/
-
-/*
- * dgap_tty_ioctl()
- *
- * The usual assortment of ioctl's
- */
-static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
- unsigned long arg)
-{
- struct board_t *bd;
- struct channel_t *ch;
- struct un_t *un;
- int rc;
- u16 head = 0;
- ulong lock_flags = 0;
- ulong lock_flags2 = 0;
- void __user *uarg = (void __user *) arg;
-
- if (!tty || tty->magic != TTY_MAGIC)
- return (-ENODEV);
-
- un = tty->driver_data;
- if (!un || un->magic != DGAP_UNIT_MAGIC)
- return (-ENODEV);
-
- ch = un->un_ch;
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
- return (-ENODEV);
-
- bd = ch->ch_bd;
- if (!bd || bd->magic != DGAP_BOARD_MAGIC)
- return (-ENODEV);
-
- DPR_IOCTL(("dgap_tty_ioctl start on port %d - cmd %s (%x), arg %lx\n",
- ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- if (un->un_open_count <= 0) {
- DPR_BASIC(("dgap_tty_ioctl - unit not open.\n"));
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return(-EIO);
- }
-
- switch (cmd) {
-
- /* Here are all the standard ioctl's that we MUST implement */
-
- case TCSBRK:
- /*
- * TCSBRK is SVID version: non-zero arg --> no break
- * this behaviour is exploited by tcdrain().
- *
- * According to POSIX.1 spec (7.2.2.1.2) breaks should be
- * between 0.25 and 0.5 seconds so we'll ask for something
- * in the middle: 0.375 seconds.
- */
- rc = tty_check_change(tty);
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- if (rc) {
- return(rc);
- }
-
- rc = dgap_wait_for_drain(tty);
-
- if (rc) {
- DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
- return(-EINTR);
- }
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- if(((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP)) {
- dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
- }
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
- ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
-
- return(0);
-
-
- case TCSBRKP:
- /* support for POSIX tcsendbreak()
-
- * According to POSIX.1 spec (7.2.2.1.2) breaks should be
- * between 0.25 and 0.5 seconds so we'll ask for something
- * in the middle: 0.375 seconds.
- */
- rc = tty_check_change(tty);
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- if (rc) {
- return(rc);
- }
-
- rc = dgap_wait_for_drain(tty);
- if (rc) {
- DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
- return(-EINTR);
- }
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
- ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
-
- return(0);
-
- case TIOCSBRK:
- /*
- * FEP5 doesn't support turning on a break unconditionally.
- * The FEP5 device will stop sending a break automatically
- * after the specified time value that was sent when turning on
- * the break.
- */
- rc = tty_check_change(tty);
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- if (rc) {
- return(rc);
- }
-
- rc = dgap_wait_for_drain(tty);
- if (rc) {
- DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
- return(-EINTR);
- }
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
-
- dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
- ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
-
- return 0;
-
- case TIOCCBRK:
- /*
- * FEP5 doesn't support turning off a break unconditionally.
- * The FEP5 device will stop sending a break automatically
- * after the specified time value that was sent when turning on
- * the break.
- */
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return 0;
-
- case TIOCGSOFTCAR:
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) arg);
- return(rc);
-
- case TIOCSSOFTCAR:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- rc = get_user(arg, (unsigned long __user *) arg);
- if (rc)
- return(rc);
-
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
- tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
- dgap_param(tty);
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- return(0);
-
- case TIOCMGET:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return(dgap_get_modem_info(ch, uarg));
-
- case TIOCMBIS:
- case TIOCMBIC:
- case TIOCMSET:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return(dgap_set_modem_info(tty, cmd, uarg));
-
- /*
- * Here are any additional ioctl's that we want to implement
- */
-
- case TCFLSH:
- /*
- * The linux tty driver doesn't have a flush
- * input routine for the driver, assuming all backed
- * up data is in the line disc. buffers. However,
- * we all know that's not the case. Here, we
- * act on the ioctl, but then lie and say we didn't
- * so the line discipline will process the flush
- * also.
- */
- rc = tty_check_change(tty);
- if (rc) {
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return(rc);
- }
-
- if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) {
- if (!(un->un_type == DGAP_PRINT)) {
- head = readw(&(ch->ch_bs->rx_head));
- writew(head, &(ch->ch_bs->rx_tail));
- writeb(0, &(ch->ch_bs->orun));
- }
- }
-
- if ((arg == TCOFLUSH) || (arg == TCIOFLUSH)) {
- ch->ch_flags &= ~CH_STOP;
- head = readw(&(ch->ch_bs->tx_head));
- dgap_cmdw(ch, FLUSHTX, (u16) head, 0 );
- dgap_cmdw(ch, RESUMETX, 0, 0);
- if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
- ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
- wake_up_interruptible(&ch->ch_tun.un_flags_wait);
- }
- if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
- ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
- wake_up_interruptible(&ch->ch_pun.un_flags_wait);
- }
- if (waitqueue_active(&tty->write_wait))
- wake_up_interruptible(&tty->write_wait);
-
- /* Can't hold any locks when calling tty_wakeup! */
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- tty_wakeup(tty);
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
- }
-
- /* pretend we didn't recognize this IOCTL */
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_tty_ioctl (LINE:%d) finish on port %d - cmd %s (%x), arg %lx\n",
- __LINE__, ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
-
- return(-ENOIOCTLCMD);
-
- case TCSETSF:
- case TCSETSW:
- /*
- * The linux tty driver doesn't have a flush
- * input routine for the driver, assuming all backed
- * up data is in the line disc. buffers. However,
- * we all know that's not the case. Here, we
- * act on the ioctl, but then lie and say we didn't
- * so the line discipline will process the flush
- * also.
- */
- if (cmd == TCSETSF) {
- /* flush rx */
- ch->ch_flags &= ~CH_STOP;
- head = readw(&(ch->ch_bs->rx_head));
- writew(head, &(ch->ch_bs->rx_tail));
- }
-
- /* now wait for all the output to drain */
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- rc = dgap_wait_for_drain(tty);
- if (rc) {
- DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
- return(-EINTR);
- }
-
- DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
- ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
-
- /* pretend we didn't recognize this */
- return(-ENOIOCTLCMD);
-
- case TCSETAW:
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- rc = dgap_wait_for_drain(tty);
- if (rc) {
- DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
- return(-EINTR);
- }
-
- /* pretend we didn't recognize this */
- return(-ENOIOCTLCMD);
-
- case TCXONC:
- /*
- * The Linux Line Discipline (LD) would do this for us if we
- * let it, but we have the special firmware options to do this
- * the "right way" regardless of hardware or software flow
- * control so we'll do it outselves instead of letting the LD
- * do it.
- */
- rc = tty_check_change(tty);
- if (rc) {
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return(rc);
- }
-
- DPR_IOCTL(("dgap_ioctl - in TCXONC - %d\n", cmd));
- switch (arg) {
-
- case TCOON:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- dgap_tty_start(tty);
- return(0);
- case TCOOFF:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- dgap_tty_stop(tty);
- return(0);
- case TCION:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- /* Make the ld do it */
- return(-ENOIOCTLCMD);
- case TCIOFF:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- /* Make the ld do it */
- return(-ENOIOCTLCMD);
- default:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return(-EINVAL);
- }
-
- case DIGI_GETA:
- /* get information for ditty */
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return(dgap_tty_digigeta(tty, uarg));
-
- case DIGI_SETAW:
- case DIGI_SETAF:
-
- /* set information for ditty */
- if (cmd == (DIGI_SETAW)) {
-
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- rc = dgap_wait_for_drain(tty);
- if (rc) {
- DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
- return(-EINTR);
- }
- DGAP_LOCK(bd->bd_lock, lock_flags);
- DGAP_LOCK(ch->ch_lock, lock_flags2);
- }
- else {
- tty_ldisc_flush(tty);
- }
- /* fall thru */
-
- case DIGI_SETA:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return(dgap_tty_digiseta(tty, uarg));
-
- case DIGI_GEDELAY:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return(dgap_tty_digigetedelay(tty, uarg));
-
- case DIGI_SEDELAY:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return(dgap_tty_digisetedelay(tty, uarg));
-
- case DIGI_GETCUSTOMBAUD:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return(dgap_tty_digigetcustombaud(tty, uarg));
-
- case DIGI_SETCUSTOMBAUD:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return(dgap_tty_digisetcustombaud(tty, uarg));
-
- case DIGI_RESET_PORT:
- dgap_firmware_reset_port(ch);
- dgap_param(tty);
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
- return 0;
-
- default:
- DGAP_UNLOCK(ch->ch_lock, lock_flags2);
- DGAP_UNLOCK(bd->bd_lock, lock_flags);
-
- DPR_IOCTL(("dgap_tty_ioctl - in default\n"));
- DPR_IOCTL(("dgap_tty_ioctl end - cmd %s (%x), arg %lx\n",
- dgap_ioctl_name(cmd), cmd, arg));
-
- return(-ENOIOCTLCMD);
- }
-}
diff --git a/drivers/staging/dgap/dgap_tty.h b/drivers/staging/dgap/dgap_tty.h
deleted file mode 100644
index 464a460b6be8..000000000000
--- a/drivers/staging/dgap/dgap_tty.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
- */
-
-#ifndef __DGAP_TTY_H
-#define __DGAP_TTY_H
-
-#include "dgap_driver.h"
-
-int dgap_tty_register(struct board_t *brd);
-
-int dgap_tty_preinit(void);
-int dgap_tty_init(struct board_t *);
-
-void dgap_tty_post_uninit(void);
-void dgap_tty_uninit(struct board_t *);
-
-void dgap_carrier(struct channel_t *ch);
-void dgap_input(struct channel_t *ch);
-
-
-#endif
diff --git a/drivers/staging/dgap/dgap_types.h b/drivers/staging/dgap/dgap_types.h
deleted file mode 100644
index eca38c7f359d..000000000000
--- a/drivers/staging/dgap/dgap_types.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
- */
-
-#ifndef __DGAP_TYPES_H
-#define __DGAP_TYPES_H
-
-#ifndef TRUE
-# define TRUE 1
-#endif
-
-#ifndef FALSE
-# define FALSE 0
-#endif
-
-/* Required for our shared headers! */
-typedef unsigned char uchar;
-
-#endif
diff --git a/drivers/staging/dgap/digi.h b/drivers/staging/dgap/digi.h
deleted file mode 100644
index bcea4f734a32..000000000000
--- a/drivers/staging/dgap/digi.h
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: digi.h,v 1.1 2009/10/23 14:01:57 markh Exp $
- *
- * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
- */
-
-#ifndef __DIGI_H
-#define __DIGI_H
-
-/************************************************************************
- *** Definitions for Digi ditty(1) command.
- ************************************************************************/
-
-
-/*
- * Copyright (c) 1988-96 Digi International Inc., All Rights Reserved.
- */
-
-/************************************************************************
- * This module provides application access to special Digi
- * serial line enhancements which are not standard UNIX(tm) features.
- ************************************************************************/
-
-#if !defined(TIOCMODG)
-
-#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */
-#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */
-
-#ifndef TIOCM_LE
-#define TIOCM_LE 0x01 /* line enable */
-#define TIOCM_DTR 0x02 /* data terminal ready */
-#define TIOCM_RTS 0x04 /* request to send */
-#define TIOCM_ST 0x08 /* secondary transmit */
-#define TIOCM_SR 0x10 /* secondary receive */
-#define TIOCM_CTS 0x20 /* clear to send */
-#define TIOCM_CAR 0x40 /* carrier detect */
-#define TIOCM_RNG 0x80 /* ring indicator */
-#define TIOCM_DSR 0x100 /* data set ready */
-#define TIOCM_RI TIOCM_RNG /* ring (alternate) */
-#define TIOCM_CD TIOCM_CAR /* carrier detect (alt) */
-#endif
-
-#endif
-
-#if !defined(TIOCMSET)
-#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */
-#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */
-#endif
-
-#if !defined(TIOCMBIC)
-#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */
-#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */
-#endif
-
-
-#if !defined(TIOCSDTR)
-#define TIOCSDTR ('e'<<8) | 0 /* set DTR */
-#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */
-#endif
-
-/************************************************************************
- * Ioctl command arguments for DIGI parameters.
- ************************************************************************/
-#define DIGI_GETA ('e'<<8) | 94 /* Read params */
-
-#define DIGI_SETA ('e'<<8) | 95 /* Set params */
-#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */
-#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */
-
-#define DIGI_KME ('e'<<8) | 98 /* Read/Write Host */
- /* Adapter Memory */
-
-#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */
- /* control characters */
-#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */
- /* control characters */
-#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */
- /* flow control chars */
-#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */
- /* flow control chars */
-
-#define DIGI_GEDELAY ('d'<<8) | 246 /* Get edelay */
-#define DIGI_SEDELAY ('d'<<8) | 247 /* Set edelay */
-
-struct digiflow_t {
- unsigned char startc; /* flow cntl start char */
- unsigned char stopc; /* flow cntl stop char */
-};
-
-
-#ifdef FLOW_2200
-#define F2200_GETA ('e'<<8) | 104 /* Get 2x36 flow cntl flags */
-#define F2200_SETAW ('e'<<8) | 105 /* Set 2x36 flow cntl flags */
-#define F2200_MASK 0x03 /* 2200 flow cntl bit mask */
-#define FCNTL_2200 0x01 /* 2x36 terminal flow cntl */
-#define PCNTL_2200 0x02 /* 2x36 printer flow cntl */
-#define F2200_XON 0xf8
-#define P2200_XON 0xf9
-#define F2200_XOFF 0xfa
-#define P2200_XOFF 0xfb
-
-#define FXOFF_MASK 0x03 /* 2200 flow status mask */
-#define RCVD_FXOFF 0x01 /* 2x36 Terminal XOFF rcvd */
-#define RCVD_PXOFF 0x02 /* 2x36 Printer XOFF rcvd */
-#endif
-
-/************************************************************************
- * Values for digi_flags
- ************************************************************************/
-#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */
-#define DIGI_FAST 0x0002 /* Fast baud rates */
-#define RTSPACE 0x0004 /* RTS input flow control */
-#define CTSPACE 0x0008 /* CTS output flow control */
-#define DSRPACE 0x0010 /* DSR output flow control */
-#define DCDPACE 0x0020 /* DCD output flow control */
-#define DTRPACE 0x0040 /* DTR input flow control */
-#define DIGI_COOK 0x0080 /* Cooked processing done in FEP */
-#define DIGI_FORCEDCD 0x0100 /* Force carrier */
-#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */
-#define DIGI_AIXON 0x0400 /* Aux flow control in fep */
-#define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl*/
-#define DIGI_PP_INPUT 0x1000 /* Change parallel port to input*/
-#define DIGI_DTR_TOGGLE 0x2000 /* Support DTR Toggle */
-#define DIGI_422 0x4000 /* for 422/232 selectable panel */
-#define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */
-
-/************************************************************************
- * These options are not supported on the comxi.
- ************************************************************************/
-#define DIGI_COMXI (DIGI_FAST|DIGI_COOK|DSRPACE|DCDPACE|DTRPACE)
-
-#define DIGI_PLEN 28 /* String length */
-#define DIGI_TSIZ 10 /* Terminal string len */
-
-/************************************************************************
- * Structure used with ioctl commands for DIGI parameters.
- ************************************************************************/
-struct digi_t {
- unsigned short digi_flags; /* Flags (see above) */
- unsigned short digi_maxcps; /* Max printer CPS */
- unsigned short digi_maxchar; /* Max chars in print queue */
- unsigned short digi_bufsize; /* Buffer size */
- unsigned char digi_onlen; /* Length of ON string */
- unsigned char digi_offlen; /* Length of OFF string */
- char digi_onstr[DIGI_PLEN]; /* Printer on string */
- char digi_offstr[DIGI_PLEN]; /* Printer off string */
- char digi_term[DIGI_TSIZ]; /* terminal string */
-};
-
-/************************************************************************
- * KME definitions and structures.
- ************************************************************************/
-#define RW_IDLE 0 /* Operation complete */
-#define RW_READ 1 /* Read Concentrator Memory */
-#define RW_WRITE 2 /* Write Concentrator Memory */
-
-struct rw_t {
- unsigned char rw_req; /* Request type */
- unsigned char rw_board; /* Host Adapter board number */
- unsigned char rw_conc; /* Concentrator number */
- unsigned char rw_reserved; /* Reserved for expansion */
- unsigned long rw_addr; /* Address in concentrator */
- unsigned short rw_size; /* Read/write request length */
- unsigned char rw_data[128]; /* Data to read/write */
-};
-
-/***********************************************************************
- * Shrink Buffer and Board Information definitions and structures.
-
- ************************************************************************/
- /* Board type return codes */
-#define PCXI_TYPE 1 /* Board type at the designated port is a PC/Xi */
-#define PCXM_TYPE 2 /* Board type at the designated port is a PC/Xm */
-#define PCXE_TYPE 3 /* Board type at the designated port is a PC/Xe */
-#define MCXI_TYPE 4 /* Board type at the designated port is a MC/Xi */
-#define COMXI_TYPE 5 /* Board type at the designated port is a COM/Xi */
-
- /* Non-Zero Result codes. */
-#define RESULT_NOBDFND 1 /* A Digi product at that port is not config installed */
-#define RESULT_NODESCT 2 /* A memory descriptor was not obtainable */
-#define RESULT_NOOSSIG 3 /* FEP/OS signature was not detected on the board */
-#define RESULT_TOOSML 4 /* Too small an area to shrink. */
-#define RESULT_NOCHAN 5 /* Channel structure for the board was not found */
-
-struct shrink_buf_struct {
- unsigned long shrink_buf_vaddr; /* Virtual address of board */
- unsigned long shrink_buf_phys; /* Physical address of board */
- unsigned long shrink_buf_bseg; /* Amount of board memory */
- unsigned long shrink_buf_hseg; /* '186 Beginning of Dual-Port */
-
- unsigned long shrink_buf_lseg; /* '186 Beginning of freed memory */
- unsigned long shrink_buf_mseg; /* Linear address from start of
- dual-port were freed memory
- begins, host viewpoint. */
-
- unsigned long shrink_buf_bdparam; /* Parameter for xxmemon and
- xxmemoff */
-
- unsigned long shrink_buf_reserva; /* Reserved */
- unsigned long shrink_buf_reservb; /* Reserved */
- unsigned long shrink_buf_reservc; /* Reserved */
- unsigned long shrink_buf_reservd; /* Reserved */
-
- unsigned char shrink_buf_result; /* Reason for call failing
- Zero is Good return */
- unsigned char shrink_buf_init; /* Non-Zero if it caused an
- xxinit call. */
-
- unsigned char shrink_buf_anports; /* Number of async ports */
- unsigned char shrink_buf_snports; /* Number of sync ports */
- unsigned char shrink_buf_type; /* Board type 1 = PC/Xi,
- 2 = PC/Xm,
- 3 = PC/Xe
- 4 = MC/Xi
- 5 = COMX/i */
- unsigned char shrink_buf_card; /* Card number */
-
-};
-
-/************************************************************************
- * Structure to get driver status information
- ************************************************************************/
-struct digi_dinfo {
- unsigned long dinfo_nboards; /* # boards configured */
- char dinfo_reserved[12]; /* for future expansion */
- char dinfo_version[16]; /* driver version */
-};
-
-#define DIGI_GETDD ('d'<<8) | 248 /* get driver info */
-
-/************************************************************************
- * Structure used with ioctl commands for per-board information
- *
- * physsize and memsize differ when board has "windowed" memory
- ************************************************************************/
-struct digi_info {
- unsigned long info_bdnum; /* Board number (0 based) */
- unsigned long info_ioport; /* io port address */
- unsigned long info_physaddr; /* memory address */
- unsigned long info_physsize; /* Size of host mem window */
- unsigned long info_memsize; /* Amount of dual-port mem */
- /* on board */
- unsigned short info_bdtype; /* Board type */
- unsigned short info_nports; /* number of ports */
- char info_bdstate; /* board state */
- char info_reserved[7]; /* for future expansion */
-};
-
-#define DIGI_GETBD ('d'<<8) | 249 /* get board info */
-
-struct digi_stat {
- unsigned int info_chan; /* Channel number (0 based) */
- unsigned int info_brd; /* Board number (0 based) */
- unsigned long info_cflag; /* cflag for channel */
- unsigned long info_iflag; /* iflag for channel */
- unsigned long info_oflag; /* oflag for channel */
- unsigned long info_mstat; /* mstat for channel */
- unsigned long info_tx_data; /* tx_data for channel */
- unsigned long info_rx_data; /* rx_data for channel */
- unsigned long info_hflow; /* hflow for channel */
- unsigned long info_reserved[8]; /* for future expansion */
-};
-
-#define DIGI_GETSTAT ('d'<<8) | 244 /* get board info */
-/************************************************************************
- *
- * Structure used with ioctl commands for per-channel information
- *
- ************************************************************************/
-struct digi_ch {
- unsigned long info_bdnum; /* Board number (0 based) */
- unsigned long info_channel; /* Channel index number */
- unsigned long info_ch_cflag; /* Channel cflag */
- unsigned long info_ch_iflag; /* Channel iflag */
- unsigned long info_ch_oflag; /* Channel oflag */
- unsigned long info_chsize; /* Channel structure size */
- unsigned long info_sleep_stat; /* sleep status */
- dev_t info_dev; /* device number */
- unsigned char info_initstate; /* Channel init state */
- unsigned char info_running; /* Channel running state */
- long reserved[8]; /* reserved for future use */
-};
-
-/*
-* This structure is used with the DIGI_FEPCMD ioctl to
-* tell the driver which port to send the command for.
-*/
-struct digi_cmd {
- int cmd;
- int word;
- int ncmds;
- int chan; /* channel index (zero based) */
- int bdid; /* board index (zero based) */
-};
-
-/*
-* info_sleep_stat defines
-*/
-#define INFO_RUNWAIT 0x0001
-#define INFO_WOPEN 0x0002
-#define INFO_TTIOW 0x0004
-#define INFO_CH_RWAIT 0x0008
-#define INFO_CH_WEMPTY 0x0010
-#define INFO_CH_WLOW 0x0020
-#define INFO_XXBUF_BUSY 0x0040
-
-#define DIGI_GETCH ('d'<<8) | 245 /* get board info */
-
-/* Board type definitions */
-
-#define SUBTYPE 0007
-#define T_PCXI 0000
-#define T_PCXM 0001
-#define T_PCXE 0002
-#define T_PCXR 0003
-#define T_SP 0004
-#define T_SP_PLUS 0005
-# define T_HERC 0000
-# define T_HOU 0001
-# define T_LON 0002
-# define T_CHA 0003
-#define FAMILY 0070
-#define T_COMXI 0000
-#define T_PCXX 0010
-#define T_CX 0020
-#define T_EPC 0030
-#define T_PCLITE 0040
-#define T_SPXX 0050
-#define T_AVXX 0060
-#define T_DXB 0070
-#define T_A2K_4_8 0070
-#define BUSTYPE 0700
-#define T_ISABUS 0000
-#define T_MCBUS 0100
-#define T_EISABUS 0200
-#define T_PCIBUS 0400
-
-/* Board State Definitions */
-
-#define BD_RUNNING 0x0
-#define BD_REASON 0x7f
-#define BD_NOTFOUND 0x1
-#define BD_NOIOPORT 0x2
-#define BD_NOMEM 0x3
-#define BD_NOBIOS 0x4
-#define BD_NOFEP 0x5
-#define BD_FAILED 0x6
-#define BD_ALLOCATED 0x7
-#define BD_TRIBOOT 0x8
-#define BD_BADKME 0x80
-
-#define DIGI_LOOPBACK ('d'<<8) | 252 /* Enable/disable UART internal loopback */
-#define DIGI_SPOLL ('d'<<8) | 254 /* change poller rate */
-
-#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) /* Set integer baud rate */
-#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) /* Get integer baud rate */
-#define DIGI_RESET_PORT ('e'<<8) | 93 /* Reset port */
-
-#endif /* DIGI_H */
diff --git a/drivers/staging/dgap/downld.c b/drivers/staging/dgap/downld.c
deleted file mode 100644
index 1f4aa2eca437..000000000000
--- a/drivers/staging/dgap/downld.c
+++ /dev/null
@@ -1,798 +0,0 @@
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: downld.c,v 1.6 2009/01/14 14:10:54 markh Exp $
- */
-
-/*
-** downld.c
-**
-** This is the daemon that sends the fep, bios, and concentrator images
-** from user space to the driver.
-** BUGS:
-** If the file changes in the middle of the download, you probably
-** will get what you deserve.
-**
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/errno.h>
-
-#include "dgap_types.h"
-#include "digi.h"
-#include "dgap_fep5.h"
-
-#include "dgap_downld.h"
-
-#include <string.h>
-#include <malloc.h>
-#include <stddef.h>
-#include <unistd.h>
-
-char *pgm;
-void myperror();
-
-/*
-** This structure is used to keep track of the different images available
-** to give to the driver. It is arranged so that the things that are
-** constants or that have defaults are first inthe strucutre to simplify
-** the table of initializers.
-*/
-struct image_info {
- short type; /* bios, fep, conc */
- short family; /* boards this applies to */
- short subtype; /* subtype */
- int len; /* size of image */
- char *image; /* ioctl struct + image */
- char *name;
- char *fname; /* filename of binary (i.e. "asfep.bin") */
- char *pathname; /* pathname to this binary ("/etc/dgap/xrfep.bin"); */
- time_t mtime; /* Last modification time */
-};
-
-#define IBIOS 0
-#define IFEP 1
-#define ICONC 2
-#define ICONFIG 3
-#define IBAD 4
-
-#define DEFAULT_LOC "/lib/firmware/dgap/"
-
-struct image_info *image_list;
-int nimages, count;
-
-struct image_info images[] = {
-{IBIOS, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxbios.bin", DEFAULT_LOC "fxbios.bin", 0 },
-{IFEP, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxfep.bin", DEFAULT_LOC "fxfep.bin", 0 },
-{ICONC, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxcon.bin", DEFAULT_LOC "fxcon.bin", 0 },
-
-{IBIOS, T_CX, SUBTYPE, 0, NULL, "C/X", "cxbios.bin", DEFAULT_LOC "cxbios.bin", 0 },
-{IFEP, T_CX, SUBTYPE, 0, NULL, "C/X", "cxhost.bin", DEFAULT_LOC "cxhost.bin", 0 },
-
-{IBIOS, T_CX, T_PCIBUS, 0, NULL, "C/X PCI", "cxpbios.bin", DEFAULT_LOC "cxpbios.bin", 0 },
-{IFEP, T_CX, T_PCIBUS, 0, NULL, "C/X PCI", "cxpfep.bin", DEFAULT_LOC "cxpfep.bin", 0 },
-
-{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "cxcon.bin", DEFAULT_LOC "cxcon.bin", 0 },
-{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "ibmcxcon.bin", DEFAULT_LOC "ibmcxcon.bin", 0 },
-{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "ibmencon.bin", DEFAULT_LOC "ibmencon.bin", 0 },
-
-{IBIOS, FAMILY, T_PCXR, 0, NULL, "PCXR", "xrbios.bin", DEFAULT_LOC "xrbios.bin", 0 },
-{IFEP, FAMILY, T_PCXR, 0, NULL, "PCXR", "xrfep.bin", DEFAULT_LOC "xrfep.bin", 0 },
-
-{IBIOS, T_PCLITE, SUBTYPE, 0, NULL, "X/em", "sxbios.bin", DEFAULT_LOC "sxbios.bin", 0 },
-{IFEP, T_PCLITE, SUBTYPE, 0, NULL, "X/em", "sxfep.bin", DEFAULT_LOC "sxfep.bin", 0 },
-
-{IBIOS, T_EPC, T_PCIBUS, 0, NULL, "PCI", "pcibios.bin", DEFAULT_LOC "pcibios.bin", 0 },
-{IFEP, T_EPC, T_PCIBUS, 0, NULL, "PCI", "pcifep.bin", DEFAULT_LOC "pcifep.bin", 0 },
-{ICONFIG, 0, 0, 0, NULL, NULL, "dgap.conf", "/etc/dgap.conf", 0 },
-
-/* IBAD/NULL entry indicating end-of-table */
-
-{IBAD, 0, 0, 0, NULL, NULL, NULL, NULL, 0 }
-
-} ;
-
-int errorprint = 1;
-int nodldprint = 1;
-int debugflag;
-int fd;
-
-struct downld_t *ip; /* Image pointer in current image */
-struct downld_t *dp; /* conc. download */
-
-
-/*
- * The same for either the FEP or the BIOS.
- * Append the downldio header, issue the ioctl, then free
- * the buffer. Not horribly CPU efficient, but quite RAM efficient.
- */
-
-void squirt(int req_type, int bdid, struct image_info *ii)
-{
- struct downldio *dliop;
- int size_buf;
- int sfd;
- struct stat sb;
-
- /*
- * If this binary comes from a file, stat it to see how
- * large it is. Yes, we intentionally do this each
- * time for the binary may change between loads.
- */
-
- if (ii->pathname) {
- sfd = open(ii->pathname, O_RDONLY);
-
- if (sfd < 0 ) {
- myperror(ii->pathname);
- goto squirt_end;
- }
-
- if (fstat(sfd, &sb) == -1 ) {
- myperror(ii->pathname);
- goto squirt_end;
- }
-
- ii->len = sb.st_size;
- }
-
- size_buf = ii->len + sizeof(struct downldio);
-
- /*
- * This buffer will be freed at the end of this function. It is
- * not resilient and should be around only long enough for the d/l
- * to happen.
- */
- dliop = (struct downldio *) malloc(size_buf);
-
- if (dliop == NULL) {
- fprintf(stderr,"%s: can't get %d bytes of memory; aborting\n",
- pgm, size_buf);
- exit (1);
- }
-
- /* Now, stick the image in fepimage. This can come from either
- * the compiled-in image or from the filesystem.
- */
- if (ii->pathname)
- read(sfd, dliop->image.fi.fepimage, ii->len);
- else
- memcpy(dliop ->image.fi.fepimage, ii->image, ii->len);
-
- dliop->req_type = req_type;
- dliop->bdid = bdid;
-
- dliop->image.fi.len = ii->len;
-
- if (debugflag)
- printf("sending %d bytes of %s %s from %s\n",
- ii->len,
- (ii->type == IFEP) ? "FEP" : (ii->type == IBIOS) ? "BIOS" : "CONFIG",
- ii->name ? ii->name : "",
- (ii->pathname) ? ii->pathname : "internal image" );
-
- if (ioctl(fd, DIGI_DLREQ_SET, (char *) dliop) == -1) {
- if(errorprint) {
- fprintf(stderr,
- "%s: warning - download ioctl failed\n",pgm);
- errorprint = 0;
- }
- sleep(2);
- }
-
-squirt_end:
-
- if (ii->pathname) {
- close(sfd);
- }
- free(dliop);
-}
-
-
-/*
- * See if we need to reload the download image in core
- *
- */
-void consider_file_rescan(struct image_info *ii)
-{
- int sfd;
- int len;
- struct stat sb;
-
- /* This operation only makes sense when we're working from a file */
-
- if (ii->pathname) {
-
- sfd = open (ii->pathname, O_RDONLY) ;
- if (sfd < 0 ) {
- myperror(ii->pathname);
- exit(1) ;
- }
-
- if( fstat(sfd,&sb) == -1 ) {
- myperror(ii->pathname);
- exit(1);
- }
-
- /* If the file hasn't changed since we last did this,
- * and we have not done a free() on the image, bail
- */
- if (ii->image && (sb.st_mtime == ii->mtime))
- goto end_rescan;
-
- ii->len = len = sb.st_size;
-
- /* Record the timestamp of the file */
- ii->mtime = sb.st_mtime;
-
- /* image should be NULL unless there is an image malloced
- * in already. Before we malloc again, make sure we don't
- * have a memory leak.
- */
- if ( ii->image ) {
- free( ii->image );
- /* ii->image = NULL; */ /* not necessary */
- }
-
- /* This image will be kept only long enough for the
- * download to happen. After sending the last block,
- * it will be freed
- */
- ii->image = malloc(len) ;
-
- if (ii->image == NULL) {
- fprintf(stderr,
- "%s: can't get %d bytes of memory; aborting\n",
- pgm, len);
- exit (1);
- }
-
- if (read(sfd, ii->image, len) < len) {
- fprintf(stderr,"%s: read error on %s; aborting\n",
- pgm, ii->pathname);
- exit (1);
- }
-
-end_rescan:
- close(sfd);
-
- }
-}
-
-/*
- * Scan for images to match the driver requests
- */
-
-struct image_info * find_conc_image()
-{
- int x;
- struct image_info *i = NULL;
-
- for ( x = 0; x < nimages; x++ ) {
- i=&image_list[x];
-
- if(i->type != ICONC)
- continue;
-
- consider_file_rescan(i) ;
-
- ip = (struct downld_t *) image_list[x].image;
- if (ip == NULL) continue;
-
- /*
- * When I removed Clusterport, I kept only the code that I
- * was SURE wasn't ClusterPort. We may not need the next two
- * lines of code.
- */
- if ((dp->dl_type != 'P' ) && ( ip->dl_srev == dp->dl_srev ))
- return i;
- }
- return NULL;
-}
-
-
-int main(int argc, char **argv)
-{
- struct downldio dlio;
- int offset, bsize;
- int x;
- char *down, *image, *fname;
- struct image_info *ii;
-
- pgm = argv[0];
- dp = &dlio.image.dl; /* conc. download */
-
- while((argc > 2) && !strcmp(argv[1],"-d")) {
- debugflag++ ;
- argc-- ;
- argv++ ;
- }
-
- if(argc < 2) {
- fprintf(stderr,
- "usage: %s download-device [image-file] ...\n",
- pgm);
- exit(1);
- }
-
-
-
- /*
- * Daemonize, unless debugging is turned on.
- */
- if (debugflag == 0) {
- switch (fork())
- {
- case 0:
- break;
-
- case -1:
- return 1;
-
- default:
- return 0;
- }
-
- setsid();
-
- /*
- * The child no longer needs "stdin", "stdout", or "stderr",
- * and should not block processes waiting for them to close.
- */
- fclose(stdin);
- fclose(stdout);
- fclose(stderr);
-
- }
-
- while (1) {
- if( (fd = open(argv[1], O_RDWR)) == -1 ) {
- sleep(1);
- }
- else
- break;
- }
-
- /*
- ** create a list of images to search through when trying to match
- ** requests from the driver. Put images from the command line in
- ** the list before built in images so that the command line images
- ** can override the built in ones.
- */
-
- /* allocate space for the list */
-
- nimages = argc - 2;
-
- /* count the number of default list entries */
-
- for (count = 0; images[count].type != IBAD; ++count) ;
-
- nimages += count;
-
- /* Really should just remove the variable "image_list".... robertl */
- image_list = images;
-
- /* get the images from the command line */
- for(x = 2; x < argc; x++) {
- int xx;
-
- /*
- * strip off any leading path information for
- * determining file type
- */
- if( (fname = strrchr(argv[x],'/')) == NULL)
- fname = argv[x];
- else
- fname++; /* skip the slash */
-
- for (xx = 0; xx < count; xx++) {
- if (strcmp(fname, images[xx].fname) == 0 ) {
- images[xx].pathname = argv[x];
-
- /* image should be NULL until */
- /* space is malloced */
- images[xx].image = NULL;
- }
- }
- }
-
- sleep(3);
-
- /*
- ** Endless loop: get a request from the fep, and service that request.
- */
- for(;;) {
- /* get the request */
- if (debugflag)
- printf("b4 get ioctl...");
-
- if (ioctl(fd,DIGI_DLREQ_GET, &dlio) == -1 ) {
- if (errorprint) {
- fprintf(stderr,
- "%s: warning - download ioctl failed\n",
- pgm);
- errorprint = 0;
- }
- sleep(2);
- } else {
- if (debugflag)
- printf("dlio.req_type is %d bd %d\n",
- dlio.req_type,dlio.bdid);
-
- switch(dlio.req_type) {
- case DLREQ_BIOS:
- /*
- ** find the bios image for this type
- */
- for ( x = 0; x < nimages; x++ ) {
- if(image_list[x].type != IBIOS)
- continue;
-
- if ((dlio.image.fi.type & FAMILY) ==
- image_list[x].family) {
-
- if ( image_list[x].family == T_CX ) {
- if ((dlio.image.fi.type & BUSTYPE)
- == T_PCIBUS ) {
- if ( image_list[x].subtype
- == T_PCIBUS )
- break;
- }
- else {
- break;
- }
- }
- else if ( image_list[x].family == T_EPC ) {
- /* If subtype of image is T_PCIBUS, it is */
- /* a PCI EPC image, so the board must */
- /* have bus type T_PCIBUS to match */
- if ((dlio.image.fi.type & BUSTYPE)
- == T_PCIBUS ) {
- if ( image_list[x].subtype
- == T_PCIBUS )
- break;
- }
- else {
- /* NON PCI EPC doesn't use PCI image */
- if ( image_list[x].subtype
- != T_PCIBUS )
- break;
- }
- }
- else
- break;
- }
- else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) {
- /* PCXR board will break out of the loop here */
- if ( image_list[x].subtype == T_PCXR ) {
- break;
- }
- }
- }
-
- if ( x >= nimages) {
- /*
- ** no valid images exist
- */
- if(nodldprint) {
- fprintf(stderr,
- "%s: cannot find correct BIOS image\n",
- pgm);
- nodldprint = 0;
- }
- dlio.image.fi.type = -1;
- if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1) {
- if (errorprint) {
- fprintf(stderr,
- "%s: warning - download ioctl failed\n",
- pgm);
- errorprint = 0;
- }
- sleep(2);
- }
- break;
- }
- squirt(dlio.req_type, dlio.bdid, &image_list[x]);
- break ;
-
- case DLREQ_FEP:
- /*
- ** find the fep image for this type
- */
- for ( x = 0; x < nimages; x++ ) {
- if(image_list[x].type != IFEP)
- continue;
- if( (dlio.image.fi.type & FAMILY) ==
- image_list[x].family ) {
- if ( image_list[x].family == T_CX ) {
- /* C/X PCI board */
- if ((dlio.image.fi.type & BUSTYPE)
- == T_PCIBUS ) {
- if ( image_list[x].subtype
- == T_PCIBUS )
- break;
- }
- else {
- /* Regular CX */
- break;
- }
- }
- else if ( image_list[x].family == T_EPC ) {
- /* If subtype of image is T_PCIBUS, it is */
- /* a PCI EPC image, so the board must */
- /* have bus type T_PCIBUS to match */
- if ((dlio.image.fi.type & BUSTYPE)
- == T_PCIBUS ) {
- if ( image_list[x].subtype
- == T_PCIBUS )
- break;
- }
- else {
- /* NON PCI EPC doesn't use PCI image */
- if ( image_list[x].subtype
- != T_PCIBUS )
- break;
- }
- }
- else
- break;
- }
- else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) {
- /* PCXR board will break out of the loop here */
- if ( image_list[x].subtype == T_PCXR ) {
- break;
- }
- }
- }
-
- if ( x >= nimages) {
- /*
- ** no valid images exist
- */
- if(nodldprint) {
- fprintf(stderr,
- "%s: cannot find correct FEP image\n",
- pgm);
- nodldprint = 0;
- }
- dlio.image.fi.type=-1;
- if( ioctl(fd,DIGI_DLREQ_SET,&dlio) == -1 ) {
- if(errorprint) {
- fprintf(stderr,
- "%s: warning - download ioctl failed\n",
- pgm);
- errorprint=0;
- }
- sleep(2);
- }
- break;
- }
- squirt(dlio.req_type, dlio.bdid, &image_list[x]);
- break;
-
- case DLREQ_DEVCREATE:
- {
- char string[1024];
-#if 0
- sprintf(string, "%s /proc/dgap/%d/mknod", DEFSHELL, dlio.bdid);
-#endif
- sprintf(string, "%s /usr/sbin/dgap_updatedevs %d", DEFSHELL, dlio.bdid);
- system(string);
-
- if (debugflag)
- printf("Created Devices.\n");
- if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
- if(errorprint) {
- fprintf(stderr, "%s: warning - DEVCREATE ioctl failed\n",pgm);
- errorprint = 0;
- }
- sleep(2);
- }
- if (debugflag)
- printf("After ioctl set - Created Device.\n");
- }
-
- break;
-
- case DLREQ_CONFIG:
- for ( x = 0; x < nimages; x++ ) {
- if(image_list[x].type != ICONFIG)
- continue;
- else
- break;
- }
-
- if ( x >= nimages) {
- /*
- ** no valid images exist
- */
- if(nodldprint) {
- fprintf(stderr,
- "%s: cannot find correct CONFIG image\n",
- pgm);
- nodldprint = 0;
- }
- dlio.image.fi.type=-1;
- if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
- if(errorprint) {
- fprintf(stderr,
- "%s: warning - download ioctl failed\n",
- pgm);
- errorprint=0;
- }
- sleep(2);
- }
- break;
- }
-
- squirt(dlio.req_type, dlio.bdid, &image_list[x]);
- break;
-
- case DLREQ_CONC:
- /*
- ** find the image needed for this download
- */
- if ( dp->dl_seq == 0 ) {
- /*
- ** find image for hardware rev range
- */
- for ( x = 0; x < nimages; x++ ) {
- ii=&image_list[x];
-
- if(image_list[x].type != ICONC)
- continue;
-
- consider_file_rescan(ii) ;
-
- ip = (struct downld_t *) image_list[x].image;
- if (ip == NULL) continue;
-
- /*
- * When I removed Clusterport, I kept only the
- * code that I was SURE wasn't ClusterPort.
- * We may not need the next four lines of code.
- */
-
- if ((dp->dl_type != 'P' ) &&
- (ip->dl_lrev <= dp->dl_lrev ) &&
- ( dp->dl_lrev <= ip->dl_hrev))
- break;
- }
-
- if ( x >= nimages ) {
- /*
- ** No valid images exist
- */
- if(nodldprint) {
- fprintf(stderr,
- "%s: cannot find correct download image %d\n",
- pgm, dp->dl_lrev);
- nodldprint=0;
- }
- continue;
- }
-
- } else {
- /*
- ** find image version required
- */
- if ((ii = find_conc_image()) == NULL ) {
- /*
- ** No valid images exist
- */
- fprintf(stderr,
- "%s: can't find rest of download image??\n",
- pgm);
- continue;
- }
- }
-
- /*
- ** download block of image
- */
-
- offset = 1024 * dp->dl_seq;
-
- /*
- ** test if block requested within image
- */
- if ( offset < ii->len ) {
-
- /*
- ** if it is, determine block size, set segment,
- ** set size, set pointers, and copy block
- */
- if (( bsize = ii->len - offset ) > 1024 )
- bsize = 1024;
-
- /*
- ** copy image version info to download area
- */
- dp->dl_srev = ip->dl_srev;
- dp->dl_lrev = ip->dl_lrev;
- dp->dl_hrev = ip->dl_hrev;
-
- dp->dl_seg = (64 * dp->dl_seq) + ip->dl_seg;
- dp->dl_size = bsize;
-
- down = (char *)&dp->dl_data[0];
- image = (char *)((char *)ip + offset);
-
- memcpy(down, image, bsize);
- }
- else {
- /*
- ** Image has been downloaded, set segment and
- ** size to indicate no more blocks
- */
- dp->dl_seg = ip->dl_seg;
- dp->dl_size = 0;
-
- /* Now, we can release the concentrator */
- /* image from memory if we're running */
- /* from filesystem images */
-
- if (ii->pathname)
- if (ii->image) {
- free(ii->image);
- ii->image = NULL;
- }
- }
-
- if (debugflag)
- printf(
- "sending conc dl section %d to %s from %s\n",
- dp->dl_seq, ii->name,
- ii->pathname ? ii->pathname : "Internal Image");
-
- if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
- if (errorprint) {
- fprintf(stderr,
- "%s: warning - download ioctl failed\n",
- pgm);
- errorprint=0;
- }
- sleep(2);
- }
- break;
- } /* switch */
- }
- if (debugflag > 1) {
- printf("pausing: "); fflush(stdout);
- fflush(stdin);
- while(getchar() != '\n');
- printf("continuing\n");
- }
- }
-}
-
-/*
-** myperror()
-**
-** Same as normal perror(), but places the program name at the beginning
-** of the message.
-*/
-void myperror(char *s)
-{
- fprintf(stderr,"%s: %s: %s.\n",pgm, s, strerror(errno));
-}
diff --git a/drivers/staging/dgnc/dgnc_cls.c b/drivers/staging/dgnc/dgnc_cls.c
index 708adbbcedbd..60d9b62c6f1f 100644
--- a/drivers/staging/dgnc/dgnc_cls.c
+++ b/drivers/staging/dgnc/dgnc_cls.c
@@ -827,9 +827,8 @@ static irqreturn_t cls_intr(int irq, void *voidbrd)
* Check to make sure its for us.
*/
if (brd->magic != DGNC_BOARD_MAGIC) {
- APR((
- "Received interrupt (%d) with a board pointer "
- "that wasn't ours!\n", irq));
+ APR(("Received interrupt (%d) with a board pointer that wasn't ours!\n",
+ irq));
return IRQ_NONE;
}
@@ -846,8 +845,7 @@ static irqreturn_t cls_intr(int irq, void *voidbrd)
/* If 0, no interrupts pending */
if (!poll_reg) {
DPR_INTR((
- "Kernel interrupted to me, but no pending "
- "interrupts...\n"));
+ "Kernel interrupted to me, but no pending interrupts...\n"));
DGNC_UNLOCK(brd->bd_intr_lock, lock_flags);
return IRQ_NONE;
}
@@ -1388,8 +1386,7 @@ static void cls_send_break(struct channel_t *ch, int msecs)
writeb((temp | UART_LCR_SBC), &ch->ch_cls_uart->lcr);
ch->ch_flags |= (CH_BREAK_SENDING);
DPR_IOCTL((
- "Port %d. Starting UART_LCR_SBC! start: %lx "
- "should end: %lx\n",
+ "Port %d. Starting UART_LCR_SBC! start: %lx should end: %lx\n",
ch->ch_portnum, jiffies, ch->ch_stop_sending_break));
}
}
diff --git a/drivers/staging/dgnc/dgnc_driver.c b/drivers/staging/dgnc/dgnc_driver.c
index c204266cb69f..b1a39b25b419 100644
--- a/drivers/staging/dgnc/dgnc_driver.c
+++ b/drivers/staging/dgnc/dgnc_driver.c
@@ -88,7 +88,7 @@ module_exit(dgnc_cleanup_module);
/*
* File operations permitted on Control/Management major.
*/
-static struct file_operations dgnc_BoardFops =
+static const struct file_operations dgnc_BoardFops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = dgnc_mgmt_ioctl,
@@ -236,7 +236,7 @@ int dgnc_init_module(void)
if (dgnc_NumBoards)
pci_unregister_driver(&dgnc_driver);
else
- printk("WARNING: dgnc driver load failed. No Digi Neo or Classic boards found.\n");
+ pr_warn("WARNING: dgnc driver load failed. No Digi Neo or Classic boards found.\n");
dgnc_cleanup_module();
}
diff --git a/drivers/staging/dgnc/dgnc_mgmt.c b/drivers/staging/dgnc/dgnc_mgmt.c
index 1c5ab3d007b0..c5b425bf6692 100644
--- a/drivers/staging/dgnc/dgnc_mgmt.c
+++ b/drivers/staging/dgnc/dgnc_mgmt.c
@@ -42,7 +42,7 @@
#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
#include <linux/serial_reg.h>
#include <linux/termios.h>
-#include <asm/uaccess.h> /* For copy_from_user/copy_to_user */
+#include <linux/uaccess.h> /* For copy_from_user/copy_to_user */
#include "dgnc_driver.h"
#include "dgnc_pci.h"
@@ -77,8 +77,7 @@ int dgnc_mgmt_open(struct inode *inode, struct file *file)
return -EBUSY;
}
dgnc_mgmt_in_use[minor]++;
- }
- else {
+ } else {
DGNC_UNLOCK(dgnc_global_lock, lock_flags);
return -ENXIO;
}
@@ -107,9 +106,8 @@ int dgnc_mgmt_close(struct inode *inode, struct file *file)
/* mgmt device */
if (minor < MAXMGMTDEVICES) {
- if (dgnc_mgmt_in_use[minor]) {
+ if (dgnc_mgmt_in_use[minor])
dgnc_mgmt_in_use[minor] = 0;
- }
}
DGNC_UNLOCK(dgnc_global_lock, lock_flags);
@@ -153,7 +151,7 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
DPR_MGMT(("DIGI_GETDD returning numboards: %d version: %s\n",
ddi.dinfo_nboards, ddi.dinfo_version));
- if (copy_to_user(uarg, &ddi, sizeof (ddi)))
+ if (copy_to_user(uarg, &ddi, sizeof(ddi)))
return -EFAULT;
break;
@@ -165,13 +163,13 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct digi_info di;
- if (copy_from_user(&brd, uarg, sizeof(int))) {
+ if (copy_from_user(&brd, uarg, sizeof(int)))
return -EFAULT;
- }
DPR_MGMT(("DIGI_GETBD asking about board: %d\n", brd));
- if ((brd < 0) || (brd > dgnc_NumBoards) || (dgnc_NumBoards == 0))
+ if ((brd < 0) || (brd > dgnc_NumBoards) ||
+ (dgnc_NumBoards == 0))
return -ENODEV;
memset(&di, 0, sizeof(di));
@@ -195,7 +193,7 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
DPR_MGMT(("DIGI_GETBD returning type: %x state: %x ports: %x size: %x\n",
di.info_bdtype, di.info_bdstate, di.info_nports, di.info_physsize));
- if (copy_to_user(uarg, &di, sizeof (di)))
+ if (copy_to_user(uarg, &di, sizeof(di)))
return -EFAULT;
break;
@@ -209,9 +207,8 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
uint board = 0;
uint channel = 0;
- if (copy_from_user(&ni, uarg, sizeof(ni))) {
+ if (copy_from_user(&ni, uarg, sizeof(ni)))
return -EFAULT;
- }
DPR_MGMT(("DIGI_GETBD asking about board: %d channel: %d\n",
ni.board, ni.channel));
@@ -268,12 +265,14 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ni.cflag = ch->ch_c_cflag;
ni.lflag = ch->ch_c_lflag;
- if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS)
+ if (ch->ch_digi.digi_flags & CTSPACE ||
+ ch->ch_c_cflag & CRTSCTS)
ni.hflow = 1;
else
ni.hflow = 0;
- if ((ch->ch_flags & CH_STOPI) || (ch->ch_flags & CH_FORCED_STOPI))
+ if ((ch->ch_flags & CH_STOPI) ||
+ (ch->ch_flags & CH_FORCED_STOPI))
ni.recv_stopped = 1;
else
ni.recv_stopped = 0;
diff --git a/drivers/staging/dgnc/dgnc_neo.c b/drivers/staging/dgnc/dgnc_neo.c
index dc5a138d8d4a..cf22c7b725f9 100644
--- a/drivers/staging/dgnc/dgnc_neo.c
+++ b/drivers/staging/dgnc/dgnc_neo.c
@@ -1201,7 +1201,8 @@ static void neo_copy_data_from_uart_to_queue(struct channel_t *ch)
ch->ch_cached_lsr = 0;
/* Store how much space we have left in the queue */
- if ((qleft = tail - head - 1) < 0)
+ qleft = tail - head - 1;
+ if (qleft < 0)
qleft += RQUEUEMASK + 1;
/*
diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c
index a6c6aba82d72..f0b17c36edd8 100644
--- a/drivers/staging/dgnc/dgnc_tty.c
+++ b/drivers/staging/dgnc/dgnc_tty.c
@@ -964,8 +964,10 @@ static void dgnc_set_custom_speed(struct channel_t *ch, uint newrate)
int deltahigh;
int deltalow;
- if (newrate < 0)
- newrate = 0;
+ if (newrate <= 0) {
+ ch->ch_custom_speed = 0;
+ return;
+ }
/*
* Since the divisor is stored in a 16-bit integer, we make sure
@@ -978,7 +980,7 @@ static void dgnc_set_custom_speed(struct channel_t *ch, uint newrate)
if (newrate && newrate > ch->ch_bd->bd_dividend)
newrate = ch->ch_bd->bd_dividend;
- while (newrate > 0) {
+ if (newrate > 0) {
testdiv = ch->ch_bd->bd_dividend / newrate;
/*
@@ -995,28 +997,23 @@ static void dgnc_set_custom_speed(struct channel_t *ch, uint newrate)
* If the rate for the requested divisor is correct, just
* use it and be done.
*/
- if (testrate_high == newrate )
- break;
-
- /*
- * Otherwise, pick the rate that is closer (i.e. whichever rate
- * has a smaller delta).
- */
- deltahigh = testrate_high - newrate;
- deltalow = newrate - testrate_low;
+ if (testrate_high != newrate) {
+ /*
+ * Otherwise, pick the rate that is closer (i.e. whichever rate
+ * has a smaller delta).
+ */
+ deltahigh = testrate_high - newrate;
+ deltalow = newrate - testrate_low;
- if (deltahigh < deltalow) {
- newrate = testrate_high;
- } else {
- newrate = testrate_low;
+ if (deltahigh < deltalow) {
+ newrate = testrate_high;
+ } else {
+ newrate = testrate_low;
+ }
}
-
- break;
}
ch->ch_custom_speed = newrate;
-
- return;
}
@@ -1025,7 +1022,8 @@ void dgnc_check_queue_flow_control(struct channel_t *ch)
int qleft = 0;
/* Store how much space we have left in the queue */
- if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0)
+ qleft = ch->ch_r_tail - ch->ch_r_head - 1;
+ if (qleft < 0)
qleft += RQUEUEMASK + 1;
/*
@@ -1119,7 +1117,8 @@ void dgnc_wakeup_writes(struct channel_t *ch)
/*
* If channel now has space, wake up anyone waiting on the condition.
*/
- if ((qlen = ch->ch_w_head - ch->ch_w_tail) < 0)
+ qlen = ch->ch_w_head - ch->ch_w_tail;
+ if (qlen < 0)
qlen += WQUEUESIZE;
if (qlen >= (WQUEUESIZE - 256)) {
@@ -1917,7 +1916,8 @@ static int dgnc_tty_write_room(struct tty_struct *tty)
head = (ch->ch_w_head) & tmask;
tail = (ch->ch_w_tail) & tmask;
- if ((ret = tail - head - 1) < 0)
+ ret = tail - head - 1;
+ if (ret < 0)
ret += WQUEUESIZE;
/* Limit printer to maxcps */
@@ -2017,7 +2017,8 @@ static int dgnc_tty_write(struct tty_struct *tty,
head = (ch->ch_w_head) & tmask;
tail = (ch->ch_w_tail) & tmask;
- if ((bufcount = tail - head - 1) < 0)
+ bufcount = tail - head - 1;
+ if (bufcount < 0)
bufcount += WQUEUESIZE;
DPR_WRITE(("%d: bufcount: %x count: %x tail: %x head: %x tmask: %x\n",
@@ -3316,10 +3317,10 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
case DIGI_SETCUSTOMBAUD:
{
- uint new_rate;
+ int new_rate;
/* Let go of locks when accessing user space, could sleep */
DGNC_UNLOCK(ch->ch_lock, lock_flags);
- rc = get_user(new_rate, (unsigned int __user *) arg);
+ rc = get_user(new_rate, (int __user *) arg);
if (rc)
return rc;
DGNC_LOCK(ch->ch_lock, lock_flags);
diff --git a/drivers/staging/dgrp/dgrp_sysfs.c b/drivers/staging/dgrp/dgrp_sysfs.c
index 9a18a2c9e73b..2f9345ff0abb 100644
--- a/drivers/staging/dgrp/dgrp_sysfs.c
+++ b/drivers/staging/dgrp/dgrp_sysfs.c
@@ -65,7 +65,9 @@ static ssize_t dgrp_class_pollrate_store(struct device *c,
struct device_attribute *attr,
const char *buf, size_t count)
{
- sscanf(buf, "0x%x\n", &dgrp_poll_tick);
+ if (sscanf(buf, "0x%x\n", &dgrp_poll_tick) != 1)
+ return -EINVAL;
+
return count;
}
static DEVICE_ATTR(pollrate, 0600, dgrp_class_pollrate_show,
diff --git a/drivers/staging/dgrp/dgrp_tty.c b/drivers/staging/dgrp/dgrp_tty.c
index 7a9694c1d9c4..30d26029b21e 100644
--- a/drivers/staging/dgrp/dgrp_tty.c
+++ b/drivers/staging/dgrp/dgrp_tty.c
@@ -1319,7 +1319,8 @@ static int dgrp_calculate_txprint_bounds(struct ch_struct *ch, int space,
if (ch->ch_tun.un_open_count != 0 &&
ch->ch_tun.un_tty->ops->chars_in_buffer &&
- ((ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) != 0)) {
+ ((ch->ch_tun.un_tty->ops->chars_in_buffer)
+ (ch->ch_tun.un_tty) != 0)) {
*un_flag = UN_PWAIT;
return 0;
}
@@ -1501,7 +1502,8 @@ static int dgrp_tty_write(struct tty_struct *tty,
*/
if (ch->ch_tun.un_open_count != 0 &&
- ((ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) != 0)) {
+ ((ch->ch_tun.un_tty->ops->chars_in_buffer)
+ (ch->ch_tun.un_tty) != 0)) {
un->un_flag |= UN_PWAIT;
count = 0;
goto out;
@@ -1666,7 +1668,8 @@ static int dgrp_tty_write(struct tty_struct *tty,
if (n >= t) {
memcpy(ch->ch_tbuf + ch->ch_tin, buf, t);
- if (nd->nd_dpa_debug && nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(un->un_tty))))
+ if (nd->nd_dpa_debug && nd->nd_dpa_port ==
+ PORT_NUM(MINOR(tty_devnum(un->un_tty))))
dgrp_dpa_data(nd, 0, (char *) buf, t);
buf += t;
n -= t;
@@ -1675,7 +1678,8 @@ static int dgrp_tty_write(struct tty_struct *tty,
}
memcpy(ch->ch_tbuf + ch->ch_tin, buf, n);
- if (nd->nd_dpa_debug && nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(un->un_tty))))
+ if (nd->nd_dpa_debug && nd->nd_dpa_port ==
+ PORT_NUM(MINOR(tty_devnum(un->un_tty))))
dgrp_dpa_data(nd, 0, (char *) buf, n);
buf += n;
ch->ch_tin += n;
@@ -2656,7 +2660,8 @@ static int dgrp_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
ch->ch_send |= RR_RX_FLUSH;
(ch->ch_nd)->nd_tx_work = 1;
(ch->ch_nd)->nd_tx_ready = 1;
- wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq);
+ wake_up_interruptible(
+ &(ch->ch_nd)->nd_tx_waitq);
}
if (arg == TCIFLUSH)
break;
@@ -2682,7 +2687,8 @@ static int dgrp_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
Linux HPUX Function
TCSETA TCSETA - set the termios
TCSETAF TCSETAF - wait for drain first, then set termios
- TCSETAW TCSETAW - wait for drain, flush the input queue, then set termios
+ TCSETAW TCSETAW - wait for drain,
+ flush the input queue, then set termios
- looking at the tty_ioctl code, these command all call our
tty_set_termios at the driver's end, when a TCSETA* is sent,
it is expecting the tty to have a termio structure,
@@ -2798,6 +2804,7 @@ static int dgrp_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
}
/* pretend we didn't recognize this */
+ /* fall-through */
case DIGI_SETA:
return dgrp_tty_digiseta(tty, (struct digi_struct *) arg);
@@ -3207,7 +3214,8 @@ dgrp_tty_init(struct nd_struct *nd)
int max_majors = 1U << (32 - MINORBITS);
for (i = 256; i < max_majors; i++) {
nd->nd_serial_ttdriver->major = i;
- rc = tty_register_driver(nd->nd_serial_ttdriver);
+ rc = tty_register_driver
+ (nd->nd_serial_ttdriver);
if (rc >= 0)
break;
}
diff --git a/drivers/staging/echo/TODO b/drivers/staging/echo/TODO
deleted file mode 100644
index 72a311a5a9cc..000000000000
--- a/drivers/staging/echo/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
-TODO:
- - send to lkml for review
-
-Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc: Steve
-Underwood <steveu@coppice.org> and David Rowe <david@rowetel.com>
diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c
index e516bb69f3b4..d329cf314360 100644
--- a/drivers/staging/et131x/et131x.c
+++ b/drivers/staging/et131x/et131x.c
@@ -485,8 +485,6 @@ struct et131x_adapter {
u8 eeprom_data[2];
/* Spinlocks */
- spinlock_t lock;
-
spinlock_t tcb_send_qlock;
spinlock_t tcb_ready_qlock;
spinlock_t send_hw_lock;
@@ -1388,6 +1386,7 @@ static int et131x_phy_mii_read(struct et131x_adapter *adapter, u8 addr,
mii_indicator);
status = -EIO;
+ goto out;
}
/* If we hit here we were able to read the register and we need to
@@ -1395,6 +1394,7 @@ static int et131x_phy_mii_read(struct et131x_adapter *adapter, u8 addr,
*/
*value = readl(&mac->mii_mgmt_stat) & ET_MAC_MIIMGMT_STAT_PHYCRTL_MASK;
+out:
/* Stop the read operation */
writel(0, &mac->mii_mgmt_cmd);
@@ -2124,7 +2124,11 @@ static int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter)
/* Alloc memory for the lookup table */
rx_ring->fbr[0] = kmalloc(sizeof(struct fbr_lookup), GFP_KERNEL);
+ if (rx_ring->fbr[0] == NULL)
+ return -ENOMEM;
rx_ring->fbr[1] = kmalloc(sizeof(struct fbr_lookup), GFP_KERNEL);
+ if (rx_ring->fbr[1] == NULL)
+ return -ENOMEM;
/* The first thing we will do is configure the sizes of the buffer
* rings. These will change based on jumbo packet support. Larger
@@ -2289,7 +2293,7 @@ static void et131x_rx_dma_memory_free(struct et131x_adapter *adapter)
for (id = 0; id < NUM_FBRS; id++) {
fbr = rx_ring->fbr[id];
- if (!fbr->ring_virtaddr)
+ if (!fbr || !fbr->ring_virtaddr)
continue;
/* First the packet memory */
@@ -3523,7 +3527,7 @@ static int et131x_pci_init(struct et131x_adapter *adapter,
goto err_out;
}
}
- memcpy(adapter->addr, adapter->rom_addr, ETH_ALEN);
+ ether_addr_copy(adapter->addr, adapter->rom_addr);
out:
return rc;
err_out:
@@ -3591,6 +3595,7 @@ static int et131x_adapter_memory_alloc(struct et131x_adapter *adapter)
if (status) {
dev_err(&adapter->pdev->dev,
"et131x_tx_dma_memory_alloc FAILED\n");
+ et131x_tx_dma_memory_free(adapter);
return status;
}
/* Receive buffer memory allocation */
@@ -3598,7 +3603,7 @@ static int et131x_adapter_memory_alloc(struct et131x_adapter *adapter)
if (status) {
dev_err(&adapter->pdev->dev,
"et131x_rx_dma_memory_alloc FAILED\n");
- et131x_tx_dma_memory_free(adapter);
+ et131x_adapter_memory_free(adapter);
return status;
}
@@ -3760,7 +3765,6 @@ static struct et131x_adapter *et131x_adapter_init(struct net_device *netdev,
adapter->netdev = netdev;
/* Initialize spinlocks here */
- spin_lock_init(&adapter->lock);
spin_lock_init(&adapter->tcb_send_qlock);
spin_lock_init(&adapter->tcb_ready_qlock);
spin_lock_init(&adapter->send_hw_lock);
@@ -3770,7 +3774,7 @@ static struct et131x_adapter *et131x_adapter_init(struct net_device *netdev,
adapter->registry_jumbo_packet = 1514; /* 1514-9216 */
/* Set the MAC address to a default */
- memcpy(adapter->addr, default_mac, ETH_ALEN);
+ ether_addr_copy(adapter->addr, default_mac);
return adapter;
}
@@ -4292,12 +4296,9 @@ static void et131x_multicast(struct net_device *netdev)
{
struct et131x_adapter *adapter = netdev_priv(netdev);
int packet_filter;
- unsigned long flags;
struct netdev_hw_addr *ha;
int i;
- spin_lock_irqsave(&adapter->lock, flags);
-
/* Before we modify the platform-independent filter flags, store them
* locally. This allows us to determine if anything's changed and if
* we even need to bother the hardware
@@ -4349,8 +4350,6 @@ static void et131x_multicast(struct net_device *netdev)
*/
if (packet_filter != adapter->packet_filter)
et131x_set_packet_filter(adapter);
-
- spin_unlock_irqrestore(&adapter->lock, flags);
}
/* et131x_tx - The handler to tx a packet on the device */
diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c
index edd5cef300d0..226b23163109 100644
--- a/drivers/staging/frontier/alphatrack.c
+++ b/drivers/staging/frontier/alphatrack.c
@@ -208,7 +208,9 @@ static void usb_alphatrack_delete(struct usb_alphatrack *dev)
kfree(dev->ring_buffer);
kfree(dev->interrupt_in_buffer);
kfree(dev->interrupt_out_buffer);
- kfree(dev); /* fixme oldi_buffer */
+ kfree(dev->oldi_buffer);
+ kfree(dev->write_buffer);
+ kfree(dev);
}
/** usb_alphatrack_interrupt_in_callback */
@@ -233,8 +235,8 @@ static void usb_alphatrack_interrupt_in_callback(struct urb *urb)
if (urb->actual_length != INPUT_CMD_SIZE) {
dev_warn(&dev->intf->dev,
- "Urb length was %d bytes!!"
- "Do something intelligent\n", urb->actual_length);
+ "Urb length was %d bytes!! Do something intelligent\n",
+ urb->actual_length);
} else {
alphatrack_ocmd_info(&dev->intf->dev,
&(*dev->ring_buffer)[dev->ring_tail].cmd,
@@ -688,8 +690,7 @@ static int usb_alphatrack_probe(struct usb_interface *intf,
}
if (dev->interrupt_out_endpoint == NULL)
dev_warn(&intf->dev,
- "Interrupt out endpoint not found"
- "(using control endpoint instead)\n");
+ "Interrupt out endpoint not found (using control endpoint instead)\n");
dev->interrupt_in_endpoint_size =
le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c
index 0e499ce5f0d7..0571988c58fc 100644
--- a/drivers/staging/frontier/tranzport.c
+++ b/drivers/staging/frontier/tranzport.c
@@ -257,8 +257,7 @@ static void usb_tranzport_interrupt_in_callback(struct urb *urb)
if (urb->actual_length != 8) {
dev_warn(&dev->intf->dev,
- "Urb length was %d bytes!!"
- "Do something intelligent\n",
+ "Urb length was %d bytes!! Do something intelligent\n",
urb->actual_length);
} else {
dbg_info(&dev->intf->dev,
@@ -542,8 +541,7 @@ static ssize_t usb_tranzport_read(struct file *file, char __user *buffer,
}
dbg_info(&dev->intf->dev,
- "%s: copying to userspace: "
- "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ "%s: copying to userspace: %02x%02x%02x%02x%02x%02x%02x%02x\n",
__func__,
(*dev->ring_buffer)[dev->ring_tail].cmd[0],
(*dev->ring_buffer)[dev->ring_tail].cmd[1],
@@ -570,8 +568,7 @@ static ssize_t usb_tranzport_read(struct file *file, char __user *buffer,
* and we are the same sign, we can compress +- 7F
*/
dbg_info(&dev->intf->dev,
- "%s: trying to compress: "
- "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ "%s: trying to compress: %02x%02x%02x%02x%02x%02x%02x%02x\n",
__func__,
(*dev->ring_buffer)[dev->ring_tail].cmd[0],
(*dev->ring_buffer)[dev->ring_tail].cmd[1],
@@ -830,8 +827,7 @@ static int usb_tranzport_probe(struct usb_interface *intf,
}
if (dev->interrupt_out_endpoint == NULL)
dev_warn(&intf->dev,
- "Interrupt out endpoint not found"
- "(using control endpoint instead)\n");
+ "Interrupt out endpoint not found (using control endpoint instead)\n");
dev->interrupt_in_endpoint_size =
le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
index a433e33049b5..b6a77088cfe4 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
@@ -1145,7 +1145,7 @@ static int ft1000_proc_drvmsg(struct ft1000_usb *dev, u16 size)
char *cmdbuffer = kmalloc(1600, GFP_KERNEL);
if (!cmdbuffer)
- return -1;
+ return -ENOMEM;
status = ft1000_read_dpram32(dev, 0x200, cmdbuffer, size);
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h b/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h
index 24b8d77a132c..419e534874f9 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h
@@ -30,7 +30,7 @@
typedef struct _IOCTL_GET_VER {
unsigned long drv_ver;
-} __attribute__ ((packed)) IOCTL_GET_VER, *PIOCTL_GET_VER;
+} __packed IOCTL_GET_VER, *PIOCTL_GET_VER;
/* Data structure for Dsp statistics */
typedef struct _IOCTL_GET_DSP_STAT {
@@ -67,19 +67,19 @@ typedef struct _IOCTL_GET_DSP_STAT {
unsigned long ConTm; /* Current session connection time in seconds */
unsigned char CalVer[CALVERSZ]; /* Proprietary Calibration Version */
unsigned char CalDate[CALDATESZ]; /* Proprietary Calibration Date */
-} __attribute__ ((packed)) IOCTL_GET_DSP_STAT, *PIOCTL_GET_DSP_STAT;
+} __packed IOCTL_GET_DSP_STAT, *PIOCTL_GET_DSP_STAT;
/* Data structure for Dual Ported RAM messaging between Host and Dsp */
typedef struct _IOCTL_DPRAM_BLK {
unsigned short total_len;
struct pseudo_hdr pseudohdr;
unsigned char buffer[1780];
-} __attribute__ ((packed)) IOCTL_DPRAM_BLK, *PIOCTL_DPRAM_BLK;
+} __packed IOCTL_DPRAM_BLK, *PIOCTL_DPRAM_BLK;
typedef struct _IOCTL_DPRAM_COMMAND {
unsigned short extra;
IOCTL_DPRAM_BLK dpram_blk;
-} __attribute__ ((packed)) IOCTL_DPRAM_COMMAND, *PIOCTL_DPRAM_COMMAND;
+} __packed IOCTL_DPRAM_COMMAND, *PIOCTL_DPRAM_COMMAND;
/*
* Custom IOCTL command codes
diff --git a/drivers/staging/ft1000/ft1000.h b/drivers/staging/ft1000/ft1000.h
index 175abfa7682e..ccb821a1f370 100644
--- a/drivers/staging/ft1000/ft1000.h
+++ b/drivers/staging/ft1000/ft1000.h
@@ -21,34 +21,64 @@
#define FT1000_REG_SUP_CTRL 0x0020 /* HCTR - Host Control Register */
#define FT1000_REG_SUP_STAT 0x0022 /* HSTAT - Host Status Register */
#define FT1000_REG_RESET 0x0024 /* HCTR - Host Control Register */
-#define FT1000_REG_SUP_ISR 0x0026 /* HISR - Host Interrupt Status Register */
+#define FT1000_REG_SUP_ISR 0x0026 /* HISR - Host Interrupt Status
+ * Register
+ */
#define FT1000_REG_SUP_IMASK 0x0028 /* HIMASK - Host Interrupt Mask */
#define FT1000_REG_DOORBELL 0x002a /* DBELL - Door Bell Register */
-#define FT1000_REG_ASIC_ID 0x002e /* ASICID - ASIC Identification Number */
+#define FT1000_REG_ASIC_ID 0x002e /* ASICID - ASIC Identification
+ * Number
+ */
/* MEMORY MAP FOR ELECTRABUZZ ASIC */
#define FT1000_REG_UFIFO_STAT 0x0000 /* UFSR - Uplink FIFO status register */
-#define FT1000_REG_UFIFO_BEG 0x0002 /* UFBR - Uplink FIFO beginning register */
+#define FT1000_REG_UFIFO_BEG 0x0002 /* UFBR - Uplink FIFO beginning
+ * register
+ */
#define FT1000_REG_UFIFO_MID 0x0004 /* UFMR - Uplink FIFO middle register */
#define FT1000_REG_UFIFO_END 0x0006 /* UFER - Uplink FIFO end register */
-#define FT1000_REG_DFIFO_STAT 0x0008 /* DFSR - Downlink FIFO status register */
+#define FT1000_REG_DFIFO_STAT 0x0008 /* DFSR - Downlink FIFO status
+ * register
+ */
#define FT1000_REG_DFIFO 0x000A /* DFR - Downlink FIFO Register */
-#define FT1000_REG_DPRAM_DATA 0x000C /* DPRAM - Dual Port Indirect Data Register */
+#define FT1000_REG_DPRAM_DATA 0x000C /* DPRAM - Dual Port Indirect
+ * Data Register
+ */
#define FT1000_REG_WATERMARK 0x0010 /* WMARK - Watermark Register */
/* MEMORY MAP FOR MAGNEMITE */
-#define FT1000_REG_MAG_UFDR 0x0000 /* UFDR - Uplink FIFO Data Register (32-bits) */
-#define FT1000_REG_MAG_UFDRL 0x0000 /* UFDRL - Uplink FIFO Data Register low-word (16-bits) */
-#define FT1000_REG_MAG_UFDRH 0x0002 /* UFDRH - Uplink FIFO Data Register high-word (16-bits) */
+#define FT1000_REG_MAG_UFDR 0x0000 /* UFDR - Uplink FIFO Data
+ * Register (32-bits)
+ */
+#define FT1000_REG_MAG_UFDRL 0x0000 /* UFDRL - Uplink FIFO Data
+ * Register low-word (16-bits)
+ */
+#define FT1000_REG_MAG_UFDRH 0x0002 /* UFDRH - Uplink FIFO Data Register
+ * high-word (16-bits)
+ */
#define FT1000_REG_MAG_UFER 0x0004 /* UFER - Uplink FIFO End Register */
#define FT1000_REG_MAG_UFSR 0x0006 /* UFSR - Uplink FIFO Status Register */
-#define FT1000_REG_MAG_DFR 0x0008 /* DFR - Downlink FIFO Register (32-bits) */
-#define FT1000_REG_MAG_DFRL 0x0008 /* DFRL - Downlink FIFO Register low-word (16-bits) */
-#define FT1000_REG_MAG_DFRH 0x000a /* DFRH - Downlink FIFO Register high-word (16-bits) */
-#define FT1000_REG_MAG_DFSR 0x000c /* DFSR - Downlink FIFO Status Register */
-#define FT1000_REG_MAG_DPDATA 0x0010 /* DPDATA - Dual Port RAM Indirect Data Register (32-bits) */
-#define FT1000_REG_MAG_DPDATAL 0x0010 /* DPDATAL - Dual Port RAM Indirect Data Register low-word (16-bits) */
-#define FT1000_REG_MAG_DPDATAH 0x0012 /* DPDATAH - Dual Port RAM Indirect Data Register high-word (16-bits) */
+#define FT1000_REG_MAG_DFR 0x0008 /* DFR - Downlink FIFO Register
+ * (32-bits)
+ */
+#define FT1000_REG_MAG_DFRL 0x0008 /* DFRL - Downlink FIFO Register
+ * low-word (16-bits)
+ */
+#define FT1000_REG_MAG_DFRH 0x000a /* DFRH - Downlink FIFO Register
+ * high-word (16-bits)
+ */
+#define FT1000_REG_MAG_DFSR 0x000c /* DFSR - Downlink FIFO Status
+ * Register
+ */
+#define FT1000_REG_MAG_DPDATA 0x0010 /* DPDATA - Dual Port RAM Indirect
+ * Data Register (32-bits)
+ */
+#define FT1000_REG_MAG_DPDATAL 0x0010 /* DPDATAL - Dual Port RAM Indirect
+ * Data Register low-word (16-bits)
+ */
+#define FT1000_REG_MAG_DPDATAH 0x0012 /* DPDATAH - Dual Port RAM Indirect Data
+ * Register high-word (16-bits)
+ */
#define FT1000_REG_MAG_WATERMARK 0x002c /* WMARK - Watermark Register */
#define FT1000_REG_MAG_VERSION 0x0030 /* LLC Version */
@@ -57,7 +87,9 @@
#define FT1000_DPRAM_RX_BASE 0x0800 /* PC Card to Host Messaging Area */
#define FT1000_FIFO_LEN 0x07FC /* total length for DSP FIFO tracking */
#define FT1000_HI_HO 0x07FE /* heartbeat with HI/HO */
-#define FT1000_DSP_STATUS 0x0FFE /* dsp status - non-zero is a request to reset dsp */
+#define FT1000_DSP_STATUS 0x0FFE /* dsp status - non-zero is a request
+ * to reset dsp
+ */
#define FT1000_DSP_LED 0x0FFA /* dsp led status for PAD device */
#define FT1000_DSP_CON_STATE 0x0FF8 /* DSP Connection Status Info */
#define FT1000_DPRAM_FEFE 0x0002 /* location for dsp ready indicator */
@@ -67,26 +99,48 @@
#define FT1000_DSP_TIMER3 0x1FF6 /* Timer Field from Basestation */
/* Reserved Dual Port RAM offsets for Magnemite */
-#define FT1000_DPRAM_MAG_TX_BASE 0x0000 /* Host to PC Card Messaging Area */
-#define FT1000_DPRAM_MAG_RX_BASE 0x0200 /* PC Card to Host Messaging Area */
+#define FT1000_DPRAM_MAG_TX_BASE 0x0000 /* Host to PC Card
+ * Messaging Area
+ */
+#define FT1000_DPRAM_MAG_RX_BASE 0x0200 /* PC Card to Host
+ * Messaging Area
+ */
-#define FT1000_MAG_FIFO_LEN 0x1FF /* total length for DSP FIFO tracking */
+#define FT1000_MAG_FIFO_LEN 0x1FF /* total length for DSP
+ * FIFO tracking
+ */
#define FT1000_MAG_FIFO_LEN_INDX 0x1 /* low-word index */
#define FT1000_MAG_HI_HO 0x1FF /* heartbeat with HI/HO */
#define FT1000_MAG_HI_HO_INDX 0x0 /* high-word index */
-#define FT1000_MAG_DSP_LED 0x3FE /* dsp led status for PAD device */
-#define FT1000_MAG_DSP_LED_INDX 0x0 /* dsp led status for PAD device */
+#define FT1000_MAG_DSP_LED 0x3FE /* dsp led status for
+ * PAD device
+ */
+#define FT1000_MAG_DSP_LED_INDX 0x0 /* dsp led status for
+ * PAD device
+ */
#define FT1000_MAG_DSP_CON_STATE 0x3FE /* DSP Connection Status Info */
#define FT1000_MAG_DSP_CON_STATE_INDX 0x1 /* DSP Connection Status Info */
-#define FT1000_MAG_DPRAM_FEFE 0x000 /* location for dsp ready indicator */
-#define FT1000_MAG_DPRAM_FEFE_INDX 0x0 /* location for dsp ready indicator */
-#define FT1000_MAG_DSP_TIMER0 0x3FC /* Timer Field from Basestation */
+#define FT1000_MAG_DPRAM_FEFE 0x000 /* location for dsp ready
+ * indicator
+ */
+#define FT1000_MAG_DPRAM_FEFE_INDX 0x0 /* location for dsp ready
+ * indicator
+ */
+#define FT1000_MAG_DSP_TIMER0 0x3FC /* Timer Field from
+ * Basestation
+ */
#define FT1000_MAG_DSP_TIMER0_INDX 0x1
-#define FT1000_MAG_DSP_TIMER1 0x3FC /* Timer Field from Basestation */
+#define FT1000_MAG_DSP_TIMER1 0x3FC /* Timer Field from
+ * Basestation
+ */
#define FT1000_MAG_DSP_TIMER1_INDX 0x0
-#define FT1000_MAG_DSP_TIMER2 0x3FD /* Timer Field from Basestation */
+#define FT1000_MAG_DSP_TIMER2 0x3FD /* Timer Field from
+ * Basestation
+ */
#define FT1000_MAG_DSP_TIMER2_INDX 0x1
-#define FT1000_MAG_DSP_TIMER3 0x3FD /* Timer Field from Basestation */
+#define FT1000_MAG_DSP_TIMER3 0x3FD /* Timer Field from
+ * Basestation
+ */
#define FT1000_MAG_DSP_TIMER3_INDX 0x0
#define FT1000_MAG_TOTAL_LEN 0x200
#define FT1000_MAG_TOTAL_LEN_INDX 0x1
@@ -99,24 +153,38 @@
#define HOST_INTF_BE 0x1 /* Host interface big endian mode */
/* FT1000 to Host Doorbell assignments */
-#define FT1000_DB_DPRAM_RX 0x0001 /* this value indicates that DSP has data for host in DPRAM */
+#define FT1000_DB_DPRAM_RX 0x0001 /* this value indicates that DSP
+ * has data for host in DPRAM
+ */
#define FT1000_DB_DNLD_RX 0x0002 /* Downloader handshake doorbell */
-#define FT1000_ASIC_RESET_REQ 0x0004 /* DSP requesting host to reset the ASIC */
-#define FT1000_DSP_ASIC_RESET 0x0008 /* DSP indicating host that it will reset the ASIC */
+#define FT1000_ASIC_RESET_REQ 0x0004 /* DSP requesting host to
+ * reset the ASIC
+ */
+#define FT1000_DSP_ASIC_RESET 0x0008 /* DSP indicating host that
+ * it will reset the ASIC
+ */
#define FT1000_DB_COND_RESET 0x0010 /* DSP request for a card reset. */
/* Host to FT1000 Doorbell assignments */
-#define FT1000_DB_DPRAM_TX 0x0100 /* this value indicates that host has data for DSP in DPRAM. */
+#define FT1000_DB_DPRAM_TX 0x0100 /* this value indicates that host
+ * has data for DSP in DPRAM.
+ */
#define FT1000_DB_DNLD_TX 0x0200 /* Downloader handshake doorbell */
#define FT1000_ASIC_RESET_DSP 0x0400 /* Responds to FT1000_ASIC_RESET_REQ */
-#define FT1000_DB_HB 0x1000 /* Indicates that supervisor has a heartbeat message for DSP. */
+#define FT1000_DB_HB 0x1000 /* Indicates that supervisor has a
+ * heartbeat message for DSP.
+ */
#define hi 0x6869 /* PC Card heartbeat values */
#define ho 0x686f /* PC Card heartbeat values */
/* Magnemite specific defines */
-#define hi_mag 0x6968 /* Byte swap hi to avoid additional system call */
-#define ho_mag 0x6f68 /* Byte swap ho to avoid additional system call */
+#define hi_mag 0x6968 /* Byte swap hi to avoid
+ * additional system call
+ */
+#define ho_mag 0x6f68 /* Byte swap ho to avoid
+ * additional system call
+ */
/* Bit field definitions for Host Interrupt Status Register */
/* Indicate the cause of an interrupt. */
@@ -133,13 +201,19 @@
#define ISR_MASK_RCV 0x0004 /* Downlink Packet available mask */
#define ISR_MASK_WATERMARK 0x0008 /* Watermark interrupt mask */
#define ISR_MASK_ALL 0xffff /* Mask all interrupts */
-/* Default interrupt mask (Enable Doorbell pending and Packet available interrupts) */
+/* Default interrupt mask
+ * (Enable Doorbell pending and Packet available interrupts)
+ */
#define ISR_DEFAULT_MASK 0x7ff9
/* Bit field definition for Host Control Register */
-#define DSP_RESET_BIT 0x0001 /* Bit field to control dsp reset state */
+#define DSP_RESET_BIT 0x0001 /* Bit field to control
+ * dsp reset state
+ */
/* (0 = out of reset 1 = reset) */
-#define ASIC_RESET_BIT 0x0002 /* Bit field to control ASIC reset state */
+#define ASIC_RESET_BIT 0x0002 /* Bit field to control
+ * ASIC reset state
+ */
/* (0 = out of reset 1 = reset) */
#define DSP_UNENCRYPTED 0x0004
#define DSP_ENCRYPTED 0x0008
@@ -195,7 +269,9 @@ struct pseudo_hdr {
unsigned char source; /* hardware source id */
/* Host = 0x10 */
/* Dsp = 0x20 */
- unsigned char destination; /* hardware destination id (refer to source) */
+ unsigned char destination; /* hardware destination id
+ * (refer to source)
+ */
unsigned char portdest; /* software destination port id */
/* Host = 0x00 */
/* Applicaton Broadcast = 0x10 */
@@ -204,7 +280,9 @@ struct pseudo_hdr {
/* Dsp Airlink = 0x90 */
/* Dsp Loader = 0xa0 */
/* Dsp MIP = 0xb0 */
- unsigned char portsrc; /* software source port id (refer to portdest) */
+ unsigned char portsrc; /* software source port id
+ * (refer to portdest)
+ */
unsigned short sh_str_id; /* not used */
unsigned char control; /* not used */
unsigned char rsvd1;
diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c
index 8af136e9c9dc..b22142ee5262 100644
--- a/drivers/staging/fwserial/fwserial.c
+++ b/drivers/staging/fwserial/fwserial.c
@@ -2036,6 +2036,13 @@ static void fwserial_auto_connect(struct work_struct *work)
schedule_delayed_work(&peer->connect, CONNECT_RETRY_DELAY);
}
+static void fwserial_peer_workfn(struct work_struct *work)
+{
+ struct fwtty_peer *peer = to_peer(work, work);
+
+ peer->workfn(work);
+}
+
/**
* fwserial_add_peer - add a newly probed 'serial' unit device as a 'peer'
* @serial: aggregate representing the specific fw_card to add the peer to
@@ -2100,7 +2107,7 @@ static int fwserial_add_peer(struct fw_serial *serial, struct fw_unit *unit)
peer->port = NULL;
init_timer(&peer->timer);
- INIT_WORK(&peer->work, NULL);
+ INIT_WORK(&peer->work, fwserial_peer_workfn);
INIT_DELAYED_WORK(&peer->connect, fwserial_auto_connect);
/* associate peer with specific fw_card */
@@ -2702,7 +2709,7 @@ static int fwserial_parse_mgmt_write(struct fwtty_peer *peer,
} else {
peer->work_params.plug_req = pkt->plug_req;
- PREPARE_WORK(&peer->work, fwserial_handle_plug_req);
+ peer->workfn = fwserial_handle_plug_req;
queue_work(system_unbound_wq, &peer->work);
}
break;
@@ -2731,7 +2738,7 @@ static int fwserial_parse_mgmt_write(struct fwtty_peer *peer,
fwtty_err(&peer->unit, "unplug req: busy\n");
rcode = RCODE_CONFLICT_ERROR;
} else {
- PREPARE_WORK(&peer->work, fwserial_handle_unplug_req);
+ peer->workfn = fwserial_handle_unplug_req;
queue_work(system_unbound_wq, &peer->work);
}
break;
diff --git a/drivers/staging/fwserial/fwserial.h b/drivers/staging/fwserial/fwserial.h
index 54f7f9b9b212..98b853d4acbc 100644
--- a/drivers/staging/fwserial/fwserial.h
+++ b/drivers/staging/fwserial/fwserial.h
@@ -91,6 +91,7 @@ struct fwtty_peer {
struct rcu_head rcu;
spinlock_t lock;
+ work_func_t workfn;
struct work_struct work;
struct peer_work_params work_params;
struct timer_list timer;
diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c
index 74a03608b2dd..64c55b99fda4 100644
--- a/drivers/staging/gdm724x/gdm_lte.c
+++ b/drivers/staging/gdm724x/gdm_lte.c
@@ -131,7 +131,8 @@ static int gdm_lte_emulate_arp(struct sk_buff *skb_in, u32 nic_type)
/* Get the pointer of the original request */
arp_in = (struct arphdr *)(skb_in->data + mac_header_len);
- arp_data_in = (struct arpdata *)(skb_in->data + mac_header_len + sizeof(struct arphdr));
+ arp_data_in = (struct arpdata *)(skb_in->data + mac_header_len +
+ sizeof(struct arphdr));
/* Get the pointer of the outgoing response */
arp_out = (struct arphdr *)arp_temp;
@@ -160,9 +161,12 @@ static int gdm_lte_emulate_arp(struct sk_buff *skb_in, u32 nic_type)
return -ENOMEM;
skb_reserve(skb_out, NET_IP_ALIGN);
- memcpy(skb_put(skb_out, mac_header_len), mac_header_data, mac_header_len);
- memcpy(skb_put(skb_out, sizeof(struct arphdr)), arp_out, sizeof(struct arphdr));
- memcpy(skb_put(skb_out, sizeof(struct arpdata)), arp_data_out, sizeof(struct arpdata));
+ memcpy(skb_put(skb_out, mac_header_len), mac_header_data,
+ mac_header_len);
+ memcpy(skb_put(skb_out, sizeof(struct arphdr)), arp_out,
+ sizeof(struct arphdr));
+ memcpy(skb_put(skb_out, sizeof(struct arpdata)), arp_data_out,
+ sizeof(struct arpdata));
skb_out->protocol = ((struct ethhdr *)mac_header_data)->h_proto;
skb_out->dev = skb_in->dev;
@@ -198,7 +202,7 @@ static int icmp6_checksum(struct ipv6hdr *ipv6, u16 *ptr, int len)
pseudo_header.ph.ph_nxt = ipv6->nexthdr;
w = (u16 *)&pseudo_header;
- for (i = 0; i < sizeof(pseudo_header.pa) / sizeof(pseudo_header.pa[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(pseudo_header.pa); i++)
sum += pseudo_header.pa[i];
w = ptr;
@@ -260,11 +264,14 @@ static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type)
return -1;
/* Check if this is NDP packet */
- icmp6_in = (struct icmp6hdr *)(skb_in->data + mac_header_len + sizeof(struct ipv6hdr));
+ icmp6_in = (struct icmp6hdr *)(skb_in->data + mac_header_len +
+ sizeof(struct ipv6hdr));
if (icmp6_in->icmp6_type == NDISC_ROUTER_SOLICITATION) { /* Check RS */
return -1;
- } else if (icmp6_in->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { /* Check NS */
- u8 icmp_na[sizeof(struct icmp6hdr) + sizeof(struct neighbour_advertisement)];
+ } else if (icmp6_in->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
+ /* Check NS */
+ u8 icmp_na[sizeof(struct icmp6hdr) +
+ sizeof(struct neighbour_advertisement)];
u8 zero_addr8[16] = {0,};
if (memcmp(ipv6_in->saddr.in6_u.u6_addr8, zero_addr8, 16) == 0)
@@ -276,7 +283,9 @@ static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type)
icmp6_out.icmp6_cksum = 0;
icmp6_out.icmp6_dataun.un_data32[0] = htonl(0x60000000); /* R=0, S=1, O=1 */
- ns = (struct neighbour_solicitation *)(skb_in->data + mac_header_len + sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr));
+ ns = (struct neighbour_solicitation *)
+ (skb_in->data + mac_header_len +
+ sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr));
memcpy(&na.target_address, ns->target_address, 16);
na.type = 0x02;
na.length = 1;
@@ -289,13 +298,17 @@ static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type)
memcpy(&ipv6_out, ipv6_in, sizeof(struct ipv6hdr));
memcpy(ipv6_out.saddr.in6_u.u6_addr8, &na.target_address, 16);
- memcpy(ipv6_out.daddr.in6_u.u6_addr8, ipv6_in->saddr.in6_u.u6_addr8, 16);
- ipv6_out.payload_len = htons(sizeof(struct icmp6hdr) + sizeof(struct neighbour_advertisement));
+ memcpy(ipv6_out.daddr.in6_u.u6_addr8,
+ ipv6_in->saddr.in6_u.u6_addr8, 16);
+ ipv6_out.payload_len = htons(sizeof(struct icmp6hdr) +
+ sizeof(struct neighbour_advertisement));
memcpy(icmp_na, &icmp6_out, sizeof(struct icmp6hdr));
- memcpy(icmp_na + sizeof(struct icmp6hdr), &na, sizeof(struct neighbour_advertisement));
+ memcpy(icmp_na + sizeof(struct icmp6hdr), &na,
+ sizeof(struct neighbour_advertisement));
- icmp6_out.icmp6_cksum = icmp6_checksum(&ipv6_out, (u16 *)icmp_na, sizeof(icmp_na));
+ icmp6_out.icmp6_cksum = icmp6_checksum(&ipv6_out,
+ (u16 *)icmp_na, sizeof(icmp_na));
} else {
return -1;
}
@@ -311,10 +324,14 @@ static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type)
return -ENOMEM;
skb_reserve(skb_out, NET_IP_ALIGN);
- memcpy(skb_put(skb_out, mac_header_len), mac_header_data, mac_header_len);
- memcpy(skb_put(skb_out, sizeof(struct ipv6hdr)), &ipv6_out, sizeof(struct ipv6hdr));
- memcpy(skb_put(skb_out, sizeof(struct icmp6hdr)), &icmp6_out, sizeof(struct icmp6hdr));
- memcpy(skb_put(skb_out, sizeof(struct neighbour_advertisement)), &na, sizeof(struct neighbour_advertisement));
+ memcpy(skb_put(skb_out, mac_header_len), mac_header_data,
+ mac_header_len);
+ memcpy(skb_put(skb_out, sizeof(struct ipv6hdr)), &ipv6_out,
+ sizeof(struct ipv6hdr));
+ memcpy(skb_put(skb_out, sizeof(struct icmp6hdr)), &icmp6_out,
+ sizeof(struct icmp6hdr));
+ memcpy(skb_put(skb_out, sizeof(struct neighbour_advertisement)), &na,
+ sizeof(struct neighbour_advertisement));
skb_out->protocol = ((struct ethhdr *)mac_header_data)->h_proto;
skb_out->dev = skb_in->dev;
@@ -363,7 +380,8 @@ static s32 gdm_lte_tx_nic_type(struct net_device *dev, struct sk_buff *skb)
/* Check DHCPv4 */
if (ip->protocol == IPPROTO_UDP) {
- struct udphdr *udp = (struct udphdr *)(network_data + sizeof(struct iphdr));
+ struct udphdr *udp = (struct udphdr *)
+ (network_data + sizeof(struct iphdr));
if (ntohs(udp->dest) == 67 || ntohs(udp->dest) == 68)
nic_type |= NIC_TYPE_F_DHCP;
}
@@ -373,12 +391,13 @@ static s32 gdm_lte_tx_nic_type(struct net_device *dev, struct sk_buff *skb)
ipv6 = (struct ipv6hdr *)network_data;
if (ipv6->nexthdr == IPPROTO_ICMPV6) /* Check NDP request */ {
- struct icmp6hdr *icmp6 = (struct icmp6hdr *)(network_data + sizeof(struct ipv6hdr));
- if (/*icmp6->icmp6_type == NDISC_ROUTER_SOLICITATION || */
- icmp6->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION)
+ struct icmp6hdr *icmp6 = (struct icmp6hdr *)
+ (network_data + sizeof(struct ipv6hdr));
+ if (icmp6->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION)
nic_type |= NIC_TYPE_ICMPV6;
} else if (ipv6->nexthdr == IPPROTO_UDP) /* Check DHCPv6 */ {
- struct udphdr *udp = (struct udphdr *)(network_data + sizeof(struct ipv6hdr));
+ struct udphdr *udp = (struct udphdr *)
+ (network_data + sizeof(struct ipv6hdr));
if (ntohs(udp->dest) == 546 || ntohs(udp->dest) == 547)
nic_type |= NIC_TYPE_F_DHCP;
}
@@ -420,11 +439,12 @@ static int gdm_lte_tx(struct sk_buff *skb, struct net_device *dev)
}
/*
- Need byte shift (that is, remove VLAN tag) if there is one
- For the case of ARP, this breaks the offset as vlan_ethhdr+4 is treated as ethhdr
- However, it shouldn't be a problem as the response starts from arp_hdr and ethhdr
- is created by this driver based on the NIC mac
- */
+ * Need byte shift (that is, remove VLAN tag) if there is one
+ * For the case of ARP, this breaks the offset as vlan_ethhdr+4
+ * is treated as ethhdr However, it shouldn't be a problem as
+ * the response starts from arp_hdr and ethhdr is created by this
+ * driver based on the NIC mac
+ */
if (nic_type & NIC_TYPE_F_VLAN) {
struct vlan_ethhdr *vlan_eth = (struct vlan_ethhdr *)skb->data;
nic->vlan_id = ntohs(vlan_eth->h_vlan_TCI) & VLAN_VID_MASK;
@@ -436,15 +456,23 @@ static int gdm_lte_tx(struct sk_buff *skb, struct net_device *dev)
data_len = skb->len;
}
- /* If it is a ICMPV6 packet, clear all the other bits : for backward compatibility with the firmware */
+ /* If it is a ICMPV6 packet, clear all the other bits :
+ * for backward compatibility with the firmware
+ */
if (nic_type & NIC_TYPE_ICMPV6)
nic_type = NIC_TYPE_ICMPV6;
- /* If it is not a dhcp packet, clear all the flag bits : original NIC, otherwise the special flag (IPVX | DHCP) */
+ /* If it is not a dhcp packet, clear all the flag bits :
+ * original NIC, otherwise the special flag (IPVX | DHCP)
+ */
if (!(nic_type & NIC_TYPE_F_DHCP))
nic_type &= NIC_TYPE_MASK;
- sscanf(dev->name, "lte%d", &idx);
+ ret = sscanf(dev->name, "lte%d", &idx);
+ if (ret != 1) {
+ dev_kfree_skb(skb);
+ return -EINVAL;
+ }
ret = nic->phy_dev->send_sdu_func(nic->phy_dev->priv_dev,
data_buf, data_len,
@@ -485,8 +513,11 @@ static int gdm_lte_event_send(struct net_device *dev, char *buf, int len)
struct nic *nic = netdev_priv(dev);
struct hci_packet *hci = (struct hci_packet *)buf;
int idx;
+ int ret;
- sscanf(dev->name, "lte%d", &idx);
+ ret = sscanf(dev->name, "lte%d", &idx);
+ if (ret != 1)
+ return -EINVAL;
return netlink_send(lte_event.sock, idx, 0, buf,
gdm_dev16_to_cpu(
@@ -495,7 +526,8 @@ static int gdm_lte_event_send(struct net_device *dev, char *buf, int len)
+ HCI_HEADER_SIZE);
}
-static void gdm_lte_event_rcv(struct net_device *dev, u16 type, void *msg, int len)
+static void gdm_lte_event_rcv(struct net_device *dev, u16 type,
+ void *msg, int len)
{
struct nic *nic = netdev_priv(dev);
@@ -536,7 +568,8 @@ static u8 find_dev_index(u32 nic_type)
return index;
}
-static void gdm_lte_netif_rx(struct net_device *dev, char *buf, int len, int flagged_nic_type)
+static void gdm_lte_netif_rx(struct net_device *dev, char *buf,
+ int len, int flagged_nic_type)
{
u32 nic_type;
struct nic *nic;
@@ -551,28 +584,46 @@ static void gdm_lte_netif_rx(struct net_device *dev, char *buf, int len, int fla
nic = netdev_priv(dev);
if (flagged_nic_type & NIC_TYPE_F_DHCP) {
- /* Change the destination mac address with the one requested the IP */
+ /* Change the destination mac address
+ * with the one requested the IP
+ */
if (flagged_nic_type & NIC_TYPE_F_IPV4) {
struct dhcp_packet {
u8 op; /* BOOTREQUEST or BOOTREPLY */
- u8 htype; /* hardware address type. 1 = 10mb ethernet */
+ u8 htype; /* hardware address type.
+ * 1 = 10mb ethernet
+ */
u8 hlen; /* hardware address length */
u8 hops; /* used by relay agents only */
u32 xid; /* unique id */
- u16 secs; /* elapsed since client began acquisition/renewal */
+ u16 secs; /* elapsed since client began
+ * acquisition/renewal
+ */
u16 flags; /* only one flag so far: */
- #define BROADCAST_FLAG 0x8000 /* "I need broadcast replies" */
- u32 ciaddr; /* client IP (if client is in BOUND, RENEW or REBINDING state) */
+ #define BROADCAST_FLAG 0x8000
+ /* "I need broadcast replies" */
+ u32 ciaddr; /* client IP (if client is in
+ * BOUND, RENEW or REBINDING state)
+ */
u32 yiaddr; /* 'your' (client) IP address */
- /* IP address of next server to use in bootstrap, returned in DHCPOFFER, DHCPACK by server */
+ /* IP address of next server to use in
+ * bootstrap, returned in DHCPOFFER,
+ * DHCPACK by server
+ */
u32 siaddr_nip;
u32 gateway_nip; /* relay agent IP address */
- u8 chaddr[16]; /* link-layer client hardware address (MAC) */
+ u8 chaddr[16]; /* link-layer client hardware
+ * address (MAC)
+ */
u8 sname[64]; /* server host name (ASCIZ) */
u8 file[128]; /* boot file name (ASCIZ) */
- u32 cookie; /* fixed first four option bytes (99,130,83,99 dec) */
+ u32 cookie; /* fixed first four option
+ * bytes (99,130,83,99 dec)
+ */
} __packed;
- void *addr = buf + sizeof(struct iphdr) + sizeof(struct udphdr) + offsetof(struct dhcp_packet, chaddr);
+ void *addr = buf + sizeof(struct iphdr) +
+ sizeof(struct udphdr) +
+ offsetof(struct dhcp_packet, chaddr);
memcpy(nic->dest_mac_addr, addr, ETH_ALEN);
}
}
@@ -593,7 +644,9 @@ static void gdm_lte_netif_rx(struct net_device *dev, char *buf, int len, int fla
vlan_eth.h_vlan_proto = htons(ETH_P_8021Q);
if (nic_type == NIC_TYPE_ARP) {
- /* Should be response: Only happens because there was a request from the host */
+ /* Should be response: Only happens because
+ * there was a request from the host
+ */
eth.h_proto = htons(ETH_P_ARP);
vlan_eth.h_vlan_encapsulated_proto = htons(ETH_P_ARP);
} else {
@@ -640,15 +693,20 @@ static void gdm_lte_multi_sdu_pkt(struct phy_dev *phy_dev, char *buf, int len)
u32 nic_type;
u8 index;
- hci_len = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), multi_sdu->len);
- num_packet = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), multi_sdu->num_packet);
+ hci_len = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev),
+ multi_sdu->len);
+ num_packet = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev),
+ multi_sdu->num_packet);
for (i = 0; i < num_packet; i++) {
sdu = (struct sdu *)data;
- cmd_evt = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->cmd_evt);
- hci_len = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->len);
- nic_type = gdm_dev32_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->nic_type);
+ cmd_evt = gdm_dev16_to_cpu(phy_dev->
+ get_endian(phy_dev->priv_dev), sdu->cmd_evt);
+ hci_len = gdm_dev16_to_cpu(phy_dev->
+ get_endian(phy_dev->priv_dev), sdu->len);
+ nic_type = gdm_dev32_to_cpu(phy_dev->
+ get_endian(phy_dev->priv_dev), sdu->nic_type);
if (cmd_evt != LTE_RX_SDU) {
pr_err("rx sdu wrong hci %04x\n", cmd_evt);
@@ -662,7 +720,8 @@ static void gdm_lte_multi_sdu_pkt(struct phy_dev *phy_dev, char *buf, int len)
index = find_dev_index(nic_type);
if (index < MAX_NIC_TYPE) {
dev = phy_dev->dev[index];
- gdm_lte_netif_rx(dev, (char *)sdu->data, (int)(hci_len-12), nic_type);
+ gdm_lte_netif_rx(dev, (char *)sdu->data,
+ (int)(hci_len-12), nic_type);
} else {
pr_err("rx sdu invalid nic_type :%x\n", nic_type);
}
@@ -709,7 +768,8 @@ static int gdm_lte_receive_pkt(struct phy_dev *phy_dev, char *buf, int len)
if (!len)
return ret;
- cmd_evt = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), hci->cmd_evt);
+ cmd_evt = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev),
+ hci->cmd_evt);
dev = phy_dev->dev[0];
if (dev == NULL)
@@ -718,7 +778,8 @@ static int gdm_lte_receive_pkt(struct phy_dev *phy_dev, char *buf, int len)
switch (cmd_evt) {
case LTE_RX_SDU:
sdu = (struct sdu *)hci->data;
- nic_type = gdm_dev32_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->nic_type);
+ nic_type = gdm_dev32_to_cpu(phy_dev->
+ get_endian(phy_dev->priv_dev), sdu->nic_type);
index = find_dev_index(nic_type);
dev = phy_dev->dev[index];
gdm_lte_netif_rx(dev, hci->data, len, nic_type);
@@ -733,7 +794,9 @@ static int gdm_lte_receive_pkt(struct phy_dev *phy_dev, char *buf, int len)
break;
case LTE_PDN_TABLE_IND:
pdn_table = (struct hci_pdn_table_ind *)buf;
- nic_type = gdm_dev32_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), pdn_table->nic_type);
+ nic_type = gdm_dev32_to_cpu(phy_dev->
+ get_endian(phy_dev->priv_dev),
+ pdn_table->nic_type);
index = find_dev_index(nic_type);
dev = phy_dev->dev[index];
gdm_lte_pdn_table(dev, buf, len);
@@ -758,7 +821,8 @@ void start_rx_proc(struct phy_dev *phy_dev)
int i;
for (i = 0; i < MAX_RX_SUBMIT_COUNT; i++)
- phy_dev->rcv_func(phy_dev->priv_dev, rx_complete, phy_dev, USB_COMPLETE);
+ phy_dev->rcv_func(phy_dev->priv_dev,
+ rx_complete, phy_dev, USB_COMPLETE);
}
static struct net_device_ops gdm_netdev_ops = {
@@ -771,7 +835,8 @@ static struct net_device_ops gdm_netdev_ops = {
static u8 gdm_lte_macaddr[ETH_ALEN] = {0x00, 0x0a, 0x3b, 0x00, 0x00, 0x00};
-static void form_mac_address(u8 *dev_addr, u8 *nic_src, u8 *nic_dest, u8 *mac_address, u8 index)
+static void form_mac_address(u8 *dev_addr, u8 *nic_src, u8 *nic_dest,
+ u8 *mac_address, u8 index)
{
/* Form the dev_addr */
if (!mac_address)
@@ -779,10 +844,14 @@ static void form_mac_address(u8 *dev_addr, u8 *nic_src, u8 *nic_dest, u8 *mac_ad
else
memcpy(dev_addr, mac_address, ETH_ALEN);
- /* The last byte of the mac address should be less than or equal to 0xFC */
+ /* The last byte of the mac address
+ * should be less than or equal to 0xFC
+ */
dev_addr[ETH_ALEN-1] += index;
- /* Create random nic src and copy the first 3 bytes to be the same as dev_addr */
+ /* Create random nic src and copy the first
+ * 3 bytes to be the same as dev_addr
+ */
random_ether_addr(nic_src);
memcpy(nic_src, dev_addr, 3);
@@ -799,7 +868,8 @@ static void validate_mac_address(u8 *mac_address)
}
}
-int register_lte_device(struct phy_dev *phy_dev, struct device *dev, u8 *mac_address)
+int register_lte_device(struct phy_dev *phy_dev,
+ struct device *dev, u8 *mac_address)
{
struct nic *nic;
struct net_device *net;
@@ -814,7 +884,8 @@ int register_lte_device(struct phy_dev *phy_dev, struct device *dev, u8 *mac_add
sprintf(pdn_dev_name, "lte%%dpdn%d", index);
/* Allocate netdev */
- net = alloc_netdev(sizeof(struct nic), pdn_dev_name, ether_setup);
+ net = alloc_netdev(sizeof(struct nic), pdn_dev_name,
+ ether_setup);
if (net == NULL) {
pr_err("alloc_netdev failed\n");
ret = -ENOMEM;
diff --git a/drivers/staging/gdm724x/gdm_lte.h b/drivers/staging/gdm724x/gdm_lte.h
index 9287d310d8e2..88414e5a70cc 100644
--- a/drivers/staging/gdm724x/gdm_lte.h
+++ b/drivers/staging/gdm724x/gdm_lte.h
@@ -56,7 +56,7 @@ struct phy_dev {
int (*cb)(void *cb_data, void *data, int len,
int context),
void *cb_data, int context);
- struct gdm_endian *(*get_endian)(void *priv_dev);
+ struct gdm_endian * (*get_endian)(void *priv_dev);
};
struct nic {
diff --git a/drivers/staging/gdm724x/gdm_mux.c b/drivers/staging/gdm724x/gdm_mux.c
index 2fa3a5a6580f..10ce2c1805bb 100644
--- a/drivers/staging/gdm724x/gdm_mux.c
+++ b/drivers/staging/gdm724x/gdm_mux.c
@@ -165,7 +165,8 @@ static int up_to_host(struct mux_rx *r)
int len = r->len;
while (1) {
- mux_header = (struct mux_pkt_header *)(r->buf + packet_size_sum);
+ mux_header = (struct mux_pkt_header *)(r->buf +
+ packet_size_sum);
start_flag = __le32_to_cpu(mux_header->start_flag);
payload_size = __le32_to_cpu(mux_header->payload_size);
packet_type = __le16_to_cpu(mux_header->packet_type);
@@ -231,7 +232,8 @@ static void do_rx(struct work_struct *work)
spin_unlock_irqrestore(&rx->to_host_lock, flags);
break;
}
- r = list_entry(rx->to_host_list.next, struct mux_rx, to_host_list);
+ r = list_entry(rx->to_host_list.next, struct mux_rx,
+ to_host_list);
list_del(&r->to_host_list);
spin_unlock_irqrestore(&rx->to_host_lock, flags);
@@ -249,7 +251,8 @@ static void remove_rx_submit_list(struct mux_rx *r, struct rx_cxt *rx)
struct mux_rx *r_remove, *r_remove_next;
spin_lock_irqsave(&rx->submit_list_lock, flags);
- list_for_each_entry_safe(r_remove, r_remove_next, &rx->rx_submit_list, rx_submit_list) {
+ list_for_each_entry_safe(r_remove, r_remove_next, &rx->rx_submit_list,
+ rx_submit_list) {
if (r == r_remove)
list_del(&r->rx_submit_list);
}
@@ -279,9 +282,8 @@ static void gdm_mux_rcv_complete(struct urb *urb)
}
}
-static int gdm_mux_recv(void *priv_dev,
- int (*cb)(void *data, int len, int tty_index, struct tty_dev *tty_dev, int complete)
- )
+static int gdm_mux_recv(void *priv_dev, int (*cb)(void *data, int len,
+ int tty_index, struct tty_dev *tty_dev, int complete))
{
struct mux_dev *mux_dev = priv_dev;
struct usb_device *usbdev = mux_dev->usbdev;
@@ -416,7 +418,8 @@ static int gdm_mux_send(void *priv_dev, void *data, int len, int tty_index,
return ret;
}
-static int gdm_mux_send_control(void *priv_dev, int request, int value, void *buf, int len)
+static int gdm_mux_send_control(void *priv_dev, int request, int value,
+ void *buf, int len)
{
struct mux_dev *mux_dev = priv_dev;
struct usb_device *usbdev = mux_dev->usbdev;
@@ -448,7 +451,8 @@ static void release_usb(struct mux_dev *mux_dev)
cancel_delayed_work(&mux_dev->work_rx);
spin_lock_irqsave(&rx->submit_list_lock, flags);
- list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list) {
+ list_for_each_entry_safe(r, r_next, &rx->rx_submit_list,
+ rx_submit_list) {
spin_unlock_irqrestore(&rx->submit_list_lock, flags);
usb_kill_urb(r->urb);
spin_lock_irqsave(&rx->submit_list_lock, flags);
@@ -503,7 +507,8 @@ static int init_usb(struct mux_dev *mux_dev)
return ret;
}
-static int gdm_mux_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static int gdm_mux_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
{
struct mux_dev *mux_dev;
struct tty_dev *tty_dev;
@@ -610,7 +615,8 @@ static int gdm_mux_suspend(struct usb_interface *intf, pm_message_t pm_msg)
spin_lock_irqsave(&rx->submit_list_lock, flags);
- list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list) {
+ list_for_each_entry_safe(r, r_next, &rx->rx_submit_list,
+ rx_submit_list) {
spin_unlock_irqrestore(&rx->submit_list_lock, flags);
usb_kill_urb(r->urb);
spin_lock_irqsave(&rx->submit_list_lock, flags);
diff --git a/drivers/staging/gdm724x/gdm_usb.c b/drivers/staging/gdm724x/gdm_usb.c
index 33458a583142..ee6e40facca7 100644
--- a/drivers/staging/gdm724x/gdm_usb.c
+++ b/drivers/staging/gdm724x/gdm_usb.c
@@ -30,14 +30,17 @@
#include "gdm_endian.h"
#define USB_DEVICE_CDC_DATA(vid, pid) \
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS,\
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+ USB_DEVICE_ID_MATCH_INT_CLASS | \
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS,\
.idVendor = vid,\
.idProduct = pid,\
.bInterfaceClass = USB_CLASS_COMM,\
.bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET
#define USB_DEVICE_MASS_DATA(vid, pid) \
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,\
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+ USB_DEVICE_ID_MATCH_INT_INFO,\
.idVendor = vid,\
.idProduct = pid,\
.bInterfaceSubClass = USB_SC_SCSI, \
@@ -59,7 +62,8 @@ static void do_tx(struct work_struct *work);
static void do_rx(struct work_struct *work);
static int gdm_usb_recv(void *priv_dev,
- int (*cb)(void *cb_data, void *data, int len, int context),
+ int (*cb)(void *cb_data,
+ void *data, int len, int context),
void *cb_data,
int context);
@@ -119,28 +123,15 @@ out:
static struct usb_tx_sdu *alloc_tx_sdu_struct(void)
{
- struct usb_tx_sdu *t_sdu = NULL;
- int ret = 0;
-
+ struct usb_tx_sdu *t_sdu;
t_sdu = kzalloc(sizeof(struct usb_tx_sdu), GFP_ATOMIC);
- if (!t_sdu) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!t_sdu)
+ return NULL;
t_sdu->buf = kmalloc(SDU_BUF_SIZE, GFP_ATOMIC);
if (!t_sdu->buf) {
- ret = -ENOMEM;
- goto out;
- }
-out:
-
- if (ret < 0) {
- if (t_sdu) {
- kfree(t_sdu->buf);
- kfree(t_sdu);
- }
+ kfree(t_sdu);
return NULL;
}
@@ -388,7 +379,8 @@ static int set_mac_address(u8 *data, void *arg)
if (tlv->type == MAC_ADDRESS && udev->request_mac_addr) {
memcpy(mac_address, tlv->data, tlv->len);
- if (register_lte_device(phy_dev, &udev->intf->dev, mac_address) < 0)
+ if (register_lte_device(phy_dev,
+ &udev->intf->dev, mac_address) < 0)
pr_err("register lte device failed\n");
udev->request_mac_addr = 0;
@@ -401,7 +393,8 @@ static int set_mac_address(u8 *data, void *arg)
static void do_rx(struct work_struct *work)
{
- struct lte_udev *udev = container_of(work, struct lte_udev, work_rx.work);
+ struct lte_udev *udev =
+ container_of(work, struct lte_udev, work_rx.work);
struct rx_cxt *rx = &udev->rx;
struct usb_rx *r;
struct hci_packet *hci;
@@ -416,7 +409,8 @@ static void do_rx(struct work_struct *work)
spin_unlock_irqrestore(&rx->to_host_lock, flags);
break;
}
- r = list_entry(rx->to_host_list.next, struct usb_rx, to_host_list);
+ r = list_entry(rx->to_host_list.next,
+ struct usb_rx, to_host_list);
list_del(&r->to_host_list);
spin_unlock_irqrestore(&rx->to_host_lock, flags);
@@ -463,7 +457,8 @@ static void remove_rx_submit_list(struct usb_rx *r, struct rx_cxt *rx)
struct usb_rx *r_remove, *r_remove_next;
spin_lock_irqsave(&rx->submit_lock, flags);
- list_for_each_entry_safe(r_remove, r_remove_next, &rx->rx_submit_list, rx_submit_list)
+ list_for_each_entry_safe(r_remove,
+ r_remove_next, &rx->rx_submit_list, rx_submit_list)
{
if (r == r_remove) {
list_del(&r->rx_submit_list);
@@ -500,7 +495,8 @@ static void gdm_usb_rcv_complete(struct urb *urb)
}
static int gdm_usb_recv(void *priv_dev,
- int (*cb)(void *cb_data, void *data, int len, int context),
+ int (*cb)(void *cb_data,
+ void *data, int len, int context),
void *cb_data,
int context)
{
@@ -654,7 +650,8 @@ static u32 packet_aggregation(struct lte_udev *udev, u8 *send_buf)
static void do_tx(struct work_struct *work)
{
- struct lte_udev *udev = container_of(work, struct lte_udev, work_tx.work);
+ struct lte_udev *udev =
+ container_of(work, struct lte_udev, work_tx.work);
struct usb_device *usbdev = udev->usbdev;
struct tx_cxt *tx = &udev->tx;
struct usb_tx *t = NULL;
@@ -813,7 +810,8 @@ static struct gdm_endian *gdm_usb_get_endian(void *priv_dev)
return &udev->gdm_ed;
}
-static int gdm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static int gdm_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
{
int ret = 0;
struct phy_dev *phy_dev = NULL;
@@ -861,7 +859,9 @@ static int gdm_usb_probe(struct usb_interface *intf, const struct usb_device_id
usb_enable_autosuspend(usbdev);
pm_runtime_set_autosuspend_delay(&usbdev->dev, AUTO_SUSPEND_TIMER);
- /* List up hosts with big endians, otherwise, defaults to little endian */
+ /* List up hosts with big endians, otherwise,
+ * defaults to little endian
+ */
if (idProduct == PID_GDM7243)
gdm_set_endian(&udev->gdm_ed, ENDIANNESS_BIG);
else
diff --git a/drivers/staging/gdm724x/netlink_k.c b/drivers/staging/gdm724x/netlink_k.c
index 77fc64e28428..5ddd36948a2f 100644
--- a/drivers/staging/gdm724x/netlink_k.c
+++ b/drivers/staging/gdm724x/netlink_k.c
@@ -32,7 +32,8 @@ static struct semaphore netlink_mutex;
#define ND_MAX_GROUP 30
#define ND_IFINDEX_LEN sizeof(int)
#define ND_NLMSG_SPACE(len) (NLMSG_SPACE(len) + ND_IFINDEX_LEN)
-#define ND_NLMSG_DATA(nlh) ((void *)((char *)NLMSG_DATA(nlh) + ND_IFINDEX_LEN))
+#define ND_NLMSG_DATA(nlh) ((void *)((char *)NLMSG_DATA(nlh) + \
+ ND_IFINDEX_LEN))
#define ND_NLMSG_S_LEN(len) (len+ND_IFINDEX_LEN)
#define ND_NLMSG_R_LEN(nlh) (nlh->nlmsg_len-ND_IFINDEX_LEN)
#define ND_NLMSG_IFIDX(nlh) NLMSG_DATA(nlh)
diff --git a/drivers/staging/gdm72xx/TODO b/drivers/staging/gdm72xx/TODO
index 30ac01ab972f..5ab27fb29594 100644
--- a/drivers/staging/gdm72xx/TODO
+++ b/drivers/staging/gdm72xx/TODO
@@ -1,5 +1,3 @@
TODO:
- Replace kernel_thread with kthread in gdm_usb.c
-- Replace hard-coded firmware paths with request_firmware in
- sdio_boot.c and usb_boot.c
- Clean up coding style to meet kernel standard.
diff --git a/drivers/staging/gdm72xx/gdm_sdio.c b/drivers/staging/gdm72xx/gdm_sdio.c
index 047a4d77f5ee..c24653739e13 100644
--- a/drivers/staging/gdm72xx/gdm_sdio.c
+++ b/drivers/staging/gdm72xx/gdm_sdio.c
@@ -38,26 +38,9 @@
#define TX_HZ 2000
#define TX_INTERVAL (1000000/TX_HZ)
-/*#define DEBUG*/
-
static int init_sdio(struct sdiowm_dev *sdev);
static void release_sdio(struct sdiowm_dev *sdev);
-#ifdef DEBUG
-static void hexdump(char *title, u8 *data, int len)
-{
- int i;
-
- printk(KERN_DEBUG "%s: length = %d\n", title, len);
- for (i = 0; i < len; i++) {
- printk(KERN_DEBUG "%02x ", data[i]);
- if ((i & 0xf) == 0xf)
- printk(KERN_DEBUG "\n");
- }
- printk(KERN_DEBUG "\n");
-}
-#endif
-
static struct sdio_tx *alloc_tx_struct(struct tx_cxt *tx)
{
struct sdio_tx *t = kzalloc(sizeof(*t), GFP_ATOMIC);
@@ -297,10 +280,9 @@ static void send_sdu(struct sdio_func *func, struct tx_cxt *tx)
spin_unlock_irqrestore(&tx->lock, flags);
-#ifdef DEBUG
- hexdump("sdio_send", tx->sdu_buf + TYPE_A_HEADER_SIZE,
- aggr_len - TYPE_A_HEADER_SIZE);
-#endif
+ print_hex_dump_debug("sdio_send: ", DUMP_PREFIX_NONE, 16, 1,
+ tx->sdu_buf + TYPE_A_HEADER_SIZE,
+ aggr_len - TYPE_A_HEADER_SIZE, false);
for (pos = TYPE_A_HEADER_SIZE; pos < aggr_len; pos += TX_CHUNK_SIZE) {
len = aggr_len - pos;
@@ -335,10 +317,9 @@ static void send_hci(struct sdio_func *func, struct tx_cxt *tx,
{
unsigned long flags;
-#ifdef DEBUG
- hexdump("sdio_send", t->buf + TYPE_A_HEADER_SIZE,
- t->len - TYPE_A_HEADER_SIZE);
-#endif
+ print_hex_dump_debug("sdio_send: ", DUMP_PREFIX_NONE, 16, 1,
+ t->buf + TYPE_A_HEADER_SIZE,
+ t->len - TYPE_A_HEADER_SIZE, false);
send_sdio_pkt(func, t->buf, t->len);
spin_lock_irqsave(&tx->lock, flags);
@@ -474,14 +455,10 @@ static int control_sdu_tx_flow(struct sdiowm_dev *sdev, u8 *hci_data, int len)
goto out;
if (hci_data[4] == 0) {
-#ifdef DEBUG
- printk(KERN_DEBUG "WIMAX ==> STOP SDU TX\n");
-#endif
+ dev_dbg(&sdev->func->dev, "WIMAX ==> STOP SDU TX\n");
tx->stop_sdu_tx = 1;
} else if (hci_data[4] == 1) {
-#ifdef DEBUG
- printk(KERN_DEBUG "WIMAX ==> START SDU TX\n");
-#endif
+ dev_dbg(&sdev->func->dev, "WIMAX ==> START SDU TX\n");
tx->stop_sdu_tx = 0;
if (tx->can_send)
schedule_work(&sdev->ws);
@@ -532,18 +509,14 @@ static void gdm_sdio_irq(struct sdio_func *func)
}
if (hdr[3] == 1) { /* Ack */
-#ifdef DEBUG
u32 *ack_seq = (u32 *)&hdr[4];
-#endif
spin_lock_irqsave(&tx->lock, flags);
tx->can_send = 1;
if (!list_empty(&tx->sdu_list) || !list_empty(&tx->hci_list))
schedule_work(&sdev->ws);
spin_unlock_irqrestore(&tx->lock, flags);
-#ifdef DEBUG
- printk(KERN_DEBUG "Ack... %0x\n", ntohl(*ack_seq));
-#endif
+ dev_dbg(&func->dev, "Ack... %0x\n", ntohl(*ack_seq));
goto done;
}
@@ -579,9 +552,8 @@ static void gdm_sdio_irq(struct sdio_func *func)
}
end_io:
-#ifdef DEBUG
- hexdump("sdio_receive", rx->rx_buf, len);
-#endif
+ print_hex_dump_debug("sdio_receive: ", DUMP_PREFIX_NONE, 16, 1,
+ rx->rx_buf, len, false);
len = control_sdu_tx_flow(sdev, rx->rx_buf, len);
spin_lock_irqsave(&rx->lock, flags);
diff --git a/drivers/staging/gdm72xx/gdm_usb.c b/drivers/staging/gdm72xx/gdm_usb.c
index cdeffe75496b..20539d809397 100644
--- a/drivers/staging/gdm72xx/gdm_usb.c
+++ b/drivers/staging/gdm72xx/gdm_usb.c
@@ -55,22 +55,6 @@ static int k_mode_stop;
static int init_usb(struct usbwm_dev *udev);
static void release_usb(struct usbwm_dev *udev);
-/*#define DEBUG */
-#ifdef DEBUG
-static void hexdump(char *title, u8 *data, int len)
-{
- int i;
-
- printk(KERN_DEBUG "%s: length = %d\n", title, len);
- for (i = 0; i < len; i++) {
- printk(KERN_DEBUG "%02x ", data[i]);
- if ((i & 0xf) == 0xf)
- printk(KERN_DEBUG "\n");
- }
- printk(KERN_DEBUG "\n");
-}
-#endif
-
static struct usb_tx *alloc_tx_struct(struct tx_cxt *tx)
{
struct usb_tx *t = kzalloc(sizeof(*t), GFP_ATOMIC);
@@ -368,9 +352,8 @@ static int gdm_usb_send(void *priv_dev, void *data, int len,
gdm_usb_send_complete,
t);
-#ifdef DEBUG
- hexdump("usb_send", t->buf, len + padding);
-#endif
+ print_hex_dump_debug("usb_send: ", DUMP_PREFIX_NONE, 16, 1,
+ t->buf, len + padding, false);
#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
if (usbdev->state & USB_STATE_SUSPENDED) {
list_add_tail(&t->p_list, &tx->pending_list);
@@ -438,10 +421,7 @@ static void gdm_usb_rcv_complete(struct urb *urb)
struct usb_tx *t;
u16 cmd_evt;
unsigned long flags, flags2;
-
-#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
struct usb_device *dev = urb->dev;
-#endif
/* Completion by usb_unlink_urb */
if (urb->status == -ECONNRESET)
@@ -451,20 +431,15 @@ static void gdm_usb_rcv_complete(struct urb *urb)
if (!urb->status) {
cmd_evt = (r->buf[0] << 8) | (r->buf[1]);
-#ifdef DEBUG
- hexdump("usb_receive", r->buf, urb->actual_length);
-#endif
+ print_hex_dump_debug("usb_receive: ", DUMP_PREFIX_NONE, 16, 1,
+ r->buf, urb->actual_length, false);
if (cmd_evt == WIMAX_SDU_TX_FLOW) {
if (r->buf[4] == 0) {
-#ifdef DEBUG
- printk(KERN_DEBUG "WIMAX ==> STOP SDU TX\n");
-#endif
+ dev_dbg(&dev->dev, "WIMAX ==> STOP SDU TX\n");
list_for_each_entry(t, &tx->sdu_list, list)
usb_unlink_urb(t->urb);
} else if (r->buf[4] == 1) {
-#ifdef DEBUG
- printk(KERN_DEBUG "WIMAX ==> START SDU TX\n");
-#endif
+ dev_dbg(&dev->dev, "WIMAX ==> START SDU TX\n");
list_for_each_entry(t, &tx->sdu_list, list) {
usb_submit_urb(t->urb, GFP_ATOMIC);
}
diff --git a/drivers/staging/gdm72xx/gdm_wimax.c b/drivers/staging/gdm72xx/gdm_wimax.c
index dd854975db7d..05ce2a22c220 100644
--- a/drivers/staging/gdm72xx/gdm_wimax.c
+++ b/drivers/staging/gdm72xx/gdm_wimax.c
@@ -62,21 +62,6 @@ static u8 gdm_wimax_macaddr[6] = {0x00, 0x0a, 0x3b, 0xf0, 0x01, 0x30};
static void gdm_wimax_ind_fsm_update(struct net_device *dev, struct fsm_s *fsm);
static void gdm_wimax_ind_if_updown(struct net_device *dev, int if_up);
-#if defined(DEBUG_SDU)
-static void printk_hex(u8 *buf, u32 size)
-{
- int i;
-
- for (i = 0; i < size; i++) {
- if (i && i % 16 == 0)
- printk(KERN_DEBUG "\n%02x ", *buf++);
- else
- printk(KERN_DEBUG "%02x ", *buf++);
- }
-
- printk(KERN_DEBUG "\n");
-}
-
static const char *get_protocol_name(u16 protocol)
{
static char buf[32];
@@ -140,7 +125,8 @@ static const char *get_port_name(u16 port)
return buf;
}
-static void dump_eth_packet(const char *title, u8 *data, int len)
+static void dump_eth_packet(struct net_device *dev, const char *title,
+ u8 *data, int len)
{
struct iphdr *ih = NULL;
struct udphdr *uh = NULL;
@@ -162,48 +148,21 @@ static void dump_eth_packet(const char *title, u8 *data, int len)
port = ntohs(uh->dest);
}
- printk(KERN_DEBUG "[%s] len=%d, %s, %s, %s\n",
+ netdev_dbg(dev, "[%s] len=%d, %s, %s, %s\n",
title, len,
get_protocol_name(protocol),
get_ip_protocol_name(ip_protocol),
get_port_name(port));
if (!(data[0] == 0xff && data[1] == 0xff)) {
- if (protocol == ETH_P_IP) {
- printk(KERN_DEBUG " src=%pI4\n", &ih->saddr);
- } else if (protocol == ETH_P_IPV6) {
- printk(KERN_DEBUG " src=%pI6\n", &ih->saddr);
- }
+ if (protocol == ETH_P_IP)
+ netdev_dbg(dev, " src=%pI4\n", &ih->saddr);
+ else if (protocol == ETH_P_IPV6)
+ netdev_dbg(dev, " src=%pI6\n", &ih->saddr);
}
- #if (DUMP_PACKET & DUMP_SDU_ALL)
- printk_hex(data, len);
- #else
- #if (DUMP_PACKET & DUMP_SDU_ARP)
- if (protocol == ETH_P_ARP)
- printk_hex(data, len);
- #endif
- #if (DUMP_PACKET & DUMP_SDU_IP)
- if (protocol == ETH_P_IP || protocol == ETH_P_IPV6)
- printk_hex(data, len);
- #else
- #if (DUMP_PACKET & DUMP_SDU_IP_TCP)
- if (ip_protocol == IPPROTO_TCP)
- printk_hex(data, len);
- #endif
- #if (DUMP_PACKET & DUMP_SDU_IP_UDP)
- if (ip_protocol == IPPROTO_UDP)
- printk_hex(data, len);
- #endif
- #if (DUMP_PACKET & DUMP_SDU_IP_ICMP)
- if (ip_protocol == IPPROTO_ICMP)
- printk_hex(data, len);
- #endif
- #endif
- #endif
+ print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, data, len, false);
}
-#endif
-
static inline int gdm_wimax_header(struct sk_buff **pskb)
{
@@ -237,12 +196,10 @@ static void gdm_wimax_event_rcv(struct net_device *dev, u16 type, void *msg,
{
struct nic *nic = netdev_priv(dev);
- #if defined(DEBUG_HCI)
u8 *buf = (u8 *) msg;
u16 hci_cmd = (buf[0]<<8) | buf[1];
u16 hci_len = (buf[2]<<8) | buf[3];
- printk(KERN_DEBUG "H=>D: 0x%04x(%d)\n", hci_cmd, hci_len);
- #endif
+ netdev_dbg(dev, "H=>D: 0x%04x(%d)\n", hci_cmd, hci_len);
gdm_wimax_send(nic, msg, len);
}
@@ -351,11 +308,9 @@ static int gdm_wimax_event_send(struct net_device *dev, char *buf, int size)
struct evt_entry *e;
unsigned long flags;
- #if defined(DEBUG_HCI)
u16 hci_cmd = ((u8)buf[0]<<8) | (u8)buf[1];
u16 hci_len = ((u8)buf[2]<<8) | (u8)buf[3];
- printk(KERN_DEBUG "D=>H: 0x%04x(%d)\n", hci_cmd, hci_len);
- #endif
+ netdev_dbg(dev, "D=>H: 0x%04x(%d)\n", hci_cmd, hci_len);
spin_lock_irqsave(&wm_event.evt_lock, flags);
@@ -415,9 +370,7 @@ static int gdm_wimax_tx(struct sk_buff *skb, struct net_device *dev)
struct nic *nic = netdev_priv(dev);
struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
- #if defined(DEBUG_SDU)
- dump_eth_packet("TX", skb->data, skb->len);
- #endif
+ dump_eth_packet(dev, "TX", skb->data, skb->len);
ret = gdm_wimax_header(&skb);
if (ret < 0) {
@@ -540,7 +493,7 @@ static int gdm_wimax_ioctl_get_data(struct data_s *dst, struct data_s *src)
if (src->size) {
if (!dst->buf)
return -EINVAL;
- if (copy_to_user(dst->buf, src->buf, size))
+ if (copy_to_user((void __user *)dst->buf, src->buf, size))
return -EFAULT;
}
return 0;
@@ -563,7 +516,7 @@ static int gdm_wimax_ioctl_set_data(struct data_s *dst, struct data_s *src)
return -ENOMEM;
}
- if (copy_from_user(dst->buf, src->buf, src->size)) {
+ if (copy_from_user(dst->buf, (void __user *)src->buf, src->size)) {
kdelete(&dst->buf);
return -EFAULT;
}
@@ -756,9 +709,7 @@ static void gdm_wimax_netif_rx(struct net_device *dev, char *buf, int len)
struct sk_buff *skb;
int ret;
- #if defined(DEBUG_SDU)
- dump_eth_packet("RX", buf, len);
- #endif
+ dump_eth_packet(dev, "RX", buf, len);
skb = dev_alloc_skb(len + 2);
if (!skb) {
diff --git a/drivers/staging/gdm72xx/gdm_wimax.h b/drivers/staging/gdm72xx/gdm_wimax.h
index 6ec0ab43e9cc..1fcfc8555417 100644
--- a/drivers/staging/gdm72xx/gdm_wimax.h
+++ b/drivers/staging/gdm72xx/gdm_wimax.h
@@ -62,26 +62,6 @@ struct nic {
};
-
-#if 0
-#define dprintk(fmt, args ...) printk(KERN_DEBUG " [GDM] " fmt, ## args)
-#else
-#define dprintk(...)
-#endif
-
-/*#define DEBUG_SDU */
-#if defined(DEBUG_SDU)
-#define DUMP_SDU_ALL (1<<0)
-#define DUMP_SDU_ARP (1<<1)
-#define DUMP_SDU_IP (1<<2)
-#define DUMP_SDU_IP_TCP (1<<8)
-#define DUMP_SDU_IP_UDP (1<<9)
-#define DUMP_SDU_IP_ICMP (1<<10)
-#define DUMP_PACKET (DUMP_SDU_ALL)
-#endif
-
-/*#define DEBUG_HCI */
-
/*#define LOOPBACK_TEST */
extern int register_wimax_device(struct phy_dev *phy_dev, struct device *pdev);
diff --git a/drivers/staging/gs_fpgaboot/Kconfig b/drivers/staging/gs_fpgaboot/Kconfig
new file mode 100644
index 000000000000..550645291fab
--- /dev/null
+++ b/drivers/staging/gs_fpgaboot/Kconfig
@@ -0,0 +1,8 @@
+#
+# "xilinx FPGA firmware download, fpgaboot"
+#
+config GS_FPGABOOT
+ tristate "Xilinx FPGA firmware download module"
+ default n
+ help
+ Xilinx FPGA firmware download module
diff --git a/drivers/staging/gs_fpgaboot/Makefile b/drivers/staging/gs_fpgaboot/Makefile
new file mode 100644
index 000000000000..34cb606e0e3d
--- /dev/null
+++ b/drivers/staging/gs_fpgaboot/Makefile
@@ -0,0 +1,4 @@
+gs_fpga-y += gs_fpgaboot.o io.o
+obj-$(CONFIG_GS_FPGABOOT) += gs_fpga.o
+
+ccflags-$(CONFIG_GS_FPGA_DEBUG) := -DDEBUG
diff --git a/drivers/staging/gs_fpgaboot/README b/drivers/staging/gs_fpgaboot/README
new file mode 100644
index 000000000000..cfa8624304e5
--- /dev/null
+++ b/drivers/staging/gs_fpgaboot/README
@@ -0,0 +1,71 @@
+==============================================================================
+Linux Driver Source for Xilinx FPGA firmware download
+==============================================================================
+
+
+TABLE OF CONTENTS.
+
+1. SUMMARY
+2. BACKGROUND
+3. DESIGN
+4. HOW TO USE
+5. REFERENCE
+
+1. SUMMARY
+
+ - Download Xilinx FPGA firmware
+ - This module downloads Xilinx FPGA firmware using gpio pins.
+
+2. BACKGROUND
+
+ An FPGA (Field Programmable Gate Array) is a programmable hardware that is
+ used in various applications. Hardware design needs to programmed through
+ a dedicated device or CPU assisted way (serial or parallel).
+ This driver provides a way to download FPGA firmware.
+
+3. DESIGN
+
+ - load Xilinx FPGA bitstream format[1] firmware image file using
+ kernel firmware framework, request_firmware()
+ - program the Xilinx FPGA using SelectMAP (parallel) mode [2]
+ - FPGA prgram is done by gpio based bit-banging, as an example
+ - platform independent file: gs_fpgaboot.c
+ - platform dependent file: io.c
+
+
+4. HOW TO USE
+
+ $ insmod gs_fpga.ko file="xlinx_fpga_top_bitstream.bit"
+ $ rmmod gs_fpga
+
+5. USE CASE (from a mailing list discussion with Greg)
+
+ a. As a FPGA development support tool,
+ During FPGA firmware development, you need to download a new FPGA
+ image frequently.
+ You would do that with a dedicated JTAG, which usually a limited
+ resource in the lab.
+ However, if you use my driver, you don't have to have a dedicated JTAG.
+ This is a real gain :)
+
+ b. For the FPGA that runs without config after the download, which
+ doesn't talk to any of Linux interfaces (such as PCIE).
+
+ We download FPGA firmware from user triggered or some other way, and that's it.
+ Since that FPGA runs on its own, it doesn't require a linux driver
+ after the download.
+
+ c. For the FPGA that requires config after the download, which talk to
+ any of linux interfaces (such as PCIE)
+
+ Then, this type of FPGA config can be put into device tree and have a
+ separate driver (pcie or others), then THAT driver calls my driver to
+ download FPGA firmware during the Linux boot, the take over the device
+ through the interface.
+
+6. REFERENCE
+
+ 1. Xilinx APP NOTE XAPP583:
+ http://www.xilinx.com/support/documentation/application_notes/xapp583-fpga-configuration.pdf
+ 2. bitstream file info:
+ http://home.earthlink.net/~davesullins/software/bitinfo.html
diff --git a/drivers/staging/gs_fpgaboot/TODO b/drivers/staging/gs_fpgaboot/TODO
new file mode 100644
index 000000000000..2d9fb17d606d
--- /dev/null
+++ b/drivers/staging/gs_fpgaboot/TODO
@@ -0,0 +1,7 @@
+TODO:
+ - get bus width input instead of hardcoded bus width
+ - get it reviewed
+
+Please send any patches for this driver to Insop Song<insop.song@gainspeed.com>
+and Greg Kroah-Hartman <gregkh@linuxfoundation.org>.
+And please CC to "Staging subsystem" mail list <devel@driverdev.osuosl.org> too.
diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c
new file mode 100644
index 000000000000..89bc84d833e6
--- /dev/null
+++ b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c
@@ -0,0 +1,422 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/firmware.h>
+
+#include "gs_fpgaboot.h"
+#include "io.h"
+
+#define DEVICE_NAME "device"
+#define CLASS_NAME "fpgaboot"
+
+static uint8_t bits_magic[] = {
+ 0x0, 0x9, 0xf, 0xf0, 0xf, 0xf0,
+ 0xf, 0xf0, 0xf, 0xf0, 0x0, 0x0, 0x1};
+
+/* fake device for request_firmware */
+static struct platform_device *firmware_pdev;
+
+static char *file = "xlinx_fpga_firmware.bit";
+module_param(file, charp, S_IRUGO);
+MODULE_PARM_DESC(file, "Xilinx FPGA firmware file.");
+
+#ifdef DEBUG_FPGA
+static void datadump(char *msg, void *m, int n)
+{
+ int i;
+ unsigned char *c;
+
+ pr_info("=== %s ===\n", msg);
+
+ c = m;
+
+ for (i = 0; i < n; i++) {
+ if ((i&0xf) == 0)
+ pr_info(KERN_INFO "\n 0x%4x: ", i);
+
+ pr_info("%02X ", c[i]);
+ }
+
+ pr_info("\n");
+}
+#endif /* DEBUG_FPGA */
+
+static void read_bitstream(char *bitdata, char *buf, int *offset, int rdsize)
+{
+ memcpy(buf, bitdata + *offset, rdsize);
+ *offset += rdsize;
+}
+
+static void readinfo_bitstream(char *bitdata, char *buf, int *offset)
+{
+ char tbuf[64];
+ int32_t len;
+
+ /* read section char */
+ read_bitstream(bitdata, tbuf, offset, 1);
+
+ /* read length */
+ read_bitstream(bitdata, tbuf, offset, 2);
+
+ len = tbuf[0] << 8 | tbuf[1];
+
+ read_bitstream(bitdata, buf, offset, len);
+ buf[len] = '\0';
+}
+
+/*
+ * read bitdata length
+ */
+static int readlength_bitstream(char *bitdata, int *lendata, int *offset)
+{
+ char tbuf[64];
+
+ /* read section char */
+ read_bitstream(bitdata, tbuf, offset, 1);
+
+ /* make sure it is section 'e' */
+ if (tbuf[0] != 'e') {
+ pr_err("error: length section is not 'e', but %c\n", tbuf[0]);
+ return -1;
+ }
+
+ /* read 4bytes length */
+ read_bitstream(bitdata, tbuf, offset, 4);
+
+ *lendata = tbuf[0] << 24 | tbuf[1] << 16 |
+ tbuf[2] << 8 | tbuf[3];
+
+ return 0;
+}
+
+
+/*
+ * read first 13 bytes to check bitstream magic number
+ */
+static int readmagic_bitstream(char *bitdata, int *offset)
+{
+ char buf[13];
+ int r;
+
+ read_bitstream(bitdata, buf, offset, 13);
+ r = memcmp(buf, bits_magic, 13);
+ if (r) {
+ pr_err("error: corrupted header");
+ return -1;
+ }
+ pr_info("bitstream file magic number Ok\n");
+
+ *offset = 13; /* magic length */
+
+ return 0;
+}
+
+/*
+ * NOTE: supports only bitstream format
+ */
+static enum fmt_image get_imageformat(struct fpgaimage *fimage)
+{
+ return f_bit;
+}
+
+static void gs_print_header(struct fpgaimage *fimage)
+{
+ pr_info("file: %s\n", fimage->filename);
+ pr_info("part: %s\n", fimage->part);
+ pr_info("date: %s\n", fimage->date);
+ pr_info("time: %s\n", fimage->time);
+ pr_info("lendata: %d\n", fimage->lendata);
+}
+
+static void gs_read_bitstream(struct fpgaimage *fimage)
+{
+ char *bitdata;
+ int size;
+ int offset;
+
+ offset = 0;
+ bitdata = (char *)fimage->fw_entry->data;
+ size = fimage->fw_entry->size;
+
+ readmagic_bitstream(bitdata, &offset);
+ readinfo_bitstream(bitdata, fimage->filename, &offset);
+ readinfo_bitstream(bitdata, fimage->part, &offset);
+ readinfo_bitstream(bitdata, fimage->date, &offset);
+ readinfo_bitstream(bitdata, fimage->time, &offset);
+ readlength_bitstream(bitdata, &fimage->lendata, &offset);
+
+ fimage->fpgadata = bitdata + offset;
+}
+
+static int gs_read_image(struct fpgaimage *fimage)
+{
+ int img_fmt;
+
+ img_fmt = get_imageformat(fimage);
+
+ switch (img_fmt) {
+ case f_bit:
+ pr_info("image is bitstream format\n");
+ gs_read_bitstream(fimage);
+ break;
+ default:
+ pr_err("unsupported fpga image format\n");
+ return -1;
+ }
+
+ gs_print_header(fimage);
+
+ return 0;
+}
+
+static int gs_load_image(struct fpgaimage *fimage, char *file)
+{
+ int err;
+
+ pr_info("load fpgaimage %s\n", file);
+
+ err = request_firmware(&fimage->fw_entry, file, &firmware_pdev->dev);
+ if (err != 0) {
+ pr_err("firmware %s is missing, cannot continue.\n", file);
+ return err;
+ }
+
+ return 0;
+}
+
+static int gs_download_image(struct fpgaimage *fimage, enum wbus bus_bytes)
+{
+ char *bitdata;
+ int size, i, cnt;
+ cnt = 0;
+
+ bitdata = (char *)fimage->fpgadata;
+ size = fimage->lendata;
+
+#ifdef DEBUG_FPGA
+ datadump("bitfile sample", bitdata, 0x100);
+#endif /* DEBUG_FPGA */
+
+ if (!xl_supported_prog_bus_width(bus_bytes)) {
+ pr_err("unsupported program bus width %d\n",
+ bus_bytes);
+ return -1;
+ }
+
+ /* Bring csi_b, rdwr_b Low and program_b High */
+ xl_program_b(1);
+ xl_rdwr_b(0);
+ xl_csi_b(0);
+
+ /* Configuration reset */
+ xl_program_b(0);
+ msleep(20);
+ xl_program_b(1);
+
+ /* Wait for Device Initialization */
+ while (xl_get_init_b() == 0)
+ ;
+
+ pr_info("device init done\n");
+
+ for (i = 0; i < size; i += bus_bytes)
+ xl_shift_bytes_out(bus_bytes, bitdata+i);
+
+ pr_info("program done\n");
+
+ /* Check INIT_B */
+ if (xl_get_init_b() == 0) {
+ pr_err("init_b 0\n");
+ return -1;
+ }
+
+ while (xl_get_done_b() == 0) {
+ if (cnt++ > MAX_WAIT_DONE) {
+ pr_err("init_B %d\n", xl_get_init_b());
+ break;
+ }
+ }
+
+ if (cnt > MAX_WAIT_DONE) {
+ pr_err("fpga download fail\n");
+ return -1;
+ }
+
+ pr_info("download fpgaimage\n");
+
+ /* Compensate for Special Startup Conditions */
+ xl_shift_cclk(8);
+
+ return 0;
+}
+
+static int gs_release_image(struct fpgaimage *fimage)
+{
+ release_firmware(fimage->fw_entry);
+ pr_info("release fpgaimage\n");
+
+ return 0;
+}
+
+/*
+ * NOTE: supports systemmap parallel programming
+ */
+static int gs_set_download_method(struct fpgaimage *fimage)
+{
+ pr_info("set program method\n");
+
+ fimage->dmethod = m_systemmap;
+
+ pr_info("systemmap program method\n");
+
+ return 0;
+}
+
+static int init_driver(void)
+{
+ firmware_pdev = platform_device_register_simple("fpgaboot", -1,
+ NULL, 0);
+ return PTR_ERR_OR_ZERO(firmware_pdev);
+}
+
+static void finish_driver(void)
+{
+ platform_device_unregister(firmware_pdev);
+}
+
+static int gs_fpgaboot(void)
+{
+ int err;
+ struct fpgaimage *fimage;
+
+ fimage = kmalloc(sizeof(struct fpgaimage), GFP_KERNEL);
+ if (fimage == NULL) {
+ pr_err("No memory is available\n");
+ goto err_out;
+ }
+
+ err = gs_load_image(fimage, file);
+ if (err) {
+ pr_err("gs_load_image error\n");
+ goto err_out1;
+ }
+
+ err = gs_read_image(fimage);
+ if (err) {
+ pr_err("gs_read_image error\n");
+ goto err_out2;
+ }
+
+ err = gs_set_download_method(fimage);
+ if (err) {
+ pr_err("gs_set_download_method error\n");
+ goto err_out2;
+ }
+
+ err = gs_download_image(fimage, bus_2byte);
+ if (err) {
+ pr_err("gs_download_image error\n");
+ goto err_out2;
+ }
+
+ err = gs_release_image(fimage);
+ if (err) {
+ pr_err("gs_release_image error\n");
+ goto err_out1;
+ }
+
+ kfree(fimage);
+ return 0;
+
+err_out2:
+ err = gs_release_image(fimage);
+ if (err)
+ pr_err("gs_release_image error\n");
+err_out1:
+ kfree(fimage);
+
+err_out:
+ return -1;
+
+}
+
+static int __init gs_fpgaboot_init(void)
+{
+ int err, r;
+
+ r = -1;
+
+ pr_info("FPGA DOWNLOAD --->\n");
+ pr_info("built at %s UTC\n", __TIMESTAMP__);
+
+ pr_info("FPGA image file name: %s\n", file);
+
+ err = init_driver();
+ if (err != 0) {
+ pr_err("FPGA DRIVER INIT FAIL!!\n");
+ return r;
+ }
+
+ err = xl_init_io();
+ if (err) {
+ pr_err("GPIO INIT FAIL!!\n");
+ r = -1;
+ goto errout;
+ }
+
+ err = gs_fpgaboot();
+ if (err) {
+ pr_err("FPGA DOWNLOAD FAIL!!\n");
+ r = -1;
+ goto errout;
+ }
+
+ pr_info("FPGA DOWNLOAD DONE <---\n");
+
+ r = 0;
+ return r;
+
+errout:
+ finish_driver();
+
+ return r;
+}
+
+static void __exit gs_fpgaboot_exit(void)
+{
+ finish_driver();
+ pr_info("FPGA image download module removed\n");
+}
+
+module_init(gs_fpgaboot_init);
+module_exit(gs_fpgaboot_exit);
+
+MODULE_AUTHOR("Insop Song");
+MODULE_DESCRIPTION("Xlinix FPGA firmware download");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.h b/drivers/staging/gs_fpgaboot/gs_fpgaboot.h
new file mode 100644
index 000000000000..f41f4cc798cc
--- /dev/null
+++ b/drivers/staging/gs_fpgaboot/gs_fpgaboot.h
@@ -0,0 +1,56 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/firmware.h>
+
+#define MAX_STR 256
+
+enum fmt_image {
+ f_bit, /* only bitstream is supported */
+ f_rbt,
+ f_bin,
+ f_mcs,
+ f_hex,
+};
+
+enum mdownload {
+ m_systemmap, /* only system map is supported */
+ m_serial,
+ m_jtag,
+};
+
+/*
+ * xilinx fpgaimage information
+ * NOTE: use MAX_STR instead of dynamic alloc for simplicity
+ */
+struct fpgaimage {
+ enum fmt_image fmt_img;
+ enum mdownload dmethod;
+
+ const struct firmware *fw_entry;
+
+ /*
+ * the followings can be read from bitstream,
+ * but other image format should have as well
+ */
+ char filename[MAX_STR];
+ char part[MAX_STR];
+ char date[MAX_STR];
+ char time[MAX_STR];
+ int32_t lendata;
+ char *fpgadata;
+};
diff --git a/drivers/staging/gs_fpgaboot/io.c b/drivers/staging/gs_fpgaboot/io.c
new file mode 100644
index 000000000000..b7be8e37b8d1
--- /dev/null
+++ b/drivers/staging/gs_fpgaboot/io.c
@@ -0,0 +1,294 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+
+#include "io.h"
+
+#ifdef CONFIG_B4860G100
+static struct gpiobus gbus;
+#endif /* CONFIG_B4860G100 */
+
+static inline void byte0_out(unsigned char data);
+static inline void byte1_out(unsigned char data);
+static inline void xl_cclk_b(int32_t i);
+
+
+/* Assert and Deassert CCLK */
+void xl_shift_cclk(int count)
+{
+ int i;
+ for (i = 0; i < count; i++) {
+ xl_cclk_b(1);
+ xl_cclk_b(0);
+ }
+}
+
+int xl_supported_prog_bus_width(enum wbus bus_bytes)
+{
+ switch (bus_bytes) {
+ case bus_1byte:
+ break;
+ case bus_2byte:
+ break;
+ default:
+ pr_err("unsupported program bus width %d\n",
+ bus_bytes);
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Serialize byte and clock each bit on target's DIN and CCLK pins */
+void xl_shift_bytes_out(enum wbus bus_byte, unsigned char *pdata)
+{
+ /*
+ * supports 1 and 2 bytes programming mode
+ */
+ if (likely(bus_byte == bus_2byte))
+ byte0_out(pdata[0]);
+
+ byte1_out(pdata[1]);
+ xl_shift_cclk(1);
+}
+
+/*
+ * generic bit swap for xilinx SYSTEMMAP FPGA programming
+ */
+static inline unsigned char bitswap(unsigned char s)
+{
+ unsigned char d;
+ d = (((s&0x80)>>7) | ((s&0x40)>>5) | ((s&0x20)>>3) | ((s&0x10)>>1) |
+ ((s&0x08)<<1) | ((s&0x04)<<3) | ((s&0x02)<<5) | ((s&0x01)<<7));
+ return d;
+}
+
+#ifdef CONFIG_B4860G100
+/*
+ * ======================================================================
+ * board specific configuration
+ */
+
+static inline void mpc85xx_gpio_set_dir(
+ int32_t port,
+ uint32_t mask,
+ uint32_t dir)
+{
+ dir |= (in_be32(gbus.r[port]+GPDIR) & ~mask);
+ out_be32(gbus.r[port]+GPDIR, dir);
+}
+
+static inline void mpc85xx_gpio_set(int32_t port, uint32_t mask, uint32_t val)
+{
+ /* First mask off the unwanted parts of "dir" and "val" */
+ val &= mask;
+
+ /* Now read in the values we're supposed to preserve */
+ val |= (in_be32(gbus.r[port]+GPDAT) & ~mask);
+
+ out_be32(gbus.r[port]+GPDAT, val);
+}
+
+static inline uint32_t mpc85xx_gpio_get(int32_t port, uint32_t mask)
+{
+ /* Read the requested values */
+ return in_be32(gbus.r[port]+GPDAT) & mask;
+}
+
+static inline void mpc85xx_gpio_set_low(int32_t port, uint32_t gpios)
+{
+ mpc85xx_gpio_set(port, gpios, 0x00000000);
+}
+
+static inline void mpc85xx_gpio_set_high(int32_t port, uint32_t gpios)
+{
+ mpc85xx_gpio_set(port, gpios, 0xFFFFFFFF);
+}
+
+static inline void gpio_set_value(int32_t port, uint32_t gpio, uint32_t value)
+{
+ int32_t g;
+ g = 31 - gpio;
+ if (value)
+ mpc85xx_gpio_set_high(port, 1U << g);
+ else
+ mpc85xx_gpio_set_low(port, 1U << g);
+}
+
+static inline int gpio_get_value(int32_t port, uint32_t gpio)
+{
+ int32_t g;
+ g = 31 - gpio;
+ return !!mpc85xx_gpio_get(port, 1U << g);
+}
+
+static inline void xl_cclk_b(int32_t i)
+{
+ gpio_set_value(XL_CCLK_PORT, XL_CCLK_PIN, i);
+}
+
+void xl_program_b(int32_t i)
+{
+ gpio_set_value(XL_PROGN_PORT, XL_PROGN_PIN, i);
+}
+
+void xl_rdwr_b(int32_t i)
+{
+ gpio_set_value(XL_RDWRN_PORT, XL_RDWRN_PIN, i);
+}
+
+void xl_csi_b(int32_t i)
+{
+ gpio_set_value(XL_CSIN_PORT, XL_CSIN_PIN, i);
+}
+
+int xl_get_init_b(void)
+{
+ return gpio_get_value(XL_INITN_PORT, XL_INITN_PIN);
+}
+
+int xl_get_done_b(void)
+{
+ return gpio_get_value(XL_DONE_PORT, XL_DONE_PIN);
+}
+
+
+/* G100 specific bit swap and remmap (to gpio pins) for byte 0 */
+static inline uint32_t bit_remap_byte0(uint32_t s)
+{
+ uint32_t d;
+ d = (((s&0x80)>>7) | ((s&0x40)>>5) | ((s&0x20)>>3) | ((s&0x10)>>1) |
+ ((s&0x08)<<1) | ((s&0x04)<<3) | ((s&0x02)<<6) | ((s&0x01)<<9));
+ return d;
+}
+
+/*
+ * G100 specific MSB, in this order [byte0 | byte1], out
+ */
+static inline void byte0_out(unsigned char data)
+{
+ uint32_t swap32;
+ swap32 = bit_remap_byte0((uint32_t) data) << 8;
+
+ mpc85xx_gpio_set(0, 0x0002BF00, (uint32_t) swap32);
+}
+
+/*
+ * G100 specific LSB, in this order [byte0 | byte1], out
+ */
+static inline void byte1_out(unsigned char data)
+{
+ mpc85xx_gpio_set(0, 0x000000FF, (uint32_t) bitswap(data));
+}
+
+/*
+ * configurable per device type for different I/O config
+ */
+int xl_init_io(void)
+{
+ struct device_node *np;
+ const u32 *p_reg;
+ int reg, cnt;
+
+ cnt = 0;
+ memset(&gbus, 0, sizeof(struct gpiobus));
+ for_each_compatible_node(np, NULL, "fsl,qoriq-gpio") {
+ p_reg = of_get_property(np, "reg", NULL);
+ if (p_reg == NULL)
+ break;
+ reg = (int) *p_reg;
+ gbus.r[cnt] = of_iomap(np, 0);
+
+ if (!gbus.r[cnt]) {
+ pr_err("not findding gpio cell-index %d\n", cnt);
+ return -ENODEV;
+ }
+ cnt++;
+ }
+ mpc85xx_gpio_set_dir(0, 0x0002BFFF, 0x0002BFFF);
+ mpc85xx_gpio_set_dir(1, 0x00240060, 0x00240060);
+
+ gbus.ngpio = cnt;
+
+ return 0;
+}
+
+
+#else /* placeholder for boards with different config */
+
+void xl_program_b(int32_t i)
+{
+ return;
+}
+
+void xl_rdwr_b(int32_t i)
+{
+ return;
+}
+
+void xl_csi_b(int32_t i)
+{
+ return;
+}
+
+int xl_get_init_b(void)
+{
+ return -1;
+}
+
+int xl_get_done_b(void)
+{
+ return -1;
+}
+
+static inline void byte0_out(unsigned char data)
+{
+ return;
+}
+
+static inline void byte1_out(unsigned char data)
+{
+ return;
+}
+
+static inline void xl_cclk_b(int32_t i)
+{
+ return;
+}
+
+/*
+ * configurable per device type for different I/O config
+ */
+int xl_init_io(void)
+{
+ return -1;
+}
+
+#endif /* CONFIG_B4860G100 */
diff --git a/drivers/staging/gs_fpgaboot/io.h b/drivers/staging/gs_fpgaboot/io.h
new file mode 100644
index 000000000000..7b46ac24b74e
--- /dev/null
+++ b/drivers/staging/gs_fpgaboot/io.h
@@ -0,0 +1,90 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define GPDIR 0
+#define GPCFG 4 /* open drain or not */
+#define GPDAT 8
+
+/*
+ * gpio port and pin definitions
+ * NOTE: port number starts from 0
+ */
+#define XL_INITN_PORT 1
+#define XL_INITN_PIN 14
+#define XL_RDWRN_PORT 1
+#define XL_RDWRN_PIN 13
+#define XL_CCLK_PORT 1
+#define XL_CCLK_PIN 10
+#define XL_PROGN_PORT 1
+#define XL_PROGN_PIN 25
+#define XL_CSIN_PORT 1
+#define XL_CSIN_PIN 26
+#define XL_DONE_PORT 1
+#define XL_DONE_PIN 27
+
+/*
+ * gpio mapping
+ *
+ XL_config_D0 – gpio1_31
+ Xl_config_d1 – gpio1_30
+ Xl_config_d2 – gpio1_29
+ Xl_config_d3 – gpio1_28
+ Xl_config_d4 – gpio1_27
+ Xl_config_d5 – gpio1_26
+ Xl_config_d6 – gpio1_25
+ Xl_config_d7 – gpio1_24
+ Xl_config_d8 – gpio1_23
+ Xl_config_d9 – gpio1_22
+ Xl_config_d10 – gpio1_21
+ Xl_config_d11 – gpio1_20
+ Xl_config_d12 – gpio1_19
+ Xl_config_d13 – gpio1_18
+ Xl_config_d14 – gpio1_16
+ Xl_config_d15 – gpio1_14
+*
+*/
+
+/*
+ * program bus width in bytes
+ */
+enum wbus {
+ bus_1byte = 1,
+ bus_2byte = 2,
+};
+
+
+#define MAX_WAIT_DONE 10000
+
+
+struct gpiobus {
+ int ngpio;
+ void __iomem *r[4];
+};
+
+int xl_supported_prog_bus_width(enum wbus bus_bytes);
+
+void xl_program_b(int32_t i);
+void xl_rdwr_b(int32_t i);
+void xl_csi_b(int32_t i);
+
+int xl_get_init_b(void);
+int xl_get_done_b(void);
+
+void xl_shift_cclk(int count);
+void xl_shift_bytes_out(enum wbus bus_byte, unsigned char *pdata);
+
+int xl_init_io(void);
diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h
index c9fedb79e3a2..2064839ef2cd 100644
--- a/drivers/staging/iio/Documentation/iio_utils.h
+++ b/drivers/staging/iio/Documentation/iio_utils.h
@@ -652,3 +652,25 @@ error_free:
free(temp);
return ret;
}
+
+read_sysfs_string(const char *filename, const char *basedir, char *str)
+{
+ float ret = 0;
+ FILE *sysfsfp;
+ char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
+ if (temp == NULL) {
+ printf("Memory allocation failed");
+ return -ENOMEM;
+ }
+ sprintf(temp, "%s/%s", basedir, filename);
+ sysfsfp = fopen(temp, "r");
+ if (sysfsfp == NULL) {
+ ret = -errno;
+ goto error_free;
+ }
+ fscanf(sysfsfp, "%s\n", str);
+ fclose(sysfsfp);
+error_free:
+ free(temp);
+ return ret;
+}
diff --git a/drivers/staging/iio/Documentation/lsiio.c b/drivers/staging/iio/Documentation/lsiio.c
new file mode 100644
index 000000000000..24ae9694eb41
--- /dev/null
+++ b/drivers/staging/iio/Documentation/lsiio.c
@@ -0,0 +1,157 @@
+/*
+ * Industrial I/O utilities - lsiio.c
+ *
+ * Copyright (c) 2010 Manuel Stahl <manuel.stahl@iis.fraunhofer.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 <string.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/dir.h>
+#include "iio_utils.h"
+
+
+static enum verbosity {
+ VERBLEVEL_DEFAULT, /* 0 gives lspci behaviour */
+ VERBLEVEL_SENSORS, /* 1 lists sensors */
+} verblevel = VERBLEVEL_DEFAULT;
+
+const char *type_device = "iio:device";
+const char *type_trigger = "trigger";
+
+
+static inline int check_prefix(const char *str, const char *prefix)
+{
+ return strlen(str) > strlen(prefix) &&
+ strncmp(str, prefix, strlen(prefix)) == 0;
+}
+
+static inline int check_postfix(const char *str, const char *postfix)
+{
+ return strlen(str) > strlen(postfix) &&
+ strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
+}
+
+static int dump_channels(const char *dev_dir_name)
+{
+ DIR *dp;
+ const struct dirent *ent;
+ dp = opendir(dev_dir_name);
+ if (dp == NULL)
+ return -errno;
+ while (ent = readdir(dp), ent != NULL)
+ if (check_prefix(ent->d_name, "in_") &&
+ check_postfix(ent->d_name, "_raw")) {
+ printf(" %-10s\n", ent->d_name);
+ }
+
+ return 0;
+}
+
+static int dump_one_device(const char *dev_dir_name)
+{
+ char name[IIO_MAX_NAME_LENGTH];
+ int dev_idx;
+
+ sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_device),
+ "%i", &dev_idx);
+ read_sysfs_string("name", dev_dir_name, name);
+ printf("Device %03d: %s\n", dev_idx, name);
+
+ if (verblevel >= VERBLEVEL_SENSORS) {
+ int ret = dump_channels(dev_dir_name);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int dump_one_trigger(const char *dev_dir_name)
+{
+ char name[IIO_MAX_NAME_LENGTH];
+ int dev_idx;
+
+ sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_trigger),
+ "%i", &dev_idx);
+ read_sysfs_string("name", dev_dir_name, name);
+ printf("Trigger %03d: %s\n", dev_idx, name);
+ return 0;
+}
+
+static void dump_devices(void)
+{
+ const struct dirent *ent;
+ int number, numstrlen;
+
+ FILE *nameFile;
+ DIR *dp;
+ char thisname[IIO_MAX_NAME_LENGTH];
+ char *filename;
+
+ dp = opendir(iio_dir);
+ if (dp == NULL) {
+ printf("No industrial I/O devices available\n");
+ return;
+ }
+
+ while (ent = readdir(dp), ent != NULL) {
+ if (check_prefix(ent->d_name, type_device)) {
+ char *dev_dir_name;
+ asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name);
+ dump_one_device(dev_dir_name);
+ free(dev_dir_name);
+ if (verblevel >= VERBLEVEL_SENSORS)
+ printf("\n");
+ }
+ }
+ rewinddir(dp);
+ while (ent = readdir(dp), ent != NULL) {
+ if (check_prefix(ent->d_name, type_trigger)) {
+ char *dev_dir_name;
+ asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name);
+ dump_one_trigger(dev_dir_name);
+ free(dev_dir_name);
+ }
+ }
+ closedir(dp);
+}
+
+int main(int argc, char **argv)
+{
+ int c, err = 0;
+
+ while ((c = getopt(argc, argv, "d:D:v")) != EOF) {
+ switch (c) {
+ case 'v':
+ verblevel++;
+ break;
+
+ case '?':
+ default:
+ err++;
+ break;
+ }
+ }
+ if (err || argc > optind) {
+ fprintf(stderr, "Usage: lsiio [options]...\n"
+ "List industrial I/O devices\n"
+ " -v, --verbose\n"
+ " Increase verbosity (may be given multiple times)\n"
+ );
+ exit(1);
+ }
+
+ dump_devices();
+
+ return 0;
+}
diff --git a/drivers/staging/iio/accel/sca3000.h b/drivers/staging/iio/accel/sca3000.h
index c1016c510dae..b284e5a6cac1 100644
--- a/drivers/staging/iio/accel/sca3000.h
+++ b/drivers/staging/iio/accel/sca3000.h
@@ -65,7 +65,8 @@
#define SCA3000_RING_BUF_ENABLE 0x80
#define SCA3000_RING_BUF_8BIT 0x40
-/* Free fall detection triggers an interrupt if the acceleration
+/*
+ * Free fall detection triggers an interrupt if the acceleration
* is below a threshold for equivalent of 25cm drop
*/
#define SCA3000_FREE_FALL_DETECT 0x10
@@ -73,8 +74,9 @@
#define SCA3000_MEAS_MODE_OP_1 0x01
#define SCA3000_MEAS_MODE_OP_2 0x02
-/* In motion detection mode the accelerations are band pass filtered
- * (aprox 1 - 25Hz) and then a programmable threshold used to trigger
+/*
+ * In motion detection mode the accelerations are band pass filtered
+ * (approx 1 - 25Hz) and then a programmable threshold used to trigger
* and interrupt.
*/
#define SCA3000_MEAS_MODE_MOT_DET 0x03
@@ -99,8 +101,10 @@
#define SCA3000_REG_CTRL_SEL_MD_Y_TH 0x03
#define SCA3000_REG_CTRL_SEL_MD_X_TH 0x04
#define SCA3000_REG_CTRL_SEL_MD_Z_TH 0x05
-/* BE VERY CAREFUL WITH THIS, IF 3 BITS ARE NOT SET the device
- will not function */
+/*
+ * BE VERY CAREFUL WITH THIS, IF 3 BITS ARE NOT SET the device
+ * will not function
+ */
#define SCA3000_REG_CTRL_SEL_OUT_CTRL 0x0B
#define SCA3000_OUT_CTRL_PROT_MASK 0xE0
#define SCA3000_OUT_CTRL_BUF_X_EN 0x10
@@ -109,8 +113,9 @@
#define SCA3000_OUT_CTRL_BUF_DIV_4 0x02
#define SCA3000_OUT_CTRL_BUF_DIV_2 0x01
-/* Control which motion detector interrupts are on.
- * For now only OR combinations are supported.x
+/*
+ * Control which motion detector interrupts are on.
+ * For now only OR combinations are supported.
*/
#define SCA3000_MD_CTRL_PROT_MASK 0xC0
#define SCA3000_MD_CTRL_OR_Y 0x01
@@ -121,7 +126,8 @@
#define SCA3000_MD_CTRL_AND_X 0x10
#define SAC3000_MD_CTRL_AND_Z 0x20
-/* Some control registers of complex access methods requiring this register to
+/*
+ * Some control registers of complex access methods requiring this register to
* be used to remove a lock.
*/
#define SCA3000_REG_ADDR_UNLOCK 0x1e
@@ -139,7 +145,8 @@
/* Values of multiplexed registers (write to ctrl_data after select) */
#define SCA3000_REG_ADDR_CTRL_DATA 0x22
-/* Measurement modes available on some sca3000 series chips. Code assumes others
+/*
+ * Measurement modes available on some sca3000 series chips. Code assumes others
* may become available in the future.
*
* Bypass - Bypass the low-pass filter in the signal channel so as to increase
@@ -160,7 +167,6 @@
* struct sca3000_state - device instance state information
* @us: the associated spi device
* @info: chip variant information
- * @indio_dev: device information used by the IIO core
* @interrupt_handler_ws: event interrupt handler for all events
* @last_timestamp: the timestamp of the last event
* @mo_det_use_count: reference counter for the motion detection unit
diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c
index 7f6ccdfaf168..ed30e32e60de 100644
--- a/drivers/staging/iio/accel/sca3000_core.c
+++ b/drivers/staging/iio/accel/sca3000_core.c
@@ -32,7 +32,8 @@ enum sca3000_variant {
e05,
};
-/* Note where option modes are not defined, the chip simply does not
+/*
+ * Note where option modes are not defined, the chip simply does not
* support any.
* Other chips in the sca3000 series use i2c and are not included here.
*
@@ -191,7 +192,6 @@ error_ret:
return ret;
}
-/* Crucial that lock is called before calling this */
/**
* sca3000_read_ctrl_reg() read from lock protected control register.
*
@@ -250,9 +250,8 @@ error_ret:
}
#endif /* SCA3000_DEBUG */
-
/**
- * sca3000_show_reg() - sysfs interface to read the chip revision number
+ * sca3000_show_rev() - sysfs interface to read the chip revision number
**/
static ssize_t sca3000_show_rev(struct device *dev,
struct device_attribute *attr,
@@ -312,7 +311,7 @@ sca3000_show_available_measurement_modes(struct device *dev,
}
/**
- * sca3000_show_measurmenet_mode() sysfs read of current mode
+ * sca3000_show_measurement_mode() sysfs read of current mode
**/
static ssize_t
sca3000_show_measurement_mode(struct device *dev,
@@ -403,7 +402,8 @@ error_ret:
}
-/* Not even vaguely standard attributes so defined here rather than
+/*
+ * Not even vaguely standard attributes so defined here rather than
* in the relevant IIO core headers
*/
static IIO_DEVICE_ATTR(measurement_mode_available, S_IRUGO,
@@ -450,6 +450,18 @@ static const struct iio_chan_spec sca3000_channels[] = {
SCA3000_CHAN(2, IIO_MOD_Z),
};
+static const struct iio_chan_spec sca3000_channels_with_temp[] = {
+ SCA3000_CHAN(0, IIO_MOD_X),
+ SCA3000_CHAN(1, IIO_MOD_Y),
+ SCA3000_CHAN(2, IIO_MOD_Z),
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ },
+};
+
static u8 sca3000_addresses[3][3] = {
[0] = {SCA3000_REG_ADDR_X_MSB, SCA3000_REG_CTRL_SEL_MD_X_TH,
SCA3000_MD_CTRL_OR_X},
@@ -472,19 +484,30 @@ static int sca3000_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&st->lock);
- if (st->mo_det_use_count) {
- mutex_unlock(&st->lock);
- return -EBUSY;
- }
- address = sca3000_addresses[chan->address][0];
- ret = sca3000_read_data_short(st, address, 2);
- if (ret < 0) {
- mutex_unlock(&st->lock);
- return ret;
+ if (chan->type == IIO_ACCEL) {
+ if (st->mo_det_use_count) {
+ mutex_unlock(&st->lock);
+ return -EBUSY;
+ }
+ address = sca3000_addresses[chan->address][0];
+ ret = sca3000_read_data_short(st, address, 2);
+ if (ret < 0) {
+ mutex_unlock(&st->lock);
+ return ret;
+ }
+ *val = (be16_to_cpup((__be16 *)st->rx) >> 3) & 0x1FFF;
+ *val = ((*val) << (sizeof(*val)*8 - 13)) >>
+ (sizeof(*val)*8 - 13);
+ } else {
+ /* get the temperature when available */
+ ret = sca3000_read_data_short(st,
+ SCA3000_REG_ADDR_TEMP_MSB, 2);
+ if (ret < 0) {
+ mutex_unlock(&st->lock);
+ return ret;
+ }
+ *val = ((st->rx[0] & 0x3F) << 3) | ((st->rx[1] & 0xE0) >> 5);
}
- *val = (be16_to_cpup((__be16 *)st->rx) >> 3) & 0x1FFF;
- *val = ((*val) << (sizeof(*val)*8 - 13)) >>
- (sizeof(*val)*8 - 13);
mutex_unlock(&st->lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
@@ -494,6 +517,10 @@ static int sca3000_read_raw(struct iio_dev *indio_dev,
else /* temperature */
*val2 = 555556;
return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = -214;
+ *val2 = 600000;
+ return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
@@ -547,7 +574,7 @@ error_ret:
return ret;
}
/**
- * __sca3000_get_base_frequency() obtain mode specific base frequency
+ * __sca3000_get_base_freq() obtain mode specific base frequency
*
* lock must be held
**/
@@ -663,7 +690,8 @@ error_free_lock:
return ret ? ret : len;
}
-/* Should only really be registered if ring buffer support is compiled in.
+/*
+ * Should only really be registered if ring buffer support is compiled in.
* Does no harm however and doing it right would add a fair bit of complexity
*/
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sca3000_read_av_freq);
@@ -672,37 +700,6 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
sca3000_read_frequency,
sca3000_set_frequency);
-
-/**
- * sca3000_read_temp() sysfs interface to get the temperature when available
- *
-* The alignment of data in here is downright odd. See data sheet.
-* Converting this into a meaningful value is left to inline functions in
-* userspace part of header.
-**/
-static ssize_t sca3000_read_temp(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct sca3000_state *st = iio_priv(indio_dev);
- int ret;
- int val;
- ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_TEMP_MSB, 2);
- if (ret < 0)
- goto error_ret;
- val = ((st->rx[0] & 0x3F) << 3) | ((st->rx[1] & 0xE0) >> 5);
-
- return sprintf(buf, "%d\n", val);
-
-error_ret:
- return ret;
-}
-static IIO_DEV_ATTR_TEMP_RAW(sca3000_read_temp);
-
-static IIO_CONST_ATTR_TEMP_SCALE("0.555556");
-static IIO_CONST_ATTR_TEMP_OFFSET("-214.6");
-
/**
* sca3000_read_thresh() - query of a threshold
**/
@@ -782,33 +779,16 @@ static struct attribute *sca3000_attributes[] = {
NULL,
};
-static struct attribute *sca3000_attributes_with_temp[] = {
- &iio_dev_attr_revision.dev_attr.attr,
- &iio_dev_attr_measurement_mode_available.dev_attr.attr,
- &iio_dev_attr_measurement_mode.dev_attr.attr,
- &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
- &iio_dev_attr_sampling_frequency.dev_attr.attr,
- /* Only present if temp sensor is */
- &iio_dev_attr_in_temp_raw.dev_attr.attr,
- &iio_const_attr_in_temp_offset.dev_attr.attr,
- &iio_const_attr_in_temp_scale.dev_attr.attr,
- NULL,
-};
-
static const struct attribute_group sca3000_attribute_group = {
.attrs = sca3000_attributes,
};
-static const struct attribute_group sca3000_attribute_group_with_temp = {
- .attrs = sca3000_attributes_with_temp,
-};
-
-/* RING RELATED interrupt handler */
-/* depending on event, push to the ring buffer event chrdev or the event one */
-
/**
* sca3000_event_handler() - handling ring and non ring events
*
+ * Ring related interrupt handler. Depending on event, push to
+ * the ring buffer event chrdev or the event one.
+ *
* This function is complicated by the fact that the devices can signify ring
* and non ring events via the same interrupt line and they can only
* be distinguished via a read of the relevant status register.
@@ -820,7 +800,8 @@ static irqreturn_t sca3000_event_handler(int irq, void *private)
int ret, val;
s64 last_timestamp = iio_get_time_ns();
- /* Could lead if badly timed to an extra read of status reg,
+ /*
+ * Could lead if badly timed to an extra read of status reg,
* but ensures no interrupt is missed.
*/
mutex_lock(&st->lock);
@@ -935,7 +916,6 @@ static ssize_t sca3000_query_free_fall_mode(struct device *dev,
* the device falls more than 25cm. This has not been tested due
* to fragile wiring.
**/
-
static ssize_t sca3000_set_free_fall_mode(struct device *dev,
struct device_attribute *attr,
const char *buf,
@@ -957,7 +937,7 @@ static ssize_t sca3000_set_free_fall_mode(struct device *dev,
if (ret)
goto error_ret;
- /*if off and should be on*/
+ /* if off and should be on */
if (val && !(st->rx[0] & protect_mask))
ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE,
(st->rx[0] | SCA3000_FREE_FALL_DETECT));
@@ -972,7 +952,7 @@ error_ret:
}
/**
- * sca3000_set_mo_det() simple on off control for motion detector
+ * sca3000_write_event_config() simple on off control for motion detector
*
* This is a per axis control, but enabling any will result in the
* motion detector unit being enabled.
@@ -992,13 +972,15 @@ static int sca3000_write_event_config(struct iio_dev *indio_dev,
int num = chan->channel2;
mutex_lock(&st->lock);
- /* First read the motion detector config to find out if
- * this axis is on*/
+ /*
+ * First read the motion detector config to find out if
+ * this axis is on
+ */
ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL);
if (ret < 0)
goto exit_point;
ctrlval = ret;
- /* Off and should be on */
+ /* if off and should be on */
if (state && !(ctrlval & sca3000_addresses[num][2])) {
ret = sca3000_write_ctrl_reg(st,
SCA3000_REG_CTRL_SEL_MD_CTRL,
@@ -1021,7 +1003,7 @@ static int sca3000_write_event_config(struct iio_dev *indio_dev,
ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1);
if (ret)
goto exit_point;
- /*if off and should be on*/
+ /* if off and should be on */
if ((st->mo_det_use_count)
&& ((st->rx[0] & protect_mask) != SCA3000_MEAS_MODE_MOT_DET))
ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE,
@@ -1067,7 +1049,7 @@ static struct attribute_group sca3000_event_attribute_group = {
* Devices use flash memory to store many of the register values
* and hence can come up in somewhat unpredictable states.
* Hence reset everything on driver load.
- **/
+ **/
static int sca3000_clean_setup(struct sca3000_state *st)
{
int ret;
@@ -1107,9 +1089,11 @@ static int sca3000_clean_setup(struct sca3000_state *st)
| SCA3000_INT_MASK_ACTIVE_LOW);
if (ret)
goto error_ret;
- /* Select normal measurement mode, free fall off, ring off */
- /* Ring in 12 bit mode - it is fine to overwrite reserved bits 3,5
- * as that occurs in one of the example on the datasheet */
+ /*
+ * Select normal measurement mode, free fall off, ring off
+ * Ring in 12 bit mode - it is fine to overwrite reserved bits 3,5
+ * as that occurs in one of the example on the datasheet
+ */
ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1);
if (ret)
goto error_ret;
@@ -1133,16 +1117,6 @@ static const struct iio_info sca3000_info = {
.driver_module = THIS_MODULE,
};
-static const struct iio_info sca3000_info_with_temp = {
- .attrs = &sca3000_attribute_group_with_temp,
- .read_raw = &sca3000_read_raw,
- .read_event_value = &sca3000_read_thresh,
- .write_event_value = &sca3000_write_thresh,
- .read_event_config = &sca3000_read_event_config,
- .write_event_config = &sca3000_write_event_config,
- .driver_module = THIS_MODULE,
-};
-
static int sca3000_probe(struct spi_device *spi)
{
int ret;
@@ -1162,10 +1136,12 @@ static int sca3000_probe(struct spi_device *spi)
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
- if (st->info->temp_output)
- indio_dev->info = &sca3000_info_with_temp;
- else {
- indio_dev->info = &sca3000_info;
+ indio_dev->info = &sca3000_info;
+ if (st->info->temp_output) {
+ indio_dev->channels = sca3000_channels_with_temp;
+ indio_dev->num_channels =
+ ARRAY_SIZE(sca3000_channels_with_temp);
+ } else {
indio_dev->channels = sca3000_channels;
indio_dev->num_channels = ARRAY_SIZE(sca3000_channels);
}
@@ -1236,7 +1212,7 @@ static int sca3000_remove(struct spi_device *spi)
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct sca3000_state *st = iio_priv(indio_dev);
- /* Must ensure no interrupts can be generated after this!*/
+ /* Must ensure no interrupts can be generated after this! */
sca3000_stop_all_interrupts(st);
if (spi->irq)
free_irq(spi->irq, indio_dev);
diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c
index ea0af6d81d2b..198710651e0e 100644
--- a/drivers/staging/iio/accel/sca3000_ring.c
+++ b/drivers/staging/iio/accel/sca3000_ring.c
@@ -309,7 +309,7 @@ int __sca3000_hw_ring_state_set(struct iio_dev *indio_dev, bool state)
if (ret)
goto error_ret;
if (state) {
- printk(KERN_INFO "supposedly enabling ring buffer\n");
+ dev_info(&indio_dev->dev, "supposedly enabling ring buffer\n");
ret = sca3000_write_reg(st,
SCA3000_REG_ADDR_MODE,
(st->rx[0] | SCA3000_RING_BUF_ENABLE));
diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h
index a591aa6feae1..fc8c85298feb 100644
--- a/drivers/staging/iio/adc/ad799x.h
+++ b/drivers/staging/iio/adc/ad799x.h
@@ -95,7 +95,7 @@ struct ad799x_state {
struct i2c_client *client;
const struct ad799x_chip_info *chip_info;
struct regulator *reg;
- u16 int_vref_mv;
+ struct regulator *vref;
unsigned id;
u16 config;
@@ -103,14 +103,6 @@ struct ad799x_state {
unsigned int transfer_size;
};
-/*
- * TODO: struct ad799x_platform_data needs to go into include/linux/iio
- */
-
-struct ad799x_platform_data {
- u16 vref_mv;
-};
-
#ifdef CONFIG_AD799X_RING_BUFFER
int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev);
void ad799x_ring_cleanup(struct iio_dev *indio_dev);
diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c
index 5708ffc62aec..979ec77d6c2d 100644
--- a/drivers/staging/iio/adc/ad799x_core.c
+++ b/drivers/staging/iio/adc/ad799x_core.c
@@ -1,6 +1,6 @@
/*
* iio/adc/ad799x.c
- * Copyright (C) 2010-1011 Michael Hennerich, Analog Devices Inc.
+ * Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc.
*
* based on iio/adc/max1363
* Copyright (C) 2008-2010 Jonathan Cameron
@@ -179,7 +179,10 @@ static int ad799x_read_raw(struct iio_dev *indio_dev,
RES_MASK(chan->scan_type.realbits);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- *val = st->int_vref_mv;
+ ret = regulator_get_voltage(st->vref);
+ if (ret < 0)
+ return ret;
+ *val = ret / 1000;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
@@ -533,7 +536,6 @@ static int ad799x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
- struct ad799x_platform_data *pdata = client->dev.platform_data;
struct ad799x_state *st;
struct iio_dev *indio_dev;
@@ -551,17 +553,21 @@ static int ad799x_probe(struct i2c_client *client,
/* TODO: Add pdata options for filtering and bit delay */
- if (!pdata)
- return -EINVAL;
-
- st->int_vref_mv = pdata->vref_mv;
-
st->reg = devm_regulator_get(&client->dev, "vcc");
- if (!IS_ERR(st->reg)) {
- ret = regulator_enable(st->reg);
- if (ret)
- return ret;
+ if (IS_ERR(st->reg))
+ return PTR_ERR(st->reg);
+ ret = regulator_enable(st->reg);
+ if (ret)
+ return ret;
+ st->vref = devm_regulator_get(&client->dev, "vref");
+ if (IS_ERR(st->vref)) {
+ ret = PTR_ERR(st->vref);
+ goto error_disable_reg;
}
+ ret = regulator_enable(st->vref);
+ if (ret)
+ goto error_disable_reg;
+
st->client = client;
indio_dev->dev.parent = &client->dev;
@@ -577,28 +583,28 @@ static int ad799x_probe(struct i2c_client *client,
goto error_disable_reg;
if (client->irq > 0) {
- ret = request_threaded_irq(client->irq,
- NULL,
- ad799x_event_handler,
- IRQF_TRIGGER_FALLING |
- IRQF_ONESHOT,
- client->name,
- indio_dev);
+ ret = devm_request_threaded_irq(&client->dev,
+ client->irq,
+ NULL,
+ ad799x_event_handler,
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ client->name,
+ indio_dev);
if (ret)
goto error_cleanup_ring;
}
ret = iio_device_register(indio_dev);
if (ret)
- goto error_free_irq;
+ goto error_cleanup_ring;
return 0;
-error_free_irq:
- if (client->irq > 0)
- free_irq(client->irq, indio_dev);
error_cleanup_ring:
ad799x_ring_cleanup(indio_dev);
error_disable_reg:
+ if (!IS_ERR(st->vref))
+ regulator_disable(st->vref);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
@@ -611,10 +617,10 @@ static int ad799x_remove(struct i2c_client *client)
struct ad799x_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
- if (client->irq > 0)
- free_irq(client->irq, indio_dev);
ad799x_ring_cleanup(indio_dev);
+ if (!IS_ERR(st->vref))
+ regulator_disable(st->vref);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
kfree(st->rx_buf);
diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c
index 7fc66a6a6e36..11fb95201545 100644
--- a/drivers/staging/iio/adc/mxs-lradc.c
+++ b/drivers/staging/iio/adc/mxs-lradc.c
@@ -757,6 +757,7 @@ static void mxs_lradc_finish_touch_event(struct mxs_lradc *lradc, bool valid)
}
/* if it is released, wait for the next touch via IRQ */
+ lradc->cur_plate = LRADC_TOUCH;
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1);
mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
}
@@ -846,7 +847,8 @@ static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val)
mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0);
/* Clean the slot's previous content, then set new one. */
- mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(0), LRADC_CTRL4);
+ mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(0),
+ LRADC_CTRL4);
mxs_lradc_reg_set(lradc, chan, LRADC_CTRL4);
mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(0));
@@ -897,10 +899,6 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev,
{
struct mxs_lradc *lradc = iio_priv(iio_dev);
- /* Check for invalid channel */
- if (chan->channel > LRADC_MAX_TOTAL_CHANS)
- return -EINVAL;
-
switch (m) {
case IIO_CHAN_INFO_RAW:
if (chan->type == IIO_TEMP)
@@ -1172,7 +1170,8 @@ static irqreturn_t mxs_lradc_handle_irq(int irq, void *data)
else if (reg & LRADC_CTRL1_LRADC_IRQ(0))
complete(&lradc->completion);
- mxs_lradc_reg_clear(lradc, reg & mxs_lradc_irq_mask(lradc), LRADC_CTRL1);
+ mxs_lradc_reg_clear(lradc, reg & mxs_lradc_irq_mask(lradc),
+ LRADC_CTRL1);
return IRQ_HANDLED;
}
@@ -1263,7 +1262,8 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio)
uint32_t ctrl1_irq = 0;
const uint32_t chan_value = LRADC_CH_ACCUMULATE |
((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
- const int len = bitmap_weight(iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS);
+ const int len = bitmap_weight(iio->active_scan_mask,
+ LRADC_MAX_TOTAL_CHANS);
if (!len)
return -EINVAL;
@@ -1562,7 +1562,7 @@ static int mxs_lradc_probe(struct platform_device *pdev)
for (i = 0; i < of_cfg->irq_count; i++) {
lradc->irq[i] = platform_get_irq(pdev, i);
if (lradc->irq[i] < 0)
- return -EINVAL;
+ return lradc->irq[i];
ret = devm_request_irq(dev, lradc->irq[i],
mxs_lradc_handle_irq, 0,
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index 16a8201228ff..9f0ebb329008 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -859,11 +859,14 @@ static ssize_t adt7316_show_DAC_update_mode(struct device *dev,
else {
switch (chip->dac_config & ADT7316_DA_EN_MODE_MASK) {
case ADT7316_DA_EN_MODE_SINGLE:
- return sprintf(buf, "0 - auto at any MSB DAC writing\n");
+ return sprintf(buf,
+ "0 - auto at any MSB DAC writing\n");
case ADT7316_DA_EN_MODE_AB_CD:
- return sprintf(buf, "1 - auto at MSB DAC AB and CD writing\n");
+ return sprintf(buf,
+ "1 - auto at MSB DAC AB and CD writing\n");
case ADT7316_DA_EN_MODE_ABCD:
- return sprintf(buf, "2 - auto at MSB DAC ABCD writing\n");
+ return sprintf(buf,
+ "2 - auto at MSB DAC ABCD writing\n");
default: /* ADT7316_DA_EN_MODE_LDAC */
return sprintf(buf, "3 - manual\n");
}
@@ -1102,7 +1105,8 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev,
ldac_config = chip->ldac_config | ADT7316_DAC_IN_VREF;
}
- ret = chip->bus.write(chip->bus.client, ADT7316_LDAC_CONFIG, ldac_config);
+ ret = chip->bus.write(chip->bus.client, ADT7316_LDAC_CONFIG,
+ ldac_config);
if (ret)
return -EIO;
@@ -1224,7 +1228,8 @@ static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev,
return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_EX, buf);
}
-static IIO_DEVICE_ATTR(ex_temp_AIN1, S_IRUGO, adt7316_show_ex_temp_AIN1, NULL, 0);
+static IIO_DEVICE_ATTR(ex_temp_AIN1, S_IRUGO, adt7316_show_ex_temp_AIN1,
+ NULL, 0);
static IIO_DEVICE_ATTR(ex_temp, S_IRUGO, adt7316_show_ex_temp_AIN1, NULL, 0);
static ssize_t adt7316_show_AIN2(struct device *dev,
@@ -1319,7 +1324,8 @@ static ssize_t adt7316_store_in_temp_offset(struct device *dev,
struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
- return adt7316_store_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf, len);
+ return adt7316_store_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf,
+ len);
}
static IIO_DEVICE_ATTR(in_temp_offset, S_IRUGO | S_IWUSR,
@@ -1344,7 +1350,8 @@ static ssize_t adt7316_store_ex_temp_offset(struct device *dev,
struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
- return adt7316_store_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf, len);
+ return adt7316_store_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf,
+ len);
}
static IIO_DEVICE_ATTR(ex_temp_offset, S_IRUGO | S_IWUSR,
diff --git a/drivers/staging/iio/addac/adt7316.h b/drivers/staging/iio/addac/adt7316.h
index 2dbfb499528d..ec50bf34628d 100644
--- a/drivers/staging/iio/addac/adt7316.h
+++ b/drivers/staging/iio/addac/adt7316.h
@@ -18,10 +18,10 @@ struct adt7316_bus {
void *client;
int irq;
int irq_flags;
- int (*read) (void *client, u8 reg, u8 *data);
- int (*write) (void *client, u8 reg, u8 val);
- int (*multi_read) (void *client, u8 first_reg, u8 count, u8 *data);
- int (*multi_write) (void *client, u8 first_reg, u8 count, u8 *data);
+ int (*read)(void *client, u8 reg, u8 *data);
+ int (*write)(void *client, u8 reg, u8 val);
+ int (*multi_read)(void *client, u8 first_reg, u8 count, u8 *data);
+ int (*multi_write)(void *client, u8 first_reg, u8 count, u8 *data);
};
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c
index f8c659568c38..0a60def92735 100644
--- a/drivers/staging/iio/light/tsl2583.c
+++ b/drivers/staging/iio/light/tsl2583.c
@@ -433,7 +433,7 @@ static int taos_chip_on(struct iio_dev *indio_dev)
TSL258X_CMD_REG | TSL258X_CNTRL, utmp);
if (ret < 0) {
dev_err(&chip->client->dev, "taos_chip_on failed on CNTRL reg.\n");
- return -1;
+ return ret;
}
/* Use the following shadow copy for our delay before enabling ADC.
@@ -445,7 +445,7 @@ static int taos_chip_on(struct iio_dev *indio_dev)
if (ret < 0) {
dev_err(&chip->client->dev,
"taos_chip_on failed on reg %d.\n", i);
- return -1;
+ return ret;
}
}
@@ -458,7 +458,7 @@ static int taos_chip_on(struct iio_dev *indio_dev)
utmp);
if (ret < 0) {
dev_err(&chip->client->dev, "taos_chip_on failed on 2nd CTRL reg.\n");
- return -1;
+ return ret;
}
chip->taos_chip_status = TSL258X_CHIP_WORKING;
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
index 1e538086d48b..9e0f2a9c73ae 100644
--- a/drivers/staging/iio/light/tsl2x7x_core.c
+++ b/drivers/staging/iio/light/tsl2x7x_core.c
@@ -352,7 +352,7 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
/* device is not enabled */
dev_err(&chip->client->dev, "%s: device is not enabled\n",
__func__);
- ret = -EBUSY ;
+ ret = -EBUSY;
goto out_unlock;
}
@@ -1507,16 +1507,16 @@ static int tsl2x7x_device_id(unsigned char *id, int target)
case tsl2571:
case tsl2671:
case tsl2771:
- return ((*id & 0xf0) == TRITON_ID);
+ return (*id & 0xf0) == TRITON_ID;
case tmd2671:
case tmd2771:
- return ((*id & 0xf0) == HALIBUT_ID);
+ return (*id & 0xf0) == HALIBUT_ID;
case tsl2572:
case tsl2672:
case tmd2672:
case tsl2772:
case tmd2772:
- return ((*id & 0xf0) == SWORDFISH_ID);
+ return (*id & 0xf0) == SWORDFISH_ID;
}
return -EINVAL;
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
index 6966d5f76648..7fbaba41c872 100644
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -312,7 +312,7 @@ static ssize_t ad2s1210_store_control(struct device *dev,
if (st->pdata->gpioin) {
data = ad2s1210_read_resolution_pin(st);
if (data != st->resolution)
- pr_warning("ad2s1210: resolution settings not match\n");
+ pr_warn("ad2s1210: resolution settings not match\n");
} else
ad2s1210_set_resolution_pin(st);
@@ -372,7 +372,7 @@ static ssize_t ad2s1210_store_resolution(struct device *dev,
if (st->pdata->gpioin) {
data = ad2s1210_read_resolution_pin(st);
if (data != st->resolution)
- pr_warning("ad2s1210: resolution settings not match\n");
+ pr_warn("ad2s1210: resolution settings not match\n");
} else
ad2s1210_set_resolution_pin(st);
ret = len;
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index 78319ad176cd..c6e8ba7b3e4e 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -20,6 +20,7 @@ config DRM_IMX_FB_HELPER
config DRM_IMX_PARALLEL_DISPLAY
tristate "Support for parallel displays"
+ select DRM_PANEL
depends on DRM_IMX
select VIDEOMODE_HELPERS
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 4677585b5ad5..129e3a3f59f1 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -1,12 +1,11 @@
-imxdrm-objs := imx-drm-core.o imx-fb.o
+imxdrm-objs := imx-drm-core.o
obj-$(CONFIG_DRM_IMX) += imxdrm.o
obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
-obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o
obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o
diff --git a/drivers/staging/imx-drm/TODO b/drivers/staging/imx-drm/TODO
index 6a9da94c9573..29636fb13959 100644
--- a/drivers/staging/imx-drm/TODO
+++ b/drivers/staging/imx-drm/TODO
@@ -1,15 +1,10 @@
TODO:
- get DRM Maintainer review for this code
-- Wait for common display framework to hit mainline and update the IPU
- driver to use it. This will most probably make changes to the devicetree
- bindings necessary.
-- Factor out more code to common helper functions
- decide where to put the base driver. It is not specific to a subsystem
and would be used by DRM/KMS and media/V4L2
Missing features (not necessarily for moving out of staging):
-- Add i.MX6 HDMI support
- Add support for IC (Image converter)
- Add support for CSI (CMOS Sensor interface)
- Add support for VDIC (Video Deinterlacer)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 236ed66f116a..4144a75e5f71 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -13,14 +13,15 @@
* GNU General Public License for more details.
*
*/
-
+#include <linux/component.h>
#include <linux/device.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
-#include <linux/fb.h>
-#include <linux/module.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
@@ -28,45 +29,29 @@
#define MAX_CRTC 4
-struct crtc_cookie {
- void *cookie;
- int id;
+struct imx_drm_crtc;
+
+struct imx_drm_component {
+ struct device_node *of_node;
struct list_head list;
};
struct imx_drm_device {
struct drm_device *drm;
- struct device *dev;
- struct list_head crtc_list;
- struct list_head encoder_list;
- struct list_head connector_list;
- struct mutex mutex;
+ struct imx_drm_crtc *crtc[MAX_CRTC];
int pipes;
struct drm_fbdev_cma *fbhelper;
};
struct imx_drm_crtc {
struct drm_crtc *crtc;
- struct list_head list;
- struct imx_drm_device *imxdrm;
int pipe;
struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
- struct module *owner;
- struct crtc_cookie cookie;
-};
-
-struct imx_drm_encoder {
- struct drm_encoder *encoder;
- struct list_head list;
- struct module *owner;
- struct list_head possible_crtcs;
+ struct device_node *port;
};
-struct imx_drm_connector {
- struct drm_connector *connector;
- struct list_head list;
- struct module *owner;
-};
+static int legacyfb_depth = 16;
+module_param(legacyfb_depth, int, 0444);
int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
{
@@ -76,69 +61,71 @@ EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
static void imx_drm_driver_lastclose(struct drm_device *drm)
{
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
struct imx_drm_device *imxdrm = drm->dev_private;
if (imxdrm->fbhelper)
drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
+#endif
}
static int imx_drm_driver_unload(struct drm_device *drm)
{
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
struct imx_drm_device *imxdrm = drm->dev_private;
+#endif
- imx_drm_device_put();
+ drm_kms_helper_poll_fini(drm);
+
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+ if (imxdrm->fbhelper)
+ drm_fbdev_cma_fini(imxdrm->fbhelper);
+#endif
+
+ component_unbind_all(drm->dev, drm);
drm_vblank_cleanup(drm);
- drm_kms_helper_poll_fini(drm);
drm_mode_config_cleanup(drm);
return 0;
}
-/*
- * We don't care at all for crtc numbers, but the core expects the
- * crtcs to be numbered
- */
-static struct imx_drm_crtc *imx_drm_crtc_by_num(struct imx_drm_device *imxdrm,
- int num)
+static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
{
- struct imx_drm_crtc *imx_drm_crtc;
+ struct imx_drm_device *imxdrm = crtc->dev->dev_private;
+ unsigned i;
+
+ for (i = 0; i < MAX_CRTC; i++)
+ if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc)
+ return imxdrm->crtc[i];
- list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list)
- if (imx_drm_crtc->pipe == num)
- return imx_drm_crtc;
return NULL;
}
-int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format_pins(struct drm_encoder *encoder,
u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
{
- struct imx_drm_device *imxdrm = crtc->dev->dev_private;
- struct imx_drm_crtc *imx_crtc;
struct imx_drm_crtc_helper_funcs *helper;
+ struct imx_drm_crtc *imx_crtc;
- list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
- if (imx_crtc->crtc == crtc)
- goto found;
+ imx_crtc = imx_drm_find_crtc(encoder->crtc);
+ if (!imx_crtc)
+ return -EINVAL;
- return -EINVAL;
-found:
helper = &imx_crtc->imx_drm_helper_funcs;
if (helper->set_interface_pix_fmt)
- return helper->set_interface_pix_fmt(crtc,
- encoder_type, interface_pix_fmt,
+ return helper->set_interface_pix_fmt(encoder->crtc,
+ encoder->encoder_type, interface_pix_fmt,
hsync_pin, vsync_pin);
return 0;
}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format_pins);
+EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
-int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
- u32 interface_pix_fmt)
+int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt)
{
- return imx_drm_crtc_panel_format_pins(crtc, encoder_type,
- interface_pix_fmt, 2, 3);
+ return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3);
}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
+EXPORT_SYMBOL_GPL(imx_drm_panel_format);
int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
{
@@ -161,10 +148,9 @@ EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
{
struct imx_drm_device *imxdrm = drm->dev_private;
- struct imx_drm_crtc *imx_drm_crtc;
+ struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
int ret;
- imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
if (!imx_drm_crtc)
return -EINVAL;
@@ -180,9 +166,8 @@ static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
{
struct imx_drm_device *imxdrm = drm->dev_private;
- struct imx_drm_crtc *imx_drm_crtc;
+ struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
- imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
if (!imx_drm_crtc)
return;
@@ -215,172 +200,54 @@ static const struct file_operations imx_drm_driver_fops = {
.llseek = noop_llseek,
};
-static struct imx_drm_device *imx_drm_device;
-
-static struct imx_drm_device *__imx_drm_device(void)
+int imx_drm_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
{
- return imx_drm_device;
+ return MODE_OK;
}
+EXPORT_SYMBOL(imx_drm_connector_mode_valid);
-struct drm_device *imx_drm_device_get(void)
+void imx_drm_connector_destroy(struct drm_connector *connector)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_encoder *enc;
- struct imx_drm_connector *con;
- struct imx_drm_crtc *crtc;
-
- list_for_each_entry(enc, &imxdrm->encoder_list, list) {
- if (!try_module_get(enc->owner)) {
- dev_err(imxdrm->dev, "could not get module %s\n",
- module_name(enc->owner));
- goto unwind_enc;
- }
- }
-
- list_for_each_entry(con, &imxdrm->connector_list, list) {
- if (!try_module_get(con->owner)) {
- dev_err(imxdrm->dev, "could not get module %s\n",
- module_name(con->owner));
- goto unwind_con;
- }
- }
-
- list_for_each_entry(crtc, &imxdrm->crtc_list, list) {
- if (!try_module_get(crtc->owner)) {
- dev_err(imxdrm->dev, "could not get module %s\n",
- module_name(crtc->owner));
- goto unwind_crtc;
- }
- }
-
- return imxdrm->drm;
-
-unwind_crtc:
- list_for_each_entry_continue_reverse(crtc, &imxdrm->crtc_list, list)
- module_put(crtc->owner);
-unwind_con:
- list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list)
- module_put(con->owner);
-unwind_enc:
- list_for_each_entry_continue_reverse(enc, &imxdrm->encoder_list, list)
- module_put(enc->owner);
-
- mutex_unlock(&imxdrm->mutex);
-
- return NULL;
-
-}
-EXPORT_SYMBOL_GPL(imx_drm_device_get);
-
-void imx_drm_device_put(void)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_encoder *enc;
- struct imx_drm_connector *con;
- struct imx_drm_crtc *crtc;
-
- mutex_lock(&imxdrm->mutex);
-
- list_for_each_entry(crtc, &imxdrm->crtc_list, list)
- module_put(crtc->owner);
-
- list_for_each_entry(con, &imxdrm->connector_list, list)
- module_put(con->owner);
-
- list_for_each_entry(enc, &imxdrm->encoder_list, list)
- module_put(enc->owner);
-
- mutex_unlock(&imxdrm->mutex);
+ drm_sysfs_connector_remove(connector);
+ drm_connector_cleanup(connector);
}
-EXPORT_SYMBOL_GPL(imx_drm_device_put);
+EXPORT_SYMBOL_GPL(imx_drm_connector_destroy);
-static int drm_mode_group_reinit(struct drm_device *dev)
+void imx_drm_encoder_destroy(struct drm_encoder *encoder)
{
- struct drm_mode_group *group = &dev->primary->mode_group;
- uint32_t *id_list = group->id_list;
- int ret;
-
- ret = drm_mode_group_init_legacy_group(dev, group);
- if (ret < 0)
- return ret;
-
- kfree(id_list);
- return 0;
-}
-
-/*
- * register an encoder to the drm core
- */
-static int imx_drm_encoder_register(struct imx_drm_encoder *imx_drm_encoder)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- INIT_LIST_HEAD(&imx_drm_encoder->possible_crtcs);
-
- drm_encoder_init(imxdrm->drm, imx_drm_encoder->encoder,
- imx_drm_encoder->encoder->funcs,
- imx_drm_encoder->encoder->encoder_type);
-
- drm_mode_group_reinit(imxdrm->drm);
-
- return 0;
-}
-
-/*
- * unregister an encoder from the drm core
- */
-static void imx_drm_encoder_unregister(struct imx_drm_encoder
- *imx_drm_encoder)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- drm_encoder_cleanup(imx_drm_encoder->encoder);
-
- drm_mode_group_reinit(imxdrm->drm);
+ drm_encoder_cleanup(encoder);
}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
-/*
- * register a connector to the drm core
- */
-static int imx_drm_connector_register(
- struct imx_drm_connector *imx_drm_connector)
+static void imx_drm_output_poll_changed(struct drm_device *drm)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- drm_connector_init(imxdrm->drm, imx_drm_connector->connector,
- imx_drm_connector->connector->funcs,
- imx_drm_connector->connector->connector_type);
- drm_mode_group_reinit(imxdrm->drm);
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+ struct imx_drm_device *imxdrm = drm->dev_private;
- return drm_sysfs_connector_add(imx_drm_connector->connector);
+ drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
+#endif
}
-/*
- * unregister a connector from the drm core
- */
-static void imx_drm_connector_unregister(
- struct imx_drm_connector *imx_drm_connector)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- drm_sysfs_connector_remove(imx_drm_connector->connector);
- drm_connector_cleanup(imx_drm_connector->connector);
-
- drm_mode_group_reinit(imxdrm->drm);
-}
+static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
+ .fb_create = drm_fb_cma_create,
+ .output_poll_changed = imx_drm_output_poll_changed,
+};
/*
- * Called by the CRTC driver when all CRTCs are registered. This
- * puts all the pieces together and initializes the driver.
- * Once this is called no more CRTCs can be registered since
- * the drm core has hardcoded the number of crtcs in several
- * places.
+ * Main DRM initialisation. This binds, initialises and registers
+ * with DRM the subcomponents of the driver.
*/
static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_device *imxdrm;
+ struct drm_connector *connector;
int ret;
+ imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL);
+ if (!imxdrm)
+ return -ENOMEM;
+
imxdrm->drm = drm;
drm->dev_private = imxdrm;
@@ -396,120 +263,118 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
*/
drm->irq_enabled = true;
- drm_mode_config_init(drm);
- imx_drm_mode_config_init(drm);
-
- mutex_lock(&imxdrm->mutex);
-
- drm_kms_helper_poll_init(drm);
+ /*
+ * set max width and height as default value(4096x4096).
+ * this value would be used to check framebuffer size limitation
+ * at drm_mode_addfb().
+ */
+ drm->mode_config.min_width = 64;
+ drm->mode_config.min_height = 64;
+ drm->mode_config.max_width = 4096;
+ drm->mode_config.max_height = 4096;
+ drm->mode_config.funcs = &imx_drm_mode_config_funcs;
- /* setup the grouping for the legacy output */
- ret = drm_mode_group_init_legacy_group(drm,
- &drm->primary->mode_group);
- if (ret)
- goto err_kms;
+ drm_mode_config_init(drm);
ret = drm_vblank_init(drm, MAX_CRTC);
if (ret)
goto err_kms;
/*
- * with vblank_disable_allowed = true, vblank interrupt will be disabled
- * by drm timer once a current process gives up ownership of
- * vblank event.(after drm_vblank_put function is called)
+ * with vblank_disable_allowed = true, vblank interrupt will be
+ * disabled by drm timer once a current process gives up ownership
+ * of vblank event. (after drm_vblank_put function is called)
*/
drm->vblank_disable_allowed = true;
- if (!imx_drm_device_get()) {
- ret = -EINVAL;
+ platform_set_drvdata(drm->platformdev, drm);
+
+ /* Now try and bind all our sub-components */
+ ret = component_bind_all(drm->dev, drm);
+ if (ret)
goto err_vblank;
+
+ /*
+ * All components are now added, we can publish the connector sysfs
+ * entries to userspace. This will generate hotplug events and so
+ * userspace will expect to be able to access DRM at this point.
+ */
+ list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
+ ret = drm_sysfs_connector_add(connector);
+ if (ret) {
+ dev_err(drm->dev,
+ "[CONNECTOR:%d:%s] drm_sysfs_connector_add failed: %d\n",
+ connector->base.id,
+ drm_get_connector_name(connector), ret);
+ goto err_unbind;
+ }
}
- platform_set_drvdata(drm->platformdev, drm);
- mutex_unlock(&imxdrm->mutex);
+ /*
+ * All components are now initialised, so setup the fb helper.
+ * The fb helper takes copies of key hardware information, so the
+ * crtcs/connectors/encoders must not change after this point.
+ */
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+ if (legacyfb_depth != 16 && legacyfb_depth != 32) {
+ dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n");
+ legacyfb_depth = 16;
+ }
+ imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
+ drm->mode_config.num_crtc, MAX_CRTC);
+ if (IS_ERR(imxdrm->fbhelper)) {
+ ret = PTR_ERR(imxdrm->fbhelper);
+ imxdrm->fbhelper = NULL;
+ goto err_unbind;
+ }
+#endif
+
+ drm_kms_helper_poll_init(drm);
+
return 0;
+err_unbind:
+ component_unbind_all(drm->dev, drm);
err_vblank:
drm_vblank_cleanup(drm);
err_kms:
- drm_kms_helper_poll_fini(drm);
drm_mode_config_cleanup(drm);
- mutex_unlock(&imxdrm->mutex);
return ret;
}
-static void imx_drm_update_possible_crtcs(void)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_crtc *imx_drm_crtc;
- struct imx_drm_encoder *enc;
- struct crtc_cookie *cookie;
-
- list_for_each_entry(enc, &imxdrm->encoder_list, list) {
- u32 possible_crtcs = 0;
-
- list_for_each_entry(cookie, &enc->possible_crtcs, list) {
- list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) {
- if (imx_drm_crtc->cookie.cookie == cookie->cookie &&
- imx_drm_crtc->cookie.id == cookie->id) {
- possible_crtcs |= 1 << imx_drm_crtc->pipe;
- }
- }
- }
- enc->encoder->possible_crtcs = possible_crtcs;
- enc->encoder->possible_clones = possible_crtcs;
- }
-}
-
/*
* imx_drm_add_crtc - add a new crtc
- *
- * The return value if !NULL is a cookie for the caller to pass to
- * imx_drm_remove_crtc later.
*/
-int imx_drm_add_crtc(struct drm_crtc *crtc,
+int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
struct imx_drm_crtc **new_crtc,
const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
- struct module *owner, void *cookie, int id)
+ struct device_node *port)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_device *imxdrm = drm->dev_private;
struct imx_drm_crtc *imx_drm_crtc;
int ret;
- mutex_lock(&imxdrm->mutex);
-
/*
* The vblank arrays are dimensioned by MAX_CRTC - we can't
* pass IDs greater than this to those functions.
*/
- if (imxdrm->pipes >= MAX_CRTC) {
- ret = -EINVAL;
- goto err_busy;
- }
+ if (imxdrm->pipes >= MAX_CRTC)
+ return -EINVAL;
- if (imxdrm->drm->open_count) {
- ret = -EBUSY;
- goto err_busy;
- }
+ if (imxdrm->drm->open_count)
+ return -EBUSY;
imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
- if (!imx_drm_crtc) {
- ret = -ENOMEM;
- goto err_alloc;
- }
+ if (!imx_drm_crtc)
+ return -ENOMEM;
imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
imx_drm_crtc->pipe = imxdrm->pipes++;
- imx_drm_crtc->cookie.cookie = cookie;
- imx_drm_crtc->cookie.id = id;
-
+ imx_drm_crtc->port = port;
imx_drm_crtc->crtc = crtc;
- imx_drm_crtc->imxdrm = imxdrm;
- imx_drm_crtc->owner = owner;
-
- list_add_tail(&imx_drm_crtc->list, &imxdrm->crtc_list);
+ imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
*new_crtc = imx_drm_crtc;
@@ -520,23 +385,14 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
drm_crtc_helper_add(crtc,
imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
- drm_crtc_init(imxdrm->drm, crtc,
+ drm_crtc_init(drm, crtc,
imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
- drm_mode_group_reinit(imxdrm->drm);
-
- imx_drm_update_possible_crtcs();
-
- mutex_unlock(&imxdrm->mutex);
-
return 0;
err_register:
- list_del(&imx_drm_crtc->list);
+ imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
kfree(imx_drm_crtc);
-err_alloc:
-err_busy:
- mutex_unlock(&imxdrm->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
@@ -546,17 +402,11 @@ EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
*/
int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
{
- struct imx_drm_device *imxdrm = imx_drm_crtc->imxdrm;
-
- mutex_lock(&imxdrm->mutex);
+ struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
drm_crtc_cleanup(imx_drm_crtc->crtc);
- list_del(&imx_drm_crtc->list);
-
- drm_mode_group_reinit(imxdrm->drm);
-
- mutex_unlock(&imxdrm->mutex);
+ imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
kfree(imx_drm_crtc);
@@ -565,220 +415,115 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
/*
- * imx_drm_add_encoder - add a new encoder
+ * Find the DRM CRTC possible mask for the connected endpoint.
+ *
+ * The encoder possible masks are defined by their position in the
+ * mode_config crtc_list. This means that CRTCs must not be added
+ * or removed once the DRM device has been fully initialised.
*/
-int imx_drm_add_encoder(struct drm_encoder *encoder,
- struct imx_drm_encoder **newenc, struct module *owner)
+static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
+ struct device_node *endpoint)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_encoder *imx_drm_encoder;
- int ret;
-
- mutex_lock(&imxdrm->mutex);
+ struct device_node *port;
+ unsigned i;
- if (imxdrm->drm->open_count) {
- ret = -EBUSY;
- goto err_busy;
- }
+ port = of_graph_get_remote_port(endpoint);
+ if (!port)
+ return 0;
+ of_node_put(port);
- imx_drm_encoder = kzalloc(sizeof(*imx_drm_encoder), GFP_KERNEL);
- if (!imx_drm_encoder) {
- ret = -ENOMEM;
- goto err_alloc;
+ for (i = 0; i < MAX_CRTC; i++) {
+ struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
+ if (imx_drm_crtc && imx_drm_crtc->port == port)
+ return drm_crtc_mask(imx_drm_crtc->crtc);
}
- imx_drm_encoder->encoder = encoder;
- imx_drm_encoder->owner = owner;
-
- ret = imx_drm_encoder_register(imx_drm_encoder);
- if (ret) {
- ret = -ENOMEM;
- goto err_register;
- }
-
- list_add_tail(&imx_drm_encoder->list, &imxdrm->encoder_list);
-
- *newenc = imx_drm_encoder;
-
- mutex_unlock(&imxdrm->mutex);
-
return 0;
+}
-err_register:
- kfree(imx_drm_encoder);
-err_alloc:
-err_busy:
- mutex_unlock(&imxdrm->mutex);
-
- return ret;
+static struct device_node *imx_drm_of_get_next_endpoint(
+ const struct device_node *parent, struct device_node *prev)
+{
+ struct device_node *node = of_graph_get_next_endpoint(parent, prev);
+ of_node_put(prev);
+ return node;
}
-EXPORT_SYMBOL_GPL(imx_drm_add_encoder);
-int imx_drm_encoder_add_possible_crtcs(
- struct imx_drm_encoder *imx_drm_encoder,
- struct device_node *np)
+int imx_drm_encoder_parse_of(struct drm_device *drm,
+ struct drm_encoder *encoder, struct device_node *np)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct of_phandle_args args;
- struct crtc_cookie *c;
- int ret = 0;
+ struct imx_drm_device *imxdrm = drm->dev_private;
+ struct device_node *ep = NULL;
+ uint32_t crtc_mask = 0;
int i;
- if (!list_empty(&imx_drm_encoder->possible_crtcs))
- return -EBUSY;
+ for (i = 0; ; i++) {
+ u32 mask;
- for (i = 0; !ret; i++) {
- ret = of_parse_phandle_with_args(np, "crtcs",
- "#crtc-cells", i, &args);
- if (ret < 0)
+ ep = imx_drm_of_get_next_endpoint(np, ep);
+ if (!ep)
break;
- c = kzalloc(sizeof(*c), GFP_KERNEL);
- if (!c) {
- of_node_put(args.np);
- return -ENOMEM;
- }
-
- c->cookie = args.np;
- c->id = args.args_count > 0 ? args.args[0] : 0;
-
- of_node_put(args.np);
-
- mutex_lock(&imxdrm->mutex);
-
- list_add_tail(&c->list, &imx_drm_encoder->possible_crtcs);
-
- mutex_unlock(&imxdrm->mutex);
- }
+ mask = imx_drm_find_crtc_mask(imxdrm, ep);
- imx_drm_update_possible_crtcs();
+ /*
+ * If we failed to find the CRTC(s) which this encoder is
+ * supposed to be connected to, it's because the CRTC has
+ * not been registered yet. Defer probing, and hope that
+ * the required CRTC is added later.
+ */
+ if (mask == 0)
+ return -EPROBE_DEFER;
- return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
-
-int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
- struct drm_crtc *crtc)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_crtc *imx_crtc;
- int i = 0;
-
- list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) {
- if (imx_crtc->crtc == crtc)
- goto found;
- i++;
+ crtc_mask |= mask;
}
- return -EINVAL;
-found:
- return i;
-}
-EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
-
-/*
- * imx_drm_remove_encoder - remove an encoder
- */
-int imx_drm_remove_encoder(struct imx_drm_encoder *imx_drm_encoder)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct crtc_cookie *c, *tmp;
-
- mutex_lock(&imxdrm->mutex);
-
- imx_drm_encoder_unregister(imx_drm_encoder);
-
- list_del(&imx_drm_encoder->list);
-
- list_for_each_entry_safe(c, tmp, &imx_drm_encoder->possible_crtcs,
- list)
- kfree(c);
+ if (ep)
+ of_node_put(ep);
+ if (i == 0)
+ return -ENOENT;
- mutex_unlock(&imxdrm->mutex);
+ encoder->possible_crtcs = crtc_mask;
- kfree(imx_drm_encoder);
+ /* FIXME: this is the mask of outputs which can clone this output. */
+ encoder->possible_clones = ~0;
return 0;
}
-EXPORT_SYMBOL_GPL(imx_drm_remove_encoder);
+EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
/*
- * imx_drm_add_connector - add a connector
+ * @node: device tree node containing encoder input ports
+ * @encoder: drm_encoder
*/
-int imx_drm_add_connector(struct drm_connector *connector,
- struct imx_drm_connector **new_con,
- struct module *owner)
+int imx_drm_encoder_get_mux_id(struct device_node *node,
+ struct drm_encoder *encoder)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_connector *imx_drm_connector;
+ struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
+ struct device_node *ep = NULL;
+ struct of_endpoint endpoint;
+ struct device_node *port;
int ret;
- mutex_lock(&imxdrm->mutex);
-
- if (imxdrm->drm->open_count) {
- ret = -EBUSY;
- goto err_busy;
- }
-
- imx_drm_connector = kzalloc(sizeof(*imx_drm_connector), GFP_KERNEL);
- if (!imx_drm_connector) {
- ret = -ENOMEM;
- goto err_alloc;
- }
-
- imx_drm_connector->connector = connector;
- imx_drm_connector->owner = owner;
-
- ret = imx_drm_connector_register(imx_drm_connector);
- if (ret)
- goto err_register;
-
- list_add_tail(&imx_drm_connector->list, &imxdrm->connector_list);
-
- *new_con = imx_drm_connector;
-
- mutex_unlock(&imxdrm->mutex);
-
- return 0;
-
-err_register:
- kfree(imx_drm_connector);
-err_alloc:
-err_busy:
- mutex_unlock(&imxdrm->mutex);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(imx_drm_add_connector);
-
-void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- imxdrm->fbhelper = fbdev_helper;
-}
-EXPORT_SYMBOL_GPL(imx_drm_fb_helper_set);
-
-/*
- * imx_drm_remove_connector - remove a connector
- */
-int imx_drm_remove_connector(struct imx_drm_connector *imx_drm_connector)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- mutex_lock(&imxdrm->mutex);
-
- imx_drm_connector_unregister(imx_drm_connector);
-
- list_del(&imx_drm_connector->list);
+ if (!node || !imx_crtc)
+ return -EINVAL;
- mutex_unlock(&imxdrm->mutex);
+ do {
+ ep = imx_drm_of_get_next_endpoint(node, ep);
+ if (!ep)
+ break;
- kfree(imx_drm_connector);
+ port = of_graph_get_remote_port(ep);
+ of_node_put(port);
+ if (port == imx_crtc->port) {
+ ret = of_graph_parse_endpoint(ep, &endpoint);
+ return ret ? ret : endpoint.id;
+ }
+ } while (ep);
- return 0;
+ return -EINVAL;
}
-EXPORT_SYMBOL_GPL(imx_drm_remove_connector);
+EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
static const struct drm_ioctl_desc imx_drm_ioctls[] = {
/* none so far */
@@ -819,80 +564,156 @@ static struct drm_driver imx_drm_driver = {
.patchlevel = 0,
};
-static int imx_drm_platform_probe(struct platform_device *pdev)
+static int compare_of(struct device *dev, void *data)
{
- int ret;
+ struct device_node *np = data;
- ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (ret)
- return ret;
-
- imx_drm_device->dev = &pdev->dev;
+ /* Special case for LDB, one device for two channels */
+ if (of_node_cmp(np->name, "lvds-channel") == 0) {
+ np = of_get_parent(np);
+ of_node_put(np);
+ }
- return drm_platform_init(&imx_drm_driver, pdev);
+ return dev->of_node == np;
}
-static int imx_drm_platform_remove(struct platform_device *pdev)
+static LIST_HEAD(imx_drm_components);
+
+static int imx_drm_add_components(struct device *master, struct master *m)
{
- drm_put_dev(platform_get_drvdata(pdev));
+ struct imx_drm_component *component;
+ int ret;
+ list_for_each_entry(component, &imx_drm_components, list) {
+ ret = component_master_add_child(m, compare_of,
+ component->of_node);
+ if (ret)
+ return ret;
+ }
return 0;
}
-static struct platform_driver imx_drm_pdrv = {
- .probe = imx_drm_platform_probe,
- .remove = imx_drm_platform_remove,
- .driver = {
- .owner = THIS_MODULE,
- .name = "imx-drm",
- },
+static int imx_drm_bind(struct device *dev)
+{
+ return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
+}
+
+static void imx_drm_unbind(struct device *dev)
+{
+ drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops imx_drm_ops = {
+ .add_components = imx_drm_add_components,
+ .bind = imx_drm_bind,
+ .unbind = imx_drm_unbind,
};
-static struct platform_device *imx_drm_pdev;
+static struct imx_drm_component *imx_drm_find_component(struct device *dev,
+ struct device_node *node)
+{
+ struct imx_drm_component *component;
+
+ list_for_each_entry(component, &imx_drm_components, list)
+ if (component->of_node == node)
+ return component;
-static int __init imx_drm_init(void)
+ return NULL;
+}
+
+static int imx_drm_add_component(struct device *dev, struct device_node *node)
{
- int ret;
+ struct imx_drm_component *component;
+
+ if (imx_drm_find_component(dev, node))
+ return 0;
- imx_drm_device = kzalloc(sizeof(*imx_drm_device), GFP_KERNEL);
- if (!imx_drm_device)
+ component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
+ if (!component)
return -ENOMEM;
- mutex_init(&imx_drm_device->mutex);
- INIT_LIST_HEAD(&imx_drm_device->crtc_list);
- INIT_LIST_HEAD(&imx_drm_device->connector_list);
- INIT_LIST_HEAD(&imx_drm_device->encoder_list);
+ component->of_node = node;
+ list_add_tail(&component->list, &imx_drm_components);
+
+ return 0;
+}
+
+static int imx_drm_platform_probe(struct platform_device *pdev)
+{
+ struct device_node *ep, *port, *remote;
+ int ret;
+ int i;
+
+ /*
+ * Bind the IPU display interface ports first, so that
+ * imx_drm_encoder_parse_of called from encoder .bind callbacks
+ * works as expected.
+ */
+ for (i = 0; ; i++) {
+ port = of_parse_phandle(pdev->dev.of_node, "ports", i);
+ if (!port)
+ break;
+
+ ret = imx_drm_add_component(&pdev->dev, port);
+ if (ret < 0)
+ return ret;
+ }
- imx_drm_pdev = platform_device_register_simple("imx-drm", -1, NULL, 0);
- if (IS_ERR(imx_drm_pdev)) {
- ret = PTR_ERR(imx_drm_pdev);
- goto err_pdev;
+ if (i == 0) {
+ dev_err(&pdev->dev, "missing 'ports' property\n");
+ return -ENODEV;
}
- ret = platform_driver_register(&imx_drm_pdrv);
- if (ret)
- goto err_pdrv;
+ /* Then bind all encoders */
+ for (i = 0; ; i++) {
+ port = of_parse_phandle(pdev->dev.of_node, "ports", i);
+ if (!port)
+ break;
- return 0;
+ for_each_child_of_node(port, ep) {
+ remote = of_graph_get_remote_port_parent(ep);
+ if (!remote || !of_device_is_available(remote)) {
+ of_node_put(remote);
+ continue;
+ }
-err_pdrv:
- platform_device_unregister(imx_drm_pdev);
-err_pdev:
- kfree(imx_drm_device);
+ ret = imx_drm_add_component(&pdev->dev, remote);
+ of_node_put(remote);
+ if (ret < 0)
+ return ret;
+ }
+ of_node_put(port);
+ }
- return ret;
+ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ return component_master_add(&pdev->dev, &imx_drm_ops);
}
-static void __exit imx_drm_exit(void)
+static int imx_drm_platform_remove(struct platform_device *pdev)
{
- platform_device_unregister(imx_drm_pdev);
- platform_driver_unregister(&imx_drm_pdrv);
-
- kfree(imx_drm_device);
+ component_master_del(&pdev->dev, &imx_drm_ops);
+ return 0;
}
-module_init(imx_drm_init);
-module_exit(imx_drm_exit);
+static const struct of_device_id imx_drm_dt_ids[] = {
+ { .compatible = "fsl,imx-display-subsystem", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);
+
+static struct platform_driver imx_drm_pdrv = {
+ .probe = imx_drm_platform_probe,
+ .remove = imx_drm_platform_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "imx-drm",
+ .of_match_table = imx_drm_dt_ids,
+ },
+};
+module_platform_driver(imx_drm_pdrv);
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
MODULE_DESCRIPTION("i.MX drm driver core");
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index ae90c9c15312..a322bac55414 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -1,17 +1,15 @@
#ifndef _IMX_DRM_H_
#define _IMX_DRM_H_
-#include <linux/videodev2.h>
-
-#define IPU_PIX_FMT_GBR24 v4l2_fourcc('G', 'B', 'R', '3')
-
+struct device_node;
struct drm_crtc;
struct drm_connector;
struct drm_device;
+struct drm_display_mode;
struct drm_encoder;
-struct imx_drm_crtc;
struct drm_fbdev_cma;
struct drm_framebuffer;
+struct imx_drm_crtc;
struct platform_device;
int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
@@ -25,10 +23,10 @@ struct imx_drm_crtc_helper_funcs {
const struct drm_crtc_funcs *crtc_funcs;
};
-int imx_drm_add_crtc(struct drm_crtc *crtc,
+int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
struct imx_drm_crtc **new_crtc,
const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
- struct module *owner, void *cookie, int id);
+ struct device_node *port);
int imx_drm_remove_crtc(struct imx_drm_crtc *);
int imx_drm_init_drm(struct platform_device *pdev,
int preferred_bpp);
@@ -38,35 +36,23 @@ int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc);
void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc);
void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc);
-struct imx_drm_encoder;
-int imx_drm_add_encoder(struct drm_encoder *encoder,
- struct imx_drm_encoder **new_enc,
- struct module *owner);
-int imx_drm_remove_encoder(struct imx_drm_encoder *);
-
-struct imx_drm_connector;
-int imx_drm_add_connector(struct drm_connector *connector,
- struct imx_drm_connector **new_con,
- struct module *owner);
-int imx_drm_remove_connector(struct imx_drm_connector *);
-
void imx_drm_mode_config_init(struct drm_device *drm);
struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
-struct drm_device *imx_drm_device_get(void);
-void imx_drm_device_put(void);
-int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format_pins(struct drm_encoder *encoder,
u32 interface_pix_fmt, int hsync_pin, int vsync_pin);
-int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format(struct drm_encoder *encoder,
u32 interface_pix_fmt);
-void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
-struct device_node;
+int imx_drm_encoder_get_mux_id(struct device_node *node,
+ struct drm_encoder *encoder);
+int imx_drm_encoder_parse_of(struct drm_device *drm,
+ struct drm_encoder *encoder, struct device_node *np);
-int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
- struct drm_crtc *crtc);
-int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
- struct device_node *np);
+int imx_drm_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+void imx_drm_connector_destroy(struct drm_connector *connector);
+void imx_drm_encoder_destroy(struct drm_encoder *encoder);
#endif /* _IMX_DRM_H_ */
diff --git a/drivers/staging/imx-drm/imx-fb.c b/drivers/staging/imx-drm/imx-fb.c
deleted file mode 100644
index 03a7b4e14f67..000000000000
--- a/drivers/staging/imx-drm/imx-fb.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * i.MX drm driver
- *
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * Based on Samsung Exynos code
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * 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 <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "imx-drm.h"
-
-static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
- .fb_create = drm_fb_cma_create,
-};
-
-void imx_drm_mode_config_init(struct drm_device *dev)
-{
- dev->mode_config.min_width = 64;
- dev->mode_config.min_height = 64;
-
- /*
- * set max width and height as default value(4096x4096).
- * this value would be used to check framebuffer size limitation
- * at drm_mode_addfb().
- */
- dev->mode_config.max_width = 4096;
- dev->mode_config.max_height = 4096;
-
- dev->mode_config.funcs = &imx_drm_mode_config_funcs;
-}
diff --git a/drivers/staging/imx-drm/imx-fbdev.c b/drivers/staging/imx-drm/imx-fbdev.c
deleted file mode 100644
index 8331739c3d08..000000000000
--- a/drivers/staging/imx-drm/imx-fbdev.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * i.MX drm driver
- *
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * Based on Samsung Exynos code
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * 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 <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "imx-drm.h"
-
-#define MAX_CONNECTOR 4
-#define PREFERRED_BPP 16
-
-static struct drm_fbdev_cma *fbdev_cma;
-
-static int legacyfb_depth = 16;
-
-module_param(legacyfb_depth, int, 0444);
-
-static int __init imx_fb_helper_init(void)
-{
- struct drm_device *drm = imx_drm_device_get();
-
- if (!drm)
- return -EINVAL;
-
- if (legacyfb_depth != 16 && legacyfb_depth != 32) {
- pr_warn("i.MX legacyfb: invalid legacyfb_depth setting. defaulting to 16bpp\n");
- legacyfb_depth = 16;
- }
-
- fbdev_cma = drm_fbdev_cma_init(drm, legacyfb_depth,
- drm->mode_config.num_crtc, MAX_CONNECTOR);
-
- if (IS_ERR(fbdev_cma)) {
- imx_drm_device_put();
- return PTR_ERR(fbdev_cma);
- }
-
- imx_drm_fb_helper_set(fbdev_cma);
-
- return 0;
-}
-
-static void __exit imx_fb_helper_exit(void)
-{
- imx_drm_fb_helper_set(NULL);
- drm_fbdev_cma_fini(fbdev_cma);
- imx_drm_device_put();
-}
-
-late_initcall(imx_fb_helper_init);
-module_exit(imx_fb_helper_exit);
-
-MODULE_DESCRIPTION("Freescale i.MX legacy fb driver");
-MODULE_AUTHOR("Sascha Hauer, Pengutronix");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 62ce0e86f14b..d47dedd2cdb4 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -12,6 +12,7 @@
* Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*/
+#include <linux/component.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -112,15 +113,15 @@ struct hdmi_data_info {
struct imx_hdmi {
struct drm_connector connector;
- struct imx_drm_connector *imx_drm_connector;
struct drm_encoder encoder;
- struct imx_drm_encoder *imx_drm_encoder;
enum imx_hdmi_devtype dev_type;
struct device *dev;
struct clk *isfr_clk;
struct clk *iahb_clk;
+ enum drm_connector_status connector_status;
+
struct hdmi_data_info hdmi_data;
int vic;
@@ -134,7 +135,6 @@ struct imx_hdmi {
struct i2c_adapter *ddc;
void __iomem *regs;
- unsigned long pixel_clk_rate;
unsigned int sample_rate;
int ratio;
};
@@ -156,37 +156,34 @@ static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
return readb(hdmi->regs + offset);
}
+static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+{
+ u8 val = hdmi_readb(hdmi, reg) & ~mask;
+ val |= data & mask;
+ hdmi_writeb(hdmi, val, reg);
+}
+
static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
u8 shift, u8 mask)
{
- u8 value = hdmi_readb(hdmi, reg) & ~mask;
- value |= (data << shift) & mask;
- hdmi_writeb(hdmi, value, reg);
+ hdmi_modb(hdmi, data << shift, mask, reg);
}
static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
unsigned int value)
{
- u8 val;
-
hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
/* nshift factor = 0 */
- val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
- val &= ~HDMI_AUD_CTS3_N_SHIFT_MASK;
- hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+ hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
}
static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
{
- u8 val;
-
/* Must be set/cleared first */
- val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
- val &= ~HDMI_AUD_CTS3_CTS_MANUAL;
- hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+ hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
@@ -331,34 +328,25 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
return (cts * ratio) / 100;
}
-static void hdmi_get_pixel_clk(struct imx_hdmi *hdmi)
-{
- unsigned long rate;
-
- rate = 65000000; /* FIXME */
-
- if (rate)
- hdmi->pixel_clk_rate = rate;
-}
-
-static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi)
+static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
+ unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;
- clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
+ clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk,
hdmi->ratio);
- clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
+ clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk,
hdmi->ratio);
if (!clk_cts) {
dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
- __func__, hdmi->pixel_clk_rate);
+ __func__, pixel_clk);
return;
}
dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n",
__func__, hdmi->sample_rate, hdmi->ratio,
- hdmi->pixel_clk_rate, clk_n, clk_cts);
+ pixel_clk, clk_n, clk_cts);
hdmi_set_clock_regenerator_n(hdmi, clk_n);
hdmi_regenerate_cts(hdmi, clk_cts);
@@ -366,32 +354,12 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi)
static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
{
- unsigned int clk_n, clk_cts;
-
- clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
- hdmi->ratio);
- clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
- hdmi->ratio);
-
- if (!clk_cts) {
- dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
- __func__, hdmi->pixel_clk_rate);
- return;
- }
-
- dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n",
- __func__, hdmi->sample_rate, hdmi->ratio,
- hdmi->pixel_clk_rate, clk_n, clk_cts);
-
- hdmi_set_clock_regenerator_n(hdmi, clk_n);
- hdmi_regenerate_cts(hdmi, clk_cts);
+ hdmi_set_clk_regenerator(hdmi, 74250000);
}
static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
{
- /* Get pixel clock from ipu */
- hdmi_get_pixel_clk(hdmi);
- hdmi_set_clk_regenerator(hdmi);
+ hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
}
/*
@@ -459,38 +427,45 @@ static void hdmi_video_sample(struct imx_hdmi *hdmi)
static int is_color_space_conversion(struct imx_hdmi *hdmi)
{
- return (hdmi->hdmi_data.enc_in_format !=
- hdmi->hdmi_data.enc_out_format);
+ return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
}
static int is_color_space_decimation(struct imx_hdmi *hdmi)
{
- return ((hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS) &&
- (hdmi->hdmi_data.enc_in_format == RGB ||
- hdmi->hdmi_data.enc_in_format == YCBCR444));
+ if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
+ return 0;
+ if (hdmi->hdmi_data.enc_in_format == RGB ||
+ hdmi->hdmi_data.enc_in_format == YCBCR444)
+ return 1;
+ return 0;
}
static int is_color_space_interpolation(struct imx_hdmi *hdmi)
{
- return ((hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) &&
- (hdmi->hdmi_data.enc_out_format == RGB ||
- hdmi->hdmi_data.enc_out_format == YCBCR444));
+ if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
+ return 0;
+ if (hdmi->hdmi_data.enc_out_format == RGB ||
+ hdmi->hdmi_data.enc_out_format == YCBCR444)
+ return 1;
+ return 0;
}
static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
{
const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
+ unsigned i;
u32 csc_scale = 1;
- u8 val;
if (is_color_space_conversion(hdmi)) {
if (hdmi->hdmi_data.enc_out_format == RGB) {
- if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
+ if (hdmi->hdmi_data.colorimetry ==
+ HDMI_COLORIMETRY_ITU_601)
csc_coeff = &csc_coeff_rgb_out_eitu601;
else
csc_coeff = &csc_coeff_rgb_out_eitu709;
} else if (hdmi->hdmi_data.enc_in_format == RGB) {
- if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
+ if (hdmi->hdmi_data.colorimetry ==
+ HDMI_COLORIMETRY_ITU_601)
csc_coeff = &csc_coeff_rgb_in_eitu601;
else
csc_coeff = &csc_coeff_rgb_in_eitu709;
@@ -498,37 +473,24 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
}
}
- hdmi_writeb(hdmi, ((*csc_coeff)[0][0] & 0xff), HDMI_CSC_COEF_A1_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][0] >> 8), HDMI_CSC_COEF_A1_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][1] & 0xff), HDMI_CSC_COEF_A2_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][1] >> 8), HDMI_CSC_COEF_A2_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][2] & 0xff), HDMI_CSC_COEF_A3_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][2] >> 8), HDMI_CSC_COEF_A3_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][3] & 0xff), HDMI_CSC_COEF_A4_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][3] >> 8), HDMI_CSC_COEF_A4_MSB);
-
- hdmi_writeb(hdmi, ((*csc_coeff)[1][0] & 0xff), HDMI_CSC_COEF_B1_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][0] >> 8), HDMI_CSC_COEF_B1_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][1] & 0xff), HDMI_CSC_COEF_B2_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][1] >> 8), HDMI_CSC_COEF_B2_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][2] & 0xff), HDMI_CSC_COEF_B3_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][2] >> 8), HDMI_CSC_COEF_B3_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][3] & 0xff), HDMI_CSC_COEF_B4_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][3] >> 8), HDMI_CSC_COEF_B4_MSB);
-
- hdmi_writeb(hdmi, ((*csc_coeff)[2][0] & 0xff), HDMI_CSC_COEF_C1_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][0] >> 8), HDMI_CSC_COEF_C1_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][1] & 0xff), HDMI_CSC_COEF_C2_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][1] >> 8), HDMI_CSC_COEF_C2_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][2] & 0xff), HDMI_CSC_COEF_C3_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][2] >> 8), HDMI_CSC_COEF_C3_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][3] & 0xff), HDMI_CSC_COEF_C4_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][3] >> 8), HDMI_CSC_COEF_C4_MSB);
-
- val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
- val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK;
- val |= csc_scale & HDMI_CSC_SCALE_CSCSCALE_MASK;
- hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+ /* The CSC registers are sequential, alternating MSB then LSB */
+ for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
+ u16 coeff_a = (*csc_coeff)[0][i];
+ u16 coeff_b = (*csc_coeff)[1][i];
+ u16 coeff_c = (*csc_coeff)[2][i];
+
+ hdmi_writeb(hdmi, coeff_a & 0xff,
+ HDMI_CSC_COEF_A1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
+ hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
+ hdmi_writeb(hdmi, coeff_c & 0xff,
+ HDMI_CSC_COEF_C1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
+ }
+
+ hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
+ HDMI_CSC_SCALE);
}
static void hdmi_video_csc(struct imx_hdmi *hdmi)
@@ -536,7 +498,6 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
int color_depth = 0;
int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
int decimation = 0;
- u8 val;
/* YCC422 interpolation to 444 mode */
if (is_color_space_interpolation(hdmi))
@@ -557,10 +518,8 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
/* Configure the CSC registers */
hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
- val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
- val &= ~HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK;
- val |= color_depth;
- hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+ hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
+ HDMI_CSC_SCALE);
imx_hdmi_update_csc_coeffs(hdmi);
}
@@ -576,7 +535,7 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
- u8 val;
+ u8 val, vp_conf;
if (hdmi_data->enc_out_format == RGB
|| hdmi_data->enc_out_format == YCBCR444) {
@@ -615,107 +574,75 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
- val = hdmi_readb(hdmi, HDMI_VP_STUFF);
- val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK;
- val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE;
- hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+ hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
+ HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
/* Data from pixel repeater block */
if (hdmi_data->pix_repet_factor > 1) {
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_PR_EN_MASK |
- HDMI_VP_CONF_BYPASS_SELECT_MASK);
- val |= HDMI_VP_CONF_PR_EN_ENABLE |
- HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_PR_EN_ENABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
} else { /* data from packetizer block */
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_PR_EN_MASK |
- HDMI_VP_CONF_BYPASS_SELECT_MASK);
- val |= HDMI_VP_CONF_PR_EN_DISABLE |
- HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
}
- val = hdmi_readb(hdmi, HDMI_VP_STUFF);
- val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK;
- val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET;
- hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+ hdmi_modb(hdmi, vp_conf,
+ HDMI_VP_CONF_PR_EN_MASK |
+ HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+
+ hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
+ HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK);
- val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
- HDMI_VP_CONF_PP_EN_ENABLE |
- HDMI_VP_CONF_YCC422_EN_DISABLE;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_ENABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK);
- val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
- HDMI_VP_CONF_PP_EN_DISABLE |
- HDMI_VP_CONF_YCC422_EN_ENABLE;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_ENABLE;
} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK);
- val |= HDMI_VP_CONF_BYPASS_EN_ENABLE |
- HDMI_VP_CONF_PP_EN_DISABLE |
- HDMI_VP_CONF_YCC422_EN_DISABLE;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
} else {
return;
}
- val = hdmi_readb(hdmi, HDMI_VP_STUFF);
- val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK |
- HDMI_VP_STUFF_YCC422_STUFFING_MASK);
- val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
- HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE;
- hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+ hdmi_modb(hdmi, vp_conf,
+ HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK;
- val |= output_select;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+ HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
+ HDMI_VP_STUFF_PP_STUFFING_MASK |
+ HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF);
+
+ hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
+ HDMI_VP_CONF);
}
static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
unsigned char bit)
{
- u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
- val &= ~HDMI_PHY_TST0_TSTCLR_MASK;
- val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) &
- HDMI_PHY_TST0_TSTCLR_MASK;
- hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+ hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
+ HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
unsigned char bit)
{
- u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
- val &= ~HDMI_PHY_TST0_TSTEN_MASK;
- val |= (bit << HDMI_PHY_TST0_TSTEN_OFFSET) &
- HDMI_PHY_TST0_TSTEN_MASK;
- hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+ hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
+ HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
unsigned char bit)
{
- u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
- val &= ~HDMI_PHY_TST0_TSTCLK_MASK;
- val |= (bit << HDMI_PHY_TST0_TSTCLK_OFFSET) &
- HDMI_PHY_TST0_TSTCLK_MASK;
- hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+ hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
+ HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
@@ -806,19 +733,94 @@ static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
+enum {
+ RES_8,
+ RES_10,
+ RES_12,
+ RES_MAX,
+};
+
+struct mpll_config {
+ unsigned long mpixelclock;
+ struct {
+ u16 cpce;
+ u16 gmp;
+ } res[RES_MAX];
+};
+
+static const struct mpll_config mpll_config[] = {
+ {
+ 45250000, {
+ { 0x01e0, 0x0000 },
+ { 0x21e1, 0x0000 },
+ { 0x41e2, 0x0000 }
+ },
+ }, {
+ 92500000, {
+ { 0x0140, 0x0005 },
+ { 0x2141, 0x0005 },
+ { 0x4142, 0x0005 },
+ },
+ }, {
+ 148500000, {
+ { 0x00a0, 0x000a },
+ { 0x20a1, 0x000a },
+ { 0x40a2, 0x000a },
+ },
+ }, {
+ ~0UL, {
+ { 0x00a0, 0x000a },
+ { 0x2001, 0x000f },
+ { 0x4002, 0x000f },
+ },
+ }
+};
+
+struct curr_ctrl {
+ unsigned long mpixelclock;
+ u16 curr[RES_MAX];
+};
+
+static const struct curr_ctrl curr_ctrl[] = {
+ /* pixelclk bpp8 bpp10 bpp12 */
+ {
+ 54000000, { 0x091c, 0x091c, 0x06dc },
+ }, {
+ 58400000, { 0x091c, 0x06dc, 0x06dc },
+ }, {
+ 72000000, { 0x06dc, 0x06dc, 0x091c },
+ }, {
+ 74250000, { 0x06dc, 0x0b5c, 0x091c },
+ }, {
+ 118800000, { 0x091c, 0x091c, 0x06dc },
+ }, {
+ 216000000, { 0x06dc, 0x0b5c, 0x091c },
+ }
+};
+
static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
unsigned char res, int cscon)
{
+ unsigned res_idx, i;
u8 val, msec;
- /* color resolution 0 is 8 bit colour depth */
- if (!res)
- res = 8;
-
if (prep)
return -EINVAL;
- else if (res != 8 && res != 12)
+
+ switch (res) {
+ case 0: /* color resolution 0 is 8 bit colour depth */
+ case 8:
+ res_idx = RES_8;
+ break;
+ case 10:
+ res_idx = RES_10;
+ break;
+ case 12:
+ res_idx = RES_12;
+ break;
+ default:
return -EINVAL;
+ }
/* Enable csc path */
if (cscon)
@@ -845,165 +847,30 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
HDMI_PHY_I2CM_SLAVE_ADDR);
hdmi_phy_test_clear(hdmi, 0);
- if (hdmi->hdmi_data.video_mode.mpixelclock <= 45250000) {
- switch (res) {
- case 8:
- /* PLL/MPLL Cfg */
- hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); /* GMPCTRL */
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x21e1, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x41e2, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+ /* PLL/MPLL Cfg - always match on final entry */
+ for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
+ if (hdmi->hdmi_data.video_mode.mpixelclock <=
+ mpll_config[i].mpixelclock)
break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 92500000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x0140, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x2141, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x4142, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 148500000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x20a1, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
- default:
- return -EINVAL;
- }
- } else {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x2001, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x4002, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
- default:
- return -EINVAL;
- }
- }
- if (hdmi->hdmi_data.video_mode.mpixelclock <= 54000000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); /* CURRCTRL */
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 58400000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 72000000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 74250000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 118800000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 216000000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
+ hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
+
+ for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
+ if (hdmi->hdmi_data.video_mode.mpixelclock <=
+ curr_ctrl[i].mpixelclock)
break;
- default:
- return -EINVAL;
- }
- } else {
+
+ if (i >= ARRAY_SIZE(curr_ctrl)) {
dev_err(hdmi->dev,
"Pixel clock %d - unsupported by HDMI\n",
hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL;
}
+ /* CURRCTRL */
+ hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
+
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
/* RESISTANCE TERM 133Ohm Cfg */
@@ -1072,7 +939,7 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
{
- u8 de, val;
+ u8 de;
if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
@@ -1080,20 +947,13 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
/* disable rx detect */
- val = hdmi_readb(hdmi, HDMI_A_HDCPCFG0);
- val &= HDMI_A_HDCPCFG0_RXDETECT_MASK;
- val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE;
- hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG0);
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
+ HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
- val = hdmi_readb(hdmi, HDMI_A_VIDPOLCFG);
- val &= HDMI_A_VIDPOLCFG_DATAENPOL_MASK;
- val |= de;
- hdmi_writeb(hdmi, val, HDMI_A_VIDPOLCFG);
+ hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
- val = hdmi_readb(hdmi, HDMI_A_HDCPCFG1);
- val &= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK;
- val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE;
- hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG1);
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
+ HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
}
static void hdmi_config_AVI(struct imx_hdmi *hdmi)
@@ -1317,11 +1177,7 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
{
- u8 clkdis;
-
- clkdis = hdmi_readb(hdmi, HDMI_MC_CLKDIS);
- clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+ hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
}
/* Workaround to clear the overflow condition */
@@ -1456,9 +1312,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
/* Clear Hotplug interrupts */
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
- /* Unmute interrupts */
- hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
-
return 0;
}
@@ -1527,12 +1380,9 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
*connector, bool force)
{
- /* FIXME */
- return connector_status_connected;
-}
-
-static void imx_hdmi_connector_destroy(struct drm_connector *connector)
-{
+ struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ connector);
+ return hdmi->connector_status;
}
static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -1560,13 +1410,6 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
}
-static int imx_hdmi_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
-
- return MODE_OK;
-}
-
static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
*connector)
{
@@ -1614,28 +1457,21 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
imx_hdmi_poweroff(hdmi);
- imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
- V4L2_PIX_FMT_RGB24);
+ imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
}
static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
{
struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
- int mux = imx_drm_encoder_get_mux_id(hdmi->imx_drm_encoder,
- encoder->crtc);
+ int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
imx_hdmi_set_ipu_di_mux(hdmi, mux);
imx_hdmi_poweron(hdmi);
}
-static void imx_hdmi_encoder_destroy(struct drm_encoder *encoder)
-{
- return;
-}
-
static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
- .destroy = imx_hdmi_encoder_destroy,
+ .destroy = imx_drm_encoder_destroy,
};
static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
@@ -1651,21 +1487,32 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_hdmi_connector_detect,
- .destroy = imx_hdmi_connector_destroy,
+ .destroy = imx_drm_connector_destroy,
};
static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
.get_modes = imx_hdmi_connector_get_modes,
- .mode_valid = imx_hdmi_connector_mode_valid,
+ .mode_valid = imx_drm_connector_mode_valid,
.best_encoder = imx_hdmi_connector_best_encoder,
};
+static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
+{
+ struct imx_hdmi *hdmi = dev_id;
+ u8 intr_stat;
+
+ intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+ if (intr_stat)
+ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+ return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
+}
+
static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
{
struct imx_hdmi *hdmi = dev_id;
u8 intr_stat;
u8 phy_int_pol;
- u8 val;
intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
@@ -1675,55 +1522,47 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
if (phy_int_pol & HDMI_PHY_HPD) {
dev_dbg(hdmi->dev, "EVENT=plugin\n");
- val = hdmi_readb(hdmi, HDMI_PHY_POL0);
- val &= ~HDMI_PHY_HPD;
- hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+ hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
+ hdmi->connector_status = connector_status_connected;
imx_hdmi_poweron(hdmi);
} else {
dev_dbg(hdmi->dev, "EVENT=plugout\n");
- val = hdmi_readb(hdmi, HDMI_PHY_POL0);
- val |= HDMI_PHY_HPD;
- hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+ hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
+ HDMI_PHY_POL0);
+ hdmi->connector_status = connector_status_disconnected;
imx_hdmi_poweroff(hdmi);
}
+ drm_helper_hpd_irq_event(hdmi->connector.dev);
}
hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
+ hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
return IRQ_HANDLED;
}
-static int imx_hdmi_register(struct imx_hdmi *hdmi)
+static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
{
int ret;
- hdmi->connector.funcs = &imx_hdmi_connector_funcs;
- hdmi->encoder.funcs = &imx_hdmi_encoder_funcs;
+ ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
+ hdmi->dev->of_node);
+ if (ret)
+ return ret;
- hdmi->encoder.encoder_type = DRM_MODE_ENCODER_TMDS;
- hdmi->connector.connector_type = DRM_MODE_CONNECTOR_HDMIA;
+ hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
- ret = imx_drm_add_encoder(&hdmi->encoder, &hdmi->imx_drm_encoder,
- THIS_MODULE);
- if (ret) {
- dev_err(hdmi->dev, "adding encoder failed: %d\n", ret);
- return ret;
- }
+ drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
drm_connector_helper_add(&hdmi->connector,
&imx_hdmi_connector_helper_funcs);
-
- ret = imx_drm_add_connector(&hdmi->connector,
- &hdmi->imx_drm_connector, THIS_MODULE);
- if (ret) {
- imx_drm_remove_encoder(hdmi->imx_drm_encoder);
- dev_err(hdmi->dev, "adding connector failed: %d\n", ret);
- return ret;
- }
+ drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
hdmi->connector.encoder = &hdmi->encoder;
@@ -1750,28 +1589,33 @@ static const struct of_device_id imx_hdmi_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
-static int imx_hdmi_platform_probe(struct platform_device *pdev)
+static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
{
+ struct platform_device *pdev = to_platform_device(dev);
const struct of_device_id *of_id =
- of_match_device(imx_hdmi_dt_ids, &pdev->dev);
- struct device_node *np = pdev->dev.of_node;
+ of_match_device(imx_hdmi_dt_ids, dev);
+ struct drm_device *drm = data;
+ struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct imx_hdmi *hdmi;
struct resource *iores;
int ret, irq;
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
return -ENOMEM;
- hdmi->dev = &pdev->dev;
+ hdmi->dev = dev;
+ hdmi->connector_status = connector_status_disconnected;
+ hdmi->sample_rate = 48000;
+ hdmi->ratio = 100;
if (of_id) {
const struct platform_device_id *device_id = of_id->data;
hdmi->dev_type = device_id->driver_data;
}
- ddc_node = of_parse_phandle(np, "ddc", 0);
+ ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
if (!hdmi->ddc)
@@ -1786,13 +1630,14 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
if (irq < 0)
return -EINVAL;
- ret = devm_request_irq(&pdev->dev, irq, imx_hdmi_irq, 0,
- dev_name(&pdev->dev), hdmi);
+ ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
+ imx_hdmi_irq, IRQF_SHARED,
+ dev_name(dev), hdmi);
if (ret)
return ret;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdmi->regs = devm_ioremap_resource(&pdev->dev, iores);
+ hdmi->regs = devm_ioremap_resource(dev, iores);
if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs);
@@ -1831,7 +1676,7 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
}
/* Product and revision IDs */
- dev_info(&pdev->dev,
+ dev_info(dev,
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
hdmi_readb(hdmi, HDMI_DESIGN_ID),
hdmi_readb(hdmi, HDMI_REVISION_ID),
@@ -1859,13 +1704,14 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
if (ret)
goto err_iahb;
- ret = imx_hdmi_register(hdmi);
+ ret = imx_hdmi_register(drm, hdmi);
if (ret)
goto err_iahb;
- imx_drm_encoder_add_possible_crtcs(hdmi->imx_drm_encoder, np);
+ /* Unmute interrupts */
+ hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
- platform_set_drvdata(pdev, hdmi);
+ dev_set_drvdata(dev, hdmi);
return 0;
@@ -1877,20 +1723,35 @@ err_isfr:
return ret;
}
-static int imx_hdmi_platform_remove(struct platform_device *pdev)
+static void imx_hdmi_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
- struct drm_connector *connector = &hdmi->connector;
- struct drm_encoder *encoder = &hdmi->encoder;
+ struct imx_hdmi *hdmi = dev_get_drvdata(dev);
- drm_mode_connector_detach_encoder(connector, encoder);
- imx_drm_remove_connector(hdmi->imx_drm_connector);
- imx_drm_remove_encoder(hdmi->imx_drm_encoder);
+ /* Disable all interrupts */
+ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+ hdmi->connector.funcs->destroy(&hdmi->connector);
+ hdmi->encoder.funcs->destroy(&hdmi->encoder);
clk_disable_unprepare(hdmi->iahb_clk);
clk_disable_unprepare(hdmi->isfr_clk);
i2c_put_adapter(hdmi->ddc);
+}
+
+static const struct component_ops hdmi_ops = {
+ .bind = imx_hdmi_bind,
+ .unbind = imx_hdmi_unbind,
+};
+
+static int imx_hdmi_platform_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &hdmi_ops);
+}
+static int imx_hdmi_platform_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &hdmi_ops);
return 0;
}
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 7e593296ac47..fe4c1ef4e7a5 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/clk.h>
+#include <linux/component.h>
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
@@ -58,9 +59,8 @@ struct imx_ldb;
struct imx_ldb_channel {
struct imx_ldb *ldb;
struct drm_connector connector;
- struct imx_drm_connector *imx_drm_connector;
struct drm_encoder encoder;
- struct imx_drm_encoder *imx_drm_encoder;
+ struct device_node *child;
int chno;
void *edid;
int edid_len;
@@ -91,11 +91,6 @@ static enum drm_connector_status imx_ldb_connector_detect(
return connector_status_connected;
}
-static void imx_ldb_connector_destroy(struct drm_connector *connector)
-{
- /* do not free here */
-}
-
static int imx_ldb_connector_get_modes(struct drm_connector *connector)
{
struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
@@ -111,6 +106,8 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
struct drm_display_mode *mode;
mode = drm_mode_create(connector->dev);
+ if (!mode)
+ return -EINVAL;
drm_mode_copy(mode, &imx_ldb_ch->mode);
mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
@@ -120,12 +117,6 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
return num_modes;
}
-static int imx_ldb_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- return 0;
-}
-
static struct drm_encoder *imx_ldb_connector_best_encoder(
struct drm_connector *connector)
{
@@ -168,7 +159,9 @@ static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno,
/* set display clock mux to LDB input clock */
ret = clk_set_parent(ldb->clk_sel[mux], ldb->clk[chno]);
if (ret)
- dev_err(ldb->dev, "unable to set di%d parent clock to ldb_di%d\n", mux, chno);
+ dev_err(ldb->dev,
+ "unable to set di%d parent clock to ldb_di%d\n", mux,
+ chno);
}
static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
@@ -179,8 +172,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
u32 pixel_fmt;
unsigned long serial_clk;
unsigned long di_clk = mode->clock * 1000;
- int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder,
- encoder->crtc);
+ int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
/* dual channel LVDS mode */
@@ -189,7 +181,8 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
} else {
serial_clk = 7000UL * mode->clock;
- imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk, di_clk);
+ imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
+ di_clk);
}
switch (imx_ldb_ch->chno) {
@@ -207,8 +200,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
pixel_fmt = V4L2_PIX_FMT_RGB24;
}
- imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_LVDS,
- pixel_fmt);
+ imx_drm_panel_format(encoder, pixel_fmt);
}
static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
@@ -216,8 +208,7 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
struct imx_ldb *ldb = imx_ldb_ch->ldb;
int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
- int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder,
- encoder->crtc);
+ int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
if (dual) {
clk_prepare_enable(ldb->clk[0]);
@@ -316,26 +307,21 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
}
}
-static void imx_ldb_encoder_destroy(struct drm_encoder *encoder)
-{
- /* do not free here */
-}
-
static struct drm_connector_funcs imx_ldb_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_ldb_connector_detect,
- .destroy = imx_ldb_connector_destroy,
+ .destroy = imx_drm_connector_destroy,
};
static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
.get_modes = imx_ldb_connector_get_modes,
.best_encoder = imx_ldb_connector_best_encoder,
- .mode_valid = imx_ldb_connector_mode_valid,
+ .mode_valid = imx_drm_connector_mode_valid,
};
static struct drm_encoder_funcs imx_ldb_encoder_funcs = {
- .destroy = imx_ldb_encoder_destroy,
+ .destroy = imx_drm_encoder_destroy,
};
static struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
@@ -351,56 +337,47 @@ static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno)
{
char clkname[16];
- sprintf(clkname, "di%d", chno);
+ snprintf(clkname, sizeof(clkname), "di%d", chno);
ldb->clk[chno] = devm_clk_get(ldb->dev, clkname);
if (IS_ERR(ldb->clk[chno]))
return PTR_ERR(ldb->clk[chno]);
- sprintf(clkname, "di%d_pll", chno);
+ snprintf(clkname, sizeof(clkname), "di%d_pll", chno);
ldb->clk_pll[chno] = devm_clk_get(ldb->dev, clkname);
return PTR_ERR_OR_ZERO(ldb->clk_pll[chno]);
}
-static int imx_ldb_register(struct imx_ldb_channel *imx_ldb_ch)
+static int imx_ldb_register(struct drm_device *drm,
+ struct imx_ldb_channel *imx_ldb_ch)
{
- int ret;
struct imx_ldb *ldb = imx_ldb_ch->ldb;
+ int ret;
+
+ ret = imx_drm_encoder_parse_of(drm, &imx_ldb_ch->encoder,
+ imx_ldb_ch->child);
+ if (ret)
+ return ret;
ret = imx_ldb_get_clk(ldb, imx_ldb_ch->chno);
if (ret)
return ret;
+
if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
- ret |= imx_ldb_get_clk(ldb, 1);
+ ret = imx_ldb_get_clk(ldb, 1);
if (ret)
return ret;
}
- imx_ldb_ch->connector.funcs = &imx_ldb_connector_funcs;
- imx_ldb_ch->encoder.funcs = &imx_ldb_encoder_funcs;
-
- imx_ldb_ch->encoder.encoder_type = DRM_MODE_ENCODER_LVDS;
- imx_ldb_ch->connector.connector_type = DRM_MODE_CONNECTOR_LVDS;
-
drm_encoder_helper_add(&imx_ldb_ch->encoder,
&imx_ldb_encoder_helper_funcs);
- ret = imx_drm_add_encoder(&imx_ldb_ch->encoder,
- &imx_ldb_ch->imx_drm_encoder, THIS_MODULE);
- if (ret) {
- dev_err(ldb->dev, "adding encoder failed with %d\n", ret);
- return ret;
- }
+ drm_encoder_init(drm, &imx_ldb_ch->encoder, &imx_ldb_encoder_funcs,
+ DRM_MODE_ENCODER_LVDS);
drm_connector_helper_add(&imx_ldb_ch->connector,
&imx_ldb_connector_helper_funcs);
-
- ret = imx_drm_add_connector(&imx_ldb_ch->connector,
- &imx_ldb_ch->imx_drm_connector, THIS_MODULE);
- if (ret) {
- imx_drm_remove_encoder(imx_ldb_ch->imx_drm_encoder);
- dev_err(ldb->dev, "adding connector failed with %d\n", ret);
- return ret;
- }
+ drm_connector_init(drm, &imx_ldb_ch->connector,
+ &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
&imx_ldb_ch->encoder);
@@ -459,11 +436,12 @@ static const struct of_device_id imx_ldb_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
-static int imx_ldb_probe(struct platform_device *pdev)
+static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
{
- struct device_node *np = pdev->dev.of_node;
+ struct drm_device *drm = data;
+ struct device_node *np = dev->of_node;
const struct of_device_id *of_id =
- of_match_device(imx_ldb_dt_ids, &pdev->dev);
+ of_match_device(imx_ldb_dt_ids, dev);
struct device_node *child;
const u8 *edidp;
struct imx_ldb *imx_ldb;
@@ -473,17 +451,17 @@ static int imx_ldb_probe(struct platform_device *pdev)
int ret;
int i;
- imx_ldb = devm_kzalloc(&pdev->dev, sizeof(*imx_ldb), GFP_KERNEL);
+ imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
if (!imx_ldb)
return -ENOMEM;
imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
if (IS_ERR(imx_ldb->regmap)) {
- dev_err(&pdev->dev, "failed to get parent regmap\n");
+ dev_err(dev, "failed to get parent regmap\n");
return PTR_ERR(imx_ldb->regmap);
}
- imx_ldb->dev = &pdev->dev;
+ imx_ldb->dev = dev;
if (of_id)
imx_ldb->lvds_mux = of_id->data;
@@ -521,7 +499,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
return -EINVAL;
if (dual && i > 0) {
- dev_warn(&pdev->dev, "dual-channel mode, ignoring second output\n");
+ dev_warn(dev, "dual-channel mode, ignoring second output\n");
continue;
}
@@ -531,6 +509,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
channel = &imx_ldb->channel[i];
channel->ldb = imx_ldb;
channel->chno = i;
+ channel->child = child;
edidp = of_get_property(child, "edid", &channel->edid_len);
if (edidp) {
@@ -553,54 +532,67 @@ static int imx_ldb_probe(struct platform_device *pdev)
case LVDS_BIT_MAP_SPWG:
if (datawidth == 24) {
if (i == 0 || dual)
- imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24;
+ imx_ldb->ldb_ctrl |=
+ LDB_DATA_WIDTH_CH0_24;
if (i == 1 || dual)
- imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24;
+ imx_ldb->ldb_ctrl |=
+ LDB_DATA_WIDTH_CH1_24;
}
break;
case LVDS_BIT_MAP_JEIDA:
if (datawidth == 18) {
- dev_err(&pdev->dev, "JEIDA standard only supported in 24 bit\n");
+ dev_err(dev, "JEIDA standard only supported in 24 bit\n");
return -EINVAL;
}
if (i == 0 || dual)
- imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | LDB_BIT_MAP_CH0_JEIDA;
+ imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |
+ LDB_BIT_MAP_CH0_JEIDA;
if (i == 1 || dual)
- imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | LDB_BIT_MAP_CH1_JEIDA;
+ imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
+ LDB_BIT_MAP_CH1_JEIDA;
break;
default:
- dev_err(&pdev->dev, "data mapping not specified or invalid\n");
+ dev_err(dev, "data mapping not specified or invalid\n");
return -EINVAL;
}
- ret = imx_ldb_register(channel);
+ ret = imx_ldb_register(drm, channel);
if (ret)
return ret;
-
- imx_drm_encoder_add_possible_crtcs(channel->imx_drm_encoder, child);
}
- platform_set_drvdata(pdev, imx_ldb);
+ dev_set_drvdata(dev, imx_ldb);
return 0;
}
-static int imx_ldb_remove(struct platform_device *pdev)
+static void imx_ldb_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct imx_ldb *imx_ldb = platform_get_drvdata(pdev);
+ struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
int i;
for (i = 0; i < 2; i++) {
struct imx_ldb_channel *channel = &imx_ldb->channel[i];
- struct drm_connector *connector = &channel->connector;
- struct drm_encoder *encoder = &channel->encoder;
-
- drm_mode_connector_detach_encoder(connector, encoder);
- imx_drm_remove_connector(channel->imx_drm_connector);
- imx_drm_remove_encoder(channel->imx_drm_encoder);
+ channel->connector.funcs->destroy(&channel->connector);
+ channel->encoder.funcs->destroy(&channel->encoder);
}
+}
+
+static const struct component_ops imx_ldb_ops = {
+ .bind = imx_ldb_bind,
+ .unbind = imx_ldb_unbind,
+};
+static int imx_ldb_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &imx_ldb_ops);
+}
+
+static int imx_ldb_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_ldb_ops);
return 0;
}
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index 9abc7ca8b6cf..575533f4fd64 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -20,6 +20,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/component.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
@@ -30,6 +31,7 @@
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
+#include "ipu-v3/imx-ipu-v3.h"
#include "imx-drm.h"
#define TVE_COM_CONF_REG 0x00
@@ -110,9 +112,7 @@ enum {
struct imx_tve {
struct drm_connector connector;
- struct imx_drm_connector *imx_drm_connector;
struct drm_encoder encoder;
- struct imx_drm_encoder *imx_drm_encoder;
struct device *dev;
spinlock_t lock; /* register lock */
bool enabled;
@@ -225,11 +225,6 @@ static enum drm_connector_status imx_tve_connector_detect(
return connector_status_connected;
}
-static void imx_tve_connector_destroy(struct drm_connector *connector)
-{
- /* do not free here */
-}
-
static int imx_tve_connector_get_modes(struct drm_connector *connector)
{
struct imx_tve *tve = con_to_tve(connector);
@@ -254,6 +249,11 @@ static int imx_tve_connector_mode_valid(struct drm_connector *connector,
{
struct imx_tve *tve = con_to_tve(connector);
unsigned long rate;
+ int ret;
+
+ ret = imx_drm_connector_mode_valid(connector, mode);
+ if (ret != MODE_OK)
+ return ret;
/* pixel clock with 2x oversampling */
rate = clk_round_rate(tve->clk, 2000UL * mode->clock) / 2000;
@@ -305,13 +305,11 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
switch (tve->mode) {
case TVE_MODE_VGA:
- imx_drm_crtc_panel_format_pins(encoder->crtc,
- DRM_MODE_ENCODER_DAC, IPU_PIX_FMT_GBR24,
+ imx_drm_panel_format_pins(encoder, IPU_PIX_FMT_GBR24,
tve->hsync_pin, tve->vsync_pin);
break;
case TVE_MODE_TVOUT:
- imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_TVDAC,
- V4L2_PIX_FMT_YUV444);
+ imx_drm_panel_format(encoder, V4L2_PIX_FMT_YUV444);
break;
}
}
@@ -364,16 +362,11 @@ static void imx_tve_encoder_disable(struct drm_encoder *encoder)
tve_disable(tve);
}
-static void imx_tve_encoder_destroy(struct drm_encoder *encoder)
-{
- /* do not free here */
-}
-
static struct drm_connector_funcs imx_tve_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_tve_connector_detect,
- .destroy = imx_tve_connector_destroy,
+ .destroy = imx_drm_connector_destroy,
};
static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
@@ -383,7 +376,7 @@ static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
};
static struct drm_encoder_funcs imx_tve_encoder_funcs = {
- .destroy = imx_tve_encoder_destroy,
+ .destroy = imx_drm_encoder_destroy,
};
static struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = {
@@ -503,34 +496,27 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
return 0;
}
-static int imx_tve_register(struct imx_tve *tve)
+static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve)
{
+ int encoder_type;
int ret;
- tve->connector.funcs = &imx_tve_connector_funcs;
- tve->encoder.funcs = &imx_tve_encoder_funcs;
+ encoder_type = tve->mode == TVE_MODE_VGA ?
+ DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
- tve->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
- tve->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
+ ret = imx_drm_encoder_parse_of(drm, &tve->encoder,
+ tve->dev->of_node);
+ if (ret)
+ return ret;
drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
- ret = imx_drm_add_encoder(&tve->encoder, &tve->imx_drm_encoder,
- THIS_MODULE);
- if (ret) {
- dev_err(tve->dev, "adding encoder failed with %d\n", ret);
- return ret;
- }
+ drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs,
+ encoder_type);
drm_connector_helper_add(&tve->connector,
&imx_tve_connector_helper_funcs);
-
- ret = imx_drm_add_connector(&tve->connector,
- &tve->imx_drm_connector, THIS_MODULE);
- if (ret) {
- imx_drm_remove_encoder(tve->imx_drm_encoder);
- dev_err(tve->dev, "adding connector failed with %d\n", ret);
- return ret;
- }
+ drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA);
drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder);
@@ -576,9 +562,11 @@ static const int of_get_tve_mode(struct device_node *np)
return -EINVAL;
}
-static int imx_tve_probe(struct platform_device *pdev)
+static int imx_tve_bind(struct device *dev, struct device *master, void *data)
{
- struct device_node *np = pdev->dev.of_node;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = data;
+ struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct imx_tve *tve;
struct resource *res;
@@ -587,14 +575,14 @@ static int imx_tve_probe(struct platform_device *pdev)
int irq;
int ret;
- tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL);
+ tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL);
if (!tve)
return -ENOMEM;
- tve->dev = &pdev->dev;
+ tve->dev = dev;
spin_lock_init(&tve->lock);
- ddc_node = of_parse_phandle(np, "ddc", 0);
+ ddc_node = of_parse_phandle(np, "i2c-ddc-bus", 0);
if (ddc_node) {
tve->ddc = of_find_i2c_adapter_by_node(ddc_node);
of_node_put(ddc_node);
@@ -602,7 +590,7 @@ static int imx_tve_probe(struct platform_device *pdev)
tve->mode = of_get_tve_mode(np);
if (tve->mode != TVE_MODE_VGA) {
- dev_err(&pdev->dev, "only VGA mode supported, currently\n");
+ dev_err(dev, "only VGA mode supported, currently\n");
return -EINVAL;
}
@@ -611,7 +599,7 @@ static int imx_tve_probe(struct platform_device *pdev)
&tve->hsync_pin);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to get vsync pin\n");
+ dev_err(dev, "failed to get vsync pin\n");
return ret;
}
@@ -619,40 +607,40 @@ static int imx_tve_probe(struct platform_device *pdev)
&tve->vsync_pin);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to get vsync pin\n");
+ dev_err(dev, "failed to get vsync pin\n");
return ret;
}
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(&pdev->dev, res);
+ base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
tve_regmap_config.lock_arg = tve;
- tve->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "tve", base,
+ tve->regmap = devm_regmap_init_mmio_clk(dev, "tve", base,
&tve_regmap_config);
if (IS_ERR(tve->regmap)) {
- dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+ dev_err(dev, "failed to init regmap: %ld\n",
PTR_ERR(tve->regmap));
return PTR_ERR(tve->regmap);
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
- dev_err(&pdev->dev, "failed to get irq\n");
+ dev_err(dev, "failed to get irq\n");
return irq;
}
- ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ ret = devm_request_threaded_irq(dev, irq, NULL,
imx_tve_irq_handler, IRQF_ONESHOT,
"imx-tve", tve);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+ dev_err(dev, "failed to request irq: %d\n", ret);
return ret;
}
- tve->dac_reg = devm_regulator_get(&pdev->dev, "dac");
+ tve->dac_reg = devm_regulator_get(dev, "dac");
if (!IS_ERR(tve->dac_reg)) {
regulator_set_voltage(tve->dac_reg, 2750000, 2750000);
ret = regulator_enable(tve->dac_reg);
@@ -660,17 +648,17 @@ static int imx_tve_probe(struct platform_device *pdev)
return ret;
}
- tve->clk = devm_clk_get(&pdev->dev, "tve");
+ tve->clk = devm_clk_get(dev, "tve");
if (IS_ERR(tve->clk)) {
- dev_err(&pdev->dev, "failed to get high speed tve clock: %ld\n",
+ dev_err(dev, "failed to get high speed tve clock: %ld\n",
PTR_ERR(tve->clk));
return PTR_ERR(tve->clk);
}
/* this is the IPU DI clock input selector, can be parented to tve_di */
- tve->di_sel_clk = devm_clk_get(&pdev->dev, "di_sel");
+ tve->di_sel_clk = devm_clk_get(dev, "di_sel");
if (IS_ERR(tve->di_sel_clk)) {
- dev_err(&pdev->dev, "failed to get ipu di mux clock: %ld\n",
+ dev_err(dev, "failed to get ipu di mux clock: %ld\n",
PTR_ERR(tve->di_sel_clk));
return PTR_ERR(tve->di_sel_clk);
}
@@ -681,42 +669,51 @@ static int imx_tve_probe(struct platform_device *pdev)
ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to read configuration register: %d\n", ret);
+ dev_err(dev, "failed to read configuration register: %d\n", ret);
return ret;
}
if (val != 0x00100000) {
- dev_err(&pdev->dev, "configuration register default value indicates this is not a TVEv2\n");
+ dev_err(dev, "configuration register default value indicates this is not a TVEv2\n");
return -ENODEV;
}
/* disable cable detection for VGA mode */
ret = regmap_write(tve->regmap, TVE_CD_CONT_REG, 0);
- ret = imx_tve_register(tve);
+ ret = imx_tve_register(drm, tve);
if (ret)
return ret;
- ret = imx_drm_encoder_add_possible_crtcs(tve->imx_drm_encoder, np);
-
- platform_set_drvdata(pdev, tve);
+ dev_set_drvdata(dev, tve);
return 0;
}
-static int imx_tve_remove(struct platform_device *pdev)
+static void imx_tve_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct imx_tve *tve = platform_get_drvdata(pdev);
- struct drm_connector *connector = &tve->connector;
- struct drm_encoder *encoder = &tve->encoder;
+ struct imx_tve *tve = dev_get_drvdata(dev);
- drm_mode_connector_detach_encoder(connector, encoder);
-
- imx_drm_remove_connector(tve->imx_drm_connector);
- imx_drm_remove_encoder(tve->imx_drm_encoder);
+ tve->connector.funcs->destroy(&tve->connector);
+ tve->encoder.funcs->destroy(&tve->encoder);
if (!IS_ERR(tve->dac_reg))
regulator_disable(tve->dac_reg);
+}
+
+static const struct component_ops imx_tve_ops = {
+ .bind = imx_tve_bind,
+ .unbind = imx_tve_unbind,
+};
+static int imx_tve_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &imx_tve_ops);
+}
+
+static int imx_tve_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_tve_ops);
return 0;
}
diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
index 4826b5c0249d..c4d14ead5837 100644
--- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
+++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
@@ -25,6 +25,8 @@ enum ipuv3_type {
IPUV3H,
};
+#define IPU_PIX_FMT_GBR24 v4l2_fourcc('G', 'B', 'R', '3')
+
/*
* Bitfield of Display Interface signal polarities.
*/
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
index d0e3bc3c53e7..d5de8bb5c803 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
@@ -262,7 +262,7 @@ void ipu_dc_disable_channel(struct ipu_dc *dc)
/* Wait for DC triple buffer to empty */
while ((readl(priv->dc_reg + DC_STAT) & val) != val) {
- msleep(2);
+ usleep_range(2000, 20000);
timeout -= 2;
if (timeout <= 0)
break;
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index 948a49b289ef..82a9ebad697c 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -19,9 +19,6 @@
#include <linux/io.h>
#include <linux/err.h>
#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
#include "imx-ipu-v3.h"
#include "ipu-prv.h"
@@ -33,10 +30,7 @@ struct ipu_di {
struct clk *clk_di; /* display input clock */
struct clk *clk_ipu; /* IPU bus clock */
struct clk *clk_di_pixel; /* resulting pixel clock */
- struct clk_hw clk_hw_out;
- char *clk_name;
bool inuse;
- unsigned long clkflags;
struct ipu_soc *ipu;
};
@@ -141,130 +135,6 @@ static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
writel(value, di->base + offset);
}
-static int ipu_di_clk_calc_div(unsigned long inrate, unsigned long outrate)
-{
- u64 tmp = inrate;
- int div;
-
- tmp *= 16;
-
- do_div(tmp, outrate);
-
- div = tmp;
-
- if (div < 0x10)
- div = 0x10;
-
-#ifdef WTF_IS_THIS
- /*
- * Freescale has this in their Kernel. It is neither clear what
- * it does nor why it does it
- */
- if (div & 0x10)
- div &= ~0x7;
- else {
- /* Round up divider if it gets us closer to desired pix clk */
- if ((div & 0xC) == 0xC) {
- div += 0x10;
- div &= ~0xF;
- }
- }
-#endif
- return div;
-}
-
-static unsigned long clk_di_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- unsigned long outrate;
- u32 div = ipu_di_read(di, DI_BS_CLKGEN0);
-
- if (div < 0x10)
- div = 0x10;
-
- outrate = (parent_rate / div) * 16;
-
- return outrate;
-}
-
-static long clk_di_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- unsigned long outrate;
- int div;
- u32 val;
-
- div = ipu_di_clk_calc_div(*prate, rate);
-
- outrate = (*prate / div) * 16;
-
- val = ipu_di_read(di, DI_GENERAL);
-
- if (!(val & DI_GEN_DI_CLK_EXT) && outrate > *prate / 2)
- outrate = *prate / 2;
-
- dev_dbg(di->ipu->dev,
- "%s: inrate: %ld div: 0x%08x outrate: %ld wanted: %ld\n",
- __func__, *prate, div, outrate, rate);
-
- return outrate;
-}
-
-static int clk_di_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- int div;
- u32 clkgen0;
-
- clkgen0 = ipu_di_read(di, DI_BS_CLKGEN0) & ~0xfff;
-
- div = ipu_di_clk_calc_div(parent_rate, rate);
-
- ipu_di_write(di, clkgen0 | div, DI_BS_CLKGEN0);
-
- dev_dbg(di->ipu->dev, "%s: inrate: %ld desired: %ld div: 0x%08x\n",
- __func__, parent_rate, rate, div);
- return 0;
-}
-
-static u8 clk_di_get_parent(struct clk_hw *hw)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- u32 val;
-
- val = ipu_di_read(di, DI_GENERAL);
-
- return val & DI_GEN_DI_CLK_EXT ? 1 : 0;
-}
-
-static int clk_di_set_parent(struct clk_hw *hw, u8 index)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- u32 val;
-
- val = ipu_di_read(di, DI_GENERAL);
-
- if (index)
- val |= DI_GEN_DI_CLK_EXT;
- else
- val &= ~DI_GEN_DI_CLK_EXT;
-
- ipu_di_write(di, val, DI_GENERAL);
-
- return 0;
-}
-
-static struct clk_ops clk_di_ops = {
- .round_rate = clk_di_round_rate,
- .set_rate = clk_di_set_rate,
- .recalc_rate = clk_di_recalc_rate,
- .set_parent = clk_di_set_parent,
- .get_parent = clk_di_get_parent,
-};
-
static void ipu_di_data_wave_config(struct ipu_di *di,
int wave_gen,
int access_size, int component_size)
@@ -528,15 +398,125 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
}
+static void ipu_di_config_clock(struct ipu_di *di,
+ const struct ipu_di_signal_cfg *sig)
+{
+ struct clk *clk;
+ unsigned clkgen0;
+ uint32_t val;
+
+ if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
+ /*
+ * CLKMODE_EXT means we must use the DI clock: this is
+ * needed for things like LVDS which needs to feed the
+ * DI and LDB with the same pixel clock.
+ */
+ clk = di->clk_di;
+
+ if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
+ /*
+ * CLKMODE_SYNC means that we want the DI to be
+ * clocked at the same rate as the parent clock.
+ * This is needed (eg) for LDB which needs to be
+ * fed with the same pixel clock. We assume that
+ * the LDB clock has already been set correctly.
+ */
+ clkgen0 = 1 << 4;
+ } else {
+ /*
+ * We can use the divider. We should really have
+ * a flag here indicating whether the bridge can
+ * cope with a fractional divider or not. For the
+ * time being, let's go for simplicitly and
+ * reliability.
+ */
+ unsigned long in_rate;
+ unsigned div;
+
+ clk_set_rate(clk, sig->pixelclock);
+
+ in_rate = clk_get_rate(clk);
+ div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+ if (div == 0)
+ div = 1;
+
+ clkgen0 = div << 4;
+ }
+ } else {
+ /*
+ * For other interfaces, we can arbitarily select between
+ * the DI specific clock and the internal IPU clock. See
+ * DI_GENERAL bit 20. We select the IPU clock if it can
+ * give us a clock rate within 1% of the requested frequency,
+ * otherwise we use the DI clock.
+ */
+ unsigned long rate, clkrate;
+ unsigned div, error;
+
+ clkrate = clk_get_rate(di->clk_ipu);
+ div = (clkrate + sig->pixelclock / 2) / sig->pixelclock;
+ rate = clkrate / div;
+
+ error = rate / (sig->pixelclock / 1000);
+
+ dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %d.%u%%\n",
+ rate, div, (signed)(error - 1000) / 10, error % 10);
+
+ /* Allow a 1% error */
+ if (error < 1010 && error >= 990) {
+ clk = di->clk_ipu;
+
+ clkgen0 = div << 4;
+ } else {
+ unsigned long in_rate;
+ unsigned div;
+
+ clk = di->clk_di;
+
+ clk_set_rate(clk, sig->pixelclock);
+
+ in_rate = clk_get_rate(clk);
+ div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+ if (div == 0)
+ div = 1;
+
+ clkgen0 = div << 4;
+ }
+ }
+
+ di->clk_di_pixel = clk;
+
+ /* Set the divider */
+ ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
+
+ /*
+ * Set the high/low periods. Bits 24:16 give us the falling edge,
+ * and bits 8:0 give the rising edge. LSB is fraction, and is
+ * based on the divider above. We want a 50% duty cycle, so set
+ * the falling edge to be half the divider.
+ */
+ ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
+
+ /* Finally select the input clock */
+ val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT;
+ if (clk == di->clk_di)
+ val |= DI_GEN_DI_CLK_EXT;
+ ipu_di_write(di, val, DI_GENERAL);
+
+ dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
+ sig->pixelclock,
+ clk_get_rate(di->clk_ipu),
+ clk_get_rate(di->clk_di),
+ clk == di->clk_di ? "DI" : "IPU",
+ clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
+}
+
int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
{
u32 reg;
u32 di_gen, vsync_cnt;
u32 div;
u32 h_total, v_total;
- int ret;
- unsigned long round;
- struct clk *parent;
dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
di->id, sig->width, sig->height);
@@ -544,33 +524,20 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
return -EINVAL;
- if (sig->clkflags & IPU_DI_CLKMODE_EXT)
- parent = di->clk_di;
- else
- parent = di->clk_ipu;
-
- ret = clk_set_parent(di->clk_di_pixel, parent);
- if (ret) {
- dev_err(di->ipu->dev,
- "setting pixel clock to parent %s failed with %d\n",
- __clk_get_name(parent), ret);
- return ret;
- }
-
- if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
- round = clk_get_rate(parent);
- else
- round = clk_round_rate(di->clk_di_pixel, sig->pixelclock);
-
- ret = clk_set_rate(di->clk_di_pixel, round);
-
h_total = sig->width + sig->h_sync_width + sig->h_start_width +
sig->h_end_width;
v_total = sig->height + sig->v_sync_width + sig->v_start_width +
sig->v_end_width;
+ dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
+ clk_get_rate(di->clk_ipu),
+ clk_get_rate(di->clk_di),
+ sig->pixelclock);
+
mutex_lock(&di_mutex);
+ ipu_di_config_clock(di, sig);
+
div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
div = div / 16; /* Now divider is integer portion */
@@ -654,7 +621,11 @@ EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
int ipu_di_enable(struct ipu_di *di)
{
- int ret = clk_prepare_enable(di->clk_di_pixel);
+ int ret;
+
+ WARN_ON(IS_ERR(di->clk_di_pixel));
+
+ ret = clk_prepare_enable(di->clk_di_pixel);
if (ret)
return ret;
@@ -666,6 +637,8 @@ EXPORT_SYMBOL_GPL(ipu_di_enable);
int ipu_di_disable(struct ipu_di *di)
{
+ WARN_ON(IS_ERR(di->clk_di_pixel));
+
ipu_module_disable(di->ipu, di->module);
clk_disable_unprepare(di->clk_di_pixel);
@@ -721,13 +694,6 @@ int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
u32 module, struct clk *clk_ipu)
{
struct ipu_di *di;
- int ret;
- const char *di_parent[2];
- struct clk_init_data init = {
- .ops = &clk_di_ops,
- .num_parents = 2,
- .flags = 0,
- };
if (id > 1)
return -ENODEV;
@@ -749,45 +715,16 @@ int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
if (!di->base)
return -ENOMEM;
- di_parent[0] = __clk_get_name(di->clk_ipu);
- di_parent[1] = __clk_get_name(di->clk_di);
-
ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
- init.parent_names = (const char **)&di_parent;
- di->clk_name = kasprintf(GFP_KERNEL, "%s_di%d_pixel",
- dev_name(dev), id);
- if (!di->clk_name)
- return -ENOMEM;
-
- init.name = di->clk_name;
-
- di->clk_hw_out.init = &init;
- di->clk_di_pixel = clk_register(dev, &di->clk_hw_out);
-
- if (IS_ERR(di->clk_di_pixel)) {
- ret = PTR_ERR(di->clk_di_pixel);
- goto failed_clk_register;
- }
-
dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
id, base, di->base);
di->inuse = false;
di->ipu = ipu;
return 0;
-
-failed_clk_register:
-
- kfree(di->clk_name);
-
- return ret;
}
void ipu_di_exit(struct ipu_soc *ipu, int id)
{
- struct ipu_di *di = ipu->di_priv[id];
-
- clk_unregister(di->clk_di_pixel);
- kfree(di->clk_name);
}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
index 98070dd8c920..45213017fa4b 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
@@ -161,9 +161,6 @@ static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots,
"dmfc: using %d slots starting from segment %d for IPU channel %d\n",
slots, segment, dmfc->data->ipu_channel);
- if (!dmfc)
- return -EINVAL;
-
switch (slots) {
case 1:
field = DMFC_FIFO_SIZE_64;
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index 22be104fbda9..a8d017854615 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -17,6 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
+#include <linux/component.h>
#include <linux/module.h>
#include <linux/export.h>
#include <linux/device.h>
@@ -284,6 +285,7 @@ static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
IPU_DI_CLKMODE_EXT;
break;
+ case DRM_MODE_ENCODER_TMDS:
case DRM_MODE_ENCODER_NONE:
ipu_crtc->di_clkflags = 0;
break;
@@ -334,7 +336,7 @@ err_out:
}
static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
- struct ipu_client_platformdata *pdata)
+ struct ipu_client_platformdata *pdata, struct drm_device *drm)
{
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
int dp = -EINVAL;
@@ -348,10 +350,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
return ret;
}
- ret = imx_drm_add_crtc(&ipu_crtc->base,
- &ipu_crtc->imx_crtc,
- &ipu_crtc_helper_funcs, THIS_MODULE,
- ipu_crtc->dev->parent->of_node, pdata->di);
+ ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
+ &ipu_crtc_helper_funcs, ipu_crtc->dev->of_node);
if (ret) {
dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
goto err_put_resources;
@@ -399,43 +399,96 @@ err_put_resources:
return ret;
}
-static int ipu_drm_probe(struct platform_device *pdev)
+static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent,
+ int port_id)
{
- struct ipu_client_platformdata *pdata = pdev->dev.platform_data;
- struct ipu_crtc *ipu_crtc;
- int ret;
+ struct device_node *port;
+ int id, ret;
+
+ port = of_get_child_by_name(parent, "port");
+ while (port) {
+ ret = of_property_read_u32(port, "reg", &id);
+ if (!ret && id == port_id)
+ return port;
+
+ do {
+ port = of_get_next_child(parent, port);
+ if (!port)
+ return NULL;
+ } while (of_node_cmp(port->name, "port"));
+ }
- if (!pdata)
- return -EINVAL;
+ return NULL;
+}
- ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (ret)
- return ret;
+static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
+{
+ struct ipu_client_platformdata *pdata = dev->platform_data;
+ struct drm_device *drm = data;
+ struct ipu_crtc *ipu_crtc;
+ int ret;
- ipu_crtc = devm_kzalloc(&pdev->dev, sizeof(*ipu_crtc), GFP_KERNEL);
+ ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
if (!ipu_crtc)
return -ENOMEM;
- ipu_crtc->dev = &pdev->dev;
+ ipu_crtc->dev = dev;
- ret = ipu_crtc_init(ipu_crtc, pdata);
+ ret = ipu_crtc_init(ipu_crtc, pdata, drm);
if (ret)
return ret;
- platform_set_drvdata(pdev, ipu_crtc);
+ dev_set_drvdata(dev, ipu_crtc);
return 0;
}
-static int ipu_drm_remove(struct platform_device *pdev)
+static void ipu_drm_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct ipu_crtc *ipu_crtc = platform_get_drvdata(pdev);
+ struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
imx_drm_remove_crtc(ipu_crtc->imx_crtc);
ipu_plane_put_resources(ipu_crtc->plane[0]);
ipu_put_resources(ipu_crtc);
+}
+
+static const struct component_ops ipu_crtc_ops = {
+ .bind = ipu_drm_bind,
+ .unbind = ipu_drm_unbind,
+};
+static int ipu_drm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ipu_client_platformdata *pdata = dev->platform_data;
+ int ret;
+
+ if (!dev->platform_data)
+ return -EINVAL;
+
+ if (!dev->of_node) {
+ /* Associate crtc device with the corresponding DI port node */
+ dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node,
+ pdata->di + 2);
+ if (!dev->of_node) {
+ dev_err(dev, "missing port@%d node in %s\n",
+ pdata->di + 2, dev->parent->of_node->full_name);
+ return -ENODEV;
+ }
+ }
+
+ ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ return component_add(dev, &ipu_crtc_ops);
+}
+
+static int ipu_drm_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &ipu_crtc_ops);
return 0;
}
diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
index 34b642a12f8b..b0c9b6ce4854 100644
--- a/drivers/staging/imx-drm/ipuv3-plane.c
+++ b/drivers/staging/imx-drm/ipuv3-plane.c
@@ -72,8 +72,8 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
return -EFAULT;
}
- dev_dbg(ipu_plane->base.dev->dev, "phys = 0x%x, x = %d, y = %d",
- cma_obj->paddr, x, y);
+ dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
+ &cma_obj->paddr, x, y);
cpmem = ipu_get_cpmem(ipu_plane->ipu_ch);
ipu_cpmem_set_stride(cpmem, fb->pitches[0]);
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 351d61dede00..c60b6c645f42 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -18,10 +18,12 @@
* MA 02110-1301, USA.
*/
+#include <linux/component.h>
#include <linux/module.h>
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
#include <linux/videodev2.h>
#include <video/of_display_timing.h>
@@ -32,15 +34,14 @@
struct imx_parallel_display {
struct drm_connector connector;
- struct imx_drm_connector *imx_drm_connector;
struct drm_encoder encoder;
- struct imx_drm_encoder *imx_drm_encoder;
struct device *dev;
void *edid;
int edid_len;
u32 interface_pix_fmt;
int mode_valid;
struct drm_display_mode mode;
+ struct drm_panel *panel;
};
static enum drm_connector_status imx_pd_connector_detect(
@@ -49,17 +50,19 @@ static enum drm_connector_status imx_pd_connector_detect(
return connector_status_connected;
}
-static void imx_pd_connector_destroy(struct drm_connector *connector)
-{
- /* do not free here */
-}
-
static int imx_pd_connector_get_modes(struct drm_connector *connector)
{
struct imx_parallel_display *imxpd = con_to_imxpd(connector);
struct device_node *np = imxpd->dev->of_node;
int num_modes = 0;
+ if (imxpd->panel && imxpd->panel->funcs &&
+ imxpd->panel->funcs->get_modes) {
+ num_modes = imxpd->panel->funcs->get_modes(imxpd->panel);
+ if (num_modes > 0)
+ return num_modes;
+ }
+
if (imxpd->edid) {
drm_mode_connector_update_edid_property(connector, imxpd->edid);
num_modes = drm_add_edid_modes(connector, imxpd->edid);
@@ -67,6 +70,8 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
if (imxpd->mode_valid) {
struct drm_display_mode *mode = drm_mode_create(connector->dev);
+ if (!mode)
+ return -EINVAL;
drm_mode_copy(mode, &imxpd->mode);
mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
drm_mode_probed_add(connector, mode);
@@ -75,6 +80,8 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
if (np) {
struct drm_display_mode *mode = drm_mode_create(connector->dev);
+ if (!mode)
+ return -EINVAL;
of_get_drm_display_mode(np, &imxpd->mode, OF_USE_NATIVE_MODE);
drm_mode_copy(mode, &imxpd->mode);
mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
@@ -85,12 +92,6 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
return num_modes;
}
-static int imx_pd_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- return 0;
-}
-
static struct drm_encoder *imx_pd_connector_best_encoder(
struct drm_connector *connector)
{
@@ -101,6 +102,12 @@ static struct drm_encoder *imx_pd_connector_best_encoder(
static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode)
{
+ struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
+
+ if (mode != DRM_MODE_DPMS_ON)
+ drm_panel_disable(imxpd->panel);
+ else
+ drm_panel_enable(imxpd->panel);
}
static bool imx_pd_encoder_mode_fixup(struct drm_encoder *encoder,
@@ -114,8 +121,7 @@ static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
{
struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
- imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
- imxpd->interface_pix_fmt);
+ imx_drm_panel_format(encoder, imxpd->interface_pix_fmt);
}
static void imx_pd_encoder_commit(struct drm_encoder *encoder)
@@ -132,26 +138,21 @@ static void imx_pd_encoder_disable(struct drm_encoder *encoder)
{
}
-static void imx_pd_encoder_destroy(struct drm_encoder *encoder)
-{
- /* do not free here */
-}
-
static struct drm_connector_funcs imx_pd_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_pd_connector_detect,
- .destroy = imx_pd_connector_destroy,
+ .destroy = imx_drm_connector_destroy,
};
static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
.get_modes = imx_pd_connector_get_modes,
.best_encoder = imx_pd_connector_best_encoder,
- .mode_valid = imx_pd_connector_mode_valid,
+ .mode_valid = imx_drm_connector_mode_valid,
};
static struct drm_encoder_funcs imx_pd_encoder_funcs = {
- .destroy = imx_pd_encoder_destroy,
+ .destroy = imx_drm_encoder_destroy,
};
static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
@@ -163,51 +164,46 @@ static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
.disable = imx_pd_encoder_disable,
};
-static int imx_pd_register(struct imx_parallel_display *imxpd)
+static int imx_pd_register(struct drm_device *drm,
+ struct imx_parallel_display *imxpd)
{
int ret;
- drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
-
- imxpd->connector.funcs = &imx_pd_connector_funcs;
- imxpd->encoder.funcs = &imx_pd_encoder_funcs;
-
- imxpd->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
- imxpd->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
+ ret = imx_drm_encoder_parse_of(drm, &imxpd->encoder,
+ imxpd->dev->of_node);
+ if (ret)
+ return ret;
drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs);
- ret = imx_drm_add_encoder(&imxpd->encoder, &imxpd->imx_drm_encoder,
- THIS_MODULE);
- if (ret) {
- dev_err(imxpd->dev, "adding encoder failed with %d\n", ret);
- return ret;
- }
+ drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs,
+ DRM_MODE_ENCODER_NONE);
drm_connector_helper_add(&imxpd->connector,
&imx_pd_connector_helper_funcs);
+ drm_connector_init(drm, &imxpd->connector, &imx_pd_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA);
- ret = imx_drm_add_connector(&imxpd->connector,
- &imxpd->imx_drm_connector, THIS_MODULE);
- if (ret) {
- imx_drm_remove_encoder(imxpd->imx_drm_encoder);
- dev_err(imxpd->dev, "adding connector failed with %d\n", ret);
- return ret;
- }
+ if (imxpd->panel)
+ drm_panel_attach(imxpd->panel, &imxpd->connector);
+
+ drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
imxpd->connector.encoder = &imxpd->encoder;
return 0;
}
-static int imx_pd_probe(struct platform_device *pdev)
+static int imx_pd_bind(struct device *dev, struct device *master, void *data)
{
- struct device_node *np = pdev->dev.of_node;
+ struct drm_device *drm = data;
+ struct device_node *np = dev->of_node;
+ struct device_node *panel_node;
const u8 *edidp;
struct imx_parallel_display *imxpd;
int ret;
const char *fmt;
- imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL);
+ imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
if (!imxpd)
return -ENOMEM;
@@ -225,30 +221,43 @@ static int imx_pd_probe(struct platform_device *pdev)
imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
}
- imxpd->dev = &pdev->dev;
+ panel_node = of_parse_phandle(np, "fsl,panel", 0);
+ if (panel_node)
+ imxpd->panel = of_drm_find_panel(panel_node);
- ret = imx_pd_register(imxpd);
+ imxpd->dev = dev;
+
+ ret = imx_pd_register(drm, imxpd);
if (ret)
return ret;
- ret = imx_drm_encoder_add_possible_crtcs(imxpd->imx_drm_encoder, np);
-
- platform_set_drvdata(pdev, imxpd);
+ dev_set_drvdata(dev, imxpd);
return 0;
}
-static int imx_pd_remove(struct platform_device *pdev)
+static void imx_pd_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct imx_parallel_display *imxpd = platform_get_drvdata(pdev);
- struct drm_connector *connector = &imxpd->connector;
- struct drm_encoder *encoder = &imxpd->encoder;
+ struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
- drm_mode_connector_detach_encoder(connector, encoder);
+ imxpd->encoder.funcs->destroy(&imxpd->encoder);
+ imxpd->connector.funcs->destroy(&imxpd->connector);
+}
- imx_drm_remove_connector(imxpd->imx_drm_connector);
- imx_drm_remove_encoder(imxpd->imx_drm_encoder);
+static const struct component_ops imx_pd_ops = {
+ .bind = imx_pd_bind,
+ .unbind = imx_pd_unbind,
+};
+static int imx_pd_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &imx_pd_ops);
+}
+
+static int imx_pd_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_pd_ops);
return 0;
}
diff --git a/drivers/staging/keucr/common.h b/drivers/staging/keucr/common.h
index cf347ccd6a6e..f0b977616cd5 100644
--- a/drivers/staging/keucr/common.h
+++ b/drivers/staging/keucr/common.h
@@ -1,14 +1,6 @@
#ifndef COMMON_INCD
#define COMMON_INCD
-typedef u8 BOOLEAN;
-typedef u8 BYTE;
-typedef u8 *PBYTE;
-typedef u16 WORD;
-typedef u16 *PWORD;
-typedef u32 DWORD;
-typedef u32 *PDWORD;
-
#define BYTE_MASK 0xff
#endif
diff --git a/drivers/staging/keucr/init.c b/drivers/staging/keucr/init.c
index f5d41e0348ce..e61183906548 100644
--- a/drivers/staging/keucr/init.c
+++ b/drivers/staging/keucr/init.c
@@ -17,7 +17,7 @@
int ENE_InitMedia(struct us_data *us)
{
int result;
- BYTE MiscReg03 = 0;
+ u8 MiscReg03 = 0;
dev_info(&us->pusb_dev->dev, "--- Init Media ---\n");
result = ene_read_byte(us, REG_CARD_STATUS, &MiscReg03);
@@ -41,7 +41,7 @@ int ENE_InitMedia(struct us_data *us)
/*
* ene_read_byte() :
*/
-int ene_read_byte(struct us_data *us, WORD index, void *buf)
+int ene_read_byte(struct us_data *us, u16 index, void *buf)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
@@ -51,8 +51,8 @@ int ene_read_byte(struct us_data *us, WORD index, void *buf)
bcb->DataTransferLength = 0x01;
bcb->Flags = 0x80;
bcb->CDB[0] = 0xED;
- bcb->CDB[2] = (BYTE)(index>>8);
- bcb->CDB[3] = (BYTE)index;
+ bcb->CDB[2] = (u8)(index>>8);
+ bcb->CDB[3] = (u8)index;
result = ENE_SendScsiCmd(us, FDIR_READ, buf, 0);
return result;
@@ -65,7 +65,7 @@ int ENE_SMInit(struct us_data *us)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
- BYTE buf[0x200];
+ u8 buf[0x200];
dev_dbg(&us->pusb_dev->dev, "transport --- ENE_SMInit\n");
@@ -122,12 +122,12 @@ int ENE_SMInit(struct us_data *us)
/*
* ENE_LoadBinCode()
*/
-int ENE_LoadBinCode(struct us_data *us, BYTE flag)
+int ENE_LoadBinCode(struct us_data *us, u8 flag)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
/* void *buf; */
- PBYTE buf;
+ u8 *buf;
/* dev_info(&us->pusb_dev->dev, "transport --- ENE_LoadBinCode\n"); */
if (us->BIN_FLAG == flag)
@@ -164,7 +164,7 @@ int ENE_LoadBinCode(struct us_data *us, BYTE flag)
/*
* ENE_SendScsiCmd():
*/
-int ENE_SendScsiCmd(struct us_data *us, BYTE fDir, void *buf, int use_sg)
+int ENE_SendScsiCmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
diff --git a/drivers/staging/keucr/init.h b/drivers/staging/keucr/init.h
index c8b2cd604460..98d2e3ba8545 100644
--- a/drivers/staging/keucr/init.h
+++ b/drivers/staging/keucr/init.h
@@ -1,11 +1,11 @@
#include "common.h"
-extern DWORD MediaChange;
+extern u32 MediaChange;
extern int Check_D_MediaFmt(struct us_data *);
-static BYTE SM_Init[] = {
+static u8 SM_Init[] = {
0x7B, 0x09, 0x7C, 0xF0, 0x7D, 0x10, 0x7E, 0xE9,
0x7F, 0xCC, 0x12, 0x2F, 0x71, 0x90, 0xE9, 0xCC,
0xE0, 0xB4, 0x07, 0x12, 0x90, 0xFF, 0x09, 0xE0,
@@ -263,7 +263,7 @@ static BYTE SM_Init[] = {
0x58, 0x44, 0x2D, 0x49, 0x6E, 0x69, 0x74, 0x20,
0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x30, 0x31 };
-static BYTE SM_Rdwr[] = {
+static u8 SM_Rdwr[] = {
0x7B, 0x0C, 0x7C, 0xF0, 0x7D, 0x10, 0x7E, 0xE9,
0x7F, 0xCC, 0x12, 0x2F, 0x71, 0x90, 0xE9, 0xC3,
0xE0, 0xB4, 0x73, 0x04, 0x74, 0x40, 0x80, 0x09,
diff --git a/drivers/staging/keucr/smil.h b/drivers/staging/keucr/smil.h
index 9136e9447261..39951738d231 100644
--- a/drivers/staging/keucr/smil.h
+++ b/drivers/staging/keucr/smil.h
@@ -169,29 +169,29 @@ SmartMedia Model & Attribute
Struct Definition
***************************************************************************/
struct keucr_media_info {
- BYTE Model;
- BYTE Attribute;
- BYTE MaxZones;
- BYTE MaxSectors;
- WORD MaxBlocks;
- WORD MaxLogBlocks;
+ u8 Model;
+ u8 Attribute;
+ u8 MaxZones;
+ u8 MaxSectors;
+ u16 MaxBlocks;
+ u16 MaxLogBlocks;
};
struct keucr_media_address {
- BYTE Zone; /* Zone Number */
- BYTE Sector; /* Sector(512byte) Number on Block */
- WORD PhyBlock; /* Physical Block Number on Zone */
- WORD LogBlock; /* Logical Block Number of Zone */
+ u8 Zone; /* Zone Number */
+ u8 Sector; /* Sector(512byte) Number on Block */
+ u16 PhyBlock; /* Physical Block Number on Zone */
+ u16 LogBlock; /* Logical Block Number of Zone */
};
struct keucr_media_area {
- BYTE Sector; /* Sector(512byte) Number on Block */
- WORD PhyBlock; /* Physical Block Number on Zone 0 */
+ u8 Sector; /* Sector(512byte) Number on Block */
+ u16 PhyBlock; /* Physical Block Number on Zone 0 */
};
-extern WORD ReadBlock;
-extern WORD WriteBlock;
-extern DWORD MediaChange;
+extern u16 ReadBlock;
+extern u16 WriteBlock;
+extern u32 MediaChange;
extern struct keucr_media_info Ssfdc;
extern struct keucr_media_address Media;
@@ -204,24 +204,24 @@ extern struct keucr_media_area CisArea;
int Init_D_SmartMedia(void);
int Pwoff_D_SmartMedia(void);
int Check_D_SmartMedia(void);
-int Check_D_Parameter(struct us_data *, WORD *, BYTE *, BYTE *);
-int Media_D_ReadSector(struct us_data *, DWORD, WORD, BYTE *);
-int Media_D_WriteSector(struct us_data *, DWORD, WORD, BYTE *);
-int Media_D_CopySector(struct us_data *, DWORD, WORD, BYTE *);
-int Media_D_EraseBlock(struct us_data *, DWORD, WORD);
+int Check_D_Parameter(struct us_data *, u16 *, u8 *, u8 *);
+int Media_D_ReadSector(struct us_data *, u32, u16, u8 *);
+int Media_D_WriteSector(struct us_data *, u32, u16, u8 *);
+int Media_D_CopySector(struct us_data *, u32, u16, u8 *);
+int Media_D_EraseBlock(struct us_data *, u32, u16);
int Media_D_EraseAll(struct us_data *);
/******************************************/
-int Media_D_OneSectWriteStart(struct us_data *, DWORD, BYTE *);
-int Media_D_OneSectWriteNext(struct us_data *, BYTE *);
+int Media_D_OneSectWriteStart(struct us_data *, u32, u8 *);
+int Media_D_OneSectWriteNext(struct us_data *, u8 *);
int Media_D_OneSectWriteFlush(struct us_data *);
/******************************************/
extern int SM_FreeMem(void); /* ENE SM function */
-void SM_EnableLED(struct us_data *, BOOLEAN);
+void SM_EnableLED(struct us_data *, bool);
void Led_D_TernOn(void);
void Led_D_TernOff(void);
-int Media_D_EraseAllRedtData(DWORD Index, BOOLEAN CheckBlock);
+int Media_D_EraseAllRedtData(u32 Index, bool CheckBlock);
/*DWORD Media_D_GetMediaInfo(struct us_data * fdoExt,
PIOCTL_MEDIA_INFO_IN pParamIn, PIOCTL_MEDIA_INFO_OUT pParamOut); */
@@ -229,31 +229,31 @@ int Media_D_EraseAllRedtData(DWORD Index, BOOLEAN CheckBlock);
* SMILSub.c
*/
/******************************************/
-int Check_D_DataBlank(BYTE *);
-int Check_D_FailBlock(BYTE *);
-int Check_D_DataStatus(BYTE *);
-int Load_D_LogBlockAddr(BYTE *);
-void Clr_D_RedundantData(BYTE *);
-void Set_D_LogBlockAddr(BYTE *);
-void Set_D_FailBlock(BYTE *);
-void Set_D_DataStaus(BYTE *);
+int Check_D_DataBlank(u8 *);
+int Check_D_FailBlock(u8 *);
+int Check_D_DataStatus(u8 *);
+int Load_D_LogBlockAddr(u8 *);
+void Clr_D_RedundantData(u8 *);
+void Set_D_LogBlockAddr(u8 *);
+void Set_D_FailBlock(u8 *);
+void Set_D_DataStaus(u8 *);
/******************************************/
void Ssfdc_D_Reset(struct us_data *);
-int Ssfdc_D_ReadCisSect(struct us_data *, BYTE *, BYTE *);
+int Ssfdc_D_ReadCisSect(struct us_data *, u8 *, u8 *);
void Ssfdc_D_WriteRedtMode(void);
-void Ssfdc_D_ReadID(BYTE *, BYTE);
-int Ssfdc_D_ReadSect(struct us_data *, BYTE *, BYTE *);
-int Ssfdc_D_ReadBlock(struct us_data *, WORD, BYTE *, BYTE *);
-int Ssfdc_D_WriteSect(struct us_data *, BYTE *, BYTE *);
-int Ssfdc_D_WriteBlock(struct us_data *, WORD, BYTE *, BYTE *);
-int Ssfdc_D_CopyBlock(struct us_data *, WORD, BYTE *, BYTE *);
-int Ssfdc_D_WriteSectForCopy(struct us_data *, BYTE *, BYTE *);
+void Ssfdc_D_ReadID(u8 *, u8);
+int Ssfdc_D_ReadSect(struct us_data *, u8 *, u8 *);
+int Ssfdc_D_ReadBlock(struct us_data *, u16, u8 *, u8 *);
+int Ssfdc_D_WriteSect(struct us_data *, u8 *, u8 *);
+int Ssfdc_D_WriteBlock(struct us_data *, u16, u8 *, u8 *);
+int Ssfdc_D_CopyBlock(struct us_data *, u16, u8 *, u8 *);
+int Ssfdc_D_WriteSectForCopy(struct us_data *, u8 *, u8 *);
int Ssfdc_D_EraseBlock(struct us_data *);
-int Ssfdc_D_ReadRedtData(struct us_data *, BYTE *);
-int Ssfdc_D_WriteRedtData(struct us_data *, BYTE *);
+int Ssfdc_D_ReadRedtData(struct us_data *, u8 *);
+int Ssfdc_D_WriteRedtData(struct us_data *, u8 *);
int Ssfdc_D_CheckStatus(void);
-int Set_D_SsfdcModel(BYTE);
+int Set_D_SsfdcModel(u8);
void Cnt_D_Reset(void);
int Cnt_D_PowerOn(void);
void Cnt_D_PowerOff(void);
@@ -263,26 +263,26 @@ int Check_D_CntPower(void);
int Check_D_CardExist(void);
int Check_D_CardStsChg(void);
int Check_D_SsfdcWP(void);
-int SM_ReadBlock(struct us_data *, BYTE *, BYTE *);
+int SM_ReadBlock(struct us_data *, u8 *, u8 *);
-int Ssfdc_D_ReadSect_DMA(struct us_data *, BYTE *, BYTE *);
-int Ssfdc_D_ReadSect_PIO(struct us_data *, BYTE *, BYTE *);
-int Ssfdc_D_WriteSect_DMA(struct us_data *, BYTE *, BYTE *);
-int Ssfdc_D_WriteSect_PIO(struct us_data *, BYTE *, BYTE *);
+int Ssfdc_D_ReadSect_DMA(struct us_data *, u8 *, u8 *);
+int Ssfdc_D_ReadSect_PIO(struct us_data *, u8 *, u8 *);
+int Ssfdc_D_WriteSect_DMA(struct us_data *, u8 *, u8 *);
+int Ssfdc_D_WriteSect_PIO(struct us_data *, u8 *, u8 *);
/******************************************/
-int Check_D_ReadError(BYTE *);
-int Check_D_Correct(BYTE *, BYTE *);
-int Check_D_CISdata(BYTE *, BYTE *);
-void Set_D_RightECC(BYTE *);
+int Check_D_ReadError(u8 *);
+int Check_D_Correct(u8 *, u8 *);
+int Check_D_CISdata(u8 *, u8 *);
+void Set_D_RightECC(u8 *);
/*
* SMILECC.c
*/
-void calculate_ecc(BYTE *, BYTE *, BYTE *, BYTE *, BYTE *);
-BYTE correct_data(BYTE *, BYTE *, BYTE, BYTE, BYTE);
-int _Correct_D_SwECC(BYTE *, BYTE *, BYTE *);
-void _Calculate_D_SwECC(BYTE *, BYTE *);
+void calculate_ecc(u8 *, u8 *, u8 *, u8 *, u8 *);
+u8 correct_data(u8 *, u8 *, u8, u8, u8);
+int _Correct_D_SwECC(u8 *, u8 *, u8 *);
+void _Calculate_D_SwECC(u8 *, u8 *);
void SM_Init(void);
diff --git a/drivers/staging/keucr/smilecc.c b/drivers/staging/keucr/smilecc.c
index 6b8f7d7a7436..ffe6030f5e4d 100644
--- a/drivers/staging/keucr/smilecc.c
+++ b/drivers/staging/keucr/smilecc.c
@@ -13,7 +13,7 @@
/* #include "EMCRIOS.h" */
/* CP0-CP5 code table */
-static BYTE ecctable[256] = {
+static u8 ecctable[256] = {
0x00, 0x55, 0x56, 0x03, 0x59, 0x0C, 0x0F, 0x5A, 0x5A, 0x0F, 0x0C, 0x59, 0x03,
0x56, 0x55, 0x00, 0x65, 0x30, 0x33, 0x66, 0x3C, 0x69, 0x6A, 0x3F, 0x3F, 0x6A,
0x69, 0x3C, 0x66, 0x33, 0x30, 0x65, 0x66, 0x33, 0x30, 0x65, 0x3F, 0x6A, 0x69,
@@ -36,7 +36,7 @@ static BYTE ecctable[256] = {
0x5A, 0x5A, 0x0F, 0x0C, 0x59, 0x03, 0x56, 0x55, 0x00
};
-static void trans_result(BYTE, BYTE, BYTE *, BYTE *);
+static void trans_result(u8, u8, u8 *, u8 *);
#define BIT7 0x80
#define BIT6 0x40
@@ -57,11 +57,11 @@ static void trans_result(BYTE, BYTE, BYTE *, BYTE *);
* *ecc1; * LP15,LP14,LP13,...
* *ecc2; * LP07,LP06,LP05,...
*/
-static void trans_result(BYTE reg2, BYTE reg3, BYTE *ecc1, BYTE *ecc2)
+static void trans_result(u8 reg2, u8 reg3, u8 *ecc1, u8 *ecc2)
{
- BYTE a; /* Working for reg2,reg3 */
- BYTE b; /* Working for ecc1,ecc2 */
- BYTE i; /* For counting */
+ u8 a; /* Working for reg2,reg3 */
+ u8 b; /* Working for ecc1,ecc2 */
+ u8 i; /* For counting */
a = BIT7; b = BIT7; /* 80h=10000000b */
*ecc1 = *ecc2 = 0; /* Clear ecc1,ecc2 */
@@ -95,21 +95,21 @@ static void trans_result(BYTE reg2, BYTE reg3, BYTE *ecc1, BYTE *ecc2)
* *ecc2; * LP07,LP06,LP05,...
* *ecc3; * CP5,CP4,CP3,...,"1","1"
*/
-void calculate_ecc(BYTE *table, BYTE *data, BYTE *ecc1, BYTE *ecc2, BYTE *ecc3)
+void calculate_ecc(u8 *table, u8 *data, u8 *ecc1, u8 *ecc2, u8 *ecc3)
{
- DWORD i; /* For counting */
- BYTE a; /* Working for table */
- BYTE reg1; /* D-all,CP5,CP4,CP3,... */
- BYTE reg2; /* LP14,LP12,L10,... */
- BYTE reg3; /* LP15,LP13,L11,... */
+ u32 i; /* For counting */
+ u8 a; /* Working for table */
+ u8 reg1; /* D-all,CP5,CP4,CP3,... */
+ u8 reg2; /* LP14,LP12,L10,... */
+ u8 reg3; /* LP15,LP13,L11,... */
reg1 = reg2 = reg3 = 0; /* Clear parameter */
for (i = 0; i < 256; ++i) {
a = table[data[i]]; /* Get CP0-CP5 code from table */
reg1 ^= (a&MASK_CPS); /* XOR with a */
if ((a&BIT6) != 0) { /* If D_all(all bit XOR) = 1 */
- reg3 ^= (BYTE)i; /* XOR with counter */
- reg2 ^= ~((BYTE)i); /* XOR with inv. of counter */
+ reg3 ^= (u8)i; /* XOR with counter */
+ reg2 ^= ~((u8)i); /* XOR with inv. of counter */
}
}
@@ -127,22 +127,22 @@ void calculate_ecc(BYTE *table, BYTE *data, BYTE *ecc1, BYTE *ecc2, BYTE *ecc3)
* ecc2; * LP07,LP06,LP05,...
* ecc3; * CP5,CP4,CP3,...,"1","1"
*/
-BYTE correct_data(BYTE *data, BYTE *eccdata, BYTE ecc1, BYTE ecc2, BYTE ecc3)
+u8 correct_data(u8 *data, u8 *eccdata, u8 ecc1, u8 ecc2, u8 ecc3)
{
- DWORD l; /* Working to check d */
- DWORD d; /* Result of comparison */
- DWORD i; /* For counting */
- BYTE d1, d2, d3; /* Result of comparison */
- BYTE a; /* Working for add */
- BYTE add; /* Byte address of cor. DATA */
- BYTE b; /* Working for bit */
- BYTE bit; /* Bit address of cor. DATA */
+ u32 l; /* Working to check d */
+ u32 d; /* Result of comparison */
+ u32 i; /* For counting */
+ u8 d1, d2, d3; /* Result of comparison */
+ u8 a; /* Working for add */
+ u8 add; /* Byte address of cor. DATA */
+ u8 b; /* Working for bit */
+ u8 bit; /* Bit address of cor. DATA */
d1 = ecc1^eccdata[1]; d2 = ecc2^eccdata[0]; /* Compare LP's */
d3 = ecc3^eccdata[2]; /* Compare CP's */
- d = ((DWORD)d1<<16) /* Result of comparison */
- +((DWORD)d2<<8)
- +(DWORD)d3;
+ d = ((u32)d1<<16) /* Result of comparison */
+ +((u32)d2<<8)
+ +(u32)d3;
if (d == 0)
return 0; /* If No error, return */
@@ -188,9 +188,9 @@ BYTE correct_data(BYTE *data, BYTE *eccdata, BYTE ecc1, BYTE ecc2, BYTE ecc3)
return 3; /* Uncorrectable error */
}
-int _Correct_D_SwECC(BYTE *buf, BYTE *redundant_ecc, BYTE *calculate_ecc)
+int _Correct_D_SwECC(u8 *buf, u8 *redundant_ecc, u8 *calculate_ecc)
{
- DWORD err;
+ u32 err;
err = correct_data(buf, redundant_ecc, *(calculate_ecc + 1),
*(calculate_ecc), *(calculate_ecc + 2));
@@ -203,7 +203,7 @@ int _Correct_D_SwECC(BYTE *buf, BYTE *redundant_ecc, BYTE *calculate_ecc)
return -1;
}
-void _Calculate_D_SwECC(BYTE *buf, BYTE *ecc)
+void _Calculate_D_SwECC(u8 *buf, u8 *ecc)
{
calculate_ecc(ecctable, buf, ecc+1, ecc+0, ecc+2);
}
diff --git a/drivers/staging/keucr/smilmain.c b/drivers/staging/keucr/smilmain.c
index 09d07e05102f..fc7cbc6f8a45 100644
--- a/drivers/staging/keucr/smilmain.c
+++ b/drivers/staging/keucr/smilmain.c
@@ -4,11 +4,11 @@
#include "smcommon.h"
#include "smil.h"
-static int Conv_D_MediaAddr(struct us_data *, DWORD);
+static int Conv_D_MediaAddr(struct us_data *, u32);
static int Inc_D_MediaAddr(struct us_data *);
-static int Media_D_ReadOneSect(struct us_data *, WORD, BYTE *);
+static int Media_D_ReadOneSect(struct us_data *, u16, u8 *);
-static int Copy_D_BlockAll(struct us_data *, DWORD);
+static int Copy_D_BlockAll(struct us_data *, u32);
static int Assign_D_WriteBlock(void);
static int Release_D_ReadBlock(struct us_data *);
@@ -16,7 +16,7 @@ static int Release_D_WriteBlock(struct us_data *);
static int Release_D_CopySector(struct us_data *);
static int Copy_D_PhyOneSect(struct us_data *);
-static int Read_D_PhyOneSect(struct us_data *, WORD, BYTE *);
+static int Read_D_PhyOneSect(struct us_data *, u16, u8 *);
static int Erase_D_PhyOneBlock(struct us_data *);
static int Set_D_PhyFmtValue(struct us_data *);
@@ -25,24 +25,24 @@ static int Make_D_LogTable(struct us_data *);
static int MarkFail_D_PhyOneBlock(struct us_data *);
-static DWORD ErrCode;
-static BYTE WorkBuf[SECTSIZE];
-static BYTE Redundant[REDTSIZE];
-static BYTE WorkRedund[REDTSIZE];
+static u32 ErrCode;
+static u8 WorkBuf[SECTSIZE];
+static u8 Redundant[REDTSIZE];
+static u8 WorkRedund[REDTSIZE];
/* 128 x 1000, Log2Phy[MAX_ZONENUM][MAX_LOGBLOCK]; */
-static WORD *Log2Phy[MAX_ZONENUM];
-static BYTE Assign[MAX_ZONENUM][MAX_BLOCKNUM / 8];
-static WORD AssignStart[MAX_ZONENUM];
-WORD ReadBlock;
-WORD WriteBlock;
-DWORD MediaChange;
-static DWORD SectCopyMode;
+static u16 *Log2Phy[MAX_ZONENUM];
+static u8 Assign[MAX_ZONENUM][MAX_BLOCKNUM / 8];
+static u16 AssignStart[MAX_ZONENUM];
+u16 ReadBlock;
+u16 WriteBlock;
+u32 MediaChange;
+static u32 SectCopyMode;
/* BIT Control Macro */
-static BYTE BitData[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
-#define Set_D_Bit(a, b) (a[(BYTE)((b) / 8)] |= BitData[(b) % 8])
-#define Clr_D_Bit(a, b) (a[(BYTE)((b) / 8)] &= ~BitData[(b) % 8])
-#define Chk_D_Bit(a, b) (a[(BYTE)((b) / 8)] & BitData[(b) % 8])
+static u8 BitData[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+#define Set_D_Bit(a, b) (a[(u8)((b) / 8)] |= BitData[(b) % 8])
+#define Clr_D_Bit(a, b) (a[(u8)((b) / 8)] &= ~BitData[(b) % 8])
+#define Chk_D_Bit(a, b) (a[(u8)((b) / 8)] & BitData[(b) % 8])
/* ----- SM_FreeMem() ------------------------------------------------- */
int SM_FreeMem(void)
@@ -62,9 +62,9 @@ int SM_FreeMem(void)
/* SmartMedia Read/Write/Erase Function */
/* ----- Media_D_ReadSector() ------------------------------------------- */
-int Media_D_ReadSector(struct us_data *us, DWORD start, WORD count, BYTE *buf)
+int Media_D_ReadSector(struct us_data *us, u32 start, u16 count, u8 *buf)
{
- WORD len, bn;
+ u16 len, bn;
if (Conv_D_MediaAddr(us, start))
return ErrCode;
@@ -97,9 +97,9 @@ int Media_D_ReadSector(struct us_data *us, DWORD start, WORD count, BYTE *buf)
}
/* here */
/* ----- Media_D_CopySector() ------------------------------------------ */
-int Media_D_CopySector(struct us_data *us, DWORD start, WORD count, BYTE *buf)
+int Media_D_CopySector(struct us_data *us, u32 start, u16 count, u8 *buf)
{
- WORD len, bn;
+ u16 len, bn;
/* pr_info("Media_D_CopySector !!!\n"); */
if (Conv_D_MediaAddr(us, start))
@@ -186,12 +186,12 @@ int Check_D_MediaFmt(struct us_data *us)
/* SmartMedia Physical Address Control Subroutine */
/* ----- Conv_D_MediaAddr() --------------------------------------------- */
-static int Conv_D_MediaAddr(struct us_data *us, DWORD addr)
+static int Conv_D_MediaAddr(struct us_data *us, u32 addr)
{
- DWORD temp;
+ u32 temp;
temp = addr / Ssfdc.MaxSectors;
- Media.Zone = (BYTE) (temp / Ssfdc.MaxLogBlocks);
+ Media.Zone = (u8) (temp / Ssfdc.MaxLogBlocks);
if (Log2Phy[Media.Zone] == NULL) {
if (Make_D_LogTable(us)) {
@@ -200,8 +200,8 @@ static int Conv_D_MediaAddr(struct us_data *us, DWORD addr)
}
}
- Media.Sector = (BYTE) (addr % Ssfdc.MaxSectors);
- Media.LogBlock = (WORD) (temp % Ssfdc.MaxLogBlocks);
+ Media.Sector = (u8) (addr % Ssfdc.MaxSectors);
+ Media.LogBlock = (u16) (temp % Ssfdc.MaxLogBlocks);
if (Media.Zone < Ssfdc.MaxZones) {
Clr_D_RedundantData(Redundant);
@@ -217,7 +217,7 @@ static int Conv_D_MediaAddr(struct us_data *us, DWORD addr)
/* ----- Inc_D_MediaAddr() ---------------------------------------------- */
static int Inc_D_MediaAddr(struct us_data *us)
{
- WORD LogBlock = Media.LogBlock;
+ u16 LogBlock = Media.LogBlock;
if (++Media.Sector < Ssfdc.MaxSectors)
return SMSUCCESS;
@@ -265,9 +265,9 @@ static int Inc_D_MediaAddr(struct us_data *us)
/* SmartMedia Read/Write Subroutine with Retry */
/* ----- Media_D_ReadOneSect() ------------------------------------------ */
-static int Media_D_ReadOneSect(struct us_data *us, WORD count, BYTE *buf)
+static int Media_D_ReadOneSect(struct us_data *us, u16 count, u8 *buf)
{
- DWORD err, retry;
+ u32 err, retry;
if (!Read_D_PhyOneSect(us, count, buf))
return SMSUCCESS;
@@ -309,9 +309,9 @@ static int Media_D_ReadOneSect(struct us_data *us, WORD count, BYTE *buf)
/* SmartMedia Physical Sector Data Copy Subroutine */
/* ----- Copy_D_BlockAll() ---------------------------------------------- */
-static int Copy_D_BlockAll(struct us_data *us, DWORD mode)
+static int Copy_D_BlockAll(struct us_data *us, u32 mode)
{
- BYTE sect;
+ u8 sect;
sect = Media.Sector;
@@ -381,7 +381,7 @@ static int Assign_D_WriteBlock(void)
/* ----- Release_D_ReadBlock() ------------------------------------------ */
static int Release_D_ReadBlock(struct us_data *us)
{
- DWORD mode;
+ u32 mode;
mode = SectCopyMode;
SectCopyMode = COMPLETED;
@@ -430,7 +430,7 @@ static int Release_D_WriteBlock(struct us_data *us)
static int Copy_D_PhyOneSect(struct us_data *us)
{
int i;
- DWORD err, retry;
+ u32 err, retry;
/* pr_info("Copy_D_PhyOneSect --- Sector = %x\n", Media.Sector); */
if (ReadBlock != NO_ASSIGN) {
@@ -504,10 +504,10 @@ static int Copy_D_PhyOneSect(struct us_data *us)
/* SmartMedia Physical Sector Read/Write/Erase Subroutine */
/* ----- Read_D_PhyOneSect() -------------------------------------------- */
-static int Read_D_PhyOneSect(struct us_data *us, WORD count, BYTE *buf)
+static int Read_D_PhyOneSect(struct us_data *us, u16 count, u8 *buf)
{
int i;
- DWORD retry;
+ u32 retry;
if (Media.PhyBlock == NO_ASSIGN) {
for (i = 0; i < SECTSIZE; i++)
@@ -637,10 +637,10 @@ static int Search_D_CIS(struct us_data *us)
/* ----- Make_D_LogTable() ---------------------------------------------- */
static int Make_D_LogTable(struct us_data *us)
{
- WORD phyblock, logblock;
+ u16 phyblock, logblock;
if (Log2Phy[Media.Zone] == NULL) {
- Log2Phy[Media.Zone] = kmalloc(MAX_LOGBLOCK * sizeof(WORD),
+ Log2Phy[Media.Zone] = kmalloc(MAX_LOGBLOCK * sizeof(u16),
GFP_KERNEL);
/* pr_info("ExAllocatePool Zone = %x, Addr = %x\n",
Media.Zone, Log2Phy[Media.Zone]); */
@@ -693,7 +693,7 @@ static int Make_D_LogTable(struct us_data *us)
phyblock = Media.PhyBlock;
logblock = Media.LogBlock;
- Media.Sector = (BYTE)(Ssfdc.MaxSectors - 1);
+ Media.Sector = (u8)(Ssfdc.MaxSectors - 1);
if (Ssfdc_D_ReadRedtData(us, Redundant)) {
Ssfdc_D_Reset(us);
@@ -738,7 +738,7 @@ static int Make_D_LogTable(struct us_data *us)
/* ----- MarkFail_D_PhyOneBlock() --------------------------------------- */
static int MarkFail_D_PhyOneBlock(struct us_data *us)
{
- BYTE sect;
+ u8 sect;
sect = Media.Sector;
Set_D_FailBlock(WorkRedund);
diff --git a/drivers/staging/keucr/smilsub.c b/drivers/staging/keucr/smilsub.c
index 16da9a9b4033..44ced8265039 100644
--- a/drivers/staging/keucr/smilsub.c
+++ b/drivers/staging/keucr/smilsub.c
@@ -6,16 +6,16 @@
#include "smcommon.h"
#include "smil.h"
-static BYTE _Check_D_DevCode(BYTE);
-static DWORD ErrXDCode;
-static BYTE IsSSFDCCompliance;
-static BYTE IsXDCompliance;
+static u8 _Check_D_DevCode(u8);
+static u32 ErrXDCode;
+static u8 IsSSFDCCompliance;
+static u8 IsXDCompliance;
struct keucr_media_info Ssfdc;
struct keucr_media_address Media;
struct keucr_media_area CisArea;
-static BYTE EccBuf[6];
+static u8 EccBuf[6];
#define EVEN 0 /* Even Page for 256byte/page */
#define ODD 1 /* Odd Page for 256byte/page */
@@ -24,7 +24,7 @@ static BYTE EccBuf[6];
/* SmartMedia Redundant buffer data Control Subroutine
*----- Check_D_DataBlank() --------------------------------------------
*/
-int Check_D_DataBlank(BYTE *redundant)
+int Check_D_DataBlank(u8 *redundant)
{
char i;
@@ -36,7 +36,7 @@ int Check_D_DataBlank(BYTE *redundant)
}
/* ----- Check_D_FailBlock() -------------------------------------------- */
-int Check_D_FailBlock(BYTE *redundant)
+int Check_D_FailBlock(u8 *redundant)
{
redundant += REDT_BLOCK;
@@ -51,7 +51,7 @@ int Check_D_FailBlock(BYTE *redundant)
}
/* ----- Check_D_DataStatus() ------------------------------------------- */
-int Check_D_DataStatus(BYTE *redundant)
+int Check_D_DataStatus(u8 *redundant)
{
redundant += REDT_DATA;
@@ -70,14 +70,14 @@ int Check_D_DataStatus(BYTE *redundant)
}
/* ----- Load_D_LogBlockAddr() ------------------------------------------ */
-int Load_D_LogBlockAddr(BYTE *redundant)
+int Load_D_LogBlockAddr(u8 *redundant)
{
- WORD addr1, addr2;
+ u16 addr1, addr2;
- addr1 = (WORD)*(redundant + REDT_ADDR1H)*0x0100 +
- (WORD)*(redundant + REDT_ADDR1L);
- addr2 = (WORD)*(redundant + REDT_ADDR2H)*0x0100 +
- (WORD)*(redundant + REDT_ADDR2L);
+ addr1 = (u16)*(redundant + REDT_ADDR1H)*0x0100 +
+ (u16)*(redundant + REDT_ADDR1L);
+ addr2 = (u16)*(redundant + REDT_ADDR2H)*0x0100 +
+ (u16)*(redundant + REDT_ADDR2L);
if (addr1 == addr2)
if ((addr1 & 0xF000) == 0x1000) {
@@ -85,7 +85,7 @@ int Load_D_LogBlockAddr(BYTE *redundant)
return SMSUCCESS;
}
- if (hweight16((WORD)(addr1^addr2)) != 0x01)
+ if (hweight16((u16)(addr1^addr2)) != 0x01)
return ERROR;
if ((addr1 & 0xF000) == 0x1000)
@@ -104,7 +104,7 @@ int Load_D_LogBlockAddr(BYTE *redundant)
}
/* ----- Clr_D_RedundantData() ------------------------------------------ */
-void Clr_D_RedundantData(BYTE *redundant)
+void Clr_D_RedundantData(u8 *redundant)
{
char i;
@@ -113,9 +113,9 @@ void Clr_D_RedundantData(BYTE *redundant)
}
/* ----- Set_D_LogBlockAddr() ------------------------------------------- */
-void Set_D_LogBlockAddr(BYTE *redundant)
+void Set_D_LogBlockAddr(u8 *redundant)
{
- WORD addr;
+ u16 addr;
*(redundant + REDT_BLOCK) = 0xFF;
*(redundant + REDT_DATA) = 0xFF;
@@ -125,20 +125,20 @@ void Set_D_LogBlockAddr(BYTE *redundant)
addr++;
*(redundant + REDT_ADDR1H) = *(redundant + REDT_ADDR2H) =
- (BYTE)(addr / 0x0100);
- *(redundant + REDT_ADDR1L) = *(redundant + REDT_ADDR2L) = (BYTE)addr;
+ (u8)(addr / 0x0100);
+ *(redundant + REDT_ADDR1L) = *(redundant + REDT_ADDR2L) = (u8)addr;
}
/*----- Set_D_FailBlock() ---------------------------------------------- */
-void Set_D_FailBlock(BYTE *redundant)
+void Set_D_FailBlock(u8 *redundant)
{
char i;
for (i = 0; i < REDTSIZE; i++)
- *redundant++ = (BYTE)((i == REDT_BLOCK) ? 0xF0 : 0xFF);
+ *redundant++ = (u8)((i == REDT_BLOCK) ? 0xF0 : 0xFF);
}
/* ----- Set_D_DataStaus() ---------------------------------------------- */
-void Set_D_DataStaus(BYTE *redundant)
+void Set_D_DataStaus(u8 *redundant)
{
redundant += REDT_DATA;
*redundant = 0x00;
@@ -154,10 +154,10 @@ void Ssfdc_D_Reset(struct us_data *us)
}
/* ----- Ssfdc_D_ReadCisSect() ------------------------------------------ */
-int Ssfdc_D_ReadCisSect(struct us_data *us, BYTE *buf, BYTE *redundant)
+int Ssfdc_D_ReadCisSect(struct us_data *us, u8 *buf, u8 *redundant)
{
- BYTE zone, sector;
- WORD block;
+ u8 zone, sector;
+ u16 block;
zone = Media.Zone; block = Media.PhyBlock; sector = Media.Sector;
Media.Zone = 0;
@@ -177,11 +177,11 @@ int Ssfdc_D_ReadCisSect(struct us_data *us, BYTE *buf, BYTE *redundant)
/* 6250 CMD 1 */
/* ----- Ssfdc_D_ReadSect() --------------------------------------------- */
-int Ssfdc_D_ReadSect(struct us_data *us, BYTE *buf, BYTE *redundant)
+int Ssfdc_D_ReadSect(struct us_data *us, u8 *buf, u8 *redundant)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
- WORD addr;
+ u16 addr;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
@@ -190,8 +190,8 @@ int Ssfdc_D_ReadSect(struct us_data *us, BYTE *buf, BYTE *redundant)
return USB_STOR_TRANSPORT_ERROR;
}
- addr = (WORD)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
- addr = addr*(WORD)Ssfdc.MaxSectors + Media.Sector;
+ addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
+ addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
/* Read sect data */
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
@@ -200,8 +200,8 @@ int Ssfdc_D_ReadSect(struct us_data *us, BYTE *buf, BYTE *redundant)
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x02;
- bcb->CDB[4] = (BYTE)addr;
- bcb->CDB[3] = (BYTE)(addr / 0x0100);
+ bcb->CDB[4] = (u8)addr;
+ bcb->CDB[3] = (u8)(addr / 0x0100);
bcb->CDB[2] = Media.Zone / 2;
result = ENE_SendScsiCmd(us, FDIR_READ, buf, 0);
@@ -215,8 +215,8 @@ int Ssfdc_D_ReadSect(struct us_data *us, BYTE *buf, BYTE *redundant)
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x03;
- bcb->CDB[4] = (BYTE)addr;
- bcb->CDB[3] = (BYTE)(addr / 0x0100);
+ bcb->CDB[4] = (u8)addr;
+ bcb->CDB[3] = (u8)(addr / 0x0100);
bcb->CDB[2] = Media.Zone / 2;
bcb->CDB[8] = 0;
bcb->CDB[9] = 1;
@@ -229,12 +229,12 @@ int Ssfdc_D_ReadSect(struct us_data *us, BYTE *buf, BYTE *redundant)
}
/* ----- Ssfdc_D_ReadBlock() --------------------------------------------- */
-int Ssfdc_D_ReadBlock(struct us_data *us, WORD count, BYTE *buf,
- BYTE *redundant)
+int Ssfdc_D_ReadBlock(struct us_data *us, u16 count, u8 *buf,
+ u8 *redundant)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
- WORD addr;
+ u16 addr;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
@@ -243,8 +243,8 @@ int Ssfdc_D_ReadBlock(struct us_data *us, WORD count, BYTE *buf,
return USB_STOR_TRANSPORT_ERROR;
}
- addr = (WORD)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
- addr = addr*(WORD)Ssfdc.MaxSectors + Media.Sector;
+ addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
+ addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
/* Read sect data */
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
@@ -253,8 +253,8 @@ int Ssfdc_D_ReadBlock(struct us_data *us, WORD count, BYTE *buf,
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x02;
- bcb->CDB[4] = (BYTE)addr;
- bcb->CDB[3] = (BYTE)(addr / 0x0100);
+ bcb->CDB[4] = (u8)addr;
+ bcb->CDB[3] = (u8)(addr / 0x0100);
bcb->CDB[2] = Media.Zone / 2;
result = ENE_SendScsiCmd(us, FDIR_READ, buf, 0);
@@ -268,8 +268,8 @@ int Ssfdc_D_ReadBlock(struct us_data *us, WORD count, BYTE *buf,
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x03;
- bcb->CDB[4] = (BYTE)addr;
- bcb->CDB[3] = (BYTE)(addr / 0x0100);
+ bcb->CDB[4] = (u8)addr;
+ bcb->CDB[3] = (u8)(addr / 0x0100);
bcb->CDB[2] = Media.Zone / 2;
bcb->CDB[8] = 0;
bcb->CDB[9] = 1;
@@ -283,12 +283,12 @@ int Ssfdc_D_ReadBlock(struct us_data *us, WORD count, BYTE *buf,
/* ----- Ssfdc_D_CopyBlock() -------------------------------------------- */
-int Ssfdc_D_CopyBlock(struct us_data *us, WORD count, BYTE *buf,
- BYTE *redundant)
+int Ssfdc_D_CopyBlock(struct us_data *us, u16 count, u8 *buf,
+ u8 *redundant)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
- WORD ReadAddr, WriteAddr;
+ u16 ReadAddr, WriteAddr;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
@@ -297,10 +297,10 @@ int Ssfdc_D_CopyBlock(struct us_data *us, WORD count, BYTE *buf,
return USB_STOR_TRANSPORT_ERROR;
}
- ReadAddr = (WORD)Media.Zone*Ssfdc.MaxBlocks + ReadBlock;
- ReadAddr = ReadAddr*(WORD)Ssfdc.MaxSectors;
- WriteAddr = (WORD)Media.Zone*Ssfdc.MaxBlocks + WriteBlock;
- WriteAddr = WriteAddr*(WORD)Ssfdc.MaxSectors;
+ ReadAddr = (u16)Media.Zone*Ssfdc.MaxBlocks + ReadBlock;
+ ReadAddr = ReadAddr*(u16)Ssfdc.MaxSectors;
+ WriteAddr = (u16)Media.Zone*Ssfdc.MaxBlocks + WriteBlock;
+ WriteAddr = WriteAddr*(u16)Ssfdc.MaxSectors;
/* Write sect data */
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
@@ -309,16 +309,16 @@ int Ssfdc_D_CopyBlock(struct us_data *us, WORD count, BYTE *buf,
bcb->Flags = 0x00;
bcb->CDB[0] = 0xF0;
bcb->CDB[1] = 0x08;
- bcb->CDB[7] = (BYTE)WriteAddr;
- bcb->CDB[6] = (BYTE)(WriteAddr / 0x0100);
+ bcb->CDB[7] = (u8)WriteAddr;
+ bcb->CDB[6] = (u8)(WriteAddr / 0x0100);
bcb->CDB[5] = Media.Zone / 2;
bcb->CDB[8] = *(redundant + REDT_ADDR1H);
bcb->CDB[9] = *(redundant + REDT_ADDR1L);
bcb->CDB[10] = Media.Sector;
if (ReadBlock != NO_ASSIGN) {
- bcb->CDB[4] = (BYTE)ReadAddr;
- bcb->CDB[3] = (BYTE)(ReadAddr / 0x0100);
+ bcb->CDB[4] = (u8)ReadAddr;
+ bcb->CDB[3] = (u8)(ReadAddr / 0x0100);
bcb->CDB[2] = Media.Zone / 2;
} else
bcb->CDB[11] = 1;
@@ -331,11 +331,11 @@ int Ssfdc_D_CopyBlock(struct us_data *us, WORD count, BYTE *buf,
}
/* ----- Ssfdc_D_WriteSectForCopy() ------------------------------------- */
-int Ssfdc_D_WriteSectForCopy(struct us_data *us, BYTE *buf, BYTE *redundant)
+int Ssfdc_D_WriteSectForCopy(struct us_data *us, u8 *buf, u8 *redundant)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
- WORD addr;
+ u16 addr;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
@@ -345,8 +345,8 @@ int Ssfdc_D_WriteSectForCopy(struct us_data *us, BYTE *buf, BYTE *redundant)
}
- addr = (WORD)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
- addr = addr*(WORD)Ssfdc.MaxSectors + Media.Sector;
+ addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
+ addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
/* Write sect data */
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
@@ -355,8 +355,8 @@ int Ssfdc_D_WriteSectForCopy(struct us_data *us, BYTE *buf, BYTE *redundant)
bcb->Flags = 0x00;
bcb->CDB[0] = 0xF0;
bcb->CDB[1] = 0x04;
- bcb->CDB[7] = (BYTE)addr;
- bcb->CDB[6] = (BYTE)(addr / 0x0100);
+ bcb->CDB[7] = (u8)addr;
+ bcb->CDB[6] = (u8)(addr / 0x0100);
bcb->CDB[5] = Media.Zone / 2;
bcb->CDB[8] = *(redundant + REDT_ADDR1H);
bcb->CDB[9] = *(redundant + REDT_ADDR1L);
@@ -374,7 +374,7 @@ int Ssfdc_D_EraseBlock(struct us_data *us)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
- WORD addr;
+ u16 addr;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
@@ -383,8 +383,8 @@ int Ssfdc_D_EraseBlock(struct us_data *us)
return USB_STOR_TRANSPORT_ERROR;
}
- addr = (WORD)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
- addr = addr*(WORD)Ssfdc.MaxSectors;
+ addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
+ addr = addr*(u16)Ssfdc.MaxSectors;
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
@@ -392,8 +392,8 @@ int Ssfdc_D_EraseBlock(struct us_data *us)
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF2;
bcb->CDB[1] = 0x06;
- bcb->CDB[7] = (BYTE)addr;
- bcb->CDB[6] = (BYTE)(addr / 0x0100);
+ bcb->CDB[7] = (u8)addr;
+ bcb->CDB[6] = (u8)(addr / 0x0100);
bcb->CDB[5] = Media.Zone / 2;
result = ENE_SendScsiCmd(us, FDIR_READ, NULL, 0);
@@ -405,12 +405,12 @@ int Ssfdc_D_EraseBlock(struct us_data *us)
/* 6250 CMD 2 */
/*----- Ssfdc_D_ReadRedtData() ----------------------------------------- */
-int Ssfdc_D_ReadRedtData(struct us_data *us, BYTE *redundant)
+int Ssfdc_D_ReadRedtData(struct us_data *us, u8 *redundant)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
- WORD addr;
- BYTE *buf;
+ u16 addr;
+ u8 *buf;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
@@ -419,8 +419,8 @@ int Ssfdc_D_ReadRedtData(struct us_data *us, BYTE *redundant)
return USB_STOR_TRANSPORT_ERROR;
}
- addr = (WORD)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
- addr = addr*(WORD)Ssfdc.MaxSectors + Media.Sector;
+ addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
+ addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
@@ -428,8 +428,8 @@ int Ssfdc_D_ReadRedtData(struct us_data *us, BYTE *redundant)
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x03;
- bcb->CDB[4] = (BYTE)addr;
- bcb->CDB[3] = (BYTE)(addr / 0x0100);
+ bcb->CDB[4] = (u8)addr;
+ bcb->CDB[3] = (u8)(addr / 0x0100);
bcb->CDB[2] = Media.Zone / 2;
bcb->CDB[8] = 0;
bcb->CDB[9] = 1;
@@ -446,11 +446,11 @@ int Ssfdc_D_ReadRedtData(struct us_data *us, BYTE *redundant)
/* 6250 CMD 4 */
/* ----- Ssfdc_D_WriteRedtData() ---------------------------------------- */
-int Ssfdc_D_WriteRedtData(struct us_data *us, BYTE *redundant)
+int Ssfdc_D_WriteRedtData(struct us_data *us, u8 *redundant)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
- WORD addr;
+ u16 addr;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
@@ -459,8 +459,8 @@ int Ssfdc_D_WriteRedtData(struct us_data *us, BYTE *redundant)
return USB_STOR_TRANSPORT_ERROR;
}
- addr = (WORD)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
- addr = addr*(WORD)Ssfdc.MaxSectors + Media.Sector;
+ addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
+ addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
@@ -468,8 +468,8 @@ int Ssfdc_D_WriteRedtData(struct us_data *us, BYTE *redundant)
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF2;
bcb->CDB[1] = 0x05;
- bcb->CDB[7] = (BYTE)addr;
- bcb->CDB[6] = (BYTE)(addr / 0x0100);
+ bcb->CDB[7] = (u8)addr;
+ bcb->CDB[6] = (u8)(addr / 0x0100);
bcb->CDB[5] = Media.Zone / 2;
bcb->CDB[8] = *(redundant + REDT_ADDR1H);
bcb->CDB[9] = *(redundant + REDT_ADDR1L);
@@ -492,7 +492,7 @@ int Ssfdc_D_CheckStatus(void)
/* SmartMedia ID Code Check & Mode Set Subroutine
* ----- Set_D_SsfdcModel() ---------------------------------------------
*/
-int Set_D_SsfdcModel(BYTE dcode)
+int Set_D_SsfdcModel(u8 dcode)
{
switch (_Check_D_DevCode(dcode)) {
case SSFDC1MB:
@@ -600,7 +600,7 @@ int Set_D_SsfdcModel(BYTE dcode)
}
/* ----- _Check_D_DevCode() --------------------------------------------- */
-BYTE _Check_D_DevCode(BYTE dcode)
+static u8 _Check_D_DevCode(u8 dcode)
{
switch (dcode) {
case 0x6E:
@@ -630,21 +630,21 @@ BYTE _Check_D_DevCode(BYTE dcode)
/* SmartMedia ECC Control Subroutine
* ----- Check_D_ReadError() ----------------------------------------------
*/
-int Check_D_ReadError(BYTE *redundant)
+int Check_D_ReadError(u8 *redundant)
{
return SMSUCCESS;
}
/* ----- Check_D_Correct() ---------------------------------------------- */
-int Check_D_Correct(BYTE *buf, BYTE *redundant)
+int Check_D_Correct(u8 *buf, u8 *redundant)
{
return SMSUCCESS;
}
/* ----- Check_D_CISdata() ---------------------------------------------- */
-int Check_D_CISdata(BYTE *buf, BYTE *redundant)
+int Check_D_CISdata(u8 *buf, u8 *redundant)
{
- BYTE cis[] = {0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02,
+ u8 cis[] = {0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02,
0xDF, 0x01, 0x20};
int cis_len = sizeof(cis);
@@ -669,7 +669,7 @@ int Check_D_CISdata(BYTE *buf, BYTE *redundant)
}
/* ----- Set_D_RightECC() ---------------------------------------------- */
-void Set_D_RightECC(BYTE *redundant)
+void Set_D_RightECC(u8 *redundant)
{
/* Driver ECC Check */
return;
diff --git a/drivers/staging/keucr/smscsi.c b/drivers/staging/keucr/smscsi.c
index 5c03eca4dba8..20858f6777c8 100644
--- a/drivers/staging/keucr/smscsi.c
+++ b/drivers/staging/keucr/smscsi.c
@@ -68,7 +68,7 @@ static int SM_SCSI_Test_Unit_Ready(struct us_data *us, struct scsi_cmnd *srb)
/* ----- SM_SCSI_Inquiry() --------------------------------------------- */
static int SM_SCSI_Inquiry(struct us_data *us, struct scsi_cmnd *srb)
{
- BYTE data_ptr[36] = {0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00,
+ u8 data_ptr[36] = {0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00,
0x55, 0x53, 0x42, 0x32, 0x2E, 0x30, 0x20,
0x20, 0x43, 0x61, 0x72, 0x64, 0x52, 0x65,
0x61, 0x64, 0x65, 0x72, 0x20, 0x20, 0x20,
@@ -82,9 +82,9 @@ static int SM_SCSI_Inquiry(struct us_data *us, struct scsi_cmnd *srb)
/* ----- SM_SCSI_Mode_Sense() ------------------------------------------ */
static int SM_SCSI_Mode_Sense(struct us_data *us, struct scsi_cmnd *srb)
{
- BYTE mediaNoWP[12] = {0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
+ u8 mediaNoWP[12] = {0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00, 0x02, 0x00};
- BYTE mediaWP[12] = {0x0b, 0x00, 0x80, 0x08, 0x00, 0x00,
+ u8 mediaWP[12] = {0x0b, 0x00, 0x80, 0x08, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00, 0x02, 0x00};
if (us->SM_Status.WtP)
@@ -101,9 +101,9 @@ static int SM_SCSI_Read_Capacity(struct us_data *us, struct scsi_cmnd *srb)
{
unsigned int offset = 0;
struct scatterlist *sg = NULL;
- DWORD bl_num;
- WORD bl_len;
- BYTE buf[8];
+ u32 bl_num;
+ u16 bl_len;
+ u8 buf[8];
dev_dbg(&us->pusb_dev->dev, "SM_SCSI_Read_Capacity\n");
@@ -132,13 +132,13 @@ static int SM_SCSI_Read_Capacity(struct us_data *us, struct scsi_cmnd *srb)
static int SM_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb)
{
int result = 0;
- PBYTE Cdb = srb->cmnd;
- DWORD bn = ((Cdb[2] << 24) & 0xff000000) |
+ u8 *Cdb = srb->cmnd;
+ u32 bn = ((Cdb[2] << 24) & 0xff000000) |
((Cdb[3] << 16) & 0x00ff0000) |
((Cdb[4] << 8) & 0x0000ff00) |
((Cdb[5] << 0) & 0x000000ff);
- WORD blen = ((Cdb[7] << 8) & 0xff00) | ((Cdb[8] << 0) & 0x00ff);
- DWORD blenByte = blen * 0x200;
+ u16 blen = ((Cdb[7] << 8) & 0xff00) | ((Cdb[8] << 0) & 0x00ff);
+ u32 blenByte = blen * 0x200;
void *buf;
@@ -164,13 +164,13 @@ static int SM_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb)
static int SM_SCSI_Write(struct us_data *us, struct scsi_cmnd *srb)
{
int result = 0;
- PBYTE Cdb = srb->cmnd;
- DWORD bn = ((Cdb[2] << 24) & 0xff000000) |
+ u8 *Cdb = srb->cmnd;
+ u32 bn = ((Cdb[2] << 24) & 0xff000000) |
((Cdb[3] << 16) & 0x00ff0000) |
((Cdb[4] << 8) & 0x0000ff00) |
((Cdb[5] << 0) & 0x000000ff);
- WORD blen = ((Cdb[7] << 8) & 0xff00) | ((Cdb[8] << 0) & 0x00ff);
- DWORD blenByte = blen * 0x200;
+ u16 blen = ((Cdb[7] << 8) & 0xff00) | ((Cdb[8] << 0) & 0x00ff);
+ u32 blenByte = blen * 0x200;
void *buf;
diff --git a/drivers/staging/keucr/transport.c b/drivers/staging/keucr/transport.c
index aeb2186d62ca..ae9414755d2f 100644
--- a/drivers/staging/keucr/transport.c
+++ b/drivers/staging/keucr/transport.c
@@ -83,8 +83,8 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
*/
static void usb_stor_print_cmd(struct us_data *us, struct scsi_cmnd *srb)
{
- PBYTE Cdb = srb->cmnd;
- DWORD cmd = Cdb[0];
+ u8 *Cdb = srb->cmnd;
+ u32 cmd = Cdb[0];
switch (cmd) {
case TEST_UNIT_READY:
@@ -545,8 +545,8 @@ Handle_Errors:
*/
void BuildSenseBuffer(struct scsi_cmnd *srb, int SrbStatus)
{
- BYTE *buf = srb->sense_buffer;
- BYTE asc;
+ u8 *buf = srb->sense_buffer;
+ u8 asc;
pr_info("transport --- BuildSenseBuffer\n");
switch (SrbStatus) {
diff --git a/drivers/staging/keucr/transport.h b/drivers/staging/keucr/transport.h
index df34474ae568..abd8e5a3dd6e 100644
--- a/drivers/staging/keucr/transport.h
+++ b/drivers/staging/keucr/transport.h
@@ -58,9 +58,9 @@ extern void usb_stor_set_xfer_buf(struct us_data*, unsigned char *buffer,
extern void ENE_stor_invoke_transport(struct scsi_cmnd *, struct us_data *);
extern int ENE_InitMedia(struct us_data *);
extern int ENE_SMInit(struct us_data *);
-extern int ENE_SendScsiCmd(struct us_data*, BYTE, void*, int);
-extern int ENE_LoadBinCode(struct us_data*, BYTE);
-extern int ene_read_byte(struct us_data*, WORD index, void *buf);
+extern int ENE_SendScsiCmd(struct us_data*, u8, void*, int);
+extern int ENE_LoadBinCode(struct us_data*, u8);
+extern int ene_read_byte(struct us_data*, u16 index, void *buf);
extern int ENE_Read_Data(struct us_data*, void *buf, unsigned int length);
extern int ENE_Write_Data(struct us_data*, void *buf, unsigned int length);
extern void BuildSenseBuffer(struct scsi_cmnd *, int);
diff --git a/drivers/staging/keucr/usb.c b/drivers/staging/keucr/usb.c
index 3e3ca6365fbc..12ebde7315cd 100644
--- a/drivers/staging/keucr/usb.c
+++ b/drivers/staging/keucr/usb.c
@@ -50,7 +50,7 @@ static int eucr_suspend(struct usb_interface *iface, pm_message_t message)
static int eucr_resume(struct usb_interface *iface)
{
- BYTE tmp = 0;
+ u8 tmp = 0;
struct us_data *us = usb_get_intfdata(iface);
pr_info("--- eucr_resume---\n");
@@ -71,7 +71,7 @@ static int eucr_resume(struct usb_interface *iface)
static int eucr_reset_resume(struct usb_interface *iface)
{
- BYTE tmp = 0;
+ u8 tmp = 0;
struct us_data *us = usb_get_intfdata(iface);
pr_info("--- eucr_reset_resume---\n");
@@ -528,7 +528,7 @@ static int eucr_probe(struct usb_interface *intf,
struct Scsi_Host *host;
struct us_data *us;
int result;
- BYTE MiscReg03 = 0;
+ u8 MiscReg03 = 0;
struct task_struct *th;
pr_info("usb --- eucr_probe\n");
diff --git a/drivers/staging/keucr/usb.h b/drivers/staging/keucr/usb.h
index d665af177b96..e894f840c708 100644
--- a/drivers/staging/keucr/usb.h
+++ b/drivers/staging/keucr/usb.h
@@ -52,34 +52,34 @@ struct us_unusual_dev {
#define FDIR_READ 1
struct keucr_sd_status {
- BYTE Insert:1;
- BYTE Ready:1;
- BYTE MediaChange:1;
- BYTE IsMMC:1;
- BYTE HiCapacity:1;
- BYTE HiSpeed:1;
- BYTE WtP:1;
- BYTE Reserved:1;
+ u8 Insert:1;
+ u8 Ready:1;
+ u8 MediaChange:1;
+ u8 IsMMC:1;
+ u8 HiCapacity:1;
+ u8 HiSpeed:1;
+ u8 WtP:1;
+ u8 Reserved:1;
};
struct keucr_ms_status {
- BYTE Insert:1;
- BYTE Ready:1;
- BYTE MediaChange:1;
- BYTE IsMSPro:1;
- BYTE IsMSPHG:1;
- BYTE Reserved1:1;
- BYTE WtP:1;
- BYTE Reserved2:1;
+ u8 Insert:1;
+ u8 Ready:1;
+ u8 MediaChange:1;
+ u8 IsMSPro:1;
+ u8 IsMSPHG:1;
+ u8 Reserved1:1;
+ u8 WtP:1;
+ u8 Reserved2:1;
};
struct keucr_sm_status {
- BYTE Insert:1;
- BYTE Ready:1;
- BYTE MediaChange:1;
- BYTE Reserved:3;
- BYTE WtP:1;
- BYTE IsMS:1;
+ u8 Insert:1;
+ u8 Ready:1;
+ u8 MediaChange:1;
+ u8 Reserved:3;
+ u8 WtP:1;
+ u8 IsMS:1;
};
/* SD Block Length */
@@ -184,38 +184,38 @@ struct us_data {
/* ----- SD Control Data ---------------- */
/* SD_REGISTER SD_Regs; */
- WORD SD_Block_Mult;
- BYTE SD_READ_BL_LEN;
- WORD SD_C_SIZE;
- BYTE SD_C_SIZE_MULT;
+ u16 SD_Block_Mult;
+ u8 SD_READ_BL_LEN;
+ u16 SD_C_SIZE;
+ u8 SD_C_SIZE_MULT;
/* SD/MMC New spec. */
- BYTE SD_SPEC_VER;
- BYTE SD_CSD_VER;
- BYTE SD20_HIGH_CAPACITY;
- DWORD HC_C_SIZE;
- BYTE MMC_SPEC_VER;
- BYTE MMC_BusWidth;
- BYTE MMC_HIGH_CAPACITY;
+ u8 SD_SPEC_VER;
+ u8 SD_CSD_VER;
+ u8 SD20_HIGH_CAPACITY;
+ u32 HC_C_SIZE;
+ u8 MMC_SPEC_VER;
+ u8 MMC_BusWidth;
+ u8 MMC_HIGH_CAPACITY;
/* ----- MS Control Data ---------------- */
- BOOLEAN MS_SWWP;
- DWORD MSP_TotalBlock;
+ bool MS_SWWP;
+ u32 MSP_TotalBlock;
/* MS_LibControl MS_Lib; */
- BOOLEAN MS_IsRWPage;
- WORD MS_Model;
+ bool MS_IsRWPage;
+ u16 MS_Model;
/* ----- SM Control Data ---------------- */
- BYTE SM_DeviceID;
- BYTE SM_CardID;
+ u8 SM_DeviceID;
+ u8 SM_CardID;
- PBYTE testbuf;
- BYTE BIN_FLAG;
- DWORD bl_num;
+ u8 *testbuf;
+ u8 BIN_FLAG;
+ u32 bl_num;
int SrbStatus;
/* ------Power Managerment --------------- */
- BOOLEAN Power_IsResum;
+ bool Power_IsResum;
};
/* Convert between us_data and the corresponding Scsi_Host */
diff --git a/drivers/staging/line6/audio.c b/drivers/staging/line6/audio.c
index a92e21f7d55b..171d80c1b020 100644
--- a/drivers/staging/line6/audio.c
+++ b/drivers/staging/line6/audio.c
@@ -24,8 +24,9 @@ int line6_init_audio(struct usb_line6 *line6)
struct snd_card *card;
int err;
- err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- THIS_MODULE, 0, &card);
+ err = snd_card_new(line6->ifcdev,
+ SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &card);
if (err < 0)
return err;
diff --git a/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c
index f8316b71f13d..0eda51d2e9a2 100644
--- a/drivers/staging/line6/capture.c
+++ b/drivers/staging/line6/capture.c
@@ -157,6 +157,7 @@ void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
copy two separate chunks.
*/
int len;
+
len = runtime->buffer_size - line6pcm->pos_in_done;
if (len > 0) {
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
index 7a6d85ebb29b..77f1b421e957 100644
--- a/drivers/staging/line6/driver.c
+++ b/drivers/staging/line6/driver.c
@@ -57,28 +57,32 @@ static const struct usb_device_id line6_id_table[] = {
MODULE_DEVICE_TABLE(usb, line6_id_table);
+#define L6PROP(dev_bit, dev_id, dev_name, dev_cap)\
+ {.device_bit = LINE6_BIT_##dev_bit, .id = dev_id,\
+ .name = dev_name, .capabilities = LINE6_BIT_##dev_cap}
+
/* *INDENT-OFF* */
-static struct line6_properties line6_properties_table[] = {
- { LINE6_BIT_BASSPODXT, "BassPODxt", "BassPODxt", LINE6_BIT_CONTROL_PCM_HWMON },
- { LINE6_BIT_BASSPODXTLIVE, "BassPODxtLive", "BassPODxt Live", LINE6_BIT_CONTROL_PCM_HWMON },
- { LINE6_BIT_BASSPODXTPRO, "BassPODxtPro", "BassPODxt Pro", LINE6_BIT_CONTROL_PCM_HWMON },
- { LINE6_BIT_GUITARPORT, "GuitarPort", "GuitarPort", LINE6_BIT_PCM },
- { LINE6_BIT_POCKETPOD, "PocketPOD", "Pocket POD", LINE6_BIT_CONTROL },
- { LINE6_BIT_PODHD300, "PODHD300", "POD HD300", LINE6_BIT_CONTROL_PCM_HWMON },
- { LINE6_BIT_PODHD400, "PODHD400", "POD HD400", LINE6_BIT_CONTROL_PCM_HWMON },
- { LINE6_BIT_PODHD500, "PODHD500", "POD HD500", LINE6_BIT_CONTROL_PCM_HWMON },
- { LINE6_BIT_PODSTUDIO_GX, "PODStudioGX", "POD Studio GX", LINE6_BIT_PCM },
- { LINE6_BIT_PODSTUDIO_UX1, "PODStudioUX1", "POD Studio UX1", LINE6_BIT_PCM },
- { LINE6_BIT_PODSTUDIO_UX2, "PODStudioUX2", "POD Studio UX2", LINE6_BIT_PCM },
- { LINE6_BIT_PODX3, "PODX3", "POD X3", LINE6_BIT_PCM },
- { LINE6_BIT_PODX3LIVE, "PODX3Live", "POD X3 Live", LINE6_BIT_PCM },
- { LINE6_BIT_PODXT, "PODxt", "PODxt", LINE6_BIT_CONTROL_PCM_HWMON },
- { LINE6_BIT_PODXTLIVE, "PODxtLive", "PODxt Live", LINE6_BIT_CONTROL_PCM_HWMON },
- { LINE6_BIT_PODXTPRO, "PODxtPro", "PODxt Pro", LINE6_BIT_CONTROL_PCM_HWMON },
- { LINE6_BIT_TONEPORT_GX, "TonePortGX", "TonePort GX", LINE6_BIT_PCM },
- { LINE6_BIT_TONEPORT_UX1, "TonePortUX1", "TonePort UX1", LINE6_BIT_PCM },
- { LINE6_BIT_TONEPORT_UX2, "TonePortUX2", "TonePort UX2", LINE6_BIT_PCM },
- { LINE6_BIT_VARIAX, "Variax", "Variax Workbench", LINE6_BIT_CONTROL },
+static const struct line6_properties line6_properties_table[] = {
+ L6PROP(BASSPODXT, "BassPODxt", "BassPODxt", CTRL_PCM_HW),
+ L6PROP(BASSPODXTLIVE, "BassPODxtLive", "BassPODxt Live", CTRL_PCM_HW),
+ L6PROP(BASSPODXTPRO, "BassPODxtPro", "BassPODxt Pro", CTRL_PCM_HW),
+ L6PROP(GUITARPORT, "GuitarPort", "GuitarPort", PCM),
+ L6PROP(POCKETPOD, "PocketPOD", "Pocket POD", CONTROL),
+ L6PROP(PODHD300, "PODHD300", "POD HD300", CTRL_PCM_HW),
+ L6PROP(PODHD400, "PODHD400", "POD HD400", CTRL_PCM_HW),
+ L6PROP(PODHD500, "PODHD500", "POD HD500", CTRL_PCM_HW),
+ L6PROP(PODSTUDIO_GX, "PODStudioGX", "POD Studio GX", PCM),
+ L6PROP(PODSTUDIO_UX1, "PODStudioUX1", "POD Studio UX1", PCM),
+ L6PROP(PODSTUDIO_UX2, "PODStudioUX2", "POD Studio UX2", PCM),
+ L6PROP(PODX3, "PODX3", "POD X3", PCM),
+ L6PROP(PODX3LIVE, "PODX3Live", "POD X3 Live", PCM),
+ L6PROP(PODXT, "PODxt", "PODxt", CTRL_PCM_HW),
+ L6PROP(PODXTLIVE, "PODxtLive", "PODxt Live", CTRL_PCM_HW),
+ L6PROP(PODXTPRO, "PODxtPro", "PODxt Pro", CTRL_PCM_HW),
+ L6PROP(TONEPORT_GX, "TonePortGX", "TonePort GX", PCM),
+ L6PROP(TONEPORT_UX1, "TonePortUX1", "TonePort UX1", PCM),
+ L6PROP(TONEPORT_UX2, "TonePortUX2", "TonePort UX2", PCM),
+ L6PROP(VARIAX, "Variax", "Variax Workbench", CONTROL),
};
/* *INDENT-ON* */
@@ -152,10 +156,10 @@ int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
int retval;
retval = usb_interrupt_msg(line6->usbdev,
- usb_sndintpipe(line6->usbdev,
- line6->ep_control_write),
- (char *)frag_buf, frag_size,
- &partial, LINE6_TIMEOUT * HZ);
+ usb_sndintpipe(line6->usbdev,
+ line6->ep_control_write),
+ (char *)frag_buf, frag_size,
+ &partial, LINE6_TIMEOUT * HZ);
if (retval) {
dev_err(line6->ifcdev,
@@ -217,7 +221,7 @@ static int line6_send_raw_message_async_part(struct message *msg,
Setup and start timer.
*/
void line6_start_timer(struct timer_list *timer, unsigned int msecs,
- void (*function) (unsigned long), unsigned long data)
+ void (*function)(unsigned long), unsigned long data)
{
setup_timer(timer, function, data);
timer->expires = jiffies + msecs * HZ / 1000;
diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h
index 34ae95e7e512..16e3fc2f1f15 100644
--- a/drivers/staging/line6/driver.h
+++ b/drivers/staging/line6/driver.h
@@ -204,7 +204,7 @@ extern int line6_send_sysex_message(struct usb_line6 *line6,
extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
extern void line6_start_timer(struct timer_list *timer, unsigned int msecs,
- void (*function) (unsigned long),
+ void (*function)(unsigned long),
unsigned long data);
extern int line6_transmit_parameter(struct usb_line6 *line6, int param,
u8 value);
diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c
index 3f6d78c585fb..02345fb06e3d 100644
--- a/drivers/staging/line6/midi.c
+++ b/drivers/staging/line6/midi.c
@@ -47,7 +47,7 @@ static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
struct snd_line6_midi *line6midi = line6->line6midi;
struct midi_buffer *mb = &line6midi->midibuf_out;
unsigned long flags;
- unsigned char chunk[line6->max_packet_size];
+ unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE];
int req, done;
spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags);
@@ -64,7 +64,8 @@ static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
}
for (;;) {
- done = line6_midibuf_read(mb, chunk, line6->max_packet_size);
+ done = line6_midibuf_read(mb, chunk,
+ LINE6_FALLBACK_MAXPACKETSIZE);
if (done == 0)
break;
@@ -307,8 +308,6 @@ int line6_init_midi(struct usb_line6 *line6)
if (err < 0)
return err;
- snd_card_set_dev(line6->card, line6->ifcdev);
-
err = snd_line6_new_midi(line6midi);
if (err < 0)
return err;
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
index df8331bce175..661080b3c39d 100644
--- a/drivers/staging/line6/pcm.c
+++ b/drivers/staging/line6/pcm.c
@@ -501,8 +501,6 @@ int line6_init_pcm(struct usb_line6 *line6,
if (err < 0)
return err;
- snd_card_set_dev(line6->card, line6->ifcdev);
-
err = snd_line6_new_pcm(line6pcm);
if (err < 0)
return err;
diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h
index 90cadddec56e..2d1cc472bead 100644
--- a/drivers/staging/line6/usbdefs.h
+++ b/drivers/staging/line6/usbdefs.h
@@ -91,9 +91,9 @@ enum {
LINE6_BITS_PODXTALL = LINE6_BIT_PODXT | LINE6_BIT_PODXTLIVE |
LINE6_BIT_PODXTPRO,
LINE6_BITS_PODX3ALL = LINE6_BIT_PODX3 | LINE6_BIT_PODX3LIVE,
- LINE6_BITS_PODHDALL = LINE6_BIT_PODHD300 |
- LINE6_BIT_PODHD400 |
- LINE6_BIT_PODHD500,
+ LINE6_BITS_PODHDALL = LINE6_BIT_PODHD300 |
+ LINE6_BIT_PODHD400 |
+ LINE6_BIT_PODHD500,
LINE6_BITS_BASSPODXTALL = LINE6_BIT_BASSPODXT |
LINE6_BIT_BASSPODXTLIVE |
LINE6_BIT_BASSPODXTPRO
@@ -106,7 +106,7 @@ enum {
/* device support hardware monitoring */
#define LINE6_BIT_HWMON (1 << 2)
-#define LINE6_BIT_CONTROL_PCM_HWMON (LINE6_BIT_CONTROL | \
+#define LINE6_BIT_CTRL_PCM_HW (LINE6_BIT_CONTROL | \
LINE6_BIT_PCM | \
LINE6_BIT_HWMON)
diff --git a/drivers/staging/lustre/include/linux/libcfs/curproc.h b/drivers/staging/lustre/include/linux/libcfs/curproc.h
index 507d16b9213c..8fd47c98fd33 100644
--- a/drivers/staging/lustre/include/linux/libcfs/curproc.h
+++ b/drivers/staging/lustre/include/linux/libcfs/curproc.h
@@ -44,13 +44,6 @@
#define __LIBCFS_CURPROC_H__
/*
- * Portable API to access common characteristics of "current" UNIX process.
- *
- * Implemented in portals/include/libcfs/<os>/
- */
-int cfs_curproc_groups_nr(void);
-
-/*
* Plus, platform-specific constant
*
* CFS_CURPROC_COMM_MAX,
@@ -91,8 +84,6 @@ void cfs_cap_raise(cfs_cap_t cap);
void cfs_cap_lower(cfs_cap_t cap);
int cfs_cap_raised(cfs_cap_t cap);
cfs_cap_t cfs_curproc_cap_pack(void);
-void cfs_curproc_cap_unpack(cfs_cap_t cap);
-int cfs_capable(cfs_cap_t cap);
/* __LIBCFS_CURPROC_H__ */
#endif
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
index 9d5ee1a69c0c..e5d5db255622 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
@@ -65,8 +65,6 @@
#include <linux/hash.h>
-#define cfs_hash_long(val, bits) hash_long(val, bits)
-
/** disable debug */
#define CFS_HASH_DEBUG_NONE 0
/** record hash depth and output to console when it's too deep,
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h
index 74dda57b98a8..49ba62a4daa8 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h
@@ -211,10 +211,10 @@ static inline int libcfs_ioctl_is_invalid(struct libcfs_ioctl_data *data)
}
-extern int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand);
-extern int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand);
-extern int libcfs_ioctl_getdata(char *buf, char *end, void *arg);
-extern int libcfs_ioctl_popdata(void *arg, void *buf, int size);
+int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand);
+int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand);
+int libcfs_ioctl_getdata(char *buf, char *end, void *arg);
+int libcfs_ioctl_popdata(void *arg, void *buf, int size);
#endif /* __LIBCFS_IOCTL_H__ */
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h
index e6e417aeefd5..7cf34aa78f79 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h
@@ -41,19 +41,10 @@
#define __LIBCFS_PRIM_H__
/*
- * Schedule
- */
-void cfs_pause(cfs_duration_t ticks);
-
-/*
* Timer
*/
typedef void (cfs_timer_func_t)(ulong_ptr_t);
-void schedule_timeout_and_set_state(long, int64_t);
-void init_waitqueue_entry_current(wait_queue_t *link);
-int64_t waitq_timedwait(wait_queue_t *, long, int64_t);
-void waitq_wait(wait_queue_t *, long);
void add_wait_queue_exclusive_head(wait_queue_head_t *, wait_queue_t *);
void cfs_init_timer(struct timer_list *t);
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h
index a6bac9c36339..509dc1e5c3b1 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h
@@ -49,18 +49,6 @@ int cfs_strncasecmp(const char *s1, const char *s2, size_t n);
/* Convert a text string to a bitmask */
int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
int *oldmask, int minmask, int allmask);
-
-/* Allocate space for and copy an existing string.
- * Must free with kfree().
- */
-char *cfs_strdup(const char *str, u_int32_t flags);
-
-/* safe vsnprintf */
-int cfs_vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
-
-/* safe snprintf */
-int cfs_snprintf(char *buf, size_t size, const char *fmt, ...);
-
/* trim leading and trailing space characters */
char *cfs_firststr(char *str, size_t size);
@@ -90,27 +78,10 @@ struct cfs_expr_list {
struct list_head el_exprs;
};
-static inline int
-cfs_iswhite(char c)
-{
- switch (c) {
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- return 1;
- default:
- break;
- }
- return 0;
-}
-
char *cfs_trimwhite(char *str);
int cfs_gettok(struct cfs_lstr *next, char delim, struct cfs_lstr *res);
int cfs_str2num_check(char *str, int nob, unsigned *num,
unsigned min, unsigned max);
-int cfs_range_expr_parse(struct cfs_lstr *src, unsigned min, unsigned max,
- int single_tok, struct cfs_range_expr **expr);
int cfs_expr_list_match(__u32 value, struct cfs_expr_list *expr_list);
int cfs_expr_list_values(struct cfs_expr_list *expr_list,
int max, __u32 **values);
@@ -124,7 +95,6 @@ cfs_expr_list_values_free(__u32 *values, int num)
}
void cfs_expr_list_free(struct cfs_expr_list *expr_list);
-void cfs_expr_list_print(struct cfs_expr_list *expr_list);
int cfs_expr_list_parse(char *str, int len, unsigned min, unsigned max,
struct cfs_expr_list **elpp);
void cfs_expr_list_free_list(struct list_head *list);
diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h
index 3ac2bb5fd2db..856fcfaafafa 100644
--- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h
+++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h
@@ -628,7 +628,7 @@ void lnet_ni_free(lnet_ni_t *ni);
static inline int
lnet_nid2peerhash(lnet_nid_t nid)
{
- return cfs_hash_long(nid, LNET_PEER_HASH_BITS);
+ return hash_long(nid, LNET_PEER_HASH_BITS);
}
static inline struct list_head *
diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h
index dd8edcf1b5c0..1c13ef7df80e 100644
--- a/drivers/staging/lustre/include/linux/lnet/lib-types.h
+++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h
@@ -282,16 +282,14 @@ typedef struct lnet_libmd {
#define LNET_MD_FLAG_AUTO_UNLINK (1 << 1)
#ifdef LNET_USE_LIB_FREELIST
-typedef struct
-{
+typedef struct {
void *fl_objs; /* single contiguous array of objects */
int fl_nobjs; /* the number of them */
int fl_objsize; /* the size (including overhead) of each of them */
struct list_head fl_list; /* where they are enqueued */
} lnet_freelist_t;
-typedef struct
-{
+typedef struct {
struct list_head fo_list; /* enqueue on fl_list */
void *fo_contents; /* aligned contents */
} lnet_freeobj_t;
@@ -312,8 +310,7 @@ typedef struct {
struct lnet_ni; /* forward ref */
-typedef struct lnet_lnd
-{
+typedef struct lnet_lnd {
/* fields managed by portals */
struct list_head lnd_list; /* stash in the LND table */
int lnd_refcount; /* # active instances */
@@ -321,8 +318,8 @@ typedef struct lnet_lnd
/* fields initialised by the LND */
unsigned int lnd_type;
- int (*lnd_startup) (struct lnet_ni *ni);
- void (*lnd_shutdown) (struct lnet_ni *ni);
+ int (*lnd_startup)(struct lnet_ni *ni);
+ void (*lnd_shutdown)(struct lnet_ni *ni);
int (*lnd_ctl)(struct lnet_ni *ni, unsigned int cmd, void *arg);
/* In data movement APIs below, payload buffers are described as a set
@@ -668,8 +665,7 @@ struct lnet_msg_container {
#define LNET_RC_STATE_RUNNING 1 /* started up OK */
#define LNET_RC_STATE_STOPPING 2 /* telling thread to stop */
-typedef struct
-{
+typedef struct {
/* CPU partition table of LNet */
struct cfs_cpt_table *ln_cpt_table;
/* number of CPTs in ln_cpt_table */
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
index 644a0000130a..0061c8afa206 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
@@ -41,7 +41,7 @@
#include "o2iblnd.h"
#include <asm/div64.h>
-lnd_t the_o2iblnd = {
+static lnd_t the_o2iblnd = {
.lnd_type = O2IBLND,
.lnd_startup = kiblnd_startup,
.lnd_shutdown = kiblnd_shutdown,
@@ -53,8 +53,8 @@ lnd_t the_o2iblnd = {
kib_data_t kiblnd_data;
-__u32
-kiblnd_cksum (void *ptr, int nob)
+static __u32
+kiblnd_cksum(void *ptr, int nob)
{
char *c = ptr;
__u32 sum = 0;
@@ -429,8 +429,8 @@ kiblnd_unlink_peer_locked (kib_peer_t *peer)
kiblnd_peer_decref(peer);
}
-int
-kiblnd_get_peer_info (lnet_ni_t *ni, int index,
+static int
+kiblnd_get_peer_info(lnet_ni_t *ni, int index,
lnet_nid_t *nidp, int *count)
{
kib_peer_t *peer;
@@ -468,8 +468,8 @@ kiblnd_get_peer_info (lnet_ni_t *ni, int index,
return -ENOENT;
}
-void
-kiblnd_del_peer_locked (kib_peer_t *peer)
+static void
+kiblnd_del_peer_locked(kib_peer_t *peer)
{
struct list_head *ctmp;
struct list_head *cnxt;
@@ -489,8 +489,8 @@ kiblnd_del_peer_locked (kib_peer_t *peer)
* last ref on it. */
}
-int
-kiblnd_del_peer (lnet_ni_t *ni, lnet_nid_t nid)
+static int
+kiblnd_del_peer(lnet_ni_t *ni, lnet_nid_t nid)
{
LIST_HEAD (zombies);
struct list_head *ptmp;
@@ -543,8 +543,8 @@ kiblnd_del_peer (lnet_ni_t *ni, lnet_nid_t nid)
return rc;
}
-kib_conn_t *
-kiblnd_get_conn_by_idx (lnet_ni_t *ni, int index)
+static kib_conn_t *
+kiblnd_get_conn_by_idx(lnet_ni_t *ni, int index)
{
kib_peer_t *peer;
struct list_head *ptmp;
@@ -584,74 +584,6 @@ kiblnd_get_conn_by_idx (lnet_ni_t *ni, int index)
return NULL;
}
-void
-kiblnd_debug_rx (kib_rx_t *rx)
-{
- CDEBUG(D_CONSOLE, " %p status %d msg_type %x cred %d\n",
- rx, rx->rx_status, rx->rx_msg->ibm_type,
- rx->rx_msg->ibm_credits);
-}
-
-void
-kiblnd_debug_tx (kib_tx_t *tx)
-{
- CDEBUG(D_CONSOLE, " %p snd %d q %d w %d rc %d dl %lx "
- "cookie "LPX64" msg %s%s type %x cred %d\n",
- tx, tx->tx_sending, tx->tx_queued, tx->tx_waiting,
- tx->tx_status, tx->tx_deadline, tx->tx_cookie,
- tx->tx_lntmsg[0] == NULL ? "-" : "!",
- tx->tx_lntmsg[1] == NULL ? "-" : "!",
- tx->tx_msg->ibm_type, tx->tx_msg->ibm_credits);
-}
-
-void
-kiblnd_debug_conn (kib_conn_t *conn)
-{
- struct list_head *tmp;
- int i;
-
- spin_lock(&conn->ibc_lock);
-
- CDEBUG(D_CONSOLE, "conn[%d] %p [version %x] -> %s: \n",
- atomic_read(&conn->ibc_refcount), conn,
- conn->ibc_version, libcfs_nid2str(conn->ibc_peer->ibp_nid));
- CDEBUG(D_CONSOLE, " state %d nposted %d/%d cred %d o_cred %d r_cred %d\n",
- conn->ibc_state, conn->ibc_noops_posted,
- conn->ibc_nsends_posted, conn->ibc_credits,
- conn->ibc_outstanding_credits, conn->ibc_reserved_credits);
- CDEBUG(D_CONSOLE, " comms_err %d\n", conn->ibc_comms_error);
-
- CDEBUG(D_CONSOLE, " early_rxs:\n");
- list_for_each(tmp, &conn->ibc_early_rxs)
- kiblnd_debug_rx(list_entry(tmp, kib_rx_t, rx_list));
-
- CDEBUG(D_CONSOLE, " tx_noops:\n");
- list_for_each(tmp, &conn->ibc_tx_noops)
- kiblnd_debug_tx(list_entry(tmp, kib_tx_t, tx_list));
-
- CDEBUG(D_CONSOLE, " tx_queue_nocred:\n");
- list_for_each(tmp, &conn->ibc_tx_queue_nocred)
- kiblnd_debug_tx(list_entry(tmp, kib_tx_t, tx_list));
-
- CDEBUG(D_CONSOLE, " tx_queue_rsrvd:\n");
- list_for_each(tmp, &conn->ibc_tx_queue_rsrvd)
- kiblnd_debug_tx(list_entry(tmp, kib_tx_t, tx_list));
-
- CDEBUG(D_CONSOLE, " tx_queue:\n");
- list_for_each(tmp, &conn->ibc_tx_queue)
- kiblnd_debug_tx(list_entry(tmp, kib_tx_t, tx_list));
-
- CDEBUG(D_CONSOLE, " active_txs:\n");
- list_for_each(tmp, &conn->ibc_active_txs)
- kiblnd_debug_tx(list_entry(tmp, kib_tx_t, tx_list));
-
- CDEBUG(D_CONSOLE, " rxs:\n");
- for (i = 0; i < IBLND_RX_MSGS(conn->ibc_version); i++)
- kiblnd_debug_rx(&conn->ibc_rxs[i]);
-
- spin_unlock(&conn->ibc_lock);
-}
-
int
kiblnd_translate_mtu(int value)
{
@@ -1039,8 +971,8 @@ kiblnd_close_stale_conns_locked (kib_peer_t *peer,
return count;
}
-int
-kiblnd_close_matching_conns (lnet_ni_t *ni, lnet_nid_t nid)
+static int
+kiblnd_close_matching_conns(lnet_ni_t *ni, lnet_nid_t nid)
{
kib_peer_t *peer;
struct list_head *ptmp;
@@ -1440,7 +1372,7 @@ kiblnd_find_rd_dma_mr(kib_hca_dev_t *hdev, kib_rdma_desc_t *rd)
return mr;
}
-void
+static void
kiblnd_destroy_fmr_pool(kib_fmr_pool_t *pool)
{
LASSERT (pool->fpo_map_count == 0);
@@ -1454,7 +1386,7 @@ kiblnd_destroy_fmr_pool(kib_fmr_pool_t *pool)
LIBCFS_FREE(pool, sizeof(kib_fmr_pool_t));
}
-void
+static void
kiblnd_destroy_fmr_pool_list(struct list_head *head)
{
kib_fmr_pool_t *pool;
@@ -1480,7 +1412,7 @@ static int kiblnd_fmr_flush_trigger(int ncpts)
return max(IBLND_FMR_POOL_FLUSH, size);
}
-int
+static int
kiblnd_create_fmr_pool(kib_fmr_poolset_t *fps, kib_fmr_pool_t **pp_fpo)
{
/* FMR pool for RDMA */
@@ -1719,7 +1651,7 @@ kiblnd_init_pool(kib_poolset_t *ps, kib_pool_t *pool, int size)
pool->po_size = size;
}
-void
+static void
kiblnd_destroy_pool_list(struct list_head *head)
{
kib_pool_t *pool;
@@ -2192,7 +2124,7 @@ kiblnd_tx_init(kib_pool_t *pool, struct list_head *node)
tx->tx_cookie = tps->tps_next_tx_cookie ++;
}
-void
+static void
kiblnd_net_fini_pools(kib_net_t *net)
{
int i;
@@ -2234,7 +2166,7 @@ kiblnd_net_fini_pools(kib_net_t *net)
}
}
-int
+static int
kiblnd_net_init_pools(kib_net_t *net, __u32 *cpts, int ncpts)
{
unsigned long flags;
@@ -2408,7 +2340,7 @@ kiblnd_hdev_get_attr(kib_hca_dev_t *hdev)
return -EINVAL;
}
-void
+static void
kiblnd_hdev_cleanup_mrs(kib_hca_dev_t *hdev)
{
int i;
@@ -2442,7 +2374,7 @@ kiblnd_hdev_destroy(kib_hca_dev_t *hdev)
LIBCFS_FREE(hdev, sizeof(*hdev));
}
-int
+static int
kiblnd_hdev_setup_mrs(kib_hca_dev_t *hdev)
{
struct ib_mr *mr;
@@ -2746,7 +2678,7 @@ kiblnd_destroy_dev (kib_dev_t *dev)
LIBCFS_FREE(dev, sizeof(*dev));
}
-kib_dev_t *
+static kib_dev_t *
kiblnd_create_dev(char *ifname)
{
struct net_device *netdev;
@@ -2800,7 +2732,7 @@ kiblnd_create_dev(char *ifname)
return dev;
}
-void
+static void
kiblnd_base_shutdown(void)
{
struct kib_sched_info *sched;
@@ -2842,7 +2774,8 @@ kiblnd_base_shutdown(void)
CDEBUG(((i & (-i)) == i) ? D_WARNING : D_NET, /* power of 2? */
"Waiting for %d threads to terminate\n",
atomic_read(&kiblnd_data.kib_nthreads));
- cfs_pause(cfs_time_seconds(1));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1));
}
/* fall through */
@@ -2903,7 +2836,8 @@ kiblnd_shutdown (lnet_ni_t *ni)
"%s: waiting for %d peers to disconnect\n",
libcfs_nid2str(ni->ni_nid),
atomic_read(&net->ibn_npeers));
- cfs_pause(cfs_time_seconds(1));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1));
}
kiblnd_net_fini_pools(net);
@@ -2940,7 +2874,7 @@ out:
return;
}
-int
+static int
kiblnd_base_startup(void)
{
struct kib_sched_info *sched;
@@ -3030,7 +2964,7 @@ kiblnd_base_startup(void)
return -ENETDOWN;
}
-int
+static int
kiblnd_start_schedulers(struct kib_sched_info *sched)
{
int rc = 0;
@@ -3071,7 +3005,7 @@ kiblnd_start_schedulers(struct kib_sched_info *sched)
return rc;
}
-int
+static int
kiblnd_dev_start_threads(kib_dev_t *dev, int newdev, __u32 *cpts, int ncpts)
{
int cpt;
@@ -3097,7 +3031,7 @@ kiblnd_dev_start_threads(kib_dev_t *dev, int newdev, __u32 *cpts, int ncpts)
return 0;
}
-kib_dev_t *
+static kib_dev_t *
kiblnd_dev_search(char *ifname)
{
kib_dev_t *alias = NULL;
@@ -3226,13 +3160,13 @@ failed:
return -ENETDOWN;
}
-void __exit
+static void __exit
kiblnd_module_fini (void)
{
lnet_unregister_lnd(&the_o2iblnd);
}
-int __init
+static int __init
kiblnd_module_init (void)
{
int rc;
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
index 6f58ead20393..6173e74d7492 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
@@ -3127,7 +3127,7 @@ kiblnd_connd (void *arg)
cfs_block_allsigs ();
- init_waitqueue_entry_current (&wait);
+ init_waitqueue_entry(&wait, current);
kiblnd_data.kib_connd = current;
spin_lock_irqsave(&kiblnd_data.kib_connd_lock, flags);
@@ -3208,7 +3208,7 @@ kiblnd_connd (void *arg)
add_wait_queue(&kiblnd_data.kib_connd_waitq, &wait);
spin_unlock_irqrestore(&kiblnd_data.kib_connd_lock, flags);
- waitq_timedwait(&wait, TASK_INTERRUPTIBLE, timeout);
+ schedule_timeout(timeout);
set_current_state(TASK_RUNNING);
remove_wait_queue(&kiblnd_data.kib_connd_waitq, &wait);
@@ -3324,7 +3324,7 @@ kiblnd_scheduler(void *arg)
cfs_block_allsigs();
- init_waitqueue_entry_current(&wait);
+ init_waitqueue_entry(&wait, current);
sched = kiblnd_data.kib_scheds[KIB_THREAD_CPT(id)];
@@ -3423,7 +3423,7 @@ kiblnd_scheduler(void *arg)
add_wait_queue_exclusive(&sched->ibs_waitq, &wait);
spin_unlock_irqrestore(&sched->ibs_lock, flags);
- waitq_wait(&wait, TASK_INTERRUPTIBLE);
+ schedule();
busy_loops = 0;
remove_wait_queue(&sched->ibs_waitq, &wait);
@@ -3450,7 +3450,7 @@ kiblnd_failover_thread(void *arg)
cfs_block_allsigs ();
- init_waitqueue_entry_current(&wait);
+ init_waitqueue_entry(&wait, current);
write_lock_irqsave(glock, flags);
while (!kiblnd_data.kib_shutdown) {
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
index 8f74d0be32f1..21d36ee5378a 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
@@ -2336,7 +2336,8 @@ ksocknal_base_shutdown(void)
"waiting for %d threads to terminate\n",
ksocknal_data.ksnd_nthreads);
read_unlock(&ksocknal_data.ksnd_global_lock);
- cfs_pause(cfs_time_seconds(1));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1));
read_lock(&ksocknal_data.ksnd_global_lock);
}
read_unlock(&ksocknal_data.ksnd_global_lock);
@@ -2584,7 +2585,8 @@ ksocknal_shutdown (lnet_ni_t *ni)
CDEBUG(((i & (-i)) == i) ? D_WARNING : D_NET, /* power of 2? */
"waiting for %d peers to disconnect\n",
net->ksnn_npeers);
- cfs_pause(cfs_time_seconds(1));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1));
ksocknal_debug_peerhash(ni);
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
index b7b53b579c85..bdf95ea8a54d 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
@@ -189,7 +189,8 @@ ksocknal_transmit (ksock_conn_t *conn, ksock_tx_t *tx)
int bufnob;
if (ksocknal_data.ksnd_stall_tx != 0) {
- cfs_pause(cfs_time_seconds(ksocknal_data.ksnd_stall_tx));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(ksocknal_data.ksnd_stall_tx));
}
LASSERT (tx->tx_resid != 0);
@@ -345,7 +346,8 @@ ksocknal_receive (ksock_conn_t *conn)
int rc;
if (ksocknal_data.ksnd_stall_rx != 0) {
- cfs_pause(cfs_time_seconds (ksocknal_data.ksnd_stall_rx));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(ksocknal_data.ksnd_stall_rx));
}
rc = ksocknal_connsock_addref(conn);
@@ -2140,7 +2142,7 @@ ksocknal_connd (void *arg)
cfs_block_allsigs ();
- init_waitqueue_entry_current (&wait);
+ init_waitqueue_entry(&wait, current);
spin_lock_bh(connd_lock);
@@ -2229,7 +2231,7 @@ ksocknal_connd (void *arg)
spin_unlock_bh(connd_lock);
nloops = 0;
- waitq_timedwait(&wait, TASK_INTERRUPTIBLE, timeout);
+ schedule_timeout(timeout);
set_current_state(TASK_RUNNING);
remove_wait_queue(&ksocknal_data.ksnd_connd_waitq, &wait);
@@ -2532,7 +2534,7 @@ ksocknal_reaper (void *arg)
cfs_block_allsigs ();
INIT_LIST_HEAD(&enomem_conns);
- init_waitqueue_entry_current (&wait);
+ init_waitqueue_entry(&wait, current);
spin_lock_bh(&ksocknal_data.ksnd_reaper_lock);
@@ -2639,8 +2641,7 @@ ksocknal_reaper (void *arg)
if (!ksocknal_data.ksnd_shuttingdown &&
list_empty (&ksocknal_data.ksnd_deathrow_conns) &&
list_empty (&ksocknal_data.ksnd_zombie_conns))
- waitq_timedwait (&wait, TASK_INTERRUPTIBLE,
- timeout);
+ schedule_timeout(timeout);
set_current_state (TASK_RUNNING);
remove_wait_queue (&ksocknal_data.ksnd_reaper_waitq, &wait);
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
index 80141aa32c21..a54b506ba7ca 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
@@ -373,7 +373,8 @@ ksocknal_lib_recv_kiov (ksock_conn_t *conn)
/* NB we can't trust socket ops to either consume our iovs
* or leave them alone. */
- if ((addr = ksocknal_lib_kiov_vmap(kiov, niov, scratchiov, pages)) != NULL) {
+ addr = ksocknal_lib_kiov_vmap(kiov, niov, scratchiov, pages);
+ if (addr != NULL) {
nob = scratchiov[0].iov_len;
msg.msg_iovlen = 1;
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
index 71205e2015ce..2d91571cbab2 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
@@ -165,7 +165,8 @@ ksocknal_queue_tx_zcack_v3(ksock_conn_t *conn,
LASSERT (tx_ack == NULL ||
tx_ack->tx_msg.ksm_type == KSOCK_MSG_NOOP);
- if ((tx = conn->ksnc_tx_carrier) == NULL) {
+ tx = conn->ksnc_tx_carrier;
+ if (tx == NULL) {
if (tx_ack != NULL) {
list_add_tail(&tx_ack->tx_list,
&conn->ksnc_tx_queue);
@@ -392,7 +393,8 @@ ksocknal_handle_zcreq(ksock_conn_t *c, __u64 cookie, int remote)
if (tx == NULL)
return -ENOMEM;
- if ((rc = ksocknal_launch_packet(peer->ksnp_ni, tx, peer->ksnp_id)) == 0)
+ rc = ksocknal_launch_packet(peer->ksnp_ni, tx, peer->ksnp_id);
+ if (rc == 0)
return 0;
ksocknal_free_tx(tx);
diff --git a/drivers/staging/lustre/lnet/lnet/acceptor.c b/drivers/staging/lustre/lnet/lnet/acceptor.c
index cb2ecd717714..09ea6cb1492c 100644
--- a/drivers/staging/lustre/lnet/lnet/acceptor.c
+++ b/drivers/staging/lustre/lnet/lnet/acceptor.c
@@ -371,7 +371,8 @@ lnet_acceptor(void *arg)
if (rc != 0) {
if (rc != -EAGAIN) {
CWARN("Accept error %d: pausing...\n", rc);
- cfs_pause(cfs_time_seconds(1));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1));
}
continue;
}
diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c
index c562ff3e9283..45c23194081b 100644
--- a/drivers/staging/lustre/lnet/lnet/api-ni.c
+++ b/drivers/staging/lustre/lnet/lnet/api-ni.c
@@ -770,7 +770,7 @@ lnet_nid_cpt_hash(lnet_nid_t nid, unsigned int number)
if (number == 1)
return 0;
- val = cfs_hash_long(key, LNET_CPT_BITS);
+ val = hash_long(key, LNET_CPT_BITS);
/* NB: LNET_CP_NUMBER doesn't have to be PO2 */
if (val < number)
return val;
@@ -994,7 +994,8 @@ lnet_shutdown_lndnis (void)
"Waiting for zombie LNI %s\n",
libcfs_nid2str(ni->ni_nid));
}
- cfs_pause(cfs_time_seconds(1));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1));
lnet_net_lock(LNET_LOCK_EX);
continue;
}
diff --git a/drivers/staging/lustre/lnet/lnet/config.c b/drivers/staging/lustre/lnet/lnet/config.c
index 6a07b0a65d12..d97464e95ddb 100644
--- a/drivers/staging/lustre/lnet/lnet/config.c
+++ b/drivers/staging/lustre/lnet/lnet/config.c
@@ -443,7 +443,7 @@ lnet_str2tbs_sep(struct list_head *tbs, char *str)
/* Split 'str' into separate commands */
for (;;) {
/* skip leading whitespace */
- while (cfs_iswhite(*str))
+ while (isspace(*str))
str++;
/* scan for separator or comment */
@@ -460,7 +460,7 @@ lnet_str2tbs_sep(struct list_head *tbs, char *str)
}
for (i = 0; i < nob; i++)
- if (cfs_iswhite(str[i]))
+ if (isspace(str[i]))
ltb->ltb_text[i] = ' ';
else
ltb->ltb_text[i] = str[i];
@@ -667,7 +667,7 @@ lnet_parse_route(char *str, int *im_a_router)
sep = str;
for (;;) {
/* scan for token start */
- while (cfs_iswhite(*sep))
+ while (isspace(*sep))
sep++;
if (*sep == 0) {
if (ntokens < (got_hops ? 3 : 2))
@@ -679,7 +679,7 @@ lnet_parse_route(char *str, int *im_a_router)
token = sep++;
/* scan for token end */
- while (*sep != 0 && !cfs_iswhite(*sep))
+ while (*sep != 0 && !isspace(*sep))
sep++;
if (*sep != 0)
*sep++ = 0;
@@ -858,7 +858,7 @@ lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip)
sep = tokens;
for (;;) {
/* scan for token start */
- while (cfs_iswhite(*sep))
+ while (isspace(*sep))
sep++;
if (*sep == 0)
break;
@@ -866,7 +866,7 @@ lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip)
token = sep++;
/* scan for token end */
- while (*sep != 0 && !cfs_iswhite(*sep))
+ while (*sep != 0 && !isspace(*sep))
sep++;
if (*sep != 0)
*sep++ = 0;
diff --git a/drivers/staging/lustre/lnet/lnet/lib-eq.c b/drivers/staging/lustre/lnet/lnet/lib-eq.c
index 4ce68d3b0931..7ce07f61b2e1 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-eq.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-eq.c
@@ -334,21 +334,20 @@ lnet_eq_wait_locked(int *timeout_ms)
if (tms == 0)
return -1; /* don't want to wait and no new event */
- init_waitqueue_entry_current(&wl);
+ init_waitqueue_entry(&wl, current);
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&the_lnet.ln_eq_waitq, &wl);
lnet_eq_wait_unlock();
if (tms < 0) {
- waitq_wait(&wl, TASK_INTERRUPTIBLE);
+ schedule();
} else {
struct timeval tv;
now = cfs_time_current();
- waitq_timedwait(&wl, TASK_INTERRUPTIBLE,
- cfs_time_seconds(tms) / 1000);
+ schedule_timeout(cfs_time_seconds(tms) / 1000);
cfs_duration_usec(cfs_time_sub(cfs_time_current(), now), &tv);
tms -= (int)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
if (tms < 0) /* no more wait but may have new event */
diff --git a/drivers/staging/lustre/lnet/lnet/lib-ptl.c b/drivers/staging/lustre/lnet/lnet/lib-ptl.c
index 6fffd5e96f9c..920df69960a5 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-ptl.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-ptl.c
@@ -366,7 +366,7 @@ lnet_mt_match_head(struct lnet_match_table *mtable,
unsigned long hash = mbits + id.nid + id.pid;
LASSERT(lnet_ptl_is_unique(ptl));
- hash = cfs_hash_long(hash, LNET_MT_HASH_BITS);
+ hash = hash_long(hash, LNET_MT_HASH_BITS);
return &mtable->mt_mhash[hash];
}
}
diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c
index 286977691393..72802b0404a4 100644
--- a/drivers/staging/lustre/lnet/lnet/peer.c
+++ b/drivers/staging/lustre/lnet/lnet/peer.c
@@ -145,7 +145,8 @@ lnet_peer_tables_cleanup(void)
"Waiting for %d peers on peer table\n",
ptable->pt_number);
}
- cfs_pause(cfs_time_seconds(1) / 2);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1) / 2);
lnet_net_lock(i);
}
list_splice_init(&ptable->pt_deathrow, &deathrow);
diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c
index d1ee44232eef..995f50976c42 100644
--- a/drivers/staging/lustre/lnet/lnet/router.c
+++ b/drivers/staging/lustre/lnet/lnet/router.c
@@ -779,7 +779,8 @@ lnet_wait_known_routerstate(void)
if (all_known)
return;
- cfs_pause(cfs_time_seconds(1));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1));
}
}
@@ -1147,7 +1148,8 @@ lnet_prune_rc_data(int wait_unlink)
i++;
CDEBUG(((i & (-i)) == i) ? D_WARNING : D_NET,
"Waiting for rc buffers to unlink\n");
- cfs_pause(cfs_time_seconds(1) / 4);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1) / 4);
lnet_net_lock(LNET_LOCK_EX);
}
@@ -1206,11 +1208,11 @@ rescan:
lnet_prune_rc_data(0); /* don't wait for UNLINK */
- /* Call cfs_pause() here always adds 1 to load average
+ /* Call schedule_timeout() here always adds 1 to load average
* because kernel counts # active tasks as nr_running
* + nr_uninterruptible. */
- schedule_timeout_and_set_state(TASK_INTERRUPTIBLE,
- cfs_time_seconds(1));
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1));
}
LASSERT(the_lnet.ln_rc_state == LNET_RC_STATE_STOPPING);
diff --git a/drivers/staging/lustre/lnet/lnet/router_proc.c b/drivers/staging/lustre/lnet/lnet/router_proc.c
index 20d53e08705e..0cbd9fc98e07 100644
--- a/drivers/staging/lustre/lnet/lnet/router_proc.c
+++ b/drivers/staging/lustre/lnet/lnet/router_proc.c
@@ -837,8 +837,8 @@ static int __proc_lnet_portal_rotor(void *data, int write,
rc = -EINVAL;
lnet_res_lock(0);
for (i = 0; portal_rotors[i].pr_name != NULL; i++) {
- if (cfs_strncasecmp(portal_rotors[i].pr_name, tmp,
- strlen(portal_rotors[i].pr_name)) == 0) {
+ if (strncasecmp(portal_rotors[i].pr_name, tmp,
+ strlen(portal_rotors[i].pr_name)) == 0) {
portal_rotor = portal_rotors[i].pr_value;
rc = 0;
break;
diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c
index 53d58924737b..8d1eea4cef6f 100644
--- a/drivers/staging/lustre/lnet/selftest/conrpc.c
+++ b/drivers/staging/lustre/lnet/selftest/conrpc.c
@@ -1346,7 +1346,8 @@ lstcon_rpc_cleanup_wait(void)
mutex_unlock(&console_session.ses_mutex);
CWARN("Session is shutting down, waiting for termination of transactions\n");
- cfs_pause(cfs_time_seconds(1));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1));
mutex_lock(&console_session.ses_mutex);
}
diff --git a/drivers/staging/lustre/lnet/selftest/console.c b/drivers/staging/lustre/lnet/selftest/console.c
index 2a8eddc7db52..352fc96398d2 100644
--- a/drivers/staging/lustre/lnet/selftest/console.c
+++ b/drivers/staging/lustre/lnet/selftest/console.c
@@ -61,7 +61,7 @@ do { \
lstcon_session_t console_session;
-void
+static void
lstcon_node_get(lstcon_node_t *nd)
{
LASSERT (nd->nd_ref >= 1);
@@ -114,7 +114,7 @@ lstcon_node_find(lnet_process_id_t id, lstcon_node_t **ndpp, int create)
return 0;
}
-void
+static void
lstcon_node_put(lstcon_node_t *nd)
{
lstcon_ndlink_t *ndl;
@@ -344,7 +344,7 @@ lstcon_group_move(lstcon_group_t *old, lstcon_group_t *new)
}
}
-int
+static int
lstcon_sesrpc_condition(int transop, lstcon_node_t *nd, void *arg)
{
lstcon_group_t *grp = (lstcon_group_t *)arg;
@@ -373,7 +373,7 @@ lstcon_sesrpc_condition(int transop, lstcon_node_t *nd, void *arg)
return 1;
}
-int
+static int
lstcon_sesrpc_readent(int transop, srpc_msg_t *msg,
lstcon_rpc_ent_t *ent_up)
{
@@ -830,7 +830,7 @@ lstcon_group_info(char *name, lstcon_ndlist_ent_t *gents_p,
return 0;
}
-int
+static int
lstcon_batch_find(const char *name, lstcon_batch_t **batpp)
{
lstcon_batch_t *bat;
@@ -998,7 +998,7 @@ lstcon_batch_info(char *name, lstcon_test_batch_ent_t *ent_up, int server,
return rc;
}
-int
+static int
lstcon_batrpc_condition(int transop, lstcon_node_t *nd, void *arg)
{
switch (transop) {
@@ -1141,7 +1141,7 @@ lstcon_batch_destroy(lstcon_batch_t *bat)
LIBCFS_FREE(bat, sizeof(lstcon_batch_t));
}
-int
+static int
lstcon_testrpc_condition(int transop, lstcon_node_t *nd, void *arg)
{
lstcon_test_t *test;
@@ -1370,7 +1370,7 @@ out:
return rc;
}
-int
+static int
lstcon_test_find(lstcon_batch_t *batch, int idx, lstcon_test_t **testpp)
{
lstcon_test_t *test;
@@ -1385,7 +1385,7 @@ lstcon_test_find(lstcon_batch_t *batch, int idx, lstcon_test_t **testpp)
return -ENOENT;
}
-int
+static int
lstcon_tsbrpc_readent(int transop, srpc_msg_t *msg,
lstcon_rpc_ent_t *ent_up)
{
@@ -1464,7 +1464,7 @@ lstcon_test_batch_query(char *name, int testidx, int client,
return rc;
}
-int
+static int
lstcon_statrpc_readent(int transop, srpc_msg_t *msg,
lstcon_rpc_ent_t *ent_up)
{
@@ -1488,7 +1488,7 @@ lstcon_statrpc_readent(int transop, srpc_msg_t *msg,
return 0;
}
-int
+static int
lstcon_ndlist_stat(struct list_head *ndlist,
int timeout, struct list_head *result_up)
{
@@ -1577,7 +1577,7 @@ lstcon_nodes_stat(int count, lnet_process_id_t *ids_up,
return rc;
}
-int
+static int
lstcon_debug_ndlist(struct list_head *ndlist,
struct list_head *translist,
int timeout, struct list_head *result_up)
diff --git a/drivers/staging/lustre/lnet/selftest/rpc.c b/drivers/staging/lustre/lnet/selftest/rpc.c
index d838985f51cb..9fc0429e8296 100644
--- a/drivers/staging/lustre/lnet/selftest/rpc.c
+++ b/drivers/staging/lustre/lnet/selftest/rpc.c
@@ -1585,7 +1585,8 @@ srpc_startup (void)
spin_lock_init(&srpc_data.rpc_glock);
/* 1 second pause to avoid timestamp reuse */
- cfs_pause(cfs_time_seconds(1));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1));
srpc_data.rpc_matchbits = ((__u64) cfs_time_current_sec()) << 48;
srpc_data.rpc_state = SRPC_STATE_NONE;
diff --git a/drivers/staging/lustre/lnet/selftest/selftest.h b/drivers/staging/lustre/lnet/selftest/selftest.h
index 228927e0f962..f4806a6bc942 100644
--- a/drivers/staging/lustre/lnet/selftest/selftest.h
+++ b/drivers/staging/lustre/lnet/selftest/selftest.h
@@ -572,7 +572,11 @@ swi_state2str (int state)
#undef STATE2STR
}
-#define selftest_wait_events() cfs_pause(cfs_time_seconds(1) / 10)
+#define selftest_wait_events() \
+ do { \
+ set_current_state(TASK_UNINTERRUPTIBLE); \
+ schedule_timeout(cfs_time_seconds(1) / 10); \
+ } while (0)
#define lst_wait_until(cond, lock, fmt, ...) \
diff --git a/drivers/staging/lustre/lustre/fid/fid_request.c b/drivers/staging/lustre/lustre/fid/fid_request.c
index 79fc2fe131a2..3401c9ad42ac 100644
--- a/drivers/staging/lustre/lustre/fid/fid_request.c
+++ b/drivers/staging/lustre/lustre/fid/fid_request.c
@@ -196,8 +196,8 @@ static int seq_client_alloc_seq(const struct lu_env *env,
if (range_is_exhausted(&seq->lcs_space)) {
rc = seq_client_alloc_meta(env, seq);
if (rc) {
- CERROR("%s: Can't allocate new meta-sequence,"
- "rc %d\n", seq->lcs_name, rc);
+ CERROR("%s: Can't allocate new meta-sequence, rc %d\n",
+ seq->lcs_name, rc);
return rc;
} else {
CDEBUG(D_INFO, "%s: New range - "DRANGE"\n",
@@ -225,7 +225,7 @@ static int seq_fid_alloc_prep(struct lu_client_seq *seq,
set_current_state(TASK_UNINTERRUPTIBLE);
mutex_unlock(&seq->lcs_mutex);
- waitq_wait(link, TASK_UNINTERRUPTIBLE);
+ schedule();
mutex_lock(&seq->lcs_mutex);
remove_wait_queue(&seq->lcs_waitq, link);
@@ -256,7 +256,7 @@ int seq_client_get_seq(const struct lu_env *env,
LASSERT(seqnr != NULL);
mutex_lock(&seq->lcs_mutex);
- init_waitqueue_entry_current(&link);
+ init_waitqueue_entry(&link, current);
while (1) {
rc = seq_fid_alloc_prep(seq, &link);
@@ -266,15 +266,15 @@ int seq_client_get_seq(const struct lu_env *env,
rc = seq_client_alloc_seq(env, seq, seqnr);
if (rc) {
- CERROR("%s: Can't allocate new sequence, "
- "rc %d\n", seq->lcs_name, rc);
+ CERROR("%s: Can't allocate new sequence, rc %d\n",
+ seq->lcs_name, rc);
seq_fid_alloc_fini(seq);
mutex_unlock(&seq->lcs_mutex);
return rc;
}
- CDEBUG(D_INFO, "%s: allocate sequence "
- "[0x%16.16"LPF64"x]\n", seq->lcs_name, *seqnr);
+ CDEBUG(D_INFO, "%s: allocate sequence [0x%16.16"LPF64"x]\n",
+ seq->lcs_name, *seqnr);
/* Since the caller require the whole seq,
* so marked this seq to be used */
@@ -306,7 +306,7 @@ int seq_client_alloc_fid(const struct lu_env *env,
LASSERT(seq != NULL);
LASSERT(fid != NULL);
- init_waitqueue_entry_current(&link);
+ init_waitqueue_entry(&link, current);
mutex_lock(&seq->lcs_mutex);
if (OBD_FAIL_CHECK(OBD_FAIL_SEQ_EXHAUST))
@@ -329,15 +329,15 @@ int seq_client_alloc_fid(const struct lu_env *env,
rc = seq_client_alloc_seq(env, seq, &seqnr);
if (rc) {
- CERROR("%s: Can't allocate new sequence, "
- "rc %d\n", seq->lcs_name, rc);
+ CERROR("%s: Can't allocate new sequence, rc %d\n",
+ seq->lcs_name, rc);
seq_fid_alloc_fini(seq);
mutex_unlock(&seq->lcs_mutex);
return rc;
}
- CDEBUG(D_INFO, "%s: Switch to sequence "
- "[0x%16.16"LPF64"x]\n", seq->lcs_name, seqnr);
+ CDEBUG(D_INFO, "%s: Switch to sequence [0x%16.16"LPF64"x]\n",
+ seq->lcs_name, seqnr);
seq->lcs_fid.f_oid = LUSTRE_FID_INIT_OID;
seq->lcs_fid.f_seq = seqnr;
@@ -370,7 +370,7 @@ void seq_client_flush(struct lu_client_seq *seq)
wait_queue_t link;
LASSERT(seq != NULL);
- init_waitqueue_entry_current(&link);
+ init_waitqueue_entry(&link, current);
mutex_lock(&seq->lcs_mutex);
while (seq->lcs_update) {
@@ -378,7 +378,7 @@ void seq_client_flush(struct lu_client_seq *seq)
set_current_state(TASK_UNINTERRUPTIBLE);
mutex_unlock(&seq->lcs_mutex);
- waitq_wait(&link, TASK_UNINTERRUPTIBLE);
+ schedule();
mutex_lock(&seq->lcs_mutex);
remove_wait_queue(&seq->lcs_waitq, &link);
@@ -428,8 +428,8 @@ static int seq_client_proc_init(struct lu_client_seq *seq)
rc = lprocfs_add_vars(seq->lcs_proc_dir,
seq_client_proc_list, seq);
if (rc) {
- CERROR("%s: Can't init sequence manager "
- "proc, rc %d\n", seq->lcs_name, rc);
+ CERROR("%s: Can't init sequence manager proc, rc %d\n",
+ seq->lcs_name, rc);
GOTO(out_cleanup, rc);
}
diff --git a/drivers/staging/lustre/lustre/fld/fld_cache.c b/drivers/staging/lustre/lustre/fld/fld_cache.c
index 6c379301df82..a06a642f549e 100644
--- a/drivers/staging/lustre/lustre/fld/fld_cache.c
+++ b/drivers/staging/lustre/lustre/fld/fld_cache.c
@@ -236,8 +236,8 @@ static int fld_cache_shrink(struct fld_cache *cache)
num++;
}
- CDEBUG(D_INFO, "%s: FLD cache - Shrunk by "
- "%d entries\n", cache->fci_name, num);
+ CDEBUG(D_INFO, "%s: FLD cache - Shrunk by %d entries\n",
+ cache->fci_name, num);
return 0;
}
@@ -355,7 +355,7 @@ static void fld_cache_overlap_handle(struct fld_cache *cache,
fld_cache_entry_add(cache, f_new, &f_curr->fce_list);
} else
CERROR("NEW range ="DRANGE" curr = "DRANGE"\n",
- PRANGE(range),PRANGE(&f_curr->fce_range));
+ PRANGE(range), PRANGE(&f_curr->fce_range));
}
struct fld_cache_entry
diff --git a/drivers/staging/lustre/lustre/fld/fld_internal.h b/drivers/staging/lustre/lustre/fld/fld_internal.h
index 5f3935cc0fd7..8661a788f120 100644
--- a/drivers/staging/lustre/lustre/fld/fld_internal.h
+++ b/drivers/staging/lustre/lustre/fld/fld_internal.h
@@ -90,7 +90,7 @@ struct fld_cache {
int fci_threshold;
/**
- * Prefered number of cached entries */
+ * Preferred number of cached entries */
int fci_cache_size;
/**
diff --git a/drivers/staging/lustre/lustre/fld/fld_request.c b/drivers/staging/lustre/lustre/fld/fld_request.c
index 896f9fe83ffd..1f8abba31428 100644
--- a/drivers/staging/lustre/lustre/fld/fld_request.c
+++ b/drivers/staging/lustre/lustre/fld/fld_request.c
@@ -138,9 +138,8 @@ fld_rrb_scan(struct lu_client_fld *fld, seqno_t seq)
return target;
}
- CERROR("%s: Can't find target by hash %d (seq "LPX64"). "
- "Targets (%d):\n", fld->lcf_name, hash, seq,
- fld->lcf_count);
+ CERROR("%s: Can't find target by hash %d (seq "LPX64"). Targets (%d):\n",
+ fld->lcf_name, hash, seq, fld->lcf_count);
list_for_each_entry(target, &fld->lcf_targets, ft_chain) {
const char *srv_name = target->ft_srv != NULL ?
@@ -209,9 +208,8 @@ int fld_client_add_target(struct lu_client_fld *fld,
LASSERT(tar->ft_srv != NULL || tar->ft_exp != NULL);
if (fld->lcf_flags != LUSTRE_FLD_INIT) {
- CERROR("%s: Attempt to add target %s (idx "LPU64") "
- "on fly - skip it\n", fld->lcf_name, name,
- tar->ft_idx);
+ CERROR("%s: Attempt to add target %s (idx "LPU64") on fly - skip it\n",
+ fld->lcf_name, name, tar->ft_idx);
return 0;
} else {
CDEBUG(D_INFO, "%s: Adding target %s (idx "
@@ -476,9 +474,8 @@ int fld_client_lookup(struct lu_client_fld *fld, seqno_t seq, mdsno_t *mds,
target = fld_client_get_target(fld, seq);
LASSERT(target != NULL);
- CDEBUG(D_INFO, "%s: Lookup fld entry (seq: "LPX64") on "
- "target %s (idx "LPU64")\n", fld->lcf_name, seq,
- fld_target_name(target), target->ft_idx);
+ CDEBUG(D_INFO, "%s: Lookup fld entry (seq: "LPX64") on target %s (idx "LPU64")\n",
+ fld->lcf_name, seq, fld_target_name(target), target->ft_idx);
res.lsr_start = seq;
fld_range_set_type(&res, flags);
diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h
index 4d692dcd96cf..c809239c0866 100644
--- a/drivers/staging/lustre/lustre/include/cl_object.h
+++ b/drivers/staging/lustre/lustre/include/cl_object.h
@@ -1314,7 +1314,7 @@ static inline int __page_in_use(const struct cl_page *page, int refc)
* calls. To achieve this, every layer can implement ->clo_fits_into() method,
* that is called by lock matching code (cl_lock_lookup()), and that can be
* used to selectively disable matching of certain locks for certain IOs. For
- * exmaple, lov layer implements lov_lock_fits_into() that allow multi-stripe
+ * example, lov layer implements lov_lock_fits_into() that allow multi-stripe
* locks to be matched only for truncates and O_APPEND writes.
*
* Interaction with DLM
@@ -2385,14 +2385,18 @@ struct cl_io {
* Check if layout changed after the IO finishes. Mainly for HSM
* requirement. If IO occurs to openning files, it doesn't need to
* verify layout because HSM won't release openning files.
- * Right now, only two opertaions need to verify layout: glimpse
+ * Right now, only two operations need to verify layout: glimpse
* and setattr.
*/
ci_verify_layout:1,
/**
* file is released, restore has to to be triggered by vvp layer
*/
- ci_restore_needed:1;
+ ci_restore_needed:1,
+ /**
+ * O_NOATIME
+ */
+ ci_noatime:1;
/**
* Number of pages owned by this IO. For invariant checking.
*/
@@ -2552,7 +2556,7 @@ struct cl_req_obj {
*/
struct cl_req {
enum cl_req_type crq_type;
- /** A list of pages being transfered */
+ /** A list of pages being transferred */
struct list_head crq_pages;
/** Number of pages in cl_req::crq_pages */
unsigned crq_nrpages;
@@ -3224,7 +3228,7 @@ void cl_sync_io_note(struct cl_sync_io *anchor, int ioret);
*
* - call chains have no non-lustre portions inserted between lustre code.
*
- * On a client both these assumtpion fails, because every user thread can
+ * On a client both these assumption fails, because every user thread can
* potentially execute lustre code as part of a system call, and lustre calls
* into VFS or MM that call back into lustre.
*
diff --git a/drivers/staging/lustre/lustre/include/ioctl.h b/drivers/staging/lustre/lustre/include/ioctl.h
index 227c261b2ae9..b986920926bd 100644
--- a/drivers/staging/lustre/lustre/include/ioctl.h
+++ b/drivers/staging/lustre/lustre/include/ioctl.h
@@ -38,7 +38,7 @@
* and on newer kernels this header is shared as _ASM_GENERIC_IOCTL_H.
*
* We can avoid any problems with the kernel header being included again by
- * defining _ASM_I386_IOCTL_H here so that a later occurence of <asm/ioctl.h>
+ * defining _ASM_I386_IOCTL_H here so that a later occurrence of <asm/ioctl.h>
* does not include the kernel's ioctl.h after this one. b=14746 */
#define _ASM_I386_IOCTL_H
#define _ASM_GENERIC_IOCTL_H
diff --git a/drivers/staging/lustre/lustre/include/lclient.h b/drivers/staging/lustre/lustre/include/lclient.h
index 27316f7b7a70..827209ea6bd0 100644
--- a/drivers/staging/lustre/lustre/include/lclient.h
+++ b/drivers/staging/lustre/lustre/include/lclient.h
@@ -118,8 +118,8 @@ struct ccc_io {
};
/**
- * True, if \a io is a normal io, False for other (sendfile, splice*).
- * must be impementated in arch specific code.
+ * True, if \a io is a normal io, False for splice_{read,write}.
+ * must be implemented in arch specific code.
*/
int cl_is_normalio(const struct lu_env *env, const struct cl_io *io);
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_acl.h b/drivers/staging/lustre/lustre/include/linux/lustre_acl.h
index 778b123ce31e..a91c5497d22c 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_acl.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_acl.h
@@ -44,7 +44,7 @@
#define _LUSTRE_LINUX_ACL_H
#ifndef _LUSTRE_ACL_H
-#error Shoud not include direectly. use #include <lustre_acl.h> instead
+#error Should not include directly. use #include <lustre_acl.h> instead
#endif
#include <linux/fs.h>
diff --git a/drivers/staging/lustre/lustre/include/linux/obd.h b/drivers/staging/lustre/lustre/include/linux/obd.h
index 01a50265239d..dc36f75eb635 100644
--- a/drivers/staging/lustre/lustre/include/linux/obd.h
+++ b/drivers/staging/lustre/lustre/include/linux/obd.h
@@ -96,7 +96,8 @@ static inline void __client_obd_list_lock(client_obd_lock_t *lock,
LCONSOLE_WARN("====== for current process =====\n");
dump_stack();
LCONSOLE_WARN("====== end =======\n");
- cfs_pause(1000 * HZ);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1000 * HZ);
}
cpu_relax();
}
diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
index 5da31c54924a..87905bbc68e1 100644
--- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
+++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
@@ -91,8 +91,8 @@
#ifndef _LUSTRE_IDL_H_
#define _LUSTRE_IDL_H_
-#if !defined(LASSERT) && !defined(LPU64)
-#include <linux/libcfs/libcfs.h> /* for LASSERT, LPUX64, etc */
+#if !defined(LPU64)
+#include <linux/libcfs/libcfs.h> /* for LPUX64, etc */
#endif
/* Defn's shared with user-space. */
@@ -232,7 +232,6 @@ static inline unsigned fld_range_is_any(const struct lu_seq_range *range)
static inline void fld_range_set_type(struct lu_seq_range *range,
unsigned flags)
{
- LASSERT(!(flags & ~LU_SEQ_RANGE_MASK));
range->lsr_flags |= flags;
}
@@ -351,7 +350,7 @@ struct som_attrs {
/** Bitfield for supported data in this structure. For future use. */
__u32 som_compat;
- /** Incompat feature list. The supported feature mask is availabe in
+ /** Incompat feature list. The supported feature mask is available in
* SOM_INCOMPAT_SUPP */
__u32 som_incompat;
@@ -615,7 +614,6 @@ static inline obd_id fid_idif_id(obd_seq seq, __u32 oid, __u32 ver)
/* extract ost index from IDIF FID */
static inline __u32 fid_idif_ost_idx(const struct lu_fid *fid)
{
- LASSERT(fid_is_idif(fid));
return (fid_seq(fid) >> 16) & 0xffff;
}
@@ -833,11 +831,6 @@ static inline void lu_igif_build(struct lu_fid *fid, __u32 ino, __u32 gen)
*/
static inline void fid_cpu_to_le(struct lu_fid *dst, const struct lu_fid *src)
{
- /* check that all fields are converted */
- CLASSERT(sizeof(*src) ==
- sizeof(fid_seq(src)) +
- sizeof(fid_oid(src)) +
- sizeof(fid_ver(src)));
dst->f_seq = cpu_to_le64(fid_seq(src));
dst->f_oid = cpu_to_le32(fid_oid(src));
dst->f_ver = cpu_to_le32(fid_ver(src));
@@ -845,11 +838,6 @@ static inline void fid_cpu_to_le(struct lu_fid *dst, const struct lu_fid *src)
static inline void fid_le_to_cpu(struct lu_fid *dst, const struct lu_fid *src)
{
- /* check that all fields are converted */
- CLASSERT(sizeof(*src) ==
- sizeof(fid_seq(src)) +
- sizeof(fid_oid(src)) +
- sizeof(fid_ver(src)));
dst->f_seq = le64_to_cpu(fid_seq(src));
dst->f_oid = le32_to_cpu(fid_oid(src));
dst->f_ver = le32_to_cpu(fid_ver(src));
@@ -857,11 +845,6 @@ static inline void fid_le_to_cpu(struct lu_fid *dst, const struct lu_fid *src)
static inline void fid_cpu_to_be(struct lu_fid *dst, const struct lu_fid *src)
{
- /* check that all fields are converted */
- CLASSERT(sizeof(*src) ==
- sizeof(fid_seq(src)) +
- sizeof(fid_oid(src)) +
- sizeof(fid_ver(src)));
dst->f_seq = cpu_to_be64(fid_seq(src));
dst->f_oid = cpu_to_be32(fid_oid(src));
dst->f_ver = cpu_to_be32(fid_ver(src));
@@ -869,11 +852,6 @@ static inline void fid_cpu_to_be(struct lu_fid *dst, const struct lu_fid *src)
static inline void fid_be_to_cpu(struct lu_fid *dst, const struct lu_fid *src)
{
- /* check that all fields are converted */
- CLASSERT(sizeof(*src) ==
- sizeof(fid_seq(src)) +
- sizeof(fid_oid(src)) +
- sizeof(fid_ver(src)));
dst->f_seq = be64_to_cpu(fid_seq(src));
dst->f_oid = be32_to_cpu(fid_oid(src));
dst->f_ver = be32_to_cpu(fid_ver(src));
@@ -897,11 +875,6 @@ extern void lustre_swab_lu_seq_range(struct lu_seq_range *range);
static inline int lu_fid_eq(const struct lu_fid *f0, const struct lu_fid *f1)
{
- /* Check that there is no alignment padding. */
- CLASSERT(sizeof(*f0) ==
- sizeof(f0->f_seq) +
- sizeof(f0->f_oid) +
- sizeof(f0->f_ver));
return memcmp(f0, f1, sizeof(*f0)) == 0;
}
@@ -960,7 +933,7 @@ enum lu_dirent_attrs {
LUDA_TYPE = 0x0002,
LUDA_64BITHASH = 0x0004,
- /* The following attrs are used for MDT interanl only,
+ /* The following attrs are used for MDT internal only,
* not visible to client */
/* Verify the dirent consistency */
@@ -1331,6 +1304,9 @@ extern void lustre_swab_ptlrpc_body(struct ptlrpc_body *pb);
#define OBD_CONNECT_LIGHTWEIGHT 0x1000000000000ULL/* lightweight connection */
#define OBD_CONNECT_SHORTIO 0x2000000000000ULL/* short io */
#define OBD_CONNECT_PINGLESS 0x4000000000000ULL/* pings not required */
+#define OBD_CONNECT_FLOCK_DEAD 0x8000000000000ULL/* flock deadlock detection */
+#define OBD_CONNECT_DISP_STRIPE 0x10000000000000ULL/*create stripe disposition*/
+
/* XXX README XXX:
* Please DO NOT add flag values here before first ensuring that this same
* flag value is not in use on some other branch. Please clear any such
@@ -1368,7 +1344,10 @@ extern void lustre_swab_ptlrpc_body(struct ptlrpc_body *pb);
OBD_CONNECT_EINPROGRESS | \
OBD_CONNECT_LIGHTWEIGHT | OBD_CONNECT_UMASK | \
OBD_CONNECT_LVB_TYPE | OBD_CONNECT_LAYOUTLOCK |\
- OBD_CONNECT_PINGLESS | OBD_CONNECT_MAX_EASIZE)
+ OBD_CONNECT_PINGLESS | OBD_CONNECT_MAX_EASIZE |\
+ OBD_CONNECT_FLOCK_DEAD | \
+ OBD_CONNECT_DISP_STRIPE)
+
#define OST_CONNECT_SUPPORTED (OBD_CONNECT_SRVLOCK | OBD_CONNECT_GRANT | \
OBD_CONNECT_REQPORTAL | OBD_CONNECT_VERSION | \
OBD_CONNECT_TRUNCLOCK | OBD_CONNECT_INDEX | \
@@ -1771,7 +1750,6 @@ static inline __u32 lov_mds_md_size(__u16 stripes, __u32 lmm_magic)
OBD_MD_FLGID | OBD_MD_FLFLAGS | OBD_MD_FLNLINK | \
OBD_MD_FLGENER | OBD_MD_FLRDEV | OBD_MD_FLGROUP)
-#define OBD_MD_FLXATTRLOCKED OBD_MD_FLGETATTRLOCK
#define OBD_MD_FLXATTRALL (OBD_MD_FLXATTR | OBD_MD_FLXATTRLS)
/* don't forget obdo_fid which is way down at the bottom so it can
@@ -2134,19 +2112,32 @@ extern void lustre_swab_generic_32s (__u32 *val);
#define DISP_LOOKUP_POS 0x00000008
#define DISP_OPEN_CREATE 0x00000010
#define DISP_OPEN_OPEN 0x00000020
-#define DISP_ENQ_COMPLETE 0x00400000
+#define DISP_ENQ_COMPLETE 0x00400000 /* obsolete and unused */
#define DISP_ENQ_OPEN_REF 0x00800000
#define DISP_ENQ_CREATE_REF 0x01000000
#define DISP_OPEN_LOCK 0x02000000
#define DISP_OPEN_LEASE 0x04000000
+#define DISP_OPEN_STRIPE 0x08000000
/* INODE LOCK PARTS */
-#define MDS_INODELOCK_LOOKUP 0x000001 /* dentry, mode, owner, group */
-#define MDS_INODELOCK_UPDATE 0x000002 /* size, links, timestamps */
-#define MDS_INODELOCK_OPEN 0x000004 /* For opened files */
-#define MDS_INODELOCK_LAYOUT 0x000008 /* for layout */
-#define MDS_INODELOCK_PERM 0x000010 /* for permission */
-#define MDS_INODELOCK_XATTR 0x000020 /* extended attributes */
+#define MDS_INODELOCK_LOOKUP 0x000001 /* For namespace, dentry etc, and also
+ * was used to protect permission (mode,
+ * owner, group etc) before 2.4. */
+#define MDS_INODELOCK_UPDATE 0x000002 /* size, links, timestamps */
+#define MDS_INODELOCK_OPEN 0x000004 /* For opened files */
+#define MDS_INODELOCK_LAYOUT 0x000008 /* for layout */
+
+/* The PERM bit is added int 2.4, and it is used to protect permission(mode,
+ * owner, group, acl etc), so to separate the permission from LOOKUP lock.
+ * Because for remote directories(in DNE), these locks will be granted by
+ * different MDTs(different ldlm namespace).
+ *
+ * For local directory, MDT will always grant UPDATE_LOCK|PERM_LOCK together.
+ * For Remote directory, the master MDT, where the remote directory is, will
+ * grant UPDATE_LOCK|PERM_LOCK, and the remote MDT, where the name entry is,
+ * will grant LOOKUP_LOCK. */
+#define MDS_INODELOCK_PERM 0x000010
+#define MDS_INODELOCK_XATTR 0x000020 /* extended attributes */
#define MDS_INODELOCK_MAXSHIFT 5
/* This FULL lock is useful to take on unlink sort of operations */
@@ -2595,7 +2586,7 @@ struct mdt_rec_setxattr {
* Do NOT change the size of various members, otherwise the value
* will be broken in lustre_swab_mdt_rec_reint().
*
- * If you add new members in other mdt_reint_xxx structres and need to use the
+ * If you add new members in other mdt_reint_xxx structures and need to use the
* rr_padding_x fields, then update lustre_swab_mdt_rec_reint() also.
*/
struct mdt_rec_reint {
@@ -3328,9 +3319,10 @@ struct obdo {
#define o_grant_used o_data_version
static inline void lustre_set_wire_obdo(struct obd_connect_data *ocd,
- struct obdo *wobdo, struct obdo *lobdo)
+ struct obdo *wobdo,
+ const struct obdo *lobdo)
{
- memcpy(wobdo, lobdo, sizeof(*lobdo));
+ *wobdo = *lobdo;
wobdo->o_flags &= ~OBD_FL_LOCAL_MASK;
if (ocd == NULL)
return;
@@ -3345,16 +3337,15 @@ static inline void lustre_set_wire_obdo(struct obd_connect_data *ocd,
}
static inline void lustre_get_wire_obdo(struct obd_connect_data *ocd,
- struct obdo *lobdo, struct obdo *wobdo)
+ struct obdo *lobdo,
+ const struct obdo *wobdo)
{
obd_flag local_flags = 0;
if (lobdo->o_valid & OBD_MD_FLFLAGS)
local_flags = lobdo->o_flags & OBD_FL_LOCAL_MASK;
- LASSERT(!(wobdo->o_flags & OBD_FL_LOCAL_MASK));
-
- memcpy(lobdo, wobdo, sizeof(*lobdo));
+ *lobdo = *wobdo;
if (local_flags != 0) {
lobdo->o_valid |= OBD_MD_FLFLAGS;
lobdo->o_flags &= ~OBD_FL_LOCAL_MASK;
diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
index 7893d83e131f..f5f369e603de 100644
--- a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
+++ b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
@@ -265,13 +265,11 @@ struct ost_id {
#define MAX_OBD_NAME 128 /* If this changes, a NEW ioctl must be added */
-/* Hopefully O_LOV_DELAY_CREATE does not conflict with standard O_xxx flags.
- * Previously it was defined as 0100000000 and conflicts with FMODE_NONOTIFY
- * which was added since kernel 2.6.36, so we redefine it as 020000000.
- * To be compatible with old version's statically linked binary, finally we
- * define it as (020000000 | 0100000000).
- * */
-#define O_LOV_DELAY_CREATE 0120000000
+/* Define O_LOV_DELAY_CREATE to be a mask that is not useful for regular
+ * files, but are unlikely to be used in practice and are not harmful if
+ * used incorrectly. O_NOCTTY and FASYNC are only meaningful for character
+ * devices and are safe for use on new files (See LU-812, LU-4209). */
+#define O_LOV_DELAY_CREATE (O_NOCTTY | FASYNC)
#define LL_FILE_IGNORE_LOCK 0x00000001
#define LL_FILE_GROUP_LOCKED 0x00000002
@@ -300,7 +298,7 @@ struct ost_id {
#define LOV_MAX_STRIPE_COUNT_OLD 160
/* This calculation is crafted so that input of 4096 will result in 160
* which in turn is equal to old maximal stripe count.
- * XXX: In fact this is too simpified for now, what it also need is to get
+ * XXX: In fact this is too simplified for now, what it also need is to get
* ea_type argument to clearly know how much space each stripe consumes.
*
* The limit of 12 pages is somewhat arbitrary, but is a reasonably large
@@ -930,7 +928,7 @@ struct hsm_state_set_ioc {
/*
* This structure describes the current in-progress action for a file.
- * it is retuned to user space and send over the wire
+ * it is returned to user space and send over the wire
*/
struct hsm_current_action {
/** The current undergoing action, if there is one */
@@ -1159,12 +1157,6 @@ struct hsm_progress {
__u32 padding;
};
-/**
- * Use by copytool during any hsm request they handled.
- * This structure is initialized by llapi_hsm_copy_start()
- * which is an helper over the ioctl() interface
- * Store Lustre, internal use only, data.
- */
struct hsm_copy {
__u64 hc_data_version;
__u16 hc_flags;
diff --git a/drivers/staging/lustre/lustre/include/lustre_cfg.h b/drivers/staging/lustre/lustre/include/lustre_cfg.h
index e14a5f674e85..3680668a8920 100644
--- a/drivers/staging/lustre/lustre/include/lustre_cfg.h
+++ b/drivers/staging/lustre/lustre/include/lustre_cfg.h
@@ -88,6 +88,8 @@ enum lcfg_command_type {
LCFG_SET_LDLM_TIMEOUT = 0x00ce030, /**< set ldlm_timeout */
LCFG_PRE_CLEANUP = 0x00cf031, /**< call type-specific pre
* cleanup cleanup */
+ LCFG_SET_PARAM = 0x00ce032, /**< use set_param syntax to set
+ *a proc parameters */
};
struct lustre_cfg_bufs {
diff --git a/drivers/staging/lustre/lustre/include/lustre_disk.h b/drivers/staging/lustre/lustre/include/lustre_disk.h
index 1de9a8bed497..ac08164793cb 100644
--- a/drivers/staging/lustre/lustre/include/lustre_disk.h
+++ b/drivers/staging/lustre/lustre/include/lustre_disk.h
@@ -99,6 +99,8 @@
#define LDD_F_IR_CAPABLE 0x2000
/** the MGS refused to register the target. */
#define LDD_F_ERROR 0x4000
+/** process at lctl conf_param */
+#define LDD_F_PARAM2 0x8000
/* opc for target register */
#define LDD_F_OPC_REG 0x10000000
diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm.h b/drivers/staging/lustre/lustre/include/lustre_dlm.h
index ec4bb5e3c13e..3e25f001c07d 100644
--- a/drivers/staging/lustre/lustre/include/lustre_dlm.h
+++ b/drivers/staging/lustre/lustre/include/lustre_dlm.h
@@ -330,7 +330,7 @@ enum {
};
typedef enum {
- /** invalide type */
+ /** invalid type */
LDLM_NS_TYPE_UNKNOWN = 0,
/** mdc namespace */
LDLM_NS_TYPE_MDC,
@@ -1185,7 +1185,7 @@ ldlm_handle2lock_long(const struct lustre_handle *h, __u64 flags)
/**
* Update Lock Value Block Operations (LVBO) on a resource taking into account
- * data from reqest \a r
+ * data from request \a r
*/
static inline int ldlm_res_lvbo_update(struct ldlm_resource *res,
struct ptlrpc_request *r, int increase)
diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h b/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h
index 75716f17f64b..16dcdbfae689 100644
--- a/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h
+++ b/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h
@@ -35,10 +35,10 @@
#ifndef LDLM_ALL_FLAGS_MASK
/** l_flags bits marked as "all_flags" bits */
-#define LDLM_FL_ALL_FLAGS_MASK 0x00FFFFFFC08F132FULL
+#define LDLM_FL_ALL_FLAGS_MASK 0x00FFFFFFC08F932FULL
/** l_flags bits marked as "ast" bits */
-#define LDLM_FL_AST_MASK 0x0000000080000000ULL
+#define LDLM_FL_AST_MASK 0x0000000080008000ULL
/** l_flags bits marked as "blocked" bits */
#define LDLM_FL_BLOCKED_MASK 0x000000000000000EULL
@@ -56,7 +56,7 @@
#define LDLM_FL_LOCAL_ONLY_MASK 0x00FFFFFF00000000ULL
/** l_flags bits marked as "on_wire" bits */
-#define LDLM_FL_ON_WIRE_MASK 0x00000000C08F132FULL
+#define LDLM_FL_ON_WIRE_MASK 0x00000000C08F932FULL
/** extent, mode, or resource changed */
#define LDLM_FL_LOCK_CHANGED 0x0000000000000001ULL // bit 0
@@ -114,6 +114,12 @@
#define ldlm_set_has_intent(_l) LDLM_SET_FLAG(( _l), 1ULL << 12)
#define ldlm_clear_has_intent(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 12)
+/** flock deadlock detected */
+#define LDLM_FL_FLOCK_DEADLOCK 0x0000000000008000ULL /* bit 15 */
+#define ldlm_is_flock_deadlock(_l) LDLM_TEST_FLAG((_l), 1ULL << 15)
+#define ldlm_set_flock_deadlock(_l) LDLM_SET_FLAG((_l), 1ULL << 15)
+#define ldlm_clear_flock_deadlock(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 15)
+
/** discard (no writeback) on cancel */
#define LDLM_FL_DISCARD_DATA 0x0000000000010000ULL // bit 16
#define ldlm_is_discard_data(_l) LDLM_TEST_FLAG(( _l), 1ULL << 16)
@@ -141,7 +147,7 @@
#define ldlm_clear_test_lock(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 19)
/**
- * Immediatelly cancel such locks when they block some other locks. Send
+ * Immediately cancel such locks when they block some other locks. Send
* cancel notification to original lock holder, but expect no reply. This
* is for clients (like liblustre) that cannot be expected to reliably
* response to blocking AST. */
@@ -242,7 +248,7 @@
/**
* A lock contributes to the known minimum size (KMS) calculation until it
- * has finished the part of its cancelation that performs write back on its
+ * has finished the part of its cancellation that performs write back on its
* dirty pages. It can remain on the granted list during this whole time.
* Threads racing to update the KMS after performing their writeback need
* to know to exclude each other's locks from the calculation as they walk
@@ -390,6 +396,7 @@ static int hf_lustre_ldlm_fl_ast_sent = -1;
static int hf_lustre_ldlm_fl_replay = -1;
static int hf_lustre_ldlm_fl_intent_only = -1;
static int hf_lustre_ldlm_fl_has_intent = -1;
+static int hf_lustre_ldlm_fl_flock_deadlock = -1;
static int hf_lustre_ldlm_fl_discard_data = -1;
static int hf_lustre_ldlm_fl_no_timeout = -1;
static int hf_lustre_ldlm_fl_block_nowait = -1;
@@ -431,6 +438,7 @@ const value_string lustre_ldlm_flags_vals[] = {
{LDLM_FL_REPLAY, "LDLM_FL_REPLAY"},
{LDLM_FL_INTENT_ONLY, "LDLM_FL_INTENT_ONLY"},
{LDLM_FL_HAS_INTENT, "LDLM_FL_HAS_INTENT"},
+ {LDLM_FL_FLOCK_DEADLOCK, "LDLM_FL_FLOCK_DEADLOCK"},
{LDLM_FL_DISCARD_DATA, "LDLM_FL_DISCARD_DATA"},
{LDLM_FL_NO_TIMEOUT, "LDLM_FL_NO_TIMEOUT"},
{LDLM_FL_BLOCK_NOWAIT, "LDLM_FL_BLOCK_NOWAIT"},
diff --git a/drivers/staging/lustre/lustre/include/lustre_export.h b/drivers/staging/lustre/lustre/include/lustre_export.h
index 2feb38b51af2..103f7a8bd83f 100644
--- a/drivers/staging/lustre/lustre/include/lustre_export.h
+++ b/drivers/staging/lustre/lustre/include/lustre_export.h
@@ -192,9 +192,9 @@ struct obd_export {
struct obd_import *exp_imp_reverse;
struct nid_stat *exp_nid_stats;
struct lprocfs_stats *exp_md_stats;
- /** Active connetion */
+ /** Active connection */
struct ptlrpc_connection *exp_connection;
- /** Connection count value from last succesful reconnect rpc */
+ /** Connection count value from last successful reconnect rpc */
__u32 exp_conn_cnt;
/** Hash list of all ldlm locks granted on this export */
struct cfs_hash *exp_lock_hash;
@@ -380,6 +380,23 @@ static inline bool imp_connect_lvb_type(struct obd_import *imp)
return false;
}
+static inline __u64 exp_connect_ibits(struct obd_export *exp)
+{
+ struct obd_connect_data *ocd;
+
+ ocd = &exp->exp_connect_data;
+ return ocd->ocd_ibits_known;
+}
+
+static inline bool imp_connect_disp_stripe(struct obd_import *imp)
+{
+ struct obd_connect_data *ocd;
+
+ LASSERT(imp != NULL);
+ ocd = &imp->imp_connect_data;
+ return ocd->ocd_connect_flags & OBD_CONNECT_DISP_STRIPE;
+}
+
extern struct obd_export *class_conn2export(struct lustre_handle *conn);
extern struct obd_device *class_conn2obd(struct lustre_handle *conn);
diff --git a/drivers/staging/lustre/lustre/include/lustre_fid.h b/drivers/staging/lustre/lustre/include/lustre_fid.h
index 84a897eed1df..5e7b3165a851 100644
--- a/drivers/staging/lustre/lustre/include/lustre_fid.h
+++ b/drivers/staging/lustre/lustre/include/lustre_fid.h
@@ -339,7 +339,7 @@ struct lu_client_seq {
struct mutex lcs_mutex;
/*
- * Range of allowed for allocation sequeces. When using lu_client_seq on
+ * Range of allowed for allocation sequences. When using lu_client_seq on
* clients, this contains meta-sequence range. And for servers this
* contains super-sequence range.
*/
@@ -398,7 +398,7 @@ struct lu_server_seq {
/* LUSTRE_SEQ_SERVER or LUSTRE_SEQ_CONTROLLER */
enum lu_mgr_type lss_type;
- /* Client interafce to request controller */
+ /* Client interface to request controller */
struct lu_client_seq *lss_cli;
/* Mutex for protecting allocation */
@@ -568,14 +568,14 @@ fid_build_pdo_res_name(const struct lu_fid *fid, unsigned int hash,
* finally, when we replace ost_id with FID in data stack.
*
* Currently, resid from the old client, whose res[0] = object_id,
- * res[1] = object_seq, is just oposite with Metatdata
+ * res[1] = object_seq, is just opposite with Metatdata
* resid, where, res[0] = fid->f_seq, res[1] = fid->f_oid.
- * To unifiy the resid identification, we will reverse the data
+ * To unify the resid identification, we will reverse the data
* resid to keep it same with Metadata resid, i.e.
*
* For resid from the old client,
* res[0] = objid, res[1] = 0, still keep the original order,
- * for compatiblity.
+ * for compatibility.
*
* For new resid
* res will be built from normal FID directly, i.e. res[0] = f_seq,
@@ -685,7 +685,7 @@ static inline __u32 fid_hash(const struct lu_fid *f, int bits)
{
/* all objects with same id and different versions will belong to same
* collisions list. */
- return cfs_hash_long(fid_flatten(f), bits);
+ return hash_long(fid_flatten(f), bits);
}
/**
diff --git a/drivers/staging/lustre/lustre/include/lustre_import.h b/drivers/staging/lustre/lustre/include/lustre_import.h
index 67259eb43cde..01ed786b40b9 100644
--- a/drivers/staging/lustre/lustre/include/lustre_import.h
+++ b/drivers/staging/lustre/lustre/include/lustre_import.h
@@ -152,7 +152,7 @@ struct import_state_hist {
};
/**
- * Defintion of PortalRPC import structure.
+ * Definition of PortalRPC import structure.
* Imports are representing client-side view to remote target.
*/
struct obd_import {
@@ -180,6 +180,17 @@ struct obd_import {
struct list_head imp_delayed_list;
/** @} */
+ /**
+ * List of requests that are retained for committed open replay. Once
+ * open is committed, open replay request will be moved from the
+ * imp_replay_list into the imp_committed_list.
+ * The imp_replay_cursor is for accelerating searching during replay.
+ * @{
+ */
+ struct list_head imp_committed_list;
+ struct list_head *imp_replay_cursor;
+ /** @} */
+
/** obd device for this import */
struct obd_device *imp_obd;
@@ -219,7 +230,7 @@ struct obd_import {
* after a check to save on unnecessary replay list iterations
*/
int imp_last_generation_checked;
- /** Last tranno we replayed */
+ /** Last transno we replayed */
__u64 imp_last_replay_transno;
/** Last transno committed on remote side */
__u64 imp_peer_committed_transno;
@@ -237,7 +248,7 @@ struct obd_import {
struct lustre_handle imp_remote_handle;
/** When to perform next ping. time in jiffies. */
cfs_time_t imp_next_ping;
- /** When we last succesfully connected. time in 64bit jiffies */
+ /** When we last successfully connected. time in 64bit jiffies */
__u64 imp_last_success_conn;
/** List of all possible connection for import. */
@@ -268,7 +279,7 @@ struct obd_import {
imp_no_lock_replay:1,
/* recovery by versions was failed */
imp_vbr_failed:1,
- /* force an immidiate ping */
+ /* force an immediate ping */
imp_force_verify:1,
/* force a scheduled ping */
imp_force_next_verify:1,
@@ -281,7 +292,7 @@ struct obd_import {
/* need IR MNE swab */
imp_need_mne_swab:1,
/* import must be reconnected instead of
- * chouse new connection */
+ * chose new connection */
imp_force_reconnect:1,
/* import has tried to connect with server */
imp_connect_tried:1;
diff --git a/drivers/staging/lustre/lustre/include/lustre_lib.h b/drivers/staging/lustre/lustre/include/lustre_lib.h
index 609a090484a6..0368ca6ffcc1 100644
--- a/drivers/staging/lustre/lustre/include/lustre_lib.h
+++ b/drivers/staging/lustre/lustre/include/lustre_lib.h
@@ -536,7 +536,7 @@ do { \
if (condition) \
break; \
\
- init_waitqueue_entry_current(&__wait); \
+ init_waitqueue_entry(&__wait, current); \
l_add_wait(&wq, &__wait); \
\
/* Block all signals (just the non-fatal ones if no timeout). */ \
@@ -558,15 +558,13 @@ do { \
break; \
\
if (__timeout == 0) { \
- waitq_wait(&__wait, __wstate); \
+ schedule(); \
} else { \
cfs_duration_t interval = info->lwi_interval? \
min_t(cfs_duration_t, \
info->lwi_interval,__timeout):\
__timeout; \
- cfs_duration_t remaining = waitq_timedwait(&__wait,\
- __wstate, \
- interval); \
+ cfs_duration_t remaining = schedule_timeout(interval);\
__timeout = cfs_time_sub(__timeout, \
cfs_time_sub(interval, remaining));\
if (__timeout == 0) { \
diff --git a/drivers/staging/lustre/lustre/include/lustre_linkea.h b/drivers/staging/lustre/lustre/include/lustre_linkea.h
index 5790be913bf6..500ace30cfbf 100644
--- a/drivers/staging/lustre/lustre/include/lustre_linkea.h
+++ b/drivers/staging/lustre/lustre/include/lustre_linkea.h
@@ -33,7 +33,7 @@ struct linkea_data {
*/
struct lu_buf *ld_buf;
/**
- * The matched header, entry and its lenght in the EA
+ * The matched header, entry and its length in the EA
*/
struct link_ea_header *ld_leh;
struct link_ea_entry *ld_lee;
diff --git a/drivers/staging/lustre/lustre/include/lustre_mdc.h b/drivers/staging/lustre/lustre/include/lustre_mdc.h
index c1e02702b931..468f36344a34 100644
--- a/drivers/staging/lustre/lustre/include/lustre_mdc.h
+++ b/drivers/staging/lustre/lustre/include/lustre_mdc.h
@@ -166,6 +166,17 @@ void it_clear_disposition(struct lookup_intent *it, int flag);
void it_set_disposition(struct lookup_intent *it, int flag);
int it_open_error(int phase, struct lookup_intent *it);
+static inline bool cl_is_lov_delay_create(unsigned int flags)
+{
+ return (flags & O_LOV_DELAY_CREATE) == O_LOV_DELAY_CREATE;
+}
+
+static inline void cl_lov_delay_create_clear(unsigned int *flags)
+{
+ if ((*flags & O_LOV_DELAY_CREATE) == O_LOV_DELAY_CREATE)
+ *flags &= ~O_LOV_DELAY_CREATE;
+}
+
/** @} mdc */
#endif
diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h
index d8d088035428..745adbb74cfc 100644
--- a/drivers/staging/lustre/lustre/include/lustre_net.h
+++ b/drivers/staging/lustre/lustre/include/lustre_net.h
@@ -445,7 +445,7 @@ struct ptlrpc_reply_state {
lnet_handle_md_t rs_md_h;
atomic_t rs_refcount;
- /** Context for the sevice thread */
+ /** Context for the service thread */
struct ptlrpc_svc_ctx *rs_svc_ctx;
/** Reply buffer (actually sent to the client), encoded if needed */
struct lustre_msg *rs_repbuf; /* wrapper */
@@ -454,9 +454,9 @@ struct ptlrpc_reply_state {
/** Size of the reply message */
int rs_repdata_len; /* wrapper msg length */
/**
- * Actual reply message. Its content is encrupted (if needed) to
+ * Actual reply message. Its content is encrypted (if needed) to
* produce reply buffer for actual sending. In simple case
- * of no network encryption we jus set \a rs_repbuf to \a rs_msg
+ * of no network encryption we just set \a rs_repbuf to \a rs_msg
*/
struct lustre_msg *rs_msg; /* reply message */
@@ -497,7 +497,7 @@ struct ptlrpc_request_pool {
spinlock_t prp_lock;
/** list of ptlrpc_request structs */
struct list_head prp_req_list;
- /** Maximum message size that would fit into a rquest from this pool */
+ /** Maximum message size that would fit into a request from this pool */
int prp_rq_size;
/** Function to allocate more requests for this pool */
void (*prp_populate)(struct ptlrpc_request_pool *, int);
@@ -904,7 +904,7 @@ struct ptlrpc_nrs_pol_conf {
*/
struct module *nc_owner;
/**
- * Policy registration flags; a bitmast of \e nrs_policy_flags
+ * Policy registration flags; a bitmask of \e nrs_policy_flags
*/
unsigned nc_flags;
};
@@ -1351,7 +1351,7 @@ struct nrs_orr_data {
*/
enum nrs_orr_supp od_supp;
/**
- * Round Robin quantum; the maxium number of RPCs that each request
+ * Round Robin quantum; the maximum number of RPCs that each request
* batch for each object or OST can have in a scheduling round.
*/
__u16 od_quantum;
@@ -1486,7 +1486,7 @@ struct ptlrpc_nrs_request {
*/
struct nrs_fifo_req fifo;
/**
- * CRR-N request defintion
+ * CRR-N request definition
*/
struct nrs_crrn_req crr;
/** ORR and TRR share the same request definition */
@@ -1550,7 +1550,7 @@ struct ptlrpc_request {
* requests in time
*/
struct list_head rq_timed_list;
- /** server-side history, used for debuging purposes. */
+ /** server-side history, used for debugging purposes. */
struct list_head rq_history_list;
/** server-side per-export list */
struct list_head rq_exp_list;
@@ -1611,7 +1611,7 @@ struct ptlrpc_request {
enum rq_phase rq_phase; /* one of RQ_PHASE_* */
enum rq_phase rq_next_phase; /* one of RQ_PHASE_* to be used next */
atomic_t rq_refcount;/* client-side refcount for SENT race,
- server-side refcounf for multiple replies */
+ server-side refcount for multiple replies */
/** Portal to which this request would be sent */
short rq_request_portal; /* XXX FIXME bug 249 */
@@ -1637,7 +1637,7 @@ struct ptlrpc_request {
/** xid */
__u64 rq_xid;
/**
- * List item to for replay list. Not yet commited requests get linked
+ * List item to for replay list. Not yet committed requests get linked
* there.
* Also see \a rq_replay comment above.
*/
@@ -1952,7 +1952,7 @@ void _debug_req(struct ptlrpc_request *req,
__attribute__ ((format (printf, 3, 4)));
/**
- * Helper that decides if we need to print request accordig to current debug
+ * Helper that decides if we need to print request according to current debug
* level settings
*/
#define debug_req(msgdata, mask, cdls, req, fmt, a...) \
@@ -1966,7 +1966,7 @@ do { \
} while(0)
/**
- * This is the debug print function you need to use to print request sturucture
+ * This is the debug print function you need to use to print request structure
* content into lustre debug log.
* for most callers (level is a constant) this is resolved at compile time */
#define DEBUG_REQ(level, req, fmt, args...) \
@@ -2621,6 +2621,8 @@ int ptlrpc_register_rqbd(struct ptlrpc_request_buffer_desc *rqbd);
* request queues, request management, etc.
* @{
*/
+void ptlrpc_request_committed(struct ptlrpc_request *req, int force);
+
void ptlrpc_init_client(int req_portal, int rep_portal, char *name,
struct ptlrpc_client *);
void ptlrpc_cleanup_client(struct obd_import *imp);
diff --git a/drivers/staging/lustre/lustre/include/lustre_quota.h b/drivers/staging/lustre/lustre/include/lustre_quota.h
index 71b5d97e0343..07cb7c310bcc 100644
--- a/drivers/staging/lustre/lustre/include/lustre_quota.h
+++ b/drivers/staging/lustre/lustre/include/lustre_quota.h
@@ -140,7 +140,7 @@ struct qsd_instance;
* (i.e. when ->ldo_recovery_complete is called). This is used
* to notify the qsd layer that quota should now be enforced
* again via the qsd_op_begin/end functions. The last step of the
- * reintegration prodecure (namely usage reconciliation) will be
+ * reintegration procedure (namely usage reconciliation) will be
* completed during start.
*
* - qsd_fini(): is used to release a qsd_instance structure allocated with
diff --git a/drivers/staging/lustre/lustre/include/lustre_sec.h b/drivers/staging/lustre/lustre/include/lustre_sec.h
index 885247d28b3a..bf3ee3915c28 100644
--- a/drivers/staging/lustre/lustre/include/lustre_sec.h
+++ b/drivers/staging/lustre/lustre/include/lustre_sec.h
@@ -572,7 +572,7 @@ struct ptlrpc_sec_cops {
/**
* Called then the reference of \a ctx dropped to 0. The policy module
* is supposed to destroy this context or whatever else according to
- * its cache maintainance mechamism.
+ * its cache maintenance mechanism.
*
* \param sync if zero, we shouldn't wait for the context being
* destroyed completely.
@@ -1002,7 +1002,7 @@ struct ptlrpc_sec *sptlrpc_sec_get(struct ptlrpc_sec *sec);
void sptlrpc_sec_put(struct ptlrpc_sec *sec);
/*
- * internal apis which only used by policy impelentation
+ * internal apis which only used by policy implementation
*/
int sptlrpc_get_next_secid(void);
void sptlrpc_sec_destroy(struct ptlrpc_sec *sec);
diff --git a/drivers/staging/lustre/lustre/include/md_object.h b/drivers/staging/lustre/lustre/include/md_object.h
index 7b45b47b48f9..ef46b2c461a6 100644
--- a/drivers/staging/lustre/lustre/include/md_object.h
+++ b/drivers/staging/lustre/lustre/include/md_object.h
@@ -35,7 +35,7 @@
*
* lustre/include/md_object.h
*
- * Extention of lu_object.h for metadata objects
+ * Extension of lu_object.h for metadata objects
*/
#ifndef _LUSTRE_MD_OBJECT_H
diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h
index c3470ce62cff..72cf3fe4b0c9 100644
--- a/drivers/staging/lustre/lustre/include/obd.h
+++ b/drivers/staging/lustre/lustre/include/obd.h
@@ -158,7 +158,7 @@ struct obd_info {
/* statfs data specific for every OSC, if needed at all. */
struct obd_statfs *oi_osfs;
/* An update callback which is called to update some data on upper
- * level. E.g. it is used for update lsm->lsm_oinfo at every recieved
+ * level. E.g. it is used for update lsm->lsm_oinfo at every received
* request in osc level for enqueue requests. It is also possible to
* update some caller data from LOV layer if needed. */
obd_enqueue_update_f oi_cb_up;
@@ -1042,8 +1042,8 @@ static inline int it_to_lock_mode(struct lookup_intent *it)
}
struct md_op_data {
- struct lu_fid op_fid1; /* operation fid1 (usualy parent) */
- struct lu_fid op_fid2; /* operation fid2 (usualy child) */
+ struct lu_fid op_fid1; /* operation fid1 (usually parent) */
+ struct lu_fid op_fid2; /* operation fid2 (usually child) */
struct lu_fid op_fid3; /* 2 extra fids to find conflicting */
struct lu_fid op_fid4; /* to the operation locks. */
mdsno_t op_mds; /* what mds server open will go to */
@@ -1323,7 +1323,8 @@ struct md_open_data {
struct obd_client_handle *mod_och;
struct ptlrpc_request *mod_open_req;
struct ptlrpc_request *mod_close_req;
- atomic_t mod_refcount;
+ atomic_t mod_refcount;
+ bool mod_is_create;
};
struct lookup_intent;
@@ -1392,7 +1393,7 @@ struct md_ops {
int (*m_set_open_replay_data)(struct obd_export *,
struct obd_client_handle *,
- struct ptlrpc_request *);
+ struct lookup_intent *);
int (*m_clear_open_replay_data)(struct obd_export *,
struct obd_client_handle *);
int (*m_set_lock_data)(struct obd_export *, __u64 *, void *, __u64 *);
diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h
index 983718fe1e55..9d1f266e55e4 100644
--- a/drivers/staging/lustre/lustre/include/obd_class.h
+++ b/drivers/staging/lustre/lustre/include/obd_class.h
@@ -175,9 +175,13 @@ enum {
CONFIG_T_CONFIG = 0,
CONFIG_T_SPTLRPC = 1,
CONFIG_T_RECOVER = 2,
- CONFIG_T_MAX = 3
+ CONFIG_T_PARAMS = 3,
+ CONFIG_T_MAX = 4
};
+#define PARAMS_FILENAME "params"
+#define LCTL_UPCALL "lctl"
+
/* list of active configuration logs */
struct config_llog_data {
struct ldlm_res_id cld_resid;
@@ -185,7 +189,8 @@ struct config_llog_data {
struct list_head cld_list_chain;
atomic_t cld_refcount;
struct config_llog_data *cld_sptlrpc;/* depended sptlrpc log */
- struct config_llog_data *cld_recover; /* imperative recover log */
+ struct config_llog_data *cld_params; /* common parameters log */
+ struct config_llog_data *cld_recover;/* imperative recover log */
struct obd_export *cld_mgcexp;
struct mutex cld_lock;
int cld_type;
@@ -1626,7 +1631,7 @@ static inline int obd_health_check(const struct lu_env *env,
{
/* returns: 0 on healthy
* >0 on unhealthy + reason code/flag
- * however the only suppored reason == 1 right now
+ * however the only supported reason == 1 right now
* We'll need to define some better reasons
* or flags in the future.
* <0 on error
@@ -1996,11 +2001,11 @@ static inline int md_getxattr(struct obd_export *exp,
static inline int md_set_open_replay_data(struct obd_export *exp,
struct obd_client_handle *och,
- struct ptlrpc_request *open_req)
+ struct lookup_intent *it)
{
EXP_CHECK_MD_OP(exp, set_open_replay_data);
EXP_MD_COUNTER_INCREMENT(exp, set_open_replay_data);
- return MDP(exp->exp_obd, set_open_replay_data)(exp, och, open_req);
+ return MDP(exp->exp_obd, set_open_replay_data)(exp, och, it);
}
static inline int md_clear_open_replay_data(struct obd_export *exp,
diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h
index 977bc231df9d..5ec336968fc8 100644
--- a/drivers/staging/lustre/lustre/include/obd_support.h
+++ b/drivers/staging/lustre/lustre/include/obd_support.h
@@ -681,7 +681,7 @@ do { \
*
* Be very careful when changing this value, especially when decreasing it,
* since vmalloc in Linux doesn't perform well on multi-cores system, calling
- * vmalloc in critical path would hurt peformance badly. See LU-66.
+ * vmalloc in critical path would hurt performance badly. See LU-66.
*/
#define OBD_ALLOC_BIG (4 * PAGE_CACHE_SIZE)
diff --git a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
index 94b164127e0c..6907a16dbbd1 100644
--- a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
+++ b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
@@ -1196,14 +1196,14 @@ static void cl_object_put_last(struct lu_env *env, struct cl_object *obj)
bkt = lu_site_bkt_from_fid(site, &header->loh_fid);
- init_waitqueue_entry_current(&waiter);
+ init_waitqueue_entry(&waiter, current);
add_wait_queue(&bkt->lsb_marche_funebre, &waiter);
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (atomic_read(&header->loh_ref) == 1)
break;
- waitq_wait(&waiter, TASK_UNINTERRUPTIBLE);
+ schedule();
}
set_current_state(TASK_RUNNING);
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
index c9aae132f98a..986bf384bff7 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
@@ -205,6 +205,26 @@ ldlm_flock_deadlock(struct ldlm_lock *req, struct ldlm_lock *bl_lock)
return 0;
}
+static void ldlm_flock_cancel_on_deadlock(struct ldlm_lock *lock,
+ struct list_head *work_list)
+{
+ CDEBUG(D_INFO, "reprocess deadlock req=%p\n", lock);
+
+ if ((exp_connect_flags(lock->l_export) &
+ OBD_CONNECT_FLOCK_DEAD) == 0) {
+ CERROR(
+ "deadlock found, but client doesn't support flock canceliation\n");
+ } else {
+ LASSERT(lock->l_completion_ast);
+ LASSERT((lock->l_flags & LDLM_FL_AST_SENT) == 0);
+ lock->l_flags |= LDLM_FL_AST_SENT | LDLM_FL_CANCEL_ON_BLOCK |
+ LDLM_FL_FLOCK_DEADLOCK;
+ ldlm_flock_blocking_unlink(lock);
+ ldlm_resource_unlink_lock(lock);
+ ldlm_add_ast_work_item(lock, NULL, work_list);
+ }
+}
+
/**
* Process a granting attempt for flock lock.
* Must be called under ns lock held.
@@ -272,6 +292,7 @@ reprocess:
}
}
} else {
+ int reprocess_failed = 0;
lockmode_verify(mode);
/* This loop determines if there are existing locks
@@ -293,8 +314,15 @@ reprocess:
if (!ldlm_flocks_overlap(lock, req))
continue;
- if (!first_enq)
- return LDLM_ITER_CONTINUE;
+ if (!first_enq) {
+ reprocess_failed = 1;
+ if (ldlm_flock_deadlock(req, lock)) {
+ ldlm_flock_cancel_on_deadlock(req,
+ work_list);
+ return LDLM_ITER_CONTINUE;
+ }
+ continue;
+ }
if (*flags & LDLM_FL_BLOCK_NOWAIT) {
ldlm_flock_destroy(req, mode, *flags);
@@ -330,6 +358,8 @@ reprocess:
*flags |= LDLM_FL_BLOCK_GRANTED;
return LDLM_ITER_STOP;
}
+ if (reprocess_failed)
+ return LDLM_ITER_CONTINUE;
}
if (*flags & LDLM_FL_TEST_LOCK) {
@@ -646,7 +676,10 @@ granted:
/* ldlm_lock_enqueue() has already placed lock on the granted list. */
list_del_init(&lock->l_res_link);
- if (flags & LDLM_FL_TEST_LOCK) {
+ if (lock->l_flags & LDLM_FL_FLOCK_DEADLOCK) {
+ LDLM_DEBUG(lock, "client-side enqueue deadlock received");
+ rc = -EDEADLK;
+ } else if (flags & LDLM_FL_TEST_LOCK) {
/* fcntl(F_GETLK) request */
/* The old mode was saved in getlk->fl_type so that if the mode
* in the lock changes we can decref the appropriate refcount.*/
@@ -672,7 +705,7 @@ granted:
ldlm_process_flock_lock(lock, &noreproc, 1, &err, NULL);
}
unlock_res_and_lock(lock);
- return 0;
+ return rc;
}
EXPORT_SYMBOL(ldlm_flock_completion_ast);
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
index 692623beee12..0548aca45e8e 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
@@ -145,8 +145,6 @@ char *ldlm_it2str(int it)
return "getxattr";
case IT_LAYOUT:
return "layout";
- case IT_SETXATTR:
- return "setxattr";
default:
CERROR("Unknown intent %d\n", it);
return "UNKNOWN";
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
index 3ed020eb89c0..7e63cf355cd9 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
@@ -192,8 +192,8 @@ static void ldlm_handle_cp_callback(struct ptlrpc_request *req,
if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_CANCEL_BL_CB_RACE)) {
int to = cfs_time_seconds(1);
while (to > 0) {
- schedule_timeout_and_set_state(
- TASK_INTERRUPTIBLE, to);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(to);
if (lock->l_granted_mode == lock->l_req_mode ||
lock->l_flags & LDLM_FL_DESTROYED)
break;
@@ -228,6 +228,7 @@ static void ldlm_handle_cp_callback(struct ptlrpc_request *req,
lock_res_and_lock(lock);
LASSERT(lock->l_lvb_data == NULL);
+ lock->l_lvb_type = LVB_T_LAYOUT;
lock->l_lvb_data = lvb_data;
lock->l_lvb_len = lvb_len;
unlock_res_and_lock(lock);
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
index c0e54aead2ce..fcc7a99ce395 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
@@ -299,7 +299,7 @@ EXPORT_SYMBOL(ldlm_completion_ast);
* A helper to build a blocking AST function
*
* Perform a common operation for blocking ASTs:
- * defferred lock cancellation.
+ * deferred lock cancellation.
*
* \param lock the lock blocking or canceling AST was called on
* \retval 0
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
index 5f89864cda14..2824d4a9a85b 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
@@ -421,9 +421,9 @@ static unsigned ldlm_res_hop_fid_hash(struct cfs_hash *hs,
} else {
val = fid_oid(&fid);
}
- hash = cfs_hash_long(hash, hs->hs_bkt_bits);
+ hash = hash_long(hash, hs->hs_bkt_bits);
/* give me another random factor */
- hash -= cfs_hash_long((unsigned long)hs, val % 11 + 3);
+ hash -= hash_long((unsigned long)hs, val % 11 + 3);
hash <<= hs->hs_cur_bits - hs->hs_bkt_bits;
hash |= ldlm_res_hop_hash(hs, key, CFS_HASH_NBKT(hs) - 1);
diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c
index f30c84f195aa..1e4c5ad26157 100644
--- a/drivers/staging/lustre/lustre/libcfs/debug.c
+++ b/drivers/staging/lustre/lustre/libcfs/debug.c
@@ -368,7 +368,7 @@ void libcfs_debug_dumplog(void)
/* we're being careful to ensure that the kernel thread is
* able to set our state to running as it exits before we
* get to schedule() */
- init_waitqueue_entry_current(&wait);
+ init_waitqueue_entry(&wait, current);
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&debug_ctlwq, &wait);
@@ -379,7 +379,7 @@ void libcfs_debug_dumplog(void)
printk(KERN_ERR "LustreError: cannot start log dump thread:"
" %ld\n", PTR_ERR(dumper));
else
- waitq_wait(&wait, TASK_INTERRUPTIBLE);
+ schedule();
/* be sure to teardown if cfs_create_thread() failed */
remove_wait_queue(&debug_ctlwq, &wait);
diff --git a/drivers/staging/lustre/lustre/libcfs/fail.c b/drivers/staging/lustre/lustre/libcfs/fail.c
index c54448d69008..ba43ff7f7900 100644
--- a/drivers/staging/lustre/lustre/libcfs/fail.c
+++ b/drivers/staging/lustre/lustre/libcfs/fail.c
@@ -127,8 +127,8 @@ int __cfs_fail_timeout_set(__u32 id, __u32 value, int ms, int set)
if (ret) {
CERROR("cfs_fail_timeout id %x sleeping for %dms\n",
id, ms);
- schedule_timeout_and_set_state(TASK_UNINTERRUPTIBLE,
- cfs_time_seconds(ms) / 1000);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(ms) / 1000);
set_current_state(TASK_RUNNING);
CERROR("cfs_fail_timeout id %x awake\n", id);
}
diff --git a/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c b/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
index 7b2c31599327..b6ddc998f750 100644
--- a/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
+++ b/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
@@ -44,106 +44,6 @@
#include <linux/libcfs/libcfs.h>
-#ifdef LUSTRE_UTILS
-/* This is the userspace side. */
-
-/** Start the userspace side of a KUC pipe.
- * @param link Private descriptor for pipe/socket.
- * @param groups KUC broadcast group to listen to
- * (can be null for unicast to this pid)
- */
-int libcfs_ukuc_start(lustre_kernelcomm *link, int group)
-{
- int pfd[2];
-
- if (pipe(pfd) < 0)
- return -errno;
-
- memset(link, 0, sizeof(*link));
- link->lk_rfd = pfd[0];
- link->lk_wfd = pfd[1];
- link->lk_group = group;
- link->lk_uid = getpid();
- return 0;
-}
-
-int libcfs_ukuc_stop(lustre_kernelcomm *link)
-{
- if (link->lk_wfd > 0)
- close(link->lk_wfd);
- return close(link->lk_rfd);
-}
-
-#define lhsz sizeof(*kuch)
-
-/** Read a message from the link.
- * Allocates memory, returns handle
- *
- * @param link Private descriptor for pipe/socket.
- * @param buf Buffer to read into, must include size for kuc_hdr
- * @param maxsize Maximum message size allowed
- * @param transport Only listen to messages on this transport
- * (and the generic transport)
- */
-int libcfs_ukuc_msg_get(lustre_kernelcomm *link, char *buf, int maxsize,
- int transport)
-{
- struct kuc_hdr *kuch;
- int rc = 0;
-
- memset(buf, 0, maxsize);
-
- CDEBUG(D_KUC, "Waiting for message from kernel on fd %d\n",
- link->lk_rfd);
-
- while (1) {
- /* Read header first to get message size */
- rc = read(link->lk_rfd, buf, lhsz);
- if (rc <= 0) {
- rc = -errno;
- break;
- }
- kuch = (struct kuc_hdr *)buf;
-
- CDEBUG(D_KUC, "Received message mg=%x t=%d m=%d l=%d\n",
- kuch->kuc_magic, kuch->kuc_transport, kuch->kuc_msgtype,
- kuch->kuc_msglen);
-
- if (kuch->kuc_magic != KUC_MAGIC) {
- CERROR("bad message magic %x != %x\n",
- kuch->kuc_magic, KUC_MAGIC);
- rc = -EPROTO;
- break;
- }
-
- if (kuch->kuc_msglen > maxsize) {
- rc = -EMSGSIZE;
- break;
- }
-
- /* Read payload */
- rc = read(link->lk_rfd, buf + lhsz, kuch->kuc_msglen - lhsz);
- if (rc < 0) {
- rc = -errno;
- break;
- }
- if (rc < (kuch->kuc_msglen - lhsz)) {
- CERROR("short read: got %d of %d bytes\n",
- rc, kuch->kuc_msglen);
- rc = -EPROTO;
- break;
- }
-
- if (kuch->kuc_transport == transport ||
- kuch->kuc_transport == KUC_TRANSPORT_GENERIC) {
- return 0;
- }
- /* Drop messages for other transports */
- }
- return rc;
-}
-
-#else /* LUSTRE_UTILS */
/* This is the kernel side (liblustre as well). */
/**
@@ -338,5 +238,3 @@ int libcfs_kkuc_group_foreach(int group, libcfs_kkuc_cb_t cb_func,
return rc;
}
EXPORT_SYMBOL(libcfs_kkuc_group_foreach);
-
-#endif /* LUSTRE_UTILS */
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
index 922debd0a412..ed0a6b531058 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
@@ -42,26 +42,6 @@
#include <linux/libcfs/libcfs.h>
-/* non-0 = don't match */
-int cfs_strncasecmp(const char *s1, const char *s2, size_t n)
-{
- if (s1 == NULL || s2 == NULL)
- return 1;
-
- if (n == 0)
- return 0;
-
- while (n-- != 0 && tolower(*s1) == tolower(*s2)) {
- if (n == 0 || *s1 == '\0' || *s2 == '\0')
- break;
- s1++;
- s2++;
- }
-
- return tolower(*(unsigned char *)s1) - tolower(*(unsigned char *)s2);
-}
-EXPORT_SYMBOL(cfs_strncasecmp);
-
/* Convert a text string to a bitmask */
int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
int *oldmask, int minmask, int allmask)
@@ -101,7 +81,7 @@ int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
debugstr = bit2str(i);
if (debugstr != NULL &&
strlen(debugstr) == len &&
- cfs_strncasecmp(str, debugstr, len) == 0) {
+ strncasecmp(str, debugstr, len) == 0) {
if (op == '-')
newmask &= ~(1 << i);
else
@@ -111,7 +91,7 @@ int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
}
}
if (!found && len == 3 &&
- (cfs_strncasecmp(str, "ALL", len) == 0)) {
+ (strncasecmp(str, "ALL", len) == 0)) {
if (op == '-')
newmask = minmask;
else
@@ -129,7 +109,6 @@ int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
*oldmask = newmask;
return 0;
}
-EXPORT_SYMBOL(cfs_str2mask);
/* get the first string out of @str */
char *cfs_firststr(char *str, size_t size)
@@ -164,12 +143,12 @@ cfs_trimwhite(char *str)
{
char *end;
- while (cfs_iswhite(*str))
+ while (isspace(*str))
str++;
end = str + strlen(str);
while (end > str) {
- if (!cfs_iswhite(end[-1]))
+ if (!isspace(end[-1]))
break;
end--;
}
@@ -199,7 +178,7 @@ cfs_gettok(struct cfs_lstr *next, char delim, struct cfs_lstr *res)
/* skip leading white spaces */
while (next->ls_len) {
- if (!cfs_iswhite(*next->ls_str))
+ if (!isspace(*next->ls_str))
break;
next->ls_str++;
next->ls_len--;
@@ -226,14 +205,13 @@ cfs_gettok(struct cfs_lstr *next, char delim, struct cfs_lstr *res)
/* skip ending whitespaces */
while (--end != res->ls_str) {
- if (!cfs_iswhite(*end))
+ if (!isspace(*end))
break;
}
res->ls_len = end - res->ls_str + 1;
return 1;
}
-EXPORT_SYMBOL(cfs_gettok);
/**
* Converts string to integer.
@@ -256,13 +234,12 @@ cfs_str2num_check(char *str, int nob, unsigned *num,
return 0;
for (; endp < str + nob; endp++) {
- if (!cfs_iswhite(*endp))
+ if (!isspace(*endp))
return 0;
}
return (*num >= min && *num <= max);
}
-EXPORT_SYMBOL(cfs_str2num_check);
/**
* Parses \<range_expr\> token of the syntax. If \a bracketed is false,
@@ -277,7 +254,7 @@ EXPORT_SYMBOL(cfs_str2num_check);
* \retval 0 will be returned if it can be parsed, otherwise -EINVAL or
* -ENOMEM will be returned.
*/
-int
+static int
cfs_range_expr_parse(struct cfs_lstr *src, unsigned min, unsigned max,
int bracketed, struct cfs_range_expr **expr)
{
@@ -340,7 +317,6 @@ cfs_range_expr_parse(struct cfs_lstr *src, unsigned min, unsigned max,
LIBCFS_FREE(re, sizeof(*re));
return -EINVAL;
}
-EXPORT_SYMBOL(cfs_range_expr_parse);
/**
* Matches value (\a value) against ranges expression list \a expr_list.
@@ -361,7 +337,6 @@ cfs_expr_list_match(__u32 value, struct cfs_expr_list *expr_list)
return 0;
}
-EXPORT_SYMBOL(cfs_expr_list_match);
/**
* Convert express list (\a expr_list) to an array of all matched values
@@ -432,18 +407,6 @@ cfs_expr_list_free(struct cfs_expr_list *expr_list)
}
EXPORT_SYMBOL(cfs_expr_list_free);
-void
-cfs_expr_list_print(struct cfs_expr_list *expr_list)
-{
- struct cfs_range_expr *expr;
-
- list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
- CDEBUG(D_WARNING, "%d-%d/%d\n",
- expr->re_lo, expr->re_hi, expr->re_stride);
- }
-}
-EXPORT_SYMBOL(cfs_expr_list_print);
-
/**
* Parses \<cfs_expr_list\> token of the syntax.
*
@@ -526,7 +489,6 @@ cfs_expr_list_free_list(struct list_head *list)
cfs_expr_list_free(el);
}
}
-EXPORT_SYMBOL(cfs_expr_list_free_list);
int
cfs_ip_addr_parse(char *str, int len, struct list_head *list)
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c
index 58bb256ee047..77b1ef64ecc0 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c
@@ -952,6 +952,7 @@ static int
cfs_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
+ bool warn;
switch (action) {
case CPU_DEAD:
@@ -962,9 +963,21 @@ cfs_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
cpt_data.cpt_version++;
spin_unlock(&cpt_data.cpt_lock);
default:
- CWARN("Lustre: can't support CPU hotplug well now, "
- "performance and stability could be impacted"
- "[CPU %u notify: %lx]\n", cpu, action);
+ if (action != CPU_DEAD && action != CPU_DEAD_FROZEN) {
+ CDEBUG(D_INFO, "CPU changed [cpu %u action %lx]\n",
+ cpu, action);
+ break;
+ }
+
+ down(&cpt_data.cpt_mutex);
+ /* if all HTs in a core are offline, it may break affinity */
+ cfs_cpu_ht_siblings(cpu, cpt_data.cpt_cpumask);
+ warn = any_online_cpu(*cpt_data.cpt_cpumask) >= nr_cpu_ids;
+ up(&cpt_data.cpt_mutex);
+ CDEBUG(warn ? D_WARNING : D_INFO,
+ "Lustre: can't support CPU plug-out well now, "
+ "performance and stability could be impacted "
+ "[CPU %u action: %lx]\n", cpu, action);
}
return NOTIFY_OK;
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
index a2ef64c3403d..e74c3e28a972 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
@@ -55,25 +55,13 @@
* for Linux kernel.
*/
-int cfs_curproc_groups_nr(void)
-{
- int nr;
-
- task_lock(current);
- nr = current_cred()->group_info->ngroups;
- task_unlock(current);
- return nr;
-}
-
-/* Currently all the CFS_CAP_* defines match CAP_* ones. */
-#define cfs_cap_pack(cap) (cap)
-#define cfs_cap_unpack(cap) (cap)
-
void cfs_cap_raise(cfs_cap_t cap)
{
struct cred *cred;
- if ((cred = prepare_creds())) {
- cap_raise(cred->cap_effective, cfs_cap_unpack(cap));
+
+ cred = prepare_creds();
+ if (cred) {
+ cap_raise(cred->cap_effective, cap);
commit_creds(cred);
}
}
@@ -81,42 +69,28 @@ void cfs_cap_raise(cfs_cap_t cap)
void cfs_cap_lower(cfs_cap_t cap)
{
struct cred *cred;
- if ((cred = prepare_creds())) {
- cap_lower(cred->cap_effective, cfs_cap_unpack(cap));
+
+ cred = prepare_creds();
+ if (cred) {
+ cap_lower(cred->cap_effective, cap);
commit_creds(cred);
}
}
int cfs_cap_raised(cfs_cap_t cap)
{
- return cap_raised(current_cap(), cfs_cap_unpack(cap));
+ return cap_raised(current_cap(), cap);
}
void cfs_kernel_cap_pack(kernel_cap_t kcap, cfs_cap_t *cap)
{
-#if defined (_LINUX_CAPABILITY_VERSION) && _LINUX_CAPABILITY_VERSION == 0x19980330
- *cap = cfs_cap_pack(kcap);
-#elif defined (_LINUX_CAPABILITY_VERSION) && _LINUX_CAPABILITY_VERSION == 0x20071026
- *cap = cfs_cap_pack(kcap[0]);
-#elif defined(_KERNEL_CAPABILITY_VERSION) && _KERNEL_CAPABILITY_VERSION == 0x20080522
/* XXX lost high byte */
- *cap = cfs_cap_pack(kcap.cap[0]);
-#else
- #error "need correct _KERNEL_CAPABILITY_VERSION "
-#endif
+ *cap = kcap.cap[0];
}
void cfs_kernel_cap_unpack(kernel_cap_t *kcap, cfs_cap_t cap)
{
-#if defined (_LINUX_CAPABILITY_VERSION) && _LINUX_CAPABILITY_VERSION == 0x19980330
- *kcap = cfs_cap_unpack(cap);
-#elif defined (_LINUX_CAPABILITY_VERSION) && _LINUX_CAPABILITY_VERSION == 0x20071026
- (*kcap)[0] = cfs_cap_unpack(cap);
-#elif defined(_KERNEL_CAPABILITY_VERSION) && _KERNEL_CAPABILITY_VERSION == 0x20080522
- kcap->cap[0] = cfs_cap_unpack(cap);
-#else
- #error "need correct _KERNEL_CAPABILITY_VERSION "
-#endif
+ kcap->cap[0] = cap;
}
cfs_cap_t cfs_curproc_cap_pack(void)
@@ -126,20 +100,6 @@ cfs_cap_t cfs_curproc_cap_pack(void)
return cap;
}
-void cfs_curproc_cap_unpack(cfs_cap_t cap)
-{
- struct cred *cred;
- if ((cred = prepare_creds())) {
- cfs_kernel_cap_unpack(&cred->cap_effective, cap);
- commit_creds(cred);
- }
-}
-
-int cfs_capable(cfs_cap_t cap)
-{
- return capable(cfs_cap_unpack(cap));
-}
-
static int cfs_access_process_vm(struct task_struct *tsk, unsigned long addr,
void *buf, int len, int write)
{
@@ -292,13 +252,10 @@ out:
}
EXPORT_SYMBOL(cfs_get_environ);
-EXPORT_SYMBOL(cfs_curproc_groups_nr);
EXPORT_SYMBOL(cfs_cap_raise);
EXPORT_SYMBOL(cfs_cap_lower);
EXPORT_SYMBOL(cfs_cap_raised);
EXPORT_SYMBOL(cfs_curproc_cap_pack);
-EXPORT_SYMBOL(cfs_curproc_cap_unpack);
-EXPORT_SYMBOL(cfs_capable);
/*
* Local variables:
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c
index 55296a3591d5..e6eae0666f0d 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c
@@ -150,12 +150,12 @@ static long libcfs_ioctl(struct file *file,
/* Handle platform-dependent IOC requests */
switch (cmd) {
case IOC_LIBCFS_PANIC:
- if (!cfs_capable(CFS_CAP_SYS_BOOT))
+ if (!capable(CFS_CAP_SYS_BOOT))
return (-EPERM);
panic("debugctl-invoked panic");
return (0);
case IOC_LIBCFS_MEMHOG:
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CFS_CAP_SYS_ADMIN))
return -EPERM;
/* go thought */
}
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c
index c7bc7fcccb8e..9a40d1415a65 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c
@@ -46,13 +46,6 @@
#include <asm/kgdb.h>
#endif
-void
-init_waitqueue_entry_current(wait_queue_t *link)
-{
- init_waitqueue_entry(link, current);
-}
-EXPORT_SYMBOL(init_waitqueue_entry_current);
-
/**
* wait_queue_t of Linux (version < 2.6.34) is a FIFO list for exclusively
* waiting threads, which is not always desirable because all threads will
@@ -77,37 +70,6 @@ add_wait_queue_exclusive_head(wait_queue_head_t *waitq, wait_queue_t *link)
}
EXPORT_SYMBOL(add_wait_queue_exclusive_head);
-void
-waitq_wait(wait_queue_t *link, long state)
-{
- schedule();
-}
-EXPORT_SYMBOL(waitq_wait);
-
-int64_t
-waitq_timedwait(wait_queue_t *link, long state, int64_t timeout)
-{
- return schedule_timeout(timeout);
-}
-EXPORT_SYMBOL(waitq_timedwait);
-
-void
-schedule_timeout_and_set_state(long state, int64_t timeout)
-{
- set_current_state(state);
- schedule_timeout(timeout);
-}
-EXPORT_SYMBOL(schedule_timeout_and_set_state);
-
-/* deschedule for a bit... */
-void
-cfs_pause(cfs_duration_t ticks)
-{
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(ticks);
-}
-EXPORT_SYMBOL(cfs_pause);
-
void cfs_init_timer(struct timer_list *t)
{
init_timer(t);
diff --git a/drivers/staging/lustre/lustre/libcfs/nidstrings.c b/drivers/staging/lustre/lustre/libcfs/nidstrings.c
index 732ae5540bf4..cfb274fc9cbd 100644
--- a/drivers/staging/lustre/lustre/libcfs/nidstrings.c
+++ b/drivers/staging/lustre/lustre/libcfs/nidstrings.c
@@ -65,23 +65,20 @@ void libcfs_init_nidstrings(void)
spin_lock_init(&libcfs_nidstring_lock);
}
-# define NIDSTR_LOCK(f) spin_lock_irqsave(&libcfs_nidstring_lock, f)
-# define NIDSTR_UNLOCK(f) spin_unlock_irqrestore(&libcfs_nidstring_lock, f)
-
static char *
libcfs_next_nidstring(void)
{
char *str;
unsigned long flags;
- NIDSTR_LOCK(flags);
+ spin_lock_irqsave(&libcfs_nidstring_lock, flags);
str = libcfs_nidstrings[libcfs_nidstring_idx++];
if (libcfs_nidstring_idx ==
sizeof(libcfs_nidstrings)/sizeof(libcfs_nidstrings[0]))
libcfs_nidstring_idx = 0;
- NIDSTR_UNLOCK(flags);
+ spin_unlock_irqrestore(&libcfs_nidstring_lock, flags);
return str;
}
diff --git a/drivers/staging/lustre/lustre/libcfs/tracefile.c b/drivers/staging/lustre/lustre/libcfs/tracefile.c
index 54290ce6bb43..c8599eefeb76 100644
--- a/drivers/staging/lustre/lustre/libcfs/tracefile.c
+++ b/drivers/staging/lustre/lustre/libcfs/tracefile.c
@@ -1076,11 +1076,10 @@ end_loop:
break;
}
}
- init_waitqueue_entry_current(&__wait);
+ init_waitqueue_entry(&__wait, current);
add_wait_queue(&tctl->tctl_waitq, &__wait);
set_current_state(TASK_INTERRUPTIBLE);
- waitq_timedwait(&__wait, TASK_INTERRUPTIBLE,
- cfs_time_seconds(1));
+ schedule_timeout(cfs_time_seconds(1));
remove_wait_queue(&tctl->tctl_waitq, &__wait);
}
complete(&tctl->tctl_stop);
diff --git a/drivers/staging/lustre/lustre/libcfs/upcall_cache.c b/drivers/staging/lustre/lustre/libcfs/upcall_cache.c
index 245b46f0dd96..8085e32e5e7a 100644
--- a/drivers/staging/lustre/lustre/libcfs/upcall_cache.c
+++ b/drivers/staging/lustre/lustre/libcfs/upcall_cache.c
@@ -218,13 +218,12 @@ find_again:
MAX_SCHEDULE_TIMEOUT;
long left;
- init_waitqueue_entry_current(&wait);
+ init_waitqueue_entry(&wait, current);
add_wait_queue(&entry->ue_waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
spin_unlock(&cache->uc_lock);
- left = waitq_timedwait(&wait, TASK_INTERRUPTIBLE,
- expiry);
+ left = schedule_timeout(expiry);
spin_lock(&cache->uc_lock);
remove_wait_queue(&entry->ue_waitq, &wait);
diff --git a/drivers/staging/lustre/lustre/libcfs/workitem.c b/drivers/staging/lustre/lustre/libcfs/workitem.c
index 1a55c81892e0..ba16fd5db704 100644
--- a/drivers/staging/lustre/lustre/libcfs/workitem.c
+++ b/drivers/staging/lustre/lustre/libcfs/workitem.c
@@ -334,7 +334,8 @@ cfs_wi_sched_destroy(struct cfs_wi_sched *sched)
sched->ws_nthreads, sched->ws_name);
spin_unlock(&cfs_wi_data.wi_glock);
- cfs_pause(cfs_time_seconds(1) / 20);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1) / 20);
spin_lock(&cfs_wi_data.wi_glock);
}
@@ -389,11 +390,11 @@ cfs_wi_sched_create(char *name, struct cfs_cpt_table *cptab,
spin_unlock(&cfs_wi_data.wi_glock);
if (sched->ws_cptab != NULL && sched->ws_cpt >= 0) {
- snprintf(name, sizeof(name), "%s_%02d_%02d",
+ snprintf(name, sizeof(name), "%s_%02d_%02u",
sched->ws_name, sched->ws_cpt,
sched->ws_nthreads);
} else {
- snprintf(name, sizeof(name), "%s_%02d",
+ snprintf(name, sizeof(name), "%s_%02u",
sched->ws_name, sched->ws_nthreads);
}
@@ -459,7 +460,8 @@ cfs_wi_shutdown (void)
while (sched->ws_nthreads != 0) {
spin_unlock(&cfs_wi_data.wi_glock);
- cfs_pause(cfs_time_seconds(1) / 20);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1) / 20);
spin_lock(&cfs_wi_data.wi_glock);
}
spin_unlock(&cfs_wi_data.wi_glock);
diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c
index cbd663ed030c..8b5508086174 100644
--- a/drivers/staging/lustre/lustre/llite/dcache.c
+++ b/drivers/staging/lustre/lustre/llite/dcache.c
@@ -160,7 +160,7 @@ static int ll_ddelete(const struct dentry *de)
/* kernel >= 2.6.38 last refcount is decreased after this function. */
LASSERT(d_count(de) == 1);
- /* Disable this piece of code temproarily because this is called
+ /* Disable this piece of code temporarily because this is called
* inside dcache_lock so it's not appropriate to do lots of work
* here. ATTENTION: Before this piece of code enabling, LU-2487 must be
* resolved. */
@@ -176,7 +176,7 @@ static int ll_ddelete(const struct dentry *de)
return 0;
}
-static int ll_set_dd(struct dentry *de)
+int ll_d_init(struct dentry *de)
{
LASSERT(de != NULL);
@@ -190,40 +190,22 @@ static int ll_set_dd(struct dentry *de)
OBD_ALLOC_PTR(lld);
if (likely(lld != NULL)) {
spin_lock(&de->d_lock);
- if (likely(de->d_fsdata == NULL))
+ if (likely(de->d_fsdata == NULL)) {
de->d_fsdata = lld;
- else
+ __d_lustre_invalidate(de);
+ } else {
OBD_FREE_PTR(lld);
+ }
spin_unlock(&de->d_lock);
} else {
return -ENOMEM;
}
}
+ LASSERT(de->d_op == &ll_d_ops);
return 0;
}
-int ll_dops_init(struct dentry *de, int block, int init_sa)
-{
- struct ll_dentry_data *lld = ll_d2d(de);
- int rc = 0;
-
- if (lld == NULL && block != 0) {
- rc = ll_set_dd(de);
- if (rc)
- return rc;
-
- lld = ll_d2d(de);
- }
-
- if (lld != NULL && init_sa != 0)
- lld->lld_sa_generation = 0;
-
- /* kernel >= 2.6.38 d_op is set in d_alloc() */
- LASSERT(de->d_op == &ll_d_ops);
- return rc;
-}
-
void ll_intent_drop_lock(struct lookup_intent *it)
{
if (it->it_op && it->d.lustre.it_lock_mode) {
@@ -259,9 +241,6 @@ void ll_intent_release(struct lookup_intent *it)
ptlrpc_req_finished(it->d.lustre.it_data); /* ll_file_open */
if (it_disposition(it, DISP_ENQ_CREATE_REF)) /* create rec */
ptlrpc_req_finished(it->d.lustre.it_data);
- if (it_disposition(it, DISP_ENQ_COMPLETE)) /* saved req from revalidate
- * to lookup */
- ptlrpc_req_finished(it->d.lustre.it_data);
it->d.lustre.it_disposition = 0;
it->d.lustre.it_data = NULL;
@@ -346,268 +325,32 @@ void ll_frob_intent(struct lookup_intent **itp, struct lookup_intent *deft)
}
-int ll_revalidate_it(struct dentry *de, int lookup_flags,
- struct lookup_intent *it)
+static int ll_revalidate_dentry(struct dentry *dentry,
+ unsigned int lookup_flags)
{
- struct md_op_data *op_data;
- struct ptlrpc_request *req = NULL;
- struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
- struct obd_export *exp;
- struct inode *parent = de->d_parent->d_inode;
- int rc;
-
- CDEBUG(D_VFSTRACE, "VFS Op:name=%s,intent=%s\n", de->d_name.name,
- LL_IT2STR(it));
+ struct inode *dir = dentry->d_parent->d_inode;
- if (de->d_inode == NULL) {
- __u64 ibits;
-
- /* We can only use negative dentries if this is stat or lookup,
- for opens and stuff we do need to query server. */
- /* If there is IT_CREAT in intent op set, then we must throw
- away this negative dentry and actually do the request to
- kernel to create whatever needs to be created (if possible)*/
- if (it && (it->it_op & IT_CREAT))
- return 0;
-
- if (d_lustre_invalid(de))
- return 0;
-
- ibits = MDS_INODELOCK_UPDATE;
- rc = ll_have_md_lock(parent, &ibits, LCK_MINMODE);
- GOTO(out_sa, rc);
- }
-
- /* Never execute intents for mount points.
- * Attributes will be fixed up in ll_inode_revalidate_it */
- if (d_mountpoint(de))
- GOTO(out_sa, rc = 1);
-
- /* need to get attributes in case root got changed from other client */
- if (de == de->d_sb->s_root) {
- rc = __ll_inode_revalidate_it(de, it, MDS_INODELOCK_LOOKUP);
- if (rc == 0)
- rc = 1;
- GOTO(out_sa, rc);
- }
-
- exp = ll_i2mdexp(de->d_inode);
-
- OBD_FAIL_TIMEOUT(OBD_FAIL_MDC_REVALIDATE_PAUSE, 5);
- ll_frob_intent(&it, &lookup_it);
- LASSERT(it);
+ /*
+ * if open&create is set, talk to MDS to make sure file is created if
+ * necessary, because we can't do this in ->open() later since that's
+ * called on an inode. return 0 here to let lookup to handle this.
+ */
+ if ((lookup_flags & (LOOKUP_OPEN | LOOKUP_CREATE)) ==
+ (LOOKUP_OPEN | LOOKUP_CREATE))
+ return 0;
- if (it->it_op == IT_LOOKUP && !d_lustre_invalid(de))
+ if (lookup_flags & (LOOKUP_PARENT | LOOKUP_OPEN | LOOKUP_CREATE))
return 1;
- if (it->it_op == IT_OPEN) {
- struct inode *inode = de->d_inode;
- struct ll_inode_info *lli = ll_i2info(inode);
- struct obd_client_handle **och_p;
- __u64 ibits;
-
- /*
- * We used to check for MDS_INODELOCK_OPEN here, but in fact
- * just having LOOKUP lock is enough to justify inode is the
- * same. And if inode is the same and we have suitable
- * openhandle, then there is no point in doing another OPEN RPC
- * just to throw away newly received openhandle. There are no
- * security implications too, if file owner or access mode is
- * change, LOOKUP lock is revoked.
- */
-
-
- if (it->it_flags & FMODE_WRITE)
- och_p = &lli->lli_mds_write_och;
- else if (it->it_flags & FMODE_EXEC)
- och_p = &lli->lli_mds_exec_och;
- else
- och_p = &lli->lli_mds_read_och;
-
- /* Check for the proper lock. */
- ibits = MDS_INODELOCK_LOOKUP;
- if (!ll_have_md_lock(inode, &ibits, LCK_MINMODE))
- goto do_lock;
- mutex_lock(&lli->lli_och_mutex);
- if (*och_p) { /* Everything is open already, do nothing */
- /* Originally it was idea to do not let them steal our
- * open handle from under us by (*och_usecount)++ here.
- * But in case we have the handle, but we cannot use it
- * due to later checks (e.g. O_CREAT|O_EXCL flags set),
- * nobody would decrement counter increased here. So we
- * just hope the lock won't be invalidated in between.
- * But if it would be, we'll reopen the open request to
- * MDS later during file open path.
- */
- mutex_unlock(&lli->lli_och_mutex);
- return 1;
- }
- mutex_unlock(&lli->lli_och_mutex);
- }
-
- if (it->it_op == IT_GETATTR) {
- rc = ll_statahead_enter(parent, &de, 0);
- if (rc == 1)
- goto mark;
- else if (rc != -EAGAIN && rc != 0)
- GOTO(out, rc = 0);
- }
-
-do_lock:
- op_data = ll_prep_md_op_data(NULL, parent, de->d_inode,
- de->d_name.name, de->d_name.len,
- 0, LUSTRE_OPC_ANY, NULL);
- if (IS_ERR(op_data))
- return PTR_ERR(op_data);
-
- if (!IS_POSIXACL(parent) || !exp_connect_umask(exp))
- it->it_create_mode &= ~current_umask();
- it->it_create_mode |= M_CHECK_STALE;
- rc = md_intent_lock(exp, op_data, NULL, 0, it,
- lookup_flags,
- &req, ll_md_blocking_ast, 0);
- it->it_create_mode &= ~M_CHECK_STALE;
- ll_finish_md_op_data(op_data);
-
- /* If req is NULL, then md_intent_lock only tried to do a lock match;
- * if all was well, it will return 1 if it found locks, 0 otherwise. */
- if (req == NULL && rc >= 0) {
- if (!rc)
- goto do_lookup;
- GOTO(out, rc);
- }
-
- if (rc < 0) {
- if (rc != -ESTALE) {
- CDEBUG(D_INFO, "ll_intent_lock: rc %d : it->it_status "
- "%d\n", rc, it->d.lustre.it_status);
- }
- GOTO(out, rc = 0);
- }
-
-revalidate_finish:
- rc = ll_revalidate_it_finish(req, it, de);
- if (rc != 0) {
- if (rc != -ESTALE && rc != -ENOENT)
- ll_intent_release(it);
- GOTO(out, rc = 0);
- }
-
- if ((it->it_op & IT_OPEN) && de->d_inode &&
- !S_ISREG(de->d_inode->i_mode) &&
- !S_ISDIR(de->d_inode->i_mode)) {
- ll_release_openhandle(de, it);
- }
- rc = 1;
-
-out:
- /* We do not free request as it may be reused during following lookup
- * (see comment in mdc/mdc_locks.c::mdc_intent_lock()), request will
- * be freed in ll_lookup_it or in ll_intent_release. But if
- * request was not completed, we need to free it. (bug 5154, 9903) */
- if (req != NULL && !it_disposition(it, DISP_ENQ_COMPLETE))
- ptlrpc_req_finished(req);
- if (rc == 0) {
- /* mdt may grant layout lock for the newly created file, so
- * release the lock to avoid leaking */
- ll_intent_drop_lock(it);
- ll_invalidate_aliases(de->d_inode);
- } else {
- __u64 bits = 0;
- __u64 matched_bits = 0;
-
- CDEBUG(D_DENTRY, "revalidated dentry %.*s (%p) parent %p "
- "inode %p refc %d\n", de->d_name.len,
- de->d_name.name, de, de->d_parent, de->d_inode,
- d_count(de));
-
- ll_set_lock_data(exp, de->d_inode, it, &bits);
-
- /* Note: We have to match both LOOKUP and PERM lock
- * here to make sure the dentry is valid and no one
- * changing the permission.
- * But if the client connects < 2.4 server, which will
- * only grant LOOKUP lock, so we can only Match LOOKUP
- * lock for old server */
- if (exp_connect_flags(ll_i2mdexp(de->d_inode)) &&
- OBD_CONNECT_LVB_TYPE)
- matched_bits =
- MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM;
- else
- matched_bits = MDS_INODELOCK_LOOKUP;
-
- if (((bits & matched_bits) == matched_bits) &&
- d_lustre_invalid(de))
- d_lustre_revalidate(de);
- ll_lookup_finish_locks(it, de);
- }
-
-mark:
- if (it != NULL && it->it_op == IT_GETATTR && rc > 0)
- ll_statahead_mark(parent, de);
- return rc;
-
- /*
- * This part is here to combat evil-evil race in real_lookup on 2.6
- * kernels. The race details are: We enter do_lookup() looking for some
- * name, there is nothing in dcache for this name yet and d_lookup()
- * returns NULL. We proceed to real_lookup(), and while we do this,
- * another process does open on the same file we looking up (most simple
- * reproducer), open succeeds and the dentry is added. Now back to
- * us. In real_lookup() we do d_lookup() again and suddenly find the
- * dentry, so we call d_revalidate on it, but there is no lock, so
- * without this code we would return 0, but unpatched real_lookup just
- * returns -ENOENT in such a case instead of retrying the lookup. Once
- * this is dealt with in real_lookup(), all of this ugly mess can go and
- * we can just check locks in ->d_revalidate without doing any RPCs
- * ever.
- */
-do_lookup:
- if (it != &lookup_it) {
- /* MDS_INODELOCK_UPDATE needed for IT_GETATTR case. */
- if (it->it_op == IT_GETATTR)
- lookup_it.it_op = IT_GETATTR;
- ll_lookup_finish_locks(it, de);
- it = &lookup_it;
- }
+ if (d_need_statahead(dir, dentry) <= 0)
+ return 1;
- /* Do real lookup here. */
- op_data = ll_prep_md_op_data(NULL, parent, NULL, de->d_name.name,
- de->d_name.len, 0, (it->it_op & IT_CREAT ?
- LUSTRE_OPC_CREATE :
- LUSTRE_OPC_ANY), NULL);
- if (IS_ERR(op_data))
- return PTR_ERR(op_data);
-
- rc = md_intent_lock(exp, op_data, NULL, 0, it, 0, &req,
- ll_md_blocking_ast, 0);
- if (rc >= 0) {
- struct mdt_body *mdt_body;
- struct lu_fid fid = {.f_seq = 0, .f_oid = 0, .f_ver = 0};
- mdt_body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
-
- if (de->d_inode)
- fid = *ll_inode2fid(de->d_inode);
-
- /* see if we got same inode, if not - return error */
- if (lu_fid_eq(&fid, &mdt_body->fid1)) {
- ll_finish_md_op_data(op_data);
- op_data = NULL;
- goto revalidate_finish;
- }
- ll_intent_release(it);
- }
- ll_finish_md_op_data(op_data);
- GOTO(out, rc = 0);
+ if (lookup_flags & LOOKUP_RCU)
+ return -ECHILD;
-out_sa:
- /*
- * For rc == 1 case, should not return directly to prevent losing
- * statahead windows; for rc == 0 case, the "lookup" will be done later.
- */
- if (it != NULL && it->it_op == IT_GETATTR && rc == 1)
- ll_statahead_enter(parent, &de, 1);
- goto mark;
+ do_statahead_enter(dir, &dentry, dentry->d_inode == NULL);
+ ll_statahead_mark(dir, dentry);
+ return 1;
}
/*
@@ -615,24 +358,13 @@ out_sa:
*/
int ll_revalidate_nd(struct dentry *dentry, unsigned int flags)
{
- struct inode *parent = dentry->d_parent->d_inode;
- int unplug = 0;
+ int rc;
- CDEBUG(D_VFSTRACE, "VFS Op:name=%s,flags=%u\n",
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%s, flags=%u\n",
dentry->d_name.name, flags);
- if (!(flags & (LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE)) &&
- ll_need_statahead(parent, dentry) > 0) {
- if (flags & LOOKUP_RCU)
- return -ECHILD;
-
- if (dentry->d_inode == NULL)
- unplug = 1;
- do_statahead_enter(parent, &dentry, unplug);
- ll_statahead_mark(parent, dentry);
- }
-
- return 1;
+ rc = ll_revalidate_dentry(dentry, flags);
+ return rc;
}
diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c
index 52b7731bcc38..7fbc18e3e654 100644
--- a/drivers/staging/lustre/lustre/llite/dir.c
+++ b/drivers/staging/lustre/lustre/llite/dir.c
@@ -362,7 +362,7 @@ struct page *ll_get_dir_page(struct inode *dir, __u64 hash,
struct ptlrpc_request *request;
struct md_op_data *op_data;
- op_data = ll_prep_md_op_data(NULL, dir, NULL, NULL, 0, 0,
+ op_data = ll_prep_md_op_data(NULL, dir, dir, NULL, 0, 0,
LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
return (void *)op_data;
@@ -1048,20 +1048,25 @@ progress:
}
-static int copy_and_ioctl(int cmd, struct obd_export *exp, void *data, int len)
+static int copy_and_ioctl(int cmd, struct obd_export *exp,
+ const void __user *data, size_t size)
{
- void *ptr;
+ void *copy;
int rc;
- OBD_ALLOC(ptr, len);
- if (ptr == NULL)
+ OBD_ALLOC(copy, size);
+ if (copy == NULL)
return -ENOMEM;
- if (copy_from_user(ptr, data, len)) {
- OBD_FREE(ptr, len);
- return -EFAULT;
+
+ if (copy_from_user(copy, data, size)) {
+ rc = -EFAULT;
+ goto out;
}
- rc = obd_iocontrol(cmd, exp, len, data, NULL);
- OBD_FREE(ptr, len);
+
+ rc = obd_iocontrol(cmd, exp, size, copy, NULL);
+out:
+ OBD_FREE(copy, size);
+
return rc;
}
@@ -1080,7 +1085,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
case Q_QUOTAOFF:
case Q_SETQUOTA:
case Q_SETINFO:
- if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
+ if (!capable(CFS_CAP_SYS_ADMIN) ||
sbi->ll_flags & LL_SBI_RMT_CLIENT)
return -EPERM;
break;
@@ -1089,7 +1094,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
!uid_eq(current_euid(), make_kuid(&init_user_ns, id))) ||
(type == GRPQUOTA &&
!in_egroup_p(make_kgid(&init_user_ns, id)))) &&
- (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
+ (!capable(CFS_CAP_SYS_ADMIN) ||
sbi->ll_flags & LL_SBI_RMT_CLIENT))
return -EPERM;
break;
@@ -1395,7 +1400,7 @@ lmv_out_free:
if (tmp == NULL)
GOTO(free_lmv, rc = -ENOMEM);
- memcpy(tmp, &lum, sizeof(lum));
+ *tmp = lum;
tmp->lum_type = LMV_STRIPE_TYPE;
tmp->lum_stripe_count = 1;
mdtindex = ll_get_mdt_idx(inode);
@@ -1597,7 +1602,7 @@ out_rmdir:
struct obd_quotactl *oqctl;
int error = 0;
- if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
+ if (!capable(CFS_CAP_SYS_ADMIN) ||
sbi->ll_flags & LL_SBI_RMT_CLIENT)
return -EPERM;
@@ -1621,7 +1626,7 @@ out_rmdir:
case OBD_IOC_POLL_QUOTACHECK: {
struct if_quotacheck *check;
- if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
+ if (!capable(CFS_CAP_SYS_ADMIN) ||
sbi->ll_flags & LL_SBI_RMT_CLIENT)
return -EPERM;
diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c
index c12821aedc2f..8e844a6371e0 100644
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -205,7 +205,7 @@ out:
return rc;
}
-int ll_md_real_close(struct inode *inode, int flags)
+int ll_md_real_close(struct inode *inode, fmode_t fmode)
{
struct ll_inode_info *lli = ll_i2info(inode);
struct obd_client_handle **och_p;
@@ -213,30 +213,33 @@ int ll_md_real_close(struct inode *inode, int flags)
__u64 *och_usecount;
int rc = 0;
- if (flags & FMODE_WRITE) {
+ if (fmode & FMODE_WRITE) {
och_p = &lli->lli_mds_write_och;
och_usecount = &lli->lli_open_fd_write_count;
- } else if (flags & FMODE_EXEC) {
+ } else if (fmode & FMODE_EXEC) {
och_p = &lli->lli_mds_exec_och;
och_usecount = &lli->lli_open_fd_exec_count;
} else {
- LASSERT(flags & FMODE_READ);
+ LASSERT(fmode & FMODE_READ);
och_p = &lli->lli_mds_read_och;
och_usecount = &lli->lli_open_fd_read_count;
}
mutex_lock(&lli->lli_och_mutex);
- if (*och_usecount) { /* There are still users of this handle, so
- skip freeing it. */
+ if (*och_usecount > 0) {
+ /* There are still users of this handle, so skip
+ * freeing it. */
mutex_unlock(&lli->lli_och_mutex);
return 0;
}
+
och=*och_p;
*och_p = NULL;
mutex_unlock(&lli->lli_och_mutex);
- if (och) { /* There might be a race and somebody have freed this och
- already */
+ if (och != NULL) {
+ /* There might be a race and this handle may already
+ be closed. */
rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp,
inode, och, NULL);
}
@@ -443,8 +446,7 @@ static int ll_intent_file_open(struct file *file, void *lmm,
itp, NULL);
out:
- ptlrpc_req_finished(itp->d.lustre.it_data);
- it_clear_disposition(itp, DISP_ENQ_COMPLETE);
+ ptlrpc_req_finished(req);
ll_intent_drop_lock(itp);
return rc;
@@ -477,7 +479,7 @@ static int ll_och_fill(struct obd_export *md_exp, struct lookup_intent *it,
och->och_magic = OBD_CLIENT_HANDLE_MAGIC;
och->och_flags = it->it_flags;
- return md_set_open_replay_data(md_exp, och, req);
+ return md_set_open_replay_data(md_exp, och, it);
}
int ll_local_open(struct file *file, struct lookup_intent *it,
@@ -671,14 +673,13 @@ restart:
ll_capa_open(inode);
- if (!lli->lli_has_smd) {
- if (file->f_flags & O_LOV_DELAY_CREATE ||
- !(file->f_mode & FMODE_WRITE)) {
- CDEBUG(D_INODE, "object creation was delayed\n");
- GOTO(out_och_free, rc);
- }
+ if (!lli->lli_has_smd &&
+ (cl_is_lov_delay_create(file->f_flags) ||
+ (file->f_mode & FMODE_WRITE) == 0)) {
+ CDEBUG(D_INODE, "object creation was delayed\n");
+ GOTO(out_och_free, rc);
}
- file->f_flags &= ~O_LOV_DELAY_CREATE;
+ cl_lov_delay_create_clear(&file->f_flags);
GOTO(out_och_free, rc);
out_och_free:
@@ -813,10 +814,7 @@ struct obd_client_handle *ll_lease_open(struct inode *inode, struct file *file,
* doesn't deal with openhandle, so normal openhandle will be leaked. */
LDLM_FL_NO_LRU | LDLM_FL_EXCL);
ll_finish_md_op_data(op_data);
- if (req != NULL) {
- ptlrpc_req_finished(req);
- it_clear_disposition(&it, DISP_ENQ_COMPLETE);
- }
+ ptlrpc_req_finished(req);
if (rc < 0)
GOTO(out_release_it, rc);
@@ -1033,6 +1031,33 @@ int ll_glimpse_ioctl(struct ll_sb_info *sbi, struct lov_stripe_md *lsm,
return rc;
}
+static bool file_is_noatime(const struct file *file)
+{
+ const struct vfsmount *mnt = file->f_path.mnt;
+ const struct inode *inode = file->f_path.dentry->d_inode;
+
+ /* Adapted from file_accessed() and touch_atime().*/
+ if (file->f_flags & O_NOATIME)
+ return true;
+
+ if (inode->i_flags & S_NOATIME)
+ return true;
+
+ if (IS_NOATIME(inode))
+ return true;
+
+ if (mnt->mnt_flags & (MNT_NOATIME | MNT_READONLY))
+ return true;
+
+ if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
+ return true;
+
+ if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
+ return true;
+
+ return false;
+}
+
void ll_io_init(struct cl_io *io, const struct file *file, int write)
{
struct inode *inode = file->f_dentry->d_inode;
@@ -1052,6 +1077,8 @@ void ll_io_init(struct cl_io *io, const struct file *file, int write)
} else if (file->f_flags & O_APPEND) {
io->ci_lockreq = CILR_MANDATORY;
}
+
+ io->ci_noatime = file_is_noatime(file);
}
static ssize_t
@@ -1092,16 +1119,12 @@ restart:
down_read(&lli->lli_trunc_sem);
}
break;
- case IO_SENDFILE:
- vio->u.sendfile.cui_actor = args->u.sendfile.via_actor;
- vio->u.sendfile.cui_target = args->u.sendfile.via_target;
- break;
case IO_SPLICE:
vio->u.splice.cui_pipe = args->u.splice.via_pipe;
vio->u.splice.cui_flags = args->u.splice.via_flags;
break;
default:
- CERROR("Unknow IO type - %u\n", vio->cui_io_subtype);
+ CERROR("Unknown IO type - %u\n", vio->cui_io_subtype);
LBUG();
}
result = cl_io_loop(env, io);
@@ -1340,7 +1363,7 @@ static int ll_lov_recreate_obj(struct inode *inode, unsigned long arg)
struct ll_recreate_obj ucreat;
struct ost_id oi;
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CFS_CAP_SYS_ADMIN))
return -EPERM;
if (copy_from_user(&ucreat, (struct ll_recreate_obj *)arg,
@@ -1358,7 +1381,7 @@ static int ll_lov_recreate_fid(struct inode *inode, unsigned long arg)
struct ost_id oi;
obd_count ost_idx;
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CFS_CAP_SYS_ADMIN))
return -EPERM;
if (copy_from_user(&fid, (struct lu_fid *)arg, sizeof(fid)))
@@ -1381,23 +1404,25 @@ int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file,
ccc_inode_lsm_put(inode, lsm);
CDEBUG(D_IOCTL, "stripe already exists for ino %lu\n",
inode->i_ino);
- return -EEXIST;
+ GOTO(out, rc = -EEXIST);
}
ll_inode_size_lock(inode);
rc = ll_intent_file_open(file, lum, lum_size, &oit);
if (rc)
- GOTO(out, rc);
+ GOTO(out_unlock, rc);
rc = oit.d.lustre.it_status;
if (rc < 0)
GOTO(out_req_free, rc);
ll_release_openhandle(file->f_dentry, &oit);
- out:
+out_unlock:
ll_inode_size_unlock(inode);
ll_intent_release(&oit);
ccc_inode_lsm_put(inode, lsm);
+out:
+ cl_lov_delay_create_clear(&file->f_flags);
return rc;
out_req_free:
ptlrpc_req_finished((struct ptlrpc_request *) oit.d.lustre.it_data);
@@ -1497,7 +1522,7 @@ static int ll_lov_setea(struct inode *inode, struct file *file,
sizeof(struct lov_user_ost_data);
int rc;
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CFS_CAP_SYS_ADMIN))
return -EPERM;
OBD_ALLOC_LARGE(lump, lum_size);
@@ -1747,7 +1772,7 @@ int ll_fid2path(struct inode *inode, void *arg)
struct getinfo_fid2path *gfout, *gfin;
int outsize, rc;
- if (!cfs_capable(CFS_CAP_DAC_READ_SEARCH) &&
+ if (!capable(CFS_CAP_DAC_READ_SEARCH) &&
!(ll_i2sbi(inode)->ll_flags & LL_SBI_USER_FID2PATH))
return -EPERM;
@@ -2005,7 +2030,7 @@ static int ll_swap_layouts(struct file *file1, struct file *file2,
llss->ia2.ia_valid = ATTR_MTIME | ATTR_ATIME;
}
- /* ultimate check, before swaping the layouts we check if
+ /* ultimate check, before swapping the layouts we check if
* dataversion has changed (if requested) */
if (llss->check_dv1) {
rc = ll_data_version(llss->inode1, &dv, 0);
@@ -2093,7 +2118,7 @@ static int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss)
/* Non-root users are forbidden to set or clear flags which are
* NOT defined in HSM_USER_MASK. */
if (((hss->hss_setmask | hss->hss_clearmask) & ~HSM_USER_MASK) &&
- !cfs_capable(CFS_CAP_SYS_ADMIN))
+ !capable(CFS_CAP_SYS_ADMIN))
return -EPERM;
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
@@ -2670,7 +2695,7 @@ int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
LASSERT((cmd == F_SETLKW) || (cmd == F_SETLK));
/* flocks are whole-file locks */
flock.l_flock.end = OFFSET_MAX;
- /* For flocks owner is determined by the local file desctiptor*/
+ /* For flocks owner is determined by the local file descriptor*/
flock.l_flock.owner = (unsigned long)file_lock->fl_file;
} else if (file_lock->fl_flags & FL_POSIX) {
flock.l_flock.owner = (unsigned long)file_lock->fl_owner;
@@ -2891,7 +2916,7 @@ int __ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it,
oit.it_op = IT_LOOKUP;
/* Call getattr by fid, so do not provide name at all. */
- op_data = ll_prep_md_op_data(NULL, dentry->d_parent->d_inode,
+ op_data = ll_prep_md_op_data(NULL, dentry->d_inode,
dentry->d_inode, NULL, 0, 0,
LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
@@ -3175,7 +3200,7 @@ struct inode_operations ll_file_inode_operations = {
.get_acl = ll_get_acl,
};
-/* dynamic ioctl number support routins */
+/* dynamic ioctl number support routines */
static struct llioc_ctl_data {
struct rw_semaphore ioc_sem;
struct list_head ioc_head;
@@ -3299,7 +3324,7 @@ int ll_layout_conf(struct inode *inode, const struct cl_object_conf *conf)
if (result == 0) {
/* it can only be allowed to match after layout is
* applied to inode otherwise false layout would be
- * seen. Applying layout shoud happen before dropping
+ * seen. Applying layout should happen before dropping
* the intent lock. */
ldlm_lock_allow_match(lock);
}
diff --git a/drivers/staging/lustre/lustre/llite/llite_close.c b/drivers/staging/lustre/lustre/llite/llite_close.c
index e2996c46b2c0..38c2d0e947db 100644
--- a/drivers/staging/lustre/lustre/llite/llite_close.c
+++ b/drivers/staging/lustre/lustre/llite/llite_close.c
@@ -348,7 +348,7 @@ static int ll_close_thread(void *arg)
break;
inode = ll_info2i(lli);
- CDEBUG(D_INFO, "done_writting for inode %lu/%u\n",
+ CDEBUG(D_INFO, "done_writing for inode %lu/%u\n",
inode->i_ino, inode->i_generation);
ll_done_writing(inode);
iput(inode);
diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h
index 7ee5c02783f9..69aba0afca41 100644
--- a/drivers/staging/lustre/lustre/llite/llite_internal.h
+++ b/drivers/staging/lustre/lustre/llite/llite_internal.h
@@ -296,13 +296,6 @@ int ll_xattr_cache_get(struct inode *inode,
size_t size,
__u64 valid);
-int ll_xattr_cache_update(struct inode *inode,
- const char *name,
- const char *newval,
- size_t size,
- __u64 valid,
- int flags);
-
/*
* Locking to guarantee consistency of non-atomic updates to long long i_size,
* consistency between file size and KMS.
@@ -532,7 +525,7 @@ struct ll_sb_info {
atomic_t ll_agl_total; /* AGL thread started count */
dev_t ll_sdev_orig; /* save s_dev before assign for
- * clustred nfs */
+ * clustered nfs */
struct rmtacl_ctl_table ll_rct;
struct eacl_table ll_et;
__kernel_fsid_t ll_fsid;
@@ -782,7 +775,7 @@ int ll_local_open(struct file *file,
int ll_release_openhandle(struct dentry *, struct lookup_intent *);
int ll_md_close(struct obd_export *md_exp, struct inode *inode,
struct file *file);
-int ll_md_real_close(struct inode *inode, int flags);
+int ll_md_real_close(struct inode *inode, fmode_t fmode);
void ll_ioepoch_close(struct inode *inode, struct md_op_data *op_data,
struct obd_client_handle **och, unsigned long flags);
void ll_done_writing_attr(struct inode *inode, struct md_op_data *op_data);
@@ -828,7 +821,7 @@ int ll_lease_close(struct obd_client_handle *och, struct inode *inode,
/* llite/dcache.c */
-int ll_dops_init(struct dentry *de, int block, int init_sa);
+int ll_d_init(struct dentry *de);
extern struct dentry_operations ll_d_ops;
void ll_intent_drop_lock(struct lookup_intent *);
void ll_intent_release(struct lookup_intent *);
@@ -915,12 +908,10 @@ struct ccc_object *cl_inode2ccc(struct inode *inode);
void vvp_write_pending (struct ccc_object *club, struct ccc_page *page);
void vvp_write_complete(struct ccc_object *club, struct ccc_page *page);
-/* specific achitecture can implement only part of this list */
+/* specific architecture can implement only part of this list */
enum vvp_io_subtype {
/** normal IO */
IO_NORMAL,
- /** io called from .sendfile */
- IO_SENDFILE,
/** io started from splice_{read|write} */
IO_SPLICE
};
@@ -932,10 +923,6 @@ struct vvp_io {
union {
struct {
- read_actor_t cui_actor;
- void *cui_target;
- } sendfile;
- struct {
struct pipe_inode_info *cui_pipe;
unsigned int cui_flags;
} splice;
@@ -981,7 +968,7 @@ struct vvp_io {
* IO arguments for various VFS I/O interfaces.
*/
struct vvp_io_args {
- /** normal/sendfile/splice */
+ /** normal/splice */
enum vvp_io_subtype via_io_subtype;
union {
@@ -991,10 +978,6 @@ struct vvp_io_args {
unsigned long via_nrsegs;
} normal;
struct {
- read_actor_t via_actor;
- void *via_target;
- } sendfile;
- struct {
struct pipe_inode_info *via_pipe;
unsigned int via_flags;
} splice;
@@ -1320,12 +1303,13 @@ ll_statahead_mark(struct inode *dir, struct dentry *dentry)
if (lli->lli_opendir_pid != current_pid())
return;
- if (sai != NULL && ldd != NULL)
+ LASSERT(ldd != NULL);
+ if (sai != NULL)
ldd->lld_sa_generation = sai->sai_generation;
}
static inline int
-ll_need_statahead(struct inode *dir, struct dentry *dentryp)
+d_need_statahead(struct inode *dir, struct dentry *dentryp)
{
struct ll_inode_info *lli;
struct ll_dentry_data *ldd;
@@ -1370,14 +1354,14 @@ ll_statahead_enter(struct inode *dir, struct dentry **dentryp, int only_unplug)
{
int ret;
- ret = ll_need_statahead(dir, *dentryp);
+ ret = d_need_statahead(dir, *dentryp);
if (ret <= 0)
return ret;
return do_statahead_enter(dir, dentryp, only_unplug);
}
-/* llite ioctl register support rountine */
+/* llite ioctl register support routine */
enum llioc_iter {
LLIOC_CONT = 0,
LLIOC_STOP
@@ -1389,7 +1373,7 @@ enum llioc_iter {
* Rules to write a callback function:
*
* Parameters:
- * @magic: Dynamic ioctl call routine will feed this vaule with the pointer
+ * @magic: Dynamic ioctl call routine will feed this value with the pointer
* returned to ll_iocontrol_register. Callback functions should use this
* data to check the potential collasion of ioctl cmd. If collasion is
* found, callback function should return LLIOC_CONT.
@@ -1414,7 +1398,7 @@ enum llioc_iter ll_iocontrol_call(struct inode *inode, struct file *file,
* @cb: callback function, it will be called if an ioctl command is found to
* belong to the command list @cmd.
*
- * Return vaule:
+ * Return value:
* A magic pointer will be returned if success;
* otherwise, NULL will be returned.
* */
@@ -1524,7 +1508,7 @@ static inline void ll_set_lock_data(struct obd_export *exp, struct inode *inode,
* separate locks in different namespaces, Master MDT,
* where the name entry is, will grant LOOKUP lock,
* remote MDT, where the object is, will grant
- * UPDATE|PERM lock. The inode will be attched to both
+ * UPDATE|PERM lock. The inode will be attached to both
* LOOKUP and PERM locks, so revoking either locks will
* case the dcache being cleared */
if (it->d.lustre.it_remote_lock_mode) {
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index 6cfdb9e4b74b..26003d3c1be7 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -155,11 +155,6 @@ void ll_free_sbi(struct super_block *sb)
}
}
-static struct dentry_operations ll_d_root_ops = {
- .d_compare = ll_dcompare,
- .d_revalidate = ll_revalidate_nd,
-};
-
static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
struct vfsmount *mnt)
{
@@ -211,7 +206,10 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
OBD_CONNECT_EINPROGRESS |
OBD_CONNECT_JOBSTATS | OBD_CONNECT_LVB_TYPE |
OBD_CONNECT_LAYOUTLOCK |
- OBD_CONNECT_PINGLESS | OBD_CONNECT_MAX_EASIZE;
+ OBD_CONNECT_PINGLESS |
+ OBD_CONNECT_MAX_EASIZE |
+ OBD_CONNECT_FLOCK_DEAD |
+ OBD_CONNECT_DISP_STRIPE;
if (sbi->ll_flags & LL_SBI_SOM_PREVIEW)
data->ocd_connect_flags |= OBD_CONNECT_SOM;
@@ -281,7 +279,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
/* For mount, we only need fs info from MDT0, and also in DNE, it
* can make sure the client can be mounted as long as MDT0 is
- * avaible */
+ * available */
err = obd_statfs(NULL, sbi->ll_md_exp, osfs,
cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
OBD_STATFS_FOR_MDT0);
@@ -579,10 +577,6 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
GOTO(out_root, err = -ENOMEM);
}
- /* kernel >= 2.6.38 store dentry operations in sb->s_d_op. */
- d_set_d_op(sb->s_root, &ll_d_root_ops);
- sb->s_d_op = &ll_d_ops;
-
sbi->ll_sdev_orig = sb->s_dev;
/* We set sb->s_dev equal on all lustre clients in order to support
@@ -723,7 +717,7 @@ void ll_kill_super(struct super_block *sb)
return;
sbi = ll_s2sbi(sb);
- /* we need restore s_dev from changed for clustred NFS before put_super
+ /* we need to restore s_dev from changed for clustered NFS before put_super
* because new kernels have cached s_dev and change sb->s_dev in
* put_super not affected real removing devices */
if (sbi) {
@@ -740,7 +734,8 @@ char *ll_read_opt(const char *opt, char *data)
CDEBUG(D_SUPER, "option: %s, data %s\n", opt, data);
if (strncmp(opt, data, strlen(opt)))
return NULL;
- if ((value = strchr(data, '=')) == NULL)
+ value = strchr(data, '=');
+ if (value == NULL)
return NULL;
value++;
@@ -1013,6 +1008,8 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt)
GOTO(out_free, err);
sb->s_bdi = &lsi->lsi_bdi;
+ /* kernel >= 2.6.38 store dentry operations in sb->s_d_op. */
+ sb->s_d_op = &ll_d_ops;
/* Generate a string unique to this super, in case some joker tries
to mount the same fs at two mount points.
@@ -1067,7 +1064,7 @@ out_free:
void ll_put_super(struct super_block *sb)
{
- struct config_llog_instance cfg;
+ struct config_llog_instance cfg, params_cfg;
struct obd_device *obd;
struct lustre_sb_info *lsi = s2lsi(sb);
struct ll_sb_info *sbi = ll_s2sbi(sb);
@@ -1081,6 +1078,9 @@ void ll_put_super(struct super_block *sb)
cfg.cfg_instance = sb;
lustre_end_log(sb, profilenm, &cfg);
+ params_cfg.cfg_instance = sb;
+ lustre_end_log(sb, PARAMS_FILENAME, &params_cfg);
+
if (sbi->ll_md_exp) {
obd = class_exp2obd(sbi->ll_md_exp);
if (obd)
@@ -1405,7 +1405,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import)
/* POSIX: check before ATTR_*TIME_SET set (from inode_change_ok) */
if (attr->ia_valid & TIMES_SET_FLAGS) {
if ((!uid_eq(current_fsuid(), inode->i_uid)) &&
- !cfs_capable(CFS_CAP_FOWNER))
+ !capable(CFS_CAP_FOWNER))
return -EPERM;
}
diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c
index caed6423e4ef..90b2c0d275f9 100644
--- a/drivers/staging/lustre/lustre/llite/llite_mmap.c
+++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c
@@ -285,7 +285,7 @@ static inline int to_fault_error(int result)
* Lustre implementation of a vm_operations_struct::fault() method, called by
* VM to server page fault (both in kernel and user space).
*
- * \param vma - is virtiual area struct related to page fault
+ * \param vma - is virtual area struct related to page fault
* \param vmf - structure which describe type and address where hit fault
*
* \return allocated and filled _locked_ page for address
@@ -370,7 +370,7 @@ restart:
goto restart;
}
- result |= VM_FAULT_LOCKED;
+ result = VM_FAULT_LOCKED;
}
cfs_restore_sigs(set);
return result;
diff --git a/drivers/staging/lustre/lustre/llite/llite_nfs.c b/drivers/staging/lustre/lustre/llite/llite_nfs.c
index 1767c741fb72..3580069789fc 100644
--- a/drivers/staging/lustre/lustre/llite/llite_nfs.c
+++ b/drivers/staging/lustre/lustre/llite/llite_nfs.c
@@ -167,10 +167,10 @@ ll_iget_for_nfs(struct super_block *sb, struct lu_fid *fid, struct lu_fid *paren
}
result = d_obtain_alias(inode);
- if (IS_ERR(result))
+ if (IS_ERR(result)) {
+ iput(inode);
return result;
-
- ll_dops_init(result, 1, 0);
+ }
return result;
}
diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c
index 0718905adeb2..f78eda235c7a 100644
--- a/drivers/staging/lustre/lustre/llite/lloop.c
+++ b/drivers/staging/lustre/lustre/llite/lloop.c
@@ -255,7 +255,7 @@ static int do_bio_lustrebacked(struct lloop_device *lo, struct bio *head)
* to store parity;
* 2. Reserve the # of (page_count * depth) cl_pages from the reserved
* pool. Afterwards, the clio would allocate the pages from reserved
- * pool, this guarantees we neeedn't allocate the cl_pages from
+ * pool, this guarantees we needn't allocate the cl_pages from
* generic cl_page slab cache.
* Of course, if there is NOT enough pages in the pool, we might
* be asked to write less pages once, this purely depends on
@@ -325,7 +325,7 @@ static unsigned int loop_get_bio(struct lloop_device *lo, struct bio **req)
bio = &(*bio)->bi_next;
}
if (*bio) {
- /* Some of bios can't be mergable. */
+ /* Some of bios can't be mergeable. */
lo->lo_bio = *bio;
*bio = NULL;
} else {
@@ -658,7 +658,7 @@ static struct block_device_operations lo_fops = {
* ll_iocontrol_call.
*
* This is a llite regular file ioctl function. It takes the responsibility
- * of attaching or detaching a file by a lloop's device numner.
+ * of attaching or detaching a file by a lloop's device number.
*/
static enum llioc_iter lloop_ioctl(struct inode *unused, struct file *file,
unsigned int cmd, unsigned long arg,
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index fc8d264f6c9a..25a6ea580f00 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -195,101 +195,107 @@ static void ll_invalidate_negative_children(struct inode *dir)
int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
void *data, int flag)
{
- int rc;
struct lustre_handle lockh;
+ int rc;
switch (flag) {
case LDLM_CB_BLOCKING:
ldlm_lock2handle(lock, &lockh);
rc = ldlm_cli_cancel(&lockh, LCF_ASYNC);
if (rc < 0) {
- CDEBUG(D_INODE, "ldlm_cli_cancel: %d\n", rc);
+ CDEBUG(D_INODE, "ldlm_cli_cancel: rc = %d\n", rc);
return rc;
}
break;
case LDLM_CB_CANCELING: {
struct inode *inode = ll_inode_from_resource_lock(lock);
- struct ll_inode_info *lli;
__u64 bits = lock->l_policy_data.l_inodebits.bits;
- struct lu_fid *fid;
- ldlm_mode_t mode = lock->l_req_mode;
/* Inode is set to lock->l_resource->lr_lvb_inode
* for mdc - bug 24555 */
LASSERT(lock->l_ast_data == NULL);
- /* Invalidate all dentries associated with this inode */
if (inode == NULL)
break;
+ /* Invalidate all dentries associated with this inode */
LASSERT(lock->l_flags & LDLM_FL_CANCELING);
- if (bits & MDS_INODELOCK_XATTR)
+ if (!fid_res_name_eq(ll_inode2fid(inode),
+ &lock->l_resource->lr_name)) {
+ LDLM_ERROR(lock, "data mismatch with object "DFID"(%p)",
+ PFID(ll_inode2fid(inode)), inode);
+ LBUG();
+ }
+
+ if (bits & MDS_INODELOCK_XATTR) {
ll_xattr_cache_destroy(inode);
+ bits &= ~MDS_INODELOCK_XATTR;
+ }
/* For OPEN locks we differentiate between lock modes
* LCK_CR, LCK_CW, LCK_PR - bug 22891 */
- if (bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_UPDATE |
- MDS_INODELOCK_LAYOUT | MDS_INODELOCK_PERM))
- ll_have_md_lock(inode, &bits, LCK_MINMODE);
-
if (bits & MDS_INODELOCK_OPEN)
- ll_have_md_lock(inode, &bits, mode);
-
- fid = ll_inode2fid(inode);
- if (!fid_res_name_eq(fid, &lock->l_resource->lr_name))
- LDLM_ERROR(lock, "data mismatch with object "
- DFID" (%p)", PFID(fid), inode);
+ ll_have_md_lock(inode, &bits, lock->l_req_mode);
if (bits & MDS_INODELOCK_OPEN) {
- int flags = 0;
+ fmode_t fmode;
+
switch (lock->l_req_mode) {
case LCK_CW:
- flags = FMODE_WRITE;
+ fmode = FMODE_WRITE;
break;
case LCK_PR:
- flags = FMODE_EXEC;
+ fmode = FMODE_EXEC;
break;
case LCK_CR:
- flags = FMODE_READ;
+ fmode = FMODE_READ;
break;
default:
- CERROR("Unexpected lock mode for OPEN lock "
- "%d, inode %ld\n", lock->l_req_mode,
- inode->i_ino);
+ LDLM_ERROR(lock, "bad lock mode for OPEN lock");
+ LBUG();
}
- ll_md_real_close(inode, flags);
+
+ ll_md_real_close(inode, fmode);
}
- lli = ll_i2info(inode);
+ if (bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_UPDATE |
+ MDS_INODELOCK_LAYOUT | MDS_INODELOCK_PERM))
+ ll_have_md_lock(inode, &bits, LCK_MINMODE);
+
if (bits & MDS_INODELOCK_LAYOUT) {
- struct cl_object_conf conf = { { 0 } };
+ struct cl_object_conf conf = {
+ .coc_opc = OBJECT_CONF_INVALIDATE,
+ .coc_inode = inode,
+ };
- conf.coc_opc = OBJECT_CONF_INVALIDATE;
- conf.coc_inode = inode;
rc = ll_layout_conf(inode, &conf);
- if (rc)
- CDEBUG(D_INODE, "invaliding layout %d.\n", rc);
+ if (rc < 0)
+ CDEBUG(D_INODE, "cannot invalidate layout of "
+ DFID": rc = %d\n",
+ PFID(ll_inode2fid(inode)), rc);
}
if (bits & MDS_INODELOCK_UPDATE) {
+ struct ll_inode_info *lli = ll_i2info(inode);
+
spin_lock(&lli->lli_lock);
lli->lli_flags &= ~LLIF_MDS_SIZE_LOCK;
spin_unlock(&lli->lli_lock);
}
- if (S_ISDIR(inode->i_mode) &&
- (bits & MDS_INODELOCK_UPDATE)) {
+ if ((bits & MDS_INODELOCK_UPDATE) && S_ISDIR(inode->i_mode)) {
CDEBUG(D_INODE, "invalidating inode %lu\n",
inode->i_ino);
truncate_inode_pages(inode->i_mapping, 0);
ll_invalidate_negative_children(inode);
}
- if (inode->i_sb->s_root &&
- inode != inode->i_sb->s_root->d_inode &&
- (bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM)))
+ if ((bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM)) &&
+ inode->i_sb->s_root != NULL &&
+ inode != inode->i_sb->s_root->d_inode)
ll_invalidate_aliases(inode);
+
iput(inode);
break;
}
@@ -400,11 +406,16 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry)
struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de)
{
struct dentry *new;
+ int rc;
if (inode) {
new = ll_find_alias(inode, de);
if (new) {
- ll_dops_init(new, 1, 1);
+ rc = ll_d_init(new);
+ if (rc < 0) {
+ dput(new);
+ return ERR_PTR(rc);
+ }
d_move(new, de);
iput(inode);
CDEBUG(D_DENTRY,
@@ -413,8 +424,9 @@ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de)
return new;
}
}
- ll_dops_init(de, 1, 1);
- __d_lustre_invalidate(de);
+ rc = ll_d_init(de);
+ if (rc < 0)
+ return ERR_PTR(rc);
d_add(de, inode);
CDEBUG(D_DENTRY, "Add dentry %p inode %p refc %d flags %#x\n",
de, de->d_inode, d_count(de), de->d_flags);
@@ -453,10 +465,22 @@ int ll_lookup_it_finish(struct ptlrpc_request *request,
}
/* Only hash *de if it is unhashed (new dentry).
- * Atoimc_open may passin hashed dentries for open.
+ * Atoimc_open may passing hashed dentries for open.
*/
- if (d_unhashed(*de))
- *de = ll_splice_alias(inode, *de);
+ if (d_unhashed(*de)) {
+ struct dentry *alias;
+
+ alias = ll_splice_alias(inode, *de);
+ if (IS_ERR(alias))
+ return PTR_ERR(alias);
+ *de = alias;
+ } else if (!it_disposition(it, DISP_LOOKUP_NEG) &&
+ !it_disposition(it, DISP_OPEN_CREATE)) {
+ /* With DISP_OPEN_CREATE dentry will
+ instantiated in ll_create_it. */
+ LASSERT((*de)->d_inode == NULL);
+ d_instantiate(*de, inode);
+ }
if (!it_disposition(it, DISP_LOOKUP_NEG)) {
/* we have lookup look - unhide dentry */
@@ -505,16 +529,6 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
ll_frob_intent(&it, &lookup_it);
- /* As do_lookup is called before follow_mount, root dentry may be left
- * not valid, revalidate it here. */
- if (parent->i_sb->s_root && (parent->i_sb->s_root->d_inode == parent) &&
- (it->it_op & (IT_OPEN | IT_CREAT))) {
- rc = ll_inode_revalidate_it(parent->i_sb->s_root, it,
- MDS_INODELOCK_LOOKUP);
- if (rc)
- return ERR_PTR(rc);
- }
-
if (it->it_op == IT_GETATTR) {
rc = ll_statahead_enter(parent, &dentry, 0);
if (rc == 1) {
@@ -584,12 +598,8 @@ static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
parent->i_generation, parent, flags);
/* Optimize away (CREATE && !OPEN). Let .create handle the race. */
- if ((flags & LOOKUP_CREATE ) && !(flags & LOOKUP_OPEN)) {
- ll_dops_init(dentry, 1, 1);
- __d_lustre_invalidate(dentry);
- d_add(dentry, NULL);
+ if ((flags & LOOKUP_CREATE) && !(flags & LOOKUP_OPEN))
return NULL;
- }
if (flags & (LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE))
itp = NULL;
diff --git a/drivers/staging/lustre/lustre/llite/rw.c b/drivers/staging/lustre/lustre/llite/rw.c
index e9ba38a553cf..416f7a094a6d 100644
--- a/drivers/staging/lustre/lustre/llite/rw.c
+++ b/drivers/staging/lustre/lustre/llite/rw.c
@@ -135,7 +135,7 @@ static struct ll_cl_context *ll_cl_init(struct file *file,
}
/*
- * Loop-back driver calls ->prepare_write() and ->sendfile()
+ * Loop-back driver calls ->prepare_write().
* methods directly, bypassing file system ->write() operation,
* so cl_io has to be created here.
*/
@@ -558,10 +558,10 @@ static int ll_read_ahead_page(const struct lu_env *env, struct cl_io *io,
* striped over, rather than having a constant value for all files here. */
/* RAS_INCREASE_STEP should be (1UL << (inode->i_blkbits - PAGE_CACHE_SHIFT)).
- * Temprarily set RAS_INCREASE_STEP to 1MB. After 4MB RPC is enabled
+ * Temporarily set RAS_INCREASE_STEP to 1MB. After 4MB RPC is enabled
* by default, this should be adjusted corresponding with max_read_ahead_mb
* and max_read_ahead_per_file_mb otherwise the readahead budget can be used
- * up quickly which will affect read performance siginificantly. See LU-2816 */
+ * up quickly which will affect read performance significantly. See LU-2816 */
#define RAS_INCREASE_STEP(inode) (ONE_MB_BRW_SIZE >> PAGE_CACHE_SHIFT)
static inline int stride_io_mode(struct ll_readahead_state *ras)
@@ -570,7 +570,7 @@ static inline int stride_io_mode(struct ll_readahead_state *ras)
}
/* The function calculates how much pages will be read in
* [off, off + length], in such stride IO area,
- * stride_offset = st_off, stride_lengh = st_len,
+ * stride_offset = st_off, stride_length = st_len,
* stride_pages = st_pgs
*
* |------------------|*****|------------------|*****|------------|*****|....
@@ -1090,7 +1090,7 @@ void ras_update(struct ll_sb_info *sbi, struct inode *inode,
ras_set_start(inode, ras, index);
if (stride_io_mode(ras))
- /* Since stride readahead is sentivite to the offset
+ /* Since stride readahead is sensitive to the offset
* of read-ahead, so we use original offset here,
* instead of ras_window_start, which is RPC aligned */
ras->ras_next_readahead = max(index, ras->ras_next_readahead);
diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c
index f6b5f4b95f37..c8624b5a9875 100644
--- a/drivers/staging/lustre/lustre/llite/statahead.c
+++ b/drivers/staging/lustre/lustre/llite/statahead.c
@@ -577,7 +577,7 @@ static void ll_agl_trigger(struct inode *inode, struct ll_statahead_info *sai)
* Someone triggered glimpse within 1 sec before.
* 1) The former glimpse succeeded with glimpse lock granted by OST, and
* if the lock is still cached on client, AGL needs to do nothing. If
- * it is cancelled by other client, AGL maybe cannot obtaion new lock
+ * it is cancelled by other client, AGL maybe cannot obtain new lock
* for no glimpse callback triggered by AGL.
* 2) The former glimpse succeeded, but OST did not grant glimpse lock.
* Under such case, it is quite possible that the OST will not grant
@@ -877,9 +877,6 @@ static int do_sa_revalidate(struct inode *dir, struct ll_sa_entry *entry,
if (d_mountpoint(dentry))
return 1;
- if (unlikely(dentry == dentry->d_sb->s_root))
- return 1;
-
entry->se_inode = igrab(inode);
rc = md_revalidate_lock(ll_i2mdexp(dir), &it, ll_inode2fid(inode),NULL);
if (rc == 1) {
@@ -1588,8 +1585,15 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp,
ll_inode2fid(inode), &bits);
if (rc == 1) {
if ((*dentryp)->d_inode == NULL) {
- *dentryp = ll_splice_alias(inode,
+ struct dentry *alias;
+
+ alias = ll_splice_alias(inode,
*dentryp);
+ if (IS_ERR(alias)) {
+ ll_sai_unplug(sai, entry);
+ return PTR_ERR(alias);
+ }
+ *dentryp = alias;
} else if ((*dentryp)->d_inode != inode) {
/* revalidate, but inode is recreated */
CDEBUG(D_READA,
diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c
index 93cbfbb7e7f7..c7d70091246e 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_io.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_io.c
@@ -51,7 +51,7 @@ static struct vvp_io *cl2vvp_io(const struct lu_env *env,
const struct cl_io_slice *slice);
/**
- * True, if \a io is a normal io, False for sendfile() / splice_{read|write}
+ * True, if \a io is a normal io, False for splice_{read,write}
*/
int cl_is_normalio(const struct lu_env *env, const struct cl_io *io)
{
@@ -474,20 +474,6 @@ static void vvp_io_setattr_fini(const struct lu_env *env,
vvp_io_fini(env, ios);
}
-static ssize_t lustre_generic_file_read(struct file *file,
- struct ccc_io *vio, loff_t *ppos)
-{
- return generic_file_aio_read(vio->cui_iocb, vio->cui_iov,
- vio->cui_nrsegs, *ppos);
-}
-
-static ssize_t lustre_generic_file_write(struct file *file,
- struct ccc_io *vio, loff_t *ppos)
-{
- return generic_file_aio_write(vio->cui_iocb, vio->cui_iov,
- vio->cui_nrsegs, *ppos);
-}
-
static int vvp_io_read_start(const struct lu_env *env,
const struct cl_io_slice *ios)
{
@@ -540,8 +526,11 @@ static int vvp_io_read_start(const struct lu_env *env,
file_accessed(file);
switch (vio->cui_io_subtype) {
case IO_NORMAL:
- result = lustre_generic_file_read(file, cio, &pos);
- break;
+ LASSERT(cio->cui_iocb->ki_pos == pos);
+ result = generic_file_aio_read(cio->cui_iocb,
+ cio->cui_iov, cio->cui_nrsegs,
+ cio->cui_iocb->ki_pos);
+ break;
case IO_SPLICE:
result = generic_file_splice_read(file, &pos,
vio->u.splice.cui_pipe, cnt,
@@ -586,7 +575,6 @@ static int vvp_io_write_start(const struct lu_env *env,
struct cl_io *io = ios->cis_io;
struct cl_object *obj = io->ci_obj;
struct inode *inode = ccc_object_inode(obj);
- struct file *file = cio->cui_fd->fd_file;
ssize_t result = 0;
loff_t pos = io->u.ci_wr.wr.crw_pos;
size_t cnt = io->u.ci_wr.wr.crw_count;
@@ -601,6 +589,8 @@ static int vvp_io_write_start(const struct lu_env *env,
*/
pos = io->u.ci_wr.wr.crw_pos = i_size_read(inode);
cio->cui_iocb->ki_pos = pos;
+ } else {
+ LASSERT(cio->cui_iocb->ki_pos == pos);
}
CDEBUG(D_VFSTRACE, "write: [%lli, %lli)\n", pos, pos + (long long)cnt);
@@ -608,8 +598,9 @@ static int vvp_io_write_start(const struct lu_env *env,
if (cio->cui_iov == NULL) /* from a temp io in ll_cl_init(). */
result = 0;
else
- result = lustre_generic_file_write(file, cio, &pos);
-
+ result = generic_file_aio_write(cio->cui_iocb,
+ cio->cui_iov, cio->cui_nrsegs,
+ cio->cui_iocb->ki_pos);
if (result > 0) {
if (result < cnt)
io->ci_continue = 0;
@@ -655,7 +646,7 @@ static int vvp_io_kernel_fault(struct vvp_fault_io *cfio)
if (cfio->fault.ft_flags & VM_FAULT_RETRY)
return -EAGAIN;
- CERROR("unknow error in page fault %d!\n", cfio->fault.ft_flags);
+ CERROR("Unknown error in page fault %d!\n", cfio->fault.ft_flags);
return -EINVAL;
}
@@ -1201,7 +1192,7 @@ int vvp_io_init(const struct lu_env *env, struct cl_object *obj,
if (result == -ENOENT)
/* If the inode on MDS has been removed, but the objects
* on OSTs haven't been destroyed (async unlink), layout
- * fetch will return -ENOENT, we'd ingore this error
+ * fetch will return -ENOENT, we'd ignore this error
* and continue with dirty flush. LU-3230. */
result = 0;
if (result < 0)
@@ -1216,7 +1207,7 @@ int vvp_io_init(const struct lu_env *env, struct cl_object *obj,
static struct vvp_io *cl2vvp_io(const struct lu_env *env,
const struct cl_io_slice *slice)
{
- /* Caling just for assertion */
+ /* Calling just for assertion */
cl2ccc_io(env, slice);
return vvp_env_io(env);
}
diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c
index 3a7d03c12dd9..b1ed4d9ea6be 100644
--- a/drivers/staging/lustre/lustre/llite/xattr.c
+++ b/drivers/staging/lustre/lustre/llite/xattr.c
@@ -95,7 +95,7 @@ int xattr_type_filter(struct ll_sb_info *sbi, int xattr_type)
if (xattr_type == XATTR_USER_T && !(sbi->ll_flags & LL_SBI_USER_XATTR))
return -EOPNOTSUPP;
- if (xattr_type == XATTR_TRUSTED_T && !cfs_capable(CFS_CAP_SYS_ADMIN))
+ if (xattr_type == XATTR_TRUSTED_T && !capable(CFS_CAP_SYS_ADMIN))
return -EPERM;
if (xattr_type == XATTR_OTHER_T)
return -EOPNOTSUPP;
@@ -183,17 +183,11 @@ int ll_setxattr_common(struct inode *inode, const char *name,
valid |= rce_ops2valid(rce->rce_ops);
}
#endif
- if (sbi->ll_xattr_cache_enabled &&
- (rce == NULL || rce->rce_ops == RMT_LSETFACL)) {
- rc = ll_xattr_cache_update(inode, name, pv, size, valid, flags);
- } else {
oc = ll_mdscapa_get(inode);
rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc,
valid, name, pv, size, 0, flags,
ll_i2suppgid(inode), &req);
capa_put(oc);
- }
-
#ifdef CONFIG_FS_POSIX_ACL
if (new_value != NULL)
lustre_posix_acl_xattr_free(new_value, size);
@@ -292,6 +286,7 @@ int ll_getxattr_common(struct inode *inode, const char *name,
void *xdata;
struct obd_capa *oc;
struct rmtacl_ctl_entry *rce = NULL;
+ struct ll_inode_info *lli = ll_i2info(inode);
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n",
inode->i_ino, inode->i_generation, inode);
@@ -339,7 +334,7 @@ int ll_getxattr_common(struct inode *inode, const char *name,
*/
if (xattr_type == XATTR_ACL_ACCESS_T &&
!(sbi->ll_flags & LL_SBI_RMT_CLIENT)) {
- struct ll_inode_info *lli = ll_i2info(inode);
+
struct posix_acl *acl;
spin_lock(&lli->lli_lock);
@@ -358,13 +353,27 @@ int ll_getxattr_common(struct inode *inode, const char *name,
#endif
do_getxattr:
- if (sbi->ll_xattr_cache_enabled && (rce == NULL ||
- rce->rce_ops == RMT_LGETFACL ||
- rce->rce_ops == RMT_LSETFACL)) {
+ if (sbi->ll_xattr_cache_enabled && xattr_type != XATTR_ACL_ACCESS_T) {
rc = ll_xattr_cache_get(inode, name, buffer, size, valid);
+ if (rc == -EAGAIN)
+ goto getxattr_nocache;
if (rc < 0)
GOTO(out_xattr, rc);
+
+ /* Add "system.posix_acl_access" to the list */
+ if (lli->lli_posix_acl != NULL && valid & OBD_MD_FLXATTRLS) {
+ if (size == 0) {
+ rc += sizeof(XATTR_NAME_ACL_ACCESS);
+ } else if (size - rc >= sizeof(XATTR_NAME_ACL_ACCESS)) {
+ memcpy(buffer + rc, XATTR_NAME_ACL_ACCESS,
+ sizeof(XATTR_NAME_ACL_ACCESS));
+ rc += sizeof(XATTR_NAME_ACL_ACCESS);
+ } else {
+ GOTO(out_xattr, rc = -ERANGE);
+ }
+ }
} else {
+getxattr_nocache:
oc = ll_mdscapa_get(inode);
rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc,
valid | (rce ? rce_ops2valid(rce->rce_ops) : 0),
diff --git a/drivers/staging/lustre/lustre/llite/xattr_cache.c b/drivers/staging/lustre/lustre/llite/xattr_cache.c
index 3e3be1f13502..4defa2fd83b3 100644
--- a/drivers/staging/lustre/lustre/llite/xattr_cache.c
+++ b/drivers/staging/lustre/lustre/llite/xattr_cache.c
@@ -98,13 +98,13 @@ static int ll_xattr_cache_find(struct list_head *cache,
}
/**
- * This adds or updates an xattr.
+ * This adds an xattr.
*
* Add @xattr_name attr with @xattr_val value and @xattr_val_len length,
- * if the attribute already exists, then update its value.
*
* \retval 0 success
* \retval -ENOMEM if no memory could be allocated for the cached attr
+ * \retval -EPROTO if duplicate xattr is being added
*/
static int ll_xattr_cache_add(struct list_head *cache,
const char *xattr_name,
@@ -116,27 +116,8 @@ static int ll_xattr_cache_add(struct list_head *cache,
if (ll_xattr_cache_find(cache, xattr_name, &xattr) == 0) {
- /* Found a cached EA, update it */
-
- if (xattr_val_len != xattr->xe_vallen) {
- char *val;
- OBD_ALLOC(val, xattr_val_len);
- if (val == NULL) {
- CDEBUG(D_CACHE,
- "failed to allocate %u bytes for xattr %s update\n",
- xattr_val_len, xattr_name);
- return -ENOMEM;
- }
- OBD_FREE(xattr->xe_value, xattr->xe_vallen);
- xattr->xe_value = val;
- xattr->xe_vallen = xattr_val_len;
- }
- memcpy(xattr->xe_value, xattr_val, xattr_val_len);
-
- CDEBUG(D_CACHE, "update: [%s]=%.*s\n", xattr_name,
- xattr_val_len, xattr_val);
-
- return 0;
+ CDEBUG(D_CACHE, "duplicate xattr: [%s]\n", xattr_name);
+ return -EPROTO;
}
OBD_SLAB_ALLOC_PTR_GFP(xattr, xattr_kmem, __GFP_IO);
@@ -261,7 +242,7 @@ int ll_xattr_cache_valid(struct ll_inode_info *lli)
*
* Free all xattr memory. @lli is the inode info pointer.
*
- * \retval 0 no error occured
+ * \retval 0 no error occurred
*/
static int ll_xattr_cache_destroy_locked(struct ll_inode_info *lli)
{
@@ -292,14 +273,14 @@ int ll_xattr_cache_destroy(struct inode *inode)
}
/**
- * Match or enqueue a PR or PW LDLM lock.
+ * Match or enqueue a PR lock.
*
* Find or request an LDLM lock with xattr data.
* Since LDLM does not provide API for atomic match_or_enqueue,
* the function handles it with a separate enq lock.
* If successful, the function exits with the list lock held.
*
- * \retval 0 no error occured
+ * \retval 0 no error occurred
* \retval -ENOMEM not enough memory
*/
static int ll_xattr_find_get_lock(struct inode *inode,
@@ -322,9 +303,7 @@ static int ll_xattr_find_get_lock(struct inode *inode,
mutex_lock(&lli->lli_xattrs_enq_lock);
/* Try matching first. */
- mode = ll_take_md_lock(inode, MDS_INODELOCK_XATTR, &lockh, 0,
- oit->it_op == IT_SETXATTR ? LCK_PW :
- (LCK_PR | LCK_PW));
+ mode = ll_take_md_lock(inode, MDS_INODELOCK_XATTR, &lockh, 0, LCK_PR);
if (mode != 0) {
/* fake oit in mdc_revalidate_lock() manner */
oit->d.lustre.it_lock_handle = lockh.cookie;
@@ -340,13 +319,7 @@ static int ll_xattr_find_get_lock(struct inode *inode,
return PTR_ERR(op_data);
}
- op_data->op_valid = OBD_MD_FLXATTR | OBD_MD_FLXATTRLS |
- OBD_MD_FLXATTRLOCKED;
-#ifdef CONFIG_FS_POSIX_ACL
- /* If working with ACLs, we would like to cache local ACLs */
- if (sbi->ll_flags & LL_SBI_RMT_CLIENT)
- op_data->op_valid |= OBD_MD_FLRMTLGETFACL;
-#endif
+ op_data->op_valid = OBD_MD_FLXATTR | OBD_MD_FLXATTRLS;
rc = md_enqueue(exp, &einfo, oit, op_data, &lockh, NULL, 0, NULL, 0);
ll_finish_md_op_data(op_data);
@@ -374,7 +347,7 @@ out:
* a read or a write xattr lock depending on operation in @oit.
* Intent is dropped on exit unless the operation is setxattr.
*
- * \retval 0 no error occured
+ * \retval 0 no error occurred
* \retval -EPROTO network protocol error
* \retval -ENOMEM not enough memory for the cache
*/
@@ -409,7 +382,11 @@ static int ll_xattr_cache_refill(struct inode *inode, struct lookup_intent *oit)
if (oit->d.lustre.it_status < 0) {
CDEBUG(D_CACHE, "getxattr intent returned %d for fid "DFID"\n",
oit->d.lustre.it_status, PFID(ll_inode2fid(inode)));
- GOTO(out_destroy, rc = oit->d.lustre.it_status);
+ rc = oit->d.lustre.it_status;
+ /* xattr data is so large that we don't want to cache it */
+ if (rc == -ERANGE)
+ rc = -EAGAIN;
+ GOTO(out_destroy, rc);
}
body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
@@ -447,6 +424,11 @@ static int ll_xattr_cache_refill(struct inode *inode, struct lookup_intent *oit)
rc = -EPROTO;
} else if (OBD_FAIL_CHECK(OBD_FAIL_LLITE_XATTR_ENOMEM)) {
rc = -ENOMEM;
+ } else if (!strcmp(xdata, XATTR_NAME_ACL_ACCESS)) {
+ /* Filter out ACL ACCESS since it's cached separately */
+ CDEBUG(D_CACHE, "not caching %s\n",
+ XATTR_NAME_ACL_ACCESS);
+ rc = 0;
} else {
rc = ll_xattr_cache_add(&lli->lli_xattrs, xdata, xval,
*xsizes);
@@ -467,8 +449,7 @@ static int ll_xattr_cache_refill(struct inode *inode, struct lookup_intent *oit)
GOTO(out_maybe_drop, rc);
out_maybe_drop:
- /* drop lock on error or getxattr */
- if (rc != 0 || oit->it_op != IT_SETXATTR)
+
ll_intent_drop_lock(oit);
if (rc != 0)
@@ -496,7 +477,7 @@ out_destroy:
* The resulting value/list is stored in @buffer if the former
* is not larger than @size.
*
- * \retval 0 no error occured
+ * \retval 0 no error occurred
* \retval -EPROTO network protocol error
* \retval -ENOMEM not enough memory for the cache
* \retval -ERANGE the buffer is not large enough
@@ -553,65 +534,3 @@ out:
return rc;
}
-
-
-/**
- * Set/update an xattr value or remove xattr using the write-through cache.
- *
- * Set/update the xattr value (if @valid has OBD_MD_FLXATTR) of @name to @newval
- * or
- * remove the xattr @name (@valid has OBD_MD_FLXATTRRM set) from @inode.
- * @flags is either XATTR_CREATE or XATTR_REPLACE as defined by setxattr(2)
- *
- * \retval 0 no error occured
- * \retval -EPROTO network protocol error
- * \retval -ENOMEM not enough memory for the cache
- * \retval -ERANGE the buffer is not large enough
- * \retval -ENODATA no such attr (in the removal case)
- */
-int ll_xattr_cache_update(struct inode *inode,
- const char *name,
- const char *newval,
- size_t size,
- __u64 valid,
- int flags)
-{
- struct lookup_intent oit = { .it_op = IT_SETXATTR };
- struct ll_sb_info *sbi = ll_i2sbi(inode);
- struct ptlrpc_request *req = NULL;
- struct ll_inode_info *lli = ll_i2info(inode);
- struct obd_capa *oc;
- int rc;
-
-
-
- LASSERT(!!(valid & OBD_MD_FLXATTR) ^ !!(valid & OBD_MD_FLXATTRRM));
-
- rc = ll_xattr_cache_refill(inode, &oit);
- if (rc)
- return rc;
-
- oc = ll_mdscapa_get(inode);
- rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc,
- valid | OBD_MD_FLXATTRLOCKED, name, newval,
- size, 0, flags, ll_i2suppgid(inode), &req);
- capa_put(oc);
-
- if (rc) {
- ll_intent_drop_lock(&oit);
- GOTO(out, rc);
- }
-
- if (valid & OBD_MD_FLXATTR)
- rc = ll_xattr_cache_add(&lli->lli_xattrs, name, newval, size);
- else if (valid & OBD_MD_FLXATTRRM)
- rc = ll_xattr_cache_del(&lli->lli_xattrs, name);
-
- ll_intent_drop_lock(&oit);
- GOTO(out, rc);
-out:
- up_write(&lli->lli_xattrs_list_rwsem);
- ptlrpc_req_finished(req);
-
- return rc;
-}
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_intent.c b/drivers/staging/lustre/lustre/lmv/lmv_intent.c
index 56dedceaf0a0..9ba5a0a57390 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_intent.c
+++ b/drivers/staging/lustre/lustre/lmv/lmv_intent.c
@@ -119,7 +119,6 @@ static int lmv_intent_remote(struct obd_export *exp, void *lmm,
CDEBUG(D_INODE, "REMOTE_INTENT with fid="DFID" -> mds #%d\n",
PFID(&body->fid1), tgt->ltd_idx);
- it->d.lustre.it_disposition &= ~DISP_ENQ_COMPLETE;
rc = md_intent_lock(tgt->ltd_exp, op_data, lmm, lmmsize, it,
flags, &req, cb_blocking, extra_lock_flags);
if (rc)
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
index 1bddd8f62fbf..3ba0a0a1d945 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c
+++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
@@ -1744,7 +1744,6 @@ lmv_enqueue_remote(struct obd_export *exp, struct ldlm_enqueue_info *einfo,
it->d.lustre.it_data = NULL;
fid1 = body->fid1;
- it->d.lustre.it_disposition &= ~DISP_ENQ_COMPLETE;
ptlrpc_req_finished(req);
tgt = lmv_find_target(lmv, &fid1);
@@ -2593,7 +2592,7 @@ int lmv_free_lustre_md(struct obd_export *exp, struct lustre_md *md)
int lmv_set_open_replay_data(struct obd_export *exp,
struct obd_client_handle *och,
- struct ptlrpc_request *open_req)
+ struct lookup_intent *it)
{
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
@@ -2603,7 +2602,7 @@ int lmv_set_open_replay_data(struct obd_export *exp,
if (IS_ERR(tgt))
return PTR_ERR(tgt);
- return md_set_open_replay_data(tgt->ltd_exp, och, open_req);
+ return md_set_open_replay_data(tgt->ltd_exp, och, it);
}
int lmv_clear_open_replay_data(struct obd_export *exp,
diff --git a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
index b355d01410e4..5d5c3081c467 100644
--- a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
+++ b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
@@ -87,8 +87,9 @@ static int lmv_placement_seq_show(struct seq_file *m, void *v)
#define MAX_POLICY_STRING_SIZE 64
-static ssize_t lmv_placement_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t lmv_placement_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
char dummy[MAX_POLICY_STRING_SIZE + 1];
diff --git a/drivers/staging/lustre/lustre/lov/lov_ea.c b/drivers/staging/lustre/lustre/lov/lov_ea.c
index e6c60151dc65..6f356e025543 100644
--- a/drivers/staging/lustre/lustre/lov/lov_ea.c
+++ b/drivers/staging/lustre/lustre/lov/lov_ea.c
@@ -98,7 +98,7 @@ struct lov_stripe_md *lsm_alloc_plain(__u16 stripe_count, int *size)
OBD_ALLOC_LARGE(lsm, *size);
if (!lsm)
- return NULL;;
+ return NULL;
for (i = 0; i < stripe_count; i++) {
OBD_SLAB_ALLOC_PTR_GFP(loi, lov_oinfo_slab, __GFP_IO);
diff --git a/drivers/staging/lustre/lustre/lov/lov_io.c b/drivers/staging/lustre/lustre/lov/lov_io.c
index 5a6ab70ed0a1..65133ea308b6 100644
--- a/drivers/staging/lustre/lustre/lov/lov_io.c
+++ b/drivers/staging/lustre/lustre/lov/lov_io.c
@@ -194,6 +194,7 @@ static int lov_io_sub_init(const struct lu_env *env, struct lov_io *lio,
sub_io->ci_lockreq = io->ci_lockreq;
sub_io->ci_type = io->ci_type;
sub_io->ci_no_srvlock = io->ci_no_srvlock;
+ sub_io->ci_noatime = io->ci_noatime;
lov_sub_enter(sub);
result = cl_io_sub_init(sub->sub_env, sub_io,
diff --git a/drivers/staging/lustre/lustre/lov/lov_obd.c b/drivers/staging/lustre/lustre/lov/lov_obd.c
index 50a77c5ef69a..02509d0cb106 100644
--- a/drivers/staging/lustre/lustre/lov/lov_obd.c
+++ b/drivers/staging/lustre/lustre/lov/lov_obd.c
@@ -339,7 +339,7 @@ static int lov_disconnect(struct obd_export *exp)
for (i = 0; i < lov->desc.ld_tgt_count; i++) {
if (lov->lov_tgts[i] && lov->lov_tgts[i]->ltd_exp) {
/* Disconnection is the last we know about an obd */
- lov_del_target(obd, i, 0, lov->lov_tgts[i]->ltd_gen);
+ lov_del_target(obd, i, NULL, lov->lov_tgts[i]->ltd_gen);
}
}
obd_putref(obd);
@@ -644,7 +644,7 @@ out:
if (rc) {
CERROR("add failed (%d), deleting %s\n", rc,
obd_uuid2str(&tgt->ltd_uuid));
- lov_del_target(obd, index, 0, 0);
+ lov_del_target(obd, index, NULL, 0);
}
obd_putref(obd);
return rc;
@@ -768,7 +768,7 @@ void lov_fix_desc(struct lov_desc *desc)
int lov_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
{
- struct lprocfs_static_vars lvars = { 0 };
+ struct lprocfs_static_vars lvars = { NULL };
struct lov_desc *desc;
struct lov_obd *lov = &obd->u.lov;
int rc;
diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c
index df8b5b5b7cf4..d6b2cb45b938 100644
--- a/drivers/staging/lustre/lustre/lov/lov_object.c
+++ b/drivers/staging/lustre/lustre/lov/lov_object.c
@@ -122,8 +122,8 @@ static struct cl_object *lov_sub_find(const struct lu_env *env,
}
static int lov_init_sub(const struct lu_env *env, struct lov_object *lov,
- struct cl_object *stripe,
- struct lov_layout_raid0 *r0, int idx)
+ struct cl_object *stripe, struct lov_layout_raid0 *r0,
+ int idx)
{
struct cl_object_header *hdr;
struct cl_object_header *subhdr;
@@ -144,7 +144,6 @@ static int lov_init_sub(const struct lu_env *env, struct lov_object *lov,
hdr = cl_object_header(lov2cl(lov));
subhdr = cl_object_header(stripe);
- parent = subhdr->coh_parent;
oinfo = lov->lo_lsm->lsm_oinfo[idx];
CDEBUG(D_INODE, DFID"@%p[%d] -> "DFID"@%p: ostid: "DOSTID
@@ -153,8 +152,12 @@ static int lov_init_sub(const struct lu_env *env, struct lov_object *lov,
PFID(&hdr->coh_lu.loh_fid), hdr, POSTID(&oinfo->loi_oi),
oinfo->loi_ost_idx, oinfo->loi_ost_gen);
+ /* reuse ->coh_attr_guard to protect coh_parent change */
+ spin_lock(&subhdr->coh_attr_guard);
+ parent = subhdr->coh_parent;
if (parent == NULL) {
subhdr->coh_parent = hdr;
+ spin_unlock(&subhdr->coh_attr_guard);
subhdr->coh_nesting = hdr->coh_nesting + 1;
lu_object_ref_add(&stripe->co_lu, "lov-parent", lov);
r0->lo_sub[idx] = cl2lovsub(stripe);
@@ -166,6 +169,7 @@ static int lov_init_sub(const struct lu_env *env, struct lov_object *lov,
struct lov_object *old_lov;
unsigned int mask = D_INODE;
+ spin_unlock(&subhdr->coh_attr_guard);
old_obj = lu_object_locate(&parent->coh_lu, &lov_device_type);
LASSERT(old_obj != NULL);
old_lov = cl2lov(lu2cl(old_obj));
@@ -306,7 +310,7 @@ static void lov_subobject_kill(const struct lu_env *env, struct lov_object *lov,
* ->lo_sub[] slot in lovsub_object_fini() */
if (r0->lo_sub[idx] == los) {
waiter = &lov_env_info(env)->lti_waiter;
- init_waitqueue_entry_current(waiter);
+ init_waitqueue_entry(waiter, current);
add_wait_queue(&bkt->lsb_marche_funebre, waiter);
set_current_state(TASK_UNINTERRUPTIBLE);
while (1) {
@@ -316,7 +320,7 @@ static void lov_subobject_kill(const struct lu_env *env, struct lov_object *lov,
spin_lock(&r0->lo_sub_lock);
if (r0->lo_sub[idx] == los) {
spin_unlock(&r0->lo_sub_lock);
- waitq_wait(waiter, TASK_UNINTERRUPTIBLE);
+ schedule();
} else {
spin_unlock(&r0->lo_sub_lock);
set_current_state(TASK_RUNNING);
@@ -508,7 +512,7 @@ static int lov_attr_get_raid0(const struct lu_env *env, struct cl_object *obj,
return result;
}
-const static struct lov_layout_operations lov_dispatch[] = {
+static const struct lov_layout_operations lov_dispatch[] = {
[LLT_EMPTY] = {
.llo_init = lov_init_empty,
.llo_delete = lov_delete_empty,
diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c
index 27ed27e6fa6a..74200cf1b331 100644
--- a/drivers/staging/lustre/lustre/lov/lov_pack.c
+++ b/drivers/staging/lustre/lustre/lov/lov_pack.c
@@ -339,7 +339,8 @@ int lov_free_memmd(struct lov_stripe_md **lsmp)
*lsmp = NULL;
LASSERT(atomic_read(&lsm->lsm_refc) > 0);
- if ((refc = atomic_dec_return(&lsm->lsm_refc)) == 0) {
+ refc = atomic_dec_return(&lsm->lsm_refc);
+ if (refc == 0) {
LASSERT(lsm_op_find(lsm->lsm_magic) != NULL);
lsm_op_find(lsm->lsm_magic)->lsm_free(lsm);
}
diff --git a/drivers/staging/lustre/lustre/lov/lov_request.c b/drivers/staging/lustre/lustre/lov/lov_request.c
index ca81cac9041c..a5481d7eb5d6 100644
--- a/drivers/staging/lustre/lustre/lov/lov_request.c
+++ b/drivers/staging/lustre/lustre/lov/lov_request.c
@@ -50,7 +50,7 @@ static void lov_init_set(struct lov_request_set *set)
atomic_set(&set->set_completes, 0);
atomic_set(&set->set_success, 0);
atomic_set(&set->set_finish_checked, 0);
- set->set_cookies = 0;
+ set->set_cookies = NULL;
INIT_LIST_HEAD(&set->set_list);
atomic_set(&set->set_refcount, 1);
init_waitqueue_head(&set->set_waitq);
diff --git a/drivers/staging/lustre/lustre/lov/lovsub_dev.c b/drivers/staging/lustre/lustre/lov/lovsub_dev.c
index 998ea1cbc7bb..926c35a25ceb 100644
--- a/drivers/staging/lustre/lustre/lov/lovsub_dev.c
+++ b/drivers/staging/lustre/lustre/lov/lovsub_dev.c
@@ -131,6 +131,10 @@ static struct lu_device *lovsub_device_free(const struct lu_env *env,
struct lovsub_device *lsd = lu2lovsub_dev(d);
struct lu_device *next = cl2lu_dev(lsd->acid_next);
+ if (atomic_read(&d->ld_ref) && d->ld_site) {
+ LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, D_ERROR, NULL);
+ lu_site_print(env, d->ld_site, &msgdata, lu_cdebug_printer);
+ }
cl_device_fini(lu2cl_dev(d));
OBD_FREE_PTR(lsd);
return next;
diff --git a/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c b/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c
index 428ffd8c37b7..e44b7a532de7 100644
--- a/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c
+++ b/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c
@@ -55,7 +55,7 @@
struct lprocfs_stats *obd_memory = NULL;
EXPORT_SYMBOL(obd_memory);
-/* refine later and change to seqlock or simlar from libcfs */
+/* refine later and change to seqlock or similar from libcfs */
/* Debugging check only needed during development */
#ifdef OBD_CTXT_DEBUG
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_internal.h b/drivers/staging/lustre/lustre/mdc/mdc_internal.h
index 506982996c0e..c78bf003c2c5 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_internal.h
+++ b/drivers/staging/lustre/lustre/mdc/mdc_internal.h
@@ -101,7 +101,7 @@ int mdc_enqueue(struct obd_export *exp, struct ldlm_enqueue_info *einfo,
struct lustre_handle *lockh, void *lmm, int lmmsize,
struct ptlrpc_request **req, __u64 extra_lock_flags);
-int mdc_resource_get_unused(struct obd_export *exp, struct lu_fid *fid,
+int mdc_resource_get_unused(struct obd_export *exp, const struct lu_fid *fid,
struct list_head *cancels, ldlm_mode_t mode,
__u64 bits);
/* mdc/mdc_request.c */
@@ -122,7 +122,7 @@ int mdc_free_lustre_md(struct obd_export *exp, struct lustre_md *md);
int mdc_set_open_replay_data(struct obd_export *exp,
struct obd_client_handle *och,
- struct ptlrpc_request *open_req);
+ struct lookup_intent *it);
int mdc_clear_open_replay_data(struct obd_export *exp,
struct obd_client_handle *och);
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_lib.c b/drivers/staging/lustre/lustre/mdc/mdc_lib.c
index 91f6876dac3f..5b9f37141512 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_lib.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_lib.c
@@ -197,7 +197,7 @@ static __u64 mds_pack_open_flags(__u64 flags, __u32 mode)
if (flags & FMODE_EXEC)
cr_flags |= MDS_FMODE_EXEC;
#endif
- if (flags & O_LOV_DELAY_CREATE)
+ if (cl_is_lov_delay_create(flags))
cr_flags |= MDS_OPEN_DELAY_CREATE;
if (flags & O_NONBLOCK)
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
index 8aa7c80c2002..53022ec390f0 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
@@ -37,15 +37,15 @@
#define DEBUG_SUBSYSTEM S_MDC
# include <linux/module.h>
-# include <linux/pagemap.h>
-# include <linux/miscdevice.h>
-#include <lustre_acl.h>
+#include <linux/lustre_intent.h>
+#include <obd.h>
#include <obd_class.h>
#include <lustre_dlm.h>
-/* fid_res_name_eq() */
-#include <lustre_fid.h>
-#include <lprocfs_status.h>
+#include <lustre_fid.h> /* fid_res_name_eq() */
+#include <lustre_mdc.h>
+#include <lustre_net.h>
+#include <lustre_req_layout.h>
#include "mdc_internal.h"
struct mdc_getattr_args {
@@ -121,7 +121,7 @@ int mdc_set_lock_data(struct obd_export *exp, __u64 *lockh, void *data,
struct ldlm_lock *lock;
struct inode *new_inode = data;
- if(bits)
+ if (bits)
*bits = 0;
if (!*lockh)
@@ -160,6 +160,8 @@ ldlm_mode_t mdc_lock_match(struct obd_export *exp, __u64 flags,
ldlm_mode_t rc;
fid_build_reg_res_name(fid, &res_id);
+ /* LU-4405: Clear bits not supported by server */
+ policy->l_inodebits.bits &= exp_connect_ibits(exp);
rc = ldlm_lock_match(class_exp2obd(exp)->obd_namespace, flags,
&res_id, type, policy, mode, lockh, 0);
return rc;
@@ -194,7 +196,7 @@ int mdc_null_inode(struct obd_export *exp,
fid_build_reg_res_name(fid, &res_id);
res = ldlm_resource_get(ns, NULL, &res_id, 0, 0);
- if(res == NULL)
+ if (res == NULL)
return 0;
lock_res(res);
@@ -334,9 +336,9 @@ static struct ptlrpc_request *mdc_intent_open_pack(struct obd_export *exp,
max(lmmsize, obddev->u.cli.cl_default_mds_easize));
rc = ldlm_prep_enqueue_req(exp, req, &cancels, count);
- if (rc) {
+ if (rc < 0) {
ptlrpc_request_free(req);
- return NULL;
+ return ERR_PTR(rc);
}
spin_lock(&req->rq_lock);
@@ -378,13 +380,6 @@ mdc_intent_getxattr_pack(struct obd_export *exp,
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
- if (it->it_op == IT_SETXATTR)
- /* If we want to upgrade to LCK_PW, let's cancel LCK_PR
- * locks now. This avoids unnecessary ASTs. */
- count = mdc_resource_get_unused(exp, &op_data->op_fid1,
- &cancels, LCK_PW,
- MDS_INODELOCK_XATTR);
-
rc = ldlm_prep_enqueue_req(exp, req, &cancels, count);
if (rc) {
ptlrpc_request_free(req);
@@ -646,7 +641,7 @@ static int mdc_finish_enqueue(struct obd_export *exp,
* happens immediately after swabbing below, new reply
* is swabbed by that handler correctly.
*/
- mdc_set_open_replay_data(NULL, NULL, req);
+ mdc_set_open_replay_data(NULL, NULL, it);
}
if ((body->valid & (OBD_MD_FLDIREA | OBD_MD_FLEASIZE)) != 0) {
@@ -758,6 +753,7 @@ static int mdc_finish_enqueue(struct obd_export *exp,
/* install lvb_data */
lock_res_and_lock(lock);
if (lock->l_lvb_data == NULL) {
+ lock->l_lvb_type = LVB_T_LAYOUT;
lock->l_lvb_data = lmm;
lock->l_lvb_len = lvb_len;
lmm = NULL;
@@ -842,7 +838,7 @@ resend:
return -EOPNOTSUPP;
req = mdc_intent_layout_pack(exp, it, op_data);
lvb_type = LVB_T_LAYOUT;
- } else if (it->it_op & (IT_GETXATTR | IT_SETXATTR)) {
+ } else if (it->it_op & IT_GETXATTR) {
req = mdc_intent_getxattr_pack(exp, it, op_data);
} else {
LBUG();
@@ -880,7 +876,7 @@ resend:
rc = ldlm_cli_enqueue(exp, &req, einfo, &res_id, policy, &flags, NULL,
0, lvb_type, lockh, 0);
if (!it) {
- /* For flock requests we immediatelly return without further
+ /* For flock requests we immediately return without further
delay and let caller deal with the rest, since rest of
this function metadata processing makes no sense for flock
requests anyway. But in case of problem during comms with
@@ -973,7 +969,6 @@ static int mdc_finish_intent_lock(struct obd_export *exp,
if (fid_is_sane(&op_data->op_fid2) &&
it->it_create_mode & M_CHECK_STALE &&
it->it_op != IT_GETATTR) {
- it_set_disposition(it, DISP_ENQ_COMPLETE);
/* Also: did we find the same inode? */
/* sever can return one of two fids:
@@ -1068,7 +1063,23 @@ int mdc_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
fid_build_reg_res_name(fid, &res_id);
switch (it->it_op) {
case IT_GETATTR:
- policy.l_inodebits.bits = MDS_INODELOCK_UPDATE;
+ /* File attributes are held under multiple bits:
+ * nlink is under lookup lock, size and times are
+ * under UPDATE lock and recently we've also got
+ * a separate permissions lock for owner/group/acl that
+ * were protected by lookup lock before.
+ * Getattr must provide all of that information,
+ * so we need to ensure we have all of those locks.
+ * Unfortunately, if the bits are split across multiple
+ * locks, there's no easy way to match all of them here,
+ * so an extra RPC would be performed to fetch all
+ * of those bits at once for now. */
+ /* For new MDTs(> 2.4), UPDATE|PERM should be enough,
+ * but for old MDTs (< 2.4), permission is covered
+ * by LOOKUP lock, so it needs to match all bits here.*/
+ policy.l_inodebits.bits = MDS_INODELOCK_UPDATE |
+ MDS_INODELOCK_LOOKUP |
+ MDS_INODELOCK_PERM;
break;
case IT_LAYOUT:
policy.l_inodebits.bits = MDS_INODELOCK_LAYOUT;
@@ -1077,10 +1088,11 @@ int mdc_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
policy.l_inodebits.bits = MDS_INODELOCK_LOOKUP;
break;
}
- mode = ldlm_lock_match(exp->exp_obd->obd_namespace,
- LDLM_FL_BLOCK_GRANTED, &res_id,
+
+ mode = mdc_lock_match(exp, LDLM_FL_BLOCK_GRANTED, fid,
LDLM_IBITS, &policy,
- LCK_CR|LCK_CW|LCK_PR|LCK_PW, &lockh, 0);
+ LCK_CR | LCK_CW | LCK_PR | LCK_PW,
+ &lockh);
}
if (mode) {
@@ -1127,6 +1139,12 @@ int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
ldlm_blocking_callback cb_blocking,
__u64 extra_lock_flags)
{
+ struct ldlm_enqueue_info einfo = {
+ .ei_type = LDLM_IBITS,
+ .ei_mode = it_to_lock_mode(it),
+ .ei_cb_bl = cb_blocking,
+ .ei_cb_cp = ldlm_completion_ast,
+ };
struct lustre_handle lockh;
int rc = 0;
@@ -1152,42 +1170,19 @@ int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
return rc;
}
- /* lookup_it may be called only after revalidate_it has run, because
- * revalidate_it cannot return errors, only zero. Returning zero causes
- * this call to lookup, which *can* return an error.
- *
- * We only want to execute the request associated with the intent one
- * time, however, so don't send the request again. Instead, skip past
- * this and use the request from revalidate. In this case, revalidate
- * never dropped its reference, so the refcounts are all OK */
- if (!it_disposition(it, DISP_ENQ_COMPLETE)) {
- struct ldlm_enqueue_info einfo = {
- .ei_type = LDLM_IBITS,
- .ei_mode = it_to_lock_mode(it),
- .ei_cb_bl = cb_blocking,
- .ei_cb_cp = ldlm_completion_ast,
- };
-
- /* For case if upper layer did not alloc fid, do it now. */
- if (!fid_is_sane(&op_data->op_fid2) && it->it_op & IT_CREAT) {
- rc = mdc_fid_alloc(exp, &op_data->op_fid2, op_data);
- if (rc < 0) {
- CERROR("Can't alloc new fid, rc %d\n", rc);
- return rc;
- }
- }
- rc = mdc_enqueue(exp, &einfo, it, op_data, &lockh,
- lmm, lmmsize, NULL, extra_lock_flags);
- if (rc < 0)
+ /* For case if upper layer did not alloc fid, do it now. */
+ if (!fid_is_sane(&op_data->op_fid2) && it->it_op & IT_CREAT) {
+ rc = mdc_fid_alloc(exp, &op_data->op_fid2, op_data);
+ if (rc < 0) {
+ CERROR("Can't alloc new fid, rc %d\n", rc);
return rc;
- } else if (!fid_is_sane(&op_data->op_fid2) ||
- !(it->it_create_mode & M_CHECK_STALE)) {
- /* DISP_ENQ_COMPLETE set means there is extra reference on
- * request referenced from this intent, saved for subsequent
- * lookup. This path is executed when we proceed to this
- * lookup, so we clear DISP_ENQ_COMPLETE */
- it_clear_disposition(it, DISP_ENQ_COMPLETE);
+ }
}
+ rc = mdc_enqueue(exp, &einfo, it, op_data, &lockh, lmm, lmmsize, NULL,
+ extra_lock_flags);
+ if (rc < 0)
+ return rc;
+
*reqp = it->d.lustre.it_data;
rc = mdc_finish_intent_lock(exp, *reqp, op_data, it, &lockh);
return rc;
@@ -1269,8 +1264,8 @@ int mdc_intent_getattr_async(struct obd_export *exp,
fid_build_reg_res_name(&op_data->op_fid1, &res_id);
req = mdc_intent_getattr_pack(exp, it, op_data);
- if (!req)
- return -ENOMEM;
+ if (IS_ERR(req))
+ return PTR_ERR(req);
rc = mdc_enter_request(&obddev->u.cli);
if (rc != 0) {
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_reint.c b/drivers/staging/lustre/lustre/mdc/mdc_reint.c
index 9f3a345f34e0..d79aa1641fef 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_reint.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_reint.c
@@ -66,7 +66,7 @@ static int mdc_reint(struct ptlrpc_request *request,
/* Find and cancel locally locks matched by inode @bits & @mode in the resource
* found by @fid. Found locks are added into @cancel list. Returns the amount of
* locks added to @cancels list. */
-int mdc_resource_get_unused(struct obd_export *exp, struct lu_fid *fid,
+int mdc_resource_get_unused(struct obd_export *exp, const struct lu_fid *fid,
struct list_head *cancels, ldlm_mode_t mode,
__u64 bits)
{
@@ -165,6 +165,7 @@ int mdc_setattr(struct obd_export *exp, struct md_op_data *op_data,
req->rq_cb_data = *mod;
(*mod)->mod_open_req = req;
req->rq_commit_cb = mdc_commit_open;
+ (*mod)->mod_is_create = true;
/**
* Take an extra reference on \var mod, it protects \var
* mod from being freed on eviction (commit callback is
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c
index 83013927e131..bde9f93c149b 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_request.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c
@@ -355,10 +355,32 @@ static int mdc_xattr_common(struct obd_export *exp,const struct req_format *fmt,
input_size);
}
- rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, opcode);
- if (rc) {
- ptlrpc_request_free(req);
- return rc;
+ /* Flush local XATTR locks to get rid of a possible cancel RPC */
+ if (opcode == MDS_REINT && fid_is_sane(fid) &&
+ exp->exp_connect_data.ocd_ibits_known & MDS_INODELOCK_XATTR) {
+ LIST_HEAD(cancels);
+ int count;
+
+ /* Without that packing would fail */
+ if (input_size == 0)
+ req_capsule_set_size(&req->rq_pill, &RMF_EADATA,
+ RCL_CLIENT, 0);
+
+ count = mdc_resource_get_unused(exp, fid,
+ &cancels, LCK_EX,
+ MDS_INODELOCK_XATTR);
+
+ rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
+ if (rc) {
+ ptlrpc_request_free(req);
+ return rc;
+ }
+ } else {
+ rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, opcode);
+ if (rc) {
+ ptlrpc_request_free(req);
+ return rc;
+ }
}
if (opcode == MDS_REINT) {
@@ -700,11 +722,12 @@ void mdc_commit_open(struct ptlrpc_request *req)
int mdc_set_open_replay_data(struct obd_export *exp,
struct obd_client_handle *och,
- struct ptlrpc_request *open_req)
+ struct lookup_intent *it)
{
struct md_open_data *mod;
struct mdt_rec_create *rec;
struct mdt_body *body;
+ struct ptlrpc_request *open_req = it->d.lustre.it_data;
struct obd_import *imp = open_req->rq_import;
if (!open_req->rq_replay)
@@ -738,6 +761,8 @@ int mdc_set_open_replay_data(struct obd_export *exp,
spin_lock(&open_req->rq_lock);
och->och_mod = mod;
mod->mod_och = och;
+ mod->mod_is_create = it_disposition(it, DISP_OPEN_CREATE) ||
+ it_disposition(it, DISP_OPEN_STRIPE);
mod->mod_open_req = open_req;
open_req->rq_cb_data = mod;
open_req->rq_commit_cb = mdc_commit_open;
@@ -758,6 +783,23 @@ int mdc_set_open_replay_data(struct obd_export *exp,
return 0;
}
+static void mdc_free_open(struct md_open_data *mod)
+{
+ int committed = 0;
+
+ if (mod->mod_is_create == 0 &&
+ imp_connect_disp_stripe(mod->mod_open_req->rq_import))
+ committed = 1;
+
+ LASSERT(mod->mod_open_req->rq_replay == 0);
+
+ DEBUG_REQ(D_RPCTRACE, mod->mod_open_req, "free open request\n");
+
+ ptlrpc_request_committed(mod->mod_open_req, committed);
+ if (mod->mod_close_req)
+ ptlrpc_request_committed(mod->mod_close_req, committed);
+}
+
int mdc_clear_open_replay_data(struct obd_export *exp,
struct obd_client_handle *och)
{
@@ -771,6 +813,8 @@ int mdc_clear_open_replay_data(struct obd_export *exp,
return 0;
LASSERT(mod != LP_POISON);
+ LASSERT(mod->mod_open_req != NULL);
+ mdc_free_open(mod);
mod->mod_och = NULL;
och->och_mod = NULL;
@@ -969,6 +1013,9 @@ int mdc_done_writing(struct obd_export *exp, struct md_op_data *op_data,
if (mod) {
if (rc != 0)
mod->mod_close_req = NULL;
+ LASSERT(mod->mod_open_req != NULL);
+ mdc_free_open(mod);
+
/* Since now, mod is accessed through setattr req only,
* thus DW req does not keep a reference on mod anymore. */
obd_mod_put(mod);
@@ -1527,8 +1574,8 @@ static int mdc_changelog_send_thread(void *csdata)
rc = llog_cat_process(NULL, llh, changelog_kkuc_cb, cs, 0, 0);
/* Send EOF no matter what our result */
- if ((kuch = changelog_kuc_hdr(cs->cs_buf, sizeof(*kuch),
- cs->cs_flags))) {
+ kuch = changelog_kuc_hdr(cs->cs_buf, sizeof(*kuch), cs->cs_flags);
+ if (kuch) {
kuch->kuc_msgtype = CL_EOF;
libcfs_kkuc_msg_put(cs->cs_fp, kuch);
}
@@ -1650,11 +1697,16 @@ static int mdc_quotactl(struct obd_device *unused, struct obd_export *exp,
if (rc)
CERROR("ptlrpc_queue_wait failed, rc: %d\n", rc);
- if (req->rq_repmsg &&
- (oqc = req_capsule_server_get(&req->rq_pill, &RMF_OBD_QUOTACTL))) {
- *oqctl = *oqc;
+ if (req->rq_repmsg) {
+ oqc = req_capsule_server_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
+ if (oqc) {
+ *oqctl = *oqc;
+ } else if (!rc) {
+ CERROR ("Can't unpack obd_quotactl\n");
+ rc = -EPROTO;
+ }
} else if (!rc) {
- CERROR ("Can't unpack obd_quotactl\n");
+ CERROR("Can't unpack obd_quotactl\n");
rc = -EPROTO;
}
ptlrpc_req_finished(req);
diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c
index 3bdbb94e020f..de9fb1433edd 100644
--- a/drivers/staging/lustre/lustre/mgc/mgc_request.c
+++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c
@@ -56,7 +56,7 @@ static int mgc_name2resid(char *name, int len, struct ldlm_res_id *res_id,
{
__u64 resname = 0;
- if (len > 8) {
+ if (len > sizeof(resname)) {
CERROR("name too long: %s\n", name);
return -EINVAL;
}
@@ -76,6 +76,7 @@ static int mgc_name2resid(char *name, int len, struct ldlm_res_id *res_id,
resname = 0;
break;
case CONFIG_T_RECOVER:
+ case CONFIG_T_PARAMS:
resname = type;
break;
default:
@@ -101,10 +102,13 @@ int mgc_logname2resid(char *logname, struct ldlm_res_id *res_id, int type)
int len;
/* logname consists of "fsname-nodetype".
- * e.g. "lustre-MDT0001", "SUN-000-client" */
+ * e.g. "lustre-MDT0001", "SUN-000-client"
+ * there is an exception: llog "params" */
name_end = strrchr(logname, '-');
- LASSERT(name_end);
- len = name_end - logname;
+ if (!name_end)
+ len = strlen(logname);
+ else
+ len = name_end - logname;
return mgc_name2resid(logname, len, res_id, type);
}
@@ -140,6 +144,8 @@ static void config_log_put(struct config_llog_data *cld)
config_log_put(cld->cld_recover);
if (cld->cld_sptlrpc)
config_log_put(cld->cld_sptlrpc);
+ if (cld->cld_params)
+ config_log_put(cld->cld_params);
if (cld_is_sptlrpc(cld))
sptlrpc_conf_log_stop(cld->cld_logname);
@@ -271,6 +277,19 @@ static struct config_llog_data *config_recover_log_add(struct obd_device *obd,
return cld;
}
+static struct config_llog_data *config_params_log_add(struct obd_device *obd,
+ struct config_llog_instance *cfg, struct super_block *sb)
+{
+ struct config_llog_instance lcfg = *cfg;
+ struct config_llog_data *cld;
+
+ lcfg.cfg_instance = sb;
+
+ cld = do_config_log_add(obd, PARAMS_FILENAME, CONFIG_T_PARAMS,
+ &lcfg, sb);
+
+ return cld;
+}
/** Add this log to the list of active logs watched by an MGC.
* Active means we're watching for updates.
@@ -284,8 +303,10 @@ static int config_log_add(struct obd_device *obd, char *logname,
struct lustre_sb_info *lsi = s2lsi(sb);
struct config_llog_data *cld;
struct config_llog_data *sptlrpc_cld;
- char seclogname[32];
- char *ptr;
+ struct config_llog_data *params_cld;
+ char seclogname[32];
+ char *ptr;
+ int rc;
CDEBUG(D_MGC, "adding config log %s:%p\n", logname, cfg->cfg_instance);
@@ -308,32 +329,49 @@ static int config_log_add(struct obd_device *obd, char *logname,
CONFIG_T_SPTLRPC, NULL, NULL);
if (IS_ERR(sptlrpc_cld)) {
CERROR("can't create sptlrpc log: %s\n", seclogname);
- return PTR_ERR(sptlrpc_cld);
+ GOTO(out_err, rc = PTR_ERR(sptlrpc_cld));
}
}
+ params_cld = config_params_log_add(obd, cfg, sb);
+ if (IS_ERR(params_cld)) {
+ rc = PTR_ERR(params_cld);
+ CERROR("%s: can't create params log: rc = %d\n",
+ obd->obd_name, rc);
+ GOTO(out_err1, rc);
+ }
cld = do_config_log_add(obd, logname, CONFIG_T_CONFIG, cfg, sb);
if (IS_ERR(cld)) {
CERROR("can't create log: %s\n", logname);
- config_log_put(sptlrpc_cld);
- return PTR_ERR(cld);
+ GOTO(out_err2, rc = PTR_ERR(cld));
}
cld->cld_sptlrpc = sptlrpc_cld;
+ cld->cld_params = params_cld;
LASSERT(lsi->lsi_lmd);
if (!(lsi->lsi_lmd->lmd_flags & LMD_FLG_NOIR)) {
struct config_llog_data *recover_cld;
*strrchr(seclogname, '-') = 0;
recover_cld = config_recover_log_add(obd, seclogname, cfg, sb);
- if (IS_ERR(recover_cld)) {
- config_log_put(cld);
- return PTR_ERR(recover_cld);
- }
+ if (IS_ERR(recover_cld))
+ GOTO(out_err3, rc = PTR_ERR(recover_cld));
cld->cld_recover = recover_cld;
}
return 0;
+
+out_err3:
+ config_log_put(cld);
+
+out_err2:
+ config_log_put(params_cld);
+
+out_err1:
+ config_log_put(sptlrpc_cld);
+
+out_err:
+ return rc;
}
DEFINE_MUTEX(llog_process_lock);
@@ -344,6 +382,7 @@ static int config_log_end(char *logname, struct config_llog_instance *cfg)
{
struct config_llog_data *cld;
struct config_llog_data *cld_sptlrpc = NULL;
+ struct config_llog_data *cld_params = NULL;
struct config_llog_data *cld_recover = NULL;
int rc = 0;
@@ -382,11 +421,20 @@ static int config_log_end(char *logname, struct config_llog_instance *cfg)
spin_lock(&config_list_lock);
cld_sptlrpc = cld->cld_sptlrpc;
cld->cld_sptlrpc = NULL;
+ cld_params = cld->cld_params;
+ cld->cld_params = NULL;
spin_unlock(&config_list_lock);
if (cld_sptlrpc)
config_log_put(cld_sptlrpc);
+ if (cld_params) {
+ mutex_lock(&cld_params->cld_lock);
+ cld_params->cld_stopping = 1;
+ mutex_unlock(&cld_params->cld_lock);
+ config_log_put(cld_params);
+ }
+
/* drop the ref from the find */
config_log_put(cld);
/* drop the start ref */
@@ -1584,7 +1632,7 @@ static int mgc_llog_local_copy(const struct lu_env *env,
/*
* - copy it to backup using llog_backup()
* - copy remote llog to logname using llog_backup()
- * - if failed then move bakup to logname again
+ * - if failed then move backup to logname again
*/
OBD_ALLOC(temp_log, strlen(logname) + 1);
@@ -1664,7 +1712,7 @@ static int mgc_process_cfg_log(struct obd_device *mgc,
LCONSOLE_ERROR_MSG(0x13a,
"Failed to get MGS log %s and no local copy.\n",
cld->cld_logname);
- GOTO(out_pop, rc = -ENOTCONN);
+ GOTO(out_pop, rc = -ENOENT);
}
CDEBUG(D_MGC,
"Failed to get MGS log %s, using local copy for now, will try to update later.\n",
@@ -1863,6 +1911,20 @@ static int mgc_process_config(struct obd_device *obd, obd_count len, void *buf)
if (rc)
CERROR("Cannot process recover llog %d\n", rc);
}
+
+ if (rc == 0 && cld->cld_params != NULL) {
+ rc = mgc_process_log(obd, cld->cld_params);
+ if (rc == -ENOENT) {
+ CDEBUG(D_MGC,
+ "There is no params config file yet\n");
+ rc = 0;
+ }
+ /* params log is optional */
+ if (rc)
+ CERROR(
+ "%s: can't process params llog: rc = %d\n",
+ obd->obd_name, rc);
+ }
config_log_put(cld);
break;
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_io.c b/drivers/staging/lustre/lustre/obdclass/cl_io.c
index e048500edd60..3bebc78e7673 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_io.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_io.c
@@ -942,7 +942,7 @@ int cl_io_cancel(const struct lu_env *env, struct cl_io *io,
struct cl_page *page;
int result = 0;
- CERROR("Canceling ongoing page trasmission\n");
+ CERROR("Canceling ongoing page transmission\n");
cl_page_list_for_each(page, queue) {
int rc;
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_lock.c b/drivers/staging/lustre/lustre/obdclass/cl_lock.c
index 749eb082f979..d795cef3f164 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_lock.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_lock.c
@@ -932,7 +932,7 @@ int cl_lock_state_wait(const struct lu_env *env, struct cl_lock *lock)
* LU-305 */
blocked = cfs_block_sigsinv(LUSTRE_FATAL_SIGS);
- init_waitqueue_entry_current(&waiter);
+ init_waitqueue_entry(&waiter, current);
add_wait_queue(&lock->cll_wq, &waiter);
set_current_state(TASK_INTERRUPTIBLE);
cl_lock_mutex_put(env, lock);
@@ -943,7 +943,7 @@ int cl_lock_state_wait(const struct lu_env *env, struct cl_lock *lock)
* can be restarted if signals are pending here */
result = -ERESTARTSYS;
if (likely(!OBD_FAIL_CHECK(OBD_FAIL_LOCK_STATE_WAIT_INTR))) {
- waitq_wait(&waiter, TASK_INTERRUPTIBLE);
+ schedule();
if (!cfs_signal_pending())
result = 0;
}
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c
index 1a926036724b..0fc256f59e92 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_object.c
@@ -508,7 +508,7 @@ EXPORT_SYMBOL(cl_site_stats_print);
* about journal_info. Currently following fields in task_struct are identified
* can be used for this purpose:
* - cl_env: for liblustre.
- * - tux_info: ony on RedHat kernel.
+ * - tux_info: only on RedHat kernel.
* - ...
* \note As long as we use task_struct to store cl_env, we assume that once
* called into Lustre, we'll never call into the other part of the kernel
diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c
index d9f750d42c80..f2bdea33041d 100644
--- a/drivers/staging/lustre/lustre/obdclass/genops.c
+++ b/drivers/staging/lustre/lustre/obdclass/genops.c
@@ -1010,6 +1010,8 @@ struct obd_import *class_new_import(struct obd_device *obd)
INIT_LIST_HEAD(&imp->imp_replay_list);
INIT_LIST_HEAD(&imp->imp_sending_list);
INIT_LIST_HEAD(&imp->imp_delayed_list);
+ INIT_LIST_HEAD(&imp->imp_committed_list);
+ imp->imp_replay_cursor = &imp->imp_committed_list;
spin_lock_init(&imp->imp_lock);
imp->imp_last_success_conn = 0;
imp->imp_state = LUSTRE_IMP_NEW;
@@ -1532,8 +1534,8 @@ void obd_exports_barrier(struct obd_device *obd)
spin_lock(&obd->obd_dev_lock);
while (!list_empty(&obd->obd_unlinked_exports)) {
spin_unlock(&obd->obd_dev_lock);
- schedule_timeout_and_set_state(TASK_UNINTERRUPTIBLE,
- cfs_time_seconds(waited));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(waited));
if (waited > 5 && IS_PO2(waited)) {
LCONSOLE_WARN("%s is waiting for obd_unlinked_exports "
"more than %d seconds. "
@@ -1625,7 +1627,7 @@ static int obd_zombie_impexp_check(void *arg)
}
/**
- * Add export to the obd_zombe thread and notify it.
+ * Add export to the obd_zombie thread and notify it.
*/
static void obd_zombie_export_add(struct obd_export *exp) {
spin_lock(&exp->exp_obd->obd_dev_lock);
@@ -1641,7 +1643,7 @@ static void obd_zombie_export_add(struct obd_export *exp) {
}
/**
- * Add import to the obd_zombe thread and notify it.
+ * Add import to the obd_zombie thread and notify it.
*/
static void obd_zombie_import_add(struct obd_import *imp) {
LASSERT(imp->imp_sec == NULL);
@@ -1661,7 +1663,7 @@ static void obd_zombie_import_add(struct obd_import *imp) {
static void obd_zombie_impexp_notify(void)
{
/*
- * Make sure obd_zomebie_impexp_thread get this notification.
+ * Make sure obd_zombie_impexp_thread get this notification.
* It is possible this signal only get by obd_zombie_barrier, and
* barrier gulps this notification and sleeps away and hangs ensues
*/
diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
index 121a856d5052..ba20776ebfa1 100644
--- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
+++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
@@ -184,7 +184,7 @@ static long obd_class_ioctl(struct file *filp, unsigned int cmd,
int err = 0;
/* Allow non-root access for OBD_IOC_PING_TARGET - used by lfs check */
- if (!cfs_capable(CFS_CAP_SYS_ADMIN) && (cmd != OBD_IOC_PING_TARGET))
+ if (!capable(CFS_CAP_SYS_ADMIN) && (cmd != OBD_IOC_PING_TARGET))
return err = -EACCES;
if ((cmd & 0xffffff00) == ((int)'T') << 8) /* ignore all tty ioctls */
return err = -ENOTTY;
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_cat.c b/drivers/staging/lustre/lustre/obdclass/llog_cat.c
index c0f3af725747..1d999310ec92 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_cat.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_cat.c
@@ -551,9 +551,8 @@ int llog_cat_process_cb(const struct lu_env *env, struct llog_handle *cat_llh,
if (rec->lrh_index < d->lpd_startcat)
/* Skip processing of the logs until startcat */
- return 0;
-
- if (d->lpd_startidx > 0) {
+ rc = 0;
+ else if (d->lpd_startidx > 0) {
struct llog_process_cat_data cd;
cd.lpcd_first_idx = d->lpd_startidx;
@@ -566,6 +565,7 @@ int llog_cat_process_cb(const struct lu_env *env, struct llog_handle *cat_llh,
rc = llog_process_or_fork(env, llh, d->lpd_cb, d->lpd_data,
NULL, false);
}
+
llog_handle_put(llh);
return rc;
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_lvfs.c b/drivers/staging/lustre/lustre/obdclass/llog_lvfs.c
index 5385d8e658cf..d86bb8c60354 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_lvfs.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_lvfs.c
@@ -376,7 +376,7 @@ static void llog_skip_over(__u64 *off, int curr, int goal)
/* sets:
* - cur_offset to the furthest point read in the log file
- * - cur_idx to the log index preceeding cur_offset
+ * - cur_idx to the log index preceding cur_offset
* returns -EIO/-EINVAL on error
*/
static int llog_lvfs_next_block(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_osd.c b/drivers/staging/lustre/lustre/obdclass/llog_osd.c
index 654c8e189653..682279de8bea 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_osd.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_osd.c
@@ -514,7 +514,7 @@ static void llog_skip_over(__u64 *off, int curr, int goal)
/* sets:
* - cur_offset to the furthest point read in the log file
- * - cur_idx to the log index preceeding cur_offset
+ * - cur_idx to the log index preceding cur_offset
* returns -EIO/-EINVAL on error
*/
static int llog_osd_next_block(const struct lu_env *env,
@@ -1073,7 +1073,7 @@ static int llog_osd_setup(const struct lu_env *env, struct obd_device *obd,
LASSERT(ctxt);
/* initialize data allowing to generate new fids,
- * literally we need a sequece */
+ * literally we need a sequence */
lgi->lgi_fid.f_seq = FID_SEQ_LLOG;
lgi->lgi_fid.f_oid = 1;
lgi->lgi_fid.f_ver = 0;
@@ -1280,7 +1280,7 @@ int llog_osd_put_cat_list(const struct lu_env *env, struct dt_device *d,
lgi->lgi_buf.lb_len = size;
rc = dt_record_write(env, o, &lgi->lgi_buf, &lgi->lgi_off, th);
if (rc)
- CDEBUG(D_INODE, "error writeing CATALOGS: rc = %d\n", rc);
+ CDEBUG(D_INODE, "error writing CATALOGS: rc = %d\n", rc);
out_trans:
dt_trans_stop(env, d, th);
out:
diff --git a/drivers/staging/lustre/lustre/obdclass/local_storage.c b/drivers/staging/lustre/lustre/obdclass/local_storage.c
index e79e4beb3628..e76f7d044231 100644
--- a/drivers/staging/lustre/lustre/obdclass/local_storage.c
+++ b/drivers/staging/lustre/lustre/obdclass/local_storage.c
@@ -737,7 +737,7 @@ int lastid_compat_check(const struct lu_env *env, struct dt_device *dev,
* All dynamic fids will be generated with the same sequence and incremented
* OIDs
*
- * Returned local_oid_storage is in-memory representaion of OID storage
+ * Returned local_oid_storage is in-memory representation of OID storage
*/
int local_oid_storage_init(const struct lu_env *env, struct dt_device *dev,
const struct lu_fid *first_fid,
diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
index ec3b605dae6b..1432dd74fe95 100644
--- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
+++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
@@ -98,6 +98,8 @@ static const char * const obd_connect_names[] = {
"lightweight_conn",
"short_io",
"pingless",
+ "flock_deadlock",
+ "disp_stripe",
"unknown",
NULL
};
diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c
index 9887d8fffb6e..92e8a15a5e5d 100644
--- a/drivers/staging/lustre/lustre/obdclass/lu_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c
@@ -571,7 +571,7 @@ static struct lu_object *htable_lookup(struct lu_site *s,
* drained), and moreover, lookup has to wait until object is freed.
*/
- init_waitqueue_entry_current(waiter);
+ init_waitqueue_entry(waiter, current);
add_wait_queue(&bkt->lsb_marche_funebre, waiter);
set_current_state(TASK_UNINTERRUPTIBLE);
lprocfs_counter_incr(s->ls_stats, LU_SS_CACHE_DEATH_RACE);
@@ -712,7 +712,7 @@ struct lu_object *lu_object_find_at(const struct lu_env *env,
* lu_object_find_try() already added waiter into the
* wait queue.
*/
- waitq_wait(&wait, TASK_UNINTERRUPTIBLE);
+ schedule();
bkt = lu_site_bkt_from_fid(dev->ld_site, (void *)f);
remove_wait_queue(&bkt->lsb_marche_funebre, &wait);
}
@@ -890,10 +890,10 @@ static unsigned lu_obj_hop_hash(struct cfs_hash *hs,
hash = fid_flatten32(fid);
hash += (hash >> 4) + (hash << 12); /* mixing oid and seq */
- hash = cfs_hash_long(hash, hs->hs_bkt_bits);
+ hash = hash_long(hash, hs->hs_bkt_bits);
/* give me another random factor */
- hash -= cfs_hash_long((unsigned long)hs, fid_oid(fid) % 11 + 3);
+ hash -= hash_long((unsigned long)hs, fid_oid(fid) % 11 + 3);
hash <<= hs->hs_cur_bits - hs->hs_bkt_bits;
hash |= (fid_seq(fid) + fid_oid(fid)) & (CFS_HASH_NBKT(hs) - 1);
@@ -2100,7 +2100,7 @@ void lu_object_assign_fid(const struct lu_env *env, struct lu_object *o,
EXPORT_SYMBOL(lu_object_assign_fid);
/**
- * allocates object with 0 (non-assiged) fid
+ * allocates object with 0 (non-assigned) fid
* XXX: temporary solution to be able to assign fid in ->do_create()
* till we have fully-functional OST fids
*/
diff --git a/drivers/staging/lustre/lustre/obdclass/md_attrs.c b/drivers/staging/lustre/lustre/obdclass/md_attrs.c
index f7187829e276..f080cceb384c 100644
--- a/drivers/staging/lustre/lustre/obdclass/md_attrs.c
+++ b/drivers/staging/lustre/lustre/obdclass/md_attrs.c
@@ -60,7 +60,7 @@ EXPORT_SYMBOL(lustre_lma_init);
*/
void lustre_lma_swab(struct lustre_mdt_attrs *lma)
{
- /* Use LUSTRE_MSG_MAGIC to detect local endianess. */
+ /* Use LUSTRE_MSG_MAGIC to detect local endianness. */
if (LUSTRE_MSG_MAGIC != cpu_to_le32(LUSTRE_MSG_MAGIC)) {
__swab32s(&lma->lma_compat);
__swab32s(&lma->lma_incompat);
@@ -77,7 +77,7 @@ EXPORT_SYMBOL(lustre_lma_swab);
*/
void lustre_som_swab(struct som_attrs *attrs)
{
- /* Use LUSTRE_MSG_MAGIC to detect local endianess. */
+ /* Use LUSTRE_MSG_MAGIC to detect local endianness. */
if (LUSTRE_MSG_MAGIC != cpu_to_le32(LUSTRE_MSG_MAGIC)) {
__swab32s(&attrs->som_compat);
__swab32s(&attrs->som_incompat);
@@ -135,7 +135,7 @@ EXPORT_SYMBOL(lustre_buf2som);
*/
void lustre_hsm_swab(struct hsm_attrs *attrs)
{
- /* Use LUSTRE_MSG_MAGIC to detect local endianess. */
+ /* Use LUSTRE_MSG_MAGIC to detect local endianness. */
if (LUSTRE_MSG_MAGIC != cpu_to_le32(LUSTRE_MSG_MAGIC)) {
__swab32s(&attrs->hsm_compat);
__swab32s(&attrs->hsm_flags);
diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c
index 362ae541b209..2d5777699f47 100644
--- a/drivers/staging/lustre/lustre/obdclass/obd_config.c
+++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c
@@ -61,7 +61,8 @@ int class_find_param(char *buf, char *key, char **valp)
if (!buf)
return 1;
- if ((ptr = strstr(buf, key)) == NULL)
+ ptr = strstr(buf, key);
+ if (ptr == NULL)
return 1;
if (valp)
@@ -592,7 +593,7 @@ int class_detach(struct obd_device *obd, struct lustre_cfg *lcfg)
}
EXPORT_SYMBOL(class_detach);
-/** Start shutting down the obd. There may be in-progess ops when
+/** Start shutting down the obd. There may be in-progress ops when
* this is called. We tell them to start shutting down with a call
* to class_disconnect_exports().
*/
@@ -655,7 +656,7 @@ int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
/* The three references that should be remaining are the
* obd_self_export and the attach and setup references. */
if (atomic_read(&obd->obd_refcount) > 3) {
- /* refcounf - 3 might be the number of real exports
+ /* refcount - 3 might be the number of real exports
(excluding self export). But class_incref is called
by other things as well, so don't count on it. */
CDEBUG(D_IOCTL, "%s: forcing exports to disconnect: %d\n",
@@ -1027,6 +1028,46 @@ struct lustre_cfg *lustre_cfg_rename(struct lustre_cfg *cfg,
}
EXPORT_SYMBOL(lustre_cfg_rename);
+static int process_param2_config(struct lustre_cfg *lcfg)
+{
+ char *param = lustre_cfg_string(lcfg, 1);
+ char *upcall = lustre_cfg_string(lcfg, 2);
+ char *argv[] = {
+ [0] = "/usr/sbin/lctl",
+ [1] = "set_param",
+ [2] = param,
+ [3] = NULL
+ };
+ struct timeval start;
+ struct timeval end;
+ int rc;
+
+
+ /* Add upcall processing here. Now only lctl is supported */
+ if (strcmp(upcall, LCTL_UPCALL) != 0) {
+ CERROR("Unsupported upcall %s\n", upcall);
+ return -EINVAL;
+ }
+
+ do_gettimeofday(&start);
+ rc = USERMODEHELPER(argv[0], argv, NULL);
+ do_gettimeofday(&end);
+
+ if (rc < 0) {
+ CERROR(
+ "lctl: error invoking upcall %s %s %s: rc = %d; time %ldus\n",
+ argv[0], argv[1], argv[2], rc,
+ cfs_timeval_sub(&end, &start, NULL));
+ } else {
+ CDEBUG(D_HA, "lctl: invoked upcall %s %s %s, time %ldus\n",
+ argv[0], argv[1], argv[2],
+ cfs_timeval_sub(&end, &start, NULL));
+ rc = 0;
+ }
+
+ return rc;
+}
+
void lustre_register_quota_process_config(int (*qpc)(struct lustre_cfg *lcfg))
{
quota_process_config = qpc;
@@ -1142,11 +1183,14 @@ int class_process_config(struct lustre_cfg *lcfg)
err = (*quota_process_config)(lcfg);
GOTO(out, err);
}
- /* Fall through */
+
break;
}
+ case LCFG_SET_PARAM: {
+ err = process_param2_config(lcfg);
+ GOTO(out, 0);
+ }
}
-
/* Commands that require a device */
obd = class_name2obd(lustre_cfg_string(lcfg, 0));
if (obd == NULL) {
diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
index a69a630b596e..6f8ba54e9667 100644
--- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c
+++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
@@ -501,7 +501,7 @@ static int lustre_stop_mgc(struct super_block *sb)
}
/* The MGC has no recoverable data in any case.
- * force shotdown set in umount_begin */
+ * force shutdown set in umount_begin */
obd->obd_no_recov = 1;
if (obd->u.cli.cl_mgc_mgsexp) {
@@ -754,7 +754,7 @@ int server_name2index(const char *svname, __u32 *idx, const char **endptr)
}
EXPORT_SYMBOL(server_name2index);
-/*************** mount common betweeen server and client ***************/
+/*************** mount common between server and client ***************/
/* Common umount */
int lustre_common_put_super(struct super_block *sb)
diff --git a/drivers/staging/lustre/lustre/obdclass/obdo.c b/drivers/staging/lustre/lustre/obdclass/obdo.c
index 70997648a4f3..3b1b28afd6b1 100644
--- a/drivers/staging/lustre/lustre/obdclass/obdo.c
+++ b/drivers/staging/lustre/lustre/obdclass/obdo.c
@@ -191,7 +191,7 @@ int obdo_cmp_md(struct obdo *dst, struct obdo *src, obd_flag compare)
}
if ( compare & OBD_MD_FLGENER )
res = (res || (dst->o_parent_oid != src->o_parent_oid));
- /* XXX Don't know if thses should be included here - wasn't previously
+ /* XXX Don't know if these should be included here - wasn't previously
if ( compare & OBD_MD_FLINLINE )
res = (res || memcmp(dst->o_inline, src->o_inline));
*/
@@ -233,7 +233,7 @@ void obdo_from_iattr(struct obdo *oa, struct iattr *attr, unsigned int ia_valid)
oa->o_mode = attr->ia_mode;
oa->o_valid |= OBD_MD_FLTYPE | OBD_MD_FLMODE;
if (!in_group_p(make_kgid(&init_user_ns, oa->o_gid)) &&
- !cfs_capable(CFS_CAP_FSETID))
+ !capable(CFS_CAP_FSETID))
oa->o_mode &= ~S_ISGID;
}
if (ia_valid & ATTR_UID) {
@@ -282,7 +282,7 @@ void iattr_from_obdo(struct iattr *attr, struct obdo *oa, obd_flag valid)
attr->ia_mode = (attr->ia_mode & S_IFMT)|(oa->o_mode & ~S_IFMT);
attr->ia_valid |= ATTR_MODE;
if (!in_group_p(make_kgid(&init_user_ns, oa->o_gid)) &&
- !cfs_capable(CFS_CAP_FSETID))
+ !capable(CFS_CAP_FSETID))
attr->ia_mode &= ~S_ISGID;
}
if (valid & OBD_MD_FLUID) {
diff --git a/drivers/staging/lustre/lustre/obdecho/echo.c b/drivers/staging/lustre/lustre/obdecho/echo.c
index debb9cec4900..96a807f82ec1 100644
--- a/drivers/staging/lustre/lustre/obdecho/echo.c
+++ b/drivers/staging/lustre/lustre/obdecho/echo.c
@@ -606,7 +606,8 @@ static int echo_cleanup(struct obd_device *obd)
/* XXX Bug 3413; wait for a bit to ensure the BL callback has
* happened before calling ldlm_namespace_free() */
- schedule_timeout_and_set_state(TASK_UNINTERRUPTIBLE, cfs_time_seconds(1));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1));
ldlm_namespace_free(obd->obd_namespace, NULL, obd->obd_force);
obd->obd_namespace = NULL;
diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c
index 9b2dea292363..754aa8e55665 100644
--- a/drivers/staging/lustre/lustre/obdecho/echo_client.c
+++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c
@@ -997,8 +997,8 @@ static struct lu_device *echo_device_free(const struct lu_env *env,
spin_unlock(&ec->ec_lock);
CERROR("echo_client still has objects at cleanup time, "
"wait for 1 second\n");
- schedule_timeout_and_set_state(TASK_UNINTERRUPTIBLE,
- cfs_time_seconds(1));
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(cfs_time_seconds(1));
lu_site_purge(env, &ed->ed_site->cs_lu, -1);
spin_lock(&ec->ec_lock);
}
@@ -2764,7 +2764,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
switch (cmd) {
case OBD_IOC_CREATE: /* may create echo object */
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CFS_CAP_SYS_ADMIN))
GOTO (out, rc = -EPERM);
rc = echo_create_object(env, ed, 1, oa, data->ioc_pbuf1,
@@ -2778,7 +2778,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
int dirlen;
__u64 id;
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CFS_CAP_SYS_ADMIN))
GOTO(out, rc = -EPERM);
count = data->ioc_count;
@@ -2806,7 +2806,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
__u64 seq;
int max_count;
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CFS_CAP_SYS_ADMIN))
GOTO(out, rc = -EPERM);
cl_env = cl_env_get(&refcheck);
@@ -2838,7 +2838,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
GOTO(out, rc);
}
case OBD_IOC_DESTROY:
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CFS_CAP_SYS_ADMIN))
GOTO (out, rc = -EPERM);
rc = echo_get_object(&eco, ed, oa);
@@ -2863,7 +2863,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
GOTO(out, rc);
case OBD_IOC_SETATTR:
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CFS_CAP_SYS_ADMIN))
GOTO (out, rc = -EPERM);
rc = echo_get_object(&eco, ed, oa);
@@ -2878,7 +2878,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
GOTO(out, rc);
case OBD_IOC_BRW_WRITE:
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CFS_CAP_SYS_ADMIN))
GOTO (out, rc = -EPERM);
rw = OBD_BRW_WRITE;
@@ -2897,7 +2897,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
GOTO(out, rc);
case ECHO_IOC_SET_STRIPE:
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CFS_CAP_SYS_ADMIN))
GOTO (out, rc = -EPERM);
if (data->ioc_pbuf1 == NULL) { /* unset */
@@ -2914,7 +2914,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
GOTO (out, rc);
case ECHO_IOC_ENQUEUE:
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CFS_CAP_SYS_ADMIN))
GOTO (out, rc = -EPERM);
rc = echo_client_enqueue(exp, oa,
diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c
index be4511e78c04..fe9989a49f81 100644
--- a/drivers/staging/lustre/lustre/osc/osc_cache.c
+++ b/drivers/staging/lustre/lustre/osc/osc_cache.c
@@ -1020,7 +1020,7 @@ out:
/**
* This function is used to make the extent prepared for transfer.
- * A race with flusing page - ll_writepage() has to be handled cautiously.
+ * A race with flushing page - ll_writepage() has to be handled cautiously.
*/
static int osc_extent_make_ready(const struct lu_env *env,
struct osc_extent *ext)
@@ -2146,7 +2146,7 @@ int osc_prep_async_page(struct osc_object *osc, struct osc_page *ops,
oap->oap_obj_off = offset;
LASSERT(!(offset & ~CFS_PAGE_MASK));
- if (!client_is_remote(exp) && cfs_capable(CFS_CAP_SYS_RESOURCE))
+ if (!client_is_remote(exp) && capable(CFS_CAP_SYS_RESOURCE))
oap->oap_brw_flags = OBD_BRW_NOQUOTA;
INIT_LIST_HEAD(&oap->oap_pending_item);
@@ -2186,7 +2186,7 @@ int osc_queue_async_io(const struct lu_env *env, struct cl_io *io,
/* Set the OBD_BRW_SRVLOCK before the page is queued. */
brw_flags |= ops->ops_srvlock ? OBD_BRW_SRVLOCK : 0;
if (!client_is_remote(osc_export(osc)) &&
- cfs_capable(CFS_CAP_SYS_RESOURCE)) {
+ capable(CFS_CAP_SYS_RESOURCE)) {
brw_flags |= OBD_BRW_NOQUOTA;
cmd |= OBD_BRW_NOQUOTA;
}
@@ -2394,6 +2394,12 @@ int osc_flush_async_page(const struct lu_env *env, struct cl_io *io,
* really sending the RPC. */
case OES_TRUNC:
/* race with truncate, page will be redirtied */
+ case OES_ACTIVE:
+ /* The extent is active so we need to abort and let the caller
+ * re-dirty the page. If we continued on here, and we were the
+ * one making the extent active, we could deadlock waiting for
+ * the page writeback to clear but it won't because the extent
+ * is active and won't be written out. */
GOTO(out, rc = -EAGAIN);
default:
break;
diff --git a/drivers/staging/lustre/lustre/osc/osc_io.c b/drivers/staging/lustre/lustre/osc/osc_io.c
index 681d60a7d5ef..5f3c545418d1 100644
--- a/drivers/staging/lustre/lustre/osc/osc_io.c
+++ b/drivers/staging/lustre/lustre/osc/osc_io.c
@@ -297,7 +297,7 @@ static int osc_io_commit_write(const struct lu_env *env,
*/
osc_page_touch(env, cl2osc_page(slice), to);
if (!client_is_remote(osc_export(obj)) &&
- cfs_capable(CFS_CAP_SYS_RESOURCE))
+ capable(CFS_CAP_SYS_RESOURCE))
oap->oap_brw_flags |= OBD_BRW_NOQUOTA;
if (oio->oi_lockless)
@@ -512,19 +512,15 @@ static int osc_io_read_start(const struct lu_env *env,
struct osc_io *oio = cl2osc_io(env, slice);
struct cl_object *obj = slice->cis_obj;
struct cl_attr *attr = &osc_env_info(env)->oti_attr;
- int result = 0;
+ int rc = 0;
- if (oio->oi_lockless == 0) {
+ if (oio->oi_lockless == 0 && !slice->cis_io->ci_noatime) {
cl_object_attr_lock(obj);
- result = cl_object_attr_get(env, obj, attr);
- if (result == 0) {
- attr->cat_atime = LTIME_S(CURRENT_TIME);
- result = cl_object_attr_set(env, obj, attr,
- CAT_ATIME);
- }
+ attr->cat_atime = LTIME_S(CURRENT_TIME);
+ rc = cl_object_attr_set(env, obj, attr, CAT_ATIME);
cl_object_attr_unlock(obj);
}
- return result;
+ return rc;
}
static int osc_io_write_start(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c
index 4909e486dc5c..96cb6e2b9c4e 100644
--- a/drivers/staging/lustre/lustre/osc/osc_page.c
+++ b/drivers/staging/lustre/lustre/osc/osc_page.c
@@ -561,7 +561,7 @@ void osc_page_submit(const struct lu_env *env, struct osc_page *opg,
oap->oap_brw_flags = OBD_BRW_SYNC | brw_flags;
if (!client_is_remote(osc_export(obj)) &&
- cfs_capable(CFS_CAP_SYS_RESOURCE)) {
+ capable(CFS_CAP_SYS_RESOURCE)) {
oap->oap_brw_flags |= OBD_BRW_NOQUOTA;
oap->oap_cmd |= OBD_BRW_NOQUOTA;
}
diff --git a/drivers/staging/lustre/lustre/osc/osc_quota.c b/drivers/staging/lustre/lustre/osc/osc_quota.c
index 6045a78a2baa..0235fabaaffe 100644
--- a/drivers/staging/lustre/lustre/osc/osc_quota.c
+++ b/drivers/staging/lustre/lustre/osc/osc_quota.c
@@ -51,11 +51,8 @@ int osc_quota_chkdq(struct client_obd *cli, const unsigned int qid[])
oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]);
if (oqi) {
- obd_uid id = oqi->oqi_id;
-
- LASSERTF(id == qid[type],
- "The ids don't match %u != %u\n",
- id, qid[type]);
+ /* do not try to access oqi here, it could have been
+ * freed by osc_quota_setdq() */
/* the slot is busy, the user is about to run out of
* quota space on this OST */
@@ -268,11 +265,16 @@ int osc_quotactl(struct obd_device *unused, struct obd_export *exp,
if (rc)
CERROR("ptlrpc_queue_wait failed, rc: %d\n", rc);
- if (req->rq_repmsg &&
- (oqc = req_capsule_server_get(&req->rq_pill, &RMF_OBD_QUOTACTL))) {
- *oqctl = *oqc;
+ if (req->rq_repmsg) {
+ oqc = req_capsule_server_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
+ if (oqc) {
+ *oqctl = *oqc;
+ } else if (!rc) {
+ CERROR("Can't unpack obd_quotactl\n");
+ rc = -EPROTO;
+ }
} else if (!rc) {
- CERROR ("Can't unpack obd_quotactl\n");
+ CERROR("Can't unpack obd_quotactl\n");
rc = -EPROTO;
}
ptlrpc_req_finished(req);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c
index d90efe408414..4c9e00695087 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/client.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/client.c
@@ -48,6 +48,7 @@
#include "ptlrpc_internal.h"
static int ptlrpc_send_new_req(struct ptlrpc_request *req);
+static int ptlrpcd_check_work(struct ptlrpc_request *req);
/**
* Initialize passed in client structure \a cl.
@@ -62,7 +63,7 @@ void ptlrpc_init_client(int req_portal, int rep_portal, char *name,
EXPORT_SYMBOL(ptlrpc_init_client);
/**
- * Return PortalRPC connection for remore uud \a uuid
+ * Return PortalRPC connection for remote uud \a uuid
*/
struct ptlrpc_connection *ptlrpc_uuid_to_connection(struct obd_uuid *uuid)
{
@@ -127,7 +128,7 @@ struct ptlrpc_bulk_desc *ptlrpc_new_bulk(unsigned npages, unsigned max_brw,
* Prepare bulk descriptor for specified outgoing request \a req that
* can fit \a npages * pages. \a type is bulk type. \a portal is where
* the bulk to be sent. Used on client-side.
- * Returns pointer to newly allocatrd initialized bulk descriptor or NULL on
+ * Returns pointer to newly allocated initialized bulk descriptor or NULL on
* error.
*/
struct ptlrpc_bulk_desc *ptlrpc_prep_bulk_imp(struct ptlrpc_request *req,
@@ -631,7 +632,7 @@ int ptlrpc_request_pack(struct ptlrpc_request *request,
/* For some old 1.8 clients (< 1.8.7), they will LASSERT the size of
* ptlrpc_body sent from server equal to local ptlrpc_body size, so we
- * have to send old ptlrpc_body to keep interoprability with these
+ * have to send old ptlrpc_body to keep interoperability with these
* clients.
*
* Only three kinds of server->client RPCs so far:
@@ -639,7 +640,7 @@ int ptlrpc_request_pack(struct ptlrpc_request *request,
* - LDLM_CP_CALLBACK
* - LDLM_GL_CALLBACK
*
- * XXX This should be removed whenever we drop the interoprability with
+ * XXX This should be removed whenever we drop the interoperability with
* the these old clients.
*/
if (opcode == LDLM_BL_CALLBACK || opcode == LDLM_CP_CALLBACK ||
@@ -686,7 +687,7 @@ struct ptlrpc_request *__ptlrpc_request_alloc(struct obd_import *imp,
/**
* Helper function for creating a request.
- * Calls __ptlrpc_request_alloc to allocate new request sturcture and inits
+ * Calls __ptlrpc_request_alloc to allocate new request structure and inits
* buffer structures according to capsule template \a format.
* Returns allocated request structure pointer or NULL on error.
*/
@@ -743,7 +744,7 @@ void ptlrpc_request_free(struct ptlrpc_request *request)
EXPORT_SYMBOL(ptlrpc_request_free);
/**
- * Allocate new request for operatione \a opcode and immediatelly pack it for
+ * Allocate new request for operation \a opcode and immediately pack it for
* network transfer.
* Only used for simple requests like OBD_PING where the only important
* part of the request is operation itself.
@@ -768,7 +769,7 @@ struct ptlrpc_request *ptlrpc_request_alloc_pack(struct obd_import *imp,
EXPORT_SYMBOL(ptlrpc_request_alloc_pack);
/**
- * Prepare request (fetched from pool \a poolif not NULL) on import \a imp
+ * Prepare request (fetched from pool \a pool if not NULL) on import \a imp
* for operation \a opcode. Request would contain \a count buffers.
* Sizes of buffers are described in array \a lengths and buffers themselves
* are provided by a pointer \a bufs.
@@ -1073,7 +1074,7 @@ static int ptlrpc_import_delay_req(struct obd_import *imp,
}
/**
- * Decide if the eror message regarding provided request \a req
+ * Decide if the error message regarding provided request \a req
* should be printed to the console or not.
* Makes it's decision on request status and other properties.
* Returns 1 to print error on the system console or 0 if not.
@@ -1159,7 +1160,7 @@ static void ptlrpc_save_versions(struct ptlrpc_request *req)
/**
* Callback function called when client receives RPC reply for \a req.
* Returns 0 on success or error code.
- * The return alue would be assigned to req->rq_status by the caller
+ * The return value would be assigned to req->rq_status by the caller
* as request processing status.
* This function also decides if the request needs to be saved for later replay.
*/
@@ -1190,7 +1191,9 @@ static int after_reply(struct ptlrpc_request *req)
* will roundup it */
req->rq_replen = req->rq_nob_received;
req->rq_nob_received = 0;
+ spin_lock(&req->rq_lock);
req->rq_resend = 1;
+ spin_unlock(&req->rq_lock);
return 0;
}
@@ -1313,7 +1316,11 @@ static int after_reply(struct ptlrpc_request *req)
/** version recovery */
ptlrpc_save_versions(req);
ptlrpc_retain_replayable_request(req, imp);
- } else if (req->rq_commit_cb != NULL) {
+ } else if (req->rq_commit_cb != NULL &&
+ list_empty(&req->rq_replay_list)) {
+ /* NB: don't call rq_commit_cb if it's already on
+ * rq_replay_list, ptlrpc_free_committed() will call
+ * it later, see LU-3618 for details */
spin_unlock(&imp->imp_lock);
req->rq_commit_cb(req);
spin_lock(&imp->imp_lock);
@@ -1408,7 +1415,9 @@ static int ptlrpc_send_new_req(struct ptlrpc_request *req)
req->rq_status = rc;
return 1;
} else {
+ spin_lock(&req->rq_lock);
req->rq_wait_ctx = 1;
+ spin_unlock(&req->rq_lock);
return 0;
}
}
@@ -1423,7 +1432,9 @@ static int ptlrpc_send_new_req(struct ptlrpc_request *req)
rc = ptl_send_rpc(req, 0);
if (rc) {
DEBUG_REQ(D_HA, req, "send failed (%d); expect timeout", rc);
+ spin_lock(&req->rq_lock);
req->rq_net_err = 1;
+ spin_unlock(&req->rq_lock);
return rc;
}
return 0;
@@ -1688,6 +1699,7 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set)
spin_lock(&req->rq_lock);
req->rq_net_err = 1;
spin_unlock(&req->rq_lock);
+ continue;
}
/* need to reset the timeout */
force_timer_recalc = 1;
@@ -1773,6 +1785,10 @@ interpret:
ptlrpc_req_interpret(env, req, req->rq_status);
+ if (ptlrpcd_check_work(req)) {
+ atomic_dec(&set->set_remaining);
+ continue;
+ }
ptlrpc_rqphase_move(req, RQ_PHASE_COMPLETE);
CDEBUG(req->rq_reqmsg != NULL ? D_RPCTRACE : 0,
@@ -2031,7 +2047,7 @@ int ptlrpc_set_next_timeout(struct ptlrpc_request_set *set)
EXPORT_SYMBOL(ptlrpc_set_next_timeout);
/**
- * Send all unset request from the set and then wait untill all
+ * Send all unset request from the set and then wait until all
* requests in the set complete (either get a reply, timeout, get an
* error or otherwise be interrupted).
* Returns 0 on success or error code otherwise.
@@ -2156,7 +2172,7 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set)
EXPORT_SYMBOL(ptlrpc_set_wait);
/**
- * Helper fuction for request freeing.
+ * Helper function for request freeing.
* Called when request count reached zero and request needs to be freed.
* Removes request from all sorts of sending/replay lists it might be on,
* frees network buffers if any are present.
@@ -2223,7 +2239,7 @@ static void __ptlrpc_free_req(struct ptlrpc_request *request, int locked)
static int __ptlrpc_req_finished(struct ptlrpc_request *request, int locked);
/**
* Drop one request reference. Must be called with import imp_lock held.
- * When reference count drops to zero, reuqest is freed.
+ * When reference count drops to zero, request is freed.
*/
void ptlrpc_req_finished_with_imp_lock(struct ptlrpc_request *request)
{
@@ -2236,7 +2252,7 @@ EXPORT_SYMBOL(ptlrpc_req_finished_with_imp_lock);
* Helper function
* Drops one reference count for request \a request.
* \a locked set indicates that caller holds import imp_lock.
- * Frees the request whe reference count reaches zero.
+ * Frees the request when reference count reaches zero.
*/
static int __ptlrpc_req_finished(struct ptlrpc_request *request, int locked)
{
@@ -2360,19 +2376,52 @@ int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async)
}
EXPORT_SYMBOL(ptlrpc_unregister_reply);
+static void ptlrpc_free_request(struct ptlrpc_request *req)
+{
+ spin_lock(&req->rq_lock);
+ req->rq_replay = 0;
+ spin_unlock(&req->rq_lock);
+
+ if (req->rq_commit_cb != NULL)
+ req->rq_commit_cb(req);
+ list_del_init(&req->rq_replay_list);
+
+ __ptlrpc_req_finished(req, 1);
+}
+
+/**
+ * the request is committed and dropped from the replay list of its import
+ */
+void ptlrpc_request_committed(struct ptlrpc_request *req, int force)
+{
+ struct obd_import *imp = req->rq_import;
+
+ spin_lock(&imp->imp_lock);
+ if (list_empty(&req->rq_replay_list)) {
+ spin_unlock(&imp->imp_lock);
+ return;
+ }
+
+ if (force || req->rq_transno <= imp->imp_peer_committed_transno)
+ ptlrpc_free_request(req);
+
+ spin_unlock(&imp->imp_lock);
+}
+EXPORT_SYMBOL(ptlrpc_request_committed);
+
/**
* Iterates through replay_list on import and prunes
* all requests have transno smaller than last_committed for the
* import and don't have rq_replay set.
- * Since requests are sorted in transno order, stops when meetign first
+ * Since requests are sorted in transno order, stops when meeting first
* transno bigger than last_committed.
* caller must hold imp->imp_lock
*/
void ptlrpc_free_committed(struct obd_import *imp)
{
- struct list_head *tmp, *saved;
- struct ptlrpc_request *req;
+ struct ptlrpc_request *req, *saved;
struct ptlrpc_request *last_req = NULL; /* temporary fire escape */
+ bool skip_committed_list = true;
LASSERT(imp != NULL);
@@ -2388,13 +2437,15 @@ void ptlrpc_free_committed(struct obd_import *imp)
CDEBUG(D_RPCTRACE, "%s: committing for last_committed "LPU64" gen %d\n",
imp->imp_obd->obd_name, imp->imp_peer_committed_transno,
imp->imp_generation);
+
+ if (imp->imp_generation != imp->imp_last_generation_checked)
+ skip_committed_list = false;
+
imp->imp_last_transno_checked = imp->imp_peer_committed_transno;
imp->imp_last_generation_checked = imp->imp_generation;
- list_for_each_safe(tmp, saved, &imp->imp_replay_list) {
- req = list_entry(tmp, struct ptlrpc_request,
- rq_replay_list);
-
+ list_for_each_entry_safe(req, saved, &imp->imp_replay_list,
+ rq_replay_list) {
/* XXX ok to remove when 1357 resolved - rread 05/29/03 */
LASSERT(req != last_req);
last_req = req;
@@ -2408,27 +2459,34 @@ void ptlrpc_free_committed(struct obd_import *imp)
GOTO(free_req, 0);
}
- if (req->rq_replay) {
- DEBUG_REQ(D_RPCTRACE, req, "keeping (FL_REPLAY)");
- continue;
- }
-
/* not yet committed */
if (req->rq_transno > imp->imp_peer_committed_transno) {
DEBUG_REQ(D_RPCTRACE, req, "stopping search");
break;
}
+ if (req->rq_replay) {
+ DEBUG_REQ(D_RPCTRACE, req, "keeping (FL_REPLAY)");
+ list_move_tail(&req->rq_replay_list,
+ &imp->imp_committed_list);
+ continue;
+ }
+
DEBUG_REQ(D_INFO, req, "commit (last_committed "LPU64")",
imp->imp_peer_committed_transno);
free_req:
- spin_lock(&req->rq_lock);
- req->rq_replay = 0;
- spin_unlock(&req->rq_lock);
- if (req->rq_commit_cb != NULL)
- req->rq_commit_cb(req);
- list_del_init(&req->rq_replay_list);
- __ptlrpc_req_finished(req, 1);
+ ptlrpc_free_request(req);
+ }
+ if (skip_committed_list)
+ return;
+
+ list_for_each_entry_safe(req, saved, &imp->imp_committed_list,
+ rq_replay_list) {
+ LASSERT(req->rq_transno != 0);
+ if (req->rq_import_generation < imp->imp_generation) {
+ DEBUG_REQ(D_RPCTRACE, req, "free stale open request");
+ ptlrpc_free_request(req);
+ }
}
}
@@ -2585,7 +2643,7 @@ struct ptlrpc_replay_async_args {
/**
* Callback used for replayed requests reply processing.
- * In case of succesful reply calls registeresd request replay callback.
+ * In case of successful reply calls registered request replay callback.
* In case of error restart replay process.
*/
static int ptlrpc_replay_interpret(const struct lu_env *env,
@@ -2834,7 +2892,7 @@ void ptlrpc_init_xid(void)
ptlrpc_last_xid = (__u64)now << 20;
}
- /* Need to always be aligned to a power-of-two for mutli-bulk BRW */
+ /* Always need to be aligned to a power-of-two for multi-bulk BRW */
CLASSERT((PTLRPC_BULK_OPS_COUNT & (PTLRPC_BULK_OPS_COUNT - 1)) == 0);
ptlrpc_last_xid &= PTLRPC_BULK_OPS_MASK;
}
@@ -2904,22 +2962,50 @@ EXPORT_SYMBOL(ptlrpc_sample_next_xid);
* have delay before it really runs by ptlrpcd thread.
*/
struct ptlrpc_work_async_args {
- __u64 magic;
int (*cb)(const struct lu_env *, void *);
void *cbdata;
};
-#define PTLRPC_WORK_MAGIC 0x6655436b676f4f44ULL /* magic code */
+static void ptlrpcd_add_work_req(struct ptlrpc_request *req)
+{
+ /* re-initialize the req */
+ req->rq_timeout = obd_timeout;
+ req->rq_sent = cfs_time_current_sec();
+ req->rq_deadline = req->rq_sent + req->rq_timeout;
+ req->rq_reply_deadline = req->rq_deadline;
+ req->rq_phase = RQ_PHASE_INTERPRET;
+ req->rq_next_phase = RQ_PHASE_COMPLETE;
+ req->rq_xid = ptlrpc_next_xid();
+ req->rq_import_generation = req->rq_import->imp_generation;
+
+ ptlrpcd_add_req(req, PDL_POLICY_ROUND, -1);
+}
static int work_interpreter(const struct lu_env *env,
struct ptlrpc_request *req, void *data, int rc)
{
struct ptlrpc_work_async_args *arg = data;
- LASSERT(arg->magic == PTLRPC_WORK_MAGIC);
+ LASSERT(ptlrpcd_check_work(req));
LASSERT(arg->cb != NULL);
- return arg->cb(env, arg->cbdata);
+ rc = arg->cb(env, arg->cbdata);
+
+ list_del_init(&req->rq_set_chain);
+ req->rq_set = NULL;
+
+ if (atomic_dec_return(&req->rq_refcount) > 1) {
+ atomic_set(&req->rq_refcount, 2);
+ ptlrpcd_add_work_req(req);
+ }
+ return rc;
+}
+
+static int worker_format;
+
+static int ptlrpcd_check_work(struct ptlrpc_request *req)
+{
+ return req->rq_pill.rc_fmt == (void *)&worker_format;
}
/**
@@ -2952,6 +3038,7 @@ void *ptlrpcd_alloc_work(struct obd_import *imp,
req->rq_receiving_reply = 0;
req->rq_must_unlink = 0;
req->rq_no_delay = req->rq_no_resend = 1;
+ req->rq_pill.rc_fmt = (void *)&worker_format;
spin_lock_init(&req->rq_lock);
INIT_LIST_HEAD(&req->rq_list);
@@ -2965,7 +3052,6 @@ void *ptlrpcd_alloc_work(struct obd_import *imp,
CLASSERT(sizeof(*args) <= sizeof(req->rq_async_args));
args = ptlrpc_req_async_args(req);
- args->magic = PTLRPC_WORK_MAGIC;
args->cb = cb;
args->cbdata = cbdata;
@@ -2995,25 +3081,8 @@ int ptlrpcd_queue_work(void *handler)
* req as opaque data. - Jinshan
*/
LASSERT(atomic_read(&req->rq_refcount) > 0);
- if (atomic_read(&req->rq_refcount) > 1)
- return -EBUSY;
-
- if (atomic_inc_return(&req->rq_refcount) > 2) { /* race */
- atomic_dec(&req->rq_refcount);
- return -EBUSY;
- }
-
- /* re-initialize the req */
- req->rq_timeout = obd_timeout;
- req->rq_sent = cfs_time_current_sec();
- req->rq_deadline = req->rq_sent + req->rq_timeout;
- req->rq_reply_deadline = req->rq_deadline;
- req->rq_phase = RQ_PHASE_INTERPRET;
- req->rq_next_phase = RQ_PHASE_COMPLETE;
- req->rq_xid = ptlrpc_next_xid();
- req->rq_import_generation = req->rq_import->imp_generation;
-
- ptlrpcd_add_req(req, PDL_POLICY_ROUND, -1);
+ if (atomic_inc_return(&req->rq_refcount) == 2)
+ ptlrpcd_add_work_req(req);
return 0;
}
EXPORT_SYMBOL(ptlrpcd_queue_work);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c
index f66cfea87acf..6ea0a491cfb3 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/events.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/events.c
@@ -545,7 +545,7 @@ int ptlrpc_ni_init(void)
* different depending on... */
/* kernel LNet calls our master callback when there are new event,
* because we are guaranteed to get every event via callback,
- * so we just set EQ size to 0 to avoid overhread of serializing
+ * so we just set EQ size to 0 to avoid overhead of serializing
* enqueue/dequeue operations in LNet. */
rc = LNetEQAlloc(0, ptlrpc_master_callback, &ptlrpc_eq_h);
if (rc == 0)
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c
index 55247af3910e..c279edf5b2a5 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c
@@ -336,7 +336,7 @@ int gss_do_ctx_init_rpc(__user char *buffer, unsigned long count)
if (rc) {
/* If any _real_ denial be made, we expect server return
* -EACCES reply or return success but indicate gss error
- * inside reply messsage. All other errors are treated as
+ * inside reply message. All other errors are treated as
* timeout, caller might try the negotiation repeatedly,
* leave recovery decisions to general ptlrpc layer.
*
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_generic_token.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_generic_token.c
index 56c28286c9c1..8dc5c724958d 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_generic_token.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_generic_token.c
@@ -144,7 +144,8 @@ int der_read_length(unsigned char **buf, int *bufsize)
sf = *(*buf)++;
(*bufsize)--;
if (sf & 0x80) {
- if ((sf &= 0x7f) > ((*bufsize) - 1))
+ sf &= 0x7f;
+ if (((*bufsize) - 1) < sf)
return -1;
if (sf > SIZEOF_INT)
return -1;
@@ -199,27 +200,32 @@ __u32 g_verify_token_header(rawobj_t *mech, int *body_size,
rawobj_t toid;
int ret = 0;
- if ((toksize -= 1) < 0)
+ toksize -= 1;
+ if (0 > toksize)
return (G_BAD_TOK_HEADER);
if (*buf++ != 0x60)
return (G_BAD_TOK_HEADER);
- if ((seqsize = der_read_length(&buf, &toksize)) < 0)
+ seqsize = der_read_length(&buf, &toksize);
+ if (seqsize < 0)
return(G_BAD_TOK_HEADER);
if (seqsize != toksize)
return (G_BAD_TOK_HEADER);
- if ((toksize -= 1) < 0)
+ toksize -= 1;
+ if (0 > toksize)
return (G_BAD_TOK_HEADER);
if (*buf++ != 0x06)
return (G_BAD_TOK_HEADER);
- if ((toksize -= 1) < 0)
+ toksize -= 1;
+ if (0 > toksize)
return (G_BAD_TOK_HEADER);
toid.len = *buf++;
- if ((toksize -= toid.len) < 0)
+ toksize -= toid.len;
+ if (0 > toksize)
return (G_BAD_TOK_HEADER);
toid.data = buf;
buf += toid.len;
@@ -231,7 +237,8 @@ __u32 g_verify_token_header(rawobj_t *mech, int *body_size,
* important to return G_BAD_TOK_HEADER if the token header is
* in fact bad
*/
- if ((toksize -= 2) < 0)
+ toksize -= 2;
+ if (0 > toksize)
return (G_BAD_TOK_HEADER);
if (ret)
@@ -256,24 +263,29 @@ __u32 g_get_mech_oid(rawobj_t *mech, rawobj_t *in_buf)
int ret = 0;
int seqsize;
- if ((len -= 1) < 0)
+ len -= 1;
+ if (0 > len)
return (G_BAD_TOK_HEADER);
if (*buf++ != 0x60)
return (G_BAD_TOK_HEADER);
- if ((seqsize = der_read_length(&buf, &len)) < 0)
+ seqsize = der_read_length(&buf, &len);
+ if (seqsize < 0)
return (G_BAD_TOK_HEADER);
- if ((len -= 1) < 0)
+ len -= 1;
+ if (0 > len)
return (G_BAD_TOK_HEADER);
if (*buf++ != 0x06)
return (G_BAD_TOK_HEADER);
- if ((len -= 1) < 0)
+ len -= 1;
+ if (0 > len)
return (G_BAD_TOK_HEADER);
mech->len = *buf++;
- if ((len -= mech->len) < 0)
+ len -= mech->len;
+ if (0 > len)
return (G_BAD_TOK_HEADER);
OBD_ALLOC_LARGE(mech->data, mech->len);
if (!mech->data)
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c
index d43a13c69669..4642bbfb9273 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c
@@ -1176,7 +1176,7 @@ int gss_kt_instantiate(struct key *key, const void *data, size_t datalen)
/*
* called with key semaphore write locked. it means we can operate
- * on the context without fear of loosing refcount.
+ * on the context without fear of losing refcount.
*/
static
int gss_kt_update(struct key *key, const void *data, size_t datalen)
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c
index b9fa3b4a40db..d03f6c114171 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c
@@ -54,7 +54,6 @@
#include <linux/slab.h>
#include <linux/crypto.h>
#include <linux/mutex.h>
-#include <linux/crypto.h>
#include <obd.h>
#include <obd_class.h>
@@ -679,7 +678,8 @@ __s32 krb5_make_checksum(__u32 enctype,
__u32 code = GSS_S_FAILURE;
int rc;
- if (!(tfm = ll_crypto_alloc_hash(ke->ke_hash_name, 0, 0))) {
+ tfm = ll_crypto_alloc_hash(ke->ke_hash_name, 0, 0);
+ if (!tfm) {
CERROR("failed to alloc TFM: %s\n", ke->ke_hash_name);
return GSS_S_FAILURE;
}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c
index c624518c181a..7a1ff4fecbe3 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c
@@ -85,7 +85,7 @@ static void gss_sec_pipe_upcall_fini(struct gss_sec *gsec)
}
/****************************************
- * internel context helpers *
+ * internal context helpers *
****************************************/
static
@@ -652,7 +652,7 @@ __u32 mech_name2idx(const char *name)
/* pipefs dentries for each mechanisms */
static struct dentry *de_pipes[MECH_MAX] = { NULL, };
-/* all upcall messgaes linked here */
+/* all upcall messages linked here */
static struct list_head upcall_lists[MECH_MAX];
/* and protected by this */
static spinlock_t upcall_locks[MECH_MAX];
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c
index 5b5365b4629f..359c48ec2f5b 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c
@@ -102,7 +102,7 @@ static inline unsigned long hash_mem(char *buf, int length, int bits)
len++;
if ((len & (BITS_PER_LONG/8-1)) == 0)
- hash = cfs_hash_long(hash^l, BITS_PER_LONG);
+ hash = hash_long(hash^l, BITS_PER_LONG);
} while (len);
return hash >> (BITS_PER_LONG - bits);
@@ -586,7 +586,7 @@ static int rsc_parse(struct cache_detail *cd, char *mesg, int mlen)
goto out;
/* currently the expiry time passed down from user-space
- * is invalid, here we retrive it from mech. */
+ * is invalid, here we retrieve it from mech. */
if (lgss_inquire_context(rsci.ctx.gsc_mechctx, &ctx_expiry)) {
CERROR("unable to get expire time, drop it\n");
goto out;
@@ -880,7 +880,7 @@ int gss_svc_upcall_handle_init(struct ptlrpc_request *req,
cache_get(&rsip->h); /* take an extra ref */
init_waitqueue_head(&rsip->waitq);
- init_waitqueue_entry_current(&wait);
+ init_waitqueue_entry(&wait, current);
add_wait_queue(&rsip->waitq, &wait);
cache_check:
@@ -1067,7 +1067,7 @@ int __init gss_init_svc_upcall(void)
* the init upcall channel, otherwise there's big chance that the first
* upcall issued before the channel be opened thus nfsv4 cache code will
* drop the request direclty, thus lead to unnecessary recovery time.
- * here we wait at miximum 1.5 seconds. */
+ * here we wait at maximum 1.5 seconds. */
for (i = 0; i < 6; i++) {
if (atomic_read(&rsi_cache.readers) > 0)
break;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c b/drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c
index 8ce6271a5daa..383601cdd4e6 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c
@@ -382,7 +382,7 @@ void gss_cli_ctx_uptodate(struct gss_cli_ctx *gctx)
/* At this point this ctx might have been marked as dead by
* someone else, in which case nobody will make further use
* of it. we don't care, and mark it UPTODATE will help
- * destroying server side context when it be destroied. */
+ * destroying server side context when it be destroyed. */
set_bit(PTLRPC_CTX_UPTODATE_BIT, &ctx->cc_flags);
if (sec_is_reverse(ctx->cc_sec)) {
@@ -676,7 +676,7 @@ redo:
* lead to the sequence number fall behind the window on server and
* be dropped. also applies to gss_cli_ctx_seal().
*
- * Note: null mode dosen't check sequence number. */
+ * Note: null mode doesn't check sequence number. */
if (svc != SPTLRPC_SVC_NULL &&
atomic_read(&gctx->gc_seq) - seq > GSS_SEQ_REPACK_THRESHOLD) {
int behind = atomic_read(&gctx->gc_seq) - seq;
@@ -1215,7 +1215,7 @@ int gss_cli_ctx_fini_common(struct ptlrpc_sec *sec,
/*
* remove UPTODATE flag of reverse ctx thus we won't send fini rpc,
* this is to avoid potential problems of client side reverse svc ctx
- * be mis-destroyed in various recovery senarios. anyway client can
+ * be mis-destroyed in various recovery scenarios. anyway client can
* manage its reverse ctx well by associating it with its buddy ctx.
*/
if (sec_is_reverse(sec))
@@ -1882,7 +1882,7 @@ int gss_svc_sign(struct ptlrpc_request *req,
LASSERT(rs->rs_msg == lustre_msg_buf(rs->rs_repbuf, 1, 0));
- /* embedded lustre_msg might have been shrinked */
+ /* embedded lustre_msg might have been shrunk */
if (req->rq_replen != rs->rs_repbuf->lm_buflens[1])
lustre_shrink_msg(rs->rs_repbuf, 1, req->rq_replen, 1);
@@ -2596,7 +2596,7 @@ static int gss_svc_seal(struct ptlrpc_request *req,
int msglen, rc;
/* get clear data length. note embedded lustre_msg might
- * have been shrinked */
+ * have been shrunk */
if (req->rq_replen != lustre_msg_buflen(rs->rs_repbuf, 0))
msglen = lustre_shrink_msg(rs->rs_repbuf, 0, req->rq_replen, 1);
else
@@ -2765,7 +2765,7 @@ int gss_copy_rvc_cli_ctx(struct ptlrpc_cli_ctx *cli_ctx,
* replay.
*
* each reverse root ctx will record its latest sequence number on its
- * buddy svcctx before be destroied, so here we continue use it.
+ * buddy svcctx before be destroyed, so here we continue use it.
*/
atomic_set(&cli_gctx->gc_seq, svc_gctx->gsc_rvs_seq);
@@ -2836,7 +2836,7 @@ int __init sptlrpc_gss_init(void)
if (rc)
goto out_svc_upcall;
- /* register policy after all other stuff be intialized, because it
+ /* register policy after all other stuff be initialized, because it
* might be in used immediately after the registration. */
rc = gss_init_keyring();
diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c
index f465547eb95e..537aa6204a51 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/import.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/import.c
@@ -560,17 +560,30 @@ static int ptlrpc_first_transno(struct obd_import *imp, __u64 *transno)
struct ptlrpc_request *req;
struct list_head *tmp;
- if (list_empty(&imp->imp_replay_list))
- return 0;
- tmp = imp->imp_replay_list.next;
- req = list_entry(tmp, struct ptlrpc_request, rq_replay_list);
- *transno = req->rq_transno;
- if (req->rq_transno == 0) {
- DEBUG_REQ(D_ERROR, req, "zero transno in replay");
- LBUG();
+ /* The requests in committed_list always have smaller transnos than
+ * the requests in replay_list */
+ if (!list_empty(&imp->imp_committed_list)) {
+ tmp = imp->imp_committed_list.next;
+ req = list_entry(tmp, struct ptlrpc_request, rq_replay_list);
+ *transno = req->rq_transno;
+ if (req->rq_transno == 0) {
+ DEBUG_REQ(D_ERROR, req,
+ "zero transno in committed_list");
+ LBUG();
+ }
+ return 1;
}
-
- return 1;
+ if (!list_empty(&imp->imp_replay_list)) {
+ tmp = imp->imp_replay_list.next;
+ req = list_entry(tmp, struct ptlrpc_request, rq_replay_list);
+ *transno = req->rq_transno;
+ if (req->rq_transno == 0) {
+ DEBUG_REQ(D_ERROR, req, "zero transno in replay_list");
+ LBUG();
+ }
+ return 1;
+ }
+ return 0;
}
/**
@@ -1042,7 +1055,7 @@ finish:
if ((ocd->ocd_cksum_types &
cksum_types_supported_client()) == 0) {
LCONSOLE_WARN("The negotiation of the checksum "
- "alogrithm to use with server %s "
+ "algorithm to use with server %s "
"failed (%x/%x), disabling "
"checksums\n",
obd2cli_tgt(imp->imp_obd),
@@ -1260,7 +1273,7 @@ static int ptlrpc_invalidate_import_thread(void *data)
/**
* This is the state machine for client-side recovery on import.
*
- * Typicaly we have two possibly paths. If we came to server and it is not
+ * Typically we have two possibly paths. If we came to server and it is not
* in recovery, we just enter IMP_EVICTED state, invalidate our import
* state and reconnect from scratch.
* If we came to server that is in recovery, we enter IMP_REPLAY import state.
diff --git a/drivers/staging/lustre/lustre/ptlrpc/layout.c b/drivers/staging/lustre/lustre/ptlrpc/layout.c
index dfcb410fe485..41c12e00129f 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/layout.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/layout.c
@@ -295,7 +295,8 @@ static const struct req_msg_field *mds_reint_setxattr_client[] = {
&RMF_REC_REINT,
&RMF_CAPA1,
&RMF_NAME,
- &RMF_EADATA
+ &RMF_EADATA,
+ &RMF_DLM_REQ
};
static const struct req_msg_field *mdt_swap_layouts[] = {
@@ -2154,7 +2155,7 @@ EXPORT_SYMBOL(req_capsule_server_sized_swab_get);
* request (if the caller is executing on the server-side) or reply (if the
* caller is executing on the client-side).
*
- * This function convienient for use is code that could be executed on the
+ * This function convenient for use is code that could be executed on the
* client and server alike.
*/
const void *req_capsule_other_get(struct req_capsule *pill,
diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
index 1be978609c59..58f1c8bf25b0 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
@@ -616,7 +616,7 @@ out:
}
/**
- * The longest valid command string is the maxium policy name size, plus the
+ * The longest valid command string is the maximum policy name size, plus the
* length of the " reg" substring
*/
#define LPROCFS_NRS_WR_MAX_CMD (NRS_POL_NAME_MAX + sizeof(" reg") - 1)
@@ -1184,7 +1184,7 @@ int lprocfs_wr_evict_client(struct file *file, const char *buffer,
}
tmpbuf = cfs_firststr(kbuf, min_t(unsigned long, BUFLEN - 1, count));
/* Kludge code(deadlock situation): the lprocfs lock has been held
- * since the client is evicted by writting client's
+ * since the client is evicted by writing client's
* uuid/nid to procfs "evict_client" entry. However,
* obd_export_evict_by_uuid() will call lprocfs_remove() to destroy
* the proc entries under the being destroyed export{}, so I have
diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
index 3c6bf23415f9..a47a8d807d5b 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
@@ -349,7 +349,7 @@ static void ptlrpc_at_set_reply(struct ptlrpc_request *req, int flags)
/**
* Send request reply from request \a req reply buffer.
* \a flags defines reply types
- * Returns 0 on sucess or error code
+ * Returns 0 on success or error code
*/
int ptlrpc_send_reply(struct ptlrpc_request *req, int flags)
{
@@ -389,7 +389,7 @@ int ptlrpc_send_reply(struct ptlrpc_request *req, int flags)
* ptlrpc_body in reply buffer to ptlrpc_body_v2, otherwise, the
* reply buffer on client will be overflow.
*
- * XXX Remove this whenver we drop the interoprability with such client.
+ * XXX Remove this whenever we drop the interoprability with such client.
*/
req->rq_replen = lustre_shrink_msg(req->rq_repmsg, 0,
sizeof(struct ptlrpc_body_v2), 1);
@@ -511,7 +511,9 @@ int ptl_send_rpc(struct ptlrpc_request *request, int noreply)
CDEBUG(D_HA, "muting rpc for failed imp obd %s\n",
request->rq_import->imp_obd->obd_name);
/* this prevents us from waiting in ptlrpc_queue_wait */
+ spin_lock(&request->rq_lock);
request->rq_err = 1;
+ spin_unlock(&request->rq_lock);
request->rq_status = -ENODEV;
return -ENODEV;
}
@@ -553,7 +555,9 @@ int ptl_send_rpc(struct ptlrpc_request *request, int noreply)
if (rc) {
/* this prevents us from looping in
* ptlrpc_queue_wait */
+ spin_lock(&request->rq_lock);
request->rq_err = 1;
+ spin_unlock(&request->rq_lock);
request->rq_status = rc;
GOTO(cleanup_bulk, rc);
}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/nrs.c b/drivers/staging/lustre/lustre/ptlrpc/nrs.c
index 0abcd6d82273..bcba1c8e8693 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/nrs.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/nrs.c
@@ -1322,7 +1322,7 @@ EXPORT_SYMBOL(ptlrpc_nrs_policy_unregister);
* Setup NRS heads on all service partitions of service \a svc, and register
* all compatible policies on those NRS heads.
*
- * To be called from withing ptl
+ * To be called from within ptl
* \param[in] svc the service to setup
*
* \retval -ve error, the calling logic should eventually call
@@ -1736,7 +1736,7 @@ fail:
}
/**
- * Removes all policy desciptors from nrs_core::nrs_policies, and frees the
+ * Removes all policy descriptors from nrs_core::nrs_policies, and frees the
* policy descriptors.
*
* Since all PTLRPC services are stopped at this point, there are no more
diff --git a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
index 464479c0f00b..45c0b84621e4 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
@@ -123,7 +123,7 @@ int lustre_msg_early_size(void)
* with the old client (< 2.3) which doesn't have pb_jobid
* in the ptlrpc_body.
*
- * XXX Remove this whenever we dorp interoprability with such
+ * XXX Remove this whenever we drop interoprability with such
* client.
*/
__u32 pblen = sizeof(struct ptlrpc_body_v2);
@@ -244,15 +244,7 @@ int lustre_pack_request(struct ptlrpc_request *req, __u32 magic, int count,
LASSERT(lens[MSG_PTLRPC_BODY_OFF] == sizeof(struct ptlrpc_body));
/* only use new format, we don't need to be compatible with 1.4 */
- magic = LUSTRE_MSG_MAGIC_V2;
-
- switch (magic) {
- case LUSTRE_MSG_MAGIC_V2:
- return lustre_pack_request_v2(req, count, lens, bufs);
- default:
- LASSERTF(0, "incorrect message magic: %08x\n", magic);
- return -EINVAL;
- }
+ return lustre_pack_request_v2(req, count, lens, bufs);
}
EXPORT_SYMBOL(lustre_pack_request);
@@ -1545,7 +1537,7 @@ void lustre_msg_set_jobid(struct lustre_msg *msg, char *jobid)
__u32 opc = lustre_msg_get_opc(msg);
struct ptlrpc_body *pb;
- /* Don't set jobid for ldlm ast RPCs, they've been shrinked.
+ /* Don't set jobid for ldlm ast RPCs, they've been shrunk.
* See the comment in ptlrpc_request_pack(). */
if (!opc || opc == LDLM_BL_CALLBACK ||
opc == LDLM_CP_CALLBACK || opc == LDLM_GL_CALLBACK)
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
index 2d26fd543d46..ca734ce079c1 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
@@ -229,7 +229,7 @@ void ptlrpcd_add_req(struct ptlrpc_request *req, pdl_policy_t policy, int idx)
spin_unlock(&req->rq_lock);
l_wait_event(req->rq_set_waitq, (req->rq_set == NULL), &lwi);
} else if (req->rq_set) {
- /* If we have a vaid "rq_set", just reuse it to avoid double
+ /* If we have a valid "rq_set", just reuse it to avoid double
* linked. */
LASSERT(req->rq_phase == RQ_PHASE_NEW);
LASSERT(req->rq_send_state == LUSTRE_IMP_REPLAY);
@@ -471,7 +471,7 @@ static int ptlrpcd(void *arg)
* be better. But it breaks former data transfer policy.
*
* So we shouldn't be blind for avoiding the data transfer. We make some
- * compromise: divide the ptlrpcd threds pool into two parts. One part is
+ * compromise: divide the ptlrpcd threads pool into two parts. One part is
* for bound mode, each ptlrpcd thread in this part is bound to some CPU
* core. The other part is for free mode, all the ptlrpcd threads in the
* part can be scheduled on any CPU core. We specify some partnership
diff --git a/drivers/staging/lustre/lustre/ptlrpc/recover.c b/drivers/staging/lustre/lustre/ptlrpc/recover.c
index 84c39e083ea4..48ae328ce24e 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/recover.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/recover.c
@@ -105,24 +105,59 @@ int ptlrpc_replay_next(struct obd_import *imp, int *inflight)
* imp_lock is being held by ptlrpc_replay, but it's not. it's
* just a little race...
*/
- list_for_each_safe(tmp, pos, &imp->imp_replay_list) {
+
+ /* Replay all the committed open requests on committed_list first */
+ if (!list_empty(&imp->imp_committed_list)) {
+ tmp = imp->imp_committed_list.prev;
req = list_entry(tmp, struct ptlrpc_request,
rq_replay_list);
- /* If need to resend the last sent transno (because a
- reconnect has occurred), then stop on the matching
- req and send it again. If, however, the last sent
- transno has been committed then we continue replay
- from the next request. */
+ /* The last request on committed_list hasn't been replayed */
if (req->rq_transno > last_transno) {
- if (imp->imp_resend_replay)
- lustre_msg_add_flags(req->rq_reqmsg,
- MSG_RESENT);
- break;
+ /* Since the imp_committed_list is immutable before
+ * all of it's requests being replayed, it's safe to
+ * use a cursor to accelerate the search */
+ imp->imp_replay_cursor = imp->imp_replay_cursor->next;
+
+ while (imp->imp_replay_cursor !=
+ &imp->imp_committed_list) {
+ req = list_entry(imp->imp_replay_cursor,
+ struct ptlrpc_request,
+ rq_replay_list);
+ if (req->rq_transno > last_transno)
+ break;
+
+ req = NULL;
+ imp->imp_replay_cursor =
+ imp->imp_replay_cursor->next;
+ }
+ } else {
+ /* All requests on committed_list have been replayed */
+ imp->imp_replay_cursor = &imp->imp_committed_list;
+ req = NULL;
+ }
+ }
+
+ /* All the requests in committed list have been replayed, let's replay
+ * the imp_replay_list */
+ if (req == NULL) {
+ list_for_each_safe(tmp, pos, &imp->imp_replay_list) {
+ req = list_entry(tmp, struct ptlrpc_request,
+ rq_replay_list);
+
+ if (req->rq_transno > last_transno)
+ break;
+ req = NULL;
}
- req = NULL;
}
+ /* If need to resend the last sent transno (because a reconnect
+ * has occurred), then stop on the matching req and send it again.
+ * If, however, the last sent transno has been committed then we
+ * continue replay from the next request. */
+ if (req != NULL && imp->imp_resend_replay)
+ lustre_msg_add_flags(req->rq_reqmsg, MSG_RESENT);
+
spin_lock(&imp->imp_lock);
imp->imp_resend_replay = 0;
spin_unlock(&imp->imp_lock);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c
index 962b31d163de..d80418057f29 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c
@@ -543,8 +543,8 @@ int sptlrpc_req_replace_dead_ctx(struct ptlrpc_request *req)
"ctx (%p, fl %lx) doesn't switch, relax a little bit\n",
newctx, newctx->cc_flags);
- schedule_timeout_and_set_state(TASK_INTERRUPTIBLE,
- HZ);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ);
} else {
/*
* it's possible newctx == oldctx if we're switching
@@ -779,7 +779,7 @@ again:
* e.g. ptlrpc_abort_inflight();
*/
if (!cli_ctx_is_refreshed(ctx)) {
- /* timed out or interruptted */
+ /* timed out or interrupted */
req_off_ctx_list(req, ctx);
LASSERT(rc != 0);
@@ -805,7 +805,7 @@ void sptlrpc_req_set_flavor(struct ptlrpc_request *req, int opcode)
LASSERT(req->rq_cli_ctx->cc_sec);
LASSERT(req->rq_bulk_read == 0 || req->rq_bulk_write == 0);
- /* special security flags accoding to opcode */
+ /* special security flags according to opcode */
switch (opcode) {
case OST_READ:
case MDS_READPAGE:
@@ -1218,7 +1218,7 @@ static void sec_cop_destroy_sec(struct ptlrpc_sec *sec)
LASSERT_ATOMIC_ZERO(&sec->ps_nctx);
LASSERT(policy->sp_cops->destroy_sec);
- CDEBUG(D_SEC, "%s@%p: being destroied\n", sec->ps_policy->sp_name, sec);
+ CDEBUG(D_SEC, "%s@%p: being destroyed\n", sec->ps_policy->sp_name, sec);
policy->sp_cops->destroy_sec(sec);
sptlrpc_policy_put(policy);
@@ -1264,7 +1264,7 @@ void sptlrpc_sec_put(struct ptlrpc_sec *sec)
EXPORT_SYMBOL(sptlrpc_sec_put);
/*
- * policy module is responsible for taking refrence of import
+ * policy module is responsible for taking reference of import
*/
static
struct ptlrpc_sec * sptlrpc_sec_create(struct obd_import *imp,
@@ -1419,7 +1419,7 @@ int sptlrpc_import_sec_adapt(struct obd_import *imp,
sp = imp->imp_obd->u.cli.cl_sp_me;
} else {
- /* reverse import, determine flavor from incoming reqeust */
+ /* reverse import, determine flavor from incoming request */
sf = *flvr;
if (sf.sf_rpc != SPTLRPC_FLVR_NULL)
@@ -2057,7 +2057,7 @@ int sptlrpc_svc_unwrap_request(struct ptlrpc_request *req)
/*
* if it's not null flavor (which means embedded packing msg),
- * reset the swab mask for the comming inner msg unpacking.
+ * reset the swab mask for the coming inner msg unpacking.
*/
if (SPTLRPC_FLVR_POLICY(req->rq_flvr.sf_rpc) != SPTLRPC_POLICY_NULL)
req->rq_req_swab_mask = 0;
@@ -2108,7 +2108,7 @@ int sptlrpc_svc_alloc_rs(struct ptlrpc_request *req, int msglen)
/**
* Used by ptlrpc server, to perform transformation upon reply message.
*
- * \post req->rq_reply_off is set to approriate server-controlled reply offset.
+ * \post req->rq_reply_off is set to appropriate server-controlled reply offset.
* \post req->rq_repmsg and req->rq_reply_state->rs_msg becomes inaccessible.
*/
int sptlrpc_svc_wrap_reply(struct ptlrpc_request *req)
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
index 316103ab7c3c..965668132747 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
@@ -113,7 +113,7 @@ static struct ptlrpc_enc_page_pool {
unsigned long epp_st_missings; /* # of cache missing */
unsigned long epp_st_lowfree; /* lowest free pages reached */
unsigned int epp_st_max_wqlen; /* highest waitqueue length */
- cfs_time_t epp_st_max_wait; /* in jeffies */
+ cfs_time_t epp_st_max_wait; /* in jiffies */
/*
* pointers to pools
*/
@@ -545,11 +545,11 @@ again:
page_pools.epp_waitqlen;
set_current_state(TASK_UNINTERRUPTIBLE);
- init_waitqueue_entry_current(&waitlink);
+ init_waitqueue_entry(&waitlink, current);
add_wait_queue(&page_pools.epp_waitq, &waitlink);
spin_unlock(&page_pools.epp_lock);
- waitq_wait(&waitlink, TASK_UNINTERRUPTIBLE);
+ schedule();
remove_wait_queue(&page_pools.epp_waitq, &waitlink);
LASSERT(page_pools.epp_waitqlen > 0);
spin_lock(&page_pools.epp_lock);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
index 6cc3f23c27cc..bf56120abfaf 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
@@ -255,7 +255,7 @@ void sptlrpc_rule_set_free(struct sptlrpc_rule_set *rset)
EXPORT_SYMBOL(sptlrpc_rule_set_free);
/*
- * return 0 if the rule set could accomodate one more rule.
+ * return 0 if the rule set could accommodate one more rule.
*/
int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset)
{
diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c
index 590fa8df8b7f..192adec5382a 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/service.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/service.c
@@ -177,7 +177,7 @@ ptlrpc_grow_req_bufs(struct ptlrpc_service_part *svcpt, int post)
/**
* Part of Rep-Ack logic.
- * Puts a lock and its mode into reply state assotiated to request reply.
+ * Puts a lock and its mode into reply state associated to request reply.
*/
void
ptlrpc_save_lock(struct ptlrpc_request *req,
@@ -252,7 +252,7 @@ struct rs_batch {
static struct ptlrpc_hr_service ptlrpc_hr;
/**
- * maximum mumber of replies scheduled in one batch
+ * maximum number of replies scheduled in one batch
*/
#define MAX_SCHEDULED 256
@@ -612,7 +612,7 @@ ptlrpc_service_part_init(struct ptlrpc_service *svc,
INIT_LIST_HEAD(&svcpt->scp_hist_reqs);
INIT_LIST_HEAD(&svcpt->scp_hist_rqbds);
- /* acitve requests and hp requests */
+ /* active requests and hp requests */
spin_lock_init(&svcpt->scp_req_lock);
/* reply states */
@@ -752,7 +752,7 @@ ptlrpc_register_service(struct ptlrpc_service_conf *conf,
spin_lock_init(&service->srv_lock);
service->srv_name = conf->psc_name;
service->srv_watchdog_factor = conf->psc_watchdog_factor;
- INIT_LIST_HEAD(&service->srv_list); /* for safty of cleanup */
+ INIT_LIST_HEAD(&service->srv_list); /* for safety of cleanup */
/* buffer configuration */
service->srv_nbuf_per_group = test_req_buffer_pressure ?
@@ -1982,7 +1982,7 @@ put_conn:
do_gettimeofday(&work_end);
timediff = cfs_timeval_sub(&work_end, &work_start, NULL);
CDEBUG(D_RPCTRACE, "Handled RPC pname:cluuid+ref:pid:xid:nid:opc "
- "%s:%s+%d:%d:x"LPU64":%s:%d Request procesed in "
+ "%s:%s+%d:%d:x"LPU64":%s:%d Request processed in "
"%ldus (%ldus total) trans "LPU64" rc %d/%d\n",
current_comm(),
(request->rq_export ?
@@ -2736,7 +2736,7 @@ int ptlrpc_start_thread(struct ptlrpc_service_part *svcpt, int wait)
spin_lock(&svcpt->scp_lock);
--svcpt->scp_nthrs_starting;
if (thread_is_stopping(thread)) {
- /* this ptlrpc_thread is being hanled
+ /* this ptlrpc_thread is being handled
* by ptlrpc_svcpt_stop_threads now
*/
thread_add_flags(thread, SVC_STOPPED);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c
index 3aa445952024..3c8846006a7b 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c
@@ -1152,6 +1152,8 @@ void lustre_assert_wire_constants(void)
OBD_CONNECT_SHORTIO);
LASSERTF(OBD_CONNECT_PINGLESS == 0x4000000000000ULL, "found 0x%.16llxULL\n",
OBD_CONNECT_PINGLESS);
+ LASSERTF(OBD_CONNECT_FLOCK_DEAD == 0x8000000000000ULL,
+ "found 0x%.16llxULL\n", OBD_CONNECT_FLOCK_DEAD);
LASSERTF(OBD_CKSUM_CRC32 == 0x00000001UL, "found 0x%.8xUL\n",
(unsigned)OBD_CKSUM_CRC32);
LASSERTF(OBD_CKSUM_ADLER == 0x00000002UL, "found 0x%.8xUL\n",
diff --git a/drivers/staging/media/as102/as10x_handle.h b/drivers/staging/media/as102/as10x_handle.h
index 62b9795ee424..5638b191b780 100644
--- a/drivers/staging/media/as102/as10x_handle.h
+++ b/drivers/staging/media/as102/as10x_handle.h
@@ -28,26 +28,26 @@ struct as102_dev_t;
#define REGMODE32 32
struct as102_priv_ops_t {
- int (*upload_fw_pkt) (struct as10x_bus_adapter_t *bus_adap,
+ int (*upload_fw_pkt)(struct as10x_bus_adapter_t *bus_adap,
unsigned char *buf, int buflen, int swap32);
- int (*send_cmd) (struct as10x_bus_adapter_t *bus_adap,
+ int (*send_cmd)(struct as10x_bus_adapter_t *bus_adap,
unsigned char *buf, int buflen);
- int (*xfer_cmd) (struct as10x_bus_adapter_t *bus_adap,
+ int (*xfer_cmd)(struct as10x_bus_adapter_t *bus_adap,
unsigned char *send_buf, int send_buf_len,
unsigned char *recv_buf, int recv_buf_len);
- int (*start_stream) (struct as102_dev_t *dev);
- void (*stop_stream) (struct as102_dev_t *dev);
+ int (*start_stream)(struct as102_dev_t *dev);
+ void (*stop_stream)(struct as102_dev_t *dev);
- int (*reset_target) (struct as10x_bus_adapter_t *bus_adap);
+ int (*reset_target)(struct as10x_bus_adapter_t *bus_adap);
int (*read_write)(struct as10x_bus_adapter_t *bus_adap, uint8_t mode,
uint32_t rd_addr, uint16_t rd_len,
uint32_t wr_addr, uint16_t wr_len);
- int (*as102_read_ep2) (struct as10x_bus_adapter_t *bus_adap,
+ int (*as102_read_ep2)(struct as10x_bus_adapter_t *bus_adap,
unsigned char *recv_buf,
int recv_buf_len);
};
diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/staging/media/cxd2099/cxd2099.c
index 6cb74dacc69d..a2a5182570c5 100644
--- a/drivers/staging/media/cxd2099/cxd2099.c
+++ b/drivers/staging/media/cxd2099/cxd2099.c
@@ -329,11 +329,14 @@ static int init(struct cxd *ci)
break;
#if 0
- status = write_reg(ci, 0x09, 0x4D); /* Input Mode C, BYPass Serial, TIVAL = low, MSB */
+ /* Input Mode C, BYPass Serial, TIVAL = low, MSB */
+ status = write_reg(ci, 0x09, 0x4D);
if (status < 0)
break;
#endif
- status = write_reg(ci, 0x0A, 0xA7); /* TOSTRT = 8, Mode B (gated clock), falling Edge, Serial, POL=HIGH, MSB */
+ /* TOSTRT = 8, Mode B (gated clock), falling Edge,
+ * Serial, POL=HIGH, MSB */
+ status = write_reg(ci, 0x0A, 0xA7);
if (status < 0)
break;
@@ -589,7 +592,7 @@ static int campoll(struct cxd *ci)
read_reg(ci, 0x01, &slotstat);
if (!(2&slotstat)) {
if (!ci->slot_stat) {
- ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;
+ ci->slot_stat = DVB_CA_EN50221_POLL_CAM_PRESENT;
write_regm(ci, 0x03, 0x08, 0x08);
}
@@ -601,7 +604,8 @@ static int campoll(struct cxd *ci)
ci->ready = 0;
}
}
- if (istat&8 && ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) {
+ if (istat&8 &&
+ ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) {
ci->ready = 1;
ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY;
}
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.h b/drivers/staging/media/davinci_vpfe/vpfe_video.h
index df0aeec8b588..ca9a70245233 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.h
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.h
@@ -32,7 +32,7 @@ struct vpfe_device;
* if there was no buffer previously queued.
*/
struct vpfe_video_operations {
- int(*queue) (struct vpfe_device *vpfe_dev, unsigned long addr);
+ int (*queue)(struct vpfe_device *vpfe_dev, unsigned long addr);
};
enum vpfe_pipeline_stream_state {
diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c
index e729e52639c5..97e7a9b48ac2 100644
--- a/drivers/staging/media/dt3155v4l/dt3155v4l.c
+++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c
@@ -299,7 +299,7 @@ dt3155_buf_queue(struct vb2_buffer *vb)
* end driver-specific callbacks
*/
-const struct vb2_ops q_ops = {
+static const struct vb2_ops q_ops = {
.queue_setup = dt3155_queue_setup,
.wait_prepare = dt3155_wait_prepare,
.wait_finish = dt3155_wait_finish,
diff --git a/drivers/staging/media/go7007/go7007-loader.c b/drivers/staging/media/go7007/go7007-loader.c
index eecb1f2a5574..491d0e697f5a 100644
--- a/drivers/staging/media/go7007/go7007-loader.c
+++ b/drivers/staging/media/go7007/go7007-loader.c
@@ -28,7 +28,7 @@ struct fw_config {
const char * const fw_name2;
};
-struct fw_config fw_configs[] = {
+static struct fw_config fw_configs[] = {
{ 0x1943, 0xa250, "go7007/s2250-1.fw", "go7007/s2250-2.fw" },
{ 0x093b, 0xa002, "go7007/px-m402u.fw", NULL },
{ 0x093b, 0xa004, "go7007/px-tv402u.fw", NULL },
diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c
index edc52e2630a9..bdf414e19c8f 100644
--- a/drivers/staging/media/go7007/go7007-v4l2.c
+++ b/drivers/staging/media/go7007/go7007-v4l2.c
@@ -433,7 +433,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
return set_capture_size(go, fmt, 0);
}
-static int go7007_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+static int go7007_queue_setup(struct vb2_queue *q,
+ const struct v4l2_format *fmt,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
@@ -737,7 +738,8 @@ static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
if (a->index >= go->board_info->num_aud_inputs)
return -EINVAL;
- strlcpy(a->name, go->board_info->aud_inputs[a->index].name, sizeof(a->name));
+ strlcpy(a->name, go->board_info->aud_inputs[a->index].name,
+ sizeof(a->name));
a->capability = V4L2_AUDCAP_STEREO;
return 0;
}
@@ -747,12 +749,14 @@ static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
struct go7007 *go = video_drvdata(file);
a->index = go->aud_input;
- strlcpy(a->name, go->board_info->aud_inputs[go->aud_input].name, sizeof(a->name));
+ strlcpy(a->name, go->board_info->aud_inputs[go->aud_input].name,
+ sizeof(a->name));
a->capability = V4L2_AUDCAP_STEREO;
return 0;
}
-static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *a)
+static int vidioc_s_audio(struct file *file, void *fh,
+ const struct v4l2_audio *a)
{
struct go7007 *go = video_drvdata(file);
@@ -760,7 +764,7 @@ static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *
return -EINVAL;
go->aud_input = a->index;
v4l2_subdev_call(go->sd_audio, audio, s_routing,
- go->board_info->aud_inputs[go->aud_input].audio_input, 0, 0);
+ go->board_info->aud_inputs[go->aud_input].audio_input, 0, 0);
return 0;
}
@@ -960,8 +964,10 @@ int go7007_v4l2_ctrl_init(struct go7007 *go)
V4L2_MPEG_VIDEO_ASPECT_1x1);
ctrl = v4l2_ctrl_new_std(hdl, NULL,
V4L2_CID_JPEG_ACTIVE_MARKER, 0,
- V4L2_JPEG_ACTIVE_MARKER_DQT | V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
- V4L2_JPEG_ACTIVE_MARKER_DQT | V4L2_JPEG_ACTIVE_MARKER_DHT);
+ V4L2_JPEG_ACTIVE_MARKER_DQT |
+ V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
+ V4L2_JPEG_ACTIVE_MARKER_DQT |
+ V4L2_JPEG_ACTIVE_MARKER_DHT);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
if (hdl->error) {
diff --git a/drivers/staging/media/go7007/snd-go7007.c b/drivers/staging/media/go7007/snd-go7007.c
index 16dd64920767..9eb2a20ae40a 100644
--- a/drivers/staging/media/go7007/snd-go7007.c
+++ b/drivers/staging/media/go7007/snd-go7007.c
@@ -245,8 +245,8 @@ int go7007_snd_init(struct go7007 *go)
spin_lock_init(&gosnd->lock);
gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0;
gosnd->capturing = 0;
- ret = snd_card_create(index[dev], id[dev], THIS_MODULE, 0,
- &gosnd->card);
+ ret = snd_card_new(go->dev, index[dev], id[dev], THIS_MODULE, 0,
+ &gosnd->card);
if (ret < 0) {
kfree(gosnd);
return ret;
@@ -257,7 +257,6 @@ int go7007_snd_init(struct go7007 *go)
kfree(gosnd);
return ret;
}
- snd_card_set_dev(gosnd->card, go->dev);
ret = snd_pcm_new(gosnd->card, "go7007", 0, 0, 1, &gosnd->pcm);
if (ret < 0) {
snd_card_free(gosnd->card);
diff --git a/drivers/staging/media/lirc/lirc_igorplugusb.c b/drivers/staging/media/lirc/lirc_igorplugusb.c
index f2dcc4a292da..f508a1372ad8 100644
--- a/drivers/staging/media/lirc/lirc_igorplugusb.c
+++ b/drivers/staging/media/lirc/lirc_igorplugusb.c
@@ -62,7 +62,7 @@
/* debugging support */
#ifdef CONFIG_USB_DEBUG
-static bool debug = 1;
+static bool debug = true;
#else
static bool debug;
#endif
diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c
index f2d396cc4a4c..a5b62eec5e21 100644
--- a/drivers/staging/media/lirc/lirc_imon.c
+++ b/drivers/staging/media/lirc/lirc_imon.c
@@ -943,13 +943,17 @@ alloc_status_switch:
usb_free_urb(tx_urb);
case 6:
usb_free_urb(rx_urb);
+ /* fall-through */
case 5:
if (rbuf)
lirc_buffer_free(rbuf);
+ /* fall-through */
case 4:
kfree(rbuf);
+ /* fall-through */
case 3:
kfree(driver);
+ /* fall-through */
case 2:
kfree(context);
context = NULL;
diff --git a/drivers/staging/media/lirc/lirc_parallel.c b/drivers/staging/media/lirc/lirc_parallel.c
index 0b589892351a..62f5137b947b 100644
--- a/drivers/staging/media/lirc/lirc_parallel.c
+++ b/drivers/staging/media/lirc/lirc_parallel.c
@@ -68,29 +68,29 @@
static bool debug;
static bool check_pselecd;
-unsigned int irq = LIRC_IRQ;
-unsigned int io = LIRC_PORT;
+static unsigned int irq = LIRC_IRQ;
+static unsigned int io = LIRC_PORT;
#ifdef LIRC_TIMER
-unsigned int timer;
-unsigned int default_timer = LIRC_TIMER;
+static unsigned int timer;
+static unsigned int default_timer = LIRC_TIMER;
#endif
#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */
static int rbuf[RBUF_SIZE];
-DECLARE_WAIT_QUEUE_HEAD(lirc_wait);
+static DECLARE_WAIT_QUEUE_HEAD(lirc_wait);
-unsigned int rptr;
-unsigned int wptr;
-unsigned int lost_irqs;
-int is_open;
+static unsigned int rptr;
+static unsigned int wptr;
+static unsigned int lost_irqs;
+static int is_open;
-struct parport *pport;
-struct pardevice *ppdevice;
-int is_claimed;
+static struct parport *pport;
+static struct pardevice *ppdevice;
+static int is_claimed;
-unsigned int tx_mask = 1;
+static unsigned int tx_mask = 1;
/*** Internal Functions ***/
diff --git a/drivers/staging/media/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c
index d2445fdd9015..81f90e17e1e6 100644
--- a/drivers/staging/media/lirc/lirc_sasem.c
+++ b/drivers/staging/media/lirc/lirc_sasem.c
@@ -74,7 +74,7 @@ static void usb_tx_callback(struct urb *urb);
static int vfd_open(struct inode *inode, struct file *file);
static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg);
static int vfd_close(struct inode *inode, struct file *file);
-static ssize_t vfd_write(struct file *file, const char *buf,
+static ssize_t vfd_write(struct file *file, const char __user *buf,
size_t n_bytes, loff_t *pos);
/* LIRC driver function prototypes */
@@ -120,7 +120,7 @@ struct sasem_context {
static const struct file_operations vfd_fops = {
.owner = THIS_MODULE,
.open = &vfd_open,
- .write = &vfd_write,
+ .write = vfd_write,
.unlocked_ioctl = &vfd_ioctl,
.release = &vfd_close,
.llseek = noop_llseek,
@@ -360,7 +360,7 @@ static int send_packet(struct sasem_context *context)
* and requires data in 9 consecutive USB interrupt packets,
* each packet carrying 8 bytes.
*/
-static ssize_t vfd_write(struct file *file, const char *buf,
+static ssize_t vfd_write(struct file *file, const char __user *buf,
size_t n_bytes, loff_t *pos)
{
int i;
@@ -389,7 +389,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
goto exit;
}
- data_buf = memdup_user(buf, n_bytes);
+ data_buf = memdup_user((void const __user *)buf, n_bytes);
if (IS_ERR(data_buf)) {
retval = PTR_ERR(data_buf);
goto exit;
@@ -865,15 +865,20 @@ alloc_status_switch:
usb_free_urb(tx_urb);
case 6:
usb_free_urb(rx_urb);
+ /* fall-through */
case 5:
lirc_buffer_free(rbuf);
+ /* fall-through */
case 4:
kfree(rbuf);
+ /* fall-through */
case 3:
kfree(driver);
+ /* fall-through */
case 2:
kfree(context);
context = NULL;
+ /* fall-through */
case 1:
if (retval == 0)
retval = -ENOMEM;
diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c
index 4c3bf776bb20..5a0400fdb98c 100644
--- a/drivers/staging/media/msi3101/sdr-msi3101.c
+++ b/drivers/staging/media/msi3101/sdr-msi3101.c
@@ -411,7 +411,7 @@ struct msi3101_state {
unsigned int vb_full; /* vb is full and packets dropped */
struct urb *urbs[MAX_ISO_BUFS];
- int (*convert_stream) (struct msi3101_state *s, u32 *dst, u8 *src,
+ int (*convert_stream)(struct msi3101_state *s, u32 *dst, u8 *src,
unsigned int src_len);
/* Controls */
diff --git a/drivers/staging/media/omap24xx/tcm825x.c b/drivers/staging/media/omap24xx/tcm825x.c
index b1ae8e9c7e14..f4dd32df2353 100644
--- a/drivers/staging/media/omap24xx/tcm825x.c
+++ b/drivers/staging/media/omap24xx/tcm825x.c
@@ -249,11 +249,11 @@ static struct vcontrol {
};
-static const struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] =
-{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };
+static const struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] = {
+ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };
-static const struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] =
-{ &yuv422, &rgb565 };
+static const struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] = {
+ &yuv422, &rgb565 };
/*
* Read a value from a register in an TCM825X sensor device. The value is
diff --git a/drivers/staging/media/omap24xx/tcm825x.h b/drivers/staging/media/omap24xx/tcm825x.h
index e2d1bcd0bcbe..9970fb1c596a 100644
--- a/drivers/staging/media/omap24xx/tcm825x.h
+++ b/drivers/staging/media/omap24xx/tcm825x.h
@@ -178,7 +178,7 @@ struct tcm825x_platform_data {
/* Set power state, zero is off, non-zero is on. */
int (*power_set)(int power);
/* Default registers written after power-on or reset. */
- const struct tcm825x_reg *(*default_regs)(void);
+ const struct tcm825x_reg * (*default_regs)(void);
int (*needs_reset)(struct v4l2_int_device *s, void *buf,
struct v4l2_pix_format *fmt);
int (*ifparm)(struct v4l2_ifparm *p);
diff --git a/drivers/staging/media/sn9c102/sn9c102_core.c b/drivers/staging/media/sn9c102/sn9c102_core.c
index 2cb44de2b92c..71f594f5aa71 100644
--- a/drivers/staging/media/sn9c102/sn9c102_core.c
+++ b/drivers/staging/media/sn9c102/sn9c102_core.c
@@ -158,8 +158,8 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
cam->nbuffers = count;
while (cam->nbuffers > 0) {
- if ((buff = vmalloc_32_user(cam->nbuffers *
- PAGE_ALIGN(imagesize))))
+ buff = vmalloc_32_user(cam->nbuffers * PAGE_ALIGN(imagesize));
+ if (buff)
break;
cam->nbuffers--;
}
@@ -1121,7 +1121,8 @@ static ssize_t sn9c102_show_val(struct device* cd,
return -ENODEV;
}
- if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) {
+ val = sn9c102_read_reg(cam, cam->sysfs.reg);
+ if (val < 0) {
mutex_unlock(&sn9c102_sysfs_lock);
return -EIO;
}
@@ -1256,7 +1257,8 @@ static ssize_t sn9c102_show_i2c_val(struct device* cd,
return -ENOSYS;
}
- if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
+ val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg);
+ if (val < 0) {
mutex_unlock(&sn9c102_sysfs_lock);
return -EIO;
}
@@ -1440,27 +1442,35 @@ static int sn9c102_create_sysfs(struct sn9c102_device* cam)
struct device *dev = &(cam->v4ldev->dev);
int err = 0;
- if ((err = device_create_file(dev, &dev_attr_reg)))
+ err = device_create_file(dev, &dev_attr_reg);
+ if (err)
goto err_out;
- if ((err = device_create_file(dev, &dev_attr_val)))
+ err = device_create_file(dev, &dev_attr_val);
+ if (err)
goto err_reg;
- if ((err = device_create_file(dev, &dev_attr_frame_header)))
+ err = device_create_file(dev, &dev_attr_frame_header);
+ if (err)
goto err_val;
if (cam->sensor.sysfs_ops) {
- if ((err = device_create_file(dev, &dev_attr_i2c_reg)))
+ err = device_create_file(dev, &dev_attr_i2c_reg);
+ if (err)
goto err_frame_header;
- if ((err = device_create_file(dev, &dev_attr_i2c_val)))
+ err = device_create_file(dev, &dev_attr_i2c_val);
+ if (err)
goto err_i2c_reg;
}
if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
- if ((err = device_create_file(dev, &dev_attr_green)))
+ err = device_create_file(dev, &dev_attr_green);
+ if (err)
goto err_i2c_val;
} else {
- if ((err = device_create_file(dev, &dev_attr_blue)))
+ err = device_create_file(dev, &dev_attr_blue);
+ if (err)
goto err_i2c_val;
- if ((err = device_create_file(dev, &dev_attr_red)))
+ err = device_create_file(dev, &dev_attr_red);
+ if (err)
goto err_blue;
}
@@ -1684,11 +1694,13 @@ static int sn9c102_init(struct sn9c102_device* cam)
else
DBG(3, "Uncompressed video format is active");
- if (s->set_crop)
- if ((err = s->set_crop(cam, rect))) {
+ if (s->set_crop) {
+ err = s->set_crop(cam, rect);
+ if (err) {
DBG(3, "set_crop() failed");
return err;
}
+ }
if (s->set_ctrl) {
for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
@@ -1835,7 +1847,8 @@ static int sn9c102_open(struct file *filp)
cam->state &= ~DEV_MISCONFIGURED;
}
- if ((err = sn9c102_start_transfer(cam)))
+ err = sn9c102_start_transfer(cam);
+ if (err)
goto out;
filp->private_data = cam;
@@ -2308,7 +2321,8 @@ sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
}
if (i == ARRAY_SIZE(s->qctrl))
return -EINVAL;
- if ((err = s->set_ctrl(cam, &ctrl)))
+ err = s->set_ctrl(cam, &ctrl);
+ if (err)
return err;
s->_qctrl[i].default_value = ctrl.value;
@@ -2416,9 +2430,11 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
} else
scale = 1;
- if (cam->stream == STREAM_ON)
- if ((err = sn9c102_stream_interrupt(cam)))
+ if (cam->stream == STREAM_ON) {
+ err = sn9c102_stream_interrupt(cam);
+ if (err)
return err;
+ }
if (copy_to_user(arg, &crop, sizeof(crop))) {
cam->stream = stream;
@@ -2672,9 +2688,11 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
return -EBUSY;
}
- if (cam->stream == STREAM_ON)
- if ((err = sn9c102_stream_interrupt(cam)))
+ if (cam->stream == STREAM_ON) {
+ err = sn9c102_stream_interrupt(cam);
+ if (err)
return err;
+ }
if (copy_to_user(arg, &format, sizeof(format))) {
cam->stream = stream;
@@ -2746,9 +2764,11 @@ sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
if (jc.quality != 0 && jc.quality != 1)
return -EINVAL;
- if (cam->stream == STREAM_ON)
- if ((err = sn9c102_stream_interrupt(cam)))
+ if (cam->stream == STREAM_ON) {
+ err = sn9c102_stream_interrupt(cam);
+ if (err)
return err;
+ }
err += sn9c102_set_compression(cam, &jc);
if (err) { /* atomic, no rollback in ioctl() */
@@ -2794,9 +2814,11 @@ sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
return -EBUSY;
}
- if (cam->stream == STREAM_ON)
- if ((err = sn9c102_stream_interrupt(cam)))
+ if (cam->stream == STREAM_ON) {
+ err = sn9c102_stream_interrupt(cam);
+ if (err)
return err;
+ }
sn9c102_empty_framequeues(cam);
@@ -2974,9 +2996,11 @@ sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg)
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
return -EINVAL;
- if (cam->stream == STREAM_ON)
- if ((err = sn9c102_stream_interrupt(cam)))
+ if (cam->stream == STREAM_ON) {
+ err = sn9c102_stream_interrupt(cam);
+ if (err)
return err;
+ }
sn9c102_empty_framequeues(cam);
@@ -3250,7 +3274,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
unsigned int i;
int err = 0, r;
- if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL)))
+ cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL);
+ if (!cam)
return -ENOMEM;
cam->usbdev = udev;
@@ -3262,13 +3287,15 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail;
}
- if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
+ cam->control_buffer = kzalloc(8, GFP_KERNEL);
+ if (!cam->control_buffer) {
DBG(1, "kzalloc() failed");
err = -ENOMEM;
goto fail;
}
- if (!(cam->v4ldev = video_device_alloc())) {
+ cam->v4ldev = video_device_alloc();
+ if (!cam->v4ldev) {
DBG(1, "video_device_alloc() failed");
err = -ENOMEM;
goto fail;
diff --git a/drivers/staging/media/sn9c102/sn9c102_hv7131d.c b/drivers/staging/media/sn9c102/sn9c102_hv7131d.c
index 2dce5c908c8e..468072176527 100644
--- a/drivers/staging/media/sn9c102/sn9c102_hv7131d.c
+++ b/drivers/staging/media/sn9c102/sn9c102_hv7131d.c
@@ -53,27 +53,32 @@ static int hv7131d_get_ctrl(struct sn9c102_device* cam,
}
return 0;
case V4L2_CID_RED_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x31);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value = 0x3f - (ctrl->value & 0x3f);
return 0;
case V4L2_CID_BLUE_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x33);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value = 0x3f - (ctrl->value & 0x3f);
return 0;
case SN9C102_V4L2_CID_GREEN_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x32);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value = 0x3f - (ctrl->value & 0x3f);
return 0;
case SN9C102_V4L2_CID_RESET_LEVEL:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x30);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x3f;
return 0;
case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x34);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x07;
return 0;
diff --git a/drivers/staging/media/sn9c102/sn9c102_hv7131r.c b/drivers/staging/media/sn9c102/sn9c102_hv7131r.c
index 4295887ff609..26a91115b831 100644
--- a/drivers/staging/media/sn9c102/sn9c102_hv7131r.c
+++ b/drivers/staging/media/sn9c102/sn9c102_hv7131r.c
@@ -142,26 +142,31 @@ static int hv7131r_get_ctrl(struct sn9c102_device* cam,
{
switch (ctrl->id) {
case V4L2_CID_GAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x30);
+ if (ctrl->value < 0)
return -EIO;
return 0;
case V4L2_CID_RED_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x31);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value = ctrl->value & 0x3f;
return 0;
case V4L2_CID_BLUE_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x33);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value = ctrl->value & 0x3f;
return 0;
case SN9C102_V4L2_CID_GREEN_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x32);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value = ctrl->value & 0x3f;
return 0;
case V4L2_CID_BLACK_LEVEL:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x01);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value = (ctrl->value & 0x08) ? 1 : 0;
return 0;
diff --git a/drivers/staging/media/sn9c102/sn9c102_ov7630.c b/drivers/staging/media/sn9c102/sn9c102_ov7630.c
index 803712c29f02..d3a1bd8d5648 100644
--- a/drivers/staging/media/sn9c102/sn9c102_ov7630.c
+++ b/drivers/staging/media/sn9c102/sn9c102_ov7630.c
@@ -260,7 +260,8 @@ static int ov7630_get_ctrl(struct sn9c102_device* cam,
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x10);
+ if (ctrl->value < 0)
return -EIO;
break;
case V4L2_CID_RED_BALANCE:
@@ -280,37 +281,44 @@ static int ov7630_get_ctrl(struct sn9c102_device* cam,
break;
break;
case V4L2_CID_GAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x00);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x3f;
break;
case V4L2_CID_DO_WHITE_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x0c);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x3f;
break;
case V4L2_CID_WHITENESS:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x0d);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x3f;
break;
case V4L2_CID_AUTOGAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x13);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x01;
break;
case V4L2_CID_VFLIP:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x75)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x75);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value = (ctrl->value & 0x80) ? 1 : 0;
break;
case SN9C102_V4L2_CID_GAMMA:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x14)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x14);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
break;
case SN9C102_V4L2_CID_BAND_FILTER:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x2d)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x2d);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
break;
diff --git a/drivers/staging/media/sn9c102/sn9c102_ov7660.c b/drivers/staging/media/sn9c102/sn9c102_ov7660.c
index 7977795d342b..530157a234e6 100644
--- a/drivers/staging/media/sn9c102/sn9c102_ov7660.c
+++ b/drivers/staging/media/sn9c102/sn9c102_ov7660.c
@@ -278,41 +278,49 @@ static int ov7660_get_ctrl(struct sn9c102_device* cam,
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x10);
+ if (ctrl->value < 0)
return -EIO;
break;
case V4L2_CID_DO_WHITE_BALANCE:
- if ((ctrl->value = sn9c102_read_reg(cam, 0x02)) < 0)
+ ctrl->value = sn9c102_read_reg(cam, 0x02);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value = (ctrl->value & 0x04) ? 1 : 0;
break;
case V4L2_CID_RED_BALANCE:
- if ((ctrl->value = sn9c102_read_reg(cam, 0x05)) < 0)
+ ctrl->value = sn9c102_read_reg(cam, 0x05);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x7f;
break;
case V4L2_CID_BLUE_BALANCE:
- if ((ctrl->value = sn9c102_read_reg(cam, 0x06)) < 0)
+ ctrl->value = sn9c102_read_reg(cam, 0x06);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x7f;
break;
case SN9C102_V4L2_CID_GREEN_BALANCE:
- if ((ctrl->value = sn9c102_read_reg(cam, 0x07)) < 0)
+ ctrl->value = sn9c102_read_reg(cam, 0x07);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x7f;
break;
case SN9C102_V4L2_CID_BAND_FILTER:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x3b)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x3b);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x08;
break;
case V4L2_CID_GAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x00);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x1f;
break;
case V4L2_CID_AUTOGAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x13);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x01;
break;
diff --git a/drivers/staging/media/sn9c102/sn9c102_pas106b.c b/drivers/staging/media/sn9c102/sn9c102_pas106b.c
index 81cd969c1b7b..47bd82de80f9 100644
--- a/drivers/staging/media/sn9c102/sn9c102_pas106b.c
+++ b/drivers/staging/media/sn9c102/sn9c102_pas106b.c
@@ -62,32 +62,38 @@ static int pas106b_get_ctrl(struct sn9c102_device* cam,
}
return 0;
case V4L2_CID_RED_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x0c);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x1f;
return 0;
case V4L2_CID_BLUE_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x09);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x1f;
return 0;
case V4L2_CID_GAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x0e);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x1f;
return 0;
case V4L2_CID_CONTRAST:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x0f);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x07;
return 0;
case SN9C102_V4L2_CID_GREEN_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x0a);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value = (ctrl->value & 0x1f) << 1;
return 0;
case SN9C102_V4L2_CID_DAC_MAGNITUDE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x08);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0xf8;
return 0;
diff --git a/drivers/staging/media/sn9c102/sn9c102_pas202bcb.c b/drivers/staging/media/sn9c102/sn9c102_pas202bcb.c
index 2e86fdc86989..cbfacc2dad84 100644
--- a/drivers/staging/media/sn9c102/sn9c102_pas202bcb.c
+++ b/drivers/staging/media/sn9c102/sn9c102_pas202bcb.c
@@ -92,27 +92,32 @@ static int pas202bcb_get_ctrl(struct sn9c102_device* cam,
}
return 0;
case V4L2_CID_RED_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x09);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x0f;
return 0;
case V4L2_CID_BLUE_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x07);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x0f;
return 0;
case V4L2_CID_GAIN:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x10);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x1f;
return 0;
case SN9C102_V4L2_CID_GREEN_BALANCE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x08);
+ if (ctrl->value < 0)
return -EIO;
ctrl->value &= 0x0f;
return 0;
case SN9C102_V4L2_CID_DAC_MAGNITUDE:
- if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
+ ctrl->value = sn9c102_i2c_read(cam, 0x0c);
+ if (ctrl->value < 0)
return -EIO;
return 0;
default:
diff --git a/drivers/staging/media/solo6x10/solo6x10-core.c b/drivers/staging/media/solo6x10/solo6x10-core.c
index 480b7c4064cc..f67046955ef6 100644
--- a/drivers/staging/media/solo6x10/solo6x10-core.c
+++ b/drivers/staging/media/solo6x10/solo6x10-core.c
@@ -40,7 +40,7 @@ MODULE_AUTHOR("Bluecherry <maintainers@bluecherrydvr.com>");
MODULE_VERSION(SOLO6X10_VERSION);
MODULE_LICENSE("GPL");
-unsigned video_nr = -1;
+static unsigned video_nr = -1;
module_param(video_nr, uint, 0644);
MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
diff --git a/drivers/staging/media/solo6x10/solo6x10-g723.c b/drivers/staging/media/solo6x10/solo6x10-g723.c
index 1db18c7972a0..74f037b6166c 100644
--- a/drivers/staging/media/solo6x10/solo6x10-g723.c
+++ b/drivers/staging/media/solo6x10/solo6x10-g723.c
@@ -366,8 +366,9 @@ int solo_g723_init(struct solo_dev *solo_dev)
/* Allows for easier mapping between video and audio */
sprintf(name, "Softlogic%d", solo_dev->vfd->num);
- ret = snd_card_create(SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0,
- &solo_dev->snd_card);
+ ret = snd_card_new(&solo_dev->pdev->dev,
+ SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0,
+ &solo_dev->snd_card);
if (ret < 0)
return ret;
@@ -377,7 +378,6 @@ int solo_g723_init(struct solo_dev *solo_dev)
strcpy(card->shortname, "SOLO-6x10 Audio");
sprintf(card->longname, "%s on %s IRQ %d", card->shortname,
pci_name(solo_dev->pdev), solo_dev->pdev->irq);
- snd_card_set_dev(card, &solo_dev->pdev->dev);
ret = snd_device_new(card, SNDRV_DEV_LOWLEVEL, solo_dev, &ops);
if (ret < 0)
diff --git a/drivers/staging/media/solo6x10/solo6x10-tw28.c b/drivers/staging/media/solo6x10/solo6x10-tw28.c
index af65ea655f15..36daa1720b54 100644
--- a/drivers/staging/media/solo6x10/solo6x10-tw28.c
+++ b/drivers/staging/media/solo6x10/solo6x10-tw28.c
@@ -516,7 +516,7 @@ static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr)
static void saa712x_write_regs(struct solo_dev *dev, const uint8_t *vals,
int start, int n)
{
- for (;start < n; start++, vals++) {
+ for (; start < n; start++, vals++) {
/* Skip read-only registers */
switch (start) {
/* case 0x00 ... 0x25: */
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
index ce9e5aaf7fd4..5aeb9c0c2781 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
@@ -399,8 +399,8 @@ static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip,
if (solo_enc->desc_count <= 1)
return 0;
- return solo_p2m_dma_desc(solo_dev, solo_enc->desc_items, solo_enc->desc_dma,
- solo_enc->desc_count - 1);
+ return solo_p2m_dma_desc(solo_dev, solo_enc->desc_items,
+ solo_enc->desc_dma, solo_enc->desc_count - 1);
}
/* Extract values from VOP header - VE_STATUSxx */
@@ -472,8 +472,7 @@ static int solo_fill_jpeg(struct solo_enc_dev *solo_enc,
if (vb2_plane_size(vb, 0) < vop_jpeg_size(vh) + solo_enc->jpeg_len)
return -EIO;
- frame_size = (vop_jpeg_size(vh) + solo_enc->jpeg_len + (DMA_ALIGN - 1))
- & ~(DMA_ALIGN - 1);
+ frame_size = ALIGN(vop_jpeg_size(vh) + solo_enc->jpeg_len, DMA_ALIGN);
vb2_set_plane_payload(vb, 0, vop_jpeg_size(vh) + solo_enc->jpeg_len);
/* may discard all previous data in vbuf->sgl */
@@ -506,21 +505,22 @@ static int solo_fill_mpeg(struct solo_enc_dev *solo_enc,
return -EIO;
/* If this is a key frame, add extra header */
- vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME);
+ vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME |
+ V4L2_BUF_FLAG_BFRAME);
if (!vop_type(vh)) {
skip = solo_enc->vop_len;
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
- vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh) + solo_enc->vop_len);
+ vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh) +
+ solo_enc->vop_len);
} else {
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
vb2_set_plane_payload(vb, 0, vop_mpeg_size(vh));
}
/* Now get the actual mpeg payload */
- frame_off = (vop_mpeg_offset(vh) - SOLO_MP4E_EXT_ADDR(solo_dev) + sizeof(*vh))
- % SOLO_MP4E_EXT_SIZE(solo_dev);
- frame_size = (vop_mpeg_size(vh) + skip + (DMA_ALIGN - 1))
- & ~(DMA_ALIGN - 1);
+ frame_off = (vop_mpeg_offset(vh) - SOLO_MP4E_EXT_ADDR(solo_dev) +
+ sizeof(*vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
+ frame_size = ALIGN(vop_mpeg_size(vh) + skip, DMA_ALIGN);
/* may discard all previous data in vbuf->sgl */
dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
@@ -589,7 +589,8 @@ static void solo_enc_handle_one(struct solo_enc_dev *solo_enc,
spin_unlock_irqrestore(&solo_enc->av_lock, flags);
goto unlock;
}
- vb = list_first_entry(&solo_enc->vidq_active, struct solo_vb2_buf, list);
+ vb = list_first_entry(&solo_enc->vidq_active, struct solo_vb2_buf,
+ list);
list_del(&vb->list);
spin_unlock_irqrestore(&solo_enc->av_lock, flags);
@@ -645,7 +646,8 @@ static void solo_handle_ring(struct solo_dev *solo_dev)
enc_buf.vh = solo_dev->vh_buf;
/* Sanity check */
- if (vop_mpeg_offset(enc_buf.vh) != SOLO_MP4E_EXT_ADDR(solo_dev) + off)
+ if (vop_mpeg_offset(enc_buf.vh) !=
+ SOLO_MP4E_EXT_ADDR(solo_dev) + off)
continue;
if (solo_motion_detected(solo_enc))
@@ -680,9 +682,11 @@ static int solo_ring_thread(void *data)
return 0;
}
-static int solo_enc_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
- unsigned int *num_buffers, unsigned int *num_planes,
- unsigned int sizes[], void *alloc_ctxs[])
+static int solo_enc_queue_setup(struct vb2_queue *q,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *alloc_ctxs[])
{
sizes[0] = FRAME_BUF_SIZE;
*num_planes = 1;
@@ -1112,14 +1116,15 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
solo_enc->motion_thresh = ctrl->val;
if (!solo_enc->motion_global || !solo_enc->motion_enabled)
return 0;
- return solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->val);
+ return solo_set_motion_threshold(solo_dev, solo_enc->ch,
+ ctrl->val);
case V4L2_CID_MOTION_MODE:
solo_enc->motion_global = ctrl->val == 1;
solo_enc->motion_enabled = ctrl->val > 0;
if (ctrl->val) {
if (solo_enc->motion_global)
- solo_set_motion_threshold(solo_dev, solo_enc->ch,
- solo_enc->motion_thresh);
+ solo_set_motion_threshold(solo_dev,
+ solo_enc->ch, solo_enc->motion_thresh);
else
solo_set_motion_block(solo_dev, solo_enc->ch,
&solo_enc->motion_thresholds);
@@ -1307,7 +1312,8 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
solo_enc->desc_nelts = 32;
solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev,
sizeof(struct solo_p2m_desc) *
- solo_enc->desc_nelts, &solo_enc->desc_dma);
+ solo_enc->desc_nelts,
+ &solo_enc->desc_dma);
ret = -ENOMEM;
if (solo_enc->desc_items == NULL)
goto hdl_free;
diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c
index d8ea25486a33..c83e3375104b 100644
--- a/drivers/staging/netlogic/xlr_net.c
+++ b/drivers/staging/netlogic/xlr_net.c
@@ -307,7 +307,8 @@ static netdev_tx_t xlr_net_start_xmit(struct sk_buff *skb,
}
static u16 xlr_net_select_queue(struct net_device *ndev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv,
+ select_queue_fallback_t fallback)
{
return (u16)smp_processor_id();
}
@@ -614,8 +615,6 @@ static void xlr_config_translate_table(struct xlr_net_priv *priv)
k = (k + 1) % j;
b2 = bkts[k];
k = (k + 1) % j;
- val = ((c1 << 23) | (b1 << 17) | (use_bkt << 16) |
- (c2 << 7) | (b2 << 1) | (use_bkt << 0));
val = ((c1 << 23) | (b1 << 17) | (use_bkt << 16) |
(c2 << 7) | (b2 << 1) | (use_bkt << 0));
diff --git a/drivers/staging/nokia_h4p/Kconfig b/drivers/staging/nokia_h4p/Kconfig
new file mode 100644
index 000000000000..4336c0ad065b
--- /dev/null
+++ b/drivers/staging/nokia_h4p/Kconfig
@@ -0,0 +1,9 @@
+config BT_NOKIA_H4P
+ tristate "HCI driver with H4 Nokia extensions"
+ depends on BT && ARCH_OMAP
+ help
+ Bluetooth HCI driver with H4 extensions. This driver provides
+ support for H4+ Bluetooth chip with vendor-specific H4 extensions.
+
+ Say Y here to compile support for h4 extended devices into the kernel
+ or say M to compile it as module (btnokia_h4p).
diff --git a/drivers/staging/nokia_h4p/Makefile b/drivers/staging/nokia_h4p/Makefile
new file mode 100644
index 000000000000..9625db4a9af3
--- /dev/null
+++ b/drivers/staging/nokia_h4p/Makefile
@@ -0,0 +1,6 @@
+
+obj-$(CONFIG_BT_NOKIA_H4P) += btnokia_h4p.o
+btnokia_h4p-objs := nokia_core.o nokia_fw.o nokia_uart.o nokia_fw-csr.o \
+ nokia_fw-bcm.o nokia_fw-ti1273.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/staging/nokia_h4p/TODO b/drivers/staging/nokia_h4p/TODO
new file mode 100644
index 000000000000..0ec5823e0ca8
--- /dev/null
+++ b/drivers/staging/nokia_h4p/TODO
@@ -0,0 +1,132 @@
+Few attempts to submission have been made, last review comments were received in
+
+Date: Wed, 15 Jan 2014 19:01:51 -0800
+From: Marcel Holtmann <marcel@holtmann.org>
+Subject: Re: [PATCH v6] Bluetooth: Add hci_h4p driver
+
+Some code refactoring is still needed.
+
+TODO:
+
+> +++ b/drivers/bluetooth/hci_h4p.h
+
+can we please get the naming straight. File names do not start with
+hci_ anymore. We moved away from it since that term is too generic.
+
+> +struct hci_h4p_info {
+
+Can we please get rid of the hci_ prefix for everything. Copying from
+drivers that are over 10 years old is not a good idea. Please look at
+recent ones.
+
+> + struct timer_list lazy_release;
+
+Timer? Not delayed work?
+
+> +void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val);
+> +u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset);
+> +void hci_h4p_set_rts(struct hci_h4p_info *info, int active);
+> +int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active, int timeout_ms);
+> +void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+> +void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+> +void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed);
+> +int hci_h4p_reset_uart(struct hci_h4p_info *info);
+> +void hci_h4p_init_uart(struct hci_h4p_info *info);
+> +void hci_h4p_enable_tx(struct hci_h4p_info *info);
+> +void hci_h4p_store_regs(struct hci_h4p_info *info);
+> +void hci_h4p_restore_regs(struct hci_h4p_info *info);
+> +void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable);
+
+These are a lot of public functions. Are they all really needed or can
+the code be done smart.
+
+> +static ssize_t hci_h4p_store_bdaddr(struct device *dev,
+> + struct device_attribute *attr,
+> + const char *buf, size_t count)
+> +{
+> + struct hci_h4p_info *info = dev_get_drvdata(dev);
+
+Since none of these devices can function without having a valid
+address, the way this should work is that we should not register the
+HCI device when probing the platform device.
+
+The HCI device should be registered once a valid address has been
+written into the sysfs file. I do not want to play the tricks with
+bringing up the device without a valid address.
+
+> + hdev->close = hci_h4p_hci_close;
+> + hdev->flush = hci_h4p_hci_flush;
+> + hdev->send = hci_h4p_hci_send_frame;
+
+It needs to use hdev->setup to load the firmware. I assume the
+firmware only needs to be loaded once. That is exactly what
+hdev->setup does. It gets executed once.
+
+> + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
+Is this quirk really needed? Normally only Bluetooth 1.1 and early
+devices qualify for it.
+
+> +static int hci_h4p_bcm_set_bdaddr(struct hci_h4p_info *info, struct sk_buff *skb)
+> +{
+> + int i;
+> + static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
+> + int not_valid;
+
+Has this actually been confirmed that we can just randomly set an
+address out of the Nokia range. I do not think so. This is a pretty
+bad idea.
+
+I have no interest in merging a driver with such a hack.
+
+> + not_valid = 1;
+> + for (i = 0; i < 6; i++) {
+> + if (info->bd_addr[i] != 0x00) {
+> + not_valid = 0;
+> + break;
+> + }
+> + }
+
+Anybody every heard of memcmp or bacmp and BDADDR_ANY?
+
+> + if (not_valid) {
+> + dev_info(info->dev, "Valid bluetooth address not found,"
+> + " setting some random\n");
+> + /* When address is not valid, use some random */
+> + memcpy(info->bd_addr, nokia_oui, 3);
+> + get_random_bytes(info->bd_addr + 3, 3);
+> + }
+
+
+And why does every single chip firmware does this differently. Seriously, this is a mess.
+
+> +void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+> +{
+> + switch (info->man_id) {
+> + case H4P_ID_CSR:
+> + hci_h4p_bc4_parse_fw_event(info, skb);
+> + break;
+...
+> +}
+
+We have proper HCI sync command handling in recent kernels. I really
+do not know why this is hand coded these days. Check how the Intel
+firmware loading inside btusb.c does it.
+
+> +inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
+> +{
+> + return __raw_readb(info->uart_base + (offset << 2));
+> +}
+
+Inline in a *.c file for a non-static function. Makes no sense to me.
+
+> +/**
+> + * struct hci_h4p_platform data - hci_h4p Platform data structure
+> + */
+> +struct hci_h4p_platform_data {
+
+please have a proper name here. For example
+btnokia_h4p_platform_data.
+
+Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc:
+Pavel Machek <pavel@ucw.cz>
diff --git a/drivers/staging/nokia_h4p/hci_h4p.h b/drivers/staging/nokia_h4p/hci_h4p.h
new file mode 100644
index 000000000000..99c4da61a56c
--- /dev/null
+++ b/drivers/staging/nokia_h4p/hci_h4p.h
@@ -0,0 +1,222 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __DRIVERS_BLUETOOTH_HCI_H4P_H
+#define __DRIVERS_BLUETOOTH_HCI_H4P_H
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#define UART_SYSC_OMAP_RESET 0x03
+#define UART_SYSS_RESETDONE 0x01
+#define UART_OMAP_SCR_EMPTY_THR 0x08
+#define UART_OMAP_SCR_WAKEUP 0x10
+#define UART_OMAP_SSR_WAKEUP 0x02
+#define UART_OMAP_SSR_TXFULL 0x01
+
+#define UART_OMAP_SYSC_IDLEMODE 0x03
+#define UART_OMAP_SYSC_IDLEMASK (3 << UART_OMAP_SYSC_IDLEMODE)
+
+#define UART_OMAP_SYSC_FORCE_IDLE (0 << UART_OMAP_SYSC_IDLEMODE)
+#define UART_OMAP_SYSC_NO_IDLE (1 << UART_OMAP_SYSC_IDLEMODE)
+#define UART_OMAP_SYSC_SMART_IDLE (2 << UART_OMAP_SYSC_IDLEMODE)
+
+#define H4P_TRANSFER_MODE 1
+#define H4P_SCHED_TRANSFER_MODE 2
+#define H4P_ACTIVE_MODE 3
+
+struct hci_h4p_info {
+ struct timer_list lazy_release;
+ struct hci_dev *hdev;
+ spinlock_t lock;
+
+ void __iomem *uart_base;
+ unsigned long uart_phys_base;
+ int irq;
+ struct device *dev;
+ u8 chip_type;
+ u8 bt_wakeup_gpio;
+ u8 host_wakeup_gpio;
+ u8 reset_gpio;
+ u8 reset_gpio_shared;
+ u8 bt_sysclk;
+ u8 man_id;
+ u8 ver_id;
+
+ struct sk_buff_head fw_queue;
+ struct sk_buff *alive_cmd_skb;
+ struct completion init_completion;
+ struct completion fw_completion;
+ struct completion test_completion;
+ int fw_error;
+ int init_error;
+
+ struct sk_buff_head txq;
+
+ struct sk_buff *rx_skb;
+ long rx_count;
+ unsigned long rx_state;
+ unsigned long garbage_bytes;
+
+ u8 bd_addr[6];
+ struct sk_buff_head *fw_q;
+
+ int pm_enabled;
+ int tx_enabled;
+ int autorts;
+ int rx_enabled;
+ unsigned long pm_flags;
+
+ int tx_clocks_en;
+ int rx_clocks_en;
+ spinlock_t clocks_lock;
+ struct clk *uart_iclk;
+ struct clk *uart_fclk;
+ atomic_t clk_users;
+ u16 dll;
+ u16 dlh;
+ u16 ier;
+ u16 mdr1;
+ u16 efr;
+};
+
+struct hci_h4p_radio_hdr {
+ __u8 evt;
+ __u8 dlen;
+} __packed;
+
+struct hci_h4p_neg_hdr {
+ __u8 dlen;
+} __packed;
+#define H4P_NEG_HDR_SIZE 1
+
+#define H4P_NEG_REQ 0x00
+#define H4P_NEG_ACK 0x20
+#define H4P_NEG_NAK 0x40
+
+#define H4P_PROTO_PKT 0x44
+#define H4P_PROTO_BYTE 0x4c
+
+#define H4P_ID_CSR 0x02
+#define H4P_ID_BCM2048 0x04
+#define H4P_ID_TI1271 0x31
+
+struct hci_h4p_neg_cmd {
+ __u8 ack;
+ __u16 baud;
+ __u16 unused1;
+ __u8 proto;
+ __u16 sys_clk;
+ __u16 unused2;
+} __packed;
+
+struct hci_h4p_neg_evt {
+ __u8 ack;
+ __u16 baud;
+ __u16 unused1;
+ __u8 proto;
+ __u16 sys_clk;
+ __u16 unused2;
+ __u8 man_id;
+ __u8 ver_id;
+} __packed;
+
+#define H4P_ALIVE_REQ 0x55
+#define H4P_ALIVE_RESP 0xcc
+
+struct hci_h4p_alive_hdr {
+ __u8 dlen;
+} __packed;
+#define H4P_ALIVE_HDR_SIZE 1
+
+struct hci_h4p_alive_pkt {
+ __u8 mid;
+ __u8 unused;
+} __packed;
+
+#define MAX_BAUD_RATE 921600
+#define BC4_MAX_BAUD_RATE 3692300
+#define UART_CLOCK 48000000
+#define BT_INIT_DIVIDER 320
+#define BT_BAUDRATE_DIVIDER 384000000
+#define BT_SYSCLK_DIV 1000
+#define INIT_SPEED 120000
+
+#define H4_TYPE_SIZE 1
+#define H4_RADIO_HDR_SIZE 2
+
+/* H4+ packet types */
+#define H4_CMD_PKT 0x01
+#define H4_ACL_PKT 0x02
+#define H4_SCO_PKT 0x03
+#define H4_EVT_PKT 0x04
+#define H4_NEG_PKT 0x06
+#define H4_ALIVE_PKT 0x07
+#define H4_RADIO_PKT 0x08
+
+/* TX states */
+#define WAIT_FOR_PKT_TYPE 1
+#define WAIT_FOR_HEADER 2
+#define WAIT_FOR_DATA 3
+
+struct hci_fw_event {
+ struct hci_event_hdr hev;
+ struct hci_ev_cmd_complete cmd;
+ u8 status;
+} __packed;
+
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info);
+
+void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb);
+int hci_h4p_bcm_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue);
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb);
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue);
+
+void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb);
+int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue);
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb);
+
+void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val);
+u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset);
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active);
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active, int timeout_ms);
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed);
+int hci_h4p_reset_uart(struct hci_h4p_info *info);
+void hci_h4p_init_uart(struct hci_h4p_info *info);
+void hci_h4p_enable_tx(struct hci_h4p_info *info);
+void hci_h4p_store_regs(struct hci_h4p_info *info);
+void hci_h4p_restore_regs(struct hci_h4p_info *info);
+void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable);
+
+#endif /* __DRIVERS_BLUETOOTH_HCI_H4P_H */
diff --git a/drivers/staging/nokia_h4p/nokia_core.c b/drivers/staging/nokia_h4p/nokia_core.c
new file mode 100644
index 000000000000..5e19cd6ccda3
--- /dev/null
+++ b/drivers/staging/nokia_h4p/nokia_core.c
@@ -0,0 +1,1206 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Thanks to all the Nokia people that helped with this driver,
+ * including Ville Tervo and Roger Quadros.
+ *
+ * Power saving functionality was removed from this driver to make
+ * merging easier.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/serial_reg.h>
+#include <linux/skbuff.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/timer.h>
+#include <linux/kthread.h>
+#include <linux/io.h>
+#include <linux/completion.h>
+#include <linux/sizes.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include <linux/platform_data/bt-nokia-h4p.h>
+
+#include "hci_h4p.h"
+
+/* This should be used in function that cannot release clocks */
+static void hci_h4p_set_clk(struct hci_h4p_info *info, int *clock, int enable)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->clocks_lock, flags);
+ if (enable && !*clock) {
+ BT_DBG("Enabling %p", clock);
+ clk_prepare_enable(info->uart_fclk);
+ clk_prepare_enable(info->uart_iclk);
+ if (atomic_read(&info->clk_users) == 0)
+ hci_h4p_restore_regs(info);
+ atomic_inc(&info->clk_users);
+ }
+
+ if (!enable && *clock) {
+ BT_DBG("Disabling %p", clock);
+ if (atomic_dec_and_test(&info->clk_users))
+ hci_h4p_store_regs(info);
+ clk_disable_unprepare(info->uart_fclk);
+ clk_disable_unprepare(info->uart_iclk);
+ }
+
+ *clock = enable;
+ spin_unlock_irqrestore(&info->clocks_lock, flags);
+}
+
+static void hci_h4p_lazy_clock_release(unsigned long data)
+{
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->lock, flags);
+ if (!info->tx_enabled)
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+/* Power management functions */
+void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable)
+{
+ u8 v;
+
+ v = hci_h4p_inb(info, UART_OMAP_SYSC);
+ v &= ~(UART_OMAP_SYSC_IDLEMASK);
+
+ if (enable)
+ v |= UART_OMAP_SYSC_SMART_IDLE;
+ else
+ v |= UART_OMAP_SYSC_NO_IDLE;
+
+ hci_h4p_outb(info, UART_OMAP_SYSC, v);
+}
+
+static inline void h4p_schedule_pm(struct hci_h4p_info *info)
+{
+}
+
+static void hci_h4p_disable_tx(struct hci_h4p_info *info)
+{
+ if (!info->pm_enabled)
+ return;
+
+ /* Re-enable smart-idle */
+ hci_h4p_smart_idle(info, 1);
+
+ gpio_set_value(info->bt_wakeup_gpio, 0);
+ mod_timer(&info->lazy_release, jiffies + msecs_to_jiffies(100));
+ info->tx_enabled = 0;
+}
+
+void hci_h4p_enable_tx(struct hci_h4p_info *info)
+{
+ unsigned long flags;
+
+ if (!info->pm_enabled)
+ return;
+
+ h4p_schedule_pm(info);
+
+ spin_lock_irqsave(&info->lock, flags);
+ del_timer(&info->lazy_release);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ info->tx_enabled = 1;
+ gpio_set_value(info->bt_wakeup_gpio, 1);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ /*
+ * Disable smart-idle as UART TX interrupts
+ * are not wake-up capable
+ */
+ hci_h4p_smart_idle(info, 0);
+
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static void hci_h4p_disable_rx(struct hci_h4p_info *info)
+{
+ if (!info->pm_enabled)
+ return;
+
+ info->rx_enabled = 0;
+
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR)
+ return;
+
+ if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT))
+ return;
+
+ __hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+ info->autorts = 0;
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+}
+
+static void hci_h4p_enable_rx(struct hci_h4p_info *info)
+{
+ if (!info->pm_enabled)
+ return;
+
+ h4p_schedule_pm(info);
+
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+ info->rx_enabled = 1;
+
+ if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT))
+ return;
+
+ __hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+ info->autorts = 1;
+}
+
+/* Negotiation functions */
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info)
+{
+ struct hci_h4p_alive_hdr *hdr;
+ struct hci_h4p_alive_pkt *pkt;
+ struct sk_buff *skb;
+ unsigned long flags;
+ int len;
+
+ BT_DBG("Sending alive packet");
+
+ len = H4_TYPE_SIZE + sizeof(*hdr) + sizeof(*pkt);
+ skb = bt_skb_alloc(len, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ memset(skb->data, 0x00, len);
+ *skb_put(skb, 1) = H4_ALIVE_PKT;
+ hdr = (struct hci_h4p_alive_hdr *)skb_put(skb, sizeof(*hdr));
+ hdr->dlen = sizeof(*pkt);
+ pkt = (struct hci_h4p_alive_pkt *)skb_put(skb, sizeof(*pkt));
+ pkt->mid = H4P_ALIVE_REQ;
+
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ BT_DBG("Alive packet sent");
+
+ return 0;
+}
+
+static void hci_h4p_alive_packet(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ struct hci_h4p_alive_hdr *hdr;
+ struct hci_h4p_alive_pkt *pkt;
+
+ BT_DBG("Received alive packet");
+ hdr = (struct hci_h4p_alive_hdr *)skb->data;
+ if (hdr->dlen != sizeof(*pkt)) {
+ dev_err(info->dev, "Corrupted alive message\n");
+ info->init_error = -EIO;
+ goto finish_alive;
+ }
+
+ pkt = (struct hci_h4p_alive_pkt *)skb_pull(skb, sizeof(*hdr));
+ if (pkt->mid != H4P_ALIVE_RESP) {
+ dev_err(info->dev, "Could not negotiate hci_h4p settings\n");
+ info->init_error = -EINVAL;
+ }
+
+finish_alive:
+ complete(&info->init_completion);
+ kfree_skb(skb);
+}
+
+static int hci_h4p_send_negotiation(struct hci_h4p_info *info)
+{
+ struct hci_h4p_neg_cmd *neg_cmd;
+ struct hci_h4p_neg_hdr *neg_hdr;
+ struct sk_buff *skb;
+ unsigned long flags;
+ int err, len;
+ u16 sysclk;
+
+ BT_DBG("Sending negotiation..");
+
+ switch (info->bt_sysclk) {
+ case 1:
+ sysclk = 12000;
+ break;
+ case 2:
+ sysclk = 38400;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ len = sizeof(*neg_cmd) + sizeof(*neg_hdr) + H4_TYPE_SIZE;
+ skb = bt_skb_alloc(len, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ memset(skb->data, 0x00, len);
+ *skb_put(skb, 1) = H4_NEG_PKT;
+ neg_hdr = (struct hci_h4p_neg_hdr *)skb_put(skb, sizeof(*neg_hdr));
+ neg_cmd = (struct hci_h4p_neg_cmd *)skb_put(skb, sizeof(*neg_cmd));
+
+ neg_hdr->dlen = sizeof(*neg_cmd);
+ neg_cmd->ack = H4P_NEG_REQ;
+ neg_cmd->baud = cpu_to_le16(BT_BAUDRATE_DIVIDER/MAX_BAUD_RATE);
+ neg_cmd->proto = H4P_PROTO_BYTE;
+ neg_cmd->sys_clk = cpu_to_le16(sysclk);
+
+ hci_h4p_change_speed(info, INIT_SPEED);
+
+ hci_h4p_set_rts(info, 1);
+ info->init_error = 0;
+ init_completion(&info->init_completion);
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ if (!wait_for_completion_interruptible_timeout(&info->init_completion,
+ msecs_to_jiffies(1000)))
+ return -ETIMEDOUT;
+
+ if (info->init_error < 0)
+ return info->init_error;
+
+ /* Change to operational settings */
+ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+ hci_h4p_set_rts(info, 0);
+ hci_h4p_change_speed(info, MAX_BAUD_RATE);
+
+ err = hci_h4p_wait_for_cts(info, 1, 100);
+ if (err < 0)
+ return err;
+
+ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+ init_completion(&info->init_completion);
+ err = hci_h4p_send_alive_packet(info);
+
+ if (err < 0)
+ return err;
+
+ if (!wait_for_completion_interruptible_timeout(&info->init_completion,
+ msecs_to_jiffies(1000)))
+ return -ETIMEDOUT;
+
+ if (info->init_error < 0)
+ return info->init_error;
+
+ BT_DBG("Negotiation successful");
+ return 0;
+}
+
+static void hci_h4p_negotiation_packet(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ struct hci_h4p_neg_hdr *hdr;
+ struct hci_h4p_neg_evt *evt;
+
+ hdr = (struct hci_h4p_neg_hdr *)skb->data;
+ if (hdr->dlen != sizeof(*evt)) {
+ info->init_error = -EIO;
+ goto finish_neg;
+ }
+
+ evt = (struct hci_h4p_neg_evt *)skb_pull(skb, sizeof(*hdr));
+
+ if (evt->ack != H4P_NEG_ACK) {
+ dev_err(info->dev, "Could not negotiate hci_h4p settings\n");
+ info->init_error = -EINVAL;
+ }
+
+ info->man_id = evt->man_id;
+ info->ver_id = evt->ver_id;
+
+finish_neg:
+
+ complete(&info->init_completion);
+ kfree_skb(skb);
+}
+
+/* H4 packet handling functions */
+static int hci_h4p_get_hdr_len(struct hci_h4p_info *info, u8 pkt_type)
+{
+ long retval;
+
+ switch (pkt_type) {
+ case H4_EVT_PKT:
+ retval = HCI_EVENT_HDR_SIZE;
+ break;
+ case H4_ACL_PKT:
+ retval = HCI_ACL_HDR_SIZE;
+ break;
+ case H4_SCO_PKT:
+ retval = HCI_SCO_HDR_SIZE;
+ break;
+ case H4_NEG_PKT:
+ retval = H4P_NEG_HDR_SIZE;
+ break;
+ case H4_ALIVE_PKT:
+ retval = H4P_ALIVE_HDR_SIZE;
+ break;
+ case H4_RADIO_PKT:
+ retval = H4_RADIO_HDR_SIZE;
+ break;
+ default:
+ dev_err(info->dev, "Unknown H4 packet type 0x%.2x\n", pkt_type);
+ retval = -1;
+ break;
+ }
+
+ return retval;
+}
+
+static unsigned int hci_h4p_get_data_len(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ long retval = -1;
+ struct hci_acl_hdr *acl_hdr;
+ struct hci_sco_hdr *sco_hdr;
+ struct hci_event_hdr *evt_hdr;
+ struct hci_h4p_neg_hdr *neg_hdr;
+ struct hci_h4p_alive_hdr *alive_hdr;
+ struct hci_h4p_radio_hdr *radio_hdr;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case H4_EVT_PKT:
+ evt_hdr = (struct hci_event_hdr *)skb->data;
+ retval = evt_hdr->plen;
+ break;
+ case H4_ACL_PKT:
+ acl_hdr = (struct hci_acl_hdr *)skb->data;
+ retval = le16_to_cpu(acl_hdr->dlen);
+ break;
+ case H4_SCO_PKT:
+ sco_hdr = (struct hci_sco_hdr *)skb->data;
+ retval = sco_hdr->dlen;
+ break;
+ case H4_RADIO_PKT:
+ radio_hdr = (struct hci_h4p_radio_hdr *)skb->data;
+ retval = radio_hdr->dlen;
+ break;
+ case H4_NEG_PKT:
+ neg_hdr = (struct hci_h4p_neg_hdr *)skb->data;
+ retval = neg_hdr->dlen;
+ break;
+ case H4_ALIVE_PKT:
+ alive_hdr = (struct hci_h4p_alive_hdr *)skb->data;
+ retval = alive_hdr->dlen;
+ break;
+ }
+
+ return retval;
+}
+
+static inline void hci_h4p_recv_frame(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) {
+ switch (bt_cb(skb)->pkt_type) {
+ case H4_NEG_PKT:
+ hci_h4p_negotiation_packet(info, skb);
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ return;
+ case H4_ALIVE_PKT:
+ hci_h4p_alive_packet(info, skb);
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ return;
+ }
+
+ if (!test_bit(HCI_UP, &info->hdev->flags)) {
+ BT_DBG("fw_event");
+ hci_h4p_parse_fw_event(info, skb);
+ return;
+ }
+ }
+
+ hci_recv_frame(info->hdev, skb);
+ BT_DBG("Frame sent to upper layer");
+}
+
+static inline void hci_h4p_handle_byte(struct hci_h4p_info *info, u8 byte)
+{
+ switch (info->rx_state) {
+ case WAIT_FOR_PKT_TYPE:
+ bt_cb(info->rx_skb)->pkt_type = byte;
+ info->rx_count = hci_h4p_get_hdr_len(info, byte);
+ if (info->rx_count < 0) {
+ info->hdev->stat.err_rx++;
+ kfree_skb(info->rx_skb);
+ info->rx_skb = NULL;
+ } else {
+ info->rx_state = WAIT_FOR_HEADER;
+ }
+ break;
+ case WAIT_FOR_HEADER:
+ info->rx_count--;
+ *skb_put(info->rx_skb, 1) = byte;
+ if (info->rx_count != 0)
+ break;
+ info->rx_count = hci_h4p_get_data_len(info, info->rx_skb);
+ if (info->rx_count > skb_tailroom(info->rx_skb)) {
+ dev_err(info->dev, "frame too long\n");
+ info->garbage_bytes = info->rx_count
+ - skb_tailroom(info->rx_skb);
+ kfree_skb(info->rx_skb);
+ info->rx_skb = NULL;
+ break;
+ }
+ info->rx_state = WAIT_FOR_DATA;
+ break;
+ case WAIT_FOR_DATA:
+ info->rx_count--;
+ *skb_put(info->rx_skb, 1) = byte;
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ if (info->rx_count == 0) {
+ /* H4+ devices should always send word aligned packets */
+ if (!(info->rx_skb->len % 2))
+ info->garbage_bytes++;
+ hci_h4p_recv_frame(info, info->rx_skb);
+ info->rx_skb = NULL;
+ }
+}
+
+static void hci_h4p_rx_tasklet(unsigned long data)
+{
+ u8 byte;
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+ BT_DBG("tasklet woke up");
+ BT_DBG("rx_tasklet woke up");
+
+ while (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+ byte = hci_h4p_inb(info, UART_RX);
+ if (info->garbage_bytes) {
+ info->garbage_bytes--;
+ continue;
+ }
+ if (info->rx_skb == NULL) {
+ info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE,
+ GFP_ATOMIC | GFP_DMA);
+ if (!info->rx_skb) {
+ dev_err(info->dev,
+ "No memory for new packet\n");
+ goto finish_rx;
+ }
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ info->rx_skb->dev = (void *)info->hdev;
+ }
+ info->hdev->stat.byte_rx++;
+ hci_h4p_handle_byte(info, byte);
+ }
+
+ if (!info->rx_enabled) {
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT &&
+ info->autorts) {
+ __hci_h4p_set_auto_ctsrts(info, 0 , UART_EFR_RTS);
+ info->autorts = 0;
+ }
+ /* Flush posted write to avoid spurious interrupts */
+ hci_h4p_inb(info, UART_OMAP_SCR);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+ }
+
+finish_rx:
+ BT_DBG("rx_ended");
+}
+
+static void hci_h4p_tx_tasklet(unsigned long data)
+{
+ unsigned int sent = 0;
+ struct sk_buff *skb;
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+ BT_DBG("tasklet woke up");
+ BT_DBG("tx_tasklet woke up");
+
+ if (info->autorts != info->rx_enabled) {
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
+ if (info->autorts && !info->rx_enabled) {
+ __hci_h4p_set_auto_ctsrts(info, 0,
+ UART_EFR_RTS);
+ info->autorts = 0;
+ }
+ if (!info->autorts && info->rx_enabled) {
+ __hci_h4p_set_auto_ctsrts(info, 1,
+ UART_EFR_RTS);
+ info->autorts = 1;
+ }
+ } else {
+ hci_h4p_outb(info, UART_OMAP_SCR,
+ hci_h4p_inb(info, UART_OMAP_SCR) |
+ UART_OMAP_SCR_EMPTY_THR);
+ goto finish_tx;
+ }
+ }
+
+ skb = skb_dequeue(&info->txq);
+ if (!skb) {
+ /* No data in buffer */
+ BT_DBG("skb ready");
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
+ hci_h4p_outb(info, UART_IER,
+ hci_h4p_inb(info, UART_IER) &
+ ~UART_IER_THRI);
+ hci_h4p_inb(info, UART_OMAP_SCR);
+ hci_h4p_disable_tx(info);
+ return;
+ }
+ hci_h4p_outb(info, UART_OMAP_SCR,
+ hci_h4p_inb(info, UART_OMAP_SCR) |
+ UART_OMAP_SCR_EMPTY_THR);
+ goto finish_tx;
+ }
+
+ /* Copy data to tx fifo */
+ while (!(hci_h4p_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
+ (sent < skb->len)) {
+ hci_h4p_outb(info, UART_TX, skb->data[sent]);
+ sent++;
+ }
+
+ info->hdev->stat.byte_tx += sent;
+ if (skb->len == sent) {
+ kfree_skb(skb);
+ } else {
+ skb_pull(skb, sent);
+ skb_queue_head(&info->txq, skb);
+ }
+
+ hci_h4p_outb(info, UART_OMAP_SCR, hci_h4p_inb(info, UART_OMAP_SCR) &
+ ~UART_OMAP_SCR_EMPTY_THR);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+
+finish_tx:
+ /* Flush posted write to avoid spurious interrupts */
+ hci_h4p_inb(info, UART_OMAP_SCR);
+
+}
+
+static irqreturn_t hci_h4p_interrupt(int irq, void *data)
+{
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+ u8 iir, msr;
+ int ret;
+
+ ret = IRQ_NONE;
+
+ iir = hci_h4p_inb(info, UART_IIR);
+ if (iir & UART_IIR_NO_INT)
+ return IRQ_HANDLED;
+
+ BT_DBG("In interrupt handler iir 0x%.2x", iir);
+
+ iir &= UART_IIR_ID;
+
+ if (iir == UART_IIR_MSI) {
+ msr = hci_h4p_inb(info, UART_MSR);
+ ret = IRQ_HANDLED;
+ }
+ if (iir == UART_IIR_RLSI) {
+ hci_h4p_inb(info, UART_RX);
+ hci_h4p_inb(info, UART_LSR);
+ ret = IRQ_HANDLED;
+ }
+
+ if (iir == UART_IIR_RDI) {
+ hci_h4p_rx_tasklet((unsigned long)data);
+ ret = IRQ_HANDLED;
+ }
+
+ if (iir == UART_IIR_THRI) {
+ hci_h4p_tx_tasklet((unsigned long)data);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static irqreturn_t hci_h4p_wakeup_interrupt(int irq, void *dev_inst)
+{
+ struct hci_h4p_info *info = dev_inst;
+ int should_wakeup;
+ struct hci_dev *hdev;
+
+ if (!info->hdev)
+ return IRQ_HANDLED;
+
+ should_wakeup = gpio_get_value(info->host_wakeup_gpio);
+ hdev = info->hdev;
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ if (should_wakeup == 1)
+ complete_all(&info->test_completion);
+
+ return IRQ_HANDLED;
+ }
+
+ BT_DBG("gpio interrupt %d", should_wakeup);
+
+ /* Check if wee have missed some interrupts */
+ if (info->rx_enabled == should_wakeup)
+ return IRQ_HANDLED;
+
+ if (should_wakeup)
+ hci_h4p_enable_rx(info);
+ else
+ hci_h4p_disable_rx(info);
+
+ return IRQ_HANDLED;
+}
+
+static inline void hci_h4p_set_pm_limits(struct hci_h4p_info *info, bool set)
+{
+ struct hci_h4p_platform_data *bt_plat_data = info->dev->platform_data;
+ const char *sset = set ? "set" : "clear";
+
+ if (unlikely(!bt_plat_data || !bt_plat_data->set_pm_limits))
+ return;
+
+ if (set != !!test_bit(H4P_ACTIVE_MODE, &info->pm_flags)) {
+ bt_plat_data->set_pm_limits(info->dev, set);
+ if (set)
+ set_bit(H4P_ACTIVE_MODE, &info->pm_flags);
+ else
+ clear_bit(H4P_ACTIVE_MODE, &info->pm_flags);
+ BT_DBG("Change pm constraints to: %s", sset);
+ return;
+ }
+
+ BT_DBG("pm constraints remains: %s", sset);
+}
+
+static int hci_h4p_reset(struct hci_h4p_info *info)
+{
+ int err;
+
+ err = hci_h4p_reset_uart(info);
+ if (err < 0) {
+ dev_err(info->dev, "Uart reset failed\n");
+ return err;
+ }
+ hci_h4p_init_uart(info);
+ hci_h4p_set_rts(info, 0);
+
+ gpio_set_value(info->reset_gpio, 0);
+ gpio_set_value(info->bt_wakeup_gpio, 1);
+ msleep(10);
+
+ if (gpio_get_value(info->host_wakeup_gpio) == 1) {
+ dev_err(info->dev, "host_wakeup_gpio not low\n");
+ return -EPROTO;
+ }
+
+ init_completion(&info->test_completion);
+ gpio_set_value(info->reset_gpio, 1);
+
+ if (!wait_for_completion_interruptible_timeout(&info->test_completion,
+ msecs_to_jiffies(100))) {
+ dev_err(info->dev, "wakeup test timed out\n");
+ complete_all(&info->test_completion);
+ return -EPROTO;
+ }
+
+ err = hci_h4p_wait_for_cts(info, 1, 100);
+ if (err < 0) {
+ dev_err(info->dev, "No cts from bt chip\n");
+ return err;
+ }
+
+ hci_h4p_set_rts(info, 1);
+
+ return 0;
+}
+
+/* hci callback functions */
+static int hci_h4p_hci_flush(struct hci_dev *hdev)
+{
+ struct hci_h4p_info *info = hci_get_drvdata(hdev);
+ skb_queue_purge(&info->txq);
+
+ return 0;
+}
+
+static int hci_h4p_bt_wakeup_test(struct hci_h4p_info *info)
+{
+ /*
+ * Test Sequence:
+ * Host de-asserts the BT_WAKE_UP line.
+ * Host polls the UART_CTS line, waiting for it to be de-asserted.
+ * Host asserts the BT_WAKE_UP line.
+ * Host polls the UART_CTS line, waiting for it to be asserted.
+ * Host de-asserts the BT_WAKE_UP line (allow the Bluetooth device to
+ * sleep).
+ * Host polls the UART_CTS line, waiting for it to be de-asserted.
+ */
+ int err;
+ int ret = -ECOMM;
+
+ if (!info)
+ return -EINVAL;
+
+ /* Disable wakeup interrupts */
+ disable_irq(gpio_to_irq(info->host_wakeup_gpio));
+
+ gpio_set_value(info->bt_wakeup_gpio, 0);
+ err = hci_h4p_wait_for_cts(info, 0, 100);
+ if (err) {
+ dev_warn(info->dev,
+ "bt_wakeup_test: fail: CTS low timed out: %d\n",
+ err);
+ goto out;
+ }
+
+ gpio_set_value(info->bt_wakeup_gpio, 1);
+ err = hci_h4p_wait_for_cts(info, 1, 100);
+ if (err) {
+ dev_warn(info->dev,
+ "bt_wakeup_test: fail: CTS high timed out: %d\n",
+ err);
+ goto out;
+ }
+
+ gpio_set_value(info->bt_wakeup_gpio, 0);
+ err = hci_h4p_wait_for_cts(info, 0, 100);
+ if (err) {
+ dev_warn(info->dev,
+ "bt_wakeup_test: fail: CTS re-low timed out: %d\n",
+ err);
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+
+ /* Re-enable wakeup interrupts */
+ enable_irq(gpio_to_irq(info->host_wakeup_gpio));
+
+ return ret;
+}
+
+static int hci_h4p_hci_open(struct hci_dev *hdev)
+{
+ struct hci_h4p_info *info;
+ int err, retries = 0;
+ struct sk_buff_head fw_queue;
+ unsigned long flags;
+
+ info = hci_get_drvdata(hdev);
+
+ if (test_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ /* TI1271 has HW bug and boot up might fail. Retry up to three times */
+again:
+
+ info->rx_enabled = 1;
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ info->rx_count = 0;
+ info->garbage_bytes = 0;
+ info->rx_skb = NULL;
+ info->pm_enabled = 0;
+ init_completion(&info->fw_completion);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+ skb_queue_head_init(&fw_queue);
+
+ err = hci_h4p_reset(info);
+ if (err < 0)
+ goto err_clean;
+
+ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_CTS | UART_EFR_RTS);
+ info->autorts = 1;
+
+ err = hci_h4p_send_negotiation(info);
+
+ err = hci_h4p_read_fw(info, &fw_queue);
+ if (err < 0) {
+ dev_err(info->dev, "Cannot read firmware\n");
+ goto err_clean;
+ }
+
+ err = hci_h4p_send_fw(info, &fw_queue);
+ if (err < 0) {
+ dev_err(info->dev, "Sending firmware failed.\n");
+ goto err_clean;
+ }
+
+ info->pm_enabled = 1;
+
+ err = hci_h4p_bt_wakeup_test(info);
+ if (err < 0) {
+ dev_err(info->dev, "BT wakeup test failed.\n");
+ goto err_clean;
+ }
+
+ spin_lock_irqsave(&info->lock, flags);
+ info->rx_enabled = gpio_get_value(info->host_wakeup_gpio);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, info->rx_enabled);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+
+ kfree_skb(info->alive_cmd_skb);
+ info->alive_cmd_skb = NULL;
+ set_bit(HCI_RUNNING, &hdev->flags);
+
+ BT_DBG("hci up and running");
+ return 0;
+
+err_clean:
+ hci_h4p_hci_flush(hdev);
+ hci_h4p_reset_uart(info);
+ del_timer_sync(&info->lazy_release);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+ gpio_set_value(info->reset_gpio, 0);
+ gpio_set_value(info->bt_wakeup_gpio, 0);
+ skb_queue_purge(&fw_queue);
+ kfree_skb(info->alive_cmd_skb);
+ info->alive_cmd_skb = NULL;
+ kfree_skb(info->rx_skb);
+ info->rx_skb = NULL;
+
+ if (retries++ < 3) {
+ dev_err(info->dev, "FW loading try %d fail. Retry.\n", retries);
+ goto again;
+ }
+
+ return err;
+}
+
+static int hci_h4p_hci_close(struct hci_dev *hdev)
+{
+ struct hci_h4p_info *info = hci_get_drvdata(hdev);
+
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ hci_h4p_hci_flush(hdev);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+ hci_h4p_reset_uart(info);
+ del_timer_sync(&info->lazy_release);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+ gpio_set_value(info->reset_gpio, 0);
+ gpio_set_value(info->bt_wakeup_gpio, 0);
+ kfree_skb(info->rx_skb);
+
+ return 0;
+}
+
+static int hci_h4p_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_h4p_info *info;
+ int err = 0;
+
+ BT_DBG("dev %p, skb %p", hdev, skb);
+
+ info = hci_get_drvdata(hdev);
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ dev_warn(info->dev, "Frame for non-running device\n");
+ return -EIO;
+ }
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ break;
+ }
+
+ /* Push frame type to skb */
+ *skb_push(skb, 1) = (bt_cb(skb)->pkt_type);
+ /* We should allways send word aligned data to h4+ devices */
+ if (skb->len % 2) {
+ err = skb_pad(skb, 1);
+ if (!err)
+ *skb_put(skb, 1) = 0x00;
+ }
+ if (err)
+ return err;
+
+ skb_queue_tail(&info->txq, skb);
+ hci_h4p_enable_tx(info);
+
+ return 0;
+}
+
+static ssize_t hci_h4p_store_bdaddr(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hci_h4p_info *info = dev_get_drvdata(dev);
+ unsigned int bdaddr[6];
+ int ret, i;
+
+ ret = sscanf(buf, "%2x:%2x:%2x:%2x:%2x:%2x\n",
+ &bdaddr[0], &bdaddr[1], &bdaddr[2],
+ &bdaddr[3], &bdaddr[4], &bdaddr[5]);
+
+ if (ret != 6)
+ return -EINVAL;
+
+ for (i = 0; i < 6; i++) {
+ if (bdaddr[i] > 0xff)
+ return -EINVAL;
+ info->bd_addr[i] = bdaddr[i] & 0xff;
+ }
+
+ return count;
+}
+
+static ssize_t hci_h4p_show_bdaddr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hci_h4p_info *info = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%pMR\n", info->bd_addr);
+}
+
+static DEVICE_ATTR(bdaddr, S_IRUGO | S_IWUSR, hci_h4p_show_bdaddr,
+ hci_h4p_store_bdaddr);
+
+static int hci_h4p_sysfs_create_files(struct device *dev)
+{
+ return device_create_file(dev, &dev_attr_bdaddr);
+}
+
+static void hci_h4p_sysfs_remove_files(struct device *dev)
+{
+ device_remove_file(dev, &dev_attr_bdaddr);
+}
+
+static int hci_h4p_register_hdev(struct hci_h4p_info *info)
+{
+ struct hci_dev *hdev;
+
+ /* Initialize and register HCI device */
+
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ dev_err(info->dev, "Can't allocate memory for device\n");
+ return -ENOMEM;
+ }
+ info->hdev = hdev;
+
+ hdev->bus = HCI_UART;
+ hci_set_drvdata(hdev, info);
+
+ hdev->open = hci_h4p_hci_open;
+ hdev->close = hci_h4p_hci_close;
+ hdev->flush = hci_h4p_hci_flush;
+ hdev->send = hci_h4p_hci_send_frame;
+ set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
+ SET_HCIDEV_DEV(hdev, info->dev);
+
+ if (hci_h4p_sysfs_create_files(info->dev) < 0) {
+ dev_err(info->dev, "failed to create sysfs files\n");
+ goto free;
+ }
+
+ if (hci_register_dev(hdev) >= 0)
+ return 0;
+
+ dev_err(info->dev, "hci_register failed %s.\n", hdev->name);
+ hci_h4p_sysfs_remove_files(info->dev);
+free:
+ hci_free_dev(info->hdev);
+ return -ENODEV;
+}
+
+static int hci_h4p_probe(struct platform_device *pdev)
+{
+ struct hci_h4p_platform_data *bt_plat_data;
+ struct hci_h4p_info *info;
+ int err;
+
+ dev_info(&pdev->dev, "Registering HCI H4P device\n");
+ info = devm_kzalloc(&pdev->dev, sizeof(struct hci_h4p_info),
+ GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->dev = &pdev->dev;
+ info->tx_enabled = 1;
+ info->rx_enabled = 1;
+ spin_lock_init(&info->lock);
+ spin_lock_init(&info->clocks_lock);
+ skb_queue_head_init(&info->txq);
+
+ if (pdev->dev.platform_data == NULL) {
+ dev_err(&pdev->dev, "Could not get Bluetooth config data\n");
+ return -ENODATA;
+ }
+
+ bt_plat_data = pdev->dev.platform_data;
+ info->chip_type = bt_plat_data->chip_type;
+ info->bt_wakeup_gpio = bt_plat_data->bt_wakeup_gpio;
+ info->host_wakeup_gpio = bt_plat_data->host_wakeup_gpio;
+ info->reset_gpio = bt_plat_data->reset_gpio;
+ info->reset_gpio_shared = bt_plat_data->reset_gpio_shared;
+ info->bt_sysclk = bt_plat_data->bt_sysclk;
+
+ BT_DBG("RESET gpio: %d", info->reset_gpio);
+ BT_DBG("BTWU gpio: %d", info->bt_wakeup_gpio);
+ BT_DBG("HOSTWU gpio: %d", info->host_wakeup_gpio);
+ BT_DBG("sysclk: %d", info->bt_sysclk);
+
+ init_completion(&info->test_completion);
+ complete_all(&info->test_completion);
+
+ if (!info->reset_gpio_shared) {
+ err = devm_gpio_request_one(&pdev->dev, info->reset_gpio,
+ GPIOF_OUT_INIT_LOW, "bt_reset");
+ if (err < 0) {
+ dev_err(&pdev->dev, "Cannot get GPIO line %d\n",
+ info->reset_gpio);
+ return err;
+ }
+ }
+
+ err = devm_gpio_request_one(&pdev->dev, info->bt_wakeup_gpio,
+ GPIOF_OUT_INIT_LOW, "bt_wakeup");
+
+ if (err < 0) {
+ dev_err(info->dev, "Cannot get GPIO line 0x%d",
+ info->bt_wakeup_gpio);
+ return err;
+ }
+
+ err = devm_gpio_request_one(&pdev->dev, info->host_wakeup_gpio,
+ GPIOF_DIR_IN, "host_wakeup");
+ if (err < 0) {
+ dev_err(info->dev, "Cannot get GPIO line %d",
+ info->host_wakeup_gpio);
+ return err;
+ }
+
+ info->irq = bt_plat_data->uart_irq;
+ info->uart_base = devm_ioremap(&pdev->dev, bt_plat_data->uart_base,
+ SZ_2K);
+ info->uart_iclk = devm_clk_get(&pdev->dev, bt_plat_data->uart_iclk);
+ info->uart_fclk = devm_clk_get(&pdev->dev, bt_plat_data->uart_fclk);
+
+ err = devm_request_irq(&pdev->dev, info->irq, hci_h4p_interrupt,
+ IRQF_DISABLED, "hci_h4p", info);
+ if (err < 0) {
+ dev_err(info->dev, "hci_h4p: unable to get IRQ %d\n",
+ info->irq);
+ return err;
+ }
+
+ err = devm_request_irq(&pdev->dev, gpio_to_irq(info->host_wakeup_gpio),
+ hci_h4p_wakeup_interrupt, IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING | IRQF_DISABLED,
+ "hci_h4p_wkup", info);
+ if (err < 0) {
+ dev_err(info->dev, "hci_h4p: unable to get wakeup IRQ %d\n",
+ gpio_to_irq(info->host_wakeup_gpio));
+ return err;
+ }
+
+ err = irq_set_irq_wake(gpio_to_irq(info->host_wakeup_gpio), 1);
+ if (err < 0) {
+ dev_err(info->dev, "hci_h4p: unable to set wakeup for IRQ %d\n",
+ gpio_to_irq(info->host_wakeup_gpio));
+ return err;
+ }
+
+ init_timer_deferrable(&info->lazy_release);
+ info->lazy_release.function = hci_h4p_lazy_clock_release;
+ info->lazy_release.data = (unsigned long)info;
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ err = hci_h4p_reset_uart(info);
+ if (err < 0)
+ return err;
+ gpio_set_value(info->reset_gpio, 0);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+
+ platform_set_drvdata(pdev, info);
+
+ if (hci_h4p_register_hdev(info) < 0) {
+ dev_err(info->dev, "failed to register hci_h4p hci device\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hci_h4p_remove(struct platform_device *pdev)
+{
+ struct hci_h4p_info *info;
+
+ info = platform_get_drvdata(pdev);
+
+ hci_h4p_sysfs_remove_files(info->dev);
+ hci_h4p_hci_close(info->hdev);
+ hci_unregister_dev(info->hdev);
+ hci_free_dev(info->hdev);
+
+ return 0;
+}
+
+static struct platform_driver hci_h4p_driver = {
+ .probe = hci_h4p_probe,
+ .remove = hci_h4p_remove,
+ .driver = {
+ .name = "hci_h4p",
+ },
+};
+
+module_platform_driver(hci_h4p_driver);
+
+MODULE_ALIAS("platform:hci_h4p");
+MODULE_DESCRIPTION("Bluetooth h4 driver with nokia extensions");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ville Tervo");
diff --git a/drivers/staging/nokia_h4p/nokia_fw-bcm.c b/drivers/staging/nokia_h4p/nokia_fw-bcm.c
new file mode 100644
index 000000000000..111ae94032d1
--- /dev/null
+++ b/drivers/staging/nokia_h4p/nokia_fw-bcm.c
@@ -0,0 +1,148 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+static int hci_h4p_bcm_set_bdaddr(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ int i;
+ static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
+ int not_valid;
+
+ not_valid = 1;
+ for (i = 0; i < 6; i++) {
+ if (info->bd_addr[i] != 0x00) {
+ not_valid = 0;
+ break;
+ }
+ }
+
+ if (not_valid) {
+ dev_info(info->dev, "Valid bluetooth address not found, setting some random\n");
+ /* When address is not valid, use some random but Nokia MAC */
+ memcpy(info->bd_addr, nokia_oui, 3);
+ get_random_bytes(info->bd_addr + 3, 3);
+ }
+
+ for (i = 0; i < 6; i++)
+ skb->data[9 - i] = info->bd_addr[i];
+
+ return 0;
+}
+
+void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ struct sk_buff *fw_skb;
+ int err;
+ unsigned long flags;
+
+ if (skb->data[5] != 0x00) {
+ dev_err(info->dev, "Firmware sending command failed 0x%.2x\n",
+ skb->data[5]);
+ info->fw_error = -EPROTO;
+ }
+
+ kfree_skb(skb);
+
+ fw_skb = skb_dequeue(info->fw_q);
+ if (fw_skb == NULL || info->fw_error) {
+ complete(&info->fw_completion);
+ return;
+ }
+
+ if (fw_skb->data[1] == 0x01 && fw_skb->data[2] == 0xfc && fw_skb->len >= 10) {
+ BT_DBG("Setting bluetooth address");
+ err = hci_h4p_bcm_set_bdaddr(info, fw_skb);
+ if (err < 0) {
+ kfree_skb(fw_skb);
+ info->fw_error = err;
+ complete(&info->fw_completion);
+ return;
+ }
+ }
+
+ skb_queue_tail(&info->txq, fw_skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+
+int hci_h4p_bcm_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue)
+{
+ struct sk_buff *skb;
+ unsigned long flags, time;
+
+ info->fw_error = 0;
+
+ BT_DBG("Sending firmware");
+
+ time = jiffies;
+
+ info->fw_q = fw_queue;
+ skb = skb_dequeue(fw_queue);
+ if (!skb)
+ return -ENODATA;
+
+ BT_DBG("Sending commands");
+
+ /*
+ * Disable smart-idle as UART TX interrupts
+ * are not wake-up capable
+ */
+ hci_h4p_smart_idle(info, 0);
+
+ /* Check if this is bd_address packet */
+ init_completion(&info->fw_completion);
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ if (!wait_for_completion_timeout(&info->fw_completion,
+ msecs_to_jiffies(2000))) {
+ dev_err(info->dev, "No reply to fw command\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info->fw_error) {
+ dev_err(info->dev, "FW error\n");
+ return -EPROTO;
+ }
+
+ BT_DBG("Firmware sent in %d msecs",
+ jiffies_to_msecs(jiffies-time));
+
+ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+ hci_h4p_set_rts(info, 0);
+ hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+
+ return 0;
+}
diff --git a/drivers/staging/nokia_h4p/nokia_fw-csr.c b/drivers/staging/nokia_h4p/nokia_fw-csr.c
new file mode 100644
index 000000000000..fe6b704b3d97
--- /dev/null
+++ b/drivers/staging/nokia_h4p/nokia_fw-csr.c
@@ -0,0 +1,149 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ /* Check if this is fw packet */
+ if (skb->data[0] != 0xff) {
+ hci_recv_frame(info->hdev, skb);
+ return;
+ }
+
+ if (skb->data[11] || skb->data[12]) {
+ dev_err(info->dev, "Firmware sending command failed\n");
+ info->fw_error = -EPROTO;
+ }
+
+ kfree_skb(skb);
+ complete(&info->fw_completion);
+}
+
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue)
+{
+ static const u8 nokia_oui[3] = {0x00, 0x19, 0x4F};
+ struct sk_buff *skb;
+ unsigned int offset;
+ int retries, count, i, not_valid;
+ unsigned long flags;
+
+ info->fw_error = 0;
+
+ BT_DBG("Sending firmware");
+ skb = skb_dequeue(fw_queue);
+
+ if (!skb)
+ return -ENOMSG;
+
+ /* Check if this is bd_address packet */
+ if (skb->data[15] == 0x01 && skb->data[16] == 0x00) {
+ offset = 21;
+ skb->data[offset + 1] = 0x00;
+ skb->data[offset + 5] = 0x00;
+
+ not_valid = 1;
+ for (i = 0; i < 6; i++) {
+ if (info->bd_addr[i] != 0x00) {
+ not_valid = 0;
+ break;
+ }
+ }
+
+ if (not_valid) {
+ dev_info(info->dev, "Valid bluetooth address not found, setting some random\n");
+ /* When address is not valid, use some random */
+ memcpy(info->bd_addr, nokia_oui, 3);
+ get_random_bytes(info->bd_addr + 3, 3);
+ }
+
+ skb->data[offset + 7] = info->bd_addr[0];
+ skb->data[offset + 6] = info->bd_addr[1];
+ skb->data[offset + 4] = info->bd_addr[2];
+ skb->data[offset + 0] = info->bd_addr[3];
+ skb->data[offset + 3] = info->bd_addr[4];
+ skb->data[offset + 2] = info->bd_addr[5];
+ }
+
+ for (count = 1; ; count++) {
+ BT_DBG("Sending firmware command %d", count);
+ init_completion(&info->fw_completion);
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ skb = skb_dequeue(fw_queue);
+ if (!skb)
+ break;
+
+ if (!wait_for_completion_timeout(&info->fw_completion,
+ msecs_to_jiffies(1000))) {
+ dev_err(info->dev, "No reply to fw command\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info->fw_error) {
+ dev_err(info->dev, "FW error\n");
+ return -EPROTO;
+ }
+ };
+
+ /* Wait for chip warm reset */
+ retries = 100;
+ while ((!skb_queue_empty(&info->txq) ||
+ !(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) &&
+ retries--) {
+ msleep(10);
+ }
+ if (!retries) {
+ dev_err(info->dev, "Transmitter not empty\n");
+ return -ETIMEDOUT;
+ }
+
+ hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+
+ if (hci_h4p_wait_for_cts(info, 1, 100)) {
+ dev_err(info->dev, "cts didn't deassert after final speed\n");
+ return -ETIMEDOUT;
+ }
+
+ retries = 100;
+ do {
+ init_completion(&info->init_completion);
+ hci_h4p_send_alive_packet(info);
+ retries--;
+ } while (!wait_for_completion_timeout(&info->init_completion, 100) &&
+ retries > 0);
+
+ if (!retries) {
+ dev_err(info->dev, "No alive reply after speed change\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
diff --git a/drivers/staging/nokia_h4p/nokia_fw-ti1273.c b/drivers/staging/nokia_h4p/nokia_fw-ti1273.c
new file mode 100644
index 000000000000..f5500f71c839
--- /dev/null
+++ b/drivers/staging/nokia_h4p/nokia_fw-ti1273.c
@@ -0,0 +1,110 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+static struct sk_buff_head *fw_q;
+
+void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ struct sk_buff *fw_skb;
+ unsigned long flags;
+
+ if (skb->data[5] != 0x00) {
+ dev_err(info->dev, "Firmware sending command failed 0x%.2x\n",
+ skb->data[5]);
+ info->fw_error = -EPROTO;
+ }
+
+ kfree_skb(skb);
+
+ fw_skb = skb_dequeue(fw_q);
+ if (fw_skb == NULL || info->fw_error) {
+ complete(&info->fw_completion);
+ return;
+ }
+
+ skb_queue_tail(&info->txq, fw_skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+
+int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue)
+{
+ struct sk_buff *skb;
+ unsigned long flags, time;
+
+ info->fw_error = 0;
+
+ BT_DBG("Sending firmware");
+
+ time = jiffies;
+
+ fw_q = fw_queue;
+ skb = skb_dequeue(fw_queue);
+ if (!skb)
+ return -ENODATA;
+
+ BT_DBG("Sending commands");
+ /* Check if this is bd_address packet */
+ init_completion(&info->fw_completion);
+ hci_h4p_smart_idle(info, 0);
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ if (!wait_for_completion_timeout(&info->fw_completion,
+ msecs_to_jiffies(2000))) {
+ dev_err(info->dev, "No reply to fw command\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info->fw_error) {
+ dev_err(info->dev, "FW error\n");
+ return -EPROTO;
+ }
+
+ BT_DBG("Firmware sent in %d msecs",
+ jiffies_to_msecs(jiffies-time));
+
+ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+ hci_h4p_set_rts(info, 0);
+ hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+ if (hci_h4p_wait_for_cts(info, 1, 100)) {
+ dev_err(info->dev,
+ "cts didn't go down after final speed change\n");
+ return -ETIMEDOUT;
+ }
+ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+
+ return 0;
+}
diff --git a/drivers/staging/nokia_h4p/nokia_fw.c b/drivers/staging/nokia_h4p/nokia_fw.c
new file mode 100644
index 000000000000..14ba2193efb6
--- /dev/null
+++ b/drivers/staging/nokia_h4p/nokia_fw.c
@@ -0,0 +1,208 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+
+#include <net/bluetooth/bluetooth.h>
+
+#include "hci_h4p.h"
+
+#define FW_NAME_TI1271_PRELE "ti1273_prele.bin"
+#define FW_NAME_TI1271_LE "ti1273_le.bin"
+#define FW_NAME_TI1271 "ti1273.bin"
+#define FW_NAME_BCM2048 "bcmfw.bin"
+#define FW_NAME_CSR "bc4fw.bin"
+
+static int fw_pos;
+
+/* Firmware handling */
+static int hci_h4p_open_firmware(struct hci_h4p_info *info,
+ const struct firmware **fw_entry)
+{
+ int err;
+
+ fw_pos = 0;
+ BT_DBG("Opening firmware man_id 0x%.2x ver_id 0x%.2x",
+ info->man_id, info->ver_id);
+ switch (info->man_id) {
+ case H4P_ID_TI1271:
+ switch (info->ver_id) {
+ case 0xe1:
+ err = request_firmware(fw_entry, FW_NAME_TI1271_PRELE,
+ info->dev);
+ break;
+ case 0xd1:
+ case 0xf1:
+ err = request_firmware(fw_entry, FW_NAME_TI1271_LE,
+ info->dev);
+ break;
+ default:
+ err = request_firmware(fw_entry, FW_NAME_TI1271,
+ info->dev);
+ }
+ break;
+ case H4P_ID_CSR:
+ err = request_firmware(fw_entry, FW_NAME_CSR, info->dev);
+ break;
+ case H4P_ID_BCM2048:
+ err = request_firmware(fw_entry, FW_NAME_BCM2048, info->dev);
+ break;
+ default:
+ dev_err(info->dev, "Invalid chip type\n");
+ *fw_entry = NULL;
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static void hci_h4p_close_firmware(const struct firmware *fw_entry)
+{
+ release_firmware(fw_entry);
+}
+
+/* Read fw. Return length of the command. If no more commands in
+ * fw 0 is returned. In error case return value is negative.
+ */
+static int hci_h4p_read_fw_cmd(struct hci_h4p_info *info, struct sk_buff **skb,
+ const struct firmware *fw_entry, gfp_t how)
+{
+ unsigned int cmd_len;
+
+ if (fw_pos >= fw_entry->size)
+ return 0;
+
+ if (fw_pos + 2 > fw_entry->size) {
+ dev_err(info->dev, "Corrupted firmware image 1\n");
+ return -EMSGSIZE;
+ }
+
+ cmd_len = fw_entry->data[fw_pos++];
+ cmd_len += fw_entry->data[fw_pos++] << 8;
+ if (cmd_len == 0)
+ return 0;
+
+ if (fw_pos + cmd_len > fw_entry->size) {
+ dev_err(info->dev, "Corrupted firmware image 2\n");
+ return -EMSGSIZE;
+ }
+
+ *skb = bt_skb_alloc(cmd_len, how);
+ if (!*skb) {
+ dev_err(info->dev, "Cannot reserve memory for buffer\n");
+ return -ENOMEM;
+ }
+ memcpy(skb_put(*skb, cmd_len), &fw_entry->data[fw_pos], cmd_len);
+
+ fw_pos += cmd_len;
+
+ return (*skb)->len;
+}
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+ const struct firmware *fw_entry = NULL;
+ struct sk_buff *skb = NULL;
+ int err;
+
+ err = hci_h4p_open_firmware(info, &fw_entry);
+ if (err < 0 || !fw_entry)
+ goto err_clean;
+
+ while ((err = hci_h4p_read_fw_cmd(info, &skb, fw_entry, GFP_KERNEL))) {
+ if (err < 0 || !skb)
+ goto err_clean;
+
+ skb_queue_tail(fw_queue, skb);
+ }
+
+ /* Chip detection code does neg and alive stuff
+ * discard two first skbs */
+ skb = skb_dequeue(fw_queue);
+ if (!skb) {
+ err = -EMSGSIZE;
+ goto err_clean;
+ }
+ kfree_skb(skb);
+ skb = skb_dequeue(fw_queue);
+ if (!skb) {
+ err = -EMSGSIZE;
+ goto err_clean;
+ }
+ kfree_skb(skb);
+
+err_clean:
+ hci_h4p_close_firmware(fw_entry);
+ return err;
+}
+
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+ int err;
+
+ switch (info->man_id) {
+ case H4P_ID_CSR:
+ err = hci_h4p_bc4_send_fw(info, fw_queue);
+ break;
+ case H4P_ID_TI1271:
+ err = hci_h4p_ti1273_send_fw(info, fw_queue);
+ break;
+ case H4P_ID_BCM2048:
+ err = hci_h4p_bcm_send_fw(info, fw_queue);
+ break;
+ default:
+ dev_err(info->dev, "Don't know how to send firmware\n");
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ switch (info->man_id) {
+ case H4P_ID_CSR:
+ hci_h4p_bc4_parse_fw_event(info, skb);
+ break;
+ case H4P_ID_TI1271:
+ hci_h4p_ti1273_parse_fw_event(info, skb);
+ break;
+ case H4P_ID_BCM2048:
+ hci_h4p_bcm_parse_fw_event(info, skb);
+ break;
+ default:
+ dev_err(info->dev, "Don't know how to parse fw event\n");
+ info->fw_error = -EINVAL;
+ }
+
+ return;
+}
+
+MODULE_FIRMWARE(FW_NAME_TI1271_PRELE);
+MODULE_FIRMWARE(FW_NAME_TI1271_LE);
+MODULE_FIRMWARE(FW_NAME_TI1271);
+MODULE_FIRMWARE(FW_NAME_BCM2048);
+MODULE_FIRMWARE(FW_NAME_CSR);
diff --git a/drivers/staging/nokia_h4p/nokia_uart.c b/drivers/staging/nokia_h4p/nokia_uart.c
new file mode 100644
index 000000000000..0fb57de4b750
--- /dev/null
+++ b/drivers/staging/nokia_h4p/nokia_uart.c
@@ -0,0 +1,199 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <linux/io.h>
+
+#include "hci_h4p.h"
+
+inline void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val)
+{
+ __raw_writeb(val, info->uart_base + (offset << 2));
+}
+
+inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
+{
+ return __raw_readb(info->uart_base + (offset << 2));
+}
+
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active)
+{
+ u8 b;
+
+ b = hci_h4p_inb(info, UART_MCR);
+ if (active)
+ b |= UART_MCR_RTS;
+ else
+ b &= ~UART_MCR_RTS;
+ hci_h4p_outb(info, UART_MCR, b);
+}
+
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active,
+ int timeout_ms)
+{
+ unsigned long timeout;
+ int state;
+
+ timeout = jiffies + msecs_to_jiffies(timeout_ms);
+ for (;;) {
+ state = hci_h4p_inb(info, UART_MSR) & UART_MSR_CTS;
+ if (active) {
+ if (state)
+ return 0;
+ } else {
+ if (!state)
+ return 0;
+ }
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ msleep(1);
+ }
+}
+
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+ u8 lcr, b;
+
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, 0xbf);
+ b = hci_h4p_inb(info, UART_EFR);
+ if (on)
+ b |= which;
+ else
+ b &= ~which;
+ hci_h4p_outb(info, UART_EFR, b);
+ hci_h4p_outb(info, UART_LCR, lcr);
+}
+
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->lock, flags);
+ __hci_h4p_set_auto_ctsrts(info, on, which);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed)
+{
+ unsigned int divisor;
+ u8 lcr, mdr1;
+
+ BT_DBG("Setting speed %lu", speed);
+
+ if (speed >= 460800) {
+ divisor = UART_CLOCK / 13 / speed;
+ mdr1 = 3;
+ } else {
+ divisor = UART_CLOCK / 16 / speed;
+ mdr1 = 0;
+ }
+
+ /* Make sure UART mode is disabled */
+ hci_h4p_outb(info, UART_OMAP_MDR1, 7);
+
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB); /* Set DLAB */
+ hci_h4p_outb(info, UART_DLL, divisor & 0xff); /* Set speed */
+ hci_h4p_outb(info, UART_DLM, divisor >> 8);
+ hci_h4p_outb(info, UART_LCR, lcr);
+
+ /* Make sure UART mode is enabled */
+ hci_h4p_outb(info, UART_OMAP_MDR1, mdr1);
+}
+
+int hci_h4p_reset_uart(struct hci_h4p_info *info)
+{
+ int count = 0;
+
+ /* Reset the UART */
+ hci_h4p_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
+ while (!(hci_h4p_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
+ if (count++ > 100) {
+ dev_err(info->dev, "hci_h4p: UART reset timeout\n");
+ return -ENODEV;
+ }
+ udelay(1);
+ }
+
+ return 0;
+}
+
+void hci_h4p_store_regs(struct hci_h4p_info *info)
+{
+ u16 lcr = 0;
+
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, 0xBF);
+ info->dll = hci_h4p_inb(info, UART_DLL);
+ info->dlh = hci_h4p_inb(info, UART_DLM);
+ info->efr = hci_h4p_inb(info, UART_EFR);
+ hci_h4p_outb(info, UART_LCR, lcr);
+ info->mdr1 = hci_h4p_inb(info, UART_OMAP_MDR1);
+ info->ier = hci_h4p_inb(info, UART_IER);
+}
+
+void hci_h4p_restore_regs(struct hci_h4p_info *info)
+{
+ u16 lcr = 0;
+
+ hci_h4p_init_uart(info);
+
+ hci_h4p_outb(info, UART_OMAP_MDR1, 7);
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, 0xBF);
+ hci_h4p_outb(info, UART_DLL, info->dll); /* Set speed */
+ hci_h4p_outb(info, UART_DLM, info->dlh);
+ hci_h4p_outb(info, UART_EFR, info->efr);
+ hci_h4p_outb(info, UART_LCR, lcr);
+ hci_h4p_outb(info, UART_OMAP_MDR1, info->mdr1);
+ hci_h4p_outb(info, UART_IER, info->ier);
+}
+
+void hci_h4p_init_uart(struct hci_h4p_info *info)
+{
+ u8 mcr, efr;
+
+ /* Enable and setup FIFO */
+ hci_h4p_outb(info, UART_OMAP_MDR1, 0x00);
+
+ hci_h4p_outb(info, UART_LCR, 0xbf);
+ efr = hci_h4p_inb(info, UART_EFR);
+ hci_h4p_outb(info, UART_EFR, UART_EFR_ECB);
+ hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
+ mcr = hci_h4p_inb(info, UART_MCR);
+ hci_h4p_outb(info, UART_MCR, UART_MCR_TCRTLR);
+ hci_h4p_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
+ (3 << 6) | (0 << 4));
+ hci_h4p_outb(info, UART_LCR, 0xbf);
+ hci_h4p_outb(info, UART_TI752_TLR, 0xed);
+ hci_h4p_outb(info, UART_TI752_TCR, 0xef);
+ hci_h4p_outb(info, UART_EFR, efr);
+ hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
+ hci_h4p_outb(info, UART_MCR, 0x00);
+ hci_h4p_outb(info, UART_LCR, UART_LCR_WLEN8);
+ hci_h4p_outb(info, UART_IER, UART_IER_RDI);
+ hci_h4p_outb(info, UART_OMAP_SYSC, (1 << 0) | (1 << 2) | (2 << 3));
+}
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index 3ee0b1887a54..90f1c4d7fa89 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -678,8 +678,7 @@ static irqreturn_t nvec_interrupt(int irq, void *dev)
nvec->rx->data[nvec->rx->pos++] = received;
else
dev_err(nvec->dev,
- "RX buffer overflow on %p: "
- "Trying to write byte %u of %u\n",
+ "RX buffer overflow on %p: Trying to write byte %u of %u\n",
nvec->rx, nvec->rx ? nvec->rx->pos : 0,
NVEC_MSG_SIZE);
break;
diff --git a/drivers/staging/nvec/nvec_ps2.c b/drivers/staging/nvec/nvec_ps2.c
index 06dbb02085a9..45b2f1308e01 100644
--- a/drivers/staging/nvec/nvec_ps2.c
+++ b/drivers/staging/nvec/nvec_ps2.c
@@ -106,7 +106,7 @@ static int nvec_mouse_probe(struct platform_device *pdev)
struct serio *ser_dev;
char mouse_reset[] = { NVEC_PS2, SEND_COMMAND, PSMOUSE_RST, 3 };
- ser_dev = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ ser_dev = devm_kzalloc(&pdev->dev, sizeof(struct serio), GFP_KERNEL);
if (ser_dev == NULL)
return -ENOMEM;
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index 5a001d9b4252..8b8ce7293c52 100644
--- a/drivers/staging/octeon-usb/octeon-hcd.c
+++ b/drivers/staging/octeon-usb/octeon-hcd.c
@@ -465,6 +465,112 @@ struct octeon_hcd {
#define USB_FIFO_ADDRESS(channel, usb_index) (CVMX_USBCX_GOTGCTL(usb_index) + ((channel)+1)*0x1000)
/**
+ * struct octeon_temp_buffer - a bounce buffer for USB transfers
+ * @temp_buffer: the newly allocated temporary buffer (including meta-data)
+ * @orig_buffer: the original buffer passed by the USB stack
+ * @data: the newly allocated temporary buffer (excluding meta-data)
+ *
+ * Both the DMA engine and FIFO mode will always transfer full 32-bit words. If
+ * the buffer is too short, we need to allocate a temporary one, and this struct
+ * represents it.
+ */
+struct octeon_temp_buffer {
+ void *temp_buffer;
+ void *orig_buffer;
+ u8 data[0];
+};
+
+/**
+ * octeon_alloc_temp_buffer - allocate a temporary buffer for USB transfer
+ * (if needed)
+ * @urb: URB.
+ * @mem_flags: Memory allocation flags.
+ *
+ * This function allocates a temporary bounce buffer whenever it's needed
+ * due to HW limitations.
+ */
+static int octeon_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
+{
+ struct octeon_temp_buffer *temp;
+
+ if (urb->num_sgs || urb->sg ||
+ (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) ||
+ !(urb->transfer_buffer_length % sizeof(u32)))
+ return 0;
+
+ temp = kmalloc(ALIGN(urb->transfer_buffer_length, sizeof(u32)) +
+ sizeof(*temp), mem_flags);
+ if (!temp)
+ return -ENOMEM;
+
+ temp->temp_buffer = temp;
+ temp->orig_buffer = urb->transfer_buffer;
+ if (usb_urb_dir_out(urb))
+ memcpy(temp->data, urb->transfer_buffer,
+ urb->transfer_buffer_length);
+ urb->transfer_buffer = temp->data;
+ urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
+
+ return 0;
+}
+
+/**
+ * octeon_free_temp_buffer - free a temporary buffer used by USB transfers.
+ * @urb: URB.
+ *
+ * Frees a buffer allocated by octeon_alloc_temp_buffer().
+ */
+static void octeon_free_temp_buffer(struct urb *urb)
+{
+ struct octeon_temp_buffer *temp;
+
+ if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
+ return;
+
+ temp = container_of(urb->transfer_buffer, struct octeon_temp_buffer,
+ data);
+ if (usb_urb_dir_in(urb))
+ memcpy(temp->orig_buffer, urb->transfer_buffer,
+ urb->actual_length);
+ urb->transfer_buffer = temp->orig_buffer;
+ urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
+ kfree(temp->temp_buffer);
+}
+
+/**
+ * octeon_map_urb_for_dma - Octeon-specific map_urb_for_dma().
+ * @hcd: USB HCD structure.
+ * @urb: URB.
+ * @mem_flags: Memory allocation flags.
+ */
+static int octeon_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ int ret;
+
+ ret = octeon_alloc_temp_buffer(urb, mem_flags);
+ if (ret)
+ return ret;
+
+ ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+ if (ret)
+ octeon_free_temp_buffer(urb);
+
+ return ret;
+}
+
+/**
+ * octeon_unmap_urb_for_dma - Octeon-specific unmap_urb_for_dma()
+ * @hcd: USB HCD structure.
+ * @urb: URB.
+ */
+static void octeon_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ usb_hcd_unmap_urb_for_dma(hcd, urb);
+ octeon_free_temp_buffer(urb);
+}
+
+/**
* Read a USB 32bit CSR. It performs the necessary address swizzle
* for 32bit CSRs and logs the value in a readable format if
* debugging is on.
@@ -605,7 +711,8 @@ static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
* 2a. Write USBN0/1_CLK_CTL[POR] = 1 and
* USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0
*/
- usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index));
+ usbn_clk_ctl.u64 =
+ __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index));
usbn_clk_ctl.s.por = 1;
usbn_clk_ctl.s.hrst = 0;
usbn_clk_ctl.s.prst = 0;
@@ -691,7 +798,8 @@ static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
* USBP control and status register:
* USBN_USBP_CTL_STATUS[ATE_RESET] = 1
*/
- usbn_usbp_ctl_status.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index));
+ usbn_usbp_ctl_status.u64 = __cvmx_usb_read_csr64(usb,
+ CVMX_USBNX_USBP_CTL_STATUS(usb->index));
usbn_usbp_ctl_status.s.ate_reset = 1;
__cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
usbn_usbp_ctl_status.u64);
@@ -758,7 +866,8 @@ static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
if (OCTEON_IS_MODEL(OCTEON_CN31XX))
usb->init_flags |= CVMX_USB_INITIALIZE_FLAGS_NO_DMA;
usbcx_gahbcfg.u32 = 0;
- usbcx_gahbcfg.s.dmaen = !(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA);
+ usbcx_gahbcfg.s.dmaen = !(usb->init_flags &
+ CVMX_USB_INITIALIZE_FLAGS_NO_DMA);
if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
/* Only use one channel with non DMA */
usb->idle_hardware_channels = 0x1;
@@ -783,7 +892,8 @@ static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
*/
{
union cvmx_usbcx_gusbcfg usbcx_gusbcfg;
- usbcx_gusbcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index));
+ usbcx_gusbcfg.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_GUSBCFG(usb->index));
usbcx_gusbcfg.s.toutcal = 0;
usbcx_gusbcfg.s.ddrsel = 0;
usbcx_gusbcfg.s.usbtrdtim = 0x5;
@@ -801,7 +911,8 @@ static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
union cvmx_usbcx_gintmsk usbcx_gintmsk;
int channel;
- usbcx_gintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTMSK(usb->index));
+ usbcx_gintmsk.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_GINTMSK(usb->index));
usbcx_gintmsk.s.otgintmsk = 1;
usbcx_gintmsk.s.modemismsk = 1;
usbcx_gintmsk.s.hchintmsk = 1;
@@ -817,7 +928,8 @@ static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
* later.
*/
for (channel = 0; channel < 8; channel++)
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
+ __cvmx_usb_write_csr32(usb,
+ CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
}
{
@@ -827,26 +939,30 @@ static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
* 1. Program the host-port interrupt-mask field to unmask,
* USBC_GINTMSK[PRTINT] = 1
*/
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk,
- prtintmsk, 1);
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk,
- disconnintmsk, 1);
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+ union cvmx_usbcx_gintmsk, prtintmsk, 1);
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+ union cvmx_usbcx_gintmsk, disconnintmsk, 1);
/*
* 2. Program the USBC_HCFG register to select full-speed host
* or high-speed host.
*/
{
union cvmx_usbcx_hcfg usbcx_hcfg;
- usbcx_hcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCFG(usb->index));
+ usbcx_hcfg.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HCFG(usb->index));
usbcx_hcfg.s.fslssupp = 0;
usbcx_hcfg.s.fslspclksel = 0;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index), usbcx_hcfg.u32);
+ __cvmx_usb_write_csr32(usb,
+ CVMX_USBCX_HCFG(usb->index),
+ usbcx_hcfg.u32);
}
/*
* 3. Program the port power bit to drive VBUS on the USB,
* USBC_HPRT[PRTPWR] = 1
*/
- USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtpwr, 1);
+ USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index),
+ union cvmx_usbcx_hprt, prtpwr, 1);
/*
* Steps 4-15 from the manual are done later in the port enable
@@ -879,7 +995,8 @@ static int cvmx_usb_shutdown(struct cvmx_usb_state *usb)
return -EBUSY;
/* Disable the clocks and put them in power on reset */
- usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index));
+ usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb,
+ CVMX_USBNX_CLK_CTL(usb->index));
usbn_clk_ctl.s.enable = 1;
usbn_clk_ctl.s.por = 1;
usbn_clk_ctl.s.hclk_rst = 1;
@@ -903,7 +1020,8 @@ static int cvmx_usb_enable(struct cvmx_usb_state *usb)
{
union cvmx_usbcx_ghwcfg3 usbcx_ghwcfg3;
- usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
+ usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HPRT(usb->index));
/*
* If the port is already enabled the just return. We don't need to do
@@ -913,12 +1031,12 @@ static int cvmx_usb_enable(struct cvmx_usb_state *usb)
return 0;
/* If there is nothing plugged into the port then fail immediately */
- if (!usb->usbcx_hprt.s.prtconnsts) {
+ if (!usb->usbcx_hprt.s.prtconnsts)
return -ETIMEDOUT;
- }
/* Program the port reset bit to start the reset process */
- USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtrst, 1);
+ USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt,
+ prtrst, 1);
/*
* Wait at least 50ms (high speed), or 10ms (full speed) for the reset
@@ -927,26 +1045,30 @@ static int cvmx_usb_enable(struct cvmx_usb_state *usb)
mdelay(50);
/* Program the port reset bit to 0, USBC_HPRT[PRTRST] = 0 */
- USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtrst, 0);
+ USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt,
+ prtrst, 0);
/* Wait for the USBC_HPRT[PRTENA]. */
- if (CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt,
- prtena, ==, 1, 100000))
+ if (CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_HPRT(usb->index),
+ union cvmx_usbcx_hprt, prtena, ==, 1, 100000))
return -ETIMEDOUT;
/*
* Read the port speed field to get the enumerated speed,
* USBC_HPRT[PRTSPD].
*/
- usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
- usbcx_ghwcfg3.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GHWCFG3(usb->index));
+ usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HPRT(usb->index));
+ usbcx_ghwcfg3.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_GHWCFG3(usb->index));
/*
* 13. Program the USBC_GRXFSIZ register to select the size of the
* receive FIFO (25%).
*/
- USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index), union cvmx_usbcx_grxfsiz,
- rxfdep, usbcx_ghwcfg3.s.dfifodepth / 4);
+ USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index),
+ union cvmx_usbcx_grxfsiz, rxfdep,
+ usbcx_ghwcfg3.s.dfifodepth / 4);
/*
* 14. Program the USBC_GNPTXFSIZ register to select the size and the
* start address of the non- periodic transmit FIFO for nonperiodic
@@ -954,10 +1076,12 @@ static int cvmx_usb_enable(struct cvmx_usb_state *usb)
*/
{
union cvmx_usbcx_gnptxfsiz siz;
- siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index));
+ siz.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_GNPTXFSIZ(usb->index));
siz.s.nptxfdep = usbcx_ghwcfg3.s.dfifodepth / 2;
siz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), siz.u32);
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index),
+ siz.u32);
}
/*
* 15. Program the USBC_HPTXFSIZ register to select the size and start
@@ -966,18 +1090,25 @@ static int cvmx_usb_enable(struct cvmx_usb_state *usb)
*/
{
union cvmx_usbcx_hptxfsiz siz;
- siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index));
+ siz.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HPTXFSIZ(usb->index));
siz.s.ptxfsize = usbcx_ghwcfg3.s.dfifodepth / 4;
siz.s.ptxfstaddr = 3 * usbcx_ghwcfg3.s.dfifodepth / 4;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index), siz.u32);
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index),
+ siz.u32);
}
/* Flush all FIFOs */
- USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, txfnum, 0x10);
- USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, txfflsh, 1);
- CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl,
+ USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
+ union cvmx_usbcx_grstctl, txfnum, 0x10);
+ USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
+ union cvmx_usbcx_grstctl, txfflsh, 1);
+ CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
+ union cvmx_usbcx_grstctl,
txfflsh, ==, 0, 100);
- USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, rxfflsh, 1);
- CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl,
+ USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
+ union cvmx_usbcx_grstctl, rxfflsh, 1);
+ CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
+ union cvmx_usbcx_grstctl,
rxfflsh, ==, 0, 100);
return 0;
@@ -997,7 +1128,8 @@ static int cvmx_usb_enable(struct cvmx_usb_state *usb)
static int cvmx_usb_disable(struct cvmx_usb_state *usb)
{
/* Disable the port */
- USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtena, 1);
+ USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt,
+ prtena, 1);
return 0;
}
@@ -1013,20 +1145,23 @@ static int cvmx_usb_disable(struct cvmx_usb_state *usb)
*
* Returns: Port status information
*/
-static struct cvmx_usb_port_status cvmx_usb_get_status(struct cvmx_usb_state *usb)
+static struct cvmx_usb_port_status cvmx_usb_get_status(
+ struct cvmx_usb_state *usb)
{
union cvmx_usbcx_hprt usbc_hprt;
struct cvmx_usb_port_status result;
memset(&result, 0, sizeof(result));
- usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
+ usbc_hprt.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HPRT(usb->index));
result.port_enabled = usbc_hprt.s.prtena;
result.port_over_current = usbc_hprt.s.prtovrcurract;
result.port_powered = usbc_hprt.s.prtpwr;
result.port_speed = usbc_hprt.s.prtspd;
result.connected = usbc_hprt.s.prtconnsts;
- result.connect_change = (result.connected != usb->port_status.connected);
+ result.connect_change =
+ (result.connected != usb->port_status.connected);
return result;
}
@@ -1121,7 +1256,8 @@ static struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct cvmx_usb_state *usb,
if (unlikely((device_speed != CVMX_USB_SPEED_HIGH) &&
(multi_count != 0)))
return NULL;
- if (unlikely((hub_device_addr < 0) || (hub_device_addr > MAX_USB_ADDRESS)))
+ if (unlikely((hub_device_addr < 0) ||
+ (hub_device_addr > MAX_USB_ADDRESS)))
return NULL;
if (unlikely((hub_port < 0) || (hub_port > MAX_USB_HUB_PORT)))
return NULL;
@@ -1186,7 +1322,8 @@ static void __cvmx_usb_poll_rx_fifo(struct cvmx_usb_state *usb)
uint64_t address;
uint32_t *ptr;
- rx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GRXSTSPH(usb->index));
+ rx_status.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_GRXSTSPH(usb->index));
/* Only read data if IN data is there */
if (rx_status.s.pktsts != 2)
return;
@@ -1236,7 +1373,8 @@ static int __cvmx_usb_fill_tx_hw(struct cvmx_usb_state *usb,
while (available && (fifo->head != fifo->tail)) {
int i = fifo->tail;
const uint32_t *ptr = cvmx_phys_to_ptr(fifo->entry[i].address);
- uint64_t csr_address = USB_FIFO_ADDRESS(fifo->entry[i].channel, usb->index) ^ 4;
+ uint64_t csr_address = USB_FIFO_ADDRESS(fifo->entry[i].channel,
+ usb->index) ^ 4;
int words = available;
/* Limit the amount of data to waht the SW fifo has */
@@ -1260,7 +1398,8 @@ static int __cvmx_usb_fill_tx_hw(struct cvmx_usb_state *usb,
cvmx_write64_uint32(csr_address, *ptr++);
cvmx_write64_uint32(csr_address, *ptr++);
cvmx_write64_uint32(csr_address, *ptr++);
- cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
+ cvmx_read64_uint64(
+ CVMX_USBNX_DMA0_INB_CHN0(usb->index));
words -= 3;
}
cvmx_write64_uint32(csr_address, *ptr++);
@@ -1284,20 +1423,32 @@ static void __cvmx_usb_poll_tx_fifo(struct cvmx_usb_state *usb)
{
if (usb->periodic.head != usb->periodic.tail) {
union cvmx_usbcx_hptxsts tx_status;
- tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXSTS(usb->index));
- if (__cvmx_usb_fill_tx_hw(usb, &usb->periodic, tx_status.s.ptxfspcavail))
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, ptxfempmsk, 1);
+ tx_status.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HPTXSTS(usb->index));
+ if (__cvmx_usb_fill_tx_hw(usb, &usb->periodic,
+ tx_status.s.ptxfspcavail))
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+ union cvmx_usbcx_gintmsk,
+ ptxfempmsk, 1);
else
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, ptxfempmsk, 0);
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+ union cvmx_usbcx_gintmsk,
+ ptxfempmsk, 0);
}
if (usb->nonperiodic.head != usb->nonperiodic.tail) {
union cvmx_usbcx_gnptxsts tx_status;
- tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXSTS(usb->index));
- if (__cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic, tx_status.s.nptxfspcavail))
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, nptxfempmsk, 1);
+ tx_status.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_GNPTXSTS(usb->index));
+ if (__cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic,
+ tx_status.s.nptxfspcavail))
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+ union cvmx_usbcx_gintmsk,
+ nptxfempmsk, 1);
else
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, nptxfempmsk, 0);
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+ union cvmx_usbcx_gintmsk,
+ nptxfempmsk, 0);
}
return;
@@ -1318,12 +1469,14 @@ static void __cvmx_usb_fill_tx_fifo(struct cvmx_usb_state *usb, int channel)
struct cvmx_usb_tx_fifo *fifo;
/* We only need to fill data on outbound channels */
- hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
+ hcchar.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HCCHARX(channel, usb->index));
if (hcchar.s.epdir != CVMX_USB_DIRECTION_OUT)
return;
/* OUT Splits only have data on the start and not the complete */
- usbc_hcsplt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index));
+ usbc_hcsplt.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HCSPLTX(channel, usb->index));
if (usbc_hcsplt.s.spltena && usbc_hcsplt.s.compsplt)
return;
@@ -1331,7 +1484,8 @@ static void __cvmx_usb_fill_tx_fifo(struct cvmx_usb_state *usb, int channel)
* Find out how many bytes we need to fill and convert it into 32bit
* words.
*/
- usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
+ usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HCTSIZX(channel, usb->index));
if (!usbc_hctsiz.s.xfersize)
return;
@@ -1371,11 +1525,13 @@ static void __cvmx_usb_start_channel_control(struct cvmx_usb_state *usb,
node);
union cvmx_usb_control_header *header =
cvmx_phys_to_ptr(transaction->control_header);
- int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes;
+ int bytes_to_transfer = transaction->buffer_length -
+ transaction->actual_bytes;
int packets_to_transfer;
union cvmx_usbcx_hctsizx usbc_hctsiz;
- usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
+ usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HCTSIZX(channel, usb->index));
switch (transaction->stage) {
case CVMX_USB_STAGE_NON_CONTROL:
@@ -1423,12 +1579,14 @@ static void __cvmx_usb_start_channel_control(struct cvmx_usb_state *usb,
((header->s.request_type & 0x80) ?
CVMX_USB_DIRECTION_IN :
CVMX_USB_DIRECTION_OUT));
- USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1);
+ USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index),
+ union cvmx_usbcx_hcspltx, compsplt, 1);
break;
case CVMX_USB_STAGE_STATUS:
usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
bytes_to_transfer = 0;
- USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir,
+ USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+ union cvmx_usbcx_hccharx, epdir,
((header->s.request_type & 0x80) ?
CVMX_USB_DIRECTION_OUT :
CVMX_USB_DIRECTION_IN));
@@ -1436,11 +1594,13 @@ static void __cvmx_usb_start_channel_control(struct cvmx_usb_state *usb,
case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
bytes_to_transfer = 0;
- USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir,
+ USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+ union cvmx_usbcx_hccharx, epdir,
((header->s.request_type & 0x80) ?
CVMX_USB_DIRECTION_OUT :
CVMX_USB_DIRECTION_IN));
- USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1);
+ USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index),
+ union cvmx_usbcx_hcspltx, compsplt, 1);
break;
}
@@ -1458,10 +1618,12 @@ static void __cvmx_usb_start_channel_control(struct cvmx_usb_state *usb,
* Calculate the number of packets to transfer. If the length is zero
* we still need to transfer one packet
*/
- packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet;
+ packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) /
+ pipe->max_packet;
if (packets_to_transfer == 0)
packets_to_transfer = 1;
- else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
+ else if ((packets_to_transfer > 1) &&
+ (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
/*
* Limit to one packet when not using DMA. Channels must be
* restarted between every packet for IN transactions, so there
@@ -1481,7 +1643,8 @@ static void __cvmx_usb_start_channel_control(struct cvmx_usb_state *usb,
usbc_hctsiz.s.xfersize = bytes_to_transfer;
usbc_hctsiz.s.pktcnt = packets_to_transfer;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32);
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index),
+ usbc_hctsiz.u32);
return;
}
@@ -1519,8 +1682,11 @@ static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb,
union cvmx_usbcx_haintmsk usbc_haintmsk;
/* Clear all channel status bits */
- usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index));
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index), usbc_hcint.u32);
+ usbc_hcint.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HCINTX(channel, usb->index));
+ __cvmx_usb_write_csr32(usb,
+ CVMX_USBCX_HCINTX(channel, usb->index),
+ usbc_hcint.u32);
usbc_hcintmsk.u32 = 0;
usbc_hcintmsk.s.chhltdmsk = 1;
@@ -1567,14 +1733,17 @@ static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb,
union cvmx_usbcx_hcspltx usbc_hcsplt = {.u32 = 0};
union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 = 0};
int packets_to_transfer;
- int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes;
+ int bytes_to_transfer = transaction->buffer_length -
+ transaction->actual_bytes;
/*
* ISOCHRONOUS transactions store each individual transfer size
* in the packet structure, not the global buffer_length
*/
if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
- bytes_to_transfer = transaction->iso_packets[0].length - transaction->actual_bytes;
+ bytes_to_transfer =
+ transaction->iso_packets[0].length -
+ transaction->actual_bytes;
/*
* We need to do split transactions when we are talking to non
@@ -1589,16 +1758,19 @@ static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb,
*/
if ((transaction->stage&1) == 0) {
if (transaction->type == CVMX_USB_TRANSFER_BULK)
- pipe->split_sc_frame = (usb->frame_number + 1) & 0x7f;
+ pipe->split_sc_frame =
+ (usb->frame_number + 1) & 0x7f;
else
- pipe->split_sc_frame = (usb->frame_number + 2) & 0x7f;
+ pipe->split_sc_frame =
+ (usb->frame_number + 2) & 0x7f;
} else
pipe->split_sc_frame = -1;
usbc_hcsplt.s.spltena = 1;
usbc_hcsplt.s.hubaddr = pipe->hub_device_addr;
usbc_hcsplt.s.prtaddr = pipe->hub_port;
- usbc_hcsplt.s.compsplt = (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE);
+ usbc_hcsplt.s.compsplt = (transaction->stage ==
+ CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE);
/*
* SPLIT transactions can only ever transmit one data
@@ -1614,8 +1786,10 @@ static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb,
* begin/middle/end of the data or all
*/
if (!usbc_hcsplt.s.compsplt &&
- (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
- (pipe->transfer_type == CVMX_USB_TRANSFER_ISOCHRONOUS)) {
+ (pipe->transfer_dir ==
+ CVMX_USB_DIRECTION_OUT) &&
+ (pipe->transfer_type ==
+ CVMX_USB_TRANSFER_ISOCHRONOUS)) {
/*
* Clear the split complete frame number as
* there isn't going to be a split complete
@@ -1667,7 +1841,8 @@ static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb,
* Round MAX_TRANSFER_BYTES to a multiple of out packet
* size
*/
- bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet;
+ bytes_to_transfer = MAX_TRANSFER_BYTES /
+ pipe->max_packet;
bytes_to_transfer *= pipe->max_packet;
}
@@ -1675,10 +1850,14 @@ static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb,
* Calculate the number of packets to transfer. If the length is
* zero we still need to transfer one packet
*/
- packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet;
+ packets_to_transfer =
+ (bytes_to_transfer + pipe->max_packet - 1) /
+ pipe->max_packet;
if (packets_to_transfer == 0)
packets_to_transfer = 1;
- else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
+ else if ((packets_to_transfer > 1) &&
+ (usb->init_flags &
+ CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
/*
* Limit to one packet when not using DMA. Channels must
* be restarted between every packet for IN
@@ -1686,14 +1865,16 @@ static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb,
* packets in a row
*/
packets_to_transfer = 1;
- bytes_to_transfer = packets_to_transfer * pipe->max_packet;
+ bytes_to_transfer = packets_to_transfer *
+ pipe->max_packet;
} else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
/*
* Limit the number of packet and data transferred to
* what the hardware can handle
*/
packets_to_transfer = MAX_TRANSFER_PACKETS;
- bytes_to_transfer = packets_to_transfer * pipe->max_packet;
+ bytes_to_transfer = packets_to_transfer *
+ pipe->max_packet;
}
usbc_hctsiz.s.xfersize = bytes_to_transfer;
@@ -1707,8 +1888,11 @@ static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb,
if (pipe->flags & __CVMX_USB_PIPE_FLAGS_NEED_PING)
usbc_hctsiz.s.dopng = 1;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index), usbc_hcsplt.u32);
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32);
+ __cvmx_usb_write_csr32(usb,
+ CVMX_USBCX_HCSPLTX(channel, usb->index),
+ usbc_hcsplt.u32);
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel,
+ usb->index), usbc_hctsiz.u32);
}
/* Setup the Host Channel Characteristics Register */
@@ -1739,11 +1923,14 @@ static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb,
/* Set the rest of the endpoint specific settings */
usbc_hcchar.s.devaddr = pipe->device_addr;
usbc_hcchar.s.eptype = transaction->type;
- usbc_hcchar.s.lspddev = (pipe->device_speed == CVMX_USB_SPEED_LOW);
+ usbc_hcchar.s.lspddev =
+ (pipe->device_speed == CVMX_USB_SPEED_LOW);
usbc_hcchar.s.epdir = pipe->transfer_dir;
usbc_hcchar.s.epnum = pipe->endpoint_num;
usbc_hcchar.s.mps = pipe->max_packet;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
+ __cvmx_usb_write_csr32(usb,
+ CVMX_USBCX_HCCHARX(channel, usb->index),
+ usbc_hcchar.u32);
}
/* Do transaction type specific fixups as needed */
@@ -1762,22 +1949,33 @@ static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb,
*/
if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
if (pipe->multi_count < 2) /* Need DATA0 */
- USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), union cvmx_usbcx_hctsizx, pid, 0);
+ USB_SET_FIELD32(
+ CVMX_USBCX_HCTSIZX(channel,
+ usb->index),
+ union cvmx_usbcx_hctsizx,
+ pid, 0);
else /* Need MDATA */
- USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), union cvmx_usbcx_hctsizx, pid, 3);
+ USB_SET_FIELD32(
+ CVMX_USBCX_HCTSIZX(channel,
+ usb->index),
+ union cvmx_usbcx_hctsizx,
+ pid, 3);
}
}
break;
}
{
- union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index))};
+ union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 =
+ __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HCTSIZX(channel, usb->index))};
transaction->xfersize = usbc_hctsiz.s.xfersize;
transaction->pktcnt = usbc_hctsiz.s.pktcnt;
}
/* Remeber when we start a split transaction */
if (__cvmx_usb_pipe_needs_split(usb, pipe))
usb->active_split = transaction;
- USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, chena, 1);
+ USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+ union cvmx_usbcx_hccharx, chena, 1);
if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
__cvmx_usb_fill_tx_fifo(usb, channel);
return;
@@ -1793,16 +1991,22 @@ static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb,
*
* Returns: Pipe or NULL if none are ready
*/
-static struct cvmx_usb_pipe *__cvmx_usb_find_ready_pipe(struct cvmx_usb_state *usb, struct list_head *list, uint64_t current_frame)
+static struct cvmx_usb_pipe *__cvmx_usb_find_ready_pipe(
+ struct cvmx_usb_state *usb,
+ struct list_head *list,
+ uint64_t current_frame)
{
struct cvmx_usb_pipe *pipe;
list_for_each_entry(pipe, list, node) {
struct cvmx_usb_transaction *t =
- list_first_entry(&pipe->transactions, typeof(*t), node);
+ list_first_entry(&pipe->transactions, typeof(*t),
+ node);
if (!(pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED) && t &&
(pipe->next_tx_frame <= current_frame) &&
- ((pipe->split_sc_frame == -1) || ((((int)current_frame - (int)pipe->split_sc_frame) & 0x7f) < 0x40)) &&
+ ((pipe->split_sc_frame == -1) ||
+ ((((int)current_frame - (int)pipe->split_sc_frame)
+ & 0x7f) < 0x40)) &&
(!usb->active_split || (usb->active_split == t))) {
CVMX_PREFETCH(pipe, 128);
CVMX_PREFETCH(t, 0);
@@ -1852,14 +2056,26 @@ static void __cvmx_usb_schedule(struct cvmx_usb_state *usb, int is_sof)
* way we are sure that the periodic data is sent in the
* beginning of the frame
*/
- pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_ISOCHRONOUS, usb->frame_number);
+ pipe = __cvmx_usb_find_ready_pipe(usb,
+ usb->active_pipes +
+ CVMX_USB_TRANSFER_ISOCHRONOUS,
+ usb->frame_number);
if (likely(!pipe))
- pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_INTERRUPT, usb->frame_number);
+ pipe = __cvmx_usb_find_ready_pipe(usb,
+ usb->active_pipes +
+ CVMX_USB_TRANSFER_INTERRUPT,
+ usb->frame_number);
}
if (likely(!pipe)) {
- pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_CONTROL, usb->frame_number);
+ pipe = __cvmx_usb_find_ready_pipe(usb,
+ usb->active_pipes +
+ CVMX_USB_TRANSFER_CONTROL,
+ usb->frame_number);
if (likely(!pipe))
- pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_BULK, usb->frame_number);
+ pipe = __cvmx_usb_find_ready_pipe(usb,
+ usb->active_pipes +
+ CVMX_USB_TRANSFER_BULK,
+ usb->frame_number);
}
if (!pipe)
break;
@@ -1873,7 +2089,8 @@ done:
* future that might need to be scheduled
*/
need_sof = 0;
- for (ttype = CVMX_USB_TRANSFER_CONTROL; ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) {
+ for (ttype = CVMX_USB_TRANSFER_CONTROL;
+ ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) {
list_for_each_entry(pipe, &usb->active_pipes[ttype], node) {
if (pipe->next_tx_frame > usb->frame_number) {
need_sof = 1;
@@ -1881,7 +2098,8 @@ done:
}
}
}
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, sofmsk, need_sof);
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+ union cvmx_usbcx_gintmsk, sofmsk, need_sof);
return;
}
@@ -1932,10 +2150,13 @@ static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb,
/* Recalculate the transfer size by adding up each packet */
urb->actual_length = 0;
for (i = 0; i < urb->number_of_packets; i++) {
- if (iso_packet[i].status == CVMX_USB_COMPLETE_SUCCESS) {
+ if (iso_packet[i].status ==
+ CVMX_USB_COMPLETE_SUCCESS) {
urb->iso_frame_desc[i].status = 0;
- urb->iso_frame_desc[i].actual_length = iso_packet[i].length;
- urb->actual_length += urb->iso_frame_desc[i].actual_length;
+ urb->iso_frame_desc[i].actual_length =
+ iso_packet[i].length;
+ urb->actual_length +=
+ urb->iso_frame_desc[i].actual_length;
} else {
dev_dbg(dev, "ISOCHRONOUS packet=%d of %d status=%d pipe=%p transaction=%p size=%d\n",
i, urb->number_of_packets,
@@ -1997,10 +2218,11 @@ static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb,
* @complete_code:
* Completion code
*/
-static void __cvmx_usb_perform_complete(struct cvmx_usb_state *usb,
- struct cvmx_usb_pipe *pipe,
- struct cvmx_usb_transaction *transaction,
- enum cvmx_usb_complete complete_code)
+static void __cvmx_usb_perform_complete(
+ struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct cvmx_usb_transaction *transaction,
+ enum cvmx_usb_complete complete_code)
{
/* If this was a split then clear our split in progress marker */
if (usb->active_split == transaction)
@@ -2019,7 +2241,8 @@ static void __cvmx_usb_perform_complete(struct cvmx_usb_state *usb,
* If there are more ISOs pending and we succeeded, schedule the
* next one
*/
- if ((transaction->iso_number_packets > 1) && (complete_code == CVMX_USB_COMPLETE_SUCCESS)) {
+ if ((transaction->iso_number_packets > 1) &&
+ (complete_code == CVMX_USB_COMPLETE_SUCCESS)) {
/* No bytes transferred for this packet as of yet */
transaction->actual_bytes = 0;
/* One less ISO waiting to transfer */
@@ -2067,16 +2290,17 @@ done:
*
* Returns: Transaction or NULL on failure.
*/
-static struct cvmx_usb_transaction *__cvmx_usb_submit_transaction(struct cvmx_usb_state *usb,
- struct cvmx_usb_pipe *pipe,
- enum cvmx_usb_transfer type,
- uint64_t buffer,
- int buffer_length,
- uint64_t control_header,
- int iso_start_frame,
- int iso_number_packets,
- struct cvmx_usb_iso_packet *iso_packets,
- struct urb *urb)
+static struct cvmx_usb_transaction *__cvmx_usb_submit_transaction(
+ struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ enum cvmx_usb_transfer type,
+ uint64_t buffer,
+ int buffer_length,
+ uint64_t control_header,
+ int iso_start_frame,
+ int iso_number_packets,
+ struct cvmx_usb_iso_packet *iso_packets,
+ struct urb *urb)
{
struct cvmx_usb_transaction *transaction;
@@ -2128,9 +2352,10 @@ static struct cvmx_usb_transaction *__cvmx_usb_submit_transaction(struct cvmx_us
*
* Returns: A submitted transaction or NULL on failure.
*/
-static struct cvmx_usb_transaction *cvmx_usb_submit_bulk(struct cvmx_usb_state *usb,
- struct cvmx_usb_pipe *pipe,
- struct urb *urb)
+static struct cvmx_usb_transaction *cvmx_usb_submit_bulk(
+ struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct urb *urb)
{
return __cvmx_usb_submit_transaction(usb, pipe, CVMX_USB_TRANSFER_BULK,
urb->transfer_dma,
@@ -2152,9 +2377,10 @@ static struct cvmx_usb_transaction *cvmx_usb_submit_bulk(struct cvmx_usb_state *
*
* Returns: A submitted transaction or NULL on failure.
*/
-static struct cvmx_usb_transaction *cvmx_usb_submit_interrupt(struct cvmx_usb_state *usb,
- struct cvmx_usb_pipe *pipe,
- struct urb *urb)
+static struct cvmx_usb_transaction *cvmx_usb_submit_interrupt(
+ struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct urb *urb)
{
return __cvmx_usb_submit_transaction(usb, pipe,
CVMX_USB_TRANSFER_INTERRUPT,
@@ -2177,9 +2403,10 @@ static struct cvmx_usb_transaction *cvmx_usb_submit_interrupt(struct cvmx_usb_st
*
* Returns: A submitted transaction or NULL on failure.
*/
-static struct cvmx_usb_transaction *cvmx_usb_submit_control(struct cvmx_usb_state *usb,
- struct cvmx_usb_pipe *pipe,
- struct urb *urb)
+static struct cvmx_usb_transaction *cvmx_usb_submit_control(
+ struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct urb *urb)
{
int buffer_length = urb->transfer_buffer_length;
uint64_t control_header = urb->setup_dma;
@@ -2209,9 +2436,10 @@ static struct cvmx_usb_transaction *cvmx_usb_submit_control(struct cvmx_usb_stat
*
* Returns: A submitted transaction or NULL on failure.
*/
-static struct cvmx_usb_transaction *cvmx_usb_submit_isochronous(struct cvmx_usb_state *usb,
- struct cvmx_usb_pipe *pipe,
- struct urb *urb)
+static struct cvmx_usb_transaction *cvmx_usb_submit_isochronous(
+ struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct urb *urb)
{
struct cvmx_usb_iso_packet *packets;
@@ -2257,17 +2485,22 @@ static int cvmx_usb_cancel(struct cvmx_usb_state *usb,
CVMX_SYNCW;
- usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index));
+ usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HCCHARX(pipe->channel, usb->index));
/*
* If the channel isn't enabled then the transaction already
* completed.
*/
if (usbc_hcchar.s.chena) {
usbc_hcchar.s.chdis = 1;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index), usbc_hcchar.u32);
+ __cvmx_usb_write_csr32(usb,
+ CVMX_USBCX_HCCHARX(pipe->channel,
+ usb->index),
+ usbc_hcchar.u32);
}
}
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_CANCEL);
+ __cvmx_usb_perform_complete(usb, pipe, transaction,
+ CVMX_USB_COMPLETE_CANCEL);
return 0;
}
@@ -2331,7 +2564,8 @@ static int cvmx_usb_get_frame_number(struct cvmx_usb_state *usb)
int frame_number;
union cvmx_usbcx_hfnum usbc_hfnum;
- usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
+ usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HFNUM(usb->index));
frame_number = usbc_hfnum.s.frnum;
return frame_number;
@@ -2359,10 +2593,12 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
int buffer_space_left;
/* Read the interrupt status bits for the channel */
- usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index));
+ usbc_hcint.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HCINTX(channel, usb->index));
if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
- usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
+ usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HCCHARX(channel, usb->index));
if (usbc_hcchar.s.chena && usbc_hcchar.s.chdis) {
/*
@@ -2370,7 +2606,10 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* interrupt IN transfers to get stuck until we do a
* write of HCCHARX without changing things
*/
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
+ __cvmx_usb_write_csr32(usb,
+ CVMX_USBCX_HCCHARX(channel,
+ usb->index),
+ usbc_hcchar.u32);
return 0;
}
@@ -2384,9 +2623,15 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
/* Disable all interrupts except CHHLTD */
hcintmsk.u32 = 0;
hcintmsk.s.chhltdmsk = 1;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), hcintmsk.u32);
+ __cvmx_usb_write_csr32(usb,
+ CVMX_USBCX_HCINTMSKX(channel,
+ usb->index),
+ hcintmsk.u32);
usbc_hcchar.s.chdis = 1;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
+ __cvmx_usb_write_csr32(usb,
+ CVMX_USBCX_HCCHARX(channel,
+ usb->index),
+ usbc_hcchar.u32);
return 0;
} else if (usbc_hcint.s.xfercompl) {
/*
@@ -2394,7 +2639,8 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* Channel halt isn't needed.
*/
} else {
- cvmx_dprintf("USB%d: Channel %d interrupt without halt\n", usb->index, channel);
+ cvmx_dprintf("USB%d: Channel %d interrupt without halt\n",
+ usb->index, channel);
return 0;
}
}
@@ -2417,7 +2663,8 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
CVMX_PREFETCH(pipe, 128);
if (!pipe)
return 0;
- transaction = list_first_entry(&pipe->transactions, typeof(*transaction),
+ transaction = list_first_entry(&pipe->transactions,
+ typeof(*transaction),
node);
CVMX_PREFETCH(transaction, 0);
@@ -2432,8 +2679,10 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* Read the channel config info so we can figure out how much data
* transfered
*/
- usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
- usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
+ usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HCCHARX(channel, usb->index));
+ usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HCTSIZX(channel, usb->index));
/*
* Calculating the number of bytes successfully transferred is dependent
@@ -2447,7 +2696,8 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* the current value of xfersize from its starting value and we
* know how many bytes were written to the buffer
*/
- bytes_this_transfer = transaction->xfersize - usbc_hctsiz.s.xfersize;
+ bytes_this_transfer = transaction->xfersize -
+ usbc_hctsiz.s.xfersize;
} else {
/*
* OUT transaction don't decrement xfersize. Instead pktcnt is
@@ -2465,7 +2715,8 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
}
/* Figure out how many bytes were in the last packet of the transfer */
if (packets_processed)
- bytes_in_last_packet = bytes_this_transfer - (packets_processed-1) * usbc_hcchar.s.mps;
+ bytes_in_last_packet = bytes_this_transfer -
+ (packets_processed - 1) * usbc_hcchar.s.mps;
else
bytes_in_last_packet = bytes_this_transfer;
@@ -2485,9 +2736,11 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
*/
transaction->actual_bytes += bytes_this_transfer;
if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
- buffer_space_left = transaction->iso_packets[0].length - transaction->actual_bytes;
+ buffer_space_left = transaction->iso_packets[0].length -
+ transaction->actual_bytes;
else
- buffer_space_left = transaction->buffer_length - transaction->actual_bytes;
+ buffer_space_left = transaction->buffer_length -
+ transaction->actual_bytes;
/*
* We need to remember the PID toggle state for the next transaction.
@@ -2513,7 +2766,8 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* the actual bytes transferred
*/
pipe->pid_toggle = 0;
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_STALL);
+ __cvmx_usb_perform_complete(usb, pipe, transaction,
+ CVMX_USB_COMPLETE_STALL);
} else if (usbc_hcint.s.xacterr) {
/*
* We know at least one packet worked if we get a ACK or NAK.
@@ -2528,7 +2782,8 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* something wrong with the transfer. For example, PID
* toggle errors cause these
*/
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_XACTERR);
+ __cvmx_usb_perform_complete(usb, pipe, transaction,
+ CVMX_USB_COMPLETE_XACTERR);
} else {
/*
* If this was a split then clear our split in progress
@@ -2544,12 +2799,15 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
pipe->split_sc_frame = -1;
pipe->next_tx_frame += pipe->interval;
if (pipe->next_tx_frame < usb->frame_number)
- pipe->next_tx_frame = usb->frame_number + pipe->interval -
- (usb->frame_number - pipe->next_tx_frame) % pipe->interval;
+ pipe->next_tx_frame =
+ usb->frame_number + pipe->interval -
+ (usb->frame_number -
+ pipe->next_tx_frame) % pipe->interval;
}
} else if (usbc_hcint.s.bblerr) {
/* Babble Error (BblErr) */
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_BABBLEERR);
+ __cvmx_usb_perform_complete(usb, pipe, transaction,
+ CVMX_USB_COMPLETE_BABBLEERR);
} else if (usbc_hcint.s.datatglerr) {
/* We'll retry the exact same transaction again */
transaction->retries++;
@@ -2566,8 +2824,11 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* If there is more data to go then we need to try
* again. Otherwise this transaction is complete
*/
- if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet))
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ if ((buffer_space_left == 0) ||
+ (bytes_in_last_packet < pipe->max_packet))
+ __cvmx_usb_perform_complete(usb, pipe,
+ transaction,
+ CVMX_USB_COMPLETE_SUCCESS);
} else {
/*
* Split transactions retry the split complete 4 times
@@ -2605,12 +2866,14 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
case CVMX_USB_STAGE_NON_CONTROL:
case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
/* This should be impossible */
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR);
+ __cvmx_usb_perform_complete(usb, pipe,
+ transaction, CVMX_USB_COMPLETE_ERROR);
break;
case CVMX_USB_STAGE_SETUP:
pipe->pid_toggle = 1;
if (__cvmx_usb_pipe_needs_split(usb, pipe))
- transaction->stage = CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE;
+ transaction->stage =
+ CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE;
else {
union cvmx_usb_control_header *header =
cvmx_phys_to_ptr(transaction->control_header);
@@ -2632,7 +2895,8 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
break;
case CVMX_USB_STAGE_DATA:
if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
- transaction->stage = CVMX_USB_STAGE_DATA_SPLIT_COMPLETE;
+ transaction->stage =
+ CVMX_USB_STAGE_DATA_SPLIT_COMPLETE;
/*
* For setup OUT data that are splits,
* the hardware doesn't appear to count
@@ -2641,31 +2905,45 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
*/
if (!usbc_hcchar.s.epdir) {
if (buffer_space_left < pipe->max_packet)
- transaction->actual_bytes += buffer_space_left;
+ transaction->actual_bytes +=
+ buffer_space_left;
else
- transaction->actual_bytes += pipe->max_packet;
+ transaction->actual_bytes +=
+ pipe->max_packet;
}
- } else if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
+ } else if ((buffer_space_left == 0) ||
+ (bytes_in_last_packet <
+ pipe->max_packet)) {
pipe->pid_toggle = 1;
- transaction->stage = CVMX_USB_STAGE_STATUS;
+ transaction->stage =
+ CVMX_USB_STAGE_STATUS;
}
break;
case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
- if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
+ if ((buffer_space_left == 0) ||
+ (bytes_in_last_packet <
+ pipe->max_packet)) {
pipe->pid_toggle = 1;
- transaction->stage = CVMX_USB_STAGE_STATUS;
+ transaction->stage =
+ CVMX_USB_STAGE_STATUS;
} else {
- transaction->stage = CVMX_USB_STAGE_DATA;
+ transaction->stage =
+ CVMX_USB_STAGE_DATA;
}
break;
case CVMX_USB_STAGE_STATUS:
if (__cvmx_usb_pipe_needs_split(usb, pipe))
- transaction->stage = CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE;
+ transaction->stage =
+ CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE;
else
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ __cvmx_usb_perform_complete(usb, pipe,
+ transaction,
+ CVMX_USB_COMPLETE_SUCCESS);
break;
case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ __cvmx_usb_perform_complete(usb, pipe,
+ transaction,
+ CVMX_USB_COMPLETE_SUCCESS);
break;
}
break;
@@ -2678,27 +2956,49 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* data is needed
*/
if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
- if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL)
- transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
+ if (transaction->stage ==
+ CVMX_USB_STAGE_NON_CONTROL)
+ transaction->stage =
+ CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
else {
- if (buffer_space_left && (bytes_in_last_packet == pipe->max_packet))
- transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
+ if (buffer_space_left &&
+ (bytes_in_last_packet ==
+ pipe->max_packet))
+ transaction->stage =
+ CVMX_USB_STAGE_NON_CONTROL;
else {
- if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT)
- pipe->next_tx_frame += pipe->interval;
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ if (transaction->type ==
+ CVMX_USB_TRANSFER_INTERRUPT)
+ pipe->next_tx_frame +=
+ pipe->interval;
+ __cvmx_usb_perform_complete(
+ usb,
+ pipe,
+ transaction,
+ CVMX_USB_COMPLETE_SUCCESS);
}
}
} else {
- if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
- (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
- (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
+ if ((pipe->device_speed ==
+ CVMX_USB_SPEED_HIGH) &&
+ (pipe->transfer_type ==
+ CVMX_USB_TRANSFER_BULK) &&
+ (pipe->transfer_dir ==
+ CVMX_USB_DIRECTION_OUT) &&
(usbc_hcint.s.nak))
- pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
- if (!buffer_space_left || (bytes_in_last_packet < pipe->max_packet)) {
- if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT)
- pipe->next_tx_frame += pipe->interval;
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ pipe->flags |=
+ __CVMX_USB_PIPE_FLAGS_NEED_PING;
+ if (!buffer_space_left ||
+ (bytes_in_last_packet <
+ pipe->max_packet)) {
+ if (transaction->type ==
+ CVMX_USB_TRANSFER_INTERRUPT)
+ pipe->next_tx_frame +=
+ pipe->interval;
+ __cvmx_usb_perform_complete(usb,
+ pipe,
+ transaction,
+ CVMX_USB_COMPLETE_SUCCESS);
}
}
break;
@@ -2719,28 +3019,45 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* complete. Otherwise start it again to
* send the next 188 bytes
*/
- if (!buffer_space_left || (bytes_this_transfer < 188)) {
+ if (!buffer_space_left ||
+ (bytes_this_transfer < 188)) {
pipe->next_tx_frame += pipe->interval;
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ __cvmx_usb_perform_complete(
+ usb,
+ pipe,
+ transaction,
+ CVMX_USB_COMPLETE_SUCCESS);
}
} else {
- if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) {
+ if (transaction->stage ==
+ CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) {
/*
* We are in the incoming data
* phase. Keep getting data
* until we run out of space or
* get a small packet
*/
- if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
- pipe->next_tx_frame += pipe->interval;
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ if ((buffer_space_left == 0) ||
+ (bytes_in_last_packet <
+ pipe->max_packet)) {
+ pipe->next_tx_frame +=
+ pipe->interval;
+ __cvmx_usb_perform_complete(
+ usb,
+ pipe,
+ transaction,
+ CVMX_USB_COMPLETE_SUCCESS);
}
} else
- transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
+ transaction->stage =
+ CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
}
} else {
pipe->next_tx_frame += pipe->interval;
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ __cvmx_usb_perform_complete(usb,
+ pipe,
+ transaction,
+ CVMX_USB_COMPLETE_SUCCESS);
}
break;
}
@@ -2760,8 +3077,10 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
transaction->stage &= ~1;
pipe->next_tx_frame += pipe->interval;
if (pipe->next_tx_frame < usb->frame_number)
- pipe->next_tx_frame = usb->frame_number + pipe->interval -
- (usb->frame_number - pipe->next_tx_frame) % pipe->interval;
+ pipe->next_tx_frame = usb->frame_number +
+ pipe->interval -
+ (usb->frame_number - pipe->next_tx_frame) %
+ pipe->interval;
} else {
struct cvmx_usb_port_status port;
port = cvmx_usb_get_status(usb);
@@ -2773,7 +3092,8 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* We get channel halted interrupts with no result bits
* sets when the cable is unplugged
*/
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR);
+ __cvmx_usb_perform_complete(usb, pipe, transaction,
+ CVMX_USB_COMPLETE_ERROR);
}
}
return 0;
@@ -2856,9 +3176,11 @@ static int cvmx_usb_poll(struct cvmx_usb_state *usb)
*/
octeon_usb_port_callback(usb);
/* Clear the port change bits */
- usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
+ usbc_hprt.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HPRT(usb->index));
usbc_hprt.s.prtena = 0;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index), usbc_hprt.u32);
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index),
+ usbc_hprt.u32);
}
if (usbc_gintsts.s.hchint) {
/*
@@ -3002,13 +3324,15 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
}
pipe = cvmx_usb_open_pipe(&priv->usb, usb_pipedevice(urb->pipe),
usb_pipeendpoint(urb->pipe), speed,
- le16_to_cpu(ep->desc.wMaxPacketSize) & 0x7ff,
+ le16_to_cpu(ep->desc.wMaxPacketSize)
+ & 0x7ff,
transfer_type,
usb_pipein(urb->pipe) ?
CVMX_USB_DIRECTION_IN :
CVMX_USB_DIRECTION_OUT,
urb->interval,
- (le16_to_cpu(ep->desc.wMaxPacketSize) >> 11) & 0x3,
+ (le16_to_cpu(ep->desc.wMaxPacketSize)
+ >> 11) & 0x3,
split_device, split_port);
if (!pipe) {
spin_unlock_irqrestore(&priv->lock, flags);
@@ -3023,7 +3347,8 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
switch (usb_pipetype(urb->pipe)) {
case PIPE_ISOCHRONOUS:
dev_dbg(dev, "Submit isochronous to %d.%d\n",
- usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe));
+ usb_pipedevice(urb->pipe),
+ usb_pipeendpoint(urb->pipe));
/*
* Allocate a structure to use for our private list of
* isochronous packets.
@@ -3035,9 +3360,12 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
int i;
/* Fill the list with the data from the URB */
for (i = 0; i < urb->number_of_packets; i++) {
- iso_packet[i].offset = urb->iso_frame_desc[i].offset;
- iso_packet[i].length = urb->iso_frame_desc[i].length;
- iso_packet[i].status = CVMX_USB_COMPLETE_ERROR;
+ iso_packet[i].offset =
+ urb->iso_frame_desc[i].offset;
+ iso_packet[i].length =
+ urb->iso_frame_desc[i].length;
+ iso_packet[i].status =
+ CVMX_USB_COMPLETE_ERROR;
}
/*
* Store a pointer to the list in the URB setup_packet
@@ -3059,17 +3387,20 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
break;
case PIPE_INTERRUPT:
dev_dbg(dev, "Submit interrupt to %d.%d\n",
- usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe));
+ usb_pipedevice(urb->pipe),
+ usb_pipeendpoint(urb->pipe));
transaction = cvmx_usb_submit_interrupt(&priv->usb, pipe, urb);
break;
case PIPE_CONTROL:
dev_dbg(dev, "Submit control to %d.%d\n",
- usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe));
+ usb_pipedevice(urb->pipe),
+ usb_pipeendpoint(urb->pipe));
transaction = cvmx_usb_submit_control(&priv->usb, pipe, urb);
break;
case PIPE_BULK:
dev_dbg(dev, "Submit bulk to %d.%d\n",
- usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe));
+ usb_pipedevice(urb->pipe),
+ usb_pipeendpoint(urb->pipe));
transaction = cvmx_usb_submit_bulk(&priv->usb, pipe, urb);
break;
}
@@ -3100,7 +3431,9 @@ static void octeon_usb_urb_dequeue_work(unsigned long arg)
spin_unlock_irqrestore(&priv->lock, flags);
}
-static int octeon_usb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+static int octeon_usb_urb_dequeue(struct usb_hcd *hcd,
+ struct urb *urb,
+ int status)
{
struct octeon_hcd *priv = hcd_to_octeon(hcd);
unsigned long flags;
@@ -3120,7 +3453,8 @@ static int octeon_usb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int stat
return 0;
}
-static void octeon_usb_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+static void octeon_usb_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
{
struct device *dev = hcd->self.controller;
@@ -3203,7 +3537,8 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
dev_dbg(dev, " C_CONNECTION\n");
/* Clears drivers internal connect status change flag */
spin_lock_irqsave(&priv->lock, flags);
- priv->usb.port_status = cvmx_usb_get_status(&priv->usb);
+ priv->usb.port_status =
+ cvmx_usb_get_status(&priv->usb);
spin_unlock_irqrestore(&priv->lock, flags);
break;
case USB_PORT_FEAT_C_RESET:
@@ -3212,7 +3547,8 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
* Clears the driver's internal Port Reset Change flag.
*/
spin_lock_irqsave(&priv->lock, flags);
- priv->usb.port_status = cvmx_usb_get_status(&priv->usb);
+ priv->usb.port_status =
+ cvmx_usb_get_status(&priv->usb);
spin_unlock_irqrestore(&priv->lock, flags);
break;
case USB_PORT_FEAT_C_ENABLE:
@@ -3222,7 +3558,8 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
* Change flag.
*/
spin_lock_irqsave(&priv->lock, flags);
- priv->usb.port_status = cvmx_usb_get_status(&priv->usb);
+ priv->usb.port_status =
+ cvmx_usb_get_status(&priv->usb);
spin_unlock_irqrestore(&priv->lock, flags);
break;
case USB_PORT_FEAT_C_SUSPEND:
@@ -3237,7 +3574,8 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
dev_dbg(dev, " C_OVER_CURRENT\n");
/* Clears the driver's overcurrent Change flag */
spin_lock_irqsave(&priv->lock, flags);
- priv->usb.port_status = cvmx_usb_get_status(&priv->usb);
+ priv->usb.port_status =
+ cvmx_usb_get_status(&priv->usb);
spin_unlock_irqrestore(&priv->lock, flags);
break;
default:
@@ -3369,6 +3707,8 @@ static const struct hc_driver octeon_hc_driver = {
.get_frame_number = octeon_usb_get_frame_number,
.hub_status_data = octeon_usb_hub_status_data,
.hub_control = octeon_usb_hub_control,
+ .map_urb_for_dma = octeon_map_urb_for_dma,
+ .unmap_urb_for_dma = octeon_unmap_urb_for_dma,
};
static int octeon_usb_probe(struct platform_device *pdev)
@@ -3411,7 +3751,8 @@ static int octeon_usb_probe(struct platform_device *pdev)
initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ;
break;
default:
- dev_err(dev, "Illebal USBN \"refclk-frequency\" %u\n", clock_rate);
+ dev_err(dev, "Illebal USBN \"refclk-frequency\" %u\n",
+ clock_rate);
return -ENXIO;
}
@@ -3477,7 +3818,8 @@ static int octeon_usb_probe(struct platform_device *pdev)
spin_lock_init(&priv->lock);
- tasklet_init(&priv->dequeue_tasklet, octeon_usb_urb_dequeue_work, (unsigned long)priv);
+ tasklet_init(&priv->dequeue_tasklet, octeon_usb_urb_dequeue_work,
+ (unsigned long)priv);
INIT_LIST_HEAD(&priv->dequeue_list);
status = cvmx_usb_initialize(&priv->usb, usb_num, initialize_flags);
diff --git a/drivers/staging/octeon/ethernet-defines.h b/drivers/staging/octeon/ethernet-defines.h
index bdaec8d2ca0c..2a98a2153e16 100644
--- a/drivers/staging/octeon/ethernet-defines.h
+++ b/drivers/staging/octeon/ethernet-defines.h
@@ -33,10 +33,6 @@
* driver will use this memory instead of kernel memory for pools. This
* allows 32bit userspace application to access the buffers, but also
* requires all received packets to be copied.
- * CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS
- * This kernel config option allows the user to control the number of
- * packet and work queue buffers allocated by the driver. If this is zero,
- * the driver uses the default from below.
* USE_SKBUFFS_IN_HW
* Tells the driver to populate the packet buffers with kernel skbuffs.
* This allows the driver to receive packets without copying them. It also
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index 83b103091cf2..3f067f189b3d 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -127,23 +127,21 @@ static void cvm_oct_adjust_link(struct net_device *dev)
link_info.s.link_up = priv->last_link ? 1 : 0;
link_info.s.full_duplex = priv->phydev->duplex ? 1 : 0;
link_info.s.speed = priv->phydev->speed;
- cvmx_helper_link_set( priv->port, link_info);
+ cvmx_helper_link_set(priv->port, link_info);
if (priv->last_link) {
netif_carrier_on(dev);
if (priv->queue != -1)
printk_ratelimited("%s: %u Mbps %s duplex, "
- "port %2d, queue %2d\n",
- dev->name, priv->phydev->speed,
- priv->phydev->duplex ?
- "Full" : "Half",
- priv->port, priv->queue);
+ "port %2d, queue %2d\n", dev->name,
+ priv->phydev->speed,
+ priv->phydev->duplex ? "Full" : "Half",
+ priv->port, priv->queue);
else
printk_ratelimited("%s: %u Mbps %s duplex, "
- "port %2d, POW\n",
- dev->name, priv->phydev->speed,
- priv->phydev->duplex ?
- "Full" : "Half",
- priv->port);
+ "port %2d, POW\n", dev->name,
+ priv->phydev->speed,
+ priv->phydev->duplex ? "Full" : "Half",
+ priv->port);
} else {
netif_carrier_off(dev);
printk_ratelimited("%s: Link down\n", dev->name);
diff --git a/drivers/staging/octeon/ethernet-mem.c b/drivers/staging/octeon/ethernet-mem.c
index 199059d64c9b..bf666b023190 100644
--- a/drivers/staging/octeon/ethernet-mem.c
+++ b/drivers/staging/octeon/ethernet-mem.c
@@ -30,6 +30,7 @@
#include <asm/octeon/octeon.h>
+#include "ethernet-mem.h"
#include "ethernet-defines.h"
#include <asm/octeon/cvmx-fpa.h>
@@ -79,10 +80,10 @@ static void cvm_oct_free_hw_skbuff(int pool, int size, int elements)
} while (memory);
if (elements < 0)
- pr_warning("Freeing of pool %u had too many skbuffs (%d)\n",
+ pr_warn("Freeing of pool %u had too many skbuffs (%d)\n",
pool, elements);
else if (elements > 0)
- pr_warning("Freeing of pool %u is missing %d skbuffs\n",
+ pr_warn("Freeing of pool %u is missing %d skbuffs\n",
pool, elements);
}
@@ -113,7 +114,7 @@ static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
*/
memory = kmalloc(size + 256, GFP_ATOMIC);
if (unlikely(memory == NULL)) {
- pr_warning("Unable to allocate %u bytes for FPA pool %d\n",
+ pr_warn("Unable to allocate %u bytes for FPA pool %d\n",
elements * size, pool);
break;
}
@@ -146,10 +147,10 @@ static void cvm_oct_free_hw_memory(int pool, int size, int elements)
} while (fpa);
if (elements < 0)
- pr_warning("Freeing of pool %u had too many buffers (%d)\n",
+ pr_warn("Freeing of pool %u had too many buffers (%d)\n",
pool, elements);
else if (elements > 0)
- pr_warning("Warning: Freeing of pool %u is missing %d buffers\n",
+ pr_warn("Warning: Freeing of pool %u is missing %d buffers\n",
pool, elements);
}
diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c
index ea53af30dfa7..0ec0da328215 100644
--- a/drivers/staging/octeon/ethernet-rgmii.c
+++ b/drivers/staging/octeon/ethernet-rgmii.c
@@ -43,7 +43,7 @@
#include <asm/octeon/cvmx-npi-defs.h>
#include <asm/octeon/cvmx-gmxx-defs.h>
-DEFINE_SPINLOCK(global_register_lock);
+static DEFINE_SPINLOCK(global_register_lock);
static int number_rgmii_ports;
@@ -72,7 +72,8 @@ static void cvm_oct_rgmii_poll(struct net_device *dev)
* If the 10Mbps preamble workaround is supported and we're
* at 10Mbps we may need to do some special checking.
*/
- if (USE_10MBPS_PREAMBLE_WORKAROUND && (link_info.s.speed == 10)) {
+ if (USE_10MBPS_PREAMBLE_WORKAROUND &&
+ (link_info.s.speed == 10)) {
/*
* Read the GMXX_RXX_INT_REG[PCTERR] bit and
@@ -166,9 +167,8 @@ static void cvm_oct_rgmii_poll(struct net_device *dev)
if (use_global_register_lock)
spin_unlock_irqrestore(&global_register_lock, flags);
- else {
+ else
mutex_unlock(&priv->phydev->bus->mdio_lock);
- }
if (priv->phydev == NULL) {
/* Tell core. */
@@ -232,8 +232,10 @@ static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
(interface, index)];
struct octeon_ethernet *priv = netdev_priv(dev);
- if (dev && !atomic_read(&cvm_oct_poll_queue_stopping))
- queue_work(cvm_oct_poll_queue, &priv->port_work);
+ if (dev &&
+ !atomic_read(&cvm_oct_poll_queue_stopping))
+ queue_work(cvm_oct_poll_queue,
+ &priv->port_work);
gmx_rx_int_reg.u64 = 0;
gmx_rx_int_reg.s.phy_dupx = 1;
@@ -274,8 +276,10 @@ static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
(interface, index)];
struct octeon_ethernet *priv = netdev_priv(dev);
- if (dev && !atomic_read(&cvm_oct_poll_queue_stopping))
- queue_work(cvm_oct_poll_queue, &priv->port_work);
+ if (dev &&
+ !atomic_read(&cvm_oct_poll_queue_stopping))
+ queue_work(cvm_oct_poll_queue,
+ &priv->port_work);
gmx_rx_int_reg.u64 = 0;
gmx_rx_int_reg.s.phy_dupx = 1;
@@ -327,7 +331,8 @@ int cvm_oct_rgmii_stop(struct net_device *dev)
static void cvm_oct_rgmii_immediate_poll(struct work_struct *work)
{
- struct octeon_ethernet *priv = container_of(work, struct octeon_ethernet, port_work);
+ struct octeon_ethernet *priv =
+ container_of(work, struct octeon_ethernet, port_work);
cvm_oct_rgmii_poll(cvm_oct_device[priv->port]);
}
diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c
index 47541e1608f3..8ca55c4e9db2 100644
--- a/drivers/staging/octeon/ethernet-tx.c
+++ b/drivers/staging/octeon/ethernet-tx.c
@@ -95,7 +95,7 @@ static void cvm_oct_kick_tx_poll_watchdog(void)
cvmx_write_csr(CVMX_CIU_TIMX(1), ciu_timx.u64);
}
-void cvm_oct_free_tx_skbs(struct net_device *dev)
+static void cvm_oct_free_tx_skbs(struct net_device *dev)
{
int32_t skb_to_free;
int qos, queues_per_port;
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index 089dc4b9efd4..ff7214aac9dd 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -55,17 +55,11 @@
#include <asm/octeon/cvmx-gmxx-defs.h>
#include <asm/octeon/cvmx-smix-defs.h>
-#if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) \
- && CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS
-int num_packet_buffers = CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS;
-#else
-int num_packet_buffers = 1024;
-#endif
+static int num_packet_buffers = 1024;
module_param(num_packet_buffers, int, 0444);
MODULE_PARM_DESC(num_packet_buffers, "\n"
"\tNumber of packet buffers to allocate and store in the\n"
- "\tFPA. By default, 1024 packet buffers are used unless\n"
- "\tCONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS is defined.");
+ "\tFPA. By default, 1024 packet buffers are used.\n");
int pow_receive_group = 15;
module_param(pow_receive_group, int, 0444);
diff --git a/drivers/staging/octeon/octeon-ethernet.h b/drivers/staging/octeon/octeon-ethernet.h
index 9360e22e0739..4cf3884070fa 100644
--- a/drivers/staging/octeon/octeon-ethernet.h
+++ b/drivers/staging/octeon/octeon-ethernet.h
@@ -58,7 +58,7 @@ struct octeon_ethernet {
/* Last negotiated link state */
uint64_t link_info;
/* Called periodically to check link status */
- void (*poll) (struct net_device *dev);
+ void (*poll)(struct net_device *dev);
struct delayed_work port_periodic_work;
struct work_struct port_work; /* may be unused. */
struct device_node *of_node;
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.h b/drivers/staging/olpc_dcon/olpc_dcon.h
index e2663b189c66..aec98958f795 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.h
+++ b/drivers/staging/olpc_dcon/olpc_dcon.h
@@ -37,7 +37,7 @@
/* Load Delay Locked Loop (DLL) settings for clock delay */
#define MEM_DLL_CLOCK_DELAY (1<<0)
/* Memory controller power down function */
-#define MEM_POWER_DOWN (1<<8)
+#define MEM_POWER_DOWN (1<<8)
/* Memory controller software reset */
#define MEM_SOFT_RESET (1<<0)
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
index 5de5981b3bba..10c0a96ce8bb 100644
--- a/drivers/staging/ozwpan/ozcdev.c
+++ b/drivers/staging/ozwpan/ozcdev.c
@@ -217,7 +217,7 @@ static int oz_set_active_pd(const u8 *addr)
pd = oz_pd_find(addr);
if (pd) {
spin_lock_bh(&g_cdev.lock);
- memcpy(g_cdev.active_addr, addr, ETH_ALEN);
+ ether_addr_copy(g_cdev.active_addr, addr);
old_pd = g_cdev.active_pd;
g_cdev.active_pd = pd;
spin_unlock_bh(&g_cdev.lock);
@@ -283,7 +283,7 @@ static long oz_cdev_ioctl(struct file *filp, unsigned int cmd,
u8 addr[ETH_ALEN];
oz_dbg(ON, "OZ_IOCTL_GET_ACTIVE_PD\n");
spin_lock_bh(&g_cdev.lock);
- memcpy(addr, g_cdev.active_addr, ETH_ALEN);
+ ether_addr_copy(addr, g_cdev.active_addr);
spin_unlock_bh(&g_cdev.lock);
if (copy_to_user((void __user *)arg, addr, ETH_ALEN))
return -EFAULT;
diff --git a/drivers/staging/ozwpan/ozhcd.c b/drivers/staging/ozwpan/ozhcd.c
index efaf26f734c3..b3d401ae41b4 100644
--- a/drivers/staging/ozwpan/ozhcd.c
+++ b/drivers/staging/ozwpan/ozhcd.c
@@ -354,7 +354,8 @@ static struct oz_endpoint *oz_ep_alloc(int buffer_size, gfp_t mem_flags)
* disabled.
* Context: softirq or process
*/
-static struct oz_urb_link *oz_uncancel_urb(struct oz_hcd *ozhcd, struct urb *urb)
+static struct oz_urb_link *oz_uncancel_urb(struct oz_hcd *ozhcd,
+ struct urb *urb)
{
struct oz_urb_link *urbl;
struct list_head *e;
@@ -1986,8 +1987,7 @@ static void oz_get_hub_descriptor(struct usb_hcd *hcd,
memset(desc, 0, sizeof(*desc));
desc->bDescriptorType = 0x29;
desc->bDescLength = 9;
- desc->wHubCharacteristics = (__force __u16)
- __constant_cpu_to_le16(0x0001);
+ desc->wHubCharacteristics = (__force __u16)cpu_to_le16(0x0001);
desc->bNbrPorts = OZ_NB_PORTS;
}
@@ -2181,7 +2181,7 @@ static int oz_hcd_hub_control(struct usb_hcd *hcd, u16 req_type, u16 wvalue,
break;
case GetHubStatus:
oz_dbg(HUB, "GetHubStatus: req_type = 0x%x\n", req_type);
- put_unaligned(__constant_cpu_to_le32(0), (__le32 *)buf);
+ put_unaligned(cpu_to_le32(0), (__le32 *)buf);
break;
case GetPortStatus:
err = oz_get_port_status(hcd, windex, buf);
diff --git a/drivers/staging/ozwpan/ozpd.c b/drivers/staging/ozwpan/ozpd.c
index 743695077346..10f1b3ac8832 100644
--- a/drivers/staging/ozwpan/ozpd.c
+++ b/drivers/staging/ozwpan/ozpd.c
@@ -8,6 +8,7 @@
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#include <linux/errno.h>
#include "ozdbg.h"
#include "ozprotocol.h"
@@ -173,7 +174,7 @@ struct oz_pd *oz_pd_alloc(const u8 *mac_addr)
pd->last_rx_pkt_num = 0xffffffff;
oz_pd_set_state(pd, OZ_PD_S_IDLE);
pd->max_tx_size = OZ_MAX_TX_SIZE;
- memcpy(pd->mac_addr, mac_addr, ETH_ALEN);
+ ether_addr_copy(pd->mac_addr, mac_addr);
if (0 != oz_elt_buf_init(&pd->elt_buff)) {
kfree(pd);
pd = NULL;
@@ -284,11 +285,11 @@ int oz_services_start(struct oz_pd *pd, u16 apps, int resume)
ai->app_id);
break;
}
- oz_polling_lock_bh();
+ spin_lock_bh(&g_polling_lock);
pd->total_apps |= (1<<ai->app_id);
if (resume)
pd->paused_apps &= ~(1<<ai->app_id);
- oz_polling_unlock_bh();
+ spin_unlock_bh(&g_polling_lock);
}
}
return rc;
@@ -304,14 +305,14 @@ void oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
oz_pd_dbg(pd, ON, "%s: (0x%x) pause(%d)\n", __func__, apps, pause);
for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
if (apps & (1<<ai->app_id)) {
- oz_polling_lock_bh();
+ spin_lock_bh(&g_polling_lock);
if (pause) {
pd->paused_apps |= (1<<ai->app_id);
} else {
pd->total_apps &= ~(1<<ai->app_id);
pd->paused_apps &= ~(1<<ai->app_id);
}
- oz_polling_unlock_bh();
+ spin_unlock_bh(&g_polling_lock);
ai->stop(pd, pause);
}
}
@@ -349,17 +350,17 @@ void oz_pd_stop(struct oz_pd *pd)
oz_dbg(ON, "oz_pd_stop() State = 0x%x\n", pd->state);
oz_pd_indicate_farewells(pd);
- oz_polling_lock_bh();
+ spin_lock_bh(&g_polling_lock);
stop_apps = pd->total_apps;
pd->total_apps = 0;
pd->paused_apps = 0;
- oz_polling_unlock_bh();
+ spin_unlock_bh(&g_polling_lock);
oz_services_stop(pd, stop_apps, 0);
- oz_polling_lock_bh();
+ spin_lock_bh(&g_polling_lock);
oz_pd_set_state(pd, OZ_PD_S_STOPPED);
/* Remove from PD list.*/
list_del(&pd->link);
- oz_polling_unlock_bh();
+ spin_unlock_bh(&g_polling_lock);
oz_dbg(ON, "pd ref count = %d\n", atomic_read(&pd->ref_count));
oz_pd_put(pd);
}
@@ -372,9 +373,9 @@ int oz_pd_sleep(struct oz_pd *pd)
int do_stop = 0;
u16 stop_apps;
- oz_polling_lock_bh();
+ spin_lock_bh(&g_polling_lock);
if (pd->state & (OZ_PD_S_SLEEP | OZ_PD_S_STOPPED)) {
- oz_polling_unlock_bh();
+ spin_unlock_bh(&g_polling_lock);
return 0;
}
if (pd->keep_alive && pd->session_id)
@@ -383,7 +384,7 @@ int oz_pd_sleep(struct oz_pd *pd)
do_stop = 1;
stop_apps = pd->total_apps;
- oz_polling_unlock_bh();
+ spin_unlock_bh(&g_polling_lock);
if (do_stop) {
oz_pd_stop(pd);
} else {
@@ -999,15 +1000,15 @@ void oz_pd_indicate_farewells(struct oz_pd *pd)
const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB-1];
while (1) {
- oz_polling_lock_bh();
+ spin_lock_bh(&g_polling_lock);
if (list_empty(&pd->farewell_list)) {
- oz_polling_unlock_bh();
+ spin_unlock_bh(&g_polling_lock);
break;
}
f = list_first_entry(&pd->farewell_list,
struct oz_farewell, link);
list_del(&f->link);
- oz_polling_unlock_bh();
+ spin_unlock_bh(&g_polling_lock);
if (ai->farewell)
ai->farewell(pd, f->ep_num, f->report, f->len);
kfree(f);
diff --git a/drivers/staging/ozwpan/ozpd.h b/drivers/staging/ozwpan/ozpd.h
index 12c712956888..ad5fe7a6e619 100644
--- a/drivers/staging/ozwpan/ozpd.h
+++ b/drivers/staging/ozwpan/ozpd.h
@@ -22,6 +22,11 @@
#define OZ_TIMER_HEARTBEAT 2
#define OZ_TIMER_STOP 3
+/*
+ *External spinlock variable
+ */
+extern spinlock_t g_polling_lock;
+
/* Data structure that hold information on a frame for transmisson. This is
* built when the frame is first transmitted and is used to rebuild the frame
* if a re-transmission is required.
diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c
index 5d965cf06d59..f09acd0bb013 100644
--- a/drivers/staging/ozwpan/ozproto.c
+++ b/drivers/staging/ozwpan/ozproto.c
@@ -38,9 +38,13 @@ struct oz_binding {
};
/*
+ * External variable
+ */
+
+DEFINE_SPINLOCK(g_polling_lock);
+/*
* Static external variables.
*/
-static DEFINE_SPINLOCK(g_polling_lock);
static LIST_HEAD(g_pd_list);
static LIST_HEAD(g_binding);
static DEFINE_SPINLOCK(g_binding_lock);
@@ -664,32 +668,26 @@ void oz_binding_add(const char *net_dev)
{
struct oz_binding *binding;
- binding = kmalloc(sizeof(struct oz_binding), GFP_KERNEL);
- if (binding) {
- binding->ptype.type = __constant_htons(OZ_ETHERTYPE);
- binding->ptype.func = oz_pkt_recv;
- if (net_dev && *net_dev) {
- memcpy(binding->name, net_dev, OZ_MAX_BINDING_LEN);
- oz_dbg(ON, "Adding binding: %s\n", net_dev);
- binding->ptype.dev =
- dev_get_by_name(&init_net, net_dev);
- if (binding->ptype.dev == NULL) {
- oz_dbg(ON, "Netdev %s not found\n", net_dev);
- kfree(binding);
- binding = NULL;
- }
- } else {
- oz_dbg(ON, "Binding to all netcards\n");
- memset(binding->name, 0, OZ_MAX_BINDING_LEN);
- binding->ptype.dev = NULL;
- }
- if (binding) {
- dev_add_pack(&binding->ptype);
- spin_lock_bh(&g_binding_lock);
- list_add_tail(&binding->link, &g_binding);
- spin_unlock_bh(&g_binding_lock);
+ binding = kzalloc(sizeof(struct oz_binding), GFP_KERNEL);
+ if (!binding)
+ return;
+
+ binding->ptype.type = htons(OZ_ETHERTYPE);
+ binding->ptype.func = oz_pkt_recv;
+ if (net_dev && *net_dev) {
+ memcpy(binding->name, net_dev, OZ_MAX_BINDING_LEN);
+ oz_dbg(ON, "Adding binding: %s\n", net_dev);
+ binding->ptype.dev = dev_get_by_name(&init_net, net_dev);
+ if (binding->ptype.dev == NULL) {
+ oz_dbg(ON, "Netdev %s not found\n", net_dev);
+ kfree(binding);
+ return;
}
}
+ dev_add_pack(&binding->ptype);
+ spin_lock_bh(&g_binding_lock);
+ list_add_tail(&binding->link, &g_binding);
+ spin_unlock_bh(&g_binding_lock);
}
/*
@@ -800,12 +798,3 @@ int oz_get_pd_list(struct oz_mac_addr *addr, int max_count)
return count;
}
-void oz_polling_lock_bh(void)
-{
- spin_lock_bh(&g_polling_lock);
-}
-
-void oz_polling_unlock_bh(void)
-{
- spin_unlock_bh(&g_polling_lock);
-}
diff --git a/drivers/staging/ozwpan/ozproto.h b/drivers/staging/ozwpan/ozproto.h
index 0c49c8a0e815..cb38e02c968e 100644
--- a/drivers/staging/ozwpan/ozproto.h
+++ b/drivers/staging/ozwpan/ozproto.h
@@ -59,8 +59,6 @@ void oz_binding_remove(const char *net_dev);
void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time);
void oz_timer_delete(struct oz_pd *pd, int type);
void oz_pd_request_heartbeat(struct oz_pd *pd);
-void oz_polling_lock_bh(void);
-void oz_polling_unlock_bh(void);
void oz_pd_heartbeat_handler(unsigned long data);
void oz_pd_timeout_handler(unsigned long data);
enum hrtimer_restart oz_pd_heartbeat_event(struct hrtimer *timer);
diff --git a/drivers/staging/ozwpan/ozprotocol.h b/drivers/staging/ozwpan/ozprotocol.h
index 17b09b9a5b08..9bbb182f2776 100644
--- a/drivers/staging/ozwpan/ozprotocol.h
+++ b/drivers/staging/ozwpan/ozprotocol.h
@@ -192,7 +192,7 @@ struct oz_get_desc_req {
u16 size;
u8 req_type;
u8 desc_type;
- u16 w_index;
+ __le16 w_index;
u8 index;
} PACKED;
@@ -219,8 +219,8 @@ struct oz_get_desc_rsp {
u8 elt_seq_num;
u8 type;
u8 req_id;
- u16 offset;
- u16 total_size;
+ __le16 offset;
+ __le16 total_size;
u8 rcode;
u8 data[1];
} PACKED;
diff --git a/drivers/staging/ozwpan/ozusbif.h b/drivers/staging/ozwpan/ozusbif.h
index 8531438d7586..4249fa374012 100644
--- a/drivers/staging/ozwpan/ozusbif.h
+++ b/drivers/staging/ozwpan/ozusbif.h
@@ -23,7 +23,7 @@ int oz_usb_stream_delete(void *hpd, u8 ep_num);
int oz_usb_control_req(void *hpd, u8 req_id, struct usb_ctrlrequest *setup,
const u8 *data, int data_len);
int oz_usb_get_desc_req(void *hpd, u8 req_id, u8 req_type, u8 desc_type,
- u8 index, u16 windex, int offset, int len);
+ u8 index, __le16 windex, int offset, int len);
int oz_usb_send_isoc(void *hpd, u8 ep_num, struct urb *urb);
void oz_usb_request_heartbeat(void *hpd);
diff --git a/drivers/staging/ozwpan/ozusbsvc1.c b/drivers/staging/ozwpan/ozusbsvc1.c
index 617f51cdaea7..f32d01427f77 100644
--- a/drivers/staging/ozwpan/ozusbsvc1.c
+++ b/drivers/staging/ozwpan/ozusbsvc1.c
@@ -54,7 +54,7 @@ static int oz_usb_submit_elt(struct oz_elt_buf *eb, struct oz_elt_info *ei,
* Context: softirq
*/
int oz_usb_get_desc_req(void *hpd, u8 req_id, u8 req_type, u8 desc_type,
- u8 index, u16 windex, int offset, int len)
+ u8 index, __le16 windex, int offset, int len)
{
struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
struct oz_pd *pd = usb_ctx->pd;
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index ec4b1fd14021..08f9a4896116 100644
--- a/drivers/staging/panel/panel.c
+++ b/drivers/staging/panel/panel.c
@@ -171,8 +171,8 @@ struct logical_input {
union {
struct { /* valid when type == INPUT_TYPE_STD */
- void (*press_fct) (int);
- void (*release_fct) (int);
+ void (*press_fct)(int);
+ void (*release_fct)(int);
int press_data;
int release_data;
} std;
@@ -417,9 +417,9 @@ static char lcd_must_clear;
static char lcd_left_shift;
static char init_in_progress;
-static void (*lcd_write_cmd) (int);
-static void (*lcd_write_data) (int);
-static void (*lcd_clear_fast) (void);
+static void (*lcd_write_cmd)(int);
+static void (*lcd_write_data)(int);
+static void (*lcd_clear_fast)(void);
static DEFINE_SPINLOCK(pprt_lock);
static struct timer_list scan_timer;
@@ -457,14 +457,12 @@ MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead");
static int lcd_type = -1;
module_param(lcd_type, int, 0000);
MODULE_PARM_DESC(lcd_type,
- "LCD type: 0=none, 1=old //, 2=serial ks0074, "
- "3=hantronix //, 4=nexcom //, 5=compiled-in");
+ "LCD type: 0=none, 1=old //, 2=serial ks0074, 3=hantronix //, 4=nexcom //, 5=compiled-in");
static int lcd_proto = -1;
module_param(lcd_proto, int, 0000);
MODULE_PARM_DESC(lcd_proto,
- "LCD communication: 0=parallel (//), 1=serial,"
- "2=TI LCD Interface");
+ "LCD communication: 0=parallel (//), 1=serial, 2=TI LCD Interface");
static int lcd_charset = -1;
module_param(lcd_charset, int, 0000);
@@ -473,8 +471,7 @@ MODULE_PARM_DESC(lcd_charset, "LCD character set: 0=standard, 1=KS0074");
static int keypad_type = -1;
module_param(keypad_type, int, 0000);
MODULE_PARM_DESC(keypad_type,
- "Keypad type: 0=none, 1=old 6 keys, 2=new 6+1 keys, "
- "3=nexcom 4 keys");
+ "Keypad type: 0=none, 1=old 6 keys, 2=new 6+1 keys, 3=nexcom 4 keys");
static int profile = DEFAULT_PROFILE;
module_param(profile, int, 0000);
@@ -494,38 +491,32 @@ MODULE_PARM_DESC(profile,
static int lcd_e_pin = PIN_NOT_SET;
module_param(lcd_e_pin, int, 0000);
MODULE_PARM_DESC(lcd_e_pin,
- "# of the // port pin connected to LCD 'E' signal, "
- "with polarity (-17..17)");
+ "# of the // port pin connected to LCD 'E' signal, with polarity (-17..17)");
static int lcd_rs_pin = PIN_NOT_SET;
module_param(lcd_rs_pin, int, 0000);
MODULE_PARM_DESC(lcd_rs_pin,
- "# of the // port pin connected to LCD 'RS' signal, "
- "with polarity (-17..17)");
+ "# of the // port pin connected to LCD 'RS' signal, with polarity (-17..17)");
static int lcd_rw_pin = PIN_NOT_SET;
module_param(lcd_rw_pin, int, 0000);
MODULE_PARM_DESC(lcd_rw_pin,
- "# of the // port pin connected to LCD 'RW' signal, "
- "with polarity (-17..17)");
+ "# of the // port pin connected to LCD 'RW' signal, with polarity (-17..17)");
static int lcd_bl_pin = PIN_NOT_SET;
module_param(lcd_bl_pin, int, 0000);
MODULE_PARM_DESC(lcd_bl_pin,
- "# of the // port pin connected to LCD backlight, "
- "with polarity (-17..17)");
+ "# of the // port pin connected to LCD backlight, with polarity (-17..17)");
static int lcd_da_pin = PIN_NOT_SET;
module_param(lcd_da_pin, int, 0000);
MODULE_PARM_DESC(lcd_da_pin,
- "# of the // port pin connected to serial LCD 'SDA' "
- "signal, with polarity (-17..17)");
+ "# of the // port pin connected to serial LCD 'SDA' signal, with polarity (-17..17)");
static int lcd_cl_pin = PIN_NOT_SET;
module_param(lcd_cl_pin, int, 0000);
MODULE_PARM_DESC(lcd_cl_pin,
- "# of the // port pin connected to serial LCD 'SCL' "
- "signal, with polarity (-17..17)");
+ "# of the // port pin connected to serial LCD 'SCL' signal, with polarity (-17..17)");
static const unsigned char *lcd_char_conv;
@@ -2017,9 +2008,9 @@ static struct logical_input *panel_bind_key(const char *name, const char *press,
* be bound.
*/
static struct logical_input *panel_bind_callback(char *name,
- void (*press_fct) (int),
+ void (*press_fct)(int),
int press_data,
- void (*release_fct) (int),
+ void (*release_fct)(int),
int release_data)
{
struct logical_input *callback;
diff --git a/drivers/staging/rtl8187se/Module.symvers b/drivers/staging/rtl8187se/Module.symvers
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/drivers/staging/rtl8187se/Module.symvers
diff --git a/drivers/staging/rtl8187se/ieee80211/dot11d.h b/drivers/staging/rtl8187se/ieee80211/dot11d.h
index 63f4f3c72f10..f996691307bf 100644
--- a/drivers/staging/rtl8187se/ieee80211/dot11d.h
+++ b/drivers/staging/rtl8187se/ieee80211/dot11d.h
@@ -11,13 +11,13 @@ typedef struct _CHNL_TXPOWER_TRIPLE {
u8 FirstChnl;
u8 NumChnls;
u8 MaxTxPowerInDbm;
-}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE;
+} CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE;
typedef enum _DOT11D_STATE {
DOT11D_STATE_NONE = 0,
DOT11D_STATE_LEARNED,
DOT11D_STATE_DONE,
-}DOT11D_STATE;
+} DOT11D_STATE;
typedef struct _RT_DOT11D_INFO {
/* DECLARE_RT_OBJECT(RT_DOT12D_INFO); */
@@ -35,9 +35,10 @@ typedef struct _RT_DOT11D_INFO {
u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1];
DOT11D_STATE State;
-}RT_DOT11D_INFO, *PRT_DOT11D_INFO;
-#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 )
-#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5])
+} RT_DOT11D_INFO, *PRT_DOT11D_INFO;
+
+#define eqMacAddr(a, b) (((a)[0] == (b)[0] && (a)[1] == (b)[1] && (a)[2] == (b)[2] && (a)[3] == (b)[3] && (a)[4] == (b)[4] && (a)[5] == (b)[5]) ? 1:0)
+#define cpMacAddr(des, src) ((des)[0] = (src)[0], (des)[1] = (src)[1], (des)[2] = (src)[2], (des)[3] = (src)[3], (des)[4] = (src)[4], (des)[5] = (src)[5])
#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo))
#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
index 09ffd9bc8991..d1763b7b8f27 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
@@ -473,7 +473,7 @@ enum {
};
struct ieee80211_header_data {
- u16 frame_ctl;
+ __le16 frame_ctl;
u16 duration_id;
u8 addr1[6];
u8 addr2[6];
@@ -482,7 +482,7 @@ struct ieee80211_header_data {
};
struct ieee80211_hdr_4addr {
- u16 frame_ctl;
+ __le16 frame_ctl;
u16 duration_id;
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
@@ -709,10 +709,10 @@ enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame};
#define MAX_IE_LEN 0xFF //+YJ,080625
-typedef struct _CHANNEL_LIST{
- u8 Channel[MAX_CHANNEL_NUMBER + 1];
- u8 Len;
-}CHANNEL_LIST, *PCHANNEL_LIST;
+struct rtl8187se_channel_list {
+ u8 channel[MAX_CHANNEL_NUMBER + 1];
+ u8 len;
+};
//by amy for ps
#define IEEE80211_WATCH_DOG_TIME 2000
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c
index c8013d373a77..4fe253818630 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c
@@ -58,7 +58,7 @@ struct ieee80211_ccmp_data {
u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN];
};
-void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm,
+static void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm,
const u8 pt[16], u8 ct[16])
{
crypto_cipher_encrypt_one((void *)tfm, ct, pt);
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c
index c5907968e1a7..6c1acc5dfba7 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c
@@ -187,8 +187,7 @@ static inline u16 Mk16_le(u16 *v)
}
-static const u16 Sbox[256] =
-{
+static const u16 Sbox[256] = {
0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
@@ -307,7 +306,7 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
int len;
u8 *pos;
struct ieee80211_hdr_4addr *hdr;
- u8 rc4key[16],*icv;
+ u8 rc4key[16], *icv;
u32 crc;
struct scatterlist sg;
int ret;
@@ -348,7 +347,7 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
icv[3] = crc >> 24;
crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
sg_init_one(&sg, pos, len + 4);
- ret= crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
+ ret = crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
tkey->tx_iv16++;
if (tkey->tx_iv16 == 0) {
@@ -537,9 +536,9 @@ static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
michael_mic_hdr(skb, tkey->tx_hdr);
- if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) {
+ if (IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl)))
tkey->tx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07;
- }
+
pos = skb_put(skb, 8);
if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
@@ -583,9 +582,8 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
return -1;
michael_mic_hdr(skb, tkey->rx_hdr);
- if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) {
+ if (IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl)))
tkey->rx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07;
- }
if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c
index f114f9a33e17..f25367224941 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c
@@ -11,7 +11,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-//#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/random.h>
@@ -28,8 +27,6 @@ MODULE_AUTHOR("Jouni Malinen");
MODULE_DESCRIPTION("Host AP crypt: WEP");
MODULE_LICENSE("GPL");
-
-
struct prism2_wep_data {
u32 iv;
#define WEP_KEY_LEN 13
@@ -40,7 +37,6 @@ struct prism2_wep_data {
struct crypto_blkcipher *rx_tfm;
};
-
static void *prism2_wep_init(int keyidx)
{
struct prism2_wep_data *priv;
@@ -79,7 +75,6 @@ fail:
return NULL;
}
-
static void prism2_wep_deinit(void *priv)
{
struct prism2_wep_data *_priv = priv;
@@ -94,7 +89,6 @@ static void prism2_wep_deinit(void *priv)
kfree(priv);
}
-
/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
* for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
* so the payload length increases with 8 bytes.
@@ -157,7 +151,6 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
}
-
/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
* the frame: IV (4 bytes), encrypted payload (including SNAP header),
* ICV (4 bytes). len includes both IV and ICV.
@@ -219,7 +212,6 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
return 0;
}
-
static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv)
{
struct prism2_wep_data *wep = priv;
@@ -233,7 +225,6 @@ static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv)
return 0;
}
-
static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
{
struct prism2_wep_data *wep = priv;
@@ -246,7 +237,6 @@ static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
return wep->key_len;
}
-
static char *prism2_wep_print_stats(char *p, void *priv)
{
struct prism2_wep_data *wep = priv;
@@ -255,7 +245,6 @@ static char *prism2_wep_print_stats(char *p, void *priv)
return p;
}
-
static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
.name = "WEP",
.init = prism2_wep_init,
@@ -272,21 +261,17 @@ static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
.owner = THIS_MODULE,
};
-
int ieee80211_crypto_wep_init(void)
{
return ieee80211_register_crypto_ops(&ieee80211_crypt_wep);
}
-
void ieee80211_crypto_wep_exit(void)
{
ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep);
}
-
void ieee80211_wep_null(void)
{
-// printk("============>%s()\n", __func__);
return;
}
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
index c27392d8b640..03eb164798cd 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
@@ -13,7 +13,6 @@
* released under the GPL
*/
-
#include "ieee80211.h"
#include <linux/random.h>
@@ -24,14 +23,6 @@
#include <linux/etherdevice.h>
#include "dot11d.h"
-u8 rsn_authen_cipher_suite[16][4] = {
- {0x00, 0x0F, 0xAC, 0x00}, //Use group key, //Reserved
- {0x00, 0x0F, 0xAC, 0x01}, //WEP-40 //RSNA default
- {0x00, 0x0F, 0xAC, 0x02}, //TKIP //NONE //{used just as default}
- {0x00, 0x0F, 0xAC, 0x03}, //WRAP-historical
- {0x00, 0x0F, 0xAC, 0x04}, //CCMP
- {0x00, 0x0F, 0xAC, 0x05}, //WEP-104
-};
short ieee80211_is_54g(const struct ieee80211_network *net)
{
@@ -62,14 +53,13 @@ static unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee)
}
/* place the MFIE rate, tag to the memory (double) poised.
- * Then it updates the pointer so that
- * it points after the new MFIE tag added.
+ * Then it updates the pointer so that it points after the new MFIE tag added.
*/
static void ieee80211_MFIE_Brate(struct ieee80211_device *ieee, u8 **tag_p)
{
u8 *tag = *tag_p;
- if (ieee->modulation & IEEE80211_CCK_MODULATION){
+ if (ieee->modulation & IEEE80211_CCK_MODULATION) {
*tag++ = MFIE_TYPE_RATES;
*tag++ = 4;
*tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
@@ -86,8 +76,7 @@ static void ieee80211_MFIE_Grate(struct ieee80211_device *ieee, u8 **tag_p)
{
u8 *tag = *tag_p;
- if (ieee->modulation & IEEE80211_OFDM_MODULATION){
-
+ if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
*tag++ = MFIE_TYPE_RATES_EX;
*tag++ = 8;
*tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB;
@@ -100,22 +89,20 @@ static void ieee80211_MFIE_Grate(struct ieee80211_device *ieee, u8 **tag_p)
*tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB;
}
-
/* We may add an option for custom rates that specific HW might support */
*tag_p = tag;
}
-
static void ieee80211_WMM_Info(struct ieee80211_device *ieee, u8 **tag_p)
{
u8 *tag = *tag_p;
- *tag++ = MFIE_TYPE_GENERIC; //0
+ *tag++ = MFIE_TYPE_GENERIC; /* 0 */
*tag++ = 7;
*tag++ = 0x00;
*tag++ = 0x50;
*tag++ = 0xf2;
- *tag++ = 0x02;//5
+ *tag++ = 0x02; /* 5 */
*tag++ = 0x00;
*tag++ = 0x01;
#ifdef SUPPORT_USPD
@@ -148,32 +135,23 @@ static void ieee80211_TURBO_Info(struct ieee80211_device *ieee, u8 **tag_p)
static void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb)
{
int nh;
- nh = (ieee->mgmt_queue_head +1) % MGMT_QUEUE_NUM;
+ nh = (ieee->mgmt_queue_head + 1) % MGMT_QUEUE_NUM;
-/*
- * if the queue is full but we have newer frames then
- * just overwrites the oldest.
- *
- * if (nh == ieee->mgmt_queue_tail)
- * return -1;
- */
ieee->mgmt_queue_head = nh;
ieee->mgmt_queue_ring[nh] = skb;
-
- //return 0;
}
static struct sk_buff *dequeue_mgmt(struct ieee80211_device *ieee)
{
struct sk_buff *ret;
- if(ieee->mgmt_queue_tail == ieee->mgmt_queue_head)
+ if (ieee->mgmt_queue_tail == ieee->mgmt_queue_head)
return NULL;
ret = ieee->mgmt_queue_ring[ieee->mgmt_queue_tail];
ieee->mgmt_queue_tail =
- (ieee->mgmt_queue_tail+1) % MGMT_QUEUE_NUM;
+ (ieee->mgmt_queue_tail + 1) % MGMT_QUEUE_NUM;
return ret;
}
@@ -183,7 +161,6 @@ static void init_mgmt_queue(struct ieee80211_device *ieee)
ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0;
}
-
void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl);
inline void softmac_mgmt_xmit(struct sk_buff *skb,
@@ -191,20 +168,18 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb,
{
unsigned long flags;
short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE;
- struct ieee80211_hdr_3addr *header=
+ struct ieee80211_hdr_3addr *header =
(struct ieee80211_hdr_3addr *) skb->data;
-
spin_lock_irqsave(&ieee->lock, flags);
/* called with 2nd param 0, no mgmt lock required */
- ieee80211_sta_wakeup(ieee,0);
+ ieee80211_sta_wakeup(ieee, 0);
- if(single){
- if(ieee->queue_stop){
-
- enqueue_mgmt(ieee,skb);
- }else{
+ if (single) {
+ if (ieee->queue_stop) {
+ enqueue_mgmt(ieee, skb);
+ } else {
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0]<<4);
if (ieee->seq_ctrl[0] == 0xFFF)
@@ -214,11 +189,11 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb,
/* avoid watchdog triggers */
ieee->dev->trans_start = jiffies;
- ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate);
+ ieee->softmac_data_hard_start_xmit(skb, ieee->dev, ieee->basic_rate);
}
spin_unlock_irqrestore(&ieee->lock, flags);
- }else{
+ } else {
spin_unlock_irqrestore(&ieee->lock, flags);
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags);
@@ -231,24 +206,20 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb,
/* avoid watchdog triggers */
ieee->dev->trans_start = jiffies;
- ieee->softmac_hard_start_xmit(skb,ieee->dev);
+ ieee->softmac_hard_start_xmit(skb, ieee->dev);
spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags);
}
}
-
inline void softmac_ps_mgmt_xmit(struct sk_buff *skb,
struct ieee80211_device *ieee)
{
-
short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE;
struct ieee80211_hdr_3addr *header =
(struct ieee80211_hdr_3addr *) skb->data;
-
- if(single){
-
+ if (single) {
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
@@ -258,10 +229,8 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb,
/* avoid watchdog triggers */
ieee->dev->trans_start = jiffies;
- ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate);
-
- }else{
-
+ ieee->softmac_data_hard_start_xmit(skb, ieee->dev, ieee->basic_rate);
+ } else {
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
if (ieee->seq_ctrl[0] == 0xFFF)
@@ -271,12 +240,10 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb,
/* avoid watchdog triggers */
ieee->dev->trans_start = jiffies;
- ieee->softmac_hard_start_xmit(skb,ieee->dev);
-
+ ieee->softmac_hard_start_xmit(skb, ieee->dev);
}
-// dev_kfree_skb_any(skb);//edit by thomas
}
-//by amy for power save
+
inline struct sk_buff *
ieee80211_disassociate_skb(struct ieee80211_network *beacon,
struct ieee80211_device *ieee, u8 asRsn)
@@ -288,7 +255,7 @@ ieee80211_disassociate_skb(struct ieee80211_network *beacon,
if (!skb)
return NULL;
- disass = (struct ieee80211_disassoc_frame *) skb_put(skb,sizeof(struct ieee80211_disassoc_frame));
+ disass = (struct ieee80211_disassoc_frame *) skb_put(skb, sizeof(struct ieee80211_disassoc_frame));
disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
disass->header.duration_id = 0;
@@ -299,21 +266,19 @@ ieee80211_disassociate_skb(struct ieee80211_network *beacon,
disass->reasoncode = asRsn;
return skb;
}
+
void SendDisassociation(struct ieee80211_device *ieee, u8 *asSta, u8 asRsn)
{
- struct ieee80211_network *beacon = &ieee->current_network;
- struct sk_buff *skb;
- skb = ieee80211_disassociate_skb(beacon,ieee,asRsn);
- if (skb){
- softmac_mgmt_xmit(skb, ieee);
- //dev_kfree_skb_any(skb);//edit by thomas
- }
+ struct ieee80211_network *beacon = &ieee->current_network;
+ struct sk_buff *skb;
+ skb = ieee80211_disassociate_skb(beacon, ieee, asRsn);
+ if (skb)
+ softmac_mgmt_xmit(skb, ieee);
}
-//by amy for power save
inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee)
{
- unsigned int len,rate_len;
+ unsigned int len, rate_len;
u8 *tag;
struct sk_buff *skb;
struct ieee80211_probe_request *req;
@@ -327,75 +292,45 @@ inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee)
if (!skb)
return NULL;
- req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request));
+ req = (struct ieee80211_probe_request *) skb_put(skb, sizeof(struct ieee80211_probe_request));
req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
- req->header.duration_id = 0; //FIXME: is this OK ?
+ req->header.duration_id = 0; /* FIXME: is this OK ? */
memset(req->header.addr1, 0xff, ETH_ALEN);
memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
memset(req->header.addr3, 0xff, ETH_ALEN);
- tag = (u8 *) skb_put(skb,len+2+rate_len);
+ tag = (u8 *) skb_put(skb, len + 2 + rate_len);
*tag++ = MFIE_TYPE_SSID;
*tag++ = len;
memcpy(tag, ieee->current_network.ssid, len);
tag += len;
- ieee80211_MFIE_Brate(ieee,&tag);
- ieee80211_MFIE_Grate(ieee,&tag);
+ ieee80211_MFIE_Brate(ieee, &tag);
+ ieee80211_MFIE_Grate(ieee, &tag);
return skb;
}
struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee);
-void ext_ieee80211_send_beacon_wq(struct ieee80211_device *ieee)
-{
- struct sk_buff *skb;
-
- //unsigned long flags;
-
- skb = ieee80211_get_beacon_(ieee);
-
- if (skb){
- softmac_mgmt_xmit(skb, ieee);
- ieee->softmac_stats.tx_beacons++;
- dev_kfree_skb_any(skb);//edit by thomas
- }
-
-
- //printk(KERN_WARNING "[1] beacon sending!\n");
- ieee->beacon_timer.expires = jiffies +
- (MSECS( ieee->current_network.beacon_interval -5));
-
- //spin_lock_irqsave(&ieee->beacon_lock,flags);
- if(ieee->beacon_txing)
- add_timer(&ieee->beacon_timer);
- //spin_unlock_irqrestore(&ieee->beacon_lock,flags);
-}
-
static void ieee80211_send_beacon(struct ieee80211_device *ieee)
{
struct sk_buff *skb;
- //unsigned long flags;
-
skb = ieee80211_get_beacon_(ieee);
- if (skb){
+ if (skb) {
softmac_mgmt_xmit(skb, ieee);
ieee->softmac_stats.tx_beacons++;
- dev_kfree_skb_any(skb);//edit by thomas
+ dev_kfree_skb_any(skb);
}
- //printk(KERN_WARNING "[1] beacon sending!\n");
ieee->beacon_timer.expires = jiffies +
- (MSECS( ieee->current_network.beacon_interval -5));
+ (MSECS(ieee->current_network.beacon_interval - 5));
- //spin_lock_irqsave(&ieee->beacon_lock,flags);
- if(ieee->beacon_txing)
+ if (ieee->beacon_txing)
add_timer(&ieee->beacon_timer);
- //spin_unlock_irqrestore(&ieee->beacon_lock,flags);
}
@@ -415,16 +350,15 @@ static void ieee80211_send_probe(struct ieee80211_device *ieee)
struct sk_buff *skb;
skb = ieee80211_probe_req(ieee);
- if (skb){
+ if (skb) {
softmac_mgmt_xmit(skb, ieee);
ieee->softmac_stats.tx_probe_rq++;
- //dev_kfree_skb_any(skb);//edit by thomas
}
}
static void ieee80211_send_probe_requests(struct ieee80211_device *ieee)
{
- if (ieee->active_scan && (ieee->softmac_features & IEEE_SOFTMAC_PROBERQ)){
+ if (ieee->active_scan && (ieee->softmac_features & IEEE_SOFTMAC_PROBERQ)) {
ieee80211_send_probe(ieee);
ieee80211_send_probe(ieee);
}
@@ -439,17 +373,14 @@ static void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee)
u8 channel_map[MAX_CHANNEL_NUMBER+1];
memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
down(&ieee->scan_sem);
-// printk("==================> Sync scan\n");
- while(1)
- {
-
- do{
+ while (1) {
+ do {
ch++;
if (ch > MAX_CHANNEL_NUMBER)
goto out; /* scan completed */
- }while(!channel_map[ch]);
+ } while (!channel_map[ch]);
/* this function can be called in two situations
* 1- We have switched to ad-hoc mode and we are
* performing a complete syncro scan before conclude
@@ -473,101 +404,74 @@ static void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee)
goto out;
ieee->set_chan(ieee->dev, ch);
-// printk("=====>channel=%d ",ch);
- if(channel_map[ch] == 1)
- {
-// printk("====send probe request\n");
+ if (channel_map[ch] == 1)
ieee80211_send_probe_requests(ieee);
- }
+
/* this prevent excessive time wait when we
* need to wait for a syncro scan to end..
*/
if (ieee->sync_scan_hurryup)
goto out;
-
msleep_interruptible_rtl(IEEE80211_SOFTMAC_SCAN_TIME);
-
}
out:
ieee->sync_scan_hurryup = 0;
up(&ieee->scan_sem);
- if(IS_DOT11D_ENABLE(ieee))
+ if (IS_DOT11D_ENABLE(ieee))
DOT11D_ScanComplete(ieee);
}
void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee)
{
int ch;
- unsigned int watch_dog = 0;
+ unsigned int watch_dog = 0;
u8 channel_map[MAX_CHANNEL_NUMBER+1];
memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
- down(&ieee->scan_sem);
+ down(&ieee->scan_sem);
ch = ieee->current_network.channel;
-// if(ieee->sync_scan_hurryup)
-// {
-
-// printk("stop scan sync\n");
-// goto out;
-// }
-// printk("=======hh===============>ips scan\n");
- while(1)
- {
- /* this function can be called in two situations
- * 1- We have switched to ad-hoc mode and we are
- * performing a complete syncro scan before conclude
- * there are no interesting cell and to create a
- * new one. In this case the link state is
- * IEEE80211_NOLINK until we found an interesting cell.
- * If so the ieee8021_new_net, called by the RX path
- * will set the state to IEEE80211_LINKED, so we stop
- * scanning
- * 2- We are linked and the root uses run iwlist scan.
- * So we switch to IEEE80211_LINKED_SCANNING to remember
- * that we are still logically linked (not interested in
- * new network events, despite for updating the net list,
- * but we are temporarily 'unlinked' as the driver shall
- * not filter RX frames and the channel is changing.
- * So the only situation in witch are interested is to check
- * if the state become LINKED because of the #1 situation
- */
+
+ while (1) {
+ /* this function can be called in two situations
+ * 1- We have switched to ad-hoc mode and we are
+ * performing a complete syncro scan before conclude
+ * there are no interesting cell and to create a
+ * new one. In this case the link state is
+ * IEEE80211_NOLINK until we found an interesting cell.
+ * If so the ieee8021_new_net, called by the RX path
+ * will set the state to IEEE80211_LINKED, so we stop
+ * scanning
+ * 2- We are linked and the root uses run iwlist scan.
+ * So we switch to IEEE80211_LINKED_SCANNING to remember
+ * that we are still logically linked (not interested in
+ * new network events, despite for updating the net list,
+ * but we are temporarily 'unlinked' as the driver shall
+ * not filter RX frames and the channel is changing.
+ * So the only situation in witch are interested is to check
+ * if the state become LINKED because of the #1 situation
+ */
if (ieee->state == IEEE80211_LINKED)
- {
goto out;
- }
- if(channel_map[ieee->current_network.channel] > 0)
- {
+
+ if (channel_map[ieee->current_network.channel] > 0)
ieee->set_chan(ieee->dev, ieee->current_network.channel);
-// printk("======>channel=%d ",ieee->current_network.channel);
- }
- if(channel_map[ieee->current_network.channel] == 1)
- {
-// printk("====send probe request\n");
+
+ if (channel_map[ieee->current_network.channel] == 1)
ieee80211_send_probe_requests(ieee);
- }
- /* this prevent excessive time wait when we
- * need to wait for a syncro scan to end..
- */
-// if (ieee->sync_scan_hurryup)
-// goto out;
msleep_interruptible_rtl(IEEE80211_SOFTMAC_SCAN_TIME);
- do{
+ do {
if (watch_dog++ >= MAX_CHANNEL_NUMBER)
- // if (++watch_dog >= 15);//MAX_CHANNEL_NUMBER) //YJ,modified,080630
goto out; /* scan completed */
ieee->current_network.channel = (ieee->current_network.channel + 1)%MAX_CHANNEL_NUMBER;
- }while(!channel_map[ieee->current_network.channel]);
- }
+ } while (!channel_map[ieee->current_network.channel]);
+ }
out:
- //ieee->sync_scan_hurryup = 0;
- //ieee->set_chan(ieee->dev, ch);
- //ieee->current_network.channel = ch;
ieee->actscanning = false;
up(&ieee->scan_sem);
- if(IS_DOT11D_ENABLE(ieee))
+ if (IS_DOT11D_ENABLE(ieee))
DOT11D_ScanComplete(ieee);
}
@@ -575,29 +479,24 @@ static void ieee80211_softmac_scan_wq(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq);
- static short watchdog = 0;
+ static short watchdog;
u8 channel_map[MAX_CHANNEL_NUMBER+1];
memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
-// printk("ieee80211_softmac_scan_wq ENABLE_IPS\n");
-// printk("in %s\n",__func__);
down(&ieee->scan_sem);
- do{
+ do {
ieee->current_network.channel =
(ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER;
if (watchdog++ > MAX_CHANNEL_NUMBER)
goto out; /* no good chans */
+ } while (!channel_map[ieee->current_network.channel]);
- }while(!channel_map[ieee->current_network.channel]);
-
- //printk("current_network.channel:%d\n", ieee->current_network.channel);
- if (ieee->scanning == 0 )
- {
+ if (ieee->scanning == 0) {
printk("error out, scanning = 0\n");
goto out;
}
ieee->set_chan(ieee->dev, ieee->current_network.channel);
- if(channel_map[ieee->current_network.channel] == 1)
+ if (channel_map[ieee->current_network.channel] == 1)
ieee80211_send_probe_requests(ieee);
queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME);
@@ -609,7 +508,7 @@ out:
ieee->scanning = 0;
up(&ieee->scan_sem);
- if(IS_DOT11D_ENABLE(ieee))
+ if (IS_DOT11D_ENABLE(ieee))
DOT11D_ScanComplete(ieee);
return;
}
@@ -618,62 +517,51 @@ static void ieee80211_beacons_start(struct ieee80211_device *ieee)
{
unsigned long flags;
- spin_lock_irqsave(&ieee->beacon_lock,flags);
+ spin_lock_irqsave(&ieee->beacon_lock, flags);
ieee->beacon_txing = 1;
ieee80211_send_beacon(ieee);
- spin_unlock_irqrestore(&ieee->beacon_lock,flags);
+ spin_unlock_irqrestore(&ieee->beacon_lock, flags);
}
static void ieee80211_beacons_stop(struct ieee80211_device *ieee)
{
unsigned long flags;
- spin_lock_irqsave(&ieee->beacon_lock,flags);
+ spin_lock_irqsave(&ieee->beacon_lock, flags);
ieee->beacon_txing = 0;
- del_timer_sync(&ieee->beacon_timer);
-
- spin_unlock_irqrestore(&ieee->beacon_lock,flags);
+ del_timer_sync(&ieee->beacon_timer);
+ spin_unlock_irqrestore(&ieee->beacon_lock, flags);
}
-
void ieee80211_stop_send_beacons(struct ieee80211_device *ieee)
{
- if(ieee->stop_send_beacons)
+ if (ieee->stop_send_beacons)
ieee->stop_send_beacons(ieee->dev);
if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS)
ieee80211_beacons_stop(ieee);
}
-
void ieee80211_start_send_beacons(struct ieee80211_device *ieee)
{
- if(ieee->start_send_beacons)
+ if (ieee->start_send_beacons)
ieee->start_send_beacons(ieee->dev);
- if(ieee->softmac_features & IEEE_SOFTMAC_BEACONS)
+ if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS)
ieee80211_beacons_start(ieee);
}
-
static void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee)
{
-// unsigned long flags;
-
- //ieee->sync_scan_hurryup = 1;
-
down(&ieee->scan_sem);
-// spin_lock_irqsave(&ieee->lock, flags);
- if (ieee->scanning == 1){
+ if (ieee->scanning == 1) {
ieee->scanning = 0;
- //del_timer_sync(&ieee->scan_timer);
cancel_delayed_work(&ieee->softmac_scan_wq);
}
-// spin_unlock_irqrestore(&ieee->lock, flags);
up(&ieee->scan_sem);
}
@@ -688,38 +576,28 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee)
/* called with ieee->lock held */
void ieee80211_rtl_start_scan(struct ieee80211_device *ieee)
{
- if(IS_DOT11D_ENABLE(ieee) )
- {
- if(IS_COUNTRY_IE_VALID(ieee))
- {
+ if (IS_DOT11D_ENABLE(ieee)) {
+ if (IS_COUNTRY_IE_VALID(ieee))
RESET_CIE_WATCHDOG(ieee);
- }
}
- if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){
- if (ieee->scanning == 0)
- {
+
+ if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) {
+ if (ieee->scanning == 0) {
ieee->scanning = 1;
- //ieee80211_softmac_scan(ieee);
- // queue_work(ieee->wq, &ieee->softmac_scan_wq);
- //care this,1203,2007,by lawrence
#if 1
- queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq,0);
+ queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, 0);
#endif
}
}else
ieee->start_scan(ieee->dev);
-
}
/* called with wx_sem held */
void ieee80211_start_scan_syncro(struct ieee80211_device *ieee)
{
- if(IS_DOT11D_ENABLE(ieee) )
- {
- if(IS_COUNTRY_IE_VALID(ieee))
- {
+ if (IS_DOT11D_ENABLE(ieee)) {
+ if (IS_COUNTRY_IE_VALID(ieee))
RESET_CIE_WATCHDOG(ieee);
- }
}
ieee->sync_scan_hurryup = 0;
@@ -727,7 +605,6 @@ void ieee80211_start_scan_syncro(struct ieee80211_device *ieee)
ieee80211_softmac_scan_syncro(ieee);
else
ieee->scan_syncro(ieee->dev);
-
}
inline struct sk_buff *
@@ -739,15 +616,17 @@ ieee80211_authentication_req(struct ieee80211_network *beacon,
skb = dev_alloc_skb(sizeof(struct ieee80211_authentication) + challengelen);
- if (!skb) return NULL;
+ if (!skb)
+ return NULL;
auth = (struct ieee80211_authentication *)
skb_put(skb, sizeof(struct ieee80211_authentication));
auth->header.frame_ctl = IEEE80211_STYPE_AUTH;
- if (challengelen) auth->header.frame_ctl |= IEEE80211_FCTL_WEP;
+ if (challengelen)
+ auth->header.frame_ctl |= IEEE80211_FCTL_WEP;
- auth->header.duration_id = 0x013a; //FIXME
+ auth->header.duration_id = 0x013a; /* FIXME */
memcpy(auth->header.addr1, beacon->bssid, ETH_ALEN);
memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
@@ -761,7 +640,6 @@ ieee80211_authentication_req(struct ieee80211_network *beacon,
auth->status = cpu_to_le16(WLAN_STATUS_SUCCESS);
return skb;
-
}
static struct sk_buff *ieee80211_probe_resp(struct ieee80211_device *ieee,
@@ -772,29 +650,30 @@ static struct sk_buff *ieee80211_probe_resp(struct ieee80211_device *ieee,
struct ieee80211_probe_response *beacon_buf;
struct sk_buff *skb;
int encrypt;
- int atim_len,erp_len;
- struct ieee80211_crypt_data* crypt;
+ int atim_len, erp_len;
+ struct ieee80211_crypt_data *crypt;
char *ssid = ieee->current_network.ssid;
int ssid_len = ieee->current_network.ssid_len;
int rate_len = ieee->current_network.rates_len+2;
int rate_ex_len = ieee->current_network.rates_ex_len;
int wpa_ie_len = ieee->wpa_ie_len;
- if(rate_ex_len > 0) rate_ex_len+=2;
+ if (rate_ex_len > 0)
+ rate_ex_len += 2;
- if(ieee->current_network.capability & WLAN_CAPABILITY_IBSS)
+ if (ieee->current_network.capability & WLAN_CAPABILITY_IBSS)
atim_len = 4;
else
atim_len = 0;
- if(ieee80211_is_54g(&ieee->current_network))
+ if (ieee80211_is_54g(&ieee->current_network))
erp_len = 3;
else
erp_len = 0;
beacon_size = sizeof(struct ieee80211_probe_response)+
ssid_len
- +3 //channel
+ +3 /* channel */
+rate_len
+rate_ex_len
+atim_len
@@ -806,19 +685,19 @@ static struct sk_buff *ieee80211_probe_resp(struct ieee80211_device *ieee,
if (!skb)
return NULL;
- beacon_buf = (struct ieee80211_probe_response*) skb_put(skb, beacon_size);
+ beacon_buf = (struct ieee80211_probe_response *) skb_put(skb, beacon_size);
- memcpy (beacon_buf->header.addr1, dest,ETH_ALEN);
- memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
- memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN);
+ memcpy(beacon_buf->header.addr1, dest, ETH_ALEN);
+ memcpy(beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
+ memcpy(beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN);
- beacon_buf->header.duration_id = 0; //FIXME
+ beacon_buf->header.duration_id = 0; /* FIXME */
beacon_buf->beacon_interval =
cpu_to_le16(ieee->current_network.beacon_interval);
beacon_buf->capability =
cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS);
- if(ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT))
+ if (ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT))
beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT);
crypt = ieee->crypt[ieee->tx_keyidx];
@@ -835,51 +714,52 @@ static struct sk_buff *ieee80211_probe_resp(struct ieee80211_device *ieee,
beacon_buf->info_element.id = MFIE_TYPE_SSID;
beacon_buf->info_element.len = ssid_len;
- tag = (u8*) beacon_buf->info_element.data;
+ tag = (u8 *) beacon_buf->info_element.data;
memcpy(tag, ssid, ssid_len);
tag += ssid_len;
*(tag++) = MFIE_TYPE_RATES;
- *(tag++) = rate_len-2;
- memcpy(tag,ieee->current_network.rates,rate_len-2);
- tag+=rate_len-2;
+ *(tag++) = rate_len - 2;
+ memcpy(tag, ieee->current_network.rates, rate_len-2);
+ tag += rate_len - 2;
*(tag++) = MFIE_TYPE_DS_SET;
*(tag++) = 1;
*(tag++) = ieee->current_network.channel;
- if(atim_len){
+ if (atim_len) {
*(tag++) = MFIE_TYPE_IBSS_SET;
*(tag++) = 2;
- *((u16*)(tag)) = cpu_to_le16(ieee->current_network.atim_window);
- tag+=2;
+ *((u16 *)(tag)) = cpu_to_le16(ieee->current_network.atim_window);
+ tag += 2;
}
- if(erp_len){
+ if (erp_len) {
*(tag++) = MFIE_TYPE_ERP;
*(tag++) = 1;
*(tag++) = 0;
}
- if(rate_ex_len){
+ if (rate_ex_len) {
*(tag++) = MFIE_TYPE_RATES_EX;
*(tag++) = rate_ex_len-2;
- memcpy(tag,ieee->current_network.rates_ex,rate_ex_len-2);
- tag+=rate_ex_len-2;
+ memcpy(tag, ieee->current_network.rates_ex, rate_ex_len-2);
+ tag += rate_ex_len - 2;
}
- if (wpa_ie_len)
- {
- if (ieee->iw_mode == IW_MODE_ADHOC)
- {//as Windows will set pairwise key same as the group key which is not allowed in Linux, so set this for IOT issue. WB 2008.07.07
+ if (wpa_ie_len) {
+ if (ieee->iw_mode == IW_MODE_ADHOC) {
+ /* as Windows will set pairwise key same as the group
+ * key which is not allowed in Linux, so set this for
+ * IOT issue.
+ */
memcpy(&ieee->wpa_ie[14], &ieee->wpa_ie[8], 4);
}
memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len);
}
-
skb->dev = ieee->dev;
return skb;
}
@@ -888,9 +768,9 @@ static struct sk_buff *ieee80211_assoc_resp(struct ieee80211_device *ieee,
u8 *dest)
{
struct sk_buff *skb;
- u8* tag;
+ u8 *tag;
- struct ieee80211_crypt_data* crypt;
+ struct ieee80211_crypt_data *crypt;
struct ieee80211_assoc_response_frame *assoc;
short encrypt;
@@ -903,34 +783,36 @@ static struct sk_buff *ieee80211_assoc_resp(struct ieee80211_device *ieee,
return NULL;
assoc = (struct ieee80211_assoc_response_frame *)
- skb_put(skb,sizeof(struct ieee80211_assoc_response_frame));
+ skb_put(skb, sizeof(struct ieee80211_assoc_response_frame));
assoc->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP);
- memcpy(assoc->header.addr1, dest,ETH_ALEN);
+ memcpy(assoc->header.addr1, dest, ETH_ALEN);
memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN);
memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ?
WLAN_CAPABILITY_BSS : WLAN_CAPABILITY_IBSS);
-
- if(ieee->short_slot)
+ if (ieee->short_slot)
assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT);
if (ieee->host_encrypt)
crypt = ieee->crypt[ieee->tx_keyidx];
- else crypt = NULL;
+ else
+ crypt = NULL;
- encrypt = ( crypt && crypt->ops);
+ encrypt = (crypt && crypt->ops);
if (encrypt)
assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
assoc->status = 0;
assoc->aid = cpu_to_le16(ieee->assoc_id);
- if (ieee->assoc_id == 0x2007) ieee->assoc_id=0;
- else ieee->assoc_id++;
+ if (ieee->assoc_id == 0x2007)
+ ieee->assoc_id = 0;
+ else
+ ieee->assoc_id++;
- tag = (u8*) skb_put(skb, rate_len);
+ tag = (u8 *) skb_put(skb, rate_len);
ieee80211_MFIE_Brate(ieee, &tag);
ieee80211_MFIE_Grate(ieee, &tag);
@@ -962,21 +844,19 @@ static struct sk_buff *ieee80211_auth_resp(struct ieee80211_device *ieee,
memcpy(auth->header.addr1, dest, ETH_ALEN);
auth->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_AUTH);
return skb;
-
-
}
static struct sk_buff *ieee80211_null_func(struct ieee80211_device *ieee, short pwr)
{
struct sk_buff *skb;
- struct ieee80211_hdr_3addr* hdr;
+ struct ieee80211_hdr_3addr *hdr;
skb = dev_alloc_skb(sizeof(struct ieee80211_hdr_3addr));
if (!skb)
return NULL;
- hdr = (struct ieee80211_hdr_3addr*)skb_put(skb,sizeof(struct ieee80211_hdr_3addr));
+ hdr = (struct ieee80211_hdr_3addr *)skb_put(skb, sizeof(struct ieee80211_hdr_3addr));
memcpy(hdr->addr1, ieee->current_network.bssid, ETH_ALEN);
memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN);
@@ -987,83 +867,64 @@ static struct sk_buff *ieee80211_null_func(struct ieee80211_device *ieee, short
(pwr ? IEEE80211_FCTL_PM:0));
return skb;
-
-
}
-
static void ieee80211_resp_to_assoc_rq(struct ieee80211_device *ieee, u8 *dest)
{
struct sk_buff *buf = ieee80211_assoc_resp(ieee, dest);
- if (buf){
+ if (buf) {
softmac_mgmt_xmit(buf, ieee);
- dev_kfree_skb_any(buf);//edit by thomas
+ dev_kfree_skb_any(buf);
}
}
-
static void ieee80211_resp_to_auth(struct ieee80211_device *ieee, int s, u8 *dest)
{
struct sk_buff *buf = ieee80211_auth_resp(ieee, s, dest);
- if (buf){
+ if (buf) {
softmac_mgmt_xmit(buf, ieee);
- dev_kfree_skb_any(buf);//edit by thomas
+ dev_kfree_skb_any(buf);
}
}
-
static void ieee80211_resp_to_probe(struct ieee80211_device *ieee, u8 *dest)
{
-
struct sk_buff *buf = ieee80211_probe_resp(ieee, dest);
if (buf) {
softmac_mgmt_xmit(buf, ieee);
- dev_kfree_skb_any(buf);//edit by thomas
+ dev_kfree_skb_any(buf);
}
}
-
inline struct sk_buff *
ieee80211_association_req(struct ieee80211_network *beacon,
struct ieee80211_device *ieee)
{
struct sk_buff *skb;
- //unsigned long flags;
struct ieee80211_assoc_request_frame *hdr;
u8 *tag;
- //short info_addr = 0;
- //int i;
- //u16 suite_count = 0;
- //u8 suit_select = 0;
unsigned int wpa_len = beacon->wpa_ie_len;
- //struct net_device *dev = ieee->dev;
- //union iwreq_data wrqu;
- //u8 *buff;
- //u8 *p;
#if 1
- // for testing purpose
+ /* for testing purpose */
unsigned int rsn_len = beacon->rsn_ie_len;
-#else
- unsigned int rsn_len = beacon->rsn_ie_len - 4;
#endif
unsigned int rate_len = ieee80211_MFIE_rate_len(ieee);
unsigned int wmm_info_len = beacon->QoS_Enable?9:0;
unsigned int turbo_info_len = beacon->Turbo_Enable?9:0;
u8 encry_proto = ieee->wpax_type_notify & 0xff;
- //u8 pairwise_type = (ieee->wpax_type_notify >> 8) & 0xff;
- //u8 authen_type = (ieee->wpax_type_notify >> 16) & 0xff;
int len = 0;
- //[0] Notify type of encryption: WPA/WPA2
- //[1] pair wise type
- //[2] authen type
- if(ieee->wpax_type_set) {
+ /* [0] Notify type of encryption: WPA/WPA2
+ * [1] pair wise type
+ * [2] authen type
+ */
+ if (ieee->wpax_type_set) {
if (IEEE_PROTO_WPA == encry_proto) {
rsn_len = 0;
} else if (IEEE_PROTO_RSN == encry_proto) {
@@ -1071,8 +932,8 @@ ieee80211_association_req(struct ieee80211_network *beacon,
}
}
len = sizeof(struct ieee80211_assoc_request_frame)+
- + beacon->ssid_len//essid tagged val
- + rate_len//rates tagged val
+ + beacon->ssid_len /* essid tagged val */
+ + rate_len /* rates tagged val */
+ wpa_len
+ rsn_len
+ wmm_info_len
@@ -1086,24 +947,23 @@ ieee80211_association_req(struct ieee80211_network *beacon,
hdr = (struct ieee80211_assoc_request_frame *)
skb_put(skb, sizeof(struct ieee80211_assoc_request_frame));
-
hdr->header.frame_control = IEEE80211_STYPE_ASSOC_REQ;
- hdr->header.duration_id= 37; //FIXME
+ hdr->header.duration_id = 37; /* FIXME */
memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN);
memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
memcpy(hdr->header.addr3, beacon->bssid, ETH_ALEN);
- memcpy(ieee->ap_mac_addr, beacon->bssid, ETH_ALEN);//for HW security, John
+ memcpy(ieee->ap_mac_addr, beacon->bssid, ETH_ALEN); /* for HW security */
hdr->capability = cpu_to_le16(WLAN_CAPABILITY_BSS);
- if (beacon->capability & WLAN_CAPABILITY_PRIVACY )
+ if (beacon->capability & WLAN_CAPABILITY_PRIVACY)
hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
if (beacon->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
- if(ieee->short_slot)
+ if (ieee->short_slot)
hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT);
- hdr->listen_interval = 0xa; //FIXME
+ hdr->listen_interval = 0xa; /* FIXME */
hdr->info_element.id = MFIE_TYPE_SSID;
@@ -1116,27 +976,26 @@ ieee80211_association_req(struct ieee80211_network *beacon,
ieee80211_MFIE_Brate(ieee, &tag);
ieee80211_MFIE_Grate(ieee, &tag);
- //add rsn==0 condition for ap's mix security mode(wpa+wpa2), john2007.8.9
- //choose AES encryption as default algorithm while using mixed mode
+ /* add rsn==0 condition for ap's mix security mode(wpa+wpa2)
+ * choose AES encryption as default algorithm while using mixed mode.
+ */
- tag = skb_put(skb,ieee->wpa_ie_len);
- memcpy(tag,ieee->wpa_ie,ieee->wpa_ie_len);
+ tag = skb_put(skb, ieee->wpa_ie_len);
+ memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len);
- tag = skb_put(skb,wmm_info_len);
- if(wmm_info_len) {
+ tag = skb_put(skb, wmm_info_len);
+ if (wmm_info_len)
ieee80211_WMM_Info(ieee, &tag);
- }
- tag = skb_put(skb,turbo_info_len);
- if(turbo_info_len) {
- ieee80211_TURBO_Info(ieee, &tag);
- }
+
+ tag = skb_put(skb, turbo_info_len);
+ if (turbo_info_len)
+ ieee80211_TURBO_Info(ieee, &tag);
return skb;
}
void ieee80211_associate_abort(struct ieee80211_device *ieee)
{
-
unsigned long flags;
spin_lock_irqsave(&ieee->lock, flags);
@@ -1148,17 +1007,17 @@ void ieee80211_associate_abort(struct ieee80211_device *ieee)
* Here we will check if there are good nets to associate
* with, so we retry or just get back to NO_LINK and scanning
*/
- if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING){
+ if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING) {
IEEE80211_DEBUG_MGMT("Authentication failed\n");
ieee->softmac_stats.no_auth_rs++;
- }else{
+ } else {
IEEE80211_DEBUG_MGMT("Association failed\n");
ieee->softmac_stats.no_ass_rs++;
}
ieee->state = IEEE80211_ASSOCIATING_RETRY;
- queue_delayed_work(ieee->wq, &ieee->associate_retry_wq,IEEE80211_SOFTMAC_ASSOC_RETRY_TIME);
+ queue_delayed_work(ieee->wq, &ieee->associate_retry_wq, IEEE80211_SOFTMAC_ASSOC_RETRY_TIME);
spin_unlock_irqrestore(&ieee->lock, flags);
}
@@ -1168,7 +1027,6 @@ static void ieee80211_associate_abort_cb(unsigned long dev)
ieee80211_associate_abort((struct ieee80211_device *) dev);
}
-
static void ieee80211_associate_step1(struct ieee80211_device *ieee)
{
struct ieee80211_network *beacon = &ieee->current_network;
@@ -1176,26 +1034,24 @@ static void ieee80211_associate_step1(struct ieee80211_device *ieee)
IEEE80211_DEBUG_MGMT("Stopping scan\n");
ieee->softmac_stats.tx_auth_rq++;
- skb=ieee80211_authentication_req(beacon, ieee, 0);
- if (!skb){
-
+ skb = ieee80211_authentication_req(beacon, ieee, 0);
+ if (!skb) {
ieee80211_associate_abort(ieee);
- }
- else{
- ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATING ;
+ } else {
+ ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATING;
IEEE80211_DEBUG_MGMT("Sending authentication request\n");
- //printk("---Sending authentication request\n");
softmac_mgmt_xmit(skb, ieee);
- //BUGON when you try to add_timer twice, using mod_timer may be better, john0709
- if(!timer_pending(&ieee->associate_timer)){
+ /* BUGON when you try to add_timer twice, using mod_timer may
+ * be better.
+ */
+ if (!timer_pending(&ieee->associate_timer)) {
ieee->associate_timer.expires = jiffies + (HZ / 2);
add_timer(&ieee->associate_timer);
}
- //If call dev_kfree_skb_any,a warning will ocur....
- //KERNEL: assertion (!atomic_read(&skb->users)) failed at net/core/dev.c (1708)
- //So ... 1204 by lawrence.
- //printk("\nIn %s,line %d call kfree skb.",__func__,__LINE__);
- //dev_kfree_skb_any(skb);//edit by thomas
+ /* If call dev_kfree_skb_any,a warning will ocur....
+ * KERNEL: assertion (!atomic_read(&skb->users)) failed at
+ * net/core/dev.c (1708)
+ */
}
}
@@ -1205,7 +1061,6 @@ static void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *chal
u8 *c;
struct sk_buff *skb;
struct ieee80211_network *beacon = &ieee->current_network;
-// int hlen = sizeof(struct ieee80211_authentication);
del_timer_sync(&ieee->associate_timer);
ieee->associate_seq++;
ieee->softmac_stats.tx_auth_rq++;
@@ -1213,7 +1068,7 @@ static void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *chal
skb = ieee80211_authentication_req(beacon, ieee, chlen+2);
if (!skb)
ieee80211_associate_abort(ieee);
- else{
+ else {
c = skb_put(skb, chlen+2);
*(c++) = MFIE_TYPE_CHALLENGE;
*(c++) = chlen;
@@ -1221,38 +1076,36 @@ static void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *chal
IEEE80211_DEBUG_MGMT("Sending authentication challenge response\n");
- ieee80211_encrypt_fragment(ieee, skb, sizeof(struct ieee80211_hdr_3addr ));
+ ieee80211_encrypt_fragment(ieee, skb, sizeof(struct ieee80211_hdr_3addr));
softmac_mgmt_xmit(skb, ieee);
- if (!timer_pending(&ieee->associate_timer)){
- //printk("=========>add timer again, to crash\n");
+ if (!timer_pending(&ieee->associate_timer)) {
ieee->associate_timer.expires = jiffies + (HZ / 2);
add_timer(&ieee->associate_timer);
}
- dev_kfree_skb_any(skb);//edit by thomas
+ dev_kfree_skb_any(skb);
}
kfree(challenge);
}
static void ieee80211_associate_step2(struct ieee80211_device *ieee)
{
- struct sk_buff* skb;
+ struct sk_buff *skb;
struct ieee80211_network *beacon = &ieee->current_network;
del_timer_sync(&ieee->associate_timer);
IEEE80211_DEBUG_MGMT("Sending association request\n");
ieee->softmac_stats.tx_ass_rq++;
- skb=ieee80211_association_req(beacon, ieee);
+ skb = ieee80211_association_req(beacon, ieee);
if (!skb)
ieee80211_associate_abort(ieee);
- else{
+ else {
softmac_mgmt_xmit(skb, ieee);
- if (!timer_pending(&ieee->associate_timer)){
+ if (!timer_pending(&ieee->associate_timer)) {
ieee->associate_timer.expires = jiffies + (HZ / 2);
add_timer(&ieee->associate_timer);
}
- //dev_kfree_skb_any(skb);//edit by thomas
}
}
@@ -1261,12 +1114,11 @@ static void ieee80211_associate_complete_wq(struct work_struct *work)
struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_complete_wq);
printk(KERN_INFO "Associated successfully\n");
- if(ieee80211_is_54g(&ieee->current_network) &&
- (ieee->modulation & IEEE80211_OFDM_MODULATION)){
-
+ if (ieee80211_is_54g(&ieee->current_network) &&
+ (ieee->modulation & IEEE80211_OFDM_MODULATION)) {
ieee->rate = 540;
printk(KERN_INFO"Using G rates\n");
- }else{
+ } else {
ieee->rate = 110;
printk(KERN_INFO"Using B rates\n");
}
@@ -1279,12 +1131,8 @@ static void ieee80211_associate_complete_wq(struct work_struct *work)
static void ieee80211_associate_complete(struct ieee80211_device *ieee)
{
- int i;
del_timer_sync(&ieee->associate_timer);
- for(i = 0; i < 6; i++) {
- //ieee->seq_ctrl[i] = 0;
- }
ieee->state = IEEE80211_LINKED;
IEEE80211_DEBUG_MGMT("Successfully associated\n");
@@ -1316,7 +1164,7 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee,
u8 tmp_ssid[IW_ESSID_MAX_SIZE+1];
int tmp_ssid_len = 0;
- short apset,ssidset,ssidbroad,apmatch,ssidmatch;
+ short apset, ssidset, ssidbroad, apmatch, ssidmatch;
/* we are interested in new new only if we are not associated
* and we are not associating / authenticating
@@ -1330,74 +1178,70 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee,
if ((ieee->iw_mode == IW_MODE_ADHOC) && !(net->capability & WLAN_CAPABILITY_IBSS))
return;
-
- if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC){
+ if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC) {
/* if the user specified the AP MAC, we need also the essid
* This could be obtained by beacons or, if the network does not
* broadcast it, it can be put manually.
*/
- apset = ieee->wap_set;//(memcmp(ieee->current_network.bssid, zero,ETH_ALEN)!=0 );
- ssidset = ieee->ssid_set;//ieee->current_network.ssid[0] != '\0';
- ssidbroad = !(net->ssid_len == 0 || net->ssid[0]== '\0');
- apmatch = (memcmp(ieee->current_network.bssid, net->bssid, ETH_ALEN)==0);
+ apset = ieee->wap_set;
+ ssidset = ieee->ssid_set;
+ ssidbroad = !(net->ssid_len == 0 || net->ssid[0] == '\0');
+ apmatch = (memcmp(ieee->current_network.bssid, net->bssid, ETH_ALEN) == 0);
- if(ieee->current_network.ssid_len != net->ssid_len)
+ if (ieee->current_network.ssid_len != net->ssid_len)
ssidmatch = 0;
else
- ssidmatch = (0==strncmp(ieee->current_network.ssid, net->ssid, net->ssid_len));
-
- //printk("cur: %s, %d, net:%s, %d\n", ieee->current_network.ssid, ieee->current_network.ssid_len, net->ssid, net->ssid_len);
- //printk("apset=%d apmatch=%d ssidset=%d ssidbroad=%d ssidmatch=%d\n",apset,apmatch,ssidset,ssidbroad,ssidmatch);
-
- if ( /* if the user set the AP check if match.
- * if the network does not broadcast essid we check the user supplied ANY essid
- * if the network does broadcast and the user does not set essid it is OK
- * if the network does broadcast and the user did set essid chech if essid match
- */
- ( apset && apmatch &&
- ((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) ||
- /* if the ap is not set, check that the user set the bssid
- * and the network does broadcast and that those two bssid matches
- */
- (!apset && ssidset && ssidbroad && ssidmatch)
- ){
-
-
+ ssidmatch = (0 == strncmp(ieee->current_network.ssid, net->ssid, net->ssid_len));
+
+ /* if the user set the AP check if match.
+ * if the network does not broadcast essid we check the user
+ * supplied ANY essid
+ * if the network does broadcast and the user does not set essid
+ * it is OK
+ * if the network does broadcast and the user did set essid
+ * chech if essid match
+ * (apset && apmatch && ((ssidset && ssidbroad && ssidmatch) ||
+ * (ssidbroad && !ssidset) || (!ssidbroad && ssidset))) ||
+ * if the ap is not set, check that the user set the bssid and
+ * the network does broadcast and that those two bssid matches
+ * (!apset && ssidset && ssidbroad && ssidmatch)
+ */
+ if ((apset && apmatch && ((ssidset && ssidbroad && ssidmatch) ||
+ (ssidbroad && !ssidset) || (!ssidbroad && ssidset))) ||
+ (!apset && ssidset && ssidbroad && ssidmatch)) {
/* if the essid is hidden replace it with the
* essid provided by the user.
*/
- if (!ssidbroad){
+ if (!ssidbroad) {
strncpy(tmp_ssid, ieee->current_network.ssid, IW_ESSID_MAX_SIZE);
tmp_ssid_len = ieee->current_network.ssid_len;
}
memcpy(&ieee->current_network, net, sizeof(struct ieee80211_network));
- if (!ssidbroad){
+ if (!ssidbroad) {
strncpy(ieee->current_network.ssid, tmp_ssid, IW_ESSID_MAX_SIZE);
ieee->current_network.ssid_len = tmp_ssid_len;
}
- printk(KERN_INFO"Linking with %s: channel is %d\n",ieee->current_network.ssid,ieee->current_network.channel);
+ printk(KERN_INFO"Linking with %s: channel is %d\n", ieee->current_network.ssid, ieee->current_network.channel);
- if (ieee->iw_mode == IW_MODE_INFRA){
+ if (ieee->iw_mode == IW_MODE_INFRA) {
ieee->state = IEEE80211_ASSOCIATING;
ieee->beinretry = false;
queue_work(ieee->wq, &ieee->associate_procedure_wq);
- }else{
- if(ieee80211_is_54g(&ieee->current_network) &&
- (ieee->modulation & IEEE80211_OFDM_MODULATION)){
+ } else {
+ if (ieee80211_is_54g(&ieee->current_network) &&
+ (ieee->modulation & IEEE80211_OFDM_MODULATION)) {
ieee->rate = 540;
printk(KERN_INFO"Using G rates\n");
- }else{
+ } else {
ieee->rate = 110;
printk(KERN_INFO"Using B rates\n");
}
ieee->state = IEEE80211_LINKED;
ieee->beinretry = false;
}
-
}
}
-
}
void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee)
@@ -1407,60 +1251,52 @@ void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee)
spin_lock_irqsave(&ieee->lock, flags);
list_for_each_entry(target, &ieee->network_list, list) {
-
/* if the state become different that NOLINK means
* we had found what we are searching for
*/
-
if (ieee->state != IEEE80211_NOLINK)
break;
if (ieee->scan_age == 0 || time_after(target->last_scanned + ieee->scan_age, jiffies))
ieee80211_softmac_new_net(ieee, target);
}
-
spin_unlock_irqrestore(&ieee->lock, flags);
-
}
-
static inline u16 auth_parse(struct sk_buff *skb, u8 **challenge, int *chlen)
{
struct ieee80211_authentication *a;
u8 *t;
- if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){
- IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n",skb->len);
+ if (skb->len < (sizeof(struct ieee80211_authentication) - sizeof(struct ieee80211_info_element))) {
+ IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len);
return 0xcafe;
}
*challenge = NULL;
- a = (struct ieee80211_authentication*) skb->data;
- if(skb->len > (sizeof(struct ieee80211_authentication) +3)){
+ a = (struct ieee80211_authentication *) skb->data;
+ if (skb->len > (sizeof(struct ieee80211_authentication) + 3)) {
t = skb->data + sizeof(struct ieee80211_authentication);
- if(*(t++) == MFIE_TYPE_CHALLENGE){
+ if (*(t++) == MFIE_TYPE_CHALLENGE) {
*chlen = *(t++);
*challenge = kmemdup(t, *chlen, GFP_ATOMIC);
if (!*challenge)
return -ENOMEM;
}
}
-
return cpu_to_le16(a->status);
-
}
-
static int auth_rq_parse(struct sk_buff *skb, u8 *dest)
{
struct ieee80211_authentication *a;
- if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){
- IEEE80211_DEBUG_MGMT("invalid len in auth request: %d\n",skb->len);
+ if (skb->len < (sizeof(struct ieee80211_authentication) - sizeof(struct ieee80211_info_element))) {
+ IEEE80211_DEBUG_MGMT("invalid len in auth request: %d\n", skb->len);
return -1;
}
- a = (struct ieee80211_authentication*) skb->data;
+ a = (struct ieee80211_authentication *) skb->data;
- memcpy(dest,a->header.addr2, ETH_ALEN);
+ memcpy(dest, a->header.addr2, ETH_ALEN);
if (le16_to_cpu(a->algorithm) != WLAN_AUTH_OPEN)
return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
@@ -1473,23 +1309,23 @@ static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb,
{
u8 *tag;
u8 *skbend;
- u8 *ssid=NULL;
+ u8 *ssid = NULL;
u8 ssidlen = 0;
struct ieee80211_hdr_3addr *header =
(struct ieee80211_hdr_3addr *) skb->data;
- if (skb->len < sizeof (struct ieee80211_hdr_3addr ))
+ if (skb->len < sizeof(struct ieee80211_hdr_3addr))
return -1; /* corrupted */
- memcpy(src,header->addr2, ETH_ALEN);
+ memcpy(src, header->addr2, ETH_ALEN);
- skbend = (u8*)skb->data + skb->len;
+ skbend = (u8 *)skb->data + skb->len;
- tag = skb->data + sizeof (struct ieee80211_hdr_3addr );
+ tag = skb->data + sizeof(struct ieee80211_hdr_3addr);
- while (tag+1 < skbend){
- if (*tag == 0){
+ while (tag+1 < skbend) {
+ if (*tag == 0) {
ssid = tag+2;
ssidlen = *(tag+1);
break;
@@ -1499,10 +1335,12 @@ static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb,
tag++; /* point to the next tag */
}
- //IEEE80211DMESG("Card MAC address is "MACSTR, MAC2STR(src));
- if (ssidlen == 0) return 1;
+ if (ssidlen == 0)
+ return 1;
+
+ if (!ssid)
+ return 1; /* ssid not found in tagged param */
- if (!ssid) return 1; /* ssid not found in tagged param */
return (!strncmp(ssid, ieee->current_network.ssid, ssidlen));
}
@@ -1514,13 +1352,13 @@ static int assoc_rq_parse(struct sk_buff *skb, u8 *dest)
if (skb->len < (sizeof(struct ieee80211_assoc_request_frame) -
sizeof(struct ieee80211_info_element))) {
- IEEE80211_DEBUG_MGMT("invalid len in auth request:%d \n", skb->len);
+ IEEE80211_DEBUG_MGMT("invalid len in auth request:%d\n", skb->len);
return -1;
}
- a = (struct ieee80211_assoc_request_frame*) skb->data;
+ a = (struct ieee80211_assoc_request_frame *) skb->data;
- memcpy(dest,a->header.addr2,ETH_ALEN);
+ memcpy(dest, a->header.addr2, ETH_ALEN);
return 0;
}
@@ -1528,12 +1366,12 @@ static int assoc_rq_parse(struct sk_buff *skb, u8 *dest)
static inline u16 assoc_parse(struct sk_buff *skb, int *aid)
{
struct ieee80211_assoc_response_frame *a;
- if (skb->len < sizeof(struct ieee80211_assoc_response_frame)){
+ if (skb->len < sizeof(struct ieee80211_assoc_response_frame)) {
IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len);
return 0xcafe;
}
- a = (struct ieee80211_assoc_response_frame*) skb->data;
+ a = (struct ieee80211_assoc_response_frame *) skb->data;
*aid = le16_to_cpu(a->aid) & 0x3fff;
return le16_to_cpu(a->status);
}
@@ -1543,11 +1381,8 @@ static inline void ieee80211_rx_probe_rq(struct ieee80211_device *ieee,
{
u8 dest[ETH_ALEN];
- //IEEE80211DMESG("Rx probe");
ieee->softmac_stats.rx_probe_rq++;
- //DMESG("Dest is "MACSTR, MAC2STR(dest));
- if (probe_rq_parse(ieee, skb, dest)){
- //IEEE80211DMESG("Was for me!");
+ if (probe_rq_parse(ieee, skb, dest)) {
ieee->softmac_stats.tx_probe_rs++;
ieee80211_resp_to_probe(ieee, dest);
}
@@ -1558,115 +1393,92 @@ inline void ieee80211_rx_auth_rq(struct ieee80211_device *ieee,
{
u8 dest[ETH_ALEN];
int status;
- //IEEE80211DMESG("Rx probe");
ieee->softmac_stats.rx_auth_rq++;
status = auth_rq_parse(skb, dest);
- if (status != -1) {
+ if (status != -1)
ieee80211_resp_to_auth(ieee, status, dest);
- }
- //DMESG("Dest is "MACSTR, MAC2STR(dest));
-
}
- inline void
+inline void
ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
{
u8 dest[ETH_ALEN];
- //unsigned long flags;
ieee->softmac_stats.rx_ass_rq++;
- if (assoc_rq_parse(skb,dest) != -1){
+ if (assoc_rq_parse(skb, dest) != -1)
ieee80211_resp_to_assoc_rq(ieee, dest);
- }
+
printk(KERN_INFO"New client associated: %pM\n", dest);
}
-
-
void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr)
{
-
struct sk_buff *buf = ieee80211_null_func(ieee, pwr);
if (buf)
softmac_ps_mgmt_xmit(buf, ieee);
-
}
-
static short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h,
u32 *time_l)
{
- int timeout = 0;
+ int timeout = 0;
u8 dtim;
- /*if(ieee->ps == IEEE80211_PS_DISABLED ||
- ieee->iw_mode != IW_MODE_INFRA ||
- ieee->state != IEEE80211_LINKED)
-
- return 0;
- */
dtim = ieee->current_network.dtim_data;
- //printk("DTIM\n");
- if(!(dtim & IEEE80211_DTIM_VALID))
+ if (!(dtim & IEEE80211_DTIM_VALID))
return 0;
- else
- timeout = ieee->current_network.beacon_interval;
+ else
+ timeout = ieee->current_network.beacon_interval;
- //printk("VALID\n");
ieee->current_network.dtim_data = IEEE80211_DTIM_INVALID;
- if(dtim & ((IEEE80211_DTIM_UCAST | IEEE80211_DTIM_MBCAST)& ieee->ps))
+ if (dtim & ((IEEE80211_DTIM_UCAST | IEEE80211_DTIM_MBCAST) & ieee->ps))
return 2;
- if(!time_after(jiffies, ieee->dev->trans_start + MSECS(timeout)))
+ if (!time_after(jiffies, ieee->dev->trans_start + MSECS(timeout)))
return 0;
- if(!time_after(jiffies, ieee->last_rx_ps_time + MSECS(timeout)))
+ if (!time_after(jiffies, ieee->last_rx_ps_time + MSECS(timeout)))
return 0;
- if((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE ) &&
+ if ((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE) &&
(ieee->mgmt_queue_tail != ieee->mgmt_queue_head))
return 0;
- if(time_l){
+ if (time_l) {
*time_l = ieee->current_network.last_dtim_sta_time[0]
+ MSECS((ieee->current_network.beacon_interval));
- //* ieee->current_network.dtim_period));
- //printk("beacon_interval:%x, dtim_period:%x, totol to Msecs:%x, HZ:%x\n", ieee->current_network.beacon_interval, ieee->current_network.dtim_period, MSECS(((ieee->current_network.beacon_interval * ieee->current_network.dtim_period))), HZ);
}
- if(time_h){
+ if (time_h) {
*time_h = ieee->current_network.last_dtim_sta_time[1];
- if(time_l && *time_l < ieee->current_network.last_dtim_sta_time[0])
+ if (time_l && *time_l < ieee->current_network.last_dtim_sta_time[0])
*time_h += 1;
}
return 1;
-
-
}
static inline void ieee80211_sta_ps(struct ieee80211_device *ieee)
{
- u32 th,tl;
+ u32 th, tl;
short sleep;
- unsigned long flags,flags2;
+ unsigned long flags, flags2;
spin_lock_irqsave(&ieee->lock, flags);
- if((ieee->ps == IEEE80211_PS_DISABLED ||
-
+ if ((ieee->ps == IEEE80211_PS_DISABLED ||
ieee->iw_mode != IW_MODE_INFRA ||
- ieee->state != IEEE80211_LINKED)){
+ ieee->state != IEEE80211_LINKED)) {
- //#warning CHECK_LOCK_HERE
+ /* #warning CHECK_LOCK_HERE */
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
ieee80211_sta_wakeup(ieee, 1);
@@ -1674,71 +1486,57 @@ static inline void ieee80211_sta_ps(struct ieee80211_device *ieee)
spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
}
- sleep = ieee80211_sta_ps_sleep(ieee,&th, &tl);
-// printk("===>%s,%d[2 wake, 1 sleep, 0 do nothing], ieee->sta_sleep = %d\n",__func__, sleep,ieee->sta_sleep);
+ sleep = ieee80211_sta_ps_sleep(ieee, &th, &tl);
/* 2 wake, 1 sleep, 0 do nothing */
- if(sleep == 0)
+ if (sleep == 0)
goto out;
- if(sleep == 1){
-
- if(ieee->sta_sleep == 1)
- ieee->enter_sleep_state(ieee->dev,th,tl);
+ if (sleep == 1) {
+ if (ieee->sta_sleep == 1)
+ ieee->enter_sleep_state(ieee->dev, th, tl);
- else if(ieee->sta_sleep == 0){
- // printk("send null 1\n");
+ else if (ieee->sta_sleep == 0) {
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
-
- if(ieee->ps_is_queue_empty(ieee->dev)){
-
-
+ if (ieee->ps_is_queue_empty(ieee->dev)) {
ieee->sta_sleep = 2;
ieee->ps_request_tx_ack(ieee->dev);
- ieee80211_sta_ps_send_null_frame(ieee,1);
+ ieee80211_sta_ps_send_null_frame(ieee, 1);
ieee->ps_th = th;
ieee->ps_tl = tl;
}
spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
-
}
-
-
- }else if(sleep == 2){
-//#warning CHECK_LOCK_HERE
+ } else if (sleep == 2) {
+ /* #warning CHECK_LOCK_HERE */
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
- // printk("send wakeup packet\n");
- ieee80211_sta_wakeup(ieee,1);
+ ieee80211_sta_wakeup(ieee, 1);
spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
}
-
out:
spin_unlock_irqrestore(&ieee->lock, flags);
-
}
void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl)
{
- if(ieee->sta_sleep == 0){
- if(nl){
- // printk("Warning: driver is probably failing to report TX ps error\n");
+ if (ieee->sta_sleep == 0) {
+ if (nl) {
ieee->ps_request_tx_ack(ieee->dev);
ieee80211_sta_ps_send_null_frame(ieee, 0);
}
return;
-
}
- if(ieee->sta_sleep == 1)
+ if (ieee->sta_sleep == 1)
ieee->sta_wake_up(ieee->dev);
ieee->sta_sleep = 0;
- if(nl){
+ if (nl) {
ieee->ps_request_tx_ack(ieee->dev);
ieee80211_sta_ps_send_null_frame(ieee, 0);
}
@@ -1746,25 +1544,20 @@ void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl)
void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success)
{
- unsigned long flags,flags2;
+ unsigned long flags, flags2;
spin_lock_irqsave(&ieee->lock, flags);
- if(ieee->sta_sleep == 2){
+ if (ieee->sta_sleep == 2) {
/* Null frame with PS bit set */
- if(success){
-
- // printk("==================> %s::enter sleep state\n",__func__);
+ if (success) {
ieee->sta_sleep = 1;
- ieee->enter_sleep_state(ieee->dev,ieee->ps_th,ieee->ps_tl);
+ ieee->enter_sleep_state(ieee->dev, ieee->ps_th, ieee->ps_tl);
}
/* if the card report not success we can't be sure the AP
* has not RXed so we can't assume the AP believe us awake
*/
- }
- /* 21112005 - tx again null without PS bit if lost */
- else {
-
- if((ieee->sta_sleep == 0) && !success){
+ } else {
+ if ((ieee->sta_sleep == 0) && !success) {
spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
ieee80211_sta_ps_send_null_frame(ieee, 0);
spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
@@ -1780,16 +1573,16 @@ inline int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee,
{
struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *) skb->data;
u16 errcode;
- u8* challenge=NULL;
- int chlen=0;
- int aid=0;
+ u8 *challenge = NULL;
+ int chlen = 0;
+ int aid = 0;
struct ieee80211_assoc_response_frame *assoc_resp;
struct ieee80211_info_element *info_element;
- if(!ieee->proto_started)
+ if (!ieee->proto_started)
return 0;
- if(ieee->sta_sleep || (ieee->ps != IEEE80211_PS_DISABLED &&
+ if (ieee->sta_sleep || (ieee->ps != IEEE80211_PS_DISABLED &&
ieee->iw_mode == IW_MODE_INFRA &&
ieee->state == IEEE80211_LINKED))
@@ -1800,30 +1593,27 @@ inline int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee,
ieee->last_rx_ps_time = jiffies;
switch (WLAN_FC_GET_STYPE(header->frame_control)) {
-
case IEEE80211_STYPE_ASSOC_RESP:
case IEEE80211_STYPE_REASSOC_RESP:
-
IEEE80211_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n",
WLAN_FC_GET_STYPE(header->frame_ctl));
if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATED &&
- ieee->iw_mode == IW_MODE_INFRA){
- if (0 == (errcode=assoc_parse(skb, &aid))){
+ ieee->iw_mode == IW_MODE_INFRA) {
+ errcode = assoc_parse(skb, &aid);
+ if (0 == errcode) {
u16 left;
- ieee->state=IEEE80211_LINKED;
+ ieee->state = IEEE80211_LINKED;
ieee->assoc_id = aid;
ieee->softmac_stats.rx_ass_ok++;
-
- //printk(KERN_WARNING "nic_type = %s", (rx_stats->nic_type == 1)?"rtl8187":"rtl8187B");
- if(1 == rx_stats->nic_type) //card type is 8187
- {
+ /* card type is 8187 */
+ if (1 == rx_stats->nic_type)
goto associate_complete;
- }
- assoc_resp = (struct ieee80211_assoc_response_frame*)skb->data;
- info_element = &assoc_resp->info_element;
- left = skb->len - ((void*)info_element - (void*)assoc_resp);
+
+ assoc_resp = (struct ieee80211_assoc_response_frame *)skb->data;
+ info_element = &assoc_resp->info_element;
+ left = skb->len - ((void *)info_element - (void *)assoc_resp);
while (left >= sizeof(struct ieee80211_info_element_hdr)) {
if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) {
@@ -1832,32 +1622,33 @@ inline int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee,
}
switch (info_element->id) {
case MFIE_TYPE_GENERIC:
- IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", info_element->len);
+ IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", info_element->len);
if (info_element->len >= 8 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x50 &&
info_element->data[2] == 0xf2 &&
info_element->data[3] == 0x02 &&
info_element->data[4] == 0x01) {
- // Not care about version at present.
- //WMM Parameter Element
- memcpy(ieee->current_network.wmm_param,(u8*)(info_element->data\
- + 8),(info_element->len - 8));
-
- if (((ieee->current_network.wmm_info^info_element->data[6])& \
- 0x0f)||(!ieee->init_wmmparam_flag)) {
- // refresh parameter element for current network
- // update the register parameter for hardware
- ieee->init_wmmparam_flag = 1;
- queue_work(ieee->wq, &ieee->wmm_param_update_wq);
-
- }
- //update info_element for current network
- ieee->current_network.wmm_info = info_element->data[6];
+ /* Not care about version at present.
+ * WMM Parameter Element.
+ */
+ memcpy(ieee->current_network.wmm_param, (u8 *)(info_element->data\
+ + 8), (info_element->len - 8));
+
+ if (((ieee->current_network.wmm_info^info_element->data[6])& \
+ 0x0f) || (!ieee->init_wmmparam_flag)) {
+ /* refresh parameter element for current network
+ * update the register parameter for hardware.
+ */
+ ieee->init_wmmparam_flag = 1;
+ queue_work(ieee->wq, &ieee->wmm_param_update_wq);
+ }
+ /* update info_element for current network */
+ ieee->current_network.wmm_info = info_element->data[6];
}
break;
default:
- //nothing to do at present!!!
+ /* nothing to do at present!!! */
break;
}
@@ -1866,14 +1657,14 @@ inline int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee,
info_element = (struct ieee80211_info_element *)
&info_element->data[info_element->len];
}
- if(!ieee->init_wmmparam_flag) //legacy AP, reset the AC_xx_param register
- {
- queue_work(ieee->wq,&ieee->wmm_param_update_wq);
- ieee->init_wmmparam_flag = 1;//indicate AC_xx_param upated since last associate
+ /* legacy AP, reset the AC_xx_param register */
+ if (!ieee->init_wmmparam_flag) {
+ queue_work(ieee->wq, &ieee->wmm_param_update_wq);
+ ieee->init_wmmparam_flag = 1; /* indicate AC_xx_param upated since last associate */
}
associate_complete:
ieee80211_associate_complete(ieee);
- }else{
+ } else {
ieee->softmac_stats.rx_ass_err++;
IEEE80211_DEBUG_MGMT(
"Association response status code 0x%x\n",
@@ -1882,47 +1673,41 @@ associate_complete:
}
}
break;
-
case IEEE80211_STYPE_ASSOC_REQ:
case IEEE80211_STYPE_REASSOC_REQ:
-
if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
ieee->iw_mode == IW_MODE_MASTER)
ieee80211_rx_assoc_rq(ieee, skb);
break;
-
case IEEE80211_STYPE_AUTH:
-
- if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE){
+ if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) {
if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING &&
ieee->iw_mode == IW_MODE_INFRA){
-
IEEE80211_DEBUG_MGMT("Received authentication response");
- if (0 == (errcode=auth_parse(skb, &challenge, &chlen))){
- if(ieee->open_wep || !challenge){
+ errcode = auth_parse(skb, &challenge, &chlen);
+ if (0 == errcode) {
+ if (ieee->open_wep || !challenge) {
ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATED;
ieee->softmac_stats.rx_auth_rs_ok++;
ieee80211_associate_step2(ieee);
- }else{
+ } else {
ieee80211_rtl_auth_challenge(ieee, challenge, chlen);
}
- }else{
+ } else {
ieee->softmac_stats.rx_auth_rs_err++;
- IEEE80211_DEBUG_MGMT("Authentication response status code 0x%x",errcode);
+ IEEE80211_DEBUG_MGMT("Authentication response status code 0x%x", errcode);
ieee80211_associate_abort(ieee);
}
- }else if (ieee->iw_mode == IW_MODE_MASTER){
+ } else if (ieee->iw_mode == IW_MODE_MASTER) {
ieee80211_rx_auth_rq(ieee, skb);
}
}
break;
-
case IEEE80211_STYPE_PROBE_REQ:
-
if ((ieee->softmac_features & IEEE_SOFTMAC_PROBERS) &&
((ieee->iw_mode == IW_MODE_ADHOC ||
ieee->iw_mode == IW_MODE_MASTER) &&
@@ -1930,36 +1715,28 @@ associate_complete:
ieee80211_rx_probe_rq(ieee, skb);
break;
-
case IEEE80211_STYPE_DISASSOC:
case IEEE80211_STYPE_DEAUTH:
/* FIXME for now repeat all the association procedure
- * both for disassociation and deauthentication
- */
+ * both for disassociation and deauthentication
+ */
if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
(ieee->state == IEEE80211_LINKED) &&
(ieee->iw_mode == IW_MODE_INFRA) &&
- (!memcmp(header->addr2,ieee->current_network.bssid,ETH_ALEN))){
+ (!memcmp(header->addr2, ieee->current_network.bssid, ETH_ALEN))) {
ieee->state = IEEE80211_ASSOCIATING;
ieee->softmac_stats.reassoc++;
- //notify_wx_assoc_event(ieee); //YJ,del,080828, do not notify os here
queue_work(ieee->wq, &ieee->associate_procedure_wq);
}
-
break;
-
default:
return -1;
break;
}
-
- //dev_kfree_skb_any(skb);
return 0;
}
-
-
/* following are for a simpler TX queue management.
* Instead of using netif_[stop/wake]_queue the driver
* will uses these two function (plus a reset one), that
@@ -1982,27 +1759,23 @@ associate_complete:
void ieee80211_softmac_xmit(struct ieee80211_txb *txb,
struct ieee80211_device *ieee)
{
-
-
unsigned long flags;
int i;
- spin_lock_irqsave(&ieee->lock,flags);
+ spin_lock_irqsave(&ieee->lock, flags);
/* called with 2nd parm 0, no tx mgmt lock required */
- ieee80211_sta_wakeup(ieee,0);
-
- for(i = 0; i < txb->nr_frags; i++) {
+ ieee80211_sta_wakeup(ieee, 0);
- if (ieee->queue_stop){
+ for (i = 0; i < txb->nr_frags; i++) {
+ if (ieee->queue_stop) {
ieee->tx_pending.txb = txb;
ieee->tx_pending.frag = i;
goto exit;
- }else{
+ } else {
ieee->softmac_data_hard_start_xmit(
txb->fragments[i],
- ieee->dev,ieee->rate);
- //(i+1)<txb->nr_frags);
+ ieee->dev, ieee->rate);
ieee->stats.tx_packets++;
ieee->stats.tx_bytes += txb->fragments[i]->len;
ieee->dev->trans_start = jiffies;
@@ -2012,66 +1785,59 @@ void ieee80211_softmac_xmit(struct ieee80211_txb *txb,
ieee80211_txb_free(txb);
exit:
- spin_unlock_irqrestore(&ieee->lock,flags);
-
+ spin_unlock_irqrestore(&ieee->lock, flags);
}
/* called with ieee->lock acquired */
static void ieee80211_resume_tx(struct ieee80211_device *ieee)
{
int i;
- for(i = ieee->tx_pending.frag; i < ieee->tx_pending.txb->nr_frags; i++) {
+ for (i = ieee->tx_pending.frag; i < ieee->tx_pending.txb->nr_frags; i++) {
- if (ieee->queue_stop){
+ if (ieee->queue_stop) {
ieee->tx_pending.frag = i;
return;
- }else{
-
+ } else {
ieee->softmac_data_hard_start_xmit(
ieee->tx_pending.txb->fragments[i],
- ieee->dev,ieee->rate);
- //(i+1)<ieee->tx_pending.txb->nr_frags);
+ ieee->dev, ieee->rate);
ieee->stats.tx_packets++;
ieee->dev->trans_start = jiffies;
}
}
-
ieee80211_txb_free(ieee->tx_pending.txb);
ieee->tx_pending.txb = NULL;
}
-
void ieee80211_reset_queue(struct ieee80211_device *ieee)
{
unsigned long flags;
- spin_lock_irqsave(&ieee->lock,flags);
+ spin_lock_irqsave(&ieee->lock, flags);
init_mgmt_queue(ieee);
- if (ieee->tx_pending.txb){
+ if (ieee->tx_pending.txb) {
ieee80211_txb_free(ieee->tx_pending.txb);
ieee->tx_pending.txb = NULL;
}
ieee->queue_stop = 0;
- spin_unlock_irqrestore(&ieee->lock,flags);
-
+ spin_unlock_irqrestore(&ieee->lock, flags);
}
void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
{
-
unsigned long flags;
struct sk_buff *skb;
struct ieee80211_hdr_3addr *header;
- spin_lock_irqsave(&ieee->lock,flags);
- if (! ieee->queue_stop) goto exit;
+ spin_lock_irqsave(&ieee->lock, flags);
+ if (!ieee->queue_stop)
+ goto exit;
ieee->queue_stop = 0;
- if(ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE){
- while (!ieee->queue_stop && (skb = dequeue_mgmt(ieee))){
-
+ if (ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE) {
+ while (!ieee->queue_stop && (skb = dequeue_mgmt(ieee))) {
header = (struct ieee80211_hdr_3addr *) skb->data;
header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
@@ -2081,42 +1847,32 @@ void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
else
ieee->seq_ctrl[0]++;
- //printk(KERN_ALERT "ieee80211_wake_queue \n");
- ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate);
- dev_kfree_skb_any(skb);//edit by thomas
+ ieee->softmac_data_hard_start_xmit(skb, ieee->dev, ieee->basic_rate);
+ dev_kfree_skb_any(skb);
}
}
if (!ieee->queue_stop && ieee->tx_pending.txb)
ieee80211_resume_tx(ieee);
- if (!ieee->queue_stop && netif_queue_stopped(ieee->dev)){
+ if (!ieee->queue_stop && netif_queue_stopped(ieee->dev)) {
ieee->softmac_stats.swtxawake++;
netif_wake_queue(ieee->dev);
}
-
-exit :
- spin_unlock_irqrestore(&ieee->lock,flags);
+exit:
+ spin_unlock_irqrestore(&ieee->lock, flags);
}
-
void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee)
{
- //unsigned long flags;
- //spin_lock_irqsave(&ieee->lock,flags);
-
- if (! netif_queue_stopped(ieee->dev)){
+ if (!netif_queue_stopped(ieee->dev)) {
netif_stop_queue(ieee->dev);
ieee->softmac_stats.swtxstop++;
}
ieee->queue_stop = 1;
- //spin_unlock_irqrestore(&ieee->lock,flags);
-
}
-
inline void ieee80211_randomize_cell(struct ieee80211_device *ieee)
{
-
random_ether_addr(ieee->current_network.bssid);
}
@@ -2125,7 +1881,7 @@ void ieee80211_start_master_bss(struct ieee80211_device *ieee)
{
ieee->assoc_id = 1;
- if (ieee->current_network.ssid_len == 0){
+ if (ieee->current_network.ssid_len == 0) {
strncpy(ieee->current_network.ssid,
IEEE80211_DEFAULT_TX_ESSID,
IW_ESSID_MAX_SIZE);
@@ -2149,7 +1905,7 @@ void ieee80211_start_master_bss(struct ieee80211_device *ieee)
static void ieee80211_start_monitor_mode(struct ieee80211_device *ieee)
{
- if(ieee->raw_tx){
+ if (ieee->raw_tx) {
if (ieee->data_hard_resume)
ieee->data_hard_resume(ieee->dev);
@@ -2173,9 +1929,8 @@ static void ieee80211_start_ibss_wq(struct work_struct *work)
down(&ieee->wx_sem);
-
- if (ieee->current_network.ssid_len == 0){
- strcpy(ieee->current_network.ssid,IEEE80211_DEFAULT_TX_ESSID);
+ if (ieee->current_network.ssid_len == 0) {
+ strcpy(ieee->current_network.ssid, IEEE80211_DEFAULT_TX_ESSID);
ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID);
ieee->ssid_set = 1;
}
@@ -2183,7 +1938,7 @@ static void ieee80211_start_ibss_wq(struct work_struct *work)
/* check if we have this cell in our network list */
ieee80211_softmac_check_all_nets(ieee);
- if(ieee->state == IEEE80211_NOLINK)
+ if (ieee->state == IEEE80211_NOLINK)
ieee->current_network.channel = 10;
/* if not then the state is not linked. Maybe the user switched to
* ad-hoc mode just after being in monitor mode, or just after
@@ -2203,13 +1958,12 @@ static void ieee80211_start_ibss_wq(struct work_struct *work)
ieee80211_start_scan_syncro(ieee);
/* the network definitively is not here.. create a new cell */
- if (ieee->state == IEEE80211_NOLINK){
+ if (ieee->state == IEEE80211_NOLINK) {
printk("creating new IBSS cell\n");
- if(!ieee->wap_set)
+ if (!ieee->wap_set)
ieee80211_randomize_cell(ieee);
- if(ieee->modulation & IEEE80211_CCK_MODULATION){
-
+ if (ieee->modulation & IEEE80211_CCK_MODULATION) {
ieee->current_network.rates_len = 4;
ieee->current_network.rates[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
@@ -2217,10 +1971,10 @@ static void ieee80211_start_ibss_wq(struct work_struct *work)
ieee->current_network.rates[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
ieee->current_network.rates[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
- }else
+ } else
ieee->current_network.rates_len = 0;
- if(ieee->modulation & IEEE80211_OFDM_MODULATION){
+ if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
ieee->current_network.rates_ex_len = 8;
ieee->current_network.rates_ex[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB;
@@ -2233,19 +1987,18 @@ static void ieee80211_start_ibss_wq(struct work_struct *work)
ieee->current_network.rates_ex[7] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB;
ieee->rate = 540;
- }else{
+ } else {
ieee->current_network.rates_ex_len = 0;
ieee->rate = 110;
}
- // By default, WMM function will be disabled in IBSS mode
+ /* By default, WMM function will be disabled in IBSS mode */
ieee->current_network.QoS_Enable = 0;
ieee->current_network.atim_window = 0;
ieee->current_network.capability = WLAN_CAPABILITY_IBSS;
- if(ieee->short_slot)
+ if (ieee->short_slot)
ieee->current_network.capability |= WLAN_CAPABILITY_SHORT_SLOT;
-
}
ieee->state = IEEE80211_LINKED;
@@ -2264,6 +2017,7 @@ static void ieee80211_start_ibss_wq(struct work_struct *work)
up(&ieee->wx_sem);
}
+
inline void ieee80211_start_ibss(struct ieee80211_device *ieee)
{
queue_delayed_work(ieee->wq, &ieee->start_ibss_wq, 100);
@@ -2273,19 +2027,15 @@ inline void ieee80211_start_ibss(struct ieee80211_device *ieee)
void ieee80211_start_bss(struct ieee80211_device *ieee)
{
unsigned long flags;
- //
- // Ref: 802.11d 11.1.3.3
- // STA shall not start a BSS unless properly formed Beacon frame including a Country IE.
- //
- if(IS_DOT11D_ENABLE(ieee) && !IS_COUNTRY_IE_VALID(ieee))
- {
- if(! ieee->bGlobalDomain)
- {
+ /* Ref: 802.11d 11.1.3.3
+ * STA shall not start a BSS unless properly formed Beacon frame
+ * including a Country IE.
+ */
+ if (IS_DOT11D_ENABLE(ieee) && !IS_COUNTRY_IE_VALID(ieee)) {
+ if (!ieee->bGlobalDomain)
return;
- }
}
- /* check if we have already found the net we
- * are interested in (if any).
+ /* check if we have already found the net we are interested in (if any).
* if not (we are disassociated and we are not
* in associating / authenticating phase) start the background scanning.
*/
@@ -2300,14 +2050,10 @@ void ieee80211_start_bss(struct ieee80211_device *ieee)
*/
spin_lock_irqsave(&ieee->lock, flags);
-//#ifdef ENABLE_IPS
-// printk("start bss ENABLE_IPS\n");
-//#else
- if (ieee->state == IEEE80211_NOLINK){
+ if (ieee->state == IEEE80211_NOLINK) {
ieee->actscanning = true;
ieee80211_rtl_start_scan(ieee);
}
-//#endif
spin_unlock_irqrestore(&ieee->lock, flags);
}
@@ -2322,7 +2068,7 @@ void ieee80211_disassociate(struct ieee80211_device *ieee)
if (ieee->data_hard_stop)
ieee->data_hard_stop(ieee->dev);
- if(IS_DOT11D_ENABLE(ieee))
+ if (IS_DOT11D_ENABLE(ieee))
Dot11d_Reset(ieee);
ieee->link_change(ieee->dev);
@@ -2337,9 +2083,9 @@ static void ieee80211_associate_retry_wq(struct work_struct *work)
struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq);
unsigned long flags;
down(&ieee->wx_sem);
- if(!ieee->proto_started)
+ if (!ieee->proto_started)
goto exit;
- if(ieee->state != IEEE80211_ASSOCIATING_RETRY)
+ if (ieee->state != IEEE80211_ASSOCIATING_RETRY)
goto exit;
/* until we do not set the state to IEEE80211_NOLINK
* there are no possibility to have someone else trying
@@ -2360,17 +2106,13 @@ static void ieee80211_associate_retry_wq(struct work_struct *work)
spin_lock_irqsave(&ieee->lock, flags);
- if(ieee->state == IEEE80211_NOLINK){
+ if (ieee->state == IEEE80211_NOLINK) {
ieee->beinretry = false;
ieee->actscanning = true;
ieee80211_rtl_start_scan(ieee);
}
- //YJ,add,080828, notify os here
- if(ieee->state == IEEE80211_NOLINK)
- {
+ if (ieee->state == IEEE80211_NOLINK)
notify_wx_assoc_event(ieee);
- }
- //YJ,add,080828,end
spin_unlock_irqrestore(&ieee->lock, flags);
exit:
@@ -2379,7 +2121,7 @@ exit:
struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee)
{
- u8 broadcast_addr[] = {0xff,0xff,0xff,0xff,0xff,0xff};
+ u8 broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
struct sk_buff *skb = NULL;
struct ieee80211_probe_response *b;
@@ -2392,7 +2134,6 @@ struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee)
b->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_BEACON);
return skb;
-
}
struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee)
@@ -2401,7 +2142,7 @@ struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee)
struct ieee80211_probe_response *b;
skb = ieee80211_get_beacon_(ieee);
- if(!skb)
+ if (!skb)
return NULL;
b = (struct ieee80211_probe_response *) skb->data;
@@ -2423,7 +2164,6 @@ void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee)
up(&ieee->wx_sem);
}
-
void ieee80211_stop_protocol(struct ieee80211_device *ieee)
{
if (!ieee->proto_started)
@@ -2432,9 +2172,9 @@ void ieee80211_stop_protocol(struct ieee80211_device *ieee)
ieee->proto_started = 0;
ieee80211_stop_send_beacons(ieee);
- if((ieee->iw_mode == IW_MODE_INFRA)&&(ieee->state == IEEE80211_LINKED)) {
- SendDisassociation(ieee,NULL,WLAN_REASON_DISASSOC_STA_HAS_LEFT);
- }
+ if ((ieee->iw_mode == IW_MODE_INFRA) && (ieee->state == IEEE80211_LINKED))
+ SendDisassociation(ieee, NULL, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
+
del_timer_sync(&ieee->associate_timer);
cancel_delayed_work(&ieee->associate_retry_wq);
cancel_delayed_work(&ieee->start_ibss_wq);
@@ -2454,36 +2194,35 @@ void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee)
void ieee80211_start_protocol(struct ieee80211_device *ieee)
{
short ch = 0;
- int i = 0;
+ int i = 0;
if (ieee->proto_started)
return;
ieee->proto_started = 1;
- if (ieee->current_network.channel == 0){
- do{
+ if (ieee->current_network.channel == 0) {
+ do {
ch++;
if (ch > MAX_CHANNEL_NUMBER)
return; /* no channel found */
- }while(!GET_DOT11D_INFO(ieee)->channel_map[ch]);
+ } while (!GET_DOT11D_INFO(ieee)->channel_map[ch]);
ieee->current_network.channel = ch;
}
if (ieee->current_network.beacon_interval == 0)
ieee->current_network.beacon_interval = 100;
- ieee->set_chan(ieee->dev,ieee->current_network.channel);
+ ieee->set_chan(ieee->dev, ieee->current_network.channel);
- for(i = 0; i < 17; i++) {
- ieee->last_rxseq_num[i] = -1;
- ieee->last_rxfrag_num[i] = -1;
- ieee->last_packet_time[i] = 0;
+ for (i = 0; i < 17; i++) {
+ ieee->last_rxseq_num[i] = -1;
+ ieee->last_rxfrag_num[i] = -1;
+ ieee->last_packet_time[i] = 0;
}
- ieee->init_wmmparam_flag = 0;//reinitialize AC_xx_PARAM registers.
-
+ ieee->init_wmmparam_flag = 0; /* reinitialize AC_xx_PARAM registers. */
/* if the user set the MAC of the ad-hoc cell and then
* switch to managed mode, shall we make sure that association
@@ -2493,7 +2232,7 @@ void ieee80211_start_protocol(struct ieee80211_device *ieee)
switch (ieee->iw_mode) {
case IW_MODE_AUTO:
ieee->iw_mode = IW_MODE_INFRA;
- //not set break here intentionly
+ /* not set break here intentionly */
case IW_MODE_INFRA:
ieee80211_start_bss(ieee);
break;
@@ -2517,7 +2256,6 @@ void ieee80211_start_protocol(struct ieee80211_device *ieee)
}
}
-
#define DRV_NAME "Ieee80211"
void ieee80211_softmac_init(struct ieee80211_device *ieee)
{
@@ -2526,36 +2264,29 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee)
ieee->state = IEEE80211_NOLINK;
ieee->sync_scan_hurryup = 0;
- for(i = 0; i < 5; i++) {
- ieee->seq_ctrl[i] = 0;
- }
+ for (i = 0; i < 5; i++)
+ ieee->seq_ctrl[i] = 0;
ieee->assoc_id = 0;
ieee->queue_stop = 0;
ieee->scanning = 0;
- ieee->softmac_features = 0; //so IEEE2100-like driver are happy
+ ieee->softmac_features = 0; /* so IEEE2100-like driver are happy */
ieee->wap_set = 0;
ieee->ssid_set = 0;
ieee->proto_started = 0;
ieee->basic_rate = IEEE80211_DEFAULT_BASIC_RATE;
ieee->rate = 3;
-//#ifdef ENABLE_LPS
ieee->ps = IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST;
-//#else
-// ieee->ps = IEEE80211_PS_DISABLED;
-//#endif
ieee->sta_sleep = 0;
-//by amy
ieee->bInactivePs = false;
ieee->actscanning = false;
ieee->ListenInterval = 2;
- ieee->NumRxDataInPeriod = 0; //YJ,add,080828
- ieee->NumRxBcnInPeriod = 0; //YJ,add,080828
- ieee->NumRxOkTotal = 0;//+by amy 080312
- ieee->NumRxUnicast = 0;//YJ,add,080828,for keep alive
+ ieee->NumRxDataInPeriod = 0;
+ ieee->NumRxBcnInPeriod = 0;
+ ieee->NumRxOkTotal = 0;
+ ieee->NumRxUnicast = 0; /* for keep alive */
ieee->beinretry = false;
ieee->bHwRadioOff = false;
-//by amy
init_mgmt_queue(ieee);
@@ -2571,13 +2302,12 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee)
ieee->wq = create_workqueue(DRV_NAME);
- INIT_DELAYED_WORK(&ieee->start_ibss_wq,(void*) ieee80211_start_ibss_wq);
- INIT_WORK(&ieee->associate_complete_wq,(void*) ieee80211_associate_complete_wq);
- INIT_WORK(&ieee->associate_procedure_wq,(void*) ieee80211_associate_procedure_wq);
- INIT_DELAYED_WORK(&ieee->softmac_scan_wq,(void*) ieee80211_softmac_scan_wq);
- INIT_DELAYED_WORK(&ieee->associate_retry_wq,(void*) ieee80211_associate_retry_wq);
- INIT_WORK(&ieee->wx_sync_scan_wq,(void*) ieee80211_wx_sync_scan_wq);
-// INIT_WORK(&ieee->watch_dog_wq,(void*) ieee80211_watch_dog_wq);
+ INIT_DELAYED_WORK(&ieee->start_ibss_wq, (void *) ieee80211_start_ibss_wq);
+ INIT_WORK(&ieee->associate_complete_wq, (void *) ieee80211_associate_complete_wq);
+ INIT_WORK(&ieee->associate_procedure_wq, (void *) ieee80211_associate_procedure_wq);
+ INIT_DELAYED_WORK(&ieee->softmac_scan_wq, (void *) ieee80211_softmac_scan_wq);
+ INIT_DELAYED_WORK(&ieee->associate_retry_wq, (void *) ieee80211_associate_retry_wq);
+ INIT_WORK(&ieee->wx_sync_scan_wq, (void *) ieee80211_wx_sync_scan_wq);
sema_init(&ieee->wx_sem, 1);
sema_init(&ieee->scan_sem, 1);
@@ -2598,8 +2328,7 @@ void ieee80211_softmac_free(struct ieee80211_device *ieee)
del_timer_sync(&ieee->associate_timer);
cancel_delayed_work(&ieee->associate_retry_wq);
-
- //add for RF power on power of by lizhaoming 080512
+ /* add for RF power on power of */
cancel_delayed_work(&ieee->GPIOChangeRFWorkItem);
destroy_workqueue(ieee->wq);
@@ -2607,22 +2336,16 @@ void ieee80211_softmac_free(struct ieee80211_device *ieee)
up(&ieee->wx_sem);
}
-/********************************************************
- * Start of WPA code. *
- * this is stolen from the ipw2200 driver *
- ********************************************************/
-
-
+/* Start of WPA code. This is stolen from the ipw2200 driver */
static int ieee80211_wpa_enable(struct ieee80211_device *ieee, int value)
{
/* This is called when wpa_supplicant loads and closes the driver
* interface. */
- printk("%s WPA\n",value ? "enabling" : "disabling");
+ printk("%s WPA\n", value ? "enabling" : "disabling");
ieee->wpa_enabled = value;
return 0;
}
-
static void ieee80211_wpa_assoc_frame(struct ieee80211_device *ieee, char *wpa_ie,
int wpa_ie_len)
{
@@ -2632,16 +2355,14 @@ static void ieee80211_wpa_assoc_frame(struct ieee80211_device *ieee, char *wpa_i
ieee80211_disassociate(ieee);
}
-
static int ieee80211_wpa_mlme(struct ieee80211_device *ieee, int command,
int reason)
{
-
int ret = 0;
switch (command) {
case IEEE_MLME_STA_DEAUTH:
- // silently ignore
+ /* silently ignore */
break;
case IEEE_MLME_STA_DISASSOC:
@@ -2656,7 +2377,6 @@ static int ieee80211_wpa_mlme(struct ieee80211_device *ieee, int command,
return ret;
}
-
static int ieee80211_wpa_set_wpa_ie(struct ieee80211_device *ieee,
struct ieee_param *param, int plen)
{
@@ -2690,7 +2410,6 @@ static int ieee80211_wpa_set_wpa_ie(struct ieee80211_device *ieee,
static int ieee80211_wpa_set_auth_algs(struct ieee80211_device *ieee, int value)
{
-
struct ieee80211_security sec = {
.flags = SEC_AUTH_MODE,
};
@@ -2715,7 +2434,7 @@ static int ieee80211_wpa_set_auth_algs(struct ieee80211_device *ieee, int value)
static int ieee80211_wpa_set_param(struct ieee80211_device *ieee, u8 name,
u32 value)
{
- int ret=0;
+ int ret = 0;
unsigned long flags;
switch (name) {
@@ -2724,7 +2443,7 @@ static int ieee80211_wpa_set_param(struct ieee80211_device *ieee, u8 name,
break;
case IEEE_PARAM_TKIP_COUNTERMEASURES:
- ieee->tkip_countermeasures=value;
+ ieee->tkip_countermeasures = value;
break;
case IEEE_PARAM_DROP_UNENCRYPTED: {
@@ -2743,15 +2462,14 @@ static int ieee80211_wpa_set_param(struct ieee80211_device *ieee, u8 name,
.flags = SEC_ENABLED,
.enabled = value,
};
- ieee->drop_unencrypted = value;
+ ieee->drop_unencrypted = value;
/* We only change SEC_LEVEL for open mode. Others
* are set by ipw_wpa_set_encryption.
*/
if (!value) {
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_0;
- }
- else {
+ } else {
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_1;
}
@@ -2761,27 +2479,22 @@ static int ieee80211_wpa_set_param(struct ieee80211_device *ieee, u8 name,
}
case IEEE_PARAM_PRIVACY_INVOKED:
- ieee->privacy_invoked=value;
+ ieee->privacy_invoked = value;
break;
-
case IEEE_PARAM_AUTH_ALGS:
ret = ieee80211_wpa_set_auth_algs(ieee, value);
break;
-
case IEEE_PARAM_IEEE_802_1X:
- ieee->ieee802_1x=value;
+ ieee->ieee802_1x = value;
break;
case IEEE_PARAM_WPAX_SELECT:
- // added for WPA2 mixed mode
- //printk(KERN_WARNING "------------------------>wpax value = %x\n", value);
- spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags);
+ spin_lock_irqsave(&ieee->wpax_suitlist_lock, flags);
ieee->wpax_type_set = 1;
ieee->wpax_type_notify = value;
- spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags);
+ spin_unlock_irqrestore(&ieee->wpax_suitlist_lock, flags);
break;
-
default:
- printk("Unknown WPA param: %d\n",name);
+ printk("Unknown WPA param: %d\n", name);
ret = -EOPNOTSUPP;
}
@@ -2823,8 +2536,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
if (strcmp(param->u.crypt.alg, "none") == 0) {
if (crypt) {
sec.enabled = 0;
- // FIXME FIXME
- //sec.encrypt = 0;
+ /* FIXME FIXME */
sec.level = SEC_LEVEL_0;
sec.flags |= SEC_ENABLED | SEC_LEVEL;
ieee80211_crypt_delayed_deinit(ieee, crypt);
@@ -2832,8 +2544,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
goto done;
}
sec.enabled = 1;
-// FIXME FIXME
-// sec.encrypt = 1;
+ /* FIXME FIXME */
sec.flags |= SEC_ENABLED;
/* IPW HW cannot build TKIP MIC, host decryption still needed. */
@@ -2942,12 +2653,11 @@ int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee,
struct iw_point *p)
{
struct ieee_param *param;
- int ret=0;
+ int ret = 0;
down(&ieee->wx_sem);
- //IEEE_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length);
- if (p->length < sizeof(struct ieee_param) || !p->pointer){
+ if (p->length < sizeof(struct ieee_param) || !p->pointer) {
ret = -EINVAL;
goto out;
}
@@ -2959,27 +2669,22 @@ int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee,
}
switch (param->cmd) {
-
case IEEE_CMD_SET_WPA_PARAM:
ret = ieee80211_wpa_set_param(ieee, param->u.wpa_param.name,
param->u.wpa_param.value);
break;
-
case IEEE_CMD_SET_WPA_IE:
ret = ieee80211_wpa_set_wpa_ie(ieee, param, p->length);
break;
-
case IEEE_CMD_SET_ENCRYPTION:
ret = ieee80211_wpa_set_encryption(ieee, param, p->length);
break;
-
case IEEE_CMD_MLME:
ret = ieee80211_wpa_mlme(ieee, param->u.mlme.command,
param->u.mlme.reason_code);
break;
-
default:
- printk("Unknown WPA supplicant request: %d\n",param->cmd);
+ printk("Unknown WPA supplicant request: %d\n", param->cmd);
ret = -EOPNOTSUPP;
break;
}
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
index 3b7955f0ff98..07c3f715a6f5 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
@@ -1,38 +1,38 @@
-/******************************************************************************
-
- Copyright(c) 2004 Intel Corporation. All rights reserved.
-
- Portions of this file are based on the WEP enablement code provided by the
- Host AP project hostap-drivers v0.1.3
- Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <jkmaline@cc.hut.fi>
- Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
-
- 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.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
- Contact Information:
- James P. Ketrenos <ipw2100-admin@linux.intel.com>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+/*
+ * Copyright(c) 2004 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are based on the WEP enablement code provided by the
+ * Host AP project hostap-drivers v0.1.3
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
-******************************************************************************/
#include <linux/wireless.h>
#include <linux/kmod.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/etherdevice.h>
#include "ieee80211.h"
static const char *ieee80211_modes[] = {
@@ -54,7 +54,7 @@ static inline char *rtl818x_translate_scan(struct ieee80211_device *ieee,
/* First entry *MUST* be the AP MAC address */
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
+ ether_addr_copy(iwe.u.ap_addr.sa_data, network->bssid);
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
/* Remaining entries will be displayed in the order we provide them */
@@ -62,17 +62,13 @@ static inline char *rtl818x_translate_scan(struct ieee80211_device *ieee,
/* Add the ESSID */
iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1;
- //YJ,modified,080903,for hidden ap
- //if (network->flags & NETWORK_EMPTY_ESSID) {
if (network->ssid_len == 0) {
- //YJ,modified,080903,end
iwe.u.data.length = sizeof("<hidden>");
start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
} else {
- iwe.u.data.length = min(network->ssid_len, (u8)32);
+ iwe.u.data.length = min_t(u8, network->ssid_len, 32);
start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
}
- //printk("ESSID: %s\n",network->ssid);
/* Add the protocol name */
iwe.cmd = SIOCGIWNAME;
snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", ieee80211_modes[network->mode]);
@@ -92,8 +88,6 @@ static inline char *rtl818x_translate_scan(struct ieee80211_device *ieee,
/* Add frequency/channel */
iwe.cmd = SIOCGIWFREQ;
-/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
- iwe.u.freq.e = 3; */
iwe.u.freq.m = network->channel;
iwe.u.freq.e = 0;
iwe.u.freq.i = 0;
@@ -145,10 +139,9 @@ static inline char *rtl818x_translate_scan(struct ieee80211_device *ieee,
/* Add quality statistics */
/* TODO: Fix these values... */
if (network->stats.signal == 0 || network->stats.rssi == 0)
- printk("========>signal:%d, rssi:%d\n", network->stats.signal,
- network->stats.rssi);
+ netdev_info(ieee->dev, "========>signal:%d, rssi:%d\n",
+ network->stats.signal, network->stats.rssi);
iwe.cmd = IWEVQUAL;
-// printk("SIGNAL: %d,RSSI: %d,NOISE: %d\n",network->stats.signal,network->stats.rssi,network->stats.noise);
iwe.u.qual.qual = network->stats.signalstrength;
iwe.u.qual.level = network->stats.signal;
iwe.u.qual.noise = network->stats.noise;
@@ -171,7 +164,6 @@ static inline char *rtl818x_translate_scan(struct ieee80211_device *ieee,
memset(&iwe, 0, sizeof(iwe));
if (network->wpa_ie_len) {
- // printk("wpa_ie_len:%d\n", network->wpa_ie_len);
char buf[MAX_WPA_IE_LEN];
memcpy(buf, network->wpa_ie, network->wpa_ie_len);
iwe.cmd = IWEVGENIE;
@@ -181,7 +173,6 @@ static inline char *rtl818x_translate_scan(struct ieee80211_device *ieee,
memset(&iwe, 0, sizeof(iwe));
if (network->rsn_ie_len) {
- // printk("=====>rsn_ie_len:\n", network->rsn_ie_len);
char buf[MAX_WPA_IE_LEN];
memcpy(buf, network->rsn_ie, network->rsn_ie_len);
iwe.cmd = IWEVGENIE;
@@ -190,7 +181,8 @@ static inline char *rtl818x_translate_scan(struct ieee80211_device *ieee,
}
/* Add EXTRA: Age to display seconds since last beacon/probe response
- * for given network. */
+ * for given network.
+ */
iwe.cmd = IWEVCUSTOM;
p = custom;
p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
@@ -210,8 +202,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
unsigned long flags;
int err = 0;
char *ev = extra;
- char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA;
- //char *stop = ev + IW_SCAN_MAX_DATA;
+ char *stop = ev + wrqu->data.length;
int i = 0;
IEEE80211_DEBUG_WX("Getting scan\n");
@@ -287,7 +278,8 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
IEEE80211_DEBUG_WX("Disabling encryption.\n");
/* Check all the keys to see if any are still configured,
- * and if no key index was provided, de-init them all */
+ * and if no key index was provided, de-init them all.
+ */
for (i = 0; i < WEP_KEYS; i++) {
if (ieee->crypt[i] != NULL) {
if (key_provided)
@@ -306,15 +298,14 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
goto done;
}
-
-
sec.enabled = 1;
sec.flags |= SEC_ENABLED;
if (*crypt != NULL && (*crypt)->ops != NULL &&
strcmp((*crypt)->ops->name, "WEP") != 0) {
/* changing to use WEP; deinit previously used algorithm
- * on this key */
+ * on this key.
+ */
ieee80211_crypt_delayed_deinit(ieee, crypt);
}
@@ -359,10 +350,11 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
(*crypt)->priv);
sec.flags |= (1 << key);
/* This ensures a key will be activated if no key is
- * explicitly set */
+ * explicitly set.
+ */
if (key == sec.active_key)
sec.flags |= SEC_ACTIVE_KEY;
- ieee->tx_keyidx = key;//by wb 080312
+ ieee->tx_keyidx = key;
} else {
len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
NULL, (*crypt)->priv);
@@ -395,7 +387,8 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
"OPEN" : "SHARED KEY");
/* For now we just support WEP, so only set that security level...
- * TODO: When WPA is added this is one place that needs to change */
+ * TODO: When WPA is added this is one place that needs to change
+ */
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
@@ -406,7 +399,8 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
* generate new IEEE 802.11 authentication which may end up in looping
* with IEEE 802.1X. If your hardware requires a reset after WEP
* configuration (for example... Prism2), implement the reset_port in
- * the callbacks structures used to initialize the 802.11 stack. */
+ * the callbacks structures used to initialize the 802.11 stack.
+ */
if (ieee->reset_on_keychange &&
ieee->iw_mode != IW_MODE_INFRA &&
ieee->reset_port && ieee->reset_port(dev)) {
@@ -448,7 +442,8 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
if (strcmp(crypt->ops->name, "WEP") != 0) {
/* only WEP is supported with wireless extensions, so just
- * report that encryption is used */
+ * report that encryption is used.
+ */
erq->length = 0;
erq->flags |= IW_ENCODE_ENABLED;
return 0;
@@ -483,7 +478,6 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
struct ieee80211_security sec = {
.flags = 0,
};
- //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
idx = encoding->flags & IW_ENCODE_INDEX;
if (idx) {
if (idx < 1 || idx > WEP_KEYS)
@@ -497,7 +491,6 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
group_key = 1;
} else {
/* some Cisco APs use idx>0 for unicast in dynamic WEP */
- //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
return -EINVAL;
if (ieee->iw_mode == IW_MODE_INFRA)
@@ -506,7 +499,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
return -EINVAL;
}
- sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
+ sec.flags |= SEC_ENABLED;
if ((encoding->flags & IW_ENCODE_DISABLED) ||
ext->alg == IW_ENCODE_ALG_NONE) {
if (*crypt)
@@ -518,16 +511,13 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
if (i == WEP_KEYS) {
sec.enabled = 0;
- // sec.encrypt = 0;
sec.level = SEC_LEVEL_0;
sec.flags |= SEC_LEVEL;
}
- //printk("disabled: flag:%x\n", encoding->flags);
goto done;
}
sec.enabled = 1;
- // sec.encrypt = 1;
switch (ext->alg) {
case IW_ENCODE_ALG_WEP:
@@ -545,7 +535,6 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
ret = -EINVAL;
goto done;
}
-// printk("8-09-08-9=====>%s, alg name:%s\n",__func__, alg);
ops = ieee80211_get_crypto_ops(alg);
if (ops == NULL)
@@ -553,7 +542,8 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
if (ops == NULL) {
IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
dev->name, ext->alg);
- printk("========>unknown crypto alg %d\n", ext->alg);
+ netdev_err(ieee->dev, "========>unknown crypto alg %d\n",
+ ext->alg);
ret = -EINVAL;
goto done;
}
@@ -584,13 +574,11 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
(*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
(*crypt)->priv) < 0) {
IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
- printk("key setting failed\n");
+ netdev_err(ieee->dev, "key setting failed\n");
ret = -EINVAL;
goto done;
}
#if 1
- //skip_host_crypt:
- //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
ieee->tx_keyidx = idx;
sec.active_key = idx;
@@ -602,15 +590,12 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
sec.key_sizes[idx] = ext->key_len;
sec.flags |= (1 << idx);
if (ext->alg == IW_ENCODE_ALG_WEP) {
- // sec.encode_alg[idx] = SEC_ALG_WEP;
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_1;
} else if (ext->alg == IW_ENCODE_ALG_TKIP) {
- // sec.encode_alg[idx] = SEC_ALG_TKIP;
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_2;
} else if (ext->alg == IW_ENCODE_ALG_CCMP) {
- // sec.encode_alg[idx] = SEC_ALG_CCMP;
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_3;
}
@@ -632,20 +617,19 @@ done:
return ret;
}
+
int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct iw_mlme *mlme = (struct iw_mlme *) extra;
-// printk("\ndkgadfslkdjgalskdf===============>%s(), cmd:%x\n", __func__, mlme->cmd);
#if 1
switch (mlme->cmd) {
case IW_MLME_DEAUTH:
case IW_MLME_DISASSOC:
- // printk("disassoc now\n");
ieee80211_disassociate(ieee);
break;
- default:
+ default:
return -EOPNOTSUPP;
}
#endif
@@ -656,24 +640,16 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
struct iw_request_info *info,
struct iw_param *data, char *extra)
{
-/*
- struct ieee80211_security sec = {
- .flags = SEC_AUTH_MODE,
- }
-*/
- //printk("set auth:flag:%x, data value:%x\n", data->flags, data->value);
switch (data->flags & IW_AUTH_INDEX) {
case IW_AUTH_WPA_VERSION:
- /*need to support wpa2 here*/
- //printk("wpa version:%x\n", data->value);
+ /* need to support wpa2 here */
break;
case IW_AUTH_CIPHER_PAIRWISE:
case IW_AUTH_CIPHER_GROUP:
case IW_AUTH_KEY_MGMT:
- /*
- * * Host AP driver does not use these parameters and allows
- * * wpa_supplicant to control them internally.
- * */
+ /* Host AP driver does not use these parameters and allows
+ * wpa_supplicant to control them internally.
+ */
break;
case IW_AUTH_TKIP_COUNTERMEASURES:
ieee->tkip_countermeasures = data->value;
@@ -684,13 +660,11 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
case IW_AUTH_80211_AUTH_ALG:
ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM) ? 1 : 0;
- //printk("open_wep:%d\n", ieee->open_wep);
break;
#if 1
case IW_AUTH_WPA_ENABLED:
ieee->wpa_enabled = (data->value) ? 1 : 0;
- //printk("enable wpa:%d\n", ieee->wpa_enabled);
break;
#endif
@@ -712,13 +686,13 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
u8 *buf = NULL;
if (len > MAX_WPA_IE_LEN || (len && ie == NULL)) {
- printk("return error out, len:%zu\n", len);
+ netdev_err(ieee->dev, "return error out, len:%zu\n", len);
return -EINVAL;
}
if (len) {
if (len != ie[1]+2) {
- printk("len:%zu, ie:%d\n", len, ie[1]);
+ netdev_err(ieee->dev, "len:%zu, ie:%d\n", len, ie[1]);
return -EINVAL;
}
buf = kmemdup(ie, len, GFP_KERNEL);
@@ -732,7 +706,6 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
ieee->wpa_ie = NULL;
ieee->wpa_ie_len = 0;
}
-// printk("<=====out %s()\n", __func__);
return 0;
diff --git a/drivers/staging/rtl8187se/r8180.h b/drivers/staging/rtl8187se/r8180.h
index 8999ec62450d..9f931dba1d82 100644
--- a/drivers/staging/rtl8187se/r8180.h
+++ b/drivers/staging/rtl8187se/r8180.h
@@ -1,19 +1,18 @@
/*
- This is part of rtl8180 OpenSource driver.
- Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
- Released under the terms of GPL (General Public Licence)
-
- Parts of this driver are based on the GPL part of the
- official realtek driver
-
- Parts of this driver are based on the rtl8180 driver skeleton
- from Patric Schenke & Andres Salomon
-
- Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
-
- We want to thanks the Authors of those projects and the Ndiswrapper
- project Authors.
-*/
+ * This is part of rtl8180 OpenSource driver.
+ * Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
+ * Released under the terms of GPL (General Public Licence)
+ *
+ * Parts of this driver are based on the GPL part of the official realtek driver
+ *
+ * Parts of this driver are based on the rtl8180 driver skeleton from Patric
+ * Schenke & Andres Salomon
+ *
+ * Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
+ *
+ * We want to thanks the Authors of those projects and the Ndiswrapper project
+ * Authors.
+ */
#ifndef R8180H
#define R8180H
@@ -21,13 +20,12 @@
#include <linux/interrupt.h>
#define RTL8180_MODULE_NAME "r8180"
-#define DMESG(x,a...) printk(KERN_INFO RTL8180_MODULE_NAME ": " x "\n", ## a)
-#define DMESGW(x,a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": WW:" x "\n", ## a)
-#define DMESGE(x,a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": EE:" x "\n", ## a)
+#define DMESG(x, a...) printk(KERN_INFO RTL8180_MODULE_NAME ": " x "\n", ## a)
+#define DMESGW(x, a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": WW:" x "\n", ## a)
+#define DMESGE(x, a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": EE:" x "\n", ## a)
#include <linux/module.h>
#include <linux/kernel.h>
-//#include <linux/config.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/types.h>
@@ -36,22 +34,21 @@
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
-#include <linux/rtnetlink.h> //for rtnl_lock()
+#include <linux/rtnetlink.h> /* for rtnl_lock() */
#include <linux/wireless.h>
#include <linux/timer.h>
-#include <linux/proc_fs.h> // Necessary because we use the proc fs
+#include <linux/proc_fs.h> /* Necessary because we use the proc fs. */
#include <linux/if_arp.h>
#include "ieee80211/ieee80211.h"
#include <asm/io.h>
-//#include <asm/semaphore.h>
#define EPROM_93c46 0
#define EPROM_93c56 1
-#define RTL_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30
+#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV + 30)
#define DEFAULT_FRAG_THRESHOLD 2342U
-#define MIN_FRAG_THRESHOLD 256U
+#define MIN_FRAG_THRESHOLD 256U
#define DEFAULT_RTS_THRESHOLD 2342U
#define MIN_RTS_THRESHOLD 0U
#define MAX_RTS_THRESHOLD 2342U
@@ -60,132 +57,99 @@
#define DEFAULT_RETRY_RTS 7
#define DEFAULT_RETRY_DATA 7
-#define BEACON_QUEUE 6
+#define BEACON_QUEUE 6
-#define aSifsTime 10
+#define aSifsTime 10
-#define sCrcLng 4
-#define sAckCtsLng 112 // bits in ACK and CTS frames
-//+by amy 080312
-#define RATE_ADAPTIVE_TIMER_PERIOD 300
+#define sCrcLng 4
+#define sAckCtsLng 112 /* bits in ACK and CTS frames. */
+/* +by amy 080312. */
+#define RATE_ADAPTIVE_TIMER_PERIOD 300
-typedef enum _WIRELESS_MODE {
+enum wireless_mode {
WIRELESS_MODE_UNKNOWN = 0x00,
WIRELESS_MODE_A = 0x01,
WIRELESS_MODE_B = 0x02,
WIRELESS_MODE_G = 0x04,
WIRELESS_MODE_AUTO = 0x08,
-} WIRELESS_MODE;
-
-typedef struct ChnlAccessSetting {
- u16 SIFS_Timer;
- u16 DIFS_Timer;
- u16 SlotTimeTimer;
- u16 EIFS_Timer;
- u16 CWminIndex;
- u16 CWmaxIndex;
-}*PCHANNEL_ACCESS_SETTING,CHANNEL_ACCESS_SETTING;
-
-typedef enum{
- NIC_8185 = 1,
- NIC_8185B
- } nic_t;
+};
+
+struct chnl_access_setting {
+ u16 sifs_timer;
+ u16 difs_timer;
+ u16 slot_time_timer;
+ u16 eifs_timer;
+ u16 cwmin_index;
+ u16 cwmax_index;
+};
+
+enum nic_t {
+ NIC_8185 = 1,
+ NIC_8185B
+};
typedef u32 AC_CODING;
-#define AC0_BE 0 // ACI: 0x00 // Best Effort
-#define AC1_BK 1 // ACI: 0x01 // Background
-#define AC2_VI 2 // ACI: 0x10 // Video
-#define AC3_VO 3 // ACI: 0x11 // Voice
-#define AC_MAX 4 // Max: define total number; Should not to be used as a real enum.
-
-//
-// ECWmin/ECWmax field.
-// Ref: WMM spec 2.2.2: WME Parameter Element, p.13.
-//
-typedef union _ECW{
- u8 charData;
- struct
- {
- u8 ECWmin:4;
- u8 ECWmax:4;
- }f; // Field
-}ECW, *PECW;
-
-//
-// ACI/AIFSN Field.
-// Ref: WMM spec 2.2.2: WME Parameter Element, p.12.
-//
-typedef union _ACI_AIFSN{
- u8 charData;
-
- struct
- {
- u8 AIFSN:4;
- u8 ACM:1;
- u8 ACI:2;
- u8 Reserved:1;
- }f; // Field
-}ACI_AIFSN, *PACI_AIFSN;
-
-//
-// AC Parameters Record Format.
-// Ref: WMM spec 2.2.2: WME Parameter Element, p.12.
-//
-typedef union _AC_PARAM{
- u32 longData;
- u8 charData[4];
-
- struct
- {
- ACI_AIFSN AciAifsn;
- ECW Ecw;
- u16 TXOPLimit;
- }f; // Field
-}AC_PARAM, *PAC_PARAM;
-
-/* it is a wrong definition. -xiong-2006-11-17
-typedef struct ThreeWireReg {
- u16 longData;
+#define AC0_BE 0 /* ACI: 0x00 */ /* Best Effort. */
+#define AC1_BK 1 /* ACI: 0x01 */ /* Background. */
+#define AC2_VI 2 /* ACI: 0x10 */ /* Video. */
+#define AC3_VO 3 /* ACI: 0x11 */ /* Voice. */
+#define AC_MAX 4 /* Max: define total number; Should not to be used as a real
+ * enum.
+ */
+
+/*
+ * ECWmin/ECWmax field.
+ * Ref: WMM spec 2.2.2: WME Parameter Element, p.13.
+ */
+typedef union _ECW {
+ u8 charData;
+ struct {
+ u8 ECWmin:4;
+ u8 ECWmax:4;
+ } f; /* Field */
+} ECW, *PECW;
+
+/*
+ * ACI/AIFSN Field. Ref: WMM spec 2.2.2: WME Parameter Element, p.12.
+ */
+typedef union _ACI_AIFSN {
+ u8 charData;
+
struct {
- u8 enableB;
- u8 data;
- u8 clk;
- u8 read_write;
- } struc;
-} ThreeWireReg;
-*/
-
-typedef union _ThreeWire{
- struct _ThreeWireStruc{
- u16 data:1;
- u16 clk:1;
- u16 enableB:1;
- u16 read_write:1;
- u16 resv1:12;
-// u2Byte resv2:14;
-// u2Byte ThreeWireEnable:1;
-// u2Byte resv3:1;
- }struc;
- u16 longData;
-}ThreeWireReg;
-
-
-typedef struct buffer
-{
+ u8 AIFSN:4;
+ u8 ACM:1;
+ u8 ACI:2;
+ u8 Reserved:1;
+ } f; /* Field */
+} ACI_AIFSN, *PACI_AIFSN;
+
+/*
+ * AC Parameters Record Format.
+ * Ref: WMM spec 2.2.2: WME Parameter Element, p.12.
+ */
+typedef union _AC_PARAM {
+ u32 longData;
+ u8 charData[4];
+
+ struct {
+ ACI_AIFSN AciAifsn;
+ ECW Ecw;
+ u16 TXOPLimit;
+ } f; /* Field */
+} AC_PARAM, *PAC_PARAM;
+
+struct buffer {
struct buffer *next;
u32 *buf;
dma_addr_t dma;
-} buffer;
+};
-//YJ,modified,080828
-typedef struct Stats
-{
+/* YJ,modified,080828. */
+struct stats {
unsigned long txrdu;
unsigned long rxrdu;
unsigned long rxnolast;
unsigned long rxnodata;
-// unsigned long rxreset;
-// unsigned long rxwrkaround;
unsigned long rxnopointer;
unsigned long txnperr;
unsigned long txresumed;
@@ -207,126 +171,123 @@ typedef struct Stats
unsigned long txbeaconerr;
unsigned long txlpokint;
unsigned long txlperr;
- unsigned long txretry;//retry number tony 20060601
- unsigned long rxcrcerrmin;//crc error (0-500)
- unsigned long rxcrcerrmid;//crc error (500-1000)
- unsigned long rxcrcerrmax;//crc error (>1000)
- unsigned long rxicverr;//ICV error
-} Stats;
+ unsigned long txretry; /* retry number tony 20060601 */
+ unsigned long rxcrcerrmin; /* crc error (0-500) */
+ unsigned long rxcrcerrmid; /* crc error (500-1000) */
+ unsigned long rxcrcerrmax; /* crc error (>1000) */
+ unsigned long rxicverr; /* ICV error */
+};
#define MAX_LD_SLOT_NUM 10
-#define KEEP_ALIVE_INTERVAL 20 // in seconds.
-#define CHECK_FOR_HANG_PERIOD 2 //be equal to watchdog check time
-#define DEFAULT_KEEP_ALIVE_LEVEL 1
-#define DEFAULT_SLOT_NUM 2
-#define POWER_PROFILE_AC 0
-#define POWER_PROFILE_BATTERY 1
-
-typedef struct _link_detect_t
-{
- u32 RxFrameNum[MAX_LD_SLOT_NUM]; // number of Rx Frame / CheckForHang_period to determine link status
- u16 SlotNum; // number of CheckForHang period to determine link status, default is 2
- u16 SlotIndex;
-
- u32 NumTxOkInPeriod; //number of packet transmitted during CheckForHang
- u32 NumRxOkInPeriod; //number of packet received during CheckForHang
-
- u8 IdleCount; // (KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD)
- u32 LastNumTxUnicast;
- u32 LastNumRxUnicast;
-
- bool bBusyTraffic; //when it is set to 1, UI cann't scan at will.
-}link_detect_t, *plink_detect_t;
-
-//YJ,modified,080828,end
-
-//by amy for led
-//================================================================================
-// LED customization.
-//================================================================================
-
-typedef enum _LED_STRATEGY_8185{
- SW_LED_MODE0, //
- SW_LED_MODE1, //
- HW_LED, // HW control 2 LEDs, LED0 and LED1 (there are 4 different control modes)
-}LED_STRATEGY_8185, *PLED_STRATEGY_8185;
-//by amy for led
-//by amy for power save
-typedef enum _LED_CTL_MODE{
- LED_CTL_POWER_ON = 1,
- LED_CTL_LINK = 2,
- LED_CTL_NO_LINK = 3,
- LED_CTL_TX = 4,
- LED_CTL_RX = 5,
- LED_CTL_SITE_SURVEY = 6,
- LED_CTL_POWER_OFF = 7
-}LED_CTL_MODE;
-
-typedef enum _RT_RF_POWER_STATE
-{
- eRfOn,
- eRfSleep,
- eRfOff
-}RT_RF_POWER_STATE;
-
-enum _ReasonCode{
- unspec_reason = 0x1,
- auth_not_valid = 0x2,
- deauth_lv_ss = 0x3,
- inactivity = 0x4,
- ap_overload = 0x5,
- class2_err = 0x6,
- class3_err = 0x7,
- disas_lv_ss = 0x8,
- asoc_not_auth = 0x9,
-
- //----MIC_CHECK
- mic_failure = 0xe,
- //----END MIC_CHECK
-
- // Reason code defined in 802.11i D10.0 p.28.
- invalid_IE = 0x0d,
- four_way_tmout = 0x0f,
- two_way_tmout = 0x10,
- IE_dismatch = 0x11,
+#define KEEP_ALIVE_INTERVAL 20 /* in seconds. */
+#define CHECK_FOR_HANG_PERIOD 2 /* be equal to watchdog check time. */
+#define DEFAULT_KEEP_ALIVE_LEVEL 1
+#define DEFAULT_SLOT_NUM 2
+#define POWER_PROFILE_AC 0
+#define POWER_PROFILE_BATTERY 1
+
+struct link_detect_t {
+ u32 rx_frame_num[MAX_LD_SLOT_NUM]; /* number of Rx Frame.
+ * CheckForHang_period to determine
+ * link status.
+ */
+ u16 slot_num; /* number of CheckForHang period to determine link status,
+ * default is 2.
+ */
+ u16 slot_index;
+ u32 num_tx_ok_in_period; /* number of packet transmitted during
+ * CheckForHang.
+ */
+ u32 num_rx_ok_in_period; /* number of packet received during
+ * CheckForHang.
+ */
+ u8 idle_count; /* (KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD) */
+ u32 last_num_tx_unicast;
+ u32 last_num_rx_unicast;
+
+ bool b_busy_traffic; /* when it is set to 1, UI cann't scan at will. */
+};
+
+/* YJ,modified,080828,end */
+
+/* by amy for led
+ * ==========================================================================
+ * LED customization.
+ * ==========================================================================
+ */
+enum led_strategy_8185 {
+ SW_LED_MODE0,
+ SW_LED_MODE1,
+ HW_LED, /* HW control 2 LEDs, LED0 and LED1 (there are 4 different
+ * control modes). */
+};
+
+enum rt_rf_power_state {
+ RF_ON,
+ RF_SLEEP,
+ RF_OFF
+};
+
+enum _ReasonCode {
+ unspec_reason = 0x1,
+ auth_not_valid = 0x2,
+ deauth_lv_ss = 0x3,
+ inactivity = 0x4,
+ ap_overload = 0x5,
+ class2_err = 0x6,
+ class3_err = 0x7,
+ disas_lv_ss = 0x8,
+ asoc_not_auth = 0x9,
+
+ /* ----MIC_CHECK */
+ mic_failure = 0xe,
+ /* ----END MIC_CHECK */
+
+ /* Reason code defined in 802.11i D10.0 p.28. */
+ invalid_IE = 0x0d,
+ four_way_tmout = 0x0f,
+ two_way_tmout = 0x10,
+ IE_dismatch = 0x11,
invalid_Gcipher = 0x12,
invalid_Pcipher = 0x13,
- invalid_AKMP = 0x14,
+ invalid_AKMP = 0x14,
unsup_RSNIEver = 0x15,
- invalid_RSNIE = 0x16,
- auth_802_1x_fail= 0x17,
- ciper_reject = 0x18,
-
- // Reason code defined in 7.3.1.7, 802.1e D13.0, p.42. Added by Annie, 2005-11-15.
- QoS_unspec = 0x20, // 32
- QAP_bandwidth = 0x21, // 33
- poor_condition = 0x22, // 34
- no_facility = 0x23, // 35
- // Where is 36???
- req_declined = 0x25, // 37
- invalid_param = 0x26, // 38
- req_not_honored= 0x27, // 39
- TS_not_created = 0x2F, // 47
- DL_not_allowed = 0x30, // 48
- dest_not_exist = 0x31, // 49
- dest_not_QSTA = 0x32, // 50
+ invalid_RSNIE = 0x16,
+ auth_802_1x_fail = 0x17,
+ ciper_reject = 0x18,
+
+ /* Reason code defined in 7.3.1.7, 802.1e D13.0, p.42. Added by Annie,
+ * 2005-11-15.
+ */
+ QoS_unspec = 0x20, /* 32 */
+ QAP_bandwidth = 0x21, /* 33 */
+ poor_condition = 0x22, /* 34 */
+ no_facility = 0x23, /* 35 */
+ /* Where is 36??? */
+ req_declined = 0x25, /* 37 */
+ invalid_param = 0x26, /* 38 */
+ req_not_honored = 0x27, /* 39 */
+ TS_not_created = 0x2F, /* 47 */
+ DL_not_allowed = 0x30, /* 48 */
+ dest_not_exist = 0x31, /* 49 */
+ dest_not_QSTA = 0x32, /* 50 */
+};
+
+enum rt_ps_mode {
+ ACTIVE, /* Active/Continuous access. */
+ MAX_PS, /* Max power save mode. */
+ FAST_PS /* Fast power save mode. */
};
-typedef enum _RT_PS_MODE
-{
- eActive, // Active/Continuous access.
- eMaxPs, // Max power save mode.
- eFastPs // Fast power save mode.
-}RT_PS_MODE;
-//by amy for power save
-typedef struct r8180_priv
-{
+
+/* by amy for power save. */
+struct r8180_priv {
struct pci_dev *pdev;
short epromtype;
int irq;
struct ieee80211_device *ieee80211;
- short plcp_preamble_mode; // 0:auto 1:short 2:long
+ short plcp_preamble_mode; /* 0:auto 1:short 2:long */
spinlock_t irq_th_lock;
spinlock_t tx_lock;
@@ -339,19 +300,15 @@ typedef struct r8180_priv
short chan;
short sens;
short max_sens;
- u8 chtxpwr[15]; //channels from 1 to 14, 0 not used
- u8 chtxpwr_ofdm[15]; //channels from 1 to 14, 0 not used
- //u8 challow[15]; //channels from 1 to 14, 0 not used
- u8 channel_plan; // it's the channel plan index
+ u8 chtxpwr[15]; /* channels from 1 to 14, 0 not used. */
+ u8 chtxpwr_ofdm[15]; /* channels from 1 to 14, 0 not used. */
+ u8 channel_plan; /* it's the channel plan index. */
short up;
- short crcmon; //if 1 allow bad crc frame reception in monitor mode
+ short crcmon; /* if 1 allow bad crc frame reception in monitor mode. */
struct timer_list scan_timer;
- /*short scanpending;
- short stopscan;*/
spinlock_t scan_lock;
u8 active_probe;
- //u8 active_scan_num;
struct semaphore wx_sem;
short hw_wep;
@@ -359,20 +316,20 @@ typedef struct r8180_priv
short antb;
short diversity;
u32 key0[4];
- short (*rf_set_sens)(struct net_device *dev,short sens);
- void (*rf_set_chan)(struct net_device *dev,short ch);
+ short (*rf_set_sens)(struct net_device *dev, short sens);
+ void (*rf_set_chan)(struct net_device *dev, short ch);
void (*rf_close)(struct net_device *dev);
void (*rf_init)(struct net_device *dev);
void (*rf_sleep)(struct net_device *dev);
void (*rf_wakeup)(struct net_device *dev);
- //short rate;
+ /* short rate; */
short promisc;
- /*stats*/
- struct Stats stats;
- struct _link_detect_t link_detect; //YJ,add,080828
+ /* stats */
+ struct stats stats;
+ struct link_detect_t link_detect; /* YJ,add,080828 */
struct iw_statistics wstats;
- /*RX stuff*/
+ /* RX stuff. */
u32 *rxring;
u32 *rxringtail;
dma_addr_t rxringdma;
@@ -387,27 +344,6 @@ typedef struct r8180_priv
u32 rx_prevlen;
- /*TX stuff*/
-/*
- u32 *txlpring;
- u32 *txhpring;
- u32 *txnpring;
- dma_addr_t txlpringdma;
- dma_addr_t txhpringdma;
- dma_addr_t txnpringdma;
- u32 *txlpringtail;
- u32 *txhpringtail;
- u32 *txnpringtail;
- u32 *txlpringhead;
- u32 *txhpringhead;
- u32 *txnpringhead;
- struct buffer *txlpbufs;
- struct buffer *txhpbufs;
- struct buffer *txnpbufs;
- struct buffer *txlpbufstail;
- struct buffer *txhpbufstail;
- struct buffer *txnpbufstail;
-*/
u32 *txmapring;
u32 *txbkpring;
u32 *txbepring;
@@ -447,54 +383,47 @@ typedef struct r8180_priv
int txringcount;
int txbuffsize;
- //struct tx_pendingbuf txnp_pending;
- //struct tasklet_struct irq_tx_tasklet;
struct tasklet_struct irq_rx_tasklet;
u8 dma_poll_mask;
- //short tx_suspend;
- /* adhoc/master mode stuff */
+ /* adhoc/master mode stuff. */
u32 *txbeaconringtail;
dma_addr_t txbeaconringdma;
u32 *txbeaconring;
int txbeaconcount;
struct buffer *txbeaconbufs;
struct buffer *txbeaconbufstail;
- //char *master_essid;
- //u16 master_beaconinterval;
- //u32 master_beaconsize;
- //u16 beacon_interval;
u8 retry_data;
u8 retry_rts;
u16 rts;
-//by amy for led
- LED_STRATEGY_8185 LedStrategy;
-//by amy for led
+ /* by amy for led. */
+ enum led_strategy_8185 led_strategy;
+ /* by amy for led. */
-//by amy for power save
+ /* by amy for power save. */
struct timer_list watch_dog_timer;
bool bInactivePs;
bool bSwRfProcessing;
- RT_RF_POWER_STATE eInactivePowerState;
- RT_RF_POWER_STATE eRFPowerState;
+ enum rt_rf_power_state eInactivePowerState;
+ enum rt_rf_power_state eRFPowerState;
u32 RfOffReason;
bool RFChangeInProgress;
bool SetRFPowerStateInProgress;
- u8 RFProgType;
+ u8 RFProgType;
bool bLeisurePs;
- RT_PS_MODE dot11PowerSaveMode;
- //u32 NumRxOkInPeriod; //YJ,del,080828
- //u32 NumTxOkInPeriod; //YJ,del,080828
- u8 TxPollingTimes;
+ enum rt_ps_mode dot11PowerSaveMode;
+ u8 TxPollingTimes;
- bool bApBufOurFrame;// TRUE if AP buffer our unicast data , we will keep eAwake until receive data or timeout.
- u8 WaitBufDataBcnCount;
- u8 WaitBufDataTimeOut;
+ bool bApBufOurFrame; /* TRUE if AP buffer our unicast data , we will
+ * keep eAwake until receive data or timeout.
+ */
+ u8 WaitBufDataBcnCount;
+ u8 WaitBufDataTimeOut;
-//by amy for power save
-//by amy for antenna
+ /* by amy for power save. */
+ /* by amy for antenna. */
u8 EEPROMSwAntennaDiversity;
bool EEPROMDefaultAntenna1;
u8 RegSwAntennaDiversityMechanism;
@@ -503,115 +432,128 @@ typedef struct r8180_priv
bool bDefaultAntenna1;
u8 SignalStrength;
long Stats_SignalStrength;
- long LastSignalStrengthInPercent; // In percentage, used for smoothing, e.g. Moving Average.
- u8 SignalQuality; // in 0-100 index.
+ long LastSignalStrengthInPercent; /* In percentage, used for smoothing,
+ * e.g. Moving Average.
+ */
+ u8 SignalQuality; /* in 0-100 index. */
long Stats_SignalQuality;
- long RecvSignalPower; // in dBm.
+ long RecvSignalPower; /* in dBm. */
long Stats_RecvSignalPower;
- u8 LastRxPktAntenna; // +by amy 080312 Antenna which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25.
+ u8 LastRxPktAntenna; /* +by amy 080312 Antenna which received the lasted
+ * packet. 0: Aux, 1:Main. Added by Roger,
+ * 2008.01.25.
+ */
u32 AdRxOkCnt;
long AdRxSignalStrength;
- u8 CurrAntennaIndex; // Index to current Antenna (both Tx and Rx).
- u8 AdTickCount; // Times of SwAntennaDiversityTimer happened.
- u8 AdCheckPeriod; // # of period SwAntennaDiversityTimer to check Rx signal strength for SW Antenna Diversity.
- u8 AdMinCheckPeriod; // Min value of AdCheckPeriod.
- u8 AdMaxCheckPeriod; // Max value of AdCheckPeriod.
- long AdRxSsThreshold; // Signal strength threshold to switch antenna.
- long AdMaxRxSsThreshold; // Max value of AdRxSsThreshold.
- bool bAdSwitchedChecking; // TRUE if we shall shall check Rx signal strength for last time switching antenna.
- long AdRxSsBeforeSwitched; // Rx signal strength before we switched antenna.
+ u8 CurrAntennaIndex; /* Index to current Antenna (both Tx and Rx). */
+ u8 AdTickCount; /* Times of SwAntennaDiversityTimer happened. */
+ u8 AdCheckPeriod; /* # of period SwAntennaDiversityTimer to check Rx
+ * signal strength for SW Antenna Diversity.
+ */
+ u8 AdMinCheckPeriod; /* Min value of AdCheckPeriod. */
+ u8 AdMaxCheckPeriod; /* Max value of AdCheckPeriod. */
+ long AdRxSsThreshold; /* Signal strength threshold to switch antenna. */
+ long AdMaxRxSsThreshold; /* Max value of AdRxSsThreshold. */
+ bool bAdSwitchedChecking; /* TRUE if we shall shall check Rx signal
+ * strength for last time switching antenna.
+ */
+ long AdRxSsBeforeSwitched; /* Rx signal strength before we switched
+ * antenna.
+ */
struct timer_list SwAntennaDiversityTimer;
-//by amy for antenna
-//{by amy 080312
-//
- // Crystal calibration.
- // Added by Roger, 2007.12.11.
- //
- bool bXtalCalibration; // Crystal calibration.
- u8 XtalCal_Xin; // Crystal calibration for Xin. 0~7.5pF
- u8 XtalCal_Xout; // Crystal calibration for Xout. 0~7.5pF
- //
- // Tx power tracking with thermal meter indication.
- // Added by Roger, 2007.12.11.
- //
- bool bTxPowerTrack; // Tx Power tracking.
- u8 ThermalMeter; // Thermal meter reference indication.
- //
- // Dynamic Initial Gain Adjustment Mechanism. Added by Bruce, 2007-02-14.
- //
- bool bDigMechanism; // TRUE if DIG is enabled, FALSE ow.
- bool bRegHighPowerMechanism; // For High Power Mechanism. 061010, by rcnjko.
- u32 FalseAlarmRegValue;
- u8 RegDigOfdmFaUpTh; // Upper threshold of OFDM false alarm, which is used in DIG.
- u8 DIG_NumberFallbackVote;
- u8 DIG_NumberUpgradeVote;
- // For HW antenna diversity, added by Roger, 2008.01.30.
- u32 AdMainAntennaRxOkCnt; // Main antenna Rx OK count.
- u32 AdAuxAntennaRxOkCnt; // Aux antenna Rx OK count.
- bool bHWAdSwitched; // TRUE if we has switched default antenna by HW evaluation.
- // RF High Power upper/lower threshold.
- u8 RegHiPwrUpperTh;
- u8 RegHiPwrLowerTh;
- // RF RSSI High Power upper/lower Threshold.
- u8 RegRSSIHiPwrUpperTh;
- u8 RegRSSIHiPwrLowerTh;
- // Current CCK RSSI value to determine CCK high power, asked by SD3 DZ, by Bruce, 2007-04-12.
- u8 CurCCKRSSI;
- bool bCurCCKPkt;
- //
- // High Power Mechanism. Added by amy, 080312.
- //
- bool bToUpdateTxPwr;
- long UndecoratedSmoothedSS;
- long UndercorateSmoothedRxPower;
- u8 RSSI;
- char RxPower;
- u8 InitialGain;
- //For adjust Dig Threshold during Legacy/Leisure Power Save Mode
- u32 DozePeriodInPast2Sec;
- // Don't access BB/RF under disable PLL situation.
- u8 InitialGainBackUp;
- u8 RegBModeGainStage;
-//by amy for rate adaptive
- struct timer_list rateadapter_timer;
- u32 RateAdaptivePeriod;
- bool bEnhanceTxPwr;
- bool bUpdateARFR;
- int ForcedDataRate; // Force Data Rate. 0: Auto, 0x02: 1M ~ 0x6C: 54M.)
- u32 NumTxUnicast; //YJ,add,080828,for keep alive
- u8 keepAliveLevel; //YJ,add,080828,for KeepAlive
- unsigned long NumTxOkTotal;
- u16 LastRetryCnt;
- u16 LastRetryRate;
- unsigned long LastTxokCnt;
- unsigned long LastRxokCnt;
- u16 CurrRetryCnt;
- unsigned long LastTxOKBytes;
- unsigned long NumTxOkBytesTotal;
- u8 LastFailTxRate;
- long LastFailTxRateSS;
- u8 FailTxRateCount;
- u32 LastTxThroughput;
- //for up rate
- unsigned short bTryuping;
- u8 CurrTxRate; //the rate before up
- u16 CurrRetryRate;
- u16 TryupingCount;
- u8 TryDownCountLowData;
- u8 TryupingCountNoData;
-
- u8 CurrentOperaRate;
-//by amy for rate adaptive
-//by amy 080312}
-// short wq_hurryup;
-// struct workqueue_struct *workqueue;
+ /* by amy for antenna {by amy 080312 */
+
+ /* Crystal calibration. Added by Roger, 2007.12.11. */
+
+ bool bXtalCalibration; /* Crystal calibration.*/
+ u8 XtalCal_Xin; /* Crystal calibration for Xin. 0~7.5pF */
+ u8 XtalCal_Xout; /* Crystal calibration for Xout. 0~7.5pF */
+
+ /* Tx power tracking with thermal meter indication.
+ * Added by Roger, 2007.12.11.
+ */
+
+ bool bTxPowerTrack; /* Tx Power tracking. */
+ u8 ThermalMeter; /* Thermal meter reference indication. */
+
+ /* Dynamic Initial Gain Adjustment Mechanism. Added by Bruce,
+ * 2007-02-14.
+ */
+ bool bDigMechanism; /* TRUE if DIG is enabled, FALSE ow. */
+ bool bRegHighPowerMechanism; /* For High Power Mechanism. 061010,
+ * by rcnjko.
+ */
+ u32 FalseAlarmRegValue;
+ u8 RegDigOfdmFaUpTh; /* Upper threshold of OFDM false alarm, which is
+ * used in DIG.
+ */
+ u8 DIG_NumberFallbackVote;
+ u8 DIG_NumberUpgradeVote;
+ /* For HW antenna diversity, added by Roger, 2008.01.30. */
+ u32 AdMainAntennaRxOkCnt; /* Main antenna Rx OK count. */
+ u32 AdAuxAntennaRxOkCnt; /* Aux antenna Rx OK count. */
+ bool bHWAdSwitched; /* TRUE if we has switched default antenna by HW
+ * evaluation.
+ */
+ /* RF High Power upper/lower threshold. */
+ u8 RegHiPwrUpperTh;
+ u8 RegHiPwrLowerTh;
+ /* RF RSSI High Power upper/lower Threshold. */
+ u8 RegRSSIHiPwrUpperTh;
+ u8 RegRSSIHiPwrLowerTh;
+ /* Current CCK RSSI value to determine CCK high power, asked by SD3 DZ,
+ * by Bruce, 2007-04-12.
+ */
+ u8 CurCCKRSSI;
+ bool bCurCCKPkt;
+ /* High Power Mechanism. Added by amy, 080312. */
+ bool bToUpdateTxPwr;
+ long UndecoratedSmoothedSS;
+ long UndecoratedSmoothedRxPower;
+ u8 RSSI;
+ char RxPower;
+ u8 InitialGain;
+ /* For adjust Dig Threshold during Legacy/Leisure Power Save Mode. */
+ u32 DozePeriodInPast2Sec;
+ /* Don't access BB/RF under disable PLL situation. */
+ u8 InitialGainBackUp;
+ u8 RegBModeGainStage;
+ /* by amy for rate adaptive */
+ struct timer_list rateadapter_timer;
+ u32 RateAdaptivePeriod;
+ bool bEnhanceTxPwr;
+ bool bUpdateARFR;
+ int ForcedDataRate; /* Force Data Rate. 0: Auto, 0x02: 1M ~ 0x6C: 54M.)
+ */
+ u32 NumTxUnicast; /* YJ,add,080828,for keep alive. */
+ u8 keepAliveLevel; /*YJ,add,080828,for KeepAlive. */
+ unsigned long NumTxOkTotal;
+ u16 LastRetryCnt;
+ u16 LastRetryRate;
+ unsigned long LastTxokCnt;
+ unsigned long LastRxokCnt;
+ u16 CurrRetryCnt;
+ unsigned long LastTxOKBytes;
+ unsigned long NumTxOkBytesTotal;
+ u8 LastFailTxRate;
+ long LastFailTxRateSS;
+ u8 FailTxRateCount;
+ u32 LastTxThroughput;
+ /* for up rate. */
+ unsigned short bTryuping;
+ u8 CurrTxRate; /* the rate before up. */
+ u16 CurrRetryRate;
+ u16 TryupingCount;
+ u8 TryDownCountLowData;
+ u8 TryupingCountNoData;
+
+ u8 CurrentOperaRate;
struct work_struct reset_wq;
struct work_struct watch_dog_wq;
short ack_tx_to_ieee;
u8 dma_poll_stop_mask;
- //u8 RegThreeWireMode;
u16 ShortRetryLimit;
u16 LongRetryLimit;
u16 EarlyRxThreshold;
@@ -619,8 +561,8 @@ typedef struct r8180_priv
u32 ReceiveConfig;
u32 IntrMask;
- struct ChnlAccessSetting ChannelAccessSetting;
-}r8180_priv;
+ struct chnl_access_setting ChannelAccessSetting;
+};
#define MANAGE_PRIORITY 0
#define BK_PRIORITY 1
@@ -632,14 +574,14 @@ typedef struct r8180_priv
#define LOW_PRIORITY VI_PRIORITY
#define NORM_PRIORITY VO_PRIORITY
-//AC2Queue mapping
+/* AC2Queue mapping. */
#define AC2Q(_ac) (((_ac) == WME_AC_VO) ? VO_PRIORITY : \
((_ac) == WME_AC_VI) ? VI_PRIORITY : \
((_ac) == WME_AC_BK) ? BK_PRIORITY : \
BE_PRIORITY)
short rtl8180_tx(struct net_device *dev, u8 *skbuf, int len, int priority,
- short morefrag, short fragdesc, int rate);
+ bool morefrag, short fragdesc, int rate);
u8 read_nic_byte(struct net_device *dev, int x);
u32 read_nic_dword(struct net_device *dev, int x);
@@ -673,7 +615,6 @@ void UpdateInitialGain(struct net_device *dev);
bool SetAntennaConfig87SE(struct net_device *dev, u8 DefaultAnt,
bool bAntDiversity);
-//#ifdef CONFIG_RTL8185B
void rtl8185b_adapter_start(struct net_device *dev);
void rtl8185b_rx_enable(struct net_device *dev);
void rtl8185b_tx_enable(struct net_device *dev);
@@ -682,9 +623,8 @@ void rtl8185b_irq_enable(struct net_device *dev);
void fix_rx_fifo(struct net_device *dev);
void fix_tx_fifo(struct net_device *dev);
void rtl8225z2_SetTXPowerLevel(struct net_device *dev, short ch);
-void rtl8180_rate_adapter(struct work_struct * work);
-//#endif
-bool MgntActSet_RF_State(struct net_device *dev, RT_RF_POWER_STATE StateToSet,
+void rtl8180_rate_adapter(struct work_struct *work);
+bool MgntActSet_RF_State(struct net_device *dev, enum rt_rf_power_state StateToSet,
u32 ChangeSource);
#endif
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index 6cafee22bec4..a6022d4e7573 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -1,31 +1,31 @@
/*
- This is part of rtl818x pci OpenSource driver - v 0.1
- Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
- Released under the terms of GPL (General Public License)
-
- Parts of this driver are based on the GPL part of the official
- Realtek driver.
-
- Parts of this driver are based on the rtl8180 driver skeleton
- from Patric Schenke & Andres Salomon.
-
- Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
-
- Parts of BB/RF code are derived from David Young rtl8180 netbsd driver.
-
- RSSI calc function from 'The Deuce'
-
- Some ideas borrowed from the 8139too.c driver included in linux kernel.
-
- We (I?) want to thanks the Authors of those projecs and also the
- Ndiswrapper's project Authors.
-
- A big big thanks goes also to Realtek corp. for their help in my attempt to
- add RTL8185 and RTL8225 support, and to David Young also.
-
- Power management interface routines.
- Written by Mariusz Matuszek.
-*/
+ * This is part of rtl818x pci OpenSource driver - v 0.1
+ * Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
+ * Released under the terms of GPL (General Public License)
+ *
+ * Parts of this driver are based on the GPL part of the official
+ * Realtek driver.
+ *
+ * Parts of this driver are based on the rtl8180 driver skeleton
+ * from Patric Schenke & Andres Salomon.
+ *
+ * Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
+ *
+ * Parts of BB/RF code are derived from David Young rtl8180 netbsd driver.
+ *
+ * RSSI calc function from 'The Deuce'
+ *
+ * Some ideas borrowed from the 8139too.c driver included in linux kernel.
+ *
+ * We (I?) want to thanks the Authors of those projecs and also the
+ * Ndiswrapper's project Authors.
+ *
+ * A big big thanks goes also to Realtek corp. for their help in my attempt to
+ * add RTL8185 and RTL8225 support, and to David Young also.
+ *
+ * Power management interface routines.
+ * Written by Mariusz Matuszek.
+ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -258,7 +258,9 @@ static int proc_get_stats_tx(struct seq_file *m, void *v)
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
unsigned long totalOK;
- totalOK = priv->stats.txnpokint+priv->stats.txhpokint+priv->stats.txlpokint;
+ totalOK = priv->stats.txnpokint + priv->stats.txhpokint +
+ priv->stats.txlpokint;
+
seq_printf(m,
"TX OK: %lu\n"
"TX Error: %lu\n"
@@ -347,9 +349,9 @@ static void rtl8180_proc_init_one(struct net_device *dev)
}
/*
- FIXME: check if we can use some standard already-existent
- data type+functions in kernel
-*/
+ * FIXME: check if we can use some standard already-existent
+ * data type+functions in kernel.
+ */
static short buffer_add(struct buffer **buffer, u32 *buf, dma_addr_t dma,
struct buffer **bufferhead)
@@ -468,9 +470,11 @@ static short check_nic_enought_desc(struct net_device *dev, int priority)
{
struct r8180_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = netdev_priv(dev);
- int requiredbyte, required;
+ int requiredbyte;
+ int required;
- requiredbyte = priv->ieee80211->fts + sizeof(struct ieee80211_header_data);
+ requiredbyte = priv->ieee80211->fts +
+ sizeof(struct ieee80211_header_data);
if (ieee->current_network.QoS_Enable)
requiredbyte += 2;
@@ -484,7 +488,7 @@ static short check_nic_enought_desc(struct net_device *dev, int priority)
* between the tail and the head
*/
- return (required+2 < get_curr_tx_free_desc(dev, priority));
+ return required + 2 < get_curr_tx_free_desc(dev, priority);
}
void fix_tx_fifo(struct net_device *dev)
@@ -649,7 +653,7 @@ void rtl8180_set_chan(struct net_device *dev, short ch)
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
if ((ch > 14) || (ch < 1)) {
- printk("In %s: Invalid chnanel %d\n", __func__, ch);
+ netdev_err(dev, "In %s: Invalid channel %d\n", __func__, ch);
return;
}
@@ -742,43 +746,50 @@ static short alloc_tx_desc_ring(struct net_device *dev, int bufsize, int count,
switch (addr) {
case TX_MANAGEPRIORITY_RING_ADDR:
- if (-1 == buffer_add(&(priv->txmapbufs), buf, dma_tmp, NULL)) {
+ if (-1 == buffer_add(&priv->txmapbufs,
+ buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer NP");
return -ENOMEM;
}
break;
case TX_BKPRIORITY_RING_ADDR:
- if (-1 == buffer_add(&(priv->txbkpbufs), buf, dma_tmp, NULL)) {
+ if (-1 == buffer_add(&priv->txbkpbufs,
+ buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer LP");
return -ENOMEM;
}
break;
case TX_BEPRIORITY_RING_ADDR:
- if (-1 == buffer_add(&(priv->txbepbufs), buf, dma_tmp, NULL)) {
+ if (-1 == buffer_add(&priv->txbepbufs,
+ buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer NP");
return -ENOMEM;
}
break;
case TX_VIPRIORITY_RING_ADDR:
- if (-1 == buffer_add(&(priv->txvipbufs), buf, dma_tmp, NULL)) {
+ if (-1 == buffer_add(&priv->txvipbufs,
+ buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer LP");
return -ENOMEM;
}
break;
case TX_VOPRIORITY_RING_ADDR:
- if (-1 == buffer_add(&(priv->txvopbufs), buf, dma_tmp, NULL)) {
+ if (-1 == buffer_add(&priv->txvopbufs,
+ buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer NP");
return -ENOMEM;
}
break;
case TX_HIGHPRIORITY_RING_ADDR:
- if (-1 == buffer_add(&(priv->txhpbufs), buf, dma_tmp, NULL)) {
+ if (-1 == buffer_add(&priv->txhpbufs,
+ buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer HP");
return -ENOMEM;
}
break;
case TX_BEACON_RING_ADDR:
- if (-1 == buffer_add(&(priv->txbeaconbufs), buf, dma_tmp, NULL)) {
+ if (-1 == buffer_add(&priv->txbeaconbufs,
+ buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer BP");
return -ENOMEM;
}
@@ -897,8 +908,8 @@ static short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count)
return -1;
}
- desc = (u32 *)pci_alloc_consistent(pdev, sizeof(u32)*rx_desc_size*count+256,
- &dma_desc);
+ desc = (u32 *)pci_alloc_consistent(pdev,
+ sizeof(u32) * rx_desc_size * count + 256, &dma_desc);
if (dma_desc & 0xff)
/*
@@ -935,7 +946,8 @@ static short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count)
tmp = tmp+rx_desc_size;
}
- *(tmp-rx_desc_size) = *(tmp-rx_desc_size) | (1<<30); /* this is the last descriptor */
+ /* this is the last descriptor */
+ *(tmp - rx_desc_size) = *(tmp - rx_desc_size) | (1 << 30);
return 0;
}
@@ -1009,7 +1021,8 @@ inline u16 ieeerate2rtlrate(int rate)
}
}
-static u16 rtl_rate[] = {10, 20, 55, 110, 60, 90, 120, 180, 240, 360, 480, 540, 720};
+static u16 rtl_rate[] = {10, 20, 55, 110, 60,
+ 90, 120, 180, 240, 360, 480, 540, 720};
inline u16 rtl8180_rate2rate(short rate)
{
@@ -1143,23 +1156,30 @@ static long TranslateToDbm8185(u8 SignalStrengthIndex)
/*
* Perform signal smoothing for dynamic mechanism.
* This is different with PerformSignalSmoothing8185 in smoothing formula.
- * No dramatic adjustion is apply because dynamic mechanism need some degree
- * of correctness. Ported from 8187B.
+ * No dramatic adjustment is applied because dynamic mechanism need some
+ * degree of correctness. Ported from 8187B.
*/
static void PerformUndecoratedSignalSmoothing8185(struct r8180_priv *priv,
bool bCckRate)
{
- /* Determin the current packet is CCK rate. */
+ long smoothedSS;
+ long smoothedRx;
+
+ /* Determine the current packet is CCK rate. */
priv->bCurCCKPkt = bCckRate;
+ smoothedSS = priv->SignalStrength * 10;
+
if (priv->UndecoratedSmoothedSS >= 0)
- priv->UndecoratedSmoothedSS = ((priv->UndecoratedSmoothedSS * 5) +
- (priv->SignalStrength * 10)) / 6;
- else
- priv->UndecoratedSmoothedSS = priv->SignalStrength * 10;
+ smoothedSS = ((priv->UndecoratedSmoothedSS * 5) +
+ smoothedSS) / 6;
- priv->UndercorateSmoothedRxPower = ((priv->UndercorateSmoothedRxPower * 50) +
- (priv->RxPower * 11)) / 60;
+ priv->UndecoratedSmoothedSS = smoothedSS;
+
+ smoothedRx = ((priv->UndecoratedSmoothedRxPower * 50) +
+ (priv->RxPower * 11)) / 60;
+
+ priv->UndecoratedSmoothedRxPower = smoothedRx;
if (bCckRate)
priv->CurCCKRSSI = priv->RSSI;
@@ -1206,8 +1226,9 @@ static void rtl8180_rx(struct net_device *dev)
rx_desc_size = 8;
if ((*(priv->rxringtail)) & (1<<31)) {
- /* we have got an RX int, but the descriptor
- * we are pointing is empty */
+ /* we have got an RX int, but the descriptor. we are pointing
+ * is empty.
+ */
priv->stats.rxnodata++;
priv->ieee80211->stats.rx_errors++;
@@ -1216,7 +1237,8 @@ static void rtl8180_rx(struct net_device *dev)
tmp = priv->rxringtail;
do {
if (tmp == priv->rxring)
- tmp = priv->rxring + (priv->rxringcount - 1)*rx_desc_size;
+ tmp = priv->rxring + (priv->rxringcount - 1) *
+ rx_desc_size;
else
tmp -= rx_desc_size;
@@ -1237,7 +1259,6 @@ static void rtl8180_rx(struct net_device *dev)
if (*(priv->rxringtail) & (1<<27)) {
priv->stats.rxdmafail++;
- /* DMESG("EE: RX DMA FAILED at buffer pointed by descriptor %x",(u32)priv->rxringtail); */
goto drop;
}
@@ -1254,10 +1275,9 @@ static void rtl8180_rx(struct net_device *dev)
if (last) {
lastlen = ((*priv->rxringtail) & 0xfff);
- /* if the last descriptor (that should
- * tell us the total packet len) tell
- * us something less than the descriptors
- * len we had until now, then there is some
+ /* if the last descriptor (that should tell us the total
+ * packet len) tell us something less than the
+ * descriptors len we had until now, then there is some
* problem..
* workaround to prevent kernel panic
*/
@@ -1293,31 +1313,36 @@ static void rtl8180_rx(struct net_device *dev)
priv->rx_prevlen += len;
if (priv->rx_prevlen > MAX_FRAG_THRESHOLD + 100) {
- /* HW is probably passing several buggy frames
- * without FD or LD flag set.
- * Throw this garbage away to prevent skb
- * memory exhausting
- */
+ /* HW is probably passing several buggy frames without
+ * FD or LD flag set.
+ * Throw this garbage away to prevent skb memory
+ * exhausting
+ */
if (!priv->rx_skb_complete)
dev_kfree_skb_any(priv->rx_skb);
priv->rx_skb_complete = 1;
}
- signal = (unsigned char)(((*(priv->rxringtail+3)) & (0x00ff0000))>>16);
+ signal = (unsigned char)((*(priv->rxringtail + 3) &
+ 0x00ff0000) >> 16);
signal = (signal & 0xfe) >> 1;
quality = (unsigned char)((*(priv->rxringtail+3)) & (0xff));
stats.mac_time[0] = *(priv->rxringtail+1);
stats.mac_time[1] = *(priv->rxringtail+2);
- rxpower = ((char)(((*(priv->rxringtail+4)) & (0x00ff0000))>>16))/2 - 42;
- RSSI = ((u8)(((*(priv->rxringtail+3)) & (0x0000ff00))>>8)) & (0x7f);
+
+ rxpower = ((char)((*(priv->rxringtail + 4) &
+ 0x00ff0000) >> 16)) / 2 - 42;
+
+ RSSI = ((u8)((*(priv->rxringtail + 3) &
+ 0x0000ff00) >> 8)) & 0x7f;
rate = ((*(priv->rxringtail)) &
((1<<23)|(1<<22)|(1<<21)|(1<<20)))>>20;
stats.rate = rtl8180_rate2rate(rate);
- Antenna = (((*(priv->rxringtail+3)) & (0x00008000)) == 0) ? 0 : 1;
+ Antenna = (*(priv->rxringtail + 3) & 0x00008000) == 0 ? 0 : 1;
if (!rtl8180_IsWirelessBMode(stats.rate)) { /* OFDM rate. */
RxAGC_dBm = rxpower+1; /* bias */
} else { /* CCK rate. */
@@ -1326,7 +1351,8 @@ static void rtl8180_rx(struct net_device *dev)
LNA = (u8) (RxAGC_dBm & 0x60) >> 5; /* bit 6~ bit 5 */
BB = (u8) (RxAGC_dBm & 0x1F); /* bit 4 ~ bit 0 */
- RxAGC_dBm = -(LNA_gain[LNA] + (BB*2)); /* Pin_11b=-(LNA_gain+BB_gain) (dBm) */
+ /* Pin_11b=-(LNA_gain+BB_gain) (dBm) */
+ RxAGC_dBm = -(LNA_gain[LNA] + (BB * 2));
RxAGC_dBm += 4; /* bias */
}
@@ -1354,21 +1380,23 @@ static void rtl8180_rx(struct net_device *dev)
priv->RSSI = RSSI;
/* SQ translation formula is provided by SD3 DZ. 2006.06.27 */
if (quality >= 127)
- quality = 1; /*0; */ /* 0 will cause epc to show signal zero , walk around now; */
+ /* 0 causes epc to show signal zero, walk around now */
+ quality = 1;
else if (quality < 27)
quality = 100;
else
quality = 127 - quality;
priv->SignalQuality = quality;
- stats.signal = (u8)quality; /*priv->wstats.qual.level = priv->SignalStrength; */
+ stats.signal = (u8) quality;
+
stats.signalstrength = RXAGC;
if (stats.signalstrength > 100)
stats.signalstrength = 100;
- stats.signalstrength = (stats.signalstrength * 70)/100 + 30;
- /* printk("==========================>rx : RXAGC is %d,signalstrength is %d\n",RXAGC,stats.signalstrength); */
+ stats.signalstrength = (stats.signalstrength * 70) / 100 + 30;
stats.rssi = priv->wstats.qual.qual = priv->SignalQuality;
- stats.noise = priv->wstats.qual.noise = 100 - priv->wstats.qual.qual;
+ stats.noise = priv->wstats.qual.noise =
+ 100 - priv->wstats.qual.qual;
bHwError = (((*(priv->rxringtail)) & (0x00000fff)) == 4080) |
(((*(priv->rxringtail)) & (0x04000000)) != 0) |
(((*(priv->rxringtail)) & (0x08000000)) != 0) |
@@ -1397,27 +1425,40 @@ static void rtl8180_rx(struct net_device *dev)
/* For good-looking singal strength. */
SignalStrengthIndex = NetgearSignalStrengthTranslate(
- priv->LastSignalStrengthInPercent,
- priv->SignalStrength);
+ priv->LastSignalStrengthInPercent,
+ priv->SignalStrength);
priv->LastSignalStrengthInPercent = SignalStrengthIndex;
- priv->Stats_SignalStrength = TranslateToDbm8185((u8)SignalStrengthIndex);
- /*
- * We need more correct power of received packets and the "SignalStrength" of RxStats is beautified,
- * so we record the correct power here.
- */
- priv->Stats_SignalQuality = (long)(priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6;
- priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower - 1) / 6;
+ priv->Stats_SignalStrength =
+ TranslateToDbm8185((u8)SignalStrengthIndex);
+
+ /*
+ * We need more correct power of received packets and
+ * the "SignalStrength" of RxStats is beautified, so we
+ * record the correct power here.
+ */
- /* Figure out which antenna that received the last packet. */
- priv->LastRxPktAntenna = Antenna ? 1 : 0; /* 0: aux, 1: main. */
+ priv->Stats_SignalQuality = (long)(
+ priv->Stats_SignalQuality * 5 +
+ (long)priv->SignalQuality + 5) / 6;
+
+ priv->Stats_RecvSignalPower = (long)(
+ priv->Stats_RecvSignalPower * 5 +
+ priv->RecvSignalPower - 1) / 6;
+
+ /*
+ * Figure out which antenna received the last packet.
+ * 0: aux, 1: main
+ */
+ priv->LastRxPktAntenna = Antenna ? 1 : 0;
SwAntennaDiversityRxOk8185(dev, priv->SignalStrength);
}
if (first) {
if (!priv->rx_skb_complete) {
/* seems that HW sometimes fails to receive and
- doesn't provide the last descriptor */
+ * doesn't provide the last descriptor.
+ */
dev_kfree_skb_any(priv->rx_skb);
priv->stats.rxnolast++;
}
@@ -1428,15 +1469,16 @@ static void rtl8180_rx(struct net_device *dev)
priv->rx_skb_complete = 0;
priv->rx_skb->dev = dev;
} else {
- /* if we are here we should have already RXed
- * the first frame.
- * If we get here and the skb is not allocated then
- * we have just throw out garbage (skb not allocated)
- * and we are still rxing garbage....
- */
+ /* if we are here we should have already RXed the first
+ * frame.
+ * If we get here and the skb is not allocated then
+ * we have just throw out garbage (skb not allocated)
+ * and we are still rxing garbage....
+ */
if (!priv->rx_skb_complete) {
- tmp_skb = dev_alloc_skb(priv->rx_skb->len+len+2);
+ tmp_skb = dev_alloc_skb(
+ priv->rx_skb->len + len + 2);
if (!tmp_skb)
goto drop;
@@ -1454,13 +1496,8 @@ static void rtl8180_rx(struct net_device *dev)
}
if (!priv->rx_skb_complete) {
- if (padding) {
- memcpy(skb_put(priv->rx_skb, len),
- (((unsigned char *)priv->rxbuffer->buf) + 2), len);
- } else {
- memcpy(skb_put(priv->rx_skb, len),
- priv->rxbuffer->buf, len);
- }
+ memcpy(skb_put(priv->rx_skb, len), ((unsigned char *)
+ priv->rxbuffer->buf) + (padding ? 2 : 0), len);
}
if (last && !priv->rx_skb_complete) {
@@ -1538,8 +1575,8 @@ static void rtl8180_hard_data_xmit(struct sk_buff *skb, struct net_device *dev,
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
int mode;
- struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data;
- short morefrag = (h->frame_control) & IEEE80211_FCTL_MOREFRAGS;
+ struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *)skb->data;
+ bool morefrag = le16_to_cpu(h->frame_control) & IEEE80211_FCTL_MOREFRAGS;
unsigned long flags;
int priority;
@@ -1547,11 +1584,10 @@ static void rtl8180_hard_data_xmit(struct sk_buff *skb, struct net_device *dev,
rate = ieeerate2rtlrate(rate);
/*
- * This function doesn't require lock because we make
- * sure it's called with the tx_lock already acquired.
- * this come from the kernel's hard_xmit callback (through
- * the ieee stack, or from the try_wake_queue (again through
- * the ieee stack.
+ * This function doesn't require lock because we make sure it's called
+ * with the tx_lock already acquired.
+ * This come from the kernel's hard_xmit callback (through the ieee
+ * stack, or from the try_wake_queue (again through the ieee stack.
*/
priority = AC2Q(skb->priority);
spin_lock_irqsave(&priv->tx_lock, flags);
@@ -1613,55 +1649,6 @@ static int rtl8180_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
-/* longpre 144+48 shortpre 72+24 */
-u16 rtl8180_len2duration(u32 len, short rate, short *ext)
-{
- u16 duration;
- u16 drift;
- *ext = 0;
-
- switch (rate) {
- case 0: /* 1mbps */
- *ext = 0;
- duration = ((len+4)<<4) / 0x2;
- drift = ((len+4)<<4) % 0x2;
- if (drift == 0)
- break;
- duration++;
- break;
- case 1: /* 2mbps */
- *ext = 0;
- duration = ((len+4)<<4) / 0x4;
- drift = ((len+4)<<4) % 0x4;
- if (drift == 0)
- break;
- duration++;
- break;
- case 2: /* 5.5mbps */
- *ext = 0;
- duration = ((len+4)<<4) / 0xb;
- drift = ((len+4)<<4) % 0xb;
- if (drift == 0)
- break;
- duration++;
- break;
- default:
- case 3: /* 11mbps */
- *ext = 0;
- duration = ((len+4)<<4) / 0x16;
- drift = ((len+4)<<4) % 0x16;
- if (drift == 0)
- break;
- duration++;
- if (drift > 6)
- break;
- *ext = 1;
- break;
- }
-
- return duration;
-}
-
static void rtl8180_prepare_beacon(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
@@ -1669,7 +1656,10 @@ static void rtl8180_prepare_beacon(struct net_device *dev)
u16 word = read_nic_word(dev, BcnItv);
word &= ~BcnItv_BcnItv; /* clear Bcn_Itv */
- word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval); /* 0x64; */
+
+ /* word |= 0x64; */
+ word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval);
+
write_nic_word(dev, BcnItv, word);
skb = ieee80211_get_beacon(priv->ieee80211);
@@ -1681,12 +1671,12 @@ static void rtl8180_prepare_beacon(struct net_device *dev)
}
/*
- * This function do the real dirty work: it enqueues a TX command
- * descriptor in the ring buffer, copyes the frame in a TX buffer
- * and kicks the NIC to ensure it does the DMA transfer.
+ * This function do the real dirty work: it enqueues a TX command descriptor in
+ * the ring buffer, copyes the frame in a TX buffer and kicks the NIC to ensure
+ * it does the DMA transfer.
*/
short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority,
- short morefrag, short descfrag, int rate)
+ bool morefrag, short descfrag, int rate)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 *tail, *temp_tail;
@@ -1697,16 +1687,17 @@ short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority,
int buflen;
int count;
struct buffer *buflist;
- struct ieee80211_hdr_3addr *frag_hdr = (struct ieee80211_hdr_3addr *)txbuf;
+ struct ieee80211_hdr_3addr *frag_hdr =
+ (struct ieee80211_hdr_3addr *)txbuf;
u8 dest[ETH_ALEN];
- u8 bUseShortPreamble = 0;
- u8 bCTSEnable = 0;
- u8 bRTSEnable = 0;
- u16 Duration = 0;
- u16 RtsDur = 0;
- u16 ThisFrameTime = 0;
- u16 TxDescDuration = 0;
- bool ownbit_flag = false;
+ u8 bUseShortPreamble = 0;
+ u8 bCTSEnable = 0;
+ u8 bRTSEnable = 0;
+ u16 Duration = 0;
+ u16 RtsDur = 0;
+ u16 ThisFrameTime = 0;
+ u16 TxDescDuration = 0;
+ bool ownbit_flag = false;
switch (priority) {
case MANAGE_PRIORITY:
@@ -1756,74 +1747,79 @@ short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority,
break;
}
- memcpy(&dest, frag_hdr->addr1, ETH_ALEN);
- if (is_multicast_ether_addr(dest)) {
- Duration = 0;
- RtsDur = 0;
- bRTSEnable = 0;
+ memcpy(&dest, frag_hdr->addr1, ETH_ALEN);
+ if (is_multicast_ether_addr(dest)) {
+ Duration = 0;
+ RtsDur = 0;
+ bRTSEnable = 0;
+ bCTSEnable = 0;
+
+ ThisFrameTime = ComputeTxTime(len + sCrcLng,
+ rtl8180_rate2rate(rate), 0, bUseShortPreamble);
+ TxDescDuration = ThisFrameTime;
+ } else { /* Unicast packet */
+ u16 AckTime;
+
+ /* for Keep alive */
+ priv->NumTxUnicast++;
+
+ /* Figure out ACK rate according to BSS basic rate
+ * and Tx rate.
+ * AckCTSLng = 14 use 1M bps send
+ */
+ AckTime = ComputeTxTime(14, 10, 0, 0);
+
+ if (((len + sCrcLng) > priv->rts) && priv->rts) { /* RTS/CTS. */
+ u16 RtsTime, CtsTime;
+ bRTSEnable = 1;
bCTSEnable = 0;
- ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate),
- 0, bUseShortPreamble);
- TxDescDuration = ThisFrameTime;
- } else { /* Unicast packet */
- u16 AckTime;
-
- /* YJ,add,080828,for Keep alive */
- priv->NumTxUnicast++;
-
- /* Figure out ACK rate according to BSS basic rate
- * and Tx rate. */
- AckTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */
-
- if (((len + sCrcLng) > priv->rts) && priv->rts) { /* RTS/CTS. */
- u16 RtsTime, CtsTime;
- /* u16 CtsRate; */
- bRTSEnable = 1;
- bCTSEnable = 0;
-
- /* Rate and time required for RTS. */
- RtsTime = ComputeTxTime(sAckCtsLng/8, priv->ieee80211->basic_rate, 0, 0);
- /* Rate and time required for CTS. */
- CtsTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */
-
- /* Figure out time required to transmit this frame. */
- ThisFrameTime = ComputeTxTime(len + sCrcLng,
- rtl8180_rate2rate(rate),
- 0,
- bUseShortPreamble);
-
- /* RTS-CTS-ThisFrame-ACK. */
- RtsDur = CtsTime + ThisFrameTime + AckTime + 3*aSifsTime;
-
- TxDescDuration = RtsTime + RtsDur;
- } else { /* Normal case. */
- bCTSEnable = 0;
- bRTSEnable = 0;
- RtsDur = 0;
-
- ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate),
- 0, bUseShortPreamble);
- TxDescDuration = ThisFrameTime + aSifsTime + AckTime;
- }
+ /* Rate and time required for RTS. */
+ RtsTime = ComputeTxTime(sAckCtsLng / 8,
+ priv->ieee80211->basic_rate, 0, 0);
- if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) {
- /* ThisFrame-ACK. */
- Duration = aSifsTime + AckTime;
- } else { /* One or more fragments remained. */
- u16 NextFragTime;
- NextFragTime = ComputeTxTime(len + sCrcLng, /* pretend following packet length equal current packet */
- rtl8180_rate2rate(rate),
- 0,
- bUseShortPreamble);
-
- /* ThisFrag-ACk-NextFrag-ACK. */
- Duration = NextFragTime + 3*aSifsTime + 2*AckTime;
- }
+ /* Rate and time required for CTS.
+ * AckCTSLng = 14 use 1M bps send
+ */
+ CtsTime = ComputeTxTime(14, 10, 0, 0);
+
+ /* Figure out time required to transmit this frame. */
+ ThisFrameTime = ComputeTxTime(len + sCrcLng,
+ rtl8180_rate2rate(rate), 0,
+ bUseShortPreamble);
+
+ /* RTS-CTS-ThisFrame-ACK. */
+ RtsDur = CtsTime + ThisFrameTime +
+ AckTime + 3 * aSifsTime;
+
+ TxDescDuration = RtsTime + RtsDur;
+ } else { /* Normal case. */
+ bCTSEnable = 0;
+ bRTSEnable = 0;
+ RtsDur = 0;
- } /* End of Unicast packet */
+ ThisFrameTime = ComputeTxTime(len + sCrcLng,
+ rtl8180_rate2rate(rate), 0, bUseShortPreamble);
+ TxDescDuration = ThisFrameTime + aSifsTime + AckTime;
+ }
+
+ if (!(le16_to_cpu(frag_hdr->frame_control) & IEEE80211_FCTL_MOREFRAGS)) {
+ /* ThisFrame-ACK. */
+ Duration = aSifsTime + AckTime;
+ } else { /* One or more fragments remained. */
+ u16 NextFragTime;
+
+ /* pretend following packet length = current packet */
+ NextFragTime = ComputeTxTime(len + sCrcLng,
+ rtl8180_rate2rate(rate), 0, bUseShortPreamble);
+
+ /* ThisFrag-ACk-NextFrag-ACK. */
+ Duration = NextFragTime + 3 * aSifsTime + 2 * AckTime;
+ }
+
+ } /* End of Unicast packet */
- frag_hdr->duration_id = Duration;
+ frag_hdr->duration_id = Duration;
buflen = priv->txbuffsize;
remain = len;
@@ -1832,7 +1828,8 @@ short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority,
while (remain != 0) {
mb();
if (!buflist) {
- DMESGE("TX buffer error, cannot TX frames. pri %d.", priority);
+ DMESGE("TX buffer error, cannot TX frames. pri %d.",
+ priority);
return -1;
}
buf = buflist->buf;
@@ -1851,43 +1848,43 @@ short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority,
*(tail+6) = 0;
*(tail+7) = 0;
- /* FIXME: this should be triggered by HW encryption parameters.*/
+ /* FIXME: should be triggered by HW encryption parameters.*/
*tail |= (1<<15); /* no encrypt */
if (remain == len && !descfrag) {
ownbit_flag = false;
- *tail = *tail | (1<<29); /* fist segment of the packet */
+ *tail = *tail | (1 << 29); /* first segment of packet */
*tail = *tail | (len);
} else {
ownbit_flag = true;
}
for (i = 0; i < buflen && remain > 0; i++, remain--) {
- ((u8 *)buf)[i] = txbuf[i]; /* copy data into descriptor pointed DMAble buffer */
+ /* copy data into descriptor pointed DMAble buffer */
+ ((u8 *)buf)[i] = txbuf[i];
+
if (remain == 4 && i+4 >= buflen)
break;
/* ensure the last desc has at least 4 bytes payload */
-
}
txbuf = txbuf + i;
*(tail+3) = *(tail+3) & ~0xfff;
*(tail+3) = *(tail+3) | i; /* buffer length */
- /* Use short preamble or not */
- if (priv->ieee80211->current_network.capability&WLAN_CAPABILITY_SHORT_PREAMBLE)
- if (priv->plcp_preamble_mode == 1 && rate != 0) /* short mode now, not long! */
- ; /* *tail |= (1<<16); */ /* enable short preamble mode. */
if (bCTSEnable)
*tail |= (1<<18);
if (bRTSEnable) { /* rts enable */
- *tail |= ((ieeerate2rtlrate(priv->ieee80211->basic_rate))<<19); /* RTS RATE */
+ /* RTS RATE */
+ *tail |= (ieeerate2rtlrate(
+ priv->ieee80211->basic_rate) << 19);
+
*tail |= (1<<23); /* rts enable */
*(tail+1) |= (RtsDur&0xffff); /* RTS Duration */
}
*(tail+3) |= ((TxDescDuration&0xffff)<<16); /* DURATION */
- /* *(tail+3) |= (0xe6<<16); */
- *(tail+5) |= (11<<8); /* (priv->retry_data<<8); */ /* retry lim; */
+
+ *(tail + 5) |= (11 << 8); /* retry lim; */
*tail = *tail | ((rate&0xf) << 24);
@@ -1901,7 +1898,8 @@ short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority,
wmb();
if (ownbit_flag)
- *tail = *tail | (1<<31); /* descriptor ready to be txed */
+ /* descriptor ready to be txed */
+ *tail |= (1 << 31);
if ((tail - begin)/8 == count-1)
tail = begin;
@@ -1983,7 +1981,8 @@ static void rtl8180_rq_tx_ack(struct net_device *dev)
struct r8180_priv *priv = ieee80211_priv(dev);
- write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) | CONFIG4_PWRMGT);
+ write_nic_byte(dev, CONFIG4,
+ read_nic_byte(dev, CONFIG4) | CONFIG4_PWRMGT);
priv->ack_tx_to_ieee = 1;
}
@@ -2031,7 +2030,8 @@ static void rtl8180_hw_wakeup(struct net_device *dev)
struct r8180_priv *priv = ieee80211_priv(dev);
spin_lock_irqsave(&priv->ps_lock, flags);
- write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) & ~CONFIG4_PWRMGT);
+ write_nic_byte(dev, CONFIG4,
+ read_nic_byte(dev, CONFIG4) & ~CONFIG4_PWRMGT);
if (priv->rf_wakeup)
priv->rf_wakeup(dev);
spin_unlock_irqrestore(&priv->ps_lock, flags);
@@ -2063,13 +2063,13 @@ static void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl)
tl -= MSECS(4+16+7);
/*
- * If the interval in witch we are requested to sleep is too
+ * If the interval in which we are requested to sleep is too
* short then give up and remain awake
*/
if (((tl >= rb) && (tl-rb) <= MSECS(MIN_SLEEP_TIME))
|| ((rb > tl) && (rb-tl) < MSECS(MIN_SLEEP_TIME))) {
spin_unlock_irqrestore(&priv->ps_lock, flags);
- printk("too short to sleep\n");
+ netdev_warn(dev, "too short to sleep\n");
return;
}
@@ -2078,7 +2078,8 @@ static void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl)
priv->DozePeriodInPast2Sec += jiffies_to_msecs(tmp);
/* as tl may be less than rb */
- queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp);
+ queue_delayed_work(priv->ieee80211->wq,
+ &priv->ieee80211->hw_wakeup_wq, tmp);
}
/*
* If we suspect the TimerInt is gone beyond tl
@@ -2095,16 +2096,49 @@ static void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl)
spin_unlock_irqrestore(&priv->ps_lock, flags);
}
+static void rtl8180_wmm_single_param_update(struct net_device *dev,
+ u8 mode, AC_CODING eACI, PAC_PARAM param)
+{
+ u8 u1bAIFS;
+ u32 u4bAcParam;
+
+ /* Retrieve parameters to update. */
+ /* Mode G/A: slotTimeTimer = 9; Mode B: 20 */
+ u1bAIFS = param->f.AciAifsn.f.AIFSN * ((mode & IEEE_G) == IEEE_G ?
+ 9 : 20) + aSifsTime;
+ u4bAcParam = (((u32)param->f.TXOPLimit << AC_PARAM_TXOP_LIMIT_OFFSET) |
+ ((u32)param->f.Ecw.f.ECWmax << AC_PARAM_ECW_MAX_OFFSET) |
+ ((u32)param->f.Ecw.f.ECWmin << AC_PARAM_ECW_MIN_OFFSET) |
+ ((u32)u1bAIFS << AC_PARAM_AIFS_OFFSET));
+
+ switch (eACI) {
+ case AC1_BK:
+ write_nic_dword(dev, AC_BK_PARAM, u4bAcParam);
+ return;
+ case AC0_BE:
+ write_nic_dword(dev, AC_BE_PARAM, u4bAcParam);
+ return;
+ case AC2_VI:
+ write_nic_dword(dev, AC_VI_PARAM, u4bAcParam);
+ return;
+ case AC3_VO:
+ write_nic_dword(dev, AC_VO_PARAM, u4bAcParam);
+ return;
+ default:
+ pr_warn("SetHwReg8185(): invalid ACI: %d!\n", eACI);
+ return;
+ }
+}
+
static void rtl8180_wmm_param_update(struct work_struct *work)
{
- struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wmm_param_update_wq);
+ struct ieee80211_device *ieee = container_of(work,
+ struct ieee80211_device, wmm_param_update_wq);
struct net_device *dev = ieee->dev;
u8 *ac_param = (u8 *)(ieee->current_network.wmm_param);
u8 mode = ieee->current_network.mode;
- AC_CODING eACI;
- AC_PARAM AcParam;
- PAC_PARAM pAcParam;
- u8 i;
+ AC_CODING eACI;
+ AC_PARAM AcParam;
if (!ieee->current_network.QoS_Enable) {
/* legacy ac_xx_param update */
@@ -2114,83 +2148,26 @@ static void rtl8180_wmm_param_update(struct work_struct *work)
AcParam.f.Ecw.f.ECWmin = 3; /* Follow 802.11 CWmin. */
AcParam.f.Ecw.f.ECWmax = 7; /* Follow 802.11 CWmax. */
AcParam.f.TXOPLimit = 0;
+
for (eACI = 0; eACI < AC_MAX; eACI++) {
AcParam.f.AciAifsn.f.ACI = (u8)eACI;
- {
- u8 u1bAIFS;
- u32 u4bAcParam;
- pAcParam = (PAC_PARAM)(&AcParam);
- /* Retrieve parameters to update. */
- u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
- u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)|
- (((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)|
- (((u32)(pAcParam->f.Ecw.f.ECWmin))<<AC_PARAM_ECW_MIN_OFFSET)|
- (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
- switch (eACI) {
- case AC1_BK:
- write_nic_dword(dev, AC_BK_PARAM, u4bAcParam);
- break;
- case AC0_BE:
- write_nic_dword(dev, AC_BE_PARAM, u4bAcParam);
- break;
- case AC2_VI:
- write_nic_dword(dev, AC_VI_PARAM, u4bAcParam);
- break;
- case AC3_VO:
- write_nic_dword(dev, AC_VO_PARAM, u4bAcParam);
- break;
- default:
- pr_warn("SetHwReg8185():invalid ACI: %d!\n",
- eACI);
- break;
- }
- }
+
+ rtl8180_wmm_single_param_update(dev, mode, eACI,
+ (PAC_PARAM)&AcParam);
}
return;
}
- for (i = 0; i < AC_MAX; i++) {
- /* AcParam.longData = 0; */
- pAcParam = (AC_PARAM *)ac_param;
- {
- AC_CODING eACI;
- u8 u1bAIFS;
- u32 u4bAcParam;
-
- /* Retrieve parameters to update. */
- eACI = pAcParam->f.AciAifsn.f.ACI;
- /* Mode G/A: slotTimeTimer = 9; Mode B: 20 */
- u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
- u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) |
- (((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) |
- (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) |
- (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
-
- switch (eACI) {
- case AC1_BK:
- write_nic_dword(dev, AC_BK_PARAM, u4bAcParam);
- break;
- case AC0_BE:
- write_nic_dword(dev, AC_BE_PARAM, u4bAcParam);
- break;
- case AC2_VI:
- write_nic_dword(dev, AC_VI_PARAM, u4bAcParam);
- break;
- case AC3_VO:
- write_nic_dword(dev, AC_VO_PARAM, u4bAcParam);
- break;
- default:
- pr_warn("SetHwReg8185(): invalid ACI: %d !\n",
- eACI);
- break;
- }
- }
- ac_param += (sizeof(AC_PARAM));
+ for (eACI = 0; eACI < AC_MAX; eACI++) {
+ rtl8180_wmm_single_param_update(dev, mode,
+ ((PAC_PARAM)ac_param)->f.AciAifsn.f.ACI,
+ (PAC_PARAM)ac_param);
+
+ ac_param += sizeof(AC_PARAM);
}
}
void rtl8180_restart_wq(struct work_struct *work);
-/* void rtl8180_rq_tx_ack(struct work_struct *work); */
void rtl8180_watch_dog_wq(struct work_struct *work);
void rtl8180_hw_wakeup_wq(struct work_struct *work);
void rtl8180_hw_sleep_wq(struct work_struct *work);
@@ -2208,7 +2185,8 @@ static void watch_dog_adaptive(unsigned long data)
/* Tx High Power Mechanism. */
if (CheckHighPower((struct net_device *)data))
- queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->tx_pw_wq);
+ queue_work(priv->ieee80211->wq,
+ (void *)&priv->ieee80211->tx_pw_wq);
/* Tx Power Tracking on 87SE. */
if (CheckTxPwrTracking((struct net_device *)data))
@@ -2216,27 +2194,59 @@ static void watch_dog_adaptive(unsigned long data)
/* Perform DIG immediately. */
if (CheckDig((struct net_device *)data))
- queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_dig_wq);
+ queue_work(priv->ieee80211->wq,
+ (void *)&priv->ieee80211->hw_dig_wq);
+
rtl8180_watch_dog((struct net_device *)data);
- queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->GPIOChangeRFWorkItem);
+ queue_work(priv->ieee80211->wq,
+ (void *)&priv->ieee80211->GPIOChangeRFWorkItem);
+
+ priv->watch_dog_timer.expires = jiffies +
+ MSECS(IEEE80211_WATCH_DOG_TIME);
- priv->watch_dog_timer.expires = jiffies + MSECS(IEEE80211_WATCH_DOG_TIME);
add_timer(&priv->watch_dog_timer);
}
-static CHANNEL_LIST ChannelPlan[] = {
- {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, /* FCC */
- {{1,2,3,4,5,6,7,8,9,10,11},11}, /* IC */
- {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* ETSI */
- {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* Spain. Change to ETSI. */
- {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* France. Change to ETSI. */
- {{14,36,40,44,48,52,56,60,64},9}, /* MKK */
- {{1,2,3,4,5,6,7,8,9,10,11,12,13,14, 36,40,44,48,52,56,60,64},22},/* MKK1 */
- {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* Israel. */
- {{1,2,3,4,5,6,7,8,9,10,11,12,13,34,38,42,46},17}, /* For 11a , TELEC */
- {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14}, /* For Global Domain. 1-11:active scan, 12-14 passive scan. //+YJ, 080626 */
- {{1,2,3,4,5,6,7,8,9,10,11,12,13},13} /* world wide 13: ch1~ch11 active scan, ch12~13 passive //lzm add 080826 */
+static struct rtl8187se_channel_list channel_plan_list[] = {
+ /* FCC */
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40,
+ 44, 48, 52, 56, 60, 64}, 19},
+
+ /* IC */
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11},
+
+ /* ETSI */
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40,
+ 44, 48, 52, 56, 60, 64}, 21},
+
+ /* Spain. Change to ETSI. */
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40,
+ 44, 48, 52, 56, 60, 64}, 21},
+
+ /* France. Change to ETSI. */
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40,
+ 44, 48, 52, 56, 60, 64}, 21},
+
+ /* MKK */
+ {{14, 36, 40, 44, 48, 52, 56, 60, 64}, 9},
+
+ /* MKK1 */
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36,
+ 40, 44, 48, 52, 56, 60, 64}, 22},
+
+ /* Israel. */
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40,
+ 44, 48, 52, 56, 60, 64}, 21},
+
+ /* For 11a , TELEC */
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 34, 38, 42, 46}, 17},
+
+ /* For Global Domain. 1-11 active, 12-14 passive. */
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14},
+
+ /* world wide 13: ch1~ch11 active, ch12~13 passive */
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}
};
static void rtl8180_set_channel_map(u8 channel_plan,
@@ -2244,7 +2254,6 @@ static void rtl8180_set_channel_map(u8 channel_plan,
{
int i;
- /* lzm add 080826 */
ieee->MinPassiveChnlNum = MAX_CHANNEL_NUMBER+1;
ieee->IbssStartChnl = 0;
@@ -2261,13 +2270,13 @@ static void rtl8180_set_channel_map(u8 channel_plan,
{
Dot11d_Init(ieee);
ieee->bGlobalDomain = false;
- if (ChannelPlan[channel_plan].Len != 0) {
+ if (channel_plan_list[channel_plan].len != 0) {
/* Clear old channel map */
memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
/* Set new channel map */
- for (i = 0; i < ChannelPlan[channel_plan].Len; i++) {
- if (ChannelPlan[channel_plan].Channel[i] <= 14)
- GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1;
+ for (i = 0; i < channel_plan_list[channel_plan].len; i++) {
+ if (channel_plan_list[channel_plan].channel[i] <= 14)
+ GET_DOT11D_INFO(ieee)->channel_map[channel_plan_list[channel_plan].channel[i]] = 1;
}
}
break;
@@ -2279,7 +2288,7 @@ static void rtl8180_set_channel_map(u8 channel_plan,
ieee->bGlobalDomain = true;
break;
}
- case COUNTRY_CODE_WORLD_WIDE_13_INDEX:/* lzm add 080826 */
+ case COUNTRY_CODE_WORLD_WIDE_13_INDEX:
{
ieee->MinPassiveChnlNum = 12;
ieee->IbssStartChnl = 10;
@@ -2299,19 +2308,17 @@ static void rtl8180_set_channel_map(u8 channel_plan,
void GPIOChangeRFWorkItemCallBack(struct work_struct *work);
-/* YJ,add,080828 */
-static void rtl8180_statistics_init(struct Stats *pstats)
+static void rtl8180_statistics_init(struct stats *pstats)
{
- memset(pstats, 0, sizeof(struct Stats));
+ memset(pstats, 0, sizeof(struct stats));
}
-static void rtl8180_link_detect_init(plink_detect_t plink_detect)
+static void rtl8180_link_detect_init(struct link_detect_t *plink_detect)
{
- memset(plink_detect, 0, sizeof(link_detect_t));
- plink_detect->SlotNum = DEFAULT_SLOT_NUM;
+ memset(plink_detect, 0, sizeof(struct link_detect_t));
+ plink_detect->slot_num = DEFAULT_SLOT_NUM;
}
-/* YJ,add,080828,end */
static void rtl8187se_eeprom_register_read(struct eeprom_93cx6 *eeprom)
{
struct net_device *dev = eeprom->data;
@@ -2360,7 +2367,7 @@ static short rtl8180_init(struct net_device *dev)
eeprom_93cx6_read(&eeprom, EEPROM_COUNTRY_CODE>>1, &eeprom_val);
priv->channel_plan = eeprom_val & 0xFF;
if (priv->channel_plan > COUNTRY_CODE_GLOBAL_DOMAIN) {
- printk("rtl8180_init:Error channel plan! Set to default.\n");
+ netdev_err(dev, "rtl8180_init: Invalid channel plan! Set to default.\n");
priv->channel_plan = 0;
}
@@ -2385,7 +2392,8 @@ static short rtl8180_init(struct net_device *dev)
rtl8180_link_detect_init(&priv->link_detect);
priv->ack_tx_to_ieee = 0;
- priv->ieee80211->current_network.beacon_interval = DEFAULT_BEACONINTERVAL;
+ priv->ieee80211->current_network.beacon_interval =
+ DEFAULT_BEACONINTERVAL;
priv->ieee80211->iw_mode = IW_MODE_INFRA;
priv->ieee80211->softmac_features = IEEE_SOFTMAC_SCAN |
IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ |
@@ -2410,12 +2418,12 @@ static short rtl8180_init(struct net_device *dev)
priv->bInactivePs = true; /* false; */
priv->ieee80211->bInactivePs = priv->bInactivePs;
priv->bSwRfProcessing = false;
- priv->eRFPowerState = eRfOff;
+ priv->eRFPowerState = RF_OFF;
priv->RfOffReason = 0;
- priv->LedStrategy = SW_LED_MODE0;
- priv->TxPollingTimes = 0; /* lzm add 080826 */
+ priv->led_strategy = SW_LED_MODE0;
+ priv->TxPollingTimes = 0;
priv->bLeisurePs = true;
- priv->dot11PowerSaveMode = eActive;
+ priv->dot11PowerSaveMode = ACTIVE;
priv->AdMinCheckPeriod = 5;
priv->AdMaxCheckPeriod = 10;
priv->AdMaxRxSsThreshold = 30; /* 60->30 */
@@ -2431,7 +2439,8 @@ static short rtl8180_init(struct net_device *dev)
priv->AdRxSsBeforeSwitched = 0;
init_timer(&priv->SwAntennaDiversityTimer);
priv->SwAntennaDiversityTimer.data = (unsigned long)dev;
- priv->SwAntennaDiversityTimer.function = (void *)SwAntennaDiversityTimerCallback;
+ priv->SwAntennaDiversityTimer.function =
+ (void *)SwAntennaDiversityTimerCallback;
priv->bDigMechanism = true;
priv->InitialGain = 6;
priv->bXtalCalibration = false;
@@ -2440,7 +2449,8 @@ static short rtl8180_init(struct net_device *dev)
priv->bTxPowerTrack = false;
priv->ThermalMeter = 0;
priv->FalseAlarmRegValue = 0;
- priv->RegDigOfdmFaUpTh = 0xc; /* Upper threshold of OFDM false alarm, which is used in DIG. */
+ priv->RegDigOfdmFaUpTh = 0xc; /* Upper threshold of OFDM false alarm,
+ which is used in DIG. */
priv->DIG_NumberFallbackVote = 0;
priv->DIG_NumberUpgradeVote = 0;
priv->LastSignalStrengthInPercent = 0;
@@ -2585,7 +2595,8 @@ static short rtl8180_init(struct net_device *dev)
priv->bSwAntennaDiverity = priv->EEPROMSwAntennaDiversity;
else
/* 1:disable antenna diversity, 2: enable antenna diversity. */
- priv->bSwAntennaDiverity = priv->RegSwAntennaDiversityMechanism == 2;
+ priv->bSwAntennaDiverity =
+ priv->RegSwAntennaDiversityMechanism == 2;
if (priv->RegDefaultAntenna == 0)
/* 0: default from EEPROM. */
@@ -2669,7 +2680,8 @@ static short rtl8180_init(struct net_device *dev)
TX_BEACON_RING_ADDR))
return -ENOMEM;
- if (request_irq(dev->irq, rtl8180_interrupt, IRQF_SHARED, dev->name, dev)) {
+ if (request_irq(dev->irq, rtl8180_interrupt,
+ IRQF_SHARED, dev->name, dev)) {
DMESGE("Error allocating IRQ %d", dev->irq);
return -1;
} else {
@@ -2718,8 +2730,6 @@ void rtl8180_set_hw_wep(struct net_device *dev)
void rtl8185_rf_pins_enable(struct net_device *dev)
{
- /* u16 tmp; */
- /* tmp = read_nic_word(dev, RFPinsEnable); */
write_nic_word(dev, RFPinsEnable, 0x1fff); /* | tmp); */
}
@@ -2768,16 +2778,11 @@ static void rtl8185_write_phy(struct net_device *dev, u8 adr, u32 data)
phyw = ((data<<8) | adr);
- /* Note that, we must write 0xff7c after 0x7d-0x7f to write BB register. */
+ /* Note: we must write 0xff7c after 0x7d-0x7f to write BB register. */
write_nic_byte(dev, 0x7f, ((phyw & 0xff000000) >> 24));
write_nic_byte(dev, 0x7e, ((phyw & 0x00ff0000) >> 16));
write_nic_byte(dev, 0x7d, ((phyw & 0x0000ff00) >> 8));
write_nic_byte(dev, 0x7c, ((phyw & 0x000000ff)));
-
- /* this is ok to fail when we write AGC table. check for AGC table might be
- * done by masking with 0x7f instead of 0xff
- */
- /* if (phyr != (data&0xff)) DMESGW("Phy write timeout %x %x %x", phyr, data, adr); */
}
inline void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data)
@@ -2812,9 +2817,9 @@ void rtl8180_start_tx_beacon(struct net_device *dev)
word = read_nic_word(dev, BintrItv);
word &= ~BintrItv_BintrItv;
word |= 1000; /* priv->ieee80211->current_network.beacon_interval *
- ((priv->txbeaconcount > 1)?(priv->txbeaconcount-1):1);
- // FIXME: check if correct ^^ worked with 0x3e8;
- */
+ * ((priv->txbeaconcount > 1)?(priv->txbeaconcount-1):1);
+ * FIXME: check if correct ^^ worked with 0x3e8;
+ */
write_nic_word(dev, BintrItv, word);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
@@ -2833,7 +2838,7 @@ static struct net_device_stats *rtl8180_stats(struct net_device *dev)
* Change current and default preamble mode.
*/
static bool MgntActSet_802_11_PowerSaveMode(struct r8180_priv *priv,
- RT_PS_MODE rtPsMode)
+ enum rt_ps_mode rtPsMode)
{
/* Currently, we do not change power save mode on IBSS mode. */
if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
@@ -2846,25 +2851,26 @@ static bool MgntActSet_802_11_PowerSaveMode(struct r8180_priv *priv,
static void LeisurePSEnter(struct r8180_priv *priv)
{
- if (priv->bLeisurePs) {
+ if (priv->bLeisurePs)
if (priv->ieee80211->ps == IEEE80211_PS_DISABLED)
/* IEEE80211_PS_ENABLE */
- MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST);
- }
+ MgntActSet_802_11_PowerSaveMode(priv,
+ IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST);
}
static void LeisurePSLeave(struct r8180_priv *priv)
{
- if (priv->bLeisurePs) {
+ if (priv->bLeisurePs)
if (priv->ieee80211->ps != IEEE80211_PS_DISABLED)
- MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_DISABLED);
- }
+ MgntActSet_802_11_PowerSaveMode(
+ priv, IEEE80211_PS_DISABLED);
}
void rtl8180_hw_wakeup_wq(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
- struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, hw_wakeup_wq);
+ struct ieee80211_device *ieee = container_of(
+ dwork, struct ieee80211_device, hw_wakeup_wq);
struct net_device *dev = ieee->dev;
rtl8180_hw_wakeup(dev);
@@ -2873,7 +2879,8 @@ void rtl8180_hw_wakeup_wq(struct work_struct *work)
void rtl8180_hw_sleep_wq(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
- struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, hw_sleep_wq);
+ struct ieee80211_device *ieee = container_of(
+ dwork, struct ieee80211_device, hw_sleep_wq);
struct net_device *dev = ieee->dev;
rtl8180_hw_sleep_down(dev);
@@ -2890,23 +2897,30 @@ static void MgntLinkKeepAlive(struct r8180_priv *priv)
*/
if ((priv->keepAliveLevel == 2) ||
- (priv->link_detect.LastNumTxUnicast == priv->NumTxUnicast &&
- priv->link_detect.LastNumRxUnicast == priv->ieee80211->NumRxUnicast)
+ (priv->link_detect.last_num_tx_unicast ==
+ priv->NumTxUnicast &&
+ priv->link_detect.last_num_rx_unicast ==
+ priv->ieee80211->NumRxUnicast)
) {
- priv->link_detect.IdleCount++;
+ priv->link_detect.idle_count++;
/*
- * Send a Keep-Alive packet packet to AP if we had been idle for a while.
+ * Send a Keep-Alive packet packet to AP if we had
+ * been idle for a while.
*/
- if (priv->link_detect.IdleCount >= ((KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD)-1)) {
- priv->link_detect.IdleCount = 0;
- ieee80211_sta_ps_send_null_frame(priv->ieee80211, false);
+ if (priv->link_detect.idle_count >=
+ KEEP_ALIVE_INTERVAL /
+ CHECK_FOR_HANG_PERIOD - 1) {
+ priv->link_detect.idle_count = 0;
+ ieee80211_sta_ps_send_null_frame(
+ priv->ieee80211, false);
}
} else {
- priv->link_detect.IdleCount = 0;
+ priv->link_detect.idle_count = 0;
}
- priv->link_detect.LastNumTxUnicast = priv->NumTxUnicast;
- priv->link_detect.LastNumRxUnicast = priv->ieee80211->NumRxUnicast;
+ priv->link_detect.last_num_tx_unicast = priv->NumTxUnicast;
+ priv->link_detect.last_num_rx_unicast =
+ priv->ieee80211->NumRxUnicast;
}
}
@@ -2922,36 +2936,42 @@ void rtl8180_watch_dog(struct net_device *dev)
if ((priv->ieee80211->iw_mode != IW_MODE_ADHOC) &&
(priv->ieee80211->state == IEEE80211_NOLINK) &&
(priv->ieee80211->beinretry == false) &&
- (priv->eRFPowerState == eRfOn))
+ (priv->eRFPowerState == RF_ON))
IPSEnter(dev);
}
- /* YJ,add,080828,for link state check */
- if ((priv->ieee80211->state == IEEE80211_LINKED) && (priv->ieee80211->iw_mode == IW_MODE_INFRA)) {
- SlotIndex = (priv->link_detect.SlotIndex++) % priv->link_detect.SlotNum;
- priv->link_detect.RxFrameNum[SlotIndex] = priv->ieee80211->NumRxDataInPeriod + priv->ieee80211->NumRxBcnInPeriod;
- for (i = 0; i < priv->link_detect.SlotNum; i++)
- TotalRxNum += priv->link_detect.RxFrameNum[i];
+ if ((priv->ieee80211->state == IEEE80211_LINKED) &&
+ (priv->ieee80211->iw_mode == IW_MODE_INFRA)) {
+ SlotIndex = (priv->link_detect.slot_index++) %
+ priv->link_detect.slot_num;
+
+ priv->link_detect.rx_frame_num[SlotIndex] =
+ priv->ieee80211->NumRxDataInPeriod +
+ priv->ieee80211->NumRxBcnInPeriod;
+
+ for (i = 0; i < priv->link_detect.slot_num; i++)
+ TotalRxNum += priv->link_detect.rx_frame_num[i];
if (TotalRxNum == 0) {
priv->ieee80211->state = IEEE80211_ASSOCIATING;
- queue_work(priv->ieee80211->wq, &priv->ieee80211->associate_procedure_wq);
+ queue_work(priv->ieee80211->wq,
+ &priv->ieee80211->associate_procedure_wq);
}
}
- /* YJ,add,080828,for KeepAlive */
MgntLinkKeepAlive(priv);
- /* YJ,add,080828,for LPS */
LeisurePSLeave(priv);
if (priv->ieee80211->state == IEEE80211_LINKED) {
- priv->link_detect.NumRxOkInPeriod = priv->ieee80211->NumRxDataInPeriod;
- if (priv->link_detect.NumRxOkInPeriod > 666 ||
- priv->link_detect.NumTxOkInPeriod > 666) {
+ priv->link_detect.num_rx_ok_in_period =
+ priv->ieee80211->NumRxDataInPeriod;
+ if (priv->link_detect.num_rx_ok_in_period > 666 ||
+ priv->link_detect.num_tx_ok_in_period > 666) {
bBusyTraffic = true;
}
- if (((priv->link_detect.NumRxOkInPeriod + priv->link_detect.NumTxOkInPeriod) > 8)
- || (priv->link_detect.NumRxOkInPeriod > 2)) {
+ if ((priv->link_detect.num_rx_ok_in_period +
+ priv->link_detect.num_tx_ok_in_period > 8)
+ || (priv->link_detect.num_rx_ok_in_period > 2)) {
bEnterPS = false;
} else
bEnterPS = true;
@@ -2962,9 +2982,9 @@ void rtl8180_watch_dog(struct net_device *dev)
LeisurePSLeave(priv);
} else
LeisurePSLeave(priv);
- priv->link_detect.bBusyTraffic = bBusyTraffic;
- priv->link_detect.NumRxOkInPeriod = 0;
- priv->link_detect.NumTxOkInPeriod = 0;
+ priv->link_detect.b_busy_traffic = bBusyTraffic;
+ priv->link_detect.num_rx_ok_in_period = 0;
+ priv->link_detect.num_tx_ok_in_period = 0;
priv->ieee80211->NumRxDataInPeriod = 0;
priv->ieee80211->NumRxBcnInPeriod = 0;
}
@@ -3047,15 +3067,17 @@ int rtl8180_down(struct net_device *dev)
cancel_delayed_work(&priv->ieee80211->hw_dig_wq);
cancel_delayed_work(&priv->ieee80211->tx_pw_wq);
del_timer_sync(&priv->SwAntennaDiversityTimer);
- SetZebraRFPowerState8185(dev, eRfOff);
- memset(&(priv->ieee80211->current_network), 0, sizeof(struct ieee80211_network));
+ SetZebraRFPowerState8185(dev, RF_OFF);
+ memset(&priv->ieee80211->current_network,
+ 0, sizeof(struct ieee80211_network));
priv->ieee80211->state = IEEE80211_NOLINK;
return 0;
}
void rtl8180_restart_wq(struct work_struct *work)
{
- struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq);
+ struct r8180_priv *priv = container_of(
+ work, struct r8180_priv, reset_wq);
struct net_device *dev = priv->dev;
down(&priv->wx_sem);
@@ -3116,7 +3138,8 @@ static int r8180_set_mac_adr(struct net_device *dev, void *mac)
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
if (priv->ieee80211->iw_mode == IW_MODE_MASTER)
- memcpy(priv->ieee80211->current_network.bssid, dev->dev_addr, ETH_ALEN);
+ memcpy(priv->ieee80211->current_network.bssid,
+ dev->dev_addr, ETH_ALEN);
if (priv->up) {
rtl8180_down(dev);
@@ -3137,7 +3160,8 @@ static int rtl8180_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case RTL_IOCTL_WPA_SUPPLICANT:
- ret = ieee80211_wpa_supplicant_ioctl(priv->ieee80211, &wrq->u.data);
+ ret = ieee80211_wpa_supplicant_ioctl(
+ priv->ieee80211, &wrq->u.data);
return ret;
default:
return -EOPNOTSUPP;
@@ -3387,7 +3411,7 @@ static void rtl8180_tx_isr(struct net_device *dev, int pri, short error)
int j, i;
int hd;
if (error)
- priv->stats.txretry++; /* tony 20060601 */
+ priv->stats.txretry++;
spin_lock_irqsave(&priv->tx_lock, flag);
switch (pri) {
case MANAGE_PRIORITY:
@@ -3540,7 +3564,7 @@ static irqreturn_t rtl8180_interrupt(int irq, void *netdev)
spin_lock_irqsave(&priv->irq_th_lock, flags);
/* ISR: 4bytes */
- inta = read_nic_dword(dev, ISR); /* & priv->IntrMask; */
+ inta = read_nic_dword(dev, ISR);
write_nic_dword(dev, ISR, inta); /* reset int situation */
priv->stats.shints++;
@@ -3586,7 +3610,7 @@ static irqreturn_t rtl8180_interrupt(int irq, void *netdev)
}
if (inta & ISR_THPDOK) { /* High priority tx ok */
- priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
+ priv->link_detect.num_tx_ok_in_period++;
priv->stats.txhpokint++;
rtl8180_tx_isr(dev, HI_PRIORITY, 0);
}
@@ -3649,14 +3673,14 @@ static irqreturn_t rtl8180_interrupt(int irq, void *netdev)
priv->stats.txoverflow++;
if (inta & ISR_TNPDOK) { /* Normal priority tx ok */
- priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
+ priv->link_detect.num_tx_ok_in_period++;
priv->stats.txnpokint++;
rtl8180_tx_isr(dev, NORM_PRIORITY, 0);
rtl8180_try_wake_queue(dev, NORM_PRIORITY);
}
if (inta & ISR_TLPDOK) { /* Low priority tx ok */
- priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
+ priv->link_detect.num_tx_ok_in_period++;
priv->stats.txlpokint++;
rtl8180_tx_isr(dev, LOW_PRIORITY, 0);
rtl8180_try_wake_queue(dev, LOW_PRIORITY);
@@ -3664,14 +3688,14 @@ static irqreturn_t rtl8180_interrupt(int irq, void *netdev)
if (inta & ISR_TBKDOK) { /* corresponding to BK_PRIORITY */
priv->stats.txbkpokint++;
- priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
+ priv->link_detect.num_tx_ok_in_period++;
rtl8180_tx_isr(dev, BK_PRIORITY, 0);
rtl8180_try_wake_queue(dev, BE_PRIORITY);
}
if (inta & ISR_TBEDOK) { /* corresponding to BE_PRIORITY */
priv->stats.txbeperr++;
- priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
+ priv->link_detect.num_tx_ok_in_period++;
rtl8180_tx_isr(dev, BE_PRIORITY, 0);
rtl8180_try_wake_queue(dev, BE_PRIORITY);
}
@@ -3688,17 +3712,19 @@ void rtl8180_irq_rx_tasklet(struct r8180_priv *priv)
void GPIOChangeRFWorkItemCallBack(struct work_struct *work)
{
- struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, GPIOChangeRFWorkItem.work);
+ struct ieee80211_device *ieee = container_of(
+ work, struct ieee80211_device, GPIOChangeRFWorkItem.work);
struct net_device *dev = ieee->dev;
struct r8180_priv *priv = ieee80211_priv(dev);
u8 btPSR;
u8 btConfig0;
- RT_RF_POWER_STATE eRfPowerStateToSet;
+ enum rt_rf_power_state eRfPowerStateToSet;
bool bActuallySet = false;
char *argv[3];
static char *RadioPowerPath = "/etc/acpi/events/RadioPower.sh";
- static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL};
+ static char *envp[] = {"HOME=/", "TERM=linux",
+ "PATH=/usr/bin:/bin", NULL};
static int readf_count;
readf_count = (readf_count+1)%0xffff;
@@ -3708,24 +3734,24 @@ void GPIOChangeRFWorkItemCallBack(struct work_struct *work)
btPSR = read_nic_byte(dev, PSR);
write_nic_byte(dev, PSR, (btPSR & ~BIT3));
- /* It need to delay 4us suggested by Jong, 2008-01-16 */
+ /* It need to delay 4us suggested */
udelay(4);
/* HW radio On/Off according to the value of FF51[4](config0) */
btConfig0 = btPSR = read_nic_byte(dev, CONFIG0);
- eRfPowerStateToSet = (btConfig0 & BIT4) ? eRfOn : eRfOff;
+ eRfPowerStateToSet = (btConfig0 & BIT4) ? RF_ON : RF_OFF;
/* Turn LED back on when radio enabled */
- if (eRfPowerStateToSet == eRfOn)
+ if (eRfPowerStateToSet == RF_ON)
write_nic_byte(dev, PSR, btPSR | BIT3);
if ((priv->ieee80211->bHwRadioOff == true) &&
- (eRfPowerStateToSet == eRfOn)) {
+ (eRfPowerStateToSet == RF_ON)) {
priv->ieee80211->bHwRadioOff = false;
bActuallySet = true;
} else if ((priv->ieee80211->bHwRadioOff == false) &&
- (eRfPowerStateToSet == eRfOff)) {
+ (eRfPowerStateToSet == RF_OFF)) {
priv->ieee80211->bHwRadioOff = true;
bActuallySet = true;
}
diff --git a/drivers/staging/rtl8187se/r8180_dm.c b/drivers/staging/rtl8187se/r8180_dm.c
index 2ccd2cb70fac..8c020e064869 100644
--- a/drivers/staging/rtl8187se/r8180_dm.c
+++ b/drivers/staging/rtl8187se/r8180_dm.c
@@ -1116,14 +1116,14 @@ bool CheckTxPwrTracking(struct net_device *dev)
void SwAntennaDiversityTimerCallback(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- RT_RF_POWER_STATE rtState;
+ enum rt_rf_power_state rtState;
/* We do NOT need to switch antenna while RF is off. */
rtState = priv->eRFPowerState;
do {
- if (rtState == eRfOff) {
+ if (rtState == RF_OFF) {
break;
- } else if (rtState == eRfSleep) {
+ } else if (rtState == RF_SLEEP) {
/* Don't access BB/RF under Disable PLL situation. */
break;
}
diff --git a/drivers/staging/rtl8187se/r8180_rtl8225.h b/drivers/staging/rtl8187se/r8180_rtl8225.h
index de084f07a071..7df73927b3cc 100644
--- a/drivers/staging/rtl8187se/r8180_rtl8225.h
+++ b/drivers/staging/rtl8187se/r8180_rtl8225.h
@@ -1,14 +1,13 @@
/*
- This is part of the rtl8180-sa2400 driver
- released under the GPL (See file COPYING for details).
- Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
-
- This files contains programming code for the rtl8225
- radio frontend.
-
- *Many* thanks to Realtek Corp. for their great support!
-
-*/
+ * This is part of the rtl8180-sa2400 driver released under the GPL (See file
+ * COPYING for details).
+ *
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
+ *
+ * This files contains programming code for the rtl8225 radio frontend.
+ *
+ * *Many* thanks to Realtek Corp. for their great support!
+ */
#include "r8180.h"
@@ -29,7 +28,7 @@ u16 RF_ReadReg(struct net_device *dev, u8 offset);
void rtl8180_set_mode(struct net_device *dev, int mode);
void rtl8180_set_mode(struct net_device *dev, int mode);
bool SetZebraRFPowerState8185(struct net_device *dev,
- RT_RF_POWER_STATE eRFPowerState);
+ enum rt_rf_power_state eRFPowerState);
void rtl8225z4_rf_sleep(struct net_device *dev);
void rtl8225z4_rf_wakeup(struct net_device *dev);
diff --git a/drivers/staging/rtl8187se/r8180_rtl8225z2.c b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
index 7c9a8bfe6d88..47104fa05c55 100644
--- a/drivers/staging/rtl8187se/r8180_rtl8225z2.c
+++ b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
@@ -279,8 +279,8 @@ void rtl8225z2_rf_close(struct net_device *dev)
* Map dBm into Tx power index according to current HW model, for example,
* RF and PA, and current wireless mode.
*/
-static s8 DbmToTxPwrIdx(struct r8180_priv *priv, WIRELESS_MODE WirelessMode,
- s32 PowerInDbm)
+static s8 DbmToTxPwrIdx(struct r8180_priv *priv,
+ enum wireless_mode mode, s32 PowerInDbm)
{
bool bUseDefault = true;
s8 TxPwrIdx = 0;
@@ -291,7 +291,7 @@ static s8 DbmToTxPwrIdx(struct r8180_priv *priv, WIRELESS_MODE WirelessMode,
*/
s32 tmp = 0;
- if (WirelessMode == WIRELESS_MODE_G) {
+ if (mode == WIRELESS_MODE_G) {
bUseDefault = false;
tmp = (2 * PowerInDbm);
@@ -301,7 +301,7 @@ static s8 DbmToTxPwrIdx(struct r8180_priv *priv, WIRELESS_MODE WirelessMode,
TxPwrIdx = 40;
else
TxPwrIdx = (s8)tmp;
- } else if (WirelessMode == WIRELESS_MODE_B) {
+ } else if (mode == WIRELESS_MODE_B) {
bUseDefault = false;
tmp = (4 * PowerInDbm) - 52;
@@ -606,51 +606,12 @@ void rtl8225z2_rf_init(struct net_device *dev)
rtl8225z2_rf_set_chan(dev, priv->chan);
}
-void rtl8225z2_rf_set_mode(struct net_device *dev)
-{
- struct r8180_priv *priv = ieee80211_priv(dev);
-
- if (priv->ieee80211->mode == IEEE_A) {
- write_rtl8225(dev, 0x5, 0x1865);
- write_nic_dword(dev, RF_PARA, 0x10084);
- write_nic_dword(dev, RF_TIMING, 0xa8008);
- write_phy_ofdm(dev, 0x0, 0x0);
- write_phy_ofdm(dev, 0xa, 0x6);
- write_phy_ofdm(dev, 0xb, 0x99);
- write_phy_ofdm(dev, 0xf, 0x20);
- write_phy_ofdm(dev, 0x11, 0x7);
-
- rtl8225z2_set_gain(dev, 4);
-
- write_phy_ofdm(dev, 0x15, 0x40);
- write_phy_ofdm(dev, 0x17, 0x40);
-
- write_nic_dword(dev, 0x94, 0x10000000);
- } else {
- write_rtl8225(dev, 0x5, 0x1864);
- write_nic_dword(dev, RF_PARA, 0x10044);
- write_nic_dword(dev, RF_TIMING, 0xa8008);
- write_phy_ofdm(dev, 0x0, 0x1);
- write_phy_ofdm(dev, 0xa, 0x6);
- write_phy_ofdm(dev, 0xb, 0x99);
- write_phy_ofdm(dev, 0xf, 0x20);
- write_phy_ofdm(dev, 0x11, 0x7);
-
- rtl8225z2_set_gain(dev, 4);
-
- write_phy_ofdm(dev, 0x15, 0x40);
- write_phy_ofdm(dev, 0x17, 0x40);
-
- write_nic_dword(dev, 0x94, 0x04000002);
- }
-}
-
#define MAX_DOZE_WAITING_TIMES_85B 20
#define MAX_POLLING_24F_TIMES_87SE 10
#define LPS_MAX_SLEEP_WAITING_TIMES_87SE 5
bool SetZebraRFPowerState8185(struct net_device *dev,
- RT_RF_POWER_STATE eRFPowerState)
+ enum rt_rf_power_state eRFPowerState)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u8 btCR9346, btConfig3;
@@ -672,7 +633,7 @@ bool SetZebraRFPowerState8185(struct net_device *dev,
write_nic_byte(dev, CONFIG3, (btConfig3 | CONFIG3_PARM_En));
switch (eRFPowerState) {
- case eRfOn:
+ case RF_ON:
write_nic_word(dev, 0x37C, 0x00EC);
/* turn on AFE */
@@ -697,7 +658,7 @@ bool SetZebraRFPowerState8185(struct net_device *dev,
u1bTmp = read_nic_byte(dev, 0x24E);
write_nic_byte(dev, 0x24E, (u1bTmp & (~(BIT5 | BIT6))));
break;
- case eRfSleep:
+ case RF_SLEEP:
for (QueueID = 0, i = 0; QueueID < 6;) {
if (get_curr_tx_free_desc(dev, QueueID) ==
priv->txringcount) {
@@ -764,7 +725,7 @@ bool SetZebraRFPowerState8185(struct net_device *dev,
}
}
break;
- case eRfOff:
+ case RF_OFF:
for (QueueID = 0, i = 0; QueueID < 6;) {
if (get_curr_tx_free_desc(dev, QueueID) ==
priv->txringcount) {
@@ -841,10 +802,10 @@ bool SetZebraRFPowerState8185(struct net_device *dev,
void rtl8225z4_rf_sleep(struct net_device *dev)
{
- MgntActSet_RF_State(dev, eRfSleep, RF_CHANGE_BY_PS);
+ MgntActSet_RF_State(dev, RF_SLEEP, RF_CHANGE_BY_PS);
}
void rtl8225z4_rf_wakeup(struct net_device *dev)
{
- MgntActSet_RF_State(dev, eRfOn, RF_CHANGE_BY_PS);
+ MgntActSet_RF_State(dev, RF_ON, RF_CHANGE_BY_PS);
}
diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c
index 9b676e027cad..b55249170f18 100644
--- a/drivers/staging/rtl8187se/r8180_wx.c
+++ b/drivers/staging/rtl8187se/r8180_wx.c
@@ -29,7 +29,7 @@ static u32 rtl8180_rates[] = {1000000, 2000000, 5500000, 11000000,
#define RATE_COUNT ARRAY_SIZE(rtl8180_rates)
-static CHANNEL_LIST DefaultChannelPlan[] = {
+static struct rtl8187se_channel_list default_channel_plan[] = {
{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64}, 19}, /* FCC */
{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, /* IC */
{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21}, /* ETSI */
@@ -337,7 +337,7 @@ static int r8180_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
} else {
/* prevent scan in BusyTraffic */
/* FIXME: Need to consider last scan time */
- if ((priv->link_detect.bBusyTraffic) && (true)) {
+ if ((priv->link_detect.b_busy_traffic) && (true)) {
ret = 0;
printk("Now traffic is busy, please try later!\n");
} else
@@ -1030,15 +1030,15 @@ static int r8180_wx_set_channelplan(struct net_device *dev,
/* unsigned long flags; */
down(&priv->wx_sem);
- if (DefaultChannelPlan[*val].Len != 0) {
+ if (default_channel_plan[*val].len != 0) {
priv->channel_plan = *val;
/* Clear old channel map 8 */
for (i = 1; i <= MAX_CHANNEL_NUMBER; i++)
GET_DOT11D_INFO(priv->ieee80211)->channel_map[i] = 0;
/* Set new channel map */
- for (i = 1; i <= DefaultChannelPlan[*val].Len; i++)
- GET_DOT11D_INFO(priv->ieee80211)->channel_map[DefaultChannelPlan[*val].Channel[i-1]] = 1;
+ for (i = 1; i <= default_channel_plan[*val].len; i++)
+ GET_DOT11D_INFO(priv->ieee80211)->channel_map[default_channel_plan[*val].channel[i-1]] = 1;
}
up(&priv->wx_sem);
diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c
index c8b9baff1dbc..cc6f100814f3 100644
--- a/drivers/staging/rtl8187se/r8185b_init.c
+++ b/drivers/staging/rtl8187se/r8185b_init.c
@@ -619,10 +619,10 @@ void UpdateInitialGain(struct net_device *dev)
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
/* lzm add 080826 */
- if (priv->eRFPowerState != eRfOn) {
+ if (priv->eRFPowerState != RF_ON) {
/* Don't access BB/RF under disable PLL situation.
* RT_TRACE(COMP_DIG, DBG_LOUD, ("UpdateInitialGain -
- * pHalData->eRFPowerState!=eRfOn\n"));
+ * pHalData->eRFPowerState!=RF_ON\n"));
* Back to the original state
*/
priv->InitialGain = priv->InitialGainBackUp;
@@ -872,8 +872,8 @@ static u8 GetSupportedWirelessMode8185(struct net_device *dev)
static void
ActUpdateChannelAccessSetting(struct net_device *dev,
- WIRELESS_MODE WirelessMode,
- PCHANNEL_ACCESS_SETTING ChnlAccessSetting)
+ enum wireless_mode mode,
+ struct chnl_access_setting *chnl_access_setting)
{
AC_CODING eACI;
@@ -890,25 +890,25 @@ ActUpdateChannelAccessSetting(struct net_device *dev,
*/
/* Suggested by Jong, 2005.12.08. */
- ChnlAccessSetting->SIFS_Timer = 0x22;
- ChnlAccessSetting->DIFS_Timer = 0x1C; /* 2006.06.02, by rcnjko. */
- ChnlAccessSetting->SlotTimeTimer = 9; /* 2006.06.02, by rcnjko. */
+ chnl_access_setting->sifs_timer = 0x22;
+ chnl_access_setting->difs_timer = 0x1C; /* 2006.06.02, by rcnjko. */
+ chnl_access_setting->slot_time_timer = 9; /* 2006.06.02, by rcnjko. */
/*
* Suggested by wcchu, it is the default value of EIFS register,
* 2005.12.08.
*/
- ChnlAccessSetting->EIFS_Timer = 0x5B;
- ChnlAccessSetting->CWminIndex = 3; /* 2006.06.02, by rcnjko. */
- ChnlAccessSetting->CWmaxIndex = 7; /* 2006.06.02, by rcnjko. */
+ chnl_access_setting->eifs_timer = 0x5B;
+ chnl_access_setting->cwmin_index = 3; /* 2006.06.02, by rcnjko. */
+ chnl_access_setting->cwmax_index = 7; /* 2006.06.02, by rcnjko. */
- write_nic_byte(dev, SIFS, ChnlAccessSetting->SIFS_Timer);
+ write_nic_byte(dev, SIFS, chnl_access_setting->sifs_timer);
/*
* Rewrited from directly use PlatformEFIOWrite1Byte(),
* by Annie, 2006-03-29.
*/
- write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer);
+ write_nic_byte(dev, SLOT, chnl_access_setting->slot_time_timer);
- write_nic_byte(dev, EIFS, ChnlAccessSetting->EIFS_Timer);
+ write_nic_byte(dev, EIFS, chnl_access_setting->eifs_timer);
/*
* <RJ_EXPR_QOS> Suggested by wcchu, it is the default value of EIFS
@@ -959,7 +959,7 @@ static void ActSetWirelessMode8185(struct net_device *dev, u8 btWirelessMode)
* wireless mode if we switch to specified band successfully.
*/
- ieee->mode = (WIRELESS_MODE)btWirelessMode;
+ ieee->mode = (enum wireless_mode)btWirelessMode;
/* 3. Change related setting. */
if (ieee->mode == WIRELESS_MODE_A)
@@ -1085,7 +1085,7 @@ static bool MgntDisconnect(struct net_device *dev, u8 asRsn)
* PASSIVE LEVEL.
*/
static bool SetRFPowerState(struct net_device *dev,
- RT_RF_POWER_STATE eRFPowerState)
+ enum rt_rf_power_state eRFPowerState)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
bool bResult = false;
@@ -1098,13 +1098,13 @@ static bool SetRFPowerState(struct net_device *dev,
return bResult;
}
-bool MgntActSet_RF_State(struct net_device *dev, RT_RF_POWER_STATE StateToSet,
+bool MgntActSet_RF_State(struct net_device *dev, enum rt_rf_power_state StateToSet,
u32 ChangeSource)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
bool bActionAllowed = false;
bool bConnectBySSID = false;
- RT_RF_POWER_STATE rtState;
+ enum rt_rf_power_state rtState;
u16 RFWaitCounter = 0;
unsigned long flag;
/*
@@ -1140,7 +1140,7 @@ bool MgntActSet_RF_State(struct net_device *dev, RT_RF_POWER_STATE StateToSet,
rtState = priv->eRFPowerState;
switch (StateToSet) {
- case eRfOn:
+ case RF_ON:
/*
* Turn On RF no matter the IPS setting because we need to
* update the RF state to Ndis under Vista, or the Windows
@@ -1153,13 +1153,13 @@ bool MgntActSet_RF_State(struct net_device *dev, RT_RF_POWER_STATE StateToSet,
priv->RfOffReason = 0;
bActionAllowed = true;
- if (rtState == eRfOff &&
+ if (rtState == RF_OFF &&
ChangeSource >= RF_CHANGE_BY_HW)
bConnectBySSID = true;
}
break;
- case eRfOff:
+ case RF_OFF:
/* 070125, rcnjko: we always keep connected in AP mode. */
if (priv->RfOffReason > RF_CHANGE_BY_IPS) {
@@ -1182,7 +1182,7 @@ bool MgntActSet_RF_State(struct net_device *dev, RT_RF_POWER_STATE StateToSet,
priv->RfOffReason |= ChangeSource;
bActionAllowed = true;
break;
- case eRfSleep:
+ case RF_SLEEP:
priv->RfOffReason |= ChangeSource;
bActionAllowed = true;
break;
@@ -1233,7 +1233,7 @@ static void InactivePowerSave(struct net_device *dev)
void IPSEnter(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- RT_RF_POWER_STATE rtState;
+ enum rt_rf_power_state rtState;
if (priv->bInactivePs) {
rtState = priv->eRFPowerState;
@@ -1245,9 +1245,9 @@ void IPSEnter(struct net_device *dev)
* trigger IPS)(4) IBSS (send Beacon)
* (5) AP mode (send Beacon)
*/
- if (rtState == eRfOn && !priv->bSwRfProcessing
+ if (rtState == RF_ON && !priv->bSwRfProcessing
&& (priv->ieee80211->state != IEEE80211_LINKED)) {
- priv->eInactivePowerState = eRfOff;
+ priv->eInactivePowerState = RF_OFF;
InactivePowerSave(dev);
}
}
@@ -1255,13 +1255,13 @@ void IPSEnter(struct net_device *dev)
void IPSLeave(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- RT_RF_POWER_STATE rtState;
+ enum rt_rf_power_state rtState;
if (priv->bInactivePs) {
rtState = priv->eRFPowerState;
- if ((rtState == eRfOff || rtState == eRfSleep) &&
+ if ((rtState == RF_OFF || rtState == RF_SLEEP) &&
!priv->bSwRfProcessing
&& priv->RfOffReason <= RF_CHANGE_BY_IPS) {
- priv->eInactivePowerState = eRfOn;
+ priv->eInactivePowerState = RF_ON;
InactivePowerSave(dev);
}
}
@@ -1385,23 +1385,23 @@ void rtl8185b_adapter_start(struct net_device *dev)
/* Initialize RegWirelessMode if it is not a valid one. */
if (bInvalidWirelessMode)
- ieee->mode = (WIRELESS_MODE)InitWirelessMode;
+ ieee->mode = (enum wireless_mode)InitWirelessMode;
} else {
/* One of B, G, A. */
InitWirelessMode = ieee->mode;
}
- priv->eRFPowerState = eRfOff;
+ priv->eRFPowerState = RF_OFF;
priv->RfOffReason = 0;
{
- MgntActSet_RF_State(dev, eRfOn, 0);
+ MgntActSet_RF_State(dev, RF_ON, 0);
}
/*
* If inactive power mode is enabled, disable rf while in
* disconnected state.
*/
if (priv->bInactivePs)
- MgntActSet_RF_State(dev , eRfOff, RF_CHANGE_BY_IPS);
+ MgntActSet_RF_State(dev , RF_OFF, RF_CHANGE_BY_IPS);
ActSetWirelessMode8185(dev, (u8)(InitWirelessMode));
diff --git a/drivers/staging/rtl8188eu/Kconfig b/drivers/staging/rtl8188eu/Kconfig
index 70fecfabc0c7..e45c106c2162 100644
--- a/drivers/staging/rtl8188eu/Kconfig
+++ b/drivers/staging/rtl8188eu/Kconfig
@@ -11,7 +11,7 @@ if R8188EU
config 88EU_AP_MODE
bool "Realtek RTL8188EU AP mode"
- default Y
+ default y
---help---
This option enables Access Point mode. Unless you know that your system
will never be used as an AP, or the target system has limited memory,
@@ -19,7 +19,7 @@ config 88EU_AP_MODE
config 88EU_P2P
bool "Realtek RTL8188EU Peer-to-peer mode"
- default Y
+ default y
---help---
This option enables peer-to-peer mode for the r8188eu driver. Unless you
know that peer-to-peer (P2P) mode will never be used, or the target system has
diff --git a/drivers/staging/rtl8188eu/Makefile b/drivers/staging/rtl8188eu/Makefile
index 0a617b42cc99..6a138ff699e9 100644
--- a/drivers/staging/rtl8188eu/Makefile
+++ b/drivers/staging/rtl8188eu/Makefile
@@ -34,7 +34,6 @@ r8188eu-y := \
hal/hal_com.o \
hal/odm.o \
hal/odm_debug.o \
- hal/odm_interface.o \
hal/odm_HWConfig.o \
hal/odm_RegConfig8188E.o\
hal/odm_RTL8188E.o \
diff --git a/drivers/staging/rtl8188eu/TODO b/drivers/staging/rtl8188eu/TODO
index f7f389c40e71..b574b235b340 100644
--- a/drivers/staging/rtl8188eu/TODO
+++ b/drivers/staging/rtl8188eu/TODO
@@ -9,6 +9,11 @@ TODO:
- merge Realtek's bugfixes and new features into the driver
- switch to use LIB80211
- switch to use MAC80211
+- figure out what to do with this code in rtw_recv_indicatepkt():
+ rcu_read_lock();
+ rcu_dereference(padapter->pnetdev->rx_handler_data);
+ rcu_read_unlock();
+ Perhaps delete it, perhaps assign to some local variable.
Please send any patches to Greg Kroah-Hartman <gregkh@linux.com>,
and Larry Finger <Larry.Finger@lwfinger.net>.
diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c
index 8ebe6bc40022..ff74d0d7efa3 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ap.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ap.c
@@ -94,7 +94,7 @@ static void update_BCNTIM(struct adapter *padapter)
} else {
tim_ielen = 0;
- /* calucate head_len */
+ /* calculate head_len */
offset = _FIXED_IE_LENGTH_;
offset += pnetwork_mlmeext->Ssid.SsidLength + 2;
@@ -129,7 +129,7 @@ static void update_BCNTIM(struct adapter *padapter)
*dst_ie++ = tim_ielen;
*dst_ie++ = 0;/* DTIM count */
- *dst_ie++ = 1;/* DTIM peroid */
+ *dst_ie++ = 1;/* DTIM period */
if (pstapriv->tim_bitmap&BIT(0))/* for bc/mc frames */
*dst_ie++ = BIT(0);/* bitmap ctrl */
@@ -285,12 +285,12 @@ void expire_timeout_chk(struct adapter *padapter)
spin_lock_bh(&pstapriv->auth_list_lock);
phead = &pstapriv->auth_list;
- plist = get_next(phead);
+ plist = phead->next;
/* check auth_queue */
while ((rtw_end_of_queue_search(phead, plist)) == false) {
- psta = LIST_CONTAINOR(plist, struct sta_info, auth_list);
- plist = get_next(plist);
+ psta = container_of(plist, struct sta_info, auth_list);
+ plist = plist->next;
if (psta->expire_to > 0) {
psta->expire_to--;
@@ -319,12 +319,12 @@ void expire_timeout_chk(struct adapter *padapter)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = get_next(phead);
+ plist = phead->next;
/* check asoc_queue */
while ((rtw_end_of_queue_search(phead, plist)) == false) {
- psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
- plist = get_next(plist);
+ psta = container_of(plist, struct sta_info, asoc_list);
+ plist = plist->next;
if (chk_sta_is_alive(psta) || !psta->expire_to) {
psta->expire_to = pstapriv->expire_to;
@@ -821,7 +821,7 @@ static void start_bss_network(struct adapter *padapter, u8 *pbuf)
/* update cur_wireless_mode */
update_wireless_mode(padapter);
- /* udpate capability after cur_wireless_mode updated */
+ /* update capability after cur_wireless_mode updated */
update_capinfo(padapter, rtw_get_capability((struct wlan_bssid_ex *)pnetwork));
/* let pnetwork_mlmeext == pnetwork_mlme. */
@@ -980,7 +980,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
for (p = ie + _BEACON_IE_OFFSET_;; p += (ie_len + 2)) {
p = rtw_get_ie(p, _SSN_IE_1_, &ie_len,
(pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
- if ((p) && (_rtw_memcmp(p+2, OUI1, 4))) {
+ if ((p) && (!memcmp(p+2, OUI1, 4))) {
if (rtw_parse_wpa_ie(p, ie_len+2, &group_cipher,
&pairwise_cipher, NULL) == _SUCCESS) {
psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
@@ -1005,7 +1005,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
for (p = ie + _BEACON_IE_OFFSET_;; p += (ie_len + 2)) {
p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len,
(pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
- if ((p) && _rtw_memcmp(p+2, WMM_PARA_IE, 6)) {
+ if ((p) && !memcmp(p+2, WMM_PARA_IE, 6)) {
pmlmepriv->qospriv.qos_option = 1;
*(p+8) |= BIT(7);/* QoS Info, support U-APSD */
@@ -1144,13 +1144,13 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
spin_lock_bh(&(pacl_node_q->lock));
phead = get_list_head(pacl_node_q);
- plist = get_next(phead);
+ plist = phead->next;
while (!rtw_end_of_queue_search(phead, plist)) {
- paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
- plist = get_next(plist);
+ paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
+ plist = plist->next;
- if (_rtw_memcmp(paclnode->addr, addr, ETH_ALEN)) {
+ if (!memcmp(paclnode->addr, addr, ETH_ALEN)) {
if (paclnode->valid) {
added = true;
DBG_88E("%s, sta has been added\n", __func__);
@@ -1205,13 +1205,13 @@ int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
spin_lock_bh(&(pacl_node_q->lock));
phead = get_list_head(pacl_node_q);
- plist = get_next(phead);
+ plist = phead->next;
while (!rtw_end_of_queue_search(phead, plist)) {
- paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
- plist = get_next(plist);
+ paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
+ plist = plist->next;
- if (_rtw_memcmp(paclnode->addr, addr, ETH_ALEN)) {
+ if (!memcmp(paclnode->addr, addr, ETH_ALEN)) {
if (paclnode->valid) {
paclnode->valid = false;
@@ -1339,8 +1339,7 @@ static void update_bcn_wps_ie(struct adapter *padapter)
pnetwork->IELength = wps_offset + (wps_ielen+2) + remainder_ielen;
}
- if (pbackup_remainder_ie)
- kfree(pbackup_remainder_ie);
+ kfree(pbackup_remainder_ie);
}
static void update_bcn_p2p_ie(struct adapter *padapter)
@@ -1351,13 +1350,13 @@ static void update_bcn_vendor_spec_ie(struct adapter *padapter, u8 *oui)
{
DBG_88E("%s\n", __func__);
- if (_rtw_memcmp(RTW_WPA_OUI, oui, 4))
+ if (!memcmp(RTW_WPA_OUI, oui, 4))
update_bcn_wpa_ie(padapter);
- else if (_rtw_memcmp(WMM_OUI, oui, 4))
+ else if (!memcmp(WMM_OUI, oui, 4))
update_bcn_wmm_ie(padapter);
- else if (_rtw_memcmp(WPS_OUI, oui, 4))
+ else if (!memcmp(WPS_OUI, oui, 4))
update_bcn_wps_ie(padapter);
- else if (_rtw_memcmp(P2P_OUI, oui, 4))
+ else if (!memcmp(P2P_OUI, oui, 4))
update_bcn_p2p_ie(padapter);
else
DBG_88E("unknown OUI type!\n");
@@ -1415,7 +1414,7 @@ void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx)
/*
op_mode
-Set to 0 (HT pure) under the followign conditions
+Set to 0 (HT pure) under the following conditions
- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
Set to 1 (HT non-member protection) if there may be non-HT STAs
@@ -1494,7 +1493,7 @@ static int rtw_ht_operation_update(struct adapter *padapter)
void associated_clients_update(struct adapter *padapter, u8 updated)
{
- /* update associcated stations cap. */
+ /* update associated stations cap. */
if (updated) {
struct list_head *phead, *plist;
struct sta_info *psta = NULL;
@@ -1503,13 +1502,13 @@ void associated_clients_update(struct adapter *padapter, u8 updated)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = get_next(phead);
+ plist = phead->next;
/* check asoc_queue */
while ((rtw_end_of_queue_search(phead, plist)) == false) {
- psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+ psta = container_of(plist, struct sta_info, asoc_list);
- plist = get_next(plist);
+ plist = plist->next;
VCS_update(padapter, psta);
}
@@ -1647,7 +1646,7 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true);
}
- /* update associcated stations cap. */
+ /* update associated stations cap. */
associated_clients_update(padapter, beacon_updated);
DBG_88E("%s, updated =%d\n", __func__, beacon_updated);
@@ -1711,7 +1710,7 @@ u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta)
update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true);
}
- /* update associcated stations cap. */
+ /* update associated stations cap. */
DBG_88E("%s, updated =%d\n", __func__, beacon_updated);
@@ -1777,12 +1776,12 @@ int rtw_ap_inform_ch_switch(struct adapter *padapter, u8 new_ch, u8 ch_offset)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = get_next(phead);
+ plist = phead->next;
/* for each sta in asoc_queue */
while (!rtw_end_of_queue_search(phead, plist)) {
- psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
- plist = get_next(plist);
+ psta = container_of(plist, struct sta_info, asoc_list);
+ plist = plist->next;
issue_action_spct_ch_switch(padapter, psta->hwaddr, new_ch, ch_offset);
psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2);
@@ -1811,13 +1810,13 @@ int rtw_sta_flush(struct adapter *padapter)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = get_next(phead);
+ plist = phead->next;
/* free sta asoc_queue */
while ((rtw_end_of_queue_search(phead, plist)) == false) {
- psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+ psta = container_of(plist, struct sta_info, asoc_list);
- plist = get_next(plist);
+ plist = plist->next;
rtw_list_delete(&psta->asoc_list);
pstapriv->asoc_list_cnt--;
@@ -1942,10 +1941,10 @@ void stop_ap_mode(struct adapter *padapter)
/* for ACL */
spin_lock_bh(&(pacl_node_q->lock));
phead = get_list_head(pacl_node_q);
- plist = get_next(phead);
+ plist = phead->next;
while ((rtw_end_of_queue_search(phead, plist)) == false) {
- paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
- plist = get_next(plist);
+ paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
+ plist = plist->next;
if (paclnode->valid) {
paclnode->valid = false;
diff --git a/drivers/staging/rtl8188eu/core/rtw_br_ext.c b/drivers/staging/rtl8188eu/core/rtw_br_ext.c
index 75e38d4ff4c3..e843c6bd4525 100644
--- a/drivers/staging/rtl8188eu/core/rtw_br_ext.c
+++ b/drivers/staging/rtl8188eu/core/rtw_br_ext.c
@@ -409,7 +409,7 @@ static void __nat25_db_network_insert(struct adapter *priv,
db = priv->nethash[hash];
while (db != NULL) {
if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
- memcpy(db->macAddr, macAddr, ETH_ALEN);
+ ether_addr_copy(db->macAddr, macAddr);
db->ageing_timer = jiffies;
spin_unlock_bh(&priv->br_ext_lock);
return;
@@ -422,7 +422,7 @@ static void __nat25_db_network_insert(struct adapter *priv,
return;
}
memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN);
- memcpy(db->macAddr, macAddr, ETH_ALEN);
+ ether_addr_copy(db->macAddr, macAddr);
atomic_set(&db->use_count, 1);
db->ageing_timer = jiffies;
@@ -543,13 +543,14 @@ int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method)
if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) {
if (*((unsigned char *)&iph->daddr + 3) == 0xff) {
/* L2 is unicast but L3 is broadcast, make L2 bacome broadcast */
- DEBUG_INFO("NAT25: Set DA as boardcast\n");
+ DEBUG_INFO("NAT25: Set DA as broadcast\n");
memset(skb->data, 0xff, ETH_ALEN);
} else {
- /* forward unknow IP packet to upper TCP/IP */
+ /* forward unknown IP packet to upper TCP/IP */
DEBUG_INFO("NAT25: Replace DA with BR's MAC\n");
if ((*(u32 *)priv->br_mac) == 0 && (*(u16 *)(priv->br_mac+4)) == 0) {
- printk("Re-init netdev_br_init() due to br_mac == 0!\n");
+ netdev_info(skb->dev,
+ "Re-init netdev_br_init() due to br_mac == 0!\n");
netdev_br_init(priv->pnetdev);
}
memcpy(skb->data, priv->br_mac, ETH_ALEN);
@@ -932,7 +933,7 @@ int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method)
(ph->code == PADO_CODE ? "PADO" : "PADS"), skb->dev->name);
} else { /* not add relay tag */
if (!priv->pppoe_connection_in_progress) {
- DEBUG_ERR("Discard PPPoE packet due to no connection in progresss!\n");
+ DEBUG_ERR("Discard PPPoE packet due to no connection in progress!\n");
return -1;
}
memcpy(skb->data, priv->pppoe_addr, ETH_ALEN);
diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c
index 82fe8c47a1de..c2fb050337d5 100644
--- a/drivers/staging/rtl8188eu/core/rtw_cmd.c
+++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c
@@ -32,11 +32,10 @@ Caller and the rtw_cmd_thread can protect cmd_q by spin_lock.
No irqsave is necessary.
*/
-int _rtw_init_cmd_priv (struct cmd_priv *pcmdpriv)
+int _rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
{
int res = _SUCCESS;
-_func_enter_;
sema_init(&(pcmdpriv->cmd_queue_sema), 0);
/* sema_init(&(pcmdpriv->cmd_done_sema), 0); */
@@ -71,7 +70,6 @@ _func_enter_;
pcmdpriv->cmd_done_cnt = 0;
pcmdpriv->rsp_cnt = 0;
exit:
-_func_exit_;
return res;
}
@@ -81,24 +79,21 @@ int _rtw_init_evt_priv(struct evt_priv *pevtpriv)
{
int res = _SUCCESS;
-_func_enter_;
/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
atomic_set(&pevtpriv->event_seq, 0);
pevtpriv->evt_done_cnt = 0;
- _init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL);
+ INIT_WORK(&pevtpriv->c2h_wk, c2h_wk_callback);
pevtpriv->c2h_wk_alive = false;
pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN+1);
-_func_exit_;
return res;
}
-void rtw_free_evt_priv(struct evt_priv *pevtpriv)
+void rtw_free_evt_priv(struct evt_priv *pevtpriv)
{
-_func_enter_;
RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+rtw_free_evt_priv\n"));
@@ -113,21 +108,15 @@ _func_enter_;
}
RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("-rtw_free_evt_priv\n"));
-_func_exit_;
}
-void _rtw_free_cmd_priv (struct cmd_priv *pcmdpriv)
+void _rtw_free_cmd_priv(struct cmd_priv *pcmdpriv)
{
-_func_enter_;
if (pcmdpriv) {
- if (pcmdpriv->cmd_allocated_buf)
- kfree(pcmdpriv->cmd_allocated_buf);
-
- if (pcmdpriv->rsp_allocated_buf)
- kfree(pcmdpriv->rsp_allocated_buf);
+ kfree(pcmdpriv->cmd_allocated_buf);
+ kfree(pcmdpriv->rsp_allocated_buf);
}
-_func_exit_;
}
/*
@@ -140,11 +129,10 @@ ISR/Call-Back functions can't call this sub-function.
*/
-int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
+int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
{
unsigned long irqL;
-_func_enter_;
if (obj == NULL)
goto exit;
@@ -157,7 +145,6 @@ _func_enter_;
exit:
-_func_exit_;
return _SUCCESS;
}
@@ -167,47 +154,39 @@ struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue)
unsigned long irqL;
struct cmd_obj *obj;
-_func_enter_;
spin_lock_irqsave(&queue->lock, irqL);
if (rtw_is_list_empty(&(queue->queue))) {
obj = NULL;
} else {
- obj = LIST_CONTAINOR(get_next(&(queue->queue)), struct cmd_obj, list);
+ obj = container_of((&queue->queue)->next, struct cmd_obj, list);
rtw_list_delete(&obj->list);
}
spin_unlock_irqrestore(&queue->lock, irqL);
-_func_exit_;
return obj;
}
-u32 rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
+u32 rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
{
u32 res;
-_func_enter_;
- res = _rtw_init_cmd_priv (pcmdpriv);
-_func_exit_;
+ res = _rtw_init_cmd_priv(pcmdpriv);
return res;
}
-u32 rtw_init_evt_priv (struct evt_priv *pevtpriv)
+u32 rtw_init_evt_priv(struct evt_priv *pevtpriv)
{
- int res;
-_func_enter_;
+ int res;
res = _rtw_init_evt_priv(pevtpriv);
-_func_exit_;
return res;
}
-void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv)
+void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv)
{
-_func_enter_;
RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("rtw_free_cmd_priv\n"));
_rtw_free_cmd_priv(pcmdpriv);
-_func_exit_;
}
static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
@@ -238,7 +217,6 @@ u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
int res = _FAIL;
struct adapter *padapter = pcmdpriv->padapter;
-_func_enter_;
if (cmd_obj == NULL)
goto exit;
@@ -258,34 +236,28 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
-struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
+struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
{
struct cmd_obj *cmd_obj;
-_func_enter_;
cmd_obj = _rtw_dequeue_cmd(&pcmdpriv->cmd_queue);
-_func_exit_;
return cmd_obj;
}
-void rtw_cmd_clr_isr(struct cmd_priv *pcmdpriv)
+void rtw_cmd_clr_isr(struct cmd_priv *pcmdpriv)
{
-_func_enter_;
pcmdpriv->cmd_done_cnt++;
/* up(&(pcmdpriv->cmd_done_sema)); */
-_func_exit_;
}
void rtw_free_cmd_obj(struct cmd_obj *pcmd)
{
-_func_enter_;
if ((pcmd->cmdcode != _JoinBss_CMD_) && (pcmd->cmdcode != _CreateBss_CMD_)) {
/* free parmbuf in cmd_obj */
@@ -302,7 +274,6 @@ _func_enter_;
/* free cmd_obj */
kfree(pcmd);
-_func_exit_;
}
int rtw_cmd_thread(void *context)
@@ -315,7 +286,6 @@ int rtw_cmd_thread(void *context)
struct adapter *padapter = (struct adapter *)context;
struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
-_func_enter_;
thread_enter("RTW_CMD_THREAD");
@@ -410,7 +380,6 @@ post_process:
up(&pcmdpriv->terminate_cmdthread_sema);
-_func_exit_;
complete_and_exit(NULL, 0);
}
@@ -423,15 +392,14 @@ u8 rtw_setstandby_cmd(struct adapter *padapter, uint action)
u8 ret = _SUCCESS;
-_func_enter_;
- ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
if (ph2c == NULL) {
ret = _FAIL;
goto exit;
}
- psetusbsuspend = (struct usb_suspend_parm *)rtw_zmalloc(sizeof(struct usb_suspend_parm));
+ psetusbsuspend = kzalloc(sizeof(struct usb_suspend_parm), GFP_KERNEL);
if (psetusbsuspend == NULL) {
kfree(ph2c);
ret = _FAIL;
@@ -446,7 +414,6 @@ _func_enter_;
exit:
-_func_exit_;
return ret;
}
@@ -465,14 +432,11 @@ u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid,
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-_func_enter_;
- if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1);
- }
- if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
p2p_ps_wk_cmd(padapter, P2P_PS_SCAN, 1);
- }
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL)
@@ -500,9 +464,6 @@ _func_enter_;
if (ssid[i].SsidLength) {
memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid));
psurveyPara->ssid_num++;
- if (0)
- DBG_88E(FUNC_ADPT_FMT" ssid:(%s, %d)\n", FUNC_ADPT_ARG(padapter),
- psurveyPara->ssid[i].Ssid, psurveyPara->ssid[i].SsidLength);
}
}
}
@@ -514,9 +475,6 @@ _func_enter_;
if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) {
memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel));
psurveyPara->ch_num++;
- if (0)
- DBG_88E(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter),
- psurveyPara->ch[i].hw_value);
}
}
}
@@ -537,7 +495,6 @@ _func_enter_;
_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
}
-_func_exit_;
return res;
}
@@ -549,7 +506,6 @@ u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
@@ -570,7 +526,6 @@ _func_enter_;
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
exit:
-_func_exit_;
return res;
}
@@ -582,7 +537,6 @@ u8 rtw_setbasicrate_cmd(struct adapter *padapter, u8 *rateset)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
@@ -604,7 +558,6 @@ _func_enter_;
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
exit:
-_func_exit_;
return res;
}
@@ -624,7 +577,6 @@ u8 rtw_setphy_cmd(struct adapter *padapter, u8 modem, u8 ch)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
@@ -648,7 +600,6 @@ _func_enter_;
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
exit:
-_func_exit_;
return res;
}
@@ -659,7 +610,6 @@ u8 rtw_setbbreg_cmd(struct adapter *padapter, u8 offset, u8 val)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
res = _FAIL;
@@ -680,7 +630,6 @@ _func_enter_;
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
exit:
-_func_exit_;
return res;
}
@@ -691,7 +640,6 @@ u8 rtw_getbbreg_cmd(struct adapter *padapter, u8 offset, u8 *pval)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
res = _FAIL;
@@ -715,7 +663,6 @@ _func_enter_;
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
exit:
-_func_exit_;
return res;
}
@@ -725,7 +672,6 @@ u8 rtw_setrfreg_cmd(struct adapter *padapter, u8 offset, u32 val)
struct writeRF_parm *pwriterfparm;
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
res = _FAIL;
@@ -746,7 +692,6 @@ _func_enter_;
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
exit:
-_func_exit_;
return res;
}
@@ -757,7 +702,6 @@ u8 rtw_getrfreg_cmd(struct adapter *padapter, u8 offset, u8 *pval)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
@@ -785,33 +729,28 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
void rtw_getbbrfreg_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
{
- _func_enter_;
kfree(pcmd->parmbuf);
kfree(pcmd);
if (padapter->registrypriv.mp_mode == 1)
padapter->mppriv.workparam.bcompleted = true;
-_func_exit_;
}
void rtw_readtssi_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
{
- _func_enter_;
kfree(pcmd->parmbuf);
kfree(pcmd);
if (padapter->registrypriv.mp_mode == 1)
padapter->mppriv.workparam.bcompleted = true;
-_func_exit_;
}
u8 rtw_createbss_cmd(struct adapter *padapter)
@@ -822,7 +761,6 @@ u8 rtw_createbss_cmd(struct adapter *padapter)
struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network;
u8 res = _SUCCESS;
-_func_enter_;
rtw_led_control(padapter, LED_CTL_START_TO_LINK);
@@ -847,7 +785,6 @@ _func_enter_;
res = rtw_enqueue_cmd(pcmdpriv, pcmd);
exit:
-_func_exit_;
return res;
}
@@ -858,7 +795,6 @@ u8 rtw_createbss_cmd_ex(struct adapter *padapter, unsigned char *pbss, unsigned
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (pcmd == NULL) {
@@ -877,7 +813,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -898,15 +833,13 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork)
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
-_func_enter_;
rtw_led_control(padapter, LED_CTL_START_TO_LINK);
- if (pmlmepriv->assoc_ssid.SsidLength == 0) {
+ if (pmlmepriv->assoc_ssid.SsidLength == 0)
RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+Join cmd: Any SSid\n"));
- } else {
+ else
RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.Ssid));
- }
pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (pcmd == NULL) {
@@ -952,11 +885,10 @@ _func_enter_;
psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength;
- if ((psecnetwork->IELength-12) < (256-1)) {
+ if ((psecnetwork->IELength-12) < (256-1))
memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength-12);
- } else {
+ else
memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256-1));
- }
psecnetwork->IELength = 0;
/* Added by Albert 2009/02/18 */
@@ -987,9 +919,12 @@ _func_enter_;
phtpriv->ht_option = false;
if (pregistrypriv->ht_enable) {
- /* Added by Albert 2010/06/23 */
- /* For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. */
- /* Especially for Realtek 8192u SoftAP. */
+ /*
+ * Added by Albert 2010/06/23
+ * For the WEP mode, we will use the bg mode to do
+ * the connection to avoid some IOT issue.
+ * Especially for Realtek 8192u SoftAP.
+ */
if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) &&
(padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) &&
(padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) {
@@ -1020,7 +955,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -1032,7 +966,6 @@ u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueu
struct cmd_priv *cmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_disassoc_cmd\n"));
@@ -1063,7 +996,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -1076,7 +1008,6 @@ u8 rtw_setopmode_cmd(struct adapter *padapter, enum ndis_802_11_network_infra n
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
@@ -1098,7 +1029,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -1115,7 +1045,6 @@ u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key)
struct sta_info *sta = (struct sta_info *)psta;
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
@@ -1142,7 +1071,7 @@ _func_enter_;
ph2c->rsp = (u8 *)psetstakey_rsp;
ph2c->rspsz = sizeof(struct set_stakey_rsp);
- memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
+ ether_addr_copy(psetstakey_para->addr, sta->hwaddr);
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
psetstakey_para->algorithm = (unsigned char) psecuritypriv->dot11PrivacyAlgrthm;
@@ -1161,7 +1090,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -1175,7 +1103,6 @@ u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue)
struct sta_info *sta = (struct sta_info *)psta;
u8 res = _SUCCESS;
-_func_enter_;
if (!enqueue) {
clear_cam_entry(padapter, entry);
@@ -1205,7 +1132,7 @@ _func_enter_;
ph2c->rsp = (u8 *)psetstakey_rsp;
ph2c->rspsz = sizeof(struct set_stakey_rsp);
- memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
+ ether_addr_copy(psetstakey_para->addr, sta->hwaddr);
psetstakey_para->algorithm = _NO_PRIVACY_;
@@ -1215,7 +1142,6 @@ _func_enter_;
}
exit:
-_func_exit_;
return res;
}
@@ -1226,7 +1152,6 @@ u8 rtw_setrttbl_cmd(struct adapter *padapter, struct setratable_parm *prate_tab
struct setratable_parm *psetrttblparm;
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
@@ -1247,7 +1172,6 @@ _func_enter_;
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
exit:
-_func_exit_;
return res;
}
@@ -1257,7 +1181,6 @@ u8 rtw_getrttbl_cmd(struct adapter *padapter, struct getratable_rsp *pval)
struct getratable_parm *pgetrttblparm;
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
@@ -1272,8 +1195,6 @@ _func_enter_;
goto exit;
}
-/* init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); */
-
_rtw_init_listhead(&ph2c->list);
ph2c->cmdcode = GEN_CMD_CODE(_GetRaTable);
ph2c->parmbuf = (unsigned char *)pgetrttblparm;
@@ -1285,7 +1206,6 @@ _func_enter_;
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
exit:
-_func_exit_;
return res;
}
@@ -1298,7 +1218,6 @@ u8 rtw_setassocsta_cmd(struct adapter *padapter, u8 *mac_addr)
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
@@ -1324,16 +1243,15 @@ _func_enter_;
ph2c->rsp = (u8 *)psetassocsta_rsp;
ph2c->rspsz = sizeof(struct set_assocsta_rsp);
- memcpy(psetassocsta_para->addr, mac_addr, ETH_ALEN);
+ ether_addr_copy(psetassocsta_para->addr, mac_addr);
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
exit:
-_func_exit_;
return res;
- }
+}
u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr)
{
@@ -1342,7 +1260,6 @@ u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr)
struct addBaReq_parm *paddbareq_parm;
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
@@ -1369,7 +1286,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -1381,7 +1297,6 @@ u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
@@ -1406,7 +1321,6 @@ _func_enter_;
/* rtw_enqueue_cmd(pcmdpriv, ph2c); */
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
exit:
-_func_exit_;
return res;
}
@@ -1418,7 +1332,6 @@ u8 rtw_set_ch_cmd(struct adapter *padapter, u8 ch, u8 bw, u8 ch_offset, u8 enque
u8 res = _SUCCESS;
-_func_enter_;
DBG_88E(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n",
FUNC_NDEV_ARG(padapter->pnetdev), ch, bw, ch_offset);
@@ -1460,7 +1373,6 @@ exit:
DBG_88E(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev), res);
-_func_exit_;
return res;
}
@@ -1473,7 +1385,6 @@ u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue)
u8 res = _SUCCESS;
-_func_enter_;
RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_chplan_cmd\n"));
@@ -1516,7 +1427,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -1529,7 +1439,6 @@ u8 rtw_led_blink_cmd(struct adapter *padapter, struct LED_871x *pLed)
u8 res = _SUCCESS;
-_func_enter_;
RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_led_blink_cmd\n"));
@@ -1553,7 +1462,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -1566,7 +1474,6 @@ u8 rtw_set_csa_cmd(struct adapter *padapter, u8 new_ch_no)
u8 res = _SUCCESS;
-_func_enter_;
RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_csa_cmd\n"));
@@ -1590,7 +1497,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -1685,7 +1591,6 @@ static void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
u8 mstatus;
-_func_enter_;
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true))
@@ -1724,7 +1629,6 @@ _func_enter_;
break;
}
-_func_exit_;
}
u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
@@ -1735,11 +1639,6 @@ u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
/* struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; */
u8 res = _SUCCESS;
-_func_enter_;
-
- /* if (!pwrctrlpriv->bLeisurePs) */
- /* return res; */
-
if (enqueue) {
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
@@ -1767,7 +1666,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -1785,7 +1683,6 @@ u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 min_time)
u8 res = _SUCCESS;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
res = _FAIL;
@@ -1806,7 +1703,6 @@ _func_enter_;
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
exit:
-_func_exit_;
return res;
}
@@ -1824,7 +1720,6 @@ u8 rtw_antenna_select_cmd(struct adapter *padapter, u8 antenna, u8 enqueue)
u8 support_ant_div;
u8 res = _SUCCESS;
-_func_enter_;
rtw_hal_get_def_var(padapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &support_ant_div);
if (!support_ant_div)
return res;
@@ -1854,7 +1749,6 @@ _func_enter_;
}
exit:
-_func_exit_;
return res;
}
@@ -1873,7 +1767,6 @@ u8 p2p_protocol_wk_cmd(struct adapter *padapter, int intCmdType)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
return res;
@@ -1892,8 +1785,8 @@ _func_enter_;
}
pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID;
- pdrvextra_cmd_parm->type_size = intCmdType; /* As the command tppe. */
- pdrvextra_cmd_parm->pbuf = NULL; /* Must be NULL here */
+ pdrvextra_cmd_parm->type_size = intCmdType; /* As the command tppe. */
+ pdrvextra_cmd_parm->pbuf = NULL; /* Must be NULL here */
init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
@@ -1901,7 +1794,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -1914,7 +1806,6 @@ u8 rtw_ps_cmd(struct adapter *padapter)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
ppscmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ppscmd == NULL) {
@@ -1937,7 +1828,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -2084,12 +1974,16 @@ static void c2h_wk_callback(struct work_struct *work)
evtpriv->c2h_wk_alive = true;
while (!rtw_cbuf_empty(evtpriv->c2h_queue)) {
- if ((c2h_evt = (struct c2h_evt_hdr *)rtw_cbuf_pop(evtpriv->c2h_queue)) != NULL) {
+ c2h_evt = (struct c2h_evt_hdr *)
+ rtw_cbuf_pop(evtpriv->c2h_queue);
+ if (c2h_evt != NULL)
/* This C2H event is read, clear it */
c2h_evt_clear(adapter);
- } else if ((c2h_evt = (struct c2h_evt_hdr *)rtw_malloc(16)) != NULL) {
+ else {
+ c2h_evt = (struct c2h_evt_hdr *)rtw_malloc(16);
/* This C2H event is not read, read & clear now */
- if (c2h_evt_read(adapter, (u8 *)c2h_evt) != _SUCCESS)
+ if (c2h_evt != NULL &&
+ c2h_evt_read(adapter, (u8 *)c2h_evt) != _SUCCESS)
continue;
}
@@ -2147,8 +2041,10 @@ u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf)
p2p_ps_wk_hdl(padapter, pdrvextra_cmd->type_size);
break;
case P2P_PROTO_WK_CID:
- /* Commented by Albert 2011/07/01 */
- /* I used the type_size as the type command */
+ /*
+ * Commented by Albert 2011/07/01
+ * I used the type_size as the type command
+ */
p2p_protocol_wk_hdl(padapter, pdrvextra_cmd->type_size);
break;
#endif
@@ -2174,13 +2070,12 @@ void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-_func_enter_;
if (pcmd->res == H2C_DROPPED) {
/* TODO: cancel timer and do timeout handler directly... */
/* need to make timeout handlerOS independent */
_set_timer(&pmlmepriv->scan_to_timer, 1);
- } else if (pcmd->res != H2C_SUCCESS) {
+ } else if (pcmd->res != H2C_SUCCESS) {
_set_timer(&pmlmepriv->scan_to_timer, 1);
RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: MgntActrtw_set_802_11_bssid_LIST_SCAN Fail ************\n\n."));
}
@@ -2188,13 +2083,11 @@ _func_enter_;
/* free cmd */
rtw_free_cmd_obj(pcmd);
-_func_exit_;
}
void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-_func_enter_;
if (pcmd->res != H2C_SUCCESS) {
spin_lock_bh(&pmlmepriv->lock);
@@ -2202,24 +2095,18 @@ _func_enter_;
spin_unlock_bh(&pmlmepriv->lock);
RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ***Error: disconnect_cmd_callback Fail ***\n."));
-
- goto exit;
+ return;
} else /* clear bridge database */
nat25_db_cleanup(padapter);
/* free cmd */
rtw_free_cmd_obj(pcmd);
-
-exit:
-
-_func_exit_;
}
void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-_func_enter_;
if (pcmd->res == H2C_DROPPED) {
/* TODO: cancel timer and do timeout handler directly... */
@@ -2232,7 +2119,6 @@ _func_enter_;
rtw_free_cmd_obj(pcmd);
-_func_exit_;
}
void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
@@ -2244,9 +2130,8 @@ void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf;
struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
-_func_enter_;
- if ((pcmd->res != H2C_SUCCESS)) {
+ if (pcmd->res != H2C_SUCCESS) {
RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: rtw_createbss_cmd_callback Fail ************\n\n."));
_set_timer(&pmlmepriv->assoc_timer, 1);
}
@@ -2261,7 +2146,7 @@ _func_enter_;
psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress);
if (psta == NULL) {
RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nCan't alloc sta_info when createbss_cmd_callback\n"));
- goto createbss_cmd_fail ;
+ goto createbss_cmd_fail;
}
}
@@ -2298,7 +2183,6 @@ createbss_cmd_fail:
rtw_free_cmd_obj(pcmd);
-_func_exit_;
}
void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
@@ -2307,7 +2191,6 @@ void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pc
struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)(pcmd->rsp);
struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr);
-_func_enter_;
if (psta == NULL) {
RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: rtw_setstaKey_cmdrsp_callback => can't get sta_info\n\n"));
@@ -2315,7 +2198,6 @@ _func_enter_;
}
exit:
rtw_free_cmd_obj(pcmd);
-_func_exit_;
}
void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
@@ -2326,7 +2208,6 @@ void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *
struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *)(pcmd->rsp);
struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr);
-_func_enter_;
if (psta == NULL) {
RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: setassocsta_cmdrsp_callbac => can't get sta_info\n\n"));
@@ -2347,5 +2228,4 @@ _func_enter_;
exit:
rtw_free_cmd_obj(pcmd);
-_func_exit_;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_debug.c b/drivers/staging/rtl8188eu/core/rtw_debug.c
index af32041a1e97..2beb2695e0f2 100644
--- a/drivers/staging/rtl8188eu/core/rtw_debug.c
+++ b/drivers/staging/rtl8188eu/core/rtw_debug.c
@@ -233,7 +233,7 @@ int proc_get_rf_info(char *page, char **start,
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
int len = 0;
- len += snprintf(page + len, count - len, "cur_ch=%d, cur_bw=%d, cur_ch_offet=%d\n",
+ len += snprintf(page + len, count - len, "cur_ch=%d, cur_bw=%d, cur_ch_offset=%d\n",
pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);
*eof = 1;
return len;
@@ -783,7 +783,7 @@ int proc_set_rx_stbc(struct file *file, const char __user *buffer,
if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
if (pregpriv) {
pregpriv->rx_stbc = mode;
- printk("rx_stbc=%d\n", mode);
+ netdev_info(dev, "rx_stbc=%d\n", mode);
}
}
return count;
@@ -820,7 +820,7 @@ int proc_set_rssi_disp(struct file *file, const char __user *buffer,
if (enable) {
DBG_88E("Turn On Rx RSSI Display Function\n");
- padapter->bRxRSSIDisplay = enable ;
+ padapter->bRxRSSIDisplay = enable;
} else {
DBG_88E("Turn Off Rx RSSI Display Function\n");
padapter->bRxRSSIDisplay = 0;
@@ -851,12 +851,12 @@ int proc_get_all_sta_info(char *page, char **start,
for (i = 0; i < NUM_STA; i++) {
phead = &(pstapriv->sta_hash[i]);
- plist = get_next(phead);
+ plist = phead->next;
while ((rtw_end_of_queue_search(phead, plist)) == false) {
- psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+ psta = container_of(plist, struct sta_info, hash_list);
- plist = get_next(plist);
+ plist = plist->next;
len += snprintf(page + len, count - len, "sta's macaddr: %pM\n", psta->hwaddr);
len += snprintf(page + len, count - len, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self);
diff --git a/drivers/staging/rtl8188eu/core/rtw_efuse.c b/drivers/staging/rtl8188eu/core/rtw_efuse.c
index 6149e3aaa011..40afe48a12ef 100644
--- a/drivers/staging/rtl8188eu/core/rtw_efuse.c
+++ b/drivers/staging/rtl8188eu/core/rtw_efuse.c
@@ -76,11 +76,10 @@ Efuse_Write1ByteToFakeContent(
{
if (Offset >= EFUSE_MAX_HW_SIZE)
return false;
- if (fakeEfuseBank == 0) {
+ if (fakeEfuseBank == 0)
fakeEfuseContent[Offset] = Value;
- } else {
+ else
fakeBTEfuseContent[fakeEfuseBank-1][Offset] = Value;
- }
return true;
}
@@ -156,17 +155,15 @@ Efuse_CalculateWordCnts(u8 word_en)
return word_cnts;
}
-/* */
-/* Description: */
-/* Execute E-Fuse read byte operation. */
-/* Referred from SD1 Richard. */
-/* */
-/* Assumption: */
-/* 1. Boot from E-Fuse and successfully auto-load. */
-/* 2. PASSIVE_LEVEL (USB interface) */
-/* */
-/* Created by Roger, 2008.10.21. */
-/* */
+/*
+ * Description:
+ * Execute E-Fuse read byte operation.
+ * Referred from SD1 Richard.
+ * Assumption:
+ * 1. Boot from E-Fuse and successfully auto-load.
+ * 2. PASSIVE_LEVEL (USB interface)
+ * Created by Roger, 2008.10.21.
+ */
void
ReadEFuseByte(
struct adapter *Adapter,
@@ -210,23 +207,21 @@ ReadEFuseByte(
*pbuf = (u8)(value32 & 0xff);
}
-/* */
-/* Description: */
-/* 1. Execute E-Fuse read byte operation according as map offset and */
-/* save to E-Fuse table. */
-/* 2. Referred from SD1 Richard. */
-/* */
-/* Assumption: */
-/* 1. Boot from E-Fuse and successfully auto-load. */
-/* 2. PASSIVE_LEVEL (USB interface) */
-/* */
-/* Created by Roger, 2008.10.21. */
-/* */
-/* 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. */
-/* 2. Add efuse utilization collect. */
-/* 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 */
-/* write addr must be after sec5. */
-/* */
+/* Description:
+ * 1. Execute E-Fuse read byte operation according as map offset and
+ * save to E-Fuse table.
+ * 2. Referred from SD1 Richard.
+ * Assumption:
+ * 1. Boot from E-Fuse and successfully auto-load.
+ * 2. PASSIVE_LEVEL (USB interface)
+ * Created by Roger, 2008.10.21.
+ * 2008/12/12 MH
+ * 1. Reorganize code flow and reserve bytes. and add description.
+ * 2. Add efuse utilization collect.
+ * 2008/12/22 MH
+ * Read Efuse must check if we write section 1 data again!!!
+ * Sec1 write addr must be after sec5.
+ */
static void efuse_ReadEFuse(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool pseudo)
{
@@ -450,7 +445,7 @@ u8 rtw_efuse_access(struct adapter *padapter, u8 write, u16 start_addr, u16 cnts
{
int i = 0;
u16 real_content_len = 0, max_available_size = 0;
- u8 res = _FAIL ;
+ u8 res = _FAIL;
u8 (*rw8)(struct adapter *, u16, u8*);
EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&real_content_len, false);
diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
index e6f98fb8f113..0552019d1cf7 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
@@ -147,7 +147,6 @@ u8 *rtw_set_ie
uint *frlen /* frame length */
)
{
-_func_enter_;
*pbuf = (u8)index;
*(pbuf + 1) = (u8)len;
@@ -157,7 +156,6 @@ _func_enter_;
*frlen = *frlen + (len + 2);
-_func_exit_;
return pbuf + len + 2;
}
@@ -221,11 +219,8 @@ u8 *rtw_get_ie(u8 *pbuf, int index, int *len, int limit)
{
int tmp, i;
u8 *p;
-_func_enter_;
- if (limit < 1) {
- _func_exit_;
+ if (limit < 1)
return NULL;
- }
p = pbuf;
i = 0;
@@ -242,7 +237,6 @@ _func_enter_;
if (i >= limit)
break;
}
-_func_exit_;
return NULL;
}
@@ -273,7 +267,7 @@ u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, u
cnt = 0;
while (cnt < in_len) {
- if (eid == in_ie[cnt] && (!oui || _rtw_memcmp(&in_ie[cnt+2], oui, oui_len))) {
+ if (eid == in_ie[cnt] && (!oui || !memcmp(&in_ie[cnt+2], oui, oui_len))) {
target_ie = &in_ie[cnt];
if (ie)
@@ -339,7 +333,6 @@ exit:
void rtw_set_supported_rate(u8 *SupportedRates, uint mode)
{
-_func_enter_;
_rtw_memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
@@ -361,13 +354,11 @@ _func_enter_;
memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
break;
}
-_func_exit_;
}
uint rtw_get_rateset_len(u8 *rateset)
{
uint i = 0;
-_func_enter_;
while (1) {
if ((rateset[i]) == 0)
break;
@@ -375,7 +366,6 @@ _func_enter_;
break;
i++;
}
-_func_exit_;
return i;
}
@@ -386,7 +376,6 @@ int rtw_generate_ie(struct registry_priv *pregistrypriv)
struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
u8 *ie = pdev_network->IEs;
-_func_enter_;
/* timestamp will be inserted by hardware */
sz += 8;
@@ -444,7 +433,6 @@ _func_enter_;
if (rateLen > 8)
ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz);
-_func_exit_;
return sz;
}
@@ -463,7 +451,7 @@ unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit)
if (pbuf) {
/* check if oui matches... */
- if (_rtw_memcmp((pbuf + 2), wpa_oui_type, sizeof (wpa_oui_type)) == false)
+ if (!memcmp((pbuf + 2), wpa_oui_type, sizeof(wpa_oui_type)) == false)
goto check_next_ie;
/* check version... */
@@ -497,15 +485,15 @@ unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit)
int rtw_get_wpa_cipher_suite(u8 *s)
{
- if (_rtw_memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == true)
+ if (!memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN))
return WPA_CIPHER_NONE;
- if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == true)
+ if (!memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN))
return WPA_CIPHER_WEP40;
- if (_rtw_memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == true)
+ if (!memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN))
return WPA_CIPHER_TKIP;
- if (_rtw_memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == true)
+ if (!memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN))
return WPA_CIPHER_CCMP;
- if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == true)
+ if (!memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN))
return WPA_CIPHER_WEP104;
return 0;
@@ -513,15 +501,15 @@ int rtw_get_wpa_cipher_suite(u8 *s)
int rtw_get_wpa2_cipher_suite(u8 *s)
{
- if (_rtw_memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == true)
+ if (!memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN))
return WPA_CIPHER_NONE;
- if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == true)
+ if (!memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN))
return WPA_CIPHER_WEP40;
- if (_rtw_memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == true)
+ if (!memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN))
return WPA_CIPHER_TKIP;
- if (_rtw_memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == true)
+ if (!memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN))
return WPA_CIPHER_CCMP;
- if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == true)
+ if (!memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN))
return WPA_CIPHER_WEP104;
return 0;
@@ -542,7 +530,7 @@ int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwis
if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie+1) != (u8)(wpa_ie_len - 2)) ||
- (_rtw_memcmp(wpa_ie+2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN) != true))
+ (memcmp(wpa_ie+2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN)))
return _FAIL;
pos = wpa_ie;
@@ -587,7 +575,7 @@ int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwis
if (is_8021x) {
if (left >= 6) {
pos += 2;
- if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) {
+ if (!memcmp(pos, SUITE_1X, 4)) {
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s : there has 802.1x auth\n", __func__));
*is_8021x = 1;
}
@@ -657,7 +645,7 @@ int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwi
if (is_8021x) {
if (left >= 6) {
pos += 2;
- if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) {
+ if (!memcmp(pos, SUITE_1X, 4)) {
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s (): there has 802.1x auth\n", __func__));
*is_8021x = 1;
}
@@ -672,7 +660,6 @@ int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie,
u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
uint cnt;
-_func_enter_;
/* Search required WPA or WPA2 IE and copy to sec_ie[] */
@@ -683,7 +670,7 @@ _func_enter_;
while (cnt < in_len) {
authmode = in_ie[cnt];
- if ((authmode == _WPA_IE_ID_) && (_rtw_memcmp(&in_ie[cnt+2], &wpa_oui[0], 4))) {
+ if ((authmode == _WPA_IE_ID_) && (!memcmp(&in_ie[cnt+2], &wpa_oui[0], 4))) {
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
("\n rtw_get_wpa_ie: sec_idx =%d in_ie[cnt+1]+2 =%d\n",
sec_idx, in_ie[cnt+1]+2));
@@ -726,7 +713,6 @@ _func_enter_;
}
}
-_func_exit_;
return *rsn_len + *wpa_len;
}
@@ -741,7 +727,7 @@ u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
eid = ie_ptr[0];
- if ((eid == _WPA_IE_ID_) && (_rtw_memcmp(&ie_ptr[2], wps_oui, 4))) {
+ if ((eid == _WPA_IE_ID_) && (!memcmp(&ie_ptr[2], wps_oui, 4))) {
*wps_ielen = ie_ptr[1]+2;
match = true;
}
@@ -774,7 +760,7 @@ u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
while (cnt < in_len) {
eid = in_ie[cnt];
- if ((eid == _WPA_IE_ID_) && (_rtw_memcmp(&in_ie[cnt+2], wps_oui, 4))) {
+ if ((eid == _WPA_IE_ID_) && (!memcmp(&in_ie[cnt+2], wps_oui, 4))) {
wpsie_ptr = &in_ie[cnt];
if (wps_ie)
@@ -813,7 +799,7 @@ u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id , u8 *buf_at
*len_attr = 0;
if ((wps_ie[0] != _VENDOR_SPECIFIC_IE_) ||
- (_rtw_memcmp(wps_ie + 2, wps_oui , 4) != true))
+ (memcmp(wps_ie + 2, wps_oui , 4)))
return attr_ptr;
/* 6 = 1(Element ID) + 1(Length) + 4(WPS OUI) */
@@ -1223,7 +1209,7 @@ u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen)
dump_stack();
return NULL;
}
- if ((eid == _VENDOR_SPECIFIC_IE_) && (_rtw_memcmp(&in_ie[cnt+2], p2p_oui, 4) == true)) {
+ if ((eid == _VENDOR_SPECIFIC_IE_) && (!memcmp(&in_ie[cnt+2], p2p_oui, 4))) {
p2p_ie_ptr = in_ie + cnt;
if (p2p_ie != NULL)
@@ -1258,7 +1244,7 @@ u8 *rtw_get_p2p_attr(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id , u8 *buf_att
*len_attr = 0;
if (!p2p_ie || (p2p_ie[0] != _VENDOR_SPECIFIC_IE_) ||
- (_rtw_memcmp(p2p_ie + 2, p2p_oui , 4) != true))
+ (memcmp(p2p_ie + 2, p2p_oui , 4)))
return attr_ptr;
/* 6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type) */
diff --git a/drivers/staging/rtl8188eu/core/rtw_io.c b/drivers/staging/rtl8188eu/core/rtw_io.c
index ff0398fca52b..7530532b3ff0 100644
--- a/drivers/staging/rtl8188eu/core/rtw_io.c
+++ b/drivers/staging/rtl8188eu/core/rtw_io.c
@@ -59,10 +59,8 @@ u8 _rtw_read8(struct adapter *adapter, u32 addr)
struct intf_hdl *pintfhdl = &(pio_priv->intf);
u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr);
- _func_enter_;
_read8 = pintfhdl->io_ops._read8;
r_val = _read8(pintfhdl, addr);
- _func_exit_;
return r_val;
}
@@ -72,11 +70,9 @@ u16 _rtw_read16(struct adapter *adapter, u32 addr)
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &(pio_priv->intf);
u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr);
-_func_enter_;
_read16 = pintfhdl->io_ops._read16;
r_val = _read16(pintfhdl, addr);
-_func_exit_;
return r_val;
}
@@ -86,11 +82,9 @@ u32 _rtw_read32(struct adapter *adapter, u32 addr)
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &(pio_priv->intf);
u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr);
-_func_enter_;
_read32 = pintfhdl->io_ops._read32;
r_val = _read32(pintfhdl, addr);
-_func_exit_;
return r_val;
}
@@ -100,11 +94,9 @@ int _rtw_write8(struct adapter *adapter, u32 addr, u8 val)
struct intf_hdl *pintfhdl = &(pio_priv->intf);
int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val);
int ret;
- _func_enter_;
_write8 = pintfhdl->io_ops._write8;
ret = _write8(pintfhdl, addr, val);
- _func_exit_;
return RTW_STATUS_CODE(ret);
}
@@ -115,11 +107,9 @@ int _rtw_write16(struct adapter *adapter, u32 addr, u16 val)
struct intf_hdl *pintfhdl = &(pio_priv->intf);
int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val);
int ret;
- _func_enter_;
_write16 = pintfhdl->io_ops._write16;
ret = _write16(pintfhdl, addr, val);
- _func_exit_;
return RTW_STATUS_CODE(ret);
}
@@ -129,11 +119,9 @@ int _rtw_write32(struct adapter *adapter, u32 addr, u32 val)
struct intf_hdl *pintfhdl = &(pio_priv->intf);
int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val);
int ret;
- _func_enter_;
_write32 = pintfhdl->io_ops._write32;
ret = _write32(pintfhdl, addr, val);
- _func_exit_;
return RTW_STATUS_CODE(ret);
}
@@ -144,11 +132,9 @@ int _rtw_writeN(struct adapter *adapter, u32 addr , u32 length , u8 *pdata)
struct intf_hdl *pintfhdl = (struct intf_hdl *)(&(pio_priv->intf));
int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata);
int ret;
- _func_enter_;
_writeN = pintfhdl->io_ops._writeN;
ret = _writeN(pintfhdl, addr, length, pdata);
- _func_exit_;
return RTW_STATUS_CODE(ret);
}
@@ -158,11 +144,9 @@ int _rtw_write8_async(struct adapter *adapter, u32 addr, u8 val)
struct intf_hdl *pintfhdl = &(pio_priv->intf);
int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val);
int ret;
- _func_enter_;
_write8_async = pintfhdl->io_ops._write8_async;
ret = _write8_async(pintfhdl, addr, val);
- _func_exit_;
return RTW_STATUS_CODE(ret);
}
@@ -174,10 +158,8 @@ int _rtw_write16_async(struct adapter *adapter, u32 addr, u16 val)
int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val);
int ret;
-_func_enter_;
_write16_async = pintfhdl->io_ops._write16_async;
ret = _write16_async(pintfhdl, addr, val);
-_func_exit_;
return RTW_STATUS_CODE(ret);
}
@@ -189,10 +171,8 @@ int _rtw_write32_async(struct adapter *adapter, u32 addr, u32 val)
int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val);
int ret;
-_func_enter_;
_write32_async = pintfhdl->io_ops._write32_async;
ret = _write32_async(pintfhdl, addr, val);
-_func_exit_;
return RTW_STATUS_CODE(ret);
}
@@ -203,7 +183,6 @@ void _rtw_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &(pio_priv->intf);
- _func_enter_;
if (adapter->bDriverStopped || adapter->bSurpriseRemoved) {
RT_TRACE(_module_rtl871x_io_c_, _drv_info_,
("rtw_read_mem:bDriverStopped(%d) OR bSurpriseRemoved(%d)",
@@ -212,7 +191,6 @@ void _rtw_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
}
_read_mem = pintfhdl->io_ops._read_mem;
_read_mem(pintfhdl, addr, cnt, pmem);
- _func_exit_;
}
void _rtw_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
@@ -221,13 +199,11 @@ void _rtw_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &(pio_priv->intf);
- _func_enter_;
_write_mem = pintfhdl->io_ops._write_mem;
_write_mem(pintfhdl, addr, cnt, pmem);
- _func_exit_;
}
void _rtw_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
@@ -236,7 +212,6 @@ void _rtw_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &(pio_priv->intf);
- _func_enter_;
if (adapter->bDriverStopped || adapter->bSurpriseRemoved) {
RT_TRACE(_module_rtl871x_io_c_, _drv_info_,
@@ -249,7 +224,6 @@ void _rtw_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
_read_port(pintfhdl, addr, cnt, pmem);
- _func_exit_;
}
void _rtw_read_port_cancel(struct adapter *adapter)
@@ -271,13 +245,11 @@ u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
struct intf_hdl *pintfhdl = &(pio_priv->intf);
u32 ret = _SUCCESS;
- _func_enter_;
_write_port = pintfhdl->io_ops._write_port;
ret = _write_port(pintfhdl, addr, cnt, pmem);
- _func_exit_;
return ret;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
index e25b39b97d9e..f1398ab01d7b 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
@@ -42,7 +42,6 @@ u8 rtw_validate_ssid(struct ndis_802_11_ssid *ssid)
u8 i;
u8 ret = true;
-_func_enter_;
if (ssid->SsidLength > 32) {
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("ssid length >32\n"));
@@ -61,8 +60,6 @@ _func_enter_;
exit:
-_func_exit_;
-
return ret;
}
@@ -74,11 +71,10 @@ u8 rtw_do_join(struct adapter *padapter)
struct __queue *queue = &(pmlmepriv->scanned_queue);
u8 ret = _SUCCESS;
-_func_enter_;
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("\n rtw_do_join: phead = %p; plist = %p\n\n\n", phead, plist));
@@ -170,7 +166,6 @@ _func_enter_;
exit:
-_func_exit_;
return ret;
}
@@ -181,7 +176,6 @@ u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid)
u32 cur_time = 0;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-_func_enter_;
DBG_88E_LEVEL(_drv_info_, "set bssid:%pM\n", bssid);
@@ -205,7 +199,7 @@ _func_enter_;
if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) {
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n"));
- if (_rtw_memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN)) {
+ if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN)) {
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false)
goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */
} else {
@@ -257,7 +251,6 @@ exit:
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
("rtw_set_802_11_bssid: status=%d\n", status));
-_func_exit_;
return status;
}
@@ -270,7 +263,6 @@ u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_network *pnetwork = &pmlmepriv->cur_network;
-_func_enter_;
DBG_88E_LEVEL(_drv_info_, "set ssid [%s] fw_state=0x%08x\n",
ssid->Ssid, get_fwstate(pmlmepriv));
@@ -285,18 +277,17 @@ _func_enter_;
spin_lock_bh(&pmlmepriv->lock);
DBG_88E("Set SSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv));
- if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) {
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true)
goto handle_tkip_countermeasure;
- } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) {
+ else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true)
goto release_mlme_lock;
- }
if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) {
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("set_ssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n"));
if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) &&
- (_rtw_memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength))) {
+ (!memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength))) {
if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false)) {
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
("Set SSID is the same ssid, fw_state = 0x%08x\n",
@@ -357,11 +348,10 @@ handle_tkip_countermeasure:
memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid));
pmlmepriv->assoc_by_bssid = false;
- if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) {
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true)
pmlmepriv->to_join = true;
- } else {
+ else
status = rtw_do_join(padapter);
- }
release_mlme_lock:
spin_unlock_bh(&pmlmepriv->lock);
@@ -369,7 +359,6 @@ release_mlme_lock:
exit:
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
("-rtw_set_802_11_ssid: status =%d\n", status));
-_func_exit_;
return status;
}
@@ -380,7 +369,6 @@ u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter,
struct wlan_network *cur_network = &pmlmepriv->cur_network;
enum ndis_802_11_network_infra *pold_state = &(cur_network->network.InfrastructureMode);
-_func_enter_;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_notice_,
("+rtw_set_802_11_infrastructure_mode: old =%d new =%d fw_state = 0x%08x\n",
@@ -411,7 +399,7 @@ _func_enter_;
if ((*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) {
if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
- rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have chked whether issue dis-assoc_cmd or not */
+ rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have checked whether issue dis-assoc_cmd or not */
}
*pold_state = networktype;
@@ -438,7 +426,6 @@ _func_enter_;
spin_unlock_bh(&pmlmepriv->lock);
}
-_func_exit_;
return true;
}
@@ -448,7 +435,6 @@ u8 rtw_set_802_11_disassociate(struct adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-_func_enter_;
spin_lock_bh(&pmlmepriv->lock);
@@ -464,7 +450,6 @@ _func_enter_;
spin_unlock_bh(&pmlmepriv->lock);
-_func_exit_;
return true;
}
@@ -474,7 +459,6 @@ u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_s
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
u8 res = true;
-_func_enter_;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("+rtw_set_802_11_bssid_list_scan(), fw_state =%x\n", get_fwstate(pmlmepriv)));
@@ -494,11 +478,12 @@ _func_enter_;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_set_802_11_bssid_list_scan fail since fw_state = %x\n", get_fwstate(pmlmepriv)));
res = true;
- if (check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)) == true) {
+ if (check_fwstate(pmlmepriv,
+ (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)) == true)
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###_FW_UNDER_SURVEY|_FW_UNDER_LINKING\n\n"));
- } else {
+ else
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###pmlmepriv->sitesurveyctrl.traffic_busy == true\n\n"));
- }
+
} else {
if (rtw_is_scan_deny(padapter)) {
DBG_88E(FUNC_ADPT_FMT": scan deny\n", FUNC_ADPT_ARG(padapter));
@@ -514,7 +499,6 @@ _func_enter_;
}
exit:
-_func_exit_;
return res;
}
@@ -525,7 +509,6 @@ u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum ndis_802_11
int res;
u8 ret;
-_func_enter_;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_802_11_auth.mode(): mode =%x\n", authmode));
@@ -545,7 +528,6 @@ _func_enter_;
else
ret = false;
-_func_exit_;
return ret;
}
@@ -556,7 +538,6 @@ u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep)
struct security_priv *psecuritypriv = &(padapter->securitypriv);
u8 ret = _SUCCESS;
-_func_enter_;
keyid = wep->KeyIndex & 0x3fffffff;
@@ -581,7 +562,7 @@ _func_enter_;
break;
}
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
- ("rtw_set_802_11_add_wep:befor memcpy, wep->KeyLength = 0x%x wep->KeyIndex = 0x%x keyid =%x\n",
+ ("rtw_set_802_11_add_wep:before memcpy, wep->KeyLength = 0x%x wep->KeyIndex = 0x%x keyid =%x\n",
wep->KeyLength, wep->KeyIndex, keyid));
memcpy(&(psecuritypriv->dot11DefKey[keyid].skey[0]), &(wep->KeyMaterial), wep->KeyLength);
@@ -611,7 +592,6 @@ _func_enter_;
if (res == _FAIL)
ret = false;
exit:
-_func_exit_;
return ret;
}
@@ -619,7 +599,6 @@ u8 rtw_set_802_11_remove_wep(struct adapter *padapter, u32 keyindex)
{
u8 ret = _SUCCESS;
-_func_enter_;
if (keyindex >= 0x80000000 || padapter == NULL) {
ret = false;
goto exit;
@@ -638,7 +617,6 @@ _func_enter_;
}
exit:
-_func_exit_;
return ret;
}
@@ -651,7 +629,6 @@ u8 rtw_set_802_11_add_key(struct adapter *padapter, struct ndis_802_11_key *key)
u8 bgrouptkey = false;/* can be removed later */
u8 ret = _SUCCESS;
-_func_enter_;
if (((key->KeyIndex & 0x80000000) == 0) && ((key->KeyIndex & 0x40000000) > 0)) {
/* It is invalid to clear bit 31 and set bit 30. If the miniport driver encounters this combination, */
@@ -992,7 +969,6 @@ _func_enter_;
}
exit:
-_func_exit_;
return ret;
}
@@ -1004,7 +980,6 @@ u8 rtw_set_802_11_remove_key(struct adapter *padapter, struct ndis_802_11_remove
u8 keyIndex = (u8)key->KeyIndex & 0x03;
u8 ret = _SUCCESS;
-_func_enter_;
if ((key->KeyIndex & 0xbffffffc) > 0) {
ret = _FAIL;
@@ -1032,7 +1007,6 @@ _func_enter_;
}
exit:
-_func_exit_;
return ret;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_led.c b/drivers/staging/rtl8188eu/core/rtw_led.c
index afac53709843..42b41ab1bce1 100644
--- a/drivers/staging/rtl8188eu/core/rtw_led.c
+++ b/drivers/staging/rtl8188eu/core/rtw_led.c
@@ -34,7 +34,7 @@ void BlinkTimerCallback(void *data)
if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
return;
- _set_workitem(&(pLed->BlinkWorkItem));
+ schedule_work(&(pLed->BlinkWorkItem));
}
/* */
@@ -80,7 +80,7 @@ void InitLed871x(struct adapter *padapter, struct LED_871x *pLed, enum LED_PIN_8
_init_timer(&(pLed->BlinkTimer), padapter->pnetdev, BlinkTimerCallback, pLed);
- _init_workitem(&(pLed->BlinkWorkItem), BlinkWorkItemCallback, pLed);
+ INIT_WORK(&(pLed->BlinkWorkItem), BlinkWorkItemCallback);
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c
index c7382303088f..769d4ddc6754 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c
@@ -31,11 +31,12 @@
#include <wlan_bssdef.h>
#include <rtw_ioctl_set.h>
#include <usb_osintf.h>
+#include <linux/vmalloc.h>
extern unsigned char MCS_rate_2R[16];
extern unsigned char MCS_rate_1R[16];
-int _rtw_init_mlme_priv (struct adapter *padapter)
+int _rtw_init_mlme_priv(struct adapter *padapter)
{
int i;
u8 *pbuf;
@@ -43,9 +44,7 @@ int _rtw_init_mlme_priv (struct adapter *padapter)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
int res = _SUCCESS;
-_func_enter_;
-
- /* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */
+ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */
pmlmepriv->nic_hdl = (u8 *)padapter;
@@ -62,7 +61,7 @@ _func_enter_;
_rtw_memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid));
- pbuf = rtw_zvmalloc(MAX_BSS_CNT * (sizeof(struct wlan_network)));
+ pbuf = vzalloc(MAX_BSS_CNT * (sizeof(struct wlan_network)));
if (pbuf == NULL) {
res = _FAIL;
@@ -87,13 +86,10 @@ _func_enter_;
rtw_init_mlme_timer(padapter);
exit:
-
-_func_exit_;
-
return res;
}
-#if defined (CONFIG_88EU_AP_MODE)
+#if defined(CONFIG_88EU_AP_MODE)
static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen)
{
kfree(*ppie);
@@ -122,24 +118,18 @@ void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv)
}
#endif
-void _rtw_free_mlme_priv (struct mlme_priv *pmlmepriv)
+void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv)
{
-_func_enter_;
-
rtw_free_mlme_priv_ie_data(pmlmepriv);
if (pmlmepriv) {
- if (pmlmepriv->free_bss_buf) {
- rtw_vmfree(pmlmepriv->free_bss_buf, MAX_BSS_CNT * sizeof(struct wlan_network));
- }
+ if (pmlmepriv->free_bss_buf)
+ vfree(pmlmepriv->free_bss_buf);
}
-_func_exit_;
}
int _rtw_enqueue_network(struct __queue *queue, struct wlan_network *pnetwork)
{
-_func_enter_;
-
if (pnetwork == NULL)
goto exit;
@@ -150,9 +140,6 @@ _func_enter_;
spin_unlock_bh(&queue->lock);
exit:
-
-_func_exit_;
-
return _SUCCESS;
}
@@ -160,22 +147,18 @@ struct wlan_network *_rtw_dequeue_network(struct __queue *queue)
{
struct wlan_network *pnetwork;
-_func_enter_;
-
spin_lock_bh(&queue->lock);
if (_rtw_queue_empty(queue)) {
pnetwork = NULL;
} else {
- pnetwork = LIST_CONTAINOR(get_next(&queue->queue), struct wlan_network, list);
+ pnetwork = container_of((&queue->queue)->next, struct wlan_network, list);
rtw_list_delete(&(pnetwork->list));
}
spin_unlock_bh(&queue->lock);
-_func_exit_;
-
return pnetwork;
}
@@ -185,17 +168,15 @@ struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv)/* _queue *f
struct __queue *free_queue = &pmlmepriv->free_bss_pool;
struct list_head *plist = NULL;
-_func_enter_;
-
spin_lock_bh(&free_queue->lock);
if (_rtw_queue_empty(free_queue) == true) {
pnetwork = NULL;
goto exit;
}
- plist = get_next(&(free_queue->queue));
+ plist = free_queue->queue.next;
- pnetwork = LIST_CONTAINOR(plist , struct wlan_network, list);
+ pnetwork = container_of(plist , struct wlan_network, list);
rtw_list_delete(&pnetwork->list);
@@ -211,8 +192,6 @@ _func_enter_;
exit:
spin_unlock_bh(&free_queue->lock);
-_func_exit_;
-
return pnetwork;
}
@@ -222,13 +201,11 @@ void _rtw_free_network(struct mlme_priv *pmlmepriv , struct wlan_network *pnetwo
u32 lifetime = SCANQUEUE_LIFETIME;
struct __queue *free_queue = &(pmlmepriv->free_bss_pool);
-_func_enter_;
-
if (pnetwork == NULL)
- goto exit;
+ return;
if (pnetwork->fixed)
- goto exit;
+ return;
curr_time = jiffies;
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)))
@@ -236,33 +213,26 @@ _func_enter_;
if (!isfreeall) {
delta_time = (curr_time - pnetwork->last_scanned)/HZ;
if (delta_time < lifetime)/* unit:sec */
- goto exit;
+ return;
}
spin_lock_bh(&free_queue->lock);
rtw_list_delete(&(pnetwork->list));
rtw_list_insert_tail(&(pnetwork->list), &(free_queue->queue));
pmlmepriv->num_of_scanned--;
spin_unlock_bh(&free_queue->lock);
-
-exit:
-_func_exit_;
}
void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork)
{
struct __queue *free_queue = &(pmlmepriv->free_bss_pool);
-_func_enter_;
if (pnetwork == NULL)
- goto exit;
+ return;
if (pnetwork->fixed)
- goto exit;
+ return;
rtw_list_delete(&(pnetwork->list));
rtw_list_insert_tail(&(pnetwork->list), get_list_head(free_queue));
pmlmepriv->num_of_scanned--;
-exit:
-
-_func_exit_;
}
/*
@@ -276,24 +246,22 @@ struct wlan_network *_rtw_find_network(struct __queue *scanned_queue, u8 *addr)
struct wlan_network *pnetwork = NULL;
u8 zero_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
-_func_enter_;
- if (_rtw_memcmp(zero_addr, addr, ETH_ALEN)) {
+ if (!memcmp(zero_addr, addr, ETH_ALEN)) {
pnetwork = NULL;
goto exit;
}
phead = get_list_head(scanned_queue);
- plist = get_next(phead);
+ plist = phead->next;
while (plist != phead) {
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network , list);
- if (_rtw_memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN) == true)
+ pnetwork = container_of(plist, struct wlan_network , list);
+ if (!memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN))
break;
- plist = get_next(plist);
+ plist = plist->next;
}
if (plist == phead)
pnetwork = NULL;
exit:
-_func_exit_;
return pnetwork;
}
@@ -305,29 +273,24 @@ void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct __queue *scanned_queue = &pmlmepriv->scanned_queue;
-_func_enter_;
-
-
spin_lock_bh(&scanned_queue->lock);
phead = get_list_head(scanned_queue);
- plist = get_next(phead);
+ plist = phead->next;
while (rtw_end_of_queue_search(phead, plist) == false) {
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pnetwork = container_of(plist, struct wlan_network, list);
- plist = get_next(plist);
+ plist = plist->next;
_rtw_free_network(pmlmepriv, pnetwork, isfreeall);
}
spin_unlock_bh(&scanned_queue->lock);
-_func_exit_;
}
int rtw_if_up(struct adapter *padapter)
{
int res;
-_func_enter_;
if (padapter->bDriverStopped || padapter->bSurpriseRemoved ||
(check_fwstate(&padapter->mlmepriv, _FW_LINKED) == false)) {
@@ -338,8 +301,6 @@ _func_enter_;
} else {
res = true;
}
-
-_func_exit_;
return res;
}
@@ -347,14 +308,12 @@ void rtw_generate_random_ibss(u8 *pibss)
{
u32 curtime = jiffies;
-_func_enter_;
pibss[0] = 0x02; /* in ad-hoc mode bit1 must set to 1 */
pibss[1] = 0x11;
pibss[2] = 0x87;
pibss[3] = (u8)(curtime & 0xff);/* p[0]; */
pibss[4] = (u8)((curtime>>8) & 0xff);/* p[1]; */
pibss[5] = (u8)((curtime>>16) & 0xff);/* p[2]; */
-_func_exit_;
return;
}
@@ -367,11 +326,9 @@ u8 *rtw_get_capability_from_ie(u8 *ie)
u16 rtw_get_capability(struct wlan_bssid_ex *bss)
{
__le16 val;
-_func_enter_;
memcpy((u8 *)&val, rtw_get_capability_from_ie(bss->IEs), 2);
-_func_exit_;
return le16_to_cpu(val);
}
@@ -385,46 +342,34 @@ u8 *rtw_get_beacon_interval_from_ie(u8 *ie)
return ie + 8;
}
-int rtw_init_mlme_priv (struct adapter *padapter)/* struct mlme_priv *pmlmepriv) */
+int rtw_init_mlme_priv(struct adapter *padapter)
{
int res;
-_func_enter_;
res = _rtw_init_mlme_priv(padapter);/* (pmlmepriv); */
-_func_exit_;
return res;
}
-void rtw_free_mlme_priv (struct mlme_priv *pmlmepriv)
+void rtw_free_mlme_priv(struct mlme_priv *pmlmepriv)
{
-_func_enter_;
RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_mlme_priv\n"));
- _rtw_free_mlme_priv (pmlmepriv);
-_func_exit_;
+ _rtw_free_mlme_priv(pmlmepriv);
}
static struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv)
{
- struct wlan_network *pnetwork;
-_func_enter_;
- pnetwork = _rtw_alloc_network(pmlmepriv);
-_func_exit_;
- return pnetwork;
+ return _rtw_alloc_network(pmlmepriv);
}
static void rtw_free_network_nolock(struct mlme_priv *pmlmepriv,
struct wlan_network *pnetwork)
{
-_func_enter_;
_rtw_free_network_nolock(pmlmepriv, pnetwork);
-_func_exit_;
}
void rtw_free_network_queue(struct adapter *dev, u8 isfreeall)
{
-_func_enter_;
_rtw_free_network_queue(dev, isfreeall);
-_func_exit_;
}
/*
@@ -458,7 +403,7 @@ int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork)
static int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b)
{
return (a->Ssid.SsidLength == b->Ssid.SsidLength) &&
- _rtw_memcmp(a->Ssid.Ssid, b->Ssid.Ssid, a->Ssid.SsidLength);
+ !memcmp(a->Ssid.Ssid, b->Ssid.Ssid, a->Ssid.SsidLength);
}
int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst)
@@ -466,7 +411,6 @@ int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst)
u16 s_cap, d_cap;
__le16 le_scap, le_dcap;
-_func_enter_;
memcpy((u8 *)&le_scap, rtw_get_capability_from_ie(src->IEs), 2);
memcpy((u8 *)&le_dcap, rtw_get_capability_from_ie(dst->IEs), 2);
@@ -474,11 +418,9 @@ _func_enter_;
s_cap = le16_to_cpu(le_scap);
d_cap = le16_to_cpu(le_dcap);
-_func_exit_;
-
return ((src->Ssid.SsidLength == dst->Ssid.SsidLength) &&
- ((_rtw_memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN)) == true) &&
- ((_rtw_memcmp(src->Ssid.Ssid, dst->Ssid.Ssid, src->Ssid.SsidLength)) == true) &&
+ ((!memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN)) == true) &&
+ ((!memcmp(src->Ssid.Ssid, dst->Ssid.Ssid, src->Ssid.SsidLength)) == true) &&
((s_cap & WLAN_CAPABILITY_IBSS) ==
(d_cap & WLAN_CAPABILITY_IBSS)) &&
((s_cap & WLAN_CAPABILITY_BSS) ==
@@ -491,25 +433,23 @@ struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue)
struct wlan_network *pwlan = NULL;
struct wlan_network *oldest = NULL;
-_func_enter_;
phead = get_list_head(scanned_queue);
- plist = get_next(phead);
+ plist = phead->next;
while (1) {
if (rtw_end_of_queue_search(phead, plist) == true)
break;
- pwlan = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pwlan = container_of(plist, struct wlan_network, list);
if (!pwlan->fixed) {
if (oldest == NULL || time_after(oldest->last_scanned, pwlan->last_scanned))
oldest = pwlan;
}
- plist = get_next(plist);
+ plist = plist->next;
}
-_func_exit_;
return oldest;
}
@@ -522,7 +462,6 @@ void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src,
u8 sq_final;
long rssi_final;
-_func_enter_;
rtw_hal_antdiv_rssi_compared(padapter, dst, src); /* this will update src.Rssi, need consider again */
/* The rule below is 1/5 for sample value, 4/5 for history value */
@@ -553,22 +492,18 @@ _func_enter_;
dst->PhyInfo.SignalQuality = sq_final;
dst->Rssi = rssi_final;
-_func_exit_;
}
static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex *pnetwork)
{
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
-_func_enter_;
-
if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) &&
(is_same_network(&(pmlmepriv->cur_network.network), pnetwork))) {
update_network(&(pmlmepriv->cur_network.network), pnetwork, adapter, true);
rtw_update_protection(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof(struct ndis_802_11_fixed_ie),
pmlmepriv->cur_network.network.IELength);
}
-_func_exit_;
}
/*
@@ -583,24 +518,22 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t
struct wlan_network *pnetwork = NULL;
struct wlan_network *oldest = NULL;
-_func_enter_;
-
spin_lock_bh(&queue->lock);
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
while (1) {
if (rtw_end_of_queue_search(phead, plist) == true)
break;
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pnetwork = container_of(plist, struct wlan_network, list);
if (is_same_network(&(pnetwork->network), target))
break;
if ((oldest == ((struct wlan_network *)0)) ||
time_after(oldest->last_scanned, pnetwork->last_scanned))
oldest = pnetwork;
- plist = get_next(plist);
+ plist = plist->next;
}
/* If we didn't find a match, then get a new network slot to initialize
* with this beacon's information */
@@ -663,27 +596,26 @@ _func_enter_;
exit:
spin_unlock_bh(&queue->lock);
-_func_exit_;
}
static void rtw_add_network(struct adapter *adapter,
struct wlan_bssid_ex *pnetwork)
{
-_func_enter_;
#if defined(CONFIG_88EU_P2P)
rtw_wlan_bssid_ex_remove_p2p_attr(pnetwork, P2P_ATTR_GROUP_INFO);
#endif
update_current_network(adapter, pnetwork);
rtw_update_scanned_network(adapter, pnetwork);
-_func_exit_;
}
-/* select the desired network based on the capability of the (i)bss. */
-/* check items: (1) security */
-/* (2) network_type */
-/* (3) WMM */
-/* (4) HT */
-/* (5) others */
+/*
+ * select the desired network based on the capability of the (i)bss.
+ * check items: (1) security
+ * (2) network_type
+ * (3) WMM
+ * (4) HT
+ * (5) others
+ */
static int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwork)
{
struct security_priv *psecuritypriv = &adapter->securitypriv;
@@ -728,9 +660,7 @@ static int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *
/* TODO: Perry: For Power Management */
void rtw_atimdone_event_callback(struct adapter *adapter , u8 *pbuf)
{
-_func_enter_;
RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("receive atimdone_evet\n"));
-_func_exit_;
return;
}
@@ -741,8 +671,6 @@ void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf)
struct wlan_bssid_ex *pnetwork;
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
-_func_enter_;
-
pnetwork = (struct wlan_bssid_ex *)pbuf;
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_survey_event_callback, ssid=%s\n", pnetwork->Ssid.Ssid));
@@ -756,7 +684,7 @@ _func_enter_;
/* update IBSS_network 's timestamp */
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) {
- if (_rtw_memcmp(&(pmlmepriv->cur_network.network.MacAddress), pnetwork->MacAddress, ETH_ALEN)) {
+ if (!memcmp(&(pmlmepriv->cur_network.network.MacAddress), pnetwork->MacAddress, ETH_ALEN)) {
struct wlan_network *ibss_wlan = NULL;
memcpy(pmlmepriv->cur_network.network.IEs, pnetwork->IEs, 8);
@@ -781,20 +709,14 @@ _func_enter_;
exit:
spin_unlock_bh(&pmlmepriv->lock);
-
-_func_exit_;
-
return;
}
-
-
void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf)
{
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
struct mlme_ext_priv *pmlmeext;
-_func_enter_;
spin_lock_bh(&pmlmepriv->lock);
if (pmlmepriv->wps_probe_req_ie) {
@@ -884,7 +806,6 @@ _func_enter_;
pmlmeext = &adapter->mlmeextpriv;
if (pmlmeext->sitesurvey_res.bss_cnt == 0)
rtw_hal_sreset_reset(adapter);
-_func_exit_;
}
void rtw_dummy_event_callback(struct adapter *adapter , u8 *pbuf)
@@ -901,17 +822,15 @@ static void free_scanqueue(struct mlme_priv *pmlmepriv)
struct __queue *scan_queue = &pmlmepriv->scanned_queue;
struct list_head *plist, *phead, *ptemp;
-_func_enter_;
-
RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+free_scanqueue\n"));
spin_lock_bh(&scan_queue->lock);
spin_lock_bh(&free_queue->lock);
phead = get_list_head(scan_queue);
- plist = get_next(phead);
+ plist = phead->next;
while (plist != phead) {
- ptemp = get_next(plist);
+ ptemp = plist->next;
rtw_list_delete(plist);
rtw_list_insert_tail(plist, &free_queue->queue);
plist = ptemp;
@@ -920,8 +839,6 @@ _func_enter_;
spin_unlock_bh(&free_queue->lock);
spin_unlock_bh(&scan_queue->lock);
-
-_func_exit_;
}
/*
@@ -934,8 +851,6 @@ void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue)
struct sta_priv *pstapriv = &adapter->stapriv;
struct wlan_network *tgt_network = &pmlmepriv->cur_network;
-_func_enter_;
-
RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_free_assoc_resources\n"));
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
("tgt_network->network.MacAddress=%pM ssid=%s\n",
@@ -979,7 +894,6 @@ _func_enter_;
if (lock_scanned_queue)
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
pmlmepriv->key_mask = 0;
-_func_exit_;
}
/*
@@ -989,8 +903,6 @@ void rtw_indicate_connect(struct adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-_func_enter_;
-
RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_connect\n"));
pmlmepriv->to_join = false;
@@ -1008,7 +920,6 @@ _func_enter_;
rtw_set_scan_deny(padapter, 3000);
RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-rtw_indicate_connect: fw_state=0x%08x\n", get_fwstate(pmlmepriv)));
-_func_exit_;
}
/*
@@ -1018,7 +929,6 @@ void rtw_indicate_disconnect(struct adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-_func_enter_;
RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_disconnect\n"));
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING | WIFI_UNDER_WPS);
@@ -1038,8 +948,6 @@ _func_enter_;
p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1);
rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 1);
-
-_func_exit_;
}
inline void rtw_indicate_scan_done(struct adapter *padapter, bool aborted)
@@ -1100,9 +1008,12 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str
_rtw_memset((u8 *)&psta->dot11txpn, 0, sizeof(union pn48));
_rtw_memset((u8 *)&psta->dot11rxpn, 0, sizeof(union pn48));
}
- /* Commented by Albert 2012/07/21 */
- /* When doing the WPS, the wps_ie_len won't equal to 0 */
- /* And the Wi-Fi driver shouldn't allow the data packet to be tramsmitted. */
+ /*
+ * Commented by Albert 2012/07/21
+ * When doing the WPS, the wps_ie_len won't equal to 0
+ * And the Wi-Fi driver shouldn't allow the data
+ * packet to be tramsmitted.
+ */
if (padapter->securitypriv.wps_ie_len != 0) {
psta->ieee8021x_blocked = true;
padapter->securitypriv.wps_ie_len = 0;
@@ -1206,8 +1117,6 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf)
struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL;
unsigned int the_same_macaddr = false;
-_func_enter_;
-
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("joinbss event call back received with res=%d\n", pnetwork->join_res));
rtw_get_encrypt_decrypt_from_registrypriv(adapter);
@@ -1218,12 +1127,12 @@ _func_enter_;
else
RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ rtw_joinbss_event_callback for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid));
- the_same_macaddr = _rtw_memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN);
+ the_same_macaddr = !memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN);
pnetwork->network.Length = get_wlan_bssid_ex_sz(&pnetwork->network);
if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) {
RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n ***joinbss_evt_callback return a wrong bss ***\n\n"));
- goto ignore_nolock;
+ return;
}
spin_lock_bh(&pmlmepriv->lock);
@@ -1319,27 +1228,21 @@ _func_enter_;
ignore_joinbss_callback:
spin_unlock_bh(&pmlmepriv->lock);
-ignore_nolock:
-_func_exit_;
}
void rtw_joinbss_event_callback(struct adapter *adapter, u8 *pbuf)
{
struct wlan_network *pnetwork = (struct wlan_network *)pbuf;
-_func_enter_;
-
mlmeext_joinbss_event_callback(adapter, pnetwork->join_res);
rtw_os_xmit_schedule(adapter);
-
-_func_exit_;
}
static u8 search_max_mac_id(struct adapter *padapter)
{
u8 mac_id;
-#if defined (CONFIG_88EU_AP_MODE)
+#if defined(CONFIG_88EU_AP_MODE)
u8 aid;
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct sta_priv *pstapriv = &padapter->stapriv;
@@ -1347,7 +1250,7 @@ static u8 search_max_mac_id(struct adapter *padapter)
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
-#if defined (CONFIG_88EU_AP_MODE)
+#if defined(CONFIG_88EU_AP_MODE)
if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
for (aid = (pstapriv->max_num_sta); aid > 0; aid--) {
if (pstapriv->sta_aid[aid-1] != NULL)
@@ -1388,19 +1291,17 @@ void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf)
struct wlan_network *cur_network = &(pmlmepriv->cur_network);
struct wlan_network *ptarget_wlan = NULL;
-_func_enter_;
-
if (rtw_access_ctrl(adapter, pstassoc->macaddr) == false)
return;
-#if defined (CONFIG_88EU_AP_MODE)
+#if defined(CONFIG_88EU_AP_MODE)
if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr);
if (psta) {
ap_sta_info_defer_update(adapter, psta);
rtw_stassoc_hw_rpt(adapter, psta);
}
- goto exit;
+ return;
}
#endif
/* for AD-HOC mode */
@@ -1408,12 +1309,12 @@ _func_enter_;
if (psta != NULL) {
/* the sta have been in sta_info_queue => do nothing */
RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error: rtw_stassoc_event_callback: sta has been in sta_hash_queue\n"));
- goto exit; /* between drv has received this event before and fw have not yet to set key to CAM_ENTRY) */
+ return; /* between drv has received this event before and fw have not yet to set key to CAM_ENTRY) */
}
psta = rtw_alloc_stainfo(&adapter->stapriv, pstassoc->macaddr);
if (psta == NULL) {
RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't alloc sta_info when rtw_stassoc_event_callback\n"));
- goto exit;
+ return;
}
/* to do: init sta_info variable */
psta->qos_option = 0;
@@ -1440,8 +1341,6 @@ _func_enter_;
}
spin_unlock_bh(&pmlmepriv->lock);
mlmeext_sta_add_event_callback(adapter, psta);
-exit:
-_func_exit_;
}
void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf)
@@ -1456,8 +1355,6 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf)
struct sta_priv *pstapriv = &adapter->stapriv;
struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
-_func_enter_;
-
psta = rtw_get_stainfo(&adapter->stapriv, pstadel->macaddr);
if (psta)
mac_id = psta->mac_id;
@@ -1541,14 +1438,11 @@ _func_enter_;
}
}
spin_unlock_bh(&pmlmepriv->lock);
-_func_exit_;
}
void rtw_cpwm_event_callback(struct adapter *padapter, u8 *pbuf)
{
-_func_enter_;
RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_cpwm_event_callback !!!\n"));
-_func_exit_;
}
/*
@@ -1560,8 +1454,6 @@ void _rtw_join_timeout_handler (struct adapter *adapter)
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
int do_join_r;
-_func_enter_;
-
DBG_88E("%s, fw_state=%x\n", __func__, get_fwstate(pmlmepriv));
if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
@@ -1592,7 +1484,6 @@ _func_enter_;
free_scanqueue(pmlmepriv);/* */
}
spin_unlock_bh(&pmlmepriv->lock);
-_func_exit_;
}
/*
@@ -1658,14 +1549,12 @@ void rtw_dynamic_check_timer_handlder(struct adapter *adapter)
/* expire NAT2.5 entry */
nat25_db_expire(adapter);
- if (adapter->pppoe_connection_in_progress > 0) {
+ if (adapter->pppoe_connection_in_progress > 0)
adapter->pppoe_connection_in_progress--;
- }
/* due to rtw_dynamic_check_timer_handlder() is called every 2 seconds */
- if (adapter->pppoe_connection_in_progress > 0) {
+ if (adapter->pppoe_connection_in_progress > 0)
adapter->pppoe_connection_in_progress--;
- }
}
rcu_read_unlock();
@@ -1687,14 +1576,14 @@ static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv
/* check bssid, if needed */
if (pmlmepriv->assoc_by_bssid) {
- if (!_rtw_memcmp(competitor->network.MacAddress, pmlmepriv->assoc_bssid, ETH_ALEN))
+ if (memcmp(competitor->network.MacAddress, pmlmepriv->assoc_bssid, ETH_ALEN))
goto exit;
}
/* check ssid, if needed */
- if (pmlmepriv->assoc_ssid.Ssid && pmlmepriv->assoc_ssid.SsidLength) {
+ if (pmlmepriv->assoc_ssid.SsidLength) {
if (competitor->network.Ssid.SsidLength != pmlmepriv->assoc_ssid.SsidLength ||
- _rtw_memcmp(competitor->network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength) == false)
+ !memcmp(competitor->network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength) == false)
goto exit;
}
@@ -1742,20 +1631,18 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv)
struct wlan_network *candidate = NULL;
u8 supp_ant_div = false;
-_func_enter_;
-
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
adapter = (struct adapter *)pmlmepriv->nic_hdl;
- pmlmepriv->pscanned = get_next(phead);
+ pmlmepriv->pscanned = phead->next;
while (!rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) {
- pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);
+ pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list);
if (pnetwork == NULL) {
RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s return _FAIL:(pnetwork==NULL)\n", __func__));
ret = _FAIL;
goto exit;
}
- pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+ pmlmepriv->pscanned = pmlmepriv->pscanned->next;
rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork);
}
if (candidate == NULL) {
@@ -1792,9 +1679,6 @@ _func_enter_;
exit:
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
-
-_func_exit_;
-
return ret;
}
@@ -1805,8 +1689,6 @@ int rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv)
struct cmd_priv *pcmdpriv = &(adapter->cmdpriv);
int res = _SUCCESS;
-_func_enter_;
-
pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (pcmd == NULL) {
res = _FAIL; /* try again */
@@ -1832,7 +1714,6 @@ _func_enter_;
psecuritypriv->dot11AuthAlgrthm));
res = rtw_enqueue_cmd(pcmdpriv, pcmd);
exit:
-_func_exit_;
return res;
}
@@ -1845,7 +1726,6 @@ int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, in
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
int res = _SUCCESS;
-_func_enter_;
pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (pcmd == NULL) {
res = _FAIL; /* try again */
@@ -1914,7 +1794,6 @@ _func_enter_;
_rtw_init_listhead(&pcmd->list);
res = rtw_enqueue_cmd(pcmdpriv, pcmd);
exit:
-_func_exit_;
return res;
}
@@ -1946,17 +1825,15 @@ int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_
return ielength;
}
-/* */
-/* Ported from 8185: IsInPreAuthKeyList(). (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.) */
-/* Added by Annie, 2006-05-07. */
-/* */
-/* Search by BSSID, */
-/* Return Value: */
-/* -1 :if there is no pre-auth key in the table */
-/* >= 0 :if there is pre-auth key, and return the entry id */
-/* */
-/* */
-
+/*
+ * Ported from 8185: IsInPreAuthKeyList().
+ * (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.)
+ * Added by Annie, 2006-05-07.
+ * Search by BSSID,
+ * Return Value:
+ * -1 :if there is no pre-auth key in the table
+ * >= 0 :if there is pre-auth key, and return the entry id
+ */
static int SecIsInPMKIDList(struct adapter *Adapter, u8 *bssid)
{
struct security_priv *psecuritypriv = &Adapter->securitypriv;
@@ -1964,7 +1841,7 @@ static int SecIsInPMKIDList(struct adapter *Adapter, u8 *bssid)
do {
if ((psecuritypriv->PMKIDList[i].bUsed) &&
- (_rtw_memcmp(psecuritypriv->PMKIDList[i].Bssid, bssid, ETH_ALEN) == true)) {
+ (!memcmp(psecuritypriv->PMKIDList[i].Bssid, bssid, ETH_ALEN))) {
break;
} else {
i++;
@@ -1973,11 +1850,9 @@ static int SecIsInPMKIDList(struct adapter *Adapter, u8 *bssid)
} while (i < NUM_PMKID_CACHE);
- if (i == NUM_PMKID_CACHE) {
+ if (i == NUM_PMKID_CACHE)
i = -1;/* Could not find. */
- } else {
- /* There is one Pre-Authentication Key for the specific BSSID. */
- }
+
return i;
}
@@ -2018,8 +1893,6 @@ int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_
uint ndisauthmode = psecuritypriv->ndisauthtype;
uint ndissecuritytype = psecuritypriv->ndisencryptstatus;
-_func_enter_;
-
RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
("+rtw_restruct_sec_ie: ndisauthmode=%d ndissecuritytype=%d\n",
ndisauthmode, ndissecuritytype));
@@ -2052,9 +1925,6 @@ _func_enter_;
if (authmode == _WPA2_IE_ID_)
ielength = rtw_append_pmkid(adapter, iEntry, out_ie, ielength);
}
-
-_func_exit_;
-
return ielength;
}
@@ -2065,8 +1935,6 @@ void rtw_init_registrypriv_dev_network(struct adapter *adapter)
struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
u8 *myhwaddr = myid(peepriv);
-_func_enter_;
-
memcpy(pdev_network->MacAddress, myhwaddr, ETH_ALEN);
memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, sizeof(struct ndis_802_11_ssid));
@@ -2077,8 +1945,6 @@ _func_enter_;
pdev_network->Configuration.FHConfig.HopPattern = 0;
pdev_network->Configuration.FHConfig.HopSet = 0;
pdev_network->Configuration.FHConfig.DwellTime = 0;
-
-_func_exit_;
}
void rtw_update_registrypriv_dev_network(struct adapter *adapter)
@@ -2089,8 +1955,6 @@ void rtw_update_registrypriv_dev_network(struct adapter *adapter)
struct security_priv *psecuritypriv = &adapter->securitypriv;
struct wlan_network *cur_network = &adapter->mlmepriv.cur_network;
-_func_enter_;
-
pdev_network->Privacy = (psecuritypriv->dot11PrivacyAlgrthm > 0 ? 1 : 0); /* adhoc no 802.1x */
pdev_network->Rssi = 0;
@@ -2140,13 +2004,10 @@ _func_enter_;
/* notes: translate IELength & Length after assign the Length to cmdsz in createbss_cmd(); */
/* pdev_network->IELength = cpu_to_le32(sz); */
-_func_exit_;
}
void rtw_get_encrypt_decrypt_from_registrypriv(struct adapter *adapter)
{
-_func_enter_;
-_func_exit_;
}
/* the function is at passive_level */
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
index 6f7e415ecb6c..3ed5941bedc3 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
@@ -171,7 +171,7 @@ static struct rt_channel_plan_map RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = {
{0x03}, /* 0x41, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G */
};
-static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03}; /* use the conbination for max channel numbers */
+static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03}; /* use the combination for max channel numbers */
/*
* Search the @param channel_num in given @param channel_set
@@ -414,21 +414,21 @@ void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext)
}
}
-static void _mgt_dispatcher(struct adapter *padapter, struct mlme_handler *ptable, union recv_frame *precv_frame)
+static void _mgt_dispatcher(struct adapter *padapter, struct mlme_handler *ptable, struct recv_frame *precv_frame)
{
u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *pframe = precv_frame->rx_data;
if (ptable->func) {
/* receive the frames that ra(a1) is my address or ra(a1) is bc address. */
- if (!_rtw_memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) &&
- !_rtw_memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN))
+ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) &&
+ memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN))
return;
ptable->func(padapter, precv_frame);
}
}
-void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame)
+void mgt_dispatcher(struct adapter *padapter, struct recv_frame *precv_frame)
{
int index;
struct mlme_handler *ptable;
@@ -436,7 +436,7 @@ void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
#endif /* CONFIG_88EU_AP_MODE */
u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *pframe = precv_frame->rx_data;
struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(pframe));
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
@@ -449,8 +449,8 @@ void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame)
}
/* receive the frames that ra(a1) is my address or ra(a1) is bc address. */
- if (!_rtw_memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) &&
- !_rtw_memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN))
+ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) &&
+ memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN))
return;
ptable = mlme_sta_tbl;
@@ -465,13 +465,15 @@ void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame)
if (psta != NULL) {
if (GetRetry(pframe)) {
- if (precv_frame->u.hdr.attrib.seq_num == psta->RxMgmtFrameSeqNum) {
+ if (precv_frame->attrib.seq_num ==
+ psta->RxMgmtFrameSeqNum) {
/* drop the duplicate management frame */
- DBG_88E("Drop duplicate management frame with seq_num=%d.\n", precv_frame->u.hdr.attrib.seq_num);
+ DBG_88E("Drop duplicate management frame with seq_num=%d.\n",
+ precv_frame->attrib.seq_num);
return;
}
}
- psta->RxMgmtFrameSeqNum = precv_frame->u.hdr.attrib.seq_num;
+ psta->RxMgmtFrameSeqNum = precv_frame->attrib.seq_num;
}
#ifdef CONFIG_88EU_AP_MODE
@@ -532,7 +534,7 @@ Following are the callback functions for each subtype of the management frames
*****************************************************************************/
-unsigned int OnProbeReq(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnProbeReq(struct adapter *padapter, struct recv_frame *precv_frame)
{
unsigned int ielen;
unsigned char *p;
@@ -540,8 +542,8 @@ unsigned int OnProbeReq(struct adapter *padapter, union recv_frame *precv_frame)
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct wlan_bssid_ex *cur = &(pmlmeinfo->network);
- u8 *pframe = precv_frame->u.hdr.rx_data;
- uint len = precv_frame->u.hdr.len;
+ u8 *pframe = precv_frame->rx_data;
+ uint len = precv_frame->len;
u8 is_valid_p2p_probereq = false;
#ifdef CONFIG_88EU_P2P
@@ -596,7 +598,7 @@ _continue:
if (is_valid_p2p_probereq)
goto _issue_probersp;
- if ((ielen != 0 && !_rtw_memcmp((void *)(p+2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) ||
+ if ((ielen != 0 && memcmp((void *)(p+2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) ||
(ielen == 0 && pmlmeinfo->hidden_ssid_mode))
return _SUCCESS;
@@ -609,18 +611,18 @@ _issue_probersp:
return _SUCCESS;
}
-unsigned int OnProbeRsp(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnProbeRsp(struct adapter *padapter, struct recv_frame *precv_frame)
{
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
#ifdef CONFIG_88EU_P2P
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
- u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *pframe = precv_frame->rx_data;
#endif
#ifdef CONFIG_88EU_P2P
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) {
if (pwdinfo->tx_prov_disc_info.benable) {
- if (_rtw_memcmp(pwdinfo->tx_prov_disc_info.peerIFAddr, GetAddr2Ptr(pframe), ETH_ALEN)) {
+ if (!memcmp(pwdinfo->tx_prov_disc_info.peerIFAddr, GetAddr2Ptr(pframe), ETH_ALEN)) {
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
pwdinfo->tx_prov_disc_info.benable = false;
issue_p2p_provision_request(padapter,
@@ -638,7 +640,7 @@ unsigned int OnProbeRsp(struct adapter *padapter, union recv_frame *precv_frame)
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) {
if (pwdinfo->nego_req_info.benable) {
DBG_88E("[%s] P2P State is GONEGO ING!\n", __func__);
- if (_rtw_memcmp(pwdinfo->nego_req_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN)) {
+ if (!memcmp(pwdinfo->nego_req_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN)) {
pwdinfo->nego_req_info.benable = false;
issue_p2p_GO_request(padapter, pwdinfo->nego_req_info.peerDevAddr);
}
@@ -646,7 +648,7 @@ unsigned int OnProbeRsp(struct adapter *padapter, union recv_frame *precv_frame)
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) {
if (pwdinfo->invitereq_info.benable) {
DBG_88E("[%s] P2P_STATE_TX_INVITE_REQ!\n", __func__);
- if (_rtw_memcmp(pwdinfo->invitereq_info.peer_macaddr, GetAddr2Ptr(pframe), ETH_ALEN)) {
+ if (!memcmp(pwdinfo->invitereq_info.peer_macaddr, GetAddr2Ptr(pframe), ETH_ALEN)) {
pwdinfo->invitereq_info.benable = false;
issue_p2p_invitation_request(padapter, pwdinfo->invitereq_info.peer_macaddr);
}
@@ -663,7 +665,7 @@ unsigned int OnProbeRsp(struct adapter *padapter, union recv_frame *precv_frame)
return _SUCCESS;
}
-unsigned int OnBeacon(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnBeacon(struct adapter *padapter, struct recv_frame *precv_frame)
{
int cam_idx;
struct sta_info *psta;
@@ -671,8 +673,8 @@ unsigned int OnBeacon(struct adapter *padapter, union recv_frame *precv_frame)
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct sta_priv *pstapriv = &padapter->stapriv;
- u8 *pframe = precv_frame->u.hdr.rx_data;
- uint len = precv_frame->u.hdr.len;
+ u8 *pframe = precv_frame->rx_data;
+ uint len = precv_frame->len;
struct wlan_bssid_ex *pbss;
int ret = _SUCCESS;
@@ -681,7 +683,7 @@ unsigned int OnBeacon(struct adapter *padapter, union recv_frame *precv_frame)
return _SUCCESS;
}
- if (_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) {
+ if (!memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) {
if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
/* we should update current network before auth, or some IE is wrong */
pbss = (struct wlan_bssid_ex *)rtw_malloc(sizeof(struct wlan_bssid_ex));
@@ -753,7 +755,7 @@ _END_ONBEACON_:
return _SUCCESS;
}
-unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnAuth(struct adapter *padapter, struct recv_frame *precv_frame)
{
#ifdef CONFIG_88EU_AP_MODE
unsigned int auth_mode, ie_len;
@@ -767,8 +769,8 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame)
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- u8 *pframe = precv_frame->u.hdr.rx_data;
- uint len = precv_frame->u.hdr.len;
+ u8 *pframe = precv_frame->rx_data;
+ uint len = precv_frame->len;
if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
return _FAIL;
@@ -878,7 +880,7 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame)
goto auth_fail;
}
- if (_rtw_memcmp((void *)(p + 2), pstat->chg_txt, 128)) {
+ if (!memcmp((void *)(p + 2), pstat->chg_txt, 128)) {
pstat->state &= (~WIFI_FW_AUTH_STATE);
pstat->state |= WIFI_FW_AUTH_SUCCESS;
/* challenging txt is correct... */
@@ -926,20 +928,20 @@ auth_fail:
return _FAIL;
}
-unsigned int OnAuthClient(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnAuthClient(struct adapter *padapter, struct recv_frame *precv_frame)
{
unsigned int seq, len, status, offset;
unsigned char *p;
unsigned int go2asoc = 0;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- u8 *pframe = precv_frame->u.hdr.rx_data;
- uint pkt_len = precv_frame->u.hdr.len;
+ u8 *pframe = precv_frame->rx_data;
+ uint pkt_len = precv_frame->len;
DBG_88E("%s\n", __func__);
/* check A1 matches or not */
- if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN))
+ if (memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN))
return _SUCCESS;
if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE))
@@ -1001,7 +1003,7 @@ authclnt_fail:
return _FAIL;
}
-unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnAssocReq(struct adapter *padapter, struct recv_frame *precv_frame)
{
#ifdef CONFIG_88EU_AP_MODE
u16 capab_info;
@@ -1020,8 +1022,8 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct wlan_bssid_ex *cur = &(pmlmeinfo->network);
struct sta_priv *pstapriv = &padapter->stapriv;
- u8 *pframe = precv_frame->u.hdr.rx_data;
- uint pkt_len = precv_frame->u.hdr.len;
+ u8 *pframe = precv_frame->rx_data;
+ uint pkt_len = precv_frame->len;
#ifdef CONFIG_88EU_P2P
struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
u8 p2p_status_code = P2P_STATUS_SUCCESS;
@@ -1097,7 +1099,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
status = _STATS_FAILURE_;
} else {
/* check if ssid match */
- if (!_rtw_memcmp((void *)(p+2), cur->Ssid.Ssid, cur->Ssid.SsidLength))
+ if (memcmp((void *)(p+2), cur->Ssid.Ssid, cur->Ssid.SsidLength))
status = _STATS_FAILURE_;
if (ie_len != cur->Ssid.SsidLength)
@@ -1270,7 +1272,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
for (;;) {
p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset);
if (p != NULL) {
- if (_rtw_memcmp(p+2, WMM_IE, 6)) {
+ if (!memcmp(p+2, WMM_IE, 6)) {
pstat->flags |= WLAN_STA_WME;
pstat->qos_option = 1;
@@ -1470,7 +1472,7 @@ OnAssocReqFail:
return _FAIL;
}
-unsigned int OnAssocRsp(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnAssocRsp(struct adapter *padapter, struct recv_frame *precv_frame)
{
uint i;
int res;
@@ -1480,13 +1482,13 @@ unsigned int OnAssocRsp(struct adapter *padapter, union recv_frame *precv_frame)
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
/* struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); */
- u8 *pframe = precv_frame->u.hdr.rx_data;
- uint pkt_len = precv_frame->u.hdr.len;
+ u8 *pframe = precv_frame->rx_data;
+ uint pkt_len = precv_frame->len;
DBG_88E("%s\n", __func__);
/* check A1 matches or not */
- if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN))
+ if (memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN))
return _SUCCESS;
if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE)))
@@ -1524,7 +1526,7 @@ unsigned int OnAssocRsp(struct adapter *padapter, union recv_frame *precv_frame)
switch (pIE->ElementID) {
case _VENDOR_SPECIFIC_IE_:
- if (_rtw_memcmp(pIE->data, WMM_PARA_OUI, 6)) /* WMM */
+ if (!memcmp(pIE->data, WMM_PARA_OUI, 6)) /* WMM */
WMM_param_handler(padapter, pIE);
break;
case _HT_CAPABILITY_IE_: /* HT caps */
@@ -1560,19 +1562,20 @@ report_assoc_result:
return _SUCCESS;
}
-unsigned int OnDeAuth(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnDeAuth(struct adapter *padapter, struct recv_frame *precv_frame)
{
unsigned short reason;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *pframe = precv_frame->rx_data;
#ifdef CONFIG_88EU_P2P
struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
#endif /* CONFIG_88EU_P2P */
/* check A3 */
- if (!(_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
+ if (memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network),
+ ETH_ALEN))
return _SUCCESS;
#ifdef CONFIG_88EU_P2P
@@ -1623,19 +1626,20 @@ unsigned int OnDeAuth(struct adapter *padapter, union recv_frame *precv_frame)
return _SUCCESS;
}
-unsigned int OnDisassoc(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnDisassoc(struct adapter *padapter, struct recv_frame *precv_frame)
{
u16 reason;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *pframe = precv_frame->rx_data;
#ifdef CONFIG_88EU_P2P
struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
#endif /* CONFIG_88EU_P2P */
/* check A3 */
- if (!(_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
+ if (memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network),
+ ETH_ALEN))
return _SUCCESS;
#ifdef CONFIG_88EU_P2P
@@ -1685,18 +1689,18 @@ unsigned int OnDisassoc(struct adapter *padapter, union recv_frame *precv_frame)
return _SUCCESS;
}
-unsigned int OnAtim(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnAtim(struct adapter *padapter, struct recv_frame *precv_frame)
{
DBG_88E("%s\n", __func__);
return _SUCCESS;
}
-unsigned int on_action_spct(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int on_action_spct(struct adapter *padapter, struct recv_frame *precv_frame)
{
unsigned int ret = _FAIL;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
- u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *pframe = precv_frame->rx_data;
u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
u8 category;
u8 action;
@@ -1729,17 +1733,17 @@ exit:
return ret;
}
-unsigned int OnAction_qos(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnAction_qos(struct adapter *padapter, struct recv_frame *precv_frame)
{
return _SUCCESS;
}
-unsigned int OnAction_dls(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnAction_dls(struct adapter *padapter, struct recv_frame *precv_frame)
{
return _SUCCESS;
}
-unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnAction_back(struct adapter *padapter, struct recv_frame *precv_frame)
{
u8 *addr;
struct sta_info *psta = NULL;
@@ -1749,10 +1753,11 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra
unsigned short tid, status, reason_code = 0;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *pframe = precv_frame->rx_data;
struct sta_priv *pstapriv = &padapter->stapriv;
/* check RA matches or not */
- if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */
+ if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe),
+ ETH_ALEN))/* for if1, sta/ap mode */
return _SUCCESS;
DBG_88E("%s\n", __func__);
@@ -1937,7 +1942,7 @@ void issue_p2p_GO_request(struct adapter *padapter, u8 *raddr)
p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
/* Commented by Albert 20110306 */
- /* According to the P2P Specification, the group negoitation request frame should contain 9 P2P attributes */
+ /* According to the P2P Specification, the group negotiation request frame should contain 9 P2P attributes */
/* 1. P2P Capability */
/* 2. Group Owner Intent */
/* 3. Configuration Timeout */
@@ -2280,7 +2285,7 @@ static void issue_p2p_GO_response(struct adapter *padapter, u8 *raddr, u8 *frame
/* Commented by Kurt 20120113 */
/* If some device wants to do p2p handshake without sending prov_disc_req */
/* We have to get peer_req_cm from here. */
- if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) {
+ if (!memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) {
if (wps_devicepassword_id == WPS_DPID_USER_SPEC)
memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3);
else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC)
@@ -2302,7 +2307,7 @@ static void issue_p2p_GO_response(struct adapter *padapter, u8 *raddr, u8 *frame
p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
/* Commented by Albert 20100908 */
- /* According to the P2P Specification, the group negoitation response frame should contain 9 P2P attributes */
+ /* According to the P2P Specification, the group negotiation response frame should contain 9 P2P attributes */
/* 1. Status */
/* 2. P2P Capability */
/* 3. Group Owner Intent */
@@ -2604,7 +2609,7 @@ static void issue_p2p_GO_confirm(struct adapter *padapter, u8 *raddr, u8 result)
p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
/* Commented by Albert 20110306 */
- /* According to the P2P Specification, the group negoitation request frame should contain 5 P2P attributes */
+ /* According to the P2P Specification, the group negotiation request frame should contain 5 P2P attributes */
/* 1. Status */
/* 2. P2P Capability */
/* 3. Operating Channel */
@@ -2825,7 +2830,8 @@ void issue_p2p_invitation_request(struct adapter *padapter, u8 *raddr)
/* Channel Number */
p2pie[p2pielen++] = pwdinfo->invitereq_info.operating_ch; /* operating channel number */
- if (_rtw_memcmp(myid(&padapter->eeprompriv), pwdinfo->invitereq_info.go_bssid, ETH_ALEN)) {
+ if (!memcmp(myid(&padapter->eeprompriv),
+ pwdinfo->invitereq_info.go_bssid, ETH_ALEN)) {
/* P2P Group BSSID */
/* Type: */
p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID;
@@ -3260,7 +3266,7 @@ static u8 is_matched_in_profilelist(u8 *peermacaddr, struct profile_info *profil
for (i = 0; i < P2P_MAX_PERSISTENT_GROUP_NUM; i++, profileinfo++) {
DBG_88E("[%s] profileinfo_mac=%.2X %.2X %.2X %.2X %.2X %.2X\n", __func__,
profileinfo->peermac[0], profileinfo->peermac[1], profileinfo->peermac[2], profileinfo->peermac[3], profileinfo->peermac[4], profileinfo->peermac[5]);
- if (_rtw_memcmp(peermacaddr, profileinfo->peermac, ETH_ALEN)) {
+ if (!memcmp(peermacaddr, profileinfo->peermac, ETH_ALEN)) {
match_result = 1;
DBG_88E("[%s] Match!\n", __func__);
break;
@@ -3853,13 +3859,13 @@ exit:
#endif /* CONFIG_88EU_P2P */
-static s32 rtw_action_public_decache(union recv_frame *recv_frame, s32 token)
+static s32 rtw_action_public_decache(struct recv_frame *recv_frame, s32 token)
{
- struct adapter *adapter = recv_frame->u.hdr.adapter;
+ struct adapter *adapter = recv_frame->adapter;
struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv);
- u8 *frame = recv_frame->u.hdr.rx_data;
- u16 seq_ctrl = ((recv_frame->u.hdr.attrib.seq_num&0xffff) << 4) |
- (recv_frame->u.hdr.attrib.frag_num & 0xf);
+ u8 *frame = recv_frame->rx_data;
+ u16 seq_ctrl = ((recv_frame->attrib.seq_num&0xffff) << 4) |
+ (recv_frame->attrib.frag_num & 0xf);
if (GetRetry(frame)) {
if (token >= 0) {
@@ -3885,14 +3891,14 @@ static s32 rtw_action_public_decache(union recv_frame *recv_frame, s32 token)
return _SUCCESS;
}
-static unsigned int on_action_public_p2p(union recv_frame *precv_frame)
+static unsigned int on_action_public_p2p(struct recv_frame *precv_frame)
{
- u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *pframe = precv_frame->rx_data;
u8 *frame_body;
u8 dialogToken = 0;
#ifdef CONFIG_88EU_P2P
- struct adapter *padapter = precv_frame->u.hdr.adapter;
- uint len = precv_frame->u.hdr.len;
+ struct adapter *padapter = precv_frame->adapter;
+ uint len = precv_frame->len;
u8 *p2p_ie;
u32 p2p_ielen;
struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
@@ -3939,7 +3945,8 @@ static unsigned int on_action_public_p2p(union recv_frame *precv_frame)
/* Commented by Kurt 20120113 */
/* Get peer_dev_addr here if peer doesn't issue prov_disc frame. */
- if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.peerDevAddr, empty_addr, ETH_ALEN))
+ if (!memcmp(pwdinfo->rx_prov_disc_info.peerDevAddr, empty_addr,
+ ETH_ALEN))
memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN);
result = process_p2p_group_negotation_req(pwdinfo, frame_body, len);
@@ -4021,7 +4028,7 @@ static unsigned int on_action_public_p2p(union recv_frame *precv_frame)
_rtw_memset(&group_id, 0x00, sizeof(struct group_id_info));
rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *)&group_id, &attr_contentlen);
if (attr_contentlen) {
- if (_rtw_memcmp(group_id.go_device_addr, myid(&padapter->eeprompriv), ETH_ALEN)) {
+ if (!memcmp(group_id.go_device_addr, myid(&padapter->eeprompriv), ETH_ALEN)) {
/* The p2p device sending this p2p invitation request wants this Wi-Fi device to be the persistent GO. */
rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_GO);
rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
@@ -4069,7 +4076,7 @@ static unsigned int on_action_public_p2p(union recv_frame *precv_frame)
_rtw_memset(&group_id, 0x00, sizeof(struct group_id_info));
rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *)&group_id, &attr_contentlen);
if (attr_contentlen) {
- if (_rtw_memcmp(group_id.go_device_addr, myid(&padapter->eeprompriv), ETH_ALEN)) {
+ if (!memcmp(group_id.go_device_addr, myid(&padapter->eeprompriv), ETH_ALEN)) {
/* In this case, the GO can't be myself. */
rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH);
status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
@@ -4116,7 +4123,7 @@ static unsigned int on_action_public_p2p(union recv_frame *precv_frame)
pwdinfo->invitereq_info.benable = false;
if (attr_content == P2P_STATUS_SUCCESS) {
- if (_rtw_memcmp(pwdinfo->invitereq_info.go_bssid, myid(&padapter->eeprompriv), ETH_ALEN)) {
+ if (!memcmp(pwdinfo->invitereq_info.go_bssid, myid(&padapter->eeprompriv), ETH_ALEN)) {
rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
} else {
rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
@@ -4175,23 +4182,22 @@ static unsigned int on_action_public_p2p(union recv_frame *precv_frame)
return _SUCCESS;
}
-static unsigned int on_action_public_vendor(union recv_frame *precv_frame)
+static unsigned int on_action_public_vendor(struct recv_frame *precv_frame)
{
unsigned int ret = _FAIL;
- u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *pframe = precv_frame->rx_data;
u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
- if (_rtw_memcmp(frame_body + 2, P2P_OUI, 4) == true) {
+ if (!memcmp(frame_body + 2, P2P_OUI, 4))
ret = on_action_public_p2p(precv_frame);
- }
return ret;
}
-static unsigned int on_action_public_default(union recv_frame *precv_frame, u8 action)
+static unsigned int on_action_public_default(struct recv_frame *precv_frame, u8 action)
{
unsigned int ret = _FAIL;
- u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *pframe = precv_frame->rx_data;
u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
u8 token;
@@ -4206,15 +4212,15 @@ exit:
return ret;
}
-unsigned int on_action_public(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int on_action_public(struct adapter *padapter, struct recv_frame *precv_frame)
{
unsigned int ret = _FAIL;
- u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *pframe = precv_frame->rx_data;
u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
u8 category, action;
/* check RA matches or not */
- if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))
+ if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))
goto exit;
category = frame_body[0];
@@ -4235,30 +4241,30 @@ exit:
return ret;
}
-unsigned int OnAction_ht(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnAction_ht(struct adapter *padapter, struct recv_frame *precv_frame)
{
return _SUCCESS;
}
-unsigned int OnAction_wmm(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnAction_wmm(struct adapter *padapter, struct recv_frame *precv_frame)
{
return _SUCCESS;
}
-unsigned int OnAction_p2p(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnAction_p2p(struct adapter *padapter, struct recv_frame *precv_frame)
{
#ifdef CONFIG_88EU_P2P
u8 *frame_body;
u8 category, OUI_Subtype;
- u8 *pframe = precv_frame->u.hdr.rx_data;
- uint len = precv_frame->u.hdr.len;
+ u8 *pframe = precv_frame->rx_data;
+ uint len = precv_frame->len;
struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
DBG_88E("%s\n", __func__);
/* check RA matches or not */
- if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */
+ if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */
return _SUCCESS;
frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
@@ -4290,13 +4296,13 @@ unsigned int OnAction_p2p(struct adapter *padapter, union recv_frame *precv_fram
return _SUCCESS;
}
-unsigned int OnAction(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int OnAction(struct adapter *padapter, struct recv_frame *precv_frame)
{
int i;
unsigned char category;
struct action_handler *ptable;
unsigned char *frame_body;
- u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *pframe = precv_frame->rx_data;
frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
@@ -4310,7 +4316,7 @@ unsigned int OnAction(struct adapter *padapter, union recv_frame *precv_frame)
return _SUCCESS;
}
-unsigned int DoReserved(struct adapter *padapter, union recv_frame *precv_frame)
+unsigned int DoReserved(struct adapter *padapter, struct recv_frame *precv_frame)
{
return _SUCCESS;
}
@@ -4341,7 +4347,7 @@ struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv)
/****************************************************************************
-Following are some TX fuctions for WiFi MLME
+Following are some TX functions for WiFi MLME
*****************************************************************************/
@@ -4432,7 +4438,7 @@ s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, struct xmit_frame *pmg
}
pxmitpriv->ack_tx = false;
- _exit_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL);
+ mutex_unlock(&pxmitpriv->ack_tx_mutex);
return ret;
}
@@ -4995,7 +5001,7 @@ exit:
return ret;
}
-/* if psta == NULL, indiate we are station(client) now... */
+/* if psta == NULL, indicate we are station(client) now... */
void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short status)
{
struct xmit_frame *pmgntframe;
@@ -5234,7 +5240,7 @@ void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_i
for (pbuf = ie + _BEACON_IE_OFFSET_;; pbuf += (ie_len + 2)) {
pbuf = rtw_get_ie(pbuf, _VENDOR_SPECIFIC_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
- if (pbuf && _rtw_memcmp(pbuf+2, WMM_PARA_IE, 6)) {
+ if (pbuf && !memcmp(pbuf+2, WMM_PARA_IE, 6)) {
memcpy(pframe, pbuf, ie_len+2);
pframe += (ie_len+2);
pattrib->pktlen += (ie_len+2);
@@ -5439,14 +5445,14 @@ void issue_assocreq(struct adapter *padapter)
switch (pIE->ElementID) {
case _VENDOR_SPECIFIC_IE_:
- if ((_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) ||
- (_rtw_memcmp(pIE->data, WMM_OUI, 4)) ||
- (_rtw_memcmp(pIE->data, WPS_OUI, 4))) {
+ if ((!memcmp(pIE->data, RTW_WPA_OUI, 4)) ||
+ (!memcmp(pIE->data, WMM_OUI, 4)) ||
+ (!memcmp(pIE->data, WPS_OUI, 4))) {
if (!padapter->registrypriv.wifi_spec) {
/* Commented by Kurt 20110629 */
/* In some older APs, WPS handshake */
/* would be fail if we append vender extensions informations to AP */
- if (_rtw_memcmp(pIE->data, WPS_OUI, 4))
+ if (!memcmp(pIE->data, WPS_OUI, 4))
pIE->Length = 14;
}
pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, pIE->Length, pIE->data, &(pattrib->pktlen));
@@ -5606,7 +5612,7 @@ exit:
return;
}
-/* when wait_ack is ture, this function shoule be called at process context */
+/* when wait_ack is true, this function should be called at process context */
static int _issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int wait_ack)
{
int ret = _FAIL;
@@ -5676,7 +5682,7 @@ exit:
}
-/* when wait_ms > 0 , this function shoule be called at process context */
+/* when wait_ms > 0 , this function should be called at process context */
/* da == NULL for station mode */
int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms)
{
@@ -5686,7 +5692,7 @@ int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int pow
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- /* da == NULL, assum it's null data for sta to ap*/
+ /* da == NULL, assume it's null data for sta to ap*/
if (da == NULL)
da = get_my_bssid(&(pmlmeinfo->network));
@@ -5721,7 +5727,7 @@ exit:
return ret;
}
-/* when wait_ack is ture, this function shoule be called at process context */
+/* when wait_ack is true, this function should be called at process context */
static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int wait_ack)
{
int ret = _FAIL;
@@ -5799,7 +5805,7 @@ exit:
return ret;
}
-/* when wait_ms > 0 , this function shoule be called at process context */
+/* when wait_ms > 0 , this function should be called at process context */
/* da == NULL for station mode */
int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int try_cnt, int wait_ms)
{
@@ -5809,7 +5815,7 @@ int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- /* da == NULL, assum it's null data for sta to ap*/
+ /* da == NULL, assume it's null data for sta to ap*/
if (da == NULL)
da = get_my_bssid(&(pmlmeinfo->network));
@@ -6103,17 +6109,26 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch
case 1: /* ADDBA rsp */
pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->ADDBA_req.dialog_token), &(pattrib->pktlen));
pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&status), &(pattrib->pktlen));
+
+ BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f;
rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor);
- if (MAX_AMPDU_FACTOR_64K == max_rx_ampdu_factor)
- BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */
- else if (MAX_AMPDU_FACTOR_32K == max_rx_ampdu_factor)
- BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0800); /* 32 buffer size */
- else if (MAX_AMPDU_FACTOR_16K == max_rx_ampdu_factor)
- BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0400); /* 16 buffer size */
- else if (MAX_AMPDU_FACTOR_8K == max_rx_ampdu_factor)
- BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0200); /* 8 buffer size */
- else
- BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */
+ switch (max_rx_ampdu_factor) {
+ case MAX_AMPDU_FACTOR_64K:
+ BA_para_set |= 0x1000; /* 64 buffer size */
+ break;
+ case MAX_AMPDU_FACTOR_32K:
+ BA_para_set |= 0x0800; /* 32 buffer size */
+ break;
+ case MAX_AMPDU_FACTOR_16K:
+ BA_para_set |= 0x0400; /* 16 buffer size */
+ break;
+ case MAX_AMPDU_FACTOR_8K:
+ BA_para_set |= 0x0200; /* 8 buffer size */
+ break;
+ default:
+ BA_para_set |= 0x1000; /* 64 buffer size */
+ break;
+ }
if (pregpriv->ampdu_amsdu == 0)/* disabled */
BA_para_set = BA_para_set & ~BIT(0);
@@ -6222,7 +6237,7 @@ static void issue_action_BSSCoexistPacket(struct adapter *padapter)
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
while (1) {
int len;
@@ -6232,9 +6247,9 @@ static void issue_action_BSSCoexistPacket(struct adapter *padapter)
if (rtw_end_of_queue_search(phead, plist))
break;
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pnetwork = container_of(plist, struct wlan_network, list);
- plist = get_next(plist);
+ plist = plist->next;
pbss_network = (struct wlan_bssid_ex *)&pnetwork->network;
@@ -6355,7 +6370,7 @@ unsigned int send_beacon(struct adapter *padapter)
/****************************************************************************
-Following are some utitity fuctions for WiFi MLME
+Following are some utility functions for WiFi MLME
*****************************************************************************/
@@ -6468,7 +6483,7 @@ void site_survey(struct adapter *padapter)
{
/* 20100721:Interrupt scan operation here. */
/* For SW antenna diversity before link, it needs to switch to another antenna and scan again. */
- /* It compares the scan result and select beter one to do connection. */
+ /* It compares the scan result and select better one to do connection. */
if (rtw_hal_antdiv_before_linked(padapter)) {
pmlmeext->sitesurvey_res.bss_cnt = 0;
pmlmeext->sitesurvey_res.channel_idx = -1;
@@ -6526,14 +6541,14 @@ void site_survey(struct adapter *padapter)
}
/* collect bss info from Beacon and Probe request/response frames. */
-u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, struct wlan_bssid_ex *bssid)
+u8 collect_bss_info(struct adapter *padapter, struct recv_frame *precv_frame, struct wlan_bssid_ex *bssid)
{
int i;
u32 len;
u8 *p;
u16 val16, subtype;
- u8 *pframe = precv_frame->u.hdr.rx_data;
- u32 packet_len = precv_frame->u.hdr.len;
+ u8 *pframe = precv_frame->rx_data;
+ u32 packet_len = precv_frame->len;
u8 ie_offset;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
@@ -6572,10 +6587,10 @@ u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, str
bssid->IELength = len;
memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength);
- /* get the signal strength */
- bssid->Rssi = precv_frame->u.hdr.attrib.phy_info.recvpower; /* in dBM.raw data */
- bssid->PhyInfo.SignalQuality = precv_frame->u.hdr.attrib.phy_info.SignalQuality;/* in percentage */
- bssid->PhyInfo.SignalStrength = precv_frame->u.hdr.attrib.phy_info.SignalStrength;/* in percentage */
+ /* get the signal strength in dBM.raw data */
+ bssid->Rssi = precv_frame->attrib.phy_info.recvpower;
+ bssid->PhyInfo.SignalQuality = precv_frame->attrib.phy_info.SignalQuality;/* in percentage */
+ bssid->PhyInfo.SignalStrength = precv_frame->attrib.phy_info.SignalStrength;/* in percentage */
rtw_hal_get_def_var(padapter, HAL_DEF_CURRENT_ANTENNA, &bssid->PhyInfo.Optimum_antenna);
/* checking SSID */
@@ -6707,7 +6722,7 @@ void start_create_ibss(struct adapter *padapter)
/* update wireless mode */
update_wireless_mode(padapter);
- /* udpate capability */
+ /* update capability */
caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork);
update_capinfo(padapter, caps);
if (caps&cap_IBSS) {/* adhoc master */
@@ -6759,7 +6774,7 @@ void start_clnt_join(struct adapter *padapter)
/* update wireless mode */
update_wireless_mode(padapter);
- /* udpate capability */
+ /* update capability */
caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork);
update_capinfo(padapter, caps);
if (caps&cap_ESS) {
@@ -6851,7 +6866,7 @@ unsigned int receive_disconnect(struct adapter *padapter, unsigned char *MacAddr
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
/* check A3 */
- if (!(_rtw_memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
+ if (memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN))
return _SUCCESS;
DBG_88E("%s\n", __func__);
@@ -7028,7 +7043,8 @@ Following are the functions to report events
*****************************************************************************/
-void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame)
+void report_survey_event(struct adapter *padapter,
+ struct recv_frame *precv_frame)
{
struct cmd_obj *pcmd_obj;
u8 *pevtcmd;
@@ -7037,8 +7053,6 @@ void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame
struct C2HEvent_Header *pc2h_evt_hdr;
struct mlme_ext_priv *pmlmeext;
struct cmd_priv *pcmdpriv;
- /* u8 *pframe = precv_frame->u.hdr.rx_data; */
- /* uint len = precv_frame->u.hdr.len; */
if (!padapter)
return;
@@ -7373,7 +7387,7 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res)
/* turn on dynamic functions */
Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true);
- /* update IOT-releated issue */
+ /* update IOT-related issue */
update_IOT_info(padapter);
rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates);
@@ -7381,7 +7395,7 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res)
/* BCN interval */
rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pmlmeinfo->bcn_interval));
- /* udpate capability */
+ /* update capability */
update_capinfo(padapter, pmlmeinfo->capability);
/* WMM, Update EDCA param */
@@ -7902,7 +7916,7 @@ u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf)
switch (pIE->ElementID) {
case _VENDOR_SPECIFIC_IE_:/* Get WMM IE. */
- if (_rtw_memcmp(pIE->data, WMM_OUI, 4))
+ if (!memcmp(pIE->data, WMM_OUI, 4))
pmlmeinfo->WMM_enable = 1;
break;
case _HT_CAPABILITY_IE_: /* Get HT Cap IE. */
@@ -8016,7 +8030,7 @@ static int rtw_scan_ch_decision(struct adapter *padapter, struct rtw_ieee80211_c
set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, in[i].hw_value);
if (in[i].hw_value && !(in[i].flags & RTW_IEEE80211_CHAN_DISABLED) &&
set_idx >= 0) {
- memcpy(&out[j], &in[i], sizeof(struct rtw_ieee80211_channel));
+ out[j] = in[i];
if (pmlmeext->channel_set[set_idx].ScanType == SCAN_PASSIVE)
out[j].flags &= RTW_IEEE80211_CHAN_PASSIVE_SCAN;
@@ -8261,7 +8275,6 @@ u8 set_tx_beacon_cmd(struct adapter *padapter)
u8 res = _SUCCESS;
int len_diff = 0;
-_func_enter_;
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
if (ph2c == NULL) {
@@ -8290,7 +8303,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -8368,12 +8380,12 @@ u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf)
spin_lock_bh(&psta_bmc->sleep_q.lock);
xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
- xmitframe_plist = get_next(xmitframe_phead);
+ xmitframe_plist = xmitframe_phead->next;
while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
- pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
- xmitframe_plist = get_next(xmitframe_plist);
+ xmitframe_plist = xmitframe_plist->next;
rtw_list_delete(&pxmitframe->list);
diff --git a/drivers/staging/rtl8188eu/core/rtw_mp.c b/drivers/staging/rtl8188eu/core/rtw_mp.c
index 6451efdfb132..705f666bca6b 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mp.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mp.c
@@ -23,6 +23,7 @@
#include "odm_precomp.h"
#include "rtl8188e_hal.h"
+#include <linux/vmalloc.h>
u32 read_macreg(struct adapter *padapter, u32 addr, u32 sz)
{
@@ -406,7 +407,7 @@ s32 mp_start_test(struct adapter *padapter)
goto end_of_mp_start_test;
}
- /* 3 3. join psudo AdHoc */
+ /* 3 3. join pseudo AdHoc */
tgt_network->join_res = 1;
tgt_network->aid = 1;
psta->aid = 1;
@@ -442,7 +443,7 @@ void mp_stop_test(struct adapter *padapter)
if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false)
goto end_of_mp_stop_test;
- /* 3 1. disconnect psudo AdHoc */
+ /* 3 1. disconnect pseudo AdHoc */
rtw_indicate_disconnect(padapter);
/* 3 2. clear psta used in mp test mode. */
@@ -882,7 +883,7 @@ u32 mp_query_psd(struct adapter *pAdapter, u8 *data)
{
u32 i, psd_pts = 0, psd_start = 0, psd_stop = 0;
u32 psd_data = 0;
-
+ int ret;
if (!netif_running(pAdapter->pnetdev)) {
RT_TRACE(_module_mp_, _drv_warning_, ("mp_query_psd: Fail! interface not opened!\n"));
@@ -899,7 +900,10 @@ u32 mp_query_psd(struct adapter *pAdapter, u8 *data)
psd_start = 64;
psd_stop = 128;
} else {
- sscanf(data, "pts =%d, start =%d, stop =%d", &psd_pts, &psd_start, &psd_stop);
+ ret = sscanf(data, "pts =%d, start =%d, stop =%d",
+ &psd_pts, &psd_start, &psd_stop);
+ if (ret != 3)
+ return 0;
}
_rtw_memset(data, '\0', sizeof(*data));
@@ -943,7 +947,7 @@ void _rtw_mp_xmit_priv(struct xmit_priv *pxmitpriv)
}
if (pxmitpriv->pallocated_xmit_extbuf)
- rtw_vmfree(pxmitpriv->pallocated_xmit_extbuf, num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
+ vfree(pxmitpriv->pallocated_xmit_extbuf);
if (padapter->registrypriv.mp_mode == 0) {
max_xmit_extbuf_size = 20000;
@@ -956,7 +960,7 @@ void _rtw_mp_xmit_priv(struct xmit_priv *pxmitpriv)
/* Init xmit extension buff */
_rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue);
- pxmitpriv->pallocated_xmit_extbuf = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
+ pxmitpriv->pallocated_xmit_extbuf = vzalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
if (pxmitpriv->pallocated_xmit_extbuf == NULL) {
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n"));
diff --git a/drivers/staging/rtl8188eu/core/rtw_mp_ioctl.c b/drivers/staging/rtl8188eu/core/rtw_mp_ioctl.c
index edcd8a5042be..e783968b29ea 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mp_ioctl.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mp_ioctl.c
@@ -33,7 +33,6 @@ int rtl8188eu_oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
if (poid_par_priv->information_buf_len < sizeof(u8))
return NDIS_STATUS_INVALID_LENGTH;
@@ -48,7 +47,6 @@ _func_enter_;
status = NDIS_STATUS_NOT_ACCEPTED;
}
-_func_exit_;
return status;
}
@@ -61,7 +59,6 @@ int rtl8188eu_oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_write_bb_reg_hdl\n"));
@@ -87,7 +84,6 @@ _func_enter_;
write_bbreg(Adapter, offset, 0xFFFFFFFF, value);
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -100,7 +96,6 @@ int rtl8188eu_oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_read_bb_reg_hdl\n"));
@@ -126,7 +121,6 @@ _func_enter_;
RT_TRACE(_module_mp_, _drv_notice_,
("-rtl8188eu_oid_rt_pro_read_bb_reg_hdl: offset=0x%03X value:0x%08X\n",
offset, value));
-_func_exit_;
return status;
}
@@ -140,7 +134,6 @@ int rtl8188eu_oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_write_rf_reg_hdl\n"));
@@ -171,7 +164,6 @@ _func_enter_;
write_rfreg(Adapter, path, offset, value);
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -185,7 +177,6 @@ int rtl8188eu_oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv)
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
int status = NDIS_STATUS_SUCCESS;
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_read_rf_reg_hdl\n"));
@@ -217,7 +208,6 @@ _func_enter_;
("-rtl8188eu_oid_rt_pro_read_rf_reg_hdl: path=%d offset=0x%02X value=0x%05X\n",
path, offset, value));
-_func_exit_;
return status;
}
@@ -232,7 +222,6 @@ int rtl8188eu_oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_,
("+rtl8188eu_oid_rt_pro_set_data_rate_hdl\n"));
@@ -255,7 +244,6 @@ _func_enter_;
SetDataRate(Adapter);
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -266,7 +254,6 @@ int rtl8188eu_oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_start_test_hdl\n"));
@@ -293,7 +280,6 @@ exit:
RT_TRACE(_module_mp_, _drv_notice_, ("-rtl8188eu_oid_rt_pro_start_test_hdl: mp_mode=%d\n", Adapter->mppriv.mode));
-_func_exit_;
return status;
}
@@ -303,7 +289,6 @@ int rtl8188eu_oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+Set OID_RT_PRO_STOP_TEST\n"));
@@ -316,7 +301,6 @@ _func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("-Set OID_RT_PRO_STOP_TEST\n"));
-_func_exit_;
return status;
}
@@ -327,7 +311,6 @@ int rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv *poid_p
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl\n"));
@@ -352,7 +335,6 @@ _func_enter_;
SetChannel(Adapter);
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -364,7 +346,6 @@ int rtl8188eu_oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *padapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_info_,
("+rtl8188eu_oid_rt_set_bandwidth_hdl\n"));
@@ -391,7 +372,6 @@ _func_enter_;
("-rtl8188eu_oid_rt_set_bandwidth_hdl: bandwidth=%d channel_offset=%d\n",
bandwidth, channel_offset));
-_func_exit_;
return status;
}
@@ -402,7 +382,6 @@ int rtl8188eu_oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_antenna_bb_hdl\n"));
@@ -426,7 +405,6 @@ _func_enter_;
*(u32 *)poid_par_priv->information_buf = antenna;
}
-_func_exit_;
return status;
}
@@ -437,7 +415,6 @@ int rtl8188eu_oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv *poid_par_
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_pro_set_tx_power_control_hdl\n"));
@@ -461,7 +438,6 @@ _func_enter_;
SetTxPower(Adapter);
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -474,7 +450,6 @@ int rtl8188eu_oid_rt_pro_query_tx_packet_sent_hdl(struct oid_par_priv *poid_par_
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
if (poid_par_priv->type_of_oid != QUERY_OID) {
status = NDIS_STATUS_NOT_ACCEPTED;
@@ -488,7 +463,6 @@ _func_enter_;
status = NDIS_STATUS_INVALID_LENGTH;
}
-_func_exit_;
return status;
}
@@ -498,7 +472,6 @@ int rtl8188eu_oid_rt_pro_query_rx_packet_received_hdl(struct oid_par_priv *poid_
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
if (poid_par_priv->type_of_oid != QUERY_OID) {
status = NDIS_STATUS_NOT_ACCEPTED;
@@ -513,7 +486,6 @@ _func_enter_;
status = NDIS_STATUS_INVALID_LENGTH;
}
-_func_exit_;
return status;
}
@@ -523,7 +495,6 @@ int rtl8188eu_oid_rt_pro_query_rx_packet_crc32_error_hdl(struct oid_par_priv *po
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
if (poid_par_priv->type_of_oid != QUERY_OID) {
status = NDIS_STATUS_NOT_ACCEPTED;
@@ -538,7 +509,6 @@ _func_enter_;
status = NDIS_STATUS_INVALID_LENGTH;
}
-_func_exit_;
return status;
}
@@ -549,7 +519,6 @@ int rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv *poid_par_
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
if (poid_par_priv->type_of_oid != SET_OID) {
status = NDIS_STATUS_NOT_ACCEPTED;
@@ -559,7 +528,6 @@ _func_enter_;
RT_TRACE(_module_mp_, _drv_alert_, ("===> rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl.\n"));
Adapter->mppriv.tx_pktcount = 0;
-_func_exit_;
return status;
}
@@ -569,7 +537,6 @@ int rtl8188eu_oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv *poid_
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
if (poid_par_priv->type_of_oid != SET_OID) {
status = NDIS_STATUS_NOT_ACCEPTED;
@@ -583,7 +550,6 @@ _func_enter_;
status = NDIS_STATUS_INVALID_LENGTH;
}
-_func_exit_;
return status;
}
@@ -593,7 +559,6 @@ int rtl8188eu_oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv *poid_par
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
if (poid_par_priv->type_of_oid != SET_OID) {
status = NDIS_STATUS_NOT_ACCEPTED;
@@ -604,7 +569,6 @@ _func_enter_;
ResetPhyRxPktCount(Adapter);
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -614,7 +578,6 @@ int rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv *poid_pa
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl\n"));
@@ -632,7 +595,6 @@ _func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("-rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl: recv_ok=%d\n", *(u32 *)poid_par_priv->information_buf));
-_func_exit_;
return status;
}
@@ -642,7 +604,6 @@ int rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv *poid
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl\n"));
@@ -663,7 +624,6 @@ _func_enter_;
("-rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl: recv_err =%d\n",
*(u32 *)poid_par_priv->information_buf));
-_func_exit_;
return status;
}
@@ -674,7 +634,6 @@ int rtl8188eu_oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv *poid_par_pri
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_continuous_tx_hdl\n"));
@@ -698,7 +657,6 @@ _func_enter_;
}
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -709,7 +667,6 @@ int rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv *poid_par
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_alert_, ("+rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl\n"));
@@ -733,7 +690,6 @@ _func_enter_;
}
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -744,7 +700,6 @@ int rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv *poi
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl\n"));
@@ -768,7 +723,6 @@ _func_enter_;
}
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -779,7 +733,6 @@ int rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv *poid_par_pr
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_alert_, ("+rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl\n"));
@@ -792,7 +745,6 @@ _func_enter_;
SetSingleToneTx(Adapter, (u8)bStartTest);
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -806,7 +758,6 @@ int rtl8188eu_oid_rt_pro_trigger_gpio_hdl(struct oid_par_priv *poid_par_priv)
{
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
int status = NDIS_STATUS_SUCCESS;
-_func_enter_;
if (poid_par_priv->type_of_oid != SET_OID)
return NDIS_STATUS_NOT_ACCEPTED;
@@ -815,7 +766,6 @@ _func_enter_;
rtw_hal_set_hwreg(Adapter, HW_VAR_TRIGGER_GPIO_0, NULL);
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -833,7 +783,6 @@ int rtl8188eu_oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_info_,
("+rtl8188eu_oid_rt_pro_read_register_hdl\n"));
@@ -870,7 +819,6 @@ _func_enter_;
*poid_par_priv->bytes_rw = width;
-_func_exit_;
return status;
}
@@ -882,7 +830,6 @@ int rtl8188eu_oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *padapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_info_,
("+rtl8188eu_oid_rt_pro_write_register_hdl\n"));
@@ -929,7 +876,6 @@ _func_enter_;
("-rtl8188eu_oid_rt_pro_write_register_hdl: offset=0x%08X width=%d value=0x%X\n",
offset, width, value));
-_func_exit_;
return status;
}
@@ -1002,7 +948,6 @@ int rtl8188eu_oid_rt_pro_set_data_rate_ex_hdl(struct oid_par_priv *poid_par_priv
int status = NDIS_STATUS_SUCCESS;
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+OID_RT_PRO_SET_DATA_RATE_EX\n"));
@@ -1016,7 +961,6 @@ _func_enter_;
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -1027,7 +971,6 @@ int rtl8188eu_oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv)
u8 thermal = 0;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_get_thermal_meter_hdl\n"));
@@ -1044,7 +987,6 @@ _func_enter_;
*(u32 *)poid_par_priv->information_buf = (u32)thermal;
*poid_par_priv->bytes_rw = sizeof(u32);
-_func_exit_;
return status;
}
@@ -1060,7 +1002,6 @@ int rtl8188eu_oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv *poid_par_pr
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
if (poid_par_priv->information_buf_len < sizeof(u8))
return NDIS_STATUS_INVALID_LENGTH;
@@ -1079,7 +1020,6 @@ _func_enter_;
}
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -1143,7 +1083,6 @@ int rtl8188eu_oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
if (poid_par_priv->type_of_oid != QUERY_OID)
return NDIS_STATUS_NOT_ACCEPTED;
@@ -1176,7 +1115,6 @@ _func_enter_;
}
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -1190,7 +1128,6 @@ int rtl8188eu_oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv)
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
if (poid_par_priv->type_of_oid != SET_OID)
return NDIS_STATUS_NOT_ACCEPTED;
@@ -1216,7 +1153,6 @@ _func_enter_;
status = NDIS_STATUS_FAILURE;
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
@@ -1227,7 +1163,6 @@ int rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
*poid_par_priv->bytes_rw = 0;
@@ -1267,7 +1202,6 @@ _func_enter_;
RT_TRACE(_module_mp_, _drv_info_,
("-rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl: status=0x%08X\n", status));
-_func_exit_;
return status;
}
@@ -1279,7 +1213,6 @@ int rtl8188eu_oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_pr
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
if (poid_par_priv->type_of_oid != QUERY_OID)
return NDIS_STATUS_NOT_ACCEPTED;
@@ -1296,7 +1229,6 @@ _func_enter_;
} else {
status = NDIS_STATUS_FAILURE;
}
-_func_exit_;
return status;
}
@@ -1306,7 +1238,6 @@ int rtl8188eu_oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv)
int status = NDIS_STATUS_SUCCESS;
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
-_func_enter_;
if (poid_par_priv->type_of_oid != QUERY_OID)
return NDIS_STATUS_NOT_ACCEPTED;
@@ -1321,7 +1252,6 @@ _func_enter_;
("-rtl8188eu_oid_rt_get_efuse_max_size_hdl: size=%d status=0x%08X\n",
*(int *)poid_par_priv->information_buf, status));
-_func_exit_;
return status;
}
@@ -1330,7 +1260,6 @@ int rtl8188eu_oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv)
{
int status;
-_func_enter_;
RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_pro_efuse_hdl\n"));
@@ -1341,7 +1270,6 @@ _func_enter_;
RT_TRACE(_module_mp_, _drv_info_, ("-rtl8188eu_oid_rt_pro_efuse_hdl: status=0x%08X\n", status));
-_func_exit_;
return status;
}
@@ -1353,7 +1281,6 @@ int rtl8188eu_oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv)
struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
u16 maplen = 0;
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_efuse_map_hdl\n"));
@@ -1398,7 +1325,6 @@ _func_enter_;
RT_TRACE(_module_mp_, _drv_info_,
("-rtl8188eu_oid_rt_pro_efuse_map_hdl: status=0x%08X\n", status));
-_func_exit_;
return status;
}
@@ -1414,7 +1340,6 @@ int rtl8188eu_oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv)
u8 rx_pkt_type;
int status = NDIS_STATUS_SUCCESS;
-_func_enter_;
RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_set_rx_packet_type_hdl\n"));
@@ -1427,7 +1352,6 @@ _func_enter_;
rx_pkt_type = *((u8 *)poid_par_priv->information_buf);/* 4 */
RT_TRACE(_module_mp_, _drv_info_, ("rx_pkt_type: %x\n", rx_pkt_type));
-_func_exit_;
return status;
}
@@ -1482,7 +1406,6 @@ int rtl8188eu_oid_rt_set_power_down_hdl(struct oid_par_priv *poid_par_priv)
{
int status = NDIS_STATUS_SUCCESS;
-_func_enter_;
if (poid_par_priv->type_of_oid != SET_OID) {
status = NDIS_STATUS_NOT_ACCEPTED;
@@ -1497,7 +1420,6 @@ _func_enter_;
/* CALL the power_down function */
_irqlevel_changed_(&oldirql, RAISE);
-_func_exit_;
return status;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_p2p.c b/drivers/staging/rtl8188eu/core/rtw_p2p.c
index 6e8c06e840b3..9425c4991ccd 100644
--- a/drivers/staging/rtl8188eu/core/rtw_p2p.c
+++ b/drivers/staging/rtl8188eu/core/rtw_p2p.c
@@ -57,13 +57,13 @@ static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = get_next(phead);
+ plist = phead->next;
/* look up sta asoc_queue */
while ((rtw_end_of_queue_search(phead, plist)) == false) {
- psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+ psta = container_of(plist, struct sta_info, asoc_list);
- plist = get_next(plist);
+ plist = plist->next;
if (psta->is_p2p_device) {
@@ -824,7 +824,7 @@ u32 process_probe_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint l
if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
p2pie = rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_ , len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_ , NULL, &p2pielen);
if (p2pie) {
- if ((p != NULL) && _rtw_memcmp((void *)(p+2), (void *)pwdinfo->p2p_wildcard_ssid , 7)) {
+ if ((p != NULL) && !memcmp((void *)(p+2), (void *)pwdinfo->p2p_wildcard_ssid , 7)) {
/* todo: */
/* Check Requested Device Type attributes in WSC IE. */
/* Check Device ID attribute in P2P IE */
@@ -972,24 +972,24 @@ u32 process_p2p_devdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint le
u32 attr_contentlen = 0;
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) {
- if (_rtw_memcmp(pwdinfo->device_addr, groupid, ETH_ALEN) &&
- _rtw_memcmp(pwdinfo->p2p_group_ssid, groupid+ETH_ALEN, pwdinfo->p2p_group_ssid_len)) {
+ if (!memcmp(pwdinfo->device_addr, groupid, ETH_ALEN) &&
+ !memcmp(pwdinfo->p2p_group_ssid, groupid+ETH_ALEN, pwdinfo->p2p_group_ssid_len)) {
attr_contentlen = 0;
if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_ID, dev_addr, &attr_contentlen)) {
struct list_head *phead, *plist;
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = get_next(phead);
+ plist = phead->next;
/* look up sta asoc_queue */
while ((rtw_end_of_queue_search(phead, plist)) == false) {
- psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+ psta = container_of(plist, struct sta_info, asoc_list);
- plist = get_next(plist);
+ plist = plist->next;
if (psta->is_p2p_device && (psta->dev_cap&P2P_DEVCAP_CLIENT_DISCOVERABILITY) &&
- _rtw_memcmp(psta->dev_addr, dev_addr, ETH_ALEN)) {
+ !memcmp(psta->dev_addr, dev_addr, ETH_ALEN)) {
/* issue GO Discoverability Request */
issue_group_disc_req(pwdinfo, psta->hwaddr);
status = P2P_STATUS_SUCCESS;
@@ -1118,7 +1118,7 @@ u8 process_p2p_group_negotation_req(struct wifidirect_info *pwdinfo, u8 *pframe,
/* Commented by Kurt 20120113 */
/* If some device wants to do p2p handshake without sending prov_disc_req */
/* We have to get peer_req_cm from here. */
- if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) {
+ if (!memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) {
rtw_get_wps_attr_content(wpsie, wps_ielen, WPS_ATTR_DEVICE_PWID, (u8 *)&be_tmp, &wps_devicepassword_id_len);
wps_devicepassword_id = be16_to_cpu(be_tmp);
@@ -1498,7 +1498,6 @@ static void find_phase_handler(struct adapter *padapter)
struct ndis_802_11_ssid ssid;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-_func_enter_;
_rtw_memset((unsigned char *)&ssid, 0, sizeof(struct ndis_802_11_ssid));
memcpy(ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN);
@@ -1509,7 +1508,6 @@ _func_enter_;
spin_lock_bh(&pmlmepriv->lock);
rtw_sitesurvey_cmd(padapter, &ssid, 1, NULL, 0);
spin_unlock_bh(&pmlmepriv->lock);
-_func_exit_;
}
void p2p_concurrent_handler(struct adapter *padapter);
@@ -1518,7 +1516,6 @@ static void restore_p2p_state_handler(struct adapter *padapter)
{
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
-_func_enter_;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL))
rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
@@ -1528,54 +1525,46 @@ _func_enter_;
/* because this P2P client should stay at the operating channel of P2P GO. */
set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
}
-_func_exit_;
}
static void pre_tx_invitereq_handler(struct adapter *padapter)
{
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
u8 val8 = 1;
-_func_enter_;
set_channel_bwmode(padapter, pwdinfo->invitereq_info.peer_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
issue_probereq_p2p(padapter, NULL);
_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
-_func_exit_;
}
static void pre_tx_provdisc_handler(struct adapter *padapter)
{
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
u8 val8 = 1;
-_func_enter_;
set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
issue_probereq_p2p(padapter, NULL);
_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
-_func_exit_;
}
static void pre_tx_negoreq_handler(struct adapter *padapter)
{
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
u8 val8 = 1;
-_func_enter_;
set_channel_bwmode(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
issue_probereq_p2p(padapter, NULL);
_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
-_func_exit_;
}
void p2p_protocol_wk_hdl(struct adapter *padapter, int intCmdType)
{
-_func_enter_;
switch (intCmdType) {
case P2P_FIND_PHASE_WK:
find_phase_handler(padapter);
@@ -1594,7 +1583,6 @@ _func_enter_;
break;
}
-_func_exit_;
}
void process_p2p_ps_ie(struct adapter *padapter, u8 *IEs, u32 IELength)
@@ -1610,7 +1598,6 @@ void process_p2p_ps_ie(struct adapter *padapter, u8 *IEs, u32 IELength)
u8 find_p2p = false, find_p2p_ps = false;
u8 noa_offset, noa_num, noa_index;
-_func_enter_;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
return;
@@ -1683,7 +1670,6 @@ _func_enter_;
p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1);
}
-_func_exit_;
}
void p2p_ps_wk_hdl(struct adapter *padapter, u8 p2p_ps_state)
@@ -1691,7 +1677,6 @@ void p2p_ps_wk_hdl(struct adapter *padapter, u8 p2p_ps_state)
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
-_func_enter_;
/* Pre action for p2p state */
switch (p2p_ps_state) {
@@ -1738,7 +1723,6 @@ _func_enter_;
break;
}
-_func_exit_;
}
u8 p2p_ps_wk_cmd(struct adapter *padapter, u8 p2p_ps_state, u8 enqueue)
@@ -1749,7 +1733,6 @@ u8 p2p_ps_wk_cmd(struct adapter *padapter, u8 p2p_ps_state, u8 enqueue)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-_func_enter_;
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
return res;
@@ -1781,7 +1764,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -2024,11 +2006,11 @@ int rtw_p2p_enable(struct adapter *padapter, enum P2P_ROLE role)
/* Disable P2P function */
if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
- _cancel_timer_ex(&pwdinfo->find_phase_timer);
- _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
- _cancel_timer_ex(&pwdinfo->pre_tx_scan_timer);
- _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
- _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey2);
+ del_timer_sync(&pwdinfo->find_phase_timer);
+ del_timer_sync(&pwdinfo->restore_p2p_state_timer);
+ del_timer_sync(&pwdinfo->pre_tx_scan_timer);
+ del_timer_sync(&pwdinfo->reset_ch_sitesurvey);
+ del_timer_sync(&pwdinfo->reset_ch_sitesurvey2);
reset_ch_sitesurvey_timer_process(padapter);
reset_ch_sitesurvey_timer_process2(padapter);
rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE);
diff --git a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
index b5db22cc81ed..f6583734aefa 100644
--- a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
+++ b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
@@ -226,11 +226,8 @@ void rtw_set_rpwm(struct adapter *padapter, u8 pslv)
u8 rpwm;
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
-_func_enter_;
-
pslv = PS_STATE(pslv);
-
if (pwrpriv->btcoex_rfon) {
if (pslv < PS_STATE_S4)
pslv = PS_STATE_S3;
@@ -274,8 +271,6 @@ _func_enter_;
pwrpriv->tog += 0x80;
pwrpriv->cpwm = pslv;
-
-_func_exit_;
}
static u8 PS_RDY_CHECK(struct adapter *padapter)
@@ -313,8 +308,6 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a
struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
#endif /* CONFIG_88EU_P2P */
-_func_enter_;
-
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
("%s: PowerMode=%d Smart_PS=%d\n",
__func__, ps_mode, smart_ps));
@@ -362,8 +355,6 @@ _func_enter_;
rtw_set_rpwm(padapter, PS_STATE_S2);
}
}
-
-_func_exit_;
}
/*
@@ -410,8 +401,6 @@ void LPS_Enter(struct adapter *padapter)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
-_func_enter_;
-
if (PS_RDY_CHECK(padapter) == false)
return;
@@ -428,8 +417,6 @@ _func_enter_;
pwrpriv->LpsIdleCount++;
}
}
-
-_func_exit_;
}
#define LPS_LEAVE_TIMEOUT_MS 100
@@ -440,8 +427,6 @@ void LPS_Leave(struct adapter *padapter)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
-_func_enter_;
-
if (pwrpriv->bLeisurePs) {
if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) {
rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0);
@@ -452,8 +437,6 @@ _func_enter_;
}
pwrpriv->bpower_saving = false;
-
-_func_exit_;
}
/* */
@@ -465,23 +448,17 @@ void LeaveAllPowerSaveMode(struct adapter *Adapter)
struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv);
u8 enqueue = 0;
-_func_enter_;
-
if (check_fwstate(pmlmepriv, _FW_LINKED)) { /* connect */
p2p_ps_wk_cmd(Adapter, P2P_PS_DISABLE, enqueue);
rtw_lps_ctrl_wk_cmd(Adapter, LPS_CTRL_LEAVE, enqueue);
}
-
-_func_exit_;
}
void rtw_init_pwrctrl_priv(struct adapter *padapter)
{
struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
-_func_enter_;
-
_init_pwrlock(&pwrctrlpriv->lock);
pwrctrlpriv->rf_pwrstate = rf_on;
pwrctrlpriv->ips_enter_cnts = 0;
@@ -518,8 +495,6 @@ _func_enter_;
pwrctrlpriv->btcoex_rfon = false;
_init_timer(&(pwrctrlpriv->pwr_state_check_timer), padapter->pnetdev, pwr_state_check_handler, (u8 *)padapter);
-
-_func_exit_;
}
u8 rtw_interface_ps_func(struct adapter *padapter, enum hal_intf_ps_func efunc_id, u8 *val)
@@ -540,7 +515,7 @@ inline void rtw_set_ips_deny(struct adapter *padapter, u32 ms)
/*
* rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend
* @adapter: pointer to struct adapter structure
-* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup
+* @ips_deffer_ms: the ms will prevent from falling into IPS after wakeup
* Return _SUCCESS or _FAIL
*/
diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c
index c9c180649c12..636ec553ae83 100644
--- a/drivers/staging/rtl8188eu/core/rtw_recv.c
+++ b/drivers/staging/rtl8188eu/core/rtw_recv.c
@@ -23,11 +23,12 @@
#include <drv_types.h>
#include <recv_osdep.h>
#include <mlme_osdep.h>
-#include <ip.h>
-#include <if_ether.h>
-#include <ethernet.h>
#include <usb_ops.h>
#include <wifi.h>
+#include <linux/vmalloc.h>
+
+#define ETHERNET_HEADER_SIZE 14 /* Ethernet Header Length */
+#define LLC_HEADER_SIZE 6 /* LLC Header Length */
static u8 SNAP_ETH_TYPE_IPX[2] = {0x81, 0x37};
static u8 SNAP_ETH_TYPE_APPLETALK_AARP[2] = {0x80, 0xf3};
@@ -45,7 +46,6 @@ void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS);
void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv)
{
-_func_enter_;
_rtw_memset((u8 *)psta_recvpriv, 0, sizeof (struct sta_recv_priv));
@@ -53,18 +53,16 @@ _func_enter_;
_rtw_init_queue(&psta_recvpriv->defrag_q);
-_func_exit_;
}
int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter)
{
int i;
- union recv_frame *precvframe;
+ struct recv_frame *precvframe;
int res = _SUCCESS;
-_func_enter_;
spin_lock_init(&precvpriv->lock);
_rtw_init_queue(&precvpriv->free_recv_queue);
@@ -77,7 +75,7 @@ _func_enter_;
rtw_os_recv_resource_init(precvpriv, padapter);
- precvpriv->pallocated_frame_buf = rtw_zvmalloc(NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ);
+ precvpriv->pallocated_frame_buf = vzalloc(NR_RECVFRAME * sizeof(struct recv_frame) + RXFRAME_ALIGN_SZ);
if (precvpriv->pallocated_frame_buf == NULL) {
res = _FAIL;
@@ -86,18 +84,19 @@ _func_enter_;
precvpriv->precv_frame_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ);
- precvframe = (union recv_frame *)precvpriv->precv_frame_buf;
+ precvframe = (struct recv_frame *)precvpriv->precv_frame_buf;
for (i = 0; i < NR_RECVFRAME; i++) {
- _rtw_init_listhead(&(precvframe->u.list));
+ _rtw_init_listhead(&(precvframe->list));
- rtw_list_insert_tail(&(precvframe->u.list), &(precvpriv->free_recv_queue.queue));
+ rtw_list_insert_tail(&(precvframe->list),
+ &(precvpriv->free_recv_queue.queue));
res = rtw_os_recv_resource_alloc(padapter, precvframe);
- precvframe->u.hdr.len = 0;
+ precvframe->len = 0;
- precvframe->u.hdr.adapter = padapter;
+ precvframe->adapter = padapter;
precvframe++;
}
precvpriv->rx_pending_cnt = 1;
@@ -113,7 +112,6 @@ _func_enter_;
rtw_set_signal_stat_timer(precvpriv);
exit:
-_func_exit_;
return res;
}
@@ -122,40 +120,37 @@ void _rtw_free_recv_priv (struct recv_priv *precvpriv)
{
struct adapter *padapter = precvpriv->adapter;
-_func_enter_;
rtw_free_uc_swdec_pending_queue(padapter);
rtw_os_recv_resource_free(precvpriv);
if (precvpriv->pallocated_frame_buf) {
- rtw_vmfree(precvpriv->pallocated_frame_buf, NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ);
+ vfree(precvpriv->pallocated_frame_buf);
}
rtw_hal_free_recv_priv(padapter);
-_func_exit_;
}
-union recv_frame *_rtw_alloc_recvframe (struct __queue *pfree_recv_queue)
+struct recv_frame *_rtw_alloc_recvframe (struct __queue *pfree_recv_queue)
{
- union recv_frame *precvframe;
+ struct recv_frame *hdr;
struct list_head *plist, *phead;
struct adapter *padapter;
struct recv_priv *precvpriv;
-_func_enter_;
if (_rtw_queue_empty(pfree_recv_queue)) {
- precvframe = NULL;
+ hdr = NULL;
} else {
phead = get_list_head(pfree_recv_queue);
- plist = get_next(phead);
+ plist = phead->next;
- precvframe = LIST_CONTAINOR(plist, union recv_frame, u);
+ hdr = container_of(plist, struct recv_frame, list);
- rtw_list_delete(&precvframe->u.hdr.list);
- padapter = precvframe->u.hdr.adapter;
+ rtw_list_delete(&hdr->list);
+ padapter = hdr->adapter;
if (padapter != NULL) {
precvpriv = &padapter->recvpriv;
if (pfree_recv_queue == &precvpriv->free_recv_queue)
@@ -163,14 +158,13 @@ _func_enter_;
}
}
-_func_exit_;
- return precvframe;
+ return (struct recv_frame *)hdr;
}
-union recv_frame *rtw_alloc_recvframe (struct __queue *pfree_recv_queue)
+struct recv_frame *rtw_alloc_recvframe(struct __queue *pfree_recv_queue)
{
- union recv_frame *precvframe;
+ struct recv_frame *precvframe;
spin_lock_bh(&pfree_recv_queue->lock);
@@ -181,36 +175,36 @@ union recv_frame *rtw_alloc_recvframe (struct __queue *pfree_recv_queue)
return precvframe;
}
-void rtw_init_recvframe(union recv_frame *precvframe, struct recv_priv *precvpriv)
+void rtw_init_recvframe(struct recv_frame *precvframe, struct recv_priv *precvpriv)
{
/* Perry: This can be removed */
- _rtw_init_listhead(&precvframe->u.hdr.list);
+ _rtw_init_listhead(&precvframe->list);
- precvframe->u.hdr.len = 0;
+ precvframe->len = 0;
}
-int rtw_free_recvframe(union recv_frame *precvframe, struct __queue *pfree_recv_queue)
+int rtw_free_recvframe(struct recv_frame *precvframe,
+ struct __queue *pfree_recv_queue)
{
struct adapter *padapter;
struct recv_priv *precvpriv;
-_func_enter_;
if (!precvframe)
return _FAIL;
- padapter = precvframe->u.hdr.adapter;
+ padapter = precvframe->adapter;
precvpriv = &padapter->recvpriv;
- if (precvframe->u.hdr.pkt) {
- dev_kfree_skb_any(precvframe->u.hdr.pkt);/* free skb by driver */
- precvframe->u.hdr.pkt = NULL;
+ if (precvframe->pkt) {
+ dev_kfree_skb_any(precvframe->pkt);/* free skb by driver */
+ precvframe->pkt = NULL;
}
spin_lock_bh(&pfree_recv_queue->lock);
- rtw_list_delete(&(precvframe->u.hdr.list));
+ rtw_list_delete(&(precvframe->list));
- precvframe->u.hdr.len = 0;
+ precvframe->len = 0;
- rtw_list_insert_tail(&(precvframe->u.hdr.list), get_list_head(pfree_recv_queue));
+ rtw_list_insert_tail(&(precvframe->list), get_list_head(pfree_recv_queue));
if (padapter != NULL) {
if (pfree_recv_queue == &precvpriv->free_recv_queue)
@@ -219,32 +213,29 @@ _func_enter_;
spin_unlock_bh(&pfree_recv_queue->lock);
-_func_exit_;
return _SUCCESS;
}
-int _rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue)
+int _rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue)
{
- struct adapter *padapter = precvframe->u.hdr.adapter;
+ struct adapter *padapter = precvframe->adapter;
struct recv_priv *precvpriv = &padapter->recvpriv;
-_func_enter_;
- rtw_list_delete(&(precvframe->u.hdr.list));
- rtw_list_insert_tail(&(precvframe->u.hdr.list), get_list_head(queue));
+ rtw_list_delete(&(precvframe->list));
+ rtw_list_insert_tail(&(precvframe->list), get_list_head(queue));
if (padapter != NULL) {
if (queue == &precvpriv->free_recv_queue)
precvpriv->free_recvframe_cnt++;
}
-_func_exit_;
return _SUCCESS;
}
-int rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue)
+int rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue)
{
int ret;
@@ -265,32 +256,30 @@ using spinlock to protect
void rtw_free_recvframe_queue(struct __queue *pframequeue, struct __queue *pfree_recv_queue)
{
- union recv_frame *precvframe;
+ struct recv_frame *hdr;
struct list_head *plist, *phead;
-_func_enter_;
spin_lock(&pframequeue->lock);
phead = get_list_head(pframequeue);
- plist = get_next(phead);
+ plist = phead->next;
while (rtw_end_of_queue_search(phead, plist) == false) {
- precvframe = LIST_CONTAINOR(plist, union recv_frame, u);
+ hdr = container_of(plist, struct recv_frame, list);
- plist = get_next(plist);
+ plist = plist->next;
- rtw_free_recvframe(precvframe, pfree_recv_queue);
+ rtw_free_recvframe((struct recv_frame *)hdr, pfree_recv_queue);
}
spin_unlock(&pframequeue->lock);
-_func_exit_;
}
u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter)
{
u32 cnt = 0;
- union recv_frame *pending_frame;
+ struct recv_frame *pending_frame;
while ((pending_frame = rtw_alloc_recvframe(&adapter->recvpriv.uc_swdec_pending_queue))) {
rtw_free_recvframe(pending_frame, &adapter->recvpriv.free_recv_queue);
DBG_88E("%s: dequeue uc_swdec_pending_queue\n", __func__);
@@ -337,9 +326,9 @@ struct recv_buf *rtw_dequeue_recvbuf (struct __queue *queue)
} else {
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
- precvbuf = LIST_CONTAINOR(plist, struct recv_buf, list);
+ precvbuf = container_of(plist, struct recv_buf, list);
rtw_list_delete(&precvbuf->list);
}
@@ -349,7 +338,8 @@ struct recv_buf *rtw_dequeue_recvbuf (struct __queue *queue)
return precvbuf;
}
-static int recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe)
+static int recvframe_chkmic(struct adapter *adapter,
+ struct recv_frame *precvframe)
{
int i, res = _SUCCESS;
u32 datalen;
@@ -358,12 +348,11 @@ static int recvframe_chkmic(struct adapter *adapter, union recv_frame *precvfra
u8 *pframe, *payload, *pframemic;
u8 *mickey;
struct sta_info *stainfo;
- struct rx_pkt_attrib *prxattrib = &precvframe->u.hdr.attrib;
+ struct rx_pkt_attrib *prxattrib = &precvframe->attrib;
struct security_priv *psecuritypriv = &adapter->securitypriv;
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
-_func_enter_;
stainfo = rtw_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]);
@@ -375,23 +364,24 @@ _func_enter_;
/* calculate mic code */
if (stainfo != NULL) {
if (IS_MCAST(prxattrib->ra)) {
- mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0];
-
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic: bcmc key\n"));
-
if (!psecuritypriv) {
res = _FAIL;
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n"));
DBG_88E("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n");
goto exit;
}
+ mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0];
+
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic: bcmc key\n"));
} else {
mickey = &stainfo->dot11tkiprxmickey.skey[0];
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic: unicast key\n"));
}
- datalen = precvframe->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len-prxattrib->icv_len-8;/* icv_len included the mic code */
- pframe = precvframe->u.hdr.rx_data;
+ /* icv_len included the mic code */
+ datalen = precvframe->len-prxattrib->hdrlen -
+ prxattrib->iv_len-prxattrib->icv_len-8;
+ pframe = precvframe->rx_data;
payload = pframe+prxattrib->hdrlen+prxattrib->iv_len;
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n prxattrib->iv_len=%d prxattrib->icv_len=%d\n", prxattrib->iv_len, prxattrib->icv_len));
@@ -424,16 +414,30 @@ _func_enter_;
*(pframemic-10), *(pframemic-9)));
{
uint i;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ======demp packet (len=%d)======\n", precvframe->u.hdr.len));
- for (i = 0; i < precvframe->u.hdr.len; i = i+8) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x",
- *(precvframe->u.hdr.rx_data+i), *(precvframe->u.hdr.rx_data+i+1),
- *(precvframe->u.hdr.rx_data+i+2), *(precvframe->u.hdr.rx_data+i+3),
- *(precvframe->u.hdr.rx_data+i+4), *(precvframe->u.hdr.rx_data+i+5),
- *(precvframe->u.hdr.rx_data+i+6), *(precvframe->u.hdr.rx_data+i+7)));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+ ("\n ======demp packet (len=%d)======\n",
+ precvframe->len));
+ for (i = 0; i < precvframe->len; i += 8) {
+ RT_TRACE(_module_rtl871x_recv_c_,
+ _drv_err_,
+ ("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x",
+ *(precvframe->rx_data+i),
+ *(precvframe->rx_data+i+1),
+ *(precvframe->rx_data+i+2),
+ *(precvframe->rx_data+i+3),
+ *(precvframe->rx_data+i+4),
+ *(precvframe->rx_data+i+5),
+ *(precvframe->rx_data+i+6),
+ *(precvframe->rx_data+i+7)));
}
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ====== demp packet end [len=%d]======\n", precvframe->u.hdr.len));
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n hrdlen=%d,\n", prxattrib->hdrlen));
+ RT_TRACE(_module_rtl871x_recv_c_,
+ _drv_err_,
+ ("\n ====== demp packet end [len=%d]======\n",
+ precvframe->len));
+ RT_TRACE(_module_rtl871x_recv_c_,
+ _drv_err_,
+ ("\n hrdlen=%d,\n",
+ prxattrib->hdrlen));
}
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
@@ -471,24 +475,23 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
/* decrypt and set the ivlen, icvlen of the recv_frame */
-static union recv_frame *decryptor(struct adapter *padapter, union recv_frame *precv_frame)
+static struct recv_frame *decryptor(struct adapter *padapter,
+ struct recv_frame *precv_frame)
{
- struct rx_pkt_attrib *prxattrib = &precv_frame->u.hdr.attrib;
+ struct rx_pkt_attrib *prxattrib = &precv_frame->attrib;
struct security_priv *psecuritypriv = &padapter->securitypriv;
- union recv_frame *return_packet = precv_frame;
+ struct recv_frame *return_packet = precv_frame;
u32 res = _SUCCESS;
-_func_enter_;
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("prxstat->decrypted=%x prxattrib->encrypt=0x%03x\n", prxattrib->bdecrypted, prxattrib->encrypt));
if (prxattrib->encrypt > 0) {
- u8 *iv = precv_frame->u.hdr.rx_data+prxattrib->hdrlen;
+ u8 *iv = precv_frame->rx_data+prxattrib->hdrlen;
prxattrib->key_index = (((iv[3])>>6)&0x3);
if (prxattrib->key_index > WEP_KEYS) {
@@ -534,34 +537,33 @@ _func_enter_;
return_packet = NULL;
}
-_func_exit_;
return return_packet;
}
/* set the security information in the recv_frame */
-static union recv_frame *portctrl(struct adapter *adapter, union recv_frame *precv_frame)
+static struct recv_frame *portctrl(struct adapter *adapter,
+ struct recv_frame *precv_frame)
{
u8 *psta_addr = NULL, *ptr;
uint auth_alg;
- struct recv_frame_hdr *pfhdr;
+ struct recv_frame *pfhdr;
struct sta_info *psta;
struct sta_priv *pstapriv;
- union recv_frame *prtnframe;
+ struct recv_frame *prtnframe;
u16 ether_type = 0;
u16 eapol_type = 0x888e;/* for Funia BD's WPA issue */
struct rx_pkt_attrib *pattrib;
__be16 be_tmp;
-_func_enter_;
pstapriv = &adapter->stapriv;
psta = rtw_get_stainfo(pstapriv, psta_addr);
auth_alg = adapter->securitypriv.dot11AuthAlgrthm;
- ptr = get_recvframe_data(precv_frame);
- pfhdr = &precv_frame->u.hdr;
+ ptr = precv_frame->rx_data;
+ pfhdr = precv_frame;
pattrib = &pfhdr->attrib;
psta_addr = pattrib->ta;
@@ -593,7 +595,9 @@ _func_enter_;
/* allowed */
/* check decryption status, and decrypt the frame if needed */
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==0\n"));
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:precv_frame->hdr.attrib.privacy=%x\n", precv_frame->u.hdr.attrib.privacy));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+ ("portctrl:precv_frame->hdr.attrib.privacy=%x\n",
+ precv_frame->attrib.privacy));
if (pattrib->bdecrypted == 0)
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:prxstat->decrypted=%x\n", pattrib->bdecrypted));
@@ -613,19 +617,18 @@ _func_enter_;
prtnframe = precv_frame;
}
-_func_exit_;
return prtnframe;
}
-static int recv_decache(union recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache)
+static int recv_decache(struct recv_frame *precv_frame, u8 bretry,
+ struct stainfo_rxcache *prxcache)
{
- int tid = precv_frame->u.hdr.attrib.priority;
+ int tid = precv_frame->attrib.priority;
- u16 seq_ctrl = ((precv_frame->u.hdr.attrib.seq_num&0xffff) << 4) |
- (precv_frame->u.hdr.attrib.frag_num & 0xf);
+ u16 seq_ctrl = ((precv_frame->attrib.seq_num&0xffff) << 4) |
+ (precv_frame->attrib.frag_num & 0xf);
-_func_enter_;
if (tid > 15) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, (tid>15)! seq_ctrl=0x%x, tid=0x%x\n", seq_ctrl, tid));
@@ -643,18 +646,17 @@ _func_enter_;
prxcache->tid_rxseq[tid] = seq_ctrl;
-_func_exit_;
return _SUCCESS;
}
-void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame);
-void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame)
+void process_pwrbit_data(struct adapter *padapter,
+ struct recv_frame *precv_frame)
{
#ifdef CONFIG_88EU_AP_MODE
unsigned char pwrbit;
- u8 *ptr = precv_frame->u.hdr.rx_data;
- struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ u8 *ptr = precv_frame->rx_data;
+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
struct sta_priv *pstapriv = &padapter->stapriv;
struct sta_info *psta = NULL;
@@ -675,10 +677,11 @@ void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame
#endif
}
-static void process_wmmps_data(struct adapter *padapter, union recv_frame *precv_frame)
+static void process_wmmps_data(struct adapter *padapter,
+ struct recv_frame *precv_frame)
{
#ifdef CONFIG_88EU_AP_MODE
- struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
struct sta_priv *pstapriv = &padapter->stapriv;
struct sta_info *psta = NULL;
@@ -730,15 +733,17 @@ static void process_wmmps_data(struct adapter *padapter, union recv_frame *precv
#endif
}
-static void count_rx_stats(struct adapter *padapter, union recv_frame *prframe, struct sta_info *sta)
+static void count_rx_stats(struct adapter *padapter,
+ struct recv_frame *prframe,
+ struct sta_info *sta)
{
int sz;
struct sta_info *psta = NULL;
struct stainfo_stats *pstats = NULL;
- struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
+ struct rx_pkt_attrib *pattrib = &prframe->attrib;
struct recv_priv *precvpriv = &padapter->recvpriv;
- sz = get_recvframe_len(prframe);
+ sz = prframe->len;
precvpriv->rx_bytes += sz;
padapter->mlmepriv.LinkDetectInfo.NumRxOkInPeriod++;
@@ -749,7 +754,7 @@ static void count_rx_stats(struct adapter *padapter, union recv_frame *prframe,
if (sta)
psta = sta;
else
- psta = prframe->u.hdr.psta;
+ psta = prframe->psta;
if (psta) {
pstats = &psta->sta_stats;
@@ -761,15 +766,16 @@ static void count_rx_stats(struct adapter *padapter, union recv_frame *prframe,
int sta2sta_data_frame(
struct adapter *adapter,
- union recv_frame *precv_frame,
+ struct recv_frame *precv_frame,
struct sta_info **psta
);
-int sta2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, struct sta_info **psta)
+int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame,
+ struct sta_info **psta)
{
- u8 *ptr = precv_frame->u.hdr.rx_data;
+ u8 *ptr = precv_frame->rx_data;
int ret = _SUCCESS;
- struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
struct sta_priv *pstapriv = &adapter->stapriv;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
u8 *mybssid = get_bssid(pmlmepriv);
@@ -777,25 +783,24 @@ int sta2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, s
u8 *sta_addr = NULL;
int bmcast = IS_MCAST(pattrib->dst);
-_func_enter_;
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) {
/* filter packets that SA is myself or multicast or broadcast */
- if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)) {
+ if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA==myself\n"));
ret = _FAIL;
goto exit;
}
- if ((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) {
+ if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) {
ret = _FAIL;
goto exit;
}
- if (_rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
- _rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
- !_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN)) {
+ if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+ !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+ memcmp(pattrib->bssid, mybssid, ETH_ALEN)) {
ret = _FAIL;
goto exit;
}
@@ -803,7 +808,7 @@ _func_enter_;
sta_addr = pattrib->src;
} else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
/* For Station mode, sa and bssid should always be BSSID, and DA is my mac-address */
- if (!_rtw_memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) {
+ if (memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("bssid!=TA under STATION_MODE; drop pkt\n"));
ret = _FAIL;
goto exit;
@@ -818,7 +823,7 @@ _func_enter_;
}
} else { /* not mc-frame */
/* For AP mode, if DA is non-MCAST, then it must be BSSID, and bssid == BSSID */
- if (!_rtw_memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN)) {
+ if (memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN)) {
ret = _FAIL;
goto exit;
}
@@ -853,17 +858,16 @@ _func_enter_;
}
exit:
-_func_exit_;
return ret;
}
static int ap2sta_data_frame (
struct adapter *adapter,
- union recv_frame *precv_frame,
+ struct recv_frame *precv_frame,
struct sta_info **psta)
{
- u8 *ptr = precv_frame->u.hdr.rx_data;
- struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ u8 *ptr = precv_frame->rx_data;
+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
int ret = _SUCCESS;
struct sta_priv *pstapriv = &adapter->stapriv;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
@@ -871,20 +875,19 @@ static int ap2sta_data_frame (
u8 *myhwaddr = myid(&adapter->eeprompriv);
int bmcast = IS_MCAST(pattrib->dst);
-_func_enter_;
if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) &&
(check_fwstate(pmlmepriv, _FW_LINKED) == true ||
check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) {
/* filter packets that SA is myself or multicast or broadcast */
- if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)) {
+ if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA==myself\n"));
ret = _FAIL;
goto exit;
}
/* da should be for me */
- if ((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) {
+ if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
(" ap2sta_data_frame: compare DA fail; DA=%pM\n", (pattrib->dst)));
ret = _FAIL;
@@ -892,9 +895,9 @@ _func_enter_;
}
/* check BSSID */
- if (_rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
- _rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
- (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN))) {
+ if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+ !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+ (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
(" ap2sta_data_frame: compare BSSID fail ; BSSID=%pM\n", (pattrib->bssid)));
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("mybssid=%pM\n", (mybssid)));
@@ -950,7 +953,7 @@ _func_enter_;
ret = RTW_RX_HANDLED;
goto exit;
} else {
- if (_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && (!bmcast)) {
+ if (!memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && (!bmcast)) {
*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */
if (*psta == NULL) {
DBG_88E("issue_deauth to the ap =%pM for the reason(7)\n", (pattrib->bssid));
@@ -964,27 +967,25 @@ _func_enter_;
exit:
-_func_exit_;
return ret;
}
static int sta2ap_data_frame(struct adapter *adapter,
- union recv_frame *precv_frame,
+ struct recv_frame *precv_frame,
struct sta_info **psta)
{
- struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
struct sta_priv *pstapriv = &adapter->stapriv;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
- u8 *ptr = precv_frame->u.hdr.rx_data;
+ u8 *ptr = precv_frame->rx_data;
unsigned char *mybssid = get_bssid(pmlmepriv);
int ret = _SUCCESS;
-_func_enter_;
if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
/* For AP mode, RA = BSSID, TX = STA(SRC_ADDR), A3 = DST_ADDR */
- if (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN)) {
+ if (memcmp(pattrib->bssid, mybssid, ETH_ALEN)) {
ret = _FAIL;
goto exit;
}
@@ -1014,7 +1015,7 @@ _func_enter_;
}
} else {
u8 *myhwaddr = myid(&adapter->eeprompriv);
- if (!_rtw_memcmp(pattrib->ra, myhwaddr, ETH_ALEN)) {
+ if (memcmp(pattrib->ra, myhwaddr, ETH_ALEN)) {
ret = RTW_RX_HANDLED;
goto exit;
}
@@ -1026,25 +1027,23 @@ _func_enter_;
exit:
-_func_exit_;
return ret;
}
static int validate_recv_ctrl_frame(struct adapter *padapter,
- union recv_frame *precv_frame)
+ struct recv_frame *precv_frame)
{
#ifdef CONFIG_88EU_AP_MODE
- struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
struct sta_priv *pstapriv = &padapter->stapriv;
- u8 *pframe = precv_frame->u.hdr.rx_data;
- /* uint len = precv_frame->u.hdr.len; */
+ u8 *pframe = precv_frame->rx_data;
if (GetFrameType(pframe) != WIFI_CTRL_TYPE)
return _FAIL;
/* receive the frames that ra(a1) is my address */
- if (!_rtw_memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN))
+ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN))
return _FAIL;
/* only handle ps-poll */
@@ -1098,12 +1097,12 @@ static int validate_recv_ctrl_frame(struct adapter *padapter,
spin_lock_bh(&psta->sleep_q.lock);
xmitframe_phead = get_list_head(&psta->sleep_q);
- xmitframe_plist = get_next(xmitframe_phead);
+ xmitframe_plist = xmitframe_phead->next;
if ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == false) {
- pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
- xmitframe_plist = get_next(xmitframe_plist);
+ xmitframe_plist = xmitframe_plist->next;
rtw_list_delete(&pxmitframe->list);
@@ -1124,7 +1123,7 @@ static int validate_recv_ctrl_frame(struct adapter *padapter,
if (psta->sleepq_len == 0) {
pstapriv->tim_bitmap &= ~BIT(psta->aid);
- /* upate BCN for TIM IE */
+ /* update BCN for TIM IE */
/* update_BCNTIM(padapter); */
update_beacon(padapter, _TIM_IE_, NULL, false);
}
@@ -1142,7 +1141,7 @@ static int validate_recv_ctrl_frame(struct adapter *padapter,
pstapriv->tim_bitmap &= ~BIT(psta->aid);
- /* upate BCN for TIM IE */
+ /* update BCN for TIM IE */
/* update_BCNTIM(padapter); */
update_beacon(padapter, _TIM_IE_, NULL, false);
}
@@ -1157,10 +1156,11 @@ static int validate_recv_ctrl_frame(struct adapter *padapter,
return _FAIL;
}
-union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_frame *precv_frame);
+struct recv_frame *recvframe_chk_defrag(struct adapter *padapter,
+ struct recv_frame *precv_frame);
static int validate_recv_mgnt_frame(struct adapter *padapter,
- union recv_frame *precv_frame)
+ struct recv_frame *precv_frame)
{
struct sta_info *psta;
@@ -1173,18 +1173,20 @@ static int validate_recv_mgnt_frame(struct adapter *padapter,
}
/* for rx pkt statistics */
- psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(precv_frame->u.hdr.rx_data));
+ psta = rtw_get_stainfo(&padapter->stapriv,
+ GetAddr2Ptr(precv_frame->rx_data));
if (psta) {
psta->sta_stats.rx_mgnt_pkts++;
- if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_BEACON) {
+ if (GetFrameSubType(precv_frame->rx_data) == WIFI_BEACON) {
psta->sta_stats.rx_beacon_pkts++;
- } else if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_PROBEREQ) {
+ } else if (GetFrameSubType(precv_frame->rx_data) == WIFI_PROBEREQ) {
psta->sta_stats.rx_probereq_pkts++;
- } else if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_PROBERSP) {
- if (_rtw_memcmp(padapter->eeprompriv.mac_addr, GetAddr1Ptr(precv_frame->u.hdr.rx_data), ETH_ALEN) == true)
+ } else if (GetFrameSubType(precv_frame->rx_data) == WIFI_PROBERSP) {
+ if (!memcmp(padapter->eeprompriv.mac_addr,
+ GetAddr1Ptr(precv_frame->rx_data), ETH_ALEN))
psta->sta_stats.rx_probersp_pkts++;
- else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data)) ||
- is_multicast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data)))
+ else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->rx_data)) ||
+ is_multicast_mac_addr(GetAddr1Ptr(precv_frame->rx_data)))
psta->sta_stats.rx_probersp_bm_pkts++;
else
psta->sta_stats.rx_probersp_uo_pkts++;
@@ -1197,17 +1199,16 @@ static int validate_recv_mgnt_frame(struct adapter *padapter,
}
static int validate_recv_data_frame(struct adapter *adapter,
- union recv_frame *precv_frame)
+ struct recv_frame *precv_frame)
{
u8 bretry;
u8 *psa, *pda, *pbssid;
struct sta_info *psta = NULL;
- u8 *ptr = precv_frame->u.hdr.rx_data;
- struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ u8 *ptr = precv_frame->rx_data;
+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
struct security_priv *psecuritypriv = &adapter->securitypriv;
int ret = _SUCCESS;
-_func_enter_;
bretry = GetRetry(ptr);
pda = get_da(ptr);
@@ -1265,7 +1266,7 @@ _func_enter_;
/* psta->rssi = prxcmd->rssi; */
/* psta->signal_quality = prxcmd->sq; */
- precv_frame->u.hdr.psta = psta;
+ precv_frame->psta = psta;
pattrib->amsdu = 0;
pattrib->ack_policy = 0;
@@ -1286,7 +1287,7 @@ _func_enter_;
if (pattrib->order)/* HT-CTRL 11n */
pattrib->hdrlen += 4;
- precv_frame->u.hdr.preorder_ctrl = &psta->recvreorder_ctrl[pattrib->priority];
+ precv_frame->preorder_ctrl = &psta->recvreorder_ctrl[pattrib->priority];
/* decache, drop duplicate recv packets */
if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == _FAIL) {
@@ -1312,12 +1313,12 @@ _func_enter_;
exit:
-_func_exit_;
return ret;
}
-static int validate_recv_frame(struct adapter *adapter, union recv_frame *precv_frame)
+static int validate_recv_frame(struct adapter *adapter,
+ struct recv_frame *precv_frame)
{
/* shall check frame subtype, to / from ds, da, bssid */
@@ -1327,12 +1328,11 @@ static int validate_recv_frame(struct adapter *adapter, union recv_frame *precv_
u8 subtype;
int retval = _SUCCESS;
u8 bDumpRxPkt;
- struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
- u8 *ptr = precv_frame->u.hdr.rx_data;
+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
+ u8 *ptr = precv_frame->rx_data;
u8 ver = (unsigned char) (*ptr)&0x3;
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
-_func_enter_;
if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
int ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, rtw_get_oper_ch(adapter));
@@ -1422,14 +1422,13 @@ _func_enter_;
exit:
-_func_exit_;
return retval;
}
/* remove the wlanhdr and add the eth_hdr */
-static int wlanhdr_to_ethhdr (union recv_frame *precvframe)
+static int wlanhdr_to_ethhdr(struct recv_frame *precvframe)
{
int rmv_len;
u16 eth_type, len;
@@ -1439,13 +1438,10 @@ static int wlanhdr_to_ethhdr (union recv_frame *precvframe)
struct ieee80211_snap_hdr *psnap;
int ret = _SUCCESS;
- struct adapter *adapter = precvframe->u.hdr.adapter;
+ struct adapter *adapter = precvframe->adapter;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
-
- u8 *ptr = get_recvframe_data(precvframe); /* point to frame_ctrl field */
- struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
-
-_func_enter_;
+ u8 *ptr = precvframe->rx_data;
+ struct rx_pkt_attrib *pattrib = &precvframe->attrib;
if (pattrib->encrypt)
recvframe_pull_tail(precvframe, pattrib->icv_len);
@@ -1453,10 +1449,10 @@ _func_enter_;
psnap = (struct ieee80211_snap_hdr *)(ptr+pattrib->hdrlen + pattrib->iv_len);
psnap_type = ptr+pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE;
/* convert hdr + possible LLC headers into Ethernet header */
- if ((_rtw_memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) &&
- (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) == false) &&
- (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2) == false)) ||
- _rtw_memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)) {
+ if ((!memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) &&
+ (!memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) == false) &&
+ (!memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2) == false)) ||
+ !memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)) {
/* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */
bsnaphdr = true;
} else {
@@ -1465,7 +1461,7 @@ _func_enter_;
}
rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0);
- len = precvframe->u.hdr.len - rmv_len;
+ len = precvframe->len - rmv_len;
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
("\n===pattrib->hdrlen: %x, pattrib->iv_len:%x===\n\n", pattrib->hdrlen, pattrib->iv_len));
@@ -1496,30 +1492,29 @@ _func_enter_;
memcpy(ptr+12, &be_tmp, 2);
}
-_func_exit_;
return ret;
}
/* perform defrag */
-static union recv_frame *recvframe_defrag(struct adapter *adapter, struct __queue *defrag_q)
+static struct recv_frame *recvframe_defrag(struct adapter *adapter,
+ struct __queue *defrag_q)
{
struct list_head *plist, *phead;
u8 wlanhdr_offset;
u8 curfragnum;
- struct recv_frame_hdr *pfhdr, *pnfhdr;
- union recv_frame *prframe, *pnextrframe;
+ struct recv_frame *pfhdr, *pnfhdr;
+ struct recv_frame *prframe, *pnextrframe;
struct __queue *pfree_recv_queue;
-_func_enter_;
curfragnum = 0;
pfree_recv_queue = &adapter->recvpriv.free_recv_queue;
phead = get_list_head(defrag_q);
- plist = get_next(phead);
- prframe = LIST_CONTAINOR(plist, union recv_frame, u);
- pfhdr = &prframe->u.hdr;
- rtw_list_delete(&(prframe->u.list));
+ plist = phead->next;
+ pfhdr = container_of(plist, struct recv_frame, list);
+ prframe = (struct recv_frame *)pfhdr;
+ rtw_list_delete(&(prframe->list));
if (curfragnum != pfhdr->attrib.frag_num) {
/* the first fragment number must be 0 */
@@ -1534,11 +1529,11 @@ _func_enter_;
plist = get_list_head(defrag_q);
- plist = get_next(plist);
+ plist = plist->next;
while (rtw_end_of_queue_search(phead, plist) == false) {
- pnextrframe = LIST_CONTAINOR(plist, union recv_frame , u);
- pnfhdr = &pnextrframe->u.hdr;
+ pnfhdr = container_of(plist, struct recv_frame, list);
+ pnextrframe = (struct recv_frame *)pnfhdr;
/* check the fragment sequence (2nd ~n fragment frame) */
@@ -1568,7 +1563,7 @@ _func_enter_;
recvframe_put(prframe, pnfhdr->len);
pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len;
- plist = get_next(plist);
+ plist = plist->next;
}
/* free the defrag_q queue and return the prframe */
@@ -1576,29 +1571,28 @@ _func_enter_;
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Performance defrag!!!!!\n"));
-_func_exit_;
return prframe;
}
/* check if need to defrag, if needed queue the frame to defrag_q */
-union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_frame *precv_frame)
+struct recv_frame *recvframe_chk_defrag(struct adapter *padapter,
+ struct recv_frame *precv_frame)
{
u8 ismfrag;
u8 fragnum;
u8 *psta_addr;
- struct recv_frame_hdr *pfhdr;
+ struct recv_frame *pfhdr;
struct sta_info *psta;
struct sta_priv *pstapriv;
struct list_head *phead;
- union recv_frame *prtnframe = NULL;
+ struct recv_frame *prtnframe = NULL;
struct __queue *pfree_recv_queue, *pdefrag_q;
-_func_enter_;
pstapriv = &padapter->stapriv;
- pfhdr = &precv_frame->u.hdr;
+ pfhdr = precv_frame;
pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
@@ -1670,7 +1664,7 @@ _func_enter_;
}
}
- if ((prtnframe != NULL) && (prtnframe->u.hdr.attrib.privacy)) {
+ if ((prtnframe != NULL) && (prtnframe->attrib.privacy)) {
/* after defrag we must check tkip mic code */
if (recvframe_chkmic(padapter, prtnframe) == _FAIL) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic(padapter, prtnframe)==_FAIL\n"));
@@ -1679,12 +1673,11 @@ _func_enter_;
}
}
-_func_exit_;
return prtnframe;
}
-static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
+static int amsdu_to_msdu(struct adapter *padapter, struct recv_frame *prframe)
{
int a_len, padding_len;
u16 eth_type, nSubframe_Length;
@@ -1698,16 +1691,16 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
int ret = _SUCCESS;
nr_subframes = 0;
- pattrib = &prframe->u.hdr.attrib;
+ pattrib = &prframe->attrib;
- recvframe_pull(prframe, prframe->u.hdr.attrib.hdrlen);
+ recvframe_pull(prframe, prframe->attrib.hdrlen);
- if (prframe->u.hdr.attrib.iv_len > 0)
- recvframe_pull(prframe, prframe->u.hdr.attrib.iv_len);
+ if (prframe->attrib.iv_len > 0)
+ recvframe_pull(prframe, prframe->attrib.iv_len);
- a_len = prframe->u.hdr.len;
+ a_len = prframe->len;
- pdata = prframe->u.hdr.rx_data;
+ pdata = prframe->rx_data;
while (a_len > ETH_HLEN) {
/* Offset 12 denote 2 mac address */
@@ -1729,7 +1722,7 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length);
memcpy(data_ptr, pdata, nSubframe_Length);
} else {
- sub_skb = skb_clone(prframe->u.hdr.pkt, GFP_ATOMIC);
+ sub_skb = skb_clone(prframe->pkt, GFP_ATOMIC);
if (sub_skb) {
sub_skb->data = pdata;
sub_skb->len = nSubframe_Length;
@@ -1768,9 +1761,9 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
/* convert hdr + possible LLC headers into Ethernet header */
eth_type = RTW_GET_BE16(&sub_skb->data[6]);
if (sub_skb->len >= 8 &&
- ((_rtw_memcmp(sub_skb->data, rtw_rfc1042_header, SNAP_SIZE) &&
+ ((!memcmp(sub_skb->data, rtw_rfc1042_header, SNAP_SIZE) &&
eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) ||
- _rtw_memcmp(sub_skb->data, rtw_bridge_tunnel_header, SNAP_SIZE))) {
+ !memcmp(sub_skb->data, rtw_bridge_tunnel_header, SNAP_SIZE))) {
/* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */
skb_pull(sub_skb, SNAP_SIZE);
memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN);
@@ -1796,7 +1789,7 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
exit:
- prframe->u.hdr.len = 0;
+ prframe->len = 0;
rtw_free_recvframe(prframe, pfree_recv_queue);/* free this recv_frame */
return ret;
@@ -1832,70 +1825,72 @@ static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_n
return true;
}
-int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe);
-int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe)
+int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl,
+ struct recv_frame *prframe)
{
- struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
+ struct rx_pkt_attrib *pattrib = &prframe->attrib;
struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
struct list_head *phead, *plist;
- union recv_frame *pnextrframe;
+ struct recv_frame *hdr;
struct rx_pkt_attrib *pnextattrib;
phead = get_list_head(ppending_recvframe_queue);
- plist = get_next(phead);
+ plist = phead->next;
while (rtw_end_of_queue_search(phead, plist) == false) {
- pnextrframe = LIST_CONTAINOR(plist, union recv_frame, u);
- pnextattrib = &pnextrframe->u.hdr.attrib;
+ hdr = container_of(plist, struct recv_frame, list);
+ pnextattrib = &hdr->attrib;
if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num))
- plist = get_next(plist);
+ plist = plist->next;
else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num))
return false;
else
break;
}
- rtw_list_delete(&(prframe->u.hdr.list));
+ rtw_list_delete(&(prframe->list));
- rtw_list_insert_tail(&(prframe->u.hdr.list), plist);
+ rtw_list_insert_tail(&(prframe->list), plist);
return true;
}
static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced)
{
struct list_head *phead, *plist;
- union recv_frame *prframe;
+ struct recv_frame *prframe;
+ struct recv_frame *prhdr;
struct rx_pkt_attrib *pattrib;
int bPktInBuf = false;
struct recv_priv *precvpriv = &padapter->recvpriv;
struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
phead = get_list_head(ppending_recvframe_queue);
- plist = get_next(phead);
+ plist = phead->next;
/* Handling some condition for forced indicate case. */
if (bforced) {
if (rtw_is_list_empty(phead))
return true;
- prframe = LIST_CONTAINOR(plist, union recv_frame, u);
- pattrib = &prframe->u.hdr.attrib;
+ prhdr = container_of(plist, struct recv_frame, list);
+ pattrib = &prhdr->attrib;
preorder_ctrl->indicate_seq = pattrib->seq_num;
}
/* Prepare indication list and indication. */
/* Check if there is any packet need indicate. */
while (!rtw_is_list_empty(phead)) {
- prframe = LIST_CONTAINOR(plist, union recv_frame, u);
- pattrib = &prframe->u.hdr.attrib;
+ prhdr = container_of(plist, struct recv_frame, list);
+ prframe = (struct recv_frame *)prhdr;
+ pattrib = &prframe->attrib;
if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
("recv_indicatepkts_in_order: indicate=%d seq=%d amsdu=%d\n",
preorder_ctrl->indicate_seq, pattrib->seq_num, pattrib->amsdu));
- plist = get_next(plist);
- rtw_list_delete(&(prframe->u.hdr.list));
+ plist = plist->next;
+ rtw_list_delete(&(prframe->list));
if (SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num))
preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF;
@@ -1924,11 +1919,12 @@ static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reor
return bPktInBuf;
}
-static int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *prframe)
+static int recv_indicatepkt_reorder(struct adapter *padapter,
+ struct recv_frame *prframe)
{
int retval = _SUCCESS;
- struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
- struct recv_reorder_ctrl *preorder_ctrl = prframe->u.hdr.preorder_ctrl;
+ struct rx_pkt_attrib *pattrib = &prframe->attrib;
+ struct recv_reorder_ctrl *preorder_ctrl = prframe->preorder_ctrl;
struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
if (!pattrib->amsdu) {
@@ -2001,7 +1997,7 @@ static int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *
spin_unlock_bh(&ppending_recvframe_queue->lock);
} else {
spin_unlock_bh(&ppending_recvframe_queue->lock);
- _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);
+ del_timer_sync(&preorder_ctrl->reordering_ctrl_timer);
}
_success_exit:
@@ -2032,17 +2028,14 @@ void rtw_reordering_ctrl_timeout_handler(void *pcontext)
spin_unlock_bh(&ppending_recvframe_queue->lock);
}
-static int process_recv_indicatepkts(struct adapter *padapter, union recv_frame *prframe)
+static int process_recv_indicatepkts(struct adapter *padapter,
+ struct recv_frame *prframe)
{
int retval = _SUCCESS;
- /* struct recv_priv *precvpriv = &padapter->recvpriv; */
- /* struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; */
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct ht_priv *phtpriv = &pmlmepriv->htpriv;
if (phtpriv->ht_option) { /* B/G/N Mode */
- /* prframe->u.hdr.preorder_ctrl = &precvpriv->recvreorder_ctrl[pattrib->priority]; */
-
if (recv_indicatepkt_reorder(padapter, prframe) != _SUCCESS) {
/* including perform A-MPDU Rx Ordering Buffer Control */
if ((!padapter->bDriverStopped) &&
@@ -2075,10 +2068,11 @@ static int process_recv_indicatepkts(struct adapter *padapter, union recv_frame
return retval;
}
-static int recv_func_prehandle(struct adapter *padapter, union recv_frame *rframe)
+static int recv_func_prehandle(struct adapter *padapter,
+ struct recv_frame *rframe)
{
int ret = _SUCCESS;
- struct rx_pkt_attrib *pattrib = &rframe->u.hdr.attrib;
+ struct rx_pkt_attrib *pattrib = &rframe->attrib;
struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -2110,10 +2104,11 @@ exit:
return ret;
}
-static int recv_func_posthandle(struct adapter *padapter, union recv_frame *prframe)
+static int recv_func_posthandle(struct adapter *padapter,
+ struct recv_frame *prframe)
{
int ret = _SUCCESS;
- union recv_frame *orig_prframe = prframe;
+ struct recv_frame *orig_prframe = prframe;
struct recv_priv *precvpriv = &padapter->recvpriv;
struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
@@ -2155,16 +2150,16 @@ _recv_data_drop:
return ret;
}
-static int recv_func(struct adapter *padapter, union recv_frame *rframe)
+static int recv_func(struct adapter *padapter, struct recv_frame *rframe)
{
int ret;
- struct rx_pkt_attrib *prxattrib = &rframe->u.hdr.attrib;
+ struct rx_pkt_attrib *prxattrib = &rframe->attrib;
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct mlme_priv *mlmepriv = &padapter->mlmepriv;
/* check if need to handle uc_swdec_pending_queue*/
if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && psecuritypriv->busetkipkey) {
- union recv_frame *pending_frame;
+ struct recv_frame *pending_frame;
while ((pending_frame = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue))) {
if (recv_func_posthandle(padapter, pending_frame) == _SUCCESS)
@@ -2193,15 +2188,14 @@ exit:
return ret;
}
-s32 rtw_recv_entry(union recv_frame *precvframe)
+s32 rtw_recv_entry(struct recv_frame *precvframe)
{
struct adapter *padapter;
struct recv_priv *precvpriv;
s32 ret = _SUCCESS;
-_func_enter_;
- padapter = precvframe->u.hdr.adapter;
+ padapter = precvframe->adapter;
precvpriv = &padapter->recvpriv;
@@ -2213,7 +2207,6 @@ _func_enter_;
precvpriv->rx_pkts++;
-_func_exit_;
return ret;
@@ -2222,7 +2215,6 @@ _recv_entry_drop:
if (padapter->registrypriv.mp_mode == 1)
padapter->mppriv.rx_pktloss = precvpriv->rx_drop;
-_func_exit_;
return ret;
}
@@ -2244,13 +2236,13 @@ void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS)
} else {
if (recvpriv->signal_strength_data.update_req == 0) {/* update_req is clear, means we got rx */
avg_signal_strength = recvpriv->signal_strength_data.avg_val;
- /* after avg_vals are accquired, we can re-stat the signal values */
+ /* after avg_vals are acquired, we can re-stat the signal values */
recvpriv->signal_strength_data.update_req = 1;
}
if (recvpriv->signal_qual_data.update_req == 0) {/* update_req is clear, means we got rx */
avg_signal_qual = recvpriv->signal_qual_data.avg_val;
- /* after avg_vals are accquired, we can re-stat the signal values */
+ /* after avg_vals are acquired, we can re-stat the signal values */
recvpriv->signal_qual_data.update_req = 1;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c
index e08845729772..c4b16ea6348a 100644
--- a/drivers/staging/rtl8188eu/core/rtw_security.c
+++ b/drivers/staging/rtl8188eu/core/rtw_security.c
@@ -41,7 +41,6 @@ static void arcfour_init(struct arc4context *parc4ctx, u8 *key, u32 key_len)
u32 stateindex;
u8 *state;
u32 counter;
-_func_enter_;
state = parc4ctx->state;
parc4ctx->x = 0;
parc4ctx->y = 0;
@@ -58,7 +57,6 @@ _func_enter_;
if (++keyindex >= key_len)
keyindex = 0;
}
-_func_exit_;
}
static u32 arcfour_byte(struct arc4context *parc4ctx)
@@ -67,7 +65,6 @@ static u32 arcfour_byte(struct arc4context *parc4ctx)
u32 y;
u32 sx, sy;
u8 *state;
-_func_enter_;
state = parc4ctx->state;
x = (parc4ctx->x + 1) & 0xff;
sx = state[x];
@@ -77,17 +74,14 @@ _func_enter_;
parc4ctx->y = y;
state[y] = (u8)sx;
state[x] = (u8)sy;
-_func_exit_;
return state[(sx + sy) & 0xff];
}
static void arcfour_encrypt(struct arc4context *parc4ctx, u8 *dest, u8 *src, u32 len)
{
u32 i;
-_func_enter_;
for (i = 0; i < len; i++)
dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx);
-_func_exit_;
}
static int bcrc32initialized;
@@ -102,9 +96,8 @@ static u8 crc32_reverseBit(u8 data)
static void crc32_init(void)
{
-_func_enter_;
if (bcrc32initialized == 1) {
- goto exit;
+ return;
} else {
int i, j;
u32 c;
@@ -126,15 +119,12 @@ _func_enter_;
}
bcrc32initialized = 1;
}
-exit:
-_func_exit_;
}
static __le32 getcrc32(u8 *buf, int len)
{
u8 *p;
u32 crc;
-_func_enter_;
if (bcrc32initialized == 0)
crc32_init();
@@ -142,7 +132,6 @@ _func_enter_;
for (p = buf; len > 0; ++p, --len)
crc = crc32_table[(crc ^ *p) & 0xff] ^ (crc >> 8);
-_func_exit_;
return cpu_to_le32(~crc); /* transmit complement, per CRC-32 spec */
}
@@ -165,7 +154,6 @@ void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe)
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
-_func_enter_;
if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL)
return;
@@ -206,7 +194,6 @@ _func_enter_;
}
}
-_func_exit_;
}
void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe)
@@ -218,12 +205,11 @@ void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe)
u32 keylength;
u8 *pframe, *payload, *iv, wepkey[16];
u8 keyindex;
- struct rx_pkt_attrib *prxattrib = &(((union recv_frame *)precvframe)->u.hdr.attrib);
+ struct rx_pkt_attrib *prxattrib = &(((struct recv_frame *)precvframe)->attrib);
struct security_priv *psecuritypriv = &padapter->securitypriv;
-_func_enter_;
- pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
+ pframe = (unsigned char *)((struct recv_frame *)precvframe)->rx_data;
/* start to decrypt recvframe */
if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == _WEP104_)) {
@@ -232,7 +218,7 @@ _func_enter_;
keylength = psecuritypriv->dot11DefKeylen[keyindex];
memcpy(&wepkey[0], iv, 3);
memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0], keylength);
- length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len;
+ length = ((struct recv_frame *)precvframe)->len-prxattrib->hdrlen-prxattrib->iv_len;
payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
@@ -252,7 +238,6 @@ _func_enter_;
&crc, &payload[length-4]));
}
}
-_func_exit_;
return;
}
@@ -263,10 +248,8 @@ static u32 secmicgetuint32(u8 *p)
{
s32 i;
u32 res = 0;
-_func_enter_;
for (i = 0; i < 4; i++)
res |= ((u32)(*p++)) << (8*i);
-_func_exit_;
return res;
}
@@ -274,39 +257,32 @@ static void secmicputuint32(u8 *p, u32 val)
/* Convert from Us3232 to Byte[] in a portable way */
{
long i;
-_func_enter_;
for (i = 0; i < 4; i++) {
*p++ = (u8) (val & 0xff);
val >>= 8;
}
-_func_exit_;
}
static void secmicclear(struct mic_data *pmicdata)
{
/* Reset the state to the empty message. */
-_func_enter_;
pmicdata->L = pmicdata->K0;
pmicdata->R = pmicdata->K1;
pmicdata->nBytesInM = 0;
pmicdata->M = 0;
-_func_exit_;
}
void rtw_secmicsetkey(struct mic_data *pmicdata, u8 *key)
{
/* Set the key */
-_func_enter_;
pmicdata->K0 = secmicgetuint32(key);
pmicdata->K1 = secmicgetuint32(key + 4);
/* and reset the message */
secmicclear(pmicdata);
-_func_exit_;
}
void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b)
{
-_func_enter_;
/* Append the byte to our word-sized buffer */
pmicdata->M |= ((unsigned long)b) << (8*pmicdata->nBytesInM);
pmicdata->nBytesInM++;
@@ -325,23 +301,19 @@ _func_enter_;
pmicdata->M = 0;
pmicdata->nBytesInM = 0;
}
-_func_exit_;
}
void rtw_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nbytes)
{
-_func_enter_;
/* This is simple */
while (nbytes > 0) {
rtw_secmicappendbyte(pmicdata, *src++);
nbytes--;
}
-_func_exit_;
}
void rtw_secgetmic(struct mic_data *pmicdata, u8 *dst)
{
-_func_enter_;
/* Append the minimum padding */
rtw_secmicappendbyte(pmicdata, 0x5a);
rtw_secmicappendbyte(pmicdata, 0);
@@ -356,14 +328,12 @@ _func_enter_;
secmicputuint32(dst+4, pmicdata->R);
/* Reset to the empty message. */
secmicclear(pmicdata);
-_func_exit_;
}
void rtw_seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len, u8 *mic_code, u8 pri)
{
struct mic_data micdata;
u8 priority[4] = {0x0, 0x0, 0x0, 0x0};
-_func_enter_;
rtw_secmicsetkey(&micdata, key);
priority[0] = pri;
@@ -386,7 +356,6 @@ _func_enter_;
rtw_secmicappend(&micdata, data, data_len);
rtw_secgetmic(&micdata, mic_code);
-_func_exit_;
}
@@ -505,7 +474,6 @@ static const unsigned short Sbox1[2][256] = { /* Sbox for hash (can be in ROM)
static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32)
{
int i;
-_func_enter_;
/* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */
p1k[0] = Lo16(iv32);
p1k[1] = Hi16(iv32);
@@ -523,7 +491,6 @@ _func_enter_;
p1k[4] += _S_(p1k[3] ^ TK16((i&1)+0));
p1k[4] += (unsigned short)i; /* avoid "slide attacks" */
}
-_func_exit_;
}
/*
@@ -553,7 +520,6 @@ static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16)
{
int i;
u16 PPK[6]; /* temporary key for mixing */
-_func_enter_;
/* Note: all adds in the PPK[] equations below are mod 2**16 */
for (i = 0; i < 5; i++)
PPK[i] = p1k[i]; /* first, copy P1K to PPK */
@@ -590,7 +556,6 @@ _func_enter_;
rc4key[4+2*i] = Lo8(PPK[i]);
rc4key[5+2*i] = Hi8(PPK[i]);
}
-_func_exit_;
}
/* The hlen isn't include the IV */
@@ -612,7 +577,6 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe)
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
u32 res = _SUCCESS;
-_func_enter_;
if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL)
return _FAIL;
@@ -672,7 +636,6 @@ _func_enter_;
res = _FAIL;
}
}
-_func_exit_;
return res;
}
@@ -690,13 +653,12 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe)
u8 *pframe, *payload, *iv, *prwskey;
union pn48 dot11txpn;
struct sta_info *stainfo;
- struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib;
+ struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib;
struct security_priv *psecuritypriv = &padapter->securitypriv;
u32 res = _SUCCESS;
-_func_enter_;
- pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
+ pframe = (unsigned char *)((struct recv_frame *)precvframe)->rx_data;
/* 4 start to decrypt recvframe */
if (prxattrib->encrypt == _TKIP_) {
@@ -716,7 +678,7 @@ _func_enter_;
iv = pframe+prxattrib->hdrlen;
payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
- length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len;
+ length = ((struct recv_frame *)precvframe)->len-prxattrib->hdrlen-prxattrib->iv_len;
GET_TKIP_PN(iv, dot11txpn);
@@ -747,7 +709,6 @@ _func_enter_;
res = _FAIL;
}
}
-_func_exit_;
exit:
return res;
}
@@ -821,19 +782,15 @@ static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext);
static void xor_128(u8 *a, u8 *b, u8 *out)
{
int i;
-_func_enter_;
for (i = 0; i < 16; i++)
out[i] = a[i] ^ b[i];
-_func_exit_;
}
static void xor_32(u8 *a, u8 *b, u8 *out)
{
int i;
-_func_enter_;
for (i = 0; i < 4; i++)
out[i] = a[i] ^ b[i];
-_func_exit_;
}
static u8 sbox(u8 a)
@@ -849,7 +806,6 @@ static void next_key(u8 *key, int round)
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0x1b, 0x36, 0x36, 0x36
};
-_func_enter_;
sbox_key[0] = sbox(key[13]);
sbox_key[1] = sbox(key[14]);
sbox_key[2] = sbox(key[15]);
@@ -863,21 +819,17 @@ _func_enter_;
xor_32(&key[4], &key[0], &key[4]);
xor_32(&key[8], &key[4], &key[8]);
xor_32(&key[12], &key[8], &key[12]);
-_func_exit_;
}
static void byte_sub(u8 *in, u8 *out)
{
int i;
-_func_enter_;
for (i = 0; i < 16; i++)
out[i] = sbox(in[i]);
-_func_exit_;
}
static void shift_row(u8 *in, u8 *out)
{
-_func_enter_;
out[0] = in[0];
out[1] = in[5];
out[2] = in[10];
@@ -894,7 +846,6 @@ _func_enter_;
out[13] = in[1];
out[14] = in[6];
out[15] = in[11];
-_func_exit_;
}
static void mix_column(u8 *in, u8 *out)
@@ -908,7 +859,6 @@ static void mix_column(u8 *in, u8 *out)
u8 rotr[4];
u8 temp[4];
u8 tempb[4];
-_func_enter_;
for (i = 0 ; i < 4; i++) {
if ((in[i] & 0x80) == 0x80)
add1b[i] = 0x1b;
@@ -952,7 +902,6 @@ _func_enter_;
xor_32(add1bf7, rotr, temp);
xor_32(swap_halfs, rotl, tempb);
xor_32(temp, tempb, out);
-_func_exit_;
}
static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext)
@@ -962,7 +911,6 @@ static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext)
u8 intermediatea[16];
u8 intermediateb[16];
u8 round_key[16];
-_func_enter_;
for (i = 0; i < 16; i++)
round_key[i] = key[i];
for (round = 0; round < 11; round++) {
@@ -984,7 +932,6 @@ _func_enter_;
next_key(round_key, round);
}
}
-_func_exit_;
}
/************************************************/
@@ -995,7 +942,6 @@ static void construct_mic_iv(u8 *mic_iv, int qc_exists, int a4_exists, u8 *mpdu,
uint payload_length, u8 *pn_vector)
{
int i;
-_func_enter_;
mic_iv[0] = 0x59;
if (qc_exists && a4_exists)
mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */
@@ -1009,7 +955,6 @@ _func_enter_;
mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */
mic_iv[14] = (unsigned char) (payload_length / 256);
mic_iv[15] = (unsigned char) (payload_length % 256);
-_func_exit_;
}
/************************************************/
@@ -1019,7 +964,6 @@ _func_exit_;
/************************************************/
static void construct_mic_header1(u8 *mic_header1, int header_length, u8 *mpdu)
{
-_func_enter_;
mic_header1[0] = (u8)((header_length - 2) / 256);
mic_header1[1] = (u8)((header_length - 2) % 256);
mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */
@@ -1036,7 +980,6 @@ _func_enter_;
mic_header1[13] = mpdu[13];
mic_header1[14] = mpdu[14];
mic_header1[15] = mpdu[15];
-_func_exit_;
}
/************************************************/
@@ -1047,7 +990,6 @@ _func_exit_;
static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, int a4_exists, int qc_exists)
{
int i;
-_func_enter_;
for (i = 0; i < 16; i++)
mic_header2[i] = 0x00;
@@ -1079,7 +1021,6 @@ _func_enter_;
mic_header2[15] = mpdu[31] & 0x00;
}
-_func_exit_;
}
/************************************************/
@@ -1090,7 +1031,6 @@ _func_exit_;
static void construct_ctr_preload(u8 *ctr_preload, int a4_exists, int qc_exists, u8 *mpdu, u8 *pn_vector, int c)
{
int i;
-_func_enter_;
for (i = 0; i < 16; i++)
ctr_preload[i] = 0x00;
i = 0;
@@ -1107,7 +1047,6 @@ _func_enter_;
ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */
ctr_preload[14] = (unsigned char) (c / 256); /* Ctr */
ctr_preload[15] = (unsigned char) (c % 256);
-_func_exit_;
}
/************************************/
@@ -1117,10 +1056,8 @@ _func_exit_;
static void bitwise_xor(u8 *ina, u8 *inb, u8 *out)
{
int i;
-_func_enter_;
for (i = 0; i < 16; i++)
out[i] = ina[i] ^ inb[i];
-_func_exit_;
}
static int aes_cipher(u8 *key, uint hdrlen, u8 *pframe, uint plen)
@@ -1142,7 +1079,6 @@ static int aes_cipher(u8 *key, uint hdrlen, u8 *pframe, uint plen)
uint frtype = GetFrameType(pframe);
uint frsubtype = GetFrameSubType(pframe);
-_func_enter_;
frsubtype = frsubtype>>4;
_rtw_memset((void *)mic_iv, 0, 16);
@@ -1253,7 +1189,6 @@ _func_enter_;
bitwise_xor(aes_out, padded_buffer, chain_buffer);
for (j = 0; j < 8; j++)
pframe[payload_index++] = chain_buffer[j];
-_func_exit_;
return _SUCCESS;
}
@@ -1274,7 +1209,6 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe)
/* uint offset = 0; */
u32 res = _SUCCESS;
-_func_enter_;
if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL)
return _FAIL;
@@ -1318,7 +1252,6 @@ _func_enter_;
}
-_func_exit_;
return res;
}
@@ -1344,7 +1277,6 @@ static int aes_decipher(u8 *key, uint hdrlen,
/* uint offset = 0; */
uint frtype = GetFrameType(pframe);
uint frsubtype = GetFrameSubType(pframe);
-_func_enter_;
frsubtype = frsubtype>>4;
_rtw_memset((void *)mic_iv, 0, 16);
@@ -1514,7 +1446,6 @@ _func_enter_;
res = _FAIL;
}
}
-_func_exit_;
return res;
}
@@ -1524,11 +1455,10 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe)
int length;
u8 *pframe, *prwskey; /* *payload,*iv */
struct sta_info *stainfo;
- struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib;
+ struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib;
struct security_priv *psecuritypriv = &padapter->securitypriv;
u32 res = _SUCCESS;
-_func_enter_;
- pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
+ pframe = (unsigned char *)((struct recv_frame *)precvframe)->rx_data;
/* 4 start to encrypt each fragment */
if ((prxattrib->encrypt == _AES_)) {
stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]);
@@ -1552,14 +1482,13 @@ _func_enter_;
} else {
prwskey = &stainfo->dot118021x_UncstKey.skey[0];
}
- length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len;
+ length = ((struct recv_frame *)precvframe)->len-prxattrib->hdrlen-prxattrib->iv_len;
res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length);
} else {
RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n"));
res = _FAIL;
}
}
-_func_exit_;
exit:
return res;
}
@@ -1767,7 +1696,6 @@ void rtw_use_tkipkey_handler(void *FunctionContext)
{
struct adapter *padapter = (struct adapter *)FunctionContext;
-_func_enter_;
RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("^^^rtw_use_tkipkey_handler ^^^\n"));
@@ -1775,5 +1703,4 @@ _func_enter_;
RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("^^^rtw_use_tkipkey_handler padapter->securitypriv.busetkipkey=%d^^^\n", padapter->securitypriv.busetkipkey));
-_func_exit_;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c
index 02e1e1f8b3ea..2d0b60686a01 100644
--- a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c
+++ b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c
@@ -25,10 +25,10 @@
#include <xmit_osdep.h>
#include <mlme_osdep.h>
#include <sta_info.h>
+#include <linux/vmalloc.h>
static void _rtw_init_stainfo(struct sta_info *psta)
{
-_func_enter_;
_rtw_memset((u8 *)psta, 0, sizeof (struct sta_info));
spin_lock_init(&psta->lock);
@@ -69,7 +69,6 @@ _func_enter_;
#endif /* CONFIG_88EU_AP_MODE */
-_func_exit_;
}
u32 _rtw_init_sta_priv(struct sta_priv *pstapriv)
@@ -77,9 +76,8 @@ u32 _rtw_init_sta_priv(struct sta_priv *pstapriv)
struct sta_info *psta;
s32 i;
-_func_enter_;
- pstapriv->pallocated_stainfo_buf = rtw_zvmalloc(sizeof(struct sta_info) * NUM_STA + 4);
+ pstapriv->pallocated_stainfo_buf = vzalloc(sizeof(struct sta_info) * NUM_STA + 4);
if (!pstapriv->pallocated_stainfo_buf)
return _FAIL;
@@ -125,7 +123,6 @@ _func_enter_;
pstapriv->max_num_sta = NUM_STA;
#endif
-_func_exit_;
return _SUCCESS;
}
@@ -154,21 +151,19 @@ static void rtw_mfree_all_stainfo(struct sta_priv *pstapriv)
struct list_head *plist, *phead;
struct sta_info *psta = NULL;
-_func_enter_;
spin_lock_bh(&pstapriv->sta_hash_lock);
phead = get_list_head(&pstapriv->free_sta_queue);
- plist = get_next(phead);
+ plist = phead->next;
while ((rtw_end_of_queue_search(phead, plist)) == false) {
- psta = LIST_CONTAINOR(plist, struct sta_info , list);
- plist = get_next(plist);
+ psta = container_of(plist, struct sta_info , list);
+ plist = plist->next;
}
spin_unlock_bh(&pstapriv->sta_hash_lock);
-_func_exit_;
}
static void rtw_mfree_sta_priv_lock(struct sta_priv *pstapriv)
@@ -183,22 +178,21 @@ u32 _rtw_free_sta_priv(struct sta_priv *pstapriv)
struct recv_reorder_ctrl *preorder_ctrl;
int index;
-_func_enter_;
if (pstapriv) {
/* delete all reordering_ctrl_timer */
spin_lock_bh(&pstapriv->sta_hash_lock);
for (index = 0; index < NUM_STA; index++) {
phead = &(pstapriv->sta_hash[index]);
- plist = get_next(phead);
+ plist = phead->next;
while ((rtw_end_of_queue_search(phead, plist)) == false) {
int i;
- psta = LIST_CONTAINOR(plist, struct sta_info , hash_list);
- plist = get_next(plist);
+ psta = container_of(plist, struct sta_info , hash_list);
+ plist = plist->next;
for (i = 0; i < 16; i++) {
preorder_ctrl = &psta->recvreorder_ctrl[i];
- _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);
+ del_timer_sync(&preorder_ctrl->reordering_ctrl_timer);
}
}
}
@@ -208,10 +202,9 @@ _func_enter_;
rtw_mfree_sta_priv_lock(pstapriv);
if (pstapriv->pallocated_stainfo_buf)
- rtw_vmfree(pstapriv->pallocated_stainfo_buf, sizeof(struct sta_info)*NUM_STA+4);
+ vfree(pstapriv->pallocated_stainfo_buf);
}
-_func_exit_;
return _SUCCESS;
}
@@ -225,7 +218,6 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
int i = 0;
u16 wRxSeqInitialValue = 0xffff;
-_func_enter_;
pfree_sta_queue = &pstapriv->free_sta_queue;
@@ -235,7 +227,7 @@ _func_enter_;
spin_unlock_bh(&pfree_sta_queue->lock);
psta = NULL;
} else {
- psta = LIST_CONTAINOR(get_next(&pfree_sta_queue->queue), struct sta_info, list);
+ psta = container_of((&pfree_sta_queue->queue)->next, struct sta_info, list);
rtw_list_delete(&(psta->list));
spin_unlock_bh(&pfree_sta_queue->lock);
_rtw_init_stainfo(psta);
@@ -297,9 +289,6 @@ _func_enter_;
}
exit:
-
-_func_exit_;
-
return psta;
}
@@ -313,7 +302,6 @@ u32 rtw_free_stainfo(struct adapter *padapter , struct sta_info *psta)
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct sta_priv *pstapriv = &padapter->stapriv;
-_func_enter_;
if (psta == NULL)
goto exit;
@@ -353,32 +341,34 @@ _func_enter_;
_rtw_init_sta_xmit_priv(&psta->sta_xmitpriv);
_rtw_init_sta_recv_priv(&psta->sta_recvpriv);
- _cancel_timer_ex(&psta->addba_retry_timer);
+ del_timer_sync(&psta->addba_retry_timer);
/* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */
for (i = 0; i < 16; i++) {
struct list_head *phead, *plist;
- union recv_frame *prframe;
+ struct recv_frame *prhdr;
+ struct recv_frame *prframe;
struct __queue *ppending_recvframe_queue;
struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
preorder_ctrl = &psta->recvreorder_ctrl[i];
- _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);
+ del_timer_sync(&preorder_ctrl->reordering_ctrl_timer);
ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
spin_lock_bh(&ppending_recvframe_queue->lock);
phead = get_list_head(ppending_recvframe_queue);
- plist = get_next(phead);
+ plist = phead->next;
while (!rtw_is_list_empty(phead)) {
- prframe = LIST_CONTAINOR(plist, union recv_frame, u);
+ prhdr = container_of(plist, struct recv_frame, list);
+ prframe = (struct recv_frame *)prhdr;
- plist = get_next(plist);
+ plist = plist->next;
- rtw_list_delete(&(prframe->u.hdr.list));
+ rtw_list_delete(&(prframe->list));
rtw_free_recvframe(prframe, pfree_recv_queue);
}
@@ -428,7 +418,6 @@ _func_enter_;
exit:
-_func_exit_;
return _SUCCESS;
}
@@ -442,32 +431,26 @@ void rtw_free_all_stainfo(struct adapter *padapter)
struct sta_priv *pstapriv = &padapter->stapriv;
struct sta_info *pbcmc_stainfo = rtw_get_bcmc_stainfo(padapter);
-_func_enter_;
if (pstapriv->asoc_sta_count == 1)
- goto exit;
+ return;
spin_lock_bh(&pstapriv->sta_hash_lock);
for (index = 0; index < NUM_STA; index++) {
phead = &(pstapriv->sta_hash[index]);
- plist = get_next(phead);
+ plist = phead->next;
while ((!rtw_end_of_queue_search(phead, plist))) {
- psta = LIST_CONTAINOR(plist, struct sta_info , hash_list);
+ psta = container_of(plist, struct sta_info , hash_list);
- plist = get_next(plist);
+ plist = plist->next;
if (pbcmc_stainfo != psta)
rtw_free_stainfo(padapter , psta);
}
}
-
spin_unlock_bh(&pstapriv->sta_hash_lock);
-
-exit:
-
-_func_exit_;
}
/* any station allocated can be searched by hash list */
@@ -479,7 +462,6 @@ struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
u8 *addr;
u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-_func_enter_;
if (hwaddr == NULL)
return NULL;
@@ -494,21 +476,20 @@ _func_enter_;
spin_lock_bh(&pstapriv->sta_hash_lock);
phead = &(pstapriv->sta_hash[index]);
- plist = get_next(phead);
+ plist = phead->next;
while ((!rtw_end_of_queue_search(phead, plist))) {
- psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+ psta = container_of(plist, struct sta_info, hash_list);
- if ((_rtw_memcmp(psta->hwaddr, addr, ETH_ALEN)) == true) {
+ if ((!memcmp(psta->hwaddr, addr, ETH_ALEN)) == true) {
/* if found the matched address */
break;
}
psta = NULL;
- plist = get_next(plist);
+ plist = plist->next;
}
spin_unlock_bh(&pstapriv->sta_hash_lock);
-_func_exit_;
return psta;
}
@@ -519,7 +500,6 @@ u32 rtw_init_bcmc_stainfo(struct adapter *padapter)
unsigned char bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
struct sta_priv *pstapriv = &padapter->stapriv;
-_func_enter_;
psta = rtw_alloc_stainfo(pstapriv, bcast_addr);
@@ -533,7 +513,6 @@ _func_enter_;
psta->mac_id = 1;
exit:
-_func_exit_;
return res;
}
@@ -542,9 +521,7 @@ struct sta_info *rtw_get_bcmc_stainfo(struct adapter *padapter)
struct sta_info *psta;
struct sta_priv *pstapriv = &padapter->stapriv;
u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-_func_enter_;
psta = rtw_get_stainfo(pstapriv, bc_addr);
-_func_exit_;
return psta;
}
@@ -561,12 +538,12 @@ u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr)
spin_lock_bh(&(pacl_node_q->lock));
phead = get_list_head(pacl_node_q);
- plist = get_next(phead);
+ plist = phead->next;
while ((!rtw_end_of_queue_search(phead, plist))) {
- paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
- plist = get_next(plist);
+ paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
+ plist = plist->next;
- if (_rtw_memcmp(paclnode->addr, mac_addr, ETH_ALEN)) {
+ if (!memcmp(paclnode->addr, mac_addr, ETH_ALEN)) {
if (paclnode->valid) {
match = true;
break;
diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
index 96df62f95b6b..3dd90599fd4b 100644
--- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
+++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
@@ -929,7 +929,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
return _FAIL;
}
- if (_rtw_memcmp(cur_network->network.MacAddress, pbssid, 6) == false) {
+ if (!memcmp(cur_network->network.MacAddress, pbssid, 6) == false) {
DBG_88E("Oops: rtw_check_network_encrypt linked but recv other bssid bcn\n%pM %pM\n",
(pbssid), (cur_network->network.MacAddress));
return true;
@@ -1014,7 +1014,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
bssid->Ssid.SsidLength, cur_network->network.Ssid.Ssid,
cur_network->network.Ssid.SsidLength));
- if (!_rtw_memcmp(bssid->Ssid.Ssid, cur_network->network.Ssid.Ssid, 32) ||
+ if (memcmp(bssid->Ssid.Ssid, cur_network->network.Ssid.Ssid, 32) ||
bssid->Ssid.SsidLength != cur_network->network.Ssid.SsidLength) {
if (bssid->Ssid.Ssid[0] != '\0' && bssid->Ssid.SsidLength != 0) { /* not hidden ssid */
DBG_88E("%s(), SSID is not match return FAIL\n", __func__);
@@ -1050,7 +1050,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
}
if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) {
- DBG_88E("%s(): enctyp is not match , return FAIL\n", __func__);
+ DBG_88E("%s(): encryption protocol is not match , return FAIL\n", __func__);
goto _mismatch;
}
@@ -1090,12 +1090,10 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
}
kfree(bssid);
- _func_exit_;
return _SUCCESS;
_mismatch:
kfree(bssid);
- _func_exit_;
return _FAIL;
}
@@ -1141,11 +1139,11 @@ unsigned int is_ap_in_tkip(struct adapter *padapter)
switch (pIE->ElementID) {
case _VENDOR_SPECIFIC_IE_:
- if ((_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) && (_rtw_memcmp((pIE->data + 12), WPA_TKIP_CIPHER, 4)))
+ if ((!memcmp(pIE->data, RTW_WPA_OUI, 4)) && (!memcmp((pIE->data + 12), WPA_TKIP_CIPHER, 4)))
return true;
break;
case _RSN_IE_2_:
- if (_rtw_memcmp((pIE->data + 8), RSN_TKIP_CIPHER, 4))
+ if (!memcmp((pIE->data + 8), RSN_TKIP_CIPHER, 4))
return true;
default:
break;
@@ -1172,14 +1170,14 @@ unsigned int should_forbid_n_rate(struct adapter *padapter)
switch (pIE->ElementID) {
case _VENDOR_SPECIFIC_IE_:
- if (_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4) &&
- ((_rtw_memcmp((pIE->data + 12), WPA_CIPHER_SUITE_CCMP, 4)) ||
- (_rtw_memcmp((pIE->data + 16), WPA_CIPHER_SUITE_CCMP, 4))))
+ if (!memcmp(pIE->data, RTW_WPA_OUI, 4) &&
+ ((!memcmp((pIE->data + 12), WPA_CIPHER_SUITE_CCMP, 4)) ||
+ (!memcmp((pIE->data + 16), WPA_CIPHER_SUITE_CCMP, 4))))
return false;
break;
case _RSN_IE_2_:
- if ((_rtw_memcmp((pIE->data + 8), RSN_CIPHER_SUITE_CCMP, 4)) ||
- (_rtw_memcmp((pIE->data + 12), RSN_CIPHER_SUITE_CCMP, 4)))
+ if ((!memcmp((pIE->data + 8), RSN_CIPHER_SUITE_CCMP, 4)) ||
+ (!memcmp((pIE->data + 12), RSN_CIPHER_SUITE_CCMP, 4)))
return false;
default:
break;
@@ -1208,7 +1206,7 @@ unsigned int is_ap_in_wep(struct adapter *padapter)
switch (pIE->ElementID) {
case _VENDOR_SPECIFIC_IE_:
- if (_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4))
+ if (!memcmp(pIE->data, RTW_WPA_OUI, 4))
return false;
break;
case _RSN_IE_2_:
@@ -1400,35 +1398,35 @@ unsigned char check_assoc_AP(u8 *pframe, uint len)
switch (pIE->ElementID) {
case _VENDOR_SPECIFIC_IE_:
- if ((_rtw_memcmp(pIE->data, ARTHEROS_OUI1, 3)) ||
- (_rtw_memcmp(pIE->data, ARTHEROS_OUI2, 3))) {
+ if ((!memcmp(pIE->data, ARTHEROS_OUI1, 3)) ||
+ (!memcmp(pIE->data, ARTHEROS_OUI2, 3))) {
DBG_88E("link to Artheros AP\n");
return HT_IOT_PEER_ATHEROS;
- } else if ((_rtw_memcmp(pIE->data, BROADCOM_OUI1, 3)) ||
- (_rtw_memcmp(pIE->data, BROADCOM_OUI2, 3)) ||
- (_rtw_memcmp(pIE->data, BROADCOM_OUI2, 3))) {
+ } else if ((!memcmp(pIE->data, BROADCOM_OUI1, 3)) ||
+ (!memcmp(pIE->data, BROADCOM_OUI2, 3)) ||
+ (!memcmp(pIE->data, BROADCOM_OUI2, 3))) {
DBG_88E("link to Broadcom AP\n");
return HT_IOT_PEER_BROADCOM;
- } else if (_rtw_memcmp(pIE->data, MARVELL_OUI, 3)) {
+ } else if (!memcmp(pIE->data, MARVELL_OUI, 3)) {
DBG_88E("link to Marvell AP\n");
return HT_IOT_PEER_MARVELL;
- } else if (_rtw_memcmp(pIE->data, RALINK_OUI, 3)) {
+ } else if (!memcmp(pIE->data, RALINK_OUI, 3)) {
if (!ralink_vendor_flag) {
ralink_vendor_flag = 1;
} else {
DBG_88E("link to Ralink AP\n");
return HT_IOT_PEER_RALINK;
}
- } else if (_rtw_memcmp(pIE->data, CISCO_OUI, 3)) {
+ } else if (!memcmp(pIE->data, CISCO_OUI, 3)) {
DBG_88E("link to Cisco AP\n");
return HT_IOT_PEER_CISCO;
- } else if (_rtw_memcmp(pIE->data, REALTEK_OUI, 3)) {
+ } else if (!memcmp(pIE->data, REALTEK_OUI, 3)) {
DBG_88E("link to Realtek 96B\n");
return HT_IOT_PEER_REALTEK;
- } else if (_rtw_memcmp(pIE->data, AIRGOCAP_OUI, 3)) {
+ } else if (!memcmp(pIE->data, AIRGOCAP_OUI, 3)) {
DBG_88E("link to Airgo Cap\n");
return HT_IOT_PEER_AIRGO;
- } else if (_rtw_memcmp(pIE->data, EPIGRAM_OUI, 3)) {
+ } else if (!memcmp(pIE->data, EPIGRAM_OUI, 3)) {
epigram_vendor_flag = 1;
if (ralink_vendor_flag) {
DBG_88E("link to Tenda W311R AP\n");
diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c
index 24182fbc6a71..8d4265fb486d 100644
--- a/drivers/staging/rtl8188eu/core/rtw_xmit.c
+++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c
@@ -23,25 +23,22 @@
#include <drv_types.h>
#include <wifi.h>
#include <osdep_intf.h>
-#include <ip.h>
#include <usb_ops.h>
#include <usb_osintf.h>
+#include <linux/vmalloc.h>
static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
static void _init_txservq(struct tx_servq *ptxservq)
{
-_func_enter_;
_rtw_init_listhead(&ptxservq->tx_pending);
_rtw_init_queue(&ptxservq->sta_pending);
ptxservq->qcnt = 0;
-_func_exit_;
}
void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv)
{
-_func_enter_;
_rtw_memset((unsigned char *)psta_xmitpriv, 0, sizeof (struct sta_xmit_priv));
spin_lock_init(&psta_xmitpriv->lock);
_init_txservq(&psta_xmitpriv->be_q);
@@ -51,7 +48,6 @@ _func_enter_;
_rtw_init_listhead(&psta_xmitpriv->legacy_dz);
_rtw_init_listhead(&psta_xmitpriv->apsd);
-_func_exit_;
}
s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
@@ -63,9 +59,8 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
u32 num_xmit_extbuf = NR_XMIT_EXTBUFF;
-_func_enter_;
- /* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */
+ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */
spin_lock_init(&pxmitpriv->lock);
sema_init(&pxmitpriv->xmit_sema, 0);
@@ -91,7 +86,7 @@ _func_enter_;
Please also apply free_txobj to link_up all the xmit_frames...
*/
- pxmitpriv->pallocated_frame_buf = rtw_zvmalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4);
+ pxmitpriv->pallocated_frame_buf = vzalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4);
if (pxmitpriv->pallocated_frame_buf == NULL) {
pxmitpriv->pxmit_frame_buf = NULL;
@@ -129,7 +124,7 @@ _func_enter_;
_rtw_init_queue(&pxmitpriv->free_xmitbuf_queue);
_rtw_init_queue(&pxmitpriv->pending_xmitbuf_queue);
- pxmitpriv->pallocated_xmitbuf = rtw_zvmalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4);
+ pxmitpriv->pallocated_xmitbuf = vzalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4);
if (pxmitpriv->pallocated_xmitbuf == NULL) {
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_buf fail!\n"));
@@ -171,7 +166,7 @@ _func_enter_;
/* Init xmit extension buff */
_rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue);
- pxmitpriv->pallocated_xmit_extbuf = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
+ pxmitpriv->pallocated_xmit_extbuf = vzalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
if (pxmitpriv->pallocated_xmit_extbuf == NULL) {
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n"));
@@ -226,7 +221,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -240,12 +234,11 @@ void _rtw_free_xmit_priv (struct xmit_priv *pxmitpriv)
u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
u32 num_xmit_extbuf = NR_XMIT_EXTBUFF;
- _func_enter_;
rtw_hal_free_xmit_priv(padapter);
if (pxmitpriv->pxmit_frame_buf == NULL)
- goto out;
+ return;
for (i = 0; i < NR_XMITFRAME; i++) {
rtw_os_xmit_complete(padapter, pxmitframe);
@@ -259,10 +252,10 @@ void _rtw_free_xmit_priv (struct xmit_priv *pxmitpriv)
}
if (pxmitpriv->pallocated_frame_buf)
- rtw_vmfree(pxmitpriv->pallocated_frame_buf, NR_XMITFRAME * sizeof(struct xmit_frame) + 4);
+ vfree(pxmitpriv->pallocated_frame_buf);
if (pxmitpriv->pallocated_xmitbuf)
- rtw_vmfree(pxmitpriv->pallocated_xmitbuf, NR_XMITBUFF * sizeof(struct xmit_buf) + 4);
+ vfree(pxmitpriv->pallocated_xmitbuf);
/* free xmit extension buff */
pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf;
@@ -272,16 +265,12 @@ void _rtw_free_xmit_priv (struct xmit_priv *pxmitpriv)
}
if (pxmitpriv->pallocated_xmit_extbuf) {
- rtw_vmfree(pxmitpriv->pallocated_xmit_extbuf, num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
+ vfree(pxmitpriv->pallocated_xmit_extbuf);
}
rtw_free_hwxmits(padapter);
mutex_destroy(&pxmitpriv->ack_tx_mutex);
-
-out:
-
-_func_exit_;
}
static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame *pxmitframe)
@@ -455,7 +444,6 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
struct qos_priv *pqospriv = &pmlmepriv->qospriv;
int res = _SUCCESS;
- _func_enter_;
_rtw_open_pktfile(pkt, &pktfile);
_rtw_pktfile_read(&pktfile, (u8 *)&etherhdr, ETH_HLEN);
@@ -639,7 +627,6 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
exit:
-_func_exit_;
return res;
}
@@ -662,7 +649,6 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr
else
stainfo = rtw_get_stainfo(&padapter->stapriv , &pattrib->ra[0]);
-_func_enter_;
hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ);
@@ -676,12 +662,12 @@ _func_enter_;
pframe = pxmitframe->buf_addr + hw_hdr_offset;
if (bmcst) {
- if (_rtw_memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16))
+ if (!memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16))
return _FAIL;
/* start to calculate the mic code */
rtw_secmicsetkey(&micdata, psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey);
} else {
- if (_rtw_memcmp(&stainfo->dot11tkiptxmickey.skey[0], null_key, 16) == true) {
+ if (!memcmp(&stainfo->dot11tkiptxmickey.skey[0], null_key, 16)) {
/* DbgPrint("\nxmitframe_addmic:stainfo->dot11tkiptxmickey == 0\n"); */
/* msleep(10); */
return _FAIL;
@@ -760,7 +746,6 @@ _func_enter_;
}
}
-_func_exit_;
return _SUCCESS;
}
@@ -769,7 +754,6 @@ static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmi
{
struct pkt_attrib *pattrib = &pxmitframe->attrib;
-_func_enter_;
if (pattrib->bswenc) {
RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("### xmitframe_swencrypt\n"));
@@ -791,7 +775,6 @@ _func_enter_;
RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, ("### xmitframe_hwencrypt\n"));
}
-_func_exit_;
return _SUCCESS;
}
@@ -812,7 +795,6 @@ s32 rtw_make_wlanhdr (struct adapter *padapter , u8 *hdr, struct pkt_attrib *pat
int bmcst = IS_MCAST(pattrib->ra);
-_func_enter_;
if (pattrib->psta) {
psta = pattrib->psta;
@@ -918,7 +900,6 @@ _func_enter_;
}
exit:
-_func_exit_;
return res;
}
@@ -1007,7 +988,6 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
s32 bmcst = IS_MCAST(pattrib->ra);
s32 res = _SUCCESS;
-_func_enter_;
psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
@@ -1145,7 +1125,6 @@ _func_enter_;
exit:
-_func_exit_;
return res;
}
@@ -1162,7 +1141,6 @@ s32 rtw_put_snap(u8 *data, u16 h_proto)
struct ieee80211_snap_hdr *snap;
u8 *oui;
-_func_enter_;
snap = (struct ieee80211_snap_hdr *)data;
snap->dsap = 0xaa;
@@ -1180,7 +1158,6 @@ _func_enter_;
*(__be16 *)(data + SNAP_SIZE) = htons(h_proto);
-_func_exit_;
return SNAP_SIZE + sizeof(u16);
}
@@ -1193,7 +1170,6 @@ void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len)
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
-_func_enter_;
switch (pxmitpriv->vcs_setting) {
case DISABLE_VCS:
@@ -1220,7 +1196,6 @@ _func_enter_;
break;
}
-_func_exit_;
}
void rtw_count_tx_stats(struct adapter *padapter, struct xmit_frame *pxmitframe, int sz)
@@ -1250,7 +1225,6 @@ struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv)
struct list_head *plist, *phead;
struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue;
-_func_enter_;
spin_lock_irqsave(&pfree_queue->lock, irql);
@@ -1259,9 +1233,9 @@ _func_enter_;
} else {
phead = get_list_head(pfree_queue);
- plist = get_next(phead);
+ plist = phead->next;
- pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
+ pxmitbuf = container_of(plist, struct xmit_buf, list);
rtw_list_delete(&(pxmitbuf->list));
}
@@ -1280,7 +1254,6 @@ _func_enter_;
spin_unlock_irqrestore(&pfree_queue->lock, irql);
-_func_exit_;
return pxmitbuf;
}
@@ -1290,7 +1263,6 @@ s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
unsigned long irql;
struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue;
-_func_enter_;
if (pxmitbuf == NULL)
return _FAIL;
@@ -1304,7 +1276,6 @@ _func_enter_;
spin_unlock_irqrestore(&pfree_queue->lock, irql);
-_func_exit_;
return _SUCCESS;
}
@@ -1316,7 +1287,6 @@ struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv)
struct list_head *plist, *phead;
struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
-_func_enter_;
/* DBG_88E("+rtw_alloc_xmitbuf\n"); */
@@ -1327,9 +1297,9 @@ _func_enter_;
} else {
phead = get_list_head(pfree_xmitbuf_queue);
- plist = get_next(phead);
+ plist = phead->next;
- pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
+ pxmitbuf = container_of(plist, struct xmit_buf, list);
rtw_list_delete(&(pxmitbuf->list));
}
@@ -1344,7 +1314,6 @@ _func_enter_;
}
spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irql);
-_func_exit_;
return pxmitbuf;
}
@@ -1354,7 +1323,6 @@ s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
unsigned long irql;
struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
-_func_enter_;
if (pxmitbuf == NULL)
return _FAIL;
@@ -1376,7 +1344,6 @@ _func_enter_;
spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irql);
}
-_func_exit_;
return _SUCCESS;
}
@@ -1405,7 +1372,6 @@ struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)/* _queue *pf
struct list_head *plist, *phead;
struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue;
-_func_enter_;
spin_lock_bh(&pfree_xmit_queue->lock);
@@ -1415,9 +1381,9 @@ _func_enter_;
} else {
phead = get_list_head(pfree_xmit_queue);
- plist = get_next(phead);
+ plist = phead->next;
- pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list);
+ pxframe = container_of(plist, struct xmit_frame, list);
rtw_list_delete(&(pxframe->list));
}
@@ -1444,7 +1410,6 @@ _func_enter_;
spin_unlock_bh(&pfree_xmit_queue->lock);
-_func_exit_;
return pxframe;
}
@@ -1455,7 +1420,6 @@ s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitfram
struct adapter *padapter = pxmitpriv->adapter;
struct sk_buff *pndis_pkt = NULL;
-_func_enter_;
if (pxmitframe == NULL) {
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====== rtw_free_xmitframe():pxmitframe == NULL!!!!!!!!!!\n"));
@@ -1483,7 +1447,6 @@ _func_enter_;
exit:
-_func_exit_;
return _SUCCESS;
}
@@ -1493,23 +1456,21 @@ void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pfram
struct list_head *plist, *phead;
struct xmit_frame *pxmitframe;
-_func_enter_;
spin_lock_bh(&(pframequeue->lock));
phead = get_list_head(pframequeue);
- plist = get_next(phead);
+ plist = phead->next;
while (!rtw_end_of_queue_search(phead, plist)) {
- pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list);
+ pxmitframe = container_of(plist, struct xmit_frame, list);
- plist = get_next(plist);
+ plist = plist->next;
rtw_free_xmitframe(pxmitpriv, pxmitframe);
}
spin_unlock_bh(&(pframequeue->lock));
-_func_exit_;
}
s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe)
@@ -1530,12 +1491,12 @@ static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, str
struct xmit_frame *pxmitframe = NULL;
xmitframe_phead = get_list_head(pframe_queue);
- xmitframe_plist = get_next(xmitframe_phead);
+ xmitframe_plist = xmitframe_phead->next;
if (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
- pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
- xmitframe_plist = get_next(xmitframe_plist);
+ xmitframe_plist = xmitframe_plist->next;
rtw_list_delete(&pxmitframe->list);
@@ -1555,7 +1516,6 @@ struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, struct hw_xmi
struct registry_priv *pregpriv = &padapter->registrypriv;
int i, inx[4];
-_func_enter_;
inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3;
@@ -1572,10 +1532,10 @@ _func_enter_;
phwxmit = phwxmit_i + inx[i];
sta_phead = get_list_head(phwxmit->sta_queue);
- sta_plist = get_next(sta_phead);
+ sta_plist = sta_phead->next;
while (!rtw_end_of_queue_search(sta_phead, sta_plist)) {
- ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending);
+ ptxservq = container_of(sta_plist, struct tx_servq, tx_pending);
pframe_queue = &ptxservq->sta_pending;
@@ -1590,12 +1550,11 @@ _func_enter_;
goto exit;
}
- sta_plist = get_next(sta_plist);
+ sta_plist = sta_plist->next;
}
}
exit:
spin_unlock_bh(&pxmitpriv->lock);
-_func_exit_;
return pxmitframe;
}
@@ -1603,7 +1562,6 @@ struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *
{
struct tx_servq *ptxservq;
-_func_enter_;
switch (up) {
case 1:
case 2:
@@ -1632,7 +1590,6 @@ _func_enter_;
break;
}
-_func_exit_;
return ptxservq;
}
@@ -1651,7 +1608,6 @@ s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe)
struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits;
int res = _SUCCESS;
-_func_enter_;
if (pattrib->psta) {
psta = pattrib->psta;
@@ -1676,7 +1632,6 @@ _func_enter_;
phwxmits[ac_index].accnt++;
exit:
-_func_exit_;
return res;
}
@@ -1719,10 +1674,8 @@ void rtw_free_hwxmits(struct adapter *padapter)
void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry)
{
int i;
-_func_enter_;
for (i = 0; i < entry; i++, phwxmit++)
phwxmit->accnt = 0;
-_func_exit_;
}
static int rtw_br_client_tx(struct adapter *padapter, struct sk_buff **pskb)
@@ -1997,7 +1950,7 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra
pstapriv->tim_bitmap |= BIT(0);/* */
pstapriv->sta_dz_bitmap |= BIT(0);
- update_beacon(padapter, _TIM_IE_, NULL, false);/* tx bc/mc packets after upate bcn */
+ update_beacon(padapter, _TIM_IE_, NULL, false);/* tx bc/mc packets after update bcn */
ret = true;
}
@@ -2047,7 +2000,7 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra
pstapriv->tim_bitmap |= BIT(psta->aid);
if (psta->sleepq_len == 1) {
- /* upate BCN for TIM IE */
+ /* update BCN for TIM IE */
update_beacon(padapter, _TIM_IE_, NULL, false);
}
}
@@ -2070,12 +2023,12 @@ static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struc
struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits;
phead = get_list_head(pframequeue);
- plist = get_next(phead);
+ plist = phead->next;
while (!rtw_end_of_queue_search(phead, plist)) {
- pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list);
+ pxmitframe = container_of(plist, struct xmit_frame, list);
- plist = get_next(plist);
+ plist = plist->next;
xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe);
@@ -2137,12 +2090,12 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
spin_lock_bh(&psta->sleep_q.lock);
xmitframe_phead = get_list_head(&psta->sleep_q);
- xmitframe_plist = get_next(xmitframe_phead);
+ xmitframe_plist = xmitframe_phead->next;
while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
- pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
- xmitframe_plist = get_next(xmitframe_plist);
+ xmitframe_plist = xmitframe_plist->next;
rtw_list_delete(&pxmitframe->list);
@@ -2218,12 +2171,12 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
spin_lock_bh(&psta_bmc->sleep_q.lock);
xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
- xmitframe_plist = get_next(xmitframe_phead);
+ xmitframe_plist = xmitframe_phead->next;
while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
- pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
- xmitframe_plist = get_next(xmitframe_plist);
+ xmitframe_plist = xmitframe_plist->next;
rtw_list_delete(&pxmitframe->list);
@@ -2265,12 +2218,12 @@ void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *pst
spin_lock_bh(&psta->sleep_q.lock);
xmitframe_phead = get_list_head(&psta->sleep_q);
- xmitframe_plist = get_next(xmitframe_phead);
+ xmitframe_plist = xmitframe_phead->next;
while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
- pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
- xmitframe_plist = get_next(xmitframe_plist);
+ xmitframe_plist = xmitframe_plist->next;
switch (pxmitframe->attrib.priority) {
case 1:
@@ -2316,7 +2269,7 @@ void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *pst
if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) && (wmmps_ac)) {
pstapriv->tim_bitmap &= ~BIT(psta->aid);
- /* upate BCN for TIM IE */
+ /* update BCN for TIM IE */
update_beacon(padapter, _TIM_IE_, NULL, false);
}
}
diff --git a/drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c b/drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c
index 3df33bc7197a..dea220b507ad 100644
--- a/drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c
+++ b/drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c
@@ -331,6 +331,7 @@ static void odm_RateDecision_8188E(struct odm_dm_struct *dm_odm,
static int odm_ARFBRefresh_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_info *pRaInfo)
{ /* Wilson 2011/10/26 */
+ struct adapter *adapt = dm_odm->Adapter;
u32 MaskFromReg;
s8 i;
@@ -357,19 +358,19 @@ static int odm_ARFBRefresh_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_inf
pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0000000d;
break;
case 12:
- MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR0);
+ MaskFromReg = rtw_read32(adapt, REG_ARFR0);
pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg;
break;
case 13:
- MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR1);
+ MaskFromReg = rtw_read32(adapt, REG_ARFR1);
pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg;
break;
case 14:
- MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR2);
+ MaskFromReg = rtw_read32(adapt, REG_ARFR2);
pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg;
break;
case 15:
- MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR3);
+ MaskFromReg = rtw_read32(adapt, REG_ARFR3);
pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg;
break;
default:
@@ -667,7 +668,9 @@ void ODM_RA_SetRSSI_8188E(struct odm_dm_struct *dm_odm, u8 macid, u8 Rssi)
void ODM_RA_Set_TxRPT_Time(struct odm_dm_struct *dm_odm, u16 minRptTime)
{
- ODM_Write2Byte(dm_odm, REG_TX_RPT_TIME, minRptTime);
+ struct adapter *adapt = dm_odm->Adapter;
+
+ rtw_write16(adapt, REG_TX_RPT_TIME, minRptTime);
}
void ODM_RA_TxRPT2Handle_8188E(struct odm_dm_struct *dm_odm, u8 *TxRPT_Buf, u16 TxRPT_Len, u32 macid_entry0, u32 macid_entry1)
diff --git a/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c b/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c
index 15e8e3f62198..056052ddd82e 100644
--- a/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c
+++ b/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c
@@ -217,7 +217,7 @@ odm_TXPowerTrackingCallback_ThermalMeter_8188E(
for (i = 0; i < CCK_TABLE_SIZE; i++) {
if (dm_odm->RFCalibrateInfo.bCCKinCH14) {
- if (ODM_CompareMemory(dm_odm, (void *)&TempCCk, (void *)&CCKSwingTable_Ch14[i][2], 4) == 0) {
+ if (memcmp(&TempCCk, &CCKSwingTable_Ch14[i][2], 4)) {
CCK_index_old = (u8)i;
dm_odm->BbSwingIdxCckBase = (u8)i;
ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
@@ -229,7 +229,7 @@ odm_TXPowerTrackingCallback_ThermalMeter_8188E(
ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
("RegA24: 0x%X, CCKSwingTable_Ch1_Ch13[%d][2]: CCKSwingTable_Ch1_Ch13[i][2]: 0x%X\n",
TempCCk, i, CCKSwingTable_Ch1_Ch13[i][2]));
- if (ODM_CompareMemory(dm_odm, (void *)&TempCCk, (void *)&CCKSwingTable_Ch1_Ch13[i][2], 4) == 0) {
+ if (memcmp(&TempCCk, &CCKSwingTable_Ch1_Ch13[i][2], 4)) {
CCK_index_old = (u8)i;
dm_odm->BbSwingIdxCckBase = (u8)i;
ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
@@ -839,9 +839,9 @@ static void _PHY_SaveMACRegisters(
struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save MAC parameters.\n"));
for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) {
- MACBackup[i] = ODM_Read1Byte(dm_odm, MACReg[i]);
+ MACBackup[i] = rtw_read8(adapt, MACReg[i]);
}
- MACBackup[i] = ODM_Read4Byte(dm_odm, MACReg[i]);
+ MACBackup[i] = rtw_read32(adapt, MACReg[i]);
}
static void reload_adda_reg(struct adapter *adapt, u32 *ADDAReg, u32 *ADDABackup, u32 RegiesterNum)
@@ -868,9 +868,9 @@ _PHY_ReloadMACRegisters(
ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Reload MAC parameters !\n"));
for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) {
- ODM_Write1Byte(dm_odm, MACReg[i], (u8)MACBackup[i]);
+ rtw_write8(adapt, MACReg[i], (u8)MACBackup[i]);
}
- ODM_Write4Byte(dm_odm, MACReg[i], MACBackup[i]);
+ rtw_write32(adapt, MACReg[i], MACBackup[i]);
}
void
@@ -912,12 +912,12 @@ _PHY_MACSettingCalibration(
ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("MAC settings for Calibration.\n"));
- ODM_Write1Byte(dm_odm, MACReg[i], 0x3F);
+ rtw_write8(adapt, MACReg[i], 0x3F);
for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++) {
- ODM_Write1Byte(dm_odm, MACReg[i], (u8)(MACBackup[i]&(~BIT3)));
+ rtw_write8(adapt, MACReg[i], (u8)(MACBackup[i]&(~BIT3)));
}
- ODM_Write1Byte(dm_odm, MACReg[i], (u8)(MACBackup[i]&(~BIT5)));
+ rtw_write8(adapt, MACReg[i], (u8)(MACBackup[i]&(~BIT5)));
}
void
@@ -1223,16 +1223,14 @@ static void phy_LCCalibrate_8188E(struct adapter *adapt, bool is2t)
{
u8 tmpreg;
u32 RF_Amode = 0, RF_Bmode = 0, LC_Cal;
- struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
- struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
/* Check continuous TX and Packet TX */
- tmpreg = ODM_Read1Byte(dm_odm, 0xd03);
+ tmpreg = rtw_read8(adapt, 0xd03);
if ((tmpreg&0x70) != 0) /* Deal with contisuous TX case */
- ODM_Write1Byte(dm_odm, 0xd03, tmpreg&0x8F); /* disable all continuous TX */
+ rtw_write8(adapt, 0xd03, tmpreg&0x8F); /* disable all continuous TX */
else /* Deal with Packet TX case */
- ODM_Write1Byte(dm_odm, REG_TXPAUSE, 0xFF); /* block all queues */
+ rtw_write8(adapt, REG_TXPAUSE, 0xFF); /* block all queues */
if ((tmpreg&0x70) != 0) {
/* 1. Read original RF mode */
@@ -1264,7 +1262,7 @@ static void phy_LCCalibrate_8188E(struct adapter *adapt, bool is2t)
if ((tmpreg&0x70) != 0) {
/* Deal with continuous TX case */
/* Path-A */
- ODM_Write1Byte(dm_odm, 0xd03, tmpreg);
+ rtw_write8(adapt, 0xd03, tmpreg);
PHY_SetRFReg(adapt, RF_PATH_A, RF_AC, bMask12Bits, RF_Amode);
/* Path-B */
@@ -1272,7 +1270,7 @@ static void phy_LCCalibrate_8188E(struct adapter *adapt, bool is2t)
PHY_SetRFReg(adapt, RF_PATH_B, RF_AC, bMask12Bits, RF_Bmode);
} else {
/* Deal with Packet TX case */
- ODM_Write1Byte(dm_odm, REG_TXPAUSE, 0x00);
+ rtw_write8(adapt, REG_TXPAUSE, 0x00);
}
}
@@ -1468,13 +1466,10 @@ void PHY_LCCalibrate_8188E(struct adapter *adapt)
static void phy_setrfpathswitch_8188e(struct adapter *adapt, bool main, bool is2t)
{
- struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
- struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
-
if (!adapt->hw_init_completed) {
u8 u1btmp;
- u1btmp = ODM_Read1Byte(dm_odm, REG_LEDCFG2) | BIT7;
- ODM_Write1Byte(dm_odm, REG_LEDCFG2, u1btmp);
+ u1btmp = rtw_read8(adapt, REG_LEDCFG2) | BIT7;
+ rtw_write8(adapt, REG_LEDCFG2, u1btmp);
PHY_SetBBReg(adapt, rFPGA0_XAB_RFParameter, BIT13, 0x01);
}
diff --git a/drivers/staging/rtl8188eu/hal/hal_intf.c b/drivers/staging/rtl8188eu/hal/hal_intf.c
index 598140464f05..d75ca7a27c86 100644
--- a/drivers/staging/rtl8188eu/hal/hal_intf.c
+++ b/drivers/staging/rtl8188eu/hal/hal_intf.c
@@ -116,8 +116,6 @@ uint rtw_hal_deinit(struct adapter *adapt)
{
uint status = _SUCCESS;
-_func_enter_;
-
status = adapt->HalFunc.hal_deinit(adapt);
if (status == _SUCCESS)
@@ -125,8 +123,6 @@ _func_enter_;
else
DBG_88E("\n rtw_hal_deinit: hal_init fail\n");
-_func_exit_;
-
return status;
}
diff --git a/drivers/staging/rtl8188eu/hal/odm.c b/drivers/staging/rtl8188eu/hal/odm.c
index 3555ffaa4e06..89a26e3e217f 100644
--- a/drivers/staging/rtl8188eu/hal/odm.c
+++ b/drivers/staging/rtl8188eu/hal/odm.c
@@ -887,9 +887,10 @@ void odm_CCKPacketDetectionThresh(struct odm_dm_struct *pDM_Odm)
void ODM_Write_CCK_CCA_Thres(struct odm_dm_struct *pDM_Odm, u8 CurCCK_CCAThres)
{
struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable;
+ struct adapter *adapt = pDM_Odm->Adapter;
if (pDM_DigTable->CurCCK_CCAThres != CurCCK_CCAThres) /* modify by Guo.Mingzhi 2012-01-03 */
- ODM_Write1Byte(pDM_Odm, ODM_REG(CCK_CCA, pDM_Odm), CurCCK_CCAThres);
+ rtw_write8(adapt, ODM_REG(CCK_CCA, pDM_Odm), CurCCK_CCAThres);
pDM_DigTable->PreCCK_CCAThres = pDM_DigTable->CurCCK_CCAThres;
pDM_DigTable->CurCCK_CCAThres = CurCCK_CCAThres;
}
@@ -1301,8 +1302,8 @@ void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm)
psta = pDM_Odm->pODM_StaInfo[i];
if (IS_STA_VALID(psta) &&
(psta->state & WIFI_ASOC_STATE) &&
- !_rtw_memcmp(psta->hwaddr, bcast_addr, ETH_ALEN) &&
- !_rtw_memcmp(psta->hwaddr, myid(&Adapter->eeprompriv), ETH_ALEN)) {
+ memcmp(psta->hwaddr, bcast_addr, ETH_ALEN) &&
+ memcmp(psta->hwaddr, myid(&Adapter->eeprompriv), ETH_ALEN)) {
if (psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB)
tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB;
@@ -1433,10 +1434,10 @@ void ODM_EdcaTurboInit(struct odm_dm_struct *pDM_Odm)
pDM_Odm->DM_EDCA_Table.bIsCurRDLState = false;
Adapter->recvpriv.bIsAnyNonBEPkts = false;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VO PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_VO_PARAM)));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VI PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_VI_PARAM)));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BE PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_BE_PARAM)));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BK PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_BK_PARAM)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VO PARAM: 0x%x\n", rtw_read32(Adapter, ODM_EDCA_VO_PARAM)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VI PARAM: 0x%x\n", rtw_read32(Adapter, ODM_EDCA_VI_PARAM)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BE PARAM: 0x%x\n", rtw_read32(Adapter, ODM_EDCA_BE_PARAM)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BK PARAM: 0x%x\n", rtw_read32(Adapter, ODM_EDCA_BK_PARAM)));
} /* ODM_InitEdcaTurbo */
void odm_EdcaTurboCheck(struct odm_dm_struct *pDM_Odm)
diff --git a/drivers/staging/rtl8188eu/hal/odm_RegConfig8188E.c b/drivers/staging/rtl8188eu/hal/odm_RegConfig8188E.c
index 6193d9fafb98..a9886122b459 100644
--- a/drivers/staging/rtl8188eu/hal/odm_RegConfig8188E.c
+++ b/drivers/staging/rtl8188eu/hal/odm_RegConfig8188E.c
@@ -66,7 +66,9 @@ void odm_ConfigRF_RadioB_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Data
void odm_ConfigMAC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u8 Data)
{
- ODM_Write1Byte(pDM_Odm, Addr, Data);
+ struct adapter *adapt = pDM_Odm->Adapter;
+
+ rtw_write8(adapt, Addr, Data);
ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigMACWithHeaderFile: [MAC_REG] %08X %08X\n", Addr, Data));
}
diff --git a/drivers/staging/rtl8188eu/hal/odm_interface.c b/drivers/staging/rtl8188eu/hal/odm_interface.c
deleted file mode 100644
index 3cd68212afd1..000000000000
--- a/drivers/staging/rtl8188eu/hal/odm_interface.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- * 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.
- *
- * 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, USA
- *
- *
- ******************************************************************************/
-
-#include "odm_precomp.h"
-/* ODM IO Relative API. */
-
-u8 ODM_Read1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr)
-{
- struct adapter *Adapter = pDM_Odm->Adapter;
- return rtw_read8(Adapter, RegAddr);
-}
-
-u16 ODM_Read2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr)
-{
- struct adapter *Adapter = pDM_Odm->Adapter;
- return rtw_read16(Adapter, RegAddr);
-}
-
-u32 ODM_Read4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr)
-{
- struct adapter *Adapter = pDM_Odm->Adapter;
- return rtw_read32(Adapter, RegAddr);
-}
-
-void ODM_Write1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u8 Data)
-{
- struct adapter *Adapter = pDM_Odm->Adapter;
- rtw_write8(Adapter, RegAddr, Data);
-}
-
-void ODM_Write2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u16 Data)
-{
- struct adapter *Adapter = pDM_Odm->Adapter;
- rtw_write16(Adapter, RegAddr, Data);
-}
-
-void ODM_Write4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 Data)
-{
- struct adapter *Adapter = pDM_Odm->Adapter;
- rtw_write32(Adapter, RegAddr, Data);
-}
-
-/* ODM Memory relative API. */
-void ODM_AllocateMemory(struct odm_dm_struct *pDM_Odm, void **pPtr, u32 length)
-{
- *pPtr = rtw_zvmalloc(length);
-}
-
-/* length could be ignored, used to detect memory leakage. */
-void ODM_FreeMemory(struct odm_dm_struct *pDM_Odm, void *pPtr, u32 length)
-{
- rtw_vmfree(pPtr, length);
-}
-
-s32 ODM_CompareMemory(struct odm_dm_struct *pDM_Odm, void *pBuf1, void *pBuf2, u32 length)
-{
- return _rtw_memcmp(pBuf1, pBuf2, length);
-}
-
-void ODM_SetTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer, u32 msDelay)
-{
- _set_timer(pTimer, msDelay); /* ms */
-}
-
-void ODM_InitializeTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer,
- void *CallBackFunc, void *pContext,
- const char *szID)
-{
- struct adapter *Adapter = pDM_Odm->Adapter;
- _init_timer(pTimer, Adapter->pnetdev, CallBackFunc, pDM_Odm);
-}
-
-void ODM_CancelTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer)
-{
- _cancel_timer_ex(pTimer);
-}
-
-/* ODM FW relative API. */
-u32 ODM_FillH2CCmd(u8 *pH2CBuffer, u32 H2CBufferLen, u32 CmdNum,
- u32 *pElementID, u32 *pCmdLen,
- u8 **pCmbBuffer, u8 *CmdStartSeq)
-{
- return true;
-}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
index ca0a7085445f..021e5879abcf 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
@@ -72,7 +72,6 @@ static s32 FillH2CCmd_88E(struct adapter *adapt, u8 ElementID, u32 CmdLen, u8 *p
u32 h2c_cmd_ex = 0;
s32 ret = _FAIL;
-_func_enter_;
if (!adapt->bFWReady) {
DBG_88E("FillH2CCmd_88E(): return H2C cmd because fw is not ready\n");
@@ -125,7 +124,6 @@ _func_enter_;
exit:
-_func_exit_;
return ret;
}
@@ -134,7 +132,6 @@ u8 rtl8188e_set_rssi_cmd(struct adapter *adapt, u8 *param)
{
u8 res = _SUCCESS;
struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
-_func_enter_;
if (haldata->fw_ractrl) {
;
@@ -143,7 +140,6 @@ _func_enter_;
res = _FAIL;
}
-_func_exit_;
return res;
}
@@ -154,7 +150,6 @@ u8 rtl8188e_set_raid_cmd(struct adapter *adapt, u32 mask)
u8 res = _SUCCESS;
struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
-_func_enter_;
if (haldata->fw_ractrl) {
__le32 lmask;
@@ -168,7 +163,6 @@ _func_enter_;
res = _FAIL;
}
-_func_exit_;
return res;
}
@@ -215,7 +209,6 @@ void rtl8188e_set_FwPwrMode_cmd(struct adapter *adapt, u8 Mode)
struct setpwrmode_parm H2CSetPwrMode;
struct pwrctrl_priv *pwrpriv = &adapt->pwrctrlpriv;
u8 RLBM = 0; /* 0:Min, 1:Max, 2:User define */
-_func_enter_;
DBG_88E("%s: Mode=%d SmartPS=%d UAPSD=%d\n", __func__,
Mode, pwrpriv->smart_ps, adapt->registrypriv.uapsd_enable);
@@ -256,7 +249,6 @@ _func_enter_;
FillH2CCmd_88E(adapt, H2C_PS_PWR_MODE, sizeof(H2CSetPwrMode), (u8 *)&H2CSetPwrMode);
-_func_exit_;
}
void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, __le16 mstatus_rpt)
@@ -617,7 +609,6 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
u8 DLBcnCount = 0;
u32 poll = 0;
-_func_enter_;
DBG_88E("%s mstatus(%x)\n", __func__, mstatus);
@@ -701,7 +692,6 @@ _func_enter_;
haldata->RegCR_1 &= (~BIT0);
rtw_write8(adapt, REG_CR+1, haldata->RegCR_1);
}
-_func_exit_;
}
void rtl8188e_set_p2p_ps_offload_cmd(struct adapter *adapt, u8 p2p_ps_state)
@@ -712,7 +702,6 @@ void rtl8188e_set_p2p_ps_offload_cmd(struct adapter *adapt, u8 p2p_ps_state)
struct P2P_PS_Offload_t *p2p_ps_offload = &haldata->p2p_ps_offload;
u8 i;
-_func_enter_;
switch (p2p_ps_state) {
case P2P_PS_DISABLE:
@@ -775,5 +764,4 @@ _func_enter_;
FillH2CCmd_88E(adapt, H2C_PS_P2P_OFFLOAD, 1, (u8 *)p2p_ps_offload);
#endif
-_func_exit_;
}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
index 4c934e2e0911..cf88bf247c85 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
@@ -160,7 +160,6 @@ void rtl8188e_HalDmWatchDog(struct adapter *Adapter)
u8 hw_init_completed = false;
struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
- _func_enter_;
hw_init_completed = Adapter->hw_init_completed;
if (!hw_init_completed)
@@ -178,7 +177,6 @@ void rtl8188e_HalDmWatchDog(struct adapter *Adapter)
/* Calculate Tx/Rx statistics. */
dm_CheckStatistics(Adapter);
- _func_exit_;
}
/* ODM */
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
index 5921db86547f..f9d5558431e0 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
@@ -20,6 +20,7 @@
#define _HAL_INIT_C_
#include <linux/firmware.h>
+#include <linux/vmalloc.h>
#include <drv_types.h>
#include <rtw_efuse.h>
@@ -365,7 +366,7 @@ void rtw_IOL_cmd_tx_pkt_buf_dump(struct adapter *Adapter, int data_len)
u32 fifo_data, reg_140;
u32 addr, rstatus, loop = 0;
u16 data_cnts = (data_len/8)+1;
- u8 *pbuf = rtw_zvmalloc(data_len+10);
+ u8 *pbuf = vzalloc(data_len+10);
DBG_88E("###### %s ######\n", __func__);
rtw_write8(Adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
@@ -387,7 +388,7 @@ void rtw_IOL_cmd_tx_pkt_buf_dump(struct adapter *Adapter, int data_len)
} while (!rstatus && (loop++ < 10));
}
rtw_IOL_cmd_buf_dump(Adapter, data_len, pbuf);
- rtw_vmfree(pbuf, data_len+10);
+ vfree(pbuf);
}
DBG_88E("###### %s ######\n", __func__);
}
@@ -583,59 +584,70 @@ static s32 _FWFreeToGo(struct adapter *padapter)
#define IS_FW_81xxC(padapter) (((GET_HAL_DATA(padapter))->FirmwareSignature & 0xFFF0) == 0x88C0)
-s32 rtl8188e_FirmwareDownload(struct adapter *padapter)
+static int load_firmware(struct rt_firmware *pFirmware, struct device *device)
{
- s32 rtStatus = _SUCCESS;
- u8 writeFW_retry = 0;
- u32 fwdl_start_time;
- struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
- struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
- struct device *device = dvobj_to_dev(dvobj);
- struct rt_firmware *pFirmware = NULL;
+ int rtstatus = _SUCCESS;
const struct firmware *fw;
- struct rt_firmware_hdr *pFwHdr = NULL;
- u8 *pFirmwareBuf;
- u32 FirmwareLen;
- char fw_name[] = "rtlwifi/rtl8188eufw.bin";
- static int log_version;
-
- RT_TRACE(_module_hal_init_c_, _drv_info_, ("+%s\n", __func__));
- pFirmware = (struct rt_firmware *)rtw_zmalloc(sizeof(struct rt_firmware));
- if (!pFirmware) {
- rtStatus = _FAIL;
- goto Exit;
- }
+ const char fw_name[] = "rtlwifi/rtl8188eufw.bin";
if (request_firmware(&fw, fw_name, device)) {
- rtStatus = _FAIL;
- goto Exit;
+ rtstatus = _FAIL;
+ goto exit;
}
if (!fw) {
pr_err("Firmware %s not available\n", fw_name);
- rtStatus = _FAIL;
- goto Exit;
+ rtstatus = _FAIL;
+ goto exit;
}
if (fw->size > FW_8188E_SIZE) {
- rtStatus = _FAIL;
- RT_TRACE(_module_hal_init_c_, _drv_err_, ("Firmware size exceed 0x%X. Check it.\n", FW_8188E_SIZE));
- goto Exit;
+ rtstatus = _FAIL;
+ RT_TRACE(_module_hal_init_c_, _drv_err_,
+ ("Firmware size exceed 0x%X. Check it.\n",
+ FW_8188E_SIZE));
+ goto exit;
}
pFirmware->szFwBuffer = kzalloc(FW_8188E_SIZE, GFP_KERNEL);
if (!pFirmware->szFwBuffer) {
- rtStatus = _FAIL;
- goto Exit;
+ rtstatus = _FAIL;
+ goto exit;
}
memcpy(pFirmware->szFwBuffer, fw->data, fw->size);
pFirmware->ulFwLength = fw->size;
- pFirmwareBuf = pFirmware->szFwBuffer;
- FirmwareLen = pFirmware->ulFwLength;
release_firmware(fw);
- DBG_88E_LEVEL(_drv_info_, "+%s: !bUsedWoWLANFw, FmrmwareLen:%d+\n", __func__, FirmwareLen);
+ DBG_88E_LEVEL(_drv_info_,
+ "+%s: !bUsedWoWLANFw, FmrmwareLen:%d+\n", __func__,
+ pFirmware->ulFwLength);
+exit:
+ return rtstatus;
+}
+
+s32 rtl8188e_FirmwareDownload(struct adapter *padapter)
+{
+ s32 rtStatus = _SUCCESS;
+ u8 writeFW_retry = 0;
+ u32 fwdl_start_time;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+ struct device *device = dvobj_to_dev(dvobj);
+ struct rt_firmware_hdr *pFwHdr = NULL;
+ u8 *pFirmwareBuf;
+ u32 FirmwareLen;
+ static int log_version;
+
+ RT_TRACE(_module_hal_init_c_, _drv_info_, ("+%s\n", __func__));
+ if (!dvobj->firmware.szFwBuffer)
+ rtStatus = load_firmware(&dvobj->firmware, device);
+ if (rtStatus == _FAIL) {
+ dvobj->firmware.szFwBuffer = NULL;
+ goto Exit;
+ }
+ pFirmwareBuf = dvobj->firmware.szFwBuffer;
+ FirmwareLen = dvobj->firmware.ulFwLength;
/* To Check Fw header. Added by tynli. 2009.12.04. */
- pFwHdr = (struct rt_firmware_hdr *)pFirmware->szFwBuffer;
+ pFwHdr = (struct rt_firmware_hdr *)dvobj->firmware.szFwBuffer;
pHalData->FirmwareVersion = le16_to_cpu(pFwHdr->Version);
pHalData->FirmwareSubVersion = pFwHdr->Subversion;
@@ -687,10 +699,7 @@ s32 rtl8188e_FirmwareDownload(struct adapter *padapter)
goto Exit;
}
RT_TRACE(_module_hal_init_c_, _drv_info_, ("Firmware is ready to run!\n"));
- kfree(pFirmware->szFwBuffer);
Exit:
-
- kfree(pFirmware);
return rtStatus;
}
@@ -707,10 +716,8 @@ void rtl8188e_InitializeFirmwareVars(struct adapter *padapter)
static void rtl8188e_free_hal_data(struct adapter *padapter)
{
-_func_enter_;
kfree(padapter->HalData);
padapter->HalData = NULL;
-_func_exit_;
}
/* */
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_mp.c b/drivers/staging/rtl8188eu/hal/rtl8188e_mp.c
index 3d0e6c9e0310..a4d057cf7db2 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_mp.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_mp.c
@@ -115,14 +115,12 @@ void Hal_MPT_CCKTxPowerAdjust(struct adapter *Adapter, bool bInCH14)
/* Write 0xa24 ~ 0xa27 */
- TempVal2 = 0;
TempVal2 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][2] +
(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][3]<<8) +
(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][4]<<16)+
(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][5]<<24);
/* Write 0xa28 0xa29 */
- TempVal3 = 0;
TempVal3 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][6] +
(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][7]<<8);
} else {
@@ -139,14 +137,12 @@ void Hal_MPT_CCKTxPowerAdjust(struct adapter *Adapter, bool bInCH14)
(CCKSwingTable_Ch14[CCKSwingIndex][1]<<8);
/* Write 0xa24 ~ 0xa27 */
- TempVal2 = 0;
TempVal2 = CCKSwingTable_Ch14[CCKSwingIndex][2] +
(CCKSwingTable_Ch14[CCKSwingIndex][3]<<8) +
(CCKSwingTable_Ch14[CCKSwingIndex][4]<<16)+
(CCKSwingTable_Ch14[CCKSwingIndex][5]<<24);
/* Write 0xa28 0xa29 */
- TempVal3 = 0;
TempVal3 = CCKSwingTable_Ch14[CCKSwingIndex][6] +
(CCKSwingTable_Ch14[CCKSwingIndex][7]<<8);
}
@@ -184,12 +180,12 @@ void Hal_MPT_CCKTxPowerAdjustbyIndex(struct adapter *pAdapter, bool beven)
TempCCk = read_bbreg(pAdapter, rCCK0_TxFilter2, bMaskDWord) & bMaskCCK;
for (i = 0; i < CCK_TABLE_SIZE; i++) {
if (pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
- if (_rtw_memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch14[i][2], 4)) {
+ if (!memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch14[i][2], 4)) {
CCK_index_old = (u8)i;
break;
}
} else {
- if (_rtw_memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch1_Ch13[i][2], 4)) {
+ if (!memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch1_Ch13[i][2], 4)) {
CCK_index_old = (u8)i;
break;
}
@@ -201,6 +197,8 @@ void Hal_MPT_CCKTxPowerAdjustbyIndex(struct adapter *pAdapter, bool beven)
else
CCK_index = CCK_index_old + 1;
+ if (CCK_index > 32)
+ CCK_index = 32;
/* Adjust CCK according to gain index */
if (!pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
rtw_write8(pAdapter, 0xa22, CCKSwingTable_Ch1_Ch13[CCK_index][0]);
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c b/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c
index 511f61cbb9e0..43eb960e4e0b 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c
@@ -23,9 +23,9 @@
#include <drv_types.h>
#include <rtl8188e_hal.h>
-static void process_rssi(struct adapter *padapter, union recv_frame *prframe)
+static void process_rssi(struct adapter *padapter, struct recv_frame *prframe)
{
- struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
+ struct rx_pkt_attrib *pattrib = &prframe->attrib;
struct signal_stat *signal_stat = &padapter->recvpriv.signal_strength_data;
if (signal_stat->update_req) {
@@ -39,7 +39,8 @@ static void process_rssi(struct adapter *padapter, union recv_frame *prframe)
signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num;
} /* Process_UI_RSSI_8192C */
-static void process_link_qual(struct adapter *padapter, union recv_frame *prframe)
+static void process_link_qual(struct adapter *padapter,
+ struct recv_frame *prframe)
{
struct rx_pkt_attrib *pattrib;
struct signal_stat *signal_stat;
@@ -47,7 +48,7 @@ static void process_link_qual(struct adapter *padapter, union recv_frame *prfram
if (prframe == NULL || padapter == NULL)
return;
- pattrib = &prframe->u.hdr.attrib;
+ pattrib = &prframe->attrib;
signal_stat = &padapter->recvpriv.signal_qual_data;
if (signal_stat->update_req) {
@@ -63,7 +64,7 @@ static void process_link_qual(struct adapter *padapter, union recv_frame *prfram
void rtl8188e_process_phy_info(struct adapter *padapter, void *prframe)
{
- union recv_frame *precvframe = (union recv_frame *)prframe;
+ struct recv_frame *precvframe = (struct recv_frame *)prframe;
/* Check RSSI */
process_rssi(padapter, precvframe);
@@ -71,7 +72,8 @@ void rtl8188e_process_phy_info(struct adapter *padapter, void *prframe)
process_link_qual(padapter, precvframe);
}
-void update_recvframe_attrib_88e(union recv_frame *precvframe, struct recv_stat *prxstat)
+void update_recvframe_attrib_88e(struct recv_frame *precvframe,
+ struct recv_stat *prxstat)
{
struct rx_pkt_attrib *pattrib;
struct recv_stat report;
@@ -83,7 +85,7 @@ void update_recvframe_attrib_88e(union recv_frame *precvframe, struct recv_stat
report.rxdw4 = prxstat->rxdw4;
report.rxdw5 = prxstat->rxdw5;
- pattrib = &precvframe->u.hdr.attrib;
+ pattrib = &precvframe->attrib;
_rtw_memset(pattrib, 0, sizeof(struct rx_pkt_attrib));
pattrib->crc_err = (u8)((le32_to_cpu(report.rxdw0) >> 14) & 0x1);/* u8)prxreport->crc32; */
@@ -136,12 +138,13 @@ void update_recvframe_attrib_88e(union recv_frame *precvframe, struct recv_stat
/*
* Notice:
* Before calling this function,
- * precvframe->u.hdr.rx_data should be ready!
+ * precvframe->rx_data should be ready!
*/
-void update_recvframe_phyinfo_88e(union recv_frame *precvframe, struct phy_stat *pphy_status)
+void update_recvframe_phyinfo_88e(struct recv_frame *precvframe,
+ struct phy_stat *pphy_status)
{
- struct adapter *padapter = precvframe->u.hdr.adapter;
- struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
+ struct adapter *padapter = precvframe->adapter;
+ struct rx_pkt_attrib *pattrib = &precvframe->attrib;
struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
struct odm_phy_status_info *pPHYInfo = (struct odm_phy_status_info *)(&pattrib->phy_info);
u8 *wlanhdr;
@@ -154,15 +157,15 @@ void update_recvframe_phyinfo_88e(union recv_frame *precvframe, struct phy_stat
pkt_info.bPacketToSelf = false;
pkt_info.bPacketBeacon = false;
- wlanhdr = get_recvframe_data(precvframe);
+ wlanhdr = precvframe->rx_data;
pkt_info.bPacketMatchBSSID = ((!IsFrameTypeCtrl(wlanhdr)) &&
!pattrib->icv_err && !pattrib->crc_err &&
- _rtw_memcmp(get_hdr_bssid(wlanhdr),
+ !memcmp(get_hdr_bssid(wlanhdr),
get_bssid(&padapter->mlmepriv), ETH_ALEN));
pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID &&
- (_rtw_memcmp(get_da(wlanhdr),
+ (!memcmp(get_da(wlanhdr),
myid(&padapter->eeprompriv), ETH_ALEN));
pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID &&
@@ -185,17 +188,17 @@ void update_recvframe_phyinfo_88e(union recv_frame *precvframe, struct phy_stat
ODM_PhyStatusQuery(&pHalData->odmpriv, pPHYInfo, (u8 *)pphy_status, &(pkt_info));
- precvframe->u.hdr.psta = NULL;
+ precvframe->psta = NULL;
if (pkt_info.bPacketMatchBSSID &&
(check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE))) {
if (psta) {
- precvframe->u.hdr.psta = psta;
+ precvframe->psta = psta;
rtl8188e_process_phy_info(padapter, precvframe);
}
} else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) {
if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) {
if (psta)
- precvframe->u.hdr.psta = psta;
+ precvframe->psta = psta;
}
rtl8188e_process_phy_info(padapter, precvframe);
}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c
index 17c94f4cc477..b1b1584af1cd 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c
@@ -22,9 +22,6 @@
#include <drv_types.h>
#include <recv_osdep.h>
#include <mlme_osdep.h>
-#include <ip.h>
-#include <if_ether.h>
-#include <ethernet.h>
#include <usb_ops.h>
#include <wifi.h>
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
index 6fb6a46f04fe..3476f8898330 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
@@ -537,11 +537,11 @@ s32 rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmitp
spin_lock_bh(&pxmitpriv->lock);
xmitframe_phead = get_list_head(&ptxservq->sta_pending);
- xmitframe_plist = get_next(xmitframe_phead);
+ xmitframe_plist = xmitframe_phead->next;
while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
- pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
- xmitframe_plist = get_next(xmitframe_plist);
+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
+ xmitframe_plist = xmitframe_plist->next;
pxmitframe->agg_num = 0; /* not first frame of aggregation */
pxmitframe->pkt_offset = 0; /* not first frame of aggregation, no need to reserve offset */
diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c
index b24ad495062c..c92067f0ef15 100644
--- a/drivers/staging/rtl8188eu/hal/usb_halinit.c
+++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c
@@ -709,7 +709,6 @@ static u32 rtl8188eu_hal_init(struct adapter *Adapter)
#define HAL_INIT_PROFILE_TAG(stage) do {} while (0)
-_func_enter_;
HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BEGIN);
@@ -967,7 +966,6 @@ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_END);
DBG_88E("%s in %dms\n", __func__, rtw_get_passing_time_ms(init_start_time));
-_func_exit_;
return status;
}
@@ -1084,7 +1082,6 @@ static unsigned int rtl8188eu_inirp_init(struct adapter *Adapter)
struct recv_priv *precvpriv = &(Adapter->recvpriv);
u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
-_func_enter_;
_read_port = pintfhdl->io_ops._read_port;
@@ -1112,7 +1109,6 @@ exit:
RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("<=== usb_inirp_init\n"));
-_func_exit_;
return status;
}
@@ -1402,7 +1398,6 @@ static void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val)
struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
struct dm_priv *pdmpriv = &haldata->dmpriv;
struct odm_dm_struct *podmpriv = &haldata->odmpriv;
-_func_enter_;
switch (variable) {
case HW_VAR_MEDIA_STATUS:
@@ -1921,14 +1916,12 @@ _func_enter_;
default:
break;
}
-_func_exit_;
}
static void GetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val)
{
struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
struct odm_dm_struct *podmpriv = &haldata->odmpriv;
-_func_enter_;
switch (variable) {
case HW_VAR_BASIC_RATE:
@@ -1980,7 +1973,6 @@ _func_enter_;
break;
}
-_func_exit_;
}
/* */
@@ -2302,7 +2294,6 @@ void rtl8188eu_set_hal_ops(struct adapter *adapt)
{
struct hal_ops *halfunc = &adapt->HalFunc;
-_func_enter_;
adapt->HalData = rtw_zmalloc(sizeof(struct hal_data_8188e));
if (adapt->HalData == NULL)
@@ -2342,5 +2333,4 @@ _func_enter_;
halfunc->interface_ps_func = &rtl8188eu_ps_func;
rtl8188e_set_hal_ops(halfunc);
-_func_exit_;
}
diff --git a/drivers/staging/rtl8188eu/hal/usb_ops_linux.c b/drivers/staging/rtl8188eu/hal/usb_ops_linux.c
index 31ae21a54c92..1fa5370f1da6 100644
--- a/drivers/staging/rtl8188eu/hal/usb_ops_linux.c
+++ b/drivers/staging/rtl8188eu/hal/usb_ops_linux.c
@@ -111,7 +111,7 @@ static int usbctrl_vendorreq(struct intf_hdl *pintfhdl, u8 request, u16 value, u
break;
}
release_mutex:
- _exit_critical_mutex(&dvobjpriv->usb_vendor_req_mutex, NULL);
+ mutex_unlock(&dvobjpriv->usb_vendor_req_mutex);
exit:
return status;
}
@@ -125,7 +125,6 @@ static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)
u16 len;
u8 data = 0;
- _func_enter_;
request = 0x05;
requesttype = 0x01;/* read_in */
@@ -136,7 +135,6 @@ static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)
usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
- _func_exit_;
return data;
@@ -151,14 +149,12 @@ static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr)
u16 len;
__le32 data;
-_func_enter_;
request = 0x05;
requesttype = 0x01;/* read_in */
index = 0;/* n/a */
wvalue = (u16)(addr&0x0000ffff);
len = 2;
usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
-_func_exit_;
return (u16)(le32_to_cpu(data)&0xffff);
}
@@ -172,7 +168,6 @@ static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr)
u16 len;
__le32 data;
-_func_enter_;
request = 0x05;
requesttype = 0x01;/* read_in */
@@ -183,7 +178,6 @@ _func_enter_;
usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
-_func_exit_;
return le32_to_cpu(data);
}
@@ -198,7 +192,6 @@ static int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
u8 data;
int ret;
- _func_enter_;
request = 0x05;
requesttype = 0x00;/* write_out */
index = 0;/* n/a */
@@ -206,7 +199,6 @@ static int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
len = 1;
data = val;
ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
- _func_exit_;
return ret;
}
@@ -220,7 +212,6 @@ static int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
__le32 data;
int ret;
- _func_enter_;
request = 0x05;
requesttype = 0x00;/* write_out */
@@ -233,7 +224,6 @@ static int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
- _func_exit_;
return ret;
}
@@ -248,7 +238,6 @@ static int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
__le32 data;
int ret;
- _func_enter_;
request = 0x05;
requesttype = 0x00;/* write_out */
@@ -260,7 +249,6 @@ static int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
- _func_exit_;
return ret;
}
@@ -275,7 +263,6 @@ static int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata
u8 buf[VENDOR_CMD_MAX_DATA_LEN] = {0};
int ret;
- _func_enter_;
request = 0x05;
requesttype = 0x00;/* write_out */
@@ -287,7 +274,6 @@ static int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata
ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, buf, len, requesttype);
- _func_exit_;
return ret;
}
@@ -320,7 +306,7 @@ static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb)
struct recv_stat *prxstat;
struct phy_stat *pphy_status = NULL;
struct sk_buff *pkt_copy = NULL;
- union recv_frame *precvframe = NULL;
+ struct recv_frame *precvframe = NULL;
struct rx_pkt_attrib *pattrib = NULL;
struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
struct recv_priv *precvpriv = &adapt->recvpriv;
@@ -346,13 +332,13 @@ static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb)
goto _exit_recvbuf2recvframe;
}
- _rtw_init_listhead(&precvframe->u.hdr.list);
- precvframe->u.hdr.precvbuf = NULL; /* can't access the precvbuf for new arch. */
- precvframe->u.hdr.len = 0;
+ _rtw_init_listhead(&precvframe->list);
+ precvframe->precvbuf = NULL; /* can't access the precvbuf for new arch. */
+ precvframe->len = 0;
update_recvframe_attrib_88e(precvframe, prxstat);
- pattrib = &precvframe->u.hdr.attrib;
+ pattrib = &precvframe->attrib;
if ((pattrib->crc_err) || (pattrib->icv_err)) {
DBG_88E("%s: RX Warning! crc_err=%d icv_err=%d, skip!\n", __func__, pattrib->crc_err, pattrib->icv_err);
@@ -399,26 +385,26 @@ static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb)
pkt_copy = netdev_alloc_skb(adapt->pnetdev, alloc_sz);
if (pkt_copy) {
pkt_copy->dev = adapt->pnetdev;
- precvframe->u.hdr.pkt = pkt_copy;
- precvframe->u.hdr.rx_head = pkt_copy->data;
- precvframe->u.hdr.rx_end = pkt_copy->data + alloc_sz;
+ precvframe->pkt = pkt_copy;
+ precvframe->rx_head = pkt_copy->data;
+ precvframe->rx_end = pkt_copy->data + alloc_sz;
skb_reserve(pkt_copy, 8 - ((size_t)(pkt_copy->data) & 7));/* force pkt_copy->data at 8-byte alignment address */
skb_reserve(pkt_copy, shift_sz);/* force ip_hdr at 8-byte alignment address according to shift_sz. */
memcpy(pkt_copy->data, (pbuf + pattrib->drvinfo_sz + RXDESC_SIZE), skb_len);
- precvframe->u.hdr.rx_tail = pkt_copy->data;
- precvframe->u.hdr.rx_data = pkt_copy->data;
+ precvframe->rx_tail = pkt_copy->data;
+ precvframe->rx_data = pkt_copy->data;
} else {
if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
DBG_88E("recvbuf2recvframe: alloc_skb fail , drop frag frame\n");
rtw_free_recvframe(precvframe, pfree_recv_queue);
goto _exit_recvbuf2recvframe;
}
- precvframe->u.hdr.pkt = skb_clone(pskb, GFP_ATOMIC);
- if (precvframe->u.hdr.pkt) {
- precvframe->u.hdr.rx_tail = pbuf + pattrib->drvinfo_sz + RXDESC_SIZE;
- precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_tail;
- precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail;
- precvframe->u.hdr.rx_end = pbuf + pattrib->drvinfo_sz + RXDESC_SIZE + alloc_sz;
+ precvframe->pkt = skb_clone(pskb, GFP_ATOMIC);
+ if (precvframe->pkt) {
+ precvframe->rx_tail = pbuf + pattrib->drvinfo_sz + RXDESC_SIZE;
+ precvframe->rx_head = precvframe->rx_tail;
+ precvframe->rx_data = precvframe->rx_tail;
+ precvframe->rx_end = pbuf + pattrib->drvinfo_sz + RXDESC_SIZE + alloc_sz;
} else {
DBG_88E("recvbuf2recvframe: skb_clone fail\n");
rtw_free_recvframe(precvframe, pfree_recv_queue);
@@ -451,17 +437,17 @@ static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb)
/* enqueue recvframe to txrtp queue */
if (pattrib->pkt_rpt_type == TX_REPORT1) {
/* CCX-TXRPT ack for xmit mgmt frames. */
- handle_txrpt_ccx_88e(adapt, precvframe->u.hdr.rx_data);
+ handle_txrpt_ccx_88e(adapt, precvframe->rx_data);
} else if (pattrib->pkt_rpt_type == TX_REPORT2) {
ODM_RA_TxRPT2Handle_8188E(
&haldata->odmpriv,
- precvframe->u.hdr.rx_data,
+ precvframe->rx_data,
pattrib->pkt_len,
pattrib->MacIDValidEntry[0],
pattrib->MacIDValidEntry[1]
);
} else if (pattrib->pkt_rpt_type == HIS_REPORT) {
- interrupt_handler_8188eu(adapt, pattrib->pkt_len, precvframe->u.hdr.rx_data);
+ interrupt_handler_8188eu(adapt, pattrib->pkt_len, precvframe->rx_data);
}
rtw_free_recvframe(precvframe, pfree_recv_queue);
}
@@ -519,7 +505,7 @@ static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs)
DBG_88E("%s() RX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bReadPortCancel(%d)\n",
__func__, adapt->bDriverStopped,
adapt->bSurpriseRemoved, adapt->bReadPortCancel);
- goto exit;
+ return;
}
if (purb->status == 0) { /* SUCCESS */
@@ -579,9 +565,6 @@ static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs)
break;
}
}
-
-exit:
-_func_exit_;
}
static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
@@ -598,7 +581,6 @@ static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
size_t alignment = 0;
u32 ret = _SUCCESS;
-_func_enter_;
if (adapter->bDriverStopped || adapter->bSurpriseRemoved ||
adapter->pwrctrlpriv.pnp_bstop_trx) {
@@ -672,7 +654,6 @@ _func_enter_;
ret = _FAIL;
}
-_func_exit_;
return ret;
}
@@ -702,7 +683,6 @@ void rtl8188eu_xmit_tasklet(void *priv)
void rtl8188eu_set_intf_ops(struct _io_ops *pops)
{
- _func_enter_;
_rtw_memset((u8 *)pops, 0, sizeof(struct _io_ops));
pops->_read8 = &usb_read8;
pops->_read16 = &usb_read16;
@@ -717,7 +697,6 @@ void rtl8188eu_set_intf_ops(struct _io_ops *pops)
pops->_write_port = &usb_write_port;
pops->_read_port_cancel = &usb_read_port_cancel;
pops->_write_port_cancel = &usb_write_port_cancel;
- _func_exit_;
}
void rtl8188eu_set_hw_type(struct adapter *adapt)
diff --git a/drivers/staging/rtl8188eu/include/drv_types.h b/drivers/staging/rtl8188eu/include/drv_types.h
index a492a1c547ae..936c196699af 100644
--- a/drivers/staging/rtl8188eu/include/drv_types.h
+++ b/drivers/staging/rtl8188eu/include/drv_types.h
@@ -159,9 +159,15 @@ struct registry_priv {
#define MAX_CONTINUAL_URB_ERR 4
+struct rt_firmware {
+ u8 *szFwBuffer;
+ u32 ulFwLength;
+};
+
struct dvobj_priv {
struct adapter *if1;
struct adapter *if2;
+ struct rt_firmware firmware;
/* For 92D, DMDP have 2 interface. */
u8 InterfaceNumber;
diff --git a/drivers/staging/rtl8188eu/include/ethernet.h b/drivers/staging/rtl8188eu/include/ethernet.h
deleted file mode 100644
index a59f9120cd7e..000000000000
--- a/drivers/staging/rtl8188eu/include/ethernet.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- * 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.
- *
- * 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, USA
- *
- *
- ******************************************************************************/
-/*! \file */
-#ifndef __INC_ETHERNET_H
-#define __INC_ETHERNET_H
-
-#define ETHERNET_ADDRESS_LENGTH 6 /* Ethernet Address Length */
-#define ETHERNET_HEADER_SIZE 14 /* Ethernet Header Length */
-#define LLC_HEADER_SIZE 6 /* LLC Header Length */
-#define TYPE_LENGTH_FIELD_SIZE 2 /* Type/Length Size */
-#define MINIMUM_ETHERNET_PACKET_SIZE 60 /* Min Ethernet Packet Size */
-#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 /* Max Ethernet Packet Size */
-
-/* Is Multicast Address? */
-#define RT_ETH_IS_MULTICAST(_addr) ((((u8 *)(_addr))[0]&0x01) != 0)
-#define RT_ETH_IS_BROADCAST(_addr) ( \
- ((u8 *)(_addr))[0] == 0xff && \
- ((u8 *)(_addr))[1] == 0xff && \
- ((u8 *)(_addr))[2] == 0xff && \
- ((u8 *)(_addr))[3] == 0xff && \
- ((u8 *)(_addr))[4] == 0xff && \
- ((u8 *)(_addr))[5] == 0xff) /* Is Broadcast Address? */
-
-
-#endif /* #ifndef __INC_ETHERNET_H */
diff --git a/drivers/staging/rtl8188eu/include/h2clbk.h b/drivers/staging/rtl8188eu/include/h2clbk.h
deleted file mode 100644
index e595030ac8a3..000000000000
--- a/drivers/staging/rtl8188eu/include/h2clbk.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- * 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.
- *
- * 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, USA
- *
- *
- ******************************************************************************/
-
-
-#define _H2CLBK_H_
-
-
-#include <rtl8711_spec.h>
-#include <TypeDef.h>
-
-
-void _lbk_cmd(struct adapter *adapter);
-
-void _lbk_rsp(struct adapter *adapter);
-
-void _lbk_evt(IN struct adapter *adapter);
-
-void h2c_event_callback(unsigned char *dev, unsigned char *pbuf);
diff --git a/drivers/staging/rtl8188eu/include/if_ether.h b/drivers/staging/rtl8188eu/include/if_ether.h
deleted file mode 100644
index db157712a203..000000000000
--- a/drivers/staging/rtl8188eu/include/if_ether.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- * 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.
- *
- * 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, USA
- *
- *
- ******************************************************************************/
-
-#ifndef _LINUX_IF_ETHER_H
-#define _LINUX_IF_ETHER_H
-
-/*
- * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
- * and FCS/CRC (frame check sequence).
- */
-
-#define ETH_ALEN 6 /* Octets in one ethernet addr */
-#define ETH_HLEN 14 /* Total octets in header. */
-#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
-#define ETH_DATA_LEN 1500 /* Max. octets in payload */
-#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
-
-/*
- * These are the defined Ethernet Protocol ID's.
- */
-
-#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */
-#define ETH_P_PUP 0x0200 /* Xerox PUP packet */
-#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */
-#define ETH_P_IP 0x0800 /* Internet Protocol packet */
-#define ETH_P_X25 0x0805 /* CCITT X.25 */
-#define ETH_P_ARP 0x0806 /* Address Resolution packet */
-#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet */
-#define ETH_P_IEEEPUP 0x0a00 /* Xerox IEEE802.3 PUP packet */
-#define ETH_P_IEEEPUPAT 0x0a01 /* Xerox IEEE802.3 PUP */
-#define ETH_P_DEC 0x6000 /* DEC Assigned proto */
-#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */
-#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */
-#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */
-#define ETH_P_LAT 0x6004 /* DEC LAT */
-#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */
-#define ETH_P_CUST 0x6006 /* DEC Customer use */
-#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */
-#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */
-#define ETH_P_ATALK 0x809B /* Appletalk DDP */
-#define ETH_P_AARP 0x80F3 /* Appletalk AARP */
-#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
-#define ETH_P_IPX 0x8137 /* IPX over DIX */
-#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
-#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */
-#define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */
-#define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */
-#define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport
- * over Ethernet
- */
-
-/*
- * Non DIX types. Won't clash for 1500 types.
- */
-
-#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
-#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
-#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */
-#define ETH_P_802_2 0x0004 /* 802.2 frames */
-#define ETH_P_SNAP 0x0005 /* Internal only */
-#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */
-#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/
-#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */
-#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
-#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
-#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */
-#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */
-#define ETH_P_CONTROL 0x0016 /* Card specific control frames */
-#define ETH_P_IRDA 0x0017 /* Linux-IrDA */
-#define ETH_P_ECONET 0x0018 /* Acorn Econet */
-
-/*
- * This is an Ethernet frame header.
- */
-
-struct ethhdr {
- unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
- unsigned char h_source[ETH_ALEN]; /* source ether addr */
- unsigned short h_proto; /* packet type ID field */
-};
-
-struct _vlan {
- unsigned short h_vlan_TCI; /* Encap prio and VLAN ID */
- unsigned short h_vlan_encapsulated_proto;
-};
-
-#define get_vlan_id(pvlan) \
- ((ntohs((unsigned short)pvlan->h_vlan_TCI)) & 0xfff)
-#define get_vlan_priority(pvlan) \
- ((ntohs((unsigned short)pvlan->h_vlan_TCI))>>13)
-#define get_vlan_encap_proto(pvlan) \
- (ntohs((unsigned short)pvlan->h_vlan_encapsulated_proto))
-
-#endif /* _LINUX_IF_ETHER_H */
diff --git a/drivers/staging/rtl8188eu/include/ioctl_cfg80211.h b/drivers/staging/rtl8188eu/include/ioctl_cfg80211.h
deleted file mode 100644
index 037e9a5e5af9..000000000000
--- a/drivers/staging/rtl8188eu/include/ioctl_cfg80211.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- * 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.
- *
- * 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, USA
- *
- *
- ******************************************************************************/
-#ifndef __IOCTL_CFG80211_H__
-#define __IOCTL_CFG80211_H__
-
-struct rtw_wdev_invit_info {
- u8 token;
- u8 flags;
- u8 status;
- u8 req_op_ch;
- u8 rsp_op_ch;
-};
-
-#define rtw_wdev_invit_info_init(invit_info) \
- do { \
- (invit_info)->token = 0; \
- (invit_info)->flags = 0x00; \
- (invit_info)->status = 0xff; \
- (invit_info)->req_op_ch = 0; \
- (invit_info)->rsp_op_ch = 0; \
- } while (0)
-
-struct rtw_wdev_priv {
- struct wireless_dev *rtw_wdev;
-
- struct adapter *padapter;
-
- struct cfg80211_scan_request *scan_request;
- spinlock_t scan_req_lock;
-
- struct net_device *pmon_ndev;/* for monitor interface */
- char ifname_mon[IFNAMSIZ + 1]; /* name of monitor interface */
-
- u8 p2p_enabled;
-
- u8 provdisc_req_issued;
-
- struct rtw_wdev_invit_info invit_info;
-
- u8 bandroid_scan;
- bool block;
- bool power_mgmt;
-};
-
-#define wdev_to_priv(w) ((struct rtw_wdev_priv *)(wdev_priv(w)))
-
-#define wiphy_to_wdev(x) \
-((struct wireless_dev *)(((struct rtw_wdev_priv *)wiphy_priv(x))->rtw_wdev))
-
-int rtw_wdev_alloc(struct adapter *padapter, struct device *dev);
-void rtw_wdev_free(struct wireless_dev *wdev);
-void rtw_wdev_unregister(struct wireless_dev *wdev);
-
-void rtw_cfg80211_init_wiphy(struct adapter *padapter);
-
-void rtw_cfg80211_surveydone_event_callback(struct adapter *padapter);
-
-void rtw_cfg80211_indicate_connect(struct adapter *padapter);
-void rtw_cfg80211_indicate_disconnect(struct adapter *padapter);
-void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv,
- bool aborted);
-
-#ifdef CONFIG_88EU_AP_MODE
-void rtw_cfg80211_indicate_sta_assoc(struct adapter *padapter,
- u8 *pmgmt_frame, uint frame_len);
-void rtw_cfg80211_indicate_sta_disassoc(struct adapter *padapter,
- unsigned char *da,
- unsigned short reason);
-#endif /* CONFIG_88EU_AP_MODE */
-
-void rtw_cfg80211_issue_p2p_provision_request(struct adapter *padapter,
- const u8 *buf, size_t len);
-void rtw_cfg80211_rx_p2p_action_public(struct adapter *padapter,
- u8 *pmgmt_frame, uint frame_len);
-void rtw_cfg80211_rx_action_p2p(struct adapter *padapter, u8 *pmgmt_frame,
- uint frame_len);
-void rtw_cfg80211_rx_action(struct adapter *adapter, u8 *frame,
- uint frame_len, const char *msg);
-
-int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net,
- char *buf, int len, int type);
-
-bool rtw_cfg80211_pwr_mgmt(struct adapter *adapter);
-
-#define rtw_cfg80211_rx_mgmt(dev, freq, sig_dbm, buf, len, gfp) \
- cfg80211_rx_mgmt(dev, freq, sig_dbm, buf, len, gfp)
-#define rtw_cfg80211_send_rx_assoc(dev, bss, buf, len) \
- cfg80211_send_rx_assoc(dev, bss, buf, len)
-
-#endif /* __IOCTL_CFG80211_H__ */
diff --git a/drivers/staging/rtl8188eu/include/ip.h b/drivers/staging/rtl8188eu/include/ip.h
deleted file mode 100644
index 9fdac6d42d17..000000000000
--- a/drivers/staging/rtl8188eu/include/ip.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- * 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.
- *
- * 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, USA
- *
- *
- ******************************************************************************/
-#ifndef _LINUX_IP_H
-#define _LINUX_IP_H
-
-/* SOL_IP socket options */
-
-#define IPTOS_TOS_MASK 0x1E
-#define IPTOS_TOS(tos) ((tos)&IPTOS_TOS_MASK)
-#define IPTOS_LOWDELAY 0x10
-#define IPTOS_THROUGHPUT 0x08
-#define IPTOS_RELIABILITY 0x04
-#define IPTOS_MINCOST 0x02
-
-#define IPTOS_PREC_MASK 0xE0
-#define IPTOS_PREC(tos) ((tos)&IPTOS_PREC_MASK)
-#define IPTOS_PREC_NETCONTROL 0xe0
-#define IPTOS_PREC_INTERNETCONTROL 0xc0
-#define IPTOS_PREC_CRITIC_ECP 0xa0
-#define IPTOS_PREC_FLASHOVERRIDE 0x80
-#define IPTOS_PREC_FLASH 0x60
-#define IPTOS_PREC_IMMEDIATE 0x40
-#define IPTOS_PREC_PRIORITY 0x20
-#define IPTOS_PREC_ROUTINE 0x00
-
-
-/* IP options */
-#define IPOPT_COPY 0x80
-#define IPOPT_CLASS_MASK 0x60
-#define IPOPT_NUMBER_MASK 0x1f
-
-#define IPOPT_COPIED(o) ((o)&IPOPT_COPY)
-#define IPOPT_CLASS(o) ((o)&IPOPT_CLASS_MASK)
-#define IPOPT_NUMBER(o) ((o)&IPOPT_NUMBER_MASK)
-
-#define IPOPT_CONTROL 0x00
-#define IPOPT_RESERVED1 0x20
-#define IPOPT_MEASUREMENT 0x40
-#define IPOPT_RESERVED2 0x60
-
-#define IPOPT_END (0 | IPOPT_CONTROL)
-#define IPOPT_NOOP (1 | IPOPT_CONTROL)
-#define IPOPT_SEC (2 | IPOPT_CONTROL | IPOPT_COPY)
-#define IPOPT_LSRR (3 | IPOPT_CONTROL | IPOPT_COPY)
-#define IPOPT_TIMESTAMP (4 | IPOPT_MEASUREMENT)
-#define IPOPT_RR (7 | IPOPT_CONTROL)
-#define IPOPT_SID (8 | IPOPT_CONTROL | IPOPT_COPY)
-#define IPOPT_SSRR (9 | IPOPT_CONTROL | IPOPT_COPY)
-#define IPOPT_RA (20 | IPOPT_CONTROL | IPOPT_COPY)
-
-#define IPVERSION 4
-#define MAXTTL 255
-#define IPDEFTTL 64
-#define IPOPT_OPTVAL 0
-#define IPOPT_OLEN 1
-#define IPOPT_OFFSET 2
-#define IPOPT_MINOFF 4
-#define MAX_IPOPTLEN 40
-#define IPOPT_NOP IPOPT_NOOP
-#define IPOPT_EOL IPOPT_END
-#define IPOPT_TS IPOPT_TIMESTAMP
-
-#define IPOPT_TS_TSONLY 0 /* timestamps only */
-#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
-#define IPOPT_TS_PRESPEC 3 /* specified modules only */
-
-struct ip_options {
- __u32 faddr; /* Saved first hop address */
- unsigned char optlen;
- unsigned char srr;
- unsigned char rr;
- unsigned char ts;
- unsigned char is_setbyuser:1, /* Set by setsockopt? */
- is_data:1, /* Options in __data, rather than skb*/
- is_strictroute:1,/* Strict source route */
- srr_is_hit:1, /* Packet destn addr was ours */
- is_changed:1, /* IP checksum more not valid */
- rr_needaddr:1, /* Need to record addr of out dev*/
- ts_needtime:1, /* Need to record timestamp */
- ts_needaddr:1; /* Need to record addr of out dev */
- unsigned char router_alert;
- unsigned char __pad1;
- unsigned char __pad2;
- unsigned char __data[0];
-};
-
-#define optlength(opt) (sizeof(struct ip_options) + opt->optlen)
-
-struct iphdr {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 ihl:4,
- version:4;
-#elif defined(__BIG_ENDIAN_BITFIELD)
- __u8 version:4,
- ihl:4;
-#endif
- __u8 tos;
- __u16 tot_len;
- __u16 id;
- __u16 frag_off;
- __u8 ttl;
- __u8 protocol;
- __u16 check;
- __u32 saddr;
- __u32 daddr;
- /*The options start here. */
-};
-
-#endif /* _LINUX_IP_H */
diff --git a/drivers/staging/rtl8188eu/include/nic_spec.h b/drivers/staging/rtl8188eu/include/nic_spec.h
deleted file mode 100644
index d42244788ca9..000000000000
--- a/drivers/staging/rtl8188eu/include/nic_spec.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- * 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.
- *
- * 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, USA
- *
- *
- ******************************************************************************/
-
-
-#ifndef __NIC_SPEC_H__
-#define __NIC_SPEC_H__
-
-#define RTL8711_MCTRL_ (0x20000)
-#define RTL8711_UART_ (0x30000)
-#define RTL8711_TIMER_ (0x40000)
-#define RTL8711_FINT_ (0x50000)
-#define RTL8711_HINT_ (0x50000)
-#define RTL8711_GPIO_ (0x60000)
-#define RTL8711_WLANCTRL_ (0x200000)
-#define RTL8711_WLANFF_ (0xe00000)
-#define RTL8711_HCICTRL_ (0x600000)
-#define RTL8711_SYSCFG_ (0x620000)
-#define RTL8711_SYSCTRL_ (0x620000)
-#define RTL8711_MCCTRL_ (0x020000)
-
-
-#include <rtl8711_regdef.h>
-
-#include <rtl8711_bitdef.h>
-
-
-#endif /* __RTL8711_SPEC_H__ */
diff --git a/drivers/staging/rtl8188eu/include/odm_interface.h b/drivers/staging/rtl8188eu/include/odm_interface.h
index a50eae3ec68e..548a309db199 100644
--- a/drivers/staging/rtl8188eu/include/odm_interface.h
+++ b/drivers/staging/rtl8188eu/include/odm_interface.h
@@ -77,32 +77,9 @@ typedef void (*RT_WORKITEM_CALL_BACK)(void *pContext);
/* =========== EXtern Function Prototype */
-u8 ODM_Read1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr);
-
-u16 ODM_Read2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr);
-
-u32 ODM_Read4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr);
-
-void ODM_Write1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u8 Data);
-
-void ODM_Write2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u16 Data);
-
-void ODM_Write4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 Data);
-
/* Memory Relative Function. */
-void ODM_AllocateMemory(struct odm_dm_struct *pDM_Odm, void **pPtr, u32 length);
-void ODM_FreeMemory(struct odm_dm_struct *pDM_Odm, void *pPtr, u32 length);
-
-s32 ODM_CompareMemory(struct odm_dm_struct *pDM_Odm, void *pBuf1, void *pBuf2,
- u32 length);
/* ODM Timer relative API. */
-void ODM_SetTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer,
- u32 msDelay);
-
-void ODM_InitializeTimer(struct odm_dm_struct *pDM_Odm,
- struct timer_list *pTimer, void *CallBackFunc,
- void *pContext, const char *szID);
void ODM_CancelTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer);
diff --git a/drivers/staging/rtl8188eu/include/osdep_service.h b/drivers/staging/rtl8188eu/include/osdep_service.h
index 7956f0cdb96b..5889f58ed7d3 100644
--- a/drivers/staging/rtl8188eu/include/osdep_service.h
+++ b/drivers/staging/rtl8188eu/include/osdep_service.h
@@ -62,20 +62,11 @@ struct __queue {
spinlock_t lock;
};
-static inline struct list_head *get_next(struct list_head *list)
-{
- return list->next;
-}
-
static inline struct list_head *get_list_head(struct __queue *queue)
{
return &(queue->queue);
}
-
-#define LIST_CONTAINOR(ptr, type, member) \
- ((type *)((char *)(ptr)-(size_t)(&((type *)0)->member)))
-
static inline int _enter_critical_mutex(struct mutex *pmutex,
unsigned long *pirqL)
{
@@ -85,13 +76,6 @@ static inline int _enter_critical_mutex(struct mutex *pmutex,
return ret;
}
-
-static inline void _exit_critical_mutex(struct mutex *pmutex,
- unsigned long *pirqL)
-{
- mutex_unlock(pmutex);
-}
-
static inline void rtw_list_delete(struct list_head *plist)
{
list_del_init(plist);
@@ -122,17 +106,6 @@ static inline void _cancel_timer(struct timer_list *ptimer, u8 *bcancelled)
#define RTW_DECLARE_TIMER_HDL(name) \
void RTW_TIMER_HDL_NAME(name)(RTW_TIMER_HDL_ARGS)
-static inline void _init_workitem(struct work_struct *pwork, void *pfunc,
- void *cntx)
-{
- INIT_WORK(pwork, pfunc);
-}
-
-static inline void _set_workitem(struct work_struct *pwork)
-{
- schedule_work(pwork);
-}
-
static inline void _cancel_workitem_sync(struct work_struct *pwork)
{
cancel_work_sync(pwork);
@@ -230,15 +203,9 @@ extern unsigned char WPA_TKIP_CIPHER[4];
extern unsigned char RSN_TKIP_CIPHER[4];
#define rtw_update_mem_stat(flag, sz) do {} while (0)
-u8 *_rtw_vmalloc(u32 sz);
-u8 *_rtw_zvmalloc(u32 sz);
-void _rtw_vmfree(u8 *pbuf, u32 sz);
u8 *_rtw_zmalloc(u32 sz);
u8 *_rtw_malloc(u32 sz);
void _rtw_mfree(u8 *pbuf, u32 sz);
-#define rtw_vmalloc(sz) _rtw_vmalloc((sz))
-#define rtw_zvmalloc(sz) _rtw_zvmalloc((sz))
-#define rtw_vmfree(pbuf, sz) _rtw_vmfree((pbuf), (sz))
#define rtw_malloc(sz) _rtw_malloc((sz))
#define rtw_zmalloc(sz) _rtw_zmalloc((sz))
#define rtw_mfree(pbuf, sz) _rtw_mfree((pbuf), (sz))
@@ -247,7 +214,6 @@ void *rtw_malloc2d(int h, int w, int size);
void rtw_mfree2d(void *pbuf, int h, int w, int size);
void _rtw_memcpy(void *dec, void *sour, u32 sz);
-int _rtw_memcmp(void *dst, void *src, u32 sz);
void _rtw_memset(void *pbuf, int c, u32 sz);
void _rtw_init_listhead(struct list_head *list);
diff --git a/drivers/staging/rtl8188eu/include/recv_osdep.h b/drivers/staging/rtl8188eu/include/recv_osdep.h
index 691238078075..d76cc2db5028 100644
--- a/drivers/staging/rtl8188eu/include/recv_osdep.h
+++ b/drivers/staging/rtl8188eu/include/recv_osdep.h
@@ -28,18 +28,20 @@ int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter);
void _rtw_free_recv_priv(struct recv_priv *precvpriv);
-s32 rtw_recv_entry(union recv_frame *precv_frame);
-int rtw_recv_indicatepkt(struct adapter *adapter, union recv_frame *recv_frame);
+s32 rtw_recv_entry(struct recv_frame *precv_frame);
+int rtw_recv_indicatepkt(struct adapter *adapter,
+ struct recv_frame *recv_frame);
void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *retpkt);
-void rtw_hostapd_mlme_rx(struct adapter *padapter, union recv_frame *recv_fr);
+void rtw_hostapd_mlme_rx(struct adapter *padapter, struct recv_frame *recv_fr);
void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup);
int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter);
void rtw_free_recv_priv(struct recv_priv *precvpriv);
int rtw_os_recv_resource_init(struct recv_priv *recvpr, struct adapter *adapt);
-int rtw_os_recv_resource_alloc(struct adapter *adapt, union recv_frame *recvfr);
+int rtw_os_recv_resource_alloc(struct adapter *adapt,
+ struct recv_frame *recvfr);
void rtw_os_recv_resource_free(struct recv_priv *precvpriv);
int rtw_os_recvbuf_resource_alloc(struct adapter *adapt, struct recv_buf *buf);
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
index 161f1e5af9e6..75e41c4aeb27 100644
--- a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
@@ -76,17 +76,6 @@
(le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x2300 || \
(le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88E0)
-enum firmware_source {
- FW_SOURCE_IMG_FILE = 0,
- FW_SOURCE_HEADER_FILE = 1, /* from header file */
-};
-
-struct rt_firmware {
- enum firmware_source eFWSource;
- u8 *szFwBuffer;
- u32 ulFwLength;
-};
-
/* This structure must be careful with byte-ordering */
struct rt_firmware_hdr {
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_recv.h b/drivers/staging/rtl8188eu/include/rtl8188e_recv.h
index a8facf00eac0..07e5f5227336 100644
--- a/drivers/staging/rtl8188eu/include/rtl8188e_recv.h
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_recv.h
@@ -61,9 +61,10 @@ s32 rtl8188eu_init_recv_priv(struct adapter *padapter);
void rtl8188eu_free_recv_priv(struct adapter *padapter);
void rtl8188eu_recv_hdl(struct adapter *padapter, struct recv_buf *precvbuf);
void rtl8188eu_recv_tasklet(void *priv);
-void rtl8188e_query_rx_phy_status(union recv_frame *fr, struct phy_stat *phy);
+void rtl8188e_query_rx_phy_status(struct recv_frame *fr, struct phy_stat *phy);
void rtl8188e_process_phy_info(struct adapter *padapter, void *prframe);
-void update_recvframe_phyinfo_88e(union recv_frame *fra, struct phy_stat *phy);
-void update_recvframe_attrib_88e(union recv_frame *fra, struct recv_stat *stat);
+void update_recvframe_phyinfo_88e(struct recv_frame *fra, struct phy_stat *phy);
+void update_recvframe_attrib_88e(struct recv_frame *fra,
+ struct recv_stat *stat);
#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_debug.h b/drivers/staging/rtl8188eu/include/rtw_debug.h
index c6b193a2e795..ae05141f5ddf 100644
--- a/drivers/staging/rtl8188eu/include/rtw_debug.h
+++ b/drivers/staging/rtl8188eu/include/rtw_debug.h
@@ -99,20 +99,6 @@ extern u32 GlobalDebugLevel;
} \
} while (0)
-#define _func_enter_ \
- do { \
- if (GlobalDebugLevel >= _drv_debug_) \
- pr_info("%s : %s enters at %d\n", \
- DRIVER_PREFIX, __func__, __LINE__); \
- } while (0)
-
-#define _func_exit_ \
- do { \
- if (GlobalDebugLevel >= _drv_debug_) \
- pr_info("%s : %s exits at %d\n", \
- DRIVER_PREFIX, __func__, __LINE__); \
- } while (0)
-
#define RT_PRINT_DATA(_comp, _level, _titlestring, _hexdata, _hexdatalen)\
do { \
if (_level <= GlobalDebugLevel) { \
@@ -277,14 +263,4 @@ int proc_get_rssi_disp(char *page, char **start,
int proc_set_rssi_disp(struct file *file, const char __user *buffer,
unsigned long count, void *data);
-#ifdef CONFIG_BT_COEXIST
-int proc_get_btcoex_dbg(char *page, char **start,
- off_t offset, int count,
- int *eof, void *data);
-
-int proc_set_btcoex_dbg(struct file *file, const char *buffer,
- signed long count, void *data);
-
-#endif /* CONFIG_BT_COEXIST */
-
#endif /* __RTW_DEBUG_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_io.h b/drivers/staging/rtl8188eu/include/rtw_io.h
index 3d1dfcc1b603..e8790f8f913e 100644
--- a/drivers/staging/rtl8188eu/include/rtw_io.h
+++ b/drivers/staging/rtl8188eu/include/rtw_io.h
@@ -99,7 +99,6 @@
struct intf_priv;
struct intf_hdl;
-struct io_queue;
struct _io_ops {
u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr);
@@ -117,7 +116,6 @@ struct _io_ops {
u8 *pmem);
void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
u8 *pmem);
- void (*_sync_irp_protocol_rw)(struct io_queue *pio_q);
u32 (*_read_interrupt)(struct intf_hdl *pintfhdl, u32 addr);
u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
u8 *pmem);
@@ -237,34 +235,11 @@ struct reg_protocol_wt {
Below is the data structure used by _io_handler
*/
-struct io_queue {
- spinlock_t lock;
- struct list_head free_ioreqs;
- struct list_head pending; /* The io_req list that will be served
- * in the single protocol read/write.*/
- struct list_head processing;
- u8 *free_ioreqs_buf; /* 4-byte aligned */
- u8 *pallocated_free_ioreqs_buf;
- struct intf_hdl intf;
-};
-
struct io_priv {
struct adapter *padapter;
struct intf_hdl intf;
};
-uint ioreq_flush(struct adapter *adapter, struct io_queue *ioqueue);
-void sync_ioreq_enqueue(struct io_req *preq, struct io_queue *ioqueue);
-uint sync_ioreq_flush(struct adapter *adapter, struct io_queue *ioqueue);
-uint free_ioreq(struct io_req *preq, struct io_queue *pio_queue);
-struct io_req *alloc_ioreq(struct io_queue *pio_q);
-
-uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl);
-void unregister_intf_hdl(struct intf_hdl *pintfhdl);
-
-void _rtw_attrib_read(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
-void _rtw_attrib_write(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
-
u8 _rtw_read8(struct adapter *adapter, u32 addr);
u16 _rtw_read16(struct adapter *adapter, u32 addr);
u32 _rtw_read32(struct adapter *adapter, u32 addr);
@@ -363,25 +338,6 @@ void async_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
int rtw_init_io_priv(struct adapter *padapter,
void (*set_intf_ops)(struct _io_ops *pops));
-uint alloc_io_queue(struct adapter *adapter);
-void free_io_queue(struct adapter *adapter);
-void async_bus_io(struct io_queue *pio_q);
-void bus_sync_io(struct io_queue *pio_q);
-u32 _ioreq2rwmem(struct io_queue *pio_q);
void dev_power_down(struct adapter *Adapter, u8 bpwrup);
-#define PlatformEFIOWrite1Byte(_a, _b, _c) \
- rtw_write8(_a, _b, _c)
-#define PlatformEFIOWrite2Byte(_a, _b, _c) \
- rtw_write16(_a, _b, _c)
-#define PlatformEFIOWrite4Byte(_a, _b, _c) \
- rtw_write32(_a, _b, _c)
-
-#define PlatformEFIORead1Byte(_a, _b) \
- rtw_read8(_a, _b)
-#define PlatformEFIORead2Byte(_a, _b) \
- rtw_read16(_a, _b)
-#define PlatformEFIORead4Byte(_a, _b) \
- rtw_read32(_a, _b)
-
#endif /* _RTL8711_IO_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_ioctl.h b/drivers/staging/rtl8188eu/include/rtw_ioctl.h
index 8772d1d178c6..f3aa924f2029 100644
--- a/drivers/staging/rtl8188eu/include/rtw_ioctl.h
+++ b/drivers/staging/rtl8188eu/include/rtw_ioctl.h
@@ -102,8 +102,6 @@ struct oid_obj_priv {
#if defined(_RTW_MP_IOCTL_C_)
static int oid_null_function(struct oid_par_priv *poid_par_priv) {
- _func_enter_;
- _func_exit_;
return NDIS_STATUS_SUCCESS;
}
#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme.h b/drivers/staging/rtl8188eu/include/rtw_mlme.h
index 6cd988f867da..45c22efe93fe 100644
--- a/drivers/staging/rtl8188eu/include/rtw_mlme.h
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme.h
@@ -106,13 +106,6 @@ SHALL not lock up more than one lock at a time!
#define traffic_threshold 10
#define traffic_scan_period 500
-struct sitesurvey_ctrl {
- u64 last_tx_pkts;
- uint last_rx_pkts;
- int traffic_busy;
- struct timer_list sitesurvey_ctrl_timer;
-};
-
struct rt_link_detect {
u32 NumTxOkInPeriod;
u32 NumRxOkInPeriod;
@@ -304,31 +297,6 @@ struct wifidirect_info {
u32 noa_start_time[P2P_MAX_NOA_NUM];
};
-struct tdls_ss_record { /* signal strength record */
- u8 macaddr[ETH_ALEN];
- u8 RxPWDBAll;
- u8 is_tdls_sta; /* true: direct link sta, false: else */
-};
-
-struct tdls_info {
- u8 ap_prohibited;
- uint setup_state;
- u8 sta_cnt;
- u8 sta_maximum; /* 1:tdls sta is equal (NUM_STA-1), reach max direct link number; 0: else; */
- struct tdls_ss_record ss_record;
- u8 macid_index; /* macid entry that is ready to write */
- u8 clear_cam; /* cam entry that is trying to clear, using it in direct link teardown */
- u8 ch_sensing;
- u8 cur_channel;
- u8 candidate_ch;
- u8 collect_pkt_num[MAX_CHANNEL_NUM];
- spinlock_t cmd_lock;
- spinlock_t hdl_lock;
- u8 watchdog_count;
- u8 dev_discovered; /* WFD_TDLS: for sigma test */
- u8 enable;
-};
-
struct mlme_priv {
spinlock_t lock;
int fw_state; /* shall we protect this variable? maybe not necessarily... */
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
index f0c982d6d5f2..09e2a3980ea7 100644
--- a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
@@ -236,13 +236,13 @@ enum SCAN_STATE {
struct mlme_handler {
unsigned int num;
char *str;
- unsigned int (*func)(struct adapter *adapt, union recv_frame *frame);
+ unsigned int (*func)(struct adapter *adapt, struct recv_frame *frame);
};
struct action_handler {
unsigned int num;
char *str;
- unsigned int (*func)(struct adapter *adapt, union recv_frame *frame);
+ unsigned int (*func)(struct adapter *adapt, struct recv_frame *frame);
};
struct ss_res {
@@ -490,7 +490,7 @@ int allocate_fw_sta_entry(struct adapter *padapter);
void flush_all_cam_entry(struct adapter *padapter);
void site_survey(struct adapter *padapter);
-u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame,
+u8 collect_bss_info(struct adapter *padapter, struct recv_frame *precv_frame,
struct wlan_bssid_ex *bssid);
void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src,
struct adapter *adapter, bool update_ie);
@@ -544,7 +544,8 @@ unsigned int is_ap_in_wep(struct adapter *padapter);
unsigned int should_forbid_n_rate(struct adapter *padapter);
void report_join_res(struct adapter *padapter, int res);
-void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame);
+void report_survey_event(struct adapter *padapter,
+ struct recv_frame *precv_frame);
void report_surveydone_event(struct adapter *padapter);
void report_del_sta_event(struct adapter *padapter,
unsigned char *addr, unsigned short reason);
@@ -609,46 +610,46 @@ void start_clnt_join(struct adapter *padapter);
void start_create_ibss(struct adapter *padapter);
unsigned int OnAssocReq(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnAssocRsp(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnProbeReq(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnProbeRsp(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int DoReserved(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnBeacon(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnAtim(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnDisassoc(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnAuth(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnAuthClient(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnDeAuth(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnAction(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int on_action_spct(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnAction_qos(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnAction_dls(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnAction_back(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int on_action_public(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnAction_ht(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnAction_wmm(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
unsigned int OnAction_p2p(struct adapter *padapter,
- union recv_frame *precv_frame);
+ struct recv_frame *precv_frame);
void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res);
void mlmeext_sta_del_event_callback(struct adapter *padapter);
diff --git a/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h b/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h
index 4a0e9ff3d479..9a42859d612b 100644
--- a/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h
+++ b/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h
@@ -206,10 +206,6 @@ struct pwrctrl_priv {
u8 bInternalAutoSuspend;
u8 bInSuspend;
-#ifdef CONFIG_BT_COEXIST
- u8 bAutoResume;
- u8 autopm_cnt;
-#endif
u8 bSupportRemoteWakeup;
struct timer_list pwr_state_check_timer;
int pwr_state_check_interval;
diff --git a/drivers/staging/rtl8188eu/include/rtw_recv.h b/drivers/staging/rtl8188eu/include/rtw_recv.h
index be9c30c57419..bcbce46cec85 100644
--- a/drivers/staging/rtl8188eu/include/rtw_recv.h
+++ b/drivers/staging/rtl8188eu/include/rtw_recv.h
@@ -270,7 +270,7 @@ struct recv_buf {
len = (unsigned int )(tail - data);
*/
-struct recv_frame_hdr {
+struct recv_frame {
struct list_head list;
struct sk_buff *pkt;
struct sk_buff *pkt_newalloc;
@@ -289,23 +289,16 @@ struct recv_frame_hdr {
struct recv_reorder_ctrl *preorder_ctrl;
};
-union recv_frame {
- union {
- struct list_head list;
- struct recv_frame_hdr hdr;
- uint mem[RECVFRAME_HDR_ALIGN>>2];
- } u;
-};
-
-union recv_frame *_rtw_alloc_recvframe(struct __queue *pfree_recv_queue);
-union recv_frame *rtw_alloc_recvframe(struct __queue *pfree_recv_queue);
-void rtw_init_recvframe(union recv_frame *precvframe,
+struct recv_frame *_rtw_alloc_recvframe(struct __queue *pfree_recv_queue);
+struct recv_frame *rtw_alloc_recvframe(struct __queue *pfree_recv_queue);
+void rtw_init_recvframe(struct recv_frame *precvframe,
struct recv_priv *precvpriv);
-int rtw_free_recvframe(union recv_frame *precvframe,
+int rtw_free_recvframe(struct recv_frame *precvframe,
struct __queue *pfree_recv_queue);
#define rtw_dequeue_recvframe(queue) rtw_alloc_recvframe(queue)
-int _rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue);
-int rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue);
+int _rtw_enqueue_recvframe(struct recv_frame *precvframe,
+ struct __queue *queue);
+int rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue);
void rtw_free_recvframe_queue(struct __queue *pframequeue,
struct __queue *pfree_recv_queue);
u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter);
@@ -315,29 +308,20 @@ struct recv_buf *rtw_dequeue_recvbuf(struct __queue *queue);
void rtw_reordering_ctrl_timeout_handler(void *pcontext);
-static inline u8 *get_rxmem(union recv_frame *precvframe)
+static inline u8 *get_rxmem(struct recv_frame *precvframe)
{
/* always return rx_head... */
if (precvframe == NULL)
return NULL;
- return precvframe->u.hdr.rx_head;
+ return precvframe->rx_head;
}
-static inline u8 *get_rx_status(union recv_frame *precvframe)
+static inline u8 *get_rx_status(struct recv_frame *precvframe)
{
return get_rxmem(precvframe);
}
-static inline u8 *get_recvframe_data(union recv_frame *precvframe)
-{
- /* always return rx_data */
- if (precvframe == NULL)
- return NULL;
-
- return precvframe->u.hdr.rx_data;
-}
-
-static inline u8 *recvframe_push(union recv_frame *precvframe, int sz)
+static inline u8 *recvframe_push(struct recv_frame *precvframe, int sz)
{
/* append data before rx_data */
@@ -348,16 +332,16 @@ static inline u8 *recvframe_push(union recv_frame *precvframe, int sz)
*/
if (precvframe == NULL)
return NULL;
- precvframe->u.hdr.rx_data -= sz ;
- if (precvframe->u.hdr.rx_data < precvframe->u.hdr.rx_head) {
- precvframe->u.hdr.rx_data += sz;
+ precvframe->rx_data -= sz;
+ if (precvframe->rx_data < precvframe->rx_head) {
+ precvframe->rx_data += sz;
return NULL;
}
- precvframe->u.hdr.len += sz;
- return precvframe->u.hdr.rx_data;
+ precvframe->len += sz;
+ return precvframe->rx_data;
}
-static inline u8 *recvframe_pull(union recv_frame *precvframe, int sz)
+static inline u8 *recvframe_pull(struct recv_frame *precvframe, int sz)
{
/* rx_data += sz; move rx_data sz bytes hereafter */
@@ -366,16 +350,16 @@ static inline u8 *recvframe_pull(union recv_frame *precvframe, int sz)
if (precvframe == NULL)
return NULL;
- precvframe->u.hdr.rx_data += sz;
- if (precvframe->u.hdr.rx_data > precvframe->u.hdr.rx_tail) {
- precvframe->u.hdr.rx_data -= sz;
+ precvframe->rx_data += sz;
+ if (precvframe->rx_data > precvframe->rx_tail) {
+ precvframe->rx_data -= sz;
return NULL;
}
- precvframe->u.hdr.len -= sz;
- return precvframe->u.hdr.rx_data;
+ precvframe->len -= sz;
+ return precvframe->rx_data;
}
-static inline u8 *recvframe_put(union recv_frame *precvframe, int sz)
+static inline u8 *recvframe_put(struct recv_frame *precvframe, int sz)
{
/* used for append sz bytes from ptr to rx_tail, update rx_tail
* and return the updated rx_tail to the caller */
@@ -384,17 +368,17 @@ static inline u8 *recvframe_put(union recv_frame *precvframe, int sz)
if (precvframe == NULL)
return NULL;
- precvframe->u.hdr.rx_tail += sz;
+ precvframe->rx_tail += sz;
- if (precvframe->u.hdr.rx_tail > precvframe->u.hdr.rx_end) {
- precvframe->u.hdr.rx_tail -= sz;
+ if (precvframe->rx_tail > precvframe->rx_end) {
+ precvframe->rx_tail -= sz;
return NULL;
}
- precvframe->u.hdr.len += sz;
- return precvframe->u.hdr.rx_tail;
+ precvframe->len += sz;
+ return precvframe->rx_tail;
}
-static inline u8 *recvframe_pull_tail(union recv_frame *precvframe, int sz)
+static inline u8 *recvframe_pull_tail(struct recv_frame *precvframe, int sz)
{
/* rmv data from rx_tail (by yitsen) */
@@ -404,64 +388,13 @@ static inline u8 *recvframe_pull_tail(union recv_frame *precvframe, int sz)
if (precvframe == NULL)
return NULL;
- precvframe->u.hdr.rx_tail -= sz;
- if (precvframe->u.hdr.rx_tail < precvframe->u.hdr.rx_data) {
- precvframe->u.hdr.rx_tail += sz;
+ precvframe->rx_tail -= sz;
+ if (precvframe->rx_tail < precvframe->rx_data) {
+ precvframe->rx_tail += sz;
return NULL;
}
- precvframe->u.hdr.len -= sz;
- return precvframe->u.hdr.rx_tail;
-}
-
-static inline unsigned char *get_rxbuf_desc(union recv_frame *precvframe)
-{
- unsigned char *buf_desc;
-
- if (precvframe == NULL)
- return NULL;
- return buf_desc;
-}
-
-static inline union recv_frame *rxmem_to_recvframe(u8 *rxmem)
-{
- /* due to the design of 2048 bytes alignment of recv_frame,
- * we can reference the union recv_frame */
- /* from any given member of recv_frame. */
- /* rxmem indicates the any member/address in recv_frame */
-
- return (union recv_frame *)(((size_t)rxmem >> RXFRAME_ALIGN) << RXFRAME_ALIGN);
-}
-
-static inline union recv_frame *pkt_to_recvframe(struct sk_buff *pkt)
-{
- u8 *buf_star;
- union recv_frame *precv_frame;
- precv_frame = rxmem_to_recvframe((unsigned char *)buf_star);
-
- return precv_frame;
-}
-
-static inline u8 *pkt_to_recvmem(struct sk_buff *pkt)
-{
- /* return the rx_head */
-
- union recv_frame *precv_frame = pkt_to_recvframe(pkt);
-
- return precv_frame->u.hdr.rx_head;
-}
-
-static inline u8 *pkt_to_recvdata(struct sk_buff *pkt)
-{
- /* return the rx_data */
-
- union recv_frame *precv_frame = pkt_to_recvframe(pkt);
-
- return precv_frame->u.hdr.rx_data;
-}
-
-static inline int get_recvframe_len(union recv_frame *precvframe)
-{
- return precvframe->u.hdr.len;
+ precvframe->len -= sz;
+ return precvframe->rx_tail;
}
static inline s32 translate_percentage_to_dbm(u32 sig_stren_index)
@@ -480,6 +413,6 @@ struct sta_info;
void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv);
-void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame);
+void mgt_dispatcher(struct adapter *padapter, struct recv_frame *precv_frame);
#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_xmit.h b/drivers/staging/rtl8188eu/include/rtw_xmit.h
index 1ac1dd31db68..62f5db169523 100644
--- a/drivers/staging/rtl8188eu/include/rtw_xmit.h
+++ b/drivers/staging/rtl8188eu/include/rtw_xmit.h
@@ -105,11 +105,6 @@ struct tx_desc {
__le32 txdw7;
};
-union txdesc {
- struct tx_desc txdesc;
- unsigned int value[TXDESC_SIZE>>2];
-};
-
struct hw_xmit {
struct __queue *sta_queue;
int accnt;
diff --git a/drivers/staging/rtl8188eu/include/wifi.h b/drivers/staging/rtl8188eu/include/wifi.h
index 2e7307f259b6..a88ebf41bba1 100644
--- a/drivers/staging/rtl8188eu/include/wifi.h
+++ b/drivers/staging/rtl8188eu/include/wifi.h
@@ -694,7 +694,7 @@ struct WMM_para_element {
struct ADDBA_request {
unsigned char dialog_token;
- unsigned short BA_para_set;
+ __le16 BA_para_set;
unsigned short BA_timeout_value;
unsigned short BA_starting_seqctrl;
} __packed;
diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
index 4ad80ae1067f..2636e7f3dbb8 100644
--- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
@@ -35,6 +35,7 @@
#include <rtw_mp.h>
#include <rtw_iol.h>
+#include <linux/vmalloc.h>
#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV + 30)
@@ -472,8 +473,6 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
#endif /* CONFIG_88EU_P2P */
-_func_enter_;
-
param->u.crypt.err = 0;
param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
@@ -614,9 +613,6 @@ _func_enter_;
exit:
kfree(pwep);
-
-_func_exit_;
-
return ret;
}
@@ -770,8 +766,6 @@ static int rtw_wx_get_name(struct net_device *dev,
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("cmd_code =%x\n", info->cmd));
- _func_enter_;
-
if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) {
/* parsing HT_CAP_IE */
p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength-12);
@@ -806,9 +800,6 @@ static int rtw_wx_get_name(struct net_device *dev,
} else {
snprintf(wrqu->name, IFNAMSIZ, "unassociated");
}
-
- _func_exit_;
-
return 0;
}
@@ -816,12 +807,7 @@ static int rtw_wx_set_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- _func_enter_;
-
RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_wx_set_freq\n"));
-
- _func_exit_;
-
return 0;
}
@@ -854,8 +840,6 @@ static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
enum ndis_802_11_network_infra networkType;
int ret = 0;
- _func_enter_;
-
if (_FAIL == rtw_pwr_wakeup(padapter)) {
ret = -EPERM;
goto exit;
@@ -894,7 +878,6 @@ static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
}
rtw_setopmode_cmd(padapter, networkType);
exit:
- _func_exit_;
return ret;
}
@@ -906,8 +889,6 @@ static int rtw_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, (" rtw_wx_get_mode\n"));
- _func_enter_;
-
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
wrqu->mode = IW_MODE_INFRA;
else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ||
@@ -918,8 +899,6 @@ static int rtw_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
else
wrqu->mode = IW_MODE_AUTO;
- _func_exit_;
-
return 0;
}
@@ -1011,8 +990,6 @@ static int rtw_wx_get_range(struct net_device *dev,
u16 val;
int i;
- _func_enter_;
-
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_range. cmd_code =%x\n", info->cmd));
wrqu->data.length = sizeof(*range);
@@ -1093,8 +1070,6 @@ static int rtw_wx_get_range(struct net_device *dev,
range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE |
IW_SCAN_CAPA_BSSID | IW_SCAN_CAPA_CHANNEL |
IW_SCAN_CAPA_MODE | IW_SCAN_CAPA_RATE;
- _func_exit_;
-
return 0;
}
@@ -1118,8 +1093,6 @@ static int rtw_wx_set_wap(struct net_device *dev,
struct wlan_network *pnetwork = NULL;
enum ndis_802_11_auth_mode authmode;
- _func_enter_;
-
if (_FAIL == rtw_pwr_wakeup(padapter)) {
ret = -1;
goto exit;
@@ -1138,15 +1111,15 @@ static int rtw_wx_set_wap(struct net_device *dev,
authmode = padapter->securitypriv.ndisauthtype;
spin_lock_bh(&queue->lock);
phead = get_list_head(queue);
- pmlmepriv->pscanned = get_next(phead);
+ pmlmepriv->pscanned = phead->next;
while (1) {
if ((rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) == true)
break;
- pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);
+ pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list);
- pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+ pmlmepriv->pscanned = pmlmepriv->pscanned->next;
dst_bssid = pnetwork->network.MacAddress;
@@ -1173,8 +1146,6 @@ static int rtw_wx_set_wap(struct net_device *dev,
exit:
- _func_exit_;
-
return ret;
}
@@ -1192,17 +1163,12 @@ static int rtw_wx_get_wap(struct net_device *dev,
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_wap\n"));
- _func_enter_;
-
if (((check_fwstate(pmlmepriv, _FW_LINKED)) == true) ||
((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) ||
((check_fwstate(pmlmepriv, WIFI_AP_STATE)) == true))
memcpy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress, ETH_ALEN);
else
_rtw_memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
-
- _func_exit_;
-
return 0;
}
@@ -1252,7 +1218,6 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
#endif /* CONFIG_88EU_P2P */
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_set_scan\n"));
-_func_enter_;
if (padapter->registrypriv.mp_mode == 1) {
if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
ret = -1;
@@ -1383,7 +1348,6 @@ _func_enter_;
exit:
-_func_exit_;
return ret;
}
@@ -1407,8 +1371,6 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan\n"));
RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, (" Start of Query SIOCGIWSCAN .\n"));
- _func_enter_;
-
if (padapter->pwrctrlpriv.brfoffbyhw && padapter->bDriverStopped) {
ret = -EINVAL;
goto exit;
@@ -1440,7 +1402,7 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
while (1) {
if (rtw_end_of_queue_search(phead, plist))
@@ -1451,13 +1413,13 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
break;
}
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pnetwork = container_of(plist, struct wlan_network, list);
/* report network only if the current channel set contains the channel to which this network belongs */
if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0)
ev = translate_scan(padapter, a, pnetwork, ev, stop);
- plist = get_next(plist);
+ plist = plist->next;
}
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
@@ -1466,7 +1428,6 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
wrqu->data.flags = 0;
exit:
- _func_exit_;
return ret;
}
@@ -1490,7 +1451,6 @@ static int rtw_wx_set_essid(struct net_device *dev,
uint ret = 0, len;
- _func_enter_;
RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
("+rtw_wx_set_essid: fw_state = 0x%08x\n", get_fwstate(pmlmepriv)));
@@ -1530,7 +1490,7 @@ static int rtw_wx_set_essid(struct net_device *dev,
RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("rtw_wx_set_essid: ssid =[%s]\n", src_ssid));
spin_lock_bh(&queue->lock);
phead = get_list_head(queue);
- pmlmepriv->pscanned = get_next(phead);
+ pmlmepriv->pscanned = phead->next;
while (1) {
if (rtw_end_of_queue_search(phead, pmlmepriv->pscanned) == true) {
@@ -1540,9 +1500,9 @@ static int rtw_wx_set_essid(struct net_device *dev,
break;
}
- pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);
+ pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list);
- pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+ pmlmepriv->pscanned = pmlmepriv->pscanned->next;
dst_ssid = pnetwork->network.Ssid.Ssid;
@@ -1583,7 +1543,6 @@ exit:
DBG_88E("<=%s, ret %d\n", __func__, ret);
- _func_exit_;
return ret;
}
@@ -1599,7 +1558,6 @@ static int rtw_wx_get_essid(struct net_device *dev,
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_essid\n"));
- _func_enter_;
if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) {
@@ -1617,7 +1575,6 @@ static int rtw_wx_get_essid(struct net_device *dev,
exit:
- _func_exit_;
return ret;
}
@@ -1634,7 +1591,6 @@ static int rtw_wx_set_rate(struct net_device *dev,
u32 ratevalue = 0;
u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
-_func_enter_;
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, (" rtw_wx_set_rate\n"));
RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("target_rate = %d, fixed = %d\n", target_rate, fixed));
@@ -1706,7 +1662,6 @@ set_rate:
ret = -1;
}
-_func_exit_;
return ret;
}
@@ -1734,7 +1689,6 @@ static int rtw_wx_set_rts(struct net_device *dev,
{
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- _func_enter_;
if (wrqu->rts.disabled) {
padapter->registrypriv.rts_thresh = 2347;
@@ -1748,7 +1702,6 @@ static int rtw_wx_set_rts(struct net_device *dev,
DBG_88E("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh);
- _func_exit_;
return 0;
}
@@ -1759,7 +1712,6 @@ static int rtw_wx_get_rts(struct net_device *dev,
{
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- _func_enter_;
DBG_88E("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh);
@@ -1767,7 +1719,6 @@ static int rtw_wx_get_rts(struct net_device *dev,
wrqu->rts.fixed = 0; /* no auto select */
/* wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); */
- _func_exit_;
return 0;
}
@@ -1778,7 +1729,6 @@ static int rtw_wx_set_frag(struct net_device *dev,
{
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- _func_enter_;
if (wrqu->frag.disabled) {
padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD;
@@ -1792,7 +1742,6 @@ static int rtw_wx_set_frag(struct net_device *dev,
DBG_88E("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len);
- _func_exit_;
return 0;
}
@@ -1803,14 +1752,12 @@ static int rtw_wx_get_frag(struct net_device *dev,
{
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- _func_enter_;
DBG_88E("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len);
wrqu->frag.value = padapter->xmitpriv.frag_len;
wrqu->frag.fixed = 0; /* no auto select */
- _func_exit_;
return 0;
}
@@ -1844,7 +1791,6 @@ static int rtw_wx_set_enc(struct net_device *dev,
key = erq->flags & IW_ENCODE_INDEX;
- _func_enter_;
if (erq->flags & IW_ENCODE_DISABLED) {
DBG_88E("EncryptionDisabled\n");
@@ -1939,7 +1885,6 @@ static int rtw_wx_set_enc(struct net_device *dev,
exit:
- _func_exit_;
return ret;
}
@@ -1953,7 +1898,6 @@ static int rtw_wx_get_enc(struct net_device *dev,
struct iw_point *erq = &(wrqu->encoding);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- _func_enter_;
if (check_fwstate(pmlmepriv, _FW_LINKED) != true) {
if (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
@@ -2007,7 +1951,6 @@ static int rtw_wx_get_enc(struct net_device *dev,
erq->flags |= IW_ENCODE_DISABLED;
break;
}
- _func_exit_;
return ret;
}
@@ -2210,6 +2153,7 @@ static int rtw_wx_read32(struct net_device *dev,
u32 data32;
u32 bytes;
u8 *ptmp;
+ int rv;
padapter = (struct adapter *)rtw_netdev_priv(dev);
p = &wrqu->data;
@@ -2225,7 +2169,11 @@ static int rtw_wx_read32(struct net_device *dev,
bytes = 0;
addr = 0;
- sscanf(ptmp, "%d,%x", &bytes, &addr);
+ rv = sscanf(ptmp, "%d,%x", &bytes, &addr);
+ if (rv != 2) {
+ kfree(ptmp);
+ return -EINVAL;
+ }
switch (bytes) {
case 1:
@@ -2255,6 +2203,7 @@ static int rtw_wx_write32(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int rv;
u32 addr;
u32 data32;
@@ -2263,7 +2212,9 @@ static int rtw_wx_write32(struct net_device *dev,
bytes = 0;
addr = 0;
data32 = 0;
- sscanf(extra, "%d,%x,%x", &bytes, &addr, &data32);
+ rv = sscanf(extra, "%d,%x,%x", &bytes, &addr, &data32);
+ if (rv != 3)
+ return -EINVAL;
switch (bytes) {
case 1:
@@ -2607,13 +2558,13 @@ static int rtw_get_ap_info(struct net_device *dev,
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
while (1) {
if (rtw_end_of_queue_search(phead, plist) == true)
break;
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pnetwork = container_of(plist, struct wlan_network, list);
if (hwaddr_aton_i(data, bssid)) {
DBG_88E("Invalid BSSID '%s'.\n", (u8 *)data);
@@ -2638,7 +2589,7 @@ static int rtw_get_ap_info(struct net_device *dev,
}
}
- plist = get_next(plist);
+ plist = plist->next;
}
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
@@ -2690,13 +2641,13 @@ static int rtw_wps_start(struct net_device *dev,
struct iw_point *pdata = &wrqu->data;
u32 u32wps_start = 0;
- ret = copy_from_user((void *)&u32wps_start, pdata->pointer, 4);
- if (ret) {
+ if ((padapter->bDriverStopped) || (pdata == NULL)) {
ret = -EINVAL;
goto exit;
}
- if ((padapter->bDriverStopped) || (pdata == NULL)) {
+ ret = copy_from_user((void *)&u32wps_start, pdata->pointer, 4);
+ if (ret) {
ret = -EINVAL;
goto exit;
}
@@ -3110,13 +3061,13 @@ static int rtw_p2p_get_wps_configmethod(struct net_device *dev,
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
while (1) {
if (rtw_end_of_queue_search(phead, plist) == true)
break;
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pnetwork = container_of(plist, struct wlan_network, list);
if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
u8 *wpsie;
uint wpsie_len = 0;
@@ -3134,7 +3085,7 @@ static int rtw_p2p_get_wps_configmethod(struct net_device *dev,
}
break;
}
- plist = get_next(plist);
+ plist = plist->next;
}
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
@@ -3180,13 +3131,13 @@ static int rtw_p2p_get_go_device_address(struct net_device *dev,
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
while (1) {
if (rtw_end_of_queue_search(phead, plist) == true)
break;
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pnetwork = container_of(plist, struct wlan_network, list);
if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
/* Commented by Albert 2011/05/18 */
/* Match the device address located in the P2P IE */
@@ -3215,7 +3166,7 @@ static int rtw_p2p_get_go_device_address(struct net_device *dev,
}
}
- plist = get_next(plist);
+ plist = plist->next;
}
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
@@ -3264,13 +3215,13 @@ static int rtw_p2p_get_device_type(struct net_device *dev,
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
while (1) {
if (rtw_end_of_queue_search(phead, plist) == true)
break;
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pnetwork = container_of(plist, struct wlan_network, list);
if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
u8 *wpsie;
uint wpsie_len = 0;
@@ -3295,7 +3246,7 @@ static int rtw_p2p_get_device_type(struct net_device *dev,
break;
}
- plist = get_next(plist);
+ plist = plist->next;
}
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
@@ -3343,13 +3294,13 @@ static int rtw_p2p_get_device_name(struct net_device *dev,
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
while (1) {
if (rtw_end_of_queue_search(phead, plist) == true)
break;
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pnetwork = container_of(plist, struct wlan_network, list);
if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
u8 *wpsie;
uint wpsie_len = 0;
@@ -3366,7 +3317,7 @@ static int rtw_p2p_get_device_name(struct net_device *dev,
break;
}
- plist = get_next(plist);
+ plist = plist->next;
}
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
@@ -3414,13 +3365,13 @@ static int rtw_p2p_get_invitation_procedure(struct net_device *dev,
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
while (1) {
if (rtw_end_of_queue_search(phead, plist) == true)
break;
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pnetwork = container_of(plist, struct wlan_network, list);
if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
/* Commented by Albert 20121226 */
/* Match the device address located in the P2P IE */
@@ -3440,7 +3391,7 @@ static int rtw_p2p_get_invitation_procedure(struct net_device *dev,
}
}
}
- plist = get_next(plist);
+ plist = plist->next;
}
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
@@ -3496,19 +3447,19 @@ static int rtw_p2p_connect(struct net_device *dev,
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
while (1) {
if (rtw_end_of_queue_search(phead, plist) == true)
break;
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pnetwork = container_of(plist, struct wlan_network, list);
if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
uintPeerChannel = pnetwork->network.Configuration.DSConfig;
break;
}
- plist = get_next(plist);
+ plist = plist->next;
}
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
@@ -3591,13 +3542,13 @@ static int rtw_p2p_invite_req(struct net_device *dev,
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
while (1) {
if (rtw_end_of_queue_search(phead, plist) == true)
break;
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pnetwork = container_of(plist, struct wlan_network, list);
/* Commented by Albert 2011/05/18 */
/* Match the device address located in the P2P IE */
@@ -3622,7 +3573,7 @@ static int rtw_p2p_invite_req(struct net_device *dev,
}
}
}
- plist = get_next(plist);
+ plist = plist->next;
}
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
@@ -3741,7 +3692,7 @@ static int rtw_p2p_prov_disc(struct net_device *dev,
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
+ plist = phead->next;
while (1) {
if (rtw_end_of_queue_search(phead, plist) == true)
@@ -3750,7 +3701,7 @@ static int rtw_p2p_prov_disc(struct net_device *dev,
if (uintPeerChannel != 0)
break;
- pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ pnetwork = container_of(plist, struct wlan_network, list);
/* Commented by Albert 2011/05/18 */
/* Match the device address located in the P2P IE */
@@ -3781,7 +3732,7 @@ static int rtw_p2p_prov_disc(struct net_device *dev,
}
}
- plist = get_next(plist);
+ plist = plist->next;
}
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
@@ -3914,24 +3865,33 @@ static int rtw_p2p_get(struct net_device *dev,
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
if (padapter->bShowGetP2PState)
- DBG_88E("[%s] extra = %s\n", __func__, (char *)wrqu->data.pointer);
- if (!memcmp(wrqu->data.pointer, "status", 6)) {
+ DBG_88E("[%s] extra = %s\n", __func__,
+ (char __user *)wrqu->data.pointer);
+ if (!memcmp((__force const char *)wrqu->data.pointer,
+ "status", 6)) {
rtw_p2p_get_status(dev, info, wrqu, extra);
- } else if (!memcmp(wrqu->data.pointer, "role", 4)) {
+ } else if (!memcmp((__force const char *)wrqu->data.pointer,
+ "role", 4)) {
rtw_p2p_get_role(dev, info, wrqu, extra);
- } else if (!memcmp(wrqu->data.pointer, "peer_ifa", 8)) {
+ } else if (!memcmp((__force const char *)wrqu->data.pointer,
+ "peer_ifa", 8)) {
rtw_p2p_get_peer_ifaddr(dev, info, wrqu, extra);
- } else if (!memcmp(wrqu->data.pointer, "req_cm", 6)) {
+ } else if (!memcmp((__force const char *)wrqu->data.pointer,
+ "req_cm", 6)) {
rtw_p2p_get_req_cm(dev, info, wrqu, extra);
- } else if (!memcmp(wrqu->data.pointer, "peer_deva", 9)) {
+ } else if (!memcmp((__force const char *)wrqu->data.pointer,
+ "peer_deva", 9)) {
/* Get the P2P device address when receiving the provision discovery request frame. */
rtw_p2p_get_peer_devaddr(dev, info, wrqu, extra);
- } else if (!memcmp(wrqu->data.pointer, "group_id", 8)) {
+ } else if (!memcmp((__force const char *)wrqu->data.pointer,
+ "group_id", 8)) {
rtw_p2p_get_groupid(dev, info, wrqu, extra);
- } else if (!memcmp(wrqu->data.pointer, "peer_deva_inv", 9)) {
+ } else if (!memcmp((__force const char *)wrqu->data.pointer,
+ "peer_deva_inv", 9)) {
/* Get the P2P device address when receiving the P2P Invitation request frame. */
rtw_p2p_get_peer_devaddr_by_invitation(dev, info, wrqu, extra);
- } else if (!memcmp(wrqu->data.pointer, "op_ch", 5)) {
+ } else if (!memcmp((__force const char *)wrqu->data.pointer,
+ "op_ch", 5)) {
rtw_p2p_get_op_ch(dev, info, wrqu, extra);
}
#endif /* CONFIG_88EU_P2P */
@@ -3945,7 +3905,8 @@ static int rtw_p2p_get2(struct net_device *dev,
int ret = 0;
#ifdef CONFIG_88EU_P2P
- DBG_88E("[%s] extra = %s\n", __func__, (char *)wrqu->data.pointer);
+ DBG_88E("[%s] extra = %s\n", __func__,
+ (char __user *)wrqu->data.pointer);
if (!memcmp(extra, "wpsCM =", 6)) {
wrqu->data.length -= 6;
rtw_p2p_get_wps_configmethod(dev, info, wrqu, &extra[6]);
@@ -4436,12 +4397,12 @@ static int rtw_dbg_port(struct net_device *dev,
for (i = 0; i < NUM_STA; i++) {
phead = &(pstapriv->sta_hash[i]);
- plist = get_next(phead);
+ plist = phead->next;
while ((rtw_end_of_queue_search(phead, plist)) == false) {
- psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+ psta = container_of(plist, struct sta_info, hash_list);
- plist = get_next(plist);
+ plist = plist->next;
if (extra_arg == psta->aid) {
DBG_88E("sta's macaddr:%pM\n", (psta->hwaddr));
@@ -4507,11 +4468,9 @@ static int rtw_dbg_port(struct net_device *dev,
struct registry_priv *pregpriv = &padapter->registrypriv;
/* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, 0x3: enable both 2.4g and 5g */
/* default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */
- if (pregpriv &&
- (extra_arg == 0 ||
- extra_arg == 1 ||
- extra_arg == 2 ||
- extra_arg == 3)) {
+ if (!pregpriv)
+ break;
+ if (extra_arg >= 0 && extra_arg <= 3) {
pregpriv->rx_stbc = extra_arg;
DBG_88E("set rx_stbc =%d\n", pregpriv->rx_stbc);
} else {
@@ -4523,7 +4482,9 @@ static int rtw_dbg_port(struct net_device *dev,
{
struct registry_priv *pregpriv = &padapter->registrypriv;
/* 0: disable, 0x1:enable (but wifi_spec should be 0), 0x2: force enable (don't care wifi_spec) */
- if (pregpriv && extra_arg >= 0 && extra_arg < 3) {
+ if (!pregpriv)
+ break;
+ if (extra_arg >= 0 && extra_arg < 3) {
pregpriv->ampdu_enable = extra_arg;
DBG_88E("set ampdu_enable =%d\n", pregpriv->ampdu_enable);
} else {
@@ -5648,12 +5609,12 @@ static int rtw_wx_set_priv(struct net_device *dev,
return -EFAULT;
len = dwrq->length;
- ext = rtw_vmalloc(len);
+ ext = vmalloc(len);
if (!ext)
return -ENOMEM;
if (copy_from_user(ext, dwrq->pointer, len)) {
- rtw_vmfree(ext, len);
+ vfree(ext);
return -EFAULT;
}
@@ -5693,7 +5654,7 @@ static int rtw_wx_set_priv(struct net_device *dev,
FREE_EXT:
- rtw_vmfree(ext, len);
+ vfree(ext);
return ret;
}
@@ -5709,10 +5670,14 @@ static int rtw_pm_set(struct net_device *dev,
DBG_88E("[%s] extra = %s\n", __func__, extra);
if (!memcmp(extra, "lps =", 4)) {
- sscanf(extra+4, "%u", &mode);
+ ret = sscanf(extra+4, "%u", &mode);
+ if (ret != 1)
+ return -EINVAL;
ret = rtw_pm_set_lps(padapter, mode);
} else if (!memcmp(extra, "ips =", 4)) {
- sscanf(extra+4, "%u", &mode);
+ ret = sscanf(extra+4, "%u", &mode);
+ if (ret != 1)
+ return -EINVAL;
ret = rtw_pm_set_ips(padapter, mode);
} else {
ret = -EINVAL;
@@ -6812,8 +6777,11 @@ static int rtw_mp_bandwidth(struct net_device *dev,
{
u32 bandwidth = 0, sg = 0;
struct adapter *padapter = rtw_netdev_priv(dev);
+ int rv;
- sscanf(extra, "40M =%d, shortGI =%d", &bandwidth, &sg);
+ rv = sscanf(extra, "40M =%d, shortGI =%d", &bandwidth, &sg);
+ if (rv != 2)
+ return -EINVAL;
if (bandwidth != HT_CHANNEL_WIDTH_40)
bandwidth = HT_CHANNEL_WIDTH_20;
@@ -6833,6 +6801,7 @@ static int rtw_mp_txpower(struct net_device *dev,
u32 idx_a = 0, idx_b = 0;
char *input = kmalloc(wrqu->length, GFP_KERNEL);
struct adapter *padapter = rtw_netdev_priv(dev);
+ int rv;
if (!input)
return -ENOMEM;
@@ -6840,7 +6809,11 @@ static int rtw_mp_txpower(struct net_device *dev,
kfree(input);
return -EFAULT;
}
- sscanf(input, "patha =%d, pathb =%d", &idx_a, &idx_b);
+ rv = sscanf(input, "patha =%d, pathb =%d", &idx_a, &idx_b);
+ if (rv != 2) {
+ kfree(input);
+ return -EINVAL;
+ }
sprintf(extra, "Set power level path_A:%d path_B:%d", idx_a, idx_b);
padapter->mppriv.txpoweridx = (u8)idx_a;
@@ -6934,6 +6907,7 @@ static int rtw_mp_ctx(struct net_device *dev,
u32 pkTx = 1, countPkTx = 1, cotuTx = 1, CarrSprTx = 1, scTx = 1, sgleTx = 1, stop = 1;
u32 bStartTest = 1;
u32 count = 0;
+ int rv;
struct mp_priv *pmp_priv;
struct pkt_attrib *pattrib;
@@ -6953,7 +6927,9 @@ static int rtw_mp_ctx(struct net_device *dev,
sgleTx = strncmp(extra, "background, stone", 20);
pkTx = strncmp(extra, "background, pkt", 20);
stop = strncmp(extra, "stop", 4);
- sscanf(extra, "count =%d, pkt", &count);
+ rv = sscanf(extra, "count =%d, pkt", &count);
+ if (rv != 2)
+ return -EINVAL;
_rtw_memset(extra, '\0', sizeof(*extra));
@@ -7312,6 +7288,7 @@ static int rtw_mp_phypara(struct net_device *dev,
{
char *input = kmalloc(wrqu->length, GFP_KERNEL);
u32 valxcap;
+ int rv;
if (!input)
return -ENOMEM;
@@ -7322,7 +7299,11 @@ static int rtw_mp_phypara(struct net_device *dev,
DBG_88E("%s:iwpriv in =%s\n", __func__, input);
- sscanf(input, "xcap =%d", &valxcap);
+ rv = sscanf(input, "xcap =%d", &valxcap);
+ if (rv != 1) {
+ kfree(input);
+ return -EINVAL;
+ }
kfree(input);
return 0;
@@ -7888,6 +7869,7 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_
s32 len;
u8 *extra = NULL;
u32 extra_size = 0;
+ int rv;
s32 k;
const iw_handler *priv; /* Private ioctl */
@@ -7913,7 +7895,11 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_
ptr = input;
len = input_len;
- sscanf(ptr, "%16s", cmdname);
+ rv = sscanf(ptr, "%16s", cmdname);
+ if (rv != 1) {
+ err = -EINVAL;
+ goto exit;
+ }
cmdlen = strlen(cmdname);
DBG_88E("%s: cmd =%s\n", __func__, cmdname);
diff --git a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
index 57d1ff750d52..0624378efd6f 100644
--- a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
@@ -61,12 +61,10 @@ void rtw_init_mlme_timer(struct adapter *padapter)
void rtw_os_indicate_connect(struct adapter *adapter)
{
-_func_enter_;
rtw_indicate_wx_assoc_event(adapter);
netif_carrier_on(adapter->pnetdev);
if (adapter->pid[2] != 0)
rtw_signal_process(adapter->pid[2], SIGALRM);
-_func_exit_;
}
void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted)
@@ -119,11 +117,9 @@ void rtw_reset_securitypriv(struct adapter *adapter)
void rtw_os_indicate_disconnect(struct adapter *adapter)
{
-_func_enter_;
netif_carrier_off(adapter->pnetdev); /* Do it first for tx broadcast pkt after disconnection issue! */
rtw_indicate_wx_disassoc_event(adapter);
rtw_reset_securitypriv(adapter);
-_func_exit_;
}
void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie)
@@ -132,7 +128,6 @@ void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie)
u8 *buff, *p, i;
union iwreq_data wrqu;
-_func_enter_;
RT_TRACE(_module_mlme_osdep_c_, _drv_info_,
("+rtw_report_sec_ie, authmode=%d\n", authmode));
buff = NULL;
@@ -141,7 +136,7 @@ _func_enter_;
("rtw_report_sec_ie, authmode=%d\n", authmode));
buff = rtw_malloc(IW_CUSTOM_MAX);
if (!buff)
- goto exit;
+ return;
_rtw_memset(buff, 0, IW_CUSTOM_MAX);
p = buff;
p += sprintf(p, "ASSOCINFO(ReqIEs =");
@@ -157,8 +152,6 @@ _func_enter_;
wireless_send_event(adapter->pnetdev, IWEVCUSTOM, &wrqu, buff);
kfree(buff);
}
-exit:
-_func_exit_;
}
static void _survey_timer_hdl(void *FunctionContext)
diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
index 68f98fa114d2..b225d1c07210 100644
--- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c
+++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
@@ -520,7 +520,6 @@ static uint loadparam(struct adapter *padapter, struct net_device *pnetdev)
uint status = _SUCCESS;
struct registry_priv *registry_par = &padapter->registrypriv;
-_func_enter_;
GlobalDebugLevel = rtw_debug;
registry_par->chip_version = (u8)rtw_chip_version;
@@ -588,7 +587,6 @@ _func_enter_;
snprintf(registry_par->ifname, 16, "%s", ifname);
snprintf(registry_par->if2name, 16, "%s", if2name);
registry_par->notch_filter = (u8)rtw_notch_filter;
-_func_exit_;
return status;
}
@@ -653,7 +651,7 @@ static unsigned int rtw_classify8021d(struct sk_buff *skb)
}
static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv, select_queue_fallback_t fallback)
{
struct adapter *padapter = rtw_netdev_priv(dev);
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -855,7 +853,6 @@ u8 rtw_init_drv_sw(struct adapter *padapter)
{
u8 ret8 = _SUCCESS;
-_func_enter_;
RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_init_drv_sw\n"));
@@ -930,7 +927,6 @@ _func_enter_;
exit:
RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_init_drv_sw\n"));
- _func_exit_;
return ret8;
}
@@ -1115,7 +1111,7 @@ int netdev_open(struct net_device *pnetdev)
_enter_critical_mutex(padapter->hw_init_mutex, NULL);
ret = _netdev_open(pnetdev);
- _exit_critical_mutex(padapter->hw_init_mutex, NULL);
+ mutex_unlock(padapter->hw_init_mutex);
return ret;
}
@@ -1208,6 +1204,7 @@ int pm_netdev_open(struct net_device *pnetdev, u8 bnormal)
int netdev_close(struct net_device *pnetdev)
{
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
+ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+88eu_drv - drv_close\n"));
@@ -1246,6 +1243,9 @@ int netdev_close(struct net_device *pnetdev)
rtw_p2p_enable(padapter, P2P_ROLE_DISABLE);
#endif /* CONFIG_88EU_P2P */
+ kfree(dvobj->firmware.szFwBuffer);
+ dvobj->firmware.szFwBuffer = NULL;
+
RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-88eu_drv - drv_close\n"));
DBG_88E("-88eu_drv - drv_close, bup =%d\n", padapter->bup);
return 0;
diff --git a/drivers/staging/rtl8188eu/os_dep/osdep_service.c b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
index 8c3b077448af..2579a404a766 100644
--- a/drivers/staging/rtl8188eu/os_dep/osdep_service.c
+++ b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
@@ -55,27 +55,6 @@ u32 rtw_atoi(u8 *s)
return num;
}
-inline u8 *_rtw_vmalloc(u32 sz)
-{
- u8 *pbuf;
- pbuf = vmalloc(sz);
- return pbuf;
-}
-
-inline u8 *_rtw_zvmalloc(u32 sz)
-{
- u8 *pbuf;
- pbuf = _rtw_vmalloc(sz);
- if (pbuf != NULL)
- memset(pbuf, 0, sz);
- return pbuf;
-}
-
-inline void _rtw_vmfree(u8 *pbuf, u32 sz)
-{
- vfree(pbuf);
-}
-
u8 *_rtw_malloc(u32 sz)
{
u8 *pbuf = NULL;
@@ -114,16 +93,6 @@ void rtw_mfree2d(void *pbuf, int h, int w, int size)
kfree(pbuf);
}
-int _rtw_memcmp(void *dst, void *src, u32 sz)
-{
-/* under Linux/GNU/GLibc, the return value of memcmp for two same
- * mem. chunk is 0 */
- if (!(memcmp(dst, src, sz)))
- return true;
- else
- return false;
-}
-
void _rtw_memset(void *pbuf, int c, u32 sz)
{
memset(pbuf, c, sz);
@@ -252,7 +221,7 @@ struct net_device *rtw_alloc_etherdev(int sizeof_priv)
pnpi = netdev_priv(pnetdev);
- pnpi->priv = rtw_zvmalloc(sizeof_priv);
+ pnpi->priv = vzalloc(sizeof_priv);
if (!pnpi->priv) {
free_netdev(pnetdev);
pnetdev = NULL;
@@ -276,7 +245,7 @@ void rtw_free_netdev(struct net_device *netdev)
if (!pnpi->priv)
goto RETURN;
- rtw_vmfree(pnpi->priv, pnpi->sizeof_priv);
+ vfree(pnpi->priv);
free_netdev(netdev);
RETURN:
diff --git a/drivers/staging/rtl8188eu/os_dep/recv_linux.c b/drivers/staging/rtl8188eu/os_dep/recv_linux.c
index 2a18b3208a00..da397e4c6773 100644
--- a/drivers/staging/rtl8188eu/os_dep/recv_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/recv_linux.c
@@ -26,7 +26,6 @@
#include <recv_osdep.h>
#include <osdep_intf.h>
-#include <ethernet.h>
#include <usb_ops.h>
/* init os related resource in struct recv_priv */
@@ -36,16 +35,16 @@ int rtw_os_recv_resource_init(struct recv_priv *precvpriv,
return _SUCCESS;
}
-/* alloc os related resource in union recv_frame */
+/* alloc os related resource in struct recv_frame */
int rtw_os_recv_resource_alloc(struct adapter *padapter,
- union recv_frame *precvframe)
+ struct recv_frame *precvframe)
{
- precvframe->u.hdr.pkt_newalloc = NULL;
- precvframe->u.hdr.pkt = NULL;
+ precvframe->pkt_newalloc = NULL;
+ precvframe->pkt = NULL;
return _SUCCESS;
}
-/* free os related resource in union recv_frame */
+/* free os related resource in struct recv_frame */
void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
{
}
@@ -118,24 +117,23 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup)
}
void rtw_hostapd_mlme_rx(struct adapter *padapter,
- union recv_frame *precv_frame)
+ struct recv_frame *precv_frame)
{
}
int rtw_recv_indicatepkt(struct adapter *padapter,
- union recv_frame *precv_frame)
+ struct recv_frame *precv_frame)
{
struct recv_priv *precvpriv;
struct __queue *pfree_recv_queue;
struct sk_buff *skb;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-_func_enter_;
precvpriv = &(padapter->recvpriv);
pfree_recv_queue = &(precvpriv->free_recv_queue);
- skb = precv_frame->u.hdr.pkt;
+ skb = precv_frame->pkt;
if (skb == NULL) {
RT_TRACE(_module_recv_osdep_c_, _drv_err_,
("rtw_recv_indicatepkt():skb == NULL something wrong!!!!\n"));
@@ -145,18 +143,18 @@ _func_enter_;
RT_TRACE(_module_recv_osdep_c_, _drv_info_,
("rtw_recv_indicatepkt():skb != NULL !!!\n"));
RT_TRACE(_module_recv_osdep_c_, _drv_info_,
- ("rtw_recv_indicatepkt():precv_frame->u.hdr.rx_head =%p precv_frame->hdr.rx_data =%p\n",
- precv_frame->u.hdr.rx_head, precv_frame->u.hdr.rx_data));
+ ("rtw_recv_indicatepkt():precv_frame->rx_head =%p precv_frame->hdr.rx_data =%p\n",
+ precv_frame->rx_head, precv_frame->rx_data));
RT_TRACE(_module_recv_osdep_c_, _drv_info_,
- ("precv_frame->hdr.rx_tail =%p precv_frame->u.hdr.rx_end =%p precv_frame->hdr.len =%d\n",
- precv_frame->u.hdr.rx_tail, precv_frame->u.hdr.rx_end,
- precv_frame->u.hdr.len));
+ ("precv_frame->hdr.rx_tail =%p precv_frame->rx_end =%p precv_frame->hdr.len =%d\n",
+ precv_frame->rx_tail, precv_frame->rx_end,
+ precv_frame->len));
- skb->data = precv_frame->u.hdr.rx_data;
+ skb->data = precv_frame->rx_data;
- skb_set_tail_pointer(skb, precv_frame->u.hdr.len);
+ skb_set_tail_pointer(skb, precv_frame->len);
- skb->len = precv_frame->u.hdr.len;
+ skb->len = precv_frame->len;
RT_TRACE(_module_recv_osdep_c_, _drv_info_,
("skb->head =%p skb->data =%p skb->tail =%p skb->end =%p skb->len =%d\n",
@@ -167,11 +165,11 @@ _func_enter_;
struct sk_buff *pskb2 = NULL;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
- struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
int bmcast = IS_MCAST(pattrib->dst);
- if (!_rtw_memcmp(pattrib->dst, myid(&padapter->eeprompriv),
- ETH_ALEN)) {
+ if (memcmp(pattrib->dst, myid(&padapter->eeprompriv),
+ ETH_ALEN)) {
if (bmcast) {
psta = rtw_get_bcmc_stainfo(padapter);
pskb2 = skb_clone(skb, GFP_ATOMIC);
@@ -209,14 +207,13 @@ _func_enter_;
_recv_indicatepkt_end:
/* pointers to NULL before rtw_free_recvframe() */
- precv_frame->u.hdr.pkt = NULL;
+ precv_frame->pkt = NULL;
rtw_free_recvframe(precv_frame, pfree_recv_queue);
RT_TRACE(_module_recv_osdep_c_, _drv_info_,
("\n rtw_recv_indicatepkt :after netif_rx!!!!\n"));
-_func_exit_;
return _SUCCESS;
@@ -225,7 +222,6 @@ _recv_indicatepkt_drop:
/* enqueue back to free_recv_queue */
rtw_free_recvframe(precv_frame, pfree_recv_queue);
-_func_exit_;
return _FAIL;
}
diff --git a/drivers/staging/rtl8188eu/os_dep/rtw_android.c b/drivers/staging/rtl8188eu/os_dep/rtw_android.c
index a3c2bc5922e4..ca2736d60b62 100644
--- a/drivers/staging/rtl8188eu/os_dep/rtw_android.c
+++ b/drivers/staging/rtl8188eu/os_dep/rtw_android.c
@@ -24,7 +24,6 @@
#include <rtw_android.h>
#include <osdep_service.h>
#include <rtw_debug.h>
-#include <ioctl_cfg80211.h>
#include <rtw_ioctl_set.h>
static const char *android_wifi_cmd_str[ANDROID_WIFI_CMD_MAX] = {
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
index a70dcef1419e..2e49cd583212 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
@@ -26,6 +26,7 @@
#include <hal_intf.h>
#include <rtw_version.h>
#include <linux/usb.h>
+#include <linux/vmalloc.h>
#include <osdep_intf.h>
#include <usb_vendor_req.h>
@@ -55,6 +56,7 @@ static struct usb_device_id rtw_usb_id_tbl[] = {
/****** 8188EUS ********/
{USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */
{USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */
+ {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */
{} /* Terminating entry */
};
@@ -161,7 +163,6 @@ static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf)
struct usb_endpoint_descriptor *pendp_desc;
struct usb_device *pusbd;
-_func_enter_;
pdvobjpriv = (struct dvobj_priv *)rtw_zmalloc(sizeof(*pdvobjpriv));
if (pdvobjpriv == NULL)
@@ -254,7 +255,6 @@ free_dvobj:
pdvobjpriv = NULL;
}
exit:
-_func_exit_;
return pdvobjpriv;
}
@@ -262,7 +262,6 @@ static void usb_dvobj_deinit(struct usb_interface *usb_intf)
{
struct dvobj_priv *dvobj = usb_get_intfdata(usb_intf);
-_func_enter_;
usb_set_intfdata(usb_intf, NULL);
if (dvobj) {
@@ -287,7 +286,6 @@ _func_enter_;
usb_put_dev(interface_to_usbdev(usb_intf));
-_func_exit_;
}
static void chip_by_usb_id(struct adapter *padapter,
@@ -389,7 +387,6 @@ int rtw_hw_suspend(struct adapter *padapter)
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
struct net_device *pnetdev = padapter->pnetdev;
- _func_enter_;
if ((!padapter->bup) || (padapter->bDriverStopped) ||
(padapter->bSurpriseRemoved)) {
@@ -442,7 +439,6 @@ int rtw_hw_suspend(struct adapter *padapter)
} else {
goto error_exit;
}
- _func_exit_;
return 0;
error_exit:
@@ -455,7 +451,6 @@ int rtw_hw_resume(struct adapter *padapter)
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
struct net_device *pnetdev = padapter->pnetdev;
- _func_enter_;
if (padapter) { /* system resume */
DBG_88E("==> rtw_hw_resume\n");
@@ -487,7 +482,6 @@ int rtw_hw_resume(struct adapter *padapter)
goto error_exit;
}
- _func_exit_;
return 0;
error_exit:
@@ -506,7 +500,6 @@ static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message)
int ret = 0;
u32 start_time = jiffies;
- _func_enter_;
DBG_88E("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
@@ -563,7 +556,6 @@ exit:
DBG_88E("<=== %s return %d.............. in %dms\n", __func__
, ret, rtw_get_passing_time_ms(start_time));
- _func_exit_;
return ret;
}
@@ -587,7 +579,6 @@ int rtw_resume_process(struct adapter *padapter)
struct pwrctrl_priv *pwrpriv = NULL;
int ret = -1;
u32 start_time = jiffies;
- _func_enter_;
DBG_88E("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
@@ -626,7 +617,6 @@ exit:
DBG_88E("<=== %s return %d.............. in %dms\n", __func__,
ret, rtw_get_passing_time_ms(start_time));
- _func_exit_;
return ret;
}
@@ -646,7 +636,7 @@ static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj,
struct net_device *pnetdev = NULL;
int status = _FAIL;
- padapter = (struct adapter *)rtw_zvmalloc(sizeof(*padapter));
+ padapter = (struct adapter *)vzalloc(sizeof(*padapter));
if (padapter == NULL)
goto exit;
padapter->dvobj = dvobj;
@@ -746,7 +736,7 @@ free_adapter:
if (pnetdev)
rtw_free_netdev(pnetdev);
else if (padapter)
- rtw_vmfree((u8 *)padapter, sizeof(*padapter));
+ vfree(padapter);
padapter = NULL;
}
exit:
@@ -835,7 +825,6 @@ static void rtw_dev_remove(struct usb_interface *pusb_intf)
struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf);
struct adapter *padapter = dvobj->if1;
-_func_enter_;
DBG_88E("+rtw_dev_remove\n");
RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+dev_remove()\n"));
@@ -854,7 +843,6 @@ _func_enter_;
RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-dev_remove()\n"));
DBG_88E("-r871xu_dev_remove, done\n");
-_func_exit_;
return;
}
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
index 7e3f2fadd5bf..fb0bba85373b 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
@@ -80,7 +80,6 @@ static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs)
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct hal_data_8188e *haldata;
-_func_enter_;
switch (pxmitbuf->flags) {
case VO_QUEUE_INX:
@@ -156,8 +155,6 @@ check_completion:
rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
-
-_func_exit_;
}
u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
@@ -174,7 +171,6 @@ u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
struct usb_device *pusbd = pdvobj->pusbdev;
-_func_enter_;
RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("+usb_write_port\n"));
@@ -255,7 +251,6 @@ _func_enter_;
exit:
if (ret != _SUCCESS)
rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
-_func_exit_;
return ret;
}
diff --git a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
index 9005971084b7..2c8e3f72dec7 100644
--- a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
@@ -23,8 +23,6 @@
#include <osdep_service.h>
#include <drv_types.h>
-#include <if_ether.h>
-#include <ip.h>
#include <wifi.h>
#include <mlme_osdep.h>
#include <xmit_osdep.h>
@@ -39,7 +37,6 @@ uint rtw_remainder_len(struct pkt_file *pfile)
void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile)
{
-_func_enter_;
pfile->pkt = pktptr;
pfile->cur_addr = pktptr->data;
@@ -49,14 +46,12 @@ _func_enter_;
pfile->cur_buffer = pfile->buf_start;
-_func_exit_;
}
uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen)
{
uint len = 0;
-_func_enter_;
len = rtw_remainder_len(pfile);
len = (rlen > len) ? len : rlen;
@@ -67,21 +62,17 @@ _func_enter_;
pfile->cur_addr += len;
pfile->pkt_len -= len;
-_func_exit_;
return len;
}
int rtw_endofpktfile(struct pkt_file *pfile)
{
-_func_enter_;
if (pfile->pkt_len == 0) {
- _func_exit_;
return true;
}
-_func_exit_;
return false;
}
@@ -200,13 +191,13 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = get_next(phead);
+ plist = phead->next;
/* free sta asoc_queue */
while (!rtw_end_of_queue_search(phead, plist)) {
- psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+ psta = container_of(plist, struct sta_info, asoc_list);
- plist = get_next(plist);
+ plist = plist->next;
/* avoid come from STA1 and send back STA1 */
if (!memcmp(psta->hwaddr, &skb->data[6], 6))
@@ -246,7 +237,6 @@ int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
s32 res = 0;
-_func_enter_;
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n"));
@@ -282,7 +272,6 @@ drop_packet:
exit:
-_func_exit_;
return 0;
}
diff --git a/drivers/staging/rtl8192e/dot11d.c b/drivers/staging/rtl8192e/dot11d.c
index eb33c517fcc8..53da61072992 100644
--- a/drivers/staging/rtl8192e/dot11d.c
+++ b/drivers/staging/rtl8192e/dot11d.c
@@ -133,14 +133,12 @@ void Dot11d_UpdateCountryIe(struct rtllib_device *dev, u8 *pTaddr,
pTriple = (struct chnl_txpow_triple *)(pCoutryIe + 3);
for (i = 0; i < NumTriples; i++) {
if (MaxChnlNum >= pTriple->FirstChnl) {
- printk(KERN_INFO "Dot11d_UpdateCountryIe(): Invalid"
- " country IE, skip it........1\n");
+ printk(KERN_INFO "Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n");
return;
}
if (MAX_CHANNEL_NUMBER < (pTriple->FirstChnl +
pTriple->NumChnls)) {
- printk(KERN_INFO "Dot11d_UpdateCountryIe(): Invalid "
- "country IE, skip it........2\n");
+ printk(KERN_INFO "Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n");
return;
}
@@ -167,8 +165,7 @@ u8 DOT11D_GetMaxTxPwrInDbm(struct rtllib_device *dev, u8 Channel)
u8 MaxTxPwrInDbm = 255;
if (MAX_CHANNEL_NUMBER < Channel) {
- printk(KERN_INFO "DOT11D_GetMaxTxPwrInDbm(): Invalid "
- "Channel\n");
+ printk(KERN_INFO "DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n");
return MaxTxPwrInDbm;
}
if (pDot11dInfo->channel_map[Channel])
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h
index 356aec437963..4b94653c50d9 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h
@@ -28,31 +28,6 @@
#include <linux/types.h>
#include <linux/pci.h>
-static inline void NdisRawWritePortUlong(u32 port, u32 val)
-{
- outl(val, port);
-}
-
-static inline void NdisRawWritePortUchar(u32 port, u8 val)
-{
- outb(val, port);
-}
-
-static inline void NdisRawReadPortUchar(u32 port, u8 *pval)
-{
- *pval = inb(port);
-}
-
-static inline void NdisRawReadPortUshort(u32 port, u16 *pval)
-{
- *pval = inw(port);
-}
-
-static inline void NdisRawReadPortUlong(u32 port, u32 *pval)
-{
- *pval = inl(port);
-}
-
struct mp_adapter {
u8 LinkCtrlReg;
@@ -70,33 +45,6 @@ struct mp_adapter {
u8 PciBridgeLinkCtrlReg;
};
-struct rt_pci_capab_header {
- unsigned char CapabilityID;
- unsigned char Next;
-};
-
-#define PCI_MAX_BRIDGE_NUMBER 255
-#define PCI_MAX_DEVICES 32
-#define PCI_MAX_FUNCTION 8
-
-#define PCI_CONF_ADDRESS 0x0CF8
-#define PCI_CONF_DATA 0x0CFC
-
-#define PCI_CLASS_BRIDGE_DEV 0x06
-#define PCI_SUBCLASS_BR_PCI_TO_PCI 0x04
-
-#define U1DONTCARE 0xFF
-#define U2DONTCARE 0xFFFF
-#define U4DONTCARE 0xFFFFFFFF
-
-#define INTEL_VENDOR_ID 0x8086
-#define SIS_VENDOR_ID 0x1039
-#define ATI_VENDOR_ID 0x1002
-#define ATI_DEVICE_ID 0x7914
-#define AMD_VENDOR_ID 0x1022
-
-#define PCI_CAPABILITY_ID_PCI_EXPRESS 0x10
-
struct net_device;
bool rtl8192_pci_findadapter(struct pci_dev *pdev, struct net_device *dev);
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
index 6202358c2984..498995d833e7 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
@@ -609,7 +609,7 @@ static int r8192_wx_set_nick(struct net_device *dev,
if (wrqu->data.length > IW_ESSID_MAX_SIZE)
return -E2BIG;
down(&priv->wx_sem);
- wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
+ wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
memset(priv->nick, 0, sizeof(priv->nick));
memcpy(priv->nick, extra, wrqu->data.length);
up(&priv->wx_sem);
diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c
index 77964885b3f2..11d0a9d8ee59 100644
--- a/drivers/staging/rtl8192e/rtllib_tx.c
+++ b/drivers/staging/rtl8192e/rtllib_tx.c
@@ -939,12 +939,12 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
if (txb) {
if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) {
dev->stats.tx_packets++;
- dev->stats.tx_bytes += txb->payload_size;
+ dev->stats.tx_bytes += le16_to_cpu(txb->payload_size);
rtllib_softmac_xmit(txb, ieee);
} else {
if ((*ieee->hard_start_xmit)(txb, dev) == 0) {
stats->tx_packets++;
- stats->tx_bytes += txb->payload_size;
+ stats->tx_bytes += le16_to_cpu(txb->payload_size);
return 0;
}
rtllib_txb_free(txb);
diff --git a/drivers/staging/rtl8192u/ieee80211/EndianFree.h b/drivers/staging/rtl8192u/ieee80211/EndianFree.h
deleted file mode 100644
index dc85fb913dc2..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/EndianFree.h
+++ /dev/null
@@ -1,194 +0,0 @@
-#ifndef __INC_ENDIANFREE_H
-#define __INC_ENDIANFREE_H
-
-/*
- * Call endian free function when
- * 1. Read/write packet content.
- * 2. Before write integer to IO.
- * 3. After read integer from IO.
- */
-
-#define __MACHINE_LITTLE_ENDIAN 1234 /* LSB first: i386, vax */
-#define __MACHINE_BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net, ppc */
-
-#define BYTE_ORDER __MACHINE_LITTLE_ENDIAN
-
-#if BYTE_ORDER == __MACHINE_LITTLE_ENDIAN
-// Convert data
-#define EF1Byte(_val) ((u8)(_val))
-#define EF2Byte(_val) ((u16)(_val))
-#define EF4Byte(_val) ((u32)(_val))
-
-#else
-// Convert data
-#define EF1Byte(_val) ((u8)(_val))
-#define EF2Byte(_val) (((((u16)(_val))&0x00ff)<<8)|((((u16)(_val))&0xff00)>>8))
-#define EF4Byte(_val) (((((u32)(_val))&0x000000ff)<<24)|\
- ((((u32)(_val))&0x0000ff00)<<8)|\
- ((((u32)(_val))&0x00ff0000)>>8)|\
- ((((u32)(_val))&0xff000000)>>24))
-#endif
-
-// Read data from memory
-#define ReadEF1Byte(_ptr) EF1Byte(*((u8 *)(_ptr)))
-#define ReadEF2Byte(_ptr) EF2Byte(*((u16 *)(_ptr)))
-#define ReadEF4Byte(_ptr) EF4Byte(*((u32 *)(_ptr)))
-
-// Write data to memory
-#define WriteEF1Byte(_ptr, _val) (*((u8 *)(_ptr)))=EF1Byte(_val)
-#define WriteEF2Byte(_ptr, _val) (*((u16 *)(_ptr)))=EF2Byte(_val)
-#define WriteEF4Byte(_ptr, _val) (*((u32 *)(_ptr)))=EF4Byte(_val)
-// Convert Host system specific byte ording (litten or big endia) to Network byte ording (big endian).
-// 2006.05.07, by rcnjko.
-#if BYTE_ORDER == __MACHINE_LITTLE_ENDIAN
-#define H2N1BYTE(_val) ((u8)(_val))
-#define H2N2BYTE(_val) (((((u16)(_val))&0x00ff)<<8)|\
- ((((u16)(_val))&0xff00)>>8))
-#define H2N4BYTE(_val) (((((u32)(_val))&0x000000ff)<<24)|\
- ((((u32)(_val))&0x0000ff00)<<8) |\
- ((((u32)(_val))&0x00ff0000)>>8) |\
- ((((u32)(_val))&0xff000000)>>24))
-#else
-#define H2N1BYTE(_val) ((u8)(_val))
-#define H2N2BYTE(_val) ((u16)(_val))
-#define H2N4BYTE(_val) ((u32)(_val))
-#endif
-
-// Convert from Network byte ording (big endian) to Host system specific byte ording (litten or big endia).
-// 2006.05.07, by rcnjko.
-#if BYTE_ORDER == __MACHINE_LITTLE_ENDIAN
-#define N2H1BYTE(_val) ((u8)(_val))
-#define N2H2BYTE(_val) (((((u16)(_val))&0x00ff)<<8)|\
- ((((u16)(_val))&0xff00)>>8))
-#define N2H4BYTE(_val) (((((u32)(_val))&0x000000ff)<<24)|\
- ((((u32)(_val))&0x0000ff00)<<8) |\
- ((((u32)(_val))&0x00ff0000)>>8) |\
- ((((u32)(_val))&0xff000000)>>24))
-#else
-#define N2H1BYTE(_val) ((u8)(_val))
-#define N2H2BYTE(_val) ((u16)(_val))
-#define N2H4BYTE(_val) ((u32)(_val))
-#endif
-
-//
-// Example:
-// BIT_LEN_MASK_32(0) => 0x00000000
-// BIT_LEN_MASK_32(1) => 0x00000001
-// BIT_LEN_MASK_32(2) => 0x00000003
-// BIT_LEN_MASK_32(32) => 0xFFFFFFFF
-//
-#define BIT_LEN_MASK_32(__BitLen) (0xFFFFFFFF >> (32 - (__BitLen)))
-//
-// Example:
-// BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003
-// BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000
-//
-#define BIT_OFFSET_LEN_MASK_32(__BitOffset, __BitLen) (BIT_LEN_MASK_32(__BitLen) << (__BitOffset))
-
-//
-// Description:
-// Return 4-byte value in host byte ordering from
-// 4-byte pointer in litten-endian system.
-//
-#define LE_P4BYTE_TO_HOST_4BYTE(__pStart) (EF4Byte(*((u32 *)(__pStart))))
-
-//
-// Description:
-// Translate subfield (continuous bits in little-endian) of 4-byte value in litten byte to
-// 4-byte value in host byte ordering.
-//
-#define LE_BITS_TO_4BYTE(__pStart, __BitOffset, __BitLen) \
- ( \
- ( LE_P4BYTE_TO_HOST_4BYTE(__pStart) >> (__BitOffset) ) \
- & \
- BIT_LEN_MASK_32(__BitLen) \
- )
-
-//
-// Description:
-// Mask subfield (continuous bits in little-endian) of 4-byte value in litten byte oredering
-// and return the result in 4-byte value in host byte ordering.
-//
-#define LE_BITS_CLEARED_TO_4BYTE(__pStart, __BitOffset, __BitLen) \
- ( \
- LE_P4BYTE_TO_HOST_4BYTE(__pStart) \
- & \
- ( ~BIT_OFFSET_LEN_MASK_32(__BitOffset, __BitLen) ) \
- )
-
-//
-// Description:
-// Set subfield of little-endian 4-byte value to specified value.
-//
-#define SET_BITS_TO_LE_4BYTE(__pStart, __BitOffset, __BitLen, __Value) \
- *((u32 *)(__pStart)) = \
- EF4Byte( \
- LE_BITS_CLEARED_TO_4BYTE(__pStart, __BitOffset, __BitLen) \
- | \
- ( (((u32)__Value) & BIT_LEN_MASK_32(__BitLen)) << (__BitOffset) ) \
- );
-
-
-#define BIT_LEN_MASK_16(__BitLen) \
- (0xFFFF >> (16 - (__BitLen)))
-
-#define BIT_OFFSET_LEN_MASK_16(__BitOffset, __BitLen) \
- (BIT_LEN_MASK_16(__BitLen) << (__BitOffset))
-
-#define LE_P2BYTE_TO_HOST_2BYTE(__pStart) \
- (EF2Byte(*((u16 *)(__pStart))))
-
-#define LE_BITS_TO_2BYTE(__pStart, __BitOffset, __BitLen) \
- ( \
- ( LE_P2BYTE_TO_HOST_2BYTE(__pStart) >> (__BitOffset) ) \
- & \
- BIT_LEN_MASK_16(__BitLen) \
- )
-
-#define LE_BITS_CLEARED_TO_2BYTE(__pStart, __BitOffset, __BitLen) \
- ( \
- LE_P2BYTE_TO_HOST_2BYTE(__pStart) \
- & \
- ( ~BIT_OFFSET_LEN_MASK_16(__BitOffset, __BitLen) ) \
- )
-
-#define SET_BITS_TO_LE_2BYTE(__pStart, __BitOffset, __BitLen, __Value) \
- *((u16 *)(__pStart)) = \
- EF2Byte( \
- LE_BITS_CLEARED_TO_2BYTE(__pStart, __BitOffset, __BitLen) \
- | \
- ( (((u16)__Value) & BIT_LEN_MASK_16(__BitLen)) << (__BitOffset) ) \
- );
-
-#define BIT_LEN_MASK_8(__BitLen) \
- (0xFF >> (8 - (__BitLen)))
-
-#define BIT_OFFSET_LEN_MASK_8(__BitOffset, __BitLen) \
- (BIT_LEN_MASK_8(__BitLen) << (__BitOffset))
-
-#define LE_P1BYTE_TO_HOST_1BYTE(__pStart) \
- (EF1Byte(*((u8 *)(__pStart))))
-
-#define LE_BITS_TO_1BYTE(__pStart, __BitOffset, __BitLen) \
- ( \
- ( LE_P1BYTE_TO_HOST_1BYTE(__pStart) >> (__BitOffset) ) \
- & \
- BIT_LEN_MASK_8(__BitLen) \
- )
-
-#define LE_BITS_CLEARED_TO_1BYTE(__pStart, __BitOffset, __BitLen) \
- ( \
- LE_P1BYTE_TO_HOST_1BYTE(__pStart) \
- & \
- ( ~BIT_OFFSET_LEN_MASK_8(__BitOffset, __BitLen) ) \
- )
-
-#define SET_BITS_TO_LE_1BYTE(__pStart, __BitOffset, __BitLen, __Value) \
- *((u8 *)(__pStart)) = \
- EF1Byte( \
- LE_BITS_CLEARED_TO_1BYTE(__pStart, __BitOffset, __BitLen) \
- | \
- ( (((u8)__Value) & BIT_LEN_MASK_8(__BitLen)) << (__BitOffset) ) \
- );
-
-#endif // #ifndef __INC_ENDIANFREE_H
diff --git a/drivers/staging/rtl8192u/ieee80211/aes.c b/drivers/staging/rtl8192u/ieee80211/aes.c
deleted file mode 100644
index abc1023cef65..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/aes.c
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Cryptographic API.
- *
- * AES Cipher Algorithm.
- *
- * Based on Brian Gladman's code.
- *
- * Linux developers:
- * Alexander Kjeldaas <astor@fast.no>
- * Herbert Valerio Riedel <hvr@hvrlab.org>
- * Kyle McMartin <kyle@debian.org>
- * Adam J. Richter <adam@yggdrasil.com> (conversion to 2.5 API).
- *
- * This program is free software; 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.
- *
- * ---------------------------------------------------------------------------
- * Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
- * All rights reserved.
- *
- * LICENSE TERMS
- *
- * The free distribution and use of this software in both source and binary
- * form is allowed (with or without changes) provided that:
- *
- * 1. distributions of this source code include the above copyright
- * notice, this list of conditions and the following disclaimer;
- *
- * 2. distributions in binary form include the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other associated materials;
- *
- * 3. the copyright holder's name is not used to endorse products
- * built using this software without specific written permission.
- *
- * ALTERNATIVELY, provided that this notice is retained in full, this product
- * may be distributed under the terms of the GNU General Public License (GPL),
- * in which case the provisions of the GPL apply INSTEAD OF those given above.
- *
- * DISCLAIMER
- *
- * This software is provided 'as is' with no explicit or implied warranties
- * in respect of its properties, including, but not limited to, correctness
- * and/or fitness for purpose.
- * ---------------------------------------------------------------------------
- */
-
-/* Some changes from the Gladman version:
- s/RIJNDAEL(e_key)/E_KEY/g
- s/RIJNDAEL(d_key)/D_KEY/g
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-//#include <linux/crypto.h>
-#include "rtl_crypto.h"
-#include <asm/byteorder.h>
-
-#define AES_MIN_KEY_SIZE 16
-#define AES_MAX_KEY_SIZE 32
-
-#define AES_BLOCK_SIZE 16
-
-static inline
-u32 generic_rotr32 (const u32 x, const unsigned bits)
-{
- const unsigned n = bits % 32;
- return (x >> n) | (x << (32 - n));
-}
-
-static inline
-u32 generic_rotl32 (const u32 x, const unsigned bits)
-{
- const unsigned n = bits % 32;
- return (x << n) | (x >> (32 - n));
-}
-
-#define rotl generic_rotl32
-#define rotr generic_rotr32
-
-/*
- * #define byte(x, nr) ((unsigned char)((x) >> (nr*8)))
- */
-inline static u8
-byte(const u32 x, const unsigned n)
-{
- return x >> (n << 3);
-}
-
-#define u32_in(x) le32_to_cpu(*(const u32 *)(x))
-#define u32_out(to, from) (*(u32 *)(to) = cpu_to_le32(from))
-
-struct aes_ctx {
- int key_length;
- u32 E[60];
- u32 D[60];
-};
-
-#define E_KEY ctx->E
-#define D_KEY ctx->D
-
-static u8 pow_tab[256] __initdata;
-static u8 log_tab[256] __initdata;
-static u8 sbx_tab[256] __initdata;
-static u8 isb_tab[256] __initdata;
-static u32 rco_tab[10];
-static u32 ft_tab[4][256];
-static u32 it_tab[4][256];
-
-static u32 fl_tab[4][256];
-static u32 il_tab[4][256];
-
-static inline u8 __init
-f_mult (u8 a, u8 b)
-{
- u8 aa = log_tab[a], cc = aa + log_tab[b];
-
- return pow_tab[cc + (cc < aa ? 1 : 0)];
-}
-
-#define ff_mult(a,b) (a && b ? f_mult(a, b) : 0)
-
-#define f_rn(bo, bi, n, k) \
- bo[n] = ft_tab[0][byte(bi[n],0)] ^ \
- ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
- ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
- ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
-
-#define i_rn(bo, bi, n, k) \
- bo[n] = it_tab[0][byte(bi[n],0)] ^ \
- it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
- it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
- it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
-
-#define ls_box(x) \
- ( fl_tab[0][byte(x, 0)] ^ \
- fl_tab[1][byte(x, 1)] ^ \
- fl_tab[2][byte(x, 2)] ^ \
- fl_tab[3][byte(x, 3)] )
-
-#define f_rl(bo, bi, n, k) \
- bo[n] = fl_tab[0][byte(bi[n],0)] ^ \
- fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
- fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
- fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
-
-#define i_rl(bo, bi, n, k) \
- bo[n] = il_tab[0][byte(bi[n],0)] ^ \
- il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
- il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
- il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
-
-static void __init
-gen_tabs (void)
-{
- u32 i, t;
- u8 p, q;
-
- /* log and power tables for GF(2**8) finite field with
- 0x011b as modular polynomial - the simplest primitive
- root is 0x03, used here to generate the tables */
-
- for (i = 0, p = 1; i < 256; ++i) {
- pow_tab[i] = (u8) p;
- log_tab[p] = (u8) i;
-
- p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0);
- }
-
- log_tab[1] = 0;
-
- for (i = 0, p = 1; i < 10; ++i) {
- rco_tab[i] = p;
-
- p = (p << 1) ^ (p & 0x80 ? 0x01b : 0);
- }
-
- for (i = 0; i < 256; ++i) {
- p = (i ? pow_tab[255 - log_tab[i]] : 0);
- q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2));
- p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2));
- sbx_tab[i] = p;
- isb_tab[p] = (u8) i;
- }
-
- for (i = 0; i < 256; ++i) {
- p = sbx_tab[i];
-
- t = p;
- fl_tab[0][i] = t;
- fl_tab[1][i] = rotl (t, 8);
- fl_tab[2][i] = rotl (t, 16);
- fl_tab[3][i] = rotl (t, 24);
-
- t = ((u32) ff_mult (2, p)) |
- ((u32) p << 8) |
- ((u32) p << 16) | ((u32) ff_mult (3, p) << 24);
-
- ft_tab[0][i] = t;
- ft_tab[1][i] = rotl (t, 8);
- ft_tab[2][i] = rotl (t, 16);
- ft_tab[3][i] = rotl (t, 24);
-
- p = isb_tab[i];
-
- t = p;
- il_tab[0][i] = t;
- il_tab[1][i] = rotl (t, 8);
- il_tab[2][i] = rotl (t, 16);
- il_tab[3][i] = rotl (t, 24);
-
- t = ((u32) ff_mult (14, p)) |
- ((u32) ff_mult (9, p) << 8) |
- ((u32) ff_mult (13, p) << 16) |
- ((u32) ff_mult (11, p) << 24);
-
- it_tab[0][i] = t;
- it_tab[1][i] = rotl (t, 8);
- it_tab[2][i] = rotl (t, 16);
- it_tab[3][i] = rotl (t, 24);
- }
-}
-
-#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
-
-#define imix_col(y,x) \
- u = star_x(x); \
- v = star_x(u); \
- w = star_x(v); \
- t = w ^ (x); \
- (y) = u ^ v ^ w; \
- (y) ^= rotr(u ^ t, 8) ^ \
- rotr(v ^ t, 16) ^ \
- rotr(t,24)
-
-/* initialise the key schedule from the user supplied key */
-
-#define loop4(i) \
-{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \
- t ^= E_KEY[4 * i]; E_KEY[4 * i + 4] = t; \
- t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t; \
- t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t; \
- t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t; \
-}
-
-#define loop6(i) \
-{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \
- t ^= E_KEY[6 * i]; E_KEY[6 * i + 6] = t; \
- t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t; \
- t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t; \
- t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t; \
- t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t; \
- t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t; \
-}
-
-#define loop8(i) \
-{ t = rotr(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \
- t ^= E_KEY[8 * i]; E_KEY[8 * i + 8] = t; \
- t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t; \
- t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t; \
- t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t; \
- t = E_KEY[8 * i + 4] ^ ls_box(t); \
- E_KEY[8 * i + 12] = t; \
- t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t; \
- t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t; \
- t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t; \
-}
-
-static int
-aes_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags)
-{
- struct aes_ctx *ctx = ctx_arg;
- u32 i, t, u, v, w;
-
- if (key_len != 16 && key_len != 24 && key_len != 32) {
- *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
- return -EINVAL;
- }
-
- ctx->key_length = key_len;
-
- E_KEY[0] = u32_in (in_key);
- E_KEY[1] = u32_in (in_key + 4);
- E_KEY[2] = u32_in (in_key + 8);
- E_KEY[3] = u32_in (in_key + 12);
-
- switch (key_len) {
- case 16:
- t = E_KEY[3];
- for (i = 0; i < 10; ++i)
- loop4 (i);
- break;
-
- case 24:
- E_KEY[4] = u32_in (in_key + 16);
- t = E_KEY[5] = u32_in (in_key + 20);
- for (i = 0; i < 8; ++i)
- loop6 (i);
- break;
-
- case 32:
- E_KEY[4] = u32_in (in_key + 16);
- E_KEY[5] = u32_in (in_key + 20);
- E_KEY[6] = u32_in (in_key + 24);
- t = E_KEY[7] = u32_in (in_key + 28);
- for (i = 0; i < 7; ++i)
- loop8 (i);
- break;
- }
-
- D_KEY[0] = E_KEY[0];
- D_KEY[1] = E_KEY[1];
- D_KEY[2] = E_KEY[2];
- D_KEY[3] = E_KEY[3];
-
- for (i = 4; i < key_len + 24; ++i) {
- imix_col (D_KEY[i], E_KEY[i]);
- }
-
- return 0;
-}
-
-/* encrypt a block of text */
-
-#define f_nround(bo, bi, k) \
- f_rn(bo, bi, 0, k); \
- f_rn(bo, bi, 1, k); \
- f_rn(bo, bi, 2, k); \
- f_rn(bo, bi, 3, k); \
- k += 4
-
-#define f_lround(bo, bi, k) \
- f_rl(bo, bi, 0, k); \
- f_rl(bo, bi, 1, k); \
- f_rl(bo, bi, 2, k); \
- f_rl(bo, bi, 3, k)
-
-static void aes_encrypt(void *ctx_arg, u8 *out, const u8 *in)
-{
- const struct aes_ctx *ctx = ctx_arg;
- u32 b0[4], b1[4];
- const u32 *kp = E_KEY + 4;
-
- b0[0] = u32_in (in) ^ E_KEY[0];
- b0[1] = u32_in (in + 4) ^ E_KEY[1];
- b0[2] = u32_in (in + 8) ^ E_KEY[2];
- b0[3] = u32_in (in + 12) ^ E_KEY[3];
-
- if (ctx->key_length > 24) {
- f_nround (b1, b0, kp);
- f_nround (b0, b1, kp);
- }
-
- if (ctx->key_length > 16) {
- f_nround (b1, b0, kp);
- f_nround (b0, b1, kp);
- }
-
- f_nround (b1, b0, kp);
- f_nround (b0, b1, kp);
- f_nround (b1, b0, kp);
- f_nround (b0, b1, kp);
- f_nround (b1, b0, kp);
- f_nround (b0, b1, kp);
- f_nround (b1, b0, kp);
- f_nround (b0, b1, kp);
- f_nround (b1, b0, kp);
- f_lround (b0, b1, kp);
-
- u32_out (out, b0[0]);
- u32_out (out + 4, b0[1]);
- u32_out (out + 8, b0[2]);
- u32_out (out + 12, b0[3]);
-}
-
-/* decrypt a block of text */
-
-#define i_nround(bo, bi, k) \
- i_rn(bo, bi, 0, k); \
- i_rn(bo, bi, 1, k); \
- i_rn(bo, bi, 2, k); \
- i_rn(bo, bi, 3, k); \
- k -= 4
-
-#define i_lround(bo, bi, k) \
- i_rl(bo, bi, 0, k); \
- i_rl(bo, bi, 1, k); \
- i_rl(bo, bi, 2, k); \
- i_rl(bo, bi, 3, k)
-
-static void aes_decrypt(void *ctx_arg, u8 *out, const u8 *in)
-{
- const struct aes_ctx *ctx = ctx_arg;
- u32 b0[4], b1[4];
- const int key_len = ctx->key_length;
- const u32 *kp = D_KEY + key_len + 20;
-
- b0[0] = u32_in (in) ^ E_KEY[key_len + 24];
- b0[1] = u32_in (in + 4) ^ E_KEY[key_len + 25];
- b0[2] = u32_in (in + 8) ^ E_KEY[key_len + 26];
- b0[3] = u32_in (in + 12) ^ E_KEY[key_len + 27];
-
- if (key_len > 24) {
- i_nround (b1, b0, kp);
- i_nround (b0, b1, kp);
- }
-
- if (key_len > 16) {
- i_nround (b1, b0, kp);
- i_nround (b0, b1, kp);
- }
-
- i_nround (b1, b0, kp);
- i_nround (b0, b1, kp);
- i_nround (b1, b0, kp);
- i_nround (b0, b1, kp);
- i_nround (b1, b0, kp);
- i_nround (b0, b1, kp);
- i_nround (b1, b0, kp);
- i_nround (b0, b1, kp);
- i_nround (b1, b0, kp);
- i_lround (b0, b1, kp);
-
- u32_out (out, b0[0]);
- u32_out (out + 4, b0[1]);
- u32_out (out + 8, b0[2]);
- u32_out (out + 12, b0[3]);
-}
-
-
-static struct crypto_alg aes_alg = {
- .cra_name = "aes",
- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct aes_ctx),
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(aes_alg.cra_list),
- .cra_u = {
- .cipher = {
- .cia_min_keysize = AES_MIN_KEY_SIZE,
- .cia_max_keysize = AES_MAX_KEY_SIZE,
- .cia_setkey = aes_set_key,
- .cia_encrypt = aes_encrypt,
- .cia_decrypt = aes_decrypt
- }
- }
-};
-
-static int __init aes_init(void)
-{
- gen_tabs();
- return crypto_register_alg(&aes_alg);
-}
-
-static void __exit aes_fini(void)
-{
- crypto_unregister_alg(&aes_alg);
-}
-
-module_init(aes_init);
-module_exit(aes_fini);
-
-MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/staging/rtl8192u/ieee80211/arc4.c b/drivers/staging/rtl8192u/ieee80211/arc4.c
deleted file mode 100644
index b790e9ad104c..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/arc4.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Cryptographic API
- *
- * ARC4 Cipher Algorithm
- *
- * Jon Oberheide <jon@oberheide.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include "rtl_crypto.h"
-
-#define ARC4_MIN_KEY_SIZE 1
-#define ARC4_MAX_KEY_SIZE 256
-#define ARC4_BLOCK_SIZE 1
-
-struct arc4_ctx {
- u8 S[256];
- u8 x, y;
-};
-
-static int arc4_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags)
-{
- struct arc4_ctx *ctx = ctx_arg;
- int i, j = 0, k = 0;
-
- ctx->x = 1;
- ctx->y = 0;
-
- for(i = 0; i < 256; i++)
- ctx->S[i] = i;
-
- for(i = 0; i < 256; i++)
- {
- u8 a = ctx->S[i];
- j = (j + in_key[k] + a) & 0xff;
- ctx->S[i] = ctx->S[j];
- ctx->S[j] = a;
- if((unsigned int)++k >= key_len)
- k = 0;
- }
-
- return 0;
-}
-
-static void arc4_crypt(void *ctx_arg, u8 *out, const u8 *in)
-{
- struct arc4_ctx *ctx = ctx_arg;
-
- u8 *const S = ctx->S;
- u8 x = ctx->x;
- u8 y = ctx->y;
- u8 a, b;
-
- a = S[x];
- y = (y + a) & 0xff;
- b = S[y];
- S[x] = b;
- S[y] = a;
- x = (x + 1) & 0xff;
- *out++ = *in ^ S[(a + b) & 0xff];
-
- ctx->x = x;
- ctx->y = y;
-}
-
-static struct crypto_alg arc4_alg = {
- .cra_name = "arc4",
- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
- .cra_blocksize = ARC4_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct arc4_ctx),
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(arc4_alg.cra_list),
- .cra_u = { .cipher = {
- .cia_min_keysize = ARC4_MIN_KEY_SIZE,
- .cia_max_keysize = ARC4_MAX_KEY_SIZE,
- .cia_setkey = arc4_set_key,
- .cia_encrypt = arc4_crypt,
- .cia_decrypt = arc4_crypt } }
-};
-
-static int __init arc4_init(void)
-{
- return crypto_register_alg(&arc4_alg);
-}
-
-
-static void __exit arc4_exit(void)
-{
- crypto_unregister_alg(&arc4_alg);
-}
-
-module_init(arc4_init);
-module_exit(arc4_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ARC4 Cipher Algorithm");
-MODULE_AUTHOR("Jon Oberheide <jon@oberheide.org>");
diff --git a/drivers/staging/rtl8192u/ieee80211/autoload.c b/drivers/staging/rtl8192u/ieee80211/autoload.c
deleted file mode 100644
index c97756f3b2ea..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/autoload.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Algorithm autoloader.
- *
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- *
- * This program is free software; 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 "kmap_types.h"
-
-#include <linux/kernel.h>
-//#include <linux/crypto.h>
-#include "rtl_crypto.h"
-#include <linux/string.h>
-#include <linux/kmod.h>
-#include "internal.h"
-
-/*
- * A far more intelligent version of this is planned. For now, just
- * try an exact match on the name of the algorithm.
- */
-void crypto_alg_autoload(const char *name)
-{
- request_module(name);
-}
-
-struct crypto_alg *crypto_alg_mod_lookup(const char *name)
-{
- struct crypto_alg *alg = crypto_alg_lookup(name);
- if (alg == NULL) {
- crypto_alg_autoload(name);
- alg = crypto_alg_lookup(name);
- }
- return alg;
-}
diff --git a/drivers/staging/rtl8192u/ieee80211/cipher.c b/drivers/staging/rtl8192u/ieee80211/cipher.c
deleted file mode 100644
index d47345c4adcf..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/cipher.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Cipher operations.
- *
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- */
-#include <linux/kernel.h>
-//#include <linux/crypto.h>
-#include "rtl_crypto.h"
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <asm/scatterlist.h>
-#include "internal.h"
-#include "scatterwalk.h"
-
-typedef void (cryptfn_t)(void *, u8 *, const u8 *);
-typedef void (procfn_t)(struct crypto_tfm *, u8 *,
- u8*, cryptfn_t, int enc, void *, int);
-
-static inline void xor_64(u8 *a, const u8 *b)
-{
- ((u32 *)a)[0] ^= ((u32 *)b)[0];
- ((u32 *)a)[1] ^= ((u32 *)b)[1];
-}
-
-static inline void xor_128(u8 *a, const u8 *b)
-{
- ((u32 *)a)[0] ^= ((u32 *)b)[0];
- ((u32 *)a)[1] ^= ((u32 *)b)[1];
- ((u32 *)a)[2] ^= ((u32 *)b)[2];
- ((u32 *)a)[3] ^= ((u32 *)b)[3];
-}
-
-
-/*
- * Generic encrypt/decrypt wrapper for ciphers, handles operations across
- * multiple page boundaries by using temporary blocks. In user context,
- * the kernel is given a chance to schedule us once per block.
- */
-static int crypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, cryptfn_t crfn,
- procfn_t prfn, int enc, void *info)
-{
- struct scatter_walk walk_in, walk_out;
- const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
- u8 tmp_src[bsize];
- u8 tmp_dst[bsize];
-
- if (!nbytes)
- return 0;
-
- if (nbytes % bsize) {
- tfm->crt_flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
- return -EINVAL;
- }
-
- scatterwalk_start(&walk_in, src);
- scatterwalk_start(&walk_out, dst);
-
- for(;;) {
- u8 *src_p, *dst_p;
- int in_place;
-
- scatterwalk_map(&walk_in);
- scatterwalk_map(&walk_out);
- src_p = scatterwalk_whichbuf(&walk_in, bsize, tmp_src);
- dst_p = scatterwalk_whichbuf(&walk_out, bsize, tmp_dst);
- in_place = scatterwalk_samebuf(&walk_in, &walk_out,
- src_p, dst_p);
-
- nbytes -= bsize;
-
- scatterwalk_copychunks(src_p, &walk_in, bsize, 0);
-
- prfn(tfm, dst_p, src_p, crfn, enc, info, in_place);
-
- scatterwalk_done(&walk_in, nbytes);
-
- scatterwalk_copychunks(dst_p, &walk_out, bsize, 1);
- scatterwalk_done(&walk_out, nbytes);
-
- if (!nbytes)
- return 0;
-
- crypto_yield(tfm);
- }
-}
-
-static void cbc_process(struct crypto_tfm *tfm, u8 *dst, u8 *src,
- cryptfn_t fn, int enc, void *info, int in_place)
-{
- u8 *iv = info;
-
- /* Null encryption */
- if (!iv)
- return;
-
- if (enc) {
- tfm->crt_u.cipher.cit_xor_block(iv, src);
- fn(crypto_tfm_ctx(tfm), dst, iv);
- memcpy(iv, dst, crypto_tfm_alg_blocksize(tfm));
- } else {
- u8 stack[in_place ? crypto_tfm_alg_blocksize(tfm) : 0];
- u8 *buf = in_place ? stack : dst;
-
- fn(crypto_tfm_ctx(tfm), buf, src);
- tfm->crt_u.cipher.cit_xor_block(buf, iv);
- memcpy(iv, src, crypto_tfm_alg_blocksize(tfm));
- if (buf != dst)
- memcpy(dst, buf, crypto_tfm_alg_blocksize(tfm));
- }
-}
-
-static void ecb_process(struct crypto_tfm *tfm, u8 *dst, u8 *src,
- cryptfn_t fn, int enc, void *info, int in_place)
-{
- fn(crypto_tfm_ctx(tfm), dst, src);
-}
-
-static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
-{
- struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
-
- if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) {
- tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
- return -EINVAL;
- } else
- return cia->cia_setkey(crypto_tfm_ctx(tfm), key, keylen,
- &tfm->crt_flags);
-}
-
-static int ecb_encrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return crypt(tfm, dst, src, nbytes,
- tfm->__crt_alg->cra_cipher.cia_encrypt,
- ecb_process, 1, NULL);
-}
-
-static int ecb_decrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- return crypt(tfm, dst, src, nbytes,
- tfm->__crt_alg->cra_cipher.cia_decrypt,
- ecb_process, 1, NULL);
-}
-
-static int cbc_encrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- return crypt(tfm, dst, src, nbytes,
- tfm->__crt_alg->cra_cipher.cia_encrypt,
- cbc_process, 1, tfm->crt_cipher.cit_iv);
-}
-
-static int cbc_encrypt_iv(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv)
-{
- return crypt(tfm, dst, src, nbytes,
- tfm->__crt_alg->cra_cipher.cia_encrypt,
- cbc_process, 1, iv);
-}
-
-static int cbc_decrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- return crypt(tfm, dst, src, nbytes,
- tfm->__crt_alg->cra_cipher.cia_decrypt,
- cbc_process, 0, tfm->crt_cipher.cit_iv);
-}
-
-static int cbc_decrypt_iv(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv)
-{
- return crypt(tfm, dst, src, nbytes,
- tfm->__crt_alg->cra_cipher.cia_decrypt,
- cbc_process, 0, iv);
-}
-
-static int nocrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- return -ENOSYS;
-}
-
-static int nocrypt_iv(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv)
-{
- return -ENOSYS;
-}
-
-int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags)
-{
- u32 mode = flags & CRYPTO_TFM_MODE_MASK;
-
- tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB;
- if (flags & CRYPTO_TFM_REQ_WEAK_KEY)
- tfm->crt_flags = CRYPTO_TFM_REQ_WEAK_KEY;
-
- return 0;
-}
-
-int crypto_init_cipher_ops(struct crypto_tfm *tfm)
-{
- int ret = 0;
- struct cipher_tfm *ops = &tfm->crt_cipher;
-
- ops->cit_setkey = setkey;
-
- switch (tfm->crt_cipher.cit_mode) {
- case CRYPTO_TFM_MODE_ECB:
- ops->cit_encrypt = ecb_encrypt;
- ops->cit_decrypt = ecb_decrypt;
- break;
-
- case CRYPTO_TFM_MODE_CBC:
- ops->cit_encrypt = cbc_encrypt;
- ops->cit_decrypt = cbc_decrypt;
- ops->cit_encrypt_iv = cbc_encrypt_iv;
- ops->cit_decrypt_iv = cbc_decrypt_iv;
- break;
-
- case CRYPTO_TFM_MODE_CFB:
- ops->cit_encrypt = nocrypt;
- ops->cit_decrypt = nocrypt;
- ops->cit_encrypt_iv = nocrypt_iv;
- ops->cit_decrypt_iv = nocrypt_iv;
- break;
-
- case CRYPTO_TFM_MODE_CTR:
- ops->cit_encrypt = nocrypt;
- ops->cit_decrypt = nocrypt;
- ops->cit_encrypt_iv = nocrypt_iv;
- ops->cit_decrypt_iv = nocrypt_iv;
- break;
-
- default:
- BUG();
- }
-
- if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) {
-
- switch (crypto_tfm_alg_blocksize(tfm)) {
- case 8:
- ops->cit_xor_block = xor_64;
- break;
-
- case 16:
- ops->cit_xor_block = xor_128;
- break;
-
- default:
- printk(KERN_WARNING "%s: block size %u not supported\n",
- crypto_tfm_alg_name(tfm),
- crypto_tfm_alg_blocksize(tfm));
- ret = -EINVAL;
- goto out;
- }
-
- ops->cit_ivsize = crypto_tfm_alg_blocksize(tfm);
- ops->cit_iv = kmalloc(ops->cit_ivsize, GFP_KERNEL);
- if (ops->cit_iv == NULL)
- ret = -ENOMEM;
- }
-
-out:
- return ret;
-}
-
-void crypto_exit_cipher_ops(struct crypto_tfm *tfm)
-{
- kfree(tfm->crt_cipher.cit_iv);
-}
diff --git a/drivers/staging/rtl8192u/ieee80211/compress.c b/drivers/staging/rtl8192u/ieee80211/compress.c
deleted file mode 100644
index 5416ab63a738..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/compress.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Compression operations.
- *
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- *
- * This program is free software; 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/types.h>
-/*#include <linux/crypto.h>*/
-#include "rtl_crypto.h"
-#include <linux/errno.h>
-#include <linux/scatterlist.h>
-#include <linux/string.h>
-#include "internal.h"
-
-static int crypto_compress(struct crypto_tfm *tfm,
- const u8 *src, unsigned int slen,
- u8 *dst, unsigned int *dlen)
-{
- return tfm->__crt_alg->cra_compress.coa_compress(crypto_tfm_ctx(tfm),
- src, slen, dst,
- dlen);
-}
-
-static int crypto_decompress(struct crypto_tfm *tfm,
- const u8 *src, unsigned int slen,
- u8 *dst, unsigned int *dlen)
-{
- return tfm->__crt_alg->cra_compress.coa_decompress(crypto_tfm_ctx(tfm),
- src, slen, dst,
- dlen);
-}
-
-int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags)
-{
- return flags ? -EINVAL : 0;
-}
-
-int crypto_init_compress_ops(struct crypto_tfm *tfm)
-{
- int ret = 0;
- struct compress_tfm *ops = &tfm->crt_compress;
-
- ret = tfm->__crt_alg->cra_compress.coa_init(crypto_tfm_ctx(tfm));
- if (ret)
- goto out;
-
- ops->cot_compress = crypto_compress;
- ops->cot_decompress = crypto_decompress;
-
-out:
- return ret;
-}
-
-void crypto_exit_compress_ops(struct crypto_tfm *tfm)
-{
- tfm->__crt_alg->cra_compress.coa_exit(crypto_tfm_ctx(tfm));
-}
diff --git a/drivers/staging/rtl8192u/ieee80211/crypto_compat.h b/drivers/staging/rtl8192u/ieee80211/crypto_compat.h
deleted file mode 100644
index 2ba374a64178..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/crypto_compat.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Header file to maintain compatibility among different kernel versions.
- *
- * Copyright (c) 2004-2006 <lawrence_wang@realsil.com.cn>
- *
- * 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 README and COPYING for
- * more details.
- */
-
-#include <linux/crypto.h>
-
-static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes);
-}
-
-
-static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes);
-}
-
- struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
-{
- struct crypto_tfm *tfm = NULL;
- int err;
- printk("call crypto_alloc_tfm!!!\n");
- do {
- struct crypto_alg *alg;
-
- alg = crypto_alg_mod_lookup(name, 0, CRYPTO_ALG_ASYNC);
- err = PTR_ERR(alg);
- if (IS_ERR(alg))
- continue;
-
- tfm = __crypto_alloc_tfm(alg, flags);
- err = 0;
- if (IS_ERR(tfm)) {
- crypto_mod_put(alg);
- err = PTR_ERR(tfm);
- tfm = NULL;
- }
- } while (err == -EAGAIN && !signal_pending(current));
-
- return tfm;
-}
-//EXPORT_SYMBOL_GPL(crypto_alloc_tfm);
-//EXPORT_SYMBOL_GPL(crypto_free_tfm);
diff --git a/drivers/staging/rtl8192u/ieee80211/digest.c b/drivers/staging/rtl8192u/ieee80211/digest.c
deleted file mode 100644
index 05e7497fd106..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/digest.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Digest operations.
- *
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- *
- * This program is free software; 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/crypto.h>
-#include "rtl_crypto.h"
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/highmem.h>
-#include <asm/scatterlist.h>
-#include "internal.h"
-
-static void init(struct crypto_tfm *tfm)
-{
- tfm->__crt_alg->cra_digest.dia_init(crypto_tfm_ctx(tfm));
-}
-
-static void update(struct crypto_tfm *tfm,
- struct scatterlist *sg, unsigned int nsg)
-{
- unsigned int i;
-
- for (i = 0; i < nsg; i++) {
-
- struct page *pg = sg[i].page;
- unsigned int offset = sg[i].offset;
- unsigned int l = sg[i].length;
-
- do {
- unsigned int bytes_from_page = min(l, ((unsigned int)
- (PAGE_SIZE)) -
- offset);
- char *p = kmap_atomic(pg) + offset;
-
- tfm->__crt_alg->cra_digest.dia_update
- (crypto_tfm_ctx(tfm), p,
- bytes_from_page);
- kunmap_atomic(p);
- crypto_yield(tfm);
- offset = 0;
- pg++;
- l -= bytes_from_page;
- } while (l > 0);
- }
-}
-
-static void final(struct crypto_tfm *tfm, u8 *out)
-{
- tfm->__crt_alg->cra_digest.dia_final(crypto_tfm_ctx(tfm), out);
-}
-
-static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
-{
- u32 flags;
- if (tfm->__crt_alg->cra_digest.dia_setkey == NULL)
- return -ENOSYS;
- return tfm->__crt_alg->cra_digest.dia_setkey(crypto_tfm_ctx(tfm),
- key, keylen, &flags);
-}
-
-static void digest(struct crypto_tfm *tfm,
- struct scatterlist *sg, unsigned int nsg, u8 *out)
-{
- unsigned int i;
-
- tfm->crt_digest.dit_init(tfm);
-
- for (i = 0; i < nsg; i++) {
- char *p = kmap_atomic(sg[i].page) + sg[i].offset;
- tfm->__crt_alg->cra_digest.dia_update(crypto_tfm_ctx(tfm),
- p, sg[i].length);
- kunmap_atomic(p);
- crypto_yield(tfm);
- }
- crypto_digest_final(tfm, out);
-}
-
-int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags)
-{
- return flags ? -EINVAL : 0;
-}
-
-int crypto_init_digest_ops(struct crypto_tfm *tfm)
-{
- struct digest_tfm *ops = &tfm->crt_digest;
-
- ops->dit_init = init;
- ops->dit_update = update;
- ops->dit_final = final;
- ops->dit_digest = digest;
- ops->dit_setkey = setkey;
-
- return crypto_alloc_hmac_block(tfm);
-}
-
-void crypto_exit_digest_ops(struct crypto_tfm *tfm)
-{
- crypto_free_hmac_block(tfm);
-}
diff --git a/drivers/staging/rtl8192u/ieee80211/dot11d.c b/drivers/staging/rtl8192u/ieee80211/dot11d.c
index 34edcfab96be..90ace791f2d7 100644
--- a/drivers/staging/rtl8192u/ieee80211/dot11d.c
+++ b/drivers/staging/rtl8192u/ieee80211/dot11d.c
@@ -1,16 +1,8 @@
-//-----------------------------------------------------------------------------
-// File:
-// Dot11d.c
-//
-// Description:
-// Implement 802.11d.
-//
-//-----------------------------------------------------------------------------
+/* Implement 802.11d. */
#include "dot11d.h"
-void
-Dot11d_Init(struct ieee80211_device *ieee)
+void Dot11d_Init(struct ieee80211_device *ieee)
{
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee);
@@ -22,55 +14,42 @@ Dot11d_Init(struct ieee80211_device *ieee)
memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
RESET_CIE_WATCHDOG(ieee);
- printk("Dot11d_Init()\n");
+ netdev_info(ieee->dev, "Dot11d_Init()\n");
}
+EXPORT_SYMBOL(Dot11d_Init);
-//
-// Description:
-// Reset to the state as we are just entering a regulatory domain.
-//
-void
-Dot11d_Reset(struct ieee80211_device *ieee)
+/* Reset to the state as we are just entering a regulatory domain. */
+void Dot11d_Reset(struct ieee80211_device *ieee)
{
u32 i;
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee);
- // Clear old channel map
+ /* Clear old channel map */
memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
- // Set new channel map
- for (i=1; i<=11; i++) {
+ /* Set new channel map */
+ for (i = 1; i <= 11; i++)
(pDot11dInfo->channel_map)[i] = 1;
- }
- for (i=12; i<=14; i++) {
+
+ for (i = 12; i <= 14; i++)
(pDot11dInfo->channel_map)[i] = 2;
- }
pDot11dInfo->State = DOT11D_STATE_NONE;
pDot11dInfo->CountryIeLen = 0;
RESET_CIE_WATCHDOG(ieee);
-
- //printk("Dot11d_Reset()\n");
}
+EXPORT_SYMBOL(Dot11d_Reset);
-//
-// Description:
-// Update country IE from Beacon or Probe Resopnse
-// and configure PHY for operation in the regulatory domain.
-//
-// TODO:
-// Configure Tx power.
-//
-// Assumption:
-// 1. IS_DOT11D_ENABLE() is TRUE.
-// 2. Input IE is an valid one.
-//
-void
-Dot11d_UpdateCountryIe(
- struct ieee80211_device *dev,
- u8 *pTaddr,
- u16 CoutryIeLen,
- u8 *pCoutryIe
- )
+/*
+ * Update country IE from Beacon or Probe Resopnse and configure PHY for
+ * operation in the regulatory domain.
+ *
+ * TODO: Configure Tx power.
+ * Assumption:
+ * 1. IS_DOT11D_ENABLE() is TRUE.
+ * 2. Input IE is an valid one.
+ */
+void Dot11d_UpdateCountryIe(struct ieee80211_device *dev, u8 *pTaddr,
+ u16 CoutryIeLen, u8 *pCoutryIe)
{
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
u8 i, j, NumTriples, MaxChnlNum;
@@ -79,23 +58,25 @@ Dot11d_UpdateCountryIe(
memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
MaxChnlNum = 0;
- NumTriples = (CoutryIeLen - 3) / 3; // skip 3-byte country string.
+ NumTriples = (CoutryIeLen - 3) / 3; /* skip 3-byte country string. */
pTriple = (PCHNL_TXPOWER_TRIPLE)(pCoutryIe + 3);
- for(i = 0; i < NumTriples; i++)
- {
- if(MaxChnlNum >= pTriple->FirstChnl)
- { // It is not in a monotonically increasing order, so stop processing.
- printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n");
+ for (i = 0; i < NumTriples; i++) {
+ if (MaxChnlNum >= pTriple->FirstChnl) {
+ /* It is not in a monotonically increasing order, so
+ * stop processing.
+ */
+ netdev_err(dev->dev, "Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n");
return;
}
- if(MAX_CHANNEL_NUMBER < (pTriple->FirstChnl + pTriple->NumChnls))
- { // It is not a valid set of channel id, so stop processing.
- printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n");
+ if (MAX_CHANNEL_NUMBER < (pTriple->FirstChnl + pTriple->NumChnls)) {
+ /* It is not a valid set of channel id, so stop
+ * processing.
+ */
+ netdev_err(dev->dev, "Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n");
return;
}
- for(j = 0 ; j < pTriple->NumChnls; j++)
- {
+ for (j = 0; j < pTriple->NumChnls; j++) {
pDot11dInfo->channel_map[pTriple->FirstChnl + j] = 1;
pDot11dInfo->MaxTxPwrDbmList[pTriple->FirstChnl + j] = pTriple->MaxTxPowerInDbm;
MaxChnlNum = pTriple->FirstChnl + j;
@@ -103,60 +84,48 @@ Dot11d_UpdateCountryIe(
pTriple = (PCHNL_TXPOWER_TRIPLE)((u8 *)pTriple + 3);
}
- //printk("Dot11d_UpdateCountryIe(): Channel List:\n");
- printk("Channel List:");
- for(i=1; i<= MAX_CHANNEL_NUMBER; i++)
- if(pDot11dInfo->channel_map[i] > 0)
- printk(" %d", i);
- printk("\n");
+ netdev_info(dev->dev, "Channel List:");
+ for (i = 1; i <= MAX_CHANNEL_NUMBER; i++)
+ if (pDot11dInfo->channel_map[i] > 0)
+ netdev_info(dev->dev, " %d", i);
+ netdev_info(dev->dev, "\n");
UPDATE_CIE_SRC(dev, pTaddr);
pDot11dInfo->CountryIeLen = CoutryIeLen;
- memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe,CoutryIeLen);
+ memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe, CoutryIeLen);
pDot11dInfo->State = DOT11D_STATE_LEARNED;
}
+EXPORT_SYMBOL(Dot11d_UpdateCountryIe);
-
-u8
-DOT11D_GetMaxTxPwrInDbm(
- struct ieee80211_device *dev,
- u8 Channel
- )
+u8 DOT11D_GetMaxTxPwrInDbm(struct ieee80211_device *dev, u8 Channel)
{
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
u8 MaxTxPwrInDbm = 255;
- if(MAX_CHANNEL_NUMBER < Channel)
- {
- printk("DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n");
+ if (MAX_CHANNEL_NUMBER < Channel) {
+ netdev_err(dev->dev, "DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n");
return MaxTxPwrInDbm;
}
- if(pDot11dInfo->channel_map[Channel])
- {
+ if (pDot11dInfo->channel_map[Channel])
MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel];
- }
return MaxTxPwrInDbm;
}
+EXPORT_SYMBOL(DOT11D_GetMaxTxPwrInDbm);
-
-void
-DOT11D_ScanComplete(
- struct ieee80211_device *dev
- )
+void DOT11D_ScanComplete(struct ieee80211_device *dev)
{
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
- switch (pDot11dInfo->State)
- {
+ switch (pDot11dInfo->State) {
case DOT11D_STATE_LEARNED:
pDot11dInfo->State = DOT11D_STATE_DONE;
break;
case DOT11D_STATE_DONE:
- if( GET_CIE_WATCHDOG(dev) == 0 )
- { // Reset country IE if previous one is gone.
+ if (GET_CIE_WATCHDOG(dev) == 0) {
+ /* Reset country IE if previous one is gone. */
Dot11d_Reset(dev);
}
break;
@@ -164,57 +133,43 @@ DOT11D_ScanComplete(
break;
}
}
+EXPORT_SYMBOL(DOT11D_ScanComplete);
-int IsLegalChannel(
- struct ieee80211_device *dev,
- u8 channel
-)
+int IsLegalChannel(struct ieee80211_device *dev, u8 channel)
{
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
- if(MAX_CHANNEL_NUMBER < channel)
- {
- printk("IsLegalChannel(): Invalid Channel\n");
+ if (MAX_CHANNEL_NUMBER < channel) {
+ netdev_err(dev->dev, "IsLegalChannel(): Invalid Channel\n");
return 0;
}
- if(pDot11dInfo->channel_map[channel] > 0)
+ if (pDot11dInfo->channel_map[channel] > 0)
return 1;
return 0;
}
+EXPORT_SYMBOL(IsLegalChannel);
-int ToLegalChannel(
- struct ieee80211_device *dev,
- u8 channel
-)
+int ToLegalChannel(struct ieee80211_device *dev, u8 channel)
{
PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
u8 default_chn = 0;
u32 i = 0;
- for (i=1; i<= MAX_CHANNEL_NUMBER; i++)
- {
- if(pDot11dInfo->channel_map[i] > 0)
- {
+ for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) {
+ if (pDot11dInfo->channel_map[i] > 0) {
default_chn = i;
break;
}
}
- if(MAX_CHANNEL_NUMBER < channel)
- {
- printk("IsLegalChannel(): Invalid Channel\n");
+ if (MAX_CHANNEL_NUMBER < channel) {
+ netdev_err(dev->dev, "IsLegalChannel(): Invalid Channel\n");
return default_chn;
}
- if(pDot11dInfo->channel_map[channel] > 0)
+ if (pDot11dInfo->channel_map[channel] > 0)
return channel;
return default_chn;
}
-EXPORT_SYMBOL(Dot11d_Init);
-EXPORT_SYMBOL(Dot11d_Reset);
-EXPORT_SYMBOL(Dot11d_UpdateCountryIe);
-EXPORT_SYMBOL(DOT11D_GetMaxTxPwrInDbm);
-EXPORT_SYMBOL(DOT11D_ScanComplete);
-EXPORT_SYMBOL(IsLegalChannel);
EXPORT_SYMBOL(ToLegalChannel);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
index bc64f05a7e6a..cac2056b7f82 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
@@ -1152,7 +1152,7 @@ struct ieee80211_probe_request {
struct ieee80211_probe_response {
struct ieee80211_hdr_3addr header;
- u32 time_stamp[2];
+ __le32 time_stamp[2];
__le16 beacon_interval;
__le16 capability;
/* SSID, supported rates, FH params, DS params,
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
index e730ed64c0fe..a98414a72bf5 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
@@ -517,11 +517,8 @@ drop:
return 1;
}
-bool
-AddReorderEntry(
- PRX_TS_RECORD pTS,
- PRX_REORDER_ENTRY pReorderEntry
- )
+
+static bool AddReorderEntry(PRX_TS_RECORD pTS, PRX_REORDER_ENTRY pReorderEntry)
{
struct list_head *pList = &pTS->RxPendingPktList;
while(pList->next != &pTS->RxPendingPktList)
@@ -601,10 +598,9 @@ void ieee80211_indicate_packets(struct ieee80211_device *ieee, struct ieee80211_
}
-void RxReorderIndicatePacket( struct ieee80211_device *ieee,
- struct ieee80211_rxb *prxb,
- PRX_TS_RECORD pTS,
- u16 SeqNum)
+static void RxReorderIndicatePacket(struct ieee80211_device *ieee,
+ struct ieee80211_rxb *prxb,
+ PRX_TS_RECORD pTS, u16 SeqNum)
{
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
PRX_REORDER_ENTRY pReorderEntry = NULL;
@@ -771,9 +767,9 @@ void RxReorderIndicatePacket( struct ieee80211_device *ieee,
}
}
-u8 parse_subframe(struct sk_buff *skb,
- struct ieee80211_rx_stats *rx_stats,
- struct ieee80211_rxb *rxb,u8 *src,u8 *dst)
+static u8 parse_subframe(struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats,
+ struct ieee80211_rxb *rxb,u8 *src,u8 *dst)
{
struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)skb->data;
u16 fc = le16_to_cpu(hdr->frame_ctl);
@@ -2200,7 +2196,7 @@ static inline int ieee80211_network_init(
network->last_scanned = jiffies;
network->time_stamp[0] = le32_to_cpu(beacon->time_stamp[0]);
network->time_stamp[1] = le32_to_cpu(beacon->time_stamp[1]);
- network->beacon_interval = le32_to_cpu(beacon->beacon_interval);
+ network->beacon_interval = le16_to_cpu(beacon->beacon_interval);
/* Where to pull this? beacon->listen_interval;*/
network->listen_interval = 0x0A;
network->rates_len = network->rates_ex_len = 0;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
index 662c7e41cd5c..2131912113d7 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
@@ -24,15 +24,6 @@
#include "dot11d.h"
-u8 rsn_authen_cipher_suite[16][4] = {
- {0x00,0x0F,0xAC,0x00}, //Use group key, //Reserved
- {0x00,0x0F,0xAC,0x01}, //WEP-40 //RSNA default
- {0x00,0x0F,0xAC,0x02}, //TKIP //NONE //{used just as default}
- {0x00,0x0F,0xAC,0x03}, //WRAP-historical
- {0x00,0x0F,0xAC,0x04}, //CCMP
- {0x00,0x0F,0xAC,0x05}, //WEP-104
-};
-
short ieee80211_is_54g(const struct ieee80211_network *net)
{
return (net->rates_ex_len > 0) || (net->rates_len > 4);
@@ -47,7 +38,7 @@ short ieee80211_is_shortslot(const struct ieee80211_network *net)
* tag and the EXTENDED RATE MFIE tag if needed.
* It encludes two bytes per tag for the tag itself and its len
*/
-unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee)
+static unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee)
{
unsigned int rate_len = 0;
@@ -65,7 +56,7 @@ unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee)
* Then it updates the pointer so that
* it points after the new MFIE tag added.
*/
-void ieee80211_MFIE_Brate(struct ieee80211_device *ieee, u8 **tag_p)
+static void ieee80211_MFIE_Brate(struct ieee80211_device *ieee, u8 **tag_p)
{
u8 *tag = *tag_p;
@@ -82,7 +73,7 @@ void ieee80211_MFIE_Brate(struct ieee80211_device *ieee, u8 **tag_p)
*tag_p = tag;
}
-void ieee80211_MFIE_Grate(struct ieee80211_device *ieee, u8 **tag_p)
+static void ieee80211_MFIE_Grate(struct ieee80211_device *ieee, u8 **tag_p)
{
u8 *tag = *tag_p;
@@ -106,7 +97,8 @@ void ieee80211_MFIE_Grate(struct ieee80211_device *ieee, u8 **tag_p)
}
-void ieee80211_WMM_Info(struct ieee80211_device *ieee, u8 **tag_p) {
+static void ieee80211_WMM_Info(struct ieee80211_device *ieee, u8 **tag_p)
+{
u8 *tag = *tag_p;
*tag++ = MFIE_TYPE_GENERIC; //0
@@ -148,7 +140,7 @@ void ieee80211_TURBO_Info(struct ieee80211_device *ieee, u8 **tag_p) {
}
#endif
-void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb)
+static void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb)
{
int nh;
nh = (ieee->mgmt_queue_head +1) % MGMT_QUEUE_NUM;
@@ -166,7 +158,7 @@ void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb)
//return 0;
}
-struct sk_buff *dequeue_mgmt(struct ieee80211_device *ieee)
+static struct sk_buff *dequeue_mgmt(struct ieee80211_device *ieee)
{
struct sk_buff *ret;
@@ -181,12 +173,12 @@ struct sk_buff *dequeue_mgmt(struct ieee80211_device *ieee)
return ret;
}
-void init_mgmt_queue(struct ieee80211_device *ieee)
+static void init_mgmt_queue(struct ieee80211_device *ieee)
{
ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0;
}
-u8 MgntQuery_MgntFrameTxRate(struct ieee80211_device *ieee)
+static u8 MgntQuery_MgntFrameTxRate(struct ieee80211_device *ieee)
{
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
u8 rate;
@@ -365,7 +357,8 @@ inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee)
}
struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee);
-void ieee80211_send_beacon(struct ieee80211_device *ieee)
+
+static void ieee80211_send_beacon(struct ieee80211_device *ieee)
{
struct sk_buff *skb;
if(!ieee->ieee_up)
@@ -391,7 +384,7 @@ void ieee80211_send_beacon(struct ieee80211_device *ieee)
}
-void ieee80211_send_beacon_cb(unsigned long _ieee)
+static void ieee80211_send_beacon_cb(unsigned long _ieee)
{
struct ieee80211_device *ieee =
(struct ieee80211_device *) _ieee;
@@ -403,7 +396,7 @@ void ieee80211_send_beacon_cb(unsigned long _ieee)
}
-void ieee80211_send_probe(struct ieee80211_device *ieee)
+static void ieee80211_send_probe(struct ieee80211_device *ieee)
{
struct sk_buff *skb;
@@ -494,7 +487,7 @@ out:
}
-void ieee80211_softmac_scan_wq(struct work_struct *work)
+static void ieee80211_softmac_scan_wq(struct work_struct *work)
{
struct delayed_work *dwork = container_of(work, struct delayed_work, work);
struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq);
@@ -538,7 +531,7 @@ out:
-void ieee80211_beacons_start(struct ieee80211_device *ieee)
+static void ieee80211_beacons_start(struct ieee80211_device *ieee)
{
unsigned long flags;
spin_lock_irqsave(&ieee->beacon_lock,flags);
@@ -549,7 +542,7 @@ void ieee80211_beacons_start(struct ieee80211_device *ieee)
spin_unlock_irqrestore(&ieee->beacon_lock,flags);
}
-void ieee80211_beacons_stop(struct ieee80211_device *ieee)
+static void ieee80211_beacons_stop(struct ieee80211_device *ieee)
{
unsigned long flags;
@@ -581,7 +574,7 @@ void ieee80211_start_send_beacons(struct ieee80211_device *ieee)
}
-void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee)
+static void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee)
{
// unsigned long flags;
@@ -609,7 +602,7 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee)
}
/* called with ieee->lock held */
-void ieee80211_start_scan(struct ieee80211_device *ieee)
+static void ieee80211_start_scan(struct ieee80211_device *ieee)
{
if(IS_DOT11D_ENABLE(ieee) )
{
@@ -841,7 +834,8 @@ static struct sk_buff *ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *d
}
-struct sk_buff *ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest)
+static struct sk_buff *ieee80211_assoc_resp(struct ieee80211_device *ieee,
+ u8 *dest)
{
struct sk_buff *skb;
u8 *tag;
@@ -896,7 +890,8 @@ struct sk_buff *ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest)
return skb;
}
-struct sk_buff *ieee80211_auth_resp(struct ieee80211_device *ieee,int status, u8 *dest)
+static struct sk_buff *ieee80211_auth_resp(struct ieee80211_device *ieee,
+ int status, u8 *dest)
{
struct sk_buff *skb;
struct ieee80211_authentication *auth;
@@ -924,7 +919,8 @@ struct sk_buff *ieee80211_auth_resp(struct ieee80211_device *ieee,int status, u8
}
-struct sk_buff *ieee80211_null_func(struct ieee80211_device *ieee,short pwr)
+static struct sk_buff *ieee80211_null_func(struct ieee80211_device *ieee,
+ short pwr)
{
struct sk_buff *skb;
struct ieee80211_hdr_3addr *hdr;
@@ -950,7 +946,7 @@ struct sk_buff *ieee80211_null_func(struct ieee80211_device *ieee,short pwr)
}
-void ieee80211_resp_to_assoc_rq(struct ieee80211_device *ieee, u8 *dest)
+static void ieee80211_resp_to_assoc_rq(struct ieee80211_device *ieee, u8 *dest)
{
struct sk_buff *buf = ieee80211_assoc_resp(ieee, dest);
@@ -959,7 +955,8 @@ void ieee80211_resp_to_assoc_rq(struct ieee80211_device *ieee, u8 *dest)
}
-void ieee80211_resp_to_auth(struct ieee80211_device *ieee, int s, u8 *dest)
+static void ieee80211_resp_to_auth(struct ieee80211_device *ieee, int s,
+ u8 *dest)
{
struct sk_buff *buf = ieee80211_auth_resp(ieee, s, dest);
@@ -968,7 +965,7 @@ void ieee80211_resp_to_auth(struct ieee80211_device *ieee, int s, u8 *dest)
}
-void ieee80211_resp_to_probe(struct ieee80211_device *ieee, u8 *dest)
+static void ieee80211_resp_to_probe(struct ieee80211_device *ieee, u8 *dest)
{
@@ -1250,13 +1247,13 @@ void ieee80211_associate_abort(struct ieee80211_device *ieee)
spin_unlock_irqrestore(&ieee->lock, flags);
}
-void ieee80211_associate_abort_cb(unsigned long dev)
+static void ieee80211_associate_abort_cb(unsigned long dev)
{
ieee80211_associate_abort((struct ieee80211_device *) dev);
}
-void ieee80211_associate_step1(struct ieee80211_device *ieee)
+static void ieee80211_associate_step1(struct ieee80211_device *ieee)
{
struct ieee80211_network *beacon = &ieee->current_network;
struct sk_buff *skb;
@@ -1282,7 +1279,9 @@ void ieee80211_associate_step1(struct ieee80211_device *ieee)
}
}
-void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
+static void ieee80211_auth_challenge(struct ieee80211_device *ieee,
+ u8 *challenge,
+ int chlen)
{
u8 *c;
struct sk_buff *skb;
@@ -1312,7 +1311,7 @@ void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int
kfree(challenge);
}
-void ieee80211_associate_step2(struct ieee80211_device *ieee)
+static void ieee80211_associate_step2(struct ieee80211_device *ieee)
{
struct sk_buff *skb;
struct ieee80211_network *beacon = &ieee->current_network;
@@ -1331,7 +1330,7 @@ void ieee80211_associate_step2(struct ieee80211_device *ieee)
//dev_kfree_skb_any(skb);//edit by thomas
}
}
-void ieee80211_associate_complete_wq(struct work_struct *work)
+static void ieee80211_associate_complete_wq(struct work_struct *work)
{
struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_complete_wq);
printk(KERN_INFO "Associated successfully\n");
@@ -1378,7 +1377,7 @@ void ieee80211_associate_complete_wq(struct work_struct *work)
netif_carrier_on(ieee->dev);
}
-void ieee80211_associate_complete(struct ieee80211_device *ieee)
+static void ieee80211_associate_complete(struct ieee80211_device *ieee)
{
// int i;
// struct net_device* dev = ieee->dev;
@@ -1389,7 +1388,7 @@ void ieee80211_associate_complete(struct ieee80211_device *ieee)
queue_work(ieee->wq, &ieee->associate_complete_wq);
}
-void ieee80211_associate_procedure_wq(struct work_struct *work)
+static void ieee80211_associate_procedure_wq(struct work_struct *work)
{
struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_procedure_wq);
ieee->sync_scan_hurryup = 1;
@@ -1562,7 +1561,7 @@ static inline u16 auth_parse(struct sk_buff *skb, u8 **challenge, int *chlen)
}
-int auth_rq_parse(struct sk_buff *skb,u8 *dest)
+static int auth_rq_parse(struct sk_buff *skb, u8 *dest)
{
struct ieee80211_authentication *a;
@@ -1618,7 +1617,7 @@ static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb,
}
-int assoc_rq_parse(struct sk_buff *skb,u8 *dest)
+static int assoc_rq_parse(struct sk_buff *skb, u8 *dest)
{
struct ieee80211_assoc_request_frame *a;
@@ -1712,7 +1711,8 @@ ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
-void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr)
+static void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee,
+ short pwr)
{
struct sk_buff *buf = ieee80211_null_func(ieee, pwr);
@@ -1723,7 +1723,8 @@ void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr)
}
-short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h, u32 *time_l)
+static short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h,
+ u32 *time_l)
{
int timeout = ieee->ps_timeout;
u8 dtim;
@@ -1771,7 +1772,7 @@ short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h, u32 *ti
}
-inline void ieee80211_sta_ps(struct ieee80211_device *ieee)
+static inline void ieee80211_sta_ps(struct ieee80211_device *ieee)
{
u32 th,tl;
@@ -1888,7 +1889,8 @@ void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success)
}
spin_unlock_irqrestore(&ieee->lock, flags);
}
-void ieee80211_process_action(struct ieee80211_device *ieee, struct sk_buff *skb)
+static void ieee80211_process_action(struct ieee80211_device *ieee,
+ struct sk_buff *skb)
{
struct ieee80211_hdr *header = (struct ieee80211_hdr *)skb->data;
u8 *act = ieee80211_get_payload(header);
@@ -1959,7 +1961,8 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
struct ieee80211_network network_resp;
struct ieee80211_network *network = &network_resp;
- if (0 == (errcode=assoc_parse(ieee,skb, &aid))){
+ errcode = assoc_parse(ieee, skb, &aid);
+ if (!errcode) {
ieee->state=IEEE80211_LINKED;
ieee->assoc_id = aid;
ieee->softmac_stats.rx_ass_ok++;
@@ -2017,7 +2020,8 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
IEEE80211_DEBUG_MGMT("Received authentication response");
- if (0 == (errcode=auth_parse(skb, &challenge, &chlen))){
+ errcode = auth_parse(skb, &challenge, &chlen);
+ if (!errcode) {
if(ieee->open_wep || !challenge){
ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATED;
ieee->softmac_stats.rx_auth_rs_ok++;
@@ -2189,7 +2193,7 @@ void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *
}
/* called with ieee->lock acquired */
-void ieee80211_resume_tx(struct ieee80211_device *ieee)
+static void ieee80211_resume_tx(struct ieee80211_device *ieee)
{
int i;
for(i = ieee->tx_pending.frag; i < ieee->tx_pending.txb->nr_frags; i++) {
@@ -2318,7 +2322,7 @@ void ieee80211_start_master_bss(struct ieee80211_device *ieee)
netif_carrier_on(ieee->dev);
}
-void ieee80211_start_monitor_mode(struct ieee80211_device *ieee)
+static void ieee80211_start_monitor_mode(struct ieee80211_device *ieee)
{
if(ieee->raw_tx){
@@ -2328,7 +2332,7 @@ void ieee80211_start_monitor_mode(struct ieee80211_device *ieee)
netif_carrier_on(ieee->dev);
}
}
-void ieee80211_start_ibss_wq(struct work_struct *work)
+static void ieee80211_start_ibss_wq(struct work_struct *work)
{
struct delayed_work *dwork = container_of(work, struct delayed_work, work);
@@ -2501,7 +2505,7 @@ void ieee80211_disassociate(struct ieee80211_device *ieee)
notify_wx_assoc_event(ieee);
}
-void ieee80211_associate_retry_wq(struct work_struct *work)
+static void ieee80211_associate_retry_wq(struct work_struct *work)
{
struct delayed_work *dwork = container_of(work, struct delayed_work, work);
struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq);
@@ -2772,7 +2776,8 @@ static int ieee80211_wpa_enable(struct ieee80211_device *ieee, int value)
}
-void ieee80211_wpa_assoc_frame(struct ieee80211_device *ieee, char *wpa_ie, int wpa_ie_len)
+static void ieee80211_wpa_assoc_frame(struct ieee80211_device *ieee,
+ char *wpa_ie, int wpa_ie_len)
{
/* make sure WPA is enabled */
ieee80211_wpa_enable(ieee, 1);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
index 157b2d7466e5..6779bdd561d7 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
@@ -378,7 +378,8 @@ FORCED_AGG_SETTING:
return;
}
-extern void ieee80211_qurey_ShortPreambleMode(struct ieee80211_device *ieee, cb_desc *tcb_desc)
+static void ieee80211_qurey_ShortPreambleMode(struct ieee80211_device *ieee,
+ cb_desc *tcb_desc)
{
tcb_desc->bUseShortPreamble = false;
if (tcb_desc->data_rate == 2)
@@ -391,7 +392,7 @@ extern void ieee80211_qurey_ShortPreambleMode(struct ieee80211_device *ieee, cb_
}
return;
}
-extern void
+static void
ieee80211_query_HTCapShortGI(struct ieee80211_device *ieee, cb_desc *tcb_desc)
{
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
index e1fe54acb4b8..bdf67ec5df21 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
@@ -39,7 +39,7 @@ struct modes_unit {
char *mode_string;
int mode_size;
};
-struct modes_unit ieee80211_modes[] = {
+static struct modes_unit ieee80211_modes[] = {
{"a",1},
{"b",1},
{"g",1},
diff --git a/drivers/staging/rtl8192u/ieee80211/internal.h b/drivers/staging/rtl8192u/ieee80211/internal.h
deleted file mode 100644
index 6f54cfe8a467..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/internal.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- *
- * This program is free software; 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_INTERNAL_H
-#define _CRYPTO_INTERNAL_H
-
-
-//#include <linux/crypto.h>
-#include "rtl_crypto.h"
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/init.h>
-#include <asm/hardirq.h>
-#include <asm/softirq.h>
-#include <asm/kmap_types.h>
-
-
-static inline void crypto_yield(struct crypto_tfm *tfm)
-{
- if (!in_softirq())
- cond_resched();
-}
-
-static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm)
-{
- return (void *)&tfm[1];
-}
-
-struct crypto_alg *crypto_alg_lookup(const char *name);
-
-#ifdef CONFIG_KMOD
-void crypto_alg_autoload(const char *name);
-struct crypto_alg *crypto_alg_mod_lookup(const char *name);
-#else
-static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name)
-{
- return crypto_alg_lookup(name);
-}
-#endif
-
-#ifdef CONFIG_CRYPTO_HMAC
-int crypto_alloc_hmac_block(struct crypto_tfm *tfm);
-void crypto_free_hmac_block(struct crypto_tfm *tfm);
-#else
-static inline int crypto_alloc_hmac_block(struct crypto_tfm *tfm)
-{
- return 0;
-}
-
-static inline void crypto_free_hmac_block(struct crypto_tfm *tfm)
-{ }
-#endif
-
-#ifdef CONFIG_PROC_FS
-void __init crypto_init_proc(void);
-#else
-static inline void crypto_init_proc(void)
-{ }
-#endif
-
-int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags);
-int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags);
-int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags);
-
-int crypto_init_digest_ops(struct crypto_tfm *tfm);
-int crypto_init_cipher_ops(struct crypto_tfm *tfm);
-int crypto_init_compress_ops(struct crypto_tfm *tfm);
-
-void crypto_exit_digest_ops(struct crypto_tfm *tfm);
-void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
-void crypto_exit_compress_ops(struct crypto_tfm *tfm);
-
-#endif /* _CRYPTO_INTERNAL_H */
diff --git a/drivers/staging/rtl8192u/ieee80211/michael_mic.c b/drivers/staging/rtl8192u/ieee80211/michael_mic.c
deleted file mode 100644
index df256e487c20..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/michael_mic.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Cryptographic API
- *
- * Michael MIC (IEEE 802.11i/TKIP) keyed digest
- *
- * Copyright (c) 2004 Jouni Malinen <jkmaline@cc.hut.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-//#include <linux/crypto.h>
-#include "rtl_crypto.h"
-
-
-struct michael_mic_ctx {
- u8 pending[4];
- size_t pending_len;
-
- u32 l, r;
-};
-
-
-static inline u32 rotl(u32 val, int bits)
-{
- return (val << bits) | (val >> (32 - bits));
-}
-
-
-static inline u32 rotr(u32 val, int bits)
-{
- return (val >> bits) | (val << (32 - bits));
-}
-
-
-static inline u32 xswap(u32 val)
-{
- return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
-}
-
-
-#define michael_block(l, r) \
-do { \
- r ^= rotl(l, 17); \
- l += r; \
- r ^= xswap(l); \
- l += r; \
- r ^= rotl(l, 3); \
- l += r; \
- r ^= rotr(l, 2); \
- l += r; \
-} while (0)
-
-
-static inline u32 get_le32(const u8 *p)
-{
- return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
-}
-
-
-static inline void put_le32(u8 *p, u32 v)
-{
- p[0] = v;
- p[1] = v >> 8;
- p[2] = v >> 16;
- p[3] = v >> 24;
-}
-
-
-static void michael_init(void *ctx)
-{
- struct michael_mic_ctx *mctx = ctx;
- mctx->pending_len = 0;
-}
-
-
-static void michael_update(void *ctx, const u8 *data, unsigned int len)
-{
- struct michael_mic_ctx *mctx = ctx;
-
- if (mctx->pending_len) {
- int flen = 4 - mctx->pending_len;
- if (flen > len)
- flen = len;
- memcpy(&mctx->pending[mctx->pending_len], data, flen);
- mctx->pending_len += flen;
- data += flen;
- len -= flen;
-
- if (mctx->pending_len < 4)
- return;
-
- mctx->l ^= get_le32(mctx->pending);
- michael_block(mctx->l, mctx->r);
- mctx->pending_len = 0;
- }
-
- while (len >= 4) {
- mctx->l ^= get_le32(data);
- michael_block(mctx->l, mctx->r);
- data += 4;
- len -= 4;
- }
-
- if (len > 0) {
- mctx->pending_len = len;
- memcpy(mctx->pending, data, len);
- }
-}
-
-
-static void michael_final(void *ctx, u8 *out)
-{
- struct michael_mic_ctx *mctx = ctx;
- u8 *data = mctx->pending;
-
- /* Last block and padding (0x5a, 4..7 x 0) */
- switch (mctx->pending_len) {
- case 0:
- mctx->l ^= 0x5a;
- break;
- case 1:
- mctx->l ^= data[0] | 0x5a00;
- break;
- case 2:
- mctx->l ^= data[0] | (data[1] << 8) | 0x5a0000;
- break;
- case 3:
- mctx->l ^= data[0] | (data[1] << 8) | (data[2] << 16) |
- 0x5a000000;
- break;
- }
- michael_block(mctx->l, mctx->r);
- /* l ^= 0; */
- michael_block(mctx->l, mctx->r);
-
- put_le32(out, mctx->l);
- put_le32(out + 4, mctx->r);
-}
-
-
-static int michael_setkey(void *ctx, const u8 *key, unsigned int keylen,
- u32 *flags)
-{
- struct michael_mic_ctx *mctx = ctx;
- if (keylen != 8) {
- if (flags)
- *flags = CRYPTO_TFM_RES_BAD_KEY_LEN;
- return -EINVAL;
- }
- mctx->l = get_le32(key);
- mctx->r = get_le32(key + 4);
- return 0;
-}
-
-
-static struct crypto_alg michael_mic_alg = {
- .cra_name = "michael_mic",
- .cra_flags = CRYPTO_ALG_TYPE_DIGEST,
- .cra_blocksize = 8,
- .cra_ctxsize = sizeof(struct michael_mic_ctx),
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(michael_mic_alg.cra_list),
- .cra_u = { .digest = {
- .dia_digestsize = 8,
- .dia_init = michael_init,
- .dia_update = michael_update,
- .dia_final = michael_final,
- .dia_setkey = michael_setkey } }
-};
-
-
-static int __init michael_mic_init(void)
-{
- return crypto_register_alg(&michael_mic_alg);
-}
-
-
-static void __exit michael_mic_exit(void)
-{
- crypto_unregister_alg(&michael_mic_alg);
-}
-
-
-module_init(michael_mic_init);
-module_exit(michael_mic_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Michael MIC");
-MODULE_AUTHOR("Jouni Malinen <jkmaline@cc.hut.fi>");
diff --git a/drivers/staging/rtl8192u/ieee80211/proc.c b/drivers/staging/rtl8192u/ieee80211/proc.c
deleted file mode 100644
index c426dfdd9fdd..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/proc.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Scatterlist Cryptographic API.
- *
- * Procfs information.
- *
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- *
- * This program is free software; 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/crypto.h>
-#include "rtl_crypto.h"
-#include <linux/rwsem.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include "internal.h"
-
-extern struct list_head crypto_alg_list;
-extern struct rw_semaphore crypto_alg_sem;
-
-static void *c_start(struct seq_file *m, loff_t *pos)
-{
- struct list_head *v;
- loff_t n = *pos;
-
- down_read(&crypto_alg_sem);
- list_for_each(v, &crypto_alg_list)
- if (!n--)
- return list_entry(v, struct crypto_alg, cra_list);
- return NULL;
-}
-
-static void *c_next(struct seq_file *m, void *p, loff_t *pos)
-{
- struct list_head *v = p;
-
- (*pos)++;
- v = v->next;
- return (v == &crypto_alg_list) ?
- NULL : list_entry(v, struct crypto_alg, cra_list);
-}
-
-static void c_stop(struct seq_file *m, void *p)
-{
- up_read(&crypto_alg_sem);
-}
-
-static int c_show(struct seq_file *m, void *p)
-{
- struct crypto_alg *alg = (struct crypto_alg *)p;
-
- seq_printf(m, "name : %s\n", alg->cra_name);
- seq_printf(m, "module : %s\n",
- (alg->cra_module ?
- alg->cra_module->name :
- "kernel"));
-
- switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
- case CRYPTO_ALG_TYPE_CIPHER:
- seq_printf(m, "type : cipher\n");
- seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
- seq_printf(m, "min keysize : %u\n",
- alg->cra_cipher.cia_min_keysize);
- seq_printf(m, "max keysize : %u\n",
- alg->cra_cipher.cia_max_keysize);
- break;
-
- case CRYPTO_ALG_TYPE_DIGEST:
- seq_printf(m, "type : digest\n");
- seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
- seq_printf(m, "digestsize : %u\n",
- alg->cra_digest.dia_digestsize);
- break;
- case CRYPTO_ALG_TYPE_COMPRESS:
- seq_printf(m, "type : compression\n");
- break;
- default:
- seq_printf(m, "type : unknown\n");
- break;
- }
-
- seq_putc(m, '\n');
- return 0;
-}
-
-static struct seq_operations crypto_seq_ops = {
- .start = c_start,
- .next = c_next,
- .stop = c_stop,
- .show = c_show
-};
-
-static int crypto_info_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &crypto_seq_ops);
-}
-
-static const struct file_operations proc_crypto_ops = {
- .open = crypto_info_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release
-};
-
-void __init crypto_init_proc(void)
-{
- proc_create("crypto", 0, NULL, &proc_crypto_ops);
-}
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
index 3684da340bd4..7bf55e393554 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
@@ -13,7 +13,7 @@
* u16 Time //indicate time delay.
* output: none
********************************************************************************************************************/
-void ActivateBAEntry(struct ieee80211_device *ieee, PBA_RECORD pBA, u16 Time)
+static void ActivateBAEntry(struct ieee80211_device *ieee, PBA_RECORD pBA, u16 Time)
{
pBA->bValid = true;
if(Time != 0)
@@ -25,7 +25,7 @@ void ActivateBAEntry(struct ieee80211_device *ieee, PBA_RECORD pBA, u16 Time)
* input: PBA_RECORD pBA //BA entry to be disabled
* output: none
********************************************************************************************************************/
-void DeActivateBAEntry( struct ieee80211_device *ieee, PBA_RECORD pBA)
+static void DeActivateBAEntry(struct ieee80211_device *ieee, PBA_RECORD pBA)
{
pBA->bValid = false;
del_timer_sync(&pBA->Timer);
@@ -37,7 +37,7 @@ void DeActivateBAEntry( struct ieee80211_device *ieee, PBA_RECORD pBA)
* output: none
* notice: As PTX_TS_RECORD structure will be defined in QOS, so wait to be merged. //FIXME
********************************************************************************************************************/
-u8 TxTsDeleteBA( struct ieee80211_device *ieee, PTX_TS_RECORD pTxTs)
+static u8 TxTsDeleteBA(struct ieee80211_device *ieee, PTX_TS_RECORD pTxTs)
{
PBA_RECORD pAdmittedBa = &pTxTs->TxAdmittedBARecord; //These two BA entries must exist in TS structure
PBA_RECORD pPendingBa = &pTxTs->TxPendingBARecord;
@@ -67,7 +67,7 @@ u8 TxTsDeleteBA( struct ieee80211_device *ieee, PTX_TS_RECORD pTxTs)
* output: none
* notice: As PRX_TS_RECORD structure will be defined in QOS, so wait to be merged. //FIXME, same with above
********************************************************************************************************************/
-u8 RxTsDeleteBA( struct ieee80211_device *ieee, PRX_TS_RECORD pRxTs)
+static u8 RxTsDeleteBA(struct ieee80211_device *ieee, PRX_TS_RECORD pRxTs)
{
PBA_RECORD pBa = &pRxTs->RxAdmittedBARecord;
u8 bSendDELBA = false;
@@ -307,7 +307,9 @@ static void ieee80211_send_ADDBARsp(struct ieee80211_device *ieee, u8 *dst,
* notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does
********************************************************************************************************************/
-void ieee80211_send_DELBA(struct ieee80211_device *ieee, u8 *dst, PBA_RECORD pBA, TR_SELECT TxRxSelect, u16 ReasonCode)
+static void ieee80211_send_DELBA(struct ieee80211_device *ieee, u8 *dst,
+ PBA_RECORD pBA, TR_SELECT TxRxSelect,
+ u16 ReasonCode)
{
struct sk_buff *skb = NULL;
skb = ieee80211_DELBA(ieee, dst, pBA, TxRxSelect, ReasonCode); //construct ACT_ADDBARSP frames
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
index e956da5a2d76..53ec2d435ffe 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
@@ -219,7 +219,7 @@ void HTDebugHTInfo(u8 *InfoIE, u8 *TitleString)
/*
* Return: true if station in half n mode and AP supports 40 bw
*/
-bool IsHTHalfNmode40Bandwidth(struct ieee80211_device *ieee)
+static bool IsHTHalfNmode40Bandwidth(struct ieee80211_device *ieee)
{
bool retValue = false;
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
@@ -238,7 +238,7 @@ bool IsHTHalfNmode40Bandwidth(struct ieee80211_device *ieee)
return retValue;
}
-bool IsHTHalfNmodeSGI(struct ieee80211_device *ieee, bool is40MHz)
+static bool IsHTHalfNmodeSGI(struct ieee80211_device *ieee, bool is40MHz)
{
bool retValue = false;
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
@@ -376,7 +376,7 @@ bool IsHTHalfNmodeAPs(struct ieee80211_device *ieee)
* return:
* notice:
* *****************************************************************************************************************/
-void HTIOTPeerDetermine(struct ieee80211_device *ieee)
+static void HTIOTPeerDetermine(struct ieee80211_device *ieee)
{
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
struct ieee80211_network *net = &ieee->current_network;
@@ -413,7 +413,7 @@ void HTIOTPeerDetermine(struct ieee80211_device *ieee)
* output: none
* return: return 1 if driver should declare MCS13 only(otherwise return 0)
* *****************************************************************************************************************/
-u8 HTIOTActIsDisableMCS14(struct ieee80211_device *ieee, u8 *PeerMacAddr)
+static u8 HTIOTActIsDisableMCS14(struct ieee80211_device *ieee, u8 *PeerMacAddr)
{
u8 ret = 0;
return ret;
@@ -432,7 +432,7 @@ u8 HTIOTActIsDisableMCS14(struct ieee80211_device *ieee, u8 *PeerMacAddr)
* Return: true if driver should disable MCS15
* 2008.04.15 Emily
*/
-bool HTIOTActIsDisableMCS15(struct ieee80211_device *ieee)
+static bool HTIOTActIsDisableMCS15(struct ieee80211_device *ieee)
{
bool retValue = false;
@@ -469,7 +469,8 @@ bool HTIOTActIsDisableMCS15(struct ieee80211_device *ieee)
* Return: true if driver should disable all two spatial stream packet
* 2008.04.21 Emily
*/
-bool HTIOTActIsDisableMCSTwoSpatialStream(struct ieee80211_device *ieee, u8 *PeerMacAddr)
+static bool HTIOTActIsDisableMCSTwoSpatialStream(struct ieee80211_device *ieee,
+ u8 *PeerMacAddr)
{
bool retValue = false;
@@ -486,7 +487,8 @@ bool HTIOTActIsDisableMCSTwoSpatialStream(struct ieee80211_device *ieee, u8 *Pee
* output: none
* return: return 1 if driver should disable EDCA turbo mode(otherwise return 0)
* *****************************************************************************************************************/
-u8 HTIOTActIsDisableEDCATurbo(struct ieee80211_device *ieee, u8 *PeerMacAddr)
+static u8 HTIOTActIsDisableEDCATurbo(struct ieee80211_device *ieee,
+ u8 *PeerMacAddr)
{
u8 retValue = false; // default enable EDCA Turbo mode.
// Set specific EDCA parameter for different AP in DM handler.
@@ -500,7 +502,7 @@ u8 HTIOTActIsDisableEDCATurbo(struct ieee80211_device *ieee, u8 *PeerMacAddr)
* output: none
* return: return 1 if true
* *****************************************************************************************************************/
-u8 HTIOTActIsMgntUseCCK6M(struct ieee80211_network *network)
+static u8 HTIOTActIsMgntUseCCK6M(struct ieee80211_network *network)
{
u8 retValue = 0;
@@ -515,7 +517,7 @@ u8 HTIOTActIsMgntUseCCK6M(struct ieee80211_network *network)
return retValue;
}
-u8 HTIOTActIsCCDFsync(u8 *PeerMacAddr)
+static u8 HTIOTActIsCCDFsync(u8 *PeerMacAddr)
{
u8 retValue = 0;
if( (memcmp(PeerMacAddr, UNKNOWN_BORADCOM, 3)==0) ||
@@ -792,7 +794,7 @@ void HTConstructRT2RTAggElement(struct ieee80211_device *ieee, u8 *posRT2RTAgg,
* return: always we return true
* notice:
* *****************************************************************************************************************/
-u8 HT_PickMCSRate(struct ieee80211_device *ieee, u8 *pOperateMCS)
+static u8 HT_PickMCSRate(struct ieee80211_device *ieee, u8 *pOperateMCS)
{
u8 i;
if (pOperateMCS == NULL)
@@ -907,7 +909,8 @@ u8 HTGetHighestMCSRate(struct ieee80211_device *ieee, u8 *pMCSRateSet, u8 *pMCSF
**
** \pHTSupportedCap: the connected STA's supported rate Capability element
*/
-u8 HTFilterMCSRate( struct ieee80211_device *ieee, u8 *pSupportMCS, u8 *pOperateMCS)
+static u8 HTFilterMCSRate(struct ieee80211_device *ieee, u8 *pSupportMCS,
+ u8 *pOperateMCS)
{
u8 i=0;
@@ -1317,51 +1320,6 @@ void HTUpdateSelfAndPeerSetting(struct ieee80211_device *ieee, struct ieee80211_
}
}
-void HTUseDefaultSetting(struct ieee80211_device *ieee)
-{
- PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
-// u8 regBwOpMode;
-
- if(pHTInfo->bEnableHT)
- {
- pHTInfo->bCurrentHTSupport = true;
-
- pHTInfo->bCurSuppCCK = pHTInfo->bRegSuppCCK;
-
- pHTInfo->bCurBW40MHz = pHTInfo->bRegBW40MHz;
-
- pHTInfo->bCurShortGI20MHz= pHTInfo->bRegShortGI20MHz;
-
- pHTInfo->bCurShortGI40MHz= pHTInfo->bRegShortGI40MHz;
-
- pHTInfo->bCurrent_AMSDU_Support = pHTInfo->bAMSDU_Support;
-
- pHTInfo->nCurrent_AMSDU_MaxSize = pHTInfo->nAMSDU_MaxSize;
-
- pHTInfo->bCurrentAMPDUEnable = pHTInfo->bAMPDUEnable;
-
- pHTInfo->CurrentAMPDUFactor = pHTInfo->AMPDU_Factor;
-
- pHTInfo->CurrentMPDUDensity = pHTInfo->MPDU_Density;
-
- // Set BWOpMode register
-
- //update RATR index0
- HTFilterMCSRate(ieee, ieee->Regdot11HTOperationalRateSet, ieee->dot11HTOperationalRateSet);
- //function below is not implemented at all. WB
-#ifdef TODO
- Adapter->HalFunc.InitHalRATRTableHandler( Adapter, &pMgntInfo->dot11OperationalRateSet, pMgntInfo->dot11HTOperationalRateSet);
-#endif
- ieee->HTHighestOperaRate = HTGetHighestMCSRate(ieee, ieee->dot11HTOperationalRateSet, MCS_FILTER_ALL);
- ieee->HTCurrentOperaRate = ieee->HTHighestOperaRate;
-
- }
- else
- {
- pHTInfo->bCurrentHTSupport = false;
- }
- return;
-}
/********************************************************************************************************************
*function: check whether HT control field exists
* input: struct ieee80211_device *ieee
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
index 3058120a3243..426f223e6a21 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
@@ -3,13 +3,13 @@
#include <linux/slab.h>
#include "rtl819x_TS.h"
-void TsSetupTimeOut(unsigned long data)
+static void TsSetupTimeOut(unsigned long data)
{
// Not implement yet
// This is used for WMMSA and ACM , that would send ADDTSReq frame.
}
-void TsInactTimeout(unsigned long data)
+static void TsInactTimeout(unsigned long data)
{
// Not implement yet
// This is used for WMMSA and ACM.
@@ -22,7 +22,7 @@ void TsInactTimeout(unsigned long data)
* return: NULL
* notice:
********************************************************************************************************************/
-void RxPktPendingTimeout(unsigned long data)
+static void RxPktPendingTimeout(unsigned long data)
{
PRX_TS_RECORD pRxTs = (PRX_TS_RECORD)data;
struct ieee80211_device *ieee = container_of(pRxTs, struct ieee80211_device, RxTsRecord[pRxTs->num]);
@@ -99,7 +99,7 @@ void RxPktPendingTimeout(unsigned long data)
* return: NULL
* notice:
********************************************************************************************************************/
-void TsAddBaProcess(unsigned long data)
+static void TsAddBaProcess(unsigned long data)
{
PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)data;
u8 num = pTxTs->num;
@@ -110,7 +110,7 @@ void TsAddBaProcess(unsigned long data)
}
-void ResetTsCommonInfo(PTS_COMMON_INFO pTsCommonInfo)
+static void ResetTsCommonInfo(PTS_COMMON_INFO pTsCommonInfo)
{
memset(pTsCommonInfo->Addr, 0, 6);
memset(&pTsCommonInfo->TSpec, 0, sizeof(TSPEC_BODY));
@@ -119,7 +119,7 @@ void ResetTsCommonInfo(PTS_COMMON_INFO pTsCommonInfo)
pTsCommonInfo->TClasNum = 0;
}
-void ResetTxTsEntry(PTX_TS_RECORD pTS)
+static void ResetTxTsEntry(PTX_TS_RECORD pTS)
{
ResetTsCommonInfo(&pTS->TsCommonInfo);
pTS->TxCurSeq = 0;
@@ -130,7 +130,7 @@ void ResetTxTsEntry(PTX_TS_RECORD pTS)
ResetBaEntry(&pTS->TxPendingBARecord);
}
-void ResetRxTsEntry(PRX_TS_RECORD pTS)
+static void ResetRxTsEntry(PRX_TS_RECORD pTS)
{
ResetTsCommonInfo(&pTS->TsCommonInfo);
pTS->RxIndicateSeq = 0xffff; // This indicate the RxIndicateSeq is not used now!!
@@ -224,7 +224,8 @@ void TSInitialize(struct ieee80211_device *ieee)
}
-void AdmitTS(struct ieee80211_device *ieee, PTS_COMMON_INFO pTsCommonInfo, u32 InactTime)
+static void AdmitTS(struct ieee80211_device *ieee,
+ PTS_COMMON_INFO pTsCommonInfo, u32 InactTime)
{
del_timer_sync(&pTsCommonInfo->SetupTimer);
del_timer_sync(&pTsCommonInfo->InactTimer);
@@ -234,7 +235,9 @@ void AdmitTS(struct ieee80211_device *ieee, PTS_COMMON_INFO pTsCommonInfo, u32 I
}
-PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee, u8 *Addr, u8 TID, TR_SELECT TxRxSelect)
+static PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee,
+ u8 *Addr, u8 TID,
+ TR_SELECT TxRxSelect)
{
//DIRECTION_VALUE dir;
u8 dir;
@@ -309,14 +312,9 @@ PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee, u8 *Addr, u8
return NULL;
}
-void MakeTSEntry(
- PTS_COMMON_INFO pTsCommonInfo,
- u8 *Addr,
- PTSPEC_BODY pTSPEC,
- PQOS_TCLAS pTCLAS,
- u8 TCLAS_Num,
- u8 TCLAS_Proc
- )
+static void MakeTSEntry(PTS_COMMON_INFO pTsCommonInfo, u8 *Addr,
+ PTSPEC_BODY pTSPEC, PQOS_TCLAS pTCLAS, u8 TCLAS_Num,
+ u8 TCLAS_Proc)
{
u8 count;
@@ -472,11 +470,8 @@ bool GetTs(
}
}
-void RemoveTsEntry(
- struct ieee80211_device *ieee,
- PTS_COMMON_INFO pTs,
- TR_SELECT TxRxSelect
- )
+static void RemoveTsEntry(struct ieee80211_device *ieee, PTS_COMMON_INFO pTs,
+ TR_SELECT TxRxSelect)
{
//u32 flags = 0;
unsigned long flags = 0;
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl_crypto.h b/drivers/staging/rtl8192u/ieee80211/rtl_crypto.h
deleted file mode 100644
index c3c87108ee9e..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/rtl_crypto.h
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Scatterlist Cryptographic API.
- *
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- * Copyright (c) 2002 David S. Miller (davem@redhat.com)
- *
- * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no>
- * and Nettle, by Niels Mé°ˆler.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- */
-#ifndef _LINUX_CRYPTO_H
-#define _LINUX_CRYPTO_H
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/string.h>
-#include <asm/page.h>
-#include <asm/errno.h>
-
-#define crypto_register_alg crypto_register_alg_rsl
-#define crypto_unregister_alg crypto_unregister_alg_rsl
-#define crypto_alloc_tfm crypto_alloc_tfm_rsl
-#define crypto_free_tfm crypto_free_tfm_rsl
-#define crypto_alg_available crypto_alg_available_rsl
-
-/*
- * Algorithm masks and types.
- */
-#define CRYPTO_ALG_TYPE_MASK 0x000000ff
-#define CRYPTO_ALG_TYPE_CIPHER 0x00000001
-#define CRYPTO_ALG_TYPE_DIGEST 0x00000002
-#define CRYPTO_ALG_TYPE_COMPRESS 0x00000004
-
-/*
- * Transform masks and values (for crt_flags).
- */
-#define CRYPTO_TFM_MODE_MASK 0x000000ff
-#define CRYPTO_TFM_REQ_MASK 0x000fff00
-#define CRYPTO_TFM_RES_MASK 0xfff00000
-
-#define CRYPTO_TFM_MODE_ECB 0x00000001
-#define CRYPTO_TFM_MODE_CBC 0x00000002
-#define CRYPTO_TFM_MODE_CFB 0x00000004
-#define CRYPTO_TFM_MODE_CTR 0x00000008
-
-#define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100
-#define CRYPTO_TFM_RES_WEAK_KEY 0x00100000
-#define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000
-#define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000
-#define CRYPTO_TFM_RES_BAD_BLOCK_LEN 0x00800000
-#define CRYPTO_TFM_RES_BAD_FLAGS 0x01000000
-
-/*
- * Miscellaneous stuff.
- */
-#define CRYPTO_UNSPEC 0
-#define CRYPTO_MAX_ALG_NAME 64
-
-struct scatterlist;
-
-/*
- * Algorithms: modular crypto algorithm implementations, managed
- * via crypto_register_alg() and crypto_unregister_alg().
- */
-struct cipher_alg {
- unsigned int cia_min_keysize;
- unsigned int cia_max_keysize;
- int (*cia_setkey)(void *ctx, const u8 *key,
- unsigned int keylen, u32 *flags);
- void (*cia_encrypt)(void *ctx, u8 *dst, const u8 *src);
- void (*cia_decrypt)(void *ctx, u8 *dst, const u8 *src);
-};
-
-struct digest_alg {
- unsigned int dia_digestsize;
- void (*dia_init)(void *ctx);
- void (*dia_update)(void *ctx, const u8 *data, unsigned int len);
- void (*dia_final)(void *ctx, u8 *out);
- int (*dia_setkey)(void *ctx, const u8 *key,
- unsigned int keylen, u32 *flags);
-};
-
-struct compress_alg {
- int (*coa_init)(void *ctx);
- void (*coa_exit)(void *ctx);
- int (*coa_compress)(void *ctx, const u8 *src, unsigned int slen,
- u8 *dst, unsigned int *dlen);
- int (*coa_decompress)(void *ctx, const u8 *src, unsigned int slen,
- u8 *dst, unsigned int *dlen);
-};
-
-#define cra_cipher cra_u.cipher
-#define cra_digest cra_u.digest
-#define cra_compress cra_u.compress
-
-struct crypto_alg {
- struct list_head cra_list;
- u32 cra_flags;
- unsigned int cra_blocksize;
- unsigned int cra_ctxsize;
- const char cra_name[CRYPTO_MAX_ALG_NAME];
-
- union {
- struct cipher_alg cipher;
- struct digest_alg digest;
- struct compress_alg compress;
- } cra_u;
-
- struct module *cra_module;
-};
-
-/*
- * Algorithm registration interface.
- */
-int crypto_register_alg(struct crypto_alg *alg);
-int crypto_unregister_alg(struct crypto_alg *alg);
-
-/*
- * Algorithm query interface.
- */
-int crypto_alg_available(const char *name, u32 flags);
-
-/*
- * Transforms: user-instantiated objects which encapsulate algorithms
- * and core processing logic. Managed via crypto_alloc_tfm() and
- * crypto_free_tfm(), as well as the various helpers below.
- */
-struct crypto_tfm;
-
-struct cipher_tfm {
- void *cit_iv;
- unsigned int cit_ivsize;
- u32 cit_mode;
- int (*cit_setkey)(struct crypto_tfm *tfm,
- const u8 *key, unsigned int keylen);
- int (*cit_encrypt)(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes);
- int (*cit_encrypt_iv)(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv);
- int (*cit_decrypt)(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes);
- int (*cit_decrypt_iv)(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv);
- void (*cit_xor_block)(u8 *dst, const u8 *src);
-};
-
-struct digest_tfm {
- void (*dit_init)(struct crypto_tfm *tfm);
- void (*dit_update)(struct crypto_tfm *tfm,
- struct scatterlist *sg, unsigned int nsg);
- void (*dit_final)(struct crypto_tfm *tfm, u8 *out);
- void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg,
- unsigned int nsg, u8 *out);
- int (*dit_setkey)(struct crypto_tfm *tfm,
- const u8 *key, unsigned int keylen);
-#ifdef CONFIG_CRYPTO_HMAC
- void *dit_hmac_block;
-#endif
-};
-
-struct compress_tfm {
- int (*cot_compress)(struct crypto_tfm *tfm,
- const u8 *src, unsigned int slen,
- u8 *dst, unsigned int *dlen);
- int (*cot_decompress)(struct crypto_tfm *tfm,
- const u8 *src, unsigned int slen,
- u8 *dst, unsigned int *dlen);
-};
-
-#define crt_cipher crt_u.cipher
-#define crt_digest crt_u.digest
-#define crt_compress crt_u.compress
-
-struct crypto_tfm {
-
- u32 crt_flags;
-
- union {
- struct cipher_tfm cipher;
- struct digest_tfm digest;
- struct compress_tfm compress;
- } crt_u;
-
- struct crypto_alg *__crt_alg;
-};
-
-/*
- * Transform user interface.
- */
-
-/*
- * crypto_alloc_tfm() will first attempt to locate an already loaded algorithm.
- * If that fails and the kernel supports dynamically loadable modules, it
- * will then attempt to load a module of the same name or alias. A refcount
- * is grabbed on the algorithm which is then associated with the new transform.
- *
- * crypto_free_tfm() frees up the transform and any associated resources,
- * then drops the refcount on the associated algorithm.
- */
-struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags);
-void crypto_free_tfm(struct crypto_tfm *tfm);
-
-/*
- * Transform helpers which query the underlying algorithm.
- */
-static inline const char *crypto_tfm_alg_name(struct crypto_tfm *tfm)
-{
- return tfm->__crt_alg->cra_name;
-}
-
-static inline const char *crypto_tfm_alg_modname(struct crypto_tfm *tfm)
-{
- struct crypto_alg *alg = tfm->__crt_alg;
-
- if (alg->cra_module)
- return alg->cra_module->name;
- else
- return NULL;
-}
-
-static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm)
-{
- return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK;
-}
-
-static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->__crt_alg->cra_cipher.cia_min_keysize;
-}
-
-static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->__crt_alg->cra_cipher.cia_max_keysize;
-}
-
-static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->crt_cipher.cit_ivsize;
-}
-
-static inline unsigned int crypto_tfm_alg_blocksize(struct crypto_tfm *tfm)
-{
- return tfm->__crt_alg->cra_blocksize;
-}
-
-static inline unsigned int crypto_tfm_alg_digestsize(struct crypto_tfm *tfm)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
- return tfm->__crt_alg->cra_digest.dia_digestsize;
-}
-
-/*
- * API wrappers.
- */
-static inline void crypto_digest_init(struct crypto_tfm *tfm)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
- tfm->crt_digest.dit_init(tfm);
-}
-
-static inline void crypto_digest_update(struct crypto_tfm *tfm,
- struct scatterlist *sg,
- unsigned int nsg)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
- tfm->crt_digest.dit_update(tfm, sg, nsg);
-}
-
-static inline void crypto_digest_final(struct crypto_tfm *tfm, u8 *out)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
- tfm->crt_digest.dit_final(tfm, out);
-}
-
-static inline void crypto_digest_digest(struct crypto_tfm *tfm,
- struct scatterlist *sg,
- unsigned int nsg, u8 *out)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
- tfm->crt_digest.dit_digest(tfm, sg, nsg, out);
-}
-
-static inline int crypto_digest_setkey(struct crypto_tfm *tfm,
- const u8 *key, unsigned int keylen)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
- if (tfm->crt_digest.dit_setkey == NULL)
- return -ENOSYS;
- return tfm->crt_digest.dit_setkey(tfm, key, keylen);
-}
-
-static inline int crypto_cipher_setkey(struct crypto_tfm *tfm,
- const u8 *key, unsigned int keylen)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->crt_cipher.cit_setkey(tfm, key, keylen);
-}
-
-static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes);
-}
-
-static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB);
- return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv);
-}
-
-static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes);
-}
-
-static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB);
- return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv);
-}
-
-static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm,
- const u8 *src, unsigned int len)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- memcpy(tfm->crt_cipher.cit_iv, src, len);
-}
-
-static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm,
- u8 *dst, unsigned int len)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
- memcpy(dst, tfm->crt_cipher.cit_iv, len);
-}
-
-static inline int crypto_comp_compress(struct crypto_tfm *tfm,
- const u8 *src, unsigned int slen,
- u8 *dst, unsigned int *dlen)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS);
- return tfm->crt_compress.cot_compress(tfm, src, slen, dst, dlen);
-}
-
-static inline int crypto_comp_decompress(struct crypto_tfm *tfm,
- const u8 *src, unsigned int slen,
- u8 *dst, unsigned int *dlen)
-{
- BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS);
- return tfm->crt_compress.cot_decompress(tfm, src, slen, dst, dlen);
-}
-
-/*
- * HMAC support.
- */
-#ifdef CONFIG_CRYPTO_HMAC
-void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen);
-void crypto_hmac_update(struct crypto_tfm *tfm,
- struct scatterlist *sg, unsigned int nsg);
-void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
- unsigned int *keylen, u8 *out);
-void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen,
- struct scatterlist *sg, unsigned int nsg, u8 *out);
-#endif /* CONFIG_CRYPTO_HMAC */
-
-#endif /* _LINUX_CRYPTO_H */
diff --git a/drivers/staging/rtl8192u/ieee80211/scatterwalk.c b/drivers/staging/rtl8192u/ieee80211/scatterwalk.c
deleted file mode 100644
index 8b73f6cefcf9..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/scatterwalk.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Cipher operations.
- *
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- * 2002 Adam J. Richter <adam@yggdrasil.com>
- * 2004 Jean-Luc Cooke <jlcooke@certainkey.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/highmem.h>
-#include <asm/scatterlist.h>
-#include "internal.h"
-#include "scatterwalk.h"
-
-void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch)
-{
- if (nbytes <= walk->len_this_page &&
- (((unsigned long)walk->data) & (PAGE_CACHE_SIZE - 1)) + nbytes <=
- PAGE_CACHE_SIZE)
- return walk->data;
- else
- return scratch;
-}
-
-static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
-{
- if (out)
- memcpy(sgdata, buf, nbytes);
- else
- memcpy(buf, sgdata, nbytes);
-}
-
-void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg)
-{
- unsigned int rest_of_page;
-
- walk->sg = sg;
-
- walk->page = sg->page;
- walk->len_this_segment = sg->length;
-
- rest_of_page = PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1));
- walk->len_this_page = min(sg->length, rest_of_page);
- walk->offset = sg->offset;
-}
-
-void scatterwalk_map(struct scatter_walk *walk)
-{
- walk->data = kmap_atomic(walk->page) + walk->offset;
-}
-
-static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
- unsigned int more)
-{
- /* walk->data may be pointing the first byte of the next page;
- however, we know we transferred at least one byte. So,
- walk->data - 1 will be a virtual address in the mapped page. */
-
- if (out)
- flush_dcache_page(walk->page);
-
- if (more) {
- walk->len_this_segment -= walk->len_this_page;
-
- if (walk->len_this_segment) {
- walk->page++;
- walk->len_this_page = min(walk->len_this_segment,
- (unsigned)PAGE_CACHE_SIZE);
- walk->offset = 0;
- }
- else
- scatterwalk_start(walk, sg_next(walk->sg));
- }
-}
-
-void scatterwalk_done(struct scatter_walk *walk, int out, int more)
-{
- crypto_kunmap(walk->data, out);
- if (walk->len_this_page == 0 || !more)
- scatterwalk_pagedone(walk, out, more);
-}
-
-/*
- * Do not call this unless the total length of all of the fragments
- * has been verified as multiple of the block size.
- */
-int scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
- size_t nbytes)
-{
- if (buf != walk->data) {
- while (nbytes > walk->len_this_page) {
- memcpy_dir(buf, walk->data, walk->len_this_page, out);
- buf += walk->len_this_page;
- nbytes -= walk->len_this_page;
-
- kunmap_atomic(walk->data);
- scatterwalk_pagedone(walk, out, 1);
- scatterwalk_map(walk);
- }
-
- memcpy_dir(buf, walk->data, nbytes, out);
- }
-
- walk->offset += nbytes;
- walk->len_this_page -= nbytes;
- walk->len_this_segment -= nbytes;
- return 0;
-}
diff --git a/drivers/staging/rtl8192u/ieee80211/scatterwalk.h b/drivers/staging/rtl8192u/ieee80211/scatterwalk.h
deleted file mode 100644
index b16446519017..000000000000
--- a/drivers/staging/rtl8192u/ieee80211/scatterwalk.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- * Copyright (c) 2002 Adam J. Richter <adam@yggdrasil.com>
- * Copyright (c) 2004 Jean-Luc Cooke <jlcooke@certainkey.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- */
-
-#ifndef _CRYPTO_SCATTERWALK_H
-#define _CRYPTO_SCATTERWALK_H
-#include <linux/mm.h>
-#include <asm/scatterlist.h>
-
-struct scatter_walk {
- struct scatterlist *sg;
- struct page *page;
- void *data;
- unsigned int len_this_page;
- unsigned int len_this_segment;
- unsigned int offset;
-};
-
-/* Define sg_next is an inline routine now in case we want to change
- scatterlist to a linked list later. */
-static inline struct scatterlist *sg_next(struct scatterlist *sg)
-{
- return sg + 1;
-}
-
-static inline int scatterwalk_samebuf(struct scatter_walk *walk_in,
- struct scatter_walk *walk_out,
- void *src_p, void *dst_p)
-{
- return walk_in->page == walk_out->page &&
- walk_in->offset == walk_out->offset &&
- walk_in->data == src_p && walk_out->data == dst_p;
-}
-
-void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch);
-void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg);
-int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out);
-void scatterwalk_map(struct scatter_walk *walk, int out);
-void scatterwalk_done(struct scatter_walk *walk, int out, int more);
-
-#endif /* _CRYPTO_SCATTERWALK_H */
diff --git a/drivers/staging/rtl8192u/r8180_93cx6.c b/drivers/staging/rtl8192u/r8180_93cx6.c
index c61729b727ef..cd06054fbedb 100644
--- a/drivers/staging/rtl8192u/r8180_93cx6.c
+++ b/drivers/staging/rtl8192u/r8180_93cx6.c
@@ -20,7 +20,7 @@
#include "r8180_93cx6.h"
-void eprom_cs(struct net_device *dev, short bit)
+static void eprom_cs(struct net_device *dev, short bit)
{
u8 cmdreg;
@@ -37,7 +37,7 @@ void eprom_cs(struct net_device *dev, short bit)
}
-void eprom_ck_cycle(struct net_device *dev)
+static void eprom_ck_cycle(struct net_device *dev)
{
u8 cmdreg;
@@ -53,7 +53,7 @@ void eprom_ck_cycle(struct net_device *dev)
}
-void eprom_w(struct net_device *dev,short bit)
+static void eprom_w(struct net_device *dev,short bit)
{
u8 cmdreg;
@@ -68,7 +68,7 @@ void eprom_w(struct net_device *dev,short bit)
}
-short eprom_r(struct net_device *dev)
+static short eprom_r(struct net_device *dev)
{
u8 bit;
@@ -82,7 +82,7 @@ short eprom_r(struct net_device *dev)
}
-void eprom_send_bits_string(struct net_device *dev, short b[], int len)
+static void eprom_send_bits_string(struct net_device *dev, short b[], int len)
{
int i;
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index c2bcbe230ed3..1bb6143cdf0f 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -238,7 +238,7 @@ static void rtl819x_set_channel_map(u8 channel_plan, struct r8192_priv *priv)
-void CamResetAllEntry(struct net_device *dev)
+static void CamResetAllEntry(struct net_device *dev)
{
u32 ulcommand = 0;
//2004/02/11 In static WEP, OID_ADD_KEY or OID_ADD_WEP are set before STA associate to AP.
@@ -591,12 +591,6 @@ static void rtl8192_proc_module_init(void)
rtl8192_proc = proc_mkdir(RTL819xU_MODULE_NAME, init_net.proc_net);
}
-
-void rtl8192_proc_module_remove(void)
-{
- remove_proc_entry(RTL819xU_MODULE_NAME, init_net.proc_net);
-}
-
/*
* seq_file wrappers for procfile show routines.
*/
@@ -673,7 +667,7 @@ short check_nic_enough_desc(struct net_device *dev, int queue_index)
return (used < MAX_TX_URB);
}
-void tx_timeout(struct net_device *dev)
+static void tx_timeout(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -689,24 +683,6 @@ void dump_eprom(struct net_device *dev)
RT_TRACE(COMP_EPROM, "EEPROM addr %x : %x", i, eprom_read(dev, i));
}
-
-/****************************************************************************
- ------------------------------HW STUFF---------------------------
-*****************************************************************************/
-
-
-void rtl8192_set_mode(struct net_device *dev, int mode)
-{
- u8 ecmd;
- read_nic_byte(dev, EPROM_CMD, &ecmd);
- ecmd = ecmd & ~EPROM_CMD_OPERATING_MODE_MASK;
- ecmd = ecmd | (mode<<EPROM_CMD_OPERATING_MODE_SHIFT);
- ecmd = ecmd & ~EPROM_CS_BIT;
- ecmd = ecmd & ~EPROM_CK_BIT;
- write_nic_byte(dev, EPROM_CMD, ecmd);
-}
-
-
void rtl8192_update_msr(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -903,12 +879,6 @@ void rtl8192_rtx_disable(struct net_device *dev)
return;
}
-
-int alloc_tx_beacon_desc_ring(struct net_device *dev, int count)
-{
- return 0;
-}
-
inline u16 ieeerate2rtlrate(int rate)
{
switch (rate) {
@@ -1011,13 +981,13 @@ static u32 rtl819xusb_rx_command_packet(struct net_device *dev,
}
-void rtl8192_data_hard_stop(struct net_device *dev)
+static void rtl8192_data_hard_stop(struct net_device *dev)
{
//FIXME !!
}
-void rtl8192_data_hard_resume(struct net_device *dev)
+static void rtl8192_data_hard_resume(struct net_device *dev)
{
// FIXME !!
}
@@ -1025,7 +995,7 @@ void rtl8192_data_hard_resume(struct net_device *dev)
/* this function TX data frames when the ieee80211 stack requires this.
* It checks also if we need to stop the ieee tx queue, eventually do it
*/
-void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, int rate)
+static void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, int rate)
{
struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
int ret;
@@ -1053,7 +1023,7 @@ void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, int rat
* If the ring is full packet are dropped (for data frame the queue
* is stopped before this can happen).
*/
-int rtl8192_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int rtl8192_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
int ret;
@@ -1318,7 +1288,8 @@ static void rtl8192_tx_isr(struct urb *tx_urb)
/* Don't send data frame during scanning.*/
if ((skb_queue_len(&priv->ieee80211->skb_waitQ[queue_index]) != 0) &&
(!(priv->ieee80211->queue_stop))) {
- if (NULL != (skb = skb_dequeue(&(priv->ieee80211->skb_waitQ[queue_index]))))
+ skb = skb_dequeue(&(priv->ieee80211->skb_waitQ[queue_index]));
+ if (skb)
priv->ieee80211->softmac_hard_start_xmit(skb, dev);
return; //modified by david to avoid further processing AMSDU
@@ -1358,25 +1329,7 @@ static void rtl8192_tx_isr(struct urb *tx_urb)
}
-void rtl8192_beacon_stop(struct net_device *dev)
-{
- u8 msr, msrm, msr2;
- struct r8192_priv *priv = ieee80211_priv(dev);
-
- read_nic_byte(dev, MSR, &msr);
- msrm = msr & MSR_LINK_MASK;
- msr2 = msr & ~MSR_LINK_MASK;
-
- if (NIC_8192U == priv->card_8192)
- usb_kill_urb(priv->rx_urb[MAX_RX_URB]);
- if ((msrm == (MSR_LINK_ADHOC<<MSR_LINK_SHIFT) ||
- (msrm == (MSR_LINK_MASTER<<MSR_LINK_SHIFT)))) {
- write_nic_byte(dev, MSR, msr2 | MSR_LINK_NONE);
- write_nic_byte(dev, MSR, msr);
- }
-}
-
-void rtl8192_config_rate(struct net_device *dev, u16 *rate_config)
+static void rtl8192_config_rate(struct net_device *dev, u16 *rate_config)
{
struct r8192_priv *priv = ieee80211_priv(dev);
struct ieee80211_network *net;
@@ -1423,7 +1376,7 @@ void rtl8192_config_rate(struct net_device *dev, u16 *rate_config)
#define SHORT_SLOT_TIME 9
#define NON_SHORT_SLOT_TIME 20
-void rtl8192_update_cap(struct net_device *dev, u16 cap)
+static void rtl8192_update_cap(struct net_device *dev, u16 cap)
{
u32 tmp = 0;
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -1445,7 +1398,7 @@ void rtl8192_update_cap(struct net_device *dev, u16 cap)
}
}
-void rtl8192_net_update(struct net_device *dev)
+static void rtl8192_net_update(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -1560,11 +1513,6 @@ u16 N_DBPSOfRate(u16 DataRate)
return N_DBPS;
}
-void rtl819xU_cmd_isr(struct urb *tx_cmd_urb, struct pt_regs *regs)
-{
- usb_free_urb(tx_cmd_urb);
-}
-
unsigned int txqueue2outpipe(struct r8192_priv *priv, unsigned int tx_queue)
{
if (tx_queue >= 9) {
@@ -1673,7 +1621,7 @@ static u8 MapHwQueueToFirmwareQueue(u8 QueueID)
return QueueSelect;
}
-u8 MRateToHwRate8190Pci(u8 rate)
+static u8 MRateToHwRate8190Pci(u8 rate)
{
u8 ret = DESC90_RATE1M;
@@ -2039,7 +1987,7 @@ void rtl8192_usb_deleteendpoints(struct net_device *dev)
#endif
extern void rtl8192_update_ratr_table(struct net_device *dev);
-void rtl8192_link_change(struct net_device *dev)
+static void rtl8192_link_change(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee80211;
@@ -2071,7 +2019,7 @@ static struct ieee80211_qos_parameters def_qos_parameters = {
};
-void rtl8192_update_beacon(struct work_struct *work)
+static void rtl8192_update_beacon(struct work_struct *work)
{
struct r8192_priv *priv = container_of(work, struct r8192_priv, update_beacon_wq.work);
struct net_device *dev = priv->ieee80211->dev;
@@ -2086,8 +2034,8 @@ void rtl8192_update_beacon(struct work_struct *work)
/*
* background support to run QoS activate functionality
*/
-int WDCAPARA_ADD[] = {EDCAPARA_BE, EDCAPARA_BK, EDCAPARA_VI, EDCAPARA_VO};
-void rtl8192_qos_activate(struct work_struct *work)
+static int WDCAPARA_ADD[] = {EDCAPARA_BE, EDCAPARA_BK, EDCAPARA_VI, EDCAPARA_VO};
+static void rtl8192_qos_activate(struct work_struct *work)
{
struct r8192_priv *priv = container_of(work, struct r8192_priv, qos_activate);
struct net_device *dev = priv->ieee80211->dev;
@@ -2315,7 +2263,7 @@ static bool GetNmodeSupportBySecCfg8192(struct net_device *dev)
return true;
}
-bool GetHalfNmodeSupportByAPs819xUsb(struct net_device *dev)
+static bool GetHalfNmodeSupportByAPs819xUsb(struct net_device *dev)
{
bool Reval;
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -2329,7 +2277,7 @@ bool GetHalfNmodeSupportByAPs819xUsb(struct net_device *dev)
return Reval;
}
-void rtl8192_refresh_supportrate(struct r8192_priv *priv)
+static void rtl8192_refresh_supportrate(struct r8192_priv *priv)
{
struct ieee80211_device *ieee = priv->ieee80211;
//we do not consider set support rate for ABG mode, only HT MCS rate is set here.
@@ -2340,7 +2288,7 @@ void rtl8192_refresh_supportrate(struct r8192_priv *priv)
return;
}
-u8 rtl8192_getSupportedWireleeMode(struct net_device *dev)
+static u8 rtl8192_getSupportedWireleeMode(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u8 ret = 0;
@@ -2359,7 +2307,7 @@ u8 rtl8192_getSupportedWireleeMode(struct net_device *dev)
}
return ret;
}
-void rtl8192_SetWirelessMode(struct net_device *dev, u8 wireless_mode)
+static void rtl8192_SetWirelessMode(struct net_device *dev, u8 wireless_mode)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u8 bSupportMode = rtl8192_getSupportedWireleeMode(dev);
@@ -2779,7 +2727,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev)
return;
}
-short rtl8192_get_channel_map(struct net_device *dev)
+static short rtl8192_get_channel_map(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
if (priv->ChannelPlan > COUNTRY_CODE_GLOBAL_DOMAIN) {
@@ -2792,7 +2740,7 @@ short rtl8192_get_channel_map(struct net_device *dev)
return 0;
}
-short rtl8192_init(struct net_device *dev)
+static short rtl8192_init(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -2840,7 +2788,7 @@ short rtl8192_init(struct net_device *dev)
* return: none
* notice: This part need to modified according to the rate set we filtered
* ****************************************************************************/
-void rtl8192_hwconfig(struct net_device *dev)
+static void rtl8192_hwconfig(struct net_device *dev)
{
u32 regRATR = 0, regRRSR = 0;
u8 regBwOpMode = 0, regTmp = 0;
@@ -2923,7 +2871,7 @@ void rtl8192_hwconfig(struct net_device *dev)
//InitializeAdapter and PhyCfg
-bool rtl8192_adapter_start(struct net_device *dev)
+static bool rtl8192_adapter_start(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u32 dwRegRead = 0;
@@ -3179,7 +3127,7 @@ static bool HalTxCheckStuck819xUsb(struct net_device *dev)
* <Assumption: RT_TX_SPINLOCK is acquired.>
* First added: 2006.11.19 by emily
*/
-RESET_TYPE TxCheckStuck(struct net_device *dev)
+static RESET_TYPE TxCheckStuck(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u8 QueueID;
@@ -3282,7 +3230,7 @@ static RESET_TYPE RxCheckStuck(struct net_device *dev)
*
* 8185 and 8185b does not implement this function. This is added by Emily at 2006.11.24
*/
-RESET_TYPE rtl819x_ifcheck_resetornot(struct net_device *dev)
+static RESET_TYPE rtl819x_ifcheck_resetornot(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
RESET_TYPE TxResetType = RESET_TYPE_NORESET;
@@ -3321,7 +3269,7 @@ int rtl8192_close(struct net_device *dev);
-void CamRestoreAllEntry(struct net_device *dev)
+static void CamRestoreAllEntry(struct net_device *dev)
{
u8 EntryId = 0;
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -3397,7 +3345,7 @@ void CamRestoreAllEntry(struct net_device *dev)
// The method checking Tx/Rx stuck of this function is supported by FW,
// which reports Tx and Rx counter to register 0x128 and 0x130.
//////////////////////////////////////////////////////////////
-void rtl819x_ifsilentreset(struct net_device *dev)
+static void rtl819x_ifsilentreset(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u8 reset_times = 0;
@@ -3517,7 +3465,7 @@ void CAM_read_entry(struct net_device *dev, u32 iIndex)
printk("\n");
}
-void rtl819x_update_rxcounts(struct r8192_priv *priv, u32 *TotalRxBcnNum,
+static void rtl819x_update_rxcounts(struct r8192_priv *priv, u32 *TotalRxBcnNum,
u32 *TotalRxDataNum)
{
u16 SlotIndex;
@@ -3536,7 +3484,7 @@ void rtl819x_update_rxcounts(struct r8192_priv *priv, u32 *TotalRxBcnNum,
}
-extern void rtl819x_watchdog_wqcallback(struct work_struct *work)
+void rtl819x_watchdog_wqcallback(struct work_struct *work)
{
struct delayed_work *dwork = container_of(work, struct delayed_work, work);
struct r8192_priv *priv = container_of(dwork, struct r8192_priv, watch_dog_wq);
@@ -3634,7 +3582,7 @@ int _rtl8192_up(struct net_device *dev)
}
-int rtl8192_open(struct net_device *dev)
+static int rtl8192_open(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
int ret;
@@ -3754,7 +3702,7 @@ static void r8192_set_multicast(struct net_device *dev)
}
-int r8192_set_mac_adr(struct net_device *dev, void *mac)
+static int r8192_set_mac_adr(struct net_device *dev, void *mac)
{
struct r8192_priv *priv = ieee80211_priv(dev);
struct sockaddr *addr = mac;
@@ -3770,7 +3718,7 @@ int r8192_set_mac_adr(struct net_device *dev, void *mac)
}
/* based on ipw2200 driver */
-int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
struct iwreq *wrq = (struct iwreq *)rq;
@@ -3861,7 +3809,7 @@ out:
return ret;
}
-u8 HwRateToMRate90(bool bIsHT, u8 rate)
+static u8 HwRateToMRate90(bool bIsHT, u8 rate)
{
u8 ret_rate = 0xff;
@@ -3947,7 +3895,7 @@ static void UpdateRxPktTimeStamp8190(struct net_device *dev,
//by amy 080606
-long rtl819x_translate_todbm(u8 signal_strength_index)// 0-100 index.
+static long rtl819x_translate_todbm(u8 signal_strength_index)// 0-100 index.
{
long signal_power; // in dBm.
@@ -3963,7 +3911,9 @@ long rtl819x_translate_todbm(u8 signal_strength_index)// 0-100 index.
be a local static. Otherwise, it may increase when we return from S3/S4. The
value will be kept in memory or disk. Declare the value in the adaptor
and it will be reinitialized when returned from S3/S4. */
-void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer, struct ieee80211_rx_stats *pprevious_stats, struct ieee80211_rx_stats *pcurrent_stats)
+static void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer,
+ struct ieee80211_rx_stats *pprevious_stats,
+ struct ieee80211_rx_stats *pcurrent_stats)
{
bool bcheck = false;
u8 rfpath;
@@ -4449,8 +4399,8 @@ static void rtl8192_query_rxphystatus(struct r8192_priv *priv,
}
} /* QueryRxPhyStatus8190Pci */
-void rtl8192_record_rxdesc_forlateruse(struct ieee80211_rx_stats *psrc_stats,
- struct ieee80211_rx_stats *ptarget_stats)
+static void rtl8192_record_rxdesc_forlateruse(struct ieee80211_rx_stats *psrc_stats,
+ struct ieee80211_rx_stats *ptarget_stats)
{
ptarget_stats->bIsAMPDU = psrc_stats->bIsAMPDU;
ptarget_stats->bFirstMPDU = psrc_stats->bFirstMPDU;
@@ -4721,7 +4671,7 @@ u32 GetRxPacketShiftBytes819xUsb(struct ieee80211_rx_stats *Status, bool bIsRxA
+ Status->RxBufShift);
}
-void rtl8192_rx_nomal(struct sk_buff *skb)
+static void rtl8192_rx_nomal(struct sk_buff *skb)
{
rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb;
struct net_device *dev = info->dev;
@@ -4871,8 +4821,8 @@ void rtl8192_rx_nomal(struct sk_buff *skb)
}
-void rtl819xusb_process_received_packet(struct net_device *dev,
- struct ieee80211_rx_stats *pstats)
+static void rtl819xusb_process_received_packet(struct net_device *dev,
+ struct ieee80211_rx_stats *pstats)
{
u8 *frame;
u16 frame_len = 0;
@@ -4932,7 +4882,7 @@ static void query_rx_cmdpkt_desc_status(struct sk_buff *skb,
}
-void rtl8192_rx_cmd(struct sk_buff *skb)
+static void rtl8192_rx_cmd(struct sk_buff *skb)
{
struct rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb;
struct net_device *dev = info->dev;
diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c
index 41fb67b7337d..d97ad7b909bc 100644
--- a/drivers/staging/rtl8192u/r8192U_dm.c
+++ b/drivers/staging/rtl8192u/r8192U_dm.c
@@ -50,34 +50,7 @@ DRxPathSel DM_RxPathSelTable;
/*--------------------Define export function prototype-----------------------*/
-extern void init_hal_dm(struct net_device *dev);
-extern void deinit_hal_dm(struct net_device *dev);
-
-extern void hal_dm_watchdog(struct net_device *dev);
-
-
-extern void init_rate_adaptive(struct net_device *dev);
-extern void dm_txpower_trackingcallback(struct work_struct *work);
-
-extern void dm_cck_txpower_adjust(struct net_device *dev,bool binch14);
-extern void dm_restore_dynamic_mechanism_state(struct net_device *dev);
-extern void dm_backup_dynamic_mechanism_state(struct net_device *dev);
-extern void dm_change_dynamic_initgain_thresh(struct net_device *dev,
- u32 dm_type,
- u32 dm_value);
-extern void DM_ChangeFsyncSetting(struct net_device *dev,
- s32 DM_Type,
- s32 DM_Value);
-extern void dm_force_tx_fw_info(struct net_device *dev,
- u32 force_type,
- u32 force_value);
-extern void dm_init_edca_turbo(struct net_device *dev);
-extern void dm_rf_operation_test_callback(unsigned long data);
-extern void dm_rf_pathcheck_workitemcallback(struct work_struct *work);
-extern void dm_fsync_timer_callback(unsigned long data);
extern void dm_check_fsync(struct net_device *dev);
-extern void dm_shadow_init(struct net_device *dev);
-
/*--------------------Define export function prototype-----------------------*/
@@ -155,8 +128,7 @@ static void dm_ctstoself(struct net_device *dev);
// This function is only invoked at driver intialization once.
//
//
-extern void
-init_hal_dm(struct net_device *dev)
+void init_hal_dm(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -176,7 +148,7 @@ init_hal_dm(struct net_device *dev)
} // InitHalDm
-extern void deinit_hal_dm(struct net_device *dev)
+void deinit_hal_dm(struct net_device *dev)
{
dm_deInit_fsync(dev);
@@ -242,7 +214,7 @@ void dm_CheckRxAggregation(struct net_device *dev) {
-extern void hal_dm_watchdog(struct net_device *dev)
+void hal_dm_watchdog(struct net_device *dev)
{
//struct r8192_priv *priv = ieee80211_priv(dev);
@@ -275,7 +247,7 @@ extern void hal_dm_watchdog(struct net_device *dev)
* 01/16/2008 MHC RF_Type is assigned in ReadAdapterInfo(). We must call
* the function after making sure RF_Type.
*/
-extern void init_rate_adaptive(struct net_device *dev)
+void init_rate_adaptive(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -875,7 +847,7 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev)
priv->txpower_count = 0;
}
-extern void dm_txpower_trackingcallback(struct work_struct *work)
+void dm_txpower_trackingcallback(struct work_struct *work)
{
struct delayed_work *dwork = container_of(work,struct delayed_work,work);
struct r8192_priv *priv = container_of(dwork,struct r8192_priv,txpower_tracking_wq);
@@ -1606,10 +1578,7 @@ static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, bool bInCH
-extern void dm_cck_txpower_adjust(
- struct net_device *dev,
- bool binch14
-)
+void dm_cck_txpower_adjust(struct net_device *dev, bool binch14)
{ // dm_CCKTxPowerAdjust
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -1642,7 +1611,7 @@ static void dm_txpower_reset_recovery(
} // dm_TXPowerResetRecovery
-extern void dm_restore_dynamic_mechanism_state(struct net_device *dev)
+void dm_restore_dynamic_mechanism_state(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u32 reg_ratr = priv->rate_adaptive.last_ratr;
@@ -1718,7 +1687,7 @@ static void dm_bb_initialgain_restore(struct net_device *dev)
} // dm_BBInitialGainRestore
-extern void dm_backup_dynamic_mechanism_state(struct net_device *dev)
+void dm_backup_dynamic_mechanism_state(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -1773,9 +1742,9 @@ static void dm_bb_initialgain_backup(struct net_device *dev)
* 05/29/2008 amy Create Version 0 porting from windows code.
*
*---------------------------------------------------------------------------*/
-extern void dm_change_dynamic_initgain_thresh(struct net_device *dev,
- u32 dm_type,
- u32 dm_value)
+
+void dm_change_dynamic_initgain_thresh(struct net_device *dev, u32 dm_type,
+ u32 dm_value)
{
if (dm_type == DIG_TYPE_THRESH_HIGH)
{
@@ -1842,24 +1811,8 @@ extern void dm_change_dynamic_initgain_thresh(struct net_device *dev,
dm_digtable.rx_gain_range_max = (u8)dm_value;
}
} /* DM_ChangeDynamicInitGainThresh */
-extern void
-dm_change_fsync_setting(
- struct net_device *dev,
- s32 DM_Type,
- s32 DM_Value)
-{
- struct r8192_priv *priv = ieee80211_priv(dev);
- if (DM_Type == 0) // monitor 0xc38 register
- {
- if(DM_Value > 1)
- DM_Value = 1;
- priv->framesyncMonitor = (u8)DM_Value;
- //DbgPrint("pHalData->framesyncMonitor = %d", pHalData->framesyncMonitor);
- }
-}
-
-extern void
+void
dm_change_rxpath_selection_setting(
struct net_device *dev,
s32 DM_Type,
@@ -2540,7 +2493,7 @@ static void dm_cs_ratio(
}
}
-extern void dm_init_edca_turbo(struct net_device *dev)
+void dm_init_edca_turbo(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -2660,26 +2613,6 @@ dm_CheckEdcaTurbo_EXIT:
lastRxOkCnt = priv->stats.rxbytesunicast;
} // dm_CheckEdcaTurbo
-extern void DM_CTSToSelfSetting(struct net_device *dev,u32 DM_Type, u32 DM_Value)
-{
- struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev);
-
- if (DM_Type == 0) // CTS to self disable/enable
- {
- if(DM_Value > 1)
- DM_Value = 1;
- priv->ieee80211->bCTSToSelfEnable = (bool)DM_Value;
- //DbgPrint("pMgntInfo->bCTSToSelfEnable = %d\n", pMgntInfo->bCTSToSelfEnable);
- }
- else if(DM_Type == 1) //CTS to self Th
- {
- if(DM_Value >= 50)
- DM_Value = 50;
- priv->ieee80211->CTSToSelfTH = (u8)DM_Value;
- //DbgPrint("pMgntInfo->CTSToSelfTH = %d\n", pMgntInfo->CTSToSelfTH);
- }
-}
-
static void dm_init_ctstoself(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev);
@@ -2779,7 +2712,7 @@ static void dm_check_pbc_gpio(struct net_device *dev)
* 01/30/2008 MHC Create Version 0.
*
*---------------------------------------------------------------------------*/
-extern void dm_rf_pathcheck_workitemcallback(struct work_struct *work)
+void dm_rf_pathcheck_workitemcallback(struct work_struct *work)
{
struct delayed_work *dwork = container_of(work,struct delayed_work,work);
struct r8192_priv *priv = container_of(dwork,struct r8192_priv,rfpath_check_wq);
@@ -3139,7 +3072,7 @@ static void dm_deInit_fsync(struct net_device *dev)
del_timer_sync(&priv->fsync_timer);
}
-extern void dm_fsync_timer_callback(unsigned long data)
+void dm_fsync_timer_callback(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct r8192_priv *priv = ieee80211_priv((struct net_device *)data);
@@ -3478,7 +3411,7 @@ void dm_check_fsync(struct net_device *dev)
* 05/29/2008 amy Create Version 0 porting from windows code.
*
*---------------------------------------------------------------------------*/
-extern void dm_shadow_init(struct net_device *dev)
+void dm_shadow_init(struct net_device *dev)
{
u8 page;
u16 offset;
diff --git a/drivers/staging/rtl8192u/r8192U_dm.h b/drivers/staging/rtl8192u/r8192U_dm.h
index ae550520311b..3008f91ad4cf 100644
--- a/drivers/staging/rtl8192u/r8192U_dm.h
+++ b/drivers/staging/rtl8192u/r8192U_dm.h
@@ -200,9 +200,9 @@ typedef struct tag_Tx_Config_Cmd_Format {
/*------------------------Export global variable----------------------------*/
-extern dig_t dm_digtable;
-extern u8 dm_shadow[16][256];
-extern DRxPathSel DM_RxPathSelTable;
+extern dig_t dm_digtable;
+extern u8 dm_shadow[16][256];
+extern DRxPathSel DM_RxPathSelTable;
/*------------------------Export global variable----------------------------*/
@@ -212,25 +212,23 @@ extern DRxPathSel DM_RxPathSelTable;
/*--------------------------Exported Function prototype---------------------*/
-extern void init_hal_dm(struct net_device *dev);
-extern void deinit_hal_dm(struct net_device *dev);
-
+extern void init_hal_dm(struct net_device *dev);
+extern void deinit_hal_dm(struct net_device *dev);
extern void hal_dm_watchdog(struct net_device *dev);
-
-extern void init_rate_adaptive(struct net_device *dev);
-extern void dm_txpower_trackingcallback(struct work_struct *work);
-extern void dm_restore_dynamic_mechanism_state(struct net_device *dev);
-extern void dm_backup_dynamic_mechanism_state(struct net_device *dev);
-extern void dm_change_dynamic_initgain_thresh(struct net_device *dev,
- u32 dm_type, u32 dm_value);
-extern void dm_force_tx_fw_info(struct net_device *dev,
- u32 force_type, u32 force_value);
-extern void dm_init_edca_turbo(struct net_device *dev);
-extern void dm_rf_operation_test_callback(unsigned long data);
-extern void dm_rf_pathcheck_workitemcallback(struct work_struct *work);
-extern void dm_fsync_timer_callback(unsigned long data);
-extern void dm_cck_txpower_adjust(struct net_device *dev, bool binch14);
-extern void dm_shadow_init(struct net_device *dev);
+extern void init_rate_adaptive(struct net_device *dev);
+extern void dm_txpower_trackingcallback(struct work_struct *work);
+extern void dm_restore_dynamic_mechanism_state(struct net_device *dev);
+extern void dm_backup_dynamic_mechanism_state(struct net_device *dev);
+extern void dm_change_dynamic_initgain_thresh(struct net_device *dev,
+ u32 dm_type, u32 dm_value);
+extern void dm_force_tx_fw_info(struct net_device *dev,
+ u32 force_type, u32 force_value);
+extern void dm_init_edca_turbo(struct net_device *dev);
+extern void dm_rf_operation_test_callback(unsigned long data);
+extern void dm_rf_pathcheck_workitemcallback(struct work_struct *work);
+extern void dm_fsync_timer_callback(unsigned long data);
+extern void dm_cck_txpower_adjust(struct net_device *dev, bool binch14);
+extern void dm_shadow_init(struct net_device *dev);
extern void dm_initialize_txpower_tracking(struct net_device *dev);
/*--------------------------Exported Function prototype---------------------*/
diff --git a/drivers/staging/rtl8192u/r819xU_HTGen.h b/drivers/staging/rtl8192u/r819xU_HTGen.h
deleted file mode 100644
index 6a4678f7da5f..000000000000
--- a/drivers/staging/rtl8192u/r819xU_HTGen.h
+++ /dev/null
@@ -1,12 +0,0 @@
-//
-// IOT Action for different AP
-//
-typedef enum _HT_IOT_ACTION{
- HT_IOT_ACT_TX_USE_AMSDU_4K = 0x00000001,
- HT_IOT_ACT_TX_USE_AMSDU_8K = 0x00000002,
- HT_IOT_ACT_DECLARE_MCS13 = 0x00000004,
- HT_IOT_ACT_DISABLE_EDCA_TURBO = 0x00000008,
- HT_IOT_ACT_MGNT_USE_CCK_6M = 0x00000010,
- HT_IOT_ACT_CDD_FSYNC = 0x00000020,
- HT_IOT_ACT_PURE_N_MODE = 0x00000040,
-}HT_IOT_ACTION_E, *PHT_IOT_ACTION_E;
diff --git a/drivers/staging/rtl8192u/r819xU_HTType.h b/drivers/staging/rtl8192u/r819xU_HTType.h
deleted file mode 100644
index 2cbb8e6584f8..000000000000
--- a/drivers/staging/rtl8192u/r819xU_HTType.h
+++ /dev/null
@@ -1,379 +0,0 @@
-#ifndef _R819XU_HTTYPE_H_
-#define _R819XU_HTTYPE_H_
-
-
-/*----------------------------------------------------------------------
- * The HT Capability element is present in beacons, association request,
- * reassociation request and probe response frames
- *----------------------------------------------------------------------*/
-
-/* Operation mode value */
-#define HT_OPMODE_NO_PROTECT 0
-#define HT_OPMODE_OPTIONAL 1
-#define HT_OPMODE_40MHZ_PROTECT 2
-#define HT_OPMODE_MIXED 3
-
-/* MIMO Power Save Settings */
-#define MIMO_PS_STATIC 0
-#define MIMO_PS_DYNAMIC 1
-#define MIMO_PS_NOLIMIT 3
-
-
-/* There should be 128 bits to cover all of the MCS rates. However, since
- * 8190 does not support too much rates, one integer is quite enough. */
-
-#define sHTCLng 4
-
-
-#define HT_SUPPORTED_MCS_1SS_BITMAP 0x000000ff
-#define HT_SUPPORTED_MCS_2SS_BITMAP 0x0000ff00
-#define HT_SUPPORTED_MCS_1SS_2SS_BITMAP \
- (HT_MCS_1SS_BITMAP | HT_MCS_1SS_2SS_BITMAP)
-
-
-typedef enum _HT_MCS_RATE {
- HT_MCS0 = 0x00000001,
- HT_MCS1 = 0x00000002,
- HT_MCS2 = 0x00000004,
- HT_MCS3 = 0x00000008,
- HT_MCS4 = 0x00000010,
- HT_MCS5 = 0x00000020,
- HT_MCS6 = 0x00000040,
- HT_MCS7 = 0x00000080,
- HT_MCS8 = 0x00000100,
- HT_MCS9 = 0x00000200,
- HT_MCS10 = 0x00000400,
- HT_MCS11 = 0x00000800,
- HT_MCS12 = 0x00001000,
- HT_MCS13 = 0x00002000,
- HT_MCS14 = 0x00004000,
- HT_MCS15 = 0x00008000,
- /* Do not define MCS32 here although 8190 support MCS32 */
-} HT_MCS_RATE, *PHT_MCS_RATE;
-
-/* Represent Channel Width in HT Capabilities */
-typedef enum _HT_CHANNEL_WIDTH {
- HT_CHANNEL_WIDTH_20 = 0,
- HT_CHANNEL_WIDTH_20_40 = 1,
-} HT_CHANNEL_WIDTH, *PHT_CHANNEL_WIDTH;
-
-/* Represent Extension Channel Offset in HT Capabilities
- * This is available only in 40Mhz mode. */
-typedef enum _HT_EXTCHNL_OFFSET {
- HT_EXTCHNL_OFFSET_NO_EXT = 0,
- HT_EXTCHNL_OFFSET_UPPER = 1,
- HT_EXTCHNL_OFFSET_NO_DEF = 2,
- HT_EXTCHNL_OFFSET_LOWER = 3,
-} HT_EXTCHNL_OFFSET, *PHT_EXTCHNL_OFFSET;
-
-typedef enum _CHNLOP {
- CHNLOP_NONE = 0, /* No Action now */
- CHNLOP_SCAN = 1, /* Scan in progress */
- CHNLOP_SWBW = 2, /* Bandwidth switching in progress */
- CHNLOP_SWCHNL = 3, /* Software Channel switching in progress */
-} CHNLOP, *PCHNLOP;
-
-/* Determine if the Channel Operation is in progress */
-#define CHHLOP_IN_PROGRESS(_pHTInfo) \
- (((_pHTInfo)->ChnlOp > CHNLOP_NONE) ? TRUE : FALSE)
-
-
-typedef enum _HT_ACTION {
- ACT_RECOMMAND_WIDTH = 0,
- ACT_MIMO_PWR_SAVE = 1,
- ACT_PSMP = 2,
- ACT_SET_PCO_PHASE = 3,
- ACT_MIMO_CHL_MEASURE = 4,
- ACT_RECIPROCITY_CORRECT = 5,
- ACT_MIMO_CSI_MATRICS = 6,
- ACT_MIMO_NOCOMPR_STEER = 7,
- ACT_MIMO_COMPR_STEER = 8,
- ACT_ANTENNA_SELECT = 9,
-} HT_ACTION, *PHT_ACTION;
-
-
-/* Define sub-carrier mode for 40MHZ. */
-typedef enum _HT_Bandwidth_40MHZ_Sub_Carrier {
- SC_MODE_DUPLICATE = 0,
- SC_MODE_LOWER = 1,
- SC_MODE_UPPER = 2,
- SC_MODE_FULL40MHZ = 3,
-} HT_BW40_SC_E;
-
-typedef struct _HT_CAPABILITY_ELE {
-
- /* HT capability info */
- u8 AdvCoding:1;
- u8 ChlWidth:1;
- u8 MimoPwrSave:2;
- u8 GreenField:1;
- u8 ShortGI20Mhz:1;
- u8 ShortGI40Mhz:1;
- u8 TxSTBC:1;
- u8 RxSTBC:2;
- u8 DelayBA:1;
- u8 MaxAMSDUSize:1;
- u8 DssCCk:1;
- u8 PSMP:1;
- u8 Rsvd1:1;
- u8 LSigTxopProtect:1;
-
- /* MAC HT parameters info */
- u8 MaxRxAMPDUFactor:2;
- u8 MPDUDensity:3;
- u8 Rsvd2:3;
-
- /* Supported MCS set */
- u8 MCS[16];
-
-
- /* Extended HT Capability Info */
- u16 ExtHTCapInfo;
-
- /* TXBF Capabilities */
- u8 TxBFCap[4];
-
- /* Antenna Selection Capabilities */
- u8 ASCap;
-
-} __packed HT_CAPABILITY_ELE, *PHT_CAPABILITY_ELE;
-
-/*------------------------------------------------------------
- * The HT Information element is present in beacons
- * Only AP is required to include this element
- *------------------------------------------------------------*/
-
-typedef struct _HT_INFORMATION_ELE {
- u8 ControlChl;
-
- u8 ExtChlOffset:2;
- u8 RecommemdedTxWidth:1;
- u8 RIFS:1;
- u8 PSMPAccessOnly:1;
- u8 SrvIntGranularity:3;
-
- u8 OptMode:2;
- u8 NonGFDevPresent:1;
- u8 Revd1:5;
- u8 Revd2:8;
-
- u8 Rsvd3:6;
- u8 DualBeacon:1;
- u8 DualCTSProtect:1;
-
- u8 SecondaryBeacon:1;
- u8 LSigTxopProtectFull:1;
- u8 PcoActive:1;
- u8 PcoPhase:1;
- u8 Rsvd4:4;
-
- u8 BasicMSC[16];
-} __packed HT_INFORMATION_ELE, *PHT_INFORMATION_ELE;
-
-/* MIMO Power Save control field.
- * This is appear in MIMO Power Save Action Frame */
-typedef struct _MIMOPS_CTRL {
- u8 MimoPsEnable:1;
- u8 MimoPsMode:1;
- u8 Reserved:6;
-} MIMOPS_CTRL, *PMIMOPS_CTRL;
-
-typedef enum _HT_SPEC_VER {
- HT_SPEC_VER_IEEE = 0,
- HT_SPEC_VER_EWC = 1,
-} HT_SPEC_VER, *PHT_SPEC_VER;
-
-typedef enum _HT_AGGRE_MODE_E {
- HT_AGG_AUTO = 0,
- HT_AGG_FORCE_ENABLE = 1,
- HT_AGG_FORCE_DISABLE = 2,
-} HT_AGGRE_MODE_E, *PHT_AGGRE_MODE_E;
-
-/*----------------------------------------------------------------------------
- * The Data structure is used to keep HT related variables when card is
- * configured as non-AP STA mode.
- * **Note** Current_xxx should be set to default value in HTInitializeHTInfo()
- *----------------------------------------------------------------------------*/
-
-typedef struct _RT_HIGH_THROUGHPUT {
- u8 bEnableHT;
- u8 bCurrentHTSupport;
- /* Tx 40MHz channel capability */
- u8 bRegBW40MHz;
- u8 bCurBW40MHz;
- /* Tx Short GI for 40Mhz */
- u8 bRegShortGI40MHz;
- u8 bCurShortGI40MHz;
- /* Tx Short GI for 20MHz */
- u8 bRegShortGI20MHz;
- u8 bCurShortGI20MHz;
- /* Tx CCK rate capability */
- u8 bRegSuppCCK;
- u8 bCurSuppCCK;
-
- /* 802.11n spec version for "peer" */
- HT_SPEC_VER ePeerHTSpecVer;
-
-
- /* HT related information for "Self" */
- /* This is HT cap element sent to peer STA, which also indicate
- * HT Rx capabilities. */
- HT_CAPABILITY_ELE SelfHTCap;
- HT_INFORMATION_ELE SelfHTInfo;
-
- /* HT related information for "Peer" */
- u8 PeerHTCapBuf[32];
- u8 PeerHTInfoBuf[32];
-
-
- /* A-MSDU related */
- /* This indicates Tx A-MSDU capability */
- u8 bAMSDU_Support;
- u16 nAMSDU_MaxSize;
- u8 bCurrent_AMSDU_Support;
- u16 nCurrent_AMSDU_MaxSize;
-
-
- /* A-MPDU related */
- /* This indicate Tx A-MPDU capability */
- u8 bAMPDUEnable;
- u8 bCurrentAMPDUEnable;
- u8 AMPDU_Factor;
- u8 CurrentAMPDUFactor;
- u8 MPDU_Density;
- u8 CurrentMPDUDensity;
-
- /* Forced A-MPDU enable */
- HT_AGGRE_MODE_E ForcedAMPDUMode;
- u8 ForcedAMPDUFactor;
- u8 ForcedMPDUDensity;
-
- /* Forced A-MSDU enable */
- HT_AGGRE_MODE_E ForcedAMSDUMode;
- u16 ForcedAMSDUMaxSize;
-
- u8 bForcedShortGI;
-
- u8 CurrentOpMode;
-
- /* MIMO PS related */
- u8 SelfMimoPs;
- u8 PeerMimoPs;
-
- /* 40MHz Channel Offset settings. */
- HT_EXTCHNL_OFFSET CurSTAExtChnlOffset;
- u8 bCurTxBW40MHz; /* If we use 40 MHz to Tx */
- u8 PeerBandwidth;
-
- /* For Bandwidth Switching */
- u8 bSwBwInProgress;
- CHNLOP ChnlOp; /* sw switching channel in progress. */
- u8 SwBwStep;
- struct timer_list SwBwTimer;
-
- /* For Realtek proprietary A-MPDU factor for aggregation */
- u8 bRegRT2RTAggregation;
- u8 bCurrentRT2RTAggregation;
- u8 bCurrentRT2RTLongSlotTime;
- u8 szRT2RTAggBuffer[10];
-
- /* Rx Reorder control */
- u8 bRegRxReorderEnable;
- u8 bCurRxReorderEnable;
- u8 RxReorderWinSize;
- u8 RxReorderPendingTime;
- u16 RxReorderDropCounter;
-
-#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE
- u8 UsbTxAggrNum;
-#endif
-#ifdef USB_RX_AGGREGATION_SUPPORT
- u8 UsbRxFwAggrEn;
- u8 UsbRxFwAggrPageNum;
- u8 UsbRxFwAggrPacketNum;
- u8 UsbRxFwAggrTimeout;
-#endif
-
- /* Add for Broadcom(Linksys) IOT. */
- u8 bIsPeerBcm;
-
- /* For IOT issue. */
- u32 IOTAction;
-} RT_HIGH_THROUGHPUT, *PRT_HIGH_THROUGHPUT;
-
-
-/*----------------------------------------------------------------------
- * The Data structure is used to keep HT related variable for "each Sta"
- * when card is configured as "AP mode"
- *----------------------------------------------------------------------*/
-
-typedef struct _RT_HTINFO_STA_ENTRY {
- u8 bEnableHT;
-
- u8 bSupportCck;
-
- u16 AMSDU_MaxSize;
-
- u8 AMPDU_Factor;
- u8 MPDU_Density;
-
- u8 HTHighestOperaRate;
-
- u8 bBw40MHz;
-
- u8 MimoPs;
-
- u8 McsRateSet[16];
-
-
-} RT_HTINFO_STA_ENTRY, *PRT_HTINFO_STA_ENTRY;
-
-
-
-
-
-/*---------------------------------------------------------------------
- * The Data structure is used to keep HT related variable for "each AP"
- * when card is configured as "STA mode"
- *---------------------------------------------------------------------*/
-
-typedef struct _BSS_HT {
-
- u8 bdSupportHT;
-
- /* HT related elements */
- u8 bdHTCapBuf[32];
- u16 bdHTCapLen;
- u8 bdHTInfoBuf[32];
- u16 bdHTInfoLen;
-
- HT_SPEC_VER bdHTSpecVer;
-
- u8 bdRT2RTAggregation;
- u8 bdRT2RTLongSlotTime;
-} BSS_HT, *PBSS_HT;
-
-typedef struct _MIMO_RSSI {
- u32 EnableAntenna;
- u32 AntennaA;
- u32 AntennaB;
- u32 AntennaC;
- u32 AntennaD;
- u32 Average;
-} MIMO_RSSI, *PMIMO_RSSI;
-
-typedef struct _MIMO_EVM {
- u32 EVM1;
- u32 EVM2;
-} MIMO_EVM, *PMIMO_EVM;
-
-typedef struct _FALSE_ALARM_STATISTICS {
- u32 Cnt_Parity_Fail;
- u32 Cnt_Rate_Illegal;
- u32 Cnt_Crc8_fail;
- u32 Cnt_all;
-} FALSE_ALARM_STATISTICS, *PFALSE_ALARM_STATISTICS;
-
-
-
-#endif
diff --git a/drivers/staging/rtl8192u/r819xU_cmdpkt.c b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
index 7bdcbd39a3b2..723c8630e9e2 100644
--- a/drivers/staging/rtl8192u/r819xU_cmdpkt.c
+++ b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
@@ -182,7 +182,7 @@ static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
}
-void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
+static void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u16 tx_rate;
diff --git a/drivers/staging/rtl8192u/r819xU_firmware.c b/drivers/staging/rtl8192u/r819xU_firmware.c
index d6a6de3a64f5..ecfb66538eb3 100644
--- a/drivers/staging/rtl8192u/r819xU_firmware.c
+++ b/drivers/staging/rtl8192u/r819xU_firmware.c
@@ -17,7 +17,8 @@
#include "r819xU_firmware_img.h"
#include "r819xU_firmware.h"
#include <linux/firmware.h>
-void firmware_init_param(struct net_device *dev)
+
+static void firmware_init_param(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
rt_firmware *pfirmware = priv->pFirmware;
@@ -29,7 +30,8 @@ void firmware_init_param(struct net_device *dev)
* segment the img and use the ptr and length to remember info on each segment
*
*/
-bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, u32 buffer_len)
+static bool fw_download_code(struct net_device *dev, u8 *code_virtual_address,
+ u32 buffer_len)
{
struct r8192_priv *priv = ieee80211_priv(dev);
bool rt_status = true;
@@ -103,46 +105,6 @@ bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, u32 buff
}
-bool
-fwSendNullPacket(
- struct net_device *dev,
- u32 Length
-)
-{
- bool rtStatus = true;
- struct r8192_priv *priv = ieee80211_priv(dev);
- struct sk_buff *skb;
- cb_desc *tcb_desc;
- unsigned char *ptr_buf;
- bool bLastInitPacket = false;
-
- //PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK);
-
- //Get TCB and local buffer from common pool. (It is shared by CmdQ, MgntQ, and USB coalesce DataQ)
- skb = dev_alloc_skb(Length+ 4);
- memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
- tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
- tcb_desc->queue_index = TXCMD_QUEUE;
- tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT;
- tcb_desc->bLastIniPkt = bLastInitPacket;
- ptr_buf = skb_put(skb, Length);
- memset(ptr_buf,0,Length);
- tcb_desc->txbuf_size= (u16)Length;
-
- if (!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)||
- (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\
- (priv->ieee80211->queue_stop) ) {
- RT_TRACE(COMP_FIRMWARE,"===================NULL packet==================================> tx full!\n");
- skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
- } else {
- priv->ieee80211->softmac_hard_start_xmit(skb,dev);
- }
-
- //PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);
- return rtStatus;
-}
-
-
//-----------------------------------------------------------------------------
// Procedure: Check whether main code is download OK. If OK, turn on CPU
//
@@ -156,7 +118,7 @@ fwSendNullPacket(
// NDIS_STATUS_FAILURE - the following initialization process should be terminated
// NDIS_STATUS_SUCCESS - if firmware initialization process success
//-----------------------------------------------------------------------------
-bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev)
+static bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev)
{
bool rt_status = true;
int check_putcodeOK_time = 200000, check_bootOk_time = 200000;
@@ -205,7 +167,7 @@ CPUCheckMainCodeOKAndTurnOnCPU_Fail:
return rt_status;
}
-bool CPUcheck_firmware_ready(struct net_device *dev)
+static bool CPUcheck_firmware_ready(struct net_device *dev)
{
bool rt_status = true;
diff --git a/drivers/staging/rtl8192u/r819xU_firmware_img.c b/drivers/staging/rtl8192u/r819xU_firmware_img.c
index df0f9d1648ec..0785de72a5ea 100644
--- a/drivers/staging/rtl8192u/r819xU_firmware_img.c
+++ b/drivers/staging/rtl8192u/r819xU_firmware_img.c
@@ -1,5 +1,6 @@
/*Created on 2008/ 7/16, 5:31*/
#include <linux/types.h>
+#include "r819xU_firmware_img.h"
u32 Rtl8192UsbPHY_REGArray[] = {
0x0, };
diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c
index 39cd426bc5e5..b9f35313c7ab 100644
--- a/drivers/staging/rtl8192u/r819xU_phy.c
+++ b/drivers/staging/rtl8192u/r819xU_phy.c
@@ -44,7 +44,7 @@ static u32 RF_CHANNEL_TABLE_ZEBRA[] = {
* output: none
* return: u32 return the shift bit position of the mask
******************************************************************************/
-u32 rtl8192_CalculateBitShift(u32 bitmask)
+static u32 rtl8192_CalculateBitShift(u32 bitmask)
{
u32 i;
@@ -144,8 +144,8 @@ static void phy_FwRFSerialWrite(struct net_device *dev,
* Driver here need to implement (1) and (2)
* ---need more spec for this information.
******************************************************************************/
-u32 rtl8192_phy_RFSerialRead(struct net_device *dev, RF90_RADIO_PATH_E eRFPath,
- u32 offset)
+static u32 rtl8192_phy_RFSerialRead(struct net_device *dev,
+ RF90_RADIO_PATH_E eRFPath, u32 offset)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u32 ret = 0;
@@ -229,8 +229,9 @@ u32 rtl8192_phy_RFSerialRead(struct net_device *dev, RF90_RADIO_PATH_E eRFPath,
* Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf)
* ---------------------------------------------------------------------------
*****************************************************************************/
-void rtl8192_phy_RFSerialWrite(struct net_device *dev,
- RF90_RADIO_PATH_E eRFPath, u32 offset, u32 data)
+static void rtl8192_phy_RFSerialWrite(struct net_device *dev,
+ RF90_RADIO_PATH_E eRFPath, u32 offset,
+ u32 data)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u32 DataAndAddr = 0, new_offset = 0;
@@ -571,7 +572,7 @@ void rtl8192_phyConfigBB(struct net_device *dev, u8 ConfigType)
* notice: Initialization value here is constant and it should never
* be changed
*****************************************************************************/
-void rtl8192_InitBBRFRegDef(struct net_device *dev)
+static void rtl8192_InitBBRFRegDef(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -780,7 +781,7 @@ u8 rtl8192_phy_checkBBAndRF(struct net_device *dev, HW90_BLOCK_E CheckBlock,
* notice: Initialization value may change all the time, so please make
* sure it has been synced with the newest.
******************************************************************************/
-void rtl8192_BB_Config_ParaFile(struct net_device *dev)
+static void rtl8192_BB_Config_ParaFile(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u8 reg_u8 = 0, eCheckItem = 0, status = 0;
@@ -1070,7 +1071,7 @@ u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device *dev,
* return: none
* notice:
******************************************************************************/
-void rtl8192_SetTxPowerLevel(struct net_device *dev, u8 channel)
+static void rtl8192_SetTxPowerLevel(struct net_device *dev, u8 channel)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u8 powerlevel = priv->TxPowerLevelCCK[channel-1];
@@ -1239,9 +1240,9 @@ bool rtl8192_SetRFPowerState(struct net_device *dev,
* return: true if finished, false otherwise
* notice:
******************************************************************************/
-u8 rtl8192_phy_SetSwChnlCmdArray(SwChnlCmd *CmdTable, u32 CmdTableIdx,
- u32 CmdTableSz, SwChnlCmdID CmdID, u32 Para1,
- u32 Para2, u32 msDelay)
+static u8 rtl8192_phy_SetSwChnlCmdArray(SwChnlCmd *CmdTable, u32 CmdTableIdx,
+ u32 CmdTableSz, SwChnlCmdID CmdID,
+ u32 Para1, u32 Para2, u32 msDelay)
{
SwChnlCmd *pCmd;
@@ -1276,8 +1277,8 @@ u8 rtl8192_phy_SetSwChnlCmdArray(SwChnlCmd *CmdTable, u32 CmdTableIdx,
* return: true if finished, false otherwise
* notice: Wait for simpler function to replace it
*****************************************************************************/
-u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, u8 *stage,
- u8 *step, u32 *delay)
+static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel,
+ u8 *stage, u8 *step, u32 *delay)
{
struct r8192_priv *priv = ieee80211_priv(dev);
SwChnlCmd PreCommonCmd[MAX_PRECMD_CNT];
@@ -1433,7 +1434,7 @@ u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, u8 *stage,
* return: none
* notice: We should not call this function directly
*****************************************************************************/
-void rtl8192_phy_FinishSwChnlNow(struct net_device *dev, u8 channel)
+static void rtl8192_phy_FinishSwChnlNow(struct net_device *dev, u8 channel)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u32 delay = 0;
diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h
index a074fe810169..3362e5e32bcc 100644
--- a/drivers/staging/rtl8712/drv_types.h
+++ b/drivers/staging/rtl8712/drv_types.h
@@ -168,7 +168,7 @@ struct _adapter {
struct task_struct *xmitThread;
pid_t recvThread;
uint(*dvobj_init)(struct _adapter *adapter);
- void (*dvobj_deinit)(struct _adapter *adapter);
+ void (*dvobj_deinit)(struct _adapter *adapter);
struct net_device *pnetdev;
int bup;
struct net_device_stats stats;
diff --git a/drivers/staging/rtl8712/ieee80211.c b/drivers/staging/rtl8712/ieee80211.c
index cc68d9748edb..57fef70ad984 100644
--- a/drivers/staging/rtl8712/ieee80211.c
+++ b/drivers/staging/rtl8712/ieee80211.c
@@ -78,9 +78,9 @@ uint r8712_is_cckrates_included(u8 *rate)
if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) ||
(((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22))
return true;
- i++;
- }
- return false;
+ i++;
+ }
+ return false;
}
uint r8712_is_cckratesonly_included(u8 *rate)
diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c
index 37fe33005c02..6bd08213cb70 100644
--- a/drivers/staging/rtl8712/os_intfs.c
+++ b/drivers/staging/rtl8712/os_intfs.c
@@ -239,7 +239,7 @@ static u32 start_drv_threads(struct _adapter *padapter)
{
padapter->cmdThread = kthread_run(r8712_cmd_thread, padapter, "%s",
padapter->pnetdev->name);
- if (IS_ERR(padapter->cmdThread) < 0)
+ if (IS_ERR(padapter->cmdThread))
return _FAIL;
return _SUCCESS;
}
diff --git a/drivers/staging/rtl8712/osdep_service.h b/drivers/staging/rtl8712/osdep_service.h
index f1ccc7ebbda7..566235a14a80 100644
--- a/drivers/staging/rtl8712/osdep_service.h
+++ b/drivers/staging/rtl8712/osdep_service.h
@@ -147,7 +147,8 @@ static inline u32 _queue_empty(struct __queue *pqueue)
return is_list_empty(&(pqueue->queue));
}
-static inline u32 end_of_queue_search(struct list_head *head, struct list_head *plist)
+static inline u32 end_of_queue_search(struct list_head *head,
+ struct list_head *plist)
{
if (head == plist)
return true;
@@ -164,7 +165,7 @@ static inline void sleep_schedulable(int ms)
delta = 1;/* 1 ms */
set_current_state(TASK_INTERRUPTIBLE);
if (schedule_timeout(delta) != 0)
- return ;
+ return;
}
static inline u8 *_malloc(u32 sz)
diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c
index ea965370d1ac..0723b2f73aad 100644
--- a/drivers/staging/rtl8712/rtl8712_recv.c
+++ b/drivers/staging/rtl8712/rtl8712_recv.c
@@ -90,7 +90,6 @@ int r8712_init_recv_priv(struct recv_priv *precvpriv, struct _adapter *padapter)
pskb = netdev_alloc_skb(padapter->pnetdev, MAX_RECVBUF_SZ +
RECVBUFF_ALIGN_SZ);
if (pskb) {
- pskb->dev = padapter->pnetdev;
tmpaddr = (addr_t)pskb->data;
alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));
@@ -1083,7 +1082,6 @@ static int recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb)
alloc_sz += 6;
pkt_copy = netdev_alloc_skb(padapter->pnetdev, alloc_sz);
if (pkt_copy) {
- pkt_copy->dev = padapter->pnetdev;
precvframe->u.hdr.pkt = pkt_copy;
skb_reserve(pkt_copy, 4 - ((addr_t)(pkt_copy->data)
% 4));
diff --git a/drivers/staging/rtl8712/rtl871x_cmd.c b/drivers/staging/rtl8712/rtl871x_cmd.c
index c71c7e55bb36..a67185db392b 100644
--- a/drivers/staging/rtl8712/rtl871x_cmd.c
+++ b/drivers/staging/rtl8712/rtl871x_cmd.c
@@ -468,10 +468,9 @@ u8 r8712_createbss_cmd(struct _adapter *padapter)
pcmd->rsp = NULL;
pcmd->rspsz = 0;
/* notes: translate IELength & Length after assign to cmdsz; */
- pdev_network->Length = cpu_to_le32(pcmd->cmdsz);
- pdev_network->IELength = cpu_to_le32(pdev_network->IELength);
- pdev_network->Ssid.SsidLength = cpu_to_le32(
- pdev_network->Ssid.SsidLength);
+ pdev_network->Length = pcmd->cmdsz;
+ pdev_network->IELength = pdev_network->IELength;
+ pdev_network->Ssid.SsidLength = pdev_network->Ssid.SsidLength;
r8712_enqueue_cmd(pcmdpriv, pcmd);
return _SUCCESS;
}
@@ -911,7 +910,7 @@ void r8712_joinbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- if ((pcmd->res != H2C_SUCCESS))
+ if (pcmd->res != H2C_SUCCESS)
_set_timer(&pmlmepriv->assoc_timer, 1);
r8712_free_cmd_obj(pcmd);
}
@@ -928,7 +927,7 @@ void r8712_createbss_cmd_callback(struct _adapter *padapter,
pcmd->parmbuf;
struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
- if ((pcmd->res != H2C_SUCCESS))
+ if (pcmd->res != H2C_SUCCESS)
_set_timer(&pmlmepriv->assoc_timer, 1);
_cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled);
#ifdef __BIG_ENDIAN
diff --git a/drivers/staging/rtl8712/rtl871x_security.c b/drivers/staging/rtl8712/rtl871x_security.c
index aae5125a2e7e..5ffc489e9501 100644
--- a/drivers/staging/rtl8712/rtl871x_security.c
+++ b/drivers/staging/rtl8712/rtl871x_security.c
@@ -1244,17 +1244,18 @@ static sint aes_decipher(u8 *key, uint hdrlen,
(frtype == WIFI_DATA_CFPOLL) ||
(frtype == WIFI_DATA_CFACKPOLL)) {
qc_exists = 1;
- if (hdrlen != WLAN_HDR_A3_QOS_LEN)
+ if (hdrlen != WLAN_HDR_A3_QOS_LEN)
hdrlen += 2;
- } else if ((frsubtype == 0x08) ||
+ } else if ((frsubtype == 0x08) ||
(frsubtype == 0x09) ||
(frsubtype == 0x0a) ||
(frsubtype == 0x0b)) {
- if (hdrlen != WLAN_HDR_A3_QOS_LEN)
- hdrlen += 2;
- qc_exists = 1;
- } else
+ if (hdrlen != WLAN_HDR_A3_QOS_LEN)
+ hdrlen += 2;
+ qc_exists = 1;
+ } else {
qc_exists = 0;
+ }
/* now, decrypt pframe with hdrlen offset and plen long */
payload_index = hdrlen + 8; /* 8 is for extiv */
for (i = 0; i < num_blocks; i++) {
diff --git a/drivers/staging/rtl8821ae/base.c b/drivers/staging/rtl8821ae/base.c
index 18c936fbdf1e..e5073fe24770 100644
--- a/drivers/staging/rtl8821ae/base.c
+++ b/drivers/staging/rtl8821ae/base.c
@@ -39,10 +39,10 @@
#include "pci.h"
/*
- *NOTICE!!!: This file will be very big, we hsould
- *keep it clear under follwing roles:
+ *NOTICE!!!: This file will be very big, we should
+ *keep it clear under following roles:
*
- *This file include follwing part, so, if you add new
+ *This file include following part, so, if you add new
*functions into this file, please check which part it
*should includes. or check if you should add new part
*for this file:
@@ -64,73 +64,73 @@
*
*********************************************************/
static struct ieee80211_channel rtl_channeltable_2g[] = {
- {.center_freq = 2412,.hw_value = 1,},
- {.center_freq = 2417,.hw_value = 2,},
- {.center_freq = 2422,.hw_value = 3,},
- {.center_freq = 2427,.hw_value = 4,},
- {.center_freq = 2432,.hw_value = 5,},
- {.center_freq = 2437,.hw_value = 6,},
- {.center_freq = 2442,.hw_value = 7,},
- {.center_freq = 2447,.hw_value = 8,},
- {.center_freq = 2452,.hw_value = 9,},
- {.center_freq = 2457,.hw_value = 10,},
- {.center_freq = 2462,.hw_value = 11,},
- {.center_freq = 2467,.hw_value = 12,},
- {.center_freq = 2472,.hw_value = 13,},
- {.center_freq = 2484,.hw_value = 14,},
+ {.center_freq = 2412, .hw_value = 1,},
+ {.center_freq = 2417, .hw_value = 2,},
+ {.center_freq = 2422, .hw_value = 3,},
+ {.center_freq = 2427, .hw_value = 4,},
+ {.center_freq = 2432, .hw_value = 5,},
+ {.center_freq = 2437, .hw_value = 6,},
+ {.center_freq = 2442, .hw_value = 7,},
+ {.center_freq = 2447, .hw_value = 8,},
+ {.center_freq = 2452, .hw_value = 9,},
+ {.center_freq = 2457, .hw_value = 10,},
+ {.center_freq = 2462, .hw_value = 11,},
+ {.center_freq = 2467, .hw_value = 12,},
+ {.center_freq = 2472, .hw_value = 13,},
+ {.center_freq = 2484, .hw_value = 14,},
};
static struct ieee80211_channel rtl_channeltable_5g[] = {
- {.center_freq = 5180,.hw_value = 36,},
- {.center_freq = 5200,.hw_value = 40,},
- {.center_freq = 5220,.hw_value = 44,},
- {.center_freq = 5240,.hw_value = 48,},
- {.center_freq = 5260,.hw_value = 52,},
- {.center_freq = 5280,.hw_value = 56,},
- {.center_freq = 5300,.hw_value = 60,},
- {.center_freq = 5320,.hw_value = 64,},
- {.center_freq = 5500,.hw_value = 100,},
- {.center_freq = 5520,.hw_value = 104,},
- {.center_freq = 5540,.hw_value = 108,},
- {.center_freq = 5560,.hw_value = 112,},
- {.center_freq = 5580,.hw_value = 116,},
- {.center_freq = 5600,.hw_value = 120,},
- {.center_freq = 5620,.hw_value = 124,},
- {.center_freq = 5640,.hw_value = 128,},
- {.center_freq = 5660,.hw_value = 132,},
- {.center_freq = 5680,.hw_value = 136,},
- {.center_freq = 5700,.hw_value = 140,},
- {.center_freq = 5745,.hw_value = 149,},
- {.center_freq = 5765,.hw_value = 153,},
- {.center_freq = 5785,.hw_value = 157,},
- {.center_freq = 5805,.hw_value = 161,},
- {.center_freq = 5825,.hw_value = 165,},
+ {.center_freq = 5180, .hw_value = 36,},
+ {.center_freq = 5200, .hw_value = 40,},
+ {.center_freq = 5220, .hw_value = 44,},
+ {.center_freq = 5240, .hw_value = 48,},
+ {.center_freq = 5260, .hw_value = 52,},
+ {.center_freq = 5280, .hw_value = 56,},
+ {.center_freq = 5300, .hw_value = 60,},
+ {.center_freq = 5320, .hw_value = 64,},
+ {.center_freq = 5500, .hw_value = 100,},
+ {.center_freq = 5520, .hw_value = 104,},
+ {.center_freq = 5540, .hw_value = 108,},
+ {.center_freq = 5560, .hw_value = 112,},
+ {.center_freq = 5580, .hw_value = 116,},
+ {.center_freq = 5600, .hw_value = 120,},
+ {.center_freq = 5620, .hw_value = 124,},
+ {.center_freq = 5640, .hw_value = 128,},
+ {.center_freq = 5660, .hw_value = 132,},
+ {.center_freq = 5680, .hw_value = 136,},
+ {.center_freq = 5700, .hw_value = 140,},
+ {.center_freq = 5745, .hw_value = 149,},
+ {.center_freq = 5765, .hw_value = 153,},
+ {.center_freq = 5785, .hw_value = 157,},
+ {.center_freq = 5805, .hw_value = 161,},
+ {.center_freq = 5825, .hw_value = 165,},
};
static struct ieee80211_rate rtl_ratetable_2g[] = {
- {.bitrate = 10,.hw_value = 0x00,},
- {.bitrate = 20,.hw_value = 0x01,},
- {.bitrate = 55,.hw_value = 0x02,},
- {.bitrate = 110,.hw_value = 0x03,},
- {.bitrate = 60,.hw_value = 0x04,},
- {.bitrate = 90,.hw_value = 0x05,},
- {.bitrate = 120,.hw_value = 0x06,},
- {.bitrate = 180,.hw_value = 0x07,},
- {.bitrate = 240,.hw_value = 0x08,},
- {.bitrate = 360,.hw_value = 0x09,},
- {.bitrate = 480,.hw_value = 0x0a,},
- {.bitrate = 540,.hw_value = 0x0b,},
+ {.bitrate = 10, .hw_value = 0x00,},
+ {.bitrate = 20, .hw_value = 0x01,},
+ {.bitrate = 55, .hw_value = 0x02,},
+ {.bitrate = 110, .hw_value = 0x03,},
+ {.bitrate = 60, .hw_value = 0x04,},
+ {.bitrate = 90, .hw_value = 0x05,},
+ {.bitrate = 120, .hw_value = 0x06,},
+ {.bitrate = 180, .hw_value = 0x07,},
+ {.bitrate = 240, .hw_value = 0x08,},
+ {.bitrate = 360, .hw_value = 0x09,},
+ {.bitrate = 480, .hw_value = 0x0a,},
+ {.bitrate = 540, .hw_value = 0x0b,},
};
static struct ieee80211_rate rtl_ratetable_5g[] = {
- {.bitrate = 60,.hw_value = 0x04,},
- {.bitrate = 90,.hw_value = 0x05,},
- {.bitrate = 120,.hw_value = 0x06,},
- {.bitrate = 180,.hw_value = 0x07,},
- {.bitrate = 240,.hw_value = 0x08,},
- {.bitrate = 360,.hw_value = 0x09,},
- {.bitrate = 480,.hw_value = 0x0a,},
- {.bitrate = 540,.hw_value = 0x0b,},
+ {.bitrate = 60, .hw_value = 0x04,},
+ {.bitrate = 90, .hw_value = 0x05,},
+ {.bitrate = 120, .hw_value = 0x06,},
+ {.bitrate = 180, .hw_value = 0x07,},
+ {.bitrate = 240, .hw_value = 0x08,},
+ {.bitrate = 360, .hw_value = 0x09,},
+ {.bitrate = 480, .hw_value = 0x0a,},
+ {.bitrate = 540, .hw_value = 0x0b,},
};
static const struct ieee80211_supported_band rtl_band_2ghz = {
@@ -320,7 +320,7 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
/* <5> set hw caps */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_RX_INCLUDES_FCS |
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0))
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
IEEE80211_HW_BEACON_FILTER |
#endif
IEEE80211_HW_AMPDU_AGGREGATION |
@@ -332,11 +332,11 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
/* swlps or hwlps has been set in diff chip in init_sw_vars */
if (rtlpriv->psc.b_swctrl_lps)
hw->flags |= IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK |
- /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
+ IEEE80211_HW_PS_NULLFUNC_STACK |
+ /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
0;
/*<delete in kernel start>*/
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
@@ -354,11 +354,11 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
/*<delete in kernel start>*/
#endif
/*<delete in kernel end>*/
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,39))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
#endif
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
#endif
@@ -402,7 +402,7 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
/* <2> work queue */
rtlpriv->works.hw = hw;
/*<delete in kernel start>*/
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
/*<delete in kernel end>*/
rtlpriv->works.rtl_wq = alloc_workqueue(rtlpriv->cfg->name, 0, 0);
/*<delete in kernel start>*/
@@ -662,30 +662,27 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
if (rtlpriv->dm.b_useramask) {
tcb_desc->ratr_index = ratr_index;
- /* TODO we will differentiate adhoc and station futrue */
+ /* TODO we will differentiate adhoc and station future */
if (mac->opmode == NL80211_IFTYPE_STATION ||
mac->opmode == NL80211_IFTYPE_MESH_POINT) {
tcb_desc->mac_id = 0;
-
- if (mac->mode == WIRELESS_MODE_N_24G) {
+ if (mac->mode == WIRELESS_MODE_N_24G)
tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB;
- } else if (mac->mode == WIRELESS_MODE_N_5G) {
+ else if (mac->mode == WIRELESS_MODE_N_5G)
tcb_desc->ratr_index = RATR_INX_WIRELESS_NG;
- } else if (mac->mode & WIRELESS_MODE_G) {
+ else if (mac->mode & WIRELESS_MODE_G)
tcb_desc->ratr_index = RATR_INX_WIRELESS_GB;
- } else if (mac->mode & WIRELESS_MODE_B) {
+ else if (mac->mode & WIRELESS_MODE_B)
tcb_desc->ratr_index = RATR_INX_WIRELESS_B;
- } else if (mac->mode & WIRELESS_MODE_A) {
+ else if (mac->mode & WIRELESS_MODE_A)
tcb_desc->ratr_index = RATR_INX_WIRELESS_G;
- }
} else if (mac->opmode == NL80211_IFTYPE_AP ||
mac->opmode == NL80211_IFTYPE_ADHOC) {
if (NULL != sta) {
- if (sta->aid > 0) {
+ if (sta->aid > 0)
tcb_desc->mac_id = sta->aid + 1;
- } else {
+ else
tcb_desc->mac_id = 1;
- }
} else {
tcb_desc->mac_id = 0;
}
@@ -711,7 +708,7 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
return;
} else if (mac->opmode == NL80211_IFTYPE_STATION) {
if (!mac->bw_40 || !(sta->ht_cap.ht_supported))
- return;
+ return;
}
if (tcb_desc->b_multicast || tcb_desc->b_broadcast)
return;
@@ -730,7 +727,7 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw,
struct rtl_phy *rtlphy = &(rtlpriv->phy);
u8 hw_rate;
- if ((get_rf_type(rtlphy) == RF_2T2R) && (sta->ht_cap.mcs.rx_mask[1]!=0))
+ if ((get_rf_type(rtlphy) == RF_2T2R) && (sta->ht_cap.mcs.rx_mask[1] != 0))
hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15];
else
hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS7];
@@ -772,16 +769,16 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
tcb_desc->disable_ratefallback = 1;
} else {
/*
- *because hw will nerver use hw_rate
+ *because hw will never use hw_rate
*when tcb_desc->use_driver_rate = false
*so we never set highest N rate here,
- *and N rate will all be controled by FW
+ *and N rate will all be controlled by FW
*when tcb_desc->use_driver_rate = false
*/
if (sta && (sta->ht_cap.ht_supported)) {
tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw, sta);
} else {
- if(rtlmac->mode == WIRELESS_MODE_B) {
+ if (rtlmac->mode == WIRELESS_MODE_B) {
tcb_desc->hw_rate =
rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M];
} else {
@@ -809,7 +806,7 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
tcb_desc->b_packet_bw = false;
}
}
-//EXPORT_SYMBOL(rtl_get_tcb_desc);
+/* EXPORT_SYMBOL(rtl_get_tcb_desc); */
bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
{
@@ -862,8 +859,8 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
RT_TRACE((COMP_SEND | COMP_RECV), DBG_DMESG,
("%s ACT_ADDBAREQ From :%pM\n",
is_tx ? "Tx" : "Rx", hdr->addr2));
- RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("req \n"),
- skb->data, skb->len);
+ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("req\n"),
+ skb->data, skb->len);
if (!is_tx) {
struct ieee80211_sta *sta = NULL;
struct rtl_sta_info *sta_entry = NULL;
@@ -897,7 +894,7 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
hdr->addr3,
tid);
if (skb_delba) {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
rx_status.freq = hw->conf.chandef.chan->center_freq;
rx_status.band = hw->conf.chandef.chan->band;
#else
@@ -1184,7 +1181,7 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb)
if (ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
return;
- rtlpriv->link_info.bcn_rx_inperiod ++;
+ rtlpriv->link_info.bcn_rx_inperiod++;
}
void rtl_watchdog_wq_callback(void *data)
@@ -1363,7 +1360,7 @@ void rtl_easy_concurrent_retrytimer_callback(unsigned long data)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_priv *buddy_priv = rtlpriv->buddy_priv;
- if(buddy_priv == NULL)
+ if (buddy_priv == NULL)
return;
rtlpriv->cfg->ops->dualmac_easy_concurrent(hw);
@@ -1478,13 +1475,13 @@ int rtl_send_smps_action(struct ieee80211_hw *hw,
/* rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); */
info->control.rates[0].idx = 0;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
info->band = hw->conf.chandef.chan->band;
#else
info->band = hw->conf.channel->band;
#endif
/*<delete in kernel start>*/
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0))
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
info->control.sta = sta;
rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
#else
@@ -1499,7 +1496,7 @@ int rtl_send_smps_action(struct ieee80211_hw *hw,
err_free:
return 0;
}
-//EXPORT_SYMBOL(rtl_send_smps_action);
+/* EXPORT_SYMBOL(rtl_send_smps_action); */
/* because mac80211 have issues when can receive del ba
* so here we just make a fake del_ba if we receive a ba_req
@@ -1528,8 +1525,8 @@ struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw,
IEEE80211_STYPE_ACTION);
action_frame->u.action.category = WLAN_CATEGORY_BACK;
action_frame->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
- params = (u16)(1 << 11); /* bit 11 initiator */
- params |= (u16)(tid << 12); /* bit 15:12 TID number */
+ params = (u16)(1 << 11); /* bit 11 initiator */
+ params |= (u16)(tid << 12); /* bit 15:12 TID number */
action_frame->u.action.u.delba.params = cpu_to_le16(params);
action_frame->u.action.u.delba.reason_code =
@@ -1652,9 +1649,8 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len)
if (ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
return;
- if (rtl_find_221_ie(hw, data, len)) {
+ if (rtl_find_221_ie(hw, data, len))
vendor = mac->vendor;
- }
if ((memcmp(mac->bssid, ap5_1, 3) == 0) ||
(memcmp(mac->bssid, ap5_2, 3) == 0) ||
@@ -1671,7 +1667,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len)
(memcmp(mac->bssid, ap4_2, 3) == 0) ||
(memcmp(mac->bssid, ap4_3, 3) == 0) ||
vendor == PEER_RAL) {
- RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>ral findn\n"));
+ RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>ral find\n"));
vendor = PEER_RAL;
} else if (memcmp(mac->bssid, ap6_1, 3) == 0 ||
vendor == PEER_CISCO) {
@@ -1715,7 +1711,7 @@ static ssize_t rtl_store_debug_level(struct device *d,
unsigned long val;
int ret;
- ret = strict_strtoul(buf, 0, &val);
+ ret = kstrtoul(buf, 0, &val);
if (ret) {
printk(KERN_DEBUG "%s is not in hex or decimal form.\n", buf);
} else {
@@ -1845,8 +1841,7 @@ struct rtl_global_var global_var = {};
int rtl_core_module_init(void)
{
if (rtl_rate_control_register())
- printk(KERN_DEBUG "rtl: Unable to register rtl_rc,"
- "use default RC !!\n");
+ printk(KERN_DEBUG "rtl: Unable to register rtl_rc, use default RC !!\n");
/* add proc for debug */
rtl_proc_add_topdir();
@@ -1861,7 +1856,7 @@ int rtl_core_module_init(void)
void rtl_core_module_exit(void)
{
/*RC*/
- rtl_rate_control_unregister();
+ rtl_rate_control_unregister();
/* add proc for debug */
rtl_proc_remove_topdir();
diff --git a/drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.c b/drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.c
index b30f17ae0215..5a54bb10698c 100644
--- a/drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.c
+++ b/drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.c
@@ -1653,7 +1653,7 @@ halbtc8812a1ant_TdmaDurationAdjustForAcl(
}
else
{
- //accquire the BT TRx retry count from BT_Info byte2
+ //acquire the BT TRx retry count from BT_Info byte2
retry_count = coex_sta->bt_retry_cnt;
bt_info_ext = coex_sta->bt_info_ext;
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retry_count = %d\n", retry_count));
diff --git a/drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.c b/drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.c
index e619923ef0ab..8e4293a35872 100644
--- a/drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.c
+++ b/drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.c
@@ -629,7 +629,7 @@ halbtc8723a1ant_TdmaDurationAdjust(
}
else
{
- //accquire the BT TRx retry count from BT_Info byte2
+ //acquire the BT TRx retry count from BT_Info byte2
retryCount = pCoexSta->btRetryCnt;
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], retryCount = %d\n", retryCount));
result = 0;
diff --git a/drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.c b/drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.c
index 973d0ea82cb8..1b04530d46bc 100644
--- a/drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.c
+++ b/drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.c
@@ -1721,7 +1721,7 @@ halbtc8192e1ant_TdmaDurationAdjustForAcl(
}
else
{
- //accquire the BT TRx retry count from BT_Info byte2
+ //acquire the BT TRx retry count from BT_Info byte2
retryCount = pCoexSta->btRetryCnt;
btInfoExt = pCoexSta->btInfoExt;
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount));
diff --git a/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c b/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c
index 44ec78562e2d..115908928ae4 100644
--- a/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c
+++ b/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c
@@ -1803,7 +1803,7 @@ void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist,
result = 0;
wait_cnt = 0;
} else {
- /* accquire the BT TRx retry count from BT_Info byte2 */
+ /* acquire the BT TRx retry count from BT_Info byte2 */
retry_cnt = coex_sta->bt_retry_cnt;
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
"[BTCoex], retry_cnt = %d\n", retry_cnt);
diff --git a/drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.c b/drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.c
index 180d6f12e7b5..3f5c4fd2e73f 100644
--- a/drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.c
+++ b/drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.c
@@ -1687,7 +1687,7 @@ halbtc8723a2ant_TdmaDurationAdjust(
}
else
{
- //accquire the BT TRx retry count from BT_Info byte2
+ //acquire the BT TRx retry count from BT_Info byte2
retryCount = pCoexSta->btRetryCnt;
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount));
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n",
diff --git a/drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.c b/drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.c
index 3414ba78cc43..9677943fc20d 100644
--- a/drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.c
+++ b/drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.c
@@ -1950,7 +1950,7 @@ void halbtc8723b1ant_tdma_duration_adjust_for_acl(struct btc_coexist *btcoexist,
result = 0;
wait_count = 0;
} else {
- /*accquire the BT TRx retry count from BT_Info byte2 */
+ /*acquire the BT TRx retry count from BT_Info byte2 */
retry_count = coex_sta->bt_retry_cnt;
bt_info_ext = coex_sta->bt_info_ext;
result = 0;
diff --git a/drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.c b/drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.c
index 83b1b4218333..d337bd0b3c1b 100644
--- a/drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.c
+++ b/drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.c
@@ -1830,7 +1830,7 @@ void halbtc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist,
result = 0;
wait_count = 0;
} else {
- /*accquire the BT TRx retry count from BT_Info byte2*/
+ /*acquire the BT TRx retry count from BT_Info byte2*/
retryCount = coex_sta->bt_retry_cnt;
BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
"[BTCoex], retryCount = %d\n", retryCount);
diff --git a/drivers/staging/rtl8821ae/btcoexist/halbtcoutsrc.c b/drivers/staging/rtl8821ae/btcoexist/halbtcoutsrc.c
index 9d9fa4d7575d..c4e83773ec98 100644
--- a/drivers/staging/rtl8821ae/btcoexist/halbtcoutsrc.c
+++ b/drivers/staging/rtl8821ae/btcoexist/halbtcoutsrc.c
@@ -732,17 +732,7 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter)
else
btcoexist->binded = true;
-#if ( defined(CONFIG_PCI_HCI))
- btcoexist->chip_interface = BTC_INTF_PCI;
-#elif ( defined(CONFIG_USB_HCI))
- btcoexist->chip_interface = BTC_INTF_USB;
-#elif ( defined(CONFIG_SDIO_HCI))
- btcoexist->chip_interface = BTC_INTF_SDIO;
-#elif ( defined(CONFIG_GSPI_HCI))
- btcoexist->chip_interface = BTC_INTF_GSPI;
-#else
btcoexist->chip_interface = BTC_INTF_UNKNOWN;
-#endif
if (NULL == btcoexist->adapter)
btcoexist->adapter = adapter;
@@ -1087,7 +1077,7 @@ void exhalbtc_dbg_control(struct btc_coexist *btcoexist,
btcoexist->statistics.cnt_dbg_ctrl++;
}
-void exhalbtc_stack_update_profile_info()
+void exhalbtc_stack_update_profile_info(void)
{
}
diff --git a/drivers/staging/rtl8821ae/core.c b/drivers/staging/rtl8821ae/core.c
index 40de6089039e..ff3139b6da65 100644
--- a/drivers/staging/rtl8821ae/core.c
+++ b/drivers/staging/rtl8821ae/core.c
@@ -373,7 +373,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
/* sleep here is must, or we may recv the beacon and
* cause mac80211 into wrong ps state, this will cause
* power save nullfunc send fail, and further cause
- * pkt loss, So sleep must quickly but not immediatly
+ * pkt loss, So sleep must quickly but not immediately
* because that will cause nullfunc send by mac80211
* fail, and cause pkt loss, we have tested that 5mA
* is worked very well */
@@ -1200,8 +1200,8 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key_type = AESCMAC_ENCRYPTION;
RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:CMAC\n"));
RT_TRACE(COMP_SEC, DBG_DMESG,
- ("HW don't support CMAC encrypiton, "
- "use software CMAC encrypiton\n"));
+ ("HW don't support CMAC encryption, "
+ "use software CMAC encryption\n"));
err = -EOPNOTSUPP;
goto out_unlock;
default:
@@ -1235,8 +1235,8 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key_type = AESCMAC_ENCRYPTION;
RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:CMAC\n"));
RT_TRACE(COMP_SEC, DBG_DMESG,
- ("HW don't support CMAC encrypiton, "
- "use software CMAC encrypiton\n"));
+ ("HW don't support CMAC encryption, "
+ "use software CMAC encryption\n"));
err = -EOPNOTSUPP;
goto out_unlock;
default:
@@ -1411,7 +1411,7 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
}
/* this function is called by mac80211 to flush tx buffer
- * before switch channle or power save, or tx buffer packet
+ * before switch channel or power save, or tx buffer packet
* maybe send after offchannel or rf sleep, this may cause
* dis-association by AP */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
diff --git a/drivers/staging/rtl8821ae/core.h b/drivers/staging/rtl8821ae/core.h
index 4b247db2861d..f0c74e9239fd 100644
--- a/drivers/staging/rtl8821ae/core.h
+++ b/drivers/staging/rtl8821ae/core.h
@@ -2,20 +2,20 @@
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
- * Tmis program is free software; you can redistribute it and/or modify it
+ * 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.
*
- * Tmis program is distributed in the hope that it will be useful, but WITHOUT
+ * 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
- * tmis program; if not, write to the Free Software Foundation, Inc.,
+ * this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
- * Tme full GNU General Public License is included in this distribution in the
+ * The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
diff --git a/drivers/staging/rtl8821ae/debug.c b/drivers/staging/rtl8821ae/debug.c
index cb051223c684..8a6c794bda41 100644
--- a/drivers/staging/rtl8821ae/debug.c
+++ b/drivers/staging/rtl8821ae/debug.c
@@ -2,20 +2,20 @@
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
- * Tmis program is free software; you can redistribute it and/or modify it
+ * 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.
*
- * Tmis program is distributed in the hope that it will be useful, but WITHOUT
+ * 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
- * tmis program; if not, write to the Free Software Foundation, Inc.,
+ * this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
- * Tme full GNU General Public License is included in this distribution in the
+ * The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
@@ -985,4 +985,4 @@ void rtl_proc_remove_topdir(void)
{
if (proc_topdir)
remove_proc_entry("rtlwifi", init_net.proc_net);
-} \ No newline at end of file
+}
diff --git a/drivers/staging/rtl8821ae/debug.h b/drivers/staging/rtl8821ae/debug.h
index 5eb6251b89da..6c0a553e98b7 100644
--- a/drivers/staging/rtl8821ae/debug.h
+++ b/drivers/staging/rtl8821ae/debug.h
@@ -2,20 +2,20 @@
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
- * Tmis program is free software; you can redistribute it and/or modify it
+ * 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.
*
- * Tmis program is distributed in the hope that it will be useful, but WITHOUT
+ * 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
- * tmis program; if not, write to the Free Software Foundation, Inc.,
+ * this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
- * Tme full GNU General Public License is included in this distribution in the
+ * The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
@@ -44,7 +44,7 @@
#define DBG_EMERG 0
/*
- *Abnormal, rare, or unexpeted cases.
+ *Abnormal, rare, or unexpected cases.
*For example, Packet/IO Ctl canceled,
*device suprisely unremoved and so on.
*/
@@ -54,7 +54,7 @@
*Normal case driver developer should
*open, we can see link status like
*assoc/AddBA/DHCP/adapter start and
- *so on basic and useful infromations.
+ *so on basic and useful informations.
*/
#define DBG_DMESG 3
diff --git a/drivers/staging/rtl8821ae/efuse.c b/drivers/staging/rtl8821ae/efuse.c
index 74c19ecc95a9..250aae1ce631 100644
--- a/drivers/staging/rtl8821ae/efuse.c
+++ b/drivers/staging/rtl8821ae/efuse.c
@@ -2,20 +2,20 @@
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
- * Tmis program is free software; you can redistribute it and/or modify it
+ * 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.
*
- * Tmis program is distributed in the hope that it will be useful, but WITHOUT
+ * 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
- * tmis program; if not, write to the Free Software Foundation, Inc.,
+ * this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
- * Tme full GNU General Public License is included in this distribution in the
+ * The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
@@ -149,7 +149,7 @@ u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address)
return 0xFF;
}
-//EXPORT_SYMBOL(efuse_read_1byte);
+/* EXPORT_SYMBOL(efuse_read_1byte); */
void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value)
{
@@ -517,7 +517,7 @@ void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw)
rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
}
-//EXPORT_SYMBOL(rtl_efuse_shadow_map_update);
+/* EXPORT_SYMBOL(rtl_efuse_shadow_map_update); */
void efuse_force_write_vendor_Id(struct ieee80211_hw *hw)
{
@@ -628,7 +628,7 @@ int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data)
}
return bresult;
}
-//EXPORT_SYMBOL(efuse_one_byte_read);
+/* EXPORT_SYMBOL(efuse_one_byte_read); */
static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data)
{
@@ -1120,16 +1120,16 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate)
{
rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_ACCESS], 0x69);
- // 1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid
+ /* 1.2V Power: From VDDON with Power Cut(0x0000h[15]), default valid */
tmpV16 = rtl_read_word(rtlpriv,
rtlpriv->cfg->maps[SYS_ISO_CTRL]);
printk("SYS_ISO_CTRL=%04x.\n",tmpV16);
if( ! (tmpV16 & PWC_EV12V ) ){
tmpV16 |= PWC_EV12V ;
- //PlatformEFIOWrite2Byte(pAdapter,REG_SYS_ISO_CTRL,tmpV16);
+ /* PlatformEFIOWrite2Byte(pAdapter,REG_SYS_ISO_CTRL,tmpV16); */
}
- // Reset: 0x0000h[28], default valid
+ /* Reset: 0x0000h[28], default valid */
tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN]);
printk("SYS_FUNC_EN=%04x.\n",tmpV16);
if( !(tmpV16 & FEN_ELDR) ){
@@ -1137,7 +1137,7 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate)
rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN], tmpV16);
}
- // Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid
+ /* Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid */
tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_CLK] );
printk("SYS_CLK=%04x.\n",tmpV16);
if( (!(tmpV16 & LOADER_CLK_EN) ) ||(!(tmpV16 & ANA8M) ) )
@@ -1148,7 +1148,7 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate)
if(bwrite == true)
{
- // Enable LDO 2.5V before read/write action
+ /* Enable LDO 2.5V before read/write action */
tempval = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3);
printk("EFUSE_TEST=%04x.\n",tmpV16);
tempval &= ~(BIT(3) | BIT(4) |BIT(5) | BIT(6));
@@ -1161,7 +1161,7 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate)
{
rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_ACCESS], 0x00);
if(bwrite == true){
- // Disable LDO 2.5V after read/write action
+ /* Disable LDO 2.5V after read/write action */
tempval = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3);
rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, (tempval & 0x7F));
}
diff --git a/drivers/staging/rtl8821ae/pci.c b/drivers/staging/rtl8821ae/pci.c
index cfa651edd238..a562aa60d595 100644
--- a/drivers/staging/rtl8821ae/pci.c
+++ b/drivers/staging/rtl8821ae/pci.c
@@ -388,13 +388,13 @@ static u8 _rtl_pci_get_pciehdr_offset(struct ieee80211_hw *hw)
* capability that we are looking for, follow the link to
* the next capability and continue looping.
*/
- rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS ,
- pcicfg_addr_port +
+ rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS ,
+ pcicfg_addr_port +
(num4bytes << 2));
rtl_pci_raw_read_port_ushort(PCI_CONF_DATA,
(u16*)&capability_hdr);
/* Found the PCI express capability. */
- if (capability_hdr.capability_id ==
+ if (capability_hdr.capability_id ==
PCI_CAPABILITY_ID_PCI_EXPRESS)
break;
else
@@ -418,7 +418,7 @@ bool rtl_pci_check_buddy_priv(struct ieee80211_hw *hw,
list_for_each_entry(temp_priv, &rtlpriv->glb_var->glb_priv_list,
list) {
if (temp_priv) {
- temp_pcipriv =
+ temp_pcipriv =
(struct rtl_pci_priv *)temp_priv->priv;
RT_TRACE(COMP_INIT, DBG_LOUD,
(("pcipriv->ndis_adapter.funcnumber %x \n"),
@@ -526,8 +526,8 @@ static void _rtl_pci_io_handler_init(struct device *dev,
}
static bool _rtl_pci_update_earlymode_info(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct rtl_tcb_desc *tcb_desc,
+ struct sk_buff *skb,
+ struct rtl_tcb_desc *tcb_desc,
u8 tid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -535,7 +535,7 @@ static bool _rtl_pci_update_earlymode_info(struct ieee80211_hw *hw,
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u8 additionlen = FCS_LEN;
struct sk_buff *next_skb;
-
+
/* here open is 4, wep/tkip is 8, aes is 12*/
if (info->control.hw_key)
additionlen += info->control.hw_key->icv_len;
@@ -544,7 +544,7 @@ static bool _rtl_pci_update_earlymode_info(struct ieee80211_hw *hw,
tcb_desc->empkt_num = 0;
spin_lock_bh(&rtlpriv->locks.waitq_lock);
skb_queue_walk(&rtlpriv->mac80211.skb_waitq[tid], next_skb) {
- struct ieee80211_tx_info *next_info =
+ struct ieee80211_tx_info *next_info =
IEEE80211_SKB_CB(next_skb);
if (next_info->flags & IEEE80211_TX_CTL_AMPDU) {
tcb_desc->empkt_len[tcb_desc->empkt_num] =
@@ -554,7 +554,7 @@ static bool _rtl_pci_update_earlymode_info(struct ieee80211_hw *hw,
break;
}
- if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid],
+ if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid],
next_skb))
break;
@@ -575,26 +575,26 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
struct sk_buff *skb = NULL;
struct ieee80211_tx_info *info = NULL;
int tid; /* should be int */
-
+
if (!rtlpriv->rtlhal.b_earlymode_enable)
- return;
+ return;
if (rtlpriv->dm.supp_phymode_switch &&
(rtlpriv->easy_concurrent_ctl.bswitch_in_process ||
- (rtlpriv->buddy_priv &&
+ (rtlpriv->buddy_priv &&
rtlpriv->buddy_priv->easy_concurrent_ctl.bswitch_in_process)))
return;
- /* we juse use em for BE/BK/VI/VO */
+ /* we just use em for BE/BK/VI/VO */
for (tid = 7; tid >= 0; tid--) {
u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(hw, tid)];
struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
- while (!mac->act_scanning &&
+ while (!mac->act_scanning &&
rtlpriv->psc.rfpwr_state == ERFON) {
struct rtl_tcb_desc tcb_desc;
- memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
spin_lock_bh(&rtlpriv->locks.waitq_lock);
if (!skb_queue_empty(&mac->skb_waitq[tid]) &&
- (ring->entries - skb_queue_len(&ring->queue) >
+ (ring->entries - skb_queue_len(&ring->queue) >
rtlhal->max_earlymode_num)) {
skb = skb_dequeue(&mac->skb_waitq[tid]);
} else {
@@ -607,7 +607,7 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
* multicast/broadcast/no_qos data */
info = IEEE80211_SKB_CB(skb);
if (info->flags & IEEE80211_TX_CTL_AMPDU)
- _rtl_pci_update_earlymode_info(hw, skb,
+ _rtl_pci_update_earlymode_info(hw, skb,
&tcb_desc, tid);
/*<delete in kernel start>*/
@@ -635,7 +635,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
u8 tid;
u8 *entry;
-
+
if (rtlpriv->use_new_trx_flow)
entry = (u8 *)(&ring->buffer_desc[ring->idx]);
else
@@ -643,11 +643,11 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
if (!rtlpriv->cfg->ops->is_tx_desc_closed(hw, prio, ring->idx))
return;
-
+
ring->idx = (ring->idx + 1) % ring->entries;
-
+
skb = __skb_dequeue(&ring->queue);
-
+
pci_unmap_single(rtlpci->pdev,
le32_to_cpu(rtlpriv->cfg->ops->
get_desc((u8 *) entry, true,
@@ -672,7 +672,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
}
/* for sw LPS, just after NULL skb send out, we can
- * sure AP kown we are sleeped, our we should not let
+ * sure AP known we are slept, our we should not let
* rf to sleep*/
fc = rtl_get_fc(skb);
if (ieee80211_is_nullfunc(fc)) {
@@ -740,7 +740,7 @@ static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
u8 tmp_one = 1;
struct sk_buff *skb;
- skb = dev_alloc_skb(rtlpci->rxbuffersize);
+ skb = dev_alloc_skb(rtlpci->rxbuffersize);
if (!skb)
return 0;
rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb;
@@ -754,25 +754,25 @@ static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))
return 0;
if (rtlpriv->use_new_trx_flow) {
- rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, false,
HW_DESC_RX_PREPARE,
(u8 *) & bufferaddress);
- } else {
- rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, false,
+ } else {
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, false,
HW_DESC_RXBUFF_ADDR,
(u8 *) & bufferaddress);
- rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, false,
HW_DESC_RXPKT_LEN,
(u8 *) & rtlpci->rxbuffersize);
- rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry, false,
HW_DESC_RXOWN,
(u8 *) & tmp_one);
}
-
+
return 1;
}
-/* inorder to receive 8K AMSDU we have set skb to
+/* In order to receive 8K AMSDU we have set skb to
* 9100bytes in init rx ring, but if this packet is
* not a AMSDU, this so big packet will be sent to
* TCP/IP directly, this cause big packet ping fail
@@ -783,7 +783,7 @@ static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
/* but some platform will fail when alloc skb sometimes.
* in this condition, we will send the old skb to
* mac80211 directly, this will not cause any other
- * issues, but only be losted by TCP/IP */
+ * issues, but only be lost by TCP/IP */
static void _rtl_pci_rx_to_mac80211(struct ieee80211_hw *hw,
struct sk_buff *skb, struct ieee80211_rx_status rx_status)
{
@@ -792,7 +792,7 @@ static void _rtl_pci_rx_to_mac80211(struct ieee80211_hw *hw,
} else {
struct sk_buff *uskb = NULL;
u8 *pdata;
-
+
uskb = dev_alloc_skb(skb->len + 128);
if (likely(uskb)) {
memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status,
@@ -804,7 +804,7 @@ static void _rtl_pci_rx_to_mac80211(struct ieee80211_hw *hw,
ieee80211_rx_irqsafe(hw, uskb);
} else {
ieee80211_rx_irqsafe(hw, skb);
- }
+ }
}
}
@@ -814,11 +814,11 @@ static void _rtl_pci_hs_interrupt(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR],
- rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR]) |
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR],
+ rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR]) |
rtlpci->sys_irq_mask);
-
+
}
static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
{
@@ -839,7 +839,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
.noise = -98,
.rate = 0,
};
-
+
/*RX NORMAL PKT */
while (count--) {
struct ieee80211_hdr *hdr;
@@ -852,65 +852,65 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
/*rx pkt */
struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[
rtlpci->rx_ring[rxring_idx].idx];
-
+
if (rtlpriv->use_new_trx_flow) {
- rx_remained_cnt =
+ rx_remained_cnt =
rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw,
hw_queue);
- if (rx_remained_cnt < 1)
+ if (rx_remained_cnt < 1)
return;
-
+
} else { /* rx descriptor */
pdesc = &rtlpci->rx_ring[rxring_idx].desc[
rtlpci->rx_ring[rxring_idx].idx];
-
+
own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
- false,
+ false,
HW_DESC_OWN);
if (own) /* wait data to be filled by hardware */
return;
}
-
+
/* Get here means: data is filled already*/
/* AAAAAAttention !!!
* We can NOT access 'skb' before 'pci_unmap_single' */
pci_unmap_single(rtlpci->pdev, *((dma_addr_t *) skb->cb),
rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE);
-
+
if (rtlpriv->use_new_trx_flow) {
buffer_desc = &rtlpci->rx_ring[rxring_idx].buffer_desc[
rtlpci->rx_ring[rxring_idx].idx];
/*means rx wifi info*/
pdesc = (struct rtl_rx_desc *)skb->data;
}
-
+
rtlpriv->cfg->ops->query_rx_desc(hw, &status,
&rx_status, (u8 *) pdesc, skb);
-
+
if (rtlpriv->use_new_trx_flow)
- rtlpriv->cfg->ops->rx_check_dma_ok(hw,
- (u8 *)buffer_desc,
+ rtlpriv->cfg->ops->rx_check_dma_ok(hw,
+ (u8 *)buffer_desc,
hw_queue);
-
- len = rtlpriv->cfg->ops->get_desc((u8 *)pdesc, false,
+
+ len = rtlpriv->cfg->ops->get_desc((u8 *)pdesc, false,
HW_DESC_RXPKT_LEN);
-
+
if (skb->end - skb->tail > len) {
skb_put(skb, len);
- if (rtlpriv->use_new_trx_flow)
- skb_reserve(skb, status.rx_drvinfo_size +
+ if (rtlpriv->use_new_trx_flow)
+ skb_reserve(skb, status.rx_drvinfo_size +
status.rx_bufshift + 24);
else
- skb_reserve(skb, status.rx_drvinfo_size +
+ skb_reserve(skb, status.rx_drvinfo_size +
status.rx_bufshift);
} else {
- printk("skb->end - skb->tail = %d, len is %d\n",
+ printk("skb->end - skb->tail = %d, len is %d\n",
skb->end - skb->tail, len);
break;
}
-
+
rtlpriv->cfg->ops->rx_command_packet_handler(hw, status, skb);
/*
@@ -922,9 +922,9 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
hdr = rtl_get_hdr(skb);
fc = rtl_get_fc(skb);
-
+
if (!status.b_crc && !status.b_hwerror) {
- memcpy(IEEE80211_SKB_RXCB(skb), &rx_status,
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status,
sizeof(rx_status));
if (is_broadcast_ether_addr(hdr->addr1)) {
@@ -947,13 +947,13 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
/* static bcn for roaming */
rtl_beacon_statistic(hw, skb);
- rtl_p2p_info(hw, (void*)skb->data, skb->len);
+ rtl_p2p_info(hw, (void*)skb->data, skb->len);
/* for sw lps */
rtl_swlps_beacon(hw, (void*)skb->data, skb->len);
rtl_recognize_peer(hw, (void*)skb->data, skb->len);
if ((rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) &&
(rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G)&&
- (ieee80211_is_beacon(fc) ||
+ (ieee80211_is_beacon(fc) ||
ieee80211_is_probe_resp(fc))) {
dev_kfree_skb_any(skb);
} else {
@@ -964,13 +964,13 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
}
if (rtlpriv->use_new_trx_flow) {
rtlpci->rx_ring[hw_queue].next_rx_rp += 1;
- rtlpci->rx_ring[hw_queue].next_rx_rp %=
+ rtlpci->rx_ring[hw_queue].next_rx_rp %=
RTL_PCI_MAX_RX_COUNT;
rx_remained_cnt--;
if (1/*rx_remained_cnt == 0*/) {
- rtl_write_word(rtlpriv, 0x3B4,
+ rtl_write_word(rtlpriv, 0x3B4,
rtlpci->rx_ring[hw_queue].next_rx_rp);
}
}
@@ -981,22 +981,22 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
}
if (rtlpriv->use_new_trx_flow) {
- _rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc,
+ _rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc,
rxring_idx,
- rtlpci->rx_ring[rxring_idx].idx);
+ rtlpci->rx_ring[rxring_idx].idx);
} else {
_rtl_pci_init_one_rxdesc(hw, (u8 *)pdesc, rxring_idx,
- rtlpci->rx_ring[rxring_idx].idx);
+ rtlpci->rx_ring[rxring_idx].idx);
- if (rtlpci->rx_ring[rxring_idx].idx ==
+ if (rtlpci->rx_ring[rxring_idx].idx ==
rtlpci->rxringcount - 1)
- rtlpriv->cfg->ops->set_desc(hw, (u8 *) pdesc,
- false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *) pdesc,
+ false,
HW_DESC_RXERO,
(u8 *) & tmp_one);
}
- rtlpci->rx_ring[rxring_idx].idx =
- (rtlpci->rx_ring[rxring_idx].idx + 1) %
+ rtlpci->rx_ring[rxring_idx].idx =
+ (rtlpci->rx_ring[rxring_idx].idx + 1) %
rtlpci->rxringcount;
}
}
@@ -1011,7 +1011,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
u32 inta = 0;
u32 intb = 0;
-
+
if (rtlpci->irq_enabled == 0)
return IRQ_HANDLED;
@@ -1020,7 +1020,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMR], 0x0);
-
+
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMRE], 0x0);
@@ -1029,7 +1029,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb);
- /*Shared IRQ or HW disappared */
+ /*Shared IRQ or HW disappeared */
if (!inta || inta == 0xffff)
goto done;
/*<1> beacon related */
@@ -1127,7 +1127,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
/*<4> fw related*/
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723AE) {
if (inta & rtlpriv->cfg->maps[RTL_IMR_C2HCMD]) {
- RT_TRACE(COMP_INTR, DBG_TRACE,
+ RT_TRACE(COMP_INTR, DBG_TRACE,
("firmware interrupt!\n"));
queue_delayed_work(rtlpriv->works.rtl_wq,
&rtlpriv->works.fwevt_wq, 0);
@@ -1142,12 +1142,12 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE ||
rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) {
if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_HSISR_IND])) {
- RT_TRACE(COMP_INTR, DBG_TRACE,
+ RT_TRACE(COMP_INTR, DBG_TRACE,
("hsisr interrupt!\n"));
_rtl_pci_hs_interrupt(hw);
}
}
-
+
if(rtlpriv->rtlhal.b_earlymode_enable)
tasklet_schedule(&rtlpriv->works.irq_tasklet);
@@ -1157,7 +1157,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[MAC_HIMRE],
rtlpci->irq_mask[1]);
spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-
+
return IRQ_HANDLED;
done:
@@ -1200,16 +1200,16 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
pdesc = &ring->desc[0];
if (rtlpriv->use_new_trx_flow)
pbuffer_desc = &ring->buffer_desc[0];
-
+
/*<delete in kernel start>*/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0))
- rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
- (u8 *)pbuffer_desc, info, pskb,
+ rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
+ (u8 *)pbuffer_desc, info, pskb,
BEACON_QUEUE, &tcb_desc);
#else
/*<delete in kernel end>*/
rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
- (u8 *)pbuffer_desc, info, NULL, pskb,
+ (u8 *)pbuffer_desc, info, NULL, pskb,
BEACON_QUEUE, &tcb_desc);
/*<delete in kernel start>*/
#endif
@@ -1235,7 +1235,7 @@ static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw)
desc_num = TX_DESC_NUM_92E;
else
desc_num = RT_TXDESC_NUM;
-
+
for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) {
rtlpci->txringcount[i] = desc_num;
}
@@ -1309,12 +1309,12 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
/* alloc tx buffer desc for new trx flow*/
if (rtlpriv->use_new_trx_flow) {
buffer_desc = pci_alloc_consistent(rtlpci->pdev,
- sizeof(*buffer_desc) * entries,
+ sizeof(*buffer_desc) * entries,
&buffer_desc_dma);
if (!buffer_desc || (unsigned long)buffer_desc & 0xFF) {
RT_TRACE(COMP_ERR, DBG_EMERG,
- ("Cannot allocate TX ring (prio = %d)\n",
+ ("Cannot allocate TX ring (prio = %d)\n",
prio));
return -ENOMEM;
}
@@ -1322,13 +1322,13 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
memset(buffer_desc, 0, sizeof(*buffer_desc) * entries);
rtlpci->tx_ring[prio].buffer_desc = buffer_desc;
rtlpci->tx_ring[prio].buffer_desc_dma = buffer_desc_dma;
-
+
rtlpci->tx_ring[prio].cur_tx_rp = 0;
rtlpci->tx_ring[prio].cur_tx_wp = 0;
rtlpci->tx_ring[prio].avl_desc = entries;
}
-
+
/* alloc dma for this ring */
desc = pci_alloc_consistent(rtlpci->pdev,
sizeof(*desc) * entries, &desc_dma);
@@ -1342,7 +1342,7 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
memset(desc, 0, sizeof(*desc) * entries);
rtlpci->tx_ring[prio].desc = desc;
rtlpci->tx_ring[prio].dma = desc_dma;
-
+
rtlpci->tx_ring[prio].idx = 0;
rtlpci->tx_ring[prio].entries = entries;
skb_queue_head_init(&rtlpci->tx_ring[prio].queue);
@@ -1357,7 +1357,7 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
sizeof(*desc));
rtlpriv->cfg->ops->set_desc(hw, (u8 *) & (desc[i]),
- true,
+ true,
HW_DESC_TX_NEXTDESC_ADDR,
(u8 *) & nextdescaddress);
}
@@ -1371,15 +1371,15 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx)
struct rtl_priv *rtlpriv = rtl_priv(hw);
int i;
-
+
if (rtlpriv->use_new_trx_flow) {
struct rtl_rx_buffer_desc *entry = NULL;
/* alloc dma for this ring */
- rtlpci->rx_ring[rxring_idx].buffer_desc =
+ rtlpci->rx_ring[rxring_idx].buffer_desc =
pci_alloc_consistent(rtlpci->pdev,
sizeof(*rtlpci->rx_ring[rxring_idx].
- buffer_desc) *
- rtlpci->rxringcount,
+ buffer_desc) *
+ rtlpci->rxringcount,
&rtlpci->rx_ring[rxring_idx].dma);
if (!rtlpci->rx_ring[rxring_idx].buffer_desc ||
(unsigned long)rtlpci->rx_ring[rxring_idx].buffer_desc & 0xFF) {
@@ -1393,9 +1393,9 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx)
/* init every desc in this ring */
rtlpci->rx_ring[rxring_idx].idx = 0;
- for (i = 0; i < rtlpci->rxringcount; i++) {
+ for (i = 0; i < rtlpci->rxringcount; i++) {
entry = &rtlpci->rx_ring[rxring_idx].buffer_desc[i];
- if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
+ if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
rxring_idx, i))
return -ENOMEM;
}
@@ -1403,14 +1403,14 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx)
struct rtl_rx_desc *entry = NULL;
u8 tmp_one = 1;
/* alloc dma for this ring */
- rtlpci->rx_ring[rxring_idx].desc =
+ rtlpci->rx_ring[rxring_idx].desc =
pci_alloc_consistent(rtlpci->pdev,
sizeof(*rtlpci->rx_ring[rxring_idx].
- desc) * rtlpci->rxringcount,
+ desc) * rtlpci->rxringcount,
&rtlpci->rx_ring[rxring_idx].dma);
if (!rtlpci->rx_ring[rxring_idx].desc ||
(unsigned long)rtlpci->rx_ring[rxring_idx].desc & 0xFF) {
- RT_TRACE(COMP_ERR, DBG_EMERG,
+ RT_TRACE(COMP_ERR, DBG_EMERG,
("Cannot allocate RX ring\n"));
return -ENOMEM;
}
@@ -1421,9 +1421,9 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx)
/* init every desc in this ring */
rtlpci->rx_ring[rxring_idx].idx = 0;
- for (i = 0; i < rtlpci->rxringcount; i++) {
+ for (i = 0; i < rtlpci->rxringcount; i++) {
entry = &rtlpci->rx_ring[rxring_idx].desc[i];
- if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
+ if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
rxring_idx, i))
return -ENOMEM;
}
@@ -1467,7 +1467,7 @@ static void _rtl_pci_free_tx_ring(struct ieee80211_hw *hw,
sizeof(*ring->buffer_desc) * ring->entries,
ring->buffer_desc, ring->buffer_desc_dma);
ring->buffer_desc = NULL;
- }
+ }
}
static void _rtl_pci_free_rx_ring(struct ieee80211_hw *hw, int rxring_idx)
@@ -1532,7 +1532,7 @@ err_free_rings:
_rtl_pci_free_rx_ring(hw, rxring_idx);
for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++)
- if (rtlpci->tx_ring[i].desc ||
+ if (rtlpci->tx_ring[i].desc ||
rtlpci->tx_ring[i].buffer_desc)
_rtl_pci_free_tx_ring(hw, i);
@@ -1567,16 +1567,16 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
/* force the rx_ring[RX_MPDU_QUEUE/
* RX_CMD_QUEUE].idx to the first one */
/*new trx flow, do nothing*/
- if ((rtlpriv->use_new_trx_flow == false) &&
+ if ((rtlpriv->use_new_trx_flow == false) &&
rtlpci->rx_ring[rxring_idx].desc) {
struct rtl_rx_desc *entry = NULL;
for (i = 0; i < rtlpci->rxringcount; i++) {
- entry = &rtlpci->rx_ring[rxring_idx].desc[i];
- rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry,
+ entry = &rtlpci->rx_ring[rxring_idx].desc[i];
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *) entry,
false,
- HW_DESC_RXOWN,
- (u8 *) & tmp_one);
+ HW_DESC_RXOWN,
+ (u8 *) & tmp_one);
}
}
rtlpci->rx_ring[rxring_idx].idx = 0; }
@@ -1585,13 +1585,13 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
* and force the tx idx to the first one */
spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) {
- if (rtlpci->tx_ring[i].desc ||
+ if (rtlpci->tx_ring[i].desc ||
rtlpci->tx_ring[i].buffer_desc) {
struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[i];
while (skb_queue_len(&ring->queue)) {
u8 *entry;
- struct sk_buff *skb =
+ struct sk_buff *skb =
__skb_dequeue(&ring->queue);
if (rtlpriv->use_new_trx_flow)
entry = (u8 *)(&ring->buffer_desc
@@ -1618,7 +1618,7 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
/*<delete in kernel start>*/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0))
-static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,
+static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,
struct sk_buff *skb)
#else
/*<delete in kernel end>*/
@@ -1741,10 +1741,10 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
}
pdesc = &ring->desc[idx];
-
+
if (rtlpriv->use_new_trx_flow) {
ptx_bd_desc = &ring->buffer_desc[idx];
- } else {
+ } else {
own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
true, HW_DESC_OWN);
@@ -1755,17 +1755,17 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
hw_queue, ring->idx, idx,
skb_queue_len(&ring->queue)));
- spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
flags);
return skb->len;
}
}
-
+
if (ieee80211_is_data_qos(fc)) {
tid = rtl_get_tid(skb);
if (sta) {
sta_entry = (struct rtl_sta_info *)sta->drv_priv;
- seq_number = (le16_to_cpu(hdr->seq_ctrl) &
+ seq_number = (le16_to_cpu(hdr->seq_ctrl) &
IEEE80211_SCTL_SEQ) >> 4;
seq_number += 1;
@@ -1779,13 +1779,13 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
/*<delete in kernel start>*/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0))
- rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
- (u8 *)ptx_bd_desc, info, skb,
+ rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
+ (u8 *)ptx_bd_desc, info, skb,
hw_queue, ptcb_desc);
#else
/*<delete in kernel end>*/
- rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
- (u8 *)ptx_bd_desc, info, sta, skb,
+ rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
+ (u8 *)ptx_bd_desc, info, sta, skb,
hw_queue, ptcb_desc);
/*<delete in kernel start>*/
#endif
@@ -1832,10 +1832,10 @@ static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop)
u16 i = 0;
int queue_id;
struct rtl8192_tx_ring *ring;
-
+
if (mac->skip_scan)
return;
-
+
for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) {
u32 queue_len;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
@@ -1936,7 +1936,7 @@ void rtl_pci_stop(struct ieee80211_hw *hw)
u8 RFInProgressTimeOut = 0;
/*
- *should before disable interrrupt&adapter
+ *should before disable interrupt&adapter
*and will do it immediately.
*/
set_hal_stop(rtlhal);
@@ -2081,13 +2081,13 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
rtlhal->interfaceindex = 0;
}
}
-
+
/* 92ee use new trx flow */
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE)
rtlpriv->use_new_trx_flow = true;
else
rtlpriv->use_new_trx_flow = false;
-
+
/*find bus info */
pcipriv->ndis_adapter.busnumber = pdev->bus->number;
pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn);
@@ -2095,7 +2095,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
/*find bridge info */
pcipriv->ndis_adapter.pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN;
- /* some ARM have no bridge_pdev and will crash here
+ /* some ARM have no bridge_pdev and will crash here
* so we should check if bridge_pdev is NULL */
if (bridge_pdev) {
pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor;
@@ -2187,7 +2187,7 @@ static int rtl_pci_intr_mode_msi(struct ieee80211_hw *hw)
}
rtlpci->using_msi = true;
-
+
RT_TRACE(COMP_INIT|COMP_INTR, DBG_DMESG, ("MSI Interrupt Mode!\n"));
return 0;
}
@@ -2198,7 +2198,7 @@ static int rtl_pci_intr_mode_legacy(struct ieee80211_hw *hw)
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
int ret;
-
+
ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
IRQF_SHARED, KBUILD_MODNAME, hw);
if (ret < 0) {
@@ -2206,7 +2206,7 @@ static int rtl_pci_intr_mode_legacy(struct ieee80211_hw *hw)
}
rtlpci->using_msi = false;
- RT_TRACE(COMP_INIT|COMP_INTR, DBG_DMESG,
+ RT_TRACE(COMP_INIT|COMP_INTR, DBG_DMESG,
("Pin-based Interrupt Mode!\n"));
return 0;
}
@@ -2293,7 +2293,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
/*
*init dbgp flags before all
*other functions, because we will
- *use it in other funtions like
+ *use it in other functions like
*RT_TRACE/RT_PRINT/RTL_PRINT_DATA
*you can not use these macro
*before this
@@ -2377,7 +2377,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
} else {
rtlpriv->mac80211.mac80211_registered = 1;
}
- /* the wiphy must have been registed to
+ /* the wiphy must have been registed to
* cfg80211 prior to regulatory_hint */
if (regulatory_hint(hw->wiphy, rtlpriv->regd.alpha2)) {
RT_TRACE(COMP_ERR, DBG_WARNING, ("regulatory_hint fail\n"));
@@ -2428,13 +2428,13 @@ fail1:
return -ENODEV;
}
-//EXPORT_SYMBOL(rtl_pci_probe);
+/* EXPORT_SYMBOL(rtl_pci_probe); */
struct ieee80211_hw *rtl_pci_get_hw_pointer(void)
{
return hw_export;
}
-//EXPORT_SYMBOL(rtl_pci_get_hw_pointer);
+/* EXPORT_SYMBOL(rtl_pci_get_hw_pointer); */
void rtl_pci_disconnect(struct pci_dev *pdev)
{
@@ -2450,7 +2450,7 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
/* add for prov */
rtl_proc_remove_one(hw);
-
+
/*ieee80211_unregister_hw will call ops_stop */
if (rtlmac->mac80211_registered == 1) {
@@ -2491,7 +2491,7 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
ieee80211_free_hw(hw);
}
-//EXPORT_SYMBOL(rtl_pci_disconnect);
+/* EXPORT_SYMBOL(rtl_pci_disconnect); */
/***************************************
kernel pci power state define:
@@ -2519,7 +2519,7 @@ int rtl_pci_suspend(struct device *dev)
return 0;
}
-//EXPORT_SYMBOL(rtl_pci_suspend);
+/* EXPORT_SYMBOL(rtl_pci_suspend); */
int rtl_pci_resume(struct device *dev)
{
@@ -2529,10 +2529,10 @@ int rtl_pci_resume(struct device *dev)
rtlpriv->cfg->ops->hw_resume(hw);
rtl_init_rfkill(hw);
-
+
return 0;
}
-//EXPORT_SYMBOL(rtl_pci_resume);
+/* EXPORT_SYMBOL(rtl_pci_resume); */
struct rtl_intf_ops rtl_pci_ops = {
.read_efuse_byte = read_efuse_byte,
diff --git a/drivers/staging/rtl8821ae/pci.h b/drivers/staging/rtl8821ae/pci.h
index 9f206550a657..06eaa521e0eb 100644
--- a/drivers/staging/rtl8821ae/pci.h
+++ b/drivers/staging/rtl8821ae/pci.h
@@ -148,11 +148,11 @@ struct rtl_pci_capabilities_header {
* RX wifi info == RX descriptor in old flow */
struct rtl_tx_buffer_desc {
#if (RTL8192EE_SEG_NUM == 2)
- u32 dword[2*(DMA_IS_64BIT + 1)*8]; //seg = 8
+ u32 dword[2*(DMA_IS_64BIT + 1)*8]; /* seg = 8 */
#elif (RTL8192EE_SEG_NUM == 1)
- u32 dword[2*(DMA_IS_64BIT + 1)*4]; //seg = 4
+ u32 dword[2*(DMA_IS_64BIT + 1)*4]; /* seg = 4 */
#elif (RTL8192EE_SEG_NUM == 0)
- u32 dword[2*(DMA_IS_64BIT + 1)*2]; //seg = 2
+ u32 dword[2*(DMA_IS_64BIT + 1)*2]; /* seg = 2 */
#endif
} __packed;
@@ -187,7 +187,7 @@ struct rtl8192_tx_ring {
};
struct rtl8192_rx_ring {
- struct rtl_rx_desc *desc;/*for old trx flow, not uesd in new trx*/
+ struct rtl_rx_desc *desc;/*for old trx flow, not used in new trx*/
/*dma matches either 'desc' or 'buffer_desc'*/
dma_addr_t dma;
unsigned int idx;
diff --git a/drivers/staging/rtl8821ae/ps.c b/drivers/staging/rtl8821ae/ps.c
index f12ffa83c58d..7876442417f4 100644
--- a/drivers/staging/rtl8821ae/ps.c
+++ b/drivers/staging/rtl8821ae/ps.c
@@ -257,7 +257,7 @@ void rtl_ips_nic_off_wq_callback(void *data)
*Do not enter IPS in the following conditions:
*(1) RF is already OFF or Sleep
*(2) b_swrf_processing (indicates the IPS is still under going)
- *(3) Connectted (only disconnected can trigger IPS)
+ *(3) Connected (only disconnected can trigger IPS)
*(4) IBSS (send Beacon)
*(5) AP mode (send Beacon)
*(6) monitor mode (rcv packet)
diff --git a/drivers/staging/rtl8821ae/regd.c b/drivers/staging/rtl8821ae/regd.c
index d89f15cb8089..0a4b3984b7ef 100644
--- a/drivers/staging/rtl8821ae/regd.c
+++ b/drivers/staging/rtl8821ae/regd.c
@@ -243,7 +243,7 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
}
/*
- *If a country IE has been recieved check its rule for this
+ *If a country IE has been received check its rule for this
*channel first before enabling active scan. The passive scan
*would have been enforced by the initial processing of our
*custom regulatory domain.
@@ -455,7 +455,7 @@ int rtl_regd_init(struct ieee80211_hw *hw,
if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) {
RT_TRACE(COMP_REGD, DBG_DMESG,
- (KERN_DEBUG "rtl: EEPROM indicates invalid contry code"
+ (KERN_DEBUG "rtl: EEPROM indicates invalid country code"
"world wide 13 should be used\n"));
rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13;
diff --git a/drivers/staging/rtl8821ae/regd.h b/drivers/staging/rtl8821ae/regd.h
index abc60ab8165c..dceb3f18200b 100644
--- a/drivers/staging/rtl8821ae/regd.h
+++ b/drivers/staging/rtl8821ae/regd.h
@@ -30,8 +30,8 @@
#ifndef __RTL_REGD_H__
#define __RTL_REGD_H__
-#define IEEE80211_CHAN_NO_IBSS 1<<2
-#define IEEE80211_CHAN_PASSIVE_SCAN 1<<1
+#define IEEE80211_CHAN_NO_IBSS (1 << 2)
+#define IEEE80211_CHAN_PASSIVE_SCAN (1 << 1)
#define WIPHY_FLAG_CUSTOM_REGULATORY BIT(0)
#define WIPHY_FLAG_STRICT_REGULATORY BIT(1)
#define WIPHY_FLAG_DISABLE_BEACON_HINTS BIT(2)
diff --git a/drivers/staging/rtl8821ae/rtl8821ae/dm.c b/drivers/staging/rtl8821ae/rtl8821ae/dm.c
index 8634206b8929..e0efcd281dfe 100644
--- a/drivers/staging/rtl8821ae/rtl8821ae/dm.c
+++ b/drivers/staging/rtl8821ae/rtl8821ae/dm.c
@@ -731,7 +731,7 @@ void rtl8821ae_dm_find_minimum_rssi(struct ieee80211_hw *hw)
rtl_dm_dig->min_undecorated_pwdb_for_dm =
rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
RT_TRACE(COMP_BB_POWERSAVING, DBG_LOUD,
- ("AP Ext Port or disconnet PWDB = 0x%x \n",
+ ("AP Ext Port or disconnect PWDB = 0x%x \n",
rtl_dm_dig->min_undecorated_pwdb_for_dm));
}
RT_TRACE(COMP_DIG, DBG_LOUD, ("MinUndecoratedPWDBForDM =%d\n",
@@ -925,7 +925,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw)
if (rtlpriv->falsealm_cnt.cnt_all > 10000) {
RT_TRACE(COMP_DIG, DBG_LOUD,
- ("rtl8821ae_dm_dig(): Abnornally false alarm case. \n"));
+ ("rtl8821ae_dm_dig(): Abnormally false alarm case. \n"));
if (dm_digtable.large_fa_hit != 3)
dm_digtable.large_fa_hit++;
@@ -1087,7 +1087,7 @@ static void rtl8821ae_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
else
falsealm_cnt->cnt_all = falsealm_cnt->cnt_ofdm_fail;
- /*reset OFDM FA coutner*/
+ /*reset OFDM FA counter*/
rtl_set_bbreg(hw, ODM_REG_OFDM_FA_RST_11AC, BIT(17), 1);
rtl_set_bbreg(hw, ODM_REG_OFDM_FA_RST_11AC, BIT(17), 0);
/* reset CCK FA counter*/
@@ -1316,7 +1316,7 @@ u8 rtl8812ae_hw_rate_to_mrate(
/*-----------------------------------------------------------------------------
* Function: odm_TxPwrTrackSetPwr88E()
*
- * Overview: 88E change all channel tx power accordign to flag.
+ * Overview: 88E change all channel tx power according to flag.
* OFDM & CCK are all different.
*
* Input: NONE
@@ -1537,7 +1537,7 @@ void rtl8812ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw,
rtldm->modify_txagc_flag_path_b = false;
RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD,
- ("******Path_B pDM_Odm->Modify_TxAGC_Flag = FALSE \n"));
+ ("******Path_B dm_Odm->Modify_TxAGC_Flag = FALSE \n"));
}
}
}
@@ -1654,7 +1654,7 @@ void rtl8812ae_dm_txpower_tracking_callback_thermalmeter
if (delta > 0 && rtldm->txpower_track_control)
{
- /*"delta" here is used to record the absolute value of differrence.*/
+ /*"delta" here is used to record the absolute value of difference.*/
delta = thermal_value > rtlefuse->eeprom_thermalmeter ? \
(thermal_value - rtlefuse->eeprom_thermalmeter) : \
(rtlefuse->eeprom_thermalmeter - thermal_value);
@@ -1976,7 +1976,7 @@ void rtl8821ae_phy_lccalibrate(
/*-----------------------------------------------------------------------------
* Function: odm_TxPwrTrackSetPwr88E()
*
- * Overview: 88E change all channel tx power accordign to flag.
+ * Overview: 88E change all channel tx power according to flag.
* OFDM & CCK are all different.
*
* Input: NONE
@@ -2159,7 +2159,7 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter
u8 *delta_swing_table_idx_tup_b;
u8 *delta_swing_table_idx_tdown_b;
- /*2. Initilization ( 7 steps in total )*/
+ /*2. Initialization ( 7 steps in total )*/
rtl8821ae_get_delta_swing_table(hw, (u8**)&delta_swing_table_idx_tup_a,
(u8**)&delta_swing_table_idx_tdown_a,
(u8**)&delta_swing_table_idx_tup_b,
@@ -2244,7 +2244,7 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter
if (delta > 0 && rtldm->txpower_track_control)
{
- /*"delta" here is used to record the absolute value of differrence.*/
+ /*"delta" here is used to record the absolute value of difference.*/
delta = thermal_value > rtlefuse->eeprom_thermalmeter ? \
(thermal_value - rtlefuse->eeprom_thermalmeter) : \
(rtlefuse->eeprom_thermalmeter - thermal_value);
@@ -2613,11 +2613,11 @@ static void rtl8821ae_dm_check_edca_turbo(struct ieee80211_hw *hw)
RT_TRACE(COMP_TURBO, DBG_LOUD,
("rtl8821ae_dm_check_edca_turbo=====>"));
RT_TRACE(COMP_TURBO, DBG_LOUD,
- ("Orginial BE PARAM: 0x%x\n",
+ ("Original BE PARAM: 0x%x\n",
rtl_read_dword(rtlpriv, DM_REG_EDCA_BE_11N)));
/*===============================
- list paramter for different platform
+ list parameter for different platform
===============================*/
b_last_is_cur_rdl_state = rtlpriv->dm.bis_cur_rdlstate;
pb_is_cur_rdl_state = &( rtlpriv->dm.bis_cur_rdlstate);
@@ -2963,7 +2963,7 @@ void rtl8821ae_dm_dynamic_atc_switch(struct ieee80211_hw *hw)
"Crystal cap = 0x%x, Crystal cap offset = %d\n",
rtldm->crystal_cap, adjust_xtal));
- /*3.Adjudt Crystal Cap.*/
+ /*3.Adjust Crystal Cap.*/
if (adjust_xtal != 0){
rtldm->is_freeze = 0;
rtldm->crystal_cap += adjust_xtal;
diff --git a/drivers/staging/rtl8821ae/rtl8821ae/fw.c b/drivers/staging/rtl8821ae/rtl8821ae/fw.c
index 4083cab926a3..46eb4125d18f 100644
--- a/drivers/staging/rtl8821ae/rtl8821ae/fw.c
+++ b/drivers/staging/rtl8821ae/rtl8821ae/fw.c
@@ -164,7 +164,7 @@ static int _rtl8821ae_fw_free_to_go(struct ieee80211_hw *hw)
if (counter >= FW_8821AE_POLLING_TIMEOUT_COUNT) {
RT_TRACE(COMP_ERR, DBG_LOUD,
- ("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
+ ("chksum report fail ! REG_MCUFWDL:0x%08x .\n",
value32));
goto exit;
}
@@ -368,7 +368,7 @@ static void _rtl8821ae_fill_h2c_command(struct ieee80211_hw *hw,
wait_h2c_limmit--;
if (wait_h2c_limmit == 0) {
RT_TRACE(COMP_CMD, DBG_LOUD,
- ("Wating too long for FW read "
+ ("Waiting too long for FW read "
"clear HMEBox(%d)!\n", boxnum));
break;
}
@@ -378,7 +378,7 @@ static void _rtl8821ae_fill_h2c_command(struct ieee80211_hw *hw,
isfw_read = _rtl8821ae_check_fw_read_last_h2c(hw, boxnum);
u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
RT_TRACE(COMP_CMD, DBG_LOUD,
- ("Wating for FW read clear HMEBox(%d)!!! "
+ ("Waiting for FW read clear HMEBox(%d)!!! "
"0x130 = %2x\n", boxnum, u1b_tmp));
}
}
@@ -1179,7 +1179,7 @@ void rtl8821ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
("Set RSVD page location to Fw FAIL!!!!!!.\n"));
}
-/*Shoud check FW support p2p or not.*/
+/*Should check FW support p2p or not.*/
void rtl8821ae_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
{
u8 u1_ctwindow_period[1] ={ ctwindow};
diff --git a/drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.h b/drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.h
index 799cc6f95cc1..b365f82f481c 100644
--- a/drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.h
+++ b/drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.h
@@ -142,7 +142,7 @@ void rtl8821ae_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw);
long rtl8821ae_dm_bt_get_rx_ss(struct ieee80211_hw *hw);
void rtl8821ae_dm_bt_balance(struct ieee80211_hw *hw,
bool b_balance_on, u8 ms0, u8 ms1);
-void rtl8821ae_dm_bt_agc_table(struct ieee80211_hw *hw, u8 tyep);
+void rtl8821ae_dm_bt_agc_table(struct ieee80211_hw *hw, u8 type);
void rtl8821ae_dm_bt_bb_back_off_level(struct ieee80211_hw *hw, u8 type);
u8 rtl8821ae_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw,
u8 level_num, u8 rssi_thresh, u8 rssi_thresh1);
diff --git a/drivers/staging/rtl8821ae/rtl8821ae/hal_btc.c b/drivers/staging/rtl8821ae/rtl8821ae/hal_btc.c
index 79386ee142f9..7b1d113505fb 100644
--- a/drivers/staging/rtl8821ae/rtl8821ae/hal_btc.c
+++ b/drivers/staging/rtl8821ae/rtl8821ae/hal_btc.c
@@ -157,7 +157,7 @@ bool rtl8821ae_dm_bt_is_same_coexist_state(struct ieee80211_hw *hw)
&&(rtlpcipriv->btcoexist.previous_state_h
== rtlpcipriv->btcoexist.current_state_h)) {
RT_TRACE(COMP_BT_COEXIST, DBG_DMESG,
- ("[DM][BT], Coexist state do not chang!!\n"));
+ ("[DM][BT], Coexist state do not change!!\n"));
return true;
} else {
RT_TRACE(COMP_BT_COEXIST, DBG_DMESG,
@@ -902,7 +902,7 @@ void rtl8821ae_dm_bt_set_bt_dm(struct ieee80211_hw *hw, struct btdm_8821ae *p_bt
/*
* Note:
- * We should add delay for making sure sw DacSwing can be set sucessfully.
+ * We should add delay for making sure sw DacSwing can be set successfully.
* because of that rtl8821ae_dm_bt_set_fw_2_ant_hid() and rtl8821ae_dm_bt_set_fw_tdma_ctrl()
* will overwrite the reg 0x880.
*/
@@ -2025,7 +2025,7 @@ void rtl_8821ae_c2h_command_handle(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, 0x1AF, 0x00);
return;
}
- ptmp_buf = (u8 *) kmalloc(c2h_event.cmd_len, GFP_KERNEL);
+ ptmp_buf = kmalloc(c2h_event.cmd_len, GFP_KERNEL);
if(ptmp_buf == NULL) {
RT_TRACE(COMP_FW, DBG_TRACE, ("malloc cmd buf failed\n"));
return;
diff --git a/drivers/staging/rtl8821ae/rtl8821ae/hw.c b/drivers/staging/rtl8821ae/rtl8821ae/hw.c
index 5ed7a114c56b..1b8583b689d4 100644
--- a/drivers/staging/rtl8821ae/rtl8821ae/hw.c
+++ b/drivers/staging/rtl8821ae/rtl8821ae/hw.c
@@ -147,6 +147,7 @@ static void _rtl8821ae_set_fw_clock_on(struct ieee80211_hw *hw,
} else {
rtlhal->bfw_clk_change_in_progress = false;
spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ break;
}
}
@@ -1016,7 +1017,7 @@ static void _rtl8821ae_hw_configure(struct ieee80211_hw *hw)
/* ARFB table 12 for 11ac 24G 1SS */
rtl_write_dword(rtlpriv, REG_ARFR3, 0x00000015);
rtl_write_dword(rtlpriv, REG_ARFR3 + 4, 0xffcff000);
- /* 0x420[7] = 0 , enable retry AMPDU in new AMPD not singal MPDU. */
+ /* 0x420[7] = 0 , enable retry AMPDU in new AMPD not signal MPDU. */
rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F00);
rtl_write_byte(rtlpriv, REG_AMPDU_MAX_TIME, 0x70);
@@ -1406,7 +1407,7 @@ int rtl8821ae_hw_init(struct ieee80211_hw *hw)
rtl8821ae_phy_mac_config(hw);
/* because last function modify RCR, so we update
* rcr var here, or TP will unstable for receive_config
- * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx
+ * is wrong, RX RCR_ACRC32 will cause TP unstable & Rx
* RCR_APP_ICV will cause mac80211 unassoc for cisco 1252
rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR);
rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV);
@@ -1562,7 +1563,7 @@ static enum version_8821ae _rtl8821ae_read_chip_version(struct ieee80211_hw *hw)
break;
default:
RT_TRACE(COMP_INIT, DBG_LOUD,
- ("Chip Version ID: Unknow (0x%X).\n", version));
+ ("Chip Version ID: Unknown (0x%X).\n", version));
break;
}
@@ -1622,7 +1623,7 @@ static int _rtl8821ae_set_media_status(struct ieee80211_hw *hw,
rtl_write_byte(rtlpriv, (MSR), bt_msr);
rtlpriv->cfg->ops->led_control(hw, ledaction);
- if ((bt_msr & 0xfc) == MSR_AP)
+ if ((bt_msr & ~0xfc) == MSR_AP)
rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);
else
rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66);
@@ -2371,7 +2372,7 @@ static void _rtl8812ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_
if (rtlefuse->eeprom_channelplan == 0xff)
rtlefuse->eeprom_channelplan = 0x7F;
- /* set channel paln to world wide 13 */
+ /* set channel plan to world wide 13 */
//rtlefuse->channel_plan = (u8) rtlefuse->eeprom_channelplan;
/*parse xtal*/
@@ -2534,7 +2535,7 @@ static void _rtl8821ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_
if (rtlefuse->eeprom_channelplan == 0xff)
rtlefuse->eeprom_channelplan = 0x7F;
- /* set channel paln to world wide 13 */
+ /* set channel plan to world wide 13 */
//rtlefuse->channel_plan = (u8) rtlefuse->eeprom_channelplan;
/*parse xtal*/
diff --git a/drivers/staging/rtl8821ae/rtl8821ae/phy.c b/drivers/staging/rtl8821ae/rtl8821ae/phy.c
index d02fca38a2b2..1dd33016b4b9 100644
--- a/drivers/staging/rtl8821ae/rtl8821ae/phy.c
+++ b/drivers/staging/rtl8821ae/rtl8821ae/phy.c
@@ -86,7 +86,7 @@ void rtl8812ae_fixspur(
/* 0x8AC[11:10] = 2'b10*/
- /* <20120914, Kordan> A workarould to resolve
+ /* <20120914, Kordan> A workaround to resolve
2480Mhz spur by setting ADC clock as 160M. (Asked by Binson)*/
if (band_width == HT_CHANNEL_WIDTH_20 &&
(channel == 13 || channel == 14)) {
@@ -107,7 +107,7 @@ void rtl8812ae_fixspur(
}
else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
{
- /* <20120914, Kordan> A workarould to resolve
+ /* <20120914, Kordan> A workaround to resolve
2480Mhz spur by setting ADC clock as 160M. (Asked by Binson)*/
if (band_width == HT_CHANNEL_WIDTH_20 &&
(channel == 13 || channel == 14))
@@ -441,8 +441,8 @@ u32 phy_get_tx_bb_swing_8812A(
struct rtl_dm *rtldm = rtl_dm(rtlpriv);
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
- char bb_swing_2g = (char) (-1 * 0xFF);
- char bb_swing_5g = (char) (-1 * 0xFF);
+ char bb_swing_2g = (char) ((-1 * 0xFF) & 0xFF);
+ char bb_swing_5g = (char) ((-1 * 0xFF) & 0xFF);
u32 out = 0x200;
const char auto_temp = -1;
diff --git a/drivers/staging/rtl8821ae/rtl8821ae/phy.h b/drivers/staging/rtl8821ae/rtl8821ae/phy.h
index a932d8c9d45d..a80bf739940a 100644
--- a/drivers/staging/rtl8821ae/rtl8821ae/phy.h
+++ b/drivers/staging/rtl8821ae/rtl8821ae/phy.h
@@ -30,7 +30,7 @@
#ifndef __RTL8821AE_PHY_H__
#define __RTL8821AE_PHY_H__
-/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/
+/*It must always set to 4, otherwise read efuse table sequence will be wrong.*/
#define MAX_TX_COUNT 4
#define TX_1S 0
#define TX_2S 1
diff --git a/drivers/staging/rtl8821ae/rtl8821ae/pwrseq.h b/drivers/staging/rtl8821ae/rtl8821ae/pwrseq.h
index 8b39c042fa93..480a6bb6d76b 100644
--- a/drivers/staging/rtl8821ae/rtl8821ae/pwrseq.h
+++ b/drivers/staging/rtl8821ae/rtl8821ae/pwrseq.h
@@ -81,7 +81,7 @@
{0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \
{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/* suspend option all off */ \
{0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x80, BIT7},/*0x14[7] = 1 turn on ZCD */ \
- {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 trun on ZCD */ \
+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 turn on ZCD */ \
{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x10, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \
{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x02, 0},/*0x8[1] = 0 ANA clk =500k */ \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3, BIT3}, /*0x04[11] = 2b'11 enable WL suspend for PCIe*/
@@ -91,7 +91,7 @@
/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3, 0}, /*0x04[11] = 2b'01enable WL suspend*/ \
{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x10, 0},/*0x23[4] = 0 hpon LDO sleep mode leave */ \
- {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 trun off ZCD */ \
+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 turn off ZCD */ \
{0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x80, 0},/*0x14[7] = 0 turn off ZCD */ \
{0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \
{0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio11 input mode, gpio10~8 input mode */
@@ -110,7 +110,7 @@
{0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0xff},/* gpio0~7 output mode */ \
{0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \
{0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x80, BIT7},/*0x14[7] = 1 turn on ZCD */ \
- {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 trun on ZCD */ \
+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 turn on ZCD */ \
{0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, 0},/*0x12[0] = 0 force PFM mode */ \
{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x10, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \
{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x02, 0},/*0x8[1] = 0 ANA clk =500k */ \
@@ -124,7 +124,7 @@
/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \
{0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, BIT0},/*0x12[0] = 1 force PWM mode */ \
{0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x80, 0},/*0x14[7] = 0 turn off ZCD */ \
- {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 trun off ZCD */ \
+ {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 turn off ZCD */ \
{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x10, 0},/*0x23[4] = 0 hpon LDO leave sleep mode */ \
{0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \
{0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio11 input mode, gpio10~8 input mode */ \
@@ -204,7 +204,7 @@ extern struct wlan_pwr_cfg rtl8812_leave_lps_flow[RTL8812_TRANS_LPS_TO_ACT_STEP
4: LPS--Low Power State
5: SUS--Suspend
- The transision from different states are defined below
+ The transition from different states are defined below
TRANS_CARDEMU_TO_ACT
TRANS_ACT_TO_CARDEMU
TRANS_CARDEMU_TO_SUS
diff --git a/drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.c b/drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.c
index 710bc015251c..ff1887187770 100644
--- a/drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.c
+++ b/drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.c
@@ -82,7 +82,7 @@ bool rtl_hal_pwrseqcmdparsing (struct rtl_priv* rtlpriv, u8 cut_version,
value = value | (GET_PWR_CFG_VALUE(pwr_cfg_cmd)
& GET_PWR_CFG_MASK(pwr_cfg_cmd));
- /*Write the value back to sytem register*/
+ /*Write the value back to system register*/
rtl_write_byte(rtlpriv, offset, value);
}
break;
diff --git a/drivers/staging/rtl8821ae/rtl8821ae/reg.h b/drivers/staging/rtl8821ae/rtl8821ae/reg.h
index 09c5f00d2603..beffb4243b1e 100644
--- a/drivers/staging/rtl8821ae/rtl8821ae/reg.h
+++ b/drivers/staging/rtl8821ae/rtl8821ae/reg.h
@@ -596,13 +596,13 @@
#define IMR_BCNDMAINT3 BIT(23) /* Beacon DMA Interrupt 3 */
#define IMR_BCNDMAINT2 BIT(22) /* Beacon DMA Interrupt 2 */
#define IMR_BCNDMAINT1 BIT(21) /* Beacon DMA Interrupt 1 */
-#define IMR_BCNDOK7 BIT(20) /* Beacon Queue DMA OK Interrup 7 */
-#define IMR_BCNDOK6 BIT(19) /* Beacon Queue DMA OK Interrup 6 */
-#define IMR_BCNDOK5 BIT(18) /* Beacon Queue DMA OK Interrup 5 */
-#define IMR_BCNDOK4 BIT(17) /* Beacon Queue DMA OK Interrup 4 */
-#define IMR_BCNDOK3 BIT(16) /* Beacon Queue DMA OK Interrup 3 */
-#define IMR_BCNDOK2 BIT(15) /* Beacon Queue DMA OK Interrup 2 */
-#define IMR_BCNDOK1 BIT(14) /* Beacon Queue DMA OK Interrup 1 */
+#define IMR_BCNDOK7 BIT(20) /* Beacon Queue DMA OK Interrupt 7 */
+#define IMR_BCNDOK6 BIT(19) /* Beacon Queue DMA OK Interrupt 6 */
+#define IMR_BCNDOK5 BIT(18) /* Beacon Queue DMA OK Interrupt 5 */
+#define IMR_BCNDOK4 BIT(17) /* Beacon Queue DMA OK Interrupt 4 */
+#define IMR_BCNDOK3 BIT(16) /* Beacon Queue DMA OK Interrupt 3 */
+#define IMR_BCNDOK2 BIT(15) /* Beacon Queue DMA OK Interrupt 2 */
+#define IMR_BCNDOK1 BIT(14) /* Beacon Queue DMA OK Interrupt 1 */
#define IMR_ATIMEND_E BIT(13) /* ATIM Window End Extension for Win7 */
#define IMR_TXERR BIT(11) /* Tx Error Flag Interrupt Status, write 1 clear. */
#define IMR_RXERR BIT(10) /* Rx Error Flag INT Status, Write 1 clear */
@@ -613,7 +613,7 @@
#define HWSET_MAX_SIZE 512
#define EFUSE_MAX_SECTION 64
#define EFUSE_REAL_CONTENT_LEN 256
-#define EFUSE_OOB_PROTECT_BYTES 18 /* PG data exclude header, dummy 7 bytes frome CP test and reserved 1byte.*/
+#define EFUSE_OOB_PROTECT_BYTES 18 /* PG data exclude header, dummy 7 bytes from CP test and reserved 1byte.*/
#define EEPROM_DEFAULT_TSSI 0x0
@@ -1511,7 +1511,7 @@
#define ROFDM0_TXCOEFF5 0xcb4
#define ROFDM0_TXCOEFF6 0xcb8
-/*Path_A RFE cotrol */
+/*Path_A RFE control */
#define RA_RFE_CTRL_8812 0xcb8
/*Path_B RFE control*/
#define RB_RFE_CTRL_8812 0xeb8
@@ -2336,19 +2336,19 @@
#define WOL_REASON_DEAUTH BIT(3)
#define WOL_REASON_FW_DISCONNECT BIT(4)
-#define RA_RFE_PINMUX 0xcb0 /* Path_A RFE cotrol pinmux*/
+#define RA_RFE_PINMUX 0xcb0 /* Path_A RFE control pinmux*/
#define RB_RFE_PINMUX 0xeb0 /* Path_B RFE control pinmux*/
#define RA_RFE_INV 0xcb4
#define RB_RFE_INV 0xeb4
/* RXIQC */
-#define RA_RXIQC_AB 0xc10 /*RxIQ imblance matrix coeff. A & B*/
-#define RA_RXIQC_CD 0xc14 /*RxIQ imblance matrix coeff. C & D*/
+#define RA_RXIQC_AB 0xc10 /*RxIQ imbalance matrix coeff. A & B*/
+#define RA_RXIQC_CD 0xc14 /*RxIQ imbalance matrix coeff. C & D*/
#define RA_TXSCALE 0xc1c /* Pah_A TX scaling factor*/
#define RB_TXSCALE 0xe1c /* Path_B TX scaling factor*/
-#define RB_RXIQC_AB 0xe10 /*RxIQ imblance matrix coeff. A & B*/
-#define RB_RXIQC_CD 0xe14 /*RxIQ imblance matrix coeff. C & D*/
+#define RB_RXIQC_AB 0xe10 /*RxIQ imbalance matrix coeff. A & B*/
+#define RB_RXIQC_CD 0xe14 /*RxIQ imbalance matrix coeff. C & D*/
#define RXIQC_AC 0x02ff /*bit mask for IQC matrix element A & C*/
#define RXIQC_BD 0x02ff0000 /*bit mask for IQC matrix element A & C*/
diff --git a/drivers/staging/rtl8821ae/rtl8821ae/sw.c b/drivers/staging/rtl8821ae/rtl8821ae/sw.c
index 85a3474fc099..a8d175569770 100644
--- a/drivers/staging/rtl8821ae/rtl8821ae/sw.c
+++ b/drivers/staging/rtl8821ae/rtl8821ae/sw.c
@@ -57,9 +57,9 @@ void rtl8821ae_init_aspm_vars(struct ieee80211_hw *hw)
* 0 - Disable ASPM,
* 1 - Enable ASPM without Clock Req,
* 2 - Enable ASPM with Clock Req,
- * 3 - Alwyas Enable ASPM with Clock Req,
+ * 3 - Always Enable ASPM with Clock Req,
* 4 - Always Enable ASPM without Clock Req.
- * set defult to RTL8192CE:3 RTL8192E:2
+ * set default to RTL8192CE:3 RTL8192E:2
* */
rtlpci->const_pci_aspm = 3;
diff --git a/drivers/staging/rtl8821ae/rtl8821ae/trx.c b/drivers/staging/rtl8821ae/rtl8821ae/trx.c
index 75ae4387fe19..dd0f6dcb3085 100644
--- a/drivers/staging/rtl8821ae/rtl8821ae/trx.c
+++ b/drivers/staging/rtl8821ae/rtl8821ae/trx.c
@@ -37,8 +37,8 @@
#include "trx.h"
#include "led.h"
#include "dm.h"
-#include "phy.h"
-u8 _rtl8821ae_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
+
+static u8 _rtl8821ae_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
{
u16 fc = rtl_get_fc(skb);
@@ -244,7 +244,7 @@ static void _rtl8821ae_query_rxphystatus(struct ieee80211_hw *hw,
cck_agc_rpt = cck_buf->cck_agc_rpt;
/* (1)Hardware does not provide RSSI for CCK */
- /* (2)PWDB, Average PWDB cacluated by
+ /* (2)PWDB, Average PWDB calculated by
* hardware (for rate adaptive) */
if (ppsc->rfpwr_state == ERFON)
cck_highpwr = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2,
@@ -363,7 +363,7 @@ static void _rtl8821ae_query_rxphystatus(struct ieee80211_hw *hw,
pstatus->rx_mimo_signalstrength[i] = (u8) rssi;
}
- /* (2)PWDB, Average PWDB cacluated by
+ /* (2)PWDB, Average PWDB calculated by
* hardware (for rate adaptive) */
rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
@@ -603,7 +603,7 @@ bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw,
/* hw will set status->decrypted true, if it finds the
* frame is open data frame or mgmt frame. */
- /* So hw will not decryption robust managment frame
+ /* So hw will not decryption robust management frame
* for IEEE80211w but still set status->decrypted
* true, so here we should set it back to undecrypted
* for IEEE80211w frame, and mac80211 sw will help
diff --git a/drivers/staging/rtl8821ae/wifi.h b/drivers/staging/rtl8821ae/wifi.h
index 76bef93ad70a..17a9d9f8781d 100644
--- a/drivers/staging/rtl8821ae/wifi.h
+++ b/drivers/staging/rtl8821ae/wifi.h
@@ -40,10 +40,10 @@
#define RF_CHANGE_BY_INIT 0
-#define RF_CHANGE_BY_IPS BIT(28)
-#define RF_CHANGE_BY_PS BIT(29)
-#define RF_CHANGE_BY_HW BIT(30)
-#define RF_CHANGE_BY_SW BIT(31)
+#define RF_CHANGE_BY_IPS BIT(28)
+#define RF_CHANGE_BY_PS BIT(29)
+#define RF_CHANGE_BY_HW BIT(30)
+#define RF_CHANGE_BY_SW BIT(31)
#define IQK_ADDA_REG_NUM 16
#define IQK_MAC_REG_NUM 4
@@ -69,35 +69,35 @@
#define QBSS_LOAD_SIZE 5
#define MAX_WMMELE_LENGTH 64
-#define TOTAL_CAM_ENTRY 32
+#define TOTAL_CAM_ENTRY 32
/*slot time for 11g. */
#define RTL_SLOT_TIME_9 9
#define RTL_SLOT_TIME_20 20
/*related with tcp/ip. */
-/*if_ehther.h*/
-#define ETH_P_PAE 0x888E /*Port Access Entity
+/*if_ether.h*/
+#define ETH_P_PAE 0x888E /*Port Access Entity
*(IEEE 802.1X) */
-#define ETH_P_IP 0x0800 /*Internet Protocol packet */
-#define ETH_P_ARP 0x0806 /*Address Resolution packet */
-#define SNAP_SIZE 6
+#define ETH_P_IP 0x0800 /*Internet Protocol packet */
+#define ETH_P_ARP 0x0806 /*Address Resolution packet */
+#define SNAP_SIZE 6
#define PROTOC_TYPE_SIZE 2
/*related with 802.11 frame*/
-#define MAC80211_3ADDR_LEN 24
-#define MAC80211_4ADDR_LEN 30
+#define MAC80211_3ADDR_LEN 24
+#define MAC80211_4ADDR_LEN 30
#define CHANNEL_MAX_NUMBER (14 + 24 + 21) /* 14 is the max
* channel number */
#define CHANNEL_MAX_NUMBER_2G 14
-#define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to
+#define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to
*"phy_GetChnlGroup8812A" and
* "Hal_ReadTxPowerInfo8812A"*/
#define CHANNEL_MAX_NUMBER_5G_80M 7
#define CHANNEL_GROUP_MAX (3 + 9) /* ch1~3, ch4~9, ch10~14
* total three groups */
-#define MAX_PG_GROUP 13
+#define MAX_PG_GROUP 13
#define CHANNEL_GROUP_MAX_2G 3
#define CHANNEL_GROUP_IDX_5GL 3
#define CHANNEL_GROUP_IDX_5GM 6
@@ -112,14 +112,14 @@
#define MAX_NUM_RATES 264
/*for 88E use*/
-/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/
+/*It must always set to 4, otherwise read efuse table sequence will be wrong.*/
#define MAX_TX_COUNT 4
#define MAX_RF_PATH 4
#define MAX_CHNL_GROUP_24G 6
#define MAX_CHNL_GROUP_5G 14
/* BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. */
-#define MAX_TX_QUEUE 9
+#define MAX_TX_QUEUE 9
#define TX_PWR_BY_RATE_NUM_BAND 2
#define TX_PWR_BY_RATE_NUM_RF 4
@@ -127,11 +127,11 @@
#define MAX_BASE_NUM_IN_PHY_REG_PG_24G 6
#define MAX_BASE_NUM_IN_PHY_REG_PG_5G 5
-#define DELTA_SWINGIDX_SIZE 30
-#define BAND_NUM 3
+#define DELTA_SWINGIDX_SIZE 30
+#define BAND_NUM 3
/*Now, it's just for 8192ee
*not OK yet, keep it 0*/
-#define DMA_IS_64BIT 0
+#define DMA_IS_64BIT 0
#define RTL8192EE_SEG_NUM 1 /* 0:2 seg, 1: 4 seg, 2: 8 seg */
struct txpower_info_2g {
@@ -219,7 +219,7 @@ enum hardware_type {
};
enum scan_operation_backup_opt {
- SCAN_OPT_BACKUP_BAND0=0,
+ SCAN_OPT_BACKUP_BAND0 = 0,
SCAN_OPT_BACKUP_BAND1,
SCAN_OPT_RESTORE,
SCAN_OPT_MAX
@@ -435,7 +435,7 @@ enum ht_channel_width {
HT_CHANNEL_WIDTH_80 = 2,
};
-/* Ref: 802.11i sepc D10.0 7.3.2.25.1
+/* Ref: 802.11i spec D10.0 7.3.2.25.1
Cipher Suites Encryption Algorithms */
enum rt_enc_alg {
NO_ENCRYPTION = 0,
@@ -499,14 +499,14 @@ enum rtl_var_map {
RTL_IMR_BCNDMAINT3, /*Beacon DMA Interrupt 3 */
RTL_IMR_BCNDMAINT2, /*Beacon DMA Interrupt 2 */
RTL_IMR_BCNDMAINT1, /*Beacon DMA Interrupt 1 */
- RTL_IMR_BCNDOK8, /*Beacon Queue DMA OK Interrup 8 */
- RTL_IMR_BCNDOK7, /*Beacon Queue DMA OK Interrup 7 */
- RTL_IMR_BCNDOK6, /*Beacon Queue DMA OK Interrup 6 */
- RTL_IMR_BCNDOK5, /*Beacon Queue DMA OK Interrup 5 */
- RTL_IMR_BCNDOK4, /*Beacon Queue DMA OK Interrup 4 */
- RTL_IMR_BCNDOK3, /*Beacon Queue DMA OK Interrup 3 */
- RTL_IMR_BCNDOK2, /*Beacon Queue DMA OK Interrup 2 */
- RTL_IMR_BCNDOK1, /*Beacon Queue DMA OK Interrup 1 */
+ RTL_IMR_BCNDOK8, /*Beacon Queue DMA OK Interrupt 8 */
+ RTL_IMR_BCNDOK7, /*Beacon Queue DMA OK Interrupt 7 */
+ RTL_IMR_BCNDOK6, /*Beacon Queue DMA OK Interrupt 6 */
+ RTL_IMR_BCNDOK5, /*Beacon Queue DMA OK Interrupt 5 */
+ RTL_IMR_BCNDOK4, /*Beacon Queue DMA OK Interrupt 4 */
+ RTL_IMR_BCNDOK3, /*Beacon Queue DMA OK Interrupt 3 */
+ RTL_IMR_BCNDOK2, /*Beacon Queue DMA OK Interrupt 2 */
+ RTL_IMR_BCNDOK1, /*Beacon Queue DMA OK Interrupt 1 */
RTL_IMR_TIMEOUT2, /*Timeout interrupt 2 */
RTL_IMR_TIMEOUT1, /*Timeout interrupt 1 */
RTL_IMR_TXFOVW, /*Transmit FIFO Overflow */
@@ -515,10 +515,10 @@ enum rtl_var_map {
RTL_IMR_RXFOVW, /*Receive FIFO Overflow */
RTL_IMR_RDU, /*Receive Descriptor Unavailable */
RTL_IMR_ATIMEND, /*For 92C,ATIM Window End Interrupt */
- RTL_IMR_BDOK, /*Beacon Queue DMA OK Interrup */
+ RTL_IMR_BDOK, /*Beacon Queue DMA OK Interrupt */
RTL_IMR_HIGHDOK, /*High Queue DMA OK Interrupt */
RTL_IMR_COMDOK, /*Command Queue DMA OK Interrupt*/
- RTL_IMR_TBDOK, /*Transmit Beacon OK interrup */
+ RTL_IMR_TBDOK, /*Transmit Beacon OK interrupt */
RTL_IMR_MGNTDOK, /*Management Queue DMA OK Interrupt */
RTL_IMR_TBDER, /*For 92C,Transmit Beacon Error Interrupt */
RTL_IMR_BKDOK, /*AC_BK DMA OK Interrupt */
@@ -645,9 +645,9 @@ enum wireless_mode {
};
enum ratr_table_mode {
- RATR_INX_WIRELESS_NGB = 0, // BGN 40 Mhz 2SS 1SS
- RATR_INX_WIRELESS_NG = 1, // GN or N
- RATR_INX_WIRELESS_NB = 2, // BGN 20 Mhz 2SS 1SS or BN
+ RATR_INX_WIRELESS_NGB = 0, /* BGN 40 Mhz 2SS 1SS */
+ RATR_INX_WIRELESS_NG = 1, /* GN or N */
+ RATR_INX_WIRELESS_NB = 2, /* BGN 20 Mhz 2SS 1SS or BN */
RATR_INX_WIRELESS_N = 3,
RATR_INX_WIRELESS_GB = 4,
RATR_INX_WIRELESS_G = 5,
@@ -759,7 +759,7 @@ struct rtl_tid_data {
struct rtl_ht_agg agg;
};
-struct rssi_sta{
+struct rssi_sta {
long undecorated_smoothed_pwdb;
};
@@ -899,7 +899,7 @@ struct regd_pair_mapping {
u16 reg_2ghz_ctl;
};
-struct dynamic_primary_cca{
+struct dynamic_primary_cca {
u8 pricca_flag;
u8 intf_flag;
u8 intf_type;
@@ -939,14 +939,14 @@ enum p2p_ps_state {
P2P_PS_ENABLE = 1,
P2P_PS_SCAN = 2,
P2P_PS_SCAN_DONE = 3,
- P2P_PS_ALLSTASLEEP = 4, // for P2P GO
+ P2P_PS_ALLSTASLEEP = 4, /* for P2P GO */
};
enum p2p_ps_mode {
P2P_PS_NONE = 0,
P2P_PS_CTWINDOW = 1,
P2P_PS_NOA = 2,
- P2P_PS_MIX = 3, // CTWindow and NoA
+ P2P_PS_MIX = 3, /* CTWindow and NoA */
};
struct rtl_p2p_ps_info {
@@ -969,7 +969,7 @@ struct rtl_p2p_ps_info {
u32 noa_start_time[P2P_MAX_NOA_NUM];
};
- struct p2p_ps_offload_t {
+struct p2p_ps_offload_t {
u8 Offload_En:1;
u8 role:1; /* 1: Owner, 0: Client */
u8 CTWindow_En:1;
@@ -981,7 +981,7 @@ struct rtl_p2p_ps_info {
};
#define IQK_MATRIX_REG_NUM 8
-#define IQK_MATRIX_SETTINGS_NUM (14+24+21) // Channels_2_4G_NUM + Channels_5G_20M_NUM + Channels_5G
+#define IQK_MATRIX_SETTINGS_NUM (14+24+21) /* Channels_2_4G_NUM + Channels_5G_20M_NUM + Channels_5G */
struct iqk_matrix_regs {
bool b_iqk_done;
long value[1][IQK_MATRIX_REG_NUM];
@@ -1074,12 +1074,12 @@ struct rtl_phy {
enum rt_polarity_ctl polarity_ctl;
};
-#define RTL_AGG_STOP 0
+#define RTL_AGG_STOP 0
#define RTL_AGG_PROGRESS 1
-#define RTL_AGG_START 2
+#define RTL_AGG_START 2
#define RTL_AGG_OPERATIONAL 3
-#define RTL_RX_AGG_START 1
-#define RTL_RX_AGG_STOP 0
+#define RTL_RX_AGG_START 1
+#define RTL_RX_AGG_STOP 0
struct rtl_priv;
struct rtl_io {
@@ -1092,13 +1092,13 @@ struct rtl_io {
/*PCI IO map */
unsigned long pci_base_addr; /*device I/O address */
- void (*write8_async) (struct rtl_priv * rtlpriv, u32 addr, u8 val);
- void (*write16_async) (struct rtl_priv * rtlpriv, u32 addr, u16 val);
- void (*write32_async) (struct rtl_priv * rtlpriv, u32 addr, u32 val);
+ void (*write8_async)(struct rtl_priv *rtlpriv, u32 addr, u8 val);
+ void (*write16_async)(struct rtl_priv *rtlpriv, u32 addr, u16 val);
+ void (*write32_async)(struct rtl_priv *rtlpriv, u32 addr, u32 val);
- u8(*read8_sync) (struct rtl_priv * rtlpriv, u32 addr);
- u16(*read16_sync) (struct rtl_priv * rtlpriv, u32 addr);
- u32(*read32_sync) (struct rtl_priv * rtlpriv, u32 addr);
+ u8 (*read8_sync)(struct rtl_priv *rtlpriv, u32 addr);
+ u16 (*read16_sync)(struct rtl_priv *rtlpriv, u32 addr);
+ u32 (*read32_sync)(struct rtl_priv *rtlpriv, u32 addr);
};
@@ -1256,7 +1256,7 @@ struct rtl_security {
bool use_defaultkey;
/*Encryption Algorithm for Unicast Packet */
enum rt_enc_alg pairwise_enc_algorithm;
- /*Encryption Algorithm for Brocast/Multicast */
+ /*Encryption Algorithm for Broadcast/Multicast */
enum rt_enc_alg group_enc_algorithm;
/*Cam Entry Bitmap */
u32 hwsec_cam_bitmap;
@@ -1317,9 +1317,9 @@ struct rtl_pstbl {
};
-#define ASSOCIATE_ENTRY_NUM 32+1
+#define ASSOCIATE_ENTRY_NUM (32+1)
-struct fast_ant_trainning{
+struct fast_ant_trainning {
u8 bssid[6];
u8 antsel_rx_keep_0;
u8 antsel_rx_keep_1;
@@ -1427,19 +1427,19 @@ struct rtl_dm {
char bb_swing_diff_5g;
u8 delta_swing_table_idx_24gccka_p[DELTA_SWINGIDX_SIZE];
- u8 delta_swing_table_idx_24gccka_n[DELTA_SWINGIDX_SIZE];
- u8 delta_swing_table_idx_24gcckb_p[DELTA_SWINGIDX_SIZE];
+ u8 delta_swing_table_idx_24gccka_n[DELTA_SWINGIDX_SIZE];
+ u8 delta_swing_table_idx_24gcckb_p[DELTA_SWINGIDX_SIZE];
u8 delta_swing_table_idx_24gcckb_n[DELTA_SWINGIDX_SIZE];
u8 delta_swing_table_idx_24ga_p[DELTA_SWINGIDX_SIZE];
- u8 delta_swing_table_idx_24ga_n[DELTA_SWINGIDX_SIZE];
- u8 delta_swing_table_idx_24gb_p[DELTA_SWINGIDX_SIZE];
- u8 delta_swing_table_idx_24gb_n[DELTA_SWINGIDX_SIZE];
- u8 delta_swing_table_idx_5ga_p[BAND_NUM][DELTA_SWINGIDX_SIZE];
- u8 delta_swing_table_idx_5ga_n[BAND_NUM][DELTA_SWINGIDX_SIZE];
- u8 delta_swing_table_idx_5gb_p[BAND_NUM][DELTA_SWINGIDX_SIZE];
- u8 delta_swing_table_idx_5gb_n[BAND_NUM][DELTA_SWINGIDX_SIZE];
- u8 delta_swing_table_idx_24ga_p_8188e[DELTA_SWINGIDX_SIZE];
- u8 delta_swing_table_idx_24ga_n_8188e[DELTA_SWINGIDX_SIZE];
+ u8 delta_swing_table_idx_24ga_n[DELTA_SWINGIDX_SIZE];
+ u8 delta_swing_table_idx_24gb_p[DELTA_SWINGIDX_SIZE];
+ u8 delta_swing_table_idx_24gb_n[DELTA_SWINGIDX_SIZE];
+ u8 delta_swing_table_idx_5ga_p[BAND_NUM][DELTA_SWINGIDX_SIZE];
+ u8 delta_swing_table_idx_5ga_n[BAND_NUM][DELTA_SWINGIDX_SIZE];
+ u8 delta_swing_table_idx_5gb_p[BAND_NUM][DELTA_SWINGIDX_SIZE];
+ u8 delta_swing_table_idx_5gb_n[BAND_NUM][DELTA_SWINGIDX_SIZE];
+ u8 delta_swing_table_idx_24ga_p_8188e[DELTA_SWINGIDX_SIZE];
+ u8 delta_swing_table_idx_24ga_n_8188e[DELTA_SWINGIDX_SIZE];
/* DMSP */
@@ -1451,7 +1451,7 @@ struct rtl_dm {
struct fast_ant_trainning fat_table;
u8 resp_tx_path;
- u8 path_sel;
+ u8 path_sel;
u32 patha_sum;
u32 pathb_sum;
u32 patha_cnt;
@@ -1671,7 +1671,6 @@ struct rtl_stats {
u8 rx_mimo_evm_dbm[4];
u16 cfo_short[4]; /* per-path's Cfo_short */
u16 cfo_tail[4];
-
u8 rx_pwr[4]; /* per-path's pwdb */
u8 rx_snr[4]; /* per-path's SNR */
u8 bandwidth;
@@ -1692,7 +1691,7 @@ struct rtl_stats {
};
struct rt_link_detect {
- /* count for raoming */
+ /* count for roaming */
u32 bcn_rx_inperiod;
u32 roam_times;
@@ -1756,48 +1755,48 @@ struct proxim {
void *proximity_priv;
int (*proxim_rx)(struct ieee80211_hw *hw, struct rtl_stats *status,
struct sk_buff *skb);
- u8 (*proxim_get_var)(struct ieee80211_hw *hw, u8 type);
+ u8 (*proxim_get_var)(struct ieee80211_hw *hw, u8 type);
};
struct rtl_hal_ops {
- int (*init_sw_vars) (struct ieee80211_hw * hw);
- void (*deinit_sw_vars) (struct ieee80211_hw * hw);
- void (*read_eeprom_info) (struct ieee80211_hw * hw);
- void (*interrupt_recognized) (struct ieee80211_hw * hw,
- u32 * p_inta, u32 * p_intb);
- int (*hw_init) (struct ieee80211_hw * hw);
- void (*hw_disable) (struct ieee80211_hw * hw);
- void (*hw_suspend) (struct ieee80211_hw * hw);
- void (*hw_resume) (struct ieee80211_hw * hw);
- void (*enable_interrupt) (struct ieee80211_hw * hw);
- void (*disable_interrupt) (struct ieee80211_hw * hw);
- int (*set_network_type) (struct ieee80211_hw * hw,
- enum nl80211_iftype type);
+ int (*init_sw_vars)(struct ieee80211_hw *hw);
+ void (*deinit_sw_vars)(struct ieee80211_hw *hw);
+ void (*read_eeprom_info)(struct ieee80211_hw *hw);
+ void (*interrupt_recognized)(struct ieee80211_hw *hw,
+ u32 *p_inta, u32 *p_intb);
+ int (*hw_init)(struct ieee80211_hw *hw);
+ void (*hw_disable)(struct ieee80211_hw *hw);
+ void (*hw_suspend)(struct ieee80211_hw *hw);
+ void (*hw_resume)(struct ieee80211_hw *hw);
+ void (*enable_interrupt)(struct ieee80211_hw *hw);
+ void (*disable_interrupt)(struct ieee80211_hw *hw);
+ int (*set_network_type)(struct ieee80211_hw *hw,
+ enum nl80211_iftype type);
void (*set_chk_bssid)(struct ieee80211_hw *hw,
bool check_bssid);
- void (*set_bw_mode) (struct ieee80211_hw * hw,
- enum nl80211_channel_type ch_type);
- u8(*switch_channel) (struct ieee80211_hw * hw);
- void (*set_qos) (struct ieee80211_hw * hw, int aci);
- void (*set_bcn_reg) (struct ieee80211_hw * hw);
- void (*set_bcn_intv) (struct ieee80211_hw * hw);
- void (*update_interrupt_mask) (struct ieee80211_hw * hw,
- u32 add_msr, u32 rm_msr);
- void (*get_hw_reg) (struct ieee80211_hw * hw, u8 variable, u8 * val);
- void (*set_hw_reg) (struct ieee80211_hw * hw, u8 variable, u8 * val);
- void (*update_rate_tbl) (struct ieee80211_hw * hw,
- struct ieee80211_sta *sta, u8 rssi_level);
- void (*pre_fill_tx_bd_desc) (struct ieee80211_hw *hw, u8 *tx_bd_desc,
- u8 *desc, u8 queue_index,
- struct sk_buff *skb, dma_addr_t addr);
- u16 (*rx_desc_buff_remained_cnt) (struct ieee80211_hw *hw,
- u8 queue_index);
- void (*rx_check_dma_ok) (struct ieee80211_hw *hw, u8 *header_desc,
- u8 queue_index);
- void (*fill_tx_desc) (struct ieee80211_hw * hw,
- struct ieee80211_hdr * hdr,
- u8 * pdesc_tx, u8 * pbd_desc,
- struct ieee80211_tx_info * info,
+ void (*set_bw_mode)(struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type);
+ u8 (*switch_channel)(struct ieee80211_hw *hw);
+ void (*set_qos)(struct ieee80211_hw *hw, int aci);
+ void (*set_bcn_reg)(struct ieee80211_hw *hw);
+ void (*set_bcn_intv)(struct ieee80211_hw *hw);
+ void (*update_interrupt_mask)(struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr);
+ void (*get_hw_reg)(struct ieee80211_hw *hw, u8 variable, u8 *val);
+ void (*set_hw_reg)(struct ieee80211_hw *hw, u8 variable, u8 *val);
+ void (*update_rate_tbl)(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi_level);
+ void (*pre_fill_tx_bd_desc)(struct ieee80211_hw *hw, u8 *tx_bd_desc,
+ u8 *desc, u8 queue_index,
+ struct sk_buff *skb, dma_addr_t addr);
+ u16 (*rx_desc_buff_remained_cnt)(struct ieee80211_hw *hw,
+ u8 queue_index);
+ void (*rx_check_dma_ok)(struct ieee80211_hw *hw, u8 *header_desc,
+ u8 queue_index);
+ void (*fill_tx_desc)(struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr,
+ u8 *pdesc_tx, u8 *pbd_desc,
+ struct ieee80211_tx_info *info,
/*<delete in kernel start>*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0))
/*<delete in kernel end>*/
@@ -1805,74 +1804,77 @@ struct rtl_hal_ops {
/*<delete in kernel start>*/
#endif
/*<delete in kernel end>*/
- struct sk_buff * skb, u8 hw_queue,
+ struct sk_buff *skb, u8 hw_queue,
struct rtl_tcb_desc *ptcb_desc);
- void (*fill_tx_cmddesc) (struct ieee80211_hw * hw, u8 * pdesc,
- bool b_firstseg, bool b_lastseg,
- struct sk_buff * skb);
- bool(*query_rx_desc) (struct ieee80211_hw * hw,
- struct rtl_stats * status,
- struct ieee80211_rx_status * rx_status,
- u8 * pdesc, struct sk_buff * skb);
- void (*set_channel_access) (struct ieee80211_hw * hw);
- bool(*radio_onoff_checking) (struct ieee80211_hw * hw, u8 * valid);
- void (*dm_watchdog) (struct ieee80211_hw * hw);
- void (*scan_operation_backup) (struct ieee80211_hw * hw, u8 operation);
- bool(*set_rf_power_state) (struct ieee80211_hw * hw,
- enum rf_pwrstate rfpwr_state);
- void (*led_control) (struct ieee80211_hw * hw,
- enum led_ctl_mode ledaction);
- void (*set_desc) (struct ieee80211_hw *hw, u8 * pdesc, bool istx,
- u8 desc_name, u8 * val);
- u32(*get_desc) (u8 * pdesc, bool istx, u8 desc_name);
- bool (*is_tx_desc_closed) (struct ieee80211_hw *hw,
- u8 hw_queue, u16 index);
- void (*tx_polling) (struct ieee80211_hw * hw, u8 hw_queue);
- void (*enable_hw_sec) (struct ieee80211_hw * hw);
- void (*set_key) (struct ieee80211_hw * hw, u32 key_index,
- u8 * p_macaddr, bool is_group, u8 enc_algo,
- bool is_wepkey, bool clear_all);
- void (*init_sw_leds) (struct ieee80211_hw * hw);
- u32(*get_bbreg) (struct ieee80211_hw * hw, u32 regaddr, u32 bitmask);
- void (*set_bbreg) (struct ieee80211_hw * hw, u32 regaddr, u32 bitmask,
- u32 data);
- u32(*get_rfreg) (struct ieee80211_hw * hw, enum radio_path rfpath,
- u32 regaddr, u32 bitmask);
- void (*set_rfreg) (struct ieee80211_hw * hw, enum radio_path rfpath,
- u32 regaddr, u32 bitmask, u32 data);
+ void (*fill_tx_cmddesc)(struct ieee80211_hw *hw, u8 *pdesc,
+ bool b_firstseg, bool b_lastseg,
+ struct sk_buff *skb);
+ bool (*query_rx_desc)(struct ieee80211_hw *hw,
+ struct rtl_stats *status,
+ struct ieee80211_rx_status *rx_status,
+ u8 *pdesc, struct sk_buff *skb);
+ void (*set_channel_access)(struct ieee80211_hw *hw);
+ bool (*radio_onoff_checking)(struct ieee80211_hw *hw, u8 *valid);
+ void (*dm_watchdog)(struct ieee80211_hw *hw);
+ void (*scan_operation_backup)(struct ieee80211_hw *hw, u8 operation);
+ bool (*set_rf_power_state)(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state);
+ void (*led_control)(struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction);
+ void (*set_desc)(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+ u8 desc_name, u8 *val);
+ u32 (*get_desc)(u8 *pdesc, bool istx, u8 desc_name);
+ bool (*is_tx_desc_closed)(struct ieee80211_hw *hw,
+ u8 hw_queue, u16 index);
+ void (*tx_polling)(struct ieee80211_hw *hw, u8 hw_queue);
+ void (*enable_hw_sec)(struct ieee80211_hw *hw);
+ void (*set_key)(struct ieee80211_hw *hw, u32 key_index,
+ u8 *p_macaddr, bool is_group, u8 enc_algo,
+ bool is_wepkey, bool clear_all);
+ void (*init_sw_leds)(struct ieee80211_hw *hw);
+ u32 (*get_bbreg)(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask);
+ void (*set_bbreg)(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask,
+ u32 data);
+ u32 (*get_rfreg)(struct ieee80211_hw *hw, enum radio_path rfpath,
+ u32 regaddr, u32 bitmask);
+ void (*set_rfreg)(struct ieee80211_hw *hw, enum radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data);
void (*allow_all_destaddr)(struct ieee80211_hw *hw,
- bool allow_all_da, bool write_into_reg);
- void (*linked_set_reg) (struct ieee80211_hw * hw);
- void (*check_switch_to_dmdp) (struct ieee80211_hw * hw);
- void (*dualmac_easy_concurrent) (struct ieee80211_hw *hw);
- void (*dualmac_switch_to_dmdp) (struct ieee80211_hw *hw);
- void (*c2h_command_handle) (struct ieee80211_hw *hw);
- void (*bt_wifi_media_status_notify) (struct ieee80211_hw *hw, bool mstate);
- void (*bt_turn_off_bt_coexist_before_enter_lps) (struct ieee80211_hw *hw);
- void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id,
- u32 cmd_len, u8 *p_cmdbuffer);
- bool (*get_btc_status) (void);
- u32 (*rx_command_packet_handler)(struct ieee80211_hw *hw, struct rtl_stats status, struct sk_buff *skb);
+ bool allow_all_da, bool write_into_reg);
+ void (*linked_set_reg)(struct ieee80211_hw *hw);
+ void (*check_switch_to_dmdp)(struct ieee80211_hw *hw);
+ void (*dualmac_easy_concurrent)(struct ieee80211_hw *hw);
+ void (*dualmac_switch_to_dmdp)(struct ieee80211_hw *hw);
+ void (*c2h_command_handle)(struct ieee80211_hw *hw);
+ void (*bt_wifi_media_status_notify)(struct ieee80211_hw *hw,
+ bool mstate);
+ void (*bt_turn_off_bt_coexist_before_enter_lps)(struct ieee80211_hw *hw);
+ void (*fill_h2c_cmd)(struct ieee80211_hw *hw, u8 element_id,
+ u32 cmd_len, u8 *p_cmdbuffer);
+ bool (*get_btc_status)(void);
+ u32 (*rx_command_packet_handler)(struct ieee80211_hw *hw,
+ struct rtl_stats status,
+ struct sk_buff *skb);
};
struct rtl_intf_ops {
/*com */
void (*read_efuse_byte)(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf);
- int (*adapter_start) (struct ieee80211_hw * hw);
- void (*adapter_stop) (struct ieee80211_hw * hw);
+ int (*adapter_start)(struct ieee80211_hw *hw);
+ void (*adapter_stop)(struct ieee80211_hw *hw);
bool (*check_buddy_priv)(struct ieee80211_hw *hw,
- struct rtl_priv **buddy_priv);
+ struct rtl_priv **buddy_priv);
/*<delete in kernel start>*/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0))
- int (*adapter_tx) (struct ieee80211_hw * hw, struct sk_buff * skb,
- struct rtl_tcb_desc *ptcb_desc);
+ int (*adapter_tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct rtl_tcb_desc *ptcb_desc);
#else
/*<delete in kernel end>*/
- int (*adapter_tx) (struct ieee80211_hw *hw,
- struct ieee80211_sta *sta,
- struct sk_buff *skb,
- struct rtl_tcb_desc *ptcb_desc);
+ int (*adapter_tx)(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
+ struct rtl_tcb_desc *ptcb_desc);
/*<delete in kernel start>*/
#endif
/*<delete in kernel end>*/
@@ -1881,22 +1883,22 @@ struct rtl_intf_ops {
#else
void (*flush)(struct ieee80211_hw *hw, bool drop);
#endif
- int (*reset_trx_ring) (struct ieee80211_hw * hw);
+ int (*reset_trx_ring)(struct ieee80211_hw *hw);
/*<delete in kernel start>*/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0))
- bool (*waitq_insert) (struct ieee80211_hw *hw, struct sk_buff *skb);
+ bool (*waitq_insert)(struct ieee80211_hw *hw, struct sk_buff *skb);
#else
/*<delete in kernel end>*/
- bool (*waitq_insert) (struct ieee80211_hw *hw,
- struct ieee80211_sta *sta,
- struct sk_buff *skb);
+ bool (*waitq_insert)(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb);
/*<delete in kernel start>*/
#endif
/*<delete in kernel end>*/
/*pci */
- void (*disable_aspm) (struct ieee80211_hw * hw);
- void (*enable_aspm) (struct ieee80211_hw * hw);
+ void (*disable_aspm)(struct ieee80211_hw *hw);
+ void (*enable_aspm)(struct ieee80211_hw *hw);
/*usb */
};
@@ -2027,21 +2029,21 @@ struct rtl_btc_info {
};
struct rtl_btc_ops {
- void (*btc_init_variables) (struct rtl_priv *rtlpriv);
- void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv);
- void (*btc_init_hw_config) (struct rtl_priv *rtlpriv);
- void (*btc_ips_notify) (struct rtl_priv *rtlpriv, u8 type);
- void (*btc_scan_notify) (struct rtl_priv *rtlpriv, u8 scantype);
- void (*btc_connect_notify) (struct rtl_priv *rtlpriv, u8 action);
- void (*btc_mediastatus_notify) (struct rtl_priv *rtlpriv,
- enum rt_media_status mstatus);
- void (*btc_periodical) (struct rtl_priv *rtlpriv);
- void (*btc_halt_notify) (void);
- void (*btc_btinfo_notify) (struct rtl_priv *rtlpriv,
- u8 * tmp_buf, u8 length);
- bool (*btc_is_limited_dig) (struct rtl_priv *rtlpriv);
- bool (*btc_is_disable_edca_turbo) (struct rtl_priv *rtlpriv);
- bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv);
+ void (*btc_init_variables)(struct rtl_priv *rtlpriv);
+ void (*btc_init_hal_vars)(struct rtl_priv *rtlpriv);
+ void (*btc_init_hw_config)(struct rtl_priv *rtlpriv);
+ void (*btc_ips_notify)(struct rtl_priv *rtlpriv, u8 type);
+ void (*btc_scan_notify)(struct rtl_priv *rtlpriv, u8 scantype);
+ void (*btc_connect_notify)(struct rtl_priv *rtlpriv, u8 action);
+ void (*btc_mediastatus_notify)(struct rtl_priv *rtlpriv,
+ enum rt_media_status mstatus);
+ void (*btc_periodical)(struct rtl_priv *rtlpriv);
+ void (*btc_halt_notify)(void);
+ void (*btc_btinfo_notify)(struct rtl_priv *rtlpriv,
+ u8 *tmp_buf, u8 length);
+ bool (*btc_is_limited_dig)(struct rtl_priv *rtlpriv);
+ bool (*btc_is_disable_edca_turbo)(struct rtl_priv *rtlpriv);
+ bool (*btc_is_bt_disabled)(struct rtl_priv *rtlpriv);
};
struct rtl_bt_coexist {
@@ -2087,7 +2089,7 @@ struct rtl_priv {
/*
*hal_cfg : for diff cards
- *intf_ops : for diff interrface usb/pcie
+ *intf_ops : for diff interface usb/pcie
*/
struct rtl_hal_cfg *cfg;
struct rtl_intf_ops *intf_ops;
@@ -2105,7 +2107,7 @@ struct rtl_priv {
/*for bt coexist use*/
struct rtl_bt_coexist btcoexist;
- /* seperate 92ee from other ICs,
+ /* separate 92ee from other ICs,
* 92ee use new trx flow. */
bool use_new_trx_flow;
/*This must be the last item so
@@ -2120,57 +2122,57 @@ struct rtl_priv {
#define rtl_hal(rtlpriv) (&((rtlpriv)->rtlhal))
#define rtl_efuse(rtlpriv) (&((rtlpriv)->efuse))
#define rtl_psc(rtlpriv) (&((rtlpriv)->psc))
-#define rtl_sec(rtlpriv) (&((rtlpriv)->sec))
-#define rtl_dm(rtlpriv) (&((rtlpriv)->dm))
+#define rtl_sec(rtlpriv) (&((rtlpriv)->sec))
+#define rtl_dm(rtlpriv) (&((rtlpriv)->dm))
/***************************************
Bluetooth Co-existance Related
****************************************/
enum bt_ant_num {
- ANT_X2 = 0,
- ANT_X1 = 1,
+ ANT_X2 = 0,
+ ANT_X1 = 1,
};
enum bt_co_type {
- BT_2WIRE = 0,
- BT_ISSC_3WIRE = 1,
- BT_ACCEL = 2,
- BT_CSR_BC4 = 3,
- BT_CSR_BC8 = 4,
- BT_RTL8756 = 5,
- BT_RTL8723A = 6,
- BT_RTL8821A = 7,
- BT_RTL8723B = 8,
- BT_RTL8192E = 9,
- BT_RTL8812A = 11,
-};
-
-enum bt_total_ant_num{
+ BT_2WIRE = 0,
+ BT_ISSC_3WIRE = 1,
+ BT_ACCEL = 2,
+ BT_CSR_BC4 = 3,
+ BT_CSR_BC8 = 4,
+ BT_RTL8756 = 5,
+ BT_RTL8723A = 6,
+ BT_RTL8821A = 7,
+ BT_RTL8723B = 8,
+ BT_RTL8192E = 9,
+ BT_RTL8812A = 11,
+};
+
+enum bt_total_ant_num {
ANT_TOTAL_X2 = 0,
ANT_TOTAL_X1 = 1
};
enum bt_cur_state {
- BT_OFF = 0,
- BT_ON = 1,
+ BT_OFF = 0,
+ BT_ON = 1,
};
enum bt_service_type {
- BT_SCO = 0,
- BT_A2DP = 1,
- BT_HID = 2,
- BT_HID_IDLE = 3,
- BT_SCAN = 4,
- BT_IDLE = 5,
- BT_OTHER_ACTION = 6,
- BT_BUSY = 7,
- BT_OTHERBUSY = 8,
- BT_PAN = 9,
+ BT_SCO = 0,
+ BT_A2DP = 1,
+ BT_HID = 2,
+ BT_HID_IDLE = 3,
+ BT_SCAN = 4,
+ BT_IDLE = 5,
+ BT_OTHER_ACTION = 6,
+ BT_BUSY = 7,
+ BT_OTHERBUSY = 8,
+ BT_PAN = 9,
};
enum bt_radio_shared {
- BT_RADIO_SHARED = 0,
- BT_RADIO_INDIVIDUAL = 1,
+ BT_RADIO_SHARED = 0,
+ BT_RADIO_INDIVIDUAL = 1,
};
struct bt_coexist_info {
@@ -2255,11 +2257,11 @@ struct bt_coexist_info {
/* Write data to memory */
#define WRITEEF1BYTE(_ptr, _val) \
- (*((u8 *)(_ptr)))=EF1BYTE(_val)
+ ((*((u8 *)(_ptr))) = EF1BYTE(_val))
#define WRITEEF2BYTE(_ptr, _val) \
- (*((u16 *)(_ptr)))=EF2BYTE(_val)
+ ((*((u16 *)(_ptr))) = EF2BYTE(_val))
#define WRITEEF4BYTE(_ptr, _val) \
- (*((u32 *)(_ptr)))=EF4BYTE(_val)
+ ((*((u32 *)(_ptr))) = EF4BYTE(_val))
/*Example:
BIT_LEN_MASK_32(0) => 0x00000000
@@ -2298,17 +2300,17 @@ Translate subfield (continuous bits in little-endian) of 4-byte
value to host byte ordering.*/
#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \
( \
- ( LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset) ) & \
+ (LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset)) & \
BIT_LEN_MASK_32(__bitlen) \
)
#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \
( \
- ( LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset) ) & \
+ (LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \
BIT_LEN_MASK_16(__bitlen) \
)
#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \
( \
- ( LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset) ) & \
+ (LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \
BIT_LEN_MASK_8(__bitlen) \
)
@@ -2318,17 +2320,17 @@ and return the result in 4-byte value in host byte ordering.*/
#define LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) \
( \
LE_P4BYTE_TO_HOST_4BYTE(__pstart) & \
- ( ~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen) ) \
+ (~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)) \
)
#define LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) \
( \
LE_P2BYTE_TO_HOST_2BYTE(__pstart) & \
- ( ~BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen) ) \
+ (~BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen)) \
)
#define LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) \
( \
LE_P1BYTE_TO_HOST_1BYTE(__pstart) & \
- ( ~BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen) ) \
+ (~BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen)) \
)
/*Description:
@@ -2337,19 +2339,19 @@ Set subfield of little-endian 4-byte value to specified value. */
*((u32 *)(__pstart)) = EF4BYTE \
( \
LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \
- ( (((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset) )\
+ ((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset))\
);
#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \
*((u16 *)(__pstart)) = EF2BYTE \
( \
LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \
- ( (((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset) )\
+ ((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset))\
);
#define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \
*((u8 *)(__pstart)) = EF1BYTE \
( \
LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) | \
- ( (((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset) ) \
+ ((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \
);
#define N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \
@@ -2359,18 +2361,18 @@ Set subfield of little-endian 4-byte value to specified value. */
mem access macro define end
****************************************/
-#define byte(x,n) ((x >> (8 * n)) & 0xff)
+#define byte(x, n) ((x >> (8 * n)) & 0xff)
#define packet_get_type(_packet) (EF1BYTE((_packet).octet[0]) & 0xFC)
-#define RTL_WATCH_DOG_TIME 2000
+#define RTL_WATCH_DOG_TIME 2000
#define MSECS(t) msecs_to_jiffies(t)
-#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS)
-#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
-#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
-#define WLAN_FC_MORE_DATA(fc) ((fc) & IEEE80211_FCTL_MOREDATA)
-#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
-#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
+#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS)
+#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
+#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
+#define WLAN_FC_MORE_DATA(fc) ((fc) & IEEE80211_FCTL_MOREDATA)
+#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
+#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
+#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
#define RT_RF_OFF_LEVL_ASPM BIT(0) /*PCI ASPM */
#define RT_RF_OFF_LEVL_CLK_REQ BIT(1) /*PCI clock request */
@@ -2383,7 +2385,7 @@ Set subfield of little-endian 4-byte value to specified value. */
#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT(6)
/* no matter RFOFF or SLEEP we set PS_ASPM_LEVL*/
#define RT_PS_LEVEL_ASPM BIT(7)
-/*When LPS is on, disable 2R if no packet is received or transmittd.*/
+/*When LPS is on, disable 2R if no packet is received or transmitted.*/
#define RT_RF_LPS_DISALBE_2R BIT(30)
#define RT_RF_LPS_LEVEL_ASPM BIT(31) /*LPS with ASPM */
#define RT_IN_PS_LEVEL(ppsc, _ps_flg) \
@@ -2397,13 +2399,13 @@ Set subfield of little-endian 4-byte value to specified value. */
container_of(container_of(x, struct delayed_work, work), y, z)
#define FILL_OCTET_STRING(_os,_octet,_len) \
- (_os).octet=(u8*)(_octet); \
- (_os).length=(_len);
+ (_os).octet = (u8 *)(_octet); \
+ (_os).length = (_len);
#define CP_MACADDR(des,src) \
- ((des)[0]=(src)[0],(des)[1]=(src)[1],\
- (des)[2]=(src)[2],(des)[3]=(src)[3],\
- (des)[4]=(src)[4],(des)[5]=(src)[5])
+ ((des)[0] = (src)[0],(des)[1] = (src)[1],\
+ (des)[2] = (src)[2],(des)[3] = (src)[3],\
+ (des)[4] = (src)[4],(des)[5] = (src)[5])
static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr)
{
diff --git a/drivers/staging/rts5139/ms.c b/drivers/staging/rts5139/ms.c
index 9253f6ab2e08..390292ad4566 100644
--- a/drivers/staging/rts5139/ms.c
+++ b/drivers/staging/rts5139/ms.c
@@ -1033,8 +1033,7 @@ static int ms_read_attribute_info(struct rts51x_chip *chip)
((u32) buf[cur_addr_off + 5] << 16) |
((u32) buf[cur_addr_off + 6] << 8) |
buf[cur_addr_off + 7];
- RTS51X_DEBUGP("sys_info_addr = 0x%x,"
- "sys_info_size = 0x%x\n",
+ RTS51X_DEBUGP("sys_info_addr = 0x%x, sys_info_size = 0x%x\n",
sys_info_addr, sys_info_size);
if (sys_info_size != 96) {
kfree(buf);
@@ -1069,8 +1068,7 @@ static int ms_read_attribute_info(struct rts51x_chip *chip)
((u32) buf[cur_addr_off + 5] << 16) |
((u32) buf[cur_addr_off + 6] << 8) |
buf[cur_addr_off + 7];
- RTS51X_DEBUGP("model_name_addr = 0x%x,"
- "model_name_size = 0x%x\n",
+ RTS51X_DEBUGP("model_name_addr = 0x%x, model_name_size = 0x%x\n",
model_name_addr, model_name_size);
if (model_name_size != 48) {
kfree(buf);
@@ -1751,8 +1749,7 @@ static int ms_copy_page(struct rts51x_chip *chip, u16 old_blk, u16 new_blk,
retval = ms_read_status_reg(chip);
if (retval != STATUS_SUCCESS) {
uncorrect_flag = 1;
- RTS51X_DEBUGP("Uncorrectable"
- "error\n");
+ RTS51X_DEBUGP("Uncorrectable error\n");
} else {
uncorrect_flag = 0;
}
@@ -1770,8 +1767,7 @@ static int ms_copy_page(struct rts51x_chip *chip, u16 old_blk, u16 new_blk,
ms_write_extra_data(chip, old_blk, i,
extra,
MS_EXTRA_SIZE);
- RTS51X_DEBUGP("page %d :"
- "extra[0] = 0x%x\n",
+ RTS51X_DEBUGP("page %d : extra[0] = 0x%x\n",
i, extra[0]);
MS_SET_BAD_BLOCK_FLG(ms_card);
@@ -1932,8 +1928,7 @@ static int ms_auto_copy_page(struct rts51x_chip *chip, u16 old_blk, u16 new_blk,
u8 page_len, bus_width, val = 0;
u8 extra[MS_EXTRA_SIZE];
- RTS51X_DEBUGP("Auto copy page from 0x%x to 0x%x,"
- "logical block is 0x%x\n",
+ RTS51X_DEBUGP("Auto copy page from 0x%x to 0x%x, logical block is 0x%x\n",
old_blk, new_blk, log_blk);
RTS51X_DEBUGP("start_page = %d, end_page = %d\n", start_page,
end_page);
@@ -2555,8 +2550,7 @@ static int ms_build_l2p_tbl(struct rts51x_chip *chip, int seg_no)
for (log_blk = 0; log_blk < 494; log_blk++) {
tmp_blk = segment->l2p_table[log_blk];
if (tmp_blk < ms_card->boot_block) {
- RTS51X_DEBUGP("Boot block is not the first"
- "normal block.\n");
+ RTS51X_DEBUGP("Boot block is not the first normal block.\n");
if (chip->card_wp & MS_CARD)
break;
@@ -3976,8 +3970,7 @@ static int rts51x_ms_rw_multi_sector(struct scsi_cmnd *srb, struct rts51x_chip *
end_page = start_page + (u8) total_sec_cnt;
page_cnt = end_page - start_page;
- RTS51X_DEBUGP("start_page = %d, end_page = %d,"
- "page_cnt = %d\n",
+ RTS51X_DEBUGP("start_page = %d, end_page = %d, page_cnt = %d\n",
start_page, end_page, page_cnt);
if (srb->sc_data_direction == DMA_FROM_DEVICE)
diff --git a/drivers/staging/rts5139/ms_mg.c b/drivers/staging/rts5139/ms_mg.c
index 54cfd85259a9..00862c1a36db 100644
--- a/drivers/staging/rts5139/ms_mg.c
+++ b/drivers/staging/rts5139/ms_mg.c
@@ -35,6 +35,7 @@
#include "rts51x_scsi.h"
#include "rts51x_card.h"
#include "ms.h"
+#include "ms_mg.h"
#ifdef SUPPORT_MAGIC_GATE
diff --git a/drivers/staging/rts5139/rts51x.c b/drivers/staging/rts5139/rts51x.c
index a8d2d046b44f..c8d06d4fddd2 100644
--- a/drivers/staging/rts5139/rts51x.c
+++ b/drivers/staging/rts5139/rts51x.c
@@ -215,7 +215,7 @@ void rts51x_try_to_exit_ss(struct rts51x_chip *chip)
* a USB port reset, whether from this driver or a different one.
*/
-int rts51x_pre_reset(struct usb_interface *iface)
+static int rts51x_pre_reset(struct usb_interface *iface)
{
struct rts51x_chip *chip = usb_get_intfdata(iface);
@@ -226,7 +226,7 @@ int rts51x_pre_reset(struct usb_interface *iface)
return 0;
}
-int rts51x_post_reset(struct usb_interface *iface)
+static int rts51x_post_reset(struct usb_interface *iface)
{
struct rts51x_chip *chip = usb_get_intfdata(iface);
@@ -832,7 +832,7 @@ static void rts51x_disconnect(struct usb_interface *intf)
* Initialization and registration
***********************************************************************/
-struct usb_device_id rts5139_usb_ids[] = {
+static struct usb_device_id rts5139_usb_ids[] = {
{USB_DEVICE(0x0BDA, 0x0139)},
{USB_DEVICE(0x0BDA, 0x0129)},
{} /* Terminating entry */
diff --git a/drivers/staging/rts5139/rts51x_fop.c b/drivers/staging/rts5139/rts51x_fop.c
index dee7d8af564e..677d18b3dcd5 100644
--- a/drivers/staging/rts5139/rts51x_fop.c
+++ b/drivers/staging/rts5139/rts51x_fop.c
@@ -93,7 +93,7 @@ static int rts51x_sd_direct_cmnd(struct rts51x_chip *chip,
}
retval =
- copy_to_user((void *)cmnd->buf, (void *)buf, cmnd->buf_len);
+ copy_to_user(cmnd->buf, (void *)buf, cmnd->buf_len);
if (retval) {
kfree(buf);
TRACE_RET(chip, STATUS_NOMEM);
@@ -109,7 +109,7 @@ static int rts51x_sd_direct_cmnd(struct rts51x_chip *chip,
TRACE_RET(chip, STATUS_NOMEM);
retval =
- copy_from_user((void *)buf, (void *)cmnd->buf,
+ copy_from_user((void *)buf, cmnd->buf,
cmnd->buf_len);
if (retval) {
kfree(buf);
@@ -154,7 +154,7 @@ static int rts51x_sd_get_rsp(struct rts51x_chip *chip, struct sd_rsp *rsp)
else
count = (rsp->rsp_len < 6) ? rsp->rsp_len : 6;
- retval = copy_to_user((void *)rsp->rsp, (void *)sd_card->rsp, count);
+ retval = copy_to_user(rsp->rsp, (void *)sd_card->rsp, count);
if (retval)
TRACE_RET(chip, STATUS_NOMEM);
@@ -250,7 +250,7 @@ long rts51x_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
switch (cmd) {
case RTS5139_IOC_SD_DIRECT:
retval =
- copy_from_user((void *)&cmnd, (void *)arg,
+ copy_from_user((void *)&cmnd, (void __user *)arg,
sizeof(struct sd_direct_cmnd));
if (retval) {
retval = -ENOMEM;
@@ -265,7 +265,7 @@ long rts51x_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
case RTS5139_IOC_SD_GET_RSP:
retval =
- copy_from_user((void *)&rsp, (void *)arg,
+ copy_from_user(&rsp, (void __user *)arg,
sizeof(struct sd_rsp));
if (retval) {
retval = -ENOMEM;
diff --git a/drivers/staging/rts5139/rts51x_fop.h b/drivers/staging/rts5139/rts51x_fop.h
index eb45acf50d1a..c691ee99720e 100644
--- a/drivers/staging/rts5139/rts51x_fop.h
+++ b/drivers/staging/rts5139/rts51x_fop.h
@@ -35,12 +35,12 @@
struct sd_direct_cmnd {
u8 cmnd[12];
- void *buf;
+ void __user *buf;
int buf_len;
};
struct sd_rsp {
- void *rsp;
+ void __user *rsp;
int rsp_len;
};
diff --git a/drivers/staging/rts5139/rts51x_scsi.c b/drivers/staging/rts5139/rts51x_scsi.c
index 3a990253c780..75282fea38f7 100644
--- a/drivers/staging/rts5139/rts51x_scsi.c
+++ b/drivers/staging/rts5139/rts51x_scsi.c
@@ -441,7 +441,7 @@ static int test_unit_ready(struct scsi_cmnd *srb, struct rts51x_chip *chip)
return TRANSPORT_GOOD;
}
-unsigned char formatter_inquiry_str[20] = {
+static unsigned char formatter_inquiry_str[20] = {
'M', 'E', 'M', 'O', 'R', 'Y', 'S', 'T', 'I', 'C', 'K',
'-', 'M', 'G', /* Byte[47:49] */
0x0B, /* Byte[50]: MG, MS, MSPro, MSXC */
@@ -1990,7 +1990,7 @@ static int show_info(struct seq_file *m, struct Scsi_Host *host)
/* queue a command */
/* This is always called with scsi_lock(host) held */
-int queuecommand_lck(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *))
+static int queuecommand_lck(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *))
{
struct rts51x_chip *chip = host_to_rts51x(srb->device->host);
diff --git a/drivers/staging/rts5139/rts51x_transport.c b/drivers/staging/rts5139/rts51x_transport.c
index c172f4ae7c23..74588d249b32 100644
--- a/drivers/staging/rts5139/rts51x_transport.c
+++ b/drivers/staging/rts5139/rts51x_transport.c
@@ -646,9 +646,9 @@ int rts51x_get_epc_status(struct rts51x_chip *chip, u16 *status)
chip->usb->intr_urb->actual_length);
}
-u8 media_not_present[] = {
+static u8 media_not_present[] = {
0x70, 0, 0x02, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0x3A, 0, 0, 0, 0, 0 };
-u8 invalid_cmd_field[] = {
+static u8 invalid_cmd_field[] = {
0x70, 0, 0x05, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0x24, 0, 0, 0, 0, 0 };
void rts51x_invoke_transport(struct scsi_cmnd *srb, struct rts51x_chip *chip)
diff --git a/drivers/staging/rts5139/sd.c b/drivers/staging/rts5139/sd.c
index 4283b0917f24..da5a9b8fb69c 100644
--- a/drivers/staging/rts5139/sd.c
+++ b/drivers/staging/rts5139/sd.c
@@ -1529,7 +1529,7 @@ static int sd_tuning_rx(struct rts51x_chip *chip)
int i, j;
u32 raw_phase_map[3], phase_map;
u8 final_phase;
- int (*tuning_cmd) (struct rts51x_chip *chip, u8 sample_point);
+ int (*tuning_cmd)(struct rts51x_chip *chip, u8 sample_point);
if (CHK_SD(sd_card)) {
if (CHK_SD_DDR50(sd_card))
@@ -1627,7 +1627,7 @@ static int sd_tuning_tx(struct rts51x_chip *chip)
int i, j;
u32 raw_phase_map[3], phase_map;
u8 final_phase;
- int (*tuning_cmd) (struct rts51x_chip *chip, u8 sample_point);
+ int (*tuning_cmd)(struct rts51x_chip *chip, u8 sample_point);
if (CHK_SD(sd_card)) {
if (CHK_SD_DDR50(sd_card))
diff --git a/drivers/staging/rts5139/sd_cprm.c b/drivers/staging/rts5139/sd_cprm.c
index d4689839e15a..cede6c07394f 100644
--- a/drivers/staging/rts5139/sd_cprm.c
+++ b/drivers/staging/rts5139/sd_cprm.c
@@ -35,6 +35,7 @@
#include "rts51x_scsi.h"
#include "rts51x_card.h"
#include "rts51x_chip.h"
+#include "sd_cprm.h"
#include "sd.h"
#ifdef SUPPORT_CPRM
diff --git a/drivers/staging/rts5139/xd.c b/drivers/staging/rts5139/xd.c
index 10fea7e16ace..be432351be86 100644
--- a/drivers/staging/rts5139/xd.c
+++ b/drivers/staging/rts5139/xd.c
@@ -473,7 +473,8 @@ static int reset_xd(struct rts51x_chip *chip)
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_DTCTL, 0xFF,
XD_TIME_SETUP_STEP * 3 + XD_TIME_RW_STEP *
(2 + i + chip->option.rts51x_xd_rw_step)
- + XD_TIME_RWN_STEP * (i + chip->option.rts51x_xd_rwn_step));
+ + XD_TIME_RWN_STEP *
+ (i + chip->option.rts51x_xd_rwn_step));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CATCTL, 0xFF,
XD_TIME_SETUP_STEP * 3 + XD_TIME_RW_STEP * (4 +
i) + XD_TIME_RWN_STEP * (3 + i));
@@ -1526,8 +1527,8 @@ static int xd_read_multiple_pages(struct rts51x_chip *chip, u32 phy_blk,
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS,
XD_AUTO_CHK_DATA_STATUS, XD_AUTO_CHK_DATA_STATUS);
- rts51x_trans_dma_enable(chip->srb->sc_data_direction, chip, page_cnt * 512,
- DMA_512);
+ rts51x_trans_dma_enable(chip->srb->sc_data_direction, chip,
+ page_cnt * 512, DMA_512);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_READ_PAGES);
@@ -1745,8 +1746,8 @@ static int xd_write_multiple_pages(struct rts51x_chip *chip, u32 old_blk,
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
RING_BUFFER);
- rts51x_trans_dma_enable(chip->srb->sc_data_direction, chip, page_cnt * 512,
- DMA_512);
+ rts51x_trans_dma_enable(chip->srb->sc_data_direction, chip,
+ page_cnt * 512, DMA_512);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_WRITE_PAGES);
@@ -1842,8 +1843,8 @@ static int xd_delay_write(struct rts51x_chip *chip)
return STATUS_SUCCESS;
}
-int rts51x_xd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
- u16 sector_cnt)
+int rts51x_xd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip,
+ u32 start_sector, u16 sector_cnt)
{
struct xd_info *xd_card = &(chip->xd_card);
unsigned int lun = SCSI_LUN(srb);
@@ -1883,7 +1884,8 @@ int rts51x_xd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sect
retval = xd_build_l2p_tbl(chip, zone_no);
if (retval != STATUS_SUCCESS) {
chip->card_fail |= XD_CARD;
- rts51x_set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ rts51x_set_sense_type(chip, lun,
+ SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, retval);
}
}
diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c
index edf979f18a6c..d22916a4b9d8 100644
--- a/drivers/staging/rts5208/ms.c
+++ b/drivers/staging/rts5208/ms.c
@@ -259,7 +259,7 @@ static int ms_read_bytes(struct rtsx_chip *chip,
MS_TRANSFER_END, MS_TRANSFER_END);
for (i = 0; i < data_len - 1; i++)
- rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0);
+ rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0);
if (data_len % 2)
rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len, 0, 0);
diff --git a/drivers/staging/rts5208/rtsx.c b/drivers/staging/rts5208/rtsx.c
index 8586ac5d2144..d2d1345fb06c 100644
--- a/drivers/staging/rts5208/rtsx.c
+++ b/drivers/staging/rts5208/rtsx.c
@@ -1031,8 +1031,10 @@ static void rtsx_remove(struct pci_dev *pci)
/* PCI IDs */
static DEFINE_PCI_DEVICE_TABLE(rtsx_ids) = {
- { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x5208), PCI_CLASS_OTHERS << 16, 0xFF0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x5288), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x5208),
+ PCI_CLASS_OTHERS << 16, 0xFF0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x5288),
+ PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ 0, },
};
diff --git a/drivers/staging/rts5208/rtsx_card.c b/drivers/staging/rts5208/rtsx_card.c
index 3055eb10c076..01aeb01bebe5 100644
--- a/drivers/staging/rts5208/rtsx_card.c
+++ b/drivers/staging/rts5208/rtsx_card.c
@@ -105,8 +105,10 @@ void try_to_switch_sdio_ctrl(struct rtsx_chip *chip)
RTSX_DEBUGP("reg 0xFF34: 0x%x, reg 0xFF38: 0x%x\n", reg1, reg2);
if ((reg1 & 0xC0) && (reg2 & 0xC0)) {
chip->sd_int = 1;
- rtsx_write_register(chip, SDIO_CTRL, 0xFF, SDIO_BUS_CTRL | SDIO_CD_CTRL);
- rtsx_write_register(chip, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_ON);
+ rtsx_write_register(chip, SDIO_CTRL, 0xFF,
+ SDIO_BUS_CTRL | SDIO_CD_CTRL);
+ rtsx_write_register(chip, PWR_GATE_CTRL,
+ LDO3318_PWR_MASK, LDO_ON);
}
}
@@ -452,7 +454,8 @@ void rtsx_reinit_cards(struct rtsx_chip *chip, int reset_chip)
}
#ifdef DISABLE_CARD_INT
-void card_cd_debounce(struct rtsx_chip *chip, unsigned long *need_reset, unsigned long *need_release)
+void card_cd_debounce(struct rtsx_chip *chip, unsigned long *need_reset,
+ unsigned long *need_release)
{
u8 release_map = 0, reset_map = 0;
@@ -504,11 +507,14 @@ void card_cd_debounce(struct rtsx_chip *chip, unsigned long *need_reset, unsigne
}
reset_map = 0;
- if (!(chip->card_exist & XD_CARD) && (xd_cnt > (DEBOUNCE_CNT-1)))
+ if (!(chip->card_exist & XD_CARD) &&
+ (xd_cnt > (DEBOUNCE_CNT-1)))
reset_map |= XD_CARD;
- if (!(chip->card_exist & SD_CARD) && (sd_cnt > (DEBOUNCE_CNT-1)))
+ if (!(chip->card_exist & SD_CARD) &&
+ (sd_cnt > (DEBOUNCE_CNT-1)))
reset_map |= SD_CARD;
- if (!(chip->card_exist & MS_CARD) && (ms_cnt > (DEBOUNCE_CNT-1)))
+ if (!(chip->card_exist & MS_CARD) &&
+ (ms_cnt > (DEBOUNCE_CNT-1)))
reset_map |= MS_CARD;
}
@@ -549,7 +555,8 @@ void rtsx_init_cards(struct rtsx_chip *chip)
if (!(chip->card_exist & MS_CARD))
clear_bit(MS_NR, &(chip->need_release));
- RTSX_DEBUGP("chip->need_release = 0x%x\n", (unsigned int)(chip->need_release));
+ RTSX_DEBUGP("chip->need_release = 0x%x\n",
+ (unsigned int)(chip->need_release));
#ifdef SUPPORT_OCP
if (chip->need_release) {
@@ -588,8 +595,10 @@ void rtsx_init_cards(struct rtsx_chip *chip)
release_xd_card(chip);
- if (CHECK_PID(chip, 0x5288) && CHECK_BARO_PKG(chip, QFN))
- rtsx_write_register(chip, HOST_SLEEP_STATE, 0xC0, 0xC0);
+ if (CHECK_PID(chip, 0x5288) &&
+ CHECK_BARO_PKG(chip, QFN))
+ rtsx_write_register(chip, HOST_SLEEP_STATE,
+ 0xC0, 0xC0);
}
if (chip->need_release & MS_CARD) {
@@ -610,13 +619,15 @@ void rtsx_init_cards(struct rtsx_chip *chip)
}
if (chip->need_reset) {
- RTSX_DEBUGP("chip->need_reset = 0x%x\n", (unsigned int)(chip->need_reset));
+ RTSX_DEBUGP("chip->need_reset = 0x%x\n",
+ (unsigned int)(chip->need_reset));
rtsx_reset_cards(chip);
}
if (chip->need_reinit) {
- RTSX_DEBUGP("chip->need_reinit = 0x%x\n", (unsigned int)(chip->need_reinit));
+ RTSX_DEBUGP("chip->need_reinit = 0x%x\n",
+ (unsigned int)(chip->need_reinit));
rtsx_reinit_cards(chip, 0);
}
@@ -624,7 +635,7 @@ void rtsx_init_cards(struct rtsx_chip *chip)
static inline u8 double_depth(u8 depth)
{
- return ((depth > 1) ? (depth - 1) : depth);
+ return (depth > 1) ? (depth - 1) : depth;
}
int switch_ssc_clock(struct rtsx_chip *chip, int clk)
@@ -641,7 +652,8 @@ int switch_ssc_clock(struct rtsx_chip *chip, int clk)
max_N = 120;
max_div = CLK_DIV_4;
- RTSX_DEBUGP("Switch SSC clock to %dMHz (cur_clk = %d)\n", clk, chip->cur_clk);
+ RTSX_DEBUGP("Switch SSC clock to %dMHz (cur_clk = %d)\n",
+ clk, chip->cur_clk);
if ((clk <= 2) || (N > max_N))
TRACE_RET(chip, STATUS_FAIL);
@@ -676,8 +688,10 @@ int switch_ssc_clock(struct rtsx_chip *chip, int clk)
rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, N);
rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
if (sd_vpclk_phase_reset) {
- rtsx_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
- rtsx_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET);
+ rtsx_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL,
+ PHASE_NOT_RESET, 0);
+ rtsx_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL,
+ PHASE_NOT_RESET, PHASE_NOT_RESET);
}
retval = rtsx_send_cmd(chip, 0, WAIT_TIME);
@@ -786,8 +800,10 @@ int switch_normal_clock(struct rtsx_chip *chip, int clk)
if (sd_vpclk_phase_reset) {
udelay(200);
- RTSX_WRITE_REG(chip, SD_VPCLK0_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET);
- RTSX_WRITE_REG(chip, SD_VPCLK1_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET);
+ RTSX_WRITE_REG(chip, SD_VPCLK0_CTL, PHASE_NOT_RESET,
+ PHASE_NOT_RESET);
+ RTSX_WRITE_REG(chip, SD_VPCLK1_CTL, PHASE_NOT_RESET,
+ PHASE_NOT_RESET);
udelay(200);
}
RTSX_WRITE_REG(chip, CLK_CTL, 0xFF, 0);
@@ -797,7 +813,8 @@ int switch_normal_clock(struct rtsx_chip *chip, int clk)
return STATUS_SUCCESS;
}
-void trans_dma_enable(enum dma_data_direction dir, struct rtsx_chip *chip, u32 byte_cnt, u8 pack_size)
+void trans_dma_enable(enum dma_data_direction dir, struct rtsx_chip *chip,
+ u32 byte_cnt, u8 pack_size)
{
if (pack_size > DMA_1024)
pack_size = DMA_512;
@@ -810,10 +827,12 @@ void trans_dma_enable(enum dma_data_direction dir, struct rtsx_chip *chip, u32 b
rtsx_add_cmd(chip, WRITE_REG_CMD, DMATC0, 0xFF, (u8)byte_cnt);
if (dir == DMA_FROM_DEVICE) {
- rtsx_add_cmd(chip, WRITE_REG_CMD, DMACTL, 0x03 | DMA_PACK_SIZE_MASK,
+ rtsx_add_cmd(chip, WRITE_REG_CMD, DMACTL,
+ 0x03 | DMA_PACK_SIZE_MASK,
DMA_DIR_FROM_CARD | DMA_EN | pack_size);
} else {
- rtsx_add_cmd(chip, WRITE_REG_CMD, DMACTL, 0x03 | DMA_PACK_SIZE_MASK,
+ rtsx_add_cmd(chip, WRITE_REG_CMD, DMACTL,
+ 0x03 | DMA_PACK_SIZE_MASK,
DMA_DIR_TO_CARD | DMA_EN | pack_size);
}
@@ -903,7 +922,8 @@ int card_power_off(struct rtsx_chip *chip, u8 card)
return STATUS_SUCCESS;
}
-int card_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 sec_addr, u16 sec_cnt)
+int card_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip,
+ u32 sec_addr, u16 sec_cnt)
{
int retval;
unsigned int lun = SCSI_LUN(srb);
@@ -921,7 +941,8 @@ int card_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 sec_addr, u16 sec
rtsx_release_chip(chip);
TRACE_RET(chip, STATUS_FAIL);
}
- if (detect_card_cd(chip, chip->cur_card) != STATUS_SUCCESS)
+ if (detect_card_cd(chip, chip->cur_card) !=
+ STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
if (!chip->rw_need_retry) {
@@ -1016,7 +1037,8 @@ void toggle_gpio(struct rtsx_chip *chip, u8 gpio)
void turn_on_led(struct rtsx_chip *chip, u8 gpio)
{
if (CHECK_PID(chip, 0x5288))
- rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), (u8)(1 << gpio));
+ rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio),
+ (u8)(1 << gpio));
else
rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), 0);
}
@@ -1026,7 +1048,8 @@ void turn_off_led(struct rtsx_chip *chip, u8 gpio)
if (CHECK_PID(chip, 0x5288))
rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), 0);
else
- rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), (u8)(1 << gpio));
+ rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio),
+ (u8)(1 << gpio));
}
int detect_card_cd(struct rtsx_chip *chip, int card)
diff --git a/drivers/staging/rts5208/rtsx_scsi.c b/drivers/staging/rts5208/rtsx_scsi.c
index 382e73a54f4d..bbfa665c5c99 100644
--- a/drivers/staging/rts5208/rtsx_scsi.c
+++ b/drivers/staging/rts5208/rtsx_scsi.c
@@ -2867,7 +2867,7 @@ static int get_ms_information(struct scsi_cmnd *srb, struct rtsx_chip *chip)
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
- if ((get_lun_card(chip, lun) != MS_CARD)) {
+ if (get_lun_card(chip, lun) != MS_CARD) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
@@ -2983,7 +2983,7 @@ static int sd_extention_cmnd(struct scsi_cmnd *srb, struct rtsx_chip *chip)
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
- if ((get_lun_card(chip, lun) != SD_CARD)) {
+ if (get_lun_card(chip, lun) != SD_CARD) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
@@ -3046,7 +3046,7 @@ static int mg_report_key(struct scsi_cmnd *srb, struct rtsx_chip *chip)
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
- if ((get_lun_card(chip, lun) != MS_CARD)) {
+ if (get_lun_card(chip, lun) != MS_CARD) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
@@ -3151,7 +3151,7 @@ static int mg_send_key(struct scsi_cmnd *srb, struct rtsx_chip *chip)
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_PROTECT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
- if ((get_lun_card(chip, lun) != MS_CARD)) {
+ if (get_lun_card(chip, lun) != MS_CARD) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
diff --git a/drivers/staging/rts5208/rtsx_transport.c b/drivers/staging/rts5208/rtsx_transport.c
index 97b7b012983e..694d3834962c 100644
--- a/drivers/staging/rts5208/rtsx_transport.c
+++ b/drivers/staging/rts5208/rtsx_transport.c
@@ -625,8 +625,8 @@ out:
return err;
}
-static int rtsx_transfer_buf(struct rtsx_chip *chip, u8 card, void *buf, size_t len,
- enum dma_data_direction dma_dir, int timeout)
+static int rtsx_transfer_buf(struct rtsx_chip *chip, u8 card, void *buf,
+ size_t len, enum dma_data_direction dma_dir, int timeout)
{
struct rtsx_dev *rtsx = chip->rtsx;
struct completion trans_done;
diff --git a/drivers/staging/sb105x/Kconfig b/drivers/staging/sb105x/Kconfig
deleted file mode 100644
index 245e7847a354..000000000000
--- a/drivers/staging/sb105x/Kconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-config SB105X
- tristate "SystemBase PCI Multiport UART"
- select SERIAL_CORE
- depends on PCI && X86 && TTY && BROKEN
- help
- A driver for the SystemBase Multi-2/PCI serial card
-
- To compile this driver a module, choose M here: the module
- will be called "sb105x".
diff --git a/drivers/staging/sb105x/Makefile b/drivers/staging/sb105x/Makefile
deleted file mode 100644
index b1bf3779acae..000000000000
--- a/drivers/staging/sb105x/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_SB105X) += sb105x.o
-
-sb105x-y := sb_pci_mp.o
diff --git a/drivers/staging/sb105x/sb_mp_register.h b/drivers/staging/sb105x/sb_mp_register.h
deleted file mode 100644
index 276c1bbcc18d..000000000000
--- a/drivers/staging/sb105x/sb_mp_register.h
+++ /dev/null
@@ -1,295 +0,0 @@
-
-/*
- * SB105X_UART.h
- *
- * Copyright (C) 2008 systembase
- *
- * UART registers.
- *
- * This program is free software; 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 UART_SB105X_H
-#define UART_SB105X_H
-
-/*
- * option register
- */
-
-/* Device Information Register */
-#define MP_OPTR_DIR0 0x04 /* port0 ~ port8 */
-#define MP_OPTR_DIR1 0x05 /* port8 ~ port15 */
-#define MP_OPTR_DIR2 0x06 /* port16 ~ port23 */
-#define MP_OPTR_DIR3 0x07 /* port24 ~ port31 */
-
-#define DIR_UART_16C550 0
-#define DIR_UART_16C1050 1
-#define DIR_UART_16C1050A 2
-
-#define DIR_CLK_1843200 0x0 /* input clock 1843200 Hz */
-#define DIR_CLK_3686400 0x1 /* input clock 3686400 Hz */
-#define DIR_CLK_7372800 0x2 /* input clock 7372800 Hz */
-#define DIR_CLK_14745600 0x3 /* input clock 14745600 Hz */
-#define DIR_CLK_29491200 0x4 /* input clock 29491200 Hz */
-#define DIR_CLK_58985400 0x5 /* input clock 58985400 Hz */
-
-/* Interface Information Register */
-#define MP_OPTR_IIR0 0x08 /* port0 ~ port8 */
-#define MP_OPTR_IIR1 0x09 /* port8 ~ port15 */
-#define MP_OPTR_IIR2 0x0A /* port16 ~ port23 */
-#define MP_OPTR_IIR3 0x0B /* port24 ~ port31 */
-
-#define IIR_RS232 0x00 /* RS232 type */
-#define IIR_RS422 0x10 /* RS422 type */
-#define IIR_RS485 0x20 /* RS485 type */
-#define IIR_TYPE_MASK 0x30
-
-/* Interrupt Mask Register */
-#define MP_OPTR_IMR0 0x0C /* port0 ~ port8 */
-#define MP_OPTR_IMR1 0x0D /* port8 ~ port15 */
-#define MP_OPTR_IMR2 0x0E /* port16 ~ port23 */
-#define MP_OPTR_IMR3 0x0F /* port24 ~ port31 */
-
-/* Interrupt Poll Register */
-#define MP_OPTR_IPR0 0x10 /* port0 ~ port8 */
-#define MP_OPTR_IPR1 0x11 /* port8 ~ port15 */
-#define MP_OPTR_IPR2 0x12 /* port16 ~ port23 */
-#define MP_OPTR_IPR3 0x13 /* port24 ~ port31 */
-
-/* General Purpose Output Control Register */
-#define MP_OPTR_GPOCR 0x20
-
-/* General Purpose Output Data Register */
-#define MP_OPTR_GPODR 0x21
-
-/* Parallel Additional Function Register */
-#define MP_OPTR_PAFR 0x23
-
-/*
- * systembase 16c105x UART register
- */
-
-#define PAGE_0 0
-#define PAGE_1 1
-#define PAGE_2 2
-#define PAGE_3 3
-#define PAGE_4 4
-
-/*
- * ******************************************************************
- * * DLAB=0 =============== Page 0 Registers *
- * ******************************************************************
- */
-
-#define SB105X_RX 0 /* In: Receive buffer */
-#define SB105X_TX 0 /* Out: Transmit buffer */
-
-#define SB105X_IER 1 /* Out: Interrupt Enable Register */
-
-#define SB105X_IER_CTSI 0x80 /* CTS# Interrupt Enable (Requires EFR[4] = 1) */
-#define SB105X_IER_RTSI 0x40 /* RTS# Interrupt Enable (Requires EFR[4] = 1) */
-#define SB105X_IER_XOI 0x20 /* Xoff Interrupt Enable (Requires EFR[4] = 1) */
-#define SB105X_IER_SME 0x10 /* Sleep Mode Enable (Requires EFR[4] = 1) */
-#define SB105X_IER_MSI 0x08 /* Enable Modem status interrupt */
-#define SB105X_IER_RLSI 0x04 /* Enable receiver line status interrupt */
-#define SB105X_IER_THRI 0x02 /* Enable Transmitter holding register int. */
-#define SB105X_IER_RDI 0x01 /* Enable receiver data interrupt */
-
-#define SB105X_ISR 2 /* In: Interrupt ID Register */
-
-#define SB105X_ISR_NOINT 0x01 /* No interrupts pending */
-#define SB105X_ISR_RLSI 0x06 /* Receiver line status interrupt (Priority = 1)*/
-#define SB105X_ISR_RDAI 0x0c /* Receive Data Available interrupt */
-#define SB105X_ISR_CTII 0x04 /* Character Timeout Indication interrupt */
-#define SB105X_ISR_THRI 0x02 /* Transmitter holding register empty */
-#define SB105X_ISR_MSI 0x00 /* Modem status interrupt */
-#define SB105X_ISR_RXCI 0x10 /* Receive Xoff or Special Character interrupt */
-#define SB105X_ISR_RCSI 0x20 /* RTS#, CTS# status interrupt during Auto RTS/CTS flow control */
-
-#define SB105X_FCR 2 /* Out: FIFO Control Register */
-
-#define SB105X_FCR_FEN 0x01 /* FIFO Enable */
-#define SB105X_FCR_RXFR 0x02 /* RX FIFO Reset */
-#define SB105X_FCR_TXFR 0x04 /* TX FIFO Reset */
-#define SB105X_FCR_DMS 0x08 /* DMA Mode Select */
-
-#define SB105X_FCR_RTR08 0x00 /* Receive Trigger Level set at 8 */
-#define SB105X_FCR_RTR16 0x40 /* Receive Trigger Level set at 16 */
-#define SB105X_FCR_RTR56 0x80 /* Receive Trigger Level set at 56 */
-#define SB105X_FCR_RTR60 0xc0 /* Receive Trigger Level set at 60 */
-#define SB105X_FCR_TTR08 0x00 /* Transmit Trigger Level set at 8 */
-#define SB105X_FCR_TTR16 0x10 /* Transmit Trigger Level set at 16 */
-#define SB105X_FCR_TTR32 0x20 /* Transmit Trigger Level set at 32 */
-#define SB105X_FCR_TTR56 0x30 /* Transmit Trigger Level set at 56 */
-
-#define SB105X_LCR 3 /* Out: Line Control Register */
-/*
- * * Note: if the word length is 5 bits (SB105X_LCR_WLEN5), then setting
- * * SB105X_LCR_STOP will select 1.5 stop bits, not 2 stop bits.
- */
-#define SB105X_LCR_DLAB 0x80 /* Divisor Latch Enable */
-#define SB105X_LCR_SBC 0x40 /* Break Enable*/
-#define SB105X_LCR_SPAR 0x20 /* Set Stick parity */
-#define SB105X_LCR_EPAR 0x10 /* Even parity select */
-#define SB105X_LCR_PAREN 0x08 /* Parity Enable */
-#define SB105X_LCR_STOP 0x04 /* Stop bits: 0->1 bit, 1->2 bits, 1 and SB105X_LCR_WLEN5 -> 1.5 bit */
-#define SB105X_LCR_WLEN5 0x00 /* Wordlength: 5 bits */
-#define SB105X_LCR_WLEN6 0x01 /* Wordlength: 6 bits */
-#define SB105X_LCR_WLEN7 0x02 /* Wordlength: 7 bits */
-#define SB105X_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
-
-#define SB105X_LCR_BF 0xBF
-
-#define SB105X_MCR 4 /* Out: Modem Control Register */
-#define SB105X_MCR_CPS 0x80 /* Clock Prescaler Select */
-#define SB105X_MCR_P2S 0x40 /* Page 2 Select /Xoff Re-Transmit Access Enable */
-#define SB105X_MCR_XOA 0x20 /* Xon Any Enable */
-#define SB105X_MCR_ILB 0x10 /* Internal Loopback Enable */
-#define SB105X_MCR_OUT2 0x08 /* Out2/Interrupt Output Enable*/
-#define SB105X_MCR_OUT1 0x04 /* Out1/Interrupt Output Enable */
-#define SB105X_MCR_RTS 0x02 /* RTS# Output */
-#define SB105X_MCR_DTR 0x01 /* DTR# Output */
-
-#define SB105X_LSR 5 /* In: Line Status Register */
-#define SB105X_LSR_RFEI 0x80 /* Receive FIFO data error Indicator */
-#define SB105X_LSR_TEMI 0x40 /* THR and TSR Empty Indicator */
-#define SB105X_LSR_THRE 0x20 /* THR Empty Indicator */
-#define SB105X_LSR_BII 0x10 /* Break interrupt indicator */
-#define SB105X_LSR_FEI 0x08 /* Frame error indicator */
-#define SB105X_LSR_PEI 0x04 /* Parity error indicator */
-#define SB105X_LSR_OEI 0x02 /* Overrun error indicator */
-#define SB105X_LSR_RDRI 0x01 /* Receive data ready Indicator*/
-
-#define SB105X_MSR 6 /* In: Modem Status Register */
-#define SB105X_MSR_DCD 0x80 /* Data Carrier Detect */
-#define SB105X_MSR_RI 0x40 /* Ring Indicator */
-#define SB105X_MSR_DSR 0x20 /* Data Set Ready */
-#define SB105X_MSR_CTS 0x10 /* Clear to Send */
-#define SB105X_MSR_DDCD 0x08 /* Delta DCD */
-#define SB105X_MSR_DRI 0x04 /* Delta ring indicator */
-#define SB105X_MSR_DDSR 0x02 /* Delta DSR */
-#define SB105X_MSR_DCTS 0x01 /* Delta CTS */
-
-#define SB105XA_MDR 6 /* Out: Multi Drop mode Register */
-#define SB105XA_MDR_NPS 0x08 /* 9th Bit Polarity Select */
-#define SB105XA_MDR_AME 0x02 /* Auto Multi-drop Enable */
-#define SB105XA_MDR_MDE 0x01 /* Multi Drop Enable */
-
-#define SB105X_SPR 7 /* I/O: Scratch Register */
-
-/*
- * DLAB=1
- */
-#define SB105X_DLL 0 /* Out: Divisor Latch Low */
-#define SB105X_DLM 1 /* Out: Divisor Latch High */
-
-/*
- * ******************************************************************
- * * DLAB(LCR[7]) = 0 , MCR[6] = 1 ============= Page 2 Registers *
- * ******************************************************************
- */
-#define SB105X_GICR 1 /* Global Interrupt Control Register */
-#define SB105X_GICR_GIM 0x01 /* Global Interrupt Mask */
-
-#define SB105X_GISR 2 /* Global Interrupt Status Register */
-#define SB105X_GISR_MGICR0 0x80 /* Mirror the content of GICR[0] */
-#define SB105X_GISR_CS3IS 0x08 /* SB105X of CS3# Interrupt Status */
-#define SB105X_GISR_CS2IS 0x04 /* SB105X of CS2# Interrupt Status */
-#define SB105X_GISR_CS1IS 0x02 /* SB105X of CS1# Interrupt Status */
-#define SB105X_GISR_CS0IS 0x01 /* SB105X of CS0# Interrupt Status */
-
-#define SB105X_TFCR 5 /* Transmit FIFO Count Register */
-
-#define SB105X_RFCR 6 /* Receive FIFO Count Register */
-
-#define SB105X_FSR 7 /* Flow Control Status Register */
-#define SB105X_FSR_THFS 0x20 /* Transmit Hardware Flow Control Status */
-#define SB105X_FSR_TSFS 0x10 /* Transmit Software Flow Control Status */
-#define SB105X_FSR_RHFS 0x02 /* Receive Hardware Flow Control Status */
-#define SB105X_FSR_RSFS 0x01 /* Receive Software Flow Control Status */
-
-/*
- * ******************************************************************
- * * LCR = 0xBF, PSR[0] = 0 ============= Page 3 Registers *
- * ******************************************************************
- */
-
-#define SB105X_PSR 0 /* Page Select Register */
-#define SB105X_PSR_P3KEY 0xA4 /* Page 3 Select Key */
-#define SB105X_PSR_P4KEY 0xA5 /* Page 5 Select Key */
-
-#define SB105X_ATR 1 /* Auto Toggle Control Register */
-#define SB105X_ATR_RPS 0x80 /* RXEN Polarity Select */
-#define SB105X_ATR_RCMS 0x40 /* RXEN Control Mode Select */
-#define SB105X_ATR_TPS 0x20 /* TXEN Polarity Select */
-#define SB105X_ATR_TCMS 0x10 /* TXEN Control Mode Select */
-#define SB105X_ATR_ATDIS 0x00 /* Auto Toggle is disabled */
-#define SB105X_ATR_ART 0x01 /* RTS#/TXEN pin operates as TXEN */
-#define SB105X_ATR_ADT 0x02 /* DTR#/TXEN pin operates as TXEN */
-#define SB105X_ATR_A80 0x03 /* only in 80 pin use */
-
-#define SB105X_EFR 2 /* (Auto) Enhanced Feature Register */
-#define SB105X_EFR_ACTS 0x80 /* Auto-CTS Flow Control Enable */
-#define SB105X_EFR_ARTS 0x40 /* Auto-RTS Flow Control Enable */
-#define SB105X_EFR_SCD 0x20 /* Special Character Detect */
-#define SB105X_EFR_EFBEN 0x10 /* Enhanced Function Bits Enable */
-
-#define SB105X_XON1 4 /* Xon1 Character Register */
-#define SB105X_XON2 5 /* Xon2 Character Register */
-#define SB105X_XOFF1 6 /* Xoff1 Character Register */
-#define SB105X_XOFF2 7 /* Xoff2 Character Register */
-
-/*
- * ******************************************************************
- * * LCR = 0xBF, PSR[0] = 1 ============ Page 4 Registers *
- * ******************************************************************
- */
-
-#define SB105X_AFR 1 /* Additional Feature Register */
-#define SB105X_AFR_GIPS 0x20 /* Global Interrupt Polarity Select */
-#define SB105X_AFR_GIEN 0x10 /* Global Interrupt Enable */
-#define SB105X_AFR_AFEN 0x01 /* 256-byte FIFO Enable */
-
-#define SB105X_XRCR 2 /* Xoff Re-transmit Count Register */
-#define SB105X_XRCR_NRC1 0x00 /* Transmits Xoff Character whenever the number of received data is 1 during XOFF status */
-#define SB105X_XRCR_NRC4 0x01 /* Transmits Xoff Character whenever the number of received data is 4 during XOFF status */
-#define SB105X_XRCR_NRC8 0x02 /* Transmits Xoff Character whenever the number of received data is 8 during XOFF status */
-#define SB105X_XRCR_NRC16 0x03 /* Transmits Xoff Character whenever the number of received data is 16 during XOFF status */
-
-#define SB105X_TTR 4 /* Transmit FIFO Trigger Level Register */
-#define SB105X_RTR 5 /* Receive FIFO Trigger Level Register */
-#define SB105X_FUR 6 /* Flow Control Upper Threshold Register */
-#define SB105X_FLR 7 /* Flow Control Lower Threshold Register */
-
-
-/* page 0 */
-
-#define SB105X_GET_CHAR(port) inb((port)->iobase + SB105X_RX)
-#define SB105X_GET_IER(port) inb((port)->iobase + SB105X_IER)
-#define SB105X_GET_ISR(port) inb((port)->iobase + SB105X_ISR)
-#define SB105X_GET_LCR(port) inb((port)->iobase + SB105X_LCR)
-#define SB105X_GET_MCR(port) inb((port)->iobase + SB105X_MCR)
-#define SB105X_GET_LSR(port) inb((port)->iobase + SB105X_LSR)
-#define SB105X_GET_MSR(port) inb((port)->iobase + SB105X_MSR)
-#define SB105X_GET_SPR(port) inb((port)->iobase + SB105X_SPR)
-
-#define SB105X_PUT_CHAR(port,v) outb((v),(port)->iobase + SB105X_TX )
-#define SB105X_PUT_IER(port,v) outb((v),(port)->iobase + SB105X_IER )
-#define SB105X_PUT_FCR(port,v) outb((v),(port)->iobase + SB105X_FCR )
-#define SB105X_PUT_LCR(port,v) outb((v),(port)->iobase + SB105X_LCR )
-#define SB105X_PUT_MCR(port,v) outb((v),(port)->iobase + SB105X_MCR )
-#define SB105X_PUT_SPR(port,v) outb((v),(port)->iobase + SB105X_SPR )
-
-
-/* page 1 */
-#define SB105X_GET_REG(port,reg) inb((port)->iobase + (reg))
-#define SB105X_PUT_REG(port,reg,v) outb((v),(port)->iobase + (reg))
-
-/* page 2 */
-
-#define SB105X_PUT_PSR(port,v) outb((v),(port)->iobase + SB105X_PSR )
-
-#endif
diff --git a/drivers/staging/sb105x/sb_pci_mp.c b/drivers/staging/sb105x/sb_pci_mp.c
deleted file mode 100644
index c9d6ee3903ad..000000000000
--- a/drivers/staging/sb105x/sb_pci_mp.c
+++ /dev/null
@@ -1,3189 +0,0 @@
-#include "sb_pci_mp.h"
-#include <linux/module.h>
-#include <linux/parport.h>
-
-extern struct parport *parport_pc_probe_port(unsigned long base_lo,
- unsigned long base_hi,
- int irq, int dma,
- struct device *dev,
- int irqflags);
-
-static struct mp_device_t mp_devs[MAX_MP_DEV];
-static int mp_nrpcibrds = sizeof(mp_pciboards)/sizeof(mppcibrd_t);
-static int NR_BOARD=0;
-static int NR_PORTS=0;
-static struct mp_port multi_ports[MAX_MP_PORT];
-static struct irq_info irq_lists[NR_IRQS];
-
-static _INLINE_ unsigned int serial_in(struct mp_port *mtpt, int offset);
-static _INLINE_ void serial_out(struct mp_port *mtpt, int offset, int value);
-static _INLINE_ unsigned int read_option_register(struct mp_port *mtpt, int offset);
-static int sb1054_get_register(struct sb_uart_port *port, int page, int reg);
-static int sb1054_set_register(struct sb_uart_port *port, int page, int reg, int value);
-static void SendATCommand(struct mp_port *mtpt);
-static int set_deep_fifo(struct sb_uart_port *port, int status);
-static int get_deep_fifo(struct sb_uart_port *port);
-static int get_device_type(int arg);
-static int set_auto_rts(struct sb_uart_port *port, int status);
-static void mp_stop(struct tty_struct *tty);
-static void __mp_start(struct tty_struct *tty);
-static void mp_start(struct tty_struct *tty);
-static void mp_tasklet_action(unsigned long data);
-static inline void mp_update_mctrl(struct sb_uart_port *port, unsigned int set, unsigned int clear);
-static int mp_startup(struct sb_uart_state *state, int init_hw);
-static void mp_shutdown(struct sb_uart_state *state);
-static void mp_change_speed(struct sb_uart_state *state, struct MP_TERMIOS *old_termios);
-
-static inline int __mp_put_char(struct sb_uart_port *port, struct circ_buf *circ, unsigned char c);
-static int mp_put_char(struct tty_struct *tty, unsigned char ch);
-
-static void mp_put_chars(struct tty_struct *tty);
-static int mp_write(struct tty_struct *tty, const unsigned char *buf, int count);
-static int mp_write_room(struct tty_struct *tty);
-static int mp_chars_in_buffer(struct tty_struct *tty);
-static void mp_flush_buffer(struct tty_struct *tty);
-static void mp_send_xchar(struct tty_struct *tty, char ch);
-static void mp_throttle(struct tty_struct *tty);
-static void mp_unthrottle(struct tty_struct *tty);
-static int mp_get_info(struct sb_uart_state *state, struct serial_struct *retinfo);
-static int mp_set_info(struct sb_uart_state *state, struct serial_struct *newinfo);
-static int mp_get_lsr_info(struct sb_uart_state *state, unsigned int *value);
-
-static int mp_tiocmget(struct tty_struct *tty);
-static int mp_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear);
-static int mp_break_ctl(struct tty_struct *tty, int break_state);
-static int mp_do_autoconfig(struct sb_uart_state *state);
-static int mp_wait_modem_status(struct sb_uart_state *state, unsigned long arg);
-static int mp_get_count(struct sb_uart_state *state, struct serial_icounter_struct *icnt);
-static int mp_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
-static void mp_set_termios(struct tty_struct *tty, struct MP_TERMIOS *old_termios);
-static void mp_close(struct tty_struct *tty, struct file *filp);
-static void mp_wait_until_sent(struct tty_struct *tty, int timeout);
-static void mp_hangup(struct tty_struct *tty);
-static void mp_update_termios(struct sb_uart_state *state);
-static int mp_block_til_ready(struct file *filp, struct sb_uart_state *state);
-static struct sb_uart_state *uart_get(struct uart_driver *drv, int line);
-static int mp_open(struct tty_struct *tty, struct file *filp);
-static const char *mp_type(struct sb_uart_port *port);
-static void mp_change_pm(struct sb_uart_state *state, int pm_state);
-static inline void mp_report_port(struct uart_driver *drv, struct sb_uart_port *port);
-static void mp_configure_port(struct uart_driver *drv, struct sb_uart_state *state, struct sb_uart_port *port);
-static void mp_unconfigure_port(struct uart_driver *drv, struct sb_uart_state *state);
-static int mp_register_driver(struct uart_driver *drv);
-static void mp_unregister_driver(struct uart_driver *drv);
-static int mp_add_one_port(struct uart_driver *drv, struct sb_uart_port *port);
-static int mp_remove_one_port(struct uart_driver *drv, struct sb_uart_port *port);
-static void autoconfig(struct mp_port *mtpt, unsigned int probeflags);
-static void autoconfig_irq(struct mp_port *mtpt);
-static void multi_stop_tx(struct sb_uart_port *port);
-static void multi_start_tx(struct sb_uart_port *port);
-static void multi_stop_rx(struct sb_uart_port *port);
-static void multi_enable_ms(struct sb_uart_port *port);
-static _INLINE_ void receive_chars(struct mp_port *mtpt, int *status );
-static _INLINE_ void transmit_chars(struct mp_port *mtpt);
-static _INLINE_ void check_modem_status(struct mp_port *mtpt);
-static inline void multi_handle_port(struct mp_port *mtpt);
-static irqreturn_t multi_interrupt(int irq, void *dev_id);
-static void serial_do_unlink(struct irq_info *i, struct mp_port *mtpt);
-static int serial_link_irq_chain(struct mp_port *mtpt);
-static void serial_unlink_irq_chain(struct mp_port *mtpt);
-static void multi_timeout(unsigned long data);
-static unsigned int multi_tx_empty(struct sb_uart_port *port);
-static unsigned int multi_get_mctrl(struct sb_uart_port *port);
-static void multi_set_mctrl(struct sb_uart_port *port, unsigned int mctrl);
-static void multi_break_ctl(struct sb_uart_port *port, int break_state);
-static int multi_startup(struct sb_uart_port *port);
-static void multi_shutdown(struct sb_uart_port *port);
-static unsigned int multi_get_divisor(struct sb_uart_port *port, unsigned int baud);
-static void multi_set_termios(struct sb_uart_port *port, struct MP_TERMIOS *termios, struct MP_TERMIOS *old);
-static void multi_pm(struct sb_uart_port *port, unsigned int state, unsigned int oldstate);
-static void multi_release_std_resource(struct mp_port *mtpt);
-static void multi_release_port(struct sb_uart_port *port);
-static int multi_request_port(struct sb_uart_port *port);
-static void multi_config_port(struct sb_uart_port *port, int flags);
-static int multi_verify_port(struct sb_uart_port *port, struct serial_struct *ser);
-static const char *multi_type(struct sb_uart_port *port);
-static void __init multi_init_ports(void);
-static void __init multi_register_ports(struct uart_driver *drv);
-static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd);
-
-static int deep[256];
-static int deep_count;
-static int fcr_arr[256];
-static int fcr_count;
-static int ttr[256];
-static int ttr_count;
-static int rtr[256];
-static int rtr_count;
-
-module_param_array(deep,int,&deep_count,0);
-module_param_array(fcr_arr,int,&fcr_count,0);
-module_param_array(ttr,int,&ttr_count,0);
-module_param_array(rtr,int,&rtr_count,0);
-
-static _INLINE_ unsigned int serial_in(struct mp_port *mtpt, int offset)
-{
- return inb(mtpt->port.iobase + offset);
-}
-
-static _INLINE_ void serial_out(struct mp_port *mtpt, int offset, int value)
-{
- outb(value, mtpt->port.iobase + offset);
-}
-
-static _INLINE_ unsigned int read_option_register(struct mp_port *mtpt, int offset)
-{
- return inb(mtpt->option_base_addr + offset);
-}
-
-static int sb1053a_get_interface(struct mp_port *mtpt, int port_num)
-{
- unsigned long option_base_addr = mtpt->option_base_addr;
- unsigned int interface = 0;
-
- switch (port_num)
- {
- case 0:
- case 1:
- /* set GPO[1:0] = 00 */
- outb(0x00, option_base_addr + MP_OPTR_GPODR);
- break;
- case 2:
- case 3:
- /* set GPO[1:0] = 01 */
- outb(0x01, option_base_addr + MP_OPTR_GPODR);
- break;
- case 4:
- case 5:
- /* set GPO[1:0] = 10 */
- outb(0x02, option_base_addr + MP_OPTR_GPODR);
- break;
- default:
- break;
- }
-
- port_num &= 0x1;
-
- /* get interface */
- interface = inb(option_base_addr + MP_OPTR_IIR0 + port_num);
-
- /* set GPO[1:0] = 11 */
- outb(0x03, option_base_addr + MP_OPTR_GPODR);
-
- return (interface);
-}
-
-static int sb1054_get_register(struct sb_uart_port *port, int page, int reg)
-{
- int ret = 0;
- unsigned int lcr = 0;
- unsigned int mcr = 0;
- unsigned int tmp = 0;
-
- if( page <= 0)
- {
- printk(" page 0 can not use this function\n");
- return -1;
- }
-
- switch(page)
- {
- case 1:
- lcr = SB105X_GET_LCR(port);
- tmp = lcr | SB105X_LCR_DLAB;
- SB105X_PUT_LCR(port, tmp);
-
- tmp = SB105X_GET_LCR(port);
-
- ret = SB105X_GET_REG(port,reg);
- SB105X_PUT_LCR(port,lcr);
- break;
- case 2:
- mcr = SB105X_GET_MCR(port);
- tmp = mcr | SB105X_MCR_P2S;
- SB105X_PUT_MCR(port,tmp);
-
- ret = SB105X_GET_REG(port,reg);
-
- SB105X_PUT_MCR(port,mcr);
- break;
- case 3:
- lcr = SB105X_GET_LCR(port);
- tmp = lcr | SB105X_LCR_BF;
- SB105X_PUT_LCR(port,tmp);
- SB105X_PUT_REG(port,SB105X_PSR,SB105X_PSR_P3KEY);
-
- ret = SB105X_GET_REG(port,reg);
-
- SB105X_PUT_LCR(port,lcr);
- break;
- case 4:
- lcr = SB105X_GET_LCR(port);
- tmp = lcr | SB105X_LCR_BF;
- SB105X_PUT_LCR(port,tmp);
- SB105X_PUT_REG(port,SB105X_PSR,SB105X_PSR_P4KEY);
-
- ret = SB105X_GET_REG(port,reg);
-
- SB105X_PUT_LCR(port,lcr);
- break;
- default:
- printk(" error invalid page number \n");
- return -1;
- }
-
- return ret;
-}
-
-static int sb1054_set_register(struct sb_uart_port *port, int page, int reg, int value)
-{
- int lcr = 0;
- int mcr = 0;
- int ret = 0;
-
- if( page <= 0)
- {
- printk(" page 0 can not use this function\n");
- return -1;
- }
- switch(page)
- {
- case 1:
- lcr = SB105X_GET_LCR(port);
- SB105X_PUT_LCR(port, lcr | SB105X_LCR_DLAB);
-
- SB105X_PUT_REG(port,reg,value);
-
- SB105X_PUT_LCR(port, lcr);
- ret = 1;
- break;
- case 2:
- mcr = SB105X_GET_MCR(port);
- SB105X_PUT_MCR(port, mcr | SB105X_MCR_P2S);
-
- SB105X_PUT_REG(port,reg,value);
-
- SB105X_PUT_MCR(port, mcr);
- ret = 1;
- break;
- case 3:
- lcr = SB105X_GET_LCR(port);
- SB105X_PUT_LCR(port, lcr | SB105X_LCR_BF);
- SB105X_PUT_PSR(port, SB105X_PSR_P3KEY);
-
- SB105X_PUT_REG(port,reg,value);
-
- SB105X_PUT_LCR(port, lcr);
- ret = 1;
- break;
- case 4:
- lcr = SB105X_GET_LCR(port);
- SB105X_PUT_LCR(port, lcr | SB105X_LCR_BF);
- SB105X_PUT_PSR(port, SB105X_PSR_P4KEY);
-
- SB105X_PUT_REG(port,reg,value);
-
- SB105X_PUT_LCR(port, lcr);
- ret = 1;
- break;
- default:
- printk(" error invalid page number \n");
- return -1;
- }
-
- return ret;
-}
-
-static int set_multidrop_mode(struct sb_uart_port *port, unsigned int mode)
-{
- int mdr = SB105XA_MDR_NPS;
-
- if (mode & MDMODE_ENABLE)
- {
- mdr |= SB105XA_MDR_MDE;
- }
-
- if (1) //(mode & MDMODE_AUTO)
- {
- int efr = 0;
- mdr |= SB105XA_MDR_AME;
- efr = sb1054_get_register(port, PAGE_3, SB105X_EFR);
- efr |= SB105X_EFR_SCD;
- sb1054_set_register(port, PAGE_3, SB105X_EFR, efr);
- }
-
- sb1054_set_register(port, PAGE_1, SB105XA_MDR, mdr);
- port->mdmode &= ~0x6;
- port->mdmode |= mode;
- printk("[%d] multidrop init: %x\n", port->line, port->mdmode);
-
- return 0;
-}
-
-static int get_multidrop_addr(struct sb_uart_port *port)
-{
- return sb1054_get_register(port, PAGE_3, SB105X_XOFF2);
-}
-
-static int set_multidrop_addr(struct sb_uart_port *port, unsigned int addr)
-{
- sb1054_set_register(port, PAGE_3, SB105X_XOFF2, addr);
-
- return 0;
-}
-
-static void SendATCommand(struct mp_port *mtpt)
-{
- // a t cr lf
- unsigned char ch[] = {0x61,0x74,0x0d,0x0a,0x0};
- unsigned char lineControl;
- unsigned char i=0;
- unsigned char Divisor = 0xc;
-
- lineControl = serial_inp(mtpt,UART_LCR);
- serial_outp(mtpt,UART_LCR,(lineControl | UART_LCR_DLAB));
- serial_outp(mtpt,UART_DLL,(Divisor & 0xff));
- serial_outp(mtpt,UART_DLM,(Divisor & 0xff00)>>8); //baudrate is 4800
-
-
- serial_outp(mtpt,UART_LCR,lineControl);
- serial_outp(mtpt,UART_LCR,0x03); // N-8-1
- serial_outp(mtpt,UART_FCR,7);
- serial_outp(mtpt,UART_MCR,0x3);
- while(ch[i]){
- while((serial_inp(mtpt,UART_LSR) & 0x60) !=0x60){
- ;
- }
- serial_outp(mtpt,0,ch[i++]);
- }
-
-
-}// end of SendATCommand()
-
-static int set_deep_fifo(struct sb_uart_port *port, int status)
-{
- int afr_status = 0;
- afr_status = sb1054_get_register(port, PAGE_4, SB105X_AFR);
-
- if(status == ENABLE)
- {
- afr_status |= SB105X_AFR_AFEN;
- }
- else
- {
- afr_status &= ~SB105X_AFR_AFEN;
- }
-
- sb1054_set_register(port,PAGE_4,SB105X_AFR,afr_status);
- sb1054_set_register(port,PAGE_4,SB105X_TTR,ttr[port->line]);
- sb1054_set_register(port,PAGE_4,SB105X_RTR,rtr[port->line]);
- afr_status = sb1054_get_register(port, PAGE_4, SB105X_AFR);
-
- return afr_status;
-}
-
-static int get_device_type(int arg)
-{
- int ret;
- ret = inb(mp_devs[arg].option_reg_addr+MP_OPTR_DIR0);
- ret = (ret & 0xf0) >> 4;
- switch (ret)
- {
- case DIR_UART_16C550:
- return PORT_16C55X;
- case DIR_UART_16C1050:
- return PORT_16C105X;
- case DIR_UART_16C1050A:
- /*
- if (mtpt->port.line < 2)
- {
- return PORT_16C105XA;
- }
- else
- {
- if (mtpt->device->device_id & 0x50)
- {
- return PORT_16C55X;
- }
- else
- {
- return PORT_16C105X;
- }
- }*/
- return PORT_16C105XA;
- default:
- return PORT_UNKNOWN;
- }
-
-}
-static int get_deep_fifo(struct sb_uart_port *port)
-{
- int afr_status = 0;
- afr_status = sb1054_get_register(port, PAGE_4, SB105X_AFR);
- return afr_status;
-}
-
-static int set_auto_rts(struct sb_uart_port *port, int status)
-{
- int atr_status = 0;
-
-#if 0
- int efr_status = 0;
-
- efr_status = sb1054_get_register(port, PAGE_3, SB105X_EFR);
- if(status == ENABLE)
- efr_status |= SB105X_EFR_ARTS;
- else
- efr_status &= ~SB105X_EFR_ARTS;
- sb1054_set_register(port,PAGE_3,SB105X_EFR,efr_status);
- efr_status = sb1054_get_register(port, PAGE_3, SB105X_EFR);
-#endif
-
-//ATR
- atr_status = sb1054_get_register(port, PAGE_3, SB105X_ATR);
- switch(status)
- {
- case RS422PTP:
- atr_status = (SB105X_ATR_TPS) | (SB105X_ATR_A80);
- break;
- case RS422MD:
- atr_status = (SB105X_ATR_TPS) | (SB105X_ATR_TCMS) | (SB105X_ATR_A80);
- break;
- case RS485NE:
- atr_status = (SB105X_ATR_RCMS) | (SB105X_ATR_TPS) | (SB105X_ATR_TCMS) | (SB105X_ATR_A80);
- break;
- case RS485ECHO:
- atr_status = (SB105X_ATR_TPS) | (SB105X_ATR_TCMS) | (SB105X_ATR_A80);
- break;
- }
-
- sb1054_set_register(port,PAGE_3,SB105X_ATR,atr_status);
- atr_status = sb1054_get_register(port, PAGE_3, SB105X_ATR);
-
- return atr_status;
-}
-
-static void mp_stop(struct tty_struct *tty)
-{
- struct sb_uart_state *state = tty->driver_data;
- struct sb_uart_port *port = state->port;
- unsigned long flags;
-
- spin_lock_irqsave(&port->lock, flags);
- port->ops->stop_tx(port);
- spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void __mp_start(struct tty_struct *tty)
-{
- struct sb_uart_state *state = tty->driver_data;
- struct sb_uart_port *port = state->port;
-
- if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf &&
- !tty->stopped && !tty->hw_stopped)
- port->ops->start_tx(port);
-}
-
-static void mp_start(struct tty_struct *tty)
-{
- __mp_start(tty);
-}
-
-static void mp_tasklet_action(unsigned long data)
-{
- struct sb_uart_state *state = (struct sb_uart_state *)data;
- struct tty_struct *tty;
-
- printk("tasklet is called!\n");
- tty = state->info->tty;
- tty_wakeup(tty);
-}
-
-static inline void mp_update_mctrl(struct sb_uart_port *port, unsigned int set, unsigned int clear)
-{
- unsigned int old;
-
- old = port->mctrl;
- port->mctrl = (old & ~clear) | set;
- if (old != port->mctrl)
- port->ops->set_mctrl(port, port->mctrl);
-}
-
-#define uart_set_mctrl(port,set) mp_update_mctrl(port,set,0)
-#define uart_clear_mctrl(port,clear) mp_update_mctrl(port,0,clear)
-
-static int mp_startup(struct sb_uart_state *state, int init_hw)
-{
- struct sb_uart_info *info = state->info;
- struct sb_uart_port *port = state->port;
- unsigned long page;
- int retval = 0;
-
- if (info->flags & UIF_INITIALIZED)
- return 0;
-
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
-
- if (port->type == PORT_UNKNOWN)
- return 0;
-
- if (!info->xmit.buf) {
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
-
- info->xmit.buf = (unsigned char *) page;
-
- uart_circ_clear(&info->xmit);
- }
-
- retval = port->ops->startup(port);
- if (retval == 0) {
- if (init_hw) {
- mp_change_speed(state, NULL);
-
- if (info->tty && (info->tty->termios.c_cflag & CBAUD))
- uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
- }
-
- info->flags |= UIF_INITIALIZED;
-
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
-
- if (retval && capable(CAP_SYS_ADMIN))
- retval = 0;
-
- return retval;
-}
-
-static void mp_shutdown(struct sb_uart_state *state)
-{
- struct sb_uart_info *info = state->info;
- struct sb_uart_port *port = state->port;
-
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
-
- if (info->flags & UIF_INITIALIZED) {
- info->flags &= ~UIF_INITIALIZED;
-
- if (!info->tty || (info->tty->termios.c_cflag & HUPCL))
- uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
-
- wake_up_interruptible(&info->delta_msr_wait);
-
- port->ops->shutdown(port);
-
- synchronize_irq(port->irq);
- }
- tasklet_kill(&info->tlet);
-
- if (info->xmit.buf) {
- free_page((unsigned long)info->xmit.buf);
- info->xmit.buf = NULL;
- }
-}
-
-static void mp_change_speed(struct sb_uart_state *state, struct MP_TERMIOS *old_termios)
-{
- struct tty_struct *tty = state->info->tty;
- struct sb_uart_port *port = state->port;
-
- if (!tty || port->type == PORT_UNKNOWN)
- return;
-
- if (tty->termios.c_cflag & CRTSCTS)
- state->info->flags |= UIF_CTS_FLOW;
- else
- state->info->flags &= ~UIF_CTS_FLOW;
-
- if (tty->termios.c_cflag & CLOCAL)
- state->info->flags &= ~UIF_CHECK_CD;
- else
- state->info->flags |= UIF_CHECK_CD;
-
- port->ops->set_termios(port, &tty->termios, old_termios);
-}
-
-static inline int __mp_put_char(struct sb_uart_port *port, struct circ_buf *circ, unsigned char c)
-{
- unsigned long flags;
- int ret = 0;
-
- if (!circ->buf)
- return 0;
-
- spin_lock_irqsave(&port->lock, flags);
- if (uart_circ_chars_free(circ) != 0) {
- circ->buf[circ->head] = c;
- circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
- ret = 1;
- }
- spin_unlock_irqrestore(&port->lock, flags);
- return ret;
-}
-
-static int mp_put_char(struct tty_struct *tty, unsigned char ch)
-{
- struct sb_uart_state *state = tty->driver_data;
-
- return __mp_put_char(state->port, &state->info->xmit, ch);
-}
-
-static void mp_put_chars(struct tty_struct *tty)
-{
- mp_start(tty);
-}
-
-static int mp_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
- struct sb_uart_state *state = tty->driver_data;
- struct sb_uart_port *port;
- struct circ_buf *circ;
- int c, ret = 0;
-
- if (!state || !state->info) {
- return -EL3HLT;
- }
-
- port = state->port;
- circ = &state->info->xmit;
-
- if (!circ->buf)
- return 0;
-
- while (1) {
- c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
- if (count < c)
- c = count;
- if (c <= 0)
- break;
- memcpy(circ->buf + circ->head, buf, c);
-
- circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
- buf += c;
- count -= c;
- ret += c;
- }
- mp_start(tty);
- return ret;
-}
-
-static int mp_write_room(struct tty_struct *tty)
-{
- struct sb_uart_state *state = tty->driver_data;
-
- return uart_circ_chars_free(&state->info->xmit);
-}
-
-static int mp_chars_in_buffer(struct tty_struct *tty)
-{
- struct sb_uart_state *state = tty->driver_data;
-
- return uart_circ_chars_pending(&state->info->xmit);
-}
-
-static void mp_flush_buffer(struct tty_struct *tty)
-{
- struct sb_uart_state *state = tty->driver_data;
- struct sb_uart_port *port;
- unsigned long flags;
-
- if (!state || !state->info) {
- return;
- }
-
- port = state->port;
- spin_lock_irqsave(&port->lock, flags);
- uart_circ_clear(&state->info->xmit);
- spin_unlock_irqrestore(&port->lock, flags);
- wake_up_interruptible(&tty->write_wait);
- tty_wakeup(tty);
-}
-
-static void mp_send_xchar(struct tty_struct *tty, char ch)
-{
- struct sb_uart_state *state = tty->driver_data;
- struct sb_uart_port *port = state->port;
- unsigned long flags;
-
- if (port->ops->send_xchar)
- port->ops->send_xchar(port, ch);
- else {
- port->x_char = ch;
- if (ch) {
- spin_lock_irqsave(&port->lock, flags);
- port->ops->start_tx(port);
- spin_unlock_irqrestore(&port->lock, flags);
- }
- }
-}
-
-static void mp_throttle(struct tty_struct *tty)
-{
- struct sb_uart_state *state = tty->driver_data;
-
- if (I_IXOFF(tty))
- mp_send_xchar(tty, STOP_CHAR(tty));
-
- if (tty->termios.c_cflag & CRTSCTS)
- uart_clear_mctrl(state->port, TIOCM_RTS);
-}
-
-static void mp_unthrottle(struct tty_struct *tty)
-{
- struct sb_uart_state *state = tty->driver_data;
- struct sb_uart_port *port = state->port;
-
- if (I_IXOFF(tty)) {
- if (port->x_char)
- port->x_char = 0;
- else
- mp_send_xchar(tty, START_CHAR(tty));
- }
-
- if (tty->termios.c_cflag & CRTSCTS)
- uart_set_mctrl(port, TIOCM_RTS);
-}
-
-static int mp_get_info(struct sb_uart_state *state, struct serial_struct *retinfo)
-{
- struct sb_uart_port *port = state->port;
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = port->type;
- tmp.line = port->line;
- tmp.port = port->iobase;
- if (HIGH_BITS_OFFSET)
- tmp.port_high = (long) port->iobase >> HIGH_BITS_OFFSET;
- tmp.irq = port->irq;
- tmp.flags = port->flags;
- tmp.xmit_fifo_size = port->fifosize;
- tmp.baud_base = port->uartclk / 16;
- tmp.close_delay = state->close_delay;
- tmp.closing_wait = state->closing_wait == USF_CLOSING_WAIT_NONE ?
- ASYNC_CLOSING_WAIT_NONE :
- state->closing_wait;
- tmp.custom_divisor = port->custom_divisor;
- tmp.hub6 = port->hub6;
- tmp.io_type = port->iotype;
- tmp.iomem_reg_shift = port->regshift;
- tmp.iomem_base = (void *)port->mapbase;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return 0;
-}
-
-static int mp_set_info(struct sb_uart_state *state, struct serial_struct *newinfo)
-{
- struct serial_struct new_serial;
- struct sb_uart_port *port = state->port;
- unsigned long new_port;
- unsigned int change_irq, change_port, closing_wait;
- unsigned int old_custom_divisor;
- unsigned int old_flags, new_flags;
- int retval = 0;
-
- if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
- return -EFAULT;
-
- new_port = new_serial.port;
- if (HIGH_BITS_OFFSET)
- new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
-
- new_serial.irq = irq_canonicalize(new_serial.irq);
-
- closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
- USF_CLOSING_WAIT_NONE : new_serial.closing_wait;
- MP_STATE_LOCK(state);
-
- change_irq = new_serial.irq != port->irq;
- change_port = new_port != port->iobase ||
- (unsigned long)new_serial.iomem_base != port->mapbase ||
- new_serial.hub6 != port->hub6 ||
- new_serial.io_type != port->iotype ||
- new_serial.iomem_reg_shift != port->regshift ||
- new_serial.type != port->type;
- old_flags = port->flags;
- new_flags = new_serial.flags;
- old_custom_divisor = port->custom_divisor;
-
- if (!capable(CAP_SYS_ADMIN)) {
- retval = -EPERM;
- if (change_irq || change_port ||
- (new_serial.baud_base != port->uartclk / 16) ||
- (new_serial.close_delay != state->close_delay) ||
- (closing_wait != state->closing_wait) ||
- (new_serial.xmit_fifo_size != port->fifosize) ||
- (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
- goto exit;
- port->flags = ((port->flags & ~UPF_USR_MASK) |
- (new_flags & UPF_USR_MASK));
- port->custom_divisor = new_serial.custom_divisor;
- goto check_and_exit;
- }
-
- if (port->ops->verify_port)
- retval = port->ops->verify_port(port, &new_serial);
-
- if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) ||
- (new_serial.baud_base < 9600))
- retval = -EINVAL;
-
- if (retval)
- goto exit;
-
- if (change_port || change_irq) {
- retval = -EBUSY;
-
- if (uart_users(state) > 1)
- goto exit;
-
- mp_shutdown(state);
- }
-
- if (change_port) {
- unsigned long old_iobase, old_mapbase;
- unsigned int old_type, old_iotype, old_hub6, old_shift;
-
- old_iobase = port->iobase;
- old_mapbase = port->mapbase;
- old_type = port->type;
- old_hub6 = port->hub6;
- old_iotype = port->iotype;
- old_shift = port->regshift;
-
- if (old_type != PORT_UNKNOWN)
- port->ops->release_port(port);
-
- port->iobase = new_port;
- port->type = new_serial.type;
- port->hub6 = new_serial.hub6;
- port->iotype = new_serial.io_type;
- port->regshift = new_serial.iomem_reg_shift;
- port->mapbase = (unsigned long)new_serial.iomem_base;
-
- if (port->type != PORT_UNKNOWN) {
- retval = port->ops->request_port(port);
- } else {
- retval = 0;
- }
-
- if (retval && old_type != PORT_UNKNOWN) {
- port->iobase = old_iobase;
- port->type = old_type;
- port->hub6 = old_hub6;
- port->iotype = old_iotype;
- port->regshift = old_shift;
- port->mapbase = old_mapbase;
- retval = port->ops->request_port(port);
- if (retval)
- port->type = PORT_UNKNOWN;
-
- retval = -EBUSY;
- }
- }
-
- port->irq = new_serial.irq;
- port->uartclk = new_serial.baud_base * 16;
- port->flags = (port->flags & ~UPF_CHANGE_MASK) |
- (new_flags & UPF_CHANGE_MASK);
- port->custom_divisor = new_serial.custom_divisor;
- state->close_delay = new_serial.close_delay;
- state->closing_wait = closing_wait;
- port->fifosize = new_serial.xmit_fifo_size;
- if (state->info->tty)
- state->info->tty->low_latency =
- (port->flags & UPF_LOW_LATENCY) ? 1 : 0;
-
-check_and_exit:
- retval = 0;
- if (port->type == PORT_UNKNOWN)
- goto exit;
- if (state->info->flags & UIF_INITIALIZED) {
- if (((old_flags ^ port->flags) & UPF_SPD_MASK) ||
- old_custom_divisor != port->custom_divisor) {
- if (port->flags & UPF_SPD_MASK) {
- printk(KERN_NOTICE
- "%s sets custom speed on ttyMP%d. This "
- "is deprecated.\n", current->comm,
- port->line);
- }
- mp_change_speed(state, NULL);
- }
- } else
- retval = mp_startup(state, 1);
-exit:
- MP_STATE_UNLOCK(state);
- return retval;
-}
-
-
-static int mp_get_lsr_info(struct sb_uart_state *state, unsigned int *value)
-{
- struct sb_uart_port *port = state->port;
- unsigned int result;
-
- result = port->ops->tx_empty(port);
-
- if (port->x_char ||
- ((uart_circ_chars_pending(&state->info->xmit) > 0) &&
- !state->info->tty->stopped && !state->info->tty->hw_stopped))
- result &= ~TIOCSER_TEMT;
-
- return put_user(result, value);
-}
-
-static int mp_tiocmget(struct tty_struct *tty)
-{
- struct sb_uart_state *state = tty->driver_data;
- struct sb_uart_port *port = state->port;
- int result = -EIO;
-
- MP_STATE_LOCK(state);
- if (!(tty->flags & (1 << TTY_IO_ERROR))) {
- result = port->mctrl;
- spin_lock_irq(&port->lock);
- result |= port->ops->get_mctrl(port);
- spin_unlock_irq(&port->lock);
- }
- MP_STATE_UNLOCK(state);
- return result;
-}
-
-static int mp_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
-{
- struct sb_uart_state *state = tty->driver_data;
- struct sb_uart_port *port = state->port;
- int ret = -EIO;
-
-
- MP_STATE_LOCK(state);
- if (!(tty->flags & (1 << TTY_IO_ERROR))) {
- mp_update_mctrl(port, set, clear);
- ret = 0;
- }
- MP_STATE_UNLOCK(state);
-
- return ret;
-}
-
-static int mp_break_ctl(struct tty_struct *tty, int break_state)
-{
- struct sb_uart_state *state = tty->driver_data;
- struct sb_uart_port *port = state->port;
-
- MP_STATE_LOCK(state);
-
- if (port->type != PORT_UNKNOWN)
- port->ops->break_ctl(port, break_state);
-
- MP_STATE_UNLOCK(state);
- return 0;
-}
-
-static int mp_do_autoconfig(struct sb_uart_state *state)
-{
- struct sb_uart_port *port = state->port;
- int flags, ret;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if (mutex_lock_interruptible(&state->mutex))
- return -ERESTARTSYS;
- ret = -EBUSY;
- if (uart_users(state) == 1) {
- mp_shutdown(state);
-
- if (port->type != PORT_UNKNOWN)
- port->ops->release_port(port);
-
- flags = UART_CONFIG_TYPE;
- if (port->flags & UPF_AUTO_IRQ)
- flags |= UART_CONFIG_IRQ;
-
- port->ops->config_port(port, flags);
-
- ret = mp_startup(state, 1);
- }
- MP_STATE_UNLOCK(state);
- return ret;
-}
-
-static int mp_wait_modem_status(struct sb_uart_state *state, unsigned long arg)
-{
- struct sb_uart_port *port = state->port;
- DECLARE_WAITQUEUE(wait, current);
- struct sb_uart_icount cprev, cnow;
- int ret;
-
- spin_lock_irq(&port->lock);
- memcpy(&cprev, &port->icount, sizeof(struct sb_uart_icount));
-
- port->ops->enable_ms(port);
- spin_unlock_irq(&port->lock);
-
- add_wait_queue(&state->info->delta_msr_wait, &wait);
- for (;;) {
- spin_lock_irq(&port->lock);
- memcpy(&cnow, &port->icount, sizeof(struct sb_uart_icount));
- spin_unlock_irq(&port->lock);
-
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- ret = 0;
- break;
- }
-
- schedule();
-
- if (signal_pending(current)) {
- ret = -ERESTARTSYS;
- break;
- }
-
- cprev = cnow;
- }
-
- current->state = TASK_RUNNING;
- remove_wait_queue(&state->info->delta_msr_wait, &wait);
-
- return ret;
-}
-
-static int mp_get_count(struct sb_uart_state *state, struct serial_icounter_struct *icnt)
-{
- struct serial_icounter_struct icount = {};
- struct sb_uart_icount cnow;
- struct sb_uart_port *port = state->port;
-
- spin_lock_irq(&port->lock);
- memcpy(&cnow, &port->icount, sizeof(struct sb_uart_icount));
- spin_unlock_irq(&port->lock);
-
- icount.cts = cnow.cts;
- icount.dsr = cnow.dsr;
- icount.rng = cnow.rng;
- icount.dcd = cnow.dcd;
- icount.rx = cnow.rx;
- icount.tx = cnow.tx;
- icount.frame = cnow.frame;
- icount.overrun = cnow.overrun;
- icount.parity = cnow.parity;
- icount.brk = cnow.brk;
- icount.buf_overrun = cnow.buf_overrun;
-
- return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
-}
-
-static int mp_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
-{
- struct sb_uart_state *state = tty->driver_data;
- struct mp_port *info = (struct mp_port *)state->port;
- int ret = -ENOIOCTLCMD;
-
-
- switch (cmd) {
- case TIOCSMULTIDROP:
- /* set multi-drop mode enable or disable, and default operation mode is H/W mode */
- if (info->port.type == PORT_16C105XA)
- {
- //arg &= ~0x6;
- //state->port->mdmode = 0;
- return set_multidrop_mode((struct sb_uart_port *)info, (unsigned int)arg);
- }
- ret = -ENOTSUPP;
- break;
- case GETDEEPFIFO:
- ret = get_deep_fifo(state->port);
- return ret;
- case SETDEEPFIFO:
- ret = set_deep_fifo(state->port,arg);
- deep[state->port->line] = arg;
- return ret;
- case SETTTR:
- if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){
- ret = sb1054_set_register(state->port,PAGE_4,SB105X_TTR,arg);
- ttr[state->port->line] = arg;
- }
- return ret;
- case SETRTR:
- if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){
- ret = sb1054_set_register(state->port,PAGE_4,SB105X_RTR,arg);
- rtr[state->port->line] = arg;
- }
- return ret;
- case GETTTR:
- if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){
- ret = sb1054_get_register(state->port,PAGE_4,SB105X_TTR);
- }
- return ret;
- case GETRTR:
- if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){
- ret = sb1054_get_register(state->port,PAGE_4,SB105X_RTR);
- }
- return ret;
-
- case SETFCR:
- if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){
- ret = sb1054_set_register(state->port,PAGE_1,SB105X_FCR,arg);
- }
- else{
- serial_out(info,2,arg);
- }
-
- return ret;
- case TIOCSMDADDR:
- /* set multi-drop address */
- if (info->port.type == PORT_16C105XA)
- {
- state->port->mdmode |= MDMODE_ADDR;
- return set_multidrop_addr((struct sb_uart_port *)info, (unsigned int)arg);
- }
- ret = -ENOTSUPP;
- break;
-
- case TIOCGMDADDR:
- /* set multi-drop address */
- if ((info->port.type == PORT_16C105XA) && (state->port->mdmode & MDMODE_ADDR))
- {
- return get_multidrop_addr((struct sb_uart_port *)info);
- }
- ret = -ENOTSUPP;
- break;
-
- case TIOCSENDADDR:
- /* send address in multi-drop mode */
- if ((info->port.type == PORT_16C105XA)
- && (state->port->mdmode & (MDMODE_ENABLE)))
- {
- if (mp_chars_in_buffer(tty) > 0)
- {
- tty_wait_until_sent(tty, 0);
- }
- //while ((serial_in(info, UART_LSR) & 0x60) != 0x60);
- //while (sb1054_get_register(state->port, PAGE_2, SB105X_TFCR) != 0);
- while ((serial_in(info, UART_LSR) & 0x60) != 0x60);
- serial_out(info, UART_SCR, (int)arg);
- }
- break;
-
- case TIOCGSERIAL:
- ret = mp_get_info(state, (struct serial_struct *)arg);
- break;
-
- case TIOCSSERIAL:
- ret = mp_set_info(state, (struct serial_struct *)arg);
- break;
-
- case TIOCSERCONFIG:
- ret = mp_do_autoconfig(state);
- break;
-
- case TIOCSERGWILD: /* obsolete */
- case TIOCSERSWILD: /* obsolete */
- ret = 0;
- break;
- /* for Multiport */
- case TIOCGNUMOFPORT: /* Get number of ports */
- return NR_PORTS;
- case TIOCGGETDEVID:
- return mp_devs[arg].device_id;
- case TIOCGGETREV:
- return mp_devs[arg].revision;
- case TIOCGGETNRPORTS:
- return mp_devs[arg].nr_ports;
- case TIOCGGETBDNO:
- return NR_BOARD;
- case TIOCGGETINTERFACE:
- if (mp_devs[arg].revision == 0xc0)
- {
- /* for SB16C1053APCI */
- return (sb1053a_get_interface(info, info->port.line));
- }
- else
- {
- return (inb(mp_devs[arg].option_reg_addr+MP_OPTR_IIR0+(state->port->line/8)));
- }
- case TIOCGGETPORTTYPE:
- ret = get_device_type(arg);
- return ret;
- case TIOCSMULTIECHO: /* set to multi-drop mode(RS422) or echo mode(RS485)*/
- outb( ( inb(info->interface_config_addr) & ~0x03 ) | 0x01 ,
- info->interface_config_addr);
- return 0;
- case TIOCSPTPNOECHO: /* set to multi-drop mode(RS422) or echo mode(RS485) */
- outb( ( inb(info->interface_config_addr) & ~0x03 ) ,
- info->interface_config_addr);
- return 0;
- }
-
- if (ret != -ENOIOCTLCMD)
- goto out;
-
- if (tty->flags & (1 << TTY_IO_ERROR)) {
- ret = -EIO;
- goto out;
- }
-
- switch (cmd) {
- case TIOCMIWAIT:
- ret = mp_wait_modem_status(state, arg);
- break;
-
- case TIOCGICOUNT:
- ret = mp_get_count(state, (struct serial_icounter_struct *)arg);
- break;
- }
-
- if (ret != -ENOIOCTLCMD)
- goto out;
-
- MP_STATE_LOCK(state);
- switch (cmd) {
- case TIOCSERGETLSR: /* Get line status register */
- ret = mp_get_lsr_info(state, (unsigned int *)arg);
- break;
-
- default: {
- struct sb_uart_port *port = state->port;
- if (port->ops->ioctl)
- ret = port->ops->ioctl(port, cmd, arg);
- break;
- }
- }
-
- MP_STATE_UNLOCK(state);
-out:
- return ret;
-}
-
-static void mp_set_termios(struct tty_struct *tty, struct MP_TERMIOS *old_termios)
-{
- struct sb_uart_state *state = tty->driver_data;
- unsigned long flags;
- unsigned int cflag = tty->termios.c_cflag;
-
-#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
- if ((cflag ^ old_termios->c_cflag) == 0 &&
- RELEVANT_IFLAG(tty->termios.c_iflag ^ old_termios->c_iflag) == 0)
- return;
-
- mp_change_speed(state, old_termios);
-
- if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
- uart_clear_mctrl(state->port, TIOCM_RTS | TIOCM_DTR);
-
- if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
- unsigned int mask = TIOCM_DTR;
- if (!(cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags))
- mask |= TIOCM_RTS;
- uart_set_mctrl(state->port, mask);
- }
-
- if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
- spin_lock_irqsave(&state->port->lock, flags);
- tty->hw_stopped = 0;
- __mp_start(tty);
- spin_unlock_irqrestore(&state->port->lock, flags);
- }
-
- if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
- spin_lock_irqsave(&state->port->lock, flags);
- if (!(state->port->ops->get_mctrl(state->port) & TIOCM_CTS)) {
- tty->hw_stopped = 1;
- state->port->ops->stop_tx(state->port);
- }
- spin_unlock_irqrestore(&state->port->lock, flags);
- }
-}
-
-static void mp_close(struct tty_struct *tty, struct file *filp)
-{
- struct sb_uart_state *state = tty->driver_data;
- struct sb_uart_port *port;
-
- printk("mp_close!\n");
- if (!state || !state->port)
- return;
-
- port = state->port;
-
- printk("close1 %d\n", __LINE__);
- MP_STATE_LOCK(state);
-
- printk("close2 %d\n", __LINE__);
- if (tty_hung_up_p(filp))
- goto done;
-
- printk("close3 %d\n", __LINE__);
- if ((tty->count == 1) && (state->count != 1)) {
- printk("mp_close: bad serial port count; tty->count is 1, "
- "state->count is %d\n", state->count);
- state->count = 1;
- }
- printk("close4 %d\n", __LINE__);
- if (--state->count < 0) {
- printk("rs_close: bad serial port count for ttyMP%d: %d\n",
- port->line, state->count);
- state->count = 0;
- }
- if (state->count)
- goto done;
-
- tty->closing = 1;
-
- printk("close5 %d\n", __LINE__);
- if (state->closing_wait != USF_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, state->closing_wait);
-
- printk("close6 %d\n", __LINE__);
- if (state->info->flags & UIF_INITIALIZED) {
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
- port->ops->stop_rx(port);
- spin_unlock_irqrestore(&port->lock, flags);
- mp_wait_until_sent(tty, port->timeout);
- }
- printk("close7 %d\n", __LINE__);
-
- mp_shutdown(state);
- printk("close8 %d\n", __LINE__);
- mp_flush_buffer(tty);
- tty_ldisc_flush(tty);
- tty->closing = 0;
- state->info->tty = NULL;
- if (state->info->blocked_open)
- {
- if (state->close_delay)
- {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(state->close_delay);
- }
- }
- else
- {
- mp_change_pm(state, 3);
- }
- printk("close8 %d\n", __LINE__);
-
- state->info->flags &= ~UIF_NORMAL_ACTIVE;
- wake_up_interruptible(&state->info->open_wait);
-
-done:
- printk("close done\n");
- MP_STATE_UNLOCK(state);
- module_put(THIS_MODULE);
-}
-
-static void mp_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- struct sb_uart_state *state = tty->driver_data;
- struct sb_uart_port *port = state->port;
- unsigned long char_time, expire;
-
- if (port->type == PORT_UNKNOWN || port->fifosize == 0)
- return;
-
- char_time = (port->timeout - HZ/50) / port->fifosize;
- char_time = char_time / 5;
- if (char_time == 0)
- char_time = 1;
- if (timeout && timeout < char_time)
- char_time = timeout;
-
- if (timeout == 0 || timeout > 2 * port->timeout)
- timeout = 2 * port->timeout;
-
- expire = jiffies + timeout;
-
- while (!port->ops->tx_empty(port)) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(char_time);
- if (signal_pending(current))
- break;
- if (time_after(jiffies, expire))
- break;
- }
- set_current_state(TASK_RUNNING); /* might not be needed */
-}
-
-static void mp_hangup(struct tty_struct *tty)
-{
- struct sb_uart_state *state = tty->driver_data;
-
- MP_STATE_LOCK(state);
- if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) {
- mp_flush_buffer(tty);
- mp_shutdown(state);
- state->count = 0;
- state->info->flags &= ~UIF_NORMAL_ACTIVE;
- state->info->tty = NULL;
- wake_up_interruptible(&state->info->open_wait);
- wake_up_interruptible(&state->info->delta_msr_wait);
- }
- MP_STATE_UNLOCK(state);
-}
-
-static void mp_update_termios(struct sb_uart_state *state)
-{
- struct tty_struct *tty = state->info->tty;
- struct sb_uart_port *port = state->port;
-
- if (!(tty->flags & (1 << TTY_IO_ERROR))) {
- mp_change_speed(state, NULL);
-
- if (tty->termios.c_cflag & CBAUD)
- uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
- }
-}
-
-static int mp_block_til_ready(struct file *filp, struct sb_uart_state *state)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct sb_uart_info *info = state->info;
- struct sb_uart_port *port = state->port;
- unsigned int mctrl;
-
- info->blocked_open++;
- state->count--;
-
- add_wait_queue(&info->open_wait, &wait);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (tty_hung_up_p(filp) || info->tty == NULL)
- break;
-
- if (!(info->flags & UIF_INITIALIZED))
- break;
-
- if ((filp->f_flags & O_NONBLOCK) ||
- (info->tty->termios.c_cflag & CLOCAL) ||
- (info->tty->flags & (1 << TTY_IO_ERROR))) {
- break;
- }
-
- if (info->tty->termios.c_cflag & CBAUD)
- uart_set_mctrl(port, TIOCM_DTR);
-
- spin_lock_irq(&port->lock);
- port->ops->enable_ms(port);
- mctrl = port->ops->get_mctrl(port);
- spin_unlock_irq(&port->lock);
- if (mctrl & TIOCM_CAR)
- break;
-
- MP_STATE_UNLOCK(state);
- schedule();
- MP_STATE_LOCK(state);
-
- if (signal_pending(current))
- break;
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&info->open_wait, &wait);
-
- state->count++;
- info->blocked_open--;
-
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (!info->tty || tty_hung_up_p(filp))
- return -EAGAIN;
-
- return 0;
-}
-
-static struct sb_uart_state *uart_get(struct uart_driver *drv, int line)
-{
- struct sb_uart_state *state;
-
- MP_MUTEX_LOCK(mp_mutex);
- state = drv->state + line;
- if (mutex_lock_interruptible(&state->mutex)) {
- state = ERR_PTR(-ERESTARTSYS);
- goto out;
- }
- state->count++;
- if (!state->port) {
- state->count--;
- MP_STATE_UNLOCK(state);
- state = ERR_PTR(-ENXIO);
- goto out;
- }
-
- if (!state->info) {
- state->info = kmalloc(sizeof(struct sb_uart_info), GFP_KERNEL);
- if (state->info) {
- memset(state->info, 0, sizeof(struct sb_uart_info));
- init_waitqueue_head(&state->info->open_wait);
- init_waitqueue_head(&state->info->delta_msr_wait);
-
- state->port->info = state->info;
-
- tasklet_init(&state->info->tlet, mp_tasklet_action,
- (unsigned long)state);
- } else {
- state->count--;
- MP_STATE_UNLOCK(state);
- state = ERR_PTR(-ENOMEM);
- }
- }
-
-out:
- MP_MUTEX_UNLOCK(mp_mutex);
- return state;
-}
-
-static int mp_open(struct tty_struct *tty, struct file *filp)
-{
- struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
- struct sb_uart_state *state;
- int retval;
- int line = tty->index;
- struct mp_port *mtpt;
-
- retval = -ENODEV;
- if (line >= tty->driver->num)
- goto fail;
-
- state = uart_get(drv, line);
-
- if (IS_ERR(state)) {
- retval = PTR_ERR(state);
- goto fail;
- }
-
- mtpt = (struct mp_port *)state->port;
-
- tty->driver_data = state;
- tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0;
- tty->alt_speed = 0;
- state->info->tty = tty;
-
- if (tty_hung_up_p(filp)) {
- retval = -EAGAIN;
- state->count--;
- MP_STATE_UNLOCK(state);
- goto fail;
- }
-
- if (state->count == 1)
- mp_change_pm(state, 0);
-
- retval = mp_startup(state, 0);
-
- if (retval == 0)
- retval = mp_block_til_ready(filp, state);
- MP_STATE_UNLOCK(state);
-
- if (retval == 0 && !(state->info->flags & UIF_NORMAL_ACTIVE)) {
- state->info->flags |= UIF_NORMAL_ACTIVE;
-
- mp_update_termios(state);
- }
-
- uart_clear_mctrl(state->port, TIOCM_RTS);
- try_module_get(THIS_MODULE);
-fail:
- return retval;
-}
-
-
-static const char *mp_type(struct sb_uart_port *port)
-{
- const char *str = NULL;
-
- if (port->ops->type)
- str = port->ops->type(port);
-
- if (!str)
- str = "unknown";
-
- return str;
-}
-
-static void mp_change_pm(struct sb_uart_state *state, int pm_state)
-{
- struct sb_uart_port *port = state->port;
- if (port->ops->pm)
- port->ops->pm(port, pm_state, state->pm_state);
- state->pm_state = pm_state;
-}
-
-static inline void mp_report_port(struct uart_driver *drv, struct sb_uart_port *port)
-{
- char address[64];
-
- switch (port->iotype) {
- case UPIO_PORT:
- snprintf(address, sizeof(address),"I/O 0x%x", port->iobase);
- break;
- case UPIO_HUB6:
- snprintf(address, sizeof(address),"I/O 0x%x offset 0x%x", port->iobase, port->hub6);
- break;
- case UPIO_MEM:
- snprintf(address, sizeof(address),"MMIO 0x%lx", port->mapbase);
- break;
- default:
- snprintf(address, sizeof(address),"*unknown*" );
- strlcpy(address, "*unknown*", sizeof(address));
- break;
- }
-
- printk( "%s%d at %s (irq = %d) is a %s\n",
- drv->dev_name, port->line, address, port->irq, mp_type(port));
-
-}
-
-static void mp_configure_port(struct uart_driver *drv, struct sb_uart_state *state, struct sb_uart_port *port)
-{
- unsigned int flags;
-
-
- if (!port->iobase && !port->mapbase && !port->membase)
- {
- DPRINTK("%s error \n",__FUNCTION__);
- return;
- }
- flags = UART_CONFIG_TYPE;
- if (port->flags & UPF_AUTO_IRQ)
- flags |= UART_CONFIG_IRQ;
- if (port->flags & UPF_BOOT_AUTOCONF) {
- port->type = PORT_UNKNOWN;
- port->ops->config_port(port, flags);
- }
-
- if (port->type != PORT_UNKNOWN) {
- unsigned long flags;
-
- mp_report_port(drv, port);
-
- spin_lock_irqsave(&port->lock, flags);
- port->ops->set_mctrl(port, 0);
- spin_unlock_irqrestore(&port->lock, flags);
-
- mp_change_pm(state, 3);
- }
-}
-
-static void mp_unconfigure_port(struct uart_driver *drv, struct sb_uart_state *state)
-{
- struct sb_uart_port *port = state->port;
- struct sb_uart_info *info = state->info;
-
- if (info && info->tty)
- tty_hangup(info->tty);
-
- MP_STATE_LOCK(state);
-
- state->info = NULL;
-
- if (port->type != PORT_UNKNOWN)
- port->ops->release_port(port);
-
- port->type = PORT_UNKNOWN;
-
- if (info) {
- tasklet_kill(&info->tlet);
- kfree(info);
- }
-
- MP_STATE_UNLOCK(state);
-}
-static struct tty_operations mp_ops = {
- .open = mp_open,
- .close = mp_close,
- .write = mp_write,
- .put_char = mp_put_char,
- .flush_chars = mp_put_chars,
- .write_room = mp_write_room,
- .chars_in_buffer= mp_chars_in_buffer,
- .flush_buffer = mp_flush_buffer,
- .ioctl = mp_ioctl,
- .throttle = mp_throttle,
- .unthrottle = mp_unthrottle,
- .send_xchar = mp_send_xchar,
- .set_termios = mp_set_termios,
- .stop = mp_stop,
- .start = mp_start,
- .hangup = mp_hangup,
- .break_ctl = mp_break_ctl,
- .wait_until_sent= mp_wait_until_sent,
-#ifdef CONFIG_PROC_FS
- .proc_fops = NULL,
-#endif
- .tiocmget = mp_tiocmget,
- .tiocmset = mp_tiocmset,
-};
-
-static int mp_register_driver(struct uart_driver *drv)
-{
- struct tty_driver *normal = NULL;
- int i, retval;
-
- drv->state = kmalloc(sizeof(struct sb_uart_state) * drv->nr, GFP_KERNEL);
- retval = -ENOMEM;
- if (!drv->state)
- {
- printk("SB PCI Error: Kernel memory allocation error!\n");
- goto out;
- }
- memset(drv->state, 0, sizeof(struct sb_uart_state) * drv->nr);
-
- normal = alloc_tty_driver(drv->nr);
- if (!normal)
- {
- printk("SB PCI Error: tty allocation error!\n");
- goto out;
- }
-
- drv->tty_driver = normal;
-
- normal->owner = drv->owner;
- normal->magic = TTY_DRIVER_MAGIC;
- normal->driver_name = drv->driver_name;
- normal->name = drv->dev_name;
- normal->major = drv->major;
- normal->minor_start = drv->minor;
-
- normal->num = MAX_MP_PORT ;
-
- normal->type = TTY_DRIVER_TYPE_SERIAL;
- normal->subtype = SERIAL_TYPE_NORMAL;
- normal->init_termios = tty_std_termios;
- normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- normal->driver_state = drv;
-
- tty_set_operations(normal, &mp_ops);
-
-for (i = 0; i < drv->nr; i++) {
- struct sb_uart_state *state = drv->state + i;
-
- state->close_delay = 500;
- state->closing_wait = 30000;
-
- mutex_init(&state->mutex);
- }
-
- retval = tty_register_driver(normal);
-out:
- if (retval < 0) {
- printk("Register tty driver Fail!\n");
- put_tty_driver(normal);
- kfree(drv->state);
- }
-
- return retval;
-}
-
-void mp_unregister_driver(struct uart_driver *drv)
-{
- struct tty_driver *normal = NULL;
-
- normal = drv->tty_driver;
-
- if (!normal)
- {
- return;
- }
-
- tty_unregister_driver(normal);
- put_tty_driver(normal);
- drv->tty_driver = NULL;
-
-
- kfree(drv->state);
-
-}
-
-static int mp_add_one_port(struct uart_driver *drv, struct sb_uart_port *port)
-{
- struct sb_uart_state *state;
- int ret = 0;
-
-
- if (port->line >= drv->nr)
- return -EINVAL;
-
- state = drv->state + port->line;
-
- MP_MUTEX_LOCK(mp_mutex);
- if (state->port) {
- ret = -EINVAL;
- goto out;
- }
-
- state->port = port;
-
- spin_lock_init(&port->lock);
- port->cons = drv->cons;
- port->info = state->info;
-
- mp_configure_port(drv, state, port);
-
- tty_register_device(drv->tty_driver, port->line, port->dev);
-
-out:
- MP_MUTEX_UNLOCK(mp_mutex);
-
-
- return ret;
-}
-
-static int mp_remove_one_port(struct uart_driver *drv, struct sb_uart_port *port)
-{
- struct sb_uart_state *state = drv->state + port->line;
-
- if (state->port != port)
- printk(KERN_ALERT "Removing wrong port: %p != %p\n",
- state->port, port);
-
- MP_MUTEX_LOCK(mp_mutex);
-
- tty_unregister_device(drv->tty_driver, port->line);
-
- mp_unconfigure_port(drv, state);
- state->port = NULL;
- MP_MUTEX_UNLOCK(mp_mutex);
-
- return 0;
-}
-
-static void autoconfig(struct mp_port *mtpt, unsigned int probeflags)
-{
- unsigned char status1, scratch, scratch2, scratch3;
- unsigned char save_lcr, save_mcr;
- unsigned long flags;
-
- unsigned char u_type;
- unsigned char b_ret = 0;
-
- if (!mtpt->port.iobase && !mtpt->port.mapbase && !mtpt->port.membase)
- return;
-
- DEBUG_AUTOCONF("ttyMP%d: autoconf (0x%04x, 0x%p): ",
- mtpt->port.line, mtpt->port.iobase, mtpt->port.membase);
-
- spin_lock_irqsave(&mtpt->port.lock, flags);
-
- if (!(mtpt->port.flags & UPF_BUGGY_UART)) {
- scratch = serial_inp(mtpt, UART_IER);
- serial_outp(mtpt, UART_IER, 0);
-#ifdef __i386__
- outb(0xff, 0x080);
-#endif
- scratch2 = serial_inp(mtpt, UART_IER) & 0x0f;
- serial_outp(mtpt, UART_IER, 0x0F);
-#ifdef __i386__
- outb(0, 0x080);
-#endif
- scratch3 = serial_inp(mtpt, UART_IER) & 0x0F;
- serial_outp(mtpt, UART_IER, scratch);
- if (scratch2 != 0 || scratch3 != 0x0F) {
- DEBUG_AUTOCONF("IER test failed (%02x, %02x) ",
- scratch2, scratch3);
- goto out;
- }
- }
-
- save_mcr = serial_in(mtpt, UART_MCR);
- save_lcr = serial_in(mtpt, UART_LCR);
-
- if (!(mtpt->port.flags & UPF_SKIP_TEST)) {
- serial_outp(mtpt, UART_MCR, UART_MCR_LOOP | 0x0A);
- status1 = serial_inp(mtpt, UART_MSR) & 0xF0;
- serial_outp(mtpt, UART_MCR, save_mcr);
- if (status1 != 0x90) {
- DEBUG_AUTOCONF("LOOP test failed (%02x) ",
- status1);
- goto out;
- }
- }
-
- serial_outp(mtpt, UART_LCR, 0xBF);
- serial_outp(mtpt, UART_EFR, 0);
- serial_outp(mtpt, UART_LCR, 0);
-
- serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO);
- scratch = serial_in(mtpt, UART_IIR) >> 6;
-
- DEBUG_AUTOCONF("iir=%d ", scratch);
- if(mtpt->device->nr_ports >= 8)
- b_ret = read_option_register(mtpt,(MP_OPTR_DIR0 + ((mtpt->port.line)/8)));
- else
- b_ret = read_option_register(mtpt,MP_OPTR_DIR0);
- u_type = (b_ret & 0xf0) >> 4;
- if(mtpt->port.type == PORT_UNKNOWN )
- {
- switch (u_type)
- {
- case DIR_UART_16C550:
- mtpt->port.type = PORT_16C55X;
- break;
- case DIR_UART_16C1050:
- mtpt->port.type = PORT_16C105X;
- break;
- case DIR_UART_16C1050A:
- if (mtpt->port.line < 2)
- {
- mtpt->port.type = PORT_16C105XA;
- }
- else
- {
- if (mtpt->device->device_id & 0x50)
- {
- mtpt->port.type = PORT_16C55X;
- }
- else
- {
- mtpt->port.type = PORT_16C105X;
- }
- }
- break;
- default:
- mtpt->port.type = PORT_UNKNOWN;
- break;
- }
- }
-
- if(mtpt->port.type == PORT_UNKNOWN )
- {
-printk("unknow2\n");
- switch (scratch) {
- case 0:
- case 1:
- mtpt->port.type = PORT_UNKNOWN;
- break;
- case 2:
- case 3:
- mtpt->port.type = PORT_16C55X;
- break;
- }
- }
-
- serial_outp(mtpt, UART_LCR, save_lcr);
-
- mtpt->port.fifosize = uart_config[mtpt->port.type].dfl_xmit_fifo_size;
- mtpt->capabilities = uart_config[mtpt->port.type].flags;
-
- if (mtpt->port.type == PORT_UNKNOWN)
- goto out;
- serial_outp(mtpt, UART_MCR, save_mcr);
- serial_outp(mtpt, UART_FCR, (UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR |
- UART_FCR_CLEAR_XMIT));
- serial_outp(mtpt, UART_FCR, 0);
- (void)serial_in(mtpt, UART_RX);
- serial_outp(mtpt, UART_IER, 0);
-
-out:
- spin_unlock_irqrestore(&mtpt->port.lock, flags);
- DEBUG_AUTOCONF("type=%s\n", uart_config[mtpt->port.type].name);
-}
-
-static void autoconfig_irq(struct mp_port *mtpt)
-{
- unsigned char save_mcr, save_ier;
- unsigned long irqs;
- int irq;
-
- /* forget possible initially masked and pending IRQ */
- probe_irq_off(probe_irq_on());
- save_mcr = serial_inp(mtpt, UART_MCR);
- save_ier = serial_inp(mtpt, UART_IER);
- serial_outp(mtpt, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
-
- irqs = probe_irq_on();
- serial_outp(mtpt, UART_MCR, 0);
- serial_outp(mtpt, UART_MCR,
- UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
-
- serial_outp(mtpt, UART_IER, 0x0f); /* enable all intrs */
- (void)serial_inp(mtpt, UART_LSR);
- (void)serial_inp(mtpt, UART_RX);
- (void)serial_inp(mtpt, UART_IIR);
- (void)serial_inp(mtpt, UART_MSR);
- serial_outp(mtpt, UART_TX, 0xFF);
- irq = probe_irq_off(irqs);
-
- serial_outp(mtpt, UART_MCR, save_mcr);
- serial_outp(mtpt, UART_IER, save_ier);
-
- mtpt->port.irq = (irq > 0) ? irq : 0;
-}
-
-static void multi_stop_tx(struct sb_uart_port *port)
-{
- struct mp_port *mtpt = (struct mp_port *)port;
-
- if (mtpt->ier & UART_IER_THRI) {
- mtpt->ier &= ~UART_IER_THRI;
- serial_out(mtpt, UART_IER, mtpt->ier);
- }
-
- tasklet_schedule(&port->info->tlet);
-}
-
-static void multi_start_tx(struct sb_uart_port *port)
-{
- struct mp_port *mtpt = (struct mp_port *)port;
-
- if (!(mtpt->ier & UART_IER_THRI)) {
- mtpt->ier |= UART_IER_THRI;
- serial_out(mtpt, UART_IER, mtpt->ier);
- }
-}
-
-static void multi_stop_rx(struct sb_uart_port *port)
-{
- struct mp_port *mtpt = (struct mp_port *)port;
-
- mtpt->ier &= ~UART_IER_RLSI;
- mtpt->port.read_status_mask &= ~UART_LSR_DR;
- serial_out(mtpt, UART_IER, mtpt->ier);
-}
-
-static void multi_enable_ms(struct sb_uart_port *port)
-{
- struct mp_port *mtpt = (struct mp_port *)port;
-
- mtpt->ier |= UART_IER_MSI;
- serial_out(mtpt, UART_IER, mtpt->ier);
-}
-
-
-static _INLINE_ void receive_chars(struct mp_port *mtpt, int *status )
-{
- struct tty_struct *tty = mtpt->port.info->tty;
- unsigned char lsr = *status;
- int max_count = 256;
- unsigned char ch;
- char flag;
-
- //lsr &= mtpt->port.read_status_mask;
-
- do {
- if ((lsr & UART_LSR_PE) && (mtpt->port.mdmode & MDMODE_ENABLE))
- {
- ch = serial_inp(mtpt, UART_RX);
- }
- else if (lsr & UART_LSR_SPECIAL)
- {
- flag = 0;
- ch = serial_inp(mtpt, UART_RX);
-
- if (lsr & UART_LSR_BI)
- {
-
- mtpt->port.icount.brk++;
- flag = TTY_BREAK;
-
- if (sb_uart_handle_break(&mtpt->port))
- goto ignore_char;
- }
- if (lsr & UART_LSR_PE)
- {
- mtpt->port.icount.parity++;
- flag = TTY_PARITY;
- }
- if (lsr & UART_LSR_FE)
- {
- mtpt->port.icount.frame++;
- flag = TTY_FRAME;
- }
- if (lsr & UART_LSR_OE)
- {
- mtpt->port.icount.overrun++;
- flag = TTY_OVERRUN;
- }
- tty_insert_flip_char(tty, ch, flag);
- }
- else
- {
- ch = serial_inp(mtpt, UART_RX);
- tty_insert_flip_char(tty, ch, 0);
- }
-ignore_char:
- lsr = serial_inp(mtpt, UART_LSR);
- } while ((lsr & UART_LSR_DR) && (max_count-- > 0));
-
- tty_flip_buffer_push(tty);
-}
-
-
-
-
-static _INLINE_ void transmit_chars(struct mp_port *mtpt)
-{
- struct circ_buf *xmit = &mtpt->port.info->xmit;
- int count;
-
- if (mtpt->port.x_char) {
- serial_outp(mtpt, UART_TX, mtpt->port.x_char);
- mtpt->port.icount.tx++;
- mtpt->port.x_char = 0;
- return;
- }
- if (uart_circ_empty(xmit) || uart_tx_stopped(&mtpt->port)) {
- multi_stop_tx(&mtpt->port);
- return;
- }
-
- count = uart_circ_chars_pending(xmit);
-
- if(count > mtpt->port.fifosize)
- {
- count = mtpt->port.fifosize;
- }
-
- printk("[%d] mdmode: %x\n", mtpt->port.line, mtpt->port.mdmode);
- do {
-#if 0
- /* check multi-drop mode */
- if ((mtpt->port.mdmode & (MDMODE_ENABLE | MDMODE_ADDR)) == (MDMODE_ENABLE | MDMODE_ADDR))
- {
- printk("send address\n");
- /* send multi-drop address */
- serial_out(mtpt, UART_SCR, xmit->buf[xmit->tail]);
- }
- else
-#endif
- {
- serial_out(mtpt, UART_TX, xmit->buf[xmit->tail]);
- }
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- mtpt->port.icount.tx++;
- } while (--count > 0);
-}
-
-
-
-static _INLINE_ void check_modem_status(struct mp_port *mtpt)
-{
- int status;
-
- status = serial_in(mtpt, UART_MSR);
-
- if ((status & UART_MSR_ANY_DELTA) == 0)
- return;
-
- if (status & UART_MSR_TERI)
- mtpt->port.icount.rng++;
- if (status & UART_MSR_DDSR)
- mtpt->port.icount.dsr++;
- if (status & UART_MSR_DDCD)
- sb_uart_handle_dcd_change(&mtpt->port, status & UART_MSR_DCD);
- if (status & UART_MSR_DCTS)
- sb_uart_handle_cts_change(&mtpt->port, status & UART_MSR_CTS);
-
- wake_up_interruptible(&mtpt->port.info->delta_msr_wait);
-}
-
-static inline void multi_handle_port(struct mp_port *mtpt)
-{
- unsigned int status = serial_inp(mtpt, UART_LSR);
-
- //printk("lsr: %x\n", status);
-
- if ((status & UART_LSR_DR) || (status & UART_LSR_SPECIAL))
- receive_chars(mtpt, &status);
- check_modem_status(mtpt);
- if (status & UART_LSR_THRE)
- {
- if ((mtpt->port.type == PORT_16C105X)
- || (mtpt->port.type == PORT_16C105XA))
- transmit_chars(mtpt);
- else
- {
- if (mtpt->interface >= RS485NE)
- uart_set_mctrl(&mtpt->port, TIOCM_RTS);
-
- transmit_chars(mtpt);
-
-
- if (mtpt->interface >= RS485NE)
- {
- while((status=serial_in(mtpt,UART_LSR) &0x60)!=0x60);
- uart_clear_mctrl(&mtpt->port, TIOCM_RTS);
- }
- }
- }
-}
-
-
-
-static irqreturn_t multi_interrupt(int irq, void *dev_id)
-{
- struct irq_info *iinfo = dev_id;
- struct list_head *lhead, *end = NULL;
- int pass_counter = 0;
-
-
- spin_lock(&iinfo->lock);
-
- lhead = iinfo->head;
- do {
- struct mp_port *mtpt;
- unsigned int iir;
-
- mtpt = list_entry(lhead, struct mp_port, list);
-
- iir = serial_in(mtpt, UART_IIR);
- printk("interrupt! port %d, iir 0x%x\n", mtpt->port.line, iir); //wlee
- if (!(iir & UART_IIR_NO_INT))
- {
- printk("interrupt handle\n");
- spin_lock(&mtpt->port.lock);
- multi_handle_port(mtpt);
- spin_unlock(&mtpt->port.lock);
-
- end = NULL;
- } else if (end == NULL)
- end = lhead;
-
- lhead = lhead->next;
- if (lhead == iinfo->head && pass_counter++ > PASS_LIMIT)
- {
- printk(KERN_ERR "multi: too much work for "
- "irq%d\n", irq);
- printk( "multi: too much work for "
- "irq%d\n", irq);
- break;
- }
- } while (lhead != end);
-
- spin_unlock(&iinfo->lock);
-
-
- return IRQ_HANDLED;
-}
-
-static void serial_do_unlink(struct irq_info *i, struct mp_port *mtpt)
-{
- spin_lock_irq(&i->lock);
-
- if (!list_empty(i->head)) {
- if (i->head == &mtpt->list)
- i->head = i->head->next;
- list_del(&mtpt->list);
- } else {
- i->head = NULL;
- }
-
- spin_unlock_irq(&i->lock);
-}
-
-static int serial_link_irq_chain(struct mp_port *mtpt)
-{
- struct irq_info *i = irq_lists + mtpt->port.irq;
- int ret, irq_flags = mtpt->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
- spin_lock_irq(&i->lock);
-
- if (i->head) {
- list_add(&mtpt->list, i->head);
- spin_unlock_irq(&i->lock);
-
- ret = 0;
- } else {
- INIT_LIST_HEAD(&mtpt->list);
- i->head = &mtpt->list;
- spin_unlock_irq(&i->lock);
-
- ret = request_irq(mtpt->port.irq, multi_interrupt,
- irq_flags, "serial", i);
- if (ret < 0)
- serial_do_unlink(i, mtpt);
- }
-
- return ret;
-}
-
-
-
-
-static void serial_unlink_irq_chain(struct mp_port *mtpt)
-{
- struct irq_info *i = irq_lists + mtpt->port.irq;
-
- if (list_empty(i->head))
- {
- free_irq(mtpt->port.irq, i);
- }
- serial_do_unlink(i, mtpt);
-}
-
-static void multi_timeout(unsigned long data)
-{
- struct mp_port *mtpt = (struct mp_port *)data;
-
-
- spin_lock(&mtpt->port.lock);
- multi_handle_port(mtpt);
- spin_unlock(&mtpt->port.lock);
-
- mod_timer(&mtpt->timer, jiffies+1 );
-}
-
-static unsigned int multi_tx_empty(struct sb_uart_port *port)
-{
- struct mp_port *mtpt = (struct mp_port *)port;
- unsigned long flags;
- unsigned int ret;
-
- spin_lock_irqsave(&mtpt->port.lock, flags);
- ret = serial_in(mtpt, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
- spin_unlock_irqrestore(&mtpt->port.lock, flags);
-
- return ret;
-}
-
-
-static unsigned int multi_get_mctrl(struct sb_uart_port *port)
-{
- struct mp_port *mtpt = (struct mp_port *)port;
- unsigned char status;
- unsigned int ret;
-
- status = serial_in(mtpt, UART_MSR);
-
- ret = 0;
- if (status & UART_MSR_DCD)
- ret |= TIOCM_CAR;
- if (status & UART_MSR_RI)
- ret |= TIOCM_RNG;
- if (status & UART_MSR_DSR)
- ret |= TIOCM_DSR;
- if (status & UART_MSR_CTS)
- ret |= TIOCM_CTS;
- return ret;
-}
-
-static void multi_set_mctrl(struct sb_uart_port *port, unsigned int mctrl)
-{
- struct mp_port *mtpt = (struct mp_port *)port;
- unsigned char mcr = 0;
-
- mctrl &= 0xff;
-
- if (mctrl & TIOCM_RTS)
- mcr |= UART_MCR_RTS;
- if (mctrl & TIOCM_DTR)
- mcr |= UART_MCR_DTR;
- if (mctrl & TIOCM_OUT1)
- mcr |= UART_MCR_OUT1;
- if (mctrl & TIOCM_OUT2)
- mcr |= UART_MCR_OUT2;
- if (mctrl & TIOCM_LOOP)
- mcr |= UART_MCR_LOOP;
-
-
- serial_out(mtpt, UART_MCR, mcr);
-}
-
-
-static void multi_break_ctl(struct sb_uart_port *port, int break_state)
-{
- struct mp_port *mtpt = (struct mp_port *)port;
- unsigned long flags;
-
- spin_lock_irqsave(&mtpt->port.lock, flags);
- if (break_state == -1)
- mtpt->lcr |= UART_LCR_SBC;
- else
- mtpt->lcr &= ~UART_LCR_SBC;
- serial_out(mtpt, UART_LCR, mtpt->lcr);
- spin_unlock_irqrestore(&mtpt->port.lock, flags);
-}
-
-
-
-static int multi_startup(struct sb_uart_port *port)
-{
- struct mp_port *mtpt = (struct mp_port *)port;
- unsigned long flags;
- int retval;
-
- mtpt->capabilities = uart_config[mtpt->port.type].flags;
- mtpt->mcr = 0;
-
- if (mtpt->capabilities & UART_CLEAR_FIFO) {
- serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
- serial_outp(mtpt, UART_FCR, 0);
- }
-
- (void) serial_inp(mtpt, UART_LSR);
- (void) serial_inp(mtpt, UART_RX);
- (void) serial_inp(mtpt, UART_IIR);
- (void) serial_inp(mtpt, UART_MSR);
- //test-wlee 9-bit disable
- serial_outp(mtpt, UART_MSR, 0);
-
-
- if (!(mtpt->port.flags & UPF_BUGGY_UART) &&
- (serial_inp(mtpt, UART_LSR) == 0xff)) {
- printk("ttyS%d: LSR safety check engaged!\n", mtpt->port.line);
- //return -ENODEV;
- }
-
- if ((!is_real_interrupt(mtpt->port.irq)) || (mtpt->poll_type==TYPE_POLL)) {
- unsigned int timeout = mtpt->port.timeout;
-
- timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
-
- mtpt->timer.data = (unsigned long)mtpt;
- mod_timer(&mtpt->timer, jiffies + timeout);
- }
- else
- {
- retval = serial_link_irq_chain(mtpt);
- if (retval)
- return retval;
- }
-
- serial_outp(mtpt, UART_LCR, UART_LCR_WLEN8);
-
- spin_lock_irqsave(&mtpt->port.lock, flags);
- if ((is_real_interrupt(mtpt->port.irq))||(mtpt->poll_type==TYPE_INTERRUPT))
- mtpt->port.mctrl |= TIOCM_OUT2;
-
- multi_set_mctrl(&mtpt->port, mtpt->port.mctrl);
- spin_unlock_irqrestore(&mtpt->port.lock, flags);
-
-
- mtpt->ier = UART_IER_RLSI | UART_IER_RDI;
- serial_outp(mtpt, UART_IER, mtpt->ier);
-
- (void) serial_inp(mtpt, UART_LSR);
- (void) serial_inp(mtpt, UART_RX);
- (void) serial_inp(mtpt, UART_IIR);
- (void) serial_inp(mtpt, UART_MSR);
-
- return 0;
-}
-
-
-
-static void multi_shutdown(struct sb_uart_port *port)
-{
- struct mp_port *mtpt = (struct mp_port *)port;
- unsigned long flags;
-
-
- mtpt->ier = 0;
- serial_outp(mtpt, UART_IER, 0);
-
- spin_lock_irqsave(&mtpt->port.lock, flags);
- mtpt->port.mctrl &= ~TIOCM_OUT2;
-
- multi_set_mctrl(&mtpt->port, mtpt->port.mctrl);
- spin_unlock_irqrestore(&mtpt->port.lock, flags);
-
- serial_out(mtpt, UART_LCR, serial_inp(mtpt, UART_LCR) & ~UART_LCR_SBC);
- serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR |
- UART_FCR_CLEAR_XMIT);
- serial_outp(mtpt, UART_FCR, 0);
-
-
- (void) serial_in(mtpt, UART_RX);
-
- if ((!is_real_interrupt(mtpt->port.irq))||(mtpt->poll_type==TYPE_POLL))
- {
- del_timer_sync(&mtpt->timer);
- }
- else
- {
- serial_unlink_irq_chain(mtpt);
- }
-}
-
-
-
-static unsigned int multi_get_divisor(struct sb_uart_port *port, unsigned int baud)
-{
- unsigned int quot;
-
- if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
- baud == (port->uartclk/4))
- quot = 0x8001;
- else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
- baud == (port->uartclk/8))
- quot = 0x8002;
- else
- quot = sb_uart_get_divisor(port, baud);
-
- return quot;
-}
-
-
-
-
-static void multi_set_termios(struct sb_uart_port *port, struct MP_TERMIOS *termios, struct MP_TERMIOS *old)
-{
- struct mp_port *mtpt = (struct mp_port *)port;
- unsigned char cval, fcr = 0;
- unsigned long flags;
- unsigned int baud, quot;
-
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- cval = 0x00;
- break;
- case CS6:
- cval = 0x01;
- break;
- case CS7:
- cval = 0x02;
- break;
- default:
- case CS8:
- cval = 0x03;
- break;
- }
-
- if (termios->c_cflag & CSTOPB)
- cval |= 0x04;
- if (termios->c_cflag & PARENB)
- cval |= UART_LCR_PARITY;
- if (!(termios->c_cflag & PARODD))
- cval |= UART_LCR_EPAR;
-
-#ifdef CMSPAR
- if (termios->c_cflag & CMSPAR)
- cval |= UART_LCR_SPAR;
-#endif
-
- baud = sb_uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
- quot = multi_get_divisor(port, baud);
-
- if (mtpt->capabilities & UART_USE_FIFO) {
- //if (baud < 2400)
- // fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
- //else
- // fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
-
- // fcr = UART_FCR_ENABLE_FIFO | 0x90;
- fcr = fcr_arr[mtpt->port.line];
- }
-
- spin_lock_irqsave(&mtpt->port.lock, flags);
-
- sb_uart_update_timeout(port, termios->c_cflag, baud);
-
- mtpt->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
- if (termios->c_iflag & INPCK)
- mtpt->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (termios->c_iflag & (BRKINT | PARMRK))
- mtpt->port.read_status_mask |= UART_LSR_BI;
-
- mtpt->port.ignore_status_mask = 0;
- if (termios->c_iflag & IGNPAR)
- mtpt->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
- if (termios->c_iflag & IGNBRK) {
- mtpt->port.ignore_status_mask |= UART_LSR_BI;
- if (termios->c_iflag & IGNPAR)
- mtpt->port.ignore_status_mask |= UART_LSR_OE;
- }
-
- if ((termios->c_cflag & CREAD) == 0)
- mtpt->port.ignore_status_mask |= UART_LSR_DR;
-
- mtpt->ier &= ~UART_IER_MSI;
- if (UART_ENABLE_MS(&mtpt->port, termios->c_cflag))
- mtpt->ier |= UART_IER_MSI;
-
- serial_out(mtpt, UART_IER, mtpt->ier);
-
- if (mtpt->capabilities & UART_STARTECH) {
- serial_outp(mtpt, UART_LCR, 0xBF);
- serial_outp(mtpt, UART_EFR,
- termios->c_cflag & CRTSCTS ? UART_EFR_CTS :0);
- }
-
- serial_outp(mtpt, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
-
- serial_outp(mtpt, UART_DLL, quot & 0xff); /* LS of divisor */
- serial_outp(mtpt, UART_DLM, quot >> 8); /* MS of divisor */
-
- serial_outp(mtpt, UART_LCR, cval); /* reset DLAB */
- mtpt->lcr = cval; /* Save LCR */
-
- if (fcr & UART_FCR_ENABLE_FIFO) {
- /* emulated UARTs (Lucent Venus 167x) need two steps */
- serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO);
- }
-
- serial_outp(mtpt, UART_FCR, fcr); /* set fcr */
-
-
- if ((mtpt->port.type == PORT_16C105X)
- || (mtpt->port.type == PORT_16C105XA))
- {
- if(deep[mtpt->port.line]!=0)
- set_deep_fifo(port, ENABLE);
-
- if (mtpt->interface != RS232)
- set_auto_rts(port,mtpt->interface);
-
- }
- else
- {
- if (mtpt->interface >= RS485NE)
- {
- uart_clear_mctrl(&mtpt->port, TIOCM_RTS);
- }
- }
-
- if(mtpt->device->device_id == PCI_DEVICE_ID_MP4M)
- {
- SendATCommand(mtpt);
- printk("SendATCommand\n");
- }
- multi_set_mctrl(&mtpt->port, mtpt->port.mctrl);
- spin_unlock_irqrestore(&mtpt->port.lock, flags);
-}
-
-static void multi_pm(struct sb_uart_port *port, unsigned int state, unsigned int oldstate)
-{
- struct mp_port *mtpt = (struct mp_port *)port;
- if (state) {
- if (mtpt->capabilities & UART_STARTECH) {
- serial_outp(mtpt, UART_LCR, 0xBF);
- serial_outp(mtpt, UART_EFR, UART_EFR_ECB);
- serial_outp(mtpt, UART_LCR, 0);
- serial_outp(mtpt, UART_IER, UART_IERX_SLEEP);
- serial_outp(mtpt, UART_LCR, 0xBF);
- serial_outp(mtpt, UART_EFR, 0);
- serial_outp(mtpt, UART_LCR, 0);
- }
-
- if (mtpt->pm)
- mtpt->pm(port, state, oldstate);
- }
- else
- {
- if (mtpt->capabilities & UART_STARTECH) {
- serial_outp(mtpt, UART_LCR, 0xBF);
- serial_outp(mtpt, UART_EFR, UART_EFR_ECB);
- serial_outp(mtpt, UART_LCR, 0);
- serial_outp(mtpt, UART_IER, 0);
- serial_outp(mtpt, UART_LCR, 0xBF);
- serial_outp(mtpt, UART_EFR, 0);
- serial_outp(mtpt, UART_LCR, 0);
- }
-
- if (mtpt->pm)
- mtpt->pm(port, state, oldstate);
- }
-}
-
-static void multi_release_std_resource(struct mp_port *mtpt)
-{
- unsigned int size = 8 << mtpt->port.regshift;
-
- switch (mtpt->port.iotype) {
- case UPIO_MEM:
- if (!mtpt->port.mapbase)
- break;
-
- if (mtpt->port.flags & UPF_IOREMAP) {
- iounmap(mtpt->port.membase);
- mtpt->port.membase = NULL;
- }
-
- release_mem_region(mtpt->port.mapbase, size);
- break;
-
- case UPIO_HUB6:
- case UPIO_PORT:
- release_region(mtpt->port.iobase,size);
- break;
- }
-}
-
-static void multi_release_port(struct sb_uart_port *port)
-{
-}
-
-static int multi_request_port(struct sb_uart_port *port)
-{
- return 0;
-}
-
-static void multi_config_port(struct sb_uart_port *port, int flags)
-{
- struct mp_port *mtpt = (struct mp_port *)port;
- int probeflags = PROBE_ANY;
-
- if (flags & UART_CONFIG_TYPE)
- autoconfig(mtpt, probeflags);
- if (mtpt->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
- autoconfig_irq(mtpt);
-
- if (mtpt->port.type == PORT_UNKNOWN)
- multi_release_std_resource(mtpt);
-}
-
-static int multi_verify_port(struct sb_uart_port *port, struct serial_struct *ser)
-{
- if (ser->irq >= NR_IRQS || ser->irq < 0 ||
- ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
- ser->type == PORT_STARTECH)
- return -EINVAL;
- return 0;
-}
-
-static const char *multi_type(struct sb_uart_port *port)
-{
- int type = port->type;
-
- if (type >= ARRAY_SIZE(uart_config))
- type = 0;
- return uart_config[type].name;
-}
-
-static struct sb_uart_ops multi_pops = {
- .tx_empty = multi_tx_empty,
- .set_mctrl = multi_set_mctrl,
- .get_mctrl = multi_get_mctrl,
- .stop_tx = multi_stop_tx,
- .start_tx = multi_start_tx,
- .stop_rx = multi_stop_rx,
- .enable_ms = multi_enable_ms,
- .break_ctl = multi_break_ctl,
- .startup = multi_startup,
- .shutdown = multi_shutdown,
- .set_termios = multi_set_termios,
- .pm = multi_pm,
- .type = multi_type,
- .release_port = multi_release_port,
- .request_port = multi_request_port,
- .config_port = multi_config_port,
- .verify_port = multi_verify_port,
-};
-
-static struct uart_driver multi_reg = {
- .owner = THIS_MODULE,
- .driver_name = "goldel_tulip",
- .dev_name = "ttyMP",
- .major = SB_TTY_MP_MAJOR,
- .minor = 0,
- .nr = MAX_MP_PORT,
- .cons = NULL,
-};
-
-static void __init multi_init_ports(void)
-{
- struct mp_port *mtpt;
- static int first = 1;
- int i,j,k;
- unsigned char osc;
- unsigned char b_ret = 0;
- static struct mp_device_t *sbdev;
-
- if (!first)
- return;
- first = 0;
-
- mtpt = multi_ports;
-
- for (k=0;k<NR_BOARD;k++)
- {
- sbdev = &mp_devs[k];
-
- for (i = 0; i < sbdev->nr_ports; i++, mtpt++)
- {
- mtpt->device = sbdev;
- mtpt->port.iobase = sbdev->uart_access_addr + 8*i;
- mtpt->port.irq = sbdev->irq;
- if ( ((sbdev->device_id == PCI_DEVICE_ID_MP4)&&(sbdev->revision==0x91)))
- mtpt->interface_config_addr = sbdev->option_reg_addr + 0x08 + i;
- else if (sbdev->revision == 0xc0)
- mtpt->interface_config_addr = sbdev->option_reg_addr + 0x08 + (i & 0x1);
- else
- mtpt->interface_config_addr = sbdev->option_reg_addr + 0x08 + i/8;
-
- mtpt->option_base_addr = sbdev->option_reg_addr;
-
- mtpt->poll_type = sbdev->poll_type;
-
- mtpt->port.uartclk = BASE_BAUD * 16;
-
- /* get input clock information */
- osc = inb(sbdev->option_reg_addr + MP_OPTR_DIR0 + i/8) & 0x0F;
- if (osc==0x0f)
- osc = 0;
- for(j=0;j<osc;j++)
- mtpt->port.uartclk *= 2;
- mtpt->port.flags |= STD_COM_FLAGS | UPF_SHARE_IRQ ;
- mtpt->port.iotype = UPIO_PORT;
- mtpt->port.ops = &multi_pops;
-
- if (sbdev->revision == 0xc0)
- {
- /* for SB16C1053APCI */
- b_ret = sb1053a_get_interface(mtpt, i);
- }
- else
- {
- b_ret = read_option_register(mtpt,(MP_OPTR_IIR0 + i/8));
- printk("IIR_RET = %x\n",b_ret);
- }
-
- /* default to RS232 */
- mtpt->interface = RS232;
- if (IIR_RS422 == (b_ret & IIR_TYPE_MASK))
- mtpt->interface = RS422PTP;
- if (IIR_RS485 == (b_ret & IIR_TYPE_MASK))
- mtpt->interface = RS485NE;
- }
- }
-}
-
-static void __init multi_register_ports(struct uart_driver *drv)
-{
- int i;
-
- multi_init_ports();
-
- for (i = 0; i < NR_PORTS; i++) {
- struct mp_port *mtpt = &multi_ports[i];
-
- mtpt->port.line = i;
- mtpt->port.ops = &multi_pops;
- init_timer(&mtpt->timer);
- mtpt->timer.function = multi_timeout;
- mp_add_one_port(drv, &mtpt->port);
- }
-}
-
-/**
- * pci_remap_base - remap BAR value of pci device
- *
- * PARAMETERS
- * pcidev - pci_dev structure address
- * offset - BAR offset PCI_BASE_ADDRESS_0 ~ PCI_BASE_ADDRESS_4
- * address - address to be changed BAR value
- * size - size of address space
- *
- * RETURNS
- * If this function performs successful, it returns 0. Otherwise, It returns -1.
- */
-static int pci_remap_base(struct pci_dev *pcidev, unsigned int offset,
- unsigned int address, unsigned int size)
-{
-#if 0
- struct resource *root;
- unsigned index = (offset - 0x10) >> 2;
-#endif
-
- pci_write_config_dword(pcidev, offset, address);
-#if 0
- root = pcidev->resource[index].parent;
- release_resource(&pcidev->resource[index]);
- address &= ~0x1;
- pcidev->resource[index].start = address;
- pcidev->resource[index].end = address + size - 1;
-
- if (request_resource(root, &pcidev->resource[index]) != NULL)
- {
- printk(KERN_ERR "pci remap conflict!! 0x%x\n", address);
- return (-1);
- }
-#endif
-
- return (0);
-}
-
-static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd)
-{
- static struct mp_device_t *sbdev = mp_devs;
- unsigned long addr = 0;
- int j;
- struct resource *ret = NULL;
-
- sbdev->device_id = brd.device_id;
- pci_read_config_byte(pcidev, PCI_CLASS_REVISION, &(sbdev->revision));
- sbdev->name = brd.name;
- sbdev->uart_access_addr = pcidev->resource[0].start & PCI_BASE_ADDRESS_IO_MASK;
-
- /* check revision. The SB16C1053APCI's option i/o address is BAR4 */
- if (sbdev->revision == 0xc0)
- {
- /* SB16C1053APCI */
- sbdev->option_reg_addr = pcidev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK;
- }
- else
- {
- sbdev->option_reg_addr = pcidev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
- }
-#if 1
- if (sbdev->revision == 0xc0)
- {
- outb(0x00, sbdev->option_reg_addr + MP_OPTR_GPOCR);
- inb(sbdev->option_reg_addr + MP_OPTR_GPOCR);
- outb(0x83, sbdev->option_reg_addr + MP_OPTR_GPOCR);
- }
-#endif
-
- sbdev->irq = pcidev->irq;
-
- if ((brd.device_id & 0x0800) || !(brd.device_id &0xff00))
- {
- sbdev->poll_type = TYPE_INTERRUPT;
- }
- else
- {
- sbdev->poll_type = TYPE_POLL;
- }
-
- /* codes which is specific to each board*/
- switch(brd.device_id){
- case PCI_DEVICE_ID_MP1 :
- case PCIE_DEVICE_ID_MP1 :
- case PCIE_DEVICE_ID_MP1E :
- case PCIE_DEVICE_ID_GT_MP1 :
- sbdev->nr_ports = 1;
- break;
- case PCI_DEVICE_ID_MP2 :
- case PCIE_DEVICE_ID_MP2 :
- case PCIE_DEVICE_ID_GT_MP2 :
- case PCIE_DEVICE_ID_MP2B :
- case PCIE_DEVICE_ID_MP2E :
- sbdev->nr_ports = 2;
-
- /* serial base address remap */
- if (sbdev->revision == 0xc0)
- {
- int prev_port_addr = 0;
-
- pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &prev_port_addr);
- pci_remap_base(pcidev, PCI_BASE_ADDRESS_1, prev_port_addr + 8, 8);
- }
- break;
- case PCI_DEVICE_ID_MP4 :
- case PCI_DEVICE_ID_MP4A :
- case PCIE_DEVICE_ID_MP4 :
- case PCI_DEVICE_ID_GT_MP4 :
- case PCI_DEVICE_ID_GT_MP4A :
- case PCIE_DEVICE_ID_GT_MP4 :
- case PCI_DEVICE_ID_MP4M :
- case PCIE_DEVICE_ID_MP4B :
- sbdev->nr_ports = 4;
-
- if(sbdev->revision == 0x91){
- sbdev->reserved_addr[0] = pcidev->resource[0].start & PCI_BASE_ADDRESS_IO_MASK;
- outb(0x03 , sbdev->reserved_addr[0] + 0x01);
- outb(0x03 , sbdev->reserved_addr[0] + 0x02);
- outb(0x01 , sbdev->reserved_addr[0] + 0x20);
- outb(0x00 , sbdev->reserved_addr[0] + 0x21);
- request_region(sbdev->reserved_addr[0], 32, sbdev->name);
- sbdev->uart_access_addr = pcidev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
- sbdev->option_reg_addr = pcidev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
- }
-
- /* SB16C1053APCI */
- if (sbdev->revision == 0xc0)
- {
- int prev_port_addr = 0;
-
- pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &prev_port_addr);
- pci_remap_base(pcidev, PCI_BASE_ADDRESS_1, prev_port_addr + 8, 8);
- pci_remap_base(pcidev, PCI_BASE_ADDRESS_2, prev_port_addr + 16, 8);
- pci_remap_base(pcidev, PCI_BASE_ADDRESS_3, prev_port_addr + 24, 8);
- }
- break;
- case PCI_DEVICE_ID_MP6 :
- case PCI_DEVICE_ID_MP6A :
- case PCI_DEVICE_ID_GT_MP6 :
- case PCI_DEVICE_ID_GT_MP6A :
- sbdev->nr_ports = 6;
-
- /* SB16C1053APCI */
- if (sbdev->revision == 0xc0)
- {
- int prev_port_addr = 0;
-
- pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &prev_port_addr);
- pci_remap_base(pcidev, PCI_BASE_ADDRESS_1, prev_port_addr + 8, 8);
- pci_remap_base(pcidev, PCI_BASE_ADDRESS_2, prev_port_addr + 16, 16);
- pci_remap_base(pcidev, PCI_BASE_ADDRESS_3, prev_port_addr + 32, 16);
- }
- break;
- case PCI_DEVICE_ID_MP8 :
- case PCIE_DEVICE_ID_MP8 :
- case PCI_DEVICE_ID_GT_MP8 :
- case PCIE_DEVICE_ID_GT_MP8 :
- case PCIE_DEVICE_ID_MP8B :
- sbdev->nr_ports = 8;
- break;
- case PCI_DEVICE_ID_MP32 :
- case PCIE_DEVICE_ID_MP32 :
- case PCI_DEVICE_ID_GT_MP32 :
- case PCIE_DEVICE_ID_GT_MP32 :
- {
- int portnum_hex=0;
- portnum_hex = inb(sbdev->option_reg_addr);
- sbdev->nr_ports = ((portnum_hex/16)*10) + (portnum_hex % 16);
- }
- break;
-#ifdef CONFIG_PARPORT_PC
- case PCI_DEVICE_ID_MP2S1P :
- sbdev->nr_ports = 2;
-
- /* SB16C1053APCI */
- if (sbdev->revision == 0xc0)
- {
- int prev_port_addr = 0;
-
- pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &prev_port_addr);
- pci_remap_base(pcidev, PCI_BASE_ADDRESS_1, prev_port_addr + 8, 8);
- }
-
- /* add PC compatible parallel port */
- parport_pc_probe_port(pcidev->resource[2].start, pcidev->resource[3].start, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &pcidev->dev, 0);
- break;
- case PCI_DEVICE_ID_MP1P :
- /* add PC compatible parallel port */
- parport_pc_probe_port(pcidev->resource[2].start, pcidev->resource[3].start, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &pcidev->dev, 0);
- break;
-#endif
- }
-
- ret = request_region(sbdev->uart_access_addr, (8*sbdev->nr_ports), sbdev->name);
-
- if (sbdev->revision == 0xc0)
- {
- ret = request_region(sbdev->option_reg_addr, 0x40, sbdev->name);
- }
- else
- {
- ret = request_region(sbdev->option_reg_addr, 0x20, sbdev->name);
- }
-
-
- NR_BOARD++;
- NR_PORTS += sbdev->nr_ports;
-
- /* Enable PCI interrupt */
- addr = sbdev->option_reg_addr + MP_OPTR_IMR0;
- for(j=0; j < (sbdev->nr_ports/8)+1; j++)
- {
- if (sbdev->poll_type == TYPE_INTERRUPT)
- {
- outb(0xff,addr +j);
- }
- }
- sbdev++;
-
- return 0;
-}
-
-static int __init multi_init(void)
-{
- int ret, i;
- struct pci_dev *dev = NULL;
-
- if(fcr_count==0)
- {
- for(i=0;i<256;i++)
- {
- fcr_arr[i] = 0x01;
-
- }
- }
- if(deep_count==0)
- {
- for(i=0;i<256;i++)
- {
- deep[i] = 1;
-
- }
- }
- if(rtr_count==0)
- {
- for(i=0;i<256;i++)
- {
- rtr[i] = 0x10;
- }
- }
- if(ttr_count==0)
- {
- for(i=0;i<256;i++)
- {
- ttr[i] = 0x38;
- }
- }
-
-
-printk("MULTI INIT\n");
- for( i=0; i< mp_nrpcibrds; i++)
- {
-
- while( (dev = pci_get_device(mp_pciboards[i].vendor_id, mp_pciboards[i].device_id, dev) ) )
-
- {
-printk("FOUND~~~\n");
-// Cent OS bug fix
-// if (mp_pciboards[i].device_id & 0x0800)
- {
- int status;
- pci_disable_device(dev);
- status = pci_enable_device(dev);
-
- if (status != 0)
- {
- printk("Multiport Board Enable Fail !\n\n");
- status = -ENXIO;
- return status;
- }
- }
-
- init_mp_dev(dev, mp_pciboards[i]);
- }
- }
-
- for (i = 0; i < NR_IRQS; i++)
- spin_lock_init(&irq_lists[i].lock);
-
- ret = mp_register_driver(&multi_reg);
-
- if (ret >= 0)
- multi_register_ports(&multi_reg);
-
- return ret;
-}
-
-static void __exit multi_exit(void)
-{
- int i;
-
- for (i = 0; i < NR_PORTS; i++)
- mp_remove_one_port(&multi_reg, &multi_ports[i].port);
-
- mp_unregister_driver(&multi_reg);
-}
-
-module_init(multi_init);
-module_exit(multi_exit);
-
-MODULE_DESCRIPTION("SystemBase Multiport PCI/PCIe CORE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/sb105x/sb_pci_mp.h b/drivers/staging/sb105x/sb_pci_mp.h
deleted file mode 100644
index 80ae4ab04603..000000000000
--- a/drivers/staging/sb105x/sb_pci_mp.h
+++ /dev/null
@@ -1,291 +0,0 @@
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/tty_driver.h>
-#include <linux/pci.h>
-#include <linux/circ_buf.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/serial.h>
-#include <linux/interrupt.h>
-
-
-#include <linux/parport.h>
-#include <linux/ctype.h>
-#include <linux/poll.h>
-
-
-#define MP_TERMIOS ktermios
-
-#include "sb_mp_register.h"
-#include "sb_ser_core.h"
-
-#define DRIVER_VERSION "1.1"
-#define DRIVER_DATE "2012/01/05"
-#define DRIVER_AUTHOR "SYSTEMBASE<tech@sysbas.com>"
-#define DRIVER_DESC "SystemBase PCI/PCIe Multiport Core"
-
-#define SB_TTY_MP_MAJOR 54
-#define PCI_VENDOR_ID_MULTIPORT 0x14A1
-
-#define PCI_DEVICE_ID_MP1 0x4d01
-#define PCI_DEVICE_ID_MP2 0x4d02
-#define PCI_DEVICE_ID_MP4 0x4d04
-#define PCI_DEVICE_ID_MP4A 0x4d54
-#define PCI_DEVICE_ID_MP6 0x4d06
-#define PCI_DEVICE_ID_MP6A 0x4d56
-#define PCI_DEVICE_ID_MP8 0x4d08
-#define PCI_DEVICE_ID_MP32 0x4d32
-/* Parallel port */
-#define PCI_DEVICE_ID_MP1P 0x4301
-#define PCI_DEVICE_ID_MP2S1P 0x4303
-
-#define PCIE_DEVICE_ID_MP1 0x4501
-#define PCIE_DEVICE_ID_MP2 0x4502
-#define PCIE_DEVICE_ID_MP4 0x4504
-#define PCIE_DEVICE_ID_MP8 0x4508
-#define PCIE_DEVICE_ID_MP32 0x4532
-
-#define PCIE_DEVICE_ID_MP1E 0x4e01
-#define PCIE_DEVICE_ID_MP2E 0x4e02
-#define PCIE_DEVICE_ID_MP2B 0x4b02
-#define PCIE_DEVICE_ID_MP4B 0x4b04
-#define PCIE_DEVICE_ID_MP8B 0x4b08
-
-#define PCI_DEVICE_ID_GT_MP4 0x0004
-#define PCI_DEVICE_ID_GT_MP4A 0x0054
-#define PCI_DEVICE_ID_GT_MP6 0x0006
-#define PCI_DEVICE_ID_GT_MP6A 0x0056
-#define PCI_DEVICE_ID_GT_MP8 0x0008
-#define PCI_DEVICE_ID_GT_MP32 0x0032
-
-#define PCIE_DEVICE_ID_GT_MP1 0x1501
-#define PCIE_DEVICE_ID_GT_MP2 0x1502
-#define PCIE_DEVICE_ID_GT_MP4 0x1504
-#define PCIE_DEVICE_ID_GT_MP8 0x1508
-#define PCIE_DEVICE_ID_GT_MP32 0x1532
-
-#define PCI_DEVICE_ID_MP4M 0x4604 //modem
-
-#define MAX_MP_DEV 8
-#define BD_MAX_PORT 32 /* Max serial port in one board */
-#define MAX_MP_PORT 256 /* Max serial port in one PC */
-
-#define PORT_16C105XA 3
-#define PORT_16C105X 2
-#define PORT_16C55X 1
-
-#define ENABLE 1
-#define DISABLE 0
-
-/* ioctls */
-#define TIOCGNUMOFPORT 0x545F
-#define TIOCSMULTIECHO 0x5440
-#define TIOCSPTPNOECHO 0x5441
-
-#define TIOCGOPTIONREG 0x5461
-#define TIOCGDISABLEIRQ 0x5462
-#define TIOCGENABLEIRQ 0x5463
-#define TIOCGSOFTRESET 0x5464
-#define TIOCGSOFTRESETR 0x5465
-#define TIOCGREGINFO 0x5466
-#define TIOCGGETLSR 0x5467
-#define TIOCGGETDEVID 0x5468
-#define TIOCGGETBDNO 0x5469
-#define TIOCGGETINTERFACE 0x546A
-#define TIOCGGETREV 0x546B
-#define TIOCGGETNRPORTS 0x546C
-#define TIOCGGETPORTTYPE 0x546D
-#define GETDEEPFIFO 0x54AA
-#define SETDEEPFIFO 0x54AB
-#define SETFCR 0x54BA
-#define SETTTR 0x54B1
-#define SETRTR 0x54B2
-#define GETTTR 0x54B3
-#define GETRTR 0x54B4
-
-/* multi-drop mode related ioctl commands */
-#define TIOCSMULTIDROP 0x5470
-#define TIOCSMDADDR 0x5471
-#define TIOCGMDADDR 0x5472
-#define TIOCSENDADDR 0x5473
-
-
-/* serial interface */
-#define RS232 1
-#define RS422PTP 2
-#define RS422MD 3
-#define RS485NE 4
-#define RS485ECHO 5
-
-#define serial_inp(up, offset) serial_in(up, offset)
-#define serial_outp(up, offset, value) serial_out(up, offset, value)
-
-#define PASS_LIMIT 256
-#define is_real_interrupt(irq) ((irq) != 0)
-
-#define PROBE_ANY (~0)
-
-static DEFINE_MUTEX(mp_mutex);
-#define MP_MUTEX_LOCK(x) mutex_lock(&(x))
-#define MP_MUTEX_UNLOCK(x) mutex_unlock(&(x))
-#define MP_STATE_LOCK(x) mutex_lock(&((x)->mutex))
-#define MP_STATE_UNLOCK(x) mutex_unlock(&((x)->mutex))
-
-
-#define UART_LSR_SPECIAL 0x1E
-
-#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
-#define uart_users(state) ((state)->count + ((state)->info ? (state)->info->blocked_open : 0))
-
-
-//#define MP_DEBUG 1
-#undef MP_DEBUG
-
-#ifdef MP_DEBUG
-#define DPRINTK(x...) printk(x)
-#else
-#define DPRINTK(x...) do { } while (0)
-#endif
-
-#ifdef MP_DEBUG
-#define DEBUG_AUTOCONF(fmt...) printk(fmt)
-#else
-#define DEBUG_AUTOCONF(fmt...) do { } while (0)
-#endif
-
-#ifdef MP_DEBUG
-#define DEBUG_INTR(fmt...) printk(fmt)
-#else
-#define DEBUG_INTR(fmt...) do { } while (0)
-#endif
-
-#if defined(__i386__) && defined(CONFIG_M486)
-#define SERIAL_INLINE
-#endif
-#ifdef SERIAL_INLINE
-#define _INLINE_ inline
-#else
-#define _INLINE_
-#endif
-
-#define TYPE_POLL 1
-#define TYPE_INTERRUPT 2
-
-
-struct mp_device_t {
- unsigned short device_id;
- unsigned char revision;
- char *name;
- unsigned long uart_access_addr;
- unsigned long option_reg_addr;
- unsigned long reserved_addr[4];
- int irq;
- int nr_ports;
- int poll_type;
-};
-
-typedef struct mppcibrd {
- char *name;
- unsigned short vendor_id;
- unsigned short device_id;
-} mppcibrd_t;
-
-static mppcibrd_t mp_pciboards[] = {
-
- { "Multi-1 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP1} ,
- { "Multi-2 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP2} ,
- { "Multi-4 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP4} ,
- { "Multi-4 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP4A} ,
- { "Multi-6 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP6} ,
- { "Multi-6 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP6A} ,
- { "Multi-8 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP8} ,
- { "Multi-32 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP32} ,
-
- { "Multi-1P PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP1P} ,
- { "Multi-2S1P PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP2S1P} ,
-
- { "Multi-4(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP4} ,
- { "Multi-4(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP4A} ,
- { "Multi-6(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP6} ,
- { "Multi-6(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP6A} ,
- { "Multi-8(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP8} ,
- { "Multi-32(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP32} ,
-
- { "Multi-1 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP1} ,
- { "Multi-2 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP2} ,
- { "Multi-4 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP4} ,
- { "Multi-8 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP8} ,
- { "Multi-32 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP32} ,
-
- { "Multi-1 PCIe E", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP1E} ,
- { "Multi-2 PCIe E", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP2E} ,
- { "Multi-2 PCIe B", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP2B} ,
- { "Multi-4 PCIe B", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP4B} ,
- { "Multi-8 PCIe B", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP8B} ,
-
- { "Multi-1(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP1} ,
- { "Multi-2(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP2} ,
- { "Multi-4(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP4} ,
- { "Multi-8(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP8} ,
- { "Multi-32(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP32} ,
-
- { "Multi-4M PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP4M} ,
-};
-
-struct mp_port {
- struct sb_uart_port port;
-
- struct timer_list timer; /* "no irq" timer */
- struct list_head list; /* ports on this IRQ */
- unsigned int capabilities; /* port capabilities */
- unsigned short rev;
- unsigned char acr;
- unsigned char ier;
- unsigned char lcr;
- unsigned char mcr;
- unsigned char mcr_mask; /* mask of user bits */
- unsigned char mcr_force; /* mask of forced bits */
- unsigned char lsr_break_flag;
-
- void (*pm)(struct sb_uart_port *port,
- unsigned int state, unsigned int old);
- struct mp_device_t *device;
- unsigned long interface_config_addr;
- unsigned long option_base_addr;
- unsigned char interface;
- unsigned char poll_type;
-};
-
-struct irq_info {
- spinlock_t lock;
- struct list_head *head;
-};
-
-struct sb105x_uart_config {
- char *name;
- int dfl_xmit_fifo_size;
- int flags;
-};
-
-static const struct sb105x_uart_config uart_config[] = {
- { "unknown", 1, 0 },
- { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
- { "SB16C1050", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
- { "SB16C1050A", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
-};
-
-
-
diff --git a/drivers/staging/sb105x/sb_ser_core.h b/drivers/staging/sb105x/sb_ser_core.h
deleted file mode 100644
index c8fb99173299..000000000000
--- a/drivers/staging/sb105x/sb_ser_core.h
+++ /dev/null
@@ -1,368 +0,0 @@
-#include <linux/wait.h>
-
-#define UART_CONFIG_TYPE (1 << 0)
-#define UART_CONFIG_IRQ (1 << 1)
-#define UPIO_PORT (0)
-#define UPIO_HUB6 (1)
-#define UPIO_MEM (2)
-#define UPIO_MEM32 (3)
-#define UPIO_AU (4) /* Au1x00 type IO */
-#define UPIO_TSI (5) /* Tsi108/109 type IO */
-#define UPF_FOURPORT (1 << 1)
-#define UPF_SAK (1 << 2)
-#define UPF_SPD_MASK (0x1030)
-#define UPF_SPD_HI (0x0010)
-#define UPF_SPD_VHI (0x0020)
-#define UPF_SPD_CUST (0x0030)
-#define UPF_SPD_SHI (0x1000)
-#define UPF_SPD_WARP (0x1010)
-#define UPF_SKIP_TEST (1 << 6)
-#define UPF_AUTO_IRQ (1 << 7)
-#define UPF_HARDPPS_CD (1 << 11)
-#define UPF_LOW_LATENCY (1 << 13)
-#define UPF_BUGGY_UART (1 << 14)
-#define UPF_MAGIC_MULTIPLIER (1 << 16)
-#define UPF_CONS_FLOW (1 << 23)
-#define UPF_SHARE_IRQ (1 << 24)
-#define UPF_BOOT_AUTOCONF (1 << 28)
-#define UPF_DEAD (1 << 30)
-#define UPF_IOREMAP (1 << 31)
-#define UPF_CHANGE_MASK (0x17fff)
-#define UPF_USR_MASK (UPF_SPD_MASK|UPF_LOW_LATENCY)
-#define USF_CLOSING_WAIT_INF (0)
-#define USF_CLOSING_WAIT_NONE (~0U)
-
-#define UART_XMIT_SIZE PAGE_SIZE
-
-#define UIF_CHECK_CD (1 << 25)
-#define UIF_CTS_FLOW (1 << 26)
-#define UIF_NORMAL_ACTIVE (1 << 29)
-#define UIF_INITIALIZED (1 << 31)
-#define UIF_SUSPENDED (1 << 30)
-
-#define WAKEUP_CHARS 256
-
-#define uart_circ_empty(circ) ((circ)->head == (circ)->tail)
-#define uart_circ_clear(circ) ((circ)->head = (circ)->tail = 0)
-
-#define uart_circ_chars_pending(circ) \
- (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE))
-
-#define uart_circ_chars_free(circ) \
- (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))
-
-#define uart_tx_stopped(port) \
- ((port)->info->tty->stopped || (port)->info->tty->hw_stopped)
-
-#define UART_ENABLE_MS(port,cflag) ((port)->flags & UPF_HARDPPS_CD || \
- (cflag) & CRTSCTS || \
- !((cflag) & CLOCAL))
-
-
-struct sb_uart_port;
-struct sb_uart_info;
-struct serial_struct;
-struct device;
-
-struct sb_uart_ops {
- unsigned int (*tx_empty)(struct sb_uart_port *);
- void (*set_mctrl)(struct sb_uart_port *, unsigned int mctrl);
- unsigned int (*get_mctrl)(struct sb_uart_port *);
- void (*stop_tx)(struct sb_uart_port *);
- void (*start_tx)(struct sb_uart_port *);
- void (*send_xchar)(struct sb_uart_port *, char ch);
- void (*stop_rx)(struct sb_uart_port *);
- void (*enable_ms)(struct sb_uart_port *);
- void (*break_ctl)(struct sb_uart_port *, int ctl);
- int (*startup)(struct sb_uart_port *);
- void (*shutdown)(struct sb_uart_port *);
- void (*set_termios)(struct sb_uart_port *, struct MP_TERMIOS *new,
- struct MP_TERMIOS *old);
- void (*pm)(struct sb_uart_port *, unsigned int state,
- unsigned int oldstate);
- int (*set_wake)(struct sb_uart_port *, unsigned int state);
-
- const char *(*type)(struct sb_uart_port *);
-
- void (*release_port)(struct sb_uart_port *);
-
- int (*request_port)(struct sb_uart_port *);
- void (*config_port)(struct sb_uart_port *, int);
- int (*verify_port)(struct sb_uart_port *, struct serial_struct *);
- int (*ioctl)(struct sb_uart_port *, unsigned int, unsigned long);
-};
-
-
-struct sb_uart_icount {
- __u32 cts;
- __u32 dsr;
- __u32 rng;
- __u32 dcd;
- __u32 rx;
- __u32 tx;
- __u32 frame;
- __u32 overrun;
- __u32 parity;
- __u32 brk;
- __u32 buf_overrun;
-};
-typedef unsigned int upf_t;
-
-struct sb_uart_port {
- spinlock_t lock; /* port lock */
- unsigned int iobase; /* in/out[bwl] */
- unsigned char __iomem *membase; /* read/write[bwl] */
- unsigned int irq; /* irq number */
- unsigned int uartclk; /* base uart clock */
- unsigned int fifosize; /* tx fifo size */
- unsigned char x_char; /* xon/xoff char */
- unsigned char regshift; /* reg offset shift */
- unsigned char iotype; /* io access style */
- unsigned char unused1;
-
-
- unsigned int read_status_mask; /* driver specific */
- unsigned int ignore_status_mask; /* driver specific */
- struct sb_uart_info *info; /* pointer to parent info */
- struct sb_uart_icount icount; /* statistics */
-
- struct console *cons; /* struct console, if any */
-#ifdef CONFIG_SERIAL_CORE_CONSOLE
- unsigned long sysrq; /* sysrq timeout */
-#endif
-
- upf_t flags;
-
- unsigned int mctrl; /* current modem ctrl settings */
- unsigned int timeout; /* character-based timeout */
- unsigned int type; /* port type */
- const struct sb_uart_ops *ops;
- unsigned int custom_divisor;
- unsigned int line; /* port index */
- unsigned long mapbase; /* for ioremap */
- struct device *dev; /* parent device */
- unsigned char hub6; /* this should be in the 8250 driver */
- unsigned char unused[3];
-};
-
-#define mdmode unused[2]
-#define MDMODE_ADDR 0x1
-#define MDMODE_ENABLE 0x2
-#define MDMODE_AUTO 0x4
-#define MDMODE_ADDRSEND 0x8
-
-struct sb_uart_state {
- unsigned int close_delay; /* msec */
- unsigned int closing_wait; /* msec */
-
-
- int count;
- int pm_state;
- struct sb_uart_info *info;
- struct sb_uart_port *port;
-
- struct mutex mutex;
-};
-
-typedef unsigned int uif_t;
-
-struct sb_uart_info {
- struct tty_struct *tty;
- struct circ_buf xmit;
- uif_t flags;
-
- int blocked_open;
-
- struct tasklet_struct tlet;
-
- wait_queue_head_t open_wait;
- wait_queue_head_t delta_msr_wait;
-};
-
-
-struct module;
-struct tty_driver;
-
-struct uart_driver {
- struct module *owner;
- const char *driver_name;
- const char *dev_name;
- int major;
- int minor;
- int nr;
- struct console *cons;
-
- struct sb_uart_state *state;
- struct tty_driver *tty_driver;
-};
-
-void sb_uart_write_wakeup(struct sb_uart_port *port)
-{
- struct sb_uart_info *info = port->info;
- tasklet_schedule(&info->tlet);
-}
-
-void sb_uart_update_timeout(struct sb_uart_port *port, unsigned int cflag,
- unsigned int baud)
-{
- unsigned int bits;
-
- switch (cflag & CSIZE)
- {
- case CS5:
- bits = 7;
- break;
-
- case CS6:
- bits = 8;
- break;
-
- case CS7:
- bits = 9;
- break;
-
- default:
- bits = 10;
- break;
- }
-
- if (cflag & CSTOPB)
- {
- bits++;
- }
-
- if (cflag & PARENB)
- {
- bits++;
- }
-
- bits = bits * port->fifosize;
-
- port->timeout = (HZ * bits) / baud + HZ/50;
-}
-unsigned int sb_uart_get_baud_rate(struct sb_uart_port *port, struct MP_TERMIOS *termios,
- struct MP_TERMIOS *old, unsigned int min,
- unsigned int max)
-{
- unsigned int try, baud, altbaud = 38400;
- upf_t flags = port->flags & UPF_SPD_MASK;
-
- if (flags == UPF_SPD_HI)
- altbaud = 57600;
- if (flags == UPF_SPD_VHI)
- altbaud = 115200;
- if (flags == UPF_SPD_SHI)
- altbaud = 230400;
- if (flags == UPF_SPD_WARP)
- altbaud = 460800;
-
- for (try = 0; try < 2; try++) {
-
- switch (termios->c_cflag & (CBAUD | CBAUDEX))
- {
- case B921600 : baud = 921600; break;
- case B460800 : baud = 460800; break;
- case B230400 : baud = 230400; break;
- case B115200 : baud = 115200; break;
- case B57600 : baud = 57600; break;
- case B38400 : baud = 38400; break;
- case B19200 : baud = 19200; break;
- case B9600 : baud = 9600; break;
- case B4800 : baud = 4800; break;
- case B2400 : baud = 2400; break;
- case B1800 : baud = 1800; break;
- case B1200 : baud = 1200; break;
- case B600 : baud = 600; break;
- case B300 : baud = 300; break;
- case B200 : baud = 200; break;
- case B150 : baud = 150; break;
- case B134 : baud = 134; break;
- case B110 : baud = 110; break;
- case B75 : baud = 75; break;
- case B50 : baud = 50; break;
- default : baud = 9600; break;
- }
-
- if (baud == 38400)
- baud = altbaud;
-
- if (baud == 0)
- baud = 9600;
-
- if (baud >= min && baud <= max)
- return baud;
-
- termios->c_cflag &= ~CBAUD;
- if (old) {
- termios->c_cflag |= old->c_cflag & CBAUD;
- old = NULL;
- continue;
- }
-
- termios->c_cflag |= B9600;
- }
-
- return 0;
-}
-unsigned int sb_uart_get_divisor(struct sb_uart_port *port, unsigned int baud)
-{
- unsigned int quot;
-
- if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
- quot = port->custom_divisor;
- else
- quot = (port->uartclk + (8 * baud)) / (16 * baud);
-
- return quot;
-}
-
-
-
-static inline int sb_uart_handle_break(struct sb_uart_port *port)
-{
- struct sb_uart_info *info = port->info;
-
- if (port->flags & UPF_SAK)
- do_SAK(info->tty);
- return 0;
-}
-
-static inline void sb_uart_handle_dcd_change(struct sb_uart_port *port, unsigned int status)
-{
- struct sb_uart_info *info = port->info;
-
- port->icount.dcd++;
-
- if (info->flags & UIF_CHECK_CD) {
- if (status)
- wake_up_interruptible(&info->open_wait);
- else if (info->tty)
- tty_hangup(info->tty);
- }
-}
-
-static inline void sb_uart_handle_cts_change(struct sb_uart_port *port, unsigned int status)
-{
- struct sb_uart_info *info = port->info;
- struct tty_struct *tty = info->tty;
-
- port->icount.cts++;
-
- if (info->flags & UIF_CTS_FLOW) {
- if (tty->hw_stopped) {
- if (status) {
- tty->hw_stopped = 0;
- port->ops->start_tx(port);
- sb_uart_write_wakeup(port);
- }
- } else {
- if (!status) {
- tty->hw_stopped = 1;
- port->ops->stop_tx(port);
- }
- }
- }
-}
-
-
-
diff --git a/drivers/staging/sbe-2t3e3/2t3e3.h b/drivers/staging/sbe-2t3e3/2t3e3.h
index ccad049c1122..e7bf721f3fd1 100644
--- a/drivers/staging/sbe-2t3e3/2t3e3.h
+++ b/drivers/staging/sbe-2t3e3/2t3e3.h
@@ -613,12 +613,12 @@
* descriptor list and data buffer
*
**********************************************************************/
-typedef struct {
+struct t3e3_rx_desc {
u32 rdes0;
u32 rdes1;
u32 rdes2;
u32 rdes3;
-} t3e3_rx_desc_t;
+};
#define SBE_2T3E3_RX_DESC_RING_SIZE 64
@@ -648,12 +648,12 @@ typedef struct {
/*********************/
-typedef struct {
+struct t3e3_tx_desc {
u32 tdes0;
u32 tdes1;
u32 tdes2;
u32 tdes3;
-} t3e3_tx_desc_t;
+};
#define SBE_2T3E3_TX_DESC_RING_SIZE 256
@@ -701,7 +701,7 @@ struct channel {
} h;
/* statistics */
- t3e3_stats_t s;
+ struct t3e3_stats s;
/* running */
struct {
@@ -709,7 +709,7 @@ struct channel {
} r;
/* parameters */
- t3e3_param_t p;
+ struct t3e3_param p;
u32 liu_regs[SBE_2T3E3_LIU_REG_MAX]; /* LIU registers */
u32 framer_regs[SBE_2T3E3_FRAMER_REG_MAX]; /* Framer registers */
@@ -723,12 +723,12 @@ struct channel {
u32 interrupt_enable_mask;
/* receive chain/ring */
- t3e3_rx_desc_t *rx_ring;
+ struct t3e3_rx_desc *rx_ring;
struct sk_buff *rx_data[SBE_2T3E3_RX_DESC_RING_SIZE];
u32 rx_ring_current_read;
/* transmit chain/ring */
- t3e3_tx_desc_t *tx_ring;
+ struct t3e3_tx_desc *tx_ring;
struct sk_buff *tx_data[SBE_2T3E3_TX_DESC_RING_SIZE];
u32 tx_ring_current_read;
u32 tx_ring_current_write;
@@ -760,8 +760,7 @@ void t3e3_init(struct channel *);
void t3e3_if_up(struct channel *);
void t3e3_if_down(struct channel *);
int t3e3_if_start_xmit(struct sk_buff *skb, struct net_device *dev);
-void t3e3_if_config(struct channel *, u32, char *,
- t3e3_resp_t *, int *);
+void t3e3_if_config(struct channel *, u32, char *, struct t3e3_resp *, int *);
void t3e3_set_frame_type(struct channel *, u32);
u32 t3e3_eeprom_read_word(struct channel *, u32);
void t3e3_read_card_serial_number(struct channel *);
@@ -838,7 +837,7 @@ static inline int has_two_ports(struct pci_dev *pdev)
return pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_2T3E3_P0;
}
-#define dev_to_priv(dev) (*(struct channel **) ((hdlc_device*)(dev) + 1))
+#define dev_to_priv(dev) (*(struct channel **) ((hdlc_device *)(dev) + 1))
static inline u32 dc_read(unsigned long addr, u32 reg)
{
diff --git a/drivers/staging/sbe-2t3e3/ctrl.c b/drivers/staging/sbe-2t3e3/ctrl.c
index d280bcfd660a..e0964ac9e7d7 100644
--- a/drivers/staging/sbe-2t3e3/ctrl.c
+++ b/drivers/staging/sbe-2t3e3/ctrl.c
@@ -164,12 +164,12 @@ static void t3e3_reg_write(struct channel *sc, u32 *reg)
}
}
-static void t3e3_port_get(struct channel *sc, t3e3_param_t *param)
+static void t3e3_port_get(struct channel *sc, struct t3e3_param *param)
{
- memcpy(param, &(sc->p), sizeof(t3e3_param_t));
+ memcpy(param, &(sc->p), sizeof(struct t3e3_param));
}
-static void t3e3_port_set(struct channel *sc, t3e3_param_t *param)
+static void t3e3_port_set(struct channel *sc, struct t3e3_param *param)
{
if (param->frame_mode != 0xff)
cpld_set_frame_mode(sc, param->frame_mode);
@@ -216,8 +216,7 @@ static void t3e3_port_set(struct channel *sc, t3e3_param_t *param)
cpld_set_scrambler(sc, param->scrambler);
}
-static void t3e3_port_get_stats(struct channel *sc,
- t3e3_stats_t *stats)
+static void t3e3_port_get_stats(struct channel *sc, struct t3e3_stats *stats)
{
u32 result;
@@ -279,18 +278,18 @@ static void t3e3_port_get_stats(struct channel *sc,
result += exar7250_read(sc, SBE_2T3E3_FRAMER_REG_PMON_HOLDING_REGISTER);
sc->s.CP_BIT += result;
- memcpy(stats, &(sc->s), sizeof(t3e3_stats_t));
+ memcpy(stats, &(sc->s), sizeof(struct t3e3_stats));
}
static void t3e3_port_del_stats(struct channel *sc)
{
- memset(&(sc->s), 0, sizeof(t3e3_stats_t));
+ memset(&(sc->s), 0, sizeof(struct t3e3_stats));
}
void t3e3_if_config(struct channel *sc, u32 cmd, char *set,
- t3e3_resp_t *ret, int *rlen)
+ struct t3e3_resp *ret, int *rlen)
{
- t3e3_param_t *param = (t3e3_param_t *)set;
+ struct t3e3_param *param = (struct t3e3_param *)set;
u32 *data = (u32 *)set;
/* turn off all interrupt */
diff --git a/drivers/staging/sbe-2t3e3/ctrl.h b/drivers/staging/sbe-2t3e3/ctrl.h
index c11a58871845..41f144d75c36 100644
--- a/drivers/staging/sbe-2t3e3/ctrl.h
+++ b/drivers/staging/sbe-2t3e3/ctrl.h
@@ -84,7 +84,7 @@
#define NG_SBE_2T3E3_NODE_TYPE "sbe2T3E3"
#define NG_SBE_2T3E3_COOKIE 0x03800891
-typedef struct t3e3_param {
+struct t3e3_param {
u_int8_t frame_mode; /* FRAME_MODE_* */
u_int8_t crc; /* CRC_* */
u_int8_t receiver_on; /* ON/OFF */
@@ -102,9 +102,9 @@ typedef struct t3e3_param {
u_int8_t fractional_mode; /* FRACTIONAL_MODE_* */
u_int8_t bandwidth_start; /* 0-255 */
u_int8_t bandwidth_stop; /* 0-255 */
-} t3e3_param_t;
+};
-typedef struct t3e3_stats {
+struct t3e3_stats {
u_int64_t in_bytes;
u32 in_packets, in_dropped;
u32 in_errors, in_error_desc, in_error_coll, in_error_drib,
@@ -117,15 +117,15 @@ typedef struct t3e3_stats {
u_int8_t LOC, LOF, OOF, LOS, AIS, FERF, IDLE, AIC, FEAC;
u_int16_t FEBE_code;
u32 LCV, FRAMING_BIT, PARITY_ERROR, FEBE_count, CP_BIT;
-} t3e3_stats_t;
+};
-typedef struct t3e3_resp {
+struct t3e3_resp {
union {
- t3e3_param_t param;
- t3e3_stats_t stats;
+ struct t3e3_param param;
+ struct t3e3_stats stats;
u32 data;
} u;
-} t3e3_resp_t;
+};
#endif /* CTRL_H */
diff --git a/drivers/staging/sbe-2t3e3/dc.c b/drivers/staging/sbe-2t3e3/dc.c
index f207b9e015ce..02510f67ac45 100644
--- a/drivers/staging/sbe-2t3e3/dc.c
+++ b/drivers/staging/sbe-2t3e3/dc.c
@@ -316,13 +316,13 @@ static int dc_init_descriptor_list(struct channel *sc)
if (sc->ether.rx_ring == NULL)
sc->ether.rx_ring = kcalloc(SBE_2T3E3_RX_DESC_RING_SIZE,
- sizeof(t3e3_rx_desc_t), GFP_KERNEL);
+ sizeof(struct t3e3_rx_desc), GFP_KERNEL);
if (sc->ether.rx_ring == NULL)
return -ENOMEM;
if (sc->ether.tx_ring == NULL)
sc->ether.tx_ring = kcalloc(SBE_2T3E3_TX_DESC_RING_SIZE,
- sizeof(t3e3_tx_desc_t), GFP_KERNEL);
+ sizeof(struct t3e3_tx_desc), GFP_KERNEL);
if (sc->ether.tx_ring == NULL) {
kfree(sc->ether.rx_ring);
sc->ether.rx_ring = NULL;
@@ -339,7 +339,8 @@ static int dc_init_descriptor_list(struct channel *sc)
SBE_2T3E3_RX_DESC_SECOND_ADDRESS_CHAINED | SBE_2T3E3_MTU;
if (sc->ether.rx_data[i] == NULL) {
- if (!(m = dev_alloc_skb(MCLBYTES))) {
+ m = dev_alloc_skb(MCLBYTES);
+ if (!m) {
for (j = 0; j < i; j++) {
dev_kfree_skb_any(sc->ether.rx_data[j]);
sc->ether.rx_data[j] = NULL;
diff --git a/drivers/staging/sbe-2t3e3/intr.c b/drivers/staging/sbe-2t3e3/intr.c
index efdeb7510047..1bf74b788008 100644
--- a/drivers/staging/sbe-2t3e3/intr.c
+++ b/drivers/staging/sbe-2t3e3/intr.c
@@ -118,7 +118,7 @@ void dc_intr_rx(struct channel *sc)
{
u32 current_read;
u32 error_mask, error;
- t3e3_rx_desc_t *current_desc;
+ struct t3e3_rx_desc *current_desc;
struct sk_buff *m, *m2;
unsigned rcv_len;
@@ -292,7 +292,7 @@ void dc_intr_tx(struct channel *sc)
{
u32 current_read, current_write;
u32 last_segment, error;
- t3e3_tx_desc_t *current_desc;
+ struct t3e3_tx_desc *current_desc;
spin_lock(&sc->ether.tx_lock);
diff --git a/drivers/staging/sbe-2t3e3/maps.c b/drivers/staging/sbe-2t3e3/maps.c
index 7084fbe7b794..e5494502cde1 100644
--- a/drivers/staging/sbe-2t3e3/maps.c
+++ b/drivers/staging/sbe-2t3e3/maps.c
@@ -13,8 +13,7 @@
#include <linux/kernel.h>
#include "2t3e3.h"
-const u32 cpld_reg_map[][2] =
-{
+const u32 cpld_reg_map[][2] = {
{ 0x0000, 0x0080 }, /* 0 - Port Control Register A (PCRA) */
{ 0x0004, 0x0084 }, /* 1 - Port Control Register B (PCRB) */
{ 0x0008, 0x0088 }, /* 2 - LCV Count Register (PLCR) */
@@ -35,8 +34,7 @@ const u32 cpld_reg_map[][2] =
{ 0x0070, 0x00f0 }, /* 17 - Port Bandwidth Stop (PBWL) */
};
-const u32 cpld_val_map[][2] =
-{
+const u32 cpld_val_map[][2] = {
{ 0x01, 0x02 }, /* LIU1 / LIU2 select for Serial Chip Select */
{ 0x04, 0x08 }, /* DAC1 / DAC2 select for Serial Chip Select */
{ 0x00, 0x04 }, /* LOOP1 / LOOP2 - select of loop timing source */
@@ -94,8 +92,7 @@ const u32 t3e3_framer_reg_map[] = {
0x81 /* 47 - LINE_INTERFACE_SCAN */
};
-const u32 t3e3_liu_reg_map[] =
-{
+const u32 t3e3_liu_reg_map[] = {
0x00, /* REG0 */
0x01, /* REG1 */
0x02, /* REG2 */
diff --git a/drivers/staging/sbe-2t3e3/module.c b/drivers/staging/sbe-2t3e3/module.c
index 0e32be5c2471..a6f93a43d216 100644
--- a/drivers/staging/sbe-2t3e3/module.c
+++ b/drivers/staging/sbe-2t3e3/module.c
@@ -122,7 +122,7 @@ static void t3e3_remove_card(struct pci_dev *pdev)
struct channel *channel0 = pci_get_drvdata(pdev);
struct card *card = channel0->card;
- del_timer(&card->timer);
+ del_timer_sync(&card->timer);
if (has_two_ports(channel0->pdev)) {
t3e3_remove_channel(&card->channels[1]);
pci_dev_put(card->channels[1].pdev);
diff --git a/drivers/staging/sbe-2t3e3/netdev.c b/drivers/staging/sbe-2t3e3/netdev.c
index 1f5088b3c10b..fe6c9513c9cd 100644
--- a/drivers/staging/sbe-2t3e3/netdev.c
+++ b/drivers/staging/sbe-2t3e3/netdev.c
@@ -25,8 +25,8 @@ static int t3e3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct channel *sc = dev_to_priv(dev);
int cmd_2t3e3, len, rlen;
- t3e3_param_t param;
- t3e3_resp_t resp;
+ struct t3e3_param param;
+ struct t3e3_resp resp;
void __user *data = ifr->ifr_data + sizeof(cmd_2t3e3) + sizeof(len);
if (cmd == SIOCWANDEV)
@@ -61,7 +61,7 @@ static struct net_device_stats *t3e3_get_stats(struct net_device *dev)
{
struct net_device_stats *nstats = &dev->stats;
struct channel *sc = dev_to_priv(dev);
- t3e3_stats_t *stats = &sc->s;
+ struct t3e3_stats *stats = &sc->s;
memset(nstats, 0, sizeof(struct net_device_stats));
nstats->rx_packets = stats->in_packets;
diff --git a/drivers/staging/sep/sep_crypto.c b/drivers/staging/sep/sep_crypto.c
index 7fc267550c65..965485f71fe9 100644
--- a/drivers/staging/sep/sep_crypto.c
+++ b/drivers/staging/sep/sep_crypto.c
@@ -112,7 +112,7 @@ static void sep_do_callback(struct work_struct *work)
* on what operation is to be done
*/
static int sep_submit_work(struct workqueue_struct *work_queue,
- void(*funct)(void *),
+ void (*funct)(void *),
void *data)
{
struct sep_work_struct *sep_work;
diff --git a/drivers/staging/sep/sep_main.c b/drivers/staging/sep/sep_main.c
index 122614c4092b..e301207eb0bd 100644
--- a/drivers/staging/sep/sep_main.c
+++ b/drivers/staging/sep/sep_main.c
@@ -1266,9 +1266,8 @@ static int sep_lock_user_pages(struct sep_device *sep,
/* Check the number of pages locked - if not all then exit with error */
if (result != num_pages) {
dev_warn(&sep->pdev->dev,
- "[PID%d] not all pages locked by get_user_pages, "
- "result 0x%X, num_pages 0x%X\n",
- current->pid, result, num_pages);
+ "[PID%d] not all pages locked by get_user_pages, result 0x%X, num_pages 0x%X\n",
+ current->pid, result, num_pages);
error = -ENOMEM;
goto end_function_with_error3;
}
@@ -1293,9 +1292,9 @@ static int sep_lock_user_pages(struct sep_device *sep,
lli_array[count].block_size = PAGE_SIZE;
dev_dbg(&sep->pdev->dev,
- "[PID%d] lli_array[%x].bus_address is %08lx, "
- "lli_array[%x].block_size is (hex) %x\n", current->pid,
- count, (unsigned long)lli_array[count].bus_address,
+ "[PID%d] lli_array[%x].bus_address is %08lx, lli_array[%x].block_size is (hex) %x\n",
+ current->pid, count,
+ (unsigned long)lli_array[count].bus_address,
count, lli_array[count].block_size);
}
@@ -1314,8 +1313,7 @@ static int sep_lock_user_pages(struct sep_device *sep,
"[PID%d] After check if page 0 has all data\n",
current->pid);
dev_dbg(&sep->pdev->dev,
- "[PID%d] lli_array[0].bus_address is (hex) %08lx, "
- "lli_array[0].block_size is (hex) %x\n",
+ "[PID%d] lli_array[0].bus_address is (hex) %08lx, lli_array[0].block_size is (hex) %x\n",
current->pid,
(unsigned long)lli_array[0].bus_address,
lli_array[0].block_size);
@@ -1332,8 +1330,7 @@ static int sep_lock_user_pages(struct sep_device *sep,
"[PID%d] After last page size adjustment\n",
current->pid);
dev_dbg(&sep->pdev->dev,
- "[PID%d] lli_array[%x].bus_address is (hex) %08lx, "
- "lli_array[%x].block_size is (hex) %x\n",
+ "[PID%d] lli_array[%x].bus_address is (hex) %08lx, lli_array[%x].block_size is (hex) %x\n",
current->pid,
num_pages - 1,
(unsigned long)lli_array[num_pages - 1].bus_address,
@@ -1449,8 +1446,7 @@ static int sep_lli_table_secure_dma(struct sep_device *sep,
start_page += PAGE_SIZE;
dev_dbg(&sep->pdev->dev,
- "[PID%d] lli_array[%x].bus_address is %08lx, "
- "lli_array[%x].block_size is (hex) %x\n",
+ "[PID%d] lli_array[%x].bus_address is %08lx, lli_array[%x].block_size is (hex) %x\n",
current->pid,
count, (unsigned long)lli_array[count].bus_address,
count, lli_array[count].block_size);
@@ -1469,8 +1465,7 @@ static int sep_lli_table_secure_dma(struct sep_device *sep,
dev_dbg(&sep->pdev->dev,
"[PID%d] After check if page 0 has all data\n"
- "lli_array[0].bus_address is (hex) %08lx, "
- "lli_array[0].block_size is (hex) %x\n",
+ "lli_array[0].bus_address is (hex) %08lx, lli_array[0].block_size is (hex) %x\n",
current->pid,
(unsigned long)lli_array[0].bus_address,
lli_array[0].block_size);
@@ -1484,8 +1479,7 @@ static int sep_lli_table_secure_dma(struct sep_device *sep,
dev_dbg(&sep->pdev->dev,
"[PID%d] After last page size adjustment\n"
- "lli_array[%x].bus_address is (hex) %08lx, "
- "lli_array[%x].block_size is (hex) %x\n",
+ "lli_array[%x].bus_address is (hex) %08lx, lli_array[%x].block_size is (hex) %x\n",
current->pid, num_pages - 1,
(unsigned long)lli_array[num_pages - 1].bus_address,
num_pages - 1,
@@ -1745,9 +1739,8 @@ static void sep_debug_print_lli_tables(struct sep_device *sep,
while ((unsigned long) lli_table_ptr->bus_address != 0xffffffff) {
dev_dbg(&sep->pdev->dev,
- "[PID%d] lli table %08lx, "
- "table_data_size is (hex) %lx\n",
- current->pid, table_count, table_data_size);
+ "[PID%d] lli table %08lx, table_data_size is (hex) %lx\n",
+ current->pid, table_count, table_data_size);
dev_dbg(&sep->pdev->dev,
"[PID%d] num_table_entries is (hex) %lx\n",
current->pid, num_table_entries);
@@ -1762,8 +1755,8 @@ static void sep_debug_print_lli_tables(struct sep_device *sep,
(unsigned long) lli_table_ptr);
dev_dbg(&sep->pdev->dev,
- "[PID%d] phys address is %08lx "
- "block size is (hex) %x\n", current->pid,
+ "[PID%d] phys address is %08lx block size is (hex) %x\n",
+ current->pid,
(unsigned long)lli_table_ptr->bus_address,
lli_table_ptr->block_size);
}
@@ -1772,14 +1765,12 @@ static void sep_debug_print_lli_tables(struct sep_device *sep,
lli_table_ptr--;
dev_dbg(&sep->pdev->dev,
- "[PID%d] phys lli_table_ptr->block_size "
- "is (hex) %x\n",
+ "[PID%d] phys lli_table_ptr->block_size is (hex) %x\n",
current->pid,
lli_table_ptr->block_size);
dev_dbg(&sep->pdev->dev,
- "[PID%d] phys lli_table_ptr->physical_address "
- "is %08lx\n",
+ "[PID%d] phys lli_table_ptr->physical_address is %08lx\n",
current->pid,
(unsigned long)lli_table_ptr->bus_address);
@@ -1788,13 +1779,11 @@ static void sep_debug_print_lli_tables(struct sep_device *sep,
num_table_entries = (lli_table_ptr->block_size >> 24) & 0xff;
dev_dbg(&sep->pdev->dev,
- "[PID%d] phys table_data_size is "
- "(hex) %lx num_table_entries is"
- " %lx bus_address is%lx\n",
- current->pid,
- table_data_size,
- num_table_entries,
- (unsigned long)lli_table_ptr->bus_address);
+ "[PID%d] phys table_data_size is (hex) %lx num_table_entries is %lx bus_address is%lx\n",
+ current->pid,
+ table_data_size,
+ num_table_entries,
+ (unsigned long)lli_table_ptr->bus_address);
if ((unsigned long)lli_table_ptr->bus_address != 0xffffffff)
lli_table_ptr = (struct sep_lli_entry *)
@@ -2244,14 +2233,12 @@ static int sep_construct_dma_tables_from_lli(
table_data_size = out_table_data_size;
dev_dbg(&sep->pdev->dev,
- "[PID%d] construct tables from lli"
- " in_table_data_size is (hex) %x\n", current->pid,
- in_table_data_size);
+ "[PID%d] construct tables from lli in_table_data_size is (hex) %x\n",
+ current->pid, in_table_data_size);
dev_dbg(&sep->pdev->dev,
- "[PID%d] construct tables from lli"
- "out_table_data_size is (hex) %x\n", current->pid,
- out_table_data_size);
+ "[PID%d] construct tables from lli out_table_data_size is (hex) %x\n",
+ current->pid, out_table_data_size);
/* Construct input lli table */
sep_build_lli_table(sep, &lli_in_array[current_in_entry],
@@ -2316,8 +2303,7 @@ static int sep_construct_dma_tables_from_lli(
info_in_entry_ptr->block_size);
dev_dbg(&sep->pdev->dev,
- "[PID%d] output lli_table_out_ptr:"
- "%08lx %08x\n",
+ "[PID%d] output lli_table_out_ptr: %08lx %08x\n",
current->pid,
(unsigned long)info_out_entry_ptr->bus_address,
info_out_entry_ptr->block_size);
@@ -2446,8 +2432,8 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep,
dma_ctx);
if (error) {
dev_warn(&sep->pdev->dev,
- "[PID%d] sep_lock_kernel_pages for input "
- "virtual buffer failed\n", current->pid);
+ "[PID%d] sep_lock_kernel_pages for input virtual buffer failed\n",
+ current->pid);
goto end_function;
}
@@ -2460,8 +2446,8 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep,
if (error) {
dev_warn(&sep->pdev->dev,
- "[PID%d] sep_lock_kernel_pages for output "
- "virtual buffer failed\n", current->pid);
+ "[PID%d] sep_lock_kernel_pages for output virtual buffer failed\n",
+ current->pid);
goto end_function_free_lli_in;
}
@@ -2476,8 +2462,8 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep,
dma_ctx);
if (error) {
dev_warn(&sep->pdev->dev,
- "[PID%d] sep_lock_user_pages for input "
- "virtual buffer failed\n", current->pid);
+ "[PID%d] sep_lock_user_pages for input virtual buffer failed\n",
+ current->pid);
goto end_function;
}
@@ -2491,8 +2477,7 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep,
SEP_DRIVER_OUT_FLAG, dma_ctx);
if (error) {
dev_warn(&sep->pdev->dev,
- "[PID%d] secure dma table setup "
- " for output virtual buffer failed\n",
+ "[PID%d] secure dma table setup for output virtual buffer failed\n",
current->pid);
goto end_function_free_lli_in;
@@ -2512,8 +2497,7 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep,
if (error) {
dev_warn(&sep->pdev->dev,
- "[PID%d] sep_lock_user_pages"
- " for output virtual buffer failed\n",
+ "[PID%d] sep_lock_user_pages for output virtual buffer failed\n",
current->pid);
goto end_function_free_lli_in;
@@ -2826,8 +2810,7 @@ int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep,
if (error) {
dev_warn(&sep->pdev->dev,
- "prepare DMA table call failed "
- "from prepare DCB call\n");
+ "prepare DMA table call failed from prepare DCB call\n");
goto end_function_error;
}
@@ -2889,7 +2872,8 @@ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet,
* Go over each DCB and see if
* tail pointer must be updated
*/
- for (i = 0; i < (*dma_ctx)->nr_dcb_creat; i++, dcb_table_ptr++) {
+ for (i = 0; i < (*dma_ctx)->nr_dcb_creat;
+ i++, dcb_table_ptr++) {
if (dcb_table_ptr->out_vr_tail_pt) {
pt_hold = (unsigned long)dcb_table_ptr->
out_vr_tail_pt;
@@ -3089,6 +3073,7 @@ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
dev_dbg(&sep->pdev->dev,
"[PID%d] SEP_IOCPREPAREDCB start\n",
current->pid);
+ /* fall-through */
case SEP_IOCPREPAREDCB_SECURE_DMA:
dev_dbg(&sep->pdev->dev,
"[PID%d] SEP_IOCPREPAREDCB_SECURE_DMA start\n",
@@ -3762,8 +3747,7 @@ static inline ssize_t sep_fastcall_args_get(struct sep_device *sep,
if (actual_count != count_user) {
dev_warn(&sep->pdev->dev,
- "[PID%d] inconsistent message "
- "sizes 0x%08zX vs 0x%08zX\n",
+ "[PID%d] inconsistent message sizes 0x%08zX vs 0x%08zX\n",
current->pid, actual_count, count_user);
error = -EMSGSIZE;
goto end_function;
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index f0fcbf7c7d7f..0267dd8b84b7 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -724,7 +724,7 @@ static int qt_startup(struct usb_serial *serial)
goto startup_error;
}
- switch (serial->dev->descriptor.idProduct) {
+ switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
case QUATECH_DSU100:
case QUATECH_QSU100:
case QUATECH_ESU100A:
@@ -762,7 +762,9 @@ static int qt_startup(struct usb_serial *serial)
}
- status = box_set_prebuffer_level(serial); /* sets to default value */
+ status = box_set_prebuffer_level(serial); /* sets to
+ * default value
+ */
if (status < 0) {
dev_dbg(dev, "box_set_prebuffer_level failed\n");
goto startup_error;
@@ -887,7 +889,8 @@ static int qt_open(struct tty_struct *tty,
(SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_CD);
/* Set Baud rate to default and turn off (default)flow control here */
- result = qt_setuart(serial, port->port_number, DEFAULT_DIVISOR, DEFAULT_LCR);
+ result = qt_setuart(serial, port->port_number, DEFAULT_DIVISOR,
+ DEFAULT_LCR);
if (result < 0) {
dev_dbg(&port->dev, "qt_setuart failed\n");
return result;
@@ -1014,11 +1017,13 @@ static void qt_close(struct usb_serial_port *port)
/* Close uart channel */
status = qt_close_channel(serial, index);
if (status < 0)
- dev_dbg(&port->dev, "%s - qt_close_channel failed.\n", __func__);
+ dev_dbg(&port->dev, "%s - qt_close_channel failed.\n",
+ __func__);
port0->open_ports--;
- dev_dbg(&port->dev, "qt_num_open_ports in close%d\n", port0->open_ports);
+ dev_dbg(&port->dev, "qt_num_open_ports in close%d\n",
+ port0->open_ports);
if (port0->open_ports == 0) {
if (serial->port[0]->interrupt_in_urb) {
@@ -1235,7 +1240,8 @@ static void qt_set_termios(struct tty_struct *tty,
/* Now determine flow control */
if (cflag & CRTSCTS) {
- dev_dbg(&port->dev, "%s - Enabling HW flow control\n", __func__);
+ dev_dbg(&port->dev, "%s - Enabling HW flow control\n",
+ __func__);
/* Enable RTS/CTS flow control */
status = box_set_hw_flow_ctrl(port->serial, index, 1);
diff --git a/drivers/staging/silicom/bp_mod.h b/drivers/staging/silicom/bp_mod.h
index 8154a7bf050f..82b4963e97b6 100644
--- a/drivers/staging/silicom/bp_mod.h
+++ b/drivers/staging/silicom/bp_mod.h
@@ -497,11 +497,19 @@ static inline unsigned int jiffies_to_msecs(const unsigned long j)
#define BPCTLI_STATUS 0x00008 /* Device Status - RO */
/* HW related */
-#define BPCTLI_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */
-#define BPCTLI_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+#define BPCTLI_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW
+ * Defineable Pin 6
+ */
+#define BPCTLI_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW
+ * Defineable Pin 7
+ */
#define BPCTLI_CTRL_SDP0_DATA 0x00040000 /* SWDPIN 0 value */
-#define BPCTLI_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */
-#define BPCTLI_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */
+#define BPCTLI_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6
+ * 0=in 1=out
+ */
+#define BPCTLI_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7
+ * 0=in 1=out
+ */
#define BPCTLI_CTRL_SDP0_DIR 0x00400000 /* SDP0 Input or output */
#define BPCTLI_CTRL_SWDPIN1 0x00080000
#define BPCTLI_CTRL_SDP1_DIR 0x00800000
@@ -565,7 +573,9 @@ static inline unsigned int jiffies_to_msecs(const unsigned long j)
#define BPCTLI_SWFW_PHY0_SM 0x02
#define BPCTLI_SWFW_PHY1_SM 0x04
-#define BPCTLI_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
+#define BPCTLI_SW_FW_SYNC 0x05B5C /* Software-Firmware
+ * Synchronization - RW
+ */
#define BPCTLI_SWSM 0x05B50 /* SW Semaphore */
#define BPCTLI_FWSM 0x05B54 /* FW Semaphore */
@@ -623,7 +633,8 @@ static inline unsigned int jiffies_to_msecs(const unsigned long j)
/*#define BP10G_MCLK_DATA_OUT9 BP10G_I2C_CLK_OUT
#define BP10G_MDIO_DATA_OUT9 BP10G_I2C_DATA_OUT*/
- /*#define BP10G_MCLK_DATA_OUT9*//*BP10G_I2C_DATA_OUT */
+ /*#define BP10G_MCLK_DATA_OUT9*/
+ /*BP10G_I2C_DATA_OUT */
#define BP10G_MDIO_DATA_OUT9 BP10G_I2C_DATA_OUT /*BP10G_I2C_CLK_OUT */
/* VIA EOSDP ! */
@@ -698,5 +709,3 @@ static inline unsigned int jiffies_to_msecs(const unsigned long j)
readl((void *)((a)->mem_map) + BP10GB_##reg))
#endif
-
-int bp_proc_create(void);
diff --git a/drivers/staging/silicom/bpctl_mod.c b/drivers/staging/silicom/bpctl_mod.c
index 20325f53328e..6b9365b28e8a 100644
--- a/drivers/staging/silicom/bpctl_mod.c
+++ b/drivers/staging/silicom/bpctl_mod.c
@@ -117,12 +117,12 @@ static int wdt_timer(struct bpctl_dev *pbpctl_dev, int *time_left);
static struct bpctl_dev *get_status_port_fn(struct bpctl_dev *pbpctl_dev);
static void if_scan_init(void);
-int bypass_proc_create_dev_sd(struct bpctl_dev *pbp_device_block);
-int bypass_proc_remove_dev_sd(struct bpctl_dev *pbp_device_block);
-int bp_proc_create(void);
+static int bypass_proc_create_dev_sd(struct bpctl_dev *pbp_device_block);
+static int bypass_proc_remove_dev_sd(struct bpctl_dev *pbp_device_block);
+static int bp_proc_create(void);
-int is_bypass_fn(struct bpctl_dev *pbpctl_dev);
-int get_dev_idx_bsf(int bus, int slot, int func);
+static int is_bypass_fn(struct bpctl_dev *pbpctl_dev);
+static int get_dev_idx_bsf(int bus, int slot, int func);
static int bp_get_dev_idx_bsf(struct net_device *dev, int *index)
{
@@ -262,7 +262,7 @@ static struct notifier_block bp_notifier_block = {
.notifier_call = bp_device_event,
};
-int is_bypass_fn(struct bpctl_dev *pbpctl_dev);
+static int is_bypass_fn(struct bpctl_dev *pbpctl_dev);
int wdt_time_left(struct bpctl_dev *pbpctl_dev);
static void write_pulse(struct bpctl_dev *pbpctl_dev,
@@ -1502,7 +1502,8 @@ static int send_wdt_pulse(struct bpctl_dev *pbpctl_dev)
return 0;
}
-void send_bypass_clear_pulse(struct bpctl_dev *pbpctl_dev, unsigned int value)
+static void send_bypass_clear_pulse(struct bpctl_dev *pbpctl_dev,
+ unsigned int value)
{
uint32_t ctrl_ext = 0;
@@ -1757,7 +1758,7 @@ static int wdt_pulse_int(struct bpctl_dev *pbpctl_dev)
/*************************************/
/* CMND_ON 0x4 (100)*/
-int cmnd_on(struct bpctl_dev *pbpctl_dev)
+static int cmnd_on(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -1774,7 +1775,7 @@ int cmnd_on(struct bpctl_dev *pbpctl_dev)
}
/* CMND_OFF 0x2 (10)*/
-int cmnd_off(struct bpctl_dev *pbpctl_dev)
+static int cmnd_off(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -1792,7 +1793,7 @@ int cmnd_off(struct bpctl_dev *pbpctl_dev)
}
/* BYPASS_ON (0xa)*/
-int bypass_on(struct bpctl_dev *pbpctl_dev)
+static int bypass_on(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -1813,7 +1814,7 @@ int bypass_on(struct bpctl_dev *pbpctl_dev)
}
/* BYPASS_OFF (0x8 111)*/
-int bypass_off(struct bpctl_dev *pbpctl_dev)
+static int bypass_off(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -1836,7 +1837,7 @@ int bypass_off(struct bpctl_dev *pbpctl_dev)
}
/* TAP_OFF (0x9)*/
-int tap_off(struct bpctl_dev *pbpctl_dev)
+static int tap_off(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if ((pbpctl_dev->bp_caps & TAP_CAP)
@@ -1849,7 +1850,7 @@ int tap_off(struct bpctl_dev *pbpctl_dev)
}
/* TAP_ON (0xb)*/
-int tap_on(struct bpctl_dev *pbpctl_dev)
+static int tap_on(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if ((pbpctl_dev->bp_caps & TAP_CAP)
@@ -1862,7 +1863,7 @@ int tap_on(struct bpctl_dev *pbpctl_dev)
}
/* DISC_OFF (0x9)*/
-int disc_off(struct bpctl_dev *pbpctl_dev)
+static int disc_off(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) {
@@ -1874,7 +1875,7 @@ int disc_off(struct bpctl_dev *pbpctl_dev)
}
/* DISC_ON (0xb)*/
-int disc_on(struct bpctl_dev *pbpctl_dev)
+static int disc_on(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) {
@@ -1885,58 +1886,8 @@ int disc_on(struct bpctl_dev *pbpctl_dev)
return ret;
}
-/* DISC_PORT_ON */
-int disc_port_on(struct bpctl_dev *pbpctl_dev)
-{
- int ret = 0;
- struct bpctl_dev *pbpctl_dev_m;
-
- if ((is_bypass_fn(pbpctl_dev)) == 1)
- pbpctl_dev_m = pbpctl_dev;
- else
- pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
- if (pbpctl_dev_m == NULL)
- return BP_NOT_CAP;
-
- if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
- if (is_bypass_fn(pbpctl_dev) == 1)
- write_data(pbpctl_dev_m, TX_DISA);
- else
- write_data(pbpctl_dev_m, TX_DISB);
-
- msec_delay_bp(LATCH_DELAY);
-
- }
- return ret;
-}
-
-/* DISC_PORT_OFF */
-int disc_port_off(struct bpctl_dev *pbpctl_dev)
-{
- int ret = 0;
- struct bpctl_dev *pbpctl_dev_m;
-
- if ((is_bypass_fn(pbpctl_dev)) == 1)
- pbpctl_dev_m = pbpctl_dev;
- else
- pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
- if (pbpctl_dev_m == NULL)
- return BP_NOT_CAP;
-
- if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
- if (is_bypass_fn(pbpctl_dev) == 1)
- write_data(pbpctl_dev_m, TX_ENA);
- else
- write_data(pbpctl_dev_m, TX_ENB);
-
- msec_delay_bp(LATCH_DELAY);
-
- }
- return ret;
-}
-
/*TWO_PORT_LINK_HW_EN (0xe)*/
-int tpl_hw_on(struct bpctl_dev *pbpctl_dev)
+static int tpl_hw_on(struct bpctl_dev *pbpctl_dev)
{
int ret = 0, ctrl = 0;
struct bpctl_dev *pbpctl_dev_b = NULL;
@@ -1964,7 +1915,7 @@ int tpl_hw_on(struct bpctl_dev *pbpctl_dev)
}
/*TWO_PORT_LINK_HW_DIS (0xc)*/
-int tpl_hw_off(struct bpctl_dev *pbpctl_dev)
+static int tpl_hw_off(struct bpctl_dev *pbpctl_dev)
{
int ret = 0, ctrl = 0;
struct bpctl_dev *pbpctl_dev_b = NULL;
@@ -1990,7 +1941,7 @@ int tpl_hw_off(struct bpctl_dev *pbpctl_dev)
}
/* WDT_OFF (0x6 110)*/
-int wdt_off(struct bpctl_dev *pbpctl_dev)
+static int wdt_off(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -2013,7 +1964,7 @@ int wdt_off(struct bpctl_dev *pbpctl_dev)
static unsigned int
wdt_val_array[] = { 1000, 1500, 2000, 3000, 4000, 8000, 16000, 32000, 0 };
-int wdt_on(struct bpctl_dev *pbpctl_dev, unsigned int timeout)
+static int wdt_on(struct bpctl_dev *pbpctl_dev, unsigned int timeout)
{
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -2065,7 +2016,7 @@ int wdt_on(struct bpctl_dev *pbpctl_dev, unsigned int timeout)
return BP_NOT_CAP;
}
-void bp75_put_hw_semaphore_generic(struct bpctl_dev *pbpctl_dev)
+static void bp75_put_hw_semaphore_generic(struct bpctl_dev *pbpctl_dev)
{
u32 swsm;
@@ -2076,7 +2027,7 @@ void bp75_put_hw_semaphore_generic(struct bpctl_dev *pbpctl_dev)
BPCTL_WRITE_REG(pbpctl_dev, SWSM, swsm);
}
-s32 bp75_get_hw_semaphore_generic(struct bpctl_dev *pbpctl_dev)
+static s32 bp75_get_hw_semaphore_generic(struct bpctl_dev *pbpctl_dev)
{
u32 swsm;
s32 ret_val = 0;
@@ -2190,7 +2141,8 @@ static s32 bp75_acquire_phy(struct bpctl_dev *pbpctl_dev)
return ret_val;
}
-s32 bp75_read_phy_reg_mdic(struct bpctl_dev *pbpctl_dev, u32 offset, u16 *data)
+static s32 bp75_read_phy_reg_mdic(struct bpctl_dev *pbpctl_dev, u32 offset,
+ u16 *data)
{
u32 i, mdic = 0;
s32 ret_val = 0;
@@ -2223,7 +2175,8 @@ s32 bp75_read_phy_reg_mdic(struct bpctl_dev *pbpctl_dev, u32 offset, u16 *data)
return ret_val;
}
-s32 bp75_write_phy_reg_mdic(struct bpctl_dev *pbpctl_dev, u32 offset, u16 data)
+static s32 bp75_write_phy_reg_mdic(struct bpctl_dev *pbpctl_dev, u32 offset,
+ u16 data)
{
u32 i, mdic = 0;
s32 ret_val = 0;
@@ -2353,11 +2306,10 @@ static int set_tx(struct bpctl_dev *pbpctl_dev, int tx_state)
if (PEG5_IF_SERIES(pbpctl_dev->subdevice)) {
if (tx_state) {
uint16_t mii_reg;
- if (!
- (ret =
- bp75_read_phy_reg(pbpctl_dev,
- BPCTLI_PHY_CONTROL,
- &mii_reg))) {
+ ret = bp75_read_phy_reg(pbpctl_dev,
+ BPCTLI_PHY_CONTROL,
+ &mii_reg);
+ if (!ret) {
if (mii_reg & BPCTLI_MII_CR_POWER_DOWN) {
ret =
bp75_write_phy_reg
@@ -2369,17 +2321,15 @@ static int set_tx(struct bpctl_dev *pbpctl_dev, int tx_state)
}
} else {
uint16_t mii_reg;
- if (!
- (ret =
- bp75_read_phy_reg(pbpctl_dev,
- BPCTLI_PHY_CONTROL,
- &mii_reg))) {
+ ret = bp75_read_phy_reg(pbpctl_dev,
+ BPCTLI_PHY_CONTROL,
+ &mii_reg);
+ if (!ret) {
mii_reg |= BPCTLI_MII_CR_POWER_DOWN;
- ret =
- bp75_write_phy_reg(pbpctl_dev,
- BPCTLI_PHY_CONTROL,
- mii_reg);
+ ret = bp75_write_phy_reg(pbpctl_dev,
+ BPCTLI_PHY_CONTROL,
+ mii_reg);
}
}
@@ -2534,7 +2484,7 @@ static int set_bp_force_link(struct bpctl_dev *pbpctl_dev, int tx_state)
}
/*RESET_CONT 0x20 */
-int reset_cont(struct bpctl_dev *pbpctl_dev)
+static int reset_cont(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -2551,7 +2501,7 @@ int reset_cont(struct bpctl_dev *pbpctl_dev)
}
/*DIS_BYPASS_CAP 0x22 */
-int dis_bypass_cap(struct bpctl_dev *pbpctl_dev)
+static int dis_bypass_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
@@ -2570,7 +2520,7 @@ int dis_bypass_cap(struct bpctl_dev *pbpctl_dev)
}
/*EN_BYPASS_CAP 0x24 */
-int en_bypass_cap(struct bpctl_dev *pbpctl_dev)
+static int en_bypass_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
@@ -2586,7 +2536,7 @@ int en_bypass_cap(struct bpctl_dev *pbpctl_dev)
}
/* BYPASS_STATE_PWRON 0x26*/
-int bypass_state_pwron(struct bpctl_dev *pbpctl_dev)
+static int bypass_state_pwron(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) {
write_data(pbpctl_dev, BYPASS_STATE_PWRON);
@@ -2600,7 +2550,7 @@ int bypass_state_pwron(struct bpctl_dev *pbpctl_dev)
}
/* NORMAL_STATE_PWRON 0x28*/
-int normal_state_pwron(struct bpctl_dev *pbpctl_dev)
+static int normal_state_pwron(struct bpctl_dev *pbpctl_dev)
{
if ((pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP)
|| (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP)) {
@@ -2615,7 +2565,7 @@ int normal_state_pwron(struct bpctl_dev *pbpctl_dev)
}
/* BYPASS_STATE_PWROFF 0x27*/
-int bypass_state_pwroff(struct bpctl_dev *pbpctl_dev)
+static int bypass_state_pwroff(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP) {
write_data(pbpctl_dev, BYPASS_STATE_PWROFF);
@@ -2626,7 +2576,7 @@ int bypass_state_pwroff(struct bpctl_dev *pbpctl_dev)
}
/* NORMAL_STATE_PWROFF 0x29*/
-int normal_state_pwroff(struct bpctl_dev *pbpctl_dev)
+static int normal_state_pwroff(struct bpctl_dev *pbpctl_dev)
{
if ((pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP)) {
write_data(pbpctl_dev, NORMAL_STATE_PWROFF);
@@ -2637,7 +2587,7 @@ int normal_state_pwroff(struct bpctl_dev *pbpctl_dev)
}
/*TAP_STATE_PWRON 0x2a*/
-int tap_state_pwron(struct bpctl_dev *pbpctl_dev)
+static int tap_state_pwron(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
write_data(pbpctl_dev, TAP_STATE_PWRON);
@@ -2648,7 +2598,7 @@ int tap_state_pwron(struct bpctl_dev *pbpctl_dev)
}
/*DIS_TAP_CAP 0x2c*/
-int dis_tap_cap(struct bpctl_dev *pbpctl_dev)
+static int dis_tap_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
write_data(pbpctl_dev, DIS_TAP_CAP);
@@ -2659,7 +2609,7 @@ int dis_tap_cap(struct bpctl_dev *pbpctl_dev)
}
/*EN_TAP_CAP 0x2e*/
-int en_tap_cap(struct bpctl_dev *pbpctl_dev)
+static int en_tap_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
write_data(pbpctl_dev, EN_TAP_CAP);
@@ -2670,7 +2620,7 @@ int en_tap_cap(struct bpctl_dev *pbpctl_dev)
}
/*DISC_STATE_PWRON 0x2a*/
-int disc_state_pwron(struct bpctl_dev *pbpctl_dev)
+static int disc_state_pwron(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8) {
@@ -2683,7 +2633,7 @@ int disc_state_pwron(struct bpctl_dev *pbpctl_dev)
}
/*DIS_DISC_CAP 0x2c*/
-int dis_disc_cap(struct bpctl_dev *pbpctl_dev)
+static int dis_disc_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DISC_DIS_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8) {
@@ -2695,60 +2645,8 @@ int dis_disc_cap(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-/*DISC_STATE_PWRON 0x2a*/
-int disc_port_state_pwron(struct bpctl_dev *pbpctl_dev)
-{
- int ret = 0;
- struct bpctl_dev *pbpctl_dev_m;
-
- return BP_NOT_CAP;
-
- if ((is_bypass_fn(pbpctl_dev)) == 1)
- pbpctl_dev_m = pbpctl_dev;
- else
- pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
- if (pbpctl_dev_m == NULL)
- return BP_NOT_CAP;
-
- if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
- if (is_bypass_fn(pbpctl_dev) == 1)
- write_data(pbpctl_dev_m, TX_DISA_PWRUP);
- else
- write_data(pbpctl_dev_m, TX_DISB_PWRUP);
-
- msec_delay_bp(LATCH_DELAY);
-
- }
- return ret;
-}
-
-int normal_port_state_pwron(struct bpctl_dev *pbpctl_dev)
-{
- int ret = 0;
- struct bpctl_dev *pbpctl_dev_m;
- return BP_NOT_CAP;
-
- if ((is_bypass_fn(pbpctl_dev)) == 1)
- pbpctl_dev_m = pbpctl_dev;
- else
- pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
- if (pbpctl_dev_m == NULL)
- return BP_NOT_CAP;
-
- if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
- if (is_bypass_fn(pbpctl_dev) == 1)
- write_data(pbpctl_dev_m, TX_ENA_PWRUP);
- else
- write_data(pbpctl_dev_m, TX_ENB_PWRUP);
-
- msec_delay_bp(LATCH_DELAY);
-
- }
- return ret;
-}
-
/*EN_TAP_CAP 0x2e*/
-int en_disc_cap(struct bpctl_dev *pbpctl_dev)
+static int en_disc_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DISC_DIS_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8) {
@@ -2760,7 +2658,7 @@ int en_disc_cap(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int std_nic_on(struct bpctl_dev *pbpctl_dev)
+static int std_nic_on(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & STD_NIC_CAP) {
@@ -2814,7 +2712,7 @@ int std_nic_on(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int std_nic_off(struct bpctl_dev *pbpctl_dev)
+static int std_nic_off(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & STD_NIC_CAP) {
@@ -2977,7 +2875,7 @@ static void wd_reset_timer(unsigned long param)
}
/*WAIT_AT_PWRUP 0x80 */
-int bp_wait_at_pwup_en(struct bpctl_dev *pbpctl_dev)
+static int bp_wait_at_pwup_en(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -2992,7 +2890,7 @@ int bp_wait_at_pwup_en(struct bpctl_dev *pbpctl_dev)
}
/*DIS_WAIT_AT_PWRUP 0x81 */
-int bp_wait_at_pwup_dis(struct bpctl_dev *pbpctl_dev)
+static int bp_wait_at_pwup_dis(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3009,7 +2907,7 @@ int bp_wait_at_pwup_dis(struct bpctl_dev *pbpctl_dev)
/*EN_HW_RESET 0x82 */
-int bp_hw_reset_en(struct bpctl_dev *pbpctl_dev)
+static int bp_hw_reset_en(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3025,7 +2923,7 @@ int bp_hw_reset_en(struct bpctl_dev *pbpctl_dev)
/*DIS_HW_RESET 0x83 */
-int bp_hw_reset_dis(struct bpctl_dev *pbpctl_dev)
+static int bp_hw_reset_dis(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3040,7 +2938,7 @@ int bp_hw_reset_dis(struct bpctl_dev *pbpctl_dev)
}
-int wdt_exp_mode(struct bpctl_dev *pbpctl_dev, int mode)
+static int wdt_exp_mode(struct bpctl_dev *pbpctl_dev, int mode)
{
uint32_t status_reg = 0, status_reg1 = 0;
@@ -3091,7 +2989,7 @@ int wdt_exp_mode(struct bpctl_dev *pbpctl_dev, int mode)
return BP_NOT_CAP;
}
-int bypass_fw_ver(struct bpctl_dev *pbpctl_dev)
+static int bypass_fw_ver(struct bpctl_dev *pbpctl_dev)
{
if (is_bypass_fn(pbpctl_dev))
return read_reg(pbpctl_dev, VER_REG_ADDR);
@@ -3099,7 +2997,7 @@ int bypass_fw_ver(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int bypass_sign_check(struct bpctl_dev *pbpctl_dev)
+static int bypass_sign_check(struct bpctl_dev *pbpctl_dev)
{
if (is_bypass_fn(pbpctl_dev))
@@ -3210,7 +3108,7 @@ static int bp_force_link_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int bypass_from_last_read(struct bpctl_dev *pbpctl_dev)
+static int bypass_from_last_read(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0;
struct bpctl_dev *pbpctl_dev_b = NULL;
@@ -3230,7 +3128,7 @@ int bypass_from_last_read(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int bypass_status_clear(struct bpctl_dev *pbpctl_dev)
+static int bypass_status_clear(struct bpctl_dev *pbpctl_dev)
{
struct bpctl_dev *pbpctl_dev_b = NULL;
@@ -3244,7 +3142,7 @@ int bypass_status_clear(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int bypass_flag_status(struct bpctl_dev *pbpctl_dev)
+static int bypass_flag_status(struct bpctl_dev *pbpctl_dev)
{
if ((pbpctl_dev->bp_caps & BP_CAP)) {
@@ -3257,7 +3155,7 @@ int bypass_flag_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int bypass_flag_status_clear(struct bpctl_dev *pbpctl_dev)
+static int bypass_flag_status_clear(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_CAP) {
@@ -3272,7 +3170,7 @@ int bypass_flag_status_clear(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int bypass_change_status(struct bpctl_dev *pbpctl_dev)
+static int bypass_change_status(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -3291,18 +3189,6 @@ int bypass_change_status(struct bpctl_dev *pbpctl_dev)
return ret;
}
-int bypass_off_status(struct bpctl_dev *pbpctl_dev)
-{
-
- if (pbpctl_dev->bp_caps & BP_CAP) {
- if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
- return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) &
- BYPASS_OFF_MASK) == BYPASS_OFF_MASK) ? 1 : 0);
- }
- }
- return BP_NOT_CAP;
-}
-
static int bypass_status(struct bpctl_dev *pbpctl_dev)
{
u32 ctrl_ext = 0;
@@ -3386,7 +3272,7 @@ static int bypass_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int default_pwron_status(struct bpctl_dev *pbpctl_dev)
+static int default_pwron_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3418,7 +3304,7 @@ static int default_pwroff_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int dis_bypass_cap_status(struct bpctl_dev *pbpctl_dev)
+static int dis_bypass_cap_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
@@ -3431,31 +3317,7 @@ int dis_bypass_cap_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int cmd_en_status(struct bpctl_dev *pbpctl_dev)
-{
-
- if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
- if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
- return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) &
- CMND_EN_MASK) == CMND_EN_MASK) ? 1 : 0);
- }
- }
- return BP_NOT_CAP;
-}
-
-int wdt_en_status(struct bpctl_dev *pbpctl_dev)
-{
-
- if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
- if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) {
- return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) &
- WDT_EN_MASK) == WDT_EN_MASK) ? 1 : 0);
- }
- }
- return BP_NOT_CAP;
-}
-
-int wdt_programmed(struct bpctl_dev *pbpctl_dev, int *timeout)
+static int wdt_programmed(struct bpctl_dev *pbpctl_dev, int *timeout)
{
int ret = 0;
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -3481,40 +3343,7 @@ int wdt_programmed(struct bpctl_dev *pbpctl_dev, int *timeout)
return ret;
}
-int bypass_support(struct bpctl_dev *pbpctl_dev)
-{
- int ret = 0;
-
- if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
- if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) {
- ret =
- ((((read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR)) &
- BYPASS_SUPPORT_MASK) ==
- BYPASS_SUPPORT_MASK) ? 1 : 0);
- } else if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER)
- ret = 1;
- } else
- ret = BP_NOT_CAP;
- return ret;
-}
-
-int tap_support(struct bpctl_dev *pbpctl_dev)
-{
- int ret = 0;
-
- if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
- if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) {
- ret =
- ((((read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR)) &
- TAP_SUPPORT_MASK) == TAP_SUPPORT_MASK) ? 1 : 0);
- } else if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER)
- ret = 0;
- } else
- ret = BP_NOT_CAP;
- return ret;
-}
-
-int normal_support(struct bpctl_dev *pbpctl_dev)
+static int normal_support(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -3530,7 +3359,7 @@ int normal_support(struct bpctl_dev *pbpctl_dev)
return ret;
}
-int get_bp_prod_caps(struct bpctl_dev *pbpctl_dev)
+static int get_bp_prod_caps(struct bpctl_dev *pbpctl_dev)
{
if ((pbpctl_dev->bp_caps & SW_CTL_CAP) &&
(pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER))
@@ -3539,7 +3368,7 @@ int get_bp_prod_caps(struct bpctl_dev *pbpctl_dev)
}
-int tap_flag_status(struct bpctl_dev *pbpctl_dev)
+static int tap_flag_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_STATUS_CAP) {
@@ -3551,7 +3380,7 @@ int tap_flag_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int tap_flag_status_clear(struct bpctl_dev *pbpctl_dev)
+static int tap_flag_status_clear(struct bpctl_dev *pbpctl_dev)
{
uint32_t status_reg = 0;
if (pbpctl_dev->bp_caps & TAP_STATUS_CAP) {
@@ -3565,7 +3394,7 @@ int tap_flag_status_clear(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int tap_change_status(struct bpctl_dev *pbpctl_dev)
+static int tap_change_status(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) {
@@ -3582,17 +3411,7 @@ int tap_change_status(struct bpctl_dev *pbpctl_dev)
return ret;
}
-int tap_off_status(struct bpctl_dev *pbpctl_dev)
-{
- if (pbpctl_dev->bp_caps & TAP_CAP) {
- if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
- return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) &
- TAP_OFF_MASK) == TAP_OFF_MASK) ? 1 : 0);
- }
- return BP_NOT_CAP;
-}
-
-int tap_status(struct bpctl_dev *pbpctl_dev)
+static int tap_status(struct bpctl_dev *pbpctl_dev)
{
u32 ctrl_ext = 0;
@@ -3631,7 +3450,7 @@ int tap_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int default_pwron_tap_status(struct bpctl_dev *pbpctl_dev)
+static int default_pwron_tap_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
@@ -3642,7 +3461,7 @@ int default_pwron_tap_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int dis_tap_cap_status(struct bpctl_dev *pbpctl_dev)
+static int dis_tap_cap_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
@@ -3653,7 +3472,7 @@ int dis_tap_cap_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int disc_flag_status(struct bpctl_dev *pbpctl_dev)
+static int disc_flag_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DISC_CAP) {
@@ -3665,7 +3484,7 @@ int disc_flag_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int disc_flag_status_clear(struct bpctl_dev *pbpctl_dev)
+static int disc_flag_status_clear(struct bpctl_dev *pbpctl_dev)
{
uint32_t status_reg = 0;
if (pbpctl_dev->bp_caps & DISC_CAP) {
@@ -3679,7 +3498,7 @@ int disc_flag_status_clear(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int disc_change_status(struct bpctl_dev *pbpctl_dev)
+static int disc_change_status(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if (pbpctl_dev->bp_caps & DISC_CAP) {
@@ -3690,7 +3509,7 @@ int disc_change_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int disc_off_status(struct bpctl_dev *pbpctl_dev)
+static int disc_off_status(struct bpctl_dev *pbpctl_dev)
{
struct bpctl_dev *pbpctl_dev_b = NULL;
u32 ctrl_ext = 0;
@@ -3786,7 +3605,7 @@ static int disc_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int default_pwron_disc_status(struct bpctl_dev *pbpctl_dev)
+static int default_pwron_disc_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8)
@@ -3797,7 +3616,7 @@ int default_pwron_disc_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int dis_disc_cap_status(struct bpctl_dev *pbpctl_dev)
+static int dis_disc_cap_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DIS_DISC_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8)
@@ -3808,55 +3627,7 @@ int dis_disc_cap_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int disc_port_status(struct bpctl_dev *pbpctl_dev)
-{
- int ret = BP_NOT_CAP;
- struct bpctl_dev *pbpctl_dev_m;
-
- if ((is_bypass_fn(pbpctl_dev)) == 1)
- pbpctl_dev_m = pbpctl_dev;
- else
- pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
- if (pbpctl_dev_m == NULL)
- return BP_NOT_CAP;
-
- if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
- if (is_bypass_fn(pbpctl_dev) == 1) {
- return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) &
- TX_DISA_MASK) == TX_DISA_MASK) ? 1 : 0);
- } else
- return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) &
- TX_DISB_MASK) == TX_DISB_MASK) ? 1 : 0);
-
- }
- return ret;
-}
-
-int default_pwron_disc_port_status(struct bpctl_dev *pbpctl_dev)
-{
- int ret = BP_NOT_CAP;
- struct bpctl_dev *pbpctl_dev_m;
-
- if ((is_bypass_fn(pbpctl_dev)) == 1)
- pbpctl_dev_m = pbpctl_dev;
- else
- pbpctl_dev_m = get_master_port_fn(pbpctl_dev);
- if (pbpctl_dev_m == NULL)
- return BP_NOT_CAP;
-
- if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) {
- if (is_bypass_fn(pbpctl_dev) == 1)
- return ret;
- /* return((((read_reg(pbpctl_dev,STATUS_TAP_REG_ADDR)) & TX_DISA_MASK)==TX_DISA_MASK)?1:0); */
- else
- return ret;
- /* return((((read_reg(pbpctl_dev,STATUS_TAP_REG_ADDR)) & TX_DISA_MASK)==TX_DISA_MASK)?1:0); */
-
- }
- return ret;
-}
-
-int wdt_exp_mode_status(struct bpctl_dev *pbpctl_dev)
+static int wdt_exp_mode_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
if (pbpctl_dev->bp_ext_ver <= PXG2BPI_VER)
@@ -3879,7 +3650,7 @@ int wdt_exp_mode_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int tpl2_flag_status(struct bpctl_dev *pbpctl_dev)
+static int tpl2_flag_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) {
@@ -3890,22 +3661,7 @@ int tpl2_flag_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int tpl_hw_status(struct bpctl_dev *pbpctl_dev)
-{
- struct bpctl_dev *pbpctl_dev_b = NULL;
-
- pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
- if (!pbpctl_dev_b)
- return BP_NOT_CAP;
-
- if (TPL_IF_SERIES(pbpctl_dev->subdevice))
- return (((BPCTL_READ_REG(pbpctl_dev, CTRL)) &
- BPCTLI_CTRL_SWDPIN0) != 0 ? 1 : 0);
- return BP_NOT_CAP;
-}
-
-
-int bp_wait_at_pwup_status(struct bpctl_dev *pbpctl_dev)
+static int bp_wait_at_pwup_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8)
@@ -3916,7 +3672,7 @@ int bp_wait_at_pwup_status(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int bp_hw_reset_status(struct bpctl_dev *pbpctl_dev)
+static int bp_hw_reset_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3930,7 +3686,7 @@ int bp_hw_reset_status(struct bpctl_dev *pbpctl_dev)
}
-int std_nic_status(struct bpctl_dev *pbpctl_dev)
+static int std_nic_status(struct bpctl_dev *pbpctl_dev)
{
int status_val = 0;
@@ -3978,7 +3734,7 @@ int std_nic_status(struct bpctl_dev *pbpctl_dev)
/******************************************************/
/**************SW_INIT*********************************/
/******************************************************/
-void bypass_caps_init(struct bpctl_dev *pbpctl_dev)
+static void bypass_caps_init(struct bpctl_dev *pbpctl_dev)
{
u_int32_t ctrl_ext = 0;
struct bpctl_dev *pbpctl_dev_m = NULL;
@@ -4196,23 +3952,7 @@ void bypass_caps_init(struct bpctl_dev *pbpctl_dev)
}
}
-int bypass_off_init(struct bpctl_dev *pbpctl_dev)
-{
- int ret = cmnd_on(pbpctl_dev);
- if (ret < 0)
- return ret;
- if (INTEL_IF_SERIES(pbpctl_dev->subdevice))
- return dis_bypass_cap(pbpctl_dev);
- wdt_off(pbpctl_dev);
- if (pbpctl_dev->bp_caps & BP_CAP)
- bypass_off(pbpctl_dev);
- if (pbpctl_dev->bp_caps & TAP_CAP)
- tap_off(pbpctl_dev);
- cmnd_off(pbpctl_dev);
- return 0;
-}
-
-void remove_bypass_wd_auto(struct bpctl_dev *pbpctl_dev)
+static void remove_bypass_wd_auto(struct bpctl_dev *pbpctl_dev)
{
#ifdef BP_SELF_TEST
struct bpctl_dev *pbpctl_dev_sl = NULL;
@@ -4241,7 +3981,7 @@ void remove_bypass_wd_auto(struct bpctl_dev *pbpctl_dev)
}
-int init_bypass_wd_auto(struct bpctl_dev *pbpctl_dev)
+static int init_bypass_wd_auto(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
init_timer(&pbpctl_dev->bp_timer);
@@ -4288,7 +4028,7 @@ int bp_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
#endif
-int set_bypass_wd_auto(struct bpctl_dev *pbpctl_dev, unsigned int param)
+static int set_bypass_wd_auto(struct bpctl_dev *pbpctl_dev, unsigned int param)
{
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
if (pbpctl_dev->reset_time != param) {
@@ -4307,7 +4047,7 @@ int set_bypass_wd_auto(struct bpctl_dev *pbpctl_dev, unsigned int param)
return BP_NOT_CAP;
}
-int get_bypass_wd_auto(struct bpctl_dev *pbpctl_dev)
+static int get_bypass_wd_auto(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & WD_CTL_CAP)
return pbpctl_dev->reset_time;
@@ -4378,7 +4118,7 @@ int is_bypass_fn(struct bpctl_dev *pbpctl_dev)
return (((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2)) ? 1 : 0);
}
-int set_bypass_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
+static int set_bypass_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
{
int ret = 0;
@@ -4396,12 +4136,12 @@ int set_bypass_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
return ret;
}
-int get_bypass_fn(struct bpctl_dev *pbpctl_dev)
+static int get_bypass_fn(struct bpctl_dev *pbpctl_dev)
{
return bypass_status(pbpctl_dev);
}
-int get_bypass_change_fn(struct bpctl_dev *pbpctl_dev)
+static int get_bypass_change_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4409,7 +4149,7 @@ int get_bypass_change_fn(struct bpctl_dev *pbpctl_dev)
return bypass_change_status(pbpctl_dev);
}
-int set_dis_bypass_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
+static int set_dis_bypass_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4428,7 +4168,7 @@ int set_dis_bypass_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
return ret;
}
-int get_dis_bypass_fn(struct bpctl_dev *pbpctl_dev)
+static int get_dis_bypass_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4436,7 +4176,7 @@ int get_dis_bypass_fn(struct bpctl_dev *pbpctl_dev)
return dis_bypass_cap_status(pbpctl_dev);
}
-int set_bypass_pwoff_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
+static int set_bypass_pwoff_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4455,7 +4195,7 @@ int set_bypass_pwoff_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
return ret;
}
-int get_bypass_pwoff_fn(struct bpctl_dev *pbpctl_dev)
+static int get_bypass_pwoff_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4463,7 +4203,7 @@ int get_bypass_pwoff_fn(struct bpctl_dev *pbpctl_dev)
return default_pwroff_status(pbpctl_dev);
}
-int set_bypass_pwup_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
+static int set_bypass_pwup_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4482,7 +4222,7 @@ int set_bypass_pwup_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
return ret;
}
-int get_bypass_pwup_fn(struct bpctl_dev *pbpctl_dev)
+static int get_bypass_pwup_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4490,7 +4230,7 @@ int get_bypass_pwup_fn(struct bpctl_dev *pbpctl_dev)
return default_pwron_status(pbpctl_dev);
}
-int set_bypass_wd_fn(struct bpctl_dev *pbpctl_dev, int timeout)
+static int set_bypass_wd_fn(struct bpctl_dev *pbpctl_dev, int timeout)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4512,7 +4252,7 @@ int set_bypass_wd_fn(struct bpctl_dev *pbpctl_dev, int timeout)
return ret;
}
-int get_bypass_wd_fn(struct bpctl_dev *pbpctl_dev, int *timeout)
+static int get_bypass_wd_fn(struct bpctl_dev *pbpctl_dev, int *timeout)
{
if (!pbpctl_dev)
return -1;
@@ -4520,7 +4260,7 @@ int get_bypass_wd_fn(struct bpctl_dev *pbpctl_dev, int *timeout)
return wdt_programmed(pbpctl_dev, timeout);
}
-int get_wd_expire_time_fn(struct bpctl_dev *pbpctl_dev, int *time_left)
+static int get_wd_expire_time_fn(struct bpctl_dev *pbpctl_dev, int *time_left)
{
if (!pbpctl_dev)
return -1;
@@ -4528,7 +4268,7 @@ int get_wd_expire_time_fn(struct bpctl_dev *pbpctl_dev, int *time_left)
return wdt_timer(pbpctl_dev, time_left);
}
-int reset_bypass_wd_timer_fn(struct bpctl_dev *pbpctl_dev)
+static int reset_bypass_wd_timer_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4536,7 +4276,7 @@ int reset_bypass_wd_timer_fn(struct bpctl_dev *pbpctl_dev)
return wdt_timer_reload(pbpctl_dev);
}
-int get_wd_set_caps_fn(struct bpctl_dev *pbpctl_dev)
+static int get_wd_set_caps_fn(struct bpctl_dev *pbpctl_dev)
{
int bp_status = 0;
@@ -4560,7 +4300,7 @@ int get_wd_set_caps_fn(struct bpctl_dev *pbpctl_dev)
return bp_status;
}
-int set_std_nic_fn(struct bpctl_dev *pbpctl_dev, int nic_mode)
+static int set_std_nic_fn(struct bpctl_dev *pbpctl_dev, int nic_mode)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4580,7 +4320,7 @@ int set_std_nic_fn(struct bpctl_dev *pbpctl_dev, int nic_mode)
return ret;
}
-int get_std_nic_fn(struct bpctl_dev *pbpctl_dev)
+static int get_std_nic_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4588,7 +4328,7 @@ int get_std_nic_fn(struct bpctl_dev *pbpctl_dev)
return std_nic_status(pbpctl_dev);
}
-int set_tap_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
+static int set_tap_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
{
if (!pbpctl_dev)
return -1;
@@ -4604,7 +4344,7 @@ int set_tap_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
return BP_NOT_CAP;
}
-int get_tap_fn(struct bpctl_dev *pbpctl_dev)
+static int get_tap_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4612,7 +4352,7 @@ int get_tap_fn(struct bpctl_dev *pbpctl_dev)
return tap_status(pbpctl_dev);
}
-int set_tap_pwup_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
+static int set_tap_pwup_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4630,7 +4370,7 @@ int set_tap_pwup_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
return ret;
}
-int get_tap_pwup_fn(struct bpctl_dev *pbpctl_dev)
+static int get_tap_pwup_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4642,7 +4382,7 @@ int get_tap_pwup_fn(struct bpctl_dev *pbpctl_dev)
return ((ret == 0) ? 1 : 0);
}
-int get_tap_change_fn(struct bpctl_dev *pbpctl_dev)
+static int get_tap_change_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4650,7 +4390,7 @@ int get_tap_change_fn(struct bpctl_dev *pbpctl_dev)
return tap_change_status(pbpctl_dev);
}
-int set_dis_tap_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
+static int set_dis_tap_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4667,7 +4407,7 @@ int set_dis_tap_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
return BP_NOT_CAP;
}
-int get_dis_tap_fn(struct bpctl_dev *pbpctl_dev)
+static int get_dis_tap_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4675,7 +4415,7 @@ int get_dis_tap_fn(struct bpctl_dev *pbpctl_dev)
return dis_tap_cap_status(pbpctl_dev);
}
-int set_disc_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
+static int set_disc_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
{
if (!pbpctl_dev)
return -1;
@@ -4692,7 +4432,7 @@ int set_disc_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
return BP_NOT_CAP;
}
-int get_disc_fn(struct bpctl_dev *pbpctl_dev)
+static int get_disc_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4703,7 +4443,7 @@ int get_disc_fn(struct bpctl_dev *pbpctl_dev)
return ret;
}
-int set_disc_pwup_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
+static int set_disc_pwup_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4721,7 +4461,7 @@ int set_disc_pwup_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
return ret;
}
-int get_disc_pwup_fn(struct bpctl_dev *pbpctl_dev)
+static int get_disc_pwup_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4731,7 +4471,7 @@ int get_disc_pwup_fn(struct bpctl_dev *pbpctl_dev)
return (ret == 0 ? 1 : (ret < 0 ? BP_NOT_CAP : 0));
}
-int get_disc_change_fn(struct bpctl_dev *pbpctl_dev)
+static int get_disc_change_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4741,7 +4481,7 @@ int get_disc_change_fn(struct bpctl_dev *pbpctl_dev)
return ret;
}
-int set_dis_disc_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
+static int set_dis_disc_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4759,7 +4499,7 @@ int set_dis_disc_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
return BP_NOT_CAP;
}
-int get_dis_disc_fn(struct bpctl_dev *pbpctl_dev)
+static int get_dis_disc_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4770,55 +4510,7 @@ int get_dis_disc_fn(struct bpctl_dev *pbpctl_dev)
return ret;
}
-int set_disc_port_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
-{
- int ret = BP_NOT_CAP;
- if (!pbpctl_dev)
- return -1;
-
- if (!disc_mode)
- ret = disc_port_off(pbpctl_dev);
- else
- ret = disc_port_on(pbpctl_dev);
-
- return ret;
-}
-
-int get_disc_port_fn(struct bpctl_dev *pbpctl_dev)
-{
- if (!pbpctl_dev)
- return -1;
-
- return disc_port_status(pbpctl_dev);
-}
-
-int set_disc_port_pwup_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
-{
- int ret = BP_NOT_CAP;
- if (!pbpctl_dev)
- return -1;
-
- if (!disc_mode)
- ret = normal_port_state_pwron(pbpctl_dev);
- else
- ret = disc_port_state_pwron(pbpctl_dev);
-
- return ret;
-}
-
-int get_disc_port_pwup_fn(struct bpctl_dev *pbpctl_dev)
-{
- int ret = 0;
- if (!pbpctl_dev)
- return -1;
-
- ret = default_pwron_disc_port_status(pbpctl_dev);
- if (ret < 0)
- return ret;
- return ((ret == 0) ? 1 : 0);
-}
-
-int get_wd_exp_mode_fn(struct bpctl_dev *pbpctl_dev)
+static int get_wd_exp_mode_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4826,7 +4518,7 @@ int get_wd_exp_mode_fn(struct bpctl_dev *pbpctl_dev)
return wdt_exp_mode_status(pbpctl_dev);
}
-int set_wd_exp_mode_fn(struct bpctl_dev *pbpctl_dev, int param)
+static int set_wd_exp_mode_fn(struct bpctl_dev *pbpctl_dev, int param)
{
if (!pbpctl_dev)
return -1;
@@ -4834,19 +4526,7 @@ int set_wd_exp_mode_fn(struct bpctl_dev *pbpctl_dev, int param)
return wdt_exp_mode(pbpctl_dev, param);
}
-int reset_cont_fn(struct bpctl_dev *pbpctl_dev)
-{
- int ret = 0;
- if (!pbpctl_dev)
- return -1;
-
- ret = cmnd_on(pbpctl_dev);
- if (ret < 0)
- return ret;
- return reset_cont(pbpctl_dev);
-}
-
-int set_tx_fn(struct bpctl_dev *pbpctl_dev, int tx_state)
+static int set_tx_fn(struct bpctl_dev *pbpctl_dev, int tx_state)
{
struct bpctl_dev *pbpctl_dev_b = NULL;
@@ -4867,7 +4547,7 @@ int set_tx_fn(struct bpctl_dev *pbpctl_dev, int tx_state)
return set_tx(pbpctl_dev, tx_state);
}
-int set_bp_force_link_fn(int dev_num, int tx_state)
+static int set_bp_force_link_fn(int dev_num, int tx_state)
{
static struct bpctl_dev *bpctl_dev_curr;
@@ -4879,7 +4559,7 @@ int set_bp_force_link_fn(int dev_num, int tx_state)
return set_bp_force_link(bpctl_dev_curr, tx_state);
}
-int set_wd_autoreset_fn(struct bpctl_dev *pbpctl_dev, int param)
+static int set_wd_autoreset_fn(struct bpctl_dev *pbpctl_dev, int param)
{
if (!pbpctl_dev)
return -1;
@@ -4887,7 +4567,7 @@ int set_wd_autoreset_fn(struct bpctl_dev *pbpctl_dev, int param)
return set_bypass_wd_auto(pbpctl_dev, param);
}
-int get_wd_autoreset_fn(struct bpctl_dev *pbpctl_dev)
+static int get_wd_autoreset_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4914,7 +4594,7 @@ int get_bp_self_test_fn(struct bpctl_dev *pbpctl_dev)
#endif
-int get_bypass_caps_fn(struct bpctl_dev *pbpctl_dev)
+static int get_bypass_caps_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4923,7 +4603,8 @@ int get_bypass_caps_fn(struct bpctl_dev *pbpctl_dev)
}
-int get_bypass_slave_fn(struct bpctl_dev *pbpctl_dev, struct bpctl_dev **pbpctl_dev_out)
+static int get_bypass_slave_fn(struct bpctl_dev *pbpctl_dev,
+ struct bpctl_dev **pbpctl_dev_out)
{
int idx_dev = 0;
if (!pbpctl_dev)
@@ -4955,7 +4636,7 @@ int get_bypass_slave_fn(struct bpctl_dev *pbpctl_dev, struct bpctl_dev **pbpctl_
return 0;
}
-int is_bypass(struct bpctl_dev *pbpctl_dev)
+static int is_bypass(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4966,7 +4647,7 @@ int is_bypass(struct bpctl_dev *pbpctl_dev)
return 0;
}
-int get_tx_fn(struct bpctl_dev *pbpctl_dev)
+static int get_tx_fn(struct bpctl_dev *pbpctl_dev)
{
struct bpctl_dev *pbpctl_dev_b = NULL;
if (!pbpctl_dev)
@@ -4986,7 +4667,7 @@ int get_tx_fn(struct bpctl_dev *pbpctl_dev)
return tx_status(pbpctl_dev);
}
-int get_bp_force_link_fn(int dev_num)
+static int get_bp_force_link_fn(int dev_num)
{
static struct bpctl_dev *bpctl_dev_curr;
@@ -5049,7 +4730,7 @@ static void bp_tpl_timer_fn(unsigned long param)
mod_timer(&pbpctl_dev->bp_tpl_timer, jiffies + BP_LINK_MON_DELAY * HZ);
}
-void remove_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev)
+static void remove_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev)
{
struct bpctl_dev *pbpctl_dev_b = NULL;
if (!pbpctl_dev)
@@ -5067,7 +4748,7 @@ void remove_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev)
return;
}
-int init_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev)
+static int init_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -5080,7 +4761,7 @@ int init_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev)
return BP_NOT_CAP;
}
-int set_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev, unsigned int param)
+static int set_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev, unsigned int param)
{
if (!pbpctl_dev)
return -1;
@@ -5098,17 +4779,7 @@ int set_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev, unsigned int param)
return BP_NOT_CAP;
}
-int get_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev)
-{
- if (!pbpctl_dev)
- return -1;
- if (pbpctl_dev->bp_caps & TPL_CAP)
- return pbpctl_dev->bp_tpl_flag;
-
- return BP_NOT_CAP;
-}
-
-int set_tpl_fn(struct bpctl_dev *pbpctl_dev, int tpl_mode)
+static int set_tpl_fn(struct bpctl_dev *pbpctl_dev, int tpl_mode)
{
struct bpctl_dev *pbpctl_dev_b = NULL;
@@ -5138,7 +4809,7 @@ int set_tpl_fn(struct bpctl_dev *pbpctl_dev, int tpl_mode)
return BP_NOT_CAP;
}
-int get_tpl_fn(struct bpctl_dev *pbpctl_dev)
+static int get_tpl_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if (!pbpctl_dev)
@@ -5152,7 +4823,7 @@ int get_tpl_fn(struct bpctl_dev *pbpctl_dev)
return ret;
}
-int set_bp_wait_at_pwup_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
+static int set_bp_wait_at_pwup_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
{
if (!pbpctl_dev)
return -1;
@@ -5172,7 +4843,7 @@ int set_bp_wait_at_pwup_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
return BP_NOT_CAP;
}
-int get_bp_wait_at_pwup_fn(struct bpctl_dev *pbpctl_dev)
+static int get_bp_wait_at_pwup_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -5185,7 +4856,7 @@ int get_bp_wait_at_pwup_fn(struct bpctl_dev *pbpctl_dev)
return ret;
}
-int set_bp_hw_reset_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
+static int set_bp_hw_reset_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
{
if (!pbpctl_dev)
return -1;
@@ -5205,7 +4876,7 @@ int set_bp_hw_reset_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
return BP_NOT_CAP;
}
-int get_bp_hw_reset_fn(struct bpctl_dev *pbpctl_dev)
+static int get_bp_hw_reset_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -5220,7 +4891,7 @@ int get_bp_hw_reset_fn(struct bpctl_dev *pbpctl_dev)
}
-int get_bypass_info_fn(struct bpctl_dev *pbpctl_dev, char *dev_name,
+static int get_bypass_info_fn(struct bpctl_dev *pbpctl_dev, char *dev_name,
char *add_param)
{
if (!pbpctl_dev)
@@ -5232,7 +4903,7 @@ int get_bypass_info_fn(struct bpctl_dev *pbpctl_dev, char *dev_name,
return 0;
}
-int get_dev_idx_bsf(int bus, int slot, int func)
+static int get_dev_idx_bsf(int bus, int slot, int func)
{
int idx_dev = 0;
for (idx_dev = 0;
@@ -7022,12 +6693,6 @@ int set_wd_exp_mode_sd(int ifindex, int param)
}
EXPORT_SYMBOL(set_wd_exp_mode_sd);
-int reset_cont_sd(int ifindex)
-{
- return reset_cont_fn(get_dev_idx_p(ifindex));
-
-}
-
int set_tx_sd(int ifindex, int tx_state)
{
return set_tx_fn(get_dev_idx_p(ifindex), tx_state);
@@ -7118,7 +6783,7 @@ EXPORT_SYMBOL(bp_if_scan_sd);
static struct proc_dir_entry *bp_procfs_dir;
-int bp_proc_create(void)
+static int bp_proc_create(void)
{
bp_procfs_dir = proc_mkdir(BP_PROC_DIR, init_net.proc_net);
if (bp_procfs_dir == (struct proc_dir_entry *)0) {
@@ -7746,7 +7411,7 @@ static int show_wd_autoreset(struct seq_file *m, void *v)
}
RW_FOPS(wd_autoreset)
-int bypass_proc_create_dev_sd(struct bpctl_dev *pbp_device_block)
+static int bypass_proc_create_dev_sd(struct bpctl_dev *pbp_device_block)
{
struct bypass_pfs_sd *current_pfs = &(pbp_device_block->bypass_pfs_set);
static struct proc_dir_entry *procfs_dir;
@@ -7816,7 +7481,7 @@ int bypass_proc_create_dev_sd(struct bpctl_dev *pbp_device_block)
return ret;
}
-int bypass_proc_remove_dev_sd(struct bpctl_dev *pbp_device_block)
+static int bypass_proc_remove_dev_sd(struct bpctl_dev *pbp_device_block)
{
struct bypass_pfs_sd *current_pfs = &pbp_device_block->bypass_pfs_set;
diff --git a/drivers/staging/silicom/bypasslib/bp_ioctl.h b/drivers/staging/silicom/bypasslib/bp_ioctl.h
index 2d1ef5384436..bf47f786866b 100644
--- a/drivers/staging/silicom/bypasslib/bp_ioctl.h
+++ b/drivers/staging/silicom/bypasslib/bp_ioctl.h
@@ -51,9 +51,9 @@
#define WDT_STEP_TIME 0x10 /* BIT_4 */
#define WD_MIN_TIME_GET(desc) (desc & 0xf)
-#define WD_STEP_COUNT_GET(desc) (desc>>5) & 0xf
+#define WD_STEP_COUNT_GET(desc) ((desc>>5) & 0xf)
-typedef enum {
+enum {
IS_BYPASS = 1,
GET_BYPASS_SLAVE,
GET_BYPASS_CAPS,
@@ -103,7 +103,7 @@ typedef enum {
SET_BP_HW_RESET,
} CMND_TYPE;
-typedef enum {
+enum {
IF_SCAN_SD,
GET_DEV_NUM_SD,
IS_BYPASS_SD,
@@ -156,7 +156,7 @@ typedef enum {
} CMND_TYPE_SD;
-#define SIOCGIFBYPASS SIOCDEVPRIVATE+10
+#define SIOCGIFBYPASS (SIOCDEVPRIVATE+10)
struct bp_info {
char prod_name[14];
diff --git a/drivers/staging/silicom/bypasslib/libbp_sd.h b/drivers/staging/silicom/bypasslib/libbp_sd.h
index 3b4f8364ed18..cac4b0b2ed78 100644
--- a/drivers/staging/silicom/bypasslib/libbp_sd.h
+++ b/drivers/staging/silicom/bypasslib/libbp_sd.h
@@ -18,7 +18,7 @@
* @if_index: network device index
*
* Output:
- * 1 - if device is bypass controlling device,
+ * 1 - if device is bypass controlling device,
* 0 - if device is bypass slave device
* -1 - device not support Bypass
**/
@@ -30,7 +30,7 @@ int is_bypass_sd(int if_index);
*
* Output:
* network device index of the slave device
- * -1 - on failure (device not support Bypass or it's a slave device)
+ * -1 - on failure (device not support Bypass or it's a slave device)
**/
int get_bypass_slave_sd(int if_index);
@@ -39,55 +39,72 @@ int get_bypass_slave_sd(int if_index);
* @if_index: network device index
*
* Output:
- * flags word on success;flag word is a 32-bit mask word with each bit defines different
- * capability as described bellow.
+ * flags word on success;flag word is a 32-bit mask word with each bit defines
+ * different capability as described bellow.
* Value of 1 for supporting this feature. 0 for not supporting this feature.
- * -1 - on failure (if the device is not capable of the operation or not a Bypass device)
- * Bit feature description
- *
- * 0 BP_CAP The interface is Bypass capable in general
- *
- * 1 BP_STATUS_CAP The interface can report of the current Bypass mode
- *
- * 2 BP_STATUS_CHANGE_CAP The interface can report on a change to bypass mode from
- * the last time the mode was defined
- *
- * 3 SW_CTL_CAP The interface is Software controlled capable for bypass/non bypass modes.
- *
- * 4 BP_DIS_CAP The interface is capable of disabling the Bypass mode at all times.
- * This mode will retain its mode even during power loss and also after
- * power recovery. This will overcome on any bypass operation due to
- * watchdog timeout or set bypass command.
- *
- * 5 BP_DIS_STATUS_CAP The interface can report of the current DIS_BP_CAP
- *
- * 6 STD_NIC_CAP The interface is capable to be configured to operate as standard, non Bypass,
- * NIC interface (have direct connection to interfaces at all power modes)
- *
- * 7 BP_PWOFF_NO_CAP The interface can be in Bypass mode at power off state
- *
- * 8 BP_PWOFF_OFF_CAP The interface can disconnect the Bypass mode at power off state without
- * effecting all the other states of operation
- *
- * 9 BP_PWOFF_CTL_CAP The behavior of the Bypass mode at Power-off state can be controlled by
- * software without effecting any other state
- *
- *10 BP_PWUP_ON_CAP The interface can be in Bypass mode when power is turned on
- * (until the system take control of the bypass functionality)
- *
- *11 BP_PWUP_OFF_CAP The interface can disconnect from Bypass mode when power is turned on
- * (until the system take control of the bypass functionality)
- *
- *12 BP_PWUP_CTL_CAP The behavior of the Bypass mode at Power-up can be controlled by software
- *
- *13 WD_CTL_CAP The interface has watchdog capabilities to turn to Bypass mode when not reset
- * for defined period of time.
- *
- *14 WD_STATUS_CAP The interface can report on the watchdog status (Active/inactive)
- *
- *15 WD_TIMEOUT_CAP The interface can report the time left till watchdog triggers to Bypass mode.
- *
- *16-31 RESERVED
+ * -1 - on failure (if the device is not capable of the operation or not a
+ * Bypass device)
+ * Bit feature description
+ *
+ * 0 BP_CAP The interface is Bypass capable in general
+ *
+ * 1 BP_STATUS_CAP The interface can report of the current Bypass
+ * mode
+ *
+ * 2 BP_STATUS_CHANGE_CAP The interface can report on a change to bypass
+ * mode from the last time the mode was defined
+ *
+ * 3 SW_CTL_CAP The interface is Software controlled capable for
+ * bypass/non bypass modes.
+ *
+ * 4 BP_DIS_CAP The interface is capable of disabling the Bypass
+ * mode at all times. This mode will retain its
+ * mode even during power loss and also after power
+ * recovery. This will overcome on any bypass
+ * operation due to watchdog timeout or set bypass
+ * command.
+ *
+ * 5 BP_DIS_STATUS_CAP The interface can report of the current
+ * DIS_BP_CAP
+ *
+ * 6 STD_NIC_CAP The interface is capable to be configured to
+ * operate as standard, non Bypass, NIC interface
+ * (have direct connection to interfaces at all
+ * power modes)
+ *
+ * 7 BP_PWOFF_NO_CAP The interface can be in Bypass mode at power off
+ * state
+ *
+ * 8 BP_PWOFF_OFF_CAP The interface can disconnect the Bypass mode at
+ * power off state without effecting all the other
+ * states of operation
+ *
+ * 9 BP_PWOFF_CTL_CAP The behavior of the Bypass mode at Power-off
+ * state can be controlled by software without
+ * effecting any other state
+ *
+ *10 BP_PWUP_ON_CAP The interface can be in Bypass mode when power
+ * is turned on (until the system take control of
+ * the bypass functionality)
+ *
+ *11 BP_PWUP_OFF_CAP The interface can disconnect from Bypass mode
+ * when power is turned on (until the system take
+ * control of the bypass functionality)
+ *
+ *12 BP_PWUP_CTL_CAP The behavior of the Bypass mode at Power-up can
+ * be controlled by software
+ *
+ *13 WD_CTL_CAP The interface has watchdog capabilities to turn
+ * to Bypass mode when not reset for defined period
+ * of time.
+ *
+ *14 WD_STATUS_CAP The interface can report on the watchdog status
+ * (Active/inactive)
+ *
+ *15 WD_TIMEOUT_CAP The interface can report the time left till
+ * watchdog triggers to Bypass mode.
+ *
+ *16-31 RESERVED
*
* **/
int get_bypass_caps_sd(int if_index);
@@ -97,34 +114,35 @@ int get_bypass_caps_sd(int if_index);
* @if_index: network device index
*
* Output:
- *
- * Set of numbers defining the various parameters of the watchdog capable
+ *
+ * Set of numbers defining the various parameters of the watchdog capable
* to be set to as described bellow.
* -1 - on failure (device not support Bypass or it's a slave device)
- *
+ *
* Bit feature description
- *
+ *
* 0-3 WD_MIN_TIME The interface WD minimal time period in 100mS units
- *
- * 4 WD_STEP_TIME The steps of the WD timer in
+ *
+ * 4 WD_STEP_TIME The steps of the WD timer in
* 0 - for linear steps (WD_MIN_TIME * X)
- * 1 - for multiply by 2 from previous step (WD_MIN_TIME * 2^X)
- *
- * 5-8 WD_STEP_COUNT Number of steps the WD timer supports in 2^X
+ * 1 - for multiply by 2 from previous step
+ * (WD_MIN_TIME * 2^X)
+ *
+ * 5-8 WD_STEP_COUNT Number of steps the WD timer supports in 2^X
* (X bit available for defining the value)
- *
- *
- *
+ *
+ *
+ *
**/
int get_wd_set_caps_sd(int if_index);
/**
* set_bypass - set Bypass state
* @if_index: network device index of the controlling device
- * @bypass_mode: bypass mode (1=on, 0=off)
+ * @bypass_mode: bypass mode (1=on, 0=off)
* Output:
* 0 - on success
- * -1 - on failure (device not support Bypass or it's a slave device)
+ * -1 - on failure (device not support Bypass or it's a slave device)
**/
int set_bypass_sd(int if_index, int bypass_mode);
@@ -133,7 +151,7 @@ int set_bypass_sd(int if_index, int bypass_mode);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - (off/on) on success
- * -1 - on failure (device not support Bypass or it's a slave device)
+ * -1 - on failure (device not support Bypass or it's a slave device)
**/
int get_bypass_sd(int if_index);
@@ -142,7 +160,7 @@ int get_bypass_sd(int if_index);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - (off/on) on success
- * -1 - on failure (device not support Bypass or it's a slave device)
+ * -1 - on failure (device not support Bypass or it's a slave device)
**/
int get_bypass_change_sd(int if_index);
@@ -152,8 +170,8 @@ int get_bypass_change_sd(int if_index);
* @dis_bypass: disable bypass(1=dis, 0=en)
* Output:
* 0 - on success
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device)
+ * -1 - on failure (device is not capable of the operation or device not support
+ * Bypass or it's a slave device)
**/
int set_dis_bypass_sd(int if_index, int dis_bypass);
@@ -162,8 +180,8 @@ int set_dis_bypass_sd(int if_index, int dis_bypass);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - on success (normal Bypass mode/ Disable bypass)
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device)
+ * -1 - on failure (device is not capable of the operation or device not support
+ * Bypass or it's a slave device)
**/
int get_dis_bypass_sd(int if_index);
@@ -172,9 +190,9 @@ int get_dis_bypass_sd(int if_index);
* @if_index: network device index of the controlling device
* @bypass_mode: bypass mode setting at power off state (1=BP en, 0=BP Dis)
* Output:
- * 0 - on success
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device)
+ * 0 - on success
+ * -1 - on failure (device is not capable of the operation or device not support
+ * Bypass or it's a slave device)
**/
int set_bypass_pwoff_sd(int if_index, int bypass_mode);
@@ -183,8 +201,8 @@ int set_bypass_pwoff_sd(int if_index, int bypass_mode);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - on success (Disable bypass at power off state / normal Bypass mode)
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device)
+ * -1 - on failure (device is not capable of the operation or device not support
+ * Bypass or it's a slave device)
**/
int get_bypass_pwoff_sd(int if_index);
@@ -193,9 +211,9 @@ int get_bypass_pwoff_sd(int if_index);
* @if_index: network device index of the controlling device
* @bypass_mode: bypass mode setting at power up state (1=BP en, 0=BP Dis)
* Output:
- * 0 - on success
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device)
+ * 0 - on success
+ * -1 - on failure (device is not capable of the operation or device not support
+ * Bypass or it's a slave device)
**/
int set_bypass_pwup_sd(int if_index, int bypass_mode);
@@ -204,59 +222,60 @@ int set_bypass_pwup_sd(int if_index, int bypass_mode);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - on success (Disable bypass at power up state / normal Bypass mode)
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device)
+ * -1 - on failure (device is not capable of the operation or device not support
+ * Bypass or it's a slave device)
**/
int get_bypass_pwup_sd(int if_index);
/**
* set_bypass_wd - Set watchdog state
* @if_index: network device index of the controlling device
- * @ms_timeout: requested timeout (in ms units), 0 for disabling the watchdog timer
- * @ms_timeout_set(output): requested timeout (in ms units),
- * that the adapter supports and will be used by the watchdog
+ * @ms_timeout: requested timeout (in ms units), 0 for disabling the watchdog
+ * timer
+ * @ms_timeout_set(output): requested timeout (in ms units), that the adapter
+ * supports and will be used by the watchdog
* Output:
- * 0 - on success
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device)
+ * 0 - on success
+ * -1 - on failure (device is not capable of the operation or device not support
+ * Bypass or it's a slave device)
**/
int set_bypass_wd_sd(int if_index, int ms_timeout, int *ms_timeout_set);
/**
* get_bypass_wd - Get watchdog state
* @if_index: network device index of the controlling device
- * @ms_timeout (output): WDT timeout (in ms units),
+ * @ms_timeout (output): WDT timeout (in ms units),
* -1 for unknown wdt status
* 0 if WDT is disabled
* Output:
* 0 - on success
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device)
+ * -1 - on failure (device is not capable of the operation or device not support
+ * Bypass or it's a slave device)
**/
int get_bypass_wd_sd(int if_index, int *ms_timeout_set);
/**
* get_wd_expire_time - Get watchdog expire
* @if_index: network device index of the controlling device
- * @ms_time_left (output): time left till watchdog time expire,
+ * @ms_time_left (output): time left till watchdog time expire,
* -1 if WDT has expired
* 0 if WDT is disabled
* Output:
* 0 - on success
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device or unknown wdt status)
+ * -1 - on failure (device is not capable of the operation or device not support
+ * Bypass or it's a slave device or unknown wdt status)
**/
int get_wd_expire_time_sd(int if_index, int *ms_time_left);
/**
* reset_bypass_wd_timer - Reset watchdog timer
* @if_index: network device index of the controlling device
- *
+ *
* Output:
* 1 - on success
* 0 - watchdog is not configured
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device or unknown wdt status)
+ * -1 - on failure (device is not capable of the operation or device not support
+ * Bypass or it's a slave device or unknown wdt status)
**/
int reset_bypass_wd_timer_sd(int if_index);
@@ -264,53 +283,54 @@ int reset_bypass_wd_timer_sd(int if_index);
* set_std_nic - Standard NIC mode of operation
* @if_index: network device index of the controlling device
* @nic_mode: 0/1 (Default Bypass mode / Standard NIC mode)
- *
+ *
* Output:
* 0 - on success
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device)
+ * -1 - on failure (device is not capable of the operation or device not support
+ * Bypass or it's a slave device)
**/
int set_std_nic_sd(int if_index, int nic_mode);
/**
* get_std_nic - Get Standard NIC mode setting
* @if_index: network device index of the controlling device
- *
+ *
* Output:
* 0/1 (Default Bypass mode / Standard NIC mode) on success
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device)
+ * -1 - on failure (device is not capable of the operation or device not support
+ * Bypass or it's a slave device)
**/
int get_std_nic_sd(int if_index);
/**
- * set_tx - set transmitter enable/disable
+ * set_tx - set transmitter enable/disable
* @if_index: network device index of the controlling device
* @tx_state: 0/1 (Transmit Disable / Transmit Enable)
- *
+ *
* Output:
* 0 - on success
- * -1 - on failure (device is not capable of the operation )
+ * -1 - on failure (device is not capable of the operation )
**/
int set_tx_sd(int if_index, int tx_state);
/**
* get_std_nic - get transmitter state (disable / enable)
* @if_index: network device index of the controlling device
- *
+ *
* Output:
* 0/1 (ransmit Disable / Transmit Enable) on success
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass)
+ * -1 - on failure (device is not capable of the operation or device not support
+ * Bypass)
**/
int get_tx_sd(int if_index);
/**
* set_tap - set TAP state
* @if_index: network device index of the controlling device
- * @tap_mode: 1 tap mode , 0 normal nic mode
+ * @tap_mode: 1 tap mode , 0 normal nic mode
* Output:
* 0 - on success
- * -1 - on failure (device not support TAP or it's a slave device)
+ * -1 - on failure (device not support TAP or it's a slave device)
**/
int set_tap_sd(int if_index, int tap_mode);
@@ -319,7 +339,7 @@ int set_tap_sd(int if_index, int tap_mode);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - (off/on) on success
- * -1 - on failure (device not support TAP or it's a slave device)
+ * -1 - on failure (device not support TAP or it's a slave device)
**/
int get_tap_sd(int if_index);
@@ -328,7 +348,7 @@ int get_tap_sd(int if_index);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - (off/on) on success
- * -1 - on failure (device not support TAP or it's a slave device)
+ * -1 - on failure (device not support TAP or it's a slave device)
**/
int get_tap_change_sd(int if_index);
@@ -338,8 +358,8 @@ int get_tap_change_sd(int if_index);
* @dis_tap: disable tap(1=dis, 0=en)
* Output:
* 0 - on success
- * -1 - on failure (device is not capable of the operation ordevice not support TAP
- * or it's a slave device)
+ * -1 - on failure (device is not capable of the operation or device not support
+ * TAP or it's a slave device)
**/
int set_dis_tap_sd(int if_index, int dis_tap);
@@ -348,8 +368,8 @@ int set_dis_tap_sd(int if_index, int dis_tap);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - on success (normal TAP mode/ Disable TAP)
- * -1 - on failure (device is not capable of the operation ordevice not support TAP
- * or it's a slave device)
+ * -1 - on failure (device is not capable of the operation or device not support
+ * TAP or it's a slave device)
**/
int get_dis_tap_sd(int if_index);
@@ -358,9 +378,9 @@ int get_dis_tap_sd(int if_index);
* @if_index: network device index of the controlling device
* @bypass_mode: tap mode setting at power up state (1=TAP en, 0=TAP Dis)
* Output:
- * 0 - on success
- * -1 - on failure (device is not capable of the operation ordevice not support TAP
- * or it's a slave device)
+ * 0 - on success
+ * -1 - on failure (device is not capable of the operation or device not
+ * support TAP or it's a slave device)
**/
int set_tap_pwup_sd(int if_index, int tap_mode);
@@ -369,18 +389,18 @@ int set_tap_pwup_sd(int if_index, int tap_mode);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - on success (Disable TAP at power up state / normal TAP mode)
- * -1 - on failure (device is not capable of the operation ordevice not support TAP
- * or it's a slave device)
+ * -1 - on failure (device is not capable of the operation or device not
+ * support TAP or it's a slave device)
**/
int get_tap_pwup_sd(int if_index);
/**
* set_bp_disc - set Disconnect state
* @if_index: network device index of the controlling device
- * @tap_mode: 1 disc mode , 0 non-disc mode
+ * @tap_mode: 1 disc mode , 0 non-disc mode
* Output:
* 0 - on success
- * -1 - on failure (device not support Disconnect or it's a slave device)
+ * -1 - on failure (device not support Disconnect or it's a slave device)
**/
int set_bp_disc_sd(int if_index, int disc_mode);
@@ -389,7 +409,7 @@ int set_bp_disc_sd(int if_index, int disc_mode);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - (off/on) on success
- * -1 - on failure (device not support Disconnect or it's a slave device)
+ * -1 - on failure (device not support Disconnect or it's a slave device)
**/
int get_bp_disc_sd(int if_index);
@@ -398,7 +418,7 @@ int get_bp_disc_sd(int if_index);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - (off/on) on success
- * -1 - on failure (device not support Disconnect or it's a slave device)
+ * -1 - on failure (device not support Disconnect or it's a slave device)
**/
int get_bp_disc_change_sd(int if_index);
@@ -408,8 +428,8 @@ int get_bp_disc_change_sd(int if_index);
* @dis_tap: disable tap(1=dis, 0=en)
* Output:
* 0 - on success
- * -1 - on failure (device is not capable ofthe operation ordevice not support Disconnect
- * or it's a slave device)
+ * -1 - on failure (device is not capable ofthe operation or device not
+ * support Disconnect or it's a slave device)
**/
int set_bp_dis_disc_sd(int if_index, int dis_disc);
@@ -418,8 +438,8 @@ int set_bp_dis_disc_sd(int if_index, int dis_disc);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - on success (normal Disconnect mode/ Disable Disconnect)
- * -1 - on failure (device is not capable of the operation ordevice not support Disconnect
- * or it's a slave device)
+ * -1 - on failure (device is not capable of the operation or device not
+ * support Disconnect or it's a slave device)
**/
int get_bp_dis_disc_sd(int if_index);
@@ -428,9 +448,9 @@ int get_bp_dis_disc_sd(int if_index);
* @if_index: network device index of the controlling device
* @disc_mode: tap mode setting at power up state (1=Disc en, 0=Disc Dis)
* Output:
- * 0 - on success
- * -1 - on failure (device is not capable of the operation ordevice not support Disconnect
- * or it's a slave device)
+ * 0 - on success
+ * -1 - on failure (device is not capable of the operation or device not
+ * support Disconnect or it's a slave device)
**/
int set_bp_disc_pwup_sd(int if_index, int disc_mode);
@@ -438,19 +458,20 @@ int set_bp_disc_pwup_sd(int if_index, int disc_mode);
* get_bp_disc_pwup - Get Disconnect mode state at power-up state
* @if_index: network device index of the controlling device
* Output:
- * 0/1 - on success (Disable Disconnect at power up state / normal Disconnect mode)
- * -1 - on failure (device is not capable of the operation ordevice not support TAP
- * or it's a slave device)
+ * 0/1 - on success (Disable Disconnect at power up state / normal Disconnect
+ * mode)
+ * -1 - on failure (device is not capable of the operation or device not
+ * support TAP or it's a slave device)
**/
int get_bp_disc_pwup_sd(int if_index);
/**
* set_wd_exp_mode - Set adapter state when WDT expired.
* @if_index: network device index of the controlling device
- * @bypass_mode: adapter mode (1=tap mode, 0=bypass mode)
+ * @bypass_mode: adapter mode (1=tap mode, 0=bypass mode)
* Output:
* 0 - on success
- * -1 - on failure (device not support Bypass or it's a slave device)
+ * -1 - on failure (device not support Bypass or it's a slave device)
**/
int set_wd_exp_mode_sd(int if_index, int bypass_mode);
@@ -459,39 +480,41 @@ int set_wd_exp_mode_sd(int if_index, int bypass_mode);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - (bypass/tap) on success
- * -1 - on failure (device not support Bypass or it's a slave device)
+ * -1 - on failure (device not support Bypass or it's a slave device)
**/
int get_wd_exp_mode_sd(int if_index);
/**
* set_wd_autoreset - reset WDT periodically.
* @if_index: network device index of the controlling device
- * @bypass_mode: adapter mode (1=tap mode, 0=bypass mode)
+ * @bypass_mode: adapter mode (1=tap mode, 0=bypass mode)
* Output:
* 1 - on success
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device or unknown wdt status)
+ * -1 - on failure (device is not capable of the operation or device not
+ * support Bypass or it's a slave device or unknown wdt
+ * status)
**/
int set_wd_autoreset_sd(int if_index, int time);
/**
* set_wd_autoreset - reset WDT periodically.
* @if_index: network device index of the controlling device
- * @bypass_mode: adapter mode (1=tap mode, 0=bypass mode)
+ * @bypass_mode: adapter mode (1=tap mode, 0=bypass mode)
* Output:
* 1 - on success
- * -1 - on failure (device is not capable of the operation ordevice not support Bypass
- * or it's a slave device or unknown wdt status)
+ * -1 - on failure (device is not capable of the operation or device not
+ * support Bypass or it's a slave device or unknown wdt
+ * status)
**/
int get_wd_autoreset_sd(int if_index);
/**
* set_tpl - set TPL state
* @if_index: network device index of the controlling device
- * @tpl_mode: 1 tpl mode , 0 normal nic mode
+ * @tpl_mode: 1 tpl mode , 0 normal nic mode
* Output:
* 0 - on success
- * -1 - on failure (device not support TPL)
+ * -1 - on failure (device not support TPL)
**/
int set_tpl_sd(int if_index, int tpl_mode);
@@ -500,7 +523,7 @@ int set_tpl_sd(int if_index, int tpl_mode);
* @if_index: network device index of the controlling device
* Output:
* 0/1 - (off/on) on success
- * -1 - on failure (device not support TPL or it's a slave device)
+ * -1 - on failure (device not support TPL or it's a slave device)
**/
int get_tpl_sd(int if_index);
diff --git a/drivers/staging/slicoss/README b/drivers/staging/slicoss/README
index 53052c4e78ae..4fa50e73ce86 100644
--- a/drivers/staging/slicoss/README
+++ b/drivers/staging/slicoss/README
@@ -5,43 +5,3 @@ This driver is supposed to support:
Kalahari cards (dual and quad port PCI-e Gigabit) copper and fiber
The driver was actually tested on Oasis and Kalahari cards.
-
-TODO:
- - move firmware loading to request_firmware()
- - remove direct memory access of structures
- - any remaining sparse and checkpatch.pl warnings
-
- - use net_device_ops
- - use dev->stats rather than adapter->stats
- - don't cast netdev_priv it is already void
- - GET RID OF MACROS
- - work on all architectures
- - without CONFIG_X86_64 confusion
- - do 64 bit correctly
- - don't depend on order of union
- - get rid of ASSERT(), use BUG() instead but only where necessary
- looks like most aren't really useful
- - no new SIOCDEVPRIVATE ioctl allowed
- - don't use module_param for configuring interrupt mitigation
- use ethtool instead
- - reorder code to elminate use of forward declarations
- - don't keep private linked list of drivers.
- - remove all the gratiutous debug infrastructure
- - use PCI_DEVICE()
- - do ethtool correctly using ethtool_ops
- - NAPI?
- - wasted overhead of extra stats
- - state variables for things that are
- easily available and shouldn't be kept in card structure, cardnum, ...
- slotnumber, events, ...
- - get rid of slic_spinlock wrapper
- - volatile == bad design => bad code
- - locking too fine grained, not designed just throw more locks
- at problem
-
-
-Please send patches to:
- Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-and Cc: Lior Dotan <liodot@gmail.com> and Christopher Harrer
-<charrer@alacritech.com> as well as they are also able to test out any
-changes.
diff --git a/drivers/staging/slicoss/TODO b/drivers/staging/slicoss/TODO
new file mode 100644
index 000000000000..62ff1008b1ee
--- /dev/null
+++ b/drivers/staging/slicoss/TODO
@@ -0,0 +1,38 @@
+TODO:
+ - move firmware loading to request_firmware()
+ - remove direct memory access of structures
+ - any remaining sparse and checkpatch.pl warnings
+
+ - use net_device_ops
+ - use dev->stats rather than adapter->stats
+ - don't cast netdev_priv it is already void
+ - GET RID OF MACROS
+ - work on all architectures
+ - without CONFIG_X86_64 confusion
+ - do 64 bit correctly
+ - don't depend on order of union
+ - get rid of ASSERT(), use BUG() instead but only where necessary
+ looks like most aren't really useful
+ - no new SIOCDEVPRIVATE ioctl allowed
+ - don't use module_param for configuring interrupt mitigation
+ use ethtool instead
+ - reorder code to elminate use of forward declarations
+ - don't keep private linked list of drivers.
+ - remove all the gratiutous debug infrastructure
+ - use PCI_DEVICE()
+ - do ethtool correctly using ethtool_ops
+ - NAPI?
+ - wasted overhead of extra stats
+ - state variables for things that are
+ easily available and shouldn't be kept in card structure, cardnum, ...
+ slotnumber, events, ...
+ - get rid of slic_spinlock wrapper
+ - volatile == bad design => bad code
+ - locking too fine grained, not designed just throw more locks
+ at problem
+
+Please send patches to:
+ Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+and Cc: Lior Dotan <liodot@gmail.com> and Christopher Harrer
+<charrer@alacritech.com> as well as they are also able to test out any
+changes.
diff --git a/drivers/staging/slicoss/slic.h b/drivers/staging/slicoss/slic.h
index 4c7822bd5358..702902cdb461 100644
--- a/drivers/staging/slicoss/slic.h
+++ b/drivers/staging/slicoss/slic.h
@@ -464,9 +464,12 @@ struct adapter {
/*
* SLIC Handles
*/
- struct slic_handle slic_handles[SLIC_CMDQ_MAXCMDS+1]; /* Object handles*/
- struct slic_handle *pfree_slic_handles; /* Free object handles*/
- struct slic_spinlock handle_lock; /* Object handle list lock*/
+ /* Object handles*/
+ struct slic_handle slic_handles[SLIC_CMDQ_MAXCMDS+1];
+ /* Free object handles*/
+ struct slic_handle *pfree_slic_handles;
+ /* Object handle list lock*/
+ struct slic_spinlock handle_lock;
ushort slic_handle_ix;
u32 xmitq_full;
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index 1426ca49bfe8..e27b88f02ccd 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -100,11 +100,11 @@
#include "slic.h"
static uint slic_first_init = 1;
-static char *slic_banner = "Alacritech SLIC Technology(tm) Server "\
+static char *slic_banner = "Alacritech SLIC Technology(tm) Server "
"and Storage Accelerator (Non-Accelerated)";
static char *slic_proc_version = "2.0.351 2006/07/14 12:26:00";
-static char *slic_product_name = "SLIC Technology(tm) Server "\
+static char *slic_product_name = "SLIC Technology(tm) Server "
"and Storage Accelerator (Non-Accelerated)";
static char *slic_vendor = "Alacritech, Inc.";
@@ -144,29 +144,6 @@ static const struct pci_device_id slic_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, slic_pci_tbl);
-#define SLIC_GET_SLIC_HANDLE(_adapter, _pslic_handle) \
-{ \
- spin_lock_irqsave(&_adapter->handle_lock.lock, \
- _adapter->handle_lock.flags); \
- _pslic_handle = _adapter->pfree_slic_handles; \
- if (_pslic_handle) { \
- _adapter->pfree_slic_handles = _pslic_handle->next; \
- } \
- spin_unlock_irqrestore(&_adapter->handle_lock.lock, \
- _adapter->handle_lock.flags); \
-}
-
-#define SLIC_FREE_SLIC_HANDLE(_adapter, _pslic_handle) \
-{ \
- _pslic_handle->type = SLIC_HANDLE_FREE; \
- spin_lock_irqsave(&_adapter->handle_lock.lock, \
- _adapter->handle_lock.flags); \
- _pslic_handle->next = _adapter->pfree_slic_handles; \
- _adapter->pfree_slic_handles = _pslic_handle; \
- spin_unlock_irqrestore(&_adapter->handle_lock.lock, \
- _adapter->handle_lock.flags); \
-}
-
static inline void slic_reg32_write(void __iomem *reg, u32 value, bool flush)
{
writel(value, reg);
@@ -1442,7 +1419,13 @@ static void slic_cmdq_addcmdpage(struct adapter *adapter, u32 *page)
while ((cmdcnt < SLIC_CMDQ_CMDSINPAGE) &&
(adapter->slic_handle_ix < 256)) {
/* Allocate and initialize a SLIC_HANDLE for this command */
- SLIC_GET_SLIC_HANDLE(adapter, pslic_handle);
+ spin_lock_irqsave(&adapter->handle_lock.lock,
+ adapter->handle_lock.flags);
+ pslic_handle = adapter->pfree_slic_handles;
+ if (pslic_handle)
+ adapter->pfree_slic_handles = pslic_handle->next;
+ spin_unlock_irqrestore(&adapter->handle_lock.lock,
+ adapter->handle_lock.flags);
pslic_handle->type = SLIC_HANDLE_CMD;
pslic_handle->address = (void *) cmd;
pslic_handle->offset = (ushort) adapter->slic_handle_ix++;
@@ -1830,7 +1813,7 @@ static int slic_debug_card_show(struct seq_file *seq, void *v)
#endif
seq_printf(seq, "driver_version : %s\n", slic_proc_version);
- seq_puts(seq, "Microcode versions: \n");
+ seq_puts(seq, "Microcode versions:\n");
seq_printf(seq, " Gigabit (gb) : %s %s\n",
MOJAVE_UCODE_VERS_STRING, MOJAVE_UCODE_VERS_DATE);
seq_printf(seq, " Gigabit Receiver : %s %s\n",
@@ -1917,16 +1900,14 @@ static int slic_debug_card_show(struct seq_file *seq, void *v)
if (config->OEMFruFormat == VENDOR4_FRU_FORMAT) {
seq_printf(seq,
- "Serial # : "
- "%c%c%c%c%c%c%c%c%c%c%c%c\n",
+ "Serial # : %c%c%c%c%c%c%c%c%c%c%c%c\n",
fru[8], fru[9], fru[10],
fru[11], fru[12], fru[13],
fru[16], fru[17], fru[18],
fru[19], fru[20], fru[21]);
} else {
seq_printf(seq,
- "Serial # : "
- "%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
+ "Serial # : %c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
fru[8], fru[9], fru[10],
fru[11], fru[12], fru[13],
fru[14], fru[15], fru[16],
@@ -1974,8 +1955,7 @@ static int slic_debug_card_show(struct seq_file *seq, void *v)
{
seq_puts(seq, "FRU Information:\n");
seq_printf(seq,
- " Part # : "
- "%c%c%c%c%c%c%c%c\n",
+ " Part # : %c%c%c%c%c%c%c%c\n",
oemfru[0], oemfru[1], oemfru[2],
oemfru[3], oemfru[4], oemfru[5],
oemfru[6], oemfru[7]);
@@ -2002,20 +1982,17 @@ static int slic_debug_card_show(struct seq_file *seq, void *v)
{
seq_puts(seq, "FRU Information:\n");
seq_printf(seq,
- " FRU Number : "
- "%c%c%c%c%c%c%c%c\n",
+ " FRU Number : %c%c%c%c%c%c%c%c\n",
oemfru[0], oemfru[1], oemfru[2],
oemfru[3], oemfru[4], oemfru[5],
oemfru[6], oemfru[7]);
seq_sprintf(seq,
- " Part Number : "
- "%c%c%c%c%c%c%c%c\n",
+ " Part Number : %c%c%c%c%c%c%c%c\n",
oemfru[8], oemfru[9], oemfru[10],
oemfru[11], oemfru[12], oemfru[13],
oemfru[14], oemfru[15]);
seq_printf(seq,
- " EC Level : "
- "%c%c%c%c%c%c%c%c\n",
+ " EC Level : %c%c%c%c%c%c%c%c\n",
oemfru[16], oemfru[17], oemfru[18],
oemfru[19], oemfru[20], oemfru[21],
oemfru[22], oemfru[23]);
@@ -2412,8 +2389,7 @@ static void slic_xmit_fail(struct adapter *adapter,
switch (status) {
case XMIT_FAIL_LINK_STATE:
dev_err(&adapter->netdev->dev,
- "reject xmit skb[%p: %x] linkstate[%s] "
- "adapter[%s:%d] card[%s:%d]\n",
+ "reject xmit skb[%p: %x] linkstate[%s] adapter[%s:%d] card[%s:%d]\n",
skb, skb->pkt_type,
SLIC_LINKSTATE(adapter->linkstate),
SLIC_ADAPTER_STATE(adapter->state),
@@ -2428,8 +2404,7 @@ static void slic_xmit_fail(struct adapter *adapter,
break;
case XMIT_FAIL_HOSTCMD_FAIL:
dev_err(&adapter->netdev->dev,
- "xmit_start skb[%p] type[%x] No host commands "
- "available\n", skb, skb->pkt_type);
+ "xmit_start skb[%p] type[%x] No host commands available\n", skb, skb->pkt_type);
break;
}
}
@@ -2642,8 +2617,7 @@ static void slic_interrupt_card_up(u32 isr, struct adapter *adapter,
}
} else if (isr & ISR_XDROP) {
dev_err(&dev->dev,
- "isr & ISR_ERR [%x] "
- "ISR_XDROP \n", isr);
+ "isr & ISR_ERR [%x] ISR_XDROP\n", isr);
} else {
dev_err(&dev->dev,
"isr & ISR_ERR [%x]\n",
@@ -2970,7 +2944,7 @@ static void slic_card_cleanup(struct sliccard *card)
{
if (card->loadtimerset) {
card->loadtimerset = 0;
- del_timer(&card->loadtimer);
+ del_timer_sync(&card->loadtimer);
}
slic_debug_card_destroy(card);
@@ -3269,8 +3243,7 @@ static int slic_card_init(struct sliccard *card, struct adapter *adapter)
if (!peeprom) {
dev_err(&adapter->pcidev->dev,
- "eeprom read failed to get memory "
- "bus %d slot %d\n", adapter->busnumber,
+ "eeprom read failed to get memory bus %d slot %d\n", adapter->busnumber,
adapter->slotnumber);
return -ENOMEM;
} else {
@@ -3703,7 +3676,7 @@ static int slic_entry_probe(struct pci_dev *pcidev,
err = slic_card_locate(adapter);
if (err) {
dev_err(&pcidev->dev, "cannot locate card\n");
- goto err_out_free_mmio_region;
+ goto err_out_unmap;
}
card = adapter->card;
@@ -3743,8 +3716,6 @@ static int slic_entry_probe(struct pci_dev *pcidev,
err_out_unmap:
iounmap(memmapped_ioaddr);
-err_out_free_mmio_region:
- release_mem_region(mmio_start, mmio_len);
err_out_free_netdev:
free_netdev(netdev);
err_out_exit_slic_probe:
diff --git a/drivers/staging/sm7xxfb/Kconfig b/drivers/staging/sm7xxfb/Kconfig
deleted file mode 100644
index e2922ae3a3ee..000000000000
--- a/drivers/staging/sm7xxfb/Kconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-config FB_SM7XX
- tristate "Silicon Motion SM7XX framebuffer support"
- depends on FB && PCI
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
- help
- Frame buffer driver for the Silicon Motion SM710, SM712, SM721
- and SM722 chips.
-
- This driver is also available as a module. The module will be
- called sm7xxfb. If you want to compile it as a module, say M
- here and read <file:Documentation/kbuild/modules.txt>.
diff --git a/drivers/staging/sm7xxfb/Makefile b/drivers/staging/sm7xxfb/Makefile
deleted file mode 100644
index 48f471cf9f36..000000000000
--- a/drivers/staging/sm7xxfb/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_FB_SM7XX) += sm7xxfb.o
diff --git a/drivers/staging/sm7xxfb/TODO b/drivers/staging/sm7xxfb/TODO
deleted file mode 100644
index 1fcead591c16..000000000000
--- a/drivers/staging/sm7xxfb/TODO
+++ /dev/null
@@ -1,9 +0,0 @@
-TODO:
-- Dual head support
-- 2D acceleration support
-- use kernel coding style
-- refine the code and remove unused code
-- move it to drivers/video/sm7xxfb.c
-
-Please send any patches to Greg Kroah-Hartman <greg@kroah.com> and
-Teddy Wang <teddy.wang@siliconmotion.com.cn>.
diff --git a/drivers/staging/sm7xxfb/sm7xx.h b/drivers/staging/sm7xxfb/sm7xx.h
deleted file mode 100644
index 85998615b801..000000000000
--- a/drivers/staging/sm7xxfb/sm7xx.h
+++ /dev/null
@@ -1,779 +0,0 @@
-/*
- * Silicon Motion SM712 frame buffer device
- *
- * Copyright (C) 2006 Silicon Motion Technology Corp.
- * Authors: Ge Wang, gewang@siliconmotion.com
- * Boyod boyod.yang@siliconmotion.com.cn
- *
- * Copyright (C) 2009 Lemote, Inc.
- * Author: Wu Zhangjin, wuzhangjin@gmail.com
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- */
-
-#define NR_PALETTE 256
-
-#define FB_ACCEL_SMI_LYNX 88
-
-#define SCREEN_X_RES 1024
-#define SCREEN_Y_RES 600
-#define SCREEN_BPP 16
-
-/*Assume SM712 graphics chip has 4MB VRAM */
-#define SM712_VIDEOMEMORYSIZE 0x00400000
-/*Assume SM722 graphics chip has 8MB VRAM */
-#define SM722_VIDEOMEMORYSIZE 0x00800000
-
-#define dac_reg (0x3c8)
-#define dac_val (0x3c9)
-
-extern void __iomem *smtc_RegBaseAddress;
-#define smtc_mmiowb(dat, reg) writeb(dat, smtc_RegBaseAddress + reg)
-#define smtc_mmioww(dat, reg) writew(dat, smtc_RegBaseAddress + reg)
-#define smtc_mmiowl(dat, reg) writel(dat, smtc_RegBaseAddress + reg)
-
-#define smtc_mmiorb(reg) readb(smtc_RegBaseAddress + reg)
-#define smtc_mmiorw(reg) readw(smtc_RegBaseAddress + reg)
-#define smtc_mmiorl(reg) readl(smtc_RegBaseAddress + reg)
-
-#define SIZE_SR00_SR04 (0x04 - 0x00 + 1)
-#define SIZE_SR10_SR24 (0x24 - 0x10 + 1)
-#define SIZE_SR30_SR75 (0x75 - 0x30 + 1)
-#define SIZE_SR80_SR93 (0x93 - 0x80 + 1)
-#define SIZE_SRA0_SRAF (0xAF - 0xA0 + 1)
-#define SIZE_GR00_GR08 (0x08 - 0x00 + 1)
-#define SIZE_AR00_AR14 (0x14 - 0x00 + 1)
-#define SIZE_CR00_CR18 (0x18 - 0x00 + 1)
-#define SIZE_CR30_CR4D (0x4D - 0x30 + 1)
-#define SIZE_CR90_CRA7 (0xA7 - 0x90 + 1)
-#define SIZE_VPR (0x6C + 1)
-#define SIZE_DPR (0x44 + 1)
-
-static inline void smtc_crtcw(int reg, int val)
-{
- smtc_mmiowb(reg, 0x3d4);
- smtc_mmiowb(val, 0x3d5);
-}
-
-static inline unsigned int smtc_crtcr(int reg)
-{
- smtc_mmiowb(reg, 0x3d4);
- return smtc_mmiorb(0x3d5);
-}
-
-static inline void smtc_grphw(int reg, int val)
-{
- smtc_mmiowb(reg, 0x3ce);
- smtc_mmiowb(val, 0x3cf);
-}
-
-static inline unsigned int smtc_grphr(int reg)
-{
- smtc_mmiowb(reg, 0x3ce);
- return smtc_mmiorb(0x3cf);
-}
-
-static inline void smtc_attrw(int reg, int val)
-{
- smtc_mmiorb(0x3da);
- smtc_mmiowb(reg, 0x3c0);
- smtc_mmiorb(0x3c1);
- smtc_mmiowb(val, 0x3c0);
-}
-
-static inline void smtc_seqw(int reg, int val)
-{
- smtc_mmiowb(reg, 0x3c4);
- smtc_mmiowb(val, 0x3c5);
-}
-
-static inline unsigned int smtc_seqr(int reg)
-{
- smtc_mmiowb(reg, 0x3c4);
- return smtc_mmiorb(0x3c5);
-}
-
-/* The next structure holds all information relevant for a specific video mode.
- */
-
-struct ModeInit {
- int mmSizeX;
- int mmSizeY;
- int bpp;
- int hz;
- unsigned char Init_MISC;
- unsigned char Init_SR00_SR04[SIZE_SR00_SR04];
- unsigned char Init_SR10_SR24[SIZE_SR10_SR24];
- unsigned char Init_SR30_SR75[SIZE_SR30_SR75];
- unsigned char Init_SR80_SR93[SIZE_SR80_SR93];
- unsigned char Init_SRA0_SRAF[SIZE_SRA0_SRAF];
- unsigned char Init_GR00_GR08[SIZE_GR00_GR08];
- unsigned char Init_AR00_AR14[SIZE_AR00_AR14];
- unsigned char Init_CR00_CR18[SIZE_CR00_CR18];
- unsigned char Init_CR30_CR4D[SIZE_CR30_CR4D];
- unsigned char Init_CR90_CRA7[SIZE_CR90_CRA7];
-};
-
-/**********************************************************************
- SM712 Mode table.
- **********************************************************************/
-struct ModeInit VGAMode[] = {
- {
- /* mode#0: 640 x 480 16Bpp 60Hz */
- 640, 480, 16, 60,
- /* Init_MISC */
- 0xE3,
- { /* Init_SR0_SR4 */
- 0x03, 0x01, 0x0F, 0x00, 0x0E,
- },
- { /* Init_SR10_SR24 */
- 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
- 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xC4, 0x30, 0x02, 0x01, 0x01,
- },
- { /* Init_SR30_SR75 */
- 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
- 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
- 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
- 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
- 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
- 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
- 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
- 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
- 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
- },
- { /* Init_SR80_SR93 */
- 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
- 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
- 0x00, 0x00, 0x00, 0x00,
- },
- { /* Init_SRA0_SRAF */
- 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
- 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
- },
- { /* Init_GR00_GR08 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
- 0xFF,
- },
- { /* Init_AR00_AR14 */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x41, 0x00, 0x0F, 0x00, 0x00,
- },
- { /* Init_CR00_CR18 */
- 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
- 0xFF,
- },
- { /* Init_CR30_CR4D */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
- 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
- 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
- 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
- },
- { /* Init_CR90_CRA7 */
- 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
- 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
- 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
- },
- },
- {
- /* mode#1: 640 x 480 24Bpp 60Hz */
- 640, 480, 24, 60,
- /* Init_MISC */
- 0xE3,
- { /* Init_SR0_SR4 */
- 0x03, 0x01, 0x0F, 0x00, 0x0E,
- },
- { /* Init_SR10_SR24 */
- 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
- 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xC4, 0x30, 0x02, 0x01, 0x01,
- },
- { /* Init_SR30_SR75 */
- 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
- 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
- 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
- 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
- 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
- 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
- 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
- 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
- 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
- },
- { /* Init_SR80_SR93 */
- 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
- 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
- 0x00, 0x00, 0x00, 0x00,
- },
- { /* Init_SRA0_SRAF */
- 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
- 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
- },
- { /* Init_GR00_GR08 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
- 0xFF,
- },
- { /* Init_AR00_AR14 */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x41, 0x00, 0x0F, 0x00, 0x00,
- },
- { /* Init_CR00_CR18 */
- 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
- 0xFF,
- },
- { /* Init_CR30_CR4D */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
- 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
- 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
- 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
- },
- { /* Init_CR90_CRA7 */
- 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
- 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
- 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
- },
- },
- {
- /* mode#0: 640 x 480 32Bpp 60Hz */
- 640, 480, 32, 60,
- /* Init_MISC */
- 0xE3,
- { /* Init_SR0_SR4 */
- 0x03, 0x01, 0x0F, 0x00, 0x0E,
- },
- { /* Init_SR10_SR24 */
- 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
- 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xC4, 0x30, 0x02, 0x01, 0x01,
- },
- { /* Init_SR30_SR75 */
- 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
- 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
- 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
- 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
- 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
- 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
- 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
- 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
- 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
- },
- { /* Init_SR80_SR93 */
- 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
- 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
- 0x00, 0x00, 0x00, 0x00,
- },
- { /* Init_SRA0_SRAF */
- 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
- 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
- },
- { /* Init_GR00_GR08 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
- 0xFF,
- },
- { /* Init_AR00_AR14 */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x41, 0x00, 0x0F, 0x00, 0x00,
- },
- { /* Init_CR00_CR18 */
- 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
- 0xFF,
- },
- { /* Init_CR30_CR4D */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
- 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
- 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
- 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
- },
- { /* Init_CR90_CRA7 */
- 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
- 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
- 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
- },
- },
-
- { /* mode#2: 800 x 600 16Bpp 60Hz */
- 800, 600, 16, 60,
- /* Init_MISC */
- 0x2B,
- { /* Init_SR0_SR4 */
- 0x03, 0x01, 0x0F, 0x03, 0x0E,
- },
- { /* Init_SR10_SR24 */
- 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
- 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xC4, 0x30, 0x02, 0x01, 0x01,
- },
- { /* Init_SR30_SR75 */
- 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
- 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
- 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
- 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
- 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
- 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
- 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
- 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
- 0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
- },
- { /* Init_SR80_SR93 */
- 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
- 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
- 0x00, 0x00, 0x00, 0x00,
- },
- { /* Init_SRA0_SRAF */
- 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
- 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
- },
- { /* Init_GR00_GR08 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
- 0xFF,
- },
- { /* Init_AR00_AR14 */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x41, 0x00, 0x0F, 0x00, 0x00,
- },
- { /* Init_CR00_CR18 */
- 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
- 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
- 0xFF,
- },
- { /* Init_CR30_CR4D */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
- 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
- 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
- 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
- },
- { /* Init_CR90_CRA7 */
- 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
- 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
- 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
- },
- },
- { /* mode#3: 800 x 600 24Bpp 60Hz */
- 800, 600, 24, 60,
- 0x2B,
- { /* Init_SR0_SR4 */
- 0x03, 0x01, 0x0F, 0x03, 0x0E,
- },
- { /* Init_SR10_SR24 */
- 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
- 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xC4, 0x30, 0x02, 0x01, 0x01,
- },
- { /* Init_SR30_SR75 */
- 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF,
- 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
- 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36,
- 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
- 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36,
- 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
- 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
- 0x02, 0x45, 0x30, 0x30, 0x40, 0x20,
- },
- { /* Init_SR80_SR93 */
- 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36,
- 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36,
- 0x00, 0x00, 0x00, 0x00,
- },
- { /* Init_SRA0_SRAF */
- 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
- 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
- },
- { /* Init_GR00_GR08 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
- 0xFF,
- },
- { /* Init_AR00_AR14 */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x41, 0x00, 0x0F, 0x00, 0x00,
- },
- { /* Init_CR00_CR18 */
- 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
- 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
- 0xFF,
- },
- { /* Init_CR30_CR4D */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
- 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
- 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
- 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
- },
- { /* Init_CR90_CRA7 */
- 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
- 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
- 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
- },
- },
- { /* mode#7: 800 x 600 32Bpp 60Hz */
- 800, 600, 32, 60,
- /* Init_MISC */
- 0x2B,
- { /* Init_SR0_SR4 */
- 0x03, 0x01, 0x0F, 0x03, 0x0E,
- },
- { /* Init_SR10_SR24 */
- 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
- 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xC4, 0x30, 0x02, 0x01, 0x01,
- },
- { /* Init_SR30_SR75 */
- 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
- 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
- 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
- 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
- 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
- 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
- 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
- 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
- 0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
- },
- { /* Init_SR80_SR93 */
- 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
- 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
- 0x00, 0x00, 0x00, 0x00,
- },
- { /* Init_SRA0_SRAF */
- 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
- 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
- },
- { /* Init_GR00_GR08 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
- 0xFF,
- },
- { /* Init_AR00_AR14 */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x41, 0x00, 0x0F, 0x00, 0x00,
- },
- { /* Init_CR00_CR18 */
- 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
- 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
- 0xFF,
- },
- { /* Init_CR30_CR4D */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
- 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
- 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
- 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
- },
- { /* Init_CR90_CRA7 */
- 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
- 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
- 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
- },
- },
- /* We use 1024x768 table to light 1024x600 panel for lemote */
- { /* mode#4: 1024 x 600 16Bpp 60Hz */
- 1024, 600, 16, 60,
- /* Init_MISC */
- 0xEB,
- { /* Init_SR0_SR4 */
- 0x03, 0x01, 0x0F, 0x00, 0x0E,
- },
- { /* Init_SR10_SR24 */
- 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20,
- 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xC4, 0x30, 0x02, 0x00, 0x01,
- },
- { /* Init_SR30_SR75 */
- 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF,
- 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
- 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22,
- 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
- 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22,
- 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
- 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02,
- 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20,
- },
- { /* Init_SR80_SR93 */
- 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
- 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
- 0x00, 0x00, 0x00, 0x00,
- },
- { /* Init_SRA0_SRAF */
- 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
- 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
- },
- { /* Init_GR00_GR08 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
- 0xFF,
- },
- { /* Init_AR00_AR14 */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x41, 0x00, 0x0F, 0x00, 0x00,
- },
- { /* Init_CR00_CR18 */
- 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
- 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
- 0xFF,
- },
- { /* Init_CR30_CR4D */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
- 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
- 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00,
- 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57,
- },
- { /* Init_CR90_CRA7 */
- 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
- 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
- },
- },
- { /* mode#5: 1024 x 768 24Bpp 60Hz */
- 1024, 768, 24, 60,
- /* Init_MISC */
- 0xEB,
- { /* Init_SR0_SR4 */
- 0x03, 0x01, 0x0F, 0x03, 0x0E,
- },
- { /* Init_SR10_SR24 */
- 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
- 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xC4, 0x30, 0x02, 0x01, 0x01,
- },
- { /* Init_SR30_SR75 */
- 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
- 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
- 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
- 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
- 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
- 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
- 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
- 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
- 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
- },
- { /* Init_SR80_SR93 */
- 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
- 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
- 0x00, 0x00, 0x00, 0x00,
- },
- { /* Init_SRA0_SRAF */
- 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
- 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
- },
- { /* Init_GR00_GR08 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
- 0xFF,
- },
- { /* Init_AR00_AR14 */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x41, 0x00, 0x0F, 0x00, 0x00,
- },
- { /* Init_CR00_CR18 */
- 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
- 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
- 0xFF,
- },
- { /* Init_CR30_CR4D */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
- 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
- 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
- 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
- },
- { /* Init_CR90_CRA7 */
- 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
- 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
- },
- },
- { /* mode#4: 1024 x 768 32Bpp 60Hz */
- 1024, 768, 32, 60,
- /* Init_MISC */
- 0xEB,
- { /* Init_SR0_SR4 */
- 0x03, 0x01, 0x0F, 0x03, 0x0E,
- },
- { /* Init_SR10_SR24 */
- 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
- 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xC4, 0x32, 0x02, 0x01, 0x01,
- },
- { /* Init_SR30_SR75 */
- 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
- 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
- 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
- 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
- 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
- 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
- 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
- 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
- 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
- },
- { /* Init_SR80_SR93 */
- 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
- 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
- 0x00, 0x00, 0x00, 0x00,
- },
- { /* Init_SRA0_SRAF */
- 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
- 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
- },
- { /* Init_GR00_GR08 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
- 0xFF,
- },
- { /* Init_AR00_AR14 */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x41, 0x00, 0x0F, 0x00, 0x00,
- },
- { /* Init_CR00_CR18 */
- 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
- 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
- 0xFF,
- },
- { /* Init_CR30_CR4D */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
- 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
- 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
- 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
- },
- { /* Init_CR90_CRA7 */
- 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
- 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
- },
- },
- { /* mode#6: 320 x 240 16Bpp 60Hz */
- 320, 240, 16, 60,
- /* Init_MISC */
- 0xEB,
- { /* Init_SR0_SR4 */
- 0x03, 0x01, 0x0F, 0x03, 0x0E,
- },
- { /* Init_SR10_SR24 */
- 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
- 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xC4, 0x32, 0x02, 0x01, 0x01,
- },
- { /* Init_SR30_SR75 */
- 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
- 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
- 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
- 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
- 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
- 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
- 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
- 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
- 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
- },
- { /* Init_SR80_SR93 */
- 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
- 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
- 0x00, 0x00, 0x00, 0x00,
- },
- { /* Init_SRA0_SRAF */
- 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
- 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
- },
- { /* Init_GR00_GR08 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
- 0xFF,
- },
- { /* Init_AR00_AR14 */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x41, 0x00, 0x0F, 0x00, 0x00,
- },
- { /* Init_CR00_CR18 */
- 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
- 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
- 0xFF,
- },
- { /* Init_CR30_CR4D */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
- 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
- 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
- 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
- },
- { /* Init_CR90_CRA7 */
- 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
- 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
- },
- },
-
- { /* mode#8: 320 x 240 32Bpp 60Hz */
- 320, 240, 32, 60,
- /* Init_MISC */
- 0xEB,
- { /* Init_SR0_SR4 */
- 0x03, 0x01, 0x0F, 0x03, 0x0E,
- },
- { /* Init_SR10_SR24 */
- 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
- 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xC4, 0x32, 0x02, 0x01, 0x01,
- },
- { /* Init_SR30_SR75 */
- 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
- 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
- 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
- 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
- 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
- 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
- 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
- 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
- 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
- },
- { /* Init_SR80_SR93 */
- 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
- 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
- 0x00, 0x00, 0x00, 0x00,
- },
- { /* Init_SRA0_SRAF */
- 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
- 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
- },
- { /* Init_GR00_GR08 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
- 0xFF,
- },
- { /* Init_AR00_AR14 */
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x41, 0x00, 0x0F, 0x00, 0x00,
- },
- { /* Init_CR00_CR18 */
- 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
- 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
- 0xFF,
- },
- { /* Init_CR30_CR4D */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
- 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
- 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
- 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
- },
- { /* Init_CR90_CRA7 */
- 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
- 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
- },
- },
-};
-
-#define numVGAModes ARRAY_SIZE(VGAMode)
diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c
deleted file mode 100644
index 6176d98744cc..000000000000
--- a/drivers/staging/sm7xxfb/sm7xxfb.c
+++ /dev/null
@@ -1,1028 +0,0 @@
-/*
- * Silicon Motion SM7XX frame buffer device
- *
- * Copyright (C) 2006 Silicon Motion Technology Corp.
- * Authors: Ge Wang, gewang@siliconmotion.com
- * Boyod boyod.yang@siliconmotion.com.cn
- *
- * Copyright (C) 2009 Lemote, Inc.
- * Author: Wu Zhangjin, wuzhangjin@gmail.com
- *
- * Copyright (C) 2011 Igalia, S.L.
- * Author: Javier M. Mellid <jmunhoz@igalia.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- *
- * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips
- */
-
-#include <linux/io.h>
-#include <linux/fb.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/screen_info.h>
-
-#ifdef CONFIG_PM
-#include <linux/pm.h>
-#endif
-
-#include "sm7xx.h"
-
-/*
-* Private structure
-*/
-struct smtcfb_info {
- struct pci_dev *pdev;
- struct fb_info fb;
- u16 chip_id;
- u8 chip_rev_id;
-
- void __iomem *lfb; /* linear frame buffer */
- void __iomem *dp_regs; /* drawing processor control regs */
- void __iomem *vp_regs; /* video processor control regs */
- void __iomem *cp_regs; /* capture processor control regs */
- void __iomem *mmio; /* memory map IO port */
-
- u_int width;
- u_int height;
- u_int hz;
-
- u32 colreg[17];
-};
-
-void __iomem *smtc_RegBaseAddress; /* Memory Map IO starting address */
-
-static struct fb_var_screeninfo smtcfb_var = {
- .xres = 1024,
- .yres = 600,
- .xres_virtual = 1024,
- .yres_virtual = 600,
- .bits_per_pixel = 16,
- .red = {16, 8, 0},
- .green = {8, 8, 0},
- .blue = {0, 8, 0},
- .activate = FB_ACTIVATE_NOW,
- .height = -1,
- .width = -1,
- .vmode = FB_VMODE_NONINTERLACED,
- .nonstd = 0,
- .accel_flags = FB_ACCELF_TEXT,
-};
-
-static struct fb_fix_screeninfo smtcfb_fix = {
- .id = "smXXXfb",
- .type = FB_TYPE_PACKED_PIXELS,
- .visual = FB_VISUAL_TRUECOLOR,
- .line_length = 800 * 3,
- .accel = FB_ACCEL_SMI_LYNX,
- .type_aux = 0,
- .xpanstep = 0,
- .ypanstep = 0,
- .ywrapstep = 0,
-};
-
-struct vesa_mode {
- char index[6];
- u16 lfb_width;
- u16 lfb_height;
- u16 lfb_depth;
-};
-
-static struct vesa_mode vesa_mode_table[] = {
- {"0x301", 640, 480, 8},
- {"0x303", 800, 600, 8},
- {"0x305", 1024, 768, 8},
- {"0x307", 1280, 1024, 8},
-
- {"0x311", 640, 480, 16},
- {"0x314", 800, 600, 16},
- {"0x317", 1024, 768, 16},
- {"0x31A", 1280, 1024, 16},
-
- {"0x312", 640, 480, 24},
- {"0x315", 800, 600, 24},
- {"0x318", 1024, 768, 24},
- {"0x31B", 1280, 1024, 24},
-};
-
-struct screen_info smtc_scr_info;
-
-/* process command line options, get vga parameter */
-static int __init sm7xx_vga_setup(char *options)
-{
- int i;
-
- if (!options || !*options)
- return -EINVAL;
-
- smtc_scr_info.lfb_width = 0;
- smtc_scr_info.lfb_height = 0;
- smtc_scr_info.lfb_depth = 0;
-
- pr_debug("sm7xx_vga_setup = %s\n", options);
-
- for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
- if (strstr(options, vesa_mode_table[i].index)) {
- smtc_scr_info.lfb_width = vesa_mode_table[i].lfb_width;
- smtc_scr_info.lfb_height =
- vesa_mode_table[i].lfb_height;
- smtc_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth;
- return 0;
- }
- }
-
- return -1;
-}
-__setup("vga=", sm7xx_vga_setup);
-
-static void sm712_setpalette(int regno, unsigned red, unsigned green,
- unsigned blue, struct fb_info *info)
-{
- /* set bit 5:4 = 01 (write LCD RAM only) */
- smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
-
- smtc_mmiowb(regno, dac_reg);
- smtc_mmiowb(red >> 10, dac_val);
- smtc_mmiowb(green >> 10, dac_val);
- smtc_mmiowb(blue >> 10, dac_val);
-}
-
-/* chan_to_field
- *
- * convert a colour value into a field position
- *
- * from pxafb.c
- */
-
-static inline unsigned int chan_to_field(unsigned int chan,
- struct fb_bitfield *bf)
-{
- chan &= 0xffff;
- chan >>= 16 - bf->length;
- return chan << bf->offset;
-}
-
-static int smtc_blank(int blank_mode, struct fb_info *info)
-{
- /* clear DPMS setting */
- switch (blank_mode) {
- case FB_BLANK_UNBLANK:
- /* Screen On: HSync: On, VSync : On */
- smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
- smtc_seqw(0x6a, 0x16);
- smtc_seqw(0x6b, 0x02);
- smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
- smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
- smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
- smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
- smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
- break;
- case FB_BLANK_NORMAL:
- /* Screen Off: HSync: On, VSync : On Soft blank */
- smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
- smtc_seqw(0x6a, 0x16);
- smtc_seqw(0x6b, 0x02);
- smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
- smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
- smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
- smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
- break;
- case FB_BLANK_VSYNC_SUSPEND:
- /* Screen On: HSync: On, VSync : Off */
- smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
- smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
- smtc_seqw(0x6a, 0x0c);
- smtc_seqw(0x6b, 0x02);
- smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
- smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
- smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
- smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
- smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
- smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
- break;
- case FB_BLANK_HSYNC_SUSPEND:
- /* Screen On: HSync: Off, VSync : On */
- smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
- smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
- smtc_seqw(0x6a, 0x0c);
- smtc_seqw(0x6b, 0x02);
- smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
- smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
- smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
- smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
- smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
- smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
- break;
- case FB_BLANK_POWERDOWN:
- /* Screen On: HSync: Off, VSync : Off */
- smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
- smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
- smtc_seqw(0x6a, 0x0c);
- smtc_seqw(0x6b, 0x02);
- smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
- smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
- smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
- smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
- smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
- smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned trans, struct fb_info *info)
-{
- struct smtcfb_info *sfb;
- u32 val;
-
- sfb = info->par;
-
- if (regno > 255)
- return 1;
-
- switch (sfb->fb.fix.visual) {
- case FB_VISUAL_DIRECTCOLOR:
- case FB_VISUAL_TRUECOLOR:
- /*
- * 16/32 bit true-colour, use pseudo-palette for 16 base color
- */
- if (regno < 16) {
- if (sfb->fb.var.bits_per_pixel == 16) {
- u32 *pal = sfb->fb.pseudo_palette;
- val = chan_to_field(red, &sfb->fb.var.red);
- val |= chan_to_field(green, &sfb->fb.var.green);
- val |= chan_to_field(blue, &sfb->fb.var.blue);
-#ifdef __BIG_ENDIAN
- pal[regno] =
- ((red & 0xf800) >> 8) |
- ((green & 0xe000) >> 13) |
- ((green & 0x1c00) << 3) |
- ((blue & 0xf800) >> 3);
-#else
- pal[regno] = val;
-#endif
- } else {
- u32 *pal = sfb->fb.pseudo_palette;
- val = chan_to_field(red, &sfb->fb.var.red);
- val |= chan_to_field(green, &sfb->fb.var.green);
- val |= chan_to_field(blue, &sfb->fb.var.blue);
-#ifdef __BIG_ENDIAN
- val =
- (val & 0xff00ff00 >> 8) |
- (val & 0x00ff00ff << 8);
-#endif
- pal[regno] = val;
- }
- }
- break;
-
- case FB_VISUAL_PSEUDOCOLOR:
- /* color depth 8 bit */
- sm712_setpalette(regno, red, green, blue, info);
- break;
-
- default:
- return 1; /* unknown type */
- }
-
- return 0;
-
-}
-
-#ifdef __BIG_ENDIAN
-static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, size_t
- count, loff_t *ppos)
-{
- unsigned long p = *ppos;
-
- u32 *buffer, *dst;
- u32 __iomem *src;
- int c, i, cnt = 0, err = 0;
- unsigned long total_size;
-
- if (!info || !info->screen_base)
- return -ENODEV;
-
- if (info->state != FBINFO_STATE_RUNNING)
- return -EPERM;
-
- total_size = info->screen_size;
-
- if (total_size == 0)
- total_size = info->fix.smem_len;
-
- if (p >= total_size)
- return 0;
-
- if (count >= total_size)
- count = total_size;
-
- if (count + p > total_size)
- count = total_size - p;
-
- buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- src = (u32 __iomem *) (info->screen_base + p);
-
- if (info->fbops->fb_sync)
- info->fbops->fb_sync(info);
-
- while (count) {
- c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
- dst = buffer;
- for (i = c >> 2; i--;) {
- *dst = fb_readl(src++);
- *dst =
- (*dst & 0xff00ff00 >> 8) |
- (*dst & 0x00ff00ff << 8);
- dst++;
- }
- if (c & 3) {
- u8 *dst8 = (u8 *) dst;
- u8 __iomem *src8 = (u8 __iomem *) src;
-
- for (i = c & 3; i--;) {
- if (i & 1) {
- *dst8++ = fb_readb(++src8);
- } else {
- *dst8++ = fb_readb(--src8);
- src8 += 2;
- }
- }
- src = (u32 __iomem *) src8;
- }
-
- if (copy_to_user(buf, buffer, c)) {
- err = -EFAULT;
- break;
- }
- *ppos += c;
- buf += c;
- cnt += c;
- count -= c;
- }
-
- kfree(buffer);
-
- return (err) ? err : cnt;
-}
-
-static ssize_t
-smtcfb_write(struct fb_info *info, const char __user *buf, size_t count,
- loff_t *ppos)
-{
- unsigned long p = *ppos;
-
- u32 *buffer, *src;
- u32 __iomem *dst;
- int c, i, cnt = 0, err = 0;
- unsigned long total_size;
-
- if (!info || !info->screen_base)
- return -ENODEV;
-
- if (info->state != FBINFO_STATE_RUNNING)
- return -EPERM;
-
- total_size = info->screen_size;
-
- if (total_size == 0)
- total_size = info->fix.smem_len;
-
- if (p > total_size)
- return -EFBIG;
-
- if (count > total_size) {
- err = -EFBIG;
- count = total_size;
- }
-
- if (count + p > total_size) {
- if (!err)
- err = -ENOSPC;
-
- count = total_size - p;
- }
-
- buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- dst = (u32 __iomem *) (info->screen_base + p);
-
- if (info->fbops->fb_sync)
- info->fbops->fb_sync(info);
-
- while (count) {
- c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
- src = buffer;
-
- if (copy_from_user(src, buf, c)) {
- err = -EFAULT;
- break;
- }
-
- for (i = c >> 2; i--;) {
- fb_writel((*src & 0xff00ff00 >> 8) |
- (*src & 0x00ff00ff << 8), dst++);
- src++;
- }
- if (c & 3) {
- u8 *src8 = (u8 *) src;
- u8 __iomem *dst8 = (u8 __iomem *) dst;
-
- for (i = c & 3; i--;) {
- if (i & 1) {
- fb_writeb(*src8++, ++dst8);
- } else {
- fb_writeb(*src8++, --dst8);
- dst8 += 2;
- }
- }
- dst = (u32 __iomem *) dst8;
- }
-
- *ppos += c;
- buf += c;
- cnt += c;
- count -= c;
- }
-
- kfree(buffer);
-
- return (cnt) ? cnt : err;
-}
-#endif /* ! __BIG_ENDIAN */
-
-static void sm7xx_set_timing(struct smtcfb_info *sfb)
-{
- int i = 0, j = 0;
- u32 m_nScreenStride;
-
- dev_dbg(&sfb->pdev->dev,
- "sfb->width=%d sfb->height=%d "
- "sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n",
- sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz);
-
- for (j = 0; j < numVGAModes; j++) {
- if (VGAMode[j].mmSizeX == sfb->width &&
- VGAMode[j].mmSizeY == sfb->height &&
- VGAMode[j].bpp == sfb->fb.var.bits_per_pixel &&
- VGAMode[j].hz == sfb->hz) {
-
- dev_dbg(&sfb->pdev->dev,
- "VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d "
- "VGAMode[j].bpp=%d VGAMode[j].hz=%d\n",
- VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
- VGAMode[j].bpp, VGAMode[j].hz);
-
- dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j);
-
- smtc_mmiowb(0x0, 0x3c6);
-
- smtc_seqw(0, 0x1);
-
- smtc_mmiowb(VGAMode[j].Init_MISC, 0x3c2);
-
- /* init SEQ register SR00 - SR04 */
- for (i = 0; i < SIZE_SR00_SR04; i++)
- smtc_seqw(i, VGAMode[j].Init_SR00_SR04[i]);
-
- /* init SEQ register SR10 - SR24 */
- for (i = 0; i < SIZE_SR10_SR24; i++)
- smtc_seqw(i + 0x10,
- VGAMode[j].Init_SR10_SR24[i]);
-
- /* init SEQ register SR30 - SR75 */
- for (i = 0; i < SIZE_SR30_SR75; i++)
- if ((i + 0x30) != 0x62 &&
- (i + 0x30) != 0x6a &&
- (i + 0x30) != 0x6b)
- smtc_seqw(i + 0x30,
- VGAMode[j].Init_SR30_SR75[i]);
-
- /* init SEQ register SR80 - SR93 */
- for (i = 0; i < SIZE_SR80_SR93; i++)
- smtc_seqw(i + 0x80,
- VGAMode[j].Init_SR80_SR93[i]);
-
- /* init SEQ register SRA0 - SRAF */
- for (i = 0; i < SIZE_SRA0_SRAF; i++)
- smtc_seqw(i + 0xa0,
- VGAMode[j].Init_SRA0_SRAF[i]);
-
- /* init Graphic register GR00 - GR08 */
- for (i = 0; i < SIZE_GR00_GR08; i++)
- smtc_grphw(i, VGAMode[j].Init_GR00_GR08[i]);
-
- /* init Attribute register AR00 - AR14 */
- for (i = 0; i < SIZE_AR00_AR14; i++)
- smtc_attrw(i, VGAMode[j].Init_AR00_AR14[i]);
-
- /* init CRTC register CR00 - CR18 */
- for (i = 0; i < SIZE_CR00_CR18; i++)
- smtc_crtcw(i, VGAMode[j].Init_CR00_CR18[i]);
-
- /* init CRTC register CR30 - CR4D */
- for (i = 0; i < SIZE_CR30_CR4D; i++)
- smtc_crtcw(i + 0x30,
- VGAMode[j].Init_CR30_CR4D[i]);
-
- /* init CRTC register CR90 - CRA7 */
- for (i = 0; i < SIZE_CR90_CRA7; i++)
- smtc_crtcw(i + 0x90,
- VGAMode[j].Init_CR90_CRA7[i]);
- }
- }
- smtc_mmiowb(0x67, 0x3c2);
-
- /* set VPR registers */
- writel(0x0, sfb->vp_regs + 0x0C);
- writel(0x0, sfb->vp_regs + 0x40);
-
- /* set data width */
- m_nScreenStride =
- (sfb->width * sfb->fb.var.bits_per_pixel) / 64;
- switch (sfb->fb.var.bits_per_pixel) {
- case 8:
- writel(0x0, sfb->vp_regs + 0x0);
- break;
- case 16:
- writel(0x00020000, sfb->vp_regs + 0x0);
- break;
- case 24:
- writel(0x00040000, sfb->vp_regs + 0x0);
- break;
- case 32:
- writel(0x00030000, sfb->vp_regs + 0x0);
- break;
- }
- writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride),
- sfb->vp_regs + 0x10);
-
-}
-
-static void smtc_set_timing(struct smtcfb_info *sfb)
-{
- switch (sfb->chip_id) {
- case 0x710:
- case 0x712:
- case 0x720:
- sm7xx_set_timing(sfb);
- break;
- }
-}
-
-static void smtcfb_setmode(struct smtcfb_info *sfb)
-{
- switch (sfb->fb.var.bits_per_pixel) {
- case 32:
- sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
- sfb->fb.fix.line_length = sfb->fb.var.xres * 4;
- sfb->fb.var.red.length = 8;
- sfb->fb.var.green.length = 8;
- sfb->fb.var.blue.length = 8;
- sfb->fb.var.red.offset = 16;
- sfb->fb.var.green.offset = 8;
- sfb->fb.var.blue.offset = 0;
- break;
- case 24:
- sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
- sfb->fb.fix.line_length = sfb->fb.var.xres * 3;
- sfb->fb.var.red.length = 8;
- sfb->fb.var.green.length = 8;
- sfb->fb.var.blue.length = 8;
- sfb->fb.var.red.offset = 16;
- sfb->fb.var.green.offset = 8;
- sfb->fb.var.blue.offset = 0;
- break;
- case 8:
- sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
- sfb->fb.fix.line_length = sfb->fb.var.xres;
- sfb->fb.var.red.length = 3;
- sfb->fb.var.green.length = 3;
- sfb->fb.var.blue.length = 2;
- sfb->fb.var.red.offset = 5;
- sfb->fb.var.green.offset = 2;
- sfb->fb.var.blue.offset = 0;
- break;
- case 16:
- default:
- sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
- sfb->fb.fix.line_length = sfb->fb.var.xres * 2;
- sfb->fb.var.red.length = 5;
- sfb->fb.var.green.length = 6;
- sfb->fb.var.blue.length = 5;
- sfb->fb.var.red.offset = 11;
- sfb->fb.var.green.offset = 5;
- sfb->fb.var.blue.offset = 0;
- break;
- }
-
- sfb->width = sfb->fb.var.xres;
- sfb->height = sfb->fb.var.yres;
- sfb->hz = 60;
- smtc_set_timing(sfb);
-}
-
-static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-{
- /* sanity checks */
- if (var->xres_virtual < var->xres)
- var->xres_virtual = var->xres;
-
- if (var->yres_virtual < var->yres)
- var->yres_virtual = var->yres;
-
- /* set valid default bpp */
- if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) &&
- (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
- var->bits_per_pixel = 16;
-
- return 0;
-}
-
-static int smtc_set_par(struct fb_info *info)
-{
- smtcfb_setmode(info->par);
-
- return 0;
-}
-
-static struct fb_ops smtcfb_ops = {
- .owner = THIS_MODULE,
- .fb_check_var = smtc_check_var,
- .fb_set_par = smtc_set_par,
- .fb_setcolreg = smtc_setcolreg,
- .fb_blank = smtc_blank,
- .fb_fillrect = cfb_fillrect,
- .fb_imageblit = cfb_imageblit,
- .fb_copyarea = cfb_copyarea,
-#ifdef __BIG_ENDIAN
- .fb_read = smtcfb_read,
- .fb_write = smtcfb_write,
-#endif
-};
-
-/*
- * alloc struct smtcfb_info and assign default values
- */
-static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev)
-{
- struct smtcfb_info *sfb;
-
- sfb = kzalloc(sizeof(*sfb), GFP_KERNEL);
-
- if (!sfb)
- return NULL;
-
- sfb->pdev = pdev;
-
- sfb->fb.flags = FBINFO_FLAG_DEFAULT;
- sfb->fb.fbops = &smtcfb_ops;
- sfb->fb.fix = smtcfb_fix;
- sfb->fb.var = smtcfb_var;
- sfb->fb.pseudo_palette = sfb->colreg;
- sfb->fb.par = sfb;
-
- return sfb;
-}
-
-/*
- * free struct smtcfb_info
- */
-static void smtc_free_fb_info(struct smtcfb_info *sfb)
-{
- kfree(sfb);
-}
-
-/*
- * Unmap in the memory mapped IO registers
- */
-
-static void smtc_unmap_mmio(struct smtcfb_info *sfb)
-{
- if (sfb && smtc_RegBaseAddress)
- smtc_RegBaseAddress = NULL;
-}
-
-/*
- * Map in the screen memory
- */
-
-static int smtc_map_smem(struct smtcfb_info *sfb,
- struct pci_dev *pdev, u_long smem_len)
-{
-
- sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
-
-#ifdef __BIG_ENDIAN
- if (sfb->fb.var.bits_per_pixel == 32)
- sfb->fb.fix.smem_start += 0x800000;
-#endif
-
- sfb->fb.fix.smem_len = smem_len;
-
- sfb->fb.screen_base = sfb->lfb;
-
- if (!sfb->fb.screen_base) {
- dev_err(&pdev->dev,
- "%s: unable to map screen memory\n", sfb->fb.fix.id);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-/*
- * Unmap in the screen memory
- *
- */
-static void smtc_unmap_smem(struct smtcfb_info *sfb)
-{
- if (sfb && sfb->fb.screen_base) {
- iounmap(sfb->fb.screen_base);
- sfb->fb.screen_base = NULL;
- }
-}
-
-/*
- * We need to wake up the device and make sure its in linear memory mode.
- */
-static inline void sm7xx_init_hw(void)
-{
- outb_p(0x18, 0x3c4);
- outb_p(0x11, 0x3c5);
-}
-
-static int smtcfb_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct smtcfb_info *sfb;
- u_long smem_size = 0x00800000; /* default 8MB */
- int err;
- unsigned long mmio_base;
-
- dev_info(&pdev->dev, "Silicon Motion display driver.");
-
- err = pci_enable_device(pdev); /* enable SMTC chip */
- if (err)
- return err;
-
- sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
-
- sfb = smtc_alloc_fb_info(pdev);
-
- if (!sfb) {
- err = -ENOMEM;
- goto failed_free;
- }
-
- sfb->chip_id = ent->device;
-
- pci_set_drvdata(pdev, sfb);
-
- sm7xx_init_hw();
-
- /* get mode parameter from smtc_scr_info */
- if (smtc_scr_info.lfb_width != 0) {
- sfb->fb.var.xres = smtc_scr_info.lfb_width;
- sfb->fb.var.yres = smtc_scr_info.lfb_height;
- sfb->fb.var.bits_per_pixel = smtc_scr_info.lfb_depth;
- } else {
- /* default resolution 1024x600 16bit mode */
- sfb->fb.var.xres = SCREEN_X_RES;
- sfb->fb.var.yres = SCREEN_Y_RES;
- sfb->fb.var.bits_per_pixel = SCREEN_BPP;
- }
-
-#ifdef __BIG_ENDIAN
- if (sfb->fb.var.bits_per_pixel == 24)
- sfb->fb.var.bits_per_pixel = (smtc_scr_info.lfb_depth = 32);
-#endif
- /* Map address and memory detection */
- mmio_base = pci_resource_start(pdev, 0);
- pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
-
- switch (sfb->chip_id) {
- case 0x710:
- case 0x712:
- sfb->fb.fix.mmio_start = mmio_base + 0x00400000;
- sfb->fb.fix.mmio_len = 0x00400000;
- smem_size = SM712_VIDEOMEMORYSIZE;
-#ifdef __BIG_ENDIAN
- sfb->lfb = ioremap(mmio_base, 0x00c00000);
-#else
- sfb->lfb = ioremap(mmio_base, 0x00800000);
-#endif
- sfb->mmio = (smtc_RegBaseAddress =
- sfb->lfb + 0x00700000);
- sfb->dp_regs = sfb->lfb + 0x00408000;
- sfb->vp_regs = sfb->lfb + 0x0040c000;
-#ifdef __BIG_ENDIAN
- if (sfb->fb.var.bits_per_pixel == 32) {
- sfb->lfb += 0x800000;
- dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb);
- }
-#endif
- if (!smtc_RegBaseAddress) {
- dev_err(&pdev->dev,
- "%s: unable to map memory mapped IO!",
- sfb->fb.fix.id);
- err = -ENOMEM;
- goto failed_fb;
- }
-
- /* set MCLK = 14.31818 * (0x16 / 0x2) */
- smtc_seqw(0x6a, 0x16);
- smtc_seqw(0x6b, 0x02);
- smtc_seqw(0x62, 0x3e);
- /* enable PCI burst */
- smtc_seqw(0x17, 0x20);
- /* enable word swap */
-#ifdef __BIG_ENDIAN
- if (sfb->fb.var.bits_per_pixel == 32)
- smtc_seqw(0x17, 0x30);
-#endif
- break;
- case 0x720:
- sfb->fb.fix.mmio_start = mmio_base;
- sfb->fb.fix.mmio_len = 0x00200000;
- smem_size = SM722_VIDEOMEMORYSIZE;
- sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
- sfb->lfb = sfb->dp_regs + 0x00200000;
- sfb->mmio = (smtc_RegBaseAddress =
- sfb->dp_regs + 0x000c0000);
- sfb->vp_regs = sfb->dp_regs + 0x800;
-
- smtc_seqw(0x62, 0xff);
- smtc_seqw(0x6a, 0x0d);
- smtc_seqw(0x6b, 0x02);
- break;
- default:
- dev_err(&pdev->dev,
- "No valid Silicon Motion display chip was detected!");
-
- goto failed_fb;
- }
-
- /* can support 32 bpp */
- if (15 == sfb->fb.var.bits_per_pixel)
- sfb->fb.var.bits_per_pixel = 16;
-
- sfb->fb.var.xres_virtual = sfb->fb.var.xres;
- sfb->fb.var.yres_virtual = sfb->fb.var.yres;
- err = smtc_map_smem(sfb, pdev, smem_size);
- if (err)
- goto failed;
-
- smtcfb_setmode(sfb);
-
- err = register_framebuffer(&sfb->fb);
- if (err < 0)
- goto failed;
-
- dev_info(&pdev->dev,
- "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.",
- sfb->chip_id, sfb->chip_rev_id, sfb->fb.var.xres,
- sfb->fb.var.yres, sfb->fb.var.bits_per_pixel);
-
- return 0;
-
-failed:
- dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.");
-
- smtc_unmap_smem(sfb);
- smtc_unmap_mmio(sfb);
-failed_fb:
- smtc_free_fb_info(sfb);
-
-failed_free:
- pci_disable_device(pdev);
-
- return err;
-}
-
-/*
- * 0x710 (LynxEM)
- * 0x712 (LynxEM+)
- * 0x720 (Lynx3DM, Lynx3DM+)
- */
-static const struct pci_device_id smtcfb_pci_table[] = {
- { PCI_DEVICE(0x126f, 0x710), },
- { PCI_DEVICE(0x126f, 0x712), },
- { PCI_DEVICE(0x126f, 0x720), },
- {0,}
-};
-
-static void smtcfb_pci_remove(struct pci_dev *pdev)
-{
- struct smtcfb_info *sfb;
-
- sfb = pci_get_drvdata(pdev);
- smtc_unmap_smem(sfb);
- smtc_unmap_mmio(sfb);
- unregister_framebuffer(&sfb->fb);
- smtc_free_fb_info(sfb);
-}
-
-#ifdef CONFIG_PM
-static int smtcfb_pci_suspend(struct device *device)
-{
- struct pci_dev *pdev = to_pci_dev(device);
- struct smtcfb_info *sfb;
-
- sfb = pci_get_drvdata(pdev);
-
- /* set the hw in sleep mode use external clock and self memory refresh
- * so that we can turn off internal PLLs later on
- */
- smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
- smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
-
- console_lock();
- fb_set_suspend(&sfb->fb, 1);
- console_unlock();
-
- /* additionally turn off all function blocks including internal PLLs */
- smtc_seqw(0x21, 0xff);
-
- return 0;
-}
-
-static int smtcfb_pci_resume(struct device *device)
-{
- struct pci_dev *pdev = to_pci_dev(device);
- struct smtcfb_info *sfb;
-
- sfb = pci_get_drvdata(pdev);
-
- /* reinit hardware */
- sm7xx_init_hw();
- switch (sfb->chip_id) {
- case 0x710:
- case 0x712:
- /* set MCLK = 14.31818 * (0x16 / 0x2) */
- smtc_seqw(0x6a, 0x16);
- smtc_seqw(0x6b, 0x02);
- smtc_seqw(0x62, 0x3e);
- /* enable PCI burst */
- smtc_seqw(0x17, 0x20);
-#ifdef __BIG_ENDIAN
- if (sfb->fb.var.bits_per_pixel == 32)
- smtc_seqw(0x17, 0x30);
-#endif
- break;
- case 0x720:
- smtc_seqw(0x62, 0xff);
- smtc_seqw(0x6a, 0x0d);
- smtc_seqw(0x6b, 0x02);
- break;
- }
-
- smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
- smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
-
- smtcfb_setmode(sfb);
-
- console_lock();
- fb_set_suspend(&sfb->fb, 0);
- console_unlock();
-
- return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
-#define SM7XX_PM_OPS (&sm7xx_pm_ops)
-
-#else /* !CONFIG_PM */
-
-#define SM7XX_PM_OPS NULL
-
-#endif /* !CONFIG_PM */
-
-static struct pci_driver smtcfb_driver = {
- .name = "smtcfb",
- .id_table = smtcfb_pci_table,
- .probe = smtcfb_pci_probe,
- .remove = smtcfb_pci_remove,
- .driver.pm = SM7XX_PM_OPS,
-};
-
-module_pci_driver(smtcfb_driver);
-
-MODULE_AUTHOR("Siliconmotion ");
-MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/speakup/serialio.c b/drivers/staging/speakup/serialio.c
index 4e18fb405344..c62d74c47906 100644
--- a/drivers/staging/speakup/serialio.c
+++ b/drivers/staging/speakup/serialio.c
@@ -40,7 +40,7 @@ const struct old_serial_port *spk_serial_init(int index)
cval |= UART_LCR_EPAR;
if (synth_request_region(ser->port, 8)) {
/* try to take it back. */
- printk(KERN_INFO "Ports not available, trying to steal them\n");
+ pr_info("Ports not available, trying to steal them\n");
__release_region(&ioport_resource, ser->port, 8);
err = synth_request_region(ser->port, 8);
if (err) {
@@ -106,7 +106,7 @@ static void start_serial_interrupt(int irq)
"serial", (void *) synth_readbuf_handler);
if (rv)
- printk(KERN_ERR "Unable to request Speakup serial I R Q\n");
+ pr_err("Unable to request Speakup serial I R Q\n");
/* Set MCR */
outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2,
speakup_info.port_tts + UART_MCR);
diff --git a/drivers/staging/speakup/speakup_dectlk.c b/drivers/staging/speakup/speakup_dectlk.c
index 15fdec323a70..756d01535d3e 100644
--- a/drivers/staging/speakup/speakup_dectlk.c
+++ b/drivers/staging/speakup/speakup_dectlk.c
@@ -270,10 +270,12 @@ static void do_catch_up(struct spk_synth *synth)
if (jiffies >= jiff_max) {
if (!in_escape)
spk_serial_out(PROCSPEECH);
- spin_lock_irqsave(&speakup_info.spinlock, flags);
+ spin_lock_irqsave(&speakup_info.spinlock,
+ flags);
jiffy_delta_val = jiffy_delta->u.n.value;
delay_time_val = delay_time->u.n.value;
- spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+ spin_unlock_irqrestore(&speakup_info.spinlock,
+ flags);
schedule_timeout(msecs_to_jiffies
(delay_time_val));
jiff_max = jiffies + jiffy_delta_val;
diff --git a/drivers/staging/tidspbridge/Kconfig b/drivers/staging/tidspbridge/Kconfig
index 1b6d581c438b..b5e74e9de6bd 100644
--- a/drivers/staging/tidspbridge/Kconfig
+++ b/drivers/staging/tidspbridge/Kconfig
@@ -17,7 +17,7 @@ menuconfig TIDSPBRIDGE
config TIDSPBRIDGE_DVFS
bool "Enable Bridge Dynamic Voltage and Frequency Scaling (DVFS)"
- depends on TIDSPBRIDGE && OMAP_PM_SRF && CPU_FREQ
+ depends on TIDSPBRIDGE && CPU_FREQ
help
DVFS allows DSP Bridge to initiate the operating point change to
scale the chip voltage and frequency in order to match the
diff --git a/drivers/staging/tidspbridge/core/io_sm.c b/drivers/staging/tidspbridge/core/io_sm.c
index e322fb7aebe1..c2829aa7780f 100644
--- a/drivers/staging/tidspbridge/core/io_sm.c
+++ b/drivers/staging/tidspbridge/core/io_sm.c
@@ -2127,7 +2127,7 @@ void dump_dl_modules(struct bridge_dev_context *bridge_context)
u32 module_size;
u32 module_struct_size = 0;
u32 sect_ndx;
- char *sect_str ;
+ char *sect_str;
int status = 0;
status = dev_get_intf_fxns(dev_object, &intf_fxns);
diff --git a/drivers/staging/tidspbridge/core/tiomap3430.c b/drivers/staging/tidspbridge/core/tiomap3430.c
index b770b2281ce8..8945b4e3a2a6 100644
--- a/drivers/staging/tidspbridge/core/tiomap3430.c
+++ b/drivers/staging/tidspbridge/core/tiomap3430.c
@@ -280,9 +280,8 @@ static int bridge_brd_monitor(struct bridge_dev_context *dev_ctxt)
OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL);
/* Wait until the state has moved to ON */
- while ((*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
- OMAP_INTRANSITION_MASK)
- ;
+ while (*pdata->dsp_prm_read(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST)&
+ OMAP_INTRANSITION_MASK);
/* Disable Automatic transition */
(*pdata->dsp_cm_write)(OMAP34XX_CLKSTCTRL_DISABLE_AUTO,
OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL);
@@ -419,7 +418,8 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
/* Assert RST1 i.e only the RST only for DSP megacell */
if (!status) {
(*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK,
- OMAP3430_RST1_IVA2_MASK, OMAP3430_IVA2_MOD,
+ OMAP3430_RST1_IVA2_MASK,
+ OMAP3430_IVA2_MOD,
OMAP2_RM_RSTCTRL);
/* Mask address with 1K for compatibility */
@@ -432,7 +432,8 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
/* Reset and Unreset the RST2, so that BOOTADDR is copied to
* IVA2 SYSC register */
(*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK,
- OMAP3430_RST2_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
+ OMAP3430_RST2_IVA2_MASK, OMAP3430_IVA2_MOD,
+ OMAP2_RM_RSTCTRL);
udelay(100);
(*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK, 0,
OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
@@ -446,7 +447,8 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
/* Only make TLB entry if both addresses are non-zero */
for (entry_ndx = 0; entry_ndx < BRDIOCTL_NUMOFMMUTLB;
entry_ndx++) {
- struct bridge_ioctl_extproc *e = &dev_context->atlb_entry[entry_ndx];
+ struct bridge_ioctl_extproc *e =
+ &dev_context->atlb_entry[entry_ndx];
struct hw_mmu_map_attrs_t map_attrs = {
.endianism = e->endianism,
.element_size = e->elem_size,
@@ -641,8 +643,8 @@ static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt)
/* as per TRM, it is advised to first drive the IVA2 to 'Standby' mode,
* before turning off the clocks.. This is to ensure that there are no
* pending L3 or other transactons from IVA2 */
- dsp_pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
- OMAP_POWERSTATEST_MASK;
+ dsp_pwr_state = (*pdata->dsp_prm_read)
+ (OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) & OMAP_POWERSTATEST_MASK;
if (dsp_pwr_state != PWRDM_POWER_OFF) {
(*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK, 0,
OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
@@ -682,8 +684,9 @@ static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt)
dev_context->mbox = NULL;
}
/* Reset IVA2 clocks*/
- (*pdata->dsp_prm_write)(OMAP3430_RST1_IVA2_MASK | OMAP3430_RST2_IVA2_MASK |
- OMAP3430_RST3_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
+ (*pdata->dsp_prm_write)(OMAP3430_RST1_IVA2_MASK |
+ OMAP3430_RST2_IVA2_MASK | OMAP3430_RST3_IVA2_MASK,
+ OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
dsp_clock_disable_all(dev_context->dsp_per_clks);
dsp_clk_disable(DSP_CLK_IVA2);
diff --git a/drivers/staging/tidspbridge/core/tiomap3430_pwr.c b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
index 1862afd80dc1..657104f37f7d 100644
--- a/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
+++ b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c
@@ -99,7 +99,8 @@ int handle_hibernation_from_dsp(struct bridge_dev_context *dev_context)
return -EPERM;
}
pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD,
- OMAP2_PM_PWSTST) & OMAP_POWERSTATEST_MASK;
+ OMAP2_PM_PWSTST) &
+ OMAP_POWERSTATEST_MASK;
}
if (timeout == 0) {
pr_err("%s: Timed out waiting for DSP off mode\n", __func__);
@@ -209,7 +210,8 @@ int sleep_dsp(struct bridge_dev_context *dev_context, u32 dw_cmd,
return -EPERM;
}
pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD,
- OMAP2_PM_PWSTST) & OMAP_POWERSTATEST_MASK;
+ OMAP2_PM_PWSTST) &
+ OMAP_POWERSTATEST_MASK;
}
if (!timeout) {
@@ -355,7 +357,7 @@ int pre_scale_dsp(struct bridge_dev_context *dev_context, void *pargs)
(dev_context->brd_state == BRD_DSP_HIBERNATION)) {
dev_dbg(bridge, "OPP: %s IVA in sleep. No message to DSP\n");
return 0;
- } else if ((dev_context->brd_state == BRD_RUNNING)) {
+ } else if (dev_context->brd_state == BRD_RUNNING) {
/* Send a prenotification to DSP */
dev_dbg(bridge, "OPP: %s sent notification to DSP\n", __func__);
sm_interrupt_dsp(dev_context, MBX_PM_SETPOINT_PRENOTIFY);
@@ -396,13 +398,14 @@ int post_scale_dsp(struct bridge_dev_context *dev_context,
io_sh_msetting(hio_mgr, SHM_CURROPP, &level);
dev_dbg(bridge, "OPP: %s IVA in sleep. Wrote to shm\n",
__func__);
- } else if ((dev_context->brd_state == BRD_RUNNING)) {
+ } else if (dev_context->brd_state == BRD_RUNNING) {
/* Update the OPP value in shared memory */
io_sh_msetting(hio_mgr, SHM_CURROPP, &level);
/* Send a post notification to DSP */
sm_interrupt_dsp(dev_context, MBX_PM_SETPOINT_POSTNOTIFY);
- dev_dbg(bridge, "OPP: %s wrote to shm. Sent post notification "
- "to DSP\n", __func__);
+ dev_dbg(bridge,
+ "OPP: %s wrote to shm. Sent post notification to DSP\n",
+ __func__);
} else {
status = -EPERM;
}
diff --git a/drivers/staging/tidspbridge/dynload/tramp.c b/drivers/staging/tidspbridge/dynload/tramp.c
index 404af1895980..5f0431305fbb 100644
--- a/drivers/staging/tidspbridge/dynload/tramp.c
+++ b/drivers/staging/tidspbridge/dynload/tramp.c
@@ -503,7 +503,7 @@ static int priv_tgt_img_gen(struct dload_state *dlthis, u32 base,
* TRAMPOLINES ARE TREATED AS 2ND PASS even though this is really
* the first (and only) relocation that will be performed on them.
*/
-static int priv_pkt_relo(struct dload_state *dlthis, tgt_au_t * data,
+static int priv_pkt_relo(struct dload_state *dlthis, tgt_au_t *data,
struct reloc_record_t *rp[], u32 relo_count)
{
int ret_val = 1;
diff --git a/drivers/staging/tidspbridge/rmgr/dbdcd.c b/drivers/staging/tidspbridge/rmgr/dbdcd.c
index 190ca3fe7327..2ae48c9a9362 100644
--- a/drivers/staging/tidspbridge/rmgr/dbdcd.c
+++ b/drivers/staging/tidspbridge/rmgr/dbdcd.c
@@ -101,14 +101,14 @@ static int dcd_uuid_from_string(char *sz_uuid, struct dsp_uuid *uuid_obj)
* if the converted value doesn't fit in u32. So, convert the
* last six bytes to u64 and memcpy what is needed
*/
- if(sscanf(sz_uuid, "%8x%c%4hx%c%4hx%c%2hhx%2hhx%c%llx",
+ if (sscanf(sz_uuid, "%8x%c%4hx%c%4hx%c%2hhx%2hhx%c%llx",
&uuid_tmp.data1, &c, &uuid_tmp.data2, &c,
&uuid_tmp.data3, &c, &uuid_tmp.data4,
&uuid_tmp.data5, &c, &t) != 10)
return -EINVAL;
t = cpu_to_be64(t);
- memcpy(&uuid_tmp.data6[0], ((char*)&t) + 2, 6);
+ memcpy(&uuid_tmp.data6[0], ((char *)&t) + 2, 6);
*uuid_obj = uuid_tmp;
return 0;
diff --git a/drivers/staging/tidspbridge/rmgr/drv.c b/drivers/staging/tidspbridge/rmgr/drv.c
index be26917a6896..757ae20b38ee 100644
--- a/drivers/staging/tidspbridge/rmgr/drv.c
+++ b/drivers/staging/tidspbridge/rmgr/drv.c
@@ -738,7 +738,7 @@ void mem_ext_phys_pool_release(void)
* Allocate physically contiguous, uncached memory from external memory pool
*/
-static void *mem_ext_phys_mem_alloc(u32 bytes, u32 align, u32 * phys_addr)
+static void *mem_ext_phys_mem_alloc(u32 bytes, u32 align, u32 *phys_addr)
{
u32 new_alloc_ptr;
u32 offset;
diff --git a/drivers/staging/tidspbridge/rmgr/mgr.c b/drivers/staging/tidspbridge/rmgr/mgr.c
index b32ba0ad2a07..93e6282f122b 100644
--- a/drivers/staging/tidspbridge/rmgr/mgr.c
+++ b/drivers/staging/tidspbridge/rmgr/mgr.c
@@ -266,15 +266,15 @@ int mgr_enum_processor_info(u32 processor_id,
* this is a clumsy overwrite */
processor_info->processor_type = DSPTYPE64;
} else {
- dev_dbg(bridge, "%s: Failed to get DCD processor info "
- "%x\n", __func__, status2);
+ dev_dbg(bridge, "%s: Failed to get DCD processor info %x\n",
+ __func__, status2);
status = -EPERM;
}
}
*pu_num_procs = proc_index;
if (proc_detect == false) {
- dev_dbg(bridge, "%s: Failed to get proc info from DCD, so use "
- "CFG registry\n", __func__);
+ dev_dbg(bridge, "%s: Failed to get proc info from DCD, so use CFG registry\n",
+ __func__);
processor_info->processor_type = DSPTYPE64;
}
func_end:
diff --git a/drivers/staging/tidspbridge/rmgr/nldr.c b/drivers/staging/tidspbridge/rmgr/nldr.c
index ca3805046a73..5ac507ccd19d 100644
--- a/drivers/staging/tidspbridge/rmgr/nldr.c
+++ b/drivers/staging/tidspbridge/rmgr/nldr.c
@@ -623,7 +623,7 @@ void nldr_delete(struct nldr_object *nldr_obj)
* ======== nldr_get_fxn_addr ========
*/
int nldr_get_fxn_addr(struct nldr_nodeobject *nldr_node_obj,
- char *str_fxn, u32 * addr)
+ char *str_fxn, u32 *addr)
{
struct dbll_sym_val *dbll_sym;
struct nldr_object *nldr_obj;
@@ -1751,9 +1751,8 @@ static void unload_ovly(struct nldr_nodeobject *nldr_node_obj,
}
if (ref_count && (*ref_count > 0)) {
*ref_count -= 1;
- if (other_ref) {
+ if (other_ref)
*other_ref -= 1;
- }
}
if (ref_count && *ref_count == 0) {
diff --git a/drivers/staging/tidspbridge/rmgr/node.c b/drivers/staging/tidspbridge/rmgr/node.c
index 87dfa92ab45b..9d3044a384ee 100644
--- a/drivers/staging/tidspbridge/rmgr/node.c
+++ b/drivers/staging/tidspbridge/rmgr/node.c
@@ -246,7 +246,7 @@ static void fill_stream_def(struct node_object *hnode,
struct node_strmdef *pstrm_def,
struct dsp_strmattr *pattrs);
static void free_stream(struct node_mgr *hnode_mgr, struct stream_chnl stream);
-static int get_fxn_address(struct node_object *hnode, u32 * fxn_addr,
+static int get_fxn_address(struct node_object *hnode, u32 *fxn_addr,
u32 phase);
static int get_node_props(struct dcd_manager *hdcd_mgr,
struct node_object *hnode,
@@ -406,7 +406,7 @@ int node_allocate(struct proc_object *hprocessor,
/* check for page aligned Heap size */
if (((attr_in->heap_size) & (PG_SIZE4K - 1))) {
- pr_err("%s: node heap size not aligned to 4K, size = 0x%x \n",
+ pr_err("%s: node heap size not aligned to 4K, size = 0x%x\n",
__func__, attr_in->heap_size);
status = -EINVAL;
} else {
@@ -703,9 +703,9 @@ DBAPI node_alloc_msg_buf(struct node_object *hnode, u32 usize,
pattr = &node_dfltbufattrs; /* set defaults */
status = proc_get_processor_id(pnode->processor, &proc_id);
- if (proc_id != DSP_UNIT) {
+ if (proc_id != DSP_UNIT)
goto func_end;
- }
+
/* If segment ID includes MEM_SETVIRTUALSEGID then pbuffer is a
* virt address, so set this info in this node's translator
* object for future ref. If MEM_GETVIRTUALSEGID then retrieve
@@ -886,11 +886,10 @@ int node_connect(struct node_object *node1, u32 stream1,
if (pattrs && pattrs->strm_mode != STRMMODE_PROCCOPY)
return -EPERM; /* illegal stream mode */
- if (node1_type != NODE_GPP) {
+ if (node1_type != NODE_GPP)
hnode_mgr = node1->node_mgr;
- } else {
+ else
hnode_mgr = node2->node_mgr;
- }
/* Enter critical section */
mutex_lock(&hnode_mgr->node_mgr_lock);
@@ -1576,7 +1575,7 @@ func_end:
* Purpose:
* Frees the message buffer.
*/
-int node_free_msg_buf(struct node_object *hnode, u8 * pbuffer,
+int node_free_msg_buf(struct node_object *hnode, u8 *pbuffer,
struct dsp_bufferattr *pattr)
{
struct node_object *pnode = (struct node_object *)hnode;
@@ -2322,7 +2321,8 @@ int node_terminate(struct node_object *hnode, int *pstatus)
if (!hdeh_mgr)
goto func_cont;
- bridge_deh_notify(hdeh_mgr, DSP_SYSERROR, DSP_EXCEPTIONABORT);
+ bridge_deh_notify(hdeh_mgr, DSP_SYSERROR,
+ DSP_EXCEPTIONABORT);
}
}
func_cont:
@@ -2640,7 +2640,7 @@ static void free_stream(struct node_mgr *hnode_mgr, struct stream_chnl stream)
* Purpose:
* Retrieves the address for create, execute or delete phase for a node.
*/
-static int get_fxn_address(struct node_object *hnode, u32 * fxn_addr,
+static int get_fxn_address(struct node_object *hnode, u32 *fxn_addr,
u32 phase)
{
char *pstr_fxn_name = NULL;
diff --git a/drivers/staging/unisys/Documentation/overview.txt b/drivers/staging/unisys/Documentation/overview.txt
new file mode 100644
index 000000000000..8d078e4de3b8
--- /dev/null
+++ b/drivers/staging/unisys/Documentation/overview.txt
@@ -0,0 +1,174 @@
+
+Overview
+
+This document describes the driver set for Unisys Secure Partitioning (s-Par®).
+
+s-Par is firmware that provides hardware partitioning capabilities for
+splitting large-scale Intel x86 servers into multiple isolated
+partitions. s-Par provides a set of para-virtualized device drivers to
+allow guest partitions on the same server to share devices that would
+normally be unsharable; specifically, PCI network interfaces and host
+bus adapters that do not support shared access via SR-IOV. The shared
+device is owned and managed by a small, single-purpose service
+partition, which communicates with each guest partition sharing that
+device through an area of shared memory called a channel. Additional
+drivers provide support interfaces for communicating with s-Par
+services, logging and diagnostics, and accessing the Linux console
+from the s-Par user interface.
+
+The driver stack consists of a set of support modules, a set of bus
+modules, and a set of device driver modules. The support modules
+handle a number of common functions across each of the other
+drivers. The bus modules provide organization for the device driver
+modules, which provide the shared device functionality.
+
+These drivers are for the Unisys virtual PCI hardware model where the
+hypervisor need not intervene (other than normal interrupt handling)
+in the interactions between the client drivers and the virtual adapter
+firmware in the adapter service partition.
+
+Driver Descriptions
+
+Device Modules
+
+The modules in this section handle shared devices and the virtual
+buses required to support them. These modules use functions in and
+depend on the modules described in the support modules section.
+
+visorchipset
+
+The visorchipset module receives device creation and destruction
+events from the Command service partition of s-Par, as well as
+controlling registration of shared device drivers with the s-Par
+driver core. The events received are used to populate other s-Par
+modules with their assigned shared devices. Visorchipset is required
+for shared device drivers to function properly. Visorchipset also
+stores information for handling dump disk device creation during
+kdump.
+
+In operation, the visorchipset module processes device creation and
+destruction messages sent by s-Par's Command service partition through
+a channel. These messages result in creation (or destruction) of each
+virtual bus and virtual device. Each bus and device is also associated
+with a communication channel, which is used to communicate with one or
+more IO service partitions to perform device IO on behalf of the
+guest.
+
+virthba
+
+The virthba module provides access to a shared SCSI host bus adapter
+and one or more disk devices, by proxying SCSI commands between the
+guest and the service partition that owns the shared SCSI adapter,
+using a channel between the guest and the service partition. The disks
+that appear on the shared bus are defined by the s-Par configuration
+and enforced by the service partition, while the guest driver handles
+sending commands and handling responses. Each disk is shared as a
+whole to a guest. Sharing the bus adapter in this way provides
+resiliency; should the device encounter an error, only the service
+partition is rebooted, and the device is reinitialized. This allows
+guests to continue running and to recover from the error.
+
+virtnic
+
+The virtnic module provides a paravirtualized network interface to a
+guest by proxying buffer information between the guest and the service
+partition that owns the shared network interface, using a channel
+between the guest and the service partition. The connectivity of this
+interface with the shared interface and possibly other guest
+partitions is defined by the s-Par configuration and enforced by the
+service partition; the guest driver handles communication and link
+status.
+
+visorserial
+
+The visorserial module allows the console of the linux guest to be
+accessed via the s-Par console serial channel. It creates devices in
+/dev/visorserialclientX which behave like a serial terminal and are
+connected to the diagnostics system in s-Par. By assigning a getty to
+the terminal in the guest, a user could log into and access the guest
+from the s-Par diagnostics SWITCH RUN terminal.
+
+visorbus
+
+The visorbus module handles the bus functions for most functional
+drivers except visorserial, visordiag, virthba, and virtnic. It
+maintains the sysfs subtree /sys/devices/visorbus*/. It is responsible
+for device creation and destruction of the devices on its bus.
+
+visorclientbus
+
+The visorclientbus module forwards the bus functions for virthba, and
+virtnic to the virtpci driver.
+
+virtpci
+
+The virtpci module handles the bus functions for virthba, and virtnic.
+
+s-Par Integration Modules
+
+The modules in this section provide integration with s-Par guest
+partition services like diagnostics and remote desktop. These modules
+depend on functions in the modules described in the support modules
+section.
+
+visorvideoclient
+
+The visorvideoclient module provides functionality for video support
+for the Unisys s-Par Partition Desktop application. The guest OS must
+also have the UEFI GOP protocol enabled for the partition desktop to
+function. visorconinclient The visorconinclient module provides
+keyboard and mouse support for the Unisys s-Par Partition Desktop
+application.
+
+sparstop
+
+The sparstop module handles requests from the Unisys s-Par platform to
+shutdown the linux guest. It allows a program on the guest to perform
+clean-up functions on the guest before the guest is shut down or
+rebooted using ACPI.
+
+visordiag
+
+This driver provides the ability for the guest to write information
+into the s-Par diagnostics subsystem. It creates a set of devices
+named /dev/visordiag.X which can be written to by the guest to add
+text to the s-Par system log.
+
+Support Modules
+
+The modules described in this section provide functions and
+abstractions to support the modules described in the previous
+sections, to avoid having duplicated functionality.
+
+visornoop
+
+The visornoop module is a placeholder that responds to device
+create/destroy messages that are currently not in use by linux guests.
+
+visoruislib
+
+The visoruislib module is a support library, used to handle requests
+from virtpci.
+
+visorchannelstub
+
+The visorchannelstub module provides support routines for storing and
+retrieving data from a channel.
+
+visorchannel
+
+The visorchannel module is a support library that abstracts reading
+and writing a channel in memory.
+
+visorutil
+
+The visorutil module is a support library required by all other s-Par
+driver modules. Among its features it abstracts reading, writing, and
+manipulating a block of memory.
+
+Minimum Required Driver Set
+
+The drivers required to boot a Linux guest are visorchipset, visorbus,
+visorvideoclient, visorconinclient, visoruislib, visorchannelstub,
+visorchannel, and visorutil. The other drivers are required by the
+product configurations that are currently being marketed.
diff --git a/drivers/staging/unisys/Documentation/proc-entries.txt b/drivers/staging/unisys/Documentation/proc-entries.txt
new file mode 100644
index 000000000000..426f92b1c577
--- /dev/null
+++ b/drivers/staging/unisys/Documentation/proc-entries.txt
@@ -0,0 +1,93 @@
+ s-Par Proc Entries
+This document describes the proc entries created by the Unisys s-Par modules.
+
+Support Module Entries
+These entries are provided primarily for debugging.
+
+/proc/uislib/info: This entry contains debugging information for the
+uislib module, including bus information and memory usage.
+
+/proc/visorchipset/controlvm: This directory contains debugging
+entries for the controlvm channel used by visorchipset.
+
+/proc/uislib/platform: This entry is used to display the platform
+number this node is in the system. For some guests, this may be
+invalid.
+
+/proc/visorchipset/chipsetready: This entry is written to by scripts
+to signify that any user level activity has been completed before the
+guest can be considered running and is shown as running in the s-Par
+UI.
+
+Device Entries
+These entries provide status of the devices shared by a service partition.
+
+/proc/uislib/vbus: this is a directory containing entries for each
+virtual bus. Each numbered sub-directory contains an info entry, which
+describes the devices that appear on that bus.
+
+/proc/uislib/cycles_before_wait: This entry is used to tune
+performance, by setting the number of cycles we wait before going idle
+when in polling mode. A longer time will reduce message latency but
+spend more processing time polling.
+
+/proc/uislib/smart_wakeup: This entry is used to tune performance, by
+enabling or disabling smart wakeup.
+
+/proc/virthba/info: This entry contains debugging information for the
+virthba module, including interrupt information and memory usage.
+
+/proc/virthba/enable_ints: This entry controls interrupt use by the
+virthba module. Writing a 0 to this entry will disable interrupts.
+
+/proc/virtnic/info: This entry contains debugging information for the
+virtnic module, including interrupt information, send and receive
+counts, and other device information.
+
+/proc/virtnic/ethX: This is a directory containing entries for each
+virtual NIC. Each named subdirectory contains two entries,
+clientstring and zone.
+
+/proc/virtpci/info: This entry contains debugging information for the
+virtpci module, including virtual PCI bus information and device
+locations.
+
+/proc/virtnic/enable_ints: This entry controls interrupt use by the
+virtnic module. Writing a 0 to this entry will disable interrupts.
+
+Visorconinclient, visordiag, visornoop, visorserialclient, and
+visorvideoclient Entries
+
+The entries in proc for these modules all follow the same
+pattern. Each module has its own proc directory with the same name,
+e.g. visordiag presents a /proc/visordiag directory. Inside of the
+module's directory are a device directory, which contains one numbered
+directory for each device provided by that module. Each device has a
+diag entry that presents the device number and visorbus name for that
+device. The module directory also has a driver/diag entry, which
+reports the corresponding s-Par version number of the driver.
+
+Automated Installation Entries
+
+These entries are used to pass information between the s-Par platform
+and the Linux-based installation and recovery tool. These values are
+read/write, however, the guest can only reset them to 0, or report an
+error status through the installer entry. The values are only set via
+s-Par's firmware interface, to help prevent accidentally booting into
+the tool.
+
+/proc/visorchipset/boottotool: This entry instructs s-Par that the
+next reboot will launch the installation and recovery tool. If set to
+0, the next boot will happen according to the UEFI boot manager
+settings.
+
+/proc/visorchipset/toolaction: This entry indicates the installation
+and recovery tool mode requested for the next boot.
+
+/proc/visorchipset/installer: this entry is used by the installation
+and recovery tool to pass status and result information back to the
+s-Par firmware.
+
+/proc/visorchipset/partition: This directory contains the guest
+partition configuration data for each virtual bus, for use during
+installation and at runtime for s-Par service partitions.
diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig
new file mode 100644
index 000000000000..ac080c9dcf46
--- /dev/null
+++ b/drivers/staging/unisys/Kconfig
@@ -0,0 +1,20 @@
+#
+# Unisys SPAR driver configuration
+#
+menuconfig UNISYSSPAR
+ bool "Unisys SPAR driver support"
+ depends on X86_64
+ ---help---
+ Support for the Unisys SPAR drivers
+
+if UNISYSSPAR
+
+source "drivers/staging/unisys/visorutil/Kconfig"
+source "drivers/staging/unisys/visorchannel/Kconfig"
+source "drivers/staging/unisys/visorchipset/Kconfig"
+source "drivers/staging/unisys/channels/Kconfig"
+source "drivers/staging/unisys/uislib/Kconfig"
+source "drivers/staging/unisys/virtpci/Kconfig"
+source "drivers/staging/unisys/virthba/Kconfig"
+
+endif # UNISYSSPAR
diff --git a/drivers/staging/unisys/MAINTAINERS b/drivers/staging/unisys/MAINTAINERS
new file mode 100644
index 000000000000..c9cef0b91531
--- /dev/null
+++ b/drivers/staging/unisys/MAINTAINERS
@@ -0,0 +1,6 @@
+Unisys s-Par drivers
+M: Ben Romer <sparmaintainer@unisys.com>
+S: Maintained
+F: Documentation/s-Par/overview.txt
+F: Documentation/s-Par/proc-entries.txt
+F: drivers/staging/unisys/
diff --git a/drivers/staging/unisys/Makefile b/drivers/staging/unisys/Makefile
new file mode 100644
index 000000000000..b988d6940aae
--- /dev/null
+++ b/drivers/staging/unisys/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for Unisys SPAR drivers
+#
+obj-$(CONFIG_UNISYS_VISORUTIL) += visorutil/
+obj-$(CONFIG_UNISYS_VISORCHANNEL) += visorchannel/
+obj-$(CONFIG_UNISYS_VISORCHIPSET) += visorchipset/
+obj-$(CONFIG_UNISYS_CHANNELSTUB) += channels/
+obj-$(CONFIG_UNISYS_UISLIB) += uislib/
+obj-$(CONFIG_UNISYS_VIRTPCI) += virtpci/
+obj-$(CONFIG_UNISYS_VIRTHBA) += virthba/
diff --git a/drivers/staging/unisys/TODO b/drivers/staging/unisys/TODO
new file mode 100644
index 000000000000..034ac61c44f2
--- /dev/null
+++ b/drivers/staging/unisys/TODO
@@ -0,0 +1,21 @@
+TODO:
+ -checkpatch warnings
+ -move /proc entries to /sys
+ -proper major number(s)
+ -add other drivers needed for full functionality:
+ -visorclientbus
+ -visorbus
+ -visordiag
+ -virtnic
+ -visornoop
+ -visorserial
+ -visorvideoclient
+ -visorconinclient
+ -sparstop
+ -move individual drivers into proper driver subsystems
+
+
+Patches to:
+ Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+ Ken Cox <jkc@redhat.com>
+ Unisys s-Par maintainer mailing list <sparmaintainer@unisys.com>
diff --git a/drivers/staging/unisys/channels/Kconfig b/drivers/staging/unisys/channels/Kconfig
new file mode 100644
index 000000000000..47a235385567
--- /dev/null
+++ b/drivers/staging/unisys/channels/Kconfig
@@ -0,0 +1,10 @@
+#
+# Unisys channels configuration
+#
+
+config UNISYS_CHANNELSTUB
+ tristate "Unisys channelstub driver"
+ depends on UNISYSSPAR
+ ---help---
+ If you say Y here, you will enable the Unisys channels driver.
+
diff --git a/drivers/staging/unisys/channels/Makefile b/drivers/staging/unisys/channels/Makefile
new file mode 100644
index 000000000000..e60b0aef4dcd
--- /dev/null
+++ b/drivers/staging/unisys/channels/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for Unisys channelstub
+#
+
+obj-$(CONFIG_UNISYS_CHANNELSTUB) += visorchannelstub.o
+
+visorchannelstub-y := channel.o chanstub.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+ccflags-y += -Idrivers/staging/unisys/common-spar/include
+ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
+ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION
+
diff --git a/drivers/staging/unisys/channels/channel.c b/drivers/staging/unisys/channels/channel.c
new file mode 100644
index 000000000000..f6452595b742
--- /dev/null
+++ b/drivers/staging/unisys/channels/channel.c
@@ -0,0 +1,219 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#include <linux/kernel.h>
+#ifdef CONFIG_MODVERSIONS
+#include <config/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/init.h> /* for module_init and module_exit */
+#include <linux/slab.h> /* for memcpy */
+#include <linux/types.h>
+
+/* Implementation of exported functions for Supervisor channels */
+#include "channel.h"
+
+/*
+ * Routine Description:
+ * Tries to insert the prebuilt signal pointed to by pSignal into the nth
+ * Queue of the Channel pointed to by pChannel
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ * pSignal: (IN) pointer to the signal
+ *
+ * Assumptions:
+ * - pChannel, Queue and pSignal are valid.
+ * - If insertion fails due to a full queue, the caller will determine the
+ * retry policy (e.g. wait & try again, report an error, etc.).
+ *
+ * Return value:
+ * 1 if the insertion succeeds, 0 if the queue was full.
+ */
+unsigned char
+visor_signal_insert(CHANNEL_HEADER __iomem *pChannel, U32 Queue, void *pSignal)
+{
+ void __iomem *psignal;
+ unsigned int head, tail, nof;
+
+ SIGNAL_QUEUE_HEADER __iomem *pqhdr =
+ (SIGNAL_QUEUE_HEADER __iomem *)
+ ((char __iomem *) pChannel + readq(&pChannel->oChannelSpace))
+ + Queue;
+
+ /* capture current head and tail */
+ head = readl(&pqhdr->Head);
+ tail = readl(&pqhdr->Tail);
+
+ /* queue is full if (head + 1) % n equals tail */
+ if (((head + 1) % readl(&pqhdr->MaxSignalSlots)) == tail) {
+ nof = readq(&pqhdr->NumOverflows) + 1;
+ writeq(nof, &pqhdr->NumOverflows);
+ return 0;
+ }
+
+ /* increment the head index */
+ head = (head + 1) % readl(&pqhdr->MaxSignalSlots);
+
+ /* copy signal to the head location from the area pointed to
+ * by pSignal
+ */
+ psignal = (char __iomem *)pqhdr + readq(&pqhdr->oSignalBase) +
+ (head * readl(&pqhdr->SignalSize));
+ MEMCPY_TOIO(psignal, pSignal, readl(&pqhdr->SignalSize));
+
+ VolatileBarrier();
+ writel(head, &pqhdr->Head);
+
+ writeq(readq(&pqhdr->NumSignalsSent) + 1, &pqhdr->NumSignalsSent);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(visor_signal_insert);
+
+/*
+ * Routine Description:
+ * Removes one signal from Channel pChannel's nth Queue at the
+ * time of the call and copies it into the memory pointed to by
+ * pSignal.
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ * pSignal: (IN) pointer to where the signals are to be copied
+ *
+ * Assumptions:
+ * - pChannel and Queue are valid.
+ * - pSignal points to a memory area large enough to hold queue's SignalSize
+ *
+ * Return value:
+ * 1 if the removal succeeds, 0 if the queue was empty.
+ */
+unsigned char
+visor_signal_remove(CHANNEL_HEADER __iomem *pChannel, U32 Queue, void *pSignal)
+{
+ void __iomem *psource;
+ unsigned int head, tail;
+ SIGNAL_QUEUE_HEADER __iomem *pqhdr =
+ (SIGNAL_QUEUE_HEADER __iomem *) ((char __iomem *) pChannel +
+ readq(&pChannel->oChannelSpace)) + Queue;
+
+ /* capture current head and tail */
+ head = readl(&pqhdr->Head);
+ tail = readl(&pqhdr->Tail);
+
+ /* queue is empty if the head index equals the tail index */
+ if (head == tail) {
+ writeq(readq(&pqhdr->NumEmptyCnt) + 1, &pqhdr->NumEmptyCnt);
+ return 0;
+ }
+
+ /* advance past the 'empty' front slot */
+ tail = (tail + 1) % readl(&pqhdr->MaxSignalSlots);
+
+ /* copy signal from tail location to the area pointed to by pSignal */
+ psource = (char __iomem *) pqhdr + readq(&pqhdr->oSignalBase) +
+ (tail * readl(&pqhdr->SignalSize));
+ MEMCPY_FROMIO(pSignal, psource, readl(&pqhdr->SignalSize));
+
+ VolatileBarrier();
+ writel(tail, &pqhdr->Tail);
+
+ writeq(readq(&pqhdr->NumSignalsReceived) + 1,
+ &pqhdr->NumSignalsReceived);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(visor_signal_remove);
+
+/*
+ * Routine Description:
+ * Removes all signals present in Channel pChannel's nth Queue at the
+ * time of the call and copies them into the memory pointed to by
+ * pSignal. Returns the # of signals copied as the value of the routine.
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ * pSignal: (IN) pointer to where the signals are to be copied
+ *
+ * Assumptions:
+ * - pChannel and Queue are valid.
+ * - pSignal points to a memory area large enough to hold Queue's MaxSignals
+ * # of signals, each of which is Queue's SignalSize.
+ *
+ * Return value:
+ * # of signals copied.
+ */
+unsigned int
+SignalRemoveAll(pCHANNEL_HEADER pChannel, U32 Queue, void *pSignal)
+{
+ void *psource;
+ unsigned int head, tail, signalCount = 0;
+ pSIGNAL_QUEUE_HEADER pqhdr =
+ (pSIGNAL_QUEUE_HEADER) ((char *) pChannel +
+ pChannel->oChannelSpace) + Queue;
+
+ /* capture current head and tail */
+ head = pqhdr->Head;
+ tail = pqhdr->Tail;
+
+ /* queue is empty if the head index equals the tail index */
+ if (head == tail)
+ return 0;
+
+ while (head != tail) {
+ /* advance past the 'empty' front slot */
+ tail = (tail + 1) % pqhdr->MaxSignalSlots;
+
+ /* copy signal from tail location to the area pointed
+ * to by pSignal
+ */
+ psource =
+ (char *) pqhdr + pqhdr->oSignalBase +
+ (tail * pqhdr->SignalSize);
+ MEMCPY((char *) pSignal + (pqhdr->SignalSize * signalCount),
+ psource, pqhdr->SignalSize);
+
+ VolatileBarrier();
+ pqhdr->Tail = tail;
+
+ signalCount++;
+ pqhdr->NumSignalsReceived++;
+ }
+
+ return signalCount;
+}
+
+/*
+ * Routine Description:
+ * Determine whether a signal queue is empty.
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ *
+ * Return value:
+ * 1 if the signal queue is empty, 0 otherwise.
+ */
+unsigned char
+visor_signalqueue_empty(CHANNEL_HEADER __iomem *pChannel, U32 Queue)
+{
+ SIGNAL_QUEUE_HEADER __iomem *pqhdr =
+ (SIGNAL_QUEUE_HEADER __iomem *) ((char __iomem *) pChannel +
+ readq(&pChannel->oChannelSpace)) + Queue;
+ return readl(&pqhdr->Head) == readl(&pqhdr->Tail);
+}
+EXPORT_SYMBOL_GPL(visor_signalqueue_empty);
+
diff --git a/drivers/staging/unisys/channels/chanstub.c b/drivers/staging/unisys/channels/chanstub.c
new file mode 100644
index 000000000000..f504f49a436a
--- /dev/null
+++ b/drivers/staging/unisys/channels/chanstub.c
@@ -0,0 +1,70 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#define EXPORT_SYMTAB
+#include <linux/kernel.h>
+#ifdef CONFIG_MODVERSIONS
+#include <config/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/init.h> /* for module_init and module_exit */
+#include <linux/slab.h> /* for memcpy */
+#include <linux/types.h>
+
+#include "channel.h"
+#include "chanstub.h"
+#include "version.h"
+
+static __init int
+channel_mod_init(void)
+{
+ return 0;
+}
+
+static __exit void
+channel_mod_exit(void)
+{
+}
+
+unsigned char
+SignalInsert_withLock(CHANNEL_HEADER __iomem *pChannel, U32 Queue,
+ void *pSignal, spinlock_t *lock)
+{
+ unsigned char result;
+ unsigned long flags;
+ spin_lock_irqsave(lock, flags);
+ result = visor_signal_insert(pChannel, Queue, pSignal);
+ spin_unlock_irqrestore(lock, flags);
+ return result;
+}
+
+unsigned char
+SignalRemove_withLock(CHANNEL_HEADER __iomem *pChannel, U32 Queue,
+ void *pSignal, spinlock_t *lock)
+{
+ unsigned char result;
+ spin_lock(lock);
+ result = visor_signal_remove(pChannel, Queue, pSignal);
+ spin_unlock(lock);
+ return result;
+}
+
+module_init(channel_mod_init);
+module_exit(channel_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Bryan Glaudel");
+MODULE_ALIAS("uischan");
+ /* this is extracted during depmod and kept in modules.dep */
diff --git a/drivers/staging/unisys/channels/chanstub.h b/drivers/staging/unisys/channels/chanstub.h
new file mode 100644
index 000000000000..8d727debca67
--- /dev/null
+++ b/drivers/staging/unisys/channels/chanstub.h
@@ -0,0 +1,23 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __CHANSTUB_H__
+#define __CHANSTUB_H__
+unsigned char SignalInsert_withLock(CHANNEL_HEADER __iomem *pChannel, U32 Queue,
+ void *pSignal, spinlock_t *lock);
+unsigned char SignalRemove_withLock(CHANNEL_HEADER __iomem *pChannel, U32 Queue,
+ void *pSignal, spinlock_t *lock);
+
+#endif
diff --git a/drivers/staging/unisys/common-spar/include/channels/channel.h b/drivers/staging/unisys/common-spar/include/channels/channel.h
new file mode 100644
index 000000000000..aee204172b21
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/channels/channel.h
@@ -0,0 +1,661 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __CHANNEL_H__
+#define __CHANNEL_H__
+
+/*
+* Whenever this file is changed a corresponding change must be made in
+* the Console/ServicePart/visordiag_early/supervisor_channel.h file
+* which is needed for Linux kernel compiles. These two files must be
+* in sync.
+*/
+
+/* define the following to prevent include nesting in kernel header
+ * files of similar abreviated content
+ */
+#define __SUPERVISOR_CHANNEL_H__
+
+#include "commontypes.h"
+
+#define SIGNATURE_16(A, B) ((A) | (B<<8))
+#define SIGNATURE_32(A, B, C, D) \
+ (SIGNATURE_16(A, B) | (SIGNATURE_16(C, D) << 16))
+#define SIGNATURE_64(A, B, C, D, E, F, G, H) \
+ (SIGNATURE_32(A, B, C, D) | ((U64)(SIGNATURE_32(E, F, G, H)) << 32))
+
+#ifndef lengthof
+#define lengthof(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER))
+#endif
+#ifndef COVERQ
+#define COVERQ(v, d) (((v)+(d)-1) / (d))
+#endif
+#ifndef COVER
+#define COVER(v, d) ((d)*COVERQ(v, d))
+#endif
+
+#ifndef GUID0
+#define GUID0 {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} }
+#endif
+
+/* The C language is inconsistent with respect to where it allows literal
+ * constants, especially literal constant structs. Literal constant structs
+ * are allowed for initialization only, whereas other types of literal
+ * constants are allowed anywhere. We get around this inconsistency by
+ * declaring a "static const" variable for each GUID. This variable can be
+ * used in expressions where the literal constant would not be allowed.
+ */
+static const GUID Guid0 = GUID0;
+
+#define ULTRA_CHANNEL_PROTOCOL_SIGNATURE SIGNATURE_32('E', 'C', 'N', 'L')
+
+typedef enum {
+ CHANNELSRV_UNINITIALIZED = 0, /* channel is in an undefined state */
+ CHANNELSRV_READY = 1 /* channel has been initialized by server */
+} CHANNEL_SERVERSTATE;
+
+typedef enum {
+ CHANNELCLI_DETACHED = 0,
+ CHANNELCLI_DISABLED = 1, /* client can see channel but is NOT
+ * allowed to use it unless given TBD
+ * explicit request (should actually be
+ * < DETACHED) */
+ CHANNELCLI_ATTACHING = 2, /* legacy EFI client request
+ * for EFI server to attach */
+ CHANNELCLI_ATTACHED = 3, /* idle, but client may want
+ * to use channel any time */
+ CHANNELCLI_BUSY = 4, /* client either wants to use or is
+ * using channel */
+ CHANNELCLI_OWNED = 5 /* "no worries" state - client can
+ * access channel anytime */
+} CHANNEL_CLIENTSTATE;
+static inline const U8 *
+ULTRA_CHANNELCLI_STRING(U32 v)
+{
+ switch (v) {
+ case CHANNELCLI_DETACHED:
+ return (const U8 *) ("DETACHED");
+ case CHANNELCLI_DISABLED:
+ return (const U8 *) ("DISABLED");
+ case CHANNELCLI_ATTACHING:
+ return (const U8 *) ("ATTACHING");
+ case CHANNELCLI_ATTACHED:
+ return (const U8 *) ("ATTACHED");
+ case CHANNELCLI_BUSY:
+ return (const U8 *) ("BUSY");
+ case CHANNELCLI_OWNED:
+ return (const U8 *) ("OWNED");
+ default:
+ break;
+ }
+ return (const U8 *) ("?");
+}
+
+#define ULTRA_CHANNELSRV_IS_READY(x) ((x) == CHANNELSRV_READY)
+#define ULTRA_CHANNEL_SERVER_READY(pChannel) \
+ (ULTRA_CHANNELSRV_IS_READY(readl(&(pChannel)->SrvState)))
+
+#define ULTRA_VALID_CHANNELCLI_TRANSITION(o, n) \
+ (((((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_DISABLED)) || \
+ (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DISABLED)) || \
+ (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DISABLED)) || \
+ (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DETACHED)) || \
+ (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DETACHED)) || \
+ (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHING)) || \
+ (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_ATTACHED)) || \
+ (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHED)) || \
+ (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_ATTACHED)) || \
+ (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_BUSY)) || \
+ (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_OWNED)) || \
+ (((o) == CHANNELCLI_DISABLED) && ((n) == CHANNELCLI_OWNED)) || \
+ (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_OWNED)) || \
+ (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_OWNED)) || \
+ (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_OWNED)) || (0)) \
+ ? (1) : (0))
+
+#define ULTRA_CHANNEL_CLIENT_CHK_TRANSITION(old, new, chanId, logCtx, \
+ file, line) \
+ do { \
+ if (!ULTRA_VALID_CHANNELCLI_TRANSITION(old, new)) \
+ UltraLogEvent(logCtx, \
+ CHANNELSTATE_DIAG_EVENTID_TRANSITERR, \
+ CHANNELSTATE_DIAG_SEVERITY, \
+ CHANNELSTATE_DIAG_SUBSYS, \
+ __func__, __LINE__, \
+ "%s Channel StateTransition INVALID! (%s) %s(%d)-->%s(%d) @%s:%d\n", \
+ chanId, "CliState<x>", \
+ ULTRA_CHANNELCLI_STRING(old), \
+ old, \
+ ULTRA_CHANNELCLI_STRING(new), \
+ new, \
+ PathName_Last_N_Nodes((U8 *)file, 4), \
+ line); \
+ } while (0)
+
+#define ULTRA_CHANNEL_CLIENT_TRANSITION(pChan, chanId, \
+ newstate, logCtx) \
+ do { \
+ ULTRA_CHANNEL_CLIENT_CHK_TRANSITION( \
+ readl(&(((CHANNEL_HEADER __iomem *) \
+ (pChan))->CliStateOS)), \
+ newstate, \
+ chanId, logCtx, __FILE__, __LINE__); \
+ UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK, \
+ CHANNELSTATE_DIAG_SEVERITY, \
+ CHANNELSTATE_DIAG_SUBSYS, \
+ __func__, __LINE__, \
+ "%s Channel StateTransition (%s) %s(%d)-->%s(%d) @%s:%d\n", \
+ chanId, "CliStateOS", \
+ ULTRA_CHANNELCLI_STRING( \
+ readl(&((CHANNEL_HEADER __iomem *) \
+ (pChan))->CliStateOS)), \
+ readl(&((CHANNEL_HEADER __iomem *) \
+ (pChan))->CliStateOS), \
+ ULTRA_CHANNELCLI_STRING(newstate), \
+ newstate, \
+ PathName_Last_N_Nodes(__FILE__, 4), __LINE__); \
+ writel(newstate, &((CHANNEL_HEADER __iomem *) \
+ (pChan))->CliStateOS); \
+ MEMORYBARRIER; \
+ } while (0)
+
+#define ULTRA_CHANNEL_CLIENT_ACQUIRE_OS(pChan, chanId, logCtx) \
+ ULTRA_channel_client_acquire_os(pChan, chanId, logCtx, \
+ (char *)__FILE__, __LINE__, \
+ (char *)__func__)
+#define ULTRA_CHANNEL_CLIENT_RELEASE_OS(pChan, chanId, logCtx) \
+ ULTRA_channel_client_release_os(pChan, chanId, logCtx, \
+ (char *)__FILE__, __LINE__, (char *)__func__)
+
+/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorBoot: */
+/* throttling invalid boot channel statetransition error due to client
+ * disabled */
+#define ULTRA_CLIERRORBOOT_THROTTLEMSG_DISABLED 0x01
+
+/* throttling invalid boot channel statetransition error due to client
+ * not attached */
+#define ULTRA_CLIERRORBOOT_THROTTLEMSG_NOTATTACHED 0x02
+
+/* throttling invalid boot channel statetransition error due to busy channel */
+#define ULTRA_CLIERRORBOOT_THROTTLEMSG_BUSY 0x04
+
+/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorOS: */
+/* throttling invalid guest OS channel statetransition error due to
+ * client disabled */
+#define ULTRA_CLIERROROS_THROTTLEMSG_DISABLED 0x01
+
+/* throttling invalid guest OS channel statetransition error due to
+ * client not attached */
+#define ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED 0x02
+
+/* throttling invalid guest OS channel statetransition error due to
+ * busy channel */
+#define ULTRA_CLIERROROS_THROTTLEMSG_BUSY 0x04
+
+/* Values for ULTRA_CHANNEL_PROTOCOL.Features: This define exists so
+* that windows guest can look at the FeatureFlags in the io channel,
+* and configure the windows driver to use interrupts or not based on
+* this setting. This flag is set in uislib after the
+* ULTRA_VHBA_init_channel is called. All feature bits for all
+* channels should be defined here. The io channel feature bits are
+* defined right here */
+#define ULTRA_IO_DRIVER_ENABLES_INTS (0x1ULL << 1)
+#define ULTRA_IO_CHANNEL_IS_POLLING (0x1ULL << 3)
+#define ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS (0x1ULL << 4)
+#define ULTRA_IO_DRIVER_DISABLES_INTS (0x1ULL << 5)
+#define ULTRA_IO_DRIVER_SUPPORTS_ENHANCED_RCVBUF_CHECKING (0x1ULL << 6)
+
+#pragma pack(push, 1) /* both GCC and VC now allow this pragma */
+/* Common Channel Header */
+typedef struct _CHANNEL_HEADER {
+ U64 Signature; /* Signature */
+ U32 LegacyState; /* DEPRECATED - being replaced by */
+ /* / SrvState, CliStateBoot, and CliStateOS below */
+ U32 HeaderSize; /* sizeof(CHANNEL_HEADER) */
+ U64 Size; /* Total size of this channel in bytes */
+ U64 Features; /* Flags to modify behavior */
+ GUID Type; /* Channel type: data, bus, control, etc. */
+ U64 PartitionHandle; /* ID of guest partition */
+ U64 Handle; /* Device number of this channel in client */
+ U64 oChannelSpace; /* Offset in bytes to channel specific area */
+ U32 VersionId; /* CHANNEL_HEADER Version ID */
+ U32 PartitionIndex; /* Index of guest partition */
+ GUID ZoneGuid; /* Guid of Channel's zone */
+ U32 oClientString; /* offset from channel header to
+ * nul-terminated ClientString (0 if
+ * ClientString not present) */
+ U32 CliStateBoot; /* CHANNEL_CLIENTSTATE of pre-boot
+ * EFI client of this channel */
+ U32 CmdStateCli; /* CHANNEL_COMMANDSTATE (overloaded in
+ * Windows drivers, see ServerStateUp,
+ * ServerStateDown, etc) */
+ U32 CliStateOS; /* CHANNEL_CLIENTSTATE of Guest OS
+ * client of this channel */
+ U32 ChannelCharacteristics; /* CHANNEL_CHARACTERISTIC_<xxx> */
+ U32 CmdStateSrv; /* CHANNEL_COMMANDSTATE (overloaded in
+ * Windows drivers, see ServerStateUp,
+ * ServerStateDown, etc) */
+ U32 SrvState; /* CHANNEL_SERVERSTATE */
+ U8 CliErrorBoot; /* bits to indicate err states for
+ * boot clients, so err messages can
+ * be throttled */
+ U8 CliErrorOS; /* bits to indicate err states for OS
+ * clients, so err messages can be
+ * throttled */
+ U8 Filler[1]; /* Pad out to 128 byte cacheline */
+ /* Please add all new single-byte values below here */
+ U8 RecoverChannel;
+} CHANNEL_HEADER, *pCHANNEL_HEADER, ULTRA_CHANNEL_PROTOCOL;
+
+#define ULTRA_CHANNEL_ENABLE_INTS (0x1ULL << 0)
+
+/* Subheader for the Signal Type variation of the Common Channel */
+typedef struct _SIGNAL_QUEUE_HEADER {
+ /* 1st cache line */
+ U32 VersionId; /* SIGNAL_QUEUE_HEADER Version ID */
+ U32 Type; /* Queue type: storage, network */
+ U64 Size; /* Total size of this queue in bytes */
+ U64 oSignalBase; /* Offset to signal queue area */
+ U64 FeatureFlags; /* Flags to modify behavior */
+ U64 NumSignalsSent; /* Total # of signals placed in this queue */
+ U64 NumOverflows; /* Total # of inserts failed due to
+ * full queue */
+ U32 SignalSize; /* Total size of a signal for this queue */
+ U32 MaxSignalSlots; /* Max # of slots in queue, 1 slot is
+ * always empty */
+ U32 MaxSignals; /* Max # of signals in queue
+ * (MaxSignalSlots-1) */
+ U32 Head; /* Queue head signal # */
+ /* 2nd cache line */
+ U64 NumSignalsReceived; /* Total # of signals removed from this queue */
+ U32 Tail; /* Queue tail signal # (on separate
+ * cache line) */
+ U32 Reserved1; /* Reserved field */
+ U64 Reserved2; /* Resrved field */
+ U64 ClientQueue;
+ U64 NumInterruptsReceived; /* Total # of Interrupts received. This
+ * is incremented by the ISR in the
+ * guest windows driver */
+ U64 NumEmptyCnt; /* Number of times that visor_signal_remove
+ * is called and returned Empty
+ * Status. */
+ U32 ErrorFlags; /* Error bits set during SignalReinit
+ * to denote trouble with client's
+ * fields */
+ U8 Filler[12]; /* Pad out to 64 byte cacheline */
+} SIGNAL_QUEUE_HEADER, *pSIGNAL_QUEUE_HEADER;
+
+#pragma pack(pop)
+
+#define SignalInit(chan, QHDRFLD, QDATAFLD, QDATATYPE, ver, typ) \
+ do { \
+ MEMSET(&chan->QHDRFLD, 0, sizeof(chan->QHDRFLD)); \
+ chan->QHDRFLD.VersionId = ver; \
+ chan->QHDRFLD.Type = typ; \
+ chan->QHDRFLD.Size = sizeof(chan->QDATAFLD); \
+ chan->QHDRFLD.SignalSize = sizeof(QDATATYPE); \
+ chan->QHDRFLD.oSignalBase = (UINTN)(chan->QDATAFLD)- \
+ (UINTN)(&chan->QHDRFLD); \
+ chan->QHDRFLD.MaxSignalSlots = \
+ sizeof(chan->QDATAFLD)/sizeof(QDATATYPE); \
+ chan->QHDRFLD.MaxSignals = chan->QHDRFLD.MaxSignalSlots-1; \
+ } while (0)
+
+/* Generic function useful for validating any type of channel when it is
+ * received by the client that will be accessing the channel.
+ * Note that <logCtx> is only needed for callers in the EFI environment, and
+ * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages.
+ */
+static inline int
+ULTRA_check_channel_client(void __iomem *pChannel,
+ GUID expectedTypeGuid,
+ char *channelName,
+ U64 expectedMinBytes,
+ U32 expectedVersionId,
+ U64 expectedSignature,
+ char *fileName, int lineNumber, void *logCtx)
+{
+ if (MEMCMP(&expectedTypeGuid, &Guid0, sizeof(GUID)) != 0)
+ /* caller wants us to verify type GUID */
+ if (MEMCMP_IO(&(((CHANNEL_HEADER __iomem *) (pChannel))->Type),
+ &expectedTypeGuid, sizeof(GUID)) != 0) {
+ CHANNEL_GUID_MISMATCH(expectedTypeGuid, channelName,
+ "type", expectedTypeGuid,
+ ((CHANNEL_HEADER __iomem *)
+ (pChannel))->Type, fileName,
+ lineNumber, logCtx);
+ return 0;
+ }
+ if (expectedMinBytes > 0) /* caller wants us to verify
+ * channel size */
+ if (readq(&((CHANNEL_HEADER __iomem *)
+ (pChannel))->Size) < expectedMinBytes) {
+ CHANNEL_U64_MISMATCH(expectedTypeGuid, channelName,
+ "size", expectedMinBytes,
+ ((CHANNEL_HEADER __iomem *)
+ (pChannel))->Size, fileName,
+ lineNumber, logCtx);
+ return 0;
+ }
+ if (expectedVersionId > 0) /* caller wants us to verify
+ * channel version */
+ if (readl(&((CHANNEL_HEADER __iomem *) (pChannel))->VersionId)
+ != expectedVersionId) {
+ CHANNEL_U32_MISMATCH(expectedTypeGuid, channelName,
+ "version", expectedVersionId,
+ ((CHANNEL_HEADER __iomem *)
+ (pChannel))->VersionId, fileName,
+ lineNumber, logCtx);
+ return 0;
+ }
+ if (expectedSignature > 0) /* caller wants us to verify
+ * channel signature */
+ if (readq(&((CHANNEL_HEADER __iomem *) (pChannel))->Signature)
+ != expectedSignature) {
+ CHANNEL_U64_MISMATCH(expectedTypeGuid, channelName,
+ "signature", expectedSignature,
+ ((CHANNEL_HEADER __iomem *)
+ (pChannel))->Signature, fileName,
+ lineNumber, logCtx);
+ return 0;
+ }
+ return 1;
+}
+
+/* Generic function useful for validating any type of channel when it is about
+ * to be initialized by the server of the channel.
+ * Note that <logCtx> is only needed for callers in the EFI environment, and
+ * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages.
+ */
+static inline int
+ULTRA_check_channel_server(GUID typeGuid,
+ char *channelName,
+ U64 expectedMinBytes,
+ U64 actualBytes,
+ char *fileName, int lineNumber, void *logCtx)
+{
+ if (expectedMinBytes > 0) /* caller wants us to verify
+ * channel size */
+ if (actualBytes < expectedMinBytes) {
+ CHANNEL_U64_MISMATCH(typeGuid, channelName, "size",
+ expectedMinBytes, actualBytes,
+ fileName, lineNumber, logCtx);
+ return 0;
+ }
+ return 1;
+}
+
+/* Given a file pathname <s> (with '/' or '\' separating directory nodes),
+ * returns a pointer to the beginning of a node within that pathname such
+ * that the number of nodes from that pointer to the end of the string is
+ * NOT more than <n>. Note that if the pathname has less than <n> nodes
+ * in it, the return pointer will be to the beginning of the string.
+ */
+static inline U8 *
+PathName_Last_N_Nodes(U8 *s, unsigned int n)
+{
+ U8 *p = s;
+ unsigned int node_count = 0;
+ while (*p != '\0') {
+ if ((*p == '/') || (*p == '\\'))
+ node_count++;
+ p++;
+ }
+ if (node_count <= n)
+ return s;
+ while (n > 0) {
+ p--;
+ if (p == s)
+ break; /* should never happen, unless someone
+ * is changing the string while we are
+ * looking at it!! */
+ if ((*p == '/') || (*p == '\\'))
+ n--;
+ }
+ return p + 1;
+}
+
+static inline int
+ULTRA_channel_client_acquire_os(void __iomem *pChannel, U8 *chanId,
+ void *logCtx, char *file, int line, char *func)
+{
+ CHANNEL_HEADER __iomem *pChan = pChannel;
+
+ if (readl(&pChan->CliStateOS) == CHANNELCLI_DISABLED) {
+ if ((readb(&pChan->CliErrorOS)
+ & ULTRA_CLIERROROS_THROTTLEMSG_DISABLED) == 0) {
+ /* we are NOT throttling this message */
+ writeb(readb(&pChan->CliErrorOS) |
+ ULTRA_CLIERROROS_THROTTLEMSG_DISABLED,
+ &pChan->CliErrorOS);
+ /* throttle until acquire successful */
+
+ UltraLogEvent(logCtx,
+ CHANNELSTATE_DIAG_EVENTID_TRANSITERR,
+ CHANNELSTATE_DIAG_SEVERITY,
+ CHANNELSTATE_DIAG_SUBSYS, func, line,
+ "%s Channel StateTransition INVALID! - acquire failed because OS client DISABLED @%s:%d\n",
+ chanId, PathName_Last_N_Nodes(
+ (U8 *) file, 4), line);
+ }
+ return 0;
+ }
+ if ((readl(&pChan->CliStateOS) != CHANNELCLI_OWNED)
+ && (readl(&pChan->CliStateBoot) == CHANNELCLI_DISABLED)) {
+ /* Our competitor is DISABLED, so we can transition to OWNED */
+ UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK,
+ CHANNELSTATE_DIAG_SEVERITY,
+ CHANNELSTATE_DIAG_SUBSYS, func, line,
+ "%s Channel StateTransition (%s) %s(%d)-->%s(%d) @%s:%d\n",
+ chanId, "CliStateOS",
+ ULTRA_CHANNELCLI_STRING(
+ readl(&pChan->CliStateOS)),
+ readl(&pChan->CliStateOS),
+ ULTRA_CHANNELCLI_STRING(CHANNELCLI_OWNED),
+ CHANNELCLI_OWNED,
+ PathName_Last_N_Nodes((U8 *) file, 4), line);
+ writel(CHANNELCLI_OWNED, &pChan->CliStateOS);
+ MEMORYBARRIER;
+ }
+ if (readl(&pChan->CliStateOS) == CHANNELCLI_OWNED) {
+ if (readb(&pChan->CliErrorOS) != 0) {
+ /* we are in an error msg throttling state;
+ * come out of it */
+ UltraLogEvent(logCtx,
+ CHANNELSTATE_DIAG_EVENTID_TRANSITOK,
+ CHANNELSTATE_DIAG_SEVERITY,
+ CHANNELSTATE_DIAG_SUBSYS, func, line,
+ "%s Channel OS client acquire now successful @%s:%d\n",
+ chanId, PathName_Last_N_Nodes((U8 *) file,
+ 4), line);
+ writeb(0, &pChan->CliErrorOS);
+ }
+ return 1;
+ }
+
+ /* We have to do it the "hard way". We transition to BUSY,
+ * and can use the channel iff our competitor has not also
+ * transitioned to BUSY. */
+ if (readl(&pChan->CliStateOS) != CHANNELCLI_ATTACHED) {
+ if ((readb(&pChan->CliErrorOS)
+ & ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED) == 0) {
+ /* we are NOT throttling this message */
+ writeb(readb(&pChan->CliErrorOS) |
+ ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED,
+ &pChan->CliErrorOS);
+ /* throttle until acquire successful */
+ UltraLogEvent(logCtx,
+ CHANNELSTATE_DIAG_EVENTID_TRANSITERR,
+ CHANNELSTATE_DIAG_SEVERITY,
+ CHANNELSTATE_DIAG_SUBSYS, func, line,
+ "%s Channel StateTransition INVALID! - acquire failed because OS client NOT ATTACHED (state=%s(%d)) @%s:%d\n",
+ chanId,
+ ULTRA_CHANNELCLI_STRING(
+ readl(&pChan->CliStateOS)),
+ readl(&pChan->CliStateOS),
+ PathName_Last_N_Nodes((U8 *) file, 4),
+ line);
+ }
+ return 0;
+ }
+ writel(CHANNELCLI_BUSY, &pChan->CliStateOS);
+ MEMORYBARRIER;
+ if (readl(&pChan->CliStateBoot) == CHANNELCLI_BUSY) {
+ if ((readb(&pChan->CliErrorOS)
+ & ULTRA_CLIERROROS_THROTTLEMSG_BUSY) == 0) {
+ /* we are NOT throttling this message */
+ writeb(readb(&pChan->CliErrorOS) |
+ ULTRA_CLIERROROS_THROTTLEMSG_BUSY,
+ &pChan->CliErrorOS);
+ /* throttle until acquire successful */
+ UltraLogEvent(logCtx,
+ CHANNELSTATE_DIAG_EVENTID_TRANSITBUSY,
+ CHANNELSTATE_DIAG_SEVERITY,
+ CHANNELSTATE_DIAG_SUBSYS, func, line,
+ "%s Channel StateTransition failed - host OS acquire failed because boot BUSY @%s:%d\n",
+ chanId, PathName_Last_N_Nodes((U8 *) file,
+ 4), line);
+ }
+ /* reset busy */
+ writel(CHANNELCLI_ATTACHED, &pChan->CliStateOS);
+ MEMORYBARRIER;
+ return 0;
+ }
+ if (readb(&pChan->CliErrorOS) != 0) {
+ /* we are in an error msg throttling state; come out of it */
+ UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK,
+ CHANNELSTATE_DIAG_SEVERITY,
+ CHANNELSTATE_DIAG_SUBSYS, func, line,
+ "%s Channel OS client acquire now successful @%s:%d\n",
+ chanId, PathName_Last_N_Nodes((U8 *) file, 4),
+ line);
+ writeb(0, &pChan->CliErrorOS);
+ }
+ return 1;
+}
+
+static inline void
+ULTRA_channel_client_release_os(void __iomem *pChannel, U8 *chanId,
+ void *logCtx, char *file, int line, char *func)
+{
+ CHANNEL_HEADER __iomem *pChan = pChannel;
+ if (readb(&pChan->CliErrorOS) != 0) {
+ /* we are in an error msg throttling state; come out of it */
+ UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK,
+ CHANNELSTATE_DIAG_SEVERITY,
+ CHANNELSTATE_DIAG_SUBSYS, func, line,
+ "%s Channel OS client error state cleared @%s:%d\n",
+ chanId, PathName_Last_N_Nodes((U8 *) file, 4),
+ line);
+ writeb(0, &pChan->CliErrorOS);
+ }
+ if (readl(&pChan->CliStateOS) == CHANNELCLI_OWNED)
+ return;
+ if (readl(&pChan->CliStateOS) != CHANNELCLI_BUSY) {
+ UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITERR,
+ CHANNELSTATE_DIAG_SEVERITY,
+ CHANNELSTATE_DIAG_SUBSYS, func, line,
+ "%s Channel StateTransition INVALID! - release failed because OS client NOT BUSY (state=%s(%d)) @%s:%d\n",
+ chanId,
+ ULTRA_CHANNELCLI_STRING(
+ readl(&pChan->CliStateOS)),
+ readl(&pChan->CliStateOS),
+ PathName_Last_N_Nodes((U8 *) file, 4), line);
+ /* return; */
+ }
+ writel(CHANNELCLI_ATTACHED, &pChan->CliStateOS); /* release busy */
+}
+
+/*
+* Routine Description:
+* Tries to insert the prebuilt signal pointed to by pSignal into the nth
+* Queue of the Channel pointed to by pChannel
+*
+* Parameters:
+* pChannel: (IN) points to the IO Channel
+* Queue: (IN) nth Queue of the IO Channel
+* pSignal: (IN) pointer to the signal
+*
+* Assumptions:
+* - pChannel, Queue and pSignal are valid.
+* - If insertion fails due to a full queue, the caller will determine the
+* retry policy (e.g. wait & try again, report an error, etc.).
+*
+* Return value: 1 if the insertion succeeds, 0 if the queue was
+* full.
+*/
+
+unsigned char visor_signal_insert(CHANNEL_HEADER __iomem *pChannel, U32 Queue,
+ void *pSignal);
+
+/*
+* Routine Description:
+* Removes one signal from Channel pChannel's nth Queue at the
+* time of the call and copies it into the memory pointed to by
+* pSignal.
+*
+* Parameters:
+* pChannel: (IN) points to the IO Channel
+* Queue: (IN) nth Queue of the IO Channel
+* pSignal: (IN) pointer to where the signals are to be copied
+*
+* Assumptions:
+* - pChannel and Queue are valid.
+* - pSignal points to a memory area large enough to hold queue's SignalSize
+*
+* Return value: 1 if the removal succeeds, 0 if the queue was
+* empty.
+*/
+
+unsigned char visor_signal_remove(CHANNEL_HEADER __iomem *pChannel, U32 Queue,
+ void *pSignal);
+
+/*
+* Routine Description:
+* Removes all signals present in Channel pChannel's nth Queue at the
+* time of the call and copies them into the memory pointed to by
+* pSignal. Returns the # of signals copied as the value of the routine.
+*
+* Parameters:
+* pChannel: (IN) points to the IO Channel
+* Queue: (IN) nth Queue of the IO Channel
+* pSignal: (IN) pointer to where the signals are to be copied
+*
+* Assumptions:
+* - pChannel and Queue are valid.
+* - pSignal points to a memory area large enough to hold Queue's MaxSignals
+* # of signals, each of which is Queue's SignalSize.
+*
+* Return value:
+* # of signals copied.
+*/
+unsigned int SignalRemoveAll(pCHANNEL_HEADER pChannel, U32 Queue,
+ void *pSignal);
+
+/*
+* Routine Description:
+* Determine whether a signal queue is empty.
+*
+* Parameters:
+* pChannel: (IN) points to the IO Channel
+* Queue: (IN) nth Queue of the IO Channel
+*
+* Return value:
+* 1 if the signal queue is empty, 0 otherwise.
+*/
+unsigned char visor_signalqueue_empty(CHANNEL_HEADER __iomem *pChannel,
+ U32 Queue);
+
+#endif
diff --git a/drivers/staging/unisys/common-spar/include/channels/channel_guid.h b/drivers/staging/unisys/common-spar/include/channels/channel_guid.h
new file mode 100644
index 000000000000..ae0dc2b2ad14
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/channels/channel_guid.h
@@ -0,0 +1,64 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * CHANNEL Guids
+ */
+
+/* Used in IOChannel
+ * {414815ed-c58c-11da-95a9-00e08161165f}
+ */
+#define ULTRA_VHBA_CHANNEL_PROTOCOL_GUID \
+ { 0x414815ed, 0xc58c, 0x11da, \
+ { 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f } }
+static const GUID UltraVhbaChannelProtocolGuid =
+ ULTRA_VHBA_CHANNEL_PROTOCOL_GUID;
+
+/* Used in IOChannel
+ * {8cd5994d-c58e-11da-95a9-00e08161165f}
+ */
+#define ULTRA_VNIC_CHANNEL_PROTOCOL_GUID \
+ { 0x8cd5994d, 0xc58e, 0x11da, \
+ { 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f } }
+static const GUID UltraVnicChannelProtocolGuid =
+ ULTRA_VNIC_CHANNEL_PROTOCOL_GUID;
+
+/* Used in IOChannel
+ * {72120008-4AAB-11DC-8530-444553544200}
+ */
+#define ULTRA_SIOVM_GUID \
+ { 0x72120008, 0x4AAB, 0x11DC, \
+ { 0x85, 0x30, 0x44, 0x45, 0x53, 0x54, 0x42, 0x00 } }
+static const GUID UltraSIOVMGuid = ULTRA_SIOVM_GUID;
+
+
+/* Used in visornoop/visornoop_main.c
+ * {5b52c5ac-e5f5-4d42-8dff-429eaecd221f}
+ */
+#define ULTRA_CONTROLDIRECTOR_CHANNEL_PROTOCOL_GUID \
+ { 0x5b52c5ac, 0xe5f5, 0x4d42, \
+ { 0x8d, 0xff, 0x42, 0x9e, 0xae, 0xcd, 0x22, 0x1f } }
+
+static const GUID UltraControlDirectorChannelProtocolGuid =
+ ULTRA_CONTROLDIRECTOR_CHANNEL_PROTOCOL_GUID;
+
+/* Used in visorchipset/visorchipset_main.c
+ * {B4E79625-AEDE-4EAA-9E11-D3EDDCD4504C}
+ */
+#define ULTRA_DIAG_POOL_CHANNEL_PROTOCOL_GUID \
+ {0xb4e79625, 0xaede, 0x4eaa, \
+ { 0x9e, 0x11, 0xd3, 0xed, 0xdc, 0xd4, 0x50, 0x4c } }
+
+
diff --git a/drivers/staging/unisys/common-spar/include/channels/controlframework.h b/drivers/staging/unisys/common-spar/include/channels/controlframework.h
new file mode 100644
index 000000000000..512643348349
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/channels/controlframework.h
@@ -0,0 +1,77 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * Module Name:
+ * controlframework.h
+ *
+ * Abstract: This file defines common structures in the unmanaged
+ * Ultravisor (mostly EFI) space.
+ *
+ */
+
+#ifndef _CONTROL_FRAMEWORK_H_
+#define _CONTROL_FRAMEWORK_H_
+
+#include "commontypes.h"
+#include "channel.h"
+
+#define ULTRA_MEMORY_COUNT_Ki 1024
+
+/* Scale order 0 is one 32-bit (4-byte) word (in 64 or 128-bit
+ * architecture potentially 64 or 128-bit word) */
+#define ULTRA_MEMORY_PAGE_WORD 4
+
+/* Define Ki scale page to be traditional 4KB page */
+#define ULTRA_MEMORY_PAGE_Ki (ULTRA_MEMORY_PAGE_WORD * ULTRA_MEMORY_COUNT_Ki)
+typedef struct _ULTRA_SEGMENT_STATE {
+ U16 Enabled:1; /* Bit 0: May enter other states */
+ U16 Active:1; /* Bit 1: Assigned to active partition */
+ U16 Alive:1; /* Bit 2: Configure message sent to
+ * service/server */
+ U16 Revoked:1; /* Bit 3: similar to partition state
+ * ShuttingDown */
+ U16 Allocated:1; /* Bit 4: memory (device/port number)
+ * has been selected by Command */
+ U16 Known:1; /* Bit 5: has been introduced to the
+ * service/guest partition */
+ U16 Ready:1; /* Bit 6: service/Guest partition has
+ * responded to introduction */
+ U16 Operating:1; /* Bit 7: resource is configured and
+ * operating */
+ /* Note: don't use high bit unless we need to switch to ushort
+ * which is non-compliant */
+} ULTRA_SEGMENT_STATE;
+static const ULTRA_SEGMENT_STATE SegmentStateRunning = {
+ 1, 1, 1, 0, 1, 1, 1, 1
+};
+static const ULTRA_SEGMENT_STATE SegmentStatePaused = {
+ 1, 1, 1, 0, 1, 1, 1, 0
+};
+static const ULTRA_SEGMENT_STATE SegmentStateStandby = {
+ 1, 1, 0, 0, 1, 1, 1, 0
+};
+typedef union {
+ U64 Full;
+ struct {
+ U8 Major; /* will be 1 for the first release and
+ * increment thereafter */
+ U8 Minor;
+ U16 Maintenance;
+ U32 Revision; /* Subversion revision */
+ } Part;
+} ULTRA_COMPONENT_VERSION;
+
+#endif /* _CONTROL_FRAMEWORK_H_ not defined */
diff --git a/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h b/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h
new file mode 100644
index 000000000000..47f1c4fa1e7e
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h
@@ -0,0 +1,619 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __CONTROLVMCHANNEL_H__
+#define __CONTROLVMCHANNEL_H__
+
+#include "commontypes.h"
+#include "channel.h"
+#include "controlframework.h"
+enum { INVALID_GUEST_FIRMWARE, SAMPLE_GUEST_FIRMWARE,
+ TIANO32_GUEST_FIRMWARE, TIANO64_GUEST_FIRMWARE
+};
+
+/* {2B3C2D10-7EF5-4ad8-B966-3448B7386B3D} */
+#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_GUID \
+ {0x2b3c2d10, 0x7ef5, 0x4ad8, \
+ {0xb9, 0x66, 0x34, 0x48, 0xb7, 0x38, 0x6b, 0x3d} }
+
+static const GUID UltraControlvmChannelProtocolGuid =
+ ULTRA_CONTROLVM_CHANNEL_PROTOCOL_GUID;
+
+#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_SIGNATURE \
+ ULTRA_CHANNEL_PROTOCOL_SIGNATURE
+#define CONTROLVM_MESSAGE_MAX 64
+
+/* Must increment this whenever you insert or delete fields within
+* this channel struct. Also increment whenever you change the meaning
+* of fields within this channel struct so as to break pre-existing
+* software. Note that you can usually add fields to the END of the
+* channel struct withOUT needing to increment this. */
+#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_VERSIONID 1
+
+#define ULTRA_CONTROLVM_CHANNEL_OK_CLIENT(pChannel, logCtx) \
+ (ULTRA_check_channel_client(pChannel, \
+ UltraControlvmChannelProtocolGuid, \
+ "controlvm", \
+ sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL), \
+ ULTRA_CONTROLVM_CHANNEL_PROTOCOL_VERSIONID, \
+ ULTRA_CONTROLVM_CHANNEL_PROTOCOL_SIGNATURE, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_CONTROLVM_CHANNEL_OK_SERVER(actualBytes, logCtx) \
+ (ULTRA_check_channel_server(UltraControlvmChannelProtocolGuid, \
+ "controlvm", \
+ sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL), \
+ actualBytes, __FILE__, __LINE__, logCtx))
+
+#define MY_DEVICE_INDEX 0
+#define MAX_MACDATA_LEN 8 /* number of bytes for MAC address in config packet */
+#define MAX_SERIAL_NUM 32
+
+#define DISK_ZERO_PUN_NUMBER 1 /* Target ID on the SCSI bus for LUN 0 */
+#define DISK_ZERO_LUN_NUMBER 3 /* Logical Unit Number */
+
+/* Defines for various channel queues... */
+#define CONTROLVM_QUEUE_REQUEST 0
+#define CONTROLVM_QUEUE_RESPONSE 1
+#define CONTROLVM_QUEUE_EVENT 2
+#define CONTROLVM_QUEUE_ACK 3
+
+/* Max number of messages stored during IOVM creation to be reused
+ * after crash */
+#define CONTROLVM_CRASHMSG_MAX 2
+
+/** Ids for commands that may appear in either queue of a ControlVm channel.
+ *
+ * Commands that are initiated by the command partition (CP), by an IO or
+ * console service partition (SP), or by a guest partition (GP)are:
+ * - issued on the RequestQueue queue (q #0) in the ControlVm channel
+ * - responded to on the ResponseQueue queue (q #1) in the ControlVm channel
+ *
+ * Events that are initiated by an IO or console service partition (SP) or
+ * by a guest partition (GP) are:
+ * - issued on the EventQueue queue (q #2) in the ControlVm channel
+ * - responded to on the EventAckQueue queue (q #3) in the ControlVm channel
+ */
+typedef enum {
+ CONTROLVM_INVALID = 0,
+ /* SWITCH commands required Parameter: SwitchNumber */
+ /* BUS commands required Parameter: BusNumber */
+ CONTROLVM_BUS_CREATE = 0x101, /* CP --> SP, GP */
+ CONTROLVM_BUS_DESTROY = 0x102, /* CP --> SP, GP */
+ CONTROLVM_BUS_CONFIGURE = 0x104, /* CP --> SP */
+ CONTROLVM_BUS_CHANGESTATE = 0x105, /* CP --> SP, GP */
+ CONTROLVM_BUS_CHANGESTATE_EVENT = 0x106, /* SP, GP --> CP */
+/* DEVICE commands required Parameter: BusNumber, DeviceNumber */
+
+ CONTROLVM_DEVICE_CREATE = 0x201, /* CP --> SP, GP */
+ CONTROLVM_DEVICE_DESTROY = 0x202, /* CP --> SP, GP */
+ CONTROLVM_DEVICE_CONFIGURE = 0x203, /* CP --> SP */
+ CONTROLVM_DEVICE_CHANGESTATE = 0x204, /* CP --> SP, GP */
+ CONTROLVM_DEVICE_CHANGESTATE_EVENT = 0x205, /* SP, GP --> CP */
+ CONTROLVM_DEVICE_RECONFIGURE = 0x206, /* CP --> Boot */
+/* DISK commands required Parameter: BusNumber, DeviceNumber */
+ CONTROLVM_DISK_CREATE = 0x221, /* CP --> SP */
+ CONTROLVM_DISK_DESTROY = 0x222, /* CP --> SP */
+ CONTROLVM_DISK_CONFIGURE = 0x223, /* CP --> SP */
+ CONTROLVM_DISK_CHANGESTATE = 0x224, /* CP --> SP */
+/* CHIPSET commands */
+ CONTROLVM_CHIPSET_INIT = 0x301, /* CP --> SP, GP */
+ CONTROLVM_CHIPSET_STOP = 0x302, /* CP --> SP, GP */
+ CONTROLVM_CHIPSET_SHUTDOWN = 0x303, /* CP --> SP */
+ CONTROLVM_CHIPSET_READY = 0x304, /* CP --> SP */
+ CONTROLVM_CHIPSET_SELFTEST = 0x305, /* CP --> SP */
+
+} CONTROLVM_ID;
+
+struct InterruptInfo {
+ /**< specifies interrupt info. It is used to send interrupts
+ * for this channel. The peer at the end of this channel
+ * who has registered an interrupt (using recv fields
+ * above) will receive the interrupt. Passed as a parameter
+ * to Issue_VMCALL_IO_QUEUE_TRANSITION, which generates the
+ * interrupt. Currently this is used by IOPart-SP to wake
+ * up GP when Data Channel transitions from empty to
+ * non-empty.*/
+ U64 sendInterruptHandle;
+
+ /**< specifies interrupt handle. It is used to retrieve the
+ * corresponding interrupt pin from Monitor; and the
+ * interrupt pin is used to connect to the corresponding
+ * intrrupt. Used by IOPart-GP only. */
+ U64 recvInterruptHandle;
+
+ /**< specifies interrupt vector. It, interrupt pin, and shared are
+ * used to connect to the corresponding interrupt. Used by
+ * IOPart-GP only. */
+ U32 recvInterruptVector;
+
+ /**< specifies if the recvInterrupt is shared. It, interrupt pin
+ * and vector are used to connect to 0 = not shared; 1 = shared.
+ * the corresponding interrupt. Used by IOPart-GP only. */
+ U8 recvInterruptShared;
+ U8 reserved[3]; /* Natural alignment purposes */
+};
+
+struct PciId {
+ U16 Domain;
+ U8 Bus;
+ U8 Slot;
+ U8 Func;
+ U8 Reserved[3]; /* Natural alignment purposes */
+};
+
+struct PciConfigHdr {
+ U16 VendorId;
+ U16 SubSysVendor;
+ U16 DeviceId;
+ U16 SubSysDevice;
+ U32 ClassCode;
+ U32 Reserved; /* Natural alignment purposes */
+};
+
+struct ScsiId {
+ U32 Bus;
+ U32 Target;
+ U32 Lun;
+ U32 Host; /* Command should ignore this for *
+ * DiskArrival/RemovalEvents */
+};
+
+struct WWID {
+ U32 wwid1;
+ U32 wwid2;
+};
+
+struct virtDiskInfo {
+ U32 switchNo; /* defined by SWITCH_CREATE */
+ U32 externalPortNo; /* 0 for SAS RAID provided (external)
+ * virtual disks, 1 for virtual disk
+ * images, 2 for gold disk images */
+ U16 VirtualDiskIndex; /* Index of disk descriptor in the
+ * VirtualDisk segment associated with
+ * externalPortNo */
+ U16 Reserved1;
+ U32 Reserved2;
+};
+
+typedef enum {
+ CONTROLVM_ACTION_NONE = 0,
+ CONTROLVM_ACTION_SET_RESTORE = 0x05E7,
+ CONTROLVM_ACTION_CLEAR_RESTORE = 0x0C18,
+ CONTROLVM_ACTION_RESTORING = 0x08E5,
+ CONTROLVM_ACTION_RESTORE_BUSY = 0x0999,
+ CONTROLVM_ACTION_CLEAR_NVRAM = 0xB01
+} CONTROLVM_ACTION;
+
+typedef enum _ULTRA_TOOL_ACTIONS {
+ /* enumeration that defines intended action */
+ ULTRA_TOOL_ACTION_NONE = 0, /* normal boot of boot disk */
+ ULTRA_TOOL_ACTION_INSTALL = 1, /* install source disk(s) to boot
+ * disk */
+ ULTRA_TOOL_ACTION_CAPTURE = 2, /* capture boot disk to target disk(s)
+ * as 'gold image' */
+ ULTRA_TOOL_ACTION_REPAIR = 3, /* use source disk(s) to repair
+ * installation on boot disk */
+ ULTRA_TOOL_ACTION_CLEAN = 4, /* 'scrub' virtual disk before
+ * releasing back to storage pool */
+ ULTRA_TOOL_ACTION_UPGRADE = 5, /* upgrade to use content of images
+ * referenced from newer blueprint */
+ ULTRA_TOOL_ACTION_DIAG = 6, /* use tool to invoke diagnostic script
+ * provided by blueprint */
+ ULTRA_TOOL_ACTION_FAILED = 7, /* used when tool fails installation
+ and cannot continue */
+ ULTRA_TOOL_ACTION_COUNT = 8
+} ULTRA_TOOL_ACTIONS;
+
+typedef struct _ULTRA_EFI_SPAR_INDICATION {
+ U64 BootToFirmwareUI:1; /* Bit 0: Stop in uefi ui */
+ U64 ClearNvram:1; /* Bit 1: Clear NVRAM */
+ U64 ClearCmos:1; /* Bit 2: Clear CMOS */
+ U64 BootToTool:1; /* Bit 3: Run install tool */
+ /* remaining bits are available */
+} ULTRA_EFI_SPAR_INDICATION;
+
+typedef enum {
+ ULTRA_CHIPSET_FEATURE_REPLY = 0x00000001,
+ ULTRA_CHIPSET_FEATURE_PARA_HOTPLUG = 0x00000002,
+ ULTRA_CHIPSET_FEATURE_PCIVBUS = 0x00000004
+} ULTRA_CHIPSET_FEATURE;
+
+/** This is the common structure that is at the beginning of every
+ * ControlVm message (both commands and responses) in any ControlVm
+ * queue. Commands are easily distinguished from responses by
+ * looking at the flags.response field.
+ */
+typedef struct _CONTROLVM_MESSAGE_HEADER {
+ U32 Id; /* See CONTROLVM_ID. */
+ /* For requests, indicates the message type. */
+ /* For responses, indicates the type of message we are responding to. */
+
+ U32 MessageSize; /* Includes size of this struct + size
+ * of message */
+ U32 SegmentIndex; /* Index of segment containing Vm
+ * message/information */
+ U32 CompletionStatus; /* Error status code or result of
+ * message completion */
+ struct {
+ U32 failed:1; /**< =1 in a response to * signify
+ * failure */
+ U32 responseExpected:1; /**< =1 in all messages that expect a
+ * response (Control ignores this
+ * bit) */
+ U32 server:1; /**< =1 in all bus & device-related
+ * messages where the message
+ * receiver is to act as the bus or
+ * device server */
+ U32 testMessage:1; /**< =1 for testing use only
+ * (Control and Command ignore this
+ * bit) */
+ U32 partialCompletion:1; /**< =1 if there are forthcoming
+ * responses/acks associated
+ * with this message */
+ U32 preserve:1; /**< =1 this is to let us know to
+ * preserve channel contents
+ * (for running guests)*/
+ U32 writerInDiag:1; /**< =1 the DiagWriter is active in the
+ * Diagnostic Partition*/
+
+ /* remaining bits in this 32-bit word are available */
+ } Flags;
+ U32 Reserved; /* Natural alignment */
+ U64 MessageHandle; /* Identifies the particular message instance,
+ * and is used to match particular */
+ /* request instances with the corresponding response instance. */
+ U64 PayloadVmOffset; /* Offset of payload area from start of this
+ * instance of ControlVm segment */
+ U32 PayloadMaxBytes; /* Maximum bytes allocated in payload
+ * area of ControlVm segment */
+ U32 PayloadBytes; /* Actual number of bytes of payload
+ * area to copy between IO/Command; */
+ /* if non-zero, there is a payload to copy. */
+} CONTROLVM_MESSAGE_HEADER;
+
+typedef struct _CONTROLVM_PACKET_DEVICE_CREATE {
+ U32 busNo; /**< bus # (0..n-1) from the msg receiver's
+ * perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 devNo; /**< bus-relative (0..n-1) device number */
+ U64 channelAddr; /**< Guest physical address of the channel, which
+ * can be dereferenced by the receiver
+ * of this ControlVm command */
+ U64 channelBytes; /**< specifies size of the channel in bytes */
+ GUID dataTypeGuid;/**< specifies format of data in channel */
+ GUID devInstGuid; /**< instance guid for the device */
+ struct InterruptInfo intr; /**< specifies interrupt information */
+} CONTROLVM_PACKET_DEVICE_CREATE; /* for CONTROLVM_DEVICE_CREATE */
+
+typedef struct _CONTROLVM_PACKET_DEVICE_CONFIGURE {
+ U32 busNo; /**< bus # (0..n-1) from the msg
+ * receiver's perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 devNo; /**< bus-relative (0..n-1) device number */
+} CONTROLVM_PACKET_DEVICE_CONFIGURE; /* for CONTROLVM_DEVICE_CONFIGURE */
+
+typedef struct _CONTROLVM_MESSAGE_DEVICE_CREATE {
+ CONTROLVM_MESSAGE_HEADER Header;
+ CONTROLVM_PACKET_DEVICE_CREATE Packet;
+} CONTROLVM_MESSAGE_DEVICE_CREATE; /* total 128 bytes */
+
+typedef struct _CONTROLVM_MESSAGE_DEVICE_CONFIGURE {
+ CONTROLVM_MESSAGE_HEADER Header;
+ CONTROLVM_PACKET_DEVICE_CONFIGURE Packet;
+} CONTROLVM_MESSAGE_DEVICE_CONFIGURE; /* total 56 bytes */
+
+/* This is the format for a message in any ControlVm queue. */
+typedef struct _CONTROLVM_MESSAGE_PACKET {
+ union {
+
+ /* BEGIN Request messages */
+ struct {
+ U32 busNo; /*< bus # (0..n-1) from the msg
+ * receiver's perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 deviceCount; /*< indicates the max number of
+ * devices on this bus */
+ U64 channelAddr; /*< Guest physical address of the
+ * channel, which can be
+ * dereferenced by the receiver
+ * of this ControlVm command */
+ U64 channelBytes; /*< size of the channel in bytes */
+ GUID busDataTypeGuid;/*< indicates format of data in bus
+ * channel */
+ GUID busInstGuid; /*< instance guid for the bus */
+ } createBus; /* for CONTROLVM_BUS_CREATE */
+ struct {
+ U32 busNo; /*< bus # (0..n-1) from the msg
+ * receiver's perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 reserved; /* Natural alignment purposes */
+ } destroyBus; /* for CONTROLVM_BUS_DESTROY */
+ struct {
+ U32 busNo; /*< bus # (0..n-1) from the
+ * msg receiver's
+ * perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 reserved1; /* for alignment purposes */
+ U64 guestHandle; /* This is used to convert
+ * guest physical address to real
+ * physical address for DMA, for ex. */
+ U64 recvBusInterruptHandle;/*< specifies interrupt
+ * info. It is used by SP to register
+ * to receive interrupts from the CP.
+ * This interrupt is used for bus
+ * level notifications. The
+ * corresponding
+ * sendBusInterruptHandle is kept in
+ * CP. */
+ } configureBus; /* for CONTROLVM_BUS_CONFIGURE */
+
+ /* for CONTROLVM_DEVICE_CREATE */
+ CONTROLVM_PACKET_DEVICE_CREATE createDevice;
+ struct {
+ U32 busNo; /*< bus # (0..n-1) from the msg
+ * receiver's perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 devNo; /*< bus-relative (0..n-1) device
+ * number */
+ } destroyDevice; /* for CONTROLVM_DEVICE_DESTROY */
+
+ /* for CONTROLVM_DEVICE_CONFIGURE */
+ CONTROLVM_PACKET_DEVICE_CONFIGURE configureDevice;
+ struct {
+ U32 busNo; /*< bus # (0..n-1) from the msg
+ * receiver's perspective */
+
+ /* Control uses header SegmentIndex field to access bus number... */
+ U32 devNo; /*< bus-relative (0..n-1) device
+ * number */
+ } reconfigureDevice; /* for CONTROLVM_DEVICE_RECONFIGURE */
+ struct {
+ U32 busNo;
+ ULTRA_SEGMENT_STATE state;
+ U8 reserved[2]; /* Natural alignment purposes */
+ } busChangeState; /* for CONTROLVM_BUS_CHANGESTATE */
+ struct {
+ U32 busNo;
+ U32 devNo;
+ ULTRA_SEGMENT_STATE state;
+ struct {
+ U32 physicalDevice:1; /* =1 if message is for
+ * a physical device */
+ /* remaining bits in this 32-bit word are available */
+ } flags;
+ U8 reserved[2]; /* Natural alignment purposes */
+ } deviceChangeState; /* for CONTROLVM_DEVICE_CHANGESTATE */
+ struct {
+ U32 busNo;
+ U32 devNo;
+ ULTRA_SEGMENT_STATE state;
+ U8 reserved[6]; /* Natural alignment purposes */
+ } deviceChangeStateEvent; /* for CONTROLVM_DEVICE_CHANGESTATE_EVENT */
+ struct {
+ U32 busCount; /*< indicates the max number of busses */
+ U32 switchCount; /*< indicates the max number of
+ * switches (applicable for service
+ * partition only) */
+ ULTRA_CHIPSET_FEATURE features;
+ U32 platformNumber; /* Platform Number */
+ } initChipset; /* for CONTROLVM_CHIPSET_INIT */
+ struct {
+ U32 Options; /*< reserved */
+ U32 Test; /*< bit 0 set to run embedded selftest */
+ } chipsetSelftest; /* for CONTROLVM_CHIPSET_SELFTEST */
+
+ /* END Request messages */
+
+ /* BEGIN Response messages */
+
+ /* END Response messages */
+
+ /* BEGIN Event messages */
+
+ /* END Event messages */
+
+ /* BEGIN Ack messages */
+
+ /* END Ack messages */
+ U64 addr; /*< a physical address of something, that
+ * can be dereferenced by the receiver of
+ * this ControlVm command (depends on
+ * command id) */
+ U64 handle; /*< a handle of something (depends on
+ * command id) */
+ };
+} CONTROLVM_MESSAGE_PACKET;
+
+/* All messages in any ControlVm queue have this layout. */
+typedef struct _CONTROLVM_MESSAGE {
+ CONTROLVM_MESSAGE_HEADER hdr;
+ CONTROLVM_MESSAGE_PACKET cmd;
+} CONTROLVM_MESSAGE;
+
+typedef struct _DEVICE_MAP {
+ GUEST_PHYSICAL_ADDRESS DeviceChannelAddress;
+ U64 DeviceChannelSize;
+ U32 CA_Index;
+ U32 Reserved; /* natural alignment */
+ U64 Reserved2; /* Align structure on 32-byte boundary */
+} DEVICE_MAP;
+
+typedef struct _GUEST_DEVICES {
+ DEVICE_MAP VideoChannel;
+ DEVICE_MAP KeyboardChannel;
+ DEVICE_MAP NetworkChannel;
+ DEVICE_MAP StorageChannel;
+ DEVICE_MAP ConsoleChannel;
+ U32 PartitionIndex;
+ U32 Pad;
+} GUEST_DEVICES;
+
+typedef struct _ULTRA_CONTROLVM_CHANNEL_PROTOCOL {
+ CHANNEL_HEADER Header;
+ GUEST_PHYSICAL_ADDRESS gpControlVm; /* guest physical address of
+ * this channel */
+ GUEST_PHYSICAL_ADDRESS gpPartitionTables; /* guest physical address of
+ * partition tables */
+ GUEST_PHYSICAL_ADDRESS gpDiagGuest; /* guest physical address of
+ * diagnostic channel */
+ GUEST_PHYSICAL_ADDRESS gpBootRomDisk; /* guest phys addr of (read
+ * only) Boot ROM disk */
+ GUEST_PHYSICAL_ADDRESS gpBootRamDisk; /* guest phys addr of writable
+ * Boot RAM disk */
+ GUEST_PHYSICAL_ADDRESS gpAcpiTable; /* guest phys addr of acpi
+ * table */
+ GUEST_PHYSICAL_ADDRESS gpControlChannel; /* guest phys addr of control
+ * channel */
+ GUEST_PHYSICAL_ADDRESS gpDiagRomDisk; /* guest phys addr of diagnostic
+ * ROM disk */
+ GUEST_PHYSICAL_ADDRESS gpNvram; /* guest phys addr of NVRAM
+ * channel */
+ U64 RequestPayloadOffset; /* Offset to request payload area */
+ U64 EventPayloadOffset; /* Offset to event payload area */
+ U32 RequestPayloadBytes; /* Bytes available in request payload
+ * area */
+ U32 EventPayloadBytes; /* Bytes available in event payload area */
+ U32 ControlChannelBytes;
+ U32 NvramChannelBytes; /* Bytes in PartitionNvram segment */
+ U32 MessageBytes; /* sizeof(CONTROLVM_MESSAGE) */
+ U32 MessageCount; /* CONTROLVM_MESSAGE_MAX */
+ GUEST_PHYSICAL_ADDRESS gpSmbiosTable; /* guest phys addr of SMBIOS
+ * tables */
+ GUEST_PHYSICAL_ADDRESS gpPhysicalSmbiosTable; /* guest phys addr of
+ * SMBIOS table */
+ /* ULTRA_MAX_GUESTS_PER_SERVICE */
+ GUEST_DEVICES gpObsoleteGuestDevices[16];
+
+ /* guest physical address of EFI firmware image base */
+ GUEST_PHYSICAL_ADDRESS VirtualGuestFirmwareImageBase;
+
+ /* guest physical address of EFI firmware entry point */
+ GUEST_PHYSICAL_ADDRESS VirtualGuestFirmwareEntryPoint;
+
+ /* guest EFI firmware image size */
+ U64 VirtualGuestFirmwareImageSize;
+
+ /* GPA = 1MB where EFI firmware image is copied to */
+ GUEST_PHYSICAL_ADDRESS VirtualGuestFirmwareBootBase;
+ GUEST_PHYSICAL_ADDRESS VirtualGuestImageBase;
+ GUEST_PHYSICAL_ADDRESS VirtualGuestImageSize;
+ U64 PrototypeControlChannelOffset;
+ GUEST_PHYSICAL_ADDRESS VirtualGuestPartitionHandle;
+
+ U16 RestoreAction; /* Restore Action field to restore the guest
+ * partition */
+ U16 DumpAction; /* For Windows guests it shows if the visordisk
+ * is running in dump mode */
+ U16 NvramFailCount;
+ U16 SavedCrashMsgCount; /* = CONTROLVM_CRASHMSG_MAX */
+ U32 SavedCrashMsgOffset; /* Offset to request payload area needed
+ * for crash dump */
+ U32 InstallationError; /* Type of error encountered during
+ * installation */
+ U32 InstallationTextId; /* Id of string to display */
+ U16 InstallationRemainingSteps; /* Number of remaining installation
+ * steps (for progress bars) */
+ U8 ToolAction; /* ULTRA_TOOL_ACTIONS Installation Action
+ * field */
+ U8 Reserved; /* alignment */
+ ULTRA_EFI_SPAR_INDICATION EfiSparIndication;
+ ULTRA_EFI_SPAR_INDICATION EfiSparIndicationSupported;
+ U32 SPReserved;
+ U8 Reserved2[28]; /* Force signals to begin on 128-byte cache
+ * line */
+ SIGNAL_QUEUE_HEADER RequestQueue; /* Service or guest partition
+ * uses this queue to send
+ * requests to Control */
+ SIGNAL_QUEUE_HEADER ResponseQueue; /* Control uses this queue to
+ * respond to service or guest
+ * partition requests */
+ SIGNAL_QUEUE_HEADER EventQueue; /* Control uses this queue to
+ * send events to service or
+ * guest partition */
+ SIGNAL_QUEUE_HEADER EventAckQueue; /* Service or guest partition
+ * uses this queue to ack
+ * Control events */
+
+ /* Request fixed-size message pool - does not include payload */
+ CONTROLVM_MESSAGE RequestMsg[CONTROLVM_MESSAGE_MAX];
+
+ /* Response fixed-size message pool - does not include payload */
+ CONTROLVM_MESSAGE ResponseMsg[CONTROLVM_MESSAGE_MAX];
+
+ /* Event fixed-size message pool - does not include payload */
+ CONTROLVM_MESSAGE EventMsg[CONTROLVM_MESSAGE_MAX];
+
+ /* Ack fixed-size message pool - does not include payload */
+ CONTROLVM_MESSAGE EventAckMsg[CONTROLVM_MESSAGE_MAX];
+
+ /* Message stored during IOVM creation to be reused after crash */
+ CONTROLVM_MESSAGE SavedCrashMsg[CONTROLVM_CRASHMSG_MAX];
+} ULTRA_CONTROLVM_CHANNEL_PROTOCOL;
+
+/* Offsets for VM channel attributes... */
+#define VM_CH_REQ_QUEUE_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, RequestQueue)
+#define VM_CH_RESP_QUEUE_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, ResponseQueue)
+#define VM_CH_EVENT_QUEUE_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventQueue)
+#define VM_CH_ACK_QUEUE_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventAckQueue)
+#define VM_CH_REQ_MSG_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, RequestMsg)
+#define VM_CH_RESP_MSG_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, ResponseMsg)
+#define VM_CH_EVENT_MSG_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventMsg)
+#define VM_CH_ACK_MSG_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventAckMsg)
+#define VM_CH_CRASH_MSG_OFFSET \
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, SavedCrashMsg)
+
+/* The following header will be located at the beginning of PayloadVmOffset for
+ * various ControlVm commands. The receiver of a ControlVm command with a
+ * PayloadVmOffset will dereference this address and then use ConnectionOffset,
+ * InitiatorOffset, and TargetOffset to get the location of UTF-8 formatted
+ * strings that can be parsed to obtain command-specific information. The value
+ * of TotalLength should equal PayloadBytes. The format of the strings at
+ * PayloadVmOffset will take different forms depending on the message. See the
+ * following Wiki page for more information:
+ * https://ustr-linux-1.na.uis.unisys.com/spar/index.php/ControlVm_Parameters_Area
+ */
+typedef struct _ULTRA_CONTROLVM_PARAMETERS_HEADER {
+ U32 TotalLength;
+ U32 HeaderLength;
+ U32 ConnectionOffset;
+ U32 ConnectionLength;
+ U32 InitiatorOffset;
+ U32 InitiatorLength;
+ U32 TargetOffset;
+ U32 TargetLength;
+ U32 ClientOffset;
+ U32 ClientLength;
+ U32 NameOffset;
+ U32 NameLength;
+ GUID Id;
+ U32 Revision;
+ U32 Reserved; /* Natural alignment */
+} ULTRA_CONTROLVM_PARAMETERS_HEADER;
+
+#endif /* __CONTROLVMCHANNEL_H__ */
diff --git a/drivers/staging/unisys/common-spar/include/channels/diagchannel.h b/drivers/staging/unisys/common-spar/include/channels/diagchannel.h
new file mode 100644
index 000000000000..c93515eb211d
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/channels/diagchannel.h
@@ -0,0 +1,427 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*++
+ *
+ * Module Name:
+ *
+ * diagchannel.h
+ *
+ * Abstract:
+ *
+ * This file defines the DiagChannel protocol. This protocol is used to aid in
+ * preserving event data sent by external applications. This protocol provides
+ * a region for event data to reside in. This data will eventually be sent to
+ * the Boot Partition where it will be committed to memory and/or disk. This
+ * file contains platform-independent data that can be built using any
+ * Supervisor build environment (Windows, Linux, EFI).
+ *
+*/
+
+#ifndef _DIAG_CHANNEL_H_
+#define _DIAG_CHANNEL_H_
+
+#include "commontypes.h"
+#include "channel.h"
+
+/* {EEA7A573-DB82-447c-8716-EFBEAAAE4858} */
+#define ULTRA_DIAG_CHANNEL_PROTOCOL_GUID \
+ {0xeea7a573, 0xdb82, 0x447c, \
+ {0x87, 0x16, 0xef, 0xbe, 0xaa, 0xae, 0x48, 0x58} }
+
+static const GUID UltraDiagChannelProtocolGuid =
+ ULTRA_DIAG_CHANNEL_PROTOCOL_GUID;
+
+/* {E850F968-3263-4484-8CA5-2A35D087A5A8} */
+#define ULTRA_DIAG_ROOT_CHANNEL_PROTOCOL_GUID \
+ {0xe850f968, 0x3263, 0x4484, \
+ {0x8c, 0xa5, 0x2a, 0x35, 0xd0, 0x87, 0xa5, 0xa8} }
+
+#define ULTRA_DIAG_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
+
+/* Must increment this whenever you insert or delete fields within this channel
+* struct. Also increment whenever you change the meaning of fields within this
+* channel struct so as to break pre-existing software. Note that you can
+* usually add fields to the END of the channel struct withOUT needing to
+* increment this. */
+#define ULTRA_DIAG_CHANNEL_PROTOCOL_VERSIONID 2
+
+#define ULTRA_DIAG_CHANNEL_OK_CLIENT(pChannel, logCtx) \
+ (ULTRA_check_channel_client(pChannel, \
+ UltraDiagChannelProtocolGuid, \
+ "diag", \
+ sizeof(ULTRA_DIAG_CHANNEL_PROTOCOL), \
+ ULTRA_DIAG_CHANNEL_PROTOCOL_VERSIONID, \
+ ULTRA_DIAG_CHANNEL_PROTOCOL_SIGNATURE, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_DIAG_CHANNEL_OK_SERVER(actualBytes, logCtx) \
+ (ULTRA_check_channel_server(UltraDiagChannelProtocolGuid, \
+ "diag", \
+ sizeof(ULTRA_DIAG_CHANNEL_PROTOCOL), \
+ actualBytes, __FILE__, __LINE__, logCtx))
+#define MAX_MODULE_NAME_SIZE 128 /* Maximum length of module name... */
+#define MAX_ADDITIONAL_INFO_SIZE 256 /* Maximum length of any additional info
+ * accompanying event... */
+#define MAX_SUBSYSTEMS 64 /* Maximum number of subsystems allowed in
+ * DiagChannel... */
+#define LOW_SUBSYSTEMS 32 /* Half of MAX_SUBSYSTEMS to allow 64-bit
+ * math */
+#define SUBSYSTEM_DEBUG 0 /* Standard subsystem for debug events */
+#define SUBSYSTEM_DEFAULT 1 /* Default subsystem for legacy calls to
+ * ReportEvent */
+
+/* few useful subsystem mask values */
+#define SUBSYSTEM_MASK_DEBUG 0x01 /* Standard subsystem for debug
+ * events */
+#define SUBSYSTEM_MASK_DEFAULT 0x02 /* Default subsystem for legacy calls to
+ * ReportEvents */
+
+/* Event parameter "Severity" is overloaded with Cause in byte 2 and Severity in
+ * byte 0, bytes 1 and 3 are reserved */
+#define SEVERITY_MASK 0x0FF /* mask out all but the Severity in byte 0 */
+#define CAUSE_MASK 0x0FF0000 /* mask out all but the cause in byte 2 */
+#define CAUSE_SHIFT_AMT 16 /* shift 2 bytes to place it in byte 2 */
+
+/* SubsystemSeverityFilter */
+#define SEVERITY_FILTER_MASK 0x0F /* mask out the Cause half, SeverityFilter is
+ * in the lower nibble */
+#define CAUSE_FILTER_MASK 0xF0 /* mask out the Severity half, CauseFilter is in
+ * the upper nibble */
+#define CAUSE_FILTER_SHIFT_AMT 4 /* shift amount to place it in lower or upper
+ * nibble */
+
+/* Copied from EFI's EFI_TIME struct in efidef.h. EFI headers are not allowed
+* in some of the Supervisor areas, such as Monitor, so it has been "ported" here
+* for use in diagnostic event timestamps... */
+typedef struct _DIAG_EFI_TIME {
+ U16 Year; /* 1998 - 20XX */
+ U8 Month; /* 1 - 12 */
+ U8 Day; /* 1 - 31 */
+ U8 Hour; /* 0 - 23 */
+ U8 Minute; /* 0 - 59 */
+ U8 Second; /* 0 - 59 */
+ U8 Pad1;
+ U32 Nanosecond; /* 0 - 999, 999, 999 */
+ S16 TimeZone; /* -1440 to 1440 or 2047 */
+ U8 Daylight;
+ U8 Pad2;
+} DIAG_EFI_TIME;
+
+typedef enum {
+ ULTRA_COMPONENT_GUEST = 0,
+ ULTRA_COMPONENT_MONITOR = 0x01,
+ ULTRA_COMPONENT_CCM = 0x02, /* Common Control module */
+ /* RESERVED 0x03 - 0x7 */
+
+ /* Ultravisor Components */
+ ULTRA_COMPONENT_BOOT = 0x08,
+ ULTRA_COMPONENT_IDLE = 0x09,
+ ULTRA_COMPONENT_CONTROL = 0x0A,
+ ULTRA_COMPONENT_LOGGER = 0x0B,
+ ULTRA_COMPONENT_ACPI = 0X0C,
+ /* RESERVED 0x0D - 0x0F */
+
+ /* sPAR Components */
+ ULTRA_COMPONENT_COMMAND = 0x10,
+ ULTRA_COMPONENT_IODRIVER = 0x11,
+ ULTRA_COMPONENT_CONSOLE = 0x12,
+ ULTRA_COMPONENT_OPERATIONS = 0x13,
+ ULTRA_COMPONENT_MANAGEMENT = 0x14,
+ ULTRA_COMPONENT_DIAG = 0x15,
+ ULTRA_COMPONENT_HWDIAG = 0x16,
+ ULTRA_COMPONENT_PSERVICES = 0x17,
+ ULTRA_COMPONENT_PDIAG = 0x18
+ /* RESERVED 0x18 - 0x1F */
+} ULTRA_COMPONENT_TYPES;
+
+/* Structure: DIAG_CHANNEL_EVENT Purpose: Contains attributes that make up an
+ * event to be written to the DIAG_CHANNEL memory. Attributes: EventId: Id of
+ * the diagnostic event to write to memory. Severity: Severity of the event
+ * (Error, Info, etc). ModuleName: Module/file name where event originated.
+ * LineNumber: Line number in module name where event originated. Timestamp:
+ * Date/time when event was received by ReportEvent, and written to DiagChannel.
+ * Reserved: Padding to align structure on a 64-byte cache line boundary.
+ * AdditionalInfo: Array of characters for additional event info (may be
+ * empty). */
+typedef struct _DIAG_CHANNEL_EVENT {
+ U32 EventId;
+ U32 Severity;
+ U8 ModuleName[MAX_MODULE_NAME_SIZE];
+ U32 LineNumber;
+ DIAG_EFI_TIME Timestamp; /* Size = 16 bytes */
+ U32 PartitionNumber; /* Filled in by Diag Switch as pool blocks are
+ * filled */
+ U16 VirtualProcessorNumber;
+ U16 LogicalProcessorNumber;
+ U8 ComponentType; /* ULTRA_COMPONENT_TYPES */
+ U8 Subsystem;
+ U16 Reserved0; /* pad to U64 alignment */
+ U32 BlockNumber; /* filled in by DiagSwitch as pool blocks are
+ * filled */
+ U32 BlockNumberHigh;
+ U32 EventNumber; /* filled in by DiagSwitch as pool blocks are
+ * filled */
+ U32 EventNumberHigh;
+
+ /* The BlockNumber and EventNumber fields are set only by DiagSwitch
+ * and referenced only by WinDiagDisplay formatting tool as
+ * additional diagnostic information. Other tools including
+ * WinDiagDisplay currently ignore these 'Reserved' bytes. */
+ U8 Reserved[8];
+ U8 AdditionalInfo[MAX_ADDITIONAL_INFO_SIZE];
+
+ /* NOTE: Changesto DIAG_CHANNEL_EVENT generally need to be reflected in
+ * existing copies *
+ * - for AppOS at
+ * GuestLinux/visordiag_early/supervisor_diagchannel.h *
+ * - for WinDiagDisplay at
+ * EFI/Ultra/Tools/WinDiagDisplay/WinDiagDisplay/diagstruct.h */
+} DIAG_CHANNEL_EVENT;
+
+/* Levels of severity for diagnostic events, in order from lowest severity to
+* highest (i.e. fatal errors are the most severe, and should always be logged,
+* but info events rarely need to be logged except during debugging). The values
+* DIAG_SEVERITY_ENUM_BEGIN and DIAG_SEVERITY_ENUM_END are not valid severity
+* values. They exist merely to dilineate the list, so that future additions
+* won't require changes to the driver (i.e. when checking for out-of-range
+* severities in SetSeverity). The values DIAG_SEVERITY_OVERRIDE and
+* DIAG_SEVERITY_SHUTOFF are not valid severity values for logging events but
+* they are valid for controlling the amount of event data. This enum is also
+* defined in DotNet\sParFramework\ControlFramework\ControlFramework.cs. If a
+* change is made to this enum, they should also be reflected in that file. */
+typedef enum { DIAG_SEVERITY_ENUM_BEGIN = 0,
+ DIAG_SEVERITY_OVERRIDE = DIAG_SEVERITY_ENUM_BEGIN,
+ DIAG_SEVERITY_VERBOSE = DIAG_SEVERITY_OVERRIDE, /* 0 */
+ DIAG_SEVERITY_INFO = DIAG_SEVERITY_VERBOSE + 1, /* 1 */
+ DIAG_SEVERITY_WARNING = DIAG_SEVERITY_INFO + 1, /* 2 */
+ DIAG_SEVERITY_ERR = DIAG_SEVERITY_WARNING + 1, /* 3 */
+ DIAG_SEVERITY_PRINT = DIAG_SEVERITY_ERR + 1, /* 4 */
+ DIAG_SEVERITY_SHUTOFF = DIAG_SEVERITY_PRINT + 1, /* 5 */
+ DIAG_SEVERITY_ENUM_END = DIAG_SEVERITY_SHUTOFF, /* 5 */
+ DIAG_SEVERITY_NONFATAL_ERR = DIAG_SEVERITY_ERR,
+ DIAG_SEVERITY_FATAL_ERR = DIAG_SEVERITY_PRINT
+} DIAG_SEVERITY;
+
+/* Event Cause enums
+*
+* Levels of cause for diagnostic events, in order from least to greatest cause
+* Internal errors are most urgent since ideally they should never exist
+* Invalid requests are preventable by avoiding invalid inputs
+* Operations errors depend on environmental factors which may impact which
+* requests are possible
+* Manifest provides intermediate value to capture firmware and configuration
+* version information
+* Trace provides suplimental debug information in release firmware
+* Unknown Log captures unclasified LogEvent calls.
+* Debug is the least urgent since it provides suplimental debug information only
+* in debug firmware
+* Unknown Debug captures unclassified DebugEvent calls.
+* This enum is also defined in
+* DotNet\sParFramework\ControlFramework\ControlFramework.cs.
+* If a change is made to this enum, they should also be reflected in that
+* file. */
+
+
+
+/* A cause value "DIAG_CAUSE_FILE_XFER" together with a severity value of
+* "DIAG_SEVERITY_PRINT" (=4), is used for transferring text or binary file to
+* the Diag partition. This cause-severity combination will be used by Logger
+* DiagSwitch to segregate events into block types. The files are transferred in
+* 256 byte chunks maximum, in the AdditionalInfo field of the DIAG_CHANNEL_EVENT
+* structure. In the file transfer mode, some event fields will have different
+* meaning: EventId specifies the file offset, severity specifies the block type,
+* ModuleName specifies the filename, LineNumber specifies the number of valid
+* data bytes in an event and AdditionalInfo contains up to 256 bytes of data. */
+
+/* The Diag DiagWriter appends event blocks to events.raw as today, and for data
+ * blocks uses DIAG_CHANNEL_EVENT
+ * PartitionNumber to extract and append 'AdditionalInfo' to filename (specified
+ * by ModuleName). */
+
+/* The Dell PDiag uses this new mechanism to stash DSET .zip onto the
+ * 'diagnostic' virtual disk. */
+typedef enum {
+ DIAG_CAUSE_UNKNOWN = 0,
+ DIAG_CAUSE_UNKNOWN_DEBUG = DIAG_CAUSE_UNKNOWN + 1, /* 1 */
+ DIAG_CAUSE_DEBUG = DIAG_CAUSE_UNKNOWN_DEBUG + 1, /* 2 */
+ DIAG_CAUSE_UNKNOWN_LOG = DIAG_CAUSE_DEBUG + 1, /* 3 */
+ DIAG_CAUSE_TRACE = DIAG_CAUSE_UNKNOWN_LOG + 1, /* 4 */
+ DIAG_CAUSE_MANIFEST = DIAG_CAUSE_TRACE + 1, /* 5 */
+ DIAG_CAUSE_OPERATIONS_ERROR = DIAG_CAUSE_MANIFEST + 1, /* 6 */
+ DIAG_CAUSE_INVALID_REQUEST = DIAG_CAUSE_OPERATIONS_ERROR + 1, /* 7 */
+ DIAG_CAUSE_INTERNAL_ERROR = DIAG_CAUSE_INVALID_REQUEST + 1, /* 8 */
+ DIAG_CAUSE_FILE_XFER = DIAG_CAUSE_INTERNAL_ERROR + 1, /* 9 */
+ DIAG_CAUSE_ENUM_END = DIAG_CAUSE_FILE_XFER /* 9 */
+} DIAG_CAUSE;
+
+/* Event Cause category defined into the byte 2 of Severity */
+#define CAUSE_DEBUG (DIAG_CAUSE_DEBUG << CAUSE_SHIFT_AMT)
+#define CAUSE_TRACE (DIAG_CAUSE_TRACE << CAUSE_SHIFT_AMT)
+#define CAUSE_MANIFEST (DIAG_CAUSE_MANIFEST << CAUSE_SHIFT_AMT)
+#define CAUSE_OPERATIONS_ERROR (DIAG_CAUSE_OPERATIONS_ERROR << CAUSE_SHIFT_AMT)
+#define CAUSE_INVALID_REQUEST (DIAG_CAUSE_INVALID_REQUEST << CAUSE_SHIFT_AMT)
+#define CAUSE_INTERNAL_ERROR (DIAG_CAUSE_INTERNAL_ERROR << CAUSE_SHIFT_AMT)
+#define CAUSE_FILE_XFER (DIAG_CAUSE_FILE_XFER << CAUSE_SHIFT_AMT)
+#define CAUSE_ENUM_END CAUSE_FILE_XFER
+
+/* Combine Cause and Severity categories into one */
+#define CAUSE_DEBUG_SEVERITY_VERBOSE \
+ (CAUSE_DEBUG | DIAG_SEVERITY_VERBOSE)
+#define CAUSE_TRACE_SEVERITY_VERBOSE \
+ (CAUSE_TRACE | DIAG_SEVERITY_VERBOSE)
+#define CAUSE_MANIFEST_SEVERITY_VERBOSE\
+ (CAUSE_MANIFEST | DIAG_SEVERITY_VERBOSE)
+#define CAUSE_OPERATIONS_SEVERITY_VERBOSE \
+ (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_VERBOSE)
+#define CAUSE_INVALID_SEVERITY_VERBOSE \
+ (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_VERBOSE)
+#define CAUSE_INTERNAL_SEVERITY_VERBOSE \
+ (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_VERBOSE)
+
+#define CAUSE_DEBUG_SEVERITY_INFO \
+ (CAUSE_DEBUG | DIAG_SEVERITY_INFO)
+#define CAUSE_TRACE_SEVERITY_INFO \
+ (CAUSE_TRACE | DIAG_SEVERITY_INFO)
+#define CAUSE_MANIFEST_SEVERITY_INFO \
+ (CAUSE_MANIFEST | DIAG_SEVERITY_INFO)
+#define CAUSE_OPERATIONS_SEVERITY_INFO \
+ (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_INFO)
+#define CAUSE_INVALID_SEVERITY_INFO \
+ (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_INFO)
+#define CAUSE_INTERNAL_SEVERITY_INFO \
+ (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_INFO)
+
+#define CAUSE_DEBUG_SEVERITY_WARN \
+ (CAUSE_DEBUG | DIAG_SEVERITY_WARNING)
+#define CAUSE_TRACE_SEVERITY_WARN \
+ (CAUSE_TRACE | DIAG_SEVERITY_WARNING)
+#define CAUSE_MANIFEST_SEVERITY_WARN \
+ (CAUSE_MANIFEST | DIAG_SEVERITY_WARNING)
+#define CAUSE_OPERATIONS_SEVERITY_WARN \
+ (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_WARNING)
+#define CAUSE_INVALID_SEVERITY_WARN \
+ (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_WARNING)
+#define CAUSE_INTERNAL_SEVERITY_WARN \
+ (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_WARNING)
+
+#define CAUSE_DEBUG_SEVERITY_ERR \
+ (CAUSE_DEBUG | DIAG_SEVERITY_ERR)
+#define CAUSE_TRACE_SEVERITY_ERR \
+ (CAUSE_TRACE | DIAG_SEVERITY_ERR)
+#define CAUSE_MANIFEST_SEVERITY_ERR \
+ (CAUSE_MANIFEST | DIAG_SEVERITY_ERR)
+#define CAUSE_OPERATIONS_SEVERITY_ERR \
+ (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_ERR)
+#define CAUSE_INVALID_SEVERITY_ERR \
+ (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_ERR)
+#define CAUSE_INTERNAL_SEVERITY_ERR \
+ (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_ERR)
+
+#define CAUSE_DEBUG_SEVERITY_PRINT \
+ (CAUSE_DEBUG | DIAG_SEVERITY_PRINT)
+#define CAUSE_TRACE_SEVERITY_PRINT \
+ (CAUSE_TRACE | DIAG_SEVERITY_PRINT)
+#define CAUSE_MANIFEST_SEVERITY_PRINT \
+ (CAUSE_MANIFEST | DIAG_SEVERITY_PRINT)
+#define CAUSE_OPERATIONS_SEVERITY_PRINT \
+ (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_PRINT)
+#define CAUSE_INVALID_SEVERITY_PRINT \
+ (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_PRINT)
+#define CAUSE_INTERNAL_SEVERITY_PRINT \
+ (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_PRINT)
+#define CAUSE_FILE_XFER_SEVERITY_PRINT \
+ (CAUSE_FILE_XFER | DIAG_SEVERITY_PRINT)
+
+/* Structure: DIAG_CHANNEL_PROTOCOL_HEADER
+ *
+ * Purpose: Contains attributes that make up the header specific to the
+ * DIAG_CHANNEL area.
+ *
+ * Attributes:
+ *
+ * DiagLock: Diag Channel spinlock.
+ *
+ *IsChannelInitialized: 1 iff SignalInit was called for this channel; otherwise
+ * 0, and assume the channel is not ready for use yet.
+ *
+ * Reserved: Padding to allign the fields in this structure.
+ *
+ *SubsystemSeverityFilter: Level of severity on a subsystem basis that controls
+ * whether events are logged. Any event's severity for a
+ * particular subsystem below this level will be discarded.
+ */
+typedef struct _DIAG_CHANNEL_PROTOCOL_HEADER {
+ volatile U32 DiagLock;
+ U8 IsChannelInitialized;
+ U8 Reserved[3];
+ U8 SubsystemSeverityFilter[64];
+} DIAG_CHANNEL_PROTOCOL_HEADER;
+
+/* The Diagram for the Diagnostic Channel: */
+/* ----------------------- */
+/* | Channel Header | Defined by ULTRA_CHANNEL_PROTOCOL */
+/* ----------------------- */
+/* | Signal Queue Header | Defined by SIGNAL_QUEUE_HEADER */
+/* ----------------------- */
+/* | DiagChannel Header | Defined by DIAG_CHANNEL_PROTOCOL_HEADER */
+/* ----------------------- */
+/* | Channel Event Info | Defined by (DIAG_CHANNEL_EVENT * MAX_EVENTS) */
+/* ----------------------- */
+/* | Reserved | Reserved (pad out to 4MB) */
+/* ----------------------- */
+
+/* Offsets/sizes for diagnostic channel attributes... */
+#define DIAG_CH_QUEUE_HEADER_OFFSET (sizeof(ULTRA_CHANNEL_PROTOCOL))
+#define DIAG_CH_QUEUE_HEADER_SIZE (sizeof(SIGNAL_QUEUE_HEADER))
+#define DIAG_CH_PROTOCOL_HEADER_OFFSET \
+ (DIAG_CH_QUEUE_HEADER_OFFSET + DIAG_CH_QUEUE_HEADER_SIZE)
+#define DIAG_CH_PROTOCOL_HEADER_SIZE (sizeof(DIAG_CHANNEL_PROTOCOL_HEADER))
+#define DIAG_CH_EVENT_OFFSET \
+ (DIAG_CH_PROTOCOL_HEADER_OFFSET + DIAG_CH_PROTOCOL_HEADER_SIZE)
+#define DIAG_CH_SIZE (4096 * 1024)
+
+/* For Control and Idle Partitions with larger (8 MB) diagnostic(root)
+ * channels */
+#define DIAG_CH_LRG_SIZE (2 * DIAG_CH_SIZE) /* 8 MB */
+
+/*
+ * Structure: ULTRA_DIAG_CHANNEL_PROTOCOL
+ *
+ * Purpose: Contains attributes that make up the DIAG_CHANNEL memory.
+ *
+ * Attributes:
+ *
+ * CommonChannelHeader: Header info common to all channels.
+ *
+ * QueueHeader: Queue header common to all channels - used to determine where to
+ * store event.
+ *
+ * DiagChannelHeader: Diagnostic channel header info (see
+ * DIAG_CHANNEL_PROTOCOL_HEADER comments).
+ *
+ * Events: Area where diagnostic events (up to MAX_EVENTS) are written.
+ *
+ *Reserved: Reserved area to allow for correct channel size padding.
+*/
+typedef struct _ULTRA_DIAG_CHANNEL_PROTOCOL {
+ ULTRA_CHANNEL_PROTOCOL CommonChannelHeader;
+ SIGNAL_QUEUE_HEADER QueueHeader;
+ DIAG_CHANNEL_PROTOCOL_HEADER DiagChannelHeader;
+ DIAG_CHANNEL_EVENT Events[(DIAG_CH_SIZE - DIAG_CH_EVENT_OFFSET) /
+ sizeof(DIAG_CHANNEL_EVENT)];
+}
+ULTRA_DIAG_CHANNEL_PROTOCOL;
+
+#endif
diff --git a/drivers/staging/unisys/common-spar/include/channels/iochannel.h b/drivers/staging/unisys/common-spar/include/channels/iochannel.h
new file mode 100644
index 000000000000..8de1d249d55f
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/channels/iochannel.h
@@ -0,0 +1,933 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION */
+/* All rights reserved. */
+#ifndef __IOCHANNEL_H__
+#define __IOCHANNEL_H__
+
+/*
+* Everything needed for IOPart-GuestPart communication is define in
+* this file. Note: Everything is OS-independent because this file is
+* used by Windows, Linux and possible EFI drivers. */
+
+
+/*
+* Communication flow between the IOPart and GuestPart uses the channel headers
+* channel state. The following states are currently being used:
+* UNINIT(All Zeroes), CHANNEL_ATTACHING, CHANNEL_ATTACHED, CHANNEL_OPENED
+*
+* additional states will be used later. No locking is needed to switch between
+* states due to the following rules:
+*
+* 1. IOPart is only the only partition allowed to change from UNIT
+* 2. IOPart is only the only partition allowed to change from
+* CHANNEL_ATTACHING
+* 3. GuestPart is only the only partition allowed to change from
+* CHANNEL_ATTACHED
+*
+* The state changes are the following: IOPart sees the channel is in UNINIT,
+* UNINIT -> CHANNEL_ATTACHING (performed only by IOPart)
+* CHANNEL_ATTACHING -> CHANNEL_ATTACHED (performed only by IOPart)
+* CHANNEL_ATTACHED -> CHANNEL_OPENED (performed only by GuestPart)
+*/
+
+#include "commontypes.h"
+#include "vmcallinterface.h"
+
+#define _ULTRA_CONTROLVM_CHANNEL_INLINE_
+#include <linux/dma-direction.h>
+#include "controlvmchannel.h"
+#include "vbuschannel.h"
+#undef _ULTRA_CONTROLVM_CHANNEL_INLINE_
+#include "channel.h"
+
+/*
+ * CHANNEL Guids
+ */
+
+#include "channel_guid.h"
+
+#define ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
+#define ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
+#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE \
+ ULTRA_CHANNEL_PROTOCOL_SIGNATURE
+
+/* Must increment these whenever you insert or delete fields within this channel
+* struct. Also increment whenever you change the meaning of fields within this
+* channel struct so as to break pre-existing software. Note that you can
+* usually add fields to the END of the channel struct withOUT needing to
+* increment this. */
+#define ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID 2
+#define ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID 2
+#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID 1
+
+#define ULTRA_VHBA_CHANNEL_OK_CLIENT(pChannel, logCtx) \
+ (ULTRA_check_channel_client(pChannel, UltraVhbaChannelProtocolGuid, \
+ "vhba", MIN_IO_CHANNEL_SIZE, \
+ ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID, \
+ ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_VHBA_CHANNEL_OK_SERVER(actualBytes, logCtx) \
+ (ULTRA_check_channel_server(UltraVhbaChannelProtocolGuid, \
+ "vhba", MIN_IO_CHANNEL_SIZE, actualBytes, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_VNIC_CHANNEL_OK_CLIENT(pChannel, logCtx) \
+ (ULTRA_check_channel_client(pChannel, UltraVnicChannelProtocolGuid, \
+ "vnic", MIN_IO_CHANNEL_SIZE, \
+ ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID, \
+ ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_VNIC_CHANNEL_OK_SERVER(actualBytes, logCtx) \
+ (ULTRA_check_channel_server(UltraVnicChannelProtocolGuid, \
+ "vnic", MIN_IO_CHANNEL_SIZE, actualBytes, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_VSWITCH_CHANNEL_OK_CLIENT(pChannel, logCtx) \
+ (ULTRA_check_channel_client(pChannel, UltraVswitchChannelProtocolGuid, \
+ "vswitch", MIN_IO_CHANNEL_SIZE, \
+ ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID, \
+ ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE, \
+ __FILE__, __LINE__, logCtx))
+#define ULTRA_VSWITCH_CHANNEL_OK_SERVER(actualBytes, logCtx) \
+ (ULTRA_check_channel_server(UltraVswitchChannelProtocolGuid, \
+ "vswitch", MIN_IO_CHANNEL_SIZE, \
+ actualBytes, \
+ __FILE__, __LINE__, logCtx))
+/*
+* Everything necessary to handle SCSI & NIC traffic between Guest Partition and
+* IO Partition is defined below. */
+
+
+/*
+* Defines and enums.
+*/
+
+#define MINNUM(a, b) (((a) < (b)) ? (a) : (b))
+#define MAXNUM(a, b) (((a) > (b)) ? (a) : (b))
+
+/* these define the two queues per data channel between iopart and
+ * ioguestparts */
+#define IOCHAN_TO_IOPART 0 /* used by ioguestpart to 'insert' signals to
+ * iopart */
+#define IOCHAN_FROM_GUESTPART 0 /* used by iopart to 'remove' signals from
+ * ioguestpart - same queue as previous queue */
+
+#define IOCHAN_TO_GUESTPART 1 /* used by iopart to 'insert' signals to
+ * ioguestpart */
+#define IOCHAN_FROM_IOPART 1 /* used by ioguestpart to 'remove' signals from
+ * iopart - same queue as previous queue */
+
+/* these define the two queues per control channel between controlpart and "its"
+ * guests, which includes the iopart */
+#define CTRLCHAN_TO_CTRLGUESTPART 0 /* used by ctrlguestpart to 'insert' signals
+ * to ctrlpart */
+#define CTLRCHAN_FROM_CTRLPART 0 /* used by ctrlpart to 'remove' signals from
+ * ctrlquestpart - same queue as previous
+ * queue */
+
+#define CTRLCHAN_TO_CTRLPART 1 /* used by ctrlpart to 'insert' signals to
+ * ctrlguestpart */
+#define CTRLCHAN_FROM_CTRLGUESTPART 1 /* used by ctrguestpart to 'remove'
+ * signals from ctrlpart - same queue as
+ * previous queue */
+
+/* these define the Event & Ack queues per control channel Events are generated
+* by CTRLGUESTPART and sent to CTRLPART; Acks are generated by CTRLPART and sent
+* to CTRLGUESTPART. */
+#define CTRLCHAN_EVENT_TO_CTRLPART 2 /* used by ctrlguestpart to 'insert' Events
+ * to ctrlpart */
+#define CTRLCHAN_EVENT_FROM_CTRLGUESTPART 2 /* used by ctrlpart to 'remove'
+ * Events from ctrlguestpart */
+
+#define CTRLCHAN_ACK_TO_CTRLGUESTPART 3 /* used by ctrlpart to 'insert' Acks to
+ * ctrlguestpart */
+#define CTRLCHAN_ACK_FROM_CTRLPART 3 /* used by ctrlguestpart to 'remove' Events
+ * from ctrlpart */
+
+/* size of cdb - i.e., scsi cmnd */
+#define MAX_CMND_SIZE 16
+
+#define MAX_SENSE_SIZE 64
+
+#define MAX_PHYS_INFO 64
+
+/* Because GuestToGuestCopy is limited to 4KiB segments, and we have limited the
+* Emulex Driver to 256 scatter list segments via the lpfc_sg_seg_cnt parameter
+* to 256, the maximum I/O size is limited to 256 * 4 KiB = 1 MB */
+#define MAX_IO_SIZE (1024*1024) /* 1 MB */
+
+/* NOTE 1: lpfc defines its support for segments in
+* #define LPFC_SG_SEG_CNT 64
+*
+* NOTE 2: In Linux, frags array in skb is currently allocated to be
+* MAX_SKB_FRAGS size, which is 18 which is smaller than MAX_PHYS_INFO for
+* now. */
+
+#ifndef MAX_SERIAL_NUM
+#define MAX_SERIAL_NUM 32
+#endif /* MAX_SERIAL_NUM */
+
+#define MAX_SCSI_BUSES 1
+#define MAX_SCSI_TARGETS 8
+#define MAX_SCSI_LUNS 16
+#define MAX_SCSI_FROM_HOST 0xFFFFFFFF /* Indicator to use Physical HBA
+ * SCSI Host value */
+
+/* various types of network packets that can be sent in cmdrsp */
+typedef enum { NET_RCV_POST = 0, /* submit buffer to hold receiving
+ * incoming packet */
+ /* virtnic -> uisnic */
+ NET_RCV, /* incoming packet received */
+ /* uisnic -> virtpci */
+ NET_XMIT, /* for outgoing net packets */
+ /* virtnic -> uisnic */
+ NET_XMIT_DONE, /* outgoing packet xmitted */
+ /* uisnic -> virtpci */
+ NET_RCV_ENBDIS, /* enable/disable packet reception */
+ /* virtnic -> uisnic */
+ NET_RCV_ENBDIS_ACK, /* acknowledge enable/disable packet
+ * reception */
+ /* uisnic -> virtnic */
+ NET_RCV_PROMISC, /* enable/disable promiscuous mode */
+ /* virtnic -> uisnic */
+ NET_CONNECT_STATUS, /* indicate the loss or restoration of a network
+ * connection */
+ /* uisnic -> virtnic */
+ NET_MACADDR, /* indicates the client has requested to update
+ * its MAC addr */
+ NET_MACADDR_ACK, /* Mac addres */
+
+} NET_TYPES;
+
+#define ETH_HEADER_SIZE 14 /* size of ethernet header */
+
+#define ETH_MIN_DATA_SIZE 46 /* minimum eth data size */
+#define ETH_MIN_PACKET_SIZE (ETH_HEADER_SIZE + ETH_MIN_DATA_SIZE)
+
+#define ETH_DEF_DATA_SIZE 1500 /* default data size */
+#define ETH_DEF_PACKET_SIZE (ETH_HEADER_SIZE + ETH_DEF_DATA_SIZE)
+
+#define ETH_MAX_MTU 16384 /* maximum data size */
+
+#ifndef MAX_MACADDR_LEN
+#define MAX_MACADDR_LEN 6 /* number of bytes in MAC address */
+#endif /* MAX_MACADDR_LEN */
+
+#define ETH_IS_LOCALLY_ADMINISTERED(Address) \
+ (((U8 *) (Address))[0] & ((U8) 0x02))
+#define NIC_VENDOR_ID 0x0008000B
+
+/* various types of scsi task mgmt commands */
+typedef enum { TASK_MGMT_ABORT_TASK =
+ 1, TASK_MGMT_BUS_RESET, TASK_MGMT_LUN_RESET,
+ TASK_MGMT_TARGET_RESET,
+} TASK_MGMT_TYPES;
+
+/* various types of vdisk mgmt commands */
+typedef enum { VDISK_MGMT_ACQUIRE = 1, VDISK_MGMT_RELEASE,
+} VDISK_MGMT_TYPES;
+
+/* this is used in the vdest field */
+#define VDEST_ALL 0xFFFF
+
+#define MIN_NUMSIGNALS 64
+#define MAX_NUMSIGNALS 4096
+
+/* MAX_NET_RCV_BUF specifies the number of rcv buffers that are created by each
+* guest's virtnic and posted to uisnic. Uisnic, for each channel, keeps the rcv
+* buffers posted and uses them to receive data on behalf of the guest's virtnic.
+* NOTE: the num_rcv_bufs is configurable for each VNIC. So the following is
+* simply an upperlimit on what each VNIC can provide. Setting it to half of the
+* NUMSIGNALS to prevent queue full deadlocks */
+#define MAX_NET_RCV_BUFS (MIN_NUMSIGNALS / 2)
+
+/*
+ * structs with pragma pack */
+
+
+/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
+/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
+
+#pragma pack(push, 1)
+
+struct guest_phys_info {
+ U64 address;
+ U64 length;
+};
+
+#define GPI_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(struct guest_phys_info))
+
+struct uisscsi_dest {
+ U32 channel; /* channel == bus number */
+ U32 id; /* id == target number */
+ U32 lun; /* lun == logical unit number */
+};
+
+struct vhba_wwnn {
+ U32 wwnn1;
+ U32 wwnn2;
+};
+
+/* WARNING: Values stired in this structure must contain maximum counts (not
+ * maximum values). */
+struct vhba_config_max { /* 20 bytes */
+ U32 max_channel; /* maximum channel for devices attached to this
+ * bus */
+ U32 max_id; /* maximum SCSI ID for devices attached to this
+ * bus */
+ U32 max_lun; /* maximum SCSI LUN for devices attached to this
+ * bus */
+ U32 cmd_per_lun; /* maximum number of outstanding commands per
+ * lun that are allowed at one time */
+ U32 max_io_size; /* maximum io size for devices attached to this
+ * bus */
+ /* max io size is often determined by the resource of the hba. e.g */
+ /* max scatter gather list length * page size / sector size */
+};
+
+struct uiscmdrsp_scsi {
+ void *scsicmd; /* the handle to the cmd that was received -
+ * send it back as is in the rsp packet. */
+ U8 cmnd[MAX_CMND_SIZE]; /* the cdb for the command */
+ U32 bufflen; /* length of data to be transferred out or in */
+ U16 guest_phys_entries; /* Number of entries in scatter-gather (sg)
+ * list */
+ struct guest_phys_info gpi_list[MAX_PHYS_INFO]; /* physical address
+ * information for each
+ * fragment */
+ enum dma_data_direction data_dir; /* direction of the data, if any */
+ struct uisscsi_dest vdest; /* identifies the virtual hba, id,
+ * channel, lun to which cmd was sent */
+
+ /* the following fields are needed to queue the rsp back to cmd
+ * originator */
+ int linuxstat; /* the original Linux status - for use by linux
+ * vdisk code */
+ U8 scsistat; /* the scsi status */
+ U8 addlstat; /* non-scsi status - covers cases like timeout
+ * needed by windows guests */
+#define ADDL_RESET 1
+#define ADDL_TIMEOUT 2
+#define ADDL_INTERNAL_ERROR 3
+#define ADDL_SEL_TIMEOUT 4
+#define ADDL_CMD_TIMEOUT 5
+#define ADDL_BAD_TARGET 6
+#define ADDL_RETRY 7
+
+ /* the following fields are need to determine the result of command */
+ U8 sensebuf[MAX_SENSE_SIZE]; /* sense info in case cmd failed; */
+ /* it holds the sense_data struct; */
+ /* see that struct for details. */
+ void *vdisk; /* contains pointer to the vdisk so that we can clean up
+ * when the IO completes. */
+ int no_disk_result; /* used to return no disk inquiry result */
+ /* when no_disk_result is set to 1, */
+ /* scsi.scsistat is SAM_STAT_GOOD */
+ /* scsi.addlstat is 0 */
+ /* scsi.linuxstat is SAM_STAT_GOOD */
+ /* That is, there is NO error. */
+};
+
+/*
+* Defines to support sending correct inquiry result when no disk is
+* configured. */
+
+/* From SCSI SPC2 -
+ *
+ * If the target is not capable of supporting a device on this logical unit, the
+ * device server shall set this field to 7Fh (PERIPHERAL QUALIFIER set to 011b
+ * and PERIPHERAL DEVICE TYPE set to 1Fh).
+ *
+ *The device server is capable of supporting the specified peripheral device
+ *type on this logical unit. However, the physical device is not currently
+ *connected to this logical unit.
+ */
+
+#define DEV_NOT_PRESENT 0x7f /* old name - compatibility */
+#define DEV_NOT_CAPABLE 0x7f /* peripheral qualifier of 0x3 */
+ /* peripheral type of 0x1f */
+ /* specifies no device but target present */
+
+#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20 /* peripheral qualifier of 0x1 */
+ /* peripheral type of 0 - disk */
+ /* specifies device capable, but not present */
+
+#define DEV_PROC_CAPABLE_NOT_PRESENT 0x23 /* peripheral qualifier of 0x1 */
+ /* peripheral type of 3 - processor */
+ /* specifies device capable, but not present */
+
+#define DEV_HISUPPORT 0x10; /* HiSup = 1; shows support for report luns */
+ /* must be returned for lun 0. */
+
+/* NOTE: Linux code assumes inquiry contains 36 bytes. Without checking length
+* in buf[4] some linux code accesses bytes beyond 5 to retrieve vendor, product
+* & revision. Yikes! So let us always send back 36 bytes, the minimum for
+* inquiry result. */
+#define NO_DISK_INQUIRY_RESULT_LEN 36
+
+#define MIN_INQUIRY_RESULT_LEN 5 /* we need at least 5 bytes minimum for inquiry
+ * result */
+
+/* SCSI device version for no disk inquiry result */
+#define SCSI_SPC2_VER 4 /* indicates SCSI SPC2 (SPC3 is 5) */
+
+/* Windows and Linux want different things for a non-existent lun. So, we'll let
+ * caller pass in the peripheral qualifier and type.
+ * NOTE:[4] SCSI returns (n-4); so we return length-1-4 or length-5. */
+
+#define SET_NO_DISK_INQUIRY_RESULT(buf, len, lun, lun0notpresent, notpresent) \
+ do { \
+ MEMSET(buf, 0, \
+ MINNUM(len, \
+ (unsigned int) NO_DISK_INQUIRY_RESULT_LEN)); \
+ buf[2] = (U8) SCSI_SPC2_VER; \
+ if (lun == 0) { \
+ buf[0] = (U8) lun0notpresent; \
+ buf[3] = (U8) DEV_HISUPPORT; \
+ } else \
+ buf[0] = (U8) notpresent; \
+ buf[4] = (U8) ( \
+ MINNUM(len, \
+ (unsigned int) NO_DISK_INQUIRY_RESULT_LEN) - 5); \
+ if (len >= NO_DISK_INQUIRY_RESULT_LEN) { \
+ buf[8] = 'D'; \
+ buf[9] = 'E'; \
+ buf[10] = 'L'; \
+ buf[11] = 'L'; \
+ buf[16] = 'P'; \
+ buf[17] = 'S'; \
+ buf[18] = 'E'; \
+ buf[19] = 'U'; \
+ buf[20] = 'D'; \
+ buf[21] = 'O'; \
+ buf[22] = ' '; \
+ buf[23] = 'D'; \
+ buf[24] = 'E'; \
+ buf[25] = 'V'; \
+ buf[26] = 'I'; \
+ buf[27] = 'C'; \
+ buf[28] = 'E'; \
+ buf[30] = ' '; \
+ buf[31] = '.'; \
+ } \
+ } while (0)
+
+
+/*
+* Struct & Defines to support sense information.
+*/
+
+
+/* The following struct is returned in sensebuf field in uiscmdrsp_scsi. It is
+* initialized in exactly the manner that is recommended in Windows (hence the
+* odd values).
+* When set, these fields will have the following values:
+* ErrorCode = 0x70 indicates current error
+* Valid = 1 indicates sense info is valid
+* SenseKey contains sense key as defined by SCSI specs.
+* AdditionalSenseCode contains sense key as defined by SCSI specs.
+* AdditionalSenseCodeQualifier contains qualifier to sense code as defined by
+* scsi docs.
+* AdditionalSenseLength contains will be sizeof(sense_data)-8=10.
+*/
+struct sense_data {
+ U8 ErrorCode:7;
+ U8 Valid:1;
+ U8 SegmentNumber;
+ U8 SenseKey:4;
+ U8 Reserved:1;
+ U8 IncorrectLength:1;
+ U8 EndOfMedia:1;
+ U8 FileMark:1;
+ U8 Information[4];
+ U8 AdditionalSenseLength;
+ U8 CommandSpecificInformation[4];
+ U8 AdditionalSenseCode;
+ U8 AdditionalSenseCodeQualifier;
+ U8 FieldReplaceableUnitCode;
+ U8 SenseKeySpecific[3];
+};
+
+/* some SCSI ADSENSE codes */
+#ifndef SCSI_ADSENSE_LUN_NOT_READY
+#define SCSI_ADSENSE_LUN_NOT_READY 0x04
+#endif /* */
+#ifndef SCSI_ADSENSE_ILLEGAL_COMMAND
+#define SCSI_ADSENSE_ILLEGAL_COMMAND 0x20
+#endif /* */
+#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK
+#endif /* */
+#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK
+#define SCSI_ADSENSE_ILLEGAL_BLOCK 0x21
+#endif /* */
+#ifndef SCSI_ADSENSE_INVALID_CDB
+#define SCSI_ADSENSE_INVALID_CDB 0x24
+#endif /* */
+#ifndef SCSI_ADSENSE_INVALID_LUN
+#define SCSI_ADSENSE_INVALID_LUN 0x25
+#endif /* */
+#ifndef SCSI_ADWRITE_PROTECT
+#define SCSI_ADWRITE_PROTECT 0x27
+#endif /* */
+#ifndef SCSI_ADSENSE_MEDIUM_CHANGED
+#define SCSI_ADSENSE_MEDIUM_CHANGED 0x28
+#endif /* */
+#ifndef SCSI_ADSENSE_BUS_RESET
+#define SCSI_ADSENSE_BUS_RESET 0x29
+#endif /* */
+#ifndef SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
+#define SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 0x3a
+#endif /* */
+
+struct net_pkt_xmt {
+ int len; /* full length of data in the packet */
+ int num_frags; /* number of fragments in frags containing data */
+ struct phys_info frags[MAX_PHYS_INFO]; /* physical page information for
+ * each fragment */
+ char ethhdr[ETH_HEADER_SIZE]; /* the ethernet header */
+ struct {
+
+ /* these are needed for csum at uisnic end */
+ U8 valid; /* 1 = rest of this struct is valid - else
+ * ignore */
+ U8 hrawoffv; /* 1 = hwrafoff is valid */
+ U8 nhrawoffv; /* 1 = nhwrafoff is valid */
+ U16 protocol; /* specifies packet protocol */
+ U32 csum; /* value used to set skb->csum at IOPart */
+ U32 hrawoff; /* value used to set skb->h.raw at IOPart */
+ /* hrawoff points to the start of the TRANSPORT LAYER HEADER */
+ U32 nhrawoff; /* value used to set skb->nh.raw at IOPart */
+ /* nhrawoff points to the start of the NETWORK LAYER HEADER */
+ } lincsum;
+
+ /* **** NOTE ****
+ * The full packet is described in frags but the ethernet header is
+ * separately kept in ethhdr so that uisnic doesn't have "MAP" the
+ * guest memory to get to the header. uisnic needs ethhdr to
+ * determine how to route the packet.
+ */
+};
+
+struct net_pkt_xmtdone {
+ U32 xmt_done_result; /* result of NET_XMIT */
+#define XMIT_SUCCESS 0
+#define XMIT_FAILED 1
+};
+
+/* RCVPOST_BUF_SIZe must be at most page_size(4096) - cache_line_size (64) The
+* reason is because dev_skb_alloc which is used to generate RCV_POST skbs in
+* virtnic requires that there is "overhead" in the buffer, and pads 16 bytes. I
+* prefer to use 1 full cache line size for "overhead" so that transfers are
+* better. IOVM requires that a buffer be represented by 1 phys_info structure
+* which can only cover page_size. */
+#define RCVPOST_BUF_SIZE 4032
+#define MAX_NET_RCV_CHAIN \
+ ((ETH_MAX_MTU+ETH_HEADER_SIZE + RCVPOST_BUF_SIZE-1) / RCVPOST_BUF_SIZE)
+
+struct net_pkt_rcvpost {
+ /* rcv buf size must be large enough to include ethernet data len +
+ * ethernet header len - we are choosing 2K because it is guaranteed
+ * to be describable */
+ struct phys_info frag; /* physical page information for the
+ * single fragment 2K rcv buf */
+ U64 UniqueNum; /* This is used to make sure that
+ * receive posts are returned to */
+ /* the Adapter which sent them origonally. */
+};
+
+struct net_pkt_rcv {
+
+ /* the number of receive buffers that can be chained */
+ /* is based on max mtu and size of each rcv buf */
+ U32 rcv_done_len; /* length of received data */
+ U8 numrcvbufs; /* number of receive buffers that contain the */
+ /* incoming data; guest end MUST chain these together. */
+ void *rcvbuf[MAX_NET_RCV_CHAIN]; /* the list of receive buffers
+ * that must be chained; */
+ /* each entry is a receive buffer provided by NET_RCV_POST. */
+ /* NOTE: first rcvbuf in the chain will also be provided in net.buf. */
+ U64 UniqueNum;
+ U32 RcvsDroppedDelta;
+};
+
+struct net_pkt_enbdis {
+ void *context;
+ U16 enable; /* 1 = enable, 0 = disable */
+};
+
+struct net_pkt_macaddr {
+ void *context;
+ U8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */
+};
+
+/* cmd rsp packet used for VNIC network traffic */
+struct uiscmdrsp_net {
+ NET_TYPES type;
+ void *buf;
+ union {
+ struct net_pkt_xmt xmt; /* used for NET_XMIT */
+ struct net_pkt_xmtdone xmtdone; /* used for NET_XMIT_DONE */
+ struct net_pkt_rcvpost rcvpost; /* used for NET_RCV_POST */
+ struct net_pkt_rcv rcv; /* used for NET_RCV */
+ struct net_pkt_enbdis enbdis; /* used for NET_RCV_ENBDIS, */
+ /* NET_RCV_ENBDIS_ACK, */
+ /* NET_RCV_PROMSIC, */
+ /* and NET_CONNECT_STATUS */
+ struct net_pkt_macaddr macaddr;
+ };
+};
+
+struct uiscmdrsp_scsitaskmgmt {
+ TASK_MGMT_TYPES tasktype;
+
+ /* the type of task */
+ struct uisscsi_dest vdest;
+
+ /* the vdisk for which this task mgmt is generated */
+ void *scsicmd;
+
+ /* This is some handle that the guest has saved off for its own use.
+ * Its value is preserved by iopart & returned as is in the task mgmt
+ * rsp. */
+ void *notify;
+
+ /* For linux guests, this is a pointer to wait_queue_head that a
+ * thread is waiting on to see if the taskmgmt command has completed.
+ * For windows guests, this is a pointer to a location that a waiting
+ * thread is testing to see if the taskmgmt command has completed.
+ * When the rsp is received by guest, the thread receiving the
+ * response uses this to notify the the thread waiting for taskmgmt
+ * command completion. Its value is preserved by iopart & returned
+ * as is in the task mgmt rsp. */
+ void *notifyresult;
+
+ /* this is a handle to location in guest where the result of the
+ * taskmgmt command (result field) is to saved off when the response
+ * is handled. Its value is preserved by iopart & returned as is in
+ * the task mgmt rsp. */
+ char result;
+
+ /* result of taskmgmt command - set by IOPart - values are: */
+#define TASK_MGMT_FAILED 0
+#define TASK_MGMT_SUCCESS 1
+};
+
+/* The following is used by uissd to send disk add/remove notifications to
+ * Guest */
+/* Note that the vHba pointer is not used by the Client/Guest side. */
+struct uiscmdrsp_disknotify {
+ U8 add; /* 0-remove, 1-add */
+ void *vHba; /* Pointer to vhba_info for channel info to
+ * route msg */
+ U32 channel, id, lun; /* SCSI Path of Disk to added or removed */
+};
+
+/* The following is used by virthba/vSCSI to send the Acquire/Release commands
+* to the IOVM. */
+struct uiscmdrsp_vdiskmgmt {
+ VDISK_MGMT_TYPES vdisktype;
+
+ /* the type of task */
+ struct uisscsi_dest vdest;
+
+ /* the vdisk for which this task mgmt is generated */
+ void *scsicmd;
+
+ /* This is some handle that the guest has saved off for its own use.
+ * Its value is preserved by iopart & returned as is in the task mgmt
+ * rsp. */
+ void *notify;
+
+ /* For linux guests, this is a pointer to wait_queue_head that a
+ * thread is waiting on to see if the taskmgmt command has completed.
+ * For windows guests, this is a pointer to a location that a waiting
+ * thread is testing to see if the taskmgmt command has completed.
+ * When the rsp is received by guest, the thread receiving the
+ * response uses this to notify the the thread waiting for taskmgmt
+ * command completion. Its value is preserved by iopart & returned
+ * as is in the task mgmt rsp. */
+ void *notifyresult;
+
+ /* this is a handle to location in guest where the result of the
+ * taskmgmt command (result field) is to saved off when the response
+ * is handled. Its value is preserved by iopart & returned as is in
+ * the task mgmt rsp. */
+ char result;
+
+ /* result of taskmgmt command - set by IOPart - values are: */
+#define VDISK_MGMT_FAILED 0
+#define VDISK_MGMT_SUCCESS 1
+};
+
+/* keeping cmd & rsp info in one structure for now cmd rsp packet for scsi */
+struct uiscmdrsp {
+ char cmdtype;
+
+ /* describes what type of information is in the struct */
+#define CMD_SCSI_TYPE 1
+#define CMD_NET_TYPE 2
+#define CMD_SCSITASKMGMT_TYPE 3
+#define CMD_NOTIFYGUEST_TYPE 4
+#define CMD_VDISKMGMT_TYPE 5
+ union {
+ struct uiscmdrsp_scsi scsi;
+ struct uiscmdrsp_net net;
+ struct uiscmdrsp_scsitaskmgmt scsitaskmgmt;
+ struct uiscmdrsp_disknotify disknotify;
+ struct uiscmdrsp_vdiskmgmt vdiskmgmt;
+ };
+ void *private_data; /* used to send the response when the cmd is
+ * done (scsi & scsittaskmgmt). */
+ struct uiscmdrsp *next; /* General Purpose Queue Link */
+ struct uiscmdrsp *activeQ_next; /* Used to track active commands */
+ struct uiscmdrsp *activeQ_prev; /* Used to track active commands */
+};
+
+/* This is just the header of the IO channel. It is assumed that directly after
+* this header there is a large region of memory which contains the command and
+* response queues as specified in cmdQ and rspQ SIGNAL_QUEUE_HEADERS. */
+typedef struct _ULTRA_IO_CHANNEL_PROTOCOL {
+ CHANNEL_HEADER ChannelHeader;
+ SIGNAL_QUEUE_HEADER cmdQ;
+ SIGNAL_QUEUE_HEADER rspQ;
+ union {
+ struct {
+ struct vhba_wwnn wwnn; /* 8 bytes */
+ struct vhba_config_max max; /* 20 bytes */
+ } vhba; /* 28 */
+ struct {
+ U8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */
+ U32 num_rcv_bufs; /* 4 */
+ U32 mtu; /* 4 */
+ GUID zoneGuid; /* 16 */
+ } vnic; /* total 30 */
+ };
+
+#define MAX_CLIENTSTRING_LEN 1024
+ U8 clientString[MAX_CLIENTSTRING_LEN]; /* NULL terminated - so holds
+ * max - 1 bytes */
+} ULTRA_IO_CHANNEL_PROTOCOL;
+
+#pragma pack(pop)
+/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */
+
+/* define offsets to members of struct uiscmdrsp */
+#define OFFSET_CMDTYPE OFFSETOF(struct uiscmdrsp, cmdtype)
+#define OFFSET_SCSI OFFSETOF(struct uiscmdrsp, scsi)
+#define OFFSET_NET OFFSETOF(struct uiscmdrsp, net)
+#define OFFSET_SCSITASKMGMT OFFSETOF(struct uiscmdrsp, scsitaskmgmt)
+#define OFFSET_NEXT OFFSETOF(struct uiscmdrsp, next)
+
+/* define offsets to members of struct uiscmdrsp_net */
+#define OFFSET_TYPE OFFSETOF(struct uiscmdrsp_net, type)
+#define OFFSET_BUF OFFSETOF(struct uiscmdrsp_net, buf)
+#define OFFSET_XMT OFFSETOF(struct uiscmdrsp_net, xmt)
+#define OFFSET_XMT_DONE_RESULT OFFSETOF(struct uiscmdrsp_net, xmtdone)
+#define OFFSET_RCVPOST OFFSETOF(struct uiscmdrsp_net, rcvpost)
+#define OFFSET_RCV_DONE_LEN OFFSETOF(struct uiscmdrsp_net, rcv)
+#define OFFSET_ENBDIS OFFSETOF(struct uiscmdrsp_net, enbdis)
+
+/* define offsets to members of struct net_pkt_rcvpost */
+#define OFFSET_TOTALLEN OFFSETOF(struct net_pkt_rcvpost, totallen)
+#define OFFSET_FRAG OFFSETOF(struct net_pkt_rcvpost, frag)
+
+/*
+* INLINE functions for initializing and accessing I/O data channels
+*/
+
+
+#define NUMSIGNALS(x, q) (((ULTRA_IO_CHANNEL_PROTOCOL *)(x))->q.MaxSignalSlots)
+#define SIZEOF_PROTOCOL (COVER(sizeof(ULTRA_IO_CHANNEL_PROTOCOL), 64))
+#define SIZEOF_CMDRSP (COVER(sizeof(struct uiscmdrsp), 64))
+
+#define IO_CHANNEL_SIZE(x) COVER(SIZEOF_PROTOCOL + \
+ (NUMSIGNALS(x, cmdQ) + \
+ NUMSIGNALS(x, rspQ)) * SIZEOF_CMDRSP, 4096)
+#define MIN_IO_CHANNEL_SIZE COVER(SIZEOF_PROTOCOL + \
+ 2 * MIN_NUMSIGNALS * SIZEOF_CMDRSP, 4096)
+#ifdef __GNUC__
+/* These defines should only ever be used in service partitons */
+/* because they rely on the size of uiscmdrsp */
+#define QSLOTSFROMBYTES(bytes) (((bytes-SIZEOF_PROTOCOL)/2)/SIZEOF_CMDRSP)
+#define QSIZEFROMBYTES(bytes) (QSLOTSFROMBYTES(bytes)*SIZEOF_CMDRSP)
+#define SignalQInit(x) \
+ do { \
+ x->cmdQ.Size = QSIZEFROMBYTES(x->ChannelHeader.Size); \
+ x->cmdQ.oSignalBase = SIZEOF_PROTOCOL - \
+ OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, cmdQ); \
+ x->cmdQ.SignalSize = SIZEOF_CMDRSP; \
+ x->cmdQ.MaxSignalSlots = \
+ QSLOTSFROMBYTES(x->ChannelHeader.Size); \
+ x->cmdQ.MaxSignals = x->cmdQ.MaxSignalSlots - 1; \
+ x->rspQ.Size = QSIZEFROMBYTES(x->ChannelHeader.Size); \
+ x->rspQ.oSignalBase = \
+ (SIZEOF_PROTOCOL + x->cmdQ.Size) - \
+ OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, rspQ); \
+ x->rspQ.SignalSize = SIZEOF_CMDRSP; \
+ x->rspQ.MaxSignalSlots = \
+ QSLOTSFROMBYTES(x->ChannelHeader.Size); \
+ x->rspQ.MaxSignals = x->rspQ.MaxSignalSlots - 1; \
+ x->ChannelHeader.oChannelSpace = \
+ OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, cmdQ); \
+ } while (0)
+
+#define INIT_CLIENTSTRING(chan, type, clientStr, clientStrLen) \
+ do { \
+ if (clientStr) { \
+ chan->ChannelHeader.oClientString = \
+ OFFSETOF(type, clientString); \
+ MEMCPY(chan->clientString, clientStr, \
+ MINNUM(clientStrLen, \
+ (U32) (MAX_CLIENTSTRING_LEN - 1))); \
+ chan->clientString[MINNUM(clientStrLen, \
+ (U32) (MAX_CLIENTSTRING_LEN \
+ - 1))] \
+ = '\0'; \
+ } \
+ else \
+ if (clientStrLen > 0) \
+ return 0; \
+ } while (0)
+
+
+#define ULTRA_IO_CHANNEL_SERVER_READY(x, chanId, logCtx) \
+ ULTRA_CHANNEL_SERVER_TRANSITION(x, chanId, SrvState, CHANNELSRV_READY, \
+ logCtx);
+
+#define ULTRA_IO_CHANNEL_SERVER_NOTREADY(x, chanId, logCtx) \
+ ULTRA_CHANNEL_SERVER_TRANSITION(x, chanId, SrvState, \
+ CHANNELSRV_UNINITIALIZED, logCtx);
+
+static inline int ULTRA_VHBA_init_channel(ULTRA_IO_CHANNEL_PROTOCOL *x,
+ struct vhba_wwnn *wwnn,
+ struct vhba_config_max *max,
+ unsigned char *clientStr,
+ U32 clientStrLen, U64 bytes) {
+ MEMSET(x, 0, sizeof(ULTRA_IO_CHANNEL_PROTOCOL));
+ x->ChannelHeader.VersionId = ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID;
+ x->ChannelHeader.Signature = ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE;
+ x->ChannelHeader.SrvState = CHANNELSRV_UNINITIALIZED;
+ x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader);
+ x->ChannelHeader.Size = COVER(bytes, 4096);
+ x->ChannelHeader.Type = UltraVhbaChannelProtocolGuid;
+ x->ChannelHeader.ZoneGuid = Guid0;
+ x->vhba.wwnn = *wwnn;
+ x->vhba.max = *max;
+ INIT_CLIENTSTRING(x, ULTRA_IO_CHANNEL_PROTOCOL, clientStr,
+ clientStrLen);
+ SignalQInit(x);
+ if ((x->cmdQ.MaxSignalSlots > MAX_NUMSIGNALS) ||
+ (x->rspQ.MaxSignalSlots > MAX_NUMSIGNALS)) {
+ return 0;
+ }
+ if ((x->cmdQ.MaxSignalSlots < MIN_NUMSIGNALS) ||
+ (x->rspQ.MaxSignalSlots < MIN_NUMSIGNALS)) {
+ return 0;
+ }
+ return 1;
+}
+
+static inline void ULTRA_VHBA_set_max(ULTRA_IO_CHANNEL_PROTOCOL *x,
+ struct vhba_config_max *max) {
+ x->vhba.max = *max;
+}
+
+static inline int ULTRA_VNIC_init_channel(ULTRA_IO_CHANNEL_PROTOCOL *x,
+ unsigned char *macaddr,
+ U32 num_rcv_bufs, U32 mtu,
+ GUID zoneGuid,
+ unsigned char *clientStr,
+ U32 clientStrLen,
+ U64 bytes) {
+ MEMSET(x, 0, sizeof(ULTRA_IO_CHANNEL_PROTOCOL));
+ x->ChannelHeader.VersionId = ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID;
+ x->ChannelHeader.Signature = ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE;
+ x->ChannelHeader.SrvState = CHANNELSRV_UNINITIALIZED;
+ x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader);
+ x->ChannelHeader.Size = COVER(bytes, 4096);
+ x->ChannelHeader.Type = UltraVnicChannelProtocolGuid;
+ x->ChannelHeader.ZoneGuid = Guid0;
+ MEMCPY(x->vnic.macaddr, macaddr, MAX_MACADDR_LEN);
+ x->vnic.num_rcv_bufs = num_rcv_bufs;
+ x->vnic.mtu = mtu;
+ x->vnic.zoneGuid = zoneGuid;
+ INIT_CLIENTSTRING(x, ULTRA_IO_CHANNEL_PROTOCOL, clientStr,
+ clientStrLen);
+ SignalQInit(x);
+ if ((x->cmdQ.MaxSignalSlots > MAX_NUMSIGNALS) ||
+ (x->rspQ.MaxSignalSlots > MAX_NUMSIGNALS)) {
+ return 0;
+ }
+ if ((x->cmdQ.MaxSignalSlots < MIN_NUMSIGNALS) ||
+ (x->rspQ.MaxSignalSlots < MIN_NUMSIGNALS)) {
+ return 0;
+ }
+ return 1;
+}
+
+#endif /* __GNUC__ */
+
+/*
+* INLINE function for expanding a guest's pfn-off-size into multiple 4K page
+* pfn-off-size entires.
+*/
+
+
+/* we deal with 4K page sizes when we it comes to passing page information
+ * between */
+/* Guest and IOPartition. */
+#define PI_PAGE_SIZE 0x1000
+#define PI_PAGE_MASK 0x0FFF
+#define PI_PAGE_SHIFT 12
+
+/* returns next non-zero index on success or zero on failure (i.e. out of
+ * room)
+ */
+static INLINE U16
+add_physinfo_entries(U32 inp_pfn, /* input - specifies the pfn to be used
+ * to add entries */
+ U16 inp_off, /* input - specifies the off to be used
+ * to add entries */
+ U32 inp_len, /* input - specifies the len to be used
+ * to add entries */
+ U16 index, /* input - index in array at which new
+ * entries are added */
+ U16 max_pi_arr_entries, /* input - specifies the maximum
+ * entries pi_arr can hold */
+ struct phys_info pi_arr[]) /* input & output - array to
+ * which entries are added */
+{
+ U32 len;
+ U16 i, firstlen;
+
+ firstlen = PI_PAGE_SIZE - inp_off;
+ if (inp_len <= firstlen) {
+
+ /* the input entry spans only one page - add as is */
+ if (index >= max_pi_arr_entries)
+ return 0;
+ pi_arr[index].pi_pfn = inp_pfn;
+ pi_arr[index].pi_off = (U16) inp_off;
+ pi_arr[index].pi_len = (U16) inp_len;
+ return index + 1;
+ }
+
+ /* this entry spans multiple pages */
+ for (len = inp_len, i = 0; len;
+ len -= pi_arr[index + i].pi_len, i++) {
+ if (index + i >= max_pi_arr_entries)
+ return 0;
+ pi_arr[index + i].pi_pfn = inp_pfn + i;
+ if (i == 0) {
+ pi_arr[index].pi_off = inp_off;
+ pi_arr[index].pi_len = firstlen;
+ }
+
+ else {
+ pi_arr[index + i].pi_off = 0;
+ pi_arr[index + i].pi_len =
+ (U16) MINNUM(len, (U32) PI_PAGE_SIZE);
+ }
+
+ }
+ return index + i;
+}
+
+#endif /* __IOCHANNEL_H__ */
diff --git a/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h b/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h
new file mode 100644
index 000000000000..99dbbcf3d11e
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h
@@ -0,0 +1,135 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __VBUSCHANNEL_H__
+#define __VBUSCHANNEL_H__
+
+/* The vbus channel is the channel area provided via the BUS_CREATE controlvm
+ * message for each virtual bus. This channel area is provided to both server
+ * and client ends of the bus. The channel header area is initialized by
+ * the server, and the remaining information is filled in by the client.
+ * We currently use this for the client to provide various information about
+ * the client devices and client drivers for the server end to see.
+ */
+#include "commontypes.h"
+#include "vbusdeviceinfo.h"
+#include "channel.h"
+
+/* {193b331b-c58f-11da-95a9-00e08161165f} */
+#define ULTRA_VBUS_CHANNEL_PROTOCOL_GUID \
+ {0x193b331b, 0xc58f, 0x11da, \
+ {0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f} }
+static const GUID UltraVbusChannelProtocolGuid =
+ ULTRA_VBUS_CHANNEL_PROTOCOL_GUID;
+
+#define ULTRA_VBUS_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
+
+/* Must increment this whenever you insert or delete fields within this channel
+* struct. Also increment whenever you change the meaning of fields within this
+* channel struct so as to break pre-existing software. Note that you can
+* usually add fields to the END of the channel struct withOUT needing to
+* increment this. */
+#define ULTRA_VBUS_CHANNEL_PROTOCOL_VERSIONID 1
+
+#define ULTRA_VBUS_CHANNEL_OK_CLIENT(pChannel, logCtx) \
+ (ULTRA_check_channel_client(pChannel, \
+ UltraVbusChannelProtocolGuid, \
+ "vbus", \
+ sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL), \
+ ULTRA_VBUS_CHANNEL_PROTOCOL_VERSIONID, \
+ ULTRA_VBUS_CHANNEL_PROTOCOL_SIGNATURE, \
+ __FILE__, __LINE__, logCtx))
+
+#define ULTRA_VBUS_CHANNEL_OK_SERVER(actualBytes, logCtx) \
+ (ULTRA_check_channel_server(UltraVbusChannelProtocolGuid, \
+ "vbus", \
+ sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL), \
+ actualBytes, \
+ __FILE__, __LINE__, logCtx))
+
+
+#pragma pack(push, 1) /* both GCC and VC now allow this pragma */
+typedef struct _ULTRA_VBUS_HEADERINFO {
+ U32 structBytes; /* size of this struct in bytes */
+ U32 deviceInfoStructBytes; /* sizeof(ULTRA_VBUS_DEVICEINFO) */
+ U32 devInfoCount; /* num of items in DevInfo member */
+ /* (this is the allocated size) */
+ U32 chpInfoByteOffset; /* byte offset from beginning of this struct */
+ /* to the the ChpInfo struct (below) */
+ U32 busInfoByteOffset; /* byte offset from beginning of this struct */
+ /* to the the BusInfo struct (below) */
+ U32 devInfoByteOffset; /* byte offset from beginning of this struct */
+ /* to the the DevInfo array (below) */
+ U8 reserved[104];
+} ULTRA_VBUS_HEADERINFO;
+
+typedef struct _ULTRA_VBUS_CHANNEL_PROTOCOL {
+ ULTRA_CHANNEL_PROTOCOL ChannelHeader; /* initialized by server */
+ ULTRA_VBUS_HEADERINFO HdrInfo; /* initialized by server */
+ /* the remainder of this channel is filled in by the client */
+ ULTRA_VBUS_DEVICEINFO ChpInfo; /* describes client chipset device and
+ * driver */
+ ULTRA_VBUS_DEVICEINFO BusInfo; /* describes client bus device and
+ * driver */
+ ULTRA_VBUS_DEVICEINFO DevInfo[0]; /* describes client device and
+ * driver for */
+ /* each device on the bus */
+} ULTRA_VBUS_CHANNEL_PROTOCOL;
+
+#define VBUS_CH_SIZE_EXACT(MAXDEVICES) \
+ (sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL) + ((MAXDEVICES) * \
+ sizeof(ULTRA_VBUS_DEVICEINFO)))
+#define VBUS_CH_SIZE(MAXDEVICES) COVER(VBUS_CH_SIZE_EXACT(MAXDEVICES), 4096)
+
+static INLINE void
+ULTRA_VBUS_init_channel(ULTRA_VBUS_CHANNEL_PROTOCOL __iomem *x,
+ int bytesAllocated)
+{
+ /* Please note that the memory at <x> does NOT necessarily have space
+ * for DevInfo structs allocated at the end, which is why we do NOT use
+ * <bytesAllocated> to clear. */
+ memset_io(x, 0, sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL));
+ if (bytesAllocated < (int) sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL))
+ return;
+ writel(ULTRA_VBUS_CHANNEL_PROTOCOL_VERSIONID,
+ &x->ChannelHeader.VersionId);
+ writeq(ULTRA_VBUS_CHANNEL_PROTOCOL_SIGNATURE,
+ &x->ChannelHeader.Signature);
+ writel(CHANNELSRV_READY, &x->ChannelHeader.SrvState);
+ writel(sizeof(x->ChannelHeader), &x->ChannelHeader.HeaderSize);
+ writeq(bytesAllocated, &x->ChannelHeader.Size);
+ memcpy_toio(&x->ChannelHeader.Type, &UltraVbusChannelProtocolGuid,
+ sizeof(x->ChannelHeader.Type));
+ memcpy_toio(&x->ChannelHeader.ZoneGuid, &Guid0,
+ sizeof(x->ChannelHeader.ZoneGuid));
+ writel(sizeof(ULTRA_VBUS_HEADERINFO), &x->HdrInfo.structBytes);
+ writel(sizeof(ULTRA_VBUS_HEADERINFO), &x->HdrInfo.chpInfoByteOffset);
+ writel(readl(&x->HdrInfo.chpInfoByteOffset) +
+ sizeof(ULTRA_VBUS_DEVICEINFO),
+ &x->HdrInfo.busInfoByteOffset);
+ writel(readl(&x->HdrInfo.busInfoByteOffset)
+ + sizeof(ULTRA_VBUS_DEVICEINFO),
+ &x->HdrInfo.devInfoByteOffset);
+ writel(sizeof(ULTRA_VBUS_DEVICEINFO),
+ &x->HdrInfo.deviceInfoStructBytes);
+ bytesAllocated -= (sizeof(ULTRA_CHANNEL_PROTOCOL)
+ + readl(&x->HdrInfo.devInfoByteOffset));
+ writel(bytesAllocated / readl(&x->HdrInfo.deviceInfoStructBytes),
+ &x->HdrInfo.devInfoCount);
+}
+
+#pragma pack(pop)
+
+#endif
diff --git a/drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h b/drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h
new file mode 100644
index 000000000000..de30d321d982
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h
@@ -0,0 +1,92 @@
+/* controlvmcompletionstatus.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* Defines for all valid values returned in the response message header
+ * completionStatus field. See controlvmchannel.h for description of
+ * the header: _CONTROLVM_MESSAGE_HEADER.
+ */
+
+#ifndef __CONTROLVMCOMPLETIONSTATUS_H__
+#define __CONTROLVMCOMPLETIONSTATUS_H__
+
+/* General Errors------------------------------------------------------[0-99] */
+#define CONTROLVM_RESP_SUCCESS 0
+#define CONTROLVM_RESP_ERROR_ALREADY_DONE 1
+#define CONTROLVM_RESP_ERROR_IOREMAP_FAILED 2
+#define CONTROLVM_RESP_ERROR_KMALLOC_FAILED 3
+#define CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN 4
+#define CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT 5
+
+/* CONTROLVM_INIT_CHIPSET-------------------------------------------[100-199] */
+#define CONTROLVM_RESP_ERROR_CLIENT_SWITCHCOUNT_NONZERO 100
+#define CONTROLVM_RESP_ERROR_EXPECTED_CHIPSET_INIT 101
+
+/* Maximum Limit----------------------------------------------------[200-299] */
+#define CONTROLVM_RESP_ERROR_MAX_BUSES 201 /* BUS_CREATE */
+#define CONTROLVM_RESP_ERROR_MAX_DEVICES 202 /* DEVICE_CREATE */
+/* Payload and Parameter Related------------------------------------[400-499] */
+#define CONTROLVM_RESP_ERROR_PAYLOAD_INVALID 400 /* SWITCH_ATTACHEXTPORT,
+ * DEVICE_CONFIGURE */
+#define CONTROLVM_RESP_ERROR_INITIATOR_PARAMETER_INVALID 401 /* Multiple */
+#define CONTROLVM_RESP_ERROR_TARGET_PARAMETER_INVALID 402 /* DEVICE_CONFIGURE */
+#define CONTROLVM_RESP_ERROR_CLIENT_PARAMETER_INVALID 403 /* DEVICE_CONFIGURE */
+/* Specified[Packet Structure] Value-------------------------------[500-599] */
+#define CONTROLVM_RESP_ERROR_BUS_INVALID 500 /* SWITCH_ATTACHINTPORT,
+ * BUS_CONFIGURE,
+ * DEVICE_CREATE,
+ * DEVICE_CONFIG
+ * DEVICE_DESTROY */
+#define CONTROLVM_RESP_ERROR_DEVICE_INVALID 501 /* SWITCH_ATTACHINTPORT */
+ /* DEVICE_CREATE,
+ * DEVICE_CONFIGURE,
+ * DEVICE_DESTROY */
+#define CONTROLVM_RESP_ERROR_CHANNEL_INVALID 502 /* DEVICE_CREATE,
+ * DEVICE_CONFIGURE */
+/* Partition Driver Callback Interface----------------------[600-699] */
+#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE 604 /* BUS_CREATE,
+ * BUS_DESTROY,
+ * DEVICE_CREATE,
+ * DEVICE_DESTROY */
+/* Unable to invoke VIRTPCI callback */
+#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR 605 /* BUS_CREATE,
+ * BUS_DESTROY,
+ * DEVICE_CREATE,
+ * DEVICE_DESTROY */
+/* VIRTPCI Callback returned error */
+#define CONTROLVM_RESP_ERROR_GENERIC_DRIVER_CALLBACK_ERROR 606 /* SWITCH_ATTACHEXTPORT,
+ * SWITCH_DETACHEXTPORT
+ * DEVICE_CONFIGURE */
+
+/* generic device callback returned error */
+/* Bus Related------------------------------------------------------[700-799] */
+#define CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED 700 /* BUS_DESTROY */
+/* Channel Related--------------------------------------------------[800-899] */
+#define CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN 800 /* GET_CHANNELINFO,
+ * DEVICE_DESTROY */
+#define CONTROLVM_RESP_ERROR_CHANNEL_SIZE_TOO_SMALL 801 /* DEVICE_CREATE */
+/* Chipset Shutdown Related---------------------------------------[1000-1099] */
+#define CONTROLVM_RESP_ERROR_CHIPSET_SHUTDOWN_FAILED 1000
+#define CONTROLVM_RESP_ERROR_CHIPSET_SHUTDOWN_ALREADY_ACTIVE 1001
+
+/* Chipset Stop Related-------------------------------------------[1100-1199] */
+#define CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_BUS 1100
+#define CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_SWITCH 1101
+
+/* Device Related-------------------------------------------------[1400-1499] */
+#define CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT 1400
+
+#endif /* __CONTROLVMCOMPLETIONSTATUS_H__ not defined */
diff --git a/drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h b/drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h
new file mode 100644
index 000000000000..4c6294d20606
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h
@@ -0,0 +1,310 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* Please note that this file is to be used ONLY for defining diagnostic
+ * subsystem values for the appos (sPAR Linux service partitions) component.
+ */
+#ifndef __APPOS_SUBSYSTEMS_H__
+#define __APPOS_SUBSYSTEMS_H__
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/string.h>
+#else
+#include <stdio.h>
+#include <string.h>
+#endif
+
+static inline char *
+subsys_unknown_to_s(int subsys, char *s, int n)
+{
+ snprintf(s, n, "SUBSYS-%-2.2d", subsys);
+ s[n - 1] = '\0';
+ return s;
+}
+
+#define SUBSYS_TO_MASK(subsys) (1ULL << (subsys))
+
+/* The first SUBSYS_APPOS_MAX subsystems are the same for each AppOS type
+ * (IOVM, SMS, etc.) The rest have unique values for each AppOS type.
+ */
+#define SUBSYS_APPOS_MAX 16
+
+#define SUBSYS_APPOS_DEFAULT 1 /* or "other" */
+#define SUBSYS_APPOS_CHIPSET 2 /* controlvm and other */
+ /* low-level sPAR activity */
+#define SUBSYS_APPOS_BUS 3 /* sPAR bus */
+/* DAK #define SUBSYS_APPOS_DIAG 4 // diagnostics and dump */
+#define SUBSYS_APPOS_CHANNELACCESS 5 /* generic channel access */
+#define SUBSYS_APPOS_NICCLIENT 6 /* virtual NIC client */
+#define SUBSYS_APPOS_HBACLIENT 7 /* virtual HBA client */
+#define SUBSYS_APPOS_CONSOLESERIAL 8 /* sPAR virtual serial console */
+#define SUBSYS_APPOS_UISLIB 9 /* */
+#define SUBSYS_APPOS_VRTCUPDD 10 /* */
+#define SUBSYS_APPOS_WATCHDOG 11 /* watchdog timer and healthcheck */
+#define SUBSYS_APPOS_13 13 /* available */
+#define SUBSYS_APPOS_14 14 /* available */
+#define SUBSYS_APPOS_15 15 /* available */
+#define SUBSYS_APPOS_16 16 /* available */
+static inline char *
+subsys_generic_to_s(int subsys, char *s, int n)
+{
+ switch (subsys) {
+ case SUBSYS_APPOS_DEFAULT:
+ strncpy(s, "APPOS_DEFAULT", n);
+ break;
+ case SUBSYS_APPOS_CHIPSET:
+ strncpy(s, "APPOS_CHIPSET", n);
+ break;
+ case SUBSYS_APPOS_BUS:
+ strncpy(s, "APPOS_BUS", n);
+ break;
+ case SUBSYS_APPOS_CHANNELACCESS:
+ strncpy(s, "APPOS_CHANNELACCESS", n);
+ break;
+ case SUBSYS_APPOS_NICCLIENT:
+ strncpy(s, "APPOS_NICCLIENT", n);
+ break;
+ case SUBSYS_APPOS_HBACLIENT:
+ strncpy(s, "APPOS_HBACLIENT", n);
+ break;
+ case SUBSYS_APPOS_CONSOLESERIAL:
+ strncpy(s, "APPOS_CONSOLESERIAL", n);
+ break;
+ case SUBSYS_APPOS_UISLIB:
+ strncpy(s, "APPOS_UISLIB", n);
+ break;
+ case SUBSYS_APPOS_VRTCUPDD:
+ strncpy(s, "APPOS_VRTCUPDD", n);
+ break;
+ case SUBSYS_APPOS_WATCHDOG:
+ strncpy(s, "APPOS_WATCHDOG", n);
+ break;
+ case SUBSYS_APPOS_13:
+ strncpy(s, "APPOS_13", n);
+ break;
+ case SUBSYS_APPOS_14:
+ strncpy(s, "APPOS_14", n);
+ break;
+ case SUBSYS_APPOS_15:
+ strncpy(s, "APPOS_15", n);
+ break;
+ case SUBSYS_APPOS_16:
+ strncpy(s, "APPOS_16", n);
+ break;
+ default:
+ subsys_unknown_to_s(subsys, s, n);
+ break;
+ }
+ s[n - 1] = '\0';
+ return s;
+}
+
+/* CONSOLE */
+
+#define SUBSYS_CONSOLE_VIDEO (SUBSYS_APPOS_MAX + 1) /* 17 */
+#define SUBSYS_CONSOLE_KBDMOU (SUBSYS_APPOS_MAX + 2) /* 18 */
+#define SUBSYS_CONSOLE_04 (SUBSYS_APPOS_MAX + 4)
+#define SUBSYS_CONSOLE_05 (SUBSYS_APPOS_MAX + 5)
+#define SUBSYS_CONSOLE_06 (SUBSYS_APPOS_MAX + 6)
+#define SUBSYS_CONSOLE_07 (SUBSYS_APPOS_MAX + 7)
+#define SUBSYS_CONSOLE_08 (SUBSYS_APPOS_MAX + 8)
+#define SUBSYS_CONSOLE_09 (SUBSYS_APPOS_MAX + 9)
+#define SUBSYS_CONSOLE_10 (SUBSYS_APPOS_MAX + 10)
+#define SUBSYS_CONSOLE_11 (SUBSYS_APPOS_MAX + 11)
+#define SUBSYS_CONSOLE_12 (SUBSYS_APPOS_MAX + 12)
+#define SUBSYS_CONSOLE_13 (SUBSYS_APPOS_MAX + 13)
+#define SUBSYS_CONSOLE_14 (SUBSYS_APPOS_MAX + 14)
+#define SUBSYS_CONSOLE_15 (SUBSYS_APPOS_MAX + 15)
+#define SUBSYS_CONSOLE_16 (SUBSYS_APPOS_MAX + 16)
+#define SUBSYS_CONSOLE_17 (SUBSYS_APPOS_MAX + 17)
+#define SUBSYS_CONSOLE_18 (SUBSYS_APPOS_MAX + 18)
+#define SUBSYS_CONSOLE_19 (SUBSYS_APPOS_MAX + 19)
+#define SUBSYS_CONSOLE_20 (SUBSYS_APPOS_MAX + 20)
+#define SUBSYS_CONSOLE_21 (SUBSYS_APPOS_MAX + 21)
+#define SUBSYS_CONSOLE_22 (SUBSYS_APPOS_MAX + 22)
+#define SUBSYS_CONSOLE_23 (SUBSYS_APPOS_MAX + 23)
+#define SUBSYS_CONSOLE_24 (SUBSYS_APPOS_MAX + 24)
+#define SUBSYS_CONSOLE_25 (SUBSYS_APPOS_MAX + 25)
+#define SUBSYS_CONSOLE_26 (SUBSYS_APPOS_MAX + 26)
+#define SUBSYS_CONSOLE_27 (SUBSYS_APPOS_MAX + 27)
+#define SUBSYS_CONSOLE_28 (SUBSYS_APPOS_MAX + 28)
+#define SUBSYS_CONSOLE_29 (SUBSYS_APPOS_MAX + 29)
+#define SUBSYS_CONSOLE_30 (SUBSYS_APPOS_MAX + 30)
+#define SUBSYS_CONSOLE_31 (SUBSYS_APPOS_MAX + 31)
+#define SUBSYS_CONSOLE_32 (SUBSYS_APPOS_MAX + 32)
+#define SUBSYS_CONSOLE_33 (SUBSYS_APPOS_MAX + 33)
+#define SUBSYS_CONSOLE_34 (SUBSYS_APPOS_MAX + 34)
+#define SUBSYS_CONSOLE_35 (SUBSYS_APPOS_MAX + 35)
+#define SUBSYS_CONSOLE_36 (SUBSYS_APPOS_MAX + 36)
+#define SUBSYS_CONSOLE_37 (SUBSYS_APPOS_MAX + 37)
+#define SUBSYS_CONSOLE_38 (SUBSYS_APPOS_MAX + 38)
+#define SUBSYS_CONSOLE_39 (SUBSYS_APPOS_MAX + 39)
+#define SUBSYS_CONSOLE_40 (SUBSYS_APPOS_MAX + 40)
+#define SUBSYS_CONSOLE_41 (SUBSYS_APPOS_MAX + 41)
+#define SUBSYS_CONSOLE_42 (SUBSYS_APPOS_MAX + 42)
+#define SUBSYS_CONSOLE_43 (SUBSYS_APPOS_MAX + 43)
+#define SUBSYS_CONSOLE_44 (SUBSYS_APPOS_MAX + 44)
+#define SUBSYS_CONSOLE_45 (SUBSYS_APPOS_MAX + 45)
+#define SUBSYS_CONSOLE_46 (SUBSYS_APPOS_MAX + 46)
+
+static inline char *
+subsys_console_to_s(int subsys, char *s, int n)
+{
+ switch (subsys) {
+ case SUBSYS_CONSOLE_VIDEO:
+ strncpy(s, "CONSOLE_VIDEO", n);
+ break;
+ case SUBSYS_CONSOLE_KBDMOU:
+ strncpy(s, "CONSOLE_KBDMOU", n);
+ break;
+ case SUBSYS_CONSOLE_04:
+ strncpy(s, "CONSOLE_04", n);
+ break;
+ case SUBSYS_CONSOLE_05:
+ strncpy(s, "CONSOLE_05", n);
+ break;
+ case SUBSYS_CONSOLE_06:
+ strncpy(s, "CONSOLE_06", n);
+ break;
+ case SUBSYS_CONSOLE_07:
+ strncpy(s, "CONSOLE_07", n);
+ break;
+ case SUBSYS_CONSOLE_08:
+ strncpy(s, "CONSOLE_08", n);
+ break;
+ case SUBSYS_CONSOLE_09:
+ strncpy(s, "CONSOLE_09", n);
+ break;
+ case SUBSYS_CONSOLE_10:
+ strncpy(s, "CONSOLE_10", n);
+ break;
+ case SUBSYS_CONSOLE_11:
+ strncpy(s, "CONSOLE_11", n);
+ break;
+ case SUBSYS_CONSOLE_12:
+ strncpy(s, "CONSOLE_12", n);
+ break;
+ case SUBSYS_CONSOLE_13:
+ strncpy(s, "CONSOLE_13", n);
+ break;
+ case SUBSYS_CONSOLE_14:
+ strncpy(s, "CONSOLE_14", n);
+ break;
+ case SUBSYS_CONSOLE_15:
+ strncpy(s, "CONSOLE_15", n);
+ break;
+ case SUBSYS_CONSOLE_16:
+ strncpy(s, "CONSOLE_16", n);
+ break;
+ case SUBSYS_CONSOLE_17:
+ strncpy(s, "CONSOLE_17", n);
+ break;
+ case SUBSYS_CONSOLE_18:
+ strncpy(s, "CONSOLE_18", n);
+ break;
+ case SUBSYS_CONSOLE_19:
+ strncpy(s, "CONSOLE_19", n);
+ break;
+ case SUBSYS_CONSOLE_20:
+ strncpy(s, "CONSOLE_20", n);
+ break;
+ case SUBSYS_CONSOLE_21:
+ strncpy(s, "CONSOLE_21", n);
+ break;
+ case SUBSYS_CONSOLE_22:
+ strncpy(s, "CONSOLE_22", n);
+ break;
+ case SUBSYS_CONSOLE_23:
+ strncpy(s, "CONSOLE_23", n);
+ break;
+ case SUBSYS_CONSOLE_24:
+ strncpy(s, "CONSOLE_24", n);
+ break;
+ case SUBSYS_CONSOLE_25:
+ strncpy(s, "CONSOLE_25", n);
+ break;
+ case SUBSYS_CONSOLE_26:
+ strncpy(s, "CONSOLE_26", n);
+ break;
+ case SUBSYS_CONSOLE_27:
+ strncpy(s, "CONSOLE_27", n);
+ break;
+ case SUBSYS_CONSOLE_28:
+ strncpy(s, "CONSOLE_28", n);
+ break;
+ case SUBSYS_CONSOLE_29:
+ strncpy(s, "CONSOLE_29", n);
+ break;
+ case SUBSYS_CONSOLE_30:
+ strncpy(s, "CONSOLE_30", n);
+ break;
+ case SUBSYS_CONSOLE_31:
+ strncpy(s, "CONSOLE_31", n);
+ break;
+ case SUBSYS_CONSOLE_32:
+ strncpy(s, "CONSOLE_32", n);
+ break;
+ case SUBSYS_CONSOLE_33:
+ strncpy(s, "CONSOLE_33", n);
+ break;
+ case SUBSYS_CONSOLE_34:
+ strncpy(s, "CONSOLE_34", n);
+ break;
+ case SUBSYS_CONSOLE_35:
+ strncpy(s, "CONSOLE_35", n);
+ break;
+ case SUBSYS_CONSOLE_36:
+ strncpy(s, "CONSOLE_36", n);
+ break;
+ case SUBSYS_CONSOLE_37:
+ strncpy(s, "CONSOLE_37", n);
+ break;
+ case SUBSYS_CONSOLE_38:
+ strncpy(s, "CONSOLE_38", n);
+ break;
+ case SUBSYS_CONSOLE_39:
+ strncpy(s, "CONSOLE_39", n);
+ break;
+ case SUBSYS_CONSOLE_40:
+ strncpy(s, "CONSOLE_40", n);
+ break;
+ case SUBSYS_CONSOLE_41:
+ strncpy(s, "CONSOLE_41", n);
+ break;
+ case SUBSYS_CONSOLE_42:
+ strncpy(s, "CONSOLE_42", n);
+ break;
+ case SUBSYS_CONSOLE_43:
+ strncpy(s, "CONSOLE_43", n);
+ break;
+ case SUBSYS_CONSOLE_44:
+ strncpy(s, "CONSOLE_44", n);
+ break;
+ case SUBSYS_CONSOLE_45:
+ strncpy(s, "CONSOLE_45", n);
+ break;
+ case SUBSYS_CONSOLE_46:
+ strncpy(s, "CONSOLE_46", n);
+ break;
+ default:
+ subsys_unknown_to_s(subsys, s, n);
+ break;
+ }
+ s[n - 1] = '\0';
+ return s;
+}
+
+#endif
diff --git a/drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h b/drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h
new file mode 100644
index 000000000000..7304e9a0648c
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h
@@ -0,0 +1,53 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* Linux GCC Version (32-bit and 64-bit) */
+static inline unsigned long
+__unisys_vmcall_gnuc(unsigned long tuple, unsigned long reg_ebx,
+ unsigned long reg_ecx)
+{
+ unsigned long result = 0;
+
+ unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;
+ cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx);
+ if (cpuid_ecx & 0x80000000) {
+ __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) :
+ "a"(tuple), "b"(reg_ebx), "c"(reg_ecx)
+ );
+ } else {
+ result = -1;
+ }
+ return result;
+}
+
+static inline unsigned long
+__unisys_extended_vmcall_gnuc(unsigned long long tuple,
+ unsigned long long reg_ebx,
+ unsigned long long reg_ecx,
+ unsigned long long reg_edx)
+{
+ unsigned long result = 0;
+
+ unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;
+ cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx);
+ if (cpuid_ecx & 0x80000000) {
+ __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) :
+ "a"(tuple), "b"(reg_ebx), "c"(reg_ecx),
+ "d"(reg_edx));
+ } else {
+ result = -1;
+ }
+ return result;
+ }
diff --git a/drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h b/drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h
new file mode 100644
index 000000000000..ae708faaa94d
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h
@@ -0,0 +1,209 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __VBUSDEVICEINFO_H__
+#define __VBUSDEVICEINFO_H__
+
+#include "commontypes.h"
+
+#pragma pack(push, 1) /* both GCC and VC now allow this pragma */
+
+/* An array of this struct is present in the channel area for each vbus.
+ * (See vbuschannel.h.)
+ * It is filled in by the client side to provide info about the device
+ * and driver from the client's perspective.
+ */
+typedef struct _ULTRA_VBUS_DEVICEINFO {
+ U8 devType[16]; /* short string identifying the device type */
+ U8 drvName[16]; /* driver .sys file name */
+ U8 infoStrings[96]; /* sequence of tab-delimited id strings: */
+ /* <DRIVER_REV> <DRIVER_VERTAG> <DRIVER_COMPILETIME> */
+ U8 reserved[128]; /* pad size to 256 bytes */
+} ULTRA_VBUS_DEVICEINFO;
+
+#pragma pack(pop)
+
+/* Reads chars from the buffer at <src> for <srcmax> bytes, and writes to
+ * the buffer at <p>, which is <remain> bytes long, ensuring never to
+ * overflow the buffer at <p>, using the following rules:
+ * - printable characters are simply copied from the buffer at <src> to the
+ * buffer at <p>
+ * - intervening streaks of non-printable characters in the buffer at <src>
+ * are replaced with a single space in the buffer at <p>
+ * Note that we pay no attention to '\0'-termination.
+ * Returns the number of bytes written to <p>.
+ *
+ * Pass <p> == NULL and <remain> == 0 for this special behavior. In this
+ * case, we simply return the number of bytes that WOULD HAVE been written
+ * to a buffer at <p>, had it been infinitely big.
+ */
+static inline int
+VBUSCHANNEL_sanitize_buffer(char *p, int remain, char __iomem *src, int srcmax)
+{
+ int chars = 0;
+ int nonprintable_streak = 0;
+ while (srcmax > 0) {
+ if ((readb(src) >= ' ') && (readb(src) < 0x7f)) {
+ if (nonprintable_streak) {
+ if (remain > 0) {
+ *p = ' ';
+ p++;
+ remain--;
+ chars++;
+ } else if (p == NULL)
+ chars++;
+ nonprintable_streak = 0;
+ }
+ if (remain > 0) {
+ *p = readb(src);
+ p++;
+ remain--;
+ chars++;
+ } else if (p == NULL)
+ chars++;
+ } else
+ nonprintable_streak = 1;
+ src++;
+ srcmax--;
+ }
+ return chars;
+}
+
+#define VBUSCHANNEL_ADDACHAR(ch, p, remain, chars) \
+ do { \
+ if (remain <= 0) \
+ break; \
+ *p = ch; \
+ p++; chars++; remain--; \
+ } while (0)
+
+/* Converts the non-negative value at <num> to an ascii decimal string
+ * at <p>, writing at most <remain> bytes. Note there is NO '\0' termination
+ * written to <p>.
+ *
+ * Returns the number of bytes written to <p>.
+ *
+ * Note that we create this function because we need to do this operation in
+ * an environment-independent way (since we are in a common header file).
+ */
+static inline int
+VBUSCHANNEL_itoa(char *p, int remain, int num)
+{
+ int digits = 0;
+ char s[32];
+ int i;
+
+ if (num == 0) {
+ /* '0' is a special case */
+ if (remain <= 0)
+ return 0;
+ *p = '0';
+ return 1;
+ }
+ /* form a backwards decimal ascii string in <s> */
+ while (num > 0) {
+ if (digits >= (int) sizeof(s))
+ return 0;
+ s[digits++] = (num % 10) + '0';
+ num = num / 10;
+ }
+ if (remain < digits) {
+ /* not enough room left at <p> to hold number, so fill with
+ * '?' */
+ for (i = 0; i < remain; i++, p++)
+ *p = '?';
+ return remain;
+ }
+ /* plug in the decimal ascii string representing the number, by */
+ /* reversing the string we just built in <s> */
+ i = digits;
+ while (i > 0) {
+ i--;
+ *p = s[i];
+ p++;
+ }
+ return digits;
+}
+
+/* Reads <devInfo>, and converts its contents to a printable string at <p>,
+ * writing at most <remain> bytes. Note there is NO '\0' termination
+ * written to <p>.
+ *
+ * Pass <devix> >= 0 if you want a device index presented.
+ *
+ * Returns the number of bytes written to <p>.
+ */
+static inline int
+VBUSCHANNEL_devInfoToStringBuffer(ULTRA_VBUS_DEVICEINFO __iomem *devInfo,
+ char *p, int remain, int devix)
+{
+ char __iomem *psrc;
+ int nsrc, x, i, pad;
+ int chars = 0;
+
+ psrc = &(devInfo->devType[0]);
+ nsrc = sizeof(devInfo->devType);
+ if (VBUSCHANNEL_sanitize_buffer(NULL, 0, psrc, nsrc) <= 0)
+ return 0;
+
+ /* emit device index */
+ if (devix >= 0) {
+ VBUSCHANNEL_ADDACHAR('[', p, remain, chars);
+ x = VBUSCHANNEL_itoa(p, remain, devix);
+ p += x;
+ remain -= x;
+ chars += x;
+ VBUSCHANNEL_ADDACHAR(']', p, remain, chars);
+ } else {
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ }
+
+ /* emit device type */
+ x = VBUSCHANNEL_sanitize_buffer(p, remain, psrc, nsrc);
+ p += x;
+ remain -= x;
+ chars += x;
+ pad = 15 - x; /* pad device type to be exactly 15 chars */
+ for (i = 0; i < pad; i++)
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+
+ /* emit driver name */
+ psrc = &(devInfo->drvName[0]);
+ nsrc = sizeof(devInfo->drvName);
+ x = VBUSCHANNEL_sanitize_buffer(p, remain, psrc, nsrc);
+ p += x;
+ remain -= x;
+ chars += x;
+ pad = 15 - x; /* pad driver name to be exactly 15 chars */
+ for (i = 0; i < pad; i++)
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+
+ /* emit strings */
+ psrc = &(devInfo->infoStrings[0]);
+ nsrc = sizeof(devInfo->infoStrings);
+ x = VBUSCHANNEL_sanitize_buffer(p, remain, psrc, nsrc);
+ p += x;
+ remain -= x;
+ chars += x;
+ VBUSCHANNEL_ADDACHAR('\n', p, remain, chars);
+
+ return chars;
+}
+
+#endif
diff --git a/drivers/staging/unisys/common-spar/include/version.h b/drivers/staging/unisys/common-spar/include/version.h
new file mode 100644
index 000000000000..00b0ebb09eae
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/version.h
@@ -0,0 +1,46 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* version.h */
+
+/* Common version/release info needed by all components goes here.
+ * (This file must compile cleanly in all environments.)
+ * Ultimately, this will be combined with defines generated dynamically as
+ * part of the sysgen, and some of the defines below may in fact end up
+ * being replaced with dynamically generated ones.
+ */
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+#define SPARVER1 "1"
+#define SPARVER2 "0"
+#define SPARVER3 "0"
+#define SPARVER4 "0"
+
+#define VERSION SPARVER1 "." SPARVER2 "." SPARVER3 "." SPARVER4
+#define VERSIONDATE __DATE__
+
+/* Here are various version forms needed in Windows environments.
+ */
+#define VISOR_PRODUCTVERSION SPARVERCOMMA
+#define VISOR_PRODUCTVERSION_STR SPARVER1 "." SPARVER2 "." SPARVER3 "." \
+ SPARVER4
+#define VISOR_OBJECTVERSION_STR SPARVER1 "," SPARVER2 "," SPARVER3 "," \
+ SPARVER4
+
+#define COPYRIGHT "Unisys Corporation"
+#define COPYRIGHTDATE "2010 - 2013"
+
+#endif
diff --git a/drivers/staging/unisys/common-spar/include/vmcallinterface.h b/drivers/staging/unisys/common-spar/include/vmcallinterface.h
new file mode 100644
index 000000000000..14c404367fa7
--- /dev/null
+++ b/drivers/staging/unisys/common-spar/include/vmcallinterface.h
@@ -0,0 +1,167 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __IOMONINTF_H__
+#define __IOMONINTF_H__
+
+/*
+* This file contains all structures needed to support the VMCALLs for IO
+* Virtualization. The VMCALLs are provided by Monitor and used by IO code
+* running on IO Partitions.
+*/
+
+#ifdef __GNUC__
+#include "iovmcall_gnuc.h"
+#endif /* */
+#include "diagchannel.h"
+
+#ifdef VMCALL_IO_CONTROLVM_ADDR
+#undef VMCALL_IO_CONTROLVM_ADDR
+#endif /* */
+
+/* define subsystem number for AppOS, used in uislib driver */
+#define MDS_APPOS 0x4000000000000000L /* subsystem = 62 - AppOS */
+typedef enum { /* VMCALL identification tuples */
+ /* Note: when a new VMCALL is added:
+ * - the 1st 2 hex digits correspond to one of the
+ * VMCALL_MONITOR_INTERFACE types and
+ * - the next 2 hex digits are the nth relative instance of within a
+ * type
+ * E.G. for VMCALL_VIRTPART_RECYCLE_PART,
+ * - the 0x02 identifies it as a VMCALL_VIRTPART type and
+ * - the 0x01 identifies it as the 1st instance of a VMCALL_VIRTPART
+ * type of VMCALL
+ */
+
+ VMCALL_IO_CONTROLVM_ADDR = 0x0501, /* used by all Guests, not just
+ * IO */
+ VMCALL_IO_DIAG_ADDR = 0x0508,
+ VMCALL_IO_VISORSERIAL_ADDR = 0x0509,
+ VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET = 0x0708, /* Allow caller to
+ * query virtual time
+ * offset */
+ VMCALL_CHANNEL_VERSION_MISMATCH = 0x0709,
+ VMCALL_POST_CODE_LOGEVENT = 0x070B, /* LOGEVENT Post Code (RDX) with
+ * specified subsystem mask (RCX
+ * - monitor_subsystems.h) and
+ * severity (RDX) */
+ VMCALL_GENERIC_SURRENDER_QUANTUM_FOREVER = 0x0802, /* Yield the
+ * remainder & all
+ * future quantums of
+ * the caller */
+ VMCALL_MEASUREMENT_DO_NOTHING = 0x0901,
+ VMCALL_UPDATE_PHYSICAL_TIME = 0x0a02 /* Allow
+ * ULTRA_SERVICE_CAPABILITY_TIME
+ * capable guest to make
+ * VMCALL */
+} VMCALL_MONITOR_INTERFACE_METHOD_TUPLE;
+
+#define VMCALL_SUCCESS 0
+#define VMCALL_SUCCESSFUL(result) (result == 0)
+
+#ifdef __GNUC__
+#define unisys_vmcall(tuple, reg_ebx, reg_ecx) \
+ __unisys_vmcall_gnuc(tuple, reg_ebx, reg_ecx)
+#define unisys_extended_vmcall(tuple, reg_ebx, reg_ecx, reg_edx) \
+ __unisys_extended_vmcall_gnuc(tuple, reg_ebx, reg_ecx, reg_edx)
+#define ISSUE_IO_VMCALL(InterfaceMethod, param, result) \
+ (result = unisys_vmcall(InterfaceMethod, (param) & 0xFFFFFFFF, \
+ (param) >> 32))
+#define ISSUE_IO_EXTENDED_VMCALL(InterfaceMethod, param1, param2, \
+ param3, result) \
+ (result = unisys_extended_vmcall(InterfaceMethod, param1, \
+ param2, param3))
+
+ /* The following uses VMCALL_POST_CODE_LOGEVENT interface but is currently
+ * not used much */
+#define ISSUE_IO_VMCALL_POSTCODE_SEVERITY(postcode, severity) \
+do { \
+ U32 _tempresult = VMCALL_SUCCESS; \
+ ISSUE_IO_EXTENDED_VMCALL(VMCALL_POST_CODE_LOGEVENT, severity, \
+ MDS_APPOS, postcode, _tempresult); \
+} while (0)
+#endif
+
+/* Structures for IO VMCALLs */
+
+/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
+/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
+#pragma pack(push, 1)
+struct phys_info {
+ U64 pi_pfn;
+ U16 pi_off;
+ U16 pi_len;
+};
+
+#pragma pack(pop)
+/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */
+typedef struct phys_info IO_DATA_STRUCTURE;
+
+/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
+/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
+#pragma pack(push, 1)
+/* Parameters to VMCALL_IO_CONTROLVM_ADDR interface */
+typedef struct _VMCALL_IO_CONTROLVM_ADDR_PARAMS {
+ /* The Guest-relative physical address of the ControlVm channel.
+ * This VMCall fills this in with the appropriate address. */
+ U64 ChannelAddress; /* contents provided by this VMCALL (OUT) */
+ /* the size of the ControlVm channel in bytes This VMCall fills this
+ * in with the appropriate address. */
+ U32 ChannelBytes; /* contents provided by this VMCALL (OUT) */
+ U8 Unused[4]; /* Unused Bytes in the 64-Bit Aligned Struct */
+} VMCALL_IO_CONTROLVM_ADDR_PARAMS;
+
+#pragma pack(pop)
+/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */
+
+/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
+/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
+#pragma pack(push, 1)
+/* Parameters to VMCALL_IO_DIAG_ADDR interface */
+typedef struct _VMCALL_IO_DIAG_ADDR_PARAMS {
+ /* The Guest-relative physical address of the diagnostic channel.
+ * This VMCall fills this in with the appropriate address. */
+ U64 ChannelAddress; /* contents provided by this VMCALL (OUT) */
+} VMCALL_IO_DIAG_ADDR_PARAMS;
+
+#pragma pack(pop)
+/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */
+
+/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
+/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
+#pragma pack(push, 1)
+/* Parameters to VMCALL_IO_VISORSERIAL_ADDR interface */
+typedef struct _VMCALL_IO_VISORSERIAL_ADDR_PARAMS {
+ /* The Guest-relative physical address of the serial console
+ * channel. This VMCall fills this in with the appropriate
+ * address. */
+ U64 ChannelAddress; /* contents provided by this VMCALL (OUT) */
+} VMCALL_IO_VISORSERIAL_ADDR_PARAMS;
+
+#pragma pack(pop)
+/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */
+
+/* Parameters to VMCALL_CHANNEL_MISMATCH interface */
+typedef struct _VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS {
+ U8 ChannelName[32]; /* Null terminated string giving name of channel
+ * (IN) */
+ U8 ItemName[32]; /* Null terminated string giving name of
+ * mismatched item (IN) */
+ U32 SourceLineNumber; /* line# where invoked. (IN) */
+ U8 SourceFileName[36]; /* source code where invoked - Null terminated
+ * string (IN) */
+} VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS;
+
+#endif /* __IOMONINTF_H__ */
diff --git a/drivers/staging/unisys/include/commontypes.h b/drivers/staging/unisys/include/commontypes.h
new file mode 100644
index 000000000000..ef12af4a72db
--- /dev/null
+++ b/drivers/staging/unisys/include/commontypes.h
@@ -0,0 +1,170 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef _COMMONTYPES_H_
+#define _COMMONTYPES_H_
+
+/* define the following to prevent include nesting in kernel header files of
+ * similar abreviated content */
+#define _SUPERVISOR_COMMONTYPES_H_
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/io.h>
+#else
+#include <stdint.h>
+#include <syslog.h>
+#endif
+
+#define U8 uint8_t
+#define U16 uint16_t
+#define U32 uint32_t
+#define U64 uint64_t
+#define S8 int8_t
+#define S16 int16_t
+#define S32 int32_t
+#define S64 int64_t
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_X86_32
+#define UINTN U32
+#else
+#define UINTN U64
+#endif
+
+#else
+
+#include <stdint.h>
+#if __WORDSIZE == 32
+#define UINTN U32
+#elif __WORDSIZE == 64
+#define UINTN U64
+#else
+#error Unsupported __WORDSIZE
+#endif
+
+#endif
+
+typedef struct {
+ U32 data1;
+ U16 data2;
+ U16 data3;
+ U8 data4[8];
+} __attribute__ ((__packed__)) GUID;
+
+#ifndef GUID0
+#define GUID0 {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} }
+#endif
+typedef U64 GUEST_PHYSICAL_ADDRESS;
+
+#define MEMSET(ptr, val, len) memset(ptr, val, len)
+#define MEMCMP(m1, m2, len) memcmp(m1, m2, len)
+#define MEMCMP_IO(m1, m2, len) memcmp((void __force *)m1, m2, len)
+#define STRLEN(s) ((UINTN)strlen((const char *)s))
+#define STRCPY(d, s) (strcpy((char *)d, (const char *)s))
+
+#define INLINE inline
+#define OFFSETOF offsetof
+
+#ifdef __KERNEL__
+#define MEMORYBARRIER mb()
+#define MEMCPY(dest, src, len) memcpy(dest, src, len)
+#define MEMCPY_TOIO(dest, src, len) memcpy_toio(dest, src, len)
+#define MEMCPY_FROMIO(dest, src, len) memcpy_fromio(dest, src, len)
+
+#define CHANNEL_GUID_MISMATCH(chType, chName, field, expected, actual, fil, \
+ lin, logCtx) \
+ do { \
+ char s1[50], s2[50], s3[50]; \
+ pr_err("Channel mismatch on channel=%s(%s) field=%s expected=%s actual=%s @%s:%d\n", \
+ chName, GUID_format2(&chType, s1), field, \
+ GUID_format2(&expected, s2), GUID_format2(&actual, s3), \
+ fil, lin); \
+ } while (0)
+#define CHANNEL_U32_MISMATCH(chType, chName, field, expected, actual, fil, \
+ lin, logCtx) \
+ do { \
+ char s1[50]; \
+ pr_err("Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8lx actual=0x%-8.8lx @%s:%d\n", \
+ chName, GUID_format2(&chType, s1), field, \
+ (unsigned long)expected, (unsigned long)actual, \
+ fil, lin); \
+ } while (0)
+
+#define CHANNEL_U64_MISMATCH(chType, chName, field, expected, actual, fil, \
+ lin, logCtx) \
+ do { \
+ char s1[50]; \
+ pr_err("Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8Lx actual=0x%-8.8Lx @%s:%d\n", \
+ chName, GUID_format2(&chType, s1), field, \
+ (unsigned long long)expected, \
+ (unsigned long long)actual, \
+ fil, lin); \
+ } while (0)
+
+#define UltraLogEvent(logCtx, EventId, Severity, SubsystemMask, pFunctionName, \
+ LineNumber, Str, args...) \
+ pr_info(Str, ## args)
+
+#else
+#define MEMCPY(dest, src, len) memcpy(dest, src, len)
+
+#define MEMORYBARRIER mb()
+
+#define CHANNEL_GUID_MISMATCH(chType, chName, field, expected, actual, fil, \
+ lin, logCtx) \
+ do { \
+ char s1[50], s2[50], s3[50]; \
+ syslog(LOG_USER | LOG_ERR, \
+ "Channel mismatch on channel=%s(%s) field=%s expected=%s actual=%s @%s:%d", \
+ chName, GUID_format2(&chType, s1), field, \
+ GUID_format2(&expected, s2), GUID_format2(&actual, s3), \
+ fil, lin); \
+ } while (0)
+
+#define CHANNEL_U32_MISMATCH(chType, chName, field, expected, actual, fil, \
+ lin, logCtx) \
+ do { \
+ char s1[50]; \
+ syslog(LOG_USER | LOG_ERR, \
+ "Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8lx actual=0x%-8.8lx @%s:%d", \
+ chName, GUID_format2(&chType, s1), field, \
+ (unsigned long)expected, (unsigned long)actual, \
+ fil, lin); \
+ } while (0)
+
+#define CHANNEL_U64_MISMATCH(chType, chName, field, expected, actual, fil, \
+ lin, logCtx) \
+ do { \
+ char s1[50]; \
+ syslog(LOG_USER | LOG_ERR, \
+ "Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8Lx actual=0x%-8.8Lx @%s:%d", \
+ chName, GUID_format2(&chType, s1), field, \
+ (unsigned long long)expected, \
+ (unsigned long long)actual, \
+ fil, lin); \
+ } while (0)
+
+#define UltraLogEvent(logCtx, EventId, Severity, SubsystemMask, pFunctionName, \
+ LineNumber, Str, args...) \
+ syslog(LOG_USER | LOG_INFO, Str, ## args)
+#endif
+
+#define VolatileBarrier() MEMORYBARRIER
+
+#endif
+#include "guidutils.h"
diff --git a/drivers/staging/unisys/include/guestlinuxdebug.h b/drivers/staging/unisys/include/guestlinuxdebug.h
new file mode 100644
index 000000000000..c3de8496e5d6
--- /dev/null
+++ b/drivers/staging/unisys/include/guestlinuxdebug.h
@@ -0,0 +1,182 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __GUESTLINUXDEBUG_H__
+#define __GUESTLINUXDEBUG_H__
+
+/*
+* This file contains supporting interface for "vmcallinterface.h", particuarly
+* regarding adding additional structure and functionality to linux
+* ISSUE_IO_VMCALL_POSTCODE_SEVERITY */
+
+
+/******* INFO ON ISSUE_POSTCODE_LINUX() BELOW *******/
+#include "vmcallinterface.h"
+typedef enum { /* POSTCODE driver identifier tuples */
+ /* visorchipset driver files */
+ VISOR_CHIPSET_PC = 0xA0,
+ VISOR_CHIPSET_PC_controlvm_c = 0xA1,
+ VISOR_CHIPSET_PC_controlvm_cm2 = 0xA2,
+ VISOR_CHIPSET_PC_controlvm_direct_c = 0xA3,
+ VISOR_CHIPSET_PC_file_c = 0xA4,
+ VISOR_CHIPSET_PC_parser_c = 0xA5,
+ VISOR_CHIPSET_PC_testing_c = 0xA6,
+ VISOR_CHIPSET_PC_visorchipset_main_c = 0xA7,
+ VISOR_CHIPSET_PC_visorswitchbus_c = 0xA8,
+ /* visorbus driver files */
+ VISOR_BUS_PC = 0xB0,
+ VISOR_BUS_PC_businst_attr_c = 0xB1,
+ VISOR_BUS_PC_channel_attr_c = 0xB2,
+ VISOR_BUS_PC_devmajorminor_attr_c = 0xB3,
+ VISOR_BUS_PC_visorbus_main_c = 0xB4,
+ /* visorclientbus driver files */
+ VISOR_CLIENT_BUS_PC = 0xC0,
+ VISOR_CLIENT_BUS_PC_visorclientbus_main_c = 0xC1,
+ /* virt hba driver files */
+ VIRT_HBA_PC = 0xC2,
+ VIRT_HBA_PC_virthba_c = 0xC3,
+ /* virtpci driver files */
+ VIRT_PCI_PC = 0xC4,
+ VIRT_PCI_PC_virtpci_c = 0xC5,
+ /* virtnic driver files */
+ VIRT_NIC_PC = 0xC6,
+ VIRT_NIC_P_virtnic_c = 0xC7,
+ /* uislib driver files */
+ UISLIB_PC = 0xD0,
+ UISLIB_PC_uislib_c = 0xD1,
+ UISLIB_PC_uisqueue_c = 0xD2,
+ UISLIB_PC_uisthread_c = 0xD3,
+ UISLIB_PC_uisutils_c = 0xD4,
+} DRIVER_PC;
+
+typedef enum { /* POSTCODE event identifier tuples */
+ ATTACH_PORT_ENTRY_PC = 0x001,
+ ATTACH_PORT_FAILURE_PC = 0x002,
+ ATTACH_PORT_SUCCESS_PC = 0x003,
+ BUS_FAILURE_PC = 0x004,
+ BUS_CREATE_ENTRY_PC = 0x005,
+ BUS_CREATE_FAILURE_PC = 0x006,
+ BUS_CREATE_EXIT_PC = 0x007,
+ BUS_CONFIGURE_ENTRY_PC = 0x008,
+ BUS_CONFIGURE_FAILURE_PC = 0x009,
+ BUS_CONFIGURE_EXIT_PC = 0x00A,
+ CHIPSET_INIT_ENTRY_PC = 0x00B,
+ CHIPSET_INIT_SUCCESS_PC = 0x00C,
+ CHIPSET_INIT_FAILURE_PC = 0x00D,
+ CHIPSET_INIT_EXIT_PC = 0x00E,
+ CREATE_WORKQUEUE_PC = 0x00F,
+ CREATE_WORKQUEUE_FAILED_PC = 0x0A0,
+ CONTROLVM_INIT_FAILURE_PC = 0x0A1,
+ DEVICE_CREATE_ENTRY_PC = 0x0A2,
+ DEVICE_CREATE_FAILURE_PC = 0x0A3,
+ DEVICE_CREATE_SUCCESS_PC = 0x0A4,
+ DEVICE_CREATE_EXIT_PC = 0x0A5,
+ DEVICE_ADD_PC = 0x0A6,
+ DEVICE_REGISTER_FAILURE_PC = 0x0A7,
+ DEVICE_CHANGESTATE_ENTRY_PC = 0x0A8,
+ DEVICE_CHANGESTATE_FAILURE_PC = 0x0A9,
+ DEVICE_CHANGESTATE_EXIT_PC = 0x0AA,
+ DRIVER_ENTRY_PC = 0x0AB,
+ DRIVER_EXIT_PC = 0x0AC,
+ MALLOC_FAILURE_PC = 0x0AD,
+ QUEUE_DELAYED_WORK_PC = 0x0AE,
+ UISLIB_THREAD_FAILURE_PC = 0x0B7,
+ VBUS_CHANNEL_ENTRY_PC = 0x0B8,
+ VBUS_CHANNEL_FAILURE_PC = 0x0B9,
+ VBUS_CHANNEL_EXIT_PC = 0x0BA,
+ VHBA_CREATE_ENTRY_PC = 0x0BB,
+ VHBA_CREATE_FAILURE_PC = 0x0BC,
+ VHBA_CREATE_EXIT_PC = 0x0BD,
+ VHBA_CREATE_SUCCESS_PC = 0x0BE,
+ VHBA_COMMAND_HANDLER_PC = 0x0BF,
+ VHBA_PROBE_ENTRY_PC = 0x0C0,
+ VHBA_PROBE_FAILURE_PC = 0x0C1,
+ VHBA_PROBE_EXIT_PC = 0x0C2,
+ VNIC_CREATE_ENTRY_PC = 0x0C3,
+ VNIC_CREATE_FAILURE_PC = 0x0C4,
+ VNIC_CREATE_SUCCESS_PC = 0x0C5,
+ VNIC_PROBE_ENTRY_PC = 0x0C6,
+ VNIC_PROBE_FAILURE_PC = 0x0C7,
+ VNIC_PROBE_EXIT_PC = 0x0C8,
+ VPCI_CREATE_ENTRY_PC = 0x0C9,
+ VPCI_CREATE_FAILURE_PC = 0x0CA,
+ VPCI_CREATE_EXIT_PC = 0x0CB,
+ VPCI_PROBE_ENTRY_PC = 0x0CC,
+ VPCI_PROBE_FAILURE_PC = 0x0CD,
+ VPCI_PROBE_EXIT_PC = 0x0CE,
+ CRASH_DEV_ENTRY_PC = 0x0CF,
+ CRASH_DEV_EXIT_PC = 0x0D0,
+ CRASH_DEV_HADDR_NULL = 0x0D1,
+ CRASH_DEV_CONTROLVM_NULL = 0x0D2,
+ CRASH_DEV_RD_BUS_FAIULRE_PC = 0x0D3,
+ CRASH_DEV_RD_DEV_FAIULRE_PC = 0x0D4,
+ CRASH_DEV_BUS_NULL_FAILURE_PC = 0x0D5,
+ CRASH_DEV_DEV_NULL_FAILURE_PC = 0x0D6,
+ CRASH_DEV_CTRL_RD_FAILURE_PC = 0x0D7,
+ CRASH_DEV_COUNT_FAILURE_PC = 0x0D8,
+ SAVE_MSG_BUS_FAILURE_PC = 0x0D9,
+ SAVE_MSG_DEV_FAILURE_PC = 0x0DA,
+ CALLHOME_INIT_FAILURE_PC = 0x0DB
+} EVENT_PC;
+
+#ifdef __GNUC__
+
+#define POSTCODE_SEVERITY_ERR DIAG_SEVERITY_ERR
+#define POSTCODE_SEVERITY_WARNING DIAG_SEVERITY_WARNING
+#define POSTCODE_SEVERITY_INFO DIAG_SEVERITY_PRINT /* TODO-> Info currently
+ * doesnt show, so we
+ * set info=warning */
+/* example call of POSTCODE_LINUX_2(VISOR_CHIPSET_PC, POSTCODE_SEVERITY_ERR);
+ * Please also note that the resulting postcode is in hex, so if you are
+ * searching for the __LINE__ number, convert it first to decimal. The line
+ * number combined with driver and type of call, will allow you to track down
+ * exactly what line an error occured on, or where the last driver
+ * entered/exited from.
+ */
+
+/* BASE FUNCTIONS */
+#define POSTCODE_LINUX_A(DRIVER_PC, EVENT_PC, pc32bit, severity) \
+do { \
+ unsigned long long post_code_temp; \
+ post_code_temp = (((U64)DRIVER_PC) << 56) | (((U64)EVENT_PC) << 44) | \
+ ((((U64)__LINE__) & 0xFFF) << 32) | \
+ (((U64)pc32bit) & 0xFFFFFFFF); \
+ ISSUE_IO_VMCALL_POSTCODE_SEVERITY(post_code_temp, severity); \
+} while (0)
+
+#define POSTCODE_LINUX_B(DRIVER_PC, EVENT_PC, pc16bit1, pc16bit2, severity) \
+do { \
+ unsigned long long post_code_temp; \
+ post_code_temp = (((U64)DRIVER_PC) << 56) | (((U64)EVENT_PC) << 44) | \
+ ((((U64)__LINE__) & 0xFFF) << 32) | \
+ ((((U64)pc16bit1) & 0xFFFF) << 16) | \
+ (((U64)pc16bit2) & 0xFFFF); \
+ ISSUE_IO_VMCALL_POSTCODE_SEVERITY(post_code_temp, severity); \
+} while (0)
+
+/* MOST COMMON */
+#define POSTCODE_LINUX_2(EVENT_PC, severity) \
+ POSTCODE_LINUX_A(CURRENT_FILE_PC, EVENT_PC, 0x0000, severity);
+
+#define POSTCODE_LINUX_3(EVENT_PC, pc32bit, severity) \
+ POSTCODE_LINUX_A(CURRENT_FILE_PC, EVENT_PC, pc32bit, severity);
+
+
+#define POSTCODE_LINUX_4(EVENT_PC, pc16bit1, pc16bit2, severity) \
+ POSTCODE_LINUX_B(CURRENT_FILE_PC, EVENT_PC, pc16bit1, \
+ pc16bit2, severity);
+
+#endif
+#endif
diff --git a/drivers/staging/unisys/include/guidutils.h b/drivers/staging/unisys/include/guidutils.h
new file mode 100644
index 000000000000..75caf929cd6d
--- /dev/null
+++ b/drivers/staging/unisys/include/guidutils.h
@@ -0,0 +1,203 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* guidutils.h
+ *
+ * These are GUID manipulation inlines that can be used from either
+ * kernel-mode or user-mode.
+ *
+ */
+#ifndef __GUIDUTILS_H__
+#define __GUIDUTILS_H__
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#define GUID_STRTOUL kstrtoul
+#else
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define GUID_STRTOUL strtoul
+#endif
+
+static inline char *
+GUID_format1(const GUID *guid, char *s)
+{
+ sprintf(s, "{%-8.8lx-%-4.4x-%-4.4x-%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x}",
+ (ulong) guid->data1,
+ guid->data2,
+ guid->data3,
+ guid->data4[0],
+ guid->data4[1],
+ guid->data4[2],
+ guid->data4[3],
+ guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]);
+ return s;
+}
+
+/** Format a GUID in Microsoft's 'what in the world were they thinking'
+ * format.
+ */
+static inline char *
+GUID_format2(const GUID *guid, char *s)
+{
+ sprintf(s, "{%-8.8lx-%-4.4x-%-4.4x-%-2.2x%-2.2x-%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x}",
+ (ulong) guid->data1,
+ guid->data2,
+ guid->data3,
+ guid->data4[0],
+ guid->data4[1],
+ guid->data4[2],
+ guid->data4[3],
+ guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]);
+ return s;
+}
+
+/**
+ * Like GUID_format2 but without the curly braces and the
+ * hex digits in upper case
+ */
+static inline char *
+GUID_format3(const GUID *guid, char *s)
+{
+ sprintf(s, "%-8.8lX-%-4.4X-%-4.4X-%-2.2X%-2.2X-%-2.2X%-2.2X%-2.2X%-2.2X%-2.2X%-2.2X",
+ (ulong) guid->data1,
+ guid->data2,
+ guid->data3,
+ guid->data4[0],
+ guid->data4[1],
+ guid->data4[2],
+ guid->data4[3],
+ guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]);
+ return s;
+}
+
+/** Parse a guid string in any of these forms:
+ * {11111111-2222-3333-4455-66778899aabb}
+ * {11111111-2222-3333-445566778899aabb}
+ * 11111111-2222-3333-4455-66778899aabb
+ * 11111111-2222-3333-445566778899aabb
+ */
+static inline GUID
+GUID_scan(U8 *p)
+{
+ GUID guid = GUID0;
+ U8 x[33];
+ int count = 0;
+ int c, i = 0;
+ U8 cdata1[9];
+ U8 cdata2[5];
+ U8 cdata3[5];
+ U8 cdata4[3];
+ int dashcount = 0;
+ int brace = 0;
+ unsigned long uldata;
+
+ if (!p)
+ return guid;
+ if (*p == '{') {
+ p++;
+ brace = 1;
+ }
+ while (count < 32) {
+ if (*p == '}')
+ return guid;
+ if (*p == '\0')
+ return guid;
+ c = toupper(*p);
+ p++;
+ if (c == '-') {
+ switch (dashcount) {
+ case 0:
+ if (i != 8)
+ return guid;
+ break;
+ case 1:
+ if (i != 4)
+ return guid;
+ break;
+ case 2:
+ if (i != 4)
+ return guid;
+ break;
+ case 3:
+ if (i != 4)
+ return guid;
+ break;
+ default:
+ return guid;
+ }
+ dashcount++;
+ i = 0;
+ continue;
+ }
+ if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))
+ i++;
+ else
+ return guid;
+ x[count++] = c;
+ }
+ x[count] = '\0';
+ if (brace) {
+ if (*p == '}')
+ p++;
+ else
+ return guid;
+ }
+ if (dashcount == 3 || dashcount == 4)
+ ;
+ else
+ return guid;
+ memset(cdata1, 0, sizeof(cdata1));
+ memset(cdata2, 0, sizeof(cdata2));
+ memset(cdata3, 0, sizeof(cdata3));
+ memset(cdata4, 0, sizeof(cdata4));
+ memcpy(cdata1, x + 0, 8);
+ memcpy(cdata2, x + 8, 4);
+ memcpy(cdata3, x + 12, 4);
+
+ if (GUID_STRTOUL((char *) cdata1, 16, &uldata) == 0)
+ guid.data1 = (U32)uldata;
+ if (GUID_STRTOUL((char *) cdata2, 16, &uldata) == 0)
+ guid.data2 = (U16)uldata;
+ if (GUID_STRTOUL((char *) cdata3, 16, &uldata) == 0)
+ guid.data3 = (U16)uldata;
+
+ for (i = 0; i < 8; i++) {
+ memcpy(cdata4, x + 16 + (i * 2), 2);
+ if (GUID_STRTOUL((char *) cdata4, 16, &uldata) == 0)
+ guid.data4[i] = (U8) uldata;
+ }
+
+ return guid;
+}
+
+static inline char *
+GUID_sanitize(char *inputGuidStr, char *outputGuidStr)
+{
+ GUID g;
+ GUID guid0 = GUID0;
+ *outputGuidStr = '\0';
+ g = GUID_scan((U8 *) inputGuidStr);
+ if (memcmp(&g, &guid0, sizeof(GUID)) == 0)
+ return outputGuidStr; /* bad GUID format */
+ return GUID_format1(&g, outputGuidStr);
+}
+
+#endif
diff --git a/drivers/staging/unisys/include/periodic_work.h b/drivers/staging/unisys/include/periodic_work.h
new file mode 100644
index 000000000000..6c7190bdcd66
--- /dev/null
+++ b/drivers/staging/unisys/include/periodic_work.h
@@ -0,0 +1,40 @@
+/* periodic_work.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __PERIODIC_WORK_H__
+#define __PERIODIC_WORK_H__
+
+#include "timskmod.h"
+
+
+
+/* PERIODIC_WORK an opaque structure to users.
+ * Fields are declared only in the implementation .c files.
+ */
+typedef struct PERIODIC_WORK_Tag PERIODIC_WORK;
+
+PERIODIC_WORK *visor_periodic_work_create(ulong jiffy_interval,
+ struct workqueue_struct *workqueue,
+ void (*workfunc)(void *),
+ void *workfuncarg,
+ const char *devnam);
+void visor_periodic_work_destroy(PERIODIC_WORK *periodic_work);
+BOOL visor_periodic_work_nextperiod(PERIODIC_WORK *periodic_work);
+BOOL visor_periodic_work_start(PERIODIC_WORK *periodic_work);
+BOOL visor_periodic_work_stop(PERIODIC_WORK *periodic_work);
+
+#endif
diff --git a/drivers/staging/unisys/include/procobjecttree.h b/drivers/staging/unisys/include/procobjecttree.h
new file mode 100644
index 000000000000..c81d11287e68
--- /dev/null
+++ b/drivers/staging/unisys/include/procobjecttree.h
@@ -0,0 +1,48 @@
+/* procobjecttree.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/** @file *********************************************************************
+ *
+ * This describes the interfaces necessary for creating a tree of types,
+ * objects, and properties in /proc.
+ *
+ ******************************************************************************
+ */
+
+#ifndef __PROCOBJECTTREE_H__
+#define __PROCOBJECTTREE_H__
+
+#include "uniklog.h"
+#include "timskmod.h"
+
+/* These are opaque structures to users.
+ * Fields are declared only in the implementation .c files.
+ */
+typedef struct MYPROCOBJECT_Tag MYPROCOBJECT;
+typedef struct MYPROCTYPE_Tag MYPROCTYPE;
+
+MYPROCOBJECT *visor_proc_CreateObject(MYPROCTYPE *type, const char *name,
+ void *context);
+void visor_proc_DestroyObject(MYPROCOBJECT *obj);
+MYPROCTYPE *visor_proc_CreateType(struct proc_dir_entry *procRootDir,
+ const char **name,
+ const char **propertyNames,
+ void (*show_property)(struct seq_file *,
+ void *, int));
+void visor_proc_DestroyType(MYPROCTYPE *type);
+
+#endif
diff --git a/drivers/staging/unisys/include/sparstop.h b/drivers/staging/unisys/include/sparstop.h
new file mode 100644
index 000000000000..3603ac607643
--- /dev/null
+++ b/drivers/staging/unisys/include/sparstop.h
@@ -0,0 +1,30 @@
+/* sparstop.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __SPARSTOP_H__
+#define __SPARSTOP_H__
+
+#include "timskmod.h"
+#include "version.h"
+#include <linux/ctype.h>
+
+typedef void (*SPARSTOP_COMPLETE_FUNC) (void *context, int status);
+
+int sp_stop(void *context, SPARSTOP_COMPLETE_FUNC get_complete_func);
+void test_remove_stop_device(void);
+
+#endif
diff --git a/drivers/staging/unisys/include/timskmod.h b/drivers/staging/unisys/include/timskmod.h
new file mode 100644
index 000000000000..5fd5ad514464
--- /dev/null
+++ b/drivers/staging/unisys/include/timskmod.h
@@ -0,0 +1,324 @@
+/* timskmod.h
+ *
+ * Copyright � 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __TIMSKMOD_H__
+#define __TIMSKMOD_H__
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <linux/cdev.h>
+#include <linux/types.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <asm/dma.h>
+#include <linux/uaccess.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+/* #define EXPORT_SYMTAB */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/fcntl.h>
+#include <linux/aio.h>
+#include <linux/workqueue.h>
+#include <linux/kthread.h>
+#include <linux/seq_file.h>
+#include <linux/mm.h>
+
+/* #define DEBUG */
+#ifndef BOOL
+#define BOOL int
+#endif
+#define FALSE 0
+#define TRUE 1
+#if !defined SUCCESS
+#define SUCCESS 0
+#endif
+#define FAILURE (-1)
+#define DRIVERNAMEMAX 50
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define STRUCTSEQUAL(x, y) (memcmp(&x, &y, sizeof(x)) == 0)
+#ifndef HOSTADDRESS
+#define HOSTADDRESS unsigned long long
+#endif
+
+typedef long VMMIO; /**< Virtual MMIO address (returned from ioremap), which
+ * is a virtual address pointer to a memory-mapped region.
+ * These are declared as "long" instead of u32* to force you to
+ * use readb()/writeb()/memcpy_fromio()/etc to access them.
+ * (On x86 we could probably get away with treating them as
+ * pointers.)
+ */
+typedef long VMMIO8; /**< #VMMIO pointing to 8-bit data */
+typedef long VMMIO16;/**< #VMMIO pointing to 16-bit data */
+typedef long VMMIO32;/**< #VMMIO pointing to 32-bit data */
+
+#define LOCKSEM(sem) down_interruptible(sem)
+#define LOCKSEM_UNINTERRUPTIBLE(sem) down(sem)
+#define UNLOCKSEM(sem) up(sem)
+
+/** lock read/write semaphore for reading.
+ Note that all read/write semaphores are of the "uninterruptible" variety.
+ @param sem (rw_semaphore *) points to semaphore to lock
+ */
+#define LOCKREADSEM(sem) down_read(sem)
+
+/** unlock read/write semaphore for reading.
+ Note that all read/write semaphores are of the "uninterruptible" variety.
+ @param sem (rw_semaphore *) points to semaphore to unlock
+ */
+#define UNLOCKREADSEM(sem) up_read(sem)
+
+/** lock read/write semaphore for writing.
+ Note that all read/write semaphores are of the "uninterruptible" variety.
+ @param sem (rw_semaphore *) points to semaphore to lock
+ */
+#define LOCKWRITESEM(sem) down_write(sem)
+
+/** unlock read/write semaphore for writing.
+ Note that all read/write semaphores are of the "uninterruptible" variety.
+ @param sem (rw_semaphore *) points to semaphore to unlock
+ */
+#define UNLOCKWRITESEM(sem) up_write(sem)
+
+#ifdef ENABLE_RETURN_TRACE
+#define RETTRACE(x) \
+ do { \
+ if (1) { \
+ INFODRV("RET 0x%lx in %s", \
+ (ulong)(x), __func__); \
+ } \
+ } while (0)
+#else
+#define RETTRACE(x)
+#endif
+
+/** Try to evaulate the provided expression, and do a RETINT(x) iff
+ * the expression evaluates to < 0.
+ * @param x the expression to try
+ */
+#define ASSERT(cond) \
+ do { if (!(cond)) \
+ HUHDRV("ASSERT failed - %s", \
+ __stringify(cond)); \
+ } while (0)
+
+#define sizeofmember(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER))
+/** "Covered quotient" function */
+#define COVQ(v, d) (((v) + (d) - 1) / (d))
+#define SWAPPOINTERS(p1, p2) \
+ do { \
+ void *SWAPPOINTERS_TEMP = (void *)p1; \
+ (void *)(p1) = (void *)(p2); \
+ (void *)(p2) = SWAPPOINTERS_TEMP; \
+ } while (0)
+
+/**
+ * @addtogroup driverlogging
+ * @{
+ */
+
+#define PRINTKDRV(fmt, args...) LOGINF(fmt, ## args)
+#define TBDDRV(fmt, args...) LOGERR(fmt, ## args)
+#define HUHDRV(fmt, args...) LOGERR(fmt, ## args)
+#define ERRDRV(fmt, args...) LOGERR(fmt, ## args)
+#define WARNDRV(fmt, args...) LOGWRN(fmt, ## args)
+#define SECUREDRV(fmt, args...) LOGWRN(fmt, ## args)
+#define INFODRV(fmt, args...) LOGINF(fmt, ## args)
+#define DEBUGDRV(fmt, args...) DBGINF(fmt, ## args)
+
+#define PRINTKDEV(devname, fmt, args...) LOGINFDEV(devname, fmt, ## args)
+#define TBDDEV(devname, fmt, args...) LOGERRDEV(devname, fmt, ## args)
+#define HUHDEV(devname, fmt, args...) LOGERRDEV(devname, fmt, ## args)
+#define ERRDEV(devname, fmt, args...) LOGERRDEV(devname, fmt, ## args)
+#define ERRDEVX(devno, fmt, args...) LOGERRDEVX(devno, fmt, ## args)
+#define WARNDEV(devname, fmt, args...) LOGWRNDEV(devname, fmt, ## args)
+#define SECUREDEV(devname, fmt, args...) LOGWRNDEV(devname, fmt, ## args)
+#define INFODEV(devname, fmt, args...) LOGINFDEV(devname, fmt, ## args)
+#define INFODEVX(devno, fmt, args...) LOGINFDEVX(devno, fmt, ## args)
+#define DEBUGDEV(devname, fmt, args...) DBGINFDEV(devname, fmt, ## args)
+
+
+/* @} */
+
+/** Verifies the consistency of your PRIVATEDEVICEDATA structure using
+ * conventional "signature" fields:
+ * <p>
+ * - sig1 should contain the size of the structure
+ * - sig2 should contain a pointer to the beginning of the structure
+ */
+#define DDLOOKSVALID(dd) \
+ ((dd != NULL) && \
+ ((dd)->sig1 == sizeof(PRIVATEDEVICEDATA)) && \
+ ((dd)->sig2 == dd))
+
+/** Verifies the consistency of your PRIVATEFILEDATA structure using
+ * conventional "signature" fields:
+ * <p>
+ * - sig1 should contain the size of the structure
+ * - sig2 should contain a pointer to the beginning of the structure
+ */
+#define FDLOOKSVALID(fd) \
+ ((fd != NULL) && \
+ ((fd)->sig1 == sizeof(PRIVATEFILEDATA)) && \
+ ((fd)->sig2 == fd))
+
+/** Locks dd->lockDev if you havn't already locked it */
+#define LOCKDEV(dd) \
+ { \
+ if (!lockedDev) { \
+ spin_lock(&dd->lockDev); \
+ lockedDev = TRUE; \
+ } \
+ }
+
+/** Unlocks dd->lockDev if you previously locked it */
+#define UNLOCKDEV(dd) \
+ { \
+ if (lockedDev) { \
+ spin_unlock(&dd->lockDev); \
+ lockedDev = FALSE; \
+ } \
+ }
+
+/** Locks dd->lockDevISR if you havn't already locked it */
+#define LOCKDEVISR(dd) \
+ { \
+ if (!lockedDevISR) { \
+ spin_lock_irqsave(&dd->lockDevISR, flags); \
+ lockedDevISR = TRUE; \
+ } \
+ }
+
+/** Unlocks dd->lockDevISR if you previously locked it */
+#define UNLOCKDEVISR(dd) \
+ { \
+ if (lockedDevISR) { \
+ spin_unlock_irqrestore(&dd->lockDevISR, flags); \
+ lockedDevISR = FALSE; \
+ } \
+ }
+
+/** Locks LockGlobalISR if you havn't already locked it */
+#define LOCKGLOBALISR \
+ { \
+ if (!lockedGlobalISR) { \
+ spin_lock_irqsave(&LockGlobalISR, flags); \
+ lockedGlobalISR = TRUE; \
+ } \
+ }
+
+/** Unlocks LockGlobalISR if you previously locked it */
+#define UNLOCKGLOBALISR \
+ { \
+ if (lockedGlobalISR) { \
+ spin_unlock_irqrestore(&LockGlobalISR, flags); \
+ lockedGlobalISR = FALSE; \
+ } \
+ }
+
+/** Locks LockGlobal if you havn't already locked it */
+#define LOCKGLOBAL \
+ { \
+ if (!lockedGlobal) { \
+ spin_lock(&LockGlobal); \
+ lockedGlobal = TRUE; \
+ } \
+ }
+
+/** Unlocks LockGlobal if you previously locked it */
+#define UNLOCKGLOBAL \
+ { \
+ if (lockedGlobal) { \
+ spin_unlock(&LockGlobal); \
+ lockedGlobal = FALSE; \
+ } \
+ }
+
+/** Use this at the beginning of functions where you intend to
+ * use #LOCKDEV/#UNLOCKDEV, #LOCKDEVISR/#UNLOCKDEVISR,
+ * #LOCKGLOBAL/#UNLOCKGLOBAL, #LOCKGLOBALISR/#UNLOCKGLOBALISR.
+ *
+ * Note that __attribute__((unused)) is how you tell GNU C to suppress
+ * any warning messages about the variable being unused.
+ */
+#define LOCKPREAMBLE \
+ ulong flags __attribute__((unused)) = 0; \
+ BOOL lockedDev __attribute__((unused)) = FALSE; \
+ BOOL lockedDevISR __attribute__((unused)) = FALSE; \
+ BOOL lockedGlobal __attribute__((unused)) = FALSE; \
+ BOOL lockedGlobalISR __attribute__((unused)) = FALSE
+
+
+
+/** Sleep for an indicated number of seconds (for use in kernel mode).
+ * @param x the number of seconds to sleep.
+ */
+#define SLEEP(x) \
+ do { current->state = TASK_INTERRUPTIBLE; \
+ schedule_timeout((x)*HZ); \
+ } while (0)
+
+/** Sleep for an indicated number of jiffies (for use in kernel mode).
+ * @param x the number of jiffies to sleep.
+ */
+#define SLEEPJIFFIES(x) \
+ do { current->state = TASK_INTERRUPTIBLE; \
+ schedule_timeout(x); \
+ } while (0)
+
+#ifndef max
+#define max(a, b) (((a) > (b)) ? (a):(b))
+#endif
+
+static inline struct cdev *cdev_alloc_init(struct module *owner,
+ const struct file_operations *fops)
+{
+ struct cdev *cdev = NULL;
+ cdev = cdev_alloc();
+ if (!cdev)
+ return NULL;
+ cdev->ops = fops;
+ cdev->owner = owner;
+
+ /* Note that the memory allocated for cdev will be deallocated
+ * when the usage count drops to 0, because it is controlled
+ * by a kobject of type ktype_cdev_dynamic. (This
+ * deallocation could very well happen outside of our kernel
+ * module, like via the cdev_put in __fput() for example.)
+ */
+ return cdev;
+}
+
+#include "timskmodutils.h"
+
+#endif
diff --git a/drivers/staging/unisys/include/timskmodutils.h b/drivers/staging/unisys/include/timskmodutils.h
new file mode 100644
index 000000000000..2d81d46bf11e
--- /dev/null
+++ b/drivers/staging/unisys/include/timskmodutils.h
@@ -0,0 +1,75 @@
+/* timskmodutils.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __TIMSKMODUTILS_H__
+#define __TIMSKMODUTILS_H__
+
+#include "timskmod.h"
+
+void *kmalloc_kernel(size_t siz);
+void myprintk(const char *myDrvName, const char *devname,
+ const char *template, ...);
+
+/*--------------------------------*
+ *--- GENERAL MESSAGEQ STUFF ---*
+ *--------------------------------*/
+
+struct MessageQEntry;
+
+/** the data structure used to hold an arbitrary data item that you want
+ * to place on a #MESSAGEQ. Declare and initialize as follows:
+ *
+ * This structure should be considered opaque; the client using it should
+ * never access the fields directly.
+ * Refer to these functions for more info:
+ *
+ * @ingroup messageq
+ */
+typedef struct MessageQEntry {
+ void *data;
+ struct MessageQEntry *qNext;
+ struct MessageQEntry *qPrev;
+} MESSAGEQENTRY;
+
+/** the data structure used to hold a FIFO queue of #MESSAGEQENTRY<b></b>s.
+ * Declare and initialize as follows:
+ * @code
+ * MESSAGEQ myQueue;
+ * @endcode
+ * This structure should be considered opaque; the client using it should
+ * never access the fields directly.
+ * Refer to these functions for more info:
+ *
+ * @ingroup messageq
+ */
+typedef struct MessageQ {
+ MESSAGEQENTRY *qHead;
+ MESSAGEQENTRY *qTail;
+ struct semaphore nQEntries;
+ spinlock_t queueLock;
+} MESSAGEQ;
+
+char *cyclesToSeconds(u64 cycles, u64 cyclesPerSecond,
+ char *buf, size_t bufsize);
+char *cyclesToIterationSeconds(u64 cycles, u64 cyclesPerSecond,
+ u64 iterations, char *buf, size_t bufsize);
+char *cyclesToSomethingsPerSecond(u64 cycles, u64 cyclesPerSecond,
+ u64 somethings, char *buf, size_t bufsize);
+struct seq_file *visor_seq_file_new_buffer(void *buf, size_t buf_size);
+void visor_seq_file_done_buffer(struct seq_file *m);
+
+#endif
diff --git a/drivers/staging/unisys/include/uisqueue.h b/drivers/staging/unisys/include/uisqueue.h
new file mode 100644
index 000000000000..6dab3900994a
--- /dev/null
+++ b/drivers/staging/unisys/include/uisqueue.h
@@ -0,0 +1,440 @@
+/* uisqueue.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * Unisys IO Virtualization header NOTE: This file contains only Linux
+ * specific structs. All OS-independent structs are in iochannel.h.xx
+ */
+
+#ifndef __UISQUEUE_H__
+#define __UISQUEUE_H__
+
+#include "linux/version.h"
+#include "iochannel.h"
+#include "uniklog.h"
+#include <linux/atomic.h>
+#include <linux/semaphore.h>
+
+#include "controlvmchannel.h"
+#include "controlvmcompletionstatus.h"
+
+struct uisqueue_info {
+
+ CHANNEL_HEADER __iomem *chan;
+ /* channel containing queues in which scsi commands &
+ * responses are queued
+ */
+ U64 packets_sent;
+ U64 packets_received;
+ U64 interrupts_sent;
+ U64 interrupts_received;
+ U64 max_not_empty_cnt;
+ U64 total_wakeup_cnt;
+ U64 non_empty_wakeup_cnt;
+
+ struct {
+ SIGNAL_QUEUE_HEADER Reserved1; /* */
+ SIGNAL_QUEUE_HEADER Reserved2; /* */
+ } safe_uis_queue;
+ unsigned int (*send_int_if_needed)(struct uisqueue_info *info,
+ unsigned int whichcqueue,
+ unsigned char issueInterruptIfEmpty,
+ U64 interruptHandle,
+ unsigned char io_termination);
+};
+
+/* uisqueue_put_cmdrsp_with_lock_client queues a commmand or response
+ * to the specified queue, at the tail if the queue is full but
+ * oktowait == 0, then it return 0 indicating failure. otherwise it
+ * wait for the queue to become non-full. If command is queued, return
+ * 1 for success.
+ */
+#define DONT_ISSUE_INTERRUPT 0
+#define ISSUE_INTERRUPT 1
+
+#define DONT_WAIT 0
+#define OK_TO_WAIT 1
+#define UISLIB_LOCK_PREFIX \
+ ".section .smp_locks,\"a\"\n" \
+ _ASM_ALIGN "\n" \
+ _ASM_PTR "661f\n" /* address */ \
+ ".previous\n" \
+ "661:\n\tlock; "
+
+unsigned long long uisqueue_InterlockedOr(unsigned long long __iomem *Target,
+ unsigned long long Set);
+unsigned long long uisqueue_InterlockedAnd(unsigned long long __iomem *Target,
+ unsigned long long Set);
+
+unsigned int uisqueue_send_int_if_needed(struct uisqueue_info *pqueueinfo,
+ unsigned int whichqueue,
+ unsigned char issueInterruptIfEmpty,
+ U64 interruptHandle,
+ unsigned char io_termination);
+
+int uisqueue_put_cmdrsp_with_lock_client(struct uisqueue_info *queueinfo,
+ struct uiscmdrsp *cmdrsp,
+ unsigned int queue,
+ void *insertlock,
+ unsigned char issueInterruptIfEmpty,
+ U64 interruptHandle,
+ char oktowait,
+ U8 *channelId);
+
+/* uisqueue_get_cmdrsp gets the cmdrsp entry at the head of the queue
+ * and copies it to the area pointed by cmdrsp param.
+ * returns 0 if queue is empty, 1 otherwise
+ */
+int
+
+uisqueue_get_cmdrsp(struct uisqueue_info *queueinfo, void *cmdrsp,
+ unsigned int queue);
+
+#define MAX_NAME_SIZE_UISQUEUE 64
+
+struct extport_info {
+ U8 valid:1;
+ /* if 1, indicates this extport slot is occupied
+ * if 0, indicates that extport slot is unoccupied */
+
+ U32 num_devs_using;
+ /* When extport is added, this is set to 0. For exports
+ * located in NETWORK switches:
+ * Each time a VNIC, i.e., intport, is added to the switch this
+ * is used to assign a pref_pnic for the VNIC and when assigned
+ * to a VNIC this counter is incremented. When a VNIC is
+ * deleted, the extport corresponding to the VNIC's pref_pnic
+ * is located and its num_devs_using is decremented. For VNICs,
+ * num_devs_using is basically used to load-balance transmit
+ * traffic from VNICs.
+ */
+
+ struct switch_info *swtch;
+ struct PciId pci_id;
+ char name[MAX_NAME_SIZE_UISQUEUE];
+ union {
+ struct vhba_wwnn wwnn;
+ unsigned char macaddr[MAX_MACADDR_LEN];
+ };
+};
+
+struct device_info {
+ void __iomem *chanptr;
+ U64 channelAddr;
+ U64 channelBytes;
+ GUID channelTypeGuid;
+ GUID devInstGuid;
+ struct InterruptInfo intr;
+ struct switch_info *swtch;
+ char devid[30]; /* "vbus<busno>:dev<devno>" */
+ U16 polling;
+ struct semaphore interrupt_callback_lock;
+ U32 busNo;
+ U32 devNo;
+ int (*interrupt)(void *);
+ void *interrupt_context;
+ void *private_data;
+ struct list_head list_polling_device_channels;
+ unsigned long long moved_to_tail_cnt;
+ unsigned long long first_busy_cnt;
+ unsigned long long last_on_list_cnt;
+};
+
+typedef enum {
+ RECOVERY_LAN = 1,
+ IB_LAN = 2
+} SWITCH_TYPE;
+
+struct bus_info {
+ U32 busNo, deviceCount;
+ struct device_info **device;
+ U64 guestHandle, recvBusInterruptHandle;
+ GUID busInstGuid;
+ ULTRA_VBUS_CHANNEL_PROTOCOL __iomem *pBusChannel;
+ int busChannelBytes;
+ struct proc_dir_entry *proc_dir; /* proc/uislib/vbus/<x> */
+ struct proc_dir_entry *proc_info; /* proc/uislib/vbus/<x>/info */
+ char name[25];
+ char partitionName[99];
+ struct bus_info *next;
+ U8 localVnic; /* 1 if local vnic created internally
+ * by IOVM; 0 otherwise... */
+};
+
+#define DEDICATED_SWITCH(pSwitch) ((pSwitch->extPortCount == 1) && \
+ (pSwitch->intPortCount == 1))
+
+struct sn_list_entry {
+ struct uisscsi_dest pdest; /* scsi bus, target, lun for
+ * phys disk */
+ U8 sernum[MAX_SERIAL_NUM]; /* serial num of physical
+ * disk.. The length is always
+ * MAX_SERIAL_NUM, padded with
+ * spaces */
+ struct sn_list_entry *next;
+};
+
+struct networkPolicy {
+ U32 promiscuous:1;
+ U32 macassign:1;
+ U32 peerforwarding:1;
+ U32 nonotify:1;
+ U32 standby:1;
+ U32 callhome:2;
+ char ip_addr[30];
+};
+
+/*
+ * IO messages sent to UisnicControlChanFunc & UissdControlChanFunc by
+ * code that processes the ControlVm channel messages.
+ */
+
+
+typedef enum {
+ IOPART_ADD_VNIC,
+ IOPART_DEL_VNIC,
+ IOPART_DEL_ALL_VNICS,
+ IOPART_ADD_VHBA,
+ IOPART_ADD_VDISK,
+ IOPART_DEL_VHBA,
+ IOPART_DEL_VDISK,
+ IOPART_DEL_ALL_VDISKS_FOR_VHBA,
+ IOPART_DEL_ALL_VHBAS,
+ IOPART_ATTACH_PHBA,
+ IOPART_DETACH_PHBA, /* 10 */
+ IOPART_ATTACH_PNIC,
+ IOPART_DETACH_PNIC,
+ IOPART_DETACH_VHBA,
+ IOPART_DETACH_VNIC,
+ IOPART_PAUSE_VDISK,
+ IOPART_RESUME_VDISK,
+ IOPART_ADD_DEVICE, /* add generic device */
+ IOPART_DEL_DEVICE, /* del generic device */
+} IOPART_MSG_TYPE;
+
+struct add_virt_iopart {
+ void *chanptr; /* pointer to data channel */
+ U64 guestHandle; /* used to convert guest physical
+ * address to real physical address
+ * for DMA, for ex. */
+ U64 recvBusInterruptHandle; /* used to register to receive
+ * bus level interrupts. */
+ struct InterruptInfo intr; /* contains recv & send
+ * interrupt info */
+ /* recvInterruptHandle is used to register to receive
+ * interrupts on the data channel. Used by GuestLinux/Windows
+ * IO drivers to connect to interrupt. sendInterruptHandle is
+ * used by IOPart drivers as parameter to
+ * Issue_VMCALL_IO_QUEUE_TRANSITION to interrupt thread in
+ * guest linux/windows IO drivers when data channel queue for
+ * vhba/vnic goes from EMPTY to NON-EMPTY. */
+ struct switch_info *swtch; /* pointer to the virtual
+ * switch to which the vnic is
+ * connected */
+
+ U8 useG2GCopy; /* Used to determine if a virtual HBA
+ * needs to use G2G copy. */
+ U8 Filler[7];
+
+ U32 busNo;
+ U32 devNo;
+ char *params;
+ ulong params_bytes;
+
+};
+
+struct add_vdisk_iopart {
+ void *chanptr; /* pointer to data channel */
+ int implicit;
+ struct uisscsi_dest vdest; /* scsi bus, target, lun for virt disk */
+ struct uisscsi_dest pdest; /* scsi bus, target, lun for phys disk */
+ U8 sernum[MAX_SERIAL_NUM]; /* serial num of physical disk */
+ U32 serlen; /* length of serial num */
+ U32 busNo;
+ U32 devNo;
+};
+
+struct del_vdisk_iopart {
+ void *chanptr; /* pointer to data channel */
+ struct uisscsi_dest vdest; /* scsi bus, target, lun for virt disk */
+ U32 busNo;
+ U32 devNo;
+};
+
+struct del_virt_iopart {
+ void *chanptr; /* pointer to data channel */
+ U32 busNo;
+ U32 devNo;
+};
+
+struct det_virt_iopart { /* detach internal port */
+ void *chanptr; /* pointer to data channel */
+ struct switch_info *swtch;
+};
+
+struct paures_vdisk_iopart {
+ void *chanptr; /* pointer to data channel */
+ struct uisscsi_dest vdest; /* scsi bus, target, lun for virt disk */
+};
+
+struct add_switch_iopart { /* add switch */
+ struct switch_info *swtch;
+ char *params;
+ ulong params_bytes;
+};
+
+struct del_switch_iopart { /* destroy switch */
+ struct switch_info *swtch;
+};
+
+struct io_msgs {
+
+ IOPART_MSG_TYPE msgtype;
+
+ /* additional params needed by some messages */
+ union {
+ struct add_virt_iopart add_vhba;
+ struct add_virt_iopart add_vnic;
+ struct add_vdisk_iopart add_vdisk;
+ struct del_virt_iopart del_vhba;
+ struct del_virt_iopart del_vnic;
+ struct det_virt_iopart det_vhba;
+ struct det_virt_iopart det_vnic;
+ struct del_vdisk_iopart del_vdisk;
+ struct del_virt_iopart del_all_vdisks_for_vhba;
+ struct add_virt_iopart add_device;
+ struct del_virt_iopart del_device;
+ struct det_virt_iopart det_intport;
+ struct add_switch_iopart add_switch;
+ struct del_switch_iopart del_switch;
+ struct extport_info *extPort; /* for attach or detach
+ * pnic/generic delete all
+ * vhbas/allvnics need no
+ * parameters */
+ struct paures_vdisk_iopart paures_vdisk;
+ };
+};
+
+/*
+* Guest messages sent to VirtControlChanFunc by code that processes
+* the ControlVm channel messages.
+*/
+
+typedef enum {
+ GUEST_ADD_VBUS,
+ GUEST_ADD_VHBA,
+ GUEST_ADD_VNIC,
+ GUEST_DEL_VBUS,
+ GUEST_DEL_VHBA,
+ GUEST_DEL_VNIC,
+ GUEST_DEL_ALL_VHBAS,
+ GUEST_DEL_ALL_VNICS,
+ GUEST_DEL_ALL_VBUSES, /* deletes all vhbas & vnics on all
+ * buses and deletes all buses */
+ GUEST_PAUSE_VHBA,
+ GUEST_PAUSE_VNIC,
+ GUEST_RESUME_VHBA,
+ GUEST_RESUME_VNIC
+} GUESTPART_MSG_TYPE;
+
+struct add_vbus_guestpart {
+ void __iomem *chanptr; /* pointer to data channel for bus -
+ * NOT YET USED */
+ U32 busNo; /* bus number to be created/deleted */
+ U32 deviceCount; /* max num of devices on bus */
+ GUID busTypeGuid; /* indicates type of bus */
+ GUID busInstGuid; /* instance guid for device */
+};
+
+struct del_vbus_guestpart {
+ U32 busNo; /* bus number to be deleted */
+ /* once we start using the bus's channel, add can dump busNo
+ * into the channel header and then delete will need only one
+ * parameter, chanptr. */
+};
+
+struct add_virt_guestpart {
+ void __iomem *chanptr; /* pointer to data channel */
+ U32 busNo; /* bus number for the operation */
+ U32 deviceNo; /* number of device on the bus */
+ GUID devInstGuid; /* instance guid for device */
+ struct InterruptInfo intr; /* recv/send interrupt info */
+ /* recvInterruptHandle contains info needed in order to
+ * register to receive interrupts on the data channel.
+ * sendInterruptHandle contains handle which is provided to
+ * monitor VMCALL that will cause an interrupt to be generated
+ * for the other end.
+ */
+};
+
+struct pause_virt_guestpart {
+ void __iomem *chanptr; /* pointer to data channel */
+};
+
+struct resume_virt_guestpart {
+ void __iomem *chanptr; /* pointer to data channel */
+};
+
+struct del_virt_guestpart {
+ void __iomem *chanptr; /* pointer to data channel */
+};
+
+struct init_chipset_guestpart {
+ U32 busCount; /* indicates the max number of busses */
+ U32 switchCount; /* indicates the max number of switches */
+};
+
+struct guest_msgs {
+
+ GUESTPART_MSG_TYPE msgtype;
+
+ /* additional params needed by messages */
+ union {
+ struct add_vbus_guestpart add_vbus;
+ struct add_virt_guestpart add_vhba;
+ struct add_virt_guestpart add_vnic;
+ struct pause_virt_guestpart pause_vhba;
+ struct pause_virt_guestpart pause_vnic;
+ struct resume_virt_guestpart resume_vhba;
+ struct resume_virt_guestpart resume_vnic;
+ struct del_vbus_guestpart del_vbus;
+ struct del_virt_guestpart del_vhba;
+ struct del_virt_guestpart del_vnic;
+ struct del_vbus_guestpart del_all_vhbas;
+ struct del_vbus_guestpart del_all_vnics;
+ /* del_all_vbuses needs no parameters */
+ };
+ struct init_chipset_guestpart init_chipset;
+
+};
+
+#ifndef __xg
+#define __xg(x) ((volatile long *)(x))
+#endif
+
+/*
+* Below code is a copy of Linux kernel's cmpxchg function located at
+* this place
+* http://tcsxeon:8080/source/xref/00trunk-AppOS-linux/include/asm-x86/cmpxchg_64.h#84
+* Reason for creating our own version of cmpxchg along with
+* UISLIB_LOCK_PREFIX is to make the operation atomic even for non SMP
+* guests.
+*/
+
+#define uislibcmpxchg64(p, o, n, s) cmpxchg(p, o, n)
+
+#endif /* __UISQUEUE_H__ */
diff --git a/drivers/staging/unisys/include/uisthread.h b/drivers/staging/unisys/include/uisthread.h
new file mode 100644
index 000000000000..2b1fba759098
--- /dev/null
+++ b/drivers/staging/unisys/include/uisthread.h
@@ -0,0 +1,46 @@
+/* uisthread.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*****************************************************************************/
+/* Unisys thread utilities header */
+/*****************************************************************************/
+
+
+#ifndef __UISTHREAD_H__
+#define __UISTHREAD_H__
+
+
+#include "linux/completion.h"
+
+struct uisthread_info {
+ struct task_struct *task;
+ int id;
+ int should_stop;
+ struct completion has_stopped;
+};
+
+
+/* returns 0 for failure, 1 for success */
+int uisthread_start(
+ struct uisthread_info *thrinfo,
+ int (*threadfn)(void *),
+ void *thrcontext,
+ char *name);
+
+void uisthread_stop(struct uisthread_info *thrinfo);
+
+#endif /* __UISTHREAD_H__ */
diff --git a/drivers/staging/unisys/include/uisutils.h b/drivers/staging/unisys/include/uisutils.h
new file mode 100644
index 000000000000..5fdab3a3464a
--- /dev/null
+++ b/drivers/staging/unisys/include/uisutils.h
@@ -0,0 +1,348 @@
+/* uisutils.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * Unisys Virtual HBA utilities header
+ */
+
+#ifndef __UISUTILS__H__
+#define __UISUTILS__H__
+#include <linux/string.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/gfp.h>
+
+#include "vmcallinterface.h"
+#include "channel.h"
+#include "uisthread.h"
+#include "uisqueue.h"
+#include "diagnostics/appos_subsystems.h"
+#include "vbusdeviceinfo.h"
+#include <linux/atomic.h>
+
+/* This is the MAGIC number stuffed by virthba in host->this_id. Used to
+ * identify virtual hbas.
+ */
+#define UIS_MAGIC_VHBA 707
+
+/* global function pointers that act as callback functions into
+ * uisnicmod, uissdmod, and virtpcimod
+ */
+extern int (*UisnicControlChanFunc)(struct io_msgs *);
+extern int (*UissdControlChanFunc)(struct io_msgs *);
+extern int (*VirtControlChanFunc)(struct guest_msgs *);
+
+/* Return values of above callback functions: */
+#define CCF_ERROR 0 /* completed and failed */
+#define CCF_OK 1 /* completed successfully */
+#define CCF_PENDING 2 /* operation still pending */
+extern atomic_t UisUtils_Registered_Services;
+
+typedef unsigned int MACARRAY[MAX_MACADDR_LEN];
+typedef struct ReqHandlerInfo_struct {
+ GUID switchTypeGuid;
+ int (*controlfunc)(struct io_msgs *);
+ unsigned long min_channel_bytes;
+ int (*Server_Channel_Ok)(unsigned long channelBytes);
+ int (*Server_Channel_Init)
+ (void *x, unsigned char *clientStr, U32 clientStrLen, U64 bytes);
+ char switch_type_name[99];
+ struct list_head list_link; /* links into ReqHandlerInfo_list */
+} ReqHandlerInfo_t;
+
+ReqHandlerInfo_t *ReqHandlerAdd(GUID switchTypeGuid,
+ const char *switch_type_name,
+ int (*controlfunc)(struct io_msgs *),
+ unsigned long min_channel_bytes,
+ int (*Server_Channel_Ok)(unsigned long
+ channelBytes),
+ int (*Server_Channel_Init)
+ (void *x, unsigned char *clientStr,
+ U32 clientStrLen, U64 bytes));
+ReqHandlerInfo_t *ReqHandlerFind(GUID switchTypeGuid);
+int ReqHandlerDel(GUID switchTypeGuid);
+
+#define uislib_ioremap_cache(addr, size) \
+ dbg_ioremap_cache(addr, size, __FILE__, __LINE__)
+
+static inline void __iomem *
+dbg_ioremap_cache(U64 addr, unsigned long size, char *file, int line)
+{
+ void __iomem *new;
+ new = ioremap_cache(addr, size);
+ return new;
+}
+
+#define uislib_ioremap(addr, size) dbg_ioremap(addr, size, __FILE__, __LINE__)
+
+static inline void *
+dbg_ioremap(U64 addr, unsigned long size, char *file, int line)
+{
+ void *new;
+ new = ioremap(addr, size);
+ return new;
+}
+
+#define uislib_iounmap(addr) dbg_iounmap(addr, __FILE__, __LINE__)
+
+static inline void
+dbg_iounmap(void __iomem *addr, char *file, int line)
+{
+ iounmap(addr);
+}
+
+#define PROC_READ_BUFFER_SIZE 131072 /* size of the buffer to allocate to
+ * hold all of /proc/XXX/info */
+int uisutil_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
+ char *format, ...);
+
+int uisctrl_register_req_handler(int type, void *fptr,
+ ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo);
+int uisctrl_register_req_handler_ex(GUID switchTypeGuid,
+ const char *switch_type_name,
+ int (*fptr)(struct io_msgs *),
+ unsigned long min_channel_bytes,
+ int (*Server_Channel_Ok)(unsigned long
+ channelBytes),
+ int (*Server_Channel_Init)
+ (void *x, unsigned char *clientStr,
+ U32 clientStrLen, U64 bytes),
+ ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo);
+
+int uisctrl_unregister_req_handler_ex(GUID switchTypeGuid);
+unsigned char *util_map_virt(struct phys_info *sg);
+void util_unmap_virt(struct phys_info *sg);
+unsigned char *util_map_virt_atomic(struct phys_info *sg);
+void util_unmap_virt_atomic(void *buf);
+int uislib_server_inject_add_vnic(U32 switchNo, U32 BusNo, U32 numIntPorts,
+ U32 numExtPorts, MACARRAY pmac[],
+ pCHANNEL_HEADER **chan);
+void uislib_server_inject_del_vnic(U32 switchNo, U32 busNo, U32 numIntPorts,
+ U32 numExtPorts);
+int uislib_client_inject_add_bus(U32 busNo, GUID instGuid,
+ U64 channelAddr, ulong nChannelBytes);
+int uislib_client_inject_del_bus(U32 busNo);
+
+int uislib_client_inject_add_vhba(U32 busNo, U32 devNo,
+ U64 phys_chan_addr, U32 chan_bytes,
+ int is_test_addr, GUID instGuid,
+ struct InterruptInfo *intr);
+int uislib_client_inject_pause_vhba(U32 busNo, U32 devNo);
+int uislib_client_inject_resume_vhba(U32 busNo, U32 devNo);
+int uislib_client_inject_del_vhba(U32 busNo, U32 devNo);
+int uislib_client_inject_add_vnic(U32 busNo, U32 devNo,
+ U64 phys_chan_addr, U32 chan_bytes,
+ int is_test_addr, GUID instGuid,
+ struct InterruptInfo *intr);
+int uislib_client_inject_pause_vnic(U32 busNo, U32 devNo);
+int uislib_client_inject_resume_vnic(U32 busNo, U32 devNo);
+int uislib_client_inject_del_vnic(U32 busNo, U32 devNo);
+#ifdef STORAGE_CHANNEL
+U64 uislib_storage_channel(int client_id);
+#endif
+int uislib_get_owned_pdest(struct uisscsi_dest *pdest);
+
+int uislib_send_event(CONTROLVM_ID id, CONTROLVM_MESSAGE_PACKET *event);
+
+/* structure used by vhba & vnic to keep track of queue & thread info */
+struct chaninfo {
+ struct uisqueue_info *queueinfo;
+ /* this specifies the queue structures for a channel */
+ /* ALLOCATED BY THE OTHER END - WE JUST GET A POINTER TO THE MEMORY */
+ spinlock_t insertlock;
+ /* currently used only in virtnic when sending data to uisnic */
+ /* to synchronize the inserts into the signal queue */
+ struct uisthread_info threadinfo;
+ /* this specifies the thread structures used by the thread that */
+ /* handles this channel */
+};
+
+/* this is the wait code for all the threads - it is used to get
+* something from a queue choices: wait_for_completion_interruptible,
+* _timeout, interruptible_timeout
+*/
+#define UIS_THREAD_WAIT_MSEC(x) { \
+ set_current_state(TASK_INTERRUPTIBLE); \
+ schedule_timeout(msecs_to_jiffies(x)); \
+}
+#define UIS_THREAD_WAIT_USEC(x) { \
+ set_current_state(TASK_INTERRUPTIBLE); \
+ schedule_timeout(usecs_to_jiffies(x)); \
+}
+#define UIS_THREAD_WAIT UIS_THREAD_WAIT_MSEC(5)
+#define UIS_THREAD_WAIT_SEC(x) { \
+ set_current_state(TASK_INTERRUPTIBLE); \
+ schedule_timeout((x)*HZ); \
+}
+
+/* This is a hack until we fix IOVM to initialize the channel header
+ * correctly at DEVICE_CREATE time, INSTEAD OF waiting until
+ * DEVICE_CONFIGURE time.
+ */
+#define WAIT_FOR_VALID_GUID(guid) \
+ do { \
+ while (MEMCMP_IO(&guid, &Guid0, sizeof(Guid0)) == 0) { \
+ LOGERR("Waiting for non-0 GUID (why???)...\n"); \
+ UIS_THREAD_WAIT_SEC(5); \
+ } \
+ LOGERR("OK... GUID is non-0 now\n"); \
+ } while (0)
+
+/* CopyFragsInfoFromSkb returns the number of entries added to frags array
+ * Returns -1 on failure.
+ */
+unsigned int uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx,
+ void *skb_in,
+ unsigned int firstfraglen,
+ unsigned int frags_max,
+ struct phys_info frags[]);
+
+static inline unsigned int
+Issue_VMCALL_IO_CONTROLVM_ADDR(U64 *ControlAddress, U32 *ControlBytes)
+{
+ VMCALL_IO_CONTROLVM_ADDR_PARAMS params;
+ int result = VMCALL_SUCCESS;
+ U64 physaddr;
+
+ physaddr = virt_to_phys(&params);
+ ISSUE_IO_VMCALL(VMCALL_IO_CONTROLVM_ADDR, physaddr, result);
+ if (VMCALL_SUCCESSFUL(result)) {
+ *ControlAddress = params.ChannelAddress;
+ *ControlBytes = params.ChannelBytes;
+ }
+ return result;
+}
+
+static inline unsigned int Issue_VMCALL_IO_DIAG_ADDR(U64 *DiagChannelAddress)
+{
+ VMCALL_IO_DIAG_ADDR_PARAMS params;
+ int result = VMCALL_SUCCESS;
+ U64 physaddr;
+
+ physaddr = virt_to_phys(&params);
+ ISSUE_IO_VMCALL(VMCALL_IO_DIAG_ADDR, physaddr, result);
+ if (VMCALL_SUCCESSFUL(result))
+ *DiagChannelAddress = params.ChannelAddress;
+ return result;
+}
+
+static inline unsigned int
+Issue_VMCALL_IO_VISORSERIAL_ADDR(U64 *DiagChannelAddress)
+{
+ VMCALL_IO_VISORSERIAL_ADDR_PARAMS params;
+ int result = VMCALL_SUCCESS;
+ U64 physaddr;
+
+ physaddr = virt_to_phys(&params);
+ ISSUE_IO_VMCALL(VMCALL_IO_VISORSERIAL_ADDR, physaddr, result);
+ if (VMCALL_SUCCESSFUL(result))
+ *DiagChannelAddress = params.ChannelAddress;
+ return result;
+}
+
+static inline S64 Issue_VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET(void)
+{
+ U64 result = VMCALL_SUCCESS;
+ U64 physaddr = 0;
+
+ ISSUE_IO_VMCALL(VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET, physaddr,
+ result);
+ return result;
+}
+
+static inline S64 Issue_VMCALL_MEASUREMENT_DO_NOTHING(void)
+{
+ U64 result = VMCALL_SUCCESS;
+ U64 physaddr = 0;
+
+ ISSUE_IO_VMCALL(VMCALL_MEASUREMENT_DO_NOTHING, physaddr, result);
+ return result;
+}
+
+struct log_info_t {
+ volatile unsigned long long last_cycles;
+ unsigned long long delta_sum[64];
+ unsigned long long delta_cnt[64];
+ unsigned long long max_delta[64];
+ unsigned long long min_delta[64];
+};
+
+static inline int Issue_VMCALL_UPDATE_PHYSICAL_TIME(U64 adjustment)
+{
+ int result = VMCALL_SUCCESS;
+
+ ISSUE_IO_VMCALL(VMCALL_UPDATE_PHYSICAL_TIME, adjustment, result);
+ return result;
+}
+
+static inline unsigned int
+Issue_VMCALL_CHANNEL_MISMATCH(const char *ChannelName,
+ const char *ItemName,
+ U32 SourceLineNumber, const char *path_n_fn)
+{
+ VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS params;
+ int result = VMCALL_SUCCESS;
+ U64 physaddr;
+ char *last_slash = NULL;
+
+ strncpy(params.ChannelName, ChannelName,
+ lengthof(VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS, ChannelName));
+ strncpy(params.ItemName, ItemName,
+ lengthof(VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS, ItemName));
+ params.SourceLineNumber = SourceLineNumber;
+
+ last_slash = strrchr(path_n_fn, '/');
+ if (last_slash != NULL) {
+ last_slash++;
+ strncpy(params.SourceFileName, last_slash,
+ lengthof(VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS,
+ SourceFileName));
+ } else
+ strncpy(params.SourceFileName,
+ "Cannot determine source filename",
+ lengthof(VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS,
+ SourceFileName));
+
+ physaddr = virt_to_phys(&params);
+ ISSUE_IO_VMCALL(VMCALL_CHANNEL_VERSION_MISMATCH, physaddr, result);
+ return result;
+}
+
+static inline unsigned int Issue_VMCALL_FATAL_BYE_BYE(void)
+{
+ int result = VMCALL_SUCCESS;
+ U64 physaddr = 0;
+
+ ISSUE_IO_VMCALL(VMCALL_GENERIC_SURRENDER_QUANTUM_FOREVER, physaddr,
+ result);
+ return result;
+}
+
+#define UIS_DAEMONIZE(nam)
+void *uislib_cache_alloc(struct kmem_cache *cur_pool, char *fn, int ln);
+#define UISCACHEALLOC(cur_pool) uislib_cache_alloc(cur_pool, __FILE__, __LINE__)
+void uislib_cache_free(struct kmem_cache *cur_pool, void *p, char *fn, int ln);
+#define UISCACHEFREE(cur_pool, p) \
+ uislib_cache_free(cur_pool, p, __FILE__, __LINE__)
+
+void uislib_enable_channel_interrupts(U32 busNo, U32 devNo,
+ int (*interrupt)(void *),
+ void *interrupt_context);
+void uislib_disable_channel_interrupts(U32 busNo, U32 devNo);
+void uislib_force_channel_interrupt(U32 busNo, U32 devNo);
+
+#endif /* __UISUTILS__H__ */
diff --git a/drivers/staging/unisys/include/uniklog.h b/drivers/staging/unisys/include/uniklog.h
new file mode 100644
index 000000000000..4d7b87cefa61
--- /dev/null
+++ b/drivers/staging/unisys/include/uniklog.h
@@ -0,0 +1,193 @@
+/* uniklog.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* This module contains macros to aid developers in logging messages.
+ *
+ * This module is affected by the DEBUG compiletime option.
+ *
+ */
+#ifndef __UNIKLOG_H__
+#define __UNIKLOG_H__
+
+
+#include <linux/printk.h>
+
+/*
+ * # DBGINF
+ *
+ * \brief Log debug informational message - log a LOG_INFO message only
+ * if DEBUG compiletime option enabled
+ *
+ * \param devname the device name of the device reporting this message, or
+ * NULL if this message is NOT device-related.
+ * \param fmt printf()-style format string containing the message to log.
+ * \param args Optional arguments to be formatted and inserted into the
+ * format string.
+ * \return nothing
+ *
+ * Log a message at the LOG_INFO level, but only if DEBUG is enabled. If
+ * DEBUG is disabled, this expands to a no-op.
+ */
+
+/*
+ * # DBGVER
+ *
+ * \brief Log debug verbose message - log a LOG_DEBUG message only if
+ * DEBUG compiletime option enabled
+ *
+ * \param devname the device name of the device reporting this message, or
+ * NULL if this message is NOT device-related.
+ * \param fmt printf()-style format string containing the message to log.
+ * \param args Optional arguments to be formatted and inserted into the
+ * format string.
+ * \return nothing
+ *
+ * Log a message at the LOG_DEBUG level, but only if DEBUG is enabled. If
+ * DEBUG is disabled, this expands to a no-op. Note also that LOG_DEBUG
+ * messages can be enabled/disabled at runtime as well.
+ */
+#define DBGINFDEV(devname, fmt, args...) do { } while (0)
+#define DBGVERDEV(devname, fmt, args...) do { } while (0)
+#define DBGINF(fmt, args...) do { } while (0)
+#define DBGVER(fmt, args...) do { } while (0)
+
+/*
+ * # LOGINF
+ *
+ * \brief Log informational message - logs a message at the LOG_INFO level
+ *
+ * \param devname the device name of the device reporting this message, or
+ * NULL if this message is NOT device-related.
+ * \param fmt printf()-style format string containing the message to log.
+ * \param args Optional arguments to be formatted and inserted into the
+ * format string.
+ * \return nothing
+ *
+ * Logs the specified message at the LOG_INFO level.
+ */
+
+#define LOGINF(fmt, args...) pr_info(fmt, ## args)
+#define LOGINFDEV(devname, fmt, args...) \
+ pr_info("%s " fmt, devname, ## args)
+#define LOGINFDEVX(devno, fmt, args...) \
+ pr_info("dev%d " fmt, devno, ## args)
+#define LOGINFNAME(vnic, fmt, args...) \
+ do { \
+ if (vnic != NULL) { \
+ pr_info("%s " fmt, vnic->name, ## args); \
+ } else { \
+ pr_info(fmt, ## args); \
+ } \
+ } while (0)
+
+/*
+ * # LOGVER
+ *
+ * \brief Log verbose message - logs a message at the LOG_DEBUG level,
+ * which can be disabled at runtime
+ *
+ * \param devname the device name of the device reporting this message, or
+ * NULL if this message is NOT device-related.
+ * \param fmt printf()-style format string containing the message to log.
+ * \param args Optional arguments to be formatted and inserted into the format
+ * \param string.
+ * \return nothing
+ *
+ * Logs the specified message at the LOG_DEBUG level. Note also that
+ * LOG_DEBUG messages can be enabled/disabled at runtime as well.
+ */
+#define LOGVER(fmt, args...) pr_debug(fmt, ## args)
+#define LOGVERDEV(devname, fmt, args...) \
+ pr_debug("%s " fmt, devname, ## args)
+#define LOGVERNAME(vnic, fmt, args...) \
+ do { \
+ if (vnic != NULL) { \
+ pr_debug("%s " fmt, vnic->name, ## args); \
+ } else { \
+ pr_debug(fmt, ## args); \
+ } \
+ } while (0)
+
+
+/*
+ * # LOGERR
+ *
+ * \brief Log error message - logs a message at the LOG_ERR level,
+ * including source line number information
+ *
+ * \param devname the device name of the device reporting this message, or
+ * NULL if this message is NOT device-related.
+ * \param fmt printf()-style format string containing the message to log.
+ * \param args Optional arguments to be formatted and inserted into the format
+ * \param string.
+ * \return nothing
+ *
+ * Logs the specified error message at the LOG_ERR level. It will also
+ * include the file, line number, and function name of where the error
+ * originated in the log message.
+ */
+#define LOGERR(fmt, args...) pr_err(fmt, ## args)
+#define LOGERRDEV(devname, fmt, args...) \
+ pr_err("%s " fmt, devname, ## args)
+#define LOGERRDEVX(devno, fmt, args...) \
+ pr_err("dev%d " fmt, devno, ## args)
+#define LOGERRNAME(vnic, fmt, args...) \
+ do { \
+ if (vnic != NULL) { \
+ pr_err("%s " fmt, vnic->name, ## args); \
+ } else { \
+ pr_err(fmt, ## args); \
+ } \
+ } while (0)
+#define LOGORDUMPERR(seqfile, fmt, args...) do { \
+ if (seqfile) { \
+ seq_printf(seqfile, fmt, ## args); \
+ } else { \
+ LOGERR(fmt, ## args); \
+ } \
+ } while (0)
+
+/*
+ * # LOGWRN
+ *
+ * \brief Log warning message - Logs a message at the LOG_WARNING level,
+ * including source line number information
+ *
+ * \param devname the device name of the device reporting this message, or
+ * NULL if this message is NOT device-related.
+ * \param fmt printf()-style format string containing the message to log.
+ * \param args Optional arguments to be formatted and inserted into the format
+ * \param string.
+ * \return nothing
+ *
+ * Logs the specified error message at the LOG_WARNING level. It will also
+ * include the file, line number, and function name of where the error
+ * originated in the log message.
+ */
+#define LOGWRN(fmt, args...) pr_warn(fmt, ## args)
+#define LOGWRNDEV(devname, fmt, args...) \
+ pr_warn("%s " fmt, devname, ## args)
+#define LOGWRNNAME(vnic, fmt, args...) \
+ do { \
+ if (vnic != NULL) { \
+ pr_warn("%s " fmt, vnic->name, ## args); \
+ } else { \
+ pr_warn(fmt, ## args); \
+ } \
+ } while (0)
+
+#endif /* __UNIKLOG_H__ */
diff --git a/drivers/staging/unisys/include/vbushelper.h b/drivers/staging/unisys/include/vbushelper.h
new file mode 100644
index 000000000000..93e35f039ded
--- /dev/null
+++ b/drivers/staging/unisys/include/vbushelper.h
@@ -0,0 +1,47 @@
+/* vbushelper.h
+ *
+ * Copyright © 2011 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __VBUSHELPER_H__
+#define __VBUSHELPER_H__
+
+#include "vbusdeviceinfo.h"
+
+/* TARGET_HOSTNAME specified as -DTARGET_HOSTNAME=\"thename\" on the
+ * command line */
+
+#define TARGET_HOSTNAME "linuxguest"
+
+static inline void
+BusDeviceInfo_Init(ULTRA_VBUS_DEVICEINFO *pBusDeviceInfo,
+ const char *deviceType, const char *driverName,
+ const char *ver, const char *verTag,
+ const char *buildDate, const char *buildTime)
+{
+ memset(pBusDeviceInfo, 0, sizeof(ULTRA_VBUS_DEVICEINFO));
+ snprintf(pBusDeviceInfo->devType, sizeof(pBusDeviceInfo->devType),
+ "%s", (deviceType) ? deviceType : "unknownType");
+ snprintf(pBusDeviceInfo->drvName, sizeof(pBusDeviceInfo->drvName),
+ "%s", (driverName) ? driverName : "unknownDriver");
+ snprintf(pBusDeviceInfo->infoStrings,
+ sizeof(pBusDeviceInfo->infoStrings), "%s\t%s\t%s %s\t%s",
+ (ver) ? ver : "unknownVer",
+ (verTag) ? verTag : "unknownVerTag",
+ (buildDate) ? buildDate : "noBuildDate",
+ (buildTime) ? buildTime : "nobuildTime", TARGET_HOSTNAME);
+}
+
+#endif
diff --git a/drivers/staging/unisys/uislib/Kconfig b/drivers/staging/unisys/uislib/Kconfig
new file mode 100644
index 000000000000..8d87d9c81c66
--- /dev/null
+++ b/drivers/staging/unisys/uislib/Kconfig
@@ -0,0 +1,10 @@
+#
+# Unisys uislib configuration
+#
+
+config UNISYS_UISLIB
+ tristate "Unisys uislib driver"
+ depends on UNISYSSPAR && UNISYS_VISORCHIPSET && UNISYS_CHANNELSTUB
+ ---help---
+ If you say Y here, you will enable the Unisys uislib driver.
+
diff --git a/drivers/staging/unisys/uislib/Makefile b/drivers/staging/unisys/uislib/Makefile
new file mode 100644
index 000000000000..6e44d49458f5
--- /dev/null
+++ b/drivers/staging/unisys/uislib/Makefile
@@ -0,0 +1,17 @@
+#
+# Makefile for Unisys uislib
+#
+
+obj-$(CONFIG_UNISYS_UISLIB) += visoruislib.o
+
+visoruislib-y := uislib.o uisqueue.o uisthread.o uisutils.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+ccflags-y += -Idrivers/staging/unisys/channels
+ccflags-y += -Idrivers/staging/unisys/visorchipset
+ccflags-y += -Idrivers/staging/unisys/sparstopdriver
+ccflags-y += -Idrivers/staging/unisys/common-spar/include
+ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
+
+ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION
+
diff --git a/drivers/staging/unisys/uislib/uislib.c b/drivers/staging/unisys/uislib/uislib.c
new file mode 100644
index 000000000000..8ea9c46e56ae
--- /dev/null
+++ b/drivers/staging/unisys/uislib/uislib.c
@@ -0,0 +1,2421 @@
+/* uislib.c
+ *
+ * Copyright � 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* @ALL_INSPECTED */
+#define EXPORT_SYMTAB
+#include <linux/kernel.h>
+#include <linux/highmem.h>
+#ifdef CONFIG_MODVERSIONS
+#include <config/modversions.h>
+#endif
+#include <linux/module.h>
+
+#include "commontypes.h"
+
+#include <linux/version.h>
+#include "uniklog.h"
+#include "diagnostics/appos_subsystems.h"
+#include "uisutils.h"
+#include "vbuschannel.h"
+
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h> /* for copy_from_user */
+#include <linux/ctype.h> /* for toupper */
+#include <linux/list.h>
+
+#include "sparstop.h"
+#include "visorchipset.h"
+#include "chanstub.h"
+#include "version.h"
+#include "guestlinuxdebug.h"
+
+#define SET_PROC_OWNER(x, y)
+
+#define UISLIB_TEST_PROC
+#define POLLJIFFIES_NORMAL 1
+/* Choose whether or not you want to wakeup the request-polling thread
+ * after an IO termination:
+ * this is shorter than using __FILE__ (full path name) in
+ * debug/info/error messages
+ */
+#define CURRENT_FILE_PC UISLIB_PC_uislib_c
+#define __MYFILE__ "uislib.c"
+
+/* global function pointers that act as callback functions into virtpcimod */
+int (*VirtControlChanFunc)(struct guest_msgs *);
+
+static int ProcReadBufferValid;
+static char *ProcReadBuffer; /* Note this MUST be global,
+ * because the contents must */
+static unsigned int chipset_inited;
+
+#define WAIT_ON_CALLBACK(handle) \
+ do { \
+ if (handle) \
+ break; \
+ UIS_THREAD_WAIT; \
+ } while (1)
+
+static struct bus_info *BusListHead;
+static rwlock_t BusListLock;
+static int BusListCount; /* number of buses in the list */
+static int MaxBusCount; /* maximum number of buses expected */
+static U64 PhysicalDataChan;
+static int PlatformNumber;
+
+static struct uisthread_info Incoming_ThreadInfo;
+static BOOL Incoming_Thread_Started = FALSE;
+static LIST_HEAD(List_Polling_Device_Channels);
+static unsigned long long tot_moved_to_tail_cnt;
+static unsigned long long tot_wait_cnt;
+static unsigned long long tot_wakeup_cnt;
+static unsigned long long tot_schedule_cnt;
+static int en_smart_wakeup = 1;
+static DEFINE_SEMAPHORE(Lock_Polling_Device_Channels); /* unlocked */
+static DECLARE_WAIT_QUEUE_HEAD(Wakeup_Polling_Device_Channels);
+static int Go_Polling_Device_Channels;
+
+static struct proc_dir_entry *uislib_proc_dir;
+static struct proc_dir_entry *uislib_proc_vbus_dir;
+static struct proc_dir_entry *vnic_proc_entry; /* Used to be "datachan" */
+static struct proc_dir_entry *ctrlchan_proc_entry;
+static struct proc_dir_entry *pmem_proc_entry;
+static struct proc_dir_entry *info_proc_entry;
+static struct proc_dir_entry *switch_proc_entry;
+static struct proc_dir_entry *extport_proc_entry;
+static struct proc_dir_entry *platformnumber_proc_entry;
+static struct proc_dir_entry *bus_proc_entry;
+static struct proc_dir_entry *dev_proc_entry;
+static struct proc_dir_entry *chipset_proc_entry;
+static struct proc_dir_entry *cycles_before_wait_proc_entry;
+static struct proc_dir_entry *reset_counts_proc_entry;
+static struct proc_dir_entry *smart_wakeup_proc_entry;
+static struct proc_dir_entry *disable_proc_entry;
+
+#define DIR_PROC_ENTRY "uislib"
+#define DIR_VBUS_PROC_ENTRY "vbus"
+#define VNIC_PROC_ENTRY_FN "vnic" /* Used to be "datachan" */
+#define CTRLCHAN_PROC_ENTRY_FN "ctrlchan"
+#define PMEM_PROC_ENTRY_FN "phys_to_virt"
+#define INFO_PROC_ENTRY_FN "info"
+#define SWITCH_PROC_ENTRY_FN "switch"
+#define SWITCH_COUNT_PROC_ENTRY_FN "switch_count"
+#define EXTPORT_PROC_ENTRY_FN "extport"
+#define PLATFORMNUMBER_PROC_ENTRY_FN "platform"
+#define BUS_PROC_ENTRY_FN "bus"
+#define DEV_PROC_ENTRY_FN "device"
+#define CHIPSET_PROC_ENTRY_FN "chipset"
+#define CYCLES_BEFORE_WAIT_PROC_ENTRY_FN "cycles_before_wait"
+#define RESET_COUNTS_PROC_ENTRY_FN "reset_counts"
+#define SMART_WAKEUP_PROC_ENTRY_FN "smart_wakeup"
+#define CALLHOME_PROC_ENTRY_FN "callhome"
+#define CALLHOME_THROTTLED_PROC_ENTRY_FN "callhome_throttled"
+#define DISABLE_PROC_ENTRY_FN "switch_state"
+#ifdef UISLIB_TEST_PROC
+static struct proc_dir_entry *test_proc_entry;
+#define TEST_PROC_ENTRY_FN "test"
+#endif
+static unsigned long long cycles_before_wait, wait_cycles;
+
+/*****************************************************/
+/* local functions */
+/*****************************************************/
+
+static int proc_info_vbus_show(struct seq_file *m, void *v);
+static int
+proc_info_vbus_open(struct inode *inode, struct file *filp)
+{
+ /* proc_info_vbus_show will grab this from seq_file.private: */
+ struct bus_info *bus = PDE_DATA(inode);
+ return single_open(filp, proc_info_vbus_show, bus);
+}
+
+static const struct file_operations proc_info_vbus_fops = {
+ .open = proc_info_vbus_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static ssize_t uislib_proc_read_writeonly(struct file *file,
+ char __user *buffer,
+ size_t count, loff_t *ppos);
+
+static ssize_t vnic_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos);
+
+static const struct file_operations proc_vnic_fops = {
+ .read = uislib_proc_read_writeonly,
+ .write = vnic_proc_write,
+};
+
+static ssize_t chipset_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos);
+
+static const struct file_operations proc_chipset_fops = {
+ .read = uislib_proc_read_writeonly,
+ .write = chipset_proc_write,
+};
+
+static ssize_t info_proc_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offset);
+static const struct file_operations proc_info_fops = {
+ .read = info_proc_read,
+};
+
+static ssize_t platformnumber_proc_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offset);
+static const struct file_operations proc_platformnumber_fops = {
+ .read = platformnumber_proc_read,
+};
+
+static ssize_t cycles_before_wait_proc_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos);
+static const struct file_operations proc_cycles_before_wait_fops = {
+ .read = uislib_proc_read_writeonly,
+ .write = cycles_before_wait_proc_write,
+};
+
+static ssize_t reset_counts_proc_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos);
+static const struct file_operations proc_reset_counts_fops = {
+ .read = uislib_proc_read_writeonly,
+ .write = reset_counts_proc_write,
+};
+
+static ssize_t smart_wakeup_proc_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos);
+static const struct file_operations proc_smart_wakeup_fops = {
+ .read = uislib_proc_read_writeonly,
+ .write = smart_wakeup_proc_write,
+};
+
+static ssize_t test_proc_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos);
+static const struct file_operations proc_test_fops = {
+ .read = uislib_proc_read_writeonly,
+ .write = test_proc_write,
+};
+
+static ssize_t bus_proc_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos);
+static const struct file_operations proc_bus_fops = {
+ .read = uislib_proc_read_writeonly,
+ .write = bus_proc_write,
+};
+
+static ssize_t dev_proc_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos);
+static const struct file_operations proc_dev_fops = {
+ .read = uislib_proc_read_writeonly,
+ .write = dev_proc_write,
+};
+
+static void
+init_msg_header(CONTROLVM_MESSAGE *msg, U32 id, uint rsp, uint svr)
+{
+ memset(msg, 0, sizeof(CONTROLVM_MESSAGE));
+ msg->hdr.Id = id;
+ msg->hdr.Flags.responseExpected = rsp;
+ msg->hdr.Flags.server = svr;
+}
+
+static void
+create_bus_proc_entries(struct bus_info *bus)
+{
+ bus->proc_dir = proc_mkdir(bus->name, uislib_proc_vbus_dir);
+ if (!bus->proc_dir) {
+ LOGERR("failed to create /proc/uislib/vbus/%s directory",
+ bus->name);
+ return;
+ }
+ bus->proc_info = proc_create_data("info", 0, bus->proc_dir,
+ &proc_info_vbus_fops, bus);
+ if (!bus->proc_info) {
+ LOGERR("failed to create /proc/uislib/vbus/%s/info", bus->name);
+ remove_proc_entry(bus->name, uislib_proc_vbus_dir);
+ bus->proc_dir = NULL;
+ return;
+ }
+ SET_PROC_OWNER(bus->proc_info, THIS_MODULE);
+
+}
+
+static __iomem void *
+init_vbus_channel(U64 channelAddr, U32 channelBytes, int isServer)
+{
+ void *rc = NULL;
+ void __iomem *pChan = uislib_ioremap_cache(channelAddr, channelBytes);
+ if (!pChan) {
+ LOGERR("CONTROLVM_BUS_CREATE error: ioremap_cache of channelAddr:%Lx for channelBytes:%llu failed",
+ (unsigned long long) channelAddr,
+ (unsigned long long) channelBytes);
+ rc = NULL;
+ goto Away;
+ }
+ if (isServer) {
+ memset_io(pChan, 0, channelBytes);
+ if (!ULTRA_VBUS_CHANNEL_OK_SERVER(channelBytes, NULL)) {
+ ERRDRV("%s channel cannot be used", __func__);
+ uislib_iounmap(pChan);
+ rc = NULL;
+ goto Away;
+ }
+ ULTRA_VBUS_init_channel(pChan, channelBytes);
+ } else {
+ if (!ULTRA_VBUS_CHANNEL_OK_CLIENT(pChan, NULL)) {
+ ERRDRV("%s channel cannot be used", __func__);
+ uislib_iounmap(pChan);
+ rc = NULL;
+ goto Away;
+ }
+ }
+ rc = pChan;
+Away:
+ return rc;
+}
+
+static int
+create_bus(CONTROLVM_MESSAGE *msg, char *buf)
+{
+ U32 busNo, deviceCount;
+ struct bus_info *tmp, *bus;
+ size_t size;
+
+ if (MaxBusCount == BusListCount) {
+ LOGERR("CONTROLVM_BUS_CREATE Failed: max buses:%d already created\n",
+ MaxBusCount);
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, MaxBusCount,
+ POSTCODE_SEVERITY_ERR);
+ return CONTROLVM_RESP_ERROR_MAX_BUSES;
+ }
+
+ busNo = msg->cmd.createBus.busNo;
+ deviceCount = msg->cmd.createBus.deviceCount;
+
+ POSTCODE_LINUX_4(BUS_CREATE_ENTRY_PC, busNo, deviceCount,
+ POSTCODE_SEVERITY_INFO);
+
+ size =
+ sizeof(struct bus_info) +
+ (deviceCount * sizeof(struct device_info *));
+ bus = kzalloc(size, GFP_ATOMIC);
+ if (!bus) {
+ LOGERR("CONTROLVM_BUS_CREATE Failed: kmalloc for bus failed.\n");
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ return CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
+ }
+
+ /* Currently by default, the bus Number is the GuestHandle.
+ * Configure Bus message can override this.
+ */
+ if (msg->hdr.Flags.testMessage) {
+ /* This implies we're the IOVM so set guest handle to 0... */
+ bus->guestHandle = 0;
+ bus->busNo = busNo;
+ bus->localVnic = 1;
+ } else
+ bus->busNo = bus->guestHandle = busNo;
+ sprintf(bus->name, "%d", (int) bus->busNo);
+ bus->deviceCount = deviceCount;
+ bus->device =
+ (struct device_info **) ((char *) bus + sizeof(struct bus_info));
+ bus->busInstGuid = msg->cmd.createBus.busInstGuid;
+ bus->busChannelBytes = 0;
+ bus->pBusChannel = NULL;
+
+ /* add bus to our bus list - but check for duplicates first */
+ read_lock(&BusListLock);
+ for (tmp = BusListHead; tmp; tmp = tmp->next) {
+ if (tmp->busNo == bus->busNo)
+ break;
+ }
+ read_unlock(&BusListLock);
+ if (tmp) {
+ /* found a bus already in the list with same busNo -
+ * reject add
+ */
+ LOGERR("CONTROLVM_BUS_CREATE Failed: bus %d already exists.\n",
+ bus->busNo);
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->busNo,
+ POSTCODE_SEVERITY_ERR);
+ kfree(bus);
+ return CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ }
+ if ((msg->cmd.createBus.channelAddr != 0)
+ && (msg->cmd.createBus.channelBytes != 0)) {
+ bus->busChannelBytes = msg->cmd.createBus.channelBytes;
+ bus->pBusChannel =
+ init_vbus_channel(msg->cmd.createBus.channelAddr,
+ msg->cmd.createBus.channelBytes,
+ msg->hdr.Flags.server);
+ }
+ /* the msg is bound for virtpci; send guest_msgs struct to callback */
+ if (!msg->hdr.Flags.server) {
+ struct guest_msgs cmd;
+ cmd.msgtype = GUEST_ADD_VBUS;
+ cmd.add_vbus.busNo = busNo;
+ cmd.add_vbus.chanptr = bus->pBusChannel;
+ cmd.add_vbus.deviceCount = deviceCount;
+ cmd.add_vbus.busTypeGuid = msg->cmd.createBus.busDataTypeGuid;
+ cmd.add_vbus.busInstGuid = msg->cmd.createBus.busInstGuid;
+ if (!VirtControlChanFunc) {
+ kfree(bus);
+ LOGERR("CONTROLVM_BUS_CREATE Failed: virtpci callback not registered.");
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->busNo,
+ POSTCODE_SEVERITY_ERR);
+ return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+ }
+ if (!VirtControlChanFunc(&cmd)) {
+ kfree(bus);
+ LOGERR("CONTROLVM_BUS_CREATE Failed: virtpci GUEST_ADD_VBUS returned error.");
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->busNo,
+ POSTCODE_SEVERITY_ERR);
+ return
+ CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+ }
+ }
+ create_bus_proc_entries(bus);
+
+ /* add bus at the head of our list */
+ write_lock(&BusListLock);
+ if (!BusListHead)
+ BusListHead = bus;
+ else {
+ bus->next = BusListHead;
+ BusListHead = bus;
+ }
+ BusListCount++;
+ write_unlock(&BusListLock);
+
+ POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, bus->busNo,
+ POSTCODE_SEVERITY_INFO);
+ return CONTROLVM_RESP_SUCCESS;
+}
+
+static int
+destroy_bus(CONTROLVM_MESSAGE *msg, char *buf)
+{
+ int i;
+ struct bus_info *bus, *prev = NULL;
+ U32 busNo;
+
+ busNo = msg->cmd.destroyBus.busNo;
+
+ /* find and delete the bus */
+ read_lock(&BusListLock);
+ for (bus = BusListHead; bus; prev = bus, bus = bus->next) {
+ if (bus->busNo == busNo) {
+ /* found the bus - ensure that all device
+ * slots are NULL
+ */
+ for (i = 0; i < bus->deviceCount; i++) {
+ if (bus->device[i] != NULL) {
+ LOGERR("CONTROLVM_BUS_DESTROY Failed: device %i attached to bus %d.",
+ i, busNo);
+ read_unlock(&BusListLock);
+ return CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED;
+ }
+ }
+ read_unlock(&BusListLock);
+ /* the msg is bound for virtpci; send
+ * guest_msgs struct to callback
+ */
+ if (!msg->hdr.Flags.server) {
+ struct guest_msgs cmd;
+ cmd.msgtype = GUEST_DEL_VBUS;
+ cmd.del_vbus.busNo = busNo;
+ if (!VirtControlChanFunc) {
+ LOGERR("CONTROLVM_BUS_DESTROY Failed: virtpci callback not registered.");
+ return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+ }
+ if (!VirtControlChanFunc(&cmd)) {
+ LOGERR("CONTROLVM_BUS_DESTROY Failed: virtpci GUEST_DEL_VBUS returned error.");
+ return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+ }
+ }
+ /* remove the bus from the list */
+ write_lock(&BusListLock);
+ if (prev) /* not at head */
+ prev->next = bus->next;
+ else
+ BusListHead = bus->next;
+ BusListCount--;
+ write_unlock(&BusListLock);
+ break;
+ }
+ }
+
+ if (!bus) {
+ LOGERR("CONTROLVM_BUS_DESTROY Failed: failed to find bus %d.\n",
+ busNo);
+ read_unlock(&BusListLock);
+ return CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ }
+ if (bus->proc_info) {
+ remove_proc_entry("info", bus->proc_dir);
+ bus->proc_info = NULL;
+ }
+ if (bus->proc_dir) {
+ remove_proc_entry(bus->name, uislib_proc_vbus_dir);
+ bus->proc_dir = NULL;
+ }
+ if (bus->pBusChannel) {
+ uislib_iounmap(bus->pBusChannel);
+ bus->pBusChannel = NULL;
+ }
+
+ kfree(bus);
+ return CONTROLVM_RESP_SUCCESS;
+}
+
+static int
+create_device(CONTROLVM_MESSAGE *msg, char *buf)
+{
+ struct device_info *dev;
+ struct bus_info *bus;
+ U32 busNo, devNo;
+ int result = CONTROLVM_RESP_SUCCESS;
+ U64 minSize = MIN_IO_CHANNEL_SIZE;
+ ReqHandlerInfo_t *pReqHandler;
+
+ busNo = msg->cmd.createDevice.busNo;
+ devNo = msg->cmd.createDevice.devNo;
+
+ POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, devNo, busNo,
+ POSTCODE_SEVERITY_INFO);
+
+ dev = kzalloc(sizeof(struct device_info), GFP_ATOMIC);
+ if (!dev) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: kmalloc for dev failed.\n");
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ return CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
+ }
+
+ dev->channelTypeGuid = msg->cmd.createDevice.dataTypeGuid;
+ dev->intr = msg->cmd.createDevice.intr;
+ dev->channelAddr = msg->cmd.createDevice.channelAddr;
+ dev->busNo = busNo;
+ dev->devNo = devNo;
+ sema_init(&dev->interrupt_callback_lock, 1); /* unlocked */
+ sprintf(dev->devid, "vbus%u:dev%u", (unsigned) busNo, (unsigned) devNo);
+ /* map the channel memory for the device. */
+ if (msg->hdr.Flags.testMessage)
+ dev->chanptr = (void __iomem *)__va(dev->channelAddr);
+ else {
+ pReqHandler = ReqHandlerFind(dev->channelTypeGuid);
+ if (pReqHandler)
+ /* generic service handler registered for this
+ * channel
+ */
+ minSize = pReqHandler->min_channel_bytes;
+ if (minSize > msg->cmd.createDevice.channelBytes) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: channel size is too small, channel size:0x%lx, required size:0x%lx",
+ (ulong) msg->cmd.createDevice.channelBytes,
+ (ulong) minSize);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ result = CONTROLVM_RESP_ERROR_CHANNEL_SIZE_TOO_SMALL;
+ goto Away;
+ }
+ dev->chanptr =
+ uislib_ioremap_cache(dev->channelAddr,
+ msg->cmd.createDevice.channelBytes);
+ if (!dev->chanptr) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: ioremap_cache of channelAddr:%Lx for channelBytes:%llu failed",
+ dev->channelAddr,
+ msg->cmd.createDevice.channelBytes);
+ result = CONTROLVM_RESP_ERROR_IOREMAP_FAILED;
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ goto Away;
+ }
+ }
+ dev->devInstGuid = msg->cmd.createDevice.devInstGuid;
+ dev->channelBytes = msg->cmd.createDevice.channelBytes;
+
+ read_lock(&BusListLock);
+ for (bus = BusListHead; bus; bus = bus->next) {
+ if (bus->busNo == busNo) {
+ /* make sure the device number is valid */
+ if (devNo >= bus->deviceCount) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: device (%d) >= deviceCount (%d).",
+ devNo, bus->deviceCount);
+ result = CONTROLVM_RESP_ERROR_MAX_DEVICES;
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
+ devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ read_unlock(&BusListLock);
+ goto Away;
+ }
+ /* make sure this device is not already set */
+ if (bus->device[devNo]) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: device %d is already exists.",
+ devNo);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
+ devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ result = CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ read_unlock(&BusListLock);
+ goto Away;
+ }
+ read_unlock(&BusListLock);
+ /* the msg is bound for virtpci; send
+ * guest_msgs struct to callback
+ */
+ if (!msg->hdr.Flags.server) {
+ struct guest_msgs cmd;
+ if (!memcmp
+ (&dev->channelTypeGuid,
+ &UltraVhbaChannelProtocolGuid,
+ sizeof(GUID))) {
+ WAIT_FOR_VALID_GUID(((CHANNEL_HEADER
+ __iomem *) (dev->
+ chanptr))->
+ Type);
+ if (!ULTRA_VHBA_CHANNEL_OK_CLIENT
+ (dev->chanptr, NULL)) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed:[CLIENT]VHBA dev %d chan invalid.",
+ devNo);
+ POSTCODE_LINUX_4
+ (DEVICE_CREATE_FAILURE_PC,
+ devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
+ goto Away;
+ }
+ cmd.msgtype = GUEST_ADD_VHBA;
+ cmd.add_vhba.chanptr = dev->chanptr;
+ cmd.add_vhba.busNo = busNo;
+ cmd.add_vhba.deviceNo = devNo;
+ cmd.add_vhba.devInstGuid =
+ dev->devInstGuid;
+ cmd.add_vhba.intr = dev->intr;
+ } else
+ if (!memcmp
+ (&dev->channelTypeGuid,
+ &UltraVnicChannelProtocolGuid,
+ sizeof(GUID))) {
+ WAIT_FOR_VALID_GUID(((CHANNEL_HEADER
+ __iomem *) (dev->
+ chanptr))->
+ Type);
+ if (!ULTRA_VNIC_CHANNEL_OK_CLIENT
+ (dev->chanptr, NULL)) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: VNIC[CLIENT] dev %d chan invalid.",
+ devNo);
+ POSTCODE_LINUX_4
+ (DEVICE_CREATE_FAILURE_PC,
+ devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
+ goto Away;
+ }
+ cmd.msgtype = GUEST_ADD_VNIC;
+ cmd.add_vnic.chanptr = dev->chanptr;
+ cmd.add_vnic.busNo = busNo;
+ cmd.add_vnic.deviceNo = devNo;
+ cmd.add_vnic.devInstGuid =
+ dev->devInstGuid;
+ cmd.add_vhba.intr = dev->intr;
+ } else {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: unknown channelTypeGuid.\n");
+ POSTCODE_LINUX_4
+ (DEVICE_CREATE_FAILURE_PC, devNo,
+ busNo, POSTCODE_SEVERITY_ERR);
+ result = CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
+ goto Away;
+ }
+
+ if (!VirtControlChanFunc) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci callback not registered.");
+ POSTCODE_LINUX_4
+ (DEVICE_CREATE_FAILURE_PC, devNo,
+ busNo, POSTCODE_SEVERITY_ERR);
+ result = CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+ goto Away;
+ }
+
+ if (!VirtControlChanFunc(&cmd)) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci GUEST_ADD_[VHBA||VNIC] returned error.");
+ POSTCODE_LINUX_4
+ (DEVICE_CREATE_FAILURE_PC, devNo,
+ busNo, POSTCODE_SEVERITY_ERR);
+ result = CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+ goto Away;
+ }
+ }
+ bus->device[devNo] = dev;
+ POSTCODE_LINUX_4(DEVICE_CREATE_SUCCESS_PC, devNo, busNo,
+ POSTCODE_SEVERITY_INFO);
+ return CONTROLVM_RESP_SUCCESS;
+ }
+ }
+ read_unlock(&BusListLock);
+
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: failed to find bus %d.", busNo);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ result = CONTROLVM_RESP_ERROR_BUS_INVALID;
+
+Away:
+ if (!msg->hdr.Flags.testMessage) {
+ uislib_iounmap(dev->chanptr);
+ dev->chanptr = NULL;
+ }
+
+ kfree(dev);
+ return result;
+}
+
+static int
+pause_device(CONTROLVM_MESSAGE *msg)
+{
+ U32 busNo, devNo;
+ struct bus_info *bus;
+ struct device_info *dev;
+ struct guest_msgs cmd;
+
+ busNo = msg->cmd.deviceChangeState.busNo;
+ devNo = msg->cmd.deviceChangeState.devNo;
+
+ read_lock(&BusListLock);
+ for (bus = BusListHead; bus; bus = bus->next) {
+ if (bus->busNo == busNo) {
+ /* make sure the device number is valid */
+ if (devNo >= bus->deviceCount) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: device(%d) >= deviceCount(%d).",
+ devNo, bus->deviceCount);
+ read_unlock(&BusListLock);
+ return CONTROLVM_RESP_ERROR_DEVICE_INVALID;
+ }
+ /* make sure this device exists */
+ dev = bus->device[devNo];
+ if (!dev) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: device %d does not exist.",
+ devNo);
+ read_unlock(&BusListLock);
+ return CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ }
+ read_unlock(&BusListLock);
+ /* the msg is bound for virtpci; send
+ * guest_msgs struct to callback
+ */
+ if (!memcmp
+ (&dev->channelTypeGuid,
+ &UltraVhbaChannelProtocolGuid, sizeof(GUID))) {
+ cmd.msgtype = GUEST_PAUSE_VHBA;
+ cmd.pause_vhba.chanptr = dev->chanptr;
+ } else
+ if (!memcmp
+ (&dev->channelTypeGuid,
+ &UltraVnicChannelProtocolGuid,
+ sizeof(GUID))) {
+ cmd.msgtype = GUEST_PAUSE_VNIC;
+ cmd.pause_vnic.chanptr = dev->chanptr;
+ } else {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: unknown channelTypeGuid.\n");
+ return
+ CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
+ }
+
+ if (!VirtControlChanFunc) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE Failed: virtpci callback not registered.");
+ return
+ CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+ }
+
+ if (!VirtControlChanFunc(&cmd)) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: virtpci GUEST_PAUSE_[VHBA||VNIC] returned error.");
+ return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+ }
+ break;
+ }
+ }
+
+ if (!bus) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: bus %d does not exist",
+ busNo);
+ read_unlock(&BusListLock);
+ return CONTROLVM_RESP_ERROR_BUS_INVALID;
+ }
+
+ return CONTROLVM_RESP_SUCCESS;
+}
+
+static int
+resume_device(CONTROLVM_MESSAGE *msg)
+{
+ U32 busNo, devNo;
+ struct bus_info *bus;
+ struct device_info *dev;
+ struct guest_msgs cmd;
+
+ busNo = msg->cmd.deviceChangeState.busNo;
+ devNo = msg->cmd.deviceChangeState.devNo;
+
+ read_lock(&BusListLock);
+ for (bus = BusListHead; bus; bus = bus->next) {
+ if (bus->busNo == busNo) {
+ /* make sure the device number is valid */
+ if (devNo >= bus->deviceCount) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: device(%d) >= deviceCount(%d).",
+ devNo, bus->deviceCount);
+ read_unlock(&BusListLock);
+ return CONTROLVM_RESP_ERROR_DEVICE_INVALID;
+ }
+ /* make sure this device exists */
+ dev = bus->device[devNo];
+ if (!dev) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: device %d does not exist.",
+ devNo);
+ read_unlock(&BusListLock);
+ return CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ }
+ read_unlock(&BusListLock);
+ /* the msg is bound for virtpci; send
+ * guest_msgs struct to callback
+ */
+ if (!memcmp(&dev->channelTypeGuid,
+ &UltraVhbaChannelProtocolGuid,
+ sizeof(GUID))) {
+ cmd.msgtype = GUEST_RESUME_VHBA;
+ cmd.resume_vhba.chanptr = dev->chanptr;
+ } else
+ if (!memcmp(&dev->channelTypeGuid,
+ &UltraVnicChannelProtocolGuid,
+ sizeof(GUID))) {
+ cmd.msgtype = GUEST_RESUME_VNIC;
+ cmd.resume_vnic.chanptr = dev->chanptr;
+ } else {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: unknown channelTypeGuid.\n");
+ return
+ CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
+ }
+
+ if (!VirtControlChanFunc) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE Failed: virtpci callback not registered.");
+ return
+ CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+ }
+
+ if (!VirtControlChanFunc(&cmd)) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: virtpci GUEST_RESUME_[VHBA||VNIC] returned error.");
+ return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+ }
+ break;
+ }
+ }
+
+ if (!bus) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: bus %d does not exist",
+ busNo);
+ read_unlock(&BusListLock);
+ return CONTROLVM_RESP_ERROR_BUS_INVALID;
+ }
+
+ return CONTROLVM_RESP_SUCCESS;
+}
+
+static int
+destroy_device(CONTROLVM_MESSAGE *msg, char *buf)
+{
+ U32 busNo, devNo;
+ struct bus_info *bus;
+ struct device_info *dev;
+ struct guest_msgs cmd;
+
+ busNo = msg->cmd.destroyDevice.busNo;
+ devNo = msg->cmd.destroyDevice.devNo;
+
+ read_lock(&BusListLock);
+ LOGINF("destroy_device called for busNo=%u, devNo=%u", busNo, devNo);
+ for (bus = BusListHead; bus; bus = bus->next) {
+ if (bus->busNo == busNo) {
+ /* make sure the device number is valid */
+ if (devNo >= bus->deviceCount) {
+ LOGERR("CONTROLVM_DEVICE_DESTORY Failed: device(%d) >= deviceCount(%d).",
+ devNo, bus->deviceCount);
+ read_unlock(&BusListLock);
+ return CONTROLVM_RESP_ERROR_DEVICE_INVALID;
+ }
+ /* make sure this device exists */
+ dev = bus->device[devNo];
+ if (!dev) {
+ LOGERR("CONTROLVM_DEVICE_DESTROY Failed: device %d does not exist.",
+ devNo);
+ read_unlock(&BusListLock);
+ return CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ }
+ read_unlock(&BusListLock);
+ /* the msg is bound for virtpci; send
+ * guest_msgs struct to callback
+ */
+ if (!memcmp
+ (&dev->channelTypeGuid,
+ &UltraVhbaChannelProtocolGuid, sizeof(GUID))) {
+ cmd.msgtype = GUEST_DEL_VHBA;
+ cmd.del_vhba.chanptr = dev->chanptr;
+ } else
+ if (!memcmp
+ (&dev->channelTypeGuid,
+ &UltraVnicChannelProtocolGuid,
+ sizeof(GUID))) {
+ cmd.msgtype = GUEST_DEL_VNIC;
+ cmd.del_vnic.chanptr = dev->chanptr;
+ } else {
+ LOGERR("CONTROLVM_DEVICE_DESTROY Failed: unknown channelTypeGuid.\n");
+ return
+ CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
+ }
+
+ if (!VirtControlChanFunc) {
+ LOGERR("CONTROLVM_DEVICE_DESTORY Failed: virtpci callback not registered.");
+ return
+ CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+ }
+
+ if (!VirtControlChanFunc(&cmd)) {
+ LOGERR("CONTROLVM_DEVICE_DESTROY Failed: virtpci GUEST_DEL_[VHBA||VNIC] returned error.");
+ return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+ }
+/* you must disable channel interrupts BEFORE you unmap the channel,
+ * because if you unmap first, there may still be some activity going
+ * on which accesses the channel and you will get a "unable to handle
+ * kernel paging request"
+ */
+ if (dev->polling) {
+ LOGINF("calling uislib_disable_channel_interrupts");
+ uislib_disable_channel_interrupts(busNo, devNo);
+ }
+ /* unmap the channel memory for the device. */
+ if (!msg->hdr.Flags.testMessage) {
+ LOGINF("destroy_device, doing iounmap");
+ uislib_iounmap(dev->chanptr);
+ }
+ kfree(dev);
+ bus->device[devNo] = NULL;
+ break;
+ }
+ }
+
+ if (!bus) {
+ LOGERR("CONTROLVM_DEVICE_DESTROY Failed: bus %d does not exist",
+ busNo);
+ read_unlock(&BusListLock);
+ return CONTROLVM_RESP_ERROR_BUS_INVALID;
+ }
+
+ return CONTROLVM_RESP_SUCCESS;
+}
+
+static int
+init_chipset(CONTROLVM_MESSAGE *msg, char *buf)
+{
+ POSTCODE_LINUX_2(CHIPSET_INIT_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+
+ MaxBusCount = msg->cmd.initChipset.busCount;
+ PlatformNumber = msg->cmd.initChipset.platformNumber;
+ PhysicalDataChan = 0;
+
+ /* We need to make sure we have our functions registered
+ * before processing messages. If we are a test vehicle the
+ * testMessage for init_chipset will be set. We can ignore the
+ * waits for the callbacks, since this will be manually entered
+ * from a user. If no testMessage is set, we will wait for the
+ * functions.
+ */
+ if (!msg->hdr.Flags.testMessage)
+ WAIT_ON_CALLBACK(VirtControlChanFunc);
+
+ chipset_inited = 1;
+ POSTCODE_LINUX_2(CHIPSET_INIT_EXIT_PC, POSTCODE_SEVERITY_INFO);
+
+ return CONTROLVM_RESP_SUCCESS;
+}
+
+static int
+stop_chipset(CONTROLVM_MESSAGE *msg, char *buf)
+{
+ /* Check that all buses and switches have been torn down and
+ * destroyed.
+ */
+ if (BusListHead) {
+ /* Buses still exist. */
+ LOGERR("CONTROLVM_CHIPSET_STOP: BusListHead is not NULL");
+ return CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_BUS;
+ }
+ if (BusListCount) {
+ /* BusListHead is NULL, but BusListCount != 0 */
+ LOGERR("CONTROLVM_CHIPSET_STOP: BusListCount != 0");
+ return CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_BUS;
+ }
+
+ /* Buses are shut down. */
+ return visorchipset_chipset_notready();
+}
+
+static int
+delete_bus_glue(U32 busNo)
+{
+ CONTROLVM_MESSAGE msg;
+
+ init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, 0);
+ msg.cmd.destroyBus.busNo = busNo;
+ if (destroy_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("destroy_bus failed. busNo=0x%x\n", busNo);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+delete_device_glue(U32 busNo, U32 devNo)
+{
+ CONTROLVM_MESSAGE msg;
+
+ init_msg_header(&msg, CONTROLVM_DEVICE_DESTROY, 0, 0);
+ msg.cmd.destroyDevice.busNo = busNo;
+ msg.cmd.destroyDevice.devNo = devNo;
+ if (destroy_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("destroy_device failed. busNo=0x%x devNo=0x%x\n", busNo,
+ devNo);
+ return 0;
+ }
+ return 1;
+}
+
+int
+uislib_client_inject_add_bus(U32 busNo, GUID instGuid,
+ U64 channelAddr, ulong nChannelBytes)
+{
+ CONTROLVM_MESSAGE msg;
+
+ LOGINF("enter busNo=0x%x\n", busNo);
+ /* step 0: init the chipset */
+ POSTCODE_LINUX_3(CHIPSET_INIT_ENTRY_PC, busNo, POSTCODE_SEVERITY_INFO);
+
+ if (!chipset_inited) {
+ /* step: initialize the chipset */
+ init_msg_header(&msg, CONTROLVM_CHIPSET_INIT, 0, 0);
+ /* this change is needed so that console will come up
+ * OK even when the bus 0 create comes in late. If the
+ * bus 0 create is the first create, then the add_vnic
+ * will work fine, but if the bus 0 create arrives
+ * after number 4, then the add_vnic will fail, and the
+ * ultraboot will fail.
+ */
+ msg.cmd.initChipset.busCount = 23;
+ msg.cmd.initChipset.switchCount = 0;
+ if (init_chipset(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("init_chipset failed.\n");
+ return 0;
+ }
+ LOGINF("chipset initialized\n");
+ POSTCODE_LINUX_3(CHIPSET_INIT_EXIT_PC, busNo,
+ POSTCODE_SEVERITY_INFO);
+ }
+
+ /* step 1: create a bus */
+ POSTCODE_LINUX_3(BUS_CREATE_ENTRY_PC, busNo, POSTCODE_SEVERITY_WARNING);
+ init_msg_header(&msg, CONTROLVM_BUS_CREATE, 0, 0);
+ msg.cmd.createBus.busNo = busNo;
+ msg.cmd.createBus.deviceCount = 23; /* devNo+1; */
+ msg.cmd.createBus.channelAddr = channelAddr;
+ msg.cmd.createBus.channelBytes = nChannelBytes;
+ if (create_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("create_bus failed.\n");
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ return 0;
+ }
+ POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, busNo, POSTCODE_SEVERITY_INFO);
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(uislib_client_inject_add_bus);
+
+
+int
+uislib_client_inject_del_bus(U32 busNo)
+{
+ return delete_bus_glue(busNo);
+}
+EXPORT_SYMBOL_GPL(uislib_client_inject_del_bus);
+
+int
+uislib_client_inject_pause_vhba(U32 busNo, U32 devNo)
+{
+ CONTROLVM_MESSAGE msg;
+ int rc;
+
+ init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0);
+ msg.cmd.deviceChangeState.busNo = busNo;
+ msg.cmd.deviceChangeState.devNo = devNo;
+ msg.cmd.deviceChangeState.state = SegmentStateStandby;
+ rc = pause_device(&msg);
+ if (rc != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("VHBA pause_device failed. busNo=0x%x devNo=0x%x\n",
+ busNo, devNo);
+ return rc;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uislib_client_inject_pause_vhba);
+
+int
+uislib_client_inject_resume_vhba(U32 busNo, U32 devNo)
+{
+ CONTROLVM_MESSAGE msg;
+ int rc;
+
+ init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0);
+ msg.cmd.deviceChangeState.busNo = busNo;
+ msg.cmd.deviceChangeState.devNo = devNo;
+ msg.cmd.deviceChangeState.state = SegmentStateRunning;
+ rc = resume_device(&msg);
+ if (rc != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("VHBA resume_device failed. busNo=0x%x devNo=0x%x\n",
+ busNo, devNo);
+ return rc;
+ }
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(uislib_client_inject_resume_vhba);
+
+int
+uislib_client_inject_add_vhba(U32 busNo, U32 devNo,
+ U64 phys_chan_addr, U32 chan_bytes,
+ int is_test_addr, GUID instGuid,
+ struct InterruptInfo *intr)
+{
+ CONTROLVM_MESSAGE msg;
+
+ LOGINF(" enter busNo=0x%x devNo=0x%x\n", busNo, devNo);
+ /* chipset init'ed with bus bus has been previously created -
+ * Verify it still exists step 2: create the VHBA device on the
+ * bus
+ */
+ POSTCODE_LINUX_4(VHBA_CREATE_ENTRY_PC, devNo, busNo,
+ POSTCODE_SEVERITY_INFO);
+
+ init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, 0);
+ if (is_test_addr)
+ /* signify that the physical channel address does NOT
+ * need to be ioremap()ed
+ */
+ msg.hdr.Flags.testMessage = 1;
+ msg.cmd.createDevice.busNo = busNo;
+ msg.cmd.createDevice.devNo = devNo;
+ msg.cmd.createDevice.devInstGuid = instGuid;
+ if (intr)
+ msg.cmd.createDevice.intr = *intr;
+ else
+ memset(&msg.cmd.createDevice.intr, 0,
+ sizeof(struct InterruptInfo));
+ msg.cmd.createDevice.channelAddr = phys_chan_addr;
+ if (chan_bytes < MIN_IO_CHANNEL_SIZE) {
+ LOGERR("wrong channel size.chan_bytes = 0x%x IO_CHANNEL_SIZE= 0x%x\n",
+ chan_bytes, (unsigned int) MIN_IO_CHANNEL_SIZE);
+ POSTCODE_LINUX_4(VHBA_CREATE_FAILURE_PC, chan_bytes,
+ MIN_IO_CHANNEL_SIZE, POSTCODE_SEVERITY_ERR);
+ return 0;
+ }
+ msg.cmd.createDevice.channelBytes = chan_bytes;
+ msg.cmd.createDevice.dataTypeGuid = UltraVhbaChannelProtocolGuid;
+ if (create_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("VHBA create_device failed.\n");
+ POSTCODE_LINUX_4(VHBA_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ return 0;
+ }
+ POSTCODE_LINUX_4(VHBA_CREATE_SUCCESS_PC, devNo, busNo,
+ POSTCODE_SEVERITY_INFO);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(uislib_client_inject_add_vhba);
+
+int
+uislib_client_inject_del_vhba(U32 busNo, U32 devNo)
+{
+ return delete_device_glue(busNo, devNo);
+}
+EXPORT_SYMBOL_GPL(uislib_client_inject_del_vhba);
+
+int
+uislib_client_inject_add_vnic(U32 busNo, U32 devNo,
+ U64 phys_chan_addr, U32 chan_bytes,
+ int is_test_addr, GUID instGuid,
+ struct InterruptInfo *intr)
+{
+ CONTROLVM_MESSAGE msg;
+
+ LOGINF(" enter busNo=0x%x devNo=0x%x\n", busNo, devNo);
+ /* chipset init'ed with bus bus has been previously created -
+ * Verify it still exists step 2: create the VNIC device on the
+ * bus
+ */
+ POSTCODE_LINUX_4(VNIC_CREATE_ENTRY_PC, devNo, busNo,
+ POSTCODE_SEVERITY_INFO);
+
+ init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, 0);
+ if (is_test_addr)
+ /* signify that the physical channel address does NOT
+ * need to be ioremap()ed
+ */
+ msg.hdr.Flags.testMessage = 1;
+ msg.cmd.createDevice.busNo = busNo;
+ msg.cmd.createDevice.devNo = devNo;
+ msg.cmd.createDevice.devInstGuid = instGuid;
+ if (intr)
+ msg.cmd.createDevice.intr = *intr;
+ else
+ memset(&msg.cmd.createDevice.intr, 0,
+ sizeof(struct InterruptInfo));
+ msg.cmd.createDevice.channelAddr = phys_chan_addr;
+ if (chan_bytes < MIN_IO_CHANNEL_SIZE) {
+ LOGERR("wrong channel size.chan_bytes = 0x%x IO_CHANNEL_SIZE= 0x%x\n",
+ chan_bytes, (unsigned int) MIN_IO_CHANNEL_SIZE);
+ POSTCODE_LINUX_4(VNIC_CREATE_FAILURE_PC, chan_bytes,
+ MIN_IO_CHANNEL_SIZE, POSTCODE_SEVERITY_ERR);
+ return 0;
+ }
+ msg.cmd.createDevice.channelBytes = chan_bytes;
+ msg.cmd.createDevice.dataTypeGuid = UltraVnicChannelProtocolGuid;
+ if (create_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("VNIC create_device failed.\n");
+ POSTCODE_LINUX_4(VNIC_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ return 0;
+ }
+
+ POSTCODE_LINUX_4(VNIC_CREATE_SUCCESS_PC, devNo, busNo,
+ POSTCODE_SEVERITY_INFO);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(uislib_client_inject_add_vnic);
+
+int
+uislib_client_inject_pause_vnic(U32 busNo, U32 devNo)
+{
+ CONTROLVM_MESSAGE msg;
+ int rc;
+
+ init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0);
+ msg.cmd.deviceChangeState.busNo = busNo;
+ msg.cmd.deviceChangeState.devNo = devNo;
+ msg.cmd.deviceChangeState.state = SegmentStateStandby;
+ rc = pause_device(&msg);
+ if (rc != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("VNIC pause_device failed. busNo=0x%x devNo=0x%x\n",
+ busNo, devNo);
+ return -1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uislib_client_inject_pause_vnic);
+
+int
+uislib_client_inject_resume_vnic(U32 busNo, U32 devNo)
+{
+ CONTROLVM_MESSAGE msg;
+ int rc;
+
+ init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0);
+ msg.cmd.deviceChangeState.busNo = busNo;
+ msg.cmd.deviceChangeState.devNo = devNo;
+ msg.cmd.deviceChangeState.state = SegmentStateRunning;
+ rc = resume_device(&msg);
+ if (rc != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("VNIC resume_device failed. busNo=0x%x devNo=0x%x\n",
+ busNo, devNo);
+ return -1;
+ }
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(uislib_client_inject_resume_vnic);
+
+int
+uislib_client_inject_del_vnic(U32 busNo, U32 devNo)
+{
+ return delete_device_glue(busNo, devNo);
+}
+EXPORT_SYMBOL_GPL(uislib_client_inject_del_vnic);
+
+static int
+uislib_client_add_vnic(U32 busNo)
+{
+ BOOL busCreated = FALSE;
+ int devNo = 0; /* Default to 0, since only one device
+ * will be created for this bus... */
+ GUID dummyGuid = GUID0;
+ CONTROLVM_MESSAGE msg;
+
+ init_msg_header(&msg, CONTROLVM_BUS_CREATE, 0, 0);
+ msg.hdr.Flags.testMessage = 1;
+ msg.cmd.createBus.busNo = busNo;
+ msg.cmd.createBus.deviceCount = 4;
+ msg.cmd.createBus.channelAddr = 0;
+ msg.cmd.createBus.channelBytes = 0;
+ if (create_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("client create_bus failed");
+ return 0;
+ }
+ busCreated = TRUE;
+
+ init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, 0);
+ msg.hdr.Flags.testMessage = 1;
+ msg.cmd.createDevice.busNo = busNo;
+ msg.cmd.createDevice.devNo = devNo;
+ msg.cmd.createDevice.devInstGuid = dummyGuid;
+ memset(&msg.cmd.createDevice.intr, 0, sizeof(struct InterruptInfo));
+ msg.cmd.createDevice.channelAddr = PhysicalDataChan;
+ msg.cmd.createDevice.channelBytes = MIN_IO_CHANNEL_SIZE;
+ msg.cmd.createDevice.dataTypeGuid = UltraVnicChannelProtocolGuid;
+ if (create_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("client create_device failed");
+ goto AwayCleanup;
+ }
+
+ return 1;
+
+AwayCleanup:
+ if (busCreated) {
+ init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, 0);
+ msg.hdr.Flags.testMessage = 1;
+ msg.cmd.destroyBus.busNo = busNo;
+ if (destroy_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS)
+ LOGERR("client destroy_bus failed.\n");
+ }
+
+ return 0;
+} /* end uislib_client_add_vnic */
+EXPORT_SYMBOL_GPL(uislib_client_add_vnic);
+
+static int
+uislib_client_delete_vnic(U32 busNo)
+{
+ int devNo = 0; /* Default to 0, since only one device
+ * will be created for this bus... */
+ CONTROLVM_MESSAGE msg;
+
+ init_msg_header(&msg, CONTROLVM_DEVICE_DESTROY, 0, 0);
+ msg.hdr.Flags.testMessage = 1;
+ msg.cmd.destroyDevice.busNo = busNo;
+ msg.cmd.destroyDevice.devNo = devNo;
+ if (destroy_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+ /* Don't error exit - try to see if bus can be destroyed... */
+ LOGERR("client destroy_device failed.\n");
+ }
+
+ init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, 0);
+ msg.hdr.Flags.testMessage = 1;
+ msg.cmd.destroyBus.busNo = busNo;
+ if (destroy_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS)
+ LOGERR("client destroy_bus failed.\n");
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(uislib_client_delete_vnic);
+/* end client_delete_vnic */
+
+void *
+uislib_cache_alloc(struct kmem_cache *cur_pool, char *fn, int ln)
+{
+ /* __GFP_NORETRY means "ok to fail", meaning kmalloc() can
+ * return NULL. If you do NOT specify __GFP_NORETRY, Linux
+ * will go to extreme measures to get memory for you (like,
+ * invoke oom killer), which will probably cripple the system.
+ */
+ void *p = kmem_cache_alloc(cur_pool, GFP_ATOMIC | __GFP_NORETRY);
+ if (p == NULL) {
+ LOGERR("uislib_malloc failed to alloc uiscmdrsp @%s:%d",
+ fn, ln);
+ return NULL;
+ }
+ return p;
+}
+EXPORT_SYMBOL_GPL(uislib_cache_alloc);
+
+void
+uislib_cache_free(struct kmem_cache *cur_pool, void *p, char *fn, int ln)
+{
+ if (p == NULL) {
+ LOGERR("uislib_free NULL pointer @%s:%d", fn, ln);
+ return;
+ }
+ kmem_cache_free(cur_pool, p);
+}
+EXPORT_SYMBOL_GPL(uislib_cache_free);
+
+/*****************************************************/
+/* proc filesystem callback functions */
+/*****************************************************/
+
+static ssize_t
+vnic_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ int action = 0xffff, busNo = 0, i, result = 0;
+ char buf[4];
+ char direction;
+/* GUID guid; */
+ if (count >= ARRAY_SIZE(buf))
+ return -EINVAL;
+
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("echo > /proc/uislib/vnic copy_from_user ****FAILED.\n");
+ return -EFAULT;
+ }
+
+ i = sscanf(buf, "%d%c", &action, &direction);
+ if (i != 2) {
+ LOGERR("unable to parse vnic proc parameters.\n");
+ return -EFAULT;
+ }
+
+ if ((direction != '-') && (direction != '+')) {
+ LOGERR("unable to determine whether to add or delete vnic\n");
+ return -EFAULT;
+ }
+
+ /* if (i < 1), i.e., if we didn't even read the action field,
+ * then action will default to 0xffff and the code below will
+ * fall through the switch and print usage.
+ */
+ switch (action) {
+ case 0:
+ /* call client method... */
+ busNo = 0; /* All client drivers use bus value of 0... */
+ if (direction == '+')
+ result = uislib_client_add_vnic(busNo);
+ else
+ result = uislib_client_delete_vnic(busNo);
+ if (!result) {
+ LOGERR("echo 0%c > /proc/uislib/vnic failed (client end)",
+ direction);
+ return -EFAULT;
+ }
+ return count;
+
+ default:
+ break;
+ }
+
+ LOGERR("USAGE: echo <action><direction (up/down)> > /proc/uislib/vnic");
+ LOGERR(" ");
+ LOGERR("Client Syntax");
+ LOGERR("-------------");
+ LOGERR("0+ ==> add vnic");
+ LOGERR("0- ==> delete vnic");
+ LOGERR(" ");
+ return count;
+} /* end vnic_proc_write */
+
+static ssize_t
+chipset_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ int i, action = 0xffff;
+ char buf[4];
+ CONTROLVM_MESSAGE msg;
+
+ if (count >= ARRAY_SIZE(buf))
+ return -EINVAL;
+
+ memset(&msg, 0, sizeof(CONTROLVM_MESSAGE));
+
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("copy_from_user ****FAILED.\n");
+ return -EFAULT;
+ }
+
+ if (chipset_inited) {
+ LOGINF("Chipset already initialized\n");
+ return -EFAULT;
+ }
+ i = sscanf(buf, "%x", &action);
+
+ /* if (i < 1), i.e., if we didn't even read the action field,
+ * then action will default to 0xffff and the code below will
+ * fall through the switch and print usage.
+ */
+ switch (action) {
+ case 1:
+ /* GUEST */
+ /* step: initialize the chipset */
+ init_msg_header(&msg, CONTROLVM_CHIPSET_INIT, 0, 0);
+ msg.hdr.Flags.testMessage = 0;
+ msg.cmd.initChipset.busCount = 23;
+ msg.cmd.initChipset.switchCount = 23;
+
+ if (init_chipset(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("init_chipset failed.\n");
+ return 0;
+ }
+ return 1;
+ case 2:
+ /* BOTH */
+ init_msg_header(&msg, CONTROLVM_CHIPSET_INIT, 0, 0);
+ msg.hdr.Flags.testMessage = 1;
+ msg.cmd.initChipset.busCount = 23;
+ msg.cmd.initChipset.switchCount = 23;
+
+ if (init_chipset(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("init_chipset failed.\n");
+ return 0;
+ }
+ return 1;
+
+ default:
+ break;
+ }
+
+ LOGERR("usage: 1 ==> init_chipset client\n");
+ LOGERR("usage: 2 ==> init_chipset test\n");
+ return -EFAULT;
+}
+
+#define PLINE(...) uisutil_add_proc_line_ex(&tot, buff, \
+ buff_len, __VA_ARGS__)
+
+static int
+info_proc_read_helper(char **buff, int *buff_len)
+{
+ int i, tot = 0;
+ struct bus_info *bus;
+
+ if (PLINE("\nBuses:\n") < 0)
+ goto err_done;
+
+ read_lock(&BusListLock);
+ for (bus = BusListHead; bus; bus = bus->next) {
+
+ if (PLINE(" bus=0x%p, busNo=%d, deviceCount=%d\n",
+ bus, bus->busNo, bus->deviceCount) < 0)
+ goto err_done_unlock;
+
+
+ if (PLINE(" Devices:\n") < 0)
+ goto err_done_unlock;
+
+ for (i = 0; i < bus->deviceCount; i++) {
+ if (bus->device[i]) {
+ if (PLINE(" busNo %d, device[%i]: 0x%p, chanptr=0x%p, swtch=0x%p\n",
+ bus->busNo, i, bus->device[i],
+ bus->device[i]->chanptr,
+ bus->device[i]->swtch) < 0)
+ goto err_done_unlock;
+
+ if (PLINE(" first_busy_cnt=%llu, moved_to_tail_cnt=%llu, last_on_list_cnt=%llu\n",
+ bus->device[i]->first_busy_cnt,
+ bus->device[i]->moved_to_tail_cnt,
+ bus->device[i]->last_on_list_cnt) < 0)
+ goto err_done_unlock;
+ }
+ }
+ }
+ read_unlock(&BusListLock);
+
+ if (PLINE("UisUtils_Registered_Services: %d\n",
+ atomic_read(&UisUtils_Registered_Services)) < 0)
+ goto err_done;
+ if (PLINE("cycles_before_wait %llu wait_cycles:%llu\n",
+ cycles_before_wait, wait_cycles) < 0)
+ goto err_done;
+ if (PLINE("tot_wakeup_cnt %llu:tot_wait_cnt %llu:tot_schedule_cnt %llu\n",
+ tot_wakeup_cnt, tot_wait_cnt, tot_schedule_cnt) < 0)
+ goto err_done;
+ if (PLINE("en_smart_wakeup %d\n", en_smart_wakeup) < 0)
+ goto err_done;
+ if (PLINE("tot_moved_to_tail_cnt %llu\n", tot_moved_to_tail_cnt) < 0)
+ goto err_done;
+
+ return tot;
+
+err_done_unlock:
+ read_unlock(&BusListLock);
+err_done:
+ return -1;
+}
+
+static ssize_t
+info_proc_read(struct file *file, char __user *buf, size_t len, loff_t *offset)
+{
+ char *temp;
+ int totalBytes = 0;
+ int remaining_bytes = PROC_READ_BUFFER_SIZE;
+
+/* *start = buf; */
+ if (ProcReadBuffer == NULL) {
+ DBGINF("ProcReadBuffer == NULL; allocating buffer.\n.");
+ ProcReadBuffer = vmalloc(PROC_READ_BUFFER_SIZE);
+
+ if (ProcReadBuffer == NULL) {
+ LOGERR("failed to allocate buffer to provide proc data.\n");
+ return -ENOMEM;
+ }
+ }
+
+ temp = ProcReadBuffer;
+
+ if ((*offset == 0) || (!ProcReadBufferValid)) {
+ DBGINF("calling info_proc_read_helper.\n");
+ /* if the read fails, then -1 will be returned */
+ totalBytes = info_proc_read_helper(&temp, &remaining_bytes);
+ ProcReadBufferValid = 1;
+ } else
+ totalBytes = strlen(ProcReadBuffer);
+
+ return simple_read_from_buffer(buf, len, offset,
+ ProcReadBuffer, totalBytes);
+}
+
+static ssize_t
+platformnumber_proc_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ int length = 0;
+ char *vbuf;
+ loff_t pos = *offset;
+
+ if (pos < 0)
+ return -EINVAL;
+
+ if (pos > 0 || !len)
+ return 0;
+
+ vbuf = kzalloc(len, GFP_KERNEL);
+ if (!vbuf)
+ return -ENOMEM;
+
+ length = sprintf(vbuf, "%d\n", PlatformNumber);
+
+ if (copy_to_user(buf, vbuf, length)) {
+ kfree(vbuf);
+ return -EFAULT;
+ }
+
+ kfree(vbuf);
+ *offset += length;
+ return length;
+}
+
+#ifdef UISLIB_TEST_PROC
+
+/* proc/uislib/vbus/<x>/info */
+static int
+proc_info_vbus_show(struct seq_file *m, void *v)
+{
+ struct bus_info *bus = m->private;
+ int i, devInfoCount, x;
+ char buf[999];
+
+ if (bus == NULL)
+ return 0;
+ seq_printf(m, "Client device / client driver info for %s partition (vbus #%d):\n",
+ bus->partitionName, bus->busNo);
+ if ((bus->busChannelBytes == 0) || (bus->pBusChannel == NULL))
+ return 0;
+ devInfoCount =
+ (bus->busChannelBytes -
+ sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL)) /
+ sizeof(ULTRA_VBUS_DEVICEINFO);
+ x = VBUSCHANNEL_devInfoToStringBuffer(&bus->pBusChannel->ChpInfo, buf,
+ sizeof(buf) - 1, -1);
+ buf[x] = '\0';
+ seq_printf(m, "%s", buf);
+ x = VBUSCHANNEL_devInfoToStringBuffer(&bus->pBusChannel->BusInfo,
+ buf, sizeof(buf) - 1, -1);
+ buf[x] = '\0';
+ seq_printf(m, "%s", buf);
+ for (i = 0; i < devInfoCount; i++) {
+ x = VBUSCHANNEL_devInfoToStringBuffer(&bus->pBusChannel->
+ DevInfo[i], buf,
+ sizeof(buf) - 1, i);
+ if (x > 0) {
+ buf[x] = '\0';
+ seq_printf(m, "%s", buf);
+ }
+ }
+ return 0;
+}
+
+static ssize_t
+bus_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ int server_flag = 0;
+ int i, action = 0xffff, result;
+ char buf[16];
+ CONTROLVM_MESSAGE msg;
+ U32 busNo, deviceCount;
+
+ if (count >= ARRAY_SIZE(buf))
+ return -EINVAL;
+
+ memset(&msg, 0, sizeof(CONTROLVM_MESSAGE));
+
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("echo > /proc/uislib/bus: copy_from_user ****FAILED.");
+ return -EFAULT;
+ }
+
+ i = sscanf(buf, "%x-%d-%d", &action, &busNo, &deviceCount);
+
+ /* if (i < 1), i.e., if we didn't even read the action field,
+ * then action will default to 0xffff and the code below will
+ * fall through the switch and print usage.
+ */
+ switch (action) {
+ case 0:
+ /* destroy a bus */
+ if (i != 2)
+ break;
+ init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, server_flag);
+ msg.cmd.destroyBus.busNo = busNo;
+
+ result = destroy_bus(&msg, NULL);
+
+ if (result != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("echo 0-%d > /proc/uislib/bus {CONTROLVM_BUS_DESTROY Failed} Result(%d)",
+ busNo, result);
+ return -EFAULT;
+ }
+ return count;
+ case 1:
+ /* create a bus */
+ if (i != 3)
+ break;
+ init_msg_header(&msg, CONTROLVM_BUS_CREATE, 0, server_flag);
+ msg.cmd.createBus.busNo = busNo;
+ msg.cmd.createBus.deviceCount = deviceCount;
+
+ result = create_bus(&msg, NULL);
+
+ if (result != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("echo 1-%d-%d > /proc/uislib/bus {CONTROLVM_BUS_CREATE Failed} Result(%d)",
+ busNo, deviceCount, result);
+ return -EFAULT;
+ }
+
+ return count;
+ default:
+ break;
+ }
+
+ LOGERR("USAGE: echo <action>-<busNo>... > /proc/uislib/bus");
+ LOGERR(" ");
+ LOGERR("Destruct Syntax ControlVM Message Id");
+ LOGERR("--------------- ---------------------");
+ LOGERR("0-<busNo> ==> CONTROLVM_BUS_DESTROY");
+ LOGERR(" ");
+ LOGERR("Construct Syntax ControlVM Message Id");
+ LOGERR("----------------------- -------------------- ");
+ LOGERR("1-<busNo>-<deviceCount> ==> CONTROLVM_BUS_CREATE");
+
+ return -EFAULT;
+}
+
+static ssize_t
+uislib_proc_read_writeonly(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ return 0;
+}
+
+static ssize_t
+dev_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ int server_flag = 0;
+ CONTROLVM_MESSAGE msg;
+ U32 busNo, devNo;
+ char buf[32];
+ unsigned int chanptr;
+ int type, i, action = 0xffff, result;
+
+ if (count >= ARRAY_SIZE(buf))
+ return -EINVAL;
+
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("echo > /proc/uislib/device: copy_from_user ****FAILED.");
+ return -EFAULT;
+ }
+
+ i = sscanf(buf, "%x-%d-%d-%x-%d",
+ &action, &busNo, &devNo, &chanptr, &type);
+
+ switch (action) {
+ case 0:
+ if (i != 3)
+ break;
+
+ /* destroy a device */
+ init_msg_header(&msg, CONTROLVM_DEVICE_DESTROY, 0, server_flag);
+ msg.cmd.destroyDevice.busNo = busNo;
+ msg.cmd.destroyDevice.devNo = devNo;
+
+ result = destroy_device(&msg, NULL);
+
+ if (result != CONTROLVM_RESP_SUCCESS) {
+ LOGERR("echo 0-%d-%d > /proc/uislib/device {CONTROLVM_DEVICE_DESTROY Failed} Result(%d)",
+ busNo, devNo, result);
+ return -EFAULT;
+ }
+
+ return count;
+
+ case 1:
+ if (i != 5)
+ break;
+
+ /* create a device */
+ init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, server_flag);
+ msg.cmd.createDevice.busNo = busNo;
+ msg.cmd.createDevice.devNo = devNo;
+ msg.cmd.createDevice.channelAddr = __pa(chanptr);
+ msg.cmd.createDevice.channelBytes = MIN_IO_CHANNEL_SIZE;
+
+ if (type == 0)
+ msg.cmd.createDevice.dataTypeGuid =
+ UltraVhbaChannelProtocolGuid;
+ else if (type == 1)
+ msg.cmd.createDevice.dataTypeGuid =
+ UltraVnicChannelProtocolGuid;
+ else {
+ LOGERR("echo 1-%d-%d-%x-<type> > /proc/uislib/devce failed: invalid device type %d.",
+ busNo, devNo, chanptr, type);
+ return -EFAULT;
+ }
+
+ result = create_device(&msg, NULL);
+
+ if (result != CONTROLVM_RESP_SUCCESS) {
+ if (type == 0)
+ LOGERR("echo 1-%d-%d-%x-0 > /proc/uislib/device {CONTROLVM_DEVICE_CREATE[vHBA] Failed} Result(%d)",
+ busNo, devNo, chanptr, result);
+ else
+ LOGERR("echo 1-%d-%d-%x-1 > /proc/uislib/device {CONTROLVM_DEVICE_CREATE[vNIC] Failed} Result(%d)",
+ busNo, devNo, chanptr, result);
+ return -EFAULT;
+ }
+
+ default:
+ break;
+ }
+
+ LOGERR("USAGE: echo <action>-<busNo>-<devNo>... > /proc/uislib/device");
+ LOGERR(" ");
+ LOGERR("Destruct Syntax ControlVM Message Id");
+ LOGERR("----------------- ------------------------");
+ LOGERR("0-<busNo>-<devNo> ==> CONTROLVM_DEVICE_DESTROY");
+ LOGERR(" ");
+ LOGERR("Construct Syntax ControlVM Message Id");
+ LOGERR
+ ("---------------------------------- ----------------------- ");
+ LOGERR
+ ("1-<busNo>-<devNo>-<chanptr>-<type> ==> CONTROLVM_DEVICE_CREATE");
+ LOGERR(" <type = 0>: vHBA");
+ LOGERR(" <type = 1>: vNIC");
+ LOGERR(" ");
+
+ return -EFAULT;
+}
+
+static ssize_t
+cycles_before_wait_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char buf[16];
+
+#define CYCLES_BEFORE_WAIT_USE_ERROR { \
+ LOGERR("Incorrect Call Home Input.\n"); \
+ pr_info("Please pass Call Home Event Parameters in the form:\n"); \
+ pr_info("EventID Category Type[parameter1][parameter2][parameter3][parameter4][parameter5][parameter6]\n"); \
+ return -EFAULT; \
+}
+ if (count >= ARRAY_SIZE(buf))
+ return -EINVAL;
+
+ if (count == 0)
+ CYCLES_BEFORE_WAIT_USE_ERROR;
+
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("copy_from_user failed.\n");
+ return -EFAULT;
+ }
+ buf[count - 1] = '\0'; /* Replace the LF at the end of the
+ * input with a NULL */
+ /* Pull out the cycles_before_wait must be decimal integer */
+ if (sscanf(buf, "%lld", &cycles_before_wait) != 1)
+ CYCLES_BEFORE_WAIT_USE_ERROR;
+
+ return count;
+}
+
+static ssize_t
+reset_counts_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char buf[16];
+ unsigned long long new_value;
+ struct bus_info *bus;
+ int i;
+
+#define RESET_COUNTS_USE_ERROR { \
+ LOGERR("Incorrect reset_counts Input.\n"); \
+ pr_info("Please pass the new value for the counters:\n"); \
+ pr_info("e.g. echo 0 > reset_counts\n"); \
+ return -EFAULT; \
+ }
+
+ if (count >= ARRAY_SIZE(buf))
+ return -EINVAL;
+
+ if (count == 0)
+ RESET_COUNTS_USE_ERROR;
+
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("copy_from_user failed.\n");
+ return -EFAULT;
+ }
+ buf[count - 1] = '\0'; /* Replace the LF at the end of the
+ * input with a NULL */
+ /* Pull out the reset_counts must be decimal integer */
+ if (sscanf(buf, "%llu", &new_value) != 1)
+ RESET_COUNTS_USE_ERROR;
+ read_lock(&BusListLock);
+ for (bus = BusListHead; bus; bus = bus->next) {
+
+ for (i = 0; i < bus->deviceCount; i++) {
+ if (bus->device[i]) {
+ bus->device[i]->first_busy_cnt = new_value;
+ bus->device[i]->moved_to_tail_cnt = new_value;
+ bus->device[i]->last_on_list_cnt = new_value;
+ }
+ }
+ }
+ read_unlock(&BusListLock);
+ tot_moved_to_tail_cnt = new_value;
+ tot_wait_cnt = new_value;
+ tot_wakeup_cnt = new_value;
+ tot_schedule_cnt = new_value;
+ return count;
+}
+
+static ssize_t
+smart_wakeup_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char buf[16];
+ int new_value;
+
+#define SMART_WAKEUP_USE_ERROR { \
+ LOGERR("Incorrect smart_wakeup Input 0 disables smart_wakeup, and 1 enables smart_wakeup.\n"); \
+ pr_info("echo 0 > smart_wakeup\n"); \
+ pr_info("echo 1 > smart_wakeup\n"); \
+ return -EFAULT; \
+ }
+
+ if (count >= ARRAY_SIZE(buf))
+ return -EINVAL;
+
+ if (count == 0)
+ SMART_WAKEUP_USE_ERROR;
+
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("copy_from_user failed.\n");
+ return -EFAULT;
+ }
+ buf[count - 1] = '\0'; /* Replace the LF at the end of the
+ * input with a NULL */
+ /* Pull out the smart_wakeup must be decimal integer */
+ if (sscanf(buf, "%d", &new_value) != 1)
+ SMART_WAKEUP_USE_ERROR;
+ en_smart_wakeup = new_value;
+ return count;
+}
+
+static ssize_t
+test_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ int i, action = 0xffff;
+ char buf[16];
+ CONTROLVM_MESSAGE msg;
+ S64 vrtc_offset;
+
+ if (count >= ARRAY_SIZE(buf))
+ return -EINVAL;
+
+ memset(&msg, 0, sizeof(CONTROLVM_MESSAGE));
+
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("copy_from_user ****FAILED.\n");
+ return -EFAULT;
+ }
+
+ i = sscanf(buf, "%x", &action);
+
+ /* if (i < 1), i.e., if we didn't even read the action field,
+ * then action will default to 0xffff and the code below will
+ * fall through the switch and print usage. */
+ switch (action) {
+ case 6:
+ msg.hdr.Id = CONTROLVM_CHIPSET_STOP;
+ msg.hdr.Flags.responseExpected = 1;
+ stop_chipset(&msg, NULL);
+ break;
+ case 7:
+ vrtc_offset = 0;
+ LOGERR("about to issue QUERY vrtc_offset=%LX", vrtc_offset);
+ vrtc_offset = Issue_VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET();
+ LOGERR("result is vrtc_offset=%LX", vrtc_offset);
+ break;
+ case 8:
+ vrtc_offset = 60;
+ LOGERR("about to increase physical time by 0x%LX seconds",
+ vrtc_offset);
+ vrtc_offset = Issue_VMCALL_UPDATE_PHYSICAL_TIME(vrtc_offset);
+ break;
+ case 9:
+ vrtc_offset = -60;
+ LOGERR("about to decrease physical time by 0x%LX seconds",
+ vrtc_offset);
+ vrtc_offset = Issue_VMCALL_UPDATE_PHYSICAL_TIME(vrtc_offset);
+ break;
+ default:
+ LOGERR("usage: 6 for CHIPSET_STOP\n");
+ LOGERR(" 7 for VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET()\n");
+ LOGERR(" 8 for VMCALL_UPDATE_PHYSICAL_TIME(60)\n");
+ LOGERR(" 9 for VMCALL_UPDATE_PHYSICAL_TIME(-60)\n");
+ return -EFAULT;
+ break;
+ }
+ return count;
+}
+
+#endif /* UISLIB_TEST_PROC */
+static struct device_info *
+find_dev(U32 busNo, U32 devNo)
+{
+ struct bus_info *bus;
+ struct device_info *dev = NULL;
+
+ read_lock(&BusListLock);
+ for (bus = BusListHead; bus; bus = bus->next) {
+ if (bus->busNo == busNo) {
+ /* make sure the device number is valid */
+ if (devNo >= bus->deviceCount) {
+ LOGERR("%s bad busNo, devNo=%d,%d",
+ __func__,
+ (int) (busNo), (int) (devNo));
+ goto Away;
+ }
+ dev = bus->device[devNo];
+ if (!dev)
+ LOGERR("%s bad busNo, devNo=%d,%d",
+ __func__,
+ (int) (busNo), (int) (devNo));
+ goto Away;
+ }
+ }
+Away:
+ read_unlock(&BusListLock);
+ return dev;
+}
+
+/* This thread calls the "interrupt" function for each device that has
+ * enabled such using uislib_enable_channel_interrupts(). The "interrupt"
+ * function typically reads and processes the devices's channel input
+ * queue. This thread repeatedly does this, until the thread is told to stop
+ * (via uisthread_stop()). Sleeping rules:
+ * - If we have called the "interrupt" function for all devices, and all of
+ * them have reported "nothing processed" (returned 0), then we will go to
+ * sleep for a maximum of POLLJIFFIES_NORMAL jiffies.
+ * - If anyone calls uislib_force_channel_interrupt(), the above jiffy
+ * sleep will be interrupted, and we will resume calling the "interrupt"
+ * function for all devices.
+ * - The list of devices is dynamically re-ordered in order to
+ * attempt to preserve fairness. Whenever we spin thru the list of
+ * devices and call the dev->interrupt() function, if we find
+ * devices which report that there is still more work to do, the
+ * the first such device we find is moved to the end of the device
+ * list. This ensures that extremely busy devices don't starve out
+ * less-busy ones.
+ *
+ */
+static int
+Process_Incoming(void *v)
+{
+ unsigned long long cur_cycles, old_cycles, idle_cycles, delta_cycles;
+ struct list_head *new_tail = NULL;
+ int i;
+ UIS_DAEMONIZE("dev_incoming");
+ for (i = 0; i < 16; i++) {
+ old_cycles = get_cycles();
+ wait_event_timeout(Wakeup_Polling_Device_Channels,
+ 0, POLLJIFFIES_NORMAL);
+ cur_cycles = get_cycles();
+ if (wait_cycles == 0) {
+ wait_cycles = (cur_cycles - old_cycles);
+ } else {
+ if (wait_cycles < (cur_cycles - old_cycles))
+ wait_cycles = (cur_cycles - old_cycles);
+ }
+ }
+ LOGINF("wait_cycles=%llu", wait_cycles);
+ cycles_before_wait = wait_cycles;
+ idle_cycles = 0;
+ Go_Polling_Device_Channels = 0;
+ while (1) {
+ struct list_head *lelt, *tmp;
+ struct device_info *dev = NULL;
+
+ /* poll each channel for input */
+ LOCKSEM_UNINTERRUPTIBLE(&Lock_Polling_Device_Channels);
+ new_tail = NULL;
+ list_for_each_safe(lelt, tmp, &List_Polling_Device_Channels) {
+ int rc = 0;
+ dev = list_entry(lelt, struct device_info,
+ list_polling_device_channels);
+ LOCKSEM_UNINTERRUPTIBLE(&dev->interrupt_callback_lock);
+ if (dev->interrupt)
+ rc = dev->interrupt(dev->interrupt_context);
+ else
+ continue;
+ UNLOCKSEM(&dev->interrupt_callback_lock);
+ if (rc) {
+ /* dev->interrupt returned, but there
+ * is still more work to do.
+ * Reschedule work to occur as soon as
+ * possible. */
+ idle_cycles = 0;
+ if (new_tail == NULL) {
+ dev->first_busy_cnt++;
+ if (!
+ (list_is_last
+ (lelt,
+ &List_Polling_Device_Channels))) {
+ new_tail = lelt;
+ dev->moved_to_tail_cnt++;
+ } else
+ dev->last_on_list_cnt++;
+ }
+
+ }
+ if (Incoming_ThreadInfo.should_stop)
+ break;
+ }
+ if (new_tail != NULL) {
+ tot_moved_to_tail_cnt++;
+ list_move_tail(new_tail, &List_Polling_Device_Channels);
+ }
+ UNLOCKSEM(&Lock_Polling_Device_Channels);
+ cur_cycles = get_cycles();
+ delta_cycles = cur_cycles - old_cycles;
+ old_cycles = cur_cycles;
+
+ /* At this point, we have scanned thru all of the
+ * channels, and at least one of the following is true:
+ * - there is no input waiting on any of the channels
+ * - we have received a signal to stop this thread
+ */
+ if (Incoming_ThreadInfo.should_stop)
+ break;
+ if (en_smart_wakeup == 0xFF) {
+ LOGINF("en_smart_wakeup set to 0xff, to force exiting process_incoming");
+ break;
+ }
+ /* wait for POLLJIFFIES_NORMAL jiffies, or until
+ * someone wakes up Wakeup_Polling_Device_Channels,
+ * whichever comes first only do a wait when we have
+ * been idle for cycles_before_wait cycles.
+ */
+ if (idle_cycles > cycles_before_wait) {
+ Go_Polling_Device_Channels = 0;
+ tot_wait_cnt++;
+ wait_event_timeout(Wakeup_Polling_Device_Channels,
+ Go_Polling_Device_Channels,
+ POLLJIFFIES_NORMAL);
+ Go_Polling_Device_Channels = 1;
+ } else {
+ tot_schedule_cnt++;
+ schedule();
+ idle_cycles = idle_cycles + delta_cycles;
+ }
+ }
+ DBGINF("exiting.\n");
+ complete_and_exit(&Incoming_ThreadInfo.has_stopped, 0);
+}
+
+static BOOL
+Initialize_incoming_thread(void)
+{
+ if (Incoming_Thread_Started)
+ return TRUE;
+ if (!uisthread_start(&Incoming_ThreadInfo,
+ &Process_Incoming, NULL, "dev_incoming")) {
+ LOGERR("uisthread_start Initialize_incoming_thread ****FAILED");
+ return FALSE;
+ }
+ Incoming_Thread_Started = TRUE;
+ return TRUE;
+}
+
+/* Add a new device/channel to the list being processed by
+ * Process_Incoming().
+ * <interrupt> - indicates the function to call periodically.
+ * <interrupt_context> - indicates the data to pass to the <interrupt>
+ * function.
+ */
+void
+uislib_enable_channel_interrupts(U32 busNo, U32 devNo,
+ int (*interrupt)(void *),
+ void *interrupt_context)
+{
+ struct device_info *dev;
+ dev = find_dev(busNo, devNo);
+ if (!dev) {
+ LOGERR("%s busNo=%d, devNo=%d", __func__, (int) (busNo),
+ (int) (devNo));
+ return;
+ }
+ LOCKSEM_UNINTERRUPTIBLE(&Lock_Polling_Device_Channels);
+ Initialize_incoming_thread();
+ dev->interrupt = interrupt;
+ dev->interrupt_context = interrupt_context;
+ dev->polling = TRUE;
+ list_add_tail(&(dev->list_polling_device_channels),
+ &List_Polling_Device_Channels);
+ UNLOCKSEM(&Lock_Polling_Device_Channels);
+}
+EXPORT_SYMBOL_GPL(uislib_enable_channel_interrupts);
+
+/* Remove a device/channel from the list being processed by
+ * Process_Incoming().
+ */
+void
+uislib_disable_channel_interrupts(U32 busNo, U32 devNo)
+{
+ struct device_info *dev;
+ dev = find_dev(busNo, devNo);
+ if (!dev) {
+ LOGERR("%s busNo=%d, devNo=%d", __func__, (int) (busNo),
+ (int) (devNo));
+ return;
+ }
+ LOCKSEM_UNINTERRUPTIBLE(&Lock_Polling_Device_Channels);
+ list_del(&dev->list_polling_device_channels);
+ dev->polling = FALSE;
+ dev->interrupt = NULL;
+ UNLOCKSEM(&Lock_Polling_Device_Channels);
+}
+EXPORT_SYMBOL_GPL(uislib_disable_channel_interrupts);
+
+static void
+do_wakeup_polling_device_channels(struct work_struct *dummy)
+{
+ if (!Go_Polling_Device_Channels) {
+ Go_Polling_Device_Channels = 1;
+ wake_up(&Wakeup_Polling_Device_Channels);
+ }
+}
+
+static DECLARE_WORK(Work_wakeup_polling_device_channels,
+ do_wakeup_polling_device_channels);
+
+/* Call this function when you want to send a hint to Process_Incoming() that
+ * your device might have more requests.
+ */
+void
+uislib_force_channel_interrupt(U32 busNo, U32 devNo)
+{
+ if (en_smart_wakeup == 0)
+ return;
+ if (Go_Polling_Device_Channels)
+ return;
+ /* The point of using schedule_work() instead of just doing
+ * the work inline is to force a slight delay before waking up
+ * the Process_Incoming() thread.
+ */
+ tot_wakeup_cnt++;
+ schedule_work(&Work_wakeup_polling_device_channels);
+}
+EXPORT_SYMBOL_GPL(uislib_force_channel_interrupt);
+
+/*****************************************************/
+/* Module Init & Exit functions */
+/*****************************************************/
+
+static int __init
+uislib_mod_init(void)
+{
+
+ LOGINF("MONITORAPIS");
+
+ LOGINF("sizeof(struct uiscmdrsp):%lu bytes\n",
+ (ulong) sizeof(struct uiscmdrsp));
+ LOGINF("sizeof(struct phys_info):%lu\n",
+ (ulong) sizeof(struct phys_info));
+ LOGINF("sizeof(uiscmdrsp_scsi):%lu\n",
+ (ulong) sizeof(struct uiscmdrsp_scsi));
+ LOGINF("sizeof(uiscmdrsp_net):%lu\n",
+ (ulong) sizeof(struct uiscmdrsp_net));
+ LOGINF("sizeof(CONTROLVM_MESSAGE):%lu bytes\n",
+ (ulong) sizeof(CONTROLVM_MESSAGE));
+ LOGINF("sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL):%lu bytes\n",
+ (ulong) sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL));
+ LOGINF("sizeof(CHANNEL_HEADER):%lu bytes\n",
+ (ulong) sizeof(CHANNEL_HEADER));
+ LOGINF("sizeof(ULTRA_IO_CHANNEL_PROTOCOL):%lu bytes\n",
+ (ulong) sizeof(ULTRA_IO_CHANNEL_PROTOCOL));
+ LOGINF("SIZEOF_CMDRSP:%lu bytes\n", SIZEOF_CMDRSP);
+ LOGINF("SIZEOF_PROTOCOL:%lu bytes\n", SIZEOF_PROTOCOL);
+
+ /* initialize global pointers to NULL */
+ BusListHead = NULL;
+ BusListCount = MaxBusCount = 0;
+ rwlock_init(&BusListLock);
+ VirtControlChanFunc = NULL;
+
+ /* Issue VMCALL_GET_CONTROLVM_ADDR to get CtrlChanPhysAddr and
+ * then map this physical address to a virtual address. */
+ POSTCODE_LINUX_2(DRIVER_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+
+ /* create the proc entries for the channels */
+ uislib_proc_dir = proc_mkdir(DIR_PROC_ENTRY, NULL);
+ /* (e.g., for /proc/uislib/vbus/<x>/info) */
+ uislib_proc_vbus_dir = proc_mkdir(DIR_VBUS_PROC_ENTRY, uislib_proc_dir);
+
+ vnic_proc_entry = proc_create(VNIC_PROC_ENTRY_FN, 0, uislib_proc_dir,
+ &proc_vnic_fops);
+ SET_PROC_OWNER(vnic_proc_entry, THIS_MODULE);
+
+ /* for testing purposes only, create the proc entries for
+ * enqueuing Control Channel messages */
+ chipset_proc_entry =
+ proc_create(CHIPSET_PROC_ENTRY_FN, 0, uislib_proc_dir,
+ &proc_chipset_fops);
+ SET_PROC_OWNER(chipset_proc_entry, THIS_MODULE);
+
+ info_proc_entry = proc_create(INFO_PROC_ENTRY_FN, 0, uislib_proc_dir,
+ &proc_info_fops);
+ SET_PROC_OWNER(info_proc_entry, THIS_MODULE);
+
+ platformnumber_proc_entry =
+ proc_create(PLATFORMNUMBER_PROC_ENTRY_FN, 0, uislib_proc_dir,
+ &proc_platformnumber_fops);
+ SET_PROC_OWNER(platformnumberinfo_proc_entry, THIS_MODULE);
+
+ cycles_before_wait_proc_entry =
+ proc_create(CYCLES_BEFORE_WAIT_PROC_ENTRY_FN, 0, uislib_proc_dir,
+ &proc_cycles_before_wait_fops);
+ SET_PROC_OWNER(cycles_before_wait_proc_entry, THIS_MODULE);
+
+ reset_counts_proc_entry =
+ proc_create(RESET_COUNTS_PROC_ENTRY_FN, 0, uislib_proc_dir,
+ &proc_reset_counts_fops);
+ SET_PROC_OWNER(reset_counts_proc_entry, THIS_MODULE);
+
+ smart_wakeup_proc_entry =
+ proc_create(SMART_WAKEUP_PROC_ENTRY_FN, 0, uislib_proc_dir,
+ &proc_smart_wakeup_fops);
+ SET_PROC_OWNER(smart_wakeup_proc_entry, THIS_MODULE);
+
+#ifdef UISLIB_TEST_PROC
+ test_proc_entry = proc_create(TEST_PROC_ENTRY_FN, 0, uislib_proc_dir,
+ &proc_test_fops);
+ SET_PROC_OWNER(test_proc_entry, THIS_MODULE);
+
+ bus_proc_entry = proc_create(BUS_PROC_ENTRY_FN, 0, uislib_proc_dir,
+ &proc_bus_fops);
+ SET_PROC_OWNER(bus_proc_entry, THIS_MODULE);
+
+ dev_proc_entry = proc_create(DEV_PROC_ENTRY_FN, 0, uislib_proc_dir,
+ &proc_dev_fops);
+ SET_PROC_OWNER(dev_proc_entry, THIS_MODULE);
+#endif /* UISLIB_TEST_PROC */
+ POSTCODE_LINUX_3(DRIVER_EXIT_PC, 0, POSTCODE_SEVERITY_INFO);
+ return 0;
+}
+
+static void __exit
+uislib_mod_exit(void)
+{
+ if (disable_proc_entry)
+ remove_proc_entry(DISABLE_PROC_ENTRY_FN, uislib_proc_dir);
+ if (cycles_before_wait_proc_entry)
+ remove_proc_entry(CYCLES_BEFORE_WAIT_PROC_ENTRY_FN,
+ uislib_proc_dir);
+ if (reset_counts_proc_entry)
+ remove_proc_entry(RESET_COUNTS_PROC_ENTRY_FN, uislib_proc_dir);
+ if (smart_wakeup_proc_entry)
+ remove_proc_entry(SMART_WAKEUP_PROC_ENTRY_FN, uislib_proc_dir);
+ if (ctrlchan_proc_entry)
+ remove_proc_entry(CTRLCHAN_PROC_ENTRY_FN, uislib_proc_dir);
+ if (pmem_proc_entry)
+ remove_proc_entry(PMEM_PROC_ENTRY_FN, uislib_proc_dir);
+ if (info_proc_entry)
+ remove_proc_entry(INFO_PROC_ENTRY_FN, uislib_proc_dir);
+ if (switch_proc_entry)
+ remove_proc_entry(SWITCH_PROC_ENTRY_FN, uislib_proc_dir);
+ if (extport_proc_entry)
+ remove_proc_entry(EXTPORT_PROC_ENTRY_FN, uislib_proc_dir);
+ if (platformnumber_proc_entry)
+ remove_proc_entry(PLATFORMNUMBER_PROC_ENTRY_FN,
+ uislib_proc_dir);
+ if (bus_proc_entry)
+ remove_proc_entry(BUS_PROC_ENTRY_FN, uislib_proc_dir);
+ if (dev_proc_entry)
+ remove_proc_entry(DEV_PROC_ENTRY_FN, uislib_proc_dir);
+ if (vnic_proc_entry)
+ remove_proc_entry(VNIC_PROC_ENTRY_FN, uislib_proc_dir);
+ if (chipset_proc_entry)
+ remove_proc_entry(CHIPSET_PROC_ENTRY_FN, uislib_proc_dir);
+ if (uislib_proc_vbus_dir)
+ remove_proc_entry(DIR_VBUS_PROC_ENTRY, uislib_proc_dir);
+ if (uislib_proc_dir)
+ remove_proc_entry(DIR_PROC_ENTRY, NULL);
+
+ if (ProcReadBuffer) {
+ vfree(ProcReadBuffer);
+ ProcReadBuffer = NULL;
+ }
+
+ DBGINF("goodbye.\n");
+ return;
+}
+
+module_init(uislib_mod_init);
+module_exit(uislib_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Usha Srinivasan");
+MODULE_ALIAS("uislib");
+ /* this is extracted during depmod and kept in modules.dep */
diff --git a/drivers/staging/unisys/uislib/uisqueue.c b/drivers/staging/unisys/uislib/uisqueue.c
new file mode 100644
index 000000000000..40598ff1f4f2
--- /dev/null
+++ b/drivers/staging/unisys/uislib/uisqueue.c
@@ -0,0 +1,160 @@
+/* uisqueue.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* @ALL_INSPECTED */
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "uisutils.h"
+
+#include "chanstub.h"
+
+/* this is shorter than using __FILE__ (full path name) in
+ * debug/info/error messages */
+#define CURRENT_FILE_PC UISLIB_PC_uisqueue_c
+#define __MYFILE__ "uisqueue.c"
+
+#define CHECK_CACHE_ALIGN 0
+
+/*****************************************************/
+/* Exported functions */
+/*****************************************************/
+unsigned long long
+uisqueue_InterlockedOr(unsigned long long __iomem *Target,
+ unsigned long long Set)
+{
+ unsigned long long i;
+ unsigned long long j;
+
+ j = readq(Target);
+ do {
+ i = j;
+ j = uislibcmpxchg64((__force unsigned long long *)Target,
+ i, i | Set, sizeof(*(Target)));
+
+ } while (i != j);
+
+ return j;
+}
+EXPORT_SYMBOL_GPL(uisqueue_InterlockedOr);
+
+unsigned long long
+uisqueue_InterlockedAnd(unsigned long long __iomem *Target,
+ unsigned long long Set)
+{
+ unsigned long long i;
+ unsigned long long j;
+
+ j = readq(Target);
+ do {
+ i = j;
+ j = uislibcmpxchg64((__force unsigned long long *)Target,
+ i, i & Set, sizeof(*(Target)));
+
+ } while (i != j);
+
+ return j;
+}
+EXPORT_SYMBOL_GPL(uisqueue_InterlockedAnd);
+
+static U8
+do_locked_client_insert(struct uisqueue_info *queueinfo,
+ unsigned int whichqueue,
+ void *pSignal,
+ spinlock_t *lock,
+ unsigned char issueInterruptIfEmpty,
+ U64 interruptHandle, U8 *channelId)
+{
+ unsigned long flags;
+ unsigned char queueWasEmpty;
+ unsigned int locked = 0;
+ unsigned int acquired = 0;
+ U8 rc = 0;
+
+ spin_lock_irqsave(lock, flags);
+ locked = 1;
+
+ if (!ULTRA_CHANNEL_CLIENT_ACQUIRE_OS(queueinfo->chan, channelId, NULL))
+ goto Away;
+
+ acquired = 1;
+
+ queueWasEmpty = visor_signalqueue_empty(queueinfo->chan, whichqueue);
+ if (!visor_signal_insert(queueinfo->chan, whichqueue, pSignal))
+ goto Away;
+ ULTRA_CHANNEL_CLIENT_RELEASE_OS(queueinfo->chan, channelId, NULL);
+ acquired = 0;
+ spin_unlock_irqrestore(lock, flags);
+ locked = 0;
+
+ queueinfo->packets_sent++;
+
+ rc = 1;
+Away:
+ if (acquired) {
+ ULTRA_CHANNEL_CLIENT_RELEASE_OS(queueinfo->chan, channelId,
+ NULL);
+ acquired = 0;
+ }
+ if (locked) {
+ spin_unlock_irqrestore((spinlock_t *) lock, flags);
+ locked = 0;
+ }
+
+ return rc;
+}
+
+int
+uisqueue_put_cmdrsp_with_lock_client(struct uisqueue_info *queueinfo,
+ struct uiscmdrsp *cmdrsp,
+ unsigned int whichqueue,
+ void *insertlock,
+ unsigned char issueInterruptIfEmpty,
+ U64 interruptHandle,
+ char oktowait, U8 *channelId)
+{
+ while (!do_locked_client_insert(queueinfo, whichqueue, cmdrsp,
+ (spinlock_t *) insertlock,
+ issueInterruptIfEmpty,
+ interruptHandle, channelId)) {
+ if (oktowait != OK_TO_WAIT) {
+ LOGERR("****FAILED visor_signal_insert failed; cannot wait; insert aborted\n");
+ return 0; /* failed to queue */
+ }
+ /* try again */
+ LOGERR("****FAILED visor_signal_insert failed; waiting to try again\n");
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(msecs_to_jiffies(10));
+ }
+ return 1;
+}
+EXPORT_SYMBOL_GPL(uisqueue_put_cmdrsp_with_lock_client);
+
+/* uisqueue_get_cmdrsp gets the cmdrsp entry at the head of the queue
+ * returns NULL if queue is empty */
+int
+uisqueue_get_cmdrsp(struct uisqueue_info *queueinfo,
+ void *cmdrsp, unsigned int whichqueue)
+{
+ if (!visor_signal_remove(queueinfo->chan, whichqueue, cmdrsp))
+ return 0;
+
+ queueinfo->packets_received++;
+
+ return 1; /* Success */
+}
+EXPORT_SYMBOL_GPL(uisqueue_get_cmdrsp);
diff --git a/drivers/staging/unisys/uislib/uisthread.c b/drivers/staging/unisys/uislib/uisthread.c
new file mode 100644
index 000000000000..782b06aad56d
--- /dev/null
+++ b/drivers/staging/unisys/uislib/uisthread.c
@@ -0,0 +1,85 @@
+/* uisthread.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* @ALL_INSPECTED */
+#include <asm/processor.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include "uniklog.h"
+#include "uisutils.h"
+#include "uisthread.h"
+
+#define KILL(a, b, c) kill_pid(find_vpid(a), b, c)
+
+/* this is shorter than using __FILE__ (full path name) in
+ * debug/info/error messages
+ */
+#define CURRENT_FILE_PC UISLIB_PC_uisthread_c
+#define __MYFILE__ "uisthread.c"
+
+/*****************************************************/
+/* Exported functions */
+/*****************************************************/
+
+/* returns 0 for failure, 1 for success */
+int
+uisthread_start(struct uisthread_info *thrinfo,
+ int (*threadfn)(void *), void *thrcontext, char *name)
+{
+ thrinfo->should_stop = 0;
+ /* used to stop the thread */
+ init_completion(&thrinfo->has_stopped);
+ thrinfo->task = kthread_create(threadfn, thrcontext, name, NULL);
+ if (IS_ERR(thrinfo->task)) {
+ thrinfo->id = 0;
+ return 0; /* failure */
+ }
+ thrinfo->id = thrinfo->task->pid;
+ wake_up_process(thrinfo->task);
+ LOGINF("started thread pid:%d\n", thrinfo->id);
+ return 1;
+
+}
+EXPORT_SYMBOL_GPL(uisthread_start);
+
+void
+uisthread_stop(struct uisthread_info *thrinfo)
+{
+ int ret;
+ int stopped = 0;
+ if (thrinfo->id == 0)
+ return; /* thread not running */
+
+ LOGINF("uisthread_stop stopping id:%d\n", thrinfo->id);
+ thrinfo->should_stop = 1;
+ ret = KILL(thrinfo->id, SIGHUP, 1);
+ if (ret) {
+ LOGERR("unable to signal thread %d\n", ret);
+ } else {
+ /* give up if the thread has NOT died in 1 minute */
+ if (wait_for_completion_timeout(&thrinfo->has_stopped, 60 * HZ))
+ stopped = 1;
+ else
+ LOGERR("timed out trying to signal thread\n");
+ }
+ if (stopped) {
+ LOGINF("uisthread_stop stopped id:%d\n", thrinfo->id);
+ thrinfo->id = 0;
+ }
+}
+EXPORT_SYMBOL_GPL(uisthread_stop);
diff --git a/drivers/staging/unisys/uislib/uisutils.c b/drivers/staging/unisys/uislib/uisutils.c
new file mode 100644
index 000000000000..3178f75e1ebe
--- /dev/null
+++ b/drivers/staging/unisys/uislib/uisutils.c
@@ -0,0 +1,350 @@
+/* uisutils.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <commontypes.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include "uniklog.h"
+#include "uisutils.h"
+#include "version.h"
+#include "vbushelper.h"
+#include "guidutils.h"
+#include <linux/skbuff.h>
+#ifdef CONFIG_HIGHMEM
+#include <linux/highmem.h>
+#endif
+
+/* this is shorter than using __FILE__ (full path name) in
+ * debug/info/error messages
+ */
+#define CURRENT_FILE_PC UISLIB_PC_uisutils_c
+#define __MYFILE__ "uisutils.c"
+
+/* exports */
+atomic_t UisUtils_Registered_Services = ATOMIC_INIT(0);
+ /* num registrations via
+ * uisctrl_register_req_handler() or
+ * uisctrl_register_req_handler_ex() */
+
+
+/*****************************************************/
+/* Utility functions */
+/*****************************************************/
+
+int
+uisutil_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
+ char *format, ...)
+{
+ va_list args;
+ int len;
+
+ DBGINF("buffer = 0x%p : *buffer = 0x%p.\n", buffer, *buffer);
+ va_start(args, format);
+ len = vsnprintf(*buffer, *buffer_remaining, format, args);
+ if (len >= *buffer_remaining) {
+ *buffer += *buffer_remaining;
+ *total += *buffer_remaining;
+ *buffer_remaining = 0;
+ LOGERR("bytes remaining is too small!\n");
+ return -1;
+ }
+ *buffer_remaining -= len;
+ *buffer += len;
+ *total += len;
+ return len;
+}
+EXPORT_SYMBOL_GPL(uisutil_add_proc_line_ex);
+
+int
+uisctrl_register_req_handler(int type, void *fptr,
+ ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo)
+{
+ LOGINF("type = %d, fptr = 0x%p.\n", type, fptr);
+
+ switch (type) {
+ case 2:
+ if (fptr) {
+ if (!VirtControlChanFunc)
+ atomic_inc(&UisUtils_Registered_Services);
+ VirtControlChanFunc = fptr;
+ } else {
+ if (VirtControlChanFunc)
+ atomic_dec(&UisUtils_Registered_Services);
+ VirtControlChanFunc = NULL;
+ }
+ break;
+
+ default:
+ LOGERR("invalid type %d.\n", type);
+ return 0;
+ }
+ if (chipset_DriverInfo)
+ BusDeviceInfo_Init(chipset_DriverInfo,
+ "chipset", "uislib",
+ VERSION, NULL, __DATE__, __TIME__);
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(uisctrl_register_req_handler);
+
+int
+uisctrl_register_req_handler_ex(GUID switchTypeGuid,
+ const char *switch_type_name,
+ int (*controlfunc)(struct io_msgs *),
+ unsigned long min_channel_bytes,
+ int (*Server_Channel_Ok)(unsigned long
+ channelBytes),
+ int (*Server_Channel_Init)
+ (void *x, unsigned char *clientStr,
+ U32 clientStrLen, U64 bytes),
+ ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo)
+{
+ char s[99];
+ ReqHandlerInfo_t *pReqHandlerInfo;
+ int rc = 0; /* assume failure */
+ LOGINF("type=%s, controlfunc=0x%p.\n",
+ GUID_format1(&switchTypeGuid, s), controlfunc);
+ if (!controlfunc) {
+ LOGERR("%s: controlfunc must be supplied\n",
+ GUID_format1(&switchTypeGuid, s));
+ goto Away;
+ }
+ if (!Server_Channel_Ok) {
+ LOGERR("%s: Server_Channel_Ok must be supplied\n",
+ GUID_format1(&switchTypeGuid, s));
+ goto Away;
+ }
+ if (!Server_Channel_Init) {
+ LOGERR("%s: Server_Channel_Init must be supplied\n",
+ GUID_format1(&switchTypeGuid, s));
+ goto Away;
+ }
+ pReqHandlerInfo = ReqHandlerAdd(switchTypeGuid,
+ switch_type_name,
+ controlfunc,
+ min_channel_bytes,
+ Server_Channel_Ok, Server_Channel_Init);
+ if (!pReqHandlerInfo) {
+ LOGERR("failed to add %s to server list\n",
+ GUID_format1(&switchTypeGuid, s));
+ goto Away;
+ }
+
+ atomic_inc(&UisUtils_Registered_Services);
+ rc = 1; /* success */
+Away:
+ if (rc) {
+ if (chipset_DriverInfo)
+ BusDeviceInfo_Init(chipset_DriverInfo,
+ "chipset", "uislib",
+ VERSION, NULL,
+ __DATE__, __TIME__);
+ } else
+ LOGERR("failed to register type %s.\n",
+ GUID_format1(&switchTypeGuid, s));
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(uisctrl_register_req_handler_ex);
+
+int
+uisctrl_unregister_req_handler_ex(GUID switchTypeGuid)
+{
+ char s[99];
+ int rc = 0; /* assume failure */
+ LOGINF("type=%s.\n", GUID_format1(&switchTypeGuid, s));
+ if (ReqHandlerDel(switchTypeGuid) < 0) {
+ LOGERR("failed to remove %s from server list\n",
+ GUID_format1(&switchTypeGuid, s));
+ goto Away;
+ }
+ atomic_dec(&UisUtils_Registered_Services);
+ rc = 1; /* success */
+Away:
+ if (!rc)
+ LOGERR("failed to unregister type %s.\n",
+ GUID_format1(&switchTypeGuid, s));
+ return rc;
+}
+EXPORT_SYMBOL_GPL(uisctrl_unregister_req_handler_ex);
+
+/*
+ * unsigned int uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx,
+ * void *skb_in,
+ * unsigned int firstfraglen,
+ * unsigned int frags_max,
+ * struct phys_info frags[])
+ *
+ * calling_ctx - input - a string that is displayed to show
+ * who called * this func
+ * void *skb_in - skb whose frag info we're copying type is hidden so we
+ * don't need to include skbbuff in uisutils.h which is
+ * included in non-networking code.
+ * unsigned int firstfraglen - input - length of first fragment in skb
+ * unsigned int frags_max - input - max len of frags array
+ * struct phys_info frags[] - output - frags array filled in on output
+ * return value indicates number of
+ * entries filled in frags
+ */
+unsigned int
+uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx, void *skb_in,
+ unsigned int firstfraglen,
+ unsigned int frags_max,
+ struct phys_info frags[])
+{
+ unsigned int count = 0, ii, size, offset = 0, numfrags;
+ struct sk_buff *skb = skb_in;
+
+ numfrags = skb_shinfo(skb)->nr_frags;
+
+ while (firstfraglen) {
+ if (count == frags_max) {
+ LOGERR("%s frags array too small: max:%d count:%d\n",
+ calling_ctx, frags_max, count);
+ return -1; /* failure */
+ }
+ frags[count].pi_pfn =
+ page_to_pfn(virt_to_page(skb->data + offset));
+ frags[count].pi_off =
+ (unsigned long) (skb->data + offset) & PI_PAGE_MASK;
+ size =
+ min(firstfraglen,
+ (unsigned int) (PI_PAGE_SIZE - frags[count].pi_off));
+ /* can take smallest of firstfraglen(what's left) OR
+ * bytes left in the page
+ */
+ frags[count].pi_len = size;
+ firstfraglen -= size;
+ offset += size;
+ count++;
+ }
+ if (numfrags) {
+ if ((count + numfrags) > frags_max) {
+ LOGERR("**** FAILED %s frags array too small: max:%d count+nr_frags:%d\n",
+ calling_ctx, frags_max, count + numfrags);
+ return -1; /* failure */
+ }
+
+ for (ii = 0; ii < numfrags; ii++) {
+ count = add_physinfo_entries(page_to_pfn(skb_frag_page(&skb_shinfo(skb)->frags[ii])), /* pfn */
+ skb_shinfo(skb)->frags[ii].
+ page_offset,
+ skb_shinfo(skb)->frags[ii].
+ size, count, frags_max,
+ frags);
+ if (count == 0) {
+ LOGERR("**** FAILED to add physinfo entries\n");
+ return -1; /* failure */
+ }
+ }
+ }
+ if (skb_shinfo(skb)->frag_list) {
+ struct sk_buff *skbinlist;
+ int c;
+ for (skbinlist = skb_shinfo(skb)->frag_list; skbinlist;
+ skbinlist = skbinlist->next) {
+
+ c = uisutil_copy_fragsinfo_from_skb("recursive",
+ skbinlist,
+ skbinlist->len -
+ skbinlist->data_len,
+ frags_max - count,
+ &frags[count]);
+ if (c == -1) {
+ LOGERR("**** FAILED recursive call failed\n");
+ return -1;
+ }
+ count += c;
+ }
+ }
+ return count;
+}
+EXPORT_SYMBOL_GPL(uisutil_copy_fragsinfo_from_skb);
+
+static LIST_HEAD(ReqHandlerInfo_list); /* list of ReqHandlerInfo_t */
+static DEFINE_SPINLOCK(ReqHandlerInfo_list_lock);
+
+ReqHandlerInfo_t *
+ReqHandlerAdd(GUID switchTypeGuid,
+ const char *switch_type_name,
+ int (*controlfunc)(struct io_msgs *),
+ unsigned long min_channel_bytes,
+ int (*Server_Channel_Ok)(unsigned long channelBytes),
+ int (*Server_Channel_Init)
+ (void *x, unsigned char *clientStr, U32 clientStrLen, U64 bytes))
+{
+ ReqHandlerInfo_t *rc = NULL;
+
+ rc = kzalloc(sizeof(*rc), GFP_ATOMIC);
+ if (!rc)
+ return NULL;
+ rc->switchTypeGuid = switchTypeGuid;
+ rc->controlfunc = controlfunc;
+ rc->min_channel_bytes = min_channel_bytes;
+ rc->Server_Channel_Ok = Server_Channel_Ok;
+ rc->Server_Channel_Init = Server_Channel_Init;
+ if (switch_type_name)
+ strncpy(rc->switch_type_name, switch_type_name,
+ sizeof(rc->switch_type_name) - 1);
+ spin_lock(&ReqHandlerInfo_list_lock);
+ list_add_tail(&(rc->list_link), &ReqHandlerInfo_list);
+ spin_unlock(&ReqHandlerInfo_list_lock);
+
+ return rc;
+}
+
+ReqHandlerInfo_t *
+ReqHandlerFind(GUID switchTypeGuid)
+{
+ struct list_head *lelt, *tmp;
+ ReqHandlerInfo_t *entry = NULL;
+ spin_lock(&ReqHandlerInfo_list_lock);
+ list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
+ entry = list_entry(lelt, ReqHandlerInfo_t, list_link);
+ if (memcmp
+ (&entry->switchTypeGuid, &switchTypeGuid,
+ sizeof(GUID)) == 0) {
+ spin_unlock(&ReqHandlerInfo_list_lock);
+ return entry;
+ }
+ }
+ spin_unlock(&ReqHandlerInfo_list_lock);
+ return NULL;
+}
+
+int
+ReqHandlerDel(GUID switchTypeGuid)
+{
+ struct list_head *lelt, *tmp;
+ ReqHandlerInfo_t *entry = NULL;
+ int rc = -1;
+ spin_lock(&ReqHandlerInfo_list_lock);
+ list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
+ entry = list_entry(lelt, ReqHandlerInfo_t, list_link);
+ if (memcmp
+ (&entry->switchTypeGuid, &switchTypeGuid,
+ sizeof(GUID)) == 0) {
+ list_del(lelt);
+ kfree(entry);
+ rc++;
+ }
+ }
+ spin_unlock(&ReqHandlerInfo_list_lock);
+ return rc;
+}
diff --git a/drivers/staging/unisys/virthba/Kconfig b/drivers/staging/unisys/virthba/Kconfig
new file mode 100644
index 000000000000..c0d7986e78cb
--- /dev/null
+++ b/drivers/staging/unisys/virthba/Kconfig
@@ -0,0 +1,10 @@
+#
+# Unisys virthba configuration
+#
+
+config UNISYS_VIRTHBA
+ tristate "Unisys virthba driver"
+ depends on UNISYSSPAR && UNISYS_VISORCHIPSET && UNISYS_CHANNELSTUB && UNISYS_UISLIB && UNISYS_VIRTPCI && SCSI
+ ---help---
+ If you say Y here, you will enable the Unisys virthba driver.
+
diff --git a/drivers/staging/unisys/virthba/Makefile b/drivers/staging/unisys/virthba/Makefile
new file mode 100644
index 000000000000..632b1c08b975
--- /dev/null
+++ b/drivers/staging/unisys/virthba/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for Unisys virthba
+#
+
+obj-$(CONFIG_UNISYS_VIRTHBA) += virthba.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+ccflags-y += -Idrivers/staging/unisys/uislib
+ccflags-y += -Idrivers/staging/unisys/timskmod
+ccflags-y += -Idrivers/staging/unisys/visorchipset
+ccflags-y += -Idrivers/staging/unisys/virtpci
+ccflags-y += -Idrivers/staging/unisys/common-spar/include
+ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
+
+ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION
+
diff --git a/drivers/staging/unisys/virthba/virthba.c b/drivers/staging/unisys/virthba/virthba.c
new file mode 100644
index 000000000000..817b11dfa19c
--- /dev/null
+++ b/drivers/staging/unisys/virthba/virthba.c
@@ -0,0 +1,1823 @@
+/* virthba.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#define EXPORT_SYMTAB
+
+/* if you want to turn on some debugging of write device data or read
+ * device data, define these two undefs. You will probably want to
+ * customize the code which is here since it was written assuming
+ * reading and writing a specific data file df.64M.txt which is a
+ * 64Megabyte file created by Art Nilson using a scritp I wrote called
+ * cr_test_data.pl. The data file consists of 256 byte lines of text
+ * which start with an 8 digit sequence number, a colon, and then
+ * letters after that */
+
+#undef DBGINF
+
+#include <linux/kernel.h>
+#ifdef CONFIG_MODVERSIONS
+#include <config/modversions.h>
+#endif
+
+#include "uniklog.h"
+#include "diagnostics/appos_subsystems.h"
+#include "uisutils.h"
+#include "uisqueue.h"
+#include "uisthread.h"
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <asm/param.h>
+#include <linux/proc_fs.h>
+#include <linux/types.h>
+
+#include "virthba.h"
+#include "virtpci.h"
+#include "visorchipset.h"
+#include "version.h"
+#include "guestlinuxdebug.h"
+/* this is shorter than using __FILE__ (full path name) in
+ * debug/info/error messages
+ */
+#define CURRENT_FILE_PC VIRT_HBA_PC_virthba_c
+#define __MYFILE__ "virthba.c"
+
+/* NOTE: L1_CACHE_BYTES >=128 */
+#define DEVICE_ATTRIBUTE struct device_attribute
+
+/*****************************************************/
+/* Forward declarations */
+/*****************************************************/
+static int virthba_probe(struct virtpci_dev *dev,
+ const struct pci_device_id *id);
+static void virthba_remove(struct virtpci_dev *dev);
+static int virthba_abort_handler(struct scsi_cmnd *scsicmd);
+static int virthba_bus_reset_handler(struct scsi_cmnd *scsicmd);
+static int virthba_device_reset_handler(struct scsi_cmnd *scsicmd);
+static int virthba_host_reset_handler(struct scsi_cmnd *scsicmd);
+static const char *virthba_get_info(struct Scsi_Host *shp);
+static int virthba_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
+static int virthba_queue_command_lck(struct scsi_cmnd *scsicmd,
+ void (*virthba_cmnd_done)(struct scsi_cmnd *));
+
+#ifdef DEF_SCSI_QCMD
+DEF_SCSI_QCMD(virthba_queue_command)
+#else
+#define virthba_queue_command virthba_queue_command_lck
+#endif
+
+
+static int virthba_slave_alloc(struct scsi_device *scsidev);
+static int virthba_slave_configure(struct scsi_device *scsidev);
+static void virthba_slave_destroy(struct scsi_device *scsidev);
+static int process_incoming_rsps(void *);
+static int virthba_serverup(struct virtpci_dev *virtpcidev);
+static int virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state);
+static void doDiskAddRemove(struct work_struct *work);
+static void virthba_serverdown_complete(struct work_struct *work);
+
+static ssize_t info_proc_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offset);
+static ssize_t rqwu_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos);
+static ssize_t enable_ints_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos);
+static ssize_t enable_ints_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos);
+
+/*****************************************************/
+/* Globals */
+/*****************************************************/
+
+static int rsltq_wait_usecs = 4000; /* Default 4ms */
+static unsigned int MaxBuffLen;
+
+/* Module options */
+static char *virthba_options = "NONE";
+
+static const struct pci_device_id virthba_id_table[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_UNISYS, PCI_DEVICE_ID_VIRTHBA)},
+ {0},
+};
+
+/* export virthba_id_table */
+MODULE_DEVICE_TABLE(pci, virthba_id_table);
+
+static struct workqueue_struct *virthba_serverdown_workqueue;
+
+static struct virtpci_driver virthba_driver = {
+ .name = "uisvirthba",
+ .version = VERSION,
+ .vertag = NULL,
+ .build_date = __DATE__,
+ .build_time = __TIME__,
+ .id_table = virthba_id_table,
+ .probe = virthba_probe,
+ .remove = virthba_remove,
+ .resume = virthba_serverup,
+ .suspend = virthba_serverdown
+};
+
+/* The Send and Recive Buffers of the IO Queue may both be full */
+#define MAX_PENDING_REQUESTS (MIN_NUMSIGNALS*2)
+#define INTERRUPT_VECTOR_MASK 0x3F
+
+struct scsipending {
+ char cmdtype; /* Type of pointer that is being stored */
+ void *sent; /* The Data being tracked */
+ /* struct scsi_cmnd *type for virthba_queue_command */
+ /* struct uiscmdrsp *type for management commands */
+};
+
+#define VIRTHBA_ERROR_COUNT 30
+#define IOS_ERROR_THRESHOLD 1000
+struct virtdisk_info {
+ U32 valid;
+ U32 channel, id, lun; /* Disk Path */
+ atomic_t ios_threshold;
+ atomic_t error_count;
+ struct virtdisk_info *next;
+};
+/* Each Scsi_Host has a host_data area that contains this struct. */
+struct virthba_info {
+ struct Scsi_Host *scsihost;
+ struct virtpci_dev *virtpcidev;
+ struct list_head dev_info_list;
+ struct chaninfo chinfo;
+ struct InterruptInfo intr; /* use recvInterrupt info to receive
+ interrupts when IOs complete */
+ int interrupt_vector;
+ struct scsipending pending[MAX_PENDING_REQUESTS]; /* Tracks the requests
+ that have been */
+ /* forwarded to the IOVM and haven't returned yet */
+ unsigned int nextinsert; /* Start search for next pending
+ free slot here */
+ spinlock_t privlock;
+ bool serverdown;
+ bool serverchangingstate;
+ unsigned long long acquire_failed_cnt;
+ unsigned long long interrupts_rcvd;
+ unsigned long long interrupts_notme;
+ unsigned long long interrupts_disabled;
+ struct work_struct serverdown_completion;
+ U64 __iomem *flags_addr;
+ atomic_t interrupt_rcvd;
+ wait_queue_head_t rsp_queue;
+ struct virtdisk_info head;
+};
+
+/* Work Data for DARWorkQ */
+struct diskaddremove {
+ U8 add; /* 0-remove, 1-add */
+ struct Scsi_Host *shost; /* Scsi Host for this virthba instance */
+ U32 channel, id, lun; /* Disk Path */
+ struct diskaddremove *next;
+};
+
+#define virtpci_dev_to_virthba_virthba_get_info(d) \
+ container_of(d, struct virthba_info, virtpcidev)
+
+static DEVICE_ATTRIBUTE *virthba_shost_attrs[];
+static struct scsi_host_template virthba_driver_template = {
+ .name = "Unisys Virtual HBA",
+ .proc_name = "uisvirthba",
+ .info = virthba_get_info,
+ .ioctl = virthba_ioctl,
+ .queuecommand = virthba_queue_command,
+ .eh_abort_handler = virthba_abort_handler,
+ .eh_device_reset_handler = virthba_device_reset_handler,
+ .eh_bus_reset_handler = virthba_bus_reset_handler,
+ .eh_host_reset_handler = virthba_host_reset_handler,
+ .shost_attrs = virthba_shost_attrs,
+
+#define VIRTHBA_MAX_CMNDS 128
+ .can_queue = VIRTHBA_MAX_CMNDS,
+ .sg_tablesize = 64, /* largest number of address/length pairs */
+ .this_id = -1,
+ .slave_alloc = virthba_slave_alloc,
+ .slave_configure = virthba_slave_configure,
+ .slave_destroy = virthba_slave_destroy,
+ .use_clustering = ENABLE_CLUSTERING,
+};
+
+struct virthba_devices_open {
+ struct virthba_info *virthbainfo;
+};
+
+static const struct file_operations proc_info_fops = {
+ .read = info_proc_read,
+};
+
+static const struct file_operations proc_rqwu_fops = {
+ .write = rqwu_proc_write,
+};
+
+static const struct file_operations proc_enable_ints_fops = {
+ .read = enable_ints_read,
+ .write = enable_ints_write,
+};
+
+
+#define VIRTHBASOPENMAX 1
+/* array of open devices maintained by open() and close(); */
+static struct virthba_devices_open VirtHbasOpen[VIRTHBASOPENMAX];
+static struct proc_dir_entry *virthba_proc_dir;
+static struct proc_dir_entry *info_proc_entry;
+static struct proc_dir_entry *rqwaitus_proc_entry;
+static struct proc_dir_entry *enable_ints_proc_entry;
+#define INFO_PROC_ENTRY_FN "info"
+#define ENABLE_INTS_ENTRY_FN "enable_ints"
+#define RQWU_PROC_ENTRY_FN "rqwait_usecs"
+#define DIR_PROC_ENTRY "virthba"
+
+/*****************************************************/
+/* Local Functions */
+/*****************************************************/
+static int
+add_scsipending_entry(struct virthba_info *vhbainfo, char cmdtype, void *new)
+{
+ unsigned long flags;
+ int insert_location;
+
+ spin_lock_irqsave(&vhbainfo->privlock, flags);
+ insert_location = vhbainfo->nextinsert;
+ while (vhbainfo->pending[insert_location].sent != NULL) {
+ insert_location = (insert_location + 1) % MAX_PENDING_REQUESTS;
+ if (insert_location == (int) vhbainfo->nextinsert) {
+ LOGERR("Queue should be full. insert_location<<%d>> Unable to find open slot for pending commands.\n",
+ insert_location);
+ spin_unlock_irqrestore(&vhbainfo->privlock, flags);
+ return -1;
+ }
+ }
+
+ vhbainfo->pending[insert_location].cmdtype = cmdtype;
+ vhbainfo->pending[insert_location].sent = new;
+ vhbainfo->nextinsert = (insert_location + 1) % MAX_PENDING_REQUESTS;
+ spin_unlock_irqrestore(&vhbainfo->privlock, flags);
+
+ return insert_location;
+}
+
+static unsigned int
+add_scsipending_entry_with_wait(struct virthba_info *vhbainfo, char cmdtype,
+ void *new)
+{
+ int insert_location = add_scsipending_entry(vhbainfo, cmdtype, new);
+
+ while (insert_location == -1) {
+ LOGERR("Failed to find empty queue slot. Waiting to try again\n");
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(msecs_to_jiffies(10));
+ insert_location = add_scsipending_entry(vhbainfo, cmdtype, new);
+ }
+
+ return (unsigned int) insert_location;
+}
+
+static void *
+del_scsipending_entry(struct virthba_info *vhbainfo, uintptr_t del)
+{
+ unsigned long flags;
+ void *sent = NULL;
+
+ if (del >= MAX_PENDING_REQUESTS) {
+ LOGERR("Invalid queue position <<%lu>> given to delete. MAX_PENDING_REQUESTS <<%d>>\n",
+ (unsigned long) del, MAX_PENDING_REQUESTS);
+ } else {
+ spin_lock_irqsave(&vhbainfo->privlock, flags);
+
+ if (vhbainfo->pending[del].sent == NULL)
+ LOGERR("Deleting already cleared queue entry at <<%lu>>.\n",
+ (unsigned long) del);
+
+ sent = vhbainfo->pending[del].sent;
+
+ vhbainfo->pending[del].cmdtype = 0;
+ vhbainfo->pending[del].sent = NULL;
+ spin_unlock_irqrestore(&vhbainfo->privlock, flags);
+ }
+
+ return sent;
+}
+
+/* DARWorkQ (Disk Add/Remove) */
+static struct work_struct DARWorkQ;
+static struct diskaddremove *DARWorkQHead;
+static spinlock_t DARWorkQLock;
+static unsigned short DARWorkQSched;
+#define QUEUE_DISKADDREMOVE(dar) { \
+ spin_lock_irqsave(&DARWorkQLock, flags); \
+ if (!DARWorkQHead) { \
+ DARWorkQHead = dar; \
+ dar->next = NULL; \
+ } \
+ else { \
+ dar->next = DARWorkQHead; \
+ DARWorkQHead = dar; \
+ } \
+ if (!DARWorkQSched) { \
+ schedule_work(&DARWorkQ); \
+ DARWorkQSched = 1; \
+ } \
+ spin_unlock_irqrestore(&DARWorkQLock, flags); \
+}
+
+static inline void
+SendDiskAddRemove(struct diskaddremove *dar)
+{
+ struct scsi_device *sdev;
+ int error;
+
+ sdev = scsi_device_lookup(dar->shost, dar->channel, dar->id, dar->lun);
+ if (sdev) {
+ if (!(dar->add))
+ scsi_remove_device(sdev);
+ } else if (dar->add) {
+ error =
+ scsi_add_device(dar->shost, dar->channel, dar->id,
+ dar->lun);
+ if (error)
+ LOGERR("Failed scsi_add_device: host_no=%d[chan=%d:id=%d:lun=%d]\n",
+ dar->shost->host_no, dar->channel, dar->id,
+ dar->lun);
+ } else
+ LOGERR("Failed scsi_device_lookup:[chan=%d:id=%d:lun=%d]\n",
+ dar->channel, dar->id, dar->lun);
+ kfree(dar);
+}
+
+/*****************************************************/
+/* DARWorkQ Handler Thread */
+/*****************************************************/
+static void
+doDiskAddRemove(struct work_struct *work)
+{
+ struct diskaddremove *dar;
+ struct diskaddremove *tmphead;
+ int i = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&DARWorkQLock, flags);
+ tmphead = DARWorkQHead;
+ DARWorkQHead = NULL;
+ DARWorkQSched = 0;
+ spin_unlock_irqrestore(&DARWorkQLock, flags);
+ while (tmphead) {
+ dar = tmphead;
+ tmphead = dar->next;
+ SendDiskAddRemove(dar);
+ i++;
+ }
+}
+
+/*****************************************************/
+/* Routine to add entry to DARWorkQ */
+/*****************************************************/
+static void
+process_disk_notify(struct Scsi_Host *shost, struct uiscmdrsp *cmdrsp)
+{
+ struct diskaddremove *dar;
+ unsigned long flags;
+
+ dar = kzalloc(sizeof(struct diskaddremove), GFP_ATOMIC);
+ if (dar) {
+ dar->add = cmdrsp->disknotify.add;
+ dar->shost = shost;
+ dar->channel = cmdrsp->disknotify.channel;
+ dar->id = cmdrsp->disknotify.id;
+ dar->lun = cmdrsp->disknotify.lun;
+ QUEUE_DISKADDREMOVE(dar);
+ } else {
+ LOGERR("kmalloc failed for dar. host_no=%d[chan=%d:id=%d:lun=%d]\n",
+ shost->host_no, cmdrsp->disknotify.channel,
+ cmdrsp->disknotify.id, cmdrsp->disknotify.lun);
+ }
+}
+
+/*****************************************************/
+/* Probe Remove Functions */
+/*****************************************************/
+static irqreturn_t
+virthba_ISR(int irq, void *dev_id)
+{
+ struct virthba_info *virthbainfo = (struct virthba_info *) dev_id;
+ CHANNEL_HEADER __iomem *pChannelHeader;
+ SIGNAL_QUEUE_HEADER __iomem *pqhdr;
+ U64 mask;
+ unsigned long long rc1;
+
+ if (virthbainfo == NULL)
+ return IRQ_NONE;
+ virthbainfo->interrupts_rcvd++;
+ pChannelHeader = virthbainfo->chinfo.queueinfo->chan;
+ if (((readq(&pChannelHeader->Features)
+ & ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS) != 0)
+ && ((readq(&pChannelHeader->Features) &
+ ULTRA_IO_DRIVER_DISABLES_INTS) !=
+ 0)) {
+ virthbainfo->interrupts_disabled++;
+ mask = ~ULTRA_CHANNEL_ENABLE_INTS;
+ rc1 = uisqueue_InterlockedAnd(virthbainfo->flags_addr, mask);
+ }
+ if (visor_signalqueue_empty(pChannelHeader, IOCHAN_FROM_IOPART)) {
+ virthbainfo->interrupts_notme++;
+ return IRQ_NONE;
+ }
+ pqhdr = (SIGNAL_QUEUE_HEADER __iomem *)
+ ((char __iomem *) pChannelHeader +
+ readq(&pChannelHeader->oChannelSpace)) + IOCHAN_FROM_IOPART;
+ writeq(readq(&pqhdr->NumInterruptsReceived) + 1,
+ &pqhdr->NumInterruptsReceived);
+ atomic_set(&virthbainfo->interrupt_rcvd, 1);
+ wake_up_interruptible(&virthbainfo->rsp_queue);
+ return IRQ_HANDLED;
+}
+
+static int
+virthba_probe(struct virtpci_dev *virtpcidev, const struct pci_device_id *id)
+{
+ int error;
+ struct Scsi_Host *scsihost;
+ struct virthba_info *virthbainfo;
+ int rsp;
+ int i;
+ irq_handler_t handler = virthba_ISR;
+ CHANNEL_HEADER __iomem *pChannelHeader;
+ SIGNAL_QUEUE_HEADER __iomem *pqhdr;
+ U64 mask;
+
+ LOGVER("entering virthba_probe...\n");
+ LOGVER("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo,
+ virtpcidev->deviceNo);
+
+ LOGINF("entering virthba_probe...\n");
+ LOGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo,
+ virtpcidev->deviceNo);
+ POSTCODE_LINUX_2(VHBA_PROBE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+ /* call scsi_host_alloc to register a scsi host adapter
+ * instance - this virthba that has just been created is an
+ * instance of a scsi host adapter. This scsi_host_alloc
+ * function allocates a new Scsi_Host struct & performs basic
+ * initializatoin. The host is not published to the scsi
+ * midlayer until scsi_add_host is called.
+ */
+ DBGINF("calling scsi_host_alloc.\n");
+
+ /* arg 2 passed in length of extra space we want allocated
+ * with scsi_host struct for our own use scsi_host_alloc
+ * assign host_no
+ */
+ scsihost = scsi_host_alloc(&virthba_driver_template,
+ sizeof(struct virthba_info));
+ if (scsihost == NULL)
+ return -ENODEV;
+
+ DBGINF("scsihost: 0x%p, scsihost->this_id: %d, host_no: %d.\n",
+ scsihost, scsihost->this_id, scsihost->host_no);
+
+ scsihost->this_id = UIS_MAGIC_VHBA;
+ /* linux treats max-channel differently than max-id & max-lun.
+ * In the latter cases, those two values result in 0 to max-1
+ * (inclusive) being scanned. But in the case of channels, the
+ * scan is 0 to max (inclusive); so we will subtract one from
+ * the max-channel value.
+ */
+ LOGINF("virtpcidev->scsi.max.max_channel=%u, max_id=%u, max_lun=%u, cmd_per_lun=%u, max_io_size=%u\n",
+ (unsigned) virtpcidev->scsi.max.max_channel - 1,
+ (unsigned) virtpcidev->scsi.max.max_id,
+ (unsigned) virtpcidev->scsi.max.max_lun,
+ (unsigned) virtpcidev->scsi.max.cmd_per_lun,
+ (unsigned) virtpcidev->scsi.max.max_io_size);
+ scsihost->max_channel = (unsigned) virtpcidev->scsi.max.max_channel;
+ scsihost->max_id = (unsigned) virtpcidev->scsi.max.max_id;
+ scsihost->max_lun = (unsigned) virtpcidev->scsi.max.max_lun;
+ scsihost->cmd_per_lun = (unsigned) virtpcidev->scsi.max.cmd_per_lun;
+ scsihost->max_sectors =
+ (unsigned short) (virtpcidev->scsi.max.max_io_size >> 9);
+ scsihost->sg_tablesize =
+ (unsigned short) (virtpcidev->scsi.max.max_io_size / PAGE_SIZE);
+ if (scsihost->sg_tablesize > MAX_PHYS_INFO)
+ scsihost->sg_tablesize = MAX_PHYS_INFO;
+ LOGINF("scsihost->max_channel=%u, max_id=%u, max_lun=%u, cmd_per_lun=%u, max_sectors=%hu, sg_tablesize=%hu\n",
+ scsihost->max_channel, scsihost->max_id, scsihost->max_lun,
+ scsihost->cmd_per_lun, scsihost->max_sectors,
+ scsihost->sg_tablesize);
+ LOGINF("scsihost->can_queue=%u, scsihost->cmd_per_lun=%u, max_sectors=%hu, sg_tablesize=%hu\n",
+ scsihost->can_queue, scsihost->cmd_per_lun, scsihost->max_sectors,
+ scsihost->sg_tablesize);
+
+ DBGINF("calling scsi_add_host\n");
+
+ /* this creates "host%d" in sysfs. If 2nd argument is NULL,
+ * then this generic /sys/devices/platform/host? device is
+ * created and /sys/scsi_host/host? ->
+ * /sys/devices/platform/host? If 2nd argument is not NULL,
+ * then this generic /sys/devices/<path>/host? is created and
+ * host? points to that device instead.
+ */
+ error = scsi_add_host(scsihost, &virtpcidev->generic_dev);
+ if (error) {
+ LOGERR("scsi_add_host ****FAILED 0x%x TBD - RECOVER\n", error);
+ POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
+ /* decr refcount on scsihost which was incremented by
+ * scsi_add_host so the scsi_host gets deleted
+ */
+ scsi_host_put(scsihost);
+ return -ENODEV;
+ }
+
+ virthbainfo = (struct virthba_info *) scsihost->hostdata;
+ memset(virthbainfo, 0, sizeof(struct virthba_info));
+ for (i = 0; i < VIRTHBASOPENMAX; i++) {
+ if (VirtHbasOpen[i].virthbainfo == NULL) {
+ VirtHbasOpen[i].virthbainfo = virthbainfo;
+ break;
+ }
+ }
+ virthbainfo->interrupt_vector = -1;
+ virthbainfo->chinfo.queueinfo = &virtpcidev->queueinfo;
+ virthbainfo->virtpcidev = virtpcidev;
+ spin_lock_init(&virthbainfo->chinfo.insertlock);
+
+ DBGINF("generic_dev: 0x%p, queueinfo: 0x%p.\n",
+ &virtpcidev->generic_dev, &virtpcidev->queueinfo);
+
+ init_waitqueue_head(&virthbainfo->rsp_queue);
+ spin_lock_init(&virthbainfo->privlock);
+ memset(&virthbainfo->pending, 0, sizeof(virthbainfo->pending));
+ virthbainfo->serverdown = false;
+ virthbainfo->serverchangingstate = false;
+
+ virthbainfo->intr = virtpcidev->intr;
+ /* save of host within virthba_info */
+ virthbainfo->scsihost = scsihost;
+
+ /* save of host within virtpci_dev */
+ virtpcidev->scsi.scsihost = scsihost;
+
+ /* Setup workqueue for serverdown messages */
+ INIT_WORK(&virthbainfo->serverdown_completion,
+ virthba_serverdown_complete);
+
+ writeq(readq(&virthbainfo->chinfo.queueinfo->chan->Features) |
+ ULTRA_IO_CHANNEL_IS_POLLING,
+ &virthbainfo->chinfo.queueinfo->chan->Features);
+ /* start thread that will receive scsicmnd responses */
+ DBGINF("starting rsp thread -- queueinfo: 0x%p, threadinfo: 0x%p.\n",
+ virthbainfo->chinfo.queueinfo, &virthbainfo->chinfo.threadinfo);
+
+ pChannelHeader = virthbainfo->chinfo.queueinfo->chan;
+ pqhdr = (SIGNAL_QUEUE_HEADER __iomem *)
+ ((char __iomem *)pChannelHeader +
+ readq(&pChannelHeader->oChannelSpace)) + IOCHAN_FROM_IOPART;
+ virthbainfo->flags_addr = &pqhdr->FeatureFlags;
+
+ if (!uisthread_start(&virthbainfo->chinfo.threadinfo,
+ process_incoming_rsps,
+ virthbainfo, "vhba_incoming")) {
+ LOGERR("uisthread_start rsp ****FAILED\n");
+ /* decr refcount on scsihost which was incremented by
+ * scsi_add_host so the scsi_host gets deleted
+ */
+ POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
+ scsi_host_put(scsihost);
+ return -ENODEV;
+ }
+ LOGINF("sendInterruptHandle=0x%16llX",
+ virthbainfo->intr.sendInterruptHandle);
+ LOGINF("recvInterruptHandle=0x%16llX",
+ virthbainfo->intr.recvInterruptHandle);
+ LOGINF("recvInterruptVector=0x%8X",
+ virthbainfo->intr.recvInterruptVector);
+ LOGINF("recvInterruptShared=0x%2X",
+ virthbainfo->intr.recvInterruptShared);
+ LOGINF("scsihost.hostt->name=%s", scsihost->hostt->name);
+ virthbainfo->interrupt_vector =
+ virthbainfo->intr.recvInterruptHandle & INTERRUPT_VECTOR_MASK;
+ rsp = request_irq(virthbainfo->interrupt_vector, handler, IRQF_SHARED,
+ scsihost->hostt->name, virthbainfo);
+ if (rsp != 0) {
+ LOGERR("request_irq(%d) uislib_virthba_ISR request failed with rsp=%d\n",
+ virthbainfo->interrupt_vector, rsp);
+ virthbainfo->interrupt_vector = -1;
+ POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
+ } else {
+ U64 __iomem *Features_addr =
+ &virthbainfo->chinfo.queueinfo->chan->Features;
+ LOGERR("request_irq(%d) uislib_virthba_ISR request succeeded\n",
+ virthbainfo->interrupt_vector);
+ mask = ~(ULTRA_IO_CHANNEL_IS_POLLING |
+ ULTRA_IO_DRIVER_DISABLES_INTS);
+ uisqueue_InterlockedAnd(Features_addr, mask);
+ mask = ULTRA_IO_DRIVER_ENABLES_INTS;
+ uisqueue_InterlockedOr(Features_addr, mask);
+ rsltq_wait_usecs = 4000000;
+ }
+
+ DBGINF("calling scsi_scan_host.\n");
+ scsi_scan_host(scsihost);
+ DBGINF("return from scsi_scan_host.\n");
+
+ LOGINF("virthba added scsihost:0x%p\n", scsihost);
+ POSTCODE_LINUX_2(VHBA_PROBE_EXIT_PC, POSTCODE_SEVERITY_INFO);
+ return 0;
+}
+
+static void
+virthba_remove(struct virtpci_dev *virtpcidev)
+{
+ struct virthba_info *virthbainfo;
+ struct Scsi_Host *scsihost =
+ (struct Scsi_Host *) virtpcidev->scsi.scsihost;
+
+ LOGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo,
+ virtpcidev->deviceNo);
+ virthbainfo = (struct virthba_info *) scsihost->hostdata;
+ if (virthbainfo->interrupt_vector != -1)
+ free_irq(virthbainfo->interrupt_vector, virthbainfo);
+ LOGINF("Removing virtpcidev: 0x%p, virthbainfo: 0x%p\n", virtpcidev,
+ virthbainfo);
+
+ DBGINF("removing scsihost: 0x%p, scsihost->this_id: %d\n", scsihost,
+ scsihost->this_id);
+ scsi_remove_host(scsihost);
+
+ DBGINF("stopping thread.\n");
+ uisthread_stop(&virthbainfo->chinfo.threadinfo);
+
+ DBGINF("calling scsi_host_put\n");
+
+ /* decr refcount on scsihost which was incremented by
+ * scsi_add_host so the scsi_host gets deleted
+ */
+ scsi_host_put(scsihost);
+ LOGINF("virthba removed scsi_host.\n");
+}
+
+static int
+forward_vdiskmgmt_command(VDISK_MGMT_TYPES vdiskcmdtype,
+ struct Scsi_Host *scsihost,
+ struct uisscsi_dest *vdest)
+{
+ struct uiscmdrsp *cmdrsp;
+ struct virthba_info *virthbainfo =
+ (struct virthba_info *) scsihost->hostdata;
+ int notifyresult = 0xffff;
+ wait_queue_head_t notifyevent;
+
+ LOGINF("vDiskMgmt:%d %d:%d:%d\n", vdiskcmdtype,
+ vdest->channel, vdest->id, vdest->lun);
+
+ if (virthbainfo->serverdown || virthbainfo->serverchangingstate) {
+ DBGINF("Server is down/changing state. Returning Failure.\n");
+ return FAILED;
+ }
+
+ cmdrsp = kzalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
+ if (cmdrsp == NULL) {
+ LOGERR("kmalloc of cmdrsp failed.\n");
+ return FAILED; /* reject */
+ }
+
+ init_waitqueue_head(&notifyevent);
+
+ /* issue VDISK_MGMT_CMD
+ * set type to command - as opposed to task mgmt
+ */
+ cmdrsp->cmdtype = CMD_VDISKMGMT_TYPE;
+ /* specify the event that has to be triggered when this cmd is
+ * complete
+ */
+ cmdrsp->vdiskmgmt.notify = (void *) &notifyevent;
+ cmdrsp->vdiskmgmt.notifyresult = (void *) &notifyresult;
+
+ /* save destination */
+ cmdrsp->vdiskmgmt.vdisktype = vdiskcmdtype;
+ cmdrsp->vdiskmgmt.vdest.channel = vdest->channel;
+ cmdrsp->vdiskmgmt.vdest.id = vdest->id;
+ cmdrsp->vdiskmgmt.vdest.lun = vdest->lun;
+ cmdrsp->vdiskmgmt.scsicmd =
+ (void *) (uintptr_t)
+ add_scsipending_entry_with_wait(virthbainfo, CMD_VDISKMGMT_TYPE,
+ (void *) cmdrsp);
+
+ uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
+ cmdrsp, IOCHAN_TO_IOPART,
+ &virthbainfo->chinfo.insertlock,
+ DONT_ISSUE_INTERRUPT, (U64) NULL,
+ OK_TO_WAIT, "vhba");
+ LOGINF("VdiskMgmt waiting on event notifyevent=0x%p\n",
+ cmdrsp->scsitaskmgmt.notify);
+ wait_event(notifyevent, notifyresult != 0xffff);
+ LOGINF("VdiskMgmt complete; result:%d\n", cmdrsp->vdiskmgmt.result);
+ kfree(cmdrsp);
+ return SUCCESS;
+}
+
+/*****************************************************/
+/* Scsi Host support functions */
+/*****************************************************/
+
+static int
+forward_taskmgmt_command(TASK_MGMT_TYPES tasktype, struct scsi_device *scsidev)
+{
+ struct uiscmdrsp *cmdrsp;
+ struct virthba_info *virthbainfo =
+ (struct virthba_info *) scsidev->host->hostdata;
+ int notifyresult = 0xffff;
+ wait_queue_head_t notifyevent;
+
+ LOGINF("TaskMgmt:%d %d:%d:%d\n", tasktype,
+ scsidev->channel, scsidev->id, scsidev->lun);
+
+ if (virthbainfo->serverdown || virthbainfo->serverchangingstate) {
+ DBGINF("Server is down/changing state. Returning Failure.\n");
+ return FAILED;
+ }
+
+ cmdrsp = kzalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
+ if (cmdrsp == NULL) {
+ LOGERR("kmalloc of cmdrsp failed.\n");
+ return FAILED; /* reject */
+ }
+
+ init_waitqueue_head(&notifyevent);
+
+ /* issue TASK_MGMT_ABORT_TASK */
+ /* set type to command - as opposed to task mgmt */
+ cmdrsp->cmdtype = CMD_SCSITASKMGMT_TYPE;
+ /* specify the event that has to be triggered when this */
+ /* cmd is complete */
+ cmdrsp->scsitaskmgmt.notify = (void *) &notifyevent;
+ cmdrsp->scsitaskmgmt.notifyresult = (void *) &notifyresult;
+
+ /* save destination */
+ cmdrsp->scsitaskmgmt.tasktype = tasktype;
+ cmdrsp->scsitaskmgmt.vdest.channel = scsidev->channel;
+ cmdrsp->scsitaskmgmt.vdest.id = scsidev->id;
+ cmdrsp->scsitaskmgmt.vdest.lun = scsidev->lun;
+ cmdrsp->scsitaskmgmt.scsicmd =
+ (void *) (uintptr_t)
+ add_scsipending_entry_with_wait(virthbainfo,
+ CMD_SCSITASKMGMT_TYPE,
+ (void *) cmdrsp);
+
+ uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
+ cmdrsp, IOCHAN_TO_IOPART,
+ &virthbainfo->chinfo.insertlock,
+ DONT_ISSUE_INTERRUPT, (U64) NULL,
+ OK_TO_WAIT, "vhba");
+ LOGINF("TaskMgmt waiting on event notifyevent=0x%p\n",
+ cmdrsp->scsitaskmgmt.notify);
+ wait_event(notifyevent, notifyresult != 0xffff);
+ LOGINF("TaskMgmt complete; result:%d\n", cmdrsp->scsitaskmgmt.result);
+ kfree(cmdrsp);
+ return SUCCESS;
+}
+
+/* The abort handler returns SUCCESS if it has succeeded to make LLDD
+ * and all related hardware forget about the scmd.
+ */
+static int
+virthba_abort_handler(struct scsi_cmnd *scsicmd)
+{
+ /* issue TASK_MGMT_ABORT_TASK */
+ struct scsi_device *scsidev;
+ struct virtdisk_info *vdisk;
+
+ scsidev = scsicmd->device;
+ for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
+ vdisk->next; vdisk = vdisk->next) {
+ if ((scsidev->channel == vdisk->channel)
+ && (scsidev->id == vdisk->id)
+ && (scsidev->lun == vdisk->lun)) {
+ if (atomic_read(&vdisk->error_count) <
+ VIRTHBA_ERROR_COUNT) {
+ atomic_inc(&vdisk->error_count);
+ POSTCODE_LINUX_2(VHBA_COMMAND_HANDLER_PC,
+ POSTCODE_SEVERITY_INFO);
+ } else
+ atomic_set(&vdisk->ios_threshold,
+ IOS_ERROR_THRESHOLD);
+ }
+ }
+ return forward_taskmgmt_command(TASK_MGMT_ABORT_TASK, scsicmd->device);
+}
+
+static int
+virthba_bus_reset_handler(struct scsi_cmnd *scsicmd)
+{
+ /* issue TASK_MGMT_TARGET_RESET for each target on the bus */
+ struct scsi_device *scsidev;
+ struct virtdisk_info *vdisk;
+
+ scsidev = scsicmd->device;
+ for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
+ vdisk->next; vdisk = vdisk->next) {
+ if ((scsidev->channel == vdisk->channel)
+ && (scsidev->id == vdisk->id)
+ && (scsidev->lun == vdisk->lun)) {
+ if (atomic_read(&vdisk->error_count) <
+ VIRTHBA_ERROR_COUNT) {
+ atomic_inc(&vdisk->error_count);
+ POSTCODE_LINUX_2(VHBA_COMMAND_HANDLER_PC,
+ POSTCODE_SEVERITY_INFO);
+ } else
+ atomic_set(&vdisk->ios_threshold,
+ IOS_ERROR_THRESHOLD);
+ }
+ }
+ return forward_taskmgmt_command(TASK_MGMT_BUS_RESET, scsicmd->device);
+}
+
+static int
+virthba_device_reset_handler(struct scsi_cmnd *scsicmd)
+{
+ /* issue TASK_MGMT_LUN_RESET */
+ struct scsi_device *scsidev;
+ struct virtdisk_info *vdisk;
+
+ scsidev = scsicmd->device;
+ for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
+ vdisk->next; vdisk = vdisk->next) {
+ if ((scsidev->channel == vdisk->channel)
+ && (scsidev->id == vdisk->id)
+ && (scsidev->lun == vdisk->lun)) {
+ if (atomic_read(&vdisk->error_count) <
+ VIRTHBA_ERROR_COUNT) {
+ atomic_inc(&vdisk->error_count);
+ POSTCODE_LINUX_2(VHBA_COMMAND_HANDLER_PC,
+ POSTCODE_SEVERITY_INFO);
+ } else
+ atomic_set(&vdisk->ios_threshold,
+ IOS_ERROR_THRESHOLD);
+ }
+ }
+ return forward_taskmgmt_command(TASK_MGMT_LUN_RESET, scsicmd->device);
+}
+
+static int
+virthba_host_reset_handler(struct scsi_cmnd *scsicmd)
+{
+ /* issue TASK_MGMT_TARGET_RESET for each target on each bus for host */
+ LOGERR("virthba_host_reset_handler Not yet implemented\n");
+ return SUCCESS;
+}
+
+static char virthba_get_info_str[256];
+
+static const char *
+virthba_get_info(struct Scsi_Host *shp)
+{
+ /* Return version string */
+ sprintf(virthba_get_info_str, "virthba, version %s\n", VIRTHBA_VERSION);
+ return virthba_get_info_str;
+}
+
+static int
+virthba_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
+{
+ DBGINF("In virthba_ioctl: ioctl: cmd=0x%x\n", cmd);
+ return -EINVAL;
+}
+
+/* This returns SCSI_MLQUEUE_DEVICE_BUSY if the signal queue to IOpart
+ * is full.
+ */
+static int
+virthba_queue_command_lck(struct scsi_cmnd *scsicmd,
+ void (*virthba_cmnd_done)(struct scsi_cmnd *))
+{
+ struct scsi_device *scsidev = scsicmd->device;
+ int insert_location;
+ unsigned char op;
+ unsigned char *cdb = scsicmd->cmnd;
+ struct Scsi_Host *scsihost = scsidev->host;
+ struct uiscmdrsp *cmdrsp;
+ unsigned int i;
+ struct virthba_info *virthbainfo =
+ (struct virthba_info *) scsihost->hostdata;
+ struct scatterlist *sg = NULL;
+ struct scatterlist *sgl = NULL;
+ int sg_failed = 0;
+
+ if (virthbainfo->serverdown || virthbainfo->serverchangingstate) {
+ DBGINF("Server is down/changing state. Returning SCSI_MLQUEUE_DEVICE_BUSY.\n");
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ }
+
+ cmdrsp = kzalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
+ if (cmdrsp == NULL) {
+ LOGERR("kmalloc of cmdrsp failed.\n");
+ return 1; /* reject the command */
+ }
+
+ /* now saving everything we need from scsi_cmd into cmdrsp
+ * before we queue cmdrsp set type to command - as opposed to
+ * task mgmt
+ */
+ cmdrsp->cmdtype = CMD_SCSI_TYPE;
+ /* save the pending insertion location. Deletion from pending
+ * will return the scsicmd pointer for completion
+ */
+ insert_location =
+ add_scsipending_entry(virthbainfo, CMD_SCSI_TYPE, (void *) scsicmd);
+ if (insert_location != -1) {
+ cmdrsp->scsi.scsicmd = (void *) (uintptr_t) insert_location;
+ } else {
+ LOGERR("Queue is full. Returning busy.\n");
+ kfree(cmdrsp);
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ }
+ /* save done function that we have call when cmd is complete */
+ scsicmd->scsi_done = virthba_cmnd_done;
+ /* save destination */
+ cmdrsp->scsi.vdest.channel = scsidev->channel;
+ cmdrsp->scsi.vdest.id = scsidev->id;
+ cmdrsp->scsi.vdest.lun = scsidev->lun;
+ /* save datadir */
+ cmdrsp->scsi.data_dir = scsicmd->sc_data_direction;
+ memcpy(cmdrsp->scsi.cmnd, cdb, MAX_CMND_SIZE);
+
+ cmdrsp->scsi.bufflen = scsi_bufflen(scsicmd);
+
+ /* keep track of the max buffer length so far. */
+ if (cmdrsp->scsi.bufflen > MaxBuffLen)
+ MaxBuffLen = cmdrsp->scsi.bufflen;
+
+ if (scsi_sg_count(scsicmd) > MAX_PHYS_INFO) {
+ LOGERR("scsicmd use_sg:%d greater than MAX:%d\n",
+ scsi_sg_count(scsicmd), MAX_PHYS_INFO);
+ del_scsipending_entry(virthbainfo, (uintptr_t) insert_location);
+ kfree(cmdrsp);
+ return 1; /* reject the command */
+ }
+
+ /* This is what we USED to do when we assumed we were running */
+ /* uissd & virthba on the same Linux system. */
+ /* cmdrsp->scsi.buffer = scsicmd->request_buffer; */
+ /* The following code does NOT make that assumption. */
+ /* convert buffer to phys information */
+ if (scsi_sg_count(scsicmd) == 0) {
+ if (scsi_bufflen(scsicmd) > 0) {
+ LOGERR("**** FAILED No scatter list for bufflen > 0\n");
+ BUG_ON(scsi_sg_count(scsicmd) == 0);
+ }
+ DBGINF("No sg; buffer:0x%p bufflen:%d\n",
+ scsi_sglist(scsicmd), scsi_bufflen(scsicmd));
+ } else {
+ /* buffer is scatterlist - copy it out */
+ sgl = scsi_sglist(scsicmd);
+
+ for_each_sg(sgl, sg, scsi_sg_count(scsicmd), i) {
+
+ cmdrsp->scsi.gpi_list[i].address = sg_phys(sg);
+ cmdrsp->scsi.gpi_list[i].length = sg->length;
+ if ((i != 0) && (sg->offset != 0))
+ LOGINF("Offset on a sg_entry other than zero =<<%d>>.\n",
+ sg->offset);
+ }
+
+ if (sg_failed) {
+ LOGERR("Start sg_list dump (entries %d, bufflen %d)...\n",
+ scsi_sg_count(scsicmd), cmdrsp->scsi.bufflen);
+ for_each_sg(sgl, sg, scsi_sg_count(scsicmd), i) {
+ LOGERR(" Entry(%d): page->[0x%p], phys->[0x%Lx], off(%d), len(%d)\n",
+ i, sg_page(sg),
+ (unsigned long long) sg_phys(sg),
+ sg->offset, sg->length);
+ }
+ LOGERR("Done sg_list dump.\n");
+ /* BUG(); ***** For now, let it fail in uissd
+ * if it is a problem, as it might just
+ * work
+ */
+ }
+
+ cmdrsp->scsi.guest_phys_entries = scsi_sg_count(scsicmd);
+ }
+
+ op = cdb[0];
+ i = uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
+ cmdrsp, IOCHAN_TO_IOPART,
+ &virthbainfo->chinfo.
+ insertlock,
+ DONT_ISSUE_INTERRUPT,
+ (U64) NULL, DONT_WAIT, "vhba");
+ if (i == 0) {
+ /* queue must be full - and we said don't wait - return busy */
+ LOGERR("uisqueue_put_cmdrsp_with_lock ****FAILED\n");
+ kfree(cmdrsp);
+ del_scsipending_entry(virthbainfo, (uintptr_t) insert_location);
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ }
+
+ /* we're done with cmdrsp space - data from it has been copied
+ * into channel - free it now.
+ */
+ kfree(cmdrsp);
+ return 0; /* non-zero implies host/device is busy */
+}
+
+static int
+virthba_slave_alloc(struct scsi_device *scsidev)
+{
+ /* this called by the midlayer before scan for new devices -
+ * LLD can alloc any struc & do init if needed.
+ */
+ struct virtdisk_info *vdisk;
+ struct virtdisk_info *tmpvdisk;
+ struct virthba_info *virthbainfo;
+ struct Scsi_Host *scsihost = (struct Scsi_Host *) scsidev->host;
+
+ virthbainfo = (struct virthba_info *) scsihost->hostdata;
+ if (!virthbainfo) {
+ LOGERR("Could not find virthba_info for scsihost\n");
+ return 0; /* even though we errored, treat as success */
+ }
+ for (vdisk = &virthbainfo->head; vdisk->next; vdisk = vdisk->next) {
+ if (vdisk->next->valid &&
+ (vdisk->next->channel == scsidev->channel) &&
+ (vdisk->next->id == scsidev->id) &&
+ (vdisk->next->lun == scsidev->lun))
+ return 0;
+ }
+ tmpvdisk = kzalloc(sizeof(struct virtdisk_info), GFP_ATOMIC);
+ if (!tmpvdisk) { /* error allocating */
+ LOGERR("Could not allocate memory for disk\n");
+ return 0;
+ }
+
+ tmpvdisk->channel = scsidev->channel;
+ tmpvdisk->id = scsidev->id;
+ tmpvdisk->lun = scsidev->lun;
+ tmpvdisk->valid = 1;
+ vdisk->next = tmpvdisk;
+ return 0; /* success */
+}
+
+static int
+virthba_slave_configure(struct scsi_device *scsidev)
+{
+ return 0; /* success */
+}
+
+static void
+virthba_slave_destroy(struct scsi_device *scsidev)
+{
+ /* midlevel calls this after device has been quiesced and
+ * before it is to be deleted.
+ */
+ struct virtdisk_info *vdisk, *delvdisk;
+ struct virthba_info *virthbainfo;
+ struct Scsi_Host *scsihost = (struct Scsi_Host *) scsidev->host;
+
+ virthbainfo = (struct virthba_info *) scsihost->hostdata;
+ if (!virthbainfo)
+ LOGERR("Could not find virthba_info for scsihost\n");
+ for (vdisk = &virthbainfo->head; vdisk->next; vdisk = vdisk->next) {
+ if (vdisk->next->valid &&
+ (vdisk->next->channel == scsidev->channel) &&
+ (vdisk->next->id == scsidev->id) &&
+ (vdisk->next->lun == scsidev->lun)) {
+ delvdisk = vdisk->next;
+ vdisk->next = vdisk->next->next;
+ kfree(delvdisk);
+ return;
+ }
+ }
+ return;
+}
+
+/*****************************************************/
+/* Scsi Cmnd support thread */
+/*****************************************************/
+
+static void
+do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
+{
+ struct virtdisk_info *vdisk;
+ struct scsi_device *scsidev;
+ struct sense_data *sd;
+
+ scsidev = scsicmd->device;
+ memcpy(scsicmd->sense_buffer, cmdrsp->scsi.sensebuf, MAX_SENSE_SIZE);
+ sd = (struct sense_data *) scsicmd->sense_buffer;
+
+ /* Do not log errors for disk-not-present inquiries */
+ if ((cmdrsp->scsi.cmnd[0] == INQUIRY) &&
+ (host_byte(cmdrsp->scsi.linuxstat) == DID_NO_CONNECT) &&
+ (cmdrsp->scsi.addlstat == ADDL_SEL_TIMEOUT))
+ return;
+
+ /* Okay see what our error_count is here.... */
+ for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
+ vdisk->next; vdisk = vdisk->next) {
+ if ((scsidev->channel != vdisk->channel)
+ || (scsidev->id != vdisk->id)
+ || (scsidev->lun != vdisk->lun))
+ continue;
+
+ if (atomic_read(&vdisk->error_count) < VIRTHBA_ERROR_COUNT) {
+ atomic_inc(&vdisk->error_count);
+ LOGERR("SCSICMD ****FAILED scsicmd:0x%p op:0x%x <%d:%d:%d:%d> 0x%x-0x%x-0x%x-0x%x-0x%x.\n",
+ scsicmd, cmdrsp->scsi.cmnd[0],
+ scsidev->host->host_no, scsidev->id,
+ scsidev->channel, scsidev->lun,
+ cmdrsp->scsi.linuxstat, sd->Valid, sd->SenseKey,
+ sd->AdditionalSenseCode,
+ sd->AdditionalSenseCodeQualifier);
+ if (atomic_read(&vdisk->error_count) ==
+ VIRTHBA_ERROR_COUNT) {
+ LOGERR("Throtling SCSICMD errors disk <%d:%d:%d:%d>\n",
+ scsidev->host->host_no, scsidev->id,
+ scsidev->channel, scsidev->lun);
+ }
+ atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD);
+ }
+ }
+}
+
+static void
+do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
+{
+ struct scsi_device *scsidev;
+ unsigned char buf[36];
+ struct scatterlist *sg;
+ unsigned int i;
+ char *thispage;
+ char *thispage_orig;
+ int bufind = 0;
+ struct virtdisk_info *vdisk;
+
+ scsidev = scsicmd->device;
+ if ((cmdrsp->scsi.cmnd[0] == INQUIRY)
+ && (cmdrsp->scsi.bufflen >= MIN_INQUIRY_RESULT_LEN)) {
+ if (cmdrsp->scsi.no_disk_result == 0)
+ return;
+
+ /* Linux scsi code is weird; it wants
+ * a device at Lun 0 to issue report
+ * luns, but we don't want a disk
+ * there so we'll present a processor
+ * there. */
+ SET_NO_DISK_INQUIRY_RESULT(buf, cmdrsp->scsi.bufflen,
+ scsidev->lun,
+ DEV_DISK_CAPABLE_NOT_PRESENT,
+ DEV_NOT_CAPABLE);
+
+ if (scsi_sg_count(scsicmd) == 0) {
+ if (scsi_bufflen(scsicmd) > 0) {
+ LOGERR("**** FAILED No scatter list for bufflen > 0\n");
+ BUG_ON(scsi_sg_count(scsicmd) ==
+ 0);
+ }
+ memcpy(scsi_sglist(scsicmd), buf,
+ cmdrsp->scsi.bufflen);
+ return;
+ }
+
+ sg = scsi_sglist(scsicmd);
+ for (i = 0; i < scsi_sg_count(scsicmd); i++) {
+ DBGVER("copying OUT OF buf into 0x%p %d\n",
+ sg_page(sg + i), sg[i].length);
+ thispage_orig = kmap_atomic(sg_page(sg + i));
+ thispage = (void *) ((unsigned long)thispage_orig |
+ sg[i].offset);
+ memcpy(thispage, buf + bufind, sg[i].length);
+ kunmap_atomic(thispage_orig);
+ bufind += sg[i].length;
+ }
+ } else {
+
+ vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
+ for ( ; vdisk->next; vdisk = vdisk->next) {
+ if ((scsidev->channel != vdisk->channel)
+ || (scsidev->id != vdisk->id)
+ || (scsidev->lun != vdisk->lun))
+ continue;
+
+ if (atomic_read(&vdisk->ios_threshold) > 0) {
+ atomic_dec(&vdisk->ios_threshold);
+ if (atomic_read(&vdisk->ios_threshold) == 0) {
+ LOGERR("Resetting error count for disk\n");
+ atomic_set(&vdisk->error_count, 0);
+ }
+ }
+ }
+ }
+}
+
+static void
+complete_scsi_command(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
+{
+ DBGINF("cmdrsp: 0x%p, scsistat:0x%x.\n", cmdrsp, cmdrsp->scsi.scsistat);
+
+ /* take what we need out of cmdrsp and complete the scsicmd */
+ scsicmd->result = cmdrsp->scsi.linuxstat;
+ if (cmdrsp->scsi.linuxstat)
+ do_scsi_linuxstat(cmdrsp, scsicmd);
+ else
+ do_scsi_nolinuxstat(cmdrsp, scsicmd);
+
+ if (scsicmd->scsi_done) {
+ DBGVER("Scsi_DONE\n");
+ scsicmd->scsi_done(scsicmd);
+ }
+}
+
+static inline void
+complete_vdiskmgmt_command(struct uiscmdrsp *cmdrsp)
+{
+ /* copy the result of the taskmgmt and */
+ /* wake up the error handler that is waiting for this */
+ *(int *) cmdrsp->vdiskmgmt.notifyresult = cmdrsp->vdiskmgmt.result;
+ wake_up_all((wait_queue_head_t *) cmdrsp->vdiskmgmt.notify);
+ LOGINF("set notify result to %d\n", cmdrsp->vdiskmgmt.result);
+}
+
+static inline void
+complete_taskmgmt_command(struct uiscmdrsp *cmdrsp)
+{
+ /* copy the result of the taskmgmt and */
+ /* wake up the error handler that is waiting for this */
+ *(int *) cmdrsp->scsitaskmgmt.notifyresult =
+ cmdrsp->scsitaskmgmt.result;
+ wake_up_all((wait_queue_head_t *) cmdrsp->scsitaskmgmt.notify);
+ LOGINF("set notify result to %d\n", cmdrsp->scsitaskmgmt.result);
+}
+
+static void
+drain_queue(struct virthba_info *virthbainfo, struct chaninfo *dc,
+ struct uiscmdrsp *cmdrsp)
+{
+ unsigned long flags;
+ int qrslt = 0;
+ struct scsi_cmnd *scsicmd;
+ struct Scsi_Host *shost = virthbainfo->scsihost;
+
+ while (1) {
+ spin_lock_irqsave(&virthbainfo->chinfo.insertlock, flags);
+ if (!ULTRA_CHANNEL_CLIENT_ACQUIRE_OS(dc->queueinfo->chan,
+ "vhba", NULL)) {
+ spin_unlock_irqrestore(&virthbainfo->chinfo.insertlock,
+ flags);
+ virthbainfo->acquire_failed_cnt++;
+ break;
+ }
+ qrslt = uisqueue_get_cmdrsp(dc->queueinfo, cmdrsp,
+ IOCHAN_FROM_IOPART);
+ ULTRA_CHANNEL_CLIENT_RELEASE_OS(dc->queueinfo->chan,
+ "vhba", NULL);
+ spin_unlock_irqrestore(&virthbainfo->chinfo.insertlock, flags);
+ if (qrslt == 0)
+ break;
+ if (cmdrsp->cmdtype == CMD_SCSI_TYPE) {
+ /* scsicmd location is returned by the
+ * deletion
+ */
+ scsicmd = del_scsipending_entry(virthbainfo,
+ (uintptr_t) cmdrsp->scsi.scsicmd);
+ if (!scsicmd)
+ break;
+ /* complete the orig cmd */
+ complete_scsi_command(cmdrsp, scsicmd);
+ } else if (cmdrsp->cmdtype == CMD_SCSITASKMGMT_TYPE) {
+ if (!del_scsipending_entry(virthbainfo,
+ (uintptr_t) cmdrsp->scsitaskmgmt.scsicmd))
+ break;
+ complete_taskmgmt_command(cmdrsp);
+ } else if (cmdrsp->cmdtype == CMD_NOTIFYGUEST_TYPE) {
+ /* The vHba pointer has no meaning in
+ * a Client/Guest Partition. Let's be
+ * safe and set it to NULL now. Do
+ * not use it here! */
+ cmdrsp->disknotify.vHba = NULL;
+ process_disk_notify(shost, cmdrsp);
+ } else if (cmdrsp->cmdtype == CMD_VDISKMGMT_TYPE) {
+ if (!del_scsipending_entry(virthbainfo,
+ (uintptr_t) cmdrsp->vdiskmgmt.scsicmd))
+ break;
+ complete_vdiskmgmt_command(cmdrsp);
+ } else
+ LOGERR("Invalid cmdtype %d\n", cmdrsp->cmdtype);
+ /* cmdrsp is now available for reuse */
+ }
+}
+
+
+/* main function for the thread that waits for scsi commands to arrive
+ * in a specified queue
+ */
+static int
+process_incoming_rsps(void *v)
+{
+ struct virthba_info *virthbainfo = v;
+ struct chaninfo *dc = &virthbainfo->chinfo;
+ struct uiscmdrsp *cmdrsp = NULL;
+ const int SZ = sizeof(struct uiscmdrsp);
+ U64 mask;
+ unsigned long long rc1;
+
+ UIS_DAEMONIZE("vhba_incoming");
+ /* alloc once and reuse */
+ cmdrsp = kmalloc(SZ, GFP_ATOMIC);
+ if (cmdrsp == NULL) {
+ LOGERR("process_incoming_rsps ****FAILED to malloc - thread exiting\n");
+ complete_and_exit(&dc->threadinfo.has_stopped, 0);
+ return 0;
+ }
+ mask = ULTRA_CHANNEL_ENABLE_INTS;
+ while (1) {
+ wait_event_interruptible_timeout(virthbainfo->rsp_queue,
+ (atomic_read(&virthbainfo->interrupt_rcvd) == 1),
+ usecs_to_jiffies(rsltq_wait_usecs));
+ atomic_set(&virthbainfo->interrupt_rcvd, 0);
+ /* drain queue */
+ drain_queue(virthbainfo, dc, cmdrsp);
+ rc1 = uisqueue_InterlockedOr(virthbainfo->flags_addr, mask);
+ if (dc->threadinfo.should_stop)
+ break;
+ }
+
+ kfree(cmdrsp);
+
+ DBGINF("exiting processing incoming rsps.\n");
+ complete_and_exit(&dc->threadinfo.has_stopped, 0);
+}
+
+/*****************************************************/
+/* proc filesystem functions */
+/*****************************************************/
+
+static ssize_t
+info_proc_read(struct file *file, char __user *buf, size_t len, loff_t *offset)
+{
+ int length = 0;
+ U64 phys_flags_addr;
+ int i;
+ struct virthba_info *virthbainfo;
+ char *vbuf;
+ loff_t pos = *offset;
+
+ if (pos < 0)
+ return -EINVAL;
+
+ if (pos > 0 || !len)
+ return 0;
+
+ vbuf = kzalloc(len, GFP_KERNEL);
+ if (!vbuf)
+ return -ENOMEM;
+
+ for (i = 0; i < VIRTHBASOPENMAX; i++) {
+ if (VirtHbasOpen[i].virthbainfo == NULL)
+ continue;
+
+ virthbainfo = VirtHbasOpen[i].virthbainfo;
+ length += sprintf(vbuf + length, "CHANSOCK is not defined.\n");
+
+ length += sprintf(vbuf + length, "MaxBuffLen:%d\n", MaxBuffLen);
+
+ length += sprintf(vbuf + length, "\nvirthba result queue poll wait:%d usecs.\n",
+ rsltq_wait_usecs);
+
+ length += sprintf(vbuf + length,
+ "\nModule build: Date:%s Time:%s\n",
+ __DATE__, __TIME__);
+ length += sprintf(vbuf + length, "\ninterrupts_rcvd = %llu, interrupts_disabled = %llu\n",
+ virthbainfo->interrupts_rcvd,
+ virthbainfo->interrupts_disabled);
+ length += sprintf(vbuf + length, "\ninterrupts_notme = %llu,\n",
+ virthbainfo->interrupts_notme);
+ phys_flags_addr = virt_to_phys((__force void *)
+ virthbainfo->flags_addr);
+ length += sprintf(vbuf + length, "flags_addr = %p, phys_flags_addr=0x%016llx, FeatureFlags=%llu\n",
+ virthbainfo->flags_addr, phys_flags_addr,
+ (__le64)readq(virthbainfo->flags_addr));
+ length += sprintf(vbuf + length, "acquire_failed_cnt:%llu\n",
+ virthbainfo->acquire_failed_cnt);
+ length += sprintf(vbuf + length, "\n");
+ }
+ if (copy_to_user(buf, vbuf, length)) {
+ kfree(vbuf);
+ return -EFAULT;
+ }
+
+ kfree(vbuf);
+ *offset += length;
+ return length;
+}
+
+static ssize_t
+enable_ints_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ return 0;
+}
+
+static ssize_t
+enable_ints_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char buf[4];
+ int i, new_value;
+ struct virthba_info *virthbainfo;
+ U64 __iomem *Features_addr;
+ U64 mask;
+
+ if (count >= ARRAY_SIZE(buf))
+ return -EINVAL;
+
+ buf[count] = '\0';
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("copy_from_user failed. buf<<%.*s>> count<<%lu>>\n",
+ (int) count, buf, count);
+ return -EFAULT;
+ }
+
+ i = sscanf(buf, "%d", &new_value);
+
+ if (i < 1) {
+ LOGERR("Failed to scan value for enable_ints, buf<<%.*s>>",
+ (int) count, buf);
+ return -EFAULT;
+ }
+
+ /* set all counts to new_value usually 0 */
+ for (i = 0; i < VIRTHBASOPENMAX; i++) {
+ if (VirtHbasOpen[i].virthbainfo != NULL) {
+ virthbainfo = VirtHbasOpen[i].virthbainfo;
+ Features_addr =
+ &virthbainfo->chinfo.queueinfo->chan->Features;
+ if (new_value == 1) {
+ mask = ~(ULTRA_IO_CHANNEL_IS_POLLING |
+ ULTRA_IO_DRIVER_DISABLES_INTS);
+ uisqueue_InterlockedAnd(Features_addr, mask);
+ mask = ULTRA_IO_DRIVER_ENABLES_INTS;
+ uisqueue_InterlockedOr(Features_addr, mask);
+ rsltq_wait_usecs = 4000000;
+ } else {
+ mask = ~(ULTRA_IO_DRIVER_ENABLES_INTS |
+ ULTRA_IO_DRIVER_DISABLES_INTS);
+ uisqueue_InterlockedAnd(Features_addr, mask);
+ mask = ULTRA_IO_CHANNEL_IS_POLLING;
+ uisqueue_InterlockedOr(Features_addr, mask);
+ rsltq_wait_usecs = 4000;
+ }
+ }
+ }
+ return count;
+}
+
+static ssize_t
+rqwu_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char buf[16];
+ int i, usecs;
+
+ if (count >= ARRAY_SIZE(buf))
+ return -EINVAL;
+
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("copy_from_user failed. buf<<%.*s>> count<<%lu>>\n",
+ (int) count, buf, count);
+ return -EFAULT;
+ }
+
+ i = sscanf(buf, "%d", &usecs);
+
+ if (i < 1) {
+ LOGERR("Failed to scan value for rqwait_usecs buf<<%.*s>>",
+ (int) count, buf);
+ return -EFAULT;
+ }
+
+ /* set global wait time */
+ rsltq_wait_usecs = usecs;
+ return count;
+}
+
+/* As per VirtpciFunc returns 1 for success and 0 for failure */
+static int
+virthba_serverup(struct virtpci_dev *virtpcidev)
+{
+ struct virthba_info *virthbainfo =
+ (struct virthba_info *) ((struct Scsi_Host *) virtpcidev->scsi.
+ scsihost)->hostdata;
+
+ DBGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo,
+ virtpcidev->deviceNo);
+
+ if (!virthbainfo->serverdown) {
+ DBGINF("Server up message recieved while server is already up.\n");
+ return 1;
+ }
+ if (virthbainfo->serverchangingstate) {
+ LOGERR("Server already processing change state message\n");
+ return 0;
+ }
+
+ virthbainfo->serverchangingstate = true;
+ /* Must transition channel to ATTACHED state BEFORE we
+ * can start using the device again
+ */
+ ULTRA_CHANNEL_CLIENT_TRANSITION(virthbainfo->chinfo.queueinfo->chan,
+ dev_name(&virtpcidev->generic_dev),
+ CHANNELCLI_ATTACHED, NULL);
+
+ /* Start Processing the IOVM Response Queue Again */
+ if (!uisthread_start(&virthbainfo->chinfo.threadinfo,
+ process_incoming_rsps,
+ virthbainfo, "vhba_incoming")) {
+ LOGERR("uisthread_start rsp ****FAILED\n");
+ return 0;
+ }
+ virthbainfo->serverdown = false;
+ virthbainfo->serverchangingstate = false;
+
+ return 1;
+}
+
+static void
+virthba_serverdown_complete(struct work_struct *work)
+{
+ struct virthba_info *virthbainfo;
+ struct virtpci_dev *virtpcidev;
+ int i;
+ struct scsipending *pendingdel = NULL;
+ struct scsi_cmnd *scsicmd = NULL;
+ struct uiscmdrsp *cmdrsp;
+ unsigned long flags;
+
+ virthbainfo = container_of(work, struct virthba_info,
+ serverdown_completion);
+
+ /* Stop Using the IOVM Response Queue (queue should be drained
+ * by the end)
+ */
+ uisthread_stop(&virthbainfo->chinfo.threadinfo);
+
+ /* Fail Commands that weren't completed */
+ spin_lock_irqsave(&virthbainfo->privlock, flags);
+ for (i = 0; i < MAX_PENDING_REQUESTS; i++) {
+ pendingdel = &(virthbainfo->pending[i]);
+ switch (pendingdel->cmdtype) {
+ case CMD_SCSI_TYPE:
+ scsicmd = (struct scsi_cmnd *) pendingdel->sent;
+ scsicmd->result = (DID_RESET << 16);
+ if (scsicmd->scsi_done)
+ scsicmd->scsi_done(scsicmd);
+ break;
+ case CMD_SCSITASKMGMT_TYPE:
+ cmdrsp = (struct uiscmdrsp *) pendingdel->sent;
+ DBGINF("cmdrsp=0x%x, notify=0x%x\n", cmdrsp,
+ cmdrsp->scsitaskmgmt.notify);
+ *(int *) cmdrsp->scsitaskmgmt.notifyresult =
+ TASK_MGMT_FAILED;
+ wake_up_all((wait_queue_head_t *)
+ cmdrsp->scsitaskmgmt.notify);
+ break;
+ case CMD_VDISKMGMT_TYPE:
+ cmdrsp = (struct uiscmdrsp *) pendingdel->sent;
+ *(int *) cmdrsp->vdiskmgmt.notifyresult =
+ VDISK_MGMT_FAILED;
+ wake_up_all((wait_queue_head_t *)
+ cmdrsp->vdiskmgmt.notify);
+ break;
+ default:
+ if (pendingdel->sent != NULL)
+ LOGERR("Unknown command type: 0x%x. Only freeing list structure.\n",
+ pendingdel->cmdtype);
+ }
+ pendingdel->cmdtype = 0;
+ pendingdel->sent = NULL;
+ }
+ spin_unlock_irqrestore(&virthbainfo->privlock, flags);
+
+ virtpcidev = virthbainfo->virtpcidev;
+
+ DBGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo,
+ virtpcidev->deviceNo);
+ virthbainfo->serverdown = true;
+ virthbainfo->serverchangingstate = false;
+ /* Return the ServerDown response to Command */
+ visorchipset_device_pause_response(virtpcidev->busNo,
+ virtpcidev->deviceNo, 0);
+}
+
+/* As per VirtpciFunc returns 1 for success and 0 for failure */
+static int
+virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state)
+{
+ struct virthba_info *virthbainfo =
+ (struct virthba_info *) ((struct Scsi_Host *) virtpcidev->scsi.
+ scsihost)->hostdata;
+
+ DBGINF("virthba_serverdown");
+ DBGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo,
+ virtpcidev->deviceNo);
+
+ if (!virthbainfo->serverdown && !virthbainfo->serverchangingstate) {
+ virthbainfo->serverchangingstate = true;
+ queue_work(virthba_serverdown_workqueue,
+ &virthbainfo->serverdown_completion);
+ } else if (virthbainfo->serverchangingstate) {
+ LOGERR("Server already processing change state message\n");
+ return 0;
+ } else
+ LOGERR("Server already down, but another server down message received.");
+
+ return 1;
+}
+
+/*****************************************************/
+/* Module Init & Exit functions */
+/*****************************************************/
+
+static int __init
+virthba_parse_line(char *str)
+{
+ DBGINF("In virthba_parse_line %s\n", str);
+ return 1;
+}
+
+static void __init
+virthba_parse_options(char *line)
+{
+ char *next = line;
+
+ POSTCODE_LINUX_2(VHBA_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+ if (line == NULL || !*line)
+ return;
+ while ((line = next) != NULL) {
+ next = strchr(line, ' ');
+ if (next != NULL)
+ *next++ = 0;
+ if (!virthba_parse_line(line))
+ DBGINF("Unknown option '%s'\n", line);
+ }
+
+ POSTCODE_LINUX_2(VHBA_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
+}
+
+static int __init
+virthba_mod_init(void)
+{
+ int error;
+ int i;
+
+ LOGINF("Entering virthba_mod_init...\n");
+
+ POSTCODE_LINUX_2(VHBA_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+ virthba_parse_options(virthba_options);
+
+ error = virtpci_register_driver(&virthba_driver);
+ if (error < 0) {
+ LOGERR("register ****FAILED 0x%x\n", error);
+ POSTCODE_LINUX_3(VHBA_CREATE_FAILURE_PC, error,
+ POSTCODE_SEVERITY_ERR);
+ } else {
+ /* create the proc directories */
+ virthba_proc_dir = proc_mkdir(DIR_PROC_ENTRY, NULL);
+ info_proc_entry = proc_create(INFO_PROC_ENTRY_FN, 0,
+ virthba_proc_dir,
+ &proc_info_fops);
+ rqwaitus_proc_entry = proc_create(RQWU_PROC_ENTRY_FN, 0,
+ virthba_proc_dir,
+ &proc_rqwu_fops);
+ enable_ints_proc_entry = proc_create(ENABLE_INTS_ENTRY_FN, 0,
+ virthba_proc_dir,
+ &proc_enable_ints_fops);
+
+ /* Initialize DARWorkQ */
+ INIT_WORK(&DARWorkQ, doDiskAddRemove);
+ spin_lock_init(&DARWorkQLock);
+
+ /* clear out array */
+ for (i = 0; i < VIRTHBASOPENMAX; i++)
+ VirtHbasOpen[i].virthbainfo = NULL;
+ /* Initialize the serverdown workqueue */
+ virthba_serverdown_workqueue =
+ create_singlethread_workqueue("virthba_serverdown");
+ if (virthba_serverdown_workqueue == NULL) {
+ LOGERR("**** FAILED virthba_serverdown_workqueue creation\n");
+ POSTCODE_LINUX_2(VHBA_CREATE_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ error = -1;
+ }
+ }
+
+ POSTCODE_LINUX_2(VHBA_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
+ LOGINF("Leaving virthba_mod_init\n");
+ return error;
+}
+
+static ssize_t
+virthba_acquire_lun(struct device *cdev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct uisscsi_dest vdest;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ int i;
+
+ i = sscanf(buf, "%d-%d-%d", &vdest.channel, &vdest.id, &vdest.lun);
+ if (i != 3)
+ return i;
+
+ return forward_vdiskmgmt_command(VDISK_MGMT_ACQUIRE, shost, &vdest);
+}
+
+static ssize_t
+virthba_release_lun(struct device *cdev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct uisscsi_dest vdest;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ int i;
+
+ i = sscanf(buf, "%d-%d-%d", &vdest.channel, &vdest.id, &vdest.lun);
+ if (i != 3)
+ return i;
+
+ return forward_vdiskmgmt_command(VDISK_MGMT_RELEASE, shost, &vdest);
+}
+
+#define CLASS_DEVICE_ATTR(_name, _mode, _show, _store) \
+ struct device_attribute class_device_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+static CLASS_DEVICE_ATTR(acquire_lun, S_IWUSR, NULL, virthba_acquire_lun);
+static CLASS_DEVICE_ATTR(release_lun, S_IWUSR, NULL, virthba_release_lun);
+
+static DEVICE_ATTRIBUTE *virthba_shost_attrs[] = {
+ &class_device_attr_acquire_lun,
+ &class_device_attr_release_lun,
+ NULL
+};
+
+static void __exit
+virthba_mod_exit(void)
+{
+ LOGINF("entering virthba_mod_exit...\n");
+
+ virtpci_unregister_driver(&virthba_driver);
+ /* unregister is going to call virthba_remove */
+ /* destroy serverdown completion workqueue */
+ if (virthba_serverdown_workqueue) {
+ destroy_workqueue(virthba_serverdown_workqueue);
+ virthba_serverdown_workqueue = NULL;
+ }
+
+ if (info_proc_entry)
+ remove_proc_entry(INFO_PROC_ENTRY_FN, virthba_proc_dir);
+
+ if (rqwaitus_proc_entry)
+ remove_proc_entry(RQWU_PROC_ENTRY_FN, NULL);
+
+ if (enable_ints_proc_entry)
+ remove_proc_entry(ENABLE_INTS_ENTRY_FN, NULL);
+
+ if (virthba_proc_dir)
+ remove_proc_entry(DIR_PROC_ENTRY, NULL);
+
+ LOGINF("Leaving virthba_mod_exit\n");
+
+}
+
+/* specify function to be run at module insertion time */
+module_init(virthba_mod_init);
+
+/* specify function to be run when module is removed */
+module_exit(virthba_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Usha Srinivasan");
+MODULE_ALIAS("uisvirthba");
+ /* this is extracted during depmod and kept in modules.dep */
+/* module parameter */
+module_param(virthba_options, charp, S_IRUGO);
diff --git a/drivers/staging/unisys/virthba/virthba.h b/drivers/staging/unisys/virthba/virthba.h
new file mode 100644
index 000000000000..88b797439a16
--- /dev/null
+++ b/drivers/staging/unisys/virthba/virthba.h
@@ -0,0 +1,31 @@
+/* virthba.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * Unisys Virtual HBA driver header
+ */
+
+
+
+#ifndef __VIRTHBA_H__
+#define __VIRTHBA_H__
+
+
+#define VIRTHBA_VERSION "01.00"
+
+
+#endif /* __VIRTHBA_H__ */
diff --git a/drivers/staging/unisys/virtpci/Kconfig b/drivers/staging/unisys/virtpci/Kconfig
new file mode 100644
index 000000000000..e59efcbc4d3b
--- /dev/null
+++ b/drivers/staging/unisys/virtpci/Kconfig
@@ -0,0 +1,10 @@
+#
+# Unisys virtpci configuration
+#
+
+config UNISYS_VIRTPCI
+ tristate "Unisys virtpci driver"
+ depends on UNISYSSPAR && UNISYS_UISLIB
+ ---help---
+ If you say Y here, you will enable the Unisys virtpci driver.
+
diff --git a/drivers/staging/unisys/virtpci/Makefile b/drivers/staging/unisys/virtpci/Makefile
new file mode 100644
index 000000000000..f9399aabddd1
--- /dev/null
+++ b/drivers/staging/unisys/virtpci/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for Unisys virtpci
+#
+
+obj-$(CONFIG_UNISYS_VIRTPCI) += virtpci.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+ccflags-y += -Idrivers/staging/unisys/uislib
+ccflags-y += -Idrivers/staging/unisys/common-spar/include
+ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
+
+ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION
+
diff --git a/drivers/staging/unisys/virtpci/virtpci.c b/drivers/staging/unisys/virtpci/virtpci.c
new file mode 100644
index 000000000000..8e34650b00b5
--- /dev/null
+++ b/drivers/staging/unisys/virtpci/virtpci.c
@@ -0,0 +1,1771 @@
+/* virtpci.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#define EXPORT_SYMTAB
+
+#include <linux/kernel.h>
+#ifdef CONFIG_MODVERSIONS
+#include <config/modversions.h>
+#endif
+#include "uniklog.h"
+#include "diagnostics/appos_subsystems.h"
+#include "uisutils.h"
+#include "commontypes.h"
+#include "vbuschannel.h"
+#include "vbushelper.h"
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
+#include <linux/proc_fs.h>
+#include <linux/if_ether.h>
+#include <linux/version.h>
+#include "version.h"
+#include "guestlinuxdebug.h"
+
+struct driver_private {
+ struct kobject kobj;
+ struct klist klist_devices;
+ struct klist_node knode_bus;
+ struct module_kobject *mkobj;
+ struct device_driver *driver;
+};
+#define to_driver(obj) container_of(obj, struct driver_private, kobj)
+
+/* bus_id went away in 2.6.30 - the size was 20 bytes, so we'll define
+ * it ourselves, and a macro to make getting the field a bit simpler.
+ */
+#ifndef BUS_ID_SIZE
+#define BUS_ID_SIZE 20
+#endif
+
+#define BUS_ID(x) dev_name(x)
+
+#include "virtpci.h"
+
+/* this is shorter than using __FILE__ (full path name) in
+ * debug/info/error messages
+ */
+#define CURRENT_FILE_PC VIRT_PCI_PC_virtpci_c
+#define __MYFILE__ "virtpci.c"
+
+#define VIRTPCI_VERSION "01.00"
+
+/*****************************************************/
+/* Forward declarations */
+/*****************************************************/
+
+static int delete_vbus_device(struct device *vbus, void *data);
+static int match_busid(struct device *dev, void *data);
+static void virtpci_bus_release(struct device *dev);
+static void virtpci_device_release(struct device *dev);
+static int virtpci_device_add(struct device *parentbus, int devtype,
+ struct add_virt_guestpart *addparams,
+ struct scsi_adap_info *scsi,
+ struct net_adap_info *net);
+static int virtpci_device_del(struct device *parentbus, int devtype,
+ struct vhba_wwnn *wwnn, unsigned char macaddr[]);
+static int virtpci_device_serverdown(struct device *parentbus, int devtype,
+ struct vhba_wwnn *wwnn,
+ unsigned char macaddr[]);
+static int virtpci_device_serverup(struct device *parentbus, int devtype,
+ struct vhba_wwnn *wwnn,
+ unsigned char macaddr[]);
+static ssize_t virtpci_driver_attr_show(struct kobject *kobj,
+ struct attribute *attr, char *buf);
+static ssize_t virtpci_driver_attr_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buf, size_t count);
+static int virtpci_bus_match(struct device *dev, struct device_driver *drv);
+static int virtpci_uevent(struct device *dev, struct kobj_uevent_env *env);
+static int virtpci_device_suspend(struct device *dev, pm_message_t state);
+static int virtpci_device_resume(struct device *dev);
+static int virtpci_device_probe(struct device *dev);
+static int virtpci_device_remove(struct device *dev);
+static ssize_t virt_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos);
+static ssize_t info_proc_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offset);
+
+static const struct file_operations proc_virt_fops = {
+ .write = virt_proc_write,
+};
+
+static const struct file_operations proc_info_fops = {
+ .read = info_proc_read,
+};
+
+/*****************************************************/
+/* Globals */
+/*****************************************************/
+
+/* methods in bus_type struct allow the bus code to serve as an
+ * intermediary between the device core and individual device core and
+ * individual drivers
+ */
+static struct bus_type virtpci_bus_type = {
+ .name = "uisvirtpci",
+ .match = virtpci_bus_match,
+ .uevent = virtpci_uevent,
+ .suspend = virtpci_device_suspend,
+ .resume = virtpci_device_resume,
+};
+
+static struct device virtpci_rootbus_device = {
+ .init_name = "vbusroot", /* root bus */
+ .release = virtpci_bus_release
+};
+
+/* filled in with info about parent chipset driver when we register with it */
+static ULTRA_VBUS_DEVICEINFO Chipset_DriverInfo;
+
+static const struct sysfs_ops virtpci_driver_sysfs_ops = {
+ .show = virtpci_driver_attr_show,
+ .store = virtpci_driver_attr_store,
+};
+
+static struct kobj_type virtpci_driver_kobj_type = {
+ .sysfs_ops = &virtpci_driver_sysfs_ops,
+};
+
+static struct virtpci_dev *VpcidevListHead;
+static DEFINE_RWLOCK(VpcidevListLock);
+
+/* filled in with info about this driver, wrt it servicing client busses */
+static ULTRA_VBUS_DEVICEINFO Bus_DriverInfo;
+
+/* virtpci_proc_dir_entry is used to create the proc entry directory
+ * for virtpci
+ */
+static struct proc_dir_entry *virtpci_proc_dir;
+/* virt_proc_entry is used to tell virtpci to add/delete vhbas/vnics/vbuses */
+static struct proc_dir_entry *virt_proc_entry;
+/* info_proc_entry is used to tell virtpci to display current info
+ * kept in the driver
+ */
+static struct proc_dir_entry *info_proc_entry;
+#define VIRT_PROC_ENTRY_FN "virt"
+#define INFO_PROC_ENTRY_FN "info"
+#define DIR_PROC_ENTRY "virtpci"
+
+struct virtpci_busdev {
+ struct device virtpci_bus_device;
+};
+
+/*****************************************************/
+/* Local functions */
+/*****************************************************/
+
+static inline
+int WAIT_FOR_IO_CHANNEL(ULTRA_IO_CHANNEL_PROTOCOL __iomem *chanptr)
+{
+ int count = 120;
+ while (count > 0) {
+
+ if (ULTRA_CHANNEL_SERVER_READY(&chanptr->ChannelHeader))
+ return 1;
+ UIS_THREAD_WAIT_SEC(1);
+ count--;
+ }
+ return 0;
+}
+
+/* Write the contents of <info> to the ULTRA_VBUS_CHANNEL_PROTOCOL.ChpInfo. */
+static int write_vbus_chpInfo(ULTRA_VBUS_CHANNEL_PROTOCOL *chan,
+ ULTRA_VBUS_DEVICEINFO *info)
+{
+ int off;
+ if (!chan) {
+ LOGERR("vbus channel not present");
+ return -1;
+ }
+ off = sizeof(ULTRA_CHANNEL_PROTOCOL) + chan->HdrInfo.chpInfoByteOffset;
+ if (chan->HdrInfo.chpInfoByteOffset == 0) {
+ LOGERR("vbus channel not used, because chpInfoByteOffset == 0");
+ return -1;
+ }
+ memcpy(((U8 *) (chan)) + off, info, sizeof(*info));
+ return 0;
+}
+
+/* Write the contents of <info> to the ULTRA_VBUS_CHANNEL_PROTOCOL.BusInfo. */
+static int write_vbus_busInfo(ULTRA_VBUS_CHANNEL_PROTOCOL *chan,
+ ULTRA_VBUS_DEVICEINFO *info)
+{
+ int off;
+ if (!chan) {
+ LOGERR("vbus channel not present");
+ return -1;
+ }
+ off = sizeof(ULTRA_CHANNEL_PROTOCOL) + chan->HdrInfo.busInfoByteOffset;
+ if (chan->HdrInfo.busInfoByteOffset == 0) {
+ LOGERR("vbus channel not used, because busInfoByteOffset == 0");
+ return -1;
+ }
+ memcpy(((U8 *) (chan)) + off, info, sizeof(*info));
+ return 0;
+}
+
+/* Write the contents of <info> to the
+ * ULTRA_VBUS_CHANNEL_PROTOCOL.DevInfo[<devix>].
+ */
+static int
+write_vbus_devInfo(ULTRA_VBUS_CHANNEL_PROTOCOL *chan,
+ ULTRA_VBUS_DEVICEINFO *info, int devix)
+{
+ int off;
+ if (!chan) {
+ LOGERR("vbus channel not present");
+ return -1;
+ }
+ off =
+ (sizeof(ULTRA_CHANNEL_PROTOCOL) +
+ chan->HdrInfo.devInfoByteOffset) +
+ (chan->HdrInfo.deviceInfoStructBytes * devix);
+ if (chan->HdrInfo.devInfoByteOffset == 0) {
+ LOGERR("vbus channel not used, because devInfoByteOffset == 0");
+ return -1;
+ }
+ memcpy(((U8 *) (chan)) + off, info, sizeof(*info));
+ return 0;
+}
+
+/* adds a vbus
+ * returns 0 failure, 1 success,
+ */
+static int add_vbus(struct add_vbus_guestpart *addparams)
+{
+ int ret;
+ struct device *vbus;
+ vbus = kzalloc(sizeof(struct device), GFP_ATOMIC);
+
+ POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+ if (!vbus)
+ return 0;
+
+ dev_set_name(vbus, "vbus%d", addparams->busNo);
+ vbus->release = virtpci_bus_release;
+ vbus->parent = &virtpci_rootbus_device; /* root bus is parent */
+ vbus->bus = &virtpci_bus_type; /* bus type */
+ vbus->platform_data = (__force void *)addparams->chanptr;
+
+ /* register a virt bus device -
+ * this bus shows up under /sys/devices with .name value
+ * "virtpci%d" any devices added to this bus then show up under
+ * /sys/devices/virtpci0
+ */
+ ret = device_register(vbus);
+ if (ret) {
+ LOGERR("device_register FAILED:%d\n", ret);
+ POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
+ return 0;
+ }
+ write_vbus_chpInfo(vbus->platform_data /* chanptr */ ,
+ &Chipset_DriverInfo);
+ write_vbus_busInfo(vbus->platform_data /* chanptr */ , &Bus_DriverInfo);
+ LOGINF("Added vbus %d; device %s created successfully\n",
+ addparams->busNo, BUS_ID(vbus));
+ POSTCODE_LINUX_2(VPCI_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
+ return 1;
+}
+
+/* for CHANSOCK wwwnn/max are AUTO-GENERATED; for normal channels,
+ * wwnn/max are in the channel header.
+ */
+#define GET_SCSIADAPINFO_FROM_CHANPTR(chanptr) { \
+ memcpy_fromio(&scsi.wwnn, \
+ &((ULTRA_IO_CHANNEL_PROTOCOL __iomem *) \
+ chanptr)->vhba.wwnn, \
+ sizeof(struct vhba_wwnn)); \
+ memcpy_fromio(&scsi.max, \
+ &((ULTRA_IO_CHANNEL_PROTOCOL __iomem *) \
+ chanptr)->vhba.max, \
+ sizeof(struct vhba_config_max)); \
+ }
+
+/* find bus device with the busid that matches - match_busid matches bus_id */
+#define GET_BUS_DEV(busno) { \
+ sprintf(busid, "vbus%d", busno); \
+ vbus = bus_find_device(&virtpci_bus_type, NULL, \
+ (void *)busid, match_busid); \
+ if (!vbus) { \
+ LOGERR("**** FAILED to find vbus %s\n", busid); \
+ return 0; \
+ } \
+}
+
+/* adds a vhba
+ * returns 0 failure, 1 success,
+ */
+static int add_vhba(struct add_virt_guestpart *addparams)
+{
+ int i;
+ struct scsi_adap_info scsi;
+ struct device *vbus;
+ unsigned char busid[BUS_ID_SIZE];
+
+ POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+ if (!WAIT_FOR_IO_CHANNEL
+ ((ULTRA_IO_CHANNEL_PROTOCOL __iomem *) addparams->chanptr)) {
+ LOGERR("Timed out. Channel not ready\n");
+ POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
+ return 0;
+ }
+
+ GET_SCSIADAPINFO_FROM_CHANPTR(addparams->chanptr);
+
+ GET_BUS_DEV(addparams->busNo);
+
+ LOGINF("Adding vhba wwnn:%x:%x config:%d-%d-%d-%d chanptr:%p\n",
+ scsi.wwnn.wwnn1, scsi.wwnn.wwnn2,
+ scsi.max.max_channel, scsi.max.max_id, scsi.max.max_lun,
+ scsi.max.cmd_per_lun, addparams->chanptr);
+ i = virtpci_device_add(vbus, VIRTHBA_TYPE, addparams, &scsi, NULL);
+ if (i) {
+ LOGINF("Added vhba wwnn:%x:%x chanptr:%p\n", scsi.wwnn.wwnn1,
+ scsi.wwnn.wwnn2, addparams->chanptr);
+ POSTCODE_LINUX_3(VPCI_CREATE_EXIT_PC, i,
+ POSTCODE_SEVERITY_INFO);
+ }
+ return i;
+
+}
+
+/* for CHANSOCK macaddr is AUTO-GENERATED; for normal channels,
+ * macaddr is in the channel header.
+ */
+#define GET_NETADAPINFO_FROM_CHANPTR(chanptr) { \
+ memcpy_fromio(net.mac_addr, \
+ ((ULTRA_IO_CHANNEL_PROTOCOL __iomem *) \
+ chanptr)->vnic.macaddr, \
+ MAX_MACADDR_LEN); \
+ net.num_rcv_bufs = \
+ readl(&((ULTRA_IO_CHANNEL_PROTOCOL __iomem *) \
+ chanptr)->vnic.num_rcv_bufs); \
+ net.mtu = readl(&((ULTRA_IO_CHANNEL_PROTOCOL __iomem *) \
+ chanptr)->vnic.mtu); \
+ memcpy_fromio(&net.zoneGuid, \
+ &((ULTRA_IO_CHANNEL_PROTOCOL __iomem *) \
+ chanptr)->vnic.zoneGuid, \
+ sizeof(GUID)); \
+}
+
+/* adds a vnic
+ * returns 0 failure, 1 success,
+ */
+static int
+add_vnic(struct add_virt_guestpart *addparams)
+{
+ int i;
+ struct net_adap_info net;
+ struct device *vbus;
+ unsigned char busid[BUS_ID_SIZE];
+
+ POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+ if (!WAIT_FOR_IO_CHANNEL
+ ((ULTRA_IO_CHANNEL_PROTOCOL __iomem *) addparams->chanptr)) {
+ LOGERR("Timed out, channel not ready\n");
+ POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
+ return 0;
+ }
+
+ GET_NETADAPINFO_FROM_CHANPTR(addparams->chanptr);
+
+ GET_BUS_DEV(addparams->busNo);
+
+ LOGINF("Adding vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x rcvbufs:%d mtu:%d chanptr:%p{%-8.8lx-%-4.4x-%-4.4x-%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x}\n",
+ net.mac_addr[0], net.mac_addr[1], net.mac_addr[2], net.mac_addr[3],
+ net.mac_addr[4], net.mac_addr[5], net.num_rcv_bufs, net.mtu,
+ addparams->chanptr, (ulong) net.zoneGuid.data1, net.zoneGuid.data2,
+ net.zoneGuid.data3, net.zoneGuid.data4[0], net.zoneGuid.data4[1],
+ net.zoneGuid.data4[2], net.zoneGuid.data4[3],
+ net.zoneGuid.data4[4], net.zoneGuid.data4[5],
+ net.zoneGuid.data4[6], net.zoneGuid.data4[7]);
+ i = virtpci_device_add(vbus, VIRTNIC_TYPE, addparams, NULL, &net);
+ if (i) {
+ LOGINF("Added vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ net.mac_addr[0], net.mac_addr[1], net.mac_addr[2],
+ net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]);
+ POSTCODE_LINUX_3(VPCI_CREATE_EXIT_PC, i,
+ POSTCODE_SEVERITY_INFO);
+ return 1;
+ }
+ return 0;
+}
+
+/* delete vbus
+ * returns 0 failure, 1 success,
+ */
+static int
+delete_vbus(struct del_vbus_guestpart *delparams)
+{
+ struct device *vbus;
+ unsigned char busid[BUS_ID_SIZE];
+
+ GET_BUS_DEV(delparams->busNo);
+ /* ensure that bus has no devices? -- TBD */
+ LOGINF("Deleting %s\n", BUS_ID(vbus));
+ if (delete_vbus_device(vbus, NULL))
+ return 0; /* failure */
+ LOGINF("Deleted vbus %d\n", delparams->busNo);
+ return 1;
+}
+
+static int
+delete_vbus_device(struct device *vbus, void *data)
+{
+ int checkforroot = (data != NULL);
+ struct device *pDev = &virtpci_rootbus_device;
+
+ if ((checkforroot) && match_busid(vbus, (void *) BUS_ID(pDev))) {
+ /* skip it - don't delete root bus */
+ LOGINF("skipping root bus\n");
+ return 0; /* pretend no error */
+ }
+ LOGINF("Calling unregister for %s\n", BUS_ID(vbus));
+ device_unregister(vbus);
+ kfree(vbus);
+ LOGINF("VBus unregister and freed\n");
+ return 0; /* no error */
+}
+
+/* pause vhba
+* returns 0 failure, 1 success,
+*/
+static int pause_vhba(struct pause_virt_guestpart *pauseparams)
+{
+ int i;
+ struct scsi_adap_info scsi;
+
+ GET_SCSIADAPINFO_FROM_CHANPTR(pauseparams->chanptr);
+
+ LOGINF("Pausing vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, scsi.wwnn.wwnn2);
+ i = virtpci_device_serverdown(NULL /*no parent bus */ , VIRTHBA_TYPE,
+ &scsi.wwnn, NULL);
+ if (i)
+ LOGINF("Paused vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1,
+ scsi.wwnn.wwnn2);
+ return i;
+}
+
+/* pause vnic
+ * returns 0 failure, 1 success,
+ */
+static int pause_vnic(struct pause_virt_guestpart *pauseparams)
+{
+ int i;
+ struct net_adap_info net;
+
+ GET_NETADAPINFO_FROM_CHANPTR(pauseparams->chanptr);
+
+ LOGINF("Pausing vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ net.mac_addr[0], net.mac_addr[1], net.mac_addr[2],
+ net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]);
+ i = virtpci_device_serverdown(NULL /*no parent bus */ , VIRTNIC_TYPE,
+ NULL, net.mac_addr);
+ if (i) {
+ LOGINF(" Paused vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ net.mac_addr[0], net.mac_addr[1], net.mac_addr[2],
+ net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]);
+ }
+ return i;
+}
+
+/* resume vhba
+ * returns 0 failure, 1 success,
+ */
+static int resume_vhba(struct resume_virt_guestpart *resumeparams)
+{
+ int i;
+ struct scsi_adap_info scsi;
+
+ GET_SCSIADAPINFO_FROM_CHANPTR(resumeparams->chanptr);
+
+ LOGINF("Resuming vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, scsi.wwnn.wwnn2);
+ i = virtpci_device_serverup(NULL /*no parent bus */ , VIRTHBA_TYPE,
+ &scsi.wwnn, NULL);
+ if (i)
+ LOGINF("Resumed vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1,
+ scsi.wwnn.wwnn2);
+ return i;
+}
+
+/* resume vnic
+* returns 0 failure, 1 success,
+*/
+static int
+resume_vnic(struct resume_virt_guestpart *resumeparams)
+{
+ int i;
+ struct net_adap_info net;
+
+ GET_NETADAPINFO_FROM_CHANPTR(resumeparams->chanptr);
+
+ LOGINF("Resuming vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ net.mac_addr[0], net.mac_addr[1], net.mac_addr[2],
+ net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]);
+ i = virtpci_device_serverup(NULL /*no parent bus */ , VIRTNIC_TYPE,
+ NULL, net.mac_addr);
+ if (i) {
+ LOGINF(" Resumed vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ net.mac_addr[0], net.mac_addr[1], net.mac_addr[2],
+ net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]);
+ }
+ return i;
+}
+
+/* delete vhba
+* returns 0 failure, 1 success,
+*/
+static int delete_vhba(struct del_virt_guestpart *delparams)
+{
+ int i;
+ struct scsi_adap_info scsi;
+
+ GET_SCSIADAPINFO_FROM_CHANPTR(delparams->chanptr);
+
+ LOGINF("Deleting vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, scsi.wwnn.wwnn2);
+ i = virtpci_device_del(NULL /*no parent bus */ , VIRTHBA_TYPE,
+ &scsi.wwnn, NULL);
+ if (i) {
+ LOGINF("Deleted vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1,
+ scsi.wwnn.wwnn2);
+ return 1;
+ }
+ return 0;
+}
+
+/* deletes a vnic
+ * returns 0 failure, 1 success,
+ */
+static int delete_vnic(struct del_virt_guestpart *delparams)
+{
+ int i;
+ struct net_adap_info net;
+
+ GET_NETADAPINFO_FROM_CHANPTR(delparams->chanptr);
+
+ LOGINF("Deleting vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ net.mac_addr[0], net.mac_addr[1], net.mac_addr[2],
+ net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]);
+ i = virtpci_device_del(NULL /*no parent bus */ , VIRTNIC_TYPE, NULL,
+ net.mac_addr);
+ if (i) {
+ LOGINF("Deleted vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ net.mac_addr[0], net.mac_addr[1], net.mac_addr[2],
+ net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]);
+ }
+ return i;
+}
+
+#define DELETE_ONE_VPCIDEV(vpcidev) { \
+ LOGINF("calling device_unregister:%p\n", &vpcidev->generic_dev); \
+ device_unregister(&vpcidev->generic_dev); \
+ LOGINF("Deleted %p\n", vpcidev); \
+ kfree(vpcidev); \
+}
+
+/* deletes all vhbas and vnics
+ * returns 0 failure, 1 success,
+ */
+static void delete_all(void)
+{
+ int count = 0;
+ unsigned long flags;
+ struct virtpci_dev *tmpvpcidev, *nextvpcidev;
+
+ /* delete the entire vhba/vnic list in one shot */
+ write_lock_irqsave(&VpcidevListLock, flags);
+ tmpvpcidev = VpcidevListHead;
+ VpcidevListHead = NULL;
+ write_unlock_irqrestore(&VpcidevListLock, flags);
+
+ /* delete one vhba/vnic at a time */
+ while (tmpvpcidev) {
+ nextvpcidev = tmpvpcidev->next;
+ /* delete the vhba/vnic at tmpvpcidev */
+ DELETE_ONE_VPCIDEV(tmpvpcidev);
+ tmpvpcidev = nextvpcidev;
+ count++;
+ }
+ LOGINF("Deleted %d vhbas/vnics.\n", count);
+
+ /* now delete each vbus */
+ if (bus_for_each_dev
+ (&virtpci_bus_type, NULL, (void *) 1, delete_vbus_device))
+ LOGERR("delete of all vbus failed\n");
+}
+
+/* deletes all vnics or vhbas
+ * returns 0 failure, 1 success,
+ */
+static int delete_all_virt(VIRTPCI_DEV_TYPE devtype, struct del_vbus_guestpart *delparams)
+{
+ int i;
+ unsigned char busid[BUS_ID_SIZE];
+ struct device *vbus;
+
+ GET_BUS_DEV(delparams->busNo);
+
+ if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE)) {
+ LOGERR("**** FAILED to delete all devices; devtype:%d not vhba:%d or vnic:%d\n",
+ devtype, VIRTHBA_TYPE, VIRTNIC_TYPE);
+ return 0;
+ }
+
+ LOGINF("Deleting all %s in vbus %s\n",
+ devtype == VIRTHBA_TYPE ? "vhbas" : "vnics", busid);
+ /* delete all vhbas/vnics */
+ i = virtpci_device_del(vbus, devtype, NULL, NULL);
+ if (i > 0)
+ LOGINF("Deleted %d %s\n", i,
+ devtype == VIRTHBA_TYPE ? "vhbas" : "vnics");
+ return 1;
+}
+
+static int virtpci_ctrlchan_func(struct guest_msgs *msg)
+{
+ switch (msg->msgtype) {
+ case GUEST_ADD_VBUS:
+ return add_vbus(&msg->add_vbus);
+ case GUEST_ADD_VHBA:
+ return add_vhba(&msg->add_vhba);
+ case GUEST_ADD_VNIC:
+ return add_vnic(&msg->add_vnic);
+ case GUEST_DEL_VBUS:
+ return delete_vbus(&msg->del_vbus);
+ case GUEST_DEL_VHBA:
+ return delete_vhba(&msg->del_vhba);
+ case GUEST_DEL_VNIC:
+ return delete_vnic(&msg->del_vhba);
+ case GUEST_DEL_ALL_VHBAS:
+ return delete_all_virt(VIRTHBA_TYPE, &msg->del_all_vhbas);
+ case GUEST_DEL_ALL_VNICS:
+ return delete_all_virt(VIRTNIC_TYPE, &msg->del_all_vnics);
+ case GUEST_DEL_ALL_VBUSES:
+ delete_all();
+ return 1;
+ case GUEST_PAUSE_VHBA:
+ return pause_vhba(&msg->pause_vhba);
+ case GUEST_PAUSE_VNIC:
+ return pause_vnic(&msg->pause_vnic);
+ case GUEST_RESUME_VHBA:
+ return resume_vhba(&msg->resume_vhba);
+ case GUEST_RESUME_VNIC:
+ return resume_vnic(&msg->resume_vnic);
+ default:
+ LOGERR("invalid message type %d.\n", msg->msgtype);
+ return 0;
+ }
+}
+
+/* same as driver_helper in bus.c linux */
+static int match_busid(struct device *dev, void *data)
+{
+ const char *name = data;
+
+ if (strcmp(name, BUS_ID(dev)) == 0)
+ return 1;
+ return 0;
+}
+
+/*****************************************************/
+/* Bus functions */
+/*****************************************************/
+
+static const struct pci_device_id *
+virtpci_match_device(const struct pci_device_id *ids,
+ const struct virtpci_dev *dev)
+{
+ while (ids->vendor || ids->subvendor || ids->class_mask) {
+ DBGINF("ids->vendor:%x dev->vendor:%x ids->device:%x dev->device:%x\n",
+ ids->vendor, dev->vendor, ids->device, dev->device);
+
+ if ((ids->vendor == dev->vendor)
+ && (ids->device == dev->device))
+ return ids;
+
+ ids++;
+ }
+ return NULL;
+}
+
+/* NOTE: !!!!!! This function is called when a new device is added
+* for this bus. Or, it is called for existing devices when a new
+* driver is added for this bus. It returns nonzero if a given device
+* can be handled by the given driver.
+*/
+static int virtpci_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct virtpci_dev *virtpcidev = device_to_virtpci_dev(dev);
+ struct virtpci_driver *virtpcidrv = driver_to_virtpci_driver(drv);
+ int match = 0;
+
+ DBGINF("In virtpci_bus_match dev->bus_id:%s drv->name:%s\n",
+ dev->bus_id, drv->name);
+
+ /* check ids list for a match */
+ if (virtpci_match_device(virtpcidrv->id_table, virtpcidev))
+ match = 1;
+
+ DBGINF("returning match:%d\n", match);
+ return match; /* 0 - no match; 1 - yes it matches */
+}
+
+static int virtpci_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ DBGINF("In virtpci_hotplug\n");
+ /* add variables to the environment prior to the generation of
+ * hotplug events to user space
+ */
+ if (add_uevent_var(env, "VIRTPCI_VERSION=%s", VIRTPCI_VERSION))
+ return -ENOMEM;
+ return 0;
+}
+
+static int virtpci_device_suspend(struct device *dev, pm_message_t state)
+{
+ DBGINF("In virtpci_device_suspend -NYI ****\n");
+ return 0;
+}
+
+static int virtpci_device_resume(struct device *dev)
+{
+ DBGINF("In virtpci_device_resume -NYI ****\n");
+ return 0;
+}
+
+/* For a child device just created on a client bus, fill in
+ * information about the driver that is controlling this device into
+ * the the appropriate slot within the vbus channel of the bus
+ * instance.
+ */
+static void fix_vbus_devInfo(struct device *dev, int devNo, int devType,
+ struct virtpci_driver *virtpcidrv)
+{
+ struct device *vbus;
+ void *pChan;
+ ULTRA_VBUS_DEVICEINFO devInfo;
+ const char *stype;
+
+ if (!dev) {
+ LOGERR("%s dev is NULL", __func__);
+ return;
+ }
+ if (!virtpcidrv) {
+ LOGERR("%s driver is NULL", __func__);
+ return;
+ }
+ vbus = dev->parent;
+ if (!vbus) {
+ LOGERR("%s dev has no parent bus", __func__);
+ return;
+ }
+ pChan = vbus->platform_data;
+ if (!pChan) {
+ LOGERR("%s dev bus has no channel", __func__);
+ return;
+ }
+ switch (devType) {
+ case PCI_DEVICE_ID_VIRTHBA:
+ stype = "vHBA";
+ break;
+ case PCI_DEVICE_ID_VIRTNIC:
+ stype = "vNIC";
+ break;
+ default:
+ stype = "unknown";
+ break;
+ }
+ BusDeviceInfo_Init(&devInfo, stype,
+ virtpcidrv->name,
+ virtpcidrv->version,
+ virtpcidrv->vertag,
+ virtpcidrv->build_date, virtpcidrv->build_time);
+ write_vbus_devInfo(pChan, &devInfo, devNo);
+
+ /* Re-write bus+chipset info, because it is possible that this
+ * was previously written by our good counterpart, visorbus.
+ */
+ write_vbus_chpInfo(pChan, &Chipset_DriverInfo);
+ write_vbus_busInfo(pChan, &Bus_DriverInfo);
+}
+
+/* This function is called to query the existence of a specific device
+* and whether this driver can work with it. It should return -ENODEV
+* in case of failure.
+*/
+static int virtpci_device_probe(struct device *dev)
+{
+ struct virtpci_dev *virtpcidev = device_to_virtpci_dev(dev);
+ struct virtpci_driver *virtpcidrv =
+ driver_to_virtpci_driver(dev->driver);
+ const struct pci_device_id *id;
+ int error = 0;
+
+ LOGINF("In virtpci_device_probe dev:%p virtpcidev:%p virtpcidrv:%p\n",
+ dev, virtpcidev, virtpcidrv); /* VERBOSE/DEBUG ? */
+ POSTCODE_LINUX_2(VPCI_PROBE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+ /* static match and static probe vs dynamic match & dynamic
+ * probe - do we care?.
+ */
+ if (!virtpcidrv->id_table)
+ return -ENODEV;
+
+ id = virtpci_match_device(virtpcidrv->id_table, virtpcidev);
+ if (!id)
+ return -ENODEV;
+
+ /* increment reference count */
+ get_device(dev);
+
+ /* if virtpcidev is not already claimed & probe function is
+ * valid, probe it
+ */
+ if (!virtpcidev->mydriver && virtpcidrv->probe) {
+ /* call the probe function - virthba or virtnic probe
+ * is what it should be
+ */
+ error = virtpcidrv->probe(virtpcidev, id);
+ if (!error) {
+ fix_vbus_devInfo(dev, virtpcidev->deviceNo,
+ virtpcidev->device, virtpcidrv);
+ virtpcidev->mydriver = virtpcidrv;
+ POSTCODE_LINUX_2(VPCI_PROBE_EXIT_PC,
+ POSTCODE_SEVERITY_INFO);
+ } else
+ put_device(dev);
+ }
+ POSTCODE_LINUX_2(VPCI_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
+ return error; /* -ENODEV for probe failure */
+}
+
+static int virtpci_device_remove(struct device *dev_)
+{
+ /* dev_ passed in is the HBA device which we called
+ * generic_dev in our virtpcidev struct
+ */
+ struct virtpci_dev *virtpcidev = device_to_virtpci_dev(dev_);
+ struct virtpci_driver *virtpcidrv = virtpcidev->mydriver;
+ LOGINF("In virtpci_device_remove bus_id:%s dev_:%p virtpcidev:%p dev->driver:%p drivername:%s\n",
+ BUS_ID(dev_), dev_, virtpcidev, dev_->driver,
+ dev_->driver->name); /* VERBOSE/DEBUG */
+ if (virtpcidrv) {
+ /* TEMP: assuming we have only one such driver for now */
+ if (virtpcidrv->remove)
+ virtpcidrv->remove(virtpcidev);
+ virtpcidev->mydriver = NULL;
+ }
+
+ DBGINF("calling putdevice\n");
+ put_device(dev_);
+
+ DBGINF("Leaving\n");
+ return 0;
+}
+
+/*****************************************************/
+/* Bus functions */
+/*****************************************************/
+
+static void virtpci_bus_release(struct device *dev)
+{
+ /* this function is called when the last reference to the
+ * device is removed
+ */
+ DBGINF("In virtpci_bus_release\n");
+ /* what else is supposed to happen here? */
+}
+
+/*****************************************************/
+/* Adapter functions */
+/*****************************************************/
+
+static int virtpci_device_add(struct device *parentbus, int devtype,
+ struct add_virt_guestpart *addparams,
+ struct scsi_adap_info *scsi, /* NULL for VNIC add */
+ struct net_adap_info *net /* NULL for VHBA add */)
+{
+ struct virtpci_dev *virtpcidev = NULL;
+ struct virtpci_dev *tmpvpcidev = NULL, *prev;
+ unsigned long flags;
+ int ret;
+ ULTRA_IO_CHANNEL_PROTOCOL __iomem *pIoChan = NULL;
+ struct device *pDev;
+
+ LOGINF("virtpci_device_add parentbus:%p chanptr:%p\n", parentbus,
+ addparams->chanptr);
+
+ POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+
+ if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE)) {
+ LOGERR("**** FAILED to add device; devtype:%d not vhba:%d or vnic:%d\n",
+ devtype, VIRTHBA_TYPE, VIRTNIC_TYPE);
+ POSTCODE_LINUX_3(VPCI_CREATE_FAILURE_PC, devtype,
+ POSTCODE_SEVERITY_ERR);
+ return 0;
+ }
+
+ /* add a Virtual Device */
+ virtpcidev = kzalloc(sizeof(struct virtpci_dev), GFP_ATOMIC);
+ if (virtpcidev == NULL) {
+ LOGERR("can't add device - malloc FALLED\n");
+ POSTCODE_LINUX_2(MALLOC_FAILURE_PC, POSTCODE_SEVERITY_ERR);
+ return 0;
+ }
+
+ /* initialize stuff unique to virtpci_dev struct */
+ virtpcidev->devtype = devtype;
+ if (devtype == VIRTHBA_TYPE) {
+ virtpcidev->device = PCI_DEVICE_ID_VIRTHBA;
+ virtpcidev->scsi = *scsi;
+ } else {
+ virtpcidev->device = PCI_DEVICE_ID_VIRTNIC;
+ virtpcidev->net = *net;
+ }
+ virtpcidev->vendor = PCI_VENDOR_ID_UNISYS;
+ virtpcidev->busNo = addparams->busNo;
+ virtpcidev->deviceNo = addparams->deviceNo;
+
+ virtpcidev->queueinfo.chan = addparams->chanptr;
+ virtpcidev->queueinfo.send_int_if_needed = NULL;
+
+ /* Set up safe queue... */
+ pIoChan = (ULTRA_IO_CHANNEL_PROTOCOL __iomem *)
+ virtpcidev->queueinfo.chan;
+
+ virtpcidev->intr = addparams->intr;
+
+ /* initialize stuff in the device portion of the struct */
+ virtpcidev->generic_dev.bus = &virtpci_bus_type;
+ virtpcidev->generic_dev.parent = parentbus;
+ virtpcidev->generic_dev.release = virtpci_device_release;
+
+ dev_set_name(&virtpcidev->generic_dev, "%x:%x",
+ addparams->busNo, addparams->deviceNo);
+
+ /* add the vhba/vnic to virtpci device list - but check for
+ * duplicate wwnn/macaddr first
+ */
+ write_lock_irqsave(&VpcidevListLock, flags);
+ for (tmpvpcidev = VpcidevListHead; tmpvpcidev;
+ tmpvpcidev = tmpvpcidev->next) {
+ if (devtype == VIRTHBA_TYPE) {
+ if ((tmpvpcidev->scsi.wwnn.wwnn1 == scsi->wwnn.wwnn1) &&
+ (tmpvpcidev->scsi.wwnn.wwnn2 == scsi->wwnn.wwnn2)) {
+ /* duplicate - already have vpcidev
+ with this wwnn */
+ break;
+ }
+ } else
+ if (memcmp
+ (tmpvpcidev->net.mac_addr, net->mac_addr,
+ MAX_MACADDR_LEN) == 0) {
+ /* duplicate - already have vnic with this wwnn */
+ break;
+ }
+ }
+ if (tmpvpcidev) {
+ /* found a vhba/vnic already in the list with same
+ * wwnn or macaddr - reject add
+ */
+ write_unlock_irqrestore(&VpcidevListLock, flags);
+ kfree(virtpcidev);
+ LOGERR("**** FAILED vhba/vnic already exists in the list\n");
+ POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
+ return 0;
+ }
+
+ /* add it at the head */
+ if (!VpcidevListHead)
+ VpcidevListHead = virtpcidev;
+ else {
+ /* insert virtpcidev at the head of our linked list of
+ * vpcidevs
+ */
+ virtpcidev->next = VpcidevListHead;
+ VpcidevListHead = virtpcidev;
+ }
+
+ write_unlock_irqrestore(&VpcidevListLock, flags);
+
+ /* Must transition channel to ATTACHED state BEFORE
+ * registering the device, because polling of the channel
+ * queues can begin at any time after device_register().
+ */
+ pDev = &virtpcidev->generic_dev;
+ ULTRA_CHANNEL_CLIENT_TRANSITION(addparams->chanptr,
+ BUS_ID(pDev),
+ CHANNELCLI_ATTACHED, NULL);
+
+ /* don't register until device has been added to
+ * list. Otherwise, a device_unregister from this function can
+ * cause a "scheduling while atomic".
+ */
+ DBGINF("registering device:%p with bus_id:%s\n",
+ &virtpcidev->generic_dev, virtpcidev->generic_dev.bus_id);
+ ret = device_register(&virtpcidev->generic_dev);
+ /* NOTE: THIS IS CALLING HOTPLUG virtpci_hotplug!!!
+ * This call to device_register results in virtpci_bus_match
+ * being called !!!!! And, if match returns success, then
+ * virtpcidev->generic_dev.driver is setup to core_driver,
+ * i.e., virtpci and the probe function
+ * virtpcidev->generic_dev.driver->probe is called which
+ * results in virtpci_device_probe being called. And if
+ * virtpci_device_probe is successful
+ */
+ if (ret) {
+ LOGERR("device_register returned %d\n", ret);
+ pDev = &virtpcidev->generic_dev;
+ ULTRA_CHANNEL_CLIENT_TRANSITION(addparams->chanptr,
+ BUS_ID(pDev),
+ CHANNELCLI_DETACHED, NULL);
+ /* remove virtpcidev, the one we just added, from the list */
+ write_lock_irqsave(&VpcidevListLock, flags);
+ for (tmpvpcidev = VpcidevListHead, prev = NULL;
+ tmpvpcidev;
+ prev = tmpvpcidev, tmpvpcidev = tmpvpcidev->next) {
+ if (tmpvpcidev == virtpcidev) {
+ if (prev)
+ prev->next = tmpvpcidev->next;
+ else
+ VpcidevListHead = tmpvpcidev->next;
+ break;
+ }
+ }
+ write_unlock_irqrestore(&VpcidevListLock, flags);
+ kfree(virtpcidev);
+ return 0;
+ }
+
+ LOGINF("Added %s:%d:%d &virtpcidev->generic_dev:%p\n",
+ (devtype == VIRTHBA_TYPE) ? "virthba" : "virtnic",
+ addparams->busNo, addparams->deviceNo, &virtpcidev->generic_dev);
+ POSTCODE_LINUX_2(VPCI_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
+ return 1;
+}
+
+static int virtpci_device_serverdown(struct device *parentbus,
+ int devtype,
+ struct vhba_wwnn *wwnn,
+ unsigned char macaddr[])
+{
+ int pausethisone = 0;
+ bool found = false;
+ struct virtpci_dev *tmpvpcidev, *prevvpcidev;
+ struct virtpci_driver *vpcidriver;
+ unsigned long flags;
+ int rc = 0;
+
+ if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE)) {
+ LOGERR("**** FAILED to pause device; devtype:%d not vhba:%d or vnic:%d\n",
+ devtype, VIRTHBA_TYPE, VIRTNIC_TYPE);
+ return 0;
+ }
+
+ /* find the vhba or vnic in virtpci device list */
+ write_lock_irqsave(&VpcidevListLock, flags);
+
+ for (tmpvpcidev = VpcidevListHead, prevvpcidev = NULL;
+ (tmpvpcidev && !found);
+ prevvpcidev = tmpvpcidev, tmpvpcidev = tmpvpcidev->next) {
+ if (tmpvpcidev->devtype != devtype)
+ continue;
+
+ if (devtype == VIRTHBA_TYPE) {
+ pausethisone =
+ ((tmpvpcidev->scsi.wwnn.wwnn1 == wwnn->wwnn1) &&
+ (tmpvpcidev->scsi.wwnn.wwnn2 == wwnn->wwnn2));
+ /* devtype is vhba, we're pausing vhba whose
+ * wwnn matches the current device's wwnn
+ */
+ } else { /* VIRTNIC_TYPE */
+ pausethisone =
+ memcmp(tmpvpcidev->net.mac_addr, macaddr,
+ MAX_MACADDR_LEN) == 0;
+ /* devtype is vnic, we're pausing vnic whose
+ * macaddr matches the current device's macaddr */
+ }
+
+ if (!pausethisone)
+ continue;
+
+ found = true;
+ vpcidriver = tmpvpcidev->mydriver;
+ rc = vpcidriver->suspend(tmpvpcidev, 0);
+ }
+ write_unlock_irqrestore(&VpcidevListLock, flags);
+
+ if (!found) {
+ LOGERR("**** FAILED to find vhba/vnic in the list\n");
+ return 0;
+ }
+
+ return rc;
+}
+
+static int virtpci_device_serverup(struct device *parentbus,
+ int devtype,
+ struct vhba_wwnn *wwnn,
+ unsigned char macaddr[])
+{
+ int resumethisone = 0;
+ bool found = false;
+ struct virtpci_dev *tmpvpcidev, *prevvpcidev;
+ struct virtpci_driver *vpcidriver;
+ unsigned long flags;
+ int rc = 0;
+
+ if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE)) {
+ LOGERR("**** FAILED to resume device; devtype:%d not vhba:%d or vnic:%d\n",
+ devtype, VIRTHBA_TYPE, VIRTNIC_TYPE);
+ return 0;
+ }
+
+ /* find the vhba or vnic in virtpci device list */
+ write_lock_irqsave(&VpcidevListLock, flags);
+
+ for (tmpvpcidev = VpcidevListHead, prevvpcidev = NULL;
+ (tmpvpcidev && !found);
+ prevvpcidev = tmpvpcidev, tmpvpcidev = tmpvpcidev->next) {
+ if (tmpvpcidev->devtype != devtype)
+ continue;
+
+ if (devtype == VIRTHBA_TYPE) {
+ resumethisone =
+ ((tmpvpcidev->scsi.wwnn.wwnn1 == wwnn->wwnn1) &&
+ (tmpvpcidev->scsi.wwnn.wwnn2 == wwnn->wwnn2));
+ /* devtype is vhba, we're resuming vhba whose
+ * wwnn matches the current device's wwnn */
+ } else { /* VIRTNIC_TYPE */
+ resumethisone =
+ memcmp(tmpvpcidev->net.mac_addr, macaddr,
+ MAX_MACADDR_LEN) == 0;
+ /* devtype is vnic, we're resuming vnic whose
+ * macaddr matches the current device's macaddr */
+ }
+
+ if (!resumethisone)
+ continue;
+
+ found = true;
+ vpcidriver = tmpvpcidev->mydriver;
+ /* This should be done at BUS resume time, but an
+ * existing problem prevents us from ever getting a bus
+ * resume... This hack would fail to work should we
+ * ever have a bus that contains NO devices, since we
+ * would never even get here in that case.
+ */
+ fix_vbus_devInfo(&tmpvpcidev->generic_dev, tmpvpcidev->deviceNo,
+ tmpvpcidev->device, vpcidriver);
+ rc = vpcidriver->resume(tmpvpcidev);
+ }
+
+ write_unlock_irqrestore(&VpcidevListLock, flags);
+
+ if (!found) {
+ LOGERR("**** FAILED to find vhba/vnic in the list\n");
+ return 0;
+ }
+
+ return rc;
+}
+
+static int virtpci_device_del(struct device *parentbus,
+ int devtype, struct vhba_wwnn *wwnn,
+ unsigned char macaddr[])
+{
+ int count = 0, all = 0, delthisone;
+ struct virtpci_dev *tmpvpcidev, *prevvpcidev, *dellist = NULL;
+ unsigned long flags;
+
+#define DEL_CONTINUE { \
+ prevvpcidev = tmpvpcidev;\
+ tmpvpcidev = tmpvpcidev->next;\
+ continue; \
+}
+
+ if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE)) {
+ LOGERR("**** FAILED to delete device; devtype:%d not vhba:%d or vnic:%d\n",
+ devtype, VIRTHBA_TYPE, VIRTNIC_TYPE);
+ return 0;
+ }
+
+ /* see if we are to delete all - NOTE: all implies we have a
+ * valid parentbus
+ */
+ all = ((devtype == VIRTHBA_TYPE) && (wwnn == NULL)) ||
+ ((devtype == VIRTNIC_TYPE) && (macaddr == NULL));
+
+ /* find all the vhba or vnic or both in virtpci device list
+ * keep list of ones we are deleting so we can call
+ * device_unregister after we release the lock; otherwise we
+ * encounter "schedule while atomic"
+ */
+ write_lock_irqsave(&VpcidevListLock, flags);
+ for (tmpvpcidev = VpcidevListHead, prevvpcidev = NULL; tmpvpcidev;) {
+ if (tmpvpcidev->devtype != devtype)
+ DEL_CONTINUE;
+
+ if (all) {
+ delthisone =
+ (tmpvpcidev->generic_dev.parent == parentbus);
+ /* we're deleting all vhbas or vnics on the
+ * specified parent bus
+ */
+ } else if (devtype == VIRTHBA_TYPE) {
+ delthisone =
+ ((tmpvpcidev->scsi.wwnn.wwnn1 == wwnn->wwnn1) &&
+ (tmpvpcidev->scsi.wwnn.wwnn2 == wwnn->wwnn2));
+ /* devtype is vhba, we're deleting vhba whose
+ * wwnn matches the current device's wwnn
+ */
+ } else { /* VIRTNIC_TYPE */
+ delthisone =
+ memcmp(tmpvpcidev->net.mac_addr, macaddr,
+ MAX_MACADDR_LEN) == 0;
+ /* devtype is vnic, we're deleting vnic whose
+ * macaddr matches the current device's macaddr
+ */
+ }
+
+ if (!delthisone)
+ DEL_CONTINUE;
+
+ /* take vhba/vnic out of the list */
+ if (prevvpcidev)
+ /* not at head */
+ prevvpcidev->next = tmpvpcidev->next;
+ else
+ VpcidevListHead = tmpvpcidev->next;
+
+ /* add it to our deletelist */
+ tmpvpcidev->next = dellist;
+ dellist = tmpvpcidev;
+
+ count++;
+ if (!all)
+ break; /* done */
+ /* going to top of loop again - set tmpvpcidev to next
+ * one we're to process
+ */
+ if (prevvpcidev)
+ tmpvpcidev = prevvpcidev->next;
+ else
+ tmpvpcidev = VpcidevListHead;
+ }
+ write_unlock_irqrestore(&VpcidevListLock, flags);
+
+ if (!all && (count == 0)) {
+ LOGERR("**** FAILED to find vhba/vnic in the list\n");
+ return 0;
+ }
+
+ /* now delete each one from delete list */
+ while (dellist) {
+ /* save next */
+ tmpvpcidev = dellist->next;
+ /* delete the vhba/vnic at dellist */
+ DELETE_ONE_VPCIDEV(dellist);
+ /* do next */
+ dellist = tmpvpcidev;
+ }
+
+ return count;
+}
+
+static void virtpci_device_release(struct device *dev_)
+{
+ /* this function is called when the last reference to the
+ * device is removed
+ */
+ LOGINF("In virtpci_device_release:%p - NOT YET IMPLEMENTED\n", dev_);
+}
+
+/*****************************************************/
+/* Driver functions */
+/*****************************************************/
+
+#define kobj_to_device_driver(obj) container_of(obj, struct device_driver, kobj)
+#define attribute_to_driver_attribute(obj) \
+ container_of(obj, struct driver_attribute, attr)
+
+static ssize_t virtpci_driver_attr_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buf)
+{
+ struct driver_attribute *dattr = attribute_to_driver_attribute(attr);
+ ssize_t ret = 0;
+
+ struct driver_private *dprivate = to_driver(kobj);
+ struct device_driver *driver;
+ if (dprivate != NULL)
+ driver = dprivate->driver;
+ else
+ driver = NULL;
+
+ DBGINF("In virtpci_driver_attr_show driver->name:%s\n", driver->name);
+ if (driver) {
+ if (dattr->show)
+ ret = dattr->show(driver, buf);
+ }
+ return ret;
+}
+
+static ssize_t virtpci_driver_attr_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct driver_attribute *dattr = attribute_to_driver_attribute(attr);
+ ssize_t ret = 0;
+
+ struct driver_private *dprivate = to_driver(kobj);
+ struct device_driver *driver;
+ if (dprivate != NULL)
+ driver = dprivate->driver;
+ else
+ driver = NULL;
+
+ DBGINF("In virtpci_driver_attr_store driver->name:%s\n", driver->name);
+
+ if (driver) {
+ if (dattr->store)
+ ret = dattr->store(driver, buf, count);
+ }
+ return ret;
+}
+
+/* register a new virtpci driver */
+int virtpci_register_driver(struct virtpci_driver *drv)
+{
+ int result = 0;
+
+ DBGINF("In virtpci_register_driver\n");
+
+ if (drv->id_table == NULL) {
+ LOGERR("id_table missing\n");
+ return 1;
+ }
+ /* initialize core driver fields needed to call driver_register */
+ drv->core_driver.name = drv->name; /* name of driver in sysfs */
+ drv->core_driver.bus = &virtpci_bus_type; /* type of bus this
+ * driver works with */
+ drv->core_driver.probe = virtpci_device_probe; /* called to query the
+ * existence of a
+ * specific device and
+ * whether this driver
+ *can work with it */
+ drv->core_driver.remove = virtpci_device_remove; /* called when the
+ * device is removed
+ * from the system */
+ /* register with core */
+ result = driver_register(&drv->core_driver);
+ /* calls bus_add_driver which calls driver_attach and
+ * module_add_driver
+ */
+ if (result)
+ return result; /* failed */
+
+ drv->core_driver.p->kobj.ktype = &virtpci_driver_kobj_type;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(virtpci_register_driver);
+
+void virtpci_unregister_driver(struct virtpci_driver *drv)
+{
+ DBGINF("In virtpci_unregister_driver drv:%p\n", drv);
+ driver_unregister(&drv->core_driver);
+ /* driver_unregister calls bus_remove_driver
+ * bus_remove_driver calls device_detach
+ * device_detach calls device_release_driver for each of the
+ * driver's devices
+ * device_release driver calls drv->remove which is
+ * virtpci_device_remove
+ * virtpci_device_remove calls virthba_remove
+ */
+ DBGINF("Leaving\n");
+}
+EXPORT_SYMBOL_GPL(virtpci_unregister_driver);
+
+/*****************************************************/
+/* proc filesystem functions */
+/*****************************************************/
+struct print_vbus_info {
+ int *length;
+ char *buf;
+};
+
+static int print_vbus(struct device *vbus, void *data)
+{
+ struct print_vbus_info *p = (struct print_vbus_info *) data;
+ int l = *(p->length);
+
+ *(p->length) = l + sprintf(p->buf + l, "bus_id:%s\n", dev_name(vbus));
+ return 0; /* no error */
+}
+
+static ssize_t info_proc_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ int length = 0;
+ struct virtpci_dev *tmpvpcidev;
+ unsigned long flags;
+ struct print_vbus_info printparam;
+ char *vbuf;
+ loff_t pos = *offset;
+
+ if (pos < 0)
+ return -EINVAL;
+
+ if (pos > 0 || !len)
+ return 0;
+
+ vbuf = kzalloc(len, GFP_KERNEL);
+ if (!vbuf)
+ return -ENOMEM;
+
+ length += sprintf(vbuf + length, "CHANSOCK is not defined.\n");
+
+ length += sprintf(vbuf + length, "\n Virtual PCI Bus devices\n");
+ printparam.length = &length;
+ printparam.buf = vbuf;
+ if (bus_for_each_dev(&virtpci_bus_type, NULL,
+ (void *) &printparam, print_vbus))
+ LOGERR("delete of all vbus failed\n");
+
+ length += sprintf(vbuf + length, "\n Virtual PCI devices\n");
+ read_lock_irqsave(&VpcidevListLock, flags);
+ tmpvpcidev = VpcidevListHead;
+ while (tmpvpcidev) {
+ if (tmpvpcidev->devtype == VIRTHBA_TYPE) {
+ length += sprintf(vbuf + length, "[%d:%d] VHba:%08x:%08x max-config:%d-%d-%d-%d",
+ tmpvpcidev->busNo, tmpvpcidev->deviceNo,
+ tmpvpcidev->scsi.wwnn.wwnn1,
+ tmpvpcidev->scsi.wwnn.wwnn2,
+ tmpvpcidev->scsi.max.max_channel,
+ tmpvpcidev->scsi.max.max_id,
+ tmpvpcidev->scsi.max.max_lun,
+ tmpvpcidev->scsi.max.cmd_per_lun);
+ } else {
+ length += sprintf(vbuf + length, "[%d:%d] VNic:%02x:%02x:%02x:%02x:%02x:%02x num_rcv_bufs:%d mtu:%d",
+ tmpvpcidev->busNo, tmpvpcidev->deviceNo,
+ tmpvpcidev->net.mac_addr[0],
+ tmpvpcidev->net.mac_addr[1],
+ tmpvpcidev->net.mac_addr[2],
+ tmpvpcidev->net.mac_addr[3],
+ tmpvpcidev->net.mac_addr[4],
+ tmpvpcidev->net.mac_addr[5],
+ tmpvpcidev->net.num_rcv_bufs,
+ tmpvpcidev->net.mtu);
+ }
+ length +=
+ sprintf(vbuf + length, " chanptr:%p\n",
+ tmpvpcidev->queueinfo.chan);
+ tmpvpcidev = tmpvpcidev->next;
+ }
+ read_unlock_irqrestore(&VpcidevListLock, flags);
+
+ length +=
+ sprintf(vbuf + length, "\nModule build: Date:%s Time:%s\n", __DATE__,
+ __TIME__);
+
+ length += sprintf(vbuf + length, "\n");
+ if (copy_to_user(buf, vbuf, length)) {
+ kfree(vbuf);
+ return -EFAULT;
+ }
+
+ kfree(vbuf);
+ *offset += length;
+ return length;
+}
+
+static ssize_t virt_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char buf[16];
+ int type, i, action = 0xffff;
+ unsigned int busno, deviceno;
+ void __iomem *chanptr;
+ struct add_vbus_guestpart busaddparams;
+ struct add_virt_guestpart addparams;
+ struct del_vbus_guestpart busdelparams;
+ struct del_virt_guestpart delparams;
+ GUID dummyGuid = GUID0;
+#ifdef STORAGE_CHANNEL
+ U64 storagechannel;
+#endif
+
+#define PRINT_USAGE_RETURN {\
+ LOGERR("usage: 0-0-<chanptr> ==> delete vhba\n"); \
+ LOGERR("usage: 0-1-<chanptr>-<busNo>-<deviceNo> ==> add vhba\n"); \
+ LOGERR("usage: 0-f-<busNo> ==> delete all vhbas\n"); \
+ LOGERR("\n"); \
+ LOGERR("usage: 1-0-<chanptr> ==> delete vnic\n"); \
+ LOGERR("usage: 1-1-<chanptr>-<busNo>-<deviceNo> ==> add vnic\n"); \
+ LOGERR("usage: 1-f-<busNo> ==> delete all vnics\n"); \
+ LOGERR("\n"); \
+ LOGERR("usage: 6-0-<busNo> ==> delete vbus\n"); \
+ LOGERR("usage: 6-1-<busNo> ==> add vbus\n"); \
+ LOGERR("usage: 6-f ==> delete all vbuses\n"); \
+ LOGERR("usage: 98-<busNo>-<deviceNo> ==> INJECT Client delete vnic\n"); \
+ LOGERR("usage: 99-<chanptr>-<busNo>-<deviceNo> ==> INJECT Client add vnic\n"); \
+ return -EINVAL; \
+}
+
+ if (count >= ARRAY_SIZE(buf))
+ return -EINVAL;
+
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("copy_from_user failed.\n");
+ return -EFAULT;
+ }
+
+ i = sscanf(buf, "%x-%x", &type, &action);
+ if (i < 2)
+ PRINT_USAGE_RETURN;
+
+ if (type == 0x98) {
+ /* client inject delete vnic */
+ i = sscanf(buf, "%x-%d-%d", &type, &busno, &deviceno);
+ if (i != 3)
+ PRINT_USAGE_RETURN;
+ uislib_client_inject_del_vnic(busno, deviceno);
+ return count; /* success */
+ } else if (type == 0x99) {
+ /* client inject add vnic */
+ i = sscanf(buf, "%x-%p-%d-%d", &type, &chanptr, &busno,
+ &deviceno);
+ if (i != 4)
+ PRINT_USAGE_RETURN;
+ if (!uislib_client_inject_add_vnic(busno, deviceno,
+ __pa(chanptr),
+ MIN_IO_CHANNEL_SIZE,
+ 1, /* test msg */
+ dummyGuid, /* inst guid */
+ NULL)) { /*interrupt info */
+ LOGERR("FAILED to inject add vnic\n");
+ return -EFAULT;
+ }
+ return count; /* success */
+ }
+
+ if ((type != VIRTHBA_TYPE) && (type != VIRTNIC_TYPE)
+ && (type != VIRTBUS_TYPE))
+ PRINT_USAGE_RETURN;
+
+ if (type == VIRTBUS_TYPE) {
+ i = sscanf(buf, "%x-%x-%d", &type, &action, &busno);
+ switch (action) {
+ case 0:
+ /* delete vbus */
+ if (i != 3)
+ break;
+ busdelparams.busNo = busno;
+ if (delete_vbus(&busdelparams))
+ return count; /* success */
+ return -EFAULT;
+
+ case 1:
+ /* add vbus */
+ if (i != 3)
+ break;
+ busaddparams.chanptr = NULL; /* NOT YET USED */
+ busaddparams.busNo = busno;
+ if (add_vbus(&busaddparams))
+ return count; /* success */
+ return -EFAULT;
+
+ case 0xf:
+ /* delete all vbuses and all vhbas/vnics on the buses */
+ if (i != 2)
+ break;
+ delete_all();
+ return count; /* success */
+ default:
+ break;
+ }
+ PRINT_USAGE_RETURN;
+ }
+
+ /* if (type == VIRTNIC_TYPE) or if (type == VIRTHBA_TYPE) */
+ switch (action) {
+ case 0:
+ /* delete vhba/vnic */
+ i = sscanf(buf, "%x-%x-%p", &type, &action, &chanptr);
+ if (i != 3)
+ break;
+ delparams.chanptr = chanptr;
+ if (type == VIRTHBA_TYPE) {
+ if (delete_vhba(&delparams))
+ return count; /* success */
+ } else {
+ if (delete_vnic(&delparams))
+ return count; /* success */
+ }
+ return -EFAULT;
+
+ case 1:
+ /* add vhba/vnic */
+ i = sscanf(buf, "%x-%x-%p-%d-%d", &type, &action, &chanptr,
+ &busno, &deviceno);
+ if (i != 5)
+ break;
+ addparams.chanptr = chanptr;
+ addparams.busNo = busno;
+ addparams.deviceNo = deviceno;
+ if (type == VIRTHBA_TYPE) {
+ if (add_vhba(&addparams))
+ return count; /* success */
+ } else {
+ if (add_vnic(&addparams))
+ return count; /* success */
+ }
+ return -EFAULT;
+
+#ifdef STORAGE_CHANNEL
+ case 2:
+ /* add vhba */
+ i = sscanf(buf, "%x-%x-%d-%d", &type, &action, &busno,
+ &deviceno);
+ if (i != 4)
+ break;
+ storagechannel = uislib_storage_channel(0); /* Get my storage channel */
+ /* ioremap_cache it now */
+ addparams.chanptr =
+ (void *) ioremap_cache(storagechannel, IO_CHANNEL_SIZE);
+ if (addparams.chanptr == NULL) {
+ LOGERR("Failure to get remap storage channel.\n");
+ return -EFAULT;
+ }
+ addparams.busNo = busno;
+ addparams.deviceNo = deviceno;
+ if (type == VIRTHBA_TYPE) {
+ if (add_vhba(&addparams))
+ return count; /* success */
+ }
+ return -EFAULT;
+#endif
+ case 0xf:
+ /* delete all vhbas/vnics */
+ i = sscanf(buf, "%x-%x-%d", &type, &action, &busno);
+ if (i != 3)
+ break;
+ busdelparams.busNo = busno;
+ delete_all_virt(type, &busdelparams);
+ return count; /* success */
+ default:
+ break;
+ }
+ PRINT_USAGE_RETURN;
+}
+
+/*****************************************************/
+/* Module Init & Exit functions */
+/*****************************************************/
+
+static int __init virtpci_mod_init(void)
+{
+ int ret;
+
+
+ LOGINF("Module build: Date:%s Time:%s...\n", __DATE__, __TIME__);
+
+ POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+
+ ret = bus_register(&virtpci_bus_type);
+ /* creates /sys/bus/uisvirtpci which contains devices &
+ * drivers directory
+ */
+ if (ret) {
+ LOGERR("bus_register ****FAILED:%d\n", ret);
+ POSTCODE_LINUX_3(VPCI_CREATE_FAILURE_PC, ret,
+ POSTCODE_SEVERITY_ERR);
+ return ret;
+ }
+ DBGINF("bus_register successful\n");
+ BusDeviceInfo_Init(&Bus_DriverInfo,
+ "clientbus", "virtpci",
+ VERSION, NULL, __DATE__, __TIME__);
+
+ /* create a root bus used to parent all the virtpci buses. */
+ ret = device_register(&virtpci_rootbus_device);
+ if (ret) {
+ LOGERR("device_register FAILED:%d\n", ret);
+ bus_unregister(&virtpci_bus_type);
+ POSTCODE_LINUX_3(VPCI_CREATE_FAILURE_PC, ret,
+ POSTCODE_SEVERITY_ERR);
+ return ret;
+ }
+ DBGINF("device_register successful ret:%x\n", ret);
+
+ if (!uisctrl_register_req_handler(2, (void *) &virtpci_ctrlchan_func,
+ &Chipset_DriverInfo)) {
+ LOGERR("uisctrl_register_req_handler ****FAILED.\n");
+ POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
+ device_unregister(&virtpci_rootbus_device);
+ bus_unregister(&virtpci_bus_type);
+ return -1;
+ }
+
+ LOGINF("successfully registered virtpci_ctrlchan_func (0x%p) as callback.\n",
+ (void *) &virtpci_ctrlchan_func);
+ /* create the proc directories */
+ virtpci_proc_dir = proc_mkdir(DIR_PROC_ENTRY, NULL);
+ virt_proc_entry = proc_create(VIRT_PROC_ENTRY_FN, 0, virtpci_proc_dir,
+ &proc_virt_fops);
+ info_proc_entry = proc_create(INFO_PROC_ENTRY_FN, 0, virtpci_proc_dir,
+ &proc_info_fops);
+ LOGINF("Leaving\n");
+ POSTCODE_LINUX_2(VPCI_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
+ return 0;
+}
+
+static void __exit virtpci_mod_exit(void)
+{
+ LOGINF("virtpci_mod_exit...\n");
+
+ /* unregister the callback function */
+ if (!uisctrl_register_req_handler(2, NULL, NULL))
+ LOGERR("uisctrl_register_req_handler ****FAILED.\n");
+
+ device_unregister(&virtpci_rootbus_device);
+ bus_unregister(&virtpci_bus_type);
+
+ if (virt_proc_entry)
+ remove_proc_entry(VIRT_PROC_ENTRY_FN, virtpci_proc_dir);
+
+ if (info_proc_entry)
+ remove_proc_entry(INFO_PROC_ENTRY_FN, virtpci_proc_dir);
+
+ if (virtpci_proc_dir)
+ remove_proc_entry(DIR_PROC_ENTRY, NULL);
+
+ LOGINF("Leaving\n");
+
+}
+
+module_init(virtpci_mod_init);
+module_exit(virtpci_mod_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Usha Srinivasan");
+MODULE_ALIAS("uisvirtpci");
+
diff --git a/drivers/staging/unisys/virtpci/virtpci.h b/drivers/staging/unisys/virtpci/virtpci.h
new file mode 100644
index 000000000000..b8fd07bc5435
--- /dev/null
+++ b/drivers/staging/unisys/virtpci/virtpci.h
@@ -0,0 +1,104 @@
+/* virtpci.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * Unisys Virtual PCI driver header
+ */
+
+#ifndef __VIRTPCI_H__
+#define __VIRTPCI_H__
+
+#include "uisqueue.h"
+#include <linux/version.h>
+
+#define PCI_DEVICE_ID_VIRTHBA 0xAA00
+#define PCI_DEVICE_ID_VIRTNIC 0xAB00
+
+struct scsi_adap_info {
+ void *scsihost; /* scsi host if this device is a scsi hba */
+ struct vhba_wwnn wwnn; /* the world wide node name of vhba */
+ struct vhba_config_max max; /* various max specifications used
+ * to config vhba */
+};
+
+struct net_adap_info {
+ struct net_device *netdev; /* network device if this
+ * device is a NIC */
+ u8 mac_addr[MAX_MACADDR_LEN];
+ int num_rcv_bufs;
+ unsigned mtu;
+ GUID zoneGuid;
+};
+
+typedef enum {
+ VIRTHBA_TYPE = 0,
+ VIRTNIC_TYPE = 1,
+ VIRTBUS_TYPE = 6,
+} VIRTPCI_DEV_TYPE;
+
+struct virtpci_dev {
+ VIRTPCI_DEV_TYPE devtype; /* indicates type of the
+ * virtual pci device */
+ struct virtpci_driver *mydriver; /* which driver has allocated
+ * this device */
+ unsigned short vendor; /* vendor id for device */
+ unsigned short device; /* device id for device */
+ U32 busNo; /* number of bus on which device exists */
+ U32 deviceNo; /* device's number on the bus */
+ struct InterruptInfo intr; /* interrupt info */
+ struct device generic_dev; /* generic device */
+ union {
+ struct scsi_adap_info scsi;
+ struct net_adap_info net;
+ };
+
+ struct uisqueue_info queueinfo; /* holds ptr to channel where cmds &
+ * rsps are queued & retrieved */
+ struct virtpci_dev *next; /* points to next virtpci device */
+};
+
+struct virtpci_driver {
+ struct list_head node;
+ const char *name; /* the name of the driver in sysfs */
+ const char *version;
+ const char *vertag;
+ const char *build_date;
+ const char *build_time;
+ const struct pci_device_id *id_table; /* must be non-NULL for probe
+ * to be called */
+ int (*probe)(struct virtpci_dev *dev,
+ const struct pci_device_id *id); /* device inserted */
+ void (*remove)(struct virtpci_dev *dev); /* Device removed (NULL if
+ * not a hot-plug capable
+ * driver) */
+ int (*suspend)(struct virtpci_dev *dev,
+ u32 state); /* Device suspended */
+ int (*resume)(struct virtpci_dev *dev); /* Device woken up */
+ int (*enable_wake)(struct virtpci_dev *dev,
+ u32 state, int enable); /* Enable wake event */
+ struct device_driver core_driver; /* VIRTPCI core fills this in */
+};
+
+#define driver_to_virtpci_driver(in_drv) \
+ container_of(in_drv, struct virtpci_driver, core_driver)
+#define device_to_virtpci_dev(in_dev) \
+ container_of(in_dev, struct virtpci_dev, generic_dev)
+
+int virtpci_register_driver(struct virtpci_driver *);
+void virtpci_unregister_driver(struct virtpci_driver *);
+
+#endif /* __VIRTPCI_H__ */
diff --git a/drivers/staging/unisys/visorchannel/Kconfig b/drivers/staging/unisys/visorchannel/Kconfig
new file mode 100644
index 000000000000..41c3b4b997eb
--- /dev/null
+++ b/drivers/staging/unisys/visorchannel/Kconfig
@@ -0,0 +1,10 @@
+#
+# Unisys visorchannel configuration
+#
+
+config UNISYS_VISORCHANNEL
+ tristate "Unisys visorchannel driver"
+ depends on UNISYSSPAR && UNISYS_VISORUTIL
+ ---help---
+ If you say Y here, you will enable the Unisys visorchannel driver.
+
diff --git a/drivers/staging/unisys/visorchannel/Makefile b/drivers/staging/unisys/visorchannel/Makefile
new file mode 100644
index 000000000000..f0060be55bc5
--- /dev/null
+++ b/drivers/staging/unisys/visorchannel/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for Unisys visorchannel
+#
+
+obj-$(CONFIG_UNISYS_VISORCHANNEL) += visorchannel.o
+
+visorchannel-y := visorchannel_main.o visorchannel_funcs.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+ccflags-y += -Idrivers/staging/unisys/common-spar/include
+ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
+ccflags-y += -Idrivers/staging/unisys/visorutil
+ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION
+
diff --git a/drivers/staging/unisys/visorchannel/globals.h b/drivers/staging/unisys/visorchannel/globals.h
new file mode 100644
index 000000000000..668f832ca566
--- /dev/null
+++ b/drivers/staging/unisys/visorchannel/globals.h
@@ -0,0 +1,29 @@
+/* globals.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __VISORCHANNEL_GLOBALS_H__
+#define __VISORCHANNEL_GLOBALS_H__
+
+#include "uniklog.h"
+#include "timskmod.h"
+#include "memregion.h"
+#include "version.h"
+
+#define MYDRVNAME "visorchannel"
+
+
+#endif
diff --git a/drivers/staging/unisys/visorchannel/visorchannel.h b/drivers/staging/unisys/visorchannel/visorchannel.h
new file mode 100644
index 000000000000..62d29a233fd0
--- /dev/null
+++ b/drivers/staging/unisys/visorchannel/visorchannel.h
@@ -0,0 +1,106 @@
+/* visorchannel.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __VISORCHANNEL_H__
+#define __VISORCHANNEL_H__
+
+#include "commontypes.h"
+#include "memregion.h"
+#include "channel.h"
+#ifndef HOSTADDRESS
+#define HOSTADDRESS U64
+#endif
+#ifndef BOOL
+#define BOOL int
+#endif
+
+/* VISORCHANNEL is an opaque structure to users.
+ * Fields are declared only in the implementation .c files.
+ */
+typedef struct VISORCHANNEL_Tag VISORCHANNEL;
+
+/* Note that for visorchannel_create() and visorchannel_create_overlapped(),
+ * <channelBytes> and <guid> arguments may be 0 if we are a channel CLIENT.
+ * In this case, the values can simply be read from the channel header.
+ */
+VISORCHANNEL *visorchannel_create(HOSTADDRESS physaddr,
+ ulong channelBytes, GUID guid);
+VISORCHANNEL *visorchannel_create_overlapped(ulong channelBytes,
+ VISORCHANNEL *parent, ulong off,
+ GUID guid);
+VISORCHANNEL *visorchannel_create_with_lock(HOSTADDRESS physaddr,
+ ulong channelBytes, GUID guid);
+VISORCHANNEL *visorchannel_create_overlapped_with_lock(ulong channelBytes,
+ VISORCHANNEL *parent,
+ ulong off, GUID guid);
+void visorchannel_destroy(VISORCHANNEL *channel);
+int visorchannel_read(VISORCHANNEL *channel, ulong offset,
+ void *local, ulong nbytes);
+int visorchannel_write(VISORCHANNEL *channel, ulong offset,
+ void *local, ulong nbytes);
+int visorchannel_clear(VISORCHANNEL *channel, ulong offset,
+ U8 ch, ulong nbytes);
+BOOL visorchannel_signalremove(VISORCHANNEL *channel, U32 queue, void *msg);
+BOOL visorchannel_signalinsert(VISORCHANNEL *channel, U32 queue, void *msg);
+int visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, U32 queue);
+int visorchannel_signalqueue_max_slots(VISORCHANNEL *channel, U32 queue);
+
+HOSTADDRESS visorchannel_get_physaddr(VISORCHANNEL *channel);
+ulong visorchannel_get_nbytes(VISORCHANNEL *channel);
+char *visorchannel_id(VISORCHANNEL *channel, char *s);
+char *visorchannel_zoneid(VISORCHANNEL *channel, char *s);
+U64 visorchannel_get_clientpartition(VISORCHANNEL *channel);
+GUID visorchannel_get_GUID(VISORCHANNEL *channel);
+MEMREGION *visorchannel_get_memregion(VISORCHANNEL *channel);
+char *visorchannel_GUID_id(GUID *guid, char *s);
+void visorchannel_debug(VISORCHANNEL *channel, int nQueues,
+ struct seq_file *seq, U32 off);
+void visorchannel_dump_section(VISORCHANNEL *chan, char *s,
+ int off, int len, struct seq_file *seq);
+void *visorchannel_get_header(VISORCHANNEL *channel);
+
+#define VISORCHANNEL_CHANGE_SERVER_STATE(chan, chanId, newstate) \
+ do { \
+ U8 *p = (U8 *)visorchannel_get_header(chan); \
+ if (p) { \
+ ULTRA_CHANNEL_SERVER_TRANSITION(p, chanId, SrvState, \
+ newstate, logCtx); \
+ visorchannel_write \
+ (chan, \
+ offsetof(ULTRA_CHANNEL_PROTOCOL, SrvState), \
+ p + \
+ offsetof(ULTRA_CHANNEL_PROTOCOL, SrvState), \
+ sizeof(U32)); \
+ } \
+ } while (0)
+
+#define VISORCHANNEL_CHANGE_CLIENT_STATE(chan, chanId, newstate) \
+ do { \
+ U8 *p = (U8 *)visorchannel_get_header(chan); \
+ if (p) { \
+ ULTRA_CHANNEL_CLIENT_TRANSITION(p, chanId, \
+ newstate, logCtx); \
+ visorchannel_write \
+ (chan, \
+ offsetof(ULTRA_CHANNEL_PROTOCOL, CliStateOS), \
+ p + \
+ offsetof(ULTRA_CHANNEL_PROTOCOL, CliStateOS), \
+ sizeof(U32)); \
+ } \
+ } while (0)
+
+#endif
diff --git a/drivers/staging/unisys/visorchannel/visorchannel_funcs.c b/drivers/staging/unisys/visorchannel/visorchannel_funcs.c
new file mode 100644
index 000000000000..053681616ba3
--- /dev/null
+++ b/drivers/staging/unisys/visorchannel/visorchannel_funcs.c
@@ -0,0 +1,674 @@
+/* visorchannel_funcs.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * This provides Supervisor channel communication primitives, which are
+ * independent of the mechanism used to access the channel data. All channel
+ * data is accessed using the memregion abstraction. (memregion has both
+ * a CM2 implementation and a direct memory implementation.)
+ */
+
+#include "globals.h"
+#include "visorchannel.h"
+#include "guidutils.h"
+
+#define MYDRVNAME "visorchannel"
+
+struct VISORCHANNEL_Tag {
+ MEMREGION *memregion; /* from visor_memregion_create() */
+ CHANNEL_HEADER chan_hdr;
+ GUID guid;
+ ulong size;
+ BOOL needs_lock;
+ spinlock_t insert_lock;
+ spinlock_t remove_lock;
+
+ struct {
+ SIGNAL_QUEUE_HEADER req_queue;
+ SIGNAL_QUEUE_HEADER rsp_queue;
+ SIGNAL_QUEUE_HEADER event_queue;
+ SIGNAL_QUEUE_HEADER ack_queue;
+ } safe_uis_queue;
+};
+
+/* Creates the VISORCHANNEL abstraction for a data area in memory, but does
+ * NOT modify this data area.
+ */
+static VISORCHANNEL *
+visorchannel_create_guts(HOSTADDRESS physaddr, ulong channelBytes,
+ VISORCHANNEL *parent, ulong off, GUID guid,
+ BOOL needs_lock)
+{
+ VISORCHANNEL *p = NULL;
+ void *rc = NULL;
+
+ p = kmalloc(sizeof(VISORCHANNEL), GFP_KERNEL|__GFP_NORETRY);
+ if (p == NULL) {
+ ERRDRV("allocation failed: (status=0)\n");
+ rc = NULL;
+ goto Away;
+ }
+ p->memregion = NULL;
+ p->needs_lock = needs_lock;
+ spin_lock_init(&p->insert_lock);
+ spin_lock_init(&p->remove_lock);
+
+ /* prepare chan_hdr (abstraction to read/write channel memory) */
+ if (parent == NULL)
+ p->memregion =
+ visor_memregion_create(physaddr, sizeof(CHANNEL_HEADER));
+ else
+ p->memregion =
+ visor_memregion_create_overlapped(parent->memregion,
+ off,
+ sizeof(CHANNEL_HEADER));
+ if (p->memregion == NULL) {
+ ERRDRV("visor_memregion_create failed failed: (status=0)\n");
+ rc = NULL;
+ goto Away;
+ }
+ if (visor_memregion_read(p->memregion, 0, &p->chan_hdr,
+ sizeof(CHANNEL_HEADER)) < 0) {
+ ERRDRV("visor_memregion_read failed: (status=0)\n");
+ rc = NULL;
+ goto Away;
+ }
+ if (channelBytes == 0)
+ /* we had better be a CLIENT of this channel */
+ channelBytes = (ulong) p->chan_hdr.Size;
+ if (STRUCTSEQUAL(guid, Guid0))
+ /* we had better be a CLIENT of this channel */
+ guid = p->chan_hdr.Type;
+ if (visor_memregion_resize(p->memregion, channelBytes) < 0) {
+ ERRDRV("visor_memregion_resize failed: (status=0)\n");
+ rc = NULL;
+ goto Away;
+ }
+ p->size = channelBytes;
+ p->guid = guid;
+
+ rc = p;
+Away:
+
+ if (rc == NULL) {
+ if (p != NULL) {
+ visorchannel_destroy(p);
+ p = NULL;
+ }
+ }
+ return rc;
+}
+
+VISORCHANNEL *
+visorchannel_create(HOSTADDRESS physaddr, ulong channelBytes, GUID guid)
+{
+ return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid,
+ FALSE);
+}
+EXPORT_SYMBOL_GPL(visorchannel_create);
+
+VISORCHANNEL *
+visorchannel_create_with_lock(HOSTADDRESS physaddr, ulong channelBytes,
+ GUID guid)
+{
+ return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid,
+ TRUE);
+}
+EXPORT_SYMBOL_GPL(visorchannel_create_with_lock);
+
+VISORCHANNEL *
+visorchannel_create_overlapped(ulong channelBytes,
+ VISORCHANNEL *parent, ulong off, GUID guid)
+{
+ return visorchannel_create_guts(0, channelBytes, parent, off, guid,
+ FALSE);
+}
+EXPORT_SYMBOL_GPL(visorchannel_create_overlapped);
+
+VISORCHANNEL *
+visorchannel_create_overlapped_with_lock(ulong channelBytes,
+ VISORCHANNEL *parent, ulong off,
+ GUID guid)
+{
+ return visorchannel_create_guts(0, channelBytes, parent, off, guid,
+ TRUE);
+}
+EXPORT_SYMBOL_GPL(visorchannel_create_overlapped_with_lock);
+
+void
+visorchannel_destroy(VISORCHANNEL *channel)
+{
+ if (channel == NULL)
+ return;
+ if (channel->memregion != NULL) {
+ visor_memregion_destroy(channel->memregion);
+ channel->memregion = NULL;
+ }
+ kfree(channel);
+}
+EXPORT_SYMBOL_GPL(visorchannel_destroy);
+
+HOSTADDRESS
+visorchannel_get_physaddr(VISORCHANNEL *channel)
+{
+ return visor_memregion_get_physaddr(channel->memregion);
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_physaddr);
+
+ulong
+visorchannel_get_nbytes(VISORCHANNEL *channel)
+{
+ return channel->size;
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_nbytes);
+
+char *
+visorchannel_GUID_id(GUID *guid, char *s)
+{
+ return GUID_format1(guid, s);
+}
+EXPORT_SYMBOL_GPL(visorchannel_GUID_id);
+
+char *
+visorchannel_id(VISORCHANNEL *channel, char *s)
+{
+ return visorchannel_GUID_id(&channel->guid, s);
+}
+EXPORT_SYMBOL_GPL(visorchannel_id);
+
+char *
+visorchannel_zoneid(VISORCHANNEL *channel, char *s)
+{
+ return visorchannel_GUID_id(&channel->chan_hdr.ZoneGuid, s);
+}
+EXPORT_SYMBOL_GPL(visorchannel_zoneid);
+
+HOSTADDRESS
+visorchannel_get_clientpartition(VISORCHANNEL *channel)
+{
+ return channel->chan_hdr.PartitionHandle;
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_clientpartition);
+
+GUID
+visorchannel_get_GUID(VISORCHANNEL *channel)
+{
+ return channel->guid;
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_GUID);
+
+MEMREGION *
+visorchannel_get_memregion(VISORCHANNEL *channel)
+{
+ return channel->memregion;
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_memregion);
+
+int
+visorchannel_read(VISORCHANNEL *channel, ulong offset,
+ void *local, ulong nbytes)
+{
+ int rc = visor_memregion_read(channel->memregion, offset,
+ local, nbytes);
+ if ((rc >= 0) && (offset == 0) && (nbytes >= sizeof(CHANNEL_HEADER)))
+ memcpy(&channel->chan_hdr, local, sizeof(CHANNEL_HEADER));
+ return rc;
+}
+EXPORT_SYMBOL_GPL(visorchannel_read);
+
+int
+visorchannel_write(VISORCHANNEL *channel, ulong offset,
+ void *local, ulong nbytes)
+{
+ if (offset == 0 && nbytes >= sizeof(CHANNEL_HEADER))
+ memcpy(&channel->chan_hdr, local, sizeof(CHANNEL_HEADER));
+ return visor_memregion_write(channel->memregion, offset, local, nbytes);
+}
+EXPORT_SYMBOL_GPL(visorchannel_write);
+
+int
+visorchannel_clear(VISORCHANNEL *channel, ulong offset, U8 ch, ulong nbytes)
+{
+ int rc = -1;
+ int bufsize = 65536;
+ int written = 0;
+ U8 *buf = vmalloc(bufsize);
+
+ if (buf == NULL) {
+ ERRDRV("%s failed memory allocation", __func__);
+ goto Away;
+ }
+ memset(buf, ch, bufsize);
+ while (nbytes > 0) {
+ ulong thisbytes = bufsize;
+ int x = -1;
+ if (nbytes < thisbytes)
+ thisbytes = nbytes;
+ x = visor_memregion_write(channel->memregion, offset + written,
+ buf, thisbytes);
+ if (x < 0) {
+ rc = x;
+ goto Away;
+ }
+ written += thisbytes;
+ nbytes -= thisbytes;
+ }
+ rc = 0;
+
+Away:
+ if (buf != NULL) {
+ vfree(buf);
+ buf = NULL;
+ }
+ return rc;
+}
+EXPORT_SYMBOL_GPL(visorchannel_clear);
+
+void *
+visorchannel_get_header(VISORCHANNEL *channel)
+{
+ return (void *) &(channel->chan_hdr);
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_header);
+
+/** Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a
+ * channel header
+ */
+#define SIG_QUEUE_OFFSET(chan_hdr, q) \
+ ((chan_hdr)->oChannelSpace + ((q) * sizeof(SIGNAL_QUEUE_HEADER)))
+
+/** Return offset of a specific queue entry (data) from the beginning of a
+ * channel header
+ */
+#define SIG_DATA_OFFSET(chan_hdr, q, sig_hdr, slot) \
+ (SIG_QUEUE_OFFSET(chan_hdr, q) + (sig_hdr)->oSignalBase + \
+ ((slot) * (sig_hdr)->SignalSize))
+
+/** Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back
+ * into host memory
+ */
+#define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \
+ (visor_memregion_write(channel->memregion, \
+ SIG_QUEUE_OFFSET(&channel->chan_hdr, queue)+ \
+ offsetof(SIGNAL_QUEUE_HEADER, FIELD), \
+ &((sig_hdr)->FIELD), \
+ sizeof((sig_hdr)->FIELD)) >= 0)
+
+static BOOL
+sig_read_header(VISORCHANNEL *channel, U32 queue,
+ SIGNAL_QUEUE_HEADER *sig_hdr)
+{
+ BOOL rc = FALSE;
+
+ if (channel->chan_hdr.oChannelSpace < sizeof(CHANNEL_HEADER)) {
+ ERRDRV("oChannelSpace too small: (status=%d)\n", rc);
+ goto Away;
+ }
+
+ /* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */
+
+ if (visor_memregion_read(channel->memregion,
+ SIG_QUEUE_OFFSET(&channel->chan_hdr, queue),
+ sig_hdr, sizeof(SIGNAL_QUEUE_HEADER)) < 0) {
+ ERRDRV("queue=%d SIG_QUEUE_OFFSET=%d",
+ queue, (int)SIG_QUEUE_OFFSET(&channel->chan_hdr, queue));
+ ERRDRV("visor_memregion_read of signal queue failed: (status=%d)\n", rc);
+ goto Away;
+ }
+ rc = TRUE;
+Away:
+ return rc;
+}
+
+static BOOL
+sig_do_data(VISORCHANNEL *channel, U32 queue,
+ SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data, BOOL is_write)
+{
+ BOOL rc = FALSE;
+ int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue,
+ sig_hdr, slot);
+ if (is_write) {
+ if (visor_memregion_write(channel->memregion,
+ signal_data_offset,
+ data, sig_hdr->SignalSize) < 0) {
+ ERRDRV("visor_memregion_write of signal data failed: (status=%d)\n", rc);
+ goto Away;
+ }
+ } else {
+ if (visor_memregion_read(channel->memregion, signal_data_offset,
+ data, sig_hdr->SignalSize) < 0) {
+ ERRDRV("visor_memregion_read of signal data failed: (status=%d)\n", rc);
+ goto Away;
+ }
+ }
+ rc = TRUE;
+Away:
+ return rc;
+}
+
+static inline BOOL
+sig_read_data(VISORCHANNEL *channel, U32 queue,
+ SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data)
+{
+ return sig_do_data(channel, queue, sig_hdr, slot, data, FALSE);
+}
+
+static inline BOOL
+sig_write_data(VISORCHANNEL *channel, U32 queue,
+ SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data)
+{
+ return sig_do_data(channel, queue, sig_hdr, slot, data, TRUE);
+}
+
+static inline unsigned char
+safe_sig_queue_validate(pSIGNAL_QUEUE_HEADER psafe_sqh,
+ pSIGNAL_QUEUE_HEADER punsafe_sqh,
+ U32 *phead, U32 *ptail)
+{
+ if ((*phead >= psafe_sqh->MaxSignalSlots)
+ || (*ptail >= psafe_sqh->MaxSignalSlots)) {
+ /* Choose 0 or max, maybe based on current tail value */
+ *phead = 0;
+ *ptail = 0;
+
+ /* Sync with client as necessary */
+ punsafe_sqh->Head = *phead;
+ punsafe_sqh->Tail = *ptail;
+
+ ERRDRV("safe_sig_queue_validate: head = 0x%x, tail = 0x%x, MaxSlots = 0x%x",
+ *phead, *ptail, psafe_sqh->MaxSignalSlots);
+ return 0;
+ }
+ return 1;
+} /* end safe_sig_queue_validate */
+
+BOOL
+visorchannel_signalremove(VISORCHANNEL *channel, U32 queue, void *msg)
+{
+ BOOL rc = FALSE;
+ SIGNAL_QUEUE_HEADER sig_hdr;
+
+ if (channel->needs_lock)
+ spin_lock(&channel->remove_lock);
+
+ if (!sig_read_header(channel, queue, &sig_hdr)) {
+ rc = FALSE;
+ goto Away;
+ }
+ if (sig_hdr.Head == sig_hdr.Tail) {
+ rc = FALSE; /* no signals to remove */
+ goto Away;
+ }
+ sig_hdr.Tail = (sig_hdr.Tail + 1) % sig_hdr.MaxSignalSlots;
+ if (!sig_read_data(channel, queue, &sig_hdr, sig_hdr.Tail, msg)) {
+ ERRDRV("sig_read_data failed: (status=%d)\n", rc);
+ goto Away;
+ }
+ sig_hdr.NumSignalsReceived++;
+
+ /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
+ * update host memory.
+ */
+ MEMORYBARRIER;
+ if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, Tail)) {
+ ERRDRV("visor_memregion_write of Tail failed: (status=%d)\n",
+ rc);
+ goto Away;
+ }
+ if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumSignalsReceived)) {
+ ERRDRV("visor_memregion_write of NumSignalsReceived failed: (status=%d)\n", rc);
+ goto Away;
+ }
+ rc = TRUE;
+Away:
+ if (channel->needs_lock)
+ spin_unlock(&channel->remove_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(visorchannel_signalremove);
+
+BOOL
+visorchannel_signalinsert(VISORCHANNEL *channel, U32 queue, void *msg)
+{
+ BOOL rc = FALSE;
+ SIGNAL_QUEUE_HEADER sig_hdr;
+
+ if (channel->needs_lock)
+ spin_lock(&channel->insert_lock);
+
+ if (!sig_read_header(channel, queue, &sig_hdr)) {
+ rc = FALSE;
+ goto Away;
+ }
+
+ sig_hdr.Head = ((sig_hdr.Head + 1) % sig_hdr.MaxSignalSlots);
+ if (sig_hdr.Head == sig_hdr.Tail) {
+ sig_hdr.NumOverflows++;
+ if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumOverflows)) {
+ ERRDRV("visor_memregion_write of NumOverflows failed: (status=%d)\n", rc);
+ goto Away;
+ }
+ rc = FALSE;
+ goto Away;
+ }
+
+ if (!sig_write_data(channel, queue, &sig_hdr, sig_hdr.Head, msg)) {
+ ERRDRV("sig_write_data failed: (status=%d)\n", rc);
+ goto Away;
+ }
+ sig_hdr.NumSignalsSent++;
+
+ /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
+ * update host memory.
+ */
+ MEMORYBARRIER;
+ if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, Head)) {
+ ERRDRV("visor_memregion_write of Head failed: (status=%d)\n",
+ rc);
+ goto Away;
+ }
+ if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumSignalsSent)) {
+ ERRDRV("visor_memregion_write of NumSignalsSent failed: (status=%d)\n", rc);
+ goto Away;
+ }
+ rc = TRUE;
+Away:
+ if (channel->needs_lock)
+ spin_unlock(&channel->insert_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(visorchannel_signalinsert);
+
+
+int
+visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, U32 queue)
+{
+ SIGNAL_QUEUE_HEADER sig_hdr;
+ U32 slots_avail, slots_used;
+ U32 head, tail;
+
+ if (!sig_read_header(channel, queue, &sig_hdr))
+ return 0;
+ head = sig_hdr.Head;
+ tail = sig_hdr.Tail;
+ if (head < tail)
+ head = head + sig_hdr.MaxSignalSlots;
+ slots_used = (head - tail);
+ slots_avail = sig_hdr.MaxSignals - slots_used;
+ return (int) slots_avail;
+}
+EXPORT_SYMBOL_GPL(visorchannel_signalqueue_slots_avail);
+
+int
+visorchannel_signalqueue_max_slots(VISORCHANNEL *channel, U32 queue)
+{
+ SIGNAL_QUEUE_HEADER sig_hdr;
+ if (!sig_read_header(channel, queue, &sig_hdr))
+ return 0;
+ return (int) sig_hdr.MaxSignals;
+}
+EXPORT_SYMBOL_GPL(visorchannel_signalqueue_max_slots);
+
+static void
+sigqueue_debug(SIGNAL_QUEUE_HEADER *q, int which, struct seq_file *seq)
+{
+ seq_printf(seq, "Signal Queue #%d\n", which);
+ seq_printf(seq, " VersionId = %lu\n", (ulong) q->VersionId);
+ seq_printf(seq, " Type = %lu\n", (ulong) q->Type);
+ seq_printf(seq, " oSignalBase = %llu\n",
+ (long long) q->oSignalBase);
+ seq_printf(seq, " SignalSize = %lu\n", (ulong) q->SignalSize);
+ seq_printf(seq, " MaxSignalSlots = %lu\n",
+ (ulong) q->MaxSignalSlots);
+ seq_printf(seq, " MaxSignals = %lu\n", (ulong) q->MaxSignals);
+ seq_printf(seq, " FeatureFlags = %-16.16Lx\n",
+ (long long) q->FeatureFlags);
+ seq_printf(seq, " NumSignalsSent = %llu\n",
+ (long long) q->NumSignalsSent);
+ seq_printf(seq, " NumSignalsReceived = %llu\n",
+ (long long) q->NumSignalsReceived);
+ seq_printf(seq, " NumOverflows = %llu\n",
+ (long long) q->NumOverflows);
+ seq_printf(seq, " Head = %lu\n", (ulong) q->Head);
+ seq_printf(seq, " Tail = %lu\n", (ulong) q->Tail);
+}
+
+void
+visorchannel_debug(VISORCHANNEL *channel, int nQueues,
+ struct seq_file *seq, U32 off)
+{
+ HOSTADDRESS addr = 0;
+ ulong nbytes = 0, nbytes_region = 0;
+ MEMREGION *memregion = NULL;
+ CHANNEL_HEADER hdr;
+ CHANNEL_HEADER *phdr = &hdr;
+ char s[99];
+ int i = 0;
+ int errcode = 0;
+
+ if (channel == NULL) {
+ ERRDRV("%s no channel", __func__);
+ return;
+ }
+ memregion = channel->memregion;
+ if (memregion == NULL) {
+ ERRDRV("%s no memregion", __func__);
+ return;
+ }
+ addr = visor_memregion_get_physaddr(memregion);
+ nbytes_region = visor_memregion_get_nbytes(memregion);
+ errcode = visorchannel_read(channel, off,
+ phdr, sizeof(CHANNEL_HEADER));
+ if (errcode < 0) {
+ seq_printf(seq,
+ "Read of channel header failed with errcode=%d)\n",
+ errcode);
+ if (off == 0) {
+ phdr = &channel->chan_hdr;
+ seq_puts(seq, "(following data may be stale)\n");
+ } else
+ return;
+ }
+ nbytes = (ulong) (phdr->Size);
+ seq_printf(seq, "--- Begin channel @0x%-16.16Lx for 0x%lx bytes (region=0x%lx bytes) ---\n",
+ addr + off, nbytes, nbytes_region);
+ seq_printf(seq, "Type = %s\n", GUID_format2(&phdr->Type, s));
+ seq_printf(seq, "ZoneGuid = %s\n",
+ GUID_format2(&phdr->ZoneGuid, s));
+ seq_printf(seq, "Signature = 0x%-16.16Lx\n",
+ (long long) phdr->Signature);
+ seq_printf(seq, "LegacyState = %lu\n", (ulong) phdr->LegacyState);
+ seq_printf(seq, "SrvState = %lu\n", (ulong) phdr->SrvState);
+ seq_printf(seq, "CliStateBoot = %lu\n", (ulong) phdr->CliStateBoot);
+ seq_printf(seq, "CliStateOS = %lu\n", (ulong) phdr->CliStateOS);
+ seq_printf(seq, "HeaderSize = %lu\n", (ulong) phdr->HeaderSize);
+ seq_printf(seq, "Size = %llu\n", (long long) phdr->Size);
+ seq_printf(seq, "Features = 0x%-16.16llx\n",
+ (long long) phdr->Features);
+ seq_printf(seq, "PartitionHandle = 0x%-16.16llx\n",
+ (long long) phdr->PartitionHandle);
+ seq_printf(seq, "Handle = 0x%-16.16llx\n",
+ (long long) phdr->Handle);
+ seq_printf(seq, "VersionId = %lu\n", (ulong) phdr->VersionId);
+ seq_printf(seq, "oChannelSpace = %llu\n",
+ (long long) phdr->oChannelSpace);
+ if ((phdr->oChannelSpace == 0) || (errcode < 0))
+ ;
+ else
+ for (i = 0; i < nQueues; i++) {
+ SIGNAL_QUEUE_HEADER q;
+ errcode = visorchannel_read(channel,
+ off + phdr->oChannelSpace +
+ (i * sizeof(q)),
+ &q, sizeof(q));
+ if (errcode < 0) {
+ seq_printf(seq,
+ "failed to read signal queue #%d from channel @0x%-16.16Lx errcode=%d\n",
+ i, addr, errcode);
+ continue;
+ }
+ sigqueue_debug(&q, i, seq);
+ }
+ seq_printf(seq, "--- End channel @0x%-16.16Lx for 0x%lx bytes ---\n",
+ addr + off, nbytes);
+}
+EXPORT_SYMBOL_GPL(visorchannel_debug);
+
+void
+visorchannel_dump_section(VISORCHANNEL *chan, char *s,
+ int off, int len, struct seq_file *seq)
+{
+ char *buf, *tbuf, *fmtbuf;
+ int fmtbufsize = 0;
+ int i;
+ int errcode = 0;
+
+ fmtbufsize = 100 * COVQ(len, 16);
+ buf = kmalloc(len, GFP_KERNEL|__GFP_NORETRY);
+ fmtbuf = kmalloc(fmtbufsize, GFP_KERNEL|__GFP_NORETRY);
+ if (buf == NULL || fmtbuf == NULL)
+ goto Away;
+
+ errcode = visorchannel_read(chan, off, buf, len);
+ if (errcode < 0) {
+ ERRDRV("%s failed to read %s from channel errcode=%d",
+ s, __func__, errcode);
+ goto Away;
+ }
+ seq_printf(seq, "channel %s:\n", s);
+ tbuf = buf;
+ while (len > 0) {
+ i = (len < 16) ? len : 16;
+ hex_dump_to_buffer(tbuf, i, 16, 1, fmtbuf, fmtbufsize, TRUE);
+ seq_printf(seq, "%s\n", fmtbuf);
+ tbuf += 16;
+ len -= 16;
+ }
+
+Away:
+ if (buf != NULL) {
+ kfree(buf);
+ buf = NULL;
+ }
+ if (fmtbuf != NULL) {
+ kfree(fmtbuf);
+ fmtbuf = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(visorchannel_dump_section);
diff --git a/drivers/staging/unisys/visorchannel/visorchannel_main.c b/drivers/staging/unisys/visorchannel/visorchannel_main.c
new file mode 100644
index 000000000000..482ee0ac1c16
--- /dev/null
+++ b/drivers/staging/unisys/visorchannel/visorchannel_main.c
@@ -0,0 +1,49 @@
+/* visorchannel_main.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * This is a module "wrapper" around visorchannel_funcs.
+ */
+
+#include "globals.h"
+#include "channel.h"
+#include "visorchannel.h"
+#include "guidutils.h"
+
+#define MYDRVNAME "visorchannel"
+
+static int __init
+visorchannel_init(void)
+{
+ INFODRV("driver version %s loaded", VERSION);
+ return 0;
+}
+
+static void
+visorchannel_exit(void)
+{
+ INFODRV("driver unloaded");
+}
+
+module_init(visorchannel_init);
+module_exit(visorchannel_exit);
+
+MODULE_AUTHOR("Unisys");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Supervisor channel driver for service partition: ver "
+ VERSION);
+MODULE_VERSION(VERSION);
diff --git a/drivers/staging/unisys/visorchipset/Kconfig b/drivers/staging/unisys/visorchipset/Kconfig
new file mode 100644
index 000000000000..7ca2fbca9d57
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/Kconfig
@@ -0,0 +1,10 @@
+#
+# Unisys visorchipset configuration
+#
+
+config UNISYS_VISORCHIPSET
+ tristate "Unisys visorchipset driver"
+ depends on UNISYSSPAR && UNISYS_VISORUTIL && UNISYS_VISORCHANNEL
+ ---help---
+ If you say Y here, you will enable the Unisys visorchipset driver.
+
diff --git a/drivers/staging/unisys/visorchipset/Makefile b/drivers/staging/unisys/visorchipset/Makefile
new file mode 100644
index 000000000000..f5e8650e1b0e
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for Unisys visorchipset
+#
+
+obj-$(CONFIG_UNISYS_VISORCHIPSET) += visorchipset.o
+
+visorchipset-y := visorchipset_main.o controlvm_direct.o file.o filexfer.o \
+ parser.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+ccflags-y += -Idrivers/staging/unisys/uislib
+ccflags-y += -Idrivers/staging/unisys/visorchannel
+ccflags-y += -Idrivers/staging/unisys/common-spar/include
+ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
+ccflags-y += -Idrivers/staging/unisys/visorutil
+ccflags-y += -Iinclude/generated
+ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION
+
diff --git a/drivers/staging/unisys/visorchipset/controlvm.h b/drivers/staging/unisys/visorchipset/controlvm.h
new file mode 100644
index 000000000000..873fa12dfe6f
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/controlvm.h
@@ -0,0 +1,27 @@
+/* controlvm.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __CONTROLVM_H__
+#define __CONTROLVM_H__
+
+#include "timskmod.h"
+
+int controlvm_init(void);
+void controlvm_deinit(void);
+HOSTADDRESS controlvm_get_channel_address(void);
+
+#endif
diff --git a/drivers/staging/unisys/visorchipset/controlvm_direct.c b/drivers/staging/unisys/visorchipset/controlvm_direct.c
new file mode 100644
index 000000000000..b911ea85c093
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/controlvm_direct.c
@@ -0,0 +1,62 @@
+/* controlvm_direct.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* This is a controlvm-related code that is dependent upon firmware running
+ * on a virtual partition.
+ */
+
+#include "globals.h"
+#include "uisutils.h"
+#include "controlvm.h"
+#define CURRENT_FILE_PC VISOR_CHIPSET_PC_controlvm_direct_c
+
+
+/* We can fill in this code when we learn how to make vmcalls... */
+
+
+
+int controlvm_init(void)
+{
+ return 0;
+}
+
+
+
+void controlvm_deinit(void)
+{
+}
+
+
+
+HOSTADDRESS controlvm_get_channel_address(void)
+{
+ static BOOL warned = FALSE;
+ U64 addr = 0;
+
+ U32 size = 0;
+
+ if (!VMCALL_SUCCESSFUL(Issue_VMCALL_IO_CONTROLVM_ADDR(&addr, &size))) {
+ if (!warned) {
+ ERRDRV("%s - vmcall to determine controlvm channel addr failed",
+ __func__);
+ warned = TRUE;
+ }
+ return 0;
+ }
+ INFODRV("controlvm addr=%Lx", addr);
+ return addr;
+}
diff --git a/drivers/staging/unisys/visorchipset/file.c b/drivers/staging/unisys/visorchipset/file.c
new file mode 100644
index 000000000000..e214a1153282
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/file.c
@@ -0,0 +1,226 @@
+/* file.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* This contains the implementation that allows a usermode program to
+ * communicate with the visorchipset driver using a device/file interface.
+ */
+
+#include "globals.h"
+#include "visorchannel.h"
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include "uisutils.h"
+#include "file.h"
+
+#define CURRENT_FILE_PC VISOR_CHIPSET_PC_file_c
+
+static struct cdev Cdev;
+static VISORCHANNEL **PControlVm_channel;
+static dev_t MajorDev = -1; /**< indicates major num for device */
+static BOOL Registered = FALSE;
+
+static int visorchipset_open(struct inode *inode, struct file *file);
+static int visorchipset_release(struct inode *inode, struct file *file);
+static int visorchipset_mmap(struct file *file, struct vm_area_struct *vma);
+#ifdef HAVE_UNLOCKED_IOCTL
+long visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#else
+int visorchipset_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+#endif
+
+static const struct file_operations visorchipset_fops = {
+ .owner = THIS_MODULE,
+ .open = visorchipset_open,
+ .read = NULL,
+ .write = NULL,
+#ifdef HAVE_UNLOCKED_IOCTL
+ .unlocked_ioctl = visorchipset_ioctl,
+#else
+ .ioctl = visorchipset_ioctl,
+#endif
+ .release = visorchipset_release,
+ .mmap = visorchipset_mmap,
+};
+
+int
+visorchipset_file_init(dev_t majorDev, VISORCHANNEL **pControlVm_channel)
+{
+ int rc = -1;
+
+ PControlVm_channel = pControlVm_channel;
+ MajorDev = majorDev;
+ cdev_init(&Cdev, &visorchipset_fops);
+ Cdev.owner = THIS_MODULE;
+ if (MAJOR(MajorDev) == 0) {
+ /* dynamic major device number registration required */
+ if (alloc_chrdev_region(&MajorDev, 0, 1, MYDRVNAME) < 0) {
+ ERRDRV("Unable to allocate+register char device %s",
+ MYDRVNAME);
+ goto Away;
+ }
+ Registered = TRUE;
+ INFODRV("New major number %d registered\n", MAJOR(MajorDev));
+ } else {
+ /* static major device number registration required */
+ if (register_chrdev_region(MajorDev, 1, MYDRVNAME) < 0) {
+ ERRDRV("Unable to register char device %s", MYDRVNAME);
+ goto Away;
+ }
+ Registered = TRUE;
+ INFODRV("Static major number %d registered\n", MAJOR(MajorDev));
+ }
+ if (cdev_add(&Cdev, MKDEV(MAJOR(MajorDev), 0), 1) < 0) {
+ ERRDRV("failed to create char device: (status=%d)\n", rc);
+ goto Away;
+ }
+ INFODRV("Registered char device for %s (major=%d)",
+ MYDRVNAME, MAJOR(MajorDev));
+ rc = 0;
+Away:
+ return rc;
+}
+
+void
+visorchipset_file_cleanup(void)
+{
+ if (Cdev.ops != NULL)
+ cdev_del(&Cdev);
+ Cdev.ops = NULL;
+ if (Registered) {
+ if (MAJOR(MajorDev) >= 0) {
+ unregister_chrdev_region(MajorDev, 1);
+ MajorDev = MKDEV(0, 0);
+ }
+ Registered = FALSE;
+ }
+}
+
+static int
+visorchipset_open(struct inode *inode, struct file *file)
+{
+ unsigned minor_number = iminor(inode);
+ int rc = -ENODEV;
+
+ DEBUGDRV("%s", __func__);
+ if (minor_number != 0)
+ goto Away;
+ file->private_data = NULL;
+ rc = 0;
+Away:
+ if (rc < 0)
+ ERRDRV("%s minor=%d failed", __func__, minor_number);
+ return rc;
+}
+
+static int
+visorchipset_release(struct inode *inode, struct file *file)
+{
+ DEBUGDRV("%s", __func__);
+ return 0;
+}
+
+static int
+visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ ulong physAddr = 0;
+ ulong offset = vma->vm_pgoff << PAGE_SHIFT;
+ GUEST_PHYSICAL_ADDRESS addr = 0;
+
+ /* sv_enable_dfp(); */
+ DEBUGDRV("%s", __func__);
+ if (offset & (PAGE_SIZE - 1)) {
+ ERRDRV("%s virtual address NOT page-aligned!", __func__);
+ return -ENXIO; /* need aligned offsets */
+ }
+ switch (offset) {
+ case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
+ vma->vm_flags |= VM_IO;
+ if (*PControlVm_channel == NULL) {
+ ERRDRV("%s no controlvm channel yet", __func__);
+ return -ENXIO;
+ }
+ visorchannel_read(*PControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ gpControlChannel), &addr,
+ sizeof(addr));
+ if (addr == 0) {
+ ERRDRV("%s control channel address is 0", __func__);
+ return -ENXIO;
+ }
+ physAddr = (ulong) (addr);
+ DEBUGDRV("mapping physical address = 0x%lx", physAddr);
+ if (remap_pfn_range(vma, vma->vm_start,
+ physAddr >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ /*pgprot_noncached */
+ (vma->vm_page_prot))) {
+ ERRDRV("%s remap_pfn_range failed", __func__);
+ return -EAGAIN;
+ }
+ break;
+ default:
+ return -ENOSYS;
+ }
+ DEBUGDRV("%s success!", __func__);
+ return 0;
+}
+
+#ifdef HAVE_UNLOCKED_IOCTL
+long
+visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+#else
+int
+visorchipset_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+#endif
+{
+ int rc = SUCCESS;
+ S64 adjustment;
+ S64 vrtc_offset;
+ DBGINF("entered visorchipset_ioctl, cmd=%d", cmd);
+ switch (cmd) {
+ case VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET:
+ /* get the physical rtc offset */
+ vrtc_offset = Issue_VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET();
+ if (copy_to_user
+ ((void __user *)arg, &vrtc_offset, sizeof(vrtc_offset))) {
+ rc = -EFAULT;
+ goto Away;
+ }
+ DBGINF("insde visorchipset_ioctl, cmd=%d, vrtc_offset=%lld",
+ cmd, vrtc_offset);
+ break;
+ case VMCALL_UPDATE_PHYSICAL_TIME:
+ if (copy_from_user
+ (&adjustment, (void __user *)arg, sizeof(adjustment))) {
+ rc = -EFAULT;
+ goto Away;
+ }
+ DBGINF("insde visorchipset_ioctl, cmd=%d, adjustment=%lld", cmd,
+ adjustment);
+ rc = Issue_VMCALL_UPDATE_PHYSICAL_TIME(adjustment);
+ break;
+ default:
+ LOGERR("visorchipset_ioctl received invalid command");
+ rc = -EFAULT;
+ break;
+ }
+Away:
+ DBGINF("exiting %d!", rc);
+ return rc;
+}
diff --git a/drivers/staging/unisys/visorchipset/file.h b/drivers/staging/unisys/visorchipset/file.h
new file mode 100644
index 000000000000..597282aa9a06
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/file.h
@@ -0,0 +1,26 @@
+/* file.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __FILE_H__
+#define __FILE_H__
+
+#include "globals.h"
+
+int visorchipset_file_init(dev_t majorDev, VISORCHANNEL **pControlVm_channel);
+void visorchipset_file_cleanup(void);
+
+#endif
diff --git a/drivers/staging/unisys/visorchipset/filexfer.c b/drivers/staging/unisys/visorchipset/filexfer.c
new file mode 100644
index 000000000000..431cff844a43
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/filexfer.c
@@ -0,0 +1,506 @@
+/* filexfer.c
+ *
+ * Copyright © 2013 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* Code here-in is the "glue" that connects controlvm messages with the
+ * sparfilexfer driver, which is used to transfer file contents as payload
+ * across the controlvm channel.
+ */
+
+#include "globals.h"
+#include "controlvm.h"
+#include "visorchipset.h"
+#include "filexfer.h"
+
+#ifdef ENABLE_SPARFILEXFER /* sparfilexfer kernel module enabled in build */
+#include "sparfilexfer.h"
+
+/* Driver-global memory */
+static LIST_HEAD(Request_list); /* list of struct any_request *, via
+ * req_list memb */
+
+/* lock for above pool for allocation of any_request structs, and pool
+* name; note that kmem_cache_create requires that we keep the storage
+* for the pool name for the life of the pool
+ */
+static DEFINE_SPINLOCK(Request_list_lock);
+
+static struct kmem_cache *Request_memory_pool;
+static const char Request_memory_pool_name[] = "filexfer_request_pool";
+size_t Caller_req_context_bytes = 0; /* passed to filexfer_constructor() */
+
+/* This structure defines a single controlvm GETFILE conversation, which
+ * consists of a single controlvm request message and 1 or more controlvm
+ * response messages.
+ */
+struct getfile_request {
+ CONTROLVM_MESSAGE_HEADER controlvm_header;
+ atomic_t buffers_in_use;
+ GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC get_contiguous_controlvm_payload;
+ CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC controlvm_respond_with_payload;
+};
+
+/* This structure defines a single controlvm PUTFILE conversation, which
+ * consists of a single controlvm request with a filename, and additional
+ * controlvm messages with file data.
+ */
+struct putfile_request {
+ GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata;
+ CONTROLVM_RESPOND_FUNC controlvm_end_putFile;
+};
+
+/* This structure defines a single file transfer operation, which can either
+ * be a GETFILE or PUTFILE.
+ */
+struct any_request {
+ struct list_head req_list;
+ ulong2 file_request_number;
+ ulong2 data_sequence_number;
+ TRANSMITFILE_DUMP_FUNC dump_func;
+ BOOL is_get;
+ union {
+ struct getfile_request get;
+ struct putfile_request put;
+ };
+ /* Size of caller_context_data will be
+ * <Caller_req_context_bytes> bytes. I aligned this because I
+ * am paranoid about what happens when an arbitrary data
+ * structure with unknown alignment requirements gets copied
+ * here. I want caller_context_data to be aligned to the
+ * coarsest possible alignment boundary that could be required
+ * for any user data structure.
+ */
+ u8 caller_context_data[1] __aligned(sizeof(ulong2);
+};
+
+/*
+ * Links the any_request into the global list of allocated requests
+ * (<Request_list>).
+ */
+static void
+unit_tracking_create(struct list_head *dev_list_link)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&Request_list_lock, flags);
+ list_add(dev_list_link, &Request_list);
+ spin_unlock_irqrestore(&Request_list_lock, flags);
+}
+
+/* Unlinks a any_request from the global list (<Request_list>).
+ */
+static void
+unit_tracking_destroy(struct list_head *dev_list_link)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&Request_list_lock, flags);
+ list_del(dev_list_link);
+ spin_unlock_irqrestore(&Request_list_lock, flags);
+}
+
+/* Allocate memory for and return a new any_request struct, and
+ * link it to the global list of outstanding requests.
+ */
+static struct any_request *
+alloc_request(char *fn, int ln)
+{
+ struct any_request *req = (struct any_request *)
+ (visorchipset_cache_alloc(Request_memory_pool,
+ FALSE,
+ fn, ln));
+ if (!req)
+ return NULL;
+ memset(req, 0, sizeof(struct any_request) + Caller_req_context_bytes);
+ unit_tracking_create(&req->req_list);
+ return req;
+}
+
+/* Book-end for alloc_request().
+ */
+static void
+free_request(struct any_request *req, char *fn, int ln)
+{
+ unit_tracking_destroy(&req->req_list);
+ visorchipset_cache_free(Request_memory_pool, req, fn, ln);
+}
+
+/* Constructor for filexfer.o.
+ */
+int
+filexfer_constructor(size_t req_context_bytes)
+{
+ int rc = -1;
+
+ Caller_req_context_bytes = req_context_bytes;
+ Request_memory_pool =
+ kmem_cache_create(Request_memory_pool_name,
+ sizeof(struct any_request) +
+ Caller_req_context_bytes,
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!Request_memory_pool) {
+ LOGERR("failed to alloc Request_memory_pool");
+ rc = -ENOMEM;
+ goto Away;
+ }
+ rc = 0;
+Away:
+ if (rc < 0) {
+ if (Request_memory_pool) {
+ kmem_cache_destroy(Request_memory_pool);
+ Request_memory_pool = NULL;
+ }
+ }
+ return rc;
+}
+
+/* Destructor for filexfer.o.
+ */
+void
+filexfer_destructor(void)
+{
+ if (Request_memory_pool) {
+ kmem_cache_destroy(Request_memory_pool);
+ Request_memory_pool = NULL;
+ }
+}
+
+/* This function will obtain an available chunk from the controlvm payload area,
+ * store the size in bytes of the chunk in <actual_size>, and return a pointer
+ * to the chunk. The function is passed to the sparfilexfer driver, which calls
+ * it whenever payload space is required to copy file data into.
+ */
+static void *
+get_empty_bucket_for_getfile_data(void *context,
+ ulong min_size, ulong max_size,
+ ulong *actual_size)
+{
+ void *bucket;
+ struct any_request *req = (struct any_request *) context;
+
+ if (!req->is_get) {
+ LOGERR("%s - unexpected call", __func__);
+ return NULL;
+ }
+ bucket = (*req->get.get_contiguous_controlvm_payload)
+ (min_size, max_size, actual_size);
+ if (bucket != NULL) {
+ atomic_inc(&req->get.buffers_in_use);
+ DBGINF("%s - sent %lu-byte buffer", __func__, *actual_size);
+ }
+ return bucket;
+}
+
+/* This function will send a controlvm response with data in the payload
+ * (whose space was obtained with get_empty_bucket_for_getfile_data). The
+ * function is passed to the sparfilexfer driver, which calls it whenever it
+ * wants to send file data back across the controlvm channel.
+ */
+static int
+send_full_getfile_data_bucket(void *context, void *bucket,
+ ulong bucket_actual_size, ulong bucket_used_size)
+{
+ struct any_request *req = (struct any_request *) context;
+
+ if (!req->is_get) {
+ LOGERR("%s - unexpected call", __func__);
+ return 0;
+ }
+ DBGINF("sending buffer for %lu/%lu",
+ bucket_used_size, bucket_actual_size);
+ if (!(*req->get.controlvm_respond_with_payload)
+ (&req->get.controlvm_header,
+ req->file_request_number,
+ req->data_sequence_number++,
+ 0, bucket, bucket_actual_size, bucket_used_size, TRUE))
+ atomic_dec(&req->get.buffers_in_use);
+ return 0;
+}
+
+/* This function will send a controlvm response indicating the end of a
+ * GETFILE transfer. The function is passed to the sparfilexfer driver.
+ */
+static void
+send_end_of_getfile_data(void *context, int status)
+{
+ struct any_request *req = (struct any_request *) context;
+ if (!req->is_get) {
+ LOGERR("%s - unexpected call", __func__);
+ return;
+ }
+ LOGINF("status=%d", status);
+ (*req->get.controlvm_respond_with_payload)
+ (&req->get.controlvm_header,
+ req->file_request_number,
+ req->data_sequence_number++, status, NULL, 0, 0, FALSE);
+ free_request(req, __FILE__, __LINE__);
+ module_put(THIS_MODULE);
+}
+
+/* This function supplies data for a PUTFILE transfer.
+ * The function is passed to the sparfilexfer driver.
+ */
+static int
+get_putfile_data(void *context, void *pbuf, size_t bufsize,
+ BOOL buf_is_userspace, size_t *bytes_transferred)
+{
+ struct any_request *req = (struct any_request *) context;
+ if (req->is_get) {
+ LOGERR("%s - unexpected call", __func__);
+ return -1;
+ }
+ return (*req->put.get_controlvm_filedata) (&req->caller_context_data[0],
+ pbuf, bufsize,
+ buf_is_userspace,
+ bytes_transferred);
+}
+
+/* This function is called to indicate the end of a PUTFILE transfer.
+ * The function is passed to the sparfilexfer driver.
+ */
+static void
+end_putfile(void *context, int status)
+{
+ struct any_request *req = (struct any_request *) context;
+ if (req->is_get) {
+ LOGERR("%s - unexpected call", __func__);
+ return;
+ }
+ (*req->put.controlvm_end_putFile) (&req->caller_context_data[0],
+ status);
+ free_request(req, __FILE__, __LINE__);
+ module_put(THIS_MODULE);
+}
+
+/* Refer to filexfer.h for description. */
+BOOL
+filexfer_getFile(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ ulong2 file_request_number,
+ uint uplink_index,
+ uint disk_index,
+ char *file_name,
+ GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC
+ get_contiguous_controlvm_payload,
+ CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC
+ controlvm_respond_with_payload,
+ TRANSMITFILE_DUMP_FUNC dump_func)
+{
+ BOOL use_count_up = FALSE;
+ BOOL failed = TRUE;
+ struct any_request *req = alloc_request(__FILE__, __LINE__);
+
+ if (!req) {
+ LOGERR("allocation of any_request failed");
+ goto Away;
+ }
+ /* We need to increment this module's use count because we're handing
+ * off pointers to functions within this module to be used by
+ * another module.
+ */
+ __module_get(THIS_MODULE);
+ use_count_up = TRUE;
+ req->is_get = TRUE;
+ req->file_request_number = file_request_number;
+ req->data_sequence_number = 0;
+ req->dump_func = dump_func;
+ req->get.controlvm_header = *msgHdr;
+ atomic_set(&req->get.buffers_in_use, 0);
+ req->get.get_contiguous_controlvm_payload =
+ get_contiguous_controlvm_payload;
+ req->get.controlvm_respond_with_payload =
+ controlvm_respond_with_payload;
+ if (sparfilexfer_local2remote(req, /* context, passed to
+ * callback funcs */
+ file_name,
+ file_request_number,
+ uplink_index,
+ disk_index,
+ get_empty_bucket_for_getfile_data,
+ send_full_getfile_data_bucket,
+ send_end_of_getfile_data) < 0) {
+ LOGERR("sparfilexfer_local2remote failed");
+ goto Away;
+ }
+ failed = FALSE;
+Away:
+ if (failed) {
+ if (use_count_up) {
+ module_put(THIS_MODULE);
+ use_count_up = FALSE;
+ }
+ if (req) {
+ free_request(req, __FILE__, __LINE__);
+ req = NULL;
+ }
+ return FALSE;
+ } else {
+ return TRUE;
+ /* success; send callbacks will be called for responses */
+ }
+}
+
+/* Refer to filexfer.h for description. */
+void *
+filexfer_putFile(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ ulong2 file_request_number,
+ uint uplink_index,
+ uint disk_index,
+ char *file_name,
+ TRANSMITFILE_INIT_CONTEXT_FUNC init_context,
+ GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata,
+ CONTROLVM_RESPOND_FUNC controlvm_end_putFile,
+ TRANSMITFILE_DUMP_FUNC dump_func)
+{
+ BOOL use_count_up = FALSE;
+ BOOL failed = TRUE;
+ struct any_request *req = alloc_request(__FILE__, __LINE__);
+ void *caller_ctx = NULL;
+
+ if (!req) {
+ LOGERR("allocation of any_request failed");
+ goto Away;
+ }
+ caller_ctx = (void *) (&(req->caller_context_data[0]));
+ /* We need to increment this module's use count because we're handing
+ * off pointers to functions within this module to be used by
+ * another module.
+ */
+ __module_get(THIS_MODULE);
+ use_count_up = TRUE;
+ req->is_get = FALSE;
+ req->file_request_number = file_request_number;
+ req->data_sequence_number = 0;
+ req->dump_func = dump_func;
+ req->put.get_controlvm_filedata = get_controlvm_filedata;
+ req->put.controlvm_end_putFile = controlvm_end_putFile;
+ (*init_context) (caller_ctx, msgHdr, file_request_number);
+ if (sparfilexfer_remote2local(req, /* context, passed to
+ * callback funcs */
+ file_name,
+ file_request_number,
+ uplink_index,
+ disk_index,
+ get_putfile_data, end_putfile) < 0) {
+ LOGERR("sparfilexfer_remote2local failed");
+ goto Away;
+ }
+ failed = FALSE;
+Away:
+ if (failed) {
+ if (use_count_up) {
+ module_put(THIS_MODULE);
+ use_count_up = FALSE;
+ }
+ if (req) {
+ free_request(req, __FILE__, __LINE__);
+ req = NULL;
+ }
+ return NULL;
+ } else {
+ return caller_ctx;
+ /* success; callbacks will be called for responses */
+ }
+}
+
+static void
+dump_get_request(struct seq_file *f, struct getfile_request *getreq)
+{
+ seq_printf(f, " buffers_in_use=%d\n",
+ atomic_read(&getreq->buffers_in_use));
+}
+
+static void
+dump_put_request(struct seq_file *f, struct putfile_request *putreq)
+{
+}
+
+static void
+dump_request(struct seq_file *f, struct any_request *req)
+{
+ seq_printf(f, "* %s id=%llu seq=%llu\n",
+ ((req->is_get) ? "Get" : "Put"),
+ req->file_request_number, req->data_sequence_number);
+ if (req->is_get)
+ dump_get_request(f, &req->get);
+ else
+ dump_put_request(f, &req->put);
+ if (req->dump_func)
+ (*req->dump_func) (f, &(req->caller_context_data[0]), " ");
+}
+
+void
+filexfer_dump(struct seq_file *f)
+{
+ ulong flags;
+ struct list_head *entry;
+
+ seq_puts(f, "Outstanding TRANSMIT_FILE requests:\n");
+ spin_lock_irqsave(&Request_list_lock, flags);
+ list_for_each(entry, &Request_list) {
+ struct any_request *req;
+ req = list_entry(entry, struct any_request, req_list);
+ dump_request(f, req);
+ }
+ spin_unlock_irqrestore(&Request_list_lock, flags);
+}
+
+#else /* ifdef ENABLE_SPARFILEXFER */
+int
+filexfer_constructor(size_t req_context_bytes)
+{
+ return 0; /* success */
+}
+
+void
+filexfer_destructor(void)
+{
+}
+
+BOOL
+filexfer_getFile(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ u64 file_request_number,
+ uint uplink_index,
+ uint disk_index,
+ char *file_name,
+ GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC
+ get_contiguous_controlvm_payload,
+ CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC
+ controlvm_respond_with_payload,
+ TRANSMITFILE_DUMP_FUNC dump_func)
+{
+ /* since no sparfilexfer module exists to call, we just fail */
+ return FALSE;
+}
+
+void *
+filexfer_putFile(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ u64 file_request_number,
+ uint uplink_index,
+ uint disk_index,
+ char *file_name,
+ TRANSMITFILE_INIT_CONTEXT_FUNC init_context,
+ GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata,
+ CONTROLVM_RESPOND_FUNC controlvm_end_putFile,
+ TRANSMITFILE_DUMP_FUNC dump_func)
+{
+ /* since no sparfilexfer module exists to call, we just fail */
+ return NULL;
+}
+
+void
+filexfer_dump(struct seq_file *f)
+{
+}
+
+#endif /* ifdef ENABLE_SPARFILEXFER */
diff --git a/drivers/staging/unisys/visorchipset/filexfer.h b/drivers/staging/unisys/visorchipset/filexfer.h
new file mode 100644
index 000000000000..a1bfca69cdcf
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/filexfer.h
@@ -0,0 +1,147 @@
+/* filexfer.h
+ *
+ * Copyright © 2013 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* This header file defines the interface that filexfer.c provides to other
+ * code in the visorchipset driver.
+ */
+
+#ifndef __FILEXFER_H__
+#define __FILEXFER_H__
+
+#include "globals.h"
+#include "controlvmchannel.h"
+#include <linux/seq_file.h>
+
+typedef void *(*GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC) (ulong min_size,
+ ulong max_size,
+ ulong *actual_size);
+
+typedef BOOL
+(*CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC) (CONTROLVM_MESSAGE_HEADER *msgHdr,
+ u64 fileRequestNumber,
+ u64 dataSequenceNumber,
+ int response,
+ void *bucket, ulong payloadChunkSize,
+ ulong payloadUsedBytes, BOOL partial);
+
+typedef void
+(*TRANSMITFILE_INIT_CONTEXT_FUNC)(void *ctx,
+ const CONTROLVM_MESSAGE_HEADER *hdr,
+ u64 file_request_number);
+typedef void (*TRANSMITFILE_DUMP_FUNC) (struct seq_file *f, void *ctx,
+ const char *pfx);
+typedef int (*GET_CONTROLVM_FILEDATA_FUNC) (void *ctx,
+ void *buf, size_t bufsize,
+ BOOL buf_is_userspace,
+ size_t *bytes_transferred);
+typedef void (*CONTROLVM_RESPOND_FUNC) (void *ctx, int response);
+
+/* Call once to initialize filexfer.o.
+ * req_context_bytes number of bytes the caller needs to keep track of each file
+ * transfer conversation. The <ctx_init_value> passed to filexfer_putFile() is
+ * assumed to be this many bytes in size. Code within filexfer.o will copy this
+ * into a dynamically-allocated area, and pass back a pointer to that area in
+ * callback functions.
+ */
+int filexfer_constructor(size_t req_context_bytes);
+
+/* Call once to clean up filexfer.o */
+void filexfer_destructor(void);
+
+/* Call this to dump diagnostic info about all outstanding getFiles/putFiles */
+void filexfer_dump(struct seq_file *f);
+
+/* Call to transfer a file from the local filesystem (i.e., from the environment
+ * where this driver is running) across the controlvm channel to a remote
+ * environment. 1 or more controlvm responses will be sent as a result, each
+ * of which whose payload contains file data. Only the last controlvm message
+ * will have Flags.partialCompletion==0.
+ *
+ * msgHdr the controlvm message header of the GETFILE request which
+ * we just received
+ * file_request_number this is all data from the GETFILE request that
+ * uplink_index define which file is to be transferred
+ * disk_index
+ * file_name
+ * get_contiguous_controlvm_payload function to call when space is needed
+ * in the payload area
+ * controlvm_respond_with_payload function to call to send each controlvm
+ * response containing file data as the
+ * payload; returns FALSE only if the
+ * payload buffer was freed inline
+ * dump_func function to dump context data in
+ * human-readable format
+ *
+ * Returns TRUE iff the file transfer request has been successfully initiated,
+ * or FALSE to indicate failure.
+ */
+BOOL
+filexfer_getFile(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ u64 file_request_number,
+ uint uplink_index,
+ uint disk_index,
+ char *file_name,
+ GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC
+ get_contiguous_controlvm_payload,
+ CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC
+ controlvm_respond_with_payload,
+ TRANSMITFILE_DUMP_FUNC dump_func);
+
+/* Call to create a file in the local filesystem (i.e., in the environment
+ * where this driver is running) from data received as payload in
+ * controlvm channel messages from a remote environment. 1 or more controlvm
+ * messages will be received for this transfer, and only the last will have
+ * Flags.partialCompletion==0.
+ *
+ * msgHdr the controlvm message header of the PUTFILE request which
+ * we just received
+ * file_request_number this is all data from the PUTFILE request that
+ * uplink_index define which file is to be created in the local
+ * disk_index filesystem
+ * file_name
+ * init_context function to call to initialize the
+ * <req_context_bytes>-sized storage area returned by
+ * this func; note that it would NOT be sufficient to
+ * allow the caller to initialize this upon return, as
+ * the the other user-supplied callbacks might have
+ * already been called by then
+ * get_controlvm_filedata function to call to obtain more data for the file
+ * being written; refer to get_controlvm_filedata()
+ * in visorchipset_main.c for a complete description
+ * of parameters
+ * controlvm_end_putFile function to call to indicate that creation of the
+ * local file has completed; set <response> to a
+ * negative value to indicate an error
+ * dump_func function to dump context data in human-readable
+ * format
+ *
+ * Returns a pointer to a dynamically-allocated storage area of size
+ * <req_context_bytes> which the caller can use, or NULL for error. The
+ * caller should NEVER free the returned pointer, but should expect to receive
+ * it as the <ctx> argument when callback functions are called.
+ */
+void *filexfer_putFile(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ u64 file_request_number,
+ uint uplink_index,
+ uint disk_index,
+ char *file_name,
+ TRANSMITFILE_INIT_CONTEXT_FUNC init_context,
+ GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata,
+ CONTROLVM_RESPOND_FUNC controlvm_end_putFile,
+ TRANSMITFILE_DUMP_FUNC dump_func);
+
+#endif
diff --git a/drivers/staging/unisys/visorchipset/globals.h b/drivers/staging/unisys/visorchipset/globals.h
new file mode 100644
index 000000000000..a0e6d4fc03ae
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/globals.h
@@ -0,0 +1,45 @@
+/* globals.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+
+#ifndef __VISORCHIPSET_GLOBALS_H__
+#define __VISORCHIPSET_GLOBALS_H__
+
+#include "uniklog.h"
+#include "diagnostics/appos_subsystems.h"
+#include "timskmod.h"
+#include "visorchipset.h"
+#include "visorchipset_umode.h"
+#include "version.h"
+
+#define MYDRVNAME "visorchipset"
+
+
+/* module parameters */
+
+extern int visorchipset_testvnic;
+extern int visorchipset_testvnicclient;
+extern int visorchipset_testmsg;
+extern int visorchipset_major;
+extern int visorchipset_serverregwait;
+extern int visorchipset_clientregwait;
+extern int visorchipset_testteardown;
+extern int visorchipset_disable_controlvm;
+extern int visorchipset_crash_kernel;
+extern int visorchipset_holdchipsetready;
+
+#endif
diff --git a/drivers/staging/unisys/visorchipset/parser.c b/drivers/staging/unisys/visorchipset/parser.c
new file mode 100644
index 000000000000..b408d415bd8c
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/parser.c
@@ -0,0 +1,474 @@
+/* parser.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#include "parser.h"
+#include "memregion.h"
+#include "controlvmchannel.h"
+#include <linux/ctype.h>
+#include <linux/mm.h>
+
+#define MYDRVNAME "visorchipset_parser"
+#define CURRENT_FILE_PC VISOR_CHIPSET_PC_parser_c
+
+/* We will refuse to allocate more than this many bytes to copy data from
+ * incoming payloads. This serves as a throttling mechanism.
+ */
+#define MAX_CONTROLVM_PAYLOAD_BYTES (1024*128)
+static ulong Controlvm_Payload_Bytes_Buffered;
+
+struct PARSER_CONTEXT_Tag {
+ ulong allocbytes;
+ ulong param_bytes;
+ u8 *curr;
+ ulong bytes_remaining;
+ BOOL byte_stream;
+ char data[0];
+};
+
+static PARSER_CONTEXT *
+parser_init_guts(U64 addr, U32 bytes, BOOL isLocal,
+ BOOL hasStandardPayloadHeader, BOOL *tryAgain)
+{
+ int allocbytes = sizeof(PARSER_CONTEXT) + bytes;
+ PARSER_CONTEXT *rc = NULL;
+ PARSER_CONTEXT *ctx = NULL;
+ MEMREGION *rgn = NULL;
+ ULTRA_CONTROLVM_PARAMETERS_HEADER *phdr = NULL;
+
+ if (tryAgain)
+ *tryAgain = FALSE;
+ if (!hasStandardPayloadHeader)
+ /* alloc and 0 extra byte to ensure payload is
+ * '\0'-terminated
+ */
+ allocbytes++;
+ if ((Controlvm_Payload_Bytes_Buffered + bytes)
+ > MAX_CONTROLVM_PAYLOAD_BYTES) {
+ ERRDRV("%s (%s:%d) - prevented allocation of %d bytes to prevent exceeding throttling max (%d)",
+ __func__, __FILE__, __LINE__, allocbytes,
+ MAX_CONTROLVM_PAYLOAD_BYTES);
+ if (tryAgain)
+ *tryAgain = TRUE;
+ rc = NULL;
+ goto Away;
+ }
+ ctx = kzalloc(allocbytes, GFP_KERNEL|__GFP_NORETRY);
+ if (ctx == NULL) {
+ ERRDRV("%s (%s:%d) - failed to allocate %d bytes",
+ __func__, __FILE__, __LINE__, allocbytes);
+ if (tryAgain)
+ *tryAgain = TRUE;
+ rc = NULL;
+ goto Away;
+ }
+
+ ctx->allocbytes = allocbytes;
+ ctx->param_bytes = bytes;
+ ctx->curr = NULL;
+ ctx->bytes_remaining = 0;
+ ctx->byte_stream = FALSE;
+ if (isLocal) {
+ void *p;
+ if (addr > virt_to_phys(high_memory - 1)) {
+ ERRDRV("%s - bad local address (0x%-16.16Lx for %lu)",
+ __func__,
+ (unsigned long long) addr, (ulong) bytes);
+ rc = NULL;
+ goto Away;
+ }
+ p = __va((ulong) (addr));
+ memcpy(ctx->data, p, bytes);
+ } else {
+ rgn = visor_memregion_create(addr, bytes);
+ if (!rgn) {
+ rc = NULL;
+ goto Away;
+ }
+ if (visor_memregion_read(rgn, 0, ctx->data, bytes) < 0) {
+ rc = NULL;
+ goto Away;
+ }
+ }
+ if (!hasStandardPayloadHeader) {
+ ctx->byte_stream = TRUE;
+ rc = ctx;
+ goto Away;
+ }
+ phdr = (ULTRA_CONTROLVM_PARAMETERS_HEADER *) (ctx->data);
+ if (phdr->TotalLength != bytes) {
+ ERRDRV("%s - bad total length %lu (should be %lu)",
+ __func__,
+ (ulong) (phdr->TotalLength), (ulong) (bytes));
+ rc = NULL;
+ goto Away;
+ }
+ if (phdr->TotalLength < phdr->HeaderLength) {
+ ERRDRV("%s - total length < header length (%lu < %lu)",
+ __func__,
+ (ulong) (phdr->TotalLength),
+ (ulong) (phdr->HeaderLength));
+ rc = NULL;
+ goto Away;
+ }
+ if (phdr->HeaderLength < sizeof(ULTRA_CONTROLVM_PARAMETERS_HEADER)) {
+ ERRDRV("%s - header is too small (%lu < %lu)",
+ __func__,
+ (ulong) (phdr->HeaderLength),
+ (ulong) (sizeof(ULTRA_CONTROLVM_PARAMETERS_HEADER)));
+ rc = NULL;
+ goto Away;
+ }
+
+ rc = ctx;
+Away:
+ if (rgn) {
+ visor_memregion_destroy(rgn);
+ rgn = NULL;
+ }
+ if (rc)
+ Controlvm_Payload_Bytes_Buffered += ctx->param_bytes;
+ else {
+ if (ctx) {
+ parser_done(ctx);
+ ctx = NULL;
+ }
+ }
+ return rc;
+}
+
+PARSER_CONTEXT *
+parser_init(U64 addr, U32 bytes, BOOL isLocal, BOOL *tryAgain)
+{
+ return parser_init_guts(addr, bytes, isLocal, TRUE, tryAgain);
+}
+
+/* Call this instead of parser_init() if the payload area consists of just
+ * a sequence of bytes, rather than a ULTRA_CONTROLVM_PARAMETERS_HEADER
+ * structures. Afterwards, you can call parser_simpleString_get() or
+ * parser_byteStream_get() to obtain the data.
+ */
+PARSER_CONTEXT *
+parser_init_byteStream(U64 addr, U32 bytes, BOOL isLocal, BOOL *tryAgain)
+{
+ return parser_init_guts(addr, bytes, isLocal, FALSE, tryAgain);
+}
+
+/* Obtain '\0'-terminated copy of string in payload area.
+ */
+char *
+parser_simpleString_get(PARSER_CONTEXT *ctx)
+{
+ if (!ctx->byte_stream)
+ return NULL;
+ return ctx->data; /* note this IS '\0'-terminated, because of
+ * the num of bytes we alloc+clear in
+ * parser_init_byteStream() */
+}
+
+/* Obtain a copy of the buffer in the payload area.
+ */
+void *
+parser_byteStream_get(PARSER_CONTEXT *ctx, ulong *nbytes)
+{
+ if (!ctx->byte_stream)
+ return NULL;
+ if (nbytes)
+ *nbytes = ctx->param_bytes;
+ return (void *) ctx->data;
+}
+
+GUID
+parser_id_get(PARSER_CONTEXT *ctx)
+{
+ ULTRA_CONTROLVM_PARAMETERS_HEADER *phdr = NULL;
+
+ if (ctx == NULL) {
+ ERRDRV("%s (%s:%d) - no context",
+ __func__, __FILE__, __LINE__);
+ return Guid0;
+ }
+ phdr = (ULTRA_CONTROLVM_PARAMETERS_HEADER *) (ctx->data);
+ return phdr->Id;
+}
+
+void
+parser_param_start(PARSER_CONTEXT *ctx, PARSER_WHICH_STRING which_string)
+{
+ ULTRA_CONTROLVM_PARAMETERS_HEADER *phdr = NULL;
+
+ if (ctx == NULL) {
+ ERRDRV("%s (%s:%d) - no context",
+ __func__, __FILE__, __LINE__);
+ goto Away;
+ }
+ phdr = (ULTRA_CONTROLVM_PARAMETERS_HEADER *) (ctx->data);
+ switch (which_string) {
+ case PARSERSTRING_INITIATOR:
+ ctx->curr = ctx->data + phdr->InitiatorOffset;
+ ctx->bytes_remaining = phdr->InitiatorLength;
+ break;
+ case PARSERSTRING_TARGET:
+ ctx->curr = ctx->data + phdr->TargetOffset;
+ ctx->bytes_remaining = phdr->TargetLength;
+ break;
+ case PARSERSTRING_CONNECTION:
+ ctx->curr = ctx->data + phdr->ConnectionOffset;
+ ctx->bytes_remaining = phdr->ConnectionLength;
+ break;
+ case PARSERSTRING_NAME:
+ ctx->curr = ctx->data + phdr->NameOffset;
+ ctx->bytes_remaining = phdr->NameLength;
+ break;
+ default:
+ ERRDRV("%s - bad which_string %d", __func__, which_string);
+ break;
+ }
+
+Away:
+ return;
+}
+
+void
+parser_done(PARSER_CONTEXT *ctx)
+{
+ if (!ctx)
+ return;
+ Controlvm_Payload_Bytes_Buffered -= ctx->param_bytes;
+ kfree(ctx);
+}
+
+/** Return length of string not counting trailing spaces. */
+static int
+string_length_no_trail(char *s, int len)
+{
+ int i = len - 1;
+ while (i >= 0) {
+ if (!isspace(s[i]))
+ return i + 1;
+ i--;
+ }
+ return 0;
+}
+
+/** Grab the next name and value out of the parameter buffer.
+ * The entire parameter buffer looks like this:
+ * <name>=<value>\0
+ * <name>=<value>\0
+ * ...
+ * \0
+ * If successful, the next <name> value is returned within the supplied
+ * <nam> buffer (the value is always upper-cased), and the corresponding
+ * <value> is returned within a kmalloc()ed buffer, whose pointer is
+ * provided as the return value of this function.
+ * (The total number of bytes allocated is strlen(<value>)+1.)
+ *
+ * NULL is returned to indicate failure, which can occur for several reasons:
+ * - all <name>=<value> pairs have already been processed
+ * - bad parameter
+ * - parameter buffer ends prematurely (couldn't find an '=' or '\0' within
+ * the confines of the parameter buffer)
+ * - the <nam> buffer is not large enough to hold the <name> of the next
+ * parameter
+ */
+void *
+parser_param_get(PARSER_CONTEXT *ctx, char *nam, int namesize)
+{
+ u8 *pscan, *pnam = nam;
+ ulong nscan;
+ int value_length = -1, orig_value_length = -1;
+ void *value = NULL;
+ int i;
+ int closing_quote = 0;
+
+ if (!ctx)
+ return NULL;
+ pscan = ctx->curr;
+ nscan = ctx->bytes_remaining;
+ if (nscan == 0)
+ return NULL;
+ if (*pscan == '\0')
+ /* This is the normal return point after you have processed
+ * all of the <name>=<value> pairs in a syntactically-valid
+ * parameter buffer.
+ */
+ return NULL;
+
+ /* skip whitespace */
+ while (isspace(*pscan)) {
+ pscan++;
+ nscan--;
+ if (nscan == 0)
+ return NULL;
+ }
+
+ while (*pscan != ':') {
+ if (namesize <= 0) {
+ ERRDRV("%s - name too big", __func__);
+ return NULL;
+ }
+ *pnam = toupper(*pscan);
+ pnam++;
+ namesize--;
+ pscan++;
+ nscan--;
+ if (nscan == 0) {
+ ERRDRV("%s - unexpected end of input parsing name",
+ __func__);
+ return NULL;
+ }
+ }
+ if (namesize <= 0) {
+ ERRDRV("%s - name too big", __func__);
+ return NULL;
+ }
+ *pnam = '\0';
+ nam[string_length_no_trail(nam, strlen(nam))] = '\0';
+
+ /* point to char immediately after ":" in "<name>:<value>" */
+ pscan++;
+ nscan--;
+ /* skip whitespace */
+ while (isspace(*pscan)) {
+ pscan++;
+ nscan--;
+ if (nscan == 0) {
+ ERRDRV("%s - unexpected end of input looking for value",
+ __func__);
+ return NULL;
+ }
+ }
+ if (nscan == 0) {
+ ERRDRV("%s - unexpected end of input looking for value",
+ __func__);
+ return NULL;
+ }
+ if (*pscan == '\'' || *pscan == '"') {
+ closing_quote = *pscan;
+ pscan++;
+ nscan--;
+ if (nscan == 0) {
+ ERRDRV("%s - unexpected end of input after %c",
+ __func__, closing_quote);
+ return NULL;
+ }
+ }
+
+ /* look for a separator character, terminator character, or
+ * end of data
+ */
+ for (i = 0, value_length = -1; i < nscan; i++) {
+ if (closing_quote) {
+ if (pscan[i] == '\0') {
+ ERRDRV("%s - unexpected end of input parsing quoted value", __func__);
+ return NULL;
+ }
+ if (pscan[i] == closing_quote) {
+ value_length = i;
+ break;
+ }
+ } else
+ if (pscan[i] == ',' || pscan[i] == ';'
+ || pscan[i] == '\0') {
+ value_length = i;
+ break;
+ }
+ }
+ if (value_length < 0) {
+ if (closing_quote) {
+ ERRDRV("%s - unexpected end of input parsing quoted value", __func__);
+ return NULL;
+ }
+ value_length = nscan;
+ }
+ orig_value_length = value_length;
+ if (closing_quote == 0)
+ value_length = string_length_no_trail(pscan, orig_value_length);
+ value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
+ if (value == NULL)
+ return NULL;
+ memcpy(value, pscan, value_length);
+ ((u8 *) (value))[value_length] = '\0';
+
+ pscan += orig_value_length;
+ nscan -= orig_value_length;
+
+ /* skip past separator or closing quote */
+ if (nscan > 0) {
+ if (*pscan != '\0') {
+ pscan++;
+ nscan--;
+ }
+ }
+
+ if (closing_quote && (nscan > 0)) {
+ /* we still need to skip around the real separator if present */
+ /* first, skip whitespace */
+ while (isspace(*pscan)) {
+ pscan++;
+ nscan--;
+ if (nscan == 0)
+ break;
+ }
+ if (nscan > 0) {
+ if (*pscan == ',' || *pscan == ';') {
+ pscan++;
+ nscan--;
+ } else if (*pscan != '\0') {
+ ERRDRV("%s - missing separator after quoted string", __func__);
+ kfree(value);
+ value = NULL;
+ return NULL;
+ }
+ }
+ }
+ ctx->curr = pscan;
+ ctx->bytes_remaining = nscan;
+ return value;
+}
+
+void *
+parser_string_get(PARSER_CONTEXT *ctx)
+{
+ u8 *pscan;
+ ulong nscan;
+ int value_length = -1;
+ void *value = NULL;
+ int i;
+
+ if (!ctx)
+ return NULL;
+ pscan = ctx->curr;
+ nscan = ctx->bytes_remaining;
+ if (nscan == 0)
+ return NULL;
+ if (!pscan)
+ return NULL;
+ for (i = 0, value_length = -1; i < nscan; i++)
+ if (pscan[i] == '\0') {
+ value_length = i;
+ break;
+ }
+ if (value_length < 0) /* '\0' was not included in the length */
+ value_length = nscan;
+ value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
+ if (value == NULL)
+ return NULL;
+ if (value_length > 0)
+ memcpy(value, pscan, value_length);
+ ((u8 *) (value))[value_length] = '\0';
+ return value;
+}
diff --git a/drivers/staging/unisys/visorchipset/parser.h b/drivers/staging/unisys/visorchipset/parser.h
new file mode 100644
index 000000000000..a0cc50a533cd
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/parser.h
@@ -0,0 +1,45 @@
+/* parser.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __PARSER_H__
+#define __PARSER_H__
+
+#include "uniklog.h"
+#include "timskmod.h"
+#include "channel.h"
+
+typedef enum {
+ PARSERSTRING_INITIATOR,
+ PARSERSTRING_TARGET,
+ PARSERSTRING_CONNECTION,
+ PARSERSTRING_NAME,
+} PARSER_WHICH_STRING;
+
+typedef struct PARSER_CONTEXT_Tag PARSER_CONTEXT;
+
+PARSER_CONTEXT *parser_init(U64 addr, U32 bytes, BOOL isLocal, BOOL *tryAgain);
+PARSER_CONTEXT *parser_init_byteStream(U64 addr, U32 bytes, BOOL isLocal,
+ BOOL *tryAgain);
+void parser_param_start(PARSER_CONTEXT *ctx, PARSER_WHICH_STRING which_string);
+void *parser_param_get(PARSER_CONTEXT *ctx, char *nam, int namesize);
+void *parser_string_get(PARSER_CONTEXT *ctx);
+GUID parser_id_get(PARSER_CONTEXT *ctx);
+char *parser_simpleString_get(PARSER_CONTEXT *ctx);
+void *parser_byteStream_get(PARSER_CONTEXT *ctx, ulong *nbytes);
+void parser_done(PARSER_CONTEXT *ctx);
+
+#endif
diff --git a/drivers/staging/unisys/visorchipset/testing.h b/drivers/staging/unisys/visorchipset/testing.h
new file mode 100644
index 000000000000..a44f5556cb21
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/testing.h
@@ -0,0 +1,41 @@
+/* testing.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __VISORCHIPSET_TESTING_H__
+#define __VISORCHIPSET_TESTING_H__
+
+#define VISORCHIPSET_TEST_PROC
+#include "globals.h"
+#include "controlvmchannel.h"
+
+void test_produce_test_message(CONTROLVM_MESSAGE *msg, int isLocalTestAddr);
+BOOL test_consume_test_message(CONTROLVM_MESSAGE *msg);
+void test_manufacture_vnic_client_add(void *p);
+void test_manufacture_vnic_client_add_phys(HOSTADDRESS addr);
+void test_manufacture_preamble_messages(void);
+void test_manufacture_device_attach(ulong busNo, ulong devNo);
+void test_manufacture_device_add(ulong busNo, ulong devNo, GUID dataTypeGuid,
+ void *pChannel);
+void test_manufacture_add_bus(ulong busNo, ulong maxDevices,
+ GUID id, u8 *name, BOOL isServer);
+void test_manufacture_device_destroy(ulong busNo, ulong devNo);
+void test_manufacture_bus_destroy(ulong busNo);
+void test_manufacture_detach_externalPort(ulong switchNo, ulong externalPortNo);
+void test_manufacture_detach_internalPort(ulong switchNo, ulong internalPortNo);
+void test_cleanup(void);
+
+#endif
diff --git a/drivers/staging/unisys/visorchipset/visorchipset.h b/drivers/staging/unisys/visorchipset/visorchipset.h
new file mode 100644
index 000000000000..d4bf203cdfdf
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/visorchipset.h
@@ -0,0 +1,307 @@
+/* visorchipset.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __VISORCHIPSET_H__
+#define __VISORCHIPSET_H__
+
+#include "timskmod.h"
+#include "channel.h"
+#include "controlvmchannel.h"
+#include "parser.h"
+#include "procobjecttree.h"
+#include "vbusdeviceinfo.h"
+#include "vbushelper.h"
+
+/** Describes the state from the perspective of which controlvm messages have
+ * been received for a bus or device.
+ */
+typedef struct {
+ U32 created:1;
+ U32 attached:1;
+ U32 configured:1;
+ U32 running:1;
+ /* Add new fields above. */
+ /* Remaining bits in this 32-bit word are unused. */
+} VISORCHIPSET_STATE;
+
+typedef enum {
+ /** address is guest physical, but outside of the physical memory
+ * region that is controlled by the running OS (this is the normal
+ * address type for Supervisor channels)
+ */
+ ADDRTYPE_localPhysical,
+
+ /** address is guest physical, and withIN the confines of the
+ * physical memory controlled by the running OS.
+ */
+ ADDRTYPE_localTest,
+} VISORCHIPSET_ADDRESSTYPE;
+
+typedef enum {
+ CRASH_dev,
+ CRASH_bus,
+} CRASH_OBJ_TYPE;
+
+/** Attributes for a particular Supervisor channel.
+ */
+typedef struct {
+ VISORCHIPSET_ADDRESSTYPE addrType;
+ HOSTADDRESS channelAddr;
+ struct InterruptInfo intr;
+ U64 nChannelBytes;
+ GUID channelTypeGuid;
+ GUID channelInstGuid;
+
+} VISORCHIPSET_CHANNEL_INFO;
+
+/** Attributes for a particular Supervisor device.
+ * Any visorchipset client can query these attributes using
+ * visorchipset_get_client_device_info() or
+ * visorchipset_get_server_device_info().
+ */
+typedef struct {
+ struct list_head entry;
+ U32 busNo;
+ U32 devNo;
+ GUID devInstGuid;
+ VISORCHIPSET_STATE state;
+ VISORCHIPSET_CHANNEL_INFO chanInfo;
+ U32 Reserved1; /* CONTROLVM_ID */
+ U64 Reserved2;
+ U32 switchNo; /* when devState.attached==1 */
+ U32 internalPortNo; /* when devState.attached==1 */
+ CONTROLVM_MESSAGE_HEADER pendingMsgHdr; /* CONTROLVM_MESSAGE */
+ /** For private use by the bus driver */
+ void *bus_driver_context;
+
+} VISORCHIPSET_DEVICE_INFO;
+
+static inline VISORCHIPSET_DEVICE_INFO *
+finddevice(struct list_head *list, U32 busNo, U32 devNo)
+{
+ VISORCHIPSET_DEVICE_INFO *p;
+
+ list_for_each_entry(p, list, entry) {
+ if (p->busNo == busNo && p->devNo == devNo)
+ return p;
+ }
+ return NULL;
+}
+
+static inline void delbusdevices(struct list_head *list, U32 busNo)
+{
+ VISORCHIPSET_DEVICE_INFO *p;
+
+ list_for_each_entry(p, list, entry) {
+ if (p->busNo == busNo) {
+ list_del(&p->entry);
+ kfree(p);
+ }
+ }
+}
+
+/** Attributes for a particular Supervisor bus.
+ * (For a service partition acting as the server for buses/devices, there
+ * is a 1-to-1 relationship between busses and guest partitions.)
+ * Any visorchipset client can query these attributes using
+ * visorchipset_get_client_bus_info() or visorchipset_get_bus_info().
+ */
+typedef struct {
+ struct list_head entry;
+ U32 busNo;
+ VISORCHIPSET_STATE state;
+ VISORCHIPSET_CHANNEL_INFO chanInfo;
+ GUID partitionGuid;
+ U64 partitionHandle;
+ U8 *name; /* UTF8 */
+ U8 *description; /* UTF8 */
+ U64 Reserved1;
+ U32 Reserved2;
+ MYPROCOBJECT *procObject;
+ struct {
+ U32 server:1;
+ /* Add new fields above. */
+ /* Remaining bits in this 32-bit word are unused. */
+ } flags;
+ CONTROLVM_MESSAGE_HEADER pendingMsgHdr; /* CONTROLVM MsgHdr */
+ /** For private use by the bus driver */
+ void *bus_driver_context;
+ U64 devNo;
+
+} VISORCHIPSET_BUS_INFO;
+
+static inline VISORCHIPSET_BUS_INFO *
+findbus(struct list_head *list, U32 busNo)
+{
+ VISORCHIPSET_BUS_INFO *p;
+
+ list_for_each_entry(p, list, entry) {
+ if (p->busNo == busNo)
+ return p;
+ }
+ return NULL;
+}
+
+/** Attributes for a particular Supervisor switch.
+ */
+typedef struct {
+ U32 switchNo;
+ VISORCHIPSET_STATE state;
+ GUID switchTypeGuid;
+ U8 *authService1;
+ U8 *authService2;
+ U8 *authService3;
+ U8 *securityContext;
+ U64 Reserved;
+ U32 Reserved2; /* CONTROLVM_ID */
+ struct device dev;
+ BOOL dev_exists;
+ CONTROLVM_MESSAGE_HEADER pendingMsgHdr;
+
+} VISORCHIPSET_SWITCH_INFO;
+
+/** Attributes for a particular Supervisor external port, which is connected
+ * to a specific switch.
+ */
+typedef struct {
+ U32 switchNo;
+ U32 externalPortNo;
+ VISORCHIPSET_STATE state;
+ GUID networkZoneGuid;
+ int pdPort;
+ U8 *ip;
+ U8 *ipNetmask;
+ U8 *ipBroadcast;
+ U8 *ipNetwork;
+ U8 *ipGateway;
+ U8 *ipDNS;
+ U64 Reserved1;
+ U32 Reserved2; /* CONTROLVM_ID */
+ struct device dev;
+ BOOL dev_exists;
+ CONTROLVM_MESSAGE_HEADER pendingMsgHdr;
+
+} VISORCHIPSET_EXTERNALPORT_INFO;
+
+/** Attributes for a particular Supervisor internal port, which is how a
+ * device connects to a particular switch.
+ */
+typedef struct {
+ U32 switchNo;
+ U32 internalPortNo;
+ VISORCHIPSET_STATE state;
+ U32 busNo; /* valid only when state.attached == 1 */
+ U32 devNo; /* valid only when state.attached == 1 */
+ U64 Reserved1;
+ U32 Reserved2; /* CONTROLVM_ID */
+ CONTROLVM_MESSAGE_HEADER pendingMsgHdr;
+ MYPROCOBJECT *procObject;
+
+} VISORCHIPSET_INTERNALPORT_INFO;
+
+/* These functions will be called from within visorchipset when certain
+ * events happen. (The implementation of these functions is outside of
+ * visorchipset.)
+ */
+typedef struct {
+ void (*bus_create)(ulong busNo);
+ void (*bus_destroy)(ulong busNo);
+ void (*device_create)(ulong busNo, ulong devNo);
+ void (*device_destroy)(ulong busNo, ulong devNo);
+ void (*device_pause)(ulong busNo, ulong devNo);
+ void (*device_resume)(ulong busNo, ulong devNo);
+ int (*get_channel_info)(GUID typeGuid, ulong *minSize,
+ ulong *maxSize);
+} VISORCHIPSET_BUSDEV_NOTIFIERS;
+
+/* These functions live inside visorchipset, and will be called to indicate
+ * responses to specific events (by code outside of visorchipset).
+ * For now, the value for each response is simply either:
+ * 0 = it worked
+ * -1 = it failed
+ */
+typedef struct {
+ void (*bus_create)(ulong busNo, int response);
+ void (*bus_destroy)(ulong busNo, int response);
+ void (*device_create)(ulong busNo, ulong devNo, int response);
+ void (*device_destroy)(ulong busNo, ulong devNo, int response);
+ void (*device_pause)(ulong busNo, ulong devNo, int response);
+ void (*device_resume)(ulong busNo, ulong devNo, int response);
+} VISORCHIPSET_BUSDEV_RESPONDERS;
+
+/** Register functions (in the bus driver) to get called by visorchipset
+ * whenever a bus or device appears for which this service partition is
+ * to be the server for. visorchipset will fill in <responders>, to
+ * indicate functions the bus driver should call to indicate message
+ * responses.
+ */
+void
+visorchipset_register_busdev_client(VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers,
+ VISORCHIPSET_BUSDEV_RESPONDERS *responders,
+ ULTRA_VBUS_DEVICEINFO *driverInfo);
+
+/** Register functions (in the bus driver) to get called by visorchipset
+ * whenever a bus or device appears for which this service partition is
+ * to be the client for. visorchipset will fill in <responders>, to
+ * indicate functions the bus driver should call to indicate message
+ * responses.
+ */
+void
+visorchipset_register_busdev_server(VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers,
+ VISORCHIPSET_BUSDEV_RESPONDERS *responders,
+ ULTRA_VBUS_DEVICEINFO *driverInfo);
+
+typedef void (*SPARREPORTEVENT_COMPLETE_FUNC) (CONTROLVM_MESSAGE *msg,
+ int status);
+
+void visorchipset_device_pause_response(ulong busNo, ulong devNo, int response);
+
+BOOL visorchipset_get_bus_info(ulong busNo, VISORCHIPSET_BUS_INFO *busInfo);
+BOOL visorchipset_get_device_info(ulong busNo, ulong devNo,
+ VISORCHIPSET_DEVICE_INFO *devInfo);
+BOOL visorchipset_get_switch_info(ulong switchNo,
+ VISORCHIPSET_SWITCH_INFO *switchInfo);
+BOOL visorchipset_get_externalport_info(ulong switchNo, ulong externalPortNo,
+ VISORCHIPSET_EXTERNALPORT_INFO
+ *externalPortInfo);
+BOOL visorchipset_set_bus_context(ulong busNo, void *context);
+BOOL visorchipset_set_device_context(ulong busNo, ulong devNo, void *context);
+int visorchipset_chipset_ready(void);
+int visorchipset_chipset_selftest(void);
+int visorchipset_chipset_notready(void);
+void visorchipset_controlvm_respond_reportEvent(CONTROLVM_MESSAGE *msg,
+ void *payload);
+void visorchipset_save_message(CONTROLVM_MESSAGE *msg, CRASH_OBJ_TYPE type);
+void *visorchipset_cache_alloc(struct kmem_cache *pool,
+ BOOL ok_to_block, char *fn, int ln);
+void visorchipset_cache_free(struct kmem_cache *pool, void *p,
+ char *fn, int ln);
+
+#if defined(TRANSMITFILE_DEBUG) || defined(DEBUG)
+#define DBG_GETFILE_PAYLOAD(msg, controlvm_header) \
+ LOGINF(msg, \
+ (ulong)controlvm_header.PayloadVmOffset, \
+ (ulong)controlvm_header.PayloadMaxBytes)
+#define DBG_GETFILE(fmt, ...) LOGINF(fmt, ##__VA_ARGS__)
+#define DBG_PUTFILE(fmt, ...) LOGINF(fmt, ##__VA_ARGS__)
+#else
+#define DBG_GETFILE_PAYLOAD(msg, controlvm_header)
+#define DBG_GETFILE(fmt, ...)
+#define DBG_PUTFILE(fmt, ...)
+#endif
+
+#endif
diff --git a/drivers/staging/unisys/visorchipset/visorchipset_main.c b/drivers/staging/unisys/visorchipset/visorchipset_main.c
new file mode 100644
index 000000000000..8252ca14695d
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/visorchipset_main.c
@@ -0,0 +1,2945 @@
+/* visorchipset_main.c
+ *
+ * Copyright � 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#include "globals.h"
+#include "controlvm.h"
+#include "visorchipset.h"
+#include "procobjecttree.h"
+#include "visorchannel.h"
+#include "periodic_work.h"
+#include "testing.h"
+#include "file.h"
+#include "parser.h"
+#include "uniklog.h"
+#include "uisutils.h"
+#include "guidutils.h"
+#include "controlvmcompletionstatus.h"
+#include "guestlinuxdebug.h"
+#include "filexfer.h"
+
+#include <linux/nls.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+
+#define CURRENT_FILE_PC VISOR_CHIPSET_PC_visorchipset_main_c
+#define TEST_VNIC_PHYSITF "eth0" /* physical network itf for
+ * vnic loopback test */
+#define TEST_VNIC_SWITCHNO 1
+#define TEST_VNIC_BUSNO 9
+
+#define MAX_NAME_SIZE 128
+#define MAX_IP_SIZE 50
+#define MAXOUTSTANDINGCHANNELCOMMAND 256
+#define POLLJIFFIES_CONTROLVMCHANNEL_FAST 1
+#define POLLJIFFIES_CONTROLVMCHANNEL_SLOW 100
+
+/* When the controlvm channel is idle for at least MIN_IDLE_SECONDS,
+* we switch to slow polling mode. As soon as we get a controlvm
+* message, we switch back to fast polling mode.
+*/
+#define MIN_IDLE_SECONDS 10
+static ulong Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
+static ulong Most_recent_message_jiffies; /* when we got our last
+ * controlvm message */
+static inline char *
+NONULLSTR(char *s)
+{
+ if (s)
+ return s;
+ else
+ return "";
+}
+
+static int serverregistered;
+static int clientregistered;
+
+#define MAX_CHIPSET_EVENTS 2
+static U8 chipset_events[MAX_CHIPSET_EVENTS] = { 0, 0 };
+
+static struct delayed_work Periodic_controlvm_work;
+static struct workqueue_struct *Periodic_controlvm_workqueue;
+static DEFINE_SEMAPHORE(NotifierLock);
+
+typedef struct {
+ CONTROLVM_MESSAGE message;
+ unsigned int crc;
+} MESSAGE_ENVELOPE;
+
+static CONTROLVM_MESSAGE_HEADER g_DiagMsgHdr;
+static CONTROLVM_MESSAGE_HEADER g_ChipSetMsgHdr;
+static CONTROLVM_MESSAGE_HEADER g_DelDumpMsgHdr;
+static const GUID UltraDiagPoolChannelProtocolGuid =
+ ULTRA_DIAG_POOL_CHANNEL_PROTOCOL_GUID;
+/* 0xffffff is an invalid Bus/Device number */
+static ulong g_diagpoolBusNo = 0xffffff;
+static ulong g_diagpoolDevNo = 0xffffff;
+static CONTROLVM_MESSAGE_PACKET g_DeviceChangeStatePacket;
+
+/* Only VNIC and VHBA channels are sent to visorclientbus (aka
+ * "visorhackbus")
+ */
+#define FOR_VISORHACKBUS(channel_type_guid) \
+ ((memcmp(&channel_type_guid, &UltraVnicChannelProtocolGuid, \
+ sizeof(GUID)) == 0) || \
+ (memcmp(&channel_type_guid, &UltraVhbaChannelProtocolGuid, \
+ sizeof(GUID)) == 0))
+#define FOR_VISORBUS(channel_type_guid) (!(FOR_VISORHACKBUS(channel_type_guid)))
+
+#define is_diagpool_channel(channel_type_guid) \
+ (memcmp(&channel_type_guid, \
+ &UltraDiagPoolChannelProtocolGuid, sizeof(GUID)) == 0)
+
+typedef enum {
+ PARTPROP_invalid,
+ PARTPROP_name,
+ PARTPROP_description,
+ PARTPROP_handle,
+ PARTPROP_busNumber,
+ /* add new properties above, but don't forget to change
+ * InitPartitionProperties() and show_partition_property() also...
+ */
+ PARTPROP_last
+} PARTITION_property;
+static const char *PartitionTypeNames[] = { "partition", NULL };
+
+static char *PartitionPropertyNames[PARTPROP_last + 1];
+static void
+InitPartitionProperties(void)
+{
+ char **p = PartitionPropertyNames;
+ p[PARTPROP_invalid] = "";
+ p[PARTPROP_name] = "name";
+ p[PARTPROP_description] = "description";
+ p[PARTPROP_handle] = "handle";
+ p[PARTPROP_busNumber] = "busNumber";
+ p[PARTPROP_last] = NULL;
+}
+
+typedef enum {
+ CTLVMPROP_invalid,
+ CTLVMPROP_physAddr,
+ CTLVMPROP_controlChannelAddr,
+ CTLVMPROP_controlChannelBytes,
+ CTLVMPROP_sparBootPart,
+ CTLVMPROP_sparStoragePart,
+ CTLVMPROP_livedumpLength,
+ CTLVMPROP_livedumpCrc32,
+ /* add new properties above, but don't forget to change
+ * InitControlVmProperties() show_controlvm_property() also...
+ */
+ CTLVMPROP_last
+} CONTROLVM_property;
+
+static const char *ControlVmTypeNames[] = { "controlvm", NULL };
+
+static char *ControlVmPropertyNames[CTLVMPROP_last + 1];
+static void
+InitControlVmProperties(void)
+{
+ char **p = ControlVmPropertyNames;
+ p[CTLVMPROP_invalid] = "";
+ p[CTLVMPROP_physAddr] = "physAddr";
+ p[CTLVMPROP_controlChannelAddr] = "controlChannelAddr";
+ p[CTLVMPROP_controlChannelBytes] = "controlChannelBytes";
+ p[CTLVMPROP_sparBootPart] = "spar_boot_part";
+ p[CTLVMPROP_sparStoragePart] = "spar_storage_part";
+ p[CTLVMPROP_livedumpLength] = "livedumpLength";
+ p[CTLVMPROP_livedumpCrc32] = "livedumpCrc32";
+ p[CTLVMPROP_last] = NULL;
+}
+
+static MYPROCOBJECT *ControlVmObject;
+static MYPROCTYPE *PartitionType;
+static MYPROCTYPE *ControlVmType;
+
+#define VISORCHIPSET_DIAG_PROC_ENTRY_FN "diagdump"
+static struct proc_dir_entry *diag_proc_dir;
+
+#define VISORCHIPSET_CHIPSET_PROC_ENTRY_FN "chipsetready"
+static struct proc_dir_entry *chipset_proc_dir;
+
+#define VISORCHIPSET_PARAHOTPLUG_PROC_ENTRY_FN "parahotplug"
+static struct proc_dir_entry *parahotplug_proc_dir;
+
+static LIST_HEAD(BusInfoList);
+static LIST_HEAD(DevInfoList);
+
+static struct proc_dir_entry *ProcDir;
+static VISORCHANNEL *ControlVm_channel;
+
+static ssize_t visorchipset_proc_read_writeonly(struct file *file,
+ char __user *buf,
+ size_t len, loff_t *offset);
+static ssize_t proc_read_installer(struct file *file, char __user *buf,
+ size_t len, loff_t *offset);
+static ssize_t proc_write_installer(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos);
+static ssize_t proc_read_toolaction(struct file *file, char __user *buf,
+ size_t len, loff_t *offset);
+static ssize_t proc_write_toolaction(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos);
+static ssize_t proc_read_bootToTool(struct file *file, char __user *buf,
+ size_t len, loff_t *offset);
+static ssize_t proc_write_bootToTool(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos);
+static const struct file_operations proc_installer_fops = {
+ .read = proc_read_installer,
+ .write = proc_write_installer,
+};
+
+static const struct file_operations proc_toolaction_fops = {
+ .read = proc_read_toolaction,
+ .write = proc_write_toolaction,
+};
+
+static const struct file_operations proc_bootToTool_fops = {
+ .read = proc_read_bootToTool,
+ .write = proc_write_bootToTool,
+};
+
+typedef struct {
+ U8 __iomem *ptr; /* pointer to base address of payload pool */
+ U64 offset; /* offset from beginning of controlvm
+ * channel to beginning of payload * pool */
+ U32 bytes; /* number of bytes in payload pool */
+} CONTROLVM_PAYLOAD_INFO;
+
+/* Manages the request payload in the controlvm channel */
+static CONTROLVM_PAYLOAD_INFO ControlVm_payload_info;
+
+static pCHANNEL_HEADER Test_Vnic_channel;
+
+typedef struct {
+ CONTROLVM_MESSAGE_HEADER Dumpcapture_header;
+ CONTROLVM_MESSAGE_HEADER Gettextdump_header;
+ CONTROLVM_MESSAGE_HEADER Dumpcomplete_header;
+ BOOL Gettextdump_outstanding;
+ u32 crc32;
+ ulong length;
+ atomic_t buffers_in_use;
+ ulong destination;
+} LIVEDUMP_INFO;
+/* Manages the info for a CONTROLVM_DUMP_CAPTURESTATE /
+ * CONTROLVM_DUMP_GETTEXTDUMP / CONTROLVM_DUMP_COMPLETE conversation.
+ */
+static LIVEDUMP_INFO LiveDump_info;
+
+/* The following globals are used to handle the scenario where we are unable to
+ * offload the payload from a controlvm message due to memory requirements. In
+ * this scenario, we simply stash the controlvm message, then attempt to
+ * process it again the next time controlvm_periodic_work() runs.
+ */
+static CONTROLVM_MESSAGE ControlVm_Pending_Msg;
+static BOOL ControlVm_Pending_Msg_Valid = FALSE;
+
+/* Pool of struct putfile_buffer_entry, for keeping track of pending (incoming)
+ * TRANSMIT_FILE PutFile payloads.
+ */
+static struct kmem_cache *Putfile_buffer_list_pool;
+static const char Putfile_buffer_list_pool_name[] =
+ "controlvm_putfile_buffer_list_pool";
+
+/* This identifies a data buffer that has been received via a controlvm messages
+ * in a remote --> local CONTROLVM_TRANSMIT_FILE conversation.
+ */
+struct putfile_buffer_entry {
+ struct list_head next; /* putfile_buffer_entry list */
+ PARSER_CONTEXT *parser_ctx; /* points to buffer containing input data */
+};
+
+/* List of struct putfile_request *, via next_putfile_request member.
+ * Each entry in this list identifies an outstanding TRANSMIT_FILE
+ * conversation.
+ */
+static LIST_HEAD(Putfile_request_list);
+
+/* This describes a buffer and its current state of transfer (e.g., how many
+ * bytes have already been supplied as putfile data, and how many bytes are
+ * remaining) for a putfile_request.
+ */
+struct putfile_active_buffer {
+ /* a payload from a controlvm message, containing a file data buffer */
+ PARSER_CONTEXT *parser_ctx;
+ /* points within data area of parser_ctx to next byte of data */
+ u8 *pnext;
+ /* # bytes left from <pnext> to the end of this data buffer */
+ size_t bytes_remaining;
+};
+
+#define PUTFILE_REQUEST_SIG 0x0906101302281211
+/* This identifies a single remote --> local CONTROLVM_TRANSMIT_FILE
+ * conversation. Structs of this type are dynamically linked into
+ * <Putfile_request_list>.
+ */
+struct putfile_request {
+ u64 sig; /* PUTFILE_REQUEST_SIG */
+
+ /* header from original TransmitFile request */
+ CONTROLVM_MESSAGE_HEADER controlvm_header;
+ u64 file_request_number; /* from original TransmitFile request */
+
+ /* link to next struct putfile_request */
+ struct list_head next_putfile_request;
+
+ /* most-recent sequence number supplied via a controlvm message */
+ u64 data_sequence_number;
+
+ /* head of putfile_buffer_entry list, which describes the data to be
+ * supplied as putfile data;
+ * - this list is added to when controlvm messages come in that supply
+ * file data
+ * - this list is removed from via the hotplug program that is actually
+ * consuming these buffers to write as file data */
+ struct list_head input_buffer_list;
+ spinlock_t req_list_lock; /* lock for input_buffer_list */
+
+ /* waiters for input_buffer_list to go non-empty */
+ wait_queue_head_t input_buffer_wq;
+
+ /* data not yet read within current putfile_buffer_entry */
+ struct putfile_active_buffer active_buf;
+
+ /* <0 = failed, 0 = in-progress, >0 = successful; */
+ /* note that this must be set with req_list_lock, and if you set <0, */
+ /* it is your responsibility to also free up all of the other objects */
+ /* in this struct (like input_buffer_list, active_buf.parser_ctx) */
+ /* before releasing the lock */
+ int completion_status;
+};
+
+static atomic_t Visorchipset_cache_buffers_in_use = ATOMIC_INIT(0);
+
+struct parahotplug_request {
+ struct list_head list;
+ int id;
+ unsigned long expiration;
+ CONTROLVM_MESSAGE msg;
+};
+
+static LIST_HEAD(Parahotplug_request_list);
+static DEFINE_SPINLOCK(Parahotplug_request_list_lock); /* lock for above */
+static void parahotplug_process_list(void);
+
+/* Manages the info for a CONTROLVM_DUMP_CAPTURESTATE /
+ * CONTROLVM_REPORTEVENT.
+ */
+static VISORCHIPSET_BUSDEV_NOTIFIERS BusDev_Server_Notifiers;
+static VISORCHIPSET_BUSDEV_NOTIFIERS BusDev_Client_Notifiers;
+
+static void bus_create_response(ulong busNo, int response);
+static void bus_destroy_response(ulong busNo, int response);
+static void device_create_response(ulong busNo, ulong devNo, int response);
+static void device_destroy_response(ulong busNo, ulong devNo, int response);
+static void device_resume_response(ulong busNo, ulong devNo, int response);
+
+static VISORCHIPSET_BUSDEV_RESPONDERS BusDev_Responders = {
+ .bus_create = bus_create_response,
+ .bus_destroy = bus_destroy_response,
+ .device_create = device_create_response,
+ .device_destroy = device_destroy_response,
+ .device_pause = visorchipset_device_pause_response,
+ .device_resume = device_resume_response,
+};
+
+/* info for /dev/visorchipset */
+static dev_t MajorDev = -1; /**< indicates major num for device */
+
+/* /sys/devices/platform/visorchipset */
+static struct platform_device Visorchipset_platform_device = {
+ .name = "visorchipset",
+ .id = -1,
+};
+
+/* Function prototypes */
+static void controlvm_respond(CONTROLVM_MESSAGE_HEADER *msgHdr, int response);
+static void controlvm_respond_chipset_init(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ int response,
+ ULTRA_CHIPSET_FEATURE features);
+static void controlvm_respond_physdev_changestate(CONTROLVM_MESSAGE_HEADER *
+ msgHdr, int response,
+ ULTRA_SEGMENT_STATE state);
+
+static void
+show_partition_property(struct seq_file *f, void *ctx, int property)
+{
+ VISORCHIPSET_BUS_INFO *info = (VISORCHIPSET_BUS_INFO *) (ctx);
+
+ switch (property) {
+ case PARTPROP_name:
+ seq_printf(f, "%s\n", NONULLSTR(info->name));
+ break;
+ case PARTPROP_description:
+ seq_printf(f, "%s\n", NONULLSTR(info->description));
+ break;
+ case PARTPROP_handle:
+ seq_printf(f, "0x%-16.16Lx\n", info->partitionHandle);
+ break;
+ case PARTPROP_busNumber:
+ seq_printf(f, "%d\n", info->busNo);
+ break;
+ default:
+ seq_printf(f, "(%d??)\n", property);
+ break;
+ }
+}
+
+static void
+show_controlvm_property(struct seq_file *f, void *ctx, int property)
+{
+ /* Note: ctx is not needed since we only have 1 controlvm channel */
+ switch (property) {
+ case CTLVMPROP_physAddr:
+ if (ControlVm_channel == NULL)
+ seq_puts(f, "0x0\n");
+ else
+ seq_printf(f, "0x%-16.16Lx\n",
+ visorchannel_get_physaddr
+ (ControlVm_channel));
+ break;
+ case CTLVMPROP_controlChannelAddr:
+ if (ControlVm_channel == NULL)
+ seq_puts(f, "0x0\n");
+ else {
+ GUEST_PHYSICAL_ADDRESS addr = 0;
+ visorchannel_read(ControlVm_channel,
+ offsetof
+ (ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ gpControlChannel), &addr,
+ sizeof(addr));
+ seq_printf(f, "0x%-16.16Lx\n", (u64) (addr));
+ }
+ break;
+ case CTLVMPROP_controlChannelBytes:
+ if (ControlVm_channel == NULL)
+ seq_puts(f, "0x0\n");
+ else {
+ U32 bytes = 0;
+ visorchannel_read(ControlVm_channel,
+ offsetof
+ (ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ ControlChannelBytes), &bytes,
+ sizeof(bytes));
+ seq_printf(f, "%lu\n", (ulong) (bytes));
+ }
+ break;
+ case CTLVMPROP_sparBootPart:
+ seq_puts(f, "0:0:0:0/1\n");
+ break;
+ case CTLVMPROP_sparStoragePart:
+ seq_puts(f, "0:0:0:0/2\n");
+ break;
+ case CTLVMPROP_livedumpLength:
+ seq_printf(f, "%lu\n", LiveDump_info.length);
+ break;
+ case CTLVMPROP_livedumpCrc32:
+ seq_printf(f, "%lu\n", (ulong) LiveDump_info.crc32);
+ break;
+ default:
+ seq_printf(f, "(%d??)\n", property);
+ break;
+ }
+}
+
+static void
+proc_Init(void)
+{
+ if (ProcDir == NULL) {
+ ProcDir = proc_mkdir(MYDRVNAME, NULL);
+ if (ProcDir == NULL) {
+ LOGERR("failed to create /proc directory %s",
+ MYDRVNAME);
+ POSTCODE_LINUX_2(CHIPSET_INIT_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ }
+ }
+}
+
+static void
+proc_DeInit(void)
+{
+ if (ProcDir != NULL)
+ remove_proc_entry(MYDRVNAME, NULL);
+ ProcDir = NULL;
+}
+
+#if 0
+static void
+testUnicode(void)
+{
+ wchar_t unicodeString[] = { 'a', 'b', 'c', 0 };
+ char s[sizeof(unicodeString) * NLS_MAX_CHARSET_SIZE];
+ wchar_t unicode2[99];
+
+ /* NOTE: Either due to a bug, or feature I don't understand, the
+ * kernel utf8_mbstowcs() and utf_wcstombs() do NOT copy the
+ * trailed NUL byte!! REALLY!!!!! Arrrrgggghhhhh
+ */
+
+ LOGINF("sizeof(wchar_t) = %d", sizeof(wchar_t));
+ LOGINF("utf8_wcstombs=%d",
+ chrs = utf8_wcstombs(s, unicodeString, sizeof(s)));
+ if (chrs >= 0)
+ s[chrs] = '\0'; /* GRRRRRRRR */
+ LOGINF("s='%s'", s);
+ LOGINF("utf8_mbstowcs=%d", chrs = utf8_mbstowcs(unicode2, s, 100));
+ if (chrs >= 0)
+ unicode2[chrs] = 0; /* GRRRRRRRR */
+ if (memcmp(unicodeString, unicode2, sizeof(unicodeString)) == 0)
+ LOGINF("strings match... good");
+ else
+ LOGINF("strings did not match!!");
+}
+#endif
+
+static void
+busInfo_clear(void *v)
+{
+ VISORCHIPSET_BUS_INFO *p = (VISORCHIPSET_BUS_INFO *) (v);
+
+ if (p->procObject) {
+ visor_proc_DestroyObject(p->procObject);
+ p->procObject = NULL;
+ }
+ kfree(p->name);
+ p->name = NULL;
+
+ kfree(p->description);
+ p->description = NULL;
+
+ p->state.created = 0;
+ memset(p, 0, sizeof(VISORCHIPSET_BUS_INFO));
+}
+
+static void
+devInfo_clear(void *v)
+{
+ VISORCHIPSET_DEVICE_INFO *p = (VISORCHIPSET_DEVICE_INFO *) (v);
+ p->state.created = 0;
+ memset(p, 0, sizeof(VISORCHIPSET_DEVICE_INFO));
+}
+
+static U8
+check_chipset_events(void)
+{
+ int i;
+ U8 send_msg = 1;
+ /* Check events to determine if response should be sent */
+ for (i = 0; i < MAX_CHIPSET_EVENTS; i++)
+ send_msg &= chipset_events[i];
+ return send_msg;
+}
+
+static void
+clear_chipset_events(void)
+{
+ int i;
+ /* Clear chipset_events */
+ for (i = 0; i < MAX_CHIPSET_EVENTS; i++)
+ chipset_events[i] = 0;
+}
+
+void
+visorchipset_register_busdev_server(VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers,
+ VISORCHIPSET_BUSDEV_RESPONDERS *responders,
+ ULTRA_VBUS_DEVICEINFO *driverInfo)
+{
+ LOCKSEM_UNINTERRUPTIBLE(&NotifierLock);
+ if (notifiers == NULL) {
+ memset(&BusDev_Server_Notifiers, 0,
+ sizeof(BusDev_Server_Notifiers));
+ serverregistered = 0; /* clear flag */
+ } else {
+ BusDev_Server_Notifiers = *notifiers;
+ serverregistered = 1; /* set flag */
+ }
+ if (responders)
+ *responders = BusDev_Responders;
+ if (driverInfo)
+ BusDeviceInfo_Init(driverInfo, "chipset", "visorchipset",
+ VERSION, NULL, __DATE__, __TIME__);
+
+ UNLOCKSEM(&NotifierLock);
+}
+EXPORT_SYMBOL_GPL(visorchipset_register_busdev_server);
+
+void
+visorchipset_register_busdev_client(VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers,
+ VISORCHIPSET_BUSDEV_RESPONDERS *responders,
+ ULTRA_VBUS_DEVICEINFO *driverInfo)
+{
+ LOCKSEM_UNINTERRUPTIBLE(&NotifierLock);
+ if (notifiers == NULL) {
+ memset(&BusDev_Client_Notifiers, 0,
+ sizeof(BusDev_Client_Notifiers));
+ clientregistered = 0; /* clear flag */
+ } else {
+ BusDev_Client_Notifiers = *notifiers;
+ clientregistered = 1; /* set flag */
+ }
+ if (responders)
+ *responders = BusDev_Responders;
+ if (driverInfo)
+ BusDeviceInfo_Init(driverInfo, "chipset(bolts)", "visorchipset",
+ VERSION, NULL, __DATE__, __TIME__);
+ UNLOCKSEM(&NotifierLock);
+}
+EXPORT_SYMBOL_GPL(visorchipset_register_busdev_client);
+
+static void
+cleanup_controlvm_structures(void)
+{
+ VISORCHIPSET_BUS_INFO *bi;
+ VISORCHIPSET_DEVICE_INFO *di;
+
+ list_for_each_entry(bi, &BusInfoList, entry) {
+ busInfo_clear(bi);
+ list_del(&bi->entry);
+ kfree(bi);
+ }
+
+ list_for_each_entry(di, &DevInfoList, entry) {
+ devInfo_clear(di);
+ list_del(&di->entry);
+ kfree(di);
+ }
+}
+
+static void
+chipset_init(CONTROLVM_MESSAGE *inmsg)
+{
+ static int chipset_inited;
+ ULTRA_CHIPSET_FEATURE features = 0;
+ int rc = CONTROLVM_RESP_SUCCESS;
+
+ POSTCODE_LINUX_2(CHIPSET_INIT_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+ if (chipset_inited) {
+ LOGERR("CONTROLVM_CHIPSET_INIT Failed: Already Done.");
+ rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ goto Away;
+ }
+ chipset_inited = 1;
+ POSTCODE_LINUX_2(CHIPSET_INIT_EXIT_PC, POSTCODE_SEVERITY_INFO);
+
+ /* Set features to indicate we support parahotplug (if Command
+ * also supports it). */
+ features =
+ inmsg->cmd.initChipset.
+ features & ULTRA_CHIPSET_FEATURE_PARA_HOTPLUG;
+
+ /* Set the "reply" bit so Command knows this is a
+ * features-aware driver. */
+ features |= ULTRA_CHIPSET_FEATURE_REPLY;
+
+Away:
+ if (rc < 0)
+ cleanup_controlvm_structures();
+ if (inmsg->hdr.Flags.responseExpected)
+ controlvm_respond_chipset_init(&inmsg->hdr, rc, features);
+}
+
+static void
+controlvm_init_response(CONTROLVM_MESSAGE *msg,
+ CONTROLVM_MESSAGE_HEADER *msgHdr, int response)
+{
+ memset(msg, 0, sizeof(CONTROLVM_MESSAGE));
+ memcpy(&msg->hdr, msgHdr, sizeof(CONTROLVM_MESSAGE_HEADER));
+ msg->hdr.PayloadBytes = 0;
+ msg->hdr.PayloadVmOffset = 0;
+ msg->hdr.PayloadMaxBytes = 0;
+ if (response < 0) {
+ msg->hdr.Flags.failed = 1;
+ msg->hdr.CompletionStatus = (U32) (-response);
+ }
+}
+
+static void
+controlvm_respond(CONTROLVM_MESSAGE_HEADER *msgHdr, int response)
+{
+ CONTROLVM_MESSAGE outmsg;
+ if (!ControlVm_channel)
+ return;
+ controlvm_init_response(&outmsg, msgHdr, response);
+ /* For DiagPool channel DEVICE_CHANGESTATE, we need to send
+ * back the deviceChangeState structure in the packet. */
+ if (msgHdr->Id == CONTROLVM_DEVICE_CHANGESTATE
+ && g_DeviceChangeStatePacket.deviceChangeState.busNo ==
+ g_diagpoolBusNo
+ && g_DeviceChangeStatePacket.deviceChangeState.devNo ==
+ g_diagpoolDevNo)
+ outmsg.cmd = g_DeviceChangeStatePacket;
+ if (outmsg.hdr.Flags.testMessage == 1) {
+ LOGINF("%s controlvm_msg=0x%x response=%d for test message",
+ __func__, outmsg.hdr.Id, response);
+ return;
+ }
+ if (!visorchannel_signalinsert(ControlVm_channel,
+ CONTROLVM_QUEUE_REQUEST, &outmsg)) {
+ LOGERR("signalinsert failed!");
+ return;
+ }
+}
+
+static void
+controlvm_respond_chipset_init(CONTROLVM_MESSAGE_HEADER *msgHdr, int response,
+ ULTRA_CHIPSET_FEATURE features)
+{
+ CONTROLVM_MESSAGE outmsg;
+ if (!ControlVm_channel)
+ return;
+ controlvm_init_response(&outmsg, msgHdr, response);
+ outmsg.cmd.initChipset.features = features;
+ if (!visorchannel_signalinsert(ControlVm_channel,
+ CONTROLVM_QUEUE_REQUEST, &outmsg)) {
+ LOGERR("signalinsert failed!");
+ return;
+ }
+}
+
+static void
+controlvm_respond_physdev_changestate(CONTROLVM_MESSAGE_HEADER *msgHdr,
+ int response, ULTRA_SEGMENT_STATE state)
+{
+ CONTROLVM_MESSAGE outmsg;
+ if (!ControlVm_channel)
+ return;
+ controlvm_init_response(&outmsg, msgHdr, response);
+ outmsg.cmd.deviceChangeState.state = state;
+ outmsg.cmd.deviceChangeState.flags.physicalDevice = 1;
+ if (!visorchannel_signalinsert(ControlVm_channel,
+ CONTROLVM_QUEUE_REQUEST, &outmsg)) {
+ LOGERR("signalinsert failed!");
+ return;
+ }
+}
+
+void
+visorchipset_save_message(CONTROLVM_MESSAGE *msg, CRASH_OBJ_TYPE type)
+{
+ U32 localSavedCrashMsgOffset;
+ U16 localSavedCrashMsgCount;
+
+ /* get saved message count */
+ if (visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ SavedCrashMsgCount),
+ &localSavedCrashMsgCount, sizeof(U16)) < 0) {
+ LOGERR("failed to get Saved Message Count");
+ POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ if (localSavedCrashMsgCount != CONTROLVM_CRASHMSG_MAX) {
+ LOGERR("Saved Message Count incorrect %d",
+ localSavedCrashMsgCount);
+ POSTCODE_LINUX_3(CRASH_DEV_COUNT_FAILURE_PC,
+ localSavedCrashMsgCount,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* get saved crash message offset */
+ if (visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ SavedCrashMsgOffset),
+ &localSavedCrashMsgOffset, sizeof(U32)) < 0) {
+ LOGERR("failed to get Saved Message Offset");
+ POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ if (type == CRASH_bus) {
+ if (visorchannel_write(ControlVm_channel,
+ localSavedCrashMsgOffset,
+ msg, sizeof(CONTROLVM_MESSAGE)) < 0) {
+ LOGERR("SAVE_MSG_BUS_FAILURE: Failed to write CrashCreateBusMsg!");
+ POSTCODE_LINUX_2(SAVE_MSG_BUS_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+ } else {
+ if (visorchannel_write(ControlVm_channel,
+ localSavedCrashMsgOffset +
+ sizeof(CONTROLVM_MESSAGE), msg,
+ sizeof(CONTROLVM_MESSAGE)) < 0) {
+ LOGERR("SAVE_MSG_DEV_FAILURE: Failed to write CrashCreateDevMsg!");
+ POSTCODE_LINUX_2(SAVE_MSG_DEV_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(visorchipset_save_message);
+
+static void
+bus_responder(CONTROLVM_ID cmdId, ulong busNo, int response)
+{
+ VISORCHIPSET_BUS_INFO *p = NULL;
+ BOOL need_clear = FALSE;
+
+ p = findbus(&BusInfoList, busNo);
+ if (!p) {
+ LOGERR("internal error busNo=%lu", busNo);
+ return;
+ }
+ if (response < 0) {
+ if ((cmdId == CONTROLVM_BUS_CREATE) &&
+ (response != (-CONTROLVM_RESP_ERROR_ALREADY_DONE)))
+ /* undo the row we just created... */
+ delbusdevices(&DevInfoList, busNo);
+ } else {
+ if (cmdId == CONTROLVM_BUS_CREATE)
+ p->state.created = 1;
+ if (cmdId == CONTROLVM_BUS_DESTROY)
+ need_clear = TRUE;
+ }
+
+ if (p->pendingMsgHdr.Id == CONTROLVM_INVALID) {
+ LOGERR("bus_responder no pending msg");
+ return; /* no controlvm response needed */
+ }
+ if (p->pendingMsgHdr.Id != (U32) cmdId) {
+ LOGERR("expected=%d, found=%d", cmdId, p->pendingMsgHdr.Id);
+ return;
+ }
+ controlvm_respond(&p->pendingMsgHdr, response);
+ p->pendingMsgHdr.Id = CONTROLVM_INVALID;
+ if (need_clear) {
+ busInfo_clear(p);
+ delbusdevices(&DevInfoList, busNo);
+ }
+}
+
+static void
+device_changestate_responder(CONTROLVM_ID cmdId,
+ ulong busNo, ulong devNo, int response,
+ ULTRA_SEGMENT_STATE responseState)
+{
+ VISORCHIPSET_DEVICE_INFO *p = NULL;
+ CONTROLVM_MESSAGE outmsg;
+
+ if (!ControlVm_channel)
+ return;
+
+ p = finddevice(&DevInfoList, busNo, devNo);
+ if (!p) {
+ LOGERR("internal error; busNo=%lu, devNo=%lu", busNo, devNo);
+ return;
+ }
+ if (p->pendingMsgHdr.Id == CONTROLVM_INVALID) {
+ LOGERR("device_responder no pending msg");
+ return; /* no controlvm response needed */
+ }
+ if (p->pendingMsgHdr.Id != cmdId) {
+ LOGERR("expected=%d, found=%d", cmdId, p->pendingMsgHdr.Id);
+ return;
+ }
+
+ controlvm_init_response(&outmsg, &p->pendingMsgHdr, response);
+
+ outmsg.cmd.deviceChangeState.busNo = busNo;
+ outmsg.cmd.deviceChangeState.devNo = devNo;
+ outmsg.cmd.deviceChangeState.state = responseState;
+
+ if (!visorchannel_signalinsert(ControlVm_channel,
+ CONTROLVM_QUEUE_REQUEST, &outmsg)) {
+ LOGERR("signalinsert failed!");
+ return;
+ }
+
+ p->pendingMsgHdr.Id = CONTROLVM_INVALID;
+}
+
+static void
+device_responder(CONTROLVM_ID cmdId, ulong busNo, ulong devNo, int response)
+{
+ VISORCHIPSET_DEVICE_INFO *p = NULL;
+ BOOL need_clear = FALSE;
+
+ p = finddevice(&DevInfoList, busNo, devNo);
+ if (!p) {
+ LOGERR("internal error; busNo=%lu, devNo=%lu", busNo, devNo);
+ return;
+ }
+ if (response >= 0) {
+ if (cmdId == CONTROLVM_DEVICE_CREATE)
+ p->state.created = 1;
+ if (cmdId == CONTROLVM_DEVICE_DESTROY)
+ need_clear = TRUE;
+ }
+
+ if (p->pendingMsgHdr.Id == CONTROLVM_INVALID) {
+ LOGERR("device_responder no pending msg");
+ return; /* no controlvm response needed */
+ }
+ if (p->pendingMsgHdr.Id != (U32) cmdId) {
+ LOGERR("expected=%d, found=%d", cmdId, p->pendingMsgHdr.Id);
+ return;
+ }
+ controlvm_respond(&p->pendingMsgHdr, response);
+ p->pendingMsgHdr.Id = CONTROLVM_INVALID;
+ if (need_clear)
+ devInfo_clear(p);
+}
+
+static void
+bus_epilog(U32 busNo,
+ U32 cmd, CONTROLVM_MESSAGE_HEADER *msgHdr,
+ int response, BOOL needResponse)
+{
+ BOOL notified = FALSE;
+
+ VISORCHIPSET_BUS_INFO *pBusInfo = findbus(&BusInfoList, busNo);
+
+ if (!pBusInfo) {
+ LOGERR("HUH? bad busNo=%d", busNo);
+ return;
+ }
+ if (needResponse) {
+ memcpy(&pBusInfo->pendingMsgHdr, msgHdr,
+ sizeof(CONTROLVM_MESSAGE_HEADER));
+ } else
+ pBusInfo->pendingMsgHdr.Id = CONTROLVM_INVALID;
+
+ LOCKSEM_UNINTERRUPTIBLE(&NotifierLock);
+ if (response == CONTROLVM_RESP_SUCCESS) {
+ switch (cmd) {
+ case CONTROLVM_BUS_CREATE:
+ /* We can't tell from the bus_create
+ * information which of our 2 bus flavors the
+ * devices on this bus will ultimately end up.
+ * FORTUNATELY, it turns out it is harmless to
+ * send the bus_create to both of them. We can
+ * narrow things down a little bit, though,
+ * because we know: - BusDev_Server can handle
+ * either server or client devices
+ * - BusDev_Client can handle ONLY client
+ * devices */
+ if (BusDev_Server_Notifiers.bus_create) {
+ (*BusDev_Server_Notifiers.bus_create) (busNo);
+ notified = TRUE;
+ }
+ if ((!pBusInfo->flags.server) /*client */ &&
+ BusDev_Client_Notifiers.bus_create) {
+ (*BusDev_Client_Notifiers.bus_create) (busNo);
+ notified = TRUE;
+ }
+ break;
+ case CONTROLVM_BUS_DESTROY:
+ if (BusDev_Server_Notifiers.bus_destroy) {
+ (*BusDev_Server_Notifiers.bus_destroy) (busNo);
+ notified = TRUE;
+ }
+ if ((!pBusInfo->flags.server) /*client */ &&
+ BusDev_Client_Notifiers.bus_destroy) {
+ (*BusDev_Client_Notifiers.bus_destroy) (busNo);
+ notified = TRUE;
+ }
+ break;
+ }
+ }
+ if (notified)
+ /* The callback function just called above is responsible
+ * for calling the appropriate VISORCHIPSET_BUSDEV_RESPONDERS
+ * function, which will call bus_responder()
+ */
+ ;
+ else
+ bus_responder(cmd, busNo, response);
+ UNLOCKSEM(&NotifierLock);
+}
+
+static void
+device_epilog(U32 busNo, U32 devNo, ULTRA_SEGMENT_STATE state, U32 cmd,
+ CONTROLVM_MESSAGE_HEADER *msgHdr, int response,
+ BOOL needResponse, BOOL for_visorbus)
+{
+ VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers = NULL;
+ BOOL notified = FALSE;
+
+ VISORCHIPSET_DEVICE_INFO *pDevInfo =
+ finddevice(&DevInfoList, busNo, devNo);
+ char *envp[] = {
+ "SPARSP_DIAGPOOL_PAUSED_STATE = 1",
+ NULL
+ };
+
+ if (!pDevInfo) {
+ LOGERR("HUH? bad busNo=%d, devNo=%d", busNo, devNo);
+ return;
+ }
+ if (for_visorbus)
+ notifiers = &BusDev_Server_Notifiers;
+ else
+ notifiers = &BusDev_Client_Notifiers;
+ if (needResponse) {
+ memcpy(&pDevInfo->pendingMsgHdr, msgHdr,
+ sizeof(CONTROLVM_MESSAGE_HEADER));
+ } else
+ pDevInfo->pendingMsgHdr.Id = CONTROLVM_INVALID;
+
+ LOCKSEM_UNINTERRUPTIBLE(&NotifierLock);
+ if (response >= 0) {
+ switch (cmd) {
+ case CONTROLVM_DEVICE_CREATE:
+ if (notifiers->device_create) {
+ (*notifiers->device_create) (busNo, devNo);
+ notified = TRUE;
+ }
+ break;
+ case CONTROLVM_DEVICE_CHANGESTATE:
+ /* ServerReady / ServerRunning / SegmentStateRunning */
+ if (state.Alive == SegmentStateRunning.Alive &&
+ state.Operating == SegmentStateRunning.Operating) {
+ if (notifiers->device_resume) {
+ (*notifiers->device_resume) (busNo,
+ devNo);
+ notified = TRUE;
+ }
+ }
+ /* ServerNotReady / ServerLost / SegmentStateStandby */
+ else if (state.Alive == SegmentStateStandby.Alive &&
+ state.Operating ==
+ SegmentStateStandby.Operating) {
+ /* technically this is standby case
+ * where server is lost
+ */
+ if (notifiers->device_pause) {
+ (*notifiers->device_pause) (busNo,
+ devNo);
+ notified = TRUE;
+ }
+ } else if (state.Alive == SegmentStatePaused.Alive &&
+ state.Operating ==
+ SegmentStatePaused.Operating) {
+ /* this is lite pause where channel is
+ * still valid just 'pause' of it
+ */
+ if (busNo == g_diagpoolBusNo
+ && devNo == g_diagpoolDevNo) {
+ LOGINF("DEVICE_CHANGESTATE(DiagpoolChannel busNo=%d devNo=%d is pausing...)",
+ busNo, devNo);
+ /* this will trigger the
+ * diag_shutdown.sh script in
+ * the visorchipset hotplug */
+ kobject_uevent_env
+ (&Visorchipset_platform_device.dev.
+ kobj, KOBJ_ONLINE, envp);
+ }
+ }
+ break;
+ case CONTROLVM_DEVICE_DESTROY:
+ if (notifiers->device_destroy) {
+ (*notifiers->device_destroy) (busNo, devNo);
+ notified = TRUE;
+ }
+ break;
+ }
+ }
+ if (notified)
+ /* The callback function just called above is responsible
+ * for calling the appropriate VISORCHIPSET_BUSDEV_RESPONDERS
+ * function, which will call device_responder()
+ */
+ ;
+ else
+ device_responder(cmd, busNo, devNo, response);
+ UNLOCKSEM(&NotifierLock);
+}
+
+static void
+bus_create(CONTROLVM_MESSAGE *inmsg)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd;
+ ulong busNo = cmd->createBus.busNo;
+ int rc = CONTROLVM_RESP_SUCCESS;
+ VISORCHIPSET_BUS_INFO *pBusInfo = NULL;
+
+
+ pBusInfo = findbus(&BusInfoList, busNo);
+ if (pBusInfo && (pBusInfo->state.created == 1)) {
+ LOGERR("CONTROLVM_BUS_CREATE Failed: bus %lu already exists",
+ busNo);
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ goto Away;
+ }
+ pBusInfo = kzalloc(sizeof(VISORCHIPSET_BUS_INFO), GFP_KERNEL);
+ if (pBusInfo == NULL) {
+ LOGERR("CONTROLVM_BUS_CREATE Failed: bus %lu kzalloc failed",
+ busNo);
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
+ goto Away;
+ }
+
+ INIT_LIST_HEAD(&pBusInfo->entry);
+ pBusInfo->busNo = busNo;
+ pBusInfo->devNo = cmd->createBus.deviceCount;
+
+ POSTCODE_LINUX_3(BUS_CREATE_ENTRY_PC, busNo, POSTCODE_SEVERITY_INFO);
+
+ if (inmsg->hdr.Flags.testMessage == 1)
+ pBusInfo->chanInfo.addrType = ADDRTYPE_localTest;
+ else
+ pBusInfo->chanInfo.addrType = ADDRTYPE_localPhysical;
+
+ pBusInfo->flags.server = inmsg->hdr.Flags.server;
+ pBusInfo->chanInfo.channelAddr = cmd->createBus.channelAddr;
+ pBusInfo->chanInfo.nChannelBytes = cmd->createBus.channelBytes;
+ pBusInfo->chanInfo.channelTypeGuid = cmd->createBus.busDataTypeGuid;
+ pBusInfo->chanInfo.channelInstGuid = cmd->createBus.busInstGuid;
+
+ list_add(&pBusInfo->entry, &BusInfoList);
+
+ POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, busNo, POSTCODE_SEVERITY_INFO);
+
+Away:
+ bus_epilog(busNo, CONTROLVM_BUS_CREATE, &inmsg->hdr,
+ rc, inmsg->hdr.Flags.responseExpected == 1);
+}
+
+static void
+bus_destroy(CONTROLVM_MESSAGE *inmsg)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd;
+ ulong busNo = cmd->destroyBus.busNo;
+ VISORCHIPSET_BUS_INFO *pBusInfo;
+ int rc = CONTROLVM_RESP_SUCCESS;
+
+ pBusInfo = findbus(&BusInfoList, busNo);
+ if (!pBusInfo) {
+ LOGERR("CONTROLVM_BUS_DESTROY Failed: bus %lu invalid", busNo);
+ rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
+ goto Away;
+ }
+ if (pBusInfo->state.created == 0) {
+ LOGERR("CONTROLVM_BUS_DESTROY Failed: bus %lu already destroyed",
+ busNo);
+ rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ goto Away;
+ }
+
+Away:
+ bus_epilog(busNo, CONTROLVM_BUS_DESTROY, &inmsg->hdr,
+ rc, inmsg->hdr.Flags.responseExpected == 1);
+}
+
+static void
+bus_configure(CONTROLVM_MESSAGE *inmsg, PARSER_CONTEXT *parser_ctx)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd;
+ ulong busNo = cmd->configureBus.busNo;
+ VISORCHIPSET_BUS_INFO *pBusInfo = NULL;
+ int rc = CONTROLVM_RESP_SUCCESS;
+ char s[99];
+
+ busNo = cmd->configureBus.busNo;
+ POSTCODE_LINUX_3(BUS_CONFIGURE_ENTRY_PC, busNo, POSTCODE_SEVERITY_INFO);
+
+ pBusInfo = findbus(&BusInfoList, busNo);
+ if (!pBusInfo) {
+ LOGERR("CONTROLVM_BUS_CONFIGURE Failed: bus %lu invalid",
+ busNo);
+ POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
+ goto Away;
+ }
+ if (pBusInfo->state.created == 0) {
+ LOGERR("CONTROLVM_BUS_CONFIGURE Failed: Invalid bus %lu - not created yet",
+ busNo);
+ POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
+ goto Away;
+ }
+ /* TBD - add this check to other commands also... */
+ if (pBusInfo->pendingMsgHdr.Id != CONTROLVM_INVALID) {
+ LOGERR("CONTROLVM_BUS_CONFIGURE Failed: bus %lu MsgId=%u outstanding",
+ busNo, (uint) pBusInfo->pendingMsgHdr.Id);
+ POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT;
+ goto Away;
+ }
+
+ pBusInfo->partitionHandle = cmd->configureBus.guestHandle;
+ pBusInfo->partitionGuid = parser_id_get(parser_ctx);
+ parser_param_start(parser_ctx, PARSERSTRING_NAME);
+ pBusInfo->name = parser_string_get(parser_ctx);
+
+ visorchannel_GUID_id(&pBusInfo->partitionGuid, s);
+ pBusInfo->procObject =
+ visor_proc_CreateObject(PartitionType, s, (void *) (pBusInfo));
+ if (pBusInfo->procObject == NULL) {
+ LOGERR("CONTROLVM_BUS_CONFIGURE Failed: busNo=%lu failed to create /proc entry",
+ busNo);
+ POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, busNo,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
+ goto Away;
+ }
+ POSTCODE_LINUX_3(BUS_CONFIGURE_EXIT_PC, busNo, POSTCODE_SEVERITY_INFO);
+Away:
+ bus_epilog(busNo, CONTROLVM_BUS_CONFIGURE, &inmsg->hdr,
+ rc, inmsg->hdr.Flags.responseExpected == 1);
+}
+
+static void
+my_device_create(CONTROLVM_MESSAGE *inmsg)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd;
+ ulong busNo = cmd->createDevice.busNo;
+ ulong devNo = cmd->createDevice.devNo;
+ VISORCHIPSET_DEVICE_INFO *pDevInfo = NULL;
+ VISORCHIPSET_BUS_INFO *pBusInfo = NULL;
+ int rc = CONTROLVM_RESP_SUCCESS;
+
+ pDevInfo = finddevice(&DevInfoList, busNo, devNo);
+ if (pDevInfo && (pDevInfo->state.created == 1)) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: busNo=%lu, devNo=%lu already exists",
+ busNo, devNo);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ goto Away;
+ }
+ pBusInfo = findbus(&BusInfoList, busNo);
+ if (!pBusInfo) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: Invalid bus %lu - out of range",
+ busNo);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
+ goto Away;
+ }
+ if (pBusInfo->state.created == 0) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: Invalid bus %lu - not created yet",
+ busNo);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
+ goto Away;
+ }
+ pDevInfo = kzalloc(sizeof(VISORCHIPSET_DEVICE_INFO), GFP_KERNEL);
+ if (pDevInfo == NULL) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: busNo=%lu, devNo=%lu kmaloc failed",
+ busNo, devNo);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
+ goto Away;
+ }
+
+ INIT_LIST_HEAD(&pDevInfo->entry);
+ pDevInfo->busNo = busNo;
+ pDevInfo->devNo = devNo;
+ pDevInfo->devInstGuid = cmd->createDevice.devInstGuid;
+ POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, devNo, busNo,
+ POSTCODE_SEVERITY_INFO);
+
+ if (inmsg->hdr.Flags.testMessage == 1)
+ pDevInfo->chanInfo.addrType = ADDRTYPE_localTest;
+ else
+ pDevInfo->chanInfo.addrType = ADDRTYPE_localPhysical;
+ pDevInfo->chanInfo.channelAddr = cmd->createDevice.channelAddr;
+ pDevInfo->chanInfo.nChannelBytes = cmd->createDevice.channelBytes;
+ pDevInfo->chanInfo.channelTypeGuid = cmd->createDevice.dataTypeGuid;
+ pDevInfo->chanInfo.intr = cmd->createDevice.intr;
+ list_add(&pDevInfo->entry, &DevInfoList);
+ POSTCODE_LINUX_4(DEVICE_CREATE_EXIT_PC, devNo, busNo,
+ POSTCODE_SEVERITY_INFO);
+Away:
+ /* get the bus and devNo for DiagPool channel */
+ if (is_diagpool_channel(pDevInfo->chanInfo.channelTypeGuid)) {
+ g_diagpoolBusNo = busNo;
+ g_diagpoolDevNo = devNo;
+ LOGINF("CONTROLVM_DEVICE_CREATE for DiagPool channel: busNo=%lu, devNo=%lu",
+ g_diagpoolBusNo, g_diagpoolDevNo);
+ }
+ device_epilog(busNo, devNo, SegmentStateRunning,
+ CONTROLVM_DEVICE_CREATE, &inmsg->hdr, rc,
+ inmsg->hdr.Flags.responseExpected == 1,
+ FOR_VISORBUS(pDevInfo->chanInfo.channelTypeGuid));
+}
+
+static void
+my_device_changestate(CONTROLVM_MESSAGE *inmsg)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd;
+ ulong busNo = cmd->deviceChangeState.busNo;
+ ulong devNo = cmd->deviceChangeState.devNo;
+ ULTRA_SEGMENT_STATE state = cmd->deviceChangeState.state;
+ VISORCHIPSET_DEVICE_INFO *pDevInfo = NULL;
+ int rc = CONTROLVM_RESP_SUCCESS;
+
+ pDevInfo = finddevice(&DevInfoList, busNo, devNo);
+ if (!pDevInfo) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE Failed: busNo=%lu, devNo=%lu invalid (doesn't exist)",
+ busNo, devNo);
+ POSTCODE_LINUX_4(DEVICE_CHANGESTATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
+ goto Away;
+ }
+ if (pDevInfo->state.created == 0) {
+ LOGERR("CONTROLVM_DEVICE_CHANGESTATE Failed: busNo=%lu, devNo=%lu invalid (not created)",
+ busNo, devNo);
+ POSTCODE_LINUX_4(DEVICE_CHANGESTATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
+ }
+Away:
+ if ((rc >= CONTROLVM_RESP_SUCCESS) && pDevInfo)
+ device_epilog(busNo, devNo, state, CONTROLVM_DEVICE_CHANGESTATE,
+ &inmsg->hdr, rc,
+ inmsg->hdr.Flags.responseExpected == 1,
+ FOR_VISORBUS(pDevInfo->chanInfo.channelTypeGuid));
+}
+
+static void
+my_device_destroy(CONTROLVM_MESSAGE *inmsg)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd;
+ ulong busNo = cmd->destroyDevice.busNo;
+ ulong devNo = cmd->destroyDevice.devNo;
+ VISORCHIPSET_DEVICE_INFO *pDevInfo = NULL;
+ int rc = CONTROLVM_RESP_SUCCESS;
+
+ pDevInfo = finddevice(&DevInfoList, busNo, devNo);
+ if (!pDevInfo) {
+ LOGERR("CONTROLVM_DEVICE_DESTROY Failed: busNo=%lu, devNo=%lu invalid",
+ busNo, devNo);
+ rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
+ goto Away;
+ }
+ if (pDevInfo->state.created == 0) {
+ LOGERR("CONTROLVM_DEVICE_DESTROY Failed: busNo=%lu, devNo=%lu already destroyed",
+ busNo, devNo);
+ rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ }
+
+Away:
+ if ((rc >= CONTROLVM_RESP_SUCCESS) && pDevInfo)
+ device_epilog(busNo, devNo, SegmentStateRunning,
+ CONTROLVM_DEVICE_DESTROY, &inmsg->hdr, rc,
+ inmsg->hdr.Flags.responseExpected == 1,
+ FOR_VISORBUS(pDevInfo->chanInfo.channelTypeGuid));
+}
+
+/* When provided with the physical address of the controlvm channel
+ * (phys_addr), the offset to the payload area we need to manage
+ * (offset), and the size of this payload area (bytes), fills in the
+ * CONTROLVM_PAYLOAD_INFO struct. Returns TRUE for success or FALSE
+ * for failure.
+ */
+static int
+initialize_controlvm_payload_info(HOSTADDRESS phys_addr, U64 offset, U32 bytes,
+ CONTROLVM_PAYLOAD_INFO *info)
+{
+ U8 __iomem *payload = NULL;
+ int rc = CONTROLVM_RESP_SUCCESS;
+
+ if (info == NULL) {
+ LOGERR("HUH ? CONTROLVM_PAYLOAD_INIT Failed : Programmer check at %s:%d",
+ __FILE__, __LINE__);
+ rc = -CONTROLVM_RESP_ERROR_PAYLOAD_INVALID;
+ goto Away;
+ }
+ memset(info, 0, sizeof(CONTROLVM_PAYLOAD_INFO));
+ if ((offset == 0) || (bytes == 0)) {
+ LOGERR("CONTROLVM_PAYLOAD_INIT Failed: RequestPayloadOffset=%llu RequestPayloadBytes=%llu!",
+ (u64) offset, (u64) bytes);
+ rc = -CONTROLVM_RESP_ERROR_PAYLOAD_INVALID;
+ goto Away;
+ }
+ payload = ioremap_cache(phys_addr + offset, bytes);
+ if (payload == NULL) {
+ LOGERR("CONTROLVM_PAYLOAD_INIT Failed: ioremap_cache %llu for %llu bytes failed",
+ (u64) offset, (u64) bytes);
+ rc = -CONTROLVM_RESP_ERROR_IOREMAP_FAILED;
+ goto Away;
+ }
+
+ info->offset = offset;
+ info->bytes = bytes;
+ info->ptr = payload;
+ LOGINF("offset=%llu, bytes=%lu, ptr=%p",
+ (u64) (info->offset), (ulong) (info->bytes), info->ptr);
+
+Away:
+ if (rc < 0) {
+ if (payload != NULL) {
+ iounmap(payload);
+ payload = NULL;
+ }
+ }
+ return rc;
+}
+
+static void
+destroy_controlvm_payload_info(CONTROLVM_PAYLOAD_INFO *info)
+{
+ if (info->ptr != NULL) {
+ iounmap(info->ptr);
+ info->ptr = NULL;
+ }
+ memset(info, 0, sizeof(CONTROLVM_PAYLOAD_INFO));
+}
+
+static void
+initialize_controlvm_payload(void)
+{
+ HOSTADDRESS phys_addr = visorchannel_get_physaddr(ControlVm_channel);
+ U64 payloadOffset = 0;
+ U32 payloadBytes = 0;
+ if (visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ RequestPayloadOffset),
+ &payloadOffset, sizeof(payloadOffset)) < 0) {
+ LOGERR("CONTROLVM_PAYLOAD_INIT Failed to read controlvm channel!");
+ POSTCODE_LINUX_2(CONTROLVM_INIT_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+ if (visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ RequestPayloadBytes),
+ &payloadBytes, sizeof(payloadBytes)) < 0) {
+ LOGERR("CONTROLVM_PAYLOAD_INIT Failed to read controlvm channel!");
+ POSTCODE_LINUX_2(CONTROLVM_INIT_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+ initialize_controlvm_payload_info(phys_addr,
+ payloadOffset, payloadBytes,
+ &ControlVm_payload_info);
+}
+
+/* Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset.
+ * Returns CONTROLVM_RESP_xxx code.
+ */
+int
+visorchipset_chipset_ready(void)
+{
+ kobject_uevent(&Visorchipset_platform_device.dev.kobj, KOBJ_ONLINE);
+ return CONTROLVM_RESP_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(visorchipset_chipset_ready);
+
+int
+visorchipset_chipset_selftest(void)
+{
+ char env_selftest[20];
+ char *envp[] = { env_selftest, NULL };
+ sprintf(env_selftest, "SPARSP_SELFTEST=%d", 1);
+ kobject_uevent_env(&Visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
+ envp);
+ return CONTROLVM_RESP_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(visorchipset_chipset_selftest);
+
+/* Send ACTION=offline for DEVPATH=/sys/devices/platform/visorchipset.
+ * Returns CONTROLVM_RESP_xxx code.
+ */
+int
+visorchipset_chipset_notready(void)
+{
+ kobject_uevent(&Visorchipset_platform_device.dev.kobj, KOBJ_OFFLINE);
+ return CONTROLVM_RESP_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(visorchipset_chipset_notready);
+
+static void
+chipset_ready(CONTROLVM_MESSAGE_HEADER *msgHdr)
+{
+ int rc = visorchipset_chipset_ready();
+ if (rc != CONTROLVM_RESP_SUCCESS)
+ rc = -rc;
+ if (msgHdr->Flags.responseExpected && !visorchipset_holdchipsetready)
+ controlvm_respond(msgHdr, rc);
+ if (msgHdr->Flags.responseExpected && visorchipset_holdchipsetready) {
+ /* Send CHIPSET_READY response when all modules have been loaded
+ * and disks mounted for the partition
+ */
+ g_ChipSetMsgHdr = *msgHdr;
+ LOGINF("Holding CHIPSET_READY response");
+ }
+}
+
+static void
+chipset_selftest(CONTROLVM_MESSAGE_HEADER *msgHdr)
+{
+ int rc = visorchipset_chipset_selftest();
+ if (rc != CONTROLVM_RESP_SUCCESS)
+ rc = -rc;
+ if (msgHdr->Flags.responseExpected)
+ controlvm_respond(msgHdr, rc);
+}
+
+static void
+chipset_notready(CONTROLVM_MESSAGE_HEADER *msgHdr)
+{
+ int rc = visorchipset_chipset_notready();
+ if (rc != CONTROLVM_RESP_SUCCESS)
+ rc = -rc;
+ if (msgHdr->Flags.responseExpected)
+ controlvm_respond(msgHdr, rc);
+}
+
+/* This is your "one-stop" shop for grabbing the next message from the
+ * CONTROLVM_QUEUE_EVENT queue in the controlvm channel.
+ */
+static BOOL
+read_controlvm_event(CONTROLVM_MESSAGE *msg)
+{
+ if (visorchannel_signalremove(ControlVm_channel,
+ CONTROLVM_QUEUE_EVENT, msg)) {
+ /* got a message */
+ if (msg->hdr.Flags.testMessage == 1) {
+ LOGERR("ignoring bad CONTROLVM_QUEUE_EVENT msg with controlvm_msg_id=0x%x because Flags.testMessage is nonsensical (=1)", msg->hdr.Id);
+ return FALSE;
+ } else
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * The general parahotplug flow works as follows. The visorchipset
+ * driver receives a DEVICE_CHANGESTATE message from Command
+ * specifying a physical device to enable or disable. The CONTROLVM
+ * message handler calls parahotplug_process_message, which then adds
+ * the message to a global list and kicks off a udev event which
+ * causes a user level script to enable or disable the specified
+ * device. The udev script then writes to
+ * /proc/visorchipset/parahotplug, which causes parahotplug_proc_write
+ * to get called, at which point the appropriate CONTROLVM message is
+ * retrieved from the list and responded to.
+ */
+
+#define PARAHOTPLUG_TIMEOUT_MS 2000
+
+/*
+ * Generate unique int to match an outstanding CONTROLVM message with a
+ * udev script /proc response
+ */
+static int
+parahotplug_next_id(void)
+{
+ static atomic_t id = ATOMIC_INIT(0);
+ return atomic_inc_return(&id);
+}
+
+/*
+ * Returns the time (in jiffies) when a CONTROLVM message on the list
+ * should expire -- PARAHOTPLUG_TIMEOUT_MS in the future
+ */
+static unsigned long
+parahotplug_next_expiration(void)
+{
+ return jiffies + PARAHOTPLUG_TIMEOUT_MS * HZ / 1000;
+}
+
+/*
+ * Create a parahotplug_request, which is basically a wrapper for a
+ * CONTROLVM_MESSAGE that we can stick on a list
+ */
+static struct parahotplug_request *
+parahotplug_request_create(CONTROLVM_MESSAGE *msg)
+{
+ struct parahotplug_request *req =
+ kmalloc(sizeof(struct parahotplug_request),
+ GFP_KERNEL|__GFP_NORETRY);
+ if (req == NULL)
+ return NULL;
+
+ req->id = parahotplug_next_id();
+ req->expiration = parahotplug_next_expiration();
+ req->msg = *msg;
+
+ return req;
+}
+
+/*
+ * Free a parahotplug_request.
+ */
+static void
+parahotplug_request_destroy(struct parahotplug_request *req)
+{
+ kfree(req);
+}
+
+/*
+ * Cause uevent to run the user level script to do the disable/enable
+ * specified in (the CONTROLVM message in) the specified
+ * parahotplug_request
+ */
+static void
+parahotplug_request_kickoff(struct parahotplug_request *req)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &req->msg.cmd;
+ char env_cmd[40], env_id[40], env_state[40], env_bus[40], env_dev[40],
+ env_func[40];
+ char *envp[] = {
+ env_cmd, env_id, env_state, env_bus, env_dev, env_func, NULL
+ };
+
+ sprintf(env_cmd, "SPAR_PARAHOTPLUG=1");
+ sprintf(env_id, "SPAR_PARAHOTPLUG_ID=%d", req->id);
+ sprintf(env_state, "SPAR_PARAHOTPLUG_STATE=%d",
+ cmd->deviceChangeState.state.Active);
+ sprintf(env_bus, "SPAR_PARAHOTPLUG_BUS=%d",
+ cmd->deviceChangeState.busNo);
+ sprintf(env_dev, "SPAR_PARAHOTPLUG_DEVICE=%d",
+ cmd->deviceChangeState.devNo >> 3);
+ sprintf(env_func, "SPAR_PARAHOTPLUG_FUNCTION=%d",
+ cmd->deviceChangeState.devNo & 0x7);
+
+ LOGINF("parahotplug_request_kickoff: state=%d, bdf=%d/%d/%d, id=%u\n",
+ cmd->deviceChangeState.state.Active,
+ cmd->deviceChangeState.busNo, cmd->deviceChangeState.devNo >> 3,
+ cmd->deviceChangeState.devNo & 7, req->id);
+
+ kobject_uevent_env(&Visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
+ envp);
+}
+
+/*
+ * Remove any request from the list that's been on there too long and
+ * respond with an error.
+ */
+static void
+parahotplug_process_list(void)
+{
+ struct list_head *pos = NULL;
+ struct list_head *tmp = NULL;
+
+ spin_lock(&Parahotplug_request_list_lock);
+
+ list_for_each_safe(pos, tmp, &Parahotplug_request_list) {
+ struct parahotplug_request *req =
+ list_entry(pos, struct parahotplug_request, list);
+ if (time_after_eq(jiffies, req->expiration)) {
+ list_del(pos);
+ if (req->msg.hdr.Flags.responseExpected)
+ controlvm_respond_physdev_changestate(
+ &req->msg.hdr,
+ CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT,
+ req->msg.cmd.deviceChangeState.state);
+ parahotplug_request_destroy(req);
+ }
+ }
+
+ spin_unlock(&Parahotplug_request_list_lock);
+}
+
+/*
+ * Called from the /proc handler, which means the user script has
+ * finished the enable/disable. Find the matching identifier, and
+ * respond to the CONTROLVM message with success.
+ */
+static int
+parahotplug_request_complete(int id, U16 active)
+{
+ struct list_head *pos = NULL;
+ struct list_head *tmp = NULL;
+
+ spin_lock(&Parahotplug_request_list_lock);
+
+ /* Look for a request matching "id". */
+ list_for_each_safe(pos, tmp, &Parahotplug_request_list) {
+ struct parahotplug_request *req =
+ list_entry(pos, struct parahotplug_request, list);
+ if (req->id == id) {
+ /* Found a match. Remove it from the list and
+ * respond.
+ */
+ list_del(pos);
+ spin_unlock(&Parahotplug_request_list_lock);
+ req->msg.cmd.deviceChangeState.state.Active = active;
+ if (req->msg.hdr.Flags.responseExpected)
+ controlvm_respond_physdev_changestate(
+ &req->msg.hdr, CONTROLVM_RESP_SUCCESS,
+ req->msg.cmd.deviceChangeState.state);
+ parahotplug_request_destroy(req);
+ return 0;
+ }
+ }
+
+ spin_unlock(&Parahotplug_request_list_lock);
+ return -1;
+}
+
+/*
+ * Enables or disables a PCI device by kicking off a udev script
+ */
+static void
+parahotplug_process_message(CONTROLVM_MESSAGE *inmsg)
+{
+ struct parahotplug_request *req;
+
+ req = parahotplug_request_create(inmsg);
+
+ if (req == NULL) {
+ LOGERR("parahotplug_process_message: couldn't allocate request");
+ return;
+ }
+
+ if (inmsg->cmd.deviceChangeState.state.Active) {
+ /* For enable messages, just respond with success
+ * right away. This is a bit of a hack, but there are
+ * issues with the early enable messages we get (with
+ * either the udev script not detecting that the device
+ * is up, or not getting called at all). Fortunately
+ * the messages that get lost don't matter anyway, as
+ * devices are automatically enabled at
+ * initialization.
+ */
+ parahotplug_request_kickoff(req);
+ controlvm_respond_physdev_changestate(&inmsg->hdr,
+ CONTROLVM_RESP_SUCCESS,
+ inmsg->cmd.
+ deviceChangeState.state);
+ parahotplug_request_destroy(req);
+ } else {
+ /* For disable messages, add the request to the
+ * request list before kicking off the udev script. It
+ * won't get responded to until the script has
+ * indicated it's done.
+ */
+ spin_lock(&Parahotplug_request_list_lock);
+ list_add_tail(&(req->list), &Parahotplug_request_list);
+ spin_unlock(&Parahotplug_request_list_lock);
+
+ parahotplug_request_kickoff(req);
+ }
+}
+
+/*
+ * Gets called when the udev script writes to
+ * /proc/visorchipset/parahotplug. Expects input in the form of "<id>
+ * <active>" where <id> is the identifier passed to the script that
+ * matches a request on the request list, and <active> is 0 or 1
+ * indicating whether the device is now enabled or not.
+ */
+static ssize_t
+parahotplug_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char buf[64];
+ uint id;
+ ushort active;
+
+ if (count > sizeof(buf) - 1) {
+ LOGERR("parahotplug_proc_write: count (%d) exceeds size of buffer (%d)",
+ (int) count, (int) sizeof(buf));
+ return -EINVAL;
+ }
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("parahotplug_proc_write: copy_from_user failed");
+ return -EFAULT;
+ }
+ buf[count] = '\0';
+
+ if (sscanf(buf, "%u %hu", &id, &active) != 2) {
+ id = 0;
+ active = 0;
+ }
+
+ if (active != 1 && active != 0) {
+ LOGERR("parahotplug_proc_write: invalid active field");
+ return -EINVAL;
+ }
+
+ parahotplug_request_complete((int) id, (U16) active);
+
+ return count;
+}
+
+static const struct file_operations parahotplug_proc_fops = {
+ .owner = THIS_MODULE,
+ .read = visorchipset_proc_read_writeonly,
+ .write = parahotplug_proc_write,
+};
+
+/* Process a controlvm message.
+ * Return result:
+ * FALSE - this function will return FALSE only in the case where the
+ * controlvm message was NOT processed, but processing must be
+ * retried before reading the next controlvm message; a
+ * scenario where this can occur is when we need to throttle
+ * the allocation of memory in which to copy out controlvm
+ * payload data
+ * TRUE - processing of the controlvm message completed,
+ * either successfully or with an error.
+ */
+static BOOL
+handle_command(CONTROLVM_MESSAGE inmsg, HOSTADDRESS channel_addr)
+{
+ CONTROLVM_MESSAGE_PACKET *cmd = &inmsg.cmd;
+ U64 parametersAddr = 0;
+ U32 parametersBytes = 0;
+ PARSER_CONTEXT *parser_ctx = NULL;
+ BOOL isLocalAddr = FALSE;
+ CONTROLVM_MESSAGE ackmsg;
+
+ /* create parsing context if necessary */
+ isLocalAddr = (inmsg.hdr.Flags.testMessage == 1);
+ if (channel_addr == 0) {
+ LOGERR("HUH? channel_addr is 0!");
+ return TRUE;
+ }
+ parametersAddr = channel_addr + inmsg.hdr.PayloadVmOffset;
+ parametersBytes = inmsg.hdr.PayloadBytes;
+
+ /* Parameter and channel addresses within test messages actually lie
+ * within our OS-controlled memory. We need to know that, because it
+ * makes a difference in how we compute the virtual address.
+ */
+ if (parametersAddr != 0 && parametersBytes != 0) {
+ BOOL retry = FALSE;
+ parser_ctx =
+ parser_init_byteStream(parametersAddr, parametersBytes,
+ isLocalAddr, &retry);
+ if (!parser_ctx) {
+ if (retry) {
+ LOGWRN("throttling to copy payload");
+ return FALSE;
+ }
+ LOGWRN("parsing failed");
+ LOGWRN("inmsg.hdr.Id=0x%lx", (ulong) inmsg.hdr.Id);
+ LOGWRN("parametersAddr=0x%llx", (u64) parametersAddr);
+ LOGWRN("parametersBytes=%lu", (ulong) parametersBytes);
+ LOGWRN("isLocalAddr=%d", isLocalAddr);
+ }
+ }
+
+ if (!isLocalAddr) {
+ controlvm_init_response(&ackmsg, &inmsg.hdr,
+ CONTROLVM_RESP_SUCCESS);
+ if ((ControlVm_channel)
+ &&
+ (!visorchannel_signalinsert
+ (ControlVm_channel, CONTROLVM_QUEUE_ACK, &ackmsg)))
+ LOGWRN("failed to send ACK failed");
+ }
+ switch (inmsg.hdr.Id) {
+ case CONTROLVM_CHIPSET_INIT:
+ LOGINF("CHIPSET_INIT(#busses=%lu,#switches=%lu)",
+ (ulong) inmsg.cmd.initChipset.busCount,
+ (ulong) inmsg.cmd.initChipset.switchCount);
+ chipset_init(&inmsg);
+ break;
+ case CONTROLVM_BUS_CREATE:
+ LOGINF("BUS_CREATE(%lu,#devs=%lu)",
+ (ulong) cmd->createBus.busNo,
+ (ulong) cmd->createBus.deviceCount);
+ bus_create(&inmsg);
+ break;
+ case CONTROLVM_BUS_DESTROY:
+ LOGINF("BUS_DESTROY(%lu)", (ulong) cmd->destroyBus.busNo);
+ bus_destroy(&inmsg);
+ break;
+ case CONTROLVM_BUS_CONFIGURE:
+ LOGINF("BUS_CONFIGURE(%lu)", (ulong) cmd->configureBus.busNo);
+ bus_configure(&inmsg, parser_ctx);
+ break;
+ case CONTROLVM_DEVICE_CREATE:
+ LOGINF("DEVICE_CREATE(%lu,%lu)",
+ (ulong) cmd->createDevice.busNo,
+ (ulong) cmd->createDevice.devNo);
+ my_device_create(&inmsg);
+ break;
+ case CONTROLVM_DEVICE_CHANGESTATE:
+ if (cmd->deviceChangeState.flags.physicalDevice) {
+ LOGINF("DEVICE_CHANGESTATE for physical device (%lu,%lu, active=%lu)",
+ (ulong) cmd->deviceChangeState.busNo,
+ (ulong) cmd->deviceChangeState.devNo,
+ (ulong) cmd->deviceChangeState.state.Active);
+ parahotplug_process_message(&inmsg);
+ } else {
+ LOGINF("DEVICE_CHANGESTATE for virtual device (%lu,%lu, state.Alive=0x%lx)",
+ (ulong) cmd->deviceChangeState.busNo,
+ (ulong) cmd->deviceChangeState.devNo,
+ (ulong) cmd->deviceChangeState.state.Alive);
+ /* save the hdr and cmd structures for later use */
+ /* when sending back the response to Command */
+ my_device_changestate(&inmsg);
+ g_DiagMsgHdr = inmsg.hdr;
+ g_DeviceChangeStatePacket = inmsg.cmd;
+ break;
+ }
+ break;
+ case CONTROLVM_DEVICE_DESTROY:
+ LOGINF("DEVICE_DESTROY(%lu,%lu)",
+ (ulong) cmd->destroyDevice.busNo,
+ (ulong) cmd->destroyDevice.devNo);
+ my_device_destroy(&inmsg);
+ break;
+ case CONTROLVM_DEVICE_CONFIGURE:
+ LOGINF("DEVICE_CONFIGURE(%lu,%lu)",
+ (ulong) cmd->configureDevice.busNo,
+ (ulong) cmd->configureDevice.devNo);
+ /* no op for now, just send a respond that we passed */
+ if (inmsg.hdr.Flags.responseExpected)
+ controlvm_respond(&inmsg.hdr, CONTROLVM_RESP_SUCCESS);
+ break;
+ case CONTROLVM_CHIPSET_READY:
+ LOGINF("CHIPSET_READY");
+ chipset_ready(&inmsg.hdr);
+ break;
+ case CONTROLVM_CHIPSET_SELFTEST:
+ LOGINF("CHIPSET_SELFTEST");
+ chipset_selftest(&inmsg.hdr);
+ break;
+ case CONTROLVM_CHIPSET_STOP:
+ LOGINF("CHIPSET_STOP");
+ chipset_notready(&inmsg.hdr);
+ break;
+ default:
+ LOGERR("unrecognized controlvm cmd=%d", (int) inmsg.hdr.Id);
+ if (inmsg.hdr.Flags.responseExpected)
+ controlvm_respond(&inmsg.hdr,
+ -CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN);
+ break;
+ }
+
+ if (parser_ctx != NULL) {
+ parser_done(parser_ctx);
+ parser_ctx = NULL;
+ }
+ return TRUE;
+}
+
+static void
+controlvm_periodic_work(struct work_struct *work)
+{
+ VISORCHIPSET_CHANNEL_INFO chanInfo;
+ CONTROLVM_MESSAGE inmsg;
+ char s[99];
+ BOOL gotACommand = FALSE;
+ BOOL handle_command_failed = FALSE;
+ static U64 Poll_Count;
+
+ /* make sure visorbus server is registered for controlvm callbacks */
+ if (visorchipset_serverregwait && !serverregistered)
+ goto Away;
+ /* make sure visorclientbus server is regsitered for controlvm
+ * callbacks
+ */
+ if (visorchipset_clientregwait && !clientregistered)
+ goto Away;
+
+ memset(&chanInfo, 0, sizeof(VISORCHIPSET_CHANNEL_INFO));
+ if (!ControlVm_channel) {
+ HOSTADDRESS addr = controlvm_get_channel_address();
+ if (addr != 0) {
+ ControlVm_channel =
+ visorchannel_create_with_lock
+ (addr,
+ sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL),
+ UltraControlvmChannelProtocolGuid);
+ if (ControlVm_channel == NULL)
+ LOGERR("failed to create controlvm channel");
+ else if (ULTRA_CONTROLVM_CHANNEL_OK_CLIENT
+ (visorchannel_get_header(ControlVm_channel),
+ NULL)) {
+ LOGINF("Channel %s (ControlVm) discovered",
+ visorchannel_id(ControlVm_channel, s));
+ initialize_controlvm_payload();
+ } else {
+ LOGERR("controlvm channel is invalid");
+ visorchannel_destroy(ControlVm_channel);
+ ControlVm_channel = NULL;
+ }
+ }
+ }
+
+ Poll_Count++;
+ if ((ControlVm_channel != NULL) || (Poll_Count >= 250))
+ ; /* keep going */
+ else
+ goto Away;
+
+ /* Check events to determine if response to CHIPSET_READY
+ * should be sent
+ */
+ if (visorchipset_holdchipsetready
+ && (g_ChipSetMsgHdr.Id != CONTROLVM_INVALID)) {
+ if (check_chipset_events() == 1) {
+ LOGINF("Sending CHIPSET_READY response");
+ controlvm_respond(&g_ChipSetMsgHdr, 0);
+ clear_chipset_events();
+ memset(&g_ChipSetMsgHdr, 0,
+ sizeof(CONTROLVM_MESSAGE_HEADER));
+ }
+ }
+
+ if (ControlVm_channel) {
+ while (visorchannel_signalremove(ControlVm_channel,
+ CONTROLVM_QUEUE_RESPONSE,
+ &inmsg)) {
+ if (inmsg.hdr.PayloadMaxBytes != 0) {
+ LOGERR("Payload of size %lu returned @%lu with unexpected message id %d.",
+ (ulong) inmsg.hdr.PayloadMaxBytes,
+ (ulong) inmsg.hdr.PayloadVmOffset,
+ inmsg.hdr.Id);
+ }
+ }
+ if (!gotACommand) {
+ if (ControlVm_Pending_Msg_Valid) {
+ /* we throttled processing of a prior
+ * msg, so try to process it again
+ * rather than reading a new one
+ */
+ inmsg = ControlVm_Pending_Msg;
+ ControlVm_Pending_Msg_Valid = FALSE;
+ gotACommand = TRUE;
+ } else
+ gotACommand = read_controlvm_event(&inmsg);
+ }
+ }
+
+ handle_command_failed = FALSE;
+ while (gotACommand && (!handle_command_failed)) {
+ Most_recent_message_jiffies = jiffies;
+ if (ControlVm_channel) {
+ if (handle_command(inmsg,
+ visorchannel_get_physaddr
+ (ControlVm_channel)))
+ gotACommand = read_controlvm_event(&inmsg);
+ else {
+ /* this is a scenario where throttling
+ * is required, but probably NOT an
+ * error...; we stash the current
+ * controlvm msg so we will attempt to
+ * reprocess it on our next loop
+ */
+ handle_command_failed = TRUE;
+ ControlVm_Pending_Msg = inmsg;
+ ControlVm_Pending_Msg_Valid = TRUE;
+ }
+
+ } else {
+ handle_command(inmsg, 0);
+ gotACommand = FALSE;
+ }
+ }
+
+ /* parahotplug_worker */
+ parahotplug_process_list();
+
+Away:
+
+ if (time_after(jiffies,
+ Most_recent_message_jiffies + (HZ * MIN_IDLE_SECONDS))) {
+ /* it's been longer than MIN_IDLE_SECONDS since we
+ * processed our last controlvm message; slow down the
+ * polling
+ */
+ if (Poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_SLOW) {
+ LOGINF("switched to slow controlvm polling");
+ Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW;
+ }
+ } else {
+ if (Poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_FAST) {
+ Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
+ LOGINF("switched to fast controlvm polling");
+ }
+ }
+
+ queue_delayed_work(Periodic_controlvm_workqueue,
+ &Periodic_controlvm_work, Poll_jiffies);
+}
+
+static void
+setup_crash_devices_work_queue(struct work_struct *work)
+{
+
+ CONTROLVM_MESSAGE localCrashCreateBusMsg;
+ CONTROLVM_MESSAGE localCrashCreateDevMsg;
+ CONTROLVM_MESSAGE msg;
+ HOSTADDRESS host_addr;
+ U32 localSavedCrashMsgOffset;
+ U16 localSavedCrashMsgCount;
+
+ /* make sure visorbus server is registered for controlvm callbacks */
+ if (visorchipset_serverregwait && !serverregistered)
+ goto Away;
+
+ /* make sure visorclientbus server is regsitered for controlvm
+ * callbacks
+ */
+ if (visorchipset_clientregwait && !clientregistered)
+ goto Away;
+
+ POSTCODE_LINUX_2(CRASH_DEV_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+
+ /* send init chipset msg */
+ msg.hdr.Id = CONTROLVM_CHIPSET_INIT;
+ msg.cmd.initChipset.busCount = 23;
+ msg.cmd.initChipset.switchCount = 0;
+
+ chipset_init(&msg);
+
+ host_addr = controlvm_get_channel_address();
+ if (!host_addr) {
+ LOGERR("Huh? Host address is NULL");
+ POSTCODE_LINUX_2(CRASH_DEV_HADDR_NULL, POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ ControlVm_channel =
+ visorchannel_create_with_lock
+ (host_addr,
+ sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL),
+ UltraControlvmChannelProtocolGuid);
+
+ if (ControlVm_channel == NULL) {
+ LOGERR("failed to create controlvm channel");
+ POSTCODE_LINUX_2(CRASH_DEV_CONTROLVM_NULL,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* get saved message count */
+ if (visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ SavedCrashMsgCount),
+ &localSavedCrashMsgCount, sizeof(U16)) < 0) {
+ LOGERR("failed to get Saved Message Count");
+ POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ if (localSavedCrashMsgCount != CONTROLVM_CRASHMSG_MAX) {
+ LOGERR("Saved Message Count incorrect %d",
+ localSavedCrashMsgCount);
+ POSTCODE_LINUX_3(CRASH_DEV_COUNT_FAILURE_PC,
+ localSavedCrashMsgCount,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* get saved crash message offset */
+ if (visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ SavedCrashMsgOffset),
+ &localSavedCrashMsgOffset, sizeof(U32)) < 0) {
+ LOGERR("failed to get Saved Message Offset");
+ POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* read create device message for storage bus offset */
+ if (visorchannel_read(ControlVm_channel,
+ localSavedCrashMsgOffset,
+ &localCrashCreateBusMsg,
+ sizeof(CONTROLVM_MESSAGE)) < 0) {
+ LOGERR("CRASH_DEV_RD_BUS_FAIULRE: Failed to read CrashCreateBusMsg!");
+ POSTCODE_LINUX_2(CRASH_DEV_RD_BUS_FAIULRE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* read create device message for storage device */
+ if (visorchannel_read(ControlVm_channel,
+ localSavedCrashMsgOffset +
+ sizeof(CONTROLVM_MESSAGE),
+ &localCrashCreateDevMsg,
+ sizeof(CONTROLVM_MESSAGE)) < 0) {
+ LOGERR("CRASH_DEV_RD_DEV_FAIULRE: Failed to read CrashCreateDevMsg!");
+ POSTCODE_LINUX_2(CRASH_DEV_RD_DEV_FAIULRE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* reuse IOVM create bus message */
+ if (localCrashCreateBusMsg.cmd.createBus.channelAddr != 0)
+ bus_create(&localCrashCreateBusMsg);
+ else {
+ LOGERR("CrashCreateBusMsg is null, no dump will be taken");
+ POSTCODE_LINUX_2(CRASH_DEV_BUS_NULL_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+
+ /* reuse create device message for storage device */
+ if (localCrashCreateDevMsg.cmd.createDevice.channelAddr != 0)
+ my_device_create(&localCrashCreateDevMsg);
+ else {
+ LOGERR("CrashCreateDevMsg is null, no dump will be taken");
+ POSTCODE_LINUX_2(CRASH_DEV_DEV_NULL_FAILURE_PC,
+ POSTCODE_SEVERITY_ERR);
+ return;
+ }
+ LOGINF("Bus and device ready for dumping");
+ POSTCODE_LINUX_2(CRASH_DEV_EXIT_PC, POSTCODE_SEVERITY_INFO);
+ return;
+
+Away:
+
+ Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW;
+
+ queue_delayed_work(Periodic_controlvm_workqueue,
+ &Periodic_controlvm_work, Poll_jiffies);
+}
+
+static void
+bus_create_response(ulong busNo, int response)
+{
+ bus_responder(CONTROLVM_BUS_CREATE, busNo, response);
+}
+
+static void
+bus_destroy_response(ulong busNo, int response)
+{
+ bus_responder(CONTROLVM_BUS_DESTROY, busNo, response);
+}
+
+static void
+device_create_response(ulong busNo, ulong devNo, int response)
+{
+ device_responder(CONTROLVM_DEVICE_CREATE, busNo, devNo, response);
+}
+
+static void
+device_destroy_response(ulong busNo, ulong devNo, int response)
+{
+ device_responder(CONTROLVM_DEVICE_DESTROY, busNo, devNo, response);
+}
+
+void
+visorchipset_device_pause_response(ulong busNo, ulong devNo, int response)
+{
+
+ device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
+ busNo, devNo, response,
+ SegmentStateStandby);
+}
+EXPORT_SYMBOL_GPL(visorchipset_device_pause_response);
+
+static void
+device_resume_response(ulong busNo, ulong devNo, int response)
+{
+ device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
+ busNo, devNo, response,
+ SegmentStateRunning);
+}
+
+BOOL
+visorchipset_get_bus_info(ulong busNo, VISORCHIPSET_BUS_INFO *busInfo)
+{
+ void *p = findbus(&BusInfoList, busNo);
+ if (!p) {
+ LOGERR("(%lu) failed", busNo);
+ return FALSE;
+ }
+ memcpy(busInfo, p, sizeof(VISORCHIPSET_BUS_INFO));
+ return TRUE;
+}
+EXPORT_SYMBOL_GPL(visorchipset_get_bus_info);
+
+BOOL
+visorchipset_set_bus_context(ulong busNo, void *context)
+{
+ VISORCHIPSET_BUS_INFO *p = findbus(&BusInfoList, busNo);
+ if (!p) {
+ LOGERR("(%lu) failed", busNo);
+ return FALSE;
+ }
+ p->bus_driver_context = context;
+ return TRUE;
+}
+EXPORT_SYMBOL_GPL(visorchipset_set_bus_context);
+
+BOOL
+visorchipset_get_device_info(ulong busNo, ulong devNo,
+ VISORCHIPSET_DEVICE_INFO *devInfo)
+{
+ void *p = finddevice(&DevInfoList, busNo, devNo);
+ if (!p) {
+ LOGERR("(%lu,%lu) failed", busNo, devNo);
+ return FALSE;
+ }
+ memcpy(devInfo, p, sizeof(VISORCHIPSET_DEVICE_INFO));
+ return TRUE;
+}
+EXPORT_SYMBOL_GPL(visorchipset_get_device_info);
+
+BOOL
+visorchipset_set_device_context(ulong busNo, ulong devNo, void *context)
+{
+ VISORCHIPSET_DEVICE_INFO *p = finddevice(&DevInfoList, busNo, devNo);
+ if (!p) {
+ LOGERR("(%lu,%lu) failed", busNo, devNo);
+ return FALSE;
+ }
+ p->bus_driver_context = context;
+ return TRUE;
+}
+EXPORT_SYMBOL_GPL(visorchipset_set_device_context);
+
+/* Generic wrapper function for allocating memory from a kmem_cache pool.
+ */
+void *
+visorchipset_cache_alloc(struct kmem_cache *pool, BOOL ok_to_block,
+ char *fn, int ln)
+{
+ gfp_t gfp;
+ void *p;
+
+ if (ok_to_block)
+ gfp = GFP_KERNEL;
+ else
+ gfp = GFP_ATOMIC;
+ /* __GFP_NORETRY means "ok to fail", meaning
+ * kmem_cache_alloc() can return NULL, implying the caller CAN
+ * cope with failure. If you do NOT specify __GFP_NORETRY,
+ * Linux will go to extreme measures to get memory for you
+ * (like, invoke oom killer), which will probably cripple the
+ * system.
+ */
+ gfp |= __GFP_NORETRY;
+ p = kmem_cache_alloc(pool, gfp);
+ if (!p) {
+ LOGERR("kmem_cache_alloc failed early @%s:%d\n", fn, ln);
+ return NULL;
+ }
+ atomic_inc(&Visorchipset_cache_buffers_in_use);
+ return p;
+}
+
+/* Generic wrapper function for freeing memory from a kmem_cache pool.
+ */
+void
+visorchipset_cache_free(struct kmem_cache *pool, void *p, char *fn, int ln)
+{
+ if (!p) {
+ LOGERR("NULL pointer @%s:%d\n", fn, ln);
+ return;
+ }
+ atomic_dec(&Visorchipset_cache_buffers_in_use);
+ kmem_cache_free(pool, p);
+}
+
+#define gettoken(bufp) strsep(bufp, " -\t\n")
+
+static ssize_t
+chipset_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char buf[512];
+ char *token, *p;
+
+ if (count > sizeof(buf) - 1) {
+ LOGERR("chipset_proc_write: count (%d) exceeds size of buffer (%d)",
+ (int) count, (int) sizeof(buffer));
+ return -EINVAL;
+ }
+ if (copy_from_user(buf, buffer, count)) {
+ LOGERR("chipset_proc_write: copy_from_user failed");
+ return -EFAULT;
+ }
+ buf[count] = '\0';
+
+ p = buf;
+ token = gettoken(&p);
+
+ if (strcmp(token, "CALLHOMEDISK_MOUNTED") == 0) {
+ token = gettoken(&p);
+ /* The Call Home Disk has been mounted */
+ if (strcmp(token, "0") == 0)
+ chipset_events[0] = 1;
+ } else if (strcmp(token, "MODULES_LOADED") == 0) {
+ token = gettoken(&p);
+ /* All modules for the partition have been loaded */
+ if (strcmp(token, "0") == 0)
+ chipset_events[1] = 1;
+ } else if (token == NULL) {
+ /* No event specified */
+ LOGERR("No event was specified to send CHIPSET_READY response");
+ return -1;
+ } else {
+ /* Unsupported event specified */
+ LOGERR("%s is an invalid event for sending CHIPSET_READY response", token);
+ return -1;
+ }
+
+ return count;
+}
+
+static ssize_t
+visorchipset_proc_read_writeonly(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ return 0;
+}
+
+/**
+ * Reads the InstallationError, InstallationTextId,
+ * InstallationRemainingSteps fields of ControlVMChannel.
+ */
+static ssize_t
+proc_read_installer(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ int length = 0;
+ U16 remainingSteps;
+ U32 error, textId;
+ char *vbuf;
+ loff_t pos = *offset;
+
+ if (pos < 0)
+ return -EINVAL;
+
+ if (pos > 0 || !len)
+ return 0;
+
+ vbuf = kzalloc(len, GFP_KERNEL);
+ if (!vbuf)
+ return -ENOMEM;
+
+ visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ InstallationRemainingSteps), &remainingSteps,
+ sizeof(U16));
+ visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ InstallationError), &error, sizeof(U32));
+ visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ InstallationTextId), &textId, sizeof(U32));
+
+ length = sprintf(vbuf, "%u %u %u\n", remainingSteps, error, textId);
+ if (copy_to_user(buf, vbuf, length)) {
+ kfree(vbuf);
+ return -EFAULT;
+ }
+
+ kfree(vbuf);
+ *offset += length;
+ return length;
+}
+
+/**
+ * Writes to the InstallationError, InstallationTextId,
+ * InstallationRemainingSteps fields of
+ * ControlVMChannel.
+ * Input: RemainingSteps Error TextId
+ * Limit 32 characters input
+ */
+#define UINT16_MAX (65535U)
+#define UINT32_MAX (4294967295U)
+static ssize_t
+proc_write_installer(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
+{
+ char buf[32];
+ U16 remainingSteps;
+ U32 error, textId;
+
+ /* Check to make sure there is no buffer overflow */
+ if (count > (sizeof(buf) - 1))
+ return -EINVAL;
+
+ if (copy_from_user(buf, buffer, count)) {
+ WARN(1, "Error copying from user space\n");
+ return -EFAULT;
+ }
+
+ if (sscanf(buf, "%hu %i %i", &remainingSteps, &error, &textId) != 3) {
+ remainingSteps = UINT16_MAX;
+ error = UINT32_MAX;
+ textId = UINT32_MAX;
+ }
+
+ if (remainingSteps != UINT16_MAX) {
+ if (visorchannel_write
+ (ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ InstallationRemainingSteps), &remainingSteps,
+ sizeof(U16)) < 0)
+ WARN(1, "Installation Status Write Failed - Write function error - RemainingSteps = %d\n",
+ remainingSteps);
+ }
+
+ if (error != UINT32_MAX) {
+ if (visorchannel_write
+ (ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ InstallationError), &error, sizeof(U32)) < 0)
+ WARN(1, "Installation Status Write Failed - Write function error - Error = %d\n",
+ error);
+ }
+
+ if (textId != UINT32_MAX) {
+ if (visorchannel_write
+ (ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ InstallationTextId), &textId, sizeof(U32)) < 0)
+ WARN(1, "Installation Status Write Failed - Write function error - TextId = %d\n",
+ textId);
+ }
+
+ /* So this function isn't called multiple times, must return
+ * size of buffer
+ */
+ return count;
+}
+
+/**
+ * Reads the ToolAction field of ControlVMChannel.
+ */
+static ssize_t
+proc_read_toolaction(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ int length = 0;
+ U8 toolAction;
+ char *vbuf;
+ loff_t pos = *offset;
+
+ if (pos < 0)
+ return -EINVAL;
+
+ if (pos > 0 || !len)
+ return 0;
+
+ vbuf = kzalloc(len, GFP_KERNEL);
+ if (!vbuf)
+ return -ENOMEM;
+
+ visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ ToolAction), &toolAction, sizeof(U8));
+
+ length = sprintf(vbuf, "%u\n", toolAction);
+ if (copy_to_user(buf, vbuf, length)) {
+ kfree(vbuf);
+ return -EFAULT;
+ }
+
+ kfree(vbuf);
+ *offset += length;
+ return length;
+}
+
+/**
+ * Writes to the ToolAction field of ControlVMChannel.
+ * Input: ToolAction
+ * Limit 3 characters input
+ */
+#define UINT8_MAX (255U)
+static ssize_t
+proc_write_toolaction(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
+{
+ char buf[3];
+ U8 toolAction;
+
+ /* Check to make sure there is no buffer overflow */
+ if (count > (sizeof(buf) - 1))
+ return -EINVAL;
+
+ if (copy_from_user(buf, buffer, count)) {
+ WARN(1, "Error copying from user space\n");
+ return -EFAULT;
+ }
+
+ if (sscanf(buf, "%hhd", &toolAction) != 1)
+ toolAction = UINT8_MAX;
+
+ if (toolAction != UINT8_MAX) {
+ if (visorchannel_write
+ (ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, ToolAction),
+ &toolAction, sizeof(U8)) < 0)
+ WARN(1, "Installation ToolAction Write Failed - ToolAction = %d\n",
+ toolAction);
+ }
+
+ /* So this function isn't called multiple times, must return
+ * size of buffer
+ */
+ return count;
+}
+
+/**
+ * Reads the EfiSparIndication.BootToTool field of ControlVMChannel.
+ */
+static ssize_t
+proc_read_bootToTool(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ int length = 0;
+ ULTRA_EFI_SPAR_INDICATION efiSparIndication;
+ char *vbuf;
+ loff_t pos = *offset;
+
+ if (pos < 0)
+ return -EINVAL;
+
+ if (pos > 0 || !len)
+ return 0;
+
+ vbuf = kzalloc(len, GFP_KERNEL);
+ if (!vbuf)
+ return -ENOMEM;
+
+ visorchannel_read(ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
+ EfiSparIndication), &efiSparIndication,
+ sizeof(ULTRA_EFI_SPAR_INDICATION));
+
+ length = sprintf(vbuf, "%d\n", (int) efiSparIndication.BootToTool);
+ if (copy_to_user(buf, vbuf, length)) {
+ kfree(vbuf);
+ return -EFAULT;
+ }
+
+ kfree(vbuf);
+ *offset += length;
+ return length;
+}
+
+/**
+ * Writes to the EfiSparIndication.BootToTool field of ControlVMChannel.
+ * Input: 1 or 0 (1 being on, 0 being off)
+ */
+static ssize_t
+proc_write_bootToTool(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
+{
+ char buf[3];
+ int inputVal;
+ ULTRA_EFI_SPAR_INDICATION efiSparIndication;
+
+ /* Check to make sure there is no buffer overflow */
+ if (count > (sizeof(buf) - 1))
+ return -EINVAL;
+
+ if (copy_from_user(buf, buffer, count)) {
+ WARN(1, "Error copying from user space\n");
+ return -EFAULT;
+ }
+
+ if (sscanf(buf, "%i", &inputVal) != 1)
+ inputVal = 0;
+
+ efiSparIndication.BootToTool = (inputVal == 1 ? 1 : 0);
+
+ if (visorchannel_write
+ (ControlVm_channel,
+ offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EfiSparIndication),
+ &efiSparIndication, sizeof(ULTRA_EFI_SPAR_INDICATION)) < 0)
+ printk
+ ("Installation BootToTool Write Failed - BootToTool = %d\n",
+ (int) efiSparIndication.BootToTool);
+
+ /* So this function isn't called multiple times, must return
+ * size of buffer
+ */
+ return count;
+}
+
+static const struct file_operations chipset_proc_fops = {
+ .owner = THIS_MODULE,
+ .read = visorchipset_proc_read_writeonly,
+ .write = chipset_proc_write,
+};
+
+static int __init
+visorchipset_init(void)
+{
+ int rc = 0, x = 0;
+ struct proc_dir_entry *installer_file;
+ struct proc_dir_entry *toolaction_file;
+ struct proc_dir_entry *bootToTool_file;
+
+ LOGINF("chipset driver version %s loaded", VERSION);
+ /* process module options */
+ POSTCODE_LINUX_2(DRIVER_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+
+ LOGINF("option - testvnic=%d", visorchipset_testvnic);
+ LOGINF("option - testvnicclient=%d", visorchipset_testvnicclient);
+ LOGINF("option - testmsg=%d", visorchipset_testmsg);
+ LOGINF("option - testteardown=%d", visorchipset_testteardown);
+ LOGINF("option - major=%d", visorchipset_major);
+ LOGINF("option - serverregwait=%d", visorchipset_serverregwait);
+ LOGINF("option - clientregwait=%d", visorchipset_clientregwait);
+ LOGINF("option - holdchipsetready=%d", visorchipset_holdchipsetready);
+
+ memset(&BusDev_Server_Notifiers, 0, sizeof(BusDev_Server_Notifiers));
+ memset(&BusDev_Client_Notifiers, 0, sizeof(BusDev_Client_Notifiers));
+ memset(&ControlVm_payload_info, 0, sizeof(ControlVm_payload_info));
+ memset(&LiveDump_info, 0, sizeof(LiveDump_info));
+ atomic_set(&LiveDump_info.buffers_in_use, 0);
+
+ if (visorchipset_testvnic) {
+ ERRDRV("testvnic option no longer supported: (status = %d)\n",
+ x);
+ POSTCODE_LINUX_3(CHIPSET_INIT_FAILURE_PC, x, DIAG_SEVERITY_ERR);
+ rc = x;
+ goto Away;
+ }
+
+ controlvm_init();
+ MajorDev = MKDEV(visorchipset_major, 0);
+ rc = visorchipset_file_init(MajorDev, &ControlVm_channel);
+ if (rc < 0) {
+ ERRDRV("visorchipset_file_init(MajorDev, &ControlVm_channel): error (status=%d)\n", rc);
+ POSTCODE_LINUX_2(CHIPSET_INIT_FAILURE_PC, DIAG_SEVERITY_ERR);
+ goto Away;
+ }
+
+ proc_Init();
+ memset(PartitionPropertyNames, 0, sizeof(PartitionPropertyNames));
+ memset(ControlVmPropertyNames, 0, sizeof(ControlVmPropertyNames));
+ InitPartitionProperties();
+ InitControlVmProperties();
+
+ PartitionType = visor_proc_CreateType(ProcDir, PartitionTypeNames,
+ (const char **)
+ PartitionPropertyNames,
+ &show_partition_property);
+ ControlVmType =
+ visor_proc_CreateType(ProcDir, ControlVmTypeNames,
+ (const char **) ControlVmPropertyNames,
+ &show_controlvm_property);
+
+ ControlVmObject = visor_proc_CreateObject(ControlVmType, NULL, NULL);
+
+ /* Setup Installation fields */
+ installer_file = proc_create("installer", 0644, ProcDir,
+ &proc_installer_fops);
+ /* Setup the ToolAction field */
+ toolaction_file = proc_create("toolaction", 0644, ProcDir,
+ &proc_toolaction_fops);
+ /* Setup the BootToTool field */
+ bootToTool_file = proc_create("boottotool", 0644, ProcDir,
+ &proc_bootToTool_fops);
+
+ memset(&g_DiagMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER));
+
+ chipset_proc_dir = proc_create(VISORCHIPSET_CHIPSET_PROC_ENTRY_FN,
+ 0644, ProcDir, &chipset_proc_fops);
+ memset(&g_ChipSetMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER));
+
+ parahotplug_proc_dir =
+ proc_create(VISORCHIPSET_PARAHOTPLUG_PROC_ENTRY_FN, 0200,
+ ProcDir, &parahotplug_proc_fops);
+ memset(&g_DelDumpMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER));
+
+ if (filexfer_constructor(sizeof(struct putfile_request)) < 0) {
+ ERRDRV("filexfer_constructor failed: (status=-1)\n");
+ POSTCODE_LINUX_2(CHIPSET_INIT_FAILURE_PC, DIAG_SEVERITY_ERR);
+ rc = -1;
+ goto Away;
+ }
+ Putfile_buffer_list_pool =
+ kmem_cache_create(Putfile_buffer_list_pool_name,
+ sizeof(struct putfile_buffer_entry),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!Putfile_buffer_list_pool) {
+ ERRDRV("failed to alloc Putfile_buffer_list_pool: (status=-1)\n");
+ POSTCODE_LINUX_2(CHIPSET_INIT_FAILURE_PC, DIAG_SEVERITY_ERR);
+ rc = -1;
+ goto Away;
+ }
+ if (visorchipset_disable_controlvm) {
+ LOGINF("visorchipset_init:controlvm disabled");
+ } else {
+ /* if booting in a crash kernel */
+ if (visorchipset_crash_kernel)
+ INIT_DELAYED_WORK(&Periodic_controlvm_work,
+ setup_crash_devices_work_queue);
+ else
+ INIT_DELAYED_WORK(&Periodic_controlvm_work,
+ controlvm_periodic_work);
+ Periodic_controlvm_workqueue =
+ create_singlethread_workqueue("visorchipset_controlvm");
+
+ if (Periodic_controlvm_workqueue == NULL) {
+ ERRDRV("cannot create controlvm workqueue: (status=%d)\n",
+ -ENOMEM);
+ POSTCODE_LINUX_2(CREATE_WORKQUEUE_FAILED_PC,
+ DIAG_SEVERITY_ERR);
+ rc = -ENOMEM;
+ goto Away;
+ }
+ Most_recent_message_jiffies = jiffies;
+ Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
+ rc = queue_delayed_work(Periodic_controlvm_workqueue,
+ &Periodic_controlvm_work, Poll_jiffies);
+ if (rc < 0) {
+ ERRDRV("queue_delayed_work(Periodic_controlvm_workqueue, &Periodic_controlvm_work, Poll_jiffies): error (status=%d)\n", rc);
+ POSTCODE_LINUX_2(QUEUE_DELAYED_WORK_PC,
+ DIAG_SEVERITY_ERR);
+ goto Away;
+ }
+
+ }
+
+ Visorchipset_platform_device.dev.devt = MajorDev;
+ if (platform_device_register(&Visorchipset_platform_device) < 0) {
+ ERRDRV("platform_device_register(visorchipset) failed: (status=-1)\n");
+ POSTCODE_LINUX_2(DEVICE_REGISTER_FAILURE_PC, DIAG_SEVERITY_ERR);
+ rc = -1;
+ goto Away;
+ }
+ LOGINF("visorchipset device created");
+ POSTCODE_LINUX_2(CHIPSET_INIT_SUCCESS_PC, POSTCODE_SEVERITY_INFO);
+ rc = 0;
+Away:
+ if (rc) {
+ LOGERR("visorchipset_init failed");
+ POSTCODE_LINUX_3(CHIPSET_INIT_FAILURE_PC, rc,
+ POSTCODE_SEVERITY_ERR);
+ }
+ return rc;
+}
+
+static void
+visorchipset_exit(void)
+{
+ char s[99];
+ POSTCODE_LINUX_2(DRIVER_EXIT_PC, POSTCODE_SEVERITY_INFO);
+
+ if (visorchipset_disable_controlvm) {
+ ;
+ } else {
+ cancel_delayed_work(&Periodic_controlvm_work);
+ flush_workqueue(Periodic_controlvm_workqueue);
+ destroy_workqueue(Periodic_controlvm_workqueue);
+ Periodic_controlvm_workqueue = NULL;
+ destroy_controlvm_payload_info(&ControlVm_payload_info);
+ }
+ Test_Vnic_channel = NULL;
+ if (Putfile_buffer_list_pool) {
+ kmem_cache_destroy(Putfile_buffer_list_pool);
+ Putfile_buffer_list_pool = NULL;
+ }
+ filexfer_destructor();
+ if (ControlVmObject) {
+ visor_proc_DestroyObject(ControlVmObject);
+ ControlVmObject = NULL;
+ }
+ cleanup_controlvm_structures();
+
+ if (ControlVmType) {
+ visor_proc_DestroyType(ControlVmType);
+ ControlVmType = NULL;
+ }
+ if (PartitionType) {
+ visor_proc_DestroyType(PartitionType);
+ PartitionType = NULL;
+ }
+ if (diag_proc_dir) {
+ remove_proc_entry(VISORCHIPSET_DIAG_PROC_ENTRY_FN, ProcDir);
+ diag_proc_dir = NULL;
+ }
+ memset(&g_DiagMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER));
+
+ if (chipset_proc_dir) {
+ remove_proc_entry(VISORCHIPSET_CHIPSET_PROC_ENTRY_FN, ProcDir);
+ chipset_proc_dir = NULL;
+ }
+ memset(&g_ChipSetMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER));
+
+ if (parahotplug_proc_dir) {
+ remove_proc_entry(VISORCHIPSET_PARAHOTPLUG_PROC_ENTRY_FN,
+ ProcDir);
+ parahotplug_proc_dir = NULL;
+ }
+
+ memset(&g_DelDumpMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER));
+
+ proc_DeInit();
+ if (ControlVm_channel != NULL) {
+ LOGINF("Channel %s (ControlVm) disconnected",
+ visorchannel_id(ControlVm_channel, s));
+ visorchannel_destroy(ControlVm_channel);
+ ControlVm_channel = NULL;
+ }
+ controlvm_deinit();
+ visorchipset_file_cleanup();
+ POSTCODE_LINUX_2(DRIVER_EXIT_PC, POSTCODE_SEVERITY_INFO);
+ LOGINF("chipset driver unloaded");
+}
+
+module_param_named(testvnic, visorchipset_testvnic, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_testvnic, "1 to test vnic, using dummy VNIC connected via a loopback to a physical ethernet");
+int visorchipset_testvnic = 0;
+
+module_param_named(testvnicclient, visorchipset_testvnicclient, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_testvnicclient, "1 to test vnic, using real VNIC channel attached to a separate IOVM guest");
+int visorchipset_testvnicclient = 0;
+
+module_param_named(testmsg, visorchipset_testmsg, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_testmsg,
+ "1 to manufacture the chipset, bus, and switch messages");
+int visorchipset_testmsg = 0;
+
+module_param_named(major, visorchipset_major, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_major, "major device number to use for the device node");
+int visorchipset_major = 0;
+
+module_param_named(serverregwait, visorchipset_serverregwait, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_serverreqwait,
+ "1 to have the module wait for the visor bus to register");
+int visorchipset_serverregwait = 0; /* default is off */
+module_param_named(clientregwait, visorchipset_clientregwait, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_clientregwait, "1 to have the module wait for the visorclientbus to register");
+int visorchipset_clientregwait = 1; /* default is on */
+module_param_named(testteardown, visorchipset_testteardown, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_testteardown,
+ "1 to test teardown of the chipset, bus, and switch");
+int visorchipset_testteardown = 0; /* default is off */
+module_param_named(disable_controlvm, visorchipset_disable_controlvm, int,
+ S_IRUGO);
+MODULE_PARM_DESC(visorchipset_disable_controlvm,
+ "1 to disable polling of controlVm channel");
+int visorchipset_disable_controlvm = 0; /* default is off */
+module_param_named(crash_kernel, visorchipset_crash_kernel, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_crash_kernel,
+ "1 means we are running in crash kernel");
+int visorchipset_crash_kernel = 0; /* default is running in non-crash kernel */
+module_param_named(holdchipsetready, visorchipset_holdchipsetready,
+ int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_holdchipsetready,
+ "1 to hold response to CHIPSET_READY");
+int visorchipset_holdchipsetready = 0; /* default is to send CHIPSET_READY
+ * response immediately */
+module_init(visorchipset_init);
+module_exit(visorchipset_exit);
+
+MODULE_AUTHOR("Unisys");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Supervisor chipset driver for service partition: ver "
+ VERSION);
+MODULE_VERSION(VERSION);
diff --git a/drivers/staging/unisys/visorchipset/visorchipset_umode.h b/drivers/staging/unisys/visorchipset/visorchipset_umode.h
new file mode 100644
index 000000000000..259e840376a5
--- /dev/null
+++ b/drivers/staging/unisys/visorchipset/visorchipset_umode.h
@@ -0,0 +1,37 @@
+/* visorchipset_umode.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/** @file *********************************************************************
+ *
+ * This describes structures needed for the interface between the
+ * visorchipset driver and a user-mode component that opens the device.
+ *
+ ******************************************************************************
+ */
+
+#ifndef __VISORCHIPSET_UMODE_H
+#define __VISORCHIPSET_UMODE_H
+
+
+
+/** The user-mode program can access the control channel buffer directly
+ * via this memory map.
+ */
+#define VISORCHIPSET_MMAP_CONTROLCHANOFFSET (0x00000000)
+#define VISORCHIPSET_MMAP_CONTROLCHANSIZE (0x00400000) /* 4MB */
+
+#endif /* __VISORCHIPSET_UMODE_H */
diff --git a/drivers/staging/unisys/visorutil/Kconfig b/drivers/staging/unisys/visorutil/Kconfig
new file mode 100644
index 000000000000..4ff61a7c506b
--- /dev/null
+++ b/drivers/staging/unisys/visorutil/Kconfig
@@ -0,0 +1,10 @@
+#
+# Unisys timskmod configuration
+#
+
+config UNISYS_VISORUTIL
+ tristate "Unisys visorutil driver"
+ depends on UNISYSSPAR
+ ---help---
+ If you say Y here, you will enable the Unisys visorutil driver.
+
diff --git a/drivers/staging/unisys/visorutil/Makefile b/drivers/staging/unisys/visorutil/Makefile
new file mode 100644
index 000000000000..3f463888dcec
--- /dev/null
+++ b/drivers/staging/unisys/visorutil/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for Unisys timskmod
+#
+
+obj-$(CONFIG_UNISYS_VISORUTIL) += visorutil.o
+
+visorutil-y := charqueue.o easyproc.o periodic_work.o procobjecttree.o \
+ memregion_direct.o visorkmodutils.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION
diff --git a/drivers/staging/unisys/visorutil/charqueue.c b/drivers/staging/unisys/visorutil/charqueue.c
new file mode 100644
index 000000000000..0ceede129e87
--- /dev/null
+++ b/drivers/staging/unisys/visorutil/charqueue.c
@@ -0,0 +1,141 @@
+/* charqueue.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * Simple character queue implementation for Linux kernel mode.
+ */
+
+#include "charqueue.h"
+
+#define MYDRVNAME "charqueue"
+
+#define IS_EMPTY(charqueue) (charqueue->head == charqueue->tail)
+
+
+
+struct CHARQUEUE_Tag {
+ int alloc_size;
+ int nslots;
+ spinlock_t lock;
+ int head, tail;
+ unsigned char buf[0];
+};
+
+
+
+CHARQUEUE *visor_charqueue_create(ulong nslots)
+{
+ int alloc_size = sizeof(CHARQUEUE) + nslots + 1;
+ CHARQUEUE *cq = kmalloc(alloc_size, GFP_KERNEL|__GFP_NORETRY);
+ if (cq == NULL) {
+ ERRDRV("visor_charqueue_create allocation failed (alloc_size=%d)",
+ alloc_size);
+ return NULL;
+ }
+ cq->alloc_size = alloc_size;
+ cq->nslots = nslots;
+ cq->head = cq->tail = 0;
+ spin_lock_init(&cq->lock);
+ return cq;
+}
+EXPORT_SYMBOL_GPL(visor_charqueue_create);
+
+
+
+void visor_charqueue_enqueue(CHARQUEUE *charqueue, unsigned char c)
+{
+ int alloc_slots = charqueue->nslots+1; /* 1 slot is always empty */
+
+ spin_lock(&charqueue->lock);
+ charqueue->head = (charqueue->head+1) % alloc_slots;
+ if (charqueue->head == charqueue->tail)
+ /* overflow; overwrite the oldest entry */
+ charqueue->tail = (charqueue->tail+1) % alloc_slots;
+ charqueue->buf[charqueue->head] = c;
+ spin_unlock(&charqueue->lock);
+}
+EXPORT_SYMBOL_GPL(visor_charqueue_enqueue);
+
+
+
+BOOL visor_charqueue_is_empty(CHARQUEUE *charqueue)
+{
+ BOOL b;
+ spin_lock(&charqueue->lock);
+ b = IS_EMPTY(charqueue);
+ spin_unlock(&charqueue->lock);
+ return b;
+}
+EXPORT_SYMBOL_GPL(visor_charqueue_is_empty);
+
+
+
+static int charqueue_dequeue_1(CHARQUEUE *charqueue)
+{
+ int alloc_slots = charqueue->nslots + 1; /* 1 slot is always empty */
+
+ if (IS_EMPTY(charqueue))
+ return -1;
+ charqueue->tail = (charqueue->tail+1) % alloc_slots;
+ return charqueue->buf[charqueue->tail];
+}
+
+
+
+int charqueue_dequeue(CHARQUEUE *charqueue)
+{
+ int rc;
+
+ spin_lock(&charqueue->lock);
+ rc = charqueue_dequeue_1(charqueue);
+ spin_unlock(&charqueue->lock);
+ return rc;
+}
+
+
+
+int visor_charqueue_dequeue_n(CHARQUEUE *charqueue, unsigned char *buf, int n)
+{
+ int rc, counter = 0, c;
+
+ spin_lock(&charqueue->lock);
+ for (;;) {
+ if (n <= 0)
+ break; /* no more buffer space */
+ c = charqueue_dequeue_1(charqueue);
+ if (c < 0)
+ break; /* no more input */
+ *buf = (unsigned char)(c);
+ buf++;
+ n--;
+ counter++;
+ }
+ rc = counter;
+ spin_unlock(&charqueue->lock);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(visor_charqueue_dequeue_n);
+
+
+
+void visor_charqueue_destroy(CHARQUEUE *charqueue)
+{
+ if (charqueue == NULL)
+ return;
+ kfree(charqueue);
+}
+EXPORT_SYMBOL_GPL(visor_charqueue_destroy);
diff --git a/drivers/staging/unisys/visorutil/charqueue.h b/drivers/staging/unisys/visorutil/charqueue.h
new file mode 100644
index 000000000000..e82ae0bc8959
--- /dev/null
+++ b/drivers/staging/unisys/visorutil/charqueue.h
@@ -0,0 +1,37 @@
+/* charqueue.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __CHARQUEUE_H__
+#define __CHARQUEUE_H__
+
+#include "uniklog.h"
+#include "timskmod.h"
+
+/* CHARQUEUE is an opaque structure to users.
+ * Fields are declared only in the implementation .c files.
+ */
+typedef struct CHARQUEUE_Tag CHARQUEUE;
+
+CHARQUEUE *visor_charqueue_create(ulong nslots);
+void visor_charqueue_enqueue(CHARQUEUE *charqueue, unsigned char c);
+int charqueue_dequeue(CHARQUEUE *charqueue);
+int visor_charqueue_dequeue_n(CHARQUEUE *charqueue, unsigned char *buf, int n);
+BOOL visor_charqueue_is_empty(CHARQUEUE *charqueue);
+void visor_charqueue_destroy(CHARQUEUE *charqueue);
+
+#endif
+
diff --git a/drivers/staging/unisys/visorutil/easyproc.c b/drivers/staging/unisys/visorutil/easyproc.c
new file mode 100644
index 000000000000..60b6b83d1b20
--- /dev/null
+++ b/drivers/staging/unisys/visorutil/easyproc.c
@@ -0,0 +1,371 @@
+/* Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/** @file *********************************************************************
+ *
+ * Handle procfs-specific tasks.
+ * Note that this file does not know about any module-specific things, nor
+ * does it know anything about what information to reveal as part of the proc
+ * entries. The 2 functions that take care of displaying device and
+ * driver specific information are passed as parameters to
+ * visor_easyproc_InitDriver().
+ *
+ * void show_device_info(struct seq_file *seq, void *p);
+ * void show_driver_info(struct seq_file *seq);
+ *
+ * The second parameter to show_device_info is actually a pointer to the
+ * device-specific info to show. It is the context that was originally
+ * passed to visor_easyproc_InitDevice().
+ *
+ ******************************************************************************
+ */
+
+#include <linux/proc_fs.h>
+
+#include "uniklog.h"
+#include "timskmod.h"
+#include "easyproc.h"
+
+#define MYDRVNAME "easyproc"
+
+
+
+/*
+ * /proc/<ProcId> ProcDir
+ * /proc/<ProcId>/driver ProcDriverDir
+ * /proc/<ProcId>/driver/diag ProcDriverDiagFile
+ * /proc/<ProcId>/device ProcDeviceDir
+ * /proc/<ProcId>/device/0 procDevicexDir
+ * /proc/<ProcId>/device/0/diag procDevicexDiagFile
+ */
+
+
+static ssize_t proc_write_device(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos);
+static ssize_t proc_write_driver(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos);
+
+static struct proc_dir_entry *
+ createProcDir(char *name, struct proc_dir_entry *parent)
+{
+ struct proc_dir_entry *p = proc_mkdir_mode(name, S_IFDIR, parent);
+ if (p == NULL)
+ ERRDRV("failed to create /proc directory %s", name);
+ return p;
+}
+
+static int seq_show_driver(struct seq_file *seq, void *offset);
+static int proc_open_driver(struct inode *inode, struct file *file)
+{
+ return single_open(file, seq_show_driver, PDE_DATA(inode));
+}
+static const struct file_operations proc_fops_driver = {
+ .open = proc_open_driver,
+ .read = seq_read,
+ .write = proc_write_driver,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int seq_show_device(struct seq_file *seq, void *offset);
+static int seq_show_device_property(struct seq_file *seq, void *offset);
+static int proc_open_device(struct inode *inode, struct file *file)
+{
+ return single_open(file, seq_show_device, PDE_DATA(inode));
+}
+static const struct file_operations proc_fops_device = {
+ .open = proc_open_device,
+ .read = seq_read,
+ .write = proc_write_device,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+static int proc_open_device_property(struct inode *inode, struct file *file)
+{
+ return single_open(file, seq_show_device_property, PDE_DATA(inode));
+}
+static const struct file_operations proc_fops_device_property = {
+ .open = proc_open_device_property,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
+
+void visor_easyproc_InitDriver(struct easyproc_driver_info *pdriver,
+ char *procId,
+ void (*show_driver_info)(struct seq_file *),
+ void (*show_device_info)(struct seq_file *,
+ void *))
+{
+ memset(pdriver, 0, sizeof(struct easyproc_driver_info));
+ pdriver->ProcId = procId;
+ if (pdriver->ProcId == NULL)
+ ERRDRV("ProcId cannot be NULL (trouble ahead)!");
+ pdriver->Show_driver_info = show_driver_info;
+ pdriver->Show_device_info = show_device_info;
+ if (pdriver->ProcDir == NULL)
+ pdriver->ProcDir = createProcDir(pdriver->ProcId, NULL);
+ if ((pdriver->ProcDir != NULL) && (pdriver->ProcDriverDir == NULL))
+ pdriver->ProcDriverDir = createProcDir("driver",
+ pdriver->ProcDir);
+ if ((pdriver->ProcDir != NULL) && (pdriver->ProcDeviceDir == NULL))
+ pdriver->ProcDeviceDir = createProcDir("device",
+ pdriver->ProcDir);
+ if ((pdriver->ProcDriverDir != NULL) &&
+ (pdriver->ProcDriverDiagFile == NULL)) {
+ pdriver->ProcDriverDiagFile =
+ proc_create_data("diag", 0,
+ pdriver->ProcDriverDir,
+ &proc_fops_driver, pdriver);
+ if (pdriver->ProcDriverDiagFile == NULL)
+ ERRDRV("failed to register /proc/%s/driver/diag entry",
+ pdriver->ProcId);
+ }
+}
+EXPORT_SYMBOL_GPL(visor_easyproc_InitDriver);
+
+
+
+void visor_easyproc_InitDriverEx(struct easyproc_driver_info *pdriver,
+ char *procId,
+ void (*show_driver_info)(struct seq_file *),
+ void (*show_device_info)(struct seq_file *,
+ void *),
+ void (*write_driver_info)(char *buf,
+ size_t count,
+ loff_t *ppos),
+ void (*write_device_info)(char *buf,
+ size_t count,
+ loff_t *ppos,
+ void *p))
+{
+ visor_easyproc_InitDriver(pdriver, procId,
+ show_driver_info, show_device_info);
+ pdriver->Write_driver_info = write_driver_info;
+ pdriver->Write_device_info = write_device_info;
+}
+EXPORT_SYMBOL_GPL(visor_easyproc_InitDriverEx);
+
+
+
+void visor_easyproc_DeInitDriver(struct easyproc_driver_info *pdriver)
+{
+ if (pdriver->ProcDriverDiagFile != NULL) {
+ remove_proc_entry("diag", pdriver->ProcDriverDir);
+ pdriver->ProcDriverDiagFile = NULL;
+ }
+ if (pdriver->ProcDriverDir != NULL) {
+ remove_proc_entry("driver", pdriver->ProcDir);
+ pdriver->ProcDriverDir = NULL;
+ }
+ if (pdriver->ProcDeviceDir != NULL) {
+ remove_proc_entry("device", pdriver->ProcDir);
+ pdriver->ProcDeviceDir = NULL;
+ }
+ if (pdriver->ProcDir != NULL) {
+ remove_proc_entry(pdriver->ProcId, NULL);
+ pdriver->ProcDir = NULL;
+ }
+ pdriver->ProcId = NULL;
+ pdriver->Show_driver_info = NULL;
+ pdriver->Show_device_info = NULL;
+ pdriver->Write_driver_info = NULL;
+ pdriver->Write_device_info = NULL;
+}
+EXPORT_SYMBOL_GPL(visor_easyproc_DeInitDriver);
+
+
+
+void visor_easyproc_InitDevice(struct easyproc_driver_info *pdriver,
+ struct easyproc_device_info *p, int devno,
+ void *devdata)
+{
+ if ((pdriver->ProcDeviceDir != NULL) && (p->procDevicexDir == NULL)) {
+ char s[29];
+ sprintf(s, "%d", devno);
+ p->procDevicexDir = createProcDir(s, pdriver->ProcDeviceDir);
+ p->devno = devno;
+ }
+ p->devdata = devdata;
+ p->pdriver = pdriver;
+ p->devno = devno;
+ if ((p->procDevicexDir != NULL) && (p->procDevicexDiagFile == NULL)) {
+ p->procDevicexDiagFile =
+ proc_create_data("diag", 0, p->procDevicexDir,
+ &proc_fops_device, p);
+ if (p->procDevicexDiagFile == NULL)
+ ERRDEVX(devno, "failed to register /proc/%s/device/%d/diag entry",
+ pdriver->ProcId, devno
+ );
+ }
+ memset(&(p->device_property_info[0]), 0,
+ sizeof(p->device_property_info));
+}
+EXPORT_SYMBOL_GPL(visor_easyproc_InitDevice);
+
+
+
+void visor_easyproc_CreateDeviceProperty(struct easyproc_device_info *p,
+ void (*show_property_info)
+ (struct seq_file *, void *),
+ char *property_name)
+{
+ size_t i;
+ struct easyproc_device_property_info *px = NULL;
+
+ if (p->procDevicexDir == NULL) {
+ ERRDRV("state error");
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(p->device_property_info); i++) {
+ if (p->device_property_info[i].procEntry == NULL) {
+ px = &(p->device_property_info[i]);
+ break;
+ }
+ }
+ if (!px) {
+ ERRDEVX(p->devno, "too many device properties");
+ return;
+ }
+ px->devdata = p->devdata;
+ px->pdriver = p->pdriver;
+ px->procEntry = proc_create_data(property_name, 0, p->procDevicexDir,
+ &proc_fops_device_property, px);
+ if (strlen(property_name)+1 > sizeof(px->property_name)) {
+ ERRDEVX(p->devno, "device property name %s too long",
+ property_name);
+ return;
+ }
+ strcpy(px->property_name, property_name);
+ if (px->procEntry == NULL) {
+ ERRDEVX(p->devno, "failed to register /proc/%s/device/%d/%s entry",
+ p->pdriver->ProcId, p->devno, property_name
+ );
+ return;
+ }
+ px->show_device_property_info = show_property_info;
+}
+EXPORT_SYMBOL_GPL(visor_easyproc_CreateDeviceProperty);
+
+
+
+void visor_easyproc_DeInitDevice(struct easyproc_driver_info *pdriver,
+ struct easyproc_device_info *p, int devno)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(p->device_property_info); i++) {
+ if (p->device_property_info[i].procEntry != NULL) {
+ struct easyproc_device_property_info *px =
+ &(p->device_property_info[i]);
+ remove_proc_entry(px->property_name, p->procDevicexDir);
+ px->procEntry = NULL;
+ }
+ }
+ if (p->procDevicexDiagFile != NULL) {
+ remove_proc_entry("diag", p->procDevicexDir);
+ p->procDevicexDiagFile = NULL;
+ }
+ if (p->procDevicexDir != NULL) {
+ char s[29];
+ sprintf(s, "%d", devno);
+ remove_proc_entry(s, pdriver->ProcDeviceDir);
+ p->procDevicexDir = NULL;
+ }
+ p->devdata = NULL;
+ p->pdriver = NULL;
+}
+EXPORT_SYMBOL_GPL(visor_easyproc_DeInitDevice);
+
+
+
+static int seq_show_driver(struct seq_file *seq, void *offset)
+{
+ struct easyproc_driver_info *p =
+ (struct easyproc_driver_info *)(seq->private);
+ if (!p)
+ return 0;
+ (*(p->Show_driver_info))(seq);
+ return 0;
+}
+
+
+
+static int seq_show_device(struct seq_file *seq, void *offset)
+{
+ struct easyproc_device_info *p =
+ (struct easyproc_device_info *)(seq->private);
+ if ((!p) || (!(p->pdriver)))
+ return 0;
+ (*(p->pdriver->Show_device_info))(seq, p->devdata);
+ return 0;
+}
+
+
+
+static int seq_show_device_property(struct seq_file *seq, void *offset)
+{
+ struct easyproc_device_property_info *p =
+ (struct easyproc_device_property_info *)(seq->private);
+ if ((!p) || (!(p->show_device_property_info)))
+ return 0;
+ (*(p->show_device_property_info))(seq, p->devdata);
+ return 0;
+}
+
+
+
+static ssize_t proc_write_driver(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *seq = (struct seq_file *)file->private_data;
+ struct easyproc_driver_info *p = NULL;
+ char local_buf[256];
+ if (seq == NULL)
+ return 0;
+ p = (struct easyproc_driver_info *)(seq->private);
+ if ((!p) || (!(p->Write_driver_info)))
+ return 0;
+ if (count >= sizeof(local_buf))
+ return -ENOMEM;
+ if (copy_from_user(local_buf, buffer, count))
+ return -EFAULT;
+ local_buf[count] = '\0'; /* be friendly */
+ (*(p->Write_driver_info))(local_buf, count, ppos);
+ return count;
+}
+
+
+
+static ssize_t proc_write_device(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *seq = (struct seq_file *)file->private_data;
+ struct easyproc_device_info *p = NULL;
+ char local_buf[256];
+ if (seq == NULL)
+ return 0;
+ p = (struct easyproc_device_info *)(seq->private);
+ if ((!p) || (!(p->pdriver)) || (!(p->pdriver->Write_device_info)))
+ return 0;
+ if (count >= sizeof(local_buf))
+ return -ENOMEM;
+ if (copy_from_user(local_buf, buffer, count))
+ return -EFAULT;
+ local_buf[count] = '\0'; /* be friendly */
+ (*(p->pdriver->Write_device_info))(local_buf, count, ppos, p->devdata);
+ return count;
+}
diff --git a/drivers/staging/unisys/visorutil/easyproc.h b/drivers/staging/unisys/visorutil/easyproc.h
new file mode 100644
index 000000000000..1cef1fd33d53
--- /dev/null
+++ b/drivers/staging/unisys/visorutil/easyproc.h
@@ -0,0 +1,92 @@
+/* easyproc.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/** @file *********************************************************************
+ *
+ * This describes the interfaces necessary for a simple /proc file
+ * implementation for a driver.
+ *
+ ******************************************************************************
+ */
+
+#ifndef __EASYPROC_H__
+#define __EASYPROC_H__
+
+#include "timskmod.h"
+
+
+struct easyproc_driver_info {
+ struct proc_dir_entry *ProcDir;
+ struct proc_dir_entry *ProcDriverDir;
+ struct proc_dir_entry *ProcDriverDiagFile;
+ struct proc_dir_entry *ProcDeviceDir;
+ char *ProcId;
+ void (*Show_device_info)(struct seq_file *seq, void *p);
+ void (*Show_driver_info)(struct seq_file *seq);
+ void (*Write_device_info)(char *buf, size_t count,
+ loff_t *ppos, void *p);
+ void (*Write_driver_info)(char *buf, size_t count, loff_t *ppos);
+};
+
+/* property is a file under /proc/<x>/device/<x>/<property_name> */
+struct easyproc_device_property_info {
+ char property_name[25];
+ struct proc_dir_entry *procEntry;
+ struct easyproc_driver_info *pdriver;
+ void *devdata;
+ void (*show_device_property_info)(struct seq_file *seq, void *p);
+};
+
+struct easyproc_device_info {
+ struct proc_dir_entry *procDevicexDir;
+ struct proc_dir_entry *procDevicexDiagFile;
+ struct easyproc_driver_info *pdriver;
+ void *devdata;
+ int devno;
+ /* allow for a number of custom properties for each device: */
+ struct easyproc_device_property_info device_property_info[10];
+};
+
+void visor_easyproc_InitDevice(struct easyproc_driver_info *pdriver,
+ struct easyproc_device_info *p, int devno,
+ void *devdata);
+void visor_easyproc_DeInitDevice(struct easyproc_driver_info *pdriver,
+ struct easyproc_device_info *p, int devno);
+void visor_easyproc_InitDriver(struct easyproc_driver_info *pdriver,
+ char *procId,
+ void (*show_driver_info)(struct seq_file *),
+ void (*show_device_info)(struct seq_file *,
+ void *));
+void visor_easyproc_InitDriverEx(struct easyproc_driver_info *pdriver,
+ char *procId,
+ void (*show_driver_info)(struct seq_file *),
+ void (*show_device_info)(struct seq_file *,
+ void *),
+ void (*Write_driver_info)(char *buf,
+ size_t count,
+ loff_t *ppos),
+ void (*Write_device_info)(char *buf,
+ size_t count,
+ loff_t *ppos,
+ void *p));
+void visor_easyproc_DeInitDriver(struct easyproc_driver_info *pdriver);
+void visor_easyproc_CreateDeviceProperty(struct easyproc_device_info *p,
+ void (*show_property_info)
+ (struct seq_file *, void *),
+ char *property_name);
+
+#endif
diff --git a/drivers/staging/unisys/visorutil/memregion.h b/drivers/staging/unisys/visorutil/memregion.h
new file mode 100644
index 000000000000..bb122dbeafbc
--- /dev/null
+++ b/drivers/staging/unisys/visorutil/memregion.h
@@ -0,0 +1,43 @@
+/* memregion.h
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __MEMREGION_H__
+#define __MEMREGION_H__
+
+#include "timskmod.h"
+
+/* MEMREGION is an opaque structure to users.
+ * Fields are declared only in the implementation .c files.
+ */
+typedef struct MEMREGION_Tag MEMREGION;
+
+MEMREGION *visor_memregion_create(HOSTADDRESS physaddr, ulong nbytes);
+MEMREGION *visor_memregion_create_overlapped(MEMREGION *parent,
+ ulong offset, ulong nbytes);
+int visor_memregion_resize(MEMREGION *memregion, ulong newsize);
+int visor_memregion_read(MEMREGION *memregion,
+ ulong offset, void *dest, ulong nbytes);
+int visor_memregion_write(MEMREGION *memregion,
+ ulong offset, void *src, ulong nbytes);
+void visor_memregion_destroy(MEMREGION *memregion);
+HOSTADDRESS visor_memregion_get_physaddr(MEMREGION *memregion);
+ulong visor_memregion_get_nbytes(MEMREGION *memregion);
+void memregion_dump(MEMREGION *memregion, char *s,
+ ulong off, ulong len, struct seq_file *seq);
+void *visor_memregion_get_pointer(MEMREGION *memregion);
+
+#endif
diff --git a/drivers/staging/unisys/visorutil/memregion_direct.c b/drivers/staging/unisys/visorutil/memregion_direct.c
new file mode 100644
index 000000000000..2c1061d55ee9
--- /dev/null
+++ b/drivers/staging/unisys/visorutil/memregion_direct.c
@@ -0,0 +1,223 @@
+/* memregion_direct.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * This is an implementation of memory regions that can be used to read/write
+ * channel memory (in main memory of the host system) from code running in
+ * a virtual partition.
+ */
+#include "uniklog.h"
+#include "timskmod.h"
+#include "memregion.h"
+
+#define MYDRVNAME "memregion"
+
+struct MEMREGION_Tag {
+ HOSTADDRESS physaddr;
+ ulong nbytes;
+ void *mapped;
+ BOOL requested;
+ BOOL overlapped;
+};
+
+static BOOL mapit(MEMREGION *memregion);
+static void unmapit(MEMREGION *memregion);
+
+MEMREGION *
+visor_memregion_create(HOSTADDRESS physaddr, ulong nbytes)
+{
+ MEMREGION *rc = NULL;
+ MEMREGION *memregion = kzalloc(sizeof(MEMREGION),
+ GFP_KERNEL | __GFP_NORETRY);
+ if (memregion == NULL) {
+ ERRDRV("visor_memregion_create allocation failed");
+ return NULL;
+ }
+ memregion->physaddr = physaddr;
+ memregion->nbytes = nbytes;
+ memregion->overlapped = FALSE;
+ if (!mapit(memregion)) {
+ rc = NULL;
+ goto Away;
+ }
+ rc = memregion;
+Away:
+ if (rc == NULL) {
+ if (memregion != NULL) {
+ visor_memregion_destroy(memregion);
+ memregion = NULL;
+ }
+ }
+ return rc;
+}
+EXPORT_SYMBOL_GPL(visor_memregion_create);
+
+MEMREGION *
+visor_memregion_create_overlapped(MEMREGION *parent, ulong offset, ulong nbytes)
+{
+ MEMREGION *memregion = NULL;
+
+ if (parent == NULL) {
+ ERRDRV("%s parent is NULL", __func__);
+ return NULL;
+ }
+ if (parent->mapped == NULL) {
+ ERRDRV("%s parent is not mapped!", __func__);
+ return NULL;
+ }
+ if ((offset >= parent->nbytes) ||
+ ((offset + nbytes) >= parent->nbytes)) {
+ ERRDRV("%s range (%lu,%lu) out of parent range",
+ __func__, offset, nbytes);
+ return NULL;
+ }
+ memregion = kzalloc(sizeof(MEMREGION), GFP_KERNEL|__GFP_NORETRY);
+ if (memregion == NULL) {
+ ERRDRV("%s allocation failed", __func__);
+ return NULL;
+ }
+
+ memregion->physaddr = parent->physaddr + offset;
+ memregion->nbytes = nbytes;
+ memregion->mapped = ((u8 *) (parent->mapped)) + offset;
+ memregion->requested = FALSE;
+ memregion->overlapped = TRUE;
+ return memregion;
+}
+EXPORT_SYMBOL_GPL(visor_memregion_create_overlapped);
+
+
+static BOOL
+mapit(MEMREGION *memregion)
+{
+ ulong physaddr = (ulong) (memregion->physaddr);
+ ulong nbytes = memregion->nbytes;
+
+ memregion->requested = FALSE;
+ if (!request_mem_region(physaddr, nbytes, MYDRVNAME))
+ ERRDRV("cannot reserve channel memory @0x%lx for 0x%lx-- no big deal", physaddr, nbytes);
+ else
+ memregion->requested = TRUE;
+ memregion->mapped = ioremap_cache(physaddr, nbytes);
+ if (memregion->mapped == NULL) {
+ ERRDRV("cannot ioremap_cache channel memory @0x%lx for 0x%lx",
+ physaddr, nbytes);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+unmapit(MEMREGION *memregion)
+{
+ if (memregion->mapped != NULL) {
+ iounmap(memregion->mapped);
+ memregion->mapped = NULL;
+ }
+ if (memregion->requested) {
+ release_mem_region((ulong) (memregion->physaddr),
+ memregion->nbytes);
+ memregion->requested = FALSE;
+ }
+}
+
+HOSTADDRESS
+visor_memregion_get_physaddr(MEMREGION *memregion)
+{
+ return memregion->physaddr;
+}
+EXPORT_SYMBOL_GPL(visor_memregion_get_physaddr);
+
+ulong
+visor_memregion_get_nbytes(MEMREGION *memregion)
+{
+ return memregion->nbytes;
+}
+EXPORT_SYMBOL_GPL(visor_memregion_get_nbytes);
+
+void *
+visor_memregion_get_pointer(MEMREGION *memregion)
+{
+ return memregion->mapped;
+}
+EXPORT_SYMBOL_GPL(visor_memregion_get_pointer);
+
+int
+visor_memregion_resize(MEMREGION *memregion, ulong newsize)
+{
+ if (newsize == memregion->nbytes)
+ return 0;
+ if (memregion->overlapped)
+ /* no error check here - we no longer know the
+ * parent's range!
+ */
+ memregion->nbytes = newsize;
+ else {
+ unmapit(memregion);
+ memregion->nbytes = newsize;
+ if (!mapit(memregion))
+ return -1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(visor_memregion_resize);
+
+
+static int
+memregion_readwrite(BOOL is_write,
+ MEMREGION *memregion, ulong offset,
+ void *local, ulong nbytes)
+{
+ if (offset + nbytes > memregion->nbytes) {
+ ERRDRV("memregion_readwrite offset out of range!!");
+ return -EFAULT;
+ }
+ if (is_write)
+ memcpy_toio(memregion->mapped + offset, local, nbytes);
+ else
+ memcpy_fromio(local, memregion->mapped + offset, nbytes);
+
+ return 0;
+}
+
+int
+visor_memregion_read(MEMREGION *memregion, ulong offset, void *dest,
+ ulong nbytes)
+{
+ return memregion_readwrite(FALSE, memregion, offset, dest, nbytes);
+}
+EXPORT_SYMBOL_GPL(visor_memregion_read);
+
+int
+visor_memregion_write(MEMREGION *memregion, ulong offset, void *src,
+ ulong nbytes)
+{
+ return memregion_readwrite(TRUE, memregion, offset, src, nbytes);
+}
+EXPORT_SYMBOL_GPL(visor_memregion_write);
+
+void
+visor_memregion_destroy(MEMREGION *memregion)
+{
+ if (memregion == NULL)
+ return;
+ if (!memregion->overlapped)
+ unmapit(memregion);
+ kfree(memregion);
+}
+EXPORT_SYMBOL_GPL(visor_memregion_destroy);
+
diff --git a/drivers/staging/unisys/visorutil/periodic_work.c b/drivers/staging/unisys/visorutil/periodic_work.c
new file mode 100644
index 000000000000..0670a3174682
--- /dev/null
+++ b/drivers/staging/unisys/visorutil/periodic_work.c
@@ -0,0 +1,236 @@
+/* periodic_work.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * Helper functions to schedule periodic work in Linux kernel mode.
+ */
+
+#include "uniklog.h"
+#include "timskmod.h"
+#include "periodic_work.h"
+
+#define MYDRVNAME "periodic_work"
+
+
+
+struct PERIODIC_WORK_Tag {
+ rwlock_t lock;
+ struct delayed_work work;
+ void (*workfunc)(void *);
+ void *workfuncarg;
+ BOOL is_scheduled;
+ BOOL want_to_stop;
+ ulong jiffy_interval;
+ struct workqueue_struct *workqueue;
+ const char *devnam;
+};
+
+
+
+static void periodic_work_func(struct work_struct *work)
+{
+ PERIODIC_WORK *periodic_work =
+ container_of(work, struct PERIODIC_WORK_Tag, work.work);
+ (*periodic_work->workfunc)(periodic_work->workfuncarg);
+}
+
+
+
+PERIODIC_WORK *visor_periodic_work_create(ulong jiffy_interval,
+ struct workqueue_struct *workqueue,
+ void (*workfunc)(void *),
+ void *workfuncarg,
+ const char *devnam)
+{
+ PERIODIC_WORK *periodic_work = kzalloc(sizeof(PERIODIC_WORK),
+ GFP_KERNEL | __GFP_NORETRY);
+ if (periodic_work == NULL) {
+ ERRDRV("periodic_work allocation failed ");
+ return NULL;
+ }
+ rwlock_init(&periodic_work->lock);
+ periodic_work->jiffy_interval = jiffy_interval;
+ periodic_work->workqueue = workqueue;
+ periodic_work->workfunc = workfunc;
+ periodic_work->workfuncarg = workfuncarg;
+ periodic_work->devnam = devnam;
+ return periodic_work;
+}
+EXPORT_SYMBOL_GPL(visor_periodic_work_create);
+
+
+
+void visor_periodic_work_destroy(PERIODIC_WORK *periodic_work)
+{
+ if (periodic_work == NULL)
+ return;
+ kfree(periodic_work);
+}
+EXPORT_SYMBOL_GPL(visor_periodic_work_destroy);
+
+
+
+/** Call this from your periodic work worker function to schedule the next
+ * call.
+ * If this function returns FALSE, there was a failure and the
+ * periodic work is no longer scheduled
+ */
+BOOL visor_periodic_work_nextperiod(PERIODIC_WORK *periodic_work)
+{
+ BOOL rc = FALSE;
+ write_lock(&periodic_work->lock);
+ if (periodic_work->want_to_stop) {
+ periodic_work->is_scheduled = FALSE;
+ periodic_work->want_to_stop = FALSE;
+ rc = TRUE; /* yes, TRUE; see visor_periodic_work_stop() */
+ goto Away;
+ } else if (queue_delayed_work(periodic_work->workqueue,
+ &periodic_work->work,
+ periodic_work->jiffy_interval) < 0) {
+ ERRDEV(periodic_work->devnam, "queue_delayed_work failed!");
+ periodic_work->is_scheduled = FALSE;
+ rc = FALSE;
+ goto Away;
+ }
+ rc = TRUE;
+Away:
+ write_unlock(&periodic_work->lock);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(visor_periodic_work_nextperiod);
+
+
+
+/** This function returns TRUE iff new periodic work was actually started.
+ * If this function returns FALSE, then no work was started
+ * (either because it was already started, or because of a failure).
+ */
+BOOL visor_periodic_work_start(PERIODIC_WORK *periodic_work)
+{
+ BOOL rc = FALSE;
+
+ write_lock(&periodic_work->lock);
+ if (periodic_work->is_scheduled) {
+ rc = FALSE;
+ goto Away;
+ }
+ if (periodic_work->want_to_stop) {
+ ERRDEV(periodic_work->devnam,
+ "dev_start_periodic_work failed!");
+ rc = FALSE;
+ goto Away;
+ }
+ INIT_DELAYED_WORK(&periodic_work->work, &periodic_work_func);
+ if (queue_delayed_work(periodic_work->workqueue,
+ &periodic_work->work,
+ periodic_work->jiffy_interval) < 0) {
+ ERRDEV(periodic_work->devnam,
+ "%s queue_delayed_work failed!", __func__);
+ rc = FALSE;
+ goto Away;
+ }
+ periodic_work->is_scheduled = TRUE;
+ rc = TRUE;
+Away:
+ write_unlock(&periodic_work->lock);
+ return rc;
+
+}
+EXPORT_SYMBOL_GPL(visor_periodic_work_start);
+
+
+
+
+/** This function returns TRUE iff your call actually stopped the periodic
+ * work.
+ *
+ * -- PAY ATTENTION... this is important --
+ *
+ * NO NO #1
+ *
+ * Do NOT call this function from some function that is running on the
+ * same workqueue as the work you are trying to stop might be running
+ * on! If you violate this rule, visor_periodic_work_stop() MIGHT work,
+ * but it also MIGHT get hung up in an infinite loop saying
+ * "waiting for delayed work...". This will happen if the delayed work
+ * you are trying to cancel has been put in the workqueue list, but can't
+ * run yet because we are running that same workqueue thread right now.
+ *
+ * Bottom line: If you need to call visor_periodic_work_stop() from a
+ * workitem, be sure the workitem is on a DIFFERENT workqueue than the
+ * workitem that you are trying to cancel.
+ *
+ * If I could figure out some way to check for this "no no" condition in
+ * the code, I would. It would have saved me the trouble of writing this
+ * long comment. And also, don't think this is some "theoretical" race
+ * condition. It is REAL, as I have spent the day chasing it.
+ *
+ * NO NO #2
+ *
+ * Take close note of the locks that you own when you call this function.
+ * You must NOT own any locks that are needed by the periodic work
+ * function that is currently installed. If you DO, a deadlock may result,
+ * because stopping the periodic work often involves waiting for the last
+ * iteration of the periodic work function to complete. Again, if you hit
+ * this deadlock, you will get hung up in an infinite loop saying
+ * "waiting for delayed work...".
+ */
+BOOL visor_periodic_work_stop(PERIODIC_WORK *periodic_work)
+{
+ BOOL stopped_something = FALSE;
+
+ write_lock(&periodic_work->lock);
+ stopped_something = periodic_work->is_scheduled &&
+ (!periodic_work->want_to_stop);
+ while (periodic_work->is_scheduled) {
+ periodic_work->want_to_stop = TRUE;
+ if (cancel_delayed_work(&periodic_work->work)) {
+ /* We get here if the delayed work was pending as
+ * delayed work, but was NOT run.
+ */
+ ASSERT(periodic_work->is_scheduled);
+ periodic_work->is_scheduled = FALSE;
+ } else {
+ /* If we get here, either the delayed work:
+ * - was run, OR,
+ * - is running RIGHT NOW on another processor, OR,
+ * - wasn't even scheduled (there is a miniscule
+ * timing window where this could be the case)
+ * flush_workqueue() would make sure it is finished
+ * executing, but that still isn't very useful, which
+ * explains the loop...
+ */
+ }
+ if (periodic_work->is_scheduled) {
+ write_unlock(&periodic_work->lock);
+ WARNDEV(periodic_work->devnam,
+ "waiting for delayed work...");
+ /* We rely on the delayed work function running here,
+ * and eventually calling
+ * visor_periodic_work_nextperiod(),
+ * which will see that want_to_stop is set, and
+ * subsequently clear is_scheduled.
+ */
+ SLEEPJIFFIES(10);
+ write_lock(&periodic_work->lock);
+ } else
+ periodic_work->want_to_stop = FALSE;
+ }
+ write_unlock(&periodic_work->lock);
+ return stopped_something;
+}
+EXPORT_SYMBOL_GPL(visor_periodic_work_stop);
diff --git a/drivers/staging/unisys/visorutil/procobjecttree.c b/drivers/staging/unisys/visorutil/procobjecttree.c
new file mode 100644
index 000000000000..67a19e1c7b02
--- /dev/null
+++ b/drivers/staging/unisys/visorutil/procobjecttree.c
@@ -0,0 +1,348 @@
+/* procobjecttree.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#include "procobjecttree.h"
+
+#define MYDRVNAME "procobjecttree"
+
+
+
+/** This is context info that we stash in each /proc file entry, which we
+ * need in order to call the callback function that supplies the /proc read
+ * info for that file.
+ */
+typedef struct {
+ void (*show_property)(struct seq_file *, void *, int);
+ MYPROCOBJECT *procObject;
+ int propertyIndex;
+
+} PROCDIRENTRYCONTEXT;
+
+/** This describes the attributes of a tree rooted at
+ * <procDirRoot>/<name[0]>/<name[1]>/...
+ * Properties for each object of this type will be located under
+ * <procDirRoot>/<name[0]>/<name[1]>/.../<objectName>/<propertyName>.
+ */
+struct MYPROCTYPE_Tag {
+ const char **name; /**< node names for this type, ending with NULL */
+ int nNames; /**< num of node names in <name> */
+
+ /** root dir for this type tree in /proc */
+ struct proc_dir_entry *procDirRoot;
+
+ struct proc_dir_entry **procDirs; /**< for each node in <name> */
+
+ /** bottom dir where objects will be rooted; i.e., this is
+ * <procDirRoot>/<name[0]>/<name[1]>/.../, which is the same as the
+ * last entry in the <procDirs> array. */
+ struct proc_dir_entry *procDir;
+
+ /** name for each property that objects of this type can have */
+ const char **propertyNames;
+
+ int nProperties; /**< num of names in <propertyNames> */
+
+ /** Call this, passing MYPROCOBJECT.context and the property index
+ * whenever someone reads the proc entry */
+ void (*show_property)(struct seq_file *, void *, int);
+};
+
+
+
+struct MYPROCOBJECT_Tag {
+ MYPROCTYPE *type;
+
+ /** This is the name of the dir node in /proc under which the
+ * properties of this object will appear as files. */
+ char *name;
+
+ int namesize; /**< number of bytes allocated for name */
+ void *context; /**< passed to MYPROCTYPE.show_property */
+
+ /** <type.procDirRoot>/<type.name[0]>/<type.name[1]>/.../<name> */
+ struct proc_dir_entry *procDir;
+
+ /** a proc dir entry for each of the properties of the object;
+ * properties are identified in MYPROCTYPE.propertyNames, so each of
+ * the <procDirProperties> describes a single file like
+ * <type.procDirRoot>/<type.name[0]>/<type.name[1]>/...
+ * /<name>/<propertyName>
+ */
+ struct proc_dir_entry **procDirProperties;
+
+ /** this is a holding area for the context information that is needed
+ * to run the /proc callback function */
+ PROCDIRENTRYCONTEXT *procDirPropertyContexts;
+};
+
+
+
+static struct proc_dir_entry *
+createProcDir(const char *name, struct proc_dir_entry *parent)
+{
+ struct proc_dir_entry *p = proc_mkdir_mode(name, S_IFDIR, parent);
+ if (p == NULL)
+ ERRDRV("failed to create /proc directory %s", name);
+ return p;
+}
+
+static struct proc_dir_entry *
+createProcFile(const char *name, struct proc_dir_entry *parent,
+ const struct file_operations *fops, void *data)
+{
+ struct proc_dir_entry *p = proc_create_data(name, 0, parent,
+ fops, data);
+ if (p == NULL)
+ ERRDRV("failed to create /proc file %s", name);
+ return p;
+}
+
+static int seq_show(struct seq_file *seq, void *offset);
+static int proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, seq_show, PDE_DATA(inode));
+}
+
+static const struct file_operations proc_fops = {
+ .open = proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
+
+MYPROCTYPE *visor_proc_CreateType(struct proc_dir_entry *procDirRoot,
+ const char **name,
+ const char **propertyNames,
+ void (*show_property)(struct seq_file *,
+ void *, int))
+{
+ int i = 0;
+ MYPROCTYPE *rc = NULL, *type = NULL;
+ struct proc_dir_entry *parent = NULL;
+
+ if (procDirRoot == NULL) {
+ ERRDRV("procDirRoot cannot be NULL!\n");
+ goto Away;
+ }
+ if (name == NULL || name[0] == NULL) {
+ ERRDRV("name must contain at least 1 node name!\n");
+ goto Away;
+ }
+ type = kzalloc(sizeof(MYPROCTYPE), GFP_KERNEL | __GFP_NORETRY);
+ if (type == NULL) {
+ ERRDRV("out of memory\n");
+ goto Away;
+ }
+ type->name = name;
+ type->propertyNames = propertyNames;
+ type->nProperties = 0;
+ type->nNames = 0;
+ type->show_property = show_property;
+ type->procDirRoot = procDirRoot;
+ if (type->propertyNames != NULL)
+ while (type->propertyNames[type->nProperties] != NULL)
+ type->nProperties++;
+ while (type->name[type->nNames] != NULL)
+ type->nNames++;
+ type->procDirs = kzalloc((type->nNames + 1) *
+ sizeof(struct proc_dir_entry *),
+ GFP_KERNEL | __GFP_NORETRY);
+ if (type->procDirs == NULL) {
+ ERRDRV("out of memory\n");
+ goto Away;
+ }
+ parent = procDirRoot;
+ for (i = 0; i < type->nNames; i++) {
+ type->procDirs[i] = createProcDir(type->name[i], parent);
+ if (type->procDirs[i] == NULL) {
+ rc = NULL;
+ goto Away;
+ }
+ parent = type->procDirs[i];
+ }
+ type->procDir = type->procDirs[type->nNames-1];
+ rc = type;
+Away:
+ if (rc == NULL) {
+ if (type != NULL) {
+ visor_proc_DestroyType(type);
+ type = NULL;
+ }
+ }
+ return rc;
+}
+EXPORT_SYMBOL_GPL(visor_proc_CreateType);
+
+
+
+void visor_proc_DestroyType(MYPROCTYPE *type)
+{
+ if (type == NULL)
+ return;
+ if (type->procDirs != NULL) {
+ int i = type->nNames-1;
+ while (i >= 0) {
+ if (type->procDirs[i] != NULL) {
+ struct proc_dir_entry *parent = NULL;
+ if (i == 0)
+ parent = type->procDirRoot;
+ else
+ parent = type->procDirs[i-1];
+ remove_proc_entry(type->name[i], parent);
+ }
+ i--;
+ }
+ kfree(type->procDirs);
+ type->procDirs = NULL;
+ }
+ kfree(type);
+}
+EXPORT_SYMBOL_GPL(visor_proc_DestroyType);
+
+
+
+MYPROCOBJECT *visor_proc_CreateObject(MYPROCTYPE *type,
+ const char *name, void *context)
+{
+ MYPROCOBJECT *obj = NULL, *rc = NULL;
+ int i = 0;
+
+ if (type == NULL) {
+ ERRDRV("type cannot be NULL\n");
+ goto Away;
+ }
+ obj = kzalloc(sizeof(MYPROCOBJECT), GFP_KERNEL | __GFP_NORETRY);
+ if (obj == NULL) {
+ ERRDRV("out of memory\n");
+ goto Away;
+ }
+ obj->type = type;
+ obj->context = context;
+ if (name == NULL) {
+ obj->name = NULL;
+ obj->procDir = type->procDir;
+ } else {
+ obj->namesize = strlen(name)+1;
+ obj->name = kmalloc(obj->namesize, GFP_KERNEL | __GFP_NORETRY);
+ if (obj->name == NULL) {
+ obj->namesize = 0;
+ ERRDRV("out of memory\n");
+ goto Away;
+ }
+ strcpy(obj->name, name);
+ obj->procDir = createProcDir(obj->name, type->procDir);
+ if (obj->procDir == NULL) {
+ goto Away;
+ }
+ }
+ obj->procDirPropertyContexts =
+ kzalloc((type->nProperties + 1) * sizeof(PROCDIRENTRYCONTEXT),
+ GFP_KERNEL | __GFP_NORETRY);
+ if (obj->procDirPropertyContexts == NULL) {
+ ERRDRV("out of memory\n");
+ goto Away;
+ }
+ obj->procDirProperties =
+ kzalloc((type->nProperties + 1) * sizeof(struct proc_dir_entry *),
+ GFP_KERNEL | __GFP_NORETRY);
+ if (obj->procDirProperties == NULL) {
+ ERRDRV("out of memory\n");
+ goto Away;
+ }
+ for (i = 0; i < type->nProperties; i++) {
+ obj->procDirPropertyContexts[i].procObject = obj;
+ obj->procDirPropertyContexts[i].propertyIndex = i;
+ obj->procDirPropertyContexts[i].show_property =
+ type->show_property;
+ if (type->propertyNames[i][0] != '\0') {
+ /* only create properties that have names */
+ obj->procDirProperties[i] =
+ createProcFile(type->propertyNames[i],
+ obj->procDir, &proc_fops,
+ &obj->procDirPropertyContexts[i]);
+ if (obj->procDirProperties[i] == NULL) {
+ rc = NULL;
+ goto Away;
+ }
+ }
+ }
+ rc = obj;
+Away:
+ if (rc == NULL) {
+ if (obj != NULL) {
+ visor_proc_DestroyObject(obj);
+ obj = NULL;
+ }
+ }
+ return rc;
+}
+EXPORT_SYMBOL_GPL(visor_proc_CreateObject);
+
+
+
+void visor_proc_DestroyObject(MYPROCOBJECT *obj)
+{
+ MYPROCTYPE *type = NULL;
+ if (obj == NULL)
+ return;
+ type = obj->type;
+ if (type == NULL)
+ return;
+ if (obj->procDirProperties != NULL) {
+ int i = 0;
+ for (i = 0; i < type->nProperties; i++) {
+ if (obj->procDirProperties[i] != NULL) {
+ remove_proc_entry(type->propertyNames[i],
+ obj->procDir);
+ obj->procDirProperties[i] = NULL;
+ }
+ }
+ kfree(obj->procDirProperties);
+ obj->procDirProperties = NULL;
+ }
+ if (obj->procDirPropertyContexts != NULL) {
+ kfree(obj->procDirPropertyContexts);
+ obj->procDirPropertyContexts = NULL;
+ }
+ if (obj->procDir != NULL) {
+ if (obj->name != NULL)
+ remove_proc_entry(obj->name, type->procDir);
+ obj->procDir = NULL;
+ }
+ if (obj->name != NULL) {
+ kfree(obj->name);
+ obj->name = NULL;
+ }
+ kfree(obj);
+}
+EXPORT_SYMBOL_GPL(visor_proc_DestroyObject);
+
+
+
+static int seq_show(struct seq_file *seq, void *offset)
+{
+ PROCDIRENTRYCONTEXT *ctx = (PROCDIRENTRYCONTEXT *)(seq->private);
+ if (ctx == NULL) {
+ ERRDRV("I don't have a freakin' clue...");
+ return 0;
+ }
+ (*ctx->show_property)(seq, ctx->procObject->context,
+ ctx->propertyIndex);
+ return 0;
+}
diff --git a/drivers/staging/unisys/visorutil/visorkmodutils.c b/drivers/staging/unisys/visorutil/visorkmodutils.c
new file mode 100644
index 000000000000..a7d1e94ca3c3
--- /dev/null
+++ b/drivers/staging/unisys/visorutil/visorkmodutils.c
@@ -0,0 +1,71 @@
+/* timskmodutils.c
+ *
+ * Copyright © 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#include "uniklog.h"
+#include "timskmod.h"
+
+#define MYDRVNAME "timskmodutils"
+
+/** Callers to interfaces that set __GFP_NORETRY flag below
+ * must check for a NULL (error) result as we are telling the
+ * kernel interface that it is okay to fail.
+ */
+
+void *kmalloc_kernel(size_t siz)
+{
+ return kmalloc(siz, GFP_KERNEL | __GFP_NORETRY);
+}
+
+/* Use these handy-dandy seq_file_xxx functions if you want to call some
+ * functions that write stuff into a seq_file, but you actually just want
+ * to dump that output into a buffer. Use them as follows:
+ * - call visor_seq_file_new_buffer to create the seq_file (you supply the buf)
+ * - call whatever functions you want that take a seq_file as an argument
+ * (the buf you supplied will get the output data)
+ * - call visor_seq_file_done_buffer to dispose of your seq_file
+ */
+struct seq_file *visor_seq_file_new_buffer(void *buf, size_t buf_size)
+{
+ struct seq_file *rc = NULL;
+ struct seq_file *m = kmalloc_kernel(sizeof(struct seq_file));
+
+ if (m == NULL) {
+ rc = NULL;
+ goto Away;
+ }
+ memset(m, 0, sizeof(struct seq_file));
+ m->buf = buf;
+ m->size = buf_size;
+ rc = m;
+Away:
+ if (rc == NULL) {
+ visor_seq_file_done_buffer(m);
+ m = NULL;
+ }
+ return rc;
+}
+EXPORT_SYMBOL_GPL(visor_seq_file_new_buffer);
+
+
+
+void visor_seq_file_done_buffer(struct seq_file *m)
+{
+ if (!m)
+ return;
+ kfree(m);
+}
+EXPORT_SYMBOL_GPL(visor_seq_file_done_buffer);
diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h
index a73e437ec215..266e2b0ce9a8 100644
--- a/drivers/staging/usbip/stub.h
+++ b/drivers/staging/usbip/stub.h
@@ -86,6 +86,7 @@ struct bus_id_priv {
char status;
int interf_count;
struct stub_device *sdev;
+ struct usb_device *udev;
char shutdown_busid;
};
@@ -93,7 +94,7 @@ struct bus_id_priv {
extern struct kmem_cache *stub_priv_cache;
/* stub_dev.c */
-extern struct usb_driver stub_driver;
+extern struct usb_device_driver stub_driver;
/* stub_main.c */
struct bus_id_priv *get_busid_priv(const char *busid);
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
index 76a1ff0e6275..773d8ca07a00 100644
--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -87,13 +87,16 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
int sockfd = 0;
struct socket *socket;
ssize_t err = -EINVAL;
+ int rv;
if (!sdev) {
dev_err(dev, "sdev is null\n");
return -ENODEV;
}
- sscanf(buf, "%d", &sockfd);
+ rv = sscanf(buf, "%d", &sockfd);
+ if (rv != 1)
+ return -EINVAL;
if (sockfd != -1) {
dev_info(dev, "stub up\n");
@@ -279,21 +282,19 @@ static void stub_device_unusable(struct usbip_device *ud)
*
* Allocates and initializes a new stub_device struct.
*/
-static struct stub_device *stub_device_alloc(struct usb_device *udev,
- struct usb_interface *interface)
+static struct stub_device *stub_device_alloc(struct usb_device *udev)
{
struct stub_device *sdev;
- int busnum = interface_to_busnum(interface);
- int devnum = interface_to_devnum(interface);
+ int busnum = udev->bus->busnum;
+ int devnum = udev->devnum;
- dev_dbg(&interface->dev, "allocating stub device");
+ dev_dbg(&udev->dev, "allocating stub device");
/* yes, it's a new device */
sdev = kzalloc(sizeof(struct stub_device), GFP_KERNEL);
if (!sdev)
return NULL;
- sdev->interface = usb_get_intf(interface);
sdev->udev = usb_get_dev(udev);
/*
@@ -322,7 +323,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev,
usbip_start_eh(&sdev->ud);
- dev_dbg(&interface->dev, "register new interface\n");
+ dev_dbg(&udev->dev, "register new device\n");
return sdev;
}
@@ -332,32 +333,21 @@ static void stub_device_free(struct stub_device *sdev)
kfree(sdev);
}
-/*
- * If a usb device has multiple active interfaces, this driver is bound to all
- * the active interfaces. However, usbip exports *a* usb device (i.e., not *an*
- * active interface). Currently, a userland program must ensure that it
- * looks at the usbip's sysfs entries of only the first active interface.
- *
- * TODO: use "struct usb_device_driver" to bind a usb device.
- * However, it seems it is not fully supported in mainline kernel yet
- * (2.6.19.2).
- */
-static int stub_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
+static int stub_probe(struct usb_device *udev)
{
- struct usb_device *udev = interface_to_usbdev(interface);
struct stub_device *sdev = NULL;
- const char *udev_busid = dev_name(interface->dev.parent);
+ const char *udev_busid = dev_name(&udev->dev);
int err = 0;
struct bus_id_priv *busid_priv;
+ int rc;
- dev_dbg(&interface->dev, "Enter\n");
+ dev_dbg(&udev->dev, "Enter\n");
/* check we should claim or not by busid_table */
busid_priv = get_busid_priv(udev_busid);
if (!busid_priv || (busid_priv->status == STUB_BUSID_REMOV) ||
(busid_priv->status == STUB_BUSID_OTHER)) {
- dev_info(&interface->dev,
+ dev_info(&udev->dev,
"%s is not in match_busid table... skip!\n",
udev_busid);
@@ -383,60 +373,41 @@ static int stub_probe(struct usb_interface *interface,
return -ENODEV;
}
- if (busid_priv->status == STUB_BUSID_ALLOC) {
- sdev = busid_priv->sdev;
- if (!sdev)
- return -ENODEV;
-
- busid_priv->interf_count++;
- dev_info(&interface->dev,
- "usbip-host: register new interface (bus %u dev %u ifn %u)\n",
- udev->bus->busnum, udev->devnum,
- interface->cur_altsetting->desc.bInterfaceNumber);
-
- /* set private data to usb_interface */
- usb_set_intfdata(interface, sdev);
-
- err = stub_add_files(&interface->dev);
- if (err) {
- dev_err(&interface->dev, "stub_add_files for %s\n",
- udev_busid);
- usb_set_intfdata(interface, NULL);
- busid_priv->interf_count--;
- return err;
- }
-
- usb_get_intf(interface);
- return 0;
- }
-
/* ok, this is my device */
- sdev = stub_device_alloc(udev, interface);
+ sdev = stub_device_alloc(udev);
if (!sdev)
return -ENOMEM;
- dev_info(&interface->dev,
- "usbip-host: register new device (bus %u dev %u ifn %u)\n",
- udev->bus->busnum, udev->devnum,
- interface->cur_altsetting->desc.bInterfaceNumber);
+ dev_info(&udev->dev,
+ "usbip-host: register new device (bus %u dev %u)\n",
+ udev->bus->busnum, udev->devnum);
- busid_priv->interf_count = 0;
busid_priv->shutdown_busid = 0;
- /* set private data to usb_interface */
- usb_set_intfdata(interface, sdev);
- busid_priv->interf_count++;
+ /* set private data to usb_device */
+ dev_set_drvdata(&udev->dev, sdev);
busid_priv->sdev = sdev;
+ busid_priv->udev = udev;
+
+ /*
+ * Claim this hub port.
+ * It doesn't matter what value we pass as owner
+ * (struct dev_state) as long as it is unique.
+ */
+ rc = usb_hub_claim_port(udev->parent, udev->portnum,
+ (struct usb_dev_state *) udev);
+ if (rc) {
+ dev_dbg(&udev->dev, "unable to claim port\n");
+ return rc;
+ }
- err = stub_add_files(&interface->dev);
+ err = stub_add_files(&udev->dev);
if (err) {
- dev_err(&interface->dev, "stub_add_files for %s\n", udev_busid);
- usb_set_intfdata(interface, NULL);
- usb_put_intf(interface);
+ dev_err(&udev->dev, "stub_add_files for %s\n", udev_busid);
+ dev_set_drvdata(&udev->dev, NULL);
usb_put_dev(udev);
kthread_stop_put(sdev->ud.eh);
- busid_priv->interf_count = 0;
busid_priv->sdev = NULL;
stub_device_free(sdev);
return err;
@@ -461,13 +432,14 @@ static void shutdown_busid(struct bus_id_priv *busid_priv)
* called in usb_disconnect() or usb_deregister()
* but only if actconfig(active configuration) exists
*/
-static void stub_disconnect(struct usb_interface *interface)
+static void stub_disconnect(struct usb_device *udev)
{
struct stub_device *sdev;
- const char *udev_busid = dev_name(interface->dev.parent);
+ const char *udev_busid = dev_name(&udev->dev);
struct bus_id_priv *busid_priv;
+ int rc;
- dev_dbg(&interface->dev, "Enter\n");
+ dev_dbg(&udev->dev, "Enter\n");
busid_priv = get_busid_priv(udev_busid);
if (!busid_priv) {
@@ -475,41 +447,37 @@ static void stub_disconnect(struct usb_interface *interface)
return;
}
- sdev = usb_get_intfdata(interface);
+ sdev = dev_get_drvdata(&udev->dev);
/* get stub_device */
if (!sdev) {
- dev_err(&interface->dev, "could not get device");
+ dev_err(&udev->dev, "could not get device");
return;
}
- usb_set_intfdata(interface, NULL);
+ dev_set_drvdata(&udev->dev, NULL);
/*
* NOTE: rx/tx threads are invoked for each usb_device.
*/
- stub_remove_files(&interface->dev);
+ stub_remove_files(&udev->dev);
- /* If usb reset is called from event handler */
- if (busid_priv->sdev->ud.eh == current) {
- busid_priv->interf_count--;
+ /* release port */
+ rc = usb_hub_release_port(udev->parent, udev->portnum,
+ (struct usb_dev_state *) udev);
+ if (rc) {
+ dev_dbg(&udev->dev, "unable to release port\n");
return;
}
- if (busid_priv->interf_count > 1) {
- busid_priv->interf_count--;
- shutdown_busid(busid_priv);
- usb_put_intf(interface);
+ /* If usb reset is called from event handler */
+ if (busid_priv->sdev->ud.eh == current)
return;
- }
-
- busid_priv->interf_count = 0;
/* shutdown the current connection */
shutdown_busid(busid_priv);
usb_put_dev(sdev->udev);
- usb_put_intf(interface);
/* free sdev */
busid_priv->sdev = NULL;
@@ -523,28 +491,34 @@ static void stub_disconnect(struct usb_interface *interface)
}
}
-/*
- * Presence of pre_reset and post_reset prevents the driver from being unbound
- * when the device is being reset
- */
+#ifdef CONFIG_PM
-static int stub_pre_reset(struct usb_interface *interface)
+/* These functions need usb_port_suspend and usb_port_resume,
+ * which reside in drivers/usb/core/usb.h. Skip for now. */
+
+static int stub_suspend(struct usb_device *udev, pm_message_t message)
{
- dev_dbg(&interface->dev, "pre_reset\n");
+ dev_dbg(&udev->dev, "stub_suspend\n");
+
return 0;
}
-static int stub_post_reset(struct usb_interface *interface)
+static int stub_resume(struct usb_device *udev, pm_message_t message)
{
- dev_dbg(&interface->dev, "post_reset\n");
+ dev_dbg(&udev->dev, "stub_resume\n");
+
return 0;
}
-struct usb_driver stub_driver = {
+#endif /* CONFIG_PM */
+
+struct usb_device_driver stub_driver = {
.name = "usbip-host",
.probe = stub_probe,
.disconnect = stub_disconnect,
- .id_table = stub_table,
- .pre_reset = stub_pre_reset,
- .post_reset = stub_post_reset,
+#ifdef CONFIG_PM
+ .suspend = stub_suspend,
+ .resume = stub_resume,
+#endif
+ .supports_autosuspend = 0,
};
diff --git a/drivers/staging/usbip/stub_main.c b/drivers/staging/usbip/stub_main.c
index baf857f7cc88..9c5832abbdf1 100644
--- a/drivers/staging/usbip/stub_main.c
+++ b/drivers/staging/usbip/stub_main.c
@@ -19,6 +19,7 @@
#include <linux/string.h>
#include <linux/module.h>
+#include <linux/device.h>
#include "usbip_common.h"
#include "stub.h"
@@ -187,6 +188,34 @@ static ssize_t store_match_busid(struct device_driver *dev, const char *buf,
static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid,
store_match_busid);
+static ssize_t rebind_store(struct device_driver *dev, const char *buf,
+ size_t count)
+{
+ int ret;
+ int len;
+ struct bus_id_priv *bid;
+
+ /* buf length should be less that BUSID_SIZE */
+ len = strnlen(buf, BUSID_SIZE);
+
+ if (!(len < BUSID_SIZE))
+ return -EINVAL;
+
+ bid = get_busid_priv(buf);
+ if (!bid)
+ return -ENODEV;
+
+ ret = device_attach(&bid->udev->dev);
+ if (ret < 0) {
+ dev_err(&bid->udev->dev, "rebind failed\n");
+ return ret;
+ }
+
+ return count;
+}
+
+static DRIVER_ATTR_WO(rebind);
+
static struct stub_priv *stub_priv_pop_from_listhead(struct list_head *listhead)
{
struct stub_priv *priv, *tmp;
@@ -254,7 +283,7 @@ static int __init usbip_host_init(void)
return -ENOMEM;
}
- ret = usb_register(&stub_driver);
+ ret = usb_register_device_driver(&stub_driver, THIS_MODULE);
if (ret) {
pr_err("usb_register failed %d\n", ret);
goto err_usb_register;
@@ -267,11 +296,18 @@ static int __init usbip_host_init(void)
goto err_create_file;
}
+ ret = driver_create_file(&stub_driver.drvwrap.driver,
+ &driver_attr_rebind);
+ if (ret) {
+ pr_err("driver_create_file failed\n");
+ goto err_create_file;
+ }
+
pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");
return ret;
err_create_file:
- usb_deregister(&stub_driver);
+ usb_deregister_device_driver(&stub_driver);
err_usb_register:
kmem_cache_destroy(stub_priv_cache);
return ret;
@@ -282,11 +318,14 @@ static void __exit usbip_host_exit(void)
driver_remove_file(&stub_driver.drvwrap.driver,
&driver_attr_match_busid);
+ driver_remove_file(&stub_driver.drvwrap.driver,
+ &driver_attr_rebind);
+
/*
* deregister() calls stub_disconnect() for all devices. Device
* specific data is cleared in stub_disconnect().
*/
- usb_deregister(&stub_driver);
+ usb_deregister_device_driver(&stub_driver);
kmem_cache_destroy(stub_priv_cache);
}
diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c
index 5d1d4a183300..e0b6d6b42728 100644
--- a/drivers/staging/usbip/stub_rx.c
+++ b/drivers/staging/usbip/stub_rx.c
@@ -142,31 +142,19 @@ static int tweak_set_interface_cmd(struct urb *urb)
static int tweak_set_configuration_cmd(struct urb *urb)
{
+ struct stub_priv *priv = (struct stub_priv *) urb->context;
+ struct stub_device *sdev = priv->sdev;
struct usb_ctrlrequest *req;
__u16 config;
+ int err;
req = (struct usb_ctrlrequest *) urb->setup_packet;
config = le16_to_cpu(req->wValue);
- /*
- * I have never seen a multi-config device. Very rare.
- * For most devices, this will be called to choose a default
- * configuration only once in an initialization phase.
- *
- * set_configuration may change a device configuration and its device
- * drivers will be unbound and assigned for a new device configuration.
- * This means this usbip driver will be also unbound when called, then
- * eventually reassigned to the device as far as driver matching
- * condition is kept.
- *
- * Unfortunately, an existing usbip connection will be dropped
- * due to this driver unbinding. So, skip here.
- * A user may need to set a special configuration value before
- * exporting the device.
- */
- dev_info(&urb->dev->dev, "usb_set_configuration %d to %s... skip!\n",
- config, dev_name(&urb->dev->dev));
-
+ err = usb_set_configuration(sdev->udev, config);
+ if (err && err != -ENODEV)
+ dev_err(&sdev->udev->dev, "can't set config #%d, error %d\n",
+ config, err);
return 0;
}
@@ -550,7 +538,7 @@ static void stub_rx_pdu(struct usbip_device *ud)
int ret;
struct usbip_header pdu;
struct stub_device *sdev = container_of(ud, struct stub_device, ud);
- struct device *dev = &sdev->interface->dev;
+ struct device *dev = &sdev->udev->dev;
usbip_dbg_stub_rx("Enter\n");
diff --git a/drivers/staging/usbip/stub_tx.c b/drivers/staging/usbip/stub_tx.c
index cd5326ae38cc..1622563823a3 100644
--- a/drivers/staging/usbip/stub_tx.c
+++ b/drivers/staging/usbip/stub_tx.c
@@ -74,12 +74,12 @@ void stub_complete(struct urb *urb)
/* OK */
break;
case -ENOENT:
- dev_info(&urb->dev->dev, "stopped by a call to usb_kill_urb() "
- "because of cleaning up a virtual connection\n");
+ dev_info(&urb->dev->dev,
+ "stopped by a call to usb_kill_urb() because of cleaning up a virtual connection\n");
return;
case -ECONNRESET:
- dev_info(&urb->dev->dev, "unlinked by a call to "
- "usb_unlink_urb()\n");
+ dev_info(&urb->dev->dev,
+ "unlinked by a call to usb_unlink_urb()\n");
break;
case -EPIPE:
dev_info(&urb->dev->dev, "endpoint %d is stalled\n",
@@ -89,8 +89,9 @@ void stub_complete(struct urb *urb)
dev_info(&urb->dev->dev, "device removed?\n");
break;
default:
- dev_info(&urb->dev->dev, "urb completion with non-zero status "
- "%d\n", urb->status);
+ dev_info(&urb->dev->dev,
+ "urb completion with non-zero status %d\n",
+ urb->status);
break;
}
@@ -228,8 +229,7 @@ static int stub_send_ret_submit(struct stub_device *sdev)
if (txsize != sizeof(pdu_header) + urb->actual_length) {
dev_err(&sdev->interface->dev,
- "actual length of urb %d does not "
- "match iso packet sizes %zu\n",
+ "actual length of urb %d does not match iso packet sizes %zu\n",
urb->actual_length,
txsize-sizeof(pdu_header));
kfree(iov);
diff --git a/drivers/staging/usbip/uapi/usbip.h b/drivers/staging/usbip/uapi/usbip.h
new file mode 100644
index 000000000000..fa5db30ede36
--- /dev/null
+++ b/drivers/staging/usbip/uapi/usbip.h
@@ -0,0 +1,26 @@
+/*
+ * usbip.h
+ *
+ * USBIP uapi defines and function prototypes etc.
+*/
+
+#ifndef _UAPI_LINUX_USBIP_H
+#define _UAPI_LINUX_USBIP_H
+
+/* usbip device status - exported in usbip device sysfs status */
+enum usbip_device_status {
+ /* sdev is available. */
+ SDEV_ST_AVAILABLE = 0x01,
+ /* sdev is now used. */
+ SDEV_ST_USED,
+ /* sdev is unusable because of a fatal error. */
+ SDEV_ST_ERROR,
+
+ /* vdev does not connect a remote device. */
+ VDEV_ST_NULL,
+ /* vdev is used, but the USB address is not assigned yet */
+ VDEV_ST_NOTASSIGNED,
+ VDEV_ST_USED,
+ VDEV_ST_ERROR
+};
+#endif /* _UAPI_LINUX_USBIP_H */
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index 96552e3a1bfb..184fa70365db 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -55,7 +55,8 @@ static ssize_t usbip_debug_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
- sscanf(buf, "%lx", &usbip_debug_flag);
+ if (sscanf(buf, "%lx", &usbip_debug_flag) != 1)
+ return -EINVAL;
return count;
}
DEVICE_ATTR_RW(usbip_debug);
@@ -99,26 +100,8 @@ static void usbip_dump_usb_device(struct usb_device *udev)
struct device *dev = &udev->dev;
int i;
- dev_dbg(dev, " devnum(%d) devpath(%s) ",
- udev->devnum, udev->devpath);
-
- switch (udev->speed) {
- case USB_SPEED_HIGH:
- pr_debug("SPD_HIGH ");
- break;
- case USB_SPEED_FULL:
- pr_debug("SPD_FULL ");
- break;
- case USB_SPEED_LOW:
- pr_debug("SPD_LOW ");
- break;
- case USB_SPEED_UNKNOWN:
- pr_debug("SPD_UNKNOWN ");
- break;
- default:
- pr_debug("SPD_ERROR ");
- break;
- }
+ dev_dbg(dev, " devnum(%d) devpath(%s) usb speed(%s)",
+ udev->devnum, udev->devpath, usb_speed_string(udev->speed));
pr_debug("tt %p, ttport %d\n", udev->tt, udev->ttport);
@@ -195,8 +178,8 @@ static void usbip_dump_usb_ctrlrequest(struct usb_ctrlrequest *cmd)
}
pr_debug(" ");
- pr_debug("bRequestType(%02X) bRequest(%02X) wValue(%04X) wIndex(%04X) "
- "wLength(%04X) ", cmd->bRequestType, cmd->bRequest,
+ pr_debug("bRequestType(%02X) bRequest(%02X) wValue(%04X) wIndex(%04X) wLength(%04X) ",
+ cmd->bRequestType, cmd->bRequest,
cmd->wValue, cmd->wIndex, cmd->wLength);
pr_debug("\n ");
@@ -307,8 +290,7 @@ void usbip_dump_header(struct usbip_header *pdu)
switch (pdu->base.command) {
case USBIP_CMD_SUBMIT:
- pr_debug("USBIP_CMD_SUBMIT: "
- "x_flags %u x_len %u sf %u #p %d iv %d\n",
+ pr_debug("USBIP_CMD_SUBMIT: x_flags %u x_len %u sf %u #p %d iv %d\n",
pdu->u.cmd_submit.transfer_flags,
pdu->u.cmd_submit.transfer_buffer_length,
pdu->u.cmd_submit.start_frame,
@@ -705,8 +687,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb)
if (total_length != urb->actual_length) {
dev_err(&urb->dev->dev,
- "total length of iso packets %d not equal to actual "
- "length of buffer %d\n",
+ "total length of iso packets %d not equal to actual length of buffer %d\n",
total_length, urb->actual_length);
if (ud->side == USBIP_STUB)
diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h
index 7e6c5436d972..732fb636a1e5 100644
--- a/drivers/staging/usbip/usbip_common.h
+++ b/drivers/staging/usbip/usbip_common.h
@@ -29,6 +29,7 @@
#include <linux/types.h>
#include <linux/usb.h>
#include <linux/wait.h>
+#include "uapi/usbip.h"
#define USBIP_VERSION "1.0.0"
@@ -235,22 +236,6 @@ enum usbip_side {
USBIP_STUB,
};
-enum usbip_status {
- /* sdev is available. */
- SDEV_ST_AVAILABLE = 0x01,
- /* sdev is now used. */
- SDEV_ST_USED,
- /* sdev is unusable because of a fatal error. */
- SDEV_ST_ERROR,
-
- /* vdev does not connect a remote device. */
- VDEV_ST_NULL,
- /* vdev is used, but the USB address is not assigned yet */
- VDEV_ST_NOTASSIGNED,
- VDEV_ST_USED,
- VDEV_ST_ERROR
-};
-
/* event handler */
#define USBIP_EH_SHUTDOWN (1 << 0)
#define USBIP_EH_BYE (1 << 1)
@@ -271,7 +256,7 @@ enum usbip_status {
/* a common structure for stub_device and vhci_device */
struct usbip_device {
enum usbip_side side;
- enum usbip_status status;
+ enum usbip_device_status status;
/* lock for status */
spinlock_t lock;
diff --git a/drivers/staging/usbip/userspace/README b/drivers/staging/usbip/userspace/README
index 00a1658b272b..f528ba462b5f 100644
--- a/drivers/staging/usbip/userspace/README
+++ b/drivers/staging/usbip/userspace/README
@@ -9,8 +9,8 @@
- USB/IP device drivers
Found in the staging directory of the Linux kernel.
- - sysfsutils >= 2.0.0
- sysfsutils library
+ - libudev >= 2.0
+ libudev library
- libwrap0-dev
tcp wrapper library
@@ -19,6 +19,10 @@
- libtool, automake >= 1.9, autoconf >= 2.5.0, pkg-config
+[Optional]
+ - hwdata
+ Contains USB device identification data.
+
[Install]
0. Generate configuration scripts.
diff --git a/drivers/staging/usbip/userspace/configure.ac b/drivers/staging/usbip/userspace/configure.ac
index 0ee5d9263996..607d05c5ccfd 100644
--- a/drivers/staging/usbip/userspace/configure.ac
+++ b/drivers/staging/usbip/userspace/configure.ac
@@ -1,7 +1,7 @@
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
-AC_INIT([usbip-utils], [1.1.1], [linux-usb@vger.kernel.org])
+AC_INIT([usbip-utils], [2.0], [linux-usb@vger.kernel.org])
AC_DEFINE([USBIP_VERSION], [0x00000111], [binary-coded decimal version number])
CURRENT=0
@@ -44,11 +44,11 @@ AC_FUNC_REALLOC
AC_CHECK_FUNCS([memset mkdir regcomp socket strchr strerror strstr dnl
strtoul])
-AC_CHECK_HEADER([sysfs/libsysfs.h],
- [AC_CHECK_LIB([sysfs], [sysfs_open_directory_list],
- [LIBS="$LIBS -lsysfs"],
- [AC_MSG_ERROR([Missing sysfs2 library!])])],
- [AC_MSG_ERROR([Missing /usr/include/sysfs/libsysfs.h])])
+AC_CHECK_HEADER([libudev.h],
+ [AC_CHECK_LIB([udev], [udev_new],
+ [LIBS="$LIBS -ludev"],
+ [AC_MSG_ERROR([Missing udev library!])])],
+ [AC_MSG_ERROR([Missing /usr/include/libudev.h])])
# Checks for libwrap library.
AC_MSG_CHECKING([whether to use the libwrap (TCP wrappers) library])
diff --git a/drivers/staging/usbip/userspace/libsrc/Makefile.am b/drivers/staging/usbip/userspace/libsrc/Makefile.am
index 4921189e0260..7c8f8a4d54e4 100644
--- a/drivers/staging/usbip/userspace/libsrc/Makefile.am
+++ b/drivers/staging/usbip/userspace/libsrc/Makefile.am
@@ -4,4 +4,5 @@ libusbip_la_LDFLAGS = -version-info @LIBUSBIP_VERSION@
lib_LTLIBRARIES := libusbip.la
libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h \
- usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h
+ usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h \
+ sysfs_utils.c sysfs_utils.h
diff --git a/drivers/staging/usbip/userspace/libsrc/list.h b/drivers/staging/usbip/userspace/libsrc/list.h
new file mode 100644
index 000000000000..8d0c936e184f
--- /dev/null
+++ b/drivers/staging/usbip/userspace/libsrc/list.h
@@ -0,0 +1,136 @@
+#ifndef _LIST_H
+#define _LIST_H
+
+/* Stripped down implementation of linked list taken
+ * from the Linux Kernel.
+ */
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+#define POISON_POINTER_DELTA 0
+#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)
+#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void __list_del_entry(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#endif
diff --git a/drivers/staging/usbip/userspace/libsrc/sysfs_utils.c b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.c
new file mode 100644
index 000000000000..36ac88ece0b8
--- /dev/null
+++ b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.c
@@ -0,0 +1,31 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "sysfs_utils.h"
+#include "usbip_common.h"
+
+int write_sysfs_attribute(const char *attr_path, const char *new_value,
+ size_t len)
+{
+ int fd;
+ int length;
+
+ fd = open(attr_path, O_WRONLY);
+ if (fd < 0) {
+ dbg("error opening attribute %s", attr_path);
+ return -1;
+ }
+
+ length = write(fd, new_value, len);
+ if (length < 0) {
+ dbg("error writing to attribute %s", attr_path);
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ return 0;
+}
diff --git a/drivers/staging/usbip/userspace/libsrc/sysfs_utils.h b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.h
new file mode 100644
index 000000000000..32ac1d105d18
--- /dev/null
+++ b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.h
@@ -0,0 +1,8 @@
+
+#ifndef __SYSFS_UTILS_H
+#define __SYSFS_UTILS_H
+
+int write_sysfs_attribute(const char *attr_path, const char *new_value,
+ size_t len);
+
+#endif
diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_common.c b/drivers/staging/usbip/userspace/libsrc/usbip_common.c
index 66f03cc62ac6..238bf5bf7f4c 100644
--- a/drivers/staging/usbip/userspace/libsrc/usbip_common.c
+++ b/drivers/staging/usbip/userspace/libsrc/usbip_common.c
@@ -2,6 +2,7 @@
* Copyright (C) 2005-2007 Takahiro Hirofuchi
*/
+#include <libudev.h>
#include "usbip_common.h"
#include "names.h"
@@ -12,6 +13,8 @@ int usbip_use_syslog;
int usbip_use_stderr;
int usbip_use_debug;
+extern struct udev *udev_context;
+
struct speed_string {
int num;
char *speed;
@@ -23,6 +26,8 @@ static const struct speed_string speed_strings[] = {
{ USB_SPEED_LOW, "1.5", "Low Speed(1.5Mbps)" },
{ USB_SPEED_FULL, "12", "Full Speed(12Mbps)" },
{ USB_SPEED_HIGH, "480", "High Speed(480Mbps)" },
+ { USB_SPEED_WIRELESS, "53.3-480", "Wireless"},
+ { USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" },
{ 0, NULL, NULL }
};
@@ -109,75 +114,61 @@ void dump_usb_device(struct usbip_usb_device *udev)
}
-int read_attr_value(struct sysfs_device *dev, const char *name,
+int read_attr_value(struct udev_device *dev, const char *name,
const char *format)
{
- char attrpath[SYSFS_PATH_MAX];
- struct sysfs_attribute *attr;
+ const char *attr;
int num = 0;
int ret;
- snprintf(attrpath, sizeof(attrpath), "%s/%s", dev->path, name);
-
- attr = sysfs_open_attribute(attrpath);
+ attr = udev_device_get_sysattr_value(dev, name);
if (!attr) {
- dbg("sysfs_open_attribute failed: %s", attrpath);
- return 0;
- }
-
- ret = sysfs_read_attribute(attr);
- if (ret < 0) {
- dbg("sysfs_read_attribute failed");
+ err("udev_device_get_sysattr_value failed");
goto err;
}
- ret = sscanf(attr->value, format, &num);
+ /* The client chooses the device configuration
+ * when attaching it so right after being bound
+ * to usbip-host on the server the device will
+ * have no configuration.
+ * Therefore, attributes such as bConfigurationValue
+ * and bNumInterfaces will not exist and sscanf will
+ * fail. Check for these cases and don't treat them
+ * as errors.
+ */
+
+ ret = sscanf(attr, format, &num);
if (ret < 1) {
- dbg("sscanf failed");
- goto err;
+ if (strcmp(name, "bConfigurationValue") &&
+ strcmp(name, "bNumInterfaces")) {
+ err("sscanf failed for attribute %s", name);
+ goto err;
+ }
}
err:
- sysfs_close_attribute(attr);
return num;
}
-int read_attr_speed(struct sysfs_device *dev)
+int read_attr_speed(struct udev_device *dev)
{
- char attrpath[SYSFS_PATH_MAX];
- struct sysfs_attribute *attr;
- char speed[100];
- int ret;
-
- snprintf(attrpath, sizeof(attrpath), "%s/%s", dev->path, "speed");
-
- attr = sysfs_open_attribute(attrpath);
- if (!attr) {
- dbg("sysfs_open_attribute failed: %s", attrpath);
- return 0;
- }
+ const char *speed;
- ret = sysfs_read_attribute(attr);
- if (ret < 0) {
- dbg("sysfs_read_attribute failed");
+ speed = udev_device_get_sysattr_value(dev, "speed");
+ if (!speed) {
+ err("udev_device_get_sysattr_value failed");
goto err;
}
- ret = sscanf(attr->value, "%99s\n", speed);
- if (ret < 1) {
- dbg("sscanf failed");
- goto err;
- }
-err:
- sysfs_close_attribute(attr);
-
for (int i = 0; speed_strings[i].speed != NULL; i++) {
if (!strcmp(speed, speed_strings[i].speed))
return speed_strings[i].num;
}
+err:
+
return USB_SPEED_UNKNOWN;
}
@@ -188,9 +179,10 @@ err:
} while (0)
-int read_usb_device(struct sysfs_device *sdev, struct usbip_usb_device *udev)
+int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev)
{
uint32_t busnum, devnum;
+ const char *path, *name;
READ_ATTR(udev, uint8_t, sdev, bDeviceClass, "%02x\n");
READ_ATTR(udev, uint8_t, sdev, bDeviceSubClass, "%02x\n");
@@ -207,10 +199,13 @@ int read_usb_device(struct sysfs_device *sdev, struct usbip_usb_device *udev)
READ_ATTR(udev, uint8_t, sdev, devnum, "%d\n");
udev->speed = read_attr_speed(sdev);
- strncpy(udev->path, sdev->path, SYSFS_PATH_MAX);
- strncpy(udev->busid, sdev->name, SYSFS_BUS_ID_SIZE);
+ path = udev_device_get_syspath(sdev);
+ name = udev_device_get_sysname(sdev);
- sscanf(sdev->name, "%u-%u", &busnum, &devnum);
+ strncpy(udev->path, path, SYSFS_PATH_MAX);
+ strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE);
+
+ sscanf(name, "%u-%u", &busnum, &devnum);
udev->busnum = busnum;
return 0;
@@ -220,13 +215,13 @@ int read_usb_interface(struct usbip_usb_device *udev, int i,
struct usbip_usb_interface *uinf)
{
char busid[SYSFS_BUS_ID_SIZE];
- struct sysfs_device *sif;
+ struct udev_device *sif;
sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i);
- sif = sysfs_open_device("usb", busid);
+ sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid);
if (!sif) {
- dbg("sysfs_open_device(\"usb\", \"%s\") failed", busid);
+ err("udev_device_new_from_subsystem_sysname %s failed", busid);
return -1;
}
@@ -234,8 +229,6 @@ int read_usb_interface(struct usbip_usb_device *udev, int i,
READ_ATTR(uinf, uint8_t, sif, bInterfaceSubClass, "%02x\n");
READ_ATTR(uinf, uint8_t, sif, bInterfaceProtocol, "%02x\n");
- sysfs_close_device(sif);
-
return 0;
}
diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_common.h b/drivers/staging/usbip/userspace/libsrc/usbip_common.h
index 938ad1c36947..23be848f24fb 100644
--- a/drivers/staging/usbip/userspace/libsrc/usbip_common.h
+++ b/drivers/staging/usbip/userspace/libsrc/usbip_common.h
@@ -5,7 +5,7 @@
#ifndef __USBIP_COMMON_H
#define __USBIP_COMMON_H
-#include <sysfs/libsysfs.h>
+#include <libudev.h>
#include <stdint.h>
#include <stdio.h>
@@ -14,6 +14,8 @@
#include <syslog.h>
#include <unistd.h>
+#include <linux/usb/ch9.h>
+#include "../../uapi/usbip.h"
#ifndef USBIDS_FILE
#define USBIDS_FILE "/usr/share/hwdata/usb.ids"
@@ -28,6 +30,15 @@
#define USBIP_HOST_DRV_NAME "usbip-host"
#define USBIP_VHCI_DRV_NAME "vhci_hcd"
+/* sysfs constants */
+#define SYSFS_MNT_PATH "/sys"
+#define SYSFS_BUS_NAME "bus"
+#define SYSFS_BUS_TYPE "usb"
+#define SYSFS_DRIVERS_NAME "drivers"
+
+#define SYSFS_PATH_MAX 256
+#define SYSFS_BUS_ID_SIZE 32
+
extern int usbip_use_syslog;
extern int usbip_use_stderr;
extern int usbip_use_debug ;
@@ -76,30 +87,6 @@ extern int usbip_use_debug ;
abort(); \
} while (0)
-enum usb_device_speed {
- USB_SPEED_UNKNOWN = 0, /* enumerating */
- USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */
- USB_SPEED_HIGH, /* usb 2.0 */
- USB_SPEED_VARIABLE /* wireless (usb 2.5) */
-};
-
-/* FIXME: how to sync with drivers/usbip_common.h ? */
-enum usbip_device_status {
- /* sdev is available. */
- SDEV_ST_AVAILABLE = 0x01,
- /* sdev is now used. */
- SDEV_ST_USED,
- /* sdev is unusable because of a fatal error. */
- SDEV_ST_ERROR,
-
- /* vdev does not connect a remote device. */
- VDEV_ST_NULL,
- /* vdev is used, but the USB address is not assigned yet */
- VDEV_ST_NOTASSIGNED,
- VDEV_ST_USED,
- VDEV_ST_ERROR
-};
-
struct usbip_usb_interface {
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
@@ -131,8 +118,8 @@ struct usbip_usb_device {
void dump_usb_interface(struct usbip_usb_interface *);
void dump_usb_device(struct usbip_usb_device *);
-int read_usb_device(struct sysfs_device *sdev, struct usbip_usb_device *udev);
-int read_attr_value(struct sysfs_device *dev, const char *name,
+int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev);
+int read_attr_value(struct udev_device *dev, const char *name,
const char *format);
int read_usb_interface(struct usbip_usb_device *udev, int i,
struct usbip_usb_interface *uinf);
diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c
index 71a449cf50db..c5bf60b135b9 100644
--- a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c
+++ b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c
@@ -18,102 +18,65 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
+#include <libudev.h>
+
#include "usbip_common.h"
#include "usbip_host_driver.h"
+#include "list.h"
+#include "sysfs_utils.h"
#undef PROGNAME
#define PROGNAME "libusbip"
struct usbip_host_driver *host_driver;
+struct udev *udev_context;
-#define SYSFS_OPEN_RETRIES 100
-
-/* only the first interface value is true! */
static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
{
- char attrpath[SYSFS_PATH_MAX];
- struct sysfs_attribute *attr;
+ char status_attr_path[SYSFS_PATH_MAX];
+ int fd;
+ int length;
+ char status;
int value = 0;
- int rc;
- struct stat s;
- int retries = SYSFS_OPEN_RETRIES;
-
- /* This access is racy!
- *
- * Just after detach, our driver removes the sysfs
- * files and recreates them.
- *
- * We may try and fail to open the usbip_status of
- * an exported device in the (short) window where
- * it has been removed and not yet recreated.
- *
- * This is a bug in the interface. Nothing we can do
- * except work around it here by polling for the sysfs
- * usbip_status to reappear.
- */
-
- snprintf(attrpath, SYSFS_PATH_MAX, "%s/%s:%d.%d/usbip_status",
- udev->path, udev->busid, udev->bConfigurationValue, 0);
-
- while (retries > 0) {
- if (stat(attrpath, &s) == 0)
- break;
-
- if (errno != ENOENT) {
- dbg("stat failed: %s", attrpath);
- return -1;
- }
-
- usleep(10000); /* 10ms */
- retries--;
- }
- if (retries == 0)
- dbg("usbip_status not ready after %d retries",
- SYSFS_OPEN_RETRIES);
- else if (retries < SYSFS_OPEN_RETRIES)
- dbg("warning: usbip_status ready after %d retries",
- SYSFS_OPEN_RETRIES - retries);
+ snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status",
+ udev->path);
- attr = sysfs_open_attribute(attrpath);
- if (!attr) {
- dbg("sysfs_open_attribute failed: %s", attrpath);
+ if ((fd = open(status_attr_path, O_RDONLY)) < 0) {
+ err("error opening attribute %s", status_attr_path);
return -1;
}
- rc = sysfs_read_attribute(attr);
- if (rc) {
- dbg("sysfs_read_attribute failed: %s", attrpath);
- sysfs_close_attribute(attr);
+ length = read(fd, &status, 1);
+ if (length < 0) {
+ err("error reading attribute %s", status_attr_path);
+ close(fd);
return -1;
}
- value = atoi(attr->value);
-
- sysfs_close_attribute(attr);
+ value = atoi(&status);
return value;
}
-static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath)
+static
+struct usbip_exported_device *usbip_exported_device_new(const char *sdevpath)
{
struct usbip_exported_device *edev = NULL;
+ struct usbip_exported_device *edev_old;
size_t size;
int i;
- edev = calloc(1, sizeof(*edev));
- if (!edev) {
- dbg("calloc failed");
- return NULL;
- }
+ edev = calloc(1, sizeof(struct usbip_exported_device));
- edev->sudev = sysfs_open_device_path(sdevpath);
+ edev->sudev = udev_device_new_from_syspath(udev_context, sdevpath);
if (!edev->sudev) {
- dbg("sysfs_open_device_path failed: %s", sdevpath);
+ err("udev_device_new_from_syspath: %s", sdevpath);
goto err;
}
@@ -124,11 +87,13 @@ static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath)
goto err;
/* reallocate buffer to include usb interface data */
- size = sizeof(*edev) + edev->udev.bNumInterfaces *
+ size = sizeof(struct usbip_exported_device) + edev->udev.bNumInterfaces *
sizeof(struct usbip_usb_interface);
+ edev_old = edev;
edev = realloc(edev, size);
if (!edev) {
+ edev = edev_old;
dbg("realloc failed");
goto err;
}
@@ -138,160 +103,88 @@ static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath)
return edev;
err:
- if (edev && edev->sudev)
- sysfs_close_device(edev->sudev);
+ if (edev->sudev)
+ udev_device_unref(edev->sudev);
if (edev)
free(edev);
return NULL;
}
-static int check_new(struct dlist *dlist, struct sysfs_device *target)
-{
- struct sysfs_device *dev;
-
- dlist_for_each_data(dlist, dev, struct sysfs_device) {
- if (!strncmp(dev->bus_id, target->bus_id, SYSFS_BUS_ID_SIZE))
- /* device found and is not new */
- return 0;
- }
- return 1;
-}
-
-static void delete_nothing(void *unused_data)
-{
- /*
- * NOTE: Do not delete anything, but the container will be deleted.
- */
- (void) unused_data;
-}
-
static int refresh_exported_devices(void)
{
- /* sysfs_device of usb_interface */
- struct sysfs_device *suintf;
- struct dlist *suintf_list;
- /* sysfs_device of usb_device */
- struct sysfs_device *sudev;
- struct dlist *sudev_list;
struct usbip_exported_device *edev;
-
- sudev_list = dlist_new_with_delete(sizeof(struct sysfs_device),
- delete_nothing);
-
- suintf_list = sysfs_get_driver_devices(host_driver->sysfs_driver);
- if (!suintf_list) {
- /*
- * Not an error condition. There are simply no devices bound to
- * the driver yet.
- */
- dbg("bind " USBIP_HOST_DRV_NAME ".ko to a usb device to be "
- "exportable!");
- return 0;
- }
-
- /* collect unique USB devices (not interfaces) */
- dlist_for_each_data(suintf_list, suintf, struct sysfs_device) {
- /* get usb device of this usb interface */
- sudev = sysfs_get_device_parent(suintf);
- if (!sudev) {
- dbg("sysfs_get_device_parent failed: %s", suintf->name);
- continue;
- }
-
- if (check_new(sudev_list, sudev)) {
- /* insert item at head of list */
- dlist_unshift(sudev_list, sudev);
- }
- }
-
- dlist_for_each_data(sudev_list, sudev, struct sysfs_device) {
- edev = usbip_exported_device_new(sudev->path);
- if (!edev) {
- dbg("usbip_exported_device_new failed");
- continue;
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *devices, *dev_list_entry;
+ struct udev_device *dev;
+ const char *path;
+
+ enumerate = udev_enumerate_new(udev_context);
+ udev_enumerate_add_match_subsystem(enumerate, "usb");
+ udev_enumerate_scan_devices(enumerate);
+
+ devices = udev_enumerate_get_list_entry(enumerate);
+
+ udev_list_entry_foreach(dev_list_entry, devices) {
+ path = udev_list_entry_get_name(dev_list_entry);
+ dev = udev_device_new_from_syspath(udev_context, path);
+
+ /* Check whether device uses usbip-host driver. */
+ if (!strcmp(udev_device_get_driver(dev),
+ USBIP_HOST_DRV_NAME)) {
+ edev = usbip_exported_device_new(path);
+ if (!edev) {
+ dbg("usbip_exported_device_new failed");
+ continue;
+ }
+
+ list_add(&edev->node, &host_driver->edev_list);
+ host_driver->ndevs++;
}
-
- dlist_unshift(host_driver->edev_list, edev);
- host_driver->ndevs++;
}
- dlist_destroy(sudev_list);
-
return 0;
}
-static struct sysfs_driver *open_sysfs_host_driver(void)
+static void usbip_exported_device_destroy(void)
{
- char bus_type[] = "usb";
- char sysfs_mntpath[SYSFS_PATH_MAX];
- char host_drv_path[SYSFS_PATH_MAX];
- struct sysfs_driver *host_drv;
- int rc;
-
- rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
- if (rc < 0) {
- dbg("sysfs_get_mnt_path failed");
- return NULL;
- }
-
- snprintf(host_drv_path, SYSFS_PATH_MAX, "%s/%s/%s/%s/%s",
- sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
- USBIP_HOST_DRV_NAME);
+ struct list_head *i, *tmp;
+ struct usbip_exported_device *edev;
- host_drv = sysfs_open_driver_path(host_drv_path);
- if (!host_drv) {
- dbg("sysfs_open_driver_path failed");
- return NULL;
+ list_for_each_safe(i, tmp, &host_driver->edev_list) {
+ edev = list_entry(i, struct usbip_exported_device, node);
+ list_del(i);
+ free(edev);
}
-
- return host_drv;
-}
-
-static void usbip_exported_device_delete(void *dev)
-{
- struct usbip_exported_device *edev = dev;
- sysfs_close_device(edev->sudev);
- free(dev);
}
int usbip_host_driver_open(void)
{
int rc;
- host_driver = calloc(1, sizeof(*host_driver));
- if (!host_driver) {
- dbg("calloc failed");
+ udev_context = udev_new();
+ if (!udev_context) {
+ err("udev_new failed");
return -1;
}
- host_driver->ndevs = 0;
- host_driver->edev_list =
- dlist_new_with_delete(sizeof(struct usbip_exported_device),
- usbip_exported_device_delete);
- if (!host_driver->edev_list) {
- dbg("dlist_new_with_delete failed");
- goto err_free_host_driver;
- }
+ host_driver = calloc(1, sizeof(*host_driver));
- host_driver->sysfs_driver = open_sysfs_host_driver();
- if (!host_driver->sysfs_driver)
- goto err_destroy_edev_list;
+ host_driver->ndevs = 0;
+ INIT_LIST_HEAD(&host_driver->edev_list);
rc = refresh_exported_devices();
if (rc < 0)
- goto err_close_sysfs_driver;
+ goto err_free_host_driver;
return 0;
-err_close_sysfs_driver:
- sysfs_close_driver(host_driver->sysfs_driver);
-err_destroy_edev_list:
- dlist_destroy(host_driver->edev_list);
err_free_host_driver:
free(host_driver);
host_driver = NULL;
+ udev_unref(udev_context);
+
return -1;
}
@@ -300,30 +193,22 @@ void usbip_host_driver_close(void)
if (!host_driver)
return;
- if (host_driver->edev_list)
- dlist_destroy(host_driver->edev_list);
- if (host_driver->sysfs_driver)
- sysfs_close_driver(host_driver->sysfs_driver);
+ usbip_exported_device_destroy();
free(host_driver);
host_driver = NULL;
+
+ udev_unref(udev_context);
}
int usbip_host_refresh_device_list(void)
{
int rc;
- if (host_driver->edev_list)
- dlist_destroy(host_driver->edev_list);
+ usbip_exported_device_destroy();
host_driver->ndevs = 0;
- host_driver->edev_list =
- dlist_new_with_delete(sizeof(struct usbip_exported_device),
- usbip_exported_device_delete);
- if (!host_driver->edev_list) {
- dbg("dlist_new_with_delete failed");
- return -1;
- }
+ INIT_LIST_HEAD(&host_driver->edev_list);
rc = refresh_exported_devices();
if (rc < 0)
@@ -335,8 +220,7 @@ int usbip_host_refresh_device_list(void)
int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd)
{
char attr_name[] = "usbip_sockfd";
- char attr_path[SYSFS_PATH_MAX];
- struct sysfs_attribute *attr;
+ char sockfd_attr_path[SYSFS_PATH_MAX];
char sockfd_buff[30];
int ret;
@@ -356,41 +240,32 @@ int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd)
}
/* only the first interface is true */
- snprintf(attr_path, sizeof(attr_path), "%s/%s:%d.%d/%s",
- edev->udev.path, edev->udev.busid,
- edev->udev.bConfigurationValue, 0, attr_name);
-
- attr = sysfs_open_attribute(attr_path);
- if (!attr) {
- dbg("sysfs_open_attribute failed: %s", attr_path);
- return -1;
- }
+ snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
+ edev->udev.path, attr_name);
snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
- dbg("write: %s", sockfd_buff);
- ret = sysfs_write_attribute(attr, sockfd_buff, strlen(sockfd_buff));
+ ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff,
+ strlen(sockfd_buff));
if (ret < 0) {
- dbg("sysfs_write_attribute failed: sockfd %s to %s",
- sockfd_buff, attr_path);
- goto err_write_sockfd;
+ err("write_sysfs_attribute failed: sockfd %s to %s",
+ sockfd_buff, sockfd_attr_path);
+ return ret;
}
- dbg("connect: %s", edev->udev.busid);
-
-err_write_sockfd:
- sysfs_close_attribute(attr);
+ info("connect: %s", edev->udev.busid);
return ret;
}
struct usbip_exported_device *usbip_host_get_device(int num)
{
+ struct list_head *i;
struct usbip_exported_device *edev;
- struct dlist *dlist = host_driver->edev_list;
int cnt = 0;
- dlist_for_each_data(dlist, edev, struct usbip_exported_device) {
+ list_for_each(i, &host_driver->edev_list) {
+ edev = list_entry(i, struct usbip_exported_device, node);
if (num == cnt)
return edev;
else
diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h
index 34fd14cbfc49..2a31f855c616 100644
--- a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h
+++ b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h
@@ -21,18 +21,19 @@
#include <stdint.h>
#include "usbip_common.h"
+#include "list.h"
struct usbip_host_driver {
int ndevs;
- struct sysfs_driver *sysfs_driver;
/* list of exported device */
- struct dlist *edev_list;
+ struct list_head edev_list;
};
struct usbip_exported_device {
- struct sysfs_device *sudev;
+ struct udev_device *sudev;
int32_t status;
struct usbip_usb_device udev;
+ struct list_head node;
struct usbip_usb_interface uinf[];
};
diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
index 209df9b37cb4..8901fcb7946f 100644
--- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
+++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
@@ -6,44 +6,28 @@
#include "vhci_driver.h"
#include <limits.h>
#include <netdb.h>
+#include <libudev.h>
+#include "sysfs_utils.h"
#undef PROGNAME
#define PROGNAME "libusbip"
struct usbip_vhci_driver *vhci_driver;
+struct udev *udev_context;
static struct usbip_imported_device *
imported_device_init(struct usbip_imported_device *idev, char *busid)
{
- struct sysfs_device *sudev;
+ struct udev_device *sudev;
- sudev = sysfs_open_device("usb", busid);
+ sudev = udev_device_new_from_subsystem_sysname(udev_context,
+ "usb", busid);
if (!sudev) {
- dbg("sysfs_open_device failed: %s", busid);
+ dbg("udev_device_new_from_subsystem_sysname failed: %s", busid);
goto err;
}
read_usb_device(sudev, &idev->udev);
- sysfs_close_device(sudev);
-
- /* add class devices of this imported device */
- struct usbip_class_device *cdev;
- dlist_for_each_data(vhci_driver->cdev_list, cdev,
- struct usbip_class_device) {
- if (!strncmp(cdev->dev_path, idev->udev.path,
- strlen(idev->udev.path))) {
- struct usbip_class_device *new_cdev;
- /*
- * alloc and copy because dlist is linked
- * from only one list
- */
- new_cdev = calloc(1, sizeof(*new_cdev));
- if (!new_cdev)
- goto err;
-
- memcpy(new_cdev, cdev, sizeof(*new_cdev));
- dlist_unshift(idev->cdev_list, (void *) new_cdev);
- }
- }
+ udev_device_unref(sudev);
return idev;
@@ -53,7 +37,7 @@ err:
-static int parse_status(char *value)
+static int parse_status(const char *value)
{
int ret = 0;
char *c;
@@ -100,12 +84,6 @@ static int parse_status(char *value)
idev->busnum = (devid >> 16);
idev->devnum = (devid & 0x0000ffff);
- idev->cdev_list = dlist_new(sizeof(struct usbip_class_device));
- if (!idev->cdev_list) {
- dbg("dlist_new failed");
- return -1;
- }
-
if (idev->status != VDEV_ST_NULL
&& idev->status != VDEV_ST_NOTASSIGNED) {
idev = imported_device_init(idev, lbusid);
@@ -129,156 +107,35 @@ static int parse_status(char *value)
return 0;
}
-
-static int check_usbip_device(struct sysfs_class_device *cdev)
-{
- /* /sys/class/video4linux/video0/device */
- char class_path[SYSFS_PATH_MAX];
- /* /sys/devices/platform/vhci_hcd/usb6/6-1:1.1 */
- char dev_path[SYSFS_PATH_MAX];
- int ret;
- struct usbip_class_device *usbip_cdev;
-
- snprintf(class_path, sizeof(class_path), "%s/device", cdev->path);
-
- ret = sysfs_get_link(class_path, dev_path, sizeof(dev_path));
- if (ret == 0) {
- if (!strncmp(dev_path, vhci_driver->hc_device->path,
- strlen(vhci_driver->hc_device->path))) {
- /* found usbip device */
- usbip_cdev = calloc(1, sizeof(*usbip_cdev));
- if (!usbip_cdev) {
- dbg("calloc failed");
- return -1;
- }
- dlist_unshift(vhci_driver->cdev_list, usbip_cdev);
- strncpy(usbip_cdev->class_path, class_path,
- sizeof(usbip_cdev->class_path));
- strncpy(usbip_cdev->dev_path, dev_path,
- sizeof(usbip_cdev->dev_path));
- dbg("found: %s %s", class_path, dev_path);
- }
- }
-
- return 0;
-}
-
-
-static int search_class_for_usbip_device(char *cname)
-{
- struct sysfs_class *class;
- struct dlist *cdev_list;
- struct sysfs_class_device *cdev;
- int ret = 0;
-
- class = sysfs_open_class(cname);
- if (!class) {
- dbg("sysfs_open_class failed");
- return -1;
- }
-
- dbg("class: %s", class->name);
-
- cdev_list = sysfs_get_class_devices(class);
- if (!cdev_list)
- /* nothing */
- goto out;
-
- dlist_for_each_data(cdev_list, cdev, struct sysfs_class_device) {
- dbg("cdev: %s", cdev->name);
- ret = check_usbip_device(cdev);
- if (ret < 0)
- goto out;
- }
-
-out:
- sysfs_close_class(class);
-
- return ret;
-}
-
-
-static int refresh_class_device_list(void)
-{
- int ret;
- struct dlist *cname_list;
- char *cname;
- char sysfs_mntpath[SYSFS_PATH_MAX];
- char class_path[SYSFS_PATH_MAX];
-
- ret = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
- if (ret < 0) {
- dbg("sysfs_get_mnt_path failed");
- return -1;
- }
-
- snprintf(class_path, sizeof(class_path), "%s/%s", sysfs_mntpath,
- SYSFS_CLASS_NAME);
-
- /* search under /sys/class */
- cname_list = sysfs_open_directory_list(class_path);
- if (!cname_list) {
- dbg("sysfs_open_directory failed");
- return -1;
- }
-
- dlist_for_each_data(cname_list, cname, char) {
- ret = search_class_for_usbip_device(cname);
- if (ret < 0) {
- sysfs_close_list(cname_list);
- return -1;
- }
- }
-
- sysfs_close_list(cname_list);
-
- /* search under /sys/block */
- ret = search_class_for_usbip_device(SYSFS_BLOCK_NAME);
- if (ret < 0)
- return -1;
-
- return 0;
-}
-
-
static int refresh_imported_device_list(void)
{
- struct sysfs_attribute *attr_status;
-
+ const char *attr_status;
- attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
+ attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
+ "status");
if (!attr_status) {
- dbg("sysfs_get_device_attr(\"status\") failed: %s",
- vhci_driver->hc_device->name);
+ err("udev_device_get_sysattr_value failed");
return -1;
}
- dbg("name: %s path: %s len: %d method: %d value: %s",
- attr_status->name, attr_status->path, attr_status->len,
- attr_status->method, attr_status->value);
-
- return parse_status(attr_status->value);
+ return parse_status(attr_status);
}
static int get_nports(void)
{
char *c;
int nports = 0;
- struct sysfs_attribute *attr_status;
+ const char *attr_status;
- attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
+ attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
+ "status");
if (!attr_status) {
- dbg("sysfs_get_device_attr(\"status\") failed: %s",
- vhci_driver->hc_device->name);
+ err("udev_device_get_sysattr_value failed");
return -1;
}
- dbg("name: %s path: %s len: %d method: %d value: %s",
- attr_status->name, attr_status->path, attr_status->len,
- attr_status->method, attr_status->value);
-
/* skip a header line */
- c = strchr(attr_status->value, '\n');
+ c = strchr(attr_status, '\n');
if (!c)
return 0;
c++;
@@ -295,71 +152,66 @@ static int get_nports(void)
return nports;
}
-static int get_hc_busid(char *sysfs_mntpath, char *hc_busid)
-{
- struct sysfs_driver *sdriver;
- char sdriver_path[SYSFS_PATH_MAX];
-
- struct sysfs_device *hc_dev;
- struct dlist *hc_devs;
-
- int found = 0;
-
- snprintf(sdriver_path, SYSFS_PATH_MAX, "%s/%s/%s/%s/%s", sysfs_mntpath,
- SYSFS_BUS_NAME, USBIP_VHCI_BUS_TYPE, SYSFS_DRIVERS_NAME,
- USBIP_VHCI_DRV_NAME);
-
- sdriver = sysfs_open_driver_path(sdriver_path);
- if (!sdriver) {
- dbg("sysfs_open_driver_path failed: %s", sdriver_path);
- dbg("make sure " USBIP_CORE_MOD_NAME ".ko and "
- USBIP_VHCI_DRV_NAME ".ko are loaded!");
- return -1;
- }
-
- hc_devs = sysfs_get_driver_devices(sdriver);
- if (!hc_devs) {
- dbg("sysfs_get_driver failed");
- goto err;
- }
-
- /* assume only one vhci_hcd */
- dlist_for_each_data(hc_devs, hc_dev, struct sysfs_device) {
- strncpy(hc_busid, hc_dev->bus_id, SYSFS_BUS_ID_SIZE);
- found = 1;
- }
-
-err:
- sysfs_close_driver(sdriver);
-
- if (found)
- return 0;
-
- dbg("%s not found", hc_busid);
- return -1;
-}
-
-static int read_record(int rhport, char *host, char *port, char *busid)
+/*
+ * Read the given port's record.
+ *
+ * To avoid buffer overflow we will read the entire line and
+ * validate each part's size. The initial buffer is padded by 4 to
+ * accommodate the 2 spaces, 1 newline and an additional character
+ * which is needed to properly validate the 3rd part without it being
+ * truncated to an acceptable length.
+ */
+static int read_record(int rhport, char *host, unsigned long host_len,
+ char *port, unsigned long port_len, char *busid)
{
+ int part;
FILE *file;
char path[PATH_MAX+1];
+ char *buffer, *start, *end;
+ char delim[] = {' ', ' ', '\n'};
+ int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE};
+ size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4;
+
+ buffer = malloc(buffer_len);
+ if (!buffer)
+ return -1;
snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
file = fopen(path, "r");
if (!file) {
err("fopen");
+ free(buffer);
return -1;
}
- if (fscanf(file, "%s %s %s\n", host, port, busid) != 3) {
- err("fscanf");
+ if (fgets(buffer, buffer_len, file) == NULL) {
+ err("fgets");
+ free(buffer);
fclose(file);
return -1;
}
-
fclose(file);
+ /* validate the length of each of the 3 parts */
+ start = buffer;
+ for (part = 0; part < 3; part++) {
+ end = strchr(start, delim[part]);
+ if (end == NULL || (end - start) > max_len[part]) {
+ free(buffer);
+ return -1;
+ }
+ start = end + 1;
+ }
+
+ if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) {
+ err("sscanf");
+ free(buffer);
+ return -1;
+ }
+
+ free(buffer);
+
return 0;
}
@@ -367,30 +219,21 @@ static int read_record(int rhport, char *host, char *port, char *busid)
int usbip_vhci_driver_open(void)
{
- int ret;
- char hc_busid[SYSFS_BUS_ID_SIZE];
-
- vhci_driver = (struct usbip_vhci_driver *) calloc(1, sizeof(*vhci_driver));
- if (!vhci_driver) {
- dbg("calloc failed");
+ udev_context = udev_new();
+ if (!udev_context) {
+ err("udev_new failed");
return -1;
}
- ret = sysfs_get_mnt_path(vhci_driver->sysfs_mntpath, SYSFS_PATH_MAX);
- if (ret < 0) {
- dbg("sysfs_get_mnt_path failed");
- goto err;
- }
-
- ret = get_hc_busid(vhci_driver->sysfs_mntpath, hc_busid);
- if (ret < 0)
- goto err;
+ vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver));
/* will be freed in usbip_driver_close() */
- vhci_driver->hc_device = sysfs_open_device(USBIP_VHCI_BUS_TYPE,
- hc_busid);
+ vhci_driver->hc_device =
+ udev_device_new_from_subsystem_sysname(udev_context,
+ USBIP_VHCI_BUS_TYPE,
+ USBIP_VHCI_DRV_NAME);
if (!vhci_driver->hc_device) {
- dbg("sysfs_open_device failed");
+ err("udev_device_new_from_subsystem_sysname failed");
goto err;
}
@@ -398,29 +241,21 @@ int usbip_vhci_driver_open(void)
dbg("available ports: %d", vhci_driver->nports);
- vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
- if (!vhci_driver->cdev_list)
- goto err;
-
- if (refresh_class_device_list())
- goto err;
-
if (refresh_imported_device_list())
goto err;
-
return 0;
-
err:
- if (vhci_driver->cdev_list)
- dlist_destroy(vhci_driver->cdev_list);
- if (vhci_driver->hc_device)
- sysfs_close_device(vhci_driver->hc_device);
+ udev_device_unref(vhci_driver->hc_device);
+
if (vhci_driver)
free(vhci_driver);
vhci_driver = NULL;
+
+ udev_unref(udev_context);
+
return -1;
}
@@ -430,53 +265,24 @@ void usbip_vhci_driver_close()
if (!vhci_driver)
return;
- if (vhci_driver->cdev_list)
- dlist_destroy(vhci_driver->cdev_list);
-
- for (int i = 0; i < vhci_driver->nports; i++) {
- if (vhci_driver->idev[i].cdev_list)
- dlist_destroy(vhci_driver->idev[i].cdev_list);
- }
+ udev_device_unref(vhci_driver->hc_device);
- if (vhci_driver->hc_device)
- sysfs_close_device(vhci_driver->hc_device);
free(vhci_driver);
vhci_driver = NULL;
+
+ udev_unref(udev_context);
}
int usbip_vhci_refresh_device_list(void)
{
- if (vhci_driver->cdev_list)
- dlist_destroy(vhci_driver->cdev_list);
-
-
- for (int i = 0; i < vhci_driver->nports; i++) {
- if (vhci_driver->idev[i].cdev_list)
- dlist_destroy(vhci_driver->idev[i].cdev_list);
- }
-
- vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
- if (!vhci_driver->cdev_list)
- goto err;
-
- if (refresh_class_device_list())
- goto err;
if (refresh_imported_device_list())
goto err;
return 0;
err:
- if (vhci_driver->cdev_list)
- dlist_destroy(vhci_driver->cdev_list);
-
- for (int i = 0; i < vhci_driver->nports; i++) {
- if (vhci_driver->idev[i].cdev_list)
- dlist_destroy(vhci_driver->idev[i].cdev_list);
- }
-
dbg("failed to refresh device list");
return -1;
}
@@ -494,24 +300,24 @@ int usbip_vhci_get_free_port(void)
int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
uint32_t speed) {
- struct sysfs_attribute *attr_attach;
char buff[200]; /* what size should be ? */
+ char attach_attr_path[SYSFS_PATH_MAX];
+ char attr_attach[] = "attach";
+ const char *path;
int ret;
- attr_attach = sysfs_get_device_attr(vhci_driver->hc_device, "attach");
- if (!attr_attach) {
- dbg("sysfs_get_device_attr(\"attach\") failed: %s",
- vhci_driver->hc_device->name);
- return -1;
- }
-
- snprintf(buff, sizeof(buff), "%u %u %u %u",
+ snprintf(buff, sizeof(buff), "%u %d %u %u",
port, sockfd, devid, speed);
dbg("writing: %s", buff);
- ret = sysfs_write_attribute(attr_attach, buff, strlen(buff));
+ path = udev_device_get_syspath(vhci_driver->hc_device);
+ snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s",
+ path, attr_attach);
+ dbg("attach attribute path: %s", attach_attr_path);
+
+ ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff));
if (ret < 0) {
- dbg("sysfs_write_attribute failed");
+ dbg("write_sysfs_attribute failed");
return -1;
}
@@ -536,23 +342,23 @@ int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
int usbip_vhci_detach_device(uint8_t port)
{
- struct sysfs_attribute *attr_detach;
+ char detach_attr_path[SYSFS_PATH_MAX];
+ char attr_detach[] = "detach";
char buff[200]; /* what size should be ? */
+ const char *path;
int ret;
- attr_detach = sysfs_get_device_attr(vhci_driver->hc_device, "detach");
- if (!attr_detach) {
- dbg("sysfs_get_device_attr(\"detach\") failed: %s",
- vhci_driver->hc_device->name);
- return -1;
- }
-
snprintf(buff, sizeof(buff), "%u", port);
dbg("writing: %s", buff);
- ret = sysfs_write_attribute(attr_detach, buff, strlen(buff));
+ path = udev_device_get_syspath(vhci_driver->hc_device);
+ snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s",
+ path, attr_detach);
+ dbg("detach attribute path: %s", detach_attr_path);
+
+ ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff));
if (ret < 0) {
- dbg("sysfs_write_attribute failed");
+ dbg("write_sysfs_attribute failed");
return -1;
}
@@ -573,7 +379,8 @@ int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED)
return 0;
- ret = read_record(idev->port, host, serv, remote_busid);
+ ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv),
+ remote_busid);
if (ret) {
err("read_record");
read_record_error = 1;
diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.h b/drivers/staging/usbip/userspace/libsrc/vhci_driver.h
index e071f8049c1f..fa2316cf2cac 100644
--- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.h
+++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.h
@@ -5,7 +5,7 @@
#ifndef __VHCI_DRIVER_H
#define __VHCI_DRIVER_H
-#include <sysfs/libsysfs.h>
+#include <libudev.h>
#include <stdint.h>
#include "usbip_common.h"
@@ -13,11 +13,6 @@
#define USBIP_VHCI_BUS_TYPE "platform"
#define MAXNPORT 128
-struct usbip_class_device {
- char class_path[SYSFS_PATH_MAX];
- char dev_path[SYSFS_PATH_MAX];
-};
-
struct usbip_imported_device {
uint8_t port;
uint32_t status;
@@ -28,18 +23,13 @@ struct usbip_imported_device {
uint8_t devnum;
/* usbip_class_device list */
- struct dlist *cdev_list;
struct usbip_usb_device udev;
};
struct usbip_vhci_driver {
- char sysfs_mntpath[SYSFS_PATH_MAX];
/* /sys/devices/platform/vhci_hcd */
- struct sysfs_device *hc_device;
-
- /* usbip_class_device list */
- struct dlist *cdev_list;
+ struct udev_device *hc_device;
int nports;
struct usbip_imported_device idev[MAXNPORT];
diff --git a/drivers/staging/usbip/userspace/src/Makefile.am b/drivers/staging/usbip/userspace/src/Makefile.am
index b4f8c4b04b2f..e81a4ebadeff 100644
--- a/drivers/staging/usbip/userspace/src/Makefile.am
+++ b/drivers/staging/usbip/userspace/src/Makefile.am
@@ -8,5 +8,4 @@ usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \
usbip_attach.c usbip_detach.c usbip_list.c \
usbip_bind.c usbip_unbind.c usbip_port.c
-
usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c
diff --git a/drivers/staging/usbip/userspace/src/usbip_attach.c b/drivers/staging/usbip/userspace/src/usbip_attach.c
index 085841196522..716a79e284c4 100644
--- a/drivers/staging/usbip/userspace/src/usbip_attach.c
+++ b/drivers/staging/usbip/userspace/src/usbip_attach.c
@@ -17,7 +17,6 @@
*/
#include <sys/stat.h>
-#include <sysfs/libsysfs.h>
#include <limits.h>
#include <stdint.h>
diff --git a/drivers/staging/usbip/userspace/src/usbip_bind.c b/drivers/staging/usbip/userspace/src/usbip_bind.c
index 9ecaf6e574df..fa46141ae68b 100644
--- a/drivers/staging/usbip/userspace/src/usbip_bind.c
+++ b/drivers/staging/usbip/userspace/src/usbip_bind.c
@@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <sysfs/libsysfs.h>
+#include <libudev.h>
#include <errno.h>
#include <stdio.h>
@@ -28,6 +28,7 @@
#include "usbip_common.h"
#include "utils.h"
#include "usbip.h"
+#include "sysfs_utils.h"
enum unbind_status {
UNBIND_ST_OK,
@@ -48,167 +49,92 @@ void usbip_bind_usage(void)
/* call at unbound state */
static int bind_usbip(char *busid)
{
- char bus_type[] = "usb";
char attr_name[] = "bind";
- char sysfs_mntpath[SYSFS_PATH_MAX];
char bind_attr_path[SYSFS_PATH_MAX];
- char intf_busid[SYSFS_BUS_ID_SIZE];
- struct sysfs_device *busid_dev;
- struct sysfs_attribute *bind_attr;
- struct sysfs_attribute *bConfValue;
- struct sysfs_attribute *bNumIntfs;
- int i, failed = 0;
- int rc, ret = -1;
-
- rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
- if (rc < 0) {
- err("sysfs must be mounted: %s", strerror(errno));
- return -1;
- }
+ int rc = -1;
snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s",
- sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
- USBIP_HOST_DRV_NAME, attr_name);
-
- bind_attr = sysfs_open_attribute(bind_attr_path);
- if (!bind_attr) {
- dbg("problem getting bind attribute: %s", strerror(errno));
- return -1;
- }
+ SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
+ SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name);
- busid_dev = sysfs_open_device(bus_type, busid);
- if (!busid_dev) {
- dbg("sysfs_open_device %s failed: %s", busid, strerror(errno));
- goto err_close_bind_attr;
- }
-
- bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue");
- bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces");
-
- if (!bConfValue || !bNumIntfs) {
- dbg("problem getting device attributes: %s",
+ rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid));
+ if (rc < 0) {
+ err("error binding device %s to driver: %s", busid,
strerror(errno));
- goto err_close_busid_dev;
- }
-
- for (i = 0; i < atoi(bNumIntfs->value); i++) {
- snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid,
- bConfValue->value, i);
-
- rc = sysfs_write_attribute(bind_attr, intf_busid,
- SYSFS_BUS_ID_SIZE);
- if (rc < 0) {
- dbg("bind driver at %s failed", intf_busid);
- failed = 1;
- }
+ return -1;
}
- if (!failed)
- ret = 0;
-
-err_close_busid_dev:
- sysfs_close_device(busid_dev);
-err_close_bind_attr:
- sysfs_close_attribute(bind_attr);
-
- return ret;
+ return 0;
}
/* buggy driver may cause dead lock */
static int unbind_other(char *busid)
{
- char bus_type[] = "usb";
- char intf_busid[SYSFS_BUS_ID_SIZE];
- struct sysfs_device *busid_dev;
- struct sysfs_device *intf_dev;
- struct sysfs_driver *intf_drv;
- struct sysfs_attribute *unbind_attr;
- struct sysfs_attribute *bConfValue;
- struct sysfs_attribute *bDevClass;
- struct sysfs_attribute *bNumIntfs;
- int i, rc;
enum unbind_status status = UNBIND_ST_OK;
- busid_dev = sysfs_open_device(bus_type, busid);
- if (!busid_dev) {
- dbg("sysfs_open_device %s failed: %s", busid, strerror(errno));
- return -1;
+ char attr_name[] = "unbind";
+ char unbind_attr_path[SYSFS_PATH_MAX];
+ int rc = -1;
+
+ struct udev *udev;
+ struct udev_device *dev;
+ const char *driver;
+ const char *bDevClass;
+
+ /* Create libudev context. */
+ udev = udev_new();
+
+ /* Get the device. */
+ dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
+ if (!dev) {
+ dbg("unable to find device with bus ID %s", busid);
+ goto err_close_busid_dev;
}
- bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue");
- bDevClass = sysfs_get_device_attr(busid_dev, "bDeviceClass");
- bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces");
- if (!bConfValue || !bDevClass || !bNumIntfs) {
- dbg("problem getting device attributes: %s",
- strerror(errno));
+ /* Check what kind of device it is. */
+ bDevClass = udev_device_get_sysattr_value(dev, "bDeviceClass");
+ if (!bDevClass) {
+ dbg("unable to get bDevClass device attribute");
goto err_close_busid_dev;
}
- if (!strncmp(bDevClass->value, "09", bDevClass->len)) {
+ if (!strncmp(bDevClass, "09", strlen(bDevClass))) {
dbg("skip unbinding of hub");
goto err_close_busid_dev;
}
- for (i = 0; i < atoi(bNumIntfs->value); i++) {
- snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid,
- bConfValue->value, i);
- intf_dev = sysfs_open_device(bus_type, intf_busid);
- if (!intf_dev) {
- dbg("could not open interface device: %s",
- strerror(errno));
- goto err_close_busid_dev;
- }
-
- dbg("%s -> %s", intf_dev->name, intf_dev->driver_name);
-
- if (!strncmp("unknown", intf_dev->driver_name, SYSFS_NAME_LEN))
- /* unbound interface */
- continue;
-
- if (!strncmp(USBIP_HOST_DRV_NAME, intf_dev->driver_name,
- SYSFS_NAME_LEN)) {
- /* already bound to usbip-host */
- status = UNBIND_ST_USBIP_HOST;
- continue;
- }
-
- /* unbinding */
- intf_drv = sysfs_open_driver(bus_type, intf_dev->driver_name);
- if (!intf_drv) {
- dbg("could not open interface driver on %s: %s",
- intf_dev->name, strerror(errno));
- goto err_close_intf_dev;
- }
+ /* Get the device driver. */
+ driver = udev_device_get_driver(dev);
+ if (!driver) {
+ /* No driver bound to this device. */
+ goto out;
+ }
- unbind_attr = sysfs_get_driver_attr(intf_drv, "unbind");
- if (!unbind_attr) {
- dbg("problem getting interface driver attribute: %s",
- strerror(errno));
- goto err_close_intf_drv;
- }
+ if (!strncmp(USBIP_HOST_DRV_NAME, driver,
+ strlen(USBIP_HOST_DRV_NAME))) {
+ /* Already bound to usbip-host. */
+ status = UNBIND_ST_USBIP_HOST;
+ goto out;
+ }
- rc = sysfs_write_attribute(unbind_attr, intf_dev->bus_id,
- SYSFS_BUS_ID_SIZE);
- if (rc < 0) {
- /* NOTE: why keep unbinding other interfaces? */
- dbg("unbind driver at %s failed", intf_dev->bus_id);
- status = UNBIND_ST_FAILED;
- }
+ /* Unbind device from driver. */
+ snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
+ SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
+ SYSFS_DRIVERS_NAME, driver, attr_name);
- sysfs_close_driver(intf_drv);
- sysfs_close_device(intf_dev);
+ rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
+ if (rc < 0) {
+ err("error unbinding device %s from driver", busid);
+ goto err_close_busid_dev;
}
goto out;
-err_close_intf_drv:
- sysfs_close_driver(intf_drv);
-err_close_intf_dev:
- sysfs_close_device(intf_dev);
err_close_busid_dev:
status = UNBIND_ST_FAILED;
out:
- sysfs_close_device(busid_dev);
+ udev_device_unref(dev);
+ udev_unref(udev);
return status;
}
@@ -216,6 +142,17 @@ out:
static int bind_device(char *busid)
{
int rc;
+ struct udev *udev;
+ struct udev_device *dev;
+
+ /* Check whether the device with this bus ID exists. */
+ udev = udev_new();
+ dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
+ if (!dev) {
+ err("device with the specified bus ID does not exist");
+ return -1;
+ }
+ udev_unref(udev);
rc = unbind_other(busid);
if (rc == UNBIND_ST_FAILED) {
@@ -240,7 +177,7 @@ static int bind_device(char *busid)
return -1;
}
- printf("bind device on busid %s: complete\n", busid);
+ info("bind device on busid %s: complete", busid);
return 0;
}
diff --git a/drivers/staging/usbip/userspace/src/usbip_detach.c b/drivers/staging/usbip/userspace/src/usbip_detach.c
index 13308df613a2..05c6d15856eb 100644
--- a/drivers/staging/usbip/userspace/src/usbip_detach.c
+++ b/drivers/staging/usbip/userspace/src/usbip_detach.c
@@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <sysfs/libsysfs.h>
-
#include <ctype.h>
#include <limits.h>
#include <stdint.h>
diff --git a/drivers/staging/usbip/userspace/src/usbip_list.c b/drivers/staging/usbip/userspace/src/usbip_list.c
index 237e099337a1..d5ce34a410e7 100644
--- a/drivers/staging/usbip/userspace/src/usbip_list.c
+++ b/drivers/staging/usbip/userspace/src/usbip_list.c
@@ -17,7 +17,7 @@
*/
#include <sys/types.h>
-#include <sysfs/libsysfs.h>
+#include <libudev.h>
#include <errno.h>
#include <stdbool.h>
@@ -54,7 +54,7 @@ static int get_exported_devices(char *host, int sockfd)
struct usbip_usb_device udev;
struct usbip_usb_interface uintf;
unsigned int i;
- int j, rc;
+ int rc, j;
rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
if (rc < 0) {
@@ -107,19 +107,20 @@ static int get_exported_devices(char *host, int sockfd)
for (j = 0; j < udev.bNumInterfaces; j++) {
rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf));
if (rc < 0) {
- dbg("usbip_net_recv failed: usbip_usb_intf[%d]",
- j);
+ err("usbip_net_recv failed: usbip_usb_intf[%d]",
+ j);
return -1;
}
usbip_net_pack_usb_interface(0, &uintf);
usbip_names_get_class(class_name, sizeof(class_name),
- uintf.bInterfaceClass,
- uintf.bInterfaceSubClass,
- uintf.bInterfaceProtocol);
+ uintf.bInterfaceClass,
+ uintf.bInterfaceSubClass,
+ uintf.bInterfaceProtocol);
printf("%11s: %2d - %s\n", "", j, class_name);
}
+
printf("\n");
}
@@ -150,8 +151,8 @@ static int list_exported_devices(char *host)
return 0;
}
-static void print_device(char *busid, char *vendor, char *product,
- bool parsable)
+static void print_device(const char *busid, const char *vendor,
+ const char *product, bool parsable)
{
if (parsable)
printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product);
@@ -165,106 +166,73 @@ static void print_product_name(char *product_name, bool parsable)
printf(" %s\n", product_name);
}
-static void print_interface(char *busid, char *driver, bool parsable)
-{
- if (parsable)
- printf("%s=%s#", busid, driver);
- else
- printf("%9s%s -> %s\n", "", busid, driver);
-}
-
-static int is_device(void *x)
-{
- struct sysfs_attribute *devpath;
- struct sysfs_device *dev = x;
- int ret = 0;
-
- devpath = sysfs_get_device_attr(dev, "devpath");
- if (devpath && *devpath->value != '0')
- ret = 1;
-
- return ret;
-}
-
-static int devcmp(void *a, void *b)
-{
- return strcmp(a, b);
-}
-
static int list_devices(bool parsable)
{
- char bus_type[] = "usb";
- char busid[SYSFS_BUS_ID_SIZE];
+ struct udev *udev;
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *devices, *dev_list_entry;
+ struct udev_device *dev;
+ const char *path;
+ const char *idVendor;
+ const char *idProduct;
+ const char *bConfValue;
+ const char *bNumIntfs;
+ const char *busid;
char product_name[128];
- struct sysfs_bus *ubus;
- struct sysfs_device *dev;
- struct sysfs_device *intf;
- struct sysfs_attribute *idVendor;
- struct sysfs_attribute *idProduct;
- struct sysfs_attribute *bConfValue;
- struct sysfs_attribute *bNumIntfs;
- struct dlist *devlist;
- int i;
int ret = -1;
- ubus = sysfs_open_bus(bus_type);
- if (!ubus) {
- err("could not open %s bus: %s", bus_type, strerror(errno));
- return -1;
- }
-
- devlist = sysfs_get_bus_devices(ubus);
- if (!devlist) {
- err("could not get %s bus devices: %s", bus_type,
- strerror(errno));
- goto err_out;
- }
-
- /* remove interfaces and root hubs from device list */
- dlist_filter_sort(devlist, is_device, devcmp);
-
- if (!parsable) {
- printf("Local USB devices\n");
- printf("=================\n");
- }
- dlist_for_each_data(devlist, dev, struct sysfs_device) {
- idVendor = sysfs_get_device_attr(dev, "idVendor");
- idProduct = sysfs_get_device_attr(dev, "idProduct");
- bConfValue = sysfs_get_device_attr(dev, "bConfigurationValue");
- bNumIntfs = sysfs_get_device_attr(dev, "bNumInterfaces");
+ /* Create libudev context. */
+ udev = udev_new();
+
+ /* Create libudev device enumeration. */
+ enumerate = udev_enumerate_new(udev);
+
+ /* Take only USB devices that are not hubs and do not have
+ * the bInterfaceNumber attribute, i.e. are not interfaces.
+ */
+ udev_enumerate_add_match_subsystem(enumerate, "usb");
+ udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09");
+ udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL);
+ udev_enumerate_scan_devices(enumerate);
+
+ devices = udev_enumerate_get_list_entry(enumerate);
+
+ /* Show information about each device. */
+ udev_list_entry_foreach(dev_list_entry, devices) {
+ path = udev_list_entry_get_name(dev_list_entry);
+ dev = udev_device_new_from_syspath(udev, path);
+
+ /* Get device information. */
+ idVendor = udev_device_get_sysattr_value(dev, "idVendor");
+ idProduct = udev_device_get_sysattr_value(dev, "idProduct");
+ bConfValue = udev_device_get_sysattr_value(dev, "bConfigurationValue");
+ bNumIntfs = udev_device_get_sysattr_value(dev, "bNumInterfaces");
+ busid = udev_device_get_sysname(dev);
if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) {
err("problem getting device attributes: %s",
strerror(errno));
goto err_out;
}
- /* get product name */
+ /* Get product name. */
usbip_names_get_product(product_name, sizeof(product_name),
- strtol(idVendor->value, NULL, 16),
- strtol(idProduct->value, NULL, 16));
- print_device(dev->bus_id, idVendor->value, idProduct->value,
- parsable);
+ strtol(idVendor, NULL, 16),
+ strtol(idProduct, NULL, 16));
+
+ /* Print information. */
+ print_device(busid, idVendor, idProduct, parsable);
print_product_name(product_name, parsable);
- for (i = 0; i < atoi(bNumIntfs->value); i++) {
- snprintf(busid, sizeof(busid), "%s:%.1s.%d",
- dev->bus_id, bConfValue->value, i);
- intf = sysfs_open_device(bus_type, busid);
- if (!intf) {
- err("could not open device interface: %s",
- strerror(errno));
- goto err_out;
- }
- print_interface(busid, intf->driver_name, parsable);
- sysfs_close_device(intf);
- }
printf("\n");
+
+ udev_device_unref(dev);
}
ret = 0;
err_out:
- sysfs_close_bus(ubus);
+ udev_enumerate_unref(enumerate);
+ udev_unref(udev);
return ret;
}
diff --git a/drivers/staging/usbip/userspace/src/usbip_network.h b/drivers/staging/usbip/userspace/src/usbip_network.h
index f19ae19799b4..c1e875cf1078 100644
--- a/drivers/staging/usbip/userspace/src/usbip_network.h
+++ b/drivers/staging/usbip/userspace/src/usbip_network.h
@@ -10,7 +10,6 @@
#endif
#include <sys/types.h>
-#include <sysfs/libsysfs.h>
#include <stdint.h>
diff --git a/drivers/staging/usbip/userspace/src/usbip_unbind.c b/drivers/staging/usbip/userspace/src/usbip_unbind.c
index d5a9ab6af2a6..a4a496c9cbaf 100644
--- a/drivers/staging/usbip/userspace/src/usbip_unbind.c
+++ b/drivers/staging/usbip/userspace/src/usbip_unbind.c
@@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <sysfs/libsysfs.h>
+#include <libudev.h>
#include <errno.h>
#include <stdio.h>
@@ -27,6 +27,7 @@
#include "usbip_common.h"
#include "utils.h"
#include "usbip.h"
+#include "sysfs_utils.h"
static const char usbip_unbind_usage_string[] =
"usbip unbind <args>\n"
@@ -41,115 +42,69 @@ void usbip_unbind_usage(void)
static int unbind_device(char *busid)
{
char bus_type[] = "usb";
- struct sysfs_driver *usbip_host_drv;
- struct sysfs_device *dev;
- struct dlist *devlist;
- int verified = 0;
int rc, ret = -1;
- char attr_name[] = "bConfigurationValue";
- char sysfs_mntpath[SYSFS_PATH_MAX];
- char busid_attr_path[SYSFS_PATH_MAX];
- struct sysfs_attribute *busid_attr;
- char *val = NULL;
- int len;
-
- /* verify the busid device is using usbip-host */
- usbip_host_drv = sysfs_open_driver(bus_type, USBIP_HOST_DRV_NAME);
- if (!usbip_host_drv) {
- err("could not open %s driver: %s", USBIP_HOST_DRV_NAME,
- strerror(errno));
- return -1;
- }
+ char unbind_attr_name[] = "unbind";
+ char unbind_attr_path[SYSFS_PATH_MAX];
+ char rebind_attr_name[] = "rebind";
+ char rebind_attr_path[SYSFS_PATH_MAX];
- devlist = sysfs_get_driver_devices(usbip_host_drv);
- if (!devlist) {
- err("%s is not in use by any devices", USBIP_HOST_DRV_NAME);
- goto err_close_usbip_host_drv;
- }
+ struct udev *udev;
+ struct udev_device *dev;
+ const char *driver;
- dlist_for_each_data(devlist, dev, struct sysfs_device) {
- if (!strncmp(busid, dev->name, strlen(busid)) &&
- !strncmp(dev->driver_name, USBIP_HOST_DRV_NAME,
- strlen(USBIP_HOST_DRV_NAME))) {
- verified = 1;
- break;
- }
- }
+ /* Create libudev context. */
+ udev = udev_new();
- if (!verified) {
- err("device on busid %s is not using %s", busid,
- USBIP_HOST_DRV_NAME);
- goto err_close_usbip_host_drv;
+ /* Check whether the device with this bus ID exists. */
+ dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
+ if (!dev) {
+ err("device with the specified bus ID does not exist");
+ goto err_close_udev;
}
- /*
- * NOTE: A read and write of an attribute value of the device busid
- * refers to must be done to start probing. That way a rebind of the
- * default driver for the device occurs.
- *
- * This seems very hackish and adds a lot of pointless code. I think it
- * should be done in the kernel by the driver after del_match_busid is
- * finished!
- */
-
- rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
- if (rc < 0) {
- err("sysfs must be mounted: %s", strerror(errno));
- return -1;
+ /* Check whether the device is using usbip-host driver. */
+ driver = udev_device_get_driver(dev);
+ if (!driver || strcmp(driver, "usbip-host")) {
+ err("device is not bound to usbip-host driver");
+ goto err_close_udev;
}
- snprintf(busid_attr_path, sizeof(busid_attr_path), "%s/%s/%s/%s/%s/%s",
- sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DEVICES_NAME,
- busid, attr_name);
+ /* Unbind device from driver. */
+ snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
+ SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
+ USBIP_HOST_DRV_NAME, unbind_attr_name);
- /* read a device attribute */
- busid_attr = sysfs_open_attribute(busid_attr_path);
- if (!busid_attr) {
- err("could not open %s/%s: %s", busid, attr_name,
- strerror(errno));
- return -1;
- }
-
- if (sysfs_read_attribute(busid_attr) < 0) {
- err("problem reading attribute: %s", strerror(errno));
- goto err_out;
+ rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
+ if (rc < 0) {
+ err("error unbinding device %s from driver", busid);
+ goto err_close_udev;
}
- len = busid_attr->len;
- val = malloc(len);
- *val = *busid_attr->value;
- sysfs_close_attribute(busid_attr);
-
- /* notify driver of unbind */
+ /* Notify driver of unbind. */
rc = modify_match_busid(busid, 0);
if (rc < 0) {
err("unable to unbind device on %s", busid);
- goto err_out;
+ goto err_close_udev;
}
- /* write the device attribute */
- busid_attr = sysfs_open_attribute(busid_attr_path);
- if (!busid_attr) {
- err("could not open %s/%s: %s", busid, attr_name,
- strerror(errno));
- return -1;
- }
+ /* Trigger new probing. */
+ snprintf(rebind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
+ SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
+ USBIP_HOST_DRV_NAME, rebind_attr_name);
- rc = sysfs_write_attribute(busid_attr, val, len);
+ rc = write_sysfs_attribute(rebind_attr_path, busid, strlen(busid));
if (rc < 0) {
- err("problem writing attribute: %s", strerror(errno));
- goto err_out;
+ err("error rebinding");
+ goto err_close_udev;
}
- sysfs_close_attribute(busid_attr);
ret = 0;
- printf("unbind device on busid %s: complete\n", busid);
+ info("unbind device on busid %s: complete", busid);
-err_out:
- free(val);
-err_close_usbip_host_drv:
- sysfs_close_driver(usbip_host_drv);
+err_close_udev:
+ udev_device_unref(dev);
+ udev_unref(udev);
return ret;
}
diff --git a/drivers/staging/usbip/userspace/src/usbipd.c b/drivers/staging/usbip/userspace/src/usbipd.c
index 7980f8b5517b..2cae4ce48d11 100644
--- a/drivers/staging/usbip/userspace/src/usbipd.c
+++ b/drivers/staging/usbip/userspace/src/usbipd.c
@@ -43,6 +43,7 @@
#include "usbip_host_driver.h"
#include "usbip_common.h"
#include "usbip_network.h"
+#include "list.h"
#undef PROGNAME
#define PROGNAME "usbipd"
@@ -93,6 +94,7 @@ static int recv_request_import(int sockfd)
struct op_common reply;
struct usbip_exported_device *edev;
struct usbip_usb_device pdu_udev;
+ struct list_head *i;
int found = 0;
int error = 0;
int rc;
@@ -107,8 +109,8 @@ static int recv_request_import(int sockfd)
}
PACK_OP_IMPORT_REQUEST(0, &req);
- dlist_for_each_data(host_driver->edev_list, edev,
- struct usbip_exported_device) {
+ list_for_each(i, &host_driver->edev_list) {
+ edev = list_entry(i, struct usbip_exported_device, node);
if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) {
info("found requested device: %s", req.busid);
found = 1;
@@ -161,13 +163,12 @@ static int send_reply_devlist(int connfd)
struct usbip_usb_device pdu_udev;
struct usbip_usb_interface pdu_uinf;
struct op_devlist_reply reply;
- int i;
- int rc;
+ struct list_head *j;
+ int rc, i;
reply.ndev = 0;
/* number of exported devices */
- dlist_for_each_data(host_driver->edev_list, edev,
- struct usbip_exported_device) {
+ list_for_each(j, &host_driver->edev_list) {
reply.ndev += 1;
}
info("exportable devices: %d", reply.ndev);
@@ -185,8 +186,8 @@ static int send_reply_devlist(int connfd)
return -1;
}
- dlist_for_each_data(host_driver->edev_list, edev,
- struct usbip_exported_device) {
+ list_for_each(j, &host_driver->edev_list) {
+ edev = list_entry(j, struct usbip_exported_device, node);
dump_usb_device(&edev->udev);
memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
usbip_net_pack_usb_device(1, &pdu_udev);
@@ -203,9 +204,9 @@ static int send_reply_devlist(int connfd)
usbip_net_pack_usb_interface(1, &pdu_uinf);
rc = usbip_net_send(connfd, &pdu_uinf,
- sizeof(pdu_uinf));
+ sizeof(pdu_uinf));
if (rc < 0) {
- dbg("usbip_net_send failed: pdu_uinf");
+ err("usbip_net_send failed: pdu_uinf");
return -1;
}
}
diff --git a/drivers/staging/usbip/userspace/src/utils.c b/drivers/staging/usbip/userspace/src/utils.c
index 2d4966e6289c..2b3d6d235015 100644
--- a/drivers/staging/usbip/userspace/src/utils.c
+++ b/drivers/staging/usbip/userspace/src/utils.c
@@ -16,61 +16,37 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <sysfs/libsysfs.h>
-
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "usbip_common.h"
#include "utils.h"
+#include "sysfs_utils.h"
int modify_match_busid(char *busid, int add)
{
- char bus_type[] = "usb";
char attr_name[] = "match_busid";
- char buff[SYSFS_BUS_ID_SIZE + 4];
- char sysfs_mntpath[SYSFS_PATH_MAX];
+ char command[SYSFS_BUS_ID_SIZE + 4];
char match_busid_attr_path[SYSFS_PATH_MAX];
- struct sysfs_attribute *match_busid_attr;
- int rc, ret = 0;
-
- if (strnlen(busid, SYSFS_BUS_ID_SIZE) > SYSFS_BUS_ID_SIZE - 1) {
- dbg("busid is too long");
- return -1;
- }
-
- rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
- if (rc < 0) {
- err("sysfs must be mounted: %s", strerror(errno));
- return -1;
- }
+ int rc;
snprintf(match_busid_attr_path, sizeof(match_busid_attr_path),
- "%s/%s/%s/%s/%s/%s", sysfs_mntpath, SYSFS_BUS_NAME, bus_type,
- SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name);
-
- match_busid_attr = sysfs_open_attribute(match_busid_attr_path);
- if (!match_busid_attr) {
- dbg("problem getting match_busid attribute: %s",
- strerror(errno));
- return -1;
- }
+ "%s/%s/%s/%s/%s/%s", SYSFS_MNT_PATH, SYSFS_BUS_NAME,
+ SYSFS_BUS_TYPE, SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME,
+ attr_name);
if (add)
- snprintf(buff, SYSFS_BUS_ID_SIZE + 4, "add %s", busid);
+ snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", busid);
else
- snprintf(buff, SYSFS_BUS_ID_SIZE + 4, "del %s", busid);
+ snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", busid);
- dbg("write \"%s\" to %s", buff, match_busid_attr->path);
-
- rc = sysfs_write_attribute(match_busid_attr, buff, sizeof(buff));
+ rc = write_sysfs_attribute(match_busid_attr_path, command,
+ sizeof(command));
if (rc < 0) {
dbg("failed to write match_busid: %s", strerror(errno));
- ret = -1;
+ return -1;
}
- sysfs_close_attribute(match_busid_attr);
-
- return ret;
+ return 0;
}
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
index 72391ef87646..1e84577230ef 100644
--- a/drivers/staging/usbip/vhci_hcd.c
+++ b/drivers/staging/usbip/vhci_hcd.c
@@ -205,8 +205,6 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
}
}
- pr_info("changed %d\n", changed);
-
if ((hcd->state == HC_STATE_SUSPENDED) && (changed == 1))
usb_hcd_resume_root_hub(hcd);
@@ -273,14 +271,14 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
}
break;
case USB_PORT_FEAT_POWER:
- usbip_dbg_vhci_rh(" ClearPortFeature: "
- "USB_PORT_FEAT_POWER\n");
+ usbip_dbg_vhci_rh(
+ " ClearPortFeature: USB_PORT_FEAT_POWER\n");
dum->port_status[rhport] = 0;
dum->resuming = 0;
break;
case USB_PORT_FEAT_C_RESET:
- usbip_dbg_vhci_rh(" ClearPortFeature: "
- "USB_PORT_FEAT_C_RESET\n");
+ usbip_dbg_vhci_rh(
+ " ClearPortFeature: USB_PORT_FEAT_C_RESET\n");
switch (dum->vdev[rhport].speed) {
case USB_SPEED_HIGH:
dum->port_status[rhport] |=
@@ -339,16 +337,17 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
if (dum->vdev[rhport].ud.status ==
VDEV_ST_NOTASSIGNED) {
- usbip_dbg_vhci_rh(" enable rhport %d "
- "(status %u)\n",
- rhport,
- dum->vdev[rhport].ud.status);
+ usbip_dbg_vhci_rh(
+ " enable rhport %d (status %u)\n",
+ rhport,
+ dum->vdev[rhport].ud.status);
dum->port_status[rhport] |=
USB_PORT_STAT_ENABLE;
}
}
((__le16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]);
- ((__le16 *) buf)[1] = cpu_to_le16(dum->port_status[rhport] >> 16);
+ ((__le16 *) buf)[1] =
+ cpu_to_le16(dum->port_status[rhport] >> 16);
usbip_dbg_vhci_rh(" GetPortStatus bye %x %x\n", ((u16 *)buf)[0],
((u16 *)buf)[1]);
@@ -360,12 +359,12 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case SetPortFeature:
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- usbip_dbg_vhci_rh(" SetPortFeature: "
- "USB_PORT_FEAT_SUSPEND\n");
+ usbip_dbg_vhci_rh(
+ " SetPortFeature: USB_PORT_FEAT_SUSPEND\n");
break;
case USB_PORT_FEAT_RESET:
- usbip_dbg_vhci_rh(" SetPortFeature: "
- "USB_PORT_FEAT_RESET\n");
+ usbip_dbg_vhci_rh(
+ " SetPortFeature: USB_PORT_FEAT_RESET\n");
/* if it's already running, disconnect first */
if (dum->port_status[rhport] & USB_PORT_STAT_ENABLE) {
dum->port_status[rhport] &=
@@ -537,9 +536,8 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
case USB_REQ_GET_DESCRIPTOR:
if (ctrlreq->wValue == cpu_to_le16(USB_DT_DEVICE << 8))
- usbip_dbg_vhci_hc("Not yet?: "
- "Get_Descriptor to device 0 "
- "(get max pipe size)\n");
+ usbip_dbg_vhci_hc(
+ "Not yet?:Get_Descriptor to device 0 (get max pipe size)\n");
if (vdev->udev)
usb_put_dev(vdev->udev);
@@ -548,8 +546,9 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
default:
/* NOT REACHED */
- dev_err(dev, "invalid request to devnum 0 bRequest %u, "
- "wValue %u\n", ctrlreq->bRequest,
+ dev_err(dev,
+ "invalid request to devnum 0 bRequest %u, wValue %u\n",
+ ctrlreq->bRequest,
ctrlreq->wValue);
ret = -EINVAL;
goto no_need_xmit;
@@ -1070,8 +1069,9 @@ static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state)
spin_unlock(&the_controller->lock);
if (connected > 0) {
- dev_info(&pdev->dev, "We have %d active connection%s. Do not "
- "suspend.\n", connected, (connected == 1 ? "" : "s"));
+ dev_info(&pdev->dev,
+ "We have %d active connection%s. Do not suspend.\n",
+ connected, (connected == 1 ? "" : "s"));
ret = -EBUSY;
} else {
dev_info(&pdev->dev, "suspend vhci_hcd");
diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c
index 0141bc34d5cc..e0980324fb03 100644
--- a/drivers/staging/usbip/vhci_sysfs.c
+++ b/drivers/staging/usbip/vhci_sysfs.c
@@ -47,8 +47,8 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
* up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
* port number and its peer IP address.
*/
- out += sprintf(out, "prt sta spd bus dev socket "
- "local_busid\n");
+ out += sprintf(out,
+ "prt sta spd bus dev socket local_busid\n");
for (i = 0; i < VHCI_NPORTS; i++) {
struct vhci_device *vdev = port_to_vdev(i);
@@ -114,7 +114,8 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
int err;
__u32 rhport = 0;
- sscanf(buf, "%u", &rhport);
+ if (sscanf(buf, "%u", &rhport) != 1)
+ return -EINVAL;
/* check rhport */
if (rhport >= VHCI_NPORTS) {
@@ -182,7 +183,8 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
* @devid: unique device identifier in a remote host
* @speed: usb device speed in a remote host
*/
- sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed);
+ if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 1)
+ return -EINVAL;
usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n",
rhport, sockfd, devid, speed);
@@ -215,8 +217,9 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
return -EINVAL;
}
- dev_info(dev, "rhport(%u) sockfd(%d) devid(%u) speed(%u)\n",
- rhport, sockfd, devid, speed);
+ dev_info(dev,
+ "rhport(%u) sockfd(%d) devid(%u) speed(%u) speed_str(%s)\n",
+ rhport, sockfd, devid, speed, usb_speed_string(speed));
vdev->devid = devid;
vdev->speed = speed;
diff --git a/drivers/staging/vt6655/80211mgr.c b/drivers/staging/vt6655/80211mgr.c
index 7949d58ad7d1..9aa2e46c4a5d 100644
--- a/drivers/staging/vt6655/80211mgr.c
+++ b/drivers/staging/vt6655/80211mgr.c
@@ -91,12 +91,15 @@ vMgrEncodeBeacon(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_BEACON_OFF_TS);
- pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_BEACON_OFF_BCN_INT);
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_BEACON_OFF_CAPINFO);
+ pFrame->pqwTimestamp = (PQWORD)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_BEACON_OFF_TS);
+ pFrame->pwBeaconInterval = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_BEACON_OFF_BCN_INT);
+ pFrame->pwCapInfo = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_BEACON_OFF_CAPINFO);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_BEACON_OFF_SSID;
@@ -124,16 +127,20 @@ vMgrDecodeBeacon(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_BEACON_OFF_TS);
- pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_BEACON_OFF_BCN_INT);
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_BEACON_OFF_CAPINFO);
+ pFrame->pqwTimestamp = (PQWORD)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_BEACON_OFF_TS);
+ pFrame->pwBeaconInterval = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_BEACON_OFF_BCN_INT);
+ pFrame->pwCapInfo = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_BEACON_OFF_CAPINFO);
/* Information elements */
- pItem = (PWLAN_IE)((unsigned char *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)))
- + WLAN_BEACON_OFF_SSID);
+ pItem = (PWLAN_IE)((unsigned char *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))) +
+ WLAN_BEACON_OFF_SSID);
while (((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) {
switch (pItem->byElementID) {
case WLAN_EID_SSID:
@@ -171,7 +178,8 @@ vMgrDecodeBeacon(
case WLAN_EID_RSN_WPA:
if (pFrame->pRSNWPA == NULL) {
if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
- pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
+ pFrame->pRSNWPA =
+ (PWLAN_IE_RSN_EXT)pItem;
}
break;
@@ -181,7 +189,8 @@ vMgrDecodeBeacon(
break;
case WLAN_EID_EXTSUPP_RATES:
if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ pFrame->pExtSuppRates =
+ (PWLAN_IE_SUPP_RATES)pItem;
break;
case WLAN_EID_COUNTRY: /* 7 */
@@ -191,7 +200,8 @@ vMgrDecodeBeacon(
case WLAN_EID_PWR_CONSTRAINT: /* 32 */
if (pFrame->pIE_PowerConstraint == NULL)
- pFrame->pIE_PowerConstraint = (PWLAN_IE_PW_CONST)pItem;
+ pFrame->pIE_PowerConstraint =
+ (PWLAN_IE_PW_CONST)pItem;
break;
case WLAN_EID_CH_SWITCH: /* 37 */
@@ -210,7 +220,9 @@ vMgrDecodeBeacon(
break;
default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in beacon decode.\n", pItem->byElementID);
+ DBG_PRT(MSG_LEVEL_DEBUG,
+ KERN_INFO "Unrecognized EID=%dd in beacon decode.\n",
+ pItem->byElementID);
break;
}
@@ -282,9 +294,11 @@ vMgrEncodeDisassociation(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_DISASSOC_OFF_REASON);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DISASSOC_OFF_REASON + sizeof(*(pFrame->pwReason));
+ pFrame->pwReason = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_DISASSOC_OFF_REASON);
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DISASSOC_OFF_REASON +
+ sizeof(*(pFrame->pwReason));
return;
}
@@ -308,8 +322,9 @@ vMgrDecodeDisassociation(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_DISASSOC_OFF_REASON);
+ pFrame->pwReason = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_DISASSOC_OFF_REASON);
return;
}
@@ -332,11 +347,14 @@ vMgrEncodeAssocRequest(
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCREQ_OFF_LISTEN_INT);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCREQ_OFF_LISTEN_INT + sizeof(*(pFrame->pwListenInterval));
+ pFrame->pwCapInfo = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_ASSOCREQ_OFF_CAP_INFO);
+ pFrame->pwListenInterval = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_ASSOCREQ_OFF_LISTEN_INT);
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCREQ_OFF_LISTEN_INT +
+ sizeof(*(pFrame->pwListenInterval));
return;
}
@@ -360,10 +378,12 @@ vMgrDecodeAssocRequest(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCREQ_OFF_LISTEN_INT);
+ pFrame->pwCapInfo = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_ASSOCREQ_OFF_CAP_INFO);
+ pFrame->pwListenInterval = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_ASSOCREQ_OFF_LISTEN_INT);
/* Information elements */
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -377,7 +397,8 @@ vMgrDecodeAssocRequest(
break;
case WLAN_EID_SUPP_RATES:
if (pFrame->pSuppRates == NULL)
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ pFrame->pSuppRates =
+ (PWLAN_IE_SUPP_RATES)pItem;
break;
case WLAN_EID_RSN:
@@ -387,16 +408,19 @@ vMgrDecodeAssocRequest(
case WLAN_EID_RSN_WPA:
if (pFrame->pRSNWPA == NULL) {
if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
- pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
+ pFrame->pRSNWPA =
+ (PWLAN_IE_RSN_EXT)pItem;
}
break;
case WLAN_EID_EXTSUPP_RATES:
if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ pFrame->pExtSuppRates =
+ (PWLAN_IE_SUPP_RATES)pItem;
break;
default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in assocreq decode.\n",
+ DBG_PRT(MSG_LEVEL_DEBUG,
+ KERN_INFO "Unrecognized EID=%dd in assocreq decode.\n",
pItem->byElementID);
break;
}
@@ -424,14 +448,17 @@ vMgrEncodeAssocResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_AID);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCRESP_OFF_AID
- + sizeof(*(pFrame->pwAid));
+ pFrame->pwCapInfo = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_ASSOCRESP_OFF_CAP_INFO);
+ pFrame->pwStatus = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_ASSOCRESP_OFF_STATUS);
+ pFrame->pwAid = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_ASSOCRESP_OFF_AID);
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCRESP_OFF_AID +
+ sizeof(*(pFrame->pwAid));
return;
}
@@ -457,16 +484,20 @@ vMgrDecodeAssocResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_AID);
+ pFrame->pwCapInfo = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_ASSOCRESP_OFF_CAP_INFO);
+ pFrame->pwStatus = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_ASSOCRESP_OFF_STATUS);
+ pFrame->pwAid = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_ASSOCRESP_OFF_AID);
/* Information elements */
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_SUPP_RATES);
+ pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_ASSOCRESP_OFF_SUPP_RATES);
pItem = (PWLAN_IE)(pFrame->pSuppRates);
pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
@@ -474,7 +505,9 @@ vMgrDecodeAssocResponse(
if ((((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) &&
(pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) {
pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pFrame->pExtSuppRates=[%p].\n", pItem);
+ DBG_PRT(MSG_LEVEL_DEBUG,
+ KERN_INFO "pFrame->pExtSuppRates=[%p].\n",
+ pItem);
} else {
pFrame->pExtSuppRates = NULL;
}
@@ -500,13 +533,17 @@ vMgrEncodeReassocRequest(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCREQ_OFF_LISTEN_INT);
- pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCREQ_OFF_CURR_AP);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCREQ_OFF_CURR_AP + sizeof(*(pFrame->pAddrCurrAP));
+ pFrame->pwCapInfo = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_REASSOCREQ_OFF_CAP_INFO);
+ pFrame->pwListenInterval = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_REASSOCREQ_OFF_LISTEN_INT);
+ pFrame->pAddrCurrAP = (PIEEE_ADDR)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_REASSOCREQ_OFF_CURR_AP);
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCREQ_OFF_CURR_AP +
+ sizeof(*(pFrame->pAddrCurrAP));
return;
}
@@ -531,12 +568,15 @@ vMgrDecodeReassocRequest(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCREQ_OFF_LISTEN_INT);
- pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCREQ_OFF_CURR_AP);
+ pFrame->pwCapInfo = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_REASSOCREQ_OFF_CAP_INFO);
+ pFrame->pwListenInterval = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_REASSOCREQ_OFF_LISTEN_INT);
+ pFrame->pAddrCurrAP = (PIEEE_ADDR)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_REASSOCREQ_OFF_CURR_AP);
/* Information elements */
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -550,7 +590,8 @@ vMgrDecodeReassocRequest(
break;
case WLAN_EID_SUPP_RATES:
if (pFrame->pSuppRates == NULL)
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ pFrame->pSuppRates =
+ (PWLAN_IE_SUPP_RATES)pItem;
break;
case WLAN_EID_RSN:
@@ -560,16 +601,19 @@ vMgrDecodeReassocRequest(
case WLAN_EID_RSN_WPA:
if (pFrame->pRSNWPA == NULL) {
if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
- pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
+ pFrame->pRSNWPA =
+ (PWLAN_IE_RSN_EXT)pItem;
}
break;
case WLAN_EID_EXTSUPP_RATES:
if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ pFrame->pExtSuppRates =
+ (PWLAN_IE_SUPP_RATES)pItem;
break;
default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in reassocreq decode.\n",
+ DBG_PRT(MSG_LEVEL_DEBUG,
+ KERN_INFO "Unrecognized EID=%dd in reassocreq decode.\n",
pItem->byElementID);
break;
}
@@ -631,16 +675,20 @@ vMgrDecodeProbeRequest(
case WLAN_EID_SUPP_RATES:
if (pFrame->pSuppRates == NULL)
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ pFrame->pSuppRates =
+ (PWLAN_IE_SUPP_RATES)pItem;
break;
case WLAN_EID_EXTSUPP_RATES:
if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ pFrame->pExtSuppRates =
+ (PWLAN_IE_SUPP_RATES)pItem;
break;
default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Bad EID=%dd in probereq\n", pItem->byElementID);
+ DBG_PRT(MSG_LEVEL_DEBUG,
+ KERN_INFO "Bad EID=%dd in probereq\n",
+ pItem->byElementID);
break;
}
@@ -668,15 +716,18 @@ vMgrEncodeProbeResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_PROBERESP_OFF_TS);
- pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_PROBERESP_OFF_BCN_INT);
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_PROBERESP_OFF_CAP_INFO);
+ pFrame->pqwTimestamp = (PQWORD)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_PROBERESP_OFF_TS);
+ pFrame->pwBeaconInterval = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_PROBERESP_OFF_BCN_INT);
+ pFrame->pwCapInfo = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_PROBERESP_OFF_CAP_INFO);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_PROBERESP_OFF_CAP_INFO +
- sizeof(*(pFrame->pwCapInfo));
+ sizeof(*(pFrame->pwCapInfo));
return;
}
@@ -702,12 +753,15 @@ vMgrDecodeProbeResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_PROBERESP_OFF_TS);
- pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_PROBERESP_OFF_BCN_INT);
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_PROBERESP_OFF_CAP_INFO);
+ pFrame->pqwTimestamp = (PQWORD)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_PROBERESP_OFF_TS);
+ pFrame->pwBeaconInterval = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_PROBERESP_OFF_BCN_INT);
+ pFrame->pwCapInfo = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_PROBERESP_OFF_CAP_INFO);
/* Information elements */
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -721,7 +775,8 @@ vMgrDecodeProbeResponse(
break;
case WLAN_EID_SUPP_RATES:
if (pFrame->pSuppRates == NULL)
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ pFrame->pSuppRates =
+ (PWLAN_IE_SUPP_RATES)pItem;
break;
case WLAN_EID_FH_PARMS:
break;
@@ -735,7 +790,8 @@ vMgrDecodeProbeResponse(
break;
case WLAN_EID_IBSS_PARMS:
if (pFrame->pIBSSParms == NULL)
- pFrame->pIBSSParms = (PWLAN_IE_IBSS_PARMS)pItem;
+ pFrame->pIBSSParms =
+ (PWLAN_IE_IBSS_PARMS)pItem;
break;
case WLAN_EID_RSN:
@@ -745,7 +801,8 @@ vMgrDecodeProbeResponse(
case WLAN_EID_RSN_WPA:
if (pFrame->pRSNWPA == NULL) {
if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
- pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
+ pFrame->pRSNWPA =
+ (PWLAN_IE_RSN_EXT)pItem;
}
break;
case WLAN_EID_ERP:
@@ -754,7 +811,8 @@ vMgrDecodeProbeResponse(
break;
case WLAN_EID_EXTSUPP_RATES:
if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ pFrame->pExtSuppRates =
+ (PWLAN_IE_SUPP_RATES)pItem;
break;
case WLAN_EID_COUNTRY: /* 7 */
@@ -764,7 +822,8 @@ vMgrDecodeProbeResponse(
case WLAN_EID_PWR_CONSTRAINT: /* 32 */
if (pFrame->pIE_PowerConstraint == NULL)
- pFrame->pIE_PowerConstraint = (PWLAN_IE_PW_CONST)pItem;
+ pFrame->pIE_PowerConstraint =
+ (PWLAN_IE_PW_CONST)pItem;
break;
case WLAN_EID_CH_SWITCH: /* 37 */
@@ -783,7 +842,9 @@ vMgrDecodeProbeResponse(
break;
default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Bad EID=%dd in proberesp\n", pItem->byElementID);
+ DBG_PRT(MSG_LEVEL_DEBUG,
+ KERN_INFO "Bad EID=%dd in proberesp\n",
+ pItem->byElementID);
break;
}
@@ -811,13 +872,17 @@ vMgrEncodeAuthen(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwAuthAlgorithm = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_AUTHEN_OFF_AUTH_ALG);
- pFrame->pwAuthSequence = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_AUTHEN_OFF_AUTH_SEQ);
- pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_AUTHEN_OFF_STATUS);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_AUTHEN_OFF_STATUS + sizeof(*(pFrame->pwStatus));
+ pFrame->pwAuthAlgorithm = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_AUTHEN_OFF_AUTH_ALG);
+ pFrame->pwAuthSequence = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_AUTHEN_OFF_AUTH_SEQ);
+ pFrame->pwStatus = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_AUTHEN_OFF_STATUS);
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_AUTHEN_OFF_STATUS +
+ sizeof(*(pFrame->pwStatus));
return;
}
@@ -843,12 +908,15 @@ vMgrDecodeAuthen(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwAuthAlgorithm = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_AUTHEN_OFF_AUTH_ALG);
- pFrame->pwAuthSequence = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_AUTHEN_OFF_AUTH_SEQ);
- pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_AUTHEN_OFF_STATUS);
+ pFrame->pwAuthAlgorithm = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_AUTHEN_OFF_AUTH_ALG);
+ pFrame->pwAuthSequence = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_AUTHEN_OFF_AUTH_SEQ);
+ pFrame->pwStatus = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_AUTHEN_OFF_STATUS);
/* Information elements */
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
@@ -880,9 +948,11 @@ vMgrEncodeDeauthen(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_DEAUTHEN_OFF_REASON);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DEAUTHEN_OFF_REASON + sizeof(*(pFrame->pwReason));
+ pFrame->pwReason = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_DEAUTHEN_OFF_REASON);
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DEAUTHEN_OFF_REASON +
+ sizeof(*(pFrame->pwReason));
return;
}
@@ -906,8 +976,9 @@ vMgrDecodeDeauthen(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_DEAUTHEN_OFF_REASON);
+ pFrame->pwReason = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_DEAUTHEN_OFF_REASON);
return;
}
@@ -931,14 +1002,18 @@ vMgrEncodeReassocResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_AID);
-
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCRESP_OFF_AID + sizeof(*(pFrame->pwAid));
+ pFrame->pwCapInfo = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_REASSOCRESP_OFF_CAP_INFO);
+ pFrame->pwStatus = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_REASSOCRESP_OFF_STATUS);
+ pFrame->pwAid = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_REASSOCRESP_OFF_AID);
+
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCRESP_OFF_AID +
+ sizeof(*(pFrame->pwAid));
return;
}
@@ -964,16 +1039,20 @@ vMgrDecodeReassocResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_AID);
+ pFrame->pwCapInfo = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_REASSOCRESP_OFF_CAP_INFO);
+ pFrame->pwStatus = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_REASSOCRESP_OFF_STATUS);
+ pFrame->pwAid = (unsigned short *)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_REASSOCRESP_OFF_AID);
/* Information elements */
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_SUPP_RATES);
+ pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)
+ (WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
+ WLAN_REASSOCRESP_OFF_SUPP_RATES);
pItem = (PWLAN_IE)(pFrame->pSuppRates);
pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
diff --git a/drivers/staging/vt6655/aes_ccmp.c b/drivers/staging/vt6655/aes_ccmp.c
index 82b0bd1c056a..4ccfe06481fc 100644
--- a/drivers/staging/vt6655/aes_ccmp.c
+++ b/drivers/staging/vt6655/aes_ccmp.c
@@ -46,8 +46,7 @@
* SBOX Table
*/
-static unsigned char sbox_table[256] =
-{
+static unsigned char sbox_table[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
@@ -153,9 +152,8 @@ static void SubBytes(unsigned char *in, unsigned char *out)
{
int i;
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < 16; i++)
out[i] = sbox_table[in[i]];
- }
}
static void ShiftRows(unsigned char *in, unsigned char *out)
@@ -205,8 +203,7 @@ static void AESv128(unsigned char *key, unsigned char *data, unsigned char *ciph
SubBytes(ciphertext, TmpdataA);
ShiftRows(TmpdataA, TmpdataB);
xor_128(TmpdataB, abyRoundKey, ciphertext);
- } else /* round 1 ~ 9 */
- {
+ } else /* round 1 ~ 9 */{
SubBytes(ciphertext, TmpdataA);
ShiftRows(TmpdataA, TmpdataB);
MixColumns(&TmpdataB[0], &TmpdataA[0]);
@@ -311,13 +308,11 @@ bool AESbGenCCMP(unsigned char *pbyRxKey, unsigned char *pbyFrame, unsigned shor
/* CCMP */
AESv128(pbyRxKey, MIC_IV, abyMIC);
- for (kk = 0; kk < 16; kk++) {
+ for (kk = 0; kk < 16; kk++)
abyTmp[kk] = MIC_HDR1[kk] ^ abyMIC[kk];
- }
AESv128(pbyRxKey, abyTmp, abyMIC);
- for (kk = 0; kk < 16; kk++) {
+ for (kk = 0; kk < 16; kk++)
abyTmp[kk] = MIC_HDR2[kk] ^ abyMIC[kk];
- }
AESv128(pbyRxKey, abyTmp, abyMIC);
wCnt = 1;
@@ -330,12 +325,10 @@ bool AESbGenCCMP(unsigned char *pbyRxKey, unsigned char *pbyFrame, unsigned shor
AESv128(pbyRxKey, abyCTRPLD, abyTmp);
- for (kk = 0; kk < 16; kk++) {
+ for (kk = 0; kk < 16; kk++)
abyPlainText[kk] = abyTmp[kk] ^ pbyPayload[kk];
- }
- for (kk = 0; kk < 16; kk++) {
+ for (kk = 0; kk < 16; kk++)
abyTmp[kk] = abyMIC[kk] ^ abyPlainText[kk];
- }
AESv128(pbyRxKey, abyTmp, abyMIC);
memcpy(pbyPayload, abyPlainText, 16);
@@ -345,27 +338,23 @@ bool AESbGenCCMP(unsigned char *pbyRxKey, unsigned char *pbyFrame, unsigned shor
/* last payload */
memcpy(&(abyLastCipher[0]), pbyPayload, jj);
- for (ii = jj; ii < 16; ii++) {
+ for (ii = jj; ii < 16; ii++)
abyLastCipher[ii] = 0x00;
- }
abyCTRPLD[14] = (unsigned char)(wCnt >> 8);
abyCTRPLD[15] = (unsigned char)(wCnt & 0xff);
AESv128(pbyRxKey, abyCTRPLD, abyTmp);
- for (kk = 0; kk < 16; kk++) {
+ for (kk = 0; kk < 16; kk++)
abyPlainText[kk] = abyTmp[kk] ^ abyLastCipher[kk];
- }
memcpy(pbyPayload, abyPlainText, jj);
pbyPayload += jj;
/* for MIC calculation */
- for (ii = jj; ii < 16; ii++) {
+ for (ii = jj; ii < 16; ii++)
abyPlainText[ii] = 0x00;
- }
- for (kk = 0; kk < 16; kk++) {
+ for (kk = 0; kk < 16; kk++)
abyTmp[kk] = abyMIC[kk] ^ abyPlainText[kk];
- }
AESv128(pbyRxKey, abyTmp, abyMIC);
/* =>above is the calculate MIC */
@@ -375,9 +364,8 @@ bool AESbGenCCMP(unsigned char *pbyRxKey, unsigned char *pbyFrame, unsigned shor
abyCTRPLD[14] = (unsigned char)(wCnt >> 8);
abyCTRPLD[15] = (unsigned char)(wCnt & 0xff);
AESv128(pbyRxKey, abyCTRPLD, abyTmp);
- for (kk = 0; kk < 8; kk++) {
+ for (kk = 0; kk < 8; kk++)
abyTmp[kk] = abyTmp[kk] ^ pbyPayload[kk];
- }
/* =>above is the dec-MIC from packet */
/* -------------------------------------------- */
diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h
index 32d808ec502a..f8e41487f856 100644
--- a/drivers/staging/vt6655/desc.h
+++ b/drivers/staging/vt6655/desc.h
@@ -276,9 +276,8 @@ typedef struct tagSRxDesc {
volatile SRDES1 m_rd1RD1;
volatile u32 buff_addr;
volatile u32 next_desc;
- struct tagSRxDesc *next;//4 bytes
- volatile PDEVICE_RD_INFO pRDInfo;//4 bytes
- volatile u32 Reserved[2];//8 bytes
+ struct tagSRxDesc *next __aligned(8);
+ volatile PDEVICE_RD_INFO pRDInfo __aligned(8);
} __attribute__ ((__packed__))
SRxDesc, *PSRxDesc;
typedef const SRxDesc *PCSRxDesc;
@@ -361,9 +360,8 @@ typedef struct tagSTxDesc {
volatile STDES1 m_td1TD1;
volatile u32 buff_addr;
volatile u32 next_desc;
- struct tagSTxDesc *next; //4 bytes
- volatile PDEVICE_TD_INFO pTDInfo;//4 bytes
- volatile u32 Reserved[2];//8 bytes
+ struct tagSTxDesc *next __aligned(8);
+ volatile PDEVICE_TD_INFO pTDInfo __aligned(8);
} __attribute__ ((__packed__))
STxDesc, *PSTxDesc;
typedef const STxDesc *PCSTxDesc;
@@ -375,9 +373,8 @@ typedef struct tagSTxSyncDesc {
volatile u32 next_desc; // pointer to next logical descriptor
volatile unsigned short m_wFIFOCtl;
volatile unsigned short m_wTimeStamp;
- struct tagSTxSyncDesc *next; //4 bytes
- volatile PDEVICE_TD_INFO pTDInfo;//4 bytes
- volatile u32 m_dwReserved2;
+ struct tagSTxSyncDesc *next __aligned(8);
+ volatile PDEVICE_TD_INFO pTDInfo __aligned(8);
} __attribute__ ((__packed__))
STxSyncDesc, *PSTxSyncDesc;
typedef const STxSyncDesc *PCSTxSyncDesc;
diff --git a/drivers/staging/vt6655/dpc.c b/drivers/staging/vt6655/dpc.c
index 0a29c9015419..771bf35ae044 100644
--- a/drivers/staging/vt6655/dpc.c
+++ b/drivers/staging/vt6655/dpc.c
@@ -729,27 +729,27 @@ device_receive_frame(
// Soft MIC
if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_TKIP)) {
if (bIsWEP) {
- unsigned long *pdwMIC_L;
- unsigned long *pdwMIC_R;
- unsigned long dwMIC_Priority;
- unsigned long dwMICKey0 = 0, dwMICKey1 = 0;
- unsigned long dwLocalMIC_L = 0;
- unsigned long dwLocalMIC_R = 0;
+ __le32 *pdwMIC_L;
+ __le32 *pdwMIC_R;
+ __le32 dwMIC_Priority;
+ __le32 dwMICKey0 = 0, dwMICKey1 = 0;
+ u32 dwLocalMIC_L = 0;
+ u32 dwLocalMIC_R = 0;
viawget_wpa_header *wpahdr;
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[24]));
- dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[28]));
+ dwMICKey0 = cpu_to_le32(*(u32 *)(&pKey->abyKey[24]));
+ dwMICKey1 = cpu_to_le32(*(u32 *)(&pKey->abyKey[28]));
} else {
if (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
- dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[16]));
- dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[20]));
+ dwMICKey0 = cpu_to_le32(*(u32 *)(&pKey->abyKey[16]));
+ dwMICKey1 = cpu_to_le32(*(u32 *)(&pKey->abyKey[20]));
} else if ((pKey->dwKeyIndex & BIT28) == 0) {
- dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[16]));
- dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[20]));
+ dwMICKey0 = cpu_to_le32(*(u32 *)(&pKey->abyKey[16]));
+ dwMICKey1 = cpu_to_le32(*(u32 *)(&pKey->abyKey[20]));
} else {
- dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[24]));
- dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[28]));
+ dwMICKey0 = cpu_to_le32(*(u32 *)(&pKey->abyKey[24]));
+ dwMICKey1 = cpu_to_le32(*(u32 *)(&pKey->abyKey[28]));
}
}
@@ -763,14 +763,14 @@ device_receive_frame(
MIC_vGetMIC(&dwLocalMIC_L, &dwLocalMIC_R);
MIC_vUnInit();
- pdwMIC_L = (unsigned long *)(skb->data + 4 + FrameSize);
- pdwMIC_R = (unsigned long *)(skb->data + 4 + FrameSize + 4);
+ pdwMIC_L = (__le32 *)(skb->data + 4 + FrameSize);
+ pdwMIC_R = (__le32 *)(skb->data + 4 + FrameSize + 4);
//DBG_PRN_GRP12(("RxL: %lx, RxR: %lx\n", *pdwMIC_L, *pdwMIC_R));
//DBG_PRN_GRP12(("LocalL: %lx, LocalR: %lx\n", dwLocalMIC_L, dwLocalMIC_R));
//DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dwMICKey0= %lx,dwMICKey1= %lx \n", dwMICKey0, dwMICKey1);
- if ((cpu_to_le32(*pdwMIC_L) != dwLocalMIC_L) ||
- (cpu_to_le32(*pdwMIC_R) != dwLocalMIC_R) ||
+ if ((le32_to_cpu(*pdwMIC_L) != dwLocalMIC_L) ||
+ (le32_to_cpu(*pdwMIC_R) != dwLocalMIC_R) ||
pDevice->bRxMICFail) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MIC comparison is fail!\n");
pDevice->bRxMICFail = false;
diff --git a/drivers/staging/vt6655/key.c b/drivers/staging/vt6655/key.c
index eab3b41f9e3c..78b5809b8304 100644
--- a/drivers/staging/vt6655/key.c
+++ b/drivers/staging/vt6655/key.c
@@ -242,7 +242,7 @@ bool KeybSetKey(
if (uKeyLength == WLAN_WEP104_KEYLEN)
pKey->abyKey[15] |= 0x80;
}
- MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pbyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
+ MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pbyBSSID, (u32 *)pKey->abyKey, byLocalID);
if ((dwKeyIndex & USE_KEYRSC) == 0) {
// RSC set by NIC
@@ -306,7 +306,7 @@ bool KeybSetKey(
if (uKeyLength == WLAN_WEP104_KEYLEN)
pKey->abyKey[15] |= 0x80;
}
- MACvSetKeyEntry(dwIoBase, pTable->KeyTable[j].wKeyCtl, j, uKeyIdx, pbyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
+ MACvSetKeyEntry(dwIoBase, pTable->KeyTable[j].wKeyCtl, j, uKeyIdx, pbyBSSID, (u32 *)pKey->abyKey, byLocalID);
if ((dwKeyIndex & USE_KEYRSC) == 0) {
// RSC set by NIC
@@ -670,7 +670,7 @@ bool KeybSetDefaultKey(
if (uKeyLength == WLAN_WEP104_KEYLEN)
pKey->abyKey[15] |= 0x80;
}
- MACvSetKeyEntry(dwIoBase, pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl, MAX_KEY_TABLE-1, uKeyIdx, pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
+ MACvSetKeyEntry(dwIoBase, pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl, MAX_KEY_TABLE-1, uKeyIdx, pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID, (u32 *)pKey->abyKey, byLocalID);
if ((dwKeyIndex & USE_KEYRSC) == 0) {
// RSC set by NIC
@@ -766,7 +766,7 @@ bool KeybSetAllGroupKey(
if (uKeyLength == WLAN_WEP104_KEYLEN)
pKey->abyKey[15] |= 0x80;
}
- MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pTable->KeyTable[i].abyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
+ MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pTable->KeyTable[i].abyBSSID, (u32 *)pKey->abyKey, byLocalID);
if ((dwKeyIndex & USE_KEYRSC) == 0) {
// RSC set by NIC
diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c
index 21bd8a1126d7..0ec079fa0398 100644
--- a/drivers/staging/vt6655/mac.c
+++ b/drivers/staging/vt6655/mac.c
@@ -1428,10 +1428,10 @@ bool MACbPSWakeup(unsigned long dwIoBase)
*/
void MACvSetKeyEntry(unsigned long dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx,
- unsigned int uKeyIdx, unsigned char *pbyAddr, unsigned long *pdwKey, unsigned char byLocalID)
+ unsigned int uKeyIdx, unsigned char *pbyAddr, u32 *pdwKey, unsigned char byLocalID)
{
unsigned short wOffset;
- unsigned long dwData;
+ u32 dwData;
int ii;
if (byLocalID <= 1)
@@ -1445,7 +1445,7 @@ void MACvSetKeyEntry(unsigned long dwIoBase, unsigned short wKeyCtl, unsigned in
dwData |= wKeyCtl;
dwData <<= 16;
dwData |= MAKEWORD(*(pbyAddr+4), *(pbyAddr+5));
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "1. wOffset: %d, Data: %lX, KeyCtl:%X\n", wOffset, dwData, wKeyCtl);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "1. wOffset: %d, Data: %X, KeyCtl:%X\n", wOffset, dwData, wKeyCtl);
VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
@@ -1460,7 +1460,7 @@ void MACvSetKeyEntry(unsigned long dwIoBase, unsigned short wKeyCtl, unsigned in
dwData |= *(pbyAddr+1);
dwData <<= 8;
dwData |= *(pbyAddr+0);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "2. wOffset: %d, Data: %lX\n", wOffset, dwData);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "2. wOffset: %d, Data: %X\n", wOffset, dwData);
VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
@@ -1470,7 +1470,7 @@ void MACvSetKeyEntry(unsigned long dwIoBase, unsigned short wKeyCtl, unsigned in
wOffset += (uKeyIdx * 4);
for (ii = 0; ii < 4; ii++) {
// always push 128 bits
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "3.(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "3.(%d) wOffset: %d, Data: %X\n", ii, wOffset+ii, *pdwKey);
VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii);
VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, *pdwKey++);
VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h
index 3f177f7c581c..4615db05549f 100644
--- a/drivers/staging/vt6655/mac.h
+++ b/drivers/staging/vt6655/mac.h
@@ -1038,7 +1038,7 @@ bool MACbFlushSYNCFifo(unsigned long dwIoBase);
bool MACbPSWakeup(unsigned long dwIoBase);
void MACvSetKeyEntry(unsigned long dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx,
- unsigned int uKeyIdx, unsigned char *pbyAddr, unsigned long *pdwKey, unsigned char byLocalID);
+ unsigned int uKeyIdx, unsigned char *pbyAddr, u32 *pdwKey, unsigned char byLocalID);
void MACvDisableKeyEntry(unsigned long dwIoBase, unsigned int uEntryIdx);
void MACvSetDefaultKeyEntry(unsigned long dwIoBase, unsigned int uKeyLen,
unsigned int uKeyIdx, unsigned long *pdwKey, unsigned char byLocalID);
diff --git a/drivers/staging/vt6655/michael.c b/drivers/staging/vt6655/michael.c
index 7ea5f7f82f43..ade4c855f20d 100644
--- a/drivers/staging/vt6655/michael.c
+++ b/drivers/staging/vt6655/michael.c
@@ -53,14 +53,14 @@
*/
static void s_vClear(void); // Clear the internal message,
// resets the object to the state just after construction.
-static void s_vSetKey(unsigned long dwK0, unsigned long dwK1);
+static void s_vSetKey(u32 dwK0, u32 dwK1);
static void s_vAppendByte(unsigned char b); // Add a single byte to the internal message
/*--------------------- Export Variables --------------------------*/
-static unsigned long L, R; // Current state
+static u32 L, R; /* Current state */
-static unsigned long K0, K1; // Key
-static unsigned long M; // Message accumulator (single word)
+static u32 K0, K1; /* Key */
+static u32 M; /* Message accumulator (single word) */
static unsigned int nBytesInM; // # bytes in M
/*--------------------- Export Functions --------------------------*/
@@ -98,7 +98,7 @@ static void s_vClear(void)
M = 0;
}
-static void s_vSetKey(unsigned long dwK0, unsigned long dwK1)
+static void s_vSetKey(u32 dwK0, u32 dwK1)
{
// Set the key
K0 = dwK0;
@@ -129,7 +129,7 @@ static void s_vAppendByte(unsigned char b)
}
}
-void MIC_vInit(unsigned long dwK0, unsigned long dwK1)
+void MIC_vInit(u32 dwK0, u32 dwK1)
{
// Set the key
s_vSetKey(dwK0, dwK1);
@@ -155,7 +155,7 @@ void MIC_vAppend(unsigned char *src, unsigned int nBytes)
}
}
-void MIC_vGetMIC(unsigned long *pdwL, unsigned long *pdwR)
+void MIC_vGetMIC(u32 *pdwL, u32 *pdwR)
{
// Append the minimum padding
s_vAppendByte(0x5a);
diff --git a/drivers/staging/vt6655/michael.h b/drivers/staging/vt6655/michael.h
index 387d20623aa3..f6c2c15d9cb6 100644
--- a/drivers/staging/vt6655/michael.h
+++ b/drivers/staging/vt6655/michael.h
@@ -31,11 +31,13 @@
#ifndef __MICHAEL_H__
#define __MICHAEL_H__
+#include <linux/types.h>
+
/*--------------------- Export Definitions -------------------------*/
/*--------------------- Export Types ------------------------------*/
-void MIC_vInit(unsigned long dwK0, unsigned long dwK1);
+void MIC_vInit(u32 dwK0, u32 dwK1);
void MIC_vUnInit(void);
@@ -44,7 +46,7 @@ void MIC_vAppend(unsigned char *src, unsigned int nBytes);
/* Get the MIC result. Destination should accept 8 bytes of result. */
/* This also resets the message to empty. */
-void MIC_vGetMIC(unsigned long *pdwL, unsigned long *pdwR);
+void MIC_vGetMIC(u32 *pdwL, u32 *pdwR);
/*--------------------- Export Macros ------------------------------*/
diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c
index 6affd6edac0d..c2653eb4f76c 100644
--- a/drivers/staging/vt6655/rxtx.c
+++ b/drivers/staging/vt6655/rxtx.c
@@ -1257,11 +1257,11 @@ s_cbFillTxBufHead(PSDevice pDevice, unsigned char byPktType, unsigned char *pbyT
// unsigned char abyTmp[8];
// unsigned long dwCRC;
unsigned int cbMICHDR = 0;
- unsigned long dwMICKey0, dwMICKey1;
- unsigned long dwMIC_Priority;
- unsigned long *pdwMIC_L;
- unsigned long *pdwMIC_R;
- unsigned long dwSafeMIC_L, dwSafeMIC_R; //Fix "Last Frag Size" < "MIC length".
+ u32 dwMICKey0, dwMICKey1;
+ u32 dwMIC_Priority;
+ u32 *pdwMIC_L;
+ u32 *pdwMIC_R;
+ u32 dwSafeMIC_L, dwSafeMIC_R; /* Fix "Last Frag Size" < "MIC length". */
bool bMIC2Frag = false;
unsigned int uMICFragLen = 0;
unsigned int uMACfragNum = 1;
@@ -1434,21 +1434,21 @@ s_cbFillTxBufHead(PSDevice pDevice, unsigned char byPktType, unsigned char *pbyT
//////////////////////////////////////////////////////////////////
if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
if (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
- dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[16]);
- dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[20]);
+ dwMICKey0 = *(u32 *)(&pTransmitKey->abyKey[16]);
+ dwMICKey1 = *(u32 *)(&pTransmitKey->abyKey[20]);
} else if ((pTransmitKey->dwKeyIndex & AUTHENTICATOR_KEY) != 0) {
- dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[16]);
- dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[20]);
+ dwMICKey0 = *(u32 *)(&pTransmitKey->abyKey[16]);
+ dwMICKey1 = *(u32 *)(&pTransmitKey->abyKey[20]);
} else {
- dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[24]);
- dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[28]);
+ dwMICKey0 = *(u32 *)(&pTransmitKey->abyKey[24]);
+ dwMICKey1 = *(u32 *)(&pTransmitKey->abyKey[28]);
}
// DO Software Michael
MIC_vInit(dwMICKey0, dwMICKey1);
MIC_vAppend((unsigned char *)&(psEthHeader->abyDstAddr[0]), 12);
dwMIC_Priority = 0;
MIC_vAppend((unsigned char *)&dwMIC_Priority, 4);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MIC KEY: %lX, %lX\n", dwMICKey0, dwMICKey1);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MIC KEY: %X, %X\n", dwMICKey0, dwMICKey1);
}
///////////////////////////////////////////////////////////////////
@@ -1624,10 +1624,10 @@ s_cbFillTxBufHead(PSDevice pDevice, unsigned char byPktType, unsigned char *pbyT
if (bMIC2Frag == false) {
if (uTmpLen != 0)
MIC_vAppend((pbyBuffer + uLength), uTmpLen);
- pdwMIC_L = (unsigned long *)(pbyBuffer + uLength + uTmpLen);
- pdwMIC_R = (unsigned long *)(pbyBuffer + uLength + uTmpLen + 4);
+ pdwMIC_L = (u32 *)(pbyBuffer + uLength + uTmpLen);
+ pdwMIC_R = (u32 *)(pbyBuffer + uLength + uTmpLen + 4);
MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Last MIC:%lX, %lX\n", *pdwMIC_L, *pdwMIC_R);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Last MIC:%X, %X\n", *pdwMIC_L, *pdwMIC_R);
} else {
if (uMICFragLen >= 4) {
memcpy((pbyBuffer + uLength), ((unsigned char *)&dwSafeMIC_R + (uMICFragLen - 4)),
@@ -1744,8 +1744,8 @@ s_cbFillTxBufHead(PSDevice pDevice, unsigned char byPktType, unsigned char *pbyT
uMICFragLen = cbFragPayloadSize - uTmpLen;
ASSERT(uMICFragLen < cbMIClen);
- pdwMIC_L = (unsigned long *)(pbyBuffer + uLength + uTmpLen);
- pdwMIC_R = (unsigned long *)(pbyBuffer + uLength + uTmpLen + 4);
+ pdwMIC_L = (u32 *)(pbyBuffer + uLength + uTmpLen);
+ pdwMIC_R = (u32 *)(pbyBuffer + uLength + uTmpLen + 4);
MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
dwSafeMIC_L = *pdwMIC_L;
dwSafeMIC_R = *pdwMIC_R;
@@ -1759,7 +1759,7 @@ s_cbFillTxBufHead(PSDevice pDevice, unsigned char byPktType, unsigned char *pbyT
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n");
*/
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Get MIC:%lX, %lX\n", *pdwMIC_L, *pdwMIC_R);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Get MIC:%X, %X\n", *pdwMIC_L, *pdwMIC_R);
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Middle frag len: %d\n", uTmpLen);
/*
@@ -1873,8 +1873,8 @@ s_cbFillTxBufHead(PSDevice pDevice, unsigned char byPktType, unsigned char *pbyT
MIC_vAppend((pbyBuffer + uLength - cb802_1_H_len), cbFrameBodySize);
- pdwMIC_L = (unsigned long *)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize);
- pdwMIC_R = (unsigned long *)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize + 4);
+ pdwMIC_L = (u32 *)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize);
+ pdwMIC_R = (u32 *)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize + 4);
MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
MIC_vUnInit();
@@ -1887,7 +1887,7 @@ s_cbFillTxBufHead(PSDevice pDevice, unsigned char byPktType, unsigned char *pbyT
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "uLength: %d, %d\n", uLength, cbFrameBodySize);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "cbReqCount:%d, %d, %d, %d\n", cbReqCount, cbHeaderLength, uPadding, cbIVlen);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MIC:%lx, %lx\n", *pdwMIC_L, *pdwMIC_R);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MIC:%x, %x\n", *pdwMIC_L, *pdwMIC_R);
/*
for (ii = 0; ii < 8; ii++) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", *(((unsigned char *)(pdwMIC_L) + ii)));
@@ -2592,10 +2592,10 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, unsigned char *pbMPDU, un
unsigned int uPadding = 0;
unsigned int cbMICHDR = 0;
unsigned int uLength = 0;
- unsigned long dwMICKey0, dwMICKey1;
- unsigned long dwMIC_Priority;
- unsigned long *pdwMIC_L;
- unsigned long *pdwMIC_R;
+ u32 dwMICKey0, dwMICKey1;
+ u32 dwMIC_Priority;
+ u32 *pdwMIC_L;
+ u32 *pdwMIC_R;
unsigned short wTxBufSize;
unsigned int cbMacHdLen;
SEthernetHeader sEthHeader;
@@ -2841,22 +2841,22 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, unsigned char *pbMPDU, un
}
if ((pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
- dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[16]);
- dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[20]);
+ dwMICKey0 = *(u32 *)(&pTransmitKey->abyKey[16]);
+ dwMICKey1 = *(u32 *)(&pTransmitKey->abyKey[20]);
// DO Software Michael
MIC_vInit(dwMICKey0, dwMICKey1);
MIC_vAppend((unsigned char *)&(sEthHeader.abyDstAddr[0]), 12);
dwMIC_Priority = 0;
MIC_vAppend((unsigned char *)&dwMIC_Priority, 4);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "DMA0_tx_8021:MIC KEY: %lX, %lX\n", dwMICKey0, dwMICKey1);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "DMA0_tx_8021:MIC KEY: %X, %X\n", dwMICKey0, dwMICKey1);
uLength = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen;
MIC_vAppend((pbyTxBufferAddr + uLength), cbFrameBodySize);
- pdwMIC_L = (unsigned long *)(pbyTxBufferAddr + uLength + cbFrameBodySize);
- pdwMIC_R = (unsigned long *)(pbyTxBufferAddr + uLength + cbFrameBodySize + 4);
+ pdwMIC_L = (u32 *)(pbyTxBufferAddr + uLength + cbFrameBodySize);
+ pdwMIC_R = (u32 *)(pbyTxBufferAddr + uLength + cbFrameBodySize + 4);
MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
MIC_vUnInit();
@@ -2869,7 +2869,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, unsigned char *pbMPDU, un
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "uLength: %d, %d\n", uLength, cbFrameBodySize);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "cbReqCount:%d, %d, %d, %d\n", cbReqCount, cbHeaderSize, uPadding, cbIVlen);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MIC:%lx, %lx\n", *pdwMIC_L, *pdwMIC_R);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MIC:%x, %x\n", *pdwMIC_L, *pdwMIC_R);
}
diff --git a/drivers/staging/vt6655/wmgr.c b/drivers/staging/vt6655/wmgr.c
index 5200a2a0ecca..b673bc9b2130 100644
--- a/drivers/staging/vt6655/wmgr.c
+++ b/drivers/staging/vt6655/wmgr.c
@@ -967,10 +967,10 @@ s_vMgrRxAssocResponse(
sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
// decode the frame
vMgrDecodeAssocResponse(&sFrame);
- if ((sFrame.pwCapInfo == 0) ||
- (sFrame.pwStatus == 0) ||
- (sFrame.pwAid == 0) ||
- (sFrame.pSuppRates == 0)) {
+ if ((sFrame.pwCapInfo == NULL) ||
+ (sFrame.pwStatus == NULL) ||
+ (sFrame.pwAid == NULL) ||
+ (sFrame.pSuppRates == NULL)) {
DBG_PORT80(0xCC);
return;
}
@@ -1812,10 +1812,10 @@ s_vMgrRxBeacon(
// decode the beacon frame
vMgrDecodeBeacon(&sFrame);
- if ((sFrame.pwBeaconInterval == 0) ||
- (sFrame.pwCapInfo == 0) ||
- (sFrame.pSSID == 0) ||
- (sFrame.pSuppRates == 0)) {
+ if ((sFrame.pwBeaconInterval == NULL) ||
+ (sFrame.pwCapInfo == NULL) ||
+ (sFrame.pSSID == NULL) ||
+ (sFrame.pSuppRates == NULL)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rx beacon frame error\n");
return;
}
@@ -2072,7 +2072,7 @@ s_vMgrRxBeacon(
if (bTSFLargeDiff)
bUpdateTSF = true;
- if (pDevice->bEnablePSMode && (sFrame.pTIM != 0)) {
+ if (pDevice->bEnablePSMode && (sFrame.pTIM != NULL)) {
// deal with DTIM, analysis TIM
pMgmt->bMulticastTIM = WLAN_MGMT_IS_MULTICAST_TIM(sFrame.pTIM->byBitMapCtl) ? true : false;
pMgmt->byDTIMCount = sFrame.pTIM->byDTIMCount;
@@ -4107,11 +4107,11 @@ s_vMgrRxProbeResponse(
sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
vMgrDecodeProbeResponse(&sFrame);
- if ((sFrame.pqwTimestamp == 0) ||
- (sFrame.pwBeaconInterval == 0) ||
- (sFrame.pwCapInfo == 0) ||
- (sFrame.pSSID == 0) ||
- (sFrame.pSuppRates == 0)) {
+ if ((sFrame.pqwTimestamp == NULL) ||
+ (sFrame.pwBeaconInterval == NULL) ||
+ (sFrame.pwCapInfo == NULL) ||
+ (sFrame.pSSID == NULL) ||
+ (sFrame.pSuppRates == NULL)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe resp:Fail addr:[%p] \n", pRxPacket->p80211Header);
DBG_PORT80(0xCC);
return;
@@ -4120,7 +4120,7 @@ s_vMgrRxProbeResponse(
if (sFrame.pSSID->len == 0)
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rx Probe resp: SSID len = 0 \n");
- if (sFrame.pDSParms != 0) {
+ if (sFrame.pDSParms != NULL) {
if (byCurrChannel > CB_MAX_CHANNEL_24G) {
// channel remapping to
byIEChannel = get_channel_mapping(pMgmt->pAdapter, sFrame.pDSParms->byCurrChannel, PHY_TYPE_11A);
diff --git a/drivers/staging/vt6656/80211hdr.h b/drivers/staging/vt6656/80211hdr.h
index 000304ffad6c..1e778ba7c634 100644
--- a/drivers/staging/vt6656/80211hdr.h
+++ b/drivers/staging/vt6656/80211hdr.h
@@ -151,7 +151,7 @@
#ifdef __BIG_ENDIAN
/* GET & SET Frame Control bit */
-#define WLAN_GET_FC_PRVER(n) ((((u16)(n) >> 8) & (BIT0 | BIT1))
+#define WLAN_GET_FC_PRVER(n) (((u16)(n) >> 8) & (BIT0 | BIT1))
#define WLAN_GET_FC_FTYPE(n) ((((u16)(n) >> 8) & (BIT2 | BIT3)) >> 2)
#define WLAN_GET_FC_FSTYPE(n) ((((u16)(n) >> 8) \
& (BIT4|BIT5|BIT6|BIT7)) >> 4)
diff --git a/drivers/staging/vt6656/aes_ccmp.c b/drivers/staging/vt6656/aes_ccmp.c
index 61b9f7bdb858..e2bfa8d266cd 100644
--- a/drivers/staging/vt6656/aes_ccmp.c
+++ b/drivers/staging/vt6656/aes_ccmp.c
@@ -269,9 +269,9 @@ bool AESbGenCCMP(u8 *pbyRxKey, u8 *pbyFrame, u16 wFrameSize)
/* MIC_HDR1 */
MIC_HDR1[0] = (u8)(wHLen >> 8);
MIC_HDR1[1] = (u8)(wHLen & 0xff);
- byTmp = (u8)(pMACHeader->frame_control & 0xff);
+ byTmp = (u8)(le16_to_cpu(pMACHeader->frame_control) >> 8);
MIC_HDR1[2] = byTmp & 0x8f;
- byTmp = (u8)(pMACHeader->frame_control >> 8);
+ byTmp = (u8)(le16_to_cpu(pMACHeader->frame_control) & 0xff);
byTmp &= 0x87;
MIC_HDR1[3] = byTmp | 0x40;
memcpy(&(MIC_HDR1[4]), pMACHeader->addr1, ETH_ALEN);
@@ -279,7 +279,7 @@ bool AESbGenCCMP(u8 *pbyRxKey, u8 *pbyFrame, u16 wFrameSize)
/* MIC_HDR2 */
memcpy(&(MIC_HDR2[0]), pMACHeader->addr3, ETH_ALEN);
- byTmp = (u8)(pMACHeader->seq_ctrl & 0xff);
+ byTmp = (u8)(le16_to_cpu(pMACHeader->seq_ctrl) >> 8);
MIC_HDR2[6] = byTmp & 0x0f;
MIC_HDR2[7] = 0;
diff --git a/drivers/staging/vt6656/card.h b/drivers/staging/vt6656/card.h
index c3017a74fa0f..f843e50875f9 100644
--- a/drivers/staging/vt6656/card.h
+++ b/drivers/staging/vt6656/card.h
@@ -39,13 +39,6 @@ typedef enum _CARD_PHY_TYPE {
PHY_TYPE_11A
} CARD_PHY_TYPE, *PCARD_PHY_TYPE;
-typedef enum _CARD_OP_MODE {
- OP_MODE_INFRASTRUCTURE = 0,
- OP_MODE_ADHOC,
- OP_MODE_AP,
- OP_MODE_UNKNOWN
-} CARD_OP_MODE, *PCARD_OP_MODE;
-
#define CB_MAX_CHANNEL_24G 14
#define CB_MAX_CHANNEL_5G 42 /* add channel9(5045MHz), 41==>42 */
#define CB_MAX_CHANNEL (CB_MAX_CHANNEL_24G+CB_MAX_CHANNEL_5G)
diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h
index 1f422574c3d8..e2abe3ddd244 100644
--- a/drivers/staging/vt6656/device.h
+++ b/drivers/staging/vt6656/device.h
@@ -158,10 +158,10 @@ typedef enum __device_msg_level {
/*
* Enum of context types for SendPacket
*/
-typedef enum _CONTEXT_TYPE {
- CONTEXT_DATA_PACKET = 1,
- CONTEXT_MGMT_PACKET
-} CONTEXT_TYPE;
+enum {
+ CONTEXT_DATA_PACKET = 1,
+ CONTEXT_MGMT_PACKET
+};
/* RCB (Receive Control Block) */
struct vnt_rcb {
@@ -180,9 +180,7 @@ struct vnt_usb_send_context {
struct sk_buff *pPacket;
struct urb *pUrb;
unsigned int uBufLen;
- CONTEXT_TYPE Type;
- struct ethhdr sEthHeader;
- void *Next;
+ u8 type;
bool bBoolInUse;
unsigned char Data[MAX_TOTAL_SIZE_WITH_ALL_HEADERS];
};
@@ -206,29 +204,10 @@ typedef struct _DEFAULT_CONFIG {
/*
* Structure to keep track of USB interrupt packets
*/
-typedef struct {
- unsigned int uDataLen;
- u8 * pDataBuf;
- /* struct urb *pUrb; */
- bool bInUse;
-} INT_BUFFER, *PINT_BUFFER;
-
-/* 0:11A 1:11B 2:11G */
-typedef enum _VIA_BB_TYPE
-{
- BB_TYPE_11A = 0,
- BB_TYPE_11B,
- BB_TYPE_11G
-} VIA_BB_TYPE, *PVIA_BB_TYPE;
-
-/* 0:11a, 1:11b, 2:11gb (only CCK in BasicRate), 3:11ga(OFDM in BasicRate) */
-typedef enum _VIA_PKT_TYPE
-{
- PK_TYPE_11A = 0,
- PK_TYPE_11B,
- PK_TYPE_11GB,
- PK_TYPE_11GA
-} VIA_PKT_TYPE, *PVIA_PKT_TYPE;
+struct vnt_interrupt_buffer {
+ u8 *data_buf;
+ bool in_use;
+};
/*++ NDIS related */
@@ -297,16 +276,6 @@ typedef struct tagSPMKIDCandidateEvent {
PMKID_CANDIDATE CandidateList[MAX_PMKIDLIST];
} SPMKIDCandidateEvent, *PSPMKIDCandidateEvent;
-/*++ 802.11h related */
-#define MAX_QUIET_COUNT 8
-
-typedef struct tagSQuietControl {
- bool bEnable;
- u32 dwStartTime;
- u8 byPeriod;
- u16 wDuration;
-} SQuietControl, *PSQuietControl;
-
/* The receive duplicate detection cache entry */
typedef struct tagSCacheEntry{
u16 wFmSequence;
@@ -386,8 +355,6 @@ struct vnt_private {
OPTIONS sOpts;
- struct tasklet_struct CmdWorkItem;
- struct tasklet_struct EventWorkItem;
struct work_struct read_work_item;
struct work_struct rx_mng_work_item;
@@ -437,29 +404,11 @@ struct vnt_private {
struct vnt_tx_pkt_info pkt_info[16];
/* Variables to track resources for the Interrupt In Pipe */
- INT_BUFFER intBuf;
- int fKillEventPollingThread;
- int bEventAvailable;
+ struct vnt_interrupt_buffer int_buf;
/* default config from file by user setting */
DEFAULT_CONFIG config_file;
- /* Statistic for USB */
- unsigned long ulBulkInPosted;
- unsigned long ulBulkInError;
- unsigned long ulBulkInContCRCError;
- unsigned long ulBulkInBytesRead;
-
- unsigned long ulBulkOutPosted;
- unsigned long ulBulkOutError;
- unsigned long ulBulkOutContCRCError;
- unsigned long ulBulkOutBytesWrite;
-
- unsigned long ulIntInPosted;
- unsigned long ulIntInError;
- unsigned long ulIntInContCRCError;
- unsigned long ulIntInBytesRead;
-
/* Version control */
u16 wFirmwareVersion;
u8 byLocalID;
@@ -480,11 +429,6 @@ struct vnt_private {
int bExistSWNetAddr;
/* Maintain statistical debug info. */
- unsigned long packetsReceived;
- unsigned long packetsReceivedDropped;
- unsigned long packetsReceivedOverflow;
- unsigned long packetsSent;
- unsigned long packetsSentDropped;
unsigned long SendContextsInUse;
unsigned long RcvBuffersInUse;
@@ -549,8 +493,8 @@ struct vnt_private {
u8 byCWMaxMin;
/* Rate */
- VIA_BB_TYPE byBBType; /* 0: 11A, 1:11B, 2:11G */
- VIA_PKT_TYPE byPacketType; /* 0:11a 1:11b 2:11gb 3:11ga */
+ u8 byBBType; /* 0: 11A, 1:11B, 2:11G */
+ u8 byPacketType; /* 0:11a 1:11b 2:11gb 3:11ga */
u16 wBasicRate;
u8 byACKRate;
u8 byTopOFDMBasicRate;
@@ -588,7 +532,9 @@ struct vnt_private {
u16 wFragmentationThreshold;
u8 byShortRetryLimit;
u8 byLongRetryLimit;
- CARD_OP_MODE eOPMode;
+
+ enum nl80211_iftype op_mode;
+
int bBSSIDFilter;
u16 wMaxTransmitMSDULifetime;
u8 abyBSSID[ETH_ALEN];
@@ -807,5 +753,6 @@ struct vnt_private {
(fMP_DISCONNECTED | fMP_RESET_IN_PROGRESS | fMP_HALT_IN_PROGRESS | fMP_INIT_IN_PROGRESS | fMP_SURPRISE_REMOVED)) == 0)
int device_alloc_frag_buf(struct vnt_private *, PSDeFragControlBlock pDeF);
+void vnt_configure_filter(struct vnt_private *);
#endif
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c
index eca04c0c1d97..4ccaa7e29a1c 100644
--- a/drivers/staging/vt6656/dpc.c
+++ b/drivers/staging/vt6656/dpc.c
@@ -627,7 +627,7 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, struct vnt_rcb *pRCB,
// Now it only supports 802.11g Infrastructure Mode, and support rate must up to 54 Mbps
if (pDevice->bDiversityEnable && (FrameSize>50) &&
- (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) &&
+ pDevice->op_mode == NL80211_IFTYPE_STATION &&
(pDevice->bLinkPass == true)) {
BBvAntennaDiversity(pDevice, s_byGetRateIdx(*pbyRxRate), 0);
}
@@ -1227,14 +1227,13 @@ static int s_bAPModeRxData(struct vnt_private *pDevice, struct sk_buff *skb,
if (is_multicast_ether_addr((u8 *)(skb->data+cbHeaderOffset))) {
if (pMgmt->sNodeDBTable[0].bPSEnable) {
- skbcpy = dev_alloc_skb((int)pDevice->rx_buf_sz);
+ skbcpy = netdev_alloc_skb(pDevice->dev, pDevice->rx_buf_sz);
// if any node in PS mode, buffer packet until DTIM.
if (skbcpy == NULL) {
DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "relay multicast no skb available \n");
}
else {
- skbcpy->dev = pDevice->dev;
skbcpy->len = FrameSize;
memcpy(skbcpy->data, skb->data+cbHeaderOffset, FrameSize);
skb_queue_tail(&(pMgmt->sNodeDBTable[0].sTxPSQueue), skbcpy);
@@ -1295,63 +1294,66 @@ static int s_bAPModeRxData(struct vnt_private *pDevice, struct sk_buff *skb,
void RXvWorkItem(struct work_struct *work)
{
- struct vnt_private *pDevice =
+ struct vnt_private *priv =
container_of(work, struct vnt_private, read_work_item);
- int ntStatus;
- struct vnt_rcb *pRCB = NULL;
+ int status;
+ struct vnt_rcb *rcb = NULL;
- if (pDevice->Flags & fMP_DISCONNECTED)
+ if (priv->Flags & fMP_DISCONNECTED)
return;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Rx Polling Thread\n");
- spin_lock_irq(&pDevice->lock);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Rx Polling Thread\n");
- while ((pDevice->Flags & fMP_POST_READS) &&
- MP_IS_READY(pDevice) &&
- (pDevice->NumRecvFreeList != 0) ) {
- pRCB = pDevice->FirstRecvFreeList;
- pDevice->NumRecvFreeList--;
- DequeueRCB(pDevice->FirstRecvFreeList, pDevice->LastRecvFreeList);
- ntStatus = PIPEnsBulkInUsbRead(pDevice, pRCB);
- }
- pDevice->bIsRxWorkItemQueued = false;
- spin_unlock_irq(&pDevice->lock);
+ spin_lock_irq(&priv->lock);
+
+ while ((priv->Flags & fMP_POST_READS) && MP_IS_READY(priv) &&
+ (priv->NumRecvFreeList != 0)) {
+ rcb = priv->FirstRecvFreeList;
+
+ priv->NumRecvFreeList--;
+
+ DequeueRCB(priv->FirstRecvFreeList, priv->LastRecvFreeList);
+
+ status = PIPEnsBulkInUsbRead(priv, rcb);
+ }
+ priv->bIsRxWorkItemQueued = false;
+
+ spin_unlock_irq(&priv->lock);
}
-void RXvFreeRCB(struct vnt_rcb *pRCB, int bReAllocSkb)
+void RXvFreeRCB(struct vnt_rcb *rcb, int re_alloc_skb)
{
- struct vnt_private *pDevice = pRCB->pDevice;
+ struct vnt_private *priv = rcb->pDevice;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->RXvFreeRCB\n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->RXvFreeRCB\n");
- if (bReAllocSkb == false) {
- kfree_skb(pRCB->skb);
- bReAllocSkb = true;
+ if (re_alloc_skb == false) {
+ kfree_skb(rcb->skb);
+ re_alloc_skb = true;
}
- if (bReAllocSkb == true) {
- pRCB->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
- // todo error handling
- if (pRCB->skb == NULL) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR" Failed to re-alloc rx skb\n");
- }else {
- pRCB->skb->dev = pDevice->dev;
- }
- }
- //
- // Insert the RCB back in the Recv free list
- //
- EnqueueRCB(pDevice->FirstRecvFreeList, pDevice->LastRecvFreeList, pRCB);
- pDevice->NumRecvFreeList++;
+ if (re_alloc_skb == true) {
+ rcb->skb = netdev_alloc_skb(priv->dev, priv->rx_buf_sz);
+ /* TODO error handling */
+ if (!rcb->skb) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR
+ " Failed to re-alloc rx skb\n");
+ }
+ }
- if ((pDevice->Flags & fMP_POST_READS) && MP_IS_READY(pDevice) &&
- (pDevice->bIsRxWorkItemQueued == false) ) {
+ /* Insert the RCB back in the Recv free list */
+ EnqueueRCB(priv->FirstRecvFreeList, priv->LastRecvFreeList, rcb);
+ priv->NumRecvFreeList++;
- pDevice->bIsRxWorkItemQueued = true;
- schedule_work(&pDevice->read_work_item);
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"<----RXFreeRCB %d %d\n",pDevice->NumRecvFreeList, pDevice->NumRecvMngList);
+ if ((priv->Flags & fMP_POST_READS) && MP_IS_READY(priv) &&
+ (priv->bIsRxWorkItemQueued == false)) {
+ priv->bIsRxWorkItemQueued = true;
+ schedule_work(&priv->read_work_item);
+ }
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"<----RXFreeRCB %d %d\n",
+ priv->NumRecvFreeList, priv->NumRecvMngList);
}
void RXvMngWorkItem(struct work_struct *work)
diff --git a/drivers/staging/vt6656/int.c b/drivers/staging/vt6656/int.c
index e0e93869a681..cca56b2f243d 100644
--- a/drivers/staging/vt6656/int.c
+++ b/drivers/staging/vt6656/int.c
@@ -70,119 +70,117 @@ void INTvWorkItem(struct vnt_private *pDevice)
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Interrupt Polling Thread\n");
spin_lock_irq(&pDevice->lock);
- if (pDevice->fKillEventPollingThread != true)
- ntStatus = PIPEnsInterruptRead(pDevice);
+
+ ntStatus = PIPEnsInterruptRead(pDevice);
+
spin_unlock_irq(&pDevice->lock);
}
-void INTnsProcessData(struct vnt_private *pDevice)
+void INTnsProcessData(struct vnt_private *priv)
{
- PSINTData pINTData;
- struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
- struct net_device_stats *pStats = &pDevice->stats;
+ struct vnt_interrupt_data *int_data;
+ struct vnt_manager *mgmt = &priv->vnt_mgmt;
+ struct net_device_stats *stats = &priv->stats;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsInterruptProcessData\n");
- pINTData = (PSINTData) pDevice->intBuf.pDataBuf;
- if (pINTData->byTSR0 & TSR_VALID) {
- if (pINTData->byTSR0 & (TSR_TMO | TSR_RETRYTMO))
- pDevice->wstats.discard.retries++;
+ int_data = (struct vnt_interrupt_data *)priv->int_buf.data_buf;
+
+ if (int_data->tsr0 & TSR_VALID) {
+ if (int_data->tsr0 & (TSR_TMO | TSR_RETRYTMO))
+ priv->wstats.discard.retries++;
else
- pStats->tx_packets++;
+ stats->tx_packets++;
- BSSvUpdateNodeTxCounter(pDevice,
- pINTData->byTSR0,
- pINTData->byPkt0);
- /*DBG_PRN_GRP01(("TSR0 %02x\n", pINTData->byTSR0));*/
+ BSSvUpdateNodeTxCounter(priv,
+ int_data->tsr0,
+ int_data->pkt0);
}
- if (pINTData->byTSR1 & TSR_VALID) {
- if (pINTData->byTSR1 & (TSR_TMO | TSR_RETRYTMO))
- pDevice->wstats.discard.retries++;
+
+ if (int_data->tsr1 & TSR_VALID) {
+ if (int_data->tsr1 & (TSR_TMO | TSR_RETRYTMO))
+ priv->wstats.discard.retries++;
else
- pStats->tx_packets++;
+ stats->tx_packets++;
- BSSvUpdateNodeTxCounter(pDevice,
- pINTData->byTSR1,
- pINTData->byPkt1);
- /*DBG_PRN_GRP01(("TSR1 %02x\n", pINTData->byTSR1));*/
+ BSSvUpdateNodeTxCounter(priv,
+ int_data->tsr1,
+ int_data->pkt1);
}
- if (pINTData->byTSR2 & TSR_VALID) {
- if (pINTData->byTSR2 & (TSR_TMO | TSR_RETRYTMO))
- pDevice->wstats.discard.retries++;
+
+ if (int_data->tsr2 & TSR_VALID) {
+ if (int_data->tsr2 & (TSR_TMO | TSR_RETRYTMO))
+ priv->wstats.discard.retries++;
else
- pStats->tx_packets++;
+ stats->tx_packets++;
- BSSvUpdateNodeTxCounter(pDevice,
- pINTData->byTSR2,
- pINTData->byPkt2);
- /*DBG_PRN_GRP01(("TSR2 %02x\n", pINTData->byTSR2));*/
+ BSSvUpdateNodeTxCounter(priv,
+ int_data->tsr2,
+ int_data->pkt2);
}
- if (pINTData->byTSR3 & TSR_VALID) {
- if (pINTData->byTSR3 & (TSR_TMO | TSR_RETRYTMO))
- pDevice->wstats.discard.retries++;
+
+ if (int_data->tsr3 & TSR_VALID) {
+ if (int_data->tsr3 & (TSR_TMO | TSR_RETRYTMO))
+ priv->wstats.discard.retries++;
else
- pStats->tx_packets++;
+ stats->tx_packets++;
- BSSvUpdateNodeTxCounter(pDevice,
- pINTData->byTSR3,
- pINTData->byPkt3);
- /*DBG_PRN_GRP01(("TSR3 %02x\n", pINTData->byTSR3));*/
+ BSSvUpdateNodeTxCounter(priv,
+ int_data->tsr3,
+ int_data->pkt3);
}
- if (pINTData->byISR0 != 0) {
- if (pINTData->byISR0 & ISR_BNTX) {
- if (pDevice->eOPMode == OP_MODE_AP) {
- if (pMgmt->byDTIMCount > 0) {
- pMgmt->byDTIMCount--;
- pMgmt->sNodeDBTable[0].bRxPSPoll =
+
+ if (int_data->isr0 != 0) {
+ if (int_data->isr0 & ISR_BNTX) {
+ if (priv->op_mode == NL80211_IFTYPE_AP) {
+ if (mgmt->byDTIMCount > 0) {
+ mgmt->byDTIMCount--;
+ mgmt->sNodeDBTable[0].bRxPSPoll =
false;
- } else if (pMgmt->byDTIMCount == 0) {
+ } else if (mgmt->byDTIMCount == 0) {
/* check if multicast tx buffering */
- pMgmt->byDTIMCount =
- pMgmt->byDTIMPeriod-1;
- pMgmt->sNodeDBTable[0].bRxPSPoll = true;
- if (pMgmt->sNodeDBTable[0].bPSEnable)
- bScheduleCommand((void *) pDevice,
+ mgmt->byDTIMCount =
+ mgmt->byDTIMPeriod-1;
+ mgmt->sNodeDBTable[0].bRxPSPoll = true;
+ if (mgmt->sNodeDBTable[0].bPSEnable)
+ bScheduleCommand((void *) priv,
WLAN_CMD_RX_PSPOLL,
NULL);
}
- bScheduleCommand((void *) pDevice,
+ bScheduleCommand((void *) priv,
WLAN_CMD_BECON_SEND,
NULL);
- } /* if (pDevice->eOPMode == OP_MODE_AP) */
- pDevice->bBeaconSent = true;
+ }
+ priv->bBeaconSent = true;
} else {
- pDevice->bBeaconSent = false;
+ priv->bBeaconSent = false;
}
- if (pINTData->byISR0 & ISR_TBTT) {
- if (pDevice->bEnablePSMode)
- bScheduleCommand((void *) pDevice,
+
+ if (int_data->isr0 & ISR_TBTT) {
+ if (priv->bEnablePSMode)
+ bScheduleCommand((void *) priv,
WLAN_CMD_TBTT_WAKEUP,
NULL);
- if (pDevice->bChannelSwitch) {
- pDevice->byChannelSwitchCount--;
- if (pDevice->byChannelSwitchCount == 0)
- bScheduleCommand((void *) pDevice,
+ if (priv->bChannelSwitch) {
+ priv->byChannelSwitchCount--;
+ if (priv->byChannelSwitchCount == 0)
+ bScheduleCommand((void *) priv,
WLAN_CMD_11H_CHSW,
NULL);
}
}
- pDevice->qwCurrTSF = cpu_to_le64(pINTData->qwTSF);
- /*DBG_PRN_GRP01(("ISR0 = %02x ,
- LoTsf = %08x,
- HiTsf = %08x\n",
- pINTData->byISR0,
- pINTData->dwLoTSF,
- pINTData->dwHiTSF)); */
+ priv->qwCurrTSF = le64_to_cpu(int_data->tsf);
}
- if (pINTData->byISR1 != 0)
- if (pINTData->byISR1 & ISR_GPIO3)
- bScheduleCommand((void *) pDevice,
+
+ if (int_data->isr1 != 0)
+ if (int_data->isr1 & ISR_GPIO3)
+ bScheduleCommand((void *) priv,
WLAN_CMD_RADIO,
NULL);
- pDevice->intBuf.uDataLen = 0;
- pDevice->intBuf.bInUse = false;
- pStats->tx_errors = pDevice->wstats.discard.retries;
- pStats->tx_dropped = pDevice->wstats.discard.retries;
+ priv->int_buf.in_use = false;
+
+ stats->tx_errors = priv->wstats.discard.retries;
+ stats->tx_dropped = priv->wstats.discard.retries;
}
diff --git a/drivers/staging/vt6656/int.h b/drivers/staging/vt6656/int.h
index 8e6e217ba4ff..08db868e1d07 100644
--- a/drivers/staging/vt6656/int.h
+++ b/drivers/staging/vt6656/int.h
@@ -32,29 +32,28 @@
#include "device.h"
-typedef struct tagSINTData {
- u8 byTSR0;
- u8 byPkt0;
- u16 wTime0;
- u8 byTSR1;
- u8 byPkt1;
- u16 wTime1;
- u8 byTSR2;
- u8 byPkt2;
- u16 wTime2;
- u8 byTSR3;
- u8 byPkt3;
- u16 wTime3;
- u64 qwTSF;
- u8 byISR0;
- u8 byISR1;
- u8 byRTSSuccess;
- u8 byRTSFail;
- u8 byACKFail;
- u8 byFCSErr;
- u8 abySW[2];
-} __attribute__ ((__packed__))
-SINTData, *PSINTData;
+struct vnt_interrupt_data {
+ u8 tsr0;
+ u8 pkt0;
+ u16 time0;
+ u8 tsr1;
+ u8 pkt1;
+ u16 time1;
+ u8 tsr2;
+ u8 pkt2;
+ u16 time2;
+ u8 tsr3;
+ u8 pkt3;
+ u16 time3;
+ __le64 tsf;
+ u8 isr0;
+ u8 isr1;
+ u8 rts_success;
+ u8 rts_fail;
+ u8 ack_fail;
+ u8 fcs_err;
+ u8 sw[2];
+} __packed;
void INTvWorkItem(struct vnt_private *);
void INTnsProcessData(struct vnt_private *);
diff --git a/drivers/staging/vt6656/iwctl.c b/drivers/staging/vt6656/iwctl.c
index 3a68dfa23d84..cf4c06a42880 100644
--- a/drivers/staging/vt6656/iwctl.c
+++ b/drivers/staging/vt6656/iwctl.c
@@ -41,6 +41,7 @@
#include "wpactl.h"
#include "control.h"
#include "rndis.h"
+#include "baseband.h"
static const long frequency_list[] = {
2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484,
@@ -57,7 +58,7 @@ struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev)
struct vnt_private *pDevice = netdev_priv(dev);
long ldBm;
- pDevice->wstats.status = pDevice->eOPMode;
+ pDevice->wstats.status = pDevice->op_mode;
RFvRSSITodBm(pDevice, (u8)(pDevice->uCurrRSSI), &ldBm);
pDevice->wstats.qual.level = ldBm;
pDevice->wstats.qual.noise = 0;
@@ -724,10 +725,10 @@ int iwctl_giwaplist(struct net_device *dev, struct iw_request_info *info,
if (!wrq->pointer)
return -EINVAL;
- sock = kzalloc(sizeof(struct sockaddr) * IW_MAX_AP, GFP_KERNEL);
+ sock = kcalloc(IW_MAX_AP, sizeof(struct sockaddr), GFP_KERNEL);
if (sock == NULL)
return -ENOMEM;
- qual = kzalloc(sizeof(struct iw_quality) * IW_MAX_AP, GFP_KERNEL);
+ qual = kcalloc(IW_MAX_AP, sizeof(struct iw_quality), GFP_KERNEL);
if (qual == NULL) {
kfree(sock);
return -ENOMEM;
@@ -1394,7 +1395,8 @@ int iwctl_giwpower(struct net_device *dev, struct iw_request_info *info,
if (pMgmt == NULL)
return -EFAULT;
- if ((wrq->disabled = (mode == WMAC_POWER_CAM)))
+ wrq->disabled = (mode == WMAC_POWER_CAM);
+ if (wrq->disabled)
return 0;
if ((wrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
diff --git a/drivers/staging/vt6656/mac.c b/drivers/staging/vt6656/mac.c
index 54414ed27191..3ce19ddbc569 100644
--- a/drivers/staging/vt6656/mac.c
+++ b/drivers/staging/vt6656/mac.c
@@ -47,25 +47,19 @@ static int msglevel =MSG_LEVEL_INFO;
*
* Parameters:
* In:
- * uByteidx - Index of Mask
- * byData - Mask Value to write
+ * mc_filter (mac filter)
* Out:
* none
*
* Return Value: none
*
*/
-void MACvWriteMultiAddr(struct vnt_private *pDevice, u32 uByteIdx, u8 byData)
+void MACvWriteMultiAddr(struct vnt_private *pDevice, u64 mc_filter)
{
- u8 byData1;
+ __le64 le_mc = cpu_to_le64(mc_filter);
- byData1 = byData;
- CONTROLnsRequestOut(pDevice,
- MESSAGE_TYPE_WRITE,
- (u16) (MAC_REG_MAR0 + uByteIdx),
- MESSAGE_REQUEST_MACREG,
- 1,
- &byData1);
+ CONTROLnsRequestOut(pDevice, MESSAGE_TYPE_WRITE, MAC_REG_MAR0,
+ MESSAGE_REQUEST_MACREG, sizeof(le_mc), (u8 *)&le_mc);
}
/*
diff --git a/drivers/staging/vt6656/mac.h b/drivers/staging/vt6656/mac.h
index 0db1be5b01c8..4053e431ef99 100644
--- a/drivers/staging/vt6656/mac.h
+++ b/drivers/staging/vt6656/mac.h
@@ -403,7 +403,7 @@
#define MAC_REVISION_A0 0x00
#define MAC_REVISION_A1 0x01
-void MACvWriteMultiAddr(struct vnt_private *, u32, u8);
+void MACvWriteMultiAddr(struct vnt_private *, u64);
void MACbShutdown(struct vnt_private *);
void MACvSetBBType(struct vnt_private *, u8);
void MACvDisableKeyEntry(struct vnt_private *, u32);
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index 58edcae74efc..3c9323069e01 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -256,7 +256,7 @@ device_set_options(struct vnt_private *pDevice) {
pDevice->byShortPreamble = PREAMBLE_TYPE_DEF;
pDevice->ePSMode = PS_MODE_DEF;
pDevice->b11hEnable = X80211h_MODE_DEF;
- pDevice->eOPMode = OP_MODE_DEF;
+ pDevice->op_mode = NL80211_IFTYPE_UNSPECIFIED;
pDevice->uConnectionRate = DATA_RATE_DEF;
if (pDevice->uConnectionRate < RATE_AUTO) pDevice->bFixRate = true;
pDevice->byBBType = BBP_TYPE_DEF;
@@ -409,7 +409,7 @@ static int device_init_registers(struct vnt_private *pDevice)
if (pDevice->abyCCKPwrTbl[ii] == 0)
pDevice->abyCCKPwrTbl[ii] = pDevice->byCCKPwr;
- pDevice->abyOFDMPwrTbl[ii] =
+ pDevice->abyOFDMPwrTbl[ii] =
pDevice->abyEEPROM[ii + EEP_OFS_OFDM_PWR_TBL];
if (pDevice->abyOFDMPwrTbl[ii] == 0)
pDevice->abyOFDMPwrTbl[ii] = pDevice->byOFDMPwrG;
@@ -749,44 +749,47 @@ err_nomem:
return rc;
}
-static void device_free_tx_bufs(struct vnt_private *pDevice)
+static void device_free_tx_bufs(struct vnt_private *priv)
{
- struct vnt_usb_send_context *pTxContext;
- int ii;
+ struct vnt_usb_send_context *tx_context;
+ int ii;
- for (ii = 0; ii < pDevice->cbTD; ii++) {
+ for (ii = 0; ii < priv->cbTD; ii++) {
+ tx_context = priv->apTD[ii];
+ /* deallocate URBs */
+ if (tx_context->pUrb) {
+ usb_kill_urb(tx_context->pUrb);
+ usb_free_urb(tx_context->pUrb);
+ }
- pTxContext = pDevice->apTD[ii];
- /* deallocate URBs */
- if (pTxContext->pUrb) {
- usb_kill_urb(pTxContext->pUrb);
- usb_free_urb(pTxContext->pUrb);
- }
- kfree(pTxContext);
- }
- return;
+ kfree(tx_context);
+ }
+
+ return;
}
-static void device_free_rx_bufs(struct vnt_private *pDevice)
+static void device_free_rx_bufs(struct vnt_private *priv)
{
- struct vnt_rcb *pRCB;
+ struct vnt_rcb *rcb;
int ii;
- for (ii = 0; ii < pDevice->cbRD; ii++) {
+ for (ii = 0; ii < priv->cbRD; ii++) {
+ rcb = priv->apRCB[ii];
- pRCB = pDevice->apRCB[ii];
- /* deallocate URBs */
- if (pRCB->pUrb) {
- usb_kill_urb(pRCB->pUrb);
- usb_free_urb(pRCB->pUrb);
- }
- /* deallocate skb */
- if (pRCB->skb)
- dev_kfree_skb(pRCB->skb);
- }
- kfree(pDevice->pRCBMem);
+ /* deallocate URBs */
+ if (rcb->pUrb) {
+ usb_kill_urb(rcb->pUrb);
+ usb_free_urb(rcb->pUrb);
+ }
- return;
+ /* deallocate skb */
+ if (rcb->skb)
+ dev_kfree_skb(rcb->skb);
+ }
+
+ kfree(priv->pRCBMem);
+
+ return;
}
static void usb_device_reset(struct vnt_private *pDevice)
@@ -798,95 +801,109 @@ static void usb_device_reset(struct vnt_private *pDevice)
return ;
}
-static void device_free_int_bufs(struct vnt_private *pDevice)
+static void device_free_int_bufs(struct vnt_private *priv)
{
- kfree(pDevice->intBuf.pDataBuf);
- return;
+ kfree(priv->int_buf.data_buf);
+
+ return;
}
-static bool device_alloc_bufs(struct vnt_private *pDevice)
+static bool device_alloc_bufs(struct vnt_private *priv)
{
- struct vnt_usb_send_context *pTxContext;
- struct vnt_rcb *pRCB;
+ struct vnt_usb_send_context *tx_context;
+ struct vnt_rcb *rcb;
int ii;
- for (ii = 0; ii < pDevice->cbTD; ii++) {
+ for (ii = 0; ii < priv->cbTD; ii++) {
+ tx_context = kmalloc(sizeof(struct vnt_usb_send_context),
+ GFP_KERNEL);
+ if (tx_context == NULL) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR
+ "%s : allocate tx usb context failed\n",
+ priv->dev->name);
+ goto free_tx;
+ }
- pTxContext = kmalloc(sizeof(struct vnt_usb_send_context), GFP_KERNEL);
- if (pTxContext == NULL) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s : allocate tx usb context failed\n", pDevice->dev->name);
- goto free_tx;
- }
- pDevice->apTD[ii] = pTxContext;
- pTxContext->pDevice = (void *) pDevice;
- /* allocate URBs */
- pTxContext->pUrb = usb_alloc_urb(0, GFP_ATOMIC);
- if (pTxContext->pUrb == NULL) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "alloc tx urb failed\n");
- goto free_tx;
- }
- pTxContext->bBoolInUse = false;
- }
+ priv->apTD[ii] = tx_context;
+ tx_context->pDevice = priv;
+
+ /* allocate URBs */
+ tx_context->pUrb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (tx_context->pUrb == NULL) {
+ DBG_PRT(MSG_LEVEL_ERR,
+ KERN_ERR "alloc tx urb failed\n");
+ goto free_tx;
+ }
+
+ tx_context->bBoolInUse = false;
+ }
- /* allocate RCB mem */
- pDevice->pRCBMem = kzalloc((sizeof(struct vnt_rcb) * pDevice->cbRD),
+ /* allocate RCB mem */
+ priv->pRCBMem = kzalloc((sizeof(struct vnt_rcb) * priv->cbRD),
GFP_KERNEL);
- if (pDevice->pRCBMem == NULL) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s : alloc rx usb context failed\n", pDevice->dev->name);
- goto free_tx;
- }
+ if (priv->pRCBMem == NULL) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR
+ "%s : alloc rx usb context failed\n",
+ priv->dev->name);
+ goto free_tx;
+ }
- pDevice->FirstRecvFreeList = NULL;
- pDevice->LastRecvFreeList = NULL;
- pDevice->FirstRecvMngList = NULL;
- pDevice->LastRecvMngList = NULL;
- pDevice->NumRecvFreeList = 0;
+ priv->FirstRecvFreeList = NULL;
+ priv->LastRecvFreeList = NULL;
+ priv->FirstRecvMngList = NULL;
+ priv->LastRecvMngList = NULL;
+ priv->NumRecvFreeList = 0;
- pRCB = (struct vnt_rcb *)pDevice->pRCBMem;
+ rcb = (struct vnt_rcb *)priv->pRCBMem;
- for (ii = 0; ii < pDevice->cbRD; ii++) {
+ for (ii = 0; ii < priv->cbRD; ii++) {
+ priv->apRCB[ii] = rcb;
+ rcb->pDevice = priv;
- pDevice->apRCB[ii] = pRCB;
- pRCB->pDevice = (void *) pDevice;
- /* allocate URBs */
- pRCB->pUrb = usb_alloc_urb(0, GFP_ATOMIC);
+ /* allocate URBs */
+ rcb->pUrb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (rcb->pUrb == NULL) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR
+ " Failed to alloc rx urb\n");
+ goto free_rx_tx;
+ }
- if (pRCB->pUrb == NULL) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR" Failed to alloc rx urb\n");
- goto free_rx_tx;
- }
- pRCB->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
- if (pRCB->skb == NULL) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR" Failed to alloc rx skb\n");
- goto free_rx_tx;
- }
- pRCB->skb->dev = pDevice->dev;
- pRCB->bBoolInUse = false;
- EnqueueRCB(pDevice->FirstRecvFreeList, pDevice->LastRecvFreeList, pRCB);
- pDevice->NumRecvFreeList++;
- pRCB++;
- }
+ rcb->skb = netdev_alloc_skb(priv->dev, priv->rx_buf_sz);
+ if (rcb->skb == NULL) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR
+ " Failed to alloc rx skb\n");
+ goto free_rx_tx;
+ }
+
+ rcb->bBoolInUse = false;
+
+ EnqueueRCB(priv->FirstRecvFreeList,
+ priv->LastRecvFreeList, rcb);
- pDevice->pInterruptURB = usb_alloc_urb(0, GFP_ATOMIC);
- if (pDevice->pInterruptURB == NULL) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR"Failed to alloc int urb\n");
- goto free_rx_tx;
+ priv->NumRecvFreeList++;
+ rcb++;
}
- pDevice->intBuf.pDataBuf = kmalloc(MAX_INTERRUPT_SIZE, GFP_KERNEL);
- if (pDevice->intBuf.pDataBuf == NULL) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR"Failed to alloc int buf\n");
- usb_free_urb(pDevice->pInterruptURB);
- goto free_rx_tx;
+ priv->pInterruptURB = usb_alloc_urb(0, GFP_ATOMIC);
+ if (priv->pInterruptURB == NULL) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR"Failed to alloc int urb\n");
+ goto free_rx_tx;
}
- return true;
+ priv->int_buf.data_buf = kmalloc(MAX_INTERRUPT_SIZE, GFP_KERNEL);
+ if (priv->int_buf.data_buf == NULL) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR"Failed to alloc int buf\n");
+ usb_free_urb(priv->pInterruptURB);
+ goto free_rx_tx;
+ }
+
+ return true;
free_rx_tx:
- device_free_rx_bufs(pDevice);
+ device_free_rx_bufs(priv);
free_tx:
- device_free_tx_bufs(pDevice);
+ device_free_tx_bufs(priv);
return false;
}
@@ -931,13 +948,11 @@ static void device_free_frag_bufs(struct vnt_private *pDevice)
int device_alloc_frag_buf(struct vnt_private *pDevice,
PSDeFragControlBlock pDeF)
{
+ pDeF->skb = netdev_alloc_skb(pDevice->dev, pDevice->rx_buf_sz);
+ if (!pDeF->skb)
+ return false;
- pDeF->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
- if (pDeF->skb == NULL)
- return false;
- pDeF->skb->dev = pDevice->dev;
-
- return true;
+ return true;
}
static int device_open(struct net_device *dev)
@@ -974,8 +989,6 @@ static int device_open(struct net_device *dev)
goto free_all;
}
- device_set_multi(pDevice->dev);
-
/* init for key management */
KeyvInitTable(pDevice,&pDevice->sKey);
memcpy(pDevice->vnt_mgmt.abyMACAddr,
@@ -992,16 +1005,12 @@ static int device_open(struct net_device *dev)
vMgrObjectInit(pDevice);
- tasklet_init(&pDevice->EventWorkItem, (void *)INTvWorkItem, (unsigned long)pDevice);
-
schedule_delayed_work(&pDevice->second_callback_work, HZ);
- pDevice->int_interval = 100; /* max 100 microframes */
+ pDevice->int_interval = 1; /* bInterval is set to 1 */
pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
pDevice->bIsRxWorkItemQueued = true;
- pDevice->fKillEventPollingThread = false;
- pDevice->bEventAvailable = false;
pDevice->bWPADEVUp = false;
pDevice->bwextstep0 = false;
@@ -1084,7 +1093,6 @@ static int device_close(struct net_device *dev)
MP_SET_FLAG(pDevice, fMP_DISCONNECTED);
MP_CLEAR_FLAG(pDevice, fMP_POST_WRITES);
MP_CLEAR_FLAG(pDevice, fMP_POST_READS);
- pDevice->fKillEventPollingThread = true;
cancel_delayed_work_sync(&pDevice->run_command_work);
cancel_delayed_work_sync(&pDevice->second_callback_work);
@@ -1098,8 +1106,6 @@ static int device_close(struct net_device *dev)
cancel_work_sync(&pDevice->rx_mng_work_item);
cancel_work_sync(&pDevice->read_work_item);
- tasklet_kill(&pDevice->EventWorkItem);
-
pDevice->bRoaming = false;
pDevice->bIsRoaming = false;
pDevice->bEnableRoaming = false;
@@ -1350,69 +1356,73 @@ static int Read_config_file(struct vnt_private *pDevice)
static void device_set_multi(struct net_device *dev)
{
- struct vnt_private *pDevice = netdev_priv(dev);
- struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
+ struct vnt_private *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ if (priv->flags & DEVICE_FLAGS_OPENED) {
+ spin_lock_irqsave(&priv->lock, flags);
+
+ bScheduleCommand(priv, WLAN_CMD_CONFIGURE_FILTER, NULL);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+}
+
+void vnt_configure_filter(struct vnt_private *priv)
+{
+ struct net_device *dev = priv->dev;
+ struct vnt_manager *mgmt = &priv->vnt_mgmt;
struct netdev_hw_addr *ha;
- u32 mc_filter[2];
- int ii;
- u8 pbyData[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- u8 byTmpMode = 0;
+ u64 mc_filter = 0;
+ u8 tmp = 0;
int rc;
- spin_lock_irq(&pDevice->lock);
- rc = CONTROLnsRequestIn(pDevice,
- MESSAGE_TYPE_READ,
- MAC_REG_RCR,
- MESSAGE_REQUEST_MACREG,
- 1,
- &byTmpMode
- );
- if (rc == 0) pDevice->byRxMode = byTmpMode;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->byRxMode in= %x\n", pDevice->byRxMode);
-
- if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
- DBG_PRT(MSG_LEVEL_ERR,KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
- /* unconditionally log net taps */
- pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST|RCR_UNICAST);
- }
- else if ((netdev_mc_count(dev) > pDevice->multicast_limit) ||
- (dev->flags & IFF_ALLMULTI)) {
- CONTROLnsRequestOut(pDevice,
- MESSAGE_TYPE_WRITE,
- MAC_REG_MAR0,
- MESSAGE_REQUEST_MACREG,
- 8,
- pbyData
- );
- pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST);
- }
- else {
- memset(mc_filter, 0, sizeof(mc_filter));
- netdev_for_each_mc_addr(ha, dev) {
- int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
- mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
- }
- for (ii = 0; ii < 4; ii++) {
- MACvWriteMultiAddr(pDevice, ii, *((u8 *)&mc_filter[0] + ii));
- MACvWriteMultiAddr(pDevice, ii+ 4, *((u8 *)&mc_filter[1] + ii));
- }
- pDevice->byRxMode &= ~(RCR_UNICAST);
- pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST);
- }
+ rc = CONTROLnsRequestIn(priv, MESSAGE_TYPE_READ,
+ MAC_REG_RCR, MESSAGE_REQUEST_MACREG, 1, &tmp);
+ if (rc == 0)
+ priv->byRxMode = tmp;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "priv->byRxMode in= %x\n",
+ priv->byRxMode);
+
+ if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
+ DBG_PRT(MSG_LEVEL_ERR, KERN_NOTICE
+ "%s: Promiscuous mode enabled.\n", dev->name);
+ /* unconditionally log net taps */
+ priv->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST|RCR_UNICAST);
+ } else if ((netdev_mc_count(dev) > priv->multicast_limit) ||
+ (dev->flags & IFF_ALLMULTI)) {
+ mc_filter = ~0x0;
+ MACvWriteMultiAddr(priv, mc_filter);
+
+ priv->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST);
+ } else {
+ netdev_for_each_mc_addr(ha, dev) {
+ int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
- if (pMgmt->eConfigMode == WMAC_CONFIG_AP) {
- /*
- * If AP mode, don't enable RCR_UNICAST since HW only compares
- * addr1 with local MAC
- */
- pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST);
- pDevice->byRxMode &= ~(RCR_UNICAST);
- }
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_MACREG, MAC_REG_RCR, pDevice->byRxMode);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->byRxMode out= %x\n", pDevice->byRxMode);
- spin_unlock_irq(&pDevice->lock);
+ mc_filter |= 1ULL << (bit_nr & 0x3f);
+ }
+
+ MACvWriteMultiAddr(priv, mc_filter);
+
+ priv->byRxMode &= ~(RCR_UNICAST);
+ priv->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST);
+ }
+
+ if (mgmt->eConfigMode == WMAC_CONFIG_AP) {
+ /*
+ * If AP mode, don't enable RCR_UNICAST since HW only compares
+ * addr1 with local MAC
+ */
+ priv->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST);
+ priv->byRxMode &= ~(RCR_UNICAST);
+ }
+
+ ControlvWriteByte(priv, MESSAGE_REQUEST_MACREG,
+ MAC_REG_RCR, priv->byRxMode);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "priv->byRxMode out= %x\n", priv->byRxMode);
}
static struct net_device_stats *device_get_stats(struct net_device *dev)
diff --git a/drivers/staging/vt6656/power.c b/drivers/staging/vt6656/power.c
index e7d5487d1041..43da58927cd2 100644
--- a/drivers/staging/vt6656/power.c
+++ b/drivers/staging/vt6656/power.c
@@ -67,22 +67,23 @@ void PSvEnablePowerSaving(struct vnt_private *pDevice, u16 wListenInterval)
/* set period of power up before TBTT */
MACvWriteWord(pDevice, MAC_REG_PWBT, C_PWBT);
- if (pDevice->eOPMode != OP_MODE_ADHOC) {
+ if (pDevice->op_mode != NL80211_IFTYPE_ADHOC) {
/* set AID */
MACvWriteWord(pDevice, MAC_REG_AIDATIM, wAID);
- } else {
- /* set ATIM Window */
- /* MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow); */
}
- /* Warren:06-18-2004,the sequence must follow PSEN->AUTOSLEEP->GO2DOZE */
+ /* Warren:06-18-2004,the sequence must follow
+ * PSEN->AUTOSLEEP->GO2DOZE
+ */
/* enable power saving hw function */
MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_PSEN);
/* Set AutoSleep */
MACvRegBitsOn(pDevice, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
- /* Warren:MUST turn on this once before turn on AUTOSLEEP ,or the AUTOSLEEP doesn't work */
+ /* Warren:MUST turn on this once before turn on AUTOSLEEP ,or the
+ * AUTOSLEEP doesn't work
+ */
MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_GO2DOZE);
if (wListenInterval >= 2) {
@@ -105,8 +106,10 @@ void PSvEnablePowerSaving(struct vnt_private *pDevice, u16 wListenInterval)
pDevice->bEnablePSMode = true;
- /* We don't send null pkt in ad hoc mode since beacon will handle this. */
- if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE)
+ /* We don't send null pkt in ad hoc mode
+ * since beacon will handle this.
+ */
+ if (pDevice->op_mode == NL80211_IFTYPE_STATION)
PSbSendNullPacket(pDevice);
pDevice->bPWBitOn = true;
@@ -137,7 +140,7 @@ void PSvDisablePowerSaving(struct vnt_private *pDevice)
MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_ALBCN);
pDevice->bEnablePSMode = false;
- if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE)
+ if (pDevice->op_mode == NL80211_IFTYPE_STATION)
PSbSendNullPacket(pDevice);
pDevice->bPWBitOn = false;
@@ -226,15 +229,19 @@ void PSvSendPSPOLL(struct vnt_private *pDevice)
WLAN_SET_FC_PWRMGT(0)
));
- pTxPacket->p80211Header->sA2.wDurationID = pMgmt->wCurrAID | BIT14 | BIT15;
- memcpy(pTxPacket->p80211Header->sA2.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
- memcpy(pTxPacket->p80211Header->sA2.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ pTxPacket->p80211Header->sA2.wDurationID =
+ pMgmt->wCurrAID | BIT14 | BIT15;
+ memcpy(pTxPacket->p80211Header->sA2.abyAddr1, pMgmt->abyCurrBSSID,
+ WLAN_ADDR_LEN);
+ memcpy(pTxPacket->p80211Header->sA2.abyAddr2, pMgmt->abyMACAddr,
+ WLAN_ADDR_LEN);
pTxPacket->cbMPDULen = WLAN_HDR_ADDR2_LEN;
pTxPacket->cbPayloadLen = 0;
/* log failure if sending failed */
if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING)
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet failed..\n");
+ DBG_PRT(MSG_LEVEL_DEBUG,
+ KERN_INFO "Send PS-Poll packet failed..\n");
}
/*
@@ -276,16 +283,21 @@ int PSbSendNullPacket(struct vnt_private *pDevice)
pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(flags);
if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA)
- pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((u16)WLAN_SET_FC_TODS(1));
-
- memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
- memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+ pTxPacket->p80211Header->sA3.wFrameCtl |=
+ cpu_to_le16((u16)WLAN_SET_FC_TODS(1));
+
+ memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID,
+ WLAN_ADDR_LEN);
+ memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr,
+ WLAN_ADDR_LEN);
+ memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID,
+ WLAN_BSSID_LEN);
pTxPacket->cbMPDULen = WLAN_HDR_ADDR3_LEN;
pTxPacket->cbPayloadLen = 0;
/* log error if sending failed */
if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet failed !\n");
+ DBG_PRT(MSG_LEVEL_DEBUG,
+ KERN_INFO "Send Null Packet failed !\n");
return false;
}
return true;
diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index 51fff896fcb5..3840323858fc 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -118,7 +118,7 @@ static void s_vSWencryption(struct vnt_private *pDevice,
static unsigned int s_uGetTxRsvTime(struct vnt_private *pDevice, u8 byPktType,
u32 cbFrameLength, u16 wRate, int bNeedAck);
-static u16 s_uGetRTSCTSRsvTime(struct vnt_private *priv,
+static __le16 s_uGetRTSCTSRsvTime(struct vnt_private *priv,
u8 rsv_type, u8 pkt_type, u32 frame_lenght, u16 current_rate);
static u16 s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx,
@@ -129,10 +129,10 @@ static u16 s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
union vnt_tx_data_head *head, u32 cbFrameLength, int bNeedAck,
struct ethhdr *psEthHeader, u16 wCurrentRate, u8 byFBOption);
-static u16 s_uGetDataDuration(struct vnt_private *pDevice,
+static __le16 s_uGetDataDuration(struct vnt_private *pDevice,
u8 byPktType, int bNeedAck);
-static u16 s_uGetRTSCTSDuration(struct vnt_private *pDevice,
+static __le16 s_uGetRTSCTSDuration(struct vnt_private *pDevice,
u8 byDurType, u32 cbFrameLength, u8 byPktType, u16 wRate,
int bNeedAck, u8 byFBOption);
@@ -327,7 +327,7 @@ static void s_vSWencryption(struct vnt_private *pDevice,
}
}
-static u16 vnt_time_stamp_off(struct vnt_private *priv, u16 rate)
+static __le16 vnt_time_stamp_off(struct vnt_private *priv, u16 rate)
{
return cpu_to_le16(wTimeStampOff[priv->byPreambleType % 2]
[rate % MAX_RATE]);
@@ -359,7 +359,7 @@ static u32 s_uGetTxRsvTime(struct vnt_private *priv, u8 pkt_type,
return data_time;
}
-static u16 vnt_rxtx_rsvtime_le16(struct vnt_private *priv, u8 pkt_type,
+static __le16 vnt_rxtx_rsvtime_le16(struct vnt_private *priv, u8 pkt_type,
u32 frame_length, u16 rate, int need_ack)
{
return cpu_to_le16((u16)s_uGetTxRsvTime(priv, pkt_type,
@@ -367,7 +367,7 @@ static u16 vnt_rxtx_rsvtime_le16(struct vnt_private *priv, u8 pkt_type,
}
//byFreqType: 0=>5GHZ 1=>2.4GHZ
-static u16 s_uGetRTSCTSRsvTime(struct vnt_private *priv,
+static __le16 s_uGetRTSCTSRsvTime(struct vnt_private *priv,
u8 rsv_type, u8 pkt_type, u32 frame_lenght, u16 current_rate)
{
u32 rrv_time, rts_time, cts_time, ack_time, data_time;
@@ -402,7 +402,7 @@ static u16 s_uGetRTSCTSRsvTime(struct vnt_private *priv,
rrv_time = cts_time + ack_time + data_time + 2 * priv->uSIFS;
- return rrv_time;
+ return cpu_to_le16((u16)rrv_time);
}
rrv_time = rts_time + cts_time + ack_time + data_time + 3 * priv->uSIFS;
@@ -411,7 +411,7 @@ static u16 s_uGetRTSCTSRsvTime(struct vnt_private *priv,
}
//byFreqType 0: 5GHz, 1:2.4Ghz
-static u16 s_uGetDataDuration(struct vnt_private *pDevice,
+static __le16 s_uGetDataDuration(struct vnt_private *pDevice,
u8 byPktType, int bNeedAck)
{
u32 uAckTime = 0;
@@ -430,7 +430,7 @@ static u16 s_uGetDataDuration(struct vnt_private *pDevice,
}
//byFreqType: 0=>5GHZ 1=>2.4GHZ
-static u16 s_uGetRTSCTSDuration(struct vnt_private *pDevice, u8 byDurType,
+static __le16 s_uGetRTSCTSDuration(struct vnt_private *pDevice, u8 byDurType,
u32 cbFrameLength, u8 byPktType, u16 wRate, int bNeedAck,
u8 byFBOption)
{
@@ -481,14 +481,14 @@ static u16 vnt_rxtx_datahead_g(struct vnt_private *priv, u8 pkt_type, u16 rate,
PK_TYPE_11B, &buf->b);
/* Get Duration and TimeStamp */
- buf->wDuration_a = s_uGetDataDuration(priv, pkt_type, need_ack);
- buf->wDuration_b = s_uGetDataDuration(priv, PK_TYPE_11B, need_ack);
+ buf->duration_a = s_uGetDataDuration(priv, pkt_type, need_ack);
+ buf->duration_b = s_uGetDataDuration(priv, PK_TYPE_11B, need_ack);
- buf->wTimeStampOff_a = vnt_time_stamp_off(priv, rate);
- buf->wTimeStampOff_b = vnt_time_stamp_off(priv,
+ buf->time_stamp_off_a = vnt_time_stamp_off(priv, rate);
+ buf->time_stamp_off_b = vnt_time_stamp_off(priv,
priv->byTopCCKBasicRate);
- return buf->wDuration_a;
+ return le16_to_cpu(buf->duration_a);
}
static u16 vnt_rxtx_datahead_g_fb(struct vnt_private *priv, u8 pkt_type,
@@ -502,17 +502,17 @@ static u16 vnt_rxtx_datahead_g_fb(struct vnt_private *priv, u8 pkt_type,
PK_TYPE_11B, &buf->b);
/* Get Duration and TimeStamp */
- buf->wDuration_a = s_uGetDataDuration(priv, pkt_type, need_ack);
- buf->wDuration_b = s_uGetDataDuration(priv, PK_TYPE_11B, need_ack);
+ buf->duration_a = s_uGetDataDuration(priv, pkt_type, need_ack);
+ buf->duration_b = s_uGetDataDuration(priv, PK_TYPE_11B, need_ack);
- buf->wDuration_a_f0 = s_uGetDataDuration(priv, pkt_type, need_ack);
- buf->wDuration_a_f1 = s_uGetDataDuration(priv, pkt_type, need_ack);
+ buf->duration_a_f0 = s_uGetDataDuration(priv, pkt_type, need_ack);
+ buf->duration_a_f1 = s_uGetDataDuration(priv, pkt_type, need_ack);
- buf->wTimeStampOff_a = vnt_time_stamp_off(priv, rate);
- buf->wTimeStampOff_b = vnt_time_stamp_off(priv,
+ buf->time_stamp_off_a = vnt_time_stamp_off(priv, rate);
+ buf->time_stamp_off_b = vnt_time_stamp_off(priv,
priv->byTopCCKBasicRate);
- return buf->wDuration_a;
+ return le16_to_cpu(buf->duration_a);
}
static u16 vnt_rxtx_datahead_a_fb(struct vnt_private *priv, u8 pkt_type,
@@ -522,14 +522,14 @@ static u16 vnt_rxtx_datahead_a_fb(struct vnt_private *priv, u8 pkt_type,
/* Get SignalField,ServiceField,Length */
BBvCalculateParameter(priv, frame_len, rate, pkt_type, &buf->a);
/* Get Duration and TimeStampOff */
- buf->wDuration = s_uGetDataDuration(priv, pkt_type, need_ack);
+ buf->duration = s_uGetDataDuration(priv, pkt_type, need_ack);
- buf->wDuration_f0 = s_uGetDataDuration(priv, pkt_type, need_ack);
- buf->wDuration_f1 = s_uGetDataDuration(priv, pkt_type, need_ack);
+ buf->duration_f0 = s_uGetDataDuration(priv, pkt_type, need_ack);
+ buf->duration_f1 = s_uGetDataDuration(priv, pkt_type, need_ack);
- buf->wTimeStampOff = vnt_time_stamp_off(priv, rate);
+ buf->time_stamp_off = vnt_time_stamp_off(priv, rate);
- return buf->wDuration;
+ return le16_to_cpu(buf->duration);
}
static u16 vnt_rxtx_datahead_ab(struct vnt_private *priv, u8 pkt_type,
@@ -539,26 +539,27 @@ static u16 vnt_rxtx_datahead_ab(struct vnt_private *priv, u8 pkt_type,
/* Get SignalField,ServiceField,Length */
BBvCalculateParameter(priv, frame_len, rate, pkt_type, &buf->ab);
/* Get Duration and TimeStampOff */
- buf->wDuration = s_uGetDataDuration(priv, pkt_type, need_ack);
+ buf->duration = s_uGetDataDuration(priv, pkt_type, need_ack);
- buf->wTimeStampOff = vnt_time_stamp_off(priv, rate);
+ buf->time_stamp_off = vnt_time_stamp_off(priv, rate);
- return buf->wDuration;
+ return le16_to_cpu(buf->duration);
}
static int vnt_fill_ieee80211_rts(struct vnt_private *priv,
struct ieee80211_rts *rts, struct ethhdr *eth_hdr,
- u16 duration)
+ __le16 duration)
{
rts->duration = duration;
rts->frame_control = TYPE_CTL_RTS;
- if (priv->eOPMode == OP_MODE_ADHOC || priv->eOPMode == OP_MODE_AP)
+ if (priv->op_mode == NL80211_IFTYPE_ADHOC ||
+ priv->op_mode == NL80211_IFTYPE_AP)
memcpy(rts->ra, eth_hdr->h_dest, ETH_ALEN);
else
memcpy(rts->ra, priv->abyBSSID, ETH_ALEN);
- if (priv->eOPMode == OP_MODE_AP)
+ if (priv->op_mode == NL80211_IFTYPE_AP)
memcpy(rts->ta, priv->abyBSSID, ETH_ALEN);
else
memcpy(rts->ta, eth_hdr->h_source, ETH_ALEN);
@@ -578,14 +579,14 @@ static u16 vnt_rxtx_rts_g_head(struct vnt_private *priv,
BBvCalculateParameter(priv, rts_frame_len,
priv->byTopOFDMBasicRate, pkt_type, &buf->a);
- buf->wDuration_bb = s_uGetRTSCTSDuration(priv, RTSDUR_BB, frame_len,
+ buf->duration_bb = s_uGetRTSCTSDuration(priv, RTSDUR_BB, frame_len,
PK_TYPE_11B, priv->byTopCCKBasicRate, need_ack, fb_option);
- buf->wDuration_aa = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
+ buf->duration_aa = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
pkt_type, current_rate, need_ack, fb_option);
- buf->wDuration_ba = s_uGetRTSCTSDuration(priv, RTSDUR_BA, frame_len,
+ buf->duration_ba = s_uGetRTSCTSDuration(priv, RTSDUR_BA, frame_len,
pkt_type, current_rate, need_ack, fb_option);
- vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration_aa);
+ vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->duration_aa);
return vnt_rxtx_datahead_g(priv, pkt_type, current_rate,
&buf->data_head, frame_len, need_ack);
@@ -604,24 +605,24 @@ static u16 vnt_rxtx_rts_g_fb_head(struct vnt_private *priv,
priv->byTopOFDMBasicRate, pkt_type, &buf->a);
- buf->wDuration_bb = s_uGetRTSCTSDuration(priv, RTSDUR_BB, frame_len,
+ buf->duration_bb = s_uGetRTSCTSDuration(priv, RTSDUR_BB, frame_len,
PK_TYPE_11B, priv->byTopCCKBasicRate, need_ack, fb_option);
- buf->wDuration_aa = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
+ buf->duration_aa = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
pkt_type, current_rate, need_ack, fb_option);
- buf->wDuration_ba = s_uGetRTSCTSDuration(priv, RTSDUR_BA, frame_len,
+ buf->duration_ba = s_uGetRTSCTSDuration(priv, RTSDUR_BA, frame_len,
pkt_type, current_rate, need_ack, fb_option);
- buf->wRTSDuration_ba_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_BA_F0,
+ buf->rts_duration_ba_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_BA_F0,
frame_len, pkt_type, priv->tx_rate_fb0, need_ack, fb_option);
- buf->wRTSDuration_aa_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F0,
+ buf->rts_duration_aa_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F0,
frame_len, pkt_type, priv->tx_rate_fb0, need_ack, fb_option);
- buf->wRTSDuration_ba_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_BA_F1,
+ buf->rts_duration_ba_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_BA_F1,
frame_len, pkt_type, priv->tx_rate_fb1, need_ack, fb_option);
- buf->wRTSDuration_aa_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F1,
+ buf->rts_duration_aa_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F1,
frame_len, pkt_type, priv->tx_rate_fb1, need_ack, fb_option);
- vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration_aa);
+ vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->duration_aa);
return vnt_rxtx_datahead_g_fb(priv, pkt_type, current_rate,
&buf->data_head, frame_len, need_ack);
@@ -637,10 +638,10 @@ static u16 vnt_rxtx_rts_ab_head(struct vnt_private *priv,
BBvCalculateParameter(priv, rts_frame_len,
priv->byTopOFDMBasicRate, pkt_type, &buf->ab);
- buf->wDuration = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
+ buf->duration = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
pkt_type, current_rate, need_ack, fb_option);
- vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration);
+ vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->duration);
return vnt_rxtx_datahead_ab(priv, pkt_type, current_rate,
&buf->data_head, frame_len, need_ack);
@@ -656,16 +657,16 @@ static u16 vnt_rxtx_rts_a_fb_head(struct vnt_private *priv,
BBvCalculateParameter(priv, rts_frame_len,
priv->byTopOFDMBasicRate, pkt_type, &buf->a);
- buf->wDuration = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
+ buf->duration = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
pkt_type, current_rate, need_ack, fb_option);
- buf->wRTSDuration_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F0,
+ buf->rts_duration_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F0,
frame_len, pkt_type, priv->tx_rate_fb0, need_ack, fb_option);
- buf->wRTSDuration_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F1,
+ buf->rts_duration_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F1,
frame_len, pkt_type, priv->tx_rate_fb1, need_ack, fb_option);
- vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration);
+ vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->duration);
return vnt_rxtx_datahead_a_fb(priv, pkt_type, current_rate,
&buf->data_head, frame_len, need_ack);
@@ -727,19 +728,19 @@ static u16 s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx,
/* Get SignalField,ServiceField,Length */
BBvCalculateParameter(pDevice, uCTSFrameLen,
pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
- pBuf->wDuration_ba = s_uGetRTSCTSDuration(pDevice, CTSDUR_BA,
+ pBuf->duration_ba = s_uGetRTSCTSDuration(pDevice, CTSDUR_BA,
cbFrameLength, byPktType,
wCurrentRate, bNeedAck, byFBOption);
/* Get CTSDuration_ba_f0 */
- pBuf->wCTSDuration_ba_f0 = s_uGetRTSCTSDuration(pDevice,
+ pBuf->cts_duration_ba_f0 = s_uGetRTSCTSDuration(pDevice,
CTSDUR_BA_F0, cbFrameLength, byPktType,
pDevice->tx_rate_fb0, bNeedAck, byFBOption);
/* Get CTSDuration_ba_f1 */
- pBuf->wCTSDuration_ba_f1 = s_uGetRTSCTSDuration(pDevice,
+ pBuf->cts_duration_ba_f1 = s_uGetRTSCTSDuration(pDevice,
CTSDUR_BA_F1, cbFrameLength, byPktType,
pDevice->tx_rate_fb1, bNeedAck, byFBOption);
/* Get CTS Frame body */
- pBuf->data.duration = pBuf->wDuration_ba;
+ pBuf->data.duration = pBuf->duration_ba;
pBuf->data.frame_control = TYPE_CTL_CTS;
memcpy(pBuf->data.ra, pDevice->abyCurrentNetAddr, ETH_ALEN);
@@ -751,11 +752,11 @@ static u16 s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx,
BBvCalculateParameter(pDevice, uCTSFrameLen,
pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
/* Get CTSDuration_ba */
- pBuf->wDuration_ba = s_uGetRTSCTSDuration(pDevice,
+ pBuf->duration_ba = s_uGetRTSCTSDuration(pDevice,
CTSDUR_BA, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, byFBOption);
/*Get CTS Frame body*/
- pBuf->data.duration = pBuf->wDuration_ba;
+ pBuf->data.duration = pBuf->duration_ba;
pBuf->data.frame_control = TYPE_CTL_CTS;
memcpy(pBuf->data.ra, pDevice->abyCurrentNetAddr, ETH_ALEN);
@@ -815,16 +816,16 @@ static u16 s_vGenerateTxParameter(struct vnt_private *pDevice,
struct vnt_rrv_time_rts *pBuf =
&tx_buffer->tx_head.tx_rts.rts;
- pBuf->wRTSTxRrvTime_aa = s_uGetRTSCTSRsvTime(pDevice, 2,
+ pBuf->rts_rrv_time_aa = s_uGetRTSCTSRsvTime(pDevice, 2,
byPktType, cbFrameSize, wCurrentRate);
- pBuf->wRTSTxRrvTime_ba = s_uGetRTSCTSRsvTime(pDevice, 1,
+ pBuf->rts_rrv_time_ba = s_uGetRTSCTSRsvTime(pDevice, 1,
byPktType, cbFrameSize, wCurrentRate);
- pBuf->wRTSTxRrvTime_bb = s_uGetRTSCTSRsvTime(pDevice, 0,
+ pBuf->rts_rrv_time_bb = s_uGetRTSCTSRsvTime(pDevice, 0,
byPktType, cbFrameSize, wCurrentRate);
- pBuf->wTxRrvTime_a = vnt_rxtx_rsvtime_le16(pDevice,
+ pBuf->rrv_time_a = vnt_rxtx_rsvtime_le16(pDevice,
byPktType, cbFrameSize, wCurrentRate, bNeedACK);
- pBuf->wTxRrvTime_b = vnt_rxtx_rsvtime_le16(pDevice,
+ pBuf->rrv_time_b = vnt_rxtx_rsvtime_le16(pDevice,
PK_TYPE_11B, cbFrameSize,
pDevice->byTopCCKBasicRate, bNeedACK);
@@ -845,13 +846,13 @@ static u16 s_vGenerateTxParameter(struct vnt_private *pDevice,
struct vnt_rrv_time_cts *pBuf = &tx_buffer->
tx_head.tx_cts.cts;
- pBuf->wTxRrvTime_a = vnt_rxtx_rsvtime_le16(pDevice,
+ pBuf->rrv_time_a = vnt_rxtx_rsvtime_le16(pDevice,
byPktType, cbFrameSize, wCurrentRate, bNeedACK);
- pBuf->wTxRrvTime_b = vnt_rxtx_rsvtime_le16(pDevice,
+ pBuf->rrv_time_b = vnt_rxtx_rsvtime_le16(pDevice,
PK_TYPE_11B, cbFrameSize,
pDevice->byTopCCKBasicRate, bNeedACK);
- pBuf->wCTSTxRrvTime_ba = s_uGetRTSCTSRsvTime(pDevice, 3,
+ pBuf->cts_rrv_time_ba = s_uGetRTSCTSRsvTime(pDevice, 3,
byPktType, cbFrameSize, wCurrentRate);
if (need_mic) {
@@ -879,10 +880,10 @@ static u16 s_vGenerateTxParameter(struct vnt_private *pDevice,
struct vnt_rrv_time_ab *pBuf = &tx_buffer->
tx_head.tx_ab.ab;
- pBuf->wRTSTxRrvTime = s_uGetRTSCTSRsvTime(pDevice, 2,
+ pBuf->rts_rrv_time = s_uGetRTSCTSRsvTime(pDevice, 2,
byPktType, cbFrameSize, wCurrentRate);
- pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice,
+ pBuf->rrv_time = vnt_rxtx_rsvtime_le16(pDevice,
byPktType, cbFrameSize, wCurrentRate, bNeedACK);
/* Fill RTS */
@@ -893,7 +894,7 @@ static u16 s_vGenerateTxParameter(struct vnt_private *pDevice,
struct vnt_rrv_time_ab *pBuf = &tx_buffer->
tx_head.tx_ab.ab;
- pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice,
+ pBuf->rrv_time = vnt_rxtx_rsvtime_le16(pDevice,
PK_TYPE_11A, cbFrameSize,
wCurrentRate, bNeedACK);
@@ -913,10 +914,10 @@ static u16 s_vGenerateTxParameter(struct vnt_private *pDevice,
struct vnt_rrv_time_ab *pBuf = &tx_buffer->
tx_head.tx_ab.ab;
- pBuf->wRTSTxRrvTime = s_uGetRTSCTSRsvTime(pDevice, 0,
+ pBuf->rts_rrv_time = s_uGetRTSCTSRsvTime(pDevice, 0,
byPktType, cbFrameSize, wCurrentRate);
- pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice,
+ pBuf->rrv_time = vnt_rxtx_rsvtime_le16(pDevice,
PK_TYPE_11B, cbFrameSize, wCurrentRate,
bNeedACK);
@@ -928,7 +929,7 @@ static u16 s_vGenerateTxParameter(struct vnt_private *pDevice,
struct vnt_rrv_time_ab *pBuf = &tx_buffer->
tx_head.tx_ab.ab;
- pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice,
+ pBuf->rrv_time = vnt_rxtx_rsvtime_le16(pDevice,
PK_TYPE_11B, cbFrameSize,
wCurrentRate, bNeedACK);
@@ -991,8 +992,8 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
//Set packet type
pTxBufHead->wFIFOCtl |= (u16)(byPktType<<8);
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
+ if (pDevice->op_mode == NL80211_IFTYPE_ADHOC ||
+ pDevice->op_mode == NL80211_IFTYPE_AP) {
if (is_multicast_ether_addr(psEthHeader->h_dest)) {
bNeedACK = false;
pTxBufHead->wFIFOCtl =
@@ -1292,7 +1293,7 @@ static void s_vGenerateMACHeader(struct vnt_private *pDevice,
pMACHeader->frame_control = TYPE_802_11_DATA;
- if (pDevice->eOPMode == OP_MODE_AP) {
+ if (pDevice->op_mode == NL80211_IFTYPE_AP) {
memcpy(&(pMACHeader->addr1[0]),
&(psEthHeader->h_dest[0]),
ETH_ALEN);
@@ -1302,7 +1303,7 @@ static void s_vGenerateMACHeader(struct vnt_private *pDevice,
ETH_ALEN);
pMACHeader->frame_control |= FC_FROMDS;
} else {
- if (pDevice->eOPMode == OP_MODE_ADHOC) {
+ if (pDevice->op_mode == NL80211_IFTYPE_ADHOC) {
memcpy(&(pMACHeader->addr1[0]),
&(psEthHeader->h_dest[0]),
ETH_ALEN);
@@ -1541,8 +1542,8 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
pbyIVHead = (u8 *)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding);
pbyPayloadHead = (u8 *)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding + cbIVlen);
do {
- if ((pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) &&
- (pDevice->bLinkPass == true)) {
+ if (pDevice->op_mode == NL80211_IFTYPE_STATION &&
+ pDevice->bLinkPass == true) {
pbyBSSID = pDevice->abyBSSID;
// get pairwise key
if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == false) {
@@ -1560,7 +1561,7 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
pbyBSSID = pDevice->abyBroadcastAddr;
if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == false) {
pTransmitKey = NULL;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KEY is NULL. OP Mode[%d]\n", pDevice->eOPMode);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KEY is NULL. OP Mode[%d]\n", pDevice->op_mode);
} else {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Get GTK.\n");
}
@@ -1592,14 +1593,14 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
struct vnt_tx_datahead_g *data_head = &pTX_Buffer->tx_head.
tx_cts.tx.head.cts_g.data_head;
- data_head->wDuration_a =
+ data_head->duration_a =
cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
- data_head->wDuration_b =
+ data_head->duration_b =
cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
} else {
struct vnt_tx_datahead_ab *data_head = &pTX_Buffer->tx_head.
tx_ab.tx.head.data_head_ab;
- data_head->wDuration =
+ data_head->duration =
cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
}
}
@@ -1609,7 +1610,7 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
pTX_Buffer->byType = 0x00;
pContext->pPacket = NULL;
- pContext->Type = CONTEXT_MGMT_PACKET;
+ pContext->type = CONTEXT_MGMT_PACKET;
pContext->uBufLen = (u16)cbReqCount + 4; //USB header
if (WLAN_GET_FC_TODS(pMACHeader->frame_control) == 0) {
@@ -1701,7 +1702,7 @@ CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
pTX_Buffer->byType = 0x01;
pContext->pPacket = NULL;
- pContext->Type = CONTEXT_MGMT_PACKET;
+ pContext->type = CONTEXT_MGMT_PACKET;
pContext->uBufLen = (u16)cbReqCount + 4; //USB header
PIPEnsSendBulkOut(pDevice,pContext);
@@ -2032,14 +2033,14 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
struct vnt_tx_datahead_g *data_head = &pTX_Buffer->tx_head.
tx_cts.tx.head.cts_g.data_head;
- data_head->wDuration_a =
+ data_head->duration_a =
cpu_to_le16(p80211Header->sA2.wDurationID);
- data_head->wDuration_b =
+ data_head->duration_b =
cpu_to_le16(p80211Header->sA2.wDurationID);
} else {
struct vnt_tx_datahead_ab *data_head = &pTX_Buffer->tx_head.
tx_ab.tx.head.data_head_ab;
- data_head->wDuration =
+ data_head->duration =
cpu_to_le16(p80211Header->sA2.wDurationID);
}
}
@@ -2049,7 +2050,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
pTX_Buffer->byType = 0x00;
pContext->pPacket = skb;
- pContext->Type = CONTEXT_MGMT_PACKET;
+ pContext->type = CONTEXT_MGMT_PACKET;
pContext->uBufLen = (u16)cbReqCount + 4; //USB header
if (WLAN_GET_FC_TODS(pMACHeader->frame_control) == 0) {
@@ -2305,7 +2306,7 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
}
}
else {
- if (pDevice->eOPMode == OP_MODE_ADHOC) {
+ if (pDevice->op_mode == NL80211_IFTYPE_ADHOC) {
// Adhoc Tx rate decided from node DB
if (is_multicast_ether_addr(pDevice->sTxEthHeader.h_dest)) {
// Multicast use highest data rate
@@ -2336,7 +2337,7 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
}
}
}
- if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) {
+ if (pDevice->op_mode == NL80211_IFTYPE_STATION) {
// Infra STA rate decided from AP Node, index = 0
pDevice->wCurrentRate = pMgmt->sNodeDBTable[0].wTxDataRate;
}
@@ -2439,11 +2440,11 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
pTX_Buffer->wTxByteCount = (u16)BytesToWrite;
pContext->pPacket = skb;
- pContext->Type = CONTEXT_DATA_PACKET;
+ pContext->type = CONTEXT_DATA_PACKET;
pContext->uBufLen = (u16)BytesToWrite + 4 ; //USB header
s_vSaveTxPktInfo(pDevice, (u8)(pTX_Buffer->byPKTNO & 0x0F),
- &pContext->sEthHeader.h_dest[0],
+ &pDevice->sTxEthHeader.h_dest[0],
(u16)(BytesToWrite-uHeaderLen),
pTX_Buffer->fifo_head.wFIFOCtl);
@@ -2593,11 +2594,11 @@ int bRelayPacketSend(struct vnt_private *pDevice, u8 *pbySkbData, u32 uDataLen,
pTX_Buffer->wTxByteCount = (u16)BytesToWrite;
pContext->pPacket = NULL;
- pContext->Type = CONTEXT_DATA_PACKET;
+ pContext->type = CONTEXT_DATA_PACKET;
pContext->uBufLen = (u16)BytesToWrite + 4 ; //USB header
s_vSaveTxPktInfo(pDevice, (u8)(pTX_Buffer->byPKTNO & 0x0F),
- &pContext->sEthHeader.h_dest[0],
+ &pDevice->sTxEthHeader.h_dest[0],
(u16)(BytesToWrite - uHeaderLen),
pTX_Buffer->fifo_head.wFIFOCtl);
diff --git a/drivers/staging/vt6656/rxtx.h b/drivers/staging/vt6656/rxtx.h
index b3ee6d01aa88..6d6539d29d04 100644
--- a/drivers/staging/vt6656/rxtx.h
+++ b/drivers/staging/vt6656/rxtx.h
@@ -53,68 +53,68 @@ struct vnt_mic_hdr {
/* RsvTime buffer header */
struct vnt_rrv_time_rts {
- u16 wRTSTxRrvTime_ba;
- u16 wRTSTxRrvTime_aa;
- u16 wRTSTxRrvTime_bb;
+ __le16 rts_rrv_time_ba;
+ __le16 rts_rrv_time_aa;
+ __le16 rts_rrv_time_bb;
u16 wReserved;
- u16 wTxRrvTime_b;
- u16 wTxRrvTime_a;
+ __le16 rrv_time_b;
+ __le16 rrv_time_a;
} __packed;
struct vnt_rrv_time_cts {
- u16 wCTSTxRrvTime_ba;
+ __le16 cts_rrv_time_ba;
u16 wReserved;
- u16 wTxRrvTime_b;
- u16 wTxRrvTime_a;
+ __le16 rrv_time_b;
+ __le16 rrv_time_a;
} __packed;
struct vnt_rrv_time_ab {
- u16 wRTSTxRrvTime;
- u16 wTxRrvTime;
+ __le16 rts_rrv_time;
+ __le16 rrv_time;
} __packed;
/* TX data header */
struct vnt_tx_datahead_g {
struct vnt_phy_field b;
struct vnt_phy_field a;
- u16 wDuration_b;
- u16 wDuration_a;
- u16 wTimeStampOff_b;
- u16 wTimeStampOff_a;
+ __le16 duration_b;
+ __le16 duration_a;
+ __le16 time_stamp_off_b;
+ __le16 time_stamp_off_a;
} __packed;
struct vnt_tx_datahead_g_fb {
struct vnt_phy_field b;
struct vnt_phy_field a;
- u16 wDuration_b;
- u16 wDuration_a;
- u16 wDuration_a_f0;
- u16 wDuration_a_f1;
- u16 wTimeStampOff_b;
- u16 wTimeStampOff_a;
+ __le16 duration_b;
+ __le16 duration_a;
+ __le16 duration_a_f0;
+ __le16 duration_a_f1;
+ __le16 time_stamp_off_b;
+ __le16 time_stamp_off_a;
} __packed;
struct vnt_tx_datahead_ab {
struct vnt_phy_field ab;
- u16 wDuration;
- u16 wTimeStampOff;
+ __le16 duration;
+ __le16 time_stamp_off;
} __packed;
struct vnt_tx_datahead_a_fb {
struct vnt_phy_field a;
- u16 wDuration;
- u16 wTimeStampOff;
- u16 wDuration_f0;
- u16 wDuration_f1;
+ __le16 duration;
+ __le16 time_stamp_off;
+ __le16 duration_f0;
+ __le16 duration_f1;
} __packed;
/* RTS buffer header */
struct vnt_rts_g {
struct vnt_phy_field b;
struct vnt_phy_field a;
- u16 wDuration_ba;
- u16 wDuration_aa;
- u16 wDuration_bb;
+ __le16 duration_ba;
+ __le16 duration_aa;
+ __le16 duration_bb;
u16 wReserved;
struct ieee80211_rts data;
struct vnt_tx_datahead_g data_head;
@@ -123,21 +123,21 @@ struct vnt_rts_g {
struct vnt_rts_g_fb {
struct vnt_phy_field b;
struct vnt_phy_field a;
- u16 wDuration_ba;
- u16 wDuration_aa;
- u16 wDuration_bb;
+ __le16 duration_ba;
+ __le16 duration_aa;
+ __le16 duration_bb;
u16 wReserved;
- u16 wRTSDuration_ba_f0;
- u16 wRTSDuration_aa_f0;
- u16 wRTSDuration_ba_f1;
- u16 wRTSDuration_aa_f1;
+ __le16 rts_duration_ba_f0;
+ __le16 rts_duration_aa_f0;
+ __le16 rts_duration_ba_f1;
+ __le16 rts_duration_aa_f1;
struct ieee80211_rts data;
struct vnt_tx_datahead_g_fb data_head;
} __packed;
struct vnt_rts_ab {
struct vnt_phy_field ab;
- u16 wDuration;
+ __le16 duration;
u16 wReserved;
struct ieee80211_rts data;
struct vnt_tx_datahead_ab data_head;
@@ -145,10 +145,10 @@ struct vnt_rts_ab {
struct vnt_rts_a_fb {
struct vnt_phy_field a;
- u16 wDuration;
+ __le16 duration;
u16 wReserved;
- u16 wRTSDuration_f0;
- u16 wRTSDuration_f1;
+ __le16 rts_duration_f0;
+ __le16 rts_duration_f1;
struct ieee80211_rts data;
struct vnt_tx_datahead_a_fb data_head;
} __packed;
@@ -156,7 +156,7 @@ struct vnt_rts_a_fb {
/* CTS buffer header */
struct vnt_cts {
struct vnt_phy_field b;
- u16 wDuration_ba;
+ __le16 duration_ba;
u16 wReserved;
struct ieee80211_cts data;
u16 reserved2;
@@ -165,10 +165,10 @@ struct vnt_cts {
struct vnt_cts_fb {
struct vnt_phy_field b;
- u16 wDuration_ba;
+ __le16 duration_ba;
u16 wReserved;
- u16 wCTSDuration_ba_f0;
- u16 wCTSDuration_ba_f1;
+ __le16 cts_duration_ba_f0;
+ __le16 cts_duration_ba_f1;
struct ieee80211_cts data;
u16 reserved2;
struct vnt_tx_datahead_g_fb data_head;
@@ -234,8 +234,8 @@ struct vnt_tx_short_buf_head {
u16 fifo_ctl;
u16 time_stamp;
struct vnt_phy_field ab;
- u16 duration;
- u16 time_stamp_off;
+ __le16 duration;
+ __le16 time_stamp_off;
} __packed;
struct vnt_beacon_buffer {
diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c
index 01cf09999b6d..c5838d99f89f 100644
--- a/drivers/staging/vt6656/usbpipe.c
+++ b/drivers/staging/vt6656/usbpipe.c
@@ -105,6 +105,8 @@ int PIPEnsControlOutAsyn(struct vnt_private *pDevice, u8 byRequest,
int PIPEnsControlOut(struct vnt_private *pDevice, u8 byRequest, u16 wValue,
u16 wIndex, u16 wLength, u8 *pbyBuffer)
+ __releases(&pDevice->lock)
+ __acquires(&pDevice->lock)
{
int ntStatus = 0;
int ii;
@@ -167,6 +169,8 @@ int PIPEnsControlOut(struct vnt_private *pDevice, u8 byRequest, u16 wValue,
int PIPEnsControlIn(struct vnt_private *pDevice, u8 byRequest, u16 wValue,
u16 wIndex, u16 wLength, u8 *pbyBuffer)
+ __releases(&pDevice->lock)
+ __acquires(&pDevice->lock)
{
int ntStatus = 0;
int ii;
@@ -295,40 +299,38 @@ static void s_nsControlInUsbIoCompleteRead(struct urb *urb)
*
*/
-int PIPEnsInterruptRead(struct vnt_private *pDevice)
+int PIPEnsInterruptRead(struct vnt_private *priv)
{
- int ntStatus = STATUS_FAILURE;
+ int status = STATUS_FAILURE;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsStartInterruptUsbRead()\n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "---->s_nsStartInterruptUsbRead()\n");
- if(pDevice->intBuf.bInUse == true){
- return (STATUS_FAILURE);
- }
- pDevice->intBuf.bInUse = true;
-// pDevice->bEventAvailable = false;
- pDevice->ulIntInPosted++;
-
- //
- // Now that we have created the urb, we will send a
- // request to the USB device object.
- //
- pDevice->pInterruptURB->interval = pDevice->int_interval;
-
-usb_fill_bulk_urb(pDevice->pInterruptURB,
- pDevice->usb,
- usb_rcvbulkpipe(pDevice->usb, 1),
- (void *) pDevice->intBuf.pDataBuf,
+ if (priv->int_buf.in_use == true)
+ return STATUS_FAILURE;
+
+ priv->int_buf.in_use = true;
+
+ usb_fill_int_urb(priv->pInterruptURB,
+ priv->usb,
+ usb_rcvintpipe(priv->usb, 1),
+ priv->int_buf.data_buf,
MAX_INTERRUPT_SIZE,
s_nsInterruptUsbIoCompleteRead,
- pDevice);
+ priv,
+ priv->int_interval);
- ntStatus = usb_submit_urb(pDevice->pInterruptURB, GFP_ATOMIC);
- if (ntStatus != 0) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Submit int URB failed %d\n", ntStatus);
- }
+ status = usb_submit_urb(priv->pInterruptURB, GFP_ATOMIC);
+ if (status) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "Submit int URB failed %d\n", status);
+ priv->int_buf.in_use = false;
+ }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"<----s_nsStartInterruptUsbRead Return(%x)\n",ntStatus);
- return ntStatus;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "<----s_nsStartInterruptUsbRead Return(%x)\n", status);
+
+ return status;
}
/*
@@ -348,67 +350,48 @@ usb_fill_bulk_urb(pDevice->pInterruptURB,
static void s_nsInterruptUsbIoCompleteRead(struct urb *urb)
{
- struct vnt_private *pDevice = (struct vnt_private *)urb->context;
- int ntStatus;
+ struct vnt_private *priv = urb->context;
+ int status;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsInterruptUsbIoCompleteRead\n");
- //
- // The context given to IoSetCompletionRoutine is the receive buffer object
- //
-
- //
- // We have a number of cases:
- // 1) The USB read timed out and we received no data.
- // 2) The USB read timed out and we received some data.
- // 3) The USB read was successful and fully filled our irp buffer.
- // 4) The irp was cancelled.
- // 5) Some other failure from the USB device object.
- //
- ntStatus = urb->status;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_nsInterruptUsbIoCompleteRead Status %d\n", ntStatus);
-
- // if we were not successful, we need to free the int buffer for future use right here
- // otherwise interrupt data handler will free int buffer after it handle it.
- if (( ntStatus != STATUS_SUCCESS )) {
- pDevice->ulBulkInError++;
- pDevice->intBuf.bInUse = false;
-
-// if (ntStatus == USBD_STATUS_CRC) {
-// pDevice->ulIntInContCRCError++;
-// }
-
-// if (ntStatus == STATUS_NOT_CONNECTED )
-// {
- pDevice->fKillEventPollingThread = true;
-// }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"IntUSBIoCompleteControl STATUS = %d\n", ntStatus );
- } else {
- pDevice->ulIntInBytesRead += (unsigned long) urb->actual_length;
- pDevice->ulIntInContCRCError = 0;
- pDevice->bEventAvailable = true;
- INTnsProcessData(pDevice);
- }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "---->s_nsInterruptUsbIoCompleteRead\n");
+
+ switch (urb->status) {
+ case 0:
+ case -ETIMEDOUT:
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ priv->int_buf.in_use = false;
+ return;
+ default:
+ break;
+ }
- if (pDevice->fKillEventPollingThread != true) {
- usb_fill_bulk_urb(pDevice->pInterruptURB,
- pDevice->usb,
- usb_rcvbulkpipe(pDevice->usb, 1),
- (void *) pDevice->intBuf.pDataBuf,
- MAX_INTERRUPT_SIZE,
- s_nsInterruptUsbIoCompleteRead,
- pDevice);
+ status = urb->status;
- ntStatus = usb_submit_urb(pDevice->pInterruptURB, GFP_ATOMIC);
- if (ntStatus != 0) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Submit int URB failed %d\n", ntStatus);
- }
- }
- //
- // We return STATUS_MORE_PROCESSING_REQUIRED so that the completion
- // routine (IofCompleteRequest) will stop working on the irp.
- //
- return ;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "s_nsInterruptUsbIoCompleteRead Status %d\n", status);
+
+ if (status != STATUS_SUCCESS) {
+ priv->int_buf.in_use = false;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "IntUSBIoCompleteControl STATUS = %d\n", status);
+ } else {
+ INTnsProcessData(priv);
+ }
+
+ status = usb_submit_urb(priv->pInterruptURB, GFP_ATOMIC);
+ if (status) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "Submit int URB failed %d\n", status);
+ } else {
+ priv->int_buf.in_use = true;
+ }
+
+ return;
}
/*
@@ -425,45 +408,41 @@ static void s_nsInterruptUsbIoCompleteRead(struct urb *urb)
*
*/
-int PIPEnsBulkInUsbRead(struct vnt_private *pDevice, struct vnt_rcb *pRCB)
+int PIPEnsBulkInUsbRead(struct vnt_private *priv, struct vnt_rcb *rcb)
{
- int ntStatus = 0;
- struct urb *pUrb;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsStartBulkInUsbRead\n");
+ int status = 0;
+ struct urb *urb;
- if (pDevice->Flags & fMP_DISCONNECTED)
- return STATUS_FAILURE;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsStartBulkInUsbRead\n");
- pDevice->ulBulkInPosted++;
+ if (priv->Flags & fMP_DISCONNECTED)
+ return STATUS_FAILURE;
- pUrb = pRCB->pUrb;
- //
- // Now that we have created the urb, we will send a
- // request to the USB device object.
- //
- if (pRCB->skb == NULL) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pRCB->skb is null \n");
- return ntStatus;
- }
+ urb = rcb->pUrb;
+ if (rcb->skb == NULL) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"rcb->skb is null\n");
+ return status;
+ }
- usb_fill_bulk_urb(pUrb,
- pDevice->usb,
- usb_rcvbulkpipe(pDevice->usb, 2),
- (void *) (pRCB->skb->data),
+ usb_fill_bulk_urb(urb,
+ priv->usb,
+ usb_rcvbulkpipe(priv->usb, 2),
+ (void *) (rcb->skb->data),
MAX_TOTAL_SIZE_WITH_ALL_HEADERS,
s_nsBulkInUsbIoCompleteRead,
- pRCB);
+ rcb);
- ntStatus = usb_submit_urb(pUrb, GFP_ATOMIC);
- if (ntStatus != 0) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Submit Rx URB failed %d\n", ntStatus);
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status != 0) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "Submit Rx URB failed %d\n", status);
return STATUS_FAILURE ;
}
- pRCB->Ref = 1;
- pRCB->bBoolInUse= true;
- return ntStatus;
+ rcb->Ref = 1;
+ rcb->bBoolInUse = true;
+
+ return status;
}
/*
@@ -483,51 +462,47 @@ int PIPEnsBulkInUsbRead(struct vnt_private *pDevice, struct vnt_rcb *pRCB)
static void s_nsBulkInUsbIoCompleteRead(struct urb *urb)
{
- struct vnt_rcb *pRCB = (struct vnt_rcb *)urb->context;
- struct vnt_private *pDevice = pRCB->pDevice;
- unsigned long bytesRead;
- int bIndicateReceive = false;
- int bReAllocSkb = false;
- int status;
+ struct vnt_rcb *rcb = urb->context;
+ struct vnt_private *priv = rcb->pDevice;
+ int re_alloc_skb = false;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkInUsbIoCompleteRead\n");
- status = urb->status;
- bytesRead = urb->actual_length;
-
- if (status) {
- pDevice->ulBulkInError++;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BULK In failed %d\n", status);
-//todo...xxxxxx
-// if (status == USBD_STATUS_CRC) {
-// pDevice->ulBulkInContCRCError++;
-// }
-// if (status == STATUS_DEVICE_NOT_CONNECTED )
-// {
-// MP_SET_FLAG(pDevice, fMP_DISCONNECTED);
-// }
- } else {
- if (bytesRead)
- bIndicateReceive = true;
- pDevice->ulBulkInContCRCError = 0;
- pDevice->ulBulkInBytesRead += bytesRead;
- }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkInUsbIoCompleteRead\n");
- if (bIndicateReceive) {
- spin_lock(&pDevice->lock);
- if (RXbBulkInProcessData(pDevice, pRCB, bytesRead) == true)
- bReAllocSkb = true;
- spin_unlock(&pDevice->lock);
- }
- pRCB->Ref--;
- if (pRCB->Ref == 0)
- {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"RxvFreeNormal %d \n",pDevice->NumRecvFreeList);
- spin_lock(&pDevice->lock);
- RXvFreeRCB(pRCB, bReAllocSkb);
- spin_unlock(&pDevice->lock);
- }
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ case -ETIMEDOUT:
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "BULK In failed %d\n", urb->status);
+ break;
+ }
+
+ if (urb->actual_length) {
+ spin_lock(&priv->lock);
+
+ if (RXbBulkInProcessData(priv, rcb, urb->actual_length) == true)
+ re_alloc_skb = true;
+
+ spin_unlock(&priv->lock);
+ }
+
+ rcb->Ref--;
+ if (rcb->Ref == 0) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"RxvFreeNormal %d\n",
+ priv->NumRecvFreeList);
+ spin_lock(&priv->lock);
+
+ RXvFreeRCB(rcb, re_alloc_skb);
- return;
+ spin_unlock(&priv->lock);
+ }
+
+ return;
}
/*
@@ -544,53 +519,40 @@ static void s_nsBulkInUsbIoCompleteRead(struct urb *urb)
*
*/
-int PIPEnsSendBulkOut(struct vnt_private *pDevice,
- struct vnt_usb_send_context *pContext)
+int PIPEnsSendBulkOut(struct vnt_private *priv,
+ struct vnt_usb_send_context *context)
{
int status;
- struct urb *pUrb;
+ struct urb *urb;
- pDevice->bPWBitOn = false;
+ priv->bPWBitOn = false;
-/*
- if (pDevice->pPendingBulkOutContext != NULL) {
- pDevice->NumContextsQueued++;
- EnqueueContext(pDevice->FirstTxContextQueue, pDevice->LastTxContextQueue, pContext);
- status = STATUS_PENDING;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Send pending!\n");
- return status;
- }
-*/
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_nsSendBulkOut\n");
-
- if (MP_IS_READY(pDevice) && (pDevice->Flags & fMP_POST_WRITES)) {
-
- pUrb = pContext->pUrb;
- pDevice->ulBulkOutPosted++;
-// pDevice->pPendingBulkOutContext = pContext;
- usb_fill_bulk_urb(
- pUrb,
- pDevice->usb,
- usb_sndbulkpipe(pDevice->usb, 3),
- (void *) &(pContext->Data[0]),
- pContext->uBufLen,
- s_nsBulkOutIoCompleteWrite,
- pContext);
-
- status = usb_submit_urb(pUrb, GFP_ATOMIC);
- if (status != 0)
- {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Submit Tx URB failed %d\n", status);
- pContext->bBoolInUse = false;
- return STATUS_FAILURE;
- }
- return STATUS_PENDING;
- }
- else {
- pContext->bBoolInUse = false;
- return STATUS_RESOURCES;
- }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_nsSendBulkOut\n");
+
+ if (!(MP_IS_READY(priv) && priv->Flags & fMP_POST_WRITES)) {
+ context->bBoolInUse = false;
+ return STATUS_RESOURCES;
+ }
+
+ urb = context->pUrb;
+
+ usb_fill_bulk_urb(urb,
+ priv->usb,
+ usb_sndbulkpipe(priv->usb, 3),
+ context->Data,
+ context->uBufLen,
+ s_nsBulkOutIoCompleteWrite,
+ context);
+
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status != 0) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "Submit Tx URB failed %d\n", status);
+ context->bBoolInUse = false;
+ return STATUS_FAILURE;
+ }
+
+ return STATUS_PENDING;
}
/*
@@ -623,68 +585,49 @@ int PIPEnsSendBulkOut(struct vnt_private *pDevice,
static void s_nsBulkOutIoCompleteWrite(struct urb *urb)
{
- struct vnt_private *pDevice;
- int status;
- CONTEXT_TYPE ContextType;
- unsigned long ulBufLen;
- struct vnt_usb_send_context *pContext;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkOutIoCompleteWrite\n");
- //
- // The context given to IoSetCompletionRoutine is an USB_CONTEXT struct
- //
- pContext = (struct vnt_usb_send_context *)urb->context;
-
- pDevice = pContext->pDevice;
- ContextType = pContext->Type;
- ulBufLen = pContext->uBufLen;
-
- if (!netif_device_present(pDevice->dev))
- return;
+ struct vnt_usb_send_context *context = urb->context;
+ struct vnt_private *priv = context->pDevice;
+ u8 context_type = context->type;
- //
- // Perform various IRP, URB, and buffer 'sanity checks'
- //
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkOutIoCompleteWrite\n");
- status = urb->status;
-
- if(status == STATUS_SUCCESS) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Write %d bytes\n",(int)ulBufLen);
- pDevice->ulBulkOutBytesWrite += ulBufLen;
- pDevice->ulBulkOutContCRCError = 0;
- } else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BULK Out failed %d\n", status);
- pDevice->ulBulkOutError++;
- }
+ switch (urb->status) {
+ case 0:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "Write %d bytes\n", context->uBufLen);
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ context->bBoolInUse = false;
+ return;
+ case -ETIMEDOUT:
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "BULK Out failed %d\n", urb->status);
+ break;
+ }
-// pDevice->ulCheckForHangCount = 0;
-// pDevice->pPendingBulkOutContext = NULL;
+ if (!netif_device_present(priv->dev))
+ return;
- if ( CONTEXT_DATA_PACKET == ContextType ) {
- // Indicate to the protocol the status of the sent packet and return
- // ownership of the packet.
- if (pContext->pPacket != NULL) {
- dev_kfree_skb_irq(pContext->pPacket);
- pContext->pPacket = NULL;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"tx %d bytes\n",(int)ulBufLen);
- }
+ if (CONTEXT_DATA_PACKET == context_type) {
+ if (context->pPacket != NULL) {
+ dev_kfree_skb_irq(context->pPacket);
+ context->pPacket = NULL;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "tx %d bytes\n", context->uBufLen);
+ }
- pDevice->dev->trans_start = jiffies;
+ priv->dev->trans_start = jiffies;
+ }
- if (status == STATUS_SUCCESS) {
- pDevice->packetsSent++;
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Send USB error! [%08xh]\n", status);
- pDevice->packetsSentDropped++;
- }
+ if (priv->bLinkPass == true) {
+ if (netif_queue_stopped(priv->dev))
+ netif_wake_queue(priv->dev);
+ }
- }
- if (pDevice->bLinkPass == true) {
- if (netif_queue_stopped(pDevice->dev))
- netif_wake_queue(pDevice->dev);
- }
- pContext->bBoolInUse = false;
+ context->bBoolInUse = false;
- return;
+ return;
}
diff --git a/drivers/staging/vt6656/wcmd.c b/drivers/staging/vt6656/wcmd.c
index 6b9522914634..3cf3f24247a3 100644
--- a/drivers/staging/vt6656/wcmd.c
+++ b/drivers/staging/vt6656/wcmd.c
@@ -293,17 +293,11 @@ void vRunCommand(struct work_struct *work)
case WLAN_CMD_SCAN_START:
pDevice->byReAssocCount = 0;
- if (pDevice->bRadioOff == true) {
- s_bCommandComplete(pDevice);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
+ if (pDevice->bRadioOff == true)
+ break;
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- s_bCommandComplete(pDevice);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)
+ break;
pItemSSID = (PWLAN_IE_SSID)pMgmt->abyScanSSID;
@@ -311,16 +305,12 @@ void vRunCommand(struct work_struct *work)
pMgmt->uScanChannel = pDevice->byMinChannel;
if (pMgmt->uScanChannel > pDevice->byMaxChannel) {
pDevice->eCommandState = WLAN_CMD_SCAN_END;
- s_bCommandComplete(pDevice);
- spin_unlock_irq(&pDevice->lock);
- return;
+ break;
} else {
if (!ChannelValid(pDevice->byZoneType, pMgmt->uScanChannel)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Invalid channel pMgmt->uScanChannel = %d\n", pMgmt->uScanChannel);
pMgmt->uScanChannel++;
- s_bCommandComplete(pDevice);
- spin_unlock_irq(&pDevice->lock);
- return;
+ break;
}
if (pMgmt->uScanChannel == pDevice->byMinChannel) {
// pMgmt->eScanType = WMAC_SCAN_ACTIVE; //mike mark
@@ -420,16 +410,13 @@ void vRunCommand(struct work_struct *work)
memset(&wrqu, 0, sizeof(wrqu));
wireless_send_event(pDevice->dev, SIOCGIWSCAN, &wrqu, NULL);
- s_bCommandComplete(pDevice);
break;
case WLAN_CMD_DISASSOCIATE_START:
pDevice->byReAssocCount = 0;
if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
(pMgmt->eCurrState != WMAC_STATE_ASSOC)) {
- s_bCommandComplete(pDevice);
- spin_unlock_irq(&pDevice->lock);
- return;
+ break;
} else {
pDevice->bwextstep0 = false;
pDevice->bwextstep1 = false;
@@ -458,17 +445,14 @@ void vRunCommand(struct work_struct *work)
netif_stop_queue(pDevice->dev);
if (pDevice->bNeedRadioOFF == true)
CARDbRadioPowerOff(pDevice);
- s_bCommandComplete(pDevice);
+
break;
case WLAN_CMD_SSID_START:
pDevice->byReAssocCount = 0;
- if (pDevice->bRadioOff == true) {
- s_bCommandComplete(pDevice);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
+ if (pDevice->bRadioOff == true)
+ break;
memcpy(pMgmt->abyAdHocSSID, pMgmt->abyDesireSSID,
((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len + WLAN_IEHDR_LEN);
@@ -489,11 +473,9 @@ void vRunCommand(struct work_struct *work)
if ((pMgmt->eCurrState == WMAC_STATE_ASSOC) ||
((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED))) {
if (pItemSSID->len == pItemSSIDCurr->len) {
- if (memcmp(pItemSSID->abySSID, pItemSSIDCurr->abySSID, pItemSSID->len) == 0) {
- s_bCommandComplete(pDevice);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
+ if (!memcmp(pItemSSID->abySSID,
+ pItemSSIDCurr->abySSID, pItemSSID->len))
+ break;
}
netif_stop_queue(pDevice->dev);
pDevice->bLinkPass = false;
@@ -582,7 +564,6 @@ void vRunCommand(struct work_struct *work)
}
}
}
- s_bCommandComplete(pDevice);
break;
case WLAN_AUTHENTICATE_WAIT:
@@ -612,7 +593,6 @@ void vRunCommand(struct work_struct *work)
}
pDevice->byLinkWaitCount = 0;
- s_bCommandComplete(pDevice);
break;
case WLAN_ASSOCIATE_WAIT:
@@ -647,7 +627,6 @@ void vRunCommand(struct work_struct *work)
return;
}
- s_bCommandComplete(pDevice);
break;
case WLAN_CMD_AP_MODE_START:
@@ -683,7 +662,6 @@ void vRunCommand(struct work_struct *work)
ControlvMaskByte(pDevice, MESSAGE_REQUEST_MACREG, MAC_REG_PAPEDELAY, LEDSTS_STS, LEDSTS_INTER);
schedule_delayed_work(&pDevice->second_callback_work, HZ);
}
- s_bCommandComplete(pDevice);
break;
case WLAN_CMD_TX_PSPACKET_START:
@@ -738,8 +716,6 @@ void vRunCommand(struct work_struct *work)
pMgmt->sNodeDBTable[ii].bRxPSPoll = false;
}
}
-
- s_bCommandComplete(pDevice);
break;
case WLAN_CMD_RADIO_START:
@@ -760,11 +736,8 @@ void vRunCommand(struct work_struct *work)
1,
&byTmp);
- if (ntStatus != STATUS_SUCCESS) {
- s_bCommandComplete(pDevice);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
+ if (ntStatus != STATUS_SUCCESS)
+ break;
if ((byTmp & GPIO3_DATA) == 0) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" WLAN_CMD_RADIO_START_OFF........................\n");
// Old commands are useless.
@@ -833,7 +806,6 @@ void vRunCommand(struct work_struct *work)
}
}
- s_bCommandComplete(pDevice);
break;
case WLAN_CMD_CHANGE_BBSENSITIVITY_START:
@@ -843,24 +815,20 @@ void vRunCommand(struct work_struct *work)
BBvSetVGAGainOffset(pDevice, pDevice->byBBVGACurrent);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Change sensitivity pDevice->byBBVGACurrent = %x\n", pDevice->byBBVGACurrent);
pDevice->bStopDataPkt = false;
- s_bCommandComplete(pDevice);
break;
case WLAN_CMD_TBTT_WAKEUP_START:
PSbIsNextTBTTWakeUp(pDevice);
- s_bCommandComplete(pDevice);
break;
case WLAN_CMD_BECON_SEND_START:
bMgrPrepareBeaconToSend(pDevice, pMgmt);
- s_bCommandComplete(pDevice);
break;
case WLAN_CMD_SETPOWER_START:
RFbSetPower(pDevice, pDevice->wCurrentRate, pMgmt->uCurrChannel);
- s_bCommandComplete(pDevice);
break;
case WLAN_CMD_CHANGE_ANTENNA_START:
@@ -878,12 +846,10 @@ void vRunCommand(struct work_struct *work)
else
BBvSetAntennaMode(pDevice, ANT_RXA);
}
- s_bCommandComplete(pDevice);
break;
case WLAN_CMD_REMOVE_ALLKEY_START:
KeybRemoveAllKey(pDevice, &(pDevice->sKey), pDevice->abyBSSID);
- s_bCommandComplete(pDevice);
break;
case WLAN_CMD_MAC_DISPOWERSAVING_START:
@@ -898,7 +864,6 @@ void vRunCommand(struct work_struct *work)
NULL
);
}
- s_bCommandComplete(pDevice);
break;
case WLAN_CMD_11H_CHSW_START:
@@ -906,14 +871,17 @@ void vRunCommand(struct work_struct *work)
pDevice->bChannelSwitch = false;
pMgmt->uCurrChannel = pDevice->byNewChannel;
pDevice->bStopDataPkt = false;
- s_bCommandComplete(pDevice);
break;
+ case WLAN_CMD_CONFIGURE_FILTER_START:
+ vnt_configure_filter(pDevice);
+ break;
default:
- s_bCommandComplete(pDevice);
break;
} //switch
+ s_bCommandComplete(pDevice);
+
spin_unlock_irq(&pDevice->lock);
return;
}
@@ -1009,6 +977,11 @@ static int s_bCommandComplete(struct vnt_private *pDevice)
pDevice->eCommandState = WLAN_CMD_11H_CHSW_START;
break;
+ case WLAN_CMD_CONFIGURE_FILTER:
+ pDevice->eCommandState =
+ WLAN_CMD_CONFIGURE_FILTER_START;
+ break;
+
default:
break;
}
diff --git a/drivers/staging/vt6656/wcmd.h b/drivers/staging/vt6656/wcmd.h
index caf2684ce915..736572101bad 100644
--- a/drivers/staging/vt6656/wcmd.h
+++ b/drivers/staging/vt6656/wcmd.h
@@ -51,7 +51,8 @@ typedef enum tagCMD_CODE {
WLAN_CMD_REMOVE_ALLKEY,
WLAN_CMD_MAC_DISPOWERSAVING,
WLAN_CMD_11H_CHSW,
- WLAN_CMD_RUN_AP
+ WLAN_CMD_RUN_AP,
+ WLAN_CMD_CONFIGURE_FILTER
} CMD_CODE, *PCMD_CODE;
#define CMD_Q_SIZE 32
@@ -96,6 +97,7 @@ typedef enum tagCMD_STATE {
WLAN_CMD_REMOVE_ALLKEY_START,
WLAN_CMD_MAC_DISPOWERSAVING_START,
WLAN_CMD_11H_CHSW_START,
+ WLAN_CMD_CONFIGURE_FILTER_START,
WLAN_CMD_IDLE
} CMD_STATE, *PCMD_STATE;
diff --git a/drivers/staging/vt6656/wmgr.c b/drivers/staging/vt6656/wmgr.c
index d74b0e7cb171..0d69719a7426 100644
--- a/drivers/staging/vt6656/wmgr.c
+++ b/drivers/staging/vt6656/wmgr.c
@@ -2164,12 +2164,12 @@ void vMgrCreateOwnIBSS(struct vnt_private *pDevice, PCMD_STATUS pStatus)
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_ESS(1);
pMgmt->byDTIMPeriod = DEFAULT_DTIM_PERIOD;
pMgmt->byDTIMCount = pMgmt->byDTIMPeriod - 1;
- pDevice->eOPMode = OP_MODE_AP;
+ pDevice->op_mode = NL80211_IFTYPE_AP;
}
if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_IBSS(1);
- pDevice->eOPMode = OP_MODE_ADHOC;
+ pDevice->op_mode = NL80211_IFTYPE_ADHOC;
}
if (pDevice->bEncryptionEnable) {
@@ -2359,7 +2359,7 @@ void vMgrJoinBSSBegin(struct vnt_private *pDevice, PCMD_STATUS pStatus)
pMgmt->eCurrState = WMAC_STATE_JOINTED;
// Adopt BSS state in Adapter Device Object
- pDevice->eOPMode = OP_MODE_INFRASTRUCTURE;
+ pDevice->op_mode = NL80211_IFTYPE_STATION;
memcpy(pDevice->abyBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN);
// Add current BSS to Candidate list
@@ -2500,7 +2500,7 @@ void vMgrJoinBSSBegin(struct vnt_private *pDevice, PCMD_STATUS pStatus)
pMgmt->eCurrMode = WMAC_MODE_IBSS_STA;
pMgmt->eCurrState = WMAC_STATE_STARTED;
// Adopt BSS state in Adapter Device Object
- pDevice->eOPMode = OP_MODE_ADHOC;
+ pDevice->op_mode = NL80211_IFTYPE_ADHOC;
pDevice->bLinkPass = true;
ControlvMaskByte(pDevice,MESSAGE_REQUEST_MACREG,MAC_REG_PAPEDELAY,LEDSTS_STS,LEDSTS_INTER);
memcpy(pDevice->abyBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN);
diff --git a/drivers/staging/winbond/localpara.h b/drivers/staging/winbond/localpara.h
index 84effc47d79d..8ca80ddda59a 100644
--- a/drivers/staging/winbond/localpara.h
+++ b/drivers/staging/winbond/localpara.h
@@ -58,9 +58,13 @@
#define LOCAL_11B_BASIC_RATE_BITMAP 0x826
#define LOCAL_11B_OPERATION_RATE_BITMAP 0x826
#define LOCAL_11G_BASIC_RATE_BITMAP 0x826 /* 1, 2, 5.5, 11 */
-#define LOCAL_11G_OPERATION_RATE_BITMAP 0x130c1240 /* 6, 9, 12, 18, 24, 36, 48, 54 */
+#define LOCAL_11G_OPERATION_RATE_BITMAP 0x130c1240 /* 6, 9, 12, 18,
+ * 24, 36, 48, 54
+ */
#define LOCAL_11A_BASIC_RATE_BITMAP 0x01001040 /* 6, 12, 24 */
-#define LOCAL_11A_OPERATION_RATE_BITMAP 0x120c0200 /* 9, 18, 36, 48, 54 */
+#define LOCAL_11A_OPERATION_RATE_BITMAP 0x120c0200 /* 9, 18, 36,
+ * 48, 54
+ */
#define PWR_ACTIVE 0
@@ -140,7 +144,9 @@ struct wb_local_para {
/* Unit time count for the decision to enter PS mode */
u16 CheckCountForPS;
u8 boHasTxActivity;/* tx activity has occurred */
- u8 boMacPsValid; /* Power save mode obtained from H/W is valid or not */
+ u8 boMacPsValid; /* Power save mode obtained
+ * from H/W is valid or not
+ */
/* Rate */
u8 TxRateMode; /*
@@ -162,35 +168,57 @@ struct wb_local_para {
u8 NumOfBRate;
u8 NumOfSRate;
- u8 NumOfDsssRateInSRate; /* number of DSSS rates in supported rate set */
+ u8 NumOfDsssRateInSRate; /* number of DSSS rates in
+ * supported rate set
+ */
u8 reserved1;
u32 dwBasicRateBitmap; /* bit map of basic rates */
- u32 dwSupportRateBitmap; /* bit map of all support rates including basic and operational rates */
+ u32 dwSupportRateBitmap; /* bit map of all support rates
+ * including basic and operational
+ * rates
+ */
/* For SME/MLME handler */
- u16 wOldSTAindex; /* valid when boHandover=TRUE, store old connected STA index */
- u16 wConnectedSTAindex; /* Index of peerly connected AP or IBSS in the descriptionset. */
- u16 Association_ID; /* The Association ID in the (Re)Association Response frame. */
- u16 ListenInterval; /* The listen interval when SME invoking MLME_ (Re)Associate_Request(). */
+ u16 wOldSTAindex; /* valid when boHandover=TRUE,
+ * store old connected STA index
+ */
+ u16 wConnectedSTAindex; /* Index of peerly connected AP or
+ * IBSS in the descriptionset.
+ */
+ u16 Association_ID; /* The Association ID in the
+ * (Re)Association Response frame.
+ */
+ u16 ListenInterval; /* The listen interval when SME invoking
+ * MLME_ (Re)Associate_Request().
+ */
struct radio_off RadioOffStatus;
u8 Reserved0[2];
- u8 boMsRadioOff; /* Ndis demands to be true when set Disassoc. OID and be false when set SSID OID. */
+ u8 boMsRadioOff; /* Ndis demands to be true when set
+ * Disassoc. OID and be false when
+ * set SSID OID.
+ */
u8 bAntennaNo; /* which antenna */
- u8 bConnectFlag; /* the connect status flag for roaming task */
+ u8 bConnectFlag; /* the connect status flag for
+ * roaming task
+ */
u8 RoamStatus;
u8 reserved7[3];
- struct chan_info CurrentChan; /* Current channel no. and channel band. It may be changed by scanning. */
+ struct chan_info CurrentChan; /* Current channel no. and channel band.
+ * It may be changed by scanning.
+ */
u8 boHandover; /* Roaming, Handover to other AP. */
u8 boCCAbusy;
- u16 CWMax; /* It may not be the real value that H/W used */
+ u16 CWMax; /* It may not be the real value
+ * that H/W used
+ */
u8 CWMin; /* 255: set according to 802.11 spec. */
u8 reserved2;
@@ -200,7 +228,9 @@ struct wb_local_para {
u8 bPreambleMode; /* AUTO, s32 */
u8 boNonERPpresent;
- u8 boProtectMechanism; /* H/W will take the necessary action based on this variable */
+ u8 boProtectMechanism; /* H/W will take the necessary action
+ * based on this variable
+ */
u8 boShortPreamble; /* Same here */
u8 boShortSlotTime; /* Same here */
u8 reserved_3;
@@ -213,8 +243,12 @@ struct wb_local_para {
u32 HwBssidValid;
/* For scan list */
- u8 BssListCount; /* Total count of valid descriptor indexes */
- u8 boReceiveUncorrectInfo; /* important settings in beacon/probe resp. have been changed */
+ u8 BssListCount; /* Total count of valid
+ * descriptor indexes
+ */
+ u8 boReceiveUncorrectInfo; /* important settings in beacon/probe
+ * resp. have been changed
+ */
u8 NoOfJoinerInIbss;
u8 reserved_4;
@@ -228,7 +262,9 @@ struct wb_local_para {
*/
u8 JoinerInIbss[(MAX_BSS_DESCRIPT_ELEMENT + 3) & ~0x03];
- /* General Statistics, count at Rx_handler or Tx_callback interrupt handler */
+ /* General Statistics, count at Rx_handler or
+ * Tx_callback interrupt handler
+ */
u64 GS_XMIT_OK; /* Good Frames Transmitted */
u64 GS_RCV_OK; /* Good Frames Received */
u32 GS_RCV_ERROR; /* Frames received with crc error */
@@ -248,10 +284,18 @@ struct wb_local_para {
u32 _dot11WEPUndecryptableCount;
u32 _dot11FrameDuplicateCount;
- struct chan_info IbssChanSetting; /* 2B. Start IBSS Channel setting by registry or WWU. */
- u8 reserved_5[2]; /* It may not be used after considering RF type, region and modulation type. */
+ struct chan_info IbssChanSetting; /* 2B. Start IBSS Channel
+ * setting by registry or
+ * WWU.
+ */
+ u8 reserved_5[2]; /* It may not be used after
+ * considering RF type, region
+ * and modulation type.
+ */
- u8 reserved_6[2]; /* two variables are for wep key error detection */
+ u8 reserved_6[2]; /* two variables are for wep
+ * key error detection
+ */
u32 bWepKeyError;
u32 bToSelfPacketReceived;
u32 WepKeyDetectTimerCount;
diff --git a/drivers/staging/winbond/wb35reg.c b/drivers/staging/winbond/wb35reg.c
index a5e255bb0f8b..bbc5ddcce6f5 100644
--- a/drivers/staging/winbond/wb35reg.c
+++ b/drivers/staging/winbond/wb35reg.c
@@ -76,41 +76,111 @@ void Wb35Reg_Update(struct hw_data *pHwData, u16 RegisterNo, u32 RegisterValue)
{
struct wb35_reg *reg = &pHwData->reg;
switch (RegisterNo) {
- case 0x3b0: reg->U1B0 = RegisterValue; break;
- case 0x3bc: reg->U1BC_LEDConfigure = RegisterValue; break;
- case 0x400: reg->D00_DmaControl = RegisterValue; break;
- case 0x800: reg->M00_MacControl = RegisterValue; break;
- case 0x804: reg->M04_MulticastAddress1 = RegisterValue; break;
- case 0x808: reg->M08_MulticastAddress2 = RegisterValue; break;
- case 0x824: reg->M24_MacControl = RegisterValue; break;
- case 0x828: reg->M28_MacControl = RegisterValue; break;
- case 0x82c: reg->M2C_MacControl = RegisterValue; break;
- case 0x838: reg->M38_MacControl = RegisterValue; break;
- case 0x840: reg->M40_MacControl = RegisterValue; break;
- case 0x844: reg->M44_MacControl = RegisterValue; break;
- case 0x848: reg->M48_MacControl = RegisterValue; break;
- case 0x84c: reg->M4C_MacStatus = RegisterValue; break;
- case 0x860: reg->M60_MacControl = RegisterValue; break;
- case 0x868: reg->M68_MacControl = RegisterValue; break;
- case 0x870: reg->M70_MacControl = RegisterValue; break;
- case 0x874: reg->M74_MacControl = RegisterValue; break;
- case 0x878: reg->M78_ERPInformation = RegisterValue; break;
- case 0x87C: reg->M7C_MacControl = RegisterValue; break;
- case 0x880: reg->M80_MacControl = RegisterValue; break;
- case 0x884: reg->M84_MacControl = RegisterValue; break;
- case 0x888: reg->M88_MacControl = RegisterValue; break;
- case 0x898: reg->M98_MacControl = RegisterValue; break;
- case 0x100c: reg->BB0C = RegisterValue; break;
- case 0x102c: reg->BB2C = RegisterValue; break;
- case 0x1030: reg->BB30 = RegisterValue; break;
- case 0x103c: reg->BB3C = RegisterValue; break;
- case 0x1048: reg->BB48 = RegisterValue; break;
- case 0x104c: reg->BB4C = RegisterValue; break;
- case 0x1050: reg->BB50 = RegisterValue; break;
- case 0x1054: reg->BB54 = RegisterValue; break;
- case 0x1058: reg->BB58 = RegisterValue; break;
- case 0x105c: reg->BB5C = RegisterValue; break;
- case 0x1060: reg->BB60 = RegisterValue; break;
+ case 0x3b0:
+ reg->U1B0 = RegisterValue;
+ break;
+ case 0x3bc:
+ reg->U1BC_LEDConfigure = RegisterValue;
+ break;
+ case 0x400:
+ reg->D00_DmaControl = RegisterValue;
+ break;
+ case 0x800:
+ reg->M00_MacControl = RegisterValue;
+ break;
+ case 0x804:
+ reg->M04_MulticastAddress1 = RegisterValue;
+ break;
+ case 0x808:
+ reg->M08_MulticastAddress2 = RegisterValue;
+ break;
+ case 0x824:
+ reg->M24_MacControl = RegisterValue;
+ break;
+ case 0x828:
+ reg->M28_MacControl = RegisterValue;
+ break;
+ case 0x82c:
+ reg->M2C_MacControl = RegisterValue;
+ break;
+ case 0x838:
+ reg->M38_MacControl = RegisterValue;
+ break;
+ case 0x840:
+ reg->M40_MacControl = RegisterValue;
+ break;
+ case 0x844:
+ reg->M44_MacControl = RegisterValue;
+ break;
+ case 0x848:
+ reg->M48_MacControl = RegisterValue;
+ break;
+ case 0x84c:
+ reg->M4C_MacStatus = RegisterValue;
+ break;
+ case 0x860:
+ reg->M60_MacControl = RegisterValue;
+ break;
+ case 0x868:
+ reg->M68_MacControl = RegisterValue;
+ break;
+ case 0x870:
+ reg->M70_MacControl = RegisterValue;
+ break;
+ case 0x874:
+ reg->M74_MacControl = RegisterValue;
+ break;
+ case 0x878:
+ reg->M78_ERPInformation = RegisterValue;
+ break;
+ case 0x87C:
+ reg->M7C_MacControl = RegisterValue;
+ break;
+ case 0x880:
+ reg->M80_MacControl = RegisterValue;
+ break;
+ case 0x884:
+ reg->M84_MacControl = RegisterValue;
+ break;
+ case 0x888:
+ reg->M88_MacControl = RegisterValue;
+ break;
+ case 0x898:
+ reg->M98_MacControl = RegisterValue;
+ break;
+ case 0x100c:
+ reg->BB0C = RegisterValue;
+ break;
+ case 0x102c:
+ reg->BB2C = RegisterValue;
+ break;
+ case 0x1030:
+ reg->BB30 = RegisterValue;
+ break;
+ case 0x103c:
+ reg->BB3C = RegisterValue;
+ break;
+ case 0x1048:
+ reg->BB48 = RegisterValue;
+ break;
+ case 0x104c:
+ reg->BB4C = RegisterValue;
+ break;
+ case 0x1050:
+ reg->BB50 = RegisterValue;
+ break;
+ case 0x1054:
+ reg->BB54 = RegisterValue;
+ break;
+ case 0x1058:
+ reg->BB58 = RegisterValue;
+ break;
+ case 0x105c:
+ reg->BB5C = RegisterValue;
+ break;
+ case 0x1060:
+ reg->BB60 = RegisterValue;
+ break;
}
}
diff --git a/drivers/staging/winbond/wb35rx.c b/drivers/staging/winbond/wb35rx.c
index 8d71bc2f5940..f006b166aebc 100644
--- a/drivers/staging/winbond/wb35rx.c
+++ b/drivers/staging/winbond/wb35rx.c
@@ -16,7 +16,8 @@
#include "core.h"
#include "wb35rx_f.h"
-static void packet_came(struct ieee80211_hw *hw, char *pRxBufferAddress, int PacketSize)
+static void packet_came(struct ieee80211_hw *hw, char *pRxBufferAddress,
+ int PacketSize)
{
struct wbsoft_priv *priv = hw->priv;
struct sk_buff *skb;
@@ -64,7 +65,8 @@ static void Wb35Rx_adjust(struct wb35_descriptor *pRxDes)
} else if (DecryptionMethod) { /* For TKIP and CCMP */
for (i = 7; i > 1; i--)
pRxBufferAddress[i] = pRxBufferAddress[i - 2];
- pRxDes->buffer_address[0] = pRxBufferAddress + 2; /* Update the descriptor, shift 8 byte */
+ /* Update the descriptor, shift 8 byte */
+ pRxDes->buffer_address[0] = pRxBufferAddress + 2;
BufferSize -= 8; /* 8 byte for IV + ICV */
}
pRxDes->buffer_size[0] = BufferSize;
@@ -95,7 +97,9 @@ static u16 Wb35Rx_indicate(struct ieee80211_hw *hw)
/* Parse the bulkin buffer */
while (BufferSize >= 4) {
- if ((cpu_to_le32(*(u32 *)pRxBufferAddress) & 0x0fffffff) == RX_END_TAG) /* Is ending? */
+ /* Is ending? */
+ if ((cpu_to_le32(*(u32 *)pRxBufferAddress) & 0x0fffffff) ==
+ RX_END_TAG)
break;
/* Get the R00 R01 first */
@@ -108,7 +112,8 @@ static u16 Wb35Rx_indicate(struct ieee80211_hw *hw)
/* Basic check for Rx length. Is length valid? */
if (PacketSize > MAX_PACKET_SIZE) {
- pr_debug("Serious ERROR : Rx data size too long, size =%d\n", PacketSize);
+ pr_debug("Serious ERROR : Rx data size too long, size =%d\n",
+ PacketSize);
pWb35Rx->EP3vm_state = VM_STOP;
pWb35Rx->Ep3ErrorCount2++;
break;
@@ -118,7 +123,8 @@ static u16 Wb35Rx_indicate(struct ieee80211_hw *hw)
* Wb35Rx_indicate() is called synchronously so it isn't
* necessary to set "RxDes.Desctriptor_ID = RxBufferID;"
*/
- BufferSize -= 8; /* subtract 8 byte for 35's USB header length */
+ /* subtract 8 byte for 35's USB header length */
+ BufferSize -= 8;
pRxBufferAddress += 8;
RxDes.buffer_address[0] = pRxBufferAddress;
@@ -255,7 +261,7 @@ static void Wb35Rx(struct ieee80211_hw *hw)
pWb35Rx->pDRx = kzalloc(MAX_USB_RX_BUFFER, GFP_ATOMIC);
if (!pWb35Rx->pDRx) {
- printk("w35und: Rx memory alloc failed\n");
+ dev_info(&hw->wiphy->dev, "w35und: Rx memory alloc failed\n");
goto error;
}
pRxBufferAddress = pWb35Rx->pDRx;
@@ -270,7 +276,7 @@ static void Wb35Rx(struct ieee80211_hw *hw)
retv = usb_submit_urb(urb, GFP_ATOMIC);
if (retv != 0) {
- printk("Rx URB sending error\n");
+ dev_info(&hw->wiphy->dev, "Rx URB sending error\n");
goto error;
}
return;
@@ -306,7 +312,9 @@ static void Wb35Rx_reset_descriptor(struct hw_data *pHwData)
pWb35Rx->EP3vm_state = VM_STOP;
pWb35Rx->rx_halt = 0;
- /* Initial the Queue. The last buffer is reserved for used if the Rx resource is unavailable. */
+ /* Initial the Queue. The last buffer is reserved for used
+ * if the Rx resource is unavailable.
+ */
for (i = 0; i < MAX_USB_RX_BUFFER_NUMBER; i++)
pWb35Rx->RxOwner[i] = 1;
}
@@ -328,7 +336,8 @@ void Wb35Rx_stop(struct hw_data *pHwData)
/* Canceling the Irp if already sends it out. */
if (pWb35Rx->EP3vm_state == VM_RUNNING) {
- usb_unlink_urb(pWb35Rx->RxUrb); /* Only use unlink, let Wb35Rx_destroy to free them */
+ /* Only use unlink, let Wb35Rx_destroy to free them */
+ usb_unlink_urb(pWb35Rx->RxUrb);
pr_debug("EP3 Rx stop\n");
}
}
diff --git a/drivers/staging/wlags49_h2/dhf.c b/drivers/staging/wlags49_h2/dhf.c
index 13d360fa58ec..4877464f04b0 100644
--- a/drivers/staging/wlags49_h2/dhf.c
+++ b/drivers/staging/wlags49_h2/dhf.c
@@ -106,7 +106,7 @@
*---------------------------------------------------------------------------*/
/* 12345678901234 */
-char signature[14] = "FUPU7D37dhfwci";
+static char signature[14] = "FUPU7D37dhfwci";
/*-----------------------------------------------------------------------------
*
@@ -123,8 +123,8 @@ char signature[14] = "FUPU7D37dhfwci";
#define DL_SIZE 2000
/* CFG_IDENTITY_STRCT pri_identity = { LOF(CFG_IDENTITY_STRCT), CFG_PRI_IDENTITY }; */
-CFG_SUP_RANGE_STRCT mfi_sup = { LOF(CFG_SUP_RANGE_STRCT), CFG_NIC_MFI_SUP_RANGE };
-CFG_SUP_RANGE_STRCT cfi_sup = { LOF(CFG_SUP_RANGE_STRCT), CFG_NIC_CFI_SUP_RANGE };
+static CFG_SUP_RANGE_STRCT mfi_sup = { LOF(CFG_SUP_RANGE_STRCT), CFG_NIC_MFI_SUP_RANGE };
+static CFG_SUP_RANGE_STRCT cfi_sup = { LOF(CFG_SUP_RANGE_STRCT), CFG_NIC_CFI_SUP_RANGE };
/* Note: could be used rather than the above explained and defined DL_SIZE if need arises
* CFG_DL_BUF_STRCT dl_buf = { LOF(CFG_DL_BUF_STRCT), CFG_DL_BUF };
*/
@@ -139,7 +139,7 @@ CFG_SUP_RANGE_STRCT cfi_sup = { LOF(CFG_SUP_RANGE_STRCT), CFG_NIC_CFI_S
* This is only relevant if the DHF used without reloading the driver/utility.
*/
-LTV_INFO_STRUCT ltv_info[] = {
+static LTV_INFO_STRUCT ltv_info[] = {
{ (LTVP)&mfi_sup, LOF(CFG_SUP_RANGE_STRCT) } ,
{ (LTVP)&cfi_sup, LOF(CFG_SUP_RANGE_STRCT) } ,
{ (LTVP) NULL, 0 }
@@ -169,7 +169,7 @@ static int check_comp_fw(memimage *fw);
* station firmware image to be downloaded is compatible.
*.ENDDOC END DOCUMENTATION
*************************************************************************************************************/
-int
+static int
check_comp_fw(memimage *fw)
{
CFG_RANGE20_STRCT *p;
diff --git a/drivers/staging/wlags49_h2/hcf.c b/drivers/staging/wlags49_h2/hcf.c
index 4aac26d486f1..f44d888ecd6e 100644
--- a/drivers/staging/wlags49_h2/hcf.c
+++ b/drivers/staging/wlags49_h2/hcf.c
@@ -250,7 +250,7 @@ HCF_STATIC hcf_8 BASED mic_pad[8] = { 0x5A, 0, 0, 0, 0, 0, 0, 0 }; //MIC pa
#endif // HCF_TYPE_WPA
#if defined MSF_COMPONENT_ID
-CFG_IDENTITY_STRCT BASED cfg_drv_identity = {
+static CFG_IDENTITY_STRCT BASED cfg_drv_identity = {
sizeof(cfg_drv_identity)/sizeof(hcf_16) - 1, //length of RID
CFG_DRV_IDENTITY, // (0x0826)
MSF_COMPONENT_ID,
@@ -259,7 +259,7 @@ CFG_IDENTITY_STRCT BASED cfg_drv_identity = {
MSF_COMPONENT_MINOR_VER
} ;
-CFG_RANGES_STRCT BASED cfg_drv_sup_range = {
+static CFG_RANGES_STRCT BASED cfg_drv_sup_range = {
sizeof(cfg_drv_sup_range)/sizeof(hcf_16) - 1, //length of RID
CFG_DRV_SUP_RANGE, // (0x0827)
@@ -271,7 +271,7 @@ CFG_RANGES_STRCT BASED cfg_drv_sup_range = {
}}
} ;
-struct CFG_RANGE3_STRCT BASED cfg_drv_act_ranges_pri = {
+static struct CFG_RANGE3_STRCT BASED cfg_drv_act_ranges_pri = {
sizeof(cfg_drv_act_ranges_pri)/sizeof(hcf_16) - 1, //length of RID
CFG_DRV_ACT_RANGES_PRI, // (0x0828)
@@ -288,7 +288,7 @@ struct CFG_RANGE3_STRCT BASED cfg_drv_act_ranges_pri = {
} ;
-struct CFG_RANGE4_STRCT BASED cfg_drv_act_ranges_sta = {
+static struct CFG_RANGE4_STRCT BASED cfg_drv_act_ranges_sta = {
sizeof(cfg_drv_act_ranges_sta)/sizeof(hcf_16) - 1, //length of RID
CFG_DRV_ACT_RANGES_STA, // (0x0829)
@@ -333,7 +333,7 @@ struct CFG_RANGE4_STRCT BASED cfg_drv_act_ranges_sta = {
} ;
-struct CFG_RANGE6_STRCT BASED cfg_drv_act_ranges_hsi = {
+static struct CFG_RANGE6_STRCT BASED cfg_drv_act_ranges_hsi = {
sizeof(cfg_drv_act_ranges_hsi)/sizeof(hcf_16) - 1, //length of RID
CFG_DRV_ACT_RANGES_HSI, // (0x082A)
COMP_ROLE_ACT,
@@ -370,7 +370,7 @@ struct CFG_RANGE6_STRCT BASED cfg_drv_act_ranges_hsi = {
} ;
-CFG_RANGE4_STRCT BASED cfg_drv_act_ranges_apf = {
+static CFG_RANGE4_STRCT BASED cfg_drv_act_ranges_apf = {
sizeof(cfg_drv_act_ranges_apf)/sizeof(hcf_16) - 1, //length of RID
CFG_DRV_ACT_RANGES_APF, // (0x082B)
@@ -3099,7 +3099,7 @@ hcf_service_nic( IFBP ifbp, wci_bufp bufp, unsigned int len )
#define L *p
#define R *(p+1)
-void
+static void
calc_mic( hcf_32* p, hcf_32 m )
{
#if HCF_BIG_ENDIAN
@@ -3415,7 +3415,7 @@ calibrate( IFBP ifbp )
*.ENDDOC END DOCUMENTATION
*
************************************************************************************************************/
-int
+static int
check_mic( IFBP ifbp )
{
int rc = HCF_SUCCESS;
diff --git a/drivers/staging/wlags49_h2/sta_h2.c b/drivers/staging/wlags49_h2/sta_h2.c
index 25ac76f7d366..0ba8defc023a 100644
--- a/drivers/staging/wlags49_h2/sta_h2.c
+++ b/drivers/staging/wlags49_h2/sta_h2.c
@@ -4435,7 +4435,7 @@ static const CFG_PROG_STRCT fw_image_code[] = {
0000,
0x000F368E, /* Start execution address */
},
- { 0000, 0000, 0000, 0000, 00000000, 0000, 00000000}
+ { 0000, 0000, 0000, 0000, 00000000, 0000, NULL}
};
static const CFG_RANGE20_STRCT fw_image_infocompat[] = {
diff --git a/drivers/staging/wlags49_h2/wl_main.c b/drivers/staging/wlags49_h2/wl_main.c
index 650def88e5c2..fc98b6dbdb89 100644
--- a/drivers/staging/wlags49_h2/wl_main.c
+++ b/drivers/staging/wlags49_h2/wl_main.c
@@ -76,38 +76,23 @@
#include <linux/seq_file.h>
#include <linux/types.h>
#include <linux/kernel.h>
-// #include <linux/sched.h>
-// #include <linux/ptrace.h>
-// #include <linux/slab.h>
-// #include <linux/ctype.h>
-// #include <linux/string.h>
-// #include <linux/timer.h>
-//#include <linux/interrupt.h>
-// #include <linux/tqueue.h>
-// #include <linux/in.h>
-// #include <linux/delay.h>
-// #include <asm/io.h>
-// // #include <asm/bitops.h>
#include <linux/unistd.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-// #include <linux/skbuff.h>
-// #include <linux/if_arp.h>
-// #include <linux/ioport.h>
#define BIN_DL 0
#if BIN_DL
#include <linux/vmalloc.h>
-#endif // BIN_DL
+#endif /* BIN_DL */
#include <debug.h>
#include <hcf.h>
#include <dhf.h>
-//in order to get around:: wl_main.c:2229: `HREG_EV_RDMAD' undeclared (first use in this function)
+/* in order to get around:: wl_main.c:2229: `HREG_EV_RDMAD' undeclared (first use in this function) */
#include <hcfdef.h>
#include <wl_if.h>
@@ -133,8 +118,7 @@
******************************************************************************/
#define VALID_PARAM(C) \
{ \
- if (!(C)) \
- { \
+ if (!(C)) { \
printk(KERN_INFO "Wireless, parameter error: \"%s\"\n", #C); \
goto failed; \
} \
@@ -142,7 +126,7 @@
/*******************************************************************************
* local functions
******************************************************************************/
-void wl_isr_handler( unsigned long p );
+void wl_isr_handler(unsigned long p);
#if 0 //SCULL_USE_PROC /* don't waste space if unused */
static int scull_read_procmem(struct seq_file *m, void *v);
@@ -168,7 +152,7 @@ static const struct file_operations scull_read_procmem_fops = {
/*******************************************************************************
* module parameter definitions - set with 'insmod'
******************************************************************************/
-static p_u16 irq_mask = 0xdeb8; // IRQ3,4,5,7,9,10,11,12,14,15
+static p_u16 irq_mask = 0xdeb8; /* IRQ3,4,5,7,9,10,11,12,14,15 */
static p_s8 irq_list[4] = { -1 };
#if 0
@@ -183,7 +167,7 @@ static p_u16 PARM_AUTH_KEY_MGMT_SUITE = PARM_DEFAULT_AUTH_KEY_MGMT_SUITE;
static p_u16 PARM_BRSC_2GHZ = PARM_DEFAULT_BRSC_2GHZ;
static p_u16 PARM_BRSC_5GHZ = PARM_DEFAULT_BRSC_5GHZ;
static p_u16 PARM_COEXISTENCE = PARM_DEFAULT_COEXISTENCE;
-static p_u16 PARM_CONNECTION_CONTROL = PARM_DEFAULT_CONNECTION_CONTROL; //;?rename and move
+static p_u16 PARM_CONNECTION_CONTROL = PARM_DEFAULT_CONNECTION_CONTROL; /* ;?rename and move */
static p_char *PARM_CREATE_IBSS = PARM_DEFAULT_CREATE_IBSS_STR;
static p_char *PARM_DESIRED_SSID = PARM_DEFAULT_SSID;
static p_char *PARM_DOWNLOAD_FIRMWARE = "";
@@ -220,7 +204,7 @@ static p_u16 PARM_RTS_THRESHOLD3 = PARM_DEFAULT_RTS_THRESHOLD;
static p_u16 PARM_RTS_THRESHOLD4 = PARM_DEFAULT_RTS_THRESHOLD;
static p_u16 PARM_RTS_THRESHOLD5 = PARM_DEFAULT_RTS_THRESHOLD;
static p_u16 PARM_RTS_THRESHOLD6 = PARM_DEFAULT_RTS_THRESHOLD;
-#endif // USE_WDS
+#endif /* USE_WDS */
static p_u16 PARM_RTS_THRESHOLD = PARM_DEFAULT_RTS_THRESHOLD;
static p_u16 PARM_SRSC_2GHZ = PARM_DEFAULT_SRSC_2GHZ;
static p_u16 PARM_SRSC_5GHZ = PARM_DEFAULT_SRSC_5GHZ;
@@ -234,7 +218,7 @@ static p_u16 PARM_TX_RATE3 = PARM_DEFAULT_TX_RATE_2GHZ;
static p_u16 PARM_TX_RATE4 = PARM_DEFAULT_TX_RATE_2GHZ;
static p_u16 PARM_TX_RATE5 = PARM_DEFAULT_TX_RATE_2GHZ;
static p_u16 PARM_TX_RATE6 = PARM_DEFAULT_TX_RATE_2GHZ;
-#endif // USE_WDS
+#endif /* USE_WDS */
static p_u16 PARM_TX_RATE = PARM_DEFAULT_TX_RATE_2GHZ;
#ifdef USE_WDS
static p_u8 PARM_WDS_ADDRESS1[ETH_ALEN] = PARM_DEFAULT_NETWORK_ADDR;
@@ -243,7 +227,7 @@ static p_u8 PARM_WDS_ADDRESS3[ETH_ALEN] = PARM_DEFAULT_NETWORK_ADDR;
static p_u8 PARM_WDS_ADDRESS4[ETH_ALEN] = PARM_DEFAULT_NETWORK_ADDR;
static p_u8 PARM_WDS_ADDRESS5[ETH_ALEN] = PARM_DEFAULT_NETWORK_ADDR;
static p_u8 PARM_WDS_ADDRESS6[ETH_ALEN] = PARM_DEFAULT_NETWORK_ADDR;
-#endif // USE_WDS
+#endif /* USE_WDS */
#if 0
@@ -299,39 +283,41 @@ MODULE_PARM(PARM_BRSC_2GHZ, "b");
MODULE_PARM_DESC(PARM_BRSC_2GHZ, "Basic Rate Set Control 2.4 GHz");
MODULE_PARM(PARM_BRSC_5GHZ, "b");
MODULE_PARM_DESC(PARM_BRSC_5GHZ, "Basic Rate Set Control 5.0 GHz");
-#if 1 //;? (HCF_TYPE) & HCF_TYPE_STA
-//;?seems reasonable that even an AP-only driver could afford this small additional footprint
+#if 1 /* (HCF_TYPE) & HCF_TYPE_STA */
+/* ;?seems reasonable that even an AP-only driver could afford this small additional footprint */
MODULE_PARM(PARM_PM_ENABLED, "h");
MODULE_PARM_DESC(PARM_PM_ENABLED, "Power Management State (0 - 2, 8001 - 8002) [0]");
MODULE_PARM(PARM_PORT_TYPE, "b");
MODULE_PARM_DESC(PARM_PORT_TYPE, "Port Type (1 - 3) [1]");
-//;?MODULE_PARM(PARM_CREATE_IBSS, "s");
-//;?MODULE_PARM_DESC(PARM_CREATE_IBSS, "Create IBSS (<string> N or Y) [N]");
-//;?MODULE_PARM(PARM_MULTICAST_RX, "s");
-//;?MODULE_PARM_DESC(PARM_MULTICAST_RX, "Multicast Receive Enable (<string> N or Y) [Y]");
-//;?MODULE_PARM(PARM_MAX_SLEEP, "h");
-//;?MODULE_PARM_DESC(PARM_MAX_SLEEP, "Maximum Power Management Sleep Duration (0 - 65535) [100]");
-//;?MODULE_PARM(PARM_NETWORK_ADDR, "6b");
-//;?MODULE_PARM_DESC(PARM_NETWORK_ADDR, "Hardware Ethernet Address ([0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff]) [<factory value>]");
-//;?MODULE_PARM(PARM_AUTHENTICATION, "b");
-//
-//tracker 12448
-//;?MODULE_PARM_DESC(PARM_AUTHENTICATION, "Authentication Type (0-2) [0] 0=Open 1=SharedKey 2=LEAP");
-//;?MODULE_PARM_DESC(authentication, "Authentication Type (1-2) [1] 1=Open 2=SharedKey");
-//tracker 12448
-//
-//;?MODULE_PARM(PARM_OWN_ATIM_WINDOW, "b");
-//;?MODULE_PARM_DESC(PARM_OWN_ATIM_WINDOW, "ATIM Window time in TU for IBSS creation (0-100) [0]");
-//;?MODULE_PARM(PARM_PM_HOLDOVER_DURATION, "b");
-//;?MODULE_PARM_DESC(PARM_PM_HOLDOVER_DURATION, "Time station remains awake after MAC frame transfer when PM is on (0-65535) [100]");
-//;?MODULE_PARM(PARM_PROMISCUOUS_MODE, "s");
-//;?MODULE_PARM_DESC(PARM_PROMISCUOUS_MODE, "Promiscuous Mode Enable (<string> Y or N ) [N]" );
-//;?
+/*
+ * ;?MODULE_PARM(PARM_CREATE_IBSS, "s");
+ *;?MODULE_PARM_DESC(PARM_CREATE_IBSS, "Create IBSS (<string> N or Y) [N]");
+ *;?MODULE_PARM(PARM_MULTICAST_RX, "s");
+ *;?MODULE_PARM_DESC(PARM_MULTICAST_RX, "Multicast Receive Enable (<string> N or Y) [Y]");
+ *;?MODULE_PARM(PARM_MAX_SLEEP, "h");
+ *;?MODULE_PARM_DESC(PARM_MAX_SLEEP, "Maximum Power Management Sleep Duration (0 - 65535) [100]");
+ *;?MODULE_PARM(PARM_NETWORK_ADDR, "6b");
+ *;?MODULE_PARM_DESC(PARM_NETWORK_ADDR, "Hardware Ethernet Address ([0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff],[0x00-0xff]) [<factory value>]");
+ *;?MODULE_PARM(PARM_AUTHENTICATION, "b");
+ *
+ *tracker 12448
+ *;?MODULE_PARM_DESC(PARM_AUTHENTICATION, "Authentication Type (0-2) [0] 0=Open 1=SharedKey 2=LEAP");
+ *;?MODULE_PARM_DESC(authentication, "Authentication Type (1-2) [1] 1=Open 2=SharedKey");
+ *tracker 12448
+ *
+ *;?MODULE_PARM(PARM_OWN_ATIM_WINDOW, "b");
+ *;?MODULE_PARM_DESC(PARM_OWN_ATIM_WINDOW, "ATIM Window time in TU for IBSS creation (0-100) [0]");
+ *;?MODULE_PARM(PARM_PM_HOLDOVER_DURATION, "b");
+ *;?MODULE_PARM_DESC(PARM_PM_HOLDOVER_DURATION, "Time station remains awake after MAC frame transfer when PM is on (0-65535) [100]");
+ *;?MODULE_PARM(PARM_PROMISCUOUS_MODE, "s");
+ *;?MODULE_PARM_DESC(PARM_PROMISCUOUS_MODE, "Promiscuous Mode Enable (<string> Y or N ) [N]" );
+ *;?
+ */
MODULE_PARM(PARM_CONNECTION_CONTROL, "b");
MODULE_PARM_DESC(PARM_CONNECTION_CONTROL, "Connection Control (0 - 3) [2]");
#endif /* HCF_STA */
-#if 1 //;? (HCF_TYPE) & HCF_TYPE_AP
- //;?should we restore this to allow smaller memory footprint
+#if 1 /* ;? (HCF_TYPE) & HCF_TYPE_AP */
+ /* ;?should we restore this to allow smaller memory footprint */
MODULE_PARM(PARM_OWN_DTIM_PERIOD, "b");
MODULE_PARM_DESC(PARM_OWN_DTIM_PERIOD, "DTIM Period (0 - 255) [1]");
MODULE_PARM(PARM_REJECT_ANY, "s");
@@ -394,11 +380,12 @@ MODULE_PARM_DESC(PARM_COEXISTENCE, "Coexistence (0-7) [0]");
#if DBG
static p_u32 pc_debug = DBG_LVL;
-//MODULE_PARM(pc_debug, "i");
-/*static ;?conflicts with my understanding of CL parameters and breaks now I moved
+/*
+ * MODULE_PARM(pc_debug, "i");
+ *static ;?conflicts with my understanding of CL parameters and breaks now I moved
* the correspondig logic to wl_profile
- */ p_u32 DebugFlag = ~0; //recognizable "undefined value" rather then DBG_DEFAULTS;
-//MODULE_PARM(DebugFlag, "l");
+ */ p_u32 DebugFlag = ~0; /* recognizable "undefined value" rather then DBG_DEFAULTS; */
+/* MODULE_PARM(DebugFlag, "l"); */
static struct dbg_info wl_info = { KBUILD_MODNAME, 0, 0 };
struct dbg_info *DbgInfo = &wl_info;
@@ -407,8 +394,8 @@ struct dbg_info *DbgInfo = &wl_info;
#ifdef USE_RTS
static p_char *useRTS = "N";
-MODULE_PARM( useRTS, "s" );
-MODULE_PARM_DESC( useRTS, "Use RTS test interface (<string> N or Y) [N]" );
+MODULE_PARM(useRTS, "s");
+MODULE_PARM_DESC(useRTS, "Use RTS test interface (<string> N or Y) [N]");
#endif /* USE_RTS */
/*******************************************************************************
@@ -427,7 +414,7 @@ extern memimage fw_image; // firmware image to be downloaded
#endif /* HCF_STA */
-int wl_insert( struct net_device *dev )
+int wl_insert(struct net_device *dev)
{
int result = 0;
int hcf_status = HCF_SUCCESS;
@@ -436,10 +423,10 @@ int wl_insert( struct net_device *dev )
struct wl_private *lp = wl_priv(dev);
/* Initialize the adapter hardware. */
- memset( &( lp->hcfCtx ), 0, sizeof( IFB_STRCT ));
+ memset(&(lp->hcfCtx), 0, sizeof(IFB_STRCT));
/* Initialize the adapter parameters. */
- spin_lock_init( &( lp->slock ));
+ spin_lock_init(&(lp->slock));
/* Initialize states */
//lp->lockcount = 0; //PE1DNN
@@ -448,31 +435,31 @@ int wl_insert( struct net_device *dev )
lp->dev = dev;
- DBG_PARAM( DbgInfo, "irq_mask", "0x%04x", irq_mask & 0x0FFFF );
- DBG_PARAM( DbgInfo, "irq_list", "0x%02x 0x%02x 0x%02x 0x%02x",
+ DBG_PARAM(DbgInfo, "irq_mask", "0x%04x", irq_mask & 0x0FFFF);
+ DBG_PARAM(DbgInfo, "irq_list", "0x%02x 0x%02x 0x%02x 0x%02x",
irq_list[0] & 0x0FF, irq_list[1] & 0x0FF,
- irq_list[2] & 0x0FF, irq_list[3] & 0x0FF );
- DBG_PARAM( DbgInfo, PARM_NAME_DESIRED_SSID, "\"%s\"", PARM_DESIRED_SSID );
- DBG_PARAM( DbgInfo, PARM_NAME_OWN_SSID, "\"%s\"", PARM_OWN_SSID );
- DBG_PARAM( DbgInfo, PARM_NAME_OWN_CHANNEL, "%d", PARM_OWN_CHANNEL);
- DBG_PARAM( DbgInfo, PARM_NAME_SYSTEM_SCALE, "%d", PARM_SYSTEM_SCALE );
- DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE, "%d", PARM_TX_RATE );
- DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD, "%d", PARM_RTS_THRESHOLD );
- DBG_PARAM( DbgInfo, PARM_NAME_MICROWAVE_ROBUSTNESS, "\"%s\"", PARM_MICROWAVE_ROBUSTNESS );
- DBG_PARAM( DbgInfo, PARM_NAME_OWN_NAME, "\"%s\"", PARM_OWN_NAME );
+ irq_list[2] & 0x0FF, irq_list[3] & 0x0FF);
+ DBG_PARAM(DbgInfo, PARM_NAME_DESIRED_SSID, "\"%s\"", PARM_DESIRED_SSID);
+ DBG_PARAM(DbgInfo, PARM_NAME_OWN_SSID, "\"%s\"", PARM_OWN_SSID);
+ DBG_PARAM(DbgInfo, PARM_NAME_OWN_CHANNEL, "%d", PARM_OWN_CHANNEL);
+ DBG_PARAM(DbgInfo, PARM_NAME_SYSTEM_SCALE, "%d", PARM_SYSTEM_SCALE);
+ DBG_PARAM(DbgInfo, PARM_NAME_TX_RATE, "%d", PARM_TX_RATE);
+ DBG_PARAM(DbgInfo, PARM_NAME_RTS_THRESHOLD, "%d", PARM_RTS_THRESHOLD);
+ DBG_PARAM(DbgInfo, PARM_NAME_MICROWAVE_ROBUSTNESS, "\"%s\"", PARM_MICROWAVE_ROBUSTNESS);
+ DBG_PARAM(DbgInfo, PARM_NAME_OWN_NAME, "\"%s\"", PARM_OWN_NAME);
//;? DBG_PARAM( DbgInfo, PARM_NAME_ENABLE_ENCRYPTION, "\"%s\"", PARM_ENABLE_ENCRYPTION );
- DBG_PARAM( DbgInfo, PARM_NAME_KEY1, "\"%s\"", PARM_KEY1 );
- DBG_PARAM( DbgInfo, PARM_NAME_KEY2, "\"%s\"", PARM_KEY2 );
- DBG_PARAM( DbgInfo, PARM_NAME_KEY3, "\"%s\"", PARM_KEY3 );
- DBG_PARAM( DbgInfo, PARM_NAME_KEY4, "\"%s\"", PARM_KEY4 );
- DBG_PARAM( DbgInfo, PARM_NAME_TX_KEY, "%d", PARM_TX_KEY );
- DBG_PARAM( DbgInfo, PARM_NAME_MULTICAST_RATE, "%d", PARM_MULTICAST_RATE );
- DBG_PARAM( DbgInfo, PARM_NAME_DOWNLOAD_FIRMWARE, "\"%s\"", PARM_DOWNLOAD_FIRMWARE );
- DBG_PARAM( DbgInfo, PARM_NAME_AUTH_KEY_MGMT_SUITE, "%d", PARM_AUTH_KEY_MGMT_SUITE );
+ DBG_PARAM(DbgInfo, PARM_NAME_KEY1, "\"%s\"", PARM_KEY1);
+ DBG_PARAM(DbgInfo, PARM_NAME_KEY2, "\"%s\"", PARM_KEY2);
+ DBG_PARAM(DbgInfo, PARM_NAME_KEY3, "\"%s\"", PARM_KEY3);
+ DBG_PARAM(DbgInfo, PARM_NAME_KEY4, "\"%s\"", PARM_KEY4);
+ DBG_PARAM(DbgInfo, PARM_NAME_TX_KEY, "%d", PARM_TX_KEY);
+ DBG_PARAM(DbgInfo, PARM_NAME_MULTICAST_RATE, "%d", PARM_MULTICAST_RATE);
+ DBG_PARAM(DbgInfo, PARM_NAME_DOWNLOAD_FIRMWARE, "\"%s\"", PARM_DOWNLOAD_FIRMWARE);
+ DBG_PARAM(DbgInfo, PARM_NAME_AUTH_KEY_MGMT_SUITE, "%d", PARM_AUTH_KEY_MGMT_SUITE);
//;?#if (HCF_TYPE) & HCF_TYPE_STA
//;?should we make this code conditional depending on in STA mode
//;? DBG_PARAM( DbgInfo, PARM_NAME_PORT_TYPE, "%d", PARM_PORT_TYPE );
- DBG_PARAM( DbgInfo, PARM_NAME_PM_ENABLED, "%04x", PARM_PM_ENABLED );
+ DBG_PARAM(DbgInfo, PARM_NAME_PM_ENABLED, "%04x", PARM_PM_ENABLED);
//;? DBG_PARAM( DbgInfo, PARM_NAME_CREATE_IBSS, "\"%s\"", PARM_CREATE_IBSS );
//;? DBG_PARAM( DbgInfo, PARM_NAME_MULTICAST_RX, "\"%s\"", PARM_MULTICAST_RX );
//;? DBG_PARAM( DbgInfo, PARM_NAME_MAX_SLEEP, "%d", PARM_MAX_SLEEP );
@@ -488,24 +475,24 @@ int wl_insert( struct net_device *dev )
#if 1 //;? (HCF_TYPE) & HCF_TYPE_AP
//;?should we restore this to allow smaller memory footprint
//;?I guess: no, since this is Debug mode only
- DBG_PARAM( DbgInfo, PARM_NAME_OWN_DTIM_PERIOD, "%d", PARM_OWN_DTIM_PERIOD );
- DBG_PARAM( DbgInfo, PARM_NAME_REJECT_ANY, "\"%s\"", PARM_REJECT_ANY );
- DBG_PARAM( DbgInfo, PARM_NAME_EXCLUDE_UNENCRYPTED, "\"%s\"", PARM_EXCLUDE_UNENCRYPTED );
- DBG_PARAM( DbgInfo, PARM_NAME_MULTICAST_PM_BUFFERING, "\"%s\"", PARM_MULTICAST_PM_BUFFERING );
- DBG_PARAM( DbgInfo, PARM_NAME_INTRA_BSS_RELAY, "\"%s\"", PARM_INTRA_BSS_RELAY );
+ DBG_PARAM(DbgInfo, PARM_NAME_OWN_DTIM_PERIOD, "%d", PARM_OWN_DTIM_PERIOD);
+ DBG_PARAM(DbgInfo, PARM_NAME_REJECT_ANY, "\"%s\"", PARM_REJECT_ANY);
+ DBG_PARAM(DbgInfo, PARM_NAME_EXCLUDE_UNENCRYPTED, "\"%s\"", PARM_EXCLUDE_UNENCRYPTED);
+ DBG_PARAM(DbgInfo, PARM_NAME_MULTICAST_PM_BUFFERING, "\"%s\"", PARM_MULTICAST_PM_BUFFERING);
+ DBG_PARAM(DbgInfo, PARM_NAME_INTRA_BSS_RELAY, "\"%s\"", PARM_INTRA_BSS_RELAY);
#ifdef USE_WDS
- DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD1, "%d", PARM_RTS_THRESHOLD1 );
- DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD2, "%d", PARM_RTS_THRESHOLD2 );
- DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD3, "%d", PARM_RTS_THRESHOLD3 );
- DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD4, "%d", PARM_RTS_THRESHOLD4 );
- DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD5, "%d", PARM_RTS_THRESHOLD5 );
- DBG_PARAM( DbgInfo, PARM_NAME_RTS_THRESHOLD6, "%d", PARM_RTS_THRESHOLD6 );
- DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE1, "%d", PARM_TX_RATE1 );
- DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE2, "%d", PARM_TX_RATE2 );
- DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE3, "%d", PARM_TX_RATE3 );
- DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE4, "%d", PARM_TX_RATE4 );
- DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE5, "%d", PARM_TX_RATE5 );
- DBG_PARAM( DbgInfo, PARM_NAME_TX_RATE6, "%d", PARM_TX_RATE6 );
+ DBG_PARAM(DbgInfo, PARM_NAME_RTS_THRESHOLD1, "%d", PARM_RTS_THRESHOLD1);
+ DBG_PARAM(DbgInfo, PARM_NAME_RTS_THRESHOLD2, "%d", PARM_RTS_THRESHOLD2);
+ DBG_PARAM(DbgInfo, PARM_NAME_RTS_THRESHOLD3, "%d", PARM_RTS_THRESHOLD3);
+ DBG_PARAM(DbgInfo, PARM_NAME_RTS_THRESHOLD4, "%d", PARM_RTS_THRESHOLD4);
+ DBG_PARAM(DbgInfo, PARM_NAME_RTS_THRESHOLD5, "%d", PARM_RTS_THRESHOLD5);
+ DBG_PARAM(DbgInfo, PARM_NAME_RTS_THRESHOLD6, "%d", PARM_RTS_THRESHOLD6);
+ DBG_PARAM(DbgInfo, PARM_NAME_TX_RATE1, "%d", PARM_TX_RATE1);
+ DBG_PARAM(DbgInfo, PARM_NAME_TX_RATE2, "%d", PARM_TX_RATE2);
+ DBG_PARAM(DbgInfo, PARM_NAME_TX_RATE3, "%d", PARM_TX_RATE3);
+ DBG_PARAM(DbgInfo, PARM_NAME_TX_RATE4, "%d", PARM_TX_RATE4);
+ DBG_PARAM(DbgInfo, PARM_NAME_TX_RATE5, "%d", PARM_TX_RATE5);
+ DBG_PARAM(DbgInfo, PARM_NAME_TX_RATE6, "%d", PARM_TX_RATE6);
DBG_PARAM(DbgInfo, PARM_NAME_WDS_ADDRESS1, "\"%pM\"",
PARM_WDS_ADDRESS1);
DBG_PARAM(DbgInfo, PARM_NAME_WDS_ADDRESS2, "\"%pM\"",
@@ -521,28 +508,28 @@ int wl_insert( struct net_device *dev )
#endif /* USE_WDS */
#endif /* HCF_AP */
- VALID_PARAM( !PARM_DESIRED_SSID || ( strlen( PARM_DESIRED_SSID ) <= PARM_MAX_NAME_LEN ));
- VALID_PARAM( !PARM_OWN_SSID || ( strlen( PARM_OWN_SSID ) <= PARM_MAX_NAME_LEN ));
- VALID_PARAM(( PARM_OWN_CHANNEL <= PARM_MAX_OWN_CHANNEL ));
- VALID_PARAM(( PARM_SYSTEM_SCALE >= PARM_MIN_SYSTEM_SCALE ) && ( PARM_SYSTEM_SCALE <= PARM_MAX_SYSTEM_SCALE ));
- VALID_PARAM(( PARM_TX_RATE >= PARM_MIN_TX_RATE ) && ( PARM_TX_RATE <= PARM_MAX_TX_RATE ));
- VALID_PARAM(( PARM_RTS_THRESHOLD <= PARM_MAX_RTS_THRESHOLD ));
- VALID_PARAM( !PARM_MICROWAVE_ROBUSTNESS || strchr( "NnYy", PARM_MICROWAVE_ROBUSTNESS[0] ) != NULL );
- VALID_PARAM( !PARM_OWN_NAME || ( strlen( PARM_NAME_OWN_NAME ) <= PARM_MAX_NAME_LEN ));
- VALID_PARAM(( PARM_ENABLE_ENCRYPTION <= PARM_MAX_ENABLE_ENCRYPTION ));
- VALID_PARAM( is_valid_key_string( PARM_KEY1 ));
- VALID_PARAM( is_valid_key_string( PARM_KEY2 ));
- VALID_PARAM( is_valid_key_string( PARM_KEY3 ));
- VALID_PARAM( is_valid_key_string( PARM_KEY4 ));
- VALID_PARAM(( PARM_TX_KEY >= PARM_MIN_TX_KEY ) && ( PARM_TX_KEY <= PARM_MAX_TX_KEY ));
-
- VALID_PARAM(( PARM_MULTICAST_RATE >= PARM_MIN_MULTICAST_RATE ) &&
- ( PARM_MULTICAST_RATE <= PARM_MAX_MULTICAST_RATE ));
-
- VALID_PARAM( !PARM_DOWNLOAD_FIRMWARE || ( strlen( PARM_DOWNLOAD_FIRMWARE ) <= 255 /*;?*/ ));
- VALID_PARAM(( PARM_AUTH_KEY_MGMT_SUITE < PARM_MAX_AUTH_KEY_MGMT_SUITE ));
-
- VALID_PARAM( !PARM_LOAD_BALANCING || strchr( "NnYy", PARM_LOAD_BALANCING[0] ) != NULL );
+ VALID_PARAM(!PARM_DESIRED_SSID || (strlen(PARM_DESIRED_SSID) <= PARM_MAX_NAME_LEN));
+ VALID_PARAM(!PARM_OWN_SSID || (strlen(PARM_OWN_SSID) <= PARM_MAX_NAME_LEN));
+ VALID_PARAM((PARM_OWN_CHANNEL <= PARM_MAX_OWN_CHANNEL));
+ VALID_PARAM((PARM_SYSTEM_SCALE >= PARM_MIN_SYSTEM_SCALE) && (PARM_SYSTEM_SCALE <= PARM_MAX_SYSTEM_SCALE));
+ VALID_PARAM((PARM_TX_RATE >= PARM_MIN_TX_RATE) && (PARM_TX_RATE <= PARM_MAX_TX_RATE));
+ VALID_PARAM((PARM_RTS_THRESHOLD <= PARM_MAX_RTS_THRESHOLD));
+ VALID_PARAM(!PARM_MICROWAVE_ROBUSTNESS || strchr("NnYy", PARM_MICROWAVE_ROBUSTNESS[0]) != NULL);
+ VALID_PARAM(!PARM_OWN_NAME || (strlen(PARM_NAME_OWN_NAME) <= PARM_MAX_NAME_LEN));
+ VALID_PARAM((PARM_ENABLE_ENCRYPTION <= PARM_MAX_ENABLE_ENCRYPTION));
+ VALID_PARAM(is_valid_key_string(PARM_KEY1));
+ VALID_PARAM(is_valid_key_string(PARM_KEY2));
+ VALID_PARAM(is_valid_key_string(PARM_KEY3));
+ VALID_PARAM(is_valid_key_string(PARM_KEY4));
+ VALID_PARAM((PARM_TX_KEY >= PARM_MIN_TX_KEY) && (PARM_TX_KEY <= PARM_MAX_TX_KEY));
+
+ VALID_PARAM((PARM_MULTICAST_RATE >= PARM_MIN_MULTICAST_RATE) &&
+ (PARM_MULTICAST_RATE <= PARM_MAX_MULTICAST_RATE));
+
+ VALID_PARAM(!PARM_DOWNLOAD_FIRMWARE || (strlen(PARM_DOWNLOAD_FIRMWARE) <= 255 /*;?*/));
+ VALID_PARAM((PARM_AUTH_KEY_MGMT_SUITE < PARM_MAX_AUTH_KEY_MGMT_SUITE));
+
+ VALID_PARAM(!PARM_LOAD_BALANCING || strchr("NnYy", PARM_LOAD_BALANCING[0]) != NULL);
VALID_PARAM( !PARM_MEDIUM_DISTRIBUTION || strchr( "NnYy", PARM_MEDIUM_DISTRIBUTION[0] ) != NULL );
VALID_PARAM(( PARM_TX_POW_LEVEL <= PARM_MAX_TX_POW_LEVEL ));
@@ -601,33 +588,25 @@ int wl_insert( struct net_device *dev )
lp->MulticastRate[0] = PARM_DEFAULT_MULTICAST_RATE_2GHZ;
lp->MulticastRate[1] = PARM_DEFAULT_MULTICAST_RATE_5GHZ;
- if ( strchr( "Yy", PARM_MICROWAVE_ROBUSTNESS[0] ) != NULL ) {
+ if ( strchr( "Yy", PARM_MICROWAVE_ROBUSTNESS[0] ) != NULL )
lp->MicrowaveRobustness = 1;
- } else {
+ else
lp->MicrowaveRobustness = 0;
- }
- if ( PARM_DESIRED_SSID && ( strlen( PARM_DESIRED_SSID ) <= HCF_MAX_NAME_LEN )) {
+ if ( PARM_DESIRED_SSID && ( strlen( PARM_DESIRED_SSID ) <= HCF_MAX_NAME_LEN ))
strcpy( lp->NetworkName, PARM_DESIRED_SSID );
- }
- if ( PARM_OWN_SSID && ( strlen( PARM_OWN_SSID ) <= HCF_MAX_NAME_LEN )) {
+ if ( PARM_OWN_SSID && ( strlen( PARM_OWN_SSID ) <= HCF_MAX_NAME_LEN ))
strcpy( lp->NetworkName, PARM_OWN_SSID );
- }
- if ( PARM_OWN_NAME && ( strlen( PARM_OWN_NAME ) <= HCF_MAX_NAME_LEN )) {
+ if ( PARM_OWN_NAME && ( strlen( PARM_OWN_NAME ) <= HCF_MAX_NAME_LEN ))
strcpy( lp->StationName, PARM_OWN_NAME );
- }
lp->EnableEncryption = PARM_ENABLE_ENCRYPTION;
- if ( PARM_KEY1 && ( strlen( PARM_KEY1 ) <= MAX_KEY_LEN )) {
+ if ( PARM_KEY1 && ( strlen( PARM_KEY1 ) <= MAX_KEY_LEN ))
strcpy( lp->Key1, PARM_KEY1 );
- }
- if ( PARM_KEY2 && ( strlen( PARM_KEY2 ) <= MAX_KEY_LEN )) {
+ if ( PARM_KEY2 && ( strlen( PARM_KEY2 ) <= MAX_KEY_LEN ))
strcpy( lp->Key2, PARM_KEY2 );
- }
- if ( PARM_KEY3 && ( strlen( PARM_KEY3 ) <= MAX_KEY_LEN )) {
+ if ( PARM_KEY3 && ( strlen( PARM_KEY3 ) <= MAX_KEY_LEN ))
strcpy( lp->Key3, PARM_KEY3 );
- }
- if ( PARM_KEY4 && ( strlen( PARM_KEY4 ) <= MAX_KEY_LEN )) {
+ if ( PARM_KEY4 && ( strlen( PARM_KEY4 ) <= MAX_KEY_LEN ))
strcpy( lp->Key4, PARM_KEY4 );
- }
lp->TransmitKeyID = PARM_TX_KEY;
@@ -639,17 +618,15 @@ int wl_insert( struct net_device *dev )
lp->DownloadFirmware = 1 ; //;?to be upgraded PARM_DOWNLOAD_FIRMWARE;
lp->AuthKeyMgmtSuite = PARM_AUTH_KEY_MGMT_SUITE;
- if ( strchr( "Yy", PARM_LOAD_BALANCING[0] ) != NULL ) {
+ if ( strchr( "Yy", PARM_LOAD_BALANCING[0] ) != NULL )
lp->loadBalancing = 1;
- } else {
+ else
lp->loadBalancing = 0;
- }
- if ( strchr( "Yy", PARM_MEDIUM_DISTRIBUTION[0] ) != NULL ) {
+ if ( strchr( "Yy", PARM_MEDIUM_DISTRIBUTION[0] ) != NULL )
lp->mediumDistribution = 1;
- } else {
+ else
lp->mediumDistribution = 0;
- }
lp->txPowLevel = PARM_TX_POW_LEVEL;
@@ -665,24 +642,20 @@ int wl_insert( struct net_device *dev )
lp->atimWindow = PARM_OWN_ATIM_WINDOW;
lp->holdoverDuration = PARM_PM_HOLDOVER_DURATION;
lp->PMEnabled = PARM_PM_ENABLED; //;?
- if ( strchr( "Yy", PARM_CREATE_IBSS[0] ) != NULL ) {
+ if ( strchr( "Yy", PARM_CREATE_IBSS[0] ) != NULL )
lp->CreateIBSS = 1;
- } else {
+ else
lp->CreateIBSS = 0;
- }
- if ( strchr( "Nn", PARM_MULTICAST_RX[0] ) != NULL ) {
+ if ( strchr( "Nn", PARM_MULTICAST_RX[0] ) != NULL )
lp->MulticastReceive = 0;
- } else {
+ else
lp->MulticastReceive = 1;
- }
- if ( strchr( "Yy", PARM_PROMISCUOUS_MODE[0] ) != NULL ) {
+ if ( strchr( "Yy", PARM_PROMISCUOUS_MODE[0] ) != NULL )
lp->promiscuousMode = 1;
- } else {
+ else
lp->promiscuousMode = 0;
- }
- for( i = 0; i < ETH_ALEN; i++ ) {
- lp->MACAddress[i] = PARM_NETWORK_ADDR[i];
- }
+ for( i = 0; i < ETH_ALEN; i++ )
+ lp->MACAddress[i] = PARM_NETWORK_ADDR[i];
lp->connectionControl = PARM_CONNECTION_CONTROL;
@@ -691,26 +664,22 @@ int wl_insert( struct net_device *dev )
//;?should we restore this to allow smaller memory footprint
lp->DTIMPeriod = PARM_OWN_DTIM_PERIOD;
- if ( strchr( "Yy", PARM_REJECT_ANY[0] ) != NULL ) {
+ if ( strchr( "Yy", PARM_REJECT_ANY[0] ) != NULL )
lp->RejectAny = 1;
- } else {
+ else
lp->RejectAny = 0;
- }
- if ( strchr( "Nn", PARM_EXCLUDE_UNENCRYPTED[0] ) != NULL ) {
+ if ( strchr( "Nn", PARM_EXCLUDE_UNENCRYPTED[0] ) != NULL )
lp->ExcludeUnencrypted = 0;
- } else {
+ else
lp->ExcludeUnencrypted = 1;
- }
- if ( strchr( "Yy", PARM_MULTICAST_PM_BUFFERING[0] ) != NULL ) {
+ if ( strchr( "Yy", PARM_MULTICAST_PM_BUFFERING[0] ) != NULL )
lp->multicastPMBuffering = 1;
- } else {
+ else
lp->multicastPMBuffering = 0;
- }
- if ( strchr( "Yy", PARM_INTRA_BSS_RELAY[0] ) != NULL ) {
+ if ( strchr( "Yy", PARM_INTRA_BSS_RELAY[0] ) != NULL )
lp->intraBSSRelay = 1;
- } else {
+ else
lp->intraBSSRelay = 0;
- }
lp->ownBeaconInterval = PARM_OWN_BEACON_INTERVAL;
lp->coexistence = PARM_COEXISTENCE;
@@ -750,11 +719,10 @@ int wl_insert( struct net_device *dev )
#endif /* USE_WDS */
#endif /* HCF_AP */
#ifdef USE_RTS
- if ( strchr( "Yy", useRTS[0] ) != NULL ) {
+ if ( strchr( "Yy", useRTS[0] ) != NULL )
lp->useRTS = 1;
- } else {
+ else
lp->useRTS = 0;
- }
#endif /* USE_RTS */
@@ -1560,7 +1528,8 @@ int wl_put_ltv( struct wl_private *lp )
hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord ));
/* Own Name (Station Nickname) */
- if (( len = ( strlen( lp->StationName ) + 1 ) & ~0x01 ) != 0 ) {
+ len = (strlen(lp->StationName) + 1) & ~0x01;
+ if (len != 0) {
//DBG_TRACE( DbgInfo, "CFG_CNF_OWN_NAME : %s\n",
// lp->StationName );
diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c
index 965b1c0a4753..77e4be21e44b 100644
--- a/drivers/staging/wlags49_h2/wl_netdev.c
+++ b/drivers/staging/wlags49_h2/wl_netdev.c
@@ -68,31 +68,14 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/kernel.h>
-// #include <linux/sched.h>
-// #include <linux/ptrace.h>
-// #include <linux/slab.h>
-// #include <linux/ctype.h>
-// #include <linux/string.h>
-//#include <linux/timer.h>
-// #include <linux/interrupt.h>
-// #include <linux/in.h>
-// #include <linux/delay.h>
-// #include <linux/skbuff.h>
-// #include <asm/io.h>
-// // #include <asm/bitops.h>
-
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
-// #include <linux/skbuff.h>
-// #include <linux/if_arp.h>
-// #include <linux/ioport.h>
#include <debug.h>
#include <hcf.h>
#include <dhf.h>
-// #include <hcfdef.h>
#include <wl_if.h>
#include <wl_internal.h>
@@ -104,16 +87,15 @@
#ifdef USE_PROFILE
#include <wl_profile.h>
-#endif /* USE_PROFILE */
+#endif /* USE_PROFILE */
#ifdef BUS_PCMCIA
#include <wl_cs.h>
-#endif /* BUS_PCMCIA */
+#endif /* BUS_PCMCIA */
#ifdef BUS_PCI
#include <wl_pci.h>
-#endif /* BUS_PCI */
-
+#endif /* BUS_PCI */
#if HCF_ENCAP
#define MTU_MAX (HCF_MAX_MSG - ETH_HLEN - 8)
@@ -121,17 +103,15 @@
#define MTU_MAX (HCF_MAX_MSG - ETH_HLEN)
#endif
-//static int mtu = MTU_MAX;
-//MODULE_PARM(mtu, "i");
-//MODULE_PARM_DESC(mtu, "MTU");
-
/*******************************************************************************
* macros
******************************************************************************/
#define BLOCK_INPUT(buf, len) \
- desc->buf_addr = buf; \
- desc->BUF_SIZE = len; \
- status = hcf_rcv_msg(&(lp->hcfCtx), desc, 0)
+ do { \
+ desc->buf_addr = buf; \
+ desc->BUF_SIZE = len; \
+ status = hcf_rcv_msg(&(lp->hcfCtx), desc, 0); \
+ } while (0)
#define BLOCK_INPUT_DMA(buf, len) memcpy( buf, desc_next->buf_addr, pktlen )
@@ -158,20 +138,12 @@
* errno value otherwise
*
******************************************************************************/
-int wl_init( struct net_device *dev )
+int wl_init(struct net_device *dev)
{
-// unsigned long flags;
-// struct wl_private *lp = wl_priv(dev);
-
- DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
+ DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
+ return 0;
+} /* wl_init */
- /* Nothing to do, but grab the spinlock anyway just in case we ever need
- this routine */
-// wl_lock( lp, &flags );
-// wl_unlock( lp, &flags );
-
- return 0;
-} // wl_init
/*============================================================================*/
/*******************************************************************************
@@ -193,17 +165,20 @@ int wl_init( struct net_device *dev )
* errno otherwise
*
******************************************************************************/
-int wl_config( struct net_device *dev, struct ifmap *map )
+int wl_config(struct net_device *dev, struct ifmap *map)
{
- DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
- DBG_PARAM( DbgInfo, "map", "0x%p", map );
+ DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
+ DBG_PARAM(DbgInfo, "map", "0x%p", map);
+
+ /*
+ * The only thing we care about here is a port change.
+ * Since this not needed, ignore the request.
+ */
+ DBG_TRACE(DbgInfo, "%s: %s called.\n", dev->name, __func__);
- /* The only thing we care about here is a port change. Since this not needed,
- ignore the request. */
- DBG_TRACE(DbgInfo, "%s: %s called.\n", dev->name, __func__);
+ return 0;
+} /* wl_config */
- return 0;
-} // wl_config
/*============================================================================*/
/*******************************************************************************
@@ -224,48 +199,47 @@ int wl_config( struct net_device *dev, struct ifmap *map )
* statistics.
*
******************************************************************************/
-struct net_device_stats *wl_stats( struct net_device *dev )
+struct net_device_stats *wl_stats(struct net_device *dev)
{
#ifdef USE_WDS
- int count;
-#endif /* USE_WDS */
- unsigned long flags;
- struct net_device_stats *pStats;
- struct wl_private *lp = wl_priv(dev);
+ int count;
+#endif /* USE_WDS */
+ unsigned long flags;
+ struct net_device_stats *pStats;
+ struct wl_private *lp = wl_priv(dev);
- //DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
+ /*DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev ); */
- pStats = NULL;
+ pStats = NULL;
- wl_lock( lp, &flags );
+ wl_lock(lp, &flags);
#ifdef USE_RTS
- if( lp->useRTS == 1 ) {
- wl_unlock( lp, &flags );
- return NULL;
- }
-#endif /* USE_RTS */
+ if (lp->useRTS == 1) {
+ wl_unlock(lp, &flags);
+ return NULL;
+ }
+#endif /* USE_RTS */
- /* Return the statistics for the appropriate device */
+ /* Return the statistics for the appropriate device */
#ifdef USE_WDS
- for( count = 0; count < NUM_WDS_PORTS; count++ ) {
- if( dev == lp->wds_port[count].dev ) {
- pStats = &( lp->wds_port[count].stats );
+ for (count = 0; count < NUM_WDS_PORTS; count++) {
+ if (dev == lp->wds_port[count].dev)
+ pStats = &(lp->wds_port[count].stats);
}
- }
-#endif /* USE_WDS */
+#endif /* USE_WDS */
+
+ /* If pStats is still NULL, then the device is not a WDS port */
+ if (pStats == NULL)
+ pStats = &(lp->stats);
- /* If pStats is still NULL, then the device is not a WDS port */
- if( pStats == NULL ) {
- pStats = &( lp->stats );
- }
+ wl_unlock(lp, &flags);
- wl_unlock( lp, &flags );
+ return pStats;
+} /* wl_stats */
- return pStats;
-} // wl_stats
/*============================================================================*/
/*******************************************************************************
@@ -288,75 +262,77 @@ struct net_device_stats *wl_stats( struct net_device *dev )
******************************************************************************/
int wl_open(struct net_device *dev)
{
- int status = HCF_SUCCESS;
- struct wl_private *lp = wl_priv(dev);
- unsigned long flags;
+ int status = HCF_SUCCESS;
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
- wl_lock( lp, &flags );
+ wl_lock(lp, &flags);
#ifdef USE_RTS
- if( lp->useRTS == 1 ) {
- DBG_TRACE( DbgInfo, "Skipping device open, in RTS mode\n" );
- wl_unlock( lp, &flags );
- return -EIO;
- }
-#endif /* USE_RTS */
+ if (lp->useRTS == 1) {
+ DBG_TRACE(DbgInfo, "Skipping device open, in RTS mode\n");
+ wl_unlock(lp, &flags);
+ return -EIO;
+ }
+#endif /* USE_RTS */
#ifdef USE_PROFILE
- parse_config( dev );
+ parse_config(dev);
#endif
- if( lp->portState == WVLAN_PORT_STATE_DISABLED ) {
- DBG_TRACE( DbgInfo, "Enabling Port 0\n" );
- status = wl_enable( lp );
-
- if( status != HCF_SUCCESS ) {
- DBG_TRACE( DbgInfo, "Enable port 0 failed: 0x%x\n", status );
- }
- }
-
- // Holding the lock too long, make a gap to allow other processes
- wl_unlock(lp, &flags);
- wl_lock( lp, &flags );
-
- if ( strlen( lp->fw_image_filename ) ) {
- DBG_TRACE( DbgInfo, ";???? Kludgy way to force a download\n" );
- status = wl_go( lp );
- } else {
- status = wl_apply( lp );
- }
-
- // Holding the lock too long, make a gap to allow other processes
- wl_unlock(lp, &flags);
- wl_lock( lp, &flags );
-
- if( status != HCF_SUCCESS ) {
- // Unsuccessful, try reset of the card to recover
- status = wl_reset( dev );
- }
-
- // Holding the lock too long, make a gap to allow other processes
- wl_unlock(lp, &flags);
- wl_lock( lp, &flags );
-
- if( status == HCF_SUCCESS ) {
- netif_carrier_on( dev );
- WL_WDS_NETIF_CARRIER_ON( lp );
-
- lp->is_handling_int = WL_HANDLING_INT; // Start handling interrupts
- wl_act_int_on( lp );
-
- netif_start_queue( dev );
- WL_WDS_NETIF_START_QUEUE( lp );
- } else {
- wl_hcf_error( dev, status ); /* Report the error */
- netif_device_detach( dev ); /* Stop the device and queue */
- }
-
- wl_unlock( lp, &flags );
-
- return status;
-} // wl_open
+ if (lp->portState == WVLAN_PORT_STATE_DISABLED) {
+ DBG_TRACE(DbgInfo, "Enabling Port 0\n");
+ status = wl_enable(lp);
+
+ if (status != HCF_SUCCESS) {
+ DBG_TRACE(DbgInfo, "Enable port 0 failed: 0x%x\n",
+ status);
+ }
+ }
+
+ /* Holding the lock too long, make a gap to allow other processes */
+ wl_unlock(lp, &flags);
+ wl_lock(lp, &flags);
+
+ if (strlen(lp->fw_image_filename)) {
+ DBG_TRACE(DbgInfo, ";???? Kludgy way to force a download\n");
+ status = wl_go(lp);
+ } else {
+ status = wl_apply(lp);
+ }
+
+ /* Holding the lock too long, make a gap to allow other processes */
+ wl_unlock(lp, &flags);
+ wl_lock(lp, &flags);
+
+ /* Unsuccessful, try reset of the card to recover */
+ if (status != HCF_SUCCESS)
+ status = wl_reset(dev);
+
+ /* Holding the lock too long, make a gap to allow other processes */
+ wl_unlock(lp, &flags);
+ wl_lock(lp, &flags);
+
+ if (status == HCF_SUCCESS) {
+ netif_carrier_on(dev);
+ WL_WDS_NETIF_CARRIER_ON(lp);
+
+ /* Start handling interrupts */
+ lp->is_handling_int = WL_HANDLING_INT;
+ wl_act_int_on(lp);
+
+ netif_start_queue(dev);
+ WL_WDS_NETIF_START_QUEUE(lp);
+ } else {
+ wl_hcf_error(dev, status); /* Report the error */
+ netif_device_detach(dev); /* Stop the device and queue */
+ }
+
+ wl_unlock(lp, &flags);
+
+ return status;
+} /* wl_open */
+
/*============================================================================*/
/*******************************************************************************
@@ -377,73 +353,70 @@ int wl_open(struct net_device *dev)
* errno otherwise
*
******************************************************************************/
-int wl_close( struct net_device *dev )
+int wl_close(struct net_device *dev)
{
- struct wl_private *lp = wl_priv(dev);
- unsigned long flags;
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
- DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
+ DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
- /* Mark the adapter as busy */
- netif_stop_queue( dev );
- WL_WDS_NETIF_STOP_QUEUE( lp );
+ /* Mark the adapter as busy */
+ netif_stop_queue(dev);
+ WL_WDS_NETIF_STOP_QUEUE(lp);
- netif_carrier_off( dev );
- WL_WDS_NETIF_CARRIER_OFF( lp );
+ netif_carrier_off(dev);
+ WL_WDS_NETIF_CARRIER_OFF(lp);
- /* Shutdown the adapter:
- Disable adapter interrupts
- Stop Tx/Rx
- Update statistics
- Set low power mode
- */
+ /*
+ * Shutdown the adapter:
+ * Disable adapter interrupts
+ * Stop Tx/Rx
+ * Update statistics
+ * Set low power mode
+ */
- wl_lock( lp, &flags );
+ wl_lock(lp, &flags);
- wl_act_int_off( lp );
- lp->is_handling_int = WL_NOT_HANDLING_INT; // Stop handling interrupts
+ wl_act_int_off(lp);
+ /* Stop handling interrupts */
+ lp->is_handling_int = WL_NOT_HANDLING_INT;
#ifdef USE_RTS
- if( lp->useRTS == 1 ) {
- DBG_TRACE( DbgInfo, "Skipping device close, in RTS mode\n" );
- wl_unlock( lp, &flags );
- return -EIO;
- }
-#endif /* USE_RTS */
+ if (lp->useRTS == 1) {
+ DBG_TRACE(DbgInfo, "Skipping device close, in RTS mode\n");
+ wl_unlock(lp, &flags);
+ return -EIO;
+ }
+#endif /* USE_RTS */
- /* Disable the ports */
- wl_disable( lp );
+ /* Disable the ports */
+ wl_disable(lp);
- wl_unlock( lp, &flags );
+ wl_unlock(lp, &flags);
+
+ return 0;
+} /* wl_close */
- return 0;
-} // wl_close
/*============================================================================*/
static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
- strlcpy(info->version, DRV_VERSION_STR, sizeof(info->version));
-// strlcpy(info.fw_version, priv->fw_name,
-// sizeof(info.fw_version));
-
- if (dev->dev.parent) {
- dev_set_name(dev->dev.parent, "%s", info->bus_info);
- //strlcpy(info->bus_info, dev->dev.parent->bus_id,
- // sizeof(info->bus_info));
- } else {
- snprintf(info->bus_info, sizeof(info->bus_info),
- "PCMCIA FIXME");
-// "PCMCIA 0x%lx", priv->hw.iobase);
- }
-} // wl_get_drvinfo
+ strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION_STR, sizeof(info->version));
+
+ if (dev->dev.parent) {
+ dev_set_name(dev->dev.parent, "%s", info->bus_info);
+ } else {
+ snprintf(info->bus_info, sizeof(info->bus_info),
+ "PCMCIA FIXME");
+ }
+} /* wl_get_drvinfo */
static struct ethtool_ops wl_ethtool_ops = {
- .get_drvinfo = wl_get_drvinfo,
- .get_link = ethtool_op_get_link,
+ .get_drvinfo = wl_get_drvinfo,
+ .get_link = ethtool_op_get_link,
};
-
/*******************************************************************************
* wl_ioctl()
*******************************************************************************
@@ -464,81 +437,86 @@ static struct ethtool_ops wl_ethtool_ops = {
* errno value otherwise
*
******************************************************************************/
-int wl_ioctl( struct net_device *dev, struct ifreq *rq, int cmd )
+int wl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct wl_private *lp = wl_priv(dev);
- unsigned long flags;
- int ret = 0;
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ int ret = 0;
- DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
- DBG_PARAM(DbgInfo, "rq", "0x%p", rq);
- DBG_PARAM(DbgInfo, "cmd", "0x%04x", cmd);
+ DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
+ DBG_PARAM(DbgInfo, "rq", "0x%p", rq);
+ DBG_PARAM(DbgInfo, "cmd", "0x%04x", cmd);
- wl_lock( lp, &flags );
+ wl_lock(lp, &flags);
- wl_act_int_off( lp );
+ wl_act_int_off(lp);
#ifdef USE_RTS
- if( lp->useRTS == 1 ) {
- /* Handle any RTS IOCTL here */
- if( cmd == WL_IOCTL_RTS ) {
- DBG_TRACE( DbgInfo, "IOCTL: WL_IOCTL_RTS\n" );
- ret = wvlan_rts( (struct rtsreq *)rq, dev->base_addr );
- } else {
- DBG_TRACE( DbgInfo, "IOCTL not supported in RTS mode: 0x%X\n", cmd );
- ret = -EOPNOTSUPP;
- }
+ if (lp->useRTS == 1) {
+ /* Handle any RTS IOCTL here */
+ if (cmd == WL_IOCTL_RTS) {
+ DBG_TRACE(DbgInfo, "IOCTL: WL_IOCTL_RTS\n");
+ ret = wvlan_rts((struct rtsreq *)rq, dev->base_addr);
+ } else {
+ DBG_TRACE(DbgInfo,
+ "IOCTL not supported in RTS mode: 0x%X\n",
+ cmd);
+ ret = -EOPNOTSUPP;
+ }
- goto out_act_int_on_unlock;
- }
-#endif /* USE_RTS */
+ goto out_act_int_on_unlock;
+ }
+#endif /* USE_RTS */
- /* Only handle UIL IOCTL requests when the UIL has the system blocked. */
- if( !(( lp->flags & WVLAN2_UIL_BUSY ) && ( cmd != WVLAN2_IOCTL_UIL ))) {
+ /* Only handle UIL IOCTL requests when the UIL has the system blocked. */
+ if (!((lp->flags & WVLAN2_UIL_BUSY) && (cmd != WVLAN2_IOCTL_UIL))) {
#ifdef USE_UIL
- struct uilreq *urq = (struct uilreq *)rq;
+ struct uilreq *urq = (struct uilreq *)rq;
#endif /* USE_UIL */
- switch( cmd ) {
- // ================== Private IOCTLs (up to 16) ==================
+ switch (cmd) {
+ /* ================== Private IOCTLs (up to 16) ================== */
#ifdef USE_UIL
- case WVLAN2_IOCTL_UIL:
- DBG_TRACE( DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL\n" );
- ret = wvlan_uil( urq, lp );
- break;
-#endif /* USE_UIL */
-
- default:
- DBG_TRACE(DbgInfo, "IOCTL CODE NOT SUPPORTED: 0x%X\n", cmd );
- ret = -EOPNOTSUPP;
- break;
+ case WVLAN2_IOCTL_UIL:
+ DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL\n");
+ ret = wvlan_uil(urq, lp);
+ break;
+#endif /* USE_UIL */
+
+ default:
+ DBG_TRACE(DbgInfo, "IOCTL CODE NOT SUPPORTED: 0x%X\n",
+ cmd);
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ } else {
+ DBG_WARNING(DbgInfo,
+ "DEVICE IS BUSY, CANNOT PROCESS REQUEST\n");
+ ret = -EBUSY;
}
- } else {
- DBG_WARNING( DbgInfo, "DEVICE IS BUSY, CANNOT PROCESS REQUEST\n" );
- ret = -EBUSY;
- }
#ifdef USE_RTS
out_act_int_on_unlock:
-#endif /* USE_RTS */
- wl_act_int_on( lp );
+#endif /* USE_RTS */
+ wl_act_int_on(lp);
- wl_unlock( lp, &flags );
+ wl_unlock(lp, &flags);
+
+ return ret;
+} /* wl_ioctl */
- return ret;
-} // wl_ioctl
/*============================================================================*/
#ifdef CONFIG_NET_POLL_CONTROLLER
-void wl_poll(struct net_device *dev)
+static void wl_poll(struct net_device *dev)
{
- struct wl_private *lp = wl_priv(dev);
- unsigned long flags;
- struct pt_regs regs;
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
+ struct pt_regs regs;
- wl_lock( lp, &flags );
- wl_isr(dev->irq, dev, &regs);
- wl_unlock( lp, &flags );
+ wl_lock(lp, &flags);
+ wl_isr(dev->irq, dev, &regs);
+ wl_unlock(lp, &flags);
}
#endif
@@ -559,53 +537,54 @@ void wl_poll(struct net_device *dev)
* N/A
*
******************************************************************************/
-void wl_tx_timeout( struct net_device *dev )
+void wl_tx_timeout(struct net_device *dev)
{
#ifdef USE_WDS
- int count;
-#endif /* USE_WDS */
- unsigned long flags;
- struct wl_private *lp = wl_priv(dev);
- struct net_device_stats *pStats = NULL;
+ int count;
+#endif /* USE_WDS */
+ unsigned long flags;
+ struct wl_private *lp = wl_priv(dev);
+ struct net_device_stats *pStats = NULL;
- DBG_WARNING( DbgInfo, "%s: Transmit timeout.\n", dev->name );
+ DBG_WARNING(DbgInfo, "%s: Transmit timeout.\n", dev->name);
- wl_lock( lp, &flags );
+ wl_lock(lp, &flags);
#ifdef USE_RTS
- if( lp->useRTS == 1 ) {
- DBG_TRACE( DbgInfo, "Skipping tx_timeout handler, in RTS mode\n" );
- wl_unlock( lp, &flags );
- return;
- }
-#endif /* USE_RTS */
-
- /* Figure out which device (the "root" device or WDS port) this timeout
- is for */
+ if (lp->useRTS == 1) {
+ DBG_TRACE(DbgInfo,
+ "Skipping tx_timeout handler, in RTS mode\n");
+ wl_unlock(lp, &flags);
+ return;
+ }
+#endif /* USE_RTS */
+
+ /* Figure out which device (the "root" device or WDS port) this timeout
+ is for */
#ifdef USE_WDS
- for( count = 0; count < NUM_WDS_PORTS; count++ ) {
- if( dev == lp->wds_port[count].dev ) {
- pStats = &( lp->wds_port[count].stats );
+ for (count = 0; count < NUM_WDS_PORTS; count++) {
+ if (dev == lp->wds_port[count].dev) {
+ pStats = &(lp->wds_port[count].stats);
- /* Break the loop so that we can use the counter to access WDS
- information in the private structure */
- break;
+ /* Break the loop so that we can use the counter to access WDS
+ information in the private structure */
+ break;
+ }
}
- }
-#endif /* USE_WDS */
+#endif /* USE_WDS */
+
+ /* If pStats is still NULL, then the device is not a WDS port */
+ if (pStats == NULL)
+ pStats = &(lp->stats);
- /* If pStats is still NULL, then the device is not a WDS port */
- if( pStats == NULL ) {
- pStats = &( lp->stats );
- }
+ /* Accumulate the timeout error */
+ pStats->tx_errors++;
- /* Accumulate the timeout error */
- pStats->tx_errors++;
+ wl_unlock(lp, &flags);
+} /* wl_tx_timeout */
- wl_unlock( lp, &flags );
-} // wl_tx_timeout
/*============================================================================*/
/*******************************************************************************
@@ -626,103 +605,105 @@ void wl_tx_timeout( struct net_device *dev )
* 1 on error
*
******************************************************************************/
-int wl_send( struct wl_private *lp )
+int wl_send(struct wl_private *lp)
{
- int status;
- DESC_STRCT *desc;
- WVLAN_LFRAME *txF = NULL;
- struct list_head *element;
- int len;
+ int status;
+ DESC_STRCT *desc;
+ WVLAN_LFRAME *txF = NULL;
+ struct list_head *element;
+ int len;
/*------------------------------------------------------------------------*/
- if( lp == NULL ) {
- DBG_ERROR( DbgInfo, "Private adapter struct is NULL\n" );
- return FALSE;
- }
- if( lp->dev == NULL ) {
- DBG_ERROR( DbgInfo, "net_device struct in wl_private is NULL\n" );
- return FALSE;
- }
-
- /* Check for the availability of FIDs; if none are available, don't take any
- frames off the txQ */
- if( lp->hcfCtx.IFB_RscInd == 0 ) {
- return FALSE;
- }
-
- /* Reclaim the TxQ Elements and place them back on the free queue */
- if( !list_empty( &( lp->txQ[0] ))) {
- element = lp->txQ[0].next;
-
- txF = (WVLAN_LFRAME * )list_entry( element, WVLAN_LFRAME, node );
- if( txF != NULL ) {
- lp->txF.skb = txF->frame.skb;
- lp->txF.port = txF->frame.port;
-
- txF->frame.skb = NULL;
- txF->frame.port = 0;
-
- list_del( &( txF->node ));
- list_add( element, &( lp->txFree ));
-
- lp->txQ_count--;
-
- if( lp->txQ_count < TX_Q_LOW_WATER_MARK ) {
- if( lp->netif_queue_on == FALSE ) {
- DBG_TX( DbgInfo, "Kickstarting Q: %d\n", lp->txQ_count );
- netif_wake_queue( lp->dev );
- WL_WDS_NETIF_WAKE_QUEUE( lp );
- lp->netif_queue_on = TRUE;
- }
- }
- }
- }
-
- if( lp->txF.skb == NULL ) {
- return FALSE;
- }
-
- /* If the device has resources (FIDs) available, then Tx the packet */
- /* Format the TxRequest and send it to the adapter */
- len = lp->txF.skb->len < ETH_ZLEN ? ETH_ZLEN : lp->txF.skb->len;
-
- desc = &( lp->desc_tx );
- desc->buf_addr = lp->txF.skb->data;
- desc->BUF_CNT = len;
- desc->next_desc_addr = NULL;
-
- status = hcf_send_msg( &( lp->hcfCtx ), desc, lp->txF.port );
-
- if( status == HCF_SUCCESS ) {
- lp->dev->trans_start = jiffies;
-
- DBG_TX( DbgInfo, "Transmit...\n" );
-
- if( lp->txF.port == HCF_PORT_0 ) {
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += lp->txF.skb->len;
- }
+ if (lp == NULL) {
+ DBG_ERROR(DbgInfo, "Private adapter struct is NULL\n");
+ return FALSE;
+ }
+ if (lp->dev == NULL) {
+ DBG_ERROR(DbgInfo, "net_device struct in wl_private is NULL\n");
+ return FALSE;
+ }
+
+ /*
+ * Check for the availability of FIDs; if none are available,
+ * don't take any frames off the txQ
+ */
+ if (lp->hcfCtx.IFB_RscInd == 0)
+ return FALSE;
+
+ /* Reclaim the TxQ Elements and place them back on the free queue */
+ if (!list_empty(&(lp->txQ[0]))) {
+ element = lp->txQ[0].next;
+
+ txF = (WVLAN_LFRAME *) list_entry(element, WVLAN_LFRAME, node);
+ if (txF != NULL) {
+ lp->txF.skb = txF->frame.skb;
+ lp->txF.port = txF->frame.port;
+
+ txF->frame.skb = NULL;
+ txF->frame.port = 0;
+
+ list_del(&(txF->node));
+ list_add(element, &(lp->txFree));
+
+ lp->txQ_count--;
+
+ if (lp->txQ_count < TX_Q_LOW_WATER_MARK) {
+ if (lp->netif_queue_on == FALSE) {
+ DBG_TX(DbgInfo, "Kickstarting Q: %d\n",
+ lp->txQ_count);
+ netif_wake_queue(lp->dev);
+ WL_WDS_NETIF_WAKE_QUEUE(lp);
+ lp->netif_queue_on = TRUE;
+ }
+ }
+ }
+ }
+
+ if (lp->txF.skb == NULL)
+ return FALSE;
+
+ /* If the device has resources (FIDs) available, then Tx the packet */
+ /* Format the TxRequest and send it to the adapter */
+ len = lp->txF.skb->len < ETH_ZLEN ? ETH_ZLEN : lp->txF.skb->len;
+
+ desc = &(lp->desc_tx);
+ desc->buf_addr = lp->txF.skb->data;
+ desc->BUF_CNT = len;
+ desc->next_desc_addr = NULL;
+
+ status = hcf_send_msg(&(lp->hcfCtx), desc, lp->txF.port);
+
+ if (status == HCF_SUCCESS) {
+ lp->dev->trans_start = jiffies;
+
+ DBG_TX(DbgInfo, "Transmit...\n");
+ if (lp->txF.port == HCF_PORT_0) {
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes += lp->txF.skb->len;
+ }
#ifdef USE_WDS
- else
- {
- lp->wds_port[(( lp->txF.port >> 8 ) - 1)].stats.tx_packets++;
- lp->wds_port[(( lp->txF.port >> 8 ) - 1)].stats.tx_bytes += lp->txF.skb->len;
- }
+ else {
+ lp->wds_port[((lp->txF.port >> 8) -
+ 1)].stats.tx_packets++;
+ lp->wds_port[((lp->txF.port >> 8) -
+ 1)].stats.tx_bytes += lp->txF.skb->len;
+ }
-#endif /* USE_WDS */
+#endif /* USE_WDS */
- /* Free the skb and perform queue cleanup, as the buffer was
- transmitted successfully */
- dev_kfree_skb( lp->txF.skb );
+ /* Free the skb and perform queue cleanup, as the buffer was
+ transmitted successfully */
+ dev_kfree_skb(lp->txF.skb);
- lp->txF.skb = NULL;
- lp->txF.port = 0;
- }
+ lp->txF.skb = NULL;
+ lp->txF.port = 0;
+ }
+
+ return TRUE;
+} /* wl_send */
- return TRUE;
-} // wl_send
/*============================================================================*/
/*******************************************************************************
@@ -744,75 +725,74 @@ int wl_send( struct wl_private *lp )
* 1 on error
*
******************************************************************************/
-int wl_tx( struct sk_buff *skb, struct net_device *dev, int port )
+int wl_tx(struct sk_buff *skb, struct net_device *dev, int port)
{
- unsigned long flags;
- struct wl_private *lp = wl_priv(dev);
- WVLAN_LFRAME *txF = NULL;
- struct list_head *element;
+ unsigned long flags;
+ struct wl_private *lp = wl_priv(dev);
+ WVLAN_LFRAME *txF = NULL;
+ struct list_head *element;
/*------------------------------------------------------------------------*/
- /* Grab the spinlock */
- wl_lock( lp, &flags );
-
- if( lp->flags & WVLAN2_UIL_BUSY ) {
- DBG_WARNING( DbgInfo, "UIL has device blocked\n" );
- /* Start dropping packets here??? */
- wl_unlock( lp, &flags );
- return 1;
- }
+ /* Grab the spinlock */
+ wl_lock(lp, &flags);
+ if (lp->flags & WVLAN2_UIL_BUSY) {
+ DBG_WARNING(DbgInfo, "UIL has device blocked\n");
+ /* Start dropping packets here??? */
+ wl_unlock(lp, &flags);
+ return 1;
+ }
#ifdef USE_RTS
- if( lp->useRTS == 1 ) {
- DBG_PRINT( "RTS: we're getting a Tx...\n" );
- wl_unlock( lp, &flags );
- return 1;
- }
-#endif /* USE_RTS */
-
- if( !lp->use_dma ) {
- /* Get an element from the queue */
- element = lp->txFree.next;
- txF = (WVLAN_LFRAME *)list_entry( element, WVLAN_LFRAME, node );
- if( txF == NULL ) {
- DBG_ERROR( DbgInfo, "Problem with list_entry\n" );
- wl_unlock( lp, &flags );
- return 1;
- }
- /* Fill out the frame */
- txF->frame.skb = skb;
- txF->frame.port = port;
- /* Move the frame to the txQ */
- /* NOTE: Here's where we would do priority queueing */
- list_move(&(txF->node), &(lp->txQ[0]));
-
- lp->txQ_count++;
- if( lp->txQ_count >= DEFAULT_NUM_TX_FRAMES ) {
- DBG_TX( DbgInfo, "Q Full: %d\n", lp->txQ_count );
- if( lp->netif_queue_on == TRUE ) {
- netif_stop_queue( lp->dev );
- WL_WDS_NETIF_STOP_QUEUE( lp );
- lp->netif_queue_on = FALSE;
- }
- }
- }
- wl_act_int_off( lp ); /* Disable Interrupts */
-
- /* Send the data to the hardware using the appropriate method */
+ if (lp->useRTS == 1) {
+ DBG_PRINT("RTS: we're getting a Tx...\n");
+ wl_unlock(lp, &flags);
+ return 1;
+ }
+#endif /* USE_RTS */
+
+ if (!lp->use_dma) {
+ /* Get an element from the queue */
+ element = lp->txFree.next;
+ txF = (WVLAN_LFRAME *) list_entry(element, WVLAN_LFRAME, node);
+ if (txF == NULL) {
+ DBG_ERROR(DbgInfo, "Problem with list_entry\n");
+ wl_unlock(lp, &flags);
+ return 1;
+ }
+ /* Fill out the frame */
+ txF->frame.skb = skb;
+ txF->frame.port = port;
+ /* Move the frame to the txQ */
+ /* NOTE: Here's where we would do priority queueing */
+ list_move(&(txF->node), &(lp->txQ[0]));
+
+ lp->txQ_count++;
+ if (lp->txQ_count >= DEFAULT_NUM_TX_FRAMES) {
+ DBG_TX(DbgInfo, "Q Full: %d\n", lp->txQ_count);
+ if (lp->netif_queue_on == TRUE) {
+ netif_stop_queue(lp->dev);
+ WL_WDS_NETIF_STOP_QUEUE(lp);
+ lp->netif_queue_on = FALSE;
+ }
+ }
+ }
+ wl_act_int_off(lp); /* Disable Interrupts */
+
+ /* Send the data to the hardware using the appropriate method */
#ifdef ENABLE_DMA
- if( lp->use_dma ) {
- wl_send_dma( lp, skb, port );
- }
- else
+ if (lp->use_dma) {
+ wl_send_dma(lp, skb, port);
+ } else
#endif
- {
- wl_send( lp );
- }
- /* Re-enable Interrupts, release the spinlock and return */
- wl_act_int_on( lp );
- wl_unlock( lp, &flags );
- return 0;
-} // wl_tx
+ {
+ wl_send(lp);
+ }
+ /* Re-enable Interrupts, release the spinlock and return */
+ wl_act_int_on(lp);
+ wl_unlock(lp, &flags);
+ return 0;
+} /* wl_tx */
+
/*============================================================================*/
/*******************************************************************************
@@ -835,67 +815,68 @@ int wl_tx( struct sk_buff *skb, struct net_device *dev, int port )
******************************************************************************/
int wl_rx(struct net_device *dev)
{
- int port;
- struct sk_buff *skb;
- struct wl_private *lp = wl_priv(dev);
- int status;
- hcf_16 pktlen;
- hcf_16 hfs_stat;
- DESC_STRCT *desc;
+ int port;
+ struct sk_buff *skb;
+ struct wl_private *lp = wl_priv(dev);
+ int status;
+ hcf_16 pktlen;
+ hcf_16 hfs_stat;
+ DESC_STRCT *desc;
/*------------------------------------------------------------------------*/
- DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
+ DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
- if(!( lp->flags & WVLAN2_UIL_BUSY )) {
+ if (!(lp->flags & WVLAN2_UIL_BUSY)) {
#ifdef USE_RTS
- if( lp->useRTS == 1 ) {
- DBG_PRINT( "RTS: We're getting an Rx...\n" );
- return -EIO;
- }
-#endif /* USE_RTS */
-
- /* Read the HFS_STAT register from the lookahead buffer */
- hfs_stat = (hcf_16)(( lp->lookAheadBuf[HFS_STAT] ) |
- ( lp->lookAheadBuf[HFS_STAT + 1] << 8 ));
-
- /* Make sure the frame isn't bad */
- if(( hfs_stat & HFS_STAT_ERR ) != HCF_SUCCESS ) {
- DBG_WARNING( DbgInfo, "HFS_STAT_ERROR (0x%x) in Rx Packet\n",
- lp->lookAheadBuf[HFS_STAT] );
- return -EIO;
- }
-
- /* Determine what port this packet is for */
- port = ( hfs_stat >> 8 ) & 0x0007;
- DBG_RX( DbgInfo, "Rx frame for port %d\n", port );
-
- pktlen = lp->hcfCtx.IFB_RxLen;
- if (pktlen != 0) {
- skb = ALLOC_SKB(pktlen);
- if (skb != NULL) {
- /* Set the netdev based on the port */
- switch( port ) {
+ if (lp->useRTS == 1) {
+ DBG_PRINT("RTS: We're getting an Rx...\n");
+ return -EIO;
+ }
+#endif /* USE_RTS */
+
+ /* Read the HFS_STAT register from the lookahead buffer */
+ hfs_stat = (hcf_16) ((lp->lookAheadBuf[HFS_STAT]) |
+ (lp->lookAheadBuf[HFS_STAT + 1] << 8));
+
+ /* Make sure the frame isn't bad */
+ if ((hfs_stat & HFS_STAT_ERR) != HCF_SUCCESS) {
+ DBG_WARNING(DbgInfo,
+ "HFS_STAT_ERROR (0x%x) in Rx Packet\n",
+ lp->lookAheadBuf[HFS_STAT]);
+ return -EIO;
+ }
+
+ /* Determine what port this packet is for */
+ port = (hfs_stat >> 8) & 0x0007;
+ DBG_RX(DbgInfo, "Rx frame for port %d\n", port);
+
+ pktlen = lp->hcfCtx.IFB_RxLen;
+ if (pktlen != 0) {
+ skb = ALLOC_SKB(pktlen);
+ if (skb != NULL) {
+ /* Set the netdev based on the port */
+ switch (port) {
#ifdef USE_WDS
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- skb->dev = lp->wds_port[port-1].dev;
- break;
-#endif /* USE_WDS */
-
- case 0:
- default:
- skb->dev = dev;
- break;
- }
-
- desc = &( lp->desc_rx );
-
- desc->next_desc_addr = NULL;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ skb->dev = lp->wds_port[port - 1].dev;
+ break;
+#endif /* USE_WDS */
+
+ case 0:
+ default:
+ skb->dev = dev;
+ break;
+ }
+
+ desc = &(lp->desc_rx);
+
+ desc->next_desc_addr = NULL;
/*
#define BLOCK_INPUT(buf, len) \
@@ -904,67 +885,73 @@ int wl_rx(struct net_device *dev)
status = hcf_rcv_msg(&(lp->hcfCtx), desc, 0)
*/
- GET_PACKET( skb->dev, skb, pktlen );
+ GET_PACKET(skb->dev, skb, pktlen);
- if( status == HCF_SUCCESS ) {
- netif_rx( skb );
+ if (status == HCF_SUCCESS) {
+ netif_rx(skb);
- if( port == 0 ) {
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pktlen;
- }
+ if (port == 0) {
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes += pktlen;
+ }
#ifdef USE_WDS
- else
- {
- lp->wds_port[port-1].stats.rx_packets++;
- lp->wds_port[port-1].stats.rx_bytes += pktlen;
- }
-#endif /* USE_WDS */
-
- dev->last_rx = jiffies;
+ else {
+ lp->wds_port[port -
+ 1].stats.
+ rx_packets++;
+ lp->wds_port[port -
+ 1].stats.
+ rx_bytes += pktlen;
+ }
+#endif /* USE_WDS */
+
+ dev->last_rx = jiffies;
#ifdef WIRELESS_EXT
#ifdef WIRELESS_SPY
- if( lp->spydata.spy_number > 0 ) {
- char *srcaddr = skb->mac.raw + MAC_ADDR_SIZE;
+ if (lp->spydata.spy_number > 0) {
+ char *srcaddr =
+ skb->mac.raw +
+ MAC_ADDR_SIZE;
- wl_spy_gather( dev, srcaddr );
- }
+ wl_spy_gather(dev, srcaddr);
+ }
#endif /* WIRELESS_SPY */
#endif /* WIRELESS_EXT */
- } else {
- DBG_ERROR( DbgInfo, "Rx request to card FAILED\n" );
+ } else {
+ DBG_ERROR(DbgInfo,
+ "Rx request to card FAILED\n");
- if( port == 0 ) {
- lp->stats.rx_dropped++;
- }
+ if (port == 0)
+ lp->stats.rx_dropped++;
#ifdef USE_WDS
- else
- {
- lp->wds_port[port-1].stats.rx_dropped++;
- }
-#endif /* USE_WDS */
-
- dev_kfree_skb( skb );
- }
- } else {
- DBG_ERROR( DbgInfo, "Could not alloc skb\n" );
-
- if( port == 0 ) {
- lp->stats.rx_dropped++;
- }
+ else {
+ lp->wds_port[port -
+ 1].stats.
+ rx_dropped++;
+ }
+#endif /* USE_WDS */
+
+ dev_kfree_skb(skb);
+ }
+ } else {
+ DBG_ERROR(DbgInfo, "Could not alloc skb\n");
+
+ if (port == 0)
+ lp->stats.rx_dropped++;
#ifdef USE_WDS
- else
- {
- lp->wds_port[port-1].stats.rx_dropped++;
- }
-#endif /* USE_WDS */
- }
- }
- }
-
- return 0;
-} // wl_rx
+ else {
+ lp->wds_port[port -
+ 1].stats.rx_dropped++;
+ }
+#endif /* USE_WDS */
+ }
+ }
+ }
+
+ return 0;
+} /* wl_rx */
+
/*============================================================================*/
/*******************************************************************************
@@ -986,142 +973,159 @@ int wl_rx(struct net_device *dev)
******************************************************************************/
#ifdef NEW_MULTICAST
-void wl_multicast( struct net_device *dev )
+void wl_multicast(struct net_device *dev)
{
-#if 1 //;? (HCF_TYPE) & HCF_TYPE_STA //;?should we return an error status in AP mode
-//;?seems reasonable that even an AP-only driver could afford this small additional footprint
+#if 1 /* (HCF_TYPE) & HCF_TYPE_STA */
+ /*
+ * should we return an error status in AP mode ?
+ * seems reasonable that even an AP-only driver
+ * could afford this small additional footprint
+ */
- int x;
- struct netdev_hw_addr *ha;
- struct wl_private *lp = wl_priv(dev);
- unsigned long flags;
+ int x;
+ struct netdev_hw_addr *ha;
+ struct wl_private *lp = wl_priv(dev);
+ unsigned long flags;
- DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
+ DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
- if( !wl_adapter_is_open( dev ))
- return;
+ if (!wl_adapter_is_open(dev))
+ return;
#if DBG
- if( DBG_FLAGS( DbgInfo ) & DBG_PARAM_ON ) {
- DBG_PRINT(" flags: %s%s%s\n",
- ( dev->flags & IFF_PROMISC ) ? "Promiscuous " : "",
- ( dev->flags & IFF_MULTICAST ) ? "Multicast " : "",
- ( dev->flags & IFF_ALLMULTI ) ? "All-Multicast" : "" );
+ if (DBG_FLAGS(DbgInfo) & DBG_PARAM_ON) {
+ DBG_PRINT(" flags: %s%s%s\n",
+ (dev->flags & IFF_PROMISC) ? "Promiscuous " : "",
+ (dev->flags & IFF_MULTICAST) ? "Multicast " : "",
+ (dev->flags & IFF_ALLMULTI) ? "All-Multicast" : "");
- DBG_PRINT( " mc_count: %d\n", netdev_mc_count(dev));
+ DBG_PRINT(" mc_count: %d\n", netdev_mc_count(dev));
- netdev_for_each_mc_addr(ha, dev)
- DBG_PRINT(" %pM (%d)\n", ha->addr, dev->addr_len);
- }
+ netdev_for_each_mc_addr(ha, dev)
+ DBG_PRINT(" %pM (%d)\n", ha->addr, dev->addr_len);
+ }
#endif /* DBG */
- if(!( lp->flags & WVLAN2_UIL_BUSY )) {
+ if (!(lp->flags & WVLAN2_UIL_BUSY)) {
#ifdef USE_RTS
- if( lp->useRTS == 1 ) {
- DBG_TRACE( DbgInfo, "Skipping multicast, in RTS mode\n" );
- return;
- }
-#endif /* USE_RTS */
-
- wl_lock( lp, &flags );
- wl_act_int_off( lp );
-
- if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA ) {
- if( dev->flags & IFF_PROMISC ) {
- /* Enable promiscuous mode */
- lp->ltvRecord.len = 2;
- lp->ltvRecord.typ = CFG_PROMISCUOUS_MODE;
- lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 1 );
- DBG_PRINT( "Enabling Promiscuous mode (IFF_PROMISC)\n" );
- hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
- }
- else if ((netdev_mc_count(dev) > HCF_MAX_MULTICAST) ||
- ( dev->flags & IFF_ALLMULTI )) {
- /* Shutting off this filter will enable all multicast frames to
- be sent up from the device; however, this is a static RID, so
- a call to wl_apply() is needed */
- lp->ltvRecord.len = 2;
- lp->ltvRecord.typ = CFG_CNF_RX_ALL_GROUP_ADDR;
- lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0 );
- DBG_PRINT( "Enabling all multicast mode (IFF_ALLMULTI)\n" );
- hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
- wl_apply( lp );
- }
- else if (!netdev_mc_empty(dev)) {
- /* Set the multicast addresses */
- lp->ltvRecord.len = ( netdev_mc_count(dev) * 3 ) + 1;
- lp->ltvRecord.typ = CFG_GROUP_ADDR;
-
- x = 0;
- netdev_for_each_mc_addr(ha, dev)
- memcpy(&(lp->ltvRecord.u.u8[x++ * ETH_ALEN]),
- ha->addr, ETH_ALEN);
- DBG_PRINT( "Setting multicast list\n" );
- hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
- } else {
- /* Disable promiscuous mode */
- lp->ltvRecord.len = 2;
- lp->ltvRecord.typ = CFG_PROMISCUOUS_MODE;
- lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 0 );
- DBG_PRINT( "Disabling Promiscuous mode\n" );
- hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
-
- /* Disable multicast mode */
- lp->ltvRecord.len = 2;
- lp->ltvRecord.typ = CFG_GROUP_ADDR;
- DBG_PRINT( "Disabling Multicast mode\n" );
- hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
-
- /* Turning on this filter will prevent all multicast frames from
- being sent up from the device; however, this is a static RID,
- so a call to wl_apply() is needed */
- lp->ltvRecord.len = 2;
- lp->ltvRecord.typ = CFG_CNF_RX_ALL_GROUP_ADDR;
- lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( 1 );
- DBG_PRINT( "Disabling all multicast mode (IFF_ALLMULTI)\n" );
- hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
- wl_apply( lp );
- }
- }
- wl_act_int_on( lp );
- wl_unlock( lp, &flags );
- }
+ if (lp->useRTS == 1) {
+ DBG_TRACE(DbgInfo, "Skipping multicast, in RTS mode\n");
+ return;
+ }
+#endif /* USE_RTS */
+
+ wl_lock(lp, &flags);
+ wl_act_int_off(lp);
+
+ if (CNV_INT_TO_LITTLE(lp->hcfCtx.IFB_FWIdentity.comp_id) ==
+ COMP_ID_FW_STA) {
+ if (dev->flags & IFF_PROMISC) {
+ /* Enable promiscuous mode */
+ lp->ltvRecord.len = 2;
+ lp->ltvRecord.typ = CFG_PROMISCUOUS_MODE;
+ lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(1);
+ DBG_PRINT
+ ("Enabling Promiscuous mode (IFF_PROMISC)\n");
+ hcf_put_info(&(lp->hcfCtx),
+ (LTVP) & (lp->ltvRecord));
+ } else if ((netdev_mc_count(dev) > HCF_MAX_MULTICAST)
+ || (dev->flags & IFF_ALLMULTI)) {
+ /* Shutting off this filter will enable all multicast frames to
+ be sent up from the device; however, this is a static RID, so
+ a call to wl_apply() is needed */
+ lp->ltvRecord.len = 2;
+ lp->ltvRecord.typ = CFG_CNF_RX_ALL_GROUP_ADDR;
+ lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(0);
+ DBG_PRINT
+ ("Enabling all multicast mode (IFF_ALLMULTI)\n");
+ hcf_put_info(&(lp->hcfCtx),
+ (LTVP) & (lp->ltvRecord));
+ wl_apply(lp);
+ } else if (!netdev_mc_empty(dev)) {
+ /* Set the multicast addresses */
+ lp->ltvRecord.len =
+ (netdev_mc_count(dev) * 3) + 1;
+ lp->ltvRecord.typ = CFG_GROUP_ADDR;
+
+ x = 0;
+ netdev_for_each_mc_addr(ha, dev)
+ memcpy(&
+ (lp->ltvRecord.u.u8[x++ * ETH_ALEN]),
+ ha->addr, ETH_ALEN);
+ DBG_PRINT("Setting multicast list\n");
+ hcf_put_info(&(lp->hcfCtx),
+ (LTVP) & (lp->ltvRecord));
+ } else {
+ /* Disable promiscuous mode */
+ lp->ltvRecord.len = 2;
+ lp->ltvRecord.typ = CFG_PROMISCUOUS_MODE;
+ lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(0);
+ DBG_PRINT("Disabling Promiscuous mode\n");
+ hcf_put_info(&(lp->hcfCtx),
+ (LTVP) & (lp->ltvRecord));
+
+ /* Disable multicast mode */
+ lp->ltvRecord.len = 2;
+ lp->ltvRecord.typ = CFG_GROUP_ADDR;
+ DBG_PRINT("Disabling Multicast mode\n");
+ hcf_put_info(&(lp->hcfCtx),
+ (LTVP) & (lp->ltvRecord));
+
+ /*
+ * Turning on this filter will prevent all multicast frames from
+ * being sent up from the device; however, this is a static RID,
+ * so a call to wl_apply() is needed
+ */
+ lp->ltvRecord.len = 2;
+ lp->ltvRecord.typ = CFG_CNF_RX_ALL_GROUP_ADDR;
+ lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(1);
+ DBG_PRINT
+ ("Disabling all multicast mode (IFF_ALLMULTI)\n");
+ hcf_put_info(&(lp->hcfCtx),
+ (LTVP) & (lp->ltvRecord));
+ wl_apply(lp);
+ }
+ }
+ wl_act_int_on(lp);
+ wl_unlock(lp, &flags);
+ }
#endif /* HCF_STA */
-} // wl_multicast
+} /* wl_multicast */
+
/*============================================================================*/
#else /* NEW_MULTICAST */
-void wl_multicast( struct net_device *dev, int num_addrs, void *addrs )
+void wl_multicast(struct net_device *dev, int num_addrs, void *addrs)
{
- DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
- DBG_PARAM( DbgInfo, "num_addrs", "%d", num_addrs );
- DBG_PARAM( DbgInfo, "addrs", "0x%p", addrs );
+ DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
+ DBG_PARAM(DbgInfo, "num_addrs", "%d", num_addrs);
+ DBG_PARAM(DbgInfo, "addrs", "0x%p", addrs);
#error Obsolete set multicast interface!
-} // wl_multicast
+} /* wl_multicast */
+
/*============================================================================*/
#endif /* NEW_MULTICAST */
-static const struct net_device_ops wl_netdev_ops =
-{
- .ndo_start_xmit = &wl_tx_port0,
+static const struct net_device_ops wl_netdev_ops = {
+ .ndo_start_xmit = &wl_tx_port0,
- .ndo_set_config = &wl_config,
- .ndo_get_stats = &wl_stats,
- .ndo_set_rx_mode = &wl_multicast,
+ .ndo_set_config = &wl_config,
+ .ndo_get_stats = &wl_stats,
+ .ndo_set_rx_mode = &wl_multicast,
- .ndo_init = &wl_insert,
- .ndo_open = &wl_adapter_open,
- .ndo_stop = &wl_adapter_close,
- .ndo_do_ioctl = &wl_ioctl,
+ .ndo_init = &wl_insert,
+ .ndo_open = &wl_adapter_open,
+ .ndo_stop = &wl_adapter_close,
+ .ndo_do_ioctl = &wl_ioctl,
- .ndo_tx_timeout = &wl_tx_timeout,
+ .ndo_tx_timeout = &wl_tx_timeout,
#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = wl_poll,
+ .ndo_poll_controller = wl_poll,
#endif
};
@@ -1144,48 +1148,51 @@ static const struct net_device_ops wl_netdev_ops =
* device.
*
******************************************************************************/
-struct net_device * wl_device_alloc( void )
+struct net_device *wl_device_alloc(void)
{
- struct net_device *dev = NULL;
- struct wl_private *lp = NULL;
-
- /* Alloc a net_device struct */
- dev = alloc_etherdev(sizeof(struct wl_private));
- if (!dev)
- return NULL;
-
- /* Initialize the 'next' pointer in the struct. Currently only used for PCI,
- but do it here just in case it's used for other buses in the future */
- lp = wl_priv(dev);
-
+ struct net_device *dev = NULL;
+ struct wl_private *lp = NULL;
+
+ /* Alloc a net_device struct */
+ dev = alloc_etherdev(sizeof(struct wl_private));
+ if (!dev)
+ return NULL;
+
+ /*
+ * Initialize the 'next' pointer in the struct.
+ * Currently only used for PCI,
+ * but do it here just in case it's used
+ * for other buses in the future
+ */
+ lp = wl_priv(dev);
+
+ /* Check MTU */
+ if (dev->mtu > MTU_MAX) {
+ DBG_WARNING(DbgInfo, "%s: MTU set too high, limiting to %d.\n",
+ dev->name, MTU_MAX);
+ dev->mtu = MTU_MAX;
+ }
- /* Check MTU */
- if( dev->mtu > MTU_MAX )
- {
- DBG_WARNING( DbgInfo, "%s: MTU set too high, limiting to %d.\n",
- dev->name, MTU_MAX );
- dev->mtu = MTU_MAX;
- }
+ /* Setup the function table in the device structure. */
- /* Setup the function table in the device structure. */
+ dev->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
+ lp->wireless_data.spy_data = &lp->spy_data;
+ dev->wireless_data = &lp->wireless_data;
- dev->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
- lp->wireless_data.spy_data = &lp->spy_data;
- dev->wireless_data = &lp->wireless_data;
+ dev->netdev_ops = &wl_netdev_ops;
- dev->netdev_ops = &wl_netdev_ops;
+ dev->watchdog_timeo = TX_TIMEOUT;
- dev->watchdog_timeo = TX_TIMEOUT;
+ dev->ethtool_ops = &wl_ethtool_ops;
- dev->ethtool_ops = &wl_ethtool_ops;
+ netif_stop_queue(dev);
- netif_stop_queue( dev );
+ /* Allocate virtual devices for WDS support if needed */
+ WL_WDS_DEVICE_ALLOC(lp);
- /* Allocate virtual devices for WDS support if needed */
- WL_WDS_DEVICE_ALLOC( lp );
+ return dev;
+} /* wl_device_alloc */
- return dev;
-} // wl_device_alloc
/*============================================================================*/
/*******************************************************************************
@@ -1206,15 +1213,14 @@ struct net_device * wl_device_alloc( void )
* N/A
*
******************************************************************************/
-void wl_device_dealloc( struct net_device *dev )
+void wl_device_dealloc(struct net_device *dev)
{
-// struct wl_private *lp = wl_priv(dev);
+ /* Dealloc the WDS ports */
+ WL_WDS_DEVICE_DEALLOC(lp);
- /* Dealloc the WDS ports */
- WL_WDS_DEVICE_DEALLOC( lp );
+ free_netdev(dev);
+} /* wl_device_dealloc */
- free_netdev( dev );
-} // wl_device_dealloc
/*============================================================================*/
/*******************************************************************************
@@ -1235,15 +1241,16 @@ void wl_device_dealloc( struct net_device *dev )
* N/A
*
******************************************************************************/
-int wl_tx_port0( struct sk_buff *skb, struct net_device *dev )
+int wl_tx_port0(struct sk_buff *skb, struct net_device *dev)
{
- DBG_TX( DbgInfo, "Tx on Port 0\n" );
+ DBG_TX(DbgInfo, "Tx on Port 0\n");
- return wl_tx( skb, dev, HCF_PORT_0 );
+ return wl_tx(skb, dev, HCF_PORT_0);
#ifdef ENABLE_DMA
- return wl_tx_dma( skb, dev, HCF_PORT_0 );
+ return wl_tx_dma(skb, dev, HCF_PORT_0);
#endif
-} // wl_tx_port0
+} /* wl_tx_port0i */
+
/*============================================================================*/
#ifdef USE_WDS
@@ -1266,11 +1273,12 @@ int wl_tx_port0( struct sk_buff *skb, struct net_device *dev )
* N/A
*
******************************************************************************/
-int wl_tx_port1( struct sk_buff *skb, struct net_device *dev )
+int wl_tx_port1(struct sk_buff *skb, struct net_device *dev)
{
- DBG_TX( DbgInfo, "Tx on Port 1\n" );
- return wl_tx( skb, dev, HCF_PORT_1 );
-} // wl_tx_port1
+ DBG_TX(DbgInfo, "Tx on Port 1\n");
+ return wl_tx(skb, dev, HCF_PORT_1);
+} /* wl_tx_port1 */
+
/*============================================================================*/
/*******************************************************************************
@@ -1291,11 +1299,12 @@ int wl_tx_port1( struct sk_buff *skb, struct net_device *dev )
* N/A
*
******************************************************************************/
-int wl_tx_port2( struct sk_buff *skb, struct net_device *dev )
+int wl_tx_port2(struct sk_buff *skb, struct net_device *dev)
{
- DBG_TX( DbgInfo, "Tx on Port 2\n" );
- return wl_tx( skb, dev, HCF_PORT_2 );
-} // wl_tx_port2
+ DBG_TX(DbgInfo, "Tx on Port 2\n");
+ return wl_tx(skb, dev, HCF_PORT_2);
+} /* wl_tx_port2 */
+
/*============================================================================*/
/*******************************************************************************
@@ -1316,11 +1325,12 @@ int wl_tx_port2( struct sk_buff *skb, struct net_device *dev )
* N/A
*
******************************************************************************/
-int wl_tx_port3( struct sk_buff *skb, struct net_device *dev )
+int wl_tx_port3(struct sk_buff *skb, struct net_device *dev)
{
- DBG_TX( DbgInfo, "Tx on Port 3\n" );
- return wl_tx( skb, dev, HCF_PORT_3 );
-} // wl_tx_port3
+ DBG_TX(DbgInfo, "Tx on Port 3\n");
+ return wl_tx(skb, dev, HCF_PORT_3);
+} /* wl_tx_port3 */
+
/*============================================================================*/
/*******************************************************************************
@@ -1341,11 +1351,12 @@ int wl_tx_port3( struct sk_buff *skb, struct net_device *dev )
* N/A
*
******************************************************************************/
-int wl_tx_port4( struct sk_buff *skb, struct net_device *dev )
+int wl_tx_port4(struct sk_buff *skb, struct net_device *dev)
{
- DBG_TX( DbgInfo, "Tx on Port 4\n" );
- return wl_tx( skb, dev, HCF_PORT_4 );
-} // wl_tx_port4
+ DBG_TX(DbgInfo, "Tx on Port 4\n");
+ return wl_tx(skb, dev, HCF_PORT_4);
+} /* wl_tx_port4 */
+
/*============================================================================*/
/*******************************************************************************
@@ -1366,11 +1377,12 @@ int wl_tx_port4( struct sk_buff *skb, struct net_device *dev )
* N/A
*
******************************************************************************/
-int wl_tx_port5( struct sk_buff *skb, struct net_device *dev )
+int wl_tx_port5(struct sk_buff *skb, struct net_device *dev)
{
- DBG_TX( DbgInfo, "Tx on Port 5\n" );
- return wl_tx( skb, dev, HCF_PORT_5 );
-} // wl_tx_port5
+ DBG_TX(DbgInfo, "Tx on Port 5\n");
+ return wl_tx(skb, dev, HCF_PORT_5);
+} /* wl_tx_port5 */
+
/*============================================================================*/
/*******************************************************************************
@@ -1391,11 +1403,12 @@ int wl_tx_port5( struct sk_buff *skb, struct net_device *dev )
* N/A
*
******************************************************************************/
-int wl_tx_port6( struct sk_buff *skb, struct net_device *dev )
+int wl_tx_port6(struct sk_buff *skb, struct net_device *dev)
{
- DBG_TX( DbgInfo, "Tx on Port 6\n" );
- return wl_tx( skb, dev, HCF_PORT_6 );
-} // wl_tx_port6
+ DBG_TX(DbgInfo, "Tx on Port 6\n");
+ return wl_tx(skb, dev, HCF_PORT_6);
+} /* wl_tx_port6 */
+
/*============================================================================*/
/*******************************************************************************
@@ -1417,50 +1430,52 @@ int wl_tx_port6( struct sk_buff *skb, struct net_device *dev )
* structs in the private adapter structure.
*
******************************************************************************/
-void wl_wds_device_alloc( struct wl_private *lp )
+void wl_wds_device_alloc(struct wl_private *lp)
{
- int count;
+ int count;
- /* WDS support requires additional net_device structs to be allocated,
- so that user space apps can use these virtual devices to specify the
- port on which to Tx/Rx */
- for( count = 0; count < NUM_WDS_PORTS; count++ ) {
- struct net_device *dev_wds = NULL;
+ /* WDS support requires additional net_device structs to be allocated,
+ so that user space apps can use these virtual devices to specify the
+ port on which to Tx/Rx */
+ for (count = 0; count < NUM_WDS_PORTS; count++) {
+ struct net_device *dev_wds = NULL;
+
+ dev_wds = kzalloc(sizeof(struct net_device), GFP_KERNEL);
+ if (!dev_wds)
+ return;
+
+ ether_setup(dev_wds);
+
+ lp->wds_port[count].dev = dev_wds;
+
+ /* Re-use wl_init for all the devices, as it currently does nothing, but
+ * is required. Re-use the stats/tx_timeout handler for all as well; the
+ * WDS port which is requesting these operations can be determined by
+ * the net_device pointer. Set the private member of all devices to point
+ * to the same net_device struct; that way, all information gets
+ * funnelled through the one "real" net_device. Name the WDS ports
+ * "wds<n>"
+ * */
+ lp->wds_port[count].dev->init = &wl_init;
+ lp->wds_port[count].dev->get_stats = &wl_stats;
+ lp->wds_port[count].dev->tx_timeout = &wl_tx_timeout;
+ lp->wds_port[count].dev->watchdog_timeo = TX_TIMEOUT;
+ lp->wds_port[count].dev->priv = lp;
+
+ sprintf(lp->wds_port[count].dev->name, "wds%d", count);
+ }
- dev_wds = kzalloc(sizeof(struct net_device), GFP_KERNEL);
- if (!dev_wds)
- return;
+ /* Register the Tx handlers */
+ lp->wds_port[0].dev->hard_start_xmit = &wl_tx_port1;
+ lp->wds_port[1].dev->hard_start_xmit = &wl_tx_port2;
+ lp->wds_port[2].dev->hard_start_xmit = &wl_tx_port3;
+ lp->wds_port[3].dev->hard_start_xmit = &wl_tx_port4;
+ lp->wds_port[4].dev->hard_start_xmit = &wl_tx_port5;
+ lp->wds_port[5].dev->hard_start_xmit = &wl_tx_port6;
+
+ WL_WDS_NETIF_STOP_QUEUE(lp);
+} /* wl_wds_device_alloc */
- ether_setup( dev_wds );
-
- lp->wds_port[count].dev = dev_wds;
-
- /* Re-use wl_init for all the devices, as it currently does nothing, but
- is required. Re-use the stats/tx_timeout handler for all as well; the
- WDS port which is requesting these operations can be determined by
- the net_device pointer. Set the private member of all devices to point
- to the same net_device struct; that way, all information gets
- funnelled through the one "real" net_device. Name the WDS ports
- "wds<n>" */
- lp->wds_port[count].dev->init = &wl_init;
- lp->wds_port[count].dev->get_stats = &wl_stats;
- lp->wds_port[count].dev->tx_timeout = &wl_tx_timeout;
- lp->wds_port[count].dev->watchdog_timeo = TX_TIMEOUT;
- lp->wds_port[count].dev->priv = lp;
-
- sprintf( lp->wds_port[count].dev->name, "wds%d", count );
- }
-
- /* Register the Tx handlers */
- lp->wds_port[0].dev->hard_start_xmit = &wl_tx_port1;
- lp->wds_port[1].dev->hard_start_xmit = &wl_tx_port2;
- lp->wds_port[2].dev->hard_start_xmit = &wl_tx_port3;
- lp->wds_port[3].dev->hard_start_xmit = &wl_tx_port4;
- lp->wds_port[4].dev->hard_start_xmit = &wl_tx_port5;
- lp->wds_port[5].dev->hard_start_xmit = &wl_tx_port6;
-
- WL_WDS_NETIF_STOP_QUEUE( lp );
-} // wl_wds_device_alloc
/*============================================================================*/
/*******************************************************************************
@@ -1480,26 +1495,27 @@ void wl_wds_device_alloc( struct wl_private *lp )
* N/A
*
******************************************************************************/
-void wl_wds_device_dealloc( struct wl_private *lp )
+void wl_wds_device_dealloc(struct wl_private *lp)
{
- int count;
+ int count;
- for( count = 0; count < NUM_WDS_PORTS; count++ ) {
- struct net_device *dev_wds = NULL;
+ for (count = 0; count < NUM_WDS_PORTS; count++) {
+ struct net_device *dev_wds = NULL;
- dev_wds = lp->wds_port[count].dev;
+ dev_wds = lp->wds_port[count].dev;
- if( dev_wds != NULL ) {
- if( dev_wds->flags & IFF_UP ) {
- dev_close( dev_wds );
- dev_wds->flags &= ~( IFF_UP | IFF_RUNNING );
- }
+ if (dev_wds != NULL) {
+ if (dev_wds->flags & IFF_UP) {
+ dev_close(dev_wds);
+ dev_wds->flags &= ~(IFF_UP | IFF_RUNNING);
+ }
+
+ free_netdev(dev_wds);
+ lp->wds_port[count].dev = NULL;
+ }
+ }
+} /* wl_wds_device_dealloc */
- free_netdev(dev_wds);
- lp->wds_port[count].dev = NULL;
- }
- }
-} // wl_wds_device_dealloc
/*============================================================================*/
/*******************************************************************************
@@ -1520,21 +1536,22 @@ void wl_wds_device_dealloc( struct wl_private *lp )
* N/A
*
******************************************************************************/
-void wl_wds_netif_start_queue( struct wl_private *lp )
+void wl_wds_netif_start_queue(struct wl_private *lp)
{
- int count;
+ int count;
/*------------------------------------------------------------------------*/
- if( lp != NULL ) {
- for( count = 0; count < NUM_WDS_PORTS; count++ ) {
- if( lp->wds_port[count].is_registered &&
- lp->wds_port[count].netif_queue_on == FALSE ) {
- netif_start_queue( lp->wds_port[count].dev );
- lp->wds_port[count].netif_queue_on = TRUE;
- }
- }
- }
-} // wl_wds_netif_start_queue
+ if (lp != NULL) {
+ for (count = 0; count < NUM_WDS_PORTS; count++) {
+ if (lp->wds_port[count].is_registered &&
+ lp->wds_port[count].netif_queue_on == FALSE) {
+ netif_start_queue(lp->wds_port[count].dev);
+ lp->wds_port[count].netif_queue_on = TRUE;
+ }
+ }
+ }
+} /* wl_wds_netif_start_queue */
+
/*============================================================================*/
/*******************************************************************************
@@ -1555,21 +1572,22 @@ void wl_wds_netif_start_queue( struct wl_private *lp )
* N/A
*
******************************************************************************/
-void wl_wds_netif_stop_queue( struct wl_private *lp )
+void wl_wds_netif_stop_queue(struct wl_private *lp)
{
- int count;
+ int count;
/*------------------------------------------------------------------------*/
- if( lp != NULL ) {
- for( count = 0; count < NUM_WDS_PORTS; count++ ) {
- if( lp->wds_port[count].is_registered &&
- lp->wds_port[count].netif_queue_on == TRUE ) {
- netif_stop_queue( lp->wds_port[count].dev );
- lp->wds_port[count].netif_queue_on = FALSE;
- }
- }
- }
-} // wl_wds_netif_stop_queue
+ if (lp != NULL) {
+ for (count = 0; count < NUM_WDS_PORTS; count++) {
+ if (lp->wds_port[count].is_registered &&
+ lp->wds_port[count].netif_queue_on == TRUE) {
+ netif_stop_queue(lp->wds_port[count].dev);
+ lp->wds_port[count].netif_queue_on = FALSE;
+ }
+ }
+ }
+} /* wl_wds_netif_stop_queue */
+
/*============================================================================*/
/*******************************************************************************
@@ -1590,21 +1608,22 @@ void wl_wds_netif_stop_queue( struct wl_private *lp )
* N/A
*
******************************************************************************/
-void wl_wds_netif_wake_queue( struct wl_private *lp )
+void wl_wds_netif_wake_queue(struct wl_private *lp)
{
- int count;
+ int count;
/*------------------------------------------------------------------------*/
- if( lp != NULL ) {
- for( count = 0; count < NUM_WDS_PORTS; count++ ) {
- if( lp->wds_port[count].is_registered &&
- lp->wds_port[count].netif_queue_on == FALSE ) {
- netif_wake_queue( lp->wds_port[count].dev );
- lp->wds_port[count].netif_queue_on = TRUE;
- }
- }
- }
-} // wl_wds_netif_wake_queue
+ if (lp != NULL) {
+ for (count = 0; count < NUM_WDS_PORTS; count++) {
+ if (lp->wds_port[count].is_registered &&
+ lp->wds_port[count].netif_queue_on == FALSE) {
+ netif_wake_queue(lp->wds_port[count].dev);
+ lp->wds_port[count].netif_queue_on = TRUE;
+ }
+ }
+ }
+} /* wl_wds_netif_wake_queue */
+
/*============================================================================*/
/*******************************************************************************
@@ -1625,19 +1644,19 @@ void wl_wds_netif_wake_queue( struct wl_private *lp )
* N/A
*
******************************************************************************/
-void wl_wds_netif_carrier_on( struct wl_private *lp )
+void wl_wds_netif_carrier_on(struct wl_private *lp)
{
- int count;
+ int count;
/*------------------------------------------------------------------------*/
- if( lp != NULL ) {
- for( count = 0; count < NUM_WDS_PORTS; count++ ) {
- if( lp->wds_port[count].is_registered ) {
- netif_carrier_on( lp->wds_port[count].dev );
- }
- }
- }
-} // wl_wds_netif_carrier_on
+ if (lp != NULL) {
+ for (count = 0; count < NUM_WDS_PORTS; count++) {
+ if (lp->wds_port[count].is_registered)
+ netif_carrier_on(lp->wds_port[count].dev);
+ }
+ }
+} /* wl_wds_netif_carrier_on */
+
/*============================================================================*/
/*******************************************************************************
@@ -1658,21 +1677,22 @@ void wl_wds_netif_carrier_on( struct wl_private *lp )
* N/A
*
******************************************************************************/
-void wl_wds_netif_carrier_off( struct wl_private *lp )
+void wl_wds_netif_carrier_off(struct wl_private *lp)
{
int count;
- if(lp != NULL) {
- for(count = 0; count < NUM_WDS_PORTS; count++) {
- if(lp->wds_port[count].is_registered)
+ if (lp != NULL) {
+ for (count = 0; count < NUM_WDS_PORTS; count++) {
+ if (lp->wds_port[count].is_registered)
netif_carrier_off(lp->wds_port[count].dev);
}
}
-} // wl_wds_netif_carrier_off
+} /* wl_wds_netif_carrier_off */
+
/*============================================================================*/
-#endif /* USE_WDS */
+#endif /* USE_WDS */
#ifdef ENABLE_DMA
/*******************************************************************************
@@ -1695,70 +1715,71 @@ void wl_wds_netif_carrier_off( struct wl_private *lp )
* 1 on error
*
******************************************************************************/
-int wl_send_dma( struct wl_private *lp, struct sk_buff *skb, int port )
+int wl_send_dma(struct wl_private *lp, struct sk_buff *skb, int port)
{
- int len;
- DESC_STRCT *desc = NULL;
- DESC_STRCT *desc_next = NULL;
+ int len;
+ DESC_STRCT *desc = NULL;
+ DESC_STRCT *desc_next = NULL;
/*------------------------------------------------------------------------*/
- if( lp == NULL ) {
- DBG_ERROR( DbgInfo, "Private adapter struct is NULL\n" );
- return FALSE;
- }
+ if (lp == NULL) {
+ DBG_ERROR(DbgInfo, "Private adapter struct is NULL\n");
+ return FALSE;
+ }
- if( lp->dev == NULL ) {
- DBG_ERROR( DbgInfo, "net_device struct in wl_private is NULL\n" );
- return FALSE;
- }
+ if (lp->dev == NULL) {
+ DBG_ERROR(DbgInfo, "net_device struct in wl_private is NULL\n");
+ return FALSE;
+ }
- /* AGAIN, ALL THE QUEUEING DONE HERE IN I/O MODE IS NOT PERFORMED */
+ /* AGAIN, ALL THE QUEUEING DONE HERE IN I/O MODE IS NOT PERFORMED */
- if( skb == NULL ) {
- DBG_WARNING (DbgInfo, "Nothing to send.\n");
- return FALSE;
- }
+ if (skb == NULL) {
+ DBG_WARNING(DbgInfo, "Nothing to send.\n");
+ return FALSE;
+ }
- len = skb->len;
+ len = skb->len;
- /* Get a free descriptor */
- desc = wl_pci_dma_get_tx_packet( lp );
+ /* Get a free descriptor */
+ desc = wl_pci_dma_get_tx_packet(lp);
- if( desc == NULL ) {
- if( lp->netif_queue_on == TRUE ) {
- netif_stop_queue( lp->dev );
- WL_WDS_NETIF_STOP_QUEUE( lp );
- lp->netif_queue_on = FALSE;
+ if (desc == NULL) {
+ if (lp->netif_queue_on == TRUE) {
+ netif_stop_queue(lp->dev);
+ WL_WDS_NETIF_STOP_QUEUE(lp);
+ lp->netif_queue_on = FALSE;
- dev_kfree_skb( skb );
- return 0;
- }
- }
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ }
+
+ SET_BUF_CNT(desc, /*HCF_DMA_FD_CNT */ HFS_ADDR_DEST);
+ SET_BUF_SIZE(desc, HCF_DMA_TX_BUF1_SIZE);
- SET_BUF_CNT( desc, /*HCF_DMA_FD_CNT*/HFS_ADDR_DEST );
- SET_BUF_SIZE( desc, HCF_DMA_TX_BUF1_SIZE );
+ desc_next = desc->next_desc_addr;
- desc_next = desc->next_desc_addr;
+ if (desc_next->buf_addr == NULL) {
+ DBG_ERROR(DbgInfo, "DMA descriptor buf_addr is NULL\n");
+ return FALSE;
+ }
- if( desc_next->buf_addr == NULL ) {
- DBG_ERROR( DbgInfo, "DMA descriptor buf_addr is NULL\n" );
- return FALSE;
- }
+ /* Copy the payload into the DMA packet */
+ memcpy(desc_next->buf_addr, skb->data, len);
- /* Copy the payload into the DMA packet */
- memcpy( desc_next->buf_addr, skb->data, len );
+ SET_BUF_CNT(desc_next, len);
+ SET_BUF_SIZE(desc_next, HCF_MAX_PACKET_SIZE);
- SET_BUF_CNT( desc_next, len );
- SET_BUF_SIZE( desc_next, HCF_MAX_PACKET_SIZE );
+ hcf_dma_tx_put(&(lp->hcfCtx), desc, 0);
- hcf_dma_tx_put( &( lp->hcfCtx ), desc, 0 );
+ /* Free the skb and perform queue cleanup, as the buffer was
+ transmitted successfully */
+ dev_kfree_skb(skb);
- /* Free the skb and perform queue cleanup, as the buffer was
- transmitted successfully */
- dev_kfree_skb( skb );
+ return TRUE;
+} /* wl_send_dma */
- return TRUE;
-} // wl_send_dma
/*============================================================================*/
/*******************************************************************************
@@ -1779,147 +1800,152 @@ int wl_send_dma( struct wl_private *lp, struct sk_buff *skb, int port )
* 1 on error
*
******************************************************************************/
-int wl_rx_dma( struct net_device *dev )
+int wl_rx_dma(struct net_device *dev)
{
- int port;
- hcf_16 pktlen;
- hcf_16 hfs_stat;
- struct sk_buff *skb;
- struct wl_private *lp = NULL;
- DESC_STRCT *desc, *desc_next;
- //CFG_MB_INFO_RANGE2_STRCT x;
+ int port;
+ hcf_16 pktlen;
+ hcf_16 hfs_stat;
+ struct sk_buff *skb;
+ struct wl_private *lp = NULL;
+ DESC_STRCT *desc, *desc_next;
/*------------------------------------------------------------------------*/
- DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
+ DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
- if((( lp = dev->priv ) != NULL ) &&
- !( lp->flags & WVLAN2_UIL_BUSY )) {
+ lp = dev->priv;
+ if ((lp != NULL) && !(lp->flags & WVLAN2_UIL_BUSY)) {
#ifdef USE_RTS
- if( lp->useRTS == 1 ) {
- DBG_PRINT( "RTS: We're getting an Rx...\n" );
- return -EIO;
- }
-#endif /* USE_RTS */
-
- //if( lp->dma.status == 0 )
- //{
- desc = hcf_dma_rx_get( &( lp->hcfCtx ));
-
- if( desc != NULL )
- {
- /* Check and see if we rcvd. a WMP frame */
- /*
- if((( *(hcf_8 *)&desc->buf_addr[HFS_STAT] ) &
- ( HFS_STAT_MSG_TYPE | HFS_STAT_ERR )) == HFS_STAT_WMP_MSG )
- {
- DBG_TRACE( DbgInfo, "Got a WMP frame\n" );
-
- x.len = sizeof( CFG_MB_INFO_RANGE2_STRCT ) / sizeof( hcf_16 );
- x.typ = CFG_MB_INFO;
- x.base_typ = CFG_WMP;
- x.frag_cnt = 2;
- x.frag_buf[0].frag_len = GET_BUF_CNT( descp ) / sizeof( hcf_16 );
- x.frag_buf[0].frag_addr = (hcf_8 *) descp->buf_addr ;
- x.frag_buf[1].frag_len = ( GET_BUF_CNT( descp->next_desc_addr ) + 1 ) / sizeof( hcf_16 );
- x.frag_buf[1].frag_addr = (hcf_8 *) descp->next_desc_addr->buf_addr ;
-
- hcf_put_info( &( lp->hcfCtx ), (LTVP)&x );
- }
- */
-
- desc_next = desc->next_desc_addr;
-
- /* Make sure the buffer isn't empty */
- if( GET_BUF_CNT( desc ) == 0 ) {
- DBG_WARNING( DbgInfo, "Buffer is empty!\n" );
-
- /* Give the descriptor back to the HCF */
- hcf_dma_rx_put( &( lp->hcfCtx ), desc );
- return -EIO;
- }
-
- /* Read the HFS_STAT register from the lookahead buffer */
- hfs_stat = (hcf_16)( desc->buf_addr[HFS_STAT/2] );
-
- /* Make sure the frame isn't bad */
- if(( hfs_stat & HFS_STAT_ERR ) != HCF_SUCCESS )
- {
- DBG_WARNING( DbgInfo, "HFS_STAT_ERROR (0x%x) in Rx Packet\n",
- desc->buf_addr[HFS_STAT/2] );
-
- /* Give the descriptor back to the HCF */
- hcf_dma_rx_put( &( lp->hcfCtx ), desc );
- return -EIO;
- }
-
- /* Determine what port this packet is for */
- port = ( hfs_stat >> 8 ) & 0x0007;
- DBG_RX( DbgInfo, "Rx frame for port %d\n", port );
-
- pktlen = GET_BUF_CNT(desc_next);
- if (pktlen != 0) {
- skb = ALLOC_SKB(pktlen);
- if (skb != NULL) {
- switch( port ) {
+ if (lp->useRTS == 1) {
+ DBG_PRINT("RTS: We're getting an Rx...\n");
+ return -EIO;
+ }
+#endif /* USE_RTS */
+
+ /*
+ *if( lp->dma.status == 0 )
+ *{
+ */
+ desc = hcf_dma_rx_get(&(lp->hcfCtx));
+
+ if (desc != NULL) {
+ /* Check and see if we rcvd. a WMP frame */
+ /*
+ if((( *(hcf_8 *)&desc->buf_addr[HFS_STAT] ) &
+ ( HFS_STAT_MSG_TYPE | HFS_STAT_ERR )) == HFS_STAT_WMP_MSG )
+ {
+ DBG_TRACE( DbgInfo, "Got a WMP frame\n" );
+
+ x.len = sizeof( CFG_MB_INFO_RANGE2_STRCT ) / sizeof( hcf_16 );
+ x.typ = CFG_MB_INFO;
+ x.base_typ = CFG_WMP;
+ x.frag_cnt = 2;
+ x.frag_buf[0].frag_len = GET_BUF_CNT( descp ) / sizeof( hcf_16 );
+ x.frag_buf[0].frag_addr = (hcf_8 *) descp->buf_addr ;
+ x.frag_buf[1].frag_len = ( GET_BUF_CNT( descp->next_desc_addr ) + 1 ) / sizeof( hcf_16 );
+ x.frag_buf[1].frag_addr = (hcf_8 *) descp->next_desc_addr->buf_addr ;
+
+ hcf_put_info( &( lp->hcfCtx ), (LTVP)&x );
+ }
+ */
+
+ desc_next = desc->next_desc_addr;
+
+ /* Make sure the buffer isn't empty */
+ if (GET_BUF_CNT(desc) == 0) {
+ DBG_WARNING(DbgInfo, "Buffer is empty!\n");
+
+ /* Give the descriptor back to the HCF */
+ hcf_dma_rx_put(&(lp->hcfCtx), desc);
+ return -EIO;
+ }
+
+ /* Read the HFS_STAT register from the lookahead buffer */
+ hfs_stat = (hcf_16) (desc->buf_addr[HFS_STAT / 2]);
+
+ /* Make sure the frame isn't bad */
+ if ((hfs_stat & HFS_STAT_ERR) != HCF_SUCCESS) {
+ DBG_WARNING(DbgInfo,
+ "HFS_STAT_ERROR (0x%x) in Rx Packet\n",
+ desc->buf_addr[HFS_STAT / 2]);
+
+ /* Give the descriptor back to the HCF */
+ hcf_dma_rx_put(&(lp->hcfCtx), desc);
+ return -EIO;
+ }
+
+ /* Determine what port this packet is for */
+ port = (hfs_stat >> 8) & 0x0007;
+ DBG_RX(DbgInfo, "Rx frame for port %d\n", port);
+
+ pktlen = GET_BUF_CNT(desc_next);
+ if (pktlen != 0) {
+ skb = ALLOC_SKB(pktlen);
+ if (skb != NULL) {
+ switch (port) {
#ifdef USE_WDS
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- skb->dev = lp->wds_port[port-1].dev;
- break;
-#endif /* USE_WDS */
-
- case 0:
- default:
- skb->dev = dev;
- break;
- }
-
- GET_PACKET_DMA( skb->dev, skb, pktlen );
-
- /* Give the descriptor back to the HCF */
- hcf_dma_rx_put( &( lp->hcfCtx ), desc );
-
- netif_rx( skb );
-
- if( port == 0 ) {
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pktlen;
- }
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ skb->dev =
+ lp->wds_port[port - 1].dev;
+ break;
+#endif /* USE_WDS */
+
+ case 0:
+ default:
+ skb->dev = dev;
+ break;
+ }
+
+ GET_PACKET_DMA(skb->dev, skb, pktlen);
+
+ /* Give the descriptor back to the HCF */
+ hcf_dma_rx_put(&(lp->hcfCtx), desc);
+
+ netif_rx(skb);
+
+ if (port == 0) {
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes += pktlen;
+ }
#ifdef USE_WDS
- else
- {
- lp->wds_port[port-1].stats.rx_packets++;
- lp->wds_port[port-1].stats.rx_bytes += pktlen;
- }
-#endif /* USE_WDS */
-
- dev->last_rx = jiffies;
-
- } else {
- DBG_ERROR( DbgInfo, "Could not alloc skb\n" );
-
- if( port == 0 )
- {
- lp->stats.rx_dropped++;
- }
+ else {
+ lp->wds_port[port -
+ 1].stats.
+ rx_packets++;
+ lp->wds_port[port -
+ 1].stats.
+ rx_bytes += pktlen;
+ }
+#endif /* USE_WDS */
+
+ dev->last_rx = jiffies;
+
+ } else {
+ DBG_ERROR(DbgInfo,
+ "Could not alloc skb\n");
+
+ if (port == 0)
+ lp->stats.rx_dropped++;
#ifdef USE_WDS
- else
- {
- lp->wds_port[port-1].stats.rx_dropped++;
- }
-#endif /* USE_WDS */
- }
- }
- }
- //}
- }
-
- return 0;
-} // wl_rx_dma
+ else {
+ lp->wds_port[port -
+ 1].stats.
+ rx_dropped++;
+ }
+#endif /* USE_WDS */
+ }
+ }
+ }
+ /*}*/
+ }
+
+ return 0;
+} /* wl_rx_dma */
+
/*============================================================================*/
-#endif // ENABLE_DMA
+#endif /* ENABLE_DMA */
diff --git a/drivers/staging/wlags49_h2/wl_util.c b/drivers/staging/wlags49_h2/wl_util.c
index 4ca6e42ecd7e..75019c171d57 100644
--- a/drivers/staging/wlags49_h2/wl_util.c
+++ b/drivers/staging/wlags49_h2/wl_util.c
@@ -161,43 +161,6 @@ int dbm( int value )
-
-/*******************************************************************************
- * percent()
- *******************************************************************************
- *
- * DESCRIPTION:
- *
- * Return a value as a percentage of min to max.
- *
- * PARAMETERS:
- *
- * value - the value in question
- * min - the minimum range value
- * max - the maximum range value
- *
- * RETURNS:
- *
- * the percentage value
- *
- ******************************************************************************/
-int percent( int value, int min, int max )
-{
- /* Truncate the value to be between min and max. */
- if( value < min )
- value = min;
-
- if( value > max )
- value = max;
-
- /* Return the value as a percentage of min to max. */
- return ((( value - min ) * 100 ) / ( max - min ));
-} // percent
-/*============================================================================*/
-
-
-
-
/*******************************************************************************
* is_valid_key_string()
*******************************************************************************
diff --git a/drivers/staging/wlags49_h2/wl_wext.c b/drivers/staging/wlags49_h2/wl_wext.c
index 187fc060de26..49eeeaee664b 100644
--- a/drivers/staging/wlags49_h2/wl_wext.c
+++ b/drivers/staging/wlags49_h2/wl_wext.c
@@ -3354,7 +3354,7 @@ void wl_wext_event_essid( struct net_device *dev )
the call to wireless_send_event() must also point to where the ESSID
lives */
wrqu.essid.length = strlen( lp->NetworkName );
- wrqu.essid.pointer = (caddr_t)lp->NetworkName;
+ wrqu.essid.pointer = (void __user *)lp->NetworkName;
wrqu.essid.flags = 1;
wireless_send_event( dev, SIOCSIWESSID, &wrqu, lp->NetworkName );
@@ -3419,7 +3419,7 @@ void wl_wext_event_encode( struct net_device *dev )
/* Only provide the key if permissions allow */
if( capable( CAP_NET_ADMIN )) {
- wrqu.encoding.pointer = (caddr_t)lp->DefaultKeys.key[index].key;
+ wrqu.encoding.pointer = (void __user *)lp->DefaultKeys.key[index].key;
wrqu.encoding.length = lp->DefaultKeys.key[index].len;
} else {
wrqu.encoding.flags |= IW_ENCODE_NOKEY;
@@ -3778,7 +3778,7 @@ static const iw_handler wl_private_handler[] =
#endif
};
-struct iw_priv_args wl_priv_args[] = {
+static struct iw_priv_args wl_priv_args[] = {
{SIOCSIWNETNAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "snetwork_name" },
{SIOCGIWNETNAME, 0, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, "gnetwork_name" },
{SIOCSIWSTANAME, IW_PRIV_TYPE_CHAR | HCF_MAX_NAME_LEN, 0, "sstation_name" },
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index a7d24c95191d..f76f95c29617 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -400,6 +400,8 @@ static int prism2_scan(struct wiphy *wiphy,
numbss = msg1.numbss.data;
for (i = 0; i < numbss; i++) {
+ int freq;
+
memset(&msg2, 0, sizeof(msg2));
msg2.msgcode = DIDmsg_dot11req_scan_results;
msg2.bssindex.data = i;
@@ -414,9 +416,10 @@ static int prism2_scan(struct wiphy *wiphy,
ie_buf[1] = msg2.ssid.data.len;
ie_len = ie_buf[1] + 2;
memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len);
+ freq = ieee80211_channel_to_frequency(msg2.dschannel.data,
+ IEEE80211_BAND_2GHZ);
bss = cfg80211_inform_bss(wiphy,
- ieee80211_get_channel(wiphy,
- ieee80211_dsss_chan_to_freq(msg2.dschannel.data)),
+ ieee80211_get_channel(wiphy, freq),
(const u8 *) &(msg2.bssid.data.data),
msg2.timestamp.data, msg2.capinfo.data,
msg2.beaconperiod.data,
@@ -746,7 +749,7 @@ static const struct cfg80211_ops prism2_usb_cfg_ops = {
/* Functions to create/free wiphy interface */
-struct wiphy *wlan_create_wiphy(struct device *dev, wlandevice_t *wlandev)
+static struct wiphy *wlan_create_wiphy(struct device *dev, wlandevice_t *wlandev)
{
struct wiphy *wiphy;
struct prism2_wiphy_private *priv;
@@ -783,7 +786,7 @@ struct wiphy *wlan_create_wiphy(struct device *dev, wlandevice_t *wlandev)
}
-void wlan_free_wiphy(struct wiphy *wiphy)
+static void wlan_free_wiphy(struct wiphy *wiphy)
{
wiphy_unregister(wiphy);
wiphy_free(wiphy);
diff --git a/drivers/staging/wlan-ng/hfa384x.h b/drivers/staging/wlan-ng/hfa384x.h
index 333a2f693e49..1f2c78cc0086 100644
--- a/drivers/staging/wlan-ng/hfa384x.h
+++ b/drivers/staging/wlan-ng/hfa384x.h
@@ -531,14 +531,14 @@ typedef struct hfa384x_rx_frame {
u16 reserved2;
/*-- 802.11 Header Information (802.11 byte order) --*/
- u16 frame_control;
+ __le16 frame_control;
u16 duration_id;
u8 address1[6];
u8 address2[6];
u8 address3[6];
u16 sequence_control;
u8 address4[6];
- u16 data_len; /* hfa384x (little endian) format */
+ __le16 data_len; /* hfa384x (little endian) format */
/*-- 802.3 Header Information --*/
u8 dest_addr[6];
diff --git a/drivers/staging/wlan-ng/p80211mgmt.h b/drivers/staging/wlan-ng/p80211mgmt.h
index 2610824d36d7..3dd066ac034e 100644
--- a/drivers/staging/wlan-ng/p80211mgmt.h
+++ b/drivers/staging/wlan-ng/p80211mgmt.h
@@ -91,7 +91,7 @@
* fall at the end of their respective frames).
* 5a) The length field is set to include the last of the fixed and fixed
* length fields. It may have to be updated for optional or variable
-* length information elements.
+* length information elements.
* 6) Optional and variable length information elements are special cases
* and must be handled individually by the client code.
* --------------------------------------------------------------------
@@ -219,82 +219,82 @@
/*-- Information Element Types --------------------*/
/* prototype structure, all IEs start with these members */
-typedef struct wlan_ie {
+struct wlan_ie {
u8 eid;
u8 len;
-} __packed wlan_ie_t;
+} __packed;
/*-- Service Set Identity (SSID) -----------------*/
-typedef struct wlan_ie_ssid {
+struct wlan_ie_ssid {
u8 eid;
u8 len;
u8 ssid[1]; /* may be zero, ptrs may overlap */
-} __packed wlan_ie_ssid_t;
+} __packed;
/*-- Supported Rates -----------------------------*/
-typedef struct wlan_ie_supp_rates {
+struct wlan_ie_supp_rates {
u8 eid;
u8 len;
u8 rates[1]; /* had better be at LEAST one! */
-} __packed wlan_ie_supp_rates_t;
+} __packed;
/*-- FH Parameter Set ----------------------------*/
-typedef struct wlan_ie_fh_parms {
+struct wlan_ie_fh_parms {
u8 eid;
u8 len;
u16 dwell;
u8 hopset;
u8 hoppattern;
u8 hopindex;
-} __packed wlan_ie_fh_parms_t;
+} __packed;
/*-- DS Parameter Set ----------------------------*/
-typedef struct wlan_ie_ds_parms {
+struct wlan_ie_ds_parms {
u8 eid;
u8 len;
u8 curr_ch;
-} __packed wlan_ie_ds_parms_t;
+} __packed;
/*-- CF Parameter Set ----------------------------*/
-typedef struct wlan_ie_cf_parms {
+struct wlan_ie_cf_parms {
u8 eid;
u8 len;
u8 cfp_cnt;
u8 cfp_period;
u16 cfp_maxdur;
u16 cfp_durremaining;
-} __packed wlan_ie_cf_parms_t;
+} __packed;
/*-- TIM ------------------------------------------*/
-typedef struct wlan_ie_tim {
+struct wlan_ie_tim {
u8 eid;
u8 len;
u8 dtim_cnt;
u8 dtim_period;
u8 bitmap_ctl;
u8 virt_bm[1];
-} __packed wlan_ie_tim_t;
+} __packed;
/*-- IBSS Parameter Set ---------------------------*/
-typedef struct wlan_ie_ibss_parms {
+struct wlan_ie_ibss_parms {
u8 eid;
u8 len;
u16 atim_win;
-} __packed wlan_ie_ibss_parms_t;
+} __packed;
/*-- Challenge Text ------------------------------*/
-typedef struct wlan_ie_challenge {
+struct wlan_ie_challenge {
u8 eid;
u8 len;
u8 challenge[1];
-} __packed wlan_ie_challenge_t;
+} __packed;
/*-------------------------------------------------*/
/* Frame Types */
/* prototype structure, all mgmt frame types will start with these members */
-typedef struct wlan_fr_mgmt {
+struct wlan_fr_mgmt {
u16 type;
u16 len; /* DOES NOT include CRC !!!! */
u8 *buf;
@@ -303,10 +303,10 @@ typedef struct wlan_fr_mgmt {
void *priv;
/*-- fixed fields -----------*/
/*-- info elements ----------*/
-} wlan_fr_mgmt_t;
+};
/*-- Beacon ---------------------------------------*/
-typedef struct wlan_fr_beacon {
+struct wlan_fr_beacon {
u16 type;
u16 len;
u8 *buf;
@@ -318,18 +318,18 @@ typedef struct wlan_fr_beacon {
u16 *bcn_int;
u16 *cap_info;
/*-- info elements ----------*/
- wlan_ie_ssid_t *ssid;
- wlan_ie_supp_rates_t *supp_rates;
- wlan_ie_fh_parms_t *fh_parms;
- wlan_ie_ds_parms_t *ds_parms;
- wlan_ie_cf_parms_t *cf_parms;
- wlan_ie_ibss_parms_t *ibss_parms;
- wlan_ie_tim_t *tim;
+ struct wlan_ie_ssid *ssid;
+ struct wlan_ie_supp_rates *supp_rates;
+ struct wlan_ie_fh_parms *fh_parms;
+ struct wlan_ie_ds_parms *ds_parms;
+ struct wlan_ie_cf_parms *cf_parms;
+ struct wlan_ie_ibss_parms *ibss_parms;
+ struct wlan_ie_tim *tim;
-} wlan_fr_beacon_t;
+};
/*-- IBSS ATIM ------------------------------------*/
-typedef struct wlan_fr_ibssatim {
+struct wlan_fr_ibssatim {
u16 type;
u16 len;
u8 *buf;
@@ -342,10 +342,10 @@ typedef struct wlan_fr_ibssatim {
/* this frame type has a null body */
-} wlan_fr_ibssatim_t;
+};
/*-- Disassociation -------------------------------*/
-typedef struct wlan_fr_disassoc {
+struct wlan_fr_disassoc {
u16 type;
u16 len;
u8 *buf;
@@ -357,10 +357,10 @@ typedef struct wlan_fr_disassoc {
/*-- info elements ----------*/
-} wlan_fr_disassoc_t;
+};
/*-- Association Request --------------------------*/
-typedef struct wlan_fr_assocreq {
+struct wlan_fr_assocreq {
u16 type;
u16 len;
u8 *buf;
@@ -371,13 +371,13 @@ typedef struct wlan_fr_assocreq {
u16 *cap_info;
u16 *listen_int;
/*-- info elements ----------*/
- wlan_ie_ssid_t *ssid;
- wlan_ie_supp_rates_t *supp_rates;
+ struct wlan_ie_ssid *ssid;
+ struct wlan_ie_supp_rates *supp_rates;
-} wlan_fr_assocreq_t;
+};
/*-- Association Response -------------------------*/
-typedef struct wlan_fr_assocresp {
+struct wlan_fr_assocresp {
u16 type;
u16 len;
u8 *buf;
@@ -389,12 +389,12 @@ typedef struct wlan_fr_assocresp {
u16 *status;
u16 *aid;
/*-- info elements ----------*/
- wlan_ie_supp_rates_t *supp_rates;
+ struct wlan_ie_supp_rates *supp_rates;
-} wlan_fr_assocresp_t;
+};
/*-- Reassociation Request ------------------------*/
-typedef struct wlan_fr_reassocreq {
+struct wlan_fr_reassocreq {
u16 type;
u16 len;
u8 *buf;
@@ -406,13 +406,13 @@ typedef struct wlan_fr_reassocreq {
u16 *listen_int;
u8 *curr_ap;
/*-- info elements ----------*/
- wlan_ie_ssid_t *ssid;
- wlan_ie_supp_rates_t *supp_rates;
+ struct wlan_ie_ssid *ssid;
+ struct wlan_ie_supp_rates *supp_rates;
-} wlan_fr_reassocreq_t;
+};
/*-- Reassociation Response -----------------------*/
-typedef struct wlan_fr_reassocresp {
+struct wlan_fr_reassocresp {
u16 type;
u16 len;
u8 *buf;
@@ -424,12 +424,12 @@ typedef struct wlan_fr_reassocresp {
u16 *status;
u16 *aid;
/*-- info elements ----------*/
- wlan_ie_supp_rates_t *supp_rates;
+ struct wlan_ie_supp_rates *supp_rates;
-} wlan_fr_reassocresp_t;
+};
/*-- Probe Request --------------------------------*/
-typedef struct wlan_fr_probereq {
+struct wlan_fr_probereq {
u16 type;
u16 len;
u8 *buf;
@@ -438,13 +438,13 @@ typedef struct wlan_fr_probereq {
void *priv;
/*-- fixed fields -----------*/
/*-- info elements ----------*/
- wlan_ie_ssid_t *ssid;
- wlan_ie_supp_rates_t *supp_rates;
+ struct wlan_ie_ssid *ssid;
+ struct wlan_ie_supp_rates *supp_rates;
-} wlan_fr_probereq_t;
+};
/*-- Probe Response -------------------------------*/
-typedef struct wlan_fr_proberesp {
+struct wlan_fr_proberesp {
u16 type;
u16 len;
u8 *buf;
@@ -456,16 +456,16 @@ typedef struct wlan_fr_proberesp {
u16 *bcn_int;
u16 *cap_info;
/*-- info elements ----------*/
- wlan_ie_ssid_t *ssid;
- wlan_ie_supp_rates_t *supp_rates;
- wlan_ie_fh_parms_t *fh_parms;
- wlan_ie_ds_parms_t *ds_parms;
- wlan_ie_cf_parms_t *cf_parms;
- wlan_ie_ibss_parms_t *ibss_parms;
-} wlan_fr_proberesp_t;
+ struct wlan_ie_ssid *ssid;
+ struct wlan_ie_supp_rates *supp_rates;
+ struct wlan_ie_fh_parms *fh_parms;
+ struct wlan_ie_ds_parms *ds_parms;
+ struct wlan_ie_cf_parms *cf_parms;
+ struct wlan_ie_ibss_parms *ibss_parms;
+};
/*-- Authentication -------------------------------*/
-typedef struct wlan_fr_authen {
+struct wlan_fr_authen {
u16 type;
u16 len;
u8 *buf;
@@ -477,12 +477,12 @@ typedef struct wlan_fr_authen {
u16 *auth_seq;
u16 *status;
/*-- info elements ----------*/
- wlan_ie_challenge_t *challenge;
+ struct wlan_ie_challenge *challenge;
-} wlan_fr_authen_t;
+};
/*-- Deauthenication -----------------------------*/
-typedef struct wlan_fr_deauthen {
+struct wlan_fr_deauthen {
u16 type;
u16 len;
u8 *buf;
@@ -494,27 +494,27 @@ typedef struct wlan_fr_deauthen {
/*-- info elements ----------*/
-} wlan_fr_deauthen_t;
-
-void wlan_mgmt_encode_beacon(wlan_fr_beacon_t *f);
-void wlan_mgmt_decode_beacon(wlan_fr_beacon_t *f);
-void wlan_mgmt_encode_disassoc(wlan_fr_disassoc_t *f);
-void wlan_mgmt_decode_disassoc(wlan_fr_disassoc_t *f);
-void wlan_mgmt_encode_assocreq(wlan_fr_assocreq_t *f);
-void wlan_mgmt_decode_assocreq(wlan_fr_assocreq_t *f);
-void wlan_mgmt_encode_assocresp(wlan_fr_assocresp_t *f);
-void wlan_mgmt_decode_assocresp(wlan_fr_assocresp_t *f);
-void wlan_mgmt_encode_reassocreq(wlan_fr_reassocreq_t *f);
-void wlan_mgmt_decode_reassocreq(wlan_fr_reassocreq_t *f);
-void wlan_mgmt_encode_reassocresp(wlan_fr_reassocresp_t *f);
-void wlan_mgmt_decode_reassocresp(wlan_fr_reassocresp_t *f);
-void wlan_mgmt_encode_probereq(wlan_fr_probereq_t *f);
-void wlan_mgmt_decode_probereq(wlan_fr_probereq_t *f);
-void wlan_mgmt_encode_proberesp(wlan_fr_proberesp_t *f);
-void wlan_mgmt_decode_proberesp(wlan_fr_proberesp_t *f);
-void wlan_mgmt_encode_authen(wlan_fr_authen_t *f);
-void wlan_mgmt_decode_authen(wlan_fr_authen_t *f);
-void wlan_mgmt_encode_deauthen(wlan_fr_deauthen_t *f);
-void wlan_mgmt_decode_deauthen(wlan_fr_deauthen_t *f);
+};
+
+void wlan_mgmt_encode_beacon(struct wlan_fr_beacon *f);
+void wlan_mgmt_decode_beacon(struct wlan_fr_beacon *f);
+void wlan_mgmt_encode_disassoc(struct wlan_fr_disassoc *f);
+void wlan_mgmt_decode_disassoc(struct wlan_fr_disassoc *f);
+void wlan_mgmt_encode_assocreq(struct wlan_fr_assocreq *f);
+void wlan_mgmt_decode_assocreq(struct wlan_fr_assocreq *f);
+void wlan_mgmt_encode_assocresp(struct wlan_fr_assocresp *f);
+void wlan_mgmt_decode_assocresp(struct wlan_fr_assocresp *f);
+void wlan_mgmt_encode_reassocreq(struct wlan_fr_reassocreq *f);
+void wlan_mgmt_decode_reassocreq(struct wlan_fr_reassocreq *f);
+void wlan_mgmt_encode_reassocresp(struct wlan_fr_reassocresp *f);
+void wlan_mgmt_decode_reassocresp(struct wlan_fr_reassocresp *f);
+void wlan_mgmt_encode_probereq(struct wlan_fr_probereq *f);
+void wlan_mgmt_decode_probereq(struct wlan_fr_probereq *f);
+void wlan_mgmt_encode_proberesp(struct wlan_fr_proberesp *f);
+void wlan_mgmt_decode_proberesp(struct wlan_fr_proberesp *f);
+void wlan_mgmt_encode_authen(struct wlan_fr_authen *f);
+void wlan_mgmt_decode_authen(struct wlan_fr_authen *f);
+void wlan_mgmt_encode_deauthen(struct wlan_fr_deauthen *f);
+void wlan_mgmt_decode_deauthen(struct wlan_fr_deauthen *f);
#endif /* _P80211MGMT_H */
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index 0039e082507d..e3ae8024d3a4 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -262,7 +262,6 @@ static void p80211netdev_rx_bh(unsigned long arg)
struct sk_buff *skb = NULL;
netdevice_t *dev = wlandev->netdev;
struct p80211_hdr_a3 *hdr;
- u16 fc;
/* Let's empty our our queue */
while ((skb = skb_dequeue(&wlandev->nsd_rxq))) {
@@ -286,8 +285,7 @@ static void p80211netdev_rx_bh(unsigned long arg)
continue;
} else {
hdr = (struct p80211_hdr_a3 *) skb->data;
- fc = le16_to_cpu(hdr->fc);
- if (p80211_rx_typedrop(wlandev, fc)) {
+ if (p80211_rx_typedrop(wlandev, hdr->fc)) {
dev_kfree_skb(skb);
continue;
}
diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c
index 0dfd2a4933ef..2b0c23587dfc 100644
--- a/drivers/staging/wlan-ng/prism2fw.c
+++ b/drivers/staging/wlan-ng/prism2fw.c
@@ -201,7 +201,7 @@ static int validate_identity(void);
* 0 - success
* ~0 - failure
----------------------------------------------------------------*/
-int prism2_fwtry(struct usb_device *udev, wlandevice_t *wlandev)
+static int prism2_fwtry(struct usb_device *udev, wlandevice_t *wlandev)
{
const struct firmware *fw_entry = NULL;
diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c
index 2199f5afbf90..f9ccf2371dba 100644
--- a/drivers/staging/wlan-ng/prism2sta.c
+++ b/drivers/staging/wlan-ng/prism2sta.c
@@ -454,9 +454,8 @@ u32 prism2sta_ifstate(wlandevice_t *wlandev, u32 ifstate)
*/
result = hfa384x_drvr_start(hw);
if (result) {
- printk(KERN_ERR
- "hfa384x_drvr_start() failed,"
- "result=%d\n", (int)result);
+ netdev_err(wlandev->netdev,
+ "hfa384x_drvr_start() failed,result=%d\n", (int)result);
result =
P80211ENUM_resultcode_implementation_failure;
wlandev->msdstate = WLAN_MSD_HWPRESENT;
@@ -499,9 +498,8 @@ u32 prism2sta_ifstate(wlandevice_t *wlandev, u32 ifstate)
*/
result = hfa384x_drvr_start(hw);
if (result) {
- printk(KERN_ERR
- "hfa384x_drvr_start() failed,"
- "result=%d\n", (int)result);
+ netdev_err(wlandev->netdev,
+ "hfa384x_drvr_start() failed,result=%d\n", (int)result);
result =
P80211ENUM_resultcode_implementation_failure;
wlandev->msdstate = WLAN_MSD_HWPRESENT;
@@ -510,9 +508,8 @@ u32 prism2sta_ifstate(wlandevice_t *wlandev, u32 ifstate)
result = prism2sta_getcardinfo(wlandev);
if (result) {
- printk(KERN_ERR
- "prism2sta_getcardinfo() failed,"
- "result=%d\n", (int)result);
+ netdev_err(wlandev->netdev,
+ "prism2sta_getcardinfo() failed,result=%d\n", (int)result);
result =
P80211ENUM_resultcode_implementation_failure;
hfa384x_drvr_stop(hw);
@@ -521,9 +518,8 @@ u32 prism2sta_ifstate(wlandevice_t *wlandev, u32 ifstate)
}
result = prism2sta_globalsetup(wlandev);
if (result) {
- printk(KERN_ERR
- "prism2sta_globalsetup() failed,"
- "result=%d\n", (int)result);
+ netdev_err(wlandev->netdev,
+ "prism2sta_globalsetup() failed,result=%d\n", (int)result);
result =
P80211ENUM_resultcode_implementation_failure;
hfa384x_drvr_stop(hw);
@@ -623,7 +619,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
&hw->ident_nic,
sizeof(hfa384x_compident_t));
if (result) {
- printk(KERN_ERR "Failed to retrieve NICIDENTITY\n");
+ netdev_err(wlandev->netdev, "Failed to retrieve NICIDENTITY\n");
goto failed;
}
@@ -633,7 +629,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
hw->ident_nic.major = le16_to_cpu(hw->ident_nic.major);
hw->ident_nic.minor = le16_to_cpu(hw->ident_nic.minor);
- printk(KERN_INFO "ident: nic h/w: id=0x%02x %d.%d.%d\n",
+ netdev_info(wlandev->netdev, "ident: nic h/w: id=0x%02x %d.%d.%d\n",
hw->ident_nic.id, hw->ident_nic.major,
hw->ident_nic.minor, hw->ident_nic.variant);
@@ -642,7 +638,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
&hw->ident_pri_fw,
sizeof(hfa384x_compident_t));
if (result) {
- printk(KERN_ERR "Failed to retrieve PRIIDENTITY\n");
+ netdev_err(wlandev->netdev, "Failed to retrieve PRIIDENTITY\n");
goto failed;
}
@@ -652,7 +648,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
hw->ident_pri_fw.major = le16_to_cpu(hw->ident_pri_fw.major);
hw->ident_pri_fw.minor = le16_to_cpu(hw->ident_pri_fw.minor);
- printk(KERN_INFO "ident: pri f/w: id=0x%02x %d.%d.%d\n",
+ netdev_info(wlandev->netdev, "ident: pri f/w: id=0x%02x %d.%d.%d\n",
hw->ident_pri_fw.id, hw->ident_pri_fw.major,
hw->ident_pri_fw.minor, hw->ident_pri_fw.variant);
@@ -661,12 +657,12 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
&hw->ident_sta_fw,
sizeof(hfa384x_compident_t));
if (result) {
- printk(KERN_ERR "Failed to retrieve STAIDENTITY\n");
+ netdev_err(wlandev->netdev, "Failed to retrieve STAIDENTITY\n");
goto failed;
}
if (hw->ident_nic.id < 0x8000) {
- printk(KERN_ERR
+ netdev_err(wlandev->netdev,
"FATAL: Card is not an Intersil Prism2/2.5/3\n");
result = -1;
goto failed;
@@ -683,16 +679,16 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
hw->ident_sta_fw.variant &= ~((u16) (BIT(14) | BIT(15)));
if (hw->ident_sta_fw.id == 0x1f) {
- printk(KERN_INFO
+ netdev_info(wlandev->netdev,
"ident: sta f/w: id=0x%02x %d.%d.%d\n",
hw->ident_sta_fw.id, hw->ident_sta_fw.major,
hw->ident_sta_fw.minor, hw->ident_sta_fw.variant);
} else {
- printk(KERN_INFO
+ netdev_info(wlandev->netdev,
"ident: ap f/w: id=0x%02x %d.%d.%d\n",
hw->ident_sta_fw.id, hw->ident_sta_fw.major,
hw->ident_sta_fw.minor, hw->ident_sta_fw.variant);
- printk(KERN_ERR "Unsupported Tertiary AP firmeare loaded!\n");
+ netdev_err(wlandev->netdev, "Unsupported Tertiary AP firmeare loaded!\n");
goto failed;
}
@@ -701,7 +697,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
&hw->cap_sup_mfi,
sizeof(hfa384x_caplevel_t));
if (result) {
- printk(KERN_ERR "Failed to retrieve MFISUPRANGE\n");
+ netdev_err(wlandev->netdev, "Failed to retrieve MFISUPRANGE\n");
goto failed;
}
@@ -713,7 +709,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
hw->cap_sup_mfi.bottom = le16_to_cpu(hw->cap_sup_mfi.bottom);
hw->cap_sup_mfi.top = le16_to_cpu(hw->cap_sup_mfi.top);
- printk(KERN_INFO
+ netdev_info(wlandev->netdev,
"MFI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
hw->cap_sup_mfi.role, hw->cap_sup_mfi.id,
hw->cap_sup_mfi.variant, hw->cap_sup_mfi.bottom,
@@ -724,7 +720,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
&hw->cap_sup_cfi,
sizeof(hfa384x_caplevel_t));
if (result) {
- printk(KERN_ERR "Failed to retrieve CFISUPRANGE\n");
+ netdev_err(wlandev->netdev, "Failed to retrieve CFISUPRANGE\n");
goto failed;
}
@@ -736,7 +732,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
hw->cap_sup_cfi.bottom = le16_to_cpu(hw->cap_sup_cfi.bottom);
hw->cap_sup_cfi.top = le16_to_cpu(hw->cap_sup_cfi.top);
- printk(KERN_INFO
+ netdev_info(wlandev->netdev,
"CFI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
hw->cap_sup_cfi.role, hw->cap_sup_cfi.id,
hw->cap_sup_cfi.variant, hw->cap_sup_cfi.bottom,
@@ -747,7 +743,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
&hw->cap_sup_pri,
sizeof(hfa384x_caplevel_t));
if (result) {
- printk(KERN_ERR "Failed to retrieve PRISUPRANGE\n");
+ netdev_err(wlandev->netdev, "Failed to retrieve PRISUPRANGE\n");
goto failed;
}
@@ -759,7 +755,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
hw->cap_sup_pri.bottom = le16_to_cpu(hw->cap_sup_pri.bottom);
hw->cap_sup_pri.top = le16_to_cpu(hw->cap_sup_pri.top);
- printk(KERN_INFO
+ netdev_info(wlandev->netdev,
"PRI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
hw->cap_sup_pri.role, hw->cap_sup_pri.id,
hw->cap_sup_pri.variant, hw->cap_sup_pri.bottom,
@@ -770,7 +766,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
&hw->cap_sup_sta,
sizeof(hfa384x_caplevel_t));
if (result) {
- printk(KERN_ERR "Failed to retrieve STASUPRANGE\n");
+ netdev_err(wlandev->netdev, "Failed to retrieve STASUPRANGE\n");
goto failed;
}
@@ -783,13 +779,13 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
hw->cap_sup_sta.top = le16_to_cpu(hw->cap_sup_sta.top);
if (hw->cap_sup_sta.id == 0x04) {
- printk(KERN_INFO
+ netdev_info(wlandev->netdev,
"STA:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
hw->cap_sup_sta.role, hw->cap_sup_sta.id,
hw->cap_sup_sta.variant, hw->cap_sup_sta.bottom,
hw->cap_sup_sta.top);
} else {
- printk(KERN_INFO
+ netdev_info(wlandev->netdev,
"AP:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
hw->cap_sup_sta.role, hw->cap_sup_sta.id,
hw->cap_sup_sta.variant, hw->cap_sup_sta.bottom,
@@ -801,7 +797,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
&hw->cap_act_pri_cfi,
sizeof(hfa384x_caplevel_t));
if (result) {
- printk(KERN_ERR "Failed to retrieve PRI_CFIACTRANGES\n");
+ netdev_err(wlandev->netdev, "Failed to retrieve PRI_CFIACTRANGES\n");
goto failed;
}
@@ -813,7 +809,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
hw->cap_act_pri_cfi.bottom = le16_to_cpu(hw->cap_act_pri_cfi.bottom);
hw->cap_act_pri_cfi.top = le16_to_cpu(hw->cap_act_pri_cfi.top);
- printk(KERN_INFO
+ netdev_info(wlandev->netdev,
"PRI-CFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
hw->cap_act_pri_cfi.role, hw->cap_act_pri_cfi.id,
hw->cap_act_pri_cfi.variant, hw->cap_act_pri_cfi.bottom,
@@ -824,7 +820,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
&hw->cap_act_sta_cfi,
sizeof(hfa384x_caplevel_t));
if (result) {
- printk(KERN_ERR "Failed to retrieve STA_CFIACTRANGES\n");
+ netdev_err(wlandev->netdev, "Failed to retrieve STA_CFIACTRANGES\n");
goto failed;
}
@@ -836,7 +832,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
hw->cap_act_sta_cfi.bottom = le16_to_cpu(hw->cap_act_sta_cfi.bottom);
hw->cap_act_sta_cfi.top = le16_to_cpu(hw->cap_act_sta_cfi.top);
- printk(KERN_INFO
+ netdev_info(wlandev->netdev,
"STA-CFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
hw->cap_act_sta_cfi.role, hw->cap_act_sta_cfi.id,
hw->cap_act_sta_cfi.variant, hw->cap_act_sta_cfi.bottom,
@@ -847,7 +843,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
&hw->cap_act_sta_mfi,
sizeof(hfa384x_caplevel_t));
if (result) {
- printk(KERN_ERR "Failed to retrieve STA_MFIACTRANGES\n");
+ netdev_err(wlandev->netdev, "Failed to retrieve STA_MFIACTRANGES\n");
goto failed;
}
@@ -859,7 +855,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
hw->cap_act_sta_mfi.bottom = le16_to_cpu(hw->cap_act_sta_mfi.bottom);
hw->cap_act_sta_mfi.top = le16_to_cpu(hw->cap_act_sta_mfi.top);
- printk(KERN_INFO
+ netdev_info(wlandev->netdev,
"STA-MFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
hw->cap_act_sta_mfi.role, hw->cap_act_sta_mfi.id,
hw->cap_act_sta_mfi.variant, hw->cap_act_sta_mfi.bottom,
@@ -871,9 +867,9 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
if (!result) {
wlan_mkprintstr(snum, HFA384x_RID_NICSERIALNUMBER_LEN,
pstr, sizeof(pstr));
- printk(KERN_INFO "Prism2 card SN: %s\n", pstr);
+ netdev_info(wlandev->netdev, "Prism2 card SN: %s\n", pstr);
} else {
- printk(KERN_ERR "Failed to retrieve Prism2 Card SN\n");
+ netdev_err(wlandev->netdev, "Failed to retrieve Prism2 Card SN\n");
goto failed;
}
@@ -881,7 +877,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CNFOWNMACADDR,
wlandev->netdev->dev_addr, ETH_ALEN);
if (result != 0) {
- printk(KERN_ERR "Failed to retrieve mac address\n");
+ netdev_err(wlandev->netdev, "Failed to retrieve mac address\n");
goto failed;
}
@@ -909,7 +905,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
goto done;
failed:
- printk(KERN_ERR "Failed, result=%d\n", result);
+ netdev_err(wlandev->netdev, "Failed, result=%d\n", result);
done:
return result;
}
@@ -1085,7 +1081,7 @@ static void prism2sta_inf_scanresults(wlandevice_t *wlandev,
HFA384x_RID_JOINREQUEST,
&joinreq, HFA384x_RID_JOINREQUEST_LEN);
if (result) {
- printk(KERN_ERR "setconfig(joinreq) failed, result=%d\n",
+ netdev_err(wlandev->netdev, "setconfig(joinreq) failed, result=%d\n",
result);
}
}
@@ -1226,7 +1222,7 @@ void prism2sta_processing_defer(struct work_struct *data)
*/
netif_carrier_off(wlandev->netdev);
- printk(KERN_INFO "linkstatus=NOTCONNECTED (unhandled)\n");
+ netdev_info(wlandev->netdev, "linkstatus=NOTCONNECTED (unhandled)\n");
break;
case HFA384x_LINK_CONNECTED:
@@ -1253,7 +1249,7 @@ void prism2sta_processing_defer(struct work_struct *data)
if (wlandev->netdev->type == ARPHRD_ETHER) {
u16 portstatus;
- printk(KERN_INFO "linkstatus=CONNECTED\n");
+ netdev_info(wlandev->netdev, "linkstatus=CONNECTED\n");
/* For non-usb devices, we can use the sync versions */
/* Collect the BSSID, and set state to allow tx */
@@ -1315,7 +1311,7 @@ void prism2sta_processing_defer(struct work_struct *data)
* Block Transmits, Ignore receives of data frames
*/
if (wlandev->netdev->type == ARPHRD_ETHER)
- printk(KERN_INFO
+ netdev_info(wlandev->netdev,
"linkstatus=DISCONNECTED (unhandled)\n");
wlandev->macmode = WLAN_MACMODE_NONE;
@@ -1341,7 +1337,7 @@ void prism2sta_processing_defer(struct work_struct *data)
* Indicate Reassociation
* Enable Transmits, Receives and pass up data frames
*/
- printk(KERN_INFO "linkstatus=AP_CHANGE\n");
+ netdev_info(wlandev->netdev, "linkstatus=AP_CHANGE\n");
result = hfa384x_drvr_getconfig(hw,
HFA384x_RID_CURRENTBSSID,
@@ -1383,7 +1379,7 @@ void prism2sta_processing_defer(struct work_struct *data)
* Response:
* Block Transmits, Ignore receives of data frames
*/
- printk(KERN_INFO "linkstatus=AP_OUTOFRANGE (unhandled)\n");
+ netdev_info(wlandev->netdev, "linkstatus=AP_OUTOFRANGE (unhandled)\n");
netif_carrier_off(wlandev->netdev);
@@ -1396,7 +1392,7 @@ void prism2sta_processing_defer(struct work_struct *data)
* Response:
* Enable Transmits, Receives and pass up data frames
*/
- printk(KERN_INFO "linkstatus=AP_INRANGE\n");
+ netdev_info(wlandev->netdev, "linkstatus=AP_INRANGE\n");
hw->link_status = HFA384x_LINK_CONNECTED;
netif_carrier_on(wlandev->netdev);
@@ -1420,10 +1416,10 @@ void prism2sta_processing_defer(struct work_struct *data)
HFA384x_RID_JOINREQUEST,
&joinreq,
HFA384x_RID_JOINREQUEST_LEN);
- printk(KERN_INFO
+ netdev_info(wlandev->netdev,
"linkstatus=ASSOCFAIL (re-submitting join)\n");
} else {
- printk(KERN_INFO "linkstatus=ASSOCFAIL (unhandled)\n");
+ netdev_info(wlandev->netdev, "linkstatus=ASSOCFAIL (unhandled)\n");
}
netif_carrier_off(wlandev->netdev);
@@ -1713,7 +1709,7 @@ static void prism2sta_inf_authreq_defer(wlandevice_t *wlandev,
if (result) {
if (added)
hw->authlist.cnt--;
- printk(KERN_ERR
+ netdev_err(wlandev->netdev,
"setconfig(authenticatestation) failed, result=%d\n",
result);
}
@@ -1928,7 +1924,7 @@ static wlandevice_t *create_wlan(void)
hw = kzalloc(sizeof(hfa384x_t), GFP_KERNEL);
if (!wlandev || !hw) {
- printk(KERN_ERR "%s: Memory allocation failure.\n", dev_info);
+ pr_err("%s: Memory allocation failure.\n", dev_info);
kfree(wlandev);
kfree(hw);
return NULL;
@@ -1980,7 +1976,7 @@ void prism2sta_commsqual_defer(struct work_struct *data)
&hw->qual, HFA384x_RID_DBMCOMMSQUALITY_LEN);
if (result) {
- printk(KERN_ERR "error fetching commsqual\n");
+ netdev_err(wlandev->netdev, "error fetching commsqual\n");
return;
}
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index b3ff603e6225..466804687fc0 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -1754,8 +1754,7 @@ static int xgifb_probe(struct pci_dev *pdev,
dev_err(&pdev->dev, "Unable request memory size %x\n",
xgifb_info->video_size);
dev_err(&pdev->dev,
- "Fatal error: Unable to reserve frame buffer memory. "
- "Is there another framebuffer driver active?\n");
+ "Fatal error: Unable to reserve frame buffer memory. Is there another framebuffer driver active?\n");
ret = -ENODEV;
goto error_disable;
}
@@ -2087,23 +2086,19 @@ static struct pci_driver xgifb_driver = {
module_param(mode, charp, 0);
MODULE_PARM_DESC(mode,
- "Selects the desired default display mode in the format XxYxDepth "
- "(eg. 1024x768x16).");
+ "Selects the desired default display mode in the format XxYxDepth (eg. 1024x768x16).");
module_param(forcecrt2type, charp, 0);
MODULE_PARM_DESC(forcecrt2type,
- "Force the second display output type. Possible values are NONE, "
- "LCD, TV, VGA, SVIDEO or COMPOSITE.");
+ "Force the second display output type. Possible values are NONE, LCD, TV, VGA, SVIDEO or COMPOSITE.");
module_param(vesa, int, 0);
MODULE_PARM_DESC(vesa,
- "Selects the desired default display mode by VESA mode number "
- "(eg. 0x117).");
+ "Selects the desired default display mode by VESA mode number (eg. 0x117).");
module_param(filter, int, 0);
MODULE_PARM_DESC(filter,
- "Selects TV flicker filter type (only for systems with a SiS301 video bridge). "
- "Possible values 0-7. Default: [no filter]).");
+ "Selects TV flicker filter type (only for systems with a SiS301 video bridge). Possible values 0-7. Default: [no filter]).");
static int __init xgifb_init(void)
{
diff --git a/drivers/staging/xillybus/Kconfig b/drivers/staging/xillybus/Kconfig
index 75c38c8c26eb..b53bdf12da0d 100644
--- a/drivers/staging/xillybus/Kconfig
+++ b/drivers/staging/xillybus/Kconfig
@@ -5,6 +5,7 @@
config XILLYBUS
tristate "Xillybus generic FPGA interface"
depends on PCI || (OF_ADDRESS && OF_IRQ)
+ select CRC32
help
Xillybus is a generic interface for peripherals designed on
programmable logic (FPGA). The driver probes the hardware for
@@ -16,7 +17,7 @@ if XILLYBUS
config XILLYBUS_PCIE
tristate "Xillybus over PCIe"
- depends on PCI
+ depends on PCI_MSI
help
Set to M if you want Xillybus to use PCI Express for communicating
with the FPGA.
diff --git a/drivers/staging/xillybus/xillybus_core.c b/drivers/staging/xillybus/xillybus_core.c
index 2ebaf166038c..b0a6696f2da0 100644
--- a/drivers/staging/xillybus/xillybus_core.c
+++ b/drivers/staging/xillybus/xillybus_core.c
@@ -2318,8 +2318,12 @@ static int __init xillybus_init(void)
}
xillybus_wq = alloc_workqueue(xillyname, 0, 0);
+ if (!xillybus_wq) {
+ class_destroy(xillybus_class);
+ rc = -ENOMEM;
+ }
- return 0; /* Success */
+ return rc;
}
static void __exit xillybus_exit(void)
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 7f1a7ce4b771..b83ec378d04f 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -785,7 +785,7 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
spin_unlock_bh(&conn->cmd_lock);
list_for_each_entry_safe(cmd, cmd_p, &ack_list, i_conn_node) {
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
iscsit_free_cmd(cmd, false);
}
}
@@ -3708,7 +3708,7 @@ iscsit_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state
break;
case ISTATE_REMOVE:
spin_lock_bh(&conn->cmd_lock);
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
iscsit_free_cmd(cmd, false);
@@ -4151,7 +4151,7 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
spin_lock_bh(&conn->cmd_lock);
list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
iscsit_increment_maxcmdsn(cmd, sess);
@@ -4196,6 +4196,10 @@ int iscsit_close_connection(
iscsit_stop_timers_for_cmds(conn);
iscsit_stop_nopin_response_timer(conn);
iscsit_stop_nopin_timer(conn);
+
+ if (conn->conn_transport->iscsit_wait_conn)
+ conn->conn_transport->iscsit_wait_conn(conn);
+
iscsit_free_queue_reqs_for_conn(conn);
/*
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
index 33be1fb1df32..4ca8fd2a70db 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.c
+++ b/drivers/target/iscsi/iscsi_target_erl2.c
@@ -138,7 +138,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
list_for_each_entry_safe(cmd, cmd_tmp,
&cr->conn_recovery_cmd_list, i_conn_node) {
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
cmd->conn = NULL;
spin_unlock(&cr->conn_recovery_cmd_lock);
iscsit_free_cmd(cmd, true);
@@ -160,7 +160,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
list_for_each_entry_safe(cmd, cmd_tmp,
&cr->conn_recovery_cmd_list, i_conn_node) {
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
cmd->conn = NULL;
spin_unlock(&cr->conn_recovery_cmd_lock);
iscsit_free_cmd(cmd, true);
@@ -216,7 +216,7 @@ int iscsit_remove_cmd_from_connection_recovery(
}
cr = cmd->cr;
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
return --cr->cmd_count;
}
@@ -297,7 +297,7 @@ int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn)
if (!(cmd->cmd_flags & ICF_OOO_CMDSN))
continue;
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
iscsit_free_cmd(cmd, true);
@@ -335,7 +335,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
/*
* Only perform connection recovery on ISCSI_OP_SCSI_CMD or
* ISCSI_OP_NOOP_OUT opcodes. For all other opcodes call
- * list_del(&cmd->i_conn_node); to release the command to the
+ * list_del_init(&cmd->i_conn_node); to release the command to the
* session pool and remove it from the connection's list.
*
* Also stop the DataOUT timer, which will be restarted after
@@ -351,7 +351,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
" CID: %hu\n", cmd->iscsi_opcode,
cmd->init_task_tag, cmd->cmd_sn, conn->cid);
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
iscsit_free_cmd(cmd, true);
spin_lock_bh(&conn->cmd_lock);
@@ -371,7 +371,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
*/
if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd &&
iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) {
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
iscsit_free_cmd(cmd, true);
spin_lock_bh(&conn->cmd_lock);
@@ -393,7 +393,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
cmd->sess = conn->sess;
- list_del(&cmd->i_conn_node);
+ list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
iscsit_free_all_datain_reqs(cmd);
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
index 39761837608d..44a5471de00f 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.c
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
@@ -137,7 +137,7 @@ struct iscsi_portal_group *iscsit_get_tpg_from_np(
list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) {
spin_lock(&tpg->tpg_state_lock);
- if (tpg->tpg_state == TPG_STATE_FREE) {
+ if (tpg->tpg_state != TPG_STATE_ACTIVE) {
spin_unlock(&tpg->tpg_state_lock);
continue;
}
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index a4489444ffbc..77e6531fb0a1 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -1074,31 +1074,36 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read,
struct scatterlist *psg;
void *paddr, *addr;
unsigned int i, len, left;
- unsigned int offset = 0;
+ unsigned int offset = sg_off;
left = sectors * dev->prot_length;
for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) {
-
- len = min(psg->length, left);
- if (offset >= sg->length) {
- sg = sg_next(sg);
- offset = 0;
- sg_off = sg->offset;
- }
+ unsigned int psg_len, copied = 0;
paddr = kmap_atomic(sg_page(psg)) + psg->offset;
- addr = kmap_atomic(sg_page(sg)) + sg_off;
+ psg_len = min(left, psg->length);
+ while (psg_len) {
+ len = min(psg_len, sg->length - offset);
+ addr = kmap_atomic(sg_page(sg)) + sg->offset + offset;
- if (read)
- memcpy(paddr, addr, len);
- else
- memcpy(addr, paddr, len);
+ if (read)
+ memcpy(paddr + copied, addr, len);
+ else
+ memcpy(addr, paddr + copied, len);
- left -= len;
- offset += len;
+ left -= len;
+ offset += len;
+ copied += len;
+ psg_len -= len;
+
+ if (offset >= sg->length) {
+ sg = sg_next(sg);
+ offset = 0;
+ }
+ kunmap_atomic(addr);
+ }
kunmap_atomic(paddr);
- kunmap_atomic(addr);
}
}
@@ -1163,7 +1168,7 @@ sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
{
struct se_device *dev = cmd->se_dev;
struct se_dif_v1_tuple *sdt;
- struct scatterlist *dsg;
+ struct scatterlist *dsg, *psg = sg;
sector_t sector = start;
void *daddr, *paddr;
int i, j, offset = sg_off;
@@ -1171,14 +1176,14 @@ sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) {
daddr = kmap_atomic(sg_page(dsg)) + dsg->offset;
- paddr = kmap_atomic(sg_page(sg)) + sg->offset;
+ paddr = kmap_atomic(sg_page(psg)) + sg->offset;
for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) {
- if (offset >= sg->length) {
+ if (offset >= psg->length) {
kunmap_atomic(paddr);
- sg = sg_next(sg);
- paddr = kmap_atomic(sg_page(sg)) + sg->offset;
+ psg = sg_next(psg);
+ paddr = kmap_atomic(sg_page(psg)) + psg->offset;
offset = 0;
}
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 24b4f65d8777..2956250b7225 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1601,6 +1601,9 @@ void transport_generic_request_failure(struct se_cmd *cmd,
case TCM_CHECK_CONDITION_ABORT_CMD:
case TCM_CHECK_CONDITION_UNIT_ATTENTION:
case TCM_CHECK_CONDITION_NOT_READY:
+ case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED:
+ case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
+ case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
break;
case TCM_OUT_OF_RESOURCES:
sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 35c066489a19..5f88d767671e 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -136,6 +136,7 @@ config SPEAR_THERMAL
config RCAR_THERMAL
tristate "Renesas R-Car thermal driver"
depends on ARCH_SHMOBILE || COMPILE_TEST
+ depends on HAS_IOMEM
help
Enable this to plug the R-Car thermal sensor driver into the Linux
thermal framework.
@@ -210,8 +211,16 @@ config ACPI_INT3403_THERMAL
tristate "ACPI INT3403 thermal driver"
depends on X86 && ACPI
help
- This driver uses ACPI INT3403 device objects. If present, it will
- register each INT3403 thermal sensor as a thermal zone.
+ Newer laptops and tablets that use ACPI may have thermal sensors
+ outside the core CPU/SOC for thermal safety reasons. These
+ temperature sensors are also exposed for the OS to use via the so
+ called INT3403 ACPI object. This driver will, on devices that have
+ such sensors, expose the temperature information from these sensors
+ to userspace via the normal thermal framework. This means that a wide
+ range of applications and GUI widgets can show this information to
+ the user or use this information for making decisions. For example,
+ the Intel Thermal Daemon can use this information to allow the user
+ to select his laptop to run without turning on the fans.
menu "Texas Instruments thermal drivers"
source "drivers/thermal/ti-soc-thermal/Kconfig"
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 338a88bf6662..71b0ec0c370d 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -56,10 +56,15 @@ static LIST_HEAD(thermal_governor_list);
static DEFINE_MUTEX(thermal_list_lock);
static DEFINE_MUTEX(thermal_governor_lock);
+static struct thermal_governor *def_governor;
+
static struct thermal_governor *__find_governor(const char *name)
{
struct thermal_governor *pos;
+ if (!name || !name[0])
+ return def_governor;
+
list_for_each_entry(pos, &thermal_governor_list, governor_list)
if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
return pos;
@@ -82,17 +87,23 @@ int thermal_register_governor(struct thermal_governor *governor)
if (__find_governor(governor->name) == NULL) {
err = 0;
list_add(&governor->governor_list, &thermal_governor_list);
+ if (!def_governor && !strncmp(governor->name,
+ DEFAULT_THERMAL_GOVERNOR, THERMAL_NAME_LENGTH))
+ def_governor = governor;
}
mutex_lock(&thermal_list_lock);
list_for_each_entry(pos, &thermal_tz_list, node) {
+ /*
+ * only thermal zones with specified tz->tzp->governor_name
+ * may run with tz->govenor unset
+ */
if (pos->governor)
continue;
- if (pos->tzp)
- name = pos->tzp->governor_name;
- else
- name = DEFAULT_THERMAL_GOVERNOR;
+
+ name = pos->tzp->governor_name;
+
if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
pos->governor = governor;
}
@@ -342,8 +353,8 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz)
static void handle_non_critical_trips(struct thermal_zone_device *tz,
int trip, enum thermal_trip_type trip_type)
{
- if (tz->governor)
- tz->governor->throttle(tz, trip);
+ tz->governor ? tz->governor->throttle(tz, trip) :
+ def_governor->throttle(tz, trip);
}
static void handle_critical_trips(struct thermal_zone_device *tz,
@@ -1107,7 +1118,7 @@ __thermal_cooling_device_register(struct device_node *np,
INIT_LIST_HEAD(&cdev->thermal_instances);
cdev->np = np;
cdev->ops = ops;
- cdev->updated = true;
+ cdev->updated = false;
cdev->device.class = &thermal_class;
cdev->devdata = devdata;
dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
@@ -1533,7 +1544,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
if (tz->tzp)
tz->governor = __find_governor(tz->tzp->governor_name);
else
- tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
+ tz->governor = def_governor;
mutex_unlock(&thermal_governor_lock);
diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c
index 972e1c73722a..081fd7e6a9f0 100644
--- a/drivers/thermal/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/x86_pkg_temp_thermal.c
@@ -68,6 +68,10 @@ struct phy_dev_entry {
struct thermal_zone_device *tzone;
};
+static const struct thermal_zone_params pkg_temp_tz_params = {
+ .no_hwmon = true,
+};
+
/* List maintaining number of package instances */
static LIST_HEAD(phy_dev_list);
static DEFINE_MUTEX(phy_dev_list_mutex);
@@ -394,7 +398,6 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
int err;
u32 tj_max;
struct phy_dev_entry *phy_dev_entry;
- char buffer[30];
int thres_count;
u32 eax, ebx, ecx, edx;
u8 *temp;
@@ -440,13 +443,11 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
phy_dev_entry->first_cpu = cpu;
phy_dev_entry->tj_max = tj_max;
phy_dev_entry->ref_cnt = 1;
- snprintf(buffer, sizeof(buffer), "pkg-temp-%d\n",
- phy_dev_entry->phys_proc_id);
- phy_dev_entry->tzone = thermal_zone_device_register(buffer,
+ phy_dev_entry->tzone = thermal_zone_device_register("x86_pkg_temp",
thres_count,
(thres_count == MAX_NUMBER_OF_TRIPS) ?
0x03 : 0x01,
- phy_dev_entry, &tzone_ops, NULL, 0, 0);
+ phy_dev_entry, &tzone_ops, &pkg_temp_tz_params, 0, 0);
if (IS_ERR(phy_dev_entry->tzone)) {
err = PTR_ERR(phy_dev_entry->tzone);
goto err_ret_free;
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 50b46881b6ca..94f9e3a38412 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -31,6 +31,7 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/major.h>
+#include <linux/atomic.h>
#include <linux/sysrq.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -70,6 +71,9 @@ static struct task_struct *hvc_task;
/* Picks up late kicks after list walk but before schedule() */
static int hvc_kicked;
+/* hvc_init is triggered from hvc_alloc, i.e. only when actually used */
+static atomic_t hvc_needs_init __read_mostly = ATOMIC_INIT(-1);
+
static int hvc_init(void);
#ifdef CONFIG_MAGIC_SYSRQ
@@ -851,7 +855,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
int i;
/* We wait until a driver actually comes along */
- if (!hvc_driver) {
+ if (atomic_inc_not_zero(&hvc_needs_init)) {
int err = hvc_init();
if (err)
return ERR_PTR(err);
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index ebd5bff0f5c1..17ee3bf0926b 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -176,9 +176,6 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
": %d chars not inserted to flip buffer!\n",
length - work);
- /*
- * This may sleep if ->low_latency is set
- */
if (work)
tty_flip_buffer_push(&tty->port);
}
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index d15624c1b751..41fe8a047d37 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1900,13 +1900,10 @@ static inline int input_available_p(struct tty_struct *tty, int poll)
struct n_tty_data *ldata = tty->disc_data;
int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1;
- if (ldata->icanon && !L_EXTPROC(tty)) {
- if (ldata->canon_head != ldata->read_tail)
- return 1;
- } else if (read_cnt(ldata) >= amt)
- return 1;
-
- return 0;
+ if (ldata->icanon && !L_EXTPROC(tty))
+ return ldata->canon_head != ldata->read_tail;
+ else
+ return read_cnt(ldata) >= amt;
}
/**
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 69932b7556cf..81f909c2101f 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -1694,6 +1694,10 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
static void serial_unlink_irq_chain(struct uart_8250_port *up)
{
+ /*
+ * yes, some broken gcc emit "warning: 'i' may be used uninitialized"
+ * but no, we are not going to take a patch that assigns NULL below.
+ */
struct irq_info *i;
struct hlist_node *n;
struct hlist_head *h;
@@ -2882,14 +2886,10 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
touch_nmi_watchdog();
- local_irq_save(flags);
- if (port->sysrq) {
- /* serial8250_handle_irq() already took the lock */
- locked = 0;
- } else if (oops_in_progress) {
- locked = spin_trylock(&port->lock);
- } else
- spin_lock(&port->lock);
+ if (port->sysrq || oops_in_progress)
+ locked = spin_trylock_irqsave(&port->lock, flags);
+ else
+ spin_lock_irqsave(&port->lock, flags);
/*
* First save the IER then disable the interrupts
@@ -2921,8 +2921,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
serial8250_modem_status(up);
if (locked)
- spin_unlock(&port->lock);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
}
static int __init serial8250_console_setup(struct console *co, char *options)
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 0ff3e3624d4c..b14bcba96c25 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1366,23 +1366,44 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud = tty_termios_baud_rate(termios);
- unsigned int m = 6912;
- unsigned int n = 15625;
+ unsigned int m, n;
u32 reg;
- /* For baud rates 1M, 2M, 3M and 4M the dividers must be adjusted. */
- if (baud == 1000000 || baud == 2000000 || baud == 4000000) {
+ /*
+ * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the
+ * dividers must be adjusted.
+ *
+ * uartclk = (m / n) * 100 MHz, where m <= n
+ */
+ switch (baud) {
+ case 500000:
+ case 1000000:
+ case 2000000:
+ case 4000000:
m = 64;
n = 100;
-
p->uartclk = 64000000;
- } else if (baud == 3000000) {
+ break;
+ case 3500000:
+ m = 56;
+ n = 100;
+ p->uartclk = 56000000;
+ break;
+ case 1500000:
+ case 3000000:
m = 48;
n = 100;
-
p->uartclk = 48000000;
- } else {
- p->uartclk = 44236800;
+ break;
+ case 2500000:
+ m = 40;
+ n = 100;
+ p->uartclk = 40000000;
+ break;
+ default:
+ m = 2304;
+ n = 3125;
+ p->uartclk = 73728000;
}
/* Reset the clock */
@@ -3449,6 +3470,10 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 921600,
.reg_shift = 2,
},
+ /*
+ * Intel BayTrail HSUART reference clock is 44.2368 MHz at power-on,
+ * but is overridden by byt_set_termios.
+ */
[pbn_byt] = {
.flags = FL_BASE0,
.num_ports = 1,
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index a3815eaed421..2577d67bacb2 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -289,7 +289,7 @@ config SERIAL_MAX3100
MAX3100 chip support
config SERIAL_MAX310X
- bool "MAX310X support"
+ tristate "MAX310X support"
depends on SPI_MASTER
select SERIAL_CORE
select REGMAP_SPI if SPI_MASTER
@@ -708,7 +708,7 @@ config SERIAL_IP22_ZILOG_CONSOLE
config SERIAL_SH_SCI
tristate "SuperH SCI(F) serial port support"
- depends on HAVE_CLK && (SUPERH || ARM || COMPILE_TEST)
+ depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
select SERIAL_CORE
config SERIAL_SH_SCI_NR_UARTS
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index d58783d364e3..d4eda24aa68b 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2154,9 +2154,19 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
amba_ports[i] = uap;
amba_set_drvdata(dev, uap);
+
+ if (!amba_reg.state) {
+ ret = uart_register_driver(&amba_reg);
+ if (ret < 0) {
+ pr_err("Failed to register AMBA-PL011 driver\n");
+ return ret;
+ }
+ }
+
ret = uart_add_one_port(&amba_reg, &uap->port);
if (ret) {
amba_ports[i] = NULL;
+ uart_unregister_driver(&amba_reg);
pl011_dma_remove(uap);
}
out:
@@ -2175,6 +2185,7 @@ static int pl011_remove(struct amba_device *dev)
amba_ports[i] = NULL;
pl011_dma_remove(uap);
+ uart_unregister_driver(&amba_reg);
return 0;
}
@@ -2230,22 +2241,14 @@ static struct amba_driver pl011_driver = {
static int __init pl011_init(void)
{
- int ret;
printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
- ret = uart_register_driver(&amba_reg);
- if (ret == 0) {
- ret = amba_driver_register(&pl011_driver);
- if (ret)
- uart_unregister_driver(&amba_reg);
- }
- return ret;
+ return amba_driver_register(&pl011_driver);
}
static void __exit pl011_exit(void)
{
amba_driver_unregister(&pl011_driver);
- uart_unregister_driver(&amba_reg);
}
/*
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index a49f10d269b2..b0603e1f7d82 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -115,9 +115,6 @@ static void atmel_stop_rx(struct uart_port *port);
#define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR)
#define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR)
-static int (*atmel_open_hook)(struct uart_port *);
-static void (*atmel_close_hook)(struct uart_port *);
-
struct atmel_dma_buffer {
unsigned char *buf;
dma_addr_t dma_addr;
@@ -1555,7 +1552,7 @@ static int atmel_startup(struct uart_port *port)
retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,
tty ? tty->name : "atmel_serial", port);
if (retval) {
- printk("atmel_serial: atmel_startup - Can't get irq\n");
+ dev_err(port->dev, "atmel_startup - Can't get irq\n");
return retval;
}
@@ -1575,17 +1572,6 @@ static int atmel_startup(struct uart_port *port)
if (retval < 0)
atmel_set_ops(port);
}
- /*
- * If there is a specific "open" function (to register
- * control line interrupts)
- */
- if (atmel_open_hook) {
- retval = atmel_open_hook(port);
- if (retval) {
- free_irq(port->irq, port);
- return retval;
- }
- }
/* Save current CSR for comparison in atmel_tasklet_func() */
atmel_port->irq_status_prev = UART_GET_CSR(port);
@@ -1684,13 +1670,6 @@ static void atmel_shutdown(struct uart_port *port)
* Free the interrupt
*/
free_irq(port->irq, port);
-
- /*
- * If there is a specific "close" function (to unregister
- * control line interrupts)
- */
- if (atmel_close_hook)
- atmel_close_hook(port);
}
/*
@@ -1738,7 +1717,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state,
clk_disable_unprepare(atmel_port->clk);
break;
default:
- printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
+ dev_err(port->dev, "atmel_serial: unknown pm %d\n", state);
}
}
@@ -1853,13 +1832,10 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
mode &= ~ATMEL_US_USMODE;
if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
- dev_dbg(port->dev, "Setting UART to RS485\n");
if ((atmel_port->rs485.delay_rts_after_send) > 0)
UART_PUT_TTGR(port,
atmel_port->rs485.delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
- } else {
- dev_dbg(port->dev, "Setting UART to RS232\n");
}
/* set the parity, stop bits and data size */
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
index 78e82b017b92..a47421e4627c 100644
--- a/drivers/tty/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
@@ -30,6 +30,8 @@
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_bcm63xx.h>
+#include <linux/io.h>
+#include <linux/of.h>
#define BCM63XX_NR_UARTS 2
@@ -588,7 +590,7 @@ static int bcm_uart_request_port(struct uart_port *port)
{
unsigned int size;
- size = RSET_UART_SIZE;
+ size = UART_REG_SIZE;
if (!request_mem_region(port->mapbase, size, "bcm63xx")) {
dev_err(port->dev, "Memory region busy\n");
return -EBUSY;
@@ -608,7 +610,7 @@ static int bcm_uart_request_port(struct uart_port *port)
*/
static void bcm_uart_release_port(struct uart_port *port)
{
- release_mem_region(port->mapbase, RSET_UART_SIZE);
+ release_mem_region(port->mapbase, UART_REG_SIZE);
iounmap(port->membase);
}
@@ -805,6 +807,9 @@ static int bcm_uart_probe(struct platform_device *pdev)
struct clk *clk;
int ret;
+ if (pdev->dev.of_node)
+ pdev->id = of_alias_get_id(pdev->dev.of_node, "uart");
+
if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS)
return -EINVAL;
@@ -856,6 +861,12 @@ static int bcm_uart_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id bcm63xx_of_match[] = {
+ { .compatible = "brcm,bcm6345-uart" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, bcm63xx_of_match);
+
/*
* platform driver stuff
*/
@@ -865,6 +876,7 @@ static struct platform_driver bcm_uart_platform_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "bcm63xx_uart",
+ .of_match_table = bcm63xx_of_match,
},
};
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index b0eacb83f831..5e6fdb1ea73b 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -368,11 +368,16 @@ static const struct uart_ops uart_clps711x_ops = {
static void uart_clps711x_console_putchar(struct uart_port *port, int ch)
{
struct clps711x_port *s = dev_get_drvdata(port->dev);
- u32 sysflg = 0;
- do {
+ /* Wait for FIFO is not full */
+ while (1) {
+ u32 sysflg = 0;
+
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
- } while (sysflg & SYSFLG_UTXFF);
+ if (!(sysflg & SYSFLG_UTXFF))
+ break;
+ cond_resched();
+ }
writew(ch, port->membase + UARTDR_OFFSET);
}
@@ -382,14 +387,18 @@ static void uart_clps711x_console_write(struct console *co, const char *c,
{
struct uart_port *port = clps711x_uart.state[co->index].uart_port;
struct clps711x_port *s = dev_get_drvdata(port->dev);
- u32 sysflg = 0;
uart_console_write(port, c, n, uart_clps711x_console_putchar);
/* Wait for transmitter to become empty */
- do {
+ while (1) {
+ u32 sysflg = 0;
+
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
- } while (sysflg & SYSFLG_UBUSY);
+ if (!(sysflg & SYSFLG_UBUSY))
+ break;
+ cond_resched();
+ }
}
static int uart_clps711x_console_setup(struct console *co, char *options)
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 690bdea0a0c1..d567ac5d3af4 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -286,7 +286,6 @@ static struct e100_serial rs_table[] = {
#endif
}, /* ttyS0 */
-#ifndef CONFIG_SVINTO_SIM
{ .baud = DEF_BAUD,
.ioport = (unsigned char *)R_SERIAL1_CTRL,
.irq = 1U << 16, /* uses DMA 8 and 9 */
@@ -447,7 +446,6 @@ static struct e100_serial rs_table[] = {
.dma_in_enabled = 0
#endif
} /* ttyS3 */
-#endif
};
@@ -1035,7 +1033,6 @@ cflag_to_etrax_baud(unsigned int cflag)
static inline void
e100_dtr(struct e100_serial *info, int set)
{
-#ifndef CONFIG_SVINTO_SIM
unsigned char mask = e100_modem_pins[info->line].dtr_mask;
#ifdef SERIAL_DEBUG_IO
@@ -1060,7 +1057,6 @@ e100_dtr(struct e100_serial *info, int set)
info->line, *e100_modem_pins[info->line].dtr_shadow,
E100_DTR_GET(info));
#endif
-#endif
}
/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
@@ -1069,7 +1065,6 @@ e100_dtr(struct e100_serial *info, int set)
static inline void
e100_rts(struct e100_serial *info, int set)
{
-#ifndef CONFIG_SVINTO_SIM
unsigned long flags;
local_irq_save(flags);
info->rx_ctrl &= ~E100_RTS_MASK;
@@ -1079,7 +1074,6 @@ e100_rts(struct e100_serial *info, int set)
#ifdef SERIAL_DEBUG_IO
printk("ser%i rts %i\n", info->line, set);
#endif
-#endif
}
@@ -1087,7 +1081,6 @@ e100_rts(struct e100_serial *info, int set)
static inline void
e100_ri_out(struct e100_serial *info, int set)
{
-#ifndef CONFIG_SVINTO_SIM
/* RI is active low */
{
unsigned char mask = e100_modem_pins[info->line].ri_mask;
@@ -1099,12 +1092,10 @@ e100_ri_out(struct e100_serial *info, int set)
*e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
local_irq_restore(flags);
}
-#endif
}
static inline void
e100_cd_out(struct e100_serial *info, int set)
{
-#ifndef CONFIG_SVINTO_SIM
/* CD is active low */
{
unsigned char mask = e100_modem_pins[info->line].cd_mask;
@@ -1116,27 +1107,22 @@ e100_cd_out(struct e100_serial *info, int set)
*e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
local_irq_restore(flags);
}
-#endif
}
static inline void
e100_disable_rx(struct e100_serial *info)
{
-#ifndef CONFIG_SVINTO_SIM
/* disable the receiver */
info->ioport[REG_REC_CTRL] =
(info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
-#endif
}
static inline void
e100_enable_rx(struct e100_serial *info)
{
-#ifndef CONFIG_SVINTO_SIM
/* enable the receiver */
info->ioport[REG_REC_CTRL] =
(info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
-#endif
}
/* the rx DMA uses both the dma_descr and the dma_eop interrupts */
@@ -1554,24 +1540,6 @@ transmit_chars_dma(struct e100_serial *info)
unsigned int c, sentl;
struct etrax_dma_descr *descr;
-#ifdef CONFIG_SVINTO_SIM
- /* This will output too little if tail is not 0 always since
- * we don't reloop to send the other part. Anyway this SHOULD be a
- * no-op - transmit_chars_dma would never really be called during sim
- * since rs_write does not write into the xmit buffer then.
- */
- if (info->xmit.tail)
- printk("Error in serial.c:transmit_chars-dma(), tail!=0\n");
- if (info->xmit.head != info->xmit.tail) {
- SIMCOUT(info->xmit.buf + info->xmit.tail,
- CIRC_CNT(info->xmit.head,
- info->xmit.tail,
- SERIAL_XMIT_SIZE));
- info->xmit.head = info->xmit.tail; /* move back head */
- info->tr_running = 0;
- }
- return;
-#endif
/* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
*info->oclrintradr =
IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
@@ -1842,13 +1810,6 @@ static void receive_chars_dma(struct e100_serial *info)
struct tty_struct *tty;
unsigned char rstat;
-#ifdef CONFIG_SVINTO_SIM
- /* No receive in the simulator. Will probably be when the rest of
- * the serial interface works, and this piece will just be removed.
- */
- return;
-#endif
-
/* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
*info->iclrintradr =
IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
@@ -1934,12 +1895,6 @@ static int start_recv_dma(struct e100_serial *info)
static void
start_receive(struct e100_serial *info)
{
-#ifdef CONFIG_SVINTO_SIM
- /* No receive in the simulator. Will probably be when the rest of
- * the serial interface works, and this piece will just be removed.
- */
- return;
-#endif
if (info->uses_dma_in) {
/* reset the input dma channel to be sure it works */
@@ -1972,17 +1927,6 @@ tr_interrupt(int irq, void *dev_id)
int i;
int handled = 0;
-#ifdef CONFIG_SVINTO_SIM
- /* No receive in the simulator. Will probably be when the rest of
- * the serial interface works, and this piece will just be removed.
- */
- {
- const char *s = "What? tr_interrupt in simulator??\n";
- SIMCOUT(s,strlen(s));
- }
- return IRQ_HANDLED;
-#endif
-
/* find out the line that caused this irq and get it from rs_table */
ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */
@@ -2021,17 +1965,6 @@ rec_interrupt(int irq, void *dev_id)
int i;
int handled = 0;
-#ifdef CONFIG_SVINTO_SIM
- /* No receive in the simulator. Will probably be when the rest of
- * the serial interface works, and this piece will just be removed.
- */
- {
- const char *s = "What? rec_interrupt in simulator??\n";
- SIMCOUT(s,strlen(s));
- }
- return IRQ_HANDLED;
-#endif
-
/* find out the line that caused this irq and get it from rs_table */
ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */
@@ -2173,10 +2106,6 @@ timed_flush_handler(unsigned long ptr)
struct e100_serial *info;
int i;
-#ifdef CONFIG_SVINTO_SIM
- return;
-#endif
-
for (i = 0; i < NR_PORTS; i++) {
info = rs_table + i;
if (info->uses_dma_in)
@@ -2729,25 +2658,6 @@ startup(struct e100_serial * info)
printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf);
#endif
-#ifdef CONFIG_SVINTO_SIM
- /* Bits and pieces collected from below. Better to have them
- in one ifdef:ed clause than to mix in a lot of ifdefs,
- right? */
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
- info->xmit.head = info->xmit.tail = 0;
- info->first_recv_buffer = info->last_recv_buffer = NULL;
- info->recv_cnt = info->max_recv_cnt = 0;
-
- for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
- info->rec_descr[i].buf = NULL;
-
- /* No real action in the simulator, but may set info important
- to ioctl. */
- change_speed(info);
-#else
-
/*
* Clear the FIFO buffers and disable them
* (they will be reenabled in change_speed())
@@ -2837,8 +2747,6 @@ startup(struct e100_serial * info)
e100_rts(info, 1);
e100_dtr(info, 1);
-#endif /* CONFIG_SVINTO_SIM */
-
info->port.flags |= ASYNC_INITIALIZED;
local_irq_restore(flags);
@@ -2857,7 +2765,6 @@ shutdown(struct e100_serial * info)
struct etrax_recv_buffer *buffer;
int i;
-#ifndef CONFIG_SVINTO_SIM
/* shut down the transmitter and receiver */
DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line));
e100_disable_rx(info);
@@ -2882,8 +2789,6 @@ shutdown(struct e100_serial * info)
info->tr_running = 0;
}
-#endif /* CONFIG_SVINTO_SIM */
-
if (!(info->port.flags & ASYNC_INITIALIZED))
return;
@@ -2995,17 +2900,12 @@ change_speed(struct e100_serial *info)
IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
r_alt_ser_baudrate_shadow &= ~mask;
r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
-#ifndef CONFIG_SVINTO_SIM
*R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
-#endif /* CONFIG_SVINTO_SIM */
info->baud = cflag_to_baud(cflag);
-#ifndef CONFIG_SVINTO_SIM
info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag);
-#endif /* CONFIG_SVINTO_SIM */
}
-#ifndef CONFIG_SVINTO_SIM
/* start with default settings and then fill in changes */
local_irq_save(flags);
/* 8 bit, no/even parity */
@@ -3073,7 +2973,6 @@ change_speed(struct e100_serial *info)
*((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
local_irq_restore(flags);
-#endif /* !CONFIG_SVINTO_SIM */
update_char_time(info);
@@ -3122,11 +3021,6 @@ static int rs_raw_write(struct tty_struct *tty,
count, info->ioport[REG_STATUS]);
#endif
-#ifdef CONFIG_SVINTO_SIM
- /* Really simple. The output is here and now. */
- SIMCOUT(buf, count);
- return count;
-#endif
local_save_flags(flags);
DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
@@ -3463,7 +3357,6 @@ static int
get_lsr_info(struct e100_serial * info, unsigned int *value)
{
unsigned int result = TIOCSER_TEMT;
-#ifndef CONFIG_SVINTO_SIM
unsigned long curr_time = jiffies;
unsigned long curr_time_usec = GET_JIFFIES_USEC();
unsigned long elapsed_usec =
@@ -3474,7 +3367,6 @@ get_lsr_info(struct e100_serial * info, unsigned int *value)
elapsed_usec < 2*info->char_time_usec) {
result = 0;
}
-#endif
if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
@@ -3804,7 +3696,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
e100_disable_serial_data_irq(info);
#endif
-#ifndef CONFIG_SVINTO_SIM
e100_disable_rx(info);
e100_disable_rx_irq(info);
@@ -3816,7 +3707,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
*/
rs_wait_until_sent(tty, HZ);
}
-#endif
shutdown(info);
rs_flush_buffer(tty);
@@ -4479,7 +4369,6 @@ static int __init rs_init(void)
fast_timer_init();
#endif
-#ifndef CONFIG_SVINTO_SIM
#ifndef CONFIG_ETRAX_KGDB
/* Not needed in simulator. May only complicate stuff. */
/* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
@@ -4489,7 +4378,6 @@ static int __init rs_init(void)
panic("%s: Failed to request irq8", __func__);
#endif
-#endif /* CONFIG_SVINTO_SIM */
return 0;
}
diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c
index 0eb5b5673ede..028582e924a5 100644
--- a/drivers/tty/serial/efm32-uart.c
+++ b/drivers/tty/serial/efm32-uart.c
@@ -671,7 +671,10 @@ static int efm32_uart_probe_dt(struct platform_device *pdev,
if (!np)
return 1;
- ret = of_property_read_u32(np, "location", &location);
+ ret = of_property_read_u32(np, "efm32,location", &location);
+ if (ret)
+ /* fall back to old and (wrongly) generic property "location" */
+ ret = of_property_read_u32(np, "location", &location);
if (!ret) {
if (location > 5) {
dev_err(&pdev->dev, "invalid location\n");
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 8978dc9a58b7..c5eb897de9de 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -13,14 +13,19 @@
#define SUPPORT_SYSRQ
#endif
-#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
#include <linux/io.h>
#include <linux/irq.h>
-#include <linux/clk.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/console.h>
+#include <linux/of_dma.h>
#include <linux/serial_core.h>
+#include <linux/slab.h>
#include <linux/tty_flip.h>
/* All registers are 8-bit width */
@@ -112,6 +117,10 @@
#define UARTSFIFO_TXOF 0x02
#define UARTSFIFO_RXUF 0x01
+#define DMA_MAXBURST 16
+#define DMA_MAXBURST_MASK (DMA_MAXBURST - 1)
+#define FSL_UART_RX_DMA_BUFFER_SIZE 64
+
#define DRIVER_NAME "fsl-lpuart"
#define DEV_NAME "ttyLP"
#define UART_NR 6
@@ -121,6 +130,24 @@ struct lpuart_port {
struct clk *clk;
unsigned int txfifo_size;
unsigned int rxfifo_size;
+
+ bool lpuart_dma_use;
+ struct dma_chan *dma_tx_chan;
+ struct dma_chan *dma_rx_chan;
+ struct dma_async_tx_descriptor *dma_tx_desc;
+ struct dma_async_tx_descriptor *dma_rx_desc;
+ dma_addr_t dma_tx_buf_bus;
+ dma_addr_t dma_rx_buf_bus;
+ dma_cookie_t dma_tx_cookie;
+ dma_cookie_t dma_rx_cookie;
+ unsigned char *dma_tx_buf_virt;
+ unsigned char *dma_rx_buf_virt;
+ unsigned int dma_tx_bytes;
+ unsigned int dma_rx_bytes;
+ int dma_tx_in_progress;
+ int dma_rx_in_progress;
+ unsigned int dma_rx_timeout;
+ struct timer_list lpuart_timer;
};
static struct of_device_id lpuart_dt_ids[] = {
@@ -131,6 +158,10 @@ static struct of_device_id lpuart_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
+/* Forward declare this for the dma callbacks*/
+static void lpuart_dma_tx_complete(void *arg);
+static void lpuart_dma_rx_complete(void *arg);
+
static void lpuart_stop_tx(struct uart_port *port)
{
unsigned char temp;
@@ -152,6 +183,210 @@ static void lpuart_enable_ms(struct uart_port *port)
{
}
+static void lpuart_copy_rx_to_tty(struct lpuart_port *sport,
+ struct tty_port *tty, int count)
+{
+ int copied;
+
+ sport->port.icount.rx += count;
+
+ if (!tty) {
+ dev_err(sport->port.dev, "No tty port\n");
+ return;
+ }
+
+ dma_sync_single_for_cpu(sport->port.dev, sport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+ copied = tty_insert_flip_string(tty,
+ ((unsigned char *)(sport->dma_rx_buf_virt)), count);
+
+ if (copied != count) {
+ WARN_ON(1);
+ dev_err(sport->port.dev, "RxData copy to tty layer failed\n");
+ }
+
+ dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+}
+
+static void lpuart_pio_tx(struct lpuart_port *sport)
+{
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ while (!uart_circ_empty(xmit) &&
+ readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) {
+ writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ sport->port.icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
+
+ if (uart_circ_empty(xmit))
+ writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS,
+ sport->port.membase + UARTCR5);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int lpuart_dma_tx(struct lpuart_port *sport, unsigned long count)
+{
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ dma_addr_t tx_bus_addr;
+
+ dma_sync_single_for_device(sport->port.dev, sport->dma_tx_buf_bus,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+ sport->dma_tx_bytes = count & ~(DMA_MAXBURST_MASK);
+ tx_bus_addr = sport->dma_tx_buf_bus + xmit->tail;
+ sport->dma_tx_desc = dmaengine_prep_slave_single(sport->dma_tx_chan,
+ tx_bus_addr, sport->dma_tx_bytes,
+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+
+ if (!sport->dma_tx_desc) {
+ dev_err(sport->port.dev, "Not able to get desc for tx\n");
+ return -EIO;
+ }
+
+ sport->dma_tx_desc->callback = lpuart_dma_tx_complete;
+ sport->dma_tx_desc->callback_param = sport;
+ sport->dma_tx_in_progress = 1;
+ sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc);
+ dma_async_issue_pending(sport->dma_tx_chan);
+
+ return 0;
+}
+
+static void lpuart_prepare_tx(struct lpuart_port *sport)
+{
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ unsigned long count = CIRC_CNT_TO_END(xmit->head,
+ xmit->tail, UART_XMIT_SIZE);
+
+ if (!count)
+ return;
+
+ if (count < DMA_MAXBURST)
+ writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_TDMAS,
+ sport->port.membase + UARTCR5);
+ else {
+ writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS,
+ sport->port.membase + UARTCR5);
+ lpuart_dma_tx(sport, count);
+ }
+}
+
+static void lpuart_dma_tx_complete(void *arg)
+{
+ struct lpuart_port *sport = arg;
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ unsigned long flags;
+
+ async_tx_ack(sport->dma_tx_desc);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1);
+ sport->dma_tx_in_progress = 0;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
+
+ lpuart_prepare_tx(sport);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int lpuart_dma_rx(struct lpuart_port *sport)
+{
+ dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+ sport->dma_rx_desc = dmaengine_prep_slave_single(sport->dma_rx_chan,
+ sport->dma_rx_buf_bus, FSL_UART_RX_DMA_BUFFER_SIZE,
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+
+ if (!sport->dma_rx_desc) {
+ dev_err(sport->port.dev, "Not able to get desc for rx\n");
+ return -EIO;
+ }
+
+ sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
+ sport->dma_rx_desc->callback_param = sport;
+ sport->dma_rx_in_progress = 1;
+ sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc);
+ dma_async_issue_pending(sport->dma_rx_chan);
+
+ return 0;
+}
+
+static void lpuart_dma_rx_complete(void *arg)
+{
+ struct lpuart_port *sport = arg;
+ struct tty_port *port = &sport->port.state->port;
+ unsigned long flags;
+
+ async_tx_ack(sport->dma_rx_desc);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ sport->dma_rx_in_progress = 0;
+ lpuart_copy_rx_to_tty(sport, port, FSL_UART_RX_DMA_BUFFER_SIZE);
+ tty_flip_buffer_push(port);
+ lpuart_dma_rx(sport);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static void lpuart_timer_func(unsigned long data)
+{
+ struct lpuart_port *sport = (struct lpuart_port *)data;
+ struct tty_port *port = &sport->port.state->port;
+ struct dma_tx_state state;
+ unsigned long flags;
+ unsigned char temp;
+ int count;
+
+ del_timer(&sport->lpuart_timer);
+ dmaengine_pause(sport->dma_rx_chan);
+ dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state);
+ dmaengine_terminate_all(sport->dma_rx_chan);
+ count = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue;
+ async_tx_ack(sport->dma_rx_desc);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ sport->dma_rx_in_progress = 0;
+ lpuart_copy_rx_to_tty(sport, port, count);
+ tty_flip_buffer_push(port);
+ temp = readb(sport->port.membase + UARTCR5);
+ writeb(temp & ~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static inline void lpuart_prepare_rx(struct lpuart_port *sport)
+{
+ unsigned long flags;
+ unsigned char temp;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ init_timer(&sport->lpuart_timer);
+ sport->lpuart_timer.function = lpuart_timer_func;
+ sport->lpuart_timer.data = (unsigned long)sport;
+ sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
+ add_timer(&sport->lpuart_timer);
+
+ lpuart_dma_rx(sport);
+ temp = readb(sport->port.membase + UARTCR5);
+ writeb(temp | UARTCR5_RDMAS, sport->port.membase + UARTCR5);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
{
struct circ_buf *xmit = &sport->port.state->xmit;
@@ -172,14 +407,21 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
static void lpuart_start_tx(struct uart_port *port)
{
- struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct circ_buf *xmit = &sport->port.state->xmit;
unsigned char temp;
temp = readb(port->membase + UARTCR2);
writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
- if (readb(port->membase + UARTSR1) & UARTSR1_TDRE)
- lpuart_transmit_buffer(sport);
+ if (sport->lpuart_dma_use) {
+ if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress)
+ lpuart_prepare_tx(sport);
+ } else {
+ if (readb(port->membase + UARTSR1) & UARTSR1_TDRE)
+ lpuart_transmit_buffer(sport);
+ }
}
static irqreturn_t lpuart_txint(int irq, void *dev_id)
@@ -279,12 +521,19 @@ static irqreturn_t lpuart_int(int irq, void *dev_id)
sts = readb(sport->port.membase + UARTSR1);
- if (sts & UARTSR1_RDRF)
- lpuart_rxint(irq, dev_id);
-
+ if (sts & UARTSR1_RDRF) {
+ if (sport->lpuart_dma_use)
+ lpuart_prepare_rx(sport);
+ else
+ lpuart_rxint(irq, dev_id);
+ }
if (sts & UARTSR1_TDRE &&
- !(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS))
- lpuart_txint(irq, dev_id);
+ !(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) {
+ if (sport->lpuart_dma_use)
+ lpuart_pio_tx(sport);
+ else
+ lpuart_txint(irq, dev_id);
+ }
return IRQ_HANDLED;
}
@@ -366,13 +615,156 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
sport->port.membase + UARTCFIFO);
- writeb(2, sport->port.membase + UARTTWFIFO);
+ writeb(0, sport->port.membase + UARTTWFIFO);
writeb(1, sport->port.membase + UARTRWFIFO);
/* Restore cr2 */
writeb(cr2_saved, sport->port.membase + UARTCR2);
}
+static int lpuart_dma_tx_request(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct dma_chan *tx_chan;
+ struct dma_slave_config dma_tx_sconfig;
+ dma_addr_t dma_bus;
+ unsigned char *dma_buf;
+ int ret;
+
+ tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
+
+ if (!tx_chan) {
+ dev_err(sport->port.dev, "Dma tx channel request failed!\n");
+ return -ENODEV;
+ }
+
+ dma_bus = dma_map_single(tx_chan->device->dev,
+ sport->port.state->xmit.buf,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+
+ if (dma_mapping_error(tx_chan->device->dev, dma_bus)) {
+ dev_err(sport->port.dev, "dma_map_single tx failed\n");
+ dma_release_channel(tx_chan);
+ return -ENOMEM;
+ }
+
+ dma_buf = sport->port.state->xmit.buf;
+ dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR;
+ dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_tx_sconfig.dst_maxburst = DMA_MAXBURST;
+ dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
+ ret = dmaengine_slave_config(tx_chan, &dma_tx_sconfig);
+
+ if (ret < 0) {
+ dev_err(sport->port.dev,
+ "Dma slave config failed, err = %d\n", ret);
+ dma_release_channel(tx_chan);
+ return ret;
+ }
+
+ sport->dma_tx_chan = tx_chan;
+ sport->dma_tx_buf_virt = dma_buf;
+ sport->dma_tx_buf_bus = dma_bus;
+ sport->dma_tx_in_progress = 0;
+
+ return 0;
+}
+
+static int lpuart_dma_rx_request(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct dma_chan *rx_chan;
+ struct dma_slave_config dma_rx_sconfig;
+ dma_addr_t dma_bus;
+ unsigned char *dma_buf;
+ int ret;
+
+ rx_chan = dma_request_slave_channel(sport->port.dev, "rx");
+
+ if (!rx_chan) {
+ dev_err(sport->port.dev, "Dma rx channel request failed!\n");
+ return -ENODEV;
+ }
+
+ dma_buf = devm_kzalloc(sport->port.dev,
+ FSL_UART_RX_DMA_BUFFER_SIZE, GFP_KERNEL);
+
+ if (!dma_buf) {
+ dev_err(sport->port.dev, "Dma rx alloc failed\n");
+ dma_release_channel(rx_chan);
+ return -ENOMEM;
+ }
+
+ dma_bus = dma_map_single(rx_chan->device->dev, dma_buf,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(rx_chan->device->dev, dma_bus)) {
+ dev_err(sport->port.dev, "dma_map_single rx failed\n");
+ dma_release_channel(rx_chan);
+ return -ENOMEM;
+ }
+
+ dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR;
+ dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_rx_sconfig.src_maxburst = 1;
+ dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
+ ret = dmaengine_slave_config(rx_chan, &dma_rx_sconfig);
+
+ if (ret < 0) {
+ dev_err(sport->port.dev,
+ "Dma slave config failed, err = %d\n", ret);
+ dma_release_channel(rx_chan);
+ return ret;
+ }
+
+ sport->dma_rx_chan = rx_chan;
+ sport->dma_rx_buf_virt = dma_buf;
+ sport->dma_rx_buf_bus = dma_bus;
+ sport->dma_rx_in_progress = 0;
+
+ sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) *
+ FSL_UART_RX_DMA_BUFFER_SIZE * 3 /
+ sport->rxfifo_size / 2;
+
+ if (sport->dma_rx_timeout < msecs_to_jiffies(20))
+ sport->dma_rx_timeout = msecs_to_jiffies(20);
+
+ return 0;
+}
+
+static void lpuart_dma_tx_free(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct dma_chan *dma_chan;
+
+ dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+ dma_chan = sport->dma_tx_chan;
+ sport->dma_tx_chan = NULL;
+ sport->dma_tx_buf_bus = 0;
+ sport->dma_tx_buf_virt = NULL;
+ dma_release_channel(dma_chan);
+}
+
+static void lpuart_dma_rx_free(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct dma_chan *dma_chan;
+
+ dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ dma_chan = sport->dma_rx_chan;
+ sport->dma_rx_chan = NULL;
+ sport->dma_rx_buf_bus = 0;
+ sport->dma_rx_buf_virt = NULL;
+ dma_release_channel(dma_chan);
+}
+
static int lpuart_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
@@ -380,6 +772,15 @@ static int lpuart_startup(struct uart_port *port)
unsigned long flags;
unsigned char temp;
+ /*whether use dma support by dma request results*/
+ if (lpuart_dma_tx_request(port) || lpuart_dma_rx_request(port)) {
+ sport->lpuart_dma_use = false;
+ } else {
+ sport->lpuart_dma_use = true;
+ temp = readb(port->membase + UARTCR5);
+ writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5);
+ }
+
ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0,
DRIVER_NAME, sport);
if (ret)
@@ -414,6 +815,11 @@ static void lpuart_shutdown(struct uart_port *port)
spin_unlock_irqrestore(&port->lock, flags);
devm_free_irq(port->dev, port->irq, sport);
+
+ if (sport->lpuart_dma_use) {
+ lpuart_dma_tx_free(port);
+ lpuart_dma_rx_free(port);
+ }
}
static void
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index d799140e53b6..3b6c1a2e25de 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -496,8 +496,7 @@ static void dma_tx_callback(void *data)
dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&sport->port);
+ uart_write_wakeup(&sport->port);
if (waitqueue_active(&sport->dma_wait)) {
wake_up(&sport->dma_wait);
@@ -1117,25 +1116,25 @@ static int imx_startup(struct uart_port *port)
*/
if (sport->txirq > 0) {
retval = request_irq(sport->rxirq, imx_rxint, 0,
- DRIVER_NAME, sport);
+ dev_name(port->dev), sport);
if (retval)
goto error_out1;
retval = request_irq(sport->txirq, imx_txint, 0,
- DRIVER_NAME, sport);
+ dev_name(port->dev), sport);
if (retval)
goto error_out2;
/* do not use RTS IRQ on IrDA */
if (!USE_IRDA(sport)) {
retval = request_irq(sport->rtsirq, imx_rtsint, 0,
- DRIVER_NAME, sport);
+ dev_name(port->dev), sport);
if (retval)
goto error_out3;
}
} else {
retval = request_irq(sport->port.irq, imx_int, 0,
- DRIVER_NAME, sport);
+ dev_name(port->dev), sport);
if (retval) {
free_irq(sport->port.irq, sport);
goto error_out1;
@@ -1470,44 +1469,13 @@ static const char *imx_type(struct uart_port *port)
}
/*
- * Release the memory region(s) being used by 'port'.
- */
-static void imx_release_port(struct uart_port *port)
-{
- struct platform_device *pdev = to_platform_device(port->dev);
- struct resource *mmres;
-
- mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(mmres->start, resource_size(mmres));
-}
-
-/*
- * Request the memory region(s) being used by 'port'.
- */
-static int imx_request_port(struct uart_port *port)
-{
- struct platform_device *pdev = to_platform_device(port->dev);
- struct resource *mmres;
- void *ret;
-
- mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mmres)
- return -ENODEV;
-
- ret = request_mem_region(mmres->start, resource_size(mmres), "imx-uart");
-
- return ret ? 0 : -EBUSY;
-}
-
-/*
* Configure/autoconfigure the port.
*/
static void imx_config_port(struct uart_port *port, int flags)
{
struct imx_port *sport = (struct imx_port *)port;
- if (flags & UART_CONFIG_TYPE &&
- imx_request_port(&sport->port) == 0)
+ if (flags & UART_CONFIG_TYPE)
sport->port.type = PORT_IMX;
}
@@ -1617,8 +1585,6 @@ static struct uart_ops imx_pops = {
.flush_buffer = imx_flush_buffer,
.set_termios = imx_set_termios,
.type = imx_type,
- .release_port = imx_release_port,
- .request_port = imx_request_port,
.config_port = imx_config_port,
.verify_port = imx_verify_port,
#if defined(CONFIG_CONSOLE_POLL)
@@ -1935,7 +1901,6 @@ static void serial_imx_probe_pdata(struct imx_port *sport,
static int serial_imx_probe(struct platform_device *pdev)
{
struct imx_port *sport;
- struct imxuart_platform_data *pdata;
void __iomem *base;
int ret = 0;
struct resource *res;
@@ -1951,12 +1916,9 @@ static int serial_imx_probe(struct platform_device *pdev)
return ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
- base = devm_ioremap(&pdev->dev, res->start, PAGE_SIZE);
- if (!base)
- return -ENOMEM;
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
sport->port.dev = &pdev->dev;
sport->port.mapbase = res->start;
@@ -1992,38 +1954,16 @@ static int serial_imx_probe(struct platform_device *pdev)
imx_ports[sport->port.line] = sport;
- pdata = dev_get_platdata(&pdev->dev);
- if (pdata && pdata->init) {
- ret = pdata->init(pdev);
- if (ret)
- return ret;
- }
-
- ret = uart_add_one_port(&imx_reg, &sport->port);
- if (ret)
- goto deinit;
platform_set_drvdata(pdev, sport);
- return 0;
-deinit:
- if (pdata && pdata->exit)
- pdata->exit(pdev);
- return ret;
+ return uart_add_one_port(&imx_reg, &sport->port);
}
static int serial_imx_remove(struct platform_device *pdev)
{
- struct imxuart_platform_data *pdata;
struct imx_port *sport = platform_get_drvdata(pdev);
- pdata = dev_get_platdata(&pdev->dev);
-
- uart_remove_one_port(&imx_reg, &sport->port);
-
- if (pdata && pdata->exit)
- pdata->exit(pdev);
-
- return 0;
+ return uart_remove_one_port(&imx_reg, &sport->port);
}
static struct platform_driver serial_imx_driver = {
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 8d71e4047bb3..2a99d0c61b9e 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1,7 +1,7 @@
/*
* Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver
*
- * Copyright (C) 2012-2013 Alexander Shiyan <shc_work@mail.ru>
+ * Copyright (C) 2012-2014 Alexander Shiyan <shc_work@mail.ru>
*
* Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
* Based on max3110.c, by Feng Tang <feng.tang@intel.com>
@@ -13,19 +13,21 @@
* (at your option) any later version.
*/
-#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <linux/regmap.h>
-#include <linux/gpio.h>
#include <linux/spi/spi.h>
-
-#include <linux/platform_data/max310x.h>
+#include <linux/uaccess.h>
#define MAX310X_NAME "max310x"
#define MAX310X_MAJOR 204
@@ -161,10 +163,6 @@
/* IRDA register bits */
#define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */
#define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */
-#define MAX310X_IRDA_SHORTIR_BIT (1 << 2) /* Short SIR mode enable */
-#define MAX310X_IRDA_MIR_BIT (1 << 3) /* MIR mode enable */
-#define MAX310X_IRDA_RXINV_BIT (1 << 4) /* RX logic inversion enable */
-#define MAX310X_IRDA_TXINV_BIT (1 << 5) /* TX logic inversion enable */
/* Flow control trigger level register masks */
#define MAX310X_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */
@@ -220,26 +218,6 @@
* XOFF2
*/
-/* GPIO configuration register bits */
-#define MAX310X_GPIOCFG_GP0OUT_BIT (1 << 0) /* GPIO 0 output enable */
-#define MAX310X_GPIOCFG_GP1OUT_BIT (1 << 1) /* GPIO 1 output enable */
-#define MAX310X_GPIOCFG_GP2OUT_BIT (1 << 2) /* GPIO 2 output enable */
-#define MAX310X_GPIOCFG_GP3OUT_BIT (1 << 3) /* GPIO 3 output enable */
-#define MAX310X_GPIOCFG_GP0OD_BIT (1 << 4) /* GPIO 0 open-drain enable */
-#define MAX310X_GPIOCFG_GP1OD_BIT (1 << 5) /* GPIO 1 open-drain enable */
-#define MAX310X_GPIOCFG_GP2OD_BIT (1 << 6) /* GPIO 2 open-drain enable */
-#define MAX310X_GPIOCFG_GP3OD_BIT (1 << 7) /* GPIO 3 open-drain enable */
-
-/* GPIO DATA register bits */
-#define MAX310X_GPIODATA_GP0OUT_BIT (1 << 0) /* GPIO 0 output value */
-#define MAX310X_GPIODATA_GP1OUT_BIT (1 << 1) /* GPIO 1 output value */
-#define MAX310X_GPIODATA_GP2OUT_BIT (1 << 2) /* GPIO 2 output value */
-#define MAX310X_GPIODATA_GP3OUT_BIT (1 << 3) /* GPIO 3 output value */
-#define MAX310X_GPIODATA_GP0IN_BIT (1 << 4) /* GPIO 0 input value */
-#define MAX310X_GPIODATA_GP1IN_BIT (1 << 5) /* GPIO 1 input value */
-#define MAX310X_GPIODATA_GP2IN_BIT (1 << 6) /* GPIO 2 input value */
-#define MAX310X_GPIODATA_GP3IN_BIT (1 << 7) /* GPIO 3 input value */
-
/* PLL configuration register masks */
#define MAX310X_PLLCFG_PREDIV_MASK (0x3f) /* PLL predivision value */
#define MAX310X_PLLCFG_PLLFACTOR_MASK (0xc0) /* PLL multiplication factor */
@@ -283,16 +261,15 @@ struct max310x_devtype {
struct max310x_one {
struct uart_port port;
struct work_struct tx_work;
+ struct work_struct md_work;
};
struct max310x_port {
struct uart_driver uart;
struct max310x_devtype *devtype;
struct regmap *regmap;
- struct regmap_config regcfg;
struct mutex mutex;
- struct max310x_pdata *pdata;
- int gpio_used;
+ struct clk *clk;
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio;
#endif
@@ -504,25 +481,33 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg)
return false;
}
-static void max310x_set_baud(struct uart_port *port, int baud)
+static int max310x_set_baud(struct uart_port *port, int baud)
{
- unsigned int mode = 0, div = port->uartclk / baud;
+ unsigned int mode = 0, clk = port->uartclk, div = clk / baud;
- if (!(div / 16)) {
+ /* Check for minimal value for divider */
+ if (div < 16)
+ div = 16;
+
+ if (clk % baud && (div / 16) < 0x8000) {
/* Mode x2 */
mode = MAX310X_BRGCFG_2XMODE_BIT;
- div = (port->uartclk * 2) / baud;
- }
-
- if (!(div / 16)) {
- /* Mode x4 */
- mode = MAX310X_BRGCFG_4XMODE_BIT;
- div = (port->uartclk * 4) / baud;
+ clk = port->uartclk * 2;
+ div = clk / baud;
+
+ if (clk % baud && (div / 16) < 0x8000) {
+ /* Mode x4 */
+ mode = MAX310X_BRGCFG_4XMODE_BIT;
+ clk = port->uartclk * 4;
+ div = clk / baud;
+ }
}
max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8);
max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16);
max310x_port_write(port, MAX310X_BRGCFG_REG, (div % 16) | mode);
+
+ return DIV_ROUND_CLOSEST(clk, div);
}
static int max310x_update_best_err(unsigned long f, long *besterr)
@@ -538,18 +523,19 @@ static int max310x_update_best_err(unsigned long f, long *besterr)
return 1;
}
-static int max310x_set_ref_clk(struct max310x_port *s)
+static int max310x_set_ref_clk(struct max310x_port *s, unsigned long freq,
+ bool xtal)
{
unsigned int div, clksrc, pllcfg = 0;
long besterr = -1;
- unsigned long fdiv, fmul, bestfreq = s->pdata->frequency;
+ unsigned long fdiv, fmul, bestfreq = freq;
/* First, update error without PLL */
- max310x_update_best_err(s->pdata->frequency, &besterr);
+ max310x_update_best_err(freq, &besterr);
/* Try all possible PLL dividers */
for (div = 1; (div <= 63) && besterr; div++) {
- fdiv = DIV_ROUND_CLOSEST(s->pdata->frequency, div);
+ fdiv = DIV_ROUND_CLOSEST(freq, div);
/* Try multiplier 6 */
fmul = fdiv * 6;
@@ -582,10 +568,7 @@ static int max310x_set_ref_clk(struct max310x_port *s)
}
/* Configure clock source */
- if (s->pdata->driver_flags & MAX310X_EXT_CLK)
- clksrc = MAX310X_CLKSRC_EXTCLK_BIT;
- else
- clksrc = MAX310X_CLKSRC_CRYST_BIT;
+ clksrc = xtal ? MAX310X_CLKSRC_CRYST_BIT : MAX310X_CLKSRC_EXTCLK_BIT;
/* Configure PLL */
if (pllcfg) {
@@ -597,7 +580,7 @@ static int max310x_set_ref_clk(struct max310x_port *s)
regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc);
/* Wait for crystal */
- if (pllcfg && !(s->pdata->driver_flags & MAX310X_EXT_CLK))
+ if (pllcfg && xtal)
msleep(10);
return (int)bestfreq;
@@ -782,11 +765,21 @@ static unsigned int max310x_get_mctrl(struct uart_port *port)
return TIOCM_DSR | TIOCM_CAR;
}
+static void max310x_md_proc(struct work_struct *ws)
+{
+ struct max310x_one *one = container_of(ws, struct max310x_one, md_work);
+
+ max310x_port_update(&one->port, MAX310X_MODE2_REG,
+ MAX310X_MODE2_LOOPBACK_BIT,
+ (one->port.mctrl & TIOCM_LOOP) ?
+ MAX310X_MODE2_LOOPBACK_BIT : 0);
+}
+
static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- /* DCD and DSR are not wired and CTS/RTS is hadnled automatically
- * so do nothing
- */
+ struct max310x_one *one = container_of(port, struct max310x_one, port);
+
+ schedule_work(&one->md_work);
}
static void max310x_break_ctl(struct uart_port *port, int break_state)
@@ -875,40 +868,76 @@ static void max310x_set_termios(struct uart_port *port,
port->uartclk / 4);
/* Setup baudrate generator */
- max310x_set_baud(port, baud);
+ baud = max310x_set_baud(port, baud);
/* Update timeout according to new baud rate */
uart_update_timeout(port, termios->c_cflag, baud);
}
+static int max310x_ioctl(struct uart_port *port, unsigned int cmd,
+ unsigned long arg)
+{
+#if defined(TIOCSRS485) && defined(TIOCGRS485)
+ struct serial_rs485 rs485;
+ unsigned int val;
+
+ switch (cmd) {
+ case TIOCSRS485:
+ if (copy_from_user(&rs485, (void __user *)arg, sizeof(rs485)))
+ return -EFAULT;
+ if (rs485.delay_rts_before_send > 0x0f ||
+ rs485.delay_rts_after_send > 0x0f)
+ return -ERANGE;
+ val = (rs485.delay_rts_before_send << 4) |
+ rs485.delay_rts_after_send;
+ max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val);
+ if (rs485.flags & SER_RS485_ENABLED) {
+ max310x_port_update(port, MAX310X_MODE1_REG,
+ MAX310X_MODE1_TRNSCVCTRL_BIT,
+ MAX310X_MODE1_TRNSCVCTRL_BIT);
+ max310x_port_update(port, MAX310X_MODE2_REG,
+ MAX310X_MODE2_ECHOSUPR_BIT,
+ MAX310X_MODE2_ECHOSUPR_BIT);
+ } else {
+ max310x_port_update(port, MAX310X_MODE1_REG,
+ MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
+ max310x_port_update(port, MAX310X_MODE2_REG,
+ MAX310X_MODE2_ECHOSUPR_BIT, 0);
+ }
+ return 0;
+ case TIOCGRS485:
+ memset(&rs485, 0, sizeof(rs485));
+ val = max310x_port_read(port, MAX310X_MODE1_REG);
+ rs485.flags = (val & MAX310X_MODE1_TRNSCVCTRL_BIT) ?
+ SER_RS485_ENABLED : 0;
+ rs485.flags |= SER_RS485_RTS_ON_SEND;
+ val = max310x_port_read(port, MAX310X_HDPIXDELAY_REG);
+ rs485.delay_rts_before_send = val >> 4;
+ rs485.delay_rts_after_send = val & 0x0f;
+ if (copy_to_user((void __user *)arg, &rs485, sizeof(rs485)))
+ return -EFAULT;
+ return 0;
+ default:
+ break;
+ }
+#endif
+
+ return -ENOIOCTLCMD;
+}
+
static int max310x_startup(struct uart_port *port)
{
- unsigned int val, line = port->line;
struct max310x_port *s = dev_get_drvdata(port->dev);
+ unsigned int val;
s->devtype->power(port, 1);
- /* Configure baud rate, 9600 as default */
- max310x_set_baud(port, 9600);
-
- /* Configure LCR register, 8N1 mode by default */
- max310x_port_write(port, MAX310X_LCR_REG, MAX310X_LCR_WORD_LEN_8);
-
/* Configure MODE1 register */
max310x_port_update(port, MAX310X_MODE1_REG,
- MAX310X_MODE1_TRNSCVCTRL_BIT,
- (s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL)
- ? MAX310X_MODE1_TRNSCVCTRL_BIT : 0);
-
- /* Configure MODE2 register */
- val = MAX310X_MODE2_RXEMPTINV_BIT;
- if (s->pdata->uart_flags[line] & MAX310X_LOOPBACK)
- val |= MAX310X_MODE2_LOOPBACK_BIT;
- if (s->pdata->uart_flags[line] & MAX310X_ECHO_SUPRESS)
- val |= MAX310X_MODE2_ECHOSUPR_BIT;
-
- /* Reset FIFOs */
- val |= MAX310X_MODE2_FIFORST_BIT;
+ MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
+
+ /* Configure MODE2 register & Reset FIFOs*/
+ val = MAX310X_MODE2_RXEMPTINV_BIT | MAX310X_MODE2_FIFORST_BIT;
max310x_port_write(port, MAX310X_MODE2_REG, val);
max310x_port_update(port, MAX310X_MODE2_REG,
MAX310X_MODE2_FIFORST_BIT, 0);
@@ -989,6 +1018,7 @@ static const struct uart_ops max310x_ops = {
.release_port = max310x_null_void,
.config_port = max310x_config_port,
.verify_port = max310x_verify_port,
+ .ioctl = max310x_ioctl,
};
static int __maybe_unused max310x_suspend(struct device *dev)
@@ -1017,6 +1047,8 @@ static int __maybe_unused max310x_resume(struct device *dev)
return 0;
}
+static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
+
#ifdef CONFIG_GPIOLIB
static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
{
@@ -1063,23 +1095,16 @@ static int max310x_gpio_direction_output(struct gpio_chip *chip,
}
#endif
-static int max310x_probe(struct device *dev, int is_spi,
- struct max310x_devtype *devtype, int irq)
+static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
+ struct regmap *regmap, int irq, unsigned long flags)
{
+ int i, ret, fmin, fmax, freq, uartclk;
+ struct clk *clk_osc, *clk_xtal;
struct max310x_port *s;
- struct max310x_pdata *pdata = dev_get_platdata(dev);
- int i, ret, uartclk;
-
- /* Check for IRQ */
- if (irq <= 0) {
- dev_err(dev, "No IRQ specified\n");
- return -ENOTSUPP;
- }
+ bool xtal = false;
- if (!pdata) {
- dev_err(dev, "No platform data supplied\n");
- return -EINVAL;
- }
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
/* Alloc port structure */
s = devm_kzalloc(dev, sizeof(*s) +
@@ -1089,52 +1114,44 @@ static int max310x_probe(struct device *dev, int is_spi,
return -ENOMEM;
}
- /* Check input frequency */
- if ((pdata->driver_flags & MAX310X_EXT_CLK) &&
- ((pdata->frequency < 500000) || (pdata->frequency > 35000000)))
- goto err_freq;
- /* Check frequency for quartz */
- if (!(pdata->driver_flags & MAX310X_EXT_CLK) &&
- ((pdata->frequency < 1000000) || (pdata->frequency > 4000000)))
- goto err_freq;
-
- s->pdata = pdata;
- s->devtype = devtype;
- dev_set_drvdata(dev, s);
-
- mutex_init(&s->mutex);
+ clk_osc = devm_clk_get(dev, "osc");
+ clk_xtal = devm_clk_get(dev, "xtal");
+ if (!IS_ERR(clk_osc)) {
+ s->clk = clk_osc;
+ fmin = 500000;
+ fmax = 35000000;
+ } else if (!IS_ERR(clk_xtal)) {
+ s->clk = clk_xtal;
+ fmin = 1000000;
+ fmax = 4000000;
+ xtal = true;
+ } else if (PTR_ERR(clk_osc) == -EPROBE_DEFER ||
+ PTR_ERR(clk_xtal) == -EPROBE_DEFER) {
+ return -EPROBE_DEFER;
+ } else {
+ dev_err(dev, "Cannot get clock\n");
+ return -EINVAL;
+ }
- /* Setup regmap */
- s->regcfg.reg_bits = 8;
- s->regcfg.val_bits = 8;
- s->regcfg.read_flag_mask = 0x00;
- s->regcfg.write_flag_mask = 0x80;
- s->regcfg.cache_type = REGCACHE_RBTREE;
- s->regcfg.writeable_reg = max310x_reg_writeable;
- s->regcfg.volatile_reg = max310x_reg_volatile;
- s->regcfg.precious_reg = max310x_reg_precious;
- s->regcfg.max_register = devtype->nr * 0x20 - 1;
-
- if (IS_ENABLED(CONFIG_SPI_MASTER) && is_spi) {
- struct spi_device *spi = to_spi_device(dev);
-
- s->regmap = devm_regmap_init_spi(spi, &s->regcfg);
- } else
- return -ENOTSUPP;
+ ret = clk_prepare_enable(s->clk);
+ if (ret)
+ return ret;
- if (IS_ERR(s->regmap)) {
- dev_err(dev, "Failed to initialize register map\n");
- return PTR_ERR(s->regmap);
+ freq = clk_get_rate(s->clk);
+ /* Check frequency limits */
+ if (freq < fmin || freq > fmax) {
+ ret = -ERANGE;
+ goto out_clk;
}
- /* Board specific configure */
- if (s->pdata->init)
- s->pdata->init();
+ s->regmap = regmap;
+ s->devtype = devtype;
+ dev_set_drvdata(dev, s);
/* Check device to ensure we are talking to what we expect */
ret = devtype->detect(dev);
if (ret)
- return ret;
+ goto out_clk;
for (i = 0; i < devtype->nr; i++) {
unsigned int offs = i << 5;
@@ -1156,7 +1173,7 @@ static int max310x_probe(struct device *dev, int is_spi,
MAX310X_MODE1_AUTOSLEEP_BIT);
}
- uartclk = max310x_set_ref_clk(s);
+ uartclk = max310x_set_ref_clk(s, freq, xtal);
dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
/* Register UART driver */
@@ -1168,9 +1185,28 @@ static int max310x_probe(struct device *dev, int is_spi,
ret = uart_register_driver(&s->uart);
if (ret) {
dev_err(dev, "Registering UART driver failed\n");
- return ret;
+ goto out_clk;
}
+#ifdef CONFIG_GPIOLIB
+ /* Setup GPIO cotroller */
+ s->gpio.owner = THIS_MODULE;
+ s->gpio.dev = dev;
+ s->gpio.label = dev_name(dev);
+ s->gpio.direction_input = max310x_gpio_direction_input;
+ s->gpio.get = max310x_gpio_get;
+ s->gpio.direction_output= max310x_gpio_direction_output;
+ s->gpio.set = max310x_gpio_set;
+ s->gpio.base = -1;
+ s->gpio.ngpio = devtype->nr * 4;
+ s->gpio.can_sleep = 1;
+ ret = gpiochip_add(&s->gpio);
+ if (ret)
+ goto out_uart;
+#endif
+
+ mutex_init(&s->mutex);
+
for (i = 0; i < devtype->nr; i++) {
/* Initialize port data */
s->p[i].port.line = i;
@@ -1178,8 +1214,7 @@ static int max310x_probe(struct device *dev, int is_spi,
s->p[i].port.irq = irq;
s->p[i].port.type = PORT_MAX310X;
s->p[i].port.fifosize = MAX310X_FIFO_SIZE;
- s->p[i].port.flags = UPF_SKIP_TEST | UPF_FIXED_TYPE |
- UPF_LOW_LATENCY;
+ s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
s->p[i].port.iotype = UPIO_PORT;
s->p[i].port.iobase = i * 0x20;
s->p[i].port.membase = (void __iomem *)~0;
@@ -1195,48 +1230,35 @@ static int max310x_probe(struct device *dev, int is_spi,
MAX310X_MODE1_IRQSEL_BIT);
/* Initialize queue for start TX */
INIT_WORK(&s->p[i].tx_work, max310x_wq_proc);
+ /* Initialize queue for changing mode */
+ INIT_WORK(&s->p[i].md_work, max310x_md_proc);
/* Register port */
uart_add_one_port(&s->uart, &s->p[i].port);
/* Go to suspend mode */
devtype->power(&s->p[i].port, 0);
}
-#ifdef CONFIG_GPIOLIB
- /* Setup GPIO cotroller */
- if (s->pdata->gpio_base) {
- s->gpio.owner = THIS_MODULE;
- s->gpio.dev = dev;
- s->gpio.label = dev_name(dev);
- s->gpio.direction_input = max310x_gpio_direction_input;
- s->gpio.get = max310x_gpio_get;
- s->gpio.direction_output= max310x_gpio_direction_output;
- s->gpio.set = max310x_gpio_set;
- s->gpio.base = s->pdata->gpio_base;
- s->gpio.ngpio = devtype->nr * 4;
- s->gpio.can_sleep = 1;
- if (!gpiochip_add(&s->gpio))
- s->gpio_used = 1;
- } else
- dev_info(dev, "GPIO support not enabled\n");
-#endif
-
/* Setup interrupt */
ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- dev_name(dev), s);
- if (ret) {
- dev_err(dev, "Unable to reguest IRQ %i\n", irq);
+ IRQF_ONESHOT | flags, dev_name(dev), s);
+ if (!ret)
+ return 0;
+
+ dev_err(dev, "Unable to reguest IRQ %i\n", irq);
+
+ mutex_destroy(&s->mutex);
+
#ifdef CONFIG_GPIOLIB
- if (s->gpio_used)
- WARN_ON(gpiochip_remove(&s->gpio));
+ WARN_ON(gpiochip_remove(&s->gpio));
+
+out_uart:
#endif
- }
+ uart_unregister_driver(&s->uart);
- return ret;
+out_clk:
+ clk_disable_unprepare(s->clk);
-err_freq:
- dev_err(dev, "Frequency parameter incorrect\n");
- return -EINVAL;
+ return ret;
}
static int max310x_remove(struct device *dev)
@@ -1244,30 +1266,51 @@ static int max310x_remove(struct device *dev)
struct max310x_port *s = dev_get_drvdata(dev);
int i, ret = 0;
+#ifdef CONFIG_GPIOLIB
+ ret = gpiochip_remove(&s->gpio);
+ if (ret)
+ return ret;
+#endif
+
for (i = 0; i < s->uart.nr; i++) {
cancel_work_sync(&s->p[i].tx_work);
+ cancel_work_sync(&s->p[i].md_work);
uart_remove_one_port(&s->uart, &s->p[i].port);
s->devtype->power(&s->p[i].port, 0);
}
+ mutex_destroy(&s->mutex);
uart_unregister_driver(&s->uart);
-
-#ifdef CONFIG_GPIOLIB
- if (s->gpio_used)
- ret = gpiochip_remove(&s->gpio);
-#endif
-
- if (s->pdata->exit)
- s->pdata->exit();
+ clk_disable_unprepare(s->clk);
return ret;
}
+static const struct of_device_id __maybe_unused max310x_dt_ids[] = {
+ { .compatible = "maxim,max3107", .data = &max3107_devtype, },
+ { .compatible = "maxim,max3108", .data = &max3108_devtype, },
+ { .compatible = "maxim,max3109", .data = &max3109_devtype, },
+ { .compatible = "maxim,max14830", .data = &max14830_devtype },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max310x_dt_ids);
+
+static struct regmap_config regcfg = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .write_flag_mask = 0x80,
+ .cache_type = REGCACHE_RBTREE,
+ .writeable_reg = max310x_reg_writeable,
+ .volatile_reg = max310x_reg_volatile,
+ .precious_reg = max310x_reg_precious,
+};
+
#ifdef CONFIG_SPI_MASTER
static int max310x_spi_probe(struct spi_device *spi)
{
- struct max310x_devtype *devtype =
- (struct max310x_devtype *)spi_get_device_id(spi)->driver_data;
+ struct max310x_devtype *devtype;
+ unsigned long flags = 0;
+ struct regmap *regmap;
int ret;
/* Setup SPI bus */
@@ -1275,12 +1318,25 @@ static int max310x_spi_probe(struct spi_device *spi)
spi->mode = spi->mode ? : SPI_MODE_0;
spi->max_speed_hz = spi->max_speed_hz ? : 26000000;
ret = spi_setup(spi);
- if (ret) {
- dev_err(&spi->dev, "SPI setup failed\n");
+ if (ret)
return ret;
+
+ if (spi->dev.of_node) {
+ const struct of_device_id *of_id =
+ of_match_device(max310x_dt_ids, &spi->dev);
+
+ devtype = (struct max310x_devtype *)of_id->data;
+ } else {
+ const struct spi_device_id *id_entry = spi_get_device_id(spi);
+
+ devtype = (struct max310x_devtype *)id_entry->driver_data;
+ flags = IRQF_TRIGGER_FALLING;
}
- return max310x_probe(&spi->dev, 1, devtype, spi->irq);
+ regcfg.max_register = devtype->nr * 0x20 - 1;
+ regmap = devm_regmap_init_spi(spi, &regcfg);
+
+ return max310x_probe(&spi->dev, devtype, regmap, spi->irq, flags);
}
static int max310x_spi_remove(struct spi_device *spi)
@@ -1288,8 +1344,6 @@ static int max310x_spi_remove(struct spi_device *spi)
return max310x_remove(&spi->dev);
}
-static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
-
static const struct spi_device_id max310x_id_table[] = {
{ "max3107", (kernel_ulong_t)&max3107_devtype, },
{ "max3108", (kernel_ulong_t)&max3108_devtype, },
@@ -1301,9 +1355,10 @@ MODULE_DEVICE_TABLE(spi, max310x_id_table);
static struct spi_driver max310x_uart_driver = {
.driver = {
- .name = MAX310X_NAME,
- .owner = THIS_MODULE,
- .pm = &max310x_pm_ops,
+ .name = MAX310X_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(max310x_dt_ids),
+ .pm = &max310x_pm_ops,
},
.probe = max310x_spi_probe,
.remove = max310x_spi_remove,
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index b5d779cd3c2b..053b98eb46c8 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -39,6 +39,13 @@
#include "msm_serial.h"
+enum {
+ UARTDM_1P1 = 1,
+ UARTDM_1P2,
+ UARTDM_1P3,
+ UARTDM_1P4,
+};
+
struct msm_port {
struct uart_port uart;
char name[16];
@@ -309,6 +316,8 @@ static unsigned int msm_get_mctrl(struct uart_port *port)
static void msm_reset(struct uart_port *port)
{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
/* reset everything */
msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
@@ -316,6 +325,10 @@ static void msm_reset(struct uart_port *port)
msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
+
+ /* Disable DM modes */
+ if (msm_port->is_uartdm)
+ msm_write(port, 0, UARTDM_DMEN);
}
static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
@@ -711,6 +724,117 @@ static void msm_power(struct uart_port *port, unsigned int state,
}
}
+#ifdef CONFIG_CONSOLE_POLL
+static int msm_poll_init(struct uart_port *port)
+{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ /* Enable single character mode on RX FIFO */
+ if (msm_port->is_uartdm >= UARTDM_1P4)
+ msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN);
+
+ return 0;
+}
+
+static int msm_poll_get_char_single(struct uart_port *port)
+{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+ unsigned int rf_reg = msm_port->is_uartdm ? UARTDM_RF : UART_RF;
+
+ if (!(msm_read(port, UART_SR) & UART_SR_RX_READY))
+ return NO_POLL_CHAR;
+ else
+ return msm_read(port, rf_reg) & 0xff;
+}
+
+static int msm_poll_get_char_dm_1p3(struct uart_port *port)
+{
+ int c;
+ static u32 slop;
+ static int count;
+ unsigned char *sp = (unsigned char *)&slop;
+
+ /* Check if a previous read had more than one char */
+ if (count) {
+ c = sp[sizeof(slop) - count];
+ count--;
+ /* Or if FIFO is empty */
+ } else if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) {
+ /*
+ * If RX packing buffer has less than a word, force stale to
+ * push contents into RX FIFO
+ */
+ count = msm_read(port, UARTDM_RXFS);
+ count = (count >> UARTDM_RXFS_BUF_SHIFT) & UARTDM_RXFS_BUF_MASK;
+ if (count) {
+ msm_write(port, UART_CR_CMD_FORCE_STALE, UART_CR);
+ slop = msm_read(port, UARTDM_RF);
+ c = sp[0];
+ count--;
+ } else {
+ c = NO_POLL_CHAR;
+ }
+ /* FIFO has a word */
+ } else {
+ slop = msm_read(port, UARTDM_RF);
+ c = sp[0];
+ count = sizeof(slop) - 1;
+ }
+
+ return c;
+}
+
+static int msm_poll_get_char(struct uart_port *port)
+{
+ u32 imr;
+ int c;
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ /* Disable all interrupts */
+ imr = msm_read(port, UART_IMR);
+ msm_write(port, 0, UART_IMR);
+
+ if (msm_port->is_uartdm == UARTDM_1P3)
+ c = msm_poll_get_char_dm_1p3(port);
+ else
+ c = msm_poll_get_char_single(port);
+
+ /* Enable interrupts */
+ msm_write(port, imr, UART_IMR);
+
+ return c;
+}
+
+static void msm_poll_put_char(struct uart_port *port, unsigned char c)
+{
+ u32 imr;
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ /* Disable all interrupts */
+ imr = msm_read(port, UART_IMR);
+ msm_write(port, 0, UART_IMR);
+
+ if (msm_port->is_uartdm)
+ reset_dm_count(port, 1);
+
+ /* Wait until FIFO is empty */
+ while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
+ cpu_relax();
+
+ /* Write a character */
+ msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF);
+
+ /* Wait until FIFO is empty */
+ while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
+ cpu_relax();
+
+ /* Enable interrupts */
+ msm_write(port, imr, UART_IMR);
+
+ return;
+}
+#endif
+
static struct uart_ops msm_uart_pops = {
.tx_empty = msm_tx_empty,
.set_mctrl = msm_set_mctrl,
@@ -729,6 +853,11 @@ static struct uart_ops msm_uart_pops = {
.config_port = msm_config_port,
.verify_port = msm_verify_port,
.pm = msm_power,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_init = msm_poll_init,
+ .poll_get_char = msm_poll_get_char,
+ .poll_put_char = msm_poll_put_char,
+#endif
};
static struct msm_port msm_uart_ports[] = {
@@ -900,7 +1029,10 @@ static struct uart_driver msm_uart_driver = {
static atomic_t msm_uart_next_id = ATOMIC_INIT(0);
static const struct of_device_id msm_uartdm_table[] = {
- { .compatible = "qcom,msm-uartdm" },
+ { .compatible = "qcom,msm-uartdm-v1.1", .data = (void *)UARTDM_1P1 },
+ { .compatible = "qcom,msm-uartdm-v1.2", .data = (void *)UARTDM_1P2 },
+ { .compatible = "qcom,msm-uartdm-v1.3", .data = (void *)UARTDM_1P3 },
+ { .compatible = "qcom,msm-uartdm-v1.4", .data = (void *)UARTDM_1P4 },
{ }
};
@@ -909,6 +1041,7 @@ static int __init msm_serial_probe(struct platform_device *pdev)
struct msm_port *msm_port;
struct resource *resource;
struct uart_port *port;
+ const struct of_device_id *id;
int irq;
if (pdev->id == -1)
@@ -923,8 +1056,9 @@ static int __init msm_serial_probe(struct platform_device *pdev)
port->dev = &pdev->dev;
msm_port = UART_TO_MSM(port);
- if (of_match_device(msm_uartdm_table, &pdev->dev))
- msm_port->is_uartdm = 1;
+ id = of_match_device(msm_uartdm_table, &pdev->dev);
+ if (id)
+ msm_port->is_uartdm = (unsigned long)id->data;
else
msm_port->is_uartdm = 0;
diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h
index 469fda50ac63..1e9b68b6f9eb 100644
--- a/drivers/tty/serial/msm_serial.h
+++ b/drivers/tty/serial/msm_serial.h
@@ -59,6 +59,7 @@
#define UART_CR_CMD_RESET_RFR (14 << 4)
#define UART_CR_CMD_PROTECTION_EN (16 << 4)
#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
+#define UART_CR_CMD_FORCE_STALE (4 << 8)
#define UART_CR_CMD_RESET_TX_READY (3 << 8)
#define UART_CR_TX_DISABLE (1 << 3)
#define UART_CR_TX_ENABLE (1 << 2)
@@ -113,6 +114,14 @@
#define GSBI_PROTOCOL_UART 0x40
#define GSBI_PROTOCOL_IDLE 0x0
+#define UARTDM_RXFS 0x50
+#define UARTDM_RXFS_BUF_SHIFT 0x7
+#define UARTDM_RXFS_BUF_MASK 0x7
+
+#define UARTDM_DMEN 0x3C
+#define UARTDM_DMEN_RX_SC_ENABLE BIT(5)
+#define UARTDM_DMEN_TX_SC_ENABLE BIT(4)
+
#define UARTDM_DMRX 0x34
#define UARTDM_NCF_TX 0x40
#define UARTDM_RX_TOTAL_SNAP 0x38
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 77f035158d6c..dd8b1a5458ff 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -342,7 +342,14 @@ static void serial_omap_stop_tx(struct uart_port *port)
if ((up->rs485.flags & SER_RS485_ENABLED) &&
!(up->rs485.flags & SER_RS485_RX_DURING_TX)) {
- up->ier = UART_IER_RLSI | UART_IER_RDI;
+ /*
+ * Empty the RX FIFO, we are not interested in anything
+ * received during the half-duplex transmission.
+ */
+ serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_RCVR);
+ /* Re-enable RX interrupts */
+ up->ier |= UART_IER_RLSI | UART_IER_RDI;
+ up->port.read_status_mask |= UART_LSR_DR;
serial_out(up, UART_IER, up->ier);
}
@@ -355,7 +362,7 @@ static void serial_omap_stop_rx(struct uart_port *port)
struct uart_omap_port *up = to_uart_omap_port(port);
pm_runtime_get_sync(up->dev);
- up->ier &= ~UART_IER_RLSI;
+ up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
up->port.read_status_mask &= ~UART_LSR_DR;
serial_out(up, UART_IER, up->ier);
pm_runtime_mark_last_busy(up->dev);
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 8fa1134e0051..0931b3fe9edf 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -1762,7 +1762,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
int fifosize;
int port_type;
struct pch_uart_driver_data *board;
+#ifdef CONFIG_DEBUG_FS
char name[32]; /* for debugfs file name */
+#endif
board = &drv_dat[id->driver_data];
port_type = board->port_type;
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 9cd706df3b33..23f459600738 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -1282,6 +1282,14 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
if (ret < 0)
goto probe_err;
+ if (!s3c24xx_uart_drv.state) {
+ ret = uart_register_driver(&s3c24xx_uart_drv);
+ if (ret < 0) {
+ pr_err("Failed to register Samsung UART driver\n");
+ return ret;
+ }
+ }
+
dbg("%s: adding port\n", __func__);
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
platform_set_drvdata(pdev, &ourport->port);
@@ -1321,6 +1329,8 @@ static int s3c24xx_serial_remove(struct platform_device *dev)
uart_remove_one_port(&s3c24xx_uart_drv, port);
}
+ uart_unregister_driver(&s3c24xx_uart_drv);
+
return 0;
}
@@ -1820,35 +1830,7 @@ static struct platform_driver samsung_serial_driver = {
},
};
-/* module initialisation code */
-
-static int __init s3c24xx_serial_modinit(void)
-{
- int ret;
-
- ret = uart_register_driver(&s3c24xx_uart_drv);
- if (ret < 0) {
- pr_err("Failed to register Samsung UART driver\n");
- return ret;
- }
-
- ret = platform_driver_register(&samsung_serial_driver);
- if (ret < 0) {
- pr_err("Failed to register platform driver\n");
- uart_unregister_driver(&s3c24xx_uart_drv);
- }
-
- return ret;
-}
-
-static void __exit s3c24xx_serial_modexit(void)
-{
- platform_driver_unregister(&samsung_serial_driver);
- uart_unregister_driver(&s3c24xx_uart_drv);
-}
-
-module_init(s3c24xx_serial_modinit);
-module_exit(s3c24xx_serial_modexit);
+module_platform_driver(samsung_serial_driver);
MODULE_ALIAS("platform:samsung-uart");
MODULE_DESCRIPTION("Samsung SoC Serial port driver");
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index ece2049bd270..2cf5649a6dc0 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1319,9 +1319,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
uport = state->uart_port;
port = &state->port;
- pr_debug("uart_close(%d) called\n", uport->line);
+ pr_debug("uart_close(%d) called\n", uport ? uport->line : -1);
- if (tty_port_close_start(port, tty, filp) == 0)
+ if (!port->count || tty_port_close_start(port, tty, filp) == 0)
return;
/*
@@ -1762,7 +1762,7 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
}
/**
- * uart_parse_options - Parse serial port baud/parity/bits/flow contro.
+ * uart_parse_options - Parse serial port baud/parity/bits/flow control.
* @options: pointer to option string
* @baud: pointer to an 'int' variable for the baud rate.
* @parity: pointer to an 'int' variable for the parity.
@@ -2609,7 +2609,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
/*
* Register the port whether it's detected or not. This allows
- * setserial to be used to alter this ports parameters.
+ * setserial to be used to alter this port's parameters.
*/
tty_dev = tty_port_register_device_attr(port, drv->tty_driver,
uport->line, uport->dev, port, tty_dev_attr_groups);
@@ -2645,6 +2645,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
{
struct uart_state *state = drv->state + uport->line;
struct tty_port *port = &state->port;
+ struct tty_struct *tty;
int ret = 0;
BUG_ON(in_interrupt());
@@ -2673,8 +2674,17 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
*/
tty_unregister_device(drv->tty_driver, uport->line);
- if (port->tty)
+ tty = tty_port_tty_get(port);
+ if (tty) {
tty_vhangup(port->tty);
+ tty_kref_put(tty);
+ }
+
+ /*
+ * If the port is used as a console, unregister it
+ */
+ if (uart_console(uport))
+ unregister_console(uport->cons);
/*
* Free the port IO and memory resources, if any.
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index be33d2b0613b..88236da0ddf7 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -428,7 +428,7 @@ static int sci_probe_regmap(struct plat_sci_port *cfg)
cfg->regtype = SCIx_HSCIF_REGTYPE;
break;
default:
- printk(KERN_ERR "Can't probe register map for given port\n");
+ pr_err("Can't probe register map for given port\n");
return -EINVAL;
}
@@ -788,7 +788,7 @@ static int sci_handle_errors(struct uart_port *port)
if (tty_insert_flip_char(tport, 0, TTY_OVERRUN))
copied++;
- dev_notice(port->dev, "overrun error");
+ dev_notice(port->dev, "overrun error\n");
}
if (status & SCxSR_FER(port)) {
@@ -830,7 +830,7 @@ static int sci_handle_errors(struct uart_port *port)
if (tty_insert_flip_char(tport, 0, TTY_PARITY))
copied++;
- dev_notice(port->dev, "parity error");
+ dev_notice(port->dev, "parity error\n");
}
if (copied)
@@ -911,7 +911,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
/* Disable future Rx interrupts */
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
disable_irq_nosync(irq);
- scr |= 0x4000;
+ scr |= SCSCR_RDRQE;
} else {
scr &= ~SCSCR_RIE;
}
@@ -1041,8 +1041,7 @@ static int sci_notifier(struct notifier_block *self,
sci_port = container_of(self, struct sci_port, freq_transition);
- if ((phase == CPUFREQ_POSTCHANGE) ||
- (phase == CPUFREQ_RESUMECHANGE)) {
+ if (phase == CPUFREQ_POSTCHANGE) {
struct uart_port *port = &sci_port->port;
spin_lock_irqsave(&port->lock, flags);
@@ -1200,7 +1199,9 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
*/
reg = sci_getreg(port, SCFCR);
if (reg->size)
- serial_port_out(port, SCFCR, serial_port_in(port, SCFCR) | 1);
+ serial_port_out(port, SCFCR,
+ serial_port_in(port, SCFCR) |
+ SCFCR_LOOP);
}
}
@@ -1290,7 +1291,8 @@ static void sci_dma_rx_complete(void *arg)
unsigned long flags;
int count;
- dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx);
+ dev_dbg(port->dev, "%s(%d) active #%d\n",
+ __func__, port->line, s->active_rx);
spin_lock_irqsave(&port->lock, flags);
@@ -1366,8 +1368,8 @@ static void sci_submit_rx(struct sci_port *s)
sci_rx_dma_release(s, true);
return;
}
- dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
- s->cookie_rx[i], i);
+ dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n",
+ __func__, s->cookie_rx[i], i);
}
s->active_rx = s->cookie_rx[0];
@@ -1426,8 +1428,8 @@ static void work_fn_rx(struct work_struct *work)
s->active_rx = s->cookie_rx[!new];
- dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__,
- s->cookie_rx[new], new, s->active_rx);
+ dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n",
+ __func__, s->cookie_rx[new], new, s->active_rx);
}
static void work_fn_tx(struct work_struct *work)
@@ -1480,8 +1482,8 @@ static void work_fn_tx(struct work_struct *work)
return;
}
- dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__,
- xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
+ dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
+ __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
dma_async_issue_pending(chan);
}
@@ -1496,9 +1498,9 @@ static void sci_start_tx(struct uart_port *port)
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
u16 new, scr = serial_port_in(port, SCSCR);
if (s->chan_tx)
- new = scr | 0x8000;
+ new = scr | SCSCR_TDRQE;
else
- new = scr & ~0x8000;
+ new = scr & ~SCSCR_TDRQE;
if (new != scr)
serial_port_out(port, SCSCR, new);
}
@@ -1525,7 +1527,7 @@ static void sci_stop_tx(struct uart_port *port)
ctrl = serial_port_in(port, SCSCR);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
- ctrl &= ~0x8000;
+ ctrl &= ~SCSCR_TDRQE;
ctrl &= ~SCSCR_TIE;
@@ -1539,7 +1541,7 @@ static void sci_start_rx(struct uart_port *port)
ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
- ctrl &= ~0x4000;
+ ctrl &= ~SCSCR_RDRQE;
serial_port_out(port, SCSCR, ctrl);
}
@@ -1551,7 +1553,7 @@ static void sci_stop_rx(struct uart_port *port)
ctrl = serial_port_in(port, SCSCR);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
- ctrl &= ~0x4000;
+ ctrl &= ~SCSCR_RDRQE;
ctrl &= ~port_rx_irq_mask(port);
@@ -1600,8 +1602,8 @@ static bool filter(struct dma_chan *chan, void *slave)
{
struct sh_dmae_slave *param = slave;
- dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__,
- param->shdma_slave.slave_id);
+ dev_dbg(chan->device->dev, "%s: slave ID %d\n",
+ __func__, param->shdma_slave.slave_id);
chan->private = &param->shdma_slave;
return true;
@@ -1614,7 +1616,7 @@ static void rx_timer_fn(unsigned long arg)
u16 scr = serial_port_in(port, SCSCR);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
- scr &= ~0x4000;
+ scr &= ~SCSCR_RDRQE;
enable_irq(s->irqs[SCIx_RXI_IRQ]);
}
serial_port_out(port, SCSCR, scr | SCSCR_RIE);
@@ -1630,8 +1632,7 @@ static void sci_request_dma(struct uart_port *port)
dma_cap_mask_t mask;
int nent;
- dev_dbg(port->dev, "%s: port %d\n", __func__,
- port->line);
+ dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);
if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0)
return;
@@ -1659,7 +1660,8 @@ static void sci_request_dma(struct uart_port *port)
if (!nent)
sci_tx_dma_release(s, false);
else
- dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__,
+ dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n",
+ __func__,
sg_dma_len(&s->sg_tx), port->state->xmit.buf,
&sg_dma_address(&s->sg_tx));
@@ -1871,13 +1873,13 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
smr_val = serial_port_in(port, SCSMR) & 3;
if ((termios->c_cflag & CSIZE) == CS7)
- smr_val |= 0x40;
+ smr_val |= SCSMR_CHR;
if (termios->c_cflag & PARENB)
- smr_val |= 0x20;
+ smr_val |= SCSMR_PE;
if (termios->c_cflag & PARODD)
- smr_val |= 0x30;
+ smr_val |= SCSMR_PE | SCSMR_ODD;
if (termios->c_cflag & CSTOPB)
- smr_val |= 0x08;
+ smr_val |= SCSMR_STOP;
uart_update_timeout(port, termios->c_cflag, baud);
@@ -1885,7 +1887,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
__func__, smr_val, cks, t, s->cfg->scscr);
if (t >= 0) {
- serial_port_out(port, SCSMR, (smr_val & ~3) | cks);
+ serial_port_out(port, SCSMR, (smr_val & ~SCSMR_CKS) | cks);
serial_port_out(port, SCBRR, t);
reg = sci_getreg(port, HSSRR);
if (reg->size)
@@ -1933,8 +1935,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
if (s->chan_rx) {
s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
port->fifosize / 2;
- dev_dbg(port->dev,
- "DMA Rx t-out %ums, tty t-out %u jiffies\n",
+ dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n",
s->rx_timeout * 1000 / HZ, port->timeout);
if (s->rx_timeout < msecs_to_jiffies(20))
s->rx_timeout = msecs_to_jiffies(20);
@@ -1953,7 +1954,7 @@ static void sci_pm(struct uart_port *port, unsigned int state,
struct sci_port *sci_port = to_sci_port(port);
switch (state) {
- case 3:
+ case UART_PM_STATE_OFF:
sci_port_disable(sci_port);
break;
default:
@@ -2018,7 +2019,7 @@ static int sci_remap_port(struct uart_port *port)
* need to do any remapping, just cast the cookie
* directly.
*/
- port->membase = (void __iomem *)port->mapbase;
+ port->membase = (void __iomem *)(uintptr_t)port->mapbase;
}
return 0;
@@ -2389,8 +2390,7 @@ static inline int sci_probe_earlyprintk(struct platform_device *pdev)
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
-static char banner[] __initdata =
- KERN_INFO "SuperH (H)SCI(F) driver initialized\n";
+static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized";
static struct uart_driver sci_uart_driver = {
.owner = THIS_MODULE,
@@ -2424,25 +2424,25 @@ struct sci_port_info {
static const struct of_device_id of_sci_match[] = {
{
.compatible = "renesas,scif",
- .data = (void *)&(const struct sci_port_info) {
+ .data = &(const struct sci_port_info) {
.type = PORT_SCIF,
.regtype = SCIx_SH4_SCIF_REGTYPE,
},
}, {
.compatible = "renesas,scifa",
- .data = (void *)&(const struct sci_port_info) {
+ .data = &(const struct sci_port_info) {
.type = PORT_SCIFA,
.regtype = SCIx_SCIFA_REGTYPE,
},
}, {
.compatible = "renesas,scifb",
- .data = (void *)&(const struct sci_port_info) {
+ .data = &(const struct sci_port_info) {
.type = PORT_SCIFB,
.regtype = SCIx_SCIFB_REGTYPE,
},
}, {
.compatible = "renesas,hscif",
- .data = (void *)&(const struct sci_port_info) {
+ .data = &(const struct sci_port_info) {
.type = PORT_HSCIF,
.regtype = SCIx_HSCIF_REGTYPE,
},
@@ -2502,11 +2502,9 @@ static int sci_probe_single(struct platform_device *dev,
/* Sanity check */
if (unlikely(index >= SCI_NPORTS)) {
- dev_notice(&dev->dev, "Attempting to register port "
- "%d when only %d are available.\n",
+ dev_notice(&dev->dev, "Attempting to register port %d when only %d are available\n",
index+1, SCI_NPORTS);
- dev_notice(&dev->dev, "Consider bumping "
- "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
+ dev_notice(&dev->dev, "Consider bumping CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
return -EINVAL;
}
@@ -2564,6 +2562,7 @@ static int sci_probe(struct platform_device *dev)
ret = cpufreq_register_notifier(&sp->freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
if (unlikely(ret < 0)) {
+ uart_remove_one_port(&sci_uart_driver, &sp->port);
sci_cleanup_single(sp);
return ret;
}
@@ -2615,7 +2614,7 @@ static int __init sci_init(void)
{
int ret;
- printk(banner);
+ pr_info("%s\n", banner);
ret = uart_register_driver(&sci_uart_driver);
if (likely(ret == 0)) {
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index b7bfe24d4ebc..68b0fd4b9a6a 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -24,7 +24,6 @@
#include <linux/dmaengine.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
-#include <linux/sirfsoc_dma.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
@@ -173,7 +172,7 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port)
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
- if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) {
+ if (sirfport->tx_dma_chan) {
if (sirfport->tx_dma_state == TX_DMA_RUNNING) {
dmaengine_pause(sirfport->tx_dma_chan);
sirfport->tx_dma_state = TX_DMA_PAUSE;
@@ -288,7 +287,7 @@ static void sirfsoc_uart_start_tx(struct uart_port *port)
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
- if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no))
+ if (sirfport->tx_dma_chan)
sirfsoc_uart_tx_with_dma(sirfport);
else {
sirfsoc_uart_pio_tx_chars(sirfport, 1);
@@ -310,7 +309,7 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port)
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
- if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) {
+ if (sirfport->rx_dma_chan) {
if (!sirfport->is_marco)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
@@ -675,7 +674,7 @@ recv_char:
uart_handle_cts_change(port, cts_status);
wake_up_interruptible(&state->port.delta_msr_wait);
}
- if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) {
+ if (sirfport->rx_dma_chan) {
if (intr_status & uint_st->sirfsoc_rx_timeout)
sirfsoc_uart_handle_rx_tmo(sirfport);
if (intr_status & uint_st->sirfsoc_rx_done)
@@ -686,7 +685,7 @@ recv_char:
SIRFSOC_UART_IO_RX_MAX_CNT);
}
if (intr_status & uint_st->sirfsoc_txfifo_empty) {
- if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no))
+ if (sirfport->tx_dma_chan)
sirfsoc_uart_tx_with_dma(sirfport);
else {
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
@@ -778,7 +777,7 @@ static void sirfsoc_uart_start_rx(struct uart_port *port)
wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
- if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no))
+ if (sirfport->rx_dma_chan)
sirfsoc_uart_start_next_rx_dma(port);
else {
if (!sirfport->is_marco)
@@ -1014,11 +1013,11 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
(sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) <<
SIRFSOC_USP_ASYNC_DIV2_OFFSET);
}
- if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no))
+ if (sirfport->tx_dma_chan)
wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_DMA_MODE);
else
wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE);
- if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no))
+ if (sirfport->rx_dma_chan)
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE);
else
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE);
@@ -1049,93 +1048,6 @@ static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state,
clk_disable_unprepare(sirfport->clk);
}
-static unsigned int sirfsoc_uart_init_tx_dma(struct uart_port *port)
-{
- struct sirfsoc_uart_port *sirfport = to_sirfport(port);
- dma_cap_mask_t dma_mask;
- struct dma_slave_config tx_slv_cfg = {
- .dst_maxburst = 2,
- };
-
- dma_cap_zero(dma_mask);
- dma_cap_set(DMA_SLAVE, dma_mask);
- sirfport->tx_dma_chan = dma_request_channel(dma_mask,
- (dma_filter_fn)sirfsoc_dma_filter_id,
- (void *)sirfport->tx_dma_no);
- if (!sirfport->tx_dma_chan) {
- dev_err(port->dev, "Uart Request Dma Channel Fail %d\n",
- sirfport->tx_dma_no);
- return -EPROBE_DEFER;
- }
- dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg);
-
- return 0;
-}
-
-static unsigned int sirfsoc_uart_init_rx_dma(struct uart_port *port)
-{
- struct sirfsoc_uart_port *sirfport = to_sirfport(port);
- dma_cap_mask_t dma_mask;
- int ret;
- int i, j;
- struct dma_slave_config slv_cfg = {
- .src_maxburst = 2,
- };
-
- dma_cap_zero(dma_mask);
- dma_cap_set(DMA_SLAVE, dma_mask);
- sirfport->rx_dma_chan = dma_request_channel(dma_mask,
- (dma_filter_fn)sirfsoc_dma_filter_id,
- (void *)sirfport->rx_dma_no);
- if (!sirfport->rx_dma_chan) {
- dev_err(port->dev, "Uart Request Dma Channel Fail %d\n",
- sirfport->rx_dma_no);
- ret = -EPROBE_DEFER;
- goto request_err;
- }
- for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) {
- sirfport->rx_dma_items[i].xmit.buf =
- dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
- &sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL);
- if (!sirfport->rx_dma_items[i].xmit.buf) {
- dev_err(port->dev, "Uart alloc bufa failed\n");
- ret = -ENOMEM;
- goto alloc_coherent_err;
- }
- sirfport->rx_dma_items[i].xmit.head =
- sirfport->rx_dma_items[i].xmit.tail = 0;
- }
- dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg);
-
- return 0;
-alloc_coherent_err:
- for (j = 0; j < i; j++)
- dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
- sirfport->rx_dma_items[j].xmit.buf,
- sirfport->rx_dma_items[j].dma_addr);
- dma_release_channel(sirfport->rx_dma_chan);
-request_err:
- return ret;
-}
-
-static void sirfsoc_uart_uninit_tx_dma(struct sirfsoc_uart_port *sirfport)
-{
- dmaengine_terminate_all(sirfport->tx_dma_chan);
- dma_release_channel(sirfport->tx_dma_chan);
-}
-
-static void sirfsoc_uart_uninit_rx_dma(struct sirfsoc_uart_port *sirfport)
-{
- int i;
- struct uart_port *port = &sirfport->port;
- dmaengine_terminate_all(sirfport->rx_dma_chan);
- dma_release_channel(sirfport->rx_dma_chan);
- for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
- dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
- sirfport->rx_dma_items[i].xmit.buf,
- sirfport->rx_dma_items[i].dma_addr);
-}
-
static int sirfsoc_uart_startup(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
@@ -1174,18 +1086,12 @@ static int sirfsoc_uart_startup(struct uart_port *port)
wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port));
wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port));
-
- if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) {
- ret = sirfsoc_uart_init_rx_dma(port);
- if (ret)
- goto init_rx_err;
+ if (sirfport->rx_dma_chan)
wr_regl(port, ureg->sirfsoc_rx_fifo_level_chk,
- SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) |
- SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) |
- SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b));
- }
- if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) {
- sirfsoc_uart_init_tx_dma(port);
+ SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) |
+ SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) |
+ SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b));
+ if (sirfport->tx_dma_chan) {
sirfport->tx_dma_state = TX_DMA_IDLE;
wr_regl(port, ureg->sirfsoc_tx_fifo_level_chk,
SIRFUART_TX_FIFO_CHK_SC(port->line, 0x1b) |
@@ -1232,12 +1138,8 @@ static void sirfsoc_uart_shutdown(struct uart_port *port)
gpio_set_value(sirfport->rts_gpio, 1);
free_irq(gpio_to_irq(sirfport->cts_gpio), sirfport);
}
- if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no))
- sirfsoc_uart_uninit_rx_dma(sirfport);
- if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) {
- sirfsoc_uart_uninit_tx_dma(sirfport);
+ if (sirfport->tx_dma_chan)
sirfport->tx_dma_state = TX_DMA_IDLE;
- }
}
static const char *sirfsoc_uart_type(struct uart_port *port)
@@ -1313,8 +1215,8 @@ sirfsoc_uart_console_setup(struct console *co, char *options)
port->cons = co;
/* default console tx/rx transfer using io mode */
- sirfport->rx_dma_no = UNVALID_DMA_CHAN;
- sirfport->tx_dma_no = UNVALID_DMA_CHAN;
+ sirfport->rx_dma_chan = NULL;
+ sirfport->tx_dma_chan = NULL;
return uart_set_options(port, co, baud, parity, bits, flow);
}
@@ -1382,6 +1284,13 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
struct uart_port *port;
struct resource *res;
int ret;
+ int i, j;
+ struct dma_slave_config slv_cfg = {
+ .src_maxburst = 2,
+ };
+ struct dma_slave_config tx_slv_cfg = {
+ .dst_maxburst = 2,
+ };
const struct of_device_id *match;
match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node);
@@ -1402,27 +1311,10 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node,
"sirf,uart-has-rtscts");
- if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart")) {
+ if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart"))
sirfport->uart_reg->uart_type = SIRF_REAL_UART;
- if (of_property_read_u32(pdev->dev.of_node,
- "sirf,uart-dma-rx-channel",
- &sirfport->rx_dma_no))
- sirfport->rx_dma_no = UNVALID_DMA_CHAN;
- if (of_property_read_u32(pdev->dev.of_node,
- "sirf,uart-dma-tx-channel",
- &sirfport->tx_dma_no))
- sirfport->tx_dma_no = UNVALID_DMA_CHAN;
- }
if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) {
sirfport->uart_reg->uart_type = SIRF_USP_UART;
- if (of_property_read_u32(pdev->dev.of_node,
- "sirf,usp-dma-rx-channel",
- &sirfport->rx_dma_no))
- sirfport->rx_dma_no = UNVALID_DMA_CHAN;
- if (of_property_read_u32(pdev->dev.of_node,
- "sirf,usp-dma-tx-channel",
- &sirfport->tx_dma_no))
- sirfport->tx_dma_no = UNVALID_DMA_CHAN;
if (!sirfport->hw_flow_ctrl)
goto usp_no_flow_control;
if (of_find_property(pdev->dev.of_node, "cts-gpios", NULL))
@@ -1515,8 +1407,32 @@ usp_no_flow_control:
goto port_err;
}
- return 0;
+ sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx");
+ for (i = 0; sirfport->rx_dma_chan && i < SIRFSOC_RX_LOOP_BUF_CNT; i++) {
+ sirfport->rx_dma_items[i].xmit.buf =
+ dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+ &sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL);
+ if (!sirfport->rx_dma_items[i].xmit.buf) {
+ dev_err(port->dev, "Uart alloc bufa failed\n");
+ ret = -ENOMEM;
+ goto alloc_coherent_err;
+ }
+ sirfport->rx_dma_items[i].xmit.head =
+ sirfport->rx_dma_items[i].xmit.tail = 0;
+ }
+ if (sirfport->rx_dma_chan)
+ dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg);
+ sirfport->tx_dma_chan = dma_request_slave_channel(port->dev, "tx");
+ if (sirfport->tx_dma_chan)
+ dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg);
+ return 0;
+alloc_coherent_err:
+ for (j = 0; j < i; j++)
+ dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+ sirfport->rx_dma_items[j].xmit.buf,
+ sirfport->rx_dma_items[j].dma_addr);
+ dma_release_channel(sirfport->rx_dma_chan);
port_err:
clk_put(sirfport->clk);
err:
@@ -1529,6 +1445,19 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)
struct uart_port *port = &sirfport->port;
clk_put(sirfport->clk);
uart_remove_one_port(&sirfsoc_uart_drv, port);
+ if (sirfport->rx_dma_chan) {
+ int i;
+ dmaengine_terminate_all(sirfport->rx_dma_chan);
+ dma_release_channel(sirfport->rx_dma_chan);
+ for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
+ dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+ sirfport->rx_dma_items[i].xmit.buf,
+ sirfport->rx_dma_items[i].dma_addr);
+ }
+ if (sirfport->tx_dma_chan) {
+ dmaengine_terminate_all(sirfport->tx_dma_chan);
+ dma_release_channel(sirfport->tx_dma_chan);
+ }
return 0;
}
diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h
index b7d679c0881b..8a6eddad2f3c 100644
--- a/drivers/tty/serial/sirfsoc_uart.h
+++ b/drivers/tty/serial/sirfsoc_uart.h
@@ -392,9 +392,6 @@ struct sirfsoc_uart_register sirfsoc_uart = {
/* Indicate how many buffers used */
#define SIRFSOC_RX_LOOP_BUF_CNT 2
-/* Indicate if DMA channel valid */
-#define IS_DMA_CHAN_VALID(x) ((x) != -1)
-#define UNVALID_DMA_CHAN -1
/* For Fast Baud Rate Calculation */
struct sirfsoc_baudrate_to_regv {
unsigned int baud_rate;
@@ -423,8 +420,6 @@ struct sirfsoc_uart_port {
/* for SiRFmarco, there are SET/CLR for UART_INT_EN */
bool is_marco;
struct sirfsoc_uart_register *uart_reg;
- int rx_dma_no;
- int tx_dma_no;
struct dma_chan *rx_dma_chan;
struct dma_chan *tx_dma_chan;
dma_addr_t tx_dma_addr;
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index cf86e729532b..dc697cee248a 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -433,13 +433,10 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
unsigned long flags;
int locked = 1;
- local_irq_save(flags);
- if (port->sysrq) {
- locked = 0;
- } else if (oops_in_progress) {
- locked = spin_trylock(&port->lock);
- } else
- spin_lock(&port->lock);
+ if (port->sysrq || oops_in_progress)
+ locked = spin_trylock_irqsave(&port->lock, flags);
+ else
+ spin_lock_irqsave(&port->lock, flags);
while (n > 0) {
unsigned long ra = __pa(con_write_page);
@@ -470,8 +467,7 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
}
if (locked)
- spin_unlock(&port->lock);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
}
static inline void sunhv_console_putchar(struct uart_port *port, char c)
@@ -492,7 +488,10 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
unsigned long flags;
int i, locked = 1;
- local_irq_save(flags);
+ if (port->sysrq || oops_in_progress)
+ locked = spin_trylock_irqsave(&port->lock, flags);
+ else
+ spin_lock_irqsave(&port->lock, flags);
if (port->sysrq) {
locked = 0;
} else if (oops_in_progress) {
@@ -507,8 +506,7 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
}
if (locked)
- spin_unlock(&port->lock);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
}
static struct console sunhv_console = {
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index 380fb5355cb2..5faa8e905e98 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -844,20 +844,16 @@ static void sunsab_console_write(struct console *con, const char *s, unsigned n)
unsigned long flags;
int locked = 1;
- local_irq_save(flags);
- if (up->port.sysrq) {
- locked = 0;
- } else if (oops_in_progress) {
- locked = spin_trylock(&up->port.lock);
- } else
- spin_lock(&up->port.lock);
+ if (up->port.sysrq || oops_in_progress)
+ locked = spin_trylock_irqsave(&up->port.lock, flags);
+ else
+ spin_lock_irqsave(&up->port.lock, flags);
uart_console_write(&up->port, s, n, sunsab_console_putchar);
sunsab_tec_wait(up);
if (locked)
- spin_unlock(&up->port.lock);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&up->port.lock, flags);
}
static int sunsab_console_setup(struct console *con, char *options)
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index db79b76f5c8e..9a0f24f83720 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -1295,13 +1295,10 @@ static void sunsu_console_write(struct console *co, const char *s,
unsigned int ier;
int locked = 1;
- local_irq_save(flags);
- if (up->port.sysrq) {
- locked = 0;
- } else if (oops_in_progress) {
- locked = spin_trylock(&up->port.lock);
- } else
- spin_lock(&up->port.lock);
+ if (up->port.sysrq || oops_in_progress)
+ locked = spin_trylock_irqsave(&up->port.lock, flags);
+ else
+ spin_lock_irqsave(&up->port.lock, flags);
/*
* First save the UER then disable the interrupts
@@ -1319,8 +1316,7 @@ static void sunsu_console_write(struct console *co, const char *s,
serial_out(up, UART_IER, ier);
if (locked)
- spin_unlock(&up->port.lock);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&up->port.lock, flags);
}
/*
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index 45a8c6aa5837..a2c40ed287d2 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -1195,20 +1195,16 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count)
unsigned long flags;
int locked = 1;
- local_irq_save(flags);
- if (up->port.sysrq) {
- locked = 0;
- } else if (oops_in_progress) {
- locked = spin_trylock(&up->port.lock);
- } else
- spin_lock(&up->port.lock);
+ if (up->port.sysrq || oops_in_progress)
+ locked = spin_trylock_irqsave(&up->port.lock, flags);
+ else
+ spin_lock_irqsave(&up->port.lock, flags);
uart_console_write(&up->port, s, count, sunzilog_putchar);
udelay(2);
if (locked)
- spin_unlock(&up->port.lock);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&up->port.lock, flags);
}
static int __init sunzilog_console_setup(struct console *con, char *options)
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 5ae14b46cce0..d48e040cd8c5 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -7866,6 +7866,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN);
+ memset(&new_line, 0, sizeof(new_line));
switch (flags){
case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break;
case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break;
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index 144202eef6fe..53ba8537de8d 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -1766,6 +1766,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN);
+ memset(&new_line, 0, sizeof(new_line));
switch (flags){
case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break;
case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break;
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 765125dff20e..8ebd9f88a6f6 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -351,14 +351,11 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags);
* Takes any pending buffers and transfers their ownership to the
* ldisc side of the queue. It then schedules those characters for
* processing by the line discipline.
- * Note that this function can only be used when the low_latency flag
- * is unset. Otherwise the workqueue won't be flushed.
*/
void tty_schedule_flip(struct tty_port *port)
{
struct tty_bufhead *buf = &port->buf;
- WARN_ON(port->low_latency);
buf->tail->commit = buf->tail->used;
schedule_work(&buf->work);
@@ -482,17 +479,15 @@ static void flush_to_ldisc(struct work_struct *work)
*/
void tty_flush_to_ldisc(struct tty_struct *tty)
{
- if (!tty->port->low_latency)
- flush_work(&tty->port->buf.work);
+ flush_work(&tty->port->buf.work);
}
/**
* tty_flip_buffer_push - terminal
* @port: tty port to push
*
- * Queue a push of the terminal flip buffers to the line discipline. This
- * function must not be called from IRQ context if port->low_latency is
- * set.
+ * Queue a push of the terminal flip buffers to the line discipline.
+ * Can be called from IRQ/atomic context.
*
* In the event of the queue being busy for flipping the work will be
* held off and retried later.
@@ -500,14 +495,7 @@ void tty_flush_to_ldisc(struct tty_struct *tty)
void tty_flip_buffer_push(struct tty_port *port)
{
- struct tty_bufhead *buf = &port->buf;
-
- buf->tail->commit = buf->tail->used;
-
- if (port->low_latency)
- flush_to_ldisc(&buf->work);
- else
- schedule_work(&buf->work);
+ tty_schedule_flip(port);
}
EXPORT_SYMBOL(tty_flip_buffer_push);
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index bd2715a9d8e5..d3448a90f0f9 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1267,7 +1267,7 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
* @p: output buffer of at least 7 bytes
*
* Generate a name from a driver reference and write it to the output
- * buffer. Return the number of bytes written.
+ * buffer.
*
* Locking: None
*/
@@ -3547,17 +3547,17 @@ static ssize_t show_cons_active(struct device *dev,
break;
}
while (i--) {
- struct tty_driver *driver;
- const char *name = cs[i]->name;
int index = cs[i]->index;
+ struct tty_driver *drv = cs[i]->device(cs[i], &index);
- driver = cs[i]->device(cs[i], &index);
- if (driver) {
- count += tty_line_name(driver, index, buf + count);
- count += sprintf(buf + count, "%c", i ? ' ':'\n');
- } else
- count += sprintf(buf + count, "%s%d%c",
- name, index, i ? ' ':'\n');
+ /* don't resolve tty0 as some programs depend on it */
+ if (drv && (cs[i]->index > 0 || drv->major != TTY_MAJOR))
+ count += tty_line_name(drv, index, buf + count);
+ else
+ count += sprintf(buf + count, "%s%d",
+ cs[i]->name, cs[i]->index);
+
+ count += sprintf(buf + count, "%c", i ? ' ':'\n');
}
console_unlock();
diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c
index d8a55e87877f..0ffb0cbe2823 100644
--- a/drivers/tty/tty_ldsem.c
+++ b/drivers/tty/tty_ldsem.c
@@ -39,17 +39,10 @@
lock_acquire(&(l)->dep_map, s, t, r, c, n, i)
# define __rel(l, n, i) \
lock_release(&(l)->dep_map, n, i)
-# ifdef CONFIG_PROVE_LOCKING
-# define lockdep_acquire(l, s, t, i) __acq(l, s, t, 0, 2, NULL, i)
-# define lockdep_acquire_nest(l, s, t, n, i) __acq(l, s, t, 0, 2, n, i)
-# define lockdep_acquire_read(l, s, t, i) __acq(l, s, t, 1, 2, NULL, i)
-# define lockdep_release(l, n, i) __rel(l, n, i)
-# else
-# define lockdep_acquire(l, s, t, i) __acq(l, s, t, 0, 1, NULL, i)
-# define lockdep_acquire_nest(l, s, t, n, i) __acq(l, s, t, 0, 1, n, i)
-# define lockdep_acquire_read(l, s, t, i) __acq(l, s, t, 1, 1, NULL, i)
-# define lockdep_release(l, n, i) __rel(l, n, i)
-# endif
+#define lockdep_acquire(l, s, t, i) __acq(l, s, t, 0, 1, NULL, i)
+#define lockdep_acquire_nest(l, s, t, n, i) __acq(l, s, t, 0, 1, n, i)
+#define lockdep_acquire_read(l, s, t, i) __acq(l, s, t, 1, 1, NULL, i)
+#define lockdep_release(l, n, i) __rel(l, n, i)
#else
# define lockdep_acquire(l, s, t, i) do { } while (0)
# define lockdep_acquire_nest(l, s, t, n, i) do { } while (0)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 23b5d32954bf..3ad0b61e35b4 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1590,9 +1590,9 @@ static void restore_cur(struct vc_data *vc)
vc->vc_need_wrap = 0;
}
-enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
+enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey,
EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
- ESpalette };
+ ESpalette, ESosc };
/* console_lock is held (except via vc_init()) */
static void reset_terminal(struct vc_data *vc, int do_clear)
@@ -1652,11 +1652,15 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
* Control characters can be used in the _middle_
* of an escape sequence.
*/
+ if (vc->vc_state == ESosc && c>=8 && c<=13) /* ... except for OSC */
+ return;
switch (c) {
case 0:
return;
case 7:
- if (vc->vc_bell_duration)
+ if (vc->vc_state == ESosc)
+ vc->vc_state = ESnormal;
+ else if (vc->vc_bell_duration)
kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
return;
case 8:
@@ -1767,7 +1771,9 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
} else if (c=='R') { /* reset palette */
reset_palette(vc);
vc->vc_state = ESnormal;
- } else
+ } else if (c>='0' && c<='9')
+ vc->vc_state = ESosc;
+ else
vc->vc_state = ESnormal;
return;
case ESpalette:
@@ -1807,9 +1813,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
vc->vc_par[vc->vc_npar] *= 10;
vc->vc_par[vc->vc_npar] += c - '0';
return;
- } else
- vc->vc_state = ESgotpars;
- case ESgotpars:
+ }
vc->vc_state = ESnormal;
switch(c) {
case 'h':
@@ -2023,6 +2027,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
vc->vc_state = ESnormal;
return;
+ case ESosc:
+ return;
default:
vc->vc_state = ESnormal;
}
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 2e6b832e004b..e0cad4418085 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -2,10 +2,6 @@
# USB device configuration
#
-# These are unused now, remove them once they are no longer selected
-config USB_ARCH_HAS_OHCI
- bool
-
config USB_OHCI_BIG_ENDIAN_DESC
bool
@@ -17,18 +13,12 @@ config USB_OHCI_LITTLE_ENDIAN
default n if STB03xxx || PPC_MPC52xx
default y
-config USB_ARCH_HAS_EHCI
- bool
-
config USB_EHCI_BIG_ENDIAN_MMIO
bool
config USB_EHCI_BIG_ENDIAN_DESC
bool
-config USB_ARCH_HAS_XHCI
- bool
-
menuconfig USB_SUPPORT
bool "USB support"
depends on HAS_IOMEM
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index 7345d2115af2..480bd4d5710a 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -10,6 +10,7 @@ ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o
# Glue/Bridge layers go here
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_msm.o
+obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_zevio.o
# PCI doesn't provide stubs, need to check
ifneq ($(CONFIG_PCI),)
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index a85713165688..83d06c1455b7 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -50,12 +50,14 @@
#define PORTSC_PTC (0x0FUL << 16)
#define PORTSC_PHCD(d) ((d) ? BIT(22) : BIT(23))
/* PTS and PTW for non lpm version only */
+#define PORTSC_PFSC BIT(24)
#define PORTSC_PTS(d) \
(u32)((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
#define PORTSC_PTW BIT(28)
#define PORTSC_STS BIT(29)
/* DEVLC */
+#define DEVLC_PFSC BIT(23)
#define DEVLC_PSPD (0x03UL << 25)
#define DEVLC_PSPD_HS (0x02UL << 25)
#define DEVLC_PTW BIT(27)
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 88b80f7728e4..e206406ae1d9 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -196,8 +196,6 @@ struct ci_hdrc {
struct ci_hdrc_platform_data *platdata;
int vbus_active;
- /* FIXME: some day, we'll not use global phy */
- bool global_phy;
struct usb_phy *transceiver;
struct usb_hcd *hcd;
struct dentry *debugfs;
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index c00f77257d36..2e58f8dfd311 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -96,7 +96,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
{
struct ci_hdrc_imx_data *data;
struct ci_hdrc_platform_data pdata = {
- .name = "ci_hdrc_imx",
+ .name = dev_name(&pdev->dev),
.capoffset = DEF_CAPOFFSET,
.flags = CI_HDRC_REQUIRE_TRANSCEIVER |
CI_HDRC_DISABLE_STREAMING,
diff --git a/drivers/usb/chipidea/ci_hdrc_zevio.c b/drivers/usb/chipidea/ci_hdrc_zevio.c
new file mode 100644
index 000000000000..3bf6489ef5ec
--- /dev/null
+++ b/drivers/usb/chipidea/ci_hdrc_zevio.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ * Based off drivers/usb/chipidea/ci_hdrc_msm.c
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+
+static struct ci_hdrc_platform_data ci_hdrc_zevio_platdata = {
+ .name = "ci_hdrc_zevio",
+ .flags = CI_HDRC_REGS_SHARED,
+ .capoffset = DEF_CAPOFFSET,
+};
+
+static int ci_hdrc_zevio_probe(struct platform_device *pdev)
+{
+ struct platform_device *ci_pdev;
+
+ dev_dbg(&pdev->dev, "ci_hdrc_zevio_probe\n");
+
+ ci_pdev = ci_hdrc_add_device(&pdev->dev,
+ pdev->resource, pdev->num_resources,
+ &ci_hdrc_zevio_platdata);
+
+ if (IS_ERR(ci_pdev)) {
+ dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n");
+ return PTR_ERR(ci_pdev);
+ }
+
+ platform_set_drvdata(pdev, ci_pdev);
+
+ return 0;
+}
+
+static int ci_hdrc_zevio_remove(struct platform_device *pdev)
+{
+ struct platform_device *ci_pdev = platform_get_drvdata(pdev);
+
+ ci_hdrc_remove_device(ci_pdev);
+
+ return 0;
+}
+
+static const struct of_device_id ci_hdrc_zevio_dt_ids[] = {
+ { .compatible = "lsi,zevio-usb", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver ci_hdrc_zevio_driver = {
+ .probe = ci_hdrc_zevio_probe,
+ .remove = ci_hdrc_zevio_remove,
+ .driver = {
+ .name = "zevio_usb",
+ .owner = THIS_MODULE,
+ .of_match_table = ci_hdrc_zevio_dt_ids,
+ },
+};
+
+MODULE_DEVICE_TABLE(of, ci_hdrc_zevio_dt_ids);
+module_platform_driver(ci_hdrc_zevio_driver);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 33f22bc6ad7f..ca6831c5b763 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -64,6 +64,7 @@
#include <linux/usb/otg.h>
#include <linux/usb/chipidea.h>
#include <linux/usb/of.h>
+#include <linux/of.h>
#include <linux/phy.h>
#include <linux/regulator/consumer.h>
@@ -298,6 +299,13 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode)
if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
+ if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) {
+ if (ci->hw_bank.lpm)
+ hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC);
+ else
+ hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC);
+ }
+
/* USBMODE should be configured step by step */
hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
hw_write(ci, OP_USBMODE, USBMODE_CM, mode);
@@ -412,6 +420,9 @@ static int ci_get_platdata(struct device *dev,
}
}
+ if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL)
+ platdata->flags |= CI_HDRC_FORCE_FULLSPEED;
+
return 0;
}
@@ -496,33 +507,6 @@ static void ci_get_otg_capable(struct ci_hdrc *ci)
}
}
-static int ci_usb_phy_init(struct ci_hdrc *ci)
-{
- if (ci->platdata->phy) {
- ci->transceiver = ci->platdata->phy;
- return usb_phy_init(ci->transceiver);
- } else {
- ci->global_phy = true;
- ci->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
- if (IS_ERR(ci->transceiver))
- ci->transceiver = NULL;
-
- return 0;
- }
-}
-
-static void ci_usb_phy_destroy(struct ci_hdrc *ci)
-{
- if (!ci->transceiver)
- return;
-
- otg_set_peripheral(ci->transceiver->otg, NULL);
- if (ci->global_phy)
- usb_put_phy(ci->transceiver);
- else
- usb_phy_shutdown(ci->transceiver);
-}
-
static int ci_hdrc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -532,7 +516,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
int ret;
enum usb_dr_mode dr_mode;
- if (!dev->platform_data) {
+ if (!dev_get_platdata(dev)) {
dev_err(dev, "platform data missing\n");
return -ENODEV;
}
@@ -549,7 +533,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
}
ci->dev = dev;
- ci->platdata = dev->platform_data;
+ ci->platdata = dev_get_platdata(dev);
ci->imx28_write_fix = !!(ci->platdata->flags &
CI_HDRC_IMX28_WRITE_FIX);
@@ -561,7 +545,26 @@ static int ci_hdrc_probe(struct platform_device *pdev)
hw_phymode_configure(ci);
- ret = ci_usb_phy_init(ci);
+ if (ci->platdata->phy)
+ ci->transceiver = ci->platdata->phy;
+ else
+ ci->transceiver = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+
+ if (IS_ERR(ci->transceiver)) {
+ ret = PTR_ERR(ci->transceiver);
+ /*
+ * if -ENXIO is returned, it means PHY layer wasn't
+ * enabled, so it makes no sense to return -EPROBE_DEFER
+ * in that case, since no PHY driver will ever probe.
+ */
+ if (ret == -ENXIO)
+ return ret;
+
+ dev_err(dev, "no usb2 phy configured\n");
+ return -EPROBE_DEFER;
+ }
+
+ ret = usb_phy_init(ci->transceiver);
if (ret) {
dev_err(dev, "unable to init phy: %d\n", ret);
return ret;
@@ -572,8 +575,8 @@ static int ci_hdrc_probe(struct platform_device *pdev)
ci->irq = platform_get_irq(pdev, 0);
if (ci->irq < 0) {
dev_err(dev, "missing IRQ\n");
- ret = -ENODEV;
- goto destroy_phy;
+ ret = ci->irq;
+ goto deinit_phy;
}
ci_get_otg_capable(ci);
@@ -590,23 +593,12 @@ static int ci_hdrc_probe(struct platform_device *pdev)
ret = ci_hdrc_gadget_init(ci);
if (ret)
dev_info(dev, "doesn't support gadget\n");
- if (!ret && ci->transceiver) {
- ret = otg_set_peripheral(ci->transceiver->otg,
- &ci->gadget);
- /*
- * If we implement all USB functions using chipidea drivers,
- * it doesn't need to call above API, meanwhile, if we only
- * use gadget function, calling above API is useless.
- */
- if (ret && ret != -ENOTSUPP)
- goto destroy_phy;
- }
}
if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
dev_err(dev, "no supported roles\n");
ret = -ENODEV;
- goto destroy_phy;
+ goto deinit_phy;
}
if (ci->is_otg) {
@@ -663,8 +655,8 @@ static int ci_hdrc_probe(struct platform_device *pdev)
free_irq(ci->irq, ci);
stop:
ci_role_destroy(ci);
-destroy_phy:
- ci_usb_phy_destroy(ci);
+deinit_phy:
+ usb_phy_shutdown(ci->transceiver);
return ret;
}
@@ -677,7 +669,8 @@ static int ci_hdrc_remove(struct platform_device *pdev)
free_irq(ci->irq, ci);
ci_role_destroy(ci);
ci_hdrc_enter_lpm(ci, true);
- ci_usb_phy_destroy(ci);
+ usb_phy_shutdown(ci->transceiver);
+ kfree(ci->hw_bank.regmap);
return 0;
}
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 80de2f88ed2c..7739c64ef259 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -105,7 +105,7 @@ static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir)
do {
/* flush any pending transfer */
- hw_write(ci, OP_ENDPTFLUSH, BIT(n), BIT(n));
+ hw_write(ci, OP_ENDPTFLUSH, ~0, BIT(n));
while (hw_read(ci, OP_ENDPTFLUSH, BIT(n)))
cpu_relax();
} while (hw_read(ci, OP_ENDPTSTAT, BIT(n)));
@@ -178,19 +178,6 @@ static int hw_ep_get_halt(struct ci_hdrc *ci, int num, int dir)
}
/**
- * hw_test_and_clear_setup_status: test & clear setup status (execute without
- * interruption)
- * @n: endpoint number
- *
- * This function returns setup status
- */
-static int hw_test_and_clear_setup_status(struct ci_hdrc *ci, int n)
-{
- n = ep_to_bit(ci, n);
- return hw_test_and_clear(ci, OP_ENDPTSETUPSTAT, BIT(n));
-}
-
-/**
* hw_ep_prime: primes endpoint (execute without interruption)
* @num: endpoint number
* @dir: endpoint direction
@@ -205,7 +192,7 @@ static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl)
if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num)))
return -EAGAIN;
- hw_write(ci, OP_ENDPTPRIME, BIT(n), BIT(n));
+ hw_write(ci, OP_ENDPTPRIME, ~0, BIT(n));
while (hw_read(ci, OP_ENDPTPRIME, BIT(n)))
cpu_relax();
@@ -962,6 +949,156 @@ __acquires(hwep->lock)
}
/**
+ * isr_setup_packet_handler: setup packet handler
+ * @ci: UDC descriptor
+ *
+ * This function handles setup packet
+ */
+static void isr_setup_packet_handler(struct ci_hdrc *ci)
+__releases(ci->lock)
+__acquires(ci->lock)
+{
+ struct ci_hw_ep *hwep = &ci->ci_hw_ep[0];
+ struct usb_ctrlrequest req;
+ int type, num, dir, err = -EINVAL;
+ u8 tmode = 0;
+
+ /*
+ * Flush data and handshake transactions of previous
+ * setup packet.
+ */
+ _ep_nuke(ci->ep0out);
+ _ep_nuke(ci->ep0in);
+
+ /* read_setup_packet */
+ do {
+ hw_test_and_set_setup_guard(ci);
+ memcpy(&req, &hwep->qh.ptr->setup, sizeof(req));
+ } while (!hw_test_and_clear_setup_guard(ci));
+
+ type = req.bRequestType;
+
+ ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
+
+ switch (req.bRequest) {
+ case USB_REQ_CLEAR_FEATURE:
+ if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+ le16_to_cpu(req.wValue) ==
+ USB_ENDPOINT_HALT) {
+ if (req.wLength != 0)
+ break;
+ num = le16_to_cpu(req.wIndex);
+ dir = num & USB_ENDPOINT_DIR_MASK;
+ num &= USB_ENDPOINT_NUMBER_MASK;
+ if (dir) /* TX */
+ num += ci->hw_ep_max / 2;
+ if (!ci->ci_hw_ep[num].wedge) {
+ spin_unlock(&ci->lock);
+ err = usb_ep_clear_halt(
+ &ci->ci_hw_ep[num].ep);
+ spin_lock(&ci->lock);
+ if (err)
+ break;
+ }
+ err = isr_setup_status_phase(ci);
+ } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
+ le16_to_cpu(req.wValue) ==
+ USB_DEVICE_REMOTE_WAKEUP) {
+ if (req.wLength != 0)
+ break;
+ ci->remote_wakeup = 0;
+ err = isr_setup_status_phase(ci);
+ } else {
+ goto delegate;
+ }
+ break;
+ case USB_REQ_GET_STATUS:
+ if (type != (USB_DIR_IN|USB_RECIP_DEVICE) &&
+ type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
+ type != (USB_DIR_IN|USB_RECIP_INTERFACE))
+ goto delegate;
+ if (le16_to_cpu(req.wLength) != 2 ||
+ le16_to_cpu(req.wValue) != 0)
+ break;
+ err = isr_get_status_response(ci, &req);
+ break;
+ case USB_REQ_SET_ADDRESS:
+ if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
+ goto delegate;
+ if (le16_to_cpu(req.wLength) != 0 ||
+ le16_to_cpu(req.wIndex) != 0)
+ break;
+ ci->address = (u8)le16_to_cpu(req.wValue);
+ ci->setaddr = true;
+ err = isr_setup_status_phase(ci);
+ break;
+ case USB_REQ_SET_FEATURE:
+ if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+ le16_to_cpu(req.wValue) ==
+ USB_ENDPOINT_HALT) {
+ if (req.wLength != 0)
+ break;
+ num = le16_to_cpu(req.wIndex);
+ dir = num & USB_ENDPOINT_DIR_MASK;
+ num &= USB_ENDPOINT_NUMBER_MASK;
+ if (dir) /* TX */
+ num += ci->hw_ep_max / 2;
+
+ spin_unlock(&ci->lock);
+ err = usb_ep_set_halt(&ci->ci_hw_ep[num].ep);
+ spin_lock(&ci->lock);
+ if (!err)
+ isr_setup_status_phase(ci);
+ } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) {
+ if (req.wLength != 0)
+ break;
+ switch (le16_to_cpu(req.wValue)) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ ci->remote_wakeup = 1;
+ err = isr_setup_status_phase(ci);
+ break;
+ case USB_DEVICE_TEST_MODE:
+ tmode = le16_to_cpu(req.wIndex) >> 8;
+ switch (tmode) {
+ case TEST_J:
+ case TEST_K:
+ case TEST_SE0_NAK:
+ case TEST_PACKET:
+ case TEST_FORCE_EN:
+ ci->test_mode = tmode;
+ err = isr_setup_status_phase(
+ ci);
+ break;
+ default:
+ break;
+ }
+ default:
+ goto delegate;
+ }
+ } else {
+ goto delegate;
+ }
+ break;
+ default:
+delegate:
+ if (req.wLength == 0) /* no data phase */
+ ci->ep0_dir = TX;
+
+ spin_unlock(&ci->lock);
+ err = ci->driver->setup(&ci->gadget, &req);
+ spin_lock(&ci->lock);
+ break;
+ }
+
+ if (err < 0) {
+ spin_unlock(&ci->lock);
+ if (usb_ep_set_halt(&hwep->ep))
+ dev_err(ci->dev, "error: ep_set_halt\n");
+ spin_lock(&ci->lock);
+ }
+}
+
+/**
* isr_tr_complete_handler: transaction complete interrupt handler
* @ci: UDC descriptor
*
@@ -972,12 +1109,10 @@ __releases(ci->lock)
__acquires(ci->lock)
{
unsigned i;
- u8 tmode = 0;
+ int err;
for (i = 0; i < ci->hw_ep_max; i++) {
struct ci_hw_ep *hwep = &ci->ci_hw_ep[i];
- int type, num, dir, err = -EINVAL;
- struct usb_ctrlrequest req;
if (hwep->ep.desc == NULL)
continue; /* not configured */
@@ -997,148 +1132,10 @@ __acquires(ci->lock)
}
}
- if (hwep->type != USB_ENDPOINT_XFER_CONTROL ||
- !hw_test_and_clear_setup_status(ci, i))
- continue;
-
- if (i != 0) {
- dev_warn(ci->dev, "ctrl traffic at endpoint %d\n", i);
- continue;
- }
-
- /*
- * Flush data and handshake transactions of previous
- * setup packet.
- */
- _ep_nuke(ci->ep0out);
- _ep_nuke(ci->ep0in);
-
- /* read_setup_packet */
- do {
- hw_test_and_set_setup_guard(ci);
- memcpy(&req, &hwep->qh.ptr->setup, sizeof(req));
- } while (!hw_test_and_clear_setup_guard(ci));
-
- type = req.bRequestType;
-
- ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
-
- switch (req.bRequest) {
- case USB_REQ_CLEAR_FEATURE:
- if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
- le16_to_cpu(req.wValue) ==
- USB_ENDPOINT_HALT) {
- if (req.wLength != 0)
- break;
- num = le16_to_cpu(req.wIndex);
- dir = num & USB_ENDPOINT_DIR_MASK;
- num &= USB_ENDPOINT_NUMBER_MASK;
- if (dir) /* TX */
- num += ci->hw_ep_max/2;
- if (!ci->ci_hw_ep[num].wedge) {
- spin_unlock(&ci->lock);
- err = usb_ep_clear_halt(
- &ci->ci_hw_ep[num].ep);
- spin_lock(&ci->lock);
- if (err)
- break;
- }
- err = isr_setup_status_phase(ci);
- } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
- le16_to_cpu(req.wValue) ==
- USB_DEVICE_REMOTE_WAKEUP) {
- if (req.wLength != 0)
- break;
- ci->remote_wakeup = 0;
- err = isr_setup_status_phase(ci);
- } else {
- goto delegate;
- }
- break;
- case USB_REQ_GET_STATUS:
- if (type != (USB_DIR_IN|USB_RECIP_DEVICE) &&
- type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
- type != (USB_DIR_IN|USB_RECIP_INTERFACE))
- goto delegate;
- if (le16_to_cpu(req.wLength) != 2 ||
- le16_to_cpu(req.wValue) != 0)
- break;
- err = isr_get_status_response(ci, &req);
- break;
- case USB_REQ_SET_ADDRESS:
- if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
- goto delegate;
- if (le16_to_cpu(req.wLength) != 0 ||
- le16_to_cpu(req.wIndex) != 0)
- break;
- ci->address = (u8)le16_to_cpu(req.wValue);
- ci->setaddr = true;
- err = isr_setup_status_phase(ci);
- break;
- case USB_REQ_SET_FEATURE:
- if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
- le16_to_cpu(req.wValue) ==
- USB_ENDPOINT_HALT) {
- if (req.wLength != 0)
- break;
- num = le16_to_cpu(req.wIndex);
- dir = num & USB_ENDPOINT_DIR_MASK;
- num &= USB_ENDPOINT_NUMBER_MASK;
- if (dir) /* TX */
- num += ci->hw_ep_max/2;
-
- spin_unlock(&ci->lock);
- err = usb_ep_set_halt(&ci->ci_hw_ep[num].ep);
- spin_lock(&ci->lock);
- if (!err)
- isr_setup_status_phase(ci);
- } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) {
- if (req.wLength != 0)
- break;
- switch (le16_to_cpu(req.wValue)) {
- case USB_DEVICE_REMOTE_WAKEUP:
- ci->remote_wakeup = 1;
- err = isr_setup_status_phase(ci);
- break;
- case USB_DEVICE_TEST_MODE:
- tmode = le16_to_cpu(req.wIndex) >> 8;
- switch (tmode) {
- case TEST_J:
- case TEST_K:
- case TEST_SE0_NAK:
- case TEST_PACKET:
- case TEST_FORCE_EN:
- ci->test_mode = tmode;
- err = isr_setup_status_phase(
- ci);
- break;
- default:
- break;
- }
- default:
- goto delegate;
- }
- } else {
- goto delegate;
- }
- break;
- default:
-delegate:
- if (req.wLength == 0) /* no data phase */
- ci->ep0_dir = TX;
-
- spin_unlock(&ci->lock);
- err = ci->driver->setup(&ci->gadget, &req);
- spin_lock(&ci->lock);
- break;
- }
-
- if (err < 0) {
- spin_unlock(&ci->lock);
- if (usb_ep_set_halt(&hwep->ep))
- dev_err(ci->dev, "error: ep_set_halt\n");
- spin_lock(&ci->lock);
- }
+ /* Only handle setup packet below */
+ if (i == 0 &&
+ hw_test_and_clear(ci, OP_ENDPTSETUPSTAT, BIT(0)))
+ isr_setup_packet_handler(ci);
}
}
@@ -1193,6 +1190,11 @@ static int ep_enable(struct usb_ep *ep,
hwep->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE); /* needed? */
+ if (hwep->num != 0 && hwep->type == USB_ENDPOINT_XFER_CONTROL) {
+ dev_err(hwep->ci->dev, "Set control xfer at non-ep0\n");
+ retval = -EINVAL;
+ }
+
/*
* Enable endpoints in the HW other than ep0 as ep0
* is always enabled
@@ -1837,12 +1839,6 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
dma_pool_destroy(ci->td_pool);
dma_pool_destroy(ci->qh_pool);
-
- if (ci->transceiver) {
- otg_set_peripheral(ci->transceiver->otg, NULL);
- if (ci->global_phy)
- usb_put_phy(ci->transceiver);
- }
}
static int udc_id_switch_for_device(struct ci_hdrc *ci)
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 8d72f0c65937..1ab4df1de2da 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -10,7 +10,6 @@
#define USB_MAXALTSETTING 128 /* Hard limit */
-#define USB_MAXENDPOINTS 30 /* Hard limit */
#define USB_MAXCONFIG 8 /* Arbitrary limit */
@@ -717,6 +716,10 @@ int usb_get_configuration(struct usb_device *dev)
result = -ENOMEM;
goto err;
}
+
+ if (dev->quirks & USB_QUIRK_DELAY_INIT)
+ msleep(100);
+
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
bigbuffer, length);
if (result < 0) {
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 90e18f6fa2bb..257876ea03a1 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -62,7 +62,7 @@
/* Mutual exclusion for removal, open, and release */
DEFINE_MUTEX(usbfs_mutex);
-struct dev_state {
+struct usb_dev_state {
struct list_head list; /* state list */
struct usb_device *dev;
struct file *file;
@@ -81,7 +81,7 @@ struct dev_state {
struct async {
struct list_head asynclist;
- struct dev_state *ps;
+ struct usb_dev_state *ps;
struct pid *pid;
const struct cred *cred;
unsigned int signr;
@@ -151,7 +151,7 @@ static void usbfs_decrease_memory_usage(unsigned amount)
atomic_sub(amount, &usbfs_memory_usage);
}
-static int connected(struct dev_state *ps)
+static int connected(struct usb_dev_state *ps)
{
return (!list_empty(&ps->list) &&
ps->dev->state != USB_STATE_NOTATTACHED);
@@ -184,7 +184,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,
loff_t *ppos)
{
- struct dev_state *ps = file->private_data;
+ struct usb_dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
ssize_t ret = 0;
unsigned len;
@@ -307,7 +307,7 @@ static void free_async(struct async *as)
static void async_newpending(struct async *as)
{
- struct dev_state *ps = as->ps;
+ struct usb_dev_state *ps = as->ps;
unsigned long flags;
spin_lock_irqsave(&ps->lock, flags);
@@ -317,7 +317,7 @@ static void async_newpending(struct async *as)
static void async_removepending(struct async *as)
{
- struct dev_state *ps = as->ps;
+ struct usb_dev_state *ps = as->ps;
unsigned long flags;
spin_lock_irqsave(&ps->lock, flags);
@@ -325,7 +325,7 @@ static void async_removepending(struct async *as)
spin_unlock_irqrestore(&ps->lock, flags);
}
-static struct async *async_getcompleted(struct dev_state *ps)
+static struct async *async_getcompleted(struct usb_dev_state *ps)
{
unsigned long flags;
struct async *as = NULL;
@@ -340,7 +340,7 @@ static struct async *async_getcompleted(struct dev_state *ps)
return as;
}
-static struct async *async_getpending(struct dev_state *ps,
+static struct async *async_getpending(struct usb_dev_state *ps,
void __user *userurb)
{
struct async *as;
@@ -448,7 +448,7 @@ static int copy_urb_data_to_user(u8 __user *userbuffer, struct urb *urb)
#define AS_CONTINUATION 1
#define AS_UNLINK 2
-static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr)
+static void cancel_bulk_urbs(struct usb_dev_state *ps, unsigned bulk_addr)
__releases(ps->lock)
__acquires(ps->lock)
{
@@ -489,7 +489,7 @@ __acquires(ps->lock)
static void async_completed(struct urb *urb)
{
struct async *as = urb->context;
- struct dev_state *ps = as->ps;
+ struct usb_dev_state *ps = as->ps;
struct siginfo sinfo;
struct pid *pid = NULL;
u32 secid = 0;
@@ -529,7 +529,7 @@ static void async_completed(struct urb *urb)
wake_up(&ps->wait);
}
-static void destroy_async(struct dev_state *ps, struct list_head *list)
+static void destroy_async(struct usb_dev_state *ps, struct list_head *list)
{
struct urb *urb;
struct async *as;
@@ -551,7 +551,7 @@ static void destroy_async(struct dev_state *ps, struct list_head *list)
spin_unlock_irqrestore(&ps->lock, flags);
}
-static void destroy_async_on_interface(struct dev_state *ps,
+static void destroy_async_on_interface(struct usb_dev_state *ps,
unsigned int ifnum)
{
struct list_head *p, *q, hitlist;
@@ -566,7 +566,7 @@ static void destroy_async_on_interface(struct dev_state *ps,
destroy_async(ps, &hitlist);
}
-static void destroy_all_async(struct dev_state *ps)
+static void destroy_all_async(struct usb_dev_state *ps)
{
destroy_async(ps, &ps->async_pending);
}
@@ -585,7 +585,7 @@ static int driver_probe(struct usb_interface *intf,
static void driver_disconnect(struct usb_interface *intf)
{
- struct dev_state *ps = usb_get_intfdata(intf);
+ struct usb_dev_state *ps = usb_get_intfdata(intf);
unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;
if (!ps)
@@ -628,7 +628,7 @@ struct usb_driver usbfs_driver = {
.resume = driver_resume,
};
-static int claimintf(struct dev_state *ps, unsigned int ifnum)
+static int claimintf(struct usb_dev_state *ps, unsigned int ifnum)
{
struct usb_device *dev = ps->dev;
struct usb_interface *intf;
@@ -650,7 +650,7 @@ static int claimintf(struct dev_state *ps, unsigned int ifnum)
return err;
}
-static int releaseintf(struct dev_state *ps, unsigned int ifnum)
+static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum)
{
struct usb_device *dev;
struct usb_interface *intf;
@@ -670,7 +670,7 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum)
return err;
}
-static int checkintf(struct dev_state *ps, unsigned int ifnum)
+static int checkintf(struct usb_dev_state *ps, unsigned int ifnum)
{
if (ps->dev->state != USB_STATE_CONFIGURED)
return -EHOSTUNREACH;
@@ -710,7 +710,7 @@ static int findintfep(struct usb_device *dev, unsigned int ep)
return -ENOENT;
}
-static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
+static int check_ctrlrecip(struct usb_dev_state *ps, unsigned int requesttype,
unsigned int request, unsigned int index)
{
int ret = 0;
@@ -769,6 +769,88 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
return ret;
}
+static struct usb_host_endpoint *ep_to_host_endpoint(struct usb_device *dev,
+ unsigned char ep)
+{
+ if (ep & USB_ENDPOINT_DIR_MASK)
+ return dev->ep_in[ep & USB_ENDPOINT_NUMBER_MASK];
+ else
+ return dev->ep_out[ep & USB_ENDPOINT_NUMBER_MASK];
+}
+
+static int parse_usbdevfs_streams(struct usb_dev_state *ps,
+ struct usbdevfs_streams __user *streams,
+ unsigned int *num_streams_ret,
+ unsigned int *num_eps_ret,
+ struct usb_host_endpoint ***eps_ret,
+ struct usb_interface **intf_ret)
+{
+ unsigned int i, num_streams, num_eps;
+ struct usb_host_endpoint **eps;
+ struct usb_interface *intf = NULL;
+ unsigned char ep;
+ int ifnum, ret;
+
+ if (get_user(num_streams, &streams->num_streams) ||
+ get_user(num_eps, &streams->num_eps))
+ return -EFAULT;
+
+ if (num_eps < 1 || num_eps > USB_MAXENDPOINTS)
+ return -EINVAL;
+
+ /* The XHCI controller allows max 2 ^ 16 streams */
+ if (num_streams_ret && (num_streams < 2 || num_streams > 65536))
+ return -EINVAL;
+
+ eps = kmalloc(num_eps * sizeof(*eps), GFP_KERNEL);
+ if (!eps)
+ return -ENOMEM;
+
+ for (i = 0; i < num_eps; i++) {
+ if (get_user(ep, &streams->eps[i])) {
+ ret = -EFAULT;
+ goto error;
+ }
+ eps[i] = ep_to_host_endpoint(ps->dev, ep);
+ if (!eps[i]) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* usb_alloc/free_streams operate on an usb_interface */
+ ifnum = findintfep(ps->dev, ep);
+ if (ifnum < 0) {
+ ret = ifnum;
+ goto error;
+ }
+
+ if (i == 0) {
+ ret = checkintf(ps, ifnum);
+ if (ret < 0)
+ goto error;
+ intf = usb_ifnum_to_if(ps->dev, ifnum);
+ } else {
+ /* Verify all eps belong to the same interface */
+ if (ifnum != intf->altsetting->desc.bInterfaceNumber) {
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ }
+
+ if (num_streams_ret)
+ *num_streams_ret = num_streams;
+ *num_eps_ret = num_eps;
+ *eps_ret = eps;
+ *intf_ret = intf;
+
+ return 0;
+
+error:
+ kfree(eps);
+ return ret;
+}
+
static int match_devt(struct device *dev, void *data)
{
return dev->devt == (dev_t) (unsigned long) data;
@@ -791,11 +873,11 @@ static struct usb_device *usbdev_lookup_by_devt(dev_t devt)
static int usbdev_open(struct inode *inode, struct file *file)
{
struct usb_device *dev = NULL;
- struct dev_state *ps;
+ struct usb_dev_state *ps;
int ret;
ret = -ENOMEM;
- ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL);
+ ps = kmalloc(sizeof(struct usb_dev_state), GFP_KERNEL);
if (!ps)
goto out_free_ps;
@@ -852,7 +934,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
static int usbdev_release(struct inode *inode, struct file *file)
{
- struct dev_state *ps = file->private_data;
+ struct usb_dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
unsigned int ifnum;
struct async *as;
@@ -883,7 +965,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
return 0;
}
-static int proc_control(struct dev_state *ps, void __user *arg)
+static int proc_control(struct usb_dev_state *ps, void __user *arg)
{
struct usb_device *dev = ps->dev;
struct usbdevfs_ctrltransfer ctrl;
@@ -970,7 +1052,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)
return ret;
}
-static int proc_bulk(struct dev_state *ps, void __user *arg)
+static int proc_bulk(struct usb_dev_state *ps, void __user *arg)
{
struct usb_device *dev = ps->dev;
struct usbdevfs_bulktransfer bulk;
@@ -1043,7 +1125,21 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
return ret;
}
-static int proc_resetep(struct dev_state *ps, void __user *arg)
+static void check_reset_of_active_ep(struct usb_device *udev,
+ unsigned int epnum, char *ioctl_name)
+{
+ struct usb_host_endpoint **eps;
+ struct usb_host_endpoint *ep;
+
+ eps = (epnum & USB_DIR_IN) ? udev->ep_in : udev->ep_out;
+ ep = eps[epnum & 0x0f];
+ if (ep && !list_empty(&ep->urb_list))
+ dev_warn(&udev->dev, "Process %d (%s) called USBDEVFS_%s for active endpoint 0x%02x\n",
+ task_pid_nr(current), current->comm,
+ ioctl_name, epnum);
+}
+
+static int proc_resetep(struct usb_dev_state *ps, void __user *arg)
{
unsigned int ep;
int ret;
@@ -1056,11 +1152,12 @@ static int proc_resetep(struct dev_state *ps, void __user *arg)
ret = checkintf(ps, ret);
if (ret)
return ret;
+ check_reset_of_active_ep(ps->dev, ep, "RESETEP");
usb_reset_endpoint(ps->dev, ep);
return 0;
}
-static int proc_clearhalt(struct dev_state *ps, void __user *arg)
+static int proc_clearhalt(struct usb_dev_state *ps, void __user *arg)
{
unsigned int ep;
int pipe;
@@ -1074,6 +1171,7 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg)
ret = checkintf(ps, ret);
if (ret)
return ret;
+ check_reset_of_active_ep(ps->dev, ep, "CLEAR_HALT");
if (ep & USB_DIR_IN)
pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
else
@@ -1082,7 +1180,7 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg)
return usb_clear_halt(ps->dev, pipe);
}
-static int proc_getdriver(struct dev_state *ps, void __user *arg)
+static int proc_getdriver(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_getdriver gd;
struct usb_interface *intf;
@@ -1101,7 +1199,7 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
return ret;
}
-static int proc_connectinfo(struct dev_state *ps, void __user *arg)
+static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_connectinfo ci = {
.devnum = ps->dev->devnum,
@@ -1113,12 +1211,12 @@ static int proc_connectinfo(struct dev_state *ps, void __user *arg)
return 0;
}
-static int proc_resetdevice(struct dev_state *ps)
+static int proc_resetdevice(struct usb_dev_state *ps)
{
return usb_reset_device(ps->dev);
}
-static int proc_setintf(struct dev_state *ps, void __user *arg)
+static int proc_setintf(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_setinterface setintf;
int ret;
@@ -1127,11 +1225,14 @@ static int proc_setintf(struct dev_state *ps, void __user *arg)
return -EFAULT;
if ((ret = checkintf(ps, setintf.interface)))
return ret;
+
+ destroy_async_on_interface(ps, setintf.interface);
+
return usb_set_interface(ps->dev, setintf.interface,
setintf.altsetting);
}
-static int proc_setconfig(struct dev_state *ps, void __user *arg)
+static int proc_setconfig(struct usb_dev_state *ps, void __user *arg)
{
int u;
int status = 0;
@@ -1179,7 +1280,7 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
return status;
}
-static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
+static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb,
struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
void __user *arg)
{
@@ -1189,6 +1290,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
struct usb_ctrlrequest *dr = NULL;
unsigned int u, totlen, isofrmlen;
int i, ret, is_in, num_sgs = 0, ifnum = -1;
+ int number_of_packets = 0;
+ unsigned int stream_id = 0;
void *buf;
if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP |
@@ -1209,15 +1312,10 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
if (ret)
return ret;
}
- if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
- is_in = 1;
- ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
- } else {
- is_in = 0;
- ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
- }
+ ep = ep_to_host_endpoint(ps->dev, uurb->endpoint);
if (!ep)
return -ENOENT;
+ is_in = (uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0;
u = 0;
switch(uurb->type) {
@@ -1242,7 +1340,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
le16_to_cpup(&dr->wIndex));
if (ret)
goto error;
- uurb->number_of_packets = 0;
uurb->buffer_length = le16_to_cpup(&dr->wLength);
uurb->buffer += 8;
if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
@@ -1272,17 +1369,17 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
uurb->type = USBDEVFS_URB_TYPE_INTERRUPT;
goto interrupt_urb;
}
- uurb->number_of_packets = 0;
num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE);
if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize)
num_sgs = 0;
+ if (ep->streams)
+ stream_id = uurb->stream_id;
break;
case USBDEVFS_URB_TYPE_INTERRUPT:
if (!usb_endpoint_xfer_int(&ep->desc))
return -EINVAL;
interrupt_urb:
- uurb->number_of_packets = 0;
break;
case USBDEVFS_URB_TYPE_ISO:
@@ -1292,15 +1389,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -EINVAL;
if (!usb_endpoint_xfer_isoc(&ep->desc))
return -EINVAL;
+ number_of_packets = uurb->number_of_packets;
isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) *
- uurb->number_of_packets;
+ number_of_packets;
if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
return -ENOMEM;
if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
ret = -EFAULT;
goto error;
}
- for (totlen = u = 0; u < uurb->number_of_packets; u++) {
+ for (totlen = u = 0; u < number_of_packets; u++) {
/*
* arbitrary limit need for USB 3.0
* bMaxBurst (0~15 allowed, 1~16 packets)
@@ -1331,7 +1429,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
ret = -EFAULT;
goto error;
}
- as = alloc_async(uurb->number_of_packets);
+ as = alloc_async(number_of_packets);
if (!as) {
ret = -ENOMEM;
goto error;
@@ -1425,7 +1523,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->urb->setup_packet = (unsigned char *)dr;
dr = NULL;
as->urb->start_frame = uurb->start_frame;
- as->urb->number_of_packets = uurb->number_of_packets;
+ as->urb->number_of_packets = number_of_packets;
+ as->urb->stream_id = stream_id;
if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
ps->dev->speed == USB_SPEED_HIGH)
as->urb->interval = 1 << min(15, ep->desc.bInterval - 1);
@@ -1433,7 +1532,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->urb->interval = ep->desc.bInterval;
as->urb->context = as;
as->urb->complete = async_completed;
- for (totlen = u = 0; u < uurb->number_of_packets; u++) {
+ for (totlen = u = 0; u < number_of_packets; u++) {
as->urb->iso_frame_desc[u].offset = totlen;
as->urb->iso_frame_desc[u].length = isopkt[u].length;
totlen += isopkt[u].length;
@@ -1508,7 +1607,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return ret;
}
-static int proc_submiturb(struct dev_state *ps, void __user *arg)
+static int proc_submiturb(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_urb uurb;
@@ -1520,7 +1619,7 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
arg);
}
-static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
+static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg)
{
struct urb *urb;
struct async *as;
@@ -1580,7 +1679,7 @@ err_out:
return -EFAULT;
}
-static struct async *reap_as(struct dev_state *ps)
+static struct async *reap_as(struct usb_dev_state *ps)
{
DECLARE_WAITQUEUE(wait, current);
struct async *as = NULL;
@@ -1603,7 +1702,7 @@ static struct async *reap_as(struct dev_state *ps)
return as;
}
-static int proc_reapurb(struct dev_state *ps, void __user *arg)
+static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
{
struct async *as = reap_as(ps);
if (as) {
@@ -1616,7 +1715,7 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg)
return -EIO;
}
-static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)
+static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
{
int retval;
struct async *as;
@@ -1631,7 +1730,7 @@ static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)
}
#ifdef CONFIG_COMPAT
-static int proc_control_compat(struct dev_state *ps,
+static int proc_control_compat(struct usb_dev_state *ps,
struct usbdevfs_ctrltransfer32 __user *p32)
{
struct usbdevfs_ctrltransfer __user *p;
@@ -1644,7 +1743,7 @@ static int proc_control_compat(struct dev_state *ps,
return proc_control(ps, p);
}
-static int proc_bulk_compat(struct dev_state *ps,
+static int proc_bulk_compat(struct usb_dev_state *ps,
struct usbdevfs_bulktransfer32 __user *p32)
{
struct usbdevfs_bulktransfer __user *p;
@@ -1661,7 +1760,7 @@ static int proc_bulk_compat(struct dev_state *ps,
return proc_bulk(ps, p);
}
-static int proc_disconnectsignal_compat(struct dev_state *ps, void __user *arg)
+static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_disconnectsignal32 ds;
@@ -1699,7 +1798,7 @@ static int get_urb32(struct usbdevfs_urb *kurb,
return 0;
}
-static int proc_submiturb_compat(struct dev_state *ps, void __user *arg)
+static int proc_submiturb_compat(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_urb uurb;
@@ -1745,7 +1844,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
return 0;
}
-static int proc_reapurb_compat(struct dev_state *ps, void __user *arg)
+static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
{
struct async *as = reap_as(ps);
if (as) {
@@ -1758,7 +1857,7 @@ static int proc_reapurb_compat(struct dev_state *ps, void __user *arg)
return -EIO;
}
-static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg)
+static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg)
{
int retval;
struct async *as;
@@ -1775,7 +1874,7 @@ static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg)
#endif
-static int proc_disconnectsignal(struct dev_state *ps, void __user *arg)
+static int proc_disconnectsignal(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_disconnectsignal ds;
@@ -1786,7 +1885,7 @@ static int proc_disconnectsignal(struct dev_state *ps, void __user *arg)
return 0;
}
-static int proc_claiminterface(struct dev_state *ps, void __user *arg)
+static int proc_claiminterface(struct usb_dev_state *ps, void __user *arg)
{
unsigned int ifnum;
@@ -1795,7 +1894,7 @@ static int proc_claiminterface(struct dev_state *ps, void __user *arg)
return claimintf(ps, ifnum);
}
-static int proc_releaseinterface(struct dev_state *ps, void __user *arg)
+static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg)
{
unsigned int ifnum;
int ret;
@@ -1808,7 +1907,7 @@ static int proc_releaseinterface(struct dev_state *ps, void __user *arg)
return 0;
}
-static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
+static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
{
int size;
void *buf = NULL;
@@ -1884,7 +1983,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
return retval;
}
-static int proc_ioctl_default(struct dev_state *ps, void __user *arg)
+static int proc_ioctl_default(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_ioctl ctrl;
@@ -1894,7 +1993,7 @@ static int proc_ioctl_default(struct dev_state *ps, void __user *arg)
}
#ifdef CONFIG_COMPAT
-static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
+static int proc_ioctl_compat(struct usb_dev_state *ps, compat_uptr_t arg)
{
struct usbdevfs_ioctl32 __user *uioc;
struct usbdevfs_ioctl ctrl;
@@ -1912,7 +2011,7 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
}
#endif
-static int proc_claim_port(struct dev_state *ps, void __user *arg)
+static int proc_claim_port(struct usb_dev_state *ps, void __user *arg)
{
unsigned portnum;
int rc;
@@ -1926,7 +2025,7 @@ static int proc_claim_port(struct dev_state *ps, void __user *arg)
return rc;
}
-static int proc_release_port(struct dev_state *ps, void __user *arg)
+static int proc_release_port(struct usb_dev_state *ps, void __user *arg)
{
unsigned portnum;
@@ -1935,7 +2034,7 @@ static int proc_release_port(struct dev_state *ps, void __user *arg)
return usb_hub_release_port(ps->dev, portnum, ps);
}
-static int proc_get_capabilities(struct dev_state *ps, void __user *arg)
+static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
{
__u32 caps;
@@ -1951,7 +2050,7 @@ static int proc_get_capabilities(struct dev_state *ps, void __user *arg)
return 0;
}
-static int proc_disconnect_claim(struct dev_state *ps, void __user *arg)
+static int proc_disconnect_claim(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_disconnect_claim dc;
struct usb_interface *intf;
@@ -1983,6 +2082,45 @@ static int proc_disconnect_claim(struct dev_state *ps, void __user *arg)
return claimintf(ps, dc.interface);
}
+static int proc_alloc_streams(struct usb_dev_state *ps, void __user *arg)
+{
+ unsigned num_streams, num_eps;
+ struct usb_host_endpoint **eps;
+ struct usb_interface *intf;
+ int r;
+
+ r = parse_usbdevfs_streams(ps, arg, &num_streams, &num_eps,
+ &eps, &intf);
+ if (r)
+ return r;
+
+ destroy_async_on_interface(ps,
+ intf->altsetting[0].desc.bInterfaceNumber);
+
+ r = usb_alloc_streams(intf, eps, num_eps, num_streams, GFP_KERNEL);
+ kfree(eps);
+ return r;
+}
+
+static int proc_free_streams(struct usb_dev_state *ps, void __user *arg)
+{
+ unsigned num_eps;
+ struct usb_host_endpoint **eps;
+ struct usb_interface *intf;
+ int r;
+
+ r = parse_usbdevfs_streams(ps, arg, NULL, &num_eps, &eps, &intf);
+ if (r)
+ return r;
+
+ destroy_async_on_interface(ps,
+ intf->altsetting[0].desc.bInterfaceNumber);
+
+ r = usb_free_streams(intf, eps, num_eps, GFP_KERNEL);
+ kfree(eps);
+ return r;
+}
+
/*
* NOTE: All requests here that have interface numbers as parameters
* are assuming that somehow the configuration has been prevented from
@@ -1991,7 +2129,7 @@ static int proc_disconnect_claim(struct dev_state *ps, void __user *arg)
static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
void __user *p)
{
- struct dev_state *ps = file->private_data;
+ struct usb_dev_state *ps = file->private_data;
struct inode *inode = file_inode(file);
struct usb_device *dev = ps->dev;
int ret = -ENOTTY;
@@ -2159,6 +2297,12 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
case USBDEVFS_DISCONNECT_CLAIM:
ret = proc_disconnect_claim(ps, p);
break;
+ case USBDEVFS_ALLOC_STREAMS:
+ ret = proc_alloc_streams(ps, p);
+ break;
+ case USBDEVFS_FREE_STREAMS:
+ ret = proc_free_streams(ps, p);
+ break;
}
usb_unlock_device(dev);
if (ret >= 0)
@@ -2192,7 +2336,7 @@ static long usbdev_compat_ioctl(struct file *file, unsigned int cmd,
static unsigned int usbdev_poll(struct file *file,
struct poll_table_struct *wait)
{
- struct dev_state *ps = file->private_data;
+ struct usb_dev_state *ps = file->private_data;
unsigned int mask = 0;
poll_wait(file, &ps->wait, wait);
@@ -2218,11 +2362,11 @@ const struct file_operations usbdev_file_operations = {
static void usbdev_remove(struct usb_device *udev)
{
- struct dev_state *ps;
+ struct usb_dev_state *ps;
struct siginfo sinfo;
while (!list_empty(&udev->filelist)) {
- ps = list_entry(udev->filelist.next, struct dev_state, list);
+ ps = list_entry(udev->filelist.next, struct usb_dev_state, list);
destroy_all_async(ps);
wake_up_all(&ps->wait);
list_del_init(&ps->list);
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index ab90a0156828..888881e5f292 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -312,9 +312,9 @@ static int usb_probe_interface(struct device *dev)
return error;
}
- id = usb_match_id(intf, driver->id_table);
+ id = usb_match_dynamic_id(intf, driver);
if (!id)
- id = usb_match_dynamic_id(intf, driver);
+ id = usb_match_id(intf, driver->id_table);
if (!id)
return error;
@@ -400,8 +400,9 @@ static int usb_unbind_interface(struct device *dev)
{
struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_host_endpoint *ep, **eps = NULL;
struct usb_device *udev;
- int error, r, lpm_disable_error;
+ int i, j, error, r, lpm_disable_error;
intf->condition = USB_INTERFACE_UNBINDING;
@@ -425,6 +426,26 @@ static int usb_unbind_interface(struct device *dev)
driver->disconnect(intf);
usb_cancel_queued_reset(intf);
+ /* Free streams */
+ for (i = 0, j = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
+ ep = &intf->cur_altsetting->endpoint[i];
+ if (ep->streams == 0)
+ continue;
+ if (j == 0) {
+ eps = kmalloc(USB_MAXENDPOINTS * sizeof(void *),
+ GFP_KERNEL);
+ if (!eps) {
+ dev_warn(dev, "oom, leaking streams\n");
+ break;
+ }
+ }
+ eps[j++] = ep;
+ }
+ if (j) {
+ usb_free_streams(intf, eps, j, GFP_KERNEL);
+ kfree(eps);
+ }
+
/* Reset other interface state.
* We cannot do a Set-Interface if the device is suspended or
* if it is prepared for a system sleep (since installing a new
@@ -990,8 +1011,7 @@ EXPORT_SYMBOL_GPL(usb_deregister);
* it doesn't support pre_reset/post_reset/reset_resume or
* because it doesn't support suspend/resume.
*
- * The caller must hold @intf's device's lock, but not its pm_mutex
- * and not @intf->dev.sem.
+ * The caller must hold @intf's device's lock, but not @intf's lock.
*/
void usb_forced_unbind_intf(struct usb_interface *intf)
{
@@ -1004,16 +1024,37 @@ void usb_forced_unbind_intf(struct usb_interface *intf)
intf->needs_binding = 1;
}
+/*
+ * Unbind drivers for @udev's marked interfaces. These interfaces have
+ * the needs_binding flag set, for example by usb_resume_interface().
+ *
+ * The caller must hold @udev's device lock.
+ */
+static void unbind_marked_interfaces(struct usb_device *udev)
+{
+ struct usb_host_config *config;
+ int i;
+ struct usb_interface *intf;
+
+ config = udev->actconfig;
+ if (config) {
+ for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+ intf = config->interface[i];
+ if (intf->dev.driver && intf->needs_binding)
+ usb_forced_unbind_intf(intf);
+ }
+ }
+}
+
/* Delayed forced unbinding of a USB interface driver and scan
* for rebinding.
*
- * The caller must hold @intf's device's lock, but not its pm_mutex
- * and not @intf->dev.sem.
+ * The caller must hold @intf's device's lock, but not @intf's lock.
*
* Note: Rebinds will be skipped if a system sleep transition is in
* progress and the PM "complete" callback hasn't occurred yet.
*/
-void usb_rebind_intf(struct usb_interface *intf)
+static void usb_rebind_intf(struct usb_interface *intf)
{
int rc;
@@ -1030,68 +1071,66 @@ void usb_rebind_intf(struct usb_interface *intf)
}
}
-#ifdef CONFIG_PM
-
-/* Unbind drivers for @udev's interfaces that don't support suspend/resume
- * There is no check for reset_resume here because it can be determined
- * only during resume whether reset_resume is needed.
+/*
+ * Rebind drivers to @udev's marked interfaces. These interfaces have
+ * the needs_binding flag set.
*
* The caller must hold @udev's device lock.
*/
-static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
+static void rebind_marked_interfaces(struct usb_device *udev)
{
struct usb_host_config *config;
int i;
struct usb_interface *intf;
- struct usb_driver *drv;
config = udev->actconfig;
if (config) {
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intf = config->interface[i];
-
- if (intf->dev.driver) {
- drv = to_usb_driver(intf->dev.driver);
- if (!drv->suspend || !drv->resume)
- usb_forced_unbind_intf(intf);
- }
+ if (intf->needs_binding)
+ usb_rebind_intf(intf);
}
}
}
-/* Unbind drivers for @udev's interfaces that failed to support reset-resume.
- * These interfaces have the needs_binding flag set by usb_resume_interface().
+/*
+ * Unbind all of @udev's marked interfaces and then rebind all of them.
+ * This ordering is necessary because some drivers claim several interfaces
+ * when they are first probed.
*
* The caller must hold @udev's device lock.
*/
-static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev)
+void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev)
{
- struct usb_host_config *config;
- int i;
- struct usb_interface *intf;
-
- config = udev->actconfig;
- if (config) {
- for (i = 0; i < config->desc.bNumInterfaces; ++i) {
- intf = config->interface[i];
- if (intf->dev.driver && intf->needs_binding)
- usb_forced_unbind_intf(intf);
- }
- }
+ unbind_marked_interfaces(udev);
+ rebind_marked_interfaces(udev);
}
-static void do_rebind_interfaces(struct usb_device *udev)
+#ifdef CONFIG_PM
+
+/* Unbind drivers for @udev's interfaces that don't support suspend/resume
+ * There is no check for reset_resume here because it can be determined
+ * only during resume whether reset_resume is needed.
+ *
+ * The caller must hold @udev's device lock.
+ */
+static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
{
struct usb_host_config *config;
int i;
struct usb_interface *intf;
+ struct usb_driver *drv;
config = udev->actconfig;
if (config) {
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intf = config->interface[i];
- if (intf->needs_binding)
- usb_rebind_intf(intf);
+
+ if (intf->dev.driver) {
+ drv = to_usb_driver(intf->dev.driver);
+ if (!drv->suspend || !drv->resume)
+ usb_forced_unbind_intf(intf);
+ }
}
}
}
@@ -1420,7 +1459,7 @@ int usb_resume_complete(struct device *dev)
* whose needs_binding flag is set
*/
if (udev->state != USB_STATE_NOTATTACHED)
- do_rebind_interfaces(udev);
+ rebind_marked_interfaces(udev);
return 0;
}
@@ -1442,7 +1481,7 @@ int usb_resume(struct device *dev, pm_message_t msg)
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
- unbind_no_reset_resume_drivers_interfaces(udev);
+ unbind_marked_interfaces(udev);
}
/* Avoid PM error messages for devices disconnected while suspended
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index acbfeb0a0119..358ca8dd784f 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -155,6 +155,7 @@ int usb_choose_configuration(struct usb_device *udev)
}
return i;
}
+EXPORT_SYMBOL_GPL(usb_choose_configuration);
static int generic_probe(struct usb_device *udev)
{
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 2518c3250750..9c4e2922b04d 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2049,7 +2049,7 @@ int usb_alloc_streams(struct usb_interface *interface,
{
struct usb_hcd *hcd;
struct usb_device *dev;
- int i;
+ int i, ret;
dev = interface_to_usbdev(interface);
hcd = bus_to_hcd(dev->bus);
@@ -2058,13 +2058,24 @@ int usb_alloc_streams(struct usb_interface *interface,
if (dev->speed != USB_SPEED_SUPER)
return -EINVAL;
- /* Streams only apply to bulk endpoints. */
- for (i = 0; i < num_eps; i++)
+ for (i = 0; i < num_eps; i++) {
+ /* Streams only apply to bulk endpoints. */
if (!usb_endpoint_xfer_bulk(&eps[i]->desc))
return -EINVAL;
+ /* Re-alloc is not allowed */
+ if (eps[i]->streams)
+ return -EINVAL;
+ }
- return hcd->driver->alloc_streams(hcd, dev, eps, num_eps,
+ ret = hcd->driver->alloc_streams(hcd, dev, eps, num_eps,
num_streams, mem_flags);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < num_eps; i++)
+ eps[i]->streams = ret;
+
+ return ret;
}
EXPORT_SYMBOL_GPL(usb_alloc_streams);
@@ -2078,8 +2089,7 @@ EXPORT_SYMBOL_GPL(usb_alloc_streams);
* Reverts a group of bulk endpoints back to not using stream IDs.
* Can fail if we are given bad arguments, or HCD is broken.
*
- * Return: On success, the number of allocated streams. On failure, a negative
- * error code.
+ * Return: 0 on success. On failure, a negative error code.
*/
int usb_free_streams(struct usb_interface *interface,
struct usb_host_endpoint **eps, unsigned int num_eps,
@@ -2087,19 +2097,26 @@ int usb_free_streams(struct usb_interface *interface,
{
struct usb_hcd *hcd;
struct usb_device *dev;
- int i;
+ int i, ret;
dev = interface_to_usbdev(interface);
hcd = bus_to_hcd(dev->bus);
if (dev->speed != USB_SPEED_SUPER)
return -EINVAL;
- /* Streams only apply to bulk endpoints. */
+ /* Double-free is not allowed */
for (i = 0; i < num_eps; i++)
- if (!eps[i] || !usb_endpoint_xfer_bulk(&eps[i]->desc))
+ if (!eps[i] || !eps[i]->streams)
return -EINVAL;
- return hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags);
+ ret = hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < num_eps; i++)
+ eps[i]->streams = 0;
+
+ return ret;
}
EXPORT_SYMBOL_GPL(usb_free_streams);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 64ea21971be2..090469ebfcff 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -141,19 +141,27 @@ static int usb_device_supports_lpm(struct usb_device *udev)
return 0;
}
- /* All USB 3.0 must support LPM, but we need their max exit latency
- * information from the SuperSpeed Extended Capabilities BOS descriptor.
+ /*
+ * According to the USB 3.0 spec, all USB 3.0 devices must support LPM.
+ * However, there are some that don't, and they set the U1/U2 exit
+ * latencies to zero.
*/
if (!udev->bos->ss_cap) {
- dev_warn(&udev->dev, "No LPM exit latency info found. "
- "Power management will be impacted.\n");
+ dev_info(&udev->dev, "No LPM exit latency info found, disabling LPM.\n");
+ return 0;
+ }
+
+ if (udev->bos->ss_cap->bU1devExitLat == 0 &&
+ udev->bos->ss_cap->bU2DevExitLat == 0) {
+ if (udev->parent)
+ dev_info(&udev->dev, "LPM exit latency is zeroed, disabling LPM.\n");
+ else
+ dev_info(&udev->dev, "We don't know the algorithms for LPM for this host, disabling LPM.\n");
return 0;
}
- if (udev->parent->lpm_capable)
- return 1;
- dev_warn(&udev->dev, "Parent hub missing LPM exit latency info. "
- "Power management will be impacted.\n");
+ if (!udev->parent || udev->parent->lpm_capable)
+ return 1;
return 0;
}
@@ -499,7 +507,8 @@ static void led_work (struct work_struct *work)
changed++;
}
if (changed)
- schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);
+ queue_delayed_work(system_power_efficient_wq,
+ &hub->leds, LED_CYCLE_PERIOD);
}
/* use a short timeout for hub/port status fetches */
@@ -1040,8 +1049,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
*/
if (type == HUB_INIT) {
delay = hub_power_on(hub, false);
- PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func2);
- schedule_delayed_work(&hub->init_work,
+ INIT_DELAYED_WORK(&hub->init_work, hub_init_func2);
+ queue_delayed_work(system_power_efficient_wq,
+ &hub->init_work,
msecs_to_jiffies(delay));
/* Suppress autosuspend until init is done */
@@ -1194,8 +1204,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
/* Don't do a long sleep inside a workqueue routine */
if (type == HUB_INIT2) {
- PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func3);
- schedule_delayed_work(&hub->init_work,
+ INIT_DELAYED_WORK(&hub->init_work, hub_init_func3);
+ queue_delayed_work(system_power_efficient_wq,
+ &hub->init_work,
msecs_to_jiffies(delay));
return; /* Continues at init3: below */
} else {
@@ -1209,7 +1220,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
if (status < 0)
dev_err(hub->intfdev, "activate --> %d\n", status);
if (hub->has_indicators && blinkenlights)
- schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);
+ queue_delayed_work(system_power_efficient_wq,
+ &hub->leds, LED_CYCLE_PERIOD);
/* Scan all ports that need attention */
kick_khubd(hub);
@@ -1788,7 +1800,7 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
* to one of these "claimed" ports, the program will "own" the device.
*/
static int find_port_owner(struct usb_device *hdev, unsigned port1,
- struct dev_state ***ppowner)
+ struct usb_dev_state ***ppowner)
{
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
@@ -1806,10 +1818,10 @@ static int find_port_owner(struct usb_device *hdev, unsigned port1,
/* In the following three functions, the caller must hold hdev's lock */
int usb_hub_claim_port(struct usb_device *hdev, unsigned port1,
- struct dev_state *owner)
+ struct usb_dev_state *owner)
{
int rc;
- struct dev_state **powner;
+ struct usb_dev_state **powner;
rc = find_port_owner(hdev, port1, &powner);
if (rc)
@@ -1819,12 +1831,13 @@ int usb_hub_claim_port(struct usb_device *hdev, unsigned port1,
*powner = owner;
return rc;
}
+EXPORT_SYMBOL_GPL(usb_hub_claim_port);
int usb_hub_release_port(struct usb_device *hdev, unsigned port1,
- struct dev_state *owner)
+ struct usb_dev_state *owner)
{
int rc;
- struct dev_state **powner;
+ struct usb_dev_state **powner;
rc = find_port_owner(hdev, port1, &powner);
if (rc)
@@ -1834,8 +1847,9 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1,
*powner = NULL;
return rc;
}
+EXPORT_SYMBOL_GPL(usb_hub_release_port);
-void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner)
+void usb_hub_release_all_ports(struct usb_device *hdev, struct usb_dev_state *owner)
{
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
int n;
@@ -3093,9 +3107,19 @@ static int finish_port_resume(struct usb_device *udev)
* operation is carried out here, after the port has been
* resumed.
*/
- if (udev->reset_resume)
+ if (udev->reset_resume) {
+ /*
+ * If the device morphs or switches modes when it is reset,
+ * we don't want to perform a reset-resume. We'll fail the
+ * resume, which will cause a logical disconnect, and then
+ * the device will be rediscovered.
+ */
retry_reset_resume:
- status = usb_reset_and_verify_device(udev);
+ if (udev->quirks & USB_QUIRK_RESET)
+ status = -ENODEV;
+ else
+ status = usb_reset_and_verify_device(udev);
+ }
/* 10.5.4.5 says be sure devices in the tree are still there.
* For now let's assume the device didn't go crazy on resume,
@@ -3958,7 +3982,7 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev)
connect_type = usb_get_hub_port_connect_type(udev->parent,
udev->portnum);
- if ((udev->bos->ext_cap->bmAttributes & USB_BESL_SUPPORT) ||
+ if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) ||
connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
udev->usb2_hw_lpm_allowed = 1;
usb_set_usb2_hardware_lpm(udev, 1);
@@ -4107,8 +4131,12 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
did_new_scheme = true;
retval = hub_enable_device(udev);
- if (retval < 0)
+ if (retval < 0) {
+ dev_err(&udev->dev,
+ "hub failed to enable device, error %d\n",
+ retval);
goto fail;
+ }
#define GET_DESCRIPTOR_BUFSIZE 64
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
@@ -4311,7 +4339,8 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1)
/* hub LEDs are probably harder to miss than syslog */
if (hub->has_indicators) {
hub->indicator[port1-1] = INDICATOR_GREEN_BLINK;
- schedule_delayed_work (&hub->leds, 0);
+ queue_delayed_work(system_power_efficient_wq,
+ &hub->leds, 0);
}
}
kfree(qual);
@@ -4540,7 +4569,9 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
if (hub->has_indicators) {
hub->indicator[port1-1] =
INDICATOR_AMBER_BLINK;
- schedule_delayed_work (&hub->leds, 0);
+ queue_delayed_work(
+ system_power_efficient_wq,
+ &hub->leds, 0);
}
status = -ENOTCONN; /* Don't retry */
goto loop_disable;
@@ -4739,6 +4770,8 @@ static void hub_events(void)
/* deal with port status changes */
for (i = 1; i <= hdev->maxchild; i++) {
+ struct usb_device *udev = hub->ports[i - 1]->child;
+
if (test_bit(i, hub->busy_bits))
continue;
connect_change = test_bit(i, hub->change_bits);
@@ -4837,8 +4870,6 @@ static void hub_events(void)
*/
if (hub_port_warm_reset_required(hub, portstatus)) {
int status;
- struct usb_device *udev =
- hub->ports[i - 1]->child;
dev_dbg(hub_dev, "warm reset port %d\n", i);
if (!udev ||
@@ -4855,6 +4886,24 @@ static void hub_events(void)
usb_unlock_device(udev);
connect_change = 0;
}
+ /*
+ * On disconnect USB3 protocol ports transit from U0 to
+ * SS.Inactive to Rx.Detect. If this happens a warm-
+ * reset is not needed, but a (re)connect may happen
+ * before khubd runs and sees the disconnect, and the
+ * device may be an unknown state.
+ *
+ * If the port went through SS.Inactive without khubd
+ * seeing it the C_LINK_STATE change flag will be set,
+ * and we reset the dev to put it in a known state.
+ */
+ } else if (udev && hub_is_superspeed(hub->hdev) &&
+ (portchange & USB_PORT_STAT_C_LINK_STATE) &&
+ (portstatus & USB_PORT_STAT_CONNECTION)) {
+ usb_lock_device(udev);
+ usb_reset_device(udev);
+ usb_unlock_device(udev);
+ connect_change = 0;
}
if (connect_change)
@@ -5112,7 +5161,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
struct usb_device_descriptor descriptor = udev->descriptor;
struct usb_host_bos *bos;
- int i, ret = 0;
+ int i, j, ret = 0;
int port1 = udev->portnum;
if (udev->state == USB_STATE_NOTATTACHED ||
@@ -5238,6 +5287,9 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
ret);
goto re_enumerate;
}
+ /* Resetting also frees any allocated streams */
+ for (j = 0; j < intf->cur_altsetting->desc.bNumEndpoints; j++)
+ intf->cur_altsetting->endpoint[j].streams = 0;
}
done:
@@ -5340,10 +5392,11 @@ int usb_reset_device(struct usb_device *udev)
else if (cintf->condition ==
USB_INTERFACE_BOUND)
rebind = 1;
+ if (rebind)
+ cintf->needs_binding = 1;
}
- if (ret == 0 && rebind)
- usb_rebind_intf(cintf);
}
+ usb_unbind_and_rebind_marked_interfaces(udev);
}
usb_autosuspend_device(udev);
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index df629a310e44..33bcb2c6f90a 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -89,7 +89,7 @@ struct usb_hub {
struct usb_port {
struct usb_device *child;
struct device dev;
- struct dev_state *port_owner;
+ struct usb_dev_state *port_owner;
enum usb_port_connect_type connect_type;
u8 portnum;
unsigned power_is_on:1;
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 5239e5163074..0c8a7fc4dad8 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1293,8 +1293,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
struct usb_interface *iface;
struct usb_host_interface *alt;
struct usb_hcd *hcd = bus_to_hcd(dev->bus);
- int ret;
- int manual = 0;
+ int i, ret, manual = 0;
unsigned int epaddr;
unsigned int pipe;
@@ -1329,6 +1328,10 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
mutex_unlock(hcd->bandwidth_mutex);
return -ENOMEM;
}
+ /* Changing alt-setting also frees any allocated streams */
+ for (i = 0; i < iface->cur_altsetting->desc.bNumEndpoints; i++)
+ iface->cur_altsetting->endpoint[i].streams = 0;
+
ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt);
if (ret < 0) {
dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n",
@@ -1920,6 +1923,7 @@ free_interfaces:
usb_autosuspend_device(dev);
return 0;
}
+EXPORT_SYMBOL_GPL(usb_set_configuration);
static LIST_HEAD(set_config_list);
static DEFINE_SPINLOCK(set_config_lock);
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 8f37063c0a49..739ee8e8bdfd 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -47,6 +47,10 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Microsoft LifeCam-VX700 v2.0 */
{ USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Logitech HD Pro Webcams C920 and C930e */
+ { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT },
+ { USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT },
+
/* Logitech Quickcam Fusion */
{ USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 823857767a16..75bf649da82d 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -2,7 +2,7 @@
#include <linux/acpi.h>
struct usb_hub_descriptor;
-struct dev_state;
+struct usb_dev_state;
/* Functions local to drivers/usb/core/ */
@@ -55,14 +55,10 @@ extern int usb_match_one_id_intf(struct usb_device *dev,
extern int usb_match_device(struct usb_device *dev,
const struct usb_device_id *id);
extern void usb_forced_unbind_intf(struct usb_interface *intf);
-extern void usb_rebind_intf(struct usb_interface *intf);
+extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev);
-extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port,
- struct dev_state *owner);
-extern int usb_hub_release_port(struct usb_device *hdev, unsigned port,
- struct dev_state *owner);
extern void usb_hub_release_all_ports(struct usb_device *hdev,
- struct dev_state *owner);
+ struct usb_dev_state *owner);
extern bool usb_device_is_owned(struct usb_device *udev);
extern int usb_hub_init(void);
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 8205799e6db3..c93918b70d03 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -72,6 +72,26 @@ static const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg)
}
/**
+ * dwc2_handle_usb_port_intr - handles OTG PRTINT interrupts.
+ * When the PRTINT interrupt fires, there are certain status bits in the Host
+ * Port that needs to get cleared.
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg)
+{
+ u32 hprt0 = readl(hsotg->regs + HPRT0);
+
+ if (hprt0 & HPRT0_ENACHG) {
+ hprt0 &= ~HPRT0_ENA;
+ writel(hprt0, hsotg->regs + HPRT0);
+ }
+
+ /* Clear interrupt */
+ writel(GINTSTS_PRTINT, hsotg->regs + GINTSTS);
+}
+
+/**
* dwc2_handle_mode_mismatch_intr() - Logs a mode mismatch warning message
*
* @hsotg: Programming view of DWC_otg controller
@@ -479,9 +499,8 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
if (dwc2_is_device_mode(hsotg)) {
dev_dbg(hsotg->dev,
" --Port interrupt received in Device mode--\n");
- gintsts = GINTSTS_PRTINT;
- writel(gintsts, hsotg->regs + GINTSTS);
- retval = 1;
+ dwc2_handle_usb_port_intr(hsotg);
+ retval = IRQ_HANDLED;
}
}
diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
index 012f17ec1a37..47b9eb5389b4 100644
--- a/drivers/usb/dwc2/hcd_intr.c
+++ b/drivers/usb/dwc2/hcd_intr.c
@@ -975,8 +975,8 @@ static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg,
struct dwc2_qtd *qtd)
{
struct dwc2_hcd_urb *urb = qtd->urb;
- int pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
enum dwc2_halt_status halt_status = DWC2_HC_XFER_COMPLETE;
+ int pipe_type;
int urb_xfer_done;
if (dbg_hc(chan))
@@ -984,6 +984,11 @@ static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg,
"--Host Channel %d Interrupt: Transfer Complete--\n",
chnum);
+ if (!urb)
+ goto handle_xfercomp_done;
+
+ pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
+
if (hsotg->core_params->dma_desc_enable > 0) {
dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, halt_status);
if (pipe_type == USB_ENDPOINT_XFER_ISOC)
@@ -1005,9 +1010,6 @@ static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg,
}
}
- if (!urb)
- goto handle_xfercomp_done;
-
/* Update the QTD and URB states */
switch (pipe_type) {
case USB_ENDPOINT_XFER_CONTROL:
@@ -1105,7 +1107,7 @@ static void dwc2_hc_stall_intr(struct dwc2_hsotg *hsotg,
struct dwc2_qtd *qtd)
{
struct dwc2_hcd_urb *urb = qtd->urb;
- int pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
+ int pipe_type;
dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: STALL Received--\n",
chnum);
@@ -1119,6 +1121,8 @@ static void dwc2_hc_stall_intr(struct dwc2_hsotg *hsotg,
if (!urb)
goto handle_stall_halt;
+ pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
+
if (pipe_type == USB_ENDPOINT_XFER_CONTROL)
dwc2_host_complete(hsotg, qtd, -EPIPE);
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index a49217ae3533..d001417e8e37 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -61,9 +61,10 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
* dwc3_core_soft_reset - Issues core soft reset and PHY reset
* @dwc: pointer to our context structure
*/
-static void dwc3_core_soft_reset(struct dwc3 *dwc)
+static int dwc3_core_soft_reset(struct dwc3 *dwc)
{
u32 reg;
+ int ret;
/* Before Resetting PHY, put Core in Reset */
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
@@ -82,6 +83,15 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc)
usb_phy_init(dwc->usb2_phy);
usb_phy_init(dwc->usb3_phy);
+ ret = phy_init(dwc->usb2_generic_phy);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_init(dwc->usb3_generic_phy);
+ if (ret < 0) {
+ phy_exit(dwc->usb2_generic_phy);
+ return ret;
+ }
mdelay(100);
/* Clear USB3 PHY reset */
@@ -100,6 +110,8 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~DWC3_GCTL_CORESOFTRESET;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+ return 0;
}
/**
@@ -242,6 +254,90 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
}
}
+static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
+{
+ if (!dwc->has_hibernation)
+ return 0;
+
+ if (!dwc->nr_scratch)
+ return 0;
+
+ dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
+ DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
+ if (!dwc->scratchbuf)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
+{
+ dma_addr_t scratch_addr;
+ u32 param;
+ int ret;
+
+ if (!dwc->has_hibernation)
+ return 0;
+
+ if (!dwc->nr_scratch)
+ return 0;
+
+ /* should never fall here */
+ if (!WARN_ON(dwc->scratchbuf))
+ return 0;
+
+ scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf,
+ dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
+ DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(dwc->dev, scratch_addr)) {
+ dev_err(dwc->dev, "failed to map scratch buffer\n");
+ ret = -EFAULT;
+ goto err0;
+ }
+
+ dwc->scratch_addr = scratch_addr;
+
+ param = lower_32_bits(scratch_addr);
+
+ ret = dwc3_send_gadget_generic_command(dwc,
+ DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
+ if (ret < 0)
+ goto err1;
+
+ param = upper_32_bits(scratch_addr);
+
+ ret = dwc3_send_gadget_generic_command(dwc,
+ DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
+ if (ret < 0)
+ goto err1;
+
+ return 0;
+
+err1:
+ dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
+ DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
+
+err0:
+ return ret;
+}
+
+static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
+{
+ if (!dwc->has_hibernation)
+ return;
+
+ if (!dwc->nr_scratch)
+ return;
+
+ /* should never fall here */
+ if (!WARN_ON(dwc->scratchbuf))
+ return;
+
+ dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
+ DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
+ kfree(dwc->scratchbuf);
+}
+
static void dwc3_core_num_eps(struct dwc3 *dwc)
{
struct dwc3_hwparams *parms = &dwc->hwparams;
@@ -277,6 +373,7 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
static int dwc3_core_init(struct dwc3 *dwc)
{
unsigned long timeout;
+ u32 hwparams4 = dwc->hwparams.hwparams4;
u32 reg;
int ret;
@@ -306,7 +403,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
cpu_relax();
} while (true);
- dwc3_core_soft_reset(dwc);
+ ret = dwc3_core_soft_reset(dwc);
+ if (ret)
+ goto err0;
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
@@ -314,7 +413,29 @@ static int dwc3_core_init(struct dwc3 *dwc)
switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
- reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+ /**
+ * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
+ * issue which would cause xHCI compliance tests to fail.
+ *
+ * Because of that we cannot enable clock gating on such
+ * configurations.
+ *
+ * Refers to:
+ *
+ * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
+ * SOF/ITP Mode Used
+ */
+ if ((dwc->dr_mode == USB_DR_MODE_HOST ||
+ dwc->dr_mode == USB_DR_MODE_OTG) &&
+ (dwc->revision >= DWC3_REVISION_210A &&
+ dwc->revision <= DWC3_REVISION_250A))
+ reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
+ else
+ reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+ break;
+ case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
+ /* enable hibernation here */
+ dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
break;
default:
dev_dbg(dwc->dev, "No power optimization available\n");
@@ -333,16 +454,36 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ ret = dwc3_alloc_scratch_buffers(dwc);
+ if (ret)
+ goto err1;
+
+ ret = dwc3_setup_scratch_buffers(dwc);
+ if (ret)
+ goto err2;
+
return 0;
+err2:
+ dwc3_free_scratch_buffers(dwc);
+
+err1:
+ usb_phy_shutdown(dwc->usb2_phy);
+ usb_phy_shutdown(dwc->usb3_phy);
+ phy_exit(dwc->usb2_generic_phy);
+ phy_exit(dwc->usb3_generic_phy);
+
err0:
return ret;
}
static void dwc3_core_exit(struct dwc3 *dwc)
{
+ dwc3_free_scratch_buffers(dwc);
usb_phy_shutdown(dwc->usb2_phy);
usb_phy_shutdown(dwc->usb3_phy);
+ phy_exit(dwc->usb2_generic_phy);
+ phy_exit(dwc->usb3_generic_phy);
}
#define DWC3_ALIGN_MASK (16 - 1)
@@ -411,32 +552,52 @@ static int dwc3_probe(struct platform_device *pdev)
if (IS_ERR(dwc->usb2_phy)) {
ret = PTR_ERR(dwc->usb2_phy);
-
- /*
- * if -ENXIO is returned, it means PHY layer wasn't
- * enabled, so it makes no sense to return -EPROBE_DEFER
- * in that case, since no PHY driver will ever probe.
- */
- if (ret == -ENXIO)
+ if (ret == -ENXIO || ret == -ENODEV) {
+ dwc->usb2_phy = NULL;
+ } else if (ret == -EPROBE_DEFER) {
return ret;
-
- dev_err(dev, "no usb2 phy configured\n");
- return -EPROBE_DEFER;
+ } else {
+ dev_err(dev, "no usb2 phy configured\n");
+ return ret;
+ }
}
if (IS_ERR(dwc->usb3_phy)) {
ret = PTR_ERR(dwc->usb3_phy);
+ if (ret == -ENXIO || ret == -ENODEV) {
+ dwc->usb3_phy = NULL;
+ } else if (ret == -EPROBE_DEFER) {
+ return ret;
+ } else {
+ dev_err(dev, "no usb3 phy configured\n");
+ return ret;
+ }
+ }
- /*
- * if -ENXIO is returned, it means PHY layer wasn't
- * enabled, so it makes no sense to return -EPROBE_DEFER
- * in that case, since no PHY driver will ever probe.
- */
- if (ret == -ENXIO)
+ dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
+ if (IS_ERR(dwc->usb2_generic_phy)) {
+ ret = PTR_ERR(dwc->usb2_generic_phy);
+ if (ret == -ENOSYS || ret == -ENODEV) {
+ dwc->usb2_generic_phy = NULL;
+ } else if (ret == -EPROBE_DEFER) {
+ return ret;
+ } else {
+ dev_err(dev, "no usb2 phy configured\n");
return ret;
+ }
+ }
- dev_err(dev, "no usb3 phy configured\n");
- return -EPROBE_DEFER;
+ dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
+ if (IS_ERR(dwc->usb3_generic_phy)) {
+ ret = PTR_ERR(dwc->usb3_generic_phy);
+ if (ret == -ENOSYS || ret == -ENODEV) {
+ dwc->usb3_generic_phy = NULL;
+ } else if (ret == -EPROBE_DEFER) {
+ return ret;
+ } else {
+ dev_err(dev, "no usb3 phy configured\n");
+ return ret;
+ }
}
dwc->xhci_resources[0].start = res->start;
@@ -479,6 +640,14 @@ static int dwc3_probe(struct platform_device *pdev)
goto err0;
}
+ if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
+ dwc->dr_mode = USB_DR_MODE_HOST;
+ else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+ dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
+
+ if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
+ dwc->dr_mode = USB_DR_MODE_OTG;
+
ret = dwc3_core_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize core\n");
@@ -487,21 +656,20 @@ static int dwc3_probe(struct platform_device *pdev)
usb_phy_set_suspend(dwc->usb2_phy, 0);
usb_phy_set_suspend(dwc->usb3_phy, 0);
+ ret = phy_power_on(dwc->usb2_generic_phy);
+ if (ret < 0)
+ goto err1;
+
+ ret = phy_power_on(dwc->usb3_generic_phy);
+ if (ret < 0)
+ goto err_usb2phy_power;
ret = dwc3_event_buffers_setup(dwc);
if (ret) {
dev_err(dwc->dev, "failed to setup event buffers\n");
- goto err1;
+ goto err_usb3phy_power;
}
- if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
- dwc->dr_mode = USB_DR_MODE_HOST;
- else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
- dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
-
- if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
- dwc->dr_mode = USB_DR_MODE_OTG;
-
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
@@ -568,6 +736,12 @@ err3:
err2:
dwc3_event_buffers_cleanup(dwc);
+err_usb3phy_power:
+ phy_power_off(dwc->usb3_generic_phy);
+
+err_usb2phy_power:
+ phy_power_off(dwc->usb2_generic_phy);
+
err1:
usb_phy_set_suspend(dwc->usb2_phy, 1);
usb_phy_set_suspend(dwc->usb3_phy, 1);
@@ -585,6 +759,8 @@ static int dwc3_remove(struct platform_device *pdev)
usb_phy_set_suspend(dwc->usb2_phy, 1);
usb_phy_set_suspend(dwc->usb3_phy, 1);
+ phy_power_off(dwc->usb2_generic_phy);
+ phy_power_off(dwc->usb3_generic_phy);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -682,6 +858,8 @@ static int dwc3_suspend(struct device *dev)
usb_phy_shutdown(dwc->usb3_phy);
usb_phy_shutdown(dwc->usb2_phy);
+ phy_exit(dwc->usb2_generic_phy);
+ phy_exit(dwc->usb3_generic_phy);
return 0;
}
@@ -690,9 +868,17 @@ static int dwc3_resume(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
unsigned long flags;
+ int ret;
usb_phy_init(dwc->usb3_phy);
usb_phy_init(dwc->usb2_phy);
+ ret = phy_init(dwc->usb2_generic_phy);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_init(dwc->usb3_generic_phy);
+ if (ret < 0)
+ goto err_usb2phy_init;
spin_lock_irqsave(&dwc->lock, flags);
@@ -716,6 +902,11 @@ static int dwc3_resume(struct device *dev)
pm_runtime_enable(dev);
return 0;
+
+err_usb2phy_init:
+ phy_exit(dwc->usb2_generic_phy);
+
+ return ret;
}
static const struct dev_pm_ops dwc3_dev_pm_ops = {
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index f8af8d44af85..57332e3768e4 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -31,11 +31,14 @@
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
+#include <linux/phy/phy.h>
+
/* Global constants */
#define DWC3_EP0_BOUNCE_SIZE 512
#define DWC3_ENDPOINTS_NUM 32
#define DWC3_XHCI_RESOURCES_NUM 2
+#define DWC3_SCRATCHBUF_SIZE 4096 /* each buffer is assumed to be 4KiB */
#define DWC3_EVENT_SIZE 4 /* bytes */
#define DWC3_EVENT_MAX_NUM 64 /* 2 events/endpoint */
#define DWC3_EVENT_BUFFERS_SIZE (DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM)
@@ -157,6 +160,7 @@
#define DWC3_GCTL_PRTCAP_OTG 3
#define DWC3_GCTL_CORESOFTRESET (1 << 11)
+#define DWC3_GCTL_SOFITPSYNC (1 << 10)
#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4)
#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
@@ -318,7 +322,7 @@
/* Device Endpoint Command Register */
#define DWC3_DEPCMD_PARAM_SHIFT 16
#define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT)
-#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
+#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
#define DWC3_DEPCMD_STATUS(x) (((x) >> 15) & 1)
#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
#define DWC3_DEPCMD_CMDACT (1 << 10)
@@ -393,6 +397,7 @@ struct dwc3_event_buffer {
* @busy_slot: first slot which is owned by HW
* @desc: usb_endpoint_descriptor pointer
* @dwc: pointer to DWC controller
+ * @saved_state: ep state saved during hibernation
* @flags: endpoint flags (wedged, stalled, ...)
* @current_trb: index of current used trb
* @number: endpoint number (1 - 15)
@@ -415,6 +420,7 @@ struct dwc3_ep {
const struct usb_ss_ep_comp_descriptor *comp_desc;
struct dwc3 *dwc;
+ u32 saved_state;
unsigned flags;
#define DWC3_EP_ENABLED (1 << 0)
#define DWC3_EP_STALL (1 << 1)
@@ -598,6 +604,7 @@ struct dwc3_scratchpad_array {
* @ep0_trb: dma address of ep0_trb
* @ep0_usb_req: dummy req used while handling STD USB requests
* @ep0_bounce_addr: dma address of ep0_bounce
+ * @scratch_addr: dma address of scratchbuf
* @lock: for synchronizing
* @dev: pointer to our struct device
* @xhci: pointer to our xHCI child
@@ -606,6 +613,7 @@ struct dwc3_scratchpad_array {
* @gadget_driver: pointer to the gadget driver
* @regs: base address for our registers
* @regs_size: address space size
+ * @nr_scratch: number of scratch buffers
* @num_event_buffers: calculated number of event buffers
* @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes)
@@ -613,16 +621,10 @@ struct dwc3_scratchpad_array {
* @dr_mode: requested mode of operation
* @usb2_phy: pointer to USB2 PHY
* @usb3_phy: pointer to USB3 PHY
+ * @usb2_generic_phy: pointer to USB2 PHY
+ * @usb3_generic_phy: pointer to USB3 PHY
* @dcfg: saved contents of DCFG register
* @gctl: saved contents of GCTL register
- * @is_selfpowered: true when we are selfpowered
- * @three_stage_setup: set if we perform a three phase setup
- * @ep0_bounced: true when we used bounce buffer
- * @ep0_expect_in: true when we expect a DATA IN transfer
- * @start_config_issued: true when StartConfig command has been issued
- * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
- * @needs_fifo_resize: not all users might want fifo resizing, flag it
- * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
* @isoch_delay: wValue from Set Isochronous Delay request;
* @u2sel: parameter from Set SEL request.
* @u2pel: parameter from Set SEL request.
@@ -637,15 +639,31 @@ struct dwc3_scratchpad_array {
* @mem: points to start of memory which is used for this struct.
* @hwparams: copy of hwparams registers
* @root: debugfs root folder pointer
+ * @regset: debugfs pointer to regdump file
+ * @test_mode: true when we're entering a USB test mode
+ * @test_mode_nr: test feature selector
+ * @delayed_status: true when gadget driver asks for delayed status
+ * @ep0_bounced: true when we used bounce buffer
+ * @ep0_expect_in: true when we expect a DATA IN transfer
+ * @has_hibernation: true when dwc3 was configured with Hibernation
+ * @is_selfpowered: true when we are selfpowered
+ * @needs_fifo_resize: not all users might want fifo resizing, flag it
+ * @pullups_connected: true when Run/Stop bit is set
+ * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
+ * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
+ * @start_config_issued: true when StartConfig command has been issued
+ * @three_stage_setup: set if we perform a three phase setup
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
struct dwc3_trb *ep0_trb;
void *ep0_bounce;
+ void *scratchbuf;
u8 *setup_buf;
dma_addr_t ctrl_req_addr;
dma_addr_t ep0_trb_addr;
dma_addr_t ep0_bounce_addr;
+ dma_addr_t scratch_addr;
struct dwc3_request ep0_usb_req;
/* device lock */
@@ -665,6 +683,9 @@ struct dwc3 {
struct usb_phy *usb2_phy;
struct usb_phy *usb3_phy;
+ struct phy *usb2_generic_phy;
+ struct phy *usb3_generic_phy;
+
void __iomem *regs;
size_t regs_size;
@@ -674,6 +695,7 @@ struct dwc3 {
u32 dcfg;
u32 gctl;
+ u32 nr_scratch;
u32 num_event_buffers;
u32 u1u2;
u32 maximum_speed;
@@ -695,17 +717,9 @@ struct dwc3 {
#define DWC3_REVISION_230A 0x5533230a
#define DWC3_REVISION_240A 0x5533240a
#define DWC3_REVISION_250A 0x5533250a
-
- unsigned is_selfpowered:1;
- unsigned three_stage_setup:1;
- unsigned ep0_bounced:1;
- unsigned ep0_expect_in:1;
- unsigned start_config_issued:1;
- unsigned setup_packet_pending:1;
- unsigned delayed_status:1;
- unsigned needs_fifo_resize:1;
- unsigned resize_fifos:1;
- unsigned pullups_connected:1;
+#define DWC3_REVISION_260A 0x5533260a
+#define DWC3_REVISION_270A 0x5533270a
+#define DWC3_REVISION_280A 0x5533280a
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
@@ -730,6 +744,18 @@ struct dwc3 {
u8 test_mode;
u8 test_mode_nr;
+
+ unsigned delayed_status:1;
+ unsigned ep0_bounced:1;
+ unsigned ep0_expect_in:1;
+ unsigned has_hibernation:1;
+ unsigned is_selfpowered:1;
+ unsigned needs_fifo_resize:1;
+ unsigned pullups_connected:1;
+ unsigned resize_fifos:1;
+ unsigned setup_packet_pending:1;
+ unsigned start_config_issued:1;
+ unsigned three_stage_setup:1;
};
/* -------------------------------------------------------------------------- */
@@ -815,15 +841,15 @@ struct dwc3_event_depevt {
* 12 - VndrDevTstRcved
* @reserved15_12: Reserved, not used
* @event_info: Information about this event
- * @reserved31_24: Reserved, not used
+ * @reserved31_25: Reserved, not used
*/
struct dwc3_event_devt {
u32 one_bit:1;
u32 device_event:7;
u32 type:4;
u32 reserved15_12:4;
- u32 event_info:8;
- u32 reserved31_24:8;
+ u32 event_info:9;
+ u32 reserved31_25:7;
} __packed;
/**
@@ -856,6 +882,19 @@ union dwc3_event {
struct dwc3_event_gevt gevt;
};
+/**
+ * struct dwc3_gadget_ep_cmd_params - representation of endpoint command
+ * parameters
+ * @param2: third parameter
+ * @param1: second parameter
+ * @param0: first parameter
+ */
+struct dwc3_gadget_ep_cmd_params {
+ u32 param2;
+ u32 param1;
+ u32 param0;
+};
+
/*
* DWC3 Features to be used as Driver Data
*/
@@ -881,11 +920,31 @@ static inline void dwc3_host_exit(struct dwc3 *dwc)
#if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
int dwc3_gadget_init(struct dwc3 *dwc);
void dwc3_gadget_exit(struct dwc3 *dwc);
+int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
+int dwc3_gadget_get_link_state(struct dwc3 *dwc);
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
+int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+ unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param);
#else
static inline int dwc3_gadget_init(struct dwc3 *dwc)
{ return 0; }
static inline void dwc3_gadget_exit(struct dwc3 *dwc)
{ }
+static inline int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
+{ return 0; }
+static inline int dwc3_gadget_get_link_state(struct dwc3 *dwc)
+{ return 0; }
+static inline int dwc3_gadget_set_link_state(struct dwc3 *dwc,
+ enum dwc3_link_state state)
+{ return 0; }
+
+static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+ unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+{ return 0; }
+static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
+ int cmd, u32 param)
+{ return 0; }
#endif
/* power management interface */
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index b269dbd47fc4..1160ff41bed4 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -29,7 +29,6 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/extcon.h>
-#include <linux/extcon/of_extcon.h>
#include <linux/regulator/consumer.h>
#include <linux/usb/otg.h>
@@ -424,11 +423,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "missing memory base resource\n");
- return -EINVAL;
- }
-
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
@@ -522,7 +516,7 @@ static int dwc3_omap_probe(struct platform_device *pdev)
dwc3_omap_enable_irqs(omap);
if (of_property_read_bool(node, "extcon")) {
- edev = of_extcon_get_extcon_dev(dev, 0);
+ edev = extcon_get_edev_by_phandle(dev, 0);
if (IS_ERR(edev)) {
dev_vdbg(dev, "couldn't get extcon device\n");
ret = -EPROBE_DEFER;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2da0a5a2803a..a740eac74d56 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -68,6 +68,22 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
}
/**
+ * dwc3_gadget_get_link_state - Gets current state of USB Link
+ * @dwc: pointer to our context structure
+ *
+ * Caller should take care of locking. This function will
+ * return the link state on success (>= 0) or -ETIMEDOUT.
+ */
+int dwc3_gadget_get_link_state(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+ return DWC3_DSTS_USBLNKST(reg);
+}
+
+/**
* dwc3_gadget_set_link_state - Sets USB Link to a particular State
* @dwc: pointer to our context structure
* @state: the state to put link into
@@ -417,7 +433,7 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
const struct usb_endpoint_descriptor *desc,
const struct usb_ss_ep_comp_descriptor *comp_desc,
- bool ignore)
+ bool ignore, bool restore)
{
struct dwc3_gadget_ep_cmd_params params;
@@ -436,6 +452,11 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
if (ignore)
params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM;
+ if (restore) {
+ params.param0 |= DWC3_DEPCFG_ACTION_RESTORE;
+ params.param2 |= dep->saved_state;
+ }
+
params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
| DWC3_DEPCFG_XFER_NOT_READY_EN;
@@ -494,7 +515,7 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
const struct usb_endpoint_descriptor *desc,
const struct usb_ss_ep_comp_descriptor *comp_desc,
- bool ignore)
+ bool ignore, bool restore)
{
struct dwc3 *dwc = dep->dwc;
u32 reg;
@@ -508,7 +529,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
return ret;
}
- ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore);
+ ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore,
+ restore);
if (ret)
return ret;
@@ -548,13 +570,13 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
return 0;
}
-static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum);
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);
static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
{
struct dwc3_request *req;
if (!list_empty(&dep->req_queued)) {
- dwc3_stop_active_transfer(dwc, dep->number);
+ dwc3_stop_active_transfer(dwc, dep->number, true);
/* - giveback all requests to gadget driver */
while (!list_empty(&dep->req_queued)) {
@@ -659,7 +681,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
}
spin_lock_irqsave(&dwc->lock, flags);
- ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false);
+ ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
@@ -771,9 +793,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
else
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS;
-
- if (!req->request.no_interrupt && !chain)
- trb->ctrl |= DWC3_TRB_CTRL_IOC;
break;
case USB_ENDPOINT_XFER_BULK:
@@ -788,6 +807,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
BUG();
}
+ if (!req->request.no_interrupt && !chain)
+ trb->ctrl |= DWC3_TRB_CTRL_IOC;
+
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
trb->ctrl |= DWC3_TRB_CTRL_CSP;
@@ -1077,7 +1099,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
*/
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
if (list_empty(&dep->req_queued)) {
- dwc3_stop_active_transfer(dwc, dep->number);
+ dwc3_stop_active_transfer(dwc, dep->number, true);
dep->flags = DWC3_EP_ENABLED;
}
return 0;
@@ -1107,6 +1129,23 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
return ret;
}
+ /*
+ * 4. Stream Capable Bulk Endpoints. We need to start the transfer
+ * right away, otherwise host will not know we have streams to be
+ * handled.
+ */
+ if (dep->stream_capable) {
+ int ret;
+
+ ret = __dwc3_gadget_kick_transfer(dep, 0, true);
+ if (ret && ret != -EBUSY) {
+ struct dwc3 *dwc = dep->dwc;
+
+ dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+ dep->name);
+ }
+ }
+
return 0;
}
@@ -1163,7 +1202,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
}
if (r == req) {
/* wait until it is processed */
- dwc3_stop_active_transfer(dwc, dep->number);
+ dwc3_stop_active_transfer(dwc, dep->number, true);
goto out1;
}
dev_err(dwc->dev, "request %p was not queued to %s\n",
@@ -1194,8 +1233,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
DWC3_DEPCMD_SETSTALL, &params);
if (ret)
- dev_err(dwc->dev, "failed to %s STALL on %s\n",
- value ? "set" : "clear",
+ dev_err(dwc->dev, "failed to set STALL on %s\n",
dep->name);
else
dep->flags |= DWC3_EP_STALL;
@@ -1203,8 +1241,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
DWC3_DEPCMD_CLEARSTALL, &params);
if (ret)
- dev_err(dwc->dev, "failed to %s STALL on %s\n",
- value ? "set" : "clear",
+ dev_err(dwc->dev, "failed to clear STALL on %s\n",
dep->name);
else
dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);
@@ -1387,7 +1424,7 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
return 0;
}
-static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
+static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
{
u32 reg;
u32 timeout = 500;
@@ -1402,9 +1439,17 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
if (dwc->revision >= DWC3_REVISION_194A)
reg &= ~DWC3_DCTL_KEEP_CONNECT;
reg |= DWC3_DCTL_RUN_STOP;
+
+ if (dwc->has_hibernation)
+ reg |= DWC3_DCTL_KEEP_CONNECT;
+
dwc->pullups_connected = true;
} else {
reg &= ~DWC3_DCTL_RUN_STOP;
+
+ if (dwc->has_hibernation && !suspend)
+ reg &= ~DWC3_DCTL_KEEP_CONNECT;
+
dwc->pullups_connected = false;
}
@@ -1442,7 +1487,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
is_on = !!is_on;
spin_lock_irqsave(&dwc->lock, flags);
- ret = dwc3_gadget_run_stop(dwc, is_on);
+ ret = dwc3_gadget_run_stop(dwc, is_on, false);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
@@ -1549,14 +1594,16 @@ static int dwc3_gadget_start(struct usb_gadget *g,
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
dep = dwc->eps[0];
- ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
+ false);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
goto err2;
}
dep = dwc->eps[1];
- ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
+ false);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
goto err3;
@@ -1849,15 +1896,12 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
*/
dep->flags = DWC3_EP_PENDING_REQUEST;
} else {
- dwc3_stop_active_transfer(dwc, dep->number);
+ dwc3_stop_active_transfer(dwc, dep->number, true);
dep->flags = DWC3_EP_ENABLED;
}
return 1;
}
- if ((event->status & DEPEVT_STATUS_IOC) &&
- (trb->ctrl & DWC3_TRB_CTRL_IOC))
- return 0;
return 1;
}
@@ -1999,7 +2043,25 @@ static void dwc3_disconnect_gadget(struct dwc3 *dwc)
}
}
-static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
+static void dwc3_suspend_gadget(struct dwc3 *dwc)
+{
+ if (dwc->gadget_driver && dwc->gadget_driver->suspend) {
+ spin_unlock(&dwc->lock);
+ dwc->gadget_driver->suspend(&dwc->gadget);
+ spin_lock(&dwc->lock);
+ }
+}
+
+static void dwc3_resume_gadget(struct dwc3 *dwc)
+{
+ if (dwc->gadget_driver && dwc->gadget_driver->resume) {
+ spin_unlock(&dwc->lock);
+ dwc->gadget_driver->resume(&dwc->gadget);
+ spin_lock(&dwc->lock);
+ }
+}
+
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
{
struct dwc3_ep *dep;
struct dwc3_gadget_ep_cmd_params params;
@@ -2031,7 +2093,8 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
*/
cmd = DWC3_DEPCMD_ENDTRANSFER;
- cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
+ cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0;
+ cmd |= DWC3_DEPCMD_CMDIOC;
cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
memset(&params, 0, sizeof(params));
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
@@ -2260,17 +2323,23 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
reg |= DWC3_DCTL_HIRD_THRES(12);
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+ } else {
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg &= ~DWC3_DCTL_HIRD_THRES_MASK;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
}
dep = dwc->eps[0];
- ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true,
+ false);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
return;
}
dep = dwc->eps[1];
- ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true,
+ false);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
return;
@@ -2378,9 +2447,50 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
dwc->link_state = next;
+ switch (next) {
+ case DWC3_LINK_STATE_U1:
+ if (dwc->speed == USB_SPEED_SUPER)
+ dwc3_suspend_gadget(dwc);
+ break;
+ case DWC3_LINK_STATE_U2:
+ case DWC3_LINK_STATE_U3:
+ dwc3_suspend_gadget(dwc);
+ break;
+ case DWC3_LINK_STATE_RESUME:
+ dwc3_resume_gadget(dwc);
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+
dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
}
+static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
+ unsigned int evtinfo)
+{
+ unsigned int is_ss = evtinfo & BIT(4);
+
+ /**
+ * WORKAROUND: DWC3 revison 2.20a with hibernation support
+ * have a known issue which can cause USB CV TD.9.23 to fail
+ * randomly.
+ *
+ * Because of this issue, core could generate bogus hibernation
+ * events which SW needs to ignore.
+ *
+ * Refers to:
+ *
+ * STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0
+ * Device Fallback from SuperSpeed
+ */
+ if (is_ss ^ (dwc->speed == USB_SPEED_SUPER))
+ return;
+
+ /* enter hibernation here */
+}
+
static void dwc3_gadget_interrupt(struct dwc3 *dwc,
const struct dwc3_event_devt *event)
{
@@ -2397,6 +2507,13 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
case DWC3_DEVICE_EVENT_WAKEUP:
dwc3_gadget_wakeup_interrupt(dwc);
break;
+ case DWC3_DEVICE_EVENT_HIBER_REQ:
+ if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation,
+ "unexpected hibernation event\n"))
+ break;
+
+ dwc3_gadget_hibernation_interrupt(dwc, event->event_info);
+ break;
case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
break;
@@ -2661,8 +2778,10 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
int dwc3_gadget_prepare(struct dwc3 *dwc)
{
- if (dwc->pullups_connected)
+ if (dwc->pullups_connected) {
dwc3_gadget_disable_irq(dwc);
+ dwc3_gadget_run_stop(dwc, true, true);
+ }
return 0;
}
@@ -2671,7 +2790,7 @@ void dwc3_gadget_complete(struct dwc3 *dwc)
{
if (dwc->pullups_connected) {
dwc3_gadget_enable_irq(dwc);
- dwc3_gadget_run_stop(dwc, true);
+ dwc3_gadget_run_stop(dwc, true, false);
}
}
@@ -2694,12 +2813,14 @@ int dwc3_gadget_resume(struct dwc3 *dwc)
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
dep = dwc->eps[0];
- ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
+ false);
if (ret)
goto err0;
dep = dwc->eps[1];
- ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
+ false);
if (ret)
goto err1;
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index febe1aa7b714..a0ee75b68a80 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -56,12 +56,6 @@ struct dwc3;
/* DEPXFERCFG parameter 0 */
#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff)
-struct dwc3_gadget_ep_cmd_params {
- u32 param2;
- u32 param1;
- u32 param0;
-};
-
/* -------------------------------------------------------------------------- */
#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))
@@ -85,9 +79,6 @@ static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status);
-int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
-int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
-
void dwc3_ep0_interrupt(struct dwc3 *dwc,
const struct dwc3_event_depevt *event);
void dwc3_ep0_out_start(struct dwc3 *dwc);
@@ -95,9 +86,6 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
gfp_t gfp_flags);
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
-int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
- unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
-int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param);
/**
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 8154165aa601..3557c7e5040d 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -226,7 +226,7 @@ config USB_GR_UDC
config USB_OMAP
tristate "OMAP USB Device Controller"
depends on ARCH_OMAP1
- select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
+ select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
help
Many Texas Instruments OMAP processors have flexible full
speed USB device controllers, with support for up to 30
@@ -301,7 +301,6 @@ config USB_PXA27X
gadget drivers to also be dynamically linked.
config USB_S3C_HSOTG
- depends on ARM
tristate "Designware/S3C HS/OtG USB Device controller"
help
The Designware USB2.0 high-speed gadget controller
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index cea8c20a1425..f605ad8c1902 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -1758,15 +1758,15 @@ static int at91udc_probe(struct platform_device *pdev)
/* newer chips have more FIFO memory than rm9200 */
if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) {
- usb_ep_set_maxpacket_limit(&udc->ep[0].ep, 64);
- usb_ep_set_maxpacket_limit(&udc->ep[3].ep, 64);
- usb_ep_set_maxpacket_limit(&udc->ep[4].ep, 512);
- usb_ep_set_maxpacket_limit(&udc->ep[5].ep, 512);
+ udc->ep[0].maxpacket = 64;
+ udc->ep[3].maxpacket = 64;
+ udc->ep[4].maxpacket = 512;
+ udc->ep[5].maxpacket = 512;
} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
- usb_ep_set_maxpacket_limit(&udc->ep[3].ep, 64);
+ udc->ep[3].maxpacket = 64;
} else if (cpu_is_at91sam9263()) {
- usb_ep_set_maxpacket_limit(&udc->ep[0].ep, 64);
- usb_ep_set_maxpacket_limit(&udc->ep[3].ep, 64);
+ udc->ep[0].maxpacket = 64;
+ udc->ep[3].maxpacket = 64;
}
udc->udp_baseaddr = ioremap(res->start, resource_size(res));
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 52771d4c44bc..9f65324f9ae0 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1661,7 +1661,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
if (dma_status) {
int i;
- for (i = 1; i < USBA_NR_ENDPOINTS; i++)
+ for (i = 1; i < USBA_NR_DMAS; i++)
if (dma_status & (1 << i))
usba_dma_irq(udc, &udc->usba_ep[i]);
}
@@ -1670,7 +1670,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
if (ep_status) {
int i;
- for (i = 0; i < USBA_NR_ENDPOINTS; i++)
+ for (i = 0; i < udc->num_ep; i++)
if (ep_status & (1 << i)) {
if (ep_is_control(&udc->usba_ep[i]))
usba_control_irq(udc, &udc->usba_ep[i]);
@@ -1827,12 +1827,12 @@ static int atmel_usba_stop(struct usb_gadget *gadget,
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
- udc->driver = NULL;
-
clk_disable_unprepare(udc->hclk);
clk_disable_unprepare(udc->pclk);
- DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
+ DBG(DBG_GADGET, "unregistered driver `%s'\n", udc->driver->driver.name);
+
+ udc->driver = NULL;
return 0;
}
@@ -1914,6 +1914,12 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
i++;
}
+ if (i == 0) {
+ dev_err(&pdev->dev, "of_probe: no endpoint specified\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
return eps;
err:
return ERR_PTR(ret);
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
index 2922db50befe..a70706e8cb02 100644
--- a/drivers/usb/gadget/atmel_usba_udc.h
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -210,7 +210,7 @@
#define USBA_FIFO_BASE(x) ((x) << 16)
/* Synth parameters */
-#define USBA_NR_ENDPOINTS 7
+#define USBA_NR_DMAS 7
#define EP0_FIFO_SIZE 64
#define EP0_EPT_SIZE USBA_EPT_SIZE_64
diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c
index 888fbb43b338..e969eb809a85 100644
--- a/drivers/usb/gadget/bcm63xx_udc.c
+++ b/drivers/usb/gadget/bcm63xx_udc.c
@@ -360,24 +360,30 @@ static inline void usb_dma_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
bcm_writel(val, udc->iudma_regs + off);
}
-static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off)
+static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off, int chan)
{
- return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off);
+ return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off +
+ (ENETDMA_CHAN_WIDTH * chan));
}
-static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off,
+ int chan)
{
- bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off);
+ bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off +
+ (ENETDMA_CHAN_WIDTH * chan));
}
-static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off)
+static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off, int chan)
{
- return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off);
+ return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off +
+ (ENETDMA_CHAN_WIDTH * chan));
}
-static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off,
+ int chan)
{
- bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off);
+ bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off +
+ (ENETDMA_CHAN_WIDTH * chan));
}
static inline void set_clocks(struct bcm63xx_udc *udc, bool is_enabled)
@@ -638,7 +644,7 @@ static void iudma_write(struct bcm63xx_udc *udc, struct iudma_ch *iudma,
} while (!last_bd);
usb_dmac_writel(udc, ENETDMAC_CHANCFG_EN_MASK,
- ENETDMAC_CHANCFG_REG(iudma->ch_idx));
+ ENETDMAC_CHANCFG_REG, iudma->ch_idx);
}
/**
@@ -694,9 +700,9 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)
bcm63xx_fifo_reset_ep(udc, max(0, iudma->ep_num));
/* stop DMA, then wait for the hardware to wrap up */
- usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG(ch_idx));
+ usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG, ch_idx);
- while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)) &
+ while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx) &
ENETDMAC_CHANCFG_EN_MASK) {
udelay(1);
@@ -713,10 +719,10 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)
dev_warn(udc->dev, "forcibly halting IUDMA channel %d\n",
ch_idx);
usb_dmac_writel(udc, ENETDMAC_CHANCFG_BUFHALT_MASK,
- ENETDMAC_CHANCFG_REG(ch_idx));
+ ENETDMAC_CHANCFG_REG, ch_idx);
}
}
- usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG(ch_idx));
+ usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG, ch_idx);
/* don't leave "live" HW-owned entries for the next guy to step on */
for (d = iudma->bd_ring; d <= iudma->end_bd; d++)
@@ -728,11 +734,11 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)
/* set up IRQs, UBUS burst size, and BD base for this channel */
usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK,
- ENETDMAC_IRMASK_REG(ch_idx));
- usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG(ch_idx));
+ ENETDMAC_IRMASK_REG, ch_idx);
+ usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG, ch_idx);
- usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG(ch_idx));
- usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG(ch_idx));
+ usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG, ch_idx);
+ usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG, ch_idx);
}
/**
@@ -2035,7 +2041,7 @@ static irqreturn_t bcm63xx_udc_data_isr(int irq, void *dev_id)
spin_lock(&udc->lock);
usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK,
- ENETDMAC_IR_REG(iudma->ch_idx));
+ ENETDMAC_IR_REG, iudma->ch_idx);
bep = iudma->bep;
rc = iudma_read(udc, iudma);
@@ -2175,18 +2181,18 @@ static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p)
seq_printf(s, " [ep%d]:\n",
max_t(int, iudma_defaults[ch_idx].ep_num, 0));
seq_printf(s, " cfg: %08x; irqstat: %08x; irqmask: %08x; maxburst: %08x\n",
- usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)),
- usb_dmac_readl(udc, ENETDMAC_IR_REG(ch_idx)),
- usb_dmac_readl(udc, ENETDMAC_IRMASK_REG(ch_idx)),
- usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG(ch_idx)));
+ usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx),
+ usb_dmac_readl(udc, ENETDMAC_IR_REG, ch_idx),
+ usb_dmac_readl(udc, ENETDMAC_IRMASK_REG, ch_idx),
+ usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG, ch_idx));
- sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG(ch_idx));
- sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG(ch_idx));
+ sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG, ch_idx);
+ sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG, ch_idx);
seq_printf(s, " base: %08x; index: %04x_%04x; desc: %04x_%04x %08x\n",
- usb_dmas_readl(udc, ENETDMAS_RSTART_REG(ch_idx)),
+ usb_dmas_readl(udc, ENETDMAS_RSTART_REG, ch_idx),
sram2 >> 16, sram2 & 0xffff,
sram3 >> 16, sram3 & 0xffff,
- usb_dmas_readl(udc, ENETDMAS_SRAM4_REG(ch_idx)));
+ usb_dmas_readl(udc, ENETDMAS_SRAM4_REG, ch_idx));
seq_printf(s, " desc: %d/%d used", iudma->n_bds_used,
iudma->n_bds);
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index d742bed7a5fa..fab906429b80 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1139,7 +1139,7 @@ struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev,
uc = copy_gadget_strings(sp, n_gstrings, n_strings);
if (IS_ERR(uc))
- return ERR_PTR(PTR_ERR(uc));
+ return ERR_CAST(uc);
n_gs = get_containers_gs(uc);
ret = usb_string_ids_tab(cdev, n_gs[0]->strings);
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index 306a2b52125c..2e164dca08e8 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -28,6 +28,10 @@
#include <linux/usb/composite.h>
#include <linux/usb/functionfs.h>
+#include <linux/aio.h>
+#include <linux/mmu_context.h>
+#include <linux/poll.h>
+
#include "u_fs.h"
#include "configfs.h"
@@ -99,6 +103,14 @@ static struct ffs_function *ffs_func_from_usb(struct usb_function *f)
}
+static inline enum ffs_setup_state
+ffs_setup_state_clear_cancelled(struct ffs_data *ffs)
+{
+ return (enum ffs_setup_state)
+ cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP);
+}
+
+
static void ffs_func_eps_disable(struct ffs_function *func);
static int __must_check ffs_func_eps_enable(struct ffs_function *func);
@@ -122,8 +134,8 @@ struct ffs_ep {
struct usb_ep *ep; /* P: ffs->eps_lock */
struct usb_request *req; /* P: epfile->mutex */
- /* [0]: full speed, [1]: high speed */
- struct usb_endpoint_descriptor *descs[2];
+ /* [0]: full speed, [1]: high speed, [2]: super speed */
+ struct usb_endpoint_descriptor *descs[3];
u8 num;
@@ -148,6 +160,25 @@ struct ffs_epfile {
unsigned char _pad;
};
+/* ffs_io_data structure ***************************************************/
+
+struct ffs_io_data {
+ bool aio;
+ bool read;
+
+ struct kiocb *kiocb;
+ const struct iovec *iovec;
+ unsigned long nr_segs;
+ char __user *buf;
+ size_t len;
+
+ struct mm_struct *mm;
+ struct work_struct work;
+
+ struct usb_ep *ep;
+ struct usb_request *req;
+};
+
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
@@ -161,8 +192,10 @@ ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
DEFINE_MUTEX(ffs_lock);
EXPORT_SYMBOL(ffs_lock);
-static struct ffs_dev *ffs_find_dev(const char *name);
+static struct ffs_dev *_ffs_find_dev(const char *name);
+static struct ffs_dev *_ffs_alloc_dev(void);
static int _ffs_name_dev(struct ffs_dev *dev, const char *name);
+static void _ffs_free_dev(struct ffs_dev *dev);
static void *ffs_acquire_dev(const char *dev_name);
static void ffs_release_dev(struct ffs_data *ffs_data);
static int ffs_ready(struct ffs_data *ffs);
@@ -218,7 +251,7 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
}
ffs->setup_state = FFS_NO_SETUP;
- return ffs->ep0req_status;
+ return req->status ? req->status : req->actual;
}
static int __ffs_ep0_stall(struct ffs_data *ffs)
@@ -244,7 +277,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
ENTER();
/* Fast check if setup was canceled */
- if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED)
+ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
return -EIDRM;
/* Acquire mutex */
@@ -310,8 +343,8 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
* rather then _irqsave
*/
spin_lock_irq(&ffs->ev.waitq.lock);
- switch (FFS_SETUP_STATE(ffs)) {
- case FFS_SETUP_CANCELED:
+ switch (ffs_setup_state_clear_cancelled(ffs)) {
+ case FFS_SETUP_CANCELLED:
ret = -EIDRM;
goto done_spin;
@@ -346,7 +379,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
/*
* We are guaranteed to be still in FFS_ACTIVE state
* but the state of setup could have changed from
- * FFS_SETUP_PENDING to FFS_SETUP_CANCELED so we need
+ * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need
* to check for that. If that happened we copied data
* from user space in vain but it's unlikely.
*
@@ -355,7 +388,8 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
* transition can be performed and it's protected by
* mutex.
*/
- if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) {
+ if (ffs_setup_state_clear_cancelled(ffs) ==
+ FFS_SETUP_CANCELLED) {
ret = -EIDRM;
done_spin:
spin_unlock_irq(&ffs->ev.waitq.lock);
@@ -421,7 +455,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
ENTER();
/* Fast check if setup was canceled */
- if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED)
+ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
return -EIDRM;
/* Acquire mutex */
@@ -441,8 +475,8 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
*/
spin_lock_irq(&ffs->ev.waitq.lock);
- switch (FFS_SETUP_STATE(ffs)) {
- case FFS_SETUP_CANCELED:
+ switch (ffs_setup_state_clear_cancelled(ffs)) {
+ case FFS_SETUP_CANCELLED:
ret = -EIDRM;
break;
@@ -489,7 +523,8 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
spin_lock_irq(&ffs->ev.waitq.lock);
/* See ffs_ep0_write() */
- if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) {
+ if (ffs_setup_state_clear_cancelled(ffs) ==
+ FFS_SETUP_CANCELLED) {
ret = -EIDRM;
break;
}
@@ -558,6 +593,45 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
return ret;
}
+static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait)
+{
+ struct ffs_data *ffs = file->private_data;
+ unsigned int mask = POLLWRNORM;
+ int ret;
+
+ poll_wait(file, &ffs->ev.waitq, wait);
+
+ ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
+ if (unlikely(ret < 0))
+ return mask;
+
+ switch (ffs->state) {
+ case FFS_READ_DESCRIPTORS:
+ case FFS_READ_STRINGS:
+ mask |= POLLOUT;
+ break;
+
+ case FFS_ACTIVE:
+ switch (ffs->setup_state) {
+ case FFS_NO_SETUP:
+ if (ffs->ev.count)
+ mask |= POLLIN;
+ break;
+
+ case FFS_SETUP_PENDING:
+ case FFS_SETUP_CANCELLED:
+ mask |= (POLLIN | POLLOUT);
+ break;
+ }
+ case FFS_CLOSING:
+ break;
+ }
+
+ mutex_unlock(&ffs->mutex);
+
+ return mask;
+}
+
static const struct file_operations ffs_ep0_operations = {
.llseek = no_llseek,
@@ -566,6 +640,7 @@ static const struct file_operations ffs_ep0_operations = {
.read = ffs_ep0_read,
.release = ffs_ep0_release,
.unlocked_ioctl = ffs_ep0_ioctl,
+ .poll = ffs_ep0_poll,
};
@@ -581,11 +656,54 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
}
}
-static ssize_t ffs_epfile_io(struct file *file,
- char __user *buf, size_t len, int read)
+static void ffs_user_copy_worker(struct work_struct *work)
+{
+ struct ffs_io_data *io_data = container_of(work, struct ffs_io_data,
+ work);
+ int ret = io_data->req->status ? io_data->req->status :
+ io_data->req->actual;
+
+ if (io_data->read && ret > 0) {
+ int i;
+ size_t pos = 0;
+ use_mm(io_data->mm);
+ for (i = 0; i < io_data->nr_segs; i++) {
+ if (unlikely(copy_to_user(io_data->iovec[i].iov_base,
+ &io_data->buf[pos],
+ io_data->iovec[i].iov_len))) {
+ ret = -EFAULT;
+ break;
+ }
+ pos += io_data->iovec[i].iov_len;
+ }
+ unuse_mm(io_data->mm);
+ }
+
+ aio_complete(io_data->kiocb, ret, ret);
+
+ usb_ep_free_request(io_data->ep, io_data->req);
+
+ io_data->kiocb->private = NULL;
+ if (io_data->read)
+ kfree(io_data->iovec);
+ kfree(io_data->buf);
+ kfree(io_data);
+}
+
+static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
+ struct usb_request *req)
+{
+ struct ffs_io_data *io_data = req->context;
+
+ ENTER();
+
+ INIT_WORK(&io_data->work, ffs_user_copy_worker);
+ schedule_work(&io_data->work);
+}
+
+static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
{
struct ffs_epfile *epfile = file->private_data;
- struct usb_gadget *gadget = epfile->ffs->gadget;
struct ffs_ep *ep;
char *data = NULL;
ssize_t ret, data_len;
@@ -613,7 +731,7 @@ static ssize_t ffs_epfile_io(struct file *file,
}
/* Do we halt? */
- halt = !read == !epfile->in;
+ halt = (!io_data->read == !epfile->in);
if (halt && epfile->isoc) {
ret = -EINVAL;
goto error;
@@ -622,18 +740,41 @@ static ssize_t ffs_epfile_io(struct file *file,
/* Allocate & copy */
if (!halt) {
/*
+ * if we _do_ wait above, the epfile->ffs->gadget might be NULL
+ * before the waiting completes, so do not assign to 'gadget' earlier
+ */
+ struct usb_gadget *gadget = epfile->ffs->gadget;
+
+ /*
* Controller may require buffer size to be aligned to
* maxpacketsize of an out endpoint.
*/
- data_len = read ? usb_ep_align_maybe(gadget, ep->ep, len) : len;
+ data_len = io_data->read ?
+ usb_ep_align_maybe(gadget, ep->ep, io_data->len) :
+ io_data->len;
data = kmalloc(data_len, GFP_KERNEL);
if (unlikely(!data))
return -ENOMEM;
-
- if (!read && unlikely(copy_from_user(data, buf, len))) {
- ret = -EFAULT;
- goto error;
+ if (io_data->aio && !io_data->read) {
+ int i;
+ size_t pos = 0;
+ for (i = 0; i < io_data->nr_segs; i++) {
+ if (unlikely(copy_from_user(&data[pos],
+ io_data->iovec[i].iov_base,
+ io_data->iovec[i].iov_len))) {
+ ret = -EFAULT;
+ goto error;
+ }
+ pos += io_data->iovec[i].iov_len;
+ }
+ } else {
+ if (!io_data->read &&
+ unlikely(__copy_from_user(data, io_data->buf,
+ io_data->len))) {
+ ret = -EFAULT;
+ goto error;
+ }
}
}
@@ -656,40 +797,78 @@ static ssize_t ffs_epfile_io(struct file *file,
ret = -EBADMSG;
} else {
/* Fire the request */
- DECLARE_COMPLETION_ONSTACK(done);
+ struct usb_request *req;
- struct usb_request *req = ep->req;
- req->context = &done;
- req->complete = ffs_epfile_io_complete;
- req->buf = data;
- req->length = data_len;
+ if (io_data->aio) {
+ req = usb_ep_alloc_request(ep->ep, GFP_KERNEL);
+ if (unlikely(!req))
+ goto error_lock;
- ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+ req->buf = data;
+ req->length = io_data->len;
- spin_unlock_irq(&epfile->ffs->eps_lock);
+ io_data->buf = data;
+ io_data->ep = ep->ep;
+ io_data->req = req;
- if (unlikely(ret < 0)) {
- /* nop */
- } else if (unlikely(wait_for_completion_interruptible(&done))) {
- ret = -EINTR;
- usb_ep_dequeue(ep->ep, req);
+ req->context = io_data;
+ req->complete = ffs_epfile_async_io_complete;
+
+ ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+ if (unlikely(ret)) {
+ usb_ep_free_request(ep->ep, req);
+ goto error_lock;
+ }
+ ret = -EIOCBQUEUED;
+
+ spin_unlock_irq(&epfile->ffs->eps_lock);
} else {
- /*
- * XXX We may end up silently droping data here.
- * Since data_len (i.e. req->length) may be bigger
- * than len (after being rounded up to maxpacketsize),
- * we may end up with more data then user space has
- * space for.
- */
- ret = ep->status;
- if (read && ret > 0 &&
- unlikely(copy_to_user(buf, data,
- min_t(size_t, ret, len))))
- ret = -EFAULT;
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ req = ep->req;
+ req->buf = data;
+ req->length = io_data->len;
+
+ req->context = &done;
+ req->complete = ffs_epfile_io_complete;
+
+ ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+
+ if (unlikely(ret < 0)) {
+ /* nop */
+ } else if (unlikely(
+ wait_for_completion_interruptible(&done))) {
+ ret = -EINTR;
+ usb_ep_dequeue(ep->ep, req);
+ } else {
+ /*
+ * XXX We may end up silently droping data
+ * here. Since data_len (i.e. req->length) may
+ * be bigger than len (after being rounded up
+ * to maxpacketsize), we may end up with more
+ * data then user space has space for.
+ */
+ ret = ep->status;
+ if (io_data->read && ret > 0) {
+ ret = min_t(size_t, ret, io_data->len);
+
+ if (unlikely(copy_to_user(io_data->buf,
+ data, ret)))
+ ret = -EFAULT;
+ }
+ }
+ kfree(data);
}
}
mutex_unlock(&epfile->mutex);
+ return ret;
+
+error_lock:
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ mutex_unlock(&epfile->mutex);
error:
kfree(data);
return ret;
@@ -699,17 +878,31 @@ static ssize_t
ffs_epfile_write(struct file *file, const char __user *buf, size_t len,
loff_t *ptr)
{
+ struct ffs_io_data io_data;
+
ENTER();
- return ffs_epfile_io(file, (char __user *)buf, len, 0);
+ io_data.aio = false;
+ io_data.read = false;
+ io_data.buf = (char * __user)buf;
+ io_data.len = len;
+
+ return ffs_epfile_io(file, &io_data);
}
static ssize_t
ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr)
{
+ struct ffs_io_data io_data;
+
ENTER();
- return ffs_epfile_io(file, buf, len, 1);
+ io_data.aio = false;
+ io_data.read = true;
+ io_data.buf = buf;
+ io_data.len = len;
+
+ return ffs_epfile_io(file, &io_data);
}
static int
@@ -728,6 +921,89 @@ ffs_epfile_open(struct inode *inode, struct file *file)
return 0;
}
+static int ffs_aio_cancel(struct kiocb *kiocb)
+{
+ struct ffs_io_data *io_data = kiocb->private;
+ struct ffs_epfile *epfile = kiocb->ki_filp->private_data;
+ int value;
+
+ ENTER();
+
+ spin_lock_irq(&epfile->ffs->eps_lock);
+
+ if (likely(io_data && io_data->ep && io_data->req))
+ value = usb_ep_dequeue(io_data->ep, io_data->req);
+ else
+ value = -EINVAL;
+
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+
+ return value;
+}
+
+static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb,
+ const struct iovec *iovec,
+ unsigned long nr_segs, loff_t loff)
+{
+ struct ffs_io_data *io_data;
+
+ ENTER();
+
+ io_data = kmalloc(sizeof(*io_data), GFP_KERNEL);
+ if (unlikely(!io_data))
+ return -ENOMEM;
+
+ io_data->aio = true;
+ io_data->read = false;
+ io_data->kiocb = kiocb;
+ io_data->iovec = iovec;
+ io_data->nr_segs = nr_segs;
+ io_data->len = kiocb->ki_nbytes;
+ io_data->mm = current->mm;
+
+ kiocb->private = io_data;
+
+ kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
+
+ return ffs_epfile_io(kiocb->ki_filp, io_data);
+}
+
+static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb,
+ const struct iovec *iovec,
+ unsigned long nr_segs, loff_t loff)
+{
+ struct ffs_io_data *io_data;
+ struct iovec *iovec_copy;
+
+ ENTER();
+
+ iovec_copy = kmalloc_array(nr_segs, sizeof(*iovec_copy), GFP_KERNEL);
+ if (unlikely(!iovec_copy))
+ return -ENOMEM;
+
+ memcpy(iovec_copy, iovec, sizeof(struct iovec)*nr_segs);
+
+ io_data = kmalloc(sizeof(*io_data), GFP_KERNEL);
+ if (unlikely(!io_data)) {
+ kfree(iovec_copy);
+ return -ENOMEM;
+ }
+
+ io_data->aio = true;
+ io_data->read = true;
+ io_data->kiocb = kiocb;
+ io_data->iovec = iovec_copy;
+ io_data->nr_segs = nr_segs;
+ io_data->len = kiocb->ki_nbytes;
+ io_data->mm = current->mm;
+
+ kiocb->private = io_data;
+
+ kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
+
+ return ffs_epfile_io(kiocb->ki_filp, io_data);
+}
+
static int
ffs_epfile_release(struct inode *inode, struct file *file)
{
@@ -784,6 +1060,8 @@ static const struct file_operations ffs_epfile_operations = {
.open = ffs_epfile_open,
.write = ffs_epfile_write,
.read = ffs_epfile_read,
+ .aio_write = ffs_epfile_aio_write,
+ .aio_read = ffs_epfile_aio_read,
.release = ffs_epfile_release,
.unlocked_ioctl = ffs_epfile_ioctl,
};
@@ -1167,7 +1445,7 @@ static void ffs_data_clear(struct ffs_data *ffs)
if (ffs->epfiles)
ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
- kfree(ffs->raw_descs);
+ kfree(ffs->raw_descs_data);
kfree(ffs->raw_strings);
kfree(ffs->stringtabs);
}
@@ -1179,14 +1457,15 @@ static void ffs_data_reset(struct ffs_data *ffs)
ffs_data_clear(ffs);
ffs->epfiles = NULL;
+ ffs->raw_descs_data = NULL;
ffs->raw_descs = NULL;
ffs->raw_strings = NULL;
ffs->stringtabs = NULL;
ffs->raw_descs_length = 0;
- ffs->raw_fs_descs_length = 0;
ffs->fs_descs_count = 0;
ffs->hs_descs_count = 0;
+ ffs->ss_descs_count = 0;
ffs->strings_count = 0;
ffs->interfaces_count = 0;
@@ -1329,7 +1608,24 @@ static int ffs_func_eps_enable(struct ffs_function *func)
spin_lock_irqsave(&func->ffs->eps_lock, flags);
do {
struct usb_endpoint_descriptor *ds;
- ds = ep->descs[ep->descs[1] ? 1 : 0];
+ int desc_idx;
+
+ if (ffs->gadget->speed == USB_SPEED_SUPER)
+ desc_idx = 2;
+ else if (ffs->gadget->speed == USB_SPEED_HIGH)
+ desc_idx = 1;
+ else
+ desc_idx = 0;
+
+ /* fall-back to lower speed if desc missing for current speed */
+ do {
+ ds = ep->descs[desc_idx];
+ } while (!ds && --desc_idx >= 0);
+
+ if (!ds) {
+ ret = -EINVAL;
+ break;
+ }
ep->ep->driver_data = ep;
ep->ep->desc = ds;
@@ -1464,6 +1760,12 @@ static int __must_check ffs_do_desc(char *data, unsigned len,
}
break;
+ case USB_DT_SS_ENDPOINT_COMP:
+ pr_vdebug("EP SS companion descriptor\n");
+ if (length != sizeof(struct usb_ss_ep_comp_descriptor))
+ goto inv_length;
+ break;
+
case USB_DT_OTHER_SPEED_CONFIG:
case USB_DT_INTERFACE_POWER:
case USB_DT_DEBUG:
@@ -1574,60 +1876,76 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
static int __ffs_data_got_descs(struct ffs_data *ffs,
char *const _data, size_t len)
{
- unsigned fs_count, hs_count;
- int fs_len, ret = -EINVAL;
- char *data = _data;
+ char *data = _data, *raw_descs;
+ unsigned counts[3], flags;
+ int ret = -EINVAL, i;
ENTER();
- if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC ||
- get_unaligned_le32(data + 4) != len))
+ if (get_unaligned_le32(data + 4) != len)
goto error;
- fs_count = get_unaligned_le32(data + 8);
- hs_count = get_unaligned_le32(data + 12);
- if (!fs_count && !hs_count)
- goto einval;
-
- data += 16;
- len -= 16;
-
- if (likely(fs_count)) {
- fs_len = ffs_do_descs(fs_count, data, len,
- __ffs_data_do_entity, ffs);
- if (unlikely(fs_len < 0)) {
- ret = fs_len;
+ switch (get_unaligned_le32(data)) {
+ case FUNCTIONFS_DESCRIPTORS_MAGIC:
+ flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
+ data += 8;
+ len -= 8;
+ break;
+ case FUNCTIONFS_DESCRIPTORS_MAGIC_V2:
+ flags = get_unaligned_le32(data + 8);
+ if (flags & ~(FUNCTIONFS_HAS_FS_DESC |
+ FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC)) {
+ ret = -ENOSYS;
goto error;
}
+ data += 12;
+ len -= 12;
+ break;
+ default:
+ goto error;
+ }
- data += fs_len;
- len -= fs_len;
- } else {
- fs_len = 0;
+ /* Read fs_count, hs_count and ss_count (if present) */
+ for (i = 0; i < 3; ++i) {
+ if (!(flags & (1 << i))) {
+ counts[i] = 0;
+ } else if (len < 4) {
+ goto error;
+ } else {
+ counts[i] = get_unaligned_le32(data);
+ data += 4;
+ len -= 4;
+ }
}
- if (likely(hs_count)) {
- ret = ffs_do_descs(hs_count, data, len,
+ /* Read descriptors */
+ raw_descs = data;
+ for (i = 0; i < 3; ++i) {
+ if (!counts[i])
+ continue;
+ ret = ffs_do_descs(counts[i], data, len,
__ffs_data_do_entity, ffs);
- if (unlikely(ret < 0))
+ if (ret < 0)
goto error;
- } else {
- ret = 0;
+ data += ret;
+ len -= ret;
}
- if (unlikely(len != ret))
- goto einval;
+ if (raw_descs == data || len) {
+ ret = -EINVAL;
+ goto error;
+ }
- ffs->raw_fs_descs_length = fs_len;
- ffs->raw_descs_length = fs_len + ret;
- ffs->raw_descs = _data;
- ffs->fs_descs_count = fs_count;
- ffs->hs_descs_count = hs_count;
+ ffs->raw_descs_data = _data;
+ ffs->raw_descs = raw_descs;
+ ffs->raw_descs_length = data - raw_descs;
+ ffs->fs_descs_count = counts[0];
+ ffs->hs_descs_count = counts[1];
+ ffs->ss_descs_count = counts[2];
return 0;
-einval:
- ret = -EINVAL;
error:
kfree(_data);
return ret;
@@ -1784,7 +2102,7 @@ static void __ffs_event_add(struct ffs_data *ffs,
* the source does nothing.
*/
if (ffs->setup_state == FFS_SETUP_PENDING)
- ffs->setup_state = FFS_SETUP_CANCELED;
+ ffs->setup_state = FFS_SETUP_CANCELLED;
switch (type) {
case FUNCTIONFS_RESUME:
@@ -1845,21 +2163,28 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
struct usb_endpoint_descriptor *ds = (void *)desc;
struct ffs_function *func = priv;
struct ffs_ep *ffs_ep;
-
- /*
- * If hs_descriptors is not NULL then we are reading hs
- * descriptors now
- */
- const int isHS = func->function.hs_descriptors != NULL;
- unsigned idx;
+ unsigned ep_desc_id, idx;
+ static const char *speed_names[] = { "full", "high", "super" };
if (type != FFS_DESCRIPTOR)
return 0;
- if (isHS)
+ /*
+ * If ss_descriptors is not NULL, we are reading super speed
+ * descriptors; if hs_descriptors is not NULL, we are reading high
+ * speed descriptors; otherwise, we are reading full speed
+ * descriptors.
+ */
+ if (func->function.ss_descriptors) {
+ ep_desc_id = 2;
+ func->function.ss_descriptors[(long)valuep] = desc;
+ } else if (func->function.hs_descriptors) {
+ ep_desc_id = 1;
func->function.hs_descriptors[(long)valuep] = desc;
- else
+ } else {
+ ep_desc_id = 0;
func->function.fs_descriptors[(long)valuep] = desc;
+ }
if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
return 0;
@@ -1867,13 +2192,13 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;
ffs_ep = func->eps + idx;
- if (unlikely(ffs_ep->descs[isHS])) {
- pr_vdebug("two %sspeed descriptors for EP %d\n",
- isHS ? "high" : "full",
+ if (unlikely(ffs_ep->descs[ep_desc_id])) {
+ pr_err("two %sspeed descriptors for EP %d\n",
+ speed_names[ep_desc_id],
ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
return -EINVAL;
}
- ffs_ep->descs[isHS] = ds;
+ ffs_ep->descs[ep_desc_id] = ds;
ffs_dump_mem(": Original ep desc", ds, ds->bLength);
if (ffs_ep->ep) {
@@ -2017,8 +2342,10 @@ static int _ffs_func_bind(struct usb_configuration *c,
const int full = !!func->ffs->fs_descs_count;
const int high = gadget_is_dualspeed(func->gadget) &&
func->ffs->hs_descs_count;
+ const int super = gadget_is_superspeed(func->gadget) &&
+ func->ffs->ss_descs_count;
- int ret;
+ int fs_len, hs_len, ret;
/* Make it a single chunk, less management later on */
vla_group(d);
@@ -2027,15 +2354,16 @@ static int _ffs_func_bind(struct usb_configuration *c,
full ? ffs->fs_descs_count + 1 : 0);
vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs,
high ? ffs->hs_descs_count + 1 : 0);
+ vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
+ super ? ffs->ss_descs_count + 1 : 0);
vla_item_with_sz(d, short, inums, ffs->interfaces_count);
- vla_item_with_sz(d, char, raw_descs,
- high ? ffs->raw_descs_length : ffs->raw_fs_descs_length);
+ vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
char *vlabuf;
ENTER();
- /* Only high speed but not supported by gadget? */
- if (unlikely(!(full | high)))
+ /* Has descriptors only for speeds gadget does not support */
+ if (unlikely(!(full | high | super)))
return -ENOTSUPP;
/* Allocate a single chunk, less management later on */
@@ -2045,8 +2373,10 @@ static int _ffs_func_bind(struct usb_configuration *c,
/* Zero */
memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz);
- memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs + 16,
- d_raw_descs__sz);
+ /* Copy descriptors */
+ memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs,
+ ffs->raw_descs_length);
+
memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
for (ret = ffs->eps_count; ret; --ret) {
struct ffs_ep *ptr;
@@ -2068,22 +2398,38 @@ static int _ffs_func_bind(struct usb_configuration *c,
*/
if (likely(full)) {
func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs);
- ret = ffs_do_descs(ffs->fs_descs_count,
- vla_ptr(vlabuf, d, raw_descs),
- d_raw_descs__sz,
- __ffs_func_bind_do_descs, func);
- if (unlikely(ret < 0))
+ fs_len = ffs_do_descs(ffs->fs_descs_count,
+ vla_ptr(vlabuf, d, raw_descs),
+ d_raw_descs__sz,
+ __ffs_func_bind_do_descs, func);
+ if (unlikely(fs_len < 0)) {
+ ret = fs_len;
goto error;
+ }
} else {
- ret = 0;
+ fs_len = 0;
}
if (likely(high)) {
func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs);
- ret = ffs_do_descs(ffs->hs_descs_count,
- vla_ptr(vlabuf, d, raw_descs) + ret,
- d_raw_descs__sz - ret,
- __ffs_func_bind_do_descs, func);
+ hs_len = ffs_do_descs(ffs->hs_descs_count,
+ vla_ptr(vlabuf, d, raw_descs) + fs_len,
+ d_raw_descs__sz - fs_len,
+ __ffs_func_bind_do_descs, func);
+ if (unlikely(hs_len < 0)) {
+ ret = hs_len;
+ goto error;
+ }
+ } else {
+ hs_len = 0;
+ }
+
+ if (likely(super)) {
+ func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs);
+ ret = ffs_do_descs(ffs->ss_descs_count,
+ vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len,
+ d_raw_descs__sz - fs_len - hs_len,
+ __ffs_func_bind_do_descs, func);
if (unlikely(ret < 0))
goto error;
}
@@ -2094,7 +2440,8 @@ static int _ffs_func_bind(struct usb_configuration *c,
* now.
*/
ret = ffs_do_descs(ffs->fs_descs_count +
- (high ? ffs->hs_descs_count : 0),
+ (high ? ffs->hs_descs_count : 0) +
+ (super ? ffs->ss_descs_count : 0),
vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz,
__ffs_func_bind_do_nums, func);
if (unlikely(ret < 0))
@@ -2253,7 +2600,7 @@ static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)
static LIST_HEAD(ffs_devices);
-static struct ffs_dev *_ffs_find_dev(const char *name)
+static struct ffs_dev *_ffs_do_find_dev(const char *name)
{
struct ffs_dev *dev;
@@ -2270,7 +2617,7 @@ static struct ffs_dev *_ffs_find_dev(const char *name)
/*
* ffs_lock must be taken by the caller of this function
*/
-static struct ffs_dev *ffs_get_single_dev(void)
+static struct ffs_dev *_ffs_get_single_dev(void)
{
struct ffs_dev *dev;
@@ -2286,15 +2633,15 @@ static struct ffs_dev *ffs_get_single_dev(void)
/*
* ffs_lock must be taken by the caller of this function
*/
-static struct ffs_dev *ffs_find_dev(const char *name)
+static struct ffs_dev *_ffs_find_dev(const char *name)
{
struct ffs_dev *dev;
- dev = ffs_get_single_dev();
+ dev = _ffs_get_single_dev();
if (dev)
return dev;
- return _ffs_find_dev(name);
+ return _ffs_do_find_dev(name);
}
/* Configfs support *********************************************************/
@@ -2330,7 +2677,7 @@ static void ffs_free_inst(struct usb_function_instance *f)
opts = to_f_fs_opts(f);
ffs_dev_lock();
- ffs_free_dev(opts->dev);
+ _ffs_free_dev(opts->dev);
ffs_dev_unlock();
kfree(opts);
}
@@ -2385,7 +2732,7 @@ static struct usb_function_instance *ffs_alloc_inst(void)
opts->func_inst.set_inst_name = ffs_set_inst_name;
opts->func_inst.free_func_inst = ffs_free_inst;
ffs_dev_lock();
- dev = ffs_alloc_dev();
+ dev = _ffs_alloc_dev();
ffs_dev_unlock();
if (IS_ERR(dev)) {
kfree(opts);
@@ -2441,6 +2788,7 @@ static void ffs_func_unbind(struct usb_configuration *c,
*/
func->function.fs_descriptors = NULL;
func->function.hs_descriptors = NULL;
+ func->function.ss_descriptors = NULL;
func->interfaces_nums = NULL;
ffs_event_add(ffs, FUNCTIONFS_UNBIND);
@@ -2473,12 +2821,12 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
/*
* ffs_lock must be taken by the caller of this function
*/
-struct ffs_dev *ffs_alloc_dev(void)
+static struct ffs_dev *_ffs_alloc_dev(void)
{
struct ffs_dev *dev;
int ret;
- if (ffs_get_single_dev())
+ if (_ffs_get_single_dev())
return ERR_PTR(-EBUSY);
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -2506,10 +2854,10 @@ static int _ffs_name_dev(struct ffs_dev *dev, const char *name)
{
struct ffs_dev *existing;
- existing = _ffs_find_dev(name);
+ existing = _ffs_do_find_dev(name);
if (existing)
return -EBUSY;
-
+
dev->name = name;
return 0;
@@ -2550,7 +2898,7 @@ EXPORT_SYMBOL(ffs_single_dev);
/*
* ffs_lock must be taken by the caller of this function
*/
-void ffs_free_dev(struct ffs_dev *dev)
+static void _ffs_free_dev(struct ffs_dev *dev)
{
list_del(&dev->entry);
if (dev->name_allocated)
@@ -2567,7 +2915,7 @@ static void *ffs_acquire_dev(const char *dev_name)
ENTER();
ffs_dev_lock();
- ffs_dev = ffs_find_dev(dev_name);
+ ffs_dev = _ffs_find_dev(dev_name);
if (!ffs_dev)
ffs_dev = ERR_PTR(-ENODEV);
else if (ffs_dev->mounted)
@@ -2590,11 +2938,12 @@ static void ffs_release_dev(struct ffs_data *ffs_data)
ffs_dev_lock();
ffs_dev = ffs_data->private_data;
- if (ffs_dev)
+ if (ffs_dev) {
ffs_dev->mounted = false;
-
- if (ffs_dev->ffs_release_dev_callback)
- ffs_dev->ffs_release_dev_callback(ffs_dev);
+
+ if (ffs_dev->ffs_release_dev_callback)
+ ffs_dev->ffs_release_dev_callback(ffs_dev);
+ }
ffs_dev_unlock();
}
diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c
index 36d4bb23087f..807b31c0edc3 100644
--- a/drivers/usb/gadget/f_midi.c
+++ b/drivers/usb/gadget/f_midi.c
@@ -664,9 +664,10 @@ static int f_midi_register_card(struct f_midi *midi)
.dev_free = f_midi_snd_free,
};
- err = snd_card_create(midi->index, midi->id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&midi->gadget->dev, midi->index, midi->id,
+ THIS_MODULE, 0, &card);
if (err < 0) {
- ERROR(midi, "snd_card_create() failed\n");
+ ERROR(midi, "snd_card_new() failed\n");
goto fail;
}
midi->card = card;
@@ -703,8 +704,6 @@ static int f_midi_register_card(struct f_midi *midi)
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops);
- snd_card_set_dev(card, &midi->gadget->dev);
-
/* register it - we're ready to go */
err = snd_card_register(card);
if (err < 0) {
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index f1a59190ac9a..df4a0dcbc993 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -276,7 +276,7 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
}
net = gether_connect(&geth->port);
- return IS_ERR(net) ? PTR_ERR(net) : 0;
+ return PTR_RET(net);
}
static void geth_disable(struct usb_function *f)
diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c
index 2f23566e53d8..bc23040c7790 100644
--- a/drivers/usb/gadget/f_uac2.c
+++ b/drivers/usb/gadget/f_uac2.c
@@ -394,7 +394,7 @@ static int snd_uac2_probe(struct platform_device *pdev)
int err;
/* Choose any slot, with no id */
- err = snd_card_create(-1, NULL, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pdev->dev, -1, NULL, THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -421,8 +421,6 @@ static int snd_uac2_probe(struct platform_device *pdev)
strcpy(card->shortname, "UAC2_Gadget");
sprintf(card->longname, "UAC2_Gadget %i", pdev->id);
- snd_card_set_dev(card, &pdev->dev);
-
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX);
diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c
index 914cbd84ee40..f984ee75324d 100644
--- a/drivers/usb/gadget/gr_udc.c
+++ b/drivers/usb/gadget/gr_udc.c
@@ -225,14 +225,8 @@ static void gr_dfs_create(struct gr_udc *dev)
const char *name = "gr_udc_state";
dev->dfs_root = debugfs_create_dir(dev_name(dev->dev), NULL);
- if (IS_ERR(dev->dfs_root)) {
- dev_err(dev->dev, "Failed to create debugfs directory\n");
- return;
- }
- dev->dfs_state = debugfs_create_file(name, 0444, dev->dfs_root,
- dev, &gr_dfs_fops);
- if (IS_ERR(dev->dfs_state))
- dev_err(dev->dev, "Failed to create debugfs file %s\n", name);
+ dev->dfs_state = debugfs_create_file(name, 0444, dev->dfs_root, dev,
+ &gr_dfs_fops);
}
static void gr_dfs_delete(struct gr_udc *dev)
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index b94c049ab0d0..b5be6f0308c2 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -439,11 +439,9 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
/* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */
value = -ENOMEM;
- kbuf = kmalloc (len, GFP_KERNEL);
- if (!kbuf)
- goto free1;
- if (copy_from_user (kbuf, buf, len)) {
- value = -EFAULT;
+ kbuf = memdup_user(buf, len);
+ if (!kbuf) {
+ value = PTR_ERR(kbuf);
goto free1;
}
@@ -452,7 +450,6 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
data->name, len, (int) value);
free1:
mutex_unlock(&data->lock);
- kfree (kbuf);
return value;
}
diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c
index 049ebab0d360..a139894c600f 100644
--- a/drivers/usb/gadget/lpc32xx_udc.c
+++ b/drivers/usb/gadget/lpc32xx_udc.c
@@ -3295,9 +3295,9 @@ usb_clk_enable_fail:
pll_set_fail:
clk_disable(udc->usb_pll_clk);
pll_enable_fail:
- clk_put(udc->usb_slv_clk);
-usb_otg_clk_get_fail:
clk_put(udc->usb_otg_clk);
+usb_otg_clk_get_fail:
+ clk_put(udc->usb_slv_clk);
usb_clk_get_fail:
clk_put(udc->usb_pll_clk);
pll_get_fail:
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index bf7a56b6d48a..6474081dcbaf 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -427,12 +427,17 @@ setup_rx_reqs(struct printer_dev *dev)
req->length = USB_BUFSIZE;
req->complete = rx_complete;
+ /* here, we unlock, and only unlock, to avoid deadlock. */
+ spin_unlock(&dev->lock);
error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
+ spin_lock(&dev->lock);
if (error) {
DBG(dev, "rx submit --> %d\n", error);
list_add(&req->list, &dev->rx_reqs);
break;
- } else {
+ }
+ /* if the req is empty, then add it into dev->rx_reqs_active. */
+ else if (list_empty(&req->list)) {
list_add(&req->list, &dev->rx_reqs_active);
}
}
@@ -1133,6 +1138,7 @@ static int __init printer_bind_config(struct usb_configuration *c)
NULL, "g_printer");
if (IS_ERR(dev->pdev)) {
ERROR(dev, "Failed to create device: g_printer\n");
+ status = PTR_ERR(dev->pdev);
goto fail;
}
@@ -1157,7 +1163,7 @@ static int __init printer_bind_config(struct usb_configuration *c)
usb_gadget_set_selfpowered(gadget);
- if (gadget->is_otg) {
+ if (gadget_is_otg(gadget)) {
otg_descriptor.bmAttributes |= USB_OTG_HNP;
printer_cfg_driver.descriptors = otg_desc;
printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 1172eaeddd85..2a9cb674926a 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -617,7 +617,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
to_write = DIV_ROUND_UP(to_write, 4);
data = hs_req->req.buf + buf_pos;
- writesl(hsotg->regs + EPFIFO(hs_ep->index), data, to_write);
+ iowrite32_rep(hsotg->regs + EPFIFO(hs_ep->index), data, to_write);
return (to_write >= can_write) ? -ENOSPC : 0;
}
@@ -720,8 +720,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
ureq->length, ureq->actual);
if (0)
dev_dbg(hsotg->dev,
- "REQ buf %p len %d dma 0x%08x noi=%d zp=%d snok=%d\n",
- ureq->buf, length, ureq->dma,
+ "REQ buf %p len %d dma 0x%pad noi=%d zp=%d snok=%d\n",
+ ureq->buf, length, &ureq->dma,
ureq->no_interrupt, ureq->zero, ureq->short_not_ok);
maxreq = get_ep_limit(hs_ep);
@@ -789,8 +789,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index);
writel(ureq->dma, hsotg->regs + dma_reg);
- dev_dbg(hsotg->dev, "%s: 0x%08x => 0x%08x\n",
- __func__, ureq->dma, dma_reg);
+ dev_dbg(hsotg->dev, "%s: 0x%pad => 0x%08x\n",
+ __func__, &ureq->dma, dma_reg);
}
ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */
@@ -1186,6 +1186,41 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg);
static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg);
/**
+ * s3c_hsotg_stall_ep0 - stall ep0
+ * @hsotg: The device state
+ *
+ * Set stall for ep0 as response for setup request.
+ */
+static void s3c_hsotg_stall_ep0(struct s3c_hsotg *hsotg) {
+ struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
+ u32 reg;
+ u32 ctrl;
+
+ dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in);
+ reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0;
+
+ /*
+ * DxEPCTL_Stall will be cleared by EP once it has
+ * taken effect, so no need to clear later.
+ */
+
+ ctrl = readl(hsotg->regs + reg);
+ ctrl |= DxEPCTL_Stall;
+ ctrl |= DxEPCTL_CNAK;
+ writel(ctrl, hsotg->regs + reg);
+
+ dev_dbg(hsotg->dev,
+ "written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n",
+ ctrl, reg, readl(hsotg->regs + reg));
+
+ /*
+ * complete won't be called, so we enqueue
+ * setup request here
+ */
+ s3c_hsotg_enqueue_setup(hsotg);
+}
+
+/**
* s3c_hsotg_process_control - process a control request
* @hsotg: The device state
* @ctrl: The control request received
@@ -1262,38 +1297,8 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
* so respond with a STALL for the status stage to indicate failure.
*/
- if (ret < 0) {
- u32 reg;
- u32 ctrl;
-
- dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in);
- reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0;
-
- /*
- * DxEPCTL_Stall will be cleared by EP once it has
- * taken effect, so no need to clear later.
- */
-
- ctrl = readl(hsotg->regs + reg);
- ctrl |= DxEPCTL_Stall;
- ctrl |= DxEPCTL_CNAK;
- writel(ctrl, hsotg->regs + reg);
-
- dev_dbg(hsotg->dev,
- "written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n",
- ctrl, reg, readl(hsotg->regs + reg));
-
- /*
- * don't believe we need to anything more to get the EP
- * to reply with a STALL packet
- */
-
- /*
- * complete won't be called, so we enqueue
- * setup request here
- */
- s3c_hsotg_enqueue_setup(hsotg);
- }
+ if (ret < 0)
+ s3c_hsotg_stall_ep0(hsotg);
}
/**
@@ -1488,7 +1493,7 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
* note, we might over-write the buffer end by 3 bytes depending on
* alignment of the data.
*/
- readsl(fifo, hs_req->req.buf + read_ptr, to_read);
+ ioread32_rep(fifo, hs_req->req.buf + read_ptr, to_read);
}
/**
@@ -2832,6 +2837,15 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value);
+ if (index == 0) {
+ if (value)
+ s3c_hsotg_stall_ep0(hs);
+ else
+ dev_warn(hs->dev,
+ "%s: can't clear halt on ep0\n", __func__);
+ return 0;
+ }
+
/* write both IN and OUT control registers */
epreg = DIEPCTL(index);
@@ -3760,10 +3774,55 @@ static int s3c_hsotg_remove(struct platform_device *pdev)
return 0;
}
-#if 1
-#define s3c_hsotg_suspend NULL
-#define s3c_hsotg_resume NULL
-#endif
+static int s3c_hsotg_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
+ unsigned long flags;
+ int ret = 0;
+
+ if (hsotg->driver)
+ dev_info(hsotg->dev, "suspending usb gadget %s\n",
+ hsotg->driver->driver.name);
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ s3c_hsotg_disconnect(hsotg);
+ s3c_hsotg_phy_disable(hsotg);
+ hsotg->gadget.speed = USB_SPEED_UNKNOWN;
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+
+ if (hsotg->driver) {
+ int ep;
+ for (ep = 0; ep < hsotg->num_of_eps; ep++)
+ s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
+
+ ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
+ hsotg->supplies);
+ }
+
+ return ret;
+}
+
+static int s3c_hsotg_resume(struct platform_device *pdev)
+{
+ struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
+ unsigned long flags;
+ int ret = 0;
+
+ if (hsotg->driver) {
+ dev_info(hsotg->dev, "resuming usb gadget %s\n",
+ hsotg->driver->driver.name);
+ ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
+ hsotg->supplies);
+ }
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ hsotg->last_rst = jiffies;
+ s3c_hsotg_phy_enable(hsotg);
+ s3c_hsotg_core_init(hsotg);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+
+ return ret;
+}
#ifdef CONFIG_OF
static const struct of_device_id s3c_hsotg_of_ids[] = {
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index ea4bbfe72ec0..10c6a128250c 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -1344,7 +1344,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
return 0;
err_add_udc:
-err_add_device:
clk_disable(hsudc->uclk);
err_res:
if (!IS_ERR_OR_NULL(hsudc->transceiver))
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index f04b2c3154de..dd9678f85c58 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1629,7 +1629,7 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev)
ep->ep.desc = NULL;
ep->halted = 0;
INIT_LIST_HEAD(&ep->queue);
- usb_ep_set_maxpacket_limit(&ep->ep, &ep->ep.maxpacket);
+ usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket);
}
}
diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c
index 0f8aad78b54f..460c266b8e24 100644
--- a/drivers/usb/gadget/tcm_usb_gadget.c
+++ b/drivers/usb/gadget/tcm_usb_gadget.c
@@ -1613,7 +1613,7 @@ static struct se_wwn *usbg_make_tport(
return ERR_PTR(-ENOMEM);
}
tport->tport_wwpn = wwpn;
- snprintf(tport->tport_name, sizeof(tport->tport_name), wnn_name);
+ snprintf(tport->tport_name, sizeof(tport->tport_name), "%s", wnn_name);
return &tport->tport_wwn;
}
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index b7d4f82872b7..50d09c289137 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -48,6 +48,8 @@
#define UETH__VERSION "29-May-2008"
+#define GETHER_NAPI_WEIGHT 32
+
struct eth_dev {
/* lock is held while accessing port_usb
*/
@@ -72,6 +74,7 @@ struct eth_dev {
struct sk_buff_head *list);
struct work_struct work;
+ struct napi_struct rx_napi;
unsigned long todo;
#define WORK_RX_MEMORY 0
@@ -253,18 +256,16 @@ enomem:
DBG(dev, "rx submit --> %d\n", retval);
if (skb)
dev_kfree_skb_any(skb);
- spin_lock_irqsave(&dev->req_lock, flags);
- list_add(&req->list, &dev->rx_reqs);
- spin_unlock_irqrestore(&dev->req_lock, flags);
}
return retval;
}
static void rx_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct sk_buff *skb = req->context, *skb2;
+ struct sk_buff *skb = req->context;
struct eth_dev *dev = ep->driver_data;
int status = req->status;
+ bool rx_queue = 0;
switch (status) {
@@ -288,30 +289,8 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
} else {
skb_queue_tail(&dev->rx_frames, skb);
}
- skb = NULL;
-
- skb2 = skb_dequeue(&dev->rx_frames);
- while (skb2) {
- if (status < 0
- || ETH_HLEN > skb2->len
- || skb2->len > VLAN_ETH_FRAME_LEN) {
- dev->net->stats.rx_errors++;
- dev->net->stats.rx_length_errors++;
- DBG(dev, "rx length %d\n", skb2->len);
- dev_kfree_skb_any(skb2);
- goto next_frame;
- }
- skb2->protocol = eth_type_trans(skb2, dev->net);
- dev->net->stats.rx_packets++;
- dev->net->stats.rx_bytes += skb2->len;
-
- /* no buffer copies needed, unless hardware can't
- * use skb buffers.
- */
- status = netif_rx(skb2);
-next_frame:
- skb2 = skb_dequeue(&dev->rx_frames);
- }
+ if (!status)
+ rx_queue = 1;
break;
/* software-driven interface shutdown */
@@ -334,22 +313,20 @@ quiesce:
/* FALLTHROUGH */
default:
+ rx_queue = 1;
+ dev_kfree_skb_any(skb);
dev->net->stats.rx_errors++;
DBG(dev, "rx status %d\n", status);
break;
}
- if (skb)
- dev_kfree_skb_any(skb);
- if (!netif_running(dev->net)) {
clean:
spin_lock(&dev->req_lock);
list_add(&req->list, &dev->rx_reqs);
spin_unlock(&dev->req_lock);
- req = NULL;
- }
- if (req)
- rx_submit(dev, req, GFP_ATOMIC);
+
+ if (rx_queue && likely(napi_schedule_prep(&dev->rx_napi)))
+ __napi_schedule(&dev->rx_napi);
}
static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n)
@@ -414,16 +391,24 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
{
struct usb_request *req;
unsigned long flags;
+ int rx_counts = 0;
/* fill unused rxq slots with some skb */
spin_lock_irqsave(&dev->req_lock, flags);
while (!list_empty(&dev->rx_reqs)) {
+
+ if (++rx_counts > qlen(dev->gadget, dev->qmult))
+ break;
+
req = container_of(dev->rx_reqs.next,
struct usb_request, list);
list_del_init(&req->list);
spin_unlock_irqrestore(&dev->req_lock, flags);
if (rx_submit(dev, req, gfp_flags) < 0) {
+ spin_lock_irqsave(&dev->req_lock, flags);
+ list_add(&req->list, &dev->rx_reqs);
+ spin_unlock_irqrestore(&dev->req_lock, flags);
defer_kevent(dev, WORK_RX_MEMORY);
return;
}
@@ -433,6 +418,41 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
spin_unlock_irqrestore(&dev->req_lock, flags);
}
+static int gether_poll(struct napi_struct *napi, int budget)
+{
+ struct eth_dev *dev = container_of(napi, struct eth_dev, rx_napi);
+ struct sk_buff *skb;
+ unsigned int work_done = 0;
+ int status = 0;
+
+ while ((skb = skb_dequeue(&dev->rx_frames))) {
+ if (status < 0
+ || ETH_HLEN > skb->len
+ || skb->len > VLAN_ETH_FRAME_LEN) {
+ dev->net->stats.rx_errors++;
+ dev->net->stats.rx_length_errors++;
+ DBG(dev, "rx length %d\n", skb->len);
+ dev_kfree_skb_any(skb);
+ continue;
+ }
+ skb->protocol = eth_type_trans(skb, dev->net);
+ dev->net->stats.rx_packets++;
+ dev->net->stats.rx_bytes += skb->len;
+
+ status = netif_rx_ni(skb);
+ }
+
+ if (netif_running(dev->net)) {
+ rx_fill(dev, GFP_KERNEL);
+ work_done++;
+ }
+
+ if (work_done < budget)
+ napi_complete(&dev->rx_napi);
+
+ return work_done;
+}
+
static void eth_work(struct work_struct *work)
{
struct eth_dev *dev = container_of(work, struct eth_dev, work);
@@ -625,6 +645,7 @@ static void eth_start(struct eth_dev *dev, gfp_t gfp_flags)
/* and open the tx floodgates */
atomic_set(&dev->tx_qlen, 0);
netif_wake_queue(dev->net);
+ napi_enable(&dev->rx_napi);
}
static int eth_open(struct net_device *net)
@@ -651,6 +672,7 @@ static int eth_stop(struct net_device *net)
unsigned long flags;
VDBG(dev, "%s\n", __func__);
+ napi_disable(&dev->rx_napi);
netif_stop_queue(net);
DBG(dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
@@ -768,6 +790,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,
return ERR_PTR(-ENOMEM);
dev = netdev_priv(net);
+ netif_napi_add(net, &dev->rx_napi, gether_poll, GETHER_NAPI_WEIGHT);
spin_lock_init(&dev->lock);
spin_lock_init(&dev->req_lock);
INIT_WORK(&dev->work, eth_work);
@@ -830,6 +853,7 @@ struct net_device *gether_setup_name_default(const char *netname)
return ERR_PTR(-ENOMEM);
dev = netdev_priv(net);
+ netif_napi_add(net, &dev->rx_napi, gether_poll, GETHER_NAPI_WEIGHT);
spin_lock_init(&dev->lock);
spin_lock_init(&dev->req_lock);
INIT_WORK(&dev->work, eth_work);
@@ -1113,6 +1137,7 @@ void gether_disconnect(struct gether *link)
{
struct eth_dev *dev = link->ioport;
struct usb_request *req;
+ struct sk_buff *skb;
WARN_ON(!dev);
if (!dev)
@@ -1139,6 +1164,12 @@ void gether_disconnect(struct gether *link)
spin_lock(&dev->req_lock);
}
spin_unlock(&dev->req_lock);
+
+ spin_lock(&dev->rx_frames.lock);
+ while ((skb = __skb_dequeue(&dev->rx_frames)))
+ dev_kfree_skb_any(skb);
+ spin_unlock(&dev->rx_frames.lock);
+
link->in_ep->driver_data = NULL;
link->in_ep->desc = NULL;
diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h
index bc2d3718219b..bf0ba375d459 100644
--- a/drivers/usb/gadget/u_fs.h
+++ b/drivers/usb/gadget/u_fs.h
@@ -65,10 +65,8 @@ static inline void ffs_dev_unlock(void)
mutex_unlock(&ffs_lock);
}
-struct ffs_dev *ffs_alloc_dev(void);
int ffs_name_dev(struct ffs_dev *dev, const char *name);
int ffs_single_dev(struct ffs_dev *dev);
-void ffs_free_dev(struct ffs_dev *dev);
struct ffs_epfile;
struct ffs_function;
@@ -125,7 +123,7 @@ enum ffs_setup_state {
* setup. If this state is set read/write on ep0 return
* -EIDRM. This state is only set when adding event.
*/
- FFS_SETUP_CANCELED
+ FFS_SETUP_CANCELLED
};
struct ffs_data {
@@ -156,7 +154,6 @@ struct ffs_data {
*/
struct usb_request *ep0req; /* P: mutex */
struct completion ep0req_completion; /* P: mutex */
- int ep0req_status; /* P: mutex */
/* reference counter */
atomic_t ref;
@@ -168,19 +165,18 @@ struct ffs_data {
/*
* Possible transitions:
- * + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock
+ * + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock
* happens only in ep0 read which is P: mutex
- * + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock
+ * + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock
* happens only in ep0 i/o which is P: mutex
- * + FFS_SETUP_PENDING -> FFS_SETUP_CANCELED -- P: ev.waitq.lock
- * + FFS_SETUP_CANCELED -> FFS_NO_SETUP -- cmpxchg
+ * + FFS_SETUP_PENDING -> FFS_SETUP_CANCELLED -- P: ev.waitq.lock
+ * + FFS_SETUP_CANCELLED -> FFS_NO_SETUP -- cmpxchg
+ *
+ * This field should never be accessed directly and instead
+ * ffs_setup_state_clear_cancelled function should be used.
*/
enum ffs_setup_state setup_state;
-#define FFS_SETUP_STATE(ffs) \
- ((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state, \
- FFS_SETUP_CANCELED, FFS_NO_SETUP))
-
/* Events & such. */
struct {
u8 types[4];
@@ -210,16 +206,16 @@ struct ffs_data {
/* filled by __ffs_data_got_descs() */
/*
- * Real descriptors are 16 bytes after raw_descs (so you need
- * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the
- * first full speed descriptor). raw_descs_length and
- * raw_fs_descs_length do not have those 16 bytes added.
+ * raw_descs is what you kfree, real_descs points inside of raw_descs,
+ * where full speed, high speed and super speed descriptors start.
+ * real_descs_length is the length of all those descriptors.
*/
+ const void *raw_descs_data;
const void *raw_descs;
unsigned raw_descs_length;
- unsigned raw_fs_descs_length;
unsigned fs_descs_count;
unsigned hs_descs_count;
+ unsigned ss_descs_count;
unsigned short strings_count;
unsigned short interfaces_count;
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index b369292d4b90..ad0aca812002 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -549,8 +549,8 @@ static void gs_rx_push(unsigned long _port)
port->read_started--;
}
- /* Push from tty to ldisc; without low_latency set this is handled by
- * a workqueue, so we won't get callbacks and can hold port_lock
+ /* Push from tty to ldisc; this is handled by a workqueue,
+ * so we won't get callbacks and can hold port_lock
*/
if (do_push)
tty_flip_buffer_push(&port->port);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index c8b4161613cf..3d9e54062d62 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -581,7 +581,6 @@ config FHCI_DEBUG
config USB_U132_HCD
tristate "Elan U132 Adapter Host Controller"
depends on USB_FTDI_ELAN
- default M
help
The U132 adapter is a USB to CardBus adapter specifically designed
for PC cards that contain an OHCI host controller. Typical PC cards
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 471142725ffe..81cda09b47e3 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -685,8 +685,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 status, masked_status, pcd_status = 0, cmd;
int bh;
+ unsigned long flags;
- spin_lock (&ehci->lock);
+ /*
+ * For threadirqs option we use spin_lock_irqsave() variant to prevent
+ * deadlock with ehci hrtimer callback, because hrtimer callbacks run
+ * in interrupt context even when threadirqs is specified. We can go
+ * back to spin_lock() variant when hrtimer callbacks become threaded.
+ */
+ spin_lock_irqsave(&ehci->lock, flags);
status = ehci_readl(ehci, &ehci->regs->status);
@@ -704,7 +711,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* Shared IRQ? */
if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) {
- spin_unlock(&ehci->lock);
+ spin_unlock_irqrestore(&ehci->lock, flags);
return IRQ_NONE;
}
@@ -815,7 +822,7 @@ dead:
if (bh)
ehci_work (ehci);
- spin_unlock (&ehci->lock);
+ spin_unlock_irqrestore(&ehci->lock, flags);
if (pcd_status)
usb_hcd_poll_rh_status(hcd);
return IRQ_HANDLED;
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 47b858fc50b2..7ae0c4d51741 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -238,6 +238,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
int port;
int mask;
int changed;
+ bool fs_idle_delay;
ehci_dbg(ehci, "suspend root hub\n");
@@ -272,6 +273,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci->bus_suspended = 0;
ehci->owned_ports = 0;
changed = 0;
+ fs_idle_delay = false;
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
u32 __iomem *reg = &ehci->regs->port_status [port];
@@ -300,16 +302,32 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
}
if (t1 != t2) {
+ /*
+ * On some controllers, Wake-On-Disconnect will
+ * generate false wakeup signals until the bus
+ * switches over to full-speed idle. For their
+ * sake, add a delay if we need one.
+ */
+ if ((t2 & PORT_WKDISC_E) &&
+ ehci_port_speed(ehci, t2) ==
+ USB_PORT_STAT_HIGH_SPEED)
+ fs_idle_delay = true;
ehci_writel(ehci, t2, reg);
changed = 1;
}
}
+ spin_unlock_irq(&ehci->lock);
+
+ if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) {
+ /*
+ * Wait for HCD to enter low-power mode or for the bus
+ * to switch to full-speed idle.
+ */
+ usleep_range(5000, 5500);
+ }
if (changed && ehci->has_tdi_phy_lpm) {
- spin_unlock_irq(&ehci->lock);
- msleep(5); /* 5 ms for HCD to enter low-power mode */
spin_lock_irq(&ehci->lock);
-
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port];
@@ -322,8 +340,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
port, (t3 & HOSTPC_PHCD) ?
"succeeded" : "failed");
}
+ spin_unlock_irq(&ehci->lock);
}
- spin_unlock_irq(&ehci->lock);
/* Apparently some devices need a >= 1-uframe delay here */
if (ehci->bus_suspended)
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 01536cfd361d..b3a0e11073aa 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -3,6 +3,7 @@
*
* Copyright 2007 Steven Brown <sbrown@cortland.com>
* Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
*
* Derived from the ohci-ssb driver
* Copyright 2007 Michael Buesch <m@bues.ch>
@@ -18,6 +19,7 @@
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
+#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/kernel.h>
@@ -25,6 +27,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
@@ -33,6 +36,13 @@
#include "ehci.h"
#define DRIVER_DESC "EHCI generic platform driver"
+#define EHCI_MAX_CLKS 3
+#define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
+
+struct ehci_platform_priv {
+ struct clk *clks[EHCI_MAX_CLKS];
+ struct phy *phy;
+};
static const char hcd_name[] = "ehci-platform";
@@ -45,8 +55,6 @@ static int ehci_platform_reset(struct usb_hcd *hcd)
hcd->has_tt = pdata->has_tt;
ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
- ehci->big_endian_desc = pdata->big_endian_desc;
- ehci->big_endian_mmio = pdata->big_endian_mmio;
if (pdata->pre_setup) {
retval = pdata->pre_setup(hcd);
@@ -64,38 +72,91 @@ static int ehci_platform_reset(struct usb_hcd *hcd)
return 0;
}
+static int ehci_platform_power_on(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
+ int clk, ret;
+
+ for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
+ ret = clk_prepare_enable(priv->clks[clk]);
+ if (ret)
+ goto err_disable_clks;
+ }
+
+ if (priv->phy) {
+ ret = phy_init(priv->phy);
+ if (ret)
+ goto err_disable_clks;
+
+ ret = phy_power_on(priv->phy);
+ if (ret)
+ goto err_exit_phy;
+ }
+
+ return 0;
+
+err_exit_phy:
+ phy_exit(priv->phy);
+err_disable_clks:
+ while (--clk >= 0)
+ clk_disable_unprepare(priv->clks[clk]);
+
+ return ret;
+}
+
+static void ehci_platform_power_off(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
+ int clk;
+
+ if (priv->phy) {
+ phy_power_off(priv->phy);
+ phy_exit(priv->phy);
+ }
+
+ for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
+ if (priv->clks[clk])
+ clk_disable_unprepare(priv->clks[clk]);
+}
+
static struct hc_driver __read_mostly ehci_platform_hc_driver;
static const struct ehci_driver_overrides platform_overrides __initconst = {
- .reset = ehci_platform_reset,
+ .reset = ehci_platform_reset,
+ .extra_priv_size = sizeof(struct ehci_platform_priv),
};
-static struct usb_ehci_pdata ehci_platform_defaults;
+static struct usb_ehci_pdata ehci_platform_defaults = {
+ .power_on = ehci_platform_power_on,
+ .power_suspend = ehci_platform_power_off,
+ .power_off = ehci_platform_power_off,
+};
static int ehci_platform_probe(struct platform_device *dev)
{
struct usb_hcd *hcd;
struct resource *res_mem;
- struct usb_ehci_pdata *pdata;
- int irq;
- int err;
+ struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
+ struct ehci_platform_priv *priv;
+ struct ehci_hcd *ehci;
+ int err, irq, clk = 0;
if (usb_disabled())
return -ENODEV;
/*
- * use reasonable defaults so platforms don't have to provide these.
- * with DT probing on ARM, none of these are set.
+ * Use reasonable defaults so platforms don't have to provide these
+ * with DT probing on ARM.
*/
- if (!dev_get_platdata(&dev->dev))
- dev->dev.platform_data = &ehci_platform_defaults;
+ if (!pdata)
+ pdata = &ehci_platform_defaults;
err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
if (err)
return err;
- pdata = dev_get_platdata(&dev->dev);
-
irq = platform_get_irq(dev, 0);
if (irq < 0) {
dev_err(&dev->dev, "no irq provided");
@@ -107,17 +168,72 @@ static int ehci_platform_probe(struct platform_device *dev)
return -ENXIO;
}
+ hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
+ dev_name(&dev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ platform_set_drvdata(dev, hcd);
+ dev->dev.platform_data = pdata;
+ priv = hcd_to_ehci_priv(hcd);
+ ehci = hcd_to_ehci(hcd);
+
+ if (pdata == &ehci_platform_defaults && dev->dev.of_node) {
+ if (of_property_read_bool(dev->dev.of_node, "big-endian-regs"))
+ ehci->big_endian_mmio = 1;
+
+ if (of_property_read_bool(dev->dev.of_node, "big-endian-desc"))
+ ehci->big_endian_desc = 1;
+
+ if (of_property_read_bool(dev->dev.of_node, "big-endian"))
+ ehci->big_endian_mmio = ehci->big_endian_desc = 1;
+
+ priv->phy = devm_phy_get(&dev->dev, "usb");
+ if (IS_ERR(priv->phy)) {
+ err = PTR_ERR(priv->phy);
+ if (err == -EPROBE_DEFER)
+ goto err_put_hcd;
+ priv->phy = NULL;
+ }
+
+ for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
+ priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
+ if (IS_ERR(priv->clks[clk])) {
+ err = PTR_ERR(priv->clks[clk]);
+ if (err == -EPROBE_DEFER)
+ goto err_put_clks;
+ priv->clks[clk] = NULL;
+ break;
+ }
+ }
+ }
+
+ if (pdata->big_endian_desc)
+ ehci->big_endian_desc = 1;
+ if (pdata->big_endian_mmio)
+ ehci->big_endian_mmio = 1;
+
+#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ if (ehci->big_endian_mmio) {
+ dev_err(&dev->dev,
+ "Error: CONFIG_USB_EHCI_BIG_ENDIAN_MMIO not set\n");
+ err = -EINVAL;
+ goto err_put_clks;
+ }
+#endif
+#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
+ if (ehci->big_endian_desc) {
+ dev_err(&dev->dev,
+ "Error: CONFIG_USB_EHCI_BIG_ENDIAN_DESC not set\n");
+ err = -EINVAL;
+ goto err_put_clks;
+ }
+#endif
+
if (pdata->power_on) {
err = pdata->power_on(dev);
if (err < 0)
- return err;
- }
-
- hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
- dev_name(&dev->dev));
- if (!hcd) {
- err = -ENOMEM;
- goto err_power;
+ goto err_put_clks;
}
hcd->rsrc_start = res_mem->start;
@@ -126,22 +242,28 @@ static int ehci_platform_probe(struct platform_device *dev)
hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
- goto err_put_hcd;
+ goto err_power;
}
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err)
- goto err_put_hcd;
+ goto err_power;
device_wakeup_enable(hcd->self.controller);
platform_set_drvdata(dev, hcd);
return err;
-err_put_hcd:
- usb_put_hcd(hcd);
err_power:
if (pdata->power_off)
pdata->power_off(dev);
+err_put_clks:
+ while (--clk >= 0)
+ clk_put(priv->clks[clk]);
+err_put_hcd:
+ if (pdata == &ehci_platform_defaults)
+ dev->dev.platform_data = NULL;
+
+ usb_put_hcd(hcd);
return err;
}
@@ -150,13 +272,19 @@ static int ehci_platform_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
+ struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
+ int clk;
usb_remove_hcd(hcd);
- usb_put_hcd(hcd);
if (pdata->power_off)
pdata->power_off(dev);
+ for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++)
+ clk_put(priv->clks[clk]);
+
+ usb_put_hcd(hcd);
+
if (pdata == &ehci_platform_defaults)
dev->dev.platform_data = NULL;
@@ -207,8 +335,10 @@ static int ehci_platform_resume(struct device *dev)
static const struct of_device_id vt8500_ehci_ids[] = {
{ .compatible = "via,vt8500-ehci", },
{ .compatible = "wm,prizm-ehci", },
+ { .compatible = "generic-ehci", },
{}
};
+MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
static const struct platform_device_id ehci_platform_table[] = {
{ "ehci-platform", 0 },
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index af28b748e87a..27ac6ad53c3d 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -38,10 +38,6 @@
#include "ehci.h"
-#define TEGRA_USB_BASE 0xC5000000
-#define TEGRA_USB2_BASE 0xC5004000
-#define TEGRA_USB3_BASE 0xC5008000
-
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
#define TEGRA_USB_DMA_ALIGN 32
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c
index e07669993f58..d0d8fadf7066 100644
--- a/drivers/usb/host/hwa-hc.c
+++ b/drivers/usb/host/hwa-hc.c
@@ -261,8 +261,44 @@ static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc)
dev_err(dev, "cannot listen to notifications: %d\n", result);
goto error_stop;
}
+ /*
+ * If WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS is set,
+ * disable transfer notifications.
+ */
+ if (hwahc->wa.quirks &
+ WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS) {
+ struct usb_host_interface *cur_altsetting =
+ hwahc->wa.usb_iface->cur_altsetting;
+
+ result = usb_control_msg(hwahc->wa.usb_dev,
+ usb_sndctrlpipe(hwahc->wa.usb_dev, 0),
+ WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_INTERFACE,
+ WA_REQ_ALEREON_FEATURE_SET,
+ cur_altsetting->desc.bInterfaceNumber,
+ NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ /*
+ * If we successfully sent the control message, start DTI here
+ * because no transfer notifications will be received which is
+ * where DTI is normally started.
+ */
+ if (result == 0)
+ result = wa_dti_start(&hwahc->wa);
+ else
+ result = 0; /* OK. Continue normally. */
+
+ if (result < 0) {
+ dev_err(dev, "cannot start DTI: %d\n", result);
+ goto error_dti_start;
+ }
+ }
+
return result;
+error_dti_start:
+ wa_nep_disarm(&hwahc->wa);
error_stop:
__wa_clear_feature(&hwahc->wa, WA_ENABLE);
return result;
@@ -827,10 +863,12 @@ static void hwahc_disconnect(struct usb_interface *usb_iface)
static struct usb_device_id hwahc_id_table[] = {
/* Alereon 5310 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x02, 0x01),
- .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC },
+ .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC |
+ WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS },
/* Alereon 5611 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x02, 0x01),
- .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC },
+ .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC |
+ WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS },
/* FIXME: use class labels for this */
{ USB_INTERFACE_INFO(0xe0, 0x02, 0x01), },
{},
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index 68f674cd095f..b6002c951c5c 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -3,6 +3,7 @@
*
* Copyright 2007 Michael Buesch <m@bues.ch>
* Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
*
* Derived from the OCHI-SSB driver
* Derived from the OHCI-PCI driver
@@ -14,11 +15,14 @@
* Licensed under the GNU/GPL. See COPYING for details.
*/
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
#include <linux/hrtimer.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
+#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/usb/ohci_pdriver.h>
#include <linux/usb.h>
@@ -27,6 +31,13 @@
#include "ohci.h"
#define DRIVER_DESC "OHCI generic platform driver"
+#define OHCI_MAX_CLKS 3
+#define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv)
+
+struct ohci_platform_priv {
+ struct clk *clks[OHCI_MAX_CLKS];
+ struct phy *phy;
+};
static const char hcd_name[] = "ohci-platform";
@@ -36,10 +47,6 @@ static int ohci_platform_reset(struct usb_hcd *hcd)
struct usb_ohci_pdata *pdata = dev_get_platdata(&pdev->dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
- if (pdata->big_endian_desc)
- ohci->flags |= OHCI_QUIRK_BE_DESC;
- if (pdata->big_endian_mmio)
- ohci->flags |= OHCI_QUIRK_BE_MMIO;
if (pdata->no_big_frame_no)
ohci->flags |= OHCI_QUIRK_FRAME_NO;
if (pdata->num_ports)
@@ -48,11 +55,67 @@ static int ohci_platform_reset(struct usb_hcd *hcd)
return ohci_setup(hcd);
}
+static int ohci_platform_power_on(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
+ int clk, ret;
+
+ for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) {
+ ret = clk_prepare_enable(priv->clks[clk]);
+ if (ret)
+ goto err_disable_clks;
+ }
+
+ if (priv->phy) {
+ ret = phy_init(priv->phy);
+ if (ret)
+ goto err_disable_clks;
+
+ ret = phy_power_on(priv->phy);
+ if (ret)
+ goto err_exit_phy;
+ }
+
+ return 0;
+
+err_exit_phy:
+ phy_exit(priv->phy);
+err_disable_clks:
+ while (--clk >= 0)
+ clk_disable_unprepare(priv->clks[clk]);
+
+ return ret;
+}
+
+static void ohci_platform_power_off(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
+ int clk;
+
+ if (priv->phy) {
+ phy_power_off(priv->phy);
+ phy_exit(priv->phy);
+ }
+
+ for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
+ if (priv->clks[clk])
+ clk_disable_unprepare(priv->clks[clk]);
+}
+
static struct hc_driver __read_mostly ohci_platform_hc_driver;
static const struct ohci_driver_overrides platform_overrides __initconst = {
- .product_desc = "Generic Platform OHCI controller",
- .reset = ohci_platform_reset,
+ .product_desc = "Generic Platform OHCI controller",
+ .reset = ohci_platform_reset,
+ .extra_priv_size = sizeof(struct ohci_platform_priv),
+};
+
+static struct usb_ohci_pdata ohci_platform_defaults = {
+ .power_on = ohci_platform_power_on,
+ .power_suspend = ohci_platform_power_off,
+ .power_off = ohci_platform_power_off,
};
static int ohci_platform_probe(struct platform_device *dev)
@@ -60,17 +123,24 @@ static int ohci_platform_probe(struct platform_device *dev)
struct usb_hcd *hcd;
struct resource *res_mem;
struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
- int irq;
- int err = -ENOMEM;
-
- if (!pdata) {
- WARN_ON(1);
- return -ENODEV;
- }
+ struct ohci_platform_priv *priv;
+ struct ohci_hcd *ohci;
+ int err, irq, clk = 0;
if (usb_disabled())
return -ENODEV;
+ /*
+ * Use reasonable defaults so platforms don't have to provide these
+ * with DT probing on ARM.
+ */
+ if (!pdata)
+ pdata = &ohci_platform_defaults;
+
+ err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
+ if (err)
+ return err;
+
irq = platform_get_irq(dev, 0);
if (irq < 0) {
dev_err(&dev->dev, "no irq provided");
@@ -83,17 +153,72 @@ static int ohci_platform_probe(struct platform_device *dev)
return -ENXIO;
}
+ hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
+ dev_name(&dev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ platform_set_drvdata(dev, hcd);
+ dev->dev.platform_data = pdata;
+ priv = hcd_to_ohci_priv(hcd);
+ ohci = hcd_to_ohci(hcd);
+
+ if (pdata == &ohci_platform_defaults && dev->dev.of_node) {
+ if (of_property_read_bool(dev->dev.of_node, "big-endian-regs"))
+ ohci->flags |= OHCI_QUIRK_BE_MMIO;
+
+ if (of_property_read_bool(dev->dev.of_node, "big-endian-desc"))
+ ohci->flags |= OHCI_QUIRK_BE_DESC;
+
+ if (of_property_read_bool(dev->dev.of_node, "big-endian"))
+ ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+ priv->phy = devm_phy_get(&dev->dev, "usb");
+ if (IS_ERR(priv->phy)) {
+ err = PTR_ERR(priv->phy);
+ if (err == -EPROBE_DEFER)
+ goto err_put_hcd;
+ priv->phy = NULL;
+ }
+
+ for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {
+ priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
+ if (IS_ERR(priv->clks[clk])) {
+ err = PTR_ERR(priv->clks[clk]);
+ if (err == -EPROBE_DEFER)
+ goto err_put_clks;
+ priv->clks[clk] = NULL;
+ break;
+ }
+ }
+ }
+
+ if (pdata->big_endian_desc)
+ ohci->flags |= OHCI_QUIRK_BE_DESC;
+ if (pdata->big_endian_mmio)
+ ohci->flags |= OHCI_QUIRK_BE_MMIO;
+
+#ifndef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ if (ohci->flags & OHCI_QUIRK_BE_MMIO) {
+ dev_err(&dev->dev,
+ "Error: CONFIG_USB_OHCI_BIG_ENDIAN_MMIO not set\n");
+ err = -EINVAL;
+ goto err_put_clks;
+ }
+#endif
+#ifndef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
+ if (ohci->flags & OHCI_QUIRK_BE_DESC) {
+ dev_err(&dev->dev,
+ "Error: CONFIG_USB_OHCI_BIG_ENDIAN_DESC not set\n");
+ err = -EINVAL;
+ goto err_put_clks;
+ }
+#endif
+
if (pdata->power_on) {
err = pdata->power_on(dev);
if (err < 0)
- return err;
- }
-
- hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
- dev_name(&dev->dev));
- if (!hcd) {
- err = -ENOMEM;
- goto err_power;
+ goto err_put_clks;
}
hcd->rsrc_start = res_mem->start;
@@ -102,11 +227,11 @@ static int ohci_platform_probe(struct platform_device *dev)
hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
- goto err_put_hcd;
+ goto err_power;
}
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err)
- goto err_put_hcd;
+ goto err_power;
device_wakeup_enable(hcd->self.controller);
@@ -114,11 +239,17 @@ static int ohci_platform_probe(struct platform_device *dev)
return err;
-err_put_hcd:
- usb_put_hcd(hcd);
err_power:
if (pdata->power_off)
pdata->power_off(dev);
+err_put_clks:
+ while (--clk >= 0)
+ clk_put(priv->clks[clk]);
+err_put_hcd:
+ if (pdata == &ohci_platform_defaults)
+ dev->dev.platform_data = NULL;
+
+ usb_put_hcd(hcd);
return err;
}
@@ -127,13 +258,22 @@ static int ohci_platform_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
+ struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
+ int clk;
usb_remove_hcd(hcd);
- usb_put_hcd(hcd);
if (pdata->power_off)
pdata->power_off(dev);
+ for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++)
+ clk_put(priv->clks[clk]);
+
+ usb_put_hcd(hcd);
+
+ if (pdata == &ohci_platform_defaults)
+ dev->dev.platform_data = NULL;
+
return 0;
}
@@ -180,6 +320,12 @@ static int ohci_platform_resume(struct device *dev)
#define ohci_platform_resume NULL
#endif /* CONFIG_PM */
+static const struct of_device_id ohci_platform_ids[] = {
+ { .compatible = "generic-ohci", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ohci_platform_ids);
+
static const struct platform_device_id ohci_platform_table[] = {
{ "ohci-platform", 0 },
{ }
@@ -200,6 +346,7 @@ static struct platform_driver ohci_platform_driver = {
.owner = THIS_MODULE,
.name = "ohci-platform",
.pm = &ohci_platform_pm_ops,
+ .of_match_table = ohci_platform_ids,
}
};
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
index 44e6c9da8892..01833ab2b5c3 100644
--- a/drivers/usb/host/uhci-platform.c
+++ b/drivers/usb/host/uhci-platform.c
@@ -148,6 +148,7 @@ static void uhci_hcd_platform_shutdown(struct platform_device *op)
}
static const struct of_device_id platform_uhci_ids[] = {
+ { .compatible = "generic-uhci", },
{ .compatible = "platform-uhci", },
{}
};
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 9992fbfec85f..1ad6bc1951c7 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -732,9 +732,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
/* Set the U1 and U2 exit latencies. */
memcpy(buf, &usb_bos_descriptor,
USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE);
- temp = readl(&xhci->cap_regs->hcs_params3);
- buf[12] = HCS_U1_LATENCY(temp);
- put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]);
+ if ((xhci->quirks & XHCI_LPM_SUPPORT)) {
+ temp = readl(&xhci->cap_regs->hcs_params3);
+ buf[12] = HCS_U1_LATENCY(temp);
+ put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]);
+ }
/* Indicate whether the host has LTM support. */
temp = readl(&xhci->cap_regs->hcc_params);
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index bce4391a0e7d..c089668308ad 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -149,14 +149,140 @@ static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring,
}
}
+/*
+ * We need a radix tree for mapping physical addresses of TRBs to which stream
+ * ID they belong to. We need to do this because the host controller won't tell
+ * us which stream ring the TRB came from. We could store the stream ID in an
+ * event data TRB, but that doesn't help us for the cancellation case, since the
+ * endpoint may stop before it reaches that event data TRB.
+ *
+ * The radix tree maps the upper portion of the TRB DMA address to a ring
+ * segment that has the same upper portion of DMA addresses. For example, say I
+ * have segments of size 1KB, that are always 1KB aligned. A segment may
+ * start at 0x10c91000 and end at 0x10c913f0. If I use the upper 10 bits, the
+ * key to the stream ID is 0x43244. I can use the DMA address of the TRB to
+ * pass the radix tree a key to get the right stream ID:
+ *
+ * 0x10c90fff >> 10 = 0x43243
+ * 0x10c912c0 >> 10 = 0x43244
+ * 0x10c91400 >> 10 = 0x43245
+ *
+ * Obviously, only those TRBs with DMA addresses that are within the segment
+ * will make the radix tree return the stream ID for that ring.
+ *
+ * Caveats for the radix tree:
+ *
+ * The radix tree uses an unsigned long as a key pair. On 32-bit systems, an
+ * unsigned long will be 32-bits; on a 64-bit system an unsigned long will be
+ * 64-bits. Since we only request 32-bit DMA addresses, we can use that as the
+ * key on 32-bit or 64-bit systems (it would also be fine if we asked for 64-bit
+ * PCI DMA addresses on a 64-bit system). There might be a problem on 32-bit
+ * extended systems (where the DMA address can be bigger than 32-bits),
+ * if we allow the PCI dma mask to be bigger than 32-bits. So don't do that.
+ */
+static int xhci_insert_segment_mapping(struct radix_tree_root *trb_address_map,
+ struct xhci_ring *ring,
+ struct xhci_segment *seg,
+ gfp_t mem_flags)
+{
+ unsigned long key;
+ int ret;
+
+ key = (unsigned long)(seg->dma >> TRB_SEGMENT_SHIFT);
+ /* Skip any segments that were already added. */
+ if (radix_tree_lookup(trb_address_map, key))
+ return 0;
+
+ ret = radix_tree_maybe_preload(mem_flags);
+ if (ret)
+ return ret;
+ ret = radix_tree_insert(trb_address_map,
+ key, ring);
+ radix_tree_preload_end();
+ return ret;
+}
+
+static void xhci_remove_segment_mapping(struct radix_tree_root *trb_address_map,
+ struct xhci_segment *seg)
+{
+ unsigned long key;
+
+ key = (unsigned long)(seg->dma >> TRB_SEGMENT_SHIFT);
+ if (radix_tree_lookup(trb_address_map, key))
+ radix_tree_delete(trb_address_map, key);
+}
+
+static int xhci_update_stream_segment_mapping(
+ struct radix_tree_root *trb_address_map,
+ struct xhci_ring *ring,
+ struct xhci_segment *first_seg,
+ struct xhci_segment *last_seg,
+ gfp_t mem_flags)
+{
+ struct xhci_segment *seg;
+ struct xhci_segment *failed_seg;
+ int ret;
+
+ if (WARN_ON_ONCE(trb_address_map == NULL))
+ return 0;
+
+ seg = first_seg;
+ do {
+ ret = xhci_insert_segment_mapping(trb_address_map,
+ ring, seg, mem_flags);
+ if (ret)
+ goto remove_streams;
+ if (seg == last_seg)
+ return 0;
+ seg = seg->next;
+ } while (seg != first_seg);
+
+ return 0;
+
+remove_streams:
+ failed_seg = seg;
+ seg = first_seg;
+ do {
+ xhci_remove_segment_mapping(trb_address_map, seg);
+ if (seg == failed_seg)
+ return ret;
+ seg = seg->next;
+ } while (seg != first_seg);
+
+ return ret;
+}
+
+static void xhci_remove_stream_mapping(struct xhci_ring *ring)
+{
+ struct xhci_segment *seg;
+
+ if (WARN_ON_ONCE(ring->trb_address_map == NULL))
+ return;
+
+ seg = ring->first_seg;
+ do {
+ xhci_remove_segment_mapping(ring->trb_address_map, seg);
+ seg = seg->next;
+ } while (seg != ring->first_seg);
+}
+
+static int xhci_update_stream_mapping(struct xhci_ring *ring, gfp_t mem_flags)
+{
+ return xhci_update_stream_segment_mapping(ring->trb_address_map, ring,
+ ring->first_seg, ring->last_seg, mem_flags);
+}
+
/* XXX: Do we need the hcd structure in all these functions? */
void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
{
if (!ring)
return;
- if (ring->first_seg)
+ if (ring->first_seg) {
+ if (ring->type == TYPE_STREAM)
+ xhci_remove_stream_mapping(ring);
xhci_free_segments_for_ring(xhci, ring->first_seg);
+ }
kfree(ring);
}
@@ -349,6 +475,21 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
if (ret)
return -ENOMEM;
+ if (ring->type == TYPE_STREAM)
+ ret = xhci_update_stream_segment_mapping(ring->trb_address_map,
+ ring, first, last, flags);
+ if (ret) {
+ struct xhci_segment *next;
+ do {
+ next = first->next;
+ xhci_segment_free(xhci, first);
+ if (first == last)
+ break;
+ first = next;
+ } while (true);
+ return ret;
+ }
+
xhci_link_rings(xhci, ring, first, last, num_segs);
xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion,
"ring expansion succeed, now has %d segments",
@@ -434,12 +575,12 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci,
struct xhci_stream_ctx *stream_ctx, dma_addr_t dma)
{
struct device *dev = xhci_to_hcd(xhci)->self.controller;
+ size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs;
- if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE)
- dma_free_coherent(dev,
- sizeof(struct xhci_stream_ctx)*num_stream_ctxs,
+ if (size > MEDIUM_STREAM_ARRAY_SIZE)
+ dma_free_coherent(dev, size,
stream_ctx, dma);
- else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE)
+ else if (size <= SMALL_STREAM_ARRAY_SIZE)
return dma_pool_free(xhci->small_streams_pool,
stream_ctx, dma);
else
@@ -462,12 +603,12 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,
gfp_t mem_flags)
{
struct device *dev = xhci_to_hcd(xhci)->self.controller;
+ size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs;
- if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE)
- return dma_alloc_coherent(dev,
- sizeof(struct xhci_stream_ctx)*num_stream_ctxs,
+ if (size > MEDIUM_STREAM_ARRAY_SIZE)
+ return dma_alloc_coherent(dev, size,
dma, mem_flags);
- else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE)
+ else if (size <= SMALL_STREAM_ARRAY_SIZE)
return dma_pool_alloc(xhci->small_streams_pool,
mem_flags, dma);
else
@@ -510,36 +651,6 @@ struct xhci_ring *xhci_stream_id_to_ring(
* The number of stream contexts in the stream context array may be bigger than
* the number of streams the driver wants to use. This is because the number of
* stream context array entries must be a power of two.
- *
- * We need a radix tree for mapping physical addresses of TRBs to which stream
- * ID they belong to. We need to do this because the host controller won't tell
- * us which stream ring the TRB came from. We could store the stream ID in an
- * event data TRB, but that doesn't help us for the cancellation case, since the
- * endpoint may stop before it reaches that event data TRB.
- *
- * The radix tree maps the upper portion of the TRB DMA address to a ring
- * segment that has the same upper portion of DMA addresses. For example, say I
- * have segments of size 1KB, that are always 64-byte aligned. A segment may
- * start at 0x10c91000 and end at 0x10c913f0. If I use the upper 10 bits, the
- * key to the stream ID is 0x43244. I can use the DMA address of the TRB to
- * pass the radix tree a key to get the right stream ID:
- *
- * 0x10c90fff >> 10 = 0x43243
- * 0x10c912c0 >> 10 = 0x43244
- * 0x10c91400 >> 10 = 0x43245
- *
- * Obviously, only those TRBs with DMA addresses that are within the segment
- * will make the radix tree return the stream ID for that ring.
- *
- * Caveats for the radix tree:
- *
- * The radix tree uses an unsigned long as a key pair. On 32-bit systems, an
- * unsigned long will be 32-bits; on a 64-bit system an unsigned long will be
- * 64-bits. Since we only request 32-bit DMA addresses, we can use that as the
- * key on 32-bit or 64-bit systems (it would also be fine if we asked for 64-bit
- * PCI DMA addresses on a 64-bit system). There might be a problem on 32-bit
- * extended systems (where the DMA address can be bigger than 32-bits),
- * if we allow the PCI dma mask to be bigger than 32-bits. So don't do that.
*/
struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
unsigned int num_stream_ctxs,
@@ -548,7 +659,6 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
struct xhci_stream_info *stream_info;
u32 cur_stream;
struct xhci_ring *cur_ring;
- unsigned long key;
u64 addr;
int ret;
@@ -603,6 +713,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
if (!cur_ring)
goto cleanup_rings;
cur_ring->stream_id = cur_stream;
+ cur_ring->trb_address_map = &stream_info->trb_address_map;
/* Set deq ptr, cycle bit, and stream context type */
addr = cur_ring->first_seg->dma |
SCT_FOR_CTX(SCT_PRI_TR) |
@@ -612,10 +723,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n",
cur_stream, (unsigned long long) addr);
- key = (unsigned long)
- (cur_ring->first_seg->dma >> TRB_SEGMENT_SHIFT);
- ret = radix_tree_insert(&stream_info->trb_address_map,
- key, cur_ring);
+ ret = xhci_update_stream_mapping(cur_ring, mem_flags);
if (ret) {
xhci_ring_free(xhci, cur_ring);
stream_info->stream_rings[cur_stream] = NULL;
@@ -635,9 +743,6 @@ cleanup_rings:
for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
cur_ring = stream_info->stream_rings[cur_stream];
if (cur_ring) {
- addr = cur_ring->first_seg->dma;
- radix_tree_delete(&stream_info->trb_address_map,
- addr >> TRB_SEGMENT_SHIFT);
xhci_ring_free(xhci, cur_ring);
stream_info->stream_rings[cur_stream] = NULL;
}
@@ -698,7 +803,6 @@ void xhci_free_stream_info(struct xhci_hcd *xhci,
{
int cur_stream;
struct xhci_ring *cur_ring;
- dma_addr_t addr;
if (!stream_info)
return;
@@ -707,9 +811,6 @@ void xhci_free_stream_info(struct xhci_hcd *xhci,
cur_stream++) {
cur_ring = stream_info->stream_rings[cur_stream];
if (cur_ring) {
- addr = cur_ring->first_seg->dma;
- radix_tree_delete(&stream_info->trb_address_map,
- addr >> TRB_SEGMENT_SHIFT);
xhci_ring_free(xhci, cur_ring);
stream_info->stream_rings[cur_stream] = NULL;
}
@@ -1711,7 +1812,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
if (xhci->lpm_command)
xhci_free_command(xhci, xhci->lpm_command);
- xhci->cmd_ring_reserved_trbs = 0;
if (xhci->cmd_ring)
xhci_ring_free(xhci, xhci->cmd_ring);
xhci->cmd_ring = NULL;
@@ -1776,6 +1876,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
}
no_bw:
+ xhci->cmd_ring_reserved_trbs = 0;
xhci->num_usb2_ports = 0;
xhci->num_usb3_ports = 0;
xhci->num_active_eps = 0;
@@ -2274,11 +2375,12 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
/*
* Initialize the ring segment pool. The ring must be a contiguous
* structure comprised of TRBs. The TRBs must be 16 byte aligned,
- * however, the command ring segment needs 64-byte aligned segments,
- * so we pick the greater alignment need.
+ * however, the command ring segment needs 64-byte aligned segments
+ * and our use of dma addresses in the trb_address_map radix tree needs
+ * TRB_SEGMENT_SIZE alignment, so we pick the greater alignment need.
*/
xhci->segment_pool = dma_pool_create("xHCI ring segments", dev,
- TRB_SEGMENT_SIZE, 64, xhci->page_size);
+ TRB_SEGMENT_SIZE, TRB_SEGMENT_SIZE, xhci->page_size);
/* See Table 46 and Note on Figure 55 */
xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev,
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 04f986d9234f..47390e369cd4 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -190,6 +190,10 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
struct usb_hcd *hcd;
driver = (struct hc_driver *)id->driver_data;
+
+ /* Prevent runtime suspending between USB-2 and USB-3 initialization */
+ pm_runtime_get_noresume(&dev->dev);
+
/* Register the USB 2.0 roothub.
* FIXME: USB core must know to register the USB 2.0 roothub first.
* This is sort of silly, because we could just set the HCD driver flags
@@ -199,7 +203,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
retval = usb_hcd_pci_probe(dev, id);
if (retval)
- return retval;
+ goto put_runtime_pm;
/* USB 2.0 roothub is stored in the PCI device now. */
hcd = dev_get_drvdata(&dev->dev);
@@ -222,11 +226,11 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
goto put_usb3_hcd;
/* Roothub already marked as USB 3.0 speed */
- /* We know the LPM timeout algorithms for this host, let the USB core
- * enable and disable LPM for devices under the USB 3.0 roothub.
- */
- if (xhci->quirks & XHCI_LPM_SUPPORT)
- hcd_to_bus(xhci->shared_hcd)->root_hub->lpm_capable = 1;
+ if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
+ xhci->shared_hcd->can_do_streams = 1;
+
+ /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
+ pm_runtime_put_noidle(&dev->dev);
return 0;
@@ -234,6 +238,8 @@ put_usb3_hcd:
usb_put_hcd(xhci->shared_hcd);
dealloc_usb2_hcd:
usb_hcd_pci_remove(dev);
+put_runtime_pm:
+ pm_runtime_put_noidle(&dev->dev);
return retval;
}
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 8abda5c73ca1..151901ce1ba9 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -158,6 +158,9 @@ static int xhci_plat_probe(struct platform_device *pdev)
*/
*((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
+ if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
+ xhci->shared_hcd->can_do_streams = 1;
+
ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
if (ret)
goto put_usb3_hcd;
@@ -226,6 +229,7 @@ static const struct dev_pm_ops xhci_plat_pm_ops = {
#ifdef CONFIG_OF
static const struct of_device_id usb_xhci_of_match[] = {
+ { .compatible = "generic-xhci" },
{ .compatible = "xhci-platform" },
{ },
};
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 0ed64eb68e48..5f926bea5ab1 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -546,9 +546,9 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
struct xhci_dequeue_state *state)
{
struct xhci_virt_device *dev = xhci->devs[slot_id];
+ struct xhci_virt_ep *ep = &dev->eps[ep_index];
struct xhci_ring *ep_ring;
struct xhci_generic_trb *trb;
- struct xhci_ep_ctx *ep_ctx;
dma_addr_t addr;
ep_ring = xhci_triad_to_transfer_ring(xhci, slot_id,
@@ -573,8 +573,16 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
/* Dig out the cycle state saved by the xHC during the stop ep cmd */
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
"Finding endpoint context");
- ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
- state->new_cycle_state = 0x1 & le64_to_cpu(ep_ctx->deq);
+ /* 4.6.9 the css flag is written to the stream context for streams */
+ if (ep->ep_state & EP_HAS_STREAMS) {
+ struct xhci_stream_ctx *ctx =
+ &ep->stream_info->stream_ctx_array[stream_id];
+ state->new_cycle_state = 0x1 & le64_to_cpu(ctx->stream_ring);
+ } else {
+ struct xhci_ep_ctx *ep_ctx
+ = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
+ state->new_cycle_state = 0x1 & le64_to_cpu(ep_ctx->deq);
+ }
state->new_deq_ptr = cur_td->last_trb;
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
@@ -892,6 +900,57 @@ remove_finished_td:
/* Return to the event handler with xhci->lock re-acquired */
}
+static void xhci_kill_ring_urbs(struct xhci_hcd *xhci, struct xhci_ring *ring)
+{
+ struct xhci_td *cur_td;
+
+ while (!list_empty(&ring->td_list)) {
+ cur_td = list_first_entry(&ring->td_list,
+ struct xhci_td, td_list);
+ list_del_init(&cur_td->td_list);
+ if (!list_empty(&cur_td->cancelled_td_list))
+ list_del_init(&cur_td->cancelled_td_list);
+ xhci_giveback_urb_in_irq(xhci, cur_td, -ESHUTDOWN);
+ }
+}
+
+static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci,
+ int slot_id, int ep_index)
+{
+ struct xhci_td *cur_td;
+ struct xhci_virt_ep *ep;
+ struct xhci_ring *ring;
+
+ ep = &xhci->devs[slot_id]->eps[ep_index];
+ if ((ep->ep_state & EP_HAS_STREAMS) ||
+ (ep->ep_state & EP_GETTING_NO_STREAMS)) {
+ int stream_id;
+
+ for (stream_id = 0; stream_id < ep->stream_info->num_streams;
+ stream_id++) {
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Killing URBs for slot ID %u, ep index %u, stream %u",
+ slot_id, ep_index, stream_id + 1);
+ xhci_kill_ring_urbs(xhci,
+ ep->stream_info->stream_rings[stream_id]);
+ }
+ } else {
+ ring = ep->ring;
+ if (!ring)
+ return;
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Killing URBs for slot ID %u, ep index %u",
+ slot_id, ep_index);
+ xhci_kill_ring_urbs(xhci, ring);
+ }
+ while (!list_empty(&ep->cancelled_td_list)) {
+ cur_td = list_first_entry(&ep->cancelled_td_list,
+ struct xhci_td, cancelled_td_list);
+ list_del_init(&cur_td->cancelled_td_list);
+ xhci_giveback_urb_in_irq(xhci, cur_td, -ESHUTDOWN);
+ }
+}
+
/* Watchdog timer function for when a stop endpoint command fails to complete.
* In this case, we assume the host controller is broken or dying or dead. The
* host may still be completing some other events, so we have to be careful to
@@ -915,9 +974,6 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
{
struct xhci_hcd *xhci;
struct xhci_virt_ep *ep;
- struct xhci_virt_ep *temp_ep;
- struct xhci_ring *ring;
- struct xhci_td *cur_td;
int ret, i, j;
unsigned long flags;
@@ -974,34 +1030,8 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
for (i = 0; i < MAX_HC_SLOTS; i++) {
if (!xhci->devs[i])
continue;
- for (j = 0; j < 31; j++) {
- temp_ep = &xhci->devs[i]->eps[j];
- ring = temp_ep->ring;
- if (!ring)
- continue;
- xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
- "Killing URBs for slot ID %u, "
- "ep index %u", i, j);
- while (!list_empty(&ring->td_list)) {
- cur_td = list_first_entry(&ring->td_list,
- struct xhci_td,
- td_list);
- list_del_init(&cur_td->td_list);
- if (!list_empty(&cur_td->cancelled_td_list))
- list_del_init(&cur_td->cancelled_td_list);
- xhci_giveback_urb_in_irq(xhci, cur_td,
- -ESHUTDOWN);
- }
- while (!list_empty(&temp_ep->cancelled_td_list)) {
- cur_td = list_first_entry(
- &temp_ep->cancelled_td_list,
- struct xhci_td,
- cancelled_td_list);
- list_del_init(&cur_td->cancelled_td_list);
- xhci_giveback_urb_in_irq(xhci, cur_td,
- -ESHUTDOWN);
- }
- }
+ for (j = 0; j < 31; j++)
+ xhci_kill_endpoint_urbs(xhci, i, j);
}
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
@@ -1073,17 +1103,18 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
unsigned int stream_id;
struct xhci_ring *ep_ring;
struct xhci_virt_device *dev;
+ struct xhci_virt_ep *ep;
struct xhci_ep_ctx *ep_ctx;
struct xhci_slot_ctx *slot_ctx;
ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3]));
stream_id = TRB_TO_STREAM_ID(le32_to_cpu(trb->generic.field[2]));
dev = xhci->devs[slot_id];
+ ep = &dev->eps[ep_index];
ep_ring = xhci_stream_id_to_ring(dev, ep_index, stream_id);
if (!ep_ring) {
- xhci_warn(xhci, "WARN Set TR deq ptr command for "
- "freed stream ID %u\n",
+ xhci_warn(xhci, "WARN Set TR deq ptr command for freed stream ID %u\n",
stream_id);
/* XXX: Harmless??? */
dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING;
@@ -1099,12 +1130,10 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
switch (cmd_comp_code) {
case COMP_TRB_ERR:
- xhci_warn(xhci, "WARN Set TR Deq Ptr cmd invalid because "
- "of stream ID configuration\n");
+ xhci_warn(xhci, "WARN Set TR Deq Ptr cmd invalid because of stream ID configuration\n");
break;
case COMP_CTX_STATE:
- xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due "
- "to incorrect slot or ep state.\n");
+ xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due to incorrect slot or ep state.\n");
ep_state = le32_to_cpu(ep_ctx->ep_info);
ep_state &= EP_STATE_MASK;
slot_state = le32_to_cpu(slot_ctx->dev_state);
@@ -1114,13 +1143,12 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
slot_state, ep_state);
break;
case COMP_EBADSLT:
- xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed because "
- "slot %u was not enabled.\n", slot_id);
+ xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed because slot %u was not enabled.\n",
+ slot_id);
break;
default:
- xhci_warn(xhci, "WARN Set TR Deq Ptr cmd with unknown "
- "completion code of %u.\n",
- cmd_comp_code);
+ xhci_warn(xhci, "WARN Set TR Deq Ptr cmd with unknown completion code of %u.\n",
+ cmd_comp_code);
break;
}
/* OK what do we do now? The endpoint state is hosed, and we
@@ -1130,23 +1158,28 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
* cancelling URBs, which might not be an error...
*/
} else {
+ u64 deq;
+ /* 4.6.10 deq ptr is written to the stream ctx for streams */
+ if (ep->ep_state & EP_HAS_STREAMS) {
+ struct xhci_stream_ctx *ctx =
+ &ep->stream_info->stream_ctx_array[stream_id];
+ deq = le64_to_cpu(ctx->stream_ring) & SCTX_DEQ_MASK;
+ } else {
+ deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK;
+ }
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
- "Successful Set TR Deq Ptr cmd, deq = @%08llx",
- le64_to_cpu(ep_ctx->deq));
- if (xhci_trb_virt_to_dma(dev->eps[ep_index].queued_deq_seg,
- dev->eps[ep_index].queued_deq_ptr) ==
- (le64_to_cpu(ep_ctx->deq) & ~(EP_CTX_CYCLE_MASK))) {
+ "Successful Set TR Deq Ptr cmd, deq = @%08llx", deq);
+ if (xhci_trb_virt_to_dma(ep->queued_deq_seg,
+ ep->queued_deq_ptr) == deq) {
/* Update the ring's dequeue segment and dequeue pointer
* to reflect the new position.
*/
update_ring_for_set_deq_completion(xhci, dev,
ep_ring, ep_index);
} else {
- xhci_warn(xhci, "Mismatch between completed Set TR Deq "
- "Ptr command & xHCI internal state.\n");
+ xhci_warn(xhci, "Mismatch between completed Set TR Deq Ptr command & xHCI internal state.\n");
xhci_warn(xhci, "ep deq seg = %p, deq ptr = %p\n",
- dev->eps[ep_index].queued_deq_seg,
- dev->eps[ep_index].queued_deq_ptr);
+ ep->queued_deq_seg, ep->queued_deq_ptr);
}
}
@@ -4070,6 +4103,7 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
u32 trb_stream_id = STREAM_ID_FOR_TRB(stream_id);
+ u32 trb_sct = 0;
u32 type = TRB_TYPE(TRB_SET_DEQ);
struct xhci_virt_ep *ep;
@@ -4088,7 +4122,9 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
}
ep->queued_deq_seg = deq_seg;
ep->queued_deq_ptr = deq_ptr;
- return queue_command(xhci, lower_32_bits(addr) | cycle_state,
+ if (stream_id)
+ trb_sct = SCT_FOR_TRB(SCT_PRI_TR);
+ return queue_command(xhci, lower_32_bits(addr) | trb_sct | cycle_state,
upper_32_bits(addr), trb_stream_id,
trb_slot_id | trb_ep_index | type, false);
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 6fe577d46fa2..8fe4e124ddd4 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -390,6 +390,10 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)
}
legacy_irq:
+ if (!strlen(hcd->irq_descr))
+ snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
+ hcd->driver->description, hcd->self.busnum);
+
/* fall back to legacy interrupt*/
ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
hcd->irq_descr, hcd);
@@ -2678,6 +2682,20 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
return ret;
}
+static void xhci_check_bw_drop_ep_streams(struct xhci_hcd *xhci,
+ struct xhci_virt_device *vdev, int i)
+{
+ struct xhci_virt_ep *ep = &vdev->eps[i];
+
+ if (ep->ep_state & EP_HAS_STREAMS) {
+ xhci_warn(xhci, "WARN: endpoint 0x%02x has streams on set_interface, freeing streams.\n",
+ xhci_get_endpoint_address(i));
+ xhci_free_stream_info(xhci, ep->stream_info);
+ ep->stream_info = NULL;
+ ep->ep_state &= ~EP_HAS_STREAMS;
+ }
+}
+
/* Called after one or more calls to xhci_add_endpoint() or
* xhci_drop_endpoint(). If this call fails, the USB core is expected
* to call xhci_reset_bandwidth().
@@ -2742,8 +2760,10 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
/* Free any rings that were dropped, but not changed. */
for (i = 1; i < 31; ++i) {
if ((le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1))) &&
- !(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1))))
+ !(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1)))) {
xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
+ xhci_check_bw_drop_ep_streams(xhci, virt_dev, i);
+ }
}
xhci_zero_in_ctx(xhci, virt_dev);
/*
@@ -2759,6 +2779,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
if (virt_dev->eps[i].ring) {
xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
}
+ xhci_check_bw_drop_ep_streams(xhci, virt_dev, i);
virt_dev->eps[i].ring = virt_dev->eps[i].new_ring;
virt_dev->eps[i].new_ring = NULL;
}
@@ -2954,7 +2975,7 @@ static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,
ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, true, __func__);
if (ret <= 0)
return -EINVAL;
- if (ep->ss_ep_comp.bmAttributes == 0) {
+ if (usb_ss_max_streams(&ep->ss_ep_comp) == 0) {
xhci_warn(xhci, "WARN: SuperSpeed Endpoint Companion"
" descriptor for ep 0x%x does not support streams\n",
ep->desc.bEndpointAddress);
@@ -3121,6 +3142,12 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
xhci_dbg(xhci, "Driver wants %u stream IDs (including stream 0).\n",
num_streams);
+ /* MaxPSASize value 0 (2 streams) means streams are not supported */
+ if (HCC_MAX_PSA(xhci->hcc_params) < 4) {
+ xhci_dbg(xhci, "xHCI controller does not support streams.\n");
+ return -ENOSYS;
+ }
+
config_cmd = xhci_alloc_command(xhci, true, true, mem_flags);
if (!config_cmd) {
xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
@@ -3519,6 +3546,8 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
struct xhci_virt_ep *ep = &virt_dev->eps[i];
if (ep->ep_state & EP_HAS_STREAMS) {
+ xhci_warn(xhci, "WARN: endpoint 0x%02x has streams on device reset, freeing streams.\n",
+ xhci_get_endpoint_address(i));
xhci_free_stream_info(xhci, ep->stream_info);
ep->stream_info = NULL;
ep->ep_state &= ~EP_HAS_STREAMS;
@@ -4733,6 +4762,9 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
/* Accept arbitrarily long scatter-gather lists */
hcd->self.sg_tablesize = ~0;
+ /* support to build packet from discontinuous buffers */
+ hcd->self.no_sg_constraint = 1;
+
/* XHCI controllers don't stop the ep queue on short packets :| */
hcd->self.no_stop_on_short = 1;
@@ -4757,14 +4789,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
/* xHCI private pointer was set in xhci_pci_probe for the second
* registered roothub.
*/
- xhci = hcd_to_xhci(hcd);
- /*
- * Support arbitrarily aligned sg-list entries on hosts without
- * TD fragment rules (which are currently unsupported).
- */
- if (xhci->hci_version < 0x100)
- hcd->self.no_sg_constraint = 1;
-
return 0;
}
@@ -4793,9 +4817,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
if (xhci->hci_version > 0x96)
xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
- if (xhci->hci_version < 0x100)
- hcd->self.no_sg_constraint = 1;
-
/* Make sure the HC is halted. */
retval = xhci_halt(xhci);
if (retval)
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 58ed9d088e63..d280e9213d08 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -703,6 +703,7 @@ struct xhci_ep_ctx {
/* deq bitmasks */
#define EP_CTX_CYCLE_MASK (1 << 0)
+#define SCTX_DEQ_MASK (~0xfL)
/**
@@ -1118,9 +1119,10 @@ enum xhci_setup_dev {
#define TRB_TO_SUSPEND_PORT(p) (((p) & (1 << 23)) >> 23)
#define LAST_EP_INDEX 30
-/* Set TR Dequeue Pointer command TRB fields */
+/* Set TR Dequeue Pointer command TRB fields, 6.4.3.9 */
#define TRB_TO_STREAM_ID(p) ((((p) & (0xffff << 16)) >> 16))
#define STREAM_ID_FOR_TRB(p) ((((p)) & 0xffff) << 16)
+#define SCT_FOR_TRB(p) (((p) << 1) & 0x7)
/* Port Status Change Event TRB fields */
@@ -1341,6 +1343,7 @@ struct xhci_ring {
unsigned int num_trbs_free_temp;
enum xhci_ring_type type;
bool last_td_was_short;
+ struct radix_tree_root *trb_address_map;
};
struct xhci_erst_entry {
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index ba5f70f92888..1bca274dc3b5 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -128,7 +128,6 @@ config USB_IDMOUSE
config USB_FTDI_ELAN
tristate "Elan PCMCIA CardBus Adapter USB Client"
- default M
help
ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters.
Currently only the U132 adapter is available.
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index de98906f786d..06b5d77cd9ad 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -2123,8 +2123,8 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
u8 tmp8, tmp82, ramtype;
int bw = 0;
char *ramtypetext1 = NULL;
- const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
- "DDR SDRAM", "DDR SGRAM" };
+ static const char ram_datarate[4] = {'S', 'S', 'D', 'D'};
+ static const char ram_dynamictype[4] = {'D', 'G', 'D', 'G'};
static const int busSDR[4] = {64, 64, 128, 128};
static const int busDDR[4] = {32, 32, 64, 64};
static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
@@ -2156,8 +2156,10 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
break;
}
- dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1,
- ramtypetext2[ramtype], bw);
+
+ dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %cDR S%cRAM, bus width %d\n",
+ sisusb->vramsize >> 20, ramtypetext1,
+ ram_datarate[ramtype], ram_dynamictype[ramtype], bw);
}
static int
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
index 78eb4ff33269..bdef0d6eb91d 100644
--- a/drivers/usb/misc/usbled.c
+++ b/drivers/usb/misc/usbled.c
@@ -22,8 +22,27 @@
enum led_type {
DELCOM_VISUAL_SIGNAL_INDICATOR,
DREAM_CHEEKY_WEBMAIL_NOTIFIER,
+ RISO_KAGAKU_LED
};
+/* the Webmail LED made by RISO KAGAKU CORP. decodes a color index
+ internally, we want to keep the red+green+blue sysfs api, so we decode
+ from 1-bit RGB to the riso kagaku color index according to this table... */
+
+static unsigned const char riso_kagaku_tbl[] = {
+/* R+2G+4B -> riso kagaku color index */
+ [0] = 0, /* black */
+ [1] = 2, /* red */
+ [2] = 1, /* green */
+ [3] = 5, /* yellow */
+ [4] = 3, /* blue */
+ [5] = 6, /* magenta */
+ [6] = 4, /* cyan */
+ [7] = 7 /* white */
+};
+
+#define RISO_KAGAKU_IX(r,g,b) riso_kagaku_tbl[((r)?1:0)+((g)?2:0)+((b)?4:0)]
+
/* table of devices that work with this driver */
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x0fc5, 0x1223),
@@ -32,6 +51,8 @@ static const struct usb_device_id id_table[] = {
.driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
{ USB_DEVICE(0x1d34, 0x000a),
.driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
+ { USB_DEVICE(0x1294, 0x1320),
+ .driver_info = RISO_KAGAKU_LED },
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
@@ -48,6 +69,7 @@ static void change_color(struct usb_led *led)
{
int retval = 0;
unsigned char *buffer;
+ int actlength;
buffer = kmalloc(8, GFP_KERNEL);
if (!buffer) {
@@ -104,6 +126,18 @@ static void change_color(struct usb_led *led)
2000);
break;
+ case RISO_KAGAKU_LED:
+ buffer[0] = RISO_KAGAKU_IX(led->red, led->green, led->blue);
+ buffer[1] = 0;
+ buffer[2] = 0;
+ buffer[3] = 0;
+ buffer[4] = 0;
+
+ retval = usb_interrupt_msg(led->udev,
+ usb_sndctrlpipe(led->udev, 2),
+ buffer, 5, &actlength, 1000 /*ms timeout*/);
+ break;
+
default:
dev_err(&led->udev->dev, "unknown device type %d\n", led->type);
}
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 688dc8bb192d..8b789792f6fa 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -43,6 +43,7 @@ config USB_MUSB_HOST
config USB_MUSB_GADGET
bool "Gadget only mode"
depends on USB_GADGET=y || USB_GADGET=USB_MUSB_HDRC
+ depends on HAS_DMA
help
Select this when you want to use MUSB in gadget mode only,
thereby the host feature will be regressed.
@@ -50,6 +51,7 @@ config USB_MUSB_GADGET
config USB_MUSB_DUAL_ROLE
bool "Dual Role mode"
depends on ((USB=y || USB=USB_MUSB_HDRC) && (USB_GADGET=y || USB_GADGET=USB_MUSB_HDRC))
+ depends on HAS_DMA
help
This is the default mode of working of MUSB controller where
both host and gadget features are enabled.
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index fc192ad9cc6a..07576907e2c6 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -438,7 +438,6 @@ void musb_hnp_stop(struct musb *musb)
static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
u8 devctl)
{
- struct usb_otg *otg = musb->xceiv->otg;
irqreturn_t handled = IRQ_NONE;
dev_dbg(musb->controller, "<== DevCtl=%02x, int_usb=0x%x\n", devctl,
@@ -477,8 +476,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb->port1_status |=
(USB_PORT_STAT_C_SUSPEND << 16)
| MUSB_PORT_STAT_RESUME;
+ musb->rh_timer = jiffies
+ + msecs_to_jiffies(20);
schedule_delayed_work(
- &musb->finish_resume_work, 20);
+ &musb->finish_resume_work,
+ msecs_to_jiffies(20));
musb->xceiv->state = OTG_STATE_A_HOST;
musb->is_active = 1;
@@ -653,7 +655,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
break;
case OTG_STATE_B_PERIPHERAL:
musb_g_suspend(musb);
- musb->is_active = otg->gadget->b_hnp_enable;
+ musb->is_active = musb->g.b_hnp_enable;
if (musb->is_active) {
musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n");
@@ -669,7 +671,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
break;
case OTG_STATE_A_HOST:
musb->xceiv->state = OTG_STATE_A_SUSPEND;
- musb->is_active = otg->host->b_hnp_enable;
+ musb->is_active = musb->hcd->self.b_hnp_enable;
break;
case OTG_STATE_B_HOST:
/* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
@@ -2157,11 +2159,19 @@ static void musb_restore_context(struct musb *musb)
void __iomem *musb_base = musb->mregs;
void __iomem *ep_target_regs;
void __iomem *epio;
+ u8 power;
musb_writew(musb_base, MUSB_FRAME, musb->context.frame);
musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);
musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
- musb_writeb(musb_base, MUSB_POWER, musb->context.power);
+
+ /* Don't affect SUSPENDM/RESUME bits in POWER reg */
+ power = musb_readb(musb_base, MUSB_POWER);
+ power &= MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME;
+ musb->context.power &= ~(MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME);
+ power |= musb->context.power;
+ musb_writeb(musb_base, MUSB_POWER, power);
+
musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe);
musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe);
musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe);
diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
index f88929609bac..7b8bbf53127e 100644
--- a/drivers/usb/musb/musb_cppi41.c
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -39,6 +39,7 @@ struct cppi41_dma_channel {
u32 transferred;
u32 packet_sz;
struct list_head tx_check;
+ struct work_struct dma_completion;
};
#define MUSB_DMA_NUM_CHANNELS 15
@@ -112,6 +113,18 @@ static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep)
return true;
}
+static bool is_isoc(struct musb_hw_ep *hw_ep, bool in)
+{
+ if (in && hw_ep->in_qh) {
+ if (hw_ep->in_qh->type == USB_ENDPOINT_XFER_ISOC)
+ return true;
+ } else if (hw_ep->out_qh) {
+ if (hw_ep->out_qh->type == USB_ENDPOINT_XFER_ISOC)
+ return true;
+ }
+ return false;
+}
+
static void cppi41_dma_callback(void *private_data);
static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
@@ -119,7 +132,8 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
struct musb *musb = hw_ep->musb;
- if (!cppi41_channel->prog_len) {
+ if (!cppi41_channel->prog_len ||
+ (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)) {
/* done, complete */
cppi41_channel->channel.actual_len =
@@ -165,6 +179,32 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
}
}
+static void cppi_trans_done_work(struct work_struct *work)
+{
+ unsigned long flags;
+ struct cppi41_dma_channel *cppi41_channel =
+ container_of(work, struct cppi41_dma_channel, dma_completion);
+ struct cppi41_dma_controller *controller = cppi41_channel->controller;
+ struct musb *musb = controller->musb;
+ struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
+ bool empty;
+
+ if (!cppi41_channel->is_tx && is_isoc(hw_ep, 1)) {
+ spin_lock_irqsave(&musb->lock, flags);
+ cppi41_trans_done(cppi41_channel);
+ spin_unlock_irqrestore(&musb->lock, flags);
+ } else {
+ empty = musb_is_tx_fifo_empty(hw_ep);
+ if (empty) {
+ spin_lock_irqsave(&musb->lock, flags);
+ cppi41_trans_done(cppi41_channel);
+ spin_unlock_irqrestore(&musb->lock, flags);
+ } else {
+ schedule_work(&cppi41_channel->dma_completion);
+ }
+ }
+}
+
static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer)
{
struct cppi41_dma_controller *controller;
@@ -228,6 +268,14 @@ static void cppi41_dma_callback(void *private_data)
transferred < cppi41_channel->packet_sz)
cppi41_channel->prog_len = 0;
+ if (!cppi41_channel->is_tx) {
+ if (is_isoc(hw_ep, 1))
+ schedule_work(&cppi41_channel->dma_completion);
+ else
+ cppi41_trans_done(cppi41_channel);
+ goto out;
+ }
+
empty = musb_is_tx_fifo_empty(hw_ep);
if (empty) {
cppi41_trans_done(cppi41_channel);
@@ -264,6 +312,10 @@ static void cppi41_dma_callback(void *private_data)
goto out;
}
}
+ if (is_isoc(hw_ep, 0)) {
+ schedule_work(&cppi41_channel->dma_completion);
+ goto out;
+ }
list_add_tail(&cppi41_channel->tx_check,
&controller->early_tx_list);
if (!hrtimer_active(&controller->early_tx)) {
@@ -448,12 +500,25 @@ static int cppi41_dma_channel_program(struct dma_channel *channel,
dma_addr_t dma_addr, u32 len)
{
int ret;
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+ int hb_mult = 0;
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
channel->status == MUSB_DMA_STATUS_BUSY);
+ if (is_host_active(cppi41_channel->controller->musb)) {
+ if (cppi41_channel->is_tx)
+ hb_mult = cppi41_channel->hw_ep->out_qh->hb_mult;
+ else
+ hb_mult = cppi41_channel->hw_ep->in_qh->hb_mult;
+ }
+
channel->status = MUSB_DMA_STATUS_BUSY;
channel->actual_len = 0;
+
+ if (hb_mult)
+ packet_sz = hb_mult * (packet_sz & 0x7FF);
+
ret = cppi41_configure_channel(channel, packet_sz, mode, dma_addr, len);
if (!ret)
channel->status = MUSB_DMA_STATUS_FREE;
@@ -607,6 +672,8 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
cppi41_channel->port_num = port;
cppi41_channel->is_tx = is_tx;
INIT_LIST_HEAD(&cppi41_channel->tx_check);
+ INIT_WORK(&cppi41_channel->dma_completion,
+ cppi_trans_done_work);
musb_dma = &cppi41_channel->channel;
musb_dma->private_data = cppi41_channel;
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 7a109eae9b9a..3372ded5def7 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -45,6 +45,8 @@
#include <linux/of_irq.h>
#include <linux/usb/of.h>
+#include <linux/debugfs.h>
+
#include "musb_core.h"
static const struct of_device_id musb_dsps_of_match[];
@@ -136,6 +138,26 @@ struct dsps_glue {
unsigned long last_timer; /* last timer data for each instance */
struct dsps_context context;
+ struct debugfs_regset32 regset;
+ struct dentry *dbgfs_root;
+};
+
+static const struct debugfs_reg32 dsps_musb_regs[] = {
+ { "revision", 0x00 },
+ { "control", 0x14 },
+ { "status", 0x18 },
+ { "eoi", 0x24 },
+ { "intr0_stat", 0x30 },
+ { "intr1_stat", 0x34 },
+ { "intr0_set", 0x38 },
+ { "intr1_set", 0x3c },
+ { "txmode", 0x70 },
+ { "rxmode", 0x74 },
+ { "autoreq", 0xd0 },
+ { "srpfixtime", 0xd4 },
+ { "tdown", 0xd8 },
+ { "phy_utmi", 0xe0 },
+ { "mode", 0xe8 },
};
static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
@@ -368,6 +390,30 @@ out:
return ret;
}
+static int dsps_musb_dbg_init(struct musb *musb, struct dsps_glue *glue)
+{
+ struct dentry *root;
+ struct dentry *file;
+ char buf[128];
+
+ sprintf(buf, "%s.dsps", dev_name(musb->controller));
+ root = debugfs_create_dir(buf, NULL);
+ if (!root)
+ return -ENOMEM;
+ glue->dbgfs_root = root;
+
+ glue->regset.regs = dsps_musb_regs;
+ glue->regset.nregs = ARRAY_SIZE(dsps_musb_regs);
+ glue->regset.base = musb->ctrl_base;
+
+ file = debugfs_create_regset32("regdump", S_IRUGO, root, &glue->regset);
+ if (!file) {
+ debugfs_remove_recursive(root);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
static int dsps_musb_init(struct musb *musb)
{
struct device *dev = musb->controller;
@@ -377,6 +423,7 @@ static int dsps_musb_init(struct musb *musb)
void __iomem *reg_base;
struct resource *r;
u32 rev, val;
+ int ret;
r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control");
if (!r)
@@ -410,6 +457,10 @@ static int dsps_musb_init(struct musb *musb)
val &= ~(1 << wrp->otg_disable);
dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
+ ret = dsps_musb_dbg_init(musb, glue);
+ if (ret)
+ return ret;
+
return 0;
}
@@ -616,7 +667,7 @@ static int dsps_probe(struct platform_device *pdev)
wrp = match->data;
/* allocate glue */
- glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "unable to allocate glue memory\n");
return -ENOMEM;
@@ -644,7 +695,6 @@ err3:
pm_runtime_put(&pdev->dev);
err2:
pm_runtime_disable(&pdev->dev);
- kfree(glue);
return ret;
}
@@ -657,7 +707,9 @@ static int dsps_remove(struct platform_device *pdev)
/* disable usbss clocks */
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- kfree(glue);
+
+ debugfs_remove_recursive(glue->dbgfs_root);
+
return 0;
}
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index ed455724017b..eb06291a40c8 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -1183,6 +1183,9 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
csr = MUSB_CSR0_H_STATUSPKT
| MUSB_CSR0_TXPKTRDY;
+ /* disable ping token in status phase */
+ csr |= MUSB_CSR0_H_DIS_PING;
+
/* flag status stage */
musb->ep0_stage = MUSB_EP0_STATUS;
@@ -1691,7 +1694,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
| MUSB_RXCSR_RXPKTRDY);
musb_writew(hw_ep->regs, MUSB_RXCSR, val);
-#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA)
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \
+ defined(CONFIG_USB_TI_CPPI41_DMA)
if (usb_pipeisoc(pipe)) {
struct usb_iso_packet_descriptor *d;
@@ -1704,10 +1708,30 @@ void musb_host_rx(struct musb *musb, u8 epnum)
if (d->status != -EILSEQ && d->status != -EOVERFLOW)
d->status = 0;
- if (++qh->iso_idx >= urb->number_of_packets)
+ if (++qh->iso_idx >= urb->number_of_packets) {
done = true;
- else
+ } else {
+#if defined(CONFIG_USB_TI_CPPI41_DMA)
+ struct dma_controller *c;
+ dma_addr_t *buf;
+ u32 length, ret;
+
+ c = musb->dma_controller;
+ buf = (void *)
+ urb->iso_frame_desc[qh->iso_idx].offset
+ + (u32)urb->transfer_dma;
+
+ length =
+ urb->iso_frame_desc[qh->iso_idx].length;
+
+ val |= MUSB_RXCSR_DMAENAB;
+ musb_writew(hw_ep->regs, MUSB_RXCSR, val);
+
+ ret = c->channel_program(dma, qh->maxpacket,
+ 0, (u32) buf, length);
+#endif
done = false;
+ }
} else {
/* done if urb buffer is full or short packet is recd */
@@ -1747,7 +1771,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
}
/* we are expecting IN packets */
-#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA)
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \
+ defined(CONFIG_USB_TI_CPPI41_DMA)
if (dma) {
struct dma_controller *c;
u16 rx_count;
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index eb634433ef09..e2d2d8c9891b 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -135,7 +135,8 @@ void musb_port_suspend(struct musb *musb, bool do_suspend)
/* later, GetPortStatus will stop RESUME signaling */
musb->port1_status |= MUSB_PORT_STAT_RESUME;
- schedule_delayed_work(&musb->finish_resume_work, 20);
+ schedule_delayed_work(&musb->finish_resume_work,
+ msecs_to_jiffies(20));
}
}
@@ -158,7 +159,6 @@ void musb_port_reset(struct musb *musb, bool do_reset)
*/
power = musb_readb(mbase, MUSB_POWER);
if (do_reset) {
-
/*
* If RESUME is set, we must make sure it stays minimum 20 ms.
* Then we must clear RESUME and wait a bit to let musb start
@@ -167,11 +167,22 @@ void musb_port_reset(struct musb *musb, bool do_reset)
* detected".
*/
if (power & MUSB_POWER_RESUME) {
- while (time_before(jiffies, musb->rh_timer))
- msleep(1);
+ long remain = (unsigned long) musb->rh_timer - jiffies;
+
+ if (musb->rh_timer > 0 && remain > 0) {
+ /* take into account the minimum delay after resume */
+ schedule_delayed_work(
+ &musb->deassert_reset_work, remain);
+ return;
+ }
+
musb_writeb(mbase, MUSB_POWER,
- power & ~MUSB_POWER_RESUME);
- msleep(1);
+ power & ~MUSB_POWER_RESUME);
+
+ /* Give the core 1 ms to clear MUSB_POWER_RESUME */
+ schedule_delayed_work(&musb->deassert_reset_work,
+ msecs_to_jiffies(1));
+ return;
}
power &= 0xf0;
@@ -180,7 +191,8 @@ void musb_port_reset(struct musb *musb, bool do_reset)
musb->port1_status |= USB_PORT_STAT_RESET;
musb->port1_status &= ~USB_PORT_STAT_ENABLE;
- schedule_delayed_work(&musb->deassert_reset_work, 50);
+ schedule_delayed_work(&musb->deassert_reset_work,
+ msecs_to_jiffies(50));
} else {
dev_dbg(musb->controller, "root port reset stopped\n");
musb_writeb(mbase, MUSB_POWER,
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 2a408cdaf7b2..d341c149a2f9 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -37,7 +37,7 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/usb/musb-omap.h>
-#include <linux/usb/omap_control_usb.h>
+#include <linux/phy/omap_control_phy.h>
#include <linux/of_platform.h>
#include "musb_core.h"
@@ -659,7 +659,6 @@ static int omap2430_runtime_suspend(struct device *dev)
OTG_INTERFSEL);
omap2430_low_level_exit(musb);
- phy_power_off(musb->phy);
}
return 0;
@@ -674,7 +673,6 @@ static int omap2430_runtime_resume(struct device *dev)
omap2430_low_level_init(musb);
musb_writel(musb->mregs, OTG_INTERFSEL,
musb->context.otg_interfsel);
- phy_power_on(musb->phy);
}
return 0;
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 7d1451d5bbea..416e0c8cf6ff 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -75,27 +75,6 @@ config NOP_USB_XCEIV
built-in with usb ip or which are autonomous and doesn't require any
phy programming such as ISP1x04 etc.
-config OMAP_CONTROL_USB
- tristate "OMAP CONTROL USB Driver"
- depends on ARCH_OMAP2PLUS || COMPILE_TEST
- help
- Enable this to add support for the USB part present in the control
- module. This driver has API to power on the USB2 PHY and to write to
- the mailbox. The mailbox is present only in omap4 and the register to
- power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
- additional register to power on USB3 PHY.
-
-config OMAP_USB3
- tristate "OMAP USB3 PHY Driver"
- depends on ARCH_OMAP2PLUS || COMPILE_TEST
- select OMAP_CONTROL_USB
- select USB_PHY
- help
- Enable this to support the USB3 PHY that is part of SOC. This
- driver takes care of all the PHY functionality apart from comparator.
- This driver interacts with the "OMAP Control USB Driver" to power
- on/off the PHY.
-
config AM335X_CONTROL_USB
tristate
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index be58adae3496..f8fa719a31b9 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -13,11 +13,9 @@ obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o
obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o
obj-$(CONFIG_NOP_USB_XCEIV) += phy-generic.o
obj-$(CONFIG_TAHVO_USB) += phy-tahvo.o
-obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o
obj-$(CONFIG_AM335X_CONTROL_USB) += phy-am335x-control.o
obj-$(CONFIG_AM335X_PHY_USB) += phy-am335x.o
obj-$(CONFIG_OMAP_OTG) += phy-omap-otg.o
-obj-$(CONFIG_OMAP_USB3) += phy-omap-usb3.o
obj-$(CONFIG_SAMSUNG_USBPHY) += phy-samsung-usb.o
obj-$(CONFIG_SAMSUNG_USB2PHY) += phy-samsung-usb2.o
obj-$(CONFIG_SAMSUNG_USB3PHY) += phy-samsung-usb3.o
diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/phy/phy-fsm-usb.c
index 7aa314ef4a8a..c47e5a6edde2 100644
--- a/drivers/usb/phy/phy-fsm-usb.c
+++ b/drivers/usb/phy/phy-fsm-usb.c
@@ -317,10 +317,12 @@ int otg_statemachine(struct otg_fsm *fsm)
otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
break;
case OTG_STATE_A_HOST:
- if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) &&
+ if (fsm->id || fsm->a_bus_drop)
+ otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
+ else if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) &&
fsm->otg->host->b_hnp_enable)
otg_set_state(fsm, OTG_STATE_A_SUSPEND);
- else if (fsm->id || !fsm->b_conn || fsm->a_bus_drop)
+ else if (!fsm->b_conn)
otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
else if (!fsm->a_vbus_vld)
otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
@@ -346,8 +348,7 @@ int otg_statemachine(struct otg_fsm *fsm)
otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
break;
case OTG_STATE_A_WAIT_VFALL:
- if (fsm->a_wait_vfall_tmout || fsm->id || fsm->a_bus_req ||
- (!fsm->a_sess_vld && !fsm->b_conn))
+ if (fsm->a_wait_vfall_tmout)
otg_set_state(fsm, OTG_STATE_A_IDLE);
break;
case OTG_STATE_A_VBUS_ERR:
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
index 8546c8dccd51..5b37b81f2ef6 100644
--- a/drivers/usb/phy/phy-msm-usb.c
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -159,32 +159,6 @@ put_3p3:
return rc;
}
-#ifdef CONFIG_PM_SLEEP
-#define USB_PHY_SUSP_DIG_VOL 500000
-static int msm_hsusb_config_vddcx(int high)
-{
- int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
- int min_vol;
- int ret;
-
- if (high)
- min_vol = USB_PHY_VDD_DIG_VOL_MIN;
- else
- min_vol = USB_PHY_SUSP_DIG_VOL;
-
- ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
- if (ret) {
- pr_err("%s: unable to set the voltage for regulator "
- "HSUSB_VDDCX\n", __func__);
- return ret;
- }
-
- pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
-
- return ret;
-}
-#endif
-
static int msm_hsusb_ldo_set_mode(int on)
{
int ret = 0;
@@ -440,7 +414,32 @@ static int msm_otg_reset(struct usb_phy *phy)
#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
+
+#define USB_PHY_SUSP_DIG_VOL 500000
+static int msm_hsusb_config_vddcx(int high)
+{
+ int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
+ int min_vol;
+ int ret;
+
+ if (high)
+ min_vol = USB_PHY_VDD_DIG_VOL_MIN;
+ else
+ min_vol = USB_PHY_SUSP_DIG_VOL;
+
+ ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
+ if (ret) {
+ pr_err("%s: unable to set the voltage for regulator "
+ "HSUSB_VDDCX\n", __func__);
+ return ret;
+ }
+
+ pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
+
+ return ret;
+}
+
static int msm_otg_suspend(struct msm_otg *motg)
{
struct usb_phy *phy = &motg->phy;
@@ -1429,7 +1428,8 @@ static int __init msm_otg_probe(struct platform_device *pdev)
motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
if (!motg->phy.otg) {
dev_err(&pdev->dev, "unable to allocate msm_otg\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto free_motg;
}
motg->pdata = dev_get_platdata(&pdev->dev);
@@ -1733,22 +1733,18 @@ static int msm_otg_pm_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM
static const struct dev_pm_ops msm_otg_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
msm_otg_runtime_idle)
};
-#endif
static struct platform_driver msm_otg_driver = {
.remove = msm_otg_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &msm_otg_dev_pm_ops,
-#endif
},
};
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index b42897b6474c..c42bdf0c4a1f 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012-2013 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Marek Vasut <marex@denx.de>
* on behalf of DENX Software Engineering GmbH
*
@@ -20,6 +20,9 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
#define DRIVER_NAME "mxs_phy"
@@ -28,18 +31,134 @@
#define HW_USBPHY_CTRL_SET 0x34
#define HW_USBPHY_CTRL_CLR 0x38
+#define HW_USBPHY_DEBUG_SET 0x54
+#define HW_USBPHY_DEBUG_CLR 0x58
+
+#define HW_USBPHY_IP 0x90
+#define HW_USBPHY_IP_SET 0x94
+#define HW_USBPHY_IP_CLR 0x98
+
#define BM_USBPHY_CTRL_SFTRST BIT(31)
#define BM_USBPHY_CTRL_CLKGATE BIT(30)
+#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS BIT(26)
+#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE BIT(25)
+#define BM_USBPHY_CTRL_ENVBUSCHG_WKUP BIT(23)
+#define BM_USBPHY_CTRL_ENIDCHG_WKUP BIT(22)
+#define BM_USBPHY_CTRL_ENDPDMCHG_WKUP BIT(21)
+#define BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD BIT(20)
+#define BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE BIT(19)
+#define BM_USBPHY_CTRL_ENAUTO_PWRON_PLL BIT(18)
#define BM_USBPHY_CTRL_ENUTMILEVEL3 BIT(15)
#define BM_USBPHY_CTRL_ENUTMILEVEL2 BIT(14)
#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT BIT(1)
+#define BM_USBPHY_IP_FIX (BIT(17) | BIT(18))
+
+#define BM_USBPHY_DEBUG_CLKGATE BIT(30)
+
+/* Anatop Registers */
+#define ANADIG_ANA_MISC0 0x150
+#define ANADIG_ANA_MISC0_SET 0x154
+#define ANADIG_ANA_MISC0_CLR 0x158
+
+#define ANADIG_USB1_VBUS_DET_STAT 0x1c0
+#define ANADIG_USB2_VBUS_DET_STAT 0x220
+
+#define ANADIG_USB1_LOOPBACK_SET 0x1e4
+#define ANADIG_USB1_LOOPBACK_CLR 0x1e8
+#define ANADIG_USB2_LOOPBACK_SET 0x244
+#define ANADIG_USB2_LOOPBACK_CLR 0x248
+
+#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG BIT(12)
+#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11)
+
+#define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID BIT(3)
+#define BM_ANADIG_USB2_VBUS_DET_STAT_VBUS_VALID BIT(3)
+
+#define BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 BIT(2)
+#define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN BIT(5)
+#define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 BIT(2)
+#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN BIT(5)
+
+#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
+
+/* Do disconnection between PHY and controller without vbus */
+#define MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS BIT(0)
+
+/*
+ * The PHY will be in messy if there is a wakeup after putting
+ * bus to suspend (set portsc.suspendM) but before setting PHY to low
+ * power mode (set portsc.phcd).
+ */
+#define MXS_PHY_ABNORMAL_IN_SUSPEND BIT(1)
+
+/*
+ * The SOF sends too fast after resuming, it will cause disconnection
+ * between host and high speed device.
+ */
+#define MXS_PHY_SENDING_SOF_TOO_FAST BIT(2)
+
+/*
+ * IC has bug fixes logic, they include
+ * MXS_PHY_ABNORMAL_IN_SUSPEND and MXS_PHY_SENDING_SOF_TOO_FAST
+ * which are described at above flags, the RTL will handle it
+ * according to different versions.
+ */
+#define MXS_PHY_NEED_IP_FIX BIT(3)
+
+struct mxs_phy_data {
+ unsigned int flags;
+};
+
+static const struct mxs_phy_data imx23_phy_data = {
+ .flags = MXS_PHY_ABNORMAL_IN_SUSPEND | MXS_PHY_SENDING_SOF_TOO_FAST,
+};
+
+static const struct mxs_phy_data imx6q_phy_data = {
+ .flags = MXS_PHY_SENDING_SOF_TOO_FAST |
+ MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
+ MXS_PHY_NEED_IP_FIX,
+};
+
+static const struct mxs_phy_data imx6sl_phy_data = {
+ .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
+ MXS_PHY_NEED_IP_FIX,
+};
+
+static const struct of_device_id mxs_phy_dt_ids[] = {
+ { .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
+ { .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, },
+ { .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);
+
struct mxs_phy {
struct usb_phy phy;
struct clk *clk;
+ const struct mxs_phy_data *data;
+ struct regmap *regmap_anatop;
+ int port_id;
};
-#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
+static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy)
+{
+ return mxs_phy->data == &imx6q_phy_data;
+}
+
+static inline bool is_imx6sl_phy(struct mxs_phy *mxs_phy)
+{
+ return mxs_phy->data == &imx6sl_phy_data;
+}
+
+/*
+ * PHY needs some 32K cycles to switch from 32K clock to
+ * bus (such as AHB/AXI, etc) clock.
+ */
+static void mxs_phy_clock_switch_delay(void)
+{
+ usleep_range(300, 400);
+}
static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
{
@@ -53,19 +172,105 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
/* Power up the PHY */
writel(0, base + HW_USBPHY_PWD);
- /* enable FS/LS device */
- writel(BM_USBPHY_CTRL_ENUTMILEVEL2 |
- BM_USBPHY_CTRL_ENUTMILEVEL3,
+ /*
+ * USB PHY Ctrl Setting
+ * - Auto clock/power on
+ * - Enable full/low speed support
+ */
+ writel(BM_USBPHY_CTRL_ENAUTOSET_USBCLKS |
+ BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE |
+ BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD |
+ BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE |
+ BM_USBPHY_CTRL_ENAUTO_PWRON_PLL |
+ BM_USBPHY_CTRL_ENUTMILEVEL2 |
+ BM_USBPHY_CTRL_ENUTMILEVEL3,
base + HW_USBPHY_CTRL_SET);
+ if (mxs_phy->data->flags & MXS_PHY_NEED_IP_FIX)
+ writel(BM_USBPHY_IP_FIX, base + HW_USBPHY_IP_SET);
+
return 0;
}
+/* Return true if the vbus is there */
+static bool mxs_phy_get_vbus_status(struct mxs_phy *mxs_phy)
+{
+ unsigned int vbus_value;
+
+ if (mxs_phy->port_id == 0)
+ regmap_read(mxs_phy->regmap_anatop,
+ ANADIG_USB1_VBUS_DET_STAT,
+ &vbus_value);
+ else if (mxs_phy->port_id == 1)
+ regmap_read(mxs_phy->regmap_anatop,
+ ANADIG_USB2_VBUS_DET_STAT,
+ &vbus_value);
+
+ if (vbus_value & BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID)
+ return true;
+ else
+ return false;
+}
+
+static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
+{
+ void __iomem *base = mxs_phy->phy.io_priv;
+ u32 reg;
+
+ if (disconnect)
+ writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
+ base + HW_USBPHY_DEBUG_CLR);
+
+ if (mxs_phy->port_id == 0) {
+ reg = disconnect ? ANADIG_USB1_LOOPBACK_SET
+ : ANADIG_USB1_LOOPBACK_CLR;
+ regmap_write(mxs_phy->regmap_anatop, reg,
+ BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 |
+ BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN);
+ } else if (mxs_phy->port_id == 1) {
+ reg = disconnect ? ANADIG_USB2_LOOPBACK_SET
+ : ANADIG_USB2_LOOPBACK_CLR;
+ regmap_write(mxs_phy->regmap_anatop, reg,
+ BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 |
+ BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN);
+ }
+
+ if (!disconnect)
+ writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
+ base + HW_USBPHY_DEBUG_SET);
+
+ /* Delay some time, and let Linestate be SE0 for controller */
+ if (disconnect)
+ usleep_range(500, 1000);
+}
+
+static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
+{
+ bool vbus_is_on = false;
+
+ /* If the SoCs don't need to disconnect line without vbus, quit */
+ if (!(mxs_phy->data->flags & MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS))
+ return;
+
+ /* If the SoCs don't have anatop, quit */
+ if (!mxs_phy->regmap_anatop)
+ return;
+
+ vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
+
+ if (on && !vbus_is_on)
+ __mxs_phy_disconnect_line(mxs_phy, true);
+ else
+ __mxs_phy_disconnect_line(mxs_phy, false);
+
+}
+
static int mxs_phy_init(struct usb_phy *phy)
{
int ret;
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
+ mxs_phy_clock_switch_delay();
ret = clk_prepare_enable(mxs_phy->clk);
if (ret)
return ret;
@@ -94,6 +299,7 @@ static int mxs_phy_suspend(struct usb_phy *x, int suspend)
x->io_priv + HW_USBPHY_CTRL_SET);
clk_disable_unprepare(mxs_phy->clk);
} else {
+ mxs_phy_clock_switch_delay();
ret = clk_prepare_enable(mxs_phy->clk);
if (ret)
return ret;
@@ -105,11 +311,28 @@ static int mxs_phy_suspend(struct usb_phy *x, int suspend)
return 0;
}
+static int mxs_phy_set_wakeup(struct usb_phy *x, bool enabled)
+{
+ struct mxs_phy *mxs_phy = to_mxs_phy(x);
+ u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP |
+ BM_USBPHY_CTRL_ENDPDMCHG_WKUP |
+ BM_USBPHY_CTRL_ENIDCHG_WKUP;
+ if (enabled) {
+ mxs_phy_disconnect_line(mxs_phy, true);
+ writel_relaxed(value, x->io_priv + HW_USBPHY_CTRL_SET);
+ } else {
+ writel_relaxed(value, x->io_priv + HW_USBPHY_CTRL_CLR);
+ mxs_phy_disconnect_line(mxs_phy, false);
+ }
+
+ return 0;
+}
+
static int mxs_phy_on_connect(struct usb_phy *phy,
enum usb_device_speed speed)
{
- dev_dbg(phy->dev, "%s speed device has connected\n",
- (speed == USB_SPEED_HIGH) ? "high" : "non-high");
+ dev_dbg(phy->dev, "%s device has connected\n",
+ (speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
if (speed == USB_SPEED_HIGH)
writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
@@ -121,8 +344,8 @@ static int mxs_phy_on_connect(struct usb_phy *phy,
static int mxs_phy_on_disconnect(struct usb_phy *phy,
enum usb_device_speed speed)
{
- dev_dbg(phy->dev, "%s speed device has disconnected\n",
- (speed == USB_SPEED_HIGH) ? "high" : "non-high");
+ dev_dbg(phy->dev, "%s device has disconnected\n",
+ (speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
if (speed == USB_SPEED_HIGH)
writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
@@ -138,6 +361,9 @@ static int mxs_phy_probe(struct platform_device *pdev)
struct clk *clk;
struct mxs_phy *mxs_phy;
int ret;
+ const struct of_device_id *of_id =
+ of_match_device(mxs_phy_dt_ids, &pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
@@ -157,6 +383,22 @@ static int mxs_phy_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ /* Some SoCs don't have anatop registers */
+ if (of_get_property(np, "fsl,anatop", NULL)) {
+ mxs_phy->regmap_anatop = syscon_regmap_lookup_by_phandle
+ (np, "fsl,anatop");
+ if (IS_ERR(mxs_phy->regmap_anatop)) {
+ dev_dbg(&pdev->dev,
+ "failed to find regmap for anatop\n");
+ return PTR_ERR(mxs_phy->regmap_anatop);
+ }
+ }
+
+ ret = of_alias_get_id(np, "usbphy");
+ if (ret < 0)
+ dev_dbg(&pdev->dev, "failed to get alias id, errno %d\n", ret);
+ mxs_phy->port_id = ret;
+
mxs_phy->phy.io_priv = base;
mxs_phy->phy.dev = &pdev->dev;
mxs_phy->phy.label = DRIVER_NAME;
@@ -166,11 +408,15 @@ static int mxs_phy_probe(struct platform_device *pdev)
mxs_phy->phy.notify_connect = mxs_phy_on_connect;
mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect;
mxs_phy->phy.type = USB_PHY_TYPE_USB2;
+ mxs_phy->phy.set_wakeup = mxs_phy_set_wakeup;
mxs_phy->clk = clk;
+ mxs_phy->data = of_id->data;
platform_set_drvdata(pdev, mxs_phy);
+ device_set_wakeup_capable(&pdev->dev, true);
+
ret = usb_add_phy_dev(&mxs_phy->phy);
if (ret)
return ret;
@@ -187,11 +433,46 @@ static int mxs_phy_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id mxs_phy_dt_ids[] = {
- { .compatible = "fsl,imx23-usbphy", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);
+#ifdef CONFIG_PM_SLEEP
+static void mxs_phy_enable_ldo_in_suspend(struct mxs_phy *mxs_phy, bool on)
+{
+ unsigned int reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR;
+
+ /* If the SoCs don't have anatop, quit */
+ if (!mxs_phy->regmap_anatop)
+ return;
+
+ if (is_imx6q_phy(mxs_phy))
+ regmap_write(mxs_phy->regmap_anatop, reg,
+ BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG);
+ else if (is_imx6sl_phy(mxs_phy))
+ regmap_write(mxs_phy->regmap_anatop,
+ reg, BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL);
+}
+
+static int mxs_phy_system_suspend(struct device *dev)
+{
+ struct mxs_phy *mxs_phy = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ mxs_phy_enable_ldo_in_suspend(mxs_phy, true);
+
+ return 0;
+}
+
+static int mxs_phy_system_resume(struct device *dev)
+{
+ struct mxs_phy *mxs_phy = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ mxs_phy_enable_ldo_in_suspend(mxs_phy, false);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(mxs_phy_pm, mxs_phy_system_suspend,
+ mxs_phy_system_resume);
static struct platform_driver mxs_phy_driver = {
.probe = mxs_phy_probe,
@@ -200,6 +481,7 @@ static struct platform_driver mxs_phy_driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = mxs_phy_dt_ids,
+ .pm = &mxs_phy_pm,
},
};
diff --git a/drivers/usb/phy/phy-omap-usb3.c b/drivers/usb/phy/phy-omap-usb3.c
deleted file mode 100644
index 0c6ba29bdddd..000000000000
--- a/drivers/usb/phy/phy-omap-usb3.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * omap-usb3 - USB PHY, talking to dwc3 controller in OMAP.
- *
- * Copyright (C) 2013 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Author: Kishon Vijay Abraham I <kishon@ti.com>
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/usb/omap_usb.h>
-#include <linux/of.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/pm_runtime.h>
-#include <linux/delay.h>
-#include <linux/usb/omap_control_usb.h>
-#include <linux/of_platform.h>
-
-#define PLL_STATUS 0x00000004
-#define PLL_GO 0x00000008
-#define PLL_CONFIGURATION1 0x0000000C
-#define PLL_CONFIGURATION2 0x00000010
-#define PLL_CONFIGURATION3 0x00000014
-#define PLL_CONFIGURATION4 0x00000020
-
-#define PLL_REGM_MASK 0x001FFE00
-#define PLL_REGM_SHIFT 0x9
-#define PLL_REGM_F_MASK 0x0003FFFF
-#define PLL_REGM_F_SHIFT 0x0
-#define PLL_REGN_MASK 0x000001FE
-#define PLL_REGN_SHIFT 0x1
-#define PLL_SELFREQDCO_MASK 0x0000000E
-#define PLL_SELFREQDCO_SHIFT 0x1
-#define PLL_SD_MASK 0x0003FC00
-#define PLL_SD_SHIFT 0x9
-#define SET_PLL_GO 0x1
-#define PLL_TICOPWDN 0x10000
-#define PLL_LOCK 0x2
-#define PLL_IDLE 0x1
-
-/*
- * This is an Empirical value that works, need to confirm the actual
- * value required for the USB3PHY_PLL_CONFIGURATION2.PLL_IDLE status
- * to be correctly reflected in the USB3PHY_PLL_STATUS register.
- */
-# define PLL_IDLE_TIME 100;
-
-struct usb_dpll_map {
- unsigned long rate;
- struct usb_dpll_params params;
-};
-
-static struct usb_dpll_map dpll_map[] = {
- {12000000, {1250, 5, 4, 20, 0} }, /* 12 MHz */
- {16800000, {3125, 20, 4, 20, 0} }, /* 16.8 MHz */
- {19200000, {1172, 8, 4, 20, 65537} }, /* 19.2 MHz */
- {20000000, {1000, 7, 4, 10, 0} }, /* 20 MHz */
- {26000000, {1250, 12, 4, 20, 0} }, /* 26 MHz */
- {38400000, {3125, 47, 4, 20, 92843} }, /* 38.4 MHz */
-};
-
-static struct usb_dpll_params *omap_usb3_get_dpll_params(unsigned long rate)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dpll_map); i++) {
- if (rate == dpll_map[i].rate)
- return &dpll_map[i].params;
- }
-
- return NULL;
-}
-
-static int omap_usb3_suspend(struct usb_phy *x, int suspend)
-{
- struct omap_usb *phy = phy_to_omapusb(x);
- int val;
- int timeout = PLL_IDLE_TIME;
-
- if (suspend && !phy->is_suspended) {
- val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
- val |= PLL_IDLE;
- omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
-
- do {
- val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS);
- if (val & PLL_TICOPWDN)
- break;
- udelay(1);
- } while (--timeout);
-
- omap_control_usb_phy_power(phy->control_dev, 0);
-
- phy->is_suspended = 1;
- } else if (!suspend && phy->is_suspended) {
- phy->is_suspended = 0;
-
- val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
- val &= ~PLL_IDLE;
- omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
-
- do {
- val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS);
- if (!(val & PLL_TICOPWDN))
- break;
- udelay(1);
- } while (--timeout);
- }
-
- return 0;
-}
-
-static void omap_usb_dpll_relock(struct omap_usb *phy)
-{
- u32 val;
- unsigned long timeout;
-
- omap_usb_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO);
-
- timeout = jiffies + msecs_to_jiffies(20);
- do {
- val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS);
- if (val & PLL_LOCK)
- break;
- } while (!WARN_ON(time_after(jiffies, timeout)));
-}
-
-static int omap_usb_dpll_lock(struct omap_usb *phy)
-{
- u32 val;
- unsigned long rate;
- struct usb_dpll_params *dpll_params;
-
- rate = clk_get_rate(phy->sys_clk);
- dpll_params = omap_usb3_get_dpll_params(rate);
- if (!dpll_params) {
- dev_err(phy->dev,
- "No DPLL configuration for %lu Hz SYS CLK\n", rate);
- return -EINVAL;
- }
-
- val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
- val &= ~PLL_REGN_MASK;
- val |= dpll_params->n << PLL_REGN_SHIFT;
- omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
-
- val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
- val &= ~PLL_SELFREQDCO_MASK;
- val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
- omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
-
- val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
- val &= ~PLL_REGM_MASK;
- val |= dpll_params->m << PLL_REGM_SHIFT;
- omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
-
- val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
- val &= ~PLL_REGM_F_MASK;
- val |= dpll_params->mf << PLL_REGM_F_SHIFT;
- omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
-
- val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
- val &= ~PLL_SD_MASK;
- val |= dpll_params->sd << PLL_SD_SHIFT;
- omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
-
- omap_usb_dpll_relock(phy);
-
- return 0;
-}
-
-static int omap_usb3_init(struct usb_phy *x)
-{
- struct omap_usb *phy = phy_to_omapusb(x);
- int ret;
-
- ret = omap_usb_dpll_lock(phy);
- if (ret)
- return ret;
-
- omap_control_usb_phy_power(phy->control_dev, 1);
-
- return 0;
-}
-
-static int omap_usb3_probe(struct platform_device *pdev)
-{
- struct omap_usb *phy;
- struct resource *res;
- struct device_node *node = pdev->dev.of_node;
- struct device_node *control_node;
- struct platform_device *control_pdev;
-
- if (!node)
- return -EINVAL;
-
- phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
- if (!phy) {
- dev_err(&pdev->dev, "unable to alloc mem for OMAP USB3 PHY\n");
- return -ENOMEM;
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_ctrl");
- phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(phy->pll_ctrl_base))
- return PTR_ERR(phy->pll_ctrl_base);
-
- phy->dev = &pdev->dev;
-
- phy->phy.dev = phy->dev;
- phy->phy.label = "omap-usb3";
- phy->phy.init = omap_usb3_init;
- phy->phy.set_suspend = omap_usb3_suspend;
- phy->phy.type = USB_PHY_TYPE_USB3;
-
- phy->is_suspended = 1;
- phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
- if (IS_ERR(phy->wkupclk)) {
- dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
- return PTR_ERR(phy->wkupclk);
- }
- clk_prepare(phy->wkupclk);
-
- phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m");
- if (IS_ERR(phy->optclk)) {
- dev_err(&pdev->dev, "unable to get usb_otg_ss_refclk960m\n");
- return PTR_ERR(phy->optclk);
- }
- clk_prepare(phy->optclk);
-
- phy->sys_clk = devm_clk_get(phy->dev, "sys_clkin");
- if (IS_ERR(phy->sys_clk)) {
- pr_err("%s: unable to get sys_clkin\n", __func__);
- return -EINVAL;
- }
-
- control_node = of_parse_phandle(node, "ctrl-module", 0);
- if (!control_node) {
- dev_err(&pdev->dev, "Failed to get control device phandle\n");
- return -EINVAL;
- }
- control_pdev = of_find_device_by_node(control_node);
- if (!control_pdev) {
- dev_err(&pdev->dev, "Failed to get control device\n");
- return -EINVAL;
- }
-
- phy->control_dev = &control_pdev->dev;
-
- omap_control_usb_phy_power(phy->control_dev, 0);
- usb_add_phy_dev(&phy->phy);
-
- platform_set_drvdata(pdev, phy);
-
- pm_runtime_enable(phy->dev);
- pm_runtime_get(&pdev->dev);
-
- return 0;
-}
-
-static int omap_usb3_remove(struct platform_device *pdev)
-{
- struct omap_usb *phy = platform_get_drvdata(pdev);
-
- clk_unprepare(phy->wkupclk);
- clk_unprepare(phy->optclk);
- usb_remove_phy(&phy->phy);
- if (!pm_runtime_suspended(&pdev->dev))
- pm_runtime_put(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
-
- return 0;
-}
-
-#ifdef CONFIG_PM_RUNTIME
-
-static int omap_usb3_runtime_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct omap_usb *phy = platform_get_drvdata(pdev);
-
- clk_disable(phy->wkupclk);
- clk_disable(phy->optclk);
-
- return 0;
-}
-
-static int omap_usb3_runtime_resume(struct device *dev)
-{
- u32 ret = 0;
- struct platform_device *pdev = to_platform_device(dev);
- struct omap_usb *phy = platform_get_drvdata(pdev);
-
- ret = clk_enable(phy->optclk);
- if (ret) {
- dev_err(phy->dev, "Failed to enable optclk %d\n", ret);
- goto err1;
- }
-
- ret = clk_enable(phy->wkupclk);
- if (ret) {
- dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
- goto err2;
- }
-
- return 0;
-
-err2:
- clk_disable(phy->optclk);
-
-err1:
- return ret;
-}
-
-static const struct dev_pm_ops omap_usb3_pm_ops = {
- SET_RUNTIME_PM_OPS(omap_usb3_runtime_suspend, omap_usb3_runtime_resume,
- NULL)
-};
-
-#define DEV_PM_OPS (&omap_usb3_pm_ops)
-#else
-#define DEV_PM_OPS NULL
-#endif
-
-#ifdef CONFIG_OF
-static const struct of_device_id omap_usb3_id_table[] = {
- { .compatible = "ti,omap-usb3" },
- {}
-};
-MODULE_DEVICE_TABLE(of, omap_usb3_id_table);
-#endif
-
-static struct platform_driver omap_usb3_driver = {
- .probe = omap_usb3_probe,
- .remove = omap_usb3_remove,
- .driver = {
- .name = "omap-usb3",
- .owner = THIS_MODULE,
- .pm = DEV_PM_OPS,
- .of_match_table = of_match_ptr(omap_usb3_id_table),
- },
-};
-
-module_platform_driver(omap_usb3_driver);
-
-MODULE_ALIAS("platform: omap_usb3");
-MODULE_AUTHOR("Texas Instruments Inc.");
-MODULE_DESCRIPTION("OMAP USB3 phy driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/phy-rcar-gen2-usb.c b/drivers/usb/phy/phy-rcar-gen2-usb.c
index 551e0a6c0e22..388d89f6b141 100644
--- a/drivers/usb/phy/phy-rcar-gen2-usb.c
+++ b/drivers/usb/phy/phy-rcar-gen2-usb.c
@@ -177,15 +177,15 @@ static int rcar_gen2_usb_phy_probe(struct platform_device *pdev)
struct clk *clk;
int retval;
- pdata = dev_get_platdata(&pdev->dev);
+ pdata = dev_get_platdata(dev);
if (!pdata) {
dev_err(dev, "No platform data\n");
return -EINVAL;
}
- clk = devm_clk_get(&pdev->dev, "usbhs");
+ clk = devm_clk_get(dev, "usbhs");
if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "Can't get the clock\n");
+ dev_err(dev, "Can't get the clock\n");
return PTR_ERR(clk);
}
diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c
index 214172b68d5d..04778cf80d60 100644
--- a/drivers/usb/phy/phy-twl6030-usb.c
+++ b/drivers/usb/phy/phy-twl6030-usb.c
@@ -27,7 +27,7 @@
#include <linux/io.h>
#include <linux/usb/musb-omap.h>
#include <linux/usb/phy_companion.h>
-#include <linux/usb/omap_usb.h>
+#include <linux/phy/omap_usb.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
diff --git a/drivers/usb/phy/phy-ulpi.c b/drivers/usb/phy/phy-ulpi.c
index 217339dd7a90..17ea3f271bd8 100644
--- a/drivers/usb/phy/phy-ulpi.c
+++ b/drivers/usb/phy/phy-ulpi.c
@@ -47,6 +47,8 @@ struct ulpi_info {
static struct ulpi_info ulpi_ids[] = {
ULPI_INFO(ULPI_ID(0x04cc, 0x1504), "NXP ISP1504"),
ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"),
+ ULPI_INFO(ULPI_ID(0x0424, 0x0007), "SMSC USB3320"),
+ ULPI_INFO(ULPI_ID(0x0451, 0x1507), "TI TUSB1210"),
};
static int ulpi_set_otg_flags(struct usb_phy *phy)
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 82371f61f23d..2d72aa3564a3 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -323,11 +323,11 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
if (r)
goto out;
- dev_dbg(&port->dev, "%s - submitting interrupt urb", __func__);
+ dev_dbg(&port->dev, "%s - submitting interrupt urb\n", __func__);
r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (r) {
- dev_err(&port->dev, "%s - failed submitting interrupt urb,"
- " error %d\n", __func__, r);
+ dev_err(&port->dev, "%s - failed to submit interrupt urb: %d\n",
+ __func__, r);
ch341_close(port);
goto out;
}
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 0ac3b3b3236c..2916dea3ede8 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -220,7 +220,7 @@ static int cyberjack_write(struct tty_struct *tty,
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
dev_err(&port->dev,
- "%s - failed submitting write urb, error %d",
+ "%s - failed submitting write urb, error %d\n",
__func__, result);
/* Throw away data. No better idea what to do with it. */
priv->wrfilled = 0;
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index bccb1223143a..01bf53392819 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -279,7 +279,7 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)
* the generic firmware, but are not used with
* NMEA and SiRF protocols */
dev_dbg(&port->dev,
- "%s - failed setting baud rate, unsupported speed of %d on Earthmate GPS",
+ "%s - failed setting baud rate, unsupported speed of %d on Earthmate GPS\n",
__func__, new_rate);
return -1;
}
@@ -1224,7 +1224,6 @@ static void cypress_write_int_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
struct cypress_private *priv = usb_get_serial_port_data(port);
struct device *dev = &urb->dev->dev;
- int result;
int status = urb->status;
switch (status) {
@@ -1239,21 +1238,9 @@ static void cypress_write_int_callback(struct urb *urb)
__func__, status);
priv->write_urb_in_use = 0;
return;
- case -EPIPE: /* no break needed; clear halt and resubmit */
- if (!priv->comm_is_ok)
- break;
- usb_clear_halt(port->serial->dev, 0x02);
- /* error in the urb, so we have to resubmit it */
- dev_dbg(dev, "%s - nonzero write bulk status received: %d\n",
- __func__, status);
- port->interrupt_out_urb->transfer_buffer_length = 1;
- result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
- if (!result)
- return;
- dev_err(dev, "%s - failed resubmitting write urb, error %d\n",
- __func__, result);
- cypress_set_dead(port);
- break;
+ case -EPIPE:
+ /* Cannot call usb_clear_halt while in_interrupt */
+ /* FALLTHROUGH */
default:
dev_err(dev, "%s - unexpected nonzero write status received: %d\n",
__func__, status);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index ee1f00f03c43..44ab12986805 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -907,6 +907,8 @@ static const struct usb_device_id id_table_combined[] = {
/* Crucible Devices */
{ USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_Z3X_PID) },
+ /* Cressi Devices */
+ { USB_DEVICE(FTDI_VID, FTDI_CRESSI_PID) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 1e2d369df86e..e599fbfcde5f 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -1320,3 +1320,9 @@
* Manufacturer: Smart GSM Team
*/
#define FTDI_Z3X_PID 0x0011
+
+/*
+ * Product: Cressi PC Interface
+ * Manufacturer: Cressi
+ */
+#define FTDI_CRESSI_PID 0x87d0
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index b63ce023f96f..1bd192290b08 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -332,9 +332,9 @@ void usb_serial_generic_process_read_urb(struct urb *urb)
* stuff like 3G modems, so shortcircuit it in the 99.9999999% of
* cases where the USB serial is not a console anyway.
*/
- if (!port->port.console || !port->sysrq)
+ if (!port->port.console || !port->sysrq) {
tty_insert_flip_string(&port->port, ch, urb->actual_length);
- else {
+ } else {
for (i = 0; i < urb->actual_length; i++, ch++) {
if (!usb_serial_handle_sysrq_char(port, *ch))
tty_insert_flip_char(&port->port, *ch, TTY_NORMAL);
@@ -359,24 +359,38 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i,
urb->actual_length);
-
- if (urb->status) {
- dev_dbg(&port->dev, "%s - non-zero urb status: %d\n",
- __func__, urb->status);
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ dev_dbg(&port->dev, "%s - urb stopped: %d\n",
+ __func__, urb->status);
return;
+ case -EPIPE:
+ dev_err(&port->dev, "%s - urb stopped: %d\n",
+ __func__, urb->status);
+ return;
+ default:
+ dev_err(&port->dev, "%s - nonzero urb status: %d\n",
+ __func__, urb->status);
+ goto resubmit;
}
usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
port->serial->type->process_read_urb(urb);
+resubmit:
/* Throttle the device if requested by tty */
spin_lock_irqsave(&port->lock, flags);
port->throttled = port->throttle_req;
if (!port->throttled) {
spin_unlock_irqrestore(&port->lock, flags);
usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC);
- } else
+ } else {
spin_unlock_irqrestore(&port->lock, flags);
+ }
}
EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
@@ -384,29 +398,38 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
{
unsigned long flags;
struct usb_serial_port *port = urb->context;
- int status = urb->status;
int i;
- for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+ for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {
if (port->write_urbs[i] == urb)
break;
-
+ }
spin_lock_irqsave(&port->lock, flags);
port->tx_bytes -= urb->transfer_buffer_length;
set_bit(i, &port->write_urbs_free);
spin_unlock_irqrestore(&port->lock, flags);
- if (status) {
- dev_dbg(&port->dev, "%s - non-zero urb status: %d\n",
- __func__, status);
-
- spin_lock_irqsave(&port->lock, flags);
- kfifo_reset_out(&port->write_fifo);
- spin_unlock_irqrestore(&port->lock, flags);
- } else {
- usb_serial_generic_write_start(port, GFP_ATOMIC);
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ dev_dbg(&port->dev, "%s - urb stopped: %d\n",
+ __func__, urb->status);
+ return;
+ case -EPIPE:
+ dev_err_console(port, "%s - urb stopped: %d\n",
+ __func__, urb->status);
+ return;
+ default:
+ dev_err_console(port, "%s - nonzero urb status: %d\n",
+ __func__, urb->status);
+ goto resubmit;
}
+resubmit:
+ usb_serial_generic_write_start(port, GFP_ATOMIC);
usb_serial_port_softint(port);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback);
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index d00dae17d520..5ad4a0fb4b26 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -1151,7 +1151,7 @@ static ssize_t vcc_mode_store(struct device *dev,
goto fail_store_vcc_mode;
}
- dev_dbg(dev, "%s: setting vcc_mode = %ld", __func__, v);
+ dev_dbg(dev, "%s: setting vcc_mode = %ld\n", __func__, v);
if ((v != 3) && (v != 5)) {
dev_err(dev, "%s - vcc_mode %ld is invalid\n", __func__, v);
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 265c6776b081..d3acaead5a81 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -397,17 +397,6 @@ static void usa26_instat_callback(struct urb *urb)
msg = (struct keyspan_usa26_portStatusMessage *)data;
-#if 0
- dev_dbg(&urb->dev->dev,
- "%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
- __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr,
- msg->ri, msg->_txOff, msg->_txXoff, msg->rxEnabled,
- msg->controlResponse);
-#endif
-
- /* Now do something useful with the data */
-
-
/* Check port number from message and retrieve private data */
if (msg->port >= serial->num_ports) {
dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
@@ -523,9 +512,6 @@ static void usa28_instat_callback(struct urb *urb)
goto exit;
}
- /*dev_dbg(&urb->dev->dev, "%s %12ph", __func__, data);*/
-
- /* Now do something useful with the data */
msg = (struct keyspan_usa28_portStatusMessage *)data;
/* Check port number from message and retrieve private data */
@@ -605,9 +591,6 @@ static void usa49_instat_callback(struct urb *urb)
goto exit;
}
- /*dev_dbg(&urb->dev->dev, "%s: %11ph", __func__, data);*/
-
- /* Now do something useful with the data */
msg = (struct keyspan_usa49_portStatusMessage *)data;
/* Check port number from message and retrieve private data */
@@ -1793,12 +1776,6 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err != 0)
dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
-#if 0
- else {
- dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__,
- this_urb->transfer_buffer_length);
- }
-#endif
return 0;
}
@@ -1976,13 +1953,6 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err != 0)
dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
-#if 0
- else {
- dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__,
- outcont_urb, this_urb->transfer_buffer_length,
- usb_pipeendpoint(this_urb->pipe));
- }
-#endif
return 0;
}
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index e972412b614b..742d827f876c 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -189,7 +189,7 @@ exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
dev_err(&port->dev,
- "%s - usb_submit_urb failed with result %d",
+ "%s - usb_submit_urb failed with result %d\n",
__func__, retval);
}
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index c88cc4966b23..d7440b7557af 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -201,7 +201,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
else {
status = get_unaligned_le16(status_buf);
- dev_info(&port->serial->dev->dev, "read status %x %x",
+ dev_info(&port->serial->dev->dev, "read status %x %x\n",
status_buf[0], status_buf[1]);
*line_state_p = klsi_105_status2linestate(status);
@@ -464,7 +464,7 @@ static void klsi_105_set_termios(struct tty_struct *tty,
priv->cfg.baudrate = kl5kusb105a_sio_b115200;
break;
default:
- dev_dbg(dev, "KLSI USB->Serial converter: unsupported baudrate request, using default of 9600");
+ dev_dbg(dev, "unsupported baudrate, using 9600\n");
priv->cfg.baudrate = kl5kusb105a_sio_b9600;
baud = 9600;
break;
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 618c1c1f227e..fee242387f55 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -557,7 +557,8 @@ static int kobil_ioctl(struct tty_struct *tty,
);
dev_dbg(&port->dev,
- "%s - Send reset_all_queues (FLUSH) URB returns: %i", __func__, result);
+ "%s - Send reset_all_queues (FLUSH) URB returns: %i\n",
+ __func__, result);
kfree(transfer_buffer);
return (result < 0) ? -EIO: 0;
default:
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 4eb277225a77..dfd728a263d2 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -209,7 +209,7 @@ static int write_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,
index, NULL, 0, MOS_WDR_TIMEOUT);
if (status < 0)
dev_err(&usbdev->dev,
- "mos7720: usb_control_msg() failed: %d", status);
+ "mos7720: usb_control_msg() failed: %d\n", status);
return status;
}
@@ -240,7 +240,7 @@ static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,
*data = *buf;
else if (status < 0)
dev_err(&usbdev->dev,
- "mos7720: usb_control_msg() failed: %d", status);
+ "mos7720: usb_control_msg() failed: %d\n", status);
kfree(buf);
return status;
@@ -399,7 +399,7 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
&mos_parport->deferred_urbs);
spin_unlock_irqrestore(&mos_parport->listlock, flags);
tasklet_schedule(&mos_parport->urb_tasklet);
- dev_dbg(&usbdev->dev, "tasklet scheduled");
+ dev_dbg(&usbdev->dev, "tasklet scheduled\n");
return 0;
}
@@ -418,7 +418,7 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
mutex_unlock(&serial->disc_mutex);
if (ret_val) {
dev_err(&usbdev->dev,
- "%s: submit_urb() failed: %d", __func__, ret_val);
+ "%s: submit_urb() failed: %d\n", __func__, ret_val);
spin_lock_irqsave(&mos_parport->listlock, flags);
list_del(&urbtrack->urblist_entry);
spin_unlock_irqrestore(&mos_parport->listlock, flags);
@@ -656,7 +656,7 @@ static size_t parport_mos7715_write_compat(struct parport *pp,
parport_epilogue(pp);
if (retval) {
dev_err(&mos_parport->serial->dev->dev,
- "mos7720: usb_bulk_msg() failed: %d", retval);
+ "mos7720: usb_bulk_msg() failed: %d\n", retval);
return 0;
}
return actual_len;
@@ -875,7 +875,7 @@ static void mos7715_interrupt_callback(struct urb *urb)
if (!(iir & 0x01)) { /* serial port interrupt pending */
switch (iir & 0x0f) {
case SERIAL_IIR_RLS:
- dev_dbg(dev, "Serial Port: Receiver status error or address bit detected in 9-bit mode\n\n");
+ dev_dbg(dev, "Serial Port: Receiver status error or address bit detected in 9-bit mode\n");
break;
case SERIAL_IIR_CTI:
dev_dbg(dev, "Serial Port: Receiver time out\n");
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index e9d967ff521b..393be562d875 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -522,11 +522,11 @@ static void mos7840_set_led_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* This urb is terminated, clean up */
- dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d",
+ dev_dbg(&urb->dev->dev, "%s - urb shutting down: %d\n",
__func__, urb->status);
break;
default:
- dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d",
+ dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n",
__func__, urb->status);
}
}
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 216d20affba8..68fc9fe65936 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1526,7 +1526,8 @@ static const struct usb_device_id option_ids[] = {
/* Cinterion */
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) },
- { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) },
+ { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX),
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index 7725ed261ed6..504f5bff79c0 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -372,7 +372,7 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
device_port, data, 2, QT2_USB_TIMEOUT);
if (status < 0) {
- dev_err(&port->dev, "%s - open port failed %i", __func__,
+ dev_err(&port->dev, "%s - open port failed %i\n", __func__,
status);
kfree(data);
return status;
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 4ec04f73c800..ef0dbf0703c5 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -220,9 +220,9 @@ static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status)
GET_UART_STATUS, GET_UART_STATUS_TYPE,
0, GET_UART_STATUS_MSR, buf, 1, 100);
if (ret < 0)
- dev_err(&port->dev, "failed to get modem status: %d", ret);
+ dev_err(&port->dev, "failed to get modem status: %d\n", ret);
- dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x", ret, *buf);
+ dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x\n", ret, *buf);
*status = *buf;
kfree(buf);
@@ -342,8 +342,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
case 1000000:
buf[0] = 0x0b; break;
default:
- dev_err(&port->dev, "spcp825 driver does not support the "
- "baudrate requested, using default of 9600.\n");
+ dev_err(&port->dev, "unsupported baudrate, using 9600\n");
}
/* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index 9fa7dd413e83..8fceec7298e0 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -74,9 +74,7 @@ static void symbol_int_callback(struct urb *urb)
tty_insert_flip_string(&port->port, &data[1], data_length);
tty_flip_buffer_push(&port->port);
} else {
- dev_dbg(&port->dev,
- "Improper amount of data received from the device, "
- "%d bytes", urb->actual_length);
+ dev_dbg(&port->dev, "%s - short packet\n", __func__);
}
exit:
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index ec7cea585663..3dd3ff8c50d3 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -293,7 +293,7 @@ static int ti_startup(struct usb_serial *serial)
int status;
dev_dbg(&dev->dev,
- "%s - product 0x%4X, num configurations %d, configuration value %d",
+ "%s - product 0x%4X, num configurations %d, configuration value %d\n",
__func__, le16_to_cpu(dev->descriptor.idProduct),
dev->descriptor.bNumConfigurations,
dev->actconfig->desc.bConfigurationValue);
@@ -803,7 +803,7 @@ static void ti_set_termios(struct tty_struct *tty,
tty_encode_baud_rate(tty, baud, baud);
dev_dbg(&port->dev,
- "%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d",
+ "%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d\n",
__func__, baud, config->wBaudRate, config->wFlags,
config->bDataBits, config->bParity, config->bStopBits,
config->cXon, config->cXoff, config->bUartMode);
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 7c9dc28640bb..81fc0dfcfdcf 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -868,7 +868,7 @@ static int usb_serial_probe(struct usb_interface *interface,
max_endpoints = max(max_endpoints, (int)serial->num_ports);
serial->num_port_pointers = max_endpoints;
- dev_dbg(ddev, "setting up %d port structures for this device", max_endpoints);
+ dev_dbg(ddev, "setting up %d port structure(s)\n", max_endpoints);
for (i = 0; i < max_endpoints; ++i) {
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
if (!port)
@@ -923,9 +923,8 @@ static int usb_serial_probe(struct usb_interface *interface,
port = serial->port[i];
if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
goto probe_error;
- buffer_size = serial->type->bulk_out_size;
- if (!buffer_size)
- buffer_size = usb_endpoint_maxp(endpoint);
+ buffer_size = max_t(int, serial->type->bulk_out_size,
+ usb_endpoint_maxp(endpoint));
port->bulk_out_size = buffer_size;
port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
@@ -1034,7 +1033,7 @@ static int usb_serial_probe(struct usb_interface *interface,
for (i = 0; i < num_ports; ++i) {
port = serial->port[i];
dev_set_name(&port->dev, "ttyUSB%d", port->minor);
- dev_dbg(ddev, "registering %s", dev_name(&port->dev));
+ dev_dbg(ddev, "registering %s\n", dev_name(&port->dev));
device_enable_async_suspend(&port->dev);
retval = device_add(&port->dev);
@@ -1161,9 +1160,9 @@ static int usb_serial_reset_resume(struct usb_interface *intf)
usb_serial_unpoison_port_urbs(serial);
serial->suspending = 0;
- if (serial->type->reset_resume)
+ if (serial->type->reset_resume) {
rv = serial->type->reset_resume(serial);
- else {
+ } else {
rv = -EOPNOTSUPP;
intf->needs_binding = 1;
}
@@ -1338,9 +1337,9 @@ static int usb_serial_register(struct usb_serial_driver *driver)
if (retval) {
pr_err("problem %d when registering driver %s\n", retval, driver->description);
list_del(&driver->driver_list);
- } else
+ } else {
pr_info("USB Serial support registered for %s\n", driver->description);
-
+ }
mutex_unlock(&table_lock);
return retval;
}
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index 1dd0604d1911..13b5bfbaf951 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -204,7 +204,7 @@ config USB_STORAGE_ENE_UB6250
config USB_UAS
tristate "USB Attached SCSI"
- depends on SCSI && BROKEN
+ depends on SCSI && USB_STORAGE
help
The USB Attached SCSI protocol is supported by some USB
storage devices. It permits higher performance by supporting
diff --git a/drivers/usb/storage/uas-detect.h b/drivers/usb/storage/uas-detect.h
new file mode 100644
index 000000000000..bb05b984d5f6
--- /dev/null
+++ b/drivers/usb/storage/uas-detect.h
@@ -0,0 +1,96 @@
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include "usb.h"
+
+static int uas_is_interface(struct usb_host_interface *intf)
+{
+ return (intf->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE &&
+ intf->desc.bInterfaceSubClass == USB_SC_SCSI &&
+ intf->desc.bInterfaceProtocol == USB_PR_UAS);
+}
+
+static int uas_isnt_supported(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ dev_warn(&udev->dev, "The driver for the USB controller %s does not "
+ "support scatter-gather which is\n",
+ hcd->driver->description);
+ dev_warn(&udev->dev, "required by the UAS driver. Please try an"
+ "alternative USB controller if you wish to use UAS.\n");
+ return -ENODEV;
+}
+
+static int uas_find_uas_alt_setting(struct usb_interface *intf)
+{
+ int i;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int sg_supported = udev->bus->sg_tablesize != 0;
+
+ for (i = 0; i < intf->num_altsetting; i++) {
+ struct usb_host_interface *alt = &intf->altsetting[i];
+
+ if (uas_is_interface(alt)) {
+ if (!sg_supported)
+ return uas_isnt_supported(udev);
+ return alt->desc.bAlternateSetting;
+ }
+ }
+
+ return -ENODEV;
+}
+
+static int uas_find_endpoints(struct usb_host_interface *alt,
+ struct usb_host_endpoint *eps[])
+{
+ struct usb_host_endpoint *endpoint = alt->endpoint;
+ unsigned i, n_endpoints = alt->desc.bNumEndpoints;
+
+ for (i = 0; i < n_endpoints; i++) {
+ unsigned char *extra = endpoint[i].extra;
+ int len = endpoint[i].extralen;
+ while (len >= 3) {
+ if (extra[1] == USB_DT_PIPE_USAGE) {
+ unsigned pipe_id = extra[2];
+ if (pipe_id > 0 && pipe_id < 5)
+ eps[pipe_id - 1] = &endpoint[i];
+ break;
+ }
+ len -= extra[0];
+ extra += extra[0];
+ }
+ }
+
+ if (!eps[0] || !eps[1] || !eps[2] || !eps[3])
+ return -ENODEV;
+
+ return 0;
+}
+
+static int uas_use_uas_driver(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_host_endpoint *eps[4] = { };
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ unsigned long flags = id->driver_info;
+ int r, alt;
+
+ usb_stor_adjust_quirks(udev, &flags);
+
+ if (flags & US_FL_IGNORE_UAS)
+ return 0;
+
+ if (udev->speed >= USB_SPEED_SUPER && !hcd->can_do_streams)
+ return 0;
+
+ alt = uas_find_uas_alt_setting(intf);
+ if (alt < 0)
+ return 0;
+
+ r = uas_find_endpoints(&intf->altsetting[alt], eps);
+ if (r < 0)
+ return 0;
+
+ return 1;
+}
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index d966b59f7d7b..a7ac97cc5949 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -2,6 +2,7 @@
* USB Attached SCSI
* Note that this is not the same as the USB Mass Storage driver
*
+ * Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013
* Copyright Matthew Wilcox for Intel Corp, 2010
* Copyright Sarah Sharp for Intel Corp, 2010
*
@@ -13,17 +14,21 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/usb.h>
+#include <linux/usb_usual.h>
#include <linux/usb/hcd.h>
#include <linux/usb/storage.h>
#include <linux/usb/uas.h>
#include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
+#include "uas-detect.h"
+
/*
* The r00-r01c specs define this version of the SENSE IU data structure.
* It's still in use by several different firmware releases.
@@ -45,12 +50,17 @@ struct uas_dev_info {
struct usb_anchor sense_urbs;
struct usb_anchor data_urbs;
int qdepth, resetting;
- struct response_ui response;
+ struct response_iu response;
unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
unsigned use_streams:1;
unsigned uas_sense_old:1;
+ unsigned running_task:1;
+ unsigned shutdown:1;
struct scsi_cmnd *cmnd;
spinlock_t lock;
+ struct work_struct work;
+ struct list_head inflight_list;
+ struct list_head dead_list;
};
enum {
@@ -85,103 +95,117 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
struct uas_dev_info *devinfo, gfp_t gfp);
static void uas_do_work(struct work_struct *work);
static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
+static void uas_free_streams(struct uas_dev_info *devinfo);
+static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller);
-static DECLARE_WORK(uas_work, uas_do_work);
-static DEFINE_SPINLOCK(uas_work_lock);
-static LIST_HEAD(uas_work_list);
-
+/* Must be called with devinfo->lock held, will temporary unlock the lock */
static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
- struct uas_cmd_info *cmdinfo)
+ struct uas_cmd_info *cmdinfo,
+ unsigned long *lock_flags)
{
- unsigned long flags;
-
/*
* The UNLINK_DATA_URBS flag makes sure uas_try_complete
* (called by urb completion) doesn't release cmdinfo
* underneath us.
*/
- spin_lock_irqsave(&devinfo->lock, flags);
cmdinfo->state |= UNLINK_DATA_URBS;
- spin_unlock_irqrestore(&devinfo->lock, flags);
+ spin_unlock_irqrestore(&devinfo->lock, *lock_flags);
if (cmdinfo->data_in_urb)
usb_unlink_urb(cmdinfo->data_in_urb);
if (cmdinfo->data_out_urb)
usb_unlink_urb(cmdinfo->data_out_urb);
- spin_lock_irqsave(&devinfo->lock, flags);
+ spin_lock_irqsave(&devinfo->lock, *lock_flags);
cmdinfo->state &= ~UNLINK_DATA_URBS;
- spin_unlock_irqrestore(&devinfo->lock, flags);
}
static void uas_do_work(struct work_struct *work)
{
+ struct uas_dev_info *devinfo =
+ container_of(work, struct uas_dev_info, work);
struct uas_cmd_info *cmdinfo;
- struct uas_cmd_info *temp;
- struct list_head list;
unsigned long flags;
int err;
- spin_lock_irq(&uas_work_lock);
- list_replace_init(&uas_work_list, &list);
- spin_unlock_irq(&uas_work_lock);
-
- list_for_each_entry_safe(cmdinfo, temp, &list, list) {
+ spin_lock_irqsave(&devinfo->lock, flags);
+ list_for_each_entry(cmdinfo, &devinfo->inflight_list, list) {
struct scsi_pointer *scp = (void *)cmdinfo;
- struct scsi_cmnd *cmnd = container_of(scp,
- struct scsi_cmnd, SCp);
- struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
- spin_lock_irqsave(&devinfo->lock, flags);
- err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
+ struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
+ SCp);
+
+ if (!(cmdinfo->state & IS_IN_WORK_LIST))
+ continue;
+
+ err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
if (!err)
cmdinfo->state &= ~IS_IN_WORK_LIST;
- spin_unlock_irqrestore(&devinfo->lock, flags);
- if (err) {
- list_del(&cmdinfo->list);
- spin_lock_irq(&uas_work_lock);
- list_add_tail(&cmdinfo->list, &uas_work_list);
- spin_unlock_irq(&uas_work_lock);
- schedule_work(&uas_work);
- }
+ else
+ schedule_work(&devinfo->work);
}
+ spin_unlock_irqrestore(&devinfo->lock, flags);
}
-static void uas_abort_work(struct uas_dev_info *devinfo)
+static void uas_mark_cmd_dead(struct uas_dev_info *devinfo,
+ struct uas_cmd_info *cmdinfo,
+ int result, const char *caller)
+{
+ struct scsi_pointer *scp = (void *)cmdinfo;
+ struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp);
+
+ uas_log_cmd_state(cmnd, caller);
+ WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
+ WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
+ cmdinfo->state |= COMMAND_ABORTED;
+ cmdinfo->state &= ~IS_IN_WORK_LIST;
+ cmnd->result = result << 16;
+ list_move_tail(&cmdinfo->list, &devinfo->dead_list);
+}
+
+static void uas_abort_inflight(struct uas_dev_info *devinfo, int result,
+ const char *caller)
{
struct uas_cmd_info *cmdinfo;
struct uas_cmd_info *temp;
- struct list_head list;
unsigned long flags;
- spin_lock_irq(&uas_work_lock);
- list_replace_init(&uas_work_list, &list);
- spin_unlock_irq(&uas_work_lock);
+ spin_lock_irqsave(&devinfo->lock, flags);
+ list_for_each_entry_safe(cmdinfo, temp, &devinfo->inflight_list, list)
+ uas_mark_cmd_dead(devinfo, cmdinfo, result, caller);
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+}
+
+static void uas_add_work(struct uas_cmd_info *cmdinfo)
+{
+ struct scsi_pointer *scp = (void *)cmdinfo;
+ struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp);
+ struct uas_dev_info *devinfo = cmnd->device->hostdata;
+
+ WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
+ cmdinfo->state |= IS_IN_WORK_LIST;
+ schedule_work(&devinfo->work);
+}
+
+static void uas_zap_dead(struct uas_dev_info *devinfo)
+{
+ struct uas_cmd_info *cmdinfo;
+ struct uas_cmd_info *temp;
+ unsigned long flags;
spin_lock_irqsave(&devinfo->lock, flags);
- list_for_each_entry_safe(cmdinfo, temp, &list, list) {
+ list_for_each_entry_safe(cmdinfo, temp, &devinfo->dead_list, list) {
struct scsi_pointer *scp = (void *)cmdinfo;
- struct scsi_cmnd *cmnd = container_of(scp,
- struct scsi_cmnd, SCp);
- struct uas_dev_info *di = (void *)cmnd->device->hostdata;
-
- if (di == devinfo) {
- cmdinfo->state |= COMMAND_ABORTED;
- cmdinfo->state &= ~IS_IN_WORK_LIST;
- if (devinfo->resetting) {
- /* uas_stat_cmplt() will not do that
- * when a device reset is in
- * progress */
- cmdinfo->state &= ~COMMAND_INFLIGHT;
- }
- uas_try_complete(cmnd, __func__);
- } else {
- /* not our uas device, relink into list */
- list_del(&cmdinfo->list);
- spin_lock_irq(&uas_work_lock);
- list_add_tail(&cmdinfo->list, &uas_work_list);
- spin_unlock_irq(&uas_work_lock);
- }
+ struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
+ SCp);
+ uas_log_cmd_state(cmnd, __func__);
+ WARN_ON_ONCE(!(cmdinfo->state & COMMAND_ABORTED));
+ /* all urbs are killed, clear inflight bits */
+ cmdinfo->state &= ~(COMMAND_INFLIGHT |
+ DATA_IN_URB_INFLIGHT |
+ DATA_OUT_URB_INFLIGHT);
+ uas_try_complete(cmnd, __func__);
}
+ devinfo->running_task = 0;
spin_unlock_irqrestore(&devinfo->lock, flags);
}
@@ -259,20 +283,19 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
- WARN_ON(!spin_is_locked(&devinfo->lock));
+ WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
if (cmdinfo->state & (COMMAND_INFLIGHT |
DATA_IN_URB_INFLIGHT |
DATA_OUT_URB_INFLIGHT |
UNLINK_DATA_URBS))
return -EBUSY;
- BUG_ON(cmdinfo->state & COMMAND_COMPLETED);
+ WARN_ON_ONCE(cmdinfo->state & COMMAND_COMPLETED);
cmdinfo->state |= COMMAND_COMPLETED;
usb_free_urb(cmdinfo->data_in_urb);
usb_free_urb(cmdinfo->data_out_urb);
- if (cmdinfo->state & COMMAND_ABORTED) {
+ if (cmdinfo->state & COMMAND_ABORTED)
scmd_printk(KERN_INFO, cmnd, "abort completed\n");
- cmnd->result = DID_ABORT << 16;
- }
+ list_del(&cmdinfo->list);
cmnd->scsi_done(cmnd);
return 0;
}
@@ -286,11 +309,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
cmdinfo->state |= direction | SUBMIT_STATUS_URB;
err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
if (err) {
- spin_lock(&uas_work_lock);
- list_add_tail(&cmdinfo->list, &uas_work_list);
- cmdinfo->state |= IS_IN_WORK_LIST;
- spin_unlock(&uas_work_lock);
- schedule_work(&uas_work);
+ uas_add_work(cmdinfo);
}
}
@@ -298,14 +317,20 @@ static void uas_stat_cmplt(struct urb *urb)
{
struct iu *iu = urb->transfer_buffer;
struct Scsi_Host *shost = urb->context;
- struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
struct scsi_cmnd *cmnd;
struct uas_cmd_info *cmdinfo;
unsigned long flags;
u16 tag;
if (urb->status) {
- dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status);
+ if (urb->status == -ENOENT) {
+ dev_err(&urb->dev->dev, "stat urb: killed, stream %d\n",
+ urb->stream_id);
+ } else {
+ dev_err(&urb->dev->dev, "stat urb: status %d\n",
+ urb->status);
+ }
usb_free_urb(urb);
return;
}
@@ -324,6 +349,9 @@ static void uas_stat_cmplt(struct urb *urb)
if (!cmnd) {
if (iu->iu_id == IU_ID_RESPONSE) {
+ if (!devinfo->running_task)
+ dev_warn(&urb->dev->dev,
+ "stat urb: recv unexpected response iu\n");
/* store results for uas_eh_task_mgmt() */
memcpy(&devinfo->response, iu, sizeof(devinfo->response));
}
@@ -346,17 +374,25 @@ static void uas_stat_cmplt(struct urb *urb)
uas_sense(urb, cmnd);
if (cmnd->result != 0) {
/* cancel data transfers on error */
- spin_unlock_irqrestore(&devinfo->lock, flags);
- uas_unlink_data_urbs(devinfo, cmdinfo);
- spin_lock_irqsave(&devinfo->lock, flags);
+ uas_unlink_data_urbs(devinfo, cmdinfo, &flags);
}
cmdinfo->state &= ~COMMAND_INFLIGHT;
uas_try_complete(cmnd, __func__);
break;
case IU_ID_READ_READY:
+ if (!cmdinfo->data_in_urb ||
+ (cmdinfo->state & DATA_IN_URB_INFLIGHT)) {
+ scmd_printk(KERN_ERR, cmnd, "unexpected read rdy\n");
+ break;
+ }
uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB);
break;
case IU_ID_WRITE_READY:
+ if (!cmdinfo->data_out_urb ||
+ (cmdinfo->state & DATA_OUT_URB_INFLIGHT)) {
+ scmd_printk(KERN_ERR, cmnd, "unexpected write rdy\n");
+ break;
+ }
uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);
break;
default:
@@ -383,8 +419,15 @@ static void uas_data_cmplt(struct urb *urb)
sdb = scsi_out(cmnd);
cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT;
}
- BUG_ON(sdb == NULL);
- if (urb->status) {
+ if (sdb == NULL) {
+ WARN_ON_ONCE(1);
+ } else if (urb->status) {
+ if (urb->status != -ECONNRESET) {
+ uas_log_cmd_state(cmnd, __func__);
+ scmd_printk(KERN_ERR, cmnd,
+ "data cmplt err %d stream %d\n",
+ urb->status, urb->stream_id);
+ }
/* error: no data transfered */
sdb->resid = sdb->length;
} else {
@@ -394,6 +437,17 @@ static void uas_data_cmplt(struct urb *urb)
spin_unlock_irqrestore(&devinfo->lock, flags);
}
+static void uas_cmd_cmplt(struct urb *urb)
+{
+ struct scsi_cmnd *cmnd = urb->context;
+
+ if (urb->status) {
+ uas_log_cmd_state(cmnd, __func__);
+ scmd_printk(KERN_ERR, cmnd, "cmd cmplt err %d\n", urb->status);
+ }
+ usb_free_urb(urb);
+}
+
static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
unsigned int pipe, u16 stream_id,
struct scsi_cmnd *cmnd,
@@ -408,8 +462,7 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
goto out;
usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
uas_data_cmplt, cmnd);
- if (devinfo->use_streams)
- urb->stream_id = stream_id;
+ urb->stream_id = stream_id;
urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
urb->sg = sdb->table.sgl;
out:
@@ -442,7 +495,7 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
}
static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
- struct scsi_cmnd *cmnd, u16 stream_id)
+ struct scsi_cmnd *cmnd)
{
struct usb_device *udev = devinfo->udev;
struct scsi_device *sdev = cmnd->device;
@@ -472,7 +525,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);
usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu) + len,
- usb_free_urb, NULL);
+ uas_cmd_cmplt, cmnd);
urb->transfer_flags |= URB_FREE_BUFFER;
out:
return urb;
@@ -512,13 +565,17 @@ static int uas_submit_task_urb(struct scsi_cmnd *cmnd, gfp_t gfp,
}
usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu),
- usb_free_urb, NULL);
+ uas_cmd_cmplt, cmnd);
urb->transfer_flags |= URB_FREE_BUFFER;
+ usb_anchor_urb(urb, &devinfo->cmd_urbs);
err = usb_submit_urb(urb, gfp);
- if (err)
+ if (err) {
+ usb_unanchor_urb(urb);
+ uas_log_cmd_state(cmnd, __func__);
+ scmd_printk(KERN_ERR, cmnd, "task submission err %d\n", err);
goto err;
- usb_anchor_urb(urb, &devinfo->cmd_urbs);
+ }
return 0;
@@ -533,38 +590,43 @@ err:
* daft to me.
*/
-static int uas_submit_sense_urb(struct Scsi_Host *shost,
- gfp_t gfp, unsigned int stream)
+static struct urb *uas_submit_sense_urb(struct scsi_cmnd *cmnd,
+ gfp_t gfp, unsigned int stream)
{
- struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
struct urb *urb;
+ int err;
urb = uas_alloc_sense_urb(devinfo, gfp, shost, stream);
if (!urb)
- return SCSI_MLQUEUE_DEVICE_BUSY;
- if (usb_submit_urb(urb, gfp)) {
+ return NULL;
+ usb_anchor_urb(urb, &devinfo->sense_urbs);
+ err = usb_submit_urb(urb, gfp);
+ if (err) {
+ usb_unanchor_urb(urb);
+ uas_log_cmd_state(cmnd, __func__);
shost_printk(KERN_INFO, shost,
- "sense urb submission failure\n");
+ "sense urb submission error %d stream %d\n",
+ err, stream);
usb_free_urb(urb);
- return SCSI_MLQUEUE_DEVICE_BUSY;
+ return NULL;
}
- usb_anchor_urb(urb, &devinfo->sense_urbs);
- return 0;
+ return urb;
}
static int uas_submit_urbs(struct scsi_cmnd *cmnd,
struct uas_dev_info *devinfo, gfp_t gfp)
{
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+ struct urb *urb;
int err;
- WARN_ON(!spin_is_locked(&devinfo->lock));
+ WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
if (cmdinfo->state & SUBMIT_STATUS_URB) {
- err = uas_submit_sense_urb(cmnd->device->host, gfp,
- cmdinfo->stream);
- if (err) {
- return err;
- }
+ urb = uas_submit_sense_urb(cmnd, gfp, cmdinfo->stream);
+ if (!urb)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~SUBMIT_STATUS_URB;
}
@@ -578,14 +640,18 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
}
if (cmdinfo->state & SUBMIT_DATA_IN_URB) {
- if (usb_submit_urb(cmdinfo->data_in_urb, gfp)) {
+ usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);
+ err = usb_submit_urb(cmdinfo->data_in_urb, gfp);
+ if (err) {
+ usb_unanchor_urb(cmdinfo->data_in_urb);
+ uas_log_cmd_state(cmnd, __func__);
scmd_printk(KERN_INFO, cmnd,
- "data in urb submission failure\n");
+ "data in urb submission error %d stream %d\n",
+ err, cmdinfo->data_in_urb->stream_id);
return SCSI_MLQUEUE_DEVICE_BUSY;
}
cmdinfo->state &= ~SUBMIT_DATA_IN_URB;
cmdinfo->state |= DATA_IN_URB_INFLIGHT;
- usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);
}
if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
@@ -598,33 +664,37 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
}
if (cmdinfo->state & SUBMIT_DATA_OUT_URB) {
- if (usb_submit_urb(cmdinfo->data_out_urb, gfp)) {
+ usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);
+ err = usb_submit_urb(cmdinfo->data_out_urb, gfp);
+ if (err) {
+ usb_unanchor_urb(cmdinfo->data_out_urb);
+ uas_log_cmd_state(cmnd, __func__);
scmd_printk(KERN_INFO, cmnd,
- "data out urb submission failure\n");
+ "data out urb submission error %d stream %d\n",
+ err, cmdinfo->data_out_urb->stream_id);
return SCSI_MLQUEUE_DEVICE_BUSY;
}
cmdinfo->state &= ~SUBMIT_DATA_OUT_URB;
cmdinfo->state |= DATA_OUT_URB_INFLIGHT;
- usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);
}
if (cmdinfo->state & ALLOC_CMD_URB) {
- cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd,
- cmdinfo->stream);
+ cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd);
if (!cmdinfo->cmd_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~ALLOC_CMD_URB;
}
if (cmdinfo->state & SUBMIT_CMD_URB) {
- usb_get_urb(cmdinfo->cmd_urb);
- if (usb_submit_urb(cmdinfo->cmd_urb, gfp)) {
+ usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs);
+ err = usb_submit_urb(cmdinfo->cmd_urb, gfp);
+ if (err) {
+ usb_unanchor_urb(cmdinfo->cmd_urb);
+ uas_log_cmd_state(cmnd, __func__);
scmd_printk(KERN_INFO, cmnd,
- "cmd urb submission failure\n");
+ "cmd urb submission error %d\n", err);
return SCSI_MLQUEUE_DEVICE_BUSY;
}
- usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs);
- usb_put_urb(cmdinfo->cmd_urb);
cmdinfo->cmd_urb = NULL;
cmdinfo->state &= ~SUBMIT_CMD_URB;
cmdinfo->state |= COMMAND_INFLIGHT;
@@ -644,18 +714,22 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
+ spin_lock_irqsave(&devinfo->lock, flags);
+
if (devinfo->resetting) {
cmnd->result = DID_ERROR << 16;
cmnd->scsi_done(cmnd);
+ spin_unlock_irqrestore(&devinfo->lock, flags);
return 0;
}
- spin_lock_irqsave(&devinfo->lock, flags);
if (devinfo->cmnd) {
spin_unlock_irqrestore(&devinfo->lock, flags);
return SCSI_MLQUEUE_DEVICE_BUSY;
}
+ memset(cmdinfo, 0, sizeof(*cmdinfo));
+
if (blk_rq_tagged(cmnd->request)) {
cmdinfo->stream = cmnd->request->tag + 2;
} else {
@@ -692,13 +766,10 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
spin_unlock_irqrestore(&devinfo->lock, flags);
return SCSI_MLQUEUE_DEVICE_BUSY;
}
- spin_lock(&uas_work_lock);
- list_add_tail(&cmdinfo->list, &uas_work_list);
- cmdinfo->state |= IS_IN_WORK_LIST;
- spin_unlock(&uas_work_lock);
- schedule_work(&uas_work);
+ uas_add_work(cmdinfo);
}
+ list_add_tail(&cmdinfo->list, &devinfo->inflight_list);
spin_unlock_irqrestore(&devinfo->lock, flags);
return 0;
}
@@ -709,46 +780,78 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
const char *fname, u8 function)
{
struct Scsi_Host *shost = cmnd->device->host;
- struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
- u16 tag = devinfo->qdepth - 1;
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+ u16 tag = devinfo->qdepth;
unsigned long flags;
+ struct urb *sense_urb;
+ int result = SUCCESS;
spin_lock_irqsave(&devinfo->lock, flags);
+
+ if (devinfo->resetting) {
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ return FAILED;
+ }
+
+ if (devinfo->running_task) {
+ shost_printk(KERN_INFO, shost,
+ "%s: %s: error already running a task\n",
+ __func__, fname);
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ return FAILED;
+ }
+
+ devinfo->running_task = 1;
memset(&devinfo->response, 0, sizeof(devinfo->response));
- if (uas_submit_sense_urb(shost, GFP_ATOMIC, tag)) {
+ sense_urb = uas_submit_sense_urb(cmnd, GFP_NOIO,
+ devinfo->use_streams ? tag : 0);
+ if (!sense_urb) {
shost_printk(KERN_INFO, shost,
"%s: %s: submit sense urb failed\n",
__func__, fname);
+ devinfo->running_task = 0;
spin_unlock_irqrestore(&devinfo->lock, flags);
return FAILED;
}
- if (uas_submit_task_urb(cmnd, GFP_ATOMIC, function, tag)) {
+ if (uas_submit_task_urb(cmnd, GFP_NOIO, function, tag)) {
shost_printk(KERN_INFO, shost,
"%s: %s: submit task mgmt urb failed\n",
__func__, fname);
+ devinfo->running_task = 0;
spin_unlock_irqrestore(&devinfo->lock, flags);
+ usb_kill_urb(sense_urb);
return FAILED;
}
spin_unlock_irqrestore(&devinfo->lock, flags);
if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) {
+ /*
+ * Note we deliberately do not clear running_task here. If we
+ * allow new tasks to be submitted, there is no way to figure
+ * out if a received response_iu is for the failed task or for
+ * the new one. A bus-reset will eventually clear running_task.
+ */
shost_printk(KERN_INFO, shost,
"%s: %s timed out\n", __func__, fname);
return FAILED;
}
+
+ spin_lock_irqsave(&devinfo->lock, flags);
+ devinfo->running_task = 0;
if (be16_to_cpu(devinfo->response.tag) != tag) {
shost_printk(KERN_INFO, shost,
"%s: %s failed (wrong tag %d/%d)\n", __func__,
fname, be16_to_cpu(devinfo->response.tag), tag);
- return FAILED;
- }
- if (devinfo->response.response_code != RC_TMF_COMPLETE) {
+ result = FAILED;
+ } else if (devinfo->response.response_code != RC_TMF_COMPLETE) {
shost_printk(KERN_INFO, shost,
"%s: %s failed (rc 0x%x)\n", __func__,
fname, devinfo->response.response_code);
- return FAILED;
+ result = FAILED;
}
- return SUCCESS;
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+
+ return result;
}
static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
@@ -758,22 +861,19 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
unsigned long flags;
int ret;
- uas_log_cmd_state(cmnd, __func__);
spin_lock_irqsave(&devinfo->lock, flags);
- cmdinfo->state |= COMMAND_ABORTED;
- if (cmdinfo->state & IS_IN_WORK_LIST) {
- spin_lock(&uas_work_lock);
- list_del(&cmdinfo->list);
- cmdinfo->state &= ~IS_IN_WORK_LIST;
- spin_unlock(&uas_work_lock);
+
+ if (devinfo->resetting) {
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ return FAILED;
}
+
+ uas_mark_cmd_dead(devinfo, cmdinfo, DID_ABORT, __func__);
if (cmdinfo->state & COMMAND_INFLIGHT) {
spin_unlock_irqrestore(&devinfo->lock, flags);
ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
} else {
- spin_unlock_irqrestore(&devinfo->lock, flags);
- uas_unlink_data_urbs(devinfo, cmdinfo);
- spin_lock_irqsave(&devinfo->lock, flags);
+ uas_unlink_data_urbs(devinfo, cmdinfo, &flags);
uas_try_complete(cmnd, __func__);
spin_unlock_irqrestore(&devinfo->lock, flags);
ret = SUCCESS;
@@ -795,14 +895,25 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
struct usb_device *udev = devinfo->udev;
int err;
+ err = usb_lock_device_for_reset(udev, devinfo->intf);
+ if (err) {
+ shost_printk(KERN_ERR, sdev->host,
+ "%s FAILED to get lock err %d\n", __func__, err);
+ return FAILED;
+ }
+
+ shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__);
devinfo->resetting = 1;
- uas_abort_work(devinfo);
+ uas_abort_inflight(devinfo, DID_RESET, __func__);
usb_kill_anchored_urbs(&devinfo->cmd_urbs);
usb_kill_anchored_urbs(&devinfo->sense_urbs);
usb_kill_anchored_urbs(&devinfo->data_urbs);
+ uas_zap_dead(devinfo);
err = usb_reset_device(udev);
devinfo->resetting = 0;
+ usb_unlock_device(udev);
+
if (err) {
shost_printk(KERN_INFO, sdev->host, "%s FAILED\n", __func__);
return FAILED;
@@ -814,7 +925,25 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
static int uas_slave_alloc(struct scsi_device *sdev)
{
- sdev->hostdata = (void *)sdev->host->hostdata[0];
+ sdev->hostdata = (void *)sdev->host->hostdata;
+
+ /* USB has unusual DMA-alignment requirements: Although the
+ * starting address of each scatter-gather element doesn't matter,
+ * the length of each element except the last must be divisible
+ * by the Bulk maxpacket value. There's currently no way to
+ * express this by block-layer constraints, so we'll cop out
+ * and simply require addresses to be aligned at 512-byte
+ * boundaries. This is okay since most block I/O involves
+ * hardware sectors that are multiples of 512 bytes in length,
+ * and since host controllers up through USB 2.0 have maxpacket
+ * values no larger than 512.
+ *
+ * But it doesn't suffice for Wireless USB, where Bulk maxpacket
+ * values can be as large as 2048. To make that work properly
+ * will require changes to the block layer.
+ */
+ blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
+
return 0;
}
@@ -822,7 +951,7 @@ static int uas_slave_configure(struct scsi_device *sdev)
{
struct uas_dev_info *devinfo = sdev->hostdata;
scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
- scsi_activate_tcq(sdev, devinfo->qdepth - 3);
+ scsi_activate_tcq(sdev, devinfo->qdepth - 2);
return 0;
}
@@ -843,7 +972,14 @@ static struct scsi_host_template uas_host_template = {
.ordered_tag = 1,
};
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
static struct usb_device_id uas_usb_ids[] = {
+# include "unusual_uas.h"
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_UAS) },
/* 0xaa is a prototype device I happen to have access to */
@@ -852,105 +988,55 @@ static struct usb_device_id uas_usb_ids[] = {
};
MODULE_DEVICE_TABLE(usb, uas_usb_ids);
-static int uas_is_interface(struct usb_host_interface *intf)
-{
- return (intf->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE &&
- intf->desc.bInterfaceSubClass == USB_SC_SCSI &&
- intf->desc.bInterfaceProtocol == USB_PR_UAS);
-}
-
-static int uas_isnt_supported(struct usb_device *udev)
-{
- struct usb_hcd *hcd = bus_to_hcd(udev->bus);
-
- dev_warn(&udev->dev, "The driver for the USB controller %s does not "
- "support scatter-gather which is\n",
- hcd->driver->description);
- dev_warn(&udev->dev, "required by the UAS driver. Please try an"
- "alternative USB controller if you wish to use UAS.\n");
- return -ENODEV;
-}
+#undef UNUSUAL_DEV
static int uas_switch_interface(struct usb_device *udev,
- struct usb_interface *intf)
+ struct usb_interface *intf)
{
- int i;
- int sg_supported = udev->bus->sg_tablesize != 0;
-
- for (i = 0; i < intf->num_altsetting; i++) {
- struct usb_host_interface *alt = &intf->altsetting[i];
-
- if (uas_is_interface(alt)) {
- if (!sg_supported)
- return uas_isnt_supported(udev);
- return usb_set_interface(udev,
- alt->desc.bInterfaceNumber,
- alt->desc.bAlternateSetting);
- }
- }
+ int alt;
+
+ alt = uas_find_uas_alt_setting(intf);
+ if (alt < 0)
+ return alt;
- return -ENODEV;
+ return usb_set_interface(udev,
+ intf->altsetting[0].desc.bInterfaceNumber, alt);
}
-static void uas_configure_endpoints(struct uas_dev_info *devinfo)
+static int uas_configure_endpoints(struct uas_dev_info *devinfo)
{
struct usb_host_endpoint *eps[4] = { };
- struct usb_interface *intf = devinfo->intf;
struct usb_device *udev = devinfo->udev;
- struct usb_host_endpoint *endpoint = intf->cur_altsetting->endpoint;
- unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints;
+ int r;
devinfo->uas_sense_old = 0;
devinfo->cmnd = NULL;
- for (i = 0; i < n_endpoints; i++) {
- unsigned char *extra = endpoint[i].extra;
- int len = endpoint[i].extralen;
- while (len > 1) {
- if (extra[1] == USB_DT_PIPE_USAGE) {
- unsigned pipe_id = extra[2];
- if (pipe_id > 0 && pipe_id < 5)
- eps[pipe_id - 1] = &endpoint[i];
- break;
- }
- len -= extra[0];
- extra += extra[0];
- }
- }
+ r = uas_find_endpoints(devinfo->intf->cur_altsetting, eps);
+ if (r)
+ return r;
- /*
- * Assume that if we didn't find a control pipe descriptor, we're
- * using a device with old firmware that happens to be set up like
- * this.
- */
- if (!eps[0]) {
- devinfo->cmd_pipe = usb_sndbulkpipe(udev, 1);
- devinfo->status_pipe = usb_rcvbulkpipe(udev, 1);
- devinfo->data_in_pipe = usb_rcvbulkpipe(udev, 2);
- devinfo->data_out_pipe = usb_sndbulkpipe(udev, 2);
-
- eps[1] = usb_pipe_endpoint(udev, devinfo->status_pipe);
- eps[2] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
- eps[3] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
- } else {
- devinfo->cmd_pipe = usb_sndbulkpipe(udev,
- eps[0]->desc.bEndpointAddress);
- devinfo->status_pipe = usb_rcvbulkpipe(udev,
- eps[1]->desc.bEndpointAddress);
- devinfo->data_in_pipe = usb_rcvbulkpipe(udev,
- eps[2]->desc.bEndpointAddress);
- devinfo->data_out_pipe = usb_sndbulkpipe(udev,
- eps[3]->desc.bEndpointAddress);
- }
+ devinfo->cmd_pipe = usb_sndbulkpipe(udev,
+ usb_endpoint_num(&eps[0]->desc));
+ devinfo->status_pipe = usb_rcvbulkpipe(udev,
+ usb_endpoint_num(&eps[1]->desc));
+ devinfo->data_in_pipe = usb_rcvbulkpipe(udev,
+ usb_endpoint_num(&eps[2]->desc));
+ devinfo->data_out_pipe = usb_sndbulkpipe(udev,
+ usb_endpoint_num(&eps[3]->desc));
- devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1, 3, 256,
- GFP_KERNEL);
- if (devinfo->qdepth < 0) {
+ if (udev->speed != USB_SPEED_SUPER) {
devinfo->qdepth = 256;
devinfo->use_streams = 0;
} else {
+ devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1,
+ 3, 256, GFP_KERNEL);
+ if (devinfo->qdepth < 0)
+ return devinfo->qdepth;
devinfo->use_streams = 1;
}
+
+ return 0;
}
static void uas_free_streams(struct uas_dev_info *devinfo)
@@ -964,30 +1050,23 @@ static void uas_free_streams(struct uas_dev_info *devinfo)
usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL);
}
-/*
- * XXX: What I'd like to do here is register a SCSI host for each USB host in
- * the system. Follow usb-storage's design of registering a SCSI host for
- * each USB device for the moment. Can implement this by walking up the
- * USB hierarchy until we find a USB host.
- */
static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
- int result;
- struct Scsi_Host *shost;
+ int result = -ENOMEM;
+ struct Scsi_Host *shost = NULL;
struct uas_dev_info *devinfo;
struct usb_device *udev = interface_to_usbdev(intf);
- if (uas_switch_interface(udev, intf))
+ if (!uas_use_uas_driver(intf, id))
return -ENODEV;
- devinfo = kmalloc(sizeof(struct uas_dev_info), GFP_KERNEL);
- if (!devinfo)
- return -ENOMEM;
+ if (uas_switch_interface(udev, intf))
+ return -ENODEV;
- result = -ENOMEM;
- shost = scsi_host_alloc(&uas_host_template, sizeof(void *));
+ shost = scsi_host_alloc(&uas_host_template,
+ sizeof(struct uas_dev_info));
if (!shost)
- goto free;
+ goto set_alt0;
shost->max_cmd_len = 16 + 252;
shost->max_id = 1;
@@ -995,33 +1074,40 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
shost->max_channel = 0;
shost->sg_tablesize = udev->bus->sg_tablesize;
+ devinfo = (struct uas_dev_info *)shost->hostdata;
devinfo->intf = intf;
devinfo->udev = udev;
devinfo->resetting = 0;
+ devinfo->running_task = 0;
+ devinfo->shutdown = 0;
init_usb_anchor(&devinfo->cmd_urbs);
init_usb_anchor(&devinfo->sense_urbs);
init_usb_anchor(&devinfo->data_urbs);
spin_lock_init(&devinfo->lock);
- uas_configure_endpoints(devinfo);
+ INIT_WORK(&devinfo->work, uas_do_work);
+ INIT_LIST_HEAD(&devinfo->inflight_list);
+ INIT_LIST_HEAD(&devinfo->dead_list);
- result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 3);
+ result = uas_configure_endpoints(devinfo);
if (result)
- goto free;
+ goto set_alt0;
- result = scsi_add_host(shost, &intf->dev);
+ result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
if (result)
- goto deconfig_eps;
+ goto free_streams;
- shost->hostdata[0] = (unsigned long)devinfo;
+ result = scsi_add_host(shost, &intf->dev);
+ if (result)
+ goto free_streams;
scsi_scan_host(shost);
usb_set_intfdata(intf, shost);
return result;
-deconfig_eps:
+free_streams:
uas_free_streams(devinfo);
- free:
- kfree(devinfo);
+set_alt0:
+ usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
if (shost)
scsi_host_put(shost);
return result;
@@ -1029,45 +1115,146 @@ deconfig_eps:
static int uas_pre_reset(struct usb_interface *intf)
{
-/* XXX: Need to return 1 if it's not our device in error handling */
+ struct Scsi_Host *shost = usb_get_intfdata(intf);
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+ unsigned long flags;
+
+ if (devinfo->shutdown)
+ return 0;
+
+ /* Block new requests */
+ spin_lock_irqsave(shost->host_lock, flags);
+ scsi_block_requests(shost);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ /* Wait for any pending requests to complete */
+ flush_work(&devinfo->work);
+ if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 5000) == 0) {
+ shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__);
+ return 1;
+ }
+
+ uas_free_streams(devinfo);
+
return 0;
}
static int uas_post_reset(struct usb_interface *intf)
{
-/* XXX: Need to return 1 if it's not our device in error handling */
+ struct Scsi_Host *shost = usb_get_intfdata(intf);
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+ unsigned long flags;
+
+ if (devinfo->shutdown)
+ return 0;
+
+ if (uas_configure_endpoints(devinfo) != 0) {
+ shost_printk(KERN_ERR, shost,
+ "%s: alloc streams error after reset", __func__);
+ return 1;
+ }
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ scsi_report_bus_reset(shost, 0);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ scsi_unblock_requests(shost);
+
+ return 0;
+}
+
+static int uas_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct Scsi_Host *shost = usb_get_intfdata(intf);
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+
+ /* Wait for any pending requests to complete */
+ flush_work(&devinfo->work);
+ if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 5000) == 0) {
+ shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__);
+ return -ETIME;
+ }
+
+ return 0;
+}
+
+static int uas_resume(struct usb_interface *intf)
+{
+ return 0;
+}
+
+static int uas_reset_resume(struct usb_interface *intf)
+{
+ struct Scsi_Host *shost = usb_get_intfdata(intf);
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+ unsigned long flags;
+
+ if (uas_configure_endpoints(devinfo) != 0) {
+ shost_printk(KERN_ERR, shost,
+ "%s: alloc streams error after reset", __func__);
+ return -EIO;
+ }
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ scsi_report_bus_reset(shost, 0);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
return 0;
}
static void uas_disconnect(struct usb_interface *intf)
{
struct Scsi_Host *shost = usb_get_intfdata(intf);
- struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
devinfo->resetting = 1;
- uas_abort_work(devinfo);
+ cancel_work_sync(&devinfo->work);
+ uas_abort_inflight(devinfo, DID_NO_CONNECT, __func__);
usb_kill_anchored_urbs(&devinfo->cmd_urbs);
usb_kill_anchored_urbs(&devinfo->sense_urbs);
usb_kill_anchored_urbs(&devinfo->data_urbs);
+ uas_zap_dead(devinfo);
scsi_remove_host(shost);
uas_free_streams(devinfo);
- kfree(devinfo);
+ scsi_host_put(shost);
}
/*
- * XXX: Should this plug into libusual so we can auto-upgrade devices from
- * Bulk-Only to UAS?
+ * Put the device back in usb-storage mode on shutdown, as some BIOS-es
+ * hang on reboot when the device is still in uas mode. Note the reset is
+ * necessary as some devices won't revert to usb-storage mode without it.
*/
+static void uas_shutdown(struct device *dev)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct Scsi_Host *shost = usb_get_intfdata(intf);
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+
+ if (system_state != SYSTEM_RESTART)
+ return;
+
+ devinfo->shutdown = 1;
+ uas_free_streams(devinfo);
+ usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
+ usb_reset_device(udev);
+}
+
static struct usb_driver uas_driver = {
.name = "uas",
.probe = uas_probe,
.disconnect = uas_disconnect,
.pre_reset = uas_pre_reset,
.post_reset = uas_post_reset,
+ .suspend = uas_suspend,
+ .resume = uas_resume,
+ .reset_resume = uas_reset_resume,
+ .drvwrap.driver.shutdown = uas_shutdown,
.id_table = uas_usb_ids,
};
module_usb_driver(uas_driver);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Matthew Wilcox and Sarah Sharp");
+MODULE_AUTHOR(
+ "Hans de Goede <hdegoede@redhat.com>, Matthew Wilcox and Sarah Sharp");
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index adbeb255616a..f4a82291894a 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -2086,6 +2086,11 @@ UNUSUAL_DEV( 0xed10, 0x7636, 0x0001, 0x0001,
"Digital MP3 Audio Player",
USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
+/* Unusual uas devices */
+#if IS_ENABLED(CONFIG_USB_UAS)
+#include "unusual_uas.h"
+#endif
+
/* Control/Bulk transport for all SubClass values */
USUAL_DEV(USB_SC_RBC, USB_PR_CB),
USUAL_DEV(USB_SC_8020, USB_PR_CB),
diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h
new file mode 100644
index 000000000000..7244444df8ee
--- /dev/null
+++ b/drivers/usb/storage/unusual_uas.h
@@ -0,0 +1,52 @@
+/* Driver for USB Attached SCSI devices - Unusual Devices File
+ *
+ * (c) 2013 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on the same file for the usb-storage driver, which is:
+ * (c) 2000-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ * (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * IMPORTANT NOTE: This file must be included in another file which defines
+ * a UNUSUAL_DEV macro before this file is included.
+ */
+
+/*
+ * If you edit this file, please try to keep it sorted first by VendorID,
+ * then by ProductID.
+ *
+ * If you want to add an entry for this file, be sure to include the
+ * following information:
+ * - a patch that adds the entry for your device, including your
+ * email address right above the entry (plus maybe a brief
+ * explanation of the reason for the entry),
+ * - lsusb -v output for the device
+ * Send your submission to Hans de Goede <hdegoede@redhat.com>
+ * and don't forget to CC: the USB development list <linux-usb@vger.kernel.org>
+ */
+
+/*
+ * This is an example entry for the US_FL_IGNORE_UAS flag. Once we have an
+ * actual entry using US_FL_IGNORE_UAS this entry should be removed.
+ *
+ * UNUSUAL_DEV( 0xabcd, 0x1234, 0x0100, 0x0100,
+ * "Example",
+ * "Storage with broken UAS",
+ * USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ * US_FL_IGNORE_UAS),
+ */
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 1c0b89f2a138..f1c96261a501 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -72,6 +72,10 @@
#include "sierra_ms.h"
#include "option_ms.h"
+#if IS_ENABLED(CONFIG_USB_UAS)
+#include "uas-detect.h"
+#endif
+
/* Some informational data */
MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
@@ -459,14 +463,14 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf)
#define TOLOWER(x) ((x) | 0x20)
/* Adjust device flags based on the "quirks=" module parameter */
-static void adjust_quirks(struct us_data *us)
+void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
{
char *p;
- u16 vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor);
- u16 pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct);
+ u16 vid = le16_to_cpu(udev->descriptor.idVendor);
+ u16 pid = le16_to_cpu(udev->descriptor.idProduct);
unsigned f = 0;
unsigned int mask = (US_FL_SANE_SENSE | US_FL_BAD_SENSE |
- US_FL_FIX_CAPACITY |
+ US_FL_FIX_CAPACITY | US_FL_IGNORE_UAS |
US_FL_CAPACITY_HEURISTICS | US_FL_IGNORE_DEVICE |
US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 |
US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE |
@@ -537,14 +541,18 @@ static void adjust_quirks(struct us_data *us)
case 's':
f |= US_FL_SINGLE_LUN;
break;
+ case 'u':
+ f |= US_FL_IGNORE_UAS;
+ break;
case 'w':
f |= US_FL_NO_WP_DETECT;
break;
/* Ignore unrecognized flag characters */
}
}
- us->fflags = (us->fflags & ~mask) | f;
+ *fflags = (*fflags & ~mask) | f;
}
+EXPORT_SYMBOL_GPL(usb_stor_adjust_quirks);
/* Get the unusual_devs entries and the string descriptors */
static int get_device_info(struct us_data *us, const struct usb_device_id *id,
@@ -564,7 +572,7 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id,
idesc->bInterfaceProtocol :
unusual_dev->useTransport;
us->fflags = id->driver_info;
- adjust_quirks(us);
+ usb_stor_adjust_quirks(us->pusb_dev, &us->fflags);
if (us->fflags & US_FL_IGNORE_DEVICE) {
dev_info(pdev, "device ignored\n");
@@ -1035,6 +1043,12 @@ static int storage_probe(struct usb_interface *intf,
int result;
int size;
+ /* If uas is enabled and this device can do uas then ignore it. */
+#if IS_ENABLED(CONFIG_USB_UAS)
+ if (uas_use_uas_driver(intf, id))
+ return -ENXIO;
+#endif
+
/*
* If the device isn't standard (is handled by a subdriver
* module) then don't accept it.
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 75f70f04f37b..307e339a9478 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -201,4 +201,7 @@ extern int usb_stor_probe1(struct us_data **pus,
extern int usb_stor_probe2(struct us_data *us);
extern void usb_stor_disconnect(struct usb_interface *intf);
+extern void usb_stor_adjust_quirks(struct usb_device *dev,
+ unsigned long *fflags);
+
#endif
diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c
index 3b959e83b28e..0677139c6065 100644
--- a/drivers/usb/wusbcore/devconnect.c
+++ b/drivers/usb/wusbcore/devconnect.c
@@ -284,7 +284,7 @@ void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc,
struct device *dev = wusbhc->dev;
struct wusb_dev *wusb_dev;
struct wusb_port *port;
- unsigned idx, devnum;
+ unsigned idx;
mutex_lock(&wusbhc->mutex);
@@ -312,8 +312,6 @@ void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc,
goto error_unlock;
}
- devnum = idx + 2;
-
/* Make sure we are using no crypto on that "virtual port" */
wusbhc->set_ptk(wusbhc, idx, 0, NULL, 0);
diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c
index 368360f9a93a..252c7bd9218a 100644
--- a/drivers/usb/wusbcore/wa-hc.c
+++ b/drivers/usb/wusbcore/wa-hc.c
@@ -75,8 +75,6 @@ void __wa_destroy(struct wahc *wa)
if (wa->dti_urb) {
usb_kill_urb(wa->dti_urb);
usb_put_urb(wa->dti_urb);
- usb_kill_urb(wa->buf_in_urb);
- usb_put_urb(wa->buf_in_urb);
}
kfree(wa->dti_buf);
wa_nep_destroy(wa);
diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h
index a2ef84b8397e..f2a8d29e17b9 100644
--- a/drivers/usb/wusbcore/wa-hc.h
+++ b/drivers/usb/wusbcore/wa-hc.h
@@ -125,7 +125,8 @@ struct wa_rpipe {
enum wa_dti_state {
WA_DTI_TRANSFER_RESULT_PENDING,
- WA_DTI_ISOC_PACKET_STATUS_PENDING
+ WA_DTI_ISOC_PACKET_STATUS_PENDING,
+ WA_DTI_BUF_IN_DATA_PENDING
};
enum wa_quirks {
@@ -134,8 +135,20 @@ enum wa_quirks {
* requests to be concatenated and not sent as separate packets.
*/
WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC = 0x01,
+ /*
+ * The Alereon HWA can be instructed to not send transfer notifications
+ * as an optimization.
+ */
+ WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS = 0x02,
};
+enum wa_vendor_specific_requests {
+ WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS = 0x4C,
+ WA_REQ_ALEREON_FEATURE_SET = 0x01,
+ WA_REQ_ALEREON_FEATURE_CLEAR = 0x00,
+};
+
+#define WA_MAX_BUF_IN_URBS 4
/**
* Instance of a HWA Host Controller
*
@@ -206,7 +219,9 @@ struct wahc {
u32 dti_isoc_xfer_in_progress;
u8 dti_isoc_xfer_seg;
struct urb *dti_urb; /* URB for reading xfer results */
- struct urb *buf_in_urb; /* URB for reading data in */
+ /* URBs for reading data in */
+ struct urb buf_in_urbs[WA_MAX_BUF_IN_URBS];
+ int active_buf_in_urbs; /* number of buf_in_urbs active. */
struct edc dti_edc; /* DTI error density counter */
void *dti_buf;
size_t dti_buf_size;
@@ -234,6 +249,7 @@ struct wahc {
extern int wa_create(struct wahc *wa, struct usb_interface *iface,
kernel_ulong_t);
extern void __wa_destroy(struct wahc *wa);
+extern int wa_dti_start(struct wahc *wa);
void wa_reset_all(struct wahc *wa);
@@ -275,6 +291,8 @@ static inline void wa_rpipe_init(struct wahc *wa)
static inline void wa_init(struct wahc *wa)
{
+ int index;
+
edc_init(&wa->nep_edc);
atomic_set(&wa->notifs_queued, 0);
wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
@@ -288,6 +306,10 @@ static inline void wa_init(struct wahc *wa)
INIT_WORK(&wa->xfer_error_work, wa_process_errored_transfers_run);
wa->dto_in_use = 0;
atomic_set(&wa->xfer_id_count, 1);
+ /* init the buf in URBs */
+ for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index)
+ usb_init_urb(&(wa->buf_in_urbs[index]));
+ wa->active_buf_in_urbs = 0;
}
/**
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c
index 6ca80a4efc1b..6d6da127f6de 100644
--- a/drivers/usb/wusbcore/wa-rpipe.c
+++ b/drivers/usb/wusbcore/wa-rpipe.c
@@ -298,7 +298,7 @@ static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find(
break;
}
itr += hdr->bLength;
- itr_size -= hdr->bDescriptorType;
+ itr_size -= hdr->bLength;
}
out:
return epcd;
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c
index 3cd96e936d77..c8e2a47d62a7 100644
--- a/drivers/usb/wusbcore/wa-xfer.c
+++ b/drivers/usb/wusbcore/wa-xfer.c
@@ -167,6 +167,8 @@ struct wa_xfer {
static void __wa_populate_dto_urb_isoc(struct wa_xfer *xfer,
struct wa_seg *seg, int curr_iso_frame);
+static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer,
+ int starting_index, enum wa_seg_status status);
static inline void wa_xfer_init(struct wa_xfer *xfer)
{
@@ -367,13 +369,13 @@ static unsigned __wa_xfer_is_done(struct wa_xfer *xfer)
break;
case WA_SEG_ERROR:
xfer->result = seg->result;
- dev_dbg(dev, "xfer %p ID %08X#%u: ERROR result %zu(0x%08zX)\n",
+ dev_dbg(dev, "xfer %p ID %08X#%u: ERROR result %zi(0x%08zX)\n",
xfer, wa_xfer_id(xfer), seg->index, seg->result,
seg->result);
goto out;
case WA_SEG_ABORTED:
xfer->result = seg->result;
- dev_dbg(dev, "xfer %p ID %08X#%u: ABORTED result %zu(0x%08zX)\n",
+ dev_dbg(dev, "xfer %p ID %08X#%u: ABORTED result %zi(0x%08zX)\n",
xfer, wa_xfer_id(xfer), seg->index, seg->result,
seg->result);
goto out;
@@ -390,6 +392,24 @@ out:
}
/*
+ * Mark the given segment as done. Return true if this completes the xfer.
+ * This should only be called for segs that have been submitted to an RPIPE.
+ * Delayed segs are not marked as submitted so they do not need to be marked
+ * as done when cleaning up.
+ *
+ * xfer->lock has to be locked
+ */
+static unsigned __wa_xfer_mark_seg_as_done(struct wa_xfer *xfer,
+ struct wa_seg *seg, enum wa_seg_status status)
+{
+ seg->status = status;
+ xfer->segs_done++;
+
+ /* check for done. */
+ return __wa_xfer_is_done(xfer);
+}
+
+/*
* Search for a transfer list ID on the HCD's URB list
*
* For 32 bit architectures, we use the pointer itself; for 64 bits, a
@@ -416,12 +436,51 @@ out:
struct wa_xfer_abort_buffer {
struct urb urb;
+ struct wahc *wa;
struct wa_xfer_abort cmd;
};
static void __wa_xfer_abort_cb(struct urb *urb)
{
struct wa_xfer_abort_buffer *b = urb->context;
+ struct wahc *wa = b->wa;
+
+ /*
+ * If the abort request URB failed, then the HWA did not get the abort
+ * command. Forcibly clean up the xfer without waiting for a Transfer
+ * Result from the HWA.
+ */
+ if (urb->status < 0) {
+ struct wa_xfer *xfer;
+ struct device *dev = &wa->usb_iface->dev;
+
+ xfer = wa_xfer_get_by_id(wa, le32_to_cpu(b->cmd.dwTransferID));
+ dev_err(dev, "%s: Transfer Abort request failed. result: %d\n",
+ __func__, urb->status);
+ if (xfer) {
+ unsigned long flags;
+ int done;
+ struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+
+ dev_err(dev, "%s: cleaning up xfer %p ID 0x%08X.\n",
+ __func__, xfer, wa_xfer_id(xfer));
+ spin_lock_irqsave(&xfer->lock, flags);
+ /* mark all segs as aborted. */
+ wa_complete_remaining_xfer_segs(xfer, 0,
+ WA_SEG_ABORTED);
+ done = __wa_xfer_is_done(xfer);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ wa_xfer_delayed_run(rpipe);
+ wa_xfer_put(xfer);
+ } else {
+ dev_err(dev, "%s: xfer ID 0x%08X already gone.\n",
+ __func__, le32_to_cpu(b->cmd.dwTransferID));
+ }
+ }
+
+ wa_put(wa); /* taken in __wa_xfer_abort */
usb_put_urb(&b->urb);
}
@@ -449,6 +508,7 @@ static int __wa_xfer_abort(struct wa_xfer *xfer)
b->cmd.bRequestType = WA_XFER_ABORT;
b->cmd.wRPipe = rpipe->descr.wRPipeIndex;
b->cmd.dwTransferID = wa_xfer_id_le32(xfer);
+ b->wa = wa_get(xfer->wa);
usb_init_urb(&b->urb);
usb_fill_bulk_urb(&b->urb, xfer->wa->usb_dev,
@@ -462,6 +522,7 @@ static int __wa_xfer_abort(struct wa_xfer *xfer)
error_submit:
+ wa_put(xfer->wa);
if (printk_ratelimit())
dev_err(dev, "xfer %p: Can't submit abort request: %d\n",
xfer, result);
@@ -733,6 +794,8 @@ static void wa_seg_dto_cb(struct urb *urb)
seg->isoc_frame_offset + seg->isoc_frame_index);
/* resubmit the URB with the next isoc frame. */
+ /* take a ref on resubmit. */
+ wa_xfer_get(xfer);
result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC);
if (result < 0) {
dev_err(dev, "xfer 0x%08X#%u: DTO submit failed: %d\n",
@@ -760,9 +823,13 @@ static void wa_seg_dto_cb(struct urb *urb)
goto error_default;
}
+ /* taken when this URB was submitted. */
+ wa_xfer_put(xfer);
return;
error_dto_submit:
+ /* taken on resubmit attempt. */
+ wa_xfer_put(xfer);
error_default:
spin_lock_irqsave(&xfer->lock, flags);
rpipe = xfer->ep->hcpriv;
@@ -772,12 +839,10 @@ error_default:
wa_reset_all(wa);
}
if (seg->status != WA_SEG_ERROR) {
- seg->status = WA_SEG_ERROR;
seg->result = urb->status;
- xfer->segs_done++;
__wa_xfer_abort(xfer);
rpipe_ready = rpipe_avail_inc(rpipe);
- done = __wa_xfer_is_done(xfer);
+ done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_ERROR);
}
spin_unlock_irqrestore(&xfer->lock, flags);
if (holding_dto) {
@@ -788,7 +853,8 @@ error_default:
wa_xfer_completion(xfer);
if (rpipe_ready)
wa_xfer_delayed_run(rpipe);
-
+ /* taken when this URB was submitted. */
+ wa_xfer_put(xfer);
}
/*
@@ -842,12 +908,11 @@ static void wa_seg_iso_pack_desc_cb(struct urb *urb)
}
if (seg->status != WA_SEG_ERROR) {
usb_unlink_urb(seg->dto_urb);
- seg->status = WA_SEG_ERROR;
seg->result = urb->status;
- xfer->segs_done++;
__wa_xfer_abort(xfer);
rpipe_ready = rpipe_avail_inc(rpipe);
- done = __wa_xfer_is_done(xfer);
+ done = __wa_xfer_mark_seg_as_done(xfer, seg,
+ WA_SEG_ERROR);
}
spin_unlock_irqrestore(&xfer->lock, flags);
if (done)
@@ -855,6 +920,8 @@ static void wa_seg_iso_pack_desc_cb(struct urb *urb)
if (rpipe_ready)
wa_xfer_delayed_run(rpipe);
}
+ /* taken when this URB was submitted. */
+ wa_xfer_put(xfer);
}
/*
@@ -919,18 +986,18 @@ static void wa_seg_tr_cb(struct urb *urb)
}
usb_unlink_urb(seg->isoc_pack_desc_urb);
usb_unlink_urb(seg->dto_urb);
- seg->status = WA_SEG_ERROR;
seg->result = urb->status;
- xfer->segs_done++;
__wa_xfer_abort(xfer);
rpipe_ready = rpipe_avail_inc(rpipe);
- done = __wa_xfer_is_done(xfer);
+ done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_ERROR);
spin_unlock_irqrestore(&xfer->lock, flags);
if (done)
wa_xfer_completion(xfer);
if (rpipe_ready)
wa_xfer_delayed_run(rpipe);
}
+ /* taken when this URB was submitted. */
+ wa_xfer_put(xfer);
}
/*
@@ -940,7 +1007,7 @@ static void wa_seg_tr_cb(struct urb *urb)
*/
static struct scatterlist *wa_xfer_create_subset_sg(struct scatterlist *in_sg,
const unsigned int bytes_transferred,
- const unsigned int bytes_to_transfer, unsigned int *out_num_sgs)
+ const unsigned int bytes_to_transfer, int *out_num_sgs)
{
struct scatterlist *out_sg;
unsigned int bytes_processed = 0, offset_into_current_page_data = 0,
@@ -1094,14 +1161,13 @@ static int __wa_populate_dto_urb(struct wa_xfer *xfer,
*/
static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
{
- int result, cnt, iso_frame_offset;
+ int result, cnt, isoc_frame_offset = 0;
size_t alloc_size = sizeof(*xfer->seg[0])
- sizeof(xfer->seg[0]->xfer_hdr) + xfer_hdr_size;
struct usb_device *usb_dev = xfer->wa->usb_dev;
const struct usb_endpoint_descriptor *dto_epd = xfer->wa->dto_epd;
struct wa_seg *seg;
size_t buf_itr, buf_size, buf_itr_size;
- int isoc_frame_offset = 0;
result = -ENOMEM;
xfer->seg = kcalloc(xfer->segs, sizeof(xfer->seg[0]), GFP_ATOMIC);
@@ -1109,7 +1175,6 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
goto error_segs_kzalloc;
buf_itr = 0;
buf_size = xfer->urb->transfer_buffer_length;
- iso_frame_offset = 0;
for (cnt = 0; cnt < xfer->segs; cnt++) {
size_t iso_pkt_descr_size = 0;
int seg_isoc_frame_count = 0, seg_isoc_size = 0;
@@ -1318,30 +1383,41 @@ static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer,
/* default to done unless we encounter a multi-frame isoc segment. */
*dto_done = 1;
+ /*
+ * Take a ref for each segment urb so the xfer cannot disappear until
+ * all of the callbacks run.
+ */
+ wa_xfer_get(xfer);
/* submit the transfer request. */
+ seg->status = WA_SEG_SUBMITTED;
result = usb_submit_urb(&seg->tr_urb, GFP_ATOMIC);
if (result < 0) {
pr_err("%s: xfer %p#%u: REQ submit failed: %d\n",
__func__, xfer, seg->index, result);
- goto error_seg_submit;
+ wa_xfer_put(xfer);
+ goto error_tr_submit;
}
/* submit the isoc packet descriptor if present. */
if (seg->isoc_pack_desc_urb) {
+ wa_xfer_get(xfer);
result = usb_submit_urb(seg->isoc_pack_desc_urb, GFP_ATOMIC);
seg->isoc_frame_index = 0;
if (result < 0) {
pr_err("%s: xfer %p#%u: ISO packet descriptor submit failed: %d\n",
__func__, xfer, seg->index, result);
+ wa_xfer_put(xfer);
goto error_iso_pack_desc_submit;
}
}
/* submit the out data if this is an out request. */
if (seg->dto_urb) {
struct wahc *wa = xfer->wa;
+ wa_xfer_get(xfer);
result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC);
if (result < 0) {
pr_err("%s: xfer %p#%u: DTO submit failed: %d\n",
__func__, xfer, seg->index, result);
+ wa_xfer_put(xfer);
goto error_dto_submit;
}
/*
@@ -1353,7 +1429,6 @@ static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer,
&& (seg->isoc_frame_count > 1))
*dto_done = 0;
}
- seg->status = WA_SEG_SUBMITTED;
rpipe_avail_dec(rpipe);
return 0;
@@ -1361,7 +1436,7 @@ error_dto_submit:
usb_unlink_urb(seg->isoc_pack_desc_urb);
error_iso_pack_desc_submit:
usb_unlink_urb(&seg->tr_urb);
-error_seg_submit:
+error_tr_submit:
seg->status = WA_SEG_ERROR;
seg->result = result;
*dto_done = 1;
@@ -1393,6 +1468,12 @@ static int __wa_xfer_delayed_run(struct wa_rpipe *rpipe, int *dto_waiting)
list_node);
list_del(&seg->list_node);
xfer = seg->xfer;
+ /*
+ * Get a reference to the xfer in case the callbacks for the
+ * URBs submitted by __wa_seg_submit attempt to complete
+ * the xfer before this function completes.
+ */
+ wa_xfer_get(xfer);
result = __wa_seg_submit(rpipe, xfer, seg, &dto_done);
/* release the dto resource if this RPIPE is done with it. */
if (dto_done)
@@ -1401,13 +1482,23 @@ static int __wa_xfer_delayed_run(struct wa_rpipe *rpipe, int *dto_waiting)
xfer, wa_xfer_id(xfer), seg->index,
atomic_read(&rpipe->segs_available), result);
if (unlikely(result < 0)) {
+ int done;
+
spin_unlock_irqrestore(&rpipe->seg_lock, flags);
spin_lock_irqsave(&xfer->lock, flags);
__wa_xfer_abort(xfer);
+ /*
+ * This seg was marked as submitted when it was put on
+ * the RPIPE seg_list. Mark it done.
+ */
xfer->segs_done++;
+ done = __wa_xfer_is_done(xfer);
spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
spin_lock_irqsave(&rpipe->seg_lock, flags);
}
+ wa_xfer_put(xfer);
}
/*
* Mark this RPIPE as waiting if dto was not acquired, there are
@@ -1592,12 +1683,19 @@ static int wa_urb_enqueue_b(struct wa_xfer *xfer)
dev_err(&(urb->dev->dev), "%s: error_xfer_setup\n", __func__);
goto error_xfer_setup;
}
+ /*
+ * Get a xfer reference since __wa_xfer_submit starts asynchronous
+ * operations that may try to complete the xfer before this function
+ * exits.
+ */
+ wa_xfer_get(xfer);
result = __wa_xfer_submit(xfer);
if (result < 0) {
dev_err(&(urb->dev->dev), "%s: error_xfer_submit\n", __func__);
goto error_xfer_submit;
}
spin_unlock_irqrestore(&xfer->lock, flags);
+ wa_xfer_put(xfer);
return 0;
/*
@@ -1623,6 +1721,7 @@ error_xfer_submit:
spin_unlock_irqrestore(&xfer->lock, flags);
if (done)
wa_xfer_completion(xfer);
+ wa_xfer_put(xfer);
/* return success since the completion routine will run. */
return 0;
}
@@ -1832,20 +1931,20 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)
/* check if it is safe to unlink. */
spin_lock_irqsave(&wa->xfer_list_lock, flags);
result = usb_hcd_check_unlink_urb(&(wa->wusb->usb_hcd), urb, status);
+ if ((result == 0) && urb->hcpriv) {
+ /*
+ * Get a xfer ref to prevent a race with wa_xfer_giveback
+ * cleaning up the xfer while we are working with it.
+ */
+ wa_xfer_get(urb->hcpriv);
+ }
spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
if (result)
return result;
xfer = urb->hcpriv;
- if (xfer == NULL) {
- /*
- * Nothing setup yet enqueue will see urb->status !=
- * -EINPROGRESS (by hcd layer) and bail out with
- * error, no need to do completion
- */
- BUG_ON(urb->status == -EINPROGRESS);
- goto out;
- }
+ if (xfer == NULL)
+ return -ENOENT;
spin_lock_irqsave(&xfer->lock, flags);
pr_debug("%s: DEQUEUE xfer id 0x%08X\n", __func__, wa_xfer_id(xfer));
rpipe = xfer->ep->hcpriv;
@@ -1856,6 +1955,16 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)
result = -ENOENT;
goto out_unlock;
}
+ /*
+ * Check for done to avoid racing with wa_xfer_giveback and completing
+ * twice.
+ */
+ if (__wa_xfer_is_done(xfer)) {
+ pr_debug("%s: xfer %p id 0x%08X already done.\n", __func__,
+ xfer, wa_xfer_id(xfer));
+ result = -ENOENT;
+ goto out_unlock;
+ }
/* Check the delayed list -> if there, release and complete */
spin_lock_irqsave(&wa->xfer_list_lock, flags2);
if (!list_empty(&xfer->list_node) && xfer->seg == NULL)
@@ -1865,6 +1974,11 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)
goto out_unlock; /* setup(), enqueue_b() completes */
/* Ok, the xfer is in flight already, it's been setup and submitted.*/
xfer_abort_pending = __wa_xfer_abort(xfer) >= 0;
+ /*
+ * grab the rpipe->seg_lock here to prevent racing with
+ * __wa_xfer_delayed_run.
+ */
+ spin_lock(&rpipe->seg_lock);
for (cnt = 0; cnt < xfer->segs; cnt++) {
seg = xfer->seg[cnt];
pr_debug("%s: xfer id 0x%08X#%d status = %d\n",
@@ -1885,16 +1999,24 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)
*/
seg->status = WA_SEG_ABORTED;
seg->result = -ENOENT;
- spin_lock_irqsave(&rpipe->seg_lock, flags2);
list_del(&seg->list_node);
xfer->segs_done++;
- spin_unlock_irqrestore(&rpipe->seg_lock, flags2);
break;
case WA_SEG_DONE:
case WA_SEG_ERROR:
case WA_SEG_ABORTED:
break;
/*
+ * The buf_in data for a segment in the
+ * WA_SEG_DTI_PENDING state is actively being read.
+ * Let wa_buf_in_cb handle it since it will be called
+ * and will increment xfer->segs_done. Cleaning up
+ * here could cause wa_buf_in_cb to access the xfer
+ * after it has been completed/freed.
+ */
+ case WA_SEG_DTI_PENDING:
+ break;
+ /*
* In the states below, the HWA device already knows
* about the transfer. If an abort request was sent,
* allow the HWA to process it and wait for the
@@ -1903,7 +2025,6 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)
*/
case WA_SEG_SUBMITTED:
case WA_SEG_PENDING:
- case WA_SEG_DTI_PENDING:
/*
* Check if the abort was successfully sent. This could
* be false if the HWA has been removed but we haven't
@@ -1917,6 +2038,7 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)
break;
}
}
+ spin_unlock(&rpipe->seg_lock);
xfer->result = urb->status; /* -ENOENT or -ECONNRESET */
done = __wa_xfer_is_done(xfer);
spin_unlock_irqrestore(&xfer->lock, flags);
@@ -1924,11 +2046,12 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)
wa_xfer_completion(xfer);
if (rpipe_ready)
wa_xfer_delayed_run(rpipe);
+ wa_xfer_put(xfer);
return result;
out_unlock:
spin_unlock_irqrestore(&xfer->lock, flags);
-out:
+ wa_xfer_put(xfer);
return result;
dequeue_delayed:
@@ -1937,6 +2060,7 @@ dequeue_delayed:
xfer->result = urb->status;
spin_unlock_irqrestore(&xfer->lock, flags);
wa_xfer_giveback(xfer);
+ wa_xfer_put(xfer);
usb_put_urb(urb); /* we got a ref in enqueue() */
return 0;
}
@@ -1996,15 +2120,17 @@ static int wa_xfer_status_to_errno(u8 status)
* no other segment transfer results will be returned from the device.
* Mark the remaining submitted or pending xfers as completed so that
* the xfer will complete cleanly.
+ *
+ * xfer->lock must be held
+ *
*/
static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer,
- struct wa_seg *incoming_seg, enum wa_seg_status status)
+ int starting_index, enum wa_seg_status status)
{
int index;
struct wa_rpipe *rpipe = xfer->ep->hcpriv;
- for (index = incoming_seg->index + 1; index < xfer->segs_submitted;
- index++) {
+ for (index = starting_index; index < xfer->segs_submitted; index++) {
struct wa_seg *current_seg = xfer->seg[index];
BUG_ON(current_seg == NULL);
@@ -2033,73 +2159,110 @@ static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer,
}
}
-/* Populate the wa->buf_in_urb based on the current isoc transfer state. */
-static void __wa_populate_buf_in_urb_isoc(struct wahc *wa, struct wa_xfer *xfer,
- struct wa_seg *seg, int curr_iso_frame)
+/* Populate the given urb based on the current isoc transfer state. */
+static int __wa_populate_buf_in_urb_isoc(struct wahc *wa,
+ struct urb *buf_in_urb, struct wa_xfer *xfer, struct wa_seg *seg)
{
- BUG_ON(wa->buf_in_urb->status == -EINPROGRESS);
+ int urb_start_frame = seg->isoc_frame_index + seg->isoc_frame_offset;
+ int seg_index, total_len = 0, urb_frame_index = urb_start_frame;
+ struct usb_iso_packet_descriptor *iso_frame_desc =
+ xfer->urb->iso_frame_desc;
+ const int dti_packet_size = usb_endpoint_maxp(wa->dti_epd);
+ int next_frame_contiguous;
+ struct usb_iso_packet_descriptor *iso_frame;
+
+ BUG_ON(buf_in_urb->status == -EINPROGRESS);
+
+ /*
+ * If the current frame actual_length is contiguous with the next frame
+ * and actual_length is a multiple of the DTI endpoint max packet size,
+ * combine the current frame with the next frame in a single URB. This
+ * reduces the number of URBs that must be submitted in that case.
+ */
+ seg_index = seg->isoc_frame_index;
+ do {
+ next_frame_contiguous = 0;
+
+ iso_frame = &iso_frame_desc[urb_frame_index];
+ total_len += iso_frame->actual_length;
+ ++urb_frame_index;
+ ++seg_index;
+
+ if (seg_index < seg->isoc_frame_count) {
+ struct usb_iso_packet_descriptor *next_iso_frame;
+
+ next_iso_frame = &iso_frame_desc[urb_frame_index];
+
+ if ((iso_frame->offset + iso_frame->actual_length) ==
+ next_iso_frame->offset)
+ next_frame_contiguous = 1;
+ }
+ } while (next_frame_contiguous
+ && ((iso_frame->actual_length % dti_packet_size) == 0));
/* this should always be 0 before a resubmit. */
- wa->buf_in_urb->num_mapped_sgs = 0;
- wa->buf_in_urb->transfer_dma = xfer->urb->transfer_dma +
- xfer->urb->iso_frame_desc[curr_iso_frame].offset;
- wa->buf_in_urb->transfer_buffer_length =
- xfer->urb->iso_frame_desc[curr_iso_frame].length;
- wa->buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- wa->buf_in_urb->transfer_buffer = NULL;
- wa->buf_in_urb->sg = NULL;
- wa->buf_in_urb->num_sgs = 0;
- wa->buf_in_urb->context = seg;
+ buf_in_urb->num_mapped_sgs = 0;
+ buf_in_urb->transfer_dma = xfer->urb->transfer_dma +
+ iso_frame_desc[urb_start_frame].offset;
+ buf_in_urb->transfer_buffer_length = total_len;
+ buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ buf_in_urb->transfer_buffer = NULL;
+ buf_in_urb->sg = NULL;
+ buf_in_urb->num_sgs = 0;
+ buf_in_urb->context = seg;
+
+ /* return the number of frames included in this URB. */
+ return seg_index - seg->isoc_frame_index;
}
-/* Populate the wa->buf_in_urb based on the current transfer state. */
-static int wa_populate_buf_in_urb(struct wahc *wa, struct wa_xfer *xfer,
+/* Populate the given urb based on the current transfer state. */
+static int wa_populate_buf_in_urb(struct urb *buf_in_urb, struct wa_xfer *xfer,
unsigned int seg_idx, unsigned int bytes_transferred)
{
int result = 0;
struct wa_seg *seg = xfer->seg[seg_idx];
- BUG_ON(wa->buf_in_urb->status == -EINPROGRESS);
+ BUG_ON(buf_in_urb->status == -EINPROGRESS);
/* this should always be 0 before a resubmit. */
- wa->buf_in_urb->num_mapped_sgs = 0;
+ buf_in_urb->num_mapped_sgs = 0;
if (xfer->is_dma) {
- wa->buf_in_urb->transfer_dma = xfer->urb->transfer_dma
+ buf_in_urb->transfer_dma = xfer->urb->transfer_dma
+ (seg_idx * xfer->seg_size);
- wa->buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- wa->buf_in_urb->transfer_buffer = NULL;
- wa->buf_in_urb->sg = NULL;
- wa->buf_in_urb->num_sgs = 0;
+ buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ buf_in_urb->transfer_buffer = NULL;
+ buf_in_urb->sg = NULL;
+ buf_in_urb->num_sgs = 0;
} else {
/* do buffer or SG processing. */
- wa->buf_in_urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP;
+ buf_in_urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP;
if (xfer->urb->transfer_buffer) {
- wa->buf_in_urb->transfer_buffer =
+ buf_in_urb->transfer_buffer =
xfer->urb->transfer_buffer
+ (seg_idx * xfer->seg_size);
- wa->buf_in_urb->sg = NULL;
- wa->buf_in_urb->num_sgs = 0;
+ buf_in_urb->sg = NULL;
+ buf_in_urb->num_sgs = 0;
} else {
/* allocate an SG list to store seg_size bytes
and copy the subset of the xfer->urb->sg
that matches the buffer subset we are
about to read. */
- wa->buf_in_urb->sg = wa_xfer_create_subset_sg(
+ buf_in_urb->sg = wa_xfer_create_subset_sg(
xfer->urb->sg,
seg_idx * xfer->seg_size,
bytes_transferred,
- &(wa->buf_in_urb->num_sgs));
+ &(buf_in_urb->num_sgs));
- if (!(wa->buf_in_urb->sg)) {
- wa->buf_in_urb->num_sgs = 0;
+ if (!(buf_in_urb->sg)) {
+ buf_in_urb->num_sgs = 0;
result = -ENOMEM;
}
- wa->buf_in_urb->transfer_buffer = NULL;
+ buf_in_urb->transfer_buffer = NULL;
}
}
- wa->buf_in_urb->transfer_buffer_length = bytes_transferred;
- wa->buf_in_urb->context = seg;
+ buf_in_urb->transfer_buffer_length = bytes_transferred;
+ buf_in_urb->context = seg;
return result;
}
@@ -2124,6 +2287,7 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer,
u8 usb_status;
unsigned rpipe_ready = 0;
unsigned bytes_transferred = le32_to_cpu(xfer_result->dwTransferLength);
+ struct urb *buf_in_urb = &(wa->buf_in_urbs[0]);
spin_lock_irqsave(&xfer->lock, flags);
seg_idx = xfer_result->bTransferSegment & 0x7f;
@@ -2147,7 +2311,7 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer,
}
if (usb_status & 0x80) {
seg->result = wa_xfer_status_to_errno(usb_status);
- dev_err(dev, "DTI: xfer %p#:%08X:%u failed (0x%02x)\n",
+ dev_err(dev, "DTI: xfer %p 0x%08X:#%u failed (0x%02x)\n",
xfer, xfer->id, seg->index, usb_status);
seg->status = ((usb_status & 0x7F) == WA_XFER_STATUS_ABORTED) ?
WA_SEG_ABORTED : WA_SEG_ERROR;
@@ -2162,7 +2326,8 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer,
* transfers with data or below for no data, the xfer will complete.
*/
if (xfer_result->bTransferSegment & 0x80)
- wa_complete_remaining_xfer_segs(xfer, seg, WA_SEG_DONE);
+ wa_complete_remaining_xfer_segs(xfer, seg->index + 1,
+ WA_SEG_DONE);
if (usb_pipeisoc(xfer->urb->pipe)
&& (le32_to_cpu(xfer_result->dwNumOfPackets) > 0)) {
/* set up WA state to read the isoc packet status next. */
@@ -2173,20 +2338,21 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer,
&& (bytes_transferred > 0)) {
/* IN data phase: read to buffer */
seg->status = WA_SEG_DTI_PENDING;
- result = wa_populate_buf_in_urb(wa, xfer, seg_idx,
+ result = wa_populate_buf_in_urb(buf_in_urb, xfer, seg_idx,
bytes_transferred);
if (result < 0)
goto error_buf_in_populate;
- result = usb_submit_urb(wa->buf_in_urb, GFP_ATOMIC);
- if (result < 0)
+ ++(wa->active_buf_in_urbs);
+ result = usb_submit_urb(buf_in_urb, GFP_ATOMIC);
+ if (result < 0) {
+ --(wa->active_buf_in_urbs);
goto error_submit_buf_in;
+ }
} else {
/* OUT data phase or no data, complete it -- */
- seg->status = WA_SEG_DONE;
seg->result = bytes_transferred;
- xfer->segs_done++;
rpipe_ready = rpipe_avail_inc(rpipe);
- done = __wa_xfer_is_done(xfer);
+ done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_DONE);
}
spin_unlock_irqrestore(&xfer->lock, flags);
if (done)
@@ -2205,15 +2371,15 @@ error_submit_buf_in:
dev_err(dev, "xfer %p#%u: can't submit DTI data phase: %d\n",
xfer, seg_idx, result);
seg->result = result;
- kfree(wa->buf_in_urb->sg);
- wa->buf_in_urb->sg = NULL;
+ kfree(buf_in_urb->sg);
+ buf_in_urb->sg = NULL;
error_buf_in_populate:
__wa_xfer_abort(xfer);
seg->status = WA_SEG_ERROR;
error_complete:
xfer->segs_done++;
rpipe_ready = rpipe_avail_inc(rpipe);
- wa_complete_remaining_xfer_segs(xfer, seg, seg->status);
+ wa_complete_remaining_xfer_segs(xfer, seg->index + 1, seg->status);
done = __wa_xfer_is_done(xfer);
/*
* queue work item to clear STALL for control endpoints.
@@ -2315,16 +2481,16 @@ static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb)
for (seg_index = 0; seg_index < seg->isoc_frame_count; ++seg_index) {
struct usb_iso_packet_descriptor *iso_frame_desc =
xfer->urb->iso_frame_desc;
- const int urb_frame_index =
+ const int xfer_frame_index =
seg->isoc_frame_offset + seg_index;
- iso_frame_desc[urb_frame_index].status =
+ iso_frame_desc[xfer_frame_index].status =
wa_xfer_status_to_errno(
le16_to_cpu(status_array[seg_index].PacketStatus));
- iso_frame_desc[urb_frame_index].actual_length =
+ iso_frame_desc[xfer_frame_index].actual_length =
le16_to_cpu(status_array[seg_index].PacketLength);
/* track the number of frames successfully transferred. */
- if (iso_frame_desc[urb_frame_index].actual_length > 0) {
+ if (iso_frame_desc[xfer_frame_index].actual_length > 0) {
/* save the starting frame index for buf_in_urb. */
if (!data_frame_count)
first_frame_index = seg_index;
@@ -2333,30 +2499,64 @@ static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb)
}
if (xfer->is_inbound && data_frame_count) {
- int result;
+ int result, total_frames_read = 0, urb_index = 0;
+ struct urb *buf_in_urb;
+ /* IN data phase: read to buffer */
+ seg->status = WA_SEG_DTI_PENDING;
+
+ /* start with the first frame with data. */
seg->isoc_frame_index = first_frame_index;
- /* submit a read URB for the first frame with data. */
- __wa_populate_buf_in_urb_isoc(wa, xfer, seg,
- seg->isoc_frame_index + seg->isoc_frame_offset);
+ /* submit up to WA_MAX_BUF_IN_URBS read URBs. */
+ do {
+ int urb_frame_index, urb_frame_count;
+ struct usb_iso_packet_descriptor *iso_frame_desc;
+
+ buf_in_urb = &(wa->buf_in_urbs[urb_index]);
+ urb_frame_count = __wa_populate_buf_in_urb_isoc(wa,
+ buf_in_urb, xfer, seg);
+ /* advance frame index to start of next read URB. */
+ seg->isoc_frame_index += urb_frame_count;
+ total_frames_read += urb_frame_count;
+
+ ++(wa->active_buf_in_urbs);
+ result = usb_submit_urb(buf_in_urb, GFP_ATOMIC);
+
+ /* skip 0-byte frames. */
+ urb_frame_index =
+ seg->isoc_frame_offset + seg->isoc_frame_index;
+ iso_frame_desc =
+ &(xfer->urb->iso_frame_desc[urb_frame_index]);
+ while ((seg->isoc_frame_index <
+ seg->isoc_frame_count) &&
+ (iso_frame_desc->actual_length == 0)) {
+ ++(seg->isoc_frame_index);
+ ++iso_frame_desc;
+ }
+ ++urb_index;
+
+ } while ((result == 0) && (urb_index < WA_MAX_BUF_IN_URBS)
+ && (seg->isoc_frame_index <
+ seg->isoc_frame_count));
- result = usb_submit_urb(wa->buf_in_urb, GFP_ATOMIC);
if (result < 0) {
+ --(wa->active_buf_in_urbs);
dev_err(dev, "DTI Error: Could not submit buf in URB (%d)",
result);
wa_reset_all(wa);
- } else if (data_frame_count > 1)
- /* If we need to read multiple frames, set DTI busy. */
+ } else if (data_frame_count > total_frames_read)
+ /* If we need to read more frames, set DTI busy. */
dti_busy = 1;
} else {
/* OUT transfer or no more IN data, complete it -- */
- seg->status = WA_SEG_DONE;
- xfer->segs_done++;
rpipe_ready = rpipe_avail_inc(rpipe);
- done = __wa_xfer_is_done(xfer);
+ done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_DONE);
}
spin_unlock_irqrestore(&xfer->lock, flags);
- wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
+ if (dti_busy)
+ wa->dti_state = WA_DTI_BUF_IN_DATA_PENDING;
+ else
+ wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
if (done)
wa_xfer_completion(xfer);
if (rpipe_ready)
@@ -2388,8 +2588,9 @@ static void wa_buf_in_cb(struct urb *urb)
struct wahc *wa;
struct device *dev;
struct wa_rpipe *rpipe;
- unsigned rpipe_ready = 0, seg_index, isoc_data_frame_count = 0;
+ unsigned rpipe_ready = 0, isoc_data_frame_count = 0;
unsigned long flags;
+ int resubmit_dti = 0, active_buf_in_urbs;
u8 done = 0;
/* free the sg if it was used. */
@@ -2399,19 +2600,20 @@ static void wa_buf_in_cb(struct urb *urb)
spin_lock_irqsave(&xfer->lock, flags);
wa = xfer->wa;
dev = &wa->usb_iface->dev;
+ --(wa->active_buf_in_urbs);
+ active_buf_in_urbs = wa->active_buf_in_urbs;
if (usb_pipeisoc(xfer->urb->pipe)) {
+ struct usb_iso_packet_descriptor *iso_frame_desc =
+ xfer->urb->iso_frame_desc;
+ int seg_index;
+
/*
- * Find the next isoc frame with data. Bail out after
- * isoc_data_frame_count > 1 since there is no need to walk
- * the entire frame array. We just need to know if
- * isoc_data_frame_count is 0, 1, or >1.
+ * Find the next isoc frame with data and count how many
+ * frames with data remain.
*/
- seg_index = seg->isoc_frame_index + 1;
- while ((seg_index < seg->isoc_frame_count)
- && (isoc_data_frame_count <= 1)) {
- struct usb_iso_packet_descriptor *iso_frame_desc =
- xfer->urb->iso_frame_desc;
+ seg_index = seg->isoc_frame_index;
+ while (seg_index < seg->isoc_frame_count) {
const int urb_frame_index =
seg->isoc_frame_offset + seg_index;
@@ -2432,24 +2634,39 @@ static void wa_buf_in_cb(struct urb *urb)
seg->result += urb->actual_length;
if (isoc_data_frame_count > 0) {
- int result;
- /* submit a read URB for the first frame with data. */
- __wa_populate_buf_in_urb_isoc(wa, xfer, seg,
- seg->isoc_frame_index + seg->isoc_frame_offset);
- result = usb_submit_urb(wa->buf_in_urb, GFP_ATOMIC);
+ int result, urb_frame_count;
+
+ /* submit a read URB for the next frame with data. */
+ urb_frame_count = __wa_populate_buf_in_urb_isoc(wa, urb,
+ xfer, seg);
+ /* advance index to start of next read URB. */
+ seg->isoc_frame_index += urb_frame_count;
+ ++(wa->active_buf_in_urbs);
+ result = usb_submit_urb(urb, GFP_ATOMIC);
if (result < 0) {
+ --(wa->active_buf_in_urbs);
dev_err(dev, "DTI Error: Could not submit buf in URB (%d)",
result);
wa_reset_all(wa);
}
- } else {
+ /*
+ * If we are in this callback and
+ * isoc_data_frame_count > 0, it means that the dti_urb
+ * submission was delayed in wa_dti_cb. Once
+ * we submit the last buf_in_urb, we can submit the
+ * delayed dti_urb.
+ */
+ resubmit_dti = (isoc_data_frame_count ==
+ urb_frame_count);
+ } else if (active_buf_in_urbs == 0) {
rpipe = xfer->ep->hcpriv;
- seg->status = WA_SEG_DONE;
- dev_dbg(dev, "xfer %p#%u: data in done (%zu bytes)\n",
- xfer, seg->index, seg->result);
- xfer->segs_done++;
+ dev_dbg(dev,
+ "xfer %p 0x%08X#%u: data in done (%zu bytes)\n",
+ xfer, wa_xfer_id(xfer), seg->index,
+ seg->result);
rpipe_ready = rpipe_avail_inc(rpipe);
- done = __wa_xfer_is_done(xfer);
+ done = __wa_xfer_mark_seg_as_done(xfer, seg,
+ WA_SEG_DONE);
}
spin_unlock_irqrestore(&xfer->lock, flags);
if (done)
@@ -2461,37 +2678,44 @@ static void wa_buf_in_cb(struct urb *urb)
case -ENOENT: /* as it was done by the who unlinked us */
break;
default: /* Other errors ... */
+ /*
+ * Error on data buf read. Only resubmit DTI if it hasn't
+ * already been done by previously hitting this error or by a
+ * successful completion of the previous buf_in_urb.
+ */
+ resubmit_dti = wa->dti_state != WA_DTI_TRANSFER_RESULT_PENDING;
spin_lock_irqsave(&xfer->lock, flags);
rpipe = xfer->ep->hcpriv;
if (printk_ratelimit())
- dev_err(dev, "xfer %p#%u: data in error %d\n",
- xfer, seg->index, urb->status);
+ dev_err(dev, "xfer %p 0x%08X#%u: data in error %d\n",
+ xfer, wa_xfer_id(xfer), seg->index,
+ urb->status);
if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
EDC_ERROR_TIMEFRAME)){
dev_err(dev, "DTO: URB max acceptable errors "
"exceeded, resetting device\n");
wa_reset_all(wa);
}
- seg->status = WA_SEG_ERROR;
seg->result = urb->status;
- xfer->segs_done++;
rpipe_ready = rpipe_avail_inc(rpipe);
- __wa_xfer_abort(xfer);
- done = __wa_xfer_is_done(xfer);
+ if (active_buf_in_urbs == 0)
+ done = __wa_xfer_mark_seg_as_done(xfer, seg,
+ WA_SEG_ERROR);
+ else
+ __wa_xfer_abort(xfer);
spin_unlock_irqrestore(&xfer->lock, flags);
if (done)
wa_xfer_completion(xfer);
if (rpipe_ready)
wa_xfer_delayed_run(rpipe);
}
- /*
- * If we are in this callback and isoc_data_frame_count > 0, it means
- * that the dti_urb submission was delayed in wa_dti_cb. Once
- * isoc_data_frame_count gets to 1, we can submit the deferred URB
- * since the last buf_in_urb was just submitted.
- */
- if (isoc_data_frame_count == 1) {
- int result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC);
+
+ if (resubmit_dti) {
+ int result;
+
+ wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
+
+ result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC);
if (result < 0) {
dev_err(dev, "DTI Error: Could not submit DTI URB (%d)\n",
result);
@@ -2561,11 +2785,15 @@ static void wa_dti_cb(struct urb *urb)
xfer_result->hdr.bNotifyType);
break;
}
+ xfer_id = le32_to_cpu(xfer_result->dwTransferID);
usb_status = xfer_result->bTransferStatus & 0x3f;
- if (usb_status == WA_XFER_STATUS_NOT_FOUND)
+ if (usb_status == WA_XFER_STATUS_NOT_FOUND) {
/* taken care of already */
+ dev_dbg(dev, "%s: xfer 0x%08X#%u not found.\n",
+ __func__, xfer_id,
+ xfer_result->bTransferSegment & 0x7f);
break;
- xfer_id = le32_to_cpu(xfer_result->dwTransferID);
+ }
xfer = wa_xfer_get_by_id(wa, xfer_id);
if (xfer == NULL) {
/* FIXME: transaction not found. */
@@ -2614,6 +2842,54 @@ out:
}
/*
+ * Initialize the DTI URB for reading transfer result notifications and also
+ * the buffer-in URB, for reading buffers. Then we just submit the DTI URB.
+ */
+int wa_dti_start(struct wahc *wa)
+{
+ const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd;
+ struct device *dev = &wa->usb_iface->dev;
+ int result = -ENOMEM, index;
+
+ if (wa->dti_urb != NULL) /* DTI URB already started */
+ goto out;
+
+ wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (wa->dti_urb == NULL) {
+ dev_err(dev, "Can't allocate DTI URB\n");
+ goto error_dti_urb_alloc;
+ }
+ usb_fill_bulk_urb(
+ wa->dti_urb, wa->usb_dev,
+ usb_rcvbulkpipe(wa->usb_dev, 0x80 | dti_epd->bEndpointAddress),
+ wa->dti_buf, wa->dti_buf_size,
+ wa_dti_cb, wa);
+
+ /* init the buf in URBs */
+ for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index) {
+ usb_fill_bulk_urb(
+ &(wa->buf_in_urbs[index]), wa->usb_dev,
+ usb_rcvbulkpipe(wa->usb_dev,
+ 0x80 | dti_epd->bEndpointAddress),
+ NULL, 0, wa_buf_in_cb, wa);
+ }
+ result = usb_submit_urb(wa->dti_urb, GFP_KERNEL);
+ if (result < 0) {
+ dev_err(dev, "DTI Error: Could not submit DTI URB (%d) resetting\n",
+ result);
+ goto error_dti_urb_submit;
+ }
+out:
+ return 0;
+
+error_dti_urb_submit:
+ usb_put_urb(wa->dti_urb);
+ wa->dti_urb = NULL;
+error_dti_urb_alloc:
+ return result;
+}
+EXPORT_SYMBOL_GPL(wa_dti_start);
+/*
* Transfer complete notification
*
* Called from the notif.c code. We get a notification on EP2 saying
@@ -2627,15 +2903,10 @@ out:
* Follow up in wa_dti_cb(), as that's where the whole state
* machine starts.
*
- * So here we just initialize the DTI URB for reading transfer result
- * notifications and also the buffer-in URB, for reading buffers. Then
- * we just submit the DTI URB.
- *
* @wa shall be referenced
*/
void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr)
{
- int result;
struct device *dev = &wa->usb_iface->dev;
struct wa_notif_xfer *notif_xfer;
const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd;
@@ -2649,45 +2920,13 @@ void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr)
notif_xfer->bEndpoint, dti_epd->bEndpointAddress);
goto error;
}
- if (wa->dti_urb != NULL) /* DTI URB already started */
- goto out;
- wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (wa->dti_urb == NULL) {
- dev_err(dev, "Can't allocate DTI URB\n");
- goto error_dti_urb_alloc;
- }
- usb_fill_bulk_urb(
- wa->dti_urb, wa->usb_dev,
- usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint),
- wa->dti_buf, wa->dti_buf_size,
- wa_dti_cb, wa);
+ /* attempt to start the DTI ep processing. */
+ if (wa_dti_start(wa) < 0)
+ goto error;
- wa->buf_in_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (wa->buf_in_urb == NULL) {
- dev_err(dev, "Can't allocate BUF-IN URB\n");
- goto error_buf_in_urb_alloc;
- }
- usb_fill_bulk_urb(
- wa->buf_in_urb, wa->usb_dev,
- usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint),
- NULL, 0, wa_buf_in_cb, wa);
- result = usb_submit_urb(wa->dti_urb, GFP_KERNEL);
- if (result < 0) {
- dev_err(dev, "DTI Error: Could not submit DTI URB (%d) resetting\n",
- result);
- goto error_dti_urb_submit;
- }
-out:
return;
-error_dti_urb_submit:
- usb_put_urb(wa->buf_in_urb);
- wa->buf_in_urb = NULL;
-error_buf_in_urb_alloc:
- usb_put_urb(wa->dti_urb);
- wa->dti_urb = NULL;
-error_dti_urb_alloc:
error:
wa_reset_all(wa);
}
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index 210357691dc0..9dd49c9839ac 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -482,15 +482,19 @@ static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)
for (i = 0; i < nvec; i++)
vdev->msix[i].entry = i;
- ret = pci_enable_msix(pdev, vdev->msix, nvec);
- if (ret) {
+ 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_block(pdev, nvec);
- if (ret) {
+ ret = pci_enable_msi_range(pdev, 1, nvec);
+ if (ret < nvec) {
+ if (ret > 0)
+ pci_disable_msi(pdev);
kfree(vdev->ctx);
return ret;
}
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 4fb7a8f83c8a..54af4e933695 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -186,12 +186,12 @@ static bool is_invalid_reserved_pfn(unsigned long pfn)
if (pfn_valid(pfn)) {
bool reserved;
struct page *tail = pfn_to_page(pfn);
- struct page *head = compound_trans_head(tail);
+ struct page *head = compound_head(tail);
reserved = !!(PageReserved(head));
if (head != tail) {
/*
* "head" is not a dangling pointer
- * (compound_trans_head takes care of that)
+ * (compound_head takes care of that)
* but the hugepage may have been split
* from under us (and we may not hold a
* reference count on the head page so it can
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 9a68409580d5..e1e22e0f01e8 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -70,7 +70,12 @@ enum {
};
struct vhost_net_ubuf_ref {
- struct kref kref;
+ /* refcount follows semantics similar to kref:
+ * 0: object is released
+ * 1: no outstanding ubufs
+ * >1: outstanding ubufs
+ */
+ atomic_t refcount;
wait_queue_head_t wait;
struct vhost_virtqueue *vq;
};
@@ -116,14 +121,6 @@ static void vhost_net_enable_zcopy(int vq)
vhost_net_zcopy_mask |= 0x1 << vq;
}
-static void vhost_net_zerocopy_done_signal(struct kref *kref)
-{
- struct vhost_net_ubuf_ref *ubufs;
-
- ubufs = container_of(kref, struct vhost_net_ubuf_ref, kref);
- wake_up(&ubufs->wait);
-}
-
static struct vhost_net_ubuf_ref *
vhost_net_ubuf_alloc(struct vhost_virtqueue *vq, bool zcopy)
{
@@ -134,21 +131,24 @@ vhost_net_ubuf_alloc(struct vhost_virtqueue *vq, bool zcopy)
ubufs = kmalloc(sizeof(*ubufs), GFP_KERNEL);
if (!ubufs)
return ERR_PTR(-ENOMEM);
- kref_init(&ubufs->kref);
+ atomic_set(&ubufs->refcount, 1);
init_waitqueue_head(&ubufs->wait);
ubufs->vq = vq;
return ubufs;
}
-static void vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs)
+static int vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs)
{
- kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal);
+ int r = atomic_sub_return(1, &ubufs->refcount);
+ if (unlikely(!r))
+ wake_up(&ubufs->wait);
+ return r;
}
static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs)
{
- kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal);
- wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount));
+ vhost_net_ubuf_put(ubufs);
+ wait_event(ubufs->wait, !atomic_read(&ubufs->refcount));
}
static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs)
@@ -306,23 +306,26 @@ static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success)
{
struct vhost_net_ubuf_ref *ubufs = ubuf->ctx;
struct vhost_virtqueue *vq = ubufs->vq;
- int cnt = atomic_read(&ubufs->kref.refcount);
+ int cnt;
+
+ rcu_read_lock_bh();
/* set len to mark this desc buffers done DMA */
vq->heads[ubuf->desc].len = success ?
VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN;
- vhost_net_ubuf_put(ubufs);
+ cnt = vhost_net_ubuf_put(ubufs);
/*
* Trigger polling thread if guest stopped submitting new buffers:
- * in this case, the refcount after decrement will eventually reach 1
- * so here it is 2.
+ * in this case, the refcount after decrement will eventually reach 1.
* We also trigger polling periodically after each 16 packets
* (the value 16 here is more or less arbitrary, it's tuned to trigger
* less than 10% of times).
*/
- if (cnt <= 2 || !(cnt % 16))
+ if (cnt <= 1 || !(cnt % 16))
vhost_poll_queue(&vq->poll);
+
+ rcu_read_unlock_bh();
}
/* Expects to be always run from workqueue - which acts as
@@ -420,7 +423,7 @@ static void handle_tx(struct vhost_net *net)
msg.msg_control = ubuf;
msg.msg_controllen = sizeof(ubuf);
ubufs = nvq->ubufs;
- kref_get(&ubufs->kref);
+ atomic_inc(&ubufs->refcount);
nvq->upend_idx = (nvq->upend_idx + 1) % UIO_MAXIOV;
} else {
msg.msg_control = NULL;
@@ -502,9 +505,13 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
r = -ENOBUFS;
goto err;
}
- d = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
+ r = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
ARRAY_SIZE(vq->iov) - seg, &out,
&in, log, log_num);
+ if (unlikely(r < 0))
+ goto err;
+
+ d = r;
if (d == vq->num) {
r = 0;
goto err;
@@ -529,6 +536,12 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
*iovcount = seg;
if (unlikely(log))
*log_num = nlogs;
+
+ /* Detect overrun */
+ if (unlikely(datalen > 0)) {
+ r = UIO_MAXIOV + 1;
+ goto err;
+ }
return headcount;
err:
vhost_discard_vq_desc(vq, headcount);
@@ -584,6 +597,14 @@ static void handle_rx(struct vhost_net *net)
/* On error, stop handling until the next kick. */
if (unlikely(headcount < 0))
break;
+ /* On overrun, truncate and discard */
+ if (unlikely(headcount > UIO_MAXIOV)) {
+ msg.msg_iovlen = 1;
+ err = sock->ops->recvmsg(NULL, sock, &msg,
+ 1, MSG_DONTWAIT | MSG_TRUNC);
+ pr_debug("Discarded rx packet: len %zd\n", sock_len);
+ continue;
+ }
/* OK, now we need to know about added descriptors. */
if (!headcount) {
if (unlikely(vhost_enable_notify(&net->dev, vq))) {
@@ -780,7 +801,7 @@ static void vhost_net_flush(struct vhost_net *n)
vhost_net_ubuf_put_and_wait(n->vqs[VHOST_NET_VQ_TX].ubufs);
mutex_lock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex);
n->tx_flush = false;
- kref_init(&n->vqs[VHOST_NET_VQ_TX].ubufs->kref);
+ atomic_set(&n->vqs[VHOST_NET_VQ_TX].ubufs->refcount, 1);
mutex_unlock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex);
}
}
@@ -800,6 +821,8 @@ static int vhost_net_release(struct inode *inode, struct file *f)
fput(tx_sock->file);
if (rx_sock)
fput(rx_sock->file);
+ /* Make sure no callbacks are outstanding */
+ synchronize_rcu_bh();
/* We do an extra flush before freeing memory,
* since jobs can re-queue themselves. */
vhost_net_flush(n);
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index 0a025b8e2a12..e48d4a672580 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -1001,6 +1001,12 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
break;
}
+ /* virtio-scsi spec requires byte 0 of the lun to be 1 */
+ if (unlikely(v_req.lun[0] != 1)) {
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ continue;
+ }
+
/* Extract the tpgt */
target = v_req.lun[1];
tpg = ACCESS_ONCE(vs_tpg[target]);
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index dade5b7699bc..b4b209ce8029 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -27,12 +27,6 @@ config VGASTATE
tristate
default n
-config VIDEO_OUTPUT_CONTROL
- tristate "Lowlevel video output switch controls"
- help
- This framework adds support for low-level control of the video
- output switch.
-
config VIDEOMODE_HELPERS
bool
@@ -802,18 +796,9 @@ config FB_HGA
As this card technology is at least 25 years old,
most people will answer N here.
-config FB_SGIVW
- tristate "SGI Visual Workstation framebuffer support"
- depends on FB && X86_VISWS
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
- help
- SGI Visual Workstation support for framebuffer graphics.
-
config FB_GBE
bool "SGI Graphics Backend frame buffer support"
- depends on (FB = y) && (SGI_IP32 || X86_VISWS)
+ depends on (FB = y) && SGI_IP32
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ae17ddf49a00..1be26fe10592 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -75,7 +75,6 @@ obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o
obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o
obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o
obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o
-obj-$(CONFIG_FB_SGIVW) += sgivwfb.o
obj-$(CONFIG_FB_ACORN) += acornfb.o
obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \
atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o
@@ -172,8 +171,6 @@ obj-$(CONFIG_FB_SIMPLE) += simplefb.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
-#video output switch sysfs driver
-obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o
ifeq ($(CONFIG_OF),y)
obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index 4c7cb368a9dc..3ec65a878ac8 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -45,10 +45,6 @@ struct gbefb_par {
#define GBE_BASE 0x16000000 /* SGI O2 */
#endif
-#ifdef CONFIG_X86_VISWS
-#define GBE_BASE 0xd0000000 /* SGI Visual Workstation */
-#endif
-
/* macro for fastest write-though access to the framebuffer */
#ifdef CONFIG_MIPS
#ifdef CONFIG_CPU_R10000
diff --git a/drivers/video/hyperv_fb.c b/drivers/video/hyperv_fb.c
index 130708f96430..e23392ec5af3 100644
--- a/drivers/video/hyperv_fb.c
+++ b/drivers/video/hyperv_fb.c
@@ -42,6 +42,7 @@
#include <linux/completion.h>
#include <linux/fb.h>
#include <linux/pci.h>
+#include <linux/efi.h>
#include <linux/hyperv.h>
@@ -212,6 +213,7 @@ struct synthvid_msg {
struct hvfb_par {
struct fb_info *info;
+ struct resource mem;
bool fb_ready; /* fb device is ready */
struct completion wait;
u32 synthvid_version;
@@ -460,13 +462,13 @@ static int synthvid_connect_vsp(struct hv_device *hdev)
goto error;
}
- if (par->synthvid_version == SYNTHVID_VERSION_WIN7) {
+ if (par->synthvid_version == SYNTHVID_VERSION_WIN7)
screen_depth = SYNTHVID_DEPTH_WIN7;
- screen_fb_size = SYNTHVID_FB_SIZE_WIN7;
- } else {
+ else
screen_depth = SYNTHVID_DEPTH_WIN8;
- screen_fb_size = SYNTHVID_FB_SIZE_WIN8;
- }
+
+ screen_fb_size = hdev->channel->offermsg.offer.
+ mmio_megabytes * 1024 * 1024;
return 0;
@@ -627,26 +629,46 @@ static void hvfb_get_option(struct fb_info *info)
/* Get framebuffer memory from Hyper-V video pci space */
static int hvfb_getmem(struct fb_info *info)
{
- struct pci_dev *pdev;
- ulong fb_phys;
+ struct hvfb_par *par = info->par;
+ struct pci_dev *pdev = NULL;
void __iomem *fb_virt;
+ int gen2vm = efi_enabled(EFI_BOOT);
+ int ret;
- pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
+ par->mem.name = KBUILD_MODNAME;
+ par->mem.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ if (gen2vm) {
+ ret = allocate_resource(&hyperv_mmio, &par->mem,
+ screen_fb_size,
+ 0, -1,
+ screen_fb_size,
+ NULL, NULL);
+ if (ret != 0) {
+ pr_err("Unable to allocate framebuffer memory\n");
+ return -ENODEV;
+ }
+ } else {
+ pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
- if (!pdev) {
- pr_err("Unable to find PCI Hyper-V video\n");
- return -ENODEV;
- }
+ if (!pdev) {
+ pr_err("Unable to find PCI Hyper-V video\n");
+ return -ENODEV;
+ }
- if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
- pci_resource_len(pdev, 0) < screen_fb_size)
- goto err1;
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
+ pci_resource_len(pdev, 0) < screen_fb_size)
+ goto err1;
- fb_phys = pci_resource_end(pdev, 0) - screen_fb_size + 1;
- if (!request_mem_region(fb_phys, screen_fb_size, KBUILD_MODNAME))
- goto err1;
+ par->mem.end = pci_resource_end(pdev, 0);
+ par->mem.start = par->mem.end - screen_fb_size + 1;
+ ret = request_resource(&pdev->resource[0], &par->mem);
+ if (ret != 0) {
+ pr_err("Unable to request framebuffer memory\n");
+ goto err1;
+ }
+ }
- fb_virt = ioremap(fb_phys, screen_fb_size);
+ fb_virt = ioremap(par->mem.start, screen_fb_size);
if (!fb_virt)
goto err2;
@@ -654,30 +676,44 @@ static int hvfb_getmem(struct fb_info *info)
if (!info->apertures)
goto err3;
- info->apertures->ranges[0].base = pci_resource_start(pdev, 0);
- info->apertures->ranges[0].size = pci_resource_len(pdev, 0);
- info->fix.smem_start = fb_phys;
+ if (gen2vm) {
+ info->apertures->ranges[0].base = screen_info.lfb_base;
+ info->apertures->ranges[0].size = screen_info.lfb_size;
+ remove_conflicting_framebuffers(info->apertures,
+ KBUILD_MODNAME, false);
+ } else {
+ info->apertures->ranges[0].base = pci_resource_start(pdev, 0);
+ info->apertures->ranges[0].size = pci_resource_len(pdev, 0);
+ }
+
+ info->fix.smem_start = par->mem.start;
info->fix.smem_len = screen_fb_size;
info->screen_base = fb_virt;
info->screen_size = screen_fb_size;
- pci_dev_put(pdev);
+ if (!gen2vm)
+ pci_dev_put(pdev);
+
return 0;
err3:
iounmap(fb_virt);
err2:
- release_mem_region(fb_phys, screen_fb_size);
+ release_resource(&par->mem);
err1:
- pci_dev_put(pdev);
+ if (!gen2vm)
+ pci_dev_put(pdev);
+
return -ENOMEM;
}
/* Release the framebuffer */
static void hvfb_putmem(struct fb_info *info)
{
+ struct hvfb_par *par = info->par;
+
iounmap(info->screen_base);
- release_mem_region(info->fix.smem_start, screen_fb_size);
+ release_resource(&par->mem);
}
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index 39ac49e0682c..0037104d66ac 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -54,7 +54,7 @@ config LOGO_PARISC_CLUT224
config LOGO_SGI_CLUT224
bool "224-color SGI Linux logo"
- depends on SGI_IP22 || SGI_IP27 || SGI_IP32 || X86_VISWS
+ depends on SGI_IP22 || SGI_IP27 || SGI_IP32
default y
config LOGO_SUN_CLUT224
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index b670cbda38e3..940cd196eef5 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -81,7 +81,7 @@ const struct linux_logo * __init_refok fb_find_logo(int depth)
logo = &logo_parisc_clut224;
#endif
#ifdef CONFIG_LOGO_SGI_CLUT224
- /* SGI Linux logo on MIPS/MIPS64 and VISWS */
+ /* SGI Linux logo on MIPS/MIPS64 */
logo = &logo_sgi_clut224;
#endif
#ifdef CONFIG_LOGO_SUN_CLUT224
diff --git a/drivers/video/output.c b/drivers/video/output.c
deleted file mode 100644
index 1446c49fe6af..000000000000
--- a/drivers/video/output.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * output.c - Display Output Switch driver
- *
- * Copyright (C) 2006 Luming Yu <luming.yu@intel.com>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#include <linux/module.h>
-#include <linux/video_output.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/ctype.h>
-
-
-MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
-
-static ssize_t state_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- ssize_t ret_size = 0;
- struct output_device *od = to_output_device(dev);
- if (od->props)
- ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od));
- return ret_size;
-}
-
-static ssize_t state_store(struct device *dev, struct device_attribute *attr,
- const char *buf,size_t count)
-{
- char *endp;
- struct output_device *od = to_output_device(dev);
- int request_state = simple_strtoul(buf,&endp,0);
- size_t size = endp - buf;
-
- if (isspace(*endp))
- size++;
- if (size != count)
- return -EINVAL;
-
- if (od->props) {
- od->request_state = request_state;
- od->props->set_state(od);
- }
- return count;
-}
-static DEVICE_ATTR_RW(state);
-
-static void video_output_release(struct device *dev)
-{
- struct output_device *od = to_output_device(dev);
- kfree(od);
-}
-
-static struct attribute *video_output_attrs[] = {
- &dev_attr_state.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(video_output);
-
-static struct class video_output_class = {
- .name = "video_output",
- .dev_release = video_output_release,
- .dev_groups = video_output_groups,
-};
-
-struct output_device *video_output_register(const char *name,
- struct device *dev,
- void *devdata,
- struct output_properties *op)
-{
- struct output_device *new_dev;
- int ret_code = 0;
-
- new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL);
- if (!new_dev) {
- ret_code = -ENOMEM;
- goto error_return;
- }
- new_dev->props = op;
- new_dev->dev.class = &video_output_class;
- new_dev->dev.parent = dev;
- dev_set_name(&new_dev->dev, "%s", name);
- dev_set_drvdata(&new_dev->dev, devdata);
- ret_code = device_register(&new_dev->dev);
- if (ret_code) {
- kfree(new_dev);
- goto error_return;
- }
- return new_dev;
-
-error_return:
- return ERR_PTR(ret_code);
-}
-EXPORT_SYMBOL(video_output_register);
-
-void video_output_unregister(struct output_device *dev)
-{
- if (!dev)
- return;
- device_unregister(&dev->dev);
-}
-EXPORT_SYMBOL(video_output_unregister);
-
-static void __exit video_output_class_exit(void)
-{
- class_unregister(&video_output_class);
-}
-
-static int __init video_output_class_init(void)
-{
- return class_register(&video_output_class);
-}
-
-postcore_initcall(video_output_class_init);
-module_exit(video_output_class_exit);
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
deleted file mode 100644
index bc74d0408998..000000000000
--- a/drivers/video/sgivwfb.c
+++ /dev/null
@@ -1,889 +0,0 @@
-/*
- * linux/drivers/video/sgivwfb.c -- SGI DBE frame buffer device
- *
- * Copyright (C) 1999 Silicon Graphics, Inc.
- * Jeffrey Newquist, newquist@engr.sgi.som
- *
- * 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.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-
-#include <asm/io.h>
-#include <asm/mtrr.h>
-#include <asm/visws/sgivw.h>
-
-#define INCLUDE_TIMING_TABLE_DATA
-#define DBE_REG_BASE par->regs
-#include <video/sgivw.h>
-
-struct sgivw_par {
- struct asregs *regs;
- u32 cmap_fifo;
- u_long timing_num;
-};
-
-#define FLATPANEL_SGI_1600SW 5
-
-/*
- * RAM we reserve for the frame buffer. This defines the maximum screen
- * size
- *
- * The default can be overridden if the driver is compiled as a module
- */
-
-static int ypan = 0;
-static int ywrap = 0;
-
-static int flatpanel_id = -1;
-
-static struct fb_fix_screeninfo sgivwfb_fix = {
- .id = "SGI Vis WS FB",
- .type = FB_TYPE_PACKED_PIXELS,
- .visual = FB_VISUAL_PSEUDOCOLOR,
- .mmio_start = DBE_REG_PHYS,
- .mmio_len = DBE_REG_SIZE,
- .accel = FB_ACCEL_NONE,
- .line_length = 640,
-};
-
-static struct fb_var_screeninfo sgivwfb_var = {
- /* 640x480, 8 bpp */
- .xres = 640,
- .yres = 480,
- .xres_virtual = 640,
- .yres_virtual = 480,
- .bits_per_pixel = 8,
- .red = { 0, 8, 0 },
- .green = { 0, 8, 0 },
- .blue = { 0, 8, 0 },
- .height = -1,
- .width = -1,
- .pixclock = 20000,
- .left_margin = 64,
- .right_margin = 64,
- .upper_margin = 32,
- .lower_margin = 32,
- .hsync_len = 64,
- .vsync_len = 2,
- .vmode = FB_VMODE_NONINTERLACED
-};
-
-static struct fb_var_screeninfo sgivwfb_var1600sw = {
- /* 1600x1024, 8 bpp */
- .xres = 1600,
- .yres = 1024,
- .xres_virtual = 1600,
- .yres_virtual = 1024,
- .bits_per_pixel = 8,
- .red = { 0, 8, 0 },
- .green = { 0, 8, 0 },
- .blue = { 0, 8, 0 },
- .height = -1,
- .width = -1,
- .pixclock = 9353,
- .left_margin = 20,
- .right_margin = 30,
- .upper_margin = 37,
- .lower_margin = 3,
- .hsync_len = 20,
- .vsync_len = 3,
- .vmode = FB_VMODE_NONINTERLACED
-};
-
-/*
- * Interface used by the world
- */
-int sgivwfb_init(void);
-
-static int sgivwfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
-static int sgivwfb_set_par(struct fb_info *info);
-static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green,
- u_int blue, u_int transp,
- struct fb_info *info);
-static int sgivwfb_mmap(struct fb_info *info,
- struct vm_area_struct *vma);
-
-static struct fb_ops sgivwfb_ops = {
- .owner = THIS_MODULE,
- .fb_check_var = sgivwfb_check_var,
- .fb_set_par = sgivwfb_set_par,
- .fb_setcolreg = sgivwfb_setcolreg,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
- .fb_mmap = sgivwfb_mmap,
-};
-
-/*
- * Internal routines
- */
-static unsigned long bytes_per_pixel(int bpp)
-{
- switch (bpp) {
- case 8:
- return 1;
- case 16:
- return 2;
- case 32:
- return 4;
- default:
- printk(KERN_INFO "sgivwfb: unsupported bpp %d\n", bpp);
- return 0;
- }
-}
-
-static unsigned long get_line_length(int xres_virtual, int bpp)
-{
- return (xres_virtual * bytes_per_pixel(bpp));
-}
-
-/*
- * Function: dbe_TurnOffDma
- * Parameters: (None)
- * Description: This should turn off the monitor and dbe. This is used
- * when switching between the serial console and the graphics
- * console.
- */
-
-static void dbe_TurnOffDma(struct sgivw_par *par)
-{
- unsigned int readVal;
- int i;
-
- // Check to see if things are already turned off:
- // 1) Check to see if dbe is not using the internal dotclock.
- // 2) Check to see if the xy counter in dbe is already off.
-
- DBE_GETREG(ctrlstat, readVal);
- if (GET_DBE_FIELD(CTRLSTAT, PCLKSEL, readVal) < 2)
- return;
-
- DBE_GETREG(vt_xy, readVal);
- if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1)
- return;
-
- // Otherwise, turn off dbe
-
- DBE_GETREG(ovr_control, readVal);
- SET_DBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, readVal, 0);
- DBE_SETREG(ovr_control, readVal);
- udelay(1000);
- DBE_GETREG(frm_control, readVal);
- SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, readVal, 0);
- DBE_SETREG(frm_control, readVal);
- udelay(1000);
- DBE_GETREG(did_control, readVal);
- SET_DBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, readVal, 0);
- DBE_SETREG(did_control, readVal);
- udelay(1000);
-
- // XXX HACK:
- //
- // This was necessary for GBE--we had to wait through two
- // vertical retrace periods before the pixel DMA was
- // turned off for sure. I've left this in for now, in
- // case dbe needs it.
-
- for (i = 0; i < 10000; i++) {
- DBE_GETREG(frm_inhwctrl, readVal);
- if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) ==
- 0)
- udelay(10);
- else {
- DBE_GETREG(ovr_inhwctrl, readVal);
- if (GET_DBE_FIELD
- (OVR_INHWCTRL, OVR_DMA_ENABLE, readVal) == 0)
- udelay(10);
- else {
- DBE_GETREG(did_inhwctrl, readVal);
- if (GET_DBE_FIELD
- (DID_INHWCTRL, DID_DMA_ENABLE,
- readVal) == 0)
- udelay(10);
- else
- break;
- }
- }
- }
-}
-
-/*
- * Set the User Defined Part of the Display. Again if par use it to get
- * real video mode.
- */
-static int sgivwfb_check_var(struct fb_var_screeninfo *var,
- struct fb_info *info)
-{
- struct sgivw_par *par = (struct sgivw_par *)info->par;
- struct dbe_timing_info *timing;
- u_long line_length;
- u_long min_mode;
- int req_dot;
- int test_mode;
-
- /*
- * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
- * as FB_VMODE_SMOOTH_XPAN is only used internally
- */
-
- if (var->vmode & FB_VMODE_CONUPDATE) {
- var->vmode |= FB_VMODE_YWRAP;
- var->xoffset = info->var.xoffset;
- var->yoffset = info->var.yoffset;
- }
-
- /* XXX FIXME - forcing var's */
- var->xoffset = 0;
- var->yoffset = 0;
-
- /* Limit bpp to 8, 16, and 32 */
- if (var->bits_per_pixel <= 8)
- var->bits_per_pixel = 8;
- else if (var->bits_per_pixel <= 16)
- var->bits_per_pixel = 16;
- else if (var->bits_per_pixel <= 32)
- var->bits_per_pixel = 32;
- else
- return -EINVAL;
-
- var->grayscale = 0; /* No grayscale for now */
-
- /* determine valid resolution and timing */
- for (min_mode = 0; min_mode < ARRAY_SIZE(dbeVTimings); min_mode++) {
- if (dbeVTimings[min_mode].width >= var->xres &&
- dbeVTimings[min_mode].height >= var->yres)
- break;
- }
-
- if (min_mode == ARRAY_SIZE(dbeVTimings))
- return -EINVAL; /* Resolution to high */
-
- /* XXX FIXME - should try to pick best refresh rate */
- /* for now, pick closest dot-clock within 3MHz */
- req_dot = PICOS2KHZ(var->pixclock);
- printk(KERN_INFO "sgivwfb: requested pixclock=%d ps (%d KHz)\n",
- var->pixclock, req_dot);
- test_mode = min_mode;
- while (dbeVTimings[min_mode].width == dbeVTimings[test_mode].width) {
- if (dbeVTimings[test_mode].cfreq + 3000 > req_dot)
- break;
- test_mode++;
- }
- if (dbeVTimings[min_mode].width != dbeVTimings[test_mode].width)
- test_mode--;
- min_mode = test_mode;
- timing = &dbeVTimings[min_mode];
- printk(KERN_INFO "sgivwfb: granted dot-clock=%d KHz\n", timing->cfreq);
-
- /* Adjust virtual resolution, if necessary */
- if (var->xres > var->xres_virtual || (!ywrap && !ypan))
- var->xres_virtual = var->xres;
- if (var->yres > var->yres_virtual || (!ywrap && !ypan))
- var->yres_virtual = var->yres;
-
- /*
- * Memory limit
- */
- line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
- if (line_length * var->yres_virtual > sgivwfb_mem_size)
- return -ENOMEM; /* Virtual resolution to high */
-
- info->fix.line_length = line_length;
-
- switch (var->bits_per_pixel) {
- case 8:
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 0;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case 16: /* RGBA 5551 */
- var->red.offset = 11;
- var->red.length = 5;
- var->green.offset = 6;
- var->green.length = 5;
- var->blue.offset = 1;
- var->blue.length = 5;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case 32: /* RGB 8888 */
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 16;
- var->blue.length = 8;
- var->transp.offset = 24;
- var->transp.length = 8;
- break;
- }
- var->red.msb_right = 0;
- var->green.msb_right = 0;
- var->blue.msb_right = 0;
- var->transp.msb_right = 0;
-
- /* set video timing information */
- var->pixclock = KHZ2PICOS(timing->cfreq);
- var->left_margin = timing->htotal - timing->hsync_end;
- var->right_margin = timing->hsync_start - timing->width;
- var->upper_margin = timing->vtotal - timing->vsync_end;
- var->lower_margin = timing->vsync_start - timing->height;
- var->hsync_len = timing->hsync_end - timing->hsync_start;
- var->vsync_len = timing->vsync_end - timing->vsync_start;
-
- /* Ouch. This breaks the rules but timing_num is only important if you
- * change a video mode */
- par->timing_num = min_mode;
-
- printk(KERN_INFO "sgivwfb: new video mode xres=%d yres=%d bpp=%d\n",
- var->xres, var->yres, var->bits_per_pixel);
- printk(KERN_INFO " vxres=%d vyres=%d\n", var->xres_virtual,
- var->yres_virtual);
- return 0;
-}
-
-/*
- * Setup flatpanel related registers.
- */
-static void sgivwfb_setup_flatpanel(struct sgivw_par *par, struct dbe_timing_info *currentTiming)
-{
- int fp_wid, fp_hgt, fp_vbs, fp_vbe;
- u32 outputVal = 0;
-
- SET_DBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal,
- (currentTiming->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
- SET_DBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal,
- (currentTiming->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
- DBE_SETREG(vt_flags, outputVal);
-
- /* Turn on the flat panel */
- switch (flatpanel_id) {
- case FLATPANEL_SGI_1600SW:
- fp_wid = 1600;
- fp_hgt = 1024;
- fp_vbs = 0;
- fp_vbe = 1600;
- currentTiming->pll_m = 4;
- currentTiming->pll_n = 1;
- currentTiming->pll_p = 0;
- break;
- default:
- fp_wid = fp_hgt = fp_vbs = fp_vbe = 0xfff;
- }
-
- outputVal = 0;
- SET_DBE_FIELD(FP_DE, FP_DE_ON, outputVal, fp_vbs);
- SET_DBE_FIELD(FP_DE, FP_DE_OFF, outputVal, fp_vbe);
- DBE_SETREG(fp_de, outputVal);
- outputVal = 0;
- SET_DBE_FIELD(FP_HDRV, FP_HDRV_OFF, outputVal, fp_wid);
- DBE_SETREG(fp_hdrv, outputVal);
- outputVal = 0;
- SET_DBE_FIELD(FP_VDRV, FP_VDRV_ON, outputVal, 1);
- SET_DBE_FIELD(FP_VDRV, FP_VDRV_OFF, outputVal, fp_hgt + 1);
- DBE_SETREG(fp_vdrv, outputVal);
-}
-
-/*
- * Set the hardware according to 'par'.
- */
-static int sgivwfb_set_par(struct fb_info *info)
-{
- struct sgivw_par *par = info->par;
- int i, j, htmp, temp;
- u32 readVal, outputVal;
- int wholeTilesX, maxPixelsPerTileX;
- int frmWrite1, frmWrite2, frmWrite3b;
- struct dbe_timing_info *currentTiming; /* Current Video Timing */
- int xpmax, ypmax; // Monitor resolution
- int bytesPerPixel; // Bytes per pixel
-
- currentTiming = &dbeVTimings[par->timing_num];
- bytesPerPixel = bytes_per_pixel(info->var.bits_per_pixel);
- xpmax = currentTiming->width;
- ypmax = currentTiming->height;
-
- /* dbe_InitGraphicsBase(); */
- /* Turn on dotclock PLL */
- DBE_SETREG(ctrlstat, 0x20000000);
-
- dbe_TurnOffDma(par);
-
- /* dbe_CalculateScreenParams(); */
- maxPixelsPerTileX = 512 / bytesPerPixel;
- wholeTilesX = xpmax / maxPixelsPerTileX;
- if (wholeTilesX * maxPixelsPerTileX < xpmax)
- wholeTilesX++;
-
- printk(KERN_DEBUG "sgivwfb: pixPerTile=%d wholeTilesX=%d\n",
- maxPixelsPerTileX, wholeTilesX);
-
- /* dbe_InitGammaMap(); */
- udelay(10);
-
- for (i = 0; i < 256; i++) {
- DBE_ISETREG(gmap, i, (i << 24) | (i << 16) | (i << 8));
- }
-
- /* dbe_TurnOn(); */
- DBE_GETREG(vt_xy, readVal);
- if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) {
- DBE_SETREG(vt_xy, 0x00000000);
- udelay(1);
- } else
- dbe_TurnOffDma(par);
-
- /* dbe_Initdbe(); */
- for (i = 0; i < 256; i++) {
- for (j = 0; j < 100; j++) {
- DBE_GETREG(cm_fifo, readVal);
- if (readVal != 0x00000000)
- break;
- else
- udelay(10);
- }
-
- // DBE_ISETREG(cmap, i, 0x00000000);
- DBE_ISETREG(cmap, i, (i << 8) | (i << 16) | (i << 24));
- }
-
- /* dbe_InitFramebuffer(); */
- frmWrite1 = 0;
- SET_DBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, frmWrite1,
- wholeTilesX);
- SET_DBE_FIELD(FRM_SIZE_TILE, FRM_RHS, frmWrite1, 0);
-
- switch (bytesPerPixel) {
- case 1:
- SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1,
- DBE_FRM_DEPTH_8);
- break;
- case 2:
- SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1,
- DBE_FRM_DEPTH_16);
- break;
- case 4:
- SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1,
- DBE_FRM_DEPTH_32);
- break;
- }
-
- frmWrite2 = 0;
- SET_DBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, frmWrite2, ypmax);
-
- // Tell dbe about the framebuffer location and type
- // XXX What format is the FRM_TILE_PTR?? 64K aligned address?
- frmWrite3b = 0;
- SET_DBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, frmWrite3b,
- sgivwfb_mem_phys >> 9);
- SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, frmWrite3b, 1);
- SET_DBE_FIELD(FRM_CONTROL, FRM_LINEAR, frmWrite3b, 1);
-
- /* Initialize DIDs */
-
- outputVal = 0;
- switch (bytesPerPixel) {
- case 1:
- SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_I8);
- break;
- case 2:
- SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGBA5);
- break;
- case 4:
- SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGB8);
- break;
- }
- SET_DBE_FIELD(WID, BUF, outputVal, DBE_BMODE_BOTH);
-
- for (i = 0; i < 32; i++) {
- DBE_ISETREG(mode_regs, i, outputVal);
- }
-
- /* dbe_InitTiming(); */
- DBE_SETREG(vt_intr01, 0xffffffff);
- DBE_SETREG(vt_intr23, 0xffffffff);
-
- DBE_GETREG(dotclock, readVal);
- DBE_SETREG(dotclock, readVal & 0xffff);
-
- DBE_SETREG(vt_xymax, 0x00000000);
- outputVal = 0;
- SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_ON, outputVal,
- currentTiming->vsync_start);
- SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_OFF, outputVal,
- currentTiming->vsync_end);
- DBE_SETREG(vt_vsync, outputVal);
- outputVal = 0;
- SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_ON, outputVal,
- currentTiming->hsync_start);
- SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_OFF, outputVal,
- currentTiming->hsync_end);
- DBE_SETREG(vt_hsync, outputVal);
- outputVal = 0;
- SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_ON, outputVal,
- currentTiming->vblank_start);
- SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_OFF, outputVal,
- currentTiming->vblank_end);
- DBE_SETREG(vt_vblank, outputVal);
- outputVal = 0;
- SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_ON, outputVal,
- currentTiming->hblank_start);
- SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_OFF, outputVal,
- currentTiming->hblank_end - 3);
- DBE_SETREG(vt_hblank, outputVal);
- outputVal = 0;
- SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_ON, outputVal,
- currentTiming->vblank_start);
- SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_OFF, outputVal,
- currentTiming->vblank_end);
- DBE_SETREG(vt_vcmap, outputVal);
- outputVal = 0;
- SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_ON, outputVal,
- currentTiming->hblank_start);
- SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_OFF, outputVal,
- currentTiming->hblank_end - 3);
- DBE_SETREG(vt_hcmap, outputVal);
-
- if (flatpanel_id != -1)
- sgivwfb_setup_flatpanel(par, currentTiming);
-
- outputVal = 0;
- temp = currentTiming->vblank_start - currentTiming->vblank_end - 1;
- if (temp > 0)
- temp = -temp;
-
- SET_DBE_FIELD(DID_START_XY, DID_STARTY, outputVal, (u32) temp);
- if (currentTiming->hblank_end >= 20)
- SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal,
- currentTiming->hblank_end - 20);
- else
- SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal,
- currentTiming->htotal - (20 -
- currentTiming->
- hblank_end));
- DBE_SETREG(did_start_xy, outputVal);
-
- outputVal = 0;
- SET_DBE_FIELD(CRS_START_XY, CRS_STARTY, outputVal,
- (u32) (temp + 1));
- if (currentTiming->hblank_end >= DBE_CRS_MAGIC)
- SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal,
- currentTiming->hblank_end - DBE_CRS_MAGIC);
- else
- SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal,
- currentTiming->htotal - (DBE_CRS_MAGIC -
- currentTiming->
- hblank_end));
- DBE_SETREG(crs_start_xy, outputVal);
-
- outputVal = 0;
- SET_DBE_FIELD(VC_START_XY, VC_STARTY, outputVal, (u32) temp);
- SET_DBE_FIELD(VC_START_XY, VC_STARTX, outputVal,
- currentTiming->hblank_end - 4);
- DBE_SETREG(vc_start_xy, outputVal);
-
- DBE_SETREG(frm_size_tile, frmWrite1);
- DBE_SETREG(frm_size_pixel, frmWrite2);
-
- outputVal = 0;
- SET_DBE_FIELD(DOTCLK, M, outputVal, currentTiming->pll_m - 1);
- SET_DBE_FIELD(DOTCLK, N, outputVal, currentTiming->pll_n - 1);
- SET_DBE_FIELD(DOTCLK, P, outputVal, currentTiming->pll_p);
- SET_DBE_FIELD(DOTCLK, RUN, outputVal, 1);
- DBE_SETREG(dotclock, outputVal);
-
- udelay(11 * 1000);
-
- DBE_SETREG(vt_vpixen, 0xffffff);
- DBE_SETREG(vt_hpixen, 0xffffff);
-
- outputVal = 0;
- SET_DBE_FIELD(VT_XYMAX, VT_MAXX, outputVal, currentTiming->htotal);
- SET_DBE_FIELD(VT_XYMAX, VT_MAXY, outputVal, currentTiming->vtotal);
- DBE_SETREG(vt_xymax, outputVal);
-
- outputVal = frmWrite1;
- SET_DBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, outputVal, 1);
- DBE_SETREG(frm_size_tile, outputVal);
- DBE_SETREG(frm_size_tile, frmWrite1);
-
- outputVal = 0;
- SET_DBE_FIELD(OVR_WIDTH_TILE, OVR_FIFO_RESET, outputVal, 1);
- DBE_SETREG(ovr_width_tile, outputVal);
- DBE_SETREG(ovr_width_tile, 0);
-
- DBE_SETREG(frm_control, frmWrite3b);
- DBE_SETREG(did_control, 0);
-
- // Wait for dbe to take frame settings
- for (i = 0; i < 100000; i++) {
- DBE_GETREG(frm_inhwctrl, readVal);
- if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) !=
- 0)
- break;
- else
- udelay(1);
- }
-
- if (i == 100000)
- printk(KERN_INFO
- "sgivwfb: timeout waiting for frame DMA enable.\n");
-
- outputVal = 0;
- htmp = currentTiming->hblank_end - 19;
- if (htmp < 0)
- htmp += currentTiming->htotal; /* allow blank to wrap around */
- SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_ON, outputVal, htmp);
- SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_OFF, outputVal,
- ((htmp + currentTiming->width -
- 2) % currentTiming->htotal));
- DBE_SETREG(vt_hpixen, outputVal);
-
- outputVal = 0;
- SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_OFF, outputVal,
- currentTiming->vblank_start);
- SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_ON, outputVal,
- currentTiming->vblank_end);
- DBE_SETREG(vt_vpixen, outputVal);
-
- // Turn off mouse cursor
- par->regs->crs_ctl = 0;
-
- // XXX What's this section for??
- DBE_GETREG(ctrlstat, readVal);
- readVal &= 0x02000000;
-
- if (readVal != 0) {
- DBE_SETREG(ctrlstat, 0x30000000);
- }
- return 0;
-}
-
-/*
- * Set a single color register. The values supplied are already
- * rounded down to the hardware's capabilities (according to the
- * entries in the var structure). Return != 0 for invalid regno.
- */
-
-static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green,
- u_int blue, u_int transp,
- struct fb_info *info)
-{
- struct sgivw_par *par = (struct sgivw_par *) info->par;
-
- if (regno > 255)
- return 1;
- red >>= 8;
- green >>= 8;
- blue >>= 8;
-
- /* wait for the color map FIFO to have a free entry */
- while (par->cmap_fifo == 0)
- par->cmap_fifo = par->regs->cm_fifo;
-
- par->regs->cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
- par->cmap_fifo--; /* assume FIFO is filling up */
- return 0;
-}
-
-static int sgivwfb_mmap(struct fb_info *info,
- struct vm_area_struct *vma)
-{
- int r;
-
- pgprot_val(vma->vm_page_prot) =
- pgprot_val(vma->vm_page_prot) | _PAGE_PCD;
-
- r = vm_iomap_memory(vma, sgivwfb_mem_phys, sgivwfb_mem_size);
-
- printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
- sgivwfb_mem_phys + (vma->vm_pgoff << PAGE_SHIFT), vma->vm_start);
-
- return r;
-}
-
-int __init sgivwfb_setup(char *options)
-{
- char *this_opt;
-
- if (!options || !*options)
- return 0;
-
- while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!strncmp(this_opt, "monitor:", 8)) {
- if (!strncmp(this_opt + 8, "crt", 3))
- flatpanel_id = -1;
- else if (!strncmp(this_opt + 8, "1600sw", 6))
- flatpanel_id = FLATPANEL_SGI_1600SW;
- }
- }
- return 0;
-}
-
-/*
- * Initialisation
- */
-static int sgivwfb_probe(struct platform_device *dev)
-{
- struct sgivw_par *par;
- struct fb_info *info;
- char *monitor;
-
- info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 16, &dev->dev);
- if (!info)
- return -ENOMEM;
- par = info->par;
-
- if (!request_mem_region(DBE_REG_PHYS, DBE_REG_SIZE, "sgivwfb")) {
- printk(KERN_ERR "sgivwfb: couldn't reserve mmio region\n");
- framebuffer_release(info);
- return -EBUSY;
- }
-
- par->regs = (struct asregs *) ioremap_nocache(DBE_REG_PHYS, DBE_REG_SIZE);
- if (!par->regs) {
- printk(KERN_ERR "sgivwfb: couldn't ioremap registers\n");
- goto fail_ioremap_regs;
- }
-
- mtrr_add(sgivwfb_mem_phys, sgivwfb_mem_size, MTRR_TYPE_WRCOMB, 1);
-
- sgivwfb_fix.smem_start = sgivwfb_mem_phys;
- sgivwfb_fix.smem_len = sgivwfb_mem_size;
- sgivwfb_fix.ywrapstep = ywrap;
- sgivwfb_fix.ypanstep = ypan;
-
- info->fix = sgivwfb_fix;
-
- switch (flatpanel_id) {
- case FLATPANEL_SGI_1600SW:
- info->var = sgivwfb_var1600sw;
- monitor = "SGI 1600SW flatpanel";
- break;
- default:
- info->var = sgivwfb_var;
- monitor = "CRT";
- }
-
- printk(KERN_INFO "sgivwfb: %s monitor selected\n", monitor);
-
- info->fbops = &sgivwfb_ops;
- info->pseudo_palette = (void *) (par + 1);
- info->flags = FBINFO_DEFAULT;
-
- info->screen_base = ioremap_nocache((unsigned long) sgivwfb_mem_phys, sgivwfb_mem_size);
- if (!info->screen_base) {
- printk(KERN_ERR "sgivwfb: couldn't ioremap screen_base\n");
- goto fail_ioremap_fbmem;
- }
-
- if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
- goto fail_color_map;
-
- if (register_framebuffer(info) < 0) {
- printk(KERN_ERR "sgivwfb: couldn't register framebuffer\n");
- goto fail_register_framebuffer;
- }
-
- platform_set_drvdata(dev, info);
-
- fb_info(info, "SGI DBE frame buffer device, using %ldK of video memory at %#lx\n",
- sgivwfb_mem_size >> 10, sgivwfb_mem_phys);
- return 0;
-
-fail_register_framebuffer:
- fb_dealloc_cmap(&info->cmap);
-fail_color_map:
- iounmap((char *) info->screen_base);
-fail_ioremap_fbmem:
- iounmap(par->regs);
-fail_ioremap_regs:
- release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE);
- framebuffer_release(info);
- return -ENXIO;
-}
-
-static int sgivwfb_remove(struct platform_device *dev)
-{
- struct fb_info *info = platform_get_drvdata(dev);
-
- if (info) {
- struct sgivw_par *par = info->par;
-
- unregister_framebuffer(info);
- dbe_TurnOffDma(par);
- iounmap(par->regs);
- iounmap(info->screen_base);
- release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE);
- fb_dealloc_cmap(&info->cmap);
- framebuffer_release(info);
- }
- return 0;
-}
-
-static struct platform_driver sgivwfb_driver = {
- .probe = sgivwfb_probe,
- .remove = sgivwfb_remove,
- .driver = {
- .name = "sgivwfb",
- },
-};
-
-static struct platform_device *sgivwfb_device;
-
-int __init sgivwfb_init(void)
-{
- int ret;
-
-#ifndef MODULE
- char *option = NULL;
-
- if (fb_get_options("sgivwfb", &option))
- return -ENODEV;
- sgivwfb_setup(option);
-#endif
- ret = platform_driver_register(&sgivwfb_driver);
- if (!ret) {
- sgivwfb_device = platform_device_alloc("sgivwfb", 0);
- if (sgivwfb_device) {
- ret = platform_device_add(sgivwfb_device);
- } else
- ret = -ENOMEM;
- if (ret) {
- platform_driver_unregister(&sgivwfb_driver);
- platform_device_put(sgivwfb_device);
- }
- }
- return ret;
-}
-
-module_init(sgivwfb_init);
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-static void __exit sgivwfb_exit(void)
-{
- platform_device_unregister(sgivwfb_device);
- platform_driver_unregister(&sgivwfb_driver);
-}
-
-module_exit(sgivwfb_exit);
-
-#endif /* MODULE */
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index 256fba7f4641..1f38445014c1 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -190,7 +190,7 @@ static int uvesafb_exec(struct uvesafb_ktask *task)
uvfb_tasks[seq] = task;
mutex_unlock(&uvfb_lock);
- err = cn_netlink_send(m, 0, GFP_KERNEL);
+ err = cn_netlink_send(m, 0, 0, GFP_KERNEL);
if (err == -ESRCH) {
/*
* Try to start the userspace helper if sending
@@ -204,7 +204,7 @@ static int uvesafb_exec(struct uvesafb_ktask *task)
"helper is installed and executable\n");
} else {
v86d_started = 1;
- err = cn_netlink_send(m, 0, gfp_any());
+ err = cn_netlink_send(m, 0, 0, gfp_any());
if (err == -ENOBUFS)
err = 0;
}
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 34bdabaecbd6..25ebe8eecdb7 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -108,8 +108,7 @@ static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)
sg_init_one(&sg, vb->pfns, sizeof(vb->pfns[0]) * vb->num_pfns);
/* We should always be able to add one buffer to an empty queue. */
- if (virtqueue_add_outbuf(vq, &sg, 1, vb, GFP_KERNEL) < 0)
- BUG();
+ virtqueue_add_outbuf(vq, &sg, 1, vb, GFP_KERNEL);
virtqueue_kick(vq);
/* When host has read buffer, this completes via balloon_ack */
@@ -258,8 +257,7 @@ static void stats_handle_request(struct virtio_balloon *vb)
if (!virtqueue_get_buf(vq, &len))
return;
sg_init_one(&sg, vb->stats, sizeof(vb->stats));
- if (virtqueue_add_outbuf(vq, &sg, 1, vb, GFP_KERNEL) < 0)
- BUG();
+ virtqueue_add_outbuf(vq, &sg, 1, vb, GFP_KERNEL);
virtqueue_kick(vq);
}
@@ -310,6 +308,12 @@ static int balloon(void *_vballoon)
else if (diff < 0)
leak_balloon(vb, -diff);
update_balloon_size(vb);
+
+ /*
+ * For large balloon changes, we could spend a lot of time
+ * and always have work to do. Be nice if preempt disabled.
+ */
+ cond_resched();
}
return 0;
}
@@ -338,7 +342,7 @@ static int init_vqs(struct virtio_balloon *vb)
/*
* Prime this virtqueue with one buffer so the hypervisor can
- * use it to signal us later.
+ * use it to signal us later (it can't be broken yet!).
*/
sg_init_one(&sg, vb->stats, sizeof vb->stats);
if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL)
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index a416f9b2a7f6..101db3faf5d4 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -333,10 +333,8 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
for (i = 0; i < nvectors; ++i)
vp_dev->msix_entries[i].entry = i;
- /* pci_enable_msix returns positive if we can't get this many. */
- err = pci_enable_msix(vp_dev->pci_dev, vp_dev->msix_entries, nvectors);
- if (err > 0)
- err = -ENOSPC;
+ err = pci_enable_msix_exact(vp_dev->pci_dev,
+ vp_dev->msix_entries, nvectors);
if (err)
goto error;
vp_dev->msix_enabled = 1;
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 28b5338fff71..1e443629f76d 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/hrtimer.h>
+#include <linux/kmemleak.h>
#ifdef DEBUG
/* For development, we want to crash whenever the ring is screwed. */
@@ -203,6 +204,11 @@ static inline int virtqueue_add(struct virtqueue *_vq,
BUG_ON(data == NULL);
+ if (unlikely(vq->broken)) {
+ END_USE(vq);
+ return -EIO;
+ }
+
#ifdef DEBUG
{
ktime_t now = ktime_get();
@@ -309,7 +315,7 @@ add_head:
* Caller must ensure we don't call this with other virtqueue operations
* at the same time (except where noted).
*
- * Returns zero or a negative error (ie. ENOSPC, ENOMEM).
+ * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
*/
int virtqueue_add_sgs(struct virtqueue *_vq,
struct scatterlist *sgs[],
@@ -347,7 +353,7 @@ EXPORT_SYMBOL_GPL(virtqueue_add_sgs);
* Caller must ensure we don't call this with other virtqueue operations
* at the same time (except where noted).
*
- * Returns zero or a negative error (ie. ENOSPC, ENOMEM).
+ * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
*/
int virtqueue_add_outbuf(struct virtqueue *vq,
struct scatterlist sg[], unsigned int num,
@@ -369,7 +375,7 @@ EXPORT_SYMBOL_GPL(virtqueue_add_outbuf);
* Caller must ensure we don't call this with other virtqueue operations
* at the same time (except where noted).
*
- * Returns zero or a negative error (ie. ENOSPC, ENOMEM).
+ * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
*/
int virtqueue_add_inbuf(struct virtqueue *vq,
struct scatterlist sg[], unsigned int num,
diff --git a/drivers/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c
index 1b5d48c578e1..bfb2d3f06738 100644
--- a/drivers/vme/bridges/vme_ca91cx42.c
+++ b/drivers/vme/bridges/vme_ca91cx42.c
@@ -869,14 +869,13 @@ static ssize_t ca91cx42_master_read(struct vme_master_resource *image,
spin_lock(&image->lock);
- /* The following code handles VME address alignment problem
- * in order to assure the maximal data width cycle.
- * We cannot use memcpy_xxx directly here because it
- * may cut data transfer in 8-bits cycles, thus making
- * D16 cycle impossible.
- * From the other hand, the bridge itself assures that
- * maximal configured data cycle is used and splits it
- * automatically for non-aligned addresses.
+ /* The following code handles VME address alignment. We cannot use
+ * memcpy_xxx here because it may cut data transfers in to 8-bit
+ * cycles when D16 or D32 cycles are required on the VME bus.
+ * On the other hand, the bridge itself assures that the maximum data
+ * cycle configured for the transfer is used and splits it
+ * automatically for non-aligned addresses, so we don't want the
+ * overhead of needlessly forcing small transfers for the entire cycle.
*/
if ((uintptr_t)addr & 0x1) {
*(u8 *)buf = ioread8(addr);
@@ -896,9 +895,9 @@ static ssize_t ca91cx42_master_read(struct vme_master_resource *image,
}
count32 = (count - done) & ~0x3;
- if (count32 > 0) {
- memcpy_fromio(buf + done, addr + done, (unsigned int)count);
- done += count32;
+ while (done < count32) {
+ *(u32 *)(buf + done) = ioread32(addr + done);
+ done += 4;
}
if ((count - done) & 0x2) {
@@ -930,7 +929,7 @@ static ssize_t ca91cx42_master_write(struct vme_master_resource *image,
spin_lock(&image->lock);
/* Here we apply for the same strategy we do in master_read
- * function in order to assure D16 cycle when required.
+ * function in order to assure the correct cycles.
*/
if ((uintptr_t)addr & 0x1) {
iowrite8(*(u8 *)buf, addr);
@@ -950,9 +949,9 @@ static ssize_t ca91cx42_master_write(struct vme_master_resource *image,
}
count32 = (count - done) & ~0x3;
- if (count32 > 0) {
- memcpy_toio(addr + done, buf + done, count32);
- done += count32;
+ while (done < count32) {
+ iowrite32(*(u32 *)(buf + done), addr + done);
+ done += 4;
}
if ((count - done) & 0x2) {
diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c
index 9911cd5fddb5..06990c6a1a69 100644
--- a/drivers/vme/bridges/vme_tsi148.c
+++ b/drivers/vme/bridges/vme_tsi148.c
@@ -1276,8 +1276,8 @@ static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
spin_lock(&image->lock);
/* The following code handles VME address alignment. We cannot use
- * memcpy_xxx directly here because it may cut small data transfers in
- * to 8-bit cycles, thus making D16 cycle impossible.
+ * memcpy_xxx here because it may cut data transfers in to 8-bit
+ * cycles when D16 or D32 cycles are required on the VME bus.
* On the other hand, the bridge itself assures that the maximum data
* cycle configured for the transfer is used and splits it
* automatically for non-aligned addresses, so we don't want the
@@ -1301,9 +1301,9 @@ static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
}
count32 = (count - done) & ~0x3;
- if (count32 > 0) {
- memcpy_fromio(buf + done, addr + done, count32);
- done += count32;
+ while (done < count32) {
+ *(u32 *)(buf + done) = ioread32(addr + done);
+ done += 4;
}
if ((count - done) & 0x2) {
@@ -1363,7 +1363,7 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
spin_lock(&image->lock);
/* Here we apply for the same strategy we do in master_read
- * function in order to assure D16 cycle when required.
+ * function in order to assure the correct cycles.
*/
if ((uintptr_t)addr & 0x1) {
iowrite8(*(u8 *)buf, addr);
@@ -1383,9 +1383,9 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
}
count32 = (count - done) & ~0x3;
- if (count32 > 0) {
- memcpy_toio(addr + done, buf + done, count32);
- done += count32;
+ while (done < count32) {
+ iowrite32(*(u32 *)(buf + done), addr + done);
+ done += 4;
}
if ((count - done) & 0x2) {
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
index efc7f075fcbe..1708b2300c7a 100644
--- a/drivers/w1/masters/Kconfig
+++ b/drivers/w1/masters/Kconfig
@@ -36,13 +36,12 @@ config W1_MASTER_DS2482
config W1_MASTER_MXC
tristate "Freescale MXC 1-wire busmaster"
- depends on W1 && ARCH_MXC
+ depends on ARCH_MXC || COMPILE_TEST
help
Say Y here to enable MXC 1-wire host
config W1_MASTER_DS1WM
tristate "Maxim DS1WM 1-wire busmaster"
- depends on W1
help
Say Y here to enable the DS1WM 1-wire driver, such as that
in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c
index 4f7e1d770f81..7404ad3062b7 100644
--- a/drivers/w1/masters/ds2490.c
+++ b/drivers/w1/masters/ds2490.c
@@ -1,5 +1,5 @@
/*
- * dscore.c
+ * ds2490.c USB to one wire bridge
*
* Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
@@ -28,6 +28,10 @@
#include "../w1_int.h"
#include "../w1.h"
+/* USB Standard */
+/* USB Control request vendor type */
+#define VENDOR 0x40
+
/* COMMAND TYPE CODES */
#define CONTROL_CMD 0x00
#define COMM_CMD 0x01
@@ -107,6 +111,8 @@
#define ST_HALT 0x10 /* DS2490 is currently halted */
#define ST_IDLE 0x20 /* DS2490 is currently idle */
#define ST_EPOF 0x80
+/* Status transfer size, 16 bytes status, 16 byte result flags */
+#define ST_SIZE 0x20
/* Result Register flags */
#define RR_DETECT 0xA5 /* New device detected */
@@ -198,7 +204,7 @@ static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
int err;
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
- CONTROL_CMD, 0x40, value, index, NULL, 0, 1000);
+ CONTROL_CMD, VENDOR, value, index, NULL, 0, 1000);
if (err < 0) {
printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n",
value, index, err);
@@ -213,7 +219,7 @@ static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
int err;
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
- MODE_CMD, 0x40, value, index, NULL, 0, 1000);
+ MODE_CMD, VENDOR, value, index, NULL, 0, 1000);
if (err < 0) {
printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n",
value, index, err);
@@ -228,7 +234,7 @@ static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
int err;
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
- COMM_CMD, 0x40, value, index, NULL, 0, 1000);
+ COMM_CMD, VENDOR, value, index, NULL, 0, 1000);
if (err < 0) {
printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n",
value, index, err);
@@ -246,7 +252,8 @@ static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
memset(st, 0, sizeof(*st));
count = 0;
- err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100);
+ err = usb_interrupt_msg(dev->udev, usb_rcvintpipe(dev->udev,
+ dev->ep[EP_STATUS]), buf, size, &count, 100);
if (err < 0) {
printk(KERN_ERR "Failed to read 1-wire data from 0x%x: err=%d.\n", dev->ep[EP_STATUS], err);
return err;
@@ -353,7 +360,7 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
buf, size, &count, 1000);
if (err < 0) {
- u8 buf[0x20];
+ u8 buf[ST_SIZE];
int count;
printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
@@ -398,7 +405,7 @@ int ds_stop_pulse(struct ds_device *dev, int limit)
{
struct ds_status st;
int count = 0, err = 0;
- u8 buf[0x20];
+ u8 buf[ST_SIZE];
do {
err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
@@ -450,10 +457,11 @@ int ds_detect(struct ds_device *dev, struct ds_status *st)
static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
{
- u8 buf[0x20];
+ u8 buf[ST_SIZE];
int err, count = 0;
do {
+ st->status = 0;
err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
#if 0
if (err >= 0) {
@@ -464,7 +472,7 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
printk("\n");
}
#endif
- } while (!(buf[0x08] & ST_IDLE) && !(err < 0) && ++count < 100);
+ } while (!(st->status & ST_IDLE) && !(err < 0) && ++count < 100);
if (err >= 16 && st->status & ST_EPOF) {
printk(KERN_INFO "Resetting device after ST_EPOF.\n");
@@ -690,37 +698,106 @@ static int ds_write_block(struct ds_device *dev, u8 *buf, int len)
return !(err == len);
}
-#if 0
-
-static int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search)
+static void ds9490r_search(void *data, struct w1_master *master,
+ u8 search_type, w1_slave_found_callback callback)
{
+ /* When starting with an existing id, the first id returned will
+ * be that device (if it is still on the bus most likely).
+ *
+ * If the number of devices found is less than or equal to the
+ * search_limit, that number of IDs will be returned. If there are
+ * more, search_limit IDs will be returned followed by a non-zero
+ * discrepency value.
+ */
+ struct ds_device *dev = data;
int err;
u16 value, index;
struct ds_status st;
+ u8 st_buf[ST_SIZE];
+ int search_limit;
+ int found = 0;
+ int i;
- memset(buf, 0, sizeof(buf));
+ /* DS18b20 spec, 13.16 ms per device, 75 per second, sleep for
+ * discovering 8 devices (1 bulk transfer and 1/2 FIFO size) at a time.
+ */
+ const unsigned long jtime = msecs_to_jiffies(1000*8/75);
+ /* FIFO 128 bytes, bulk packet size 64, read a multiple of the
+ * packet size.
+ */
+ u64 buf[2*64/8];
- err = ds_send_data(ds_dev, (unsigned char *)&init, 8);
- if (err)
- return err;
+ mutex_lock(&master->bus_mutex);
- ds_wait_status(ds_dev, &st);
+ /* address to start searching at */
+ if (ds_send_data(dev, (u8 *)&master->search_id, 8) < 0)
+ goto search_out;
+ master->search_id = 0;
- value = COMM_SEARCH_ACCESS | COMM_IM | COMM_SM | COMM_F | COMM_RTS;
- index = (conditional_search ? 0xEC : 0xF0) | (id_number << 8);
- err = ds_send_control(ds_dev, value, index);
- if (err)
- return err;
+ value = COMM_SEARCH_ACCESS | COMM_IM | COMM_RST | COMM_SM | COMM_F |
+ COMM_RTS;
+ search_limit = master->max_slave_count;
+ if (search_limit > 255)
+ search_limit = 0;
+ index = search_type | (search_limit << 8);
+ if (ds_send_control(dev, value, index) < 0)
+ goto search_out;
- ds_wait_status(ds_dev, &st);
+ do {
+ schedule_timeout(jtime);
- err = ds_recv_data(ds_dev, (unsigned char *)buf, 8*id_number);
- if (err < 0)
- return err;
+ if (ds_recv_status_nodump(dev, &st, st_buf, sizeof(st_buf)) <
+ sizeof(st)) {
+ break;
+ }
- return err/8;
+ if (st.data_in_buffer_status) {
+ /* Bulk in can receive partial ids, but when it does
+ * they fail crc and will be discarded anyway.
+ * That has only been seen when status in buffer
+ * is 0 and bulk is read anyway, so don't read
+ * bulk without first checking if status says there
+ * is data to read.
+ */
+ err = ds_recv_data(dev, (u8 *)buf, sizeof(buf));
+ if (err < 0)
+ break;
+ for (i = 0; i < err/8; ++i) {
+ ++found;
+ if (found <= search_limit)
+ callback(master, buf[i]);
+ /* can't know if there will be a discrepancy
+ * value after until the next id */
+ if (found == search_limit)
+ master->search_id = buf[i];
+ }
+ }
+
+ if (test_bit(W1_ABORT_SEARCH, &master->flags))
+ break;
+ } while (!(st.status & (ST_IDLE | ST_HALT)));
+
+ /* only continue the search if some weren't found */
+ if (found <= search_limit) {
+ master->search_id = 0;
+ } else if (!test_bit(W1_WARN_MAX_COUNT, &master->flags)) {
+ /* Only max_slave_count will be scanned in a search,
+ * but it will start where it left off next search
+ * until all ids are identified and then it will start
+ * over. A continued search will report the previous
+ * last id as the first id (provided it is still on the
+ * bus).
+ */
+ dev_info(&dev->udev->dev, "%s: max_slave_count %d reached, "
+ "will continue next search.\n", __func__,
+ master->max_slave_count);
+ set_bit(W1_WARN_MAX_COUNT, &master->flags);
+ }
+search_out:
+ mutex_unlock(&master->bus_mutex);
}
+#if 0
static int ds_match_access(struct ds_device *dev, u64 init)
{
int err;
@@ -894,6 +971,7 @@ static int ds_w1_init(struct ds_device *dev)
dev->master.write_block = &ds9490r_write_block;
dev->master.reset_bus = &ds9490r_reset;
dev->master.set_pullup = &ds9490r_set_pullup;
+ dev->master.search = &ds9490r_search;
return w1_add_master_device(&dev->master);
}
@@ -910,15 +988,13 @@ static int ds_probe(struct usb_interface *intf,
struct usb_endpoint_descriptor *endpoint;
struct usb_host_interface *iface_desc;
struct ds_device *dev;
- int i, err;
+ int i, err, alt;
- dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct ds_device), GFP_KERNEL);
if (!dev) {
printk(KERN_INFO "Failed to allocate new DS9490R structure.\n");
return -ENOMEM;
}
- dev->spu_sleep = 0;
- dev->spu_bit = 0;
dev->udev = usb_get_dev(udev);
if (!dev->udev) {
err = -ENOMEM;
@@ -928,20 +1004,25 @@ static int ds_probe(struct usb_interface *intf,
usb_set_intfdata(intf, dev);
- err = usb_set_interface(dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3);
+ err = usb_reset_configuration(dev->udev);
if (err) {
- printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n",
- intf->altsetting[0].desc.bInterfaceNumber, err);
+ dev_err(&dev->udev->dev,
+ "Failed to reset configuration: err=%d.\n", err);
goto err_out_clear;
}
- err = usb_reset_configuration(dev->udev);
+ /* alternative 3, 1ms interrupt (greatly speeds search), 64 byte bulk */
+ alt = 3;
+ err = usb_set_interface(dev->udev,
+ intf->altsetting[alt].desc.bInterfaceNumber, alt);
if (err) {
- printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err);
+ dev_err(&dev->udev->dev, "Failed to set alternative setting %d "
+ "for %d interface: err=%d.\n", alt,
+ intf->altsetting[alt].desc.bInterfaceNumber, err);
goto err_out_clear;
}
- iface_desc = &intf->altsetting[0];
+ iface_desc = &intf->altsetting[alt];
if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints);
err = -EINVAL;
diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c
index 1e5d94c5afc9..67b067a3e2ab 100644
--- a/drivers/w1/masters/mxc_w1.c
+++ b/drivers/w1/masters/mxc_w1.c
@@ -10,24 +10,16 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU 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.
- *
*/
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
#include <linux/clk.h>
-#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
#include "../w1.h"
#include "../w1_int.h"
-#include "../w1_log.h"
/* According to the mx27 Datasheet the reset procedure should take up to about
* 1350us. We set the timeout to 500*100us = 50ms for sure */
@@ -36,13 +28,13 @@
/*
* MXC W1 Register offsets
*/
-#define MXC_W1_CONTROL 0x00
-#define MXC_W1_TIME_DIVIDER 0x02
-#define MXC_W1_RESET 0x04
-#define MXC_W1_COMMAND 0x06
-#define MXC_W1_TXRX 0x08
-#define MXC_W1_INTERRUPT 0x0A
-#define MXC_W1_INTERRUPT_EN 0x0C
+#define MXC_W1_CONTROL 0x00
+# define MXC_W1_CONTROL_RDST BIT(3)
+# define MXC_W1_CONTROL_WR(x) BIT(5 - (x))
+# define MXC_W1_CONTROL_PST BIT(6)
+# define MXC_W1_CONTROL_RPP BIT(7)
+#define MXC_W1_TIME_DIVIDER 0x02
+#define MXC_W1_RESET 0x04
struct mxc_w1_device {
void __iomem *regs;
@@ -61,12 +53,12 @@ static u8 mxc_w1_ds2_reset_bus(void *data)
unsigned int timeout_cnt = 0;
struct mxc_w1_device *dev = data;
- __raw_writeb(0x80, (dev->regs + MXC_W1_CONTROL));
+ writeb(MXC_W1_CONTROL_RPP, (dev->regs + MXC_W1_CONTROL));
while (1) {
- reg_val = __raw_readb(dev->regs + MXC_W1_CONTROL);
+ reg_val = readb(dev->regs + MXC_W1_CONTROL);
- if (((reg_val >> 7) & 0x1) == 0 ||
+ if (!(reg_val & MXC_W1_CONTROL_RPP) ||
timeout_cnt > MXC_W1_RESET_TIMEOUT)
break;
else
@@ -74,7 +66,7 @@ static u8 mxc_w1_ds2_reset_bus(void *data)
udelay(100);
}
- return (reg_val >> 7) & 0x1;
+ return !!(reg_val & MXC_W1_CONTROL_PST);
}
/*
@@ -90,16 +82,16 @@ static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
* datasheet.
*/
- __raw_writeb((1 << (5 - bit)), ctrl_addr);
+ writeb(MXC_W1_CONTROL_WR(bit), ctrl_addr);
while (timeout_cnt--) {
- if (!((__raw_readb(ctrl_addr) >> (5 - bit)) & 0x1))
+ if (!(readb(ctrl_addr) & MXC_W1_CONTROL_WR(bit)))
break;
udelay(1);
}
- return ((__raw_readb(ctrl_addr)) >> 3) & 0x1;
+ return !!(readb(ctrl_addr) & MXC_W1_CONTROL_RDST);
}
static int mxc_w1_probe(struct platform_device *pdev)
@@ -139,7 +131,7 @@ static int mxc_w1_probe(struct platform_device *pdev)
if (err)
return err;
- __raw_writeb(clkdiv - 1, mdev->regs + MXC_W1_TIME_DIVIDER);
+ writeb(clkdiv - 1, mdev->regs + MXC_W1_TIME_DIVIDER);
mdev->bus_master.data = mdev;
mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus;
@@ -177,6 +169,7 @@ MODULE_DEVICE_TABLE(of, mxc_w1_dt_ids);
static struct platform_driver mxc_w1_driver = {
.driver = {
.name = "mxc_w1",
+ .owner = THIS_MODULE,
.of_match_table = mxc_w1_dt_ids,
},
.probe = mxc_w1_probe,
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index 9709b8b484ba..1d111e56c8c8 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -89,11 +89,22 @@ static int w1_gpio_probe_dt(struct platform_device *pdev)
pdata->is_open_drain = 1;
gpio = of_get_gpio(np, 0);
- if (gpio < 0)
+ if (gpio < 0) {
+ if (gpio != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "Failed to parse gpio property for data pin (%d)\n",
+ gpio);
+
return gpio;
+ }
pdata->pin = gpio;
- pdata->ext_pullup_enable_pin = of_get_gpio(np, 1);
+ gpio = of_get_gpio(np, 1);
+ if (gpio == -EPROBE_DEFER)
+ return gpio;
+ /* ignore other errors as the pullup gpio is optional */
+ pdata->ext_pullup_enable_pin = gpio;
+
pdev->dev.platform_data = pdata;
return 0;
@@ -107,10 +118,8 @@ static int w1_gpio_probe(struct platform_device *pdev)
if (of_have_populated_dt()) {
err = w1_gpio_probe_dt(pdev);
- if (err < 0) {
- dev_err(&pdev->dev, "Failed to parse DT\n");
+ if (err < 0)
return err;
- }
}
pdata = dev_get_platdata(&pdev->dev);
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index 5e6a3c9e510b..1cdce80b6abf 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -72,7 +72,6 @@ config W1_SLAVE_DS2433_CRC
config W1_SLAVE_DS2760
tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)"
- depends on W1
help
If you enable this you will have the DS2760 battery monitor
chip support.
@@ -85,7 +84,6 @@ config W1_SLAVE_DS2760
config W1_SLAVE_DS2780
tristate "Dallas 2780 battery monitor chip"
- depends on W1
help
If you enable this you will have the DS2780 battery monitor
chip support.
@@ -98,7 +96,6 @@ config W1_SLAVE_DS2780
config W1_SLAVE_DS2781
tristate "Dallas 2781 battery monitor chip"
- depends on W1
help
If you enable this you will have the DS2781 battery monitor
chip support.
@@ -111,7 +108,6 @@ config W1_SLAVE_DS2781
config W1_SLAVE_DS28E04
tristate "4096-Bit Addressable 1-Wire EEPROM with PIO (DS28E04-100)"
- depends on W1
select CRC16
help
If you enable this you will have the DS28E04-100
@@ -124,7 +120,6 @@ config W1_SLAVE_DS28E04
config W1_SLAVE_BQ27000
tristate "BQ27000 slave support"
- depends on W1
help
Say Y here if you want to use a hdq
bq27000 slave support.
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index 8b5ff33f72cf..1f11a20a8ab9 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -27,6 +27,7 @@
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/types.h>
+#include <linux/slab.h>
#include <linux/delay.h>
#include "../w1.h"
@@ -58,6 +59,19 @@ MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS28EA00));
static int w1_strong_pullup = 1;
module_param_named(strong_pullup, w1_strong_pullup, int, 0);
+static int w1_therm_add_slave(struct w1_slave *sl)
+{
+ sl->family_data = kzalloc(9, GFP_KERNEL);
+ if (!sl->family_data)
+ return -ENOMEM;
+ return 0;
+}
+
+static void w1_therm_remove_slave(struct w1_slave *sl)
+{
+ kfree(sl->family_data);
+ sl->family_data = NULL;
+}
static ssize_t w1_slave_show(struct device *device,
struct device_attribute *attr, char *buf);
@@ -71,6 +85,8 @@ static struct attribute *w1_therm_attrs[] = {
ATTRIBUTE_GROUPS(w1_therm);
static struct w1_family_ops w1_therm_fops = {
+ .add_slave = w1_therm_add_slave,
+ .remove_slave = w1_therm_remove_slave,
.groups = w1_therm_groups,
};
@@ -253,12 +269,13 @@ static ssize_t w1_slave_show(struct device *device,
c -= snprintf(buf + PAGE_SIZE - c, c, ": crc=%02x %s\n",
crc, (verdict) ? "YES" : "NO");
if (verdict)
- memcpy(sl->rom, rom, sizeof(sl->rom));
+ memcpy(sl->family_data, rom, sizeof(rom));
else
dev_warn(device, "Read failed CRC check\n");
for (i = 0; i < 9; ++i)
- c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", sl->rom[i]);
+ c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ",
+ ((u8 *)sl->family_data)[i]);
c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n",
w1_convert_temp(rom, sl->family->fid));
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 66efa96c4603..b96f61b15dc6 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -46,18 +46,29 @@ MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
static int w1_timeout = 10;
-int w1_max_slave_count = 10;
+int w1_max_slave_count = 64;
int w1_max_slave_ttl = 10;
module_param_named(timeout, w1_timeout, int, 0);
+MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches");
+/* A search stops when w1_max_slave_count devices have been found in that
+ * search. The next search will start over and detect the same set of devices
+ * on a static 1-wire bus. Memory is not allocated based on this number, just
+ * on the number of devices known to the kernel. Having a high number does not
+ * consume additional resources. As a special case, if there is only one
+ * device on the network and w1_max_slave_count is set to 1, the device id can
+ * be read directly skipping the normal slower search process.
+ */
module_param_named(max_slave_count, w1_max_slave_count, int, 0);
+MODULE_PARM_DESC(max_slave_count,
+ "maximum number of slaves detected in a search");
module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
+MODULE_PARM_DESC(slave_ttl,
+ "Number of searches not seeing a slave before it will be removed");
DEFINE_MUTEX(w1_mlock);
LIST_HEAD(w1_masters);
-static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn);
-
static int w1_master_match(struct device *dev, struct device_driver *drv)
{
return 1;
@@ -81,19 +92,10 @@ static void w1_slave_release(struct device *dev)
{
struct w1_slave *sl = dev_to_w1_slave(dev);
- dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name);
-
- while (atomic_read(&sl->refcnt)) {
- dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n",
- sl->name, atomic_read(&sl->refcnt));
- if (msleep_interruptible(1000))
- flush_signals(current);
- }
+ dev_dbg(dev, "%s: Releasing %s [%p]\n", __func__, sl->name, sl);
w1_family_put(sl->family);
sl->master->slave_count--;
-
- complete(&sl->released);
}
static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -243,7 +245,9 @@ static ssize_t w1_master_attribute_store_search(struct device * dev,
mutex_lock(&md->mutex);
md->search_count = tmp;
mutex_unlock(&md->mutex);
- wake_up_process(md->thread);
+ /* Only wake if it is going to be searching. */
+ if (tmp)
+ wake_up_process(md->thread);
return count;
}
@@ -277,7 +281,6 @@ static ssize_t w1_master_attribute_store_pullup(struct device *dev,
mutex_lock(&md->mutex);
md->enable_pullup = tmp;
mutex_unlock(&md->mutex);
- wake_up_process(md->thread);
return count;
}
@@ -314,6 +317,24 @@ static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct devic
return count;
}
+static ssize_t w1_master_attribute_store_max_slave_count(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int tmp;
+ struct w1_master *md = dev_to_w1_master(dev);
+
+ if (kstrtoint(buf, 0, &tmp) == -EINVAL || tmp < 1)
+ return -EINVAL;
+
+ mutex_lock(&md->mutex);
+ md->max_slave_count = tmp;
+ /* allow each time the max_slave_count is updated */
+ clear_bit(W1_WARN_MAX_COUNT, &md->flags);
+ mutex_unlock(&md->mutex);
+
+ return count;
+}
+
static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
{
struct w1_master *md = dev_to_w1_master(dev);
@@ -352,23 +373,20 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev,
{
struct w1_master *md = dev_to_w1_master(dev);
int c = PAGE_SIZE;
+ struct list_head *ent, *n;
+ struct w1_slave *sl = NULL;
- mutex_lock(&md->mutex);
-
- if (md->slave_count == 0)
- c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n");
- else {
- struct list_head *ent, *n;
- struct w1_slave *sl;
+ mutex_lock(&md->list_mutex);
- list_for_each_safe(ent, n, &md->slist) {
- sl = list_entry(ent, struct w1_slave, w1_slave_entry);
+ list_for_each_safe(ent, n, &md->slist) {
+ sl = list_entry(ent, struct w1_slave, w1_slave_entry);
- c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);
- }
+ c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);
}
+ if (!sl)
+ c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n");
- mutex_unlock(&md->mutex);
+ mutex_unlock(&md->list_mutex);
return PAGE_SIZE - c;
}
@@ -422,19 +440,22 @@ static int w1_atoreg_num(struct device *dev, const char *buf, size_t count,
}
/* Searches the slaves in the w1_master and returns a pointer or NULL.
- * Note: must hold the mutex
+ * Note: must not hold list_mutex
*/
-static struct w1_slave *w1_slave_search_device(struct w1_master *dev,
+struct w1_slave *w1_slave_search_device(struct w1_master *dev,
struct w1_reg_num *rn)
{
struct w1_slave *sl;
+ mutex_lock(&dev->list_mutex);
list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
if (sl->reg_num.family == rn->family &&
sl->reg_num.id == rn->id &&
sl->reg_num.crc == rn->crc) {
+ mutex_unlock(&dev->list_mutex);
return sl;
}
}
+ mutex_unlock(&dev->list_mutex);
return NULL;
}
@@ -491,7 +512,10 @@ static ssize_t w1_master_attribute_store_remove(struct device *dev,
mutex_lock(&md->mutex);
sl = w1_slave_search_device(md, &rn);
if (sl) {
- w1_slave_detach(sl);
+ result = w1_slave_detach(sl);
+ /* refcnt 0 means it was detached in the call */
+ if (result == 0)
+ result = count;
} else {
dev_info(dev, "Device %02x-%012llx doesn't exists\n", rn.family,
(unsigned long long)rn.id);
@@ -516,7 +540,7 @@ static ssize_t w1_master_attribute_store_remove(struct device *dev,
static W1_MASTER_ATTR_RO(name, S_IRUGO);
static W1_MASTER_ATTR_RO(slaves, S_IRUGO);
static W1_MASTER_ATTR_RO(slave_count, S_IRUGO);
-static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO);
+static W1_MASTER_ATTR_RW(max_slave_count, S_IRUGO | S_IWUSR | S_IWGRP);
static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
@@ -686,12 +710,14 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
dev_set_uevent_suppress(&sl->dev, false);
kobject_uevent(&sl->dev.kobj, KOBJ_ADD);
+ mutex_lock(&sl->master->list_mutex);
list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
+ mutex_unlock(&sl->master->list_mutex);
return 0;
}
-static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
+int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
{
struct w1_slave *sl;
struct w1_family *f;
@@ -713,8 +739,8 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
memset(&msg, 0, sizeof(msg));
memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
- atomic_set(&sl->refcnt, 0);
- init_completion(&sl->released);
+ atomic_set(&sl->refcnt, 1);
+ atomic_inc(&sl->master->refcnt);
/* slave modules need to be loaded in a context with unlocked mutex */
mutex_unlock(&dev->mutex);
@@ -754,23 +780,48 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
return 0;
}
-void w1_slave_detach(struct w1_slave *sl)
+int w1_unref_slave(struct w1_slave *sl)
{
- struct w1_netlink_msg msg;
-
- dev_dbg(&sl->dev, "%s: detaching %s [%p].\n", __func__, sl->name, sl);
-
- list_del(&sl->w1_slave_entry);
-
- memset(&msg, 0, sizeof(msg));
- memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id));
- msg.type = W1_SLAVE_REMOVE;
- w1_netlink_send(sl->master, &msg);
-
- device_unregister(&sl->dev);
+ struct w1_master *dev = sl->master;
+ int refcnt;
+ mutex_lock(&dev->list_mutex);
+ refcnt = atomic_sub_return(1, &sl->refcnt);
+ if (refcnt == 0) {
+ struct w1_netlink_msg msg;
+
+ dev_dbg(&sl->dev, "%s: detaching %s [%p].\n", __func__,
+ sl->name, sl);
+
+ list_del(&sl->w1_slave_entry);
+
+ memset(&msg, 0, sizeof(msg));
+ memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id));
+ msg.type = W1_SLAVE_REMOVE;
+ w1_netlink_send(sl->master, &msg);
+
+ device_unregister(&sl->dev);
+ #ifdef DEBUG
+ memset(sl, 0, sizeof(*sl));
+ #endif
+ kfree(sl);
+ }
+ atomic_dec(&dev->refcnt);
+ mutex_unlock(&dev->list_mutex);
+ return refcnt;
+}
- wait_for_completion(&sl->released);
- kfree(sl);
+int w1_slave_detach(struct w1_slave *sl)
+{
+ /* Only detach a slave once as it decreases the refcnt each time. */
+ int destroy_now;
+ mutex_lock(&sl->master->list_mutex);
+ destroy_now = !test_bit(W1_SLAVE_DETACH, &sl->flags);
+ set_bit(W1_SLAVE_DETACH, &sl->flags);
+ mutex_unlock(&sl->master->list_mutex);
+
+ if (destroy_now)
+ destroy_now = !w1_unref_slave(sl);
+ return destroy_now ? 0 : -EBUSY;
}
struct w1_master *w1_search_master_id(u32 id)
@@ -799,7 +850,7 @@ struct w1_slave *w1_search_slave(struct w1_reg_num *id)
mutex_lock(&w1_mlock);
list_for_each_entry(dev, &w1_masters, w1_master_entry) {
- mutex_lock(&dev->mutex);
+ mutex_lock(&dev->list_mutex);
list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
if (sl->reg_num.family == id->family &&
sl->reg_num.id == id->id &&
@@ -810,7 +861,7 @@ struct w1_slave *w1_search_slave(struct w1_reg_num *id)
break;
}
}
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->list_mutex);
if (found)
break;
@@ -830,6 +881,7 @@ void w1_reconnect_slaves(struct w1_family *f, int attach)
dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
"for family %02x.\n", dev->name, f->fid);
mutex_lock(&dev->mutex);
+ mutex_lock(&dev->list_mutex);
list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
/* If it is a new family, slaves with the default
* family driver and are that family will be
@@ -841,14 +893,19 @@ void w1_reconnect_slaves(struct w1_family *f, int attach)
(!attach && sl->family->fid == f->fid)) {
struct w1_reg_num rn;
+ mutex_unlock(&dev->list_mutex);
memcpy(&rn, &sl->reg_num, sizeof(rn));
- w1_slave_detach(sl);
-
- w1_attach_slave_device(dev, &rn);
+ /* If it was already in use let the automatic
+ * scan pick it up again later.
+ */
+ if (!w1_slave_detach(sl))
+ w1_attach_slave_device(dev, &rn);
+ mutex_lock(&dev->list_mutex);
}
}
dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
"has been finished.\n", dev->name);
+ mutex_unlock(&dev->list_mutex);
mutex_unlock(&dev->mutex);
}
mutex_unlock(&w1_mlock);
@@ -876,7 +933,12 @@ void w1_slave_found(struct w1_master *dev, u64 rn)
}
/**
- * Performs a ROM Search & registers any devices found.
+ * w1_search() - Performs a ROM Search & registers any devices found.
+ * @dev: The master device to search
+ * @search_type: W1_SEARCH to search all devices, or W1_ALARM_SEARCH
+ * to return only devices in the alarmed state
+ * @cb: Function to call when a device is found
+ *
* The 1-wire search is a simple binary tree search.
* For each bit of the address, we read two bits and write one bit.
* The bit written will put to sleep all devies that don't match that bit.
@@ -886,8 +948,6 @@ void w1_slave_found(struct w1_master *dev, u64 rn)
*
* See "Application note 187 1-wire search algorithm" at www.maxim-ic.com
*
- * @dev The master device to search
- * @cb Function to call when a device is found
*/
void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb)
{
@@ -898,7 +958,8 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
u8 triplet_ret = 0;
search_bit = 0;
- rn = last_rn = 0;
+ rn = dev->search_id;
+ last_rn = 0;
last_device = 0;
last_zero = -1;
@@ -945,7 +1006,7 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
else
search_bit = ((last_rn >> i) & 0x1);
- /** Read two bits and write one bit */
+ /* Read two bits and write one bit */
triplet_ret = w1_triplet(dev, search_bit);
/* quit if no device responded */
@@ -960,8 +1021,7 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
tmp64 = (triplet_ret >> 2);
rn |= (tmp64 << i);
- /* ensure we're called from kthread and not by netlink callback */
- if (!dev->priv && kthread_should_stop()) {
+ if (test_bit(W1_ABORT_SEARCH, &dev->flags)) {
mutex_unlock(&dev->bus_mutex);
dev_dbg(&dev->dev, "Abort w1_search\n");
return;
@@ -970,11 +1030,30 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
mutex_unlock(&dev->bus_mutex);
if ( (triplet_ret & 0x03) != 0x03 ) {
- if ( (desc_bit == last_zero) || (last_zero < 0))
+ if ((desc_bit == last_zero) || (last_zero < 0)) {
last_device = 1;
+ dev->search_id = 0;
+ } else {
+ dev->search_id = rn;
+ }
desc_bit = last_zero;
cb(dev, rn);
}
+
+ if (!last_device && slave_count == dev->max_slave_count &&
+ !test_bit(W1_WARN_MAX_COUNT, &dev->flags)) {
+ /* Only max_slave_count will be scanned in a search,
+ * but it will start where it left off next search
+ * until all ids are identified and then it will start
+ * over. A continued search will report the previous
+ * last id as the first id (provided it is still on the
+ * bus).
+ */
+ dev_info(&dev->dev, "%s: max_slave_count %d reached, "
+ "will continue next search.\n", __func__,
+ dev->max_slave_count);
+ set_bit(W1_WARN_MAX_COUNT, &dev->flags);
+ }
}
}
@@ -983,17 +1062,24 @@ void w1_search_process_cb(struct w1_master *dev, u8 search_type,
{
struct w1_slave *sl, *sln;
+ mutex_lock(&dev->list_mutex);
list_for_each_entry(sl, &dev->slist, w1_slave_entry)
clear_bit(W1_SLAVE_ACTIVE, &sl->flags);
+ mutex_unlock(&dev->list_mutex);
w1_search_devices(dev, search_type, cb);
+ mutex_lock(&dev->list_mutex);
list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
- if (!test_bit(W1_SLAVE_ACTIVE, &sl->flags) && !--sl->ttl)
+ if (!test_bit(W1_SLAVE_ACTIVE, &sl->flags) && !--sl->ttl) {
+ mutex_unlock(&dev->list_mutex);
w1_slave_detach(sl);
+ mutex_lock(&dev->list_mutex);
+ }
else if (test_bit(W1_SLAVE_ACTIVE, &sl->flags))
sl->ttl = dev->slave_ttl;
}
+ mutex_unlock(&dev->list_mutex);
if (dev->search_count > 0)
dev->search_count--;
@@ -1004,6 +1090,32 @@ static void w1_search_process(struct w1_master *dev, u8 search_type)
w1_search_process_cb(dev, search_type, w1_slave_found);
}
+/**
+ * w1_process_callbacks() - execute each dev->async_list callback entry
+ * @dev: w1_master device
+ *
+ * Return: 1 if there were commands to executed 0 otherwise
+ */
+int w1_process_callbacks(struct w1_master *dev)
+{
+ int ret = 0;
+ struct w1_async_cmd *async_cmd, *async_n;
+
+ /* The list can be added to in another thread, loop until it is empty */
+ while (!list_empty(&dev->async_list)) {
+ list_for_each_entry_safe(async_cmd, async_n, &dev->async_list,
+ async_entry) {
+ /* drop the lock, if it is a search it can take a long
+ * time */
+ mutex_unlock(&dev->list_mutex);
+ async_cmd->cb(dev, async_cmd);
+ ret = 1;
+ mutex_lock(&dev->list_mutex);
+ }
+ }
+ return ret;
+}
+
int w1_process(void *data)
{
struct w1_master *dev = (struct w1_master *) data;
@@ -1011,23 +1123,46 @@ int w1_process(void *data)
* time can be calculated in jiffies once.
*/
const unsigned long jtime = msecs_to_jiffies(w1_timeout * 1000);
+ /* remainder if it woke up early */
+ unsigned long jremain = 0;
- while (!kthread_should_stop()) {
- if (dev->search_count) {
+ for (;;) {
+
+ if (!jremain && dev->search_count) {
mutex_lock(&dev->mutex);
w1_search_process(dev, W1_SEARCH);
mutex_unlock(&dev->mutex);
}
+ mutex_lock(&dev->list_mutex);
+ /* Note, w1_process_callback drops the lock while processing,
+ * but locks it again before returning.
+ */
+ if (!w1_process_callbacks(dev) && jremain) {
+ /* a wake up is either to stop the thread, process
+ * callbacks, or search, it isn't process callbacks, so
+ * schedule a search.
+ */
+ jremain = 1;
+ }
+
try_to_freeze();
__set_current_state(TASK_INTERRUPTIBLE);
+ /* hold list_mutex until after interruptible to prevent loosing
+ * the wakeup signal when async_cmd is added.
+ */
+ mutex_unlock(&dev->list_mutex);
+
if (kthread_should_stop())
break;
/* Only sleep when the search is active. */
- if (dev->search_count)
- schedule_timeout(jtime);
+ if (dev->search_count) {
+ if (!jremain)
+ jremain = jtime;
+ jremain = schedule_timeout(jremain);
+ }
else
schedule();
}
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h
index ca8081a101d6..734dab7fc687 100644
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -22,6 +22,13 @@
#ifndef __W1_H
#define __W1_H
+/**
+ * struct w1_reg_num - broken out slave device id
+ *
+ * @family: identifies the type of device
+ * @id: along with family is the unique device id
+ * @crc: checksum of the other bytes
+ */
struct w1_reg_num
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
@@ -58,7 +65,24 @@ struct w1_reg_num
#define W1_RESUME_CMD 0xA5
#define W1_SLAVE_ACTIVE 0
+#define W1_SLAVE_DETACH 1
+/**
+ * struct w1_slave - holds a single slave device on the bus
+ *
+ * @owner: Points to the one wire "wire" kernel module.
+ * @name: Device id is ascii.
+ * @w1_slave_entry: data for the linked list
+ * @reg_num: the slave id in binary
+ * @refcnt: reference count, delete when 0
+ * @flags: bit flags for W1_SLAVE_ACTIVE W1_SLAVE_DETACH
+ * @ttl: decrement per search this slave isn't found, deatch at 0
+ * @master: bus which this slave is on
+ * @family: module for device family type
+ * @family_data: pointer for use by the family module
+ * @dev: kernel device identifier
+ *
+ */
struct w1_slave
{
struct module *owner;
@@ -66,7 +90,6 @@ struct w1_slave
struct list_head w1_slave_entry;
struct w1_reg_num reg_num;
atomic_t refcnt;
- u8 rom[9];
int ttl;
unsigned long flags;
@@ -74,99 +97,146 @@ struct w1_slave
struct w1_family *family;
void *family_data;
struct device dev;
- struct completion released;
};
typedef void (*w1_slave_found_callback)(struct w1_master *, u64);
/**
+ * struct w1_bus_master - operations available on a bus master
+ *
+ * @data: the first parameter in all the functions below
+ *
+ * @read_bit: Sample the line level @return the level read (0 or 1)
+ *
+ * @write_bit: Sets the line level
+ *
+ * @touch_bit: the lowest-level function for devices that really support the
+ * 1-wire protocol.
+ * touch_bit(0) = write-0 cycle
+ * touch_bit(1) = write-1 / read cycle
+ * @return the bit read (0 or 1)
+ *
+ * @read_byte: Reads a bytes. Same as 8 touch_bit(1) calls.
+ * @return the byte read
+ *
+ * @write_byte: Writes a byte. Same as 8 touch_bit(x) calls.
+ *
+ * @read_block: Same as a series of read_byte() calls
+ * @return the number of bytes read
+ *
+ * @write_block: Same as a series of write_byte() calls
+ *
+ * @triplet: Combines two reads and a smart write for ROM searches
+ * @return bit0=Id bit1=comp_id bit2=dir_taken
+ *
+ * @reset_bus: long write-0 with a read for the presence pulse detection
+ * @return -1=Error, 0=Device present, 1=No device present
+ *
+ * @set_pullup: Put out a strong pull-up pulse of the specified duration.
+ * @return -1=Error, 0=completed
+ *
+ * @search: Really nice hardware can handles the different types of ROM search
+ * w1_master* is passed to the slave found callback.
+ * u8 is search_type, W1_SEARCH or W1_ALARM_SEARCH
+ *
* Note: read_bit and write_bit are very low level functions and should only
* be used with hardware that doesn't really support 1-wire operations,
* like a parallel/serial port.
* Either define read_bit and write_bit OR define, at minimum, touch_bit and
* reset_bus.
+ *
*/
struct w1_bus_master
{
- /** the first parameter in all the functions below */
void *data;
- /**
- * Sample the line level
- * @return the level read (0 or 1)
- */
u8 (*read_bit)(void *);
- /** Sets the line level */
void (*write_bit)(void *, u8);
- /**
- * touch_bit is the lowest-level function for devices that really
- * support the 1-wire protocol.
- * touch_bit(0) = write-0 cycle
- * touch_bit(1) = write-1 / read cycle
- * @return the bit read (0 or 1)
- */
u8 (*touch_bit)(void *, u8);
- /**
- * Reads a bytes. Same as 8 touch_bit(1) calls.
- * @return the byte read
- */
u8 (*read_byte)(void *);
- /**
- * Writes a byte. Same as 8 touch_bit(x) calls.
- */
void (*write_byte)(void *, u8);
- /**
- * Same as a series of read_byte() calls
- * @return the number of bytes read
- */
u8 (*read_block)(void *, u8 *, int);
- /** Same as a series of write_byte() calls */
void (*write_block)(void *, const u8 *, int);
- /**
- * Combines two reads and a smart write for ROM searches
- * @return bit0=Id bit1=comp_id bit2=dir_taken
- */
u8 (*triplet)(void *, u8);
- /**
- * long write-0 with a read for the presence pulse detection
- * @return -1=Error, 0=Device present, 1=No device present
- */
u8 (*reset_bus)(void *);
- /**
- * Put out a strong pull-up pulse of the specified duration.
- * @return -1=Error, 0=completed
- */
u8 (*set_pullup)(void *, int);
- /** Really nice hardware can handles the different types of ROM search
- * w1_master* is passed to the slave found callback.
- */
void (*search)(void *, struct w1_master *,
u8, w1_slave_found_callback);
};
+/**
+ * enum w1_master_flags - bitfields used in w1_master.flags
+ * @W1_ABORT_SEARCH: abort searching early on shutdown
+ * @W1_WARN_MAX_COUNT: limit warning when the maximum count is reached
+ */
+enum w1_master_flags {
+ W1_ABORT_SEARCH = 0,
+ W1_WARN_MAX_COUNT = 1,
+};
+
+/**
+ * struct w1_master - one per bus master
+ * @w1_master_entry: master linked list
+ * @owner: module owner
+ * @name: dynamically allocate bus name
+ * @list_mutex: protect slist and async_list
+ * @slist: linked list of slaves
+ * @async_list: linked list of netlink commands to execute
+ * @max_slave_count: maximum number of slaves to search for at a time
+ * @slave_count: current number of slaves known
+ * @attempts: number of searches ran
+ * @slave_ttl: number of searches before a slave is timed out
+ * @initialized: prevent init/removal race conditions
+ * @id: w1 bus number
+ * @search_count: number of automatic searches to run, -1 unlimited
+ * @search_id: allows continuing a search
+ * @refcnt: reference count
+ * @priv: private data storage
+ * @priv_size: size allocated
+ * @enable_pullup: allows a strong pullup
+ * @pullup_duration: time for the next strong pullup
+ * @flags: one of w1_master_flags
+ * @thread: thread for bus search and netlink commands
+ * @mutex: protect most of w1_master
+ * @bus_mutex: pretect concurrent bus access
+ * @driver: sysfs driver
+ * @dev: sysfs device
+ * @bus_master: io operations available
+ * @seq: sequence number used for netlink broadcasts
+ * @portid: destination for the current netlink command
+ */
struct w1_master
{
struct list_head w1_master_entry;
struct module *owner;
unsigned char name[W1_MAXNAMELEN];
+ /* list_mutex protects just slist and async_list so slaves can be
+ * searched for and async commands added while the master has
+ * w1_master.mutex locked and is operating on the bus.
+ * lock order w1_mlock, w1_master.mutex, w1_master.list_mutex
+ */
+ struct mutex list_mutex;
struct list_head slist;
+ struct list_head async_list;
int max_slave_count, slave_count;
unsigned long attempts;
int slave_ttl;
int initialized;
u32 id;
int search_count;
+ /* id to start searching on, to continue a search or 0 to restart */
+ u64 search_id;
atomic_t refcnt;
@@ -178,6 +248,8 @@ struct w1_master
/** 5V strong pullup duration in milliseconds, zero disabled. */
int pullup_duration;
+ long flags;
+
struct task_struct *thread;
struct mutex mutex;
struct mutex bus_mutex;
@@ -188,16 +260,41 @@ struct w1_master
struct w1_bus_master *bus_master;
u32 seq;
+ /* port id to send netlink responses to. The value is temporarily
+ * stored here while processing a message, set after locking the
+ * mutex, zero before unlocking the mutex.
+ */
+ u32 portid;
+};
+
+/**
+ * struct w1_async_cmd - execute callback from the w1_process kthread
+ * @async_entry: link entry
+ * @cb: callback function, must list_del and destroy this list before
+ * returning
+ *
+ * When inserted into the w1_master async_list, w1_process will execute
+ * the callback. Embed this into the structure with the command details.
+ */
+struct w1_async_cmd {
+ struct list_head async_entry;
+ void (*cb)(struct w1_master *dev, struct w1_async_cmd *async_cmd);
};
int w1_create_master_attributes(struct w1_master *);
void w1_destroy_master_attributes(struct w1_master *master);
void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb);
void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb);
+/* call w1_unref_slave to release the reference counts w1_search_slave added */
struct w1_slave *w1_search_slave(struct w1_reg_num *id);
+/* decrements the reference on sl->master and sl, and cleans up if zero
+ * returns the reference count after it has been decremented */
+int w1_unref_slave(struct w1_slave *sl);
void w1_slave_found(struct w1_master *dev, u64 rn);
void w1_search_process_cb(struct w1_master *dev, u8 search_type,
w1_slave_found_callback cb);
+struct w1_slave *w1_slave_search_device(struct w1_master *dev,
+ struct w1_reg_num *rn);
struct w1_master *w1_search_master_id(u32 id);
/* Disconnect and reconnect devices in the given family. Used for finding
@@ -206,7 +303,9 @@ struct w1_master *w1_search_master_id(u32 id);
* has just been registered, to 0 when it has been unregistered.
*/
void w1_reconnect_slaves(struct w1_family *f, int attach);
-void w1_slave_detach(struct w1_slave *sl);
+int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn);
+/* 0 success, otherwise EBUSY */
+int w1_slave_detach(struct w1_slave *sl);
u8 w1_triplet(struct w1_master *dev, int bdir);
void w1_write_8(struct w1_master *, u8);
@@ -242,6 +341,7 @@ extern int w1_max_slave_ttl;
extern struct list_head w1_masters;
extern struct mutex w1_mlock;
+extern int w1_process_callbacks(struct w1_master *dev);
extern int w1_process(void *);
#endif /* __KERNEL__ */
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c
index e9309778ee72..3bff6b37b472 100644
--- a/drivers/w1/w1_family.c
+++ b/drivers/w1/w1_family.c
@@ -31,6 +31,10 @@
DEFINE_SPINLOCK(w1_flock);
static LIST_HEAD(w1_families);
+/**
+ * w1_register_family() - register a device family driver
+ * @newf: family to register
+ */
int w1_register_family(struct w1_family *newf)
{
struct list_head *ent, *n;
@@ -59,6 +63,10 @@ int w1_register_family(struct w1_family *newf)
return ret;
}
+/**
+ * w1_unregister_family() - unregister a device family driver
+ * @fent: family to unregister
+ */
void w1_unregister_family(struct w1_family *fent)
{
struct list_head *ent, *n;
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 4ad0e81b6404..26ca1343055b 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -48,6 +48,12 @@
struct w1_slave;
+/**
+ * struct w1_family_ops - operations for a family type
+ * @add_slave: add_slave
+ * @remove_slave: remove_slave
+ * @groups: sysfs group
+ */
struct w1_family_ops
{
int (* add_slave)(struct w1_slave *);
@@ -55,6 +61,13 @@ struct w1_family_ops
const struct attribute_group **groups;
};
+/**
+ * struct w1_family - reference counted family structure.
+ * @family_entry: family linked list
+ * @fid: 8 bit family identifier
+ * @fops: operations for this family
+ * @refcnt: reference counter
+ */
struct w1_family
{
struct list_head family_entry;
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 590bd8a7cd1b..9b084db739c7 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -75,8 +75,10 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
atomic_set(&dev->refcnt, 2);
INIT_LIST_HEAD(&dev->slist);
+ INIT_LIST_HEAD(&dev->async_list);
mutex_init(&dev->mutex);
mutex_init(&dev->bus_mutex);
+ mutex_init(&dev->list_mutex);
memcpy(&dev->dev, device, sizeof(struct device));
dev_set_name(&dev->dev, "w1_bus_master%u", dev->id);
@@ -103,6 +105,10 @@ static void w1_free_dev(struct w1_master *dev)
device_unregister(&dev->dev);
}
+/**
+ * w1_add_master_device() - registers a new master device
+ * @master: master bus device to register
+ */
int w1_add_master_device(struct w1_bus_master *master)
{
struct w1_master *dev, *entry;
@@ -172,6 +178,7 @@ int w1_add_master_device(struct w1_bus_master *master)
#if 0 /* Thread cleanup code, not required currently. */
err_out_kill_thread:
+ set_bit(W1_ABORT_SEARCH, &dev->flags);
kthread_stop(dev->thread);
#endif
err_out_rm_attr:
@@ -187,16 +194,22 @@ void __w1_remove_master_device(struct w1_master *dev)
struct w1_netlink_msg msg;
struct w1_slave *sl, *sln;
- kthread_stop(dev->thread);
-
mutex_lock(&w1_mlock);
list_del(&dev->w1_master_entry);
mutex_unlock(&w1_mlock);
+ set_bit(W1_ABORT_SEARCH, &dev->flags);
+ kthread_stop(dev->thread);
+
mutex_lock(&dev->mutex);
- list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry)
+ mutex_lock(&dev->list_mutex);
+ list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
+ mutex_unlock(&dev->list_mutex);
w1_slave_detach(sl);
+ mutex_lock(&dev->list_mutex);
+ }
w1_destroy_master_attributes(dev);
+ mutex_unlock(&dev->list_mutex);
mutex_unlock(&dev->mutex);
atomic_dec(&dev->refcnt);
@@ -206,7 +219,9 @@ void __w1_remove_master_device(struct w1_master *dev)
if (msleep_interruptible(1000))
flush_signals(current);
+ w1_process_callbacks(dev);
}
+ w1_process_callbacks(dev);
memset(&msg, 0, sizeof(msg));
msg.id.mst.id = dev->id;
@@ -216,6 +231,10 @@ void __w1_remove_master_device(struct w1_master *dev)
w1_free_dev(dev);
}
+/**
+ * w1_remove_master_device() - unregister a master device
+ * @bm: master bus device to remove
+ */
void w1_remove_master_device(struct w1_bus_master *bm)
{
struct w1_master *dev, *found = NULL;
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
index e10acc237733..282092421cc9 100644
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -62,7 +62,9 @@ static void w1_write_bit(struct w1_master *dev, int bit);
static u8 w1_read_bit(struct w1_master *dev);
/**
- * Generates a write-0 or write-1 cycle and samples the level.
+ * w1_touch_bit() - Generates a write-0 or write-1 cycle and samples the level.
+ * @dev: the master device
+ * @bit: 0 - write a 0, 1 - write a 0 read the level
*/
static u8 w1_touch_bit(struct w1_master *dev, int bit)
{
@@ -77,7 +79,10 @@ static u8 w1_touch_bit(struct w1_master *dev, int bit)
}
/**
- * Generates a write-0 or write-1 cycle.
+ * w1_write_bit() - Generates a write-0 or write-1 cycle.
+ * @dev: the master device
+ * @bit: bit to write
+ *
* Only call if dev->bus_master->touch_bit is NULL
*/
static void w1_write_bit(struct w1_master *dev, int bit)
@@ -102,11 +107,12 @@ static void w1_write_bit(struct w1_master *dev, int bit)
}
/**
+ * w1_pre_write() - pre-write operations
+ * @dev: the master device
+ *
* Pre-write operation, currently only supporting strong pullups.
* Program the hardware for a strong pullup, if one has been requested and
* the hardware supports it.
- *
- * @param dev the master device
*/
static void w1_pre_write(struct w1_master *dev)
{
@@ -118,11 +124,12 @@ static void w1_pre_write(struct w1_master *dev)
}
/**
+ * w1_post_write() - post-write options
+ * @dev: the master device
+ *
* Post-write operation, currently only supporting strong pullups.
* If a strong pullup was requested, clear it if the hardware supports
* them, or execute the delay otherwise, in either case clear the request.
- *
- * @param dev the master device
*/
static void w1_post_write(struct w1_master *dev)
{
@@ -136,10 +143,9 @@ static void w1_post_write(struct w1_master *dev)
}
/**
- * Writes 8 bits.
- *
- * @param dev the master device
- * @param byte the byte to write
+ * w1_write_8() - Writes 8 bits.
+ * @dev: the master device
+ * @byte: the byte to write
*/
void w1_write_8(struct w1_master *dev, u8 byte)
{
@@ -161,7 +167,9 @@ EXPORT_SYMBOL_GPL(w1_write_8);
/**
- * Generates a write-1 cycle and samples the level.
+ * w1_read_bit() - Generates a write-1 cycle and samples the level.
+ * @dev: the master device
+ *
* Only call if dev->bus_master->touch_bit is NULL
*/
static u8 w1_read_bit(struct w1_master *dev)
@@ -185,16 +193,17 @@ static u8 w1_read_bit(struct w1_master *dev)
}
/**
- * Does a triplet - used for searching ROM addresses.
+ * w1_triplet() - * Does a triplet - used for searching ROM addresses.
+ * @dev: the master device
+ * @bdir: the bit to write if both id_bit and comp_bit are 0
+ *
* Return bits:
* bit 0 = id_bit
* bit 1 = comp_bit
* bit 2 = dir_taken
* If both bits 0 & 1 are set, the search should be restarted.
*
- * @param dev the master device
- * @param bdir the bit to write if both id_bit and comp_bit are 0
- * @return bit fields - see above
+ * Return: bit fields - see above
*/
u8 w1_triplet(struct w1_master *dev, int bdir)
{
@@ -226,10 +235,10 @@ u8 w1_triplet(struct w1_master *dev, int bdir)
}
/**
- * Reads 8 bits.
+ * w1_read_8() - Reads 8 bits.
+ * @dev: the master device
*
- * @param dev the master device
- * @return the byte read
+ * Return: the byte read
*/
u8 w1_read_8(struct w1_master *dev)
{
@@ -247,11 +256,10 @@ u8 w1_read_8(struct w1_master *dev)
EXPORT_SYMBOL_GPL(w1_read_8);
/**
- * Writes a series of bytes.
- *
- * @param dev the master device
- * @param buf pointer to the data to write
- * @param len the number of bytes to write
+ * w1_write_block() - Writes a series of bytes.
+ * @dev: the master device
+ * @buf: pointer to the data to write
+ * @len: the number of bytes to write
*/
void w1_write_block(struct w1_master *dev, const u8 *buf, int len)
{
@@ -269,11 +277,10 @@ void w1_write_block(struct w1_master *dev, const u8 *buf, int len)
EXPORT_SYMBOL_GPL(w1_write_block);
/**
- * Touches a series of bytes.
- *
- * @param dev the master device
- * @param buf pointer to the data to write
- * @param len the number of bytes to write
+ * w1_touch_block() - Touches a series of bytes.
+ * @dev: the master device
+ * @buf: pointer to the data to write
+ * @len: the number of bytes to write
*/
void w1_touch_block(struct w1_master *dev, u8 *buf, int len)
{
@@ -294,12 +301,11 @@ void w1_touch_block(struct w1_master *dev, u8 *buf, int len)
EXPORT_SYMBOL_GPL(w1_touch_block);
/**
- * Reads a series of bytes.
- *
- * @param dev the master device
- * @param buf pointer to the buffer to fill
- * @param len the number of bytes to read
- * @return the number of bytes read
+ * w1_read_block() - Reads a series of bytes.
+ * @dev: the master device
+ * @buf: pointer to the buffer to fill
+ * @len: the number of bytes to read
+ * Return: the number of bytes read
*/
u8 w1_read_block(struct w1_master *dev, u8 *buf, int len)
{
@@ -319,10 +325,9 @@ u8 w1_read_block(struct w1_master *dev, u8 *buf, int len)
EXPORT_SYMBOL_GPL(w1_read_block);
/**
- * Issues a reset bus sequence.
- *
- * @param dev The bus master pointer
- * @return 0=Device present, 1=No device present or error
+ * w1_reset_bus() - Issues a reset bus sequence.
+ * @dev: the master device
+ * Return: 0=Device present, 1=No device present or error
*/
int w1_reset_bus(struct w1_master *dev)
{
@@ -383,12 +388,15 @@ void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_cal
}
/**
+ * w1_reset_select_slave() - reset and select a slave
+ * @sl: the slave to select
+ *
* Resets the bus and then selects the slave by sending either a skip rom
- * or a rom match.
+ * or a rom match. A skip rom is issued if there is only one device
+ * registered on the bus.
* The w1 master lock must be held.
*
- * @param sl the slave to select
- * @return 0=success, anything else=error
+ * Return: 0=success, anything else=error
*/
int w1_reset_select_slave(struct w1_slave *sl)
{
@@ -409,6 +417,9 @@ int w1_reset_select_slave(struct w1_slave *sl)
EXPORT_SYMBOL_GPL(w1_reset_select_slave);
/**
+ * w1_reset_resume_command() - resume instead of another match ROM
+ * @dev: the master device
+ *
* When the workflow with a slave amongst many requires several
* successive commands a reset between each, this function is similar
* to doing a reset then a match ROM for the last matched ROM. The
@@ -420,8 +431,6 @@ EXPORT_SYMBOL_GPL(w1_reset_select_slave);
* doesn't work of course, but the resume command is the next best thing.
*
* The w1 master lock must be held.
- *
- * @param dev the master device
*/
int w1_reset_resume_command(struct w1_master *dev)
{
@@ -435,6 +444,10 @@ int w1_reset_resume_command(struct w1_master *dev)
EXPORT_SYMBOL_GPL(w1_reset_resume_command);
/**
+ * w1_next_pullup() - register for a strong pullup
+ * @dev: the master device
+ * @delay: time in milliseconds
+ *
* Put out a strong pull-up of the specified duration after the next write
* operation. Not all hardware supports strong pullups. Hardware that
* doesn't support strong pullups will sleep for the given time after the
@@ -442,8 +455,7 @@ EXPORT_SYMBOL_GPL(w1_reset_resume_command);
* the next write, specifying zero will clear a previous request.
* The w1 master lock must be held.
*
- * @param delay time in milliseconds
- * @return 0=success, anything else=error
+ * Return: 0=success, anything else=error
*/
void w1_next_pullup(struct w1_master *dev, int delay)
{
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
index 40788c925d1c..5234964fe001 100644
--- a/drivers/w1/w1_netlink.c
+++ b/drivers/w1/w1_netlink.c
@@ -45,7 +45,7 @@ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
memcpy(w, msg, sizeof(struct w1_netlink_msg));
- cn_netlink_send(m, 0, GFP_KERNEL);
+ cn_netlink_send(m, dev->portid, 0, GFP_KERNEL);
}
static void w1_send_slave(struct w1_master *dev, u64 rn)
@@ -54,53 +54,95 @@ static void w1_send_slave(struct w1_master *dev, u64 rn)
struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1);
struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1);
int avail;
-
- /* update kernel slave list */
- w1_slave_found(dev, rn);
+ u64 *data;
avail = dev->priv_size - cmd->len;
- if (avail > 8) {
- u64 *data = (void *)(cmd + 1) + cmd->len;
+ if (avail < 8) {
+ msg->ack++;
+ cn_netlink_send(msg, dev->portid, 0, GFP_KERNEL);
- *data = rn;
- cmd->len += 8;
- hdr->len += 8;
- msg->len += 8;
- return;
+ msg->len = sizeof(struct w1_netlink_msg) +
+ sizeof(struct w1_netlink_cmd);
+ hdr->len = sizeof(struct w1_netlink_cmd);
+ cmd->len = 0;
}
- msg->ack++;
- cn_netlink_send(msg, 0, GFP_KERNEL);
+ data = (void *)(cmd + 1) + cmd->len;
- msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd);
- hdr->len = sizeof(struct w1_netlink_cmd);
- cmd->len = 0;
+ *data = rn;
+ cmd->len += 8;
+ hdr->len += 8;
+ msg->len += 8;
}
-static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg,
- unsigned int avail)
+static void w1_found_send_slave(struct w1_master *dev, u64 rn)
{
- struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1);
- struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1);
- int search_type = (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH;
+ /* update kernel slave list */
+ w1_slave_found(dev, rn);
- dev->priv = msg;
- dev->priv_size = avail;
+ w1_send_slave(dev, rn);
+}
+
+/* Get the current slave list, or search (with or without alarm) */
+static int w1_get_slaves(struct w1_master *dev,
+ struct cn_msg *req_msg, struct w1_netlink_msg *req_hdr,
+ struct w1_netlink_cmd *req_cmd)
+{
+ struct cn_msg *msg;
+ struct w1_netlink_msg *hdr;
+ struct w1_netlink_cmd *cmd;
+ struct w1_slave *sl;
+
+ msg = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->id = req_msg->id;
+ msg->seq = req_msg->seq;
+ msg->ack = 0;
+ msg->len = sizeof(struct w1_netlink_msg) +
+ sizeof(struct w1_netlink_cmd);
+
+ hdr = (struct w1_netlink_msg *)(msg + 1);
+ cmd = (struct w1_netlink_cmd *)(hdr + 1);
+
+ hdr->type = W1_MASTER_CMD;
+ hdr->id = req_hdr->id;
+ hdr->len = sizeof(struct w1_netlink_cmd);
+
+ cmd->cmd = req_cmd->cmd;
+ cmd->len = 0;
- w1_search_process_cb(dev, search_type, w1_send_slave);
+ dev->priv = msg;
+ dev->priv_size = PAGE_SIZE - msg->len - sizeof(struct cn_msg);
+
+ if (req_cmd->cmd == W1_CMD_LIST_SLAVES) {
+ __u64 rn;
+ mutex_lock(&dev->list_mutex);
+ list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
+ memcpy(&rn, &sl->reg_num, sizeof(rn));
+ w1_send_slave(dev, rn);
+ }
+ mutex_unlock(&dev->list_mutex);
+ } else {
+ w1_search_process_cb(dev, cmd->cmd == W1_CMD_ALARM_SEARCH ?
+ W1_ALARM_SEARCH : W1_SEARCH, w1_found_send_slave);
+ }
msg->ack = 0;
- cn_netlink_send(msg, 0, GFP_KERNEL);
+ cn_netlink_send(msg, dev->portid, 0, GFP_KERNEL);
dev->priv = NULL;
dev->priv_size = 0;
+ kfree(msg);
+
return 0;
}
static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr,
- struct w1_netlink_cmd *cmd)
+ struct w1_netlink_cmd *cmd, u32 portid)
{
void *data;
struct w1_netlink_msg *h;
@@ -131,7 +173,7 @@ static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr,
memcpy(c->data, cmd->data, c->len);
- err = cn_netlink_send(cm, 0, GFP_KERNEL);
+ err = cn_netlink_send(cm, portid, 0, GFP_KERNEL);
kfree(data);
@@ -146,11 +188,11 @@ static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg,
switch (cmd->cmd) {
case W1_CMD_TOUCH:
w1_touch_block(dev, cmd->data, cmd->len);
- w1_send_read_reply(msg, hdr, cmd);
+ w1_send_read_reply(msg, hdr, cmd, dev->portid);
break;
case W1_CMD_READ:
w1_read_block(dev, cmd->data, cmd->len);
- w1_send_read_reply(msg, hdr, cmd);
+ w1_send_read_reply(msg, hdr, cmd, dev->portid);
break;
case W1_CMD_WRITE:
w1_write_block(dev, cmd->data, cmd->len);
@@ -163,38 +205,57 @@ static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg,
return err;
}
-static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_msg,
- struct w1_netlink_msg *req_hdr, struct w1_netlink_cmd *req_cmd)
+static int w1_process_command_addremove(struct w1_master *dev,
+ struct cn_msg *msg, struct w1_netlink_msg *hdr,
+ struct w1_netlink_cmd *cmd)
{
- int err = -EINVAL;
- struct cn_msg *msg;
- struct w1_netlink_msg *hdr;
- struct w1_netlink_cmd *cmd;
+ struct w1_slave *sl;
+ int err = 0;
+ struct w1_reg_num *id;
- msg = kzalloc(PAGE_SIZE, GFP_KERNEL);
- if (!msg)
- return -ENOMEM;
+ if (cmd->len != 8)
+ return -EINVAL;
- msg->id = req_msg->id;
- msg->seq = req_msg->seq;
- msg->ack = 0;
- msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd);
+ id = (struct w1_reg_num *)cmd->data;
- hdr = (struct w1_netlink_msg *)(msg + 1);
- cmd = (struct w1_netlink_cmd *)(hdr + 1);
+ sl = w1_slave_search_device(dev, id);
+ switch (cmd->cmd) {
+ case W1_CMD_SLAVE_ADD:
+ if (sl)
+ err = -EINVAL;
+ else
+ err = w1_attach_slave_device(dev, id);
+ break;
+ case W1_CMD_SLAVE_REMOVE:
+ if (sl)
+ w1_slave_detach(sl);
+ else
+ err = -EINVAL;
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
- hdr->type = W1_MASTER_CMD;
- hdr->id = req_hdr->id;
- hdr->len = sizeof(struct w1_netlink_cmd);
+ return err;
+}
- cmd->cmd = req_cmd->cmd;
- cmd->len = 0;
+static int w1_process_command_master(struct w1_master *dev,
+ struct cn_msg *req_msg, struct w1_netlink_msg *req_hdr,
+ struct w1_netlink_cmd *req_cmd)
+{
+ int err = -EINVAL;
- switch (cmd->cmd) {
+ /* drop bus_mutex for search (does it's own locking), and add/remove
+ * which doesn't use the bus
+ */
+ switch (req_cmd->cmd) {
case W1_CMD_SEARCH:
case W1_CMD_ALARM_SEARCH:
- err = w1_process_search_command(dev, msg,
- PAGE_SIZE - msg->len - sizeof(struct cn_msg));
+ case W1_CMD_LIST_SLAVES:
+ mutex_unlock(&dev->bus_mutex);
+ err = w1_get_slaves(dev, req_msg, req_hdr, req_cmd);
+ mutex_lock(&dev->bus_mutex);
break;
case W1_CMD_READ:
case W1_CMD_WRITE:
@@ -204,12 +265,20 @@ static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_m
case W1_CMD_RESET:
err = w1_reset_bus(dev);
break;
+ case W1_CMD_SLAVE_ADD:
+ case W1_CMD_SLAVE_REMOVE:
+ mutex_unlock(&dev->bus_mutex);
+ mutex_lock(&dev->mutex);
+ err = w1_process_command_addremove(dev, req_msg, req_hdr,
+ req_cmd);
+ mutex_unlock(&dev->mutex);
+ mutex_lock(&dev->bus_mutex);
+ break;
default:
err = -EINVAL;
break;
}
- kfree(msg);
return err;
}
@@ -223,7 +292,8 @@ static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg,
return w1_process_command_io(sl->master, msg, hdr, cmd);
}
-static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mcmd)
+static int w1_process_command_root(struct cn_msg *msg,
+ struct w1_netlink_msg *mcmd, u32 portid)
{
struct w1_master *m;
struct cn_msg *cn;
@@ -256,7 +326,7 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mc
mutex_lock(&w1_mlock);
list_for_each_entry(m, &w1_masters, w1_master_entry) {
if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) {
- cn_netlink_send(cn, 0, GFP_KERNEL);
+ cn_netlink_send(cn, portid, 0, GFP_KERNEL);
cn->ack++;
cn->len = sizeof(struct w1_netlink_msg);
w->len = 0;
@@ -269,7 +339,7 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mc
id++;
}
cn->ack = 0;
- cn_netlink_send(cn, 0, GFP_KERNEL);
+ cn_netlink_send(cn, portid, 0, GFP_KERNEL);
mutex_unlock(&w1_mlock);
kfree(cn);
@@ -277,7 +347,7 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mc
}
static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rmsg,
- struct w1_netlink_cmd *rcmd, int error)
+ struct w1_netlink_cmd *rcmd, int portid, int error)
{
struct cn_msg *cmsg;
struct w1_netlink_msg *msg;
@@ -304,35 +374,147 @@ static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rm
cmsg->len += sizeof(*cmd);
}
- error = cn_netlink_send(cmsg, 0, GFP_KERNEL);
+ error = cn_netlink_send(cmsg, portid, 0, GFP_KERNEL);
kfree(cmsg);
return error;
}
+/* Bundle together a reference count, the full message, and broken out
+ * commands to be executed on each w1 master kthread in one memory allocation.
+ */
+struct w1_cb_block {
+ atomic_t refcnt;
+ u32 portid; /* Sending process port ID */
+ struct cn_msg msg;
+ /* cn_msg data */
+ /* one or more variable length struct w1_cb_node */
+};
+struct w1_cb_node {
+ struct w1_async_cmd async;
+ /* pointers within w1_cb_block and msg data */
+ struct w1_cb_block *block;
+ struct w1_netlink_msg *m;
+ struct w1_slave *sl;
+ struct w1_master *dev;
+};
+
+static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd)
+{
+ struct w1_cb_node *node = container_of(async_cmd, struct w1_cb_node,
+ async);
+ u16 mlen = node->m->len;
+ u8 *cmd_data = node->m->data;
+ int err = 0;
+ struct w1_slave *sl = node->sl;
+ struct w1_netlink_cmd *cmd = NULL;
+
+ mutex_lock(&dev->bus_mutex);
+ dev->portid = node->block->portid;
+ if (sl && w1_reset_select_slave(sl))
+ err = -ENODEV;
+
+ while (mlen && !err) {
+ cmd = (struct w1_netlink_cmd *)cmd_data;
+
+ if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) {
+ err = -E2BIG;
+ break;
+ }
+
+ if (sl)
+ err = w1_process_command_slave(sl, &node->block->msg,
+ node->m, cmd);
+ else
+ err = w1_process_command_master(dev, &node->block->msg,
+ node->m, cmd);
+
+ w1_netlink_send_error(&node->block->msg, node->m, cmd,
+ node->block->portid, err);
+ err = 0;
+
+ cmd_data += cmd->len + sizeof(struct w1_netlink_cmd);
+ mlen -= cmd->len + sizeof(struct w1_netlink_cmd);
+ }
+
+ if (!cmd || err)
+ w1_netlink_send_error(&node->block->msg, node->m, cmd,
+ node->block->portid, err);
+
+ if (sl)
+ w1_unref_slave(sl);
+ else
+ atomic_dec(&dev->refcnt);
+ dev->portid = 0;
+ mutex_unlock(&dev->bus_mutex);
+
+ mutex_lock(&dev->list_mutex);
+ list_del(&async_cmd->async_entry);
+ mutex_unlock(&dev->list_mutex);
+
+ if (atomic_sub_return(1, &node->block->refcnt) == 0)
+ kfree(node->block);
+}
+
static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1);
- struct w1_netlink_cmd *cmd;
struct w1_slave *sl;
struct w1_master *dev;
+ u16 msg_len;
int err = 0;
+ struct w1_cb_block *block = NULL;
+ struct w1_cb_node *node = NULL;
+ int node_count = 0;
+
+ /* Count the number of master or slave commands there are to allocate
+ * space for one cb_node each.
+ */
+ msg_len = msg->len;
+ while (msg_len && !err) {
+ if (m->len + sizeof(struct w1_netlink_msg) > msg_len) {
+ err = -E2BIG;
+ break;
+ }
+
+ if (m->type == W1_MASTER_CMD || m->type == W1_SLAVE_CMD)
+ ++node_count;
- while (msg->len && !err) {
+ msg_len -= sizeof(struct w1_netlink_msg) + m->len;
+ m = (struct w1_netlink_msg *)(((u8 *)m) +
+ sizeof(struct w1_netlink_msg) + m->len);
+ }
+ m = (struct w1_netlink_msg *)(msg + 1);
+ if (node_count) {
+ /* msg->len doesn't include itself */
+ long size = sizeof(struct w1_cb_block) + msg->len +
+ node_count*sizeof(struct w1_cb_node);
+ block = kmalloc(size, GFP_KERNEL);
+ if (!block) {
+ w1_netlink_send_error(msg, m, NULL, nsp->portid,
+ -ENOMEM);
+ return;
+ }
+ atomic_set(&block->refcnt, 1);
+ block->portid = nsp->portid;
+ memcpy(&block->msg, msg, sizeof(*msg) + msg->len);
+ node = (struct w1_cb_node *)((u8 *)block->msg.data + msg->len);
+ }
+
+ msg_len = msg->len;
+ while (msg_len && !err) {
struct w1_reg_num id;
u16 mlen = m->len;
- u8 *cmd_data = m->data;
dev = NULL;
sl = NULL;
- cmd = NULL;
memcpy(&id, m->id.id, sizeof(id));
#if 0
printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n",
__func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len);
#endif
- if (m->len + sizeof(struct w1_netlink_msg) > msg->len) {
+ if (m->len + sizeof(struct w1_netlink_msg) > msg_len) {
err = -E2BIG;
break;
}
@@ -344,7 +526,7 @@ static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
if (sl)
dev = sl->master;
} else {
- err = w1_process_command_root(msg, m);
+ err = w1_process_command_root(msg, m, nsp->portid);
goto out_cont;
}
@@ -357,41 +539,24 @@ static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
if (!mlen)
goto out_cont;
- mutex_lock(&dev->mutex);
-
- if (sl && w1_reset_select_slave(sl)) {
- err = -ENODEV;
- goto out_up;
- }
+ atomic_inc(&block->refcnt);
+ node->async.cb = w1_process_cb;
+ node->block = block;
+ node->m = (struct w1_netlink_msg *)((u8 *)&block->msg +
+ (size_t)((u8 *)m - (u8 *)msg));
+ node->sl = sl;
+ node->dev = dev;
- while (mlen) {
- cmd = (struct w1_netlink_cmd *)cmd_data;
+ mutex_lock(&dev->list_mutex);
+ list_add_tail(&node->async.async_entry, &dev->async_list);
+ wake_up_process(dev->thread);
+ mutex_unlock(&dev->list_mutex);
+ ++node;
- if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) {
- err = -E2BIG;
- break;
- }
-
- if (sl)
- err = w1_process_command_slave(sl, msg, m, cmd);
- else
- err = w1_process_command_master(dev, msg, m, cmd);
-
- w1_netlink_send_error(msg, m, cmd, err);
- err = 0;
-
- cmd_data += cmd->len + sizeof(struct w1_netlink_cmd);
- mlen -= cmd->len + sizeof(struct w1_netlink_cmd);
- }
-out_up:
- atomic_dec(&dev->refcnt);
- if (sl)
- atomic_dec(&sl->refcnt);
- mutex_unlock(&dev->mutex);
out_cont:
- if (!cmd || err)
- w1_netlink_send_error(msg, m, cmd, err);
- msg->len -= sizeof(struct w1_netlink_msg) + m->len;
+ if (err)
+ w1_netlink_send_error(msg, m, NULL, nsp->portid, err);
+ msg_len -= sizeof(struct w1_netlink_msg) + m->len;
m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len);
/*
@@ -400,6 +565,8 @@ out_cont:
if (err == -ENODEV)
err = 0;
}
+ if (block && atomic_sub_return(1, &block->refcnt) == 0)
+ kfree(block);
}
int w1_init_netlink(void)
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h
index b0922dc29658..1e9504e67650 100644
--- a/drivers/w1/w1_netlink.h
+++ b/drivers/w1/w1_netlink.h
@@ -27,6 +27,18 @@
#include "w1.h"
+/**
+ * enum w1_netlink_message_types - message type
+ *
+ * @W1_SLAVE_ADD: notification that a slave device was added
+ * @W1_SLAVE_REMOVE: notification that a slave device was removed
+ * @W1_MASTER_ADD: notification that a new bus master was added
+ * @W1_MASTER_REMOVE: notification that a bus masterwas removed
+ * @W1_MASTER_CMD: initiate operations on a specific master
+ * @W1_SLAVE_CMD: sends reset, selects the slave, then does a read/write/touch
+ * operation
+ * @W1_LIST_MASTERS: used to determine the bus master identifiers
+ */
enum w1_netlink_message_types {
W1_SLAVE_ADD = 0,
W1_SLAVE_REMOVE,
@@ -52,6 +64,22 @@ struct w1_netlink_msg
__u8 data[0];
};
+/**
+ * enum w1_commands - commands available for master or slave operations
+ * @W1_CMD_READ: read len bytes
+ * @W1_CMD_WRITE: write len bytes
+ * @W1_CMD_SEARCH: initiate a standard search, returns only the slave
+ * devices found during that search
+ * @W1_CMD_ALARM_SEARCH: search for devices that are currently alarming
+ * @W1_CMD_TOUCH: Touches a series of bytes.
+ * @W1_CMD_RESET: sends a bus reset on the given master
+ * @W1_CMD_SLAVE_ADD: adds a slave to the given master,
+ * 8 byte slave id at data[0]
+ * @W1_CMD_SLAVE_REMOVE: removes a slave to the given master,
+ * 8 byte slave id at data[0]
+ * @W1_CMD_LIST_SLAVES: list of slaves registered on this master
+ * @W1_CMD_MAX: number of available commands
+ */
enum w1_commands {
W1_CMD_READ = 0,
W1_CMD_WRITE,
@@ -59,7 +87,10 @@ enum w1_commands {
W1_CMD_ALARM_SEARCH,
W1_CMD_TOUCH,
W1_CMD_RESET,
- W1_CMD_MAX,
+ W1_CMD_SLAVE_ADD,
+ W1_CMD_SLAVE_REMOVE,
+ W1_CMD_LIST_SLAVES,
+ W1_CMD_MAX
};
struct w1_netlink_cmd
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 79d25894343a..0c6048d5c9a3 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -111,6 +111,15 @@ config WM8350_WATCHDOG
Support for the watchdog in the WM8350 AudioPlus PMIC. When
the watchdog triggers the system will be reset.
+config XILINX_WATCHDOG
+ tristate "Xilinx Watchdog timer"
+ select WATCHDOG_CORE
+ help
+ Watchdog driver for the xps_timebase_wdt ip core.
+
+ To compile this driver as a module, choose M here: the
+ module will be called of_xilinx_wdt.
+
# ALPHA Architecture
# ARM Architecture
@@ -292,7 +301,7 @@ config DAVINCI_WATCHDOG
config ORION_WATCHDOG
tristate "Orion watchdog"
- depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE
+ depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE || MACH_DOVE
select WATCHDOG_CORE
help
Say Y here if to include support for the watchdog timer
@@ -421,6 +430,17 @@ config SIRFSOC_WATCHDOG
Support for CSR SiRFprimaII and SiRFatlasVI watchdog. When
the watchdog triggers the system will be reset.
+config TEGRA_WATCHDOG
+ tristate "Tegra watchdog"
+ depends on ARCH_TEGRA || COMPILE_TEST
+ select WATCHDOG_CORE
+ help
+ Say Y here to include support for the watchdog timer
+ embedded in NVIDIA Tegra SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tegra_wdt.
+
# AVR32 Architecture
config AT32AP700X_WDT
@@ -533,7 +553,7 @@ config GEODE_WDT
config SC520_WDT
tristate "AMD Elan SC520 processor Watchdog"
- depends on X86
+ depends on MELAN
help
This is the driver for the hardware watchdog built in to the
AMD "Elan" SC520 microcomputer commonly used in embedded systems.
@@ -1023,18 +1043,6 @@ config M54xx_WATCHDOG
# MicroBlaze Architecture
-config XILINX_WATCHDOG
- tristate "Xilinx Watchdog timer"
- depends on MICROBLAZE
- ---help---
- Watchdog driver for the xps_timebase_wdt ip core.
-
- IMPORTANT: The xps_timebase_wdt parent must have the property
- "clock-frequency" at device tree.
-
- To compile this driver as a module, choose M here: the
- module will be called of_xilinx_wdt.
-
# MIPS Architecture
config ATH79_WDT
@@ -1160,7 +1168,7 @@ config BCM2835_WDT
config BCM_KONA_WDT
tristate "BCM Kona Watchdog"
- depends on ARCH_BCM
+ depends on ARCH_BCM_MOBILE
select WATCHDOG_CORE
help
Support for the watchdog timer on the following Broadcom BCM281xx
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 985a66cda76f..1b5f3d5efad5 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
obj-$(CONFIG_MOXART_WDT) += moxart_wdt.o
obj-$(CONFIG_SIRFSOC_WATCHDOG) += sirfsoc_wdt.o
obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o
+obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
diff --git a/drivers/watchdog/acquirewdt.c b/drivers/watchdog/acquirewdt.c
index 5cf1621def9c..5614416f1032 100644
--- a/drivers/watchdog/acquirewdt.c
+++ b/drivers/watchdog/acquirewdt.c
@@ -239,7 +239,7 @@ static struct miscdevice acq_miscdev = {
* Init & exit routines
*/
-static int acq_probe(struct platform_device *dev)
+static int __init acq_probe(struct platform_device *dev)
{
int ret;
@@ -291,7 +291,6 @@ static void acq_shutdown(struct platform_device *dev)
}
static struct platform_driver acquirewdt_driver = {
- .probe = acq_probe,
.remove = acq_remove,
.shutdown = acq_shutdown,
.driver = {
@@ -306,20 +305,18 @@ static int __init acq_init(void)
pr_info("WDT driver for Acquire single board computer initialising\n");
- err = platform_driver_register(&acquirewdt_driver);
- if (err)
- return err;
-
acq_platform_device = platform_device_register_simple(DRV_NAME,
-1, NULL, 0);
- if (IS_ERR(acq_platform_device)) {
- err = PTR_ERR(acq_platform_device);
- goto unreg_platform_driver;
- }
+ if (IS_ERR(acq_platform_device))
+ return PTR_ERR(acq_platform_device);
+
+ err = platform_driver_probe(&acquirewdt_driver, acq_probe);
+ if (err)
+ goto unreg_platform_device;
return 0;
-unreg_platform_driver:
- platform_driver_unregister(&acquirewdt_driver);
+unreg_platform_device:
+ platform_device_unregister(acq_platform_device);
return err;
}
diff --git a/drivers/watchdog/advantechwdt.c b/drivers/watchdog/advantechwdt.c
index a8961addc59c..7796db7fa6e1 100644
--- a/drivers/watchdog/advantechwdt.c
+++ b/drivers/watchdog/advantechwdt.c
@@ -238,7 +238,7 @@ static struct miscdevice advwdt_miscdev = {
* Init & exit routines
*/
-static int advwdt_probe(struct platform_device *dev)
+static int __init advwdt_probe(struct platform_device *dev)
{
int ret;
@@ -299,7 +299,6 @@ static void advwdt_shutdown(struct platform_device *dev)
}
static struct platform_driver advwdt_driver = {
- .probe = advwdt_probe,
.remove = advwdt_remove,
.shutdown = advwdt_shutdown,
.driver = {
@@ -314,21 +313,19 @@ static int __init advwdt_init(void)
pr_info("WDT driver for Advantech single board computer initialising\n");
- err = platform_driver_register(&advwdt_driver);
- if (err)
- return err;
-
advwdt_platform_device = platform_device_register_simple(DRV_NAME,
-1, NULL, 0);
- if (IS_ERR(advwdt_platform_device)) {
- err = PTR_ERR(advwdt_platform_device);
- goto unreg_platform_driver;
- }
+ if (IS_ERR(advwdt_platform_device))
+ return PTR_ERR(advwdt_platform_device);
+
+ err = platform_driver_probe(&advwdt_driver, advwdt_probe);
+ if (err)
+ goto unreg_platform_device;
return 0;
-unreg_platform_driver:
- platform_driver_unregister(&advwdt_driver);
+unreg_platform_device:
+ platform_device_unregister(advwdt_platform_device);
return err;
}
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
index 3a996576343a..ae6c287a49cb 100644
--- a/drivers/watchdog/ar7_wdt.c
+++ b/drivers/watchdog/ar7_wdt.c
@@ -28,7 +28,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
diff --git a/drivers/watchdog/at32ap700x_wdt.c b/drivers/watchdog/at32ap700x_wdt.c
index afe7d17e6776..25b5c67d3af9 100644
--- a/drivers/watchdog/at32ap700x_wdt.c
+++ b/drivers/watchdog/at32ap700x_wdt.c
@@ -323,10 +323,8 @@ static int __init at32_wdt_probe(struct platform_device *pdev)
wdt = devm_kzalloc(&pdev->dev, sizeof(struct wdt_at32ap700x),
GFP_KERNEL);
- if (!wdt) {
- dev_dbg(&pdev->dev, "no memory for wdt structure\n");
+ if (!wdt)
return -ENOMEM;
- }
wdt->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
if (!wdt->regs) {
diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c
index 9fa1f69dac13..399c3fddecf6 100644
--- a/drivers/watchdog/ath79_wdt.c
+++ b/drivers/watchdog/ath79_wdt.c
@@ -22,7 +22,6 @@
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c
index cafa973c43be..8df450c090a9 100644
--- a/drivers/watchdog/bcm2835_wdt.c
+++ b/drivers/watchdog/bcm2835_wdt.c
@@ -114,10 +114,8 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
int err;
wdt = devm_kzalloc(dev, sizeof(struct bcm2835_wdt), GFP_KERNEL);
- if (!wdt) {
- dev_err(dev, "Failed to allocate memory for watchdog device");
+ if (!wdt)
return -ENOMEM;
- }
platform_set_drvdata(pdev, wdt);
spin_lock_init(&wdt->lock);
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index b4021a2b459b..b61fcc535979 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -16,7 +16,6 @@
#include <linux/bcm47xx_wdt.h>
#include <linux/bitops.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/drivers/watchdog/bcm63xx_wdt.c b/drivers/watchdog/bcm63xx_wdt.c
index 4eb188b87f8e..5a8e879a430a 100644
--- a/drivers/watchdog/bcm63xx_wdt.c
+++ b/drivers/watchdog/bcm63xx_wdt.c
@@ -15,7 +15,6 @@
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
@@ -45,7 +44,6 @@
static struct {
void __iomem *regs;
struct timer_list timer;
- int default_ticks;
unsigned long inuse;
atomic_t ticks;
} bcm63xx_wdt_device;
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index f1b8d555080e..a8dbceb32914 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -138,14 +138,6 @@ static void __booke_wdt_enable(void *data)
val &= ~WDTP_MASK;
val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
-#ifdef CONFIG_PPC_BOOK3E_64
- /*
- * Crit ints are currently broken on PPC64 Book-E, so
- * just disable them for now.
- */
- val &= ~TCR_WIE;
-#endif
-
mtspr(SPRN_TCR, val);
}
diff --git a/drivers/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c
index f7ae49edb518..6d03e8e30f8b 100644
--- a/drivers/watchdog/cpu5wdt.c
+++ b/drivers/watchdog/cpu5wdt.c
@@ -27,7 +27,6 @@
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
-#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/completion.h>
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
index 213225edd059..e55ed702209f 100644
--- a/drivers/watchdog/cpwd.c
+++ b/drivers/watchdog/cpwd.c
@@ -21,7 +21,6 @@
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/major.h>
-#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c
index f09c54e9686f..2e9589652e1e 100644
--- a/drivers/watchdog/da9052_wdt.c
+++ b/drivers/watchdog/da9052_wdt.c
@@ -185,7 +185,6 @@ static int da9052_wdt_probe(struct platform_device *pdev)
driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
GFP_KERNEL);
if (!driver_data) {
- dev_err(da9052->dev, "Unable to alloacate watchdog device\n");
ret = -ENOMEM;
goto err;
}
diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c
index 575f37a965a4..495089d8dbfe 100644
--- a/drivers/watchdog/da9055_wdt.c
+++ b/drivers/watchdog/da9055_wdt.c
@@ -151,10 +151,8 @@ static int da9055_wdt_probe(struct platform_device *pdev)
driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
GFP_KERNEL);
- if (!driver_data) {
- dev_err(da9055->dev, "Failed to allocate watchdog device\n");
+ if (!driver_data)
return -ENOMEM;
- }
driver_data->da9055 = da9055;
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c
index b1bae03742a9..d09ad2254b57 100644
--- a/drivers/watchdog/davinci_wdt.c
+++ b/drivers/watchdog/davinci_wdt.c
@@ -16,7 +16,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/watchdog.h>
-#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/device.h>
diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c
index d1d07f2f69df..5f54e1e5819a 100644
--- a/drivers/watchdog/ep93xx_wdt.c
+++ b/drivers/watchdog/ep93xx_wdt.c
@@ -118,16 +118,9 @@ static int ep93xx_wdt_probe(struct platform_device *pdev)
int err;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENXIO;
-
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), pdev->name))
- return -EBUSY;
-
- mmio_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!mmio_base)
- return -ENXIO;
+ mmio_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mmio_base))
+ return PTR_ERR(mmio_base);
if (timeout < 1 || timeout > 3600) {
timeout = WDT_TIMEOUT;
@@ -172,9 +165,9 @@ static struct platform_driver ep93xx_wdt_driver = {
module_platform_driver(ep93xx_wdt_driver);
-MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>,"
- "Alessandro Zummo <a.zummo@towertech.it>,"
- "H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>");
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
MODULE_DESCRIPTION("EP93xx Watchdog");
MODULE_LICENSE("GPL");
MODULE_VERSION(WDT_VERSION);
diff --git a/drivers/watchdog/geodewdt.c b/drivers/watchdog/geodewdt.c
index 4a6ae84b42bc..4c43e3fa8bd2 100644
--- a/drivers/watchdog/geodewdt.c
+++ b/drivers/watchdog/geodewdt.c
@@ -215,7 +215,7 @@ static struct miscdevice geodewdt_miscdev = {
.fops = &geodewdt_fops,
};
-static int geodewdt_probe(struct platform_device *dev)
+static int __init geodewdt_probe(struct platform_device *dev)
{
int ret;
@@ -255,7 +255,6 @@ static void geodewdt_shutdown(struct platform_device *dev)
}
static struct platform_driver geodewdt_driver = {
- .probe = geodewdt_probe,
.remove = geodewdt_remove,
.shutdown = geodewdt_shutdown,
.driver = {
@@ -268,20 +267,18 @@ static int __init geodewdt_init(void)
{
int ret;
- ret = platform_driver_register(&geodewdt_driver);
- if (ret)
- return ret;
-
geodewdt_platform_device = platform_device_register_simple(DRV_NAME,
-1, NULL, 0);
- if (IS_ERR(geodewdt_platform_device)) {
- ret = PTR_ERR(geodewdt_platform_device);
+ if (IS_ERR(geodewdt_platform_device))
+ return PTR_ERR(geodewdt_platform_device);
+
+ ret = platform_driver_probe(&geodewdt_driver, geodewdt_probe);
+ if (ret)
goto err;
- }
return 0;
err:
- platform_driver_unregister(&geodewdt_driver);
+ platform_device_unregister(geodewdt_platform_device);
return ret;
}
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 2b75e8b47279..75d2243b94f5 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -17,7 +17,6 @@
#include <linux/device.h>
#include <linux/fs.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/bitops.h>
#include <linux/kernel.h>
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c
index 25a2bfdb4e9d..d7befd58b391 100644
--- a/drivers/watchdog/i6300esb.c
+++ b/drivers/watchdog/i6300esb.c
@@ -36,7 +36,6 @@
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
-#include <linux/init.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/uaccess.h>
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index 04f8af65acfd..0e6c0333f775 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -347,15 +347,15 @@ static const struct watchdog_info ident = {
static const struct watchdog_ops iTCO_wdt_ops = {
.owner = THIS_MODULE,
.start = iTCO_wdt_start,
- .stop = iTCO_wdt_stop,
- .ping = iTCO_wdt_ping,
+ .stop = iTCO_wdt_stop,
+ .ping = iTCO_wdt_ping,
.set_timeout = iTCO_wdt_set_timeout,
.get_timeleft = iTCO_wdt_get_timeleft,
};
static struct watchdog_device iTCO_wdt_watchdog_dev = {
.info = &ident,
- .ops = &iTCO_wdt_ops,
+ .ops = &iTCO_wdt_ops,
};
/*
@@ -485,7 +485,7 @@ static int iTCO_wdt_probe(struct platform_device *dev)
iTCO_wdt_watchdog_dev.bootstatus = 0;
iTCO_wdt_watchdog_dev.timeout = WATCHDOG_TIMEOUT;
watchdog_set_nowayout(&iTCO_wdt_watchdog_dev, nowayout);
- iTCO_wdt_watchdog_dev.parent = dev->dev.parent;
+ iTCO_wdt_watchdog_dev.parent = &dev->dev;
/* Make sure the watchdog is not running */
iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
diff --git a/drivers/watchdog/ib700wdt.c b/drivers/watchdog/ib700wdt.c
index 7ae36690c449..4247c498ee78 100644
--- a/drivers/watchdog/ib700wdt.c
+++ b/drivers/watchdog/ib700wdt.c
@@ -277,7 +277,7 @@ static struct miscdevice ibwdt_miscdev = {
* Init & exit routines
*/
-static int ibwdt_probe(struct platform_device *dev)
+static int __init ibwdt_probe(struct platform_device *dev)
{
int res;
@@ -336,7 +336,6 @@ static void ibwdt_shutdown(struct platform_device *dev)
}
static struct platform_driver ibwdt_driver = {
- .probe = ibwdt_probe,
.remove = ibwdt_remove,
.shutdown = ibwdt_shutdown,
.driver = {
@@ -351,21 +350,19 @@ static int __init ibwdt_init(void)
pr_info("WDT driver for IB700 single board computer initialising\n");
- err = platform_driver_register(&ibwdt_driver);
- if (err)
- return err;
-
ibwdt_platform_device = platform_device_register_simple(DRV_NAME,
-1, NULL, 0);
- if (IS_ERR(ibwdt_platform_device)) {
- err = PTR_ERR(ibwdt_platform_device);
- goto unreg_platform_driver;
- }
+ if (IS_ERR(ibwdt_platform_device))
+ return PTR_ERR(ibwdt_platform_device);
+
+ err = platform_driver_probe(&ibwdt_driver, ibwdt_probe);
+ if (err)
+ goto unreg_platform_device;
return 0;
-unreg_platform_driver:
- platform_driver_unregister(&ibwdt_driver);
+unreg_platform_device:
+ platform_device_unregister(ibwdt_platform_device);
return err;
}
diff --git a/drivers/watchdog/ibmasr.c b/drivers/watchdog/ibmasr.c
index db0a34460e57..366b0474f278 100644
--- a/drivers/watchdog/ibmasr.c
+++ b/drivers/watchdog/ibmasr.c
@@ -360,7 +360,7 @@ struct ibmasr_id {
int type;
};
-static struct ibmasr_id __initdata ibmasr_id_table[] = {
+static struct ibmasr_id ibmasr_id_table[] __initdata = {
{ "IBM Automatic Server Restart - eserver xSeries 220", ASMTYPE_TOPAZ },
{ "IBM Automatic Server Restart - Machine Type 8673", ASMTYPE_PEARL },
{ "IBM Automatic Server Restart - Machine Type 8480", ASMTYPE_JASPER },
diff --git a/drivers/watchdog/indydog.c b/drivers/watchdog/indydog.c
index 1b5c25a47b87..5d20cdd30efe 100644
--- a/drivers/watchdog/indydog.c
+++ b/drivers/watchdog/indydog.c
@@ -41,24 +41,15 @@ MODULE_PARM_DESC(nowayout,
static void indydog_start(void)
{
- u32 mc_ctrl0;
-
spin_lock(&indydog_lock);
- mc_ctrl0 = sgimc->cpuctrl0;
- mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG;
- sgimc->cpuctrl0 = mc_ctrl0;
+ sgimc->cpuctrl0 |= SGIMC_CCTRL0_WDOG;
spin_unlock(&indydog_lock);
}
static void indydog_stop(void)
{
- u32 mc_ctrl0;
-
spin_lock(&indydog_lock);
-
- mc_ctrl0 = sgimc->cpuctrl0;
- mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
- sgimc->cpuctrl0 = mc_ctrl0;
+ sgimc->cpuctrl0 &= ~SGIMC_CCTRL0_WDOG;
spin_unlock(&indydog_lock);
pr_info("Stopped watchdog timer\n");
diff --git a/drivers/watchdog/intel_scu_watchdog.c b/drivers/watchdog/intel_scu_watchdog.c
index e13e65e996aa..0caab6241eb7 100644
--- a/drivers/watchdog/intel_scu_watchdog.c
+++ b/drivers/watchdog/intel_scu_watchdog.c
@@ -211,7 +211,6 @@ static int intel_scu_set_heartbeat(u32 t)
int ipc_ret;
int retry_count;
u32 soft_value;
- u32 hw_pre_value;
u32 hw_value;
watchdog_device.timer_set = t;
@@ -273,8 +272,7 @@ static int intel_scu_set_heartbeat(u32 t)
watchdog_device.timer_load_count_addr);
/* read count value before starting timer */
- hw_pre_value = ioread32(watchdog_device.timer_load_count_addr);
- hw_pre_value = hw_pre_value & 0xFFFF0000;
+ ioread32(watchdog_device.timer_load_count_addr);
/* Start the timer */
iowrite32(0x00000003, watchdog_device.timer_control_addr);
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index e2bba68ae71e..0b93739c0106 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -54,6 +54,7 @@
/* Defaults for Module Parameter */
#define DEFAULT_NOGAMEPORT 0
+#define DEFAULT_NOCIR 0
#define DEFAULT_EXCLUSIVE 1
#define DEFAULT_TIMEOUT 60
#define DEFAULT_TESTMODE 0
@@ -136,11 +137,13 @@
#define WDTS_LOCKED 3
#define WDTS_USE_GP 4
#define WDTS_EXPECTED 5
+#define WDTS_USE_CIR 6
static unsigned int base, gpact, ciract, max_units, chip_type;
static unsigned long wdt_status;
static int nogameport = DEFAULT_NOGAMEPORT;
+static int nocir = DEFAULT_NOCIR;
static int exclusive = DEFAULT_EXCLUSIVE;
static int timeout = DEFAULT_TIMEOUT;
static int testmode = DEFAULT_TESTMODE;
@@ -149,6 +152,9 @@ static bool nowayout = DEFAULT_NOWAYOUT;
module_param(nogameport, int, 0);
MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
__MODULE_STRING(DEFAULT_NOGAMEPORT));
+module_param(nocir, int, 0);
+MODULE_PARM_DESC(nocir, "Forbid the use of Consumer IR interrupts to reset timer, default="
+ __MODULE_STRING(DEFAULT_NOCIR));
module_param(exclusive, int, 0);
MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default="
__MODULE_STRING(DEFAULT_EXCLUSIVE));
@@ -258,9 +264,17 @@ static void wdt_keepalive(void)
{
if (test_bit(WDTS_USE_GP, &wdt_status))
inb(base);
- else
+ else if (test_bit(WDTS_USE_CIR, &wdt_status))
/* The timer reloads with around 5 msec delay */
outb(0x55, CIR_DR(base));
+ else {
+ if (superio_enter())
+ return;
+
+ superio_select(GPIO);
+ wdt_update_timeout();
+ superio_exit();
+ }
set_bit(WDTS_KEEPALIVE, &wdt_status);
}
@@ -273,7 +287,7 @@ static int wdt_start(void)
superio_select(GPIO);
if (test_bit(WDTS_USE_GP, &wdt_status))
superio_outb(WDT_GAMEPORT, WDTCTRL);
- else
+ else if (test_bit(WDTS_USE_CIR, &wdt_status))
superio_outb(WDT_CIRINT, WDTCTRL);
wdt_update_timeout();
@@ -660,7 +674,7 @@ static int __init it87_wdt_init(void)
}
/* If we haven't Gameport support, try to get CIR support */
- if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+ if (!nocir && !test_bit(WDTS_USE_GP, &wdt_status)) {
if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
if (gp_rreq_fail)
pr_err("I/O Address 0x%04x and 0x%04x already in use\n",
@@ -682,6 +696,7 @@ static int __init it87_wdt_init(void)
superio_select(GAMEPORT);
superio_outb(gpact, ACTREG);
}
+ set_bit(WDTS_USE_CIR, &wdt_status);
}
if (timeout < 1 || timeout > max_units * 60) {
@@ -707,7 +722,7 @@ static int __init it87_wdt_init(void)
}
/* Initialize CIR to use it as keepalive source */
- if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+ if (test_bit(WDTS_USE_CIR, &wdt_status)) {
outb(0x00, CIR_RCR(base));
outb(0xc0, CIR_TCR1(base));
outb(0x5c, CIR_TCR2(base));
@@ -717,9 +732,9 @@ static int __init it87_wdt_init(void)
outb(0x09, CIR_IER(base));
}
- pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d)\n",
+ pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d nocir=%d)\n",
chip_type, chip_rev, timeout,
- nowayout, testmode, exclusive, nogameport);
+ nowayout, testmode, exclusive, nogameport, nocir);
superio_exit();
return 0;
@@ -727,8 +742,10 @@ static int __init it87_wdt_init(void)
err_out_reboot:
unregister_reboot_notifier(&wdt_notifier);
err_out_region:
- release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
- if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+ if (test_bit(WDTS_USE_GP, &wdt_status))
+ release_region(base, 1);
+ else if (test_bit(WDTS_USE_CIR, &wdt_status)) {
+ release_region(base, 8);
superio_select(CIR);
superio_outb(ciract, ACTREG);
}
@@ -754,7 +771,7 @@ static void __exit it87_wdt_exit(void)
if (test_bit(WDTS_USE_GP, &wdt_status)) {
superio_select(GAMEPORT);
superio_outb(gpact, ACTREG);
- } else {
+ } else if (test_bit(WDTS_USE_CIR, &wdt_status)) {
superio_select(CIR);
superio_outb(ciract, ACTREG);
}
@@ -763,7 +780,11 @@ static void __exit it87_wdt_exit(void)
misc_deregister(&wdt_miscdev);
unregister_reboot_notifier(&wdt_notifier);
- release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
+
+ if (test_bit(WDTS_USE_GP, &wdt_status))
+ release_region(base, 1);
+ else if (test_bit(WDTS_USE_CIR, &wdt_status))
+ release_region(base, 8);
}
module_init(it87_wdt_init);
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c
index 3aa50cfa335f..91e45ca589e6 100644
--- a/drivers/watchdog/jz4740_wdt.c
+++ b/drivers/watchdog/jz4740_wdt.c
@@ -18,7 +18,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/watchdog.h>
-#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/device.h>
diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c
index bdb3f4a5b27c..0e9cc6f5a919 100644
--- a/drivers/watchdog/max63xx_wdt.c
+++ b/drivers/watchdog/max63xx_wdt.c
@@ -20,7 +20,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/watchdog.h>
-#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
index c1f65b4c0aa4..7831955cd9e1 100644
--- a/drivers/watchdog/mpc8xxx_wdt.c
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -237,6 +237,7 @@ static const struct of_device_id mpc8xxx_wdt_match[] = {
.compatible = "fsl,mpc823-wdt",
.data = &(struct mpc8xxx_wdt_type) {
.prescaler = 0x800,
+ .hw_enabled = true,
},
},
{},
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
index edb31ffd7927..ff27c4ac96e4 100644
--- a/drivers/watchdog/mtx-1_wdt.c
+++ b/drivers/watchdog/mtx-1_wdt.c
@@ -40,7 +40,6 @@
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
-#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/completion.h>
diff --git a/drivers/watchdog/nuc900_wdt.c b/drivers/watchdog/nuc900_wdt.c
index a0d893b0930e..7135803ca1a3 100644
--- a/drivers/watchdog/nuc900_wdt.c
+++ b/drivers/watchdog/nuc900_wdt.c
@@ -12,7 +12,6 @@
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/kernel.h>
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c
index fb57103c8ebc..57ccae8327ff 100644
--- a/drivers/watchdog/of_xilinx_wdt.c
+++ b/drivers/watchdog/of_xilinx_wdt.c
@@ -1,6 +1,7 @@
/*
* Watchdog Device Driver for Xilinx axi/xps_timebase_wdt
*
+ * (C) Copyright 2013 - 2014 Xilinx, Inc.
* (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>)
*
* This program is free software; you can redistribute it and/or
@@ -9,18 +10,13 @@
* 2 of the License, or (at your option) any later version.
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/watchdog.h>
#include <linux/io.h>
-#include <linux/uaccess.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
@@ -43,102 +39,103 @@
#define XWT_TIMER_FAILED 0xFFFFFFFF
#define WATCHDOG_NAME "Xilinx Watchdog"
-#define PFX WATCHDOG_NAME ": "
struct xwdt_device {
- struct resource res;
void __iomem *base;
- u32 nowayout;
u32 wdt_interval;
- u32 boot_status;
+ spinlock_t spinlock;
+ struct watchdog_device xilinx_wdt_wdd;
};
-static struct xwdt_device xdev;
-
-static u32 timeout;
-static u32 control_status_reg;
-static u8 expect_close;
-static u8 no_timeout;
-static unsigned long driver_open;
-
-static DEFINE_SPINLOCK(spinlock);
-
-static void xwdt_start(void)
+static int xilinx_wdt_start(struct watchdog_device *wdd)
{
- spin_lock(&spinlock);
+ u32 control_status_reg;
+ struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
+
+ spin_lock(&xdev->spinlock);
/* Clean previous status and enable the watchdog timer */
- control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
+ control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET);
control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK),
- xdev.base + XWT_TWCSR0_OFFSET);
+ xdev->base + XWT_TWCSR0_OFFSET);
+
+ iowrite32(XWT_CSRX_EWDT2_MASK, xdev->base + XWT_TWCSR1_OFFSET);
- iowrite32(XWT_CSRX_EWDT2_MASK, xdev.base + XWT_TWCSR1_OFFSET);
+ spin_unlock(&xdev->spinlock);
- spin_unlock(&spinlock);
+ return 0;
}
-static void xwdt_stop(void)
+static int xilinx_wdt_stop(struct watchdog_device *wdd)
{
- spin_lock(&spinlock);
+ u32 control_status_reg;
+ struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
+
+ spin_lock(&xdev->spinlock);
- control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
+ control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET);
iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK),
- xdev.base + XWT_TWCSR0_OFFSET);
+ xdev->base + XWT_TWCSR0_OFFSET);
- iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET);
+ iowrite32(0, xdev->base + XWT_TWCSR1_OFFSET);
- spin_unlock(&spinlock);
+ spin_unlock(&xdev->spinlock);
pr_info("Stopped!\n");
+
+ return 0;
}
-static void xwdt_keepalive(void)
+static int xilinx_wdt_keepalive(struct watchdog_device *wdd)
{
- spin_lock(&spinlock);
+ u32 control_status_reg;
+ struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
- control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
- control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
- iowrite32(control_status_reg, xdev.base + XWT_TWCSR0_OFFSET);
+ spin_lock(&xdev->spinlock);
- spin_unlock(&spinlock);
-}
+ control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET);
+ control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
+ iowrite32(control_status_reg, xdev->base + XWT_TWCSR0_OFFSET);
-static void xwdt_get_status(int *status)
-{
- int new_status;
+ spin_unlock(&xdev->spinlock);
- spin_lock(&spinlock);
+ return 0;
+}
- control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
- new_status = ((control_status_reg &
- (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK)) != 0);
- spin_unlock(&spinlock);
+static const struct watchdog_info xilinx_wdt_ident = {
+ .options = WDIOF_MAGICCLOSE |
+ WDIOF_KEEPALIVEPING,
+ .firmware_version = 1,
+ .identity = WATCHDOG_NAME,
+};
- *status = 0;
- if (new_status & 1)
- *status |= WDIOF_CARDRESET;
-}
+static const struct watchdog_ops xilinx_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = xilinx_wdt_start,
+ .stop = xilinx_wdt_stop,
+ .ping = xilinx_wdt_keepalive,
+};
-static u32 xwdt_selftest(void)
+static u32 xwdt_selftest(struct xwdt_device *xdev)
{
int i;
u32 timer_value1;
u32 timer_value2;
- spin_lock(&spinlock);
+ spin_lock(&xdev->spinlock);
- timer_value1 = ioread32(xdev.base + XWT_TBR_OFFSET);
- timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
+ timer_value1 = ioread32(xdev->base + XWT_TBR_OFFSET);
+ timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET);
for (i = 0;
((i <= XWT_MAX_SELFTEST_LOOP_COUNT) &&
(timer_value2 == timer_value1)); i++) {
- timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
+ timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET);
}
- spin_unlock(&spinlock);
+ spin_unlock(&xdev->spinlock);
if (timer_value2 != timer_value1)
return ~XWT_TIMER_FAILED;
@@ -146,238 +143,83 @@ static u32 xwdt_selftest(void)
return XWT_TIMER_FAILED;
}
-static int xwdt_open(struct inode *inode, struct file *file)
-{
- /* Only one process can handle the wdt at a time */
- if (test_and_set_bit(0, &driver_open))
- return -EBUSY;
-
- /* Make sure that the module are always loaded...*/
- if (xdev.nowayout)
- __module_get(THIS_MODULE);
-
- xwdt_start();
- pr_info("Started...\n");
-
- return nonseekable_open(inode, file);
-}
-
-static int xwdt_release(struct inode *inode, struct file *file)
-{
- if (expect_close == 42) {
- xwdt_stop();
- } else {
- pr_crit("Unexpected close, not stopping watchdog!\n");
- xwdt_keepalive();
- }
-
- clear_bit(0, &driver_open);
- expect_close = 0;
- return 0;
-}
-
-/*
- * xwdt_write:
- * @file: file handle to the watchdog
- * @buf: buffer to write (unused as data does not matter here
- * @count: count of bytes
- * @ppos: pointer to the position to write. No seeks allowed
- *
- * A write to a watchdog device is defined as a keepalive signal. Any
- * write of data will do, as we don't define content meaning.
- */
-static ssize_t xwdt_write(struct file *file, const char __user *buf,
- size_t len, loff_t *ppos)
-{
- if (len) {
- if (!xdev.nowayout) {
- size_t i;
-
- /* In case it was set long ago */
- expect_close = 0;
-
- for (i = 0; i != len; i++) {
- char c;
-
- if (get_user(c, buf + i))
- return -EFAULT;
- if (c == 'V')
- expect_close = 42;
- }
- }
- xwdt_keepalive();
- }
- return len;
-}
-
-static const struct watchdog_info ident = {
- .options = WDIOF_MAGICCLOSE |
- WDIOF_KEEPALIVEPING,
- .firmware_version = 1,
- .identity = WATCHDOG_NAME,
-};
-
-/*
- * xwdt_ioctl:
- * @file: file handle to the device
- * @cmd: watchdog command
- * @arg: argument pointer
- *
- * The watchdog API defines a common set of functions for all watchdogs
- * according to their available features.
- */
-static long xwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- int status;
-
- union {
- struct watchdog_info __user *ident;
- int __user *i;
- } uarg;
-
- uarg.i = (int __user *)arg;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- return copy_to_user(uarg.ident, &ident,
- sizeof(ident)) ? -EFAULT : 0;
-
- case WDIOC_GETBOOTSTATUS:
- return put_user(xdev.boot_status, uarg.i);
-
- case WDIOC_GETSTATUS:
- xwdt_get_status(&status);
- return put_user(status, uarg.i);
-
- case WDIOC_KEEPALIVE:
- xwdt_keepalive();
- return 0;
-
- case WDIOC_GETTIMEOUT:
- if (no_timeout)
- return -ENOTTY;
- else
- return put_user(timeout, uarg.i);
-
- default:
- return -ENOTTY;
- }
-}
-
-static const struct file_operations xwdt_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = xwdt_write,
- .open = xwdt_open,
- .release = xwdt_release,
- .unlocked_ioctl = xwdt_ioctl,
-};
-
-static struct miscdevice xwdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &xwdt_fops,
-};
-
static int xwdt_probe(struct platform_device *pdev)
{
int rc;
- u32 *tmptr;
- u32 *pfreq;
-
- no_timeout = 0;
-
- pfreq = (u32 *)of_get_property(pdev->dev.of_node,
- "clock-frequency", NULL);
-
- if (pfreq == NULL) {
- pr_warn("The watchdog clock frequency cannot be obtained!\n");
- no_timeout = 1;
- }
-
- rc = of_address_to_resource(pdev->dev.of_node, 0, &xdev.res);
- if (rc) {
- pr_warn("invalid address!\n");
- return rc;
- }
-
- tmptr = (u32 *)of_get_property(pdev->dev.of_node,
- "xlnx,wdt-interval", NULL);
- if (tmptr == NULL) {
- pr_warn("Parameter \"xlnx,wdt-interval\" not found in device tree!\n");
- no_timeout = 1;
- } else {
- xdev.wdt_interval = *tmptr;
- }
-
- tmptr = (u32 *)of_get_property(pdev->dev.of_node,
- "xlnx,wdt-enable-once", NULL);
- if (tmptr == NULL) {
- pr_warn("Parameter \"xlnx,wdt-enable-once\" not found in device tree!\n");
- xdev.nowayout = WATCHDOG_NOWAYOUT;
- }
-
-/*
- * Twice of the 2^wdt_interval / freq because the first wdt overflow is
- * ignored (interrupt), reset is only generated at second wdt overflow
- */
- if (!no_timeout)
- timeout = 2 * ((1<<xdev.wdt_interval) / *pfreq);
-
- if (!request_mem_region(xdev.res.start,
- xdev.res.end - xdev.res.start + 1, WATCHDOG_NAME)) {
- rc = -ENXIO;
- pr_err("memory request failure!\n");
- goto err_out;
- }
-
- xdev.base = ioremap(xdev.res.start, xdev.res.end - xdev.res.start + 1);
- if (xdev.base == NULL) {
- rc = -ENOMEM;
- pr_err("ioremap failure!\n");
- goto release_mem;
- }
-
- rc = xwdt_selftest();
+ u32 pfreq = 0, enable_once = 0;
+ struct resource *res;
+ struct xwdt_device *xdev;
+ struct watchdog_device *xilinx_wdt_wdd;
+
+ xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
+ if (!xdev)
+ return -ENOMEM;
+
+ xilinx_wdt_wdd = &xdev->xilinx_wdt_wdd;
+ xilinx_wdt_wdd->info = &xilinx_wdt_ident;
+ xilinx_wdt_wdd->ops = &xilinx_wdt_ops;
+ xilinx_wdt_wdd->parent = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xdev->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(xdev->base))
+ return PTR_ERR(xdev->base);
+
+ rc = of_property_read_u32(pdev->dev.of_node, "clock-frequency", &pfreq);
+ if (rc)
+ dev_warn(&pdev->dev,
+ "The watchdog clock frequency cannot be obtained\n");
+
+ rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-interval",
+ &xdev->wdt_interval);
+ if (rc)
+ dev_warn(&pdev->dev,
+ "Parameter \"xlnx,wdt-interval\" not found\n");
+
+ rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-enable-once",
+ &enable_once);
+ if (rc)
+ dev_warn(&pdev->dev,
+ "Parameter \"xlnx,wdt-enable-once\" not found\n");
+
+ watchdog_set_nowayout(xilinx_wdt_wdd, enable_once);
+
+ /*
+ * Twice of the 2^wdt_interval / freq because the first wdt overflow is
+ * ignored (interrupt), reset is only generated at second wdt overflow
+ */
+ if (pfreq && xdev->wdt_interval)
+ xilinx_wdt_wdd->timeout = 2 * ((1 << xdev->wdt_interval) /
+ pfreq);
+
+ spin_lock_init(&xdev->spinlock);
+ watchdog_set_drvdata(xilinx_wdt_wdd, xdev);
+
+ rc = xwdt_selftest(xdev);
if (rc == XWT_TIMER_FAILED) {
- pr_err("SelfTest routine error!\n");
- goto unmap_io;
+ dev_err(&pdev->dev, "SelfTest routine error\n");
+ return rc;
}
- xwdt_get_status(&xdev.boot_status);
-
- rc = misc_register(&xwdt_miscdev);
+ rc = watchdog_register_device(xilinx_wdt_wdd);
if (rc) {
- pr_err("cannot register miscdev on minor=%d (err=%d)\n",
- xwdt_miscdev.minor, rc);
- goto unmap_io;
+ dev_err(&pdev->dev, "Cannot register watchdog (err=%d)\n", rc);
+ return rc;
}
- if (no_timeout)
- pr_info("driver loaded (timeout=? sec, nowayout=%d)\n",
- xdev.nowayout);
- else
- pr_info("driver loaded (timeout=%d sec, nowayout=%d)\n",
- timeout, xdev.nowayout);
+ dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n",
+ xdev->base, xilinx_wdt_wdd->timeout);
- expect_close = 0;
- clear_bit(0, &driver_open);
+ platform_set_drvdata(pdev, xdev);
return 0;
-
-unmap_io:
- iounmap(xdev.base);
-release_mem:
- release_mem_region(xdev.res.start, resource_size(&xdev.res));
-err_out:
- return rc;
}
-static int xwdt_remove(struct platform_device *dev)
+static int xwdt_remove(struct platform_device *pdev)
{
- misc_deregister(&xwdt_miscdev);
- iounmap(xdev.base);
- release_mem_region(xdev.res.start, resource_size(&xdev.res));
+ struct xwdt_device *xdev = platform_get_drvdata(pdev);
+
+ watchdog_unregister_device(&xdev->xilinx_wdt_wdd);
return 0;
}
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 09cf0135e8ac..3691b157516a 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -34,7 +34,6 @@
#include <linux/mm.h>
#include <linux/watchdog.h>
#include <linux/reboot.h>
-#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/moduleparam.h>
@@ -58,7 +57,6 @@ struct omap_wdt_dev {
void __iomem *base; /* physical */
struct device *dev;
bool omap_wdt_users;
- struct resource *mem;
int wdt_trgr_pattern;
struct mutex lock; /* to avoid races with PM */
};
@@ -207,7 +205,7 @@ static int omap_wdt_probe(struct platform_device *pdev)
{
struct omap_wd_timer_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct watchdog_device *omap_wdt;
- struct resource *res, *mem;
+ struct resource *res;
struct omap_wdt_dev *wdev;
u32 rs;
int ret;
@@ -216,29 +214,20 @@ static int omap_wdt_probe(struct platform_device *pdev)
if (!omap_wdt)
return -ENOMEM;
- /* reserve static register mappings */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENOENT;
-
- mem = devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), pdev->name);
- if (!mem)
- return -EBUSY;
-
wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
if (!wdev)
return -ENOMEM;
wdev->omap_wdt_users = false;
- wdev->mem = mem;
wdev->dev = &pdev->dev;
wdev->wdt_trgr_pattern = 0x1234;
mutex_init(&wdev->lock);
- wdev->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!wdev->base)
- return -ENOMEM;
+ /* reserve static register mappings */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ wdev->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(wdev->base))
+ return PTR_ERR(wdev->base);
omap_wdt->info = &omap_wdt_info;
omap_wdt->ops = &omap_wdt_ops;
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index f7722a424676..498163497c1c 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -18,7 +18,6 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/clk.h>
diff --git a/drivers/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c
index 5211d56b3681..9f15dd9435d1 100644
--- a/drivers/watchdog/pc87413_wdt.c
+++ b/drivers/watchdog/pc87413_wdt.c
@@ -512,9 +512,8 @@ static int __init pc87413_init(void)
return -EBUSY;
ret = register_reboot_notifier(&pc87413_notifier);
- if (ret != 0) {
+ if (ret != 0)
pr_err("cannot register reboot notifier (err=%d)\n", ret);
- }
ret = misc_register(&pc87413_miscdev);
if (ret != 0) {
@@ -575,8 +574,8 @@ static void __exit pc87413_exit(void)
module_init(pc87413_init);
module_exit(pc87413_exit);
-MODULE_AUTHOR("Sven Anders <anders@anduras.de>, "
- "Marcus Junker <junker@anduras.de>,");
+MODULE_AUTHOR("Sven Anders <anders@anduras.de>");
+MODULE_AUTHOR("Marcus Junker <junker@anduras.de>");
MODULE_DESCRIPTION("PC87413 WDT driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c
index e562e0476016..1a11aedc4fe8 100644
--- a/drivers/watchdog/pcwd_usb.c
+++ b/drivers/watchdog/pcwd_usb.c
@@ -645,10 +645,8 @@ static int usb_pcwd_probe(struct usb_interface *interface,
/* allocate memory for our device and initialize it */
usb_pcwd = kzalloc(sizeof(struct usb_pcwd_private), GFP_KERNEL);
- if (usb_pcwd == NULL) {
- pr_err("Out of memory\n");
+ if (usb_pcwd == NULL)
goto error;
- }
usb_pcwd_device = usb_pcwd;
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index 5bec20f5dc2d..15fb316e9437 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -24,7 +24,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/watchdog.h>
-#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/spinlock.h>
diff --git a/drivers/watchdog/rdc321x_wdt.c b/drivers/watchdog/rdc321x_wdt.c
index 082d06262959..29cf4dcbc59c 100644
--- a/drivers/watchdog/rdc321x_wdt.c
+++ b/drivers/watchdog/rdc321x_wdt.c
@@ -27,7 +27,6 @@
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
-#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/completion.h>
diff --git a/drivers/watchdog/retu_wdt.c b/drivers/watchdog/retu_wdt.c
index f53615dc633d..a7a0695971e4 100644
--- a/drivers/watchdog/retu_wdt.c
+++ b/drivers/watchdog/retu_wdt.c
@@ -16,7 +16,6 @@
* GNU General Public License for more details.
*/
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/device.h>
diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c
index 3dd8ed28adc8..cfed0fe264dc 100644
--- a/drivers/watchdog/riowd.c
+++ b/drivers/watchdog/riowd.c
@@ -10,7 +10,6 @@
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/of.h>
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index aec946df6ed9..7c6ccd071baf 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -30,7 +30,6 @@
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/watchdog.h>
-#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
@@ -526,7 +525,11 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
goto err;
}
- clk_prepare_enable(wdt->clock);
+ ret = clk_prepare_enable(wdt->clock);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable clock\n");
+ return ret;
+ }
ret = s3c2410wdt_cpufreq_register(wdt);
if (ret < 0) {
@@ -608,7 +611,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
err_clk:
clk_disable_unprepare(wdt->clock);
- wdt->clock = NULL;
err:
return ret;
@@ -628,7 +630,6 @@ static int s3c2410wdt_remove(struct platform_device *dev)
s3c2410wdt_cpufreq_deregister(wdt);
clk_disable_unprepare(wdt->clock);
- wdt->clock = NULL;
return 0;
}
diff --git a/drivers/watchdog/sc520_wdt.c b/drivers/watchdog/sc520_wdt.c
index f353e18b1a82..1cfd3f6a13d5 100644
--- a/drivers/watchdog/sc520_wdt.c
+++ b/drivers/watchdog/sc520_wdt.c
@@ -158,12 +158,11 @@ static void wdt_timer_ping(unsigned long data)
static void wdt_config(int writeval)
{
- __u16 dummy;
unsigned long flags;
/* buy some time (ping) */
spin_lock_irqsave(&wdt_spinlock, flags);
- dummy = readw(wdtmrctl); /* ensure write synchronization */
+ readw(wdtmrctl); /* ensure write synchronization */
writew(0xAAAA, wdtmrctl);
writew(0x5555, wdtmrctl);
/* unlock WDT = make WDT configuration register writable one time */
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index af3528f84d65..d04d02b41c32 100644
--- a/drivers/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
@@ -293,8 +293,6 @@ static int sh_wdt_probe(struct platform_device *pdev)
static int sh_wdt_remove(struct platform_device *pdev)
{
- struct sh_wdt *wdt = platform_get_drvdata(pdev);
-
watchdog_unregister_device(&sh_wdt_dev);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c
index c04a1aa158e2..0dc5e323d59d 100644
--- a/drivers/watchdog/softdog.c
+++ b/drivers/watchdog/softdog.c
@@ -62,7 +62,7 @@ MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-static int soft_noboot = 0;
+static int soft_noboot;
module_param(soft_noboot, int, 0);
MODULE_PARM_DESC(soft_noboot,
"Softdog action, set to 1 to ignore reboots, 0 to reboot (default=0)");
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
index 3f786ce0a6f2..47629d268e0a 100644
--- a/drivers/watchdog/sp805_wdt.c
+++ b/drivers/watchdog/sp805_wdt.c
@@ -16,7 +16,6 @@
#include <linux/amba/bus.h>
#include <linux/bitops.h>
#include <linux/clk.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
@@ -209,27 +208,15 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
struct sp805_wdt *wdt;
int ret = 0;
- if (!devm_request_mem_region(&adev->dev, adev->res.start,
- resource_size(&adev->res), "sp805_wdt")) {
- dev_warn(&adev->dev, "Failed to get memory region resource\n");
- ret = -ENOENT;
- goto err;
- }
-
wdt = devm_kzalloc(&adev->dev, sizeof(*wdt), GFP_KERNEL);
if (!wdt) {
- dev_warn(&adev->dev, "Kzalloc failed\n");
ret = -ENOMEM;
goto err;
}
- wdt->base = devm_ioremap(&adev->dev, adev->res.start,
- resource_size(&adev->res));
- if (!wdt->base) {
- ret = -ENOMEM;
- dev_warn(&adev->dev, "ioremap fail\n");
- goto err;
- }
+ wdt->base = devm_ioremap_resource(&adev->dev, &adev->res);
+ if (IS_ERR(wdt->base))
+ return PTR_ERR(wdt->base);
wdt->clk = devm_clk_get(&adev->dev, NULL);
if (IS_ERR(wdt->clk)) {
diff --git a/drivers/watchdog/stmp3xxx_rtc_wdt.c b/drivers/watchdog/stmp3xxx_rtc_wdt.c
index bb64ae3f47da..3804d5e9baea 100644
--- a/drivers/watchdog/stmp3xxx_rtc_wdt.c
+++ b/drivers/watchdog/stmp3xxx_rtc_wdt.c
@@ -9,7 +9,6 @@
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/watchdog.h>
diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c
index 76332d893e12..cd00a7836cdc 100644
--- a/drivers/watchdog/sunxi_wdt.c
+++ b/drivers/watchdog/sunxi_wdt.c
@@ -205,7 +205,7 @@ static void sunxi_wdt_shutdown(struct platform_device *pdev)
}
static const struct of_device_id sunxi_wdt_dt_ids[] = {
- { .compatible = "allwinner,sun4i-wdt" },
+ { .compatible = "allwinner,sun4i-a10-wdt" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sunxi_wdt_dt_ids);
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
new file mode 100644
index 000000000000..750e2a26cb12
--- /dev/null
+++ b/drivers/watchdog/tegra_wdt.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+
+/* minimum and maximum watchdog trigger timeout, in seconds */
+#define MIN_WDT_TIMEOUT 1
+#define MAX_WDT_TIMEOUT 255
+
+/*
+ * Base of the WDT registers, from the timer base address. There are
+ * actually 5 watchdogs that can be configured (by pairing with an available
+ * timer), at bases 0x100 + (WDT ID) * 0x20, where WDT ID is 0 through 4.
+ * This driver only configures the first watchdog (WDT ID 0).
+ */
+#define WDT_BASE 0x100
+#define WDT_ID 0
+
+/*
+ * Register base of the timer that's selected for pairing with the watchdog.
+ * This driver arbitrarily uses timer 5, which is currently unused by
+ * other drivers (in particular, the Tegra clocksource driver). If this
+ * needs to change, take care that the new timer is not used by the
+ * clocksource driver.
+ */
+#define WDT_TIMER_BASE 0x60
+#define WDT_TIMER_ID 5
+
+/* WDT registers */
+#define WDT_CFG 0x0
+#define WDT_CFG_PERIOD_SHIFT 4
+#define WDT_CFG_PERIOD_MASK 0xff
+#define WDT_CFG_INT_EN (1 << 12)
+#define WDT_CFG_PMC2CAR_RST_EN (1 << 15)
+#define WDT_STS 0x4
+#define WDT_STS_COUNT_SHIFT 4
+#define WDT_STS_COUNT_MASK 0xff
+#define WDT_STS_EXP_SHIFT 12
+#define WDT_STS_EXP_MASK 0x3
+#define WDT_CMD 0x8
+#define WDT_CMD_START_COUNTER (1 << 0)
+#define WDT_CMD_DISABLE_COUNTER (1 << 1)
+#define WDT_UNLOCK (0xc)
+#define WDT_UNLOCK_PATTERN (0xc45a << 0)
+
+/* Timer registers */
+#define TIMER_PTV 0x0
+#define TIMER_EN (1 << 31)
+#define TIMER_PERIODIC (1 << 30)
+
+struct tegra_wdt {
+ struct watchdog_device wdd;
+ void __iomem *wdt_regs;
+ void __iomem *tmr_regs;
+};
+
+#define WDT_HEARTBEAT 120
+static int heartbeat = WDT_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+ "Watchdog heartbeats in seconds. (default = "
+ __MODULE_STRING(WDT_HEARTBEAT) ")");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int tegra_wdt_start(struct watchdog_device *wdd)
+{
+ struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
+ u32 val;
+
+ /*
+ * This thing has a fixed 1MHz clock. Normally, we would set the
+ * period to 1 second by writing 1000000ul, but the watchdog system
+ * reset actually occurs on the 4th expiration of this counter,
+ * so we set the period to 1/4 of this amount.
+ */
+ val = 1000000ul / 4;
+ val |= (TIMER_EN | TIMER_PERIODIC);
+ writel(val, wdt->tmr_regs + TIMER_PTV);
+
+ /*
+ * Set number of periods and start counter.
+ *
+ * Interrupt handler is not required for user space
+ * WDT accesses, since the caller is responsible to ping the
+ * WDT to reset the counter before expiration, through ioctls.
+ */
+ val = WDT_TIMER_ID |
+ (wdd->timeout << WDT_CFG_PERIOD_SHIFT) |
+ WDT_CFG_PMC2CAR_RST_EN;
+ writel(val, wdt->wdt_regs + WDT_CFG);
+
+ writel(WDT_CMD_START_COUNTER, wdt->wdt_regs + WDT_CMD);
+
+ return 0;
+}
+
+static int tegra_wdt_stop(struct watchdog_device *wdd)
+{
+ struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
+
+ writel(WDT_UNLOCK_PATTERN, wdt->wdt_regs + WDT_UNLOCK);
+ writel(WDT_CMD_DISABLE_COUNTER, wdt->wdt_regs + WDT_CMD);
+ writel(0, wdt->tmr_regs + TIMER_PTV);
+
+ return 0;
+}
+
+static int tegra_wdt_ping(struct watchdog_device *wdd)
+{
+ struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
+
+ writel(WDT_CMD_START_COUNTER, wdt->wdt_regs + WDT_CMD);
+
+ return 0;
+}
+
+static int tegra_wdt_set_timeout(struct watchdog_device *wdd,
+ unsigned int timeout)
+{
+ wdd->timeout = timeout;
+
+ if (watchdog_active(wdd))
+ return tegra_wdt_start(wdd);
+
+ return 0;
+}
+
+static unsigned int tegra_wdt_get_timeleft(struct watchdog_device *wdd)
+{
+ struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
+ u32 val;
+ int count;
+ int exp;
+
+ val = readl(wdt->wdt_regs + WDT_STS);
+
+ /* Current countdown (from timeout) */
+ count = (val >> WDT_STS_COUNT_SHIFT) & WDT_STS_COUNT_MASK;
+
+ /* Number of expirations (we are waiting for the 4th expiration) */
+ exp = (val >> WDT_STS_EXP_SHIFT) & WDT_STS_EXP_MASK;
+
+ /*
+ * The entire thing is divided by 4 because we are ticking down 4 times
+ * faster due to needing to wait for the 4th expiration.
+ */
+ return (((3 - exp) * wdd->timeout) + count) / 4;
+}
+
+static const struct watchdog_info tegra_wdt_info = {
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_MAGICCLOSE |
+ WDIOF_KEEPALIVEPING,
+ .firmware_version = 0,
+ .identity = "Tegra Watchdog",
+};
+
+static struct watchdog_ops tegra_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = tegra_wdt_start,
+ .stop = tegra_wdt_stop,
+ .ping = tegra_wdt_ping,
+ .set_timeout = tegra_wdt_set_timeout,
+ .get_timeleft = tegra_wdt_get_timeleft,
+};
+
+static int tegra_wdt_probe(struct platform_device *pdev)
+{
+ struct watchdog_device *wdd;
+ struct tegra_wdt *wdt;
+ struct resource *res;
+ void __iomem *regs;
+ int ret;
+
+ /* This is the timer base. */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ /*
+ * Allocate our watchdog driver data, which has the
+ * struct watchdog_device nested within it.
+ */
+ wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+ if (!wdt)
+ return -ENOMEM;
+
+ /* Initialize struct tegra_wdt. */
+ wdt->wdt_regs = regs + WDT_BASE;
+ wdt->tmr_regs = regs + WDT_TIMER_BASE;
+
+ /* Initialize struct watchdog_device. */
+ wdd = &wdt->wdd;
+ wdd->timeout = heartbeat;
+ wdd->info = &tegra_wdt_info;
+ wdd->ops = &tegra_wdt_ops;
+ wdd->min_timeout = MIN_WDT_TIMEOUT;
+ wdd->max_timeout = MAX_WDT_TIMEOUT;
+
+ watchdog_set_drvdata(wdd, wdt);
+
+ watchdog_set_nowayout(wdd, nowayout);
+
+ ret = watchdog_register_device(wdd);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to register watchdog device\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, wdt);
+
+ dev_info(&pdev->dev,
+ "initialized (heartbeat = %d sec, nowayout = %d)\n",
+ heartbeat, nowayout);
+
+ return 0;
+}
+
+static int tegra_wdt_remove(struct platform_device *pdev)
+{
+ struct tegra_wdt *wdt = platform_get_drvdata(pdev);
+
+ tegra_wdt_stop(&wdt->wdd);
+
+ watchdog_unregister_device(&wdt->wdd);
+
+ dev_info(&pdev->dev, "removed wdt\n");
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tegra_wdt_runtime_suspend(struct device *dev)
+{
+ struct tegra_wdt *wdt = dev_get_drvdata(dev);
+
+ if (watchdog_active(&wdt->wdd))
+ tegra_wdt_stop(&wdt->wdd);
+
+ return 0;
+}
+
+static int tegra_wdt_runtime_resume(struct device *dev)
+{
+ struct tegra_wdt *wdt = dev_get_drvdata(dev);
+
+ if (watchdog_active(&wdt->wdd))
+ tegra_wdt_start(&wdt->wdd);
+
+ return 0;
+}
+#endif
+
+static const struct of_device_id tegra_wdt_of_match[] = {
+ { .compatible = "nvidia,tegra30-timer", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, tegra_wdt_of_match);
+
+static const struct dev_pm_ops tegra_wdt_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(tegra_wdt_runtime_suspend,
+ tegra_wdt_runtime_resume)
+};
+
+static struct platform_driver tegra_wdt_driver = {
+ .probe = tegra_wdt_probe,
+ .remove = tegra_wdt_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tegra-wdt",
+ .pm = &tegra_wdt_pm_ops,
+ .of_match_table = tegra_wdt_of_match,
+ },
+};
+module_platform_driver(tegra_wdt_driver);
+
+MODULE_AUTHOR("NVIDIA Corporation");
+MODULE_DESCRIPTION("Tegra Watchdog Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c
index 09d4831aa61f..afa9d6ef353a 100644
--- a/drivers/watchdog/ts72xx_wdt.c
+++ b/drivers/watchdog/ts72xx_wdt.c
@@ -61,7 +61,7 @@ struct ts72xx_wdt {
struct platform_device *pdev;
};
-struct platform_device *ts72xx_wdt_pdev;
+static struct platform_device *ts72xx_wdt_pdev;
/*
* TS-72xx Watchdog supports following timeouts (value written
@@ -394,10 +394,8 @@ static int ts72xx_wdt_probe(struct platform_device *pdev)
int error = 0;
wdt = devm_kzalloc(&pdev->dev, sizeof(struct ts72xx_wdt), GFP_KERNEL);
- if (!wdt) {
- dev_err(&pdev->dev, "failed to allocate memory\n");
+ if (!wdt)
return -ENOMEM;
- }
r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
wdt->control_reg = devm_ioremap_resource(&pdev->dev, r1);
diff --git a/drivers/watchdog/w83697hf_wdt.c b/drivers/watchdog/w83697hf_wdt.c
index aaf2995d37f4..e9ea856b8ff2 100644
--- a/drivers/watchdog/w83697hf_wdt.c
+++ b/drivers/watchdog/w83697hf_wdt.c
@@ -402,7 +402,7 @@ static int __init wdt_init(void)
if (!found) {
pr_err("No W83697HF/HG could be found\n");
- ret = -EIO;
+ ret = -ENODEV;
goto out;
}
@@ -455,6 +455,6 @@ module_init(wdt_init);
module_exit(wdt_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marcus Junker <junker@anduras.de>, "
- "Samuel Tardieu <sam@rfc1149.net>");
+MODULE_AUTHOR("Marcus Junker <junker@anduras.de>");
+MODULE_AUTHOR("Samuel Tardieu <sam@rfc1149.net>");
MODULE_DESCRIPTION("w83697hf/hg WDT driver");
diff --git a/drivers/watchdog/wdt285.c b/drivers/watchdog/wdt285.c
index 7355ddd0b207..ebbb183be618 100644
--- a/drivers/watchdog/wdt285.c
+++ b/drivers/watchdog/wdt285.c
@@ -139,9 +139,8 @@ static const struct watchdog_info ident = {
static long watchdog_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
- unsigned int new_margin;
int __user *int_arg = (int __user *)arg;
- int ret = -ENOTTY;
+ int new_margin, ret = -ENOTTY;
switch (cmd) {
case WDIOC_GETSUPPORT:
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index 3dc578e71211..48b2c058b009 100644
--- a/drivers/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -49,7 +49,6 @@
#include <linux/delay.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
-#include <linux/init.h>
#include <linux/fs.h>
#include <linux/pci.h>
#include <linux/io.h>
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c
index e243bd01c774..2fa17e746ff6 100644
--- a/drivers/watchdog/wm831x_wdt.c
+++ b/drivers/watchdog/wm831x_wdt.c
@@ -204,7 +204,6 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
GFP_KERNEL);
if (!driver_data) {
- dev_err(wm831x->dev, "Unable to alloacate watchdog device\n");
ret = -ENOMEM;
goto err;
}
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 37d06ea624aa..61a6ac8fa8fc 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -399,11 +399,25 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
state = BP_EAGAIN;
break;
}
+ scrub_page(page);
- pfn = page_to_pfn(page);
- frame_list[i] = pfn_to_mfn(pfn);
+ frame_list[i] = page_to_pfn(page);
+ }
- scrub_page(page);
+ /*
+ * Ensure that ballooned highmem pages don't have kmaps.
+ *
+ * Do this before changing the p2m as kmap_flush_unused()
+ * reads PTEs to obtain pages (and hence needs the original
+ * p2m entry).
+ */
+ kmap_flush_unused();
+
+ /* Update direct mapping, invalidate P2M, and add to balloon. */
+ for (i = 0; i < nr_pages; i++) {
+ pfn = frame_list[i];
+ frame_list[i] = pfn_to_mfn(pfn);
+ page = pfn_to_page(pfn);
#ifdef CONFIG_XEN_HAVE_PVMMU
/*
@@ -429,11 +443,9 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
}
#endif
- balloon_append(pfn_to_page(pfn));
+ balloon_append(page);
}
- /* Ensure that ballooned highmem pages don't have kmaps. */
- kmap_flush_unused();
flush_tlb_all();
set_xen_guest_handle(reservation.extent_start, frame_list);
diff --git a/drivers/xen/events/events_2l.c b/drivers/xen/events/events_2l.c
index d7ff91757307..5db43fc100a4 100644
--- a/drivers/xen/events/events_2l.c
+++ b/drivers/xen/events/events_2l.c
@@ -166,7 +166,6 @@ static void evtchn_2l_handle_events(unsigned cpu)
int start_word_idx, start_bit_idx;
int word_idx, bit_idx;
int i;
- struct irq_desc *desc;
struct shared_info *s = HYPERVISOR_shared_info;
struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
@@ -176,11 +175,8 @@ static void evtchn_2l_handle_events(unsigned cpu)
unsigned int evtchn = evtchn_from_irq(irq);
word_idx = evtchn / BITS_PER_LONG;
bit_idx = evtchn % BITS_PER_LONG;
- if (active_evtchns(cpu, s, word_idx) & (1ULL << bit_idx)) {
- desc = irq_to_desc(irq);
- if (desc)
- generic_handle_irq_desc(irq, desc);
- }
+ if (active_evtchns(cpu, s, word_idx) & (1ULL << bit_idx))
+ generic_handle_irq(irq);
}
/*
@@ -245,11 +241,8 @@ static void evtchn_2l_handle_events(unsigned cpu)
port = (word_idx * BITS_PER_EVTCHN_WORD) + bit_idx;
irq = get_evtchn_to_irq(port);
- if (irq != -1) {
- desc = irq_to_desc(irq);
- if (desc)
- generic_handle_irq_desc(irq, desc);
- }
+ if (irq != -1)
+ generic_handle_irq(irq);
bit_idx = (bit_idx + 1) % BITS_PER_EVTCHN_WORD;
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index f4a9e3311297..c3458f58de90 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -336,9 +336,8 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
BUG_ON(irq == -1);
#ifdef CONFIG_SMP
- cpumask_copy(irq_to_desc(irq)->irq_data.affinity, cpumask_of(cpu));
+ cpumask_copy(irq_get_irq_data(irq)->affinity, cpumask_of(cpu));
#endif
-
xen_evtchn_port_bind_to_cpu(info, cpu);
info->cpu = cpu;
@@ -373,10 +372,8 @@ static void xen_irq_init(unsigned irq)
{
struct irq_info *info;
#ifdef CONFIG_SMP
- struct irq_desc *desc = irq_to_desc(irq);
-
/* By default all event channels notify CPU#0. */
- cpumask_copy(desc->irq_data.affinity, cpumask_of(0));
+ cpumask_copy(irq_get_irq_data(irq)->affinity, cpumask_of(0));
#endif
info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -490,13 +487,6 @@ static void pirq_query_unmask(int irq)
info->u.pirq.flags |= PIRQ_NEEDS_EOI;
}
-static bool probing_irq(int irq)
-{
- struct irq_desc *desc = irq_to_desc(irq);
-
- return desc && desc->action == NULL;
-}
-
static void eoi_pirq(struct irq_data *data)
{
int evtchn = evtchn_from_irq(data->irq);
@@ -538,8 +528,7 @@ static unsigned int __startup_pirq(unsigned int irq)
BIND_PIRQ__WILL_SHARE : 0;
rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq);
if (rc != 0) {
- if (!probing_irq(irq))
- pr_info("Failed to obtain physical IRQ %d\n", irq);
+ pr_warn("Failed to obtain physical IRQ %d\n", irq);
return 0;
}
evtchn = bind_pirq.port;
@@ -772,17 +761,12 @@ error_irq:
int xen_destroy_irq(int irq)
{
- struct irq_desc *desc;
struct physdev_unmap_pirq unmap_irq;
struct irq_info *info = info_for_irq(irq);
int rc = -ENOENT;
mutex_lock(&irq_mapping_update_lock);
- desc = irq_to_desc(irq);
- if (!desc)
- goto out;
-
if (xen_initial_domain()) {
unmap_irq.pirq = info->u.pirq.pirq;
unmap_irq.domid = info->u.pirq.domid;
@@ -1251,6 +1235,7 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
#ifdef CONFIG_X86
exit_idle();
#endif
+ inc_irq_stat(irq_hv_callback_count);
__xen_evtchn_do_upcall();
@@ -1339,7 +1324,7 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
bool force)
{
- unsigned tcpu = cpumask_first(dest);
+ unsigned tcpu = cpumask_first_and(dest, cpu_online_mask);
return rebind_irq_to_cpu(data->irq, tcpu);
}
diff --git a/drivers/xen/events/events_fifo.c b/drivers/xen/events/events_fifo.c
index 1de2a191b395..96109a9972b6 100644
--- a/drivers/xen/events/events_fifo.c
+++ b/drivers/xen/events/events_fifo.c
@@ -235,14 +235,10 @@ static uint32_t clear_linked(volatile event_word_t *word)
static void handle_irq_for_port(unsigned port)
{
int irq;
- struct irq_desc *desc;
irq = get_evtchn_to_irq(port);
- if (irq != -1) {
- desc = irq_to_desc(irq);
- if (desc)
- generic_handle_irq_desc(irq, desc);
- }
+ if (irq != -1)
+ generic_handle_irq(irq);
}
static void consume_one_event(unsigned cpu,
diff --git a/drivers/xen/xen-acpi-cpuhotplug.c b/drivers/xen/xen-acpi-cpuhotplug.c
index 80875fb770ed..3e62ee4b3b66 100644
--- a/drivers/xen/xen-acpi-cpuhotplug.c
+++ b/drivers/xen/xen-acpi-cpuhotplug.c
@@ -313,7 +313,7 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
goto out;
}
- (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
+ (void) acpi_evaluate_ost(handle, event, ost_code, NULL);
out:
acpi_scan_lock_release();
diff --git a/drivers/xen/xen-acpi-memhotplug.c b/drivers/xen/xen-acpi-memhotplug.c
index f8d18626969a..34e40b733f9a 100644
--- a/drivers/xen/xen-acpi-memhotplug.c
+++ b/drivers/xen/xen-acpi-memhotplug.c
@@ -285,7 +285,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
return;
}
- (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
+ (void) acpi_evaluate_ost(handle, event, ost_code, NULL);
return;
}
diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c
index 40c4bc06b5fa..f83b754505f8 100644
--- a/drivers/xen/xen-acpi-pad.c
+++ b/drivers/xen/xen-acpi-pad.c
@@ -77,27 +77,14 @@ static int acpi_pad_pur(acpi_handle handle)
return num;
}
-/* Notify firmware how many CPUs are idle */
-static void acpi_pad_ost(acpi_handle handle, int stat,
- uint32_t idle_nums)
-{
- union acpi_object params[3] = {
- {.type = ACPI_TYPE_INTEGER,},
- {.type = ACPI_TYPE_INTEGER,},
- {.type = ACPI_TYPE_BUFFER,},
- };
- struct acpi_object_list arg_list = {3, params};
-
- params[0].integer.value = ACPI_PROCESSOR_AGGREGATOR_NOTIFY;
- params[1].integer.value = stat;
- params[2].buffer.length = 4;
- params[2].buffer.pointer = (void *)&idle_nums;
- acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
-}
-
static void acpi_pad_handle_notify(acpi_handle handle)
{
int idle_nums;
+ struct acpi_buffer param = {
+ .length = 4,
+ .pointer = (void *)&idle_nums,
+ };
+
mutex_lock(&xen_cpu_lock);
idle_nums = acpi_pad_pur(handle);
@@ -109,7 +96,8 @@ static void acpi_pad_handle_notify(acpi_handle handle)
idle_nums = xen_acpi_pad_idle_cpus(idle_nums)
?: xen_acpi_pad_idle_cpus_num();
if (idle_nums >= 0)
- acpi_pad_ost(handle, 0, idle_nums);
+ acpi_evaluate_ost(handle, ACPI_PROCESSOR_AGGREGATOR_NOTIFY,
+ 0, &param);
mutex_unlock(&xen_cpu_lock);
}
diff --git a/fs/Kconfig b/fs/Kconfig
index 7385e54be4b9..312393f32948 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -96,6 +96,7 @@ endif # BLOCK
menu "Pseudo filesystems"
source "fs/proc/Kconfig"
+source "fs/kernfs/Kconfig"
source "fs/sysfs/Kconfig"
config TMPFS
diff --git a/fs/Makefile b/fs/Makefile
index 47ac07bb4acc..f9cb9876e466 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -52,7 +52,8 @@ obj-$(CONFIG_FHANDLE) += fhandle.o
obj-y += quota/
obj-$(CONFIG_PROC_FS) += proc/
-obj-$(CONFIG_SYSFS) += sysfs/ kernfs/
+obj-$(CONFIG_KERNFS) += kernfs/
+obj-$(CONFIG_SYSFS) += sysfs/
obj-$(CONFIG_CONFIGFS_FS) += configfs/
obj-y += devpts/
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 6621f8008122..be75b500005d 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -75,6 +75,7 @@ struct afs_call {
const struct afs_call_type *type; /* type of call */
const struct afs_wait_mode *wait_mode; /* completion wait mode */
wait_queue_head_t waitq; /* processes awaiting completion */
+ work_func_t async_workfn;
struct work_struct async_work; /* asynchronous work processor */
struct work_struct work; /* actual work processor */
struct sk_buff_head rx_queue; /* received packets */
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 8ad8c2a0703a..ef943df73b8c 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -644,7 +644,7 @@ static void afs_process_async_call(struct work_struct *work)
/* we can't just delete the call because the work item may be
* queued */
- PREPARE_WORK(&call->async_work, afs_delete_async_call);
+ call->async_workfn = afs_delete_async_call;
queue_work(afs_async_calls, &call->async_work);
}
@@ -663,6 +663,13 @@ void afs_transfer_reply(struct afs_call *call, struct sk_buff *skb)
call->reply_size += len;
}
+static void afs_async_workfn(struct work_struct *work)
+{
+ struct afs_call *call = container_of(work, struct afs_call, async_work);
+
+ call->async_workfn(work);
+}
+
/*
* accept the backlog of incoming calls
*/
@@ -685,7 +692,8 @@ static void afs_collect_incoming_call(struct work_struct *work)
return;
}
- INIT_WORK(&call->async_work, afs_process_async_call);
+ call->async_workfn = afs_process_async_call;
+ INIT_WORK(&call->async_work, afs_async_workfn);
call->wait_mode = &afs_async_incoming_call;
call->type = &afs_RXCMxxxx;
init_waitqueue_head(&call->waitq);
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index 24084732b1d0..80ef38c73e5a 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -41,19 +41,8 @@ static const struct dentry_operations anon_inodefs_dentry_operations = {
static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
- struct dentry *root;
- root = mount_pseudo(fs_type, "anon_inode:", NULL,
+ return mount_pseudo(fs_type, "anon_inode:", NULL,
&anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC);
- if (!IS_ERR(root)) {
- struct super_block *s = root->d_sb;
- anon_inode_inode = alloc_anon_inode(s);
- if (IS_ERR(anon_inode_inode)) {
- dput(root);
- deactivate_locked_super(s);
- root = ERR_CAST(anon_inode_inode);
- }
- }
- return root;
}
static struct file_system_type anon_inode_fs_type = {
@@ -175,22 +164,15 @@ EXPORT_SYMBOL_GPL(anon_inode_getfd);
static int __init anon_inode_init(void)
{
- int error;
-
- error = register_filesystem(&anon_inode_fs_type);
- if (error)
- goto err_exit;
anon_inode_mnt = kern_mount(&anon_inode_fs_type);
- if (IS_ERR(anon_inode_mnt)) {
- error = PTR_ERR(anon_inode_mnt);
- goto err_unregister_filesystem;
- }
- return 0;
+ if (IS_ERR(anon_inode_mnt))
+ panic("anon_inode_init() kernel mount failed (%ld)\n", PTR_ERR(anon_inode_mnt));
-err_unregister_filesystem:
- unregister_filesystem(&anon_inode_fs_type);
-err_exit:
- panic(KERN_ERR "anon_inode_init() failed (%d)\n", error);
+ anon_inode_inode = alloc_anon_inode(anon_inode_mnt->mnt_sb);
+ if (IS_ERR(anon_inode_inode))
+ panic("anon_inode_init() inode allocation failed (%ld)\n", PTR_ERR(anon_inode_inode));
+
+ return 0;
}
fs_initcall(anon_inode_init);
diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c
index 0129b78a6908..29696b78d1f4 100644
--- a/fs/bio-integrity.c
+++ b/fs/bio-integrity.c
@@ -301,25 +301,25 @@ int bio_integrity_get_tag(struct bio *bio, void *tag_buf, unsigned int len)
EXPORT_SYMBOL(bio_integrity_get_tag);
/**
- * bio_integrity_generate - Generate integrity metadata for a bio
- * @bio: bio to generate integrity metadata for
- *
- * Description: Generates integrity metadata for a bio by calling the
- * block device's generation callback function. The bio must have a
- * bip attached with enough room to accommodate the generated
- * integrity metadata.
+ * bio_integrity_generate_verify - Generate/verify integrity metadata for a bio
+ * @bio: bio to generate/verify integrity metadata for
+ * @operate: operate number, 1 for generate, 0 for verify
*/
-static void bio_integrity_generate(struct bio *bio)
+static int bio_integrity_generate_verify(struct bio *bio, int operate)
{
struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
struct blk_integrity_exchg bix;
struct bio_vec bv;
struct bvec_iter iter;
- sector_t sector = bio->bi_iter.bi_sector;
- unsigned int sectors, total;
+ sector_t sector;
+ unsigned int sectors, ret = 0;
void *prot_buf = bio->bi_integrity->bip_buf;
- total = 0;
+ if (operate)
+ sector = bio->bi_iter.bi_sector;
+ else
+ sector = bio->bi_integrity->bip_iter.bi_sector;
+
bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
bix.sector_size = bi->sector_size;
@@ -330,16 +330,37 @@ static void bio_integrity_generate(struct bio *bio)
bix.prot_buf = prot_buf;
bix.sector = sector;
- bi->generate_fn(&bix);
+ if (operate) {
+ bi->generate_fn(&bix);
+ } else {
+ ret = bi->verify_fn(&bix);
+ if (ret) {
+ kunmap_atomic(kaddr);
+ return ret;
+ }
+ }
sectors = bv.bv_len / bi->sector_size;
sector += sectors;
prot_buf += sectors * bi->tuple_size;
- total += sectors * bi->tuple_size;
- BUG_ON(total > bio->bi_integrity->bip_iter.bi_size);
kunmap_atomic(kaddr);
}
+ return ret;
+}
+
+/**
+ * bio_integrity_generate - Generate integrity metadata for a bio
+ * @bio: bio to generate integrity metadata for
+ *
+ * Description: Generates integrity metadata for a bio by calling the
+ * block device's generation callback function. The bio must have a
+ * bip attached with enough room to accommodate the generated
+ * integrity metadata.
+ */
+static void bio_integrity_generate(struct bio *bio)
+{
+ bio_integrity_generate_verify(bio, 1);
}
static inline unsigned short blk_integrity_tuple_size(struct blk_integrity *bi)
@@ -454,43 +475,7 @@ EXPORT_SYMBOL(bio_integrity_prep);
*/
static int bio_integrity_verify(struct bio *bio)
{
- struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
- struct blk_integrity_exchg bix;
- struct bio_vec *bv;
- sector_t sector = bio->bi_integrity->bip_iter.bi_sector;
- unsigned int sectors, total, ret;
- void *prot_buf = bio->bi_integrity->bip_buf;
- int i;
-
- ret = total = 0;
- bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
- bix.sector_size = bi->sector_size;
-
- bio_for_each_segment_all(bv, bio, i) {
- void *kaddr = kmap_atomic(bv->bv_page);
-
- bix.data_buf = kaddr + bv->bv_offset;
- bix.data_size = bv->bv_len;
- bix.prot_buf = prot_buf;
- bix.sector = sector;
-
- ret = bi->verify_fn(&bix);
-
- if (ret) {
- kunmap_atomic(kaddr);
- return ret;
- }
-
- sectors = bv->bv_len / bi->sector_size;
- sector += sectors;
- prot_buf += sectors * bi->tuple_size;
- total += sectors * bi->tuple_size;
- BUG_ON(total > bio->bi_integrity->bip_iter.bi_size);
-
- kunmap_atomic(kaddr);
- }
-
- return ret;
+ return bio_integrity_generate_verify(bio, 0);
}
/**
diff --git a/fs/bio.c b/fs/bio.c
index 8754e7b6eb49..b2dd42ed9edd 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -116,7 +116,6 @@ static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size)
if (!slab)
goto out_unlock;
- printk(KERN_INFO "bio: create slab <%s> at %d\n", bslab->name, entry);
bslab->slab = slab;
bslab->slab_ref = 1;
bslab->slab_size = sz;
diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c
index 4c2d452c4bfc..21887d63dad5 100644
--- a/fs/ceph/acl.c
+++ b/fs/ceph/acl.c
@@ -54,11 +54,6 @@ static inline struct posix_acl *ceph_get_cached_acl(struct inode *inode,
return acl;
}
-void ceph_forget_all_cached_acls(struct inode *inode)
-{
- forget_all_cached_acls(inode);
-}
-
struct posix_acl *ceph_get_acl(struct inode *inode, int type)
{
int size;
@@ -160,11 +155,7 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
goto out_dput;
}
- if (value)
- ret = __ceph_setxattr(dentry, name, value, size, 0);
- else
- ret = __ceph_removexattr(dentry, name);
-
+ ret = __ceph_setxattr(dentry, name, value, size, 0);
if (ret) {
if (new_mode != old_mode) {
newattrs.ia_mode = old_mode;
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 6da4df84ba30..45eda6d7a40c 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -100,6 +100,14 @@ static unsigned fpos_off(loff_t p)
return p & 0xffffffff;
}
+static int fpos_cmp(loff_t l, loff_t r)
+{
+ int v = ceph_frag_compare(fpos_frag(l), fpos_frag(r));
+ if (v)
+ return v;
+ return (int)(fpos_off(l) - fpos_off(r));
+}
+
/*
* When possible, we try to satisfy a readdir by peeking at the
* dcache. We make this work by carefully ordering dentries on
@@ -156,7 +164,7 @@ more:
if (!d_unhashed(dentry) && dentry->d_inode &&
ceph_snap(dentry->d_inode) != CEPH_SNAPDIR &&
ceph_ino(dentry->d_inode) != CEPH_INO_CEPH &&
- ctx->pos <= di->offset)
+ fpos_cmp(ctx->pos, di->offset) <= 0)
break;
dout(" skipping %p %.*s at %llu (%llu)%s%s\n", dentry,
dentry->d_name.len, dentry->d_name.name, di->offset,
@@ -695,9 +703,8 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
ceph_mdsc_put_request(req);
if (!err)
- err = ceph_init_acl(dentry, dentry->d_inode, dir);
-
- if (err)
+ ceph_init_acl(dentry, dentry->d_inode, dir);
+ else
d_drop(dentry);
return err;
}
@@ -735,7 +742,9 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry,
if (!err && !req->r_reply_info.head->is_dentry)
err = ceph_handle_notrace_create(dir, dentry);
ceph_mdsc_put_request(req);
- if (err)
+ if (!err)
+ ceph_init_acl(dentry, dentry->d_inode, dir);
+ else
d_drop(dentry);
return err;
}
@@ -776,7 +785,9 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
err = ceph_handle_notrace_create(dir, dentry);
ceph_mdsc_put_request(req);
out:
- if (err < 0)
+ if (!err)
+ ceph_init_acl(dentry, dentry->d_inode, dir);
+ else
d_drop(dentry);
return err;
}
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index dfd2ce3419f8..09c7afe32e49 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -286,6 +286,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
} else {
dout("atomic_open finish_open on dn %p\n", dn);
if (req->r_op == CEPH_MDS_OP_CREATE && req->r_reply_info.has_create_ino) {
+ ceph_init_acl(dentry, dentry->d_inode, dir);
*opened |= FILE_CREATED;
}
err = finish_open(file, dentry, ceph_open, opened);
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index 2df963f1cf5a..10a4ccbf38da 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -144,7 +144,11 @@ enum {
Opt_ino32,
Opt_noino32,
Opt_fscache,
- Opt_nofscache
+ Opt_nofscache,
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+ Opt_acl,
+#endif
+ Opt_noacl
};
static match_table_t fsopt_tokens = {
@@ -172,6 +176,10 @@ static match_table_t fsopt_tokens = {
{Opt_noino32, "noino32"},
{Opt_fscache, "fsc"},
{Opt_nofscache, "nofsc"},
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+ {Opt_acl, "acl"},
+#endif
+ {Opt_noacl, "noacl"},
{-1, NULL}
};
@@ -271,6 +279,14 @@ static int parse_fsopt_token(char *c, void *private)
case Opt_nofscache:
fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE;
break;
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+ case Opt_acl:
+ fsopt->sb_flags |= MS_POSIXACL;
+ break;
+#endif
+ case Opt_noacl:
+ fsopt->sb_flags &= ~MS_POSIXACL;
+ break;
default:
BUG_ON(token);
}
@@ -438,6 +454,13 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
else
seq_puts(m, ",nofsc");
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+ if (fsopt->sb_flags & MS_POSIXACL)
+ seq_puts(m, ",acl");
+ else
+ seq_puts(m, ",noacl");
+#endif
+
if (fsopt->wsize)
seq_printf(m, ",wsize=%d", fsopt->wsize);
if (fsopt->rsize != CEPH_RSIZE_DEFAULT)
@@ -819,9 +842,6 @@ static int ceph_set_super(struct super_block *s, void *data)
s->s_flags = fsc->mount_options->sb_flags;
s->s_maxbytes = 1ULL << 40; /* temp value until we get mdsmap */
-#ifdef CONFIG_CEPH_FS_POSIX_ACL
- s->s_flags |= MS_POSIXACL;
-#endif
s->s_xattr = ceph_xattr_handlers;
s->s_fs_info = fsc;
@@ -911,6 +931,10 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type,
struct ceph_options *opt = NULL;
dout("ceph_mount\n");
+
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+ flags |= MS_POSIXACL;
+#endif
err = parse_mount_options(&fsopt, &opt, flags, data, dev_name, &path);
if (err < 0) {
res = ERR_PTR(err);
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 19793b56d0a7..d8801a95b685 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -13,6 +13,7 @@
#include <linux/wait.h>
#include <linux/writeback.h>
#include <linux/slab.h>
+#include <linux/posix_acl.h>
#include <linux/ceph/libceph.h>
@@ -743,7 +744,11 @@ extern const struct xattr_handler *ceph_xattr_handlers[];
struct posix_acl *ceph_get_acl(struct inode *, int);
int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type);
int ceph_init_acl(struct dentry *, struct inode *, struct inode *);
-void ceph_forget_all_cached_acls(struct inode *inode);
+
+static inline void ceph_forget_all_cached_acls(struct inode *inode)
+{
+ forget_all_cached_acls(inode);
+}
#else
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
index 898b6565ad3e..a55ec37378c6 100644
--- a/fs/ceph/xattr.c
+++ b/fs/ceph/xattr.c
@@ -12,6 +12,9 @@
#define XATTR_CEPH_PREFIX "ceph."
#define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1)
+static int __remove_xattr(struct ceph_inode_info *ci,
+ struct ceph_inode_xattr *xattr);
+
/*
* List of handlers for synthetic system.* attributes. Other
* attributes are handled directly.
@@ -319,8 +322,7 @@ static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode,
static int __set_xattr(struct ceph_inode_info *ci,
const char *name, int name_len,
const char *val, int val_len,
- int dirty,
- int should_free_name, int should_free_val,
+ int flags, int update_xattr,
struct ceph_inode_xattr **newxattr)
{
struct rb_node **p;
@@ -349,12 +351,31 @@ static int __set_xattr(struct ceph_inode_info *ci,
xattr = NULL;
}
+ if (update_xattr) {
+ int err = 0;
+ if (xattr && (flags & XATTR_CREATE))
+ err = -EEXIST;
+ else if (!xattr && (flags & XATTR_REPLACE))
+ err = -ENODATA;
+ if (err) {
+ kfree(name);
+ kfree(val);
+ return err;
+ }
+ if (update_xattr < 0) {
+ if (xattr)
+ __remove_xattr(ci, xattr);
+ kfree(name);
+ return 0;
+ }
+ }
+
if (!xattr) {
new = 1;
xattr = *newxattr;
xattr->name = name;
xattr->name_len = name_len;
- xattr->should_free_name = should_free_name;
+ xattr->should_free_name = update_xattr;
ci->i_xattrs.count++;
dout("__set_xattr count=%d\n", ci->i_xattrs.count);
@@ -364,7 +385,7 @@ static int __set_xattr(struct ceph_inode_info *ci,
if (xattr->should_free_val)
kfree((void *)xattr->val);
- if (should_free_name) {
+ if (update_xattr) {
kfree((void *)name);
name = xattr->name;
}
@@ -379,8 +400,8 @@ static int __set_xattr(struct ceph_inode_info *ci,
xattr->val = "";
xattr->val_len = val_len;
- xattr->dirty = dirty;
- xattr->should_free_val = (val && should_free_val);
+ xattr->dirty = update_xattr;
+ xattr->should_free_val = (val && update_xattr);
if (new) {
rb_link_node(&xattr->node, parent, p);
@@ -442,7 +463,7 @@ static int __remove_xattr(struct ceph_inode_info *ci,
struct ceph_inode_xattr *xattr)
{
if (!xattr)
- return -EOPNOTSUPP;
+ return -ENODATA;
rb_erase(&xattr->node, &ci->i_xattrs.index);
@@ -588,7 +609,7 @@ start:
p += len;
err = __set_xattr(ci, name, namelen, val, len,
- 0, 0, 0, &xattrs[numattr]);
+ 0, 0, &xattrs[numattr]);
if (err < 0)
goto bad;
@@ -850,6 +871,9 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
dout("setxattr value=%.*s\n", (int)size, value);
+ if (!value)
+ flags |= CEPH_XATTR_REMOVE;
+
/* do request */
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETXATTR,
USE_AUTH_MDS);
@@ -892,7 +916,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name,
struct ceph_inode_info *ci = ceph_inode(inode);
int issued;
int err;
- int dirty;
+ int dirty = 0;
int name_len = strlen(name);
int val_len = size;
char *newname = NULL;
@@ -953,12 +977,14 @@ retry:
goto retry;
}
- err = __set_xattr(ci, newname, name_len, newval,
- val_len, 1, 1, 1, &xattr);
+ err = __set_xattr(ci, newname, name_len, newval, val_len,
+ flags, value ? 1 : -1, &xattr);
- dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
- ci->i_xattrs.dirty = true;
- inode->i_ctime = CURRENT_TIME;
+ if (!err) {
+ dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
+ ci->i_xattrs.dirty = true;
+ inode->i_ctime = CURRENT_TIME;
+ }
spin_unlock(&ci->i_ceph_lock);
if (dirty)
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index c819b0bd491a..7ff866dbb89e 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -865,8 +865,8 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
return rc;
}
-static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
- __u16 fid, u32 *pacllen)
+struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
+ const struct cifs_fid *cifsfid, u32 *pacllen)
{
struct cifs_ntsd *pntsd = NULL;
unsigned int xid;
@@ -877,7 +877,8 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
return ERR_CAST(tlink);
xid = get_xid();
- rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
+ rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
+ pacllen);
free_xid(xid);
cifs_put_tlink(tlink);
@@ -946,7 +947,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
if (!open_file)
return get_cifs_acl_by_path(cifs_sb, path, pacllen);
- pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
+ pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
cifsFileInfo_put(open_file);
return pntsd;
}
@@ -1006,19 +1007,31 @@ out:
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
int
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
- struct inode *inode, const char *path, const __u16 *pfid)
+ struct inode *inode, const char *path,
+ const struct cifs_fid *pfid)
{
struct cifs_ntsd *pntsd = NULL;
u32 acllen = 0;
int rc = 0;
+ struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
+ struct cifs_tcon *tcon;
cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
- if (pfid)
- pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
- else
- pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+ if (pfid && (tcon->ses->server->ops->get_acl_by_fid))
+ pntsd = tcon->ses->server->ops->get_acl_by_fid(cifs_sb, pfid,
+ &acllen);
+ else if (tcon->ses->server->ops->get_acl)
+ pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
+ &acllen);
+ else {
+ cifs_put_tlink(tlink);
+ return -EOPNOTSUPP;
+ }
/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
if (IS_ERR(pntsd)) {
rc = PTR_ERR(pntsd);
@@ -1030,6 +1043,8 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
}
+ cifs_put_tlink(tlink);
+
return rc;
}
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 86dc28c7aa5c..c0f3718b77a8 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -398,6 +398,8 @@ struct smb_version_operations {
const struct nls_table *, int);
struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *,
const char *, u32 *);
+ struct cifs_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *,
+ const struct cifs_fid *, u32 *);
int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
int);
};
@@ -511,7 +513,7 @@ struct cifs_mnt_data {
static inline unsigned int
get_rfc1002_length(void *buf)
{
- return be32_to_cpu(*((__be32 *)buf));
+ return be32_to_cpu(*((__be32 *)buf)) & 0xffffff;
}
static inline void
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index d00e09dfc452..acc4ee8ed075 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -151,7 +151,7 @@ extern struct inode *cifs_iget(struct super_block *sb,
extern int cifs_get_inode_info(struct inode **inode, const char *full_path,
FILE_ALL_INFO *data, struct super_block *sb,
- int xid, const __u16 *fid);
+ int xid, const struct cifs_fid *fid);
extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path,
struct super_block *sb, unsigned int xid);
@@ -162,11 +162,13 @@ extern int cifs_rename_pending_delete(const char *full_path,
const unsigned int xid);
extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
struct cifs_fattr *fattr, struct inode *inode,
- const char *path, const __u16 *pfid);
+ const char *path, const struct cifs_fid *pfid);
extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64,
kuid_t, kgid_t);
extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
const char *, u32 *);
+extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *,
+ const struct cifs_fid *, u32 *);
extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
const char *, int);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index d3a6796caa5a..3db0c5fd9a11 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -378,7 +378,7 @@ cifs_create_get_file_info:
xid);
else {
rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,
- xid, &fid->netfid);
+ xid, fid);
if (newinode) {
if (server->ops->set_lease_key)
server->ops->set_lease_key(newinode, fid);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 755584684f6c..834fce759d80 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -244,7 +244,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
xid);
else
rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
- xid, &fid->netfid);
+ xid, fid);
out:
kfree(buf);
@@ -2389,7 +2389,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
unsigned long nr_segs, loff_t *poffset)
{
unsigned long nr_pages, i;
- size_t copied, len, cur_len;
+ size_t bytes, copied, len, cur_len;
ssize_t total_written = 0;
loff_t offset;
struct iov_iter it;
@@ -2444,14 +2444,45 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
save_len = cur_len;
for (i = 0; i < nr_pages; i++) {
- copied = min_t(const size_t, cur_len, PAGE_SIZE);
+ bytes = min_t(const size_t, cur_len, PAGE_SIZE);
copied = iov_iter_copy_from_user(wdata->pages[i], &it,
- 0, copied);
+ 0, bytes);
cur_len -= copied;
iov_iter_advance(&it, copied);
+ /*
+ * If we didn't copy as much as we expected, then that
+ * may mean we trod into an unmapped area. Stop copying
+ * at that point. On the next pass through the big
+ * loop, we'll likely end up getting a zero-length
+ * write and bailing out of it.
+ */
+ if (copied < bytes)
+ break;
}
cur_len = save_len - cur_len;
+ /*
+ * If we have no data to send, then that probably means that
+ * the copy above failed altogether. That's most likely because
+ * the address in the iovec was bogus. Set the rc to -EFAULT,
+ * free anything we allocated and bail out.
+ */
+ if (!cur_len) {
+ for (i = 0; i < nr_pages; i++)
+ put_page(wdata->pages[i]);
+ kfree(wdata);
+ rc = -EFAULT;
+ break;
+ }
+
+ /*
+ * i + 1 now represents the number of pages we actually used in
+ * the copy phase above. Bring nr_pages down to that, and free
+ * any pages that we didn't use.
+ */
+ for ( ; nr_pages > i + 1; nr_pages--)
+ put_page(wdata->pages[nr_pages - 1]);
+
wdata->sync_mode = WB_SYNC_ALL;
wdata->nr_pages = nr_pages;
wdata->offset = (__u64)offset;
@@ -2548,31 +2579,19 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov,
struct cifsInodeInfo *cinode = CIFS_I(inode);
struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
ssize_t rc = -EACCES;
+ loff_t lock_pos = pos;
- BUG_ON(iocb->ki_pos != pos);
-
+ if (file->f_flags & O_APPEND)
+ lock_pos = i_size_read(inode);
/*
* We need to hold the sem to be sure nobody modifies lock list
* with a brlock that prevents writing.
*/
down_read(&cinode->lock_sem);
- if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs),
+ if (!cifs_find_lock_conflict(cfile, lock_pos, iov_length(iov, nr_segs),
server->vals->exclusive_lock_type, NULL,
- CIFS_WRITE_OP)) {
- mutex_lock(&inode->i_mutex);
- rc = __generic_file_aio_write(iocb, iov, nr_segs,
- &iocb->ki_pos);
- mutex_unlock(&inode->i_mutex);
- }
-
- if (rc > 0) {
- ssize_t err;
-
- err = generic_write_sync(file, iocb->ki_pos - rc, rc);
- if (err < 0)
- rc = err;
- }
-
+ CIFS_WRITE_OP))
+ rc = generic_file_aio_write(iocb, iov, nr_segs, pos);
up_read(&cinode->lock_sem);
return rc;
}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index be58b8fcdb3c..aadc2b68678b 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -677,7 +677,7 @@ cgfi_exit:
int
cifs_get_inode_info(struct inode **inode, const char *full_path,
FILE_ALL_INFO *data, struct super_block *sb, int xid,
- const __u16 *fid)
+ const struct cifs_fid *fid)
{
bool validinum = false;
__u16 srchflgs;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index bfd66d84831e..526fb89f9230 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -1073,6 +1073,7 @@ struct smb_version_operations smb1_operations = {
#endif /* CIFS_XATTR */
#ifdef CONFIG_CIFS_ACL
.get_acl = get_cifs_acl,
+ .get_acl_by_fid = get_cifs_acl_by_fid,
.set_acl = set_cifs_acl,
#endif /* CIFS_ACL */
};
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index c38350851b08..bc0bb9c34f72 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -57,4 +57,7 @@
#define SMB2_CMACAES_SIZE (16)
#define SMB3_SIGNKEY_SIZE (16)
+/* Maximum buffer size value we can send with 1 credit */
+#define SMB2_MAX_BUFFER_SIZE 65536
+
#endif /* _SMB2_GLOB_H */
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 757da3e54d3d..192f51a12cf1 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -182,11 +182,8 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
/* start with specified wsize, or default */
wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
wsize = min_t(unsigned int, wsize, server->max_write);
- /*
- * limit write size to 2 ** 16, because we don't support multicredit
- * requests now.
- */
- wsize = min_t(unsigned int, wsize, 2 << 15);
+ /* set it to the maximum buffer size value we can send with 1 credit */
+ wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
return wsize;
}
@@ -200,11 +197,8 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
/* start with specified rsize, or default */
rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
rsize = min_t(unsigned int, rsize, server->max_read);
- /*
- * limit write size to 2 ** 16, because we don't support multicredit
- * requests now.
- */
- rsize = min_t(unsigned int, rsize, 2 << 15);
+ /* set it to the maximum buffer size value we can send with 1 credit */
+ rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
return rsize;
}
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index a3f7a9c3cc69..860344701067 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -413,7 +413,9 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
/* SMB2 only has an extended negflavor */
server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
- server->maxBuf = le32_to_cpu(rsp->MaxTransactSize);
+ /* set it to the maximum buffer size value we can send with 1 credit */
+ server->maxBuf = min_t(unsigned int, le32_to_cpu(rsp->MaxTransactSize),
+ SMB2_MAX_BUFFER_SIZE);
server->max_read = le32_to_cpu(rsp->MaxReadSize);
server->max_write = le32_to_cpu(rsp->MaxWriteSize);
/* BB Do we need to validate the SecurityMode? */
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index b37570952846..18cd5650a5fc 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -270,6 +270,26 @@ cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx,
iov->iov_len = rqst->rq_pagesz;
}
+static unsigned long
+rqst_len(struct smb_rqst *rqst)
+{
+ unsigned int i;
+ struct kvec *iov = rqst->rq_iov;
+ unsigned long buflen = 0;
+
+ /* total up iov array first */
+ for (i = 0; i < rqst->rq_nvec; i++)
+ buflen += iov[i].iov_len;
+
+ /* add in the page array if there is one */
+ if (rqst->rq_npages) {
+ buflen += rqst->rq_pagesz * (rqst->rq_npages - 1);
+ buflen += rqst->rq_tailsz;
+ }
+
+ return buflen;
+}
+
static int
smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
{
@@ -277,6 +297,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
struct kvec *iov = rqst->rq_iov;
int n_vec = rqst->rq_nvec;
unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
+ unsigned long send_length;
unsigned int i;
size_t total_len = 0, sent;
struct socket *ssocket = server->ssocket;
@@ -285,6 +306,14 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
if (ssocket == NULL)
return -ENOTSOCK;
+ /* sanity check send length */
+ send_length = rqst_len(rqst);
+ if (send_length != smb_buf_length + 4) {
+ WARN(1, "Send length mismatch(send_length=%lu smb_buf_length=%u)\n",
+ send_length, smb_buf_length);
+ return -EIO;
+ }
+
cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
dump_smb(iov[0].iov_base, iov[0].iov_len);
diff --git a/fs/compat.c b/fs/compat.c
index 6af20de2c1a3..f86df85dff61 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -72,8 +72,8 @@ int compat_printk(const char *fmt, ...)
* Not all architectures have sys_utime, so implement this in terms
* of sys_utimes.
*/
-asmlinkage long compat_sys_utime(const char __user *filename,
- struct compat_utimbuf __user *t)
+COMPAT_SYSCALL_DEFINE2(utime, const char __user *, filename,
+ struct compat_utimbuf __user *, t)
{
struct timespec tv[2];
@@ -87,13 +87,13 @@ asmlinkage long compat_sys_utime(const char __user *filename,
return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0);
}
-asmlinkage long compat_sys_utimensat(unsigned int dfd, const char __user *filename, struct compat_timespec __user *t, int flags)
+COMPAT_SYSCALL_DEFINE4(utimensat, unsigned int, dfd, const char __user *, filename, struct compat_timespec __user *, t, int, flags)
{
struct timespec tv[2];
if (t) {
- if (get_compat_timespec(&tv[0], &t[0]) ||
- get_compat_timespec(&tv[1], &t[1]))
+ if (compat_get_timespec(&tv[0], &t[0]) ||
+ compat_get_timespec(&tv[1], &t[1]))
return -EFAULT;
if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT)
@@ -102,7 +102,7 @@ asmlinkage long compat_sys_utimensat(unsigned int dfd, const char __user *filena
return do_utimes(dfd, filename, t ? tv : NULL, flags);
}
-asmlinkage long compat_sys_futimesat(unsigned int dfd, const char __user *filename, struct compat_timeval __user *t)
+COMPAT_SYSCALL_DEFINE3(futimesat, unsigned int, dfd, const char __user *, filename, struct compat_timeval __user *, t)
{
struct timespec tv[2];
@@ -121,7 +121,7 @@ asmlinkage long compat_sys_futimesat(unsigned int dfd, const char __user *filena
return do_utimes(dfd, filename, t ? tv : NULL, 0);
}
-asmlinkage long compat_sys_utimes(const char __user *filename, struct compat_timeval __user *t)
+COMPAT_SYSCALL_DEFINE2(utimes, const char __user *, filename, struct compat_timeval __user *, t)
{
return compat_sys_futimesat(AT_FDCWD, filename, t);
}
@@ -159,8 +159,8 @@ static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
-asmlinkage long compat_sys_newstat(const char __user * filename,
- struct compat_stat __user *statbuf)
+COMPAT_SYSCALL_DEFINE2(newstat, const char __user *, filename,
+ struct compat_stat __user *, statbuf)
{
struct kstat stat;
int error;
@@ -171,8 +171,8 @@ asmlinkage long compat_sys_newstat(const char __user * filename,
return cp_compat_stat(&stat, statbuf);
}
-asmlinkage long compat_sys_newlstat(const char __user * filename,
- struct compat_stat __user *statbuf)
+COMPAT_SYSCALL_DEFINE2(newlstat, const char __user *, filename,
+ struct compat_stat __user *, statbuf)
{
struct kstat stat;
int error;
@@ -184,9 +184,9 @@ asmlinkage long compat_sys_newlstat(const char __user * filename,
}
#ifndef __ARCH_WANT_STAT64
-asmlinkage long compat_sys_newfstatat(unsigned int dfd,
- const char __user *filename,
- struct compat_stat __user *statbuf, int flag)
+COMPAT_SYSCALL_DEFINE4(newfstatat, unsigned int, dfd,
+ const char __user *, filename,
+ struct compat_stat __user *, statbuf, int, flag)
{
struct kstat stat;
int error;
@@ -198,8 +198,8 @@ asmlinkage long compat_sys_newfstatat(unsigned int dfd,
}
#endif
-asmlinkage long compat_sys_newfstat(unsigned int fd,
- struct compat_stat __user * statbuf)
+COMPAT_SYSCALL_DEFINE2(newfstat, unsigned int, fd,
+ struct compat_stat __user *, statbuf)
{
struct kstat stat;
int error = vfs_fstat(fd, &stat);
@@ -247,7 +247,7 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *
* The following statfs calls are copies of code from fs/statfs.c and
* should be checked against those from time to time
*/
-asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf)
+COMPAT_SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct compat_statfs __user *, buf)
{
struct kstatfs tmp;
int error = user_statfs(pathname, &tmp);
@@ -256,7 +256,7 @@ asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_sta
return error;
}
-asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf)
+COMPAT_SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct compat_statfs __user *, buf)
{
struct kstatfs tmp;
int error = fd_statfs(fd, &tmp);
@@ -298,7 +298,7 @@ static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstat
return 0;
}
-asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf)
+COMPAT_SYSCALL_DEFINE3(statfs64, const char __user *, pathname, compat_size_t, sz, struct compat_statfs64 __user *, buf)
{
struct kstatfs tmp;
int error;
@@ -312,7 +312,7 @@ asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t s
return error;
}
-asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf)
+COMPAT_SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, compat_size_t, sz, struct compat_statfs64 __user *, buf)
{
struct kstatfs tmp;
int error;
@@ -331,7 +331,7 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c
* Given how simple this syscall is that apporach is more maintainable
* than the various conversion hacks.
*/
-asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u)
+COMPAT_SYSCALL_DEFINE2(ustat, unsigned, dev, struct compat_ustat __user *, u)
{
struct compat_ustat tmp;
struct kstatfs sbuf;
@@ -399,8 +399,8 @@ static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *u
}
#endif
-asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
- unsigned long arg)
+COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
+ compat_ulong_t, arg)
{
mm_segment_t old_fs;
struct flock f;
@@ -468,16 +468,15 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
return ret;
}
-asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,
- unsigned long arg)
+COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd,
+ compat_ulong_t, arg)
{
if ((cmd == F_GETLK64) || (cmd == F_SETLK64) || (cmd == F_SETLKW64))
return -EINVAL;
return compat_sys_fcntl64(fd, cmd, arg);
}
-asmlinkage long
-compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p)
+COMPAT_SYSCALL_DEFINE2(io_setup, unsigned, nr_reqs, u32 __user *, ctx32p)
{
long ret;
aio_context_t ctx64;
@@ -496,32 +495,24 @@ compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p)
return ret;
}
-asmlinkage long
-compat_sys_io_getevents(aio_context_t ctx_id,
- unsigned long min_nr,
- unsigned long nr,
- struct io_event __user *events,
- struct compat_timespec __user *timeout)
+COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id,
+ compat_long_t, min_nr,
+ compat_long_t, nr,
+ struct io_event __user *, events,
+ struct compat_timespec __user *, timeout)
{
- long ret;
struct timespec t;
struct timespec __user *ut = NULL;
- ret = -EFAULT;
- if (unlikely(!access_ok(VERIFY_WRITE, events,
- nr * sizeof(struct io_event))))
- goto out;
if (timeout) {
- if (get_compat_timespec(&t, timeout))
- goto out;
+ if (compat_get_timespec(&t, timeout))
+ return -EFAULT;
ut = compat_alloc_user_space(sizeof(*ut));
if (copy_to_user(ut, &t, sizeof(t)) )
- goto out;
+ return -EFAULT;
}
- ret = sys_io_getevents(ctx_id, min_nr, nr, events, ut);
-out:
- return ret;
+ return sys_io_getevents(ctx_id, min_nr, nr, events, ut);
}
/* A write operation does a read from user space and vice versa */
@@ -617,8 +608,8 @@ copy_iocb(long nr, u32 __user *ptr32, struct iocb __user * __user *ptr64)
#define MAX_AIO_SUBMITS (PAGE_SIZE/sizeof(struct iocb *))
-asmlinkage long
-compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb)
+COMPAT_SYSCALL_DEFINE3(io_submit, compat_aio_context_t, ctx_id,
+ int, nr, u32 __user *, iocb)
{
struct iocb __user * __user *iocb64;
long ret;
@@ -770,10 +761,10 @@ static int do_nfs4_super_data_conv(void *raw_data)
#define NCPFS_NAME "ncpfs"
#define NFS4_NAME "nfs4"
-asmlinkage long compat_sys_mount(const char __user * dev_name,
- const char __user * dir_name,
- const char __user * type, unsigned long flags,
- const void __user * data)
+COMPAT_SYSCALL_DEFINE5(mount, const char __user *, dev_name,
+ const char __user *, dir_name,
+ const char __user *, type, compat_ulong_t, flags,
+ const void __user *, data)
{
char *kernel_type;
unsigned long data_page;
@@ -869,8 +860,8 @@ efault:
return -EFAULT;
}
-asmlinkage long compat_sys_old_readdir(unsigned int fd,
- struct compat_old_linux_dirent __user *dirent, unsigned int count)
+COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
+ struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
{
int error;
struct fd f = fdget(fd);
@@ -948,8 +939,8 @@ efault:
return -EFAULT;
}
-asmlinkage long compat_sys_getdents(unsigned int fd,
- struct compat_linux_dirent __user *dirent, unsigned int count)
+COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
+ struct compat_linux_dirent __user *, dirent, unsigned int, count)
{
struct fd f;
struct compat_linux_dirent __user * lastdirent;
@@ -981,7 +972,7 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
return error;
}
-#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
+#ifdef __ARCH_WANT_COMPAT_SYS_GETDENTS64
struct compat_getdents_callback64 {
struct dir_context ctx;
@@ -1033,8 +1024,8 @@ efault:
return -EFAULT;
}
-asmlinkage long compat_sys_getdents64(unsigned int fd,
- struct linux_dirent64 __user * dirent, unsigned int count)
+COMPAT_SYSCALL_DEFINE3(getdents64, unsigned int, fd,
+ struct linux_dirent64 __user *, dirent, unsigned int, count)
{
struct fd f;
struct linux_dirent64 __user * lastdirent;
@@ -1066,7 +1057,7 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
fdput(f);
return error;
}
-#endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */
+#endif /* __ARCH_WANT_COMPAT_SYS_GETDENTS64 */
/*
* Exactly like fs/open.c:sys_open(), except that it doesn't set the
@@ -1287,9 +1278,9 @@ out_nofds:
return ret;
}
-asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
- compat_ulong_t __user *outp, compat_ulong_t __user *exp,
- struct compat_timeval __user *tvp)
+COMPAT_SYSCALL_DEFINE5(select, int, n, compat_ulong_t __user *, inp,
+ compat_ulong_t __user *, outp, compat_ulong_t __user *, exp,
+ struct compat_timeval __user *, tvp)
{
struct timespec end_time, *to = NULL;
struct compat_timeval tv;
@@ -1320,7 +1311,7 @@ struct compat_sel_arg_struct {
compat_uptr_t tvp;
};
-asmlinkage long compat_sys_old_select(struct compat_sel_arg_struct __user *arg)
+COMPAT_SYSCALL_DEFINE1(old_select, struct compat_sel_arg_struct __user *, arg)
{
struct compat_sel_arg_struct a;
@@ -1381,9 +1372,9 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp,
return ret;
}
-asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp,
- compat_ulong_t __user *outp, compat_ulong_t __user *exp,
- struct compat_timespec __user *tsp, void __user *sig)
+COMPAT_SYSCALL_DEFINE6(pselect6, int, n, compat_ulong_t __user *, inp,
+ compat_ulong_t __user *, outp, compat_ulong_t __user *, exp,
+ struct compat_timespec __user *, tsp, void __user *, sig)
{
compat_size_t sigsetsize = 0;
compat_uptr_t up = 0;
@@ -1400,9 +1391,9 @@ asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp,
sigsetsize);
}
-asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
- unsigned int nfds, struct compat_timespec __user *tsp,
- const compat_sigset_t __user *sigmask, compat_size_t sigsetsize)
+COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds,
+ unsigned int, nfds, struct compat_timespec __user *, tsp,
+ const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize)
{
compat_sigset_t ss32;
sigset_t ksigmask, sigsaved;
diff --git a/fs/compat_binfmt_elf.c b/fs/compat_binfmt_elf.c
index a81147e2e4ef..4d24d17bcfc1 100644
--- a/fs/compat_binfmt_elf.c
+++ b/fs/compat_binfmt_elf.c
@@ -88,6 +88,11 @@ static void cputime_to_compat_timeval(const cputime_t cputime,
#define ELF_HWCAP COMPAT_ELF_HWCAP
#endif
+#ifdef COMPAT_ELF_HWCAP2
+#undef ELF_HWCAP2
+#define ELF_HWCAP2 COMPAT_ELF_HWCAP2
+#endif
+
#ifdef COMPAT_ARCH_DLINFO
#undef ARCH_DLINFO
#define ARCH_DLINFO COMPAT_ARCH_DLINFO
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 3881610b6438..e82289047272 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1538,9 +1538,10 @@ static int compat_ioctl_check_table(unsigned int xcmd)
return ioctl_pointer[i] == xcmd;
}
-asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
- unsigned long arg)
+COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
+ compat_ulong_t, arg32)
{
+ unsigned long arg = arg32;
struct fd f = fdget(fd);
int error = -EBADF;
if (!f.file)
diff --git a/fs/dcache.c b/fs/dcache.c
index 265e0ce9769c..ca02c13a84aa 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2833,9 +2833,9 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
u32 dlen = ACCESS_ONCE(name->len);
char *p;
- if (*buflen < dlen + 1)
- return -ENAMETOOLONG;
*buflen -= dlen + 1;
+ if (*buflen < 0)
+ return -ENAMETOOLONG;
p = *buffer -= dlen + 1;
*p++ = '/';
while (dlen--) {
diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c
index 8dd524f32284..cdb2971192a5 100644
--- a/fs/efivarfs/file.c
+++ b/fs/efivarfs/file.c
@@ -21,7 +21,7 @@ static ssize_t efivarfs_file_write(struct file *file,
u32 attributes;
struct inode *inode = file->f_mapping->host;
unsigned long datasize = count - sizeof(attributes);
- ssize_t bytes = 0;
+ ssize_t bytes;
bool set = false;
if (count < sizeof(attributes))
@@ -33,14 +33,9 @@ static ssize_t efivarfs_file_write(struct file *file,
if (attributes & ~(EFI_VARIABLE_MASK))
return -EINVAL;
- data = kmalloc(datasize, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) {
- bytes = -EFAULT;
- goto out;
- }
+ data = memdup_user(userbuf + sizeof(attributes), datasize);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
bytes = efivar_entry_set_get_size(var, attributes, &datasize,
data, &set);
diff --git a/fs/exec.c b/fs/exec.c
index 3d78fccdd723..4f59402fdda5 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1619,9 +1619,9 @@ SYSCALL_DEFINE3(execve,
return do_execve(getname(filename), argv, envp);
}
#ifdef CONFIG_COMPAT
-asmlinkage long compat_sys_execve(const char __user * filename,
- const compat_uptr_t __user * argv,
- const compat_uptr_t __user * envp)
+COMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename,
+ const compat_uptr_t __user *, argv,
+ const compat_uptr_t __user *, envp)
{
return compat_do_execve(getname(filename), argv, envp);
}
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index ece55565b9cd..d3a534fdc5ff 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -771,6 +771,8 @@ do { \
if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \
(einode)->xtime.tv_sec = \
(signed)le32_to_cpu((raw_inode)->xtime); \
+ else \
+ (einode)->xtime.tv_sec = 0; \
if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \
ext4_decode_extra_time(&(einode)->xtime, \
raw_inode->xtime ## _extra); \
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 10cff4736b11..74bc2d549c58 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3906,6 +3906,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
} else
err = ret;
map->m_flags |= EXT4_MAP_MAPPED;
+ map->m_pblk = newblock;
if (allocated > map->m_len)
allocated = map->m_len;
map->m_len = allocated;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 6e39895a91b8..24bfd7ff3049 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -38,6 +38,7 @@
#include <linux/slab.h>
#include <linux/ratelimit.h>
#include <linux/aio.h>
+#include <linux/bitops.h>
#include "ext4_jbd2.h"
#include "xattr.h"
@@ -3921,18 +3922,20 @@ int ext4_get_inode_loc(struct inode *inode, struct ext4_iloc *iloc)
void ext4_set_inode_flags(struct inode *inode)
{
unsigned int flags = EXT4_I(inode)->i_flags;
+ unsigned int new_fl = 0;
- inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
if (flags & EXT4_SYNC_FL)
- inode->i_flags |= S_SYNC;
+ new_fl |= S_SYNC;
if (flags & EXT4_APPEND_FL)
- inode->i_flags |= S_APPEND;
+ new_fl |= S_APPEND;
if (flags & EXT4_IMMUTABLE_FL)
- inode->i_flags |= S_IMMUTABLE;
+ new_fl |= S_IMMUTABLE;
if (flags & EXT4_NOATIME_FL)
- inode->i_flags |= S_NOATIME;
+ new_fl |= S_NOATIME;
if (flags & EXT4_DIRSYNC_FL)
- inode->i_flags |= S_DIRSYNC;
+ new_fl |= S_DIRSYNC;
+ set_mask_bits(&inode->i_flags,
+ S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC, new_fl);
}
/* Propagate flags from i_flags to EXT4_I(inode)->i_flags */
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 6bea80614d77..a2a837f00407 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -140,7 +140,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2);
if (IS_ERR(handle)) {
err = -EINVAL;
- goto swap_boot_out;
+ goto journal_err_out;
}
/* Protect extent tree against block allocations via delalloc */
@@ -198,6 +198,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
ext4_double_up_write_data_sem(inode, inode_bl);
+journal_err_out:
ext4_inode_resume_unlocked_dio(inode);
ext4_inode_resume_unlocked_dio(inode_bl);
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index c5adbb318a90..f3b84cd9de56 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -243,6 +243,7 @@ static int ext4_alloc_group_tables(struct super_block *sb,
ext4_group_t group;
ext4_group_t last_group;
unsigned overhead;
+ __u16 uninit_mask = (flexbg_size > 1) ? ~EXT4_BG_BLOCK_UNINIT : ~0;
BUG_ON(flex_gd->count == 0 || group_data == NULL);
@@ -266,7 +267,7 @@ next_group:
src_group++;
for (; src_group <= last_group; src_group++) {
overhead = ext4_group_overhead_blocks(sb, src_group);
- if (overhead != 0)
+ if (overhead == 0)
last_blk += group_data[src_group - group].blocks_count;
else
break;
@@ -280,8 +281,7 @@ next_group:
group = ext4_get_group_number(sb, start_blk - 1);
group -= group_data[0].group;
group_data[group].free_blocks_count--;
- if (flexbg_size > 1)
- flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT;
+ flex_gd->bg_flags[group] &= uninit_mask;
}
/* Allocate inode bitmaps */
@@ -292,22 +292,30 @@ next_group:
group = ext4_get_group_number(sb, start_blk - 1);
group -= group_data[0].group;
group_data[group].free_blocks_count--;
- if (flexbg_size > 1)
- flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT;
+ flex_gd->bg_flags[group] &= uninit_mask;
}
/* Allocate inode tables */
for (; it_index < flex_gd->count; it_index++) {
- if (start_blk + EXT4_SB(sb)->s_itb_per_group > last_blk)
+ unsigned int itb = EXT4_SB(sb)->s_itb_per_group;
+ ext4_fsblk_t next_group_start;
+
+ if (start_blk + itb > last_blk)
goto next_group;
group_data[it_index].inode_table = start_blk;
- group = ext4_get_group_number(sb, start_blk - 1);
+ group = ext4_get_group_number(sb, start_blk);
+ next_group_start = ext4_group_first_block_no(sb, group + 1);
group -= group_data[0].group;
- group_data[group].free_blocks_count -=
- EXT4_SB(sb)->s_itb_per_group;
- if (flexbg_size > 1)
- flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT;
+ if (start_blk + itb > next_group_start) {
+ flex_gd->bg_flags[group + 1] &= uninit_mask;
+ overhead = start_blk + itb - next_group_start;
+ group_data[group + 1].free_blocks_count -= overhead;
+ itb -= overhead;
+ }
+
+ group_data[group].free_blocks_count -= itb;
+ flex_gd->bg_flags[group] &= uninit_mask;
start_blk += EXT4_SB(sb)->s_itb_per_group;
}
@@ -401,7 +409,7 @@ static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle,
start = ext4_group_first_block_no(sb, group);
group -= flex_gd->groups[0].group;
- count2 = sb->s_blocksize * 8 - (block - start);
+ count2 = EXT4_BLOCKS_PER_GROUP(sb) - (block - start);
if (count2 > count)
count2 = count;
@@ -620,7 +628,7 @@ handle_ib:
if (err)
goto out;
count = group_table_count[j];
- start = group_data[i].block_bitmap;
+ start = (&group_data[i].block_bitmap)[j];
block = start;
}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 1f7784de05b6..710fed2377d4 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3695,16 +3695,22 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
for (i = 0; i < 4; i++)
sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
sbi->s_def_hash_version = es->s_def_hash_version;
- i = le32_to_cpu(es->s_flags);
- if (i & EXT2_FLAGS_UNSIGNED_HASH)
- sbi->s_hash_unsigned = 3;
- else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) {
+ if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
+ i = le32_to_cpu(es->s_flags);
+ if (i & EXT2_FLAGS_UNSIGNED_HASH)
+ sbi->s_hash_unsigned = 3;
+ else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) {
#ifdef __CHAR_UNSIGNED__
- es->s_flags |= cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH);
- sbi->s_hash_unsigned = 3;
+ if (!(sb->s_flags & MS_RDONLY))
+ es->s_flags |=
+ cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH);
+ sbi->s_hash_unsigned = 3;
#else
- es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);
+ if (!(sb->s_flags & MS_RDONLY))
+ es->s_flags |=
+ cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);
#endif
+ }
}
/* Handle clustersize */
diff --git a/fs/file.c b/fs/file.c
index db25c2bdfe46..b61293badfb1 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -497,7 +497,7 @@ repeat:
error = fd;
#if 1
/* Sanity check */
- if (rcu_dereference_raw(fdt->fd[fd]) != NULL) {
+ if (rcu_access_pointer(fdt->fd[fd]) != NULL) {
printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd);
rcu_assign_pointer(fdt->fd[fd], NULL);
}
@@ -683,35 +683,54 @@ EXPORT_SYMBOL(fget_raw);
* The fput_needed flag returned by fget_light should be passed to the
* corresponding fput_light.
*/
-struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed)
+static unsigned long __fget_light(unsigned int fd, fmode_t mask)
{
struct files_struct *files = current->files;
struct file *file;
- *fput_needed = 0;
if (atomic_read(&files->count) == 1) {
file = __fcheck_files(files, fd);
- if (file && (file->f_mode & mask))
- file = NULL;
+ if (!file || unlikely(file->f_mode & mask))
+ return 0;
+ return (unsigned long)file;
} else {
file = __fget(fd, mask);
- if (file)
- *fput_needed = 1;
+ if (!file)
+ return 0;
+ return FDPUT_FPUT | (unsigned long)file;
}
-
- return file;
}
-struct file *fget_light(unsigned int fd, int *fput_needed)
+unsigned long __fdget(unsigned int fd)
{
- return __fget_light(fd, FMODE_PATH, fput_needed);
+ return __fget_light(fd, FMODE_PATH);
}
-EXPORT_SYMBOL(fget_light);
+EXPORT_SYMBOL(__fdget);
-struct file *fget_raw_light(unsigned int fd, int *fput_needed)
+unsigned long __fdget_raw(unsigned int fd)
{
- return __fget_light(fd, 0, fput_needed);
+ return __fget_light(fd, 0);
}
+unsigned long __fdget_pos(unsigned int fd)
+{
+ unsigned long v = __fdget(fd);
+ struct file *file = (struct file *)(v & ~3);
+
+ if (file && (file->f_mode & FMODE_ATOMIC_POS)) {
+ if (file_count(file) > 1) {
+ v |= FDPUT_POS_UNLOCK;
+ mutex_lock(&file->f_pos_lock);
+ }
+ }
+ return v;
+}
+
+/*
+ * We only lock f_pos if we have threads or if the file might be
+ * shared with another process. In both cases we'll have an elevated
+ * file count (done either by fdget() or by fork()).
+ */
+
void set_close_on_exec(unsigned int fd, int flag)
{
struct files_struct *files = current->files;
diff --git a/fs/file_table.c b/fs/file_table.c
index 5fff9030be34..5b24008ea4f6 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -135,6 +135,7 @@ struct file *get_empty_filp(void)
atomic_long_set(&f->f_count, 1);
rwlock_init(&f->f_owner.lock);
spin_lock_init(&f->f_lock);
+ mutex_init(&f->f_pos_lock);
eventpoll_init_file(f);
/* f->f_version: 0 */
return f;
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index e0259a163f98..d754e3cf99a8 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -40,18 +40,13 @@
struct wb_writeback_work {
long nr_pages;
struct super_block *sb;
- /*
- * Write only inodes dirtied before this time. Don't forget to set
- * older_than_this_is_set when you set this.
- */
- unsigned long older_than_this;
+ unsigned long *older_than_this;
enum writeback_sync_modes sync_mode;
unsigned int tagged_writepages:1;
unsigned int for_kupdate:1;
unsigned int range_cyclic:1;
unsigned int for_background:1;
unsigned int for_sync:1; /* sync(2) WB_SYNC_ALL writeback */
- unsigned int older_than_this_is_set:1;
enum wb_reason reason; /* why was writeback initiated? */
struct list_head list; /* pending work list */
@@ -252,10 +247,10 @@ static int move_expired_inodes(struct list_head *delaying_queue,
int do_sb_sort = 0;
int moved = 0;
- WARN_ON_ONCE(!work->older_than_this_is_set);
while (!list_empty(delaying_queue)) {
inode = wb_inode(delaying_queue->prev);
- if (inode_dirtied_after(inode, work->older_than_this))
+ if (work->older_than_this &&
+ inode_dirtied_after(inode, *work->older_than_this))
break;
list_move(&inode->i_wb_list, &tmp);
moved++;
@@ -742,8 +737,6 @@ static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
.sync_mode = WB_SYNC_NONE,
.range_cyclic = 1,
.reason = reason,
- .older_than_this = jiffies,
- .older_than_this_is_set = 1,
};
spin_lock(&wb->list_lock);
@@ -802,13 +795,12 @@ static long wb_writeback(struct bdi_writeback *wb,
{
unsigned long wb_start = jiffies;
long nr_pages = work->nr_pages;
+ unsigned long oldest_jif;
struct inode *inode;
long progress;
- if (!work->older_than_this_is_set) {
- work->older_than_this = jiffies;
- work->older_than_this_is_set = 1;
- }
+ oldest_jif = jiffies;
+ work->older_than_this = &oldest_jif;
spin_lock(&wb->list_lock);
for (;;) {
@@ -842,10 +834,10 @@ static long wb_writeback(struct bdi_writeback *wb,
* safe.
*/
if (work->for_kupdate) {
- work->older_than_this = jiffies -
+ oldest_jif = jiffies -
msecs_to_jiffies(dirty_expire_interval * 10);
} else if (work->for_background)
- work->older_than_this = jiffies;
+ oldest_jif = jiffies;
trace_writeback_start(wb->bdi, work);
if (list_empty(&wb->b_io))
@@ -1357,21 +1349,18 @@ EXPORT_SYMBOL(try_to_writeback_inodes_sb);
/**
* sync_inodes_sb - sync sb inode pages
- * @sb: the superblock
- * @older_than_this: timestamp
+ * @sb: the superblock
*
* This function writes and waits on any dirty inode belonging to this
- * superblock that has been dirtied before given timestamp.
+ * super_block.
*/
-void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this)
+void sync_inodes_sb(struct super_block *sb)
{
DECLARE_COMPLETION_ONSTACK(done);
struct wb_writeback_work work = {
.sb = sb,
.sync_mode = WB_SYNC_ALL,
.nr_pages = LONG_MAX,
- .older_than_this = older_than_this,
- .older_than_this_is_set = 1,
.range_cyclic = 0,
.done = &done,
.reason = WB_REASON_SYNC,
diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c
index e1959efad64f..b5ebc2d7d80d 100644
--- a/fs/fscache/object-list.c
+++ b/fs/fscache/object-list.c
@@ -50,6 +50,8 @@ void fscache_objlist_add(struct fscache_object *obj)
struct fscache_object *xobj;
struct rb_node **p = &fscache_object_list.rb_node, *parent = NULL;
+ ASSERT(RB_EMPTY_NODE(&obj->objlist_link));
+
write_lock(&fscache_object_list_lock);
while (*p) {
@@ -75,6 +77,9 @@ void fscache_objlist_add(struct fscache_object *obj)
*/
void fscache_objlist_remove(struct fscache_object *obj)
{
+ if (RB_EMPTY_NODE(&obj->objlist_link))
+ return;
+
write_lock(&fscache_object_list_lock);
BUG_ON(RB_EMPTY_ROOT(&fscache_object_list));
diff --git a/fs/fscache/object.c b/fs/fscache/object.c
index 53d35c504240..d3b4539f1651 100644
--- a/fs/fscache/object.c
+++ b/fs/fscache/object.c
@@ -314,6 +314,9 @@ void fscache_object_init(struct fscache_object *object,
object->cache = cache;
object->cookie = cookie;
object->parent = NULL;
+#ifdef CONFIG_FSCACHE_OBJECT_LIST
+ RB_CLEAR_NODE(&object->objlist_link);
+#endif
object->oob_event_mask = 0;
for (t = object->oob_table; t->events; t++)
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
index 968ce411db53..32602c667b4a 100644
--- a/fs/hfsplus/catalog.c
+++ b/fs/hfsplus/catalog.c
@@ -103,6 +103,8 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry,
folder = &entry->folder;
memset(folder, 0, sizeof(*folder));
folder->type = cpu_to_be16(HFSPLUS_FOLDER);
+ if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags))
+ folder->flags |= cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT);
folder->id = cpu_to_be32(inode->i_ino);
HFSPLUS_I(inode)->create_date =
folder->create_date =
@@ -203,6 +205,36 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
return hfs_brec_find(fd, hfs_find_rec_by_key);
}
+static void hfsplus_subfolders_inc(struct inode *dir)
+{
+ struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
+
+ if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
+ /*
+ * Increment subfolder count. Note, the value is only meaningful
+ * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set.
+ */
+ HFSPLUS_I(dir)->subfolders++;
+ }
+}
+
+static void hfsplus_subfolders_dec(struct inode *dir)
+{
+ struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
+
+ if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
+ /*
+ * Decrement subfolder count. Note, the value is only meaningful
+ * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set.
+ *
+ * Check for zero. Some subfolders may have been created
+ * by an implementation ignorant of this counter.
+ */
+ if (HFSPLUS_I(dir)->subfolders)
+ HFSPLUS_I(dir)->subfolders--;
+ }
+}
+
int hfsplus_create_cat(u32 cnid, struct inode *dir,
struct qstr *str, struct inode *inode)
{
@@ -247,6 +279,8 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir,
goto err1;
dir->i_size++;
+ if (S_ISDIR(inode->i_mode))
+ hfsplus_subfolders_inc(dir);
dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
@@ -336,6 +370,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
goto out;
dir->i_size--;
+ if (type == HFSPLUS_FOLDER)
+ hfsplus_subfolders_dec(dir);
dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
@@ -380,6 +416,7 @@ int hfsplus_rename_cat(u32 cnid,
hfs_bnode_read(src_fd.bnode, &entry, src_fd.entryoffset,
src_fd.entrylength);
+ type = be16_to_cpu(entry.type);
/* create new dir entry with the data from the old entry */
hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name);
@@ -394,6 +431,8 @@ int hfsplus_rename_cat(u32 cnid,
if (err)
goto out;
dst_dir->i_size++;
+ if (type == HFSPLUS_FOLDER)
+ hfsplus_subfolders_inc(dst_dir);
dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC;
/* finally remove the old entry */
@@ -405,6 +444,8 @@ int hfsplus_rename_cat(u32 cnid,
if (err)
goto out;
src_dir->i_size--;
+ if (type == HFSPLUS_FOLDER)
+ hfsplus_subfolders_dec(src_dir);
src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC;
/* remove old thread entry */
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 08846425b67f..62d571eb69ba 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -242,6 +242,7 @@ struct hfsplus_inode_info {
*/
sector_t fs_blocks;
u8 userflags; /* BSD user file flags */
+ u32 subfolders; /* Subfolder count (HFSX only) */
struct list_head open_dir_list;
loff_t phys_size;
diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h
index 8ffb3a8ffe75..5a126828d85e 100644
--- a/fs/hfsplus/hfsplus_raw.h
+++ b/fs/hfsplus/hfsplus_raw.h
@@ -261,7 +261,7 @@ struct hfsplus_cat_folder {
struct DInfo user_info;
struct DXInfo finder_info;
__be32 text_encoding;
- u32 reserved;
+ __be32 subfolders; /* Subfolder count in HFSX. Reserved in HFS+. */
} __packed;
/* HFS file info (stolen from hfs.h) */
@@ -301,11 +301,13 @@ struct hfsplus_cat_file {
struct hfsplus_fork_raw rsrc_fork;
} __packed;
-/* File attribute bits */
+/* File and folder flag bits */
#define HFSPLUS_FILE_LOCKED 0x0001
#define HFSPLUS_FILE_THREAD_EXISTS 0x0002
#define HFSPLUS_XATTR_EXISTS 0x0004
#define HFSPLUS_ACL_EXISTS 0x0008
+#define HFSPLUS_HAS_FOLDER_COUNT 0x0010 /* Folder has subfolder count
+ * (HFSX only) */
/* HFS+ catalog thread (part of a cat_entry) */
struct hfsplus_cat_thread {
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index fa929f325f87..a4f45bd88a63 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -375,6 +375,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
hip->extent_state = 0;
hip->flags = 0;
hip->userflags = 0;
+ hip->subfolders = 0;
memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
hip->alloc_blocks = 0;
@@ -494,6 +495,10 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date);
HFSPLUS_I(inode)->create_date = folder->create_date;
HFSPLUS_I(inode)->fs_blocks = 0;
+ if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
+ HFSPLUS_I(inode)->subfolders =
+ be32_to_cpu(folder->subfolders);
+ }
inode->i_op = &hfsplus_dir_inode_operations;
inode->i_fop = &hfsplus_dir_operations;
} else if (type == HFSPLUS_FILE) {
@@ -566,6 +571,10 @@ int hfsplus_cat_write_inode(struct inode *inode)
folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
folder->valence = cpu_to_be32(inode->i_size - 2);
+ if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
+ folder->subfolders =
+ cpu_to_be32(HFSPLUS_I(inode)->subfolders);
+ }
hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
sizeof(struct hfsplus_cat_folder));
} else if (HFSPLUS_IS_RSRC(inode)) {
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index 968eab5bc1f5..68537e8b7a09 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -75,7 +75,7 @@ int hfsplus_parse_options_remount(char *input, int *force)
int token;
if (!input)
- return 0;
+ return 1;
while ((p = strsep(&input, ",")) != NULL) {
if (!*p)
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index 8360674c85bc..60bb365f54a5 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -514,11 +514,13 @@ int jbd2_journal_start_reserved(handle_t *handle, unsigned int type,
* similarly constrained call sites
*/
ret = start_this_handle(journal, handle, GFP_NOFS);
- if (ret < 0)
+ if (ret < 0) {
jbd2_journal_free_reserved(handle);
+ return ret;
+ }
handle->h_type = type;
handle->h_line_no = line_no;
- return ret;
+ return 0;
}
EXPORT_SYMBOL(jbd2_journal_start_reserved);
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index e973b85d6afd..5a8ea16eedbc 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -86,6 +86,8 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
rc = posix_acl_equiv_mode(acl, &inode->i_mode);
if (rc < 0)
return rc;
+ inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
if (rc == 0)
acl = NULL;
break;
diff --git a/fs/kernfs/Kconfig b/fs/kernfs/Kconfig
new file mode 100644
index 000000000000..397b5f7a7a16
--- /dev/null
+++ b/fs/kernfs/Kconfig
@@ -0,0 +1,7 @@
+#
+# KERNFS should be selected by its users
+#
+
+config KERNFS
+ bool
+ default n
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index bd6e18be6e1a..0bd05ab26003 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -8,6 +8,7 @@
* This file is released under the GPLv2.
*/
+#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/idr.h>
@@ -18,9 +19,161 @@
#include "kernfs-internal.h"
DEFINE_MUTEX(kernfs_mutex);
+static DEFINE_SPINLOCK(kernfs_rename_lock); /* kn->parent and ->name */
+static char kernfs_pr_cont_buf[PATH_MAX]; /* protected by rename_lock */
#define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb)
+static bool kernfs_active(struct kernfs_node *kn)
+{
+ lockdep_assert_held(&kernfs_mutex);
+ return atomic_read(&kn->active) >= 0;
+}
+
+static bool kernfs_lockdep(struct kernfs_node *kn)
+{
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ return kn->flags & KERNFS_LOCKDEP;
+#else
+ return false;
+#endif
+}
+
+static int kernfs_name_locked(struct kernfs_node *kn, char *buf, size_t buflen)
+{
+ return strlcpy(buf, kn->parent ? kn->name : "/", buflen);
+}
+
+static char * __must_check kernfs_path_locked(struct kernfs_node *kn, char *buf,
+ size_t buflen)
+{
+ char *p = buf + buflen;
+ int len;
+
+ *--p = '\0';
+
+ do {
+ len = strlen(kn->name);
+ if (p - buf < len + 1) {
+ buf[0] = '\0';
+ p = NULL;
+ break;
+ }
+ p -= len;
+ memcpy(p, kn->name, len);
+ *--p = '/';
+ kn = kn->parent;
+ } while (kn && kn->parent);
+
+ return p;
+}
+
+/**
+ * kernfs_name - obtain the name of a given node
+ * @kn: kernfs_node of interest
+ * @buf: buffer to copy @kn's name into
+ * @buflen: size of @buf
+ *
+ * Copies the name of @kn into @buf of @buflen bytes. The behavior is
+ * similar to strlcpy(). It returns the length of @kn's name and if @buf
+ * isn't long enough, it's filled upto @buflen-1 and nul terminated.
+ *
+ * This function can be called from any context.
+ */
+int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&kernfs_rename_lock, flags);
+ ret = kernfs_name_locked(kn, buf, buflen);
+ spin_unlock_irqrestore(&kernfs_rename_lock, flags);
+ return ret;
+}
+
+/**
+ * kernfs_path - build full path of a given node
+ * @kn: kernfs_node of interest
+ * @buf: buffer to copy @kn's name into
+ * @buflen: size of @buf
+ *
+ * Builds and returns the full path of @kn in @buf of @buflen bytes. The
+ * path is built from the end of @buf so the returned pointer usually
+ * doesn't match @buf. If @buf isn't long enough, @buf is nul terminated
+ * and %NULL is returned.
+ */
+char *kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen)
+{
+ unsigned long flags;
+ char *p;
+
+ spin_lock_irqsave(&kernfs_rename_lock, flags);
+ p = kernfs_path_locked(kn, buf, buflen);
+ spin_unlock_irqrestore(&kernfs_rename_lock, flags);
+ return p;
+}
+
+/**
+ * pr_cont_kernfs_name - pr_cont name of a kernfs_node
+ * @kn: kernfs_node of interest
+ *
+ * This function can be called from any context.
+ */
+void pr_cont_kernfs_name(struct kernfs_node *kn)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&kernfs_rename_lock, flags);
+
+ kernfs_name_locked(kn, kernfs_pr_cont_buf, sizeof(kernfs_pr_cont_buf));
+ pr_cont("%s", kernfs_pr_cont_buf);
+
+ spin_unlock_irqrestore(&kernfs_rename_lock, flags);
+}
+
+/**
+ * pr_cont_kernfs_path - pr_cont path of a kernfs_node
+ * @kn: kernfs_node of interest
+ *
+ * This function can be called from any context.
+ */
+void pr_cont_kernfs_path(struct kernfs_node *kn)
+{
+ unsigned long flags;
+ char *p;
+
+ spin_lock_irqsave(&kernfs_rename_lock, flags);
+
+ p = kernfs_path_locked(kn, kernfs_pr_cont_buf,
+ sizeof(kernfs_pr_cont_buf));
+ if (p)
+ pr_cont("%s", p);
+ else
+ pr_cont("<name too long>");
+
+ spin_unlock_irqrestore(&kernfs_rename_lock, flags);
+}
+
+/**
+ * kernfs_get_parent - determine the parent node and pin it
+ * @kn: kernfs_node of interest
+ *
+ * Determines @kn's parent, pins and returns it. This function can be
+ * called from any context.
+ */
+struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn)
+{
+ struct kernfs_node *parent;
+ unsigned long flags;
+
+ spin_lock_irqsave(&kernfs_rename_lock, flags);
+ parent = kn->parent;
+ kernfs_get(parent);
+ spin_unlock_irqrestore(&kernfs_rename_lock, flags);
+
+ return parent;
+}
+
/**
* kernfs_name_hash
* @name: Null terminated string to hash
@@ -37,7 +190,7 @@ static unsigned int kernfs_name_hash(const char *name, const void *ns)
hash = (end_name_hash(hash) ^ hash_ptr((void *)ns, 31));
hash &= 0x7fffffffU;
/* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */
- if (hash < 1)
+ if (hash < 2)
hash += 2;
if (hash >= INT_MAX)
hash = INT_MAX - 1;
@@ -105,18 +258,24 @@ static int kernfs_link_sibling(struct kernfs_node *kn)
* kernfs_unlink_sibling - unlink kernfs_node from sibling rbtree
* @kn: kernfs_node of interest
*
- * Unlink @kn from its sibling rbtree which starts from
- * kn->parent->dir.children.
+ * Try to unlink @kn from its sibling rbtree which starts from
+ * kn->parent->dir.children. Returns %true if @kn was actually
+ * removed, %false if @kn wasn't on the rbtree.
*
* Locking:
* mutex_lock(kernfs_mutex)
*/
-static void kernfs_unlink_sibling(struct kernfs_node *kn)
+static bool kernfs_unlink_sibling(struct kernfs_node *kn)
{
+ if (RB_EMPTY_NODE(&kn->rb))
+ return false;
+
if (kernfs_type(kn) == KERNFS_DIR)
kn->parent->dir.subdirs--;
rb_erase(&kn->rb, &kn->parent->dir.children);
+ RB_CLEAR_NODE(&kn->rb);
+ return true;
}
/**
@@ -137,7 +296,7 @@ struct kernfs_node *kernfs_get_active(struct kernfs_node *kn)
if (!atomic_inc_unless_negative(&kn->active))
return NULL;
- if (kn->flags & KERNFS_LOCKDEP)
+ if (kernfs_lockdep(kn))
rwsem_acquire_read(&kn->dep_map, 0, 1, _RET_IP_);
return kn;
}
@@ -151,59 +310,57 @@ struct kernfs_node *kernfs_get_active(struct kernfs_node *kn)
*/
void kernfs_put_active(struct kernfs_node *kn)
{
+ struct kernfs_root *root = kernfs_root(kn);
int v;
if (unlikely(!kn))
return;
- if (kn->flags & KERNFS_LOCKDEP)
+ if (kernfs_lockdep(kn))
rwsem_release(&kn->dep_map, 1, _RET_IP_);
v = atomic_dec_return(&kn->active);
if (likely(v != KN_DEACTIVATED_BIAS))
return;
- /*
- * atomic_dec_return() is a mb(), we'll always see the updated
- * kn->u.completion.
- */
- complete(kn->u.completion);
+ wake_up_all(&root->deactivate_waitq);
}
/**
- * kernfs_deactivate - deactivate kernfs_node
- * @kn: kernfs_node to deactivate
+ * kernfs_drain - drain kernfs_node
+ * @kn: kernfs_node to drain
*
- * Deny new active references and drain existing ones.
+ * Drain existing usages and nuke all existing mmaps of @kn. Mutiple
+ * removers may invoke this function concurrently on @kn and all will
+ * return after draining is complete.
*/
-static void kernfs_deactivate(struct kernfs_node *kn)
+static void kernfs_drain(struct kernfs_node *kn)
+ __releases(&kernfs_mutex) __acquires(&kernfs_mutex)
{
- DECLARE_COMPLETION_ONSTACK(wait);
- int v;
+ struct kernfs_root *root = kernfs_root(kn);
- BUG_ON(!(kn->flags & KERNFS_REMOVED));
-
- if (!(kernfs_type(kn) & KERNFS_ACTIVE_REF))
- return;
+ lockdep_assert_held(&kernfs_mutex);
+ WARN_ON_ONCE(kernfs_active(kn));
- kn->u.completion = (void *)&wait;
+ mutex_unlock(&kernfs_mutex);
- if (kn->flags & KERNFS_LOCKDEP)
+ if (kernfs_lockdep(kn)) {
rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_);
- /* atomic_add_return() is a mb(), put_active() will always see
- * the updated kn->u.completion.
- */
- v = atomic_add_return(KN_DEACTIVATED_BIAS, &kn->active);
-
- if (v != KN_DEACTIVATED_BIAS) {
- if (kn->flags & KERNFS_LOCKDEP)
+ if (atomic_read(&kn->active) != KN_DEACTIVATED_BIAS)
lock_contended(&kn->dep_map, _RET_IP_);
- wait_for_completion(&wait);
}
- if (kn->flags & KERNFS_LOCKDEP) {
+ /* but everyone should wait for draining */
+ wait_event(root->deactivate_waitq,
+ atomic_read(&kn->active) == KN_DEACTIVATED_BIAS);
+
+ if (kernfs_lockdep(kn)) {
lock_acquired(&kn->dep_map, _RET_IP_);
rwsem_release(&kn->dep_map, 1, _RET_IP_);
}
+
+ kernfs_unmap_bin_file(kn);
+
+ mutex_lock(&kernfs_mutex);
}
/**
@@ -234,13 +391,15 @@ void kernfs_put(struct kernfs_node *kn)
return;
root = kernfs_root(kn);
repeat:
- /* Moving/renaming is always done while holding reference.
+ /*
+ * Moving/renaming is always done while holding reference.
* kn->parent won't change beneath us.
*/
parent = kn->parent;
- WARN(!(kn->flags & KERNFS_REMOVED), "kernfs: free using entry: %s/%s\n",
- parent ? parent->name : "", kn->name);
+ WARN_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS,
+ "kernfs_put: %s/%s: released with incorrect active_ref %d\n",
+ parent ? parent->name : "", kn->name, atomic_read(&kn->active));
if (kernfs_type(kn) == KERNFS_LINK)
kernfs_put(kn->symlink.target_kn);
@@ -282,8 +441,8 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
kn = dentry->d_fsdata;
mutex_lock(&kernfs_mutex);
- /* The kernfs node has been deleted */
- if (kn->flags & KERNFS_REMOVED)
+ /* The kernfs node has been deactivated */
+ if (!kernfs_active(kn))
goto out_bad;
/* The kernfs node has been moved? */
@@ -328,6 +487,24 @@ const struct dentry_operations kernfs_dops = {
.d_release = kernfs_dop_release,
};
+/**
+ * kernfs_node_from_dentry - determine kernfs_node associated with a dentry
+ * @dentry: the dentry in question
+ *
+ * Return the kernfs_node associated with @dentry. If @dentry is not a
+ * kernfs one, %NULL is returned.
+ *
+ * While the returned kernfs_node will stay accessible as long as @dentry
+ * is accessible, the returned node can be in any state and the caller is
+ * fully responsible for determining what's accessible.
+ */
+struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry)
+{
+ if (dentry->d_sb->s_op == &kernfs_sops)
+ return dentry->d_fsdata;
+ return NULL;
+}
+
static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
const char *name, umode_t mode,
unsigned flags)
@@ -352,11 +529,12 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
kn->ino = ret;
atomic_set(&kn->count, 1);
- atomic_set(&kn->active, 0);
+ atomic_set(&kn->active, KN_DEACTIVATED_BIAS);
+ RB_CLEAR_NODE(&kn->rb);
kn->name = name;
kn->mode = mode;
- kn->flags = flags | KERNFS_REMOVED;
+ kn->flags = flags;
return kn;
@@ -382,69 +560,44 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
}
/**
- * kernfs_addrm_start - prepare for kernfs_node add/remove
- * @acxt: pointer to kernfs_addrm_cxt to be used
- *
- * This function is called when the caller is about to add or remove
- * kernfs_node. This function acquires kernfs_mutex. @acxt is used
- * to keep and pass context to other addrm functions.
- *
- * LOCKING:
- * Kernel thread context (may sleep). kernfs_mutex is locked on
- * return.
- */
-void kernfs_addrm_start(struct kernfs_addrm_cxt *acxt)
- __acquires(kernfs_mutex)
-{
- memset(acxt, 0, sizeof(*acxt));
-
- mutex_lock(&kernfs_mutex);
-}
-
-/**
* kernfs_add_one - add kernfs_node to parent without warning
- * @acxt: addrm context to use
* @kn: kernfs_node to be added
*
* The caller must already have initialized @kn->parent. This
* function increments nlink of the parent's inode if @kn is a
* directory and link into the children list of the parent.
*
- * This function should be called between calls to
- * kernfs_addrm_start() and kernfs_addrm_finish() and should be passed
- * the same @acxt as passed to kernfs_addrm_start().
- *
- * LOCKING:
- * Determined by kernfs_addrm_start().
- *
* RETURNS:
* 0 on success, -EEXIST if entry with the given name already
* exists.
*/
-int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn)
+int kernfs_add_one(struct kernfs_node *kn)
{
struct kernfs_node *parent = kn->parent;
- bool has_ns = kernfs_ns_enabled(parent);
struct kernfs_iattrs *ps_iattr;
+ bool has_ns;
int ret;
- if (has_ns != (bool)kn->ns) {
- WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n",
- has_ns ? "required" : "invalid", parent->name, kn->name);
- return -EINVAL;
- }
+ mutex_lock(&kernfs_mutex);
+
+ ret = -EINVAL;
+ has_ns = kernfs_ns_enabled(parent);
+ if (WARN(has_ns != (bool)kn->ns, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n",
+ has_ns ? "required" : "invalid", parent->name, kn->name))
+ goto out_unlock;
if (kernfs_type(parent) != KERNFS_DIR)
- return -EINVAL;
+ goto out_unlock;
- if (parent->flags & KERNFS_REMOVED)
- return -ENOENT;
+ ret = -ENOENT;
+ if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent))
+ goto out_unlock;
kn->hash = kernfs_name_hash(kn->name, kn->ns);
ret = kernfs_link_sibling(kn);
if (ret)
- return ret;
+ goto out_unlock;
/* Update timestamps on the parent */
ps_iattr = parent->iattr;
@@ -453,82 +606,22 @@ int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn)
ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME;
}
- /* Mark the entry added into directory tree */
- kn->flags &= ~KERNFS_REMOVED;
-
- return 0;
-}
-
-/**
- * kernfs_remove_one - remove kernfs_node from parent
- * @acxt: addrm context to use
- * @kn: kernfs_node to be removed
- *
- * Mark @kn removed and drop nlink of parent inode if @kn is a
- * directory. @kn is unlinked from the children list.
- *
- * This function should be called between calls to
- * kernfs_addrm_start() and kernfs_addrm_finish() and should be
- * passed the same @acxt as passed to kernfs_addrm_start().
- *
- * LOCKING:
- * Determined by kernfs_addrm_start().
- */
-static void kernfs_remove_one(struct kernfs_addrm_cxt *acxt,
- struct kernfs_node *kn)
-{
- struct kernfs_iattrs *ps_iattr;
+ mutex_unlock(&kernfs_mutex);
/*
- * Removal can be called multiple times on the same node. Only the
- * first invocation is effective and puts the base ref.
+ * Activate the new node unless CREATE_DEACTIVATED is requested.
+ * If not activated here, the kernfs user is responsible for
+ * activating the node with kernfs_activate(). A node which hasn't
+ * been activated is not visible to userland and its removal won't
+ * trigger deactivation.
*/
- if (kn->flags & KERNFS_REMOVED)
- return;
-
- if (kn->parent) {
- kernfs_unlink_sibling(kn);
-
- /* Update timestamps on the parent */
- ps_iattr = kn->parent->iattr;
- if (ps_iattr) {
- ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME;
- ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME;
- }
- }
-
- kn->flags |= KERNFS_REMOVED;
- kn->u.removed_list = acxt->removed;
- acxt->removed = kn;
-}
+ if (!(kernfs_root(kn)->flags & KERNFS_ROOT_CREATE_DEACTIVATED))
+ kernfs_activate(kn);
+ return 0;
-/**
- * kernfs_addrm_finish - finish up kernfs_node add/remove
- * @acxt: addrm context to finish up
- *
- * Finish up kernfs_node add/remove. Resources acquired by
- * kernfs_addrm_start() are released and removed kernfs_nodes are
- * cleaned up.
- *
- * LOCKING:
- * kernfs_mutex is released.
- */
-void kernfs_addrm_finish(struct kernfs_addrm_cxt *acxt)
- __releases(kernfs_mutex)
-{
- /* release resources acquired by kernfs_addrm_start() */
+out_unlock:
mutex_unlock(&kernfs_mutex);
-
- /* kill removed kernfs_nodes */
- while (acxt->removed) {
- struct kernfs_node *kn = acxt->removed;
-
- acxt->removed = kn->u.removed_list;
-
- kernfs_deactivate(kn);
- kernfs_unmap_bin_file(kn);
- kernfs_put(kn);
- }
+ return ret;
}
/**
@@ -599,13 +692,15 @@ EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns);
/**
* kernfs_create_root - create a new kernfs hierarchy
- * @kdops: optional directory syscall operations for the hierarchy
+ * @scops: optional syscall operations for the hierarchy
+ * @flags: KERNFS_ROOT_* flags
* @priv: opaque data associated with the new directory
*
* Returns the root of the new hierarchy on success, ERR_PTR() value on
* failure.
*/
-struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv)
+struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
+ unsigned int flags, void *priv)
{
struct kernfs_root *root;
struct kernfs_node *kn;
@@ -624,12 +719,16 @@ struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv)
return ERR_PTR(-ENOMEM);
}
- kn->flags &= ~KERNFS_REMOVED;
kn->priv = priv;
kn->dir.root = root;
- root->dir_ops = kdops;
+ root->syscall_ops = scops;
+ root->flags = flags;
root->kn = kn;
+ init_waitqueue_head(&root->deactivate_waitq);
+
+ if (!(root->flags & KERNFS_ROOT_CREATE_DEACTIVATED))
+ kernfs_activate(kn);
return root;
}
@@ -660,7 +759,6 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
const char *name, umode_t mode,
void *priv, const void *ns)
{
- struct kernfs_addrm_cxt acxt;
struct kernfs_node *kn;
int rc;
@@ -674,10 +772,7 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
kn->priv = priv;
/* link in */
- kernfs_addrm_start(&acxt);
- rc = kernfs_add_one(&acxt, kn);
- kernfs_addrm_finish(&acxt);
-
+ rc = kernfs_add_one(kn);
if (!rc)
return kn;
@@ -703,7 +798,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
kn = kernfs_find_ns(parent, dentry->d_name.name, ns);
/* no such entry */
- if (!kn) {
+ if (!kn || !kernfs_active(kn)) {
ret = NULL;
goto out_unlock;
}
@@ -728,23 +823,37 @@ static int kernfs_iop_mkdir(struct inode *dir, struct dentry *dentry,
umode_t mode)
{
struct kernfs_node *parent = dir->i_private;
- struct kernfs_dir_ops *kdops = kernfs_root(parent)->dir_ops;
+ struct kernfs_syscall_ops *scops = kernfs_root(parent)->syscall_ops;
+ int ret;
- if (!kdops || !kdops->mkdir)
+ if (!scops || !scops->mkdir)
return -EPERM;
- return kdops->mkdir(parent, dentry->d_name.name, mode);
+ if (!kernfs_get_active(parent))
+ return -ENODEV;
+
+ ret = scops->mkdir(parent, dentry->d_name.name, mode);
+
+ kernfs_put_active(parent);
+ return ret;
}
static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry)
{
struct kernfs_node *kn = dentry->d_fsdata;
- struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops;
+ struct kernfs_syscall_ops *scops = kernfs_root(kn)->syscall_ops;
+ int ret;
- if (!kdops || !kdops->rmdir)
+ if (!scops || !scops->rmdir)
return -EPERM;
- return kdops->rmdir(kn);
+ if (!kernfs_get_active(kn))
+ return -ENODEV;
+
+ ret = scops->rmdir(kn);
+
+ kernfs_put_active(kn);
+ return ret;
}
static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -752,12 +861,25 @@ static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry,
{
struct kernfs_node *kn = old_dentry->d_fsdata;
struct kernfs_node *new_parent = new_dir->i_private;
- struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops;
+ struct kernfs_syscall_ops *scops = kernfs_root(kn)->syscall_ops;
+ int ret;
- if (!kdops || !kdops->rename)
+ if (!scops || !scops->rename)
return -EPERM;
- return kdops->rename(kn, new_parent, new_dentry->d_name.name);
+ if (!kernfs_get_active(kn))
+ return -ENODEV;
+
+ if (!kernfs_get_active(new_parent)) {
+ kernfs_put_active(kn);
+ return -ENODEV;
+ }
+
+ ret = scops->rename(kn, new_parent, new_dentry->d_name.name);
+
+ kernfs_put_active(new_parent);
+ kernfs_put_active(kn);
+ return ret;
}
const struct inode_operations kernfs_dir_iops = {
@@ -830,23 +952,104 @@ static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos,
return pos->parent;
}
-static void __kernfs_remove(struct kernfs_addrm_cxt *acxt,
- struct kernfs_node *kn)
+/**
+ * kernfs_activate - activate a node which started deactivated
+ * @kn: kernfs_node whose subtree is to be activated
+ *
+ * If the root has KERNFS_ROOT_CREATE_DEACTIVATED set, a newly created node
+ * needs to be explicitly activated. A node which hasn't been activated
+ * isn't visible to userland and deactivation is skipped during its
+ * removal. This is useful to construct atomic init sequences where
+ * creation of multiple nodes should either succeed or fail atomically.
+ *
+ * The caller is responsible for ensuring that this function is not called
+ * after kernfs_remove*() is invoked on @kn.
+ */
+void kernfs_activate(struct kernfs_node *kn)
{
- struct kernfs_node *pos, *next;
+ struct kernfs_node *pos;
- if (!kn)
+ mutex_lock(&kernfs_mutex);
+
+ pos = NULL;
+ while ((pos = kernfs_next_descendant_post(pos, kn))) {
+ if (!pos || (pos->flags & KERNFS_ACTIVATED))
+ continue;
+
+ WARN_ON_ONCE(pos->parent && RB_EMPTY_NODE(&pos->rb));
+ WARN_ON_ONCE(atomic_read(&pos->active) != KN_DEACTIVATED_BIAS);
+
+ atomic_sub(KN_DEACTIVATED_BIAS, &pos->active);
+ pos->flags |= KERNFS_ACTIVATED;
+ }
+
+ mutex_unlock(&kernfs_mutex);
+}
+
+static void __kernfs_remove(struct kernfs_node *kn)
+{
+ struct kernfs_node *pos;
+
+ lockdep_assert_held(&kernfs_mutex);
+
+ /*
+ * Short-circuit if non-root @kn has already finished removal.
+ * This is for kernfs_remove_self() which plays with active ref
+ * after removal.
+ */
+ if (!kn || (kn->parent && RB_EMPTY_NODE(&kn->rb)))
return;
pr_debug("kernfs %s: removing\n", kn->name);
- next = NULL;
+ /* prevent any new usage under @kn by deactivating all nodes */
+ pos = NULL;
+ while ((pos = kernfs_next_descendant_post(pos, kn)))
+ if (kernfs_active(pos))
+ atomic_add(KN_DEACTIVATED_BIAS, &pos->active);
+
+ /* deactivate and unlink the subtree node-by-node */
do {
- pos = next;
- next = kernfs_next_descendant_post(pos, kn);
- if (pos)
- kernfs_remove_one(acxt, pos);
- } while (next);
+ pos = kernfs_leftmost_descendant(kn);
+
+ /*
+ * kernfs_drain() drops kernfs_mutex temporarily and @pos's
+ * base ref could have been put by someone else by the time
+ * the function returns. Make sure it doesn't go away
+ * underneath us.
+ */
+ kernfs_get(pos);
+
+ /*
+ * Drain iff @kn was activated. This avoids draining and
+ * its lockdep annotations for nodes which have never been
+ * activated and allows embedding kernfs_remove() in create
+ * error paths without worrying about draining.
+ */
+ if (kn->flags & KERNFS_ACTIVATED)
+ kernfs_drain(pos);
+ else
+ WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS);
+
+ /*
+ * kernfs_unlink_sibling() succeeds once per node. Use it
+ * to decide who's responsible for cleanups.
+ */
+ if (!pos->parent || kernfs_unlink_sibling(pos)) {
+ struct kernfs_iattrs *ps_iattr =
+ pos->parent ? pos->parent->iattr : NULL;
+
+ /* update timestamps on the parent */
+ if (ps_iattr) {
+ ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME;
+ ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME;
+ }
+
+ kernfs_put(pos);
+ }
+
+ kernfs_put(pos);
+ } while (pos != kn);
}
/**
@@ -857,11 +1060,140 @@ static void __kernfs_remove(struct kernfs_addrm_cxt *acxt,
*/
void kernfs_remove(struct kernfs_node *kn)
{
- struct kernfs_addrm_cxt acxt;
+ mutex_lock(&kernfs_mutex);
+ __kernfs_remove(kn);
+ mutex_unlock(&kernfs_mutex);
+}
- kernfs_addrm_start(&acxt);
- __kernfs_remove(&acxt, kn);
- kernfs_addrm_finish(&acxt);
+/**
+ * kernfs_break_active_protection - break out of active protection
+ * @kn: the self kernfs_node
+ *
+ * The caller must be running off of a kernfs operation which is invoked
+ * with an active reference - e.g. one of kernfs_ops. Each invocation of
+ * this function must also be matched with an invocation of
+ * kernfs_unbreak_active_protection().
+ *
+ * This function releases the active reference of @kn the caller is
+ * holding. Once this function is called, @kn may be removed at any point
+ * and the caller is solely responsible for ensuring that the objects it
+ * dereferences are accessible.
+ */
+void kernfs_break_active_protection(struct kernfs_node *kn)
+{
+ /*
+ * Take out ourself out of the active ref dependency chain. If
+ * we're called without an active ref, lockdep will complain.
+ */
+ kernfs_put_active(kn);
+}
+
+/**
+ * kernfs_unbreak_active_protection - undo kernfs_break_active_protection()
+ * @kn: the self kernfs_node
+ *
+ * If kernfs_break_active_protection() was called, this function must be
+ * invoked before finishing the kernfs operation. Note that while this
+ * function restores the active reference, it doesn't and can't actually
+ * restore the active protection - @kn may already or be in the process of
+ * being removed. Once kernfs_break_active_protection() is invoked, that
+ * protection is irreversibly gone for the kernfs operation instance.
+ *
+ * While this function may be called at any point after
+ * kernfs_break_active_protection() is invoked, its most useful location
+ * would be right before the enclosing kernfs operation returns.
+ */
+void kernfs_unbreak_active_protection(struct kernfs_node *kn)
+{
+ /*
+ * @kn->active could be in any state; however, the increment we do
+ * here will be undone as soon as the enclosing kernfs operation
+ * finishes and this temporary bump can't break anything. If @kn
+ * is alive, nothing changes. If @kn is being deactivated, the
+ * soon-to-follow put will either finish deactivation or restore
+ * deactivated state. If @kn is already removed, the temporary
+ * bump is guaranteed to be gone before @kn is released.
+ */
+ atomic_inc(&kn->active);
+ if (kernfs_lockdep(kn))
+ rwsem_acquire(&kn->dep_map, 0, 1, _RET_IP_);
+}
+
+/**
+ * kernfs_remove_self - remove a kernfs_node from its own method
+ * @kn: the self kernfs_node to remove
+ *
+ * The caller must be running off of a kernfs operation which is invoked
+ * with an active reference - e.g. one of kernfs_ops. This can be used to
+ * implement a file operation which deletes itself.
+ *
+ * For example, the "delete" file for a sysfs device directory can be
+ * implemented by invoking kernfs_remove_self() on the "delete" file
+ * itself. This function breaks the circular dependency of trying to
+ * deactivate self while holding an active ref itself. It isn't necessary
+ * to modify the usual removal path to use kernfs_remove_self(). The
+ * "delete" implementation can simply invoke kernfs_remove_self() on self
+ * before proceeding with the usual removal path. kernfs will ignore later
+ * kernfs_remove() on self.
+ *
+ * kernfs_remove_self() can be called multiple times concurrently on the
+ * same kernfs_node. Only the first one actually performs removal and
+ * returns %true. All others will wait until the kernfs operation which
+ * won self-removal finishes and return %false. Note that the losers wait
+ * for the completion of not only the winning kernfs_remove_self() but also
+ * the whole kernfs_ops which won the arbitration. This can be used to
+ * guarantee, for example, all concurrent writes to a "delete" file to
+ * finish only after the whole operation is complete.
+ */
+bool kernfs_remove_self(struct kernfs_node *kn)
+{
+ bool ret;
+
+ mutex_lock(&kernfs_mutex);
+ kernfs_break_active_protection(kn);
+
+ /*
+ * SUICIDAL is used to arbitrate among competing invocations. Only
+ * the first one will actually perform removal. When the removal
+ * is complete, SUICIDED is set and the active ref is restored
+ * while holding kernfs_mutex. The ones which lost arbitration
+ * waits for SUICDED && drained which can happen only after the
+ * enclosing kernfs operation which executed the winning instance
+ * of kernfs_remove_self() finished.
+ */
+ if (!(kn->flags & KERNFS_SUICIDAL)) {
+ kn->flags |= KERNFS_SUICIDAL;
+ __kernfs_remove(kn);
+ kn->flags |= KERNFS_SUICIDED;
+ ret = true;
+ } else {
+ wait_queue_head_t *waitq = &kernfs_root(kn)->deactivate_waitq;
+ DEFINE_WAIT(wait);
+
+ while (true) {
+ prepare_to_wait(waitq, &wait, TASK_UNINTERRUPTIBLE);
+
+ if ((kn->flags & KERNFS_SUICIDED) &&
+ atomic_read(&kn->active) == KN_DEACTIVATED_BIAS)
+ break;
+
+ mutex_unlock(&kernfs_mutex);
+ schedule();
+ mutex_lock(&kernfs_mutex);
+ }
+ finish_wait(waitq, &wait);
+ WARN_ON_ONCE(!RB_EMPTY_NODE(&kn->rb));
+ ret = false;
+ }
+
+ /*
+ * This must be done while holding kernfs_mutex; otherwise, waiting
+ * for SUICIDED && deactivated could finish prematurely.
+ */
+ kernfs_unbreak_active_protection(kn);
+
+ mutex_unlock(&kernfs_mutex);
+ return ret;
}
/**
@@ -876,7 +1208,6 @@ void kernfs_remove(struct kernfs_node *kn)
int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name,
const void *ns)
{
- struct kernfs_addrm_cxt acxt;
struct kernfs_node *kn;
if (!parent) {
@@ -885,13 +1216,13 @@ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name,
return -ENOENT;
}
- kernfs_addrm_start(&acxt);
+ mutex_lock(&kernfs_mutex);
kn = kernfs_find_ns(parent, name, ns);
if (kn)
- __kernfs_remove(&acxt, kn);
+ __kernfs_remove(kn);
- kernfs_addrm_finish(&acxt);
+ mutex_unlock(&kernfs_mutex);
if (kn)
return 0;
@@ -909,12 +1240,18 @@ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name,
int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
const char *new_name, const void *new_ns)
{
+ struct kernfs_node *old_parent;
+ const char *old_name = NULL;
int error;
+ /* can't move or rename root */
+ if (!kn->parent)
+ return -EINVAL;
+
mutex_lock(&kernfs_mutex);
error = -ENOENT;
- if ((kn->flags | new_parent->flags) & KERNFS_REMOVED)
+ if (!kernfs_active(kn) || !kernfs_active(new_parent))
goto out;
error = 0;
@@ -932,13 +1269,8 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
new_name = kstrdup(new_name, GFP_KERNEL);
if (!new_name)
goto out;
-
- if (kn->flags & KERNFS_STATIC_NAME)
- kn->flags &= ~KERNFS_STATIC_NAME;
- else
- kfree(kn->name);
-
- kn->name = new_name;
+ } else {
+ new_name = NULL;
}
/*
@@ -946,12 +1278,29 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
*/
kernfs_unlink_sibling(kn);
kernfs_get(new_parent);
- kernfs_put(kn->parent);
+
+ /* rename_lock protects ->parent and ->name accessors */
+ spin_lock_irq(&kernfs_rename_lock);
+
+ old_parent = kn->parent;
+ kn->parent = new_parent;
+
kn->ns = new_ns;
+ if (new_name) {
+ if (!(kn->flags & KERNFS_STATIC_NAME))
+ old_name = kn->name;
+ kn->flags &= ~KERNFS_STATIC_NAME;
+ kn->name = new_name;
+ }
+
+ spin_unlock_irq(&kernfs_rename_lock);
+
kn->hash = kernfs_name_hash(kn->name, kn->ns);
- kn->parent = new_parent;
kernfs_link_sibling(kn);
+ kernfs_put(old_parent);
+ kfree(old_name);
+
error = 0;
out:
mutex_unlock(&kernfs_mutex);
@@ -974,7 +1323,7 @@ static struct kernfs_node *kernfs_dir_pos(const void *ns,
struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos)
{
if (pos) {
- int valid = !(pos->flags & KERNFS_REMOVED) &&
+ int valid = kernfs_active(pos) &&
pos->parent == parent && hash == pos->hash;
kernfs_put(pos);
if (!valid)
@@ -993,8 +1342,8 @@ static struct kernfs_node *kernfs_dir_pos(const void *ns,
break;
}
}
- /* Skip over entries in the wrong namespace */
- while (pos && pos->ns != ns) {
+ /* Skip over entries which are dying/dead or in the wrong namespace */
+ while (pos && (!kernfs_active(pos) || pos->ns != ns)) {
struct rb_node *node = rb_next(&pos->rb);
if (!node)
pos = NULL;
@@ -1008,14 +1357,15 @@ static struct kernfs_node *kernfs_dir_next_pos(const void *ns,
struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos)
{
pos = kernfs_dir_pos(ns, parent, ino, pos);
- if (pos)
+ if (pos) {
do {
struct rb_node *node = rb_next(&pos->rb);
if (!node)
pos = NULL;
else
pos = rb_to_kn(node);
- } while (pos && pos->ns != ns);
+ } while (pos && (!kernfs_active(pos) || pos->ns != ns));
+ }
return pos;
}
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index dbf397bfdff2..8034706a7af8 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -252,10 +252,18 @@ static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct kernfs_open_file *of = kernfs_of(file);
- ssize_t len = min_t(size_t, count, PAGE_SIZE);
const struct kernfs_ops *ops;
+ size_t len;
char *buf;
+ if (of->atomic_write_len) {
+ len = count;
+ if (len > of->atomic_write_len)
+ return -E2BIG;
+ } else {
+ len = min_t(size_t, count, PAGE_SIZE);
+ }
+
buf = kmalloc(len + 1, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -653,6 +661,12 @@ static int kernfs_fop_open(struct inode *inode, struct file *file)
of->file = file;
/*
+ * Write path needs to atomic_write_len outside active reference.
+ * Cache it in open_file. See kernfs_fop_write() for details.
+ */
+ of->atomic_write_len = ops->atomic_write_len;
+
+ /*
* Always instantiate seq_file even if read access doesn't use
* seq_file or is not requested. This unifies private data access
* and readable regular files are the vast majority anyway.
@@ -820,7 +834,6 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
bool name_is_static,
struct lock_class_key *key)
{
- struct kernfs_addrm_cxt acxt;
struct kernfs_node *kn;
unsigned flags;
int rc;
@@ -855,10 +868,7 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
if (ops->mmap)
kn->flags |= KERNFS_HAS_MMAP;
- kernfs_addrm_start(&acxt);
- rc = kernfs_add_one(&acxt, kn);
- kernfs_addrm_finish(&acxt);
-
+ rc = kernfs_add_one(kn);
if (rc) {
kernfs_put(kn);
return ERR_PTR(rc);
diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
index eb536b76374a..8be13b2a079b 100644
--- a/fs/kernfs/kernfs-internal.h
+++ b/fs/kernfs/kernfs-internal.h
@@ -26,7 +26,8 @@ struct kernfs_iattrs {
struct simple_xattrs xattrs;
};
-#define KN_DEACTIVATED_BIAS INT_MIN
+/* +1 to avoid triggering overflow warning when negating it */
+#define KN_DEACTIVATED_BIAS (INT_MIN + 1)
/* KERNFS_TYPE_MASK and types are defined in include/linux/kernfs.h */
@@ -45,13 +46,6 @@ static inline struct kernfs_root *kernfs_root(struct kernfs_node *kn)
}
/*
- * Context structure to be used while adding/removing nodes.
- */
-struct kernfs_addrm_cxt {
- struct kernfs_node *removed;
-};
-
-/*
* mount.c
*/
struct kernfs_super_info {
@@ -71,6 +65,7 @@ struct kernfs_super_info {
};
#define kernfs_info(SB) ((struct kernfs_super_info *)(SB->s_fs_info))
+extern const struct super_operations kernfs_sops;
extern struct kmem_cache *kernfs_node_cache;
/*
@@ -100,9 +95,7 @@ extern const struct inode_operations kernfs_dir_iops;
struct kernfs_node *kernfs_get_active(struct kernfs_node *kn);
void kernfs_put_active(struct kernfs_node *kn);
-void kernfs_addrm_start(struct kernfs_addrm_cxt *acxt);
-int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn);
-void kernfs_addrm_finish(struct kernfs_addrm_cxt *acxt);
+int kernfs_add_one(struct kernfs_node *kn);
struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
const char *name, umode_t mode,
unsigned flags);
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index 0d6ce895a9ee..6a5f04ac8704 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -19,12 +19,49 @@
struct kmem_cache *kernfs_node_cache;
-static const struct super_operations kernfs_sops = {
+static int kernfs_sop_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+ struct kernfs_root *root = kernfs_info(sb)->root;
+ struct kernfs_syscall_ops *scops = root->syscall_ops;
+
+ if (scops && scops->remount_fs)
+ return scops->remount_fs(root, flags, data);
+ return 0;
+}
+
+static int kernfs_sop_show_options(struct seq_file *sf, struct dentry *dentry)
+{
+ struct kernfs_root *root = kernfs_root(dentry->d_fsdata);
+ struct kernfs_syscall_ops *scops = root->syscall_ops;
+
+ if (scops && scops->show_options)
+ return scops->show_options(sf, root);
+ return 0;
+}
+
+const struct super_operations kernfs_sops = {
.statfs = simple_statfs,
.drop_inode = generic_delete_inode,
.evict_inode = kernfs_evict_inode,
+
+ .remount_fs = kernfs_sop_remount_fs,
+ .show_options = kernfs_sop_show_options,
};
+/**
+ * kernfs_root_from_sb - determine kernfs_root associated with a super_block
+ * @sb: the super_block in question
+ *
+ * Return the kernfs_root associated with @sb. If @sb is not a kernfs one,
+ * %NULL is returned.
+ */
+struct kernfs_root *kernfs_root_from_sb(struct super_block *sb)
+{
+ if (sb->s_op == &kernfs_sops)
+ return kernfs_info(sb)->root;
+ return NULL;
+}
+
static int kernfs_fill_super(struct super_block *sb)
{
struct kernfs_super_info *info = kernfs_info(sb);
@@ -94,6 +131,7 @@ const void *kernfs_super_ns(struct super_block *sb)
* @fs_type: file_system_type of the fs being mounted
* @flags: mount flags specified for the mount
* @root: kernfs_root of the hierarchy being mounted
+ * @new_sb_created: tell the caller if we allocated a new superblock
* @ns: optional namespace tag of the mount
*
* This is to be called from each kernfs user's file_system_type->mount()
@@ -104,7 +142,8 @@ const void *kernfs_super_ns(struct super_block *sb)
* The return value can be passed to the vfs layer verbatim.
*/
struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
- struct kernfs_root *root, const void *ns)
+ struct kernfs_root *root, bool *new_sb_created,
+ const void *ns)
{
struct super_block *sb;
struct kernfs_super_info *info;
@@ -122,6 +161,10 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
kfree(info);
if (IS_ERR(sb))
return ERR_CAST(sb);
+
+ if (new_sb_created)
+ *new_sb_created = !sb->s_root;
+
if (!sb->s_root) {
error = kernfs_fill_super(sb);
if (error) {
diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
index 4d457055acb9..8a198898e39a 100644
--- a/fs/kernfs/symlink.c
+++ b/fs/kernfs/symlink.c
@@ -27,7 +27,6 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
struct kernfs_node *target)
{
struct kernfs_node *kn;
- struct kernfs_addrm_cxt acxt;
int error;
kn = kernfs_new_node(parent, name, S_IFLNK|S_IRWXUGO, KERNFS_LINK);
@@ -39,10 +38,7 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
kn->symlink.target_kn = target;
kernfs_get(target); /* ref owned by symlink */
- kernfs_addrm_start(&acxt);
- error = kernfs_add_one(&acxt, kn);
- kernfs_addrm_finish(&acxt);
-
+ error = kernfs_add_one(kn);
if (!error)
return kn;
diff --git a/fs/mount.h b/fs/mount.h
index a17458ca6f29..b29e42f05f34 100644
--- a/fs/mount.h
+++ b/fs/mount.h
@@ -19,13 +19,13 @@ struct mnt_pcp {
};
struct mountpoint {
- struct list_head m_hash;
+ struct hlist_node m_hash;
struct dentry *m_dentry;
int m_count;
};
struct mount {
- struct list_head mnt_hash;
+ struct hlist_node mnt_hash;
struct mount *mnt_parent;
struct dentry *mnt_mountpoint;
struct vfsmount mnt;
diff --git a/fs/namei.c b/fs/namei.c
index 385f7817bfcc..4b491b431990 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1109,7 +1109,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
return false;
if (!d_mountpoint(path->dentry))
- break;
+ return true;
mounted = __lookup_mnt(path->mnt, path->dentry);
if (!mounted)
@@ -1125,20 +1125,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
*/
*inode = path->dentry->d_inode;
}
- return true;
-}
-
-static void follow_mount_rcu(struct nameidata *nd)
-{
- while (d_mountpoint(nd->path.dentry)) {
- struct mount *mounted;
- mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
- if (!mounted)
- break;
- nd->path.mnt = &mounted->mnt;
- nd->path.dentry = mounted->mnt.mnt_root;
- nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
- }
+ return read_seqretry(&mount_lock, nd->m_seq);
}
static int follow_dotdot_rcu(struct nameidata *nd)
@@ -1166,7 +1153,17 @@ static int follow_dotdot_rcu(struct nameidata *nd)
break;
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
}
- follow_mount_rcu(nd);
+ while (d_mountpoint(nd->path.dentry)) {
+ struct mount *mounted;
+ mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
+ if (!mounted)
+ break;
+ nd->path.mnt = &mounted->mnt;
+ nd->path.dentry = mounted->mnt.mnt_root;
+ nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
+ if (!read_seqretry(&mount_lock, nd->m_seq))
+ goto failed;
+ }
nd->inode = nd->path.dentry->d_inode;
return 0;
@@ -1884,7 +1881,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
nd->path = f.file->f_path;
if (flags & LOOKUP_RCU) {
- if (f.need_put)
+ if (f.flags & FDPUT_FPUT)
*fp = f.file;
nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
rcu_read_lock();
diff --git a/fs/namespace.c b/fs/namespace.c
index 22e536705c45..2ffc5a2905d4 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -23,11 +23,34 @@
#include <linux/uaccess.h>
#include <linux/proc_ns.h>
#include <linux/magic.h>
+#include <linux/bootmem.h>
#include "pnode.h"
#include "internal.h"
-#define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head))
-#define HASH_SIZE (1UL << HASH_SHIFT)
+static unsigned int m_hash_mask __read_mostly;
+static unsigned int m_hash_shift __read_mostly;
+static unsigned int mp_hash_mask __read_mostly;
+static unsigned int mp_hash_shift __read_mostly;
+
+static __initdata unsigned long mhash_entries;
+static int __init set_mhash_entries(char *str)
+{
+ if (!str)
+ return 0;
+ mhash_entries = simple_strtoul(str, &str, 0);
+ return 1;
+}
+__setup("mhash_entries=", set_mhash_entries);
+
+static __initdata unsigned long mphash_entries;
+static int __init set_mphash_entries(char *str)
+{
+ if (!str)
+ return 0;
+ mphash_entries = simple_strtoul(str, &str, 0);
+ return 1;
+}
+__setup("mphash_entries=", set_mphash_entries);
static int event;
static DEFINE_IDA(mnt_id_ida);
@@ -36,8 +59,8 @@ static DEFINE_SPINLOCK(mnt_id_lock);
static int mnt_id_start = 0;
static int mnt_group_start = 1;
-static struct list_head *mount_hashtable __read_mostly;
-static struct list_head *mountpoint_hashtable __read_mostly;
+static struct hlist_head *mount_hashtable __read_mostly;
+static struct hlist_head *mountpoint_hashtable __read_mostly;
static struct kmem_cache *mnt_cache __read_mostly;
static DECLARE_RWSEM(namespace_sem);
@@ -55,12 +78,19 @@ EXPORT_SYMBOL_GPL(fs_kobj);
*/
__cacheline_aligned_in_smp DEFINE_SEQLOCK(mount_lock);
-static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
+static inline struct hlist_head *m_hash(struct vfsmount *mnt, struct dentry *dentry)
{
unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES);
tmp += ((unsigned long)dentry / L1_CACHE_BYTES);
- tmp = tmp + (tmp >> HASH_SHIFT);
- return tmp & (HASH_SIZE - 1);
+ tmp = tmp + (tmp >> m_hash_shift);
+ return &mount_hashtable[tmp & m_hash_mask];
+}
+
+static inline struct hlist_head *mp_hash(struct dentry *dentry)
+{
+ unsigned long tmp = ((unsigned long)dentry / L1_CACHE_BYTES);
+ tmp = tmp + (tmp >> mp_hash_shift);
+ return &mountpoint_hashtable[tmp & mp_hash_mask];
}
/*
@@ -187,7 +217,7 @@ static struct mount *alloc_vfsmnt(const char *name)
mnt->mnt_writers = 0;
#endif
- INIT_LIST_HEAD(&mnt->mnt_hash);
+ INIT_HLIST_NODE(&mnt->mnt_hash);
INIT_LIST_HEAD(&mnt->mnt_child);
INIT_LIST_HEAD(&mnt->mnt_mounts);
INIT_LIST_HEAD(&mnt->mnt_list);
@@ -575,10 +605,10 @@ bool legitimize_mnt(struct vfsmount *bastard, unsigned seq)
*/
struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
{
- struct list_head *head = mount_hashtable + hash(mnt, dentry);
+ struct hlist_head *head = m_hash(mnt, dentry);
struct mount *p;
- list_for_each_entry_rcu(p, head, mnt_hash)
+ hlist_for_each_entry_rcu(p, head, mnt_hash)
if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry)
return p;
return NULL;
@@ -590,13 +620,17 @@ struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
*/
struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry)
{
- struct list_head *head = mount_hashtable + hash(mnt, dentry);
- struct mount *p;
-
- list_for_each_entry_reverse(p, head, mnt_hash)
- if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry)
- return p;
- return NULL;
+ struct mount *p, *res;
+ res = p = __lookup_mnt(mnt, dentry);
+ if (!p)
+ goto out;
+ hlist_for_each_entry_continue(p, mnt_hash) {
+ if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry)
+ break;
+ res = p;
+ }
+out:
+ return res;
}
/*
@@ -633,11 +667,11 @@ struct vfsmount *lookup_mnt(struct path *path)
static struct mountpoint *new_mountpoint(struct dentry *dentry)
{
- struct list_head *chain = mountpoint_hashtable + hash(NULL, dentry);
+ struct hlist_head *chain = mp_hash(dentry);
struct mountpoint *mp;
int ret;
- list_for_each_entry(mp, chain, m_hash) {
+ hlist_for_each_entry(mp, chain, m_hash) {
if (mp->m_dentry == dentry) {
/* might be worth a WARN_ON() */
if (d_unlinked(dentry))
@@ -659,7 +693,7 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry)
mp->m_dentry = dentry;
mp->m_count = 1;
- list_add(&mp->m_hash, chain);
+ hlist_add_head(&mp->m_hash, chain);
return mp;
}
@@ -670,7 +704,7 @@ static void put_mountpoint(struct mountpoint *mp)
spin_lock(&dentry->d_lock);
dentry->d_flags &= ~DCACHE_MOUNTED;
spin_unlock(&dentry->d_lock);
- list_del(&mp->m_hash);
+ hlist_del(&mp->m_hash);
kfree(mp);
}
}
@@ -712,7 +746,7 @@ static void detach_mnt(struct mount *mnt, struct path *old_path)
mnt->mnt_parent = mnt;
mnt->mnt_mountpoint = mnt->mnt.mnt_root;
list_del_init(&mnt->mnt_child);
- list_del_init(&mnt->mnt_hash);
+ hlist_del_init_rcu(&mnt->mnt_hash);
put_mountpoint(mnt->mnt_mp);
mnt->mnt_mp = NULL;
}
@@ -739,15 +773,14 @@ static void attach_mnt(struct mount *mnt,
struct mountpoint *mp)
{
mnt_set_mountpoint(parent, mp, mnt);
- list_add_tail(&mnt->mnt_hash, mount_hashtable +
- hash(&parent->mnt, mp->m_dentry));
+ hlist_add_head_rcu(&mnt->mnt_hash, m_hash(&parent->mnt, mp->m_dentry));
list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
}
/*
* vfsmount lock must be held for write
*/
-static void commit_tree(struct mount *mnt)
+static void commit_tree(struct mount *mnt, struct mount *shadows)
{
struct mount *parent = mnt->mnt_parent;
struct mount *m;
@@ -762,8 +795,11 @@ static void commit_tree(struct mount *mnt)
list_splice(&head, n->list.prev);
- list_add_tail(&mnt->mnt_hash, mount_hashtable +
- hash(&parent->mnt, mnt->mnt_mountpoint));
+ if (shadows)
+ hlist_add_after_rcu(&shadows->mnt_hash, &mnt->mnt_hash);
+ else
+ hlist_add_head_rcu(&mnt->mnt_hash,
+ m_hash(&parent->mnt, mnt->mnt_mountpoint));
list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
touch_mnt_namespace(n);
}
@@ -1153,26 +1189,28 @@ int may_umount(struct vfsmount *mnt)
EXPORT_SYMBOL(may_umount);
-static LIST_HEAD(unmounted); /* protected by namespace_sem */
+static HLIST_HEAD(unmounted); /* protected by namespace_sem */
static void namespace_unlock(void)
{
struct mount *mnt;
- LIST_HEAD(head);
+ struct hlist_head head = unmounted;
- if (likely(list_empty(&unmounted))) {
+ if (likely(hlist_empty(&head))) {
up_write(&namespace_sem);
return;
}
- list_splice_init(&unmounted, &head);
+ head.first->pprev = &head.first;
+ INIT_HLIST_HEAD(&unmounted);
+
up_write(&namespace_sem);
synchronize_rcu();
- while (!list_empty(&head)) {
- mnt = list_first_entry(&head, struct mount, mnt_hash);
- list_del_init(&mnt->mnt_hash);
+ while (!hlist_empty(&head)) {
+ mnt = hlist_entry(head.first, struct mount, mnt_hash);
+ hlist_del_init(&mnt->mnt_hash);
if (mnt->mnt_ex_mountpoint.mnt)
path_put(&mnt->mnt_ex_mountpoint);
mntput(&mnt->mnt);
@@ -1193,16 +1231,19 @@ static inline void namespace_lock(void)
*/
void umount_tree(struct mount *mnt, int how)
{
- LIST_HEAD(tmp_list);
+ HLIST_HEAD(tmp_list);
struct mount *p;
+ struct mount *last = NULL;
- for (p = mnt; p; p = next_mnt(p, mnt))
- list_move(&p->mnt_hash, &tmp_list);
+ for (p = mnt; p; p = next_mnt(p, mnt)) {
+ hlist_del_init_rcu(&p->mnt_hash);
+ hlist_add_head(&p->mnt_hash, &tmp_list);
+ }
if (how)
propagate_umount(&tmp_list);
- list_for_each_entry(p, &tmp_list, mnt_hash) {
+ hlist_for_each_entry(p, &tmp_list, mnt_hash) {
list_del_init(&p->mnt_expire);
list_del_init(&p->mnt_list);
__touch_mnt_namespace(p->mnt_ns);
@@ -1220,8 +1261,13 @@ void umount_tree(struct mount *mnt, int how)
p->mnt_mp = NULL;
}
change_mnt_propagation(p, MS_PRIVATE);
+ last = p;
+ }
+ if (last) {
+ last->mnt_hash.next = unmounted.first;
+ unmounted.first = tmp_list.first;
+ unmounted.first->pprev = &unmounted.first;
}
- list_splice(&tmp_list, &unmounted);
}
static void shrink_submounts(struct mount *mnt);
@@ -1605,24 +1651,23 @@ static int attach_recursive_mnt(struct mount *source_mnt,
struct mountpoint *dest_mp,
struct path *parent_path)
{
- LIST_HEAD(tree_list);
+ HLIST_HEAD(tree_list);
struct mount *child, *p;
+ struct hlist_node *n;
int err;
if (IS_MNT_SHARED(dest_mnt)) {
err = invent_group_ids(source_mnt, true);
if (err)
goto out;
- }
- err = propagate_mnt(dest_mnt, dest_mp, source_mnt, &tree_list);
- if (err)
- goto out_cleanup_ids;
-
- lock_mount_hash();
-
- if (IS_MNT_SHARED(dest_mnt)) {
+ err = propagate_mnt(dest_mnt, dest_mp, source_mnt, &tree_list);
+ if (err)
+ goto out_cleanup_ids;
+ lock_mount_hash();
for (p = source_mnt; p; p = next_mnt(p, source_mnt))
set_mnt_shared(p);
+ } else {
+ lock_mount_hash();
}
if (parent_path) {
detach_mnt(source_mnt, parent_path);
@@ -1630,20 +1675,22 @@ static int attach_recursive_mnt(struct mount *source_mnt,
touch_mnt_namespace(source_mnt->mnt_ns);
} else {
mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt);
- commit_tree(source_mnt);
+ commit_tree(source_mnt, NULL);
}
- list_for_each_entry_safe(child, p, &tree_list, mnt_hash) {
- list_del_init(&child->mnt_hash);
- commit_tree(child);
+ hlist_for_each_entry_safe(child, n, &tree_list, mnt_hash) {
+ struct mount *q;
+ hlist_del_init(&child->mnt_hash);
+ q = __lookup_mnt_last(&child->mnt_parent->mnt,
+ child->mnt_mountpoint);
+ commit_tree(child, q);
}
unlock_mount_hash();
return 0;
out_cleanup_ids:
- if (IS_MNT_SHARED(dest_mnt))
- cleanup_group_ids(source_mnt, NULL);
+ cleanup_group_ids(source_mnt, NULL);
out:
return err;
}
@@ -2777,18 +2824,24 @@ void __init mnt_init(void)
mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount),
0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
- mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);
- mountpoint_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);
+ mount_hashtable = alloc_large_system_hash("Mount-cache",
+ sizeof(struct hlist_head),
+ mhash_entries, 19,
+ 0,
+ &m_hash_shift, &m_hash_mask, 0, 0);
+ mountpoint_hashtable = alloc_large_system_hash("Mountpoint-cache",
+ sizeof(struct hlist_head),
+ mphash_entries, 19,
+ 0,
+ &mp_hash_shift, &mp_hash_mask, 0, 0);
if (!mount_hashtable || !mountpoint_hashtable)
panic("Failed to allocate mount hash table\n");
- printk(KERN_INFO "Mount-cache hash table entries: %lu\n", HASH_SIZE);
-
- for (u = 0; u < HASH_SIZE; u++)
- INIT_LIST_HEAD(&mount_hashtable[u]);
- for (u = 0; u < HASH_SIZE; u++)
- INIT_LIST_HEAD(&mountpoint_hashtable[u]);
+ for (u = 0; u <= m_hash_mask; u++)
+ INIT_HLIST_HEAD(&mount_hashtable[u]);
+ for (u = 0; u <= mp_hash_mask; u++)
+ INIT_HLIST_HEAD(&mountpoint_hashtable[u]);
kernfs_init();
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index ef792f29f831..5d8ccecf5f5c 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -659,16 +659,19 @@ int nfs_async_inode_return_delegation(struct inode *inode,
rcu_read_lock();
delegation = rcu_dereference(NFS_I(inode)->delegation);
+ if (delegation == NULL)
+ goto out_enoent;
- if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
- rcu_read_unlock();
- return -ENOENT;
- }
+ if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid))
+ goto out_enoent;
nfs_mark_return_delegation(server, delegation);
rcu_read_unlock();
nfs_delegation_run_state_manager(clp);
return 0;
+out_enoent:
+ rcu_read_unlock();
+ return -ENOENT;
}
static struct inode *
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 28a0a3cbd3b7..360114ae8b82 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -164,17 +164,16 @@ static void nfs_zap_caches_locked(struct inode *inode)
if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) {
nfs_fscache_invalidate(inode);
nfsi->cache_validity |= NFS_INO_INVALID_ATTR
- | NFS_INO_INVALID_LABEL
| NFS_INO_INVALID_DATA
| NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL
| NFS_INO_REVAL_PAGECACHE;
} else
nfsi->cache_validity |= NFS_INO_INVALID_ATTR
- | NFS_INO_INVALID_LABEL
| NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL
| NFS_INO_REVAL_PAGECACHE;
+ nfs_zap_label_cache_locked(nfsi);
}
void nfs_zap_caches(struct inode *inode)
@@ -266,6 +265,13 @@ nfs_init_locked(struct inode *inode, void *opaque)
}
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+static void nfs_clear_label_invalid(struct inode *inode)
+{
+ spin_lock(&inode->i_lock);
+ NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_LABEL;
+ spin_unlock(&inode->i_lock);
+}
+
void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
struct nfs4_label *label)
{
@@ -283,6 +289,7 @@ void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
__func__,
(char *)label->label,
label->len, error);
+ nfs_clear_label_invalid(inode);
}
}
@@ -1648,7 +1655,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_blocks = fattr->du.nfs2.blocks;
/* Update attrtimeo value if we're out of the unstable period */
- if (invalid & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) {
+ if (invalid & NFS_INO_INVALID_ATTR) {
nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = now;
@@ -1661,7 +1668,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
}
}
invalid &= ~NFS_INO_INVALID_ATTR;
- invalid &= ~NFS_INO_INVALID_LABEL;
/* Don't invalidate the data if we were to blame */
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
|| S_ISLNK(inode->i_mode)))
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 8b5cc04a8611..b46cf5a67329 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -176,7 +176,8 @@ extern struct nfs_server *nfs4_create_server(
extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
struct nfs_fh *);
extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
- struct sockaddr *sap, size_t salen);
+ struct sockaddr *sap, size_t salen,
+ struct net *net);
extern void nfs_free_server(struct nfs_server *server);
extern struct nfs_server *nfs_clone_server(struct nfs_server *,
struct nfs_fh *,
@@ -279,9 +280,18 @@ static inline void nfs4_label_free(struct nfs4_label *label)
}
return;
}
+
+static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi)
+{
+ if (nfs_server_capable(&nfsi->vfs_inode, NFS_CAP_SECURITY_LABEL))
+ nfsi->cache_validity |= NFS_INO_INVALID_LABEL;
+}
#else
static inline struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) { return NULL; }
static inline void nfs4_label_free(void *label) {}
+static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi)
+{
+}
#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
/* proc.c */
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index aa9bc973f36a..a462ef0fb5d6 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -18,6 +18,7 @@
#include <linux/lockd/bind.h>
#include <linux/nfs_mount.h>
#include <linux/freezer.h>
+#include <linux/xattr.h>
#include "iostat.h"
#include "internal.h"
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 860ad26a5590..0e46d3d1b6cc 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -1135,6 +1135,7 @@ static int nfs_probe_destination(struct nfs_server *server)
* @hostname: new end-point's hostname
* @sap: new end-point's socket address
* @salen: size of "sap"
+ * @net: net namespace
*
* The nfs_server must be quiescent before this function is invoked.
* Either its session is drained (NFSv4.1+), or its transport is
@@ -1143,13 +1144,13 @@ static int nfs_probe_destination(struct nfs_server *server)
* Returns zero on success, or a negative errno value.
*/
int nfs4_update_server(struct nfs_server *server, const char *hostname,
- struct sockaddr *sap, size_t salen)
+ struct sockaddr *sap, size_t salen, struct net *net)
{
struct nfs_client *clp = server->nfs_client;
struct rpc_clnt *clnt = server->client;
struct xprt_create xargs = {
.ident = clp->cl_proto,
- .net = &init_net,
+ .net = net,
.dstaddr = sap,
.addrlen = salen,
.servername = hostname,
@@ -1189,7 +1190,7 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
error = nfs4_set_client(server, hostname, sap, salen, buf,
clp->cl_rpcclient->cl_auth->au_flavor,
clp->cl_proto, clnt->cl_timeout,
- clp->cl_minorversion, clp->cl_net);
+ clp->cl_minorversion, net);
nfs_put_client(clp);
if (error != 0) {
nfs_server_insert_lists(server);
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 12c8132ad408..b9a35c05b60f 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -324,8 +324,9 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
&rdata->res.seq_res,
task))
return;
- nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context,
- rdata->args.lock_context, FMODE_READ);
+ if (nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context,
+ rdata->args.lock_context, FMODE_READ) == -EIO)
+ rpc_exit(task, -EIO); /* lost lock, terminate I/O */
}
static void filelayout_read_call_done(struct rpc_task *task, void *data)
@@ -435,8 +436,9 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data)
&wdata->res.seq_res,
task))
return;
- nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context,
- wdata->args.lock_context, FMODE_WRITE);
+ if (nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context,
+ wdata->args.lock_context, FMODE_WRITE) == -EIO)
+ rpc_exit(task, -EIO); /* lost lock, terminate I/O */
}
static void filelayout_write_call_done(struct rpc_task *task, void *data)
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 4e7f05d3e9db..3d5dbf80d46a 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -121,9 +121,8 @@ static int nfs4_validate_fspath(struct dentry *dentry,
}
static size_t nfs_parse_server_name(char *string, size_t len,
- struct sockaddr *sa, size_t salen, struct nfs_server *server)
+ struct sockaddr *sa, size_t salen, struct net *net)
{
- struct net *net = rpc_net_ns(server->client);
ssize_t ret;
ret = rpc_pton(net, string, len, sa, salen);
@@ -223,6 +222,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
const struct nfs4_fs_location *location)
{
const size_t addr_bufsize = sizeof(struct sockaddr_storage);
+ struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client);
struct vfsmount *mnt = ERR_PTR(-ENOENT);
char *mnt_path;
unsigned int maxbuflen;
@@ -248,8 +248,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
continue;
mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len,
- mountdata->addr, addr_bufsize,
- NFS_SB(mountdata->sb));
+ mountdata->addr, addr_bufsize, net);
if (mountdata->addrlen == 0)
continue;
@@ -419,6 +418,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server,
const struct nfs4_fs_location *location)
{
const size_t addr_bufsize = sizeof(struct sockaddr_storage);
+ struct net *net = rpc_net_ns(server->client);
struct sockaddr *sap;
unsigned int s;
size_t salen;
@@ -440,7 +440,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server,
continue;
salen = nfs_parse_server_name(buf->data, buf->len,
- sap, addr_bufsize, server);
+ sap, addr_bufsize, net);
if (salen == 0)
continue;
rpc_set_port(sap, NFS_PORT);
@@ -450,7 +450,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server,
if (hostname == NULL)
break;
- error = nfs4_update_server(server, hostname, sap, salen);
+ error = nfs4_update_server(server, hostname, sap, salen, net);
kfree(hostname);
if (error == 0)
break;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 2da6a698b8f7..450bfedbe2f4 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2398,13 +2398,16 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) {
/* Use that stateid */
- } else if (truncate && state != NULL && nfs4_valid_open_stateid(state)) {
+ } else if (truncate && state != NULL) {
struct nfs_lockowner lockowner = {
.l_owner = current->files,
.l_pid = current->tgid,
};
- nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
- &lockowner);
+ if (!nfs4_valid_open_stateid(state))
+ return -EBADF;
+ if (nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
+ &lockowner) == -EIO)
+ return -EBADF;
} else
nfs4_stateid_copy(&arg.stateid, &zero_stateid);
@@ -4011,8 +4014,9 @@ static bool nfs4_stateid_is_current(nfs4_stateid *stateid,
{
nfs4_stateid current_stateid;
- if (nfs4_set_rw_stateid(&current_stateid, ctx, l_ctx, fmode))
- return false;
+ /* If the current stateid represents a lost lock, then exit */
+ if (nfs4_set_rw_stateid(&current_stateid, ctx, l_ctx, fmode) == -EIO)
+ return true;
return nfs4_stateid_match(stateid, &current_stateid);
}
@@ -5828,8 +5832,7 @@ struct nfs_release_lockowner_data {
struct nfs4_lock_state *lsp;
struct nfs_server *server;
struct nfs_release_lockowner_args args;
- struct nfs4_sequence_args seq_args;
- struct nfs4_sequence_res seq_res;
+ struct nfs_release_lockowner_res res;
unsigned long timestamp;
};
@@ -5837,7 +5840,7 @@ static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata
{
struct nfs_release_lockowner_data *data = calldata;
nfs40_setup_sequence(data->server,
- &data->seq_args, &data->seq_res, task);
+ &data->args.seq_args, &data->res.seq_res, task);
data->timestamp = jiffies;
}
@@ -5846,7 +5849,7 @@ static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata)
struct nfs_release_lockowner_data *data = calldata;
struct nfs_server *server = data->server;
- nfs40_sequence_done(task, &data->seq_res);
+ nfs40_sequence_done(task, &data->res.seq_res);
switch (task->tk_status) {
case 0:
@@ -5887,7 +5890,6 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
data = kmalloc(sizeof(*data), GFP_NOFS);
if (!data)
return -ENOMEM;
- nfs4_init_sequence(&data->seq_args, &data->seq_res, 0);
data->lsp = lsp;
data->server = server;
data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
@@ -5895,6 +5897,8 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
data->args.lock_owner.s_dev = server->s_dev;
msg.rpc_argp = &data->args;
+ msg.rpc_resp = &data->res;
+ nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
return 0;
}
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index e5be72518bd7..0deb32105ccf 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -974,9 +974,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
nfs4_stateid_copy(dst, &lsp->ls_stateid);
ret = 0;
- smp_rmb();
- if (!list_empty(&lsp->ls_seqid.list))
- ret = -EWOULDBLOCK;
}
spin_unlock(&state->state_lock);
nfs4_put_lock_state(lsp);
@@ -984,10 +981,9 @@ out:
return ret;
}
-static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
+static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
{
const nfs4_stateid *src;
- int ret;
int seq;
do {
@@ -996,12 +992,7 @@ static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
if (test_bit(NFS_OPEN_STATE, &state->flags))
src = &state->open_stateid;
nfs4_stateid_copy(dst, src);
- ret = 0;
- smp_rmb();
- if (!list_empty(&state->owner->so_seqid.list))
- ret = -EWOULDBLOCK;
} while (read_seqretry(&state->seqlock, seq));
- return ret;
}
/*
@@ -1015,15 +1006,19 @@ int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
if (ret == -EIO)
/* A lost lock - don't even consider delegations */
goto out;
- if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
+ /* returns true if delegation stateid found and copied */
+ if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) {
+ ret = 0;
goto out;
+ }
if (ret != -ENOENT)
/* nfs4_copy_delegation_stateid() didn't over-write
* dst, so it still has the lock stateid which we now
* choose to use.
*/
goto out;
- ret = nfs4_copy_open_stateid(dst, state);
+ nfs4_copy_open_stateid(dst, state);
+ ret = 0;
out:
if (nfs_server_capable(state->inode, NFS_CAP_STATEID_NFSV41))
dst->seqid = 0;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 017d3cb5e99b..6d7be3f80356 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -449,6 +449,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
fh_lock(fhp);
host_err = notify_change(dentry, iap, NULL);
fh_unlock(fhp);
+ err = nfserrno(host_err);
out_put_write_access:
if (size_change)
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index 0b9ff4395e6a..abc8cbcfe90e 100644
--- a/fs/notify/dnotify/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -86,7 +86,7 @@ static int dnotify_handle_event(struct fsnotify_group *group,
struct fsnotify_mark *inode_mark,
struct fsnotify_mark *vfsmount_mark,
u32 mask, void *data, int data_type,
- const unsigned char *file_name)
+ const unsigned char *file_name, u32 cookie)
{
struct dnotify_mark *dn_mark;
struct dnotify_struct *dn;
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 0e792f5e3147..dc638f786d5c 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -147,7 +147,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
struct fsnotify_mark *inode_mark,
struct fsnotify_mark *fanotify_mark,
u32 mask, void *data, int data_type,
- const unsigned char *file_name)
+ const unsigned char *file_name, u32 cookie)
{
int ret = 0;
struct fanotify_event_info *event;
@@ -192,10 +192,12 @@ static int fanotify_handle_event(struct fsnotify_group *group,
ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge);
if (ret) {
- BUG_ON(mask & FAN_ALL_PERM_EVENTS);
+ /* Permission events shouldn't be merged */
+ BUG_ON(ret == 1 && mask & FAN_ALL_PERM_EVENTS);
/* Our event wasn't used in the end. Free it. */
fsnotify_destroy_event(group, fsn_event);
- ret = 0;
+
+ return 0;
}
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index b6175fa11bf8..287a22c04149 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -698,6 +698,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
struct fsnotify_group *group;
int f_flags, fd;
struct user_struct *user;
+ struct fanotify_event_info *oevent;
pr_debug("%s: flags=%d event_f_flags=%d\n",
__func__, flags, event_f_flags);
@@ -730,8 +731,20 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
group->fanotify_data.user = user;
atomic_inc(&user->fanotify_listeners);
+ oevent = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL);
+ if (unlikely(!oevent)) {
+ fd = -ENOMEM;
+ goto out_destroy_group;
+ }
+ group->overflow_event = &oevent->fse;
+ fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW);
+ oevent->tgid = get_pid(task_tgid(current));
+ oevent->path.mnt = NULL;
+ oevent->path.dentry = NULL;
+
group->fanotify_data.f_flags = event_f_flags;
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+ oevent->response = 0;
mutex_init(&group->fanotify_data.access_mutex);
init_waitqueue_head(&group->fanotify_data.access_waitq);
INIT_LIST_HEAD(&group->fanotify_data.access_list);
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 1d4e1ea2f37c..9d3e9c50066a 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -179,7 +179,7 @@ static int send_to_group(struct inode *to_tell,
return group->ops->handle_event(group, to_tell, inode_mark,
vfsmount_mark, mask, data, data_is,
- file_name);
+ file_name, cookie);
}
/*
diff --git a/fs/notify/group.c b/fs/notify/group.c
index ee674fe2cec7..ad1995980456 100644
--- a/fs/notify/group.c
+++ b/fs/notify/group.c
@@ -55,6 +55,13 @@ void fsnotify_destroy_group(struct fsnotify_group *group)
/* clear the notification queue of all events */
fsnotify_flush_notify(group);
+ /*
+ * Destroy overflow event (we cannot use fsnotify_destroy_event() as
+ * that deliberately ignores overflow events.
+ */
+ if (group->overflow_event)
+ group->ops->free_event(group->overflow_event);
+
fsnotify_put_group(group);
}
@@ -99,7 +106,6 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
INIT_LIST_HEAD(&group->marks_list);
group->ops = ops;
- fsnotify_init_event(&group->overflow_event, NULL, FS_Q_OVERFLOW);
return group;
}
diff --git a/fs/notify/inotify/inotify.h b/fs/notify/inotify/inotify.h
index 485eef3f4407..ed855ef6f077 100644
--- a/fs/notify/inotify/inotify.h
+++ b/fs/notify/inotify/inotify.h
@@ -27,6 +27,6 @@ extern int inotify_handle_event(struct fsnotify_group *group,
struct fsnotify_mark *inode_mark,
struct fsnotify_mark *vfsmount_mark,
u32 mask, void *data, int data_type,
- const unsigned char *file_name);
+ const unsigned char *file_name, u32 cookie);
extern const struct fsnotify_ops inotify_fsnotify_ops;
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index d5ee56348bb8..43ab1e1a07a2 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -67,7 +67,7 @@ int inotify_handle_event(struct fsnotify_group *group,
struct fsnotify_mark *inode_mark,
struct fsnotify_mark *vfsmount_mark,
u32 mask, void *data, int data_type,
- const unsigned char *file_name)
+ const unsigned char *file_name, u32 cookie)
{
struct inotify_inode_mark *i_mark;
struct inotify_event_info *event;
@@ -103,6 +103,7 @@ int inotify_handle_event(struct fsnotify_group *group,
fsn_event = &event->fse;
fsnotify_init_event(fsn_event, inode, mask);
event->wd = i_mark->wd;
+ event->sync_cookie = cookie;
event->name_len = len;
if (len)
strcpy(event->name, file_name);
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 497395c8274b..78a2ca3966c3 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -495,7 +495,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
/* Queue ignore event for the watch */
inotify_handle_event(group, NULL, fsn_mark, NULL, FS_IN_IGNORED,
- NULL, FSNOTIFY_EVENT_NONE, NULL);
+ NULL, FSNOTIFY_EVENT_NONE, NULL, 0);
i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
/* remove this mark from the idr */
@@ -633,11 +633,23 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod
static struct fsnotify_group *inotify_new_group(unsigned int max_events)
{
struct fsnotify_group *group;
+ struct inotify_event_info *oevent;
group = fsnotify_alloc_group(&inotify_fsnotify_ops);
if (IS_ERR(group))
return group;
+ oevent = kmalloc(sizeof(struct inotify_event_info), GFP_KERNEL);
+ if (unlikely(!oevent)) {
+ fsnotify_destroy_group(group);
+ return ERR_PTR(-ENOMEM);
+ }
+ group->overflow_event = &oevent->fse;
+ fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW);
+ oevent->wd = -1;
+ oevent->sync_cookie = 0;
+ oevent->name_len = 0;
+
group->max_events = max_events;
spin_lock_init(&group->inotify_data.idr_lock);
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index 18b3c4427dca..1e58402171a5 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -80,7 +80,8 @@ void fsnotify_destroy_event(struct fsnotify_group *group,
/*
* Add an event to the group notification queue. The group can later pull this
* event off the queue to deal with. The function returns 0 if the event was
- * added to the queue, 1 if the event was merged with some other queued event.
+ * added to the queue, 1 if the event was merged with some other queued event,
+ * 2 if the queue of events has overflown.
*/
int fsnotify_add_notify_event(struct fsnotify_group *group,
struct fsnotify_event *event,
@@ -95,10 +96,14 @@ int fsnotify_add_notify_event(struct fsnotify_group *group,
mutex_lock(&group->notification_mutex);
if (group->q_len >= group->max_events) {
+ ret = 2;
/* Queue overflow event only if it isn't already queued */
- if (list_empty(&group->overflow_event.list))
- event = &group->overflow_event;
- ret = 1;
+ if (!list_empty(&group->overflow_event->list)) {
+ mutex_unlock(&group->notification_mutex);
+ return ret;
+ }
+ event = group->overflow_event;
+ goto queue;
}
if (!list_empty(list) && merge) {
@@ -109,6 +114,7 @@ int fsnotify_add_notify_event(struct fsnotify_group *group,
}
}
+queue:
group->q_len++;
list_add_tail(&event->list, list);
mutex_unlock(&group->notification_mutex);
@@ -132,7 +138,11 @@ struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group *group
event = list_first_entry(&group->notification_list,
struct fsnotify_event, list);
- list_del(&event->list);
+ /*
+ * We need to init list head for the case of overflow event so that
+ * check in fsnotify_add_notify_events() works
+ */
+ list_del_init(&event->list);
group->q_len--;
return event;
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 8450262bcf2a..51632c40e896 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -2393,8 +2393,8 @@ out_dio:
if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) ||
((file->f_flags & O_DIRECT) && !direct_io)) {
- ret = filemap_fdatawrite_range(file->f_mapping, pos,
- pos + count - 1);
+ ret = filemap_fdatawrite_range(file->f_mapping, *ppos,
+ *ppos + count - 1);
if (ret < 0)
written = ret;
@@ -2407,8 +2407,8 @@ out_dio:
}
if (!ret)
- ret = filemap_fdatawait_range(file->f_mapping, pos,
- pos + count - 1);
+ ret = filemap_fdatawait_range(file->f_mapping, *ppos,
+ *ppos + count - 1);
}
/*
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
index aaa50611ec66..d7b5108789e2 100644
--- a/fs/ocfs2/quota_global.c
+++ b/fs/ocfs2/quota_global.c
@@ -717,6 +717,12 @@ static int ocfs2_release_dquot(struct dquot *dquot)
*/
if (status < 0)
mlog_errno(status);
+ /*
+ * Clear dq_off so that we search for the structure in quota file next
+ * time we acquire it. The structure might be deleted and reallocated
+ * elsewhere by another node while our dquot structure is on freelist.
+ */
+ dquot->dq_off = 0;
clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
out_trans:
ocfs2_commit_trans(osb, handle);
@@ -756,16 +762,17 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
status = ocfs2_lock_global_qf(info, 1);
if (status < 0)
goto out;
- if (!test_bit(DQ_READ_B, &dquot->dq_flags)) {
- status = ocfs2_qinfo_lock(info, 0);
- if (status < 0)
- goto out_dq;
- status = qtree_read_dquot(&info->dqi_gi, dquot);
- ocfs2_qinfo_unlock(info, 0);
- if (status < 0)
- goto out_dq;
- }
- set_bit(DQ_READ_B, &dquot->dq_flags);
+ status = ocfs2_qinfo_lock(info, 0);
+ if (status < 0)
+ goto out_dq;
+ /*
+ * We always want to read dquot structure from disk because we don't
+ * know what happened with it while it was on freelist.
+ */
+ status = qtree_read_dquot(&info->dqi_gi, dquot);
+ ocfs2_qinfo_unlock(info, 0);
+ if (status < 0)
+ goto out_dq;
OCFS2_DQUOT(dquot)->dq_use_count++;
OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
index 2e4344be3b96..2001862bf2b1 100644
--- a/fs/ocfs2/quota_local.c
+++ b/fs/ocfs2/quota_local.c
@@ -1303,10 +1303,6 @@ int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot)
ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh);
out:
- /* Clear the read bit so that next time someone uses this
- * dquot he reads fresh info from disk and allocates local
- * dquot structure */
- clear_bit(DQ_READ_B, &dquot->dq_flags);
return status;
}
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c
index 1324e6600e57..ca5ce14cbddc 100644
--- a/fs/ocfs2/stackglue.c
+++ b/fs/ocfs2/stackglue.c
@@ -346,7 +346,9 @@ int ocfs2_cluster_connect(const char *stack_name,
strlcpy(new_conn->cc_name, group, GROUP_NAME_MAX + 1);
new_conn->cc_namelen = grouplen;
- strlcpy(new_conn->cc_cluster_name, cluster_name, CLUSTER_NAME_MAX + 1);
+ if (cluster_name_len)
+ strlcpy(new_conn->cc_cluster_name, cluster_name,
+ CLUSTER_NAME_MAX + 1);
new_conn->cc_cluster_name_len = cluster_name_len;
new_conn->cc_recovery_handler = recovery_handler;
new_conn->cc_recovery_data = recovery_data;
diff --git a/fs/open.c b/fs/open.c
index 4b3e1edf2fe4..b9ed8b25c108 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -705,6 +705,10 @@ static int do_dentry_open(struct file *f,
return 0;
}
+ /* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */
+ if (S_ISREG(inode->i_mode))
+ f->f_mode |= FMODE_ATOMIC_POS;
+
f->f_op = fops_get(inode->i_fop);
if (unlikely(WARN_ON(!f->f_op))) {
error = -ENODEV;
diff --git a/fs/pnode.c b/fs/pnode.c
index c7221bb19801..88396df725b4 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -220,14 +220,14 @@ static struct mount *get_source(struct mount *dest,
* @tree_list : list of heads of trees to be attached.
*/
int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
- struct mount *source_mnt, struct list_head *tree_list)
+ struct mount *source_mnt, struct hlist_head *tree_list)
{
struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;
struct mount *m, *child;
int ret = 0;
struct mount *prev_dest_mnt = dest_mnt;
struct mount *prev_src_mnt = source_mnt;
- LIST_HEAD(tmp_list);
+ HLIST_HEAD(tmp_list);
for (m = propagation_next(dest_mnt, dest_mnt); m;
m = propagation_next(m, dest_mnt)) {
@@ -246,27 +246,29 @@ int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
child = copy_tree(source, source->mnt.mnt_root, type);
if (IS_ERR(child)) {
ret = PTR_ERR(child);
- list_splice(tree_list, tmp_list.prev);
+ tmp_list = *tree_list;
+ tmp_list.first->pprev = &tmp_list.first;
+ INIT_HLIST_HEAD(tree_list);
goto out;
}
if (is_subdir(dest_mp->m_dentry, m->mnt.mnt_root)) {
mnt_set_mountpoint(m, dest_mp, child);
- list_add_tail(&child->mnt_hash, tree_list);
+ hlist_add_head(&child->mnt_hash, tree_list);
} else {
/*
* This can happen if the parent mount was bind mounted
* on some subdirectory of a shared/slave mount.
*/
- list_add_tail(&child->mnt_hash, &tmp_list);
+ hlist_add_head(&child->mnt_hash, &tmp_list);
}
prev_dest_mnt = m;
prev_src_mnt = child;
}
out:
lock_mount_hash();
- while (!list_empty(&tmp_list)) {
- child = list_first_entry(&tmp_list, struct mount, mnt_hash);
+ while (!hlist_empty(&tmp_list)) {
+ child = hlist_entry(tmp_list.first, struct mount, mnt_hash);
umount_tree(child, 0);
}
unlock_mount_hash();
@@ -338,8 +340,10 @@ static void __propagate_umount(struct mount *mnt)
* umount the child only if the child has no
* other children
*/
- if (child && list_empty(&child->mnt_mounts))
- list_move_tail(&child->mnt_hash, &mnt->mnt_hash);
+ if (child && list_empty(&child->mnt_mounts)) {
+ hlist_del_init_rcu(&child->mnt_hash);
+ hlist_add_before_rcu(&child->mnt_hash, &mnt->mnt_hash);
+ }
}
}
@@ -350,11 +354,11 @@ static void __propagate_umount(struct mount *mnt)
*
* vfsmount lock must be held for write
*/
-int propagate_umount(struct list_head *list)
+int propagate_umount(struct hlist_head *list)
{
struct mount *mnt;
- list_for_each_entry(mnt, list, mnt_hash)
+ hlist_for_each_entry(mnt, list, mnt_hash)
__propagate_umount(mnt);
return 0;
}
diff --git a/fs/pnode.h b/fs/pnode.h
index 59e7eda1851e..fc28a27fa892 100644
--- a/fs/pnode.h
+++ b/fs/pnode.h
@@ -36,8 +36,8 @@ static inline void set_mnt_shared(struct mount *mnt)
void change_mnt_propagation(struct mount *, int);
int propagate_mnt(struct mount *, struct mountpoint *, struct mount *,
- struct list_head *);
-int propagate_umount(struct list_head *);
+ struct hlist_head *);
+int propagate_umount(struct hlist_head *);
int propagate_mount_busy(struct mount *, int);
void mnt_release_group_id(struct mount *);
int get_dominating_id(struct mount *mnt, const struct path *root);
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index ab30716584f5..239493ec718e 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -27,6 +27,5 @@ proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o
proc-$(CONFIG_NET) += proc_net.o
proc-$(CONFIG_PROC_KCORE) += kcore.o
proc-$(CONFIG_PROC_VMCORE) += vmcore.o
-proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o
proc-$(CONFIG_PRINTK) += kmsg.o
proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 51507065263b..b9760628e1fd 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1824,6 +1824,7 @@ static int proc_map_files_get_link(struct dentry *dentry, struct path *path)
if (rc)
goto out_mmput;
+ rc = -ENOENT;
down_read(&mm->mmap_sem);
vma = find_exact_vma(mm, vm_start, vm_end);
if (vma && vma->vm_file) {
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 651d09a11dde..3ab6d14e71c5 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -211,13 +211,6 @@ extern int proc_fill_super(struct super_block *);
extern void proc_entry_rundown(struct proc_dir_entry *);
/*
- * proc_devtree.c
- */
-#ifdef CONFIG_PROC_DEVICETREE
-extern void proc_device_tree_init(void);
-#endif
-
-/*
* proc_namespaces.c
*/
extern const struct inode_operations proc_ns_dir_inode_operations;
diff --git a/fs/proc/page.c b/fs/proc/page.c
index 02174a610315..e647c55275d9 100644
--- a/fs/proc/page.c
+++ b/fs/proc/page.c
@@ -121,9 +121,8 @@ u64 stable_page_flags(struct page *page)
* just checks PG_head/PG_tail, so we need to check PageLRU/PageAnon
* to make sure a given page is a thp, not a non-huge compound page.
*/
- else if (PageTransCompound(page) &&
- (PageLRU(compound_trans_head(page)) ||
- PageAnon(compound_trans_head(page))))
+ else if (PageTransCompound(page) && (PageLRU(compound_head(page)) ||
+ PageAnon(compound_head(page))))
u |= 1 << KPF_THP;
/*
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
deleted file mode 100644
index c82dd5147845..000000000000
--- a/fs/proc/proc_devtree.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * proc_devtree.c - handles /proc/device-tree
- *
- * Copyright 1997 Paul Mackerras
- */
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/printk.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/of.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <asm/uaccess.h>
-#include "internal.h"
-
-static inline void set_node_proc_entry(struct device_node *np,
- struct proc_dir_entry *de)
-{
- np->pde = de;
-}
-
-static struct proc_dir_entry *proc_device_tree;
-
-/*
- * Supply data on a read from /proc/device-tree/node/property.
- */
-static int property_proc_show(struct seq_file *m, void *v)
-{
- struct property *pp = m->private;
-
- seq_write(m, pp->value, pp->length);
- return 0;
-}
-
-static int property_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, property_proc_show, __PDE_DATA(inode));
-}
-
-static const struct file_operations property_proc_fops = {
- .owner = THIS_MODULE,
- .open = property_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-/*
- * For a node with a name like "gc@10", we make symlinks called "gc"
- * and "@10" to it.
- */
-
-/*
- * Add a property to a node
- */
-static struct proc_dir_entry *
-__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp,
- const char *name)
-{
- struct proc_dir_entry *ent;
-
- /*
- * Unfortunately proc_register puts each new entry
- * at the beginning of the list. So we rearrange them.
- */
- ent = proc_create_data(name,
- strncmp(name, "security-", 9) ? S_IRUGO : S_IRUSR,
- de, &property_proc_fops, pp);
- if (ent == NULL)
- return NULL;
-
- if (!strncmp(name, "security-", 9))
- proc_set_size(ent, 0); /* don't leak number of password chars */
- else
- proc_set_size(ent, pp->length);
-
- return ent;
-}
-
-
-void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop)
-{
- __proc_device_tree_add_prop(pde, prop, prop->name);
-}
-
-void proc_device_tree_remove_prop(struct proc_dir_entry *pde,
- struct property *prop)
-{
- remove_proc_entry(prop->name, pde);
-}
-
-void proc_device_tree_update_prop(struct proc_dir_entry *pde,
- struct property *newprop,
- struct property *oldprop)
-{
- struct proc_dir_entry *ent;
-
- if (!oldprop) {
- proc_device_tree_add_prop(pde, newprop);
- return;
- }
-
- for (ent = pde->subdir; ent != NULL; ent = ent->next)
- if (ent->data == oldprop)
- break;
- if (ent == NULL) {
- pr_warn("device-tree: property \"%s\" does not exist\n",
- oldprop->name);
- } else {
- ent->data = newprop;
- ent->size = newprop->length;
- }
-}
-
-/*
- * Various dodgy firmware might give us nodes and/or properties with
- * conflicting names. That's generally ok, except for exporting via /proc,
- * so munge names here to ensure they're unique.
- */
-
-static int duplicate_name(struct proc_dir_entry *de, const char *name)
-{
- struct proc_dir_entry *ent;
- int found = 0;
-
- spin_lock(&proc_subdir_lock);
-
- for (ent = de->subdir; ent != NULL; ent = ent->next) {
- if (strcmp(ent->name, name) == 0) {
- found = 1;
- break;
- }
- }
-
- spin_unlock(&proc_subdir_lock);
-
- return found;
-}
-
-static const char *fixup_name(struct device_node *np, struct proc_dir_entry *de,
- const char *name)
-{
- char *fixed_name;
- int fixup_len = strlen(name) + 2 + 1; /* name + #x + \0 */
- int i = 1, size;
-
-realloc:
- fixed_name = kmalloc(fixup_len, GFP_KERNEL);
- if (fixed_name == NULL) {
- pr_err("device-tree: Out of memory trying to fixup "
- "name \"%s\"\n", name);
- return name;
- }
-
-retry:
- size = snprintf(fixed_name, fixup_len, "%s#%d", name, i);
- size++; /* account for NULL */
-
- if (size > fixup_len) {
- /* We ran out of space, free and reallocate. */
- kfree(fixed_name);
- fixup_len = size;
- goto realloc;
- }
-
- if (duplicate_name(de, fixed_name)) {
- /* Multiple duplicates. Retry with a different offset. */
- i++;
- goto retry;
- }
-
- pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n",
- np->full_name, fixed_name);
-
- return fixed_name;
-}
-
-/*
- * Process a node, adding entries for its children and its properties.
- */
-void proc_device_tree_add_node(struct device_node *np,
- struct proc_dir_entry *de)
-{
- struct property *pp;
- struct proc_dir_entry *ent;
- struct device_node *child;
- const char *p;
-
- set_node_proc_entry(np, de);
- for (child = NULL; (child = of_get_next_child(np, child));) {
- /* Use everything after the last slash, or the full name */
- p = kbasename(child->full_name);
-
- if (duplicate_name(de, p))
- p = fixup_name(np, de, p);
-
- ent = proc_mkdir(p, de);
- if (ent == NULL)
- break;
- proc_device_tree_add_node(child, ent);
- }
- of_node_put(child);
-
- for (pp = np->properties; pp != NULL; pp = pp->next) {
- p = pp->name;
-
- if (strchr(p, '/'))
- continue;
-
- if (duplicate_name(de, p))
- p = fixup_name(np, de, p);
-
- ent = __proc_device_tree_add_prop(de, pp, p);
- if (ent == NULL)
- break;
- }
-}
-
-/*
- * Called on initialization to set up the /proc/device-tree subtree
- */
-void __init proc_device_tree_init(void)
-{
- struct device_node *root;
-
- proc_device_tree = proc_mkdir("device-tree", NULL);
- if (proc_device_tree == NULL)
- return;
- root = of_find_node_by_path("/");
- if (root == NULL) {
- remove_proc_entry("device-tree", NULL);
- pr_debug("/proc/device-tree: can't find root\n");
- return;
- }
- proc_device_tree_add_node(root, proc_device_tree);
- of_node_put(root);
-}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 87dbcbef7fe4..7bbeb5257af1 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -183,9 +183,6 @@ void __init proc_root_init(void)
proc_mkdir("openprom", NULL);
#endif
proc_tty_init();
-#ifdef CONFIG_PROC_DEVICETREE
- proc_device_tree_init();
-#endif
proc_mkdir("bus", NULL);
proc_sys_init();
}
diff --git a/fs/proc/stat.c b/fs/proc/stat.c
index 6f599c62f0cc..9d231e9e5f0e 100644
--- a/fs/proc/stat.c
+++ b/fs/proc/stat.c
@@ -9,7 +9,7 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/irqnr.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
#include <linux/tick.h>
#ifndef arch_irq_stat_cpu
diff --git a/fs/proc/uptime.c b/fs/proc/uptime.c
index 7141b8d0ca9e..33de567c25af 100644
--- a/fs/proc/uptime.c
+++ b/fs/proc/uptime.c
@@ -5,7 +5,7 @@
#include <linux/seq_file.h>
#include <linux/time.h>
#include <linux/kernel_stat.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
static int uptime_proc_show(struct seq_file *m, void *v)
{
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 831d49a4111f..cfc8dcc16043 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -581,9 +581,17 @@ int dquot_scan_active(struct super_block *sb,
dqstats_inc(DQST_LOOKUPS);
dqput(old_dquot);
old_dquot = dquot;
- ret = fn(dquot, priv);
- if (ret < 0)
- goto out;
+ /*
+ * ->release_dquot() can be racing with us. Our reference
+ * protects us from new calls to it so just wait for any
+ * outstanding call and recheck the DQ_ACTIVE_B after that.
+ */
+ wait_on_dquot(dquot);
+ if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
+ ret = fn(dquot, priv);
+ if (ret < 0)
+ goto out;
+ }
spin_lock(&dq_list_lock);
/* We are safe to continue now because our dquot could not
* be moved out of the inuse list while we hold the reference */
diff --git a/fs/read_write.c b/fs/read_write.c
index edc5746a902a..31c6efa43183 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -264,10 +264,22 @@ loff_t vfs_llseek(struct file *file, loff_t offset, int whence)
}
EXPORT_SYMBOL(vfs_llseek);
+static inline struct fd fdget_pos(int fd)
+{
+ return __to_fd(__fdget_pos(fd));
+}
+
+static inline void fdput_pos(struct fd f)
+{
+ if (f.flags & FDPUT_POS_UNLOCK)
+ mutex_unlock(&f.file->f_pos_lock);
+ fdput(f);
+}
+
SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
{
off_t retval;
- struct fd f = fdget(fd);
+ struct fd f = fdget_pos(fd);
if (!f.file)
return -EBADF;
@@ -278,7 +290,7 @@ SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
if (res != (loff_t)retval)
retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */
}
- fdput(f);
+ fdput_pos(f);
return retval;
}
@@ -295,7 +307,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
unsigned int, whence)
{
int retval;
- struct fd f = fdget(fd);
+ struct fd f = fdget_pos(fd);
loff_t offset;
if (!f.file)
@@ -315,7 +327,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
retval = 0;
}
out_putf:
- fdput(f);
+ fdput_pos(f);
return retval;
}
#endif
@@ -498,7 +510,7 @@ static inline void file_pos_write(struct file *file, loff_t pos)
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
- struct fd f = fdget(fd);
+ struct fd f = fdget_pos(fd);
ssize_t ret = -EBADF;
if (f.file) {
@@ -506,7 +518,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
ret = vfs_read(f.file, buf, count, &pos);
if (ret >= 0)
file_pos_write(f.file, pos);
- fdput(f);
+ fdput_pos(f);
}
return ret;
}
@@ -514,7 +526,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
size_t, count)
{
- struct fd f = fdget(fd);
+ struct fd f = fdget_pos(fd);
ssize_t ret = -EBADF;
if (f.file) {
@@ -522,7 +534,7 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
ret = vfs_write(f.file, buf, count, &pos);
if (ret >= 0)
file_pos_write(f.file, pos);
- fdput(f);
+ fdput_pos(f);
}
return ret;
@@ -797,7 +809,7 @@ EXPORT_SYMBOL(vfs_writev);
SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
unsigned long, vlen)
{
- struct fd f = fdget(fd);
+ struct fd f = fdget_pos(fd);
ssize_t ret = -EBADF;
if (f.file) {
@@ -805,7 +817,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
ret = vfs_readv(f.file, vec, vlen, &pos);
if (ret >= 0)
file_pos_write(f.file, pos);
- fdput(f);
+ fdput_pos(f);
}
if (ret > 0)
@@ -817,7 +829,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
unsigned long, vlen)
{
- struct fd f = fdget(fd);
+ struct fd f = fdget_pos(fd);
ssize_t ret = -EBADF;
if (f.file) {
@@ -825,7 +837,7 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
ret = vfs_writev(f.file, vec, vlen, &pos);
if (ret >= 0)
file_pos_write(f.file, pos);
- fdput(f);
+ fdput_pos(f);
}
if (ret > 0)
@@ -968,7 +980,7 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,
const struct compat_iovec __user *,vec,
compat_ulong_t, vlen)
{
- struct fd f = fdget(fd);
+ struct fd f = fdget_pos(fd);
ssize_t ret;
loff_t pos;
@@ -978,13 +990,13 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,
ret = compat_readv(f.file, vec, vlen, &pos);
if (ret >= 0)
f.file->f_pos = pos;
- fdput(f);
+ fdput_pos(f);
return ret;
}
-COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd,
- const struct compat_iovec __user *,vec,
- unsigned long, vlen, loff_t, pos)
+static long __compat_sys_preadv64(unsigned long fd,
+ const struct compat_iovec __user *vec,
+ unsigned long vlen, loff_t pos)
{
struct fd f;
ssize_t ret;
@@ -1001,12 +1013,22 @@ COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd,
return ret;
}
+#ifdef __ARCH_WANT_COMPAT_SYS_PREADV64
+COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd,
+ const struct compat_iovec __user *,vec,
+ unsigned long, vlen, loff_t, pos)
+{
+ return __compat_sys_preadv64(fd, vec, vlen, pos);
+}
+#endif
+
COMPAT_SYSCALL_DEFINE5(preadv, compat_ulong_t, fd,
const struct compat_iovec __user *,vec,
compat_ulong_t, vlen, u32, pos_low, u32, pos_high)
{
loff_t pos = ((loff_t)pos_high << 32) | pos_low;
- return compat_sys_preadv64(fd, vec, vlen, pos);
+
+ return __compat_sys_preadv64(fd, vec, vlen, pos);
}
static size_t compat_writev(struct file *file,
@@ -1035,7 +1057,7 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,
const struct compat_iovec __user *, vec,
compat_ulong_t, vlen)
{
- struct fd f = fdget(fd);
+ struct fd f = fdget_pos(fd);
ssize_t ret;
loff_t pos;
@@ -1045,13 +1067,13 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,
ret = compat_writev(f.file, vec, vlen, &pos);
if (ret >= 0)
f.file->f_pos = pos;
- fdput(f);
+ fdput_pos(f);
return ret;
}
-COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd,
- const struct compat_iovec __user *,vec,
- unsigned long, vlen, loff_t, pos)
+static long __compat_sys_pwritev64(unsigned long fd,
+ const struct compat_iovec __user *vec,
+ unsigned long vlen, loff_t pos)
{
struct fd f;
ssize_t ret;
@@ -1068,12 +1090,22 @@ COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd,
return ret;
}
+#ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64
+COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd,
+ const struct compat_iovec __user *,vec,
+ unsigned long, vlen, loff_t, pos)
+{
+ return __compat_sys_pwritev64(fd, vec, vlen, pos);
+}
+#endif
+
COMPAT_SYSCALL_DEFINE5(pwritev, compat_ulong_t, fd,
const struct compat_iovec __user *,vec,
compat_ulong_t, vlen, u32, pos_low, u32, pos_high)
{
loff_t pos = ((loff_t)pos_high << 32) | pos_low;
- return compat_sys_pwritev64(fd, vec, vlen, pos);
+
+ return __compat_sys_pwritev64(fd, vec, vlen, pos);
}
#endif
diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c
index 2b7882b508db..9a3c68cf6026 100644
--- a/fs/reiserfs/do_balan.c
+++ b/fs/reiserfs/do_balan.c
@@ -324,23 +324,17 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
switch (flag) {
case M_INSERT: /* insert item into L[0] */
- if (item_pos == tb->lnum[0] - 1
- && tb->lbytes != -1) {
+ if (item_pos == tb->lnum[0] - 1 && tb->lbytes != -1) {
/* part of new item falls into L[0] */
int new_item_len;
int version;
- ret_val =
- leaf_shift_left(tb, tb->lnum[0] - 1,
- -1);
+ ret_val = leaf_shift_left(tb, tb->lnum[0] - 1, -1);
/* Calculate item length to insert to S[0] */
- new_item_len =
- ih_item_len(ih) - tb->lbytes;
+ new_item_len = ih_item_len(ih) - tb->lbytes;
/* Calculate and check item length to insert to L[0] */
- put_ih_item_len(ih,
- ih_item_len(ih) -
- new_item_len);
+ put_ih_item_len(ih, ih_item_len(ih) - new_item_len);
RFALSE(ih_item_len(ih) <= 0,
"PAP-12080: there is nothing to insert into L[0]: ih_item_len=%d",
@@ -349,30 +343,18 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
/* Insert new item into L[0] */
buffer_info_init_left(tb, &bi);
leaf_insert_into_buf(&bi,
- n + item_pos -
- ret_val, ih, body,
- zeros_num >
- ih_item_len(ih) ?
- ih_item_len(ih) :
- zeros_num);
+ n + item_pos - ret_val, ih, body,
+ zeros_num > ih_item_len(ih) ? ih_item_len(ih) : zeros_num);
version = ih_version(ih);
/* Calculate key component, item length and body to insert into S[0] */
- set_le_ih_k_offset(ih,
- le_ih_k_offset(ih) +
- (tb->
- lbytes <<
- (is_indirect_le_ih
- (ih) ? tb->tb_sb->
- s_blocksize_bits -
- UNFM_P_SHIFT :
- 0)));
+ set_le_ih_k_offset(ih, le_ih_k_offset(ih) +
+ (tb-> lbytes << (is_indirect_le_ih(ih) ? tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT : 0)));
put_ih_item_len(ih, new_item_len);
if (tb->lbytes > zeros_num) {
- body +=
- (tb->lbytes - zeros_num);
+ body += (tb->lbytes - zeros_num);
zeros_num = 0;
} else
zeros_num -= tb->lbytes;
@@ -383,15 +365,10 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
} else {
/* new item in whole falls into L[0] */
/* Shift lnum[0]-1 items to L[0] */
- ret_val =
- leaf_shift_left(tb, tb->lnum[0] - 1,
- tb->lbytes);
+ ret_val = leaf_shift_left(tb, tb->lnum[0] - 1, tb->lbytes);
/* Insert new item into L[0] */
buffer_info_init_left(tb, &bi);
- leaf_insert_into_buf(&bi,
- n + item_pos -
- ret_val, ih, body,
- zeros_num);
+ leaf_insert_into_buf(&bi, n + item_pos - ret_val, ih, body, zeros_num);
tb->insert_size[0] = 0;
zeros_num = 0;
}
@@ -399,264 +376,117 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
case M_PASTE: /* append item in L[0] */
- if (item_pos == tb->lnum[0] - 1
- && tb->lbytes != -1) {
+ if (item_pos == tb->lnum[0] - 1 && tb->lbytes != -1) {
/* we must shift the part of the appended item */
- if (is_direntry_le_ih
- (B_N_PITEM_HEAD(tbS0, item_pos))) {
+ if (is_direntry_le_ih(B_N_PITEM_HEAD(tbS0, item_pos))) {
RFALSE(zeros_num,
"PAP-12090: invalid parameter in case of a directory");
/* directory item */
if (tb->lbytes > pos_in_item) {
/* new directory entry falls into L[0] */
- struct item_head
- *pasted;
- int l_pos_in_item =
- pos_in_item;
+ struct item_head *pasted;
+ int l_pos_in_item = pos_in_item;
/* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 entries from given directory item */
- ret_val =
- leaf_shift_left(tb,
- tb->
- lnum
- [0],
- tb->
- lbytes
- -
- 1);
- if (ret_val
- && !item_pos) {
- pasted =
- B_N_PITEM_HEAD
- (tb->L[0],
- B_NR_ITEMS
- (tb->
- L[0]) -
- 1);
- l_pos_in_item +=
- I_ENTRY_COUNT
- (pasted) -
- (tb->
- lbytes -
- 1);
+ ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes-1);
+ if (ret_val && !item_pos) {
+ pasted = B_N_PITEM_HEAD(tb->L[0], B_NR_ITEMS(tb->L[0]) - 1);
+ l_pos_in_item += I_ENTRY_COUNT(pasted) - (tb->lbytes -1);
}
/* Append given directory entry to directory item */
buffer_info_init_left(tb, &bi);
- leaf_paste_in_buffer
- (&bi,
- n + item_pos -
- ret_val,
- l_pos_in_item,
- tb->insert_size[0],
- body, zeros_num);
+ leaf_paste_in_buffer(&bi, n + item_pos - ret_val, l_pos_in_item, tb->insert_size[0], body, zeros_num);
/* previous string prepared space for pasting new entry, following string pastes this entry */
/* when we have merge directory item, pos_in_item has been changed too */
/* paste new directory entry. 1 is entry number */
- leaf_paste_entries(&bi,
- n +
- item_pos
- -
- ret_val,
- l_pos_in_item,
- 1,
- (struct
- reiserfs_de_head
- *)
- body,
- body
- +
- DEH_SIZE,
- tb->
- insert_size
- [0]
- );
+ leaf_paste_entries(&bi, n + item_pos - ret_val, l_pos_in_item,
+ 1, (struct reiserfs_de_head *) body,
+ body + DEH_SIZE, tb->insert_size[0]);
tb->insert_size[0] = 0;
} else {
/* new directory item doesn't fall into L[0] */
/* Shift lnum[0]-1 items in whole. Shift lbytes directory entries from directory item number lnum[0] */
- leaf_shift_left(tb,
- tb->
- lnum[0],
- tb->
- lbytes);
+ leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
}
/* Calculate new position to append in item body */
pos_in_item -= tb->lbytes;
} else {
/* regular object */
- RFALSE(tb->lbytes <= 0,
- "PAP-12095: there is nothing to shift to L[0]. lbytes=%d",
- tb->lbytes);
- RFALSE(pos_in_item !=
- ih_item_len
- (B_N_PITEM_HEAD
- (tbS0, item_pos)),
+ RFALSE(tb->lbytes <= 0, "PAP-12095: there is nothing to shift to L[0]. lbytes=%d", tb->lbytes);
+ RFALSE(pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)),
"PAP-12100: incorrect position to paste: item_len=%d, pos_in_item=%d",
- ih_item_len
- (B_N_PITEM_HEAD
- (tbS0, item_pos)),
- pos_in_item);
+ ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)),pos_in_item);
if (tb->lbytes >= pos_in_item) {
/* appended item will be in L[0] in whole */
int l_n;
/* this bytes number must be appended to the last item of L[h] */
- l_n =
- tb->lbytes -
- pos_in_item;
+ l_n = tb->lbytes - pos_in_item;
/* Calculate new insert_size[0] */
- tb->insert_size[0] -=
- l_n;
+ tb->insert_size[0] -= l_n;
- RFALSE(tb->
- insert_size[0] <=
- 0,
+ RFALSE(tb->insert_size[0] <= 0,
"PAP-12105: there is nothing to paste into L[0]. insert_size=%d",
- tb->
- insert_size[0]);
- ret_val =
- leaf_shift_left(tb,
- tb->
- lnum
- [0],
- ih_item_len
- (B_N_PITEM_HEAD
- (tbS0,
- item_pos)));
+ tb->insert_size[0]);
+ ret_val = leaf_shift_left(tb, tb->lnum[0], ih_item_len
+ (B_N_PITEM_HEAD(tbS0, item_pos)));
/* Append to body of item in L[0] */
buffer_info_init_left(tb, &bi);
leaf_paste_in_buffer
- (&bi,
- n + item_pos -
- ret_val,
- ih_item_len
- (B_N_PITEM_HEAD
- (tb->L[0],
- n + item_pos -
- ret_val)), l_n,
- body,
- zeros_num >
- l_n ? l_n :
- zeros_num);
+ (&bi, n + item_pos - ret_val, ih_item_len
+ (B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val)),
+ l_n, body,
+ zeros_num > l_n ? l_n : zeros_num);
/* 0-th item in S0 can be only of DIRECT type when l_n != 0 */
{
int version;
- int temp_l =
- l_n;
-
- RFALSE
- (ih_item_len
- (B_N_PITEM_HEAD
- (tbS0,
- 0)),
+ int temp_l = l_n;
+
+ RFALSE(ih_item_len(B_N_PITEM_HEAD(tbS0, 0)),
"PAP-12106: item length must be 0");
- RFALSE
- (comp_short_le_keys
- (B_N_PKEY
- (tbS0, 0),
- B_N_PKEY
- (tb->L[0],
- n +
- item_pos
- -
- ret_val)),
+ RFALSE(comp_short_le_keys(B_N_PKEY(tbS0, 0), B_N_PKEY
+ (tb->L[0], n + item_pos - ret_val)),
"PAP-12107: items must be of the same file");
if (is_indirect_le_ih(B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val))) {
- temp_l =
- l_n
- <<
- (tb->
- tb_sb->
- s_blocksize_bits
- -
- UNFM_P_SHIFT);
+ temp_l = l_n << (tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT);
}
/* update key of first item in S0 */
- version =
- ih_version
- (B_N_PITEM_HEAD
- (tbS0, 0));
- set_le_key_k_offset
- (version,
- B_N_PKEY
- (tbS0, 0),
- le_key_k_offset
- (version,
- B_N_PKEY
- (tbS0,
- 0)) +
- temp_l);
+ version = ih_version(B_N_PITEM_HEAD(tbS0, 0));
+ set_le_key_k_offset(version, B_N_PKEY(tbS0, 0),
+ le_key_k_offset(version,B_N_PKEY(tbS0, 0)) + temp_l);
/* update left delimiting key */
- set_le_key_k_offset
- (version,
- B_N_PDELIM_KEY
- (tb->
- CFL[0],
- tb->
- lkey[0]),
- le_key_k_offset
- (version,
- B_N_PDELIM_KEY
- (tb->
- CFL[0],
- tb->
- lkey[0]))
- + temp_l);
+ set_le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]),
+ le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0])) + temp_l);
}
/* Calculate new body, position in item and insert_size[0] */
if (l_n > zeros_num) {
- body +=
- (l_n -
- zeros_num);
+ body += (l_n - zeros_num);
zeros_num = 0;
} else
- zeros_num -=
- l_n;
+ zeros_num -= l_n;
pos_in_item = 0;
- RFALSE
- (comp_short_le_keys
- (B_N_PKEY(tbS0, 0),
- B_N_PKEY(tb->L[0],
- B_NR_ITEMS
- (tb->
- L[0]) -
- 1))
- ||
- !op_is_left_mergeable
- (B_N_PKEY(tbS0, 0),
- tbS0->b_size)
- ||
- !op_is_left_mergeable
- (B_N_PDELIM_KEY
- (tb->CFL[0],
- tb->lkey[0]),
- tbS0->b_size),
+ RFALSE(comp_short_le_keys(B_N_PKEY(tbS0, 0), B_N_PKEY(tb->L[0], B_NR_ITEMS(tb->L[0]) - 1))
+ || !op_is_left_mergeable(B_N_PKEY(tbS0, 0), tbS0->b_size)
+ || !op_is_left_mergeable(B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]), tbS0->b_size),
"PAP-12120: item must be merge-able with left neighboring item");
} else { /* only part of the appended item will be in L[0] */
/* Calculate position in item for append in S[0] */
- pos_in_item -=
- tb->lbytes;
+ pos_in_item -= tb->lbytes;
- RFALSE(pos_in_item <= 0,
- "PAP-12125: no place for paste. pos_in_item=%d",
- pos_in_item);
+ RFALSE(pos_in_item <= 0, "PAP-12125: no place for paste. pos_in_item=%d", pos_in_item);
/* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
- leaf_shift_left(tb,
- tb->
- lnum[0],
- tb->
- lbytes);
+ leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
}
}
} else { /* appended item will be in L[0] in whole */
@@ -665,52 +495,30 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
if (!item_pos && op_is_left_mergeable(B_N_PKEY(tbS0, 0), tbS0->b_size)) { /* if we paste into first item of S[0] and it is left mergable */
/* then increment pos_in_item by the size of the last item in L[0] */
- pasted =
- B_N_PITEM_HEAD(tb->L[0],
- n - 1);
+ pasted = B_N_PITEM_HEAD(tb->L[0], n - 1);
if (is_direntry_le_ih(pasted))
- pos_in_item +=
- ih_entry_count
- (pasted);
+ pos_in_item += ih_entry_count(pasted);
else
- pos_in_item +=
- ih_item_len(pasted);
+ pos_in_item += ih_item_len(pasted);
}
/* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
- ret_val =
- leaf_shift_left(tb, tb->lnum[0],
- tb->lbytes);
+ ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
/* Append to body of item in L[0] */
buffer_info_init_left(tb, &bi);
- leaf_paste_in_buffer(&bi,
- n + item_pos -
- ret_val,
+ leaf_paste_in_buffer(&bi, n + item_pos - ret_val,
pos_in_item,
tb->insert_size[0],
body, zeros_num);
/* if appended item is directory, paste entry */
- pasted =
- B_N_PITEM_HEAD(tb->L[0],
- n + item_pos -
- ret_val);
+ pasted = B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val);
if (is_direntry_le_ih(pasted))
- leaf_paste_entries(&bi,
- n +
- item_pos -
- ret_val,
- pos_in_item,
- 1,
- (struct
- reiserfs_de_head
- *)body,
- body +
- DEH_SIZE,
- tb->
- insert_size
- [0]
- );
+ leaf_paste_entries(&bi, n + item_pos - ret_val,
+ pos_in_item, 1,
+ (struct reiserfs_de_head *) body,
+ body + DEH_SIZE,
+ tb->insert_size[0]);
/* if appended item is indirect item, put unformatted node into un list */
if (is_indirect_le_ih(pasted))
set_ih_free_space(pasted, 0);
@@ -722,13 +530,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
reiserfs_panic(tb->tb_sb, "PAP-12130",
"lnum > 0: unexpected mode: "
" %s(%d)",
- (flag ==
- M_DELETE) ? "DELETE" : ((flag ==
- M_CUT)
- ? "CUT"
- :
- "UNKNOWN"),
- flag);
+ (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
}
} else {
/* new item doesn't fall into L[0] */
@@ -748,14 +550,12 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
case M_INSERT: /* insert item */
if (n - tb->rnum[0] < item_pos) { /* new item or its part falls to R[0] */
if (item_pos == n - tb->rnum[0] + 1 && tb->rbytes != -1) { /* part of new item falls into R[0] */
- loff_t old_key_comp, old_len,
- r_zeros_number;
+ loff_t old_key_comp, old_len, r_zeros_number;
const char *r_body;
int version;
loff_t offset;
- leaf_shift_right(tb, tb->rnum[0] - 1,
- -1);
+ leaf_shift_right(tb, tb->rnum[0] - 1, -1);
version = ih_version(ih);
/* Remember key component and item length */
@@ -763,29 +563,17 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
old_len = ih_item_len(ih);
/* Calculate key component and item length to insert into R[0] */
- offset =
- le_ih_k_offset(ih) +
- ((old_len -
- tb->
- rbytes) << (is_indirect_le_ih(ih)
- ? tb->tb_sb->
- s_blocksize_bits -
- UNFM_P_SHIFT : 0));
+ offset = le_ih_k_offset(ih) + ((old_len - tb->rbytes) << (is_indirect_le_ih(ih) ? tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT : 0));
set_le_ih_k_offset(ih, offset);
put_ih_item_len(ih, tb->rbytes);
/* Insert part of the item into R[0] */
buffer_info_init_right(tb, &bi);
if ((old_len - tb->rbytes) > zeros_num) {
r_zeros_number = 0;
- r_body =
- body + (old_len -
- tb->rbytes) -
- zeros_num;
+ r_body = body + (old_len - tb->rbytes) - zeros_num;
} else {
r_body = body;
- r_zeros_number =
- zeros_num - (old_len -
- tb->rbytes);
+ r_zeros_number = zeros_num - (old_len - tb->rbytes);
zeros_num -= r_zeros_number;
}
@@ -798,25 +586,18 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
/* Calculate key component and item length to insert into S[0] */
set_le_ih_k_offset(ih, old_key_comp);
- put_ih_item_len(ih,
- old_len - tb->rbytes);
+ put_ih_item_len(ih, old_len - tb->rbytes);
tb->insert_size[0] -= tb->rbytes;
} else { /* whole new item falls into R[0] */
/* Shift rnum[0]-1 items to R[0] */
- ret_val =
- leaf_shift_right(tb,
- tb->rnum[0] - 1,
- tb->rbytes);
+ ret_val = leaf_shift_right(tb, tb->rnum[0] - 1, tb->rbytes);
/* Insert new item into R[0] */
buffer_info_init_right(tb, &bi);
- leaf_insert_into_buf(&bi,
- item_pos - n +
- tb->rnum[0] - 1,
- ih, body,
- zeros_num);
+ leaf_insert_into_buf(&bi, item_pos - n + tb->rnum[0] - 1,
+ ih, body, zeros_num);
if (item_pos - n + tb->rnum[0] - 1 == 0) {
replace_key(tb, tb->CFR[0],
@@ -841,200 +622,97 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
RFALSE(zeros_num,
"PAP-12145: invalid parameter in case of a directory");
- entry_count =
- I_ENTRY_COUNT(B_N_PITEM_HEAD
- (tbS0,
- item_pos));
+ entry_count = I_ENTRY_COUNT(B_N_PITEM_HEAD
+ (tbS0, item_pos));
if (entry_count - tb->rbytes <
pos_in_item)
/* new directory entry falls into R[0] */
{
int paste_entry_position;
- RFALSE(tb->rbytes - 1 >=
- entry_count
- || !tb->
- insert_size[0],
+ RFALSE(tb->rbytes - 1 >= entry_count || !tb-> insert_size[0],
"PAP-12150: no enough of entries to shift to R[0]: rbytes=%d, entry_count=%d",
- tb->rbytes,
- entry_count);
+ tb->rbytes, entry_count);
/* Shift rnum[0]-1 items in whole. Shift rbytes-1 directory entries from directory item number rnum[0] */
- leaf_shift_right(tb,
- tb->
- rnum
- [0],
- tb->
- rbytes
- - 1);
+ leaf_shift_right(tb, tb->rnum[0], tb->rbytes - 1);
/* Paste given directory entry to directory item */
- paste_entry_position =
- pos_in_item -
- entry_count +
- tb->rbytes - 1;
+ paste_entry_position = pos_in_item - entry_count + tb->rbytes - 1;
buffer_info_init_right(tb, &bi);
- leaf_paste_in_buffer
- (&bi, 0,
- paste_entry_position,
- tb->insert_size[0],
- body, zeros_num);
+ leaf_paste_in_buffer(&bi, 0, paste_entry_position, tb->insert_size[0], body, zeros_num);
/* paste entry */
- leaf_paste_entries(&bi,
- 0,
- paste_entry_position,
- 1,
- (struct
- reiserfs_de_head
- *)
- body,
- body
- +
- DEH_SIZE,
- tb->
- insert_size
- [0]
- );
-
- if (paste_entry_position
- == 0) {
+ leaf_paste_entries(&bi, 0, paste_entry_position, 1,
+ (struct reiserfs_de_head *) body,
+ body + DEH_SIZE, tb->insert_size[0]);
+
+ if (paste_entry_position == 0) {
/* change delimiting keys */
- replace_key(tb,
- tb->
- CFR
- [0],
- tb->
- rkey
- [0],
- tb->
- R
- [0],
- 0);
+ replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0],0);
}
tb->insert_size[0] = 0;
pos_in_item++;
} else { /* new directory entry doesn't fall into R[0] */
- leaf_shift_right(tb,
- tb->
- rnum
- [0],
- tb->
- rbytes);
+ leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
}
} else { /* regular object */
- int n_shift, n_rem,
- r_zeros_number;
+ int n_shift, n_rem, r_zeros_number;
const char *r_body;
/* Calculate number of bytes which must be shifted from appended item */
- if ((n_shift =
- tb->rbytes -
- tb->insert_size[0]) < 0)
+ if ((n_shift = tb->rbytes - tb->insert_size[0]) < 0)
n_shift = 0;
- RFALSE(pos_in_item !=
- ih_item_len
- (B_N_PITEM_HEAD
- (tbS0, item_pos)),
+ RFALSE(pos_in_item != ih_item_len
+ (B_N_PITEM_HEAD(tbS0, item_pos)),
"PAP-12155: invalid position to paste. ih_item_len=%d, pos_in_item=%d",
- pos_in_item,
- ih_item_len
- (B_N_PITEM_HEAD
- (tbS0, item_pos)));
-
- leaf_shift_right(tb,
- tb->rnum[0],
- n_shift);
+ pos_in_item, ih_item_len
+ (B_N_PITEM_HEAD(tbS0, item_pos)));
+
+ leaf_shift_right(tb, tb->rnum[0], n_shift);
/* Calculate number of bytes which must remain in body after appending to R[0] */
- if ((n_rem =
- tb->insert_size[0] -
- tb->rbytes) < 0)
+ if ((n_rem = tb->insert_size[0] - tb->rbytes) < 0)
n_rem = 0;
{
int version;
- unsigned long temp_rem =
- n_rem;
-
- version =
- ih_version
- (B_N_PITEM_HEAD
- (tb->R[0], 0));
- if (is_indirect_le_key
- (version,
- B_N_PKEY(tb->R[0],
- 0))) {
- temp_rem =
- n_rem <<
- (tb->tb_sb->
- s_blocksize_bits
- -
- UNFM_P_SHIFT);
+ unsigned long temp_rem = n_rem;
+
+ version = ih_version(B_N_PITEM_HEAD(tb->R[0], 0));
+ if (is_indirect_le_key(version, B_N_PKEY(tb->R[0], 0))) {
+ temp_rem = n_rem << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT);
}
- set_le_key_k_offset
- (version,
- B_N_PKEY(tb->R[0],
- 0),
- le_key_k_offset
- (version,
- B_N_PKEY(tb->R[0],
- 0)) +
- temp_rem);
- set_le_key_k_offset
- (version,
- B_N_PDELIM_KEY(tb->
- CFR
- [0],
- tb->
- rkey
- [0]),
- le_key_k_offset
- (version,
- B_N_PDELIM_KEY
- (tb->CFR[0],
- tb->rkey[0])) +
- temp_rem);
+ set_le_key_k_offset(version, B_N_PKEY(tb->R[0], 0),
+ le_key_k_offset(version, B_N_PKEY(tb->R[0], 0)) + temp_rem);
+ set_le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0]),
+ le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0])) + temp_rem);
}
/* k_offset (B_N_PKEY(tb->R[0],0)) += n_rem;
k_offset (B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) += n_rem;*/
- do_balance_mark_internal_dirty
- (tb, tb->CFR[0], 0);
+ do_balance_mark_internal_dirty(tb, tb->CFR[0], 0);
/* Append part of body into R[0] */
buffer_info_init_right(tb, &bi);
if (n_rem > zeros_num) {
r_zeros_number = 0;
- r_body =
- body + n_rem -
- zeros_num;
+ r_body = body + n_rem - zeros_num;
} else {
r_body = body;
- r_zeros_number =
- zeros_num - n_rem;
- zeros_num -=
- r_zeros_number;
+ r_zeros_number = zeros_num - n_rem;
+ zeros_num -= r_zeros_number;
}
- leaf_paste_in_buffer(&bi, 0,
- n_shift,
- tb->
- insert_size
- [0] -
- n_rem,
- r_body,
- r_zeros_number);
-
- if (is_indirect_le_ih
- (B_N_PITEM_HEAD
- (tb->R[0], 0))) {
+ leaf_paste_in_buffer(&bi, 0, n_shift,
+ tb->insert_size[0] - n_rem,
+ r_body, r_zeros_number);
+
+ if (is_indirect_le_ih(B_N_PITEM_HEAD(tb->R[0], 0))) {
#if 0
RFALSE(n_rem,
"PAP-12160: paste more than one unformatted node pointer");
#endif
- set_ih_free_space
- (B_N_PITEM_HEAD
- (tb->R[0], 0), 0);
+ set_ih_free_space(B_N_PITEM_HEAD(tb->R[0], 0), 0);
}
tb->insert_size[0] = n_rem;
if (!n_rem)
@@ -1044,58 +722,28 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
struct item_head *pasted;
- ret_val =
- leaf_shift_right(tb, tb->rnum[0],
- tb->rbytes);
+ ret_val = leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
/* append item in R[0] */
if (pos_in_item >= 0) {
buffer_info_init_right(tb, &bi);
- leaf_paste_in_buffer(&bi,
- item_pos -
- n +
- tb->
- rnum[0],
- pos_in_item,
- tb->
- insert_size
- [0], body,
- zeros_num);
+ leaf_paste_in_buffer(&bi, item_pos - n + tb->rnum[0], pos_in_item,
+ tb->insert_size[0], body, zeros_num);
}
/* paste new entry, if item is directory item */
- pasted =
- B_N_PITEM_HEAD(tb->R[0],
- item_pos - n +
- tb->rnum[0]);
- if (is_direntry_le_ih(pasted)
- && pos_in_item >= 0) {
- leaf_paste_entries(&bi,
- item_pos -
- n +
- tb->rnum[0],
- pos_in_item,
- 1,
- (struct
- reiserfs_de_head
- *)body,
- body +
- DEH_SIZE,
- tb->
- insert_size
- [0]
- );
+ pasted = B_N_PITEM_HEAD(tb->R[0], item_pos - n + tb->rnum[0]);
+ if (is_direntry_le_ih(pasted) && pos_in_item >= 0) {
+ leaf_paste_entries(&bi, item_pos - n + tb->rnum[0],
+ pos_in_item, 1,
+ (struct reiserfs_de_head *) body,
+ body + DEH_SIZE, tb->insert_size[0]);
if (!pos_in_item) {
- RFALSE(item_pos - n +
- tb->rnum[0],
+ RFALSE(item_pos - n + tb->rnum[0],
"PAP-12165: directory item must be first item of node when pasting is in 0th position");
/* update delimiting keys */
- replace_key(tb,
- tb->CFR[0],
- tb->rkey[0],
- tb->R[0],
- 0);
+ replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
}
}
@@ -1111,22 +759,16 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
default: /* cases d and t */
reiserfs_panic(tb->tb_sb, "PAP-12175",
"rnum > 0: unexpected mode: %s(%d)",
- (flag ==
- M_DELETE) ? "DELETE" : ((flag ==
- M_CUT) ? "CUT"
- : "UNKNOWN"),
- flag);
+ (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
}
}
/* tb->rnum[0] > 0 */
RFALSE(tb->blknum[0] > 3,
- "PAP-12180: blknum can not be %d. It must be <= 3",
- tb->blknum[0]);
+ "PAP-12180: blknum can not be %d. It must be <= 3", tb->blknum[0]);
RFALSE(tb->blknum[0] < 0,
- "PAP-12185: blknum can not be %d. It must be >= 0",
- tb->blknum[0]);
+ "PAP-12185: blknum can not be %d. It must be >= 0", tb->blknum[0]);
/* if while adding to a node we discover that it is possible to split
it in two, and merge the left part into the left neighbor and the
@@ -1177,8 +819,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
if (n - snum[i] < item_pos) { /* new item or it's part falls to first new node S_new[i] */
if (item_pos == n - snum[i] + 1 && sbytes[i] != -1) { /* part of new item falls into S_new[i] */
- int old_key_comp, old_len,
- r_zeros_number;
+ int old_key_comp, old_len, r_zeros_number;
const char *r_body;
int version;
@@ -1192,15 +833,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
old_len = ih_item_len(ih);
/* Calculate key component and item length to insert into S_new[i] */
- set_le_ih_k_offset(ih,
- le_ih_k_offset(ih) +
- ((old_len -
- sbytes[i]) <<
- (is_indirect_le_ih
- (ih) ? tb->tb_sb->
- s_blocksize_bits -
- UNFM_P_SHIFT :
- 0)));
+ set_le_ih_k_offset(ih, le_ih_k_offset(ih) +
+ ((old_len - sbytes[i]) << (is_indirect_le_ih(ih) ? tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT : 0)));
put_ih_item_len(ih, sbytes[i]);
@@ -1209,39 +843,29 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
if ((old_len - sbytes[i]) > zeros_num) {
r_zeros_number = 0;
- r_body =
- body + (old_len -
- sbytes[i]) -
- zeros_num;
+ r_body = body + (old_len - sbytes[i]) - zeros_num;
} else {
r_body = body;
- r_zeros_number =
- zeros_num - (old_len -
- sbytes[i]);
+ r_zeros_number = zeros_num - (old_len - sbytes[i]);
zeros_num -= r_zeros_number;
}
- leaf_insert_into_buf(&bi, 0, ih, r_body,
- r_zeros_number);
+ leaf_insert_into_buf(&bi, 0, ih, r_body, r_zeros_number);
/* Calculate key component and item length to insert into S[i] */
set_le_ih_k_offset(ih, old_key_comp);
- put_ih_item_len(ih,
- old_len - sbytes[i]);
+ put_ih_item_len(ih, old_len - sbytes[i]);
tb->insert_size[0] -= sbytes[i];
} else { /* whole new item falls into S_new[i] */
/* Shift snum[0] - 1 items to S_new[i] (sbytes[i] of split item) */
leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
- snum[i] - 1, sbytes[i],
- S_new[i]);
+ snum[i] - 1, sbytes[i], S_new[i]);
/* Insert new item into S_new[i] */
buffer_info_init_bh(tb, &bi, S_new[i]);
- leaf_insert_into_buf(&bi,
- item_pos - n +
- snum[i] - 1, ih,
- body, zeros_num);
+ leaf_insert_into_buf(&bi, item_pos - n + snum[i] - 1,
+ ih, body, zeros_num);
zeros_num = tb->insert_size[0] = 0;
}
@@ -1268,150 +892,73 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
int entry_count;
- entry_count =
- ih_entry_count(aux_ih);
+ entry_count = ih_entry_count(aux_ih);
- if (entry_count - sbytes[i] <
- pos_in_item
- && pos_in_item <=
- entry_count) {
+ if (entry_count - sbytes[i] < pos_in_item && pos_in_item <= entry_count) {
/* new directory entry falls into S_new[i] */
- RFALSE(!tb->
- insert_size[0],
- "PAP-12215: insert_size is already 0");
- RFALSE(sbytes[i] - 1 >=
- entry_count,
+ RFALSE(!tb->insert_size[0], "PAP-12215: insert_size is already 0");
+ RFALSE(sbytes[i] - 1 >= entry_count,
"PAP-12220: there are no so much entries (%d), only %d",
- sbytes[i] - 1,
- entry_count);
+ sbytes[i] - 1, entry_count);
/* Shift snum[i]-1 items in whole. Shift sbytes[i] directory entries from directory item number snum[i] */
- leaf_move_items
- (LEAF_FROM_S_TO_SNEW,
- tb, snum[i],
- sbytes[i] - 1,
- S_new[i]);
+ leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i] - 1, S_new[i]);
/* Paste given directory entry to directory item */
buffer_info_init_bh(tb, &bi, S_new[i]);
- leaf_paste_in_buffer
- (&bi, 0,
- pos_in_item -
- entry_count +
- sbytes[i] - 1,
- tb->insert_size[0],
- body, zeros_num);
+ leaf_paste_in_buffer(&bi, 0, pos_in_item - entry_count + sbytes[i] - 1,
+ tb->insert_size[0], body, zeros_num);
/* paste new directory entry */
- leaf_paste_entries(&bi,
- 0,
- pos_in_item
- -
- entry_count
- +
- sbytes
- [i] -
- 1, 1,
- (struct
- reiserfs_de_head
- *)
- body,
- body
- +
- DEH_SIZE,
- tb->
- insert_size
- [0]
- );
+ leaf_paste_entries(&bi, 0, pos_in_item - entry_count + sbytes[i] - 1, 1,
+ (struct reiserfs_de_head *) body,
+ body + DEH_SIZE, tb->insert_size[0]);
tb->insert_size[0] = 0;
pos_in_item++;
} else { /* new directory entry doesn't fall into S_new[i] */
- leaf_move_items
- (LEAF_FROM_S_TO_SNEW,
- tb, snum[i],
- sbytes[i],
- S_new[i]);
+ leaf_move_items(LEAF_FROM_S_TO_SNEW,tb, snum[i], sbytes[i], S_new[i]);
}
} else { /* regular object */
- int n_shift, n_rem,
- r_zeros_number;
+ int n_shift, n_rem, r_zeros_number;
const char *r_body;
- RFALSE(pos_in_item !=
- ih_item_len
- (B_N_PITEM_HEAD
- (tbS0, item_pos))
- || tb->insert_size[0] <=
- 0,
+ RFALSE(pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)) || tb->insert_size[0] <= 0,
"PAP-12225: item too short or insert_size <= 0");
/* Calculate number of bytes which must be shifted from appended item */
- n_shift =
- sbytes[i] -
- tb->insert_size[0];
+ n_shift = sbytes[i] - tb->insert_size[0];
if (n_shift < 0)
n_shift = 0;
- leaf_move_items
- (LEAF_FROM_S_TO_SNEW, tb,
- snum[i], n_shift,
- S_new[i]);
+ leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, snum[i], n_shift, S_new[i]);
/* Calculate number of bytes which must remain in body after append to S_new[i] */
- n_rem =
- tb->insert_size[0] -
- sbytes[i];
+ n_rem = tb->insert_size[0] - sbytes[i];
if (n_rem < 0)
n_rem = 0;
/* Append part of body into S_new[0] */
buffer_info_init_bh(tb, &bi, S_new[i]);
if (n_rem > zeros_num) {
r_zeros_number = 0;
- r_body =
- body + n_rem -
- zeros_num;
+ r_body = body + n_rem - zeros_num;
} else {
r_body = body;
- r_zeros_number =
- zeros_num - n_rem;
- zeros_num -=
- r_zeros_number;
+ r_zeros_number = zeros_num - n_rem;
+ zeros_num -= r_zeros_number;
}
- leaf_paste_in_buffer(&bi, 0,
- n_shift,
- tb->
- insert_size
- [0] -
- n_rem,
- r_body,
- r_zeros_number);
+ leaf_paste_in_buffer(&bi, 0, n_shift,
+ tb->insert_size[0] - n_rem,
+ r_body, r_zeros_number);
{
struct item_head *tmp;
- tmp =
- B_N_PITEM_HEAD(S_new
- [i],
- 0);
+ tmp = B_N_PITEM_HEAD(S_new[i], 0);
if (is_indirect_le_ih
(tmp)) {
- set_ih_free_space
- (tmp, 0);
- set_le_ih_k_offset
- (tmp,
- le_ih_k_offset
- (tmp) +
- (n_rem <<
- (tb->
- tb_sb->
- s_blocksize_bits
- -
- UNFM_P_SHIFT)));
+ set_ih_free_space(tmp, 0);
+ set_le_ih_k_offset(tmp, le_ih_k_offset(tmp) + (n_rem << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT)));
} else {
- set_le_ih_k_offset
- (tmp,
- le_ih_k_offset
- (tmp) +
- n_rem);
+ set_le_ih_k_offset(tmp, le_ih_k_offset(tmp) + n_rem);
}
}
@@ -1426,8 +973,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
struct item_head *pasted;
#ifdef CONFIG_REISERFS_CHECK
- struct item_head *ih_check =
- B_N_PITEM_HEAD(tbS0, item_pos);
+ struct item_head *ih_check = B_N_PITEM_HEAD(tbS0, item_pos);
if (!is_direntry_le_ih(ih_check)
&& (pos_in_item != ih_item_len(ih_check)
@@ -1439,8 +985,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
"to ih_item_len");
#endif /* CONFIG_REISERFS_CHECK */
- leaf_mi =
- leaf_move_items(LEAF_FROM_S_TO_SNEW,
+ leaf_mi = leaf_move_items(LEAF_FROM_S_TO_SNEW,
tb, snum[i],
sbytes[i],
S_new[i]);
@@ -1452,30 +997,19 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
/* paste into item */
buffer_info_init_bh(tb, &bi, S_new[i]);
leaf_paste_in_buffer(&bi,
- item_pos - n +
- snum[i],
+ item_pos - n + snum[i],
pos_in_item,
tb->insert_size[0],
body, zeros_num);
- pasted =
- B_N_PITEM_HEAD(S_new[i],
- item_pos - n +
- snum[i]);
+ pasted = B_N_PITEM_HEAD(S_new[i], item_pos - n + snum[i]);
if (is_direntry_le_ih(pasted)) {
leaf_paste_entries(&bi,
- item_pos -
- n + snum[i],
- pos_in_item,
- 1,
- (struct
- reiserfs_de_head
- *)body,
- body +
- DEH_SIZE,
- tb->
- insert_size
- [0]
+ item_pos - n + snum[i],
+ pos_in_item, 1,
+ (struct reiserfs_de_head *)body,
+ body + DEH_SIZE,
+ tb->insert_size[0]
);
}
@@ -1495,11 +1029,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
default: /* cases d and t */
reiserfs_panic(tb->tb_sb, "PAP-12245",
"blknum > 2: unexpected mode: %s(%d)",
- (flag ==
- M_DELETE) ? "DELETE" : ((flag ==
- M_CUT) ? "CUT"
- : "UNKNOWN"),
- flag);
+ (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
}
memcpy(insert_key + i, B_N_PKEY(S_new[i], 0), KEY_SIZE);
@@ -1524,9 +1054,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
/* If we insert the first key change the delimiting key */
if (item_pos == 0) {
if (tb->CFL[0]) /* can be 0 in reiserfsck */
- replace_key(tb, tb->CFL[0], tb->lkey[0],
- tbS0, 0);
-
+ replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0);
}
break;
@@ -1536,53 +1064,27 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
pasted = B_N_PITEM_HEAD(tbS0, item_pos);
/* when directory, may be new entry already pasted */
if (is_direntry_le_ih(pasted)) {
- if (pos_in_item >= 0 &&
- pos_in_item <=
- ih_entry_count(pasted)) {
+ if (pos_in_item >= 0 && pos_in_item <= ih_entry_count(pasted)) {
RFALSE(!tb->insert_size[0],
"PAP-12260: insert_size is 0 already");
/* prepare space */
buffer_info_init_tbS0(tb, &bi);
- leaf_paste_in_buffer(&bi,
- item_pos,
- pos_in_item,
- tb->
- insert_size
- [0], body,
+ leaf_paste_in_buffer(&bi, item_pos, pos_in_item,
+ tb->insert_size[0], body,
zeros_num);
/* paste entry */
- leaf_paste_entries(&bi,
- item_pos,
- pos_in_item,
- 1,
- (struct
- reiserfs_de_head
- *)body,
- body +
- DEH_SIZE,
- tb->
- insert_size
- [0]
- );
+ leaf_paste_entries(&bi, item_pos, pos_in_item, 1,
+ (struct reiserfs_de_head *)body,
+ body + DEH_SIZE,
+ tb->insert_size[0]);
if (!item_pos && !pos_in_item) {
- RFALSE(!tb->CFL[0]
- || !tb->L[0],
+ RFALSE(!tb->CFL[0] || !tb->L[0],
"PAP-12270: CFL[0]/L[0] must be specified");
- if (tb->CFL[0]) {
- replace_key(tb,
- tb->
- CFL
- [0],
- tb->
- lkey
- [0],
- tbS0,
- 0);
-
- }
+ if (tb->CFL[0])
+ replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0);
}
tb->insert_size[0] = 0;
}
@@ -1593,13 +1095,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
"PAP-12275: insert size must not be %d",
tb->insert_size[0]);
buffer_info_init_tbS0(tb, &bi);
- leaf_paste_in_buffer(&bi,
- item_pos,
- pos_in_item,
- tb->
- insert_size
- [0], body,
- zeros_num);
+ leaf_paste_in_buffer(&bi, item_pos, pos_in_item,
+ tb->insert_size[0], body, zeros_num);
if (is_indirect_le_ih(pasted)) {
#if 0
@@ -1611,8 +1108,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
tb->
insert_size[0]);
#endif
- set_ih_free_space
- (pasted, 0);
+ set_ih_free_space(pasted, 0);
}
tb->insert_size[0] = 0;
}
@@ -1620,8 +1116,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h
else {
if (tb->insert_size[0]) {
print_cur_tb("12285");
- reiserfs_panic(tb->
- tb_sb,
+ reiserfs_panic(tb->tb_sb,
"PAP-12285",
"insert_size "
"must be 0 "
diff --git a/fs/sync.c b/fs/sync.c
index e8ba024a055b..b28d1dd10e8b 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -27,11 +27,10 @@
* wait == 1 case since in that case write_inode() functions do
* sync_dirty_buffer() and thus effectively write one block at a time.
*/
-static int __sync_filesystem(struct super_block *sb, int wait,
- unsigned long start)
+static int __sync_filesystem(struct super_block *sb, int wait)
{
if (wait)
- sync_inodes_sb(sb, start);
+ sync_inodes_sb(sb);
else
writeback_inodes_sb(sb, WB_REASON_SYNC);
@@ -48,7 +47,6 @@ static int __sync_filesystem(struct super_block *sb, int wait,
int sync_filesystem(struct super_block *sb)
{
int ret;
- unsigned long start = jiffies;
/*
* We need to be protected against the filesystem going from
@@ -62,17 +60,17 @@ int sync_filesystem(struct super_block *sb)
if (sb->s_flags & MS_RDONLY)
return 0;
- ret = __sync_filesystem(sb, 0, start);
+ ret = __sync_filesystem(sb, 0);
if (ret < 0)
return ret;
- return __sync_filesystem(sb, 1, start);
+ return __sync_filesystem(sb, 1);
}
EXPORT_SYMBOL_GPL(sync_filesystem);
static void sync_inodes_one_sb(struct super_block *sb, void *arg)
{
if (!(sb->s_flags & MS_RDONLY))
- sync_inodes_sb(sb, *((unsigned long *)arg));
+ sync_inodes_sb(sb);
}
static void sync_fs_one_sb(struct super_block *sb, void *arg)
@@ -104,10 +102,9 @@ static void fdatawait_one_bdev(struct block_device *bdev, void *arg)
SYSCALL_DEFINE0(sync)
{
int nowait = 0, wait = 1;
- unsigned long start = jiffies;
wakeup_flusher_threads(0, WB_REASON_SYNC);
- iterate_supers(sync_inodes_one_sb, &start);
+ iterate_supers(sync_inodes_one_sb, NULL);
iterate_supers(sync_fs_one_sb, &nowait);
iterate_supers(sync_fs_one_sb, &wait);
iterate_bdevs(fdatawrite_one_bdev, NULL);
diff --git a/fs/sysfs/Kconfig b/fs/sysfs/Kconfig
index 8c41feacbac5..b2756014508c 100644
--- a/fs/sysfs/Kconfig
+++ b/fs/sysfs/Kconfig
@@ -1,6 +1,7 @@
config SYSFS
bool "sysfs file system support" if EXPERT
default y
+ select KERNFS
help
The sysfs filesystem is a virtual filesystem that the kernel uses to
export internal kernel objects, their attributes, and their
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index ee0d761c3179..0b45ff42f374 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -19,39 +19,18 @@
DEFINE_SPINLOCK(sysfs_symlink_target_lock);
-/**
- * sysfs_pathname - return full path to sysfs dirent
- * @kn: kernfs_node whose path we want
- * @path: caller allocated buffer of size PATH_MAX
- *
- * Gives the name "/" to the sysfs_root entry; any path returned
- * is relative to wherever sysfs is mounted.
- */
-static char *sysfs_pathname(struct kernfs_node *kn, char *path)
-{
- if (kn->parent) {
- sysfs_pathname(kn->parent, path);
- strlcat(path, "/", PATH_MAX);
- }
- strlcat(path, kn->name, PATH_MAX);
- return path;
-}
-
void sysfs_warn_dup(struct kernfs_node *parent, const char *name)
{
- char *path;
+ char *buf, *path = NULL;
- path = kzalloc(PATH_MAX, GFP_KERNEL);
- if (path) {
- sysfs_pathname(parent, path);
- strlcat(path, "/", PATH_MAX);
- strlcat(path, name, PATH_MAX);
- }
+ buf = kzalloc(PATH_MAX, GFP_KERNEL);
+ if (buf)
+ path = kernfs_path(parent, buf, PATH_MAX);
- WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n",
- path ? path : name);
+ WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s/%s'\n",
+ path, name);
- kfree(path);
+ kfree(buf);
}
/**
@@ -122,9 +101,13 @@ void sysfs_remove_dir(struct kobject *kobj)
int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
const void *new_ns)
{
- struct kernfs_node *parent = kobj->sd->parent;
+ struct kernfs_node *parent;
+ int ret;
- return kernfs_rename_ns(kobj->sd, parent, new_name, new_ns);
+ parent = kernfs_get_parent(kobj->sd);
+ ret = kernfs_rename_ns(kobj->sd, parent, new_name, new_ns);
+ kernfs_put(parent);
+ return ret;
}
int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
@@ -133,7 +116,6 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
struct kernfs_node *kn = kobj->sd;
struct kernfs_node *new_parent;
- BUG_ON(!kn->parent);
new_parent = new_parent_kobj && new_parent_kobj->sd ?
new_parent_kobj->sd : sysfs_root_kn;
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 810cf6e613e5..1b8b91b67fdb 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -372,6 +372,29 @@ void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr,
}
EXPORT_SYMBOL_GPL(sysfs_remove_file_ns);
+/**
+ * sysfs_remove_file_self - remove an object attribute from its own method
+ * @kobj: object we're acting for
+ * @attr: attribute descriptor
+ *
+ * See kernfs_remove_self() for details.
+ */
+bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr)
+{
+ struct kernfs_node *parent = kobj->sd;
+ struct kernfs_node *kn;
+ bool ret;
+
+ kn = kernfs_find_and_get(parent, attr->name);
+ if (WARN_ON_ONCE(!kn))
+ return false;
+
+ ret = kernfs_remove_self(kn);
+
+ kernfs_put(kn);
+ return ret;
+}
+
void sysfs_remove_files(struct kobject *kobj, const struct attribute **ptr)
{
int i;
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 6b579387c67a..aa0406895b53 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -70,8 +70,11 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
if (grp->bin_attrs) {
for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) {
if (update)
- sysfs_remove_bin_file(kobj, *bin_attr);
- error = sysfs_create_bin_file(kobj, *bin_attr);
+ kernfs_remove_by_name(parent,
+ (*bin_attr)->attr.name);
+ error = sysfs_add_file_mode_ns(parent,
+ &(*bin_attr)->attr, true,
+ (*bin_attr)->attr.mode, NULL);
if (error)
break;
}
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 6211230814fd..a66ad6196f59 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -27,6 +27,7 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
{
struct dentry *root;
void *ns;
+ bool new_sb;
if (!(flags & MS_KERNMOUNT)) {
if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
@@ -37,8 +38,8 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
}
ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
- root = kernfs_mount_ns(fs_type, flags, sysfs_root, ns);
- if (IS_ERR(root))
+ root = kernfs_mount_ns(fs_type, flags, sysfs_root, &new_sb, ns);
+ if (IS_ERR(root) || !new_sb)
kobj_ns_drop(KOBJ_NS_TYPE_NET, ns);
return root;
}
@@ -62,7 +63,7 @@ int __init sysfs_init(void)
{
int err;
- sysfs_root = kernfs_create_root(NULL, NULL);
+ sysfs_root = kernfs_create_root(NULL, 0, NULL);
if (IS_ERR(sysfs_root))
return PTR_ERR(sysfs_root);
diff --git a/fs/timerfd.c b/fs/timerfd.c
index 929312180dd0..0013142c0475 100644
--- a/fs/timerfd.c
+++ b/fs/timerfd.c
@@ -317,6 +317,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
(clockid != CLOCK_MONOTONIC &&
clockid != CLOCK_REALTIME &&
clockid != CLOCK_REALTIME_ALARM &&
+ clockid != CLOCK_BOOTTIME &&
clockid != CLOCK_BOOTTIME_ALARM))
return -EINVAL;
diff --git a/fs/udf/file.c b/fs/udf/file.c
index c02a27a19c6d..1037637957c7 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -144,6 +144,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
size_t count = iocb->ki_nbytes;
struct udf_inode_info *iinfo = UDF_I(inode);
+ mutex_lock(&inode->i_mutex);
down_write(&iinfo->i_data_sem);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
if (file->f_flags & O_APPEND)
@@ -156,6 +157,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
pos + count)) {
err = udf_expand_file_adinicb(inode);
if (err) {
+ mutex_unlock(&inode->i_mutex);
udf_debug("udf_expand_adinicb: err=%d\n", err);
return err;
}
@@ -169,9 +171,17 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
} else
up_write(&iinfo->i_data_sem);
- retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
- if (retval > 0)
+ retval = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
+ mutex_unlock(&inode->i_mutex);
+
+ if (retval > 0) {
+ ssize_t err;
+
mark_inode_dirty(inode);
+ err = generic_write_sync(file, iocb->ki_pos - retval, retval);
+ if (err < 0)
+ retval = err;
+ }
return retval;
}
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 062b7925bca0..982ce05c87ed 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -265,6 +265,7 @@ int udf_expand_file_adinicb(struct inode *inode)
.nr_to_write = 1,
};
+ WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex));
if (!iinfo->i_lenAlloc) {
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index f35d5c953ff9..9ddfb8190ca1 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -705,7 +705,6 @@ xfs_setattr_size(
{
struct xfs_mount *mp = ip->i_mount;
struct inode *inode = VFS_I(ip);
- int mask = iattr->ia_valid;
xfs_off_t oldsize, newsize;
struct xfs_trans *tp;
int error;
@@ -726,8 +725,8 @@ xfs_setattr_size(
ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
ASSERT(S_ISREG(ip->i_d.di_mode));
- ASSERT((mask & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
- ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
+ ASSERT((iattr->ia_valid & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
+ ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
oldsize = inode->i_size;
newsize = iattr->ia_size;
@@ -736,7 +735,7 @@ xfs_setattr_size(
* Short circuit the truncate case for zero length files.
*/
if (newsize == 0 && oldsize == 0 && ip->i_d.di_nextents == 0) {
- if (!(mask & (ATTR_CTIME|ATTR_MTIME)))
+ if (!(iattr->ia_valid & (ATTR_CTIME|ATTR_MTIME)))
return 0;
/*
@@ -824,10 +823,11 @@ xfs_setattr_size(
* these flags set. For all other operations the VFS set these flags
* explicitly if it wants a timestamp update.
*/
- if (newsize != oldsize && (!(mask & (ATTR_CTIME | ATTR_MTIME)))) {
+ if (newsize != oldsize &&
+ !(iattr->ia_valid & (ATTR_CTIME | ATTR_MTIME))) {
iattr->ia_ctime = iattr->ia_mtime =
current_fs_time(inode->i_sb);
- mask |= ATTR_CTIME | ATTR_MTIME;
+ iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME;
}
/*
@@ -863,9 +863,9 @@ xfs_setattr_size(
xfs_inode_clear_eofblocks_tag(ip);
}
- if (mask & ATTR_MODE)
+ if (iattr->ia_valid & ATTR_MODE)
xfs_setattr_mode(ip, iattr);
- if (mask & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME))
+ if (iattr->ia_valid & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME))
xfs_setattr_time(ip, iattr);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c
index cdebd832c3db..4ef6fdbced78 100644
--- a/fs/xfs/xfs_log_cil.c
+++ b/fs/xfs/xfs_log_cil.c
@@ -205,16 +205,25 @@ xlog_cil_insert_format_items(
/*
* We 64-bit align the length of each iovec so that the start
* of the next one is naturally aligned. We'll need to
- * account for that slack space here.
+ * account for that slack space here. Then round nbytes up
+ * to 64-bit alignment so that the initial buffer alignment is
+ * easy to calculate and verify.
*/
nbytes += niovecs * sizeof(uint64_t);
+ nbytes = round_up(nbytes, sizeof(uint64_t));
/* grab the old item if it exists for reservation accounting */
old_lv = lip->li_lv;
- /* calc buffer size */
- buf_size = sizeof(struct xfs_log_vec) + nbytes +
- niovecs * sizeof(struct xfs_log_iovec);
+ /*
+ * The data buffer needs to start 64-bit aligned, so round up
+ * that space to ensure we can align it appropriately and not
+ * overrun the buffer.
+ */
+ buf_size = nbytes +
+ round_up((sizeof(struct xfs_log_vec) +
+ niovecs * sizeof(struct xfs_log_iovec)),
+ sizeof(uint64_t));
/* compare to existing item size */
if (lip->li_lv && buf_size <= lip->li_lv->lv_size) {
@@ -251,6 +260,8 @@ xlog_cil_insert_format_items(
/* The allocated data region lies beyond the iovec region */
lv->lv_buf_len = 0;
lv->lv_buf = (char *)lv + buf_size - nbytes;
+ ASSERT(IS_ALIGNED((unsigned long)lv->lv_buf, sizeof(uint64_t)));
+
lip->li_ops->iop_format(lip, lv);
insert:
ASSERT(lv->lv_buf_len <= nbytes);
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 02df7b408a26..f96c05669a9e 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -282,22 +282,29 @@ xfs_readsb(
struct xfs_sb *sbp = &mp->m_sb;
int error;
int loud = !(flags & XFS_MFSI_QUIET);
+ const struct xfs_buf_ops *buf_ops;
ASSERT(mp->m_sb_bp == NULL);
ASSERT(mp->m_ddev_targp != NULL);
/*
+ * For the initial read, we must guess at the sector
+ * size based on the block device. It's enough to
+ * get the sb_sectsize out of the superblock and
+ * then reread with the proper length.
+ * We don't verify it yet, because it may not be complete.
+ */
+ sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
+ buf_ops = NULL;
+
+ /*
* Allocate a (locked) buffer to hold the superblock.
* This will be kept around at all times to optimize
* access to the superblock.
*/
- sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
-
reread:
bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR,
- BTOBB(sector_size), 0,
- loud ? &xfs_sb_buf_ops
- : &xfs_sb_quiet_buf_ops);
+ BTOBB(sector_size), 0, buf_ops);
if (!bp) {
if (loud)
xfs_warn(mp, "SB buffer read failed");
@@ -328,12 +335,13 @@ reread:
}
/*
- * If device sector size is smaller than the superblock size,
- * re-read the superblock so the buffer is correctly sized.
+ * Re-read the superblock so the buffer is correctly sized,
+ * and properly verified.
*/
- if (sector_size < sbp->sb_sectsize) {
+ if (buf_ops == NULL) {
xfs_buf_relse(bp);
sector_size = sbp->sb_sectsize;
+ buf_ops = loud ? &xfs_sb_buf_ops : &xfs_sb_quiet_buf_ops;
goto reread;
}
diff --git a/fs/xfs/xfs_sb.c b/fs/xfs/xfs_sb.c
index b7c9aea77f8f..1e116794bb66 100644
--- a/fs/xfs/xfs_sb.c
+++ b/fs/xfs/xfs_sb.c
@@ -295,8 +295,7 @@ xfs_mount_validate_sb(
sbp->sb_dblocks == 0 ||
sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp) ||
sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))) {
- XFS_CORRUPTION_ERROR("SB sanity check failed",
- XFS_ERRLEVEL_LOW, mp, sbp);
+ xfs_notice(mp, "SB sanity check failed");
return XFS_ERROR(EFSCORRUPTED);
}
@@ -611,10 +610,10 @@ xfs_sb_read_verify(
XFS_SB_VERSION_5) ||
dsb->sb_crc != 0)) {
- if (!xfs_verify_cksum(bp->b_addr, be16_to_cpu(dsb->sb_sectsize),
+ if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
offsetof(struct xfs_sb, sb_crc))) {
/* Only fail bad secondaries on a known V5 filesystem */
- if (bp->b_bn != XFS_SB_DADDR &&
+ if (bp->b_bn == XFS_SB_DADDR ||
xfs_sb_version_hascrc(&mp->m_sb)) {
error = EFSCORRUPTED;
goto out_error;
@@ -625,7 +624,7 @@ xfs_sb_read_verify(
out_error:
if (error) {
- if (error != EWRONGFS)
+ if (error == EFSCORRUPTED)
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
mp, bp->b_addr);
xfs_buf_ioerror(bp, error);
@@ -644,7 +643,6 @@ xfs_sb_quiet_read_verify(
{
struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp);
-
if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) {
/* XFS filesystem, verify noisily! */
xfs_sb_read_verify(bp);
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index f317488263dd..d971f4932b5d 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -913,7 +913,7 @@ xfs_flush_inodes(
struct super_block *sb = mp->m_super;
if (down_read_trylock(&sb->s_umount)) {
- sync_inodes_sb(sb, jiffies);
+ sync_inodes_sb(sb);
up_read(&sb->s_umount);
}
}
diff --git a/include/acpi/acbuffer.h b/include/acpi/acbuffer.h
index c927a0b1de78..88cb477524a6 100644
--- a/include/acpi/acbuffer.h
+++ b/include/acpi/acbuffer.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h
index 3ea214cff349..932a60d6ed82 100644
--- a/include/acpi/acconfig.h
+++ b/include/acpi/acconfig.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index 4e280bd226dd..8b06e4c1dd5d 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h
index 1f36777e26fe..3dd6e838dc30 100644
--- a/include/acpi/acnames.h
+++ b/include/acpi/acnames.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h
index 4607b027a657..1baae6edda89 100644
--- a/include/acpi/acoutput.h
+++ b/include/acpi/acoutput.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h
index 618787715d56..ca0cb603b171 100644
--- a/include/acpi/acpi.h
+++ b/include/acpi/acpi.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -62,5 +62,8 @@
#include <acpi/acrestyp.h> /* Resource Descriptor structs */
#include <acpi/acpiosxf.h> /* OSL interfaces (ACPICA-to-OS) */
#include <acpi/acpixf.h> /* ACPI core subsystem external interfaces */
+#ifdef ACPI_NATIVE_INTERFACE_HEADER
+#include ACPI_NATIVE_INTERFACE_HEADER
+#endif
#endif /* __ACPI_H__ */
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 8256eb4ad057..84a2e29a2314 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -49,8 +49,8 @@ acpi_evaluate_reference(acpi_handle handle,
struct acpi_object_list *arguments,
struct acpi_handle_list *list);
acpi_status
-acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
- u32 status_code, struct acpi_buffer *status_buf);
+acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code,
+ struct acpi_buffer *status_buf);
acpi_status
acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld);
@@ -133,10 +133,24 @@ struct acpi_scan_handler {
struct list_head list_node;
int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
void (*detach)(struct acpi_device *dev);
+ void (*bind)(struct device *phys_dev);
+ void (*unbind)(struct device *phys_dev);
struct acpi_hotplug_profile hotplug;
};
/*
+ * ACPI Hotplug Context
+ * --------------------
+ */
+
+struct acpi_hotplug_context {
+ struct acpi_device *self;
+ int (*notify)(struct acpi_device *, u32);
+ void (*uevent)(struct acpi_device *, u32);
+ void (*fixup)(struct acpi_device *);
+};
+
+/*
* ACPI Driver
* -----------
*/
@@ -190,7 +204,9 @@ struct acpi_device_flags {
u32 initialized:1;
u32 visited:1;
u32 no_hotplug:1;
- u32 reserved:24;
+ u32 hotplug_notify:1;
+ u32 is_dock_station:1;
+ u32 reserved:22;
};
/* File System */
@@ -329,6 +345,7 @@ struct acpi_device {
struct acpi_device_perf performance;
struct acpi_device_dir dir;
struct acpi_scan_handler *handler;
+ struct acpi_hotplug_context *hp;
struct acpi_driver *driver;
void *driver_data;
struct device dev;
@@ -351,6 +368,24 @@ static inline void acpi_set_device_status(struct acpi_device *adev, u32 sta)
*((u32 *)&adev->status) = sta;
}
+static inline void acpi_set_hp_context(struct acpi_device *adev,
+ struct acpi_hotplug_context *hp,
+ int (*notify)(struct acpi_device *, u32),
+ void (*uevent)(struct acpi_device *, u32),
+ void (*fixup)(struct acpi_device *))
+{
+ hp->self = adev;
+ hp->notify = notify;
+ hp->uevent = uevent;
+ hp->fixup = fixup;
+ adev->hp = hp;
+}
+
+void acpi_initialize_hp_context(struct acpi_device *adev,
+ struct acpi_hotplug_context *hp,
+ int (*notify)(struct acpi_device *, u32),
+ void (*uevent)(struct acpi_device *, u32));
+
/* acpi_device.dev.bus == &acpi_bus_type */
extern struct bus_type acpi_bus_type;
@@ -381,6 +416,8 @@ extern int unregister_acpi_notifier(struct notifier_block *);
*/
int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device);
+struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle);
+void acpi_bus_put_acpi_device(struct acpi_device *adev);
acpi_status acpi_bus_get_status_handle(acpi_handle handle,
unsigned long long *sta);
int acpi_bus_get_status(struct acpi_device *device);
@@ -402,6 +439,8 @@ static inline bool acpi_bus_can_wakeup(acpi_handle handle) { return false; }
void acpi_scan_lock_acquire(void);
void acpi_scan_lock_release(void);
+void acpi_lock_hp_context(void);
+void acpi_unlock_hp_context(void);
int acpi_scan_add_handler(struct acpi_scan_handler *handler);
int acpi_bus_register_driver(struct acpi_driver *driver);
void acpi_bus_unregister_driver(struct acpi_driver *driver);
@@ -418,10 +457,6 @@ static inline bool acpi_device_enumerated(struct acpi_device *adev)
return adev && adev->flags.initialized && adev->flags.visited;
}
-typedef void (*acpi_hp_callback)(void *data, u32 src);
-
-acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src);
-
/**
* module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver
* @__acpi_driver: acpi_driver struct
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index b124fdb26046..d504613bbf80 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -109,36 +109,14 @@ void pci_acpi_crs_quirks(void);
/*--------------------------------------------------------------------------
Dock Station
-------------------------------------------------------------------------- */
-struct acpi_dock_ops {
- acpi_notify_handler fixup;
- acpi_notify_handler handler;
- acpi_notify_handler uevent;
-};
#ifdef CONFIG_ACPI_DOCK
-extern int is_dock_device(acpi_handle handle);
-extern int register_hotplug_dock_device(acpi_handle handle,
- const struct acpi_dock_ops *ops,
- void *context,
- void (*init)(void *),
- void (*release)(void *));
-extern void unregister_hotplug_dock_device(acpi_handle handle);
+extern int is_dock_device(struct acpi_device *adev);
#else
-static inline int is_dock_device(acpi_handle handle)
+static inline int is_dock_device(struct acpi_device *adev)
{
return 0;
}
-static inline int register_hotplug_dock_device(acpi_handle handle,
- const struct acpi_dock_ops *ops,
- void *context,
- void (*init)(void *),
- void (*release)(void *))
-{
- return -ENODEV;
-}
-static inline void unregister_hotplug_dock_device(acpi_handle handle)
-{
-}
#endif /* CONFIG_ACPI_DOCK */
#endif /*__ACPI_DRIVERS_H__*/
diff --git a/include/acpi/acpi_numa.h b/include/acpi/acpi_numa.h
index 451823cb8837..94a37cd7fbda 100644
--- a/include/acpi/acpi_numa.h
+++ b/include/acpi/acpi_numa.h
@@ -13,7 +13,6 @@
extern int pxm_to_node(int);
extern int node_to_pxm(int);
-extern void __acpi_map_pxm_to_node(int, int);
extern int acpi_map_pxm_to_node(int);
extern unsigned char acpi_srat_revision;
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 01e6c6d8b7e1..f6f5f8af2112 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index fea6773f87fc..44f5e9749601 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20131218
+#define ACPI_CA_VERSION 0x20140214
#include <acpi/acconfig.h>
#include <acpi/actypes.h>
@@ -71,7 +71,7 @@ extern u32 acpi_dbg_layer;
/* ACPICA runtime options */
-extern u8 acpi_gbl_all_methods_serialized;
+extern u8 acpi_gbl_auto_serialize_methods;
extern u8 acpi_gbl_copy_dsdt_locally;
extern u8 acpi_gbl_create_osi_method;
extern u8 acpi_gbl_disable_auto_repair;
@@ -230,6 +230,10 @@ acpi_attach_data(acpi_handle object, acpi_object_handler handler, void *data);
acpi_status acpi_detach_data(acpi_handle object, acpi_object_handler handler);
acpi_status
+acpi_get_data_full(acpi_handle object, acpi_object_handler handler, void **data,
+ void (*callback)(void *));
+
+acpi_status
acpi_get_data(acpi_handle object, acpi_object_handler handler, void **data);
acpi_status
diff --git a/include/acpi/acrestyp.h b/include/acpi/acrestyp.h
index cbf4bf977f75..eb760ca0b2e0 100644
--- a/include/acpi/acrestyp.h
+++ b/include/acpi/acrestyp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index 325aeae1fa99..3b30e36b53b5 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index 4ec8c194bfe5..212c65de75df 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
index 094a906a0e98..f3372441e3a5 100644
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/actbl3.h b/include/acpi/actbl3.h
index 01c2a9013e40..c2295cc4a5c0 100644
--- a/include/acpi/actbl3.h
+++ b/include/acpi/actbl3.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 68a3ada689c9..e76356574374 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,18 +55,16 @@
#error ACPI_MACHINE_WIDTH not defined
#endif
-/*! [Begin] no source code translation */
-
/*
* Data type ranges
* Note: These macros are designed to be compiler independent as well as
* working around problems that some 32-bit compilers have with 64-bit
* constants.
*/
-#define ACPI_UINT8_MAX (UINT8) (~((UINT8) 0)) /* 0xFF */
-#define ACPI_UINT16_MAX (UINT16)(~((UINT16) 0)) /* 0xFFFF */
-#define ACPI_UINT32_MAX (UINT32)(~((UINT32) 0)) /* 0xFFFFFFFF */
-#define ACPI_UINT64_MAX (UINT64)(~((UINT64) 0)) /* 0xFFFFFFFFFFFFFFFF */
+#define ACPI_UINT8_MAX (u8) (~((u8) 0)) /* 0xFF */
+#define ACPI_UINT16_MAX (u16)(~((u16) 0)) /* 0xFFFF */
+#define ACPI_UINT32_MAX (u32)(~((u32) 0)) /* 0xFFFFFFFF */
+#define ACPI_UINT64_MAX (u64)(~((u64) 0)) /* 0xFFFFFFFFFFFFFFFF */
#define ACPI_ASCII_MAX 0x7F
/*
@@ -77,18 +75,18 @@
*
* 1) The following types are of fixed size for all targets (16/32/64):
*
- * BOOLEAN Logical boolean
+ * u8 Logical boolean
*
- * UINT8 8-bit (1 byte) unsigned value
- * UINT16 16-bit (2 byte) unsigned value
- * UINT32 32-bit (4 byte) unsigned value
- * UINT64 64-bit (8 byte) unsigned value
+ * u8 8-bit (1 byte) unsigned value
+ * u16 16-bit (2 byte) unsigned value
+ * u32 32-bit (4 byte) unsigned value
+ * u64 64-bit (8 byte) unsigned value
*
- * INT16 16-bit (2 byte) signed value
- * INT32 32-bit (4 byte) signed value
- * INT64 64-bit (8 byte) signed value
+ * s16 16-bit (2 byte) signed value
+ * s32 32-bit (4 byte) signed value
+ * s64 64-bit (8 byte) signed value
*
- * COMPILER_DEPENDENT_UINT64/INT64 - These types are defined in the
+ * COMPILER_DEPENDENT_UINT64/s64 - These types are defined in the
* compiler-dependent header(s) and were introduced because there is no common
* 64-bit integer type across the various compilation models, as shown in
* the table below.
@@ -110,11 +108,11 @@
* usually used for memory allocation, efficient loop counters, and array
* indexes. The types are similar to the size_t type in the C library and are
* required because there is no C type that consistently represents the native
- * data width. ACPI_SIZE is needed because there is no guarantee that a
+ * data width. acpi_size is needed because there is no guarantee that a
* kernel-level C library is present.
*
- * ACPI_SIZE 16/32/64-bit unsigned value
- * ACPI_NATIVE_INT 16/32/64-bit signed value
+ * acpi_size 16/32/64-bit unsigned value
+ * acpi_native_int 16/32/64-bit signed value
*/
/*******************************************************************************
@@ -123,13 +121,15 @@
*
******************************************************************************/
-typedef unsigned char BOOLEAN;
-typedef unsigned char UINT8;
-typedef unsigned short UINT16;
-typedef COMPILER_DEPENDENT_UINT64 UINT64;
-typedef COMPILER_DEPENDENT_INT64 INT64;
+#ifndef ACPI_USE_SYSTEM_INTTYPES
+
+typedef unsigned char u8;
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef COMPILER_DEPENDENT_UINT64 u64;
+typedef COMPILER_DEPENDENT_INT64 s64;
-/*! [End] no source code translation !*/
+#endif /* ACPI_USE_SYSTEM_INTTYPES */
/*
* Value returned by acpi_os_get_thread_id. There is no standard "thread_id"
@@ -149,12 +149,12 @@ typedef COMPILER_DEPENDENT_INT64 INT64;
#if ACPI_MACHINE_WIDTH == 64
-/*! [Begin] no source code translation (keep the typedefs as-is) */
+#ifndef ACPI_USE_SYSTEM_INTTYPES
-typedef unsigned int UINT32;
-typedef int INT32;
+typedef unsigned int u32;
+typedef int s32;
-/*! [End] no source code translation !*/
+#endif /* ACPI_USE_SYSTEM_INTTYPES */
typedef s64 acpi_native_int;
@@ -188,12 +188,12 @@ typedef u64 acpi_physical_address;
#elif ACPI_MACHINE_WIDTH == 32
-/*! [Begin] no source code translation (keep the typedefs as-is) */
+#ifndef ACPI_USE_SYSTEM_INTTYPES
-typedef unsigned int UINT32;
-typedef int INT32;
+typedef unsigned int u32;
+typedef int s32;
-/*! [End] no source code translation !*/
+#endif /* ACPI_USE_SYSTEM_INTTYPES */
typedef s32 acpi_native_int;
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index b402eb67af83..e863dd5c4e04 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h
index e077ce6c38ca..a476b9118b49 100644
--- a/include/acpi/platform/acgcc.h
+++ b/include/acpi/platform/acgcc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 008aa287c7a9..93c55ed7c53d 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2013, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -52,6 +52,14 @@
#ifdef __KERNEL__
+#define ACPI_USE_SYSTEM_INTTYPES
+
+/* Compile for reduced hardware mode only with this kernel config */
+
+#ifdef CONFIG_ACPI_REDUCED_HARDWARE_ONLY
+#define ACPI_REDUCED_HARDWARE 1
+#endif
+
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
@@ -83,6 +91,16 @@
#include <ctype.h>
#include <unistd.h>
+/* Disable kernel specific declarators */
+
+#ifndef __init
+#define __init
+#endif
+
+#ifndef __iomem
+#define __iomem
+#endif
+
/* Host-dependent types and defines for user-space ACPICA */
#define ACPI_FLUSH_CPU_CACHE()
diff --git a/include/asm-generic/bitops/const_hweight.h b/include/asm-generic/bitops/const_hweight.h
index fa2a50b7ee66..0a7e06623470 100644
--- a/include/asm-generic/bitops/const_hweight.h
+++ b/include/asm-generic/bitops/const_hweight.h
@@ -5,14 +5,15 @@
* Compile time versions of __arch_hweightN()
*/
#define __const_hweight8(w) \
- ( (!!((w) & (1ULL << 0))) + \
- (!!((w) & (1ULL << 1))) + \
- (!!((w) & (1ULL << 2))) + \
- (!!((w) & (1ULL << 3))) + \
- (!!((w) & (1ULL << 4))) + \
- (!!((w) & (1ULL << 5))) + \
- (!!((w) & (1ULL << 6))) + \
- (!!((w) & (1ULL << 7))) )
+ ((unsigned int) \
+ ((!!((w) & (1ULL << 0))) + \
+ (!!((w) & (1ULL << 1))) + \
+ (!!((w) & (1ULL << 2))) + \
+ (!!((w) & (1ULL << 3))) + \
+ (!!((w) & (1ULL << 4))) + \
+ (!!((w) & (1ULL << 5))) + \
+ (!!((w) & (1ULL << 6))) + \
+ (!!((w) & (1ULL << 7)))))
#define __const_hweight16(w) (__const_hweight8(w) + __const_hweight8((w) >> 8 ))
#define __const_hweight32(w) (__const_hweight16(w) + __const_hweight16((w) >> 16))
diff --git a/include/asm-generic/cputime_jiffies.h b/include/asm-generic/cputime_jiffies.h
index 272ecba9f588..d5cb78f53986 100644
--- a/include/asm-generic/cputime_jiffies.h
+++ b/include/asm-generic/cputime_jiffies.h
@@ -15,8 +15,10 @@ typedef u64 __nocast cputime64_t;
/*
- * Convert nanoseconds to cputime
+ * Convert nanoseconds <-> cputime
*/
+#define cputime_to_nsecs(__ct) \
+ jiffies_to_nsecs(cputime_to_jiffies(__ct))
#define nsecs_to_cputime64(__nsec) \
jiffies64_to_cputime64(nsecs_to_jiffies64(__nsec))
#define nsecs_to_cputime(__nsec) \
diff --git a/include/asm-generic/cputime_nsecs.h b/include/asm-generic/cputime_nsecs.h
index 2c9e62c2bfd0..4e817606c549 100644
--- a/include/asm-generic/cputime_nsecs.h
+++ b/include/asm-generic/cputime_nsecs.h
@@ -44,7 +44,10 @@ typedef u64 __nocast cputime64_t;
/*
* Convert cputime <-> nanoseconds
*/
-#define nsecs_to_cputime(__nsecs) ((__force u64)(__nsecs))
+#define cputime_to_nsecs(__ct) \
+ (__force u64)(__ct)
+#define nsecs_to_cputime(__nsecs) \
+ (__force cputime_t)(__nsecs)
/*
diff --git a/include/asm-generic/mcs_spinlock.h b/include/asm-generic/mcs_spinlock.h
new file mode 100644
index 000000000000..10cd4ffc6ba2
--- /dev/null
+++ b/include/asm-generic/mcs_spinlock.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_MCS_SPINLOCK_H
+#define __ASM_MCS_SPINLOCK_H
+
+/*
+ * Architectures can define their own:
+ *
+ * arch_mcs_spin_lock_contended(l)
+ * arch_mcs_spin_unlock_contended(l)
+ *
+ * See kernel/locking/mcs_spinlock.c.
+ */
+
+#endif /* __ASM_MCS_SPINLOCK_H */
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 8e4f41d9af4d..1ec08c198b66 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -193,6 +193,19 @@ static inline int pte_same(pte_t pte_a, pte_t pte_b)
}
#endif
+#ifndef __HAVE_ARCH_PTE_UNUSED
+/*
+ * Some architectures provide facilities to virtualization guests
+ * so that they can flag allocated pages as unused. This allows the
+ * host to transparently reclaim unused pages. This function returns
+ * whether the pte's page is unused.
+ */
+static inline int pte_unused(pte_t pte)
+{
+ return 0;
+}
+#endif
+
#ifndef __HAVE_ARCH_PMD_SAME
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b)
@@ -701,6 +714,18 @@ static inline pte_t pte_mknuma(pte_t pte)
}
#endif
+#ifndef ptep_set_numa
+static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ pte_t ptent = *ptep;
+
+ ptent = pte_mknuma(ptent);
+ set_pte_at(mm, addr, ptep, ptent);
+ return;
+}
+#endif
+
#ifndef pmd_mknuma
static inline pmd_t pmd_mknuma(pmd_t pmd)
{
@@ -708,6 +733,18 @@ static inline pmd_t pmd_mknuma(pmd_t pmd)
return pmd_clear_flags(pmd, _PAGE_PRESENT);
}
#endif
+
+#ifndef pmdp_set_numa
+static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp)
+{
+ pmd_t pmd = *pmdp;
+
+ pmd = pmd_mknuma(pmd);
+ set_pmd_at(mm, addr, pmdp, pmd);
+ return;
+}
+#endif
#else
extern int pte_numa(pte_t pte);
extern int pmd_numa(pmd_t pmd);
@@ -715,6 +752,8 @@ extern pte_t pte_mknonnuma(pte_t pte);
extern pmd_t pmd_mknonnuma(pmd_t pmd);
extern pte_t pte_mknuma(pte_t pte);
extern pmd_t pmd_mknuma(pmd_t pmd);
+extern void ptep_set_numa(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+extern void pmdp_set_numa(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp);
#endif /* CONFIG_ARCH_USES_NUMA_PROT_NONE */
#else
static inline int pmd_numa(pmd_t pmd)
@@ -742,10 +781,23 @@ static inline pte_t pte_mknuma(pte_t pte)
return pte;
}
+static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ return;
+}
+
+
static inline pmd_t pmd_mknuma(pmd_t pmd)
{
return pmd;
}
+
+static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp)
+{
+ return ;
+}
#endif /* CONFIG_NUMA_BALANCING */
#endif /* CONFIG_MMU */
diff --git a/include/asm-generic/rwsem.h b/include/asm-generic/rwsem.h
index bb1e2cdeb9bf..d48bf5a95cc1 100644
--- a/include/asm-generic/rwsem.h
+++ b/include/asm-generic/rwsem.h
@@ -1,5 +1,5 @@
-#ifndef _ASM_POWERPC_RWSEM_H
-#define _ASM_POWERPC_RWSEM_H
+#ifndef _ASM_GENERIC_RWSEM_H
+#define _ASM_GENERIC_RWSEM_H
#ifndef _LINUX_RWSEM_H
#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
@@ -8,7 +8,7 @@
#ifdef __KERNEL__
/*
- * R/W semaphores for PPC using the stuff in lib/rwsem.c.
+ * R/W semaphores originally for PPC using the stuff in lib/rwsem.c.
* Adapted largely from include/asm-i386/rwsem.h
* by Paul Mackerras <paulus@samba.org>.
*/
@@ -16,7 +16,7 @@
/*
* the semaphore definition
*/
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_64BIT
# define RWSEM_ACTIVE_MASK 0xffffffffL
#else
# define RWSEM_ACTIVE_MASK 0x0000ffffL
@@ -129,4 +129,4 @@ static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
}
#endif /* __KERNEL__ */
-#endif /* _ASM_POWERPC_RWSEM_H */
+#endif /* _ASM_GENERIC_RWSEM_H */
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index bc2121fa9132..f10f64fcc815 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -167,6 +167,16 @@
#define CLK_OF_TABLES()
#endif
+#ifdef CONFIG_OF_RESERVED_MEM
+#define RESERVEDMEM_OF_TABLES() \
+ . = ALIGN(8); \
+ VMLINUX_SYMBOL(__reservedmem_of_table) = .; \
+ *(__reservedmem_of_table) \
+ *(__reservedmem_of_table_end)
+#else
+#define RESERVEDMEM_OF_TABLES()
+#endif
+
#define KERNEL_DTB() \
STRUCT_ALIGN(); \
VMLINUX_SYMBOL(__dtb_start) = .; \
@@ -490,6 +500,7 @@
TRACE_SYSCALLS() \
MEM_DISCARD(init.rodata) \
CLK_OF_TABLES() \
+ RESERVEDMEM_OF_TABLES() \
CLKSRC_OF_TABLES() \
KERNEL_DTB() \
IRQCHIP_OF_MATCH_TABLE()
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 71727b6210ae..8f3dee097579 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -907,6 +907,9 @@ struct drm_mode_config {
/* whether async page flip is supported or not */
bool async_page_flip;
+
+ /* cursor size */
+ uint32_t cursor_width, cursor_height;
};
#define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
diff --git a/include/drm/ttm/ttm_page_alloc.h b/include/drm/ttm/ttm_page_alloc.h
index d1f61bfe0ebe..49a828425fa2 100644
--- a/include/drm/ttm/ttm_page_alloc.h
+++ b/include/drm/ttm/ttm_page_alloc.h
@@ -29,6 +29,8 @@
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_memory.h>
+struct device;
+
/**
* Initialize pool allocator.
*/
diff --git a/include/dt-bindings/clock/tegra124-car.h b/include/dt-bindings/clock/tegra124-car.h
index a1116a3b54ef..8c1603b10665 100644
--- a/include/dt-bindings/clock/tegra124-car.h
+++ b/include/dt-bindings/clock/tegra124-car.h
@@ -36,10 +36,10 @@
#define TEGRA124_CLK_PWM 17
#define TEGRA124_CLK_I2S2 18
/* 20 (register bit affects vi and vi_sensor) */
-#define TEGRA124_CLK_GR_2D 21
+/* 21 */
#define TEGRA124_CLK_USBD 22
#define TEGRA124_CLK_ISP 23
-#define TEGRA124_CLK_GR_3D 24
+/* 26 */
/* 25 */
#define TEGRA124_CLK_DISP2 26
#define TEGRA124_CLK_DISP1 27
diff --git a/include/dt-bindings/sound/tlv320aic31xx-micbias.h b/include/dt-bindings/sound/tlv320aic31xx-micbias.h
new file mode 100644
index 000000000000..f5cb772ab9c8
--- /dev/null
+++ b/include/dt-bindings/sound/tlv320aic31xx-micbias.h
@@ -0,0 +1,8 @@
+#ifndef __DT_TLV320AIC31XX_MICBIAS_H
+#define __DT_TLV320AIC31XX_MICBIAS_H
+
+#define MICBIAS_2_0V 1
+#define MICBIAS_2_5V 2
+#define MICBIAS_AVDDV 3
+
+#endif /* __DT_TLV320AIC31XX_MICBIAS_H */
diff --git a/include/dt-bindings/spmi/spmi.h b/include/dt-bindings/spmi/spmi.h
new file mode 100644
index 000000000000..d11e1e543871
--- /dev/null
+++ b/include/dt-bindings/spmi/spmi.h
@@ -0,0 +1,18 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DT_BINDINGS_SPMI_H
+#define __DT_BINDINGS_SPMI_H
+
+#define SPMI_USID 0
+#define SPMI_GSID 1
+
+#endif
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index be85127bfed3..f27000f55a83 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -171,6 +171,11 @@ static inline int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 add
return 0;
}
+static inline int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
+{
+ return -ENXIO;
+}
+
static inline int kvm_vgic_init(struct kvm *kvm)
{
return 0;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 1151a1dcfe41..7a8f2cd66c8b 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -108,6 +108,10 @@ static inline void acpi_initrd_override(void *data, size_t size)
}
#endif
+#define BAD_MADT_ENTRY(entry, end) ( \
+ (!entry) || (unsigned long)entry + sizeof(*entry) > end || \
+ ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
+
char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
void __acpi_unmap_table(char *map, unsigned long size);
int early_acpi_boot_init(void);
@@ -259,14 +263,9 @@ extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d);
extern void acpi_osi_setup(char *str);
#ifdef CONFIG_ACPI_NUMA
-int acpi_get_pxm(acpi_handle handle);
-int acpi_get_node(acpi_handle *handle);
+int acpi_get_node(acpi_handle handle);
#else
-static inline int acpi_get_pxm(acpi_handle handle)
-{
- return 0;
-}
-static inline int acpi_get_node(acpi_handle *handle)
+static inline int acpi_get_node(acpi_handle handle)
{
return 0;
}
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 73a25005d88a..1f16d502600c 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -19,15 +19,37 @@
struct device;
struct ata_port_info;
+struct ahci_host_priv;
+struct platform_device;
+/*
+ * Note ahci_platform_data is deprecated, it is only kept around for use
+ * by the old da850 and spear13xx ahci code.
+ * New drivers should instead declare their own platform_driver struct, and
+ * use ahci_platform* functions in their own probe, suspend and resume methods.
+ */
struct ahci_platform_data {
int (*init)(struct device *dev, void __iomem *addr);
void (*exit)(struct device *dev);
int (*suspend)(struct device *dev);
int (*resume)(struct device *dev);
- const struct ata_port_info *ata_port_info;
- unsigned int force_port_map;
- unsigned int mask_port_map;
};
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
+void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
+int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
+void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
+struct ahci_host_priv *ahci_platform_get_resources(
+ struct platform_device *pdev);
+int ahci_platform_init_host(struct platform_device *pdev,
+ struct ahci_host_priv *hpriv,
+ const struct ata_port_info *pi_template,
+ unsigned int force_port_map,
+ unsigned int mask_port_map);
+
+int ahci_platform_suspend_host(struct device *dev);
+int ahci_platform_resume_host(struct device *dev);
+int ahci_platform_suspend(struct device *dev);
+int ahci_platform_resume(struct device *dev);
+
#endif /* _AHCI_PLATFORM_H */
diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h
index 66a0e5384edd..571a12ebb018 100644
--- a/include/linux/atmel-ssc.h
+++ b/include/linux/atmel-ssc.h
@@ -18,6 +18,7 @@ struct ssc_device {
struct clk *clk;
int user;
int irq;
+ bool clk_from_rk_pin;
};
struct ssc_device * __must_check ssc_request(unsigned int ssc_num);
diff --git a/include/linux/audit.h b/include/linux/audit.h
index aa865a9a4c4f..ec1464df4c60 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -43,6 +43,7 @@ struct mq_attr;
struct mqstat;
struct audit_watch;
struct audit_tree;
+struct sk_buff;
struct audit_krule {
int vers_ops;
@@ -463,7 +464,7 @@ extern int audit_filter_user(int type);
extern int audit_filter_type(int type);
extern int audit_rule_change(int type, __u32 portid, int seq,
void *data, size_t datasz);
-extern int audit_list_rules_send(__u32 portid, int seq);
+extern int audit_list_rules_send(struct sk_buff *request_skb, int seq);
extern u32 audit_enabled;
#else /* CONFIG_AUDIT */
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index abc9ca778456..be5fd38bd5a0 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -196,6 +196,21 @@ static inline unsigned long __ffs64(u64 word)
#ifdef __KERNEL__
+#ifndef set_mask_bits
+#define set_mask_bits(ptr, _mask, _bits) \
+({ \
+ const typeof(*ptr) mask = (_mask), bits = (_bits); \
+ typeof(*ptr) old, new; \
+ \
+ do { \
+ old = ACCESS_ONCE(*ptr); \
+ new = (old & ~mask) | bits; \
+ } while (cmpxchg(ptr, old, new) != old); \
+ \
+ new; \
+})
+#endif
+
#ifndef find_last_bit
/**
* find_last_bit - find the last set bit in a memory region
diff --git a/include/linux/blk-iopoll.h b/include/linux/blk-iopoll.h
index 308734d3d4a2..77ae77c0b704 100644
--- a/include/linux/blk-iopoll.h
+++ b/include/linux/blk-iopoll.h
@@ -43,6 +43,4 @@ extern void __blk_iopoll_complete(struct blk_iopoll *);
extern void blk_iopoll_enable(struct blk_iopoll *);
extern void blk_iopoll_disable(struct blk_iopoll *);
-extern int blk_iopoll_enabled;
-
#endif
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index 18ba8a627f46..0120451545d8 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -109,7 +109,7 @@ enum {
BLK_MQ_F_SHOULD_SORT = 1 << 1,
BLK_MQ_F_SHOULD_IPI = 1 << 2,
- BLK_MQ_S_STOPPED = 1 << 0,
+ BLK_MQ_S_STOPPED = 0,
BLK_MQ_MAX_DEPTH = 2048,
};
@@ -117,12 +117,12 @@ enum {
struct request_queue *blk_mq_init_queue(struct blk_mq_reg *, void *);
int blk_mq_register_disk(struct gendisk *);
void blk_mq_unregister_disk(struct gendisk *);
-void blk_mq_init_commands(struct request_queue *, void (*init)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data);
+int blk_mq_init_commands(struct request_queue *, int (*init)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data);
+void blk_mq_free_commands(struct request_queue *, void (*free)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data);
void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule);
-void blk_mq_insert_request(struct request_queue *, struct request *,
- bool, bool);
+void blk_mq_insert_request(struct request *, bool, bool, bool);
void blk_mq_run_queues(struct request_queue *q, bool async);
void blk_mq_free_request(struct request *rq);
bool blk_mq_can_queue(struct blk_mq_hw_ctx *);
@@ -134,7 +134,13 @@ struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *, const int ctx_ind
struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_reg *, unsigned int);
void blk_mq_free_single_hw_queue(struct blk_mq_hw_ctx *, unsigned int);
-void blk_mq_end_io(struct request *rq, int error);
+bool blk_mq_end_io_partial(struct request *rq, int error,
+ unsigned int nr_bytes);
+static inline void blk_mq_end_io(struct request *rq, int error)
+{
+ bool done = !blk_mq_end_io_partial(rq, error, blk_rq_bytes(rq));
+ BUG_ON(!done);
+}
void blk_mq_complete_request(struct request *rq);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 4afa4f8f6090..1e1fa3f93d5f 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -99,6 +99,7 @@ struct request {
union {
struct call_single_data csd;
struct work_struct mq_flush_work;
+ unsigned long fifo_time;
};
struct request_queue *q;
diff --git a/include/linux/ceph/ceph_fs.h b/include/linux/ceph/ceph_fs.h
index 2623cffc73a1..25bfb0eff772 100644
--- a/include/linux/ceph/ceph_fs.h
+++ b/include/linux/ceph/ceph_fs.h
@@ -373,8 +373,9 @@ extern const char *ceph_mds_op_name(int op);
/*
* Ceph setxattr request flags.
*/
-#define CEPH_XATTR_CREATE 1
-#define CEPH_XATTR_REPLACE 2
+#define CEPH_XATTR_CREATE (1 << 0)
+#define CEPH_XATTR_REPLACE (1 << 1)
+#define CEPH_XATTR_REMOVE (1 << 31)
union ceph_mds_request_args {
struct {
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 5c097596104b..9450f025fe0c 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -166,6 +166,8 @@ struct cgroup {
*
* The ID of the root cgroup is always 0, and a new cgroup
* will be assigned with a smallest available ID.
+ *
+ * Allocating/Removing ID must be protected by cgroup_mutex.
*/
int id;
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
index 092b64168d7f..4a21a872dbbd 100644
--- a/include/linux/clk/ti.h
+++ b/include/linux/clk/ti.h
@@ -245,6 +245,10 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
void omap2_init_clk_clkdm(struct clk_hw *clk);
unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
unsigned long parent_rate);
+int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate);
+long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate);
int omap2_clkops_enable_clkdm(struct clk_hw *hw);
void omap2_clkops_disable_clkdm(struct clk_hw *hw);
int omap2_clk_disable_autoidle_all(void);
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 493aa021c7a9..2e4cb67f6e56 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -62,6 +62,11 @@ enum clock_event_mode {
#define CLOCK_EVT_FEAT_DYNIRQ 0x000020
#define CLOCK_EVT_FEAT_PERCPU 0x000040
+/*
+ * Clockevent device is based on a hrtimer for broadcast
+ */
+#define CLOCK_EVT_FEAT_HRTIMER 0x000080
+
/**
* struct clock_event_device - clock event device descriptor
* @event_handler: Assigned by the framework to be called by the low
@@ -83,6 +88,7 @@ enum clock_event_mode {
* @name: ptr to clock event name
* @rating: variable to rate clock event devices
* @irq: IRQ number (only for non CPU local devices)
+ * @bound_on: Bound on CPU
* @cpumask: cpumask to indicate for which CPUs this device works
* @list: list head for the management code
* @owner: module reference
@@ -113,6 +119,7 @@ struct clock_event_device {
const char *name;
int rating;
int irq;
+ int bound_on;
const struct cpumask *cpumask;
struct list_head list;
struct module *owner;
@@ -180,15 +187,17 @@ extern int tick_receive_broadcast(void);
#endif
#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT)
+extern void tick_setup_hrtimer_broadcast(void);
extern int tick_check_broadcast_expired(void);
#else
static inline int tick_check_broadcast_expired(void) { return 0; }
+static inline void tick_setup_hrtimer_broadcast(void) {};
#endif
#ifdef CONFIG_GENERIC_CLOCKEVENTS
-extern void clockevents_notify(unsigned long reason, void *arg);
+extern int clockevents_notify(unsigned long reason, void *arg);
#else
-static inline void clockevents_notify(unsigned long reason, void *arg) {}
+static inline int clockevents_notify(unsigned long reason, void *arg) { return 0; }
#endif
#else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */
@@ -196,8 +205,9 @@ static inline void clockevents_notify(unsigned long reason, void *arg) {}
static inline void clockevents_suspend(void) {}
static inline void clockevents_resume(void) {}
-static inline void clockevents_notify(unsigned long reason, void *arg) {}
+static inline int clockevents_notify(unsigned long reason, void *arg) { return 0; }
static inline int tick_check_broadcast_expired(void) { return 0; }
+static inline void tick_setup_hrtimer_broadcast(void) {};
#endif
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 3f448c65511b..e6494261eaff 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -14,6 +14,7 @@
#include <linux/if.h>
#include <linux/fs.h>
#include <linux/aio_abi.h> /* for aio_context_t */
+#include <linux/unistd.h>
#include <asm/compat.h>
#include <asm/siginfo.h>
@@ -27,6 +28,9 @@
#define __SC_DELOUSE(t,v) ((t)(unsigned long)(v))
#endif
+#define COMPAT_SYSCALL_DEFINE0(name) \
+ asmlinkage long compat_sys_##name(void)
+
#define COMPAT_SYSCALL_DEFINE1(name, ...) \
COMPAT_SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define COMPAT_SYSCALL_DEFINE2(name, ...) \
@@ -68,6 +72,8 @@ typedef struct compat_sigaltstack {
typedef __compat_uid32_t compat_uid_t;
typedef __compat_gid32_t compat_gid_t;
+typedef compat_ulong_t compat_aio_context_t;
+
struct compat_sel_arg_struct;
struct rusage;
@@ -141,26 +147,23 @@ struct compat_sigaction {
};
/*
- * These functions operate strictly on struct compat_time*
- */
-extern int get_compat_timespec(struct timespec *,
- const struct compat_timespec __user *);
-extern int put_compat_timespec(const struct timespec *,
- struct compat_timespec __user *);
-extern int get_compat_timeval(struct timeval *,
- const struct compat_timeval __user *);
-extern int put_compat_timeval(const struct timeval *,
- struct compat_timeval __user *);
-/*
* These functions operate on 32- or 64-bit specs depending on
- * COMPAT_USE_64BIT_TIME, hence the void user pointer arguments and the
- * naming as compat_get/put_ rather than get/put_compat_.
+ * COMPAT_USE_64BIT_TIME, hence the void user pointer arguments.
*/
extern int compat_get_timespec(struct timespec *, const void __user *);
extern int compat_put_timespec(const struct timespec *, void __user *);
extern int compat_get_timeval(struct timeval *, const void __user *);
extern int compat_put_timeval(const struct timeval *, void __user *);
+/*
+ * This function convert a timespec if necessary and returns a *user
+ * space* pointer. If no conversion is necessary, it returns the
+ * initial pointer. NULL is a legitimate argument and will always
+ * output NULL.
+ */
+extern int compat_convert_timespec(struct timespec __user **,
+ const void __user *);
+
struct compat_iovec {
compat_uptr_t iov_base;
compat_size_t iov_len;
@@ -318,7 +321,7 @@ asmlinkage long compat_sys_semctl(int semid, int semnum, int cmd, int arg);
asmlinkage long compat_sys_msgsnd(int msqid, compat_uptr_t msgp,
compat_ssize_t msgsz, int msgflg);
asmlinkage long compat_sys_msgrcv(int msqid, compat_uptr_t msgp,
- compat_ssize_t msgsz, long msgtyp, int msgflg);
+ compat_ssize_t msgsz, compat_long_t msgtyp, int msgflg);
long compat_sys_msgctl(int first, int second, void __user *uptr);
long compat_sys_shmctl(int first, int second, void __user *uptr);
long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
@@ -337,6 +340,19 @@ asmlinkage ssize_t compat_sys_preadv(compat_ulong_t fd,
asmlinkage ssize_t compat_sys_pwritev(compat_ulong_t fd,
const struct compat_iovec __user *vec,
compat_ulong_t vlen, u32 pos_low, u32 pos_high);
+
+#ifdef __ARCH_WANT_COMPAT_SYS_PREADV64
+asmlinkage long compat_sys_preadv64(unsigned long fd,
+ const struct compat_iovec __user *vec,
+ unsigned long vlen, loff_t pos);
+#endif
+
+#ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64
+asmlinkage long compat_sys_pwritev64(unsigned long fd,
+ const struct compat_iovec __user *vec,
+ unsigned long vlen, loff_t pos);
+#endif
+
asmlinkage long compat_sys_lseek(unsigned int, compat_off_t, unsigned int);
asmlinkage long compat_sys_execve(const char __user *filename, const compat_uptr_t __user *argv,
@@ -451,7 +467,7 @@ asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
asmlinkage long compat_sys_timerfd_gettime(int ufd,
struct compat_itimerspec __user *otmr);
-asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_page,
+asmlinkage long compat_sys_move_pages(pid_t pid, compat_ulong_t nr_pages,
__u32 __user *pages,
const int __user *nodes,
int __user *status,
@@ -481,20 +497,20 @@ asmlinkage long compat_sys_statfs64(const char __user *pathname,
asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz,
struct compat_statfs64 __user *buf);
asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
- unsigned long arg);
+ compat_ulong_t arg);
asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,
- unsigned long arg);
+ compat_ulong_t arg);
asmlinkage long compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p);
-asmlinkage long compat_sys_io_getevents(aio_context_t ctx_id,
- unsigned long min_nr,
- unsigned long nr,
+asmlinkage long compat_sys_io_getevents(compat_aio_context_t ctx_id,
+ compat_long_t min_nr,
+ compat_long_t nr,
struct io_event __user *events,
struct compat_timespec __user *timeout);
-asmlinkage long compat_sys_io_submit(aio_context_t ctx_id, int nr,
+asmlinkage long compat_sys_io_submit(compat_aio_context_t ctx_id, int nr,
u32 __user *iocb);
asmlinkage long compat_sys_mount(const char __user *dev_name,
const char __user *dir_name,
- const char __user *type, unsigned long flags,
+ const char __user *type, compat_ulong_t flags,
const void __user *data);
asmlinkage long compat_sys_old_readdir(unsigned int fd,
struct compat_old_linux_dirent __user *,
@@ -502,9 +518,11 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd,
asmlinkage long compat_sys_getdents(unsigned int fd,
struct compat_linux_dirent __user *dirent,
unsigned int count);
+#ifdef __ARCH_WANT_COMPAT_SYS_GETDENTS64
asmlinkage long compat_sys_getdents64(unsigned int fd,
struct linux_dirent64 __user *dirent,
unsigned int count);
+#endif
asmlinkage long compat_sys_vmsplice(int fd, const struct compat_iovec __user *,
unsigned int nr_segs, unsigned int flags);
asmlinkage long compat_sys_open(const char __user *filename, int flags,
@@ -549,9 +567,9 @@ asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
unsigned vlen, unsigned int flags);
asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg,
unsigned int flags);
-asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len,
+asmlinkage long compat_sys_recv(int fd, void __user *buf, compat_size_t len,
unsigned flags);
-asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
+asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, compat_size_t len,
unsigned flags, struct sockaddr __user *addr,
int __user *addrlen);
asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
@@ -615,16 +633,16 @@ asmlinkage long compat_sys_rt_sigqueueinfo(compat_pid_t pid, int sig,
struct compat_siginfo __user *uinfo);
asmlinkage long compat_sys_sysinfo(struct compat_sysinfo __user *info);
asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
- unsigned long arg);
+ compat_ulong_t arg);
asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
struct compat_timespec __user *utime, u32 __user *uaddr2,
u32 val3);
asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
char __user *optval, int __user *optlen);
-asmlinkage long compat_sys_kexec_load(unsigned long entry,
- unsigned long nr_segments,
+asmlinkage long compat_sys_kexec_load(compat_ulong_t entry,
+ compat_ulong_t nr_segments,
struct compat_kexec_segment __user *,
- unsigned long flags);
+ compat_ulong_t flags);
asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes,
const struct compat_mq_attr __user *u_mqstat,
struct compat_mq_attr __user *u_omqstat);
@@ -635,11 +653,11 @@ asmlinkage long compat_sys_mq_open(const char __user *u_name,
struct compat_mq_attr __user *u_attr);
asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes,
const char __user *u_msg_ptr,
- size_t msg_len, unsigned int msg_prio,
+ compat_size_t msg_len, unsigned int msg_prio,
const struct compat_timespec __user *u_abs_timeout);
asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes,
char __user *u_msg_ptr,
- size_t msg_len, unsigned int __user *u_msg_prio,
+ compat_size_t msg_len, unsigned int __user *u_msg_prio,
const struct compat_timespec __user *u_abs_timeout);
asmlinkage long compat_sys_socketcall(int call, u32 __user *args);
asmlinkage long compat_sys_sysctl(struct compat_sysctl_args __user *args);
@@ -654,12 +672,12 @@ extern void __user *compat_alloc_user_space(unsigned long len);
asmlinkage ssize_t compat_sys_process_vm_readv(compat_pid_t pid,
const struct compat_iovec __user *lvec,
- unsigned long liovcnt, const struct compat_iovec __user *rvec,
- unsigned long riovcnt, unsigned long flags);
+ compat_ulong_t liovcnt, const struct compat_iovec __user *rvec,
+ compat_ulong_t riovcnt, compat_ulong_t flags);
asmlinkage ssize_t compat_sys_process_vm_writev(compat_pid_t pid,
const struct compat_iovec __user *lvec,
- unsigned long liovcnt, const struct compat_iovec __user *rvec,
- unsigned long riovcnt, unsigned long flags);
+ compat_ulong_t liovcnt, const struct compat_iovec __user *rvec,
+ compat_ulong_t riovcnt, compat_ulong_t flags);
asmlinkage long compat_sys_sendfile(int out_fd, int in_fd,
compat_off_t __user *offset, compat_size_t count);
diff --git a/include/linux/connector.h b/include/linux/connector.h
index b2b5a41b6a24..be9c4747d511 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -71,7 +71,7 @@ struct cn_dev {
int cn_add_callback(struct cb_id *id, const char *name,
void (*callback)(struct cn_msg *, struct netlink_skb_parms *));
void cn_del_callback(struct cb_id *);
-int cn_netlink_send(struct cn_msg *, u32, gfp_t);
+int cn_netlink_send(struct cn_msg *msg, u32 portid, u32 group, gfp_t gfp_mask);
int cn_queue_add_callback(struct cn_queue_dev *dev, const char *name,
struct cb_id *id,
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 03e235ad1bba..03e962e23eaf 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -46,13 +46,6 @@ extern ssize_t arch_cpu_release(const char *, size_t);
#endif
struct notifier_block;
-#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
-extern int arch_cpu_uevent(struct device *dev, struct kobj_uevent_env *env);
-extern ssize_t arch_print_cpu_modalias(struct device *dev,
- struct device_attribute *attr,
- char *bufptr);
-#endif
-
/*
* CPU notifier priorities.
*/
diff --git a/include/linux/cpufeature.h b/include/linux/cpufeature.h
new file mode 100644
index 000000000000..c4d4eb8ac9fe
--- /dev/null
+++ b/include/linux/cpufeature.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@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.
+ */
+
+#ifndef __LINUX_CPUFEATURE_H
+#define __LINUX_CPUFEATURE_H
+
+#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
+
+#include <linux/mod_devicetable.h>
+#include <asm/cpufeature.h>
+
+/*
+ * Macros imported from <asm/cpufeature.h>:
+ * - cpu_feature(x) ordinal value of feature called 'x'
+ * - cpu_have_feature(u32 n) whether feature #n is available
+ * - MAX_CPU_FEATURES upper bound for feature ordinal values
+ * Optional:
+ * - CPU_FEATURE_TYPEFMT format string fragment for printing the cpu type
+ * - CPU_FEATURE_TYPEVAL set of values matching the format string above
+ */
+
+#ifndef CPU_FEATURE_TYPEFMT
+#define CPU_FEATURE_TYPEFMT "%s"
+#endif
+
+#ifndef CPU_FEATURE_TYPEVAL
+#define CPU_FEATURE_TYPEVAL ELF_PLATFORM
+#endif
+
+/*
+ * Use module_cpu_feature_match(feature, module_init_function) to
+ * declare that
+ * a) the module shall be probed upon discovery of CPU feature 'feature'
+ * (typically at boot time using udev)
+ * b) the module must not be loaded if CPU feature 'feature' is not present
+ * (not even by manual insmod).
+ *
+ * For a list of legal values for 'feature', please consult the file
+ * 'asm/cpufeature.h' of your favorite architecture.
+ */
+#define module_cpu_feature_match(x, __init) \
+static struct cpu_feature const cpu_feature_match_ ## x[] = \
+ { { .feature = cpu_feature(x) }, { } }; \
+MODULE_DEVICE_TABLE(cpu, cpu_feature_match_ ## x); \
+ \
+static int cpu_feature_match_ ## x ## _init(void) \
+{ \
+ if (!cpu_have_feature(cpu_feature(x))) \
+ return -ENODEV; \
+ return __init(); \
+} \
+module_init(cpu_feature_match_ ## x ## _init)
+
+#endif
+#endif
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 4d89e0e6f9cc..c48e595f623e 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -16,6 +16,7 @@
#include <linux/completion.h>
#include <linux/kobject.h>
#include <linux/notifier.h>
+#include <linux/spinlock.h>
#include <linux/sysfs.h>
/*********************************************************************
@@ -74,6 +75,8 @@ struct cpufreq_policy {
unsigned int max; /* in kHz */
unsigned int cur; /* in kHz, only needed if cpufreq
* governors are used */
+ unsigned int suspend_freq; /* freq to set during suspend */
+
unsigned int policy; /* see above */
struct cpufreq_governor *governor; /* see below */
void *governor_data;
@@ -83,6 +86,7 @@ struct cpufreq_policy {
* called, but you're in IRQ context */
struct cpufreq_real_policy user_policy;
+ struct cpufreq_frequency_table *freq_table;
struct list_head policy_list;
struct kobject kobj;
@@ -101,6 +105,11 @@ struct cpufreq_policy {
* __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
*/
struct rw_semaphore rwsem;
+
+ /* Synchronization for frequency transitions */
+ bool transition_ongoing; /* Tracks transition status */
+ spinlock_t transition_lock;
+ wait_queue_head_t transition_wait;
};
/* Only for ACPI */
@@ -224,6 +233,7 @@ struct cpufreq_driver {
int (*bios_limit) (int cpu, unsigned int *limit);
int (*exit) (struct cpufreq_policy *policy);
+ void (*stop_cpu) (struct cpufreq_policy *policy);
int (*suspend) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
@@ -296,6 +306,15 @@ cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy)
policy->cpuinfo.max_freq);
}
+#ifdef CONFIG_CPU_FREQ
+void cpufreq_suspend(void);
+void cpufreq_resume(void);
+int cpufreq_generic_suspend(struct cpufreq_policy *policy);
+#else
+static inline void cpufreq_suspend(void) {}
+static inline void cpufreq_resume(void) {}
+#endif
+
/*********************************************************************
* CPUFREQ NOTIFIER INTERFACE *
*********************************************************************/
@@ -306,8 +325,6 @@ cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy)
/* Transition notifiers */
#define CPUFREQ_PRECHANGE (0)
#define CPUFREQ_POSTCHANGE (1)
-#define CPUFREQ_RESUMECHANGE (8)
-#define CPUFREQ_SUSPENDCHANGE (9)
/* Policy Notifiers */
#define CPUFREQ_ADJUST (0)
@@ -322,9 +339,9 @@ cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy)
int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
-void cpufreq_notify_transition(struct cpufreq_policy *policy,
- struct cpufreq_freqs *freqs, unsigned int state);
-void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
+void cpufreq_freq_transition_begin(struct cpufreq_policy *policy,
+ struct cpufreq_freqs *freqs);
+void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, int transition_failed);
#else /* CONFIG_CPU_FREQ */
@@ -463,7 +480,6 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
unsigned int freq);
-void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
#ifdef CONFIG_CPU_FREQ
@@ -490,9 +506,6 @@ struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
/* the following are really really optional */
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
extern struct freq_attr *cpufreq_generic_attr[];
-void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
- unsigned int cpu);
-void cpufreq_frequency_table_put_attr(unsigned int cpu);
int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table);
@@ -500,10 +513,4 @@ unsigned int cpufreq_generic_get(unsigned int cpu);
int cpufreq_generic_init(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table,
unsigned int transition_latency);
-static inline int cpufreq_generic_exit(struct cpufreq_policy *policy)
-{
- cpufreq_frequency_table_put_attr(policy->cpu);
- return 0;
-}
-
#endif /* _LINUX_CPUFREQ_H */
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 50fcbb0ac4e7..b0238cba440b 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -119,7 +119,15 @@ struct cpuidle_driver {
#ifdef CONFIG_CPU_IDLE
extern void disable_cpuidle(void);
-extern int cpuidle_idle_call(void);
+
+extern int cpuidle_enabled(struct cpuidle_driver *drv,
+ struct cpuidle_device *dev);
+extern int cpuidle_select(struct cpuidle_driver *drv,
+ struct cpuidle_device *dev);
+extern int cpuidle_enter(struct cpuidle_driver *drv,
+ struct cpuidle_device *dev, int index);
+extern void cpuidle_reflect(struct cpuidle_device *dev, int index);
+
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
extern struct cpuidle_driver *cpuidle_get_driver(void);
extern struct cpuidle_driver *cpuidle_driver_ref(void);
@@ -141,7 +149,16 @@ extern int cpuidle_play_dead(void);
extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev);
#else
static inline void disable_cpuidle(void) { }
-static inline int cpuidle_idle_call(void) { return -ENODEV; }
+static inline int cpuidle_enabled(struct cpuidle_driver *drv,
+ struct cpuidle_device *dev)
+{return -ENODEV; }
+static inline int cpuidle_select(struct cpuidle_driver *drv,
+ struct cpuidle_device *dev)
+{return -ENODEV; }
+static inline int cpuidle_enter(struct cpuidle_driver *drv,
+ struct cpuidle_device *dev, int index)
+{return -ENODEV; }
+static inline void cpuidle_reflect(struct cpuidle_device *dev, int index) { }
static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
{return -ENODEV; }
static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }
@@ -163,6 +180,8 @@ static inline int cpuidle_enable_device(struct cpuidle_device *dev)
{return -ENODEV; }
static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
static inline int cpuidle_play_dead(void) {return -ENODEV; }
+static inline struct cpuidle_driver *cpuidle_get_cpu_driver(
+ struct cpuidle_device *dev) {return NULL; }
#endif
#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
diff --git a/include/linux/cputime.h b/include/linux/cputime.h
new file mode 100644
index 000000000000..f2eb2ee535ca
--- /dev/null
+++ b/include/linux/cputime.h
@@ -0,0 +1,16 @@
+#ifndef __LINUX_CPUTIME_H
+#define __LINUX_CPUTIME_H
+
+#include <asm/cputime.h>
+
+#ifndef cputime_to_nsecs
+# define cputime_to_nsecs(__ct) \
+ (cputime_to_usecs(__ct) * NSEC_PER_USEC)
+#endif
+
+#ifndef nsecs_to_cputime
+# define nsecs_to_cputime(__nsecs) \
+ usecs_to_cputime((__nsecs) / NSEC_PER_USEC)
+#endif
+
+#endif /* __LINUX_CPUTIME_H */
diff --git a/include/linux/device.h b/include/linux/device.h
index 952b01033c32..233bbbeb768d 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -560,6 +560,8 @@ extern int device_create_file(struct device *device,
const struct device_attribute *entry);
extern void device_remove_file(struct device *dev,
const struct device_attribute *attr);
+extern bool device_remove_file_self(struct device *dev,
+ const struct device_attribute *attr);
extern int __must_check device_create_bin_file(struct device *dev,
const struct bin_attribute *attr);
extern void device_remove_bin_file(struct device *dev,
@@ -626,6 +628,7 @@ static inline void *devm_kcalloc(struct device *dev,
return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO);
}
extern void devm_kfree(struct device *dev, void *p);
+extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp);
void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res);
void __iomem *devm_request_and_ioremap(struct device *dev,
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index dfac5ed31120..f886985a28b2 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -171,7 +171,7 @@ struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops,
size_t size, int flags, const char *);
#define dma_buf_export(priv, ops, size, flags) \
- dma_buf_export_named(priv, ops, size, flags, __FILE__)
+ dma_buf_export_named(priv, ops, size, flags, KBUILD_MODNAME)
int dma_buf_fd(struct dma_buf *dmabuf, int flags);
struct dma_buf *dma_buf_get(int fd);
diff --git a/include/linux/drbd.h b/include/linux/drbd.h
index de7d74ab3de6..3dbe9bd57a09 100644
--- a/include/linux/drbd.h
+++ b/include/linux/drbd.h
@@ -327,12 +327,6 @@ enum drbd_state_rv {
SS_AFTER_LAST_ERROR = -22, /* Keep this at bottom */
};
-/* from drbd_strings.c */
-extern const char *drbd_conn_str(enum drbd_conns);
-extern const char *drbd_role_str(enum drbd_role);
-extern const char *drbd_disk_str(enum drbd_disk_state);
-extern const char *drbd_set_st_err_str(enum drbd_state_rv);
-
#define SHARED_SECRET_MAX 64
#define MDF_CONSISTENT (1 << 0)
@@ -382,4 +376,6 @@ enum drbd_timeout_flag {
#define DRBD_MD_INDEX_FLEX_EXT -2
#define DRBD_MD_INDEX_FLEX_INT -3
+#define DRBD_CPU_MASK_SIZE 32
+
#endif
diff --git a/include/linux/drbd_genl.h b/include/linux/drbd_genl.h
index e8c44572b8cb..4193f5f2636c 100644
--- a/include/linux/drbd_genl.h
+++ b/include/linux/drbd_genl.h
@@ -135,7 +135,7 @@ GENL_struct(DRBD_NLA_DISK_CONF, 3, disk_conf,
)
GENL_struct(DRBD_NLA_RESOURCE_OPTS, 4, res_opts,
- __str_field_def(1, DRBD_GENLA_F_MANDATORY, cpu_mask, 32)
+ __str_field_def(1, DRBD_GENLA_F_MANDATORY, cpu_mask, DRBD_CPU_MASK_SIZE)
__u32_field_def(2, DRBD_GENLA_F_MANDATORY, on_no_data, DRBD_ON_NO_DATA_DEF)
)
@@ -276,9 +276,9 @@ GENL_op(
)
/* add DRBD minor devices as volumes to resources */
-GENL_op(DRBD_ADM_NEW_MINOR, 5, GENL_doit(drbd_adm_add_minor),
+GENL_op(DRBD_ADM_NEW_MINOR, 5, GENL_doit(drbd_adm_new_minor),
GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED))
-GENL_op(DRBD_ADM_DEL_MINOR, 6, GENL_doit(drbd_adm_delete_minor),
+GENL_op(DRBD_ADM_DEL_MINOR, 6, GENL_doit(drbd_adm_del_minor),
GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, DRBD_F_REQUIRED))
/* add or delete resources */
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 0a819e7a60c9..6c100ff0cae4 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -153,6 +153,102 @@ typedef struct {
u8 sets_to_zero;
} efi_time_cap_t;
+typedef struct {
+ efi_table_hdr_t hdr;
+ u32 raise_tpl;
+ u32 restore_tpl;
+ u32 allocate_pages;
+ u32 free_pages;
+ u32 get_memory_map;
+ u32 allocate_pool;
+ u32 free_pool;
+ u32 create_event;
+ u32 set_timer;
+ u32 wait_for_event;
+ u32 signal_event;
+ u32 close_event;
+ u32 check_event;
+ u32 install_protocol_interface;
+ u32 reinstall_protocol_interface;
+ u32 uninstall_protocol_interface;
+ u32 handle_protocol;
+ u32 __reserved;
+ u32 register_protocol_notify;
+ u32 locate_handle;
+ u32 locate_device_path;
+ u32 install_configuration_table;
+ u32 load_image;
+ u32 start_image;
+ u32 exit;
+ u32 unload_image;
+ u32 exit_boot_services;
+ u32 get_next_monotonic_count;
+ u32 stall;
+ u32 set_watchdog_timer;
+ u32 connect_controller;
+ u32 disconnect_controller;
+ u32 open_protocol;
+ u32 close_protocol;
+ u32 open_protocol_information;
+ u32 protocols_per_handle;
+ u32 locate_handle_buffer;
+ u32 locate_protocol;
+ u32 install_multiple_protocol_interfaces;
+ u32 uninstall_multiple_protocol_interfaces;
+ u32 calculate_crc32;
+ u32 copy_mem;
+ u32 set_mem;
+ u32 create_event_ex;
+} __packed efi_boot_services_32_t;
+
+typedef struct {
+ efi_table_hdr_t hdr;
+ u64 raise_tpl;
+ u64 restore_tpl;
+ u64 allocate_pages;
+ u64 free_pages;
+ u64 get_memory_map;
+ u64 allocate_pool;
+ u64 free_pool;
+ u64 create_event;
+ u64 set_timer;
+ u64 wait_for_event;
+ u64 signal_event;
+ u64 close_event;
+ u64 check_event;
+ u64 install_protocol_interface;
+ u64 reinstall_protocol_interface;
+ u64 uninstall_protocol_interface;
+ u64 handle_protocol;
+ u64 __reserved;
+ u64 register_protocol_notify;
+ u64 locate_handle;
+ u64 locate_device_path;
+ u64 install_configuration_table;
+ u64 load_image;
+ u64 start_image;
+ u64 exit;
+ u64 unload_image;
+ u64 exit_boot_services;
+ u64 get_next_monotonic_count;
+ u64 stall;
+ u64 set_watchdog_timer;
+ u64 connect_controller;
+ u64 disconnect_controller;
+ u64 open_protocol;
+ u64 close_protocol;
+ u64 open_protocol_information;
+ u64 protocols_per_handle;
+ u64 locate_handle_buffer;
+ u64 locate_protocol;
+ u64 install_multiple_protocol_interfaces;
+ u64 uninstall_multiple_protocol_interfaces;
+ u64 calculate_crc32;
+ u64 copy_mem;
+ u64 set_mem;
+ u64 create_event_ex;
+} __packed efi_boot_services_64_t;
+
/*
* EFI Boot Services table
*/
@@ -231,6 +327,15 @@ typedef enum {
EfiPciIoAttributeOperationMaximum
} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION;
+typedef struct {
+ u32 read;
+ u32 write;
+} efi_pci_io_protocol_access_32_t;
+
+typedef struct {
+ u64 read;
+ u64 write;
+} efi_pci_io_protocol_access_64_t;
typedef struct {
void *read;
@@ -238,6 +343,46 @@ typedef struct {
} efi_pci_io_protocol_access_t;
typedef struct {
+ u32 poll_mem;
+ u32 poll_io;
+ efi_pci_io_protocol_access_32_t mem;
+ efi_pci_io_protocol_access_32_t io;
+ efi_pci_io_protocol_access_32_t pci;
+ u32 copy_mem;
+ u32 map;
+ u32 unmap;
+ u32 allocate_buffer;
+ u32 free_buffer;
+ u32 flush;
+ u32 get_location;
+ u32 attributes;
+ u32 get_bar_attributes;
+ u32 set_bar_attributes;
+ uint64_t romsize;
+ void *romimage;
+} efi_pci_io_protocol_32;
+
+typedef struct {
+ u64 poll_mem;
+ u64 poll_io;
+ efi_pci_io_protocol_access_64_t mem;
+ efi_pci_io_protocol_access_64_t io;
+ efi_pci_io_protocol_access_64_t pci;
+ u64 copy_mem;
+ u64 map;
+ u64 unmap;
+ u64 allocate_buffer;
+ u64 free_buffer;
+ u64 flush;
+ u64 get_location;
+ u64 attributes;
+ u64 get_bar_attributes;
+ u64 set_bar_attributes;
+ uint64_t romsize;
+ void *romimage;
+} efi_pci_io_protocol_64;
+
+typedef struct {
void *poll_mem;
void *poll_io;
efi_pci_io_protocol_access_t mem;
@@ -292,6 +437,42 @@ typedef struct {
typedef struct {
efi_table_hdr_t hdr;
+ u32 get_time;
+ u32 set_time;
+ u32 get_wakeup_time;
+ u32 set_wakeup_time;
+ u32 set_virtual_address_map;
+ u32 convert_pointer;
+ u32 get_variable;
+ u32 get_next_variable;
+ u32 set_variable;
+ u32 get_next_high_mono_count;
+ u32 reset_system;
+ u32 update_capsule;
+ u32 query_capsule_caps;
+ u32 query_variable_info;
+} efi_runtime_services_32_t;
+
+typedef struct {
+ efi_table_hdr_t hdr;
+ u64 get_time;
+ u64 set_time;
+ u64 get_wakeup_time;
+ u64 set_wakeup_time;
+ u64 set_virtual_address_map;
+ u64 convert_pointer;
+ u64 get_variable;
+ u64 get_next_variable;
+ u64 set_variable;
+ u64 get_next_high_mono_count;
+ u64 reset_system;
+ u64 update_capsule;
+ u64 query_capsule_caps;
+ u64 query_variable_info;
+} efi_runtime_services_64_t;
+
+typedef struct {
+ efi_table_hdr_t hdr;
void *get_time;
void *set_time;
void *get_wakeup_time;
@@ -485,6 +666,38 @@ struct efi_memory_map {
typedef struct {
u32 revision;
+ u32 parent_handle;
+ u32 system_table;
+ u32 device_handle;
+ u32 file_path;
+ u32 reserved;
+ u32 load_options_size;
+ u32 load_options;
+ u32 image_base;
+ __aligned_u64 image_size;
+ unsigned int image_code_type;
+ unsigned int image_data_type;
+ unsigned long unload;
+} efi_loaded_image_32_t;
+
+typedef struct {
+ u32 revision;
+ u64 parent_handle;
+ u64 system_table;
+ u64 device_handle;
+ u64 file_path;
+ u64 reserved;
+ u32 load_options_size;
+ u64 load_options;
+ u64 image_base;
+ __aligned_u64 image_size;
+ unsigned int image_code_type;
+ unsigned int image_data_type;
+ unsigned long unload;
+} efi_loaded_image_64_t;
+
+typedef struct {
+ u32 revision;
void *parent_handle;
efi_system_table_t *system_table;
void *device_handle;
@@ -511,6 +724,34 @@ typedef struct {
efi_char16_t filename[1];
} efi_file_info_t;
+typedef struct {
+ u64 revision;
+ u32 open;
+ u32 close;
+ u32 delete;
+ u32 read;
+ u32 write;
+ u32 get_position;
+ u32 set_position;
+ u32 get_info;
+ u32 set_info;
+ u32 flush;
+} efi_file_handle_32_t;
+
+typedef struct {
+ u64 revision;
+ u64 open;
+ u64 close;
+ u64 delete;
+ u64 read;
+ u64 write;
+ u64 get_position;
+ u64 set_position;
+ u64 get_info;
+ u64 set_info;
+ u64 flush;
+} efi_file_handle_64_t;
+
typedef struct _efi_file_handle {
u64 revision;
efi_status_t (*open)(struct _efi_file_handle *,
@@ -573,6 +814,7 @@ extern struct efi {
efi_reset_system_t *reset_system;
efi_set_virtual_address_map_t *set_virtual_address_map;
struct efi_memory_map *memmap;
+ unsigned long flags;
} efi;
static inline int
@@ -659,18 +901,17 @@ extern int __init efi_setup_pcdp_console(char *);
#define EFI_ARCH_1 6 /* First arch-specific bit */
#ifdef CONFIG_EFI
-# ifdef CONFIG_X86
-extern int efi_enabled(int facility);
-# else
-static inline int efi_enabled(int facility)
+/*
+ * Test whether the above EFI_* bits are enabled.
+ */
+static inline bool efi_enabled(int feature)
{
- return 1;
+ return test_bit(feature, &efi.flags) != 0;
}
-# endif
#else
-static inline int efi_enabled(int facility)
+static inline bool efi_enabled(int feature)
{
- return 0;
+ return false;
}
#endif
@@ -809,6 +1050,17 @@ struct efivar_entry {
bool deleting;
};
+struct efi_simple_text_output_protocol_32 {
+ u32 reset;
+ u32 output_string;
+ u32 test_string;
+};
+
+struct efi_simple_text_output_protocol_64 {
+ u64 reset;
+ u64 output_string;
+ u64 test_string;
+};
struct efi_simple_text_output_protocol {
void *reset;
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index 306dd8cd0b6f..df63bd3a8cf1 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -202,17 +202,8 @@ enum {
#define rq_end_sector(rq) (blk_rq_pos(rq) + blk_rq_sectors(rq))
#define rb_entry_rq(node) rb_entry((node), struct request, rb_node)
-/*
- * Hack to reuse the csd.list list_head as the fifo time holder while
- * the request is in the io scheduler. Saves an unsigned long in rq.
- */
-#define rq_fifo_time(rq) ((unsigned long) (rq)->csd.list.next)
-#define rq_set_fifo_time(rq,exp) ((rq)->csd.list.next = (void *) (exp))
#define rq_entry_fifo(ptr) list_entry((ptr), struct request, queuelist)
-#define rq_fifo_clear(rq) do { \
- list_del_init(&(rq)->queuelist); \
- INIT_LIST_HEAD(&(rq)->csd.list); \
- } while (0)
+#define rq_fifo_clear(rq) list_del_init(&(rq)->queuelist)
#else /* CONFIG_BLOCK */
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
index 21c59af1150b..f488145bb2d4 100644
--- a/include/linux/extcon.h
+++ b/include/linux/extcon.h
@@ -240,6 +240,12 @@ extern int extcon_register_notifier(struct extcon_dev *edev,
struct notifier_block *nb);
extern int extcon_unregister_notifier(struct extcon_dev *edev,
struct notifier_block *nb);
+
+/*
+ * Following API get the extcon device from devicetree.
+ * This function use phandle of devicetree to get extcon device directly.
+ */
+extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index);
#else /* CONFIG_EXTCON */
static inline int extcon_dev_register(struct extcon_dev *edev)
{
@@ -324,5 +330,11 @@ static inline int extcon_unregister_interest(struct extcon_specific_cable_nb
{
return 0;
}
+
+static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
+ int index)
+{
+ return ERR_PTR(-ENODEV);
+}
#endif /* CONFIG_EXTCON */
#endif /* __LINUX_EXTCON_H__ */
diff --git a/include/linux/extcon/of_extcon.h b/include/linux/extcon/of_extcon.h
deleted file mode 100644
index 0ebfeff1b55d..000000000000
--- a/include/linux/extcon/of_extcon.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * OF helpers for External connector (extcon) framework
- *
- * Copyright (C) 2013 Texas Instruments, Inc.
- * Kishon Vijay Abraham I <kishon@ti.com>
- *
- * Copyright (C) 2013 Samsung Electronics
- * Chanwoo Choi <cw00.choi@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __LINUX_OF_EXTCON_H
-#define __LINUX_OF_EXTCON_H
-
-#include <linux/err.h>
-
-#if IS_ENABLED(CONFIG_OF_EXTCON)
-extern struct extcon_dev
- *of_extcon_get_extcon_dev(struct device *dev, int index);
-#else
-static inline struct extcon_dev
- *of_extcon_get_extcon_dev(struct device *dev, int index)
-{
- return ERR_PTR(-ENOSYS);
-}
-#endif /* CONFIG_OF_EXTCON */
-#endif /* __LINUX_OF_EXTCON_H */
diff --git a/include/linux/file.h b/include/linux/file.h
index cbacf4faf447..4d69123377a2 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -28,33 +28,36 @@ static inline void fput_light(struct file *file, int fput_needed)
struct fd {
struct file *file;
- int need_put;
+ unsigned int flags;
};
+#define FDPUT_FPUT 1
+#define FDPUT_POS_UNLOCK 2
static inline void fdput(struct fd fd)
{
- if (fd.need_put)
+ if (fd.flags & FDPUT_FPUT)
fput(fd.file);
}
extern struct file *fget(unsigned int fd);
-extern struct file *fget_light(unsigned int fd, int *fput_needed);
+extern struct file *fget_raw(unsigned int fd);
+extern unsigned long __fdget(unsigned int fd);
+extern unsigned long __fdget_raw(unsigned int fd);
+extern unsigned long __fdget_pos(unsigned int fd);
-static inline struct fd fdget(unsigned int fd)
+static inline struct fd __to_fd(unsigned long v)
{
- int b;
- struct file *f = fget_light(fd, &b);
- return (struct fd){f,b};
+ return (struct fd){(struct file *)(v & ~3),v & 3};
}
-extern struct file *fget_raw(unsigned int fd);
-extern struct file *fget_raw_light(unsigned int fd, int *fput_needed);
+static inline struct fd fdget(unsigned int fd)
+{
+ return __to_fd(__fdget(fd));
+}
static inline struct fd fdget_raw(unsigned int fd)
{
- int b;
- struct file *f = fget_raw_light(fd, &b);
- return (struct fd){f,b};
+ return __to_fd(__fdget_raw(fd));
}
extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index 5d7782e42b8f..c3683bdf28fe 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -200,6 +200,7 @@ struct fw_device {
unsigned irmc:1;
unsigned bc_implemented:2;
+ work_func_t workfn;
struct delayed_work work;
struct fw_attribute_group attribute_group;
};
diff --git a/include/linux/fmc-sdb.h b/include/linux/fmc-sdb.h
index 1974317a9b3d..599bd6bab56d 100644
--- a/include/linux/fmc-sdb.h
+++ b/include/linux/fmc-sdb.h
@@ -14,6 +14,8 @@ union sdb_record {
struct sdb_bridge bridge;
struct sdb_integration integr;
struct sdb_empty empty;
+ struct sdb_synthesis synthesis;
+ struct sdb_repo_url repo_url;
};
struct fmc_device;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 60829565e552..23b2a35d712e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -123,6 +123,9 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
/* File is opened with O_PATH; almost nothing can be done with it */
#define FMODE_PATH ((__force fmode_t)0x4000)
+/* File needs atomic accesses to f_pos */
+#define FMODE_ATOMIC_POS ((__force fmode_t)0x8000)
+
/* File was opened by fanotify and shouldn't generate fanotify events */
#define FMODE_NONOTIFY ((__force fmode_t)0x1000000)
@@ -780,13 +783,14 @@ struct file {
const struct file_operations *f_op;
/*
- * Protects f_ep_links, f_flags, f_pos vs i_size in lseek SEEK_CUR.
+ * Protects f_ep_links, f_flags.
* Must not be taken from IRQ context.
*/
spinlock_t f_lock;
atomic_long_t f_count;
unsigned int f_flags;
fmode_t f_mode;
+ struct mutex f_pos_lock;
loff_t f_pos;
struct fown_struct f_owner;
const struct cred *f_cred;
@@ -808,7 +812,7 @@ struct file {
#ifdef CONFIG_DEBUG_WRITECOUNT
unsigned long f_mnt_write_state;
#endif
-};
+} __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
struct file_handle {
__u32 handle_bytes;
diff --git a/arch/powerpc/include/asm/fsl_ifc.h b/include/linux/fsl_ifc.h
index f49ddb1b2273..f49ddb1b2273 100644
--- a/arch/powerpc/include/asm/fsl_ifc.h
+++ b/include/linux/fsl_ifc.h
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 3d286ff49ab0..64cf3ef50696 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -99,7 +99,7 @@ struct fsnotify_ops {
struct fsnotify_mark *inode_mark,
struct fsnotify_mark *vfsmount_mark,
u32 mask, void *data, int data_type,
- const unsigned char *file_name);
+ const unsigned char *file_name, u32 cookie);
void (*free_group_priv)(struct fsnotify_group *group);
void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group);
void (*free_event)(struct fsnotify_event *event);
@@ -160,7 +160,7 @@ struct fsnotify_group {
struct fasync_struct *fsn_fa; /* async notification */
- struct fsnotify_event overflow_event; /* Event we queue when the
+ struct fsnotify_event *overflow_event; /* Event we queue when the
* notification list is too
* full */
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 4e4cc28623ad..4cdb3a17bcb5 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -495,10 +495,6 @@ enum {
FILTER_TRACE_FN,
};
-#define EVENT_STORAGE_SIZE 128
-extern struct mutex event_storage_mutex;
-extern char event_storage[EVENT_STORAGE_SIZE];
-
extern int trace_event_raw_init(struct ftrace_event_call *call);
extern int trace_define_field(struct ftrace_event_call *call, const char *type,
const char *name, int offset, int size,
diff --git a/include/linux/futex.h b/include/linux/futex.h
index b0d95cac826e..6435f46d6e13 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -55,7 +55,11 @@ union futex_key {
#ifdef CONFIG_FUTEX
extern void exit_robust_list(struct task_struct *curr);
extern void exit_pi_state_list(struct task_struct *curr);
+#ifdef CONFIG_HAVE_FUTEX_CMPXCHG
+#define futex_cmpxchg_enabled 1
+#else
extern int futex_cmpxchg_enabled;
+#endif
#else
static inline void exit_robust_list(struct task_struct *curr)
{
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 0437439bc047..39b81dc7d01a 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -123,6 +123,10 @@ struct vm_area_struct;
__GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN | \
__GFP_NO_KSWAPD)
+/*
+ * GFP_THISNODE does not perform any reclaim, you most likely want to
+ * use __GFP_THISNODE to allocate from a given node without fallback!
+ */
#ifdef CONFIG_NUMA
#define GFP_THISNODE (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY)
#else
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 12d5f972f23f..cba442ec3c66 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -9,6 +9,7 @@
extern void synchronize_irq(unsigned int irq);
+extern void synchronize_hardirq(unsigned int irq);
#if defined(CONFIG_TINY_RCU)
diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h
index beaf965621c1..537161a997ab 100644
--- a/include/linux/hid-sensor-ids.h
+++ b/include/linux/hid-sensor-ids.h
@@ -33,6 +33,16 @@
#define HID_USAGE_SENSOR_DATA_LIGHT 0x2004d0
#define HID_USAGE_SENSOR_LIGHT_ILLUM 0x2004d1
+/* PROX (200011) */
+#define HID_USAGE_SENSOR_PROX 0x200011
+#define HID_USAGE_SENSOR_DATA_PRESENCE 0x2004b0
+#define HID_USAGE_SENSOR_HUMAN_PRESENCE 0x2004b1
+
+/* Pressure (200031) */
+#define HID_USAGE_SENSOR_PRESSURE 0x200031
+#define HID_USAGE_SENSOR_DATA_ATMOSPHERIC_PRESSURE 0x200430
+#define HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE 0x200431
+
/* Gyro 3D: (200076) */
#define HID_USAGE_SENSOR_GYRO_3D 0x200076
#define HID_USAGE_SENSOR_DATA_ANGL_VELOCITY 0x200456
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index d19a5c2d2270..e7a8d3fa91d5 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -96,12 +96,12 @@ enum hrtimer_restart {
* @function: timer expiry callback function
* @base: pointer to the timer base (per cpu and per clock)
* @state: state information (See bit values above)
+ * @start_pid: timer statistics field to store the pid of the task which
+ * started the timer
* @start_site: timer statistics field to store the site where the timer
* was started
* @start_comm: timer statistics field to store the name of the process which
* started the timer
- * @start_pid: timer statistics field to store the pid of the task which
- * started the timer
*
* The hrtimer structure must be initialized by hrtimer_init()
*/
diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index db512014e061..b826239bdce0 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -157,46 +157,6 @@ static inline int hpage_nr_pages(struct page *page)
return HPAGE_PMD_NR;
return 1;
}
-/*
- * compound_trans_head() should be used instead of compound_head(),
- * whenever the "page" passed as parameter could be the tail of a
- * transparent hugepage that could be undergoing a
- * __split_huge_page_refcount(). The page structure layout often
- * changes across releases and it makes extensive use of unions. So if
- * the page structure layout will change in a way that
- * page->first_page gets clobbered by __split_huge_page_refcount, the
- * implementation making use of smp_rmb() will be required.
- *
- * Currently we define compound_trans_head as compound_head, because
- * page->private is in the same union with page->first_page, and
- * page->private isn't clobbered. However this also means we're
- * currently leaving dirt into the page->private field of anonymous
- * pages resulting from a THP split, instead of setting page->private
- * to zero like for every other page that has PG_private not set. But
- * anonymous pages don't use page->private so this is not a problem.
- */
-#if 0
-/* This will be needed if page->private will be clobbered in split_huge_page */
-static inline struct page *compound_trans_head(struct page *page)
-{
- if (PageTail(page)) {
- struct page *head;
- head = page->first_page;
- smp_rmb();
- /*
- * head may be a dangling pointer.
- * __split_huge_page_refcount clears PageTail before
- * overwriting first_page, so if PageTail is still
- * there it means the head pointer isn't dangling.
- */
- if (PageTail(page))
- return head;
- }
- return page;
-}
-#else
-#define compound_trans_head(page) compound_head(page)
-#endif
extern int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long addr, pmd_t pmd, pmd_t *pmdp);
@@ -226,7 +186,6 @@ static inline int split_huge_page(struct page *page)
do { } while (0)
#define split_huge_page_pmd_mm(__mm, __address, __pmd) \
do { } while (0)
-#define compound_trans_head(page) compound_head(page)
static inline int hugepage_madvise(struct vm_area_struct *vma,
unsigned long *vm_flags, int advice)
{
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 344883dce584..ab7359fde987 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -25,328 +25,11 @@
#ifndef _HYPERV_H
#define _HYPERV_H
-#include <linux/types.h>
-
-/*
- * Framework version for util services.
- */
-#define UTIL_FW_MINOR 0
-
-#define UTIL_WS2K8_FW_MAJOR 1
-#define UTIL_WS2K8_FW_VERSION (UTIL_WS2K8_FW_MAJOR << 16 | UTIL_FW_MINOR)
-
-#define UTIL_FW_MAJOR 3
-#define UTIL_FW_VERSION (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR)
-
-
-/*
- * Implementation of host controlled snapshot of the guest.
- */
-
-#define VSS_OP_REGISTER 128
-
-enum hv_vss_op {
- VSS_OP_CREATE = 0,
- VSS_OP_DELETE,
- VSS_OP_HOT_BACKUP,
- VSS_OP_GET_DM_INFO,
- VSS_OP_BU_COMPLETE,
- /*
- * Following operations are only supported with IC version >= 5.0
- */
- VSS_OP_FREEZE, /* Freeze the file systems in the VM */
- VSS_OP_THAW, /* Unfreeze the file systems */
- VSS_OP_AUTO_RECOVER,
- VSS_OP_COUNT /* Number of operations, must be last */
-};
-
-
-/*
- * Header for all VSS messages.
- */
-struct hv_vss_hdr {
- __u8 operation;
- __u8 reserved[7];
-} __attribute__((packed));
-
-
-/*
- * Flag values for the hv_vss_check_feature. Linux supports only
- * one value.
- */
-#define VSS_HBU_NO_AUTO_RECOVERY 0x00000005
-
-struct hv_vss_check_feature {
- __u32 flags;
-} __attribute__((packed));
-
-struct hv_vss_check_dm_info {
- __u32 flags;
-} __attribute__((packed));
-
-struct hv_vss_msg {
- union {
- struct hv_vss_hdr vss_hdr;
- int error;
- };
- union {
- struct hv_vss_check_feature vss_cf;
- struct hv_vss_check_dm_info dm_info;
- };
-} __attribute__((packed));
-
-/*
- * An implementation of HyperV key value pair (KVP) functionality for Linux.
- *
- *
- * Copyright (C) 2010, Novell, Inc.
- * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
- *
- */
-
-/*
- * Maximum value size - used for both key names and value data, and includes
- * any applicable NULL terminators.
- *
- * Note: This limit is somewhat arbitrary, but falls easily within what is
- * supported for all native guests (back to Win 2000) and what is reasonable
- * for the IC KVP exchange functionality. Note that Windows Me/98/95 are
- * limited to 255 character key names.
- *
- * MSDN recommends not storing data values larger than 2048 bytes in the
- * registry.
- *
- * Note: This value is used in defining the KVP exchange message - this value
- * cannot be modified without affecting the message size and compatibility.
- */
-
-/*
- * bytes, including any null terminators
- */
-#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE (2048)
-
-
-/*
- * Maximum key size - the registry limit for the length of an entry name
- * is 256 characters, including the null terminator
- */
-
-#define HV_KVP_EXCHANGE_MAX_KEY_SIZE (512)
-
-/*
- * In Linux, we implement the KVP functionality in two components:
- * 1) The kernel component which is packaged as part of the hv_utils driver
- * is responsible for communicating with the host and responsible for
- * implementing the host/guest protocol. 2) A user level daemon that is
- * responsible for data gathering.
- *
- * Host/Guest Protocol: The host iterates over an index and expects the guest
- * to assign a key name to the index and also return the value corresponding to
- * the key. The host will have atmost one KVP transaction outstanding at any
- * given point in time. The host side iteration stops when the guest returns
- * an error. Microsoft has specified the following mapping of key names to
- * host specified index:
- *
- * Index Key Name
- * 0 FullyQualifiedDomainName
- * 1 IntegrationServicesVersion
- * 2 NetworkAddressIPv4
- * 3 NetworkAddressIPv6
- * 4 OSBuildNumber
- * 5 OSName
- * 6 OSMajorVersion
- * 7 OSMinorVersion
- * 8 OSVersion
- * 9 ProcessorArchitecture
- *
- * The Windows host expects the Key Name and Key Value to be encoded in utf16.
- *
- * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the
- * data gathering functionality in a user mode daemon. The user level daemon
- * is also responsible for binding the key name to the index as well. The
- * kernel and user-level daemon communicate using a connector channel.
- *
- * The user mode component first registers with the
- * the kernel component. Subsequently, the kernel component requests, data
- * for the specified keys. In response to this message the user mode component
- * fills in the value corresponding to the specified key. We overload the
- * sequence field in the cn_msg header to define our KVP message types.
- *
- *
- * The kernel component simply acts as a conduit for communication between the
- * Windows host and the user-level daemon. The kernel component passes up the
- * index received from the Host to the user-level daemon. If the index is
- * valid (supported), the corresponding key as well as its
- * value (both are strings) is returned. If the index is invalid
- * (not supported), a NULL key string is returned.
- */
-
-
-/*
- * Registry value types.
- */
-
-#define REG_SZ 1
-#define REG_U32 4
-#define REG_U64 8
-
-/*
- * As we look at expanding the KVP functionality to include
- * IP injection functionality, we need to maintain binary
- * compatibility with older daemons.
- *
- * The KVP opcodes are defined by the host and it was unfortunate
- * that I chose to treat the registration operation as part of the
- * KVP operations defined by the host.
- * Here is the level of compatibility
- * (between the user level daemon and the kernel KVP driver) that we
- * will implement:
- *
- * An older daemon will always be supported on a newer driver.
- * A given user level daemon will require a minimal version of the
- * kernel driver.
- * If we cannot handle the version differences, we will fail gracefully
- * (this can happen when we have a user level daemon that is more
- * advanced than the KVP driver.
- *
- * We will use values used in this handshake for determining if we have
- * workable user level daemon and the kernel driver. We begin by taking the
- * registration opcode out of the KVP opcode namespace. We will however,
- * maintain compatibility with the existing user-level daemon code.
- */
-
-/*
- * Daemon code not supporting IP injection (legacy daemon).
- */
-
-#define KVP_OP_REGISTER 4
-
-/*
- * Daemon code supporting IP injection.
- * The KVP opcode field is used to communicate the
- * registration information; so define a namespace that
- * will be distinct from the host defined KVP opcode.
- */
-
-#define KVP_OP_REGISTER1 100
-
-enum hv_kvp_exchg_op {
- KVP_OP_GET = 0,
- KVP_OP_SET,
- KVP_OP_DELETE,
- KVP_OP_ENUMERATE,
- KVP_OP_GET_IP_INFO,
- KVP_OP_SET_IP_INFO,
- KVP_OP_COUNT /* Number of operations, must be last. */
-};
-
-enum hv_kvp_exchg_pool {
- KVP_POOL_EXTERNAL = 0,
- KVP_POOL_GUEST,
- KVP_POOL_AUTO,
- KVP_POOL_AUTO_EXTERNAL,
- KVP_POOL_AUTO_INTERNAL,
- KVP_POOL_COUNT /* Number of pools, must be last. */
-};
-
-/*
- * Some Hyper-V status codes.
- */
+#include <uapi/linux/hyperv.h>
-#define HV_S_OK 0x00000000
-#define HV_E_FAIL 0x80004005
-#define HV_S_CONT 0x80070103
-#define HV_ERROR_NOT_SUPPORTED 0x80070032
-#define HV_ERROR_MACHINE_LOCKED 0x800704F7
-#define HV_ERROR_DEVICE_NOT_CONNECTED 0x8007048F
-#define HV_INVALIDARG 0x80070057
-#define HV_GUID_NOTFOUND 0x80041002
-
-#define ADDR_FAMILY_NONE 0x00
-#define ADDR_FAMILY_IPV4 0x01
-#define ADDR_FAMILY_IPV6 0x02
-
-#define MAX_ADAPTER_ID_SIZE 128
-#define MAX_IP_ADDR_SIZE 1024
-#define MAX_GATEWAY_SIZE 512
-
-
-struct hv_kvp_ipaddr_value {
- __u16 adapter_id[MAX_ADAPTER_ID_SIZE];
- __u8 addr_family;
- __u8 dhcp_enabled;
- __u16 ip_addr[MAX_IP_ADDR_SIZE];
- __u16 sub_net[MAX_IP_ADDR_SIZE];
- __u16 gate_way[MAX_GATEWAY_SIZE];
- __u16 dns_addr[MAX_IP_ADDR_SIZE];
-} __attribute__((packed));
-
-
-struct hv_kvp_hdr {
- __u8 operation;
- __u8 pool;
- __u16 pad;
-} __attribute__((packed));
-
-struct hv_kvp_exchg_msg_value {
- __u32 value_type;
- __u32 key_size;
- __u32 value_size;
- __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
- union {
- __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
- __u32 value_u32;
- __u64 value_u64;
- };
-} __attribute__((packed));
-
-struct hv_kvp_msg_enumerate {
- __u32 index;
- struct hv_kvp_exchg_msg_value data;
-} __attribute__((packed));
-
-struct hv_kvp_msg_get {
- struct hv_kvp_exchg_msg_value data;
-};
-
-struct hv_kvp_msg_set {
- struct hv_kvp_exchg_msg_value data;
-};
-
-struct hv_kvp_msg_delete {
- __u32 key_size;
- __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
-};
-
-struct hv_kvp_register {
- __u8 version[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
-};
-
-struct hv_kvp_msg {
- union {
- struct hv_kvp_hdr kvp_hdr;
- int error;
- };
- union {
- struct hv_kvp_msg_get kvp_get;
- struct hv_kvp_msg_set kvp_set;
- struct hv_kvp_msg_delete kvp_delete;
- struct hv_kvp_msg_enumerate kvp_enum_data;
- struct hv_kvp_ipaddr_value kvp_ip_val;
- struct hv_kvp_register kvp_register;
- } body;
-} __attribute__((packed));
-
-struct hv_kvp_ip_msg {
- __u8 operation;
- __u8 pool;
- struct hv_kvp_ipaddr_value kvp_ip_val;
-} __attribute__((packed));
-
-#ifdef __KERNEL__
+#include <linux/types.h>
#include <linux/scatterlist.h>
#include <linux/list.h>
-#include <linux/uuid.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/completion.h>
@@ -354,7 +37,7 @@ struct hv_kvp_ip_msg {
#include <linux/mod_devicetable.h>
-#define MAX_PAGE_BUFFER_COUNT 19
+#define MAX_PAGE_BUFFER_COUNT 32
#define MAX_MULTIPAGE_BUFFER_COUNT 32 /* 128K */
#pragma pack(push, 1)
@@ -1043,6 +726,10 @@ struct vmbus_channel {
* This will be NULL for the primary channel.
*/
struct vmbus_channel *primary_channel;
+ /*
+ * Support per-channel state for use by vmbus drivers.
+ */
+ void *per_channel_state;
};
static inline void set_channel_read_state(struct vmbus_channel *c, bool state)
@@ -1050,6 +737,16 @@ static inline void set_channel_read_state(struct vmbus_channel *c, bool state)
c->batched_reading = state;
}
+static inline void set_per_channel_state(struct vmbus_channel *c, void *s)
+{
+ c->per_channel_state = s;
+}
+
+static inline void *get_per_channel_state(struct vmbus_channel *c)
+{
+ return c->per_channel_state;
+}
+
void vmbus_onmessage(void *context);
int vmbus_request_offers(void);
@@ -1118,7 +815,7 @@ extern int vmbus_open(struct vmbus_channel *channel,
extern void vmbus_close(struct vmbus_channel *channel);
extern int vmbus_sendpacket(struct vmbus_channel *channel,
- const void *buffer,
+ void *buffer,
u32 bufferLen,
u64 requestid,
enum vmbus_packet_type type,
@@ -1352,6 +1049,17 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver);
}
/*
+ * Guest File Copy Service
+ * {34D14BE3-DEE4-41c8-9AE7-6B174977C192}
+ */
+
+#define HV_FCOPY_GUID \
+ .guid = { \
+ 0xE3, 0x4B, 0xD1, 0x34, 0xE4, 0xDE, 0xC8, 0x41, \
+ 0x9A, 0xE7, 0x6B, 0x17, 0x49, 0x77, 0xC1, 0x92 \
+ }
+
+/*
* Common header for Hyper-V ICs
*/
@@ -1459,11 +1167,12 @@ int hv_vss_init(struct hv_util_service *);
void hv_vss_deinit(void);
void hv_vss_onchannelcallback(void *);
+extern struct resource hyperv_mmio;
+
/*
* Negotiated version with the Host.
*/
extern __u32 vmbus_proto_version;
-#endif /* __KERNEL__ */
#endif /* _HYPERV_H */
diff --git a/include/linux/idr.h b/include/linux/idr.h
index ff94a4875e1c..f669585c4fc5 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -84,6 +84,7 @@ void *idr_replace(struct idr *idp, void *ptr, int id);
void idr_remove(struct idr *idp, int id);
void idr_destroy(struct idr *idp);
void idr_init(struct idr *idp);
+bool idr_is_empty(struct idr *idp);
/**
* idr_preload_end - end preload section started with idr_preload()
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 75a8a20c8179..5f2d00e7e488 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -254,12 +254,16 @@ static inline bool iio_channel_has_info(const struct iio_chan_spec *chan,
(chan->info_mask_shared_by_all & BIT(type));
}
-#define IIO_ST(si, rb, sb, sh) \
- { .sign = si, .realbits = rb, .storagebits = sb, .shift = sh }
-
-#define IIO_CHAN_SOFT_TIMESTAMP(_si) \
- { .type = IIO_TIMESTAMP, .channel = -1, \
- .scan_index = _si, .scan_type = IIO_ST('s', 64, 64, 0) }
+#define IIO_CHAN_SOFT_TIMESTAMP(_si) { \
+ .type = IIO_TIMESTAMP, \
+ .channel = -1, \
+ .scan_index = _si, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 64, \
+ .storagebits = 64, \
+ }, \
+}
/**
* iio_get_time_ns() - utility function to get a time stamp for events etc
diff --git a/include/linux/init.h b/include/linux/init.h
index e1688802964f..a3ba27076342 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -163,6 +163,23 @@ extern bool initcall_debug;
#ifndef __ASSEMBLY__
+#ifdef CONFIG_LTO
+/* Work around a LTO gcc problem: when there is no reference to a variable
+ * in a module it will be moved to the end of the program. This causes
+ * reordering of initcalls which the kernel does not like.
+ * Add a dummy reference function to avoid this. The function is
+ * deleted by the linker.
+ */
+#define LTO_REFERENCE_INITCALL(x) \
+ ; /* yes this is needed */ \
+ static __used __exit void *reference_##x(void) \
+ { \
+ return &x; \
+ }
+#else
+#define LTO_REFERENCE_INITCALL(x)
+#endif
+
/* initcalls are now grouped by functionality into separate
* subsections. Ordering inside the subsections is determined
* by link order.
@@ -175,7 +192,8 @@ extern bool initcall_debug;
#define __define_initcall(fn, id) \
static initcall_t __initcall_##fn##id __used \
- __attribute__((__section__(".initcall" #id ".init"))) = fn
+ __attribute__((__section__(".initcall" #id ".init"))) = fn; \
+ LTO_REFERENCE_INITCALL(__initcall_##fn##id)
/*
* Early initcalls run before initializing SMP.
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index a2678d35b5a2..c7bfac1c4a7b 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -188,6 +188,7 @@ extern void disable_irq(unsigned int irq);
extern void disable_percpu_irq(unsigned int irq);
extern void enable_irq(unsigned int irq);
extern void enable_percpu_irq(unsigned int irq, unsigned int type);
+extern void irq_wake_thread(unsigned int irq, void *dev_id);
/* The following three functions are for the core kernel use only. */
extern void suspend_device_irqs(void);
diff --git a/include/linux/io.h b/include/linux/io.h
index f4f42faec686..8a18e75600cc 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -24,7 +24,7 @@
struct device;
-void __iowrite32_copy(void __iomem *to, const void *from, size_t count);
+__visible void __iowrite32_copy(void __iomem *to, const void *from, size_t count);
void __iowrite64_copy(void __iomem *to, const void *from, size_t count);
#ifdef CONFIG_MMU
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 89b7c24a36e9..5e3a906cc089 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -51,7 +51,7 @@ struct resource {
#define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */
#define IORESOURCE_DISABLED 0x10000000
-#define IORESOURCE_UNSET 0x20000000
+#define IORESOURCE_UNSET 0x20000000 /* No address assigned yet */
#define IORESOURCE_AUTO 0x40000000
#define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */
@@ -169,6 +169,16 @@ static inline unsigned long resource_type(const struct resource *res)
{
return res->flags & IORESOURCE_TYPE_BITS;
}
+/* True iff r1 completely contains r2 */
+static inline bool resource_contains(struct resource *r1, struct resource *r2)
+{
+ if (resource_type(r1) != resource_type(r2))
+ return false;
+ if (r1->flags & IORESOURCE_UNSET || r2->flags & IORESOURCE_UNSET)
+ return false;
+ return r1->start <= r2->start && r1->end >= r2->end;
+}
+
/* Convenience shorthand with allocation */
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0)
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index e7831d203737..35e7eca4e33b 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -118,9 +118,7 @@ extern int mq_init_ns(struct ipc_namespace *ns);
* the new maximum will handle anyone else. I may have to revisit this
* in the future.
*/
-#define MIN_QUEUESMAX 1
#define DFLT_QUEUESMAX 256
-#define HARD_QUEUESMAX 1024
#define MIN_MSGMAX 1
#define DFLT_MSG 10U
#define DFLT_MSGMAX 10
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 7dc10036eff5..d278838908cb 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -303,6 +303,10 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
* @irq_pm_shutdown: function called from core code on shutdown once per chip
* @irq_calc_mask: Optional function to set irq_data.mask for special cases
* @irq_print_chip: optional to print special chip info in show_interrupts
+ * @irq_request_resources: optional to request resources before calling
+ * any other callback related to this irq
+ * @irq_release_resources: optional to release resources acquired with
+ * irq_request_resources
* @flags: chip specific flags
*/
struct irq_chip {
@@ -336,6 +340,8 @@ struct irq_chip {
void (*irq_calc_mask)(struct irq_data *data);
void (*irq_print_chip)(struct irq_data *data, struct seq_file *p);
+ int (*irq_request_resources)(struct irq_data *data);
+ void (*irq_release_resources)(struct irq_data *data);
unsigned long flags;
};
@@ -349,6 +355,8 @@ struct irq_chip {
* IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks
* when irq enabled
* IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip
+ * IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask
+ * IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode
*/
enum {
IRQCHIP_SET_TYPE_MASKED = (1 << 0),
@@ -357,6 +365,7 @@ enum {
IRQCHIP_ONOFFLINE_ENABLED = (1 << 3),
IRQCHIP_SKIP_SET_WAKE = (1 << 4),
IRQCHIP_ONESHOT_SAFE = (1 << 5),
+ IRQCHIP_EOI_THREADED = (1 << 6),
};
/* This include will go away once we isolated irq_desc usage to core code */
diff --git a/include/linux/irq_work.h b/include/linux/irq_work.h
index 66017028dcb3..19ae05d4b8ec 100644
--- a/include/linux/irq_work.h
+++ b/include/linux/irq_work.h
@@ -30,7 +30,9 @@ void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *))
work->func = func;
}
-void irq_work_queue(struct irq_work *work);
+#define DEFINE_IRQ_WORK(name, _f) struct irq_work name = { .func = (_f), }
+
+bool irq_work_queue(struct irq_work *work);
void irq_work_run(void);
void irq_work_sync(struct irq_work *work);
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 196d1ea86df0..08fb02477641 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -458,7 +458,7 @@ extern enum system_states {
#define TAINT_PROPRIETARY_MODULE 0
#define TAINT_FORCED_MODULE 1
-#define TAINT_UNSAFE_SMP 2
+#define TAINT_CPU_OUT_OF_SPEC 2
#define TAINT_FORCED_RMMOD 3
#define TAINT_MACHINE_CHECK 4
#define TAINT_BAD_PAGE 5
diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h
index 51c72be4a7c3..ecbc52f9ff77 100644
--- a/include/linux/kernel_stat.h
+++ b/include/linux/kernel_stat.h
@@ -9,7 +9,7 @@
#include <linux/sched.h>
#include <linux/vtime.h>
#include <asm/irq.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
/*
* 'kernel_stat.h' contains the definitions needed for doing
@@ -51,14 +51,8 @@ DECLARE_PER_CPU(struct kernel_cpustat, kernel_cpustat);
extern unsigned long long nr_context_switches(void);
-#include <linux/irq.h>
extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
-
-#define kstat_incr_irqs_this_cpu(irqno, DESC) \
-do { \
- __this_cpu_inc(*(DESC)->kstat_irqs); \
- __this_cpu_inc(kstat.irqs_sum); \
-} while (0)
+extern void kstat_incr_irq_this_cpu(unsigned int irq);
static inline void kstat_incr_softirqs_this_cpu(unsigned int irq)
{
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index 5be9f0228a3b..b0122dc6f96a 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -15,7 +15,7 @@
#include <linux/lockdep.h>
#include <linux/rbtree.h>
#include <linux/atomic.h>
-#include <linux/completion.h>
+#include <linux/wait.h>
struct file;
struct dentry;
@@ -35,16 +35,22 @@ enum kernfs_node_type {
};
#define KERNFS_TYPE_MASK 0x000f
-#define KERNFS_ACTIVE_REF KERNFS_FILE
#define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK
enum kernfs_node_flag {
- KERNFS_REMOVED = 0x0010,
+ KERNFS_ACTIVATED = 0x0010,
KERNFS_NS = 0x0020,
KERNFS_HAS_SEQ_SHOW = 0x0040,
KERNFS_HAS_MMAP = 0x0080,
KERNFS_LOCKDEP = 0x0100,
KERNFS_STATIC_NAME = 0x0200,
+ KERNFS_SUICIDAL = 0x0400,
+ KERNFS_SUICIDED = 0x0800,
+};
+
+/* @flags for kernfs_create_root() */
+enum kernfs_root_flag {
+ KERNFS_ROOT_CREATE_DEACTIVATED = 0x0001,
};
/* type-specific structures for kernfs_node union members */
@@ -85,17 +91,17 @@ struct kernfs_node {
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
- /* the following two fields are published */
+ /*
+ * Use kernfs_get_parent() and kernfs_name/path() instead of
+ * accessing the following two fields directly. If the node is
+ * never moved to a different parent, it is safe to access the
+ * parent directly.
+ */
struct kernfs_node *parent;
const char *name;
struct rb_node rb;
- union {
- struct completion *completion;
- struct kernfs_node *removed_list;
- } u;
-
const void *ns; /* namespace tag */
unsigned int hash; /* ns + name hash */
union {
@@ -113,12 +119,16 @@ struct kernfs_node {
};
/*
- * kernfs_dir_ops may be specified on kernfs_create_root() to support
- * directory manipulation syscalls. These optional callbacks are invoked
- * on the matching syscalls and can perform any kernfs operations which
- * don't necessarily have to be the exact operation requested.
+ * kernfs_syscall_ops may be specified on kernfs_create_root() to support
+ * syscalls. These optional callbacks are invoked on the matching syscalls
+ * and can perform any kernfs operations which don't necessarily have to be
+ * the exact operation requested. An active reference is held for each
+ * kernfs_node parameter.
*/
-struct kernfs_dir_ops {
+struct kernfs_syscall_ops {
+ int (*remount_fs)(struct kernfs_root *root, int *flags, char *data);
+ int (*show_options)(struct seq_file *sf, struct kernfs_root *root);
+
int (*mkdir)(struct kernfs_node *parent, const char *name,
umode_t mode);
int (*rmdir)(struct kernfs_node *kn);
@@ -129,22 +139,26 @@ struct kernfs_dir_ops {
struct kernfs_root {
/* published fields */
struct kernfs_node *kn;
+ unsigned int flags; /* KERNFS_ROOT_* flags */
/* private fields, do not use outside kernfs proper */
struct ida ino_ida;
- struct kernfs_dir_ops *dir_ops;
+ struct kernfs_syscall_ops *syscall_ops;
+ wait_queue_head_t deactivate_waitq;
};
struct kernfs_open_file {
/* published fields */
struct kernfs_node *kn;
struct file *file;
+ void *priv;
/* private fields, do not use outside kernfs proper */
struct mutex mutex;
int event;
struct list_head list;
+ size_t atomic_write_len;
bool mmapped;
const struct vm_operations_struct *vm_ops;
};
@@ -171,9 +185,13 @@ struct kernfs_ops {
loff_t off);
/*
- * write() is bounced through kernel buffer and a write larger than
- * PAGE_SIZE results in partial operation of PAGE_SIZE.
+ * write() is bounced through kernel buffer. If atomic_write_len
+ * is not set, a write larger than PAGE_SIZE results in partial
+ * operations of PAGE_SIZE chunks. If atomic_write_len is set,
+ * writes upto the specified size are executed atomically but
+ * larger ones are rejected with -E2BIG.
*/
+ size_t atomic_write_len;
ssize_t (*write)(struct kernfs_open_file *of, char *buf, size_t bytes,
loff_t off);
@@ -184,7 +202,7 @@ struct kernfs_ops {
#endif
};
-#ifdef CONFIG_SYSFS
+#ifdef CONFIG_KERNFS
static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn)
{
@@ -217,13 +235,22 @@ static inline bool kernfs_ns_enabled(struct kernfs_node *kn)
return kn->flags & KERNFS_NS;
}
+int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen);
+char * __must_check kernfs_path(struct kernfs_node *kn, char *buf,
+ size_t buflen);
+void pr_cont_kernfs_name(struct kernfs_node *kn);
+void pr_cont_kernfs_path(struct kernfs_node *kn);
+struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn);
struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent,
const char *name, const void *ns);
void kernfs_get(struct kernfs_node *kn);
void kernfs_put(struct kernfs_node *kn);
-struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops,
- void *priv);
+struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry);
+struct kernfs_root *kernfs_root_from_sb(struct super_block *sb);
+
+struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
+ unsigned int flags, void *priv);
void kernfs_destroy_root(struct kernfs_root *root);
struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
@@ -239,7 +266,11 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
const char *name,
struct kernfs_node *target);
+void kernfs_activate(struct kernfs_node *kn);
void kernfs_remove(struct kernfs_node *kn);
+void kernfs_break_active_protection(struct kernfs_node *kn);
+void kernfs_unbreak_active_protection(struct kernfs_node *kn);
+bool kernfs_remove_self(struct kernfs_node *kn);
int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name,
const void *ns);
int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
@@ -249,12 +280,13 @@ void kernfs_notify(struct kernfs_node *kn);
const void *kernfs_super_ns(struct super_block *sb);
struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
- struct kernfs_root *root, const void *ns);
+ struct kernfs_root *root, bool *new_sb_created,
+ const void *ns);
void kernfs_kill_sb(struct super_block *sb);
void kernfs_init(void);
-#else /* CONFIG_SYSFS */
+#else /* CONFIG_KERNFS */
static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn)
{ return 0; } /* whatever */
@@ -264,6 +296,19 @@ static inline void kernfs_enable_ns(struct kernfs_node *kn) { }
static inline bool kernfs_ns_enabled(struct kernfs_node *kn)
{ return false; }
+static inline int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen)
+{ return -ENOSYS; }
+
+static inline char * __must_check kernfs_path(struct kernfs_node *kn, char *buf,
+ size_t buflen)
+{ return NULL; }
+
+static inline void pr_cont_kernfs_name(struct kernfs_node *kn) { }
+static inline void pr_cont_kernfs_path(struct kernfs_node *kn) { }
+
+static inline struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn)
+{ return NULL; }
+
static inline struct kernfs_node *
kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name,
const void *ns)
@@ -272,8 +317,15 @@ kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name,
static inline void kernfs_get(struct kernfs_node *kn) { }
static inline void kernfs_put(struct kernfs_node *kn) { }
+static inline struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry)
+{ return NULL; }
+
+static inline struct kernfs_root *kernfs_root_from_sb(struct super_block *sb)
+{ return NULL; }
+
static inline struct kernfs_root *
-kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv)
+kernfs_create_root(struct kernfs_syscall_ops *scops, unsigned int flags,
+ void *priv)
{ return ERR_PTR(-ENOSYS); }
static inline void kernfs_destroy_root(struct kernfs_root *root) { }
@@ -295,8 +347,13 @@ kernfs_create_link(struct kernfs_node *parent, const char *name,
struct kernfs_node *target)
{ return ERR_PTR(-ENOSYS); }
+static inline void kernfs_activate(struct kernfs_node *kn) { }
+
static inline void kernfs_remove(struct kernfs_node *kn) { }
+static inline bool kernfs_remove_self(struct kernfs_node *kn)
+{ return false; }
+
static inline int kernfs_remove_by_name_ns(struct kernfs_node *kn,
const char *name, const void *ns)
{ return -ENOSYS; }
@@ -317,14 +374,14 @@ static inline const void *kernfs_super_ns(struct super_block *sb)
static inline struct dentry *
kernfs_mount_ns(struct file_system_type *fs_type, int flags,
- struct kernfs_root *root, const void *ns)
+ struct kernfs_root *root, bool *new_sb_created, const void *ns)
{ return ERR_PTR(-ENOSYS); }
static inline void kernfs_kill_sb(struct super_block *sb) { }
static inline void kernfs_init(void) { }
-#endif /* CONFIG_SYSFS */
+#endif /* CONFIG_KERNFS */
static inline struct kernfs_node *
kernfs_find_and_get(struct kernfs_node *kn, const char *name)
@@ -366,11 +423,18 @@ static inline int kernfs_remove_by_name(struct kernfs_node *parent,
return kernfs_remove_by_name_ns(parent, name, NULL);
}
+static inline int kernfs_rename(struct kernfs_node *kn,
+ struct kernfs_node *new_parent,
+ const char *new_name)
+{
+ return kernfs_rename_ns(kn, new_parent, new_name, NULL);
+}
+
static inline struct dentry *
kernfs_mount(struct file_system_type *fs_type, int flags,
- struct kernfs_root *root)
+ struct kernfs_root *root, bool *new_sb_created)
{
- return kernfs_mount_ns(fs_type, flags, root, NULL);
+ return kernfs_mount_ns(fs_type, flags, root, new_sb_created, NULL);
}
#endif /* __LINUX_KERNFS_H */
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 6d4066cdb5b5..a75641930049 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -127,12 +127,6 @@ extern asmlinkage long sys_kexec_load(unsigned long entry,
struct kexec_segment __user *segments,
unsigned long flags);
extern int kernel_kexec(void);
-#ifdef CONFIG_COMPAT
-extern asmlinkage long compat_sys_kexec_load(unsigned long entry,
- unsigned long nr_segments,
- struct compat_kexec_segment __user *segments,
- unsigned long flags);
-#endif
extern struct page *kimage_alloc_control_pages(struct kimage *image,
unsigned int order);
extern void crash_kexec(struct pt_regs *);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index b8e9a43e501a..7d21cf9f4380 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -192,7 +192,7 @@ struct kvm_async_pf {
void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu);
void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu);
-int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn,
+int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva,
struct kvm_arch_async_pf *arch);
int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu);
#endif
@@ -297,6 +297,14 @@ static inline unsigned long kvm_dirty_bitmap_bytes(struct kvm_memory_slot *memsl
return ALIGN(memslot->npages, BITS_PER_LONG) / 8;
}
+struct kvm_s390_adapter_int {
+ u64 ind_addr;
+ u64 summary_addr;
+ u64 ind_offset;
+ u32 summary_offset;
+ u32 adapter_id;
+};
+
struct kvm_kernel_irq_routing_entry {
u32 gsi;
u32 type;
@@ -309,6 +317,7 @@ struct kvm_kernel_irq_routing_entry {
unsigned pin;
} irqchip;
struct msi_msg msi;
+ struct kvm_s390_adapter_int adapter;
};
struct hlist_node link;
};
@@ -401,7 +410,9 @@ struct kvm {
unsigned long mmu_notifier_seq;
long mmu_notifier_count;
#endif
- long tlbs_dirty;
+ /* Protected by mmu_lock */
+ bool tlbs_dirty;
+
struct list_head devices;
};
@@ -911,7 +922,11 @@ static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq)
#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING
+#ifdef CONFIG_S390
+#define KVM_MAX_IRQ_ROUTES 4096 //FIXME: we can have more than that...
+#else
#define KVM_MAX_IRQ_ROUTES 1024
+#endif
int kvm_setup_default_irq_routing(struct kvm *kvm);
int kvm_set_irq_routing(struct kvm *kvm,
@@ -1064,6 +1079,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
extern struct kvm_device_ops kvm_xics_ops;
extern struct kvm_device_ops kvm_vfio_ops;
extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
+extern struct kvm_device_ops kvm_flic_ops;
#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
diff --git a/include/linux/libata.h b/include/linux/libata.h
index bec6dbe939a0..1de36be64df4 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -848,7 +848,6 @@ struct ata_port {
struct completion park_req_pending;
pm_message_t pm_mesg;
- int *pm_result;
enum ata_lpm_policy target_lpm_policy;
struct timer_list fastdrain_timer;
@@ -1140,16 +1139,14 @@ extern bool ata_link_offline(struct ata_link *link);
#ifdef CONFIG_PM
extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
extern void ata_host_resume(struct ata_host *host);
-extern int ata_sas_port_async_suspend(struct ata_port *ap, int *async);
-extern int ata_sas_port_async_resume(struct ata_port *ap, int *async);
+extern void ata_sas_port_suspend(struct ata_port *ap);
+extern void ata_sas_port_resume(struct ata_port *ap);
#else
-static inline int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
+static inline void ata_sas_port_suspend(struct ata_port *ap)
{
- return 0;
}
-static inline int ata_sas_port_async_resume(struct ata_port *ap, int *async)
+static inline void ata_sas_port_resume(struct ata_port *ap)
{
- return 0;
}
#endif
extern int ata_ratelimit(void);
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index a6a42dd02466..34a513a2727b 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -12,9 +12,9 @@
#endif
#ifdef __cplusplus
-#define CPP_ASMLINKAGE extern "C"
+#define CPP_ASMLINKAGE extern "C" __visible
#else
-#define CPP_ASMLINKAGE
+#define CPP_ASMLINKAGE __visible
#endif
#ifndef asmlinkage
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 92b1bfc5da60..008388f920d7 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -252,9 +252,9 @@ struct held_lock {
unsigned int trylock:1; /* 16 bits */
unsigned int read:2; /* see lock_acquire() comment */
- unsigned int check:2; /* see lock_acquire() comment */
+ unsigned int check:1; /* see lock_acquire() comment */
unsigned int hardirqs_off:1;
- unsigned int references:11; /* 32 bits */
+ unsigned int references:12; /* 32 bits */
};
/*
@@ -265,7 +265,7 @@ extern void lockdep_info(void);
extern void lockdep_reset(void);
extern void lockdep_reset_lock(struct lockdep_map *lock);
extern void lockdep_free_key_range(void *start, unsigned long size);
-extern void lockdep_sys_exit(void);
+extern asmlinkage void lockdep_sys_exit(void);
extern void lockdep_off(void);
extern void lockdep_on(void);
@@ -303,7 +303,7 @@ extern void lockdep_init_map(struct lockdep_map *lock, const char *name,
(lock)->dep_map.key, sub)
#define lockdep_set_novalidate_class(lock) \
- lockdep_set_class(lock, &__lockdep_no_validate__)
+ lockdep_set_class_and_name(lock, &__lockdep_no_validate__, #lock)
/*
* Compare locking classes
*/
@@ -326,9 +326,8 @@ static inline int lockdep_match_key(struct lockdep_map *lock,
*
* Values for check:
*
- * 0: disabled
- * 1: simple checks (freeing, held-at-exit-time, etc.)
- * 2: full validation
+ * 0: simple checks (freeing, held-at-exit-time, etc.)
+ * 1: full validation
*/
extern void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
int trylock, int read, int check,
@@ -479,15 +478,9 @@ static inline void print_irqtrace_events(struct task_struct *curr)
* on the per lock-class debug mode:
*/
-#ifdef CONFIG_PROVE_LOCKING
- #define lock_acquire_exclusive(l, s, t, n, i) lock_acquire(l, s, t, 0, 2, n, i)
- #define lock_acquire_shared(l, s, t, n, i) lock_acquire(l, s, t, 1, 2, n, i)
- #define lock_acquire_shared_recursive(l, s, t, n, i) lock_acquire(l, s, t, 2, 2, n, i)
-#else
- #define lock_acquire_exclusive(l, s, t, n, i) lock_acquire(l, s, t, 0, 1, n, i)
- #define lock_acquire_shared(l, s, t, n, i) lock_acquire(l, s, t, 1, 1, n, i)
- #define lock_acquire_shared_recursive(l, s, t, n, i) lock_acquire(l, s, t, 2, 1, n, i)
-#endif
+#define lock_acquire_exclusive(l, s, t, n, i) lock_acquire(l, s, t, 0, 1, n, i)
+#define lock_acquire_shared(l, s, t, n, i) lock_acquire(l, s, t, 1, 1, n, i)
+#define lock_acquire_shared_recursive(l, s, t, n, i) lock_acquire(l, s, t, 2, 1, n, i)
#define spin_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i)
#define spin_acquire_nest(l, s, t, n, i) lock_acquire_exclusive(l, s, t, n, i)
@@ -518,13 +511,13 @@ static inline void print_irqtrace_events(struct task_struct *curr)
# define might_lock(lock) \
do { \
typecheck(struct lockdep_map *, &(lock)->dep_map); \
- lock_acquire(&(lock)->dep_map, 0, 0, 0, 2, NULL, _THIS_IP_); \
+ lock_acquire(&(lock)->dep_map, 0, 0, 0, 1, NULL, _THIS_IP_); \
lock_release(&(lock)->dep_map, 0, _THIS_IP_); \
} while (0)
# define might_lock_read(lock) \
do { \
typecheck(struct lockdep_map *, &(lock)->dep_map); \
- lock_acquire(&(lock)->dep_map, 0, 0, 1, 2, NULL, _THIS_IP_); \
+ lock_acquire(&(lock)->dep_map, 0, 0, 1, 1, NULL, _THIS_IP_); \
lock_release(&(lock)->dep_map, 0, _THIS_IP_); \
} while (0)
#else
diff --git a/include/linux/mcb.h b/include/linux/mcb.h
new file mode 100644
index 000000000000..2db284d14064
--- /dev/null
+++ b/include/linux/mcb.h
@@ -0,0 +1,119 @@
+/*
+ * MEN Chameleon Bus.
+ *
+ * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
+ * Author: Johannes Thumshirn <johannes.thumshirn@men.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; version 2 of the License.
+ */
+#ifndef _LINUX_MCB_H
+#define _LINUX_MCB_H
+
+#include <linux/mod_devicetable.h>
+#include <linux/device.h>
+#include <linux/irqreturn.h>
+
+struct mcb_driver;
+
+/**
+ * struct mcb_bus - MEN Chameleon Bus
+ *
+ * @dev: pointer to carrier device
+ * @children: the child busses
+ * @bus_nr: mcb bus number
+ */
+struct mcb_bus {
+ struct list_head children;
+ struct device dev;
+ int bus_nr;
+};
+#define to_mcb_bus(b) container_of((b), struct mcb_bus, dev)
+
+/**
+ * struct mcb_device - MEN Chameleon Bus device
+ *
+ * @bus_list: internal list handling for bus code
+ * @dev: device in kernel representation
+ * @bus: mcb bus the device is plugged to
+ * @subordinate: subordinate MCBus in case of bridge
+ * @is_added: flag to check if device is added to bus
+ * @driver: associated mcb_driver
+ * @id: mcb device id
+ * @inst: instance in Chameleon table
+ * @group: group in Chameleon table
+ * @var: variant in Chameleon table
+ * @bar: BAR in Chameleon table
+ * @rev: revision in Chameleon table
+ * @irq: IRQ resource
+ * @memory: memory resource
+ */
+struct mcb_device {
+ struct list_head bus_list;
+ struct device dev;
+ struct mcb_bus *bus;
+ struct mcb_bus *subordinate;
+ bool is_added;
+ struct mcb_driver *driver;
+ u16 id;
+ int inst;
+ int group;
+ int var;
+ int bar;
+ int rev;
+ struct resource irq;
+ struct resource mem;
+};
+#define to_mcb_device(x) container_of((x), struct mcb_device, dev)
+
+/**
+ * struct mcb_driver - MEN Chameleon Bus device driver
+ *
+ * @driver: device_driver
+ * @id_table: mcb id table
+ * @probe: probe callback
+ * @remove: remove callback
+ * @shutdown: shutdown callback
+ */
+struct mcb_driver {
+ struct device_driver driver;
+ const struct mcb_device_id *id_table;
+ int (*probe)(struct mcb_device *mdev, const struct mcb_device_id *id);
+ void (*remove)(struct mcb_device *mdev);
+ void (*shutdown)(struct mcb_device *mdev);
+};
+#define to_mcb_driver(x) container_of((x), struct mcb_driver, driver)
+
+static inline void *mcb_get_drvdata(struct mcb_device *dev)
+{
+ return dev_get_drvdata(&dev->dev);
+}
+
+static inline void mcb_set_drvdata(struct mcb_device *dev, void *data)
+{
+ dev_set_drvdata(&dev->dev, data);
+}
+
+extern int __must_check __mcb_register_driver(struct mcb_driver *drv,
+ struct module *owner,
+ const char *mod_name);
+#define mcb_register_driver(driver) \
+ __mcb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
+extern void mcb_unregister_driver(struct mcb_driver *driver);
+#define module_mcb_driver(__mcb_driver) \
+ module_driver(__mcb_driver, mcb_register_driver, mcb_unregister_driver);
+extern void mcb_bus_add_devices(const struct mcb_bus *bus);
+extern int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev);
+extern struct mcb_bus *mcb_alloc_bus(void);
+extern struct mcb_bus *mcb_bus_get(struct mcb_bus *bus);
+extern void mcb_bus_put(struct mcb_bus *bus);
+extern struct mcb_device *mcb_alloc_dev(struct mcb_bus *bus);
+extern void mcb_free_dev(struct mcb_device *dev);
+extern void mcb_release_bus(struct mcb_bus *bus);
+extern struct resource *mcb_request_mem(struct mcb_device *dev,
+ const char *name);
+extern void mcb_release_mem(struct resource *mem);
+extern int mcb_get_irq(struct mcb_device *dev);
+
+#endif /* _LINUX_MCB_H */
diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h
index fdf3aa376eb2..3ddaa634b19d 100644
--- a/include/linux/mfd/arizona/registers.h
+++ b/include/linux/mfd/arizona/registers.h
@@ -1702,9 +1702,9 @@
/*
* R373 (0x175) - FLL1 Control 5
*/
-#define ARIZONA_FLL1_FRATIO_MASK 0x0700 /* FLL1_FRATIO - [10:8] */
-#define ARIZONA_FLL1_FRATIO_SHIFT 8 /* FLL1_FRATIO - [10:8] */
-#define ARIZONA_FLL1_FRATIO_WIDTH 3 /* FLL1_FRATIO - [10:8] */
+#define ARIZONA_FLL1_FRATIO_MASK 0x0F00 /* FLL1_FRATIO - [11:8] */
+#define ARIZONA_FLL1_FRATIO_SHIFT 8 /* FLL1_FRATIO - [11:8] */
+#define ARIZONA_FLL1_FRATIO_WIDTH 4 /* FLL1_FRATIO - [11:8] */
#define ARIZONA_FLL1_OUTDIV_MASK 0x000E /* FLL1_OUTDIV - [3:1] */
#define ARIZONA_FLL1_OUTDIV_SHIFT 1 /* FLL1_OUTDIV - [3:1] */
#define ARIZONA_FLL1_OUTDIV_WIDTH 3 /* FLL1_OUTDIV - [3:1] */
diff --git a/include/linux/mfd/max8997-private.h b/include/linux/mfd/max8997-private.h
index ad1ae7f345ad..78c76cd4d37b 100644
--- a/include/linux/mfd/max8997-private.h
+++ b/include/linux/mfd/max8997-private.h
@@ -387,7 +387,7 @@ struct max8997_dev {
struct i2c_client *muic; /* slave addr 0x4a */
struct mutex iolock;
- int type;
+ unsigned long type;
struct platform_device *battery; /* battery control (not fuel gauge) */
int irq;
diff --git a/include/linux/mfd/max8998-private.h b/include/linux/mfd/max8998-private.h
index 4ecb24b4b863..d68ada502ff3 100644
--- a/include/linux/mfd/max8998-private.h
+++ b/include/linux/mfd/max8998-private.h
@@ -163,7 +163,7 @@ struct max8998_dev {
int ono;
u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS];
u8 irq_masks_cache[MAX8998_NUM_IRQ_REGS];
- int type;
+ unsigned long type;
bool wakeup;
};
diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h
index 41c9bde410c5..157e32b6ca28 100644
--- a/include/linux/mfd/samsung/core.h
+++ b/include/linux/mfd/samsung/core.h
@@ -18,7 +18,9 @@ enum sec_device_type {
S5M8751X,
S5M8763X,
S5M8767X,
+ S2MPA01,
S2MPS11X,
+ S2MPS14X,
};
/**
@@ -50,7 +52,7 @@ struct sec_pmic_dev {
struct regmap_irq_chip_data *irq_data;
int ono;
- int type;
+ unsigned long type;
bool wakeup;
bool wtsr_smpl;
};
@@ -92,7 +94,7 @@ struct sec_platform_data {
int buck3_default_idx;
int buck4_default_idx;
- int buck_ramp_delay;
+ int buck_ramp_delay;
int buck2_ramp_delay;
int buck34_ramp_delay;
@@ -100,10 +102,15 @@ struct sec_platform_data {
int buck16_ramp_delay;
int buck7810_ramp_delay;
int buck9_ramp_delay;
-
- bool buck2_ramp_enable;
- bool buck3_ramp_enable;
- bool buck4_ramp_enable;
+ int buck24_ramp_delay;
+ int buck3_ramp_delay;
+ int buck7_ramp_delay;
+ int buck8910_ramp_delay;
+
+ bool buck1_ramp_enable;
+ bool buck2_ramp_enable;
+ bool buck3_ramp_enable;
+ bool buck4_ramp_enable;
bool buck6_ramp_enable;
int buck2_init;
@@ -119,7 +126,8 @@ struct sec_platform_data {
struct sec_regulator_data {
int id;
struct regulator_init_data *initdata;
- struct device_node *reg_node;
+ struct device_node *reg_node;
+ int ext_control_gpio;
};
/*
diff --git a/include/linux/mfd/samsung/irq.h b/include/linux/mfd/samsung/irq.h
index d43b4f9e7fb2..1224f447356b 100644
--- a/include/linux/mfd/samsung/irq.h
+++ b/include/linux/mfd/samsung/irq.h
@@ -13,6 +13,56 @@
#ifndef __LINUX_MFD_SEC_IRQ_H
#define __LINUX_MFD_SEC_IRQ_H
+enum s2mpa01_irq {
+ S2MPA01_IRQ_PWRONF,
+ S2MPA01_IRQ_PWRONR,
+ S2MPA01_IRQ_JIGONBF,
+ S2MPA01_IRQ_JIGONBR,
+ S2MPA01_IRQ_ACOKBF,
+ S2MPA01_IRQ_ACOKBR,
+ S2MPA01_IRQ_PWRON1S,
+ S2MPA01_IRQ_MRB,
+
+ S2MPA01_IRQ_RTC60S,
+ S2MPA01_IRQ_RTCA1,
+ S2MPA01_IRQ_RTCA0,
+ S2MPA01_IRQ_SMPL,
+ S2MPA01_IRQ_RTC1S,
+ S2MPA01_IRQ_WTSR,
+
+ S2MPA01_IRQ_INT120C,
+ S2MPA01_IRQ_INT140C,
+ S2MPA01_IRQ_LDO3_TSD,
+ S2MPA01_IRQ_B16_TSD,
+ S2MPA01_IRQ_B24_TSD,
+ S2MPA01_IRQ_B35_TSD,
+
+ S2MPA01_IRQ_NR,
+};
+
+#define S2MPA01_IRQ_PWRONF_MASK (1 << 0)
+#define S2MPA01_IRQ_PWRONR_MASK (1 << 1)
+#define S2MPA01_IRQ_JIGONBF_MASK (1 << 2)
+#define S2MPA01_IRQ_JIGONBR_MASK (1 << 3)
+#define S2MPA01_IRQ_ACOKBF_MASK (1 << 4)
+#define S2MPA01_IRQ_ACOKBR_MASK (1 << 5)
+#define S2MPA01_IRQ_PWRON1S_MASK (1 << 6)
+#define S2MPA01_IRQ_MRB_MASK (1 << 7)
+
+#define S2MPA01_IRQ_RTC60S_MASK (1 << 0)
+#define S2MPA01_IRQ_RTCA1_MASK (1 << 1)
+#define S2MPA01_IRQ_RTCA0_MASK (1 << 2)
+#define S2MPA01_IRQ_SMPL_MASK (1 << 3)
+#define S2MPA01_IRQ_RTC1S_MASK (1 << 4)
+#define S2MPA01_IRQ_WTSR_MASK (1 << 5)
+
+#define S2MPA01_IRQ_INT120C_MASK (1 << 0)
+#define S2MPA01_IRQ_INT140C_MASK (1 << 1)
+#define S2MPA01_IRQ_LDO3_TSD_MASK (1 << 2)
+#define S2MPA01_IRQ_B16_TSD_MASK (1 << 3)
+#define S2MPA01_IRQ_B24_TSD_MASK (1 << 4)
+#define S2MPA01_IRQ_B35_TSD_MASK (1 << 5)
+
enum s2mps11_irq {
S2MPS11_IRQ_PWRONF,
S2MPS11_IRQ_PWRONR,
@@ -24,8 +74,8 @@ enum s2mps11_irq {
S2MPS11_IRQ_MRB,
S2MPS11_IRQ_RTC60S,
+ S2MPS11_IRQ_RTCA0,
S2MPS11_IRQ_RTCA1,
- S2MPS11_IRQ_RTCA2,
S2MPS11_IRQ_SMPL,
S2MPS11_IRQ_RTC1S,
S2MPS11_IRQ_WTSR,
@@ -47,7 +97,7 @@ enum s2mps11_irq {
#define S2MPS11_IRQ_RTC60S_MASK (1 << 0)
#define S2MPS11_IRQ_RTCA1_MASK (1 << 1)
-#define S2MPS11_IRQ_RTCA2_MASK (1 << 2)
+#define S2MPS11_IRQ_RTCA0_MASK (1 << 2)
#define S2MPS11_IRQ_SMPL_MASK (1 << 3)
#define S2MPS11_IRQ_RTC1S_MASK (1 << 4)
#define S2MPS11_IRQ_WTSR_MASK (1 << 5)
@@ -55,6 +105,33 @@ enum s2mps11_irq {
#define S2MPS11_IRQ_INT120C_MASK (1 << 0)
#define S2MPS11_IRQ_INT140C_MASK (1 << 1)
+enum s2mps14_irq {
+ S2MPS14_IRQ_PWRONF,
+ S2MPS14_IRQ_PWRONR,
+ S2MPS14_IRQ_JIGONBF,
+ S2MPS14_IRQ_JIGONBR,
+ S2MPS14_IRQ_ACOKBF,
+ S2MPS14_IRQ_ACOKBR,
+ S2MPS14_IRQ_PWRON1S,
+ S2MPS14_IRQ_MRB,
+
+ S2MPS14_IRQ_RTC60S,
+ S2MPS14_IRQ_RTCA1,
+ S2MPS14_IRQ_RTCA0,
+ S2MPS14_IRQ_SMPL,
+ S2MPS14_IRQ_RTC1S,
+ S2MPS14_IRQ_WTSR,
+
+ S2MPS14_IRQ_INT120C,
+ S2MPS14_IRQ_INT140C,
+ S2MPS14_IRQ_TSD,
+
+ S2MPS14_IRQ_NR,
+};
+
+/* Masks for interrupts are the same as in s2mps11 */
+#define S2MPS14_IRQ_TSD_MASK (1 << 2)
+
enum s5m8767_irq {
S5M8767_IRQ_PWRR,
S5M8767_IRQ_PWRF,
diff --git a/include/linux/mfd/samsung/rtc.h b/include/linux/mfd/samsung/rtc.h
index 94b7cd6d8891..3e02b768d537 100644
--- a/include/linux/mfd/samsung/rtc.h
+++ b/include/linux/mfd/samsung/rtc.h
@@ -1,12 +1,17 @@
-/* rtc.h
+/* rtc.h
*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd
* http://www.samsung.com
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * This program is free software; 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.
*
*/
@@ -43,6 +48,39 @@ enum sec_rtc_reg {
SEC_RTC_STATUS,
SEC_WTSR_SMPL_CNTL,
SEC_RTC_UDR_CON,
+
+ SEC_RTC_REG_MAX,
+};
+
+enum s2mps_rtc_reg {
+ S2MPS_RTC_CTRL,
+ S2MPS_WTSR_SMPL_CNTL,
+ S2MPS_RTC_UDR_CON,
+ S2MPS_RSVD,
+ S2MPS_RTC_SEC,
+ S2MPS_RTC_MIN,
+ S2MPS_RTC_HOUR,
+ S2MPS_RTC_WEEKDAY,
+ S2MPS_RTC_DATE,
+ S2MPS_RTC_MONTH,
+ S2MPS_RTC_YEAR,
+ S2MPS_ALARM0_SEC,
+ S2MPS_ALARM0_MIN,
+ S2MPS_ALARM0_HOUR,
+ S2MPS_ALARM0_WEEKDAY,
+ S2MPS_ALARM0_DATE,
+ S2MPS_ALARM0_MONTH,
+ S2MPS_ALARM0_YEAR,
+ S2MPS_ALARM1_SEC,
+ S2MPS_ALARM1_MIN,
+ S2MPS_ALARM1_HOUR,
+ S2MPS_ALARM1_WEEKDAY,
+ S2MPS_ALARM1_DATE,
+ S2MPS_ALARM1_MONTH,
+ S2MPS_ALARM1_YEAR,
+ S2MPS_OFFSRC,
+
+ S2MPS_RTC_REG_MAX,
};
#define RTC_I2C_ADDR (0x0C >> 1)
@@ -54,6 +92,9 @@ enum sec_rtc_reg {
#define ALARM1_STATUS (1 << 2)
#define UPDATE_AD (1 << 0)
+#define S2MPS_ALARM0_STATUS (1 << 2)
+#define S2MPS_ALARM1_STATUS (1 << 1)
+
/* RTC Control Register */
#define BCD_EN_SHIFT 0
#define BCD_EN_MASK (1 << BCD_EN_SHIFT)
@@ -62,6 +103,10 @@ enum sec_rtc_reg {
/* RTC Update Register1 */
#define RTC_UDR_SHIFT 0
#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT)
+#define S2MPS_RTC_WUDR_SHIFT 4
+#define S2MPS_RTC_WUDR_MASK (1 << S2MPS_RTC_WUDR_SHIFT)
+#define S2MPS_RTC_RUDR_SHIFT 0
+#define S2MPS_RTC_RUDR_MASK (1 << S2MPS_RTC_RUDR_SHIFT)
#define RTC_TCON_SHIFT 1
#define RTC_TCON_MASK (1 << RTC_TCON_SHIFT)
#define RTC_TIME_EN_SHIFT 3
diff --git a/include/linux/mfd/samsung/s2mpa01.h b/include/linux/mfd/samsung/s2mpa01.h
new file mode 100644
index 000000000000..fbc63bc0d6a2
--- /dev/null
+++ b/include/linux/mfd/samsung/s2mpa01.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd
+ * http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_S2MPA01_H
+#define __LINUX_MFD_S2MPA01_H
+
+/* S2MPA01 registers */
+enum s2mpa01_reg {
+ S2MPA01_REG_ID,
+ S2MPA01_REG_INT1,
+ S2MPA01_REG_INT2,
+ S2MPA01_REG_INT3,
+ S2MPA01_REG_INT1M,
+ S2MPA01_REG_INT2M,
+ S2MPA01_REG_INT3M,
+ S2MPA01_REG_ST1,
+ S2MPA01_REG_ST2,
+ S2MPA01_REG_PWRONSRC,
+ S2MPA01_REG_OFFSRC,
+ S2MPA01_REG_RTC_BUF,
+ S2MPA01_REG_CTRL1,
+ S2MPA01_REG_ETC_TEST,
+ S2MPA01_REG_RSVD1,
+ S2MPA01_REG_BU_CHG,
+ S2MPA01_REG_RAMP1,
+ S2MPA01_REG_RAMP2,
+ S2MPA01_REG_LDO_DSCH1,
+ S2MPA01_REG_LDO_DSCH2,
+ S2MPA01_REG_LDO_DSCH3,
+ S2MPA01_REG_LDO_DSCH4,
+ S2MPA01_REG_OTP_ADRL,
+ S2MPA01_REG_OTP_ADRH,
+ S2MPA01_REG_OTP_DATA,
+ S2MPA01_REG_MON1SEL,
+ S2MPA01_REG_MON2SEL,
+ S2MPA01_REG_LEE,
+ S2MPA01_REG_RSVD2,
+ S2MPA01_REG_RSVD3,
+ S2MPA01_REG_RSVD4,
+ S2MPA01_REG_RSVD5,
+ S2MPA01_REG_RSVD6,
+ S2MPA01_REG_TOP_RSVD,
+ S2MPA01_REG_DVS_SEL,
+ S2MPA01_REG_DVS_PTR,
+ S2MPA01_REG_DVS_DATA,
+ S2MPA01_REG_RSVD_NO,
+ S2MPA01_REG_UVLO,
+ S2MPA01_REG_LEE_NO,
+ S2MPA01_REG_B1CTRL1,
+ S2MPA01_REG_B1CTRL2,
+ S2MPA01_REG_B2CTRL1,
+ S2MPA01_REG_B2CTRL2,
+ S2MPA01_REG_B3CTRL1,
+ S2MPA01_REG_B3CTRL2,
+ S2MPA01_REG_B4CTRL1,
+ S2MPA01_REG_B4CTRL2,
+ S2MPA01_REG_B5CTRL1,
+ S2MPA01_REG_B5CTRL2,
+ S2MPA01_REG_B5CTRL3,
+ S2MPA01_REG_B5CTRL4,
+ S2MPA01_REG_B5CTRL5,
+ S2MPA01_REG_B5CTRL6,
+ S2MPA01_REG_B6CTRL1,
+ S2MPA01_REG_B6CTRL2,
+ S2MPA01_REG_B7CTRL1,
+ S2MPA01_REG_B7CTRL2,
+ S2MPA01_REG_B8CTRL1,
+ S2MPA01_REG_B8CTRL2,
+ S2MPA01_REG_B9CTRL1,
+ S2MPA01_REG_B9CTRL2,
+ S2MPA01_REG_B10CTRL1,
+ S2MPA01_REG_B10CTRL2,
+ S2MPA01_REG_L1CTRL,
+ S2MPA01_REG_L2CTRL,
+ S2MPA01_REG_L3CTRL,
+ S2MPA01_REG_L4CTRL,
+ S2MPA01_REG_L5CTRL,
+ S2MPA01_REG_L6CTRL,
+ S2MPA01_REG_L7CTRL,
+ S2MPA01_REG_L8CTRL,
+ S2MPA01_REG_L9CTRL,
+ S2MPA01_REG_L10CTRL,
+ S2MPA01_REG_L11CTRL,
+ S2MPA01_REG_L12CTRL,
+ S2MPA01_REG_L13CTRL,
+ S2MPA01_REG_L14CTRL,
+ S2MPA01_REG_L15CTRL,
+ S2MPA01_REG_L16CTRL,
+ S2MPA01_REG_L17CTRL,
+ S2MPA01_REG_L18CTRL,
+ S2MPA01_REG_L19CTRL,
+ S2MPA01_REG_L20CTRL,
+ S2MPA01_REG_L21CTRL,
+ S2MPA01_REG_L22CTRL,
+ S2MPA01_REG_L23CTRL,
+ S2MPA01_REG_L24CTRL,
+ S2MPA01_REG_L25CTRL,
+ S2MPA01_REG_L26CTRL,
+
+ S2MPA01_REG_LDO_OVCB1,
+ S2MPA01_REG_LDO_OVCB2,
+ S2MPA01_REG_LDO_OVCB3,
+ S2MPA01_REG_LDO_OVCB4,
+
+};
+
+/* S2MPA01 regulator ids */
+enum s2mpa01_regulators {
+ S2MPA01_LDO1,
+ S2MPA01_LDO2,
+ S2MPA01_LDO3,
+ S2MPA01_LDO4,
+ S2MPA01_LDO5,
+ S2MPA01_LDO6,
+ S2MPA01_LDO7,
+ S2MPA01_LDO8,
+ S2MPA01_LDO9,
+ S2MPA01_LDO10,
+ S2MPA01_LDO11,
+ S2MPA01_LDO12,
+ S2MPA01_LDO13,
+ S2MPA01_LDO14,
+ S2MPA01_LDO15,
+ S2MPA01_LDO16,
+ S2MPA01_LDO17,
+ S2MPA01_LDO18,
+ S2MPA01_LDO19,
+ S2MPA01_LDO20,
+ S2MPA01_LDO21,
+ S2MPA01_LDO22,
+ S2MPA01_LDO23,
+ S2MPA01_LDO24,
+ S2MPA01_LDO25,
+ S2MPA01_LDO26,
+
+ S2MPA01_BUCK1,
+ S2MPA01_BUCK2,
+ S2MPA01_BUCK3,
+ S2MPA01_BUCK4,
+ S2MPA01_BUCK5,
+ S2MPA01_BUCK6,
+ S2MPA01_BUCK7,
+ S2MPA01_BUCK8,
+ S2MPA01_BUCK9,
+ S2MPA01_BUCK10,
+
+ S2MPA01_REGULATOR_MAX,
+};
+
+#define S2MPA01_BUCK_MIN1 600000
+#define S2MPA01_BUCK_MIN2 800000
+#define S2MPA01_BUCK_MIN3 1000000
+#define S2MPA01_BUCK_MIN4 1500000
+#define S2MPA01_LDO_MIN 800000
+
+#define S2MPA01_BUCK_STEP1 6250
+#define S2MPA01_BUCK_STEP2 12500
+
+#define S2MPA01_LDO_STEP1 50000
+#define S2MPA01_LDO_STEP2 25000
+
+#define S2MPA01_LDO_VSEL_MASK 0x3F
+#define S2MPA01_BUCK_VSEL_MASK 0xFF
+#define S2MPA01_ENABLE_MASK (0x03 << S2MPA01_ENABLE_SHIFT)
+#define S2MPA01_ENABLE_SHIFT 0x06
+#define S2MPA01_LDO_N_VOLTAGES (S2MPA01_LDO_VSEL_MASK + 1)
+#define S2MPA01_BUCK_N_VOLTAGES (S2MPA01_BUCK_VSEL_MASK + 1)
+
+#define S2MPA01_RAMP_DELAY 12500 /* uV/us */
+
+#define S2MPA01_BUCK16_RAMP_SHIFT 4
+#define S2MPA01_BUCK24_RAMP_SHIFT 6
+#define S2MPA01_BUCK3_RAMP_SHIFT 4
+#define S2MPA01_BUCK5_RAMP_SHIFT 6
+#define S2MPA01_BUCK7_RAMP_SHIFT 2
+#define S2MPA01_BUCK8910_RAMP_SHIFT 0
+
+#define S2MPA01_BUCK1_RAMP_EN_SHIFT 3
+#define S2MPA01_BUCK2_RAMP_EN_SHIFT 2
+#define S2MPA01_BUCK3_RAMP_EN_SHIFT 1
+#define S2MPA01_BUCK4_RAMP_EN_SHIFT 0
+#define S2MPA01_PMIC_EN_SHIFT 6
+
+#endif /*__LINUX_MFD_S2MPA01_H */
diff --git a/include/linux/mfd/samsung/s2mps14.h b/include/linux/mfd/samsung/s2mps14.h
new file mode 100644
index 000000000000..4b449b8ac548
--- /dev/null
+++ b/include/linux/mfd/samsung/s2mps14.h
@@ -0,0 +1,154 @@
+/*
+ * s2mps14.h
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ * http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ *
+ */
+
+#ifndef __LINUX_MFD_S2MPS14_H
+#define __LINUX_MFD_S2MPS14_H
+
+/* S2MPS14 registers */
+enum s2mps14_reg {
+ S2MPS14_REG_ID,
+ S2MPS14_REG_INT1,
+ S2MPS14_REG_INT2,
+ S2MPS14_REG_INT3,
+ S2MPS14_REG_INT1M,
+ S2MPS14_REG_INT2M,
+ S2MPS14_REG_INT3M,
+ S2MPS14_REG_ST1,
+ S2MPS14_REG_ST2,
+ S2MPS14_REG_PWRONSRC,
+ S2MPS14_REG_OFFSRC,
+ S2MPS14_REG_BU_CHG,
+ S2MPS14_REG_RTCCTRL,
+ S2MPS14_REG_CTRL1,
+ S2MPS14_REG_CTRL2,
+ S2MPS14_REG_RSVD1,
+ S2MPS14_REG_RSVD2,
+ S2MPS14_REG_RSVD3,
+ S2MPS14_REG_RSVD4,
+ S2MPS14_REG_RSVD5,
+ S2MPS14_REG_RSVD6,
+ S2MPS14_REG_CTRL3,
+ S2MPS14_REG_RSVD7,
+ S2MPS14_REG_RSVD8,
+ S2MPS14_REG_WRSTBI,
+ S2MPS14_REG_B1CTRL1,
+ S2MPS14_REG_B1CTRL2,
+ S2MPS14_REG_B2CTRL1,
+ S2MPS14_REG_B2CTRL2,
+ S2MPS14_REG_B3CTRL1,
+ S2MPS14_REG_B3CTRL2,
+ S2MPS14_REG_B4CTRL1,
+ S2MPS14_REG_B4CTRL2,
+ S2MPS14_REG_B5CTRL1,
+ S2MPS14_REG_B5CTRL2,
+ S2MPS14_REG_L1CTRL,
+ S2MPS14_REG_L2CTRL,
+ S2MPS14_REG_L3CTRL,
+ S2MPS14_REG_L4CTRL,
+ S2MPS14_REG_L5CTRL,
+ S2MPS14_REG_L6CTRL,
+ S2MPS14_REG_L7CTRL,
+ S2MPS14_REG_L8CTRL,
+ S2MPS14_REG_L9CTRL,
+ S2MPS14_REG_L10CTRL,
+ S2MPS14_REG_L11CTRL,
+ S2MPS14_REG_L12CTRL,
+ S2MPS14_REG_L13CTRL,
+ S2MPS14_REG_L14CTRL,
+ S2MPS14_REG_L15CTRL,
+ S2MPS14_REG_L16CTRL,
+ S2MPS14_REG_L17CTRL,
+ S2MPS14_REG_L18CTRL,
+ S2MPS14_REG_L19CTRL,
+ S2MPS14_REG_L20CTRL,
+ S2MPS14_REG_L21CTRL,
+ S2MPS14_REG_L22CTRL,
+ S2MPS14_REG_L23CTRL,
+ S2MPS14_REG_L24CTRL,
+ S2MPS14_REG_L25CTRL,
+ S2MPS14_REG_LDODSCH1,
+ S2MPS14_REG_LDODSCH2,
+ S2MPS14_REG_LDODSCH3,
+};
+
+/* S2MPS14 regulator ids */
+enum s2mps14_regulators {
+ S2MPS14_LDO1,
+ S2MPS14_LDO2,
+ S2MPS14_LDO3,
+ S2MPS14_LDO4,
+ S2MPS14_LDO5,
+ S2MPS14_LDO6,
+ S2MPS14_LDO7,
+ S2MPS14_LDO8,
+ S2MPS14_LDO9,
+ S2MPS14_LDO10,
+ S2MPS14_LDO11,
+ S2MPS14_LDO12,
+ S2MPS14_LDO13,
+ S2MPS14_LDO14,
+ S2MPS14_LDO15,
+ S2MPS14_LDO16,
+ S2MPS14_LDO17,
+ S2MPS14_LDO18,
+ S2MPS14_LDO19,
+ S2MPS14_LDO20,
+ S2MPS14_LDO21,
+ S2MPS14_LDO22,
+ S2MPS14_LDO23,
+ S2MPS14_LDO24,
+ S2MPS14_LDO25,
+ S2MPS14_BUCK1,
+ S2MPS14_BUCK2,
+ S2MPS14_BUCK3,
+ S2MPS14_BUCK4,
+ S2MPS14_BUCK5,
+
+ S2MPS14_REGULATOR_MAX,
+};
+
+/* Regulator constraints for BUCKx */
+#define S2MPS14_BUCK1235_MIN_600MV 600000
+#define S2MPS14_BUCK4_MIN_1400MV 1400000
+#define S2MPS14_BUCK1235_STEP_6_25MV 6250
+#define S2MPS14_BUCK4_STEP_12_5MV 12500
+#define S2MPS14_BUCK1235_START_SEL 0x20
+#define S2MPS14_BUCK4_START_SEL 0x40
+/*
+ * Default ramp delay in uv/us. Datasheet says that ramp delay can be
+ * controlled however it does not specify which register is used for that.
+ * Let's assume that default value will be set.
+ */
+#define S2MPS14_BUCK_RAMP_DELAY 12500
+
+/* Regulator constraints for different types of LDOx */
+#define S2MPS14_LDO_MIN_800MV 800000
+#define S2MPS14_LDO_MIN_1800MV 1800000
+#define S2MPS14_LDO_STEP_12_5MV 12500
+#define S2MPS14_LDO_STEP_25MV 25000
+
+#define S2MPS14_LDO_VSEL_MASK 0x3F
+#define S2MPS14_BUCK_VSEL_MASK 0xFF
+#define S2MPS14_ENABLE_MASK (0x03 << S2MPS14_ENABLE_SHIFT)
+#define S2MPS14_ENABLE_SHIFT 6
+/* On/Off controlled by PWREN */
+#define S2MPS14_ENABLE_SUSPEND (0x01 << S2MPS14_ENABLE_SHIFT)
+#define S2MPS14_LDO_N_VOLTAGES (S2MPS14_LDO_VSEL_MASK + 1)
+#define S2MPS14_BUCK_N_VOLTAGES (S2MPS14_BUCK_VSEL_MASK + 1)
+
+#endif /* __LINUX_MFD_S2MPS14_H */
diff --git a/include/linux/mfd/samsung/s5m8767.h b/include/linux/mfd/samsung/s5m8767.h
index 2ab0b0f03641..243b58fec33d 100644
--- a/include/linux/mfd/samsung/s5m8767.h
+++ b/include/linux/mfd/samsung/s5m8767.h
@@ -183,10 +183,17 @@ enum s5m8767_regulators {
S5M8767_REG_MAX,
};
+/* LDO_EN/BUCK_EN field in registers */
#define S5M8767_ENCTRL_SHIFT 6
#define S5M8767_ENCTRL_MASK (0x3 << S5M8767_ENCTRL_SHIFT)
/*
+ * LDO_EN/BUCK_EN register value for controlling this Buck or LDO
+ * by GPIO (PWREN, BUCKEN).
+ */
+#define S5M8767_ENCTRL_USE_GPIO 0x1
+
+/*
* Values for BUCK_RAMP field in DVS_RAMP register, matching raw values
* in mV/us.
*/
diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h
index a5a7f0130e96..54b5458ec084 100644
--- a/include/linux/mfd/tps65217.h
+++ b/include/linux/mfd/tps65217.h
@@ -252,7 +252,7 @@ struct tps65217_board {
struct tps65217 {
struct device *dev;
struct tps65217_board *pdata;
- unsigned int id;
+ unsigned long id;
struct regulator_desc desc[TPS65217_NUM_REGULATOR];
struct regulator_dev *rdev[TPS65217_NUM_REGULATOR];
struct regmap *regmap;
@@ -263,7 +263,7 @@ static inline struct tps65217 *dev_to_tps65217(struct device *dev)
return dev_get_drvdata(dev);
}
-static inline int tps65217_chip_id(struct tps65217 *tps65217)
+static inline unsigned long tps65217_chip_id(struct tps65217 *tps65217)
{
return tps65217->id;
}
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index 3737f7218f51..2cf1547096d9 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -11,23 +11,23 @@
*/
#define PSMOUSE_MINOR 1
-#define MS_BUSMOUSE_MINOR 2
-#define ATIXL_BUSMOUSE_MINOR 3
+#define MS_BUSMOUSE_MINOR 2 /* unused */
+#define ATIXL_BUSMOUSE_MINOR 3 /* unused */
/*#define AMIGAMOUSE_MINOR 4 FIXME OBSOLETE */
-#define ATARIMOUSE_MINOR 5
-#define SUN_MOUSE_MINOR 6
-#define APOLLO_MOUSE_MINOR 7
-#define PC110PAD_MINOR 9
+#define ATARIMOUSE_MINOR 5 /* unused */
+#define SUN_MOUSE_MINOR 6 /* unused */
+#define APOLLO_MOUSE_MINOR 7 /* unused */
+#define PC110PAD_MINOR 9 /* unused */
/*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */
#define WATCHDOG_MINOR 130 /* Watchdog timer */
#define TEMP_MINOR 131 /* Temperature Sensor */
#define RTC_MINOR 135
#define EFI_RTC_MINOR 136 /* EFI Time services */
#define SUN_OPENPROM_MINOR 139
-#define DMAPI_MINOR 140 /* DMAPI */
+#define DMAPI_MINOR 140 /* unused */
#define NVRAM_MINOR 144
#define SGI_MMTIMER 153
-#define STORE_QUEUE_MINOR 155
+#define STORE_QUEUE_MINOR 155 /* unused */
#define I2O_MINOR 166
#define MICROCODE_MINOR 184
#define VFIO_MINOR 196
diff --git a/include/linux/mm.h b/include/linux/mm.h
index f28f46eade6a..2eec61fe75c9 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -175,7 +175,7 @@ extern unsigned int kobjsize(const void *objp);
* Special vmas that are non-mergable, non-mlock()able.
* Note: mm/huge_memory.c VM_NO_THP depends on this definition.
*/
-#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP)
+#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP | VM_MIXEDMAP)
/*
* mapping from the currently active vm_flags protection bits (the
@@ -399,8 +399,18 @@ static inline void compound_unlock_irqrestore(struct page *page,
static inline struct page *compound_head(struct page *page)
{
- if (unlikely(PageTail(page)))
- return page->first_page;
+ if (unlikely(PageTail(page))) {
+ struct page *head = page->first_page;
+
+ /*
+ * page->first_page may be a dangling pointer to an old
+ * compound page, so recheck that it is still a tail
+ * page before returning.
+ */
+ smp_rmb();
+ if (likely(PageTail(page)))
+ return head;
+ }
return page;
}
@@ -757,7 +767,7 @@ static inline bool __cpupid_match_pid(pid_t task_pid, int cpupid)
#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
static inline int page_cpupid_xchg_last(struct page *page, int cpupid)
{
- return xchg(&page->_last_cpupid, cpupid);
+ return xchg(&page->_last_cpupid, cpupid & LAST_CPUPID_MASK);
}
static inline int page_cpupid_last(struct page *page)
@@ -766,7 +776,7 @@ static inline int page_cpupid_last(struct page *page)
}
static inline void page_cpupid_reset_last(struct page *page)
{
- page->_last_cpupid = -1;
+ page->_last_cpupid = -1 & LAST_CPUPID_MASK;
}
#else
static inline int page_cpupid_last(struct page *page)
@@ -1477,9 +1487,15 @@ static inline void pgtable_page_dtor(struct page *page)
#if USE_SPLIT_PMD_PTLOCKS
+static struct page *pmd_to_page(pmd_t *pmd)
+{
+ unsigned long mask = ~(PTRS_PER_PMD * sizeof(pmd_t) - 1);
+ return virt_to_page((void *)((unsigned long) pmd & mask));
+}
+
static inline spinlock_t *pmd_lockptr(struct mm_struct *mm, pmd_t *pmd)
{
- return ptlock_ptr(virt_to_page(pmd));
+ return ptlock_ptr(pmd_to_page(pmd));
}
static inline bool pgtable_pmd_page_ctor(struct page *page)
@@ -1498,7 +1514,7 @@ static inline void pgtable_pmd_page_dtor(struct page *page)
ptlock_free(page);
}
-#define pmd_huge_pte(mm, pmd) (virt_to_page(pmd)->pmd_huge_pte)
+#define pmd_huge_pte(mm, pmd) (pmd_to_page(pmd)->pmd_huge_pte)
#else
@@ -1740,6 +1756,9 @@ extern void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file);
extern struct file *get_mm_exe_file(struct mm_struct *mm);
extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
+extern struct vm_area_struct *_install_special_mapping(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long flags, struct page **pages);
extern int install_special_mapping(struct mm_struct *mm,
unsigned long addr, unsigned long len,
unsigned long flags, struct page **pages);
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 5f2052c83154..9b61b9bf81ac 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -590,10 +590,10 @@ static inline bool zone_is_empty(struct zone *zone)
/*
* The NUMA zonelists are doubled because we need zonelists that restrict the
- * allocations to a single node for GFP_THISNODE.
+ * allocations to a single node for __GFP_THISNODE.
*
* [0] : Zonelist with fallback
- * [1] : No fallback (GFP_THISNODE)
+ * [1] : No fallback (__GFP_THISNODE)
*/
#define MAX_ZONELISTS 2
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 45e921401b06..9a165a213d93 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -432,6 +432,14 @@ struct spi_device_id {
kernel_ulong_t driver_data; /* Data private to the driver */
};
+#define SPMI_NAME_SIZE 32
+#define SPMI_MODULE_PREFIX "spmi:"
+
+struct spmi_device_id {
+ char name[SPMI_NAME_SIZE];
+ kernel_ulong_t driver_data; /* Data private to the driver */
+};
+
/* dmi */
enum dmi_field {
DMI_NONE,
@@ -564,6 +572,15 @@ struct x86_cpu_id {
#define X86_MODEL_ANY 0
#define X86_FEATURE_ANY 0 /* Same as FPU, you can't test for that */
+/*
+ * Generic table type for matching CPU features.
+ * @feature: the bit number of the feature (0 - 65535)
+ */
+
+struct cpu_feature {
+ __u16 feature;
+};
+
#define IPACK_ANY_FORMAT 0xff
#define IPACK_ANY_ID (~0)
struct ipack_device_id {
@@ -599,4 +616,9 @@ struct rio_device_id {
__u16 asm_did, asm_vid;
};
+struct mcb_device_id {
+ __u16 device;
+ kernel_ulong_t driver_data;
+};
+
#endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index d3181936c138..11692dea18aa 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -46,6 +46,7 @@
* - detects multi-task circular deadlocks and prints out all affected
* locks and tasks (and only those tasks)
*/
+struct optimistic_spin_queue;
struct mutex {
/* 1: unlocked, 0: locked, negative: locked, possible waiters */
atomic_t count;
@@ -55,7 +56,7 @@ struct mutex {
struct task_struct *owner;
#endif
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
- void *spin_mlock; /* Spinner MCS lock */
+ struct optimistic_spin_queue *osq; /* Spinner MCS lock */
#endif
#ifdef CONFIG_DEBUG_MUTEXES
const char *name;
@@ -179,4 +180,4 @@ extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
# define arch_mutex_cpu_relax() cpu_relax()
#endif
-#endif
+#endif /* __LINUX_MUTEX_H */
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index 1005ebf17575..5a09a48f2658 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -163,4 +163,11 @@ enum {
/* changeable features with no special hardware requirements */
#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO)
+#define NETIF_F_VLAN_FEATURES (NETIF_F_HW_VLAN_CTAG_FILTER | \
+ NETIF_F_HW_VLAN_CTAG_RX | \
+ NETIF_F_HW_VLAN_CTAG_TX | \
+ NETIF_F_HW_VLAN_STAG_FILTER | \
+ NETIF_F_HW_VLAN_STAG_RX | \
+ NETIF_F_HW_VLAN_STAG_TX)
+
#endif /* _LINUX_NETDEV_FEATURES_H */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 440a02ee6f92..daafd9561cbc 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -752,6 +752,9 @@ struct netdev_phys_port_id {
unsigned char id_len;
};
+typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
+ struct sk_buff *skb);
+
/*
* This structure defines the management hooks for network devices.
* The following hooks can be defined; unless noted otherwise, they are
@@ -783,7 +786,7 @@ struct netdev_phys_port_id {
* Required can not be NULL.
*
* u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb,
- * void *accel_priv);
+ * void *accel_priv, select_queue_fallback_t fallback);
* Called to decide which queue to when device supports multiple
* transmit queues.
*
@@ -1005,7 +1008,8 @@ struct net_device_ops {
struct net_device *dev);
u16 (*ndo_select_queue)(struct net_device *dev,
struct sk_buff *skb,
- void *accel_priv);
+ void *accel_priv,
+ select_queue_fallback_t fallback);
void (*ndo_change_rx_flags)(struct net_device *dev,
int flags);
void (*ndo_set_rx_mode)(struct net_device *dev);
@@ -1551,7 +1555,6 @@ static inline void netdev_for_each_tx_queue(struct net_device *dev,
struct netdev_queue *netdev_pick_tx(struct net_device *dev,
struct sk_buff *skb,
void *accel_priv);
-u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb);
/*
* Net namespace inlines
@@ -2276,6 +2279,26 @@ static inline void netdev_reset_queue(struct net_device *dev_queue)
}
/**
+ * netdev_cap_txqueue - check if selected tx queue exceeds device queues
+ * @dev: network device
+ * @queue_index: given tx queue index
+ *
+ * Returns 0 if given tx queue index >= number of device tx queues,
+ * otherwise returns the originally passed tx queue index.
+ */
+static inline u16 netdev_cap_txqueue(struct net_device *dev, u16 queue_index)
+{
+ if (unlikely(queue_index >= dev->real_num_tx_queues)) {
+ net_warn_ratelimited("%s selects TX queue %d, but real number of TX queues is %d\n",
+ dev->name, queue_index,
+ dev->real_num_tx_queues);
+ return 0;
+ }
+
+ return queue_index;
+}
+
+/**
* netif_running - test if up
* @dev: network device
*
@@ -2991,7 +3014,7 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, netdev_features_t features)
{
return __skb_gso_segment(skb, features, true);
}
-__be16 skb_network_protocol(struct sk_buff *skb);
+__be16 skb_network_protocol(struct sk_buff *skb, int *depth);
static inline bool can_checksum_protocol(netdev_features_t features,
__be16 protocol)
@@ -3068,7 +3091,12 @@ void netdev_change_features(struct net_device *dev);
void netif_stacked_transfer_operstate(const struct net_device *rootdev,
struct net_device *dev);
-netdev_features_t netif_skb_features(struct sk_buff *skb);
+netdev_features_t netif_skb_dev_features(struct sk_buff *skb,
+ const struct net_device *dev);
+static inline netdev_features_t netif_skb_features(struct sk_buff *skb)
+{
+ return netif_skb_dev_features(skb, skb->dev);
+}
static inline bool net_gso_ok(netdev_features_t features, int gso_type)
{
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index b2fb167b2e6d..5624e4e2763c 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -467,9 +467,14 @@ struct nfs_lockt_res {
};
struct nfs_release_lockowner_args {
+ struct nfs4_sequence_args seq_args;
struct nfs_lowner lock_owner;
};
+struct nfs_release_lockowner_res {
+ struct nfs4_sequence_res seq_res;
+};
+
struct nfs4_delegreturnargs {
struct nfs4_sequence_args seq_args;
const struct nfs_fh *fhandle;
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index 69ae03f6eb15..6b9aafed225f 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -87,6 +87,7 @@ struct nvme_dev {
struct list_head namespaces;
struct kref kref;
struct miscdevice miscdev;
+ work_func_t reset_workfn;
struct work_struct reset_work;
char name[12];
char serial[20];
diff --git a/include/linux/of.h b/include/linux/of.h
index 435cb995904d..919bf211877d 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -18,7 +18,7 @@
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/errno.h>
-#include <linux/kref.h>
+#include <linux/kobject.h>
#include <linux/mod_devicetable.h>
#include <linux/spinlock.h>
#include <linux/topology.h>
@@ -37,6 +37,7 @@ struct property {
struct property *next;
unsigned long _flags;
unsigned int unique_id;
+ struct bin_attribute attr;
};
#if defined(CONFIG_SPARC)
@@ -56,8 +57,7 @@ struct device_node {
struct device_node *sibling;
struct device_node *next; /* next device of same type */
struct device_node *allnext; /* next in list of all nodes */
- struct proc_dir_entry *pde; /* this node's proc directory */
- struct kref kref;
+ struct kobject kobj;
unsigned long _flags;
void *data;
#if defined(CONFIG_SPARC)
@@ -67,13 +67,34 @@ struct device_node {
#endif
};
-#define MAX_PHANDLE_ARGS 8
+#define MAX_PHANDLE_ARGS 16
struct of_phandle_args {
struct device_node *np;
int args_count;
uint32_t args[MAX_PHANDLE_ARGS];
};
+extern int of_node_add(struct device_node *node);
+
+/* initialize a node */
+extern struct kobj_type of_node_ktype;
+static inline void of_node_init(struct device_node *node)
+{
+ kobject_init(&node->kobj, &of_node_ktype);
+}
+
+/* true when node is initialized */
+static inline int of_node_is_initialized(struct device_node *node)
+{
+ return node && node->kobj.state_initialized;
+}
+
+/* true when node is attached (i.e. present on sysfs) */
+static inline int of_node_is_attached(struct device_node *node)
+{
+ return node && node->kobj.state_in_sysfs;
+}
+
#ifdef CONFIG_OF_DYNAMIC
extern struct device_node *of_node_get(struct device_node *node);
extern void of_node_put(struct device_node *node);
@@ -114,6 +135,26 @@ static inline void of_node_set_flag(struct device_node *n, unsigned long flag)
set_bit(flag, &n->_flags);
}
+static inline void of_node_clear_flag(struct device_node *n, unsigned long flag)
+{
+ clear_bit(flag, &n->_flags);
+}
+
+static inline int of_property_check_flag(struct property *p, unsigned long flag)
+{
+ return test_bit(flag, &p->_flags);
+}
+
+static inline void of_property_set_flag(struct property *p, unsigned long flag)
+{
+ set_bit(flag, &p->_flags);
+}
+
+static inline void of_property_clear_flag(struct property *p, unsigned long flag)
+{
+ clear_bit(flag, &p->_flags);
+}
+
extern struct device_node *of_find_all_nodes(struct device_node *prev);
/*
@@ -167,6 +208,8 @@ static inline const char *of_node_full_name(const struct device_node *np)
return np ? np->full_name : "<no-node>";
}
+#define for_each_of_allnodes(dn) \
+ for (dn = of_allnodes; dn; dn = dn->allnext)
extern struct device_node *of_find_node_by_name(struct device_node *from,
const char *name);
extern struct device_node *of_find_node_by_type(struct device_node *from,
@@ -198,6 +241,8 @@ extern struct device_node *of_find_node_with_property(
extern struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp);
+extern int of_property_count_elems_of_size(const struct device_node *np,
+ const char *propname, int elem_size);
extern int of_property_read_u32_index(const struct device_node *np,
const char *propname,
u32 index, u32 *out_value);
@@ -390,6 +435,12 @@ static inline struct device_node *of_find_compatible_node(
return NULL;
}
+static inline int of_property_count_elems_of_size(const struct device_node *np,
+ const char *propname, int elem_size)
+{
+ return -ENOSYS;
+}
+
static inline int of_property_read_u32_index(const struct device_node *np,
const char *propname, u32 index, u32 *out_value)
{
@@ -536,6 +587,74 @@ static inline struct device_node *of_find_matching_node(
}
/**
+ * of_property_count_u8_elems - Count the number of u8 elements in a property
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device node and count the number of u8 elements
+ * in it. Returns number of elements on sucess, -EINVAL if the property does
+ * not exist or its length does not match a multiple of u8 and -ENODATA if the
+ * property does not have a value.
+ */
+static inline int of_property_count_u8_elems(const struct device_node *np,
+ const char *propname)
+{
+ return of_property_count_elems_of_size(np, propname, sizeof(u8));
+}
+
+/**
+ * of_property_count_u16_elems - Count the number of u16 elements in a property
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device node and count the number of u16 elements
+ * in it. Returns number of elements on sucess, -EINVAL if the property does
+ * not exist or its length does not match a multiple of u16 and -ENODATA if the
+ * property does not have a value.
+ */
+static inline int of_property_count_u16_elems(const struct device_node *np,
+ const char *propname)
+{
+ return of_property_count_elems_of_size(np, propname, sizeof(u16));
+}
+
+/**
+ * of_property_count_u32_elems - Count the number of u32 elements in a property
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device node and count the number of u32 elements
+ * in it. Returns number of elements on sucess, -EINVAL if the property does
+ * not exist or its length does not match a multiple of u32 and -ENODATA if the
+ * property does not have a value.
+ */
+static inline int of_property_count_u32_elems(const struct device_node *np,
+ const char *propname)
+{
+ return of_property_count_elems_of_size(np, propname, sizeof(u32));
+}
+
+/**
+ * of_property_count_u64_elems - Count the number of u64 elements in a property
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device node and count the number of u64 elements
+ * in it. Returns number of elements on sucess, -EINVAL if the property does
+ * not exist or its length does not match a multiple of u64 and -ENODATA if the
+ * property does not have a value.
+ */
+static inline int of_property_count_u64_elems(const struct device_node *np,
+ const char *propname)
+{
+ return of_property_count_elems_of_size(np, propname, sizeof(u64));
+}
+
+/**
* of_property_read_bool - Findfrom a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
@@ -633,14 +752,4 @@ static inline int of_get_available_child_count(const struct device_node *np)
return num;
}
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
-extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
-extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
-extern void proc_device_tree_remove_prop(struct proc_dir_entry *pde,
- struct property *prop);
-extern void proc_device_tree_update_prop(struct proc_dir_entry *pde,
- struct property *newprop,
- struct property *oldprop);
-#endif
-
#endif /* _LINUX_OF_H */
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index 2b77058a7335..ddd7219af8ac 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -98,7 +98,10 @@ extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data);
extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
int depth, void *data);
+extern void early_init_fdt_scan_reserved_mem(void);
extern void early_init_dt_add_memory_arch(u64 base, u64 size);
+extern int early_init_dt_reserve_memory_arch(phys_addr_t base, phys_addr_t size,
+ bool no_map);
extern void * early_init_dt_alloc_memory_arch(u64 size, u64 align);
extern u64 dt_mem_next_cell(int s, __be32 **cellp);
@@ -118,6 +121,7 @@ extern void unflatten_and_copy_device_tree(void);
extern void early_init_devtree(void *);
extern void early_get_first_memblock_info(void *, phys_addr_t *);
#else /* CONFIG_OF_FLATTREE */
+static inline void early_init_fdt_scan_reserved_mem(void) {}
static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }
static inline void unflatten_device_tree(void) {}
static inline void unflatten_and_copy_device_tree(void) {}
diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h
new file mode 100644
index 000000000000..befef42e015b
--- /dev/null
+++ b/include/linux/of_graph.h
@@ -0,0 +1,66 @@
+/*
+ * OF graph binding parsing helpers
+ *
+ * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * Copyright (C) 2012 Renesas Electronics Corp.
+ * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * 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.
+ */
+#ifndef __LINUX_OF_GRAPH_H
+#define __LINUX_OF_GRAPH_H
+
+/**
+ * struct of_endpoint - the OF graph endpoint data structure
+ * @port: identifier (value of reg property) of a port this endpoint belongs to
+ * @id: identifier (value of reg property) of this endpoint
+ * @local_node: pointer to device_node of this endpoint
+ */
+struct of_endpoint {
+ unsigned int port;
+ unsigned int id;
+ const struct device_node *local_node;
+};
+
+#ifdef CONFIG_OF
+int of_graph_parse_endpoint(const struct device_node *node,
+ struct of_endpoint *endpoint);
+struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
+ struct device_node *previous);
+struct device_node *of_graph_get_remote_port_parent(
+ const struct device_node *node);
+struct device_node *of_graph_get_remote_port(const struct device_node *node);
+#else
+
+static inline int of_graph_parse_endpoint(const struct device_node *node,
+ struct of_endpoint *endpoint)
+{
+ return -ENOSYS;
+}
+
+static inline struct device_node *of_graph_get_next_endpoint(
+ const struct device_node *parent,
+ struct device_node *previous)
+{
+ return NULL;
+}
+
+static inline struct device_node *of_graph_get_remote_port_parent(
+ const struct device_node *node)
+{
+ return NULL;
+}
+
+static inline struct device_node *of_graph_get_remote_port(
+ const struct device_node *node)
+{
+ return NULL;
+}
+
+#endif /* CONFIG_OF */
+
+#endif /* __LINUX_OF_GRAPH_H */
diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
new file mode 100644
index 000000000000..9b1fbb7f29fc
--- /dev/null
+++ b/include/linux/of_reserved_mem.h
@@ -0,0 +1,53 @@
+#ifndef __OF_RESERVED_MEM_H
+#define __OF_RESERVED_MEM_H
+
+struct device;
+struct of_phandle_args;
+struct reserved_mem_ops;
+
+struct reserved_mem {
+ const char *name;
+ unsigned long fdt_node;
+ const struct reserved_mem_ops *ops;
+ phys_addr_t base;
+ phys_addr_t size;
+ void *priv;
+};
+
+struct reserved_mem_ops {
+ void (*device_init)(struct reserved_mem *rmem,
+ struct device *dev);
+ void (*device_release)(struct reserved_mem *rmem,
+ struct device *dev);
+};
+
+typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem,
+ unsigned long node, const char *uname);
+
+#ifdef CONFIG_OF_RESERVED_MEM
+void fdt_init_reserved_mem(void);
+void fdt_reserved_mem_save_node(unsigned long node, const char *uname,
+ phys_addr_t base, phys_addr_t size);
+
+#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
+ static const struct of_device_id __reservedmem_of_table_##name \
+ __used __section(__reservedmem_of_table) \
+ = { .compatible = compat, \
+ .data = (init == (reservedmem_of_init_fn)NULL) ? \
+ init : init }
+
+#else
+static inline void fdt_init_reserved_mem(void) { }
+static inline void fdt_reserved_mem_save_node(unsigned long node,
+ const char *uname, phys_addr_t base, phys_addr_t size) { }
+
+#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
+ static const struct of_device_id __reservedmem_of_table_##name \
+ __attribute__((unused)) \
+ = { .compatible = compat, \
+ .data = (init == (reservedmem_of_init_fn)NULL) ? \
+ init : init }
+
+#endif
+
+#endif /* __OF_RESERVED_MEM_H */
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 5a462c4e5009..637a608ded0b 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -59,12 +59,12 @@ static inline void acpi_pci_slot_remove(struct pci_bus *bus) { }
void acpiphp_init(void);
void acpiphp_enumerate_slots(struct pci_bus *bus);
void acpiphp_remove_slots(struct pci_bus *bus);
-void acpiphp_check_host_bridge(acpi_handle handle);
+void acpiphp_check_host_bridge(struct acpi_device *adev);
#else
static inline void acpiphp_init(void) { }
static inline void acpiphp_enumerate_slots(struct pci_bus *bus) { }
static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
-static inline void acpiphp_check_host_bridge(acpi_handle handle) { }
+static inline void acpiphp_check_host_bridge(struct acpi_device *adev) { }
#endif
#else /* CONFIG_ACPI */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index fb57c892b214..aab57b4abe7f 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -29,7 +29,6 @@
#include <linux/atomic.h>
#include <linux/device.h>
#include <linux/io.h>
-#include <linux/irqreturn.h>
#include <uapi/linux/pci.h>
#include <linux/pci_ids.h>
@@ -170,6 +169,8 @@ enum pci_dev_flags {
PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2,
/* Provide indication device is assigned by a Virtual Machine Manager */
PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4,
+ /* Flag for quirk use to store if quirk-specific ACS is enabled */
+ PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) 8,
};
enum pci_irq_reroute_variant {
@@ -461,7 +462,6 @@ struct pci_bus {
unsigned int is_added:1;
};
-#define pci_bus_b(n) list_entry(n, struct pci_bus, node)
#define to_pci_bus(n) container_of(n, struct pci_bus, dev)
/*
@@ -1066,7 +1066,7 @@ void pci_bus_remove_resources(struct pci_bus *bus);
int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
struct resource *res, resource_size_t size,
resource_size_t align, resource_size_t min,
- unsigned int type_mask,
+ unsigned long type_mask,
resource_size_t (*alignf)(void *,
const struct resource *,
resource_size_t,
@@ -1169,8 +1169,23 @@ void msi_remove_pci_irq_vectors(struct pci_dev *dev);
void pci_restore_msi_state(struct pci_dev *dev);
int pci_msi_enabled(void);
int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec);
+static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
+{
+ int rc = pci_enable_msi_range(dev, nvec, nvec);
+ if (rc < 0)
+ return rc;
+ return 0;
+}
int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
int minvec, int maxvec);
+static inline int pci_enable_msix_exact(struct pci_dev *dev,
+ struct msix_entry *entries, int nvec)
+{
+ int rc = pci_enable_msix_range(dev, entries, nvec, nvec);
+ if (rc < 0)
+ return rc;
+ return 0;
+}
#else
static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; }
static inline int pci_enable_msi_block(struct pci_dev *dev, int nvec)
@@ -1189,9 +1204,14 @@ static inline int pci_msi_enabled(void) { return 0; }
static inline int pci_enable_msi_range(struct pci_dev *dev, int minvec,
int maxvec)
{ return -ENOSYS; }
+static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
+{ return -ENOSYS; }
static inline int pci_enable_msix_range(struct pci_dev *dev,
struct msix_entry *entries, int minvec, int maxvec)
{ return -ENOSYS; }
+static inline int pci_enable_msix_exact(struct pci_dev *dev,
+ struct msix_entry *entries, int nvec)
+{ return -ENOSYS; }
#endif
#ifdef CONFIG_PCIEPORTBUS
@@ -1510,6 +1530,7 @@ enum pci_fixup_pass {
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
struct pci_dev *pci_get_dma_source(struct pci_dev *dev);
int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
+void pci_dev_specific_enable_acs(struct pci_dev *dev);
#else
static inline void pci_fixup_device(enum pci_fixup_pass pass,
struct pci_dev *dev) { }
@@ -1522,6 +1543,7 @@ static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev,
{
return -ENOTTY;
}
+static inline void pci_dev_specific_enable_acs(struct pci_dev *dev) { }
#endif
void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
@@ -1577,7 +1599,6 @@ void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar);
#ifdef CONFIG_PCI_IOV
int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
void pci_disable_sriov(struct pci_dev *dev);
-irqreturn_t pci_sriov_migration(struct pci_dev *dev);
int pci_num_vf(struct pci_dev *dev);
int pci_vfs_assigned(struct pci_dev *dev);
int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
@@ -1586,8 +1607,6 @@ int pci_sriov_get_totalvfs(struct pci_dev *dev);
static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
{ return -ENODEV; }
static inline void pci_disable_sriov(struct pci_dev *dev) { }
-static inline irqreturn_t pci_sriov_migration(struct pci_dev *dev)
-{ return IRQ_NONE; }
static inline int pci_num_vf(struct pci_dev *dev) { return 0; }
static inline int pci_vfs_assigned(struct pci_dev *dev)
{ return 0; }
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 97fbecdd7a40..d4de24b4d4c6 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -528,6 +528,8 @@
#define PCI_DEVICE_ID_AMD_15H_NB_F5 0x1605
#define PCI_DEVICE_ID_AMD_16H_NB_F3 0x1533
#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534
+#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F3 0x1583
+#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F4 0x1584
#define PCI_DEVICE_ID_AMD_CNB17H_F3 0x1703
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
@@ -726,6 +728,7 @@
#define PCI_DEVICE_ID_SI_7018 0x7018
#define PCI_VENDOR_ID_HP 0x103c
+#define PCI_VENDOR_ID_HP_3PAR 0x1590
#define PCI_DEVICE_ID_HP_VISUALIZE_EG 0x1005
#define PCI_DEVICE_ID_HP_VISUALIZE_FX6 0x1006
#define PCI_DEVICE_ID_HP_VISUALIZE_FX4 0x1008
@@ -2531,6 +2534,9 @@
#define PCI_VENDOR_ID_INTEL 0x8086
#define PCI_DEVICE_ID_INTEL_EESSC 0x0008
+#define PCI_DEVICE_ID_INTEL_SNB_IMC 0x0100
+#define PCI_DEVICE_ID_INTEL_IVB_IMC 0x0154
+#define PCI_DEVICE_ID_INTEL_HSW_IMC 0x0c00
#define PCI_DEVICE_ID_INTEL_PXHD_0 0x0320
#define PCI_DEVICE_ID_INTEL_PXHD_1 0x0321
#define PCI_DEVICE_ID_INTEL_PXH_0 0x0329
diff --git a/include/linux/usb/omap_control_usb.h b/include/linux/phy/omap_control_phy.h
index 69ae383ee3cc..5450403c7546 100644
--- a/include/linux/usb/omap_control_usb.h
+++ b/include/linux/phy/omap_control_phy.h
@@ -1,5 +1,5 @@
/*
- * omap_control_usb.h - Header file for the USB part of control module.
+ * omap_control_phy.h - Header file for the PHY part of control module.
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
* This program is free software; you can redistribute it and/or modify
@@ -16,10 +16,10 @@
*
*/
-#ifndef __OMAP_CONTROL_USB_H__
-#define __OMAP_CONTROL_USB_H__
+#ifndef __OMAP_CONTROL_PHY_H__
+#define __OMAP_CONTROL_PHY_H__
-enum omap_control_usb_type {
+enum omap_control_phy_type {
OMAP_CTRL_TYPE_OTGHS = 1, /* Mailbox OTGHS_CONTROL */
OMAP_CTRL_TYPE_USB2, /* USB2_PHY, power down in CONTROL_DEV_CONF */
OMAP_CTRL_TYPE_PIPE3, /* PIPE3 PHY, DPLL & seperate Rx/Tx power */
@@ -27,7 +27,7 @@ enum omap_control_usb_type {
OMAP_CTRL_TYPE_AM437USB2, /* USB2 PHY, power e.g. AM437x */
};
-struct omap_control_usb {
+struct omap_control_phy {
struct device *dev;
u32 __iomem *otghs_control;
@@ -36,7 +36,7 @@ struct omap_control_usb {
struct clk *sys_clk;
- enum omap_control_usb_type type;
+ enum omap_control_phy_type type;
};
enum omap_control_usb_mode {
@@ -54,14 +54,14 @@ enum omap_control_usb_mode {
#define OMAP_CTRL_DEV_SESSEND BIT(3)
#define OMAP_CTRL_DEV_IDDIG BIT(4)
-#define OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK 0x003FC000
-#define OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT 0xE
+#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK 0x003FC000
+#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT 0xE
-#define OMAP_CTRL_USB_PWRCTL_CLK_FREQ_MASK 0xFFC00000
-#define OMAP_CTRL_USB_PWRCTL_CLK_FREQ_SHIFT 0x16
+#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK 0xFFC00000
+#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT 0x16
-#define OMAP_CTRL_USB3_PHY_TX_RX_POWERON 0x3
-#define OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF 0x0
+#define OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON 0x3
+#define OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF 0x0
#define OMAP_CTRL_USB2_PHY_PD BIT(28)
@@ -70,13 +70,13 @@ enum omap_control_usb_mode {
#define AM437X_CTRL_USB2_OTGVDET_EN BIT(19)
#define AM437X_CTRL_USB2_OTGSESSEND_EN BIT(20)
-#if IS_ENABLED(CONFIG_OMAP_CONTROL_USB)
-extern void omap_control_usb_phy_power(struct device *dev, int on);
-extern void omap_control_usb_set_mode(struct device *dev,
- enum omap_control_usb_mode mode);
+#if IS_ENABLED(CONFIG_OMAP_CONTROL_PHY)
+void omap_control_phy_power(struct device *dev, int on);
+void omap_control_usb_set_mode(struct device *dev,
+ enum omap_control_usb_mode mode);
#else
-static inline void omap_control_usb_phy_power(struct device *dev, int on)
+static inline void omap_control_phy_power(struct device *dev, int on)
{
}
@@ -86,4 +86,4 @@ static inline void omap_control_usb_set_mode(struct device *dev,
}
#endif
-#endif /* __OMAP_CONTROL_USB_H__ */
+#endif /* __OMAP_CONTROL_PHY_H__ */
diff --git a/include/linux/usb/omap_usb.h b/include/linux/phy/omap_usb.h
index 6ae29360e1d2..dc2c541a619b 100644
--- a/include/linux/usb/omap_usb.h
+++ b/include/linux/phy/omap_usb.h
@@ -34,14 +34,24 @@ struct omap_usb {
struct usb_phy phy;
struct phy_companion *comparator;
void __iomem *pll_ctrl_base;
+ void __iomem *phy_base;
struct device *dev;
struct device *control_dev;
struct clk *wkupclk;
- struct clk *sys_clk;
struct clk *optclk;
- u8 is_suspended:1;
+ u8 flags;
};
+struct usb_phy_data {
+ const char *label;
+ u8 flags;
+};
+
+/* Driver Flags */
+#define OMAP_USB2_HAS_START_SRP (1 << 0)
+#define OMAP_USB2_HAS_SET_VBUS (1 << 1)
+#define OMAP_USB2_CALIBRATE_FALSE_DISCONNECT (1 << 2)
+
#define phy_to_omapusb(x) container_of((x), struct omap_usb, phy)
#if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE)
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 3f83459dbb20..e2f5ca96cddc 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -149,8 +149,11 @@ struct phy *phy_get(struct device *dev, const char *string);
struct phy *phy_optional_get(struct device *dev, const char *string);
struct phy *devm_phy_get(struct device *dev, const char *string);
struct phy *devm_phy_optional_get(struct device *dev, const char *string);
+struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
+ const char *con_id);
void phy_put(struct phy *phy);
void devm_phy_put(struct device *dev, struct phy *phy);
+struct phy *of_phy_get(struct device_node *np, const char *con_id);
struct phy *of_phy_simple_xlate(struct device *dev,
struct of_phandle_args *args);
struct phy *phy_create(struct device *dev, const struct phy_ops *ops,
@@ -251,6 +254,13 @@ static inline struct phy *devm_phy_optional_get(struct device *dev,
return ERR_PTR(-ENOSYS);
}
+static inline struct phy *devm_of_phy_get(struct device *dev,
+ struct device_node *np,
+ const char *con_id)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
static inline void phy_put(struct phy *phy)
{
}
@@ -259,6 +269,11 @@ static inline void devm_phy_put(struct device *dev, struct phy *phy)
{
}
+static inline struct phy *of_phy_get(struct device_node *np, const char *con_id)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
static inline struct phy *of_phy_simple_xlate(struct device *dev,
struct of_phandle_args *args)
{
diff --git a/include/linux/platform_data/adau1977.h b/include/linux/platform_data/adau1977.h
new file mode 100644
index 000000000000..bed11d908f92
--- /dev/null
+++ b/include/linux/platform_data/adau1977.h
@@ -0,0 +1,45 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __LINUX_PLATFORM_DATA_ADAU1977_H__
+#define __LINUX_PLATFORM_DATA_ADAU1977_H__
+
+/**
+ * enum adau1977_micbias - ADAU1977 MICBIAS pin voltage setting
+ * @ADAU1977_MICBIAS_5V0: MICBIAS is set to 5.0 V
+ * @ADAU1977_MICBIAS_5V5: MICBIAS is set to 5.5 V
+ * @ADAU1977_MICBIAS_6V0: MICBIAS is set to 6.0 V
+ * @ADAU1977_MICBIAS_6V5: MICBIAS is set to 6.5 V
+ * @ADAU1977_MICBIAS_7V0: MICBIAS is set to 7.0 V
+ * @ADAU1977_MICBIAS_7V5: MICBIAS is set to 7.5 V
+ * @ADAU1977_MICBIAS_8V0: MICBIAS is set to 8.0 V
+ * @ADAU1977_MICBIAS_8V5: MICBIAS is set to 8.5 V
+ * @ADAU1977_MICBIAS_9V0: MICBIAS is set to 9.0 V
+ */
+enum adau1977_micbias {
+ ADAU1977_MICBIAS_5V0 = 0x0,
+ ADAU1977_MICBIAS_5V5 = 0x1,
+ ADAU1977_MICBIAS_6V0 = 0x2,
+ ADAU1977_MICBIAS_6V5 = 0x3,
+ ADAU1977_MICBIAS_7V0 = 0x4,
+ ADAU1977_MICBIAS_7V5 = 0x5,
+ ADAU1977_MICBIAS_8V0 = 0x6,
+ ADAU1977_MICBIAS_8V5 = 0x7,
+ ADAU1977_MICBIAS_9V0 = 0x8,
+};
+
+/**
+ * struct adau1977_platform_data - Platform configuration data for the ADAU1977
+ * @micbias: Specifies the voltage for the MICBIAS pin
+ */
+struct adau1977_platform_data {
+ enum adau1977_micbias micbias;
+};
+
+#endif
diff --git a/include/linux/platform_data/asoc-s3c.h b/include/linux/platform_data/asoc-s3c.h
index 9efc04dd255a..709c6f7e2f8c 100644
--- a/include/linux/platform_data/asoc-s3c.h
+++ b/include/linux/platform_data/asoc-s3c.h
@@ -1,5 +1,4 @@
-/* arch/arm/plat-samsung/include/plat/audio.h
- *
+/*
* Copyright (c) 2009 Samsung Electronics Co. Ltd
* Author: Jaswinder Singh <jassi.brar@samsung.com>
*
diff --git a/include/linux/platform_data/asoc-s3c24xx_simtec.h b/include/linux/platform_data/asoc-s3c24xx_simtec.h
index 376af5286a3e..d220e54123aa 100644
--- a/include/linux/platform_data/asoc-s3c24xx_simtec.h
+++ b/include/linux/platform_data/asoc-s3c24xx_simtec.h
@@ -1,5 +1,4 @@
-/* arch/arm/plat-samsung/include/plat/audio-simtec.h
- *
+/*
* Copyright 2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
diff --git a/include/linux/platform_data/bt-nokia-h4p.h b/include/linux/platform_data/bt-nokia-h4p.h
new file mode 100644
index 000000000000..30d169dfadf3
--- /dev/null
+++ b/include/linux/platform_data/bt-nokia-h4p.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+/**
+ * struct hci_h4p_platform data - hci_h4p Platform data structure
+ */
+struct hci_h4p_platform_data {
+ int chip_type;
+ int bt_sysclk;
+ unsigned int bt_wakeup_gpio;
+ unsigned int host_wakeup_gpio;
+ unsigned int reset_gpio;
+ int reset_gpio_shared;
+ unsigned int uart_irq;
+ phys_addr_t uart_base;
+ const char *uart_iclk;
+ const char *uart_fclk;
+ void (*set_pm_limits)(struct device *dev, bool set);
+};
diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h
index 5245992b0367..85ad68f9206a 100644
--- a/include/linux/platform_data/davinci_asp.h
+++ b/include/linux/platform_data/davinci_asp.h
@@ -18,7 +18,7 @@
#include <linux/genalloc.h>
-struct snd_platform_data {
+struct davinci_mcasp_pdata {
u32 tx_dma_offset;
u32 rx_dma_offset;
int asp_chan_q; /* event queue number for ASP channel */
@@ -87,6 +87,8 @@ struct snd_platform_data {
int tx_dma_channel;
int rx_dma_channel;
};
+/* TODO: Fix arch/arm/mach-davinci/ users and remove this define */
+#define snd_platform_data davinci_mcasp_pdata
enum {
MCASP_VERSION_1 = 0, /* DM646x */
diff --git a/include/linux/platform_data/max310x.h b/include/linux/platform_data/max310x.h
deleted file mode 100644
index dd11dcd1a184..000000000000
--- a/include/linux/platform_data/max310x.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver
- *
- * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
- *
- * Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
- * Based on max3110.c, by Feng Tang <feng.tang@intel.com>
- * Based on max3107.c, by Aavamobile
- *
- * This program is free software; 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 _MAX310X_H_
-#define _MAX310X_H_
-
-/*
- * Example board initialization data:
- *
- * static struct max310x_pdata max3107_pdata = {
- * .driver_flags = MAX310X_EXT_CLK,
- * .uart_flags[0] = MAX310X_ECHO_SUPRESS | MAX310X_AUTO_DIR_CTRL,
- * .frequency = 3686400,
- * .gpio_base = -1,
- * };
- *
- * static struct spi_board_info spi_device_max3107[] = {
- * {
- * .modalias = "max3107",
- * .irq = IRQ_EINT3,
- * .bus_num = 1,
- * .chip_select = 1,
- * .platform_data = &max3107_pdata,
- * },
- * };
- */
-
-#define MAX310X_MAX_UARTS 4
-
-/* MAX310X platform data structure */
-struct max310x_pdata {
- /* Flags global to driver */
- const u8 driver_flags;
-#define MAX310X_EXT_CLK (0x00000001) /* External clock enable */
- /* Flags global to UART port */
- const u8 uart_flags[MAX310X_MAX_UARTS];
-#define MAX310X_LOOPBACK (0x00000001) /* Loopback mode enable */
-#define MAX310X_ECHO_SUPRESS (0x00000002) /* Enable echo supress */
-#define MAX310X_AUTO_DIR_CTRL (0x00000004) /* Enable Auto direction
- * control (RS-485)
- */
- /* Frequency (extrenal clock or crystal) */
- const int frequency;
- /* GPIO base number (can be negative) */
- const int gpio_base;
- /* Called during startup */
- void (*init)(void);
- /* Called before finish */
- void (*exit)(void);
-};
-
-#endif
diff --git a/include/linux/platform_data/serial-imx.h b/include/linux/platform_data/serial-imx.h
index 4adec9b154dd..3cc2e3c40914 100644
--- a/include/linux/platform_data/serial-imx.h
+++ b/include/linux/platform_data/serial-imx.h
@@ -23,8 +23,6 @@
#define IMXUART_IRDA (1<<1)
struct imxuart_platform_data {
- int (*init)(struct platform_device *pdev);
- void (*exit)(struct platform_device *pdev);
unsigned int flags;
void (*irda_enable)(int enable);
unsigned int irda_inv_rx:1;
diff --git a/include/linux/platform_data/spi-s3c64xx.h b/include/linux/platform_data/spi-s3c64xx.h
index 8447f634c7f5..d3889b98a1a1 100644
--- a/include/linux/platform_data/spi-s3c64xx.h
+++ b/include/linux/platform_data/spi-s3c64xx.h
@@ -1,5 +1,4 @@
-/* linux/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
- *
+/*
* Copyright (C) 2009 Samsung Electronics Ltd.
* Jaswinder Singh <jassi.brar@samsung.com>
*
@@ -8,8 +7,8 @@
* published by the Free Software Foundation.
*/
-#ifndef __S3C64XX_PLAT_SPI_H
-#define __S3C64XX_PLAT_SPI_H
+#ifndef __SPI_S3C64XX_H
+#define __SPI_S3C64XX_H
#include <linux/dmaengine.h>
@@ -68,4 +67,4 @@ extern int s3c64xx_spi2_cfg_gpio(void);
extern struct s3c64xx_spi_info s3c64xx_spi0_pdata;
extern struct s3c64xx_spi_info s3c64xx_spi1_pdata;
extern struct s3c64xx_spi_info s3c64xx_spi2_pdata;
-#endif /* __S3C64XX_PLAT_SPI_H */
+#endif /*__SPI_S3C64XX_H */
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 8c6583a53a06..d915d0345fa1 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -264,9 +264,9 @@ typedef struct pm_message {
* registers, so that it is fully operational.
*
* @runtime_idle: Device appears to be inactive and it might be put into a
- * low-power state if all of the necessary conditions are satisfied. Check
- * these conditions and handle the device as appropriate, possibly queueing
- * a suspend request for it. The return value is ignored by the PM core.
+ * low-power state if all of the necessary conditions are satisfied.
+ * Check these conditions, and return 0 if it's appropriate to let the PM
+ * core queue a suspend request for the device.
*
* Refer to Documentation/power/runtime_pm.txt for more information about the
* role of the above callbacks in device runtime power management.
@@ -352,7 +352,7 @@ const struct dev_pm_ops name = { \
/*
* Use this for defining a set of PM operations to be used in all situations
- * (sustem suspend, hibernation or runtime PM).
+ * (system suspend, hibernation or runtime PM).
* NOTE: In general, system suspend callbacks, .suspend() and .resume(), should
* be different from the corresponding runtime PM callbacks, .runtime_suspend(),
* and .runtime_resume(), because .runtime_suspend() always works on an already
@@ -379,7 +379,7 @@ const struct dev_pm_ops name = { \
*
* ON No transition.
*
- * FREEZE System is going to hibernate, call ->prepare() and ->freeze()
+ * FREEZE System is going to hibernate, call ->prepare() and ->freeze()
* for all devices.
*
* SUSPEND System is going to suspend, call ->prepare() and ->suspend()
@@ -423,7 +423,7 @@ const struct dev_pm_ops name = { \
#define PM_EVENT_INVALID (-1)
#define PM_EVENT_ON 0x0000
-#define PM_EVENT_FREEZE 0x0001
+#define PM_EVENT_FREEZE 0x0001
#define PM_EVENT_SUSPEND 0x0002
#define PM_EVENT_HIBERNATE 0x0004
#define PM_EVENT_QUIESCE 0x0008
@@ -542,6 +542,8 @@ struct dev_pm_info {
unsigned int async_suspend:1;
bool is_prepared:1; /* Owned by the PM core */
bool is_suspended:1; /* Ditto */
+ bool is_noirq_suspended:1;
+ bool is_late_suspended:1;
bool ignore_children:1;
bool early_init:1; /* Owned by the PM core */
spinlock_t lock;
@@ -582,6 +584,7 @@ struct dev_pm_info {
unsigned long accounting_timestamp;
#endif
struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */
+ void (*set_latency_tolerance)(struct device *, s32);
struct dev_pm_qos *qos;
};
@@ -612,11 +615,11 @@ struct dev_pm_domain {
* message is implicit:
*
* ON Driver starts working again, responding to hardware events
- * and software requests. The hardware may have gone through
- * a power-off reset, or it may have maintained state from the
- * previous suspend() which the driver will rely on while
- * resuming. On most platforms, there are no restrictions on
- * availability of resources like clocks during resume().
+ * and software requests. The hardware may have gone through
+ * a power-off reset, or it may have maintained state from the
+ * previous suspend() which the driver will rely on while
+ * resuming. On most platforms, there are no restrictions on
+ * availability of resources like clocks during resume().
*
* Other transitions are triggered by messages sent using suspend(). All
* these transitions quiesce the driver, so that I/O queues are inactive.
@@ -626,21 +629,21 @@ struct dev_pm_domain {
* differ according to the message:
*
* SUSPEND Quiesce, enter a low power device state appropriate for
- * the upcoming system state (such as PCI_D3hot), and enable
- * wakeup events as appropriate.
+ * the upcoming system state (such as PCI_D3hot), and enable
+ * wakeup events as appropriate.
*
* HIBERNATE Enter a low power device state appropriate for the hibernation
- * state (eg. ACPI S4) and enable wakeup events as appropriate.
+ * state (eg. ACPI S4) and enable wakeup events as appropriate.
*
* FREEZE Quiesce operations so that a consistent image can be saved;
- * but do NOT otherwise enter a low power device state, and do
- * NOT emit system wakeup events.
+ * but do NOT otherwise enter a low power device state, and do
+ * NOT emit system wakeup events.
*
* PRETHAW Quiesce as if for FREEZE; additionally, prepare for restoring
- * the system from a snapshot taken after an earlier FREEZE.
- * Some drivers will need to reset their hardware state instead
- * of preserving it, to ensure that it's never mistaken for the
- * state which that earlier snapshot had set up.
+ * the system from a snapshot taken after an earlier FREEZE.
+ * Some drivers will need to reset their hardware state instead
+ * of preserving it, to ensure that it's never mistaken for the
+ * state which that earlier snapshot had set up.
*
* A minimally power-aware driver treats all messages as SUSPEND, fully
* reinitializes its device during resume() -- whether or not it was reset
@@ -717,14 +720,26 @@ static inline void dpm_for_each_dev(void *data, void (*fn)(struct device *, void
{
}
-#define pm_generic_prepare NULL
-#define pm_generic_suspend NULL
-#define pm_generic_resume NULL
-#define pm_generic_freeze NULL
-#define pm_generic_thaw NULL
-#define pm_generic_restore NULL
-#define pm_generic_poweroff NULL
-#define pm_generic_complete NULL
+#define pm_generic_prepare NULL
+#define pm_generic_suspend_late NULL
+#define pm_generic_suspend_noirq NULL
+#define pm_generic_suspend NULL
+#define pm_generic_resume_early NULL
+#define pm_generic_resume_noirq NULL
+#define pm_generic_resume NULL
+#define pm_generic_freeze_noirq NULL
+#define pm_generic_freeze_late NULL
+#define pm_generic_freeze NULL
+#define pm_generic_thaw_noirq NULL
+#define pm_generic_thaw_early NULL
+#define pm_generic_thaw NULL
+#define pm_generic_restore_noirq NULL
+#define pm_generic_restore_early NULL
+#define pm_generic_restore NULL
+#define pm_generic_poweroff_noirq NULL
+#define pm_generic_poweroff_late NULL
+#define pm_generic_poweroff NULL
+#define pm_generic_complete NULL
#endif /* !CONFIG_PM_SLEEP */
/* How to reorder dpm_list after device_move() */
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 5a95013905c8..9ab4bf7c4646 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -32,7 +32,10 @@ enum pm_qos_flags_status {
#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0
-#define PM_QOS_DEV_LAT_DEFAULT_VALUE 0
+#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE 0
+#define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0
+#define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1)
+#define PM_QOS_LATENCY_ANY ((s32)(~(__u32)0 >> 1))
#define PM_QOS_FLAG_NO_POWER_OFF (1 << 0)
#define PM_QOS_FLAG_REMOTE_WAKEUP (1 << 1)
@@ -49,7 +52,8 @@ struct pm_qos_flags_request {
};
enum dev_pm_qos_req_type {
- DEV_PM_QOS_LATENCY = 1,
+ DEV_PM_QOS_RESUME_LATENCY = 1,
+ DEV_PM_QOS_LATENCY_TOLERANCE,
DEV_PM_QOS_FLAGS,
};
@@ -77,6 +81,7 @@ struct pm_qos_constraints {
struct plist_head list;
s32 target_value; /* Do not change to 64 bit */
s32 default_value;
+ s32 no_constraint_value;
enum pm_qos_type type;
struct blocking_notifier_head *notifiers;
};
@@ -87,9 +92,11 @@ struct pm_qos_flags {
};
struct dev_pm_qos {
- struct pm_qos_constraints latency;
+ struct pm_qos_constraints resume_latency;
+ struct pm_qos_constraints latency_tolerance;
struct pm_qos_flags flags;
- struct dev_pm_qos_request *latency_req;
+ struct dev_pm_qos_request *resume_latency_req;
+ struct dev_pm_qos_request *latency_tolerance_req;
struct dev_pm_qos_request *flags_req;
};
@@ -142,7 +149,8 @@ int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier);
void dev_pm_qos_constraints_init(struct device *dev);
void dev_pm_qos_constraints_destroy(struct device *dev);
int dev_pm_qos_add_ancestor_request(struct device *dev,
- struct dev_pm_qos_request *req, s32 value);
+ struct dev_pm_qos_request *req,
+ enum dev_pm_qos_req_type type, s32 value);
#else
static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
s32 mask)
@@ -185,7 +193,9 @@ static inline void dev_pm_qos_constraints_destroy(struct device *dev)
dev->power.power_state = PMSG_INVALID;
}
static inline int dev_pm_qos_add_ancestor_request(struct device *dev,
- struct dev_pm_qos_request *req, s32 value)
+ struct dev_pm_qos_request *req,
+ enum dev_pm_qos_req_type type,
+ s32 value)
{ return 0; }
#endif
@@ -195,10 +205,12 @@ void dev_pm_qos_hide_latency_limit(struct device *dev);
int dev_pm_qos_expose_flags(struct device *dev, s32 value);
void dev_pm_qos_hide_flags(struct device *dev);
int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set);
+s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev);
+int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val);
-static inline s32 dev_pm_qos_requested_latency(struct device *dev)
+static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
{
- return dev->power.qos->latency_req->data.pnode.prio;
+ return dev->power.qos->resume_latency_req->data.pnode.prio;
}
static inline s32 dev_pm_qos_requested_flags(struct device *dev)
@@ -214,8 +226,12 @@ static inline int dev_pm_qos_expose_flags(struct device *dev, s32 value)
static inline void dev_pm_qos_hide_flags(struct device *dev) {}
static inline int dev_pm_qos_update_flags(struct device *dev, s32 m, bool set)
{ return 0; }
+static inline s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev)
+ { return PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT; }
+static inline int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val)
+ { return 0; }
-static inline s32 dev_pm_qos_requested_latency(struct device *dev) { return 0; }
+static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; }
static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
#endif
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 16c9a62fa1c0..2a5897a4afbc 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -26,9 +26,13 @@
#ifdef CONFIG_PM
extern int pm_generic_runtime_suspend(struct device *dev);
extern int pm_generic_runtime_resume(struct device *dev);
+extern int pm_runtime_force_suspend(struct device *dev);
+extern int pm_runtime_force_resume(struct device *dev);
#else
static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
+static inline int pm_runtime_force_suspend(struct device *dev) { return 0; }
+static inline int pm_runtime_force_resume(struct device *dev) { return 0; }
#endif
#ifdef CONFIG_PM_RUNTIME
diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index dbaf99084112..8183b46fbaa2 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -247,9 +247,10 @@ static inline void list_splice_init_rcu(struct list_head *list,
* primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
*/
#define list_entry_rcu(ptr, type, member) \
- ({typeof (*ptr) __rcu *__ptr = (typeof (*ptr) __rcu __force *)ptr; \
- container_of((typeof(ptr))rcu_dereference_raw(__ptr), type, member); \
- })
+({ \
+ typeof(*ptr) __rcu *__ptr = (typeof(*ptr) __rcu __force *)ptr; \
+ container_of((typeof(ptr))rcu_dereference_raw(__ptr), type, member); \
+})
/**
* Where are list_empty_rcu() and list_first_entry_rcu()?
@@ -285,11 +286,11 @@ static inline void list_splice_init_rcu(struct list_head *list,
* primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
*/
#define list_first_or_null_rcu(ptr, type, member) \
- ({struct list_head *__ptr = (ptr); \
- struct list_head *__next = ACCESS_ONCE(__ptr->next); \
- likely(__ptr != __next) ? \
- list_entry_rcu(__next, type, member) : NULL; \
- })
+({ \
+ struct list_head *__ptr = (ptr); \
+ struct list_head *__next = ACCESS_ONCE(__ptr->next); \
+ likely(__ptr != __next) ? list_entry_rcu(__next, type, member) : NULL; \
+})
/**
* list_for_each_entry_rcu - iterate over rcu list of given type
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 72bf3a01a4ee..00a7fd61b3c6 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -12,8 +12,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright IBM Corporation, 2001
*
@@ -44,7 +44,9 @@
#include <linux/debugobjects.h>
#include <linux/bug.h>
#include <linux/compiler.h>
+#include <asm/barrier.h>
+extern int rcu_expedited; /* for sysctl */
#ifdef CONFIG_RCU_TORTURE_TEST
extern int rcutorture_runnable; /* for sysctl */
#endif /* #ifdef CONFIG_RCU_TORTURE_TEST */
@@ -314,7 +316,7 @@ static inline bool rcu_lockdep_current_cpu_online(void)
static inline void rcu_lock_acquire(struct lockdep_map *map)
{
- lock_acquire(map, 0, 0, 2, 1, NULL, _THIS_IP_);
+ lock_acquire(map, 0, 0, 2, 0, NULL, _THIS_IP_);
}
static inline void rcu_lock_release(struct lockdep_map *map)
@@ -479,11 +481,9 @@ static inline void rcu_preempt_sleep_check(void)
do { \
rcu_preempt_sleep_check(); \
rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map), \
- "Illegal context switch in RCU-bh" \
- " read-side critical section"); \
+ "Illegal context switch in RCU-bh read-side critical section"); \
rcu_lockdep_assert(!lock_is_held(&rcu_sched_lock_map), \
- "Illegal context switch in RCU-sched"\
- " read-side critical section"); \
+ "Illegal context switch in RCU-sched read-side critical section"); \
} while (0)
#else /* #ifdef CONFIG_PROVE_RCU */
@@ -510,43 +510,40 @@ static inline void rcu_preempt_sleep_check(void)
#endif /* #else #ifdef __CHECKER__ */
#define __rcu_access_pointer(p, space) \
- ({ \
- typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \
- rcu_dereference_sparse(p, space); \
- ((typeof(*p) __force __kernel *)(_________p1)); \
- })
+({ \
+ typeof(*p) *_________p1 = (typeof(*p) *__force)ACCESS_ONCE(p); \
+ rcu_dereference_sparse(p, space); \
+ ((typeof(*p) __force __kernel *)(_________p1)); \
+})
#define __rcu_dereference_check(p, c, space) \
- ({ \
- typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \
- rcu_lockdep_assert(c, "suspicious rcu_dereference_check()" \
- " usage"); \
- rcu_dereference_sparse(p, space); \
- smp_read_barrier_depends(); \
- ((typeof(*p) __force __kernel *)(_________p1)); \
- })
+({ \
+ typeof(*p) *_________p1 = (typeof(*p) *__force)ACCESS_ONCE(p); \
+ rcu_lockdep_assert(c, "suspicious rcu_dereference_check() usage"); \
+ rcu_dereference_sparse(p, space); \
+ smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
+ ((typeof(*p) __force __kernel *)(_________p1)); \
+})
#define __rcu_dereference_protected(p, c, space) \
- ({ \
- rcu_lockdep_assert(c, "suspicious rcu_dereference_protected()" \
- " usage"); \
- rcu_dereference_sparse(p, space); \
- ((typeof(*p) __force __kernel *)(p)); \
- })
+({ \
+ rcu_lockdep_assert(c, "suspicious rcu_dereference_protected() usage"); \
+ rcu_dereference_sparse(p, space); \
+ ((typeof(*p) __force __kernel *)(p)); \
+})
#define __rcu_access_index(p, space) \
- ({ \
- typeof(p) _________p1 = ACCESS_ONCE(p); \
- rcu_dereference_sparse(p, space); \
- (_________p1); \
- })
+({ \
+ typeof(p) _________p1 = ACCESS_ONCE(p); \
+ rcu_dereference_sparse(p, space); \
+ (_________p1); \
+})
#define __rcu_dereference_index_check(p, c) \
- ({ \
- typeof(p) _________p1 = ACCESS_ONCE(p); \
- rcu_lockdep_assert(c, \
- "suspicious rcu_dereference_index_check()" \
- " usage"); \
- smp_read_barrier_depends(); \
- (_________p1); \
- })
+({ \
+ typeof(p) _________p1 = ACCESS_ONCE(p); \
+ rcu_lockdep_assert(c, \
+ "suspicious rcu_dereference_index_check() usage"); \
+ smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
+ (_________p1); \
+})
/**
* RCU_INITIALIZER() - statically initialize an RCU-protected global variable
@@ -585,12 +582,7 @@ static inline void rcu_preempt_sleep_check(void)
* please be careful when making changes to rcu_assign_pointer() and the
* other macros that it invokes.
*/
-#define rcu_assign_pointer(p, v) \
- do { \
- smp_wmb(); \
- ACCESS_ONCE(p) = RCU_INITIALIZER(v); \
- } while (0)
-
+#define rcu_assign_pointer(p, v) smp_store_release(&p, RCU_INITIALIZER(v))
/**
* rcu_access_pointer() - fetch RCU pointer with no dereferencing
@@ -1015,11 +1007,21 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
#define kfree_rcu(ptr, rcu_head) \
__kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head))
-#ifdef CONFIG_RCU_NOCB_CPU
+#if defined(CONFIG_TINY_RCU) || defined(CONFIG_RCU_NOCB_CPU_ALL)
+static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
+{
+ *delta_jiffies = ULONG_MAX;
+ return 0;
+}
+#endif /* #if defined(CONFIG_TINY_RCU) || defined(CONFIG_RCU_NOCB_CPU_ALL) */
+
+#if defined(CONFIG_RCU_NOCB_CPU_ALL)
+static inline bool rcu_is_nocb_cpu(int cpu) { return true; }
+#elif defined(CONFIG_RCU_NOCB_CPU)
bool rcu_is_nocb_cpu(int cpu);
#else
static inline bool rcu_is_nocb_cpu(int cpu) { return false; }
-#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
+#endif
/* Only for use by adaptive-ticks code. */
diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h
index 6f01771b571c..425c659d54e5 100644
--- a/include/linux/rcutiny.h
+++ b/include/linux/rcutiny.h
@@ -12,8 +12,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright IBM Corporation, 2008
*
@@ -27,6 +27,16 @@
#include <linux/cache.h>
+static inline unsigned long get_state_synchronize_rcu(void)
+{
+ return 0;
+}
+
+static inline void cond_synchronize_rcu(unsigned long oldstate)
+{
+ might_sleep();
+}
+
static inline void rcu_barrier_bh(void)
{
wait_rcu_gp(call_rcu_bh);
@@ -68,12 +78,6 @@ static inline void kfree_call_rcu(struct rcu_head *head,
call_rcu(head, func);
}
-static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
-{
- *delta_jiffies = ULONG_MAX;
- return 0;
-}
-
static inline void rcu_note_context_switch(int cpu)
{
rcu_sched_qs(cpu);
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index 72137ee8c603..a59ca05fd4e3 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -12,8 +12,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright IBM Corporation, 2008
*
@@ -31,7 +31,9 @@
#define __LINUX_RCUTREE_H
void rcu_note_context_switch(int cpu);
+#ifndef CONFIG_RCU_NOCB_CPU_ALL
int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies);
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
void rcu_cpu_stall_reset(void);
/*
@@ -74,6 +76,8 @@ static inline void synchronize_rcu_bh_expedited(void)
void rcu_barrier(void);
void rcu_barrier_bh(void);
void rcu_barrier_sched(void);
+unsigned long get_state_synchronize_rcu(void);
+void cond_synchronize_rcu(unsigned long oldstate);
extern unsigned long rcutorture_testseq;
extern unsigned long rcutorture_vernum;
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 4149f1a9b003..85691b9b4fa7 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -164,6 +164,9 @@ typedef void (*regmap_unlock)(void *);
* @use_single_rw: If set, converts the bulk read and write operations into
* a series of single read and write operations. This is useful
* for device that does not support bulk read and write.
+ * @can_multi_write: If set, the device supports the multi write mode of bulk
+ * write operations, if clear multi write requests will be
+ * split into individual write operations
*
* @cache_type: The actual cache type.
* @reg_defaults_raw: Power on reset values for registers (for use with
@@ -215,6 +218,7 @@ struct regmap_config {
u8 write_flag_mask;
bool use_single_rw;
+ bool can_multi_write;
enum regmap_endian reg_format_endian;
enum regmap_endian val_format_endian;
@@ -317,12 +321,16 @@ struct regmap *regmap_init(struct device *dev,
const struct regmap_bus *bus,
void *bus_context,
const struct regmap_config *config);
+int regmap_attach_dev(struct device *dev, struct regmap *map,
+ const struct regmap_config *config);
struct regmap *regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config);
struct regmap *regmap_init_spi(struct spi_device *dev,
const struct regmap_config *config);
-struct regmap *regmap_init_spmi(struct spmi_device *dev,
- const struct regmap_config *config);
+struct regmap *regmap_init_spmi_base(struct spmi_device *dev,
+ const struct regmap_config *config);
+struct regmap *regmap_init_spmi_ext(struct spmi_device *dev,
+ const struct regmap_config *config);
struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
void __iomem *regs,
const struct regmap_config *config);
@@ -335,8 +343,10 @@ struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config);
struct regmap *devm_regmap_init_spi(struct spi_device *dev,
const struct regmap_config *config);
-struct regmap *devm_regmap_init_spmi(struct spmi_device *dev,
- const struct regmap_config *config);
+struct regmap *devm_regmap_init_spmi_base(struct spmi_device *dev,
+ const struct regmap_config *config);
+struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev,
+ const struct regmap_config *config);
struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
void __iomem *regs,
const struct regmap_config *config);
@@ -386,8 +396,11 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_len);
int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
size_t val_count);
-int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs,
+int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
int num_regs);
+int regmap_multi_reg_write_bypassed(struct regmap *map,
+ const struct reg_default *regs,
+ int num_regs);
int regmap_raw_write_async(struct regmap *map, unsigned int reg,
const void *val, size_t val_len);
int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);
@@ -423,6 +436,8 @@ bool regmap_check_range_table(struct regmap *map, unsigned int reg,
int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
int num_regs);
+int regmap_parse_val(struct regmap *map, const void *buf,
+ unsigned int *val);
static inline bool regmap_reg_in_range(unsigned int reg,
const struct regmap_range *range)
@@ -695,6 +710,13 @@ static inline int regmap_register_patch(struct regmap *map,
return -EINVAL;
}
+static inline int regmap_parse_val(struct regmap *map, const void *buf,
+ unsigned int *val)
+{
+ WARN_ONCE(1, "regmap API is disabled");
+ return -EINVAL;
+}
+
static inline struct regmap *dev_get_regmap(struct device *dev,
const char *name)
{
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 9370e65348a4..bbe03a1924c0 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -228,10 +228,14 @@ enum regulator_type {
* output when using regulator_set_voltage_sel_regmap
* @enable_reg: Register for control when using regmap enable/disable ops
* @enable_mask: Mask for control when using regmap enable/disable ops
+ * @enable_val: Enabling value for control when using regmap enable/disable ops
+ * @disable_val: Disabling value for control when using regmap enable/disable ops
* @enable_is_inverted: A flag to indicate set enable_mask bits to disable
* when using regulator_enable_regmap and friends APIs.
* @bypass_reg: Register for control when using regmap set_bypass
* @bypass_mask: Mask for control when using regmap set_bypass
+ * @bypass_val_on: Enabling value for control when using regmap set_bypass
+ * @bypass_val_off: Disabling value for control when using regmap set_bypass
*
* @enable_time: Time taken for initial enable of regulator (in uS).
*/
@@ -263,9 +267,13 @@ struct regulator_desc {
unsigned int apply_bit;
unsigned int enable_reg;
unsigned int enable_mask;
+ unsigned int enable_val;
+ unsigned int disable_val;
bool enable_is_inverted;
unsigned int bypass_reg;
unsigned int bypass_mask;
+ unsigned int bypass_val_on;
+ unsigned int bypass_val_off;
unsigned int enable_time;
};
diff --git a/include/linux/regulator/pfuze100.h b/include/linux/regulator/pfuze100.h
index 65d550bf3954..364f7a7c43db 100644
--- a/include/linux/regulator/pfuze100.h
+++ b/include/linux/regulator/pfuze100.h
@@ -35,6 +35,20 @@
#define PFUZE100_VGEN6 14
#define PFUZE100_MAX_REGULATOR 15
+#define PFUZE200_SW1AB 0
+#define PFUZE200_SW2 1
+#define PFUZE200_SW3A 2
+#define PFUZE200_SW3B 3
+#define PFUZE200_SWBST 4
+#define PFUZE200_VSNVS 5
+#define PFUZE200_VREFDDR 6
+#define PFUZE200_VGEN1 7
+#define PFUZE200_VGEN2 8
+#define PFUZE200_VGEN3 9
+#define PFUZE200_VGEN4 10
+#define PFUZE200_VGEN5 11
+#define PFUZE200_VGEN6 12
+
struct regulator_init_data;
struct pfuze_regulator_platform_data {
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index 1da693d51255..b66c2110cb1f 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -250,8 +250,7 @@ struct rmap_walk_control {
int (*rmap_one)(struct page *page, struct vm_area_struct *vma,
unsigned long addr, void *arg);
int (*done)(struct page *page);
- int (*file_nonlinear)(struct page *, struct address_space *,
- struct vm_area_struct *vma);
+ int (*file_nonlinear)(struct page *, struct address_space *, void *arg);
struct anon_vma *(*anon_lock)(struct page *page);
bool (*invalid_vma)(struct vm_area_struct *vma, void *arg);
};
diff --git a/include/linux/sched.h b/include/linux/sched.h
index a781dec1cd0b..7cb07fd26680 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -3,6 +3,8 @@
#include <uapi/linux/sched.h>
+#include <linux/sched/prio.h>
+
struct sched_param {
int sched_priority;
@@ -27,7 +29,7 @@ struct sched_param {
#include <asm/page.h>
#include <asm/ptrace.h>
-#include <asm/cputime.h>
+#include <linux/cputime.h>
#include <linux/smp.h>
#include <linux/sem.h>
@@ -292,10 +294,14 @@ extern int runqueue_is_locked(int cpu);
#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
extern void nohz_balance_enter_idle(int cpu);
extern void set_cpu_sd_state_idle(void);
-extern int get_nohz_timer_target(void);
+extern int get_nohz_timer_target(int pinned);
#else
static inline void nohz_balance_enter_idle(int cpu) { }
static inline void set_cpu_sd_state_idle(void) { }
+static inline int get_nohz_timer_target(int pinned)
+{
+ return smp_processor_id();
+}
#endif
/*
@@ -1077,6 +1083,7 @@ struct sched_entity {
#endif
#ifdef CONFIG_FAIR_GROUP_SCHED
+ int depth;
struct sched_entity *parent;
/* rq on which this entity is (to be) queued: */
struct cfs_rq *cfs_rq;
@@ -1460,6 +1467,9 @@ struct task_struct {
struct mutex perf_event_mutex;
struct list_head perf_event_list;
#endif
+#ifdef CONFIG_DEBUG_PREEMPT
+ unsigned long preempt_disable_ip;
+#endif
#ifdef CONFIG_NUMA
struct mempolicy *mempolicy; /* Protected by alloc_lock */
short il_next;
@@ -1470,9 +1480,10 @@ struct task_struct {
unsigned int numa_scan_period;
unsigned int numa_scan_period_max;
int numa_preferred_nid;
- int numa_migrate_deferred;
unsigned long numa_migrate_retry;
u64 node_stamp; /* migration stamp */
+ u64 last_task_numa_placement;
+ u64 last_sum_exec_runtime;
struct callback_head numa_work;
struct list_head numa_entry;
@@ -1483,15 +1494,22 @@ struct task_struct {
* Scheduling placement decisions are made based on the these counts.
* The values remain static for the duration of a PTE scan
*/
- unsigned long *numa_faults;
+ unsigned long *numa_faults_memory;
unsigned long total_numa_faults;
/*
* numa_faults_buffer records faults per node during the current
- * scan window. When the scan completes, the counts in numa_faults
- * decay and these values are copied.
+ * scan window. When the scan completes, the counts in
+ * numa_faults_memory decay and these values are copied.
*/
- unsigned long *numa_faults_buffer;
+ unsigned long *numa_faults_buffer_memory;
+
+ /*
+ * Track the nodes the process was running on when a NUMA hinting
+ * fault was incurred.
+ */
+ unsigned long *numa_faults_cpu;
+ unsigned long *numa_faults_buffer_cpu;
/*
* numa_faults_locality tracks if faults recorded during the last
@@ -1596,8 +1614,8 @@ extern void task_numa_fault(int last_node, int node, int pages, int flags);
extern pid_t task_numa_group_id(struct task_struct *p);
extern void set_numabalancing_state(bool enabled);
extern void task_numa_free(struct task_struct *p);
-
-extern unsigned int sysctl_numa_balancing_migrate_deferred;
+extern bool should_numa_migrate_memory(struct task_struct *p, struct page *page,
+ int src_nid, int dst_cpu);
#else
static inline void task_numa_fault(int last_node, int node, int pages,
int flags)
@@ -1613,6 +1631,11 @@ static inline void set_numabalancing_state(bool enabled)
static inline void task_numa_free(struct task_struct *p)
{
}
+static inline bool should_numa_migrate_memory(struct task_struct *p,
+ struct page *page, int src_nid, int dst_cpu)
+{
+ return true;
+}
#endif
static inline struct pid *task_pid(struct task_struct *task)
@@ -2080,7 +2103,16 @@ static inline void sched_autogroup_exit(struct signal_struct *sig) { }
extern bool yield_to(struct task_struct *p, bool preempt);
extern void set_user_nice(struct task_struct *p, long nice);
extern int task_prio(const struct task_struct *p);
-extern int task_nice(const struct task_struct *p);
+/**
+ * task_nice - return the nice value of a given task.
+ * @p: the task in question.
+ *
+ * Return: The nice value [ -20 ... 0 ... 19 ].
+ */
+static inline int task_nice(const struct task_struct *p)
+{
+ return PRIO_TO_NICE((p)->static_prio);
+}
extern int can_nice(const struct task_struct *p, const int nice);
extern int task_curr(const struct task_struct *p);
extern int idle_cpu(int cpu);
diff --git a/include/linux/sched/prio.h b/include/linux/sched/prio.h
new file mode 100644
index 000000000000..ac322583c820
--- /dev/null
+++ b/include/linux/sched/prio.h
@@ -0,0 +1,44 @@
+#ifndef _SCHED_PRIO_H
+#define _SCHED_PRIO_H
+
+#define MAX_NICE 19
+#define MIN_NICE -20
+#define NICE_WIDTH (MAX_NICE - MIN_NICE + 1)
+
+/*
+ * Priority of a process goes from 0..MAX_PRIO-1, valid RT
+ * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
+ * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
+ * values are inverted: lower p->prio value means higher priority.
+ *
+ * The MAX_USER_RT_PRIO value allows the actual maximum
+ * RT priority to be separate from the value exported to
+ * user-space. This allows kernel threads to set their
+ * priority to a value higher than any user task. Note:
+ * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
+ */
+
+#define MAX_USER_RT_PRIO 100
+#define MAX_RT_PRIO MAX_USER_RT_PRIO
+
+#define MAX_PRIO (MAX_RT_PRIO + NICE_WIDTH)
+#define DEFAULT_PRIO (MAX_RT_PRIO + NICE_WIDTH / 2)
+
+/*
+ * Convert user-nice values [ -20 ... 0 ... 19 ]
+ * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
+ * and back.
+ */
+#define NICE_TO_PRIO(nice) ((nice) + DEFAULT_PRIO)
+#define PRIO_TO_NICE(prio) ((prio) - DEFAULT_PRIO)
+
+/*
+ * 'User priority' is the nice value converted to something we
+ * can work with better when scaling various scheduler parameters,
+ * it's a [ 0 ... 39 ] range.
+ */
+#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
+#define TASK_USER_PRIO(p) USER_PRIO((p)->static_prio)
+#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
+
+#endif /* _SCHED_PRIO_H */
diff --git a/include/linux/sched/rt.h b/include/linux/sched/rt.h
index 34e4ebea8fce..6341f5be6e24 100644
--- a/include/linux/sched/rt.h
+++ b/include/linux/sched/rt.h
@@ -1,24 +1,7 @@
#ifndef _SCHED_RT_H
#define _SCHED_RT_H
-/*
- * Priority of a process goes from 0..MAX_PRIO-1, valid RT
- * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
- * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
- * values are inverted: lower p->prio value means higher priority.
- *
- * The MAX_USER_RT_PRIO value allows the actual maximum
- * RT priority to be separate from the value exported to
- * user-space. This allows kernel threads to set their
- * priority to a value higher than any user task. Note:
- * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
- */
-
-#define MAX_USER_RT_PRIO 100
-#define MAX_RT_PRIO MAX_USER_RT_PRIO
-
-#define MAX_PRIO (MAX_RT_PRIO + 40)
-#define DEFAULT_PRIO (MAX_RT_PRIO + 20)
+#include <linux/sched/prio.h>
static inline int rt_prio(int prio)
{
@@ -35,6 +18,7 @@ static inline int rt_task(struct task_struct *p)
#ifdef CONFIG_RT_MUTEXES
extern int rt_mutex_getprio(struct task_struct *p);
extern void rt_mutex_setprio(struct task_struct *p, int prio);
+extern int rt_mutex_check_prio(struct task_struct *task, int newprio);
extern struct task_struct *rt_mutex_get_top_task(struct task_struct *task);
extern void rt_mutex_adjust_pi(struct task_struct *p);
static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
@@ -46,6 +30,12 @@ static inline int rt_mutex_getprio(struct task_struct *p)
{
return p->normal_prio;
}
+
+static inline int rt_mutex_check_prio(struct task_struct *task, int newprio)
+{
+ return 0;
+}
+
static inline struct task_struct *rt_mutex_get_top_task(struct task_struct *task)
{
return NULL;
diff --git a/include/linux/security.h b/include/linux/security.h
index 5623a7f965b7..2fc42d191f79 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1040,6 +1040,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Allocate a security structure to the xp->security field; the security
* field is initialized to NULL when the xfrm_policy is allocated.
* Return 0 if operation was successful (memory to allocate, legal context)
+ * @gfp is to specify the context for the allocation
* @xfrm_policy_clone_security:
* @old_ctx contains an existing xfrm_sec_ctx.
* @new_ctxp contains a new xfrm_sec_ctx being cloned from old.
@@ -1683,7 +1684,7 @@ struct security_operations {
#ifdef CONFIG_SECURITY_NETWORK_XFRM
int (*xfrm_policy_alloc_security) (struct xfrm_sec_ctx **ctxp,
- struct xfrm_user_sec_ctx *sec_ctx);
+ struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp);
int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx);
void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx);
int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx);
@@ -2859,7 +2860,8 @@ static inline void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
#ifdef CONFIG_SECURITY_NETWORK_XFRM
-int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx);
+int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
+ struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp);
int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctxp);
void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx);
int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx);
@@ -2877,7 +2879,9 @@ void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl);
#else /* CONFIG_SECURITY_NETWORK_XFRM */
-static inline int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx)
+static inline int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
+ struct xfrm_user_sec_ctx *sec_ctx,
+ gfp_t gfp)
{
return 0;
}
diff --git a/include/linux/serial_bcm63xx.h b/include/linux/serial_bcm63xx.h
index 570e964dc899..a80aa1a5bee2 100644
--- a/include/linux/serial_bcm63xx.h
+++ b/include/linux/serial_bcm63xx.h
@@ -116,4 +116,6 @@
UART_FIFO_PARERR_MASK | \
UART_FIFO_BRKDET_MASK)
+#define UART_REG_SIZE 24
+
#endif /* _LINUX_SERIAL_BCM63XX_H */
diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h
index 22b3640c9424..6c5e3bb282b0 100644
--- a/include/linux/serial_sci.h
+++ b/include/linux/serial_sci.h
@@ -10,45 +10,59 @@
#define SCIx_NOT_SUPPORTED (-1)
-#define SCSCR_TIE (1 << 7)
-#define SCSCR_RIE (1 << 6)
-#define SCSCR_TE (1 << 5)
-#define SCSCR_RE (1 << 4)
-#define SCSCR_REIE (1 << 3) /* not supported by all parts */
-#define SCSCR_TOIE (1 << 2) /* not supported by all parts */
-#define SCSCR_CKE1 (1 << 1)
-#define SCSCR_CKE0 (1 << 0)
-
-/* SCxSR SCI */
-#define SCI_TDRE 0x80
-#define SCI_RDRF 0x40
-#define SCI_ORER 0x20
-#define SCI_FER 0x10
-#define SCI_PER 0x08
-#define SCI_TEND 0x04
+/* SCSMR (Serial Mode Register) */
+#define SCSMR_CHR (1 << 6) /* 7-bit Character Length */
+#define SCSMR_PE (1 << 5) /* Parity Enable */
+#define SCSMR_ODD (1 << 4) /* Odd Parity */
+#define SCSMR_STOP (1 << 3) /* Stop Bit Length */
+#define SCSMR_CKS 0x0003 /* Clock Select */
+
+/* Serial Control Register (@ = not supported by all parts) */
+#define SCSCR_TIE (1 << 7) /* Transmit Interrupt Enable */
+#define SCSCR_RIE (1 << 6) /* Receive Interrupt Enable */
+#define SCSCR_TE (1 << 5) /* Transmit Enable */
+#define SCSCR_RE (1 << 4) /* Receive Enable */
+#define SCSCR_REIE (1 << 3) /* Receive Error Interrupt Enable @ */
+#define SCSCR_TOIE (1 << 2) /* Timeout Interrupt Enable @ */
+#define SCSCR_CKE1 (1 << 1) /* Clock Enable 1 */
+#define SCSCR_CKE0 (1 << 0) /* Clock Enable 0 */
+/* SCIFA/SCIFB only */
+#define SCSCR_TDRQE (1 << 15) /* Tx Data Transfer Request Enable */
+#define SCSCR_RDRQE (1 << 14) /* Rx Data Transfer Request Enable */
+
+/* SCxSR (Serial Status Register) on SCI */
+#define SCI_TDRE 0x80 /* Transmit Data Register Empty */
+#define SCI_RDRF 0x40 /* Receive Data Register Full */
+#define SCI_ORER 0x20 /* Overrun Error */
+#define SCI_FER 0x10 /* Framing Error */
+#define SCI_PER 0x08 /* Parity Error */
+#define SCI_TEND 0x04 /* Transmit End */
#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
-/* SCxSR SCIF, HSCIF */
-#define SCIF_ER 0x0080
-#define SCIF_TEND 0x0040
-#define SCIF_TDFE 0x0020
-#define SCIF_BRK 0x0010
-#define SCIF_FER 0x0008
-#define SCIF_PER 0x0004
-#define SCIF_RDF 0x0002
-#define SCIF_DR 0x0001
+/* SCxSR (Serial Status Register) on SCIF, HSCIF */
+#define SCIF_ER 0x0080 /* Receive Error */
+#define SCIF_TEND 0x0040 /* Transmission End */
+#define SCIF_TDFE 0x0020 /* Transmit FIFO Data Empty */
+#define SCIF_BRK 0x0010 /* Break Detect */
+#define SCIF_FER 0x0008 /* Framing Error */
+#define SCIF_PER 0x0004 /* Parity Error */
+#define SCIF_RDF 0x0002 /* Receive FIFO Data Full */
+#define SCIF_DR 0x0001 /* Receive Data Ready */
#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
-/* SCSPTR, optional */
-#define SCSPTR_RTSIO (1 << 7)
-#define SCSPTR_CTSIO (1 << 5)
-#define SCSPTR_SPB2IO (1 << 1)
-#define SCSPTR_SPB2DT (1 << 0)
+/* SCFCR (FIFO Control Register) */
+#define SCFCR_LOOP (1 << 0) /* Loopback Test */
+
+/* SCSPTR (Serial Port Register), optional */
+#define SCSPTR_RTSIO (1 << 7) /* Serial Port RTS Pin Input/Output */
+#define SCSPTR_CTSIO (1 << 5) /* Serial Port CTS Pin Input/Output */
+#define SCSPTR_SPB2IO (1 << 1) /* Serial Port Break Input/Output */
+#define SCSPTR_SPB2DT (1 << 0) /* Serial Port Break Data */
/* HSSRR HSCIF */
-#define HSCIF_SRE 0x8000
+#define HSCIF_SRE 0x8000 /* Sampling Rate Register Enable */
enum {
SCIx_PROBE_REGTYPE,
@@ -73,10 +87,19 @@ enum {
* Not all registers will exist on all parts.
*/
enum {
- SCSMR, SCBRR, SCSCR, SCxSR,
- SCFCR, SCFDR, SCxTDR, SCxRDR,
- SCLSR, SCTFDR, SCRFDR, SCSPTR,
- HSSRR,
+ SCSMR, /* Serial Mode Register */
+ SCBRR, /* Bit Rate Register */
+ SCSCR, /* Serial Control Register */
+ SCxSR, /* Serial Status Register */
+ SCFCR, /* FIFO Control Register */
+ SCFDR, /* FIFO Data Count Register */
+ SCxTDR, /* Transmit (FIFO) Data Register */
+ SCxRDR, /* Receive (FIFO) Data Register */
+ SCLSR, /* Line Status Register */
+ SCTFDR, /* Transmit FIFO Data Count Register */
+ SCRFDR, /* Receive FIFO Data Count Register */
+ SCSPTR, /* Serial Port Register */
+ HSSRR, /* Sampling Rate Register */
SCIx_NR_REGS,
};
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index fc71710fba45..6b8466365fbd 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2451,8 +2451,8 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
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);
-void skb_zerocopy(struct sk_buff *to, const struct sk_buff *from,
- int len, int hlen);
+int skb_zerocopy(struct sk_buff *to, struct sk_buff *from,
+ int len, int hlen);
void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
void skb_scrub_packet(struct sk_buff *skb, bool xnet);
@@ -2725,7 +2725,7 @@ static inline void nf_reset(struct sk_buff *skb)
static inline void nf_reset_trace(struct sk_buff *skb)
{
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
skb->nf_trace = 0;
#endif
}
@@ -2742,6 +2742,9 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
dst->nf_bridge = src->nf_bridge;
nf_bridge_get(src->nf_bridge);
#endif
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
+ dst->nf_trace = src->nf_trace;
+#endif
}
static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src)
@@ -2916,5 +2919,22 @@ static inline bool skb_head_is_locked(const struct sk_buff *skb)
{
return !skb->head_frag || skb_cloned(skb);
}
+
+/**
+ * skb_gso_network_seglen - Return length of individual segments of a gso packet
+ *
+ * @skb: GSO skb
+ *
+ * skb_gso_network_seglen is used to determine the real size of the
+ * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP).
+ *
+ * The MAC/L2 header is not accounted for.
+ */
+static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb)
+{
+ unsigned int hdr_len = skb_transport_header(skb) -
+ skb_network_header(skb);
+ return hdr_len + skb_gso_transport_seglen(skb);
+}
#endif /* __KERNEL__ */
#endif /* _LINUX_SKBUFF_H */
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 9260abdd67df..b5b2df60299e 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -410,7 +410,7 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
*
* %GFP_NOWAIT - Allocation will not sleep.
*
- * %GFP_THISNODE - Allocate node-local memory only.
+ * %__GFP_THISNODE - Allocate node-local memory only.
*
* %GFP_DMA - Allocation suitable for DMA.
* Should only be used for kmalloc() caches. Otherwise, use a
diff --git a/include/linux/smp.h b/include/linux/smp.h
index 6ae004e437ea..633f5edd7470 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -17,10 +17,7 @@ extern void cpu_idle(void);
typedef void (*smp_call_func_t)(void *info);
struct call_single_data {
- union {
- struct list_head list;
- struct llist_node llist;
- };
+ struct llist_node llist;
smp_call_func_t func;
void *info;
u16 flags;
@@ -53,8 +50,7 @@ void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info),
smp_call_func_t func, void *info, bool wait,
gfp_t gfp_flags);
-void __smp_call_function_single(int cpuid, struct call_single_data *data,
- int wait);
+int smp_call_function_single_async(int cpu, struct call_single_data *csd);
#ifdef CONFIG_SMP
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 2c9cdef0598f..e713543336f1 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -24,6 +24,9 @@
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/completion.h>
+#include <linux/scatterlist.h>
+
+struct dma_chan;
/*
* INTERFACES between SPI master-side drivers and SPI infrastructure.
@@ -266,6 +269,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @auto_runtime_pm: the core should ensure a runtime PM reference is held
* while the hardware is prepared, using the parent
* device for the spidev
+ * @max_dma_len: Maximum length of a DMA transfer for the device.
* @prepare_transfer_hardware: a message will soon arrive from the queue
* so the subsystem requests the driver to prepare the transfer hardware
* by issuing this call
@@ -348,6 +352,8 @@ struct spi_master {
#define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */
#define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */
#define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */
+#define SPI_MASTER_MUST_RX BIT(3) /* requires rx */
+#define SPI_MASTER_MUST_TX BIT(4) /* requires tx */
/* lock and mutex for SPI bus locking */
spinlock_t bus_lock_spinlock;
@@ -390,6 +396,17 @@ struct spi_master {
void (*cleanup)(struct spi_device *spi);
/*
+ * Used to enable core support for DMA handling, if can_dma()
+ * exists and returns true then the transfer will be mapped
+ * prior to transfer_one() being called. The driver should
+ * not modify or store xfer and dma_tx and dma_rx must be set
+ * while the device is prepared.
+ */
+ bool (*can_dma)(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer);
+
+ /*
* These hooks are for drivers that want to use the generic
* master transfer queueing mechanism. If these are used, the
* transfer() function above must NOT be specified by the driver.
@@ -407,7 +424,9 @@ struct spi_master {
bool rt;
bool auto_runtime_pm;
bool cur_msg_prepared;
+ bool cur_msg_mapped;
struct completion xfer_completion;
+ size_t max_dma_len;
int (*prepare_transfer_hardware)(struct spi_master *master);
int (*transfer_one_message)(struct spi_master *master,
@@ -428,6 +447,14 @@ struct spi_master {
/* gpio chip select */
int *cs_gpios;
+
+ /* DMA channels for use with core dmaengine helpers */
+ struct dma_chan *dma_tx;
+ struct dma_chan *dma_rx;
+
+ /* dummy data for full duplex devices */
+ void *dummy_rx;
+ void *dummy_tx;
};
static inline void *spi_master_get_devdata(struct spi_master *master)
@@ -512,6 +539,8 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
* (optionally) changing the chipselect status, then starting
* the next transfer or completing this @spi_message.
* @transfer_list: transfers are sequenced through @spi_message.transfers
+ * @tx_sg: Scatterlist for transmit, currently not for client use
+ * @rx_sg: Scatterlist for receive, currently not for client use
*
* SPI transfers always write the same number of bytes as they read.
* Protocol drivers should always provide @rx_buf and/or @tx_buf.
@@ -579,6 +608,8 @@ struct spi_transfer {
dma_addr_t tx_dma;
dma_addr_t rx_dma;
+ struct sg_table tx_sg;
+ struct sg_table rx_sg;
unsigned cs_change:1;
unsigned tx_nbits:3;
diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h
index daebaba886aa..85578d4be034 100644
--- a/include/linux/spi/spi_bitbang.h
+++ b/include/linux/spi/spi_bitbang.h
@@ -42,6 +42,6 @@ extern int spi_bitbang_setup_transfer(struct spi_device *spi,
/* start or stop queue processing */
extern int spi_bitbang_start(struct spi_bitbang *spi);
-extern int spi_bitbang_stop(struct spi_bitbang *spi);
+extern void spi_bitbang_stop(struct spi_bitbang *spi);
#endif /* __SPI_BITBANG_H */
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
new file mode 100644
index 000000000000..91f5eab9e428
--- /dev/null
+++ b/include/linux/spmi.h
@@ -0,0 +1,191 @@
+/* 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.
+ */
+#ifndef _LINUX_SPMI_H
+#define _LINUX_SPMI_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+/* Maximum slave identifier */
+#define SPMI_MAX_SLAVE_ID 16
+
+/* SPMI Commands */
+#define SPMI_CMD_EXT_WRITE 0x00
+#define SPMI_CMD_RESET 0x10
+#define SPMI_CMD_SLEEP 0x11
+#define SPMI_CMD_SHUTDOWN 0x12
+#define SPMI_CMD_WAKEUP 0x13
+#define SPMI_CMD_AUTHENTICATE 0x14
+#define SPMI_CMD_MSTR_READ 0x15
+#define SPMI_CMD_MSTR_WRITE 0x16
+#define SPMI_CMD_TRANSFER_BUS_OWNERSHIP 0x1A
+#define SPMI_CMD_DDB_MASTER_READ 0x1B
+#define SPMI_CMD_DDB_SLAVE_READ 0x1C
+#define SPMI_CMD_EXT_READ 0x20
+#define SPMI_CMD_EXT_WRITEL 0x30
+#define SPMI_CMD_EXT_READL 0x38
+#define SPMI_CMD_WRITE 0x40
+#define SPMI_CMD_READ 0x60
+#define SPMI_CMD_ZERO_WRITE 0x80
+
+/**
+ * struct spmi_device - Basic representation of an SPMI device
+ * @dev: Driver model representation of the device.
+ * @ctrl: SPMI controller managing the bus hosting this device.
+ * @usid: This devices' Unique Slave IDentifier.
+ */
+struct spmi_device {
+ struct device dev;
+ struct spmi_controller *ctrl;
+ u8 usid;
+};
+
+static inline struct spmi_device *to_spmi_device(struct device *d)
+{
+ return container_of(d, struct spmi_device, dev);
+}
+
+static inline void *spmi_device_get_drvdata(const struct spmi_device *sdev)
+{
+ return dev_get_drvdata(&sdev->dev);
+}
+
+static inline void spmi_device_set_drvdata(struct spmi_device *sdev, void *data)
+{
+ dev_set_drvdata(&sdev->dev, data);
+}
+
+struct spmi_device *spmi_device_alloc(struct spmi_controller *ctrl);
+
+static inline void spmi_device_put(struct spmi_device *sdev)
+{
+ if (sdev)
+ put_device(&sdev->dev);
+}
+
+int spmi_device_add(struct spmi_device *sdev);
+
+void spmi_device_remove(struct spmi_device *sdev);
+
+/**
+ * struct spmi_controller - interface to the SPMI master controller
+ * @dev: Driver model representation of the device.
+ * @nr: board-specific number identifier for this controller/bus
+ * @cmd: sends a non-data command sequence on the SPMI bus.
+ * @read_cmd: sends a register read command sequence on the SPMI bus.
+ * @write_cmd: sends a register write command sequence on the SPMI bus.
+ */
+struct spmi_controller {
+ struct device dev;
+ unsigned int nr;
+ int (*cmd)(struct spmi_controller *ctrl, u8 opcode, u8 sid);
+ int (*read_cmd)(struct spmi_controller *ctrl, u8 opcode,
+ u8 sid, u16 addr, u8 *buf, size_t len);
+ int (*write_cmd)(struct spmi_controller *ctrl, u8 opcode,
+ u8 sid, u16 addr, const u8 *buf, size_t len);
+};
+
+static inline struct spmi_controller *to_spmi_controller(struct device *d)
+{
+ return container_of(d, struct spmi_controller, dev);
+}
+
+static inline
+void *spmi_controller_get_drvdata(const struct spmi_controller *ctrl)
+{
+ return dev_get_drvdata(&ctrl->dev);
+}
+
+static inline void spmi_controller_set_drvdata(struct spmi_controller *ctrl,
+ void *data)
+{
+ dev_set_drvdata(&ctrl->dev, data);
+}
+
+struct spmi_controller *spmi_controller_alloc(struct device *parent,
+ size_t size);
+
+/**
+ * spmi_controller_put() - decrement controller refcount
+ * @ctrl SPMI controller.
+ */
+static inline void spmi_controller_put(struct spmi_controller *ctrl)
+{
+ if (ctrl)
+ put_device(&ctrl->dev);
+}
+
+int spmi_controller_add(struct spmi_controller *ctrl);
+void spmi_controller_remove(struct spmi_controller *ctrl);
+
+/**
+ * struct spmi_driver - SPMI slave device driver
+ * @driver: SPMI device drivers should initialize name and owner field of
+ * this structure.
+ * @probe: binds this driver to a SPMI device.
+ * @remove: unbinds this driver from the SPMI device.
+ * @shutdown: standard shutdown callback used during powerdown/halt.
+ * @suspend: standard suspend callback used during system suspend.
+ * @resume: standard resume callback used during system resume.
+ *
+ * If PM runtime support is desired for a slave, a device driver can call
+ * pm_runtime_put() from their probe() routine (and a balancing
+ * pm_runtime_get() in remove()). PM runtime support for a slave is
+ * implemented by issuing a SLEEP command to the slave on runtime_suspend(),
+ * transitioning the slave into the SLEEP state. On runtime_resume(), a WAKEUP
+ * command is sent to the slave to bring it back to ACTIVE.
+ */
+struct spmi_driver {
+ struct device_driver driver;
+ int (*probe)(struct spmi_device *sdev);
+ void (*remove)(struct spmi_device *sdev);
+};
+
+static inline struct spmi_driver *to_spmi_driver(struct device_driver *d)
+{
+ return container_of(d, struct spmi_driver, driver);
+}
+
+int spmi_driver_register(struct spmi_driver *sdrv);
+
+/**
+ * spmi_driver_unregister() - unregister an SPMI client driver
+ * @sdrv: the driver to unregister
+ */
+static inline void spmi_driver_unregister(struct spmi_driver *sdrv)
+{
+ if (sdrv)
+ driver_unregister(&sdrv->driver);
+}
+
+#define module_spmi_driver(__spmi_driver) \
+ module_driver(__spmi_driver, spmi_driver_register, \
+ spmi_driver_unregister)
+
+int spmi_register_read(struct spmi_device *sdev, u8 addr, u8 *buf);
+int spmi_ext_register_read(struct spmi_device *sdev, u8 addr, u8 *buf,
+ size_t len);
+int spmi_ext_register_readl(struct spmi_device *sdev, u16 addr, u8 *buf,
+ size_t len);
+int spmi_register_write(struct spmi_device *sdev, u8 addr, u8 data);
+int spmi_register_zero_write(struct spmi_device *sdev, u8 data);
+int spmi_ext_register_write(struct spmi_device *sdev, u8 addr,
+ const u8 *buf, size_t len);
+int spmi_ext_register_writel(struct spmi_device *sdev, u16 addr,
+ const u8 *buf, size_t len);
+int spmi_command_reset(struct spmi_device *sdev);
+int spmi_command_sleep(struct spmi_device *sdev);
+int spmi_command_wakeup(struct spmi_device *sdev);
+int spmi_command_shutdown(struct spmi_device *sdev);
+
+#endif
diff --git a/include/linux/srcu.h b/include/linux/srcu.h
index 9b058eecd403..a2783cb5d275 100644
--- a/include/linux/srcu.h
+++ b/include/linux/srcu.h
@@ -12,8 +12,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright (C) IBM Corporation, 2006
* Copyright (C) Fujitsu, 2012
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 40ed9e9a77e5..1e67b7a5968c 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -98,6 +98,8 @@ struct sigaltstack;
#define __MAP(n,...) __MAP##n(__VA_ARGS__)
#define __SC_DECL(t, a) t a
+#define __TYPE_IS_L(t) (__same_type((t)0, 0L))
+#define __TYPE_IS_UL(t) (__same_type((t)0, 0UL))
#define __TYPE_IS_LL(t) (__same_type((t)0, 0LL) || __same_type((t)0, 0ULL))
#define __SC_LONG(t, a) __typeof(__builtin_choose_expr(__TYPE_IS_LL(t), 0LL, 0L)) a
#define __SC_CAST(t, a) (t) a
@@ -281,13 +283,15 @@ asmlinkage long sys_sched_setscheduler(pid_t pid, int policy,
asmlinkage long sys_sched_setparam(pid_t pid,
struct sched_param __user *param);
asmlinkage long sys_sched_setattr(pid_t pid,
- struct sched_attr __user *attr);
+ struct sched_attr __user *attr,
+ unsigned int flags);
asmlinkage long sys_sched_getscheduler(pid_t pid);
asmlinkage long sys_sched_getparam(pid_t pid,
struct sched_param __user *param);
asmlinkage long sys_sched_getattr(pid_t pid,
struct sched_attr __user *attr,
- unsigned int size);
+ unsigned int size,
+ unsigned int flags);
asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len,
unsigned long __user *user_mask_ptr);
asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len,
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 30b2ebee6439..e0bf210ddffd 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -198,6 +198,7 @@ int __must_check sysfs_chmod_file(struct kobject *kobj,
const struct attribute *attr, umode_t mode);
void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr,
const void *ns);
+bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr);
void sysfs_remove_files(struct kobject *kobj, const struct attribute **attr);
int __must_check sysfs_create_bin_file(struct kobject *kobj,
@@ -246,6 +247,11 @@ void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);
int __must_check sysfs_init(void);
+static inline void sysfs_enable_ns(struct kernfs_node *kn)
+{
+ return kernfs_enable_ns(kn);
+}
+
#else /* CONFIG_SYSFS */
static inline int sysfs_schedule_callback(struct kobject *kobj,
@@ -301,6 +307,12 @@ static inline void sysfs_remove_file_ns(struct kobject *kobj,
{
}
+static inline bool sysfs_remove_file_self(struct kobject *kobj,
+ const struct attribute *attr)
+{
+ return false;
+}
+
static inline void sysfs_remove_files(struct kobject *kobj,
const struct attribute **attr)
{
@@ -418,6 +430,10 @@ static inline int __must_check sysfs_init(void)
return 0;
}
+static inline void sysfs_enable_ns(struct kernfs_node *kn)
+{
+}
+
#endif /* CONFIG_SYSFS */
static inline int __must_check sysfs_create_file(struct kobject *kobj,
diff --git a/include/linux/torture.h b/include/linux/torture.h
new file mode 100644
index 000000000000..b2e2b468e511
--- /dev/null
+++ b/include/linux/torture.h
@@ -0,0 +1,100 @@
+/*
+ * Common functions for in-kernel torture tests.
+ *
+ * This program is free software; 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, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ *
+ * Copyright IBM Corporation, 2014
+ *
+ * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+ */
+
+#ifndef __LINUX_TORTURE_H
+#define __LINUX_TORTURE_H
+
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/seqlock.h>
+#include <linux/lockdep.h>
+#include <linux/completion.h>
+#include <linux/debugobjects.h>
+#include <linux/bug.h>
+#include <linux/compiler.h>
+
+/* Definitions for a non-string torture-test module parameter. */
+#define torture_param(type, name, init, msg) \
+ static type name = init; \
+ module_param(name, type, 0444); \
+ MODULE_PARM_DESC(name, msg);
+
+#define TORTURE_FLAG "-torture:"
+#define TOROUT_STRING(s) \
+ pr_alert("%s" TORTURE_FLAG s "\n", torture_type)
+#define VERBOSE_TOROUT_STRING(s) \
+ do { if (verbose) pr_alert("%s" TORTURE_FLAG " %s\n", torture_type, s); } while (0)
+#define VERBOSE_TOROUT_ERRSTRING(s) \
+ do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! %s\n", torture_type, s); } while (0)
+
+/* Definitions for a non-string torture-test module parameter. */
+#define torture_parm(type, name, init, msg) \
+ static type name = init; \
+ module_param(name, type, 0444); \
+ MODULE_PARM_DESC(name, msg);
+
+/* Definitions for online/offline exerciser. */
+int torture_onoff_init(long ooholdoff, long oointerval);
+char *torture_onoff_stats(char *page);
+bool torture_onoff_failures(void);
+
+/* Low-rider random number generator. */
+struct torture_random_state {
+ unsigned long trs_state;
+ long trs_count;
+};
+#define DEFINE_TORTURE_RANDOM(name) struct torture_random_state name = { 0, 0 }
+unsigned long torture_random(struct torture_random_state *trsp);
+
+/* Task shuffler, which causes CPUs to occasionally go idle. */
+void torture_shuffle_task_register(struct task_struct *tp);
+int torture_shuffle_init(long shuffint);
+
+/* Test auto-shutdown handling. */
+void torture_shutdown_absorb(const char *title);
+int torture_shutdown_init(int ssecs, void (*cleanup)(void));
+
+/* Task stuttering, which forces load/no-load transitions. */
+void stutter_wait(const char *title);
+int torture_stutter_init(int s);
+
+/* Initialization and cleanup. */
+void torture_init_begin(char *ttype, bool v, int *runnable);
+void torture_init_end(void);
+bool torture_cleanup(void);
+bool torture_must_stop(void);
+bool torture_must_stop_irq(void);
+void torture_kthread_stopping(char *title);
+int _torture_create_kthread(int (*fn)(void *arg), void *arg, char *s, char *m,
+ char *f, struct task_struct **tp);
+void _torture_stop_kthread(char *m, struct task_struct **tp);
+
+#define torture_create_kthread(n, arg, tp) \
+ _torture_create_kthread(n, (arg), #n, "Creating " #n " task", \
+ "Failed to create " #n, &(tp))
+#define torture_stop_kthread(n, tp) \
+ _torture_stop_kthread("Stopping " #n " task", &(tp))
+
+#endif /* __LINUX_TORTURE_H */
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index accc497f8d72..7159a0a933df 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -60,6 +60,12 @@ struct tp_module {
unsigned int num_tracepoints;
struct tracepoint * const *tracepoints_ptrs;
};
+bool trace_module_has_bad_taint(struct module *mod);
+#else
+static inline bool trace_module_has_bad_taint(struct module *mod)
+{
+ return false;
+}
#endif /* CONFIG_MODULES */
struct tracepoint_iter {
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 90b4fdc8a61f..b90b5c221ff0 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -208,7 +208,7 @@ struct tty_port {
wait_queue_head_t delta_msr_wait; /* Modem status change */
unsigned long flags; /* TTY flags ASY_*/
unsigned char console:1, /* port is a console */
- low_latency:1; /* direct buffer flush */
+ low_latency:1; /* optional: tune for latency */
struct mutex mutex; /* Locking */
struct mutex buf_mutex; /* Buffer alloc lock */
unsigned char *xmit_buf; /* Optional buffer */
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index b8347c207cb8..add26da2faeb 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -126,7 +126,6 @@
#include <linux/fs.h>
#include <linux/wait.h>
-#include <linux/wait.h>
/*
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 7f6eb859873e..6b7ec376fb4d 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -57,6 +57,7 @@ struct ep_device;
* @extra: descriptors following this endpoint in the configuration
* @extralen: how many bytes of "extra" are valid
* @enabled: URBs may be submitted to this endpoint
+ * @streams: number of USB-3 streams allocated on the endpoint
*
* USB requests are always queued to a given endpoint, identified by a
* descriptor within an active interface in a given USB configuration.
@@ -71,6 +72,7 @@ struct usb_host_endpoint {
unsigned char *extra; /* Extra descriptors */
int extralen;
int enabled;
+ int streams;
};
/* host-side wrapper for one interface setting's parsed descriptors */
@@ -202,6 +204,8 @@ static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
struct usb_interface *usb_get_intf(struct usb_interface *intf);
void usb_put_intf(struct usb_interface *intf);
+/* Hard limit */
+#define USB_MAXENDPOINTS 30
/* this maximum is arbitrary */
#define USB_MAXINTERFACES 32
#define USB_MAXIADS (USB_MAXINTERFACES/2)
@@ -366,6 +370,8 @@ struct usb_bus {
#endif
};
+struct usb_dev_state;
+
/* ----------------------------------------------------------------------- */
struct usb_tt;
@@ -749,6 +755,11 @@ extern struct usb_host_interface *usb_find_alt_setting(
unsigned int iface_num,
unsigned int alt_num);
+/* port claiming functions */
+int usb_hub_claim_port(struct usb_device *hdev, unsigned port1,
+ struct usb_dev_state *owner);
+int usb_hub_release_port(struct usb_device *hdev, unsigned port1,
+ struct usb_dev_state *owner);
/**
* usb_make_path - returns stable device path in the usb tree
@@ -1666,6 +1677,10 @@ extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr);
/* this request isn't really synchronous, but it belongs with the others */
extern int usb_driver_set_configuration(struct usb_device *udev, int config);
+/* choose and set configuration for device */
+extern int usb_choose_configuration(struct usb_device *udev);
+extern int usb_set_configuration(struct usb_device *dev, int configuration);
+
/*
* timeouts, in milliseconds, used for sending/receiving control messages
* they typically complete within a few frames (msec) after they're issued
diff --git a/include/linux/usb/cdc_ncm.h b/include/linux/usb/cdc_ncm.h
index c3fa80745996..2c14d9cdd57a 100644
--- a/include/linux/usb/cdc_ncm.h
+++ b/include/linux/usb/cdc_ncm.h
@@ -88,6 +88,7 @@
#define cdc_ncm_data_intf_is_mbim(x) ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB)
struct cdc_ncm_ctx {
+ struct usb_cdc_ncm_ntb_parameters ncm_parm;
struct hrtimer tx_timer;
struct tasklet_struct bh;
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h
index 708bd119627f..bbe779f640be 100644
--- a/include/linux/usb/chipidea.h
+++ b/include/linux/usb/chipidea.h
@@ -25,6 +25,7 @@ struct ci_hdrc_platform_data {
*/
#define CI_HDRC_DUAL_ROLE_NOT_OTG BIT(4)
#define CI_HDRC_IMX28_WRITE_FIX BIT(5)
+#define CI_HDRC_FORCE_FULLSPEED BIT(6)
enum usb_dr_mode dr_mode;
#define CI_HDRC_CONTROLLER_RESET_EVENT 0
#define CI_HDRC_CONTROLLER_STOPPED_EVENT 1
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index efe8d8a7c7ad..485cd5e2100c 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -143,6 +143,7 @@ struct usb_hcd {
unsigned authorized_default:1;
unsigned has_tt:1; /* Integrated TT in root hub */
unsigned amd_resume_bug:1; /* AMD remote wakeup quirk */
+ unsigned can_do_streams:1; /* HC supports streams */
unsigned int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
index 6c0b1c513db7..353053a33f21 100644
--- a/include/linux/usb/phy.h
+++ b/include/linux/usb/phy.h
@@ -111,6 +111,13 @@ struct usb_phy {
int (*set_suspend)(struct usb_phy *x,
int suspend);
+ /*
+ * Set wakeup enable for PHY, in that case, the PHY can be
+ * woken up from suspend status due to external events,
+ * like vbus change, dp/dm change and id.
+ */
+ int (*set_wakeup)(struct usb_phy *x, bool enabled);
+
/* notify phy connect status change */
int (*notify_connect)(struct usb_phy *x,
enum usb_device_speed speed);
@@ -265,6 +272,15 @@ usb_phy_set_suspend(struct usb_phy *x, int suspend)
}
static inline int
+usb_phy_set_wakeup(struct usb_phy *x, bool enabled)
+{
+ if (x && x->set_wakeup)
+ return x->set_wakeup(x, enabled);
+ else
+ return 0;
+}
+
+static inline int
usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed)
{
if (x && x->notify_connect)
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 704a1ab8240c..9bb547c7bce7 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -190,7 +190,8 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data)
* @num_ports: the number of different ports this device will have.
* @bulk_in_size: minimum number of bytes to allocate for bulk-in buffer
* (0 = end-point size)
- * @bulk_out_size: bytes to allocate for bulk-out buffer (0 = end-point size)
+ * @bulk_out_size: minimum number of bytes to allocate for bulk-out buffer
+ * (0 = end-point size)
* @calc_num_ports: pointer to a function to determine how many ports this
* device has dynamically. It will be called after the probe()
* callback is called, but before attach()
diff --git a/include/linux/usb/uas.h b/include/linux/usb/uas.h
index 5499ab5c94bd..3fc8e8b9f043 100644
--- a/include/linux/usb/uas.h
+++ b/include/linux/usb/uas.h
@@ -9,7 +9,7 @@ struct iu {
__u8 iu_id;
__u8 rsvd1;
__be16 tag;
-};
+} __attribute__((__packed__));
enum {
IU_ID_COMMAND = 0x01,
@@ -52,7 +52,7 @@ struct command_iu {
__u8 rsvd7;
struct scsi_lun lun;
__u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */
-};
+} __attribute__((__packed__));
struct task_mgmt_iu {
__u8 iu_id;
@@ -62,7 +62,7 @@ struct task_mgmt_iu {
__u8 rsvd2;
__be16 task_tag;
struct scsi_lun lun;
-};
+} __attribute__((__packed__));
/*
* Also used for the Read Ready and Write Ready IUs since they have the
@@ -77,15 +77,15 @@ struct sense_iu {
__u8 rsvd7[7];
__be16 len;
__u8 sense[SCSI_SENSE_BUFFERSIZE];
-};
+} __attribute__((__packed__));
-struct response_ui {
+struct response_iu {
__u8 iu_id;
__u8 rsvd1;
__be16 tag;
- __be16 add_response_info;
+ __u8 add_response_info[3];
__u8 response_code;
-};
+} __attribute__((__packed__));
struct usb_pipe_usage_descriptor {
__u8 bLength;
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index e303eef94dd5..0662e98fef72 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -30,7 +30,7 @@ struct usbnet {
struct driver_info *driver_info;
const char *driver_name;
void *driver_priv;
- wait_queue_head_t *wait;
+ wait_queue_head_t wait;
struct mutex phy_mutex;
unsigned char suspend_count;
unsigned char pkt_cnt, pkt_err;
diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h
index 630356866030..1a64b26046ed 100644
--- a/include/linux/usb_usual.h
+++ b/include/linux/usb_usual.h
@@ -67,8 +67,10 @@
/* Initial READ(10) (and others) must be retried */ \
US_FLAG(WRITE_CACHE, 0x00200000) \
/* Write Cache status is not available */ \
- US_FLAG(NEEDS_CAP16, 0x00400000)
- /* cannot handle READ_CAPACITY_10 */
+ US_FLAG(NEEDS_CAP16, 0x00400000) \
+ /* cannot handle READ_CAPACITY_10 */ \
+ US_FLAG(IGNORE_UAS, 0x00800000) \
+ /* Device advertises UAS but it is broken */
#define US_FLAG(name, value) US_FL_##name = value ,
enum { US_DO_ALL_FLAGS };
diff --git a/include/linux/video_output.h b/include/linux/video_output.h
deleted file mode 100644
index ed5cdeb3604d..000000000000
--- a/include/linux/video_output.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *
- * Copyright (C) 2006 Luming Yu <luming.yu@intel.com>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#ifndef _LINUX_VIDEO_OUTPUT_H
-#define _LINUX_VIDEO_OUTPUT_H
-#include <linux/device.h>
-#include <linux/err.h>
-struct output_device;
-struct output_properties {
- int (*set_state)(struct output_device *);
- int (*get_status)(struct output_device *);
-};
-struct output_device {
- int request_state;
- struct output_properties *props;
- struct device dev;
-};
-#define to_output_device(obj) container_of(obj, struct output_device, dev)
-#if defined(CONFIG_VIDEO_OUTPUT_CONTROL) || defined(CONFIG_VIDEO_OUTPUT_CONTROL_MODULE)
-struct output_device *video_output_register(const char *name,
- struct device *dev,
- void *devdata,
- struct output_properties *op);
-void video_output_unregister(struct output_device *dev);
-#else
-static struct output_device *video_output_register(const char *name,
- struct device *dev,
- void *devdata,
- struct output_properties *op)
-{
- return ERR_PTR(-ENODEV);
-}
-static void video_output_unregister(struct output_device *dev)
-{
- return;
-}
-#endif
-#endif
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 594521ba0d43..1b22c42e9c2d 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -177,20 +177,10 @@ struct execute_work {
#define DECLARE_DEFERRABLE_WORK(n, f) \
struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, TIMER_DEFERRABLE)
-/*
- * initialize a work item's function pointer
- */
-#define PREPARE_WORK(_work, _func) \
- do { \
- (_work)->func = (_func); \
- } while (0)
-
-#define PREPARE_DELAYED_WORK(_work, _func) \
- PREPARE_WORK(&(_work)->work, (_func))
-
#ifdef CONFIG_DEBUG_OBJECTS_WORK
extern void __init_work(struct work_struct *work, int onstack);
extern void destroy_work_on_stack(struct work_struct *work);
+extern void destroy_delayed_work_on_stack(struct delayed_work *work);
static inline unsigned int work_static(struct work_struct *work)
{
return *work_data_bits(work) & WORK_STRUCT_STATIC;
@@ -198,6 +188,7 @@ static inline unsigned int work_static(struct work_struct *work)
#else
static inline void __init_work(struct work_struct *work, int onstack) { }
static inline void destroy_work_on_stack(struct work_struct *work) { }
+static inline void destroy_delayed_work_on_stack(struct delayed_work *work) { }
static inline unsigned int work_static(struct work_struct *work) { return 0; }
#endif
@@ -217,7 +208,7 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
(_work)->data = (atomic_long_t) WORK_DATA_INIT(); \
lockdep_init_map(&(_work)->lockdep_map, #_work, &__key, 0); \
INIT_LIST_HEAD(&(_work)->entry); \
- PREPARE_WORK((_work), (_func)); \
+ (_work)->func = (_func); \
} while (0)
#else
#define __INIT_WORK(_work, _func, _onstack) \
@@ -225,7 +216,7 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
__init_work((_work), _onstack); \
(_work)->data = (atomic_long_t) WORK_DATA_INIT(); \
INIT_LIST_HEAD(&(_work)->entry); \
- PREPARE_WORK((_work), (_func)); \
+ (_work)->func = (_func); \
} while (0)
#endif
@@ -295,17 +286,11 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
* Documentation/workqueue.txt.
*/
enum {
- /*
- * All wqs are now non-reentrant making the following flag
- * meaningless. Will be removed.
- */
- WQ_NON_REENTRANT = 1 << 0, /* DEPRECATED */
-
WQ_UNBOUND = 1 << 1, /* not bound to any cpu */
WQ_FREEZABLE = 1 << 2, /* freeze during suspend */
WQ_MEM_RECLAIM = 1 << 3, /* may be used for memory reclaim */
WQ_HIGHPRI = 1 << 4, /* high priority */
- WQ_CPU_INTENSIVE = 1 << 5, /* cpu instensive workqueue */
+ WQ_CPU_INTENSIVE = 1 << 5, /* cpu intensive workqueue */
WQ_SYSFS = 1 << 6, /* visible in sysfs, see wq_sysfs_register() */
/*
@@ -419,10 +404,7 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
static struct lock_class_key __key; \
const char *__lock_name; \
\
- if (__builtin_constant_p(fmt)) \
- __lock_name = (fmt); \
- else \
- __lock_name = #fmt; \
+ __lock_name = #fmt#args; \
\
__alloc_workqueue_key((fmt), (flags), (max_active), \
&__key, __lock_name, ##args); \
@@ -605,21 +587,6 @@ static inline bool keventd_up(void)
return system_wq != NULL;
}
-/*
- * Like above, but uses del_timer() instead of del_timer_sync(). This means,
- * if it returns 0 the timer function may be running and the queueing is in
- * progress.
- */
-static inline bool __deprecated __cancel_delayed_work(struct delayed_work *work)
-{
- bool ret;
-
- ret = del_timer(&work->timer);
- if (ret)
- work_clear_pending(&work->work);
- return ret;
-}
-
/* used to be different but now identical to flush_work(), deprecated */
static inline bool __deprecated flush_work_sync(struct work_struct *work)
{
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index fc0e4320aa6d..021b8a319b9e 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -97,7 +97,7 @@ void writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
int try_to_writeback_inodes_sb(struct super_block *, enum wb_reason reason);
int try_to_writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
enum wb_reason reason);
-void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this);
+void sync_inodes_sb(struct super_block *);
void wakeup_flusher_threads(long nr_pages, enum wb_reason reason);
void inode_wait_for_writeback(struct inode *inode);
diff --git a/include/media/v4l2-of.h b/include/media/v4l2-of.h
index 541cea4122e9..70fa7b7b0487 100644
--- a/include/media/v4l2-of.h
+++ b/include/media/v4l2-of.h
@@ -17,6 +17,7 @@
#include <linux/list.h>
#include <linux/types.h>
#include <linux/errno.h>
+#include <linux/of_graph.h>
#include <media/v4l2-mediabus.h>
@@ -50,17 +51,13 @@ struct v4l2_of_bus_parallel {
/**
* struct v4l2_of_endpoint - the endpoint data structure
- * @port: identifier (value of reg property) of a port this endpoint belongs to
- * @id: identifier (value of reg property) of this endpoint
- * @local_node: pointer to device_node of this endpoint
+ * @base: struct of_endpoint containing port, id, and local of_node
* @bus_type: bus type
* @bus: bus configuration data structure
* @head: list head for this structure
*/
struct v4l2_of_endpoint {
- unsigned int port;
- unsigned int id;
- const struct device_node *local_node;
+ struct of_endpoint base;
enum v4l2_mbus_type bus_type;
union {
struct v4l2_of_bus_parallel parallel;
@@ -72,11 +69,6 @@ struct v4l2_of_endpoint {
#ifdef CONFIG_OF
int v4l2_of_parse_endpoint(const struct device_node *node,
struct v4l2_of_endpoint *endpoint);
-struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent,
- struct device_node *previous);
-struct device_node *v4l2_of_get_remote_port_parent(
- const struct device_node *node);
-struct device_node *v4l2_of_get_remote_port(const struct device_node *node);
#else /* CONFIG_OF */
static inline int v4l2_of_parse_endpoint(const struct device_node *node,
@@ -85,25 +77,6 @@ static inline int v4l2_of_parse_endpoint(const struct device_node *node,
return -ENOSYS;
}
-static inline struct device_node *v4l2_of_get_next_endpoint(
- const struct device_node *parent,
- struct device_node *previous)
-{
- return NULL;
-}
-
-static inline struct device_node *v4l2_of_get_remote_port_parent(
- const struct device_node *node)
-{
- return NULL;
-}
-
-static inline struct device_node *v4l2_of_get_remote_port(
- const struct device_node *node)
-{
- return NULL;
-}
-
#endif /* CONFIG_OF */
#endif /* _V4L2_OF_H */
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
index 9650a3ffd2d2..b4956a5fcc3f 100644
--- a/include/net/if_inet6.h
+++ b/include/net/if_inet6.h
@@ -31,8 +31,10 @@
#define IF_PREFIX_AUTOCONF 0x02
enum {
+ INET6_IFADDR_STATE_PREDAD,
INET6_IFADDR_STATE_DAD,
INET6_IFADDR_STATE_POSTDAD,
+ INET6_IFADDR_STATE_ERRDAD,
INET6_IFADDR_STATE_UP,
INET6_IFADDR_STATE_DEAD,
};
@@ -58,7 +60,7 @@ struct inet6_ifaddr {
unsigned long cstamp; /* created timestamp */
unsigned long tstamp; /* updated timestamp */
- struct timer_list dad_timer;
+ struct delayed_work dad_work;
struct inet6_dev *idev;
struct rt6_info *rt;
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 48ed75c21260..e77c10405d51 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -129,6 +129,7 @@ int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
struct ip_tunnel_parm *p);
void ip_tunnel_setup(struct net_device *dev, int net_id);
+void ip_tunnel_dst_reset_all(struct ip_tunnel *t);
/* Extract dsfield from inner protocol */
static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph,
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index d992ca3145fe..6ee76c804893 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1653,17 +1653,6 @@ struct sctp_association {
/* This is the last advertised value of rwnd over a SACK chunk. */
__u32 a_rwnd;
- /* Number of bytes by which the rwnd has slopped. The rwnd is allowed
- * to slop over a maximum of the association's frag_point.
- */
- __u32 rwnd_over;
-
- /* Keeps treack of rwnd pressure. This happens when we have
- * a window, but not recevie buffer (i.e small packets). This one
- * is releases slowly (1 PMTU at a time ).
- */
- __u32 rwnd_press;
-
/* This is the sndbuf size in use for the association.
* This corresponds to the sndbuf size for the association,
* as specified in the sk->sndbuf.
@@ -1892,8 +1881,7 @@ void sctp_assoc_update(struct sctp_association *old,
__u32 sctp_association_get_next_tsn(struct sctp_association *);
void sctp_assoc_sync_pmtu(struct sock *, struct sctp_association *);
-void sctp_assoc_rwnd_increase(struct sctp_association *, unsigned int);
-void sctp_assoc_rwnd_decrease(struct sctp_association *, unsigned int);
+void sctp_assoc_rwnd_update(struct sctp_association *, bool);
void sctp_assoc_set_primary(struct sctp_association *,
struct sctp_transport *);
void sctp_assoc_del_nonprimary_peers(struct sctp_association *,
diff --git a/include/net/sock.h b/include/net/sock.h
index 5c3f7c3624aa..b9586a137cad 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1488,6 +1488,11 @@ static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb)
*/
#define sock_owned_by_user(sk) ((sk)->sk_lock.owned)
+static inline void sock_release_ownership(struct sock *sk)
+{
+ sk->sk_lock.owned = 0;
+}
+
/*
* Macro so as to not evaluate some arguments when
* lockdep is not enabled.
@@ -2186,7 +2191,6 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
{
#define FLAGS_TS_OR_DROPS ((1UL << SOCK_RXQ_OVFL) | \
(1UL << SOCK_RCVTSTAMP) | \
- (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE) | \
(1UL << SOCK_TIMESTAMPING_SOFTWARE) | \
(1UL << SOCK_TIMESTAMPING_RAW_HARDWARE) | \
(1UL << SOCK_TIMESTAMPING_SYS_HARDWARE))
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 56fc366da6d5..743accec6c76 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -480,20 +480,21 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
#ifdef CONFIG_SYN_COOKIES
#include <linux/ktime.h>
-/* Syncookies use a monotonic timer which increments every 64 seconds.
+/* Syncookies use a monotonic timer which increments every 60 seconds.
* This counter is used both as a hash input and partially encoded into
* the cookie value. A cookie is only validated further if the delta
* between the current counter value and the encoded one is less than this,
- * i.e. a sent cookie is valid only at most for 128 seconds (or less if
+ * i.e. a sent cookie is valid only at most for 2*60 seconds (or less if
* the counter advances immediately after a cookie is generated).
*/
#define MAX_SYNCOOKIE_AGE 2
static inline u32 tcp_cookie_time(void)
{
- struct timespec now;
- getnstimeofday(&now);
- return now.tv_sec >> 6; /* 64 seconds granularity */
+ u64 val = get_jiffies_64();
+
+ do_div(val, 60 * HZ);
+ return val;
}
u32 __cookie_v4_init_sequence(const struct iphdr *iph, const struct tcphdr *th,
@@ -1303,7 +1304,8 @@ struct tcp_fastopen_request {
/* Fast Open cookie. Size 0 means a cookie request */
struct tcp_fastopen_cookie cookie;
struct msghdr *data; /* data in MSG_FASTOPEN */
- u16 copied; /* queued in tcp_connect() */
+ size_t size;
+ int copied; /* queued in tcp_connect() */
};
void tcp_free_fastopen_req(struct tcp_sock *tp);
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index afa5730fb3bd..fb5654a8ca3c 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1648,6 +1648,11 @@ static inline int xfrm_aevent_is_on(struct net *net)
}
#endif
+static inline int aead_len(struct xfrm_algo_aead *alg)
+{
+ return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
+}
+
static inline int xfrm_alg_len(const struct xfrm_algo *alg)
{
return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
@@ -1686,6 +1691,12 @@ static inline int xfrm_replay_clone(struct xfrm_state *x,
return 0;
}
+static inline struct xfrm_algo_aead *xfrm_algo_aead_clone(struct xfrm_algo_aead *orig)
+{
+ return kmemdup(orig, aead_len(orig), GFP_KERNEL);
+}
+
+
static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig)
{
return kmemdup(orig, xfrm_alg_len(orig), GFP_KERNEL);
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 309f51336fb9..7221a24e821b 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -327,12 +327,19 @@ struct iscsi_session {
struct iscsi_transport *tt;
struct Scsi_Host *host;
struct iscsi_conn *leadconn; /* leading connection */
- spinlock_t lock; /* protects session state, *
- * sequence numbers, *
+ /* Between the forward and the backward locks exists a strict locking
+ * hierarchy. The mutual exclusion zone protected by the forward lock
+ * can enclose the mutual exclusion zone protected by the backward lock
+ * but not vice versa.
+ */
+ spinlock_t frwd_lock; /* protects session state, *
+ * cmdsn, queued_cmdsn *
* session resources: *
- * - cmdpool, *
- * - mgmtpool, *
- * - r2tpool */
+ * - cmdpool kfifo_out , *
+ * - mgmtpool, */
+ spinlock_t back_lock; /* protects cmdsn_exp *
+ * cmdsn_max, *
+ * cmdpool kfifo_in */
int state; /* session state */
int age; /* counts session re-opens */
diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h
index 215469a9b801..2a7aa75dd009 100644
--- a/include/scsi/libiscsi_tcp.h
+++ b/include/scsi/libiscsi_tcp.h
@@ -83,6 +83,8 @@ struct iscsi_tcp_task {
struct iscsi_pool r2tpool;
struct kfifo r2tqueue;
void *dd_data;
+ spinlock_t pool2queue;
+ spinlock_t queue2pool;
};
enum {
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index f843dd8722a9..ef7872c20da9 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -172,7 +172,6 @@ struct sata_device {
enum ata_command_set command_set;
struct smp_resp rps_resp; /* report_phy_sata_resp */
u8 port_no; /* port number, if this is a PM (Port) */
- int pm_result;
struct ata_port *ap;
struct ata_host ata_host;
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 91558a1f97f4..dd7c998221b3 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -142,8 +142,7 @@ static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
extern struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *, gfp_t);
extern void scsi_put_command(struct scsi_cmnd *);
-extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *,
- struct device *);
+extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *);
extern void scsi_finish_command(struct scsi_cmnd *cmd);
extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
@@ -156,9 +155,6 @@ extern void scsi_release_buffers(struct scsi_cmnd *cmd);
extern int scsi_dma_map(struct scsi_cmnd *cmd);
extern void scsi_dma_unmap(struct scsi_cmnd *cmd);
-struct scsi_cmnd *scsi_allocate_command(gfp_t gfp_mask);
-void scsi_free_command(gfp_t gfp_mask, struct scsi_cmnd *cmd);
-
static inline unsigned scsi_sg_count(struct scsi_cmnd *cmd)
{
return cmd->sdb.table.nents;
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index d65fbec2533d..4e845b80efd3 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -113,6 +113,12 @@ struct scsi_device {
const char * vendor; /* [back_compat] point into 'inquiry' ... */
const char * model; /* ... after scan; point to static string */
const char * rev; /* ... "nullnullnullnull" before scan */
+
+#define SCSI_VPD_PG_LEN 255
+ int vpd_pg83_len;
+ unsigned char *vpd_pg83;
+ int vpd_pg80_len;
+ unsigned char *vpd_pg80;
unsigned char current_tag; /* current tag */
struct scsi_target *sdev_target; /* used only for single_lun */
@@ -235,12 +241,24 @@ struct scsi_dh_data {
#define sdev_printk(prefix, sdev, fmt, a...) \
dev_printk(prefix, &(sdev)->sdev_gendev, fmt, ##a)
+#define sdev_dbg(sdev, fmt, a...) \
+ dev_dbg(&(sdev)->sdev_gendev, fmt, ##a)
+
#define scmd_printk(prefix, scmd, fmt, a...) \
(scmd)->request->rq_disk ? \
sdev_printk(prefix, (scmd)->device, "[%s] " fmt, \
(scmd)->request->rq_disk->disk_name, ##a) : \
sdev_printk(prefix, (scmd)->device, fmt, ##a)
+#define scmd_dbg(scmd, fmt, a...) \
+ do { \
+ if ((scmd)->request->rq_disk) \
+ sdev_dbg((scmd)->device, "[%s] " fmt, \
+ (scmd)->request->rq_disk->disk_name, ##a);\
+ else \
+ sdev_dbg((scmd)->device, fmt, ##a); \
+ } while (0)
+
enum scsi_target_state {
STARGET_CREATED = 1,
STARGET_RUNNING,
@@ -257,7 +275,7 @@ struct scsi_target {
struct list_head siblings;
struct list_head devices;
struct device dev;
- unsigned int reap_ref; /* protected by the host lock */
+ struct kref reap_ref; /* last put renders target invisible */
unsigned int channel;
unsigned int id; /* target id ... replace
* scsi_device.id eventually */
@@ -284,7 +302,6 @@ struct scsi_target {
#define SCSI_DEFAULT_TARGET_BLOCKED 3
char scsi_level;
- struct execute_work ew;
enum scsi_target_state state;
void *hostdata; /* available to low-level driver */
unsigned long starget_data[0]; /* for the transport */
@@ -309,6 +326,7 @@ extern int scsi_add_device(struct Scsi_Host *host, uint channel,
extern int scsi_register_device_handler(struct scsi_device_handler *scsi_dh);
extern void scsi_remove_device(struct scsi_device *);
extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh);
+void scsi_attach_vpd(struct scsi_device *sdev);
extern int scsi_device_get(struct scsi_device *);
extern void scsi_device_put(struct scsi_device *);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 53075e5039e6..94844fc77b97 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -15,6 +15,7 @@ struct completion;
struct module;
struct scsi_cmnd;
struct scsi_device;
+struct scsi_host_cmd_pool;
struct scsi_target;
struct Scsi_Host;
struct scsi_host_cmd_pool;
@@ -524,6 +525,12 @@ struct scsi_host_template {
* scsi_netlink.h
*/
u64 vendor_id;
+
+ /*
+ * Additional per-command data allocated for the driver.
+ */
+ unsigned int cmd_size;
+ struct scsi_host_cmd_pool *cmd_pool;
};
/*
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index b797e8fad669..8c79980dc8f2 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -130,6 +130,7 @@ enum fc_vport_state {
#define FC_PORTSPEED_4GBIT 8
#define FC_PORTSPEED_8GBIT 0x10
#define FC_PORTSPEED_16GBIT 0x20
+#define FC_PORTSPEED_32GBIT 0x40
#define FC_PORTSPEED_NOT_NEGOTIATED (1 << 15) /* Speed not established */
/*
diff --git a/include/sound/core.h b/include/sound/core.h
index 2a14f1f02d4f..d3f5f818e0b9 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -22,6 +22,7 @@
*
*/
+#include <linux/device.h>
#include <linux/sched.h> /* wake_up() */
#include <linux/mutex.h> /* struct mutex */
#include <linux/rwsem.h> /* struct rw_semaphore */
@@ -41,39 +42,33 @@
/* forward declarations */
struct pci_dev;
struct module;
-struct device;
-struct device_attribute;
+struct completion;
/* device allocation stuff */
-#define SNDRV_DEV_TYPE_RANGE_SIZE 0x1000
-
-typedef int __bitwise snd_device_type_t;
-#define SNDRV_DEV_TOPLEVEL ((__force snd_device_type_t) 0)
-#define SNDRV_DEV_CONTROL ((__force snd_device_type_t) 1)
-#define SNDRV_DEV_LOWLEVEL_PRE ((__force snd_device_type_t) 2)
-#define SNDRV_DEV_LOWLEVEL_NORMAL ((__force snd_device_type_t) 0x1000)
-#define SNDRV_DEV_PCM ((__force snd_device_type_t) 0x1001)
-#define SNDRV_DEV_RAWMIDI ((__force snd_device_type_t) 0x1002)
-#define SNDRV_DEV_TIMER ((__force snd_device_type_t) 0x1003)
-#define SNDRV_DEV_SEQUENCER ((__force snd_device_type_t) 0x1004)
-#define SNDRV_DEV_HWDEP ((__force snd_device_type_t) 0x1005)
-#define SNDRV_DEV_INFO ((__force snd_device_type_t) 0x1006)
-#define SNDRV_DEV_BUS ((__force snd_device_type_t) 0x1007)
-#define SNDRV_DEV_CODEC ((__force snd_device_type_t) 0x1008)
-#define SNDRV_DEV_JACK ((__force snd_device_type_t) 0x1009)
-#define SNDRV_DEV_COMPRESS ((__force snd_device_type_t) 0x100A)
-#define SNDRV_DEV_LOWLEVEL ((__force snd_device_type_t) 0x2000)
-
-typedef int __bitwise snd_device_state_t;
-#define SNDRV_DEV_BUILD ((__force snd_device_state_t) 0)
-#define SNDRV_DEV_REGISTERED ((__force snd_device_state_t) 1)
-#define SNDRV_DEV_DISCONNECTED ((__force snd_device_state_t) 2)
-
-typedef int __bitwise snd_device_cmd_t;
-#define SNDRV_DEV_CMD_PRE ((__force snd_device_cmd_t) 0)
-#define SNDRV_DEV_CMD_NORMAL ((__force snd_device_cmd_t) 1)
-#define SNDRV_DEV_CMD_POST ((__force snd_device_cmd_t) 2)
+/* type of the object used in snd_device_*()
+ * this also defines the calling order
+ */
+enum snd_device_type {
+ SNDRV_DEV_LOWLEVEL,
+ SNDRV_DEV_CONTROL,
+ SNDRV_DEV_INFO,
+ SNDRV_DEV_BUS,
+ SNDRV_DEV_CODEC,
+ SNDRV_DEV_PCM,
+ SNDRV_DEV_COMPRESS,
+ SNDRV_DEV_RAWMIDI,
+ SNDRV_DEV_TIMER,
+ SNDRV_DEV_SEQUENCER,
+ SNDRV_DEV_HWDEP,
+ SNDRV_DEV_JACK,
+};
+
+enum snd_device_state {
+ SNDRV_DEV_BUILD,
+ SNDRV_DEV_REGISTERED,
+ SNDRV_DEV_DISCONNECTED,
+};
struct snd_device;
@@ -86,8 +81,8 @@ struct snd_device_ops {
struct snd_device {
struct list_head list; /* list of registered devices */
struct snd_card *card; /* card which holds this device */
- snd_device_state_t state; /* state of the device */
- snd_device_type_t type; /* device type */
+ enum snd_device_state state; /* state of the device */
+ enum snd_device_type type; /* device type */
void *device_data; /* device structure */
struct snd_device_ops *ops; /* operations */
};
@@ -131,11 +126,10 @@ struct snd_card {
state */
spinlock_t files_lock; /* lock the files for this card */
int shutdown; /* this card is going down */
- int free_on_last_close; /* free in context of file_release */
- wait_queue_head_t shutdown_sleep;
- atomic_t refcount; /* refcount for disconnection */
+ struct completion *release_completion;
struct device *dev; /* device assigned to this card */
- struct device *card_dev; /* cardX object for sysfs */
+ struct device card_dev; /* cardX object for sysfs */
+ bool registered; /* card_dev is registered? */
#ifdef CONFIG_PM
unsigned int power_state; /* power state */
@@ -149,6 +143,8 @@ struct snd_card {
#endif
};
+#define dev_to_snd_card(p) container_of(p, struct snd_card, card_dev)
+
#ifdef CONFIG_PM
static inline void snd_power_lock(struct snd_card *card)
{
@@ -197,7 +193,7 @@ struct snd_minor {
/* return a device pointer linked to each sound device as a parent */
static inline struct device *snd_card_get_device_link(struct snd_card *card)
{
- return card ? card->card_dev : NULL;
+ return card ? &card->card_dev : NULL;
}
/* sound.c */
@@ -244,13 +240,11 @@ static inline int snd_register_device(int type, struct snd_card *card, int dev,
int snd_unregister_device(int type, struct snd_card *card, int dev);
void *snd_lookup_minor_data(unsigned int minor, int type);
-int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
- struct device_attribute *attr);
+struct device *snd_get_device(int type, struct snd_card *card, int dev);
#ifdef CONFIG_SND_OSSEMUL
int snd_register_oss_device(int type, struct snd_card *card, int dev,
- const struct file_operations *f_ops, void *private_data,
- const char *name);
+ const struct file_operations *f_ops, void *private_data);
int snd_unregister_oss_device(int type, struct snd_card *card, int dev);
void *snd_lookup_oss_minor_data(unsigned int minor, int type);
#endif
@@ -284,9 +278,16 @@ int snd_card_locked(int card);
extern int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int cmd);
#endif
-int snd_card_create(int idx, const char *id,
- struct module *module, int extra_size,
- struct snd_card **card_ret);
+int snd_card_new(struct device *parent, int idx, const char *xid,
+ struct module *module, int extra_size,
+ struct snd_card **card_ret);
+
+static inline int __deprecated
+snd_card_create(int idx, const char *id, struct module *module, int extra_size,
+ struct snd_card **ret)
+{
+ return snd_card_new(NULL, idx, id, module, extra_size, ret);
+}
int snd_card_disconnect(struct snd_card *card);
int snd_card_free(struct snd_card *card);
@@ -298,20 +299,19 @@ int snd_card_info_done(void);
int snd_component_add(struct snd_card *card, const char *component);
int snd_card_file_add(struct snd_card *card, struct file *file);
int snd_card_file_remove(struct snd_card *card, struct file *file);
-void snd_card_unref(struct snd_card *card);
+#define snd_card_unref(card) put_device(&(card)->card_dev)
#define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
/* device.c */
-int snd_device_new(struct snd_card *card, snd_device_type_t type,
+int snd_device_new(struct snd_card *card, enum snd_device_type type,
void *device_data, struct snd_device_ops *ops);
int snd_device_register(struct snd_card *card, void *device_data);
int snd_device_register_all(struct snd_card *card);
-int snd_device_disconnect(struct snd_card *card, void *device_data);
int snd_device_disconnect_all(struct snd_card *card);
-int snd_device_free(struct snd_card *card, void *device_data);
-int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd);
+void snd_device_free(struct snd_card *card, void *device_data);
+void snd_device_free_all(struct snd_card *card);
/* isadma.c */
@@ -433,7 +433,6 @@ static inline void snd_printdd(const char *format, ...) {}
#define gameport_get_port_data(gp) (gp)->port_data
#endif
-#ifdef CONFIG_PCI
/* PCI quirk list helper */
struct snd_pci_quirk {
unsigned short subvendor; /* PCI subvendor ID */
@@ -469,12 +468,26 @@ struct snd_pci_quirk {
#define snd_pci_quirk_name(q) ""
#endif
+#ifdef CONFIG_PCI
const struct snd_pci_quirk *
snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list);
const struct snd_pci_quirk *
snd_pci_quirk_lookup_id(u16 vendor, u16 device,
const struct snd_pci_quirk *list);
+#else
+static inline const struct snd_pci_quirk *
+snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
+{
+ return NULL;
+}
+
+static inline const struct snd_pci_quirk *
+snd_pci_quirk_lookup_id(u16 vendor, u16 device,
+ const struct snd_pci_quirk *list)
+{
+ return NULL;
+}
#endif
#endif /* __SOUND_CORE_H */
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index dfb42ca6d043..c46908c1bb3f 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -436,8 +436,6 @@
#define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */
#define CCCA_CURRADDR 0x18000008
-/* undefine CCR to avoid conflict with the definition for SH */
-#undef CCR
#define CCR 0x09 /* Cache control register */
#define CCR_CACHEINVALIDSIZE 0x07190009
#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */
diff --git a/include/sound/hwdep.h b/include/sound/hwdep.h
index 8c05e47a4090..ae04a3ec9c77 100644
--- a/include/sound/hwdep.h
+++ b/include/sound/hwdep.h
@@ -60,7 +60,6 @@ struct snd_hwdep {
int iface;
#ifdef CONFIG_SND_OSSEMUL
- char oss_dev[32];
int oss_type;
int ossreg;
#endif
@@ -69,6 +68,8 @@ struct snd_hwdep {
wait_queue_head_t open_wait;
void *private_data;
void (*private_free) (struct snd_hwdep *hwdep);
+ struct device *dev;
+ const struct attribute_group **groups;
struct mutex open_mutex;
int used; /* reference counter */
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 4883499ab38b..b4d6697085fe 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -1141,4 +1141,12 @@ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
return 1ULL << (__force int) pcm_format;
}
+/* printk helpers */
+#define pcm_err(pcm, fmt, args...) \
+ dev_err((pcm)->card->dev, fmt, ##args)
+#define pcm_warn(pcm, fmt, args...) \
+ dev_warn((pcm)->card->dev, fmt, ##args)
+#define pcm_dbg(pcm, fmt, args...) \
+ dev_dbg((pcm)->card->dev, fmt, ##args)
+
#endif /* __SOUND_PCM_H */
diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h
index adf0885153f3..311dafe6cc4b 100644
--- a/include/sound/rawmidi.h
+++ b/include/sound/rawmidi.h
@@ -157,10 +157,8 @@ void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
/* callbacks */
-void snd_rawmidi_receive_reset(struct snd_rawmidi_substream *substream);
int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
const unsigned char *buffer, int count);
-void snd_rawmidi_transmit_reset(struct snd_rawmidi_substream *substream);
int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream);
int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
unsigned char *buffer, int count);
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
index 6add6ccc811e..34a3c02a4576 100644
--- a/include/sound/rcar_snd.h
+++ b/include/sound/rcar_snd.h
@@ -34,17 +34,17 @@
* B : SSI direction
*/
#define RSND_SSI_CLK_PIN_SHARE (1 << 31)
-#define RSND_SSI_SYNC (1 << 29) /* SSI34_sync etc */
-
#define RSND_SSI_PLAY (1 << 24)
+#define RSND_SSI(_dma_id, _pio_irq, _flags) \
+{ .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
#define RSND_SSI_SET(_dai_id, _dma_id, _pio_irq, _flags) \
{ .dai_id = _dai_id, .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
#define RSND_SSI_UNUSED \
{ .dai_id = -1, .dma_id = -1, .pio_irq = -1, .flags = 0 }
struct rsnd_ssi_platform_info {
- int dai_id;
+ int dai_id; /* will be removed */
int dma_id;
int pio_irq;
u32 flags;
@@ -55,9 +55,31 @@ struct rsnd_ssi_platform_info {
*/
#define RSND_SCU_USE_HPBIF (1 << 31) /* it needs RSND_SSI_DEPENDENT */
-struct rsnd_scu_platform_info {
+#define RSND_SRC(rate, _dma_id) \
+{ .flags = RSND_SCU_USE_HPBIF, .convert_rate = rate, .dma_id = _dma_id, }
+#define RSND_SRC_SET(rate, _dma_id) \
+ { .flags = RSND_SCU_USE_HPBIF, .convert_rate = rate, .dma_id = _dma_id, }
+#define RSND_SRC_UNUSED \
+ { .flags = 0, .convert_rate = 0, .dma_id = 0, }
+
+#define rsnd_scu_platform_info rsnd_src_platform_info
+#define src_info scu_info
+#define src_info_nr scu_info_nr
+
+struct rsnd_src_platform_info {
u32 flags;
u32 convert_rate; /* sampling rate convert */
+ int dma_id; /* for Gen2 SCU */
+};
+
+struct rsnd_dai_path_info {
+ struct rsnd_ssi_platform_info *ssi;
+ struct rsnd_src_platform_info *src;
+};
+
+struct rsnd_dai_platform_info {
+ struct rsnd_dai_path_info playback;
+ struct rsnd_dai_path_info capture;
};
/*
@@ -75,8 +97,10 @@ struct rcar_snd_info {
u32 flags;
struct rsnd_ssi_platform_info *ssi_info;
int ssi_info_nr;
- struct rsnd_scu_platform_info *scu_info;
- int scu_info_nr;
+ struct rsnd_src_platform_info *src_info;
+ int src_info_nr;
+ struct rsnd_dai_platform_info *dai_info;
+ int dai_info_nr;
int (*start)(int id);
int (*stop)(int id);
};
diff --git a/include/sound/simple_card.h b/include/sound/simple_card.h
index 6c74527d4926..9b0ac77177b6 100644
--- a/include/sound/simple_card.h
+++ b/include/sound/simple_card.h
@@ -18,6 +18,8 @@ struct asoc_simple_dai {
const char *name;
unsigned int fmt;
unsigned int sysclk;
+ int slots;
+ int slot_width;
};
struct asoc_simple_card_info {
@@ -29,10 +31,6 @@ struct asoc_simple_card_info {
unsigned int daifmt;
struct asoc_simple_dai cpu_dai;
struct asoc_simple_dai codec_dai;
-
- /* used in simple-card.c */
- struct snd_soc_dai_link snd_link;
- struct snd_soc_card snd_card;
};
#endif /* __SIMPLE_CARD_H */
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 71f27c403194..fad76769f153 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -142,6 +142,8 @@ struct snd_soc_dai_ops {
* Called by soc_card drivers, normally in their hw_params.
*/
int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
+ int (*xlate_tdm_slot_mask)(unsigned int slots,
+ unsigned int *tx_mask, unsigned int *rx_mask);
int (*set_tdm_slot)(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask,
int slots, int slot_width);
@@ -270,6 +272,7 @@ struct snd_soc_dai {
/* parent platform/codec */
struct snd_soc_platform *platform;
struct snd_soc_codec *codec;
+ struct snd_soc_component *component;
struct snd_soc_card *card;
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 68d92e36facd..ef78f562f4a8 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -108,13 +108,9 @@ struct device;
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = 1}
#define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{ .id = snd_soc_dapm_virt_mux, .name = wname, \
- SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
- .kcontrol_news = wcontrols, .num_kcontrols = 1}
+ SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols)
#define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{ .id = snd_soc_dapm_value_mux, .name = wname, \
- SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
- .kcontrol_news = wcontrols, .num_kcontrols = 1}
+ SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols)
/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
#define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
@@ -172,10 +168,8 @@ struct device;
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \
-{ .id = snd_soc_dapm_virt_mux, .name = wname, \
- SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
- .kcontrol_news = wcontrols, .num_kcontrols = 1, \
- .event = wevent, .event_flags = wflags}
+ SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, wevent, \
+ wflags)
/* additional sequencing control within an event type */
#define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \
@@ -311,12 +305,8 @@ struct device;
.get = snd_soc_dapm_get_enum_double, \
.put = snd_soc_dapm_put_enum_double, \
.private_value = (unsigned long)&xenum }
-#define SOC_DAPM_ENUM_VIRT(xname, xenum) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_enum_double, \
- .get = snd_soc_dapm_get_enum_virt, \
- .put = snd_soc_dapm_put_enum_virt, \
- .private_value = (unsigned long)&xenum }
+#define SOC_DAPM_ENUM_VIRT(xname, xenum) \
+ SOC_DAPM_ENUM(xname, xenum)
#define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_enum_double, \
@@ -324,11 +314,7 @@ struct device;
.put = xput, \
.private_value = (unsigned long)&xenum }
#define SOC_DAPM_VALUE_ENUM(xname, xenum) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_enum_double, \
- .get = snd_soc_dapm_get_value_enum_double, \
- .put = snd_soc_dapm_put_value_enum_double, \
- .private_value = (unsigned long)&xenum }
+ SOC_DAPM_ENUM(xname, xenum)
#define SOC_DAPM_PIN_SWITCH(xname) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname " Switch", \
.info = snd_soc_dapm_info_pin_switch, \
@@ -392,14 +378,6 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
-int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
@@ -449,20 +427,28 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
/* dapm audio pin control and status */
int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
const char *pin);
+int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+ const char *pin);
int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
const char *pin);
+int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+ const char *pin);
int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
+ const char *pin);
int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
const char *pin);
int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm);
+int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm);
int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
const char *pin);
+int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+ const char *pin);
int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
const char *pin);
void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec);
/* Mostly internal - should not normally be used */
-void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason);
void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm);
/* dapm path query */
@@ -476,8 +462,6 @@ enum snd_soc_dapm_type {
snd_soc_dapm_input = 0, /* input pin */
snd_soc_dapm_output, /* output pin */
snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
- snd_soc_dapm_virt_mux, /* virtual version of snd_soc_dapm_mux */
- snd_soc_dapm_value_mux, /* selects 1 analog signal from many inputs */
snd_soc_dapm_mixer, /* mixes several analog signals together */
snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */
snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 9a001472b96a..0b83168d8ff4 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -45,6 +45,11 @@
((unsigned long)&(struct soc_mixer_control) \
{.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
.max = xmax, .platform_max = xmax, .invert = xinvert})
+#define SOC_DOUBLE_R_S_VALUE(xlreg, xrreg, xshift, xmin, xmax, xsign_bit, xinvert) \
+ ((unsigned long)&(struct soc_mixer_control) \
+ {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
+ .max = xmax, .min = xmin, .platform_max = xmax, .sign_bit = xsign_bit, \
+ .invert = xinvert})
#define SOC_DOUBLE_R_RANGE_VALUE(xlreg, xrreg, xshift, xmin, xmax, xinvert) \
((unsigned long)&(struct soc_mixer_control) \
{.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
@@ -152,6 +157,15 @@
{.reg = xreg, .rreg = xrreg, \
.shift = xshift, .rshift = xshift, \
.max = xmax, .min = xmin} }
+#define SOC_DOUBLE_R_S_TLV(xname, reg_left, reg_right, xshift, xmin, xmax, xsign_bit, xinvert, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw, \
+ .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
+ .private_value = SOC_DOUBLE_R_S_VALUE(reg_left, reg_right, xshift, \
+ xmin, xmax, xsign_bit, xinvert) }
#define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
@@ -162,30 +176,28 @@
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .min = xmin, .max = xmax, \
.platform_max = xmax} }
-#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \
+#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xitems, xtexts) \
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
- .max = xmax, .texts = xtexts, \
- .mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0}
-#define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \
- SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts)
-#define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \
-{ .max = xmax, .texts = xtexts }
-#define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xmax, xtexts, xvalues) \
+ .items = xitems, .texts = xtexts, \
+ .mask = xitems ? roundup_pow_of_two(xitems) - 1 : 0}
+#define SOC_ENUM_SINGLE(xreg, xshift, xitems, xtexts) \
+ SOC_ENUM_DOUBLE(xreg, xshift, xshift, xitems, xtexts)
+#define SOC_ENUM_SINGLE_EXT(xitems, xtexts) \
+{ .items = xitems, .texts = xtexts }
+#define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xitems, xtexts, xvalues) \
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
- .mask = xmask, .max = xmax, .texts = xtexts, .values = xvalues}
-#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xmax, xtexts, xvalues) \
- SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xmax, xtexts, xvalues)
+ .mask = xmask, .items = xitems, .texts = xtexts, .values = xvalues}
+#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xnitmes, xtexts, xvalues) \
+ SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xnitmes, xtexts, xvalues)
+#define SOC_ENUM_SINGLE_VIRT(xitems, xtexts) \
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, xitems, xtexts)
#define SOC_ENUM(xname, xenum) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
.info = snd_soc_info_enum_double, \
.get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
.private_value = (unsigned long)&xenum }
#define SOC_VALUE_ENUM(xname, xenum) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
- .info = snd_soc_info_enum_double, \
- .get = snd_soc_get_value_enum_double, \
- .put = snd_soc_put_value_enum_double, \
- .private_value = (unsigned long)&xenum }
+ SOC_ENUM(xname, xenum)
#define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\
xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -272,17 +284,19 @@
* ARRAY_SIZE internally
*/
#define SOC_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xtexts) \
- struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \
+ const struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \
ARRAY_SIZE(xtexts), xtexts)
#define SOC_ENUM_SINGLE_DECL(name, xreg, xshift, xtexts) \
SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts)
#define SOC_ENUM_SINGLE_EXT_DECL(name, xtexts) \
- struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts)
+ const struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts)
#define SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xmask, xtexts, xvalues) \
- struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \
+ const struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \
ARRAY_SIZE(xtexts), xtexts, xvalues)
#define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
+#define SOC_ENUM_SINGLE_VIRT_DECL(name, xtexts) \
+ const struct soc_enum name = SOC_ENUM_SINGLE_VIRT(ARRAY_SIZE(xtexts), xtexts)
/*
* Component probe and remove ordering levels for components with runtime
@@ -340,12 +354,6 @@ typedef int (*hw_write_t)(void *,const char* ,int);
extern struct snd_ac97_bus_ops *soc_ac97_ops;
-enum snd_soc_control_type {
- SND_SOC_I2C = 1,
- SND_SOC_SPI,
- SND_SOC_REGMAP,
-};
-
enum snd_soc_pcm_subclass {
SND_SOC_PCM_CLASS_PCM = 0,
SND_SOC_PCM_CLASS_BE = 1,
@@ -392,8 +400,7 @@ int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
unsigned int reg);
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
- int addr_bits, int data_bits,
- enum snd_soc_control_type control);
+ struct regmap *regmap);
int snd_soc_cache_sync(struct snd_soc_codec *codec);
int snd_soc_cache_init(struct snd_soc_codec *codec);
int snd_soc_cache_exit(struct snd_soc_codec *codec);
@@ -413,6 +420,10 @@ struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
const char *dai_link);
+bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd);
+void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream);
+void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream);
+
/* Utility functions to get clock rates from various things */
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -496,10 +507,6 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
-int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
#define snd_soc_info_bool_ext snd_ctl_boolean_mono_info
@@ -600,7 +607,8 @@ struct snd_soc_jack_gpio {
struct snd_soc_jack *jack;
struct delayed_work work;
- int (*jack_status_check)(void);
+ void *data;
+ int (*jack_status_check)(void *data);
};
struct snd_soc_jack {
@@ -656,12 +664,19 @@ struct snd_soc_component {
const char *name;
int id;
struct device *dev;
+
+ unsigned int active;
+
+ unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
+
struct list_head list;
struct snd_soc_dai_driver *dai_drv;
int num_dai;
const struct snd_soc_component_driver *driver;
+
+ struct list_head dai_list;
};
/* SoC Audio Codec device */
@@ -683,7 +698,6 @@ struct snd_soc_codec {
/* runtime */
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
- unsigned int active;
unsigned int cache_bypass:1; /* Suppress access to the cache */
unsigned int suspended:1; /* Codec is in suspend PM state */
unsigned int probed:1; /* Codec has been probed */
@@ -697,7 +711,6 @@ struct snd_soc_codec {
/* codec IO */
void *control_data; /* codec control (i2c/3wire) data */
hw_write_t hw_write;
- unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
void *reg_cache;
@@ -709,7 +722,6 @@ struct snd_soc_codec {
/* dapm */
struct snd_soc_dapm_context dapm;
- unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_codec_root;
@@ -1067,6 +1079,7 @@ struct soc_mixer_control {
int min, max, platform_max;
int reg, rreg;
unsigned int shift, rshift;
+ unsigned int sign_bit;
unsigned int invert:1;
unsigned int autodisable:1;
};
@@ -1085,16 +1098,28 @@ struct soc_mreg_control {
/* enumerated kcontrol */
struct soc_enum {
- unsigned short reg;
- unsigned short reg2;
+ int reg;
unsigned char shift_l;
unsigned char shift_r;
- unsigned int max;
+ unsigned int items;
unsigned int mask;
const char * const *texts;
const unsigned int *values;
};
+/**
+ * snd_soc_component_to_codec() - Casts a component to the CODEC it is embedded in
+ * @component: The component to cast to a CODEC
+ *
+ * This function must only be used on components that are known to be CODECs.
+ * Otherwise the behavior is undefined.
+ */
+static inline struct snd_soc_codec *snd_soc_component_to_codec(
+ struct snd_soc_component *component)
+{
+ return container_of(component, struct snd_soc_codec, component);
+}
+
/* codec IO */
unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
unsigned int snd_soc_write(struct snd_soc_codec *codec,
@@ -1168,11 +1193,51 @@ static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
return 1;
}
+static inline unsigned int snd_soc_enum_val_to_item(struct soc_enum *e,
+ unsigned int val)
+{
+ unsigned int i;
+
+ if (!e->values)
+ return val;
+
+ for (i = 0; i < e->items; i++)
+ if (val == e->values[i])
+ return i;
+
+ return 0;
+}
+
+static inline unsigned int snd_soc_enum_item_to_val(struct soc_enum *e,
+ unsigned int item)
+{
+ if (!e->values)
+ return item;
+
+ return e->values[item];
+}
+
+static inline bool snd_soc_component_is_active(
+ struct snd_soc_component *component)
+{
+ return component->active != 0;
+}
+
+static inline bool snd_soc_codec_is_active(struct snd_soc_codec *codec)
+{
+ return snd_soc_component_is_active(&codec->component);
+}
+
int snd_soc_util_init(void);
void snd_soc_util_exit(void);
int snd_soc_of_parse_card_name(struct snd_soc_card *card,
const char *propname);
+int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
+ const char *propname);
+int snd_soc_of_parse_tdm_slot(struct device_node *np,
+ unsigned int *slots,
+ unsigned int *slot_width);
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname);
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
@@ -1188,4 +1253,15 @@ extern struct dentry *snd_soc_debugfs_root;
extern const struct dev_pm_ops snd_soc_pm_ops;
+/* Helper functions */
+static inline void snd_soc_dapm_mutex_lock(struct snd_soc_dapm_context *dapm)
+{
+ mutex_lock(&dapm->card->dapm_mutex);
+}
+
+static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm)
+{
+ mutex_unlock(&dapm->card->dapm_mutex);
+}
+
#endif
diff --git a/include/target/iscsi/iscsi_transport.h b/include/target/iscsi/iscsi_transport.h
index ae5a17111968..4483fadfa68d 100644
--- a/include/target/iscsi/iscsi_transport.h
+++ b/include/target/iscsi/iscsi_transport.h
@@ -12,6 +12,7 @@ struct iscsit_transport {
int (*iscsit_setup_np)(struct iscsi_np *, struct __kernel_sockaddr_storage *);
int (*iscsit_accept_np)(struct iscsi_np *, struct iscsi_conn *);
void (*iscsit_free_np)(struct iscsi_np *);
+ void (*iscsit_wait_conn)(struct iscsi_conn *);
void (*iscsit_free_conn)(struct iscsi_conn *);
int (*iscsit_get_login_rx)(struct iscsi_conn *, struct iscsi_login *);
int (*iscsit_put_login_tx)(struct iscsi_conn *, struct iscsi_login *, u32);
diff --git a/include/trace/events/bcache.h b/include/trace/events/bcache.h
index 7110897c3dfa..c9c3c044b32f 100644
--- a/include/trace/events/bcache.h
+++ b/include/trace/events/bcache.h
@@ -399,26 +399,43 @@ TRACE_EVENT(bcache_keyscan,
/* Allocator */
-TRACE_EVENT(bcache_alloc_invalidate,
- TP_PROTO(struct cache *ca),
- TP_ARGS(ca),
+TRACE_EVENT(bcache_invalidate,
+ TP_PROTO(struct cache *ca, size_t bucket),
+ TP_ARGS(ca, bucket),
TP_STRUCT__entry(
- __field(unsigned, free )
- __field(unsigned, free_inc )
- __field(unsigned, free_inc_size )
- __field(unsigned, unused )
+ __field(unsigned, sectors )
+ __field(dev_t, dev )
+ __field(__u64, offset )
),
TP_fast_assign(
- __entry->free = fifo_used(&ca->free[RESERVE_NONE]);
- __entry->free_inc = fifo_used(&ca->free_inc);
- __entry->free_inc_size = ca->free_inc.size;
- __entry->unused = fifo_used(&ca->unused);
+ __entry->dev = ca->bdev->bd_dev;
+ __entry->offset = bucket << ca->set->bucket_bits;
+ __entry->sectors = GC_SECTORS_USED(&ca->buckets[bucket]);
),
- TP_printk("free %u free_inc %u/%u unused %u", __entry->free,
- __entry->free_inc, __entry->free_inc_size, __entry->unused)
+ TP_printk("invalidated %u sectors at %d,%d sector=%llu",
+ __entry->sectors, MAJOR(__entry->dev),
+ MINOR(__entry->dev), __entry->offset)
+);
+
+TRACE_EVENT(bcache_alloc,
+ TP_PROTO(struct cache *ca, size_t bucket),
+ TP_ARGS(ca, bucket),
+
+ TP_STRUCT__entry(
+ __field(dev_t, dev )
+ __field(__u64, offset )
+ ),
+
+ TP_fast_assign(
+ __entry->dev = ca->bdev->bd_dev;
+ __entry->offset = bucket << ca->set->bucket_bits;
+ ),
+
+ TP_printk("allocated %d,%d sector=%llu", MAJOR(__entry->dev),
+ MINOR(__entry->dev), __entry->offset)
);
TRACE_EVENT(bcache_alloc_fail,
@@ -426,21 +443,22 @@ TRACE_EVENT(bcache_alloc_fail,
TP_ARGS(ca, reserve),
TP_STRUCT__entry(
+ __field(dev_t, dev )
__field(unsigned, free )
__field(unsigned, free_inc )
- __field(unsigned, unused )
__field(unsigned, blocked )
),
TP_fast_assign(
+ __entry->dev = ca->bdev->bd_dev;
__entry->free = fifo_used(&ca->free[reserve]);
__entry->free_inc = fifo_used(&ca->free_inc);
- __entry->unused = fifo_used(&ca->unused);
__entry->blocked = atomic_read(&ca->set->prio_blocked);
),
- TP_printk("free %u free_inc %u unused %u blocked %u", __entry->free,
- __entry->free_inc, __entry->unused, __entry->blocked)
+ TP_printk("alloc fail %d,%d free %u free_inc %u blocked %u",
+ MAJOR(__entry->dev), MINOR(__entry->dev), __entry->free,
+ __entry->free_inc, __entry->blocked)
);
/* Background writeback */
diff --git a/include/trace/events/block.h b/include/trace/events/block.h
index e76ae19a8d6f..e8a5eca1dbe5 100644
--- a/include/trace/events/block.h
+++ b/include/trace/events/block.h
@@ -132,6 +132,7 @@ DEFINE_EVENT(block_rq_with_error, block_rq_requeue,
* block_rq_complete - block IO operation completed by device driver
* @q: queue containing the block operation request
* @rq: block operations request
+ * @nr_bytes: number of completed bytes
*
* The block_rq_complete tracepoint event indicates that some portion
* of operation request has been completed by the device driver. If
@@ -139,11 +140,37 @@ DEFINE_EVENT(block_rq_with_error, block_rq_requeue,
* do for the request. If @rq->bio is non-NULL then there is
* additional work required to complete the request.
*/
-DEFINE_EVENT(block_rq_with_error, block_rq_complete,
+TRACE_EVENT(block_rq_complete,
- TP_PROTO(struct request_queue *q, struct request *rq),
+ TP_PROTO(struct request_queue *q, struct request *rq,
+ unsigned int nr_bytes),
- TP_ARGS(q, rq)
+ TP_ARGS(q, rq, nr_bytes),
+
+ TP_STRUCT__entry(
+ __field( dev_t, dev )
+ __field( sector_t, sector )
+ __field( unsigned int, nr_sector )
+ __field( int, errors )
+ __array( char, rwbs, RWBS_LEN )
+ __dynamic_array( char, cmd, blk_cmd_buf_len(rq) )
+ ),
+
+ TP_fast_assign(
+ __entry->dev = rq->rq_disk ? disk_devt(rq->rq_disk) : 0;
+ __entry->sector = blk_rq_pos(rq);
+ __entry->nr_sector = nr_bytes >> 9;
+ __entry->errors = rq->errors;
+
+ blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, nr_bytes);
+ blk_dump_cmd(__get_str(cmd), rq);
+ ),
+
+ TP_printk("%d,%d %s (%s) %llu + %u [%d]",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->rwbs, __get_str(cmd),
+ (unsigned long long)__entry->sector,
+ __entry->nr_sector, __entry->errors)
);
DECLARE_EVENT_CLASS(block_rq,
diff --git a/include/trace/events/hswadsp.h b/include/trace/events/hswadsp.h
new file mode 100644
index 000000000000..0f78bbb02002
--- /dev/null
+++ b/include/trace/events/hswadsp.h
@@ -0,0 +1,384 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hswadsp
+
+#if !defined(_TRACE_HSWADSP_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_HSWADSP_H
+
+#include <linux/types.h>
+#include <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+struct sst_hsw;
+struct sst_hsw_stream;
+struct sst_hsw_ipc_stream_free_req;
+struct sst_hsw_ipc_volume_req;
+struct sst_hsw_ipc_stream_alloc_req;
+struct sst_hsw_audio_data_format_ipc;
+struct sst_hsw_ipc_stream_info_reply;
+struct sst_hsw_ipc_device_config_req;
+
+DECLARE_EVENT_CLASS(sst_irq,
+
+ TP_PROTO(uint32_t status, uint32_t mask),
+
+ TP_ARGS(status, mask),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, status )
+ __field( unsigned int, mask )
+ ),
+
+ TP_fast_assign(
+ __entry->status = status;
+ __entry->mask = mask;
+ ),
+
+ TP_printk("status 0x%8.8x mask 0x%8.8x",
+ (unsigned int)__entry->status, (unsigned int)__entry->mask)
+);
+
+DEFINE_EVENT(sst_irq, sst_irq_busy,
+
+ TP_PROTO(unsigned int status, unsigned int mask),
+
+ TP_ARGS(status, mask)
+
+);
+
+DEFINE_EVENT(sst_irq, sst_irq_done,
+
+ TP_PROTO(unsigned int status, unsigned int mask),
+
+ TP_ARGS(status, mask)
+
+);
+
+DECLARE_EVENT_CLASS(ipc,
+
+ TP_PROTO(const char *name, int val),
+
+ TP_ARGS(name, val),
+
+ TP_STRUCT__entry(
+ __string( name, name )
+ __field( unsigned int, val )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, name);
+ __entry->val = val;
+ ),
+
+ TP_printk("%s 0x%8.8x", __get_str(name), (unsigned int)__entry->val)
+
+);
+
+DEFINE_EVENT(ipc, ipc_request,
+
+ TP_PROTO(const char *name, int val),
+
+ TP_ARGS(name, val)
+
+);
+
+DEFINE_EVENT(ipc, ipc_reply,
+
+ TP_PROTO(const char *name, int val),
+
+ TP_ARGS(name, val)
+
+);
+
+DEFINE_EVENT(ipc, ipc_pending_reply,
+
+ TP_PROTO(const char *name, int val),
+
+ TP_ARGS(name, val)
+
+);
+
+DEFINE_EVENT(ipc, ipc_notification,
+
+ TP_PROTO(const char *name, int val),
+
+ TP_ARGS(name, val)
+
+);
+
+DEFINE_EVENT(ipc, ipc_error,
+
+ TP_PROTO(const char *name, int val),
+
+ TP_ARGS(name, val)
+
+);
+
+DECLARE_EVENT_CLASS(stream_position,
+
+ TP_PROTO(unsigned int id, unsigned int pos),
+
+ TP_ARGS(id, pos),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, id )
+ __field( unsigned int, pos )
+ ),
+
+ TP_fast_assign(
+ __entry->id = id;
+ __entry->pos = pos;
+ ),
+
+ TP_printk("id %d position 0x%x",
+ (unsigned int)__entry->id, (unsigned int)__entry->pos)
+);
+
+DEFINE_EVENT(stream_position, stream_read_position,
+
+ TP_PROTO(unsigned int id, unsigned int pos),
+
+ TP_ARGS(id, pos)
+
+);
+
+DEFINE_EVENT(stream_position, stream_write_position,
+
+ TP_PROTO(unsigned int id, unsigned int pos),
+
+ TP_ARGS(id, pos)
+
+);
+
+TRACE_EVENT(hsw_stream_buffer,
+
+ TP_PROTO(struct sst_hsw_stream *stream),
+
+ TP_ARGS(stream),
+
+ TP_STRUCT__entry(
+ __field( int, id )
+ __field( int, pt_addr )
+ __field( int, num_pages )
+ __field( int, ring_size )
+ __field( int, ring_offset )
+ __field( int, first_pfn )
+ ),
+
+ TP_fast_assign(
+ __entry->id = stream->host_id;
+ __entry->pt_addr = stream->request.ringinfo.ring_pt_address;
+ __entry->num_pages = stream->request.ringinfo.num_pages;
+ __entry->ring_size = stream->request.ringinfo.ring_size;
+ __entry->ring_offset = stream->request.ringinfo.ring_offset;
+ __entry->first_pfn = stream->request.ringinfo.ring_first_pfn;
+ ),
+
+ TP_printk("stream %d ring addr 0x%x pages %d size 0x%x offset 0x%x PFN 0x%x",
+ (int) __entry->id, (int)__entry->pt_addr,
+ (int)__entry->num_pages, (int)__entry->ring_size,
+ (int)__entry->ring_offset, (int)__entry->first_pfn)
+);
+
+TRACE_EVENT(hsw_stream_alloc_reply,
+
+ TP_PROTO(struct sst_hsw_stream *stream),
+
+ TP_ARGS(stream),
+
+ TP_STRUCT__entry(
+ __field( int, id )
+ __field( int, stream_id )
+ __field( int, mixer_id )
+ __field( int, peak0 )
+ __field( int, peak1 )
+ __field( int, vol0 )
+ __field( int, vol1 )
+ ),
+
+ TP_fast_assign(
+ __entry->id = stream->host_id;
+ __entry->stream_id = stream->reply.stream_hw_id;
+ __entry->mixer_id = stream->reply.mixer_hw_id;
+ __entry->peak0 = stream->reply.peak_meter_register_address[0];
+ __entry->peak1 = stream->reply.peak_meter_register_address[1];
+ __entry->vol0 = stream->reply.volume_register_address[0];
+ __entry->vol1 = stream->reply.volume_register_address[1];
+ ),
+
+ TP_printk("stream %d hw id %d mixer %d peak 0x%x:0x%x vol 0x%x,0x%x",
+ (int) __entry->id, (int) __entry->stream_id, (int)__entry->mixer_id,
+ (int)__entry->peak0, (int)__entry->peak1,
+ (int)__entry->vol0, (int)__entry->vol1)
+);
+
+TRACE_EVENT(hsw_mixer_info_reply,
+
+ TP_PROTO(struct sst_hsw_ipc_stream_info_reply *reply),
+
+ TP_ARGS(reply),
+
+ TP_STRUCT__entry(
+ __field( int, mixer_id )
+ __field( int, peak0 )
+ __field( int, peak1 )
+ __field( int, vol0 )
+ __field( int, vol1 )
+ ),
+
+ TP_fast_assign(
+ __entry->mixer_id = reply->mixer_hw_id;
+ __entry->peak0 = reply->peak_meter_register_address[0];
+ __entry->peak1 = reply->peak_meter_register_address[1];
+ __entry->vol0 = reply->volume_register_address[0];
+ __entry->vol1 = reply->volume_register_address[1];
+ ),
+
+ TP_printk("mixer id %d peak 0x%x:0x%x vol 0x%x,0x%x",
+ (int)__entry->mixer_id,
+ (int)__entry->peak0, (int)__entry->peak1,
+ (int)__entry->vol0, (int)__entry->vol1)
+);
+
+TRACE_EVENT(hsw_stream_data_format,
+
+ TP_PROTO(struct sst_hsw_stream *stream,
+ struct sst_hsw_audio_data_format_ipc *req),
+
+ TP_ARGS(stream, req),
+
+ TP_STRUCT__entry(
+ __field( uint32_t, id )
+ __field( uint32_t, frequency )
+ __field( uint32_t, bitdepth )
+ __field( uint32_t, map )
+ __field( uint32_t, config )
+ __field( uint32_t, style )
+ __field( uint8_t, ch_num )
+ __field( uint8_t, valid_bit )
+ ),
+
+ TP_fast_assign(
+ __entry->id = stream->host_id;
+ __entry->frequency = req->frequency;
+ __entry->bitdepth = req->bitdepth;
+ __entry->map = req->map;
+ __entry->config = req->config;
+ __entry->style = req->style;
+ __entry->ch_num = req->ch_num;
+ __entry->valid_bit = req->valid_bit;
+ ),
+
+ TP_printk("stream %d freq %d depth %d map 0x%x config 0x%x style 0x%x ch %d bits %d",
+ (int) __entry->id, (uint32_t)__entry->frequency,
+ (uint32_t)__entry->bitdepth, (uint32_t)__entry->map,
+ (uint32_t)__entry->config, (uint32_t)__entry->style,
+ (uint8_t)__entry->ch_num, (uint8_t)__entry->valid_bit)
+);
+
+TRACE_EVENT(hsw_stream_alloc_request,
+
+ TP_PROTO(struct sst_hsw_stream *stream,
+ struct sst_hsw_ipc_stream_alloc_req *req),
+
+ TP_ARGS(stream, req),
+
+ TP_STRUCT__entry(
+ __field( uint32_t, id )
+ __field( uint8_t, path_id )
+ __field( uint8_t, stream_type )
+ __field( uint8_t, format_id )
+ ),
+
+ TP_fast_assign(
+ __entry->id = stream->host_id;
+ __entry->path_id = req->path_id;
+ __entry->stream_type = req->stream_type;
+ __entry->format_id = req->format_id;
+ ),
+
+ TP_printk("stream %d path %d type %d format %d",
+ (int) __entry->id, (uint8_t)__entry->path_id,
+ (uint8_t)__entry->stream_type, (uint8_t)__entry->format_id)
+);
+
+TRACE_EVENT(hsw_stream_free_req,
+
+ TP_PROTO(struct sst_hsw_stream *stream,
+ struct sst_hsw_ipc_stream_free_req *req),
+
+ TP_ARGS(stream, req),
+
+ TP_STRUCT__entry(
+ __field( int, id )
+ __field( int, stream_id )
+ ),
+
+ TP_fast_assign(
+ __entry->id = stream->host_id;
+ __entry->stream_id = req->stream_id;
+ ),
+
+ TP_printk("stream %d hw id %d",
+ (int) __entry->id, (int) __entry->stream_id)
+);
+
+TRACE_EVENT(hsw_volume_req,
+
+ TP_PROTO(struct sst_hsw_stream *stream,
+ struct sst_hsw_ipc_volume_req *req),
+
+ TP_ARGS(stream, req),
+
+ TP_STRUCT__entry(
+ __field( int, id )
+ __field( uint32_t, channel )
+ __field( uint32_t, target_volume )
+ __field( uint64_t, curve_duration )
+ __field( uint32_t, curve_type )
+ ),
+
+ TP_fast_assign(
+ __entry->id = stream->host_id;
+ __entry->channel = req->channel;
+ __entry->target_volume = req->target_volume;
+ __entry->curve_duration = req->curve_duration;
+ __entry->curve_type = req->curve_type;
+ ),
+
+ TP_printk("stream %d chan 0x%x vol %d duration %llu type %d",
+ (int) __entry->id, (uint32_t) __entry->channel,
+ (uint32_t)__entry->target_volume,
+ (uint64_t)__entry->curve_duration,
+ (uint32_t)__entry->curve_type)
+);
+
+TRACE_EVENT(hsw_device_config_req,
+
+ TP_PROTO(struct sst_hsw_ipc_device_config_req *req),
+
+ TP_ARGS(req),
+
+ TP_STRUCT__entry(
+ __field( uint32_t, ssp )
+ __field( uint32_t, clock_freq )
+ __field( uint32_t, mode )
+ __field( uint16_t, clock_divider )
+ ),
+
+ TP_fast_assign(
+ __entry->ssp = req->ssp_interface;
+ __entry->clock_freq = req->clock_frequency;
+ __entry->mode = req->mode;
+ __entry->clock_divider = req->clock_divider;
+ ),
+
+ TP_printk("SSP %d Freq %d mode %d div %d",
+ (uint32_t)__entry->ssp,
+ (uint32_t)__entry->clock_freq, (uint32_t)__entry->mode,
+ (uint32_t)__entry->clock_divider)
+);
+
+#endif /* _TRACE_HSWADSP_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/intel-sst.h b/include/trace/events/intel-sst.h
new file mode 100644
index 000000000000..76c72d3f1902
--- /dev/null
+++ b/include/trace/events/intel-sst.h
@@ -0,0 +1,148 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM intel-sst
+
+#if !defined(_TRACE_INTEL_SST_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_INTEL_SST_H
+
+#include <linux/types.h>
+#include <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(sst_ipc_msg,
+
+ TP_PROTO(unsigned int val),
+
+ TP_ARGS(val),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, val )
+ ),
+
+ TP_fast_assign(
+ __entry->val = val;
+ ),
+
+ TP_printk("0x%8.8x", (unsigned int)__entry->val)
+);
+
+DEFINE_EVENT(sst_ipc_msg, sst_ipc_msg_tx,
+
+ TP_PROTO(unsigned int val),
+
+ TP_ARGS(val)
+
+);
+
+DEFINE_EVENT(sst_ipc_msg, sst_ipc_msg_rx,
+
+ TP_PROTO(unsigned int val),
+
+ TP_ARGS(val)
+
+);
+
+DECLARE_EVENT_CLASS(sst_ipc_mailbox,
+
+ TP_PROTO(unsigned int offset, unsigned int val),
+
+ TP_ARGS(offset, val),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, offset )
+ __field( unsigned int, val )
+ ),
+
+ TP_fast_assign(
+ __entry->offset = offset;
+ __entry->val = val;
+ ),
+
+ TP_printk(" 0x%4.4x = 0x%8.8x",
+ (unsigned int)__entry->offset, (unsigned int)__entry->val)
+);
+
+DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_inbox_rdata,
+
+ TP_PROTO(unsigned int offset, unsigned int val),
+
+ TP_ARGS(offset, val)
+
+);
+
+DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_inbox_wdata,
+
+ TP_PROTO(unsigned int offset, unsigned int val),
+
+ TP_ARGS(offset, val)
+
+);
+
+DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_outbox_rdata,
+
+ TP_PROTO(unsigned int offset, unsigned int val),
+
+ TP_ARGS(offset, val)
+
+);
+
+DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_outbox_wdata,
+
+ TP_PROTO(unsigned int offset, unsigned int val),
+
+ TP_ARGS(offset, val)
+
+);
+
+DECLARE_EVENT_CLASS(sst_ipc_mailbox_info,
+
+ TP_PROTO(unsigned int size),
+
+ TP_ARGS(size),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, size )
+ ),
+
+ TP_fast_assign(
+ __entry->size = size;
+ ),
+
+ TP_printk("Mailbox bytes 0x%8.8x", (unsigned int)__entry->size)
+);
+
+DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_inbox_read,
+
+ TP_PROTO(unsigned int size),
+
+ TP_ARGS(size)
+
+);
+
+DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_inbox_write,
+
+ TP_PROTO(unsigned int size),
+
+ TP_ARGS(size)
+
+);
+
+DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_outbox_read,
+
+ TP_PROTO(unsigned int size),
+
+ TP_ARGS(size)
+
+);
+
+DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_outbox_write,
+
+ TP_PROTO(unsigned int size),
+
+ TP_ARGS(size)
+
+);
+
+#endif /* _TRACE_SST_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index e5bf9a76f169..9a7e08d61258 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -407,8 +407,8 @@ DECLARE_EVENT_CLASS(dev_pm_qos_request,
TP_printk("device=%s type=%s new_value=%d",
__get_str(name),
__print_symbolic(__entry->type,
- { DEV_PM_QOS_LATENCY, "DEV_PM_QOS_LATENCY" },
- { DEV_PM_QOS_FLAGS, "DEV_PM_QOS_FLAGS" }),
+ { DEV_PM_QOS_RESUME_LATENCY, "DEV_PM_QOS_RESUME_LATENCY" },
+ { DEV_PM_QOS_FLAGS, "DEV_PM_QOS_FLAGS" }),
__entry->new_value)
);
diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h
index ddc179b7a105..1fef3e6e9436 100644
--- a/include/trace/events/sunrpc.h
+++ b/include/trace/events/sunrpc.h
@@ -83,7 +83,7 @@ DECLARE_EVENT_CLASS(rpc_task_running,
),
TP_fast_assign(
- __entry->client_id = clnt->cl_clid;
+ __entry->client_id = clnt ? clnt->cl_clid : -1;
__entry->task_id = task->tk_pid;
__entry->action = action;
__entry->runstate = task->tk_runstate;
@@ -91,7 +91,7 @@ DECLARE_EVENT_CLASS(rpc_task_running,
__entry->flags = task->tk_flags;
),
- TP_printk("task:%u@%u flags=%4.4x state=%4.4lx status=%d action=%pf",
+ TP_printk("task:%u@%d flags=%4.4x state=%4.4lx status=%d action=%pf",
__entry->task_id, __entry->client_id,
__entry->flags,
__entry->runstate,
diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h
index c7bbbe794e65..464ea82e10db 100644
--- a/include/trace/events/writeback.h
+++ b/include/trace/events/writeback.h
@@ -287,11 +287,11 @@ TRACE_EVENT(writeback_queue_io,
__field(int, reason)
),
TP_fast_assign(
- unsigned long older_than_this = work->older_than_this;
+ unsigned long *older_than_this = work->older_than_this;
strncpy(__entry->name, dev_name(wb->bdi->dev), 32);
- __entry->older = older_than_this;
+ __entry->older = older_than_this ? *older_than_this : 0;
__entry->age = older_than_this ?
- (jiffies - older_than_this) * 1000 / HZ : -1;
+ (jiffies - *older_than_this) * 1000 / HZ : -1;
__entry->moved = moved;
__entry->reason = work->reason;
),
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 1a8b28db3775..1ee19a24cc5f 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -310,15 +310,12 @@ static struct trace_event_functions ftrace_event_type_funcs_##call = { \
#undef __array
#define __array(type, item, len) \
do { \
- mutex_lock(&event_storage_mutex); \
+ char *type_str = #type"["__stringify(len)"]"; \
BUILD_BUG_ON(len > MAX_FILTER_STR_VAL); \
- snprintf(event_storage, sizeof(event_storage), \
- "%s[%d]", #type, len); \
- ret = trace_define_field(event_call, event_storage, #item, \
+ ret = trace_define_field(event_call, type_str, #item, \
offsetof(typeof(field), item), \
sizeof(field.item), \
is_signed_type(type), FILTER_OTHER); \
- mutex_unlock(&event_storage_mutex); \
if (ret) \
return ret; \
} while (0);
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index a20a9b4d3871..6db66783d268 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -191,6 +191,7 @@ __SYSCALL(__NR_quotactl, sys_quotactl)
/* fs/readdir.c */
#define __NR_getdents64 61
+#define __ARCH_WANT_COMPAT_SYS_GETDENTS64
__SC_COMP(__NR_getdents64, sys_getdents64, compat_sys_getdents64)
/* fs/read_write.c */
@@ -692,9 +693,13 @@ __SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \
__SYSCALL(__NR_kcmp, sys_kcmp)
#define __NR_finit_module 273
__SYSCALL(__NR_finit_module, sys_finit_module)
+#define __NR_sched_setattr 274
+__SYSCALL(__NR_sched_setattr, sys_sched_setattr)
+#define __NR_sched_getattr 275
+__SYSCALL(__NR_sched_getattr, sys_sched_getattr)
#undef __NR_syscalls
-#define __NR_syscalls 274
+#define __NR_syscalls 276
/*
* All syscalls below here should go away really,
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index 3c9a833992e8..b06c8ed68707 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -619,6 +619,8 @@ struct drm_gem_open {
#define DRM_PRIME_CAP_EXPORT 0x2
#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
#define DRM_CAP_ASYNC_PAGE_FLIP 0x7
+#define DRM_CAP_CURSOR_WIDTH 0x8
+#define DRM_CAP_CURSOR_HEIGHT 0x9
/** DRM_IOCTL_GET_CAP ioctl argument type */
struct drm_get_cap {
diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h
index 9971c560ed9a..87792a5fee3b 100644
--- a/include/uapi/drm/vmwgfx_drm.h
+++ b/include/uapi/drm/vmwgfx_drm.h
@@ -87,6 +87,7 @@
#define DRM_VMW_PARAM_MAX_SURF_MEMORY 7
#define DRM_VMW_PARAM_3D_CAPS_SIZE 8
#define DRM_VMW_PARAM_MAX_MOB_MEMORY 9
+#define DRM_VMW_PARAM_MAX_MOB_SIZE 10
/**
* struct drm_vmw_getparam_arg
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 3ce25b5d75a9..6929571b79b0 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -139,6 +139,7 @@ header-y += hid.h
header-y += hiddev.h
header-y += hidraw.h
header-y += hpet.h
+header-y += hyperv.h
header-y += hysdn_if.h
header-y += i2c-dev.h
header-y += i2c.h
diff --git a/include/uapi/linux/hyperv.h b/include/uapi/linux/hyperv.h
new file mode 100644
index 000000000000..9beb7c991638
--- /dev/null
+++ b/include/uapi/linux/hyperv.h
@@ -0,0 +1,390 @@
+/*
+ *
+ * Copyright (c) 2011, Microsoft Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Authors:
+ * Haiyang Zhang <haiyangz@microsoft.com>
+ * Hank Janssen <hjanssen@microsoft.com>
+ * K. Y. Srinivasan <kys@microsoft.com>
+ *
+ */
+
+#ifndef _UAPI_HYPERV_H
+#define _UAPI_HYPERV_H
+
+#include <linux/uuid.h>
+
+/*
+ * Framework version for util services.
+ */
+#define UTIL_FW_MINOR 0
+
+#define UTIL_WS2K8_FW_MAJOR 1
+#define UTIL_WS2K8_FW_VERSION (UTIL_WS2K8_FW_MAJOR << 16 | UTIL_FW_MINOR)
+
+#define UTIL_FW_MAJOR 3
+#define UTIL_FW_VERSION (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR)
+
+
+/*
+ * Implementation of host controlled snapshot of the guest.
+ */
+
+#define VSS_OP_REGISTER 128
+
+enum hv_vss_op {
+ VSS_OP_CREATE = 0,
+ VSS_OP_DELETE,
+ VSS_OP_HOT_BACKUP,
+ VSS_OP_GET_DM_INFO,
+ VSS_OP_BU_COMPLETE,
+ /*
+ * Following operations are only supported with IC version >= 5.0
+ */
+ VSS_OP_FREEZE, /* Freeze the file systems in the VM */
+ VSS_OP_THAW, /* Unfreeze the file systems */
+ VSS_OP_AUTO_RECOVER,
+ VSS_OP_COUNT /* Number of operations, must be last */
+};
+
+
+/*
+ * Header for all VSS messages.
+ */
+struct hv_vss_hdr {
+ __u8 operation;
+ __u8 reserved[7];
+} __attribute__((packed));
+
+
+/*
+ * Flag values for the hv_vss_check_feature. Linux supports only
+ * one value.
+ */
+#define VSS_HBU_NO_AUTO_RECOVERY 0x00000005
+
+struct hv_vss_check_feature {
+ __u32 flags;
+} __attribute__((packed));
+
+struct hv_vss_check_dm_info {
+ __u32 flags;
+} __attribute__((packed));
+
+struct hv_vss_msg {
+ union {
+ struct hv_vss_hdr vss_hdr;
+ int error;
+ };
+ union {
+ struct hv_vss_check_feature vss_cf;
+ struct hv_vss_check_dm_info dm_info;
+ };
+} __attribute__((packed));
+
+/*
+ * Implementation of a host to guest copy facility.
+ */
+
+#define FCOPY_VERSION_0 0
+#define FCOPY_CURRENT_VERSION FCOPY_VERSION_0
+#define W_MAX_PATH 260
+
+enum hv_fcopy_op {
+ START_FILE_COPY = 0,
+ WRITE_TO_FILE,
+ COMPLETE_FCOPY,
+ CANCEL_FCOPY,
+};
+
+struct hv_fcopy_hdr {
+ __u32 operation;
+ uuid_le service_id0; /* currently unused */
+ uuid_le service_id1; /* currently unused */
+} __attribute__((packed));
+
+#define OVER_WRITE 0x1
+#define CREATE_PATH 0x2
+
+struct hv_start_fcopy {
+ struct hv_fcopy_hdr hdr;
+ __u16 file_name[W_MAX_PATH];
+ __u16 path_name[W_MAX_PATH];
+ __u32 copy_flags;
+ __u64 file_size;
+} __attribute__((packed));
+
+/*
+ * The file is chunked into fragments.
+ */
+#define DATA_FRAGMENT (6 * 1024)
+
+struct hv_do_fcopy {
+ struct hv_fcopy_hdr hdr;
+ __u64 offset;
+ __u32 size;
+ __u8 data[DATA_FRAGMENT];
+};
+
+/*
+ * An implementation of HyperV key value pair (KVP) functionality for Linux.
+ *
+ *
+ * Copyright (C) 2010, Novell, Inc.
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
+ *
+ */
+
+/*
+ * Maximum value size - used for both key names and value data, and includes
+ * any applicable NULL terminators.
+ *
+ * Note: This limit is somewhat arbitrary, but falls easily within what is
+ * supported for all native guests (back to Win 2000) and what is reasonable
+ * for the IC KVP exchange functionality. Note that Windows Me/98/95 are
+ * limited to 255 character key names.
+ *
+ * MSDN recommends not storing data values larger than 2048 bytes in the
+ * registry.
+ *
+ * Note: This value is used in defining the KVP exchange message - this value
+ * cannot be modified without affecting the message size and compatibility.
+ */
+
+/*
+ * bytes, including any null terminators
+ */
+#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE (2048)
+
+
+/*
+ * Maximum key size - the registry limit for the length of an entry name
+ * is 256 characters, including the null terminator
+ */
+
+#define HV_KVP_EXCHANGE_MAX_KEY_SIZE (512)
+
+/*
+ * In Linux, we implement the KVP functionality in two components:
+ * 1) The kernel component which is packaged as part of the hv_utils driver
+ * is responsible for communicating with the host and responsible for
+ * implementing the host/guest protocol. 2) A user level daemon that is
+ * responsible for data gathering.
+ *
+ * Host/Guest Protocol: The host iterates over an index and expects the guest
+ * to assign a key name to the index and also return the value corresponding to
+ * the key. The host will have atmost one KVP transaction outstanding at any
+ * given point in time. The host side iteration stops when the guest returns
+ * an error. Microsoft has specified the following mapping of key names to
+ * host specified index:
+ *
+ * Index Key Name
+ * 0 FullyQualifiedDomainName
+ * 1 IntegrationServicesVersion
+ * 2 NetworkAddressIPv4
+ * 3 NetworkAddressIPv6
+ * 4 OSBuildNumber
+ * 5 OSName
+ * 6 OSMajorVersion
+ * 7 OSMinorVersion
+ * 8 OSVersion
+ * 9 ProcessorArchitecture
+ *
+ * The Windows host expects the Key Name and Key Value to be encoded in utf16.
+ *
+ * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the
+ * data gathering functionality in a user mode daemon. The user level daemon
+ * is also responsible for binding the key name to the index as well. The
+ * kernel and user-level daemon communicate using a connector channel.
+ *
+ * The user mode component first registers with the
+ * the kernel component. Subsequently, the kernel component requests, data
+ * for the specified keys. In response to this message the user mode component
+ * fills in the value corresponding to the specified key. We overload the
+ * sequence field in the cn_msg header to define our KVP message types.
+ *
+ *
+ * The kernel component simply acts as a conduit for communication between the
+ * Windows host and the user-level daemon. The kernel component passes up the
+ * index received from the Host to the user-level daemon. If the index is
+ * valid (supported), the corresponding key as well as its
+ * value (both are strings) is returned. If the index is invalid
+ * (not supported), a NULL key string is returned.
+ */
+
+
+/*
+ * Registry value types.
+ */
+
+#define REG_SZ 1
+#define REG_U32 4
+#define REG_U64 8
+
+/*
+ * As we look at expanding the KVP functionality to include
+ * IP injection functionality, we need to maintain binary
+ * compatibility with older daemons.
+ *
+ * The KVP opcodes are defined by the host and it was unfortunate
+ * that I chose to treat the registration operation as part of the
+ * KVP operations defined by the host.
+ * Here is the level of compatibility
+ * (between the user level daemon and the kernel KVP driver) that we
+ * will implement:
+ *
+ * An older daemon will always be supported on a newer driver.
+ * A given user level daemon will require a minimal version of the
+ * kernel driver.
+ * If we cannot handle the version differences, we will fail gracefully
+ * (this can happen when we have a user level daemon that is more
+ * advanced than the KVP driver.
+ *
+ * We will use values used in this handshake for determining if we have
+ * workable user level daemon and the kernel driver. We begin by taking the
+ * registration opcode out of the KVP opcode namespace. We will however,
+ * maintain compatibility with the existing user-level daemon code.
+ */
+
+/*
+ * Daemon code not supporting IP injection (legacy daemon).
+ */
+
+#define KVP_OP_REGISTER 4
+
+/*
+ * Daemon code supporting IP injection.
+ * The KVP opcode field is used to communicate the
+ * registration information; so define a namespace that
+ * will be distinct from the host defined KVP opcode.
+ */
+
+#define KVP_OP_REGISTER1 100
+
+enum hv_kvp_exchg_op {
+ KVP_OP_GET = 0,
+ KVP_OP_SET,
+ KVP_OP_DELETE,
+ KVP_OP_ENUMERATE,
+ KVP_OP_GET_IP_INFO,
+ KVP_OP_SET_IP_INFO,
+ KVP_OP_COUNT /* Number of operations, must be last. */
+};
+
+enum hv_kvp_exchg_pool {
+ KVP_POOL_EXTERNAL = 0,
+ KVP_POOL_GUEST,
+ KVP_POOL_AUTO,
+ KVP_POOL_AUTO_EXTERNAL,
+ KVP_POOL_AUTO_INTERNAL,
+ KVP_POOL_COUNT /* Number of pools, must be last. */
+};
+
+/*
+ * Some Hyper-V status codes.
+ */
+
+#define HV_S_OK 0x00000000
+#define HV_E_FAIL 0x80004005
+#define HV_S_CONT 0x80070103
+#define HV_ERROR_NOT_SUPPORTED 0x80070032
+#define HV_ERROR_MACHINE_LOCKED 0x800704F7
+#define HV_ERROR_DEVICE_NOT_CONNECTED 0x8007048F
+#define HV_INVALIDARG 0x80070057
+#define HV_GUID_NOTFOUND 0x80041002
+
+#define ADDR_FAMILY_NONE 0x00
+#define ADDR_FAMILY_IPV4 0x01
+#define ADDR_FAMILY_IPV6 0x02
+
+#define MAX_ADAPTER_ID_SIZE 128
+#define MAX_IP_ADDR_SIZE 1024
+#define MAX_GATEWAY_SIZE 512
+
+
+struct hv_kvp_ipaddr_value {
+ __u16 adapter_id[MAX_ADAPTER_ID_SIZE];
+ __u8 addr_family;
+ __u8 dhcp_enabled;
+ __u16 ip_addr[MAX_IP_ADDR_SIZE];
+ __u16 sub_net[MAX_IP_ADDR_SIZE];
+ __u16 gate_way[MAX_GATEWAY_SIZE];
+ __u16 dns_addr[MAX_IP_ADDR_SIZE];
+} __attribute__((packed));
+
+
+struct hv_kvp_hdr {
+ __u8 operation;
+ __u8 pool;
+ __u16 pad;
+} __attribute__((packed));
+
+struct hv_kvp_exchg_msg_value {
+ __u32 value_type;
+ __u32 key_size;
+ __u32 value_size;
+ __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+ union {
+ __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+ __u32 value_u32;
+ __u64 value_u64;
+ };
+} __attribute__((packed));
+
+struct hv_kvp_msg_enumerate {
+ __u32 index;
+ struct hv_kvp_exchg_msg_value data;
+} __attribute__((packed));
+
+struct hv_kvp_msg_get {
+ struct hv_kvp_exchg_msg_value data;
+};
+
+struct hv_kvp_msg_set {
+ struct hv_kvp_exchg_msg_value data;
+};
+
+struct hv_kvp_msg_delete {
+ __u32 key_size;
+ __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+};
+
+struct hv_kvp_register {
+ __u8 version[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+};
+
+struct hv_kvp_msg {
+ union {
+ struct hv_kvp_hdr kvp_hdr;
+ int error;
+ };
+ union {
+ struct hv_kvp_msg_get kvp_get;
+ struct hv_kvp_msg_set kvp_set;
+ struct hv_kvp_msg_delete kvp_delete;
+ struct hv_kvp_msg_enumerate kvp_enum_data;
+ struct hv_kvp_ipaddr_value kvp_ip_val;
+ struct hv_kvp_register kvp_register;
+ } body;
+} __attribute__((packed));
+
+struct hv_kvp_ip_msg {
+ __u8 operation;
+ __u8 pool;
+ struct hv_kvp_ipaddr_value kvp_ip_val;
+} __attribute__((packed));
+
+#endif /* _UAPI_HYPERV_H */
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 932d7f2637d6..a8f4ee5d2e82 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -413,6 +413,8 @@ struct kvm_s390_psw {
#define KVM_S390_PROGRAM_INT 0xfffe0001u
#define KVM_S390_SIGP_SET_PREFIX 0xfffe0002u
#define KVM_S390_RESTART 0xfffe0003u
+#define KVM_S390_INT_PFAULT_INIT 0xfffe0004u
+#define KVM_S390_INT_PFAULT_DONE 0xfffe0005u
#define KVM_S390_MCHK 0xfffe1000u
#define KVM_S390_INT_VIRTIO 0xffff2603u
#define KVM_S390_INT_SERVICE 0xffff2401u
@@ -434,6 +436,69 @@ struct kvm_s390_interrupt {
__u64 parm64;
};
+struct kvm_s390_io_info {
+ __u16 subchannel_id;
+ __u16 subchannel_nr;
+ __u32 io_int_parm;
+ __u32 io_int_word;
+};
+
+struct kvm_s390_ext_info {
+ __u32 ext_params;
+ __u32 pad;
+ __u64 ext_params2;
+};
+
+struct kvm_s390_pgm_info {
+ __u64 trans_exc_code;
+ __u64 mon_code;
+ __u64 per_address;
+ __u32 data_exc_code;
+ __u16 code;
+ __u16 mon_class_nr;
+ __u8 per_code;
+ __u8 per_atmid;
+ __u8 exc_access_id;
+ __u8 per_access_id;
+ __u8 op_access_id;
+ __u8 pad[3];
+};
+
+struct kvm_s390_prefix_info {
+ __u32 address;
+};
+
+struct kvm_s390_extcall_info {
+ __u16 code;
+};
+
+struct kvm_s390_emerg_info {
+ __u16 code;
+};
+
+struct kvm_s390_mchk_info {
+ __u64 cr14;
+ __u64 mcic;
+ __u64 failing_storage_address;
+ __u32 ext_damage_code;
+ __u32 pad;
+ __u8 fixed_logout[16];
+};
+
+struct kvm_s390_irq {
+ __u64 type;
+ union {
+ struct kvm_s390_io_info io;
+ struct kvm_s390_ext_info ext;
+ struct kvm_s390_pgm_info pgm;
+ struct kvm_s390_emerg_info emerg;
+ struct kvm_s390_extcall_info extcall;
+ struct kvm_s390_prefix_info prefix;
+ struct kvm_s390_mchk_info mchk;
+ char reserved[64];
+ } u;
+};
+
/* for KVM_SET_GUEST_DEBUG */
#define KVM_GUESTDBG_ENABLE 0x00000001
@@ -675,6 +740,9 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_SPAPR_MULTITCE 94
#define KVM_CAP_EXT_EMUL_CPUID 95
#define KVM_CAP_HYPERV_TIME 96
+#define KVM_CAP_IOAPIC_POLARITY_IGNORED 97
+#define KVM_CAP_ENABLE_CAP_VM 98
+#define KVM_CAP_S390_IRQCHIP 99
#ifdef KVM_CAP_IRQ_ROUTING
@@ -690,9 +758,18 @@ struct kvm_irq_routing_msi {
__u32 pad;
};
+struct kvm_irq_routing_s390_adapter {
+ __u64 ind_addr;
+ __u64 summary_addr;
+ __u64 ind_offset;
+ __u32 summary_offset;
+ __u32 adapter_id;
+};
+
/* gsi routing entry types */
#define KVM_IRQ_ROUTING_IRQCHIP 1
#define KVM_IRQ_ROUTING_MSI 2
+#define KVM_IRQ_ROUTING_S390_ADAPTER 3
struct kvm_irq_routing_entry {
__u32 gsi;
@@ -702,6 +779,7 @@ struct kvm_irq_routing_entry {
union {
struct kvm_irq_routing_irqchip irqchip;
struct kvm_irq_routing_msi msi;
+ struct kvm_irq_routing_s390_adapter adapter;
__u32 pad[8];
} u;
};
@@ -855,6 +933,7 @@ struct kvm_device_attr {
#define KVM_DEV_VFIO_GROUP_ADD 1
#define KVM_DEV_VFIO_GROUP_DEL 2
#define KVM_DEV_TYPE_ARM_VGIC_V2 5
+#define KVM_DEV_TYPE_FLIC 6
/*
* ioctls for VM fds
@@ -1009,6 +1088,10 @@ struct kvm_s390_ucas_mapping {
/* Available with KVM_CAP_DEBUGREGS */
#define KVM_GET_DEBUGREGS _IOR(KVMIO, 0xa1, struct kvm_debugregs)
#define KVM_SET_DEBUGREGS _IOW(KVMIO, 0xa2, struct kvm_debugregs)
+/*
+ * vcpu version available with KVM_ENABLE_CAP
+ * vm version available with KVM_CAP_ENABLE_CAP_VM
+ */
#define KVM_ENABLE_CAP _IOW(KVMIO, 0xa3, struct kvm_enable_cap)
/* Available with KVM_CAP_XSAVE */
#define KVM_GET_XSAVE _IOR(KVMIO, 0xa4, struct kvm_xsave)
diff --git a/include/uapi/linux/spi/spidev.h b/include/uapi/linux/spi/spidev.h
index 52d9ed01855f..dd5f21e75805 100644
--- a/include/uapi/linux/spi/spidev.h
+++ b/include/uapi/linux/spi/spidev.h
@@ -42,6 +42,10 @@
#define SPI_LOOP 0x20
#define SPI_NO_CS 0x40
#define SPI_READY 0x80
+#define SPI_TX_DUAL 0x100
+#define SPI_TX_QUAD 0x200
+#define SPI_RX_DUAL 0x400
+#define SPI_RX_QUAD 0x800
/*---------------------------------------------------------------------------*/
@@ -92,7 +96,9 @@ struct spi_ioc_transfer {
__u16 delay_usecs;
__u8 bits_per_word;
__u8 cs_change;
- __u32 pad;
+ __u8 tx_nbits;
+ __u8 rx_nbits;
+ __u16 pad;
/* If the contents of 'struct spi_ioc_transfer' ever change
* incompatibly, then the ioctl number (currently 0) must change;
@@ -110,7 +116,7 @@ struct spi_ioc_transfer {
#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
-/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */
+/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) (limited to 8 bits) */
#define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8)
#define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8)
@@ -126,6 +132,10 @@ struct spi_ioc_transfer {
#define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32)
#define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32)
+/* Read / Write of the SPI mode field */
+#define SPI_IOC_RD_MODE32 _IOR(SPI_IOC_MAGIC, 5, __u32)
+#define SPI_IOC_WR_MODE32 _IOW(SPI_IOC_MAGIC, 5, __u32)
+
#endif /* SPIDEV_H */
diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h
index d6b01283f85c..2a4b4a72a4f9 100644
--- a/include/uapi/linux/usb/functionfs.h
+++ b/include/uapi/linux/usb/functionfs.h
@@ -10,9 +10,15 @@
enum {
FUNCTIONFS_DESCRIPTORS_MAGIC = 1,
- FUNCTIONFS_STRINGS_MAGIC = 2
+ FUNCTIONFS_STRINGS_MAGIC = 2,
+ FUNCTIONFS_DESCRIPTORS_MAGIC_V2 = 3,
};
+enum functionfs_flags {
+ FUNCTIONFS_HAS_FS_DESC = 1,
+ FUNCTIONFS_HAS_HS_DESC = 2,
+ FUNCTIONFS_HAS_SS_DESC = 4,
+};
#ifndef __KERNEL__
@@ -29,29 +35,39 @@ struct usb_endpoint_descriptor_no_audio {
/*
- * All numbers must be in little endian order.
- */
-
-struct usb_functionfs_descs_head {
- __le32 magic;
- __le32 length;
- __le32 fs_count;
- __le32 hs_count;
-} __attribute__((packed));
-
-/*
* Descriptors format:
*
* | off | name | type | description |
* |-----+-----------+--------------+--------------------------------------|
- * | 0 | magic | LE32 | FUNCTIONFS_{FS,HS}_DESCRIPTORS_MAGIC |
+ * | 0 | magic | LE32 | FUNCTIONFS_DESCRIPTORS_MAGIC_V2 |
+ * | 4 | length | LE32 | length of the whole data chunk |
+ * | 8 | flags | LE32 | combination of functionfs_flags |
+ * | | fs_count | LE32 | number of full-speed descriptors |
+ * | | hs_count | LE32 | number of high-speed descriptors |
+ * | | ss_count | LE32 | number of super-speed descriptors |
+ * | | fs_descrs | Descriptor[] | list of full-speed descriptors |
+ * | | hs_descrs | Descriptor[] | list of high-speed descriptors |
+ * | | ss_descrs | Descriptor[] | list of super-speed descriptors |
+ *
+ * Depending on which flags are set, various fields may be missing in the
+ * structure. Any flags that are not recognised cause the whole block to be
+ * rejected with -ENOSYS.
+ *
+ * Legacy descriptors format:
+ *
+ * | off | name | type | description |
+ * |-----+-----------+--------------+--------------------------------------|
+ * | 0 | magic | LE32 | FUNCTIONFS_DESCRIPTORS_MAGIC |
* | 4 | length | LE32 | length of the whole data chunk |
* | 8 | fs_count | LE32 | number of full-speed descriptors |
* | 12 | hs_count | LE32 | number of high-speed descriptors |
* | 16 | fs_descrs | Descriptor[] | list of full-speed descriptors |
* | | hs_descrs | Descriptor[] | list of high-speed descriptors |
*
- * descs are just valid USB descriptors and have the following format:
+ * All numbers must be in little endian order.
+ *
+ * Descriptor[] is an array of valid USB descriptors which have the following
+ * format:
*
* | off | name | type | description |
* |-----+-----------------+------+--------------------------|
diff --git a/include/uapi/linux/usbdevice_fs.h b/include/uapi/linux/usbdevice_fs.h
index 0c65e4b12617..abe5f4bd4d82 100644
--- a/include/uapi/linux/usbdevice_fs.h
+++ b/include/uapi/linux/usbdevice_fs.h
@@ -102,7 +102,10 @@ struct usbdevfs_urb {
int buffer_length;
int actual_length;
int start_frame;
- int number_of_packets;
+ union {
+ int number_of_packets; /* Only used for isoc urbs */
+ unsigned int stream_id; /* Only used with bulk streams */
+ };
int error_count;
unsigned int signr; /* signal to be sent on completion,
or 0 if none should be sent. */
@@ -144,6 +147,11 @@ struct usbdevfs_disconnect_claim {
char driver[USBDEVFS_MAXDRIVERNAME + 1];
};
+struct usbdevfs_streams {
+ unsigned int num_streams; /* Not used by USBDEVFS_FREE_STREAMS */
+ unsigned int num_eps;
+ unsigned char eps[0];
+};
#define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer)
#define USBDEVFS_CONTROL32 _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
@@ -176,5 +184,7 @@ struct usbdevfs_disconnect_claim {
#define USBDEVFS_RELEASE_PORT _IOR('U', 25, unsigned int)
#define USBDEVFS_GET_CAPABILITIES _IOR('U', 26, __u32)
#define USBDEVFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbdevfs_disconnect_claim)
+#define USBDEVFS_ALLOC_STREAMS _IOR('U', 28, struct usbdevfs_streams)
+#define USBDEVFS_FREE_STREAMS _IOR('U', 29, struct usbdevfs_streams)
#endif /* _UAPI_LINUX_USBDEVICE_FS_H */
diff --git a/include/video/sgivw.h b/include/video/sgivw.h
deleted file mode 100644
index f6aa5692e74b..000000000000
--- a/include/video/sgivw.h
+++ /dev/null
@@ -1,681 +0,0 @@
-/*
- * linux/drivers/video/sgivw.h -- SGI DBE frame buffer device header
- *
- * Copyright (C) 1999 Silicon Graphics, Inc.
- * Jeffrey Newquist, newquist@engr.sgi.som
- *
- * 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.
- */
-
-#ifndef __SGIVWFB_H__
-#define __SGIVWFB_H__
-
-#define DBE_GETREG(reg, dest) ((dest) = DBE_REG_BASE->reg)
-#define DBE_SETREG(reg, src) DBE_REG_BASE->reg = (src)
-#define DBE_IGETREG(reg, idx, dest) ((dest) = DBE_REG_BASE->reg[idx])
-#define DBE_ISETREG(reg, idx, src) (DBE_REG_BASE->reg[idx] = (src))
-
-#define MASK(msb, lsb) ( (((u32)1<<((msb)-(lsb)+1))-1) << (lsb) )
-#define GET(v, msb, lsb) ( ((u32)(v) & MASK(msb,lsb)) >> (lsb) )
-#define SET(v, f, msb, lsb) ( (v) = ((v)&~MASK(msb,lsb)) | (( (u32)(f)<<(lsb) ) & MASK(msb,lsb)) )
-
-#define GET_DBE_FIELD(reg, field, v) GET((v), DBE_##reg##_##field##_MSB, DBE_##reg##_##field##_LSB)
-#define SET_DBE_FIELD(reg, field, v, f) SET((v), (f), DBE_##reg##_##field##_MSB, DBE_##reg##_##field##_LSB)
-
-/* NOTE: All loads/stores must be 32 bits and uncached */
-
-#define DBE_REG_PHYS 0xd0000000
-#define DBE_REG_SIZE 0x01000000
-
-struct asregs {
- volatile u32 ctrlstat; /* 0x000000 general control */
- volatile u32 dotclock; /* 0x000004 dot clock PLL control */
- volatile u32 i2c; /* 0x000008 crt I2C control */
- volatile u32 sysclk; /* 0x00000c system clock PLL control */
- volatile u32 i2cfp; /* 0x000010 flat panel I2C control */
- volatile u32 id; /* 0x000014 device id/chip revision */
- volatile u32 config; /* 0x000018 power on configuration */
- volatile u32 bist; /* 0x00001c internal bist status */
-
- char _pad0[ 0x010000 - 0x000020 ];
-
- volatile u32 vt_xy; /* 0x010000 current dot coords */
- volatile u32 vt_xymax; /* 0x010004 maximum dot coords */
- volatile u32 vt_vsync; /* 0x010008 vsync on/off */
- volatile u32 vt_hsync; /* 0x01000c hsync on/off */
- volatile u32 vt_vblank; /* 0x010010 vblank on/off */
- volatile u32 vt_hblank; /* 0x010014 hblank on/off */
- volatile u32 vt_flags; /* 0x010018 polarity of vt signals */
- volatile u32 vt_f2rf_lock; /* 0x01001c f2rf & framelck y coord */
- volatile u32 vt_intr01; /* 0x010020 intr 0,1 y coords */
- volatile u32 vt_intr23; /* 0x010024 intr 2,3 y coords */
- volatile u32 fp_hdrv; /* 0x010028 flat panel hdrv on/off */
- volatile u32 fp_vdrv; /* 0x01002c flat panel vdrv on/off */
- volatile u32 fp_de; /* 0x010030 flat panel de on/off */
- volatile u32 vt_hpixen; /* 0x010034 intrnl horiz pixel on/off*/
- volatile u32 vt_vpixen; /* 0x010038 intrnl vert pixel on/off */
- volatile u32 vt_hcmap; /* 0x01003c cmap write (horiz) */
- volatile u32 vt_vcmap; /* 0x010040 cmap write (vert) */
- volatile u32 did_start_xy; /* 0x010044 eol/f did/xy reset val */
- volatile u32 crs_start_xy; /* 0x010048 eol/f crs/xy reset val */
- volatile u32 vc_start_xy; /* 0x01004c eol/f vc/xy reset val */
-
- char _pad1[ 0x020000 - 0x010050 ];
-
- volatile u32 ovr_width_tile; /* 0x020000 overlay plane ctrl 0 */
- volatile u32 ovr_inhwctrl; /* 0x020004 overlay plane ctrl 1 */
- volatile u32 ovr_control; /* 0x020008 overlay plane ctrl 1 */
-
- char _pad2[ 0x030000 - 0x02000C ];
-
- volatile u32 frm_size_tile; /* 0x030000 normal plane ctrl 0 */
- volatile u32 frm_size_pixel; /* 0x030004 normal plane ctrl 1 */
- volatile u32 frm_inhwctrl; /* 0x030008 normal plane ctrl 2 */
- volatile u32 frm_control; /* 0x03000C normal plane ctrl 3 */
-
- char _pad3[ 0x040000 - 0x030010 ];
-
- volatile u32 did_inhwctrl; /* 0x040000 DID control */
- volatile u32 did_control; /* 0x040004 DID shadow */
-
- char _pad4[ 0x048000 - 0x040008 ];
-
- volatile u32 mode_regs[32]; /* 0x048000 - 0x04807c WID table */
-
- char _pad5[ 0x050000 - 0x048080 ];
-
- volatile u32 cmap[6144]; /* 0x050000 - 0x055ffc color map */
-
- char _pad6[ 0x058000 - 0x056000 ];
-
- volatile u32 cm_fifo; /* 0x058000 color map fifo status */
-
- char _pad7[ 0x060000 - 0x058004 ];
-
- volatile u32 gmap[256]; /* 0x060000 - 0x0603fc gamma map */
-
- char _pad8[ 0x068000 - 0x060400 ];
-
- volatile u32 gmap10[1024]; /* 0x068000 - 0x068ffc gamma map */
-
- char _pad9[ 0x070000 - 0x069000 ];
-
- volatile u32 crs_pos; /* 0x070000 cusror control 0 */
- volatile u32 crs_ctl; /* 0x070004 cusror control 1 */
- volatile u32 crs_cmap[3]; /* 0x070008 - 0x070010 crs cmap */
-
- char _pad10[ 0x078000 - 0x070014 ];
-
- volatile u32 crs_glyph[64]; /* 0x078000 - 0x0780fc crs glyph */
-
- char _pad11[ 0x080000 - 0x078100 ];
-
- volatile u32 vc_0; /* 0x080000 video capture crtl 0 */
- volatile u32 vc_1; /* 0x080004 video capture crtl 1 */
- volatile u32 vc_2; /* 0x080008 video capture crtl 2 */
- volatile u32 vc_3; /* 0x08000c video capture crtl 3 */
- volatile u32 vc_4; /* 0x080010 video capture crtl 3 */
- volatile u32 vc_5; /* 0x080014 video capture crtl 3 */
- volatile u32 vc_6; /* 0x080018 video capture crtl 3 */
- volatile u32 vc_7; /* 0x08001c video capture crtl 3 */
- volatile u32 vc_8; /* 0x08000c video capture crtl 3 */
-};
-
-/* Bit mask information */
-
-#define DBE_CTRLSTAT_CHIPID_MSB 3
-#define DBE_CTRLSTAT_CHIPID_LSB 0
-#define DBE_CTRLSTAT_SENSE_N_MSB 4
-#define DBE_CTRLSTAT_SENSE_N_LSB 4
-#define DBE_CTRLSTAT_PCLKSEL_MSB 29
-#define DBE_CTRLSTAT_PCLKSEL_LSB 28
-
-#define DBE_DOTCLK_M_MSB 7
-#define DBE_DOTCLK_M_LSB 0
-#define DBE_DOTCLK_N_MSB 13
-#define DBE_DOTCLK_N_LSB 8
-#define DBE_DOTCLK_P_MSB 15
-#define DBE_DOTCLK_P_LSB 14
-#define DBE_DOTCLK_RUN_MSB 20
-#define DBE_DOTCLK_RUN_LSB 20
-
-#define DBE_VT_XY_VT_FREEZE_MSB 31
-#define DBE_VT_XY_VT_FREEZE_LSB 31
-
-#define DBE_FP_VDRV_FP_VDRV_ON_MSB 23
-#define DBE_FP_VDRV_FP_VDRV_ON_LSB 12
-#define DBE_FP_VDRV_FP_VDRV_OFF_MSB 11
-#define DBE_FP_VDRV_FP_VDRV_OFF_LSB 0
-
-#define DBE_FP_HDRV_FP_HDRV_ON_MSB 23
-#define DBE_FP_HDRV_FP_HDRV_ON_LSB 12
-#define DBE_FP_HDRV_FP_HDRV_OFF_MSB 11
-#define DBE_FP_HDRV_FP_HDRV_OFF_LSB 0
-
-#define DBE_FP_DE_FP_DE_ON_MSB 23
-#define DBE_FP_DE_FP_DE_ON_LSB 12
-#define DBE_FP_DE_FP_DE_OFF_MSB 11
-#define DBE_FP_DE_FP_DE_OFF_LSB 0
-
-#define DBE_VT_VSYNC_VT_VSYNC_ON_MSB 23
-#define DBE_VT_VSYNC_VT_VSYNC_ON_LSB 12
-#define DBE_VT_VSYNC_VT_VSYNC_OFF_MSB 11
-#define DBE_VT_VSYNC_VT_VSYNC_OFF_LSB 0
-
-#define DBE_VT_HSYNC_VT_HSYNC_ON_MSB 23
-#define DBE_VT_HSYNC_VT_HSYNC_ON_LSB 12
-#define DBE_VT_HSYNC_VT_HSYNC_OFF_MSB 11
-#define DBE_VT_HSYNC_VT_HSYNC_OFF_LSB 0
-
-#define DBE_VT_VBLANK_VT_VBLANK_ON_MSB 23
-#define DBE_VT_VBLANK_VT_VBLANK_ON_LSB 12
-#define DBE_VT_VBLANK_VT_VBLANK_OFF_MSB 11
-#define DBE_VT_VBLANK_VT_VBLANK_OFF_LSB 0
-
-#define DBE_VT_HBLANK_VT_HBLANK_ON_MSB 23
-#define DBE_VT_HBLANK_VT_HBLANK_ON_LSB 12
-#define DBE_VT_HBLANK_VT_HBLANK_OFF_MSB 11
-#define DBE_VT_HBLANK_VT_HBLANK_OFF_LSB 0
-
-#define DBE_VT_FLAGS_VDRV_INVERT_MSB 0
-#define DBE_VT_FLAGS_VDRV_INVERT_LSB 0
-#define DBE_VT_FLAGS_HDRV_INVERT_MSB 2
-#define DBE_VT_FLAGS_HDRV_INVERT_LSB 2
-
-#define DBE_VT_VCMAP_VT_VCMAP_ON_MSB 23
-#define DBE_VT_VCMAP_VT_VCMAP_ON_LSB 12
-#define DBE_VT_VCMAP_VT_VCMAP_OFF_MSB 11
-#define DBE_VT_VCMAP_VT_VCMAP_OFF_LSB 0
-
-#define DBE_VT_HCMAP_VT_HCMAP_ON_MSB 23
-#define DBE_VT_HCMAP_VT_HCMAP_ON_LSB 12
-#define DBE_VT_HCMAP_VT_HCMAP_OFF_MSB 11
-#define DBE_VT_HCMAP_VT_HCMAP_OFF_LSB 0
-
-#define DBE_VT_XYMAX_VT_MAXX_MSB 11
-#define DBE_VT_XYMAX_VT_MAXX_LSB 0
-#define DBE_VT_XYMAX_VT_MAXY_MSB 23
-#define DBE_VT_XYMAX_VT_MAXY_LSB 12
-
-#define DBE_VT_HPIXEN_VT_HPIXEN_ON_MSB 23
-#define DBE_VT_HPIXEN_VT_HPIXEN_ON_LSB 12
-#define DBE_VT_HPIXEN_VT_HPIXEN_OFF_MSB 11
-#define DBE_VT_HPIXEN_VT_HPIXEN_OFF_LSB 0
-
-#define DBE_VT_VPIXEN_VT_VPIXEN_ON_MSB 23
-#define DBE_VT_VPIXEN_VT_VPIXEN_ON_LSB 12
-#define DBE_VT_VPIXEN_VT_VPIXEN_OFF_MSB 11
-#define DBE_VT_VPIXEN_VT_VPIXEN_OFF_LSB 0
-
-#define DBE_OVR_CONTROL_OVR_DMA_ENABLE_MSB 0
-#define DBE_OVR_CONTROL_OVR_DMA_ENABLE_LSB 0
-
-#define DBE_OVR_INHWCTRL_OVR_DMA_ENABLE_MSB 0
-#define DBE_OVR_INHWCTRL_OVR_DMA_ENABLE_LSB 0
-
-#define DBE_OVR_WIDTH_TILE_OVR_FIFO_RESET_MSB 13
-#define DBE_OVR_WIDTH_TILE_OVR_FIFO_RESET_LSB 13
-
-#define DBE_FRM_CONTROL_FRM_DMA_ENABLE_MSB 0
-#define DBE_FRM_CONTROL_FRM_DMA_ENABLE_LSB 0
-#define DBE_FRM_CONTROL_FRM_TILE_PTR_MSB 31
-#define DBE_FRM_CONTROL_FRM_TILE_PTR_LSB 9
-#define DBE_FRM_CONTROL_FRM_LINEAR_MSB 1
-#define DBE_FRM_CONTROL_FRM_LINEAR_LSB 1
-
-#define DBE_FRM_INHWCTRL_FRM_DMA_ENABLE_MSB 0
-#define DBE_FRM_INHWCTRL_FRM_DMA_ENABLE_LSB 0
-
-#define DBE_FRM_SIZE_TILE_FRM_WIDTH_TILE_MSB 12
-#define DBE_FRM_SIZE_TILE_FRM_WIDTH_TILE_LSB 5
-#define DBE_FRM_SIZE_TILE_FRM_RHS_MSB 4
-#define DBE_FRM_SIZE_TILE_FRM_RHS_LSB 0
-#define DBE_FRM_SIZE_TILE_FRM_DEPTH_MSB 14
-#define DBE_FRM_SIZE_TILE_FRM_DEPTH_LSB 13
-#define DBE_FRM_SIZE_TILE_FRM_FIFO_RESET_MSB 15
-#define DBE_FRM_SIZE_TILE_FRM_FIFO_RESET_LSB 15
-
-#define DBE_FRM_SIZE_PIXEL_FB_HEIGHT_PIX_MSB 31
-#define DBE_FRM_SIZE_PIXEL_FB_HEIGHT_PIX_LSB 16
-
-#define DBE_DID_CONTROL_DID_DMA_ENABLE_MSB 0
-#define DBE_DID_CONTROL_DID_DMA_ENABLE_LSB 0
-#define DBE_DID_INHWCTRL_DID_DMA_ENABLE_MSB 0
-#define DBE_DID_INHWCTRL_DID_DMA_ENABLE_LSB 0
-
-#define DBE_DID_START_XY_DID_STARTY_MSB 23
-#define DBE_DID_START_XY_DID_STARTY_LSB 12
-#define DBE_DID_START_XY_DID_STARTX_MSB 11
-#define DBE_DID_START_XY_DID_STARTX_LSB 0
-
-#define DBE_CRS_START_XY_CRS_STARTY_MSB 23
-#define DBE_CRS_START_XY_CRS_STARTY_LSB 12
-#define DBE_CRS_START_XY_CRS_STARTX_MSB 11
-#define DBE_CRS_START_XY_CRS_STARTX_LSB 0
-
-#define DBE_WID_TYP_MSB 4
-#define DBE_WID_TYP_LSB 2
-#define DBE_WID_BUF_MSB 1
-#define DBE_WID_BUF_LSB 0
-
-#define DBE_VC_START_XY_VC_STARTY_MSB 23
-#define DBE_VC_START_XY_VC_STARTY_LSB 12
-#define DBE_VC_START_XY_VC_STARTX_MSB 11
-#define DBE_VC_START_XY_VC_STARTX_LSB 0
-
-/* Constants */
-
-#define DBE_FRM_DEPTH_8 0
-#define DBE_FRM_DEPTH_16 1
-#define DBE_FRM_DEPTH_32 2
-
-#define DBE_CMODE_I8 0
-#define DBE_CMODE_I12 1
-#define DBE_CMODE_RG3B2 2
-#define DBE_CMODE_RGB4 3
-#define DBE_CMODE_ARGB5 4
-#define DBE_CMODE_RGB8 5
-#define DBE_CMODE_RGBA5 6
-#define DBE_CMODE_RGB10 7
-
-#define DBE_BMODE_BOTH 3
-
-#define DBE_CRS_MAGIC 54
-
-#define DBE_CLOCK_REF_KHZ 27000
-
-/* Config Register (DBE Only) Definitions */
-
-#define DBE_CONFIG_VDAC_ENABLE 0x00000001
-#define DBE_CONFIG_VDAC_GSYNC 0x00000002
-#define DBE_CONFIG_VDAC_PBLANK 0x00000004
-#define DBE_CONFIG_FPENABLE 0x00000008
-#define DBE_CONFIG_LENDIAN 0x00000020
-#define DBE_CONFIG_TILEHIST 0x00000040
-#define DBE_CONFIG_EXT_ADDR 0x00000080
-
-#define DBE_CONFIG_FBDEV ( DBE_CONFIG_VDAC_ENABLE | \
- DBE_CONFIG_VDAC_GSYNC | \
- DBE_CONFIG_VDAC_PBLANK | \
- DBE_CONFIG_LENDIAN | \
- DBE_CONFIG_EXT_ADDR )
-
-/*
- * Available Video Timings and Corresponding Indices
- */
-
-typedef enum {
- DBE_VT_640_480_60,
-
- DBE_VT_800_600_60,
- DBE_VT_800_600_75,
- DBE_VT_800_600_120,
-
- DBE_VT_1024_768_50,
- DBE_VT_1024_768_60,
- DBE_VT_1024_768_75,
- DBE_VT_1024_768_85,
- DBE_VT_1024_768_120,
-
- DBE_VT_1280_1024_50,
- DBE_VT_1280_1024_60,
- DBE_VT_1280_1024_75,
- DBE_VT_1280_1024_85,
-
- DBE_VT_1600_1024_53,
- DBE_VT_1600_1024_60,
-
- DBE_VT_1600_1200_50,
- DBE_VT_1600_1200_60,
- DBE_VT_1600_1200_75,
-
- DBE_VT_1920_1080_50,
- DBE_VT_1920_1080_60,
- DBE_VT_1920_1080_72,
-
- DBE_VT_1920_1200_50,
- DBE_VT_1920_1200_60,
- DBE_VT_1920_1200_66,
-
- DBE_VT_UNKNOWN
-} dbe_timing_t;
-
-
-
-/*
- * Crime Video Timing Data Structure
- */
-
-struct dbe_timing_info
-{
- dbe_timing_t type;
- int flags;
- short width; /* Monitor resolution */
- short height;
- int fields_sec; /* fields/sec (Hz -3 dec. places */
- int cfreq; /* pixel clock frequency (MHz -3 dec. places) */
- short htotal; /* Horizontal total pixels */
- short hblank_start; /* Horizontal blank start */
- short hblank_end; /* Horizontal blank end */
- short hsync_start; /* Horizontal sync start */
- short hsync_end; /* Horizontal sync end */
- short vtotal; /* Vertical total lines */
- short vblank_start; /* Vertical blank start */
- short vblank_end; /* Vertical blank end */
- short vsync_start; /* Vertical sync start */
- short vsync_end; /* Vertical sync end */
- short pll_m; /* PLL M parameter */
- short pll_n; /* PLL P parameter */
- short pll_p; /* PLL N parameter */
-};
-
-/* Defines for dbe_vof_info_t flags */
-
-#define DBE_VOF_UNKNOWNMON 1
-#define DBE_VOF_STEREO 2
-#define DBE_VOF_DO_GENSYNC 4 /* enable incoming sync */
-#define DBE_VOF_SYNC_ON_GREEN 8 /* sync on green */
-#define DBE_VOF_FLATPANEL 0x1000 /* FLATPANEL Timing */
-#define DBE_VOF_MAGICKEY 0x2000 /* Backdoor key */
-
-/*
- * DBE Timing Tables
- */
-
-#ifdef INCLUDE_TIMING_TABLE_DATA
-struct dbe_timing_info dbeVTimings[] = {
- {
- DBE_VT_640_480_60,
- /* flags, width, height, fields_sec, cfreq */
- 0, 640, 480, 59940, 25175,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 800, 640, 800, 656, 752,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 525, 480, 525, 490, 492,
- /* pll_m, pll_n, pll_p */
- 15, 2, 3
- },
-
- {
- DBE_VT_800_600_60,
- /* flags, width, height, fields_sec, cfreq */
- 0, 800, 600, 60317, 40000,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1056, 800, 1056, 840, 968,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 628, 600, 628, 601, 605,
- /* pll_m, pll_n, pll_p */
- 3, 1, 1
- },
-
- {
- DBE_VT_800_600_75,
- /* flags, width, height, fields_sec, cfreq */
- 0, 800, 600, 75000, 49500,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1056, 800, 1056, 816, 896,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 625, 600, 625, 601, 604,
- /* pll_m, pll_n, pll_p */
- 11, 3, 1
- },
-
- {
- DBE_VT_800_600_120,
- /* flags, width, height, fields_sec, cfreq */
- DBE_VOF_STEREO, 800, 600, 119800, 82978,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1040, 800, 1040, 856, 976,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 666, 600, 666, 637, 643,
- /* pll_m, pll_n, pll_p */
- 31, 5, 1
- },
-
- {
- DBE_VT_1024_768_50,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1024, 768, 50000, 54163,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1344, 1024, 1344, 1048, 1184,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 806, 768, 806, 771, 777,
- /* pll_m, pll_n, pll_p */
- 4, 1, 1
- },
-
- {
- DBE_VT_1024_768_60,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1024, 768, 60004, 65000,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1344, 1024, 1344, 1048, 1184,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 806, 768, 806, 771, 777,
- /* pll_m, pll_n, pll_p */
- 12, 5, 0
- },
-
- {
- DBE_VT_1024_768_75,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1024, 768, 75029, 78750,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1312, 1024, 1312, 1040, 1136,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 800, 768, 800, 769, 772,
- /* pll_m, pll_n, pll_p */
- 29, 5, 1
- },
-
- {
- DBE_VT_1024_768_85,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1024, 768, 84997, 94500,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1376, 1024, 1376, 1072, 1168,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 808, 768, 808, 769, 772,
- /* pll_m, pll_n, pll_p */
- 7, 2, 0
- },
-
- {
- DBE_VT_1024_768_120,
- /* flags, width, height, fields_sec, cfreq */
- DBE_VOF_STEREO, 1024, 768, 119800, 133195,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1376, 1024, 1376, 1072, 1168,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 808, 768, 808, 769, 772,
- /* pll_m, pll_n, pll_p */
- 5, 1, 0
- },
-
- {
- DBE_VT_1280_1024_50,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1280, 1024, 50000, 89460,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1680, 1280, 1680, 1360, 1480,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1065, 1024, 1065, 1027, 1030,
- /* pll_m, pll_n, pll_p */
- 10, 3, 0
- },
-
- {
- DBE_VT_1280_1024_60,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1280, 1024, 60020, 108000,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1688, 1280, 1688, 1328, 1440,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1066, 1024, 1066, 1025, 1028,
- /* pll_m, pll_n, pll_p */
- 4, 1, 0
- },
-
- {
- DBE_VT_1280_1024_75,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1280, 1024, 75025, 135000,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1688, 1280, 1688, 1296, 1440,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1066, 1024, 1066, 1025, 1028,
- /* pll_m, pll_n, pll_p */
- 5, 1, 0
- },
-
- {
- DBE_VT_1280_1024_85,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1280, 1024, 85024, 157500,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1728, 1280, 1728, 1344, 1504,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1072, 1024, 1072, 1025, 1028,
- /* pll_m, pll_n, pll_p */
- 29, 5, 0
- },
-
- {
- DBE_VT_1600_1024_53,
- /* flags, width, height, fields_sec, cfreq */
- DBE_VOF_FLATPANEL | DBE_VOF_MAGICKEY,
- 1600, 1024, 53000, 107447,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1900, 1600, 1900, 1630, 1730,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1067, 1024, 1067, 1027, 1030,
- /* pll_m, pll_n, pll_p */
- 4, 1, 0
- },
-
- {
- DBE_VT_1600_1024_60,
- /* flags, width, height, fields_sec, cfreq */
- DBE_VOF_FLATPANEL, 1600, 1024, 60000, 106913,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 1670, 1600, 1670, 1630, 1650,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1067, 1024, 1067, 1027, 1030,
- /* pll_m, pll_n, pll_p */
- 4, 1, 0
- },
-
- {
- DBE_VT_1600_1200_50,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1600, 1200, 50000, 130500,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 2088, 1600, 2088, 1644, 1764,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1250, 1200, 1250, 1205, 1211,
- /* pll_m, pll_n, pll_p */
- 24, 5, 0
- },
-
- {
- DBE_VT_1600_1200_60,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1600, 1200, 59940, 162000,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 2160, 1600, 2160, 1644, 1856,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1250, 1200, 1250, 1201, 1204,
- /* pll_m, pll_n, pll_p */
- 6, 1, 0
- },
-
- {
- DBE_VT_1600_1200_75,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1600, 1200, 75000, 202500,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 2160, 1600, 2160, 1644, 1856,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1250, 1200, 1250, 1201, 1204,
- /* pll_m, pll_n, pll_p */
- 15, 2, 0
- },
-
- {
- DBE_VT_1920_1080_50,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1920, 1080, 50000, 133200,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 2368, 1920, 2368, 1952, 2096,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1125, 1080, 1125, 1083, 1086,
- /* pll_m, pll_n, pll_p */
- 5, 1, 0
- },
-
- {
- DBE_VT_1920_1080_60,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1920, 1080, 59940, 159840,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 2368, 1920, 2368, 1952, 2096,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1125, 1080, 1125, 1083, 1086,
- /* pll_m, pll_n, pll_p */
- 6, 1, 0
- },
-
- {
- DBE_VT_1920_1080_72,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1920, 1080, 72000, 216023,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 2560, 1920, 2560, 1968, 2184,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1172, 1080, 1172, 1083, 1086,
- /* pll_m, pll_n, pll_p */
- 8, 1, 0
- },
-
- {
- DBE_VT_1920_1200_50,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1920, 1200, 50000, 161500,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 2584, 1920, 2584, 1984, 2240,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1250, 1200, 1250, 1203, 1206,
- /* pll_m, pll_n, pll_p */
- 6, 1, 0
- },
-
- {
- DBE_VT_1920_1200_60,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1920, 1200, 59940, 193800,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 2584, 1920, 2584, 1984, 2240,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1250, 1200, 1250, 1203, 1206,
- /* pll_m, pll_n, pll_p */
- 29, 4, 0
- },
-
- {
- DBE_VT_1920_1200_66,
- /* flags, width, height, fields_sec, cfreq */
- 0, 1920, 1200, 66000, 213180,
- /* htotal, hblank_start, hblank_end, hsync_start, hsync_end */
- 2584, 1920, 2584, 1984, 2240,
- /* vtotal, vblank_start, vblank_end, vsync_start, vsync_end */
- 1250, 1200, 1250, 1203, 1206,
- /* pll_m, pll_n, pll_p */
- 8, 1, 0
- }
-};
-
-#endif // INCLUDE_TIMING_TABLE_DATA
-
-#endif // ! __SGIVWFB_H__
diff --git a/init/Kconfig b/init/Kconfig
index 009a797dd242..d56cb03c1b49 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1387,6 +1387,13 @@ config FUTEX
support for "fast userspace mutexes". The resulting kernel may not
run glibc-based applications correctly.
+config HAVE_FUTEX_CMPXCHG
+ bool
+ help
+ Architectures should select this if futex_atomic_cmpxchg_inatomic()
+ is implemented and always working. This removes a couple of runtime
+ checks.
+
config EPOLL
bool "Enable eventpoll support" if EXPERT
default y
diff --git a/init/main.c b/init/main.c
index eb03090cdced..9c7fd4c9249f 100644
--- a/init/main.c
+++ b/init/main.c
@@ -561,7 +561,6 @@ asmlinkage void __init start_kernel(void)
init_timers();
hrtimers_init();
softirq_init();
- acpi_early_init();
timekeeping_init();
time_init();
sched_clock_postinit();
@@ -613,6 +612,7 @@ asmlinkage void __init start_kernel(void)
calibrate_delay();
pidmap_init();
anon_vma_init();
+ acpi_early_init();
#ifdef CONFIG_X86
if (efi_enabled(EFI_RUNTIME_SERVICES))
efi_enter_virtual_mode();
diff --git a/ipc/compat.c b/ipc/compat.c
index f486b0096a67..a4695ada3275 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -430,9 +430,9 @@ COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp,
}
COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
- compat_ssize_t, msgsz, long, msgtyp, int, msgflg)
+ compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg)
{
- return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, msgtyp,
+ return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp,
msgflg, compat_do_msg_fill);
}
@@ -498,7 +498,7 @@ static inline int put_compat_msqid_ds(struct msqid64_ds *m,
return err;
}
-long compat_sys_msgctl(int first, int second, void __user *uptr)
+COMPAT_SYSCALL_DEFINE3(msgctl, int, first, int, second, void __user *, uptr)
{
int err, err2;
struct msqid64_ds m64;
@@ -668,7 +668,7 @@ static inline int put_compat_shm_info(struct shm_info __user *ip,
return err;
}
-long compat_sys_shmctl(int first, int second, void __user *uptr)
+COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr)
{
void __user *p;
struct shmid64_ds s64;
@@ -749,17 +749,12 @@ long compat_sys_shmctl(int first, int second, void __user *uptr)
return err;
}
-long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
- unsigned nsops, const struct compat_timespec __user *timeout)
+COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems,
+ unsigned, nsops,
+ const struct compat_timespec __user *, timeout)
{
- struct timespec __user *ts64 = NULL;
- if (timeout) {
- struct timespec ts;
- ts64 = compat_alloc_user_space(sizeof(*ts64));
- if (get_compat_timespec(&ts, timeout))
- return -EFAULT;
- if (copy_to_user(ts64, &ts, sizeof(ts)))
- return -EFAULT;
- }
+ struct timespec __user *ts64;
+ if (compat_convert_timespec(&ts64, timeout))
+ return -EFAULT;
return sys_semtimedop(semid, tsems, nsops, ts64);
}
diff --git a/ipc/compat_mq.c b/ipc/compat_mq.c
index 63d7c6de335b..90d29f59cac6 100644
--- a/ipc/compat_mq.c
+++ b/ipc/compat_mq.c
@@ -46,9 +46,9 @@ static inline int put_compat_mq_attr(const struct mq_attr *attr,
| __put_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
}
-asmlinkage long compat_sys_mq_open(const char __user *u_name,
- int oflag, compat_mode_t mode,
- struct compat_mq_attr __user *u_attr)
+COMPAT_SYSCALL_DEFINE4(mq_open, const char __user *, u_name,
+ int, oflag, compat_mode_t, mode,
+ struct compat_mq_attr __user *, u_attr)
{
void __user *p = NULL;
if (u_attr && oflag & O_CREAT) {
@@ -64,49 +64,36 @@ asmlinkage long compat_sys_mq_open(const char __user *u_name,
return sys_mq_open(u_name, oflag, mode, p);
}
-static int compat_prepare_timeout(struct timespec __user **p,
- const struct compat_timespec __user *u)
-{
- struct timespec ts;
- if (!u) {
- *p = NULL;
- return 0;
- }
- *p = compat_alloc_user_space(sizeof(ts));
- if (get_compat_timespec(&ts, u) || copy_to_user(*p, &ts, sizeof(ts)))
- return -EFAULT;
- return 0;
-}
-
-asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes,
- const char __user *u_msg_ptr,
- size_t msg_len, unsigned int msg_prio,
- const struct compat_timespec __user *u_abs_timeout)
+COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes,
+ const char __user *, u_msg_ptr,
+ compat_size_t, msg_len, unsigned int, msg_prio,
+ const struct compat_timespec __user *, u_abs_timeout)
{
struct timespec __user *u_ts;
- if (compat_prepare_timeout(&u_ts, u_abs_timeout))
+ if (compat_convert_timespec(&u_ts, u_abs_timeout))
return -EFAULT;
return sys_mq_timedsend(mqdes, u_msg_ptr, msg_len,
msg_prio, u_ts);
}
-asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes,
- char __user *u_msg_ptr,
- size_t msg_len, unsigned int __user *u_msg_prio,
- const struct compat_timespec __user *u_abs_timeout)
+COMPAT_SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes,
+ char __user *, u_msg_ptr,
+ compat_size_t, msg_len, unsigned int __user *, u_msg_prio,
+ const struct compat_timespec __user *, u_abs_timeout)
{
struct timespec __user *u_ts;
- if (compat_prepare_timeout(&u_ts, u_abs_timeout))
+
+ if (compat_convert_timespec(&u_ts, u_abs_timeout))
return -EFAULT;
return sys_mq_timedreceive(mqdes, u_msg_ptr, msg_len,
u_msg_prio, u_ts);
}
-asmlinkage long compat_sys_mq_notify(mqd_t mqdes,
- const struct compat_sigevent __user *u_notification)
+COMPAT_SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
+ const struct compat_sigevent __user *, u_notification)
{
struct sigevent __user *p = NULL;
if (u_notification) {
@@ -122,9 +109,9 @@ asmlinkage long compat_sys_mq_notify(mqd_t mqdes,
return sys_mq_notify(mqdes, p);
}
-asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes,
- const struct compat_mq_attr __user *u_mqstat,
- struct compat_mq_attr __user *u_omqstat)
+COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
+ const struct compat_mq_attr __user *, u_mqstat,
+ struct compat_mq_attr __user *, u_omqstat)
{
struct mq_attr mqstat;
struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p));
diff --git a/ipc/mq_sysctl.c b/ipc/mq_sysctl.c
index 383d638340b8..5bb8bfe67149 100644
--- a/ipc/mq_sysctl.c
+++ b/ipc/mq_sysctl.c
@@ -22,6 +22,16 @@ static void *get_mq(ctl_table *table)
return which;
}
+static int proc_mq_dointvec(ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ struct ctl_table mq_table;
+ memcpy(&mq_table, table, sizeof(mq_table));
+ mq_table.data = get_mq(table);
+
+ return proc_dointvec(&mq_table, write, buffer, lenp, ppos);
+}
+
static int proc_mq_dointvec_minmax(ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
@@ -33,12 +43,10 @@ static int proc_mq_dointvec_minmax(ctl_table *table, int write,
lenp, ppos);
}
#else
+#define proc_mq_dointvec NULL
#define proc_mq_dointvec_minmax NULL
#endif
-static int msg_queues_limit_min = MIN_QUEUESMAX;
-static int msg_queues_limit_max = HARD_QUEUESMAX;
-
static int msg_max_limit_min = MIN_MSGMAX;
static int msg_max_limit_max = HARD_MSGMAX;
@@ -51,9 +59,7 @@ static ctl_table mq_sysctls[] = {
.data = &init_ipc_ns.mq_queues_max,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = proc_mq_dointvec_minmax,
- .extra1 = &msg_queues_limit_min,
- .extra2 = &msg_queues_limit_max,
+ .proc_handler = proc_mq_dointvec,
},
{
.procname = "msg_max",
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index ccf1f9fd263a..c3b31179122c 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -433,9 +433,9 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry,
error = -EACCES;
goto out_unlock;
}
- if (ipc_ns->mq_queues_count >= HARD_QUEUESMAX ||
- (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max &&
- !capable(CAP_SYS_RESOURCE))) {
+
+ if (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max &&
+ !capable(CAP_SYS_RESOURCE)) {
error = -ENOSPC;
goto out_unlock;
}
diff --git a/ipc/msg.c b/ipc/msg.c
index 245db1140ad6..649853105a5d 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -901,6 +901,8 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
return -EINVAL;
if (msgflg & MSG_COPY) {
+ if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT))
+ return -EINVAL;
copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
if (IS_ERR(copy))
return PTR_ERR(copy);
diff --git a/kernel/Makefile b/kernel/Makefile
index bc010ee272b6..f2a8b6246ce9 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -18,11 +18,13 @@ CFLAGS_REMOVE_cgroup-debug.o = -pg
CFLAGS_REMOVE_irq_work.o = -pg
endif
+# cond_syscall is currently not LTO compatible
+CFLAGS_sys_ni.o = $(DISABLE_LTO)
+
obj-y += sched/
obj-y += locking/
obj-y += power/
obj-y += printk/
-obj-y += cpu/
obj-y += irq/
obj-y += rcu/
@@ -93,6 +95,7 @@ obj-$(CONFIG_PADATA) += padata.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o
+obj-$(CONFIG_TORTURE_TEST) += torture.o
$(obj)/configs.o: $(obj)/config_data.h
diff --git a/kernel/audit.c b/kernel/audit.c
index 34c5a2310fbf..95a20f3f52f1 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -182,7 +182,7 @@ struct audit_buffer {
struct audit_reply {
__u32 portid;
- pid_t pid;
+ struct net *net;
struct sk_buff *skb;
};
@@ -500,7 +500,7 @@ int audit_send_list(void *_dest)
{
struct audit_netlink_list *dest = _dest;
struct sk_buff *skb;
- struct net *net = get_net_ns_by_pid(dest->pid);
+ struct net *net = dest->net;
struct audit_net *aunet = net_generic(net, audit_net_id);
/* wait for parent to finish and send an ACK */
@@ -510,6 +510,7 @@ int audit_send_list(void *_dest)
while ((skb = __skb_dequeue(&dest->q)) != NULL)
netlink_unicast(aunet->nlsk, skb, dest->portid, 0);
+ put_net(net);
kfree(dest);
return 0;
@@ -543,7 +544,7 @@ out_kfree_skb:
static int audit_send_reply_thread(void *arg)
{
struct audit_reply *reply = (struct audit_reply *)arg;
- struct net *net = get_net_ns_by_pid(reply->pid);
+ struct net *net = reply->net;
struct audit_net *aunet = net_generic(net, audit_net_id);
mutex_lock(&audit_cmd_mutex);
@@ -552,12 +553,13 @@ static int audit_send_reply_thread(void *arg)
/* Ignore failure. It'll only happen if the sender goes away,
because our timeout is set to infinite. */
netlink_unicast(aunet->nlsk , reply->skb, reply->portid, 0);
+ put_net(net);
kfree(reply);
return 0;
}
/**
* audit_send_reply - send an audit reply message via netlink
- * @portid: netlink port to which to send reply
+ * @request_skb: skb of request we are replying to (used to target the reply)
* @seq: sequence number
* @type: audit message type
* @done: done (last) flag
@@ -568,9 +570,11 @@ static int audit_send_reply_thread(void *arg)
* Allocates an skb, builds the netlink message, and sends it to the port id.
* No failure notifications.
*/
-static void audit_send_reply(__u32 portid, int seq, int type, int done,
+static void audit_send_reply(struct sk_buff *request_skb, int seq, int type, int done,
int multi, const void *payload, int size)
{
+ u32 portid = NETLINK_CB(request_skb).portid;
+ struct net *net = sock_net(NETLINK_CB(request_skb).sk);
struct sk_buff *skb;
struct task_struct *tsk;
struct audit_reply *reply = kmalloc(sizeof(struct audit_reply),
@@ -583,8 +587,8 @@ static void audit_send_reply(__u32 portid, int seq, int type, int done,
if (!skb)
goto out;
+ reply->net = get_net(net);
reply->portid = portid;
- reply->pid = task_pid_vnr(current);
reply->skb = skb;
tsk = kthread_run(audit_send_reply_thread, reply, "audit_send_reply");
@@ -604,9 +608,19 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
int err = 0;
/* Only support the initial namespaces for now. */
+ /*
+ * We return ECONNREFUSED because it tricks userspace into thinking
+ * that audit was not configured into the kernel. Lots of users
+ * configure their PAM stack (because that's what the distro does)
+ * to reject login if unable to send messages to audit. If we return
+ * ECONNREFUSED the PAM stack thinks the kernel does not have audit
+ * configured in and will let login proceed. If we return EPERM
+ * userspace will reject all logins. This should be removed when we
+ * support non init namespaces!!
+ */
if ((current_user_ns() != &init_user_ns) ||
(task_active_pid_ns(current) != &init_pid_ns))
- return -EPERM;
+ return -ECONNREFUSED;
switch (msg_type) {
case AUDIT_LIST:
@@ -673,8 +687,7 @@ static int audit_get_feature(struct sk_buff *skb)
seq = nlmsg_hdr(skb)->nlmsg_seq;
- audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0,
- &af, sizeof(af));
+ audit_send_reply(skb, seq, AUDIT_GET, 0, 0, &af, sizeof(af));
return 0;
}
@@ -794,8 +807,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
s.backlog = skb_queue_len(&audit_skb_queue);
s.version = AUDIT_VERSION_LATEST;
s.backlog_wait_time = audit_backlog_wait_time;
- audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0,
- &s, sizeof(s));
+ audit_send_reply(skb, seq, AUDIT_GET, 0, 0, &s, sizeof(s));
break;
}
case AUDIT_SET: {
@@ -905,7 +917,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
seq, data, nlmsg_len(nlh));
break;
case AUDIT_LIST_RULES:
- err = audit_list_rules_send(NETLINK_CB(skb).portid, seq);
+ err = audit_list_rules_send(skb, seq);
break;
case AUDIT_TRIM:
audit_trim_trees();
@@ -970,8 +982,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
memcpy(sig_data->ctx, ctx, len);
security_release_secctx(ctx, len);
}
- audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_SIGNAL_INFO,
- 0, 0, sig_data, sizeof(*sig_data) + len);
+ audit_send_reply(skb, seq, AUDIT_SIGNAL_INFO, 0, 0,
+ sig_data, sizeof(*sig_data) + len);
kfree(sig_data);
break;
case AUDIT_TTY_GET: {
@@ -983,8 +995,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
s.log_passwd = tsk->signal->audit_tty_log_passwd;
spin_unlock(&tsk->sighand->siglock);
- audit_send_reply(NETLINK_CB(skb).portid, seq,
- AUDIT_TTY_GET, 0, 0, &s, sizeof(s));
+ audit_send_reply(skb, seq, AUDIT_TTY_GET, 0, 0, &s, sizeof(s));
break;
}
case AUDIT_TTY_SET: {
diff --git a/kernel/audit.h b/kernel/audit.h
index 57cc64d67718..8df132214606 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -247,7 +247,7 @@ extern void audit_panic(const char *message);
struct audit_netlink_list {
__u32 portid;
- pid_t pid;
+ struct net *net;
struct sk_buff_head q;
};
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 67ccf0e7cca9..135944a7b28a 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -916,7 +916,7 @@ static int audit_tree_handle_event(struct fsnotify_group *group,
struct fsnotify_mark *inode_mark,
struct fsnotify_mark *vfsmount_mark,
u32 mask, void *data, int data_type,
- const unsigned char *file_name)
+ const unsigned char *file_name, u32 cookie)
{
return 0;
}
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 2596fac5dcb4..70b4554d2fbe 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -471,7 +471,7 @@ static int audit_watch_handle_event(struct fsnotify_group *group,
struct fsnotify_mark *inode_mark,
struct fsnotify_mark *vfsmount_mark,
u32 mask, void *data, int data_type,
- const unsigned char *dname)
+ const unsigned char *dname, u32 cookie)
{
struct inode *inode;
struct audit_parent *parent;
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 14a78cca384e..92062fd6cc8c 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -29,6 +29,8 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/security.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
#include "audit.h"
/*
@@ -1065,11 +1067,13 @@ int audit_rule_change(int type, __u32 portid, int seq, void *data,
/**
* audit_list_rules_send - list the audit rules
- * @portid: target portid for netlink audit messages
+ * @request_skb: skb of request we are replying to (used to target the reply)
* @seq: netlink audit message sequence (serial) number
*/
-int audit_list_rules_send(__u32 portid, int seq)
+int audit_list_rules_send(struct sk_buff *request_skb, int seq)
{
+ u32 portid = NETLINK_CB(request_skb).portid;
+ struct net *net = sock_net(NETLINK_CB(request_skb).sk);
struct task_struct *tsk;
struct audit_netlink_list *dest;
int err = 0;
@@ -1083,8 +1087,8 @@ int audit_list_rules_send(__u32 portid, int seq)
dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL);
if (!dest)
return -ENOMEM;
+ dest->net = get_net(net);
dest->portid = portid;
- dest->pid = task_pid_vnr(current);
skb_queue_head_init(&dest->q);
mutex_lock(&audit_filter_mutex);
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index e2f46ba37f72..0c753ddd223b 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -886,7 +886,9 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
* per-subsystem and moved to css->id so that lookups are
* successful until the target css is released.
*/
+ mutex_lock(&cgroup_mutex);
idr_remove(&cgrp->root->cgroup_idr, cgrp->id);
+ mutex_unlock(&cgroup_mutex);
cgrp->id = -1;
call_rcu(&cgrp->rcu_head, cgroup_free_rcu);
@@ -1566,10 +1568,10 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
mutex_lock(&cgroup_mutex);
mutex_lock(&cgroup_root_mutex);
- root_cgrp->id = idr_alloc(&root->cgroup_idr, root_cgrp,
- 0, 1, GFP_KERNEL);
- if (root_cgrp->id < 0)
+ ret = idr_alloc(&root->cgroup_idr, root_cgrp, 0, 1, GFP_KERNEL);
+ if (ret < 0)
goto unlock_drop;
+ root_cgrp->id = ret;
/* Check for name clashes with existing mounts */
ret = -EBUSY;
@@ -2763,10 +2765,7 @@ static int cgroup_cfts_commit(struct cftype *cfts, bool is_add)
*/
update_before = cgroup_serial_nr_next;
- mutex_unlock(&cgroup_mutex);
-
/* add/rm files for all cgroups created before */
- rcu_read_lock();
css_for_each_descendant_pre(css, cgroup_css(root, ss)) {
struct cgroup *cgrp = css->cgroup;
@@ -2775,23 +2774,19 @@ static int cgroup_cfts_commit(struct cftype *cfts, bool is_add)
inode = cgrp->dentry->d_inode;
dget(cgrp->dentry);
- rcu_read_unlock();
-
dput(prev);
prev = cgrp->dentry;
+ mutex_unlock(&cgroup_mutex);
mutex_lock(&inode->i_mutex);
mutex_lock(&cgroup_mutex);
if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp))
ret = cgroup_addrm_files(cgrp, cfts, is_add);
- mutex_unlock(&cgroup_mutex);
mutex_unlock(&inode->i_mutex);
-
- rcu_read_lock();
if (ret)
break;
}
- rcu_read_unlock();
+ mutex_unlock(&cgroup_mutex);
dput(prev);
deactivate_super(sb);
return ret;
@@ -2910,9 +2905,14 @@ static void cgroup_enable_task_cg_lists(void)
* We should check if the process is exiting, otherwise
* it will race with cgroup_exit() in that the list
* entry won't be deleted though the process has exited.
+ * Do it while holding siglock so that we don't end up
+ * racing against cgroup_exit().
*/
+ spin_lock_irq(&p->sighand->siglock);
if (!(p->flags & PF_EXITING) && list_empty(&p->cg_list))
list_add(&p->cg_list, &task_css_set(p)->tasks);
+ spin_unlock_irq(&p->sighand->siglock);
+
task_unlock(p);
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
@@ -4112,17 +4112,17 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss)
err = percpu_ref_init(&css->refcnt, css_release);
if (err)
- goto err_free;
+ goto err_free_css;
init_css(css, ss, cgrp);
err = cgroup_populate_dir(cgrp, 1 << ss->subsys_id);
if (err)
- goto err_free;
+ goto err_free_percpu_ref;
err = online_css(css);
if (err)
- goto err_free;
+ goto err_clear_dir;
dget(cgrp->dentry);
css_get(css->parent);
@@ -4138,8 +4138,11 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss)
return 0;
-err_free:
+err_clear_dir:
+ cgroup_clear_dir(css->cgroup, 1 << css->ss->subsys_id);
+err_free_percpu_ref:
percpu_ref_cancel_init(&css->refcnt);
+err_free_css:
ss->css_free(css);
return err;
}
@@ -4158,7 +4161,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
struct cgroup *cgrp;
struct cgroup_name *name;
struct cgroupfs_root *root = parent->root;
- int ssid, err = 0;
+ int ssid, err;
struct cgroup_subsys *ss;
struct super_block *sb = root->sb;
@@ -4168,19 +4171,13 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
return -ENOMEM;
name = cgroup_alloc_name(dentry);
- if (!name)
+ if (!name) {
+ err = -ENOMEM;
goto err_free_cgrp;
+ }
rcu_assign_pointer(cgrp->name, name);
/*
- * Temporarily set the pointer to NULL, so idr_find() won't return
- * a half-baked cgroup.
- */
- cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL);
- if (cgrp->id < 0)
- goto err_free_name;
-
- /*
* Only live parents can have children. Note that the liveliness
* check isn't strictly necessary because cgroup_mkdir() and
* cgroup_rmdir() are fully synchronized by i_mutex; however, do it
@@ -4189,7 +4186,17 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
*/
if (!cgroup_lock_live_group(parent)) {
err = -ENODEV;
- goto err_free_id;
+ goto err_free_name;
+ }
+
+ /*
+ * Temporarily set the pointer to NULL, so idr_find() won't return
+ * a half-baked cgroup.
+ */
+ cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL);
+ if (cgrp->id < 0) {
+ err = -ENOMEM;
+ goto err_unlock;
}
/* Grab a reference on the superblock so the hierarchy doesn't
@@ -4221,7 +4228,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
*/
err = cgroup_create_file(dentry, S_IFDIR | mode, sb);
if (err < 0)
- goto err_unlock;
+ goto err_free_id;
lockdep_assert_held(&dentry->d_inode->i_mutex);
cgrp->serial_nr = cgroup_serial_nr_next++;
@@ -4257,12 +4264,12 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
return 0;
-err_unlock:
- mutex_unlock(&cgroup_mutex);
- /* Release the reference count that we took on the superblock */
- deactivate_super(sb);
err_free_id:
idr_remove(&root->cgroup_idr, cgrp->id);
+ /* Release the reference count that we took on the superblock */
+ deactivate_super(sb);
+err_unlock:
+ mutex_unlock(&cgroup_mutex);
err_free_name:
kfree(rcu_dereference_raw(cgrp->name));
err_free_cgrp:
diff --git a/kernel/compat.c b/kernel/compat.c
index 0a09e481b70b..e40b0430b562 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -30,28 +30,6 @@
#include <asm/uaccess.h>
-/*
- * Get/set struct timeval with struct timespec on the native side
- */
-static int compat_get_timeval_convert(struct timespec *o,
- struct compat_timeval __user *i)
-{
- long usec;
-
- if (get_user(o->tv_sec, &i->tv_sec) ||
- get_user(usec, &i->tv_usec))
- return -EFAULT;
- o->tv_nsec = usec * 1000;
- return 0;
-}
-
-static int compat_put_timeval_convert(struct compat_timeval __user *o,
- struct timeval *i)
-{
- return (put_user(i->tv_sec, &o->tv_sec) ||
- put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0;
-}
-
static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp)
{
memset(txc, 0, sizeof(struct timex));
@@ -110,13 +88,13 @@ static int compat_put_timex(struct compat_timex __user *utp, struct timex *txc)
return 0;
}
-asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
- struct timezone __user *tz)
+COMPAT_SYSCALL_DEFINE2(gettimeofday, struct compat_timeval __user *, tv,
+ struct timezone __user *, tz)
{
if (tv) {
struct timeval ktv;
do_gettimeofday(&ktv);
- if (compat_put_timeval_convert(tv, &ktv))
+ if (compat_put_timeval(&ktv, tv))
return -EFAULT;
}
if (tz) {
@@ -127,62 +105,61 @@ asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
return 0;
}
-asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
- struct timezone __user *tz)
+COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv,
+ struct timezone __user *, tz)
{
- struct timespec kts;
- struct timezone ktz;
+ struct timeval user_tv;
+ struct timespec new_ts;
+ struct timezone new_tz;
if (tv) {
- if (compat_get_timeval_convert(&kts, tv))
+ if (compat_get_timeval(&user_tv, tv))
return -EFAULT;
+ new_ts.tv_sec = user_tv.tv_sec;
+ new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC;
}
if (tz) {
- if (copy_from_user(&ktz, tz, sizeof(ktz)))
+ if (copy_from_user(&new_tz, tz, sizeof(*tz)))
return -EFAULT;
}
- return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
+ return do_sys_settimeofday(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
}
-int get_compat_timeval(struct timeval *tv, const struct compat_timeval __user *ctv)
+static int __compat_get_timeval(struct timeval *tv, const struct compat_timeval __user *ctv)
{
return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) ||
__get_user(tv->tv_sec, &ctv->tv_sec) ||
__get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
}
-EXPORT_SYMBOL_GPL(get_compat_timeval);
-int put_compat_timeval(const struct timeval *tv, struct compat_timeval __user *ctv)
+static int __compat_put_timeval(const struct timeval *tv, struct compat_timeval __user *ctv)
{
return (!access_ok(VERIFY_WRITE, ctv, sizeof(*ctv)) ||
__put_user(tv->tv_sec, &ctv->tv_sec) ||
__put_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
}
-EXPORT_SYMBOL_GPL(put_compat_timeval);
-int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
+static int __compat_get_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
{
return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) ||
__get_user(ts->tv_sec, &cts->tv_sec) ||
__get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
}
-EXPORT_SYMBOL_GPL(get_compat_timespec);
-int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user *cts)
+static int __compat_put_timespec(const struct timespec *ts, struct compat_timespec __user *cts)
{
return (!access_ok(VERIFY_WRITE, cts, sizeof(*cts)) ||
__put_user(ts->tv_sec, &cts->tv_sec) ||
__put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
}
-EXPORT_SYMBOL_GPL(put_compat_timespec);
int compat_get_timeval(struct timeval *tv, const void __user *utv)
{
if (COMPAT_USE_64BIT_TIME)
return copy_from_user(tv, utv, sizeof *tv) ? -EFAULT : 0;
else
- return get_compat_timeval(tv, utv);
+ return __compat_get_timeval(tv, utv);
}
EXPORT_SYMBOL_GPL(compat_get_timeval);
@@ -191,7 +168,7 @@ int compat_put_timeval(const struct timeval *tv, void __user *utv)
if (COMPAT_USE_64BIT_TIME)
return copy_to_user(utv, tv, sizeof *tv) ? -EFAULT : 0;
else
- return put_compat_timeval(tv, utv);
+ return __compat_put_timeval(tv, utv);
}
EXPORT_SYMBOL_GPL(compat_put_timeval);
@@ -200,7 +177,7 @@ int compat_get_timespec(struct timespec *ts, const void __user *uts)
if (COMPAT_USE_64BIT_TIME)
return copy_from_user(ts, uts, sizeof *ts) ? -EFAULT : 0;
else
- return get_compat_timespec(ts, uts);
+ return __compat_get_timespec(ts, uts);
}
EXPORT_SYMBOL_GPL(compat_get_timespec);
@@ -209,10 +186,33 @@ int compat_put_timespec(const struct timespec *ts, void __user *uts)
if (COMPAT_USE_64BIT_TIME)
return copy_to_user(uts, ts, sizeof *ts) ? -EFAULT : 0;
else
- return put_compat_timespec(ts, uts);
+ return __compat_put_timespec(ts, uts);
}
EXPORT_SYMBOL_GPL(compat_put_timespec);
+int compat_convert_timespec(struct timespec __user **kts,
+ const void __user *cts)
+{
+ struct timespec ts;
+ struct timespec __user *uts;
+
+ if (!cts || COMPAT_USE_64BIT_TIME) {
+ *kts = (struct timespec __user *)cts;
+ return 0;
+ }
+
+ uts = compat_alloc_user_space(sizeof(ts));
+ if (!uts)
+ return -EFAULT;
+ if (compat_get_timespec(&ts, cts))
+ return -EFAULT;
+ if (copy_to_user(uts, &ts, sizeof(ts)))
+ return -EFAULT;
+
+ *kts = uts;
+ return 0;
+}
+
static long compat_nanosleep_restart(struct restart_block *restart)
{
struct compat_timespec __user *rmtp;
@@ -229,21 +229,21 @@ static long compat_nanosleep_restart(struct restart_block *restart)
if (ret) {
rmtp = restart->nanosleep.compat_rmtp;
- if (rmtp && put_compat_timespec(&rmt, rmtp))
+ if (rmtp && compat_put_timespec(&rmt, rmtp))
return -EFAULT;
}
return ret;
}
-asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
- struct compat_timespec __user *rmtp)
+COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,
+ struct compat_timespec __user *, rmtp)
{
struct timespec tu, rmt;
mm_segment_t oldfs;
long ret;
- if (get_compat_timespec(&tu, rqtp))
+ if (compat_get_timespec(&tu, rqtp))
return -EFAULT;
if (!timespec_valid(&tu))
@@ -263,7 +263,7 @@ asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
restart->fn = compat_nanosleep_restart;
restart->nanosleep.compat_rmtp = rmtp;
- if (rmtp && put_compat_timespec(&rmt, rmtp))
+ if (rmtp && compat_put_timespec(&rmt, rmtp))
return -EFAULT;
}
@@ -328,7 +328,7 @@ static compat_clock_t clock_t_to_compat_clock_t(clock_t x)
return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));
}
-asmlinkage long compat_sys_times(struct compat_tms __user *tbuf)
+COMPAT_SYSCALL_DEFINE1(times, struct compat_tms __user *, tbuf)
{
if (tbuf) {
struct tms tms;
@@ -354,7 +354,7 @@ asmlinkage long compat_sys_times(struct compat_tms __user *tbuf)
* types that can be passed to put_user()/get_user().
*/
-asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set)
+COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set)
{
old_sigset_t s;
long ret;
@@ -424,8 +424,8 @@ COMPAT_SYSCALL_DEFINE3(sigprocmask, int, how,
#endif
-asmlinkage long compat_sys_setrlimit(unsigned int resource,
- struct compat_rlimit __user *rlim)
+COMPAT_SYSCALL_DEFINE2(setrlimit, unsigned int, resource,
+ struct compat_rlimit __user *, rlim)
{
struct rlimit r;
@@ -443,15 +443,15 @@ asmlinkage long compat_sys_setrlimit(unsigned int resource,
#ifdef COMPAT_RLIM_OLD_INFINITY
-asmlinkage long compat_sys_old_getrlimit(unsigned int resource,
- struct compat_rlimit __user *rlim)
+COMPAT_SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
+ struct compat_rlimit __user *, rlim)
{
struct rlimit r;
int ret;
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
- ret = sys_old_getrlimit(resource, &r);
+ ret = sys_old_getrlimit(resource, (struct rlimit __user *)&r);
set_fs(old_fs);
if (!ret) {
@@ -470,8 +470,8 @@ asmlinkage long compat_sys_old_getrlimit(unsigned int resource,
#endif
-asmlinkage long compat_sys_getrlimit(unsigned int resource,
- struct compat_rlimit __user *rlim)
+COMPAT_SYSCALL_DEFINE2(getrlimit, unsigned int, resource,
+ struct compat_rlimit __user *, rlim)
{
struct rlimit r;
int ret;
@@ -596,9 +596,9 @@ static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr,
return compat_get_bitmap(k, user_mask_ptr, len * 8);
}
-asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid,
- unsigned int len,
- compat_ulong_t __user *user_mask_ptr)
+COMPAT_SYSCALL_DEFINE3(sched_setaffinity, compat_pid_t, pid,
+ unsigned int, len,
+ compat_ulong_t __user *, user_mask_ptr)
{
cpumask_var_t new_mask;
int retval;
@@ -616,8 +616,8 @@ out:
return retval;
}
-asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,
- compat_ulong_t __user *user_mask_ptr)
+COMPAT_SYSCALL_DEFINE3(sched_getaffinity, compat_pid_t, pid, unsigned int, len,
+ compat_ulong_t __user *, user_mask_ptr)
{
int ret;
cpumask_var_t mask;
@@ -647,8 +647,8 @@ asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,
int get_compat_itimerspec(struct itimerspec *dst,
const struct compat_itimerspec __user *src)
{
- if (get_compat_timespec(&dst->it_interval, &src->it_interval) ||
- get_compat_timespec(&dst->it_value, &src->it_value))
+ if (__compat_get_timespec(&dst->it_interval, &src->it_interval) ||
+ __compat_get_timespec(&dst->it_value, &src->it_value))
return -EFAULT;
return 0;
}
@@ -656,15 +656,15 @@ int get_compat_itimerspec(struct itimerspec *dst,
int put_compat_itimerspec(struct compat_itimerspec __user *dst,
const struct itimerspec *src)
{
- if (put_compat_timespec(&src->it_interval, &dst->it_interval) ||
- put_compat_timespec(&src->it_value, &dst->it_value))
+ if (__compat_put_timespec(&src->it_interval, &dst->it_interval) ||
+ __compat_put_timespec(&src->it_value, &dst->it_value))
return -EFAULT;
return 0;
}
-long compat_sys_timer_create(clockid_t which_clock,
- struct compat_sigevent __user *timer_event_spec,
- timer_t __user *created_timer_id)
+COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_clock,
+ struct compat_sigevent __user *, timer_event_spec,
+ timer_t __user *, created_timer_id)
{
struct sigevent __user *event = NULL;
@@ -680,9 +680,9 @@ long compat_sys_timer_create(clockid_t which_clock,
return sys_timer_create(which_clock, event, created_timer_id);
}
-long compat_sys_timer_settime(timer_t timer_id, int flags,
- struct compat_itimerspec __user *new,
- struct compat_itimerspec __user *old)
+COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
+ struct compat_itimerspec __user *, new,
+ struct compat_itimerspec __user *, old)
{
long err;
mm_segment_t oldfs;
@@ -703,8 +703,8 @@ long compat_sys_timer_settime(timer_t timer_id, int flags,
return err;
}
-long compat_sys_timer_gettime(timer_t timer_id,
- struct compat_itimerspec __user *setting)
+COMPAT_SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id,
+ struct compat_itimerspec __user *, setting)
{
long err;
mm_segment_t oldfs;
@@ -720,14 +720,14 @@ long compat_sys_timer_gettime(timer_t timer_id,
return err;
}
-long compat_sys_clock_settime(clockid_t which_clock,
- struct compat_timespec __user *tp)
+COMPAT_SYSCALL_DEFINE2(clock_settime, clockid_t, which_clock,
+ struct compat_timespec __user *, tp)
{
long err;
mm_segment_t oldfs;
struct timespec ts;
- if (get_compat_timespec(&ts, tp))
+ if (compat_get_timespec(&ts, tp))
return -EFAULT;
oldfs = get_fs();
set_fs(KERNEL_DS);
@@ -737,8 +737,8 @@ long compat_sys_clock_settime(clockid_t which_clock,
return err;
}
-long compat_sys_clock_gettime(clockid_t which_clock,
- struct compat_timespec __user *tp)
+COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock,
+ struct compat_timespec __user *, tp)
{
long err;
mm_segment_t oldfs;
@@ -749,13 +749,13 @@ long compat_sys_clock_gettime(clockid_t which_clock,
err = sys_clock_gettime(which_clock,
(struct timespec __user *) &ts);
set_fs(oldfs);
- if (!err && put_compat_timespec(&ts, tp))
+ if (!err && compat_put_timespec(&ts, tp))
return -EFAULT;
return err;
}
-long compat_sys_clock_adjtime(clockid_t which_clock,
- struct compat_timex __user *utp)
+COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock,
+ struct compat_timex __user *, utp)
{
struct timex txc;
mm_segment_t oldfs;
@@ -777,8 +777,8 @@ long compat_sys_clock_adjtime(clockid_t which_clock,
return ret;
}
-long compat_sys_clock_getres(clockid_t which_clock,
- struct compat_timespec __user *tp)
+COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock,
+ struct compat_timespec __user *, tp)
{
long err;
mm_segment_t oldfs;
@@ -789,7 +789,7 @@ long compat_sys_clock_getres(clockid_t which_clock,
err = sys_clock_getres(which_clock,
(struct timespec __user *) &ts);
set_fs(oldfs);
- if (!err && tp && put_compat_timespec(&ts, tp))
+ if (!err && tp && compat_put_timespec(&ts, tp))
return -EFAULT;
return err;
}
@@ -799,7 +799,7 @@ static long compat_clock_nanosleep_restart(struct restart_block *restart)
long err;
mm_segment_t oldfs;
struct timespec tu;
- struct compat_timespec *rmtp = restart->nanosleep.compat_rmtp;
+ struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp;
restart->nanosleep.rmtp = (struct timespec __user *) &tu;
oldfs = get_fs();
@@ -808,7 +808,7 @@ static long compat_clock_nanosleep_restart(struct restart_block *restart)
set_fs(oldfs);
if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
- put_compat_timespec(&tu, rmtp))
+ compat_put_timespec(&tu, rmtp))
return -EFAULT;
if (err == -ERESTART_RESTARTBLOCK) {
@@ -818,16 +818,16 @@ static long compat_clock_nanosleep_restart(struct restart_block *restart)
return err;
}
-long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
- struct compat_timespec __user *rqtp,
- struct compat_timespec __user *rmtp)
+COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags,
+ struct compat_timespec __user *, rqtp,
+ struct compat_timespec __user *, rmtp)
{
long err;
mm_segment_t oldfs;
struct timespec in, out;
struct restart_block *restart;
- if (get_compat_timespec(&in, rqtp))
+ if (compat_get_timespec(&in, rqtp))
return -EFAULT;
oldfs = get_fs();
@@ -838,7 +838,7 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
set_fs(oldfs);
if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
- put_compat_timespec(&out, rmtp))
+ compat_put_timespec(&out, rmtp))
return -EFAULT;
if (err == -ERESTART_RESTARTBLOCK) {
@@ -1010,7 +1010,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
/* compat_time_t is a 32 bit "long" and needs to get converted. */
-asmlinkage long compat_sys_time(compat_time_t __user * tloc)
+COMPAT_SYSCALL_DEFINE1(time, compat_time_t __user *, tloc)
{
compat_time_t i;
struct timeval tv;
@@ -1026,7 +1026,7 @@ asmlinkage long compat_sys_time(compat_time_t __user * tloc)
return i;
}
-asmlinkage long compat_sys_stime(compat_time_t __user *tptr)
+COMPAT_SYSCALL_DEFINE1(stime, compat_time_t __user *, tptr)
{
struct timespec tv;
int err;
@@ -1046,7 +1046,7 @@ asmlinkage long compat_sys_stime(compat_time_t __user *tptr)
#endif /* __ARCH_WANT_COMPAT_SYS_TIME */
-asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
+COMPAT_SYSCALL_DEFINE1(adjtimex, struct compat_timex __user *, utp)
{
struct timex txc;
int err, ret;
@@ -1065,11 +1065,11 @@ asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
}
#ifdef CONFIG_NUMA
-asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages,
- compat_uptr_t __user *pages32,
- const int __user *nodes,
- int __user *status,
- int flags)
+COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages,
+ compat_uptr_t __user *, pages32,
+ const int __user *, nodes,
+ int __user *, status,
+ int, flags)
{
const void __user * __user *pages;
int i;
@@ -1085,10 +1085,10 @@ asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages,
return sys_move_pages(pid, nr_pages, pages, nodes, status, flags);
}
-asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
- compat_ulong_t maxnode,
- const compat_ulong_t __user *old_nodes,
- const compat_ulong_t __user *new_nodes)
+COMPAT_SYSCALL_DEFINE4(migrate_pages, compat_pid_t, pid,
+ compat_ulong_t, maxnode,
+ const compat_ulong_t __user *, old_nodes,
+ const compat_ulong_t __user *, new_nodes)
{
unsigned long __user *old = NULL;
unsigned long __user *new = NULL;
@@ -1130,7 +1130,7 @@ COMPAT_SYSCALL_DEFINE2(sched_rr_get_interval,
set_fs(KERNEL_DS);
ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
set_fs(old_fs);
- if (put_compat_timespec(&t, interval))
+ if (compat_put_timespec(&t, interval))
return -EFAULT;
return ret;
}
diff --git a/kernel/cpu/Makefile b/kernel/cpu/Makefile
deleted file mode 100644
index 59ab052ef7a0..000000000000
--- a/kernel/cpu/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-y = idle.o
diff --git a/kernel/cpu/idle.c b/kernel/cpu/idle.c
deleted file mode 100644
index 277f494c2a9a..000000000000
--- a/kernel/cpu/idle.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Generic entry point for the idle threads
- */
-#include <linux/sched.h>
-#include <linux/cpu.h>
-#include <linux/tick.h>
-#include <linux/mm.h>
-#include <linux/stackprotector.h>
-
-#include <asm/tlb.h>
-
-#include <trace/events/power.h>
-
-static int __read_mostly cpu_idle_force_poll;
-
-void cpu_idle_poll_ctrl(bool enable)
-{
- if (enable) {
- cpu_idle_force_poll++;
- } else {
- cpu_idle_force_poll--;
- WARN_ON_ONCE(cpu_idle_force_poll < 0);
- }
-}
-
-#ifdef CONFIG_GENERIC_IDLE_POLL_SETUP
-static int __init cpu_idle_poll_setup(char *__unused)
-{
- cpu_idle_force_poll = 1;
- return 1;
-}
-__setup("nohlt", cpu_idle_poll_setup);
-
-static int __init cpu_idle_nopoll_setup(char *__unused)
-{
- cpu_idle_force_poll = 0;
- return 1;
-}
-__setup("hlt", cpu_idle_nopoll_setup);
-#endif
-
-static inline int cpu_idle_poll(void)
-{
- rcu_idle_enter();
- trace_cpu_idle_rcuidle(0, smp_processor_id());
- local_irq_enable();
- while (!tif_need_resched())
- cpu_relax();
- trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
- rcu_idle_exit();
- return 1;
-}
-
-/* Weak implementations for optional arch specific functions */
-void __weak arch_cpu_idle_prepare(void) { }
-void __weak arch_cpu_idle_enter(void) { }
-void __weak arch_cpu_idle_exit(void) { }
-void __weak arch_cpu_idle_dead(void) { }
-void __weak arch_cpu_idle(void)
-{
- cpu_idle_force_poll = 1;
- local_irq_enable();
-}
-
-/*
- * Generic idle loop implementation
- */
-static void cpu_idle_loop(void)
-{
- while (1) {
- tick_nohz_idle_enter();
-
- while (!need_resched()) {
- check_pgt_cache();
- rmb();
-
- if (cpu_is_offline(smp_processor_id()))
- arch_cpu_idle_dead();
-
- local_irq_disable();
- arch_cpu_idle_enter();
-
- /*
- * In poll mode we reenable interrupts and spin.
- *
- * Also if we detected in the wakeup from idle
- * path that the tick broadcast device expired
- * for us, we don't want to go deep idle as we
- * know that the IPI is going to arrive right
- * away
- */
- if (cpu_idle_force_poll || tick_check_broadcast_expired()) {
- cpu_idle_poll();
- } else {
- if (!current_clr_polling_and_test()) {
- stop_critical_timings();
- rcu_idle_enter();
- arch_cpu_idle();
- WARN_ON_ONCE(irqs_disabled());
- rcu_idle_exit();
- start_critical_timings();
- } else {
- local_irq_enable();
- }
- __current_set_polling();
- }
- arch_cpu_idle_exit();
- }
-
- /*
- * Since we fell out of the loop above, we know
- * TIF_NEED_RESCHED must be set, propagate it into
- * PREEMPT_NEED_RESCHED.
- *
- * This is required because for polling idle loops we will
- * not have had an IPI to fold the state for us.
- */
- preempt_set_need_resched();
- tick_nohz_idle_exit();
- schedule_preempt_disabled();
- }
-}
-
-void cpu_startup_entry(enum cpuhp_state state)
-{
- /*
- * This #ifdef needs to die, but it's too late in the cycle to
- * make this generic (arm and sh have never invoked the canary
- * init for the non boot cpus!). Will be fixed in 3.11
- */
-#ifdef CONFIG_X86
- /*
- * If we're the non-boot CPU, nothing set the stack canary up
- * for us. The boot CPU already has it initialized but no harm
- * in doing it again. This is a good place for updating it, as
- * we wont ever return from this function (so the invalid
- * canaries already on the stack wont ever trigger).
- */
- boot_init_stack_canary();
-#endif
- __current_set_polling();
- arch_cpu_idle_prepare();
- cpu_idle_loop();
-}
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 4410ac6a55f1..e6b1b66afe52 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -974,12 +974,6 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
* Temporarilly set tasks mems_allowed to target nodes of migration,
* so that the migration code can allocate pages on these nodes.
*
- * Call holding cpuset_mutex, so current's cpuset won't change
- * during this call, as manage_mutex holds off any cpuset_attach()
- * calls. Therefore we don't need to take task_lock around the
- * call to guarantee_online_mems(), as we know no one is changing
- * our task's cpuset.
- *
* While the mm_struct we are migrating is typically from some
* other task, the task_struct mems_allowed that we are hacking
* is for our current task, which must allocate new pages for that
@@ -996,8 +990,10 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
do_migrate_pages(mm, from, to, MPOL_MF_MOVE_ALL);
+ rcu_read_lock();
mems_cs = effective_nodemask_cpuset(task_cs(tsk));
guarantee_online_mems(mems_cs, &tsk->mems_allowed);
+ rcu_read_unlock();
}
/*
@@ -2486,9 +2482,9 @@ int __cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
task_lock(current);
cs = nearest_hardwall_ancestor(task_cs(current));
+ allowed = node_isset(node, cs->mems_allowed);
task_unlock(current);
- allowed = node_isset(node, cs->mems_allowed);
mutex_unlock(&callback_mutex);
return allowed;
}
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
index 334b3980ffc1..99982a70ddad 100644
--- a/kernel/debug/debug_core.c
+++ b/kernel/debug/debug_core.c
@@ -1035,7 +1035,7 @@ int dbg_io_get_char(void)
* otherwise as a quick means to stop program execution and "break" into
* the debugger.
*/
-void kgdb_breakpoint(void)
+noinline void kgdb_breakpoint(void)
{
atomic_inc(&kgdb_setting_breakpoint);
wmb(); /* Sync point before breakpoint */
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 56003c6edfd3..661951ab8ae7 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -231,11 +231,29 @@ int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write,
#define NR_ACCUMULATED_SAMPLES 128
static DEFINE_PER_CPU(u64, running_sample_length);
-void perf_sample_event_took(u64 sample_len_ns)
+static void perf_duration_warn(struct irq_work *w)
{
+ u64 allowed_ns = ACCESS_ONCE(perf_sample_allowed_ns);
u64 avg_local_sample_len;
u64 local_samples_len;
+
+ local_samples_len = __get_cpu_var(running_sample_length);
+ avg_local_sample_len = local_samples_len/NR_ACCUMULATED_SAMPLES;
+
+ printk_ratelimited(KERN_WARNING
+ "perf interrupt took too long (%lld > %lld), lowering "
+ "kernel.perf_event_max_sample_rate to %d\n",
+ avg_local_sample_len, allowed_ns >> 1,
+ sysctl_perf_event_sample_rate);
+}
+
+static DEFINE_IRQ_WORK(perf_duration_work, perf_duration_warn);
+
+void perf_sample_event_took(u64 sample_len_ns)
+{
u64 allowed_ns = ACCESS_ONCE(perf_sample_allowed_ns);
+ u64 avg_local_sample_len;
+ u64 local_samples_len;
if (allowed_ns == 0)
return;
@@ -263,13 +281,14 @@ void perf_sample_event_took(u64 sample_len_ns)
sysctl_perf_event_sample_rate = max_samples_per_tick * HZ;
perf_sample_period_ns = NSEC_PER_SEC / sysctl_perf_event_sample_rate;
- printk_ratelimited(KERN_WARNING
- "perf samples too long (%lld > %lld), lowering "
- "kernel.perf_event_max_sample_rate to %d\n",
- avg_local_sample_len, allowed_ns,
- sysctl_perf_event_sample_rate);
-
update_perf_cpu_limits();
+
+ if (!irq_work_queue(&perf_duration_work)) {
+ early_printk("perf interrupt took too long (%lld > %lld), lowering "
+ "kernel.perf_event_max_sample_rate to %d\n",
+ avg_local_sample_len, allowed_ns >> 1,
+ sysctl_perf_event_sample_rate);
+ }
}
static atomic64_t perf_event_id;
@@ -1714,7 +1733,7 @@ group_sched_in(struct perf_event *group_event,
struct perf_event_context *ctx)
{
struct perf_event *event, *partial_group = NULL;
- struct pmu *pmu = group_event->pmu;
+ struct pmu *pmu = ctx->pmu;
u64 now = ctx->time;
bool simulate = false;
@@ -2563,8 +2582,6 @@ static void perf_branch_stack_sched_in(struct task_struct *prev,
if (cpuctx->ctx.nr_branch_stack > 0
&& pmu->flush_branch_stack) {
- pmu = cpuctx->ctx.pmu;
-
perf_ctx_lock(cpuctx, cpuctx->task_ctx);
perf_pmu_disable(pmu);
@@ -6294,7 +6311,7 @@ static int perf_event_idx_default(struct perf_event *event)
* Ensures all contexts with the same task_ctx_nr have the same
* pmu_cpu_context too.
*/
-static void *find_pmu_context(int ctxn)
+static struct perf_cpu_context __percpu *find_pmu_context(int ctxn)
{
struct pmu *pmu;
@@ -7856,14 +7873,14 @@ static void perf_pmu_rotate_stop(struct pmu *pmu)
static void __perf_event_exit_context(void *__info)
{
struct perf_event_context *ctx = __info;
- struct perf_event *event, *tmp;
+ struct perf_event *event;
perf_pmu_rotate_stop(ctx->pmu);
- list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry)
- __perf_remove_from_context(event);
- list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, group_entry)
+ rcu_read_lock();
+ list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
__perf_remove_from_context(event);
+ rcu_read_unlock();
}
static void perf_event_exit_cpu_context(int cpu)
@@ -7887,11 +7904,11 @@ static void perf_event_exit_cpu(int cpu)
{
struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
+ perf_event_exit_cpu_context(cpu);
+
mutex_lock(&swhash->hlist_mutex);
swevent_hlist_release(swhash);
mutex_unlock(&swhash->hlist_mutex);
-
- perf_event_exit_cpu_context(cpu);
}
#else
static inline void perf_event_exit_cpu(int cpu) { }
diff --git a/kernel/extable.c b/kernel/extable.c
index 763faf037ec1..d8a6446adbcb 100644
--- a/kernel/extable.c
+++ b/kernel/extable.c
@@ -36,7 +36,7 @@ extern struct exception_table_entry __start___ex_table[];
extern struct exception_table_entry __stop___ex_table[];
/* Cleared by build time tools if the table is already sorted. */
-u32 __initdata main_extable_sort_needed = 1;
+u32 __initdata __visible main_extable_sort_needed = 1;
/* Sort the kernel's built-in exception table */
void __init sort_main_extable(void)
diff --git a/kernel/fork.c b/kernel/fork.c
index a17621c6cd42..332688e5e7b4 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -237,6 +237,7 @@ void __put_task_struct(struct task_struct *tsk)
WARN_ON(atomic_read(&tsk->usage));
WARN_ON(tsk == current);
+ task_numa_free(tsk);
security_task_free(tsk);
exit_creds(tsk);
delayacct_tsk_free(tsk);
diff --git a/kernel/futex.c b/kernel/futex.c
index 44a1261cb9ff..67dacaf93e56 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -157,7 +157,9 @@
* enqueue.
*/
+#ifndef CONFIG_HAVE_FUTEX_CMPXCHG
int __read_mostly futex_cmpxchg_enabled;
+#endif
/*
* Futex flags used to encode options to functions and preserve them across
@@ -234,6 +236,7 @@ static const struct futex_q futex_q_init = {
* waiting on a futex.
*/
struct futex_hash_bucket {
+ atomic_t waiters;
spinlock_t lock;
struct plist_head chain;
} ____cacheline_aligned_in_smp;
@@ -253,22 +256,37 @@ static inline void futex_get_mm(union futex_key *key)
smp_mb__after_atomic_inc();
}
-static inline bool hb_waiters_pending(struct futex_hash_bucket *hb)
+/*
+ * Reflects a new waiter being added to the waitqueue.
+ */
+static inline void hb_waiters_inc(struct futex_hash_bucket *hb)
{
#ifdef CONFIG_SMP
+ atomic_inc(&hb->waiters);
/*
- * Tasks trying to enter the critical region are most likely
- * potential waiters that will be added to the plist. Ensure
- * that wakers won't miss to-be-slept tasks in the window between
- * the wait call and the actual plist_add.
+ * Full barrier (A), see the ordering comment above.
*/
- if (spin_is_locked(&hb->lock))
- return true;
- smp_rmb(); /* Make sure we check the lock state first */
+ smp_mb__after_atomic_inc();
+#endif
+}
+
+/*
+ * Reflects a waiter being removed from the waitqueue by wakeup
+ * paths.
+ */
+static inline void hb_waiters_dec(struct futex_hash_bucket *hb)
+{
+#ifdef CONFIG_SMP
+ atomic_dec(&hb->waiters);
+#endif
+}
- return !plist_head_empty(&hb->chain);
+static inline int hb_waiters_pending(struct futex_hash_bucket *hb)
+{
+#ifdef CONFIG_SMP
+ return atomic_read(&hb->waiters);
#else
- return true;
+ return 1;
#endif
}
@@ -954,6 +972,7 @@ static void __unqueue_futex(struct futex_q *q)
hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock);
plist_del(&q->list, &hb->chain);
+ hb_waiters_dec(hb);
}
/*
@@ -1257,7 +1276,9 @@ void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1,
*/
if (likely(&hb1->chain != &hb2->chain)) {
plist_del(&q->list, &hb1->chain);
+ hb_waiters_dec(hb1);
plist_add(&q->list, &hb2->chain);
+ hb_waiters_inc(hb2);
q->lock_ptr = &hb2->lock;
}
get_futex_key_refs(key2);
@@ -1600,6 +1621,17 @@ static inline struct futex_hash_bucket *queue_lock(struct futex_q *q)
struct futex_hash_bucket *hb;
hb = hash_futex(&q->key);
+
+ /*
+ * Increment the counter before taking the lock so that
+ * a potential waker won't miss a to-be-slept task that is
+ * waiting for the spinlock. This is safe as all queue_lock()
+ * users end up calling queue_me(). Similarly, for housekeeping,
+ * decrement the counter at queue_unlock() when some error has
+ * occurred and we don't end up adding the task to the list.
+ */
+ hb_waiters_inc(hb);
+
q->lock_ptr = &hb->lock;
spin_lock(&hb->lock); /* implies MB (A) */
@@ -1611,6 +1643,7 @@ queue_unlock(struct futex_hash_bucket *hb)
__releases(&hb->lock)
{
spin_unlock(&hb->lock);
+ hb_waiters_dec(hb);
}
/**
@@ -2342,6 +2375,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
* Unqueue the futex_q and determine which it was.
*/
plist_del(&q->list, &hb->chain);
+ hb_waiters_dec(hb);
/* Handle spurious wakeups gracefully */
ret = -EWOULDBLOCK;
@@ -2843,9 +2877,28 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
}
-static int __init futex_init(void)
+static void __init futex_detect_cmpxchg(void)
{
+#ifndef CONFIG_HAVE_FUTEX_CMPXCHG
u32 curval;
+
+ /*
+ * This will fail and we want it. Some arch implementations do
+ * runtime detection of the futex_atomic_cmpxchg_inatomic()
+ * functionality. We want to know that before we call in any
+ * of the complex code paths. Also we want to prevent
+ * registration of robust lists in that case. NULL is
+ * guaranteed to fault and we get -EFAULT on functional
+ * implementation, the non-functional ones will return
+ * -ENOSYS.
+ */
+ if (cmpxchg_futex_value_locked(&curval, NULL, 0, 0) == -EFAULT)
+ futex_cmpxchg_enabled = 1;
+#endif
+}
+
+static int __init futex_init(void)
+{
unsigned int futex_shift;
unsigned long i;
@@ -2861,20 +2914,11 @@ static int __init futex_init(void)
&futex_shift, NULL,
futex_hashsize, futex_hashsize);
futex_hashsize = 1UL << futex_shift;
- /*
- * This will fail and we want it. Some arch implementations do
- * runtime detection of the futex_atomic_cmpxchg_inatomic()
- * functionality. We want to know that before we call in any
- * of the complex code paths. Also we want to prevent
- * registration of robust lists in that case. NULL is
- * guaranteed to fault and we get -EFAULT on functional
- * implementation, the non-functional ones will return
- * -ENOSYS.
- */
- if (cmpxchg_futex_value_locked(&curval, NULL, 0, 0) == -EFAULT)
- futex_cmpxchg_enabled = 1;
+
+ futex_detect_cmpxchg();
for (i = 0; i < futex_hashsize; i++) {
+ atomic_set(&futex_queues[i].waiters, 0);
plist_head_init(&futex_queues[i].chain);
spin_lock_init(&futex_queues[i].lock);
}
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
index f9f44fd4d34d..55c8c9349cfe 100644
--- a/kernel/futex_compat.c
+++ b/kernel/futex_compat.c
@@ -183,7 +183,7 @@ COMPAT_SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
cmd == FUTEX_WAIT_BITSET ||
cmd == FUTEX_WAIT_REQUEUE_PI)) {
- if (get_compat_timespec(&ts, utime))
+ if (compat_get_timespec(&ts, utime))
return -EFAULT;
if (!timespec_valid(&ts))
return -EINVAL;
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 09094361dce5..d55092ceee29 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -168,19 +168,6 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer,
}
}
-
-/*
- * Get the preferred target CPU for NOHZ
- */
-static int hrtimer_get_target(int this_cpu, int pinned)
-{
-#ifdef CONFIG_NO_HZ_COMMON
- if (!pinned && get_sysctl_timer_migration() && idle_cpu(this_cpu))
- return get_nohz_timer_target();
-#endif
- return this_cpu;
-}
-
/*
* With HIGHRES=y we do not migrate the timer when it is expiring
* before the next event on the target cpu because we cannot reprogram
@@ -214,7 +201,7 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
struct hrtimer_clock_base *new_base;
struct hrtimer_cpu_base *new_cpu_base;
int this_cpu = smp_processor_id();
- int cpu = hrtimer_get_target(this_cpu, pinned);
+ int cpu = get_nohz_timer_target(pinned);
int basenum = base->index;
again:
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index dc04c166c54d..6397df2d6945 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -281,6 +281,19 @@ void unmask_irq(struct irq_desc *desc)
}
}
+void unmask_threaded_irq(struct irq_desc *desc)
+{
+ struct irq_chip *chip = desc->irq_data.chip;
+
+ if (chip->flags & IRQCHIP_EOI_THREADED)
+ chip->irq_eoi(&desc->irq_data);
+
+ if (chip->irq_unmask) {
+ chip->irq_unmask(&desc->irq_data);
+ irq_state_clr_masked(desc);
+ }
+}
+
/*
* handle_nested_irq - Handle a nested irq from a irq thread
* @irq: the interrupt number
@@ -435,6 +448,27 @@ static inline void preflow_handler(struct irq_desc *desc)
static inline void preflow_handler(struct irq_desc *desc) { }
#endif
+static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
+{
+ if (!(desc->istate & IRQS_ONESHOT)) {
+ chip->irq_eoi(&desc->irq_data);
+ return;
+ }
+ /*
+ * We need to unmask in the following cases:
+ * - Oneshot irq which did not wake the thread (caused by a
+ * spurious interrupt or a primary handler handling it
+ * completely).
+ */
+ if (!irqd_irq_disabled(&desc->irq_data) &&
+ irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) {
+ chip->irq_eoi(&desc->irq_data);
+ unmask_irq(desc);
+ } else if (!(chip->flags & IRQCHIP_EOI_THREADED)) {
+ chip->irq_eoi(&desc->irq_data);
+ }
+}
+
/**
* handle_fasteoi_irq - irq handler for transparent controllers
* @irq: the interrupt number
@@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { }
void
handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = desc->irq_data.chip;
+
raw_spin_lock(&desc->lock);
if (unlikely(irqd_irq_inprogress(&desc->irq_data)))
@@ -473,18 +509,14 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
preflow_handler(desc);
handle_irq_event(desc);
- if (desc->istate & IRQS_ONESHOT)
- cond_unmask_irq(desc);
+ cond_unmask_eoi_irq(desc, chip);
-out_eoi:
- desc->irq_data.chip->irq_eoi(&desc->irq_data);
-out_unlock:
raw_spin_unlock(&desc->lock);
return;
out:
- if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED))
- goto out_eoi;
- goto out_unlock;
+ if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED))
+ chip->irq_eoi(&desc->irq_data);
+ raw_spin_unlock(&desc->lock);
}
/**
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 131ca176b497..635480270858 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -41,6 +41,7 @@ irqreturn_t no_action(int cpl, void *dev_id)
{
return IRQ_NONE;
}
+EXPORT_SYMBOL_GPL(no_action);
static void warn_no_thread(unsigned int irq, struct irqaction *action)
{
@@ -51,7 +52,7 @@ static void warn_no_thread(unsigned int irq, struct irqaction *action)
"but no thread function available.", irq, action->name);
}
-static void irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
+void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
{
/*
* In case the thread crashed and was killed we just pretend that
@@ -157,7 +158,7 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
break;
}
- irq_wake_thread(desc, action);
+ __irq_wake_thread(desc, action);
/* Fall through to add to randomness */
case IRQ_HANDLED:
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 001fa5bab490..ddf1ffeb79f1 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -6,6 +6,7 @@
* of this file for your non core code.
*/
#include <linux/irqdesc.h>
+#include <linux/kernel_stat.h>
#ifdef CONFIG_SPARSE_IRQ
# define IRQ_BITMAP_BITS (NR_IRQS + 8196)
@@ -73,6 +74,7 @@ extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu);
extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu);
extern void mask_irq(struct irq_desc *desc);
extern void unmask_irq(struct irq_desc *desc);
+extern void unmask_threaded_irq(struct irq_desc *desc);
extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
@@ -82,6 +84,7 @@ irqreturn_t handle_irq_event(struct irq_desc *desc);
/* Resending of interrupts :*/
void check_irq_resend(struct irq_desc *desc, unsigned int irq);
bool irq_wait_for_poll(struct irq_desc *desc);
+void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action);
#ifdef CONFIG_PROC_FS
extern void register_irq_proc(unsigned int irq, struct irq_desc *desc);
@@ -179,3 +182,9 @@ static inline bool irqd_has_set(struct irq_data *d, unsigned int mask)
{
return d->state_use_accessors & mask;
}
+
+static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *desc)
+{
+ __this_cpu_inc(*desc->kstat_irqs);
+ __this_cpu_inc(kstat.irqs_sum);
+}
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index 8ab8e9390297..a7174617616b 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -489,6 +489,11 @@ void dynamic_irq_cleanup(unsigned int irq)
raw_spin_unlock_irqrestore(&desc->lock, flags);
}
+void kstat_incr_irq_this_cpu(unsigned int irq)
+{
+ kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+}
+
unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
{
struct irq_desc *desc = irq_to_desc(irq);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index cf68bb36fe58..f14033700c25 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -10,6 +10,7 @@
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/topology.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 481a13c43b17..2486a4c1a710 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -32,24 +32,10 @@ static int __init setup_forced_irqthreads(char *arg)
early_param("threadirqs", setup_forced_irqthreads);
#endif
-/**
- * synchronize_irq - wait for pending IRQ handlers (on other CPUs)
- * @irq: interrupt number to wait for
- *
- * This function waits for any pending IRQ handlers for this interrupt
- * to complete before returning. If you use this function while
- * holding a resource the IRQ handler may need you will deadlock.
- *
- * This function may be called - with care - from IRQ context.
- */
-void synchronize_irq(unsigned int irq)
+static void __synchronize_hardirq(struct irq_desc *desc)
{
- struct irq_desc *desc = irq_to_desc(irq);
bool inprogress;
- if (!desc)
- return;
-
do {
unsigned long flags;
@@ -67,12 +53,56 @@ void synchronize_irq(unsigned int irq)
/* Oops, that failed? */
} while (inprogress);
+}
- /*
- * We made sure that no hardirq handler is running. Now verify
- * that no threaded handlers are active.
- */
- wait_event(desc->wait_for_threads, !atomic_read(&desc->threads_active));
+/**
+ * synchronize_hardirq - wait for pending hard IRQ handlers (on other CPUs)
+ * @irq: interrupt number to wait for
+ *
+ * This function waits for any pending hard IRQ handlers for this
+ * interrupt to complete before returning. If you use this
+ * function while holding a resource the IRQ handler may need you
+ * will deadlock. It does not take associated threaded handlers
+ * into account.
+ *
+ * Do not use this for shutdown scenarios where you must be sure
+ * that all parts (hardirq and threaded handler) have completed.
+ *
+ * This function may be called - with care - from IRQ context.
+ */
+void synchronize_hardirq(unsigned int irq)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ if (desc)
+ __synchronize_hardirq(desc);
+}
+EXPORT_SYMBOL(synchronize_hardirq);
+
+/**
+ * synchronize_irq - wait for pending IRQ handlers (on other CPUs)
+ * @irq: interrupt number to wait for
+ *
+ * This function waits for any pending IRQ handlers for this interrupt
+ * to complete before returning. If you use this function while
+ * holding a resource the IRQ handler may need you will deadlock.
+ *
+ * This function may be called - with care - from IRQ context.
+ */
+void synchronize_irq(unsigned int irq)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ if (desc) {
+ __synchronize_hardirq(desc);
+ /*
+ * We made sure that no hardirq handler is
+ * running. Now verify that no threaded handlers are
+ * active.
+ */
+ wait_event(desc->wait_for_threads,
+ !atomic_read(&desc->threads_active));
+ }
}
EXPORT_SYMBOL(synchronize_irq);
@@ -718,7 +748,7 @@ again:
if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) &&
irqd_irq_masked(&desc->irq_data))
- unmask_irq(desc);
+ unmask_threaded_irq(desc);
out_unlock:
raw_spin_unlock_irq(&desc->lock);
@@ -727,7 +757,7 @@ out_unlock:
#ifdef CONFIG_SMP
/*
- * Check whether we need to chasnge the affinity of the interrupt thread.
+ * Check whether we need to change the affinity of the interrupt thread.
*/
static void
irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)
@@ -802,8 +832,7 @@ static irqreturn_t irq_thread_fn(struct irq_desc *desc,
static void wake_threads_waitq(struct irq_desc *desc)
{
- if (atomic_dec_and_test(&desc->threads_active) &&
- waitqueue_active(&desc->wait_for_threads))
+ if (atomic_dec_and_test(&desc->threads_active))
wake_up(&desc->wait_for_threads);
}
@@ -881,6 +910,33 @@ static int irq_thread(void *data)
return 0;
}
+/**
+ * irq_wake_thread - wake the irq thread for the action identified by dev_id
+ * @irq: Interrupt line
+ * @dev_id: Device identity for which the thread should be woken
+ *
+ */
+void irq_wake_thread(unsigned int irq, void *dev_id)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+ struct irqaction *action;
+ unsigned long flags;
+
+ if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))
+ return;
+
+ raw_spin_lock_irqsave(&desc->lock, flags);
+ for (action = desc->action; action; action = action->next) {
+ if (action->dev_id == dev_id) {
+ if (action->thread)
+ __irq_wake_thread(desc, action);
+ break;
+ }
+ }
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+}
+EXPORT_SYMBOL_GPL(irq_wake_thread);
+
static void irq_setup_forced_threading(struct irqaction *new)
{
if (!force_irqthreads)
@@ -897,6 +953,23 @@ static void irq_setup_forced_threading(struct irqaction *new)
}
}
+static int irq_request_resources(struct irq_desc *desc)
+{
+ struct irq_data *d = &desc->irq_data;
+ struct irq_chip *c = d->chip;
+
+ return c->irq_request_resources ? c->irq_request_resources(d) : 0;
+}
+
+static void irq_release_resources(struct irq_desc *desc)
+{
+ struct irq_data *d = &desc->irq_data;
+ struct irq_chip *c = d->chip;
+
+ if (c->irq_release_resources)
+ c->irq_release_resources(d);
+}
+
/*
* Internal function to register an irqaction - typically used to
* allocate special interrupts that are part of the architecture.
@@ -1092,6 +1165,13 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
}
if (!shared) {
+ ret = irq_request_resources(desc);
+ if (ret) {
+ pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
+ new->name, irq, desc->irq_data.chip->name);
+ goto out_mask;
+ }
+
init_waitqueue_head(&desc->wait_for_threads);
/* Setup the type (level, edge polarity) if configured: */
@@ -1262,8 +1342,10 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
*action_ptr = action->next;
/* If this was the last handler, shut down the IRQ line: */
- if (!desc->action)
+ if (!desc->action) {
irq_shutdown(desc);
+ irq_release_resources(desc);
+ }
#ifdef CONFIG_SMP
/* make sure affinity_hint is cleaned up */
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 36f6ee181b0c..ac1ba2f11032 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -324,15 +324,15 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc)
#ifdef CONFIG_SMP
/* create /proc/irq/<irq>/smp_affinity */
- proc_create_data("smp_affinity", 0600, desc->dir,
+ proc_create_data("smp_affinity", 0644, desc->dir,
&irq_affinity_proc_fops, (void *)(long)irq);
/* create /proc/irq/<irq>/affinity_hint */
- proc_create_data("affinity_hint", 0400, desc->dir,
+ proc_create_data("affinity_hint", 0444, desc->dir,
&irq_affinity_hint_proc_fops, (void *)(long)irq);
/* create /proc/irq/<irq>/smp_affinity_list */
- proc_create_data("smp_affinity_list", 0600, desc->dir,
+ proc_create_data("smp_affinity_list", 0644, desc->dir,
&irq_affinity_list_proc_fops, (void *)(long)irq);
proc_create_data("node", 0444, desc->dir,
@@ -372,7 +372,7 @@ void unregister_handler_proc(unsigned int irq, struct irqaction *action)
static void register_default_affinity_proc(void)
{
#ifdef CONFIG_SMP
- proc_create("irq/default_smp_affinity", 0600, NULL,
+ proc_create("irq/default_smp_affinity", 0644, NULL,
&default_affinity_proc_fops);
#endif
}
diff --git a/kernel/irq_work.c b/kernel/irq_work.c
index 55fcce6065cf..a82170e2fa78 100644
--- a/kernel/irq_work.c
+++ b/kernel/irq_work.c
@@ -61,11 +61,11 @@ void __weak arch_irq_work_raise(void)
*
* Can be re-enqueued while the callback is still in progress.
*/
-void irq_work_queue(struct irq_work *work)
+bool irq_work_queue(struct irq_work *work)
{
/* Only queue if not already pending */
if (!irq_work_claim(work))
- return;
+ return false;
/* Queue the entry and raise the IPI if needed. */
preempt_disable();
@@ -83,6 +83,8 @@ void irq_work_queue(struct irq_work *work)
}
preempt_enable();
+
+ return true;
}
EXPORT_SYMBOL_GPL(irq_work_queue);
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 60bafbed06ab..45601cf41bee 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -1039,10 +1039,10 @@ void __weak crash_unmap_reserved_pages(void)
{}
#ifdef CONFIG_COMPAT
-asmlinkage long compat_sys_kexec_load(unsigned long entry,
- unsigned long nr_segments,
- struct compat_kexec_segment __user *segments,
- unsigned long flags)
+COMPAT_SYSCALL_DEFINE4(kexec_load, compat_ulong_t, entry,
+ compat_ulong_t, nr_segments,
+ struct compat_kexec_segment __user *, segments,
+ compat_ulong_t, flags)
{
struct compat_kexec_segment in;
struct kexec_segment out, __user *ksegments;
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index d945a949760f..e660964086e2 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -19,6 +19,8 @@
#include <linux/sched.h>
#include <linux/capability.h>
+#include <linux/rcupdate.h> /* rcu_expedited */
+
#define KERNEL_ATTR_RO(_name) \
static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
diff --git a/kernel/locking/Makefile b/kernel/locking/Makefile
index baab8e5e7f66..306a76b51e0f 100644
--- a/kernel/locking/Makefile
+++ b/kernel/locking/Makefile
@@ -1,5 +1,5 @@
-obj-y += mutex.o semaphore.o rwsem.o lglock.o
+obj-y += mutex.o semaphore.o rwsem.o lglock.o mcs_spinlock.o
ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_lockdep.o = -pg
@@ -23,3 +23,4 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o
obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem-xadd.o
obj-$(CONFIG_PERCPU_RWSEM) += percpu-rwsem.o
+obj-$(CONFIG_LOCK_TORTURE_TEST) += locktorture.o
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index eb8a54783fa0..b0e9467922e1 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -1936,12 +1936,12 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)
for (;;) {
int distance = curr->lockdep_depth - depth + 1;
- hlock = curr->held_locks + depth-1;
+ hlock = curr->held_locks + depth - 1;
/*
* Only non-recursive-read entries get new dependencies
* added:
*/
- if (hlock->read != 2) {
+ if (hlock->read != 2 && hlock->check) {
if (!check_prev_add(curr, hlock, next,
distance, trylock_loop))
return 0;
@@ -2098,7 +2098,7 @@ static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
* (If lookup_chain_cache() returns with 1 it acquires
* graph_lock for us)
*/
- if (!hlock->trylock && (hlock->check == 2) &&
+ if (!hlock->trylock && hlock->check &&
lookup_chain_cache(curr, hlock, chain_key)) {
/*
* Check whether last held lock:
@@ -2517,7 +2517,7 @@ mark_held_locks(struct task_struct *curr, enum mark_type mark)
BUG_ON(usage_bit >= LOCK_USAGE_STATES);
- if (hlock_class(hlock)->key == __lockdep_no_validate__.subkeys)
+ if (!hlock->check)
continue;
if (!mark_lock(curr, hlock, usage_bit))
@@ -2557,7 +2557,7 @@ static void __trace_hardirqs_on_caller(unsigned long ip)
debug_atomic_inc(hardirqs_on_events);
}
-void trace_hardirqs_on_caller(unsigned long ip)
+__visible void trace_hardirqs_on_caller(unsigned long ip)
{
time_hardirqs_on(CALLER_ADDR0, ip);
@@ -2610,7 +2610,7 @@ EXPORT_SYMBOL(trace_hardirqs_on);
/*
* Hardirqs were disabled:
*/
-void trace_hardirqs_off_caller(unsigned long ip)
+__visible void trace_hardirqs_off_caller(unsigned long ip)
{
struct task_struct *curr = current;
@@ -3055,9 +3055,6 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
int class_idx;
u64 chain_key;
- if (!prove_locking)
- check = 1;
-
if (unlikely(!debug_locks))
return 0;
@@ -3069,8 +3066,8 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
return 0;
- if (lock->key == &__lockdep_no_validate__)
- check = 1;
+ if (!prove_locking || lock->key == &__lockdep_no_validate__)
+ check = 0;
if (subclass < NR_LOCKDEP_CACHING_CLASSES)
class = lock->class_cache[subclass];
@@ -3138,7 +3135,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
hlock->holdtime_stamp = lockstat_clock();
#endif
- if (check == 2 && !mark_irqflags(curr, hlock))
+ if (check && !mark_irqflags(curr, hlock))
return 0;
/* mark it as used: */
@@ -4191,7 +4188,7 @@ void debug_show_held_locks(struct task_struct *task)
}
EXPORT_SYMBOL_GPL(debug_show_held_locks);
-void lockdep_sys_exit(void)
+asmlinkage void lockdep_sys_exit(void)
{
struct task_struct *curr = current;
diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c
new file mode 100644
index 000000000000..f26b1a18e34e
--- /dev/null
+++ b/kernel/locking/locktorture.c
@@ -0,0 +1,452 @@
+/*
+ * Module-based torture test facility for locking
+ *
+ * This program is free software; 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, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ *
+ * Copyright (C) IBM Corporation, 2014
+ *
+ * Author: Paul E. McKenney <paulmck@us.ibm.com>
+ * Based on kernel/rcu/torture.c.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/atomic.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/moduleparam.h>
+#include <linux/percpu.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/freezer.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/trace_clock.h>
+#include <asm/byteorder.h>
+#include <linux/torture.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com>");
+
+torture_param(int, nwriters_stress, -1,
+ "Number of write-locking stress-test threads");
+torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)");
+torture_param(int, onoff_interval, 0,
+ "Time between CPU hotplugs (s), 0=disable");
+torture_param(int, shuffle_interval, 3,
+ "Number of jiffies between shuffles, 0=disable");
+torture_param(int, shutdown_secs, 0, "Shutdown time (j), <= zero to disable.");
+torture_param(int, stat_interval, 60,
+ "Number of seconds between stats printk()s");
+torture_param(int, stutter, 5, "Number of jiffies to run/halt test, 0=disable");
+torture_param(bool, verbose, true,
+ "Enable verbose debugging printk()s");
+
+static char *torture_type = "spin_lock";
+module_param(torture_type, charp, 0444);
+MODULE_PARM_DESC(torture_type,
+ "Type of lock to torture (spin_lock, spin_lock_irq, ...)");
+
+static atomic_t n_lock_torture_errors;
+
+static struct task_struct *stats_task;
+static struct task_struct **writer_tasks;
+
+static int nrealwriters_stress;
+static bool lock_is_write_held;
+
+struct lock_writer_stress_stats {
+ long n_write_lock_fail;
+ long n_write_lock_acquired;
+};
+static struct lock_writer_stress_stats *lwsa;
+
+#if defined(MODULE) || defined(CONFIG_LOCK_TORTURE_TEST_RUNNABLE)
+#define LOCKTORTURE_RUNNABLE_INIT 1
+#else
+#define LOCKTORTURE_RUNNABLE_INIT 0
+#endif
+int locktorture_runnable = LOCKTORTURE_RUNNABLE_INIT;
+module_param(locktorture_runnable, int, 0444);
+MODULE_PARM_DESC(locktorture_runnable, "Start locktorture at boot");
+
+/* Forward reference. */
+static void lock_torture_cleanup(void);
+
+/*
+ * Operations vector for selecting different types of tests.
+ */
+struct lock_torture_ops {
+ void (*init)(void);
+ int (*writelock)(void);
+ void (*write_delay)(struct torture_random_state *trsp);
+ void (*writeunlock)(void);
+ unsigned long flags;
+ const char *name;
+};
+
+static struct lock_torture_ops *cur_ops;
+
+/*
+ * Definitions for lock torture testing.
+ */
+
+static int torture_lock_busted_write_lock(void)
+{
+ return 0; /* BUGGY, do not use in real life!!! */
+}
+
+static void torture_lock_busted_write_delay(struct torture_random_state *trsp)
+{
+ const unsigned long longdelay_us = 100;
+
+ /* We want a long delay occasionally to force massive contention. */
+ if (!(torture_random(trsp) %
+ (nrealwriters_stress * 2000 * longdelay_us)))
+ mdelay(longdelay_us);
+#ifdef CONFIG_PREEMPT
+ if (!(torture_random(trsp) % (nrealwriters_stress * 20000)))
+ preempt_schedule(); /* Allow test to be preempted. */
+#endif
+}
+
+static void torture_lock_busted_write_unlock(void)
+{
+ /* BUGGY, do not use in real life!!! */
+}
+
+static struct lock_torture_ops lock_busted_ops = {
+ .writelock = torture_lock_busted_write_lock,
+ .write_delay = torture_lock_busted_write_delay,
+ .writeunlock = torture_lock_busted_write_unlock,
+ .name = "lock_busted"
+};
+
+static DEFINE_SPINLOCK(torture_spinlock);
+
+static int torture_spin_lock_write_lock(void) __acquires(torture_spinlock)
+{
+ spin_lock(&torture_spinlock);
+ return 0;
+}
+
+static void torture_spin_lock_write_delay(struct torture_random_state *trsp)
+{
+ const unsigned long shortdelay_us = 2;
+ const unsigned long longdelay_us = 100;
+
+ /* We want a short delay mostly to emulate likely code, and
+ * we want a long delay occasionally to force massive contention.
+ */
+ if (!(torture_random(trsp) %
+ (nrealwriters_stress * 2000 * longdelay_us)))
+ mdelay(longdelay_us);
+ if (!(torture_random(trsp) %
+ (nrealwriters_stress * 2 * shortdelay_us)))
+ udelay(shortdelay_us);
+#ifdef CONFIG_PREEMPT
+ if (!(torture_random(trsp) % (nrealwriters_stress * 20000)))
+ preempt_schedule(); /* Allow test to be preempted. */
+#endif
+}
+
+static void torture_spin_lock_write_unlock(void) __releases(torture_spinlock)
+{
+ spin_unlock(&torture_spinlock);
+}
+
+static struct lock_torture_ops spin_lock_ops = {
+ .writelock = torture_spin_lock_write_lock,
+ .write_delay = torture_spin_lock_write_delay,
+ .writeunlock = torture_spin_lock_write_unlock,
+ .name = "spin_lock"
+};
+
+static int torture_spin_lock_write_lock_irq(void)
+__acquires(torture_spinlock_irq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&torture_spinlock, flags);
+ cur_ops->flags = flags;
+ return 0;
+}
+
+static void torture_lock_spin_write_unlock_irq(void)
+__releases(torture_spinlock)
+{
+ spin_unlock_irqrestore(&torture_spinlock, cur_ops->flags);
+}
+
+static struct lock_torture_ops spin_lock_irq_ops = {
+ .writelock = torture_spin_lock_write_lock_irq,
+ .write_delay = torture_spin_lock_write_delay,
+ .writeunlock = torture_lock_spin_write_unlock_irq,
+ .name = "spin_lock_irq"
+};
+
+/*
+ * Lock torture writer kthread. Repeatedly acquires and releases
+ * the lock, checking for duplicate acquisitions.
+ */
+static int lock_torture_writer(void *arg)
+{
+ struct lock_writer_stress_stats *lwsp = arg;
+ static DEFINE_TORTURE_RANDOM(rand);
+
+ VERBOSE_TOROUT_STRING("lock_torture_writer task started");
+ set_user_nice(current, 19);
+
+ do {
+ schedule_timeout_uninterruptible(1);
+ cur_ops->writelock();
+ if (WARN_ON_ONCE(lock_is_write_held))
+ lwsp->n_write_lock_fail++;
+ lock_is_write_held = 1;
+ lwsp->n_write_lock_acquired++;
+ cur_ops->write_delay(&rand);
+ lock_is_write_held = 0;
+ cur_ops->writeunlock();
+ stutter_wait("lock_torture_writer");
+ } while (!torture_must_stop());
+ torture_kthread_stopping("lock_torture_writer");
+ return 0;
+}
+
+/*
+ * Create an lock-torture-statistics message in the specified buffer.
+ */
+static void lock_torture_printk(char *page)
+{
+ bool fail = 0;
+ int i;
+ long max = 0;
+ long min = lwsa[0].n_write_lock_acquired;
+ long long sum = 0;
+
+ for (i = 0; i < nrealwriters_stress; i++) {
+ if (lwsa[i].n_write_lock_fail)
+ fail = true;
+ sum += lwsa[i].n_write_lock_acquired;
+ if (max < lwsa[i].n_write_lock_fail)
+ max = lwsa[i].n_write_lock_fail;
+ if (min > lwsa[i].n_write_lock_fail)
+ min = lwsa[i].n_write_lock_fail;
+ }
+ page += sprintf(page, "%s%s ", torture_type, TORTURE_FLAG);
+ page += sprintf(page,
+ "Writes: Total: %lld Max/Min: %ld/%ld %s Fail: %d %s\n",
+ sum, max, min, max / 2 > min ? "???" : "",
+ fail, fail ? "!!!" : "");
+ if (fail)
+ atomic_inc(&n_lock_torture_errors);
+}
+
+/*
+ * Print torture statistics. Caller must ensure that there is only one
+ * call to this function at a given time!!! This is normally accomplished
+ * by relying on the module system to only have one copy of the module
+ * loaded, and then by giving the lock_torture_stats kthread full control
+ * (or the init/cleanup functions when lock_torture_stats thread is not
+ * running).
+ */
+static void lock_torture_stats_print(void)
+{
+ int size = nrealwriters_stress * 200 + 8192;
+ char *buf;
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf) {
+ pr_err("lock_torture_stats_print: Out of memory, need: %d",
+ size);
+ return;
+ }
+ lock_torture_printk(buf);
+ pr_alert("%s", buf);
+ kfree(buf);
+}
+
+/*
+ * Periodically prints torture statistics, if periodic statistics printing
+ * was specified via the stat_interval module parameter.
+ *
+ * No need to worry about fullstop here, since this one doesn't reference
+ * volatile state or register callbacks.
+ */
+static int lock_torture_stats(void *arg)
+{
+ VERBOSE_TOROUT_STRING("lock_torture_stats task started");
+ do {
+ schedule_timeout_interruptible(stat_interval * HZ);
+ lock_torture_stats_print();
+ torture_shutdown_absorb("lock_torture_stats");
+ } while (!torture_must_stop());
+ torture_kthread_stopping("lock_torture_stats");
+ return 0;
+}
+
+static inline void
+lock_torture_print_module_parms(struct lock_torture_ops *cur_ops,
+ const char *tag)
+{
+ pr_alert("%s" TORTURE_FLAG
+ "--- %s: nwriters_stress=%d stat_interval=%d verbose=%d shuffle_interval=%d stutter=%d shutdown_secs=%d onoff_interval=%d onoff_holdoff=%d\n",
+ torture_type, tag, nrealwriters_stress, stat_interval, verbose,
+ shuffle_interval, stutter, shutdown_secs,
+ onoff_interval, onoff_holdoff);
+}
+
+static void lock_torture_cleanup(void)
+{
+ int i;
+
+ if (torture_cleanup())
+ return;
+
+ if (writer_tasks) {
+ for (i = 0; i < nrealwriters_stress; i++)
+ torture_stop_kthread(lock_torture_writer,
+ writer_tasks[i]);
+ kfree(writer_tasks);
+ writer_tasks = NULL;
+ }
+
+ torture_stop_kthread(lock_torture_stats, stats_task);
+ lock_torture_stats_print(); /* -After- the stats thread is stopped! */
+
+ if (atomic_read(&n_lock_torture_errors))
+ lock_torture_print_module_parms(cur_ops,
+ "End of test: FAILURE");
+ else if (torture_onoff_failures())
+ lock_torture_print_module_parms(cur_ops,
+ "End of test: LOCK_HOTPLUG");
+ else
+ lock_torture_print_module_parms(cur_ops,
+ "End of test: SUCCESS");
+}
+
+static int __init lock_torture_init(void)
+{
+ int i;
+ int firsterr = 0;
+ static struct lock_torture_ops *torture_ops[] = {
+ &lock_busted_ops, &spin_lock_ops, &spin_lock_irq_ops,
+ };
+
+ torture_init_begin(torture_type, verbose, &locktorture_runnable);
+
+ /* Process args and tell the world that the torturer is on the job. */
+ for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
+ cur_ops = torture_ops[i];
+ if (strcmp(torture_type, cur_ops->name) == 0)
+ break;
+ }
+ if (i == ARRAY_SIZE(torture_ops)) {
+ pr_alert("lock-torture: invalid torture type: \"%s\"\n",
+ torture_type);
+ pr_alert("lock-torture types:");
+ for (i = 0; i < ARRAY_SIZE(torture_ops); i++)
+ pr_alert(" %s", torture_ops[i]->name);
+ pr_alert("\n");
+ torture_init_end();
+ return -EINVAL;
+ }
+ if (cur_ops->init)
+ cur_ops->init(); /* no "goto unwind" prior to this point!!! */
+
+ if (nwriters_stress >= 0)
+ nrealwriters_stress = nwriters_stress;
+ else
+ nrealwriters_stress = 2 * num_online_cpus();
+ lock_torture_print_module_parms(cur_ops, "Start of test");
+
+ /* Initialize the statistics so that each run gets its own numbers. */
+
+ lock_is_write_held = 0;
+ lwsa = kmalloc(sizeof(*lwsa) * nrealwriters_stress, GFP_KERNEL);
+ if (lwsa == NULL) {
+ VERBOSE_TOROUT_STRING("lwsa: Out of memory");
+ firsterr = -ENOMEM;
+ goto unwind;
+ }
+ for (i = 0; i < nrealwriters_stress; i++) {
+ lwsa[i].n_write_lock_fail = 0;
+ lwsa[i].n_write_lock_acquired = 0;
+ }
+
+ /* Start up the kthreads. */
+
+ if (onoff_interval > 0) {
+ firsterr = torture_onoff_init(onoff_holdoff * HZ,
+ onoff_interval * HZ);
+ if (firsterr)
+ goto unwind;
+ }
+ if (shuffle_interval > 0) {
+ firsterr = torture_shuffle_init(shuffle_interval);
+ if (firsterr)
+ goto unwind;
+ }
+ if (shutdown_secs > 0) {
+ firsterr = torture_shutdown_init(shutdown_secs,
+ lock_torture_cleanup);
+ if (firsterr)
+ goto unwind;
+ }
+ if (stutter > 0) {
+ firsterr = torture_stutter_init(stutter);
+ if (firsterr)
+ goto unwind;
+ }
+
+ writer_tasks = kzalloc(nrealwriters_stress * sizeof(writer_tasks[0]),
+ GFP_KERNEL);
+ if (writer_tasks == NULL) {
+ VERBOSE_TOROUT_ERRSTRING("writer_tasks: Out of memory");
+ firsterr = -ENOMEM;
+ goto unwind;
+ }
+ for (i = 0; i < nrealwriters_stress; i++) {
+ firsterr = torture_create_kthread(lock_torture_writer, &lwsa[i],
+ writer_tasks[i]);
+ if (firsterr)
+ goto unwind;
+ }
+ if (stat_interval > 0) {
+ firsterr = torture_create_kthread(lock_torture_stats, NULL,
+ stats_task);
+ if (firsterr)
+ goto unwind;
+ }
+ torture_init_end();
+ return 0;
+
+unwind:
+ torture_init_end();
+ lock_torture_cleanup();
+ return firsterr;
+}
+
+module_init(lock_torture_init);
+module_exit(lock_torture_cleanup);
diff --git a/kernel/locking/mcs_spinlock.c b/kernel/locking/mcs_spinlock.c
new file mode 100644
index 000000000000..838dc9e00669
--- /dev/null
+++ b/kernel/locking/mcs_spinlock.c
@@ -0,0 +1,178 @@
+
+#include <linux/percpu.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include "mcs_spinlock.h"
+
+#ifdef CONFIG_SMP
+
+/*
+ * An MCS like lock especially tailored for optimistic spinning for sleeping
+ * lock implementations (mutex, rwsem, etc).
+ *
+ * Using a single mcs node per CPU is safe because sleeping locks should not be
+ * called from interrupt context and we have preemption disabled while
+ * spinning.
+ */
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct optimistic_spin_queue, osq_node);
+
+/*
+ * Get a stable @node->next pointer, either for unlock() or unqueue() purposes.
+ * Can return NULL in case we were the last queued and we updated @lock instead.
+ */
+static inline struct optimistic_spin_queue *
+osq_wait_next(struct optimistic_spin_queue **lock,
+ struct optimistic_spin_queue *node,
+ struct optimistic_spin_queue *prev)
+{
+ struct optimistic_spin_queue *next = NULL;
+
+ for (;;) {
+ if (*lock == node && cmpxchg(lock, node, prev) == node) {
+ /*
+ * We were the last queued, we moved @lock back. @prev
+ * will now observe @lock and will complete its
+ * unlock()/unqueue().
+ */
+ break;
+ }
+
+ /*
+ * We must xchg() the @node->next value, because if we were to
+ * leave it in, a concurrent unlock()/unqueue() from
+ * @node->next might complete Step-A and think its @prev is
+ * still valid.
+ *
+ * If the concurrent unlock()/unqueue() wins the race, we'll
+ * wait for either @lock to point to us, through its Step-B, or
+ * wait for a new @node->next from its Step-C.
+ */
+ if (node->next) {
+ next = xchg(&node->next, NULL);
+ if (next)
+ break;
+ }
+
+ arch_mutex_cpu_relax();
+ }
+
+ return next;
+}
+
+bool osq_lock(struct optimistic_spin_queue **lock)
+{
+ struct optimistic_spin_queue *node = this_cpu_ptr(&osq_node);
+ struct optimistic_spin_queue *prev, *next;
+
+ node->locked = 0;
+ node->next = NULL;
+
+ node->prev = prev = xchg(lock, node);
+ if (likely(prev == NULL))
+ return true;
+
+ ACCESS_ONCE(prev->next) = node;
+
+ /*
+ * Normally @prev is untouchable after the above store; because at that
+ * moment unlock can proceed and wipe the node element from stack.
+ *
+ * However, since our nodes are static per-cpu storage, we're
+ * guaranteed their existence -- this allows us to apply
+ * cmpxchg in an attempt to undo our queueing.
+ */
+
+ while (!smp_load_acquire(&node->locked)) {
+ /*
+ * If we need to reschedule bail... so we can block.
+ */
+ if (need_resched())
+ goto unqueue;
+
+ arch_mutex_cpu_relax();
+ }
+ return true;
+
+unqueue:
+ /*
+ * Step - A -- stabilize @prev
+ *
+ * Undo our @prev->next assignment; this will make @prev's
+ * unlock()/unqueue() wait for a next pointer since @lock points to us
+ * (or later).
+ */
+
+ for (;;) {
+ if (prev->next == node &&
+ cmpxchg(&prev->next, node, NULL) == node)
+ break;
+
+ /*
+ * We can only fail the cmpxchg() racing against an unlock(),
+ * in which case we should observe @node->locked becomming
+ * true.
+ */
+ if (smp_load_acquire(&node->locked))
+ return true;
+
+ arch_mutex_cpu_relax();
+
+ /*
+ * Or we race against a concurrent unqueue()'s step-B, in which
+ * case its step-C will write us a new @node->prev pointer.
+ */
+ prev = ACCESS_ONCE(node->prev);
+ }
+
+ /*
+ * Step - B -- stabilize @next
+ *
+ * Similar to unlock(), wait for @node->next or move @lock from @node
+ * back to @prev.
+ */
+
+ next = osq_wait_next(lock, node, prev);
+ if (!next)
+ return false;
+
+ /*
+ * Step - C -- unlink
+ *
+ * @prev is stable because its still waiting for a new @prev->next
+ * pointer, @next is stable because our @node->next pointer is NULL and
+ * it will wait in Step-A.
+ */
+
+ ACCESS_ONCE(next->prev) = prev;
+ ACCESS_ONCE(prev->next) = next;
+
+ return false;
+}
+
+void osq_unlock(struct optimistic_spin_queue **lock)
+{
+ struct optimistic_spin_queue *node = this_cpu_ptr(&osq_node);
+ struct optimistic_spin_queue *next;
+
+ /*
+ * Fast path for the uncontended case.
+ */
+ if (likely(cmpxchg(lock, node, NULL) == node))
+ return;
+
+ /*
+ * Second most likely case.
+ */
+ next = xchg(&node->next, NULL);
+ if (next) {
+ ACCESS_ONCE(next->locked) = 1;
+ return;
+ }
+
+ next = osq_wait_next(lock, node, NULL);
+ if (next)
+ ACCESS_ONCE(next->locked) = 1;
+}
+
+#endif
+
diff --git a/kernel/locking/mcs_spinlock.h b/kernel/locking/mcs_spinlock.h
new file mode 100644
index 000000000000..a2dbac4aca6b
--- /dev/null
+++ b/kernel/locking/mcs_spinlock.h
@@ -0,0 +1,129 @@
+/*
+ * MCS lock defines
+ *
+ * This file contains the main data structure and API definitions of MCS lock.
+ *
+ * The MCS lock (proposed by Mellor-Crummey and Scott) is a simple spin-lock
+ * with the desirable properties of being fair, and with each cpu trying
+ * to acquire the lock spinning on a local variable.
+ * It avoids expensive cache bouncings that common test-and-set spin-lock
+ * implementations incur.
+ */
+#ifndef __LINUX_MCS_SPINLOCK_H
+#define __LINUX_MCS_SPINLOCK_H
+
+#include <asm/mcs_spinlock.h>
+
+struct mcs_spinlock {
+ struct mcs_spinlock *next;
+ int locked; /* 1 if lock acquired */
+};
+
+#ifndef arch_mcs_spin_lock_contended
+/*
+ * Using smp_load_acquire() provides a memory barrier that ensures
+ * subsequent operations happen after the lock is acquired.
+ */
+#define arch_mcs_spin_lock_contended(l) \
+do { \
+ while (!(smp_load_acquire(l))) \
+ arch_mutex_cpu_relax(); \
+} while (0)
+#endif
+
+#ifndef arch_mcs_spin_unlock_contended
+/*
+ * smp_store_release() provides a memory barrier to ensure all
+ * operations in the critical section has been completed before
+ * unlocking.
+ */
+#define arch_mcs_spin_unlock_contended(l) \
+ smp_store_release((l), 1)
+#endif
+
+/*
+ * Note: the smp_load_acquire/smp_store_release pair is not
+ * sufficient to form a full memory barrier across
+ * cpus for many architectures (except x86) for mcs_unlock and mcs_lock.
+ * For applications that need a full barrier across multiple cpus
+ * with mcs_unlock and mcs_lock pair, smp_mb__after_unlock_lock() should be
+ * used after mcs_lock.
+ */
+
+/*
+ * In order to acquire the lock, the caller should declare a local node and
+ * pass a reference of the node to this function in addition to the lock.
+ * If the lock has already been acquired, then this will proceed to spin
+ * on this node->locked until the previous lock holder sets the node->locked
+ * in mcs_spin_unlock().
+ *
+ * We don't inline mcs_spin_lock() so that perf can correctly account for the
+ * time spent in this lock function.
+ */
+static inline
+void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
+{
+ struct mcs_spinlock *prev;
+
+ /* Init node */
+ node->locked = 0;
+ node->next = NULL;
+
+ prev = xchg(lock, node);
+ if (likely(prev == NULL)) {
+ /*
+ * Lock acquired, don't need to set node->locked to 1. Threads
+ * only spin on its own node->locked value for lock acquisition.
+ * However, since this thread can immediately acquire the lock
+ * and does not proceed to spin on its own node->locked, this
+ * value won't be used. If a debug mode is needed to
+ * audit lock status, then set node->locked value here.
+ */
+ return;
+ }
+ ACCESS_ONCE(prev->next) = node;
+
+ /* Wait until the lock holder passes the lock down. */
+ arch_mcs_spin_lock_contended(&node->locked);
+}
+
+/*
+ * Releases the lock. The caller should pass in the corresponding node that
+ * was used to acquire the lock.
+ */
+static inline
+void mcs_spin_unlock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
+{
+ struct mcs_spinlock *next = ACCESS_ONCE(node->next);
+
+ if (likely(!next)) {
+ /*
+ * Release the lock by setting it to NULL
+ */
+ if (likely(cmpxchg(lock, node, NULL) == node))
+ return;
+ /* Wait until the next pointer is set */
+ while (!(next = ACCESS_ONCE(node->next)))
+ arch_mutex_cpu_relax();
+ }
+
+ /* Pass lock to next waiter. */
+ arch_mcs_spin_unlock_contended(&next->locked);
+}
+
+/*
+ * Cancellable version of the MCS lock above.
+ *
+ * Intended for adaptive spinning of sleeping locks:
+ * mutex_lock()/rwsem_down_{read,write}() etc.
+ */
+
+struct optimistic_spin_queue {
+ struct optimistic_spin_queue *next, *prev;
+ int locked; /* 1 if lock acquired */
+};
+
+extern bool osq_lock(struct optimistic_spin_queue **lock);
+extern void osq_unlock(struct optimistic_spin_queue **lock);
+
+#endif /* __LINUX_MCS_SPINLOCK_H */
diff --git a/kernel/locking/mutex-debug.c b/kernel/locking/mutex-debug.c
index faf6f5b53e77..e1191c996c59 100644
--- a/kernel/locking/mutex-debug.c
+++ b/kernel/locking/mutex-debug.c
@@ -83,6 +83,12 @@ void debug_mutex_unlock(struct mutex *lock)
DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next);
mutex_clear_owner(lock);
+
+ /*
+ * __mutex_slowpath_needs_to_unlock() is explicitly 0 for debug
+ * mutexes so that we can do it here after we've verified state.
+ */
+ atomic_set(&lock->count, 1);
}
void debug_mutex_init(struct mutex *lock, const char *name,
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index 4dd6e4c219de..bc73d33c6760 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -25,6 +25,7 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/debug_locks.h>
+#include "mcs_spinlock.h"
/*
* In the DEBUG case we are using the "NULL fastpath" for mutexes,
@@ -33,6 +34,13 @@
#ifdef CONFIG_DEBUG_MUTEXES
# include "mutex-debug.h"
# include <asm-generic/mutex-null.h>
+/*
+ * Must be 0 for the debug case so we do not do the unlock outside of the
+ * wait_lock region. debug_mutex_unlock() will do the actual unlock in this
+ * case.
+ */
+# undef __mutex_slowpath_needs_to_unlock
+# define __mutex_slowpath_needs_to_unlock() 0
#else
# include "mutex.h"
# include <asm/mutex.h>
@@ -52,7 +60,7 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
INIT_LIST_HEAD(&lock->wait_list);
mutex_clear_owner(lock);
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
- lock->spin_mlock = NULL;
+ lock->osq = NULL;
#endif
debug_mutex_init(lock, name, key);
@@ -67,8 +75,7 @@ EXPORT_SYMBOL(__mutex_init);
* We also put the fastpath first in the kernel image, to make sure the
* branch is predicted by the CPU as default-untaken.
*/
-static __used noinline void __sched
-__mutex_lock_slowpath(atomic_t *lock_count);
+__visible void __sched __mutex_lock_slowpath(atomic_t *lock_count);
/**
* mutex_lock - acquire the mutex
@@ -111,54 +118,7 @@ EXPORT_SYMBOL(mutex_lock);
* more or less simultaneously, the spinners need to acquire a MCS lock
* first before spinning on the owner field.
*
- * We don't inline mspin_lock() so that perf can correctly account for the
- * time spent in this lock function.
*/
-struct mspin_node {
- struct mspin_node *next ;
- int locked; /* 1 if lock acquired */
-};
-#define MLOCK(mutex) ((struct mspin_node **)&((mutex)->spin_mlock))
-
-static noinline
-void mspin_lock(struct mspin_node **lock, struct mspin_node *node)
-{
- struct mspin_node *prev;
-
- /* Init node */
- node->locked = 0;
- node->next = NULL;
-
- prev = xchg(lock, node);
- if (likely(prev == NULL)) {
- /* Lock acquired */
- node->locked = 1;
- return;
- }
- ACCESS_ONCE(prev->next) = node;
- smp_wmb();
- /* Wait until the lock holder passes the lock down */
- while (!ACCESS_ONCE(node->locked))
- arch_mutex_cpu_relax();
-}
-
-static void mspin_unlock(struct mspin_node **lock, struct mspin_node *node)
-{
- struct mspin_node *next = ACCESS_ONCE(node->next);
-
- if (likely(!next)) {
- /*
- * Release the lock by setting it to NULL
- */
- if (cmpxchg(lock, node, NULL) == node)
- return;
- /* Wait until the next pointer is set */
- while (!(next = ACCESS_ONCE(node->next)))
- arch_mutex_cpu_relax();
- }
- ACCESS_ONCE(next->locked) = 1;
- smp_wmb();
-}
/*
* Mutex spinning code migrated from kernel/sched/core.c
@@ -212,6 +172,9 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock)
struct task_struct *owner;
int retval = 1;
+ if (need_resched())
+ return 0;
+
rcu_read_lock();
owner = ACCESS_ONCE(lock->owner);
if (owner)
@@ -225,7 +188,8 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock)
}
#endif
-static __used noinline void __sched __mutex_unlock_slowpath(atomic_t *lock_count);
+__visible __used noinline
+void __sched __mutex_unlock_slowpath(atomic_t *lock_count);
/**
* mutex_unlock - release the mutex
@@ -446,9 +410,11 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
if (!mutex_can_spin_on_owner(lock))
goto slowpath;
+ if (!osq_lock(&lock->osq))
+ goto slowpath;
+
for (;;) {
struct task_struct *owner;
- struct mspin_node node;
if (use_ww_ctx && ww_ctx->acquired > 0) {
struct ww_mutex *ww;
@@ -463,19 +429,16 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
* performed the optimistic spinning cannot be done.
*/
if (ACCESS_ONCE(ww->ctx))
- goto slowpath;
+ break;
}
/*
* If there's an owner, wait for it to either
* release the lock or go to sleep.
*/
- mspin_lock(MLOCK(lock), &node);
owner = ACCESS_ONCE(lock->owner);
- if (owner && !mutex_spin_on_owner(lock, owner)) {
- mspin_unlock(MLOCK(lock), &node);
- goto slowpath;
- }
+ if (owner && !mutex_spin_on_owner(lock, owner))
+ break;
if ((atomic_read(&lock->count) == 1) &&
(atomic_cmpxchg(&lock->count, 1, 0) == 1)) {
@@ -488,11 +451,10 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
}
mutex_set_owner(lock);
- mspin_unlock(MLOCK(lock), &node);
+ osq_unlock(&lock->osq);
preempt_enable();
return 0;
}
- mspin_unlock(MLOCK(lock), &node);
/*
* When there's no owner, we might have preempted between the
@@ -501,7 +463,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
* the owner complete.
*/
if (!owner && (need_resched() || rt_task(task)))
- goto slowpath;
+ break;
/*
* The cpu_relax() call is a compiler barrier which forces
@@ -511,7 +473,15 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
*/
arch_mutex_cpu_relax();
}
+ osq_unlock(&lock->osq);
slowpath:
+ /*
+ * If we fell out of the spin path because of need_resched(),
+ * reschedule now, before we try-lock the mutex. This avoids getting
+ * scheduled out right after we obtained the mutex.
+ */
+ if (need_resched())
+ schedule_preempt_disabled();
#endif
spin_lock_mutex(&lock->wait_lock, flags);
@@ -717,10 +687,6 @@ __mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)
struct mutex *lock = container_of(lock_count, struct mutex, count);
unsigned long flags;
- spin_lock_mutex(&lock->wait_lock, flags);
- mutex_release(&lock->dep_map, nested, _RET_IP_);
- debug_mutex_unlock(lock);
-
/*
* some architectures leave the lock unlocked in the fastpath failure
* case, others need to leave it locked. In the later case we have to
@@ -729,6 +695,10 @@ __mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)
if (__mutex_slowpath_needs_to_unlock())
atomic_set(&lock->count, 1);
+ spin_lock_mutex(&lock->wait_lock, flags);
+ mutex_release(&lock->dep_map, nested, _RET_IP_);
+ debug_mutex_unlock(lock);
+
if (!list_empty(&lock->wait_list)) {
/* get the first entry from the wait-list: */
struct mutex_waiter *waiter =
@@ -746,7 +716,7 @@ __mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)
/*
* Release the lock, slowpath:
*/
-static __used noinline void
+__visible void
__mutex_unlock_slowpath(atomic_t *lock_count)
{
__mutex_unlock_common_slowpath(lock_count, 1);
@@ -803,7 +773,7 @@ int __sched mutex_lock_killable(struct mutex *lock)
}
EXPORT_SYMBOL(mutex_lock_killable);
-static __used noinline void __sched
+__visible void __sched
__mutex_lock_slowpath(atomic_t *lock_count)
{
struct mutex *lock = container_of(lock_count, struct mutex, count);
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
index 2e960a2bab81..aa4dff04b594 100644
--- a/kernel/locking/rtmutex.c
+++ b/kernel/locking/rtmutex.c
@@ -213,6 +213,18 @@ struct task_struct *rt_mutex_get_top_task(struct task_struct *task)
}
/*
+ * Called by sched_setscheduler() to check whether the priority change
+ * is overruled by a possible priority boosting.
+ */
+int rt_mutex_check_prio(struct task_struct *task, int newprio)
+{
+ if (!task_has_pi_waiters(task))
+ return 0;
+
+ return task_top_pi_waiter(task)->task->prio <= newprio;
+}
+
+/*
* Adjust the priority of a task, after its pi_waiters got modified.
*
* This can be both boosting and unboosting. task->pi_lock must be held.
diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c
index 19c5fa95e0b4..1d66e08e897d 100644
--- a/kernel/locking/rwsem-xadd.c
+++ b/kernel/locking/rwsem-xadd.c
@@ -143,6 +143,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, enum rwsem_wake_type wake_type)
/*
* wait for the read lock to be granted
*/
+__visible
struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem)
{
long count, adjustment = -RWSEM_ACTIVE_READ_BIAS;
@@ -190,6 +191,7 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem)
/*
* wait until we successfully acquire the write lock
*/
+__visible
struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
{
long count, adjustment = -RWSEM_ACTIVE_WRITE_BIAS;
@@ -252,6 +254,7 @@ struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
* handle waking up a waiter on the semaphore
* - up_read/up_write has decremented the active part of count if we come here
*/
+__visible
struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
{
unsigned long flags;
@@ -272,6 +275,7 @@ struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
* - caller incremented waiting part of count and discovered it still negative
* - just wake up any readers at the front of the queue
*/
+__visible
struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem)
{
unsigned long flags;
diff --git a/kernel/module.c b/kernel/module.c
index d24fcf29cb64..8dc7f5e80dd8 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1015,7 +1015,7 @@ static size_t module_flags_taint(struct module *mod, char *buf)
buf[l++] = 'C';
/*
* TAINT_FORCED_RMMOD: could be added.
- * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
+ * TAINT_CPU_OUT_OF_SPEC, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
* apply to modules.
*/
return l;
@@ -1948,6 +1948,10 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
switch (sym[i].st_shndx) {
case SHN_COMMON:
+ /* Ignore common symbols */
+ if (!strncmp(name, "__gnu_lto", 9))
+ break;
+
/* We compiled with -fno-common. These are not
supposed to happen. */
pr_debug("Common symbol: %s\n", name);
diff --git a/kernel/notifier.c b/kernel/notifier.c
index 2d5cc4ccff7f..db4c8b08a50c 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -309,7 +309,7 @@ int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
* racy then it does not matter what the result of the test
* is, we re-check the list after having taken the lock anyway:
*/
- if (rcu_dereference_raw(nh->head)) {
+ if (rcu_access_pointer(nh->head)) {
down_read(&nh->rwsem);
ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
nr_calls);
diff --git a/kernel/panic.c b/kernel/panic.c
index 6d6300375090..cca8a913ae7c 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -199,7 +199,7 @@ struct tnt {
static const struct tnt tnts[] = {
{ TAINT_PROPRIETARY_MODULE, 'P', 'G' },
{ TAINT_FORCED_MODULE, 'F', ' ' },
- { TAINT_UNSAFE_SMP, 'S', ' ' },
+ { TAINT_CPU_OUT_OF_SPEC, 'S', ' ' },
{ TAINT_FORCED_RMMOD, 'R', ' ' },
{ TAINT_MACHINE_CHECK, 'M', ' ' },
{ TAINT_BAD_PAGE, 'B', ' ' },
@@ -459,7 +459,7 @@ EXPORT_SYMBOL(warn_slowpath_null);
* Called when gcc's -fstack-protector feature is used, and
* gcc detects corruption of the on-stack canary value
*/
-void __stack_chk_fail(void)
+__visible void __stack_chk_fail(void)
{
panic("stack-protector: Kernel stack is corrupted in: %p\n",
__builtin_return_address(0));
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 06c62de9c711..db95d8eb761b 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -318,7 +318,9 @@ static void *pidns_get(struct task_struct *task)
struct pid_namespace *ns;
rcu_read_lock();
- ns = get_pid_ns(task_active_pid_ns(task));
+ ns = task_active_pid_ns(task);
+ if (ns)
+ get_pid_ns(ns);
rcu_read_unlock();
return ns;
diff --git a/kernel/power/console.c b/kernel/power/console.c
index eacb8bd8cab4..aba9c545a0e3 100644
--- a/kernel/power/console.c
+++ b/kernel/power/console.c
@@ -9,6 +9,7 @@
#include <linux/kbd_kern.h>
#include <linux/vt.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include "power.h"
#define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1)
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 37170d4dd9a6..f4f2073711d3 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -973,16 +973,20 @@ static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
- unsigned int maj, min;
dev_t res;
- int ret = -EINVAL;
+ int len = n;
+ char *name;
- if (sscanf(buf, "%u:%u", &maj, &min) != 2)
- goto out;
+ if (len && buf[len-1] == '\n')
+ len--;
+ name = kstrndup(buf, len, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
- res = MKDEV(maj,min);
- if (maj != MAJOR(res) || min != MINOR(res))
- goto out;
+ res = name_to_dev_t(name);
+ kfree(name);
+ if (!res)
+ return -EINVAL;
lock_system_sleep();
swsusp_resume_device = res;
@@ -990,9 +994,7 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
printk(KERN_INFO "PM: Starting manual resume from disk\n");
noresume = 0;
software_resume();
- ret = n;
- out:
- return ret;
+ return n;
}
power_attr(resume);
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 1d1bf630e6e9..6271bc4073ef 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -282,8 +282,8 @@ struct kobject *power_kobj;
* state - control system power state.
*
* show() returns what states are supported, which is hard-coded to
- * 'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and
- * 'disk' (Suspend-to-Disk).
+ * 'freeze' (Low-Power Idle), 'standby' (Power-On Suspend),
+ * 'mem' (Suspend-to-RAM), and 'disk' (Suspend-to-Disk).
*
* store() accepts one of those strings, translates it into the
* proper enumerated value, and initiates a suspend transition.
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 7d4b7ffb3c1d..1ca753106557 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -49,6 +49,8 @@ static inline char *check_image_kernel(struct swsusp_info *info)
*/
#define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT)
+asmlinkage int swsusp_save(void);
+
/* kernel/power/hibernate.c */
extern bool freezer_test_done;
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 8dff9b48075a..884b77058864 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -66,6 +66,7 @@ static struct pm_qos_constraints cpu_dma_constraints = {
.list = PLIST_HEAD_INIT(cpu_dma_constraints.list),
.target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
.default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
+ .no_constraint_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
.type = PM_QOS_MIN,
.notifiers = &cpu_dma_lat_notifier,
};
@@ -79,6 +80,7 @@ static struct pm_qos_constraints network_lat_constraints = {
.list = PLIST_HEAD_INIT(network_lat_constraints.list),
.target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
.default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
+ .no_constraint_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
.type = PM_QOS_MIN,
.notifiers = &network_lat_notifier,
};
@@ -93,6 +95,7 @@ static struct pm_qos_constraints network_tput_constraints = {
.list = PLIST_HEAD_INIT(network_tput_constraints.list),
.target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
.default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
+ .no_constraint_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
.type = PM_QOS_MAX,
.notifiers = &network_throughput_notifier,
};
@@ -128,7 +131,7 @@ static const struct file_operations pm_qos_power_fops = {
static inline int pm_qos_get_value(struct pm_qos_constraints *c)
{
if (plist_head_empty(&c->list))
- return c->default_value;
+ return c->no_constraint_value;
switch (c->type) {
case PM_QOS_MIN:
@@ -170,6 +173,7 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
{
unsigned long flags;
int prev_value, curr_value, new_value;
+ int ret;
spin_lock_irqsave(&pm_qos_lock, flags);
prev_value = pm_qos_get_value(c);
@@ -205,13 +209,15 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
trace_pm_qos_update_target(action, prev_value, curr_value);
if (prev_value != curr_value) {
- blocking_notifier_call_chain(c->notifiers,
- (unsigned long)curr_value,
- NULL);
- return 1;
+ ret = 1;
+ if (c->notifiers)
+ blocking_notifier_call_chain(c->notifiers,
+ (unsigned long)curr_value,
+ NULL);
} else {
- return 0;
+ ret = 0;
}
+ return ret;
}
/**
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index d9f61a145802..149e745eaa52 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -1268,7 +1268,7 @@ static void free_unnecessary_pages(void)
* [number of saveable pages] - [number of pages that can be freed in theory]
*
* where the second term is the sum of (1) reclaimable slab pages, (2) active
- * and (3) inactive anonymouns pages, (4) active and (5) inactive file pages,
+ * and (3) inactive anonymous pages, (4) active and (5) inactive file pages,
* minus mapped file pages.
*/
static unsigned long minimum_image_size(unsigned long saveable)
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 62ee437b5c7e..90b3d9366d1a 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -39,7 +39,7 @@ static const struct platform_suspend_ops *suspend_ops;
static bool need_suspend_ops(suspend_state_t state)
{
- return !!(state > PM_SUSPEND_FREEZE);
+ return state > PM_SUSPEND_FREEZE;
}
static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head);
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index 8f50de394d22..019069c84ff6 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -18,6 +18,8 @@
#include <linux/rbtree.h>
#include <linux/slab.h>
+#include "power.h"
+
static DEFINE_MUTEX(wakelocks_lock);
struct wakelock {
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index b1d255f04135..4dae9cbe9259 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1076,7 +1076,6 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
next_seq = log_next_seq;
len = 0;
- prev = 0;
while (len >= 0 && seq < next_seq) {
struct printk_log *msg = log_from_idx(idx);
int textlen;
@@ -2788,7 +2787,6 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
next_idx = idx;
l = 0;
- prev = 0;
while (seq < dumper->next_seq) {
struct printk_log *msg = log_from_idx(idx);
diff --git a/kernel/profile.c b/kernel/profile.c
index 6631e1ef55ab..ebdd9c1a86b4 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -549,14 +549,14 @@ static int create_hash_tables(void)
struct page *page;
page = alloc_pages_exact_node(node,
- GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+ GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
0);
if (!page)
goto out_cleanup;
per_cpu(cpu_profile_hits, cpu)[1]
= (struct profile_hit *)page_address(page);
page = alloc_pages_exact_node(node,
- GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+ GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
0);
if (!page)
goto out_cleanup;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 1f4bcb3cc21c..adf98622cb32 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -1180,8 +1180,8 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
return ret;
}
-asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
- compat_long_t addr, compat_long_t data)
+COMPAT_SYSCALL_DEFINE4(ptrace, compat_long_t, request, compat_long_t, pid,
+ compat_long_t, addr, compat_long_t, data)
{
struct task_struct *child;
long ret;
diff --git a/kernel/rcu/Makefile b/kernel/rcu/Makefile
index 01e9ec37a3e3..807ccfbf69b3 100644
--- a/kernel/rcu/Makefile
+++ b/kernel/rcu/Makefile
@@ -1,5 +1,5 @@
obj-y += update.o srcu.o
-obj-$(CONFIG_RCU_TORTURE_TEST) += torture.o
+obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
obj-$(CONFIG_TREE_RCU) += tree.o
obj-$(CONFIG_TREE_PREEMPT_RCU) += tree.o
obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o
diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h
index 79c3877e9c5b..bfda2726ca45 100644
--- a/kernel/rcu/rcu.h
+++ b/kernel/rcu/rcu.h
@@ -12,8 +12,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright IBM Corporation, 2011
*
@@ -23,6 +23,7 @@
#ifndef __LINUX_RCU_H
#define __LINUX_RCU_H
+#include <trace/events/rcu.h>
#ifdef CONFIG_RCU_TRACE
#define RCU_TRACE(stmt) stmt
#else /* #ifdef CONFIG_RCU_TRACE */
@@ -116,8 +117,6 @@ static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head)
}
}
-extern int rcu_expedited;
-
#ifdef CONFIG_RCU_STALL_COMMON
extern int rcu_cpu_stall_suppress;
diff --git a/kernel/rcu/torture.c b/kernel/rcu/rcutorture.c
index 732f8ae3086a..bd30bc61bc05 100644
--- a/kernel/rcu/torture.c
+++ b/kernel/rcu/rcutorture.c
@@ -12,8 +12,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright (C) IBM Corporation, 2005, 2006
*
@@ -48,110 +48,58 @@
#include <linux/slab.h>
#include <linux/trace_clock.h>
#include <asm/byteorder.h>
+#include <linux/torture.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and Josh Triplett <josh@freedesktop.org>");
-MODULE_ALIAS("rcutorture");
-#ifdef MODULE_PARAM_PREFIX
-#undef MODULE_PARAM_PREFIX
-#endif
-#define MODULE_PARAM_PREFIX "rcutorture."
-
-static int fqs_duration;
-module_param(fqs_duration, int, 0444);
-MODULE_PARM_DESC(fqs_duration, "Duration of fqs bursts (us), 0 to disable");
-static int fqs_holdoff;
-module_param(fqs_holdoff, int, 0444);
-MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)");
-static int fqs_stutter = 3;
-module_param(fqs_stutter, int, 0444);
-MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
-static bool gp_exp;
-module_param(gp_exp, bool, 0444);
-MODULE_PARM_DESC(gp_exp, "Use expedited GP wait primitives");
-static bool gp_normal;
-module_param(gp_normal, bool, 0444);
-MODULE_PARM_DESC(gp_normal, "Use normal (non-expedited) GP wait primitives");
-static int irqreader = 1;
-module_param(irqreader, int, 0444);
-MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
-static int n_barrier_cbs;
-module_param(n_barrier_cbs, int, 0444);
-MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
-static int nfakewriters = 4;
-module_param(nfakewriters, int, 0444);
-MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
-static int nreaders = -1;
-module_param(nreaders, int, 0444);
-MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
-static int object_debug;
-module_param(object_debug, int, 0444);
-MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
-static int onoff_holdoff;
-module_param(onoff_holdoff, int, 0444);
-MODULE_PARM_DESC(onoff_holdoff, "Time after boot before CPU hotplugs (s)");
-static int onoff_interval;
-module_param(onoff_interval, int, 0444);
-MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
-static int shuffle_interval = 3;
-module_param(shuffle_interval, int, 0444);
-MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
-static int shutdown_secs;
-module_param(shutdown_secs, int, 0444);
-MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), <= zero to disable.");
-static int stall_cpu;
-module_param(stall_cpu, int, 0444);
-MODULE_PARM_DESC(stall_cpu, "Stall duration (s), zero to disable.");
-static int stall_cpu_holdoff = 10;
-module_param(stall_cpu_holdoff, int, 0444);
-MODULE_PARM_DESC(stall_cpu_holdoff, "Time to wait before starting stall (s).");
-static int stat_interval = 60;
-module_param(stat_interval, int, 0644);
-MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
-static int stutter = 5;
-module_param(stutter, int, 0444);
-MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
-static int test_boost = 1;
-module_param(test_boost, int, 0444);
-MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
-static int test_boost_duration = 4;
-module_param(test_boost_duration, int, 0444);
-MODULE_PARM_DESC(test_boost_duration, "Duration of each boost test, seconds.");
-static int test_boost_interval = 7;
-module_param(test_boost_interval, int, 0444);
-MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds.");
-static bool test_no_idle_hz = true;
-module_param(test_no_idle_hz, bool, 0444);
-MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
+
+torture_param(int, fqs_duration, 0,
+ "Duration of fqs bursts (us), 0 to disable");
+torture_param(int, fqs_holdoff, 0, "Holdoff time within fqs bursts (us)");
+torture_param(int, fqs_stutter, 3, "Wait time between fqs bursts (s)");
+torture_param(bool, gp_exp, false, "Use expedited GP wait primitives");
+torture_param(bool, gp_normal, false,
+ "Use normal (non-expedited) GP wait primitives");
+torture_param(int, irqreader, 1, "Allow RCU readers from irq handlers");
+torture_param(int, n_barrier_cbs, 0,
+ "# of callbacks/kthreads for barrier testing");
+torture_param(int, nfakewriters, 4, "Number of RCU fake writer threads");
+torture_param(int, nreaders, -1, "Number of RCU reader threads");
+torture_param(int, object_debug, 0,
+ "Enable debug-object double call_rcu() testing");
+torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)");
+torture_param(int, onoff_interval, 0,
+ "Time between CPU hotplugs (s), 0=disable");
+torture_param(int, shuffle_interval, 3, "Number of seconds between shuffles");
+torture_param(int, shutdown_secs, 0, "Shutdown time (s), <= zero to disable.");
+torture_param(int, stall_cpu, 0, "Stall duration (s), zero to disable.");
+torture_param(int, stall_cpu_holdoff, 10,
+ "Time to wait before starting stall (s).");
+torture_param(int, stat_interval, 60,
+ "Number of seconds between stats printk()s");
+torture_param(int, stutter, 5, "Number of seconds to run/halt test");
+torture_param(int, test_boost, 1, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
+torture_param(int, test_boost_duration, 4,
+ "Duration of each boost test, seconds.");
+torture_param(int, test_boost_interval, 7,
+ "Interval between boost tests, seconds.");
+torture_param(bool, test_no_idle_hz, true,
+ "Test support for tickless idle CPUs");
+torture_param(bool, verbose, true,
+ "Enable verbose debugging printk()s");
+
static char *torture_type = "rcu";
module_param(torture_type, charp, 0444);
MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, ...)");
-static bool verbose;
-module_param(verbose, bool, 0444);
-MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
-
-#define TORTURE_FLAG "-torture:"
-#define PRINTK_STRING(s) \
- do { pr_alert("%s" TORTURE_FLAG s "\n", torture_type); } while (0)
-#define VERBOSE_PRINTK_STRING(s) \
- do { if (verbose) pr_alert("%s" TORTURE_FLAG s "\n", torture_type); } while (0)
-#define VERBOSE_PRINTK_ERRSTRING(s) \
- do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0)
static int nrealreaders;
static struct task_struct *writer_task;
static struct task_struct **fakewriter_tasks;
static struct task_struct **reader_tasks;
static struct task_struct *stats_task;
-static struct task_struct *shuffler_task;
-static struct task_struct *stutter_task;
static struct task_struct *fqs_task;
static struct task_struct *boost_tasks[NR_CPUS];
-static struct task_struct *shutdown_task;
-#ifdef CONFIG_HOTPLUG_CPU
-static struct task_struct *onoff_task;
-#endif /* #ifdef CONFIG_HOTPLUG_CPU */
static struct task_struct *stall_task;
static struct task_struct **barrier_cbs_tasks;
static struct task_struct *barrier_task;
@@ -170,10 +118,10 @@ static struct rcu_torture __rcu *rcu_torture_current;
static unsigned long rcu_torture_current_version;
static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN];
static DEFINE_SPINLOCK(rcu_torture_lock);
-static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) =
- { 0 };
-static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_batch) =
- { 0 };
+static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1],
+ rcu_torture_count) = { 0 };
+static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1],
+ rcu_torture_batch) = { 0 };
static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1];
static atomic_t n_rcu_torture_alloc;
static atomic_t n_rcu_torture_alloc_fail;
@@ -186,22 +134,9 @@ static long n_rcu_torture_boost_rterror;
static long n_rcu_torture_boost_failure;
static long n_rcu_torture_boosts;
static long n_rcu_torture_timers;
-static long n_offline_attempts;
-static long n_offline_successes;
-static unsigned long sum_offline;
-static int min_offline = -1;
-static int max_offline;
-static long n_online_attempts;
-static long n_online_successes;
-static unsigned long sum_online;
-static int min_online = -1;
-static int max_online;
static long n_barrier_attempts;
static long n_barrier_successes;
static struct list_head rcu_torture_removed;
-static cpumask_var_t shuffle_tmp_mask;
-
-static int stutter_pause_test;
#if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE)
#define RCUTORTURE_RUNNABLE_INIT 1
@@ -232,7 +167,6 @@ static u64 notrace rcu_trace_clock_local(void)
}
#endif /* #else #ifdef CONFIG_RCU_TRACE */
-static unsigned long shutdown_time; /* jiffies to system shutdown. */
static unsigned long boost_starttime; /* jiffies of next boost test start. */
DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */
/* and boost task create/destroy. */
@@ -242,51 +176,6 @@ static atomic_t barrier_cbs_invoked; /* Barrier callbacks invoked. */
static wait_queue_head_t *barrier_cbs_wq; /* Coordinate barrier testing. */
static DECLARE_WAIT_QUEUE_HEAD(barrier_wq);
-/* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */
-
-#define FULLSTOP_DONTSTOP 0 /* Normal operation. */
-#define FULLSTOP_SHUTDOWN 1 /* System shutdown with rcutorture running. */
-#define FULLSTOP_RMMOD 2 /* Normal rmmod of rcutorture. */
-static int fullstop = FULLSTOP_RMMOD;
-/*
- * Protect fullstop transitions and spawning of kthreads.
- */
-static DEFINE_MUTEX(fullstop_mutex);
-
-/* Forward reference. */
-static void rcu_torture_cleanup(void);
-
-/*
- * Detect and respond to a system shutdown.
- */
-static int
-rcutorture_shutdown_notify(struct notifier_block *unused1,
- unsigned long unused2, void *unused3)
-{
- mutex_lock(&fullstop_mutex);
- if (fullstop == FULLSTOP_DONTSTOP)
- fullstop = FULLSTOP_SHUTDOWN;
- else
- pr_warn(/* but going down anyway, so... */
- "Concurrent 'rmmod rcutorture' and shutdown illegal!\n");
- mutex_unlock(&fullstop_mutex);
- return NOTIFY_DONE;
-}
-
-/*
- * Absorb kthreads into a kernel function that won't return, so that
- * they won't ever access module text or data again.
- */
-static void rcutorture_shutdown_absorb(const char *title)
-{
- if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) {
- pr_notice(
- "rcutorture thread %s parking due to system shutdown\n",
- title);
- schedule_timeout_uninterruptible(MAX_SCHEDULE_TIMEOUT);
- }
-}
-
/*
* Allocate an element from the rcu_tortures pool.
*/
@@ -320,44 +209,6 @@ rcu_torture_free(struct rcu_torture *p)
spin_unlock_bh(&rcu_torture_lock);
}
-struct rcu_random_state {
- unsigned long rrs_state;
- long rrs_count;
-};
-
-#define RCU_RANDOM_MULT 39916801 /* prime */
-#define RCU_RANDOM_ADD 479001701 /* prime */
-#define RCU_RANDOM_REFRESH 10000
-
-#define DEFINE_RCU_RANDOM(name) struct rcu_random_state name = { 0, 0 }
-
-/*
- * Crude but fast random-number generator. Uses a linear congruential
- * generator, with occasional help from cpu_clock().
- */
-static unsigned long
-rcu_random(struct rcu_random_state *rrsp)
-{
- if (--rrsp->rrs_count < 0) {
- rrsp->rrs_state += (unsigned long)local_clock();
- rrsp->rrs_count = RCU_RANDOM_REFRESH;
- }
- rrsp->rrs_state = rrsp->rrs_state * RCU_RANDOM_MULT + RCU_RANDOM_ADD;
- return swahw32(rrsp->rrs_state);
-}
-
-static void
-rcu_stutter_wait(const char *title)
-{
- while (stutter_pause_test || !rcutorture_runnable) {
- if (rcutorture_runnable)
- schedule_timeout_interruptible(1);
- else
- schedule_timeout_interruptible(round_jiffies_relative(HZ));
- rcutorture_shutdown_absorb(title);
- }
-}
-
/*
* Operations vector for selecting different types of tests.
*/
@@ -365,7 +216,7 @@ rcu_stutter_wait(const char *title)
struct rcu_torture_ops {
void (*init)(void);
int (*readlock)(void);
- void (*read_delay)(struct rcu_random_state *rrsp);
+ void (*read_delay)(struct torture_random_state *rrsp);
void (*readunlock)(int idx);
int (*completed)(void);
void (*deferred_free)(struct rcu_torture *p);
@@ -392,7 +243,7 @@ static int rcu_torture_read_lock(void) __acquires(RCU)
return 0;
}
-static void rcu_read_delay(struct rcu_random_state *rrsp)
+static void rcu_read_delay(struct torture_random_state *rrsp)
{
const unsigned long shortdelay_us = 200;
const unsigned long longdelay_ms = 50;
@@ -401,12 +252,13 @@ static void rcu_read_delay(struct rcu_random_state *rrsp)
* period, and we want a long delay occasionally to trigger
* force_quiescent_state. */
- if (!(rcu_random(rrsp) % (nrealreaders * 2000 * longdelay_ms)))
+ if (!(torture_random(rrsp) % (nrealreaders * 2000 * longdelay_ms)))
mdelay(longdelay_ms);
- if (!(rcu_random(rrsp) % (nrealreaders * 2 * shortdelay_us)))
+ if (!(torture_random(rrsp) % (nrealreaders * 2 * shortdelay_us)))
udelay(shortdelay_us);
#ifdef CONFIG_PREEMPT
- if (!preempt_count() && !(rcu_random(rrsp) % (nrealreaders * 20000)))
+ if (!preempt_count() &&
+ !(torture_random(rrsp) % (nrealreaders * 20000)))
preempt_schedule(); /* No QS if preempt_disable() in effect */
#endif
}
@@ -427,7 +279,7 @@ rcu_torture_cb(struct rcu_head *p)
int i;
struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu);
- if (fullstop != FULLSTOP_DONTSTOP) {
+ if (torture_must_stop_irq()) {
/* Test is ending, just drop callbacks on the floor. */
/* The next initialization will pick up the pieces. */
return;
@@ -520,6 +372,48 @@ static struct rcu_torture_ops rcu_bh_ops = {
};
/*
+ * Don't even think about trying any of these in real life!!!
+ * The names includes "busted", and they really means it!
+ * The only purpose of these functions is to provide a buggy RCU
+ * implementation to make sure that rcutorture correctly emits
+ * buggy-RCU error messages.
+ */
+static void rcu_busted_torture_deferred_free(struct rcu_torture *p)
+{
+ /* This is a deliberate bug for testing purposes only! */
+ rcu_torture_cb(&p->rtort_rcu);
+}
+
+static void synchronize_rcu_busted(void)
+{
+ /* This is a deliberate bug for testing purposes only! */
+}
+
+static void
+call_rcu_busted(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
+{
+ /* This is a deliberate bug for testing purposes only! */
+ func(head);
+}
+
+static struct rcu_torture_ops rcu_busted_ops = {
+ .init = rcu_sync_torture_init,
+ .readlock = rcu_torture_read_lock,
+ .read_delay = rcu_read_delay, /* just reuse rcu's version. */
+ .readunlock = rcu_torture_read_unlock,
+ .completed = rcu_no_completed,
+ .deferred_free = rcu_busted_torture_deferred_free,
+ .sync = synchronize_rcu_busted,
+ .exp_sync = synchronize_rcu_busted,
+ .call = call_rcu_busted,
+ .cb_barrier = NULL,
+ .fqs = NULL,
+ .stats = NULL,
+ .irq_capable = 1,
+ .name = "rcu_busted"
+};
+
+/*
* Definitions for srcu torture testing.
*/
@@ -530,7 +424,7 @@ static int srcu_torture_read_lock(void) __acquires(&srcu_ctl)
return srcu_read_lock(&srcu_ctl);
}
-static void srcu_read_delay(struct rcu_random_state *rrsp)
+static void srcu_read_delay(struct torture_random_state *rrsp)
{
long delay;
const long uspertick = 1000000 / HZ;
@@ -538,7 +432,8 @@ static void srcu_read_delay(struct rcu_random_state *rrsp)
/* We want there to be long-running readers, but not all the time. */
- delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay * uspertick);
+ delay = torture_random(rrsp) %
+ (nrealreaders * 2 * longdelay * uspertick);
if (!delay)
schedule_timeout_interruptible(longdelay);
else
@@ -677,12 +572,12 @@ static int rcu_torture_boost(void *arg)
struct rcu_boost_inflight rbi = { .inflight = 0 };
struct sched_param sp;
- VERBOSE_PRINTK_STRING("rcu_torture_boost started");
+ VERBOSE_TOROUT_STRING("rcu_torture_boost started");
/* Set real-time priority. */
sp.sched_priority = 1;
if (sched_setscheduler(current, SCHED_FIFO, &sp) < 0) {
- VERBOSE_PRINTK_STRING("rcu_torture_boost RT prio failed!");
+ VERBOSE_TOROUT_STRING("rcu_torture_boost RT prio failed!");
n_rcu_torture_boost_rterror++;
}
@@ -693,9 +588,8 @@ static int rcu_torture_boost(void *arg)
oldstarttime = boost_starttime;
while (ULONG_CMP_LT(jiffies, oldstarttime)) {
schedule_timeout_interruptible(oldstarttime - jiffies);
- rcu_stutter_wait("rcu_torture_boost");
- if (kthread_should_stop() ||
- fullstop != FULLSTOP_DONTSTOP)
+ stutter_wait("rcu_torture_boost");
+ if (torture_must_stop())
goto checkwait;
}
@@ -710,15 +604,14 @@ static int rcu_torture_boost(void *arg)
call_rcu(&rbi.rcu, rcu_torture_boost_cb);
if (jiffies - call_rcu_time >
test_boost_duration * HZ - HZ / 2) {
- VERBOSE_PRINTK_STRING("rcu_torture_boost boosting failed");
+ VERBOSE_TOROUT_STRING("rcu_torture_boost boosting failed");
n_rcu_torture_boost_failure++;
}
call_rcu_time = jiffies;
}
cond_resched();
- rcu_stutter_wait("rcu_torture_boost");
- if (kthread_should_stop() ||
- fullstop != FULLSTOP_DONTSTOP)
+ stutter_wait("rcu_torture_boost");
+ if (torture_must_stop())
goto checkwait;
}
@@ -742,16 +635,17 @@ static int rcu_torture_boost(void *arg)
}
/* Go do the stutter. */
-checkwait: rcu_stutter_wait("rcu_torture_boost");
- } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
+checkwait: stutter_wait("rcu_torture_boost");
+ } while (!torture_must_stop());
/* Clean up and exit. */
- VERBOSE_PRINTK_STRING("rcu_torture_boost task stopping");
- rcutorture_shutdown_absorb("rcu_torture_boost");
- while (!kthread_should_stop() || rbi.inflight)
+ while (!kthread_should_stop() || rbi.inflight) {
+ torture_shutdown_absorb("rcu_torture_boost");
schedule_timeout_uninterruptible(1);
+ }
smp_mb(); /* order accesses to ->inflight before stack-frame death. */
destroy_rcu_head_on_stack(&rbi.rcu);
+ torture_kthread_stopping("rcu_torture_boost");
return 0;
}
@@ -766,7 +660,7 @@ rcu_torture_fqs(void *arg)
unsigned long fqs_resume_time;
int fqs_burst_remaining;
- VERBOSE_PRINTK_STRING("rcu_torture_fqs task started");
+ VERBOSE_TOROUT_STRING("rcu_torture_fqs task started");
do {
fqs_resume_time = jiffies + fqs_stutter * HZ;
while (ULONG_CMP_LT(jiffies, fqs_resume_time) &&
@@ -780,12 +674,9 @@ rcu_torture_fqs(void *arg)
udelay(fqs_holdoff);
fqs_burst_remaining -= fqs_holdoff;
}
- rcu_stutter_wait("rcu_torture_fqs");
- } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
- VERBOSE_PRINTK_STRING("rcu_torture_fqs task stopping");
- rcutorture_shutdown_absorb("rcu_torture_fqs");
- while (!kthread_should_stop())
- schedule_timeout_uninterruptible(1);
+ stutter_wait("rcu_torture_fqs");
+ } while (!torture_must_stop());
+ torture_kthread_stopping("rcu_torture_fqs");
return 0;
}
@@ -802,10 +693,10 @@ rcu_torture_writer(void *arg)
struct rcu_torture *rp;
struct rcu_torture *rp1;
struct rcu_torture *old_rp;
- static DEFINE_RCU_RANDOM(rand);
+ static DEFINE_TORTURE_RANDOM(rand);
- VERBOSE_PRINTK_STRING("rcu_torture_writer task started");
- set_user_nice(current, 19);
+ VERBOSE_TOROUT_STRING("rcu_torture_writer task started");
+ set_user_nice(current, MAX_NICE);
do {
schedule_timeout_uninterruptible(1);
@@ -813,7 +704,7 @@ rcu_torture_writer(void *arg)
if (rp == NULL)
continue;
rp->rtort_pipe_count = 0;
- udelay(rcu_random(&rand) & 0x3ff);
+ udelay(torture_random(&rand) & 0x3ff);
old_rp = rcu_dereference_check(rcu_torture_current,
current == writer_task);
rp->rtort_mbtest = 1;
@@ -826,7 +717,7 @@ rcu_torture_writer(void *arg)
atomic_inc(&rcu_torture_wcount[i]);
old_rp->rtort_pipe_count++;
if (gp_normal == gp_exp)
- exp = !!(rcu_random(&rand) & 0x80);
+ exp = !!(torture_random(&rand) & 0x80);
else
exp = gp_exp;
if (!exp) {
@@ -852,12 +743,9 @@ rcu_torture_writer(void *arg)
}
}
rcutorture_record_progress(++rcu_torture_current_version);
- rcu_stutter_wait("rcu_torture_writer");
- } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
- VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
- rcutorture_shutdown_absorb("rcu_torture_writer");
- while (!kthread_should_stop())
- schedule_timeout_uninterruptible(1);
+ stutter_wait("rcu_torture_writer");
+ } while (!torture_must_stop());
+ torture_kthread_stopping("rcu_torture_writer");
return 0;
}
@@ -868,19 +756,19 @@ rcu_torture_writer(void *arg)
static int
rcu_torture_fakewriter(void *arg)
{
- DEFINE_RCU_RANDOM(rand);
+ DEFINE_TORTURE_RANDOM(rand);
- VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
- set_user_nice(current, 19);
+ VERBOSE_TOROUT_STRING("rcu_torture_fakewriter task started");
+ set_user_nice(current, MAX_NICE);
do {
- schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
- udelay(rcu_random(&rand) & 0x3ff);
+ schedule_timeout_uninterruptible(1 + torture_random(&rand)%10);
+ udelay(torture_random(&rand) & 0x3ff);
if (cur_ops->cb_barrier != NULL &&
- rcu_random(&rand) % (nfakewriters * 8) == 0) {
+ torture_random(&rand) % (nfakewriters * 8) == 0) {
cur_ops->cb_barrier();
} else if (gp_normal == gp_exp) {
- if (rcu_random(&rand) & 0x80)
+ if (torture_random(&rand) & 0x80)
cur_ops->sync();
else
cur_ops->exp_sync();
@@ -889,13 +777,10 @@ rcu_torture_fakewriter(void *arg)
} else {
cur_ops->exp_sync();
}
- rcu_stutter_wait("rcu_torture_fakewriter");
- } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
+ stutter_wait("rcu_torture_fakewriter");
+ } while (!torture_must_stop());
- VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
- rcutorture_shutdown_absorb("rcu_torture_fakewriter");
- while (!kthread_should_stop())
- schedule_timeout_uninterruptible(1);
+ torture_kthread_stopping("rcu_torture_fakewriter");
return 0;
}
@@ -921,7 +806,7 @@ static void rcu_torture_timer(unsigned long unused)
int idx;
int completed;
int completed_end;
- static DEFINE_RCU_RANDOM(rand);
+ static DEFINE_TORTURE_RANDOM(rand);
static DEFINE_SPINLOCK(rand_lock);
struct rcu_torture *p;
int pipe_count;
@@ -980,14 +865,14 @@ rcu_torture_reader(void *arg)
int completed;
int completed_end;
int idx;
- DEFINE_RCU_RANDOM(rand);
+ DEFINE_TORTURE_RANDOM(rand);
struct rcu_torture *p;
int pipe_count;
struct timer_list t;
unsigned long long ts;
- VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
- set_user_nice(current, 19);
+ VERBOSE_TOROUT_STRING("rcu_torture_reader task started");
+ set_user_nice(current, MAX_NICE);
if (irqreader && cur_ops->irq_capable)
setup_timer_on_stack(&t, rcu_torture_timer, 0);
@@ -1034,14 +919,11 @@ rcu_torture_reader(void *arg)
preempt_enable();
cur_ops->readunlock(idx);
schedule();
- rcu_stutter_wait("rcu_torture_reader");
- } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
- VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
- rcutorture_shutdown_absorb("rcu_torture_reader");
+ stutter_wait("rcu_torture_reader");
+ } while (!torture_must_stop());
if (irqreader && cur_ops->irq_capable)
del_timer_sync(&t);
- while (!kthread_should_stop())
- schedule_timeout_uninterruptible(1);
+ torture_kthread_stopping("rcu_torture_reader");
return 0;
}
@@ -1083,13 +965,7 @@ rcu_torture_printk(char *page)
n_rcu_torture_boost_failure,
n_rcu_torture_boosts,
n_rcu_torture_timers);
- page += sprintf(page,
- "onoff: %ld/%ld:%ld/%ld %d,%d:%d,%d %lu:%lu (HZ=%d) ",
- n_online_successes, n_online_attempts,
- n_offline_successes, n_offline_attempts,
- min_online, max_online,
- min_offline, max_offline,
- sum_online, sum_offline, HZ);
+ page = torture_onoff_stats(page);
page += sprintf(page, "barrier: %ld/%ld:%ld",
n_barrier_successes,
n_barrier_attempts,
@@ -1150,123 +1026,17 @@ rcu_torture_stats_print(void)
/*
* Periodically prints torture statistics, if periodic statistics printing
* was specified via the stat_interval module parameter.
- *
- * No need to worry about fullstop here, since this one doesn't reference
- * volatile state or register callbacks.
*/
static int
rcu_torture_stats(void *arg)
{
- VERBOSE_PRINTK_STRING("rcu_torture_stats task started");
+ VERBOSE_TOROUT_STRING("rcu_torture_stats task started");
do {
schedule_timeout_interruptible(stat_interval * HZ);
rcu_torture_stats_print();
- rcutorture_shutdown_absorb("rcu_torture_stats");
- } while (!kthread_should_stop());
- VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping");
- return 0;
-}
-
-static int rcu_idle_cpu; /* Force all torture tasks off this CPU */
-
-/* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case
- * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs.
- */
-static void rcu_torture_shuffle_tasks(void)
-{
- int i;
-
- cpumask_setall(shuffle_tmp_mask);
- get_online_cpus();
-
- /* No point in shuffling if there is only one online CPU (ex: UP) */
- if (num_online_cpus() == 1) {
- put_online_cpus();
- return;
- }
-
- if (rcu_idle_cpu != -1)
- cpumask_clear_cpu(rcu_idle_cpu, shuffle_tmp_mask);
-
- set_cpus_allowed_ptr(current, shuffle_tmp_mask);
-
- if (reader_tasks) {
- for (i = 0; i < nrealreaders; i++)
- if (reader_tasks[i])
- set_cpus_allowed_ptr(reader_tasks[i],
- shuffle_tmp_mask);
- }
- if (fakewriter_tasks) {
- for (i = 0; i < nfakewriters; i++)
- if (fakewriter_tasks[i])
- set_cpus_allowed_ptr(fakewriter_tasks[i],
- shuffle_tmp_mask);
- }
- if (writer_task)
- set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask);
- if (stats_task)
- set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask);
- if (stutter_task)
- set_cpus_allowed_ptr(stutter_task, shuffle_tmp_mask);
- if (fqs_task)
- set_cpus_allowed_ptr(fqs_task, shuffle_tmp_mask);
- if (shutdown_task)
- set_cpus_allowed_ptr(shutdown_task, shuffle_tmp_mask);
-#ifdef CONFIG_HOTPLUG_CPU
- if (onoff_task)
- set_cpus_allowed_ptr(onoff_task, shuffle_tmp_mask);
-#endif /* #ifdef CONFIG_HOTPLUG_CPU */
- if (stall_task)
- set_cpus_allowed_ptr(stall_task, shuffle_tmp_mask);
- if (barrier_cbs_tasks)
- for (i = 0; i < n_barrier_cbs; i++)
- if (barrier_cbs_tasks[i])
- set_cpus_allowed_ptr(barrier_cbs_tasks[i],
- shuffle_tmp_mask);
- if (barrier_task)
- set_cpus_allowed_ptr(barrier_task, shuffle_tmp_mask);
-
- if (rcu_idle_cpu == -1)
- rcu_idle_cpu = num_online_cpus() - 1;
- else
- rcu_idle_cpu--;
-
- put_online_cpus();
-}
-
-/* Shuffle tasks across CPUs, with the intent of allowing each CPU in the
- * system to become idle at a time and cut off its timer ticks. This is meant
- * to test the support for such tickless idle CPU in RCU.
- */
-static int
-rcu_torture_shuffle(void *arg)
-{
- VERBOSE_PRINTK_STRING("rcu_torture_shuffle task started");
- do {
- schedule_timeout_interruptible(shuffle_interval * HZ);
- rcu_torture_shuffle_tasks();
- rcutorture_shutdown_absorb("rcu_torture_shuffle");
- } while (!kthread_should_stop());
- VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping");
- return 0;
-}
-
-/* Cause the rcutorture test to "stutter", starting and stopping all
- * threads periodically.
- */
-static int
-rcu_torture_stutter(void *arg)
-{
- VERBOSE_PRINTK_STRING("rcu_torture_stutter task started");
- do {
- schedule_timeout_interruptible(stutter * HZ);
- stutter_pause_test = 1;
- if (!kthread_should_stop())
- schedule_timeout_interruptible(stutter * HZ);
- stutter_pause_test = 0;
- rcutorture_shutdown_absorb("rcu_torture_stutter");
- } while (!kthread_should_stop());
- VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping");
+ torture_shutdown_absorb("rcu_torture_stats");
+ } while (!torture_must_stop());
+ torture_kthread_stopping("rcu_torture_stats");
return 0;
}
@@ -1293,10 +1063,6 @@ rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag)
onoff_interval, onoff_holdoff);
}
-static struct notifier_block rcutorture_shutdown_nb = {
- .notifier_call = rcutorture_shutdown_notify,
-};
-
static void rcutorture_booster_cleanup(int cpu)
{
struct task_struct *t;
@@ -1304,14 +1070,12 @@ static void rcutorture_booster_cleanup(int cpu)
if (boost_tasks[cpu] == NULL)
return;
mutex_lock(&boost_mutex);
- VERBOSE_PRINTK_STRING("Stopping rcu_torture_boost task");
t = boost_tasks[cpu];
boost_tasks[cpu] = NULL;
mutex_unlock(&boost_mutex);
/* This must be outside of the mutex, otherwise deadlock! */
- kthread_stop(t);
- boost_tasks[cpu] = NULL;
+ torture_stop_kthread(rcu_torture_boost, t);
}
static int rcutorture_booster_init(int cpu)
@@ -1323,13 +1087,13 @@ static int rcutorture_booster_init(int cpu)
/* Don't allow time recalculation while creating a new task. */
mutex_lock(&boost_mutex);
- VERBOSE_PRINTK_STRING("Creating rcu_torture_boost task");
+ VERBOSE_TOROUT_STRING("Creating rcu_torture_boost task");
boost_tasks[cpu] = kthread_create_on_node(rcu_torture_boost, NULL,
cpu_to_node(cpu),
"rcu_torture_boost");
if (IS_ERR(boost_tasks[cpu])) {
retval = PTR_ERR(boost_tasks[cpu]);
- VERBOSE_PRINTK_STRING("rcu_torture_boost task create failed");
+ VERBOSE_TOROUT_STRING("rcu_torture_boost task create failed");
n_rcu_torture_boost_ktrerror++;
boost_tasks[cpu] = NULL;
mutex_unlock(&boost_mutex);
@@ -1342,175 +1106,6 @@ static int rcutorture_booster_init(int cpu)
}
/*
- * Cause the rcutorture test to shutdown the system after the test has
- * run for the time specified by the shutdown_secs module parameter.
- */
-static int
-rcu_torture_shutdown(void *arg)
-{
- long delta;
- unsigned long jiffies_snap;
-
- VERBOSE_PRINTK_STRING("rcu_torture_shutdown task started");
- jiffies_snap = ACCESS_ONCE(jiffies);
- while (ULONG_CMP_LT(jiffies_snap, shutdown_time) &&
- !kthread_should_stop()) {
- delta = shutdown_time - jiffies_snap;
- if (verbose)
- pr_alert("%s" TORTURE_FLAG
- "rcu_torture_shutdown task: %lu jiffies remaining\n",
- torture_type, delta);
- schedule_timeout_interruptible(delta);
- jiffies_snap = ACCESS_ONCE(jiffies);
- }
- if (kthread_should_stop()) {
- VERBOSE_PRINTK_STRING("rcu_torture_shutdown task stopping");
- return 0;
- }
-
- /* OK, shut down the system. */
-
- VERBOSE_PRINTK_STRING("rcu_torture_shutdown task shutting down system");
- shutdown_task = NULL; /* Avoid self-kill deadlock. */
- rcu_torture_cleanup(); /* Get the success/failure message. */
- kernel_power_off(); /* Shut down the system. */
- return 0;
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-/*
- * Execute random CPU-hotplug operations at the interval specified
- * by the onoff_interval.
- */
-static int
-rcu_torture_onoff(void *arg)
-{
- int cpu;
- unsigned long delta;
- int maxcpu = -1;
- DEFINE_RCU_RANDOM(rand);
- int ret;
- unsigned long starttime;
-
- VERBOSE_PRINTK_STRING("rcu_torture_onoff task started");
- for_each_online_cpu(cpu)
- maxcpu = cpu;
- WARN_ON(maxcpu < 0);
- if (onoff_holdoff > 0) {
- VERBOSE_PRINTK_STRING("rcu_torture_onoff begin holdoff");
- schedule_timeout_interruptible(onoff_holdoff * HZ);
- VERBOSE_PRINTK_STRING("rcu_torture_onoff end holdoff");
- }
- while (!kthread_should_stop()) {
- cpu = (rcu_random(&rand) >> 4) % (maxcpu + 1);
- if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) {
- if (verbose)
- pr_alert("%s" TORTURE_FLAG
- "rcu_torture_onoff task: offlining %d\n",
- torture_type, cpu);
- starttime = jiffies;
- n_offline_attempts++;
- ret = cpu_down(cpu);
- if (ret) {
- if (verbose)
- pr_alert("%s" TORTURE_FLAG
- "rcu_torture_onoff task: offline %d failed: errno %d\n",
- torture_type, cpu, ret);
- } else {
- if (verbose)
- pr_alert("%s" TORTURE_FLAG
- "rcu_torture_onoff task: offlined %d\n",
- torture_type, cpu);
- n_offline_successes++;
- delta = jiffies - starttime;
- sum_offline += delta;
- if (min_offline < 0) {
- min_offline = delta;
- max_offline = delta;
- }
- if (min_offline > delta)
- min_offline = delta;
- if (max_offline < delta)
- max_offline = delta;
- }
- } else if (cpu_is_hotpluggable(cpu)) {
- if (verbose)
- pr_alert("%s" TORTURE_FLAG
- "rcu_torture_onoff task: onlining %d\n",
- torture_type, cpu);
- starttime = jiffies;
- n_online_attempts++;
- ret = cpu_up(cpu);
- if (ret) {
- if (verbose)
- pr_alert("%s" TORTURE_FLAG
- "rcu_torture_onoff task: online %d failed: errno %d\n",
- torture_type, cpu, ret);
- } else {
- if (verbose)
- pr_alert("%s" TORTURE_FLAG
- "rcu_torture_onoff task: onlined %d\n",
- torture_type, cpu);
- n_online_successes++;
- delta = jiffies - starttime;
- sum_online += delta;
- if (min_online < 0) {
- min_online = delta;
- max_online = delta;
- }
- if (min_online > delta)
- min_online = delta;
- if (max_online < delta)
- max_online = delta;
- }
- }
- schedule_timeout_interruptible(onoff_interval * HZ);
- }
- VERBOSE_PRINTK_STRING("rcu_torture_onoff task stopping");
- return 0;
-}
-
-static int
-rcu_torture_onoff_init(void)
-{
- int ret;
-
- if (onoff_interval <= 0)
- return 0;
- onoff_task = kthread_run(rcu_torture_onoff, NULL, "rcu_torture_onoff");
- if (IS_ERR(onoff_task)) {
- ret = PTR_ERR(onoff_task);
- onoff_task = NULL;
- return ret;
- }
- return 0;
-}
-
-static void rcu_torture_onoff_cleanup(void)
-{
- if (onoff_task == NULL)
- return;
- VERBOSE_PRINTK_STRING("Stopping rcu_torture_onoff task");
- kthread_stop(onoff_task);
- onoff_task = NULL;
-}
-
-#else /* #ifdef CONFIG_HOTPLUG_CPU */
-
-static int
-rcu_torture_onoff_init(void)
-{
- return 0;
-}
-
-static void rcu_torture_onoff_cleanup(void)
-{
-}
-
-#endif /* #else #ifdef CONFIG_HOTPLUG_CPU */
-
-/*
* CPU-stall kthread. It waits as specified by stall_cpu_holdoff, then
* induces a CPU stall for the time specified by stall_cpu.
*/
@@ -1518,11 +1113,11 @@ static int rcu_torture_stall(void *args)
{
unsigned long stop_at;
- VERBOSE_PRINTK_STRING("rcu_torture_stall task started");
+ VERBOSE_TOROUT_STRING("rcu_torture_stall task started");
if (stall_cpu_holdoff > 0) {
- VERBOSE_PRINTK_STRING("rcu_torture_stall begin holdoff");
+ VERBOSE_TOROUT_STRING("rcu_torture_stall begin holdoff");
schedule_timeout_interruptible(stall_cpu_holdoff * HZ);
- VERBOSE_PRINTK_STRING("rcu_torture_stall end holdoff");
+ VERBOSE_TOROUT_STRING("rcu_torture_stall end holdoff");
}
if (!kthread_should_stop()) {
stop_at = get_seconds() + stall_cpu;
@@ -1536,7 +1131,7 @@ static int rcu_torture_stall(void *args)
rcu_read_unlock();
pr_alert("rcu_torture_stall end.\n");
}
- rcutorture_shutdown_absorb("rcu_torture_stall");
+ torture_shutdown_absorb("rcu_torture_stall");
while (!kthread_should_stop())
schedule_timeout_interruptible(10 * HZ);
return 0;
@@ -1545,27 +1140,9 @@ static int rcu_torture_stall(void *args)
/* Spawn CPU-stall kthread, if stall_cpu specified. */
static int __init rcu_torture_stall_init(void)
{
- int ret;
-
if (stall_cpu <= 0)
return 0;
- stall_task = kthread_run(rcu_torture_stall, NULL, "rcu_torture_stall");
- if (IS_ERR(stall_task)) {
- ret = PTR_ERR(stall_task);
- stall_task = NULL;
- return ret;
- }
- return 0;
-}
-
-/* Clean up after the CPU-stall kthread, if one was spawned. */
-static void rcu_torture_stall_cleanup(void)
-{
- if (stall_task == NULL)
- return;
- VERBOSE_PRINTK_STRING("Stopping rcu_torture_stall_task.");
- kthread_stop(stall_task);
- stall_task = NULL;
+ return torture_create_kthread(rcu_torture_stall, NULL, stall_task);
}
/* Callback function for RCU barrier testing. */
@@ -1583,28 +1160,24 @@ static int rcu_torture_barrier_cbs(void *arg)
struct rcu_head rcu;
init_rcu_head_on_stack(&rcu);
- VERBOSE_PRINTK_STRING("rcu_torture_barrier_cbs task started");
- set_user_nice(current, 19);
+ VERBOSE_TOROUT_STRING("rcu_torture_barrier_cbs task started");
+ set_user_nice(current, MAX_NICE);
do {
wait_event(barrier_cbs_wq[myid],
(newphase =
ACCESS_ONCE(barrier_phase)) != lastphase ||
- kthread_should_stop() ||
- fullstop != FULLSTOP_DONTSTOP);
+ torture_must_stop());
lastphase = newphase;
smp_mb(); /* ensure barrier_phase load before ->call(). */
- if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP)
+ if (torture_must_stop())
break;
cur_ops->call(&rcu, rcu_torture_barrier_cbf);
if (atomic_dec_and_test(&barrier_cbs_count))
wake_up(&barrier_wq);
- } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
- VERBOSE_PRINTK_STRING("rcu_torture_barrier_cbs task stopping");
- rcutorture_shutdown_absorb("rcu_torture_barrier_cbs");
- while (!kthread_should_stop())
- schedule_timeout_interruptible(1);
+ } while (!torture_must_stop());
cur_ops->cb_barrier();
destroy_rcu_head_on_stack(&rcu);
+ torture_kthread_stopping("rcu_torture_barrier_cbs");
return 0;
}
@@ -1613,7 +1186,7 @@ static int rcu_torture_barrier(void *arg)
{
int i;
- VERBOSE_PRINTK_STRING("rcu_torture_barrier task starting");
+ VERBOSE_TOROUT_STRING("rcu_torture_barrier task starting");
do {
atomic_set(&barrier_cbs_invoked, 0);
atomic_set(&barrier_cbs_count, n_barrier_cbs);
@@ -1623,9 +1196,8 @@ static int rcu_torture_barrier(void *arg)
wake_up(&barrier_cbs_wq[i]);
wait_event(barrier_wq,
atomic_read(&barrier_cbs_count) == 0 ||
- kthread_should_stop() ||
- fullstop != FULLSTOP_DONTSTOP);
- if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP)
+ torture_must_stop());
+ if (torture_must_stop())
break;
n_barrier_attempts++;
cur_ops->cb_barrier(); /* Implies smp_mb() for wait_event(). */
@@ -1635,11 +1207,8 @@ static int rcu_torture_barrier(void *arg)
}
n_barrier_successes++;
schedule_timeout_interruptible(HZ / 10);
- } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
- VERBOSE_PRINTK_STRING("rcu_torture_barrier task stopping");
- rcutorture_shutdown_absorb("rcu_torture_barrier");
- while (!kthread_should_stop())
- schedule_timeout_interruptible(1);
+ } while (!torture_must_stop());
+ torture_kthread_stopping("rcu_torture_barrier");
return 0;
}
@@ -1672,24 +1241,13 @@ static int rcu_torture_barrier_init(void)
return -ENOMEM;
for (i = 0; i < n_barrier_cbs; i++) {
init_waitqueue_head(&barrier_cbs_wq[i]);
- barrier_cbs_tasks[i] = kthread_run(rcu_torture_barrier_cbs,
- (void *)(long)i,
- "rcu_torture_barrier_cbs");
- if (IS_ERR(barrier_cbs_tasks[i])) {
- ret = PTR_ERR(barrier_cbs_tasks[i]);
- VERBOSE_PRINTK_ERRSTRING("Failed to create rcu_torture_barrier_cbs");
- barrier_cbs_tasks[i] = NULL;
+ ret = torture_create_kthread(rcu_torture_barrier_cbs,
+ (void *)(long)i,
+ barrier_cbs_tasks[i]);
+ if (ret)
return ret;
- }
}
- barrier_task = kthread_run(rcu_torture_barrier, NULL,
- "rcu_torture_barrier");
- if (IS_ERR(barrier_task)) {
- ret = PTR_ERR(barrier_task);
- VERBOSE_PRINTK_ERRSTRING("Failed to create rcu_torture_barrier");
- barrier_task = NULL;
- }
- return 0;
+ return torture_create_kthread(rcu_torture_barrier, NULL, barrier_task);
}
/* Clean up after RCU barrier testing. */
@@ -1697,19 +1255,11 @@ static void rcu_torture_barrier_cleanup(void)
{
int i;
- if (barrier_task != NULL) {
- VERBOSE_PRINTK_STRING("Stopping rcu_torture_barrier task");
- kthread_stop(barrier_task);
- barrier_task = NULL;
- }
+ torture_stop_kthread(rcu_torture_barrier, barrier_task);
if (barrier_cbs_tasks != NULL) {
- for (i = 0; i < n_barrier_cbs; i++) {
- if (barrier_cbs_tasks[i] != NULL) {
- VERBOSE_PRINTK_STRING("Stopping rcu_torture_barrier_cbs task");
- kthread_stop(barrier_cbs_tasks[i]);
- barrier_cbs_tasks[i] = NULL;
- }
- }
+ for (i = 0; i < n_barrier_cbs; i++)
+ torture_stop_kthread(rcu_torture_barrier_cbs,
+ barrier_cbs_tasks[i]);
kfree(barrier_cbs_tasks);
barrier_cbs_tasks = NULL;
}
@@ -1747,90 +1297,42 @@ rcu_torture_cleanup(void)
{
int i;
- mutex_lock(&fullstop_mutex);
rcutorture_record_test_transition();
- if (fullstop == FULLSTOP_SHUTDOWN) {
- pr_warn(/* but going down anyway, so... */
- "Concurrent 'rmmod rcutorture' and shutdown illegal!\n");
- mutex_unlock(&fullstop_mutex);
- schedule_timeout_uninterruptible(10);
+ if (torture_cleanup()) {
if (cur_ops->cb_barrier != NULL)
cur_ops->cb_barrier();
return;
}
- fullstop = FULLSTOP_RMMOD;
- mutex_unlock(&fullstop_mutex);
- unregister_reboot_notifier(&rcutorture_shutdown_nb);
- rcu_torture_barrier_cleanup();
- rcu_torture_stall_cleanup();
- if (stutter_task) {
- VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task");
- kthread_stop(stutter_task);
- }
- stutter_task = NULL;
- if (shuffler_task) {
- VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
- kthread_stop(shuffler_task);
- free_cpumask_var(shuffle_tmp_mask);
- }
- shuffler_task = NULL;
- if (writer_task) {
- VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task");
- kthread_stop(writer_task);
- }
- writer_task = NULL;
+ rcu_torture_barrier_cleanup();
+ torture_stop_kthread(rcu_torture_stall, stall_task);
+ torture_stop_kthread(rcu_torture_writer, writer_task);
if (reader_tasks) {
- for (i = 0; i < nrealreaders; i++) {
- if (reader_tasks[i]) {
- VERBOSE_PRINTK_STRING(
- "Stopping rcu_torture_reader task");
- kthread_stop(reader_tasks[i]);
- }
- reader_tasks[i] = NULL;
- }
+ for (i = 0; i < nrealreaders; i++)
+ torture_stop_kthread(rcu_torture_reader,
+ reader_tasks[i]);
kfree(reader_tasks);
- reader_tasks = NULL;
}
rcu_torture_current = NULL;
if (fakewriter_tasks) {
for (i = 0; i < nfakewriters; i++) {
- if (fakewriter_tasks[i]) {
- VERBOSE_PRINTK_STRING(
- "Stopping rcu_torture_fakewriter task");
- kthread_stop(fakewriter_tasks[i]);
- }
- fakewriter_tasks[i] = NULL;
+ torture_stop_kthread(rcu_torture_fakewriter,
+ fakewriter_tasks[i]);
}
kfree(fakewriter_tasks);
fakewriter_tasks = NULL;
}
- if (stats_task) {
- VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
- kthread_stop(stats_task);
- }
- stats_task = NULL;
-
- if (fqs_task) {
- VERBOSE_PRINTK_STRING("Stopping rcu_torture_fqs task");
- kthread_stop(fqs_task);
- }
- fqs_task = NULL;
+ torture_stop_kthread(rcu_torture_stats, stats_task);
+ torture_stop_kthread(rcu_torture_fqs, fqs_task);
if ((test_boost == 1 && cur_ops->can_boost) ||
test_boost == 2) {
unregister_cpu_notifier(&rcutorture_cpu_nb);
for_each_possible_cpu(i)
rcutorture_booster_cleanup(i);
}
- if (shutdown_task != NULL) {
- VERBOSE_PRINTK_STRING("Stopping rcu_torture_shutdown task");
- kthread_stop(shutdown_task);
- }
- shutdown_task = NULL;
- rcu_torture_onoff_cleanup();
/* Wait for all RCU callbacks to fire. */
@@ -1841,8 +1343,7 @@ rcu_torture_cleanup(void)
if (atomic_read(&n_rcu_torture_error) || n_rcu_torture_barrier_error)
rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE");
- else if (n_online_successes != n_online_attempts ||
- n_offline_successes != n_offline_attempts)
+ else if (torture_onoff_failures())
rcu_torture_print_module_parms(cur_ops,
"End of test: RCU_HOTPLUG");
else
@@ -1911,12 +1412,11 @@ rcu_torture_init(void)
int i;
int cpu;
int firsterr = 0;
- int retval;
static struct rcu_torture_ops *torture_ops[] = {
- &rcu_ops, &rcu_bh_ops, &srcu_ops, &sched_ops,
+ &rcu_ops, &rcu_bh_ops, &rcu_busted_ops, &srcu_ops, &sched_ops,
};
- mutex_lock(&fullstop_mutex);
+ torture_init_begin(torture_type, verbose, &rcutorture_runnable);
/* Process args and tell the world that the torturer is on the job. */
for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
@@ -1931,7 +1431,7 @@ rcu_torture_init(void)
for (i = 0; i < ARRAY_SIZE(torture_ops); i++)
pr_alert(" %s", torture_ops[i]->name);
pr_alert("\n");
- mutex_unlock(&fullstop_mutex);
+ torture_init_end();
return -EINVAL;
}
if (cur_ops->fqs == NULL && fqs_duration != 0) {
@@ -1946,7 +1446,6 @@ rcu_torture_init(void)
else
nrealreaders = 2 * num_online_cpus();
rcu_torture_print_module_parms(cur_ops, "Start of test");
- fullstop = FULLSTOP_DONTSTOP;
/* Set up the freelist. */
@@ -1982,108 +1481,61 @@ rcu_torture_init(void)
/* Start up the kthreads. */
- VERBOSE_PRINTK_STRING("Creating rcu_torture_writer task");
- writer_task = kthread_create(rcu_torture_writer, NULL,
- "rcu_torture_writer");
- if (IS_ERR(writer_task)) {
- firsterr = PTR_ERR(writer_task);
- VERBOSE_PRINTK_ERRSTRING("Failed to create writer");
- writer_task = NULL;
+ firsterr = torture_create_kthread(rcu_torture_writer, NULL,
+ writer_task);
+ if (firsterr)
goto unwind;
- }
- wake_up_process(writer_task);
fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
GFP_KERNEL);
if (fakewriter_tasks == NULL) {
- VERBOSE_PRINTK_ERRSTRING("out of memory");
+ VERBOSE_TOROUT_ERRSTRING("out of memory");
firsterr = -ENOMEM;
goto unwind;
}
for (i = 0; i < nfakewriters; i++) {
- VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task");
- fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL,
- "rcu_torture_fakewriter");
- if (IS_ERR(fakewriter_tasks[i])) {
- firsterr = PTR_ERR(fakewriter_tasks[i]);
- VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter");
- fakewriter_tasks[i] = NULL;
+ firsterr = torture_create_kthread(rcu_torture_fakewriter,
+ NULL, fakewriter_tasks[i]);
+ if (firsterr)
goto unwind;
- }
}
reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
GFP_KERNEL);
if (reader_tasks == NULL) {
- VERBOSE_PRINTK_ERRSTRING("out of memory");
+ VERBOSE_TOROUT_ERRSTRING("out of memory");
firsterr = -ENOMEM;
goto unwind;
}
for (i = 0; i < nrealreaders; i++) {
- VERBOSE_PRINTK_STRING("Creating rcu_torture_reader task");
- reader_tasks[i] = kthread_run(rcu_torture_reader, NULL,
- "rcu_torture_reader");
- if (IS_ERR(reader_tasks[i])) {
- firsterr = PTR_ERR(reader_tasks[i]);
- VERBOSE_PRINTK_ERRSTRING("Failed to create reader");
- reader_tasks[i] = NULL;
+ firsterr = torture_create_kthread(rcu_torture_reader, NULL,
+ reader_tasks[i]);
+ if (firsterr)
goto unwind;
- }
}
if (stat_interval > 0) {
- VERBOSE_PRINTK_STRING("Creating rcu_torture_stats task");
- stats_task = kthread_run(rcu_torture_stats, NULL,
- "rcu_torture_stats");
- if (IS_ERR(stats_task)) {
- firsterr = PTR_ERR(stats_task);
- VERBOSE_PRINTK_ERRSTRING("Failed to create stats");
- stats_task = NULL;
+ firsterr = torture_create_kthread(rcu_torture_stats, NULL,
+ stats_task);
+ if (firsterr)
goto unwind;
- }
}
if (test_no_idle_hz) {
- rcu_idle_cpu = num_online_cpus() - 1;
-
- if (!alloc_cpumask_var(&shuffle_tmp_mask, GFP_KERNEL)) {
- firsterr = -ENOMEM;
- VERBOSE_PRINTK_ERRSTRING("Failed to alloc mask");
- goto unwind;
- }
-
- /* Create the shuffler thread */
- shuffler_task = kthread_run(rcu_torture_shuffle, NULL,
- "rcu_torture_shuffle");
- if (IS_ERR(shuffler_task)) {
- free_cpumask_var(shuffle_tmp_mask);
- firsterr = PTR_ERR(shuffler_task);
- VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler");
- shuffler_task = NULL;
+ firsterr = torture_shuffle_init(shuffle_interval * HZ);
+ if (firsterr)
goto unwind;
- }
}
if (stutter < 0)
stutter = 0;
if (stutter) {
- /* Create the stutter thread */
- stutter_task = kthread_run(rcu_torture_stutter, NULL,
- "rcu_torture_stutter");
- if (IS_ERR(stutter_task)) {
- firsterr = PTR_ERR(stutter_task);
- VERBOSE_PRINTK_ERRSTRING("Failed to create stutter");
- stutter_task = NULL;
+ firsterr = torture_stutter_init(stutter * HZ);
+ if (firsterr)
goto unwind;
- }
}
if (fqs_duration < 0)
fqs_duration = 0;
if (fqs_duration) {
- /* Create the stutter thread */
- fqs_task = kthread_run(rcu_torture_fqs, NULL,
- "rcu_torture_fqs");
- if (IS_ERR(fqs_task)) {
- firsterr = PTR_ERR(fqs_task);
- VERBOSE_PRINTK_ERRSTRING("Failed to create fqs");
- fqs_task = NULL;
+ /* Create the fqs thread */
+ torture_create_kthread(rcu_torture_fqs, NULL, fqs_task);
+ if (firsterr)
goto unwind;
- }
}
if (test_boost_interval < 1)
test_boost_interval = 1;
@@ -2097,49 +1549,31 @@ rcu_torture_init(void)
for_each_possible_cpu(i) {
if (cpu_is_offline(i))
continue; /* Heuristic: CPU can go offline. */
- retval = rcutorture_booster_init(i);
- if (retval < 0) {
- firsterr = retval;
+ firsterr = rcutorture_booster_init(i);
+ if (firsterr)
goto unwind;
- }
}
}
- if (shutdown_secs > 0) {
- shutdown_time = jiffies + shutdown_secs * HZ;
- shutdown_task = kthread_create(rcu_torture_shutdown, NULL,
- "rcu_torture_shutdown");
- if (IS_ERR(shutdown_task)) {
- firsterr = PTR_ERR(shutdown_task);
- VERBOSE_PRINTK_ERRSTRING("Failed to create shutdown");
- shutdown_task = NULL;
- goto unwind;
- }
- wake_up_process(shutdown_task);
- }
- i = rcu_torture_onoff_init();
- if (i != 0) {
- firsterr = i;
+ firsterr = torture_shutdown_init(shutdown_secs, rcu_torture_cleanup);
+ if (firsterr)
goto unwind;
- }
- register_reboot_notifier(&rcutorture_shutdown_nb);
- i = rcu_torture_stall_init();
- if (i != 0) {
- firsterr = i;
+ firsterr = torture_onoff_init(onoff_holdoff * HZ, onoff_interval * HZ);
+ if (firsterr)
goto unwind;
- }
- retval = rcu_torture_barrier_init();
- if (retval != 0) {
- firsterr = retval;
+ firsterr = rcu_torture_stall_init();
+ if (firsterr)
+ goto unwind;
+ firsterr = rcu_torture_barrier_init();
+ if (firsterr)
goto unwind;
- }
if (object_debug)
rcu_test_debug_objects();
rcutorture_record_test_transition();
- mutex_unlock(&fullstop_mutex);
+ torture_init_end();
return 0;
unwind:
- mutex_unlock(&fullstop_mutex);
+ torture_init_end();
rcu_torture_cleanup();
return firsterr;
}
diff --git a/kernel/rcu/srcu.c b/kernel/rcu/srcu.c
index 3318d8284384..c639556f3fa0 100644
--- a/kernel/rcu/srcu.c
+++ b/kernel/rcu/srcu.c
@@ -12,8 +12,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright (C) IBM Corporation, 2006
* Copyright (C) Fujitsu, 2012
@@ -36,8 +36,6 @@
#include <linux/delay.h>
#include <linux/srcu.h>
-#include <trace/events/rcu.h>
-
#include "rcu.h"
/*
@@ -398,7 +396,7 @@ void call_srcu(struct srcu_struct *sp, struct rcu_head *head,
rcu_batch_queue(&sp->batch_queue, head);
if (!sp->running) {
sp->running = true;
- schedule_delayed_work(&sp->work, 0);
+ queue_delayed_work(system_power_efficient_wq, &sp->work, 0);
}
spin_unlock_irqrestore(&sp->queue_lock, flags);
}
@@ -674,7 +672,8 @@ static void srcu_reschedule(struct srcu_struct *sp)
}
if (pending)
- schedule_delayed_work(&sp->work, SRCU_INTERVAL);
+ queue_delayed_work(system_power_efficient_wq,
+ &sp->work, SRCU_INTERVAL);
}
/*
diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c
index 1254f312d024..d9efcc13008c 100644
--- a/kernel/rcu/tiny.c
+++ b/kernel/rcu/tiny.c
@@ -12,8 +12,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright IBM Corporation, 2008
*
@@ -37,10 +37,6 @@
#include <linux/prefetch.h>
#include <linux/ftrace_event.h>
-#ifdef CONFIG_RCU_TRACE
-#include <trace/events/rcu.h>
-#endif /* #else #ifdef CONFIG_RCU_TRACE */
-
#include "rcu.h"
/* Forward declarations for tiny_plugin.h. */
diff --git a/kernel/rcu/tiny_plugin.h b/kernel/rcu/tiny_plugin.h
index 280d06cae352..431528520562 100644
--- a/kernel/rcu/tiny_plugin.h
+++ b/kernel/rcu/tiny_plugin.h
@@ -14,8 +14,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright (c) 2010 Linaro
*
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index b3d116cd072d..0c47e300210a 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -12,8 +12,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright IBM Corporation, 2008
*
@@ -58,8 +58,6 @@
#include <linux/suspend.h>
#include "tree.h"
-#include <trace/events/rcu.h>
-
#include "rcu.h"
MODULE_ALIAS("rcutree");
@@ -837,7 +835,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp,
* to the next. Only do this for the primary flavor of RCU.
*/
if (rdp->rsp == rcu_state &&
- ULONG_CMP_GE(ACCESS_ONCE(jiffies), rdp->rsp->jiffies_resched)) {
+ ULONG_CMP_GE(jiffies, rdp->rsp->jiffies_resched)) {
rdp->rsp->jiffies_resched += 5;
resched_cpu(rdp->cpu);
}
@@ -847,7 +845,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp,
static void record_gp_stall_check_time(struct rcu_state *rsp)
{
- unsigned long j = ACCESS_ONCE(jiffies);
+ unsigned long j = jiffies;
unsigned long j1;
rsp->gp_start = j;
@@ -1005,7 +1003,7 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)
if (rcu_cpu_stall_suppress || !rcu_gp_in_progress(rsp))
return;
- j = ACCESS_ONCE(jiffies);
+ j = jiffies;
/*
* Lots of memory barriers to reject false positives.
@@ -1423,13 +1421,14 @@ static int rcu_gp_init(struct rcu_state *rsp)
/* Advance to a new grace period and initialize state. */
record_gp_stall_check_time(rsp);
- smp_wmb(); /* Record GP times before starting GP. */
- rsp->gpnum++;
+ /* Record GP times before starting GP, hence smp_store_release(). */
+ smp_store_release(&rsp->gpnum, rsp->gpnum + 1);
trace_rcu_grace_period(rsp->name, rsp->gpnum, TPS("start"));
raw_spin_unlock_irq(&rnp->lock);
/* Exclude any concurrent CPU-hotplug operations. */
mutex_lock(&rsp->onoff_mutex);
+ smp_mb__after_unlock_lock(); /* ->gpnum increment before GP! */
/*
* Set the quiescent-state-needed bits in all the rcu_node
@@ -1557,10 +1556,11 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
}
rnp = rcu_get_root(rsp);
raw_spin_lock_irq(&rnp->lock);
- smp_mb__after_unlock_lock();
+ smp_mb__after_unlock_lock(); /* Order GP before ->completed update. */
rcu_nocb_gp_set(rnp, nocb);
- rsp->completed = rsp->gpnum; /* Declare grace period done. */
+ /* Declare grace period done. */
+ ACCESS_ONCE(rsp->completed) = rsp->gpnum;
trace_rcu_grace_period(rsp->name, rsp->completed, TPS("end"));
rsp->fqs_state = RCU_GP_IDLE;
rdp = this_cpu_ptr(rsp->rda);
@@ -2304,7 +2304,7 @@ static void force_quiescent_state(struct rcu_state *rsp)
if (rnp_old != NULL)
raw_spin_unlock(&rnp_old->fqslock);
if (ret) {
- rsp->n_force_qs_lh++;
+ ACCESS_ONCE(rsp->n_force_qs_lh)++;
return;
}
rnp_old = rnp;
@@ -2316,7 +2316,7 @@ static void force_quiescent_state(struct rcu_state *rsp)
smp_mb__after_unlock_lock();
raw_spin_unlock(&rnp_old->fqslock);
if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
- rsp->n_force_qs_lh++;
+ ACCESS_ONCE(rsp->n_force_qs_lh)++;
raw_spin_unlock_irqrestore(&rnp_old->lock, flags);
return; /* Someone beat us to it. */
}
@@ -2639,6 +2639,58 @@ void synchronize_rcu_bh(void)
}
EXPORT_SYMBOL_GPL(synchronize_rcu_bh);
+/**
+ * get_state_synchronize_rcu - Snapshot current RCU state
+ *
+ * Returns a cookie that is used by a later call to cond_synchronize_rcu()
+ * to determine whether or not a full grace period has elapsed in the
+ * meantime.
+ */
+unsigned long get_state_synchronize_rcu(void)
+{
+ /*
+ * Any prior manipulation of RCU-protected data must happen
+ * before the load from ->gpnum.
+ */
+ smp_mb(); /* ^^^ */
+
+ /*
+ * Make sure this load happens before the purportedly
+ * time-consuming work between get_state_synchronize_rcu()
+ * and cond_synchronize_rcu().
+ */
+ return smp_load_acquire(&rcu_state->gpnum);
+}
+EXPORT_SYMBOL_GPL(get_state_synchronize_rcu);
+
+/**
+ * cond_synchronize_rcu - Conditionally wait for an RCU grace period
+ *
+ * @oldstate: return value from earlier call to get_state_synchronize_rcu()
+ *
+ * If a full RCU grace period has elapsed since the earlier call to
+ * get_state_synchronize_rcu(), just return. Otherwise, invoke
+ * synchronize_rcu() to wait for a full grace period.
+ *
+ * Yes, this function does not take counter wrap into account. But
+ * counter wrap is harmless. If the counter wraps, we have waited for
+ * more than 2 billion grace periods (and way more on a 64-bit system!),
+ * so waiting for one additional grace period should be just fine.
+ */
+void cond_synchronize_rcu(unsigned long oldstate)
+{
+ unsigned long newstate;
+
+ /*
+ * Ensure that this load happens before any RCU-destructive
+ * actions the caller might carry out after we return.
+ */
+ newstate = smp_load_acquire(&rcu_state->completed);
+ if (ULONG_CMP_GE(oldstate, newstate))
+ synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(cond_synchronize_rcu);
+
static int synchronize_sched_expedited_cpu_stop(void *data)
{
/*
@@ -2880,7 +2932,7 @@ static int rcu_pending(int cpu)
* non-NULL, store an indication of whether all callbacks are lazy.
* (If there are no callbacks, all of them are deemed to be lazy.)
*/
-static int rcu_cpu_has_callbacks(int cpu, bool *all_lazy)
+static int __maybe_unused rcu_cpu_has_callbacks(int cpu, bool *all_lazy)
{
bool al = true;
bool hc = false;
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
index 8c19873f1ac9..75dc3c39a02a 100644
--- a/kernel/rcu/tree.h
+++ b/kernel/rcu/tree.h
@@ -13,8 +13,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright IBM Corporation, 2008
*
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 6e2ef4b2b920..962d1d589929 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -14,8 +14,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright Red Hat, 2009
* Copyright IBM Corporation, 2009
@@ -1586,11 +1586,13 @@ static void rcu_prepare_kthreads(int cpu)
* Because we not have RCU_FAST_NO_HZ, just check whether this CPU needs
* any flavor of RCU.
*/
+#ifndef CONFIG_RCU_NOCB_CPU_ALL
int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
{
*delta_jiffies = ULONG_MAX;
return rcu_cpu_has_callbacks(cpu, NULL);
}
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
/*
* Because we do not have RCU_FAST_NO_HZ, don't bother cleaning up
@@ -1656,7 +1658,7 @@ extern int tick_nohz_active;
* only if it has been awhile since the last time we did so. Afterwards,
* if there are any callbacks ready for immediate invocation, return true.
*/
-static bool rcu_try_advance_all_cbs(void)
+static bool __maybe_unused rcu_try_advance_all_cbs(void)
{
bool cbs_ready = false;
struct rcu_data *rdp;
@@ -1696,6 +1698,7 @@ static bool rcu_try_advance_all_cbs(void)
*
* The caller must have disabled interrupts.
*/
+#ifndef CONFIG_RCU_NOCB_CPU_ALL
int rcu_needs_cpu(int cpu, unsigned long *dj)
{
struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
@@ -1726,6 +1729,7 @@ int rcu_needs_cpu(int cpu, unsigned long *dj)
}
return 0;
}
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
/*
* Prepare a CPU for idle from an RCU perspective. The first major task
@@ -1739,6 +1743,7 @@ int rcu_needs_cpu(int cpu, unsigned long *dj)
*/
static void rcu_prepare_for_idle(int cpu)
{
+#ifndef CONFIG_RCU_NOCB_CPU_ALL
struct rcu_data *rdp;
struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
struct rcu_node *rnp;
@@ -1790,6 +1795,7 @@ static void rcu_prepare_for_idle(int cpu)
rcu_accelerate_cbs(rsp, rnp, rdp);
raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
}
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
}
/*
@@ -1799,11 +1805,12 @@ static void rcu_prepare_for_idle(int cpu)
*/
static void rcu_cleanup_after_idle(int cpu)
{
-
+#ifndef CONFIG_RCU_NOCB_CPU_ALL
if (rcu_is_nocb_cpu(cpu))
return;
if (rcu_try_advance_all_cbs())
invoke_rcu_core();
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
}
/*
@@ -2101,6 +2108,7 @@ static void rcu_init_one_nocb(struct rcu_node *rnp)
init_waitqueue_head(&rnp->nocb_gp_wq[1]);
}
+#ifndef CONFIG_RCU_NOCB_CPU_ALL
/* Is the specified CPU a no-CPUs CPU? */
bool rcu_is_nocb_cpu(int cpu)
{
@@ -2108,6 +2116,7 @@ bool rcu_is_nocb_cpu(int cpu)
return cpumask_test_cpu(cpu, rcu_nocb_mask);
return false;
}
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
/*
* Enqueue the specified string of rcu_head structures onto the specified
@@ -2893,7 +2902,7 @@ static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp)
* CPU unless the grace period has extended for too long.
*
* This code relies on the fact that all NO_HZ_FULL CPUs are also
- * CONFIG_RCU_NOCB_CPUs.
+ * CONFIG_RCU_NOCB_CPU CPUs.
*/
static bool rcu_nohz_full_cpu(struct rcu_state *rsp)
{
diff --git a/kernel/rcu/tree_trace.c b/kernel/rcu/tree_trace.c
index 4def475336d4..5cdc62e1beeb 100644
--- a/kernel/rcu/tree_trace.c
+++ b/kernel/rcu/tree_trace.c
@@ -12,8 +12,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright IBM Corporation, 2008
*
@@ -273,7 +273,7 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
seq_printf(m, "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu oqlen=%ld/%ld\n",
rsp->n_force_qs, rsp->n_force_qs_ngp,
rsp->n_force_qs - rsp->n_force_qs_ngp,
- rsp->n_force_qs_lh, rsp->qlen_lazy, rsp->qlen);
+ ACCESS_ONCE(rsp->n_force_qs_lh), rsp->qlen_lazy, rsp->qlen);
for (rnp = &rsp->node[0]; rnp - &rsp->node[0] < rcu_num_nodes; rnp++) {
if (rnp->level != level) {
seq_puts(m, "\n");
diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
index c54609faf233..4c0a9b0af469 100644
--- a/kernel/rcu/update.c
+++ b/kernel/rcu/update.c
@@ -12,8 +12,8 @@
* GNU 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.
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright IBM Corporation, 2001
*
@@ -49,7 +49,6 @@
#include <linux/module.h>
#define CREATE_TRACE_POINTS
-#include <trace/events/rcu.h>
#include "rcu.h"
diff --git a/kernel/resource.c b/kernel/resource.c
index 3f285dce9347..673061c06da1 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -432,11 +432,6 @@ static void resource_clip(struct resource *res, resource_size_t min,
res->end = max;
}
-static bool resource_contains(struct resource *res1, struct resource *res2)
-{
- return res1->start <= res2->start && res1->end >= res2->end;
-}
-
/*
* Find empty slot in the resource tree with the given range and
* alignment constraints
@@ -471,10 +466,11 @@ static int __find_resource(struct resource *root, struct resource *old,
arch_remove_reservations(&tmp);
/* Check for overflow after ALIGN() */
- avail = *new;
avail.start = ALIGN(tmp.start, constraint->align);
avail.end = tmp.end;
+ avail.flags = new->flags & ~IORESOURCE_UNSET;
if (avail.start >= tmp.start) {
+ alloc.flags = avail.flags;
alloc.start = constraint->alignf(constraint->alignf_data, &avail,
size, constraint->align);
alloc.end = alloc.start + size - 1;
@@ -949,8 +945,8 @@ struct resource * __request_region(struct resource *parent,
res->name = name;
res->start = start;
res->end = start + n - 1;
- res->flags = IORESOURCE_BUSY;
- res->flags |= flags;
+ res->flags = resource_type(parent);
+ res->flags |= IORESOURCE_BUSY | flags;
write_lock(&resource_lock);
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
index 9a95c8c2af2a..ab32b7b0db5c 100644
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -13,7 +13,7 @@ endif
obj-y += core.o proc.o clock.o cputime.o
obj-y += idle_task.o fair.o rt.o deadline.o stop_task.o
-obj-y += wait.o completion.o
+obj-y += wait.o completion.o idle.o
obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o
obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
obj-$(CONFIG_SCHEDSTATS) += stats.o
diff --git a/kernel/sched/auto_group.c b/kernel/sched/auto_group.c
index 4a073539c58e..e73efba98301 100644
--- a/kernel/sched/auto_group.c
+++ b/kernel/sched/auto_group.c
@@ -203,7 +203,7 @@ int proc_sched_autogroup_set_nice(struct task_struct *p, int nice)
struct autogroup *ag;
int err;
- if (nice < -20 || nice > 19)
+ if (nice < MIN_NICE || nice > MAX_NICE)
return -EINVAL;
err = security_task_setnice(current, nice);
diff --git a/kernel/sched/clock.c b/kernel/sched/clock.c
index 43c2bcc35761..b30a2924ef14 100644
--- a/kernel/sched/clock.c
+++ b/kernel/sched/clock.c
@@ -301,14 +301,14 @@ u64 sched_clock_cpu(int cpu)
if (unlikely(!sched_clock_running))
return 0ull;
- preempt_disable();
+ preempt_disable_notrace();
scd = cpu_sdc(cpu);
if (cpu != smp_processor_id())
clock = sched_clock_remote(scd);
else
clock = sched_clock_local(scd);
- preempt_enable();
+ preempt_enable_notrace();
return clock;
}
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index b46131ef6aab..9cae286824bb 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -432,7 +432,7 @@ void hrtick_start(struct rq *rq, u64 delay)
if (rq == this_rq()) {
__hrtick_restart(rq);
} else if (!rq->hrtick_csd_pending) {
- __smp_call_function_single(cpu_of(rq), &rq->hrtick_csd, 0);
+ smp_call_function_single_async(cpu_of(rq), &rq->hrtick_csd);
rq->hrtick_csd_pending = 1;
}
}
@@ -555,12 +555,15 @@ void resched_cpu(int cpu)
* selecting an idle cpu will add more delays to the timers than intended
* (as that cpu's timer base may not be uptodate wrt jiffies etc).
*/
-int get_nohz_timer_target(void)
+int get_nohz_timer_target(int pinned)
{
int cpu = smp_processor_id();
int i;
struct sched_domain *sd;
+ if (pinned || !get_sysctl_timer_migration() || !idle_cpu(cpu))
+ return cpu;
+
rcu_read_lock();
for_each_domain(cpu, sd) {
for_each_cpu(i, sched_domain_span(sd)) {
@@ -823,19 +826,13 @@ static void update_rq_clock_task(struct rq *rq, s64 delta)
#endif
#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
if (static_key_false((&paravirt_steal_rq_enabled))) {
- u64 st;
-
steal = paravirt_steal_clock(cpu_of(rq));
steal -= rq->prev_steal_time_rq;
if (unlikely(steal > delta))
steal = delta;
- st = steal_ticks(steal);
- steal = st * TICK_NSEC;
-
rq->prev_steal_time_rq += steal;
-
delta -= steal;
}
#endif
@@ -1745,8 +1742,10 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p)
p->numa_scan_seq = p->mm ? p->mm->numa_scan_seq : 0;
p->numa_scan_period = sysctl_numa_balancing_scan_delay;
p->numa_work.next = &p->numa_work;
- p->numa_faults = NULL;
- p->numa_faults_buffer = NULL;
+ p->numa_faults_memory = NULL;
+ p->numa_faults_buffer_memory = NULL;
+ p->last_task_numa_placement = 0;
+ p->last_sum_exec_runtime = 0;
INIT_LIST_HEAD(&p->numa_entry);
p->numa_group = NULL;
@@ -1952,7 +1951,7 @@ static int dl_overflow(struct task_struct *p, int policy,
{
struct dl_bw *dl_b = dl_bw_of(task_cpu(p));
- u64 period = attr->sched_period;
+ u64 period = attr->sched_period ?: attr->sched_deadline;
u64 runtime = attr->sched_runtime;
u64 new_bw = dl_policy(policy) ? to_ratio(period, runtime) : 0;
int cpus, err = -1;
@@ -2149,8 +2148,6 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev)
if (mm)
mmdrop(mm);
if (unlikely(prev_state == TASK_DEAD)) {
- task_numa_free(prev);
-
if (prev->sched_class->task_dead)
prev->sched_class->task_dead(prev);
@@ -2167,13 +2164,6 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev)
#ifdef CONFIG_SMP
-/* assumes rq->lock is held */
-static inline void pre_schedule(struct rq *rq, struct task_struct *prev)
-{
- if (prev->sched_class->pre_schedule)
- prev->sched_class->pre_schedule(rq, prev);
-}
-
/* rq->lock is NOT held, but preemption is disabled */
static inline void post_schedule(struct rq *rq)
{
@@ -2191,10 +2181,6 @@ static inline void post_schedule(struct rq *rq)
#else
-static inline void pre_schedule(struct rq *rq, struct task_struct *p)
-{
-}
-
static inline void post_schedule(struct rq *rq)
{
}
@@ -2510,8 +2496,13 @@ void __kprobes preempt_count_add(int val)
DEBUG_LOCKS_WARN_ON((preempt_count() & PREEMPT_MASK) >=
PREEMPT_MASK - 10);
#endif
- if (preempt_count() == val)
- trace_preempt_off(CALLER_ADDR0, get_parent_ip(CALLER_ADDR1));
+ if (preempt_count() == val) {
+ unsigned long ip = get_parent_ip(CALLER_ADDR1);
+#ifdef CONFIG_DEBUG_PREEMPT
+ current->preempt_disable_ip = ip;
+#endif
+ trace_preempt_off(CALLER_ADDR0, ip);
+ }
}
EXPORT_SYMBOL(preempt_count_add);
@@ -2554,6 +2545,13 @@ static noinline void __schedule_bug(struct task_struct *prev)
print_modules();
if (irqs_disabled())
print_irqtrace_events(prev);
+#ifdef CONFIG_DEBUG_PREEMPT
+ if (in_atomic_preempt_off()) {
+ pr_err("Preemption disabled at:");
+ print_ip_sym(current->preempt_disable_ip);
+ pr_cont("\n");
+ }
+#endif
dump_stack();
add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
}
@@ -2577,36 +2575,34 @@ static inline void schedule_debug(struct task_struct *prev)
schedstat_inc(this_rq(), sched_count);
}
-static void put_prev_task(struct rq *rq, struct task_struct *prev)
-{
- if (prev->on_rq || rq->skip_clock_update < 0)
- update_rq_clock(rq);
- prev->sched_class->put_prev_task(rq, prev);
-}
-
/*
* Pick up the highest-prio task:
*/
static inline struct task_struct *
-pick_next_task(struct rq *rq)
+pick_next_task(struct rq *rq, struct task_struct *prev)
{
- const struct sched_class *class;
+ const struct sched_class *class = &fair_sched_class;
struct task_struct *p;
/*
* Optimization: we know that if all tasks are in
* the fair class we can call that function directly:
*/
- if (likely(rq->nr_running == rq->cfs.h_nr_running)) {
- p = fair_sched_class.pick_next_task(rq);
- if (likely(p))
+ if (likely(prev->sched_class == class &&
+ rq->nr_running == rq->cfs.h_nr_running)) {
+ p = fair_sched_class.pick_next_task(rq, prev);
+ if (likely(p && p != RETRY_TASK))
return p;
}
+again:
for_each_class(class) {
- p = class->pick_next_task(rq);
- if (p)
+ p = class->pick_next_task(rq, prev);
+ if (p) {
+ if (unlikely(p == RETRY_TASK))
+ goto again;
return p;
+ }
}
BUG(); /* the idle class will always have a runnable task */
@@ -2700,13 +2696,10 @@ need_resched:
switch_count = &prev->nvcsw;
}
- pre_schedule(rq, prev);
-
- if (unlikely(!rq->nr_running))
- idle_balance(cpu, rq);
+ if (prev->on_rq || rq->skip_clock_update < 0)
+ update_rq_clock(rq);
- put_prev_task(rq, prev);
- next = pick_next_task(rq);
+ next = pick_next_task(rq, prev);
clear_tsk_need_resched(prev);
clear_preempt_need_resched();
rq->skip_clock_update = 0;
@@ -2908,7 +2901,8 @@ EXPORT_SYMBOL(sleep_on_timeout);
* This function changes the 'effective' priority of a task. It does
* not touch ->normal_prio like __setscheduler().
*
- * Used by the rt_mutex code to implement priority inheritance logic.
+ * Used by the rt_mutex code to implement priority inheritance
+ * logic. Call site only calls if the priority of the task changed.
*/
void rt_mutex_setprio(struct task_struct *p, int prio)
{
@@ -2998,7 +2992,7 @@ void set_user_nice(struct task_struct *p, long nice)
unsigned long flags;
struct rq *rq;
- if (TASK_NICE(p) == nice || nice < -20 || nice > 19)
+ if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE)
return;
/*
* We have to be careful, if called from sys_setpriority(),
@@ -3076,11 +3070,11 @@ SYSCALL_DEFINE1(nice, int, increment)
if (increment > 40)
increment = 40;
- nice = TASK_NICE(current) + increment;
- if (nice < -20)
- nice = -20;
- if (nice > 19)
- nice = 19;
+ nice = task_nice(current) + increment;
+ if (nice < MIN_NICE)
+ nice = MIN_NICE;
+ if (nice > MAX_NICE)
+ nice = MAX_NICE;
if (increment < 0 && !can_nice(current, nice))
return -EPERM;
@@ -3109,18 +3103,6 @@ int task_prio(const struct task_struct *p)
}
/**
- * task_nice - return the nice value of a given task.
- * @p: the task in question.
- *
- * Return: The nice value [ -20 ... 0 ... 19 ].
- */
-int task_nice(const struct task_struct *p)
-{
- return TASK_NICE(p);
-}
-EXPORT_SYMBOL(task_nice);
-
-/**
* idle_cpu - is a given cpu idle currently?
* @cpu: the processor in question.
*
@@ -3189,9 +3171,8 @@ __setparam_dl(struct task_struct *p, const struct sched_attr *attr)
dl_se->dl_new = 1;
}
-/* Actually do priority change: must hold pi & rq lock. */
-static void __setscheduler(struct rq *rq, struct task_struct *p,
- const struct sched_attr *attr)
+static void __setscheduler_params(struct task_struct *p,
+ const struct sched_attr *attr)
{
int policy = attr->sched_policy;
@@ -3211,9 +3192,21 @@ static void __setscheduler(struct rq *rq, struct task_struct *p,
* getparam()/getattr() don't report silly values for !rt tasks.
*/
p->rt_priority = attr->sched_priority;
-
p->normal_prio = normal_prio(p);
- p->prio = rt_mutex_getprio(p);
+ set_load_weight(p);
+}
+
+/* Actually do priority change: must hold pi & rq lock. */
+static void __setscheduler(struct rq *rq, struct task_struct *p,
+ const struct sched_attr *attr)
+{
+ __setscheduler_params(p, attr);
+
+ /*
+ * If we get here, there was no pi waiters boosting the
+ * task. It is safe to use the normal prio.
+ */
+ p->prio = normal_prio(p);
if (dl_prio(p->prio))
p->sched_class = &dl_sched_class;
@@ -3221,8 +3214,6 @@ static void __setscheduler(struct rq *rq, struct task_struct *p,
p->sched_class = &rt_sched_class;
else
p->sched_class = &fair_sched_class;
-
- set_load_weight(p);
}
static void
@@ -3275,6 +3266,8 @@ static int __sched_setscheduler(struct task_struct *p,
const struct sched_attr *attr,
bool user)
{
+ int newprio = dl_policy(attr->sched_policy) ? MAX_DL_PRIO - 1 :
+ MAX_RT_PRIO - 1 - attr->sched_priority;
int retval, oldprio, oldpolicy = -1, on_rq, running;
int policy = attr->sched_policy;
unsigned long flags;
@@ -3319,7 +3312,7 @@ recheck:
*/
if (user && !capable(CAP_SYS_NICE)) {
if (fair_policy(policy)) {
- if (attr->sched_nice < TASK_NICE(p) &&
+ if (attr->sched_nice < task_nice(p) &&
!can_nice(p, attr->sched_nice))
return -EPERM;
}
@@ -3338,12 +3331,21 @@ recheck:
return -EPERM;
}
+ /*
+ * Can't set/change SCHED_DEADLINE policy at all for now
+ * (safest behavior); in the future we would like to allow
+ * unprivileged DL tasks to increase their relative deadline
+ * or reduce their runtime (both ways reducing utilization)
+ */
+ if (dl_policy(policy))
+ return -EPERM;
+
/*
* Treat SCHED_IDLE as nice 20. Only allow a switch to
* SCHED_NORMAL if the RLIMIT_NICE would normally permit it.
*/
if (p->policy == SCHED_IDLE && policy != SCHED_IDLE) {
- if (!can_nice(p, TASK_NICE(p)))
+ if (!can_nice(p, task_nice(p)))
return -EPERM;
}
@@ -3380,16 +3382,18 @@ recheck:
}
/*
- * If not changing anything there's no need to proceed further:
+ * If not changing anything there's no need to proceed further,
+ * but store a possible modification of reset_on_fork.
*/
if (unlikely(policy == p->policy)) {
- if (fair_policy(policy) && attr->sched_nice != TASK_NICE(p))
+ if (fair_policy(policy) && attr->sched_nice != task_nice(p))
goto change;
if (rt_policy(policy) && attr->sched_priority != p->rt_priority)
goto change;
if (dl_policy(policy))
goto change;
+ p->sched_reset_on_fork = reset_on_fork;
task_rq_unlock(rq, p, &flags);
return 0;
}
@@ -3443,6 +3447,24 @@ change:
return -EBUSY;
}
+ p->sched_reset_on_fork = reset_on_fork;
+ oldprio = p->prio;
+
+ /*
+ * Special case for priority boosted tasks.
+ *
+ * If the new priority is lower or equal (user space view)
+ * than the current (boosted) priority, we just store the new
+ * normal parameters and do not touch the scheduler class and
+ * the runqueue. This will be done when the task deboost
+ * itself.
+ */
+ if (rt_mutex_check_prio(p, newprio)) {
+ __setscheduler_params(p, attr);
+ task_rq_unlock(rq, p, &flags);
+ return 0;
+ }
+
on_rq = p->on_rq;
running = task_current(rq, p);
if (on_rq)
@@ -3450,16 +3472,18 @@ change:
if (running)
p->sched_class->put_prev_task(rq, p);
- p->sched_reset_on_fork = reset_on_fork;
-
- oldprio = p->prio;
prev_class = p->sched_class;
__setscheduler(rq, p, attr);
if (running)
p->sched_class->set_curr_task(rq);
- if (on_rq)
- enqueue_task(rq, p, 0);
+ if (on_rq) {
+ /*
+ * We enqueue to tail when the priority of a task is
+ * increased (user space view).
+ */
+ enqueue_task(rq, p, oldprio <= p->prio ? ENQUEUE_HEAD : 0);
+ }
check_class_changed(rq, p, prev_class, oldprio);
task_rq_unlock(rq, p, &flags);
@@ -3615,7 +3639,7 @@ static int sched_copy_attr(struct sched_attr __user *uattr,
* XXX: do we want to be lenient like existing syscalls; or do we want
* to be strict and return an error on out-of-bounds values?
*/
- attr->sched_nice = clamp(attr->sched_nice, -20, 19);
+ attr->sched_nice = clamp(attr->sched_nice, MIN_NICE, MAX_NICE);
out:
return ret;
@@ -3661,13 +3685,14 @@ SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param)
* @pid: the pid in question.
* @uattr: structure containing the extended parameters.
*/
-SYSCALL_DEFINE2(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr)
+SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr,
+ unsigned int, flags)
{
struct sched_attr attr;
struct task_struct *p;
int retval;
- if (!uattr || pid < 0)
+ if (!uattr || pid < 0 || flags)
return -EINVAL;
if (sched_copy_attr(uattr, &attr))
@@ -3786,7 +3811,7 @@ static int sched_read_attr(struct sched_attr __user *uattr,
attr->size = usize;
}
- ret = copy_to_user(uattr, attr, usize);
+ ret = copy_to_user(uattr, attr, attr->size);
if (ret)
return -EFAULT;
@@ -3804,8 +3829,8 @@ err_size:
* @uattr: structure containing the extended parameters.
* @size: sizeof(attr) for fwd/bwd comp.
*/
-SYSCALL_DEFINE3(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
- unsigned int, size)
+SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
+ unsigned int, size, unsigned int, flags)
{
struct sched_attr attr = {
.size = sizeof(struct sched_attr),
@@ -3814,7 +3839,7 @@ SYSCALL_DEFINE3(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
int retval;
if (!uattr || pid < 0 || size > PAGE_SIZE ||
- size < SCHED_ATTR_SIZE_VER0)
+ size < SCHED_ATTR_SIZE_VER0 || flags)
return -EINVAL;
rcu_read_lock();
@@ -3835,7 +3860,7 @@ SYSCALL_DEFINE3(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
else if (task_has_rt_policy(p))
attr.sched_priority = p->rt_priority;
else
- attr.sched_nice = TASK_NICE(p);
+ attr.sched_nice = task_nice(p);
rcu_read_unlock();
@@ -4473,6 +4498,7 @@ void init_idle(struct task_struct *idle, int cpu)
rcu_read_unlock();
rq->curr = rq->idle = idle;
+ idle->on_rq = 1;
#if defined(CONFIG_SMP)
idle->on_cpu = 1;
#endif
@@ -4692,8 +4718,10 @@ void idle_task_exit(void)
BUG_ON(cpu_online(smp_processor_id()));
- if (mm != &init_mm)
+ if (mm != &init_mm) {
switch_mm(mm, &init_mm, current);
+ finish_arch_post_lock_switch();
+ }
mmdrop(mm);
}
@@ -4711,6 +4739,22 @@ static void calc_load_migrate(struct rq *rq)
atomic_long_add(delta, &calc_load_tasks);
}
+static void put_prev_task_fake(struct rq *rq, struct task_struct *prev)
+{
+}
+
+static const struct sched_class fake_sched_class = {
+ .put_prev_task = put_prev_task_fake,
+};
+
+static struct task_struct fake_task = {
+ /*
+ * Avoid pull_{rt,dl}_task()
+ */
+ .prio = MAX_PRIO + 1,
+ .sched_class = &fake_sched_class,
+};
+
/*
* Migrate all tasks from the rq, sleeping tasks will be migrated by
* try_to_wake_up()->select_task_rq().
@@ -4751,7 +4795,7 @@ static void migrate_tasks(unsigned int dead_cpu)
if (rq->nr_running == 1)
break;
- next = pick_next_task(rq);
+ next = pick_next_task(rq, &fake_task);
BUG_ON(!next);
next->sched_class->put_prev_task(rq, next);
@@ -4841,7 +4885,7 @@ set_table_entry(struct ctl_table *entry,
static struct ctl_table *
sd_alloc_ctl_domain_table(struct sched_domain *sd)
{
- struct ctl_table *table = sd_alloc_ctl_entry(13);
+ struct ctl_table *table = sd_alloc_ctl_entry(14);
if (table == NULL)
return NULL;
@@ -4869,9 +4913,12 @@ sd_alloc_ctl_domain_table(struct sched_domain *sd)
sizeof(int), 0644, proc_dointvec_minmax, false);
set_table_entry(&table[10], "flags", &sd->flags,
sizeof(int), 0644, proc_dointvec_minmax, false);
- set_table_entry(&table[11], "name", sd->name,
+ set_table_entry(&table[11], "max_newidle_lb_cost",
+ &sd->max_newidle_lb_cost,
+ sizeof(long), 0644, proc_doulongvec_minmax, false);
+ set_table_entry(&table[12], "name", sd->name,
CORENAME_MAX_SIZE, 0444, proc_dostring, false);
- /* &table[12] is terminator */
+ /* &table[13] is terminator */
return table;
}
@@ -6848,7 +6895,6 @@ void __init sched_init(void)
rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime;
#ifdef CONFIG_RT_GROUP_SCHED
- INIT_LIST_HEAD(&rq->leaf_rt_rq_list);
init_tg_rt_entry(&root_task_group, &rq->rt, NULL, i, NULL);
#endif
@@ -6937,7 +6983,8 @@ void __might_sleep(const char *file, int line, int preempt_offset)
static unsigned long prev_jiffy; /* ratelimiting */
rcu_sleep_check(); /* WARN_ON_ONCE() by default, no rate limit reqd. */
- if ((preempt_count_equals(preempt_offset) && !irqs_disabled()) ||
+ if ((preempt_count_equals(preempt_offset) && !irqs_disabled() &&
+ !is_idle_task(current)) ||
system_state != SYSTEM_RUNNING || oops_in_progress)
return;
if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
@@ -6955,6 +7002,13 @@ void __might_sleep(const char *file, int line, int preempt_offset)
debug_show_held_locks(current);
if (irqs_disabled())
print_irqtrace_events(current);
+#ifdef CONFIG_DEBUG_PREEMPT
+ if (!preempt_count_equals(preempt_offset)) {
+ pr_err("Preemption disabled at:");
+ print_ip_sym(current->preempt_disable_ip);
+ pr_cont("\n");
+ }
+#endif
dump_stack();
}
EXPORT_SYMBOL(__might_sleep);
@@ -7008,7 +7062,7 @@ void normalize_rt_tasks(void)
* Renice negative nice level userspace
* tasks back to 0:
*/
- if (TASK_NICE(p) < 0 && p->mm)
+ if (task_nice(p) < 0 && p->mm)
set_user_nice(p, 0);
continue;
}
@@ -7422,6 +7476,7 @@ static int sched_dl_global_constraints(void)
u64 period = global_rt_period();
u64 new_bw = to_ratio(period, runtime);
int cpu, ret = 0;
+ unsigned long flags;
/*
* Here we want to check the bandwidth not being set to some
@@ -7435,10 +7490,10 @@ static int sched_dl_global_constraints(void)
for_each_possible_cpu(cpu) {
struct dl_bw *dl_b = dl_bw_of(cpu);
- raw_spin_lock(&dl_b->lock);
+ raw_spin_lock_irqsave(&dl_b->lock, flags);
if (new_bw < dl_b->total_bw)
ret = -EBUSY;
- raw_spin_unlock(&dl_b->lock);
+ raw_spin_unlock_irqrestore(&dl_b->lock, flags);
if (ret)
break;
@@ -7451,6 +7506,7 @@ static void sched_dl_do_global(void)
{
u64 new_bw = -1;
int cpu;
+ unsigned long flags;
def_dl_bandwidth.dl_period = global_rt_period();
def_dl_bandwidth.dl_runtime = global_rt_runtime();
@@ -7464,9 +7520,9 @@ static void sched_dl_do_global(void)
for_each_possible_cpu(cpu) {
struct dl_bw *dl_b = dl_bw_of(cpu);
- raw_spin_lock(&dl_b->lock);
+ raw_spin_lock_irqsave(&dl_b->lock, flags);
dl_b->bw = new_bw;
- raw_spin_unlock(&dl_b->lock);
+ raw_spin_unlock_irqrestore(&dl_b->lock, flags);
}
}
@@ -7475,7 +7531,8 @@ static int sched_rt_global_validate(void)
if (sysctl_sched_rt_period <= 0)
return -EINVAL;
- if (sysctl_sched_rt_runtime > sysctl_sched_rt_period)
+ if ((sysctl_sched_rt_runtime != RUNTIME_INF) &&
+ (sysctl_sched_rt_runtime > sysctl_sched_rt_period))
return -EINVAL;
return 0;
diff --git a/kernel/sched/cpudeadline.c b/kernel/sched/cpudeadline.c
index 045fc74e3f09..5b9bb42b2d47 100644
--- a/kernel/sched/cpudeadline.c
+++ b/kernel/sched/cpudeadline.c
@@ -70,7 +70,7 @@ static void cpudl_heapify(struct cpudl *cp, int idx)
static void cpudl_change_key(struct cpudl *cp, int idx, u64 new_dl)
{
- WARN_ON(idx > num_present_cpus() || idx == IDX_INVALID);
+ WARN_ON(idx == IDX_INVALID || !cpu_present(idx));
if (dl_time_before(new_dl, cp->elements[idx].dl)) {
cp->elements[idx].dl = new_dl;
@@ -117,7 +117,7 @@ int cpudl_find(struct cpudl *cp, struct task_struct *p,
}
out:
- WARN_ON(best_cpu > num_present_cpus() && best_cpu != -1);
+ WARN_ON(best_cpu != -1 && !cpu_present(best_cpu));
return best_cpu;
}
@@ -137,7 +137,7 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl, int is_valid)
int old_idx, new_cpu;
unsigned long flags;
- WARN_ON(cpu > num_present_cpus());
+ WARN_ON(!cpu_present(cpu));
raw_spin_lock_irqsave(&cp->lock, flags);
old_idx = cp->cpu_to_idx[cpu];
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
index 99947919e30b..a95097cb4591 100644
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -142,7 +142,7 @@ void account_user_time(struct task_struct *p, cputime_t cputime,
p->utimescaled += cputime_scaled;
account_group_user_time(p, cputime);
- index = (TASK_NICE(p) > 0) ? CPUTIME_NICE : CPUTIME_USER;
+ index = (task_nice(p) > 0) ? CPUTIME_NICE : CPUTIME_USER;
/* Add user time to cpustat. */
task_group_account_field(p, index, (__force u64) cputime);
@@ -169,7 +169,7 @@ static void account_guest_time(struct task_struct *p, cputime_t cputime,
p->gtime += cputime;
/* Add guest time to cpustat. */
- if (TASK_NICE(p) > 0) {
+ if (task_nice(p) > 0) {
cpustat[CPUTIME_NICE] += (__force u64) cputime;
cpustat[CPUTIME_GUEST_NICE] += (__force u64) cputime;
} else {
@@ -258,16 +258,22 @@ static __always_inline bool steal_account_process_tick(void)
{
#ifdef CONFIG_PARAVIRT
if (static_key_false(&paravirt_steal_enabled)) {
- u64 steal, st = 0;
+ u64 steal;
+ cputime_t steal_ct;
steal = paravirt_steal_clock(smp_processor_id());
steal -= this_rq()->prev_steal_time;
- st = steal_ticks(steal);
- this_rq()->prev_steal_time += st * TICK_NSEC;
+ /*
+ * cputime_t may be less precise than nsecs (eg: if it's
+ * based on jiffies). Lets cast the result to cputime
+ * granularity and account the rest on the next rounds.
+ */
+ steal_ct = nsecs_to_cputime(steal);
+ this_rq()->prev_steal_time += cputime_to_nsecs(steal_ct);
- account_steal_time(st);
- return st;
+ account_steal_time(steal_ct);
+ return steal_ct;
}
#endif
return false;
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 0dd5e0971a07..27ef40925525 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -121,7 +121,7 @@ static inline void dl_clear_overload(struct rq *rq)
static void update_dl_migration(struct dl_rq *dl_rq)
{
- if (dl_rq->dl_nr_migratory && dl_rq->dl_nr_total > 1) {
+ if (dl_rq->dl_nr_migratory && dl_rq->dl_nr_running > 1) {
if (!dl_rq->overloaded) {
dl_set_overload(rq_of_dl_rq(dl_rq));
dl_rq->overloaded = 1;
@@ -135,9 +135,7 @@ static void update_dl_migration(struct dl_rq *dl_rq)
static void inc_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
{
struct task_struct *p = dl_task_of(dl_se);
- dl_rq = &rq_of_dl_rq(dl_rq)->dl;
- dl_rq->dl_nr_total++;
if (p->nr_cpus_allowed > 1)
dl_rq->dl_nr_migratory++;
@@ -147,9 +145,7 @@ static void inc_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
static void dec_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
{
struct task_struct *p = dl_task_of(dl_se);
- dl_rq = &rq_of_dl_rq(dl_rq)->dl;
- dl_rq->dl_nr_total--;
if (p->nr_cpus_allowed > 1)
dl_rq->dl_nr_migratory--;
@@ -214,6 +210,16 @@ static inline int has_pushable_dl_tasks(struct rq *rq)
static int push_dl_task(struct rq *rq);
+static inline bool need_pull_dl_task(struct rq *rq, struct task_struct *prev)
+{
+ return dl_task(prev);
+}
+
+static inline void set_post_schedule(struct rq *rq)
+{
+ rq->post_schedule = has_pushable_dl_tasks(rq);
+}
+
#else
static inline
@@ -236,6 +242,19 @@ void dec_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
{
}
+static inline bool need_pull_dl_task(struct rq *rq, struct task_struct *prev)
+{
+ return false;
+}
+
+static inline int pull_dl_task(struct rq *rq)
+{
+ return 0;
+}
+
+static inline void set_post_schedule(struct rq *rq)
+{
+}
#endif /* CONFIG_SMP */
static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags);
@@ -566,6 +585,8 @@ int dl_runtime_exceeded(struct rq *rq, struct sched_dl_entity *dl_se)
return 1;
}
+extern bool sched_rt_bandwidth_account(struct rt_rq *rt_rq);
+
/*
* Update the current task's runtime statistics (provided it is still
* a -deadline task and has not been removed from the dl_rq).
@@ -588,8 +609,8 @@ static void update_curr_dl(struct rq *rq)
* approach need further study.
*/
delta_exec = rq_clock_task(rq) - curr->se.exec_start;
- if (unlikely((s64)delta_exec < 0))
- delta_exec = 0;
+ if (unlikely((s64)delta_exec <= 0))
+ return;
schedstat_set(curr->se.statistics.exec_max,
max(curr->se.statistics.exec_max, delta_exec));
@@ -629,11 +650,13 @@ static void update_curr_dl(struct rq *rq)
struct rt_rq *rt_rq = &rq->rt;
raw_spin_lock(&rt_rq->rt_runtime_lock);
- rt_rq->rt_time += delta_exec;
/*
* We'll let actual RT tasks worry about the overflow here, we
- * have our own CBS to keep us inline -- see above.
+ * have our own CBS to keep us inline; only account when RT
+ * bandwidth is relevant.
*/
+ if (sched_rt_bandwidth_account(rt_rq))
+ rt_rq->rt_time += delta_exec;
raw_spin_unlock(&rt_rq->rt_runtime_lock);
}
}
@@ -717,6 +740,7 @@ void inc_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
WARN_ON(!dl_prio(prio));
dl_rq->dl_nr_running++;
+ inc_nr_running(rq_of_dl_rq(dl_rq));
inc_dl_deadline(dl_rq, deadline);
inc_dl_migration(dl_se, dl_rq);
@@ -730,6 +754,7 @@ void dec_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
WARN_ON(!dl_prio(prio));
WARN_ON(!dl_rq->dl_nr_running);
dl_rq->dl_nr_running--;
+ dec_nr_running(rq_of_dl_rq(dl_rq));
dec_dl_deadline(dl_rq, dl_se->deadline);
dec_dl_migration(dl_se, dl_rq);
@@ -836,8 +861,6 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags)
if (!task_current(rq, p) && p->nr_cpus_allowed > 1)
enqueue_pushable_dl_task(rq, p);
-
- inc_nr_running(rq);
}
static void __dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags)
@@ -850,8 +873,6 @@ static void dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags)
{
update_curr_dl(rq);
__dequeue_task_dl(rq, p, flags);
-
- dec_nr_running(rq);
}
/*
@@ -944,6 +965,8 @@ static void check_preempt_equal_dl(struct rq *rq, struct task_struct *p)
resched_task(rq->curr);
}
+static int pull_dl_task(struct rq *this_rq);
+
#endif /* CONFIG_SMP */
/*
@@ -990,7 +1013,7 @@ static struct sched_dl_entity *pick_next_dl_entity(struct rq *rq,
return rb_entry(left, struct sched_dl_entity, rb_node);
}
-struct task_struct *pick_next_task_dl(struct rq *rq)
+struct task_struct *pick_next_task_dl(struct rq *rq, struct task_struct *prev)
{
struct sched_dl_entity *dl_se;
struct task_struct *p;
@@ -998,9 +1021,20 @@ struct task_struct *pick_next_task_dl(struct rq *rq)
dl_rq = &rq->dl;
+ if (need_pull_dl_task(rq, prev))
+ pull_dl_task(rq);
+ /*
+ * When prev is DL, we may throttle it in put_prev_task().
+ * So, we update time before we check for dl_nr_running.
+ */
+ if (prev->sched_class == &dl_sched_class)
+ update_curr_dl(rq);
+
if (unlikely(!dl_rq->dl_nr_running))
return NULL;
+ put_prev_task(rq, prev);
+
dl_se = pick_next_dl_entity(rq, dl_rq);
BUG_ON(!dl_se);
@@ -1015,9 +1049,7 @@ struct task_struct *pick_next_task_dl(struct rq *rq)
start_hrtick_dl(rq, p);
#endif
-#ifdef CONFIG_SMP
- rq->post_schedule = has_pushable_dl_tasks(rq);
-#endif /* CONFIG_SMP */
+ set_post_schedule(rq);
return p;
}
@@ -1426,13 +1458,6 @@ skip:
return ret;
}
-static void pre_schedule_dl(struct rq *rq, struct task_struct *prev)
-{
- /* Try to pull other tasks here */
- if (dl_task(prev))
- pull_dl_task(rq);
-}
-
static void post_schedule_dl(struct rq *rq)
{
push_dl_tasks(rq);
@@ -1560,7 +1585,7 @@ static void switched_to_dl(struct rq *rq, struct task_struct *p)
if (unlikely(p->dl.dl_throttled))
return;
- if (p->on_rq || rq->curr != p) {
+ if (p->on_rq && rq->curr != p) {
#ifdef CONFIG_SMP
if (rq->dl.overloaded && push_dl_task(rq) && rq != task_rq(p))
/* Only reschedule if pushing failed */
@@ -1625,7 +1650,6 @@ const struct sched_class dl_sched_class = {
.set_cpus_allowed = set_cpus_allowed_dl,
.rq_online = rq_online_dl,
.rq_offline = rq_offline_dl,
- .pre_schedule = pre_schedule_dl,
.post_schedule = post_schedule_dl,
.task_woken = task_woken_dl,
#endif
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index dd52e7ffb10e..f3344c31632a 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -321,6 +321,7 @@ do { \
P(sched_goidle);
#ifdef CONFIG_SMP
P64(avg_idle);
+ P64(max_idle_balance_cost);
#endif
P(ttwu_count);
@@ -533,15 +534,15 @@ static void sched_show_numa(struct task_struct *p, struct seq_file *m)
unsigned long nr_faults = -1;
int cpu_current, home_node;
- if (p->numa_faults)
- nr_faults = p->numa_faults[2*node + i];
+ if (p->numa_faults_memory)
+ nr_faults = p->numa_faults_memory[2*node + i];
cpu_current = !i ? (task_node(p) == node) :
(pol && node_isset(node, pol->v.nodes));
home_node = (p->numa_preferred_nid == node);
- SEQ_printf(m, "numa_faults, %d, %d, %d, %d, %ld\n",
+ SEQ_printf(m, "numa_faults_memory, %d, %d, %d, %d, %ld\n",
i, node, cpu_current, home_node, nr_faults);
}
}
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 966cc2bfcb77..7e9bd0b1fa9e 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -322,13 +322,13 @@ static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
list_for_each_entry_rcu(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list)
/* Do the two (enqueued) entities belong to the same group ? */
-static inline int
+static inline struct cfs_rq *
is_same_group(struct sched_entity *se, struct sched_entity *pse)
{
if (se->cfs_rq == pse->cfs_rq)
- return 1;
+ return se->cfs_rq;
- return 0;
+ return NULL;
}
static inline struct sched_entity *parent_entity(struct sched_entity *se)
@@ -336,17 +336,6 @@ static inline struct sched_entity *parent_entity(struct sched_entity *se)
return se->parent;
}
-/* return depth at which a sched entity is present in the hierarchy */
-static inline int depth_se(struct sched_entity *se)
-{
- int depth = 0;
-
- for_each_sched_entity(se)
- depth++;
-
- return depth;
-}
-
static void
find_matching_se(struct sched_entity **se, struct sched_entity **pse)
{
@@ -360,8 +349,8 @@ find_matching_se(struct sched_entity **se, struct sched_entity **pse)
*/
/* First walk up until both entities are at same depth */
- se_depth = depth_se(*se);
- pse_depth = depth_se(*pse);
+ se_depth = (*se)->depth;
+ pse_depth = (*pse)->depth;
while (se_depth > pse_depth) {
se_depth--;
@@ -426,12 +415,6 @@ static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
#define for_each_leaf_cfs_rq(rq, cfs_rq) \
for (cfs_rq = &rq->cfs; cfs_rq; cfs_rq = NULL)
-static inline int
-is_same_group(struct sched_entity *se, struct sched_entity *pse)
-{
- return 1;
-}
-
static inline struct sched_entity *parent_entity(struct sched_entity *se)
{
return NULL;
@@ -819,14 +802,6 @@ unsigned int sysctl_numa_balancing_scan_size = 256;
/* Scan @scan_size MB every @scan_period after an initial @scan_delay in ms */
unsigned int sysctl_numa_balancing_scan_delay = 1000;
-/*
- * After skipping a page migration on a shared page, skip N more numa page
- * migrations unconditionally. This reduces the number of NUMA migrations
- * in shared memory workloads, and has the effect of pulling tasks towards
- * where their memory lives, over pulling the memory towards the task.
- */
-unsigned int sysctl_numa_balancing_migrate_deferred = 16;
-
static unsigned int task_nr_scan_windows(struct task_struct *p)
{
unsigned long rss = 0;
@@ -893,10 +868,26 @@ struct numa_group {
struct list_head task_list;
struct rcu_head rcu;
+ nodemask_t active_nodes;
unsigned long total_faults;
+ /*
+ * Faults_cpu is used to decide whether memory should move
+ * towards the CPU. As a consequence, these stats are weighted
+ * more by CPU use than by memory faults.
+ */
+ unsigned long *faults_cpu;
unsigned long faults[0];
};
+/* Shared or private faults. */
+#define NR_NUMA_HINT_FAULT_TYPES 2
+
+/* Memory and CPU locality */
+#define NR_NUMA_HINT_FAULT_STATS (NR_NUMA_HINT_FAULT_TYPES * 2)
+
+/* Averaged statistics, and temporary buffers. */
+#define NR_NUMA_HINT_FAULT_BUCKETS (NR_NUMA_HINT_FAULT_STATS * 2)
+
pid_t task_numa_group_id(struct task_struct *p)
{
return p->numa_group ? p->numa_group->gid : 0;
@@ -904,16 +895,16 @@ pid_t task_numa_group_id(struct task_struct *p)
static inline int task_faults_idx(int nid, int priv)
{
- return 2 * nid + priv;
+ return NR_NUMA_HINT_FAULT_TYPES * nid + priv;
}
static inline unsigned long task_faults(struct task_struct *p, int nid)
{
- if (!p->numa_faults)
+ if (!p->numa_faults_memory)
return 0;
- return p->numa_faults[task_faults_idx(nid, 0)] +
- p->numa_faults[task_faults_idx(nid, 1)];
+ return p->numa_faults_memory[task_faults_idx(nid, 0)] +
+ p->numa_faults_memory[task_faults_idx(nid, 1)];
}
static inline unsigned long group_faults(struct task_struct *p, int nid)
@@ -925,6 +916,12 @@ static inline unsigned long group_faults(struct task_struct *p, int nid)
p->numa_group->faults[task_faults_idx(nid, 1)];
}
+static inline unsigned long group_faults_cpu(struct numa_group *group, int nid)
+{
+ return group->faults_cpu[task_faults_idx(nid, 0)] +
+ group->faults_cpu[task_faults_idx(nid, 1)];
+}
+
/*
* These return the fraction of accesses done by a particular task, or
* task group, on a particular numa node. The group weight is given a
@@ -935,7 +932,7 @@ static inline unsigned long task_weight(struct task_struct *p, int nid)
{
unsigned long total_faults;
- if (!p->numa_faults)
+ if (!p->numa_faults_memory)
return 0;
total_faults = p->total_numa_faults;
@@ -954,6 +951,69 @@ static inline unsigned long group_weight(struct task_struct *p, int nid)
return 1000 * group_faults(p, nid) / p->numa_group->total_faults;
}
+bool should_numa_migrate_memory(struct task_struct *p, struct page * page,
+ int src_nid, int dst_cpu)
+{
+ struct numa_group *ng = p->numa_group;
+ int dst_nid = cpu_to_node(dst_cpu);
+ int last_cpupid, this_cpupid;
+
+ this_cpupid = cpu_pid_to_cpupid(dst_cpu, current->pid);
+
+ /*
+ * Multi-stage node selection is used in conjunction with a periodic
+ * migration fault to build a temporal task<->page relation. By using
+ * a two-stage filter we remove short/unlikely relations.
+ *
+ * Using P(p) ~ n_p / n_t as per frequentist probability, we can equate
+ * a task's usage of a particular page (n_p) per total usage of this
+ * page (n_t) (in a given time-span) to a probability.
+ *
+ * Our periodic faults will sample this probability and getting the
+ * same result twice in a row, given these samples are fully
+ * independent, is then given by P(n)^2, provided our sample period
+ * is sufficiently short compared to the usage pattern.
+ *
+ * This quadric squishes small probabilities, making it less likely we
+ * act on an unlikely task<->page relation.
+ */
+ last_cpupid = page_cpupid_xchg_last(page, this_cpupid);
+ if (!cpupid_pid_unset(last_cpupid) &&
+ cpupid_to_nid(last_cpupid) != dst_nid)
+ return false;
+
+ /* Always allow migrate on private faults */
+ if (cpupid_match_pid(p, last_cpupid))
+ return true;
+
+ /* A shared fault, but p->numa_group has not been set up yet. */
+ if (!ng)
+ return true;
+
+ /*
+ * Do not migrate if the destination is not a node that
+ * is actively used by this numa group.
+ */
+ if (!node_isset(dst_nid, ng->active_nodes))
+ return false;
+
+ /*
+ * Source is a node that is not actively used by this
+ * numa group, while the destination is. Migrate.
+ */
+ if (!node_isset(src_nid, ng->active_nodes))
+ return true;
+
+ /*
+ * Both source and destination are nodes in active
+ * use by this numa group. Maximize memory bandwidth
+ * by migrating from more heavily used groups, to less
+ * heavily used ones, spreading the load around.
+ * Use a 1/4 hysteresis to avoid spurious page movement.
+ */
+ return group_faults(p, dst_nid) < (group_faults(p, src_nid) * 3 / 4);
+}
+
static unsigned long weighted_cpuload(const int cpu);
static unsigned long source_load(int cpu, int type);
static unsigned long target_load(int cpu, int type);
@@ -1267,7 +1327,7 @@ static int task_numa_migrate(struct task_struct *p)
static void numa_migrate_preferred(struct task_struct *p)
{
/* This task has no NUMA fault statistics yet */
- if (unlikely(p->numa_preferred_nid == -1 || !p->numa_faults))
+ if (unlikely(p->numa_preferred_nid == -1 || !p->numa_faults_memory))
return;
/* Periodically retry migrating the task to the preferred node */
@@ -1282,6 +1342,38 @@ static void numa_migrate_preferred(struct task_struct *p)
}
/*
+ * Find the nodes on which the workload is actively running. We do this by
+ * tracking the nodes from which NUMA hinting faults are triggered. This can
+ * be different from the set of nodes where the workload's memory is currently
+ * located.
+ *
+ * The bitmask is used to make smarter decisions on when to do NUMA page
+ * migrations, To prevent flip-flopping, and excessive page migrations, nodes
+ * are added when they cause over 6/16 of the maximum number of faults, but
+ * only removed when they drop below 3/16.
+ */
+static void update_numa_active_node_mask(struct numa_group *numa_group)
+{
+ unsigned long faults, max_faults = 0;
+ int nid;
+
+ for_each_online_node(nid) {
+ faults = group_faults_cpu(numa_group, nid);
+ if (faults > max_faults)
+ max_faults = faults;
+ }
+
+ for_each_online_node(nid) {
+ faults = group_faults_cpu(numa_group, nid);
+ if (!node_isset(nid, numa_group->active_nodes)) {
+ if (faults > max_faults * 6 / 16)
+ node_set(nid, numa_group->active_nodes);
+ } else if (faults < max_faults * 3 / 16)
+ node_clear(nid, numa_group->active_nodes);
+ }
+}
+
+/*
* When adapting the scan rate, the period is divided into NUMA_PERIOD_SLOTS
* increments. The more local the fault statistics are, the higher the scan
* period will be for the next scan window. If local/remote ratio is below
@@ -1355,11 +1447,41 @@ static void update_task_scan_period(struct task_struct *p,
memset(p->numa_faults_locality, 0, sizeof(p->numa_faults_locality));
}
+/*
+ * Get the fraction of time the task has been running since the last
+ * NUMA placement cycle. The scheduler keeps similar statistics, but
+ * decays those on a 32ms period, which is orders of magnitude off
+ * from the dozens-of-seconds NUMA balancing period. Use the scheduler
+ * stats only if the task is so new there are no NUMA statistics yet.
+ */
+static u64 numa_get_avg_runtime(struct task_struct *p, u64 *period)
+{
+ u64 runtime, delta, now;
+ /* Use the start of this time slice to avoid calculations. */
+ now = p->se.exec_start;
+ runtime = p->se.sum_exec_runtime;
+
+ if (p->last_task_numa_placement) {
+ delta = runtime - p->last_sum_exec_runtime;
+ *period = now - p->last_task_numa_placement;
+ } else {
+ delta = p->se.avg.runnable_avg_sum;
+ *period = p->se.avg.runnable_avg_period;
+ }
+
+ p->last_sum_exec_runtime = runtime;
+ p->last_task_numa_placement = now;
+
+ return delta;
+}
+
static void task_numa_placement(struct task_struct *p)
{
int seq, nid, max_nid = -1, max_group_nid = -1;
unsigned long max_faults = 0, max_group_faults = 0;
unsigned long fault_types[2] = { 0, 0 };
+ unsigned long total_faults;
+ u64 runtime, period;
spinlock_t *group_lock = NULL;
seq = ACCESS_ONCE(p->mm->numa_scan_seq);
@@ -1368,6 +1490,10 @@ static void task_numa_placement(struct task_struct *p)
p->numa_scan_seq = seq;
p->numa_scan_period_max = task_scan_max(p);
+ total_faults = p->numa_faults_locality[0] +
+ p->numa_faults_locality[1];
+ runtime = numa_get_avg_runtime(p, &period);
+
/* If the task is part of a group prevent parallel updates to group stats */
if (p->numa_group) {
group_lock = &p->numa_group->lock;
@@ -1379,24 +1505,37 @@ static void task_numa_placement(struct task_struct *p)
unsigned long faults = 0, group_faults = 0;
int priv, i;
- for (priv = 0; priv < 2; priv++) {
- long diff;
+ for (priv = 0; priv < NR_NUMA_HINT_FAULT_TYPES; priv++) {
+ long diff, f_diff, f_weight;
i = task_faults_idx(nid, priv);
- diff = -p->numa_faults[i];
/* Decay existing window, copy faults since last scan */
- p->numa_faults[i] >>= 1;
- p->numa_faults[i] += p->numa_faults_buffer[i];
- fault_types[priv] += p->numa_faults_buffer[i];
- p->numa_faults_buffer[i] = 0;
+ diff = p->numa_faults_buffer_memory[i] - p->numa_faults_memory[i] / 2;
+ fault_types[priv] += p->numa_faults_buffer_memory[i];
+ p->numa_faults_buffer_memory[i] = 0;
- faults += p->numa_faults[i];
- diff += p->numa_faults[i];
+ /*
+ * Normalize the faults_from, so all tasks in a group
+ * count according to CPU use, instead of by the raw
+ * number of faults. Tasks with little runtime have
+ * little over-all impact on throughput, and thus their
+ * faults are less important.
+ */
+ f_weight = div64_u64(runtime << 16, period + 1);
+ f_weight = (f_weight * p->numa_faults_buffer_cpu[i]) /
+ (total_faults + 1);
+ f_diff = f_weight - p->numa_faults_cpu[i] / 2;
+ p->numa_faults_buffer_cpu[i] = 0;
+
+ p->numa_faults_memory[i] += diff;
+ p->numa_faults_cpu[i] += f_diff;
+ faults += p->numa_faults_memory[i];
p->total_numa_faults += diff;
if (p->numa_group) {
/* safe because we can only change our own group */
p->numa_group->faults[i] += diff;
+ p->numa_group->faults_cpu[i] += f_diff;
p->numa_group->total_faults += diff;
group_faults += p->numa_group->faults[i];
}
@@ -1416,6 +1555,7 @@ static void task_numa_placement(struct task_struct *p)
update_task_scan_period(p, fault_types[0], fault_types[1]);
if (p->numa_group) {
+ update_numa_active_node_mask(p->numa_group);
/*
* If the preferred task and group nids are different,
* iterate over the nodes again to find the best place.
@@ -1465,7 +1605,7 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
if (unlikely(!p->numa_group)) {
unsigned int size = sizeof(struct numa_group) +
- 2*nr_node_ids*sizeof(unsigned long);
+ 4*nr_node_ids*sizeof(unsigned long);
grp = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
if (!grp)
@@ -1475,9 +1615,14 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
spin_lock_init(&grp->lock);
INIT_LIST_HEAD(&grp->task_list);
grp->gid = p->pid;
+ /* Second half of the array tracks nids where faults happen */
+ grp->faults_cpu = grp->faults + NR_NUMA_HINT_FAULT_TYPES *
+ nr_node_ids;
+
+ node_set(task_node(current), grp->active_nodes);
- for (i = 0; i < 2*nr_node_ids; i++)
- grp->faults[i] = p->numa_faults[i];
+ for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++)
+ grp->faults[i] = p->numa_faults_memory[i];
grp->total_faults = p->total_numa_faults;
@@ -1534,9 +1679,9 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
double_lock(&my_grp->lock, &grp->lock);
- for (i = 0; i < 2*nr_node_ids; i++) {
- my_grp->faults[i] -= p->numa_faults[i];
- grp->faults[i] += p->numa_faults[i];
+ for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++) {
+ my_grp->faults[i] -= p->numa_faults_memory[i];
+ grp->faults[i] += p->numa_faults_memory[i];
}
my_grp->total_faults -= p->total_numa_faults;
grp->total_faults += p->total_numa_faults;
@@ -1562,12 +1707,12 @@ void task_numa_free(struct task_struct *p)
{
struct numa_group *grp = p->numa_group;
int i;
- void *numa_faults = p->numa_faults;
+ void *numa_faults = p->numa_faults_memory;
if (grp) {
spin_lock(&grp->lock);
- for (i = 0; i < 2*nr_node_ids; i++)
- grp->faults[i] -= p->numa_faults[i];
+ for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++)
+ grp->faults[i] -= p->numa_faults_memory[i];
grp->total_faults -= p->total_numa_faults;
list_del(&p->numa_entry);
@@ -1577,18 +1722,21 @@ void task_numa_free(struct task_struct *p)
put_numa_group(grp);
}
- p->numa_faults = NULL;
- p->numa_faults_buffer = NULL;
+ p->numa_faults_memory = NULL;
+ p->numa_faults_buffer_memory = NULL;
+ p->numa_faults_cpu= NULL;
+ p->numa_faults_buffer_cpu = NULL;
kfree(numa_faults);
}
/*
* Got a PROT_NONE fault for a page on @node.
*/
-void task_numa_fault(int last_cpupid, int node, int pages, int flags)
+void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
{
struct task_struct *p = current;
bool migrated = flags & TNF_MIGRATED;
+ int cpu_node = task_node(current);
int priv;
if (!numabalancing_enabled)
@@ -1603,16 +1751,24 @@ void task_numa_fault(int last_cpupid, int node, int pages, int flags)
return;
/* Allocate buffer to track faults on a per-node basis */
- if (unlikely(!p->numa_faults)) {
- int size = sizeof(*p->numa_faults) * 2 * nr_node_ids;
+ if (unlikely(!p->numa_faults_memory)) {
+ int size = sizeof(*p->numa_faults_memory) *
+ NR_NUMA_HINT_FAULT_BUCKETS * nr_node_ids;
- /* numa_faults and numa_faults_buffer share the allocation */
- p->numa_faults = kzalloc(size * 2, GFP_KERNEL|__GFP_NOWARN);
- if (!p->numa_faults)
+ p->numa_faults_memory = kzalloc(size, GFP_KERNEL|__GFP_NOWARN);
+ if (!p->numa_faults_memory)
return;
- BUG_ON(p->numa_faults_buffer);
- p->numa_faults_buffer = p->numa_faults + (2 * nr_node_ids);
+ BUG_ON(p->numa_faults_buffer_memory);
+ /*
+ * The averaged statistics, shared & private, memory & cpu,
+ * occupy the first half of the array. The second half of the
+ * array is for current counters, which are averaged into the
+ * first set by task_numa_placement.
+ */
+ p->numa_faults_cpu = p->numa_faults_memory + (2 * nr_node_ids);
+ p->numa_faults_buffer_memory = p->numa_faults_memory + (4 * nr_node_ids);
+ p->numa_faults_buffer_cpu = p->numa_faults_memory + (6 * nr_node_ids);
p->total_numa_faults = 0;
memset(p->numa_faults_locality, 0, sizeof(p->numa_faults_locality));
}
@@ -1641,7 +1797,8 @@ void task_numa_fault(int last_cpupid, int node, int pages, int flags)
if (migrated)
p->numa_pages_migrated += pages;
- p->numa_faults_buffer[task_faults_idx(node, priv)] += pages;
+ p->numa_faults_buffer_memory[task_faults_idx(mem_node, priv)] += pages;
+ p->numa_faults_buffer_cpu[task_faults_idx(cpu_node, priv)] += pages;
p->numa_faults_locality[!!(flags & TNF_FAULT_LOCAL)] += pages;
}
@@ -1757,6 +1914,8 @@ void task_numa_work(struct callback_head *work)
start = end;
if (pages <= 0)
goto out;
+
+ cond_resched();
} while (end != vma->vm_end);
}
@@ -2217,13 +2376,20 @@ static inline void __update_group_entity_contrib(struct sched_entity *se)
se->avg.load_avg_contrib >>= NICE_0_SHIFT;
}
}
-#else
+
+static inline void update_rq_runnable_avg(struct rq *rq, int runnable)
+{
+ __update_entity_runnable_avg(rq_clock_task(rq), &rq->avg, runnable);
+ __update_tg_runnable_avg(&rq->avg, &rq->cfs);
+}
+#else /* CONFIG_FAIR_GROUP_SCHED */
static inline void __update_cfs_rq_tg_load_contrib(struct cfs_rq *cfs_rq,
int force_update) {}
static inline void __update_tg_runnable_avg(struct sched_avg *sa,
struct cfs_rq *cfs_rq) {}
static inline void __update_group_entity_contrib(struct sched_entity *se) {}
-#endif
+static inline void update_rq_runnable_avg(struct rq *rq, int runnable) {}
+#endif /* CONFIG_FAIR_GROUP_SCHED */
static inline void __update_task_entity_contrib(struct sched_entity *se)
{
@@ -2321,12 +2487,6 @@ static void update_cfs_rq_blocked_load(struct cfs_rq *cfs_rq, int force_update)
__update_cfs_rq_tg_load_contrib(cfs_rq, force_update);
}
-static inline void update_rq_runnable_avg(struct rq *rq, int runnable)
-{
- __update_entity_runnable_avg(rq_clock_task(rq), &rq->avg, runnable);
- __update_tg_runnable_avg(&rq->avg, &rq->cfs);
-}
-
/* Add the load generated by se into cfs_rq's child load-average */
static inline void enqueue_entity_load_avg(struct cfs_rq *cfs_rq,
struct sched_entity *se,
@@ -2414,7 +2574,10 @@ void idle_exit_fair(struct rq *this_rq)
update_rq_runnable_avg(this_rq, 0);
}
-#else
+static int idle_balance(struct rq *this_rq);
+
+#else /* CONFIG_SMP */
+
static inline void update_entity_load_avg(struct sched_entity *se,
int update_cfs_rq) {}
static inline void update_rq_runnable_avg(struct rq *rq, int runnable) {}
@@ -2426,7 +2589,13 @@ static inline void dequeue_entity_load_avg(struct cfs_rq *cfs_rq,
int sleep) {}
static inline void update_cfs_rq_blocked_load(struct cfs_rq *cfs_rq,
int force_update) {}
-#endif
+
+static inline int idle_balance(struct rq *rq)
+{
+ return 0;
+}
+
+#endif /* CONFIG_SMP */
static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
@@ -2576,10 +2745,10 @@ static void __clear_buddies_last(struct sched_entity *se)
{
for_each_sched_entity(se) {
struct cfs_rq *cfs_rq = cfs_rq_of(se);
- if (cfs_rq->last == se)
- cfs_rq->last = NULL;
- else
+ if (cfs_rq->last != se)
break;
+
+ cfs_rq->last = NULL;
}
}
@@ -2587,10 +2756,10 @@ static void __clear_buddies_next(struct sched_entity *se)
{
for_each_sched_entity(se) {
struct cfs_rq *cfs_rq = cfs_rq_of(se);
- if (cfs_rq->next == se)
- cfs_rq->next = NULL;
- else
+ if (cfs_rq->next != se)
break;
+
+ cfs_rq->next = NULL;
}
}
@@ -2598,10 +2767,10 @@ static void __clear_buddies_skip(struct sched_entity *se)
{
for_each_sched_entity(se) {
struct cfs_rq *cfs_rq = cfs_rq_of(se);
- if (cfs_rq->skip == se)
- cfs_rq->skip = NULL;
- else
+ if (cfs_rq->skip != se)
break;
+
+ cfs_rq->skip = NULL;
}
}
@@ -2744,17 +2913,36 @@ wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se);
* 3) pick the "last" process, for cache locality
* 4) do not run the "skip" process, if something else is available
*/
-static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
+static struct sched_entity *
+pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{
- struct sched_entity *se = __pick_first_entity(cfs_rq);
- struct sched_entity *left = se;
+ struct sched_entity *left = __pick_first_entity(cfs_rq);
+ struct sched_entity *se;
+
+ /*
+ * If curr is set we have to see if its left of the leftmost entity
+ * still in the tree, provided there was anything in the tree at all.
+ */
+ if (!left || (curr && entity_before(curr, left)))
+ left = curr;
+
+ se = left; /* ideally we run the leftmost entity */
/*
* Avoid running the skip buddy, if running something else can
* be done without getting too unfair.
*/
if (cfs_rq->skip == se) {
- struct sched_entity *second = __pick_next_entity(se);
+ struct sched_entity *second;
+
+ if (se == curr) {
+ second = __pick_first_entity(cfs_rq);
+ } else {
+ second = __pick_next_entity(se);
+ if (!second || (curr && entity_before(curr, second)))
+ second = curr;
+ }
+
if (second && wakeup_preempt_entity(second, left) < 1)
se = second;
}
@@ -2776,7 +2964,7 @@ static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
return se;
}
-static void check_cfs_rq_runtime(struct cfs_rq *cfs_rq);
+static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq);
static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
{
@@ -3431,22 +3619,23 @@ static void check_enqueue_throttle(struct cfs_rq *cfs_rq)
}
/* conditionally throttle active cfs_rq's from put_prev_entity() */
-static void check_cfs_rq_runtime(struct cfs_rq *cfs_rq)
+static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq)
{
if (!cfs_bandwidth_used())
- return;
+ return false;
if (likely(!cfs_rq->runtime_enabled || cfs_rq->runtime_remaining > 0))
- return;
+ return false;
/*
* it's possible for a throttled entity to be forced into a running
* state (e.g. set_curr_task), in this case we're finished.
*/
if (cfs_rq_throttled(cfs_rq))
- return;
+ return true;
throttle_cfs_rq(cfs_rq);
+ return true;
}
static enum hrtimer_restart sched_cfs_slack_timer(struct hrtimer *timer)
@@ -3556,7 +3745,7 @@ static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq)
}
static void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) {}
-static void check_cfs_rq_runtime(struct cfs_rq *cfs_rq) {}
+static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq) { return false; }
static void check_enqueue_throttle(struct cfs_rq *cfs_rq) {}
static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq) {}
@@ -4211,13 +4400,14 @@ done:
}
/*
- * sched_balance_self: balance the current task (running on cpu) in domains
- * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and
- * SD_BALANCE_EXEC.
+ * select_task_rq_fair: Select target runqueue for the waking task in domains
+ * that have the 'sd_flag' flag set. In practice, this is SD_BALANCE_WAKE,
+ * SD_BALANCE_FORK, or SD_BALANCE_EXEC.
*
- * Balance, ie. select the least loaded group.
+ * Balances load by selecting the idlest cpu in the idlest group, or under
+ * certain conditions an idle sibling cpu if the domain has SD_WAKE_AFFINE set.
*
- * Returns the target CPU number, or the same CPU if no balancing is needed.
+ * Returns the target cpu number.
*
* preempt must be disabled.
*/
@@ -4492,26 +4682,124 @@ preempt:
set_last_buddy(se);
}
-static struct task_struct *pick_next_task_fair(struct rq *rq)
+static struct task_struct *
+pick_next_task_fair(struct rq *rq, struct task_struct *prev)
{
- struct task_struct *p;
struct cfs_rq *cfs_rq = &rq->cfs;
struct sched_entity *se;
+ struct task_struct *p;
+ int new_tasks;
+again:
+#ifdef CONFIG_FAIR_GROUP_SCHED
if (!cfs_rq->nr_running)
- return NULL;
+ goto idle;
+
+ if (prev->sched_class != &fair_sched_class)
+ goto simple;
+
+ /*
+ * Because of the set_next_buddy() in dequeue_task_fair() it is rather
+ * likely that a next task is from the same cgroup as the current.
+ *
+ * Therefore attempt to avoid putting and setting the entire cgroup
+ * hierarchy, only change the part that actually changes.
+ */
do {
- se = pick_next_entity(cfs_rq);
+ struct sched_entity *curr = cfs_rq->curr;
+
+ /*
+ * Since we got here without doing put_prev_entity() we also
+ * have to consider cfs_rq->curr. If it is still a runnable
+ * entity, update_curr() will update its vruntime, otherwise
+ * forget we've ever seen it.
+ */
+ if (curr && curr->on_rq)
+ update_curr(cfs_rq);
+ else
+ curr = NULL;
+
+ /*
+ * This call to check_cfs_rq_runtime() will do the throttle and
+ * dequeue its entity in the parent(s). Therefore the 'simple'
+ * nr_running test will indeed be correct.
+ */
+ if (unlikely(check_cfs_rq_runtime(cfs_rq)))
+ goto simple;
+
+ se = pick_next_entity(cfs_rq, curr);
+ cfs_rq = group_cfs_rq(se);
+ } while (cfs_rq);
+
+ p = task_of(se);
+
+ /*
+ * Since we haven't yet done put_prev_entity and if the selected task
+ * is a different task than we started out with, try and touch the
+ * least amount of cfs_rqs.
+ */
+ if (prev != p) {
+ struct sched_entity *pse = &prev->se;
+
+ while (!(cfs_rq = is_same_group(se, pse))) {
+ int se_depth = se->depth;
+ int pse_depth = pse->depth;
+
+ if (se_depth <= pse_depth) {
+ put_prev_entity(cfs_rq_of(pse), pse);
+ pse = parent_entity(pse);
+ }
+ if (se_depth >= pse_depth) {
+ set_next_entity(cfs_rq_of(se), se);
+ se = parent_entity(se);
+ }
+ }
+
+ put_prev_entity(cfs_rq, pse);
+ set_next_entity(cfs_rq, se);
+ }
+
+ if (hrtick_enabled(rq))
+ hrtick_start_fair(rq, p);
+
+ return p;
+simple:
+ cfs_rq = &rq->cfs;
+#endif
+
+ if (!cfs_rq->nr_running)
+ goto idle;
+
+ put_prev_task(rq, prev);
+
+ do {
+ se = pick_next_entity(cfs_rq, NULL);
set_next_entity(cfs_rq, se);
cfs_rq = group_cfs_rq(se);
} while (cfs_rq);
p = task_of(se);
+
if (hrtick_enabled(rq))
hrtick_start_fair(rq, p);
return p;
+
+idle:
+ new_tasks = idle_balance(rq);
+ /*
+ * Because idle_balance() releases (and re-acquires) rq->lock, it is
+ * possible for any higher priority task to appear. In that case we
+ * must re-start the pick_next_entity() loop.
+ */
+ if (new_tasks < 0)
+ return RETRY_TASK;
+
+ if (new_tasks > 0)
+ goto again;
+
+ return NULL;
}
/*
@@ -4749,7 +5037,7 @@ static void move_task(struct task_struct *p, struct lb_env *env)
* Is this task likely cache-hot:
*/
static int
-task_hot(struct task_struct *p, u64 now, struct sched_domain *sd)
+task_hot(struct task_struct *p, u64 now)
{
s64 delta;
@@ -4783,7 +5071,7 @@ static bool migrate_improves_locality(struct task_struct *p, struct lb_env *env)
{
int src_nid, dst_nid;
- if (!sched_feat(NUMA_FAVOUR_HIGHER) || !p->numa_faults ||
+ if (!sched_feat(NUMA_FAVOUR_HIGHER) || !p->numa_faults_memory ||
!(env->sd->flags & SD_NUMA)) {
return false;
}
@@ -4814,7 +5102,7 @@ static bool migrate_degrades_locality(struct task_struct *p, struct lb_env *env)
if (!sched_feat(NUMA) || !sched_feat(NUMA_RESIST_LOWER))
return false;
- if (!p->numa_faults || !(env->sd->flags & SD_NUMA))
+ if (!p->numa_faults_memory || !(env->sd->flags & SD_NUMA))
return false;
src_nid = cpu_to_node(env->src_cpu);
@@ -4910,7 +5198,7 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
* 2) task is cache cold, or
* 3) too many balance attempts have failed.
*/
- tsk_cache_hot = task_hot(p, rq_clock_task(env->src_rq), env->sd);
+ tsk_cache_hot = task_hot(p, rq_clock_task(env->src_rq));
if (!tsk_cache_hot)
tsk_cache_hot = migrate_degrades_locality(p, env);
@@ -5773,12 +6061,10 @@ void fix_small_imbalance(struct lb_env *env, struct sd_lb_stats *sds)
pwr_now /= SCHED_POWER_SCALE;
/* Amount of load we'd subtract */
- tmp = (busiest->load_per_task * SCHED_POWER_SCALE) /
- busiest->group_power;
- if (busiest->avg_load > tmp) {
+ if (busiest->avg_load > scaled_busy_load_per_task) {
pwr_move += busiest->group_power *
min(busiest->load_per_task,
- busiest->avg_load - tmp);
+ busiest->avg_load - scaled_busy_load_per_task);
}
/* Amount of load we'd add */
@@ -6357,17 +6643,23 @@ out:
* idle_balance is called by schedule() if this_cpu is about to become
* idle. Attempts to pull tasks from other CPUs.
*/
-void idle_balance(int this_cpu, struct rq *this_rq)
+static int idle_balance(struct rq *this_rq)
{
struct sched_domain *sd;
int pulled_task = 0;
unsigned long next_balance = jiffies + HZ;
u64 curr_cost = 0;
+ int this_cpu = this_rq->cpu;
+ idle_enter_fair(this_rq);
+ /*
+ * We must set idle_stamp _before_ calling idle_balance(), such that we
+ * measure the duration of idle_balance() as idle time.
+ */
this_rq->idle_stamp = rq_clock(this_rq);
if (this_rq->avg_idle < sysctl_sched_migration_cost)
- return;
+ goto out;
/*
* Drop the rq->lock, but keep IRQ/preempt disabled.
@@ -6405,15 +6697,22 @@ void idle_balance(int this_cpu, struct rq *this_rq)
interval = msecs_to_jiffies(sd->balance_interval);
if (time_after(next_balance, sd->last_balance + interval))
next_balance = sd->last_balance + interval;
- if (pulled_task) {
- this_rq->idle_stamp = 0;
+ if (pulled_task)
break;
- }
}
rcu_read_unlock();
raw_spin_lock(&this_rq->lock);
+ /*
+ * While browsing the domains, we released the rq lock.
+ * A task could have be enqueued in the meantime
+ */
+ if (this_rq->cfs.h_nr_running && !pulled_task) {
+ pulled_task = 1;
+ goto out;
+ }
+
if (pulled_task || time_after(jiffies, this_rq->next_balance)) {
/*
* We are going idle. next_balance may be set based on
@@ -6424,6 +6723,20 @@ void idle_balance(int this_cpu, struct rq *this_rq)
if (curr_cost > this_rq->max_idle_balance_cost)
this_rq->max_idle_balance_cost = curr_cost;
+
+out:
+ /* Is there a task of a high priority class? */
+ if (this_rq->nr_running != this_rq->cfs.h_nr_running &&
+ (this_rq->dl.dl_nr_running ||
+ (this_rq->rt.rt_nr_running && !rt_rq_throttled(&this_rq->rt))))
+ pulled_task = -1;
+
+ if (pulled_task) {
+ idle_exit_fair(this_rq);
+ this_rq->idle_stamp = 0;
+ }
+
+ return pulled_task;
}
/*
@@ -6494,6 +6807,11 @@ out_unlock:
return 0;
}
+static inline int on_null_domain(struct rq *rq)
+{
+ return unlikely(!rcu_dereference_sched(rq->sd));
+}
+
#ifdef CONFIG_NO_HZ_COMMON
/*
* idle load balancing details
@@ -6548,8 +6866,13 @@ static void nohz_balancer_kick(void)
static inline void nohz_balance_exit_idle(int cpu)
{
if (unlikely(test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))) {
- cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
- atomic_dec(&nohz.nr_cpus);
+ /*
+ * Completely isolated CPUs don't ever set, so we must test.
+ */
+ if (likely(cpumask_test_cpu(cpu, nohz.idle_cpus_mask))) {
+ cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
+ atomic_dec(&nohz.nr_cpus);
+ }
clear_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
}
}
@@ -6603,6 +6926,12 @@ void nohz_balance_enter_idle(int cpu)
if (test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))
return;
+ /*
+ * If we're a completely isolated CPU, we don't play.
+ */
+ if (on_null_domain(cpu_rq(cpu)))
+ return;
+
cpumask_set_cpu(cpu, nohz.idle_cpus_mask);
atomic_inc(&nohz.nr_cpus);
set_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
@@ -6865,11 +7194,6 @@ static void run_rebalance_domains(struct softirq_action *h)
nohz_idle_balance(this_rq, idle);
}
-static inline int on_null_domain(struct rq *rq)
-{
- return !rcu_dereference_sched(rq->sd);
-}
-
/*
* Trigger the SCHED_SOFTIRQ if it is time to do periodic load balancing.
*/
@@ -6999,15 +7323,15 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p)
struct cfs_rq *cfs_rq = cfs_rq_of(se);
/*
- * Ensure the task's vruntime is normalized, so that when its
+ * Ensure the task's vruntime is normalized, so that when it's
* switched back to the fair class the enqueue_entity(.flags=0) will
* do the right thing.
*
- * If it was on_rq, then the dequeue_entity(.flags=0) will already
- * have normalized the vruntime, if it was !on_rq, then only when
+ * If it's on_rq, then the dequeue_entity(.flags=0) will already
+ * have normalized the vruntime, if it's !on_rq, then only when
* the task is sleeping will it still have non-normalized vruntime.
*/
- if (!se->on_rq && p->state != TASK_RUNNING) {
+ if (!p->on_rq && p->state != TASK_RUNNING) {
/*
* Fix up our vruntime so that the current sleep doesn't
* cause 'unlimited' sleep bonus.
@@ -7034,7 +7358,15 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p)
*/
static void switched_to_fair(struct rq *rq, struct task_struct *p)
{
- if (!p->se.on_rq)
+ struct sched_entity *se = &p->se;
+#ifdef CONFIG_FAIR_GROUP_SCHED
+ /*
+ * Since the real-depth could have been changed (only FAIR
+ * class maintain depth value), reset depth properly.
+ */
+ se->depth = se->parent ? se->parent->depth + 1 : 0;
+#endif
+ if (!se->on_rq)
return;
/*
@@ -7082,7 +7414,9 @@ void init_cfs_rq(struct cfs_rq *cfs_rq)
#ifdef CONFIG_FAIR_GROUP_SCHED
static void task_move_group_fair(struct task_struct *p, int on_rq)
{
+ struct sched_entity *se = &p->se;
struct cfs_rq *cfs_rq;
+
/*
* If the task was not on the rq at the time of this cgroup movement
* it must have been asleep, sleeping tasks keep their ->vruntime
@@ -7108,23 +7442,24 @@ static void task_move_group_fair(struct task_struct *p, int on_rq)
* To prevent boost or penalty in the new cfs_rq caused by delta
* min_vruntime between the two cfs_rqs, we skip vruntime adjustment.
*/
- if (!on_rq && (!p->se.sum_exec_runtime || p->state == TASK_WAKING))
+ if (!on_rq && (!se->sum_exec_runtime || p->state == TASK_WAKING))
on_rq = 1;
if (!on_rq)
- p->se.vruntime -= cfs_rq_of(&p->se)->min_vruntime;
+ se->vruntime -= cfs_rq_of(se)->min_vruntime;
set_task_rq(p, task_cpu(p));
+ se->depth = se->parent ? se->parent->depth + 1 : 0;
if (!on_rq) {
- cfs_rq = cfs_rq_of(&p->se);
- p->se.vruntime += cfs_rq->min_vruntime;
+ cfs_rq = cfs_rq_of(se);
+ se->vruntime += cfs_rq->min_vruntime;
#ifdef CONFIG_SMP
/*
* migrate_task_rq_fair() will have removed our previous
* contribution, but we must synchronize for ongoing future
* decay.
*/
- p->se.avg.decay_count = atomic64_read(&cfs_rq->decay_counter);
- cfs_rq->blocked_load_avg += p->se.avg.load_avg_contrib;
+ se->avg.decay_count = atomic64_read(&cfs_rq->decay_counter);
+ cfs_rq->blocked_load_avg += se->avg.load_avg_contrib;
#endif
}
}
@@ -7220,10 +7555,13 @@ void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq,
if (!se)
return;
- if (!parent)
+ if (!parent) {
se->cfs_rq = &rq->cfs;
- else
+ se->depth = 0;
+ } else {
se->cfs_rq = parent->my_q;
+ se->depth = parent->depth + 1;
+ }
se->my_q = cfs_rq;
/* guarantee group entities always have weight */
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
new file mode 100644
index 000000000000..8f4390a079c7
--- /dev/null
+++ b/kernel/sched/idle.c
@@ -0,0 +1,265 @@
+/*
+ * Generic entry point for the idle threads
+ */
+#include <linux/sched.h>
+#include <linux/cpu.h>
+#include <linux/cpuidle.h>
+#include <linux/tick.h>
+#include <linux/mm.h>
+#include <linux/stackprotector.h>
+
+#include <asm/tlb.h>
+
+#include <trace/events/power.h>
+
+static int __read_mostly cpu_idle_force_poll;
+
+void cpu_idle_poll_ctrl(bool enable)
+{
+ if (enable) {
+ cpu_idle_force_poll++;
+ } else {
+ cpu_idle_force_poll--;
+ WARN_ON_ONCE(cpu_idle_force_poll < 0);
+ }
+}
+
+#ifdef CONFIG_GENERIC_IDLE_POLL_SETUP
+static int __init cpu_idle_poll_setup(char *__unused)
+{
+ cpu_idle_force_poll = 1;
+ return 1;
+}
+__setup("nohlt", cpu_idle_poll_setup);
+
+static int __init cpu_idle_nopoll_setup(char *__unused)
+{
+ cpu_idle_force_poll = 0;
+ return 1;
+}
+__setup("hlt", cpu_idle_nopoll_setup);
+#endif
+
+static inline int cpu_idle_poll(void)
+{
+ rcu_idle_enter();
+ trace_cpu_idle_rcuidle(0, smp_processor_id());
+ local_irq_enable();
+ while (!tif_need_resched())
+ cpu_relax();
+ trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
+ rcu_idle_exit();
+ return 1;
+}
+
+/* Weak implementations for optional arch specific functions */
+void __weak arch_cpu_idle_prepare(void) { }
+void __weak arch_cpu_idle_enter(void) { }
+void __weak arch_cpu_idle_exit(void) { }
+void __weak arch_cpu_idle_dead(void) { }
+void __weak arch_cpu_idle(void)
+{
+ cpu_idle_force_poll = 1;
+ local_irq_enable();
+}
+
+/**
+ * cpuidle_idle_call - the main idle function
+ *
+ * NOTE: no locks or semaphores should be used here
+ * return non-zero on failure
+ */
+static int cpuidle_idle_call(void)
+{
+ struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
+ struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
+ int next_state, entered_state, ret;
+ bool broadcast;
+
+ /*
+ * Check if the idle task must be rescheduled. If it is the
+ * case, exit the function after re-enabling the local irq and
+ * set again the polling flag
+ */
+ if (current_clr_polling_and_test()) {
+ local_irq_enable();
+ __current_set_polling();
+ return 0;
+ }
+
+ /*
+ * During the idle period, stop measuring the disabled irqs
+ * critical sections latencies
+ */
+ stop_critical_timings();
+
+ /*
+ * Tell the RCU framework we are entering an idle section,
+ * so no more rcu read side critical sections and one more
+ * step to the grace period
+ */
+ rcu_idle_enter();
+
+ /*
+ * Check if the cpuidle framework is ready, otherwise fallback
+ * to the default arch specific idle method
+ */
+ ret = cpuidle_enabled(drv, dev);
+
+ if (!ret) {
+ /*
+ * Ask the governor to choose an idle state it thinks
+ * it is convenient to go to. There is *always* a
+ * convenient idle state
+ */
+ next_state = cpuidle_select(drv, dev);
+
+ /*
+ * The idle task must be scheduled, it is pointless to
+ * go to idle, just update no idle residency and get
+ * out of this function
+ */
+ if (current_clr_polling_and_test()) {
+ dev->last_residency = 0;
+ entered_state = next_state;
+ local_irq_enable();
+ } else {
+ broadcast = !!(drv->states[next_state].flags &
+ CPUIDLE_FLAG_TIMER_STOP);
+
+ if (broadcast)
+ /*
+ * Tell the time framework to switch
+ * to a broadcast timer because our
+ * local timer will be shutdown. If a
+ * local timer is used from another
+ * cpu as a broadcast timer, this call
+ * may fail if it is not available
+ */
+ ret = clockevents_notify(
+ CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
+ &dev->cpu);
+
+ if (!ret) {
+ trace_cpu_idle_rcuidle(next_state, dev->cpu);
+
+ /*
+ * Enter the idle state previously
+ * returned by the governor
+ * decision. This function will block
+ * until an interrupt occurs and will
+ * take care of re-enabling the local
+ * interrupts
+ */
+ entered_state = cpuidle_enter(drv, dev,
+ next_state);
+
+ trace_cpu_idle_rcuidle(PWR_EVENT_EXIT,
+ dev->cpu);
+
+ if (broadcast)
+ clockevents_notify(
+ CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
+ &dev->cpu);
+
+ /*
+ * Give the governor an opportunity to reflect on the
+ * outcome
+ */
+ cpuidle_reflect(dev, entered_state);
+ }
+ }
+ }
+
+ /*
+ * We can't use the cpuidle framework, let's use the default
+ * idle routine
+ */
+ if (ret)
+ arch_cpu_idle();
+
+ __current_set_polling();
+
+ /*
+ * It is up to the idle functions to enable back the local
+ * interrupt
+ */
+ if (WARN_ON_ONCE(irqs_disabled()))
+ local_irq_enable();
+
+ rcu_idle_exit();
+ start_critical_timings();
+
+ return 0;
+}
+
+/*
+ * Generic idle loop implementation
+ */
+static void cpu_idle_loop(void)
+{
+ while (1) {
+ tick_nohz_idle_enter();
+
+ while (!need_resched()) {
+ check_pgt_cache();
+ rmb();
+
+ if (cpu_is_offline(smp_processor_id()))
+ arch_cpu_idle_dead();
+
+ local_irq_disable();
+ arch_cpu_idle_enter();
+
+ /*
+ * In poll mode we reenable interrupts and spin.
+ *
+ * Also if we detected in the wakeup from idle
+ * path that the tick broadcast device expired
+ * for us, we don't want to go deep idle as we
+ * know that the IPI is going to arrive right
+ * away
+ */
+ if (cpu_idle_force_poll || tick_check_broadcast_expired())
+ cpu_idle_poll();
+ else
+ cpuidle_idle_call();
+
+ arch_cpu_idle_exit();
+ }
+
+ /*
+ * Since we fell out of the loop above, we know
+ * TIF_NEED_RESCHED must be set, propagate it into
+ * PREEMPT_NEED_RESCHED.
+ *
+ * This is required because for polling idle loops we will
+ * not have had an IPI to fold the state for us.
+ */
+ preempt_set_need_resched();
+ tick_nohz_idle_exit();
+ schedule_preempt_disabled();
+ }
+}
+
+void cpu_startup_entry(enum cpuhp_state state)
+{
+ /*
+ * This #ifdef needs to die, but it's too late in the cycle to
+ * make this generic (arm and sh have never invoked the canary
+ * init for the non boot cpus!). Will be fixed in 3.11
+ */
+#ifdef CONFIG_X86
+ /*
+ * If we're the non-boot CPU, nothing set the stack canary up
+ * for us. The boot CPU already has it initialized but no harm
+ * in doing it again. This is a good place for updating it, as
+ * we wont ever return from this function (so the invalid
+ * canaries already on the stack wont ever trigger).
+ */
+ boot_init_stack_canary();
+#endif
+ __current_set_polling();
+ arch_cpu_idle_prepare();
+ cpu_idle_loop();
+}
diff --git a/kernel/sched/idle_task.c b/kernel/sched/idle_task.c
index 516c3d9ceea1..879f2b75266a 100644
--- a/kernel/sched/idle_task.c
+++ b/kernel/sched/idle_task.c
@@ -13,18 +13,8 @@ select_task_rq_idle(struct task_struct *p, int cpu, int sd_flag, int flags)
{
return task_cpu(p); /* IDLE tasks as never migrated */
}
-
-static void pre_schedule_idle(struct rq *rq, struct task_struct *prev)
-{
- idle_exit_fair(rq);
- rq_last_tick_reset(rq);
-}
-
-static void post_schedule_idle(struct rq *rq)
-{
- idle_enter_fair(rq);
-}
#endif /* CONFIG_SMP */
+
/*
* Idle tasks are unconditionally rescheduled:
*/
@@ -33,13 +23,12 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int fl
resched_task(rq->idle);
}
-static struct task_struct *pick_next_task_idle(struct rq *rq)
+static struct task_struct *
+pick_next_task_idle(struct rq *rq, struct task_struct *prev)
{
+ put_prev_task(rq, prev);
+
schedstat_inc(rq, sched_goidle);
-#ifdef CONFIG_SMP
- /* Trigger the post schedule to do an idle_enter for CFS */
- rq->post_schedule = 1;
-#endif
return rq->idle;
}
@@ -58,6 +47,8 @@ dequeue_task_idle(struct rq *rq, struct task_struct *p, int flags)
static void put_prev_task_idle(struct rq *rq, struct task_struct *prev)
{
+ idle_exit_fair(rq);
+ rq_last_tick_reset(rq);
}
static void task_tick_idle(struct rq *rq, struct task_struct *curr, int queued)
@@ -101,8 +92,6 @@ const struct sched_class idle_sched_class = {
#ifdef CONFIG_SMP
.select_task_rq = select_task_rq_idle,
- .pre_schedule = pre_schedule_idle,
- .post_schedule = post_schedule_idle,
#endif
.set_curr_task = set_curr_task_idle,
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index a2740b775b45..d8cdf1618551 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -229,6 +229,14 @@ int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent)
#ifdef CONFIG_SMP
+static int pull_rt_task(struct rq *this_rq);
+
+static inline bool need_pull_rt_task(struct rq *rq, struct task_struct *prev)
+{
+ /* Try to pull RT tasks here if we lower this rq's prio */
+ return rq->rt.highest_prio.curr > prev->prio;
+}
+
static inline int rt_overloaded(struct rq *rq)
{
return atomic_read(&rq->rd->rto_count);
@@ -315,6 +323,15 @@ static inline int has_pushable_tasks(struct rq *rq)
return !plist_head_empty(&rq->rt.pushable_tasks);
}
+static inline void set_post_schedule(struct rq *rq)
+{
+ /*
+ * We detect this state here so that we can avoid taking the RQ
+ * lock again later if there is no need to push
+ */
+ rq->post_schedule = has_pushable_tasks(rq);
+}
+
static void enqueue_pushable_task(struct rq *rq, struct task_struct *p)
{
plist_del(&p->pushable_tasks, &rq->rt.pushable_tasks);
@@ -359,6 +376,19 @@ void dec_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
{
}
+static inline bool need_pull_rt_task(struct rq *rq, struct task_struct *prev)
+{
+ return false;
+}
+
+static inline int pull_rt_task(struct rq *this_rq)
+{
+ return 0;
+}
+
+static inline void set_post_schedule(struct rq *rq)
+{
+}
#endif /* CONFIG_SMP */
static inline int on_rt_rq(struct sched_rt_entity *rt_se)
@@ -440,11 +470,6 @@ static void sched_rt_rq_dequeue(struct rt_rq *rt_rq)
dequeue_rt_entity(rt_se);
}
-static inline int rt_rq_throttled(struct rt_rq *rt_rq)
-{
- return rt_rq->rt_throttled && !rt_rq->rt_nr_boosted;
-}
-
static int rt_se_boosted(struct sched_rt_entity *rt_se)
{
struct rt_rq *rt_rq = group_rt_rq(rt_se);
@@ -515,11 +540,6 @@ static inline void sched_rt_rq_dequeue(struct rt_rq *rt_rq)
{
}
-static inline int rt_rq_throttled(struct rt_rq *rt_rq)
-{
- return rt_rq->rt_throttled;
-}
-
static inline const struct cpumask *sched_rt_period_mask(void)
{
return cpu_online_mask;
@@ -538,6 +558,14 @@ static inline struct rt_bandwidth *sched_rt_bandwidth(struct rt_rq *rt_rq)
#endif /* CONFIG_RT_GROUP_SCHED */
+bool sched_rt_bandwidth_account(struct rt_rq *rt_rq)
+{
+ struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);
+
+ return (hrtimer_active(&rt_b->rt_period_timer) ||
+ rt_rq->rt_time < rt_b->rt_runtime);
+}
+
#ifdef CONFIG_SMP
/*
* We ran out of runtime, see if we can borrow some from our neighbours.
@@ -1310,15 +1338,7 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq)
{
struct sched_rt_entity *rt_se;
struct task_struct *p;
- struct rt_rq *rt_rq;
-
- rt_rq = &rq->rt;
-
- if (!rt_rq->rt_nr_running)
- return NULL;
-
- if (rt_rq_throttled(rt_rq))
- return NULL;
+ struct rt_rq *rt_rq = &rq->rt;
do {
rt_se = pick_next_rt_entity(rq, rt_rq);
@@ -1332,21 +1352,45 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq)
return p;
}
-static struct task_struct *pick_next_task_rt(struct rq *rq)
+static struct task_struct *
+pick_next_task_rt(struct rq *rq, struct task_struct *prev)
{
- struct task_struct *p = _pick_next_task_rt(rq);
+ struct task_struct *p;
+ struct rt_rq *rt_rq = &rq->rt;
+
+ if (need_pull_rt_task(rq, prev)) {
+ pull_rt_task(rq);
+ /*
+ * pull_rt_task() can drop (and re-acquire) rq->lock; this
+ * means a dl task can slip in, in which case we need to
+ * re-start task selection.
+ */
+ if (unlikely(rq->dl.dl_nr_running))
+ return RETRY_TASK;
+ }
+
+ /*
+ * We may dequeue prev's rt_rq in put_prev_task().
+ * So, we update time before rt_nr_running check.
+ */
+ if (prev->sched_class == &rt_sched_class)
+ update_curr_rt(rq);
+
+ if (!rt_rq->rt_nr_running)
+ return NULL;
+
+ if (rt_rq_throttled(rt_rq))
+ return NULL;
+
+ put_prev_task(rq, prev);
+
+ p = _pick_next_task_rt(rq);
/* The running task is never eligible for pushing */
if (p)
dequeue_pushable_task(rq, p);
-#ifdef CONFIG_SMP
- /*
- * We detect this state here so that we can avoid taking the RQ
- * lock again later if there is no need to push
- */
- rq->post_schedule = has_pushable_tasks(rq);
-#endif
+ set_post_schedule(rq);
return p;
}
@@ -1716,13 +1760,6 @@ skip:
return ret;
}
-static void pre_schedule_rt(struct rq *rq, struct task_struct *prev)
-{
- /* Try to pull RT tasks here if we lower this rq's prio */
- if (rq->rt.highest_prio.curr > prev->prio)
- pull_rt_task(rq);
-}
-
static void post_schedule_rt(struct rq *rq)
{
push_rt_tasks(rq);
@@ -1825,7 +1862,7 @@ static void switched_from_rt(struct rq *rq, struct task_struct *p)
resched_task(rq->curr);
}
-void init_sched_rt_class(void)
+void __init init_sched_rt_class(void)
{
unsigned int i;
@@ -1999,7 +2036,6 @@ const struct sched_class rt_sched_class = {
.set_cpus_allowed = set_cpus_allowed_rt,
.rq_online = rq_online_rt,
.rq_offline = rq_offline_rt,
- .pre_schedule = pre_schedule_rt,
.post_schedule = post_schedule_rt,
.task_woken = task_woken_rt,
.switched_from = switched_from_rt,
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index c2119fd20f8b..c9007f28d3a2 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -24,24 +24,6 @@ extern long calc_load_fold_active(struct rq *this_rq);
extern void update_cpu_load_active(struct rq *this_rq);
/*
- * Convert user-nice values [ -20 ... 0 ... 19 ]
- * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
- * and back.
- */
-#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20)
-#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20)
-#define TASK_NICE(p) PRIO_TO_NICE((p)->static_prio)
-
-/*
- * 'User priority' is the nice value converted to something we
- * can work with better when scaling various scheduler parameters,
- * it's a [ 0 ... 39 ] range.
- */
-#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
-#define TASK_USER_PRIO(p) USER_PRIO((p)->static_prio)
-#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
-
-/*
* Helpers for converting nanosecond timing to jiffy resolution
*/
#define NS_TO_JIFFIES(TIME) ((unsigned long)(TIME) / (NSEC_PER_SEC / HZ))
@@ -441,6 +423,18 @@ struct rt_rq {
#endif
};
+#ifdef CONFIG_RT_GROUP_SCHED
+static inline int rt_rq_throttled(struct rt_rq *rt_rq)
+{
+ return rt_rq->rt_throttled && !rt_rq->rt_nr_boosted;
+}
+#else
+static inline int rt_rq_throttled(struct rt_rq *rt_rq)
+{
+ return rt_rq->rt_throttled;
+}
+#endif
+
/* Deadline class' related fields in a runqueue */
struct dl_rq {
/* runqueue is an rbtree, ordered by deadline */
@@ -462,7 +456,6 @@ struct dl_rq {
} earliest_dl;
unsigned long dl_nr_migratory;
- unsigned long dl_nr_total;
int overloaded;
/*
@@ -559,11 +552,9 @@ struct rq {
#ifdef CONFIG_FAIR_GROUP_SCHED
/* list of leaf cfs_rq on this cpu: */
struct list_head leaf_cfs_rq_list;
-#endif /* CONFIG_FAIR_GROUP_SCHED */
-#ifdef CONFIG_RT_GROUP_SCHED
- struct list_head leaf_rt_rq_list;
-#endif
+ struct sched_avg avg;
+#endif /* CONFIG_FAIR_GROUP_SCHED */
/*
* This is part of a global counter where only the total sum
@@ -652,8 +643,6 @@ struct rq {
#ifdef CONFIG_SMP
struct llist_head wake_list;
#endif
-
- struct sched_avg avg;
};
static inline int cpu_of(struct rq *rq)
@@ -1113,6 +1102,8 @@ static const u32 prio_to_wmult[40] = {
#define DEQUEUE_SLEEP 1
+#define RETRY_TASK ((void *)-1UL)
+
struct sched_class {
const struct sched_class *next;
@@ -1123,14 +1114,22 @@ struct sched_class {
void (*check_preempt_curr) (struct rq *rq, struct task_struct *p, int flags);
- struct task_struct * (*pick_next_task) (struct rq *rq);
+ /*
+ * It is the responsibility of the pick_next_task() method that will
+ * return the next task to call put_prev_task() on the @prev task or
+ * something equivalent.
+ *
+ * May return RETRY_TASK when it finds a higher prio class has runnable
+ * tasks.
+ */
+ struct task_struct * (*pick_next_task) (struct rq *rq,
+ struct task_struct *prev);
void (*put_prev_task) (struct rq *rq, struct task_struct *p);
#ifdef CONFIG_SMP
int (*select_task_rq)(struct task_struct *p, int task_cpu, int sd_flag, int flags);
void (*migrate_task_rq)(struct task_struct *p, int next_cpu);
- void (*pre_schedule) (struct rq *this_rq, struct task_struct *task);
void (*post_schedule) (struct rq *this_rq);
void (*task_waking) (struct task_struct *task);
void (*task_woken) (struct rq *this_rq, struct task_struct *task);
@@ -1160,6 +1159,11 @@ struct sched_class {
#endif
};
+static inline void put_prev_task(struct rq *rq, struct task_struct *prev)
+{
+ prev->sched_class->put_prev_task(rq, prev);
+}
+
#define sched_class_highest (&stop_sched_class)
#define for_each_class(class) \
for (class = sched_class_highest; class; class = class->next)
@@ -1176,16 +1180,14 @@ extern const struct sched_class idle_sched_class;
extern void update_group_power(struct sched_domain *sd, int cpu);
extern void trigger_load_balance(struct rq *rq);
-extern void idle_balance(int this_cpu, struct rq *this_rq);
extern void idle_enter_fair(struct rq *this_rq);
extern void idle_exit_fair(struct rq *this_rq);
-#else /* CONFIG_SMP */
+#else
-static inline void idle_balance(int cpu, struct rq *rq)
-{
-}
+static inline void idle_enter_fair(struct rq *rq) { }
+static inline void idle_exit_fair(struct rq *rq) { }
#endif
@@ -1214,16 +1216,6 @@ extern void update_idle_cpu_load(struct rq *this_rq);
extern void init_task_runnable_average(struct task_struct *p);
-#ifdef CONFIG_PARAVIRT
-static inline u64 steal_ticks(u64 steal)
-{
- if (unlikely(steal > NSEC_PER_SEC))
- return div_u64(steal, TICK_NSEC);
-
- return __iter_div_u64_rem(steal, TICK_NSEC, &steal);
-}
-#endif
-
static inline void inc_nr_running(struct rq *rq)
{
rq->nr_running++;
diff --git a/kernel/sched/stop_task.c b/kernel/sched/stop_task.c
index fdb6bb0b3356..d6ce65dde541 100644
--- a/kernel/sched/stop_task.c
+++ b/kernel/sched/stop_task.c
@@ -23,16 +23,19 @@ check_preempt_curr_stop(struct rq *rq, struct task_struct *p, int flags)
/* we're never preempted */
}
-static struct task_struct *pick_next_task_stop(struct rq *rq)
+static struct task_struct *
+pick_next_task_stop(struct rq *rq, struct task_struct *prev)
{
struct task_struct *stop = rq->stop;
- if (stop && stop->on_rq) {
- stop->se.exec_start = rq_clock_task(rq);
- return stop;
- }
+ if (!stop || !stop->on_rq)
+ return NULL;
- return NULL;
+ put_prev_task(rq, prev);
+
+ stop->se.exec_start = rq_clock_task(rq);
+
+ return stop;
}
static void
diff --git a/kernel/smp.c b/kernel/smp.c
index ffee35bef179..06d574e42c72 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -117,13 +117,43 @@ static void csd_unlock(struct call_single_data *csd)
csd->flags &= ~CSD_FLAG_LOCK;
}
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_data, csd_data);
+
/*
* Insert a previously allocated call_single_data element
* for execution on the given CPU. data must already have
* ->func, ->info, and ->flags set.
*/
-static void generic_exec_single(int cpu, struct call_single_data *csd, int wait)
+static int generic_exec_single(int cpu, struct call_single_data *csd,
+ smp_call_func_t func, void *info, int wait)
{
+ struct call_single_data csd_stack = { .flags = 0 };
+ unsigned long flags;
+
+
+ if (cpu == smp_processor_id()) {
+ local_irq_save(flags);
+ func(info);
+ local_irq_restore(flags);
+ return 0;
+ }
+
+
+ if ((unsigned)cpu >= nr_cpu_ids || !cpu_online(cpu))
+ return -ENXIO;
+
+
+ if (!csd) {
+ csd = &csd_stack;
+ if (!wait)
+ csd = &__get_cpu_var(csd_data);
+ }
+
+ csd_lock(csd);
+
+ csd->func = func;
+ csd->info = info;
+
if (wait)
csd->flags |= CSD_FLAG_WAIT;
@@ -143,6 +173,8 @@ static void generic_exec_single(int cpu, struct call_single_data *csd, int wait)
if (wait)
csd_lock_wait(csd);
+
+ return 0;
}
/*
@@ -151,7 +183,8 @@ static void generic_exec_single(int cpu, struct call_single_data *csd, int wait)
*/
void generic_smp_call_function_single_interrupt(void)
{
- struct llist_node *entry, *next;
+ struct llist_node *entry;
+ struct call_single_data *csd, *csd_next;
/*
* Shouldn't receive this interrupt on a cpu that is not yet online.
@@ -161,21 +194,12 @@ void generic_smp_call_function_single_interrupt(void)
entry = llist_del_all(&__get_cpu_var(call_single_queue));
entry = llist_reverse_order(entry);
- while (entry) {
- struct call_single_data *csd;
-
- next = entry->next;
-
- csd = llist_entry(entry, struct call_single_data, llist);
+ llist_for_each_entry_safe(csd, csd_next, entry, llist) {
csd->func(csd->info);
csd_unlock(csd);
-
- entry = next;
}
}
-static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_data, csd_data);
-
/*
* smp_call_function_single - Run a function on a specific CPU
* @func: The function to run. This must be fast and non-blocking.
@@ -187,12 +211,8 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_data, csd_data);
int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
int wait)
{
- struct call_single_data d = {
- .flags = 0,
- };
- unsigned long flags;
int this_cpu;
- int err = 0;
+ int err;
/*
* prevent preemption and reschedule on another processor,
@@ -209,32 +229,41 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
&& !oops_in_progress);
- if (cpu == this_cpu) {
- local_irq_save(flags);
- func(info);
- local_irq_restore(flags);
- } else {
- if ((unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) {
- struct call_single_data *csd = &d;
+ err = generic_exec_single(cpu, NULL, func, info, wait);
- if (!wait)
- csd = &__get_cpu_var(csd_data);
+ put_cpu();
- csd_lock(csd);
+ return err;
+}
+EXPORT_SYMBOL(smp_call_function_single);
- csd->func = func;
- csd->info = info;
- generic_exec_single(cpu, csd, wait);
- } else {
- err = -ENXIO; /* CPU not online */
- }
- }
+/**
+ * smp_call_function_single_async(): Run an asynchronous function on a
+ * specific CPU.
+ * @cpu: The CPU to run on.
+ * @csd: Pre-allocated and setup data structure
+ *
+ * Like smp_call_function_single(), but the call is asynchonous and
+ * can thus be done from contexts with disabled interrupts.
+ *
+ * The caller passes his own pre-allocated data structure
+ * (ie: embedded in an object) and is responsible for synchronizing it
+ * such that the IPIs performed on the @csd are strictly serialized.
+ *
+ * NOTE: Be careful, there is unfortunately no current debugging facility to
+ * validate the correctness of this serialization.
+ */
+int smp_call_function_single_async(int cpu, struct call_single_data *csd)
+{
+ int err = 0;
- put_cpu();
+ preempt_disable();
+ err = generic_exec_single(cpu, csd, csd->func, csd->info, 0);
+ preempt_enable();
return err;
}
-EXPORT_SYMBOL(smp_call_function_single);
+EXPORT_SYMBOL_GPL(smp_call_function_single_async);
/*
* smp_call_function_any - Run a function on any of the given cpus
@@ -280,44 +309,6 @@ call:
EXPORT_SYMBOL_GPL(smp_call_function_any);
/**
- * __smp_call_function_single(): Run a function on a specific CPU
- * @cpu: The CPU to run on.
- * @data: Pre-allocated and setup data structure
- * @wait: If true, wait until function has completed on specified CPU.
- *
- * Like smp_call_function_single(), but allow caller to pass in a
- * pre-allocated data structure. Useful for embedding @data inside
- * other structures, for instance.
- */
-void __smp_call_function_single(int cpu, struct call_single_data *csd,
- int wait)
-{
- unsigned int this_cpu;
- unsigned long flags;
-
- this_cpu = get_cpu();
- /*
- * Can deadlock when called with interrupts disabled.
- * We allow cpu's that are not yet online though, as no one else can
- * send smp call function interrupt to this cpu and as such deadlocks
- * can't happen.
- */
- WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait && irqs_disabled()
- && !oops_in_progress);
-
- if (cpu == this_cpu) {
- local_irq_save(flags);
- csd->func(csd->info);
- local_irq_restore(flags);
- } else {
- csd_lock(csd);
- generic_exec_single(cpu, csd, wait);
- }
- put_cpu();
-}
-EXPORT_SYMBOL_GPL(__smp_call_function_single);
-
-/**
* smp_call_function_many(): Run a function on a set of other CPUs.
* @mask: The set of cpus to run on (only runs on online subset).
* @func: The function to run. This must be fast and non-blocking.
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 490fcbb1dc5b..b50990a5bea0 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -25,6 +25,7 @@
#include <linux/smp.h>
#include <linux/smpboot.h>
#include <linux/tick.h>
+#include <linux/irq.h>
#define CREATE_TRACE_POINTS
#include <trace/events/irq.h>
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index 84571e09c907..01fbae5b97b7 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -293,7 +293,7 @@ int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *
*/
smp_call_function_single(min(cpu1, cpu2),
&irq_cpu_stop_queue_work,
- &call_args, 0);
+ &call_args, 1);
lg_local_unlock(&stop_cpus_lock);
preempt_enable();
diff --git a/kernel/sys.c b/kernel/sys.c
index c0a58be780a4..adaeab6f7a87 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -174,10 +174,10 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
/* normalize: avoid signed division (rounding problems) */
error = -ESRCH;
- if (niceval < -20)
- niceval = -20;
- if (niceval > 19)
- niceval = 19;
+ if (niceval < MIN_NICE)
+ niceval = MIN_NICE;
+ if (niceval > MAX_NICE)
+ niceval = MAX_NICE;
rcu_read_lock();
read_lock(&tasklist_lock);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 49e13e1f8fe6..09d2e2413605 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -112,9 +112,6 @@ extern int sysctl_nr_open_min, sysctl_nr_open_max;
#ifndef CONFIG_MMU
extern int sysctl_nr_trim_pages;
#endif
-#ifdef CONFIG_BLOCK
-extern int blk_iopoll_enabled;
-#endif
/* Constants used for minimum and maximum */
#ifdef CONFIG_LOCKUP_DETECTOR
@@ -386,13 +383,6 @@ static struct ctl_table kern_table[] = {
.proc_handler = proc_dointvec,
},
{
- .procname = "numa_balancing_migrate_deferred",
- .data = &sysctl_numa_balancing_migrate_deferred,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
.procname = "numa_balancing",
.data = NULL, /* filled in by handler */
.maxlen = sizeof(unsigned int),
@@ -1094,15 +1084,6 @@ static struct ctl_table kern_table[] = {
.proc_handler = proc_dointvec,
},
#endif
-#ifdef CONFIG_BLOCK
- {
- .procname = "blk_iopoll",
- .data = &blk_iopoll_enabled,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
-#endif
{ }
};
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
index 3ce6e8c5f3fc..f448513a45ed 100644
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -124,7 +124,7 @@ config NO_HZ_FULL
endchoice
config NO_HZ_FULL_ALL
- bool "Full dynticks system on all CPUs by default"
+ bool "Full dynticks system on all CPUs by default (except CPU 0)"
depends on NO_HZ_FULL
help
If the user doesn't pass the nohz_full boot option to
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
index 9250130646f5..57a413fd0ebf 100644
--- a/kernel/time/Makefile
+++ b/kernel/time/Makefile
@@ -3,7 +3,10 @@ obj-y += timeconv.o posix-clock.o alarmtimer.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o
-obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += tick-broadcast.o
+ifeq ($(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST),y)
+ obj-y += tick-broadcast.o
+ obj-$(CONFIG_TICK_ONESHOT) += tick-broadcast-hrtimer.o
+endif
obj-$(CONFIG_GENERIC_SCHED_CLOCK) += sched_clock.o
obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o
obj-$(CONFIG_TICK_ONESHOT) += tick-sched.o
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 086ad6043bcb..ad362c260ef4 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -439,6 +439,19 @@ void clockevents_config_and_register(struct clock_event_device *dev,
}
EXPORT_SYMBOL_GPL(clockevents_config_and_register);
+int __clockevents_update_freq(struct clock_event_device *dev, u32 freq)
+{
+ clockevents_config(dev, freq);
+
+ if (dev->mode == CLOCK_EVT_MODE_ONESHOT)
+ return clockevents_program_event(dev, dev->next_event, false);
+
+ if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
+ dev->set_mode(CLOCK_EVT_MODE_PERIODIC, dev);
+
+ return 0;
+}
+
/**
* clockevents_update_freq - Update frequency and reprogram a clock event device.
* @dev: device to modify
@@ -446,17 +459,22 @@ EXPORT_SYMBOL_GPL(clockevents_config_and_register);
*
* Reconfigure and reprogram a clock event device in oneshot
* mode. Must be called on the cpu for which the device delivers per
- * cpu timer events with interrupts disabled! Returns 0 on success,
- * -ETIME when the event is in the past.
+ * cpu timer events. If called for the broadcast device the core takes
+ * care of serialization.
+ *
+ * Returns 0 on success, -ETIME when the event is in the past.
*/
int clockevents_update_freq(struct clock_event_device *dev, u32 freq)
{
- clockevents_config(dev, freq);
-
- if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
- return 0;
+ unsigned long flags;
+ int ret;
- return clockevents_program_event(dev, dev->next_event, false);
+ local_irq_save(flags);
+ ret = tick_broadcast_update_freq(dev, freq);
+ if (ret == -ENODEV)
+ ret = __clockevents_update_freq(dev, freq);
+ local_irq_restore(flags);
+ return ret;
}
/*
@@ -524,12 +542,13 @@ void clockevents_resume(void)
#ifdef CONFIG_GENERIC_CLOCKEVENTS
/**
* clockevents_notify - notification about relevant events
+ * Returns 0 on success, any other value on error
*/
-void clockevents_notify(unsigned long reason, void *arg)
+int clockevents_notify(unsigned long reason, void *arg)
{
struct clock_event_device *dev, *tmp;
unsigned long flags;
- int cpu;
+ int cpu, ret = 0;
raw_spin_lock_irqsave(&clockevents_lock, flags);
@@ -542,7 +561,7 @@ void clockevents_notify(unsigned long reason, void *arg)
case CLOCK_EVT_NOTIFY_BROADCAST_ENTER:
case CLOCK_EVT_NOTIFY_BROADCAST_EXIT:
- tick_broadcast_oneshot_control(reason);
+ ret = tick_broadcast_oneshot_control(reason);
break;
case CLOCK_EVT_NOTIFY_CPU_DYING:
@@ -585,6 +604,7 @@ void clockevents_notify(unsigned long reason, void *arg)
break;
}
raw_spin_unlock_irqrestore(&clockevents_lock, flags);
+ return ret;
}
EXPORT_SYMBOL_GPL(clockevents_notify);
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index af8d1d4f3d55..419a52cecd20 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -514,12 +514,13 @@ static void sync_cmos_clock(struct work_struct *work)
next.tv_sec++;
next.tv_nsec -= NSEC_PER_SEC;
}
- schedule_delayed_work(&sync_cmos_work, timespec_to_jiffies(&next));
+ queue_delayed_work(system_power_efficient_wq,
+ &sync_cmos_work, timespec_to_jiffies(&next));
}
void ntp_notify_cmos_timer(void)
{
- schedule_delayed_work(&sync_cmos_work, 0);
+ queue_delayed_work(system_power_efficient_wq, &sync_cmos_work, 0);
}
#else
diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c
index 0abb36464281..4d23dc4d8139 100644
--- a/kernel/time/sched_clock.c
+++ b/kernel/time/sched_clock.c
@@ -116,20 +116,42 @@ static enum hrtimer_restart sched_clock_poll(struct hrtimer *hrt)
void __init sched_clock_register(u64 (*read)(void), int bits,
unsigned long rate)
{
+ u64 res, wrap, new_mask, new_epoch, cyc, ns;
+ u32 new_mult, new_shift;
+ ktime_t new_wrap_kt;
unsigned long r;
- u64 res, wrap;
char r_unit;
if (cd.rate > rate)
return;
WARN_ON(!irqs_disabled());
- read_sched_clock = read;
- sched_clock_mask = CLOCKSOURCE_MASK(bits);
- cd.rate = rate;
/* calculate the mult/shift to convert counter ticks to ns. */
- clocks_calc_mult_shift(&cd.mult, &cd.shift, rate, NSEC_PER_SEC, 3600);
+ clocks_calc_mult_shift(&new_mult, &new_shift, rate, NSEC_PER_SEC, 3600);
+
+ new_mask = CLOCKSOURCE_MASK(bits);
+
+ /* calculate how many ns until we wrap */
+ wrap = clocks_calc_max_nsecs(new_mult, new_shift, 0, new_mask);
+ new_wrap_kt = ns_to_ktime(wrap - (wrap >> 3));
+
+ /* update epoch for new counter and update epoch_ns from old counter*/
+ new_epoch = read();
+ cyc = read_sched_clock();
+ ns = cd.epoch_ns + cyc_to_ns((cyc - cd.epoch_cyc) & sched_clock_mask,
+ cd.mult, cd.shift);
+
+ raw_write_seqcount_begin(&cd.seq);
+ read_sched_clock = read;
+ sched_clock_mask = new_mask;
+ cd.rate = rate;
+ cd.wrap_kt = new_wrap_kt;
+ cd.mult = new_mult;
+ cd.shift = new_shift;
+ cd.epoch_cyc = new_epoch;
+ cd.epoch_ns = ns;
+ raw_write_seqcount_end(&cd.seq);
r = rate;
if (r >= 4000000) {
@@ -141,22 +163,12 @@ void __init sched_clock_register(u64 (*read)(void), int bits,
} else
r_unit = ' ';
- /* calculate how many ns until we wrap */
- wrap = clocks_calc_max_nsecs(cd.mult, cd.shift, 0, sched_clock_mask);
- cd.wrap_kt = ns_to_ktime(wrap - (wrap >> 3));
-
/* calculate the ns resolution of this counter */
- res = cyc_to_ns(1ULL, cd.mult, cd.shift);
+ res = cyc_to_ns(1ULL, new_mult, new_shift);
+
pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lluns\n",
bits, r, r_unit, res, wrap);
- update_sched_clock();
-
- /*
- * Ensure that sched_clock() starts off at 0ns
- */
- cd.epoch_ns = 0;
-
/* Enable IRQ time accounting if we have a fast enough sched_clock */
if (irqtime > 0 || (irqtime == -1 && rate >= 1000000))
enable_sched_clock_irqtime();
diff --git a/kernel/time/tick-broadcast-hrtimer.c b/kernel/time/tick-broadcast-hrtimer.c
new file mode 100644
index 000000000000..eb682d5c697c
--- /dev/null
+++ b/kernel/time/tick-broadcast-hrtimer.c
@@ -0,0 +1,106 @@
+/*
+ * linux/kernel/time/tick-broadcast-hrtimer.c
+ * This file emulates a local clock event device
+ * via a pseudo clock device.
+ */
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/profile.h>
+#include <linux/clockchips.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/module.h>
+
+#include "tick-internal.h"
+
+static struct hrtimer bctimer;
+
+static void bc_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *bc)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ /*
+ * Note, we cannot cancel the timer here as we might
+ * run into the following live lock scenario:
+ *
+ * cpu 0 cpu1
+ * lock(broadcast_lock);
+ * hrtimer_interrupt()
+ * bc_handler()
+ * tick_handle_oneshot_broadcast();
+ * lock(broadcast_lock);
+ * hrtimer_cancel()
+ * wait_for_callback()
+ */
+ hrtimer_try_to_cancel(&bctimer);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * This is called from the guts of the broadcast code when the cpu
+ * which is about to enter idle has the earliest broadcast timer event.
+ */
+static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
+{
+ /*
+ * We try to cancel the timer first. If the callback is on
+ * flight on some other cpu then we let it handle it. If we
+ * were able to cancel the timer nothing can rearm it as we
+ * own broadcast_lock.
+ *
+ * However we can also be called from the event handler of
+ * ce_broadcast_hrtimer itself when it expires. We cannot
+ * restart the timer because we are in the callback, but we
+ * can set the expiry time and let the callback return
+ * HRTIMER_RESTART.
+ */
+ if (hrtimer_try_to_cancel(&bctimer) >= 0) {
+ hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED);
+ /* Bind the "device" to the cpu */
+ bc->bound_on = smp_processor_id();
+ } else if (bc->bound_on == smp_processor_id()) {
+ hrtimer_set_expires(&bctimer, expires);
+ }
+ return 0;
+}
+
+static struct clock_event_device ce_broadcast_hrtimer = {
+ .set_mode = bc_set_mode,
+ .set_next_ktime = bc_set_next,
+ .features = CLOCK_EVT_FEAT_ONESHOT |
+ CLOCK_EVT_FEAT_KTIME |
+ CLOCK_EVT_FEAT_HRTIMER,
+ .rating = 0,
+ .bound_on = -1,
+ .min_delta_ns = 1,
+ .max_delta_ns = KTIME_MAX,
+ .min_delta_ticks = 1,
+ .max_delta_ticks = ULONG_MAX,
+ .mult = 1,
+ .shift = 0,
+ .cpumask = cpu_all_mask,
+};
+
+static enum hrtimer_restart bc_handler(struct hrtimer *t)
+{
+ ce_broadcast_hrtimer.event_handler(&ce_broadcast_hrtimer);
+
+ if (ce_broadcast_hrtimer.next_event.tv64 == KTIME_MAX)
+ return HRTIMER_NORESTART;
+
+ return HRTIMER_RESTART;
+}
+
+void tick_setup_hrtimer_broadcast(void)
+{
+ hrtimer_init(&bctimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ bctimer.function = bc_handler;
+ clockevents_register_device(&ce_broadcast_hrtimer);
+}
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 98977a57ac72..64c5990fd500 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -120,6 +120,19 @@ int tick_is_broadcast_device(struct clock_event_device *dev)
return (dev && tick_broadcast_device.evtdev == dev);
}
+int tick_broadcast_update_freq(struct clock_event_device *dev, u32 freq)
+{
+ int ret = -ENODEV;
+
+ if (tick_is_broadcast_device(dev)) {
+ raw_spin_lock(&tick_broadcast_lock);
+ ret = __clockevents_update_freq(dev, freq);
+ raw_spin_unlock(&tick_broadcast_lock);
+ }
+ return ret;
+}
+
+
static void err_broadcast(const struct cpumask *mask)
{
pr_crit_once("Failed to broadcast timer tick. Some CPUs may be unresponsive.\n");
@@ -272,12 +285,8 @@ static void tick_do_broadcast(struct cpumask *mask)
*/
static void tick_do_periodic_broadcast(void)
{
- raw_spin_lock(&tick_broadcast_lock);
-
cpumask_and(tmpmask, cpu_online_mask, tick_broadcast_mask);
tick_do_broadcast(tmpmask);
-
- raw_spin_unlock(&tick_broadcast_lock);
}
/*
@@ -287,13 +296,15 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
{
ktime_t next;
+ raw_spin_lock(&tick_broadcast_lock);
+
tick_do_periodic_broadcast();
/*
* The device is in periodic mode. No reprogramming necessary:
*/
if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
- return;
+ goto unlock;
/*
* Setup the next period for devices, which do not have
@@ -306,9 +317,11 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
next = ktime_add(next, tick_period);
if (!clockevents_program_event(dev, next, false))
- return;
+ goto unlock;
tick_do_periodic_broadcast();
}
+unlock:
+ raw_spin_unlock(&tick_broadcast_lock);
}
/*
@@ -630,24 +643,61 @@ again:
raw_spin_unlock(&tick_broadcast_lock);
}
+static int broadcast_needs_cpu(struct clock_event_device *bc, int cpu)
+{
+ if (!(bc->features & CLOCK_EVT_FEAT_HRTIMER))
+ return 0;
+ if (bc->next_event.tv64 == KTIME_MAX)
+ return 0;
+ return bc->bound_on == cpu ? -EBUSY : 0;
+}
+
+static void broadcast_shutdown_local(struct clock_event_device *bc,
+ struct clock_event_device *dev)
+{
+ /*
+ * For hrtimer based broadcasting we cannot shutdown the cpu
+ * local device if our own event is the first one to expire or
+ * if we own the broadcast timer.
+ */
+ if (bc->features & CLOCK_EVT_FEAT_HRTIMER) {
+ if (broadcast_needs_cpu(bc, smp_processor_id()))
+ return;
+ if (dev->next_event.tv64 < bc->next_event.tv64)
+ return;
+ }
+ clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN);
+}
+
+static void broadcast_move_bc(int deadcpu)
+{
+ struct clock_event_device *bc = tick_broadcast_device.evtdev;
+
+ if (!bc || !broadcast_needs_cpu(bc, deadcpu))
+ return;
+ /* This moves the broadcast assignment to this cpu */
+ clockevents_program_event(bc, bc->next_event, 1);
+}
+
/*
* Powerstate information: The system enters/leaves a state, where
* affected devices might stop
+ * Returns 0 on success, -EBUSY if the cpu is used to broadcast wakeups.
*/
-void tick_broadcast_oneshot_control(unsigned long reason)
+int tick_broadcast_oneshot_control(unsigned long reason)
{
struct clock_event_device *bc, *dev;
struct tick_device *td;
unsigned long flags;
ktime_t now;
- int cpu;
+ int cpu, ret = 0;
/*
* Periodic mode does not care about the enter/exit of power
* states
*/
if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
- return;
+ return 0;
/*
* We are called with preemtion disabled from the depth of the
@@ -658,7 +708,7 @@ void tick_broadcast_oneshot_control(unsigned long reason)
dev = td->evtdev;
if (!(dev->features & CLOCK_EVT_FEAT_C3STOP))
- return;
+ return 0;
bc = tick_broadcast_device.evtdev;
@@ -666,7 +716,7 @@ void tick_broadcast_oneshot_control(unsigned long reason)
if (reason == CLOCK_EVT_NOTIFY_BROADCAST_ENTER) {
if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_oneshot_mask)) {
WARN_ON_ONCE(cpumask_test_cpu(cpu, tick_broadcast_pending_mask));
- clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN);
+ broadcast_shutdown_local(bc, dev);
/*
* We only reprogram the broadcast timer if we
* did not mark ourself in the force mask and
@@ -679,6 +729,16 @@ void tick_broadcast_oneshot_control(unsigned long reason)
dev->next_event.tv64 < bc->next_event.tv64)
tick_broadcast_set_event(bc, cpu, dev->next_event, 1);
}
+ /*
+ * If the current CPU owns the hrtimer broadcast
+ * mechanism, it cannot go deep idle and we remove the
+ * CPU from the broadcast mask. We don't have to go
+ * through the EXIT path as the local timer is not
+ * shutdown.
+ */
+ ret = broadcast_needs_cpu(bc, cpu);
+ if (ret)
+ cpumask_clear_cpu(cpu, tick_broadcast_oneshot_mask);
} else {
if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_oneshot_mask)) {
clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
@@ -746,6 +806,7 @@ void tick_broadcast_oneshot_control(unsigned long reason)
}
out:
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
+ return ret;
}
/*
@@ -852,6 +913,8 @@ void tick_shutdown_broadcast_oneshot(unsigned int *cpup)
cpumask_clear_cpu(cpu, tick_broadcast_pending_mask);
cpumask_clear_cpu(cpu, tick_broadcast_force_mask);
+ broadcast_move_bc(cpu);
+
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
}
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index 20b2fe37d105..015661279b68 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -98,18 +98,19 @@ static void tick_periodic(int cpu)
void tick_handle_periodic(struct clock_event_device *dev)
{
int cpu = smp_processor_id();
- ktime_t next;
+ ktime_t next = dev->next_event;
tick_periodic(cpu);
if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
return;
- /*
- * Setup the next period for devices, which do not have
- * periodic mode:
- */
- next = ktime_add(dev->next_event, tick_period);
for (;;) {
+ /*
+ * Setup the next period for devices, which do not have
+ * periodic mode:
+ */
+ next = ktime_add(next, tick_period);
+
if (!clockevents_program_event(dev, next, false))
return;
/*
@@ -118,12 +119,11 @@ void tick_handle_periodic(struct clock_event_device *dev)
* to be sure we're using a real hardware clocksource.
* Otherwise we could get trapped in an infinite
* loop, as the tick_periodic() increments jiffies,
- * when then will increment time, posibly causing
+ * which then will increment time, possibly causing
* the loop to trigger again and again.
*/
if (timekeeping_valid_for_hres())
tick_periodic(cpu);
- next = ktime_add(next, tick_period);
}
}
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index 8329669b51ec..7ab92b19965a 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -46,7 +46,7 @@ extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *));
extern void tick_resume_oneshot(void);
# ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
extern void tick_broadcast_setup_oneshot(struct clock_event_device *bc);
-extern void tick_broadcast_oneshot_control(unsigned long reason);
+extern int tick_broadcast_oneshot_control(unsigned long reason);
extern void tick_broadcast_switch_to_oneshot(void);
extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup);
extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc);
@@ -58,7 +58,7 @@ static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
{
BUG();
}
-static inline void tick_broadcast_oneshot_control(unsigned long reason) { }
+static inline int tick_broadcast_oneshot_control(unsigned long reason) { return 0; }
static inline void tick_broadcast_switch_to_oneshot(void) { }
static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { }
static inline int tick_broadcast_oneshot_active(void) { return 0; }
@@ -87,7 +87,7 @@ static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
{
BUG();
}
-static inline void tick_broadcast_oneshot_control(unsigned long reason) { }
+static inline int tick_broadcast_oneshot_control(unsigned long reason) { return 0; }
static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { }
static inline int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
{
@@ -111,6 +111,7 @@ extern int tick_resume_broadcast(void);
extern void tick_broadcast_init(void);
extern void
tick_set_periodic_handler(struct clock_event_device *dev, int broadcast);
+int tick_broadcast_update_freq(struct clock_event_device *dev, u32 freq);
#else /* !BROADCAST */
@@ -133,6 +134,8 @@ static inline void tick_shutdown_broadcast(unsigned int *cpup) { }
static inline void tick_suspend_broadcast(void) { }
static inline int tick_resume_broadcast(void) { return 0; }
static inline void tick_broadcast_init(void) { }
+static inline int tick_broadcast_update_freq(struct clock_event_device *dev,
+ u32 freq) { return -ENODEV; }
/*
* Set the periodic handler in non broadcast mode
@@ -152,6 +155,8 @@ static inline int tick_device_is_functional(struct clock_event_device *dev)
return !(dev->features & CLOCK_EVT_FEAT_DUMMY);
}
+int __clockevents_update_freq(struct clock_event_device *dev, u32 freq);
+
#endif
extern void do_timer(unsigned long ticks);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 0aa4ce81bc16..5b40279ecd71 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1435,7 +1435,8 @@ void update_wall_time(void)
out:
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
if (clock_set)
- clock_was_set();
+ /* Have to call _delayed version, since in irq context*/
+ clock_was_set_delayed();
}
/**
diff --git a/kernel/time/timekeeping_debug.c b/kernel/time/timekeeping_debug.c
index 802433a4f5eb..4d54f97558df 100644
--- a/kernel/time/timekeeping_debug.c
+++ b/kernel/time/timekeeping_debug.c
@@ -21,6 +21,8 @@
#include <linux/seq_file.h>
#include <linux/time.h>
+#include "timekeeping_internal.h"
+
static unsigned int sleep_time_bin[32] = {0};
static int tk_debug_show_sleep_time(struct seq_file *s, void *data)
diff --git a/kernel/timer.c b/kernel/timer.c
index accfd241b9e5..87bd529879c2 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -52,7 +52,7 @@
#define CREATE_TRACE_POINTS
#include <trace/events/timer.h>
-u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
+__visible u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
EXPORT_SYMBOL(jiffies_64);
@@ -81,6 +81,7 @@ struct tvec_base {
unsigned long timer_jiffies;
unsigned long next_timer;
unsigned long active_timers;
+ unsigned long all_timers;
struct tvec_root tv1;
struct tvec tv2;
struct tvec tv3;
@@ -337,6 +338,20 @@ void set_timer_slack(struct timer_list *timer, int slack_hz)
}
EXPORT_SYMBOL_GPL(set_timer_slack);
+/*
+ * If the list is empty, catch up ->timer_jiffies to the current time.
+ * The caller must hold the tvec_base lock. Returns true if the list
+ * was empty and therefore ->timer_jiffies was updated.
+ */
+static bool catchup_timer_jiffies(struct tvec_base *base)
+{
+ if (!base->all_timers) {
+ base->timer_jiffies = jiffies;
+ return true;
+ }
+ return false;
+}
+
static void
__internal_add_timer(struct tvec_base *base, struct timer_list *timer)
{
@@ -383,15 +398,17 @@ __internal_add_timer(struct tvec_base *base, struct timer_list *timer)
static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
{
+ (void)catchup_timer_jiffies(base);
__internal_add_timer(base, timer);
/*
* Update base->active_timers and base->next_timer
*/
if (!tbase_get_deferrable(timer->base)) {
- if (time_before(timer->expires, base->next_timer))
+ if (!base->active_timers++ ||
+ time_before(timer->expires, base->next_timer))
base->next_timer = timer->expires;
- base->active_timers++;
}
+ base->all_timers++;
}
#ifdef CONFIG_TIMER_STATS
@@ -671,6 +688,8 @@ detach_expired_timer(struct timer_list *timer, struct tvec_base *base)
detach_timer(timer, true);
if (!tbase_get_deferrable(timer->base))
base->active_timers--;
+ base->all_timers--;
+ (void)catchup_timer_jiffies(base);
}
static int detach_if_pending(struct timer_list *timer, struct tvec_base *base,
@@ -685,6 +704,8 @@ static int detach_if_pending(struct timer_list *timer, struct tvec_base *base,
if (timer->expires == base->next_timer)
base->next_timer = base->timer_jiffies;
}
+ base->all_timers--;
+ (void)catchup_timer_jiffies(base);
return 1;
}
@@ -739,12 +760,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires,
debug_activate(timer, expires);
- cpu = smp_processor_id();
-
-#if defined(CONFIG_NO_HZ_COMMON) && defined(CONFIG_SMP)
- if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu))
- cpu = get_nohz_timer_target();
-#endif
+ cpu = get_nohz_timer_target(pinned);
new_base = per_cpu(tvec_bases, cpu);
if (base != new_base) {
@@ -939,8 +955,15 @@ void add_timer_on(struct timer_list *timer, int cpu)
* with the timer by holding the timer base lock. This also
* makes sure that a CPU on the way to stop its tick can not
* evaluate the timer wheel.
+ *
+ * Spare the IPI for deferrable timers on idle targets though.
+ * The next busy ticks will take care of it. Except full dynticks
+ * require special care against races with idle_cpu(), lets deal
+ * with that later.
*/
- wake_up_nohz_cpu(cpu);
+ if (!tbase_get_deferrable(timer->base) || tick_nohz_full_cpu(cpu))
+ wake_up_nohz_cpu(cpu);
+
spin_unlock_irqrestore(&base->lock, flags);
}
EXPORT_SYMBOL_GPL(add_timer_on);
@@ -1146,6 +1169,10 @@ static inline void __run_timers(struct tvec_base *base)
struct timer_list *timer;
spin_lock_irq(&base->lock);
+ if (catchup_timer_jiffies(base)) {
+ spin_unlock_irq(&base->lock);
+ return;
+ }
while (time_after_eq(jiffies, base->timer_jiffies)) {
struct list_head work_list;
struct list_head *head = &work_list;
@@ -1160,7 +1187,7 @@ static inline void __run_timers(struct tvec_base *base)
!cascade(base, &base->tv4, INDEX(2)))
cascade(base, &base->tv5, INDEX(3));
++base->timer_jiffies;
- list_replace_init(base->tv1.vec + index, &work_list);
+ list_replace_init(base->tv1.vec + index, head);
while (!list_empty(head)) {
void (*fn)(unsigned long);
unsigned long data;
@@ -1523,9 +1550,8 @@ static int init_timers_cpu(int cpu)
if (!base)
return -ENOMEM;
- /* Make sure that tvec_base is 2 byte aligned */
- if (tbase_get_deferrable(base)) {
- WARN_ON(1);
+ /* Make sure tvec_base has TIMER_FLAG_MASK bits free */
+ if (WARN_ON(base != tbase_get_base(base))) {
kfree(base);
return -ENOMEM;
}
@@ -1559,6 +1585,7 @@ static int init_timers_cpu(int cpu)
base->timer_jiffies = jiffies;
base->next_timer = base->timer_jiffies;
base->active_timers = 0;
+ base->all_timers = 0;
return 0;
}
@@ -1648,9 +1675,9 @@ void __init init_timers(void)
err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
(void *)(long)smp_processor_id());
- init_timer_stats();
-
BUG_ON(err != NOTIFY_OK);
+
+ init_timer_stats();
register_cpu_notifier(&timers_nb);
open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
}
diff --git a/kernel/torture.c b/kernel/torture.c
new file mode 100644
index 000000000000..acc9afc2f26e
--- /dev/null
+++ b/kernel/torture.c
@@ -0,0 +1,719 @@
+/*
+ * Common functions for in-kernel torture tests.
+ *
+ * This program is free software; 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, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ *
+ * Copyright (C) IBM Corporation, 2014
+ *
+ * Author: Paul E. McKenney <paulmck@us.ibm.com>
+ * Based on kernel/rcu/torture.c.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/atomic.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/moduleparam.h>
+#include <linux/percpu.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/freezer.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/trace_clock.h>
+#include <asm/byteorder.h>
+#include <linux/torture.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com>");
+
+static char *torture_type;
+static bool verbose;
+
+/* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */
+#define FULLSTOP_DONTSTOP 0 /* Normal operation. */
+#define FULLSTOP_SHUTDOWN 1 /* System shutdown with torture running. */
+#define FULLSTOP_RMMOD 2 /* Normal rmmod of torture. */
+static int fullstop = FULLSTOP_RMMOD;
+static DEFINE_MUTEX(fullstop_mutex);
+static int *torture_runnable;
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+/*
+ * Variables for online-offline handling. Only present if CPU hotplug
+ * is enabled, otherwise does nothing.
+ */
+
+static struct task_struct *onoff_task;
+static long onoff_holdoff;
+static long onoff_interval;
+static long n_offline_attempts;
+static long n_offline_successes;
+static unsigned long sum_offline;
+static int min_offline = -1;
+static int max_offline;
+static long n_online_attempts;
+static long n_online_successes;
+static unsigned long sum_online;
+static int min_online = -1;
+static int max_online;
+
+/*
+ * Execute random CPU-hotplug operations at the interval specified
+ * by the onoff_interval.
+ */
+static int
+torture_onoff(void *arg)
+{
+ int cpu;
+ unsigned long delta;
+ int maxcpu = -1;
+ DEFINE_TORTURE_RANDOM(rand);
+ int ret;
+ unsigned long starttime;
+
+ VERBOSE_TOROUT_STRING("torture_onoff task started");
+ for_each_online_cpu(cpu)
+ maxcpu = cpu;
+ WARN_ON(maxcpu < 0);
+ if (onoff_holdoff > 0) {
+ VERBOSE_TOROUT_STRING("torture_onoff begin holdoff");
+ schedule_timeout_interruptible(onoff_holdoff);
+ VERBOSE_TOROUT_STRING("torture_onoff end holdoff");
+ }
+ while (!torture_must_stop()) {
+ cpu = (torture_random(&rand) >> 4) % (maxcpu + 1);
+ if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) {
+ if (verbose)
+ pr_alert("%s" TORTURE_FLAG
+ "torture_onoff task: offlining %d\n",
+ torture_type, cpu);
+ starttime = jiffies;
+ n_offline_attempts++;
+ ret = cpu_down(cpu);
+ if (ret) {
+ if (verbose)
+ pr_alert("%s" TORTURE_FLAG
+ "torture_onoff task: offline %d failed: errno %d\n",
+ torture_type, cpu, ret);
+ } else {
+ if (verbose)
+ pr_alert("%s" TORTURE_FLAG
+ "torture_onoff task: offlined %d\n",
+ torture_type, cpu);
+ n_offline_successes++;
+ delta = jiffies - starttime;
+ sum_offline += delta;
+ if (min_offline < 0) {
+ min_offline = delta;
+ max_offline = delta;
+ }
+ if (min_offline > delta)
+ min_offline = delta;
+ if (max_offline < delta)
+ max_offline = delta;
+ }
+ } else if (cpu_is_hotpluggable(cpu)) {
+ if (verbose)
+ pr_alert("%s" TORTURE_FLAG
+ "torture_onoff task: onlining %d\n",
+ torture_type, cpu);
+ starttime = jiffies;
+ n_online_attempts++;
+ ret = cpu_up(cpu);
+ if (ret) {
+ if (verbose)
+ pr_alert("%s" TORTURE_FLAG
+ "torture_onoff task: online %d failed: errno %d\n",
+ torture_type, cpu, ret);
+ } else {
+ if (verbose)
+ pr_alert("%s" TORTURE_FLAG
+ "torture_onoff task: onlined %d\n",
+ torture_type, cpu);
+ n_online_successes++;
+ delta = jiffies - starttime;
+ sum_online += delta;
+ if (min_online < 0) {
+ min_online = delta;
+ max_online = delta;
+ }
+ if (min_online > delta)
+ min_online = delta;
+ if (max_online < delta)
+ max_online = delta;
+ }
+ }
+ schedule_timeout_interruptible(onoff_interval);
+ }
+ torture_kthread_stopping("torture_onoff");
+ return 0;
+}
+
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+
+/*
+ * Initiate online-offline handling.
+ */
+int torture_onoff_init(long ooholdoff, long oointerval)
+{
+ int ret = 0;
+
+#ifdef CONFIG_HOTPLUG_CPU
+ onoff_holdoff = ooholdoff;
+ onoff_interval = oointerval;
+ if (onoff_interval <= 0)
+ return 0;
+ ret = torture_create_kthread(torture_onoff, NULL, onoff_task);
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+ return ret;
+}
+EXPORT_SYMBOL_GPL(torture_onoff_init);
+
+/*
+ * Clean up after online/offline testing.
+ */
+static void torture_onoff_cleanup(void)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+ if (onoff_task == NULL)
+ return;
+ VERBOSE_TOROUT_STRING("Stopping torture_onoff task");
+ kthread_stop(onoff_task);
+ onoff_task = NULL;
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+}
+EXPORT_SYMBOL_GPL(torture_onoff_cleanup);
+
+/*
+ * Print online/offline testing statistics.
+ */
+char *torture_onoff_stats(char *page)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+ page += sprintf(page,
+ "onoff: %ld/%ld:%ld/%ld %d,%d:%d,%d %lu:%lu (HZ=%d) ",
+ n_online_successes, n_online_attempts,
+ n_offline_successes, n_offline_attempts,
+ min_online, max_online,
+ min_offline, max_offline,
+ sum_online, sum_offline, HZ);
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+ return page;
+}
+EXPORT_SYMBOL_GPL(torture_onoff_stats);
+
+/*
+ * Were all the online/offline operations successful?
+ */
+bool torture_onoff_failures(void)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+ return n_online_successes != n_online_attempts ||
+ n_offline_successes != n_offline_attempts;
+#else /* #ifdef CONFIG_HOTPLUG_CPU */
+ return false;
+#endif /* #else #ifdef CONFIG_HOTPLUG_CPU */
+}
+EXPORT_SYMBOL_GPL(torture_onoff_failures);
+
+#define TORTURE_RANDOM_MULT 39916801 /* prime */
+#define TORTURE_RANDOM_ADD 479001701 /* prime */
+#define TORTURE_RANDOM_REFRESH 10000
+
+/*
+ * Crude but fast random-number generator. Uses a linear congruential
+ * generator, with occasional help from cpu_clock().
+ */
+unsigned long
+torture_random(struct torture_random_state *trsp)
+{
+ if (--trsp->trs_count < 0) {
+ trsp->trs_state += (unsigned long)local_clock();
+ trsp->trs_count = TORTURE_RANDOM_REFRESH;
+ }
+ trsp->trs_state = trsp->trs_state * TORTURE_RANDOM_MULT +
+ TORTURE_RANDOM_ADD;
+ return swahw32(trsp->trs_state);
+}
+EXPORT_SYMBOL_GPL(torture_random);
+
+/*
+ * Variables for shuffling. The idea is to ensure that each CPU stays
+ * idle for an extended period to test interactions with dyntick idle,
+ * as well as interactions with any per-CPU varibles.
+ */
+struct shuffle_task {
+ struct list_head st_l;
+ struct task_struct *st_t;
+};
+
+static long shuffle_interval; /* In jiffies. */
+static struct task_struct *shuffler_task;
+static cpumask_var_t shuffle_tmp_mask;
+static int shuffle_idle_cpu; /* Force all torture tasks off this CPU */
+static struct list_head shuffle_task_list = LIST_HEAD_INIT(shuffle_task_list);
+static DEFINE_MUTEX(shuffle_task_mutex);
+
+/*
+ * Register a task to be shuffled. If there is no memory, just splat
+ * and don't bother registering.
+ */
+void torture_shuffle_task_register(struct task_struct *tp)
+{
+ struct shuffle_task *stp;
+
+ if (WARN_ON_ONCE(tp == NULL))
+ return;
+ stp = kmalloc(sizeof(*stp), GFP_KERNEL);
+ if (WARN_ON_ONCE(stp == NULL))
+ return;
+ stp->st_t = tp;
+ mutex_lock(&shuffle_task_mutex);
+ list_add(&stp->st_l, &shuffle_task_list);
+ mutex_unlock(&shuffle_task_mutex);
+}
+EXPORT_SYMBOL_GPL(torture_shuffle_task_register);
+
+/*
+ * Unregister all tasks, for example, at the end of the torture run.
+ */
+static void torture_shuffle_task_unregister_all(void)
+{
+ struct shuffle_task *stp;
+ struct shuffle_task *p;
+
+ mutex_lock(&shuffle_task_mutex);
+ list_for_each_entry_safe(stp, p, &shuffle_task_list, st_l) {
+ list_del(&stp->st_l);
+ kfree(stp);
+ }
+ mutex_unlock(&shuffle_task_mutex);
+}
+
+/* Shuffle tasks such that we allow shuffle_idle_cpu to become idle.
+ * A special case is when shuffle_idle_cpu = -1, in which case we allow
+ * the tasks to run on all CPUs.
+ */
+static void torture_shuffle_tasks(void)
+{
+ struct shuffle_task *stp;
+
+ cpumask_setall(shuffle_tmp_mask);
+ get_online_cpus();
+
+ /* No point in shuffling if there is only one online CPU (ex: UP) */
+ if (num_online_cpus() == 1) {
+ put_online_cpus();
+ return;
+ }
+
+ /* Advance to the next CPU. Upon overflow, don't idle any CPUs. */
+ shuffle_idle_cpu = cpumask_next(shuffle_idle_cpu, shuffle_tmp_mask);
+ if (shuffle_idle_cpu >= nr_cpu_ids)
+ shuffle_idle_cpu = -1;
+ if (shuffle_idle_cpu != -1) {
+ cpumask_clear_cpu(shuffle_idle_cpu, shuffle_tmp_mask);
+ if (cpumask_empty(shuffle_tmp_mask)) {
+ put_online_cpus();
+ return;
+ }
+ }
+
+ mutex_lock(&shuffle_task_mutex);
+ list_for_each_entry(stp, &shuffle_task_list, st_l)
+ set_cpus_allowed_ptr(stp->st_t, shuffle_tmp_mask);
+ mutex_unlock(&shuffle_task_mutex);
+
+ put_online_cpus();
+}
+
+/* Shuffle tasks across CPUs, with the intent of allowing each CPU in the
+ * system to become idle at a time and cut off its timer ticks. This is meant
+ * to test the support for such tickless idle CPU in RCU.
+ */
+static int torture_shuffle(void *arg)
+{
+ VERBOSE_TOROUT_STRING("torture_shuffle task started");
+ do {
+ schedule_timeout_interruptible(shuffle_interval);
+ torture_shuffle_tasks();
+ torture_shutdown_absorb("torture_shuffle");
+ } while (!torture_must_stop());
+ torture_kthread_stopping("torture_shuffle");
+ return 0;
+}
+
+/*
+ * Start the shuffler, with shuffint in jiffies.
+ */
+int torture_shuffle_init(long shuffint)
+{
+ shuffle_interval = shuffint;
+
+ shuffle_idle_cpu = -1;
+
+ if (!alloc_cpumask_var(&shuffle_tmp_mask, GFP_KERNEL)) {
+ VERBOSE_TOROUT_ERRSTRING("Failed to alloc mask");
+ return -ENOMEM;
+ }
+
+ /* Create the shuffler thread */
+ return torture_create_kthread(torture_shuffle, NULL, shuffler_task);
+}
+EXPORT_SYMBOL_GPL(torture_shuffle_init);
+
+/*
+ * Stop the shuffling.
+ */
+static void torture_shuffle_cleanup(void)
+{
+ torture_shuffle_task_unregister_all();
+ if (shuffler_task) {
+ VERBOSE_TOROUT_STRING("Stopping torture_shuffle task");
+ kthread_stop(shuffler_task);
+ free_cpumask_var(shuffle_tmp_mask);
+ }
+ shuffler_task = NULL;
+}
+EXPORT_SYMBOL_GPL(torture_shuffle_cleanup);
+
+/*
+ * Variables for auto-shutdown. This allows "lights out" torture runs
+ * to be fully scripted.
+ */
+static int shutdown_secs; /* desired test duration in seconds. */
+static struct task_struct *shutdown_task;
+static unsigned long shutdown_time; /* jiffies to system shutdown. */
+static void (*torture_shutdown_hook)(void);
+
+/*
+ * Absorb kthreads into a kernel function that won't return, so that
+ * they won't ever access module text or data again.
+ */
+void torture_shutdown_absorb(const char *title)
+{
+ while (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) {
+ pr_notice("torture thread %s parking due to system shutdown\n",
+ title);
+ schedule_timeout_uninterruptible(MAX_SCHEDULE_TIMEOUT);
+ }
+}
+EXPORT_SYMBOL_GPL(torture_shutdown_absorb);
+
+/*
+ * Cause the torture test to shutdown the system after the test has
+ * run for the time specified by the shutdown_secs parameter.
+ */
+static int torture_shutdown(void *arg)
+{
+ long delta;
+ unsigned long jiffies_snap;
+
+ VERBOSE_TOROUT_STRING("torture_shutdown task started");
+ jiffies_snap = jiffies;
+ while (ULONG_CMP_LT(jiffies_snap, shutdown_time) &&
+ !torture_must_stop()) {
+ delta = shutdown_time - jiffies_snap;
+ if (verbose)
+ pr_alert("%s" TORTURE_FLAG
+ "torture_shutdown task: %lu jiffies remaining\n",
+ torture_type, delta);
+ schedule_timeout_interruptible(delta);
+ jiffies_snap = jiffies;
+ }
+ if (torture_must_stop()) {
+ torture_kthread_stopping("torture_shutdown");
+ return 0;
+ }
+
+ /* OK, shut down the system. */
+
+ VERBOSE_TOROUT_STRING("torture_shutdown task shutting down system");
+ shutdown_task = NULL; /* Avoid self-kill deadlock. */
+ if (torture_shutdown_hook)
+ torture_shutdown_hook();
+ else
+ VERBOSE_TOROUT_STRING("No torture_shutdown_hook(), skipping.");
+ kernel_power_off(); /* Shut down the system. */
+ return 0;
+}
+
+/*
+ * Start up the shutdown task.
+ */
+int torture_shutdown_init(int ssecs, void (*cleanup)(void))
+{
+ int ret = 0;
+
+ shutdown_secs = ssecs;
+ torture_shutdown_hook = cleanup;
+ if (shutdown_secs > 0) {
+ shutdown_time = jiffies + shutdown_secs * HZ;
+ ret = torture_create_kthread(torture_shutdown, NULL,
+ shutdown_task);
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(torture_shutdown_init);
+
+/*
+ * Detect and respond to a system shutdown.
+ */
+static int torture_shutdown_notify(struct notifier_block *unused1,
+ unsigned long unused2, void *unused3)
+{
+ mutex_lock(&fullstop_mutex);
+ if (ACCESS_ONCE(fullstop) == FULLSTOP_DONTSTOP) {
+ VERBOSE_TOROUT_STRING("Unscheduled system shutdown detected");
+ ACCESS_ONCE(fullstop) = FULLSTOP_SHUTDOWN;
+ } else {
+ pr_warn("Concurrent rmmod and shutdown illegal!\n");
+ }
+ mutex_unlock(&fullstop_mutex);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block torture_shutdown_nb = {
+ .notifier_call = torture_shutdown_notify,
+};
+
+/*
+ * Shut down the shutdown task. Say what??? Heh! This can happen if
+ * the torture module gets an rmmod before the shutdown time arrives. ;-)
+ */
+static void torture_shutdown_cleanup(void)
+{
+ unregister_reboot_notifier(&torture_shutdown_nb);
+ if (shutdown_task != NULL) {
+ VERBOSE_TOROUT_STRING("Stopping torture_shutdown task");
+ kthread_stop(shutdown_task);
+ }
+ shutdown_task = NULL;
+}
+
+/*
+ * Variables for stuttering, which means to periodically pause and
+ * restart testing in order to catch bugs that appear when load is
+ * suddenly applied to or removed from the system.
+ */
+static struct task_struct *stutter_task;
+static int stutter_pause_test;
+static int stutter;
+
+/*
+ * Block until the stutter interval ends. This must be called periodically
+ * by all running kthreads that need to be subject to stuttering.
+ */
+void stutter_wait(const char *title)
+{
+ while (ACCESS_ONCE(stutter_pause_test) ||
+ (torture_runnable && !ACCESS_ONCE(*torture_runnable))) {
+ if (stutter_pause_test)
+ schedule_timeout_interruptible(1);
+ else
+ schedule_timeout_interruptible(round_jiffies_relative(HZ));
+ torture_shutdown_absorb(title);
+ }
+}
+EXPORT_SYMBOL_GPL(stutter_wait);
+
+/*
+ * Cause the torture test to "stutter", starting and stopping all
+ * threads periodically.
+ */
+static int torture_stutter(void *arg)
+{
+ VERBOSE_TOROUT_STRING("torture_stutter task started");
+ do {
+ if (!torture_must_stop()) {
+ schedule_timeout_interruptible(stutter);
+ ACCESS_ONCE(stutter_pause_test) = 1;
+ }
+ if (!torture_must_stop())
+ schedule_timeout_interruptible(stutter);
+ ACCESS_ONCE(stutter_pause_test) = 0;
+ torture_shutdown_absorb("torture_stutter");
+ } while (!torture_must_stop());
+ torture_kthread_stopping("torture_stutter");
+ return 0;
+}
+
+/*
+ * Initialize and kick off the torture_stutter kthread.
+ */
+int torture_stutter_init(int s)
+{
+ int ret;
+
+ stutter = s;
+ ret = torture_create_kthread(torture_stutter, NULL, stutter_task);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(torture_stutter_init);
+
+/*
+ * Cleanup after the torture_stutter kthread.
+ */
+static void torture_stutter_cleanup(void)
+{
+ if (!stutter_task)
+ return;
+ VERBOSE_TOROUT_STRING("Stopping torture_stutter task");
+ kthread_stop(stutter_task);
+ stutter_task = NULL;
+}
+
+/*
+ * Initialize torture module. Please note that this is -not- invoked via
+ * the usual module_init() mechanism, but rather by an explicit call from
+ * the client torture module. This call must be paired with a later
+ * torture_init_end().
+ *
+ * The runnable parameter points to a flag that controls whether or not
+ * the test is currently runnable. If there is no such flag, pass in NULL.
+ */
+void __init torture_init_begin(char *ttype, bool v, int *runnable)
+{
+ mutex_lock(&fullstop_mutex);
+ torture_type = ttype;
+ verbose = v;
+ torture_runnable = runnable;
+ fullstop = FULLSTOP_DONTSTOP;
+
+}
+EXPORT_SYMBOL_GPL(torture_init_begin);
+
+/*
+ * Tell the torture module that initialization is complete.
+ */
+void __init torture_init_end(void)
+{
+ mutex_unlock(&fullstop_mutex);
+ register_reboot_notifier(&torture_shutdown_nb);
+}
+EXPORT_SYMBOL_GPL(torture_init_end);
+
+/*
+ * Clean up torture module. Please note that this is -not- invoked via
+ * the usual module_exit() mechanism, but rather by an explicit call from
+ * the client torture module. Returns true if a race with system shutdown
+ * is detected, otherwise, all kthreads started by functions in this file
+ * will be shut down.
+ *
+ * This must be called before the caller starts shutting down its own
+ * kthreads.
+ */
+bool torture_cleanup(void)
+{
+ mutex_lock(&fullstop_mutex);
+ if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) {
+ pr_warn("Concurrent rmmod and shutdown illegal!\n");
+ mutex_unlock(&fullstop_mutex);
+ schedule_timeout_uninterruptible(10);
+ return true;
+ }
+ ACCESS_ONCE(fullstop) = FULLSTOP_RMMOD;
+ mutex_unlock(&fullstop_mutex);
+ torture_shutdown_cleanup();
+ torture_shuffle_cleanup();
+ torture_stutter_cleanup();
+ torture_onoff_cleanup();
+ return false;
+}
+EXPORT_SYMBOL_GPL(torture_cleanup);
+
+/*
+ * Is it time for the current torture test to stop?
+ */
+bool torture_must_stop(void)
+{
+ return torture_must_stop_irq() || kthread_should_stop();
+}
+EXPORT_SYMBOL_GPL(torture_must_stop);
+
+/*
+ * Is it time for the current torture test to stop? This is the irq-safe
+ * version, hence no check for kthread_should_stop().
+ */
+bool torture_must_stop_irq(void)
+{
+ return ACCESS_ONCE(fullstop) != FULLSTOP_DONTSTOP;
+}
+EXPORT_SYMBOL_GPL(torture_must_stop_irq);
+
+/*
+ * Each kthread must wait for kthread_should_stop() before returning from
+ * its top-level function, otherwise segfaults ensue. This function
+ * prints a "stopping" message and waits for kthread_should_stop(), and
+ * should be called from all torture kthreads immediately prior to
+ * returning.
+ */
+void torture_kthread_stopping(char *title)
+{
+ if (verbose)
+ VERBOSE_TOROUT_STRING(title);
+ while (!kthread_should_stop()) {
+ torture_shutdown_absorb(title);
+ schedule_timeout_uninterruptible(1);
+ }
+}
+EXPORT_SYMBOL_GPL(torture_kthread_stopping);
+
+/*
+ * Create a generic torture kthread that is immediately runnable. If you
+ * need the kthread to be stopped so that you can do something to it before
+ * it starts, you will need to open-code your own.
+ */
+int _torture_create_kthread(int (*fn)(void *arg), void *arg, char *s, char *m,
+ char *f, struct task_struct **tp)
+{
+ int ret = 0;
+
+ VERBOSE_TOROUT_STRING(m);
+ *tp = kthread_run(fn, arg, s);
+ if (IS_ERR(*tp)) {
+ ret = PTR_ERR(*tp);
+ VERBOSE_TOROUT_ERRSTRING(f);
+ *tp = NULL;
+ }
+ torture_shuffle_task_register(*tp);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(_torture_create_kthread);
+
+/*
+ * Stop a generic kthread, emitting a message.
+ */
+void _torture_stop_kthread(char *m, struct task_struct **tp)
+{
+ if (*tp == NULL)
+ return;
+ VERBOSE_TOROUT_STRING(m);
+ kthread_stop(*tp);
+ *tp = NULL;
+}
+EXPORT_SYMBOL_GPL(_torture_stop_kthread);
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index b418cb0d7242..4f3a3c03eadb 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -702,6 +702,7 @@ void blk_trace_shutdown(struct request_queue *q)
* blk_add_trace_rq - Add a trace for a request oriented action
* @q: queue the io is for
* @rq: the source request
+ * @nr_bytes: number of completed bytes
* @what: the action
*
* Description:
@@ -709,7 +710,7 @@ void blk_trace_shutdown(struct request_queue *q)
*
**/
static void blk_add_trace_rq(struct request_queue *q, struct request *rq,
- u32 what)
+ unsigned int nr_bytes, u32 what)
{
struct blk_trace *bt = q->blk_trace;
@@ -718,11 +719,11 @@ static void blk_add_trace_rq(struct request_queue *q, struct request *rq,
if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
what |= BLK_TC_ACT(BLK_TC_PC);
- __blk_add_trace(bt, 0, blk_rq_bytes(rq), rq->cmd_flags,
+ __blk_add_trace(bt, 0, nr_bytes, rq->cmd_flags,
what, rq->errors, rq->cmd_len, rq->cmd);
} else {
what |= BLK_TC_ACT(BLK_TC_FS);
- __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq),
+ __blk_add_trace(bt, blk_rq_pos(rq), nr_bytes,
rq->cmd_flags, what, rq->errors, 0, NULL);
}
}
@@ -730,33 +731,34 @@ static void blk_add_trace_rq(struct request_queue *q, struct request *rq,
static void blk_add_trace_rq_abort(void *ignore,
struct request_queue *q, struct request *rq)
{
- blk_add_trace_rq(q, rq, BLK_TA_ABORT);
+ blk_add_trace_rq(q, rq, blk_rq_bytes(rq), BLK_TA_ABORT);
}
static void blk_add_trace_rq_insert(void *ignore,
struct request_queue *q, struct request *rq)
{
- blk_add_trace_rq(q, rq, BLK_TA_INSERT);
+ blk_add_trace_rq(q, rq, blk_rq_bytes(rq), BLK_TA_INSERT);
}
static void blk_add_trace_rq_issue(void *ignore,
struct request_queue *q, struct request *rq)
{
- blk_add_trace_rq(q, rq, BLK_TA_ISSUE);
+ blk_add_trace_rq(q, rq, blk_rq_bytes(rq), BLK_TA_ISSUE);
}
static void blk_add_trace_rq_requeue(void *ignore,
struct request_queue *q,
struct request *rq)
{
- blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
+ blk_add_trace_rq(q, rq, blk_rq_bytes(rq), BLK_TA_REQUEUE);
}
static void blk_add_trace_rq_complete(void *ignore,
struct request_queue *q,
- struct request *rq)
+ struct request *rq,
+ unsigned int nr_bytes)
{
- blk_add_trace_rq(q, rq, BLK_TA_COMPLETE);
+ blk_add_trace_rq(q, rq, nr_bytes, BLK_TA_COMPLETE);
}
/**
diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c
index a5457d577b98..0434ff1b808e 100644
--- a/kernel/trace/ring_buffer_benchmark.c
+++ b/kernel/trace/ring_buffer_benchmark.c
@@ -40,8 +40,8 @@ static int write_iteration = 50;
module_param(write_iteration, uint, 0644);
MODULE_PARM_DESC(write_iteration, "# of writes between timestamp readings");
-static int producer_nice = 19;
-static int consumer_nice = 19;
+static int producer_nice = MAX_NICE;
+static int consumer_nice = MAX_NICE;
static int producer_fifo = -1;
static int consumer_fifo = -1;
@@ -308,7 +308,7 @@ static void ring_buffer_producer(void)
/* Let the user know that the test is running at low priority */
if (producer_fifo < 0 && consumer_fifo < 0 &&
- producer_nice == 19 && consumer_nice == 19)
+ producer_nice == MAX_NICE && consumer_nice == MAX_NICE)
trace_printk("WARNING!!! This test is running at lowest priority.\n");
trace_printk("Time: %lld (usecs)\n", time);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 815c878f409b..24c1f2382557 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1600,15 +1600,31 @@ void trace_buffer_unlock_commit(struct ring_buffer *buffer,
}
EXPORT_SYMBOL_GPL(trace_buffer_unlock_commit);
+static struct ring_buffer *temp_buffer;
+
struct ring_buffer_event *
trace_event_buffer_lock_reserve(struct ring_buffer **current_rb,
struct ftrace_event_file *ftrace_file,
int type, unsigned long len,
unsigned long flags, int pc)
{
+ struct ring_buffer_event *entry;
+
*current_rb = ftrace_file->tr->trace_buffer.buffer;
- return trace_buffer_lock_reserve(*current_rb,
+ entry = trace_buffer_lock_reserve(*current_rb,
type, len, flags, pc);
+ /*
+ * If tracing is off, but we have triggers enabled
+ * we still need to look at the event data. Use the temp_buffer
+ * to store the trace event for the tigger to use. It's recusive
+ * safe and will not be recorded anywhere.
+ */
+ if (!entry && ftrace_file->flags & FTRACE_EVENT_FL_TRIGGER_COND) {
+ *current_rb = temp_buffer;
+ entry = trace_buffer_lock_reserve(*current_rb,
+ type, len, flags, pc);
+ }
+ return entry;
}
EXPORT_SYMBOL_GPL(trace_event_buffer_lock_reserve);
@@ -6494,11 +6510,16 @@ __init static int tracer_alloc_buffers(void)
raw_spin_lock_init(&global_trace.start_lock);
+ /* Used for event triggers */
+ temp_buffer = ring_buffer_alloc(PAGE_SIZE, RB_FL_OVERWRITE);
+ if (!temp_buffer)
+ goto out_free_cpumask;
+
/* TODO: make the number of buffers hot pluggable with CPUS */
if (allocate_trace_buffers(&global_trace, ring_buf_size) < 0) {
printk(KERN_ERR "tracer: failed to allocate ring buffer!\n");
WARN_ON(1);
- goto out_free_cpumask;
+ goto out_free_temp_buffer;
}
if (global_trace.buffer_disabled)
@@ -6540,6 +6561,8 @@ __init static int tracer_alloc_buffers(void)
return 0;
+out_free_temp_buffer:
+ ring_buffer_free(temp_buffer);
out_free_cpumask:
free_percpu(global_trace.trace_buffer.data);
#ifdef CONFIG_TRACER_MAX_TRACE
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index e854f420e033..c894614de14d 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -31,9 +31,25 @@ static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
}
/* The ftrace function trace is allowed only for root. */
- if (ftrace_event_is_function(tp_event) &&
- perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
- return -EPERM;
+ if (ftrace_event_is_function(tp_event)) {
+ if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ /*
+ * We don't allow user space callchains for function trace
+ * event, due to issues with page faults while tracing page
+ * fault handler and its overall trickiness nature.
+ */
+ if (!p_event->attr.exclude_callchain_user)
+ return -EINVAL;
+
+ /*
+ * Same reason to disable user stack dump as for user space
+ * callchains above.
+ */
+ if (p_event->attr.sample_type & PERF_SAMPLE_STACK_USER)
+ return -EINVAL;
+ }
/* No tracing, just counting, so no obvious leak */
if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW))
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index e71ffd4eccb5..7b16d40bd64d 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -27,12 +27,6 @@
DEFINE_MUTEX(event_mutex);
-DEFINE_MUTEX(event_storage_mutex);
-EXPORT_SYMBOL_GPL(event_storage_mutex);
-
-char event_storage[EVENT_STORAGE_SIZE];
-EXPORT_SYMBOL_GPL(event_storage);
-
LIST_HEAD(ftrace_events);
static LIST_HEAD(ftrace_common_fields);
@@ -1777,6 +1771,16 @@ static void trace_module_add_events(struct module *mod)
{
struct ftrace_event_call **call, **start, **end;
+ if (!mod->num_trace_events)
+ return;
+
+ /* Don't add infrastructure for mods without tracepoints */
+ if (trace_module_has_bad_taint(mod)) {
+ pr_err("%s: module has bad taint, not creating trace events\n",
+ mod->name);
+ return;
+ }
+
start = mod->trace_events;
end = mod->trace_events + mod->num_trace_events;
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
index 7c3e3e72e2b6..ee0a5098ac43 100644
--- a/kernel/trace/trace_export.c
+++ b/kernel/trace/trace_export.c
@@ -95,15 +95,12 @@ static void __always_unused ____ftrace_check_##name(void) \
#undef __array
#define __array(type, item, len) \
do { \
+ char *type_str = #type"["__stringify(len)"]"; \
BUILD_BUG_ON(len > MAX_FILTER_STR_VAL); \
- mutex_lock(&event_storage_mutex); \
- snprintf(event_storage, sizeof(event_storage), \
- "%s[%d]", #type, len); \
- ret = trace_define_field(event_call, event_storage, #item, \
+ ret = trace_define_field(event_call, type_str, #item, \
offsetof(typeof(field), item), \
sizeof(field.item), \
is_signed_type(type), filter_type); \
- mutex_unlock(&event_storage_mutex); \
if (ret) \
return ret; \
} while (0);
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 2aefbee93a6d..887ef88b0bc7 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -498,14 +498,14 @@ void trace_hardirqs_off(void)
}
EXPORT_SYMBOL(trace_hardirqs_off);
-void trace_hardirqs_on_caller(unsigned long caller_addr)
+__visible void trace_hardirqs_on_caller(unsigned long caller_addr)
{
if (!preempt_trace() && irq_trace())
stop_critical_timing(CALLER_ADDR0, caller_addr);
}
EXPORT_SYMBOL(trace_hardirqs_on_caller);
-void trace_hardirqs_off_caller(unsigned long caller_addr)
+__visible void trace_hardirqs_off_caller(unsigned long caller_addr)
{
if (!preempt_trace() && irq_trace())
start_critical_timing(CALLER_ADDR0, caller_addr);
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
index 29f26540e9c9..031cc5655a51 100644
--- a/kernel/tracepoint.c
+++ b/kernel/tracepoint.c
@@ -631,6 +631,11 @@ void tracepoint_iter_reset(struct tracepoint_iter *iter)
EXPORT_SYMBOL_GPL(tracepoint_iter_reset);
#ifdef CONFIG_MODULES
+bool trace_module_has_bad_taint(struct module *mod)
+{
+ return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP));
+}
+
static int tracepoint_module_coming(struct module *mod)
{
struct tp_module *tp_mod, *iter;
@@ -641,7 +646,7 @@ static int tracepoint_module_coming(struct module *mod)
* module headers (for forced load), to make sure we don't cause a crash.
* Staging and out-of-tree GPL modules are fine.
*/
- if (mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP)))
+ if (trace_module_has_bad_taint(mod))
return 0;
mutex_lock(&tracepoints_mutex);
tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL);
diff --git a/kernel/up.c b/kernel/up.c
index 509403e3fbc6..1760bf3d1463 100644
--- a/kernel/up.c
+++ b/kernel/up.c
@@ -22,16 +22,16 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
}
EXPORT_SYMBOL(smp_call_function_single);
-void __smp_call_function_single(int cpu, struct call_single_data *csd,
- int wait)
+int smp_call_function_single_async(int cpu, struct call_single_data *csd)
{
unsigned long flags;
local_irq_save(flags);
csd->func(csd->info);
local_irq_restore(flags);
+ return 0;
}
-EXPORT_SYMBOL(__smp_call_function_single);
+EXPORT_SYMBOL(smp_call_function_single_async);
int on_each_cpu(smp_call_func_t func, void *info, int wait)
{
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 4431610f049a..01c6f979486f 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -505,7 +505,6 @@ static void restart_watchdog_hrtimer(void *info)
static void update_timers(int cpu)
{
- struct call_single_data data = {.func = restart_watchdog_hrtimer};
/*
* Make sure that perf event counter will adopt to a new
* sampling period. Updating the sampling period directly would
@@ -515,7 +514,7 @@ static void update_timers(int cpu)
* might be late already so we have to restart the timer as well.
*/
watchdog_nmi_disable(cpu);
- __smp_call_function_single(cpu, &data, 1);
+ smp_call_function_single(cpu, restart_watchdog_hrtimer, NULL, 1);
watchdog_nmi_enable(cpu);
}
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 82ef9f3b7473..0ee63af30bd1 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -516,6 +516,13 @@ void destroy_work_on_stack(struct work_struct *work)
}
EXPORT_SYMBOL_GPL(destroy_work_on_stack);
+void destroy_delayed_work_on_stack(struct delayed_work *work)
+{
+ destroy_timer_on_stack(&work->timer);
+ debug_object_free(&work->work, &work_debug_descr);
+}
+EXPORT_SYMBOL_GPL(destroy_delayed_work_on_stack);
+
#else
static inline void debug_work_activate(struct work_struct *work) { }
static inline void debug_work_deactivate(struct work_struct *work) { }
@@ -1851,6 +1858,12 @@ static void destroy_worker(struct worker *worker)
if (worker->flags & WORKER_IDLE)
pool->nr_idle--;
+ /*
+ * Once WORKER_DIE is set, the kworker may destroy itself at any
+ * point. Pin to ensure the task stays until we're done with it.
+ */
+ get_task_struct(worker->task);
+
list_del_init(&worker->entry);
worker->flags |= WORKER_DIE;
@@ -1859,6 +1872,7 @@ static void destroy_worker(struct worker *worker)
spin_unlock_irq(&pool->lock);
kthread_stop(worker->task);
+ put_task_struct(worker->task);
kfree(worker);
spin_lock_irq(&pool->lock);
@@ -3218,7 +3232,7 @@ static ssize_t wq_nice_store(struct device *dev, struct device_attribute *attr,
return -ENOMEM;
if (sscanf(buf, "%d", &attrs->nice) == 1 &&
- attrs->nice >= -20 && attrs->nice <= 19)
+ attrs->nice >= MIN_NICE && attrs->nice <= MAX_NICE)
ret = apply_workqueue_attrs(wq, attrs);
else
ret = -EINVAL;
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index a48abeac753f..dd7f8858188a 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -980,6 +980,21 @@ config DEBUG_LOCKING_API_SELFTESTS
The following locking APIs are covered: spinlocks, rwlocks,
mutexes and rwsems.
+config LOCK_TORTURE_TEST
+ tristate "torture tests for locking"
+ depends on DEBUG_KERNEL
+ select TORTURE_TEST
+ default n
+ help
+ This option provides a kernel module that runs torture tests
+ on kernel locking primitives. The kernel module may be built
+ after the fact on the running kernel to be tested, if desired.
+
+ Say Y here if you want kernel locking-primitive torture tests
+ to be built into the kernel.
+ Say M if you want these torture tests to build as a module.
+ Say N if you are unsure.
+
endmenu # lock debugging
config TRACE_IRQFLAGS
@@ -1141,9 +1156,14 @@ config SPARSE_RCU_POINTER
Say N if you are unsure.
+config TORTURE_TEST
+ tristate
+ default n
+
config RCU_TORTURE_TEST
tristate "torture tests for RCU"
depends on DEBUG_KERNEL
+ select TORTURE_TEST
default n
help
This option provides a kernel module that runs torture tests
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index 2defd1308b04..98f2d7e91a91 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -424,111 +424,134 @@ void debug_dma_dump_mappings(struct device *dev)
EXPORT_SYMBOL(debug_dma_dump_mappings);
/*
- * For each page mapped (initial page in the case of
- * dma_alloc_coherent/dma_map_{single|page}, or each page in a
- * scatterlist) insert into this tree using the pfn as the key. At
+ * For each mapping (initial cacheline in the case of
+ * dma_alloc_coherent/dma_map_page, initial cacheline in each page of a
+ * scatterlist, or the cacheline specified in dma_map_single) insert
+ * into this tree using the cacheline as the key. At
* dma_unmap_{single|sg|page} or dma_free_coherent delete the entry. If
- * the pfn already exists at insertion time add a tag as a reference
+ * the entry already exists at insertion time add a tag as a reference
* count for the overlapping mappings. For now, the overlap tracking
- * just ensures that 'unmaps' balance 'maps' before marking the pfn
- * idle, but we should also be flagging overlaps as an API violation.
+ * just ensures that 'unmaps' balance 'maps' before marking the
+ * cacheline idle, but we should also be flagging overlaps as an API
+ * violation.
*
* Memory usage is mostly constrained by the maximum number of available
* dma-debug entries in that we need a free dma_debug_entry before
- * inserting into the tree. In the case of dma_map_{single|page} and
- * dma_alloc_coherent there is only one dma_debug_entry and one pfn to
- * track per event. dma_map_sg(), on the other hand,
- * consumes a single dma_debug_entry, but inserts 'nents' entries into
- * the tree.
+ * inserting into the tree. In the case of dma_map_page and
+ * dma_alloc_coherent there is only one dma_debug_entry and one
+ * dma_active_cacheline entry to track per event. dma_map_sg(), on the
+ * other hand, consumes a single dma_debug_entry, but inserts 'nents'
+ * entries into the tree.
*
* At any time debug_dma_assert_idle() can be called to trigger a
- * warning if the given page is in the active set.
+ * warning if any cachelines in the given page are in the active set.
*/
-static RADIX_TREE(dma_active_pfn, GFP_NOWAIT);
+static RADIX_TREE(dma_active_cacheline, GFP_NOWAIT);
static DEFINE_SPINLOCK(radix_lock);
-#define ACTIVE_PFN_MAX_OVERLAP ((1 << RADIX_TREE_MAX_TAGS) - 1)
+#define ACTIVE_CACHELINE_MAX_OVERLAP ((1 << RADIX_TREE_MAX_TAGS) - 1)
+#define CACHELINE_PER_PAGE_SHIFT (PAGE_SHIFT - L1_CACHE_SHIFT)
+#define CACHELINES_PER_PAGE (1 << CACHELINE_PER_PAGE_SHIFT)
-static int active_pfn_read_overlap(unsigned long pfn)
+static phys_addr_t to_cacheline_number(struct dma_debug_entry *entry)
+{
+ return (entry->pfn << CACHELINE_PER_PAGE_SHIFT) +
+ (entry->offset >> L1_CACHE_SHIFT);
+}
+
+static int active_cacheline_read_overlap(phys_addr_t cln)
{
int overlap = 0, i;
for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
- if (radix_tree_tag_get(&dma_active_pfn, pfn, i))
+ if (radix_tree_tag_get(&dma_active_cacheline, cln, i))
overlap |= 1 << i;
return overlap;
}
-static int active_pfn_set_overlap(unsigned long pfn, int overlap)
+static int active_cacheline_set_overlap(phys_addr_t cln, int overlap)
{
int i;
- if (overlap > ACTIVE_PFN_MAX_OVERLAP || overlap < 0)
+ if (overlap > ACTIVE_CACHELINE_MAX_OVERLAP || overlap < 0)
return overlap;
for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
if (overlap & 1 << i)
- radix_tree_tag_set(&dma_active_pfn, pfn, i);
+ radix_tree_tag_set(&dma_active_cacheline, cln, i);
else
- radix_tree_tag_clear(&dma_active_pfn, pfn, i);
+ radix_tree_tag_clear(&dma_active_cacheline, cln, i);
return overlap;
}
-static void active_pfn_inc_overlap(unsigned long pfn)
+static void active_cacheline_inc_overlap(phys_addr_t cln)
{
- int overlap = active_pfn_read_overlap(pfn);
+ int overlap = active_cacheline_read_overlap(cln);
- overlap = active_pfn_set_overlap(pfn, ++overlap);
+ overlap = active_cacheline_set_overlap(cln, ++overlap);
/* If we overflowed the overlap counter then we're potentially
* leaking dma-mappings. Otherwise, if maps and unmaps are
* balanced then this overflow may cause false negatives in
- * debug_dma_assert_idle() as the pfn may be marked idle
+ * debug_dma_assert_idle() as the cacheline may be marked idle
* prematurely.
*/
- WARN_ONCE(overlap > ACTIVE_PFN_MAX_OVERLAP,
- "DMA-API: exceeded %d overlapping mappings of pfn %lx\n",
- ACTIVE_PFN_MAX_OVERLAP, pfn);
+ WARN_ONCE(overlap > ACTIVE_CACHELINE_MAX_OVERLAP,
+ "DMA-API: exceeded %d overlapping mappings of cacheline %pa\n",
+ ACTIVE_CACHELINE_MAX_OVERLAP, &cln);
}
-static int active_pfn_dec_overlap(unsigned long pfn)
+static int active_cacheline_dec_overlap(phys_addr_t cln)
{
- int overlap = active_pfn_read_overlap(pfn);
+ int overlap = active_cacheline_read_overlap(cln);
- return active_pfn_set_overlap(pfn, --overlap);
+ return active_cacheline_set_overlap(cln, --overlap);
}
-static int active_pfn_insert(struct dma_debug_entry *entry)
+static int active_cacheline_insert(struct dma_debug_entry *entry)
{
+ phys_addr_t cln = to_cacheline_number(entry);
unsigned long flags;
int rc;
+ /* If the device is not writing memory then we don't have any
+ * concerns about the cpu consuming stale data. This mitigates
+ * legitimate usages of overlapping mappings.
+ */
+ if (entry->direction == DMA_TO_DEVICE)
+ return 0;
+
spin_lock_irqsave(&radix_lock, flags);
- rc = radix_tree_insert(&dma_active_pfn, entry->pfn, entry);
+ rc = radix_tree_insert(&dma_active_cacheline, cln, entry);
if (rc == -EEXIST)
- active_pfn_inc_overlap(entry->pfn);
+ active_cacheline_inc_overlap(cln);
spin_unlock_irqrestore(&radix_lock, flags);
return rc;
}
-static void active_pfn_remove(struct dma_debug_entry *entry)
+static void active_cacheline_remove(struct dma_debug_entry *entry)
{
+ phys_addr_t cln = to_cacheline_number(entry);
unsigned long flags;
+ /* ...mirror the insert case */
+ if (entry->direction == DMA_TO_DEVICE)
+ return;
+
spin_lock_irqsave(&radix_lock, flags);
/* since we are counting overlaps the final put of the
- * entry->pfn will occur when the overlap count is 0.
- * active_pfn_dec_overlap() returns -1 in that case
+ * cacheline will occur when the overlap count is 0.
+ * active_cacheline_dec_overlap() returns -1 in that case
*/
- if (active_pfn_dec_overlap(entry->pfn) < 0)
- radix_tree_delete(&dma_active_pfn, entry->pfn);
+ if (active_cacheline_dec_overlap(cln) < 0)
+ radix_tree_delete(&dma_active_cacheline, cln);
spin_unlock_irqrestore(&radix_lock, flags);
}
/**
* debug_dma_assert_idle() - assert that a page is not undergoing dma
- * @page: page to lookup in the dma_active_pfn tree
+ * @page: page to lookup in the dma_active_cacheline tree
*
* Place a call to this routine in cases where the cpu touching the page
* before the dma completes (page is dma_unmapped) will lead to data
@@ -536,22 +559,38 @@ static void active_pfn_remove(struct dma_debug_entry *entry)
*/
void debug_dma_assert_idle(struct page *page)
{
+ static struct dma_debug_entry *ents[CACHELINES_PER_PAGE];
+ struct dma_debug_entry *entry = NULL;
+ void **results = (void **) &ents;
+ unsigned int nents, i;
unsigned long flags;
- struct dma_debug_entry *entry;
+ phys_addr_t cln;
if (!page)
return;
+ cln = (phys_addr_t) page_to_pfn(page) << CACHELINE_PER_PAGE_SHIFT;
spin_lock_irqsave(&radix_lock, flags);
- entry = radix_tree_lookup(&dma_active_pfn, page_to_pfn(page));
+ nents = radix_tree_gang_lookup(&dma_active_cacheline, results, cln,
+ CACHELINES_PER_PAGE);
+ for (i = 0; i < nents; i++) {
+ phys_addr_t ent_cln = to_cacheline_number(ents[i]);
+
+ if (ent_cln == cln) {
+ entry = ents[i];
+ break;
+ } else if (ent_cln >= cln + CACHELINES_PER_PAGE)
+ break;
+ }
spin_unlock_irqrestore(&radix_lock, flags);
if (!entry)
return;
+ cln = to_cacheline_number(entry);
err_printk(entry->dev, entry,
- "DMA-API: cpu touching an active dma mapped page "
- "[pfn=0x%lx]\n", entry->pfn);
+ "DMA-API: cpu touching an active dma mapped cacheline [cln=%pa]\n",
+ &cln);
}
/*
@@ -568,9 +607,9 @@ static void add_dma_entry(struct dma_debug_entry *entry)
hash_bucket_add(bucket, entry);
put_hash_bucket(bucket, &flags);
- rc = active_pfn_insert(entry);
+ rc = active_cacheline_insert(entry);
if (rc == -ENOMEM) {
- pr_err("DMA-API: pfn tracking ENOMEM, dma-debug disabled\n");
+ pr_err("DMA-API: cacheline tracking ENOMEM, dma-debug disabled\n");
global_disable = true;
}
@@ -631,7 +670,7 @@ static void dma_entry_free(struct dma_debug_entry *entry)
{
unsigned long flags;
- active_pfn_remove(entry);
+ active_cacheline_remove(entry);
/*
* add to beginning of the list - this way the entries are
diff --git a/lib/fonts/Kconfig b/lib/fonts/Kconfig
index 4dc1b990aa23..34fd931b54b5 100644
--- a/lib/fonts/Kconfig
+++ b/lib/fonts/Kconfig
@@ -9,7 +9,7 @@ if FONT_SUPPORT
config FONTS
bool "Select compiled-in fonts"
- depends on FRAMEBUFFER_CONSOLE
+ depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
help
Say Y here if you would like to use fonts other than the default
your frame buffer console usually use.
@@ -22,7 +22,7 @@ config FONTS
config FONT_8x8
bool "VGA 8x8 font" if FONTS
- depends on FRAMEBUFFER_CONSOLE
+ depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
default y if !SPARC && !FONTS
help
This is the "high resolution" font for the VGA frame buffer (the one
@@ -45,7 +45,7 @@ config FONT_8x16
config FONT_6x11
bool "Mac console 6x11 font (not supported by all drivers)" if FONTS
- depends on FRAMEBUFFER_CONSOLE
+ depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
default y if !SPARC && !FONTS && MAC
help
Small console font with Macintosh-style high-half glyphs. Some Mac
diff --git a/lib/idr.c b/lib/idr.c
index bfe4db4e165f..1ba4956bfbff 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -869,6 +869,16 @@ void idr_init(struct idr *idp)
}
EXPORT_SYMBOL(idr_init);
+static int idr_has_entry(int id, void *p, void *data)
+{
+ return 1;
+}
+
+bool idr_is_empty(struct idr *idp)
+{
+ return !idr_for_each(idp, idr_has_entry, NULL);
+}
+EXPORT_SYMBOL(idr_is_empty);
/**
* DOC: IDA description
diff --git a/lib/kobject.c b/lib/kobject.c
index cb14aeac4cca..58751bb80a7c 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -94,7 +94,7 @@ static int create_dir(struct kobject *kobj)
BUG_ON(ops->type >= KOBJ_NS_TYPES);
BUG_ON(!kobj_ns_type_registered(ops->type));
- kernfs_enable_ns(kobj->sd);
+ sysfs_enable_ns(kobj->sd);
}
return 0;
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 7811ed3b4e70..bd4a8dfdf0b8 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -1253,8 +1253,10 @@ unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item)
node = indirect_to_ptr(node);
max_index = radix_tree_maxindex(node->height);
- if (cur_index > max_index)
+ if (cur_index > max_index) {
+ rcu_read_unlock();
break;
+ }
cur_index = __locate(node, item, cur_index, &found_index);
rcu_read_unlock();
diff --git a/lib/random32.c b/lib/random32.c
index 1e5b2df44291..614896778700 100644
--- a/lib/random32.c
+++ b/lib/random32.c
@@ -244,8 +244,19 @@ static void __prandom_reseed(bool late)
static bool latch = false;
static DEFINE_SPINLOCK(lock);
+ /* Asking for random bytes might result in bytes getting
+ * moved into the nonblocking pool and thus marking it
+ * as initialized. In this case we would double back into
+ * this function and attempt to do a late reseed.
+ * Ignore the pointless attempt to reseed again if we're
+ * already waiting for bytes when the nonblocking pool
+ * got initialized.
+ */
+
/* only allow initial seeding (late == false) once */
- spin_lock_irqsave(&lock, flags);
+ if (!spin_trylock_irqsave(&lock, flags))
+ return;
+
if (latch && !late)
goto out;
latch = true;
diff --git a/lib/string.c b/lib/string.c
index e5878de4f101..9b1f9062a202 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -648,7 +648,7 @@ EXPORT_SYMBOL(memmove);
* @count: The size of the area.
*/
#undef memcmp
-int memcmp(const void *cs, const void *ct, size_t count)
+__visible int memcmp(const void *cs, const void *ct, size_t count)
{
const unsigned char *su1, *su2;
int res = 0;
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 185b6d300ebc..5e2cf6f342f8 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -719,10 +719,15 @@ char *resource_string(char *buf, char *end, struct resource *res,
specp = &mem_spec;
decode = 0;
}
- p = number(p, pend, res->start, *specp);
- if (res->start != res->end) {
- *p++ = '-';
- p = number(p, pend, res->end, *specp);
+ if (decode && res->flags & IORESOURCE_UNSET) {
+ p = string(p, pend, "size ", str_spec);
+ p = number(p, pend, resource_size(res), *specp);
+ } else {
+ p = number(p, pend, res->start, *specp);
+ if (res->start != res->end) {
+ *p++ = '-';
+ p = number(p, pend, res->end, *specp);
+ }
}
if (decode) {
if (res->flags & IORESOURCE_MEM_64)
diff --git a/mm/Kconfig b/mm/Kconfig
index 2d9f1504d75e..2888024e0b0a 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -575,5 +575,5 @@ config PGTABLE_MAPPING
then you should select this. This causes zsmalloc to use page table
mapping rather than copying for object mapping.
- You can check speed with zsmalloc benchmark[1].
- [1] https://github.com/spartacus06/zsmalloc
+ You can check speed with zsmalloc benchmark:
+ https://github.com/spartacus06/zsmapbench
diff --git a/mm/compaction.c b/mm/compaction.c
index b48c5259ea33..918577595ea8 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -251,7 +251,6 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
{
int nr_scanned = 0, total_isolated = 0;
struct page *cursor, *valid_page = NULL;
- unsigned long nr_strict_required = end_pfn - blockpfn;
unsigned long flags;
bool locked = false;
@@ -264,11 +263,12 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
nr_scanned++;
if (!pfn_valid_within(blockpfn))
- continue;
+ goto isolate_fail;
+
if (!valid_page)
valid_page = page;
if (!PageBuddy(page))
- continue;
+ goto isolate_fail;
/*
* The zone lock must be held to isolate freepages.
@@ -289,12 +289,10 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
/* Recheck this is a buddy page under lock */
if (!PageBuddy(page))
- continue;
+ goto isolate_fail;
/* Found a free page, break it into order-0 pages */
isolated = split_free_page(page);
- if (!isolated && strict)
- break;
total_isolated += isolated;
for (i = 0; i < isolated; i++) {
list_add(&page->lru, freelist);
@@ -305,7 +303,15 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
if (isolated) {
blockpfn += isolated - 1;
cursor += isolated - 1;
+ continue;
}
+
+isolate_fail:
+ if (strict)
+ break;
+ else
+ continue;
+
}
trace_mm_compaction_isolate_freepages(nr_scanned, total_isolated);
@@ -315,7 +321,7 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
* pages requested were isolated. If there were any failures, 0 is
* returned and CMA will fail.
*/
- if (strict && nr_strict_required > total_isolated)
+ if (strict && blockpfn < end_pfn)
total_isolated = 0;
if (locked)
diff --git a/mm/fremap.c b/mm/fremap.c
index bbc4d660221a..34feba60a17e 100644
--- a/mm/fremap.c
+++ b/mm/fremap.c
@@ -23,28 +23,44 @@
#include "internal.h"
+static int mm_counter(struct page *page)
+{
+ return PageAnon(page) ? MM_ANONPAGES : MM_FILEPAGES;
+}
+
static void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep)
{
pte_t pte = *ptep;
+ struct page *page;
+ swp_entry_t entry;
if (pte_present(pte)) {
- struct page *page;
-
flush_cache_page(vma, addr, pte_pfn(pte));
pte = ptep_clear_flush(vma, addr, ptep);
page = vm_normal_page(vma, addr, pte);
if (page) {
if (pte_dirty(pte))
set_page_dirty(page);
+ update_hiwater_rss(mm);
+ dec_mm_counter(mm, mm_counter(page));
page_remove_rmap(page);
page_cache_release(page);
+ }
+ } else { /* zap_pte() is not called when pte_none() */
+ if (!pte_file(pte)) {
update_hiwater_rss(mm);
- dec_mm_counter(mm, MM_FILEPAGES);
+ entry = pte_to_swp_entry(pte);
+ if (non_swap_entry(entry)) {
+ if (is_migration_entry(entry)) {
+ page = migration_entry_to_page(entry);
+ dec_mm_counter(mm, mm_counter(page));
+ }
+ } else {
+ free_swap_and_cache(entry);
+ dec_mm_counter(mm, MM_SWAPENTS);
+ }
}
- } else {
- if (!pte_file(pte))
- free_swap_and_cache(pte_to_swp_entry(pte));
pte_clear_not_present_full(mm, addr, ptep, 0);
}
}
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 82166bf974e1..1546655a2d78 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1166,8 +1166,10 @@ alloc:
} else {
ret = do_huge_pmd_wp_page_fallback(mm, vma, address,
pmd, orig_pmd, page, haddr);
- if (ret & VM_FAULT_OOM)
+ if (ret & VM_FAULT_OOM) {
split_huge_page(page);
+ ret |= VM_FAULT_FALLBACK;
+ }
put_page(page);
}
count_vm_event(THP_FAULT_FALLBACK);
@@ -1179,9 +1181,10 @@ alloc:
if (page) {
split_huge_page(page);
put_page(page);
- }
+ } else
+ split_huge_page_pmd(vma, address, pmd);
+ ret |= VM_FAULT_FALLBACK;
count_vm_event(THP_FAULT_FALLBACK);
- ret |= VM_FAULT_OOM;
goto out;
}
@@ -1545,6 +1548,7 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
entry = pmd_mknonnuma(entry);
entry = pmd_modify(entry, newprot);
ret = HPAGE_PMD_NR;
+ set_pmd_at(mm, addr, pmd, entry);
BUG_ON(pmd_write(entry));
} else {
struct page *page = pmd_page(*pmd);
@@ -1557,16 +1561,10 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
*/
if (!is_huge_zero_page(page) &&
!pmd_numa(*pmd)) {
- entry = *pmd;
- entry = pmd_mknuma(entry);
+ pmdp_set_numa(mm, addr, pmd);
ret = HPAGE_PMD_NR;
}
}
-
- /* Set PMD if cleared earlier */
- if (ret == HPAGE_PMD_NR)
- set_pmd_at(mm, addr, pmd, entry);
-
spin_unlock(ptl);
}
@@ -1963,7 +1961,7 @@ out:
return ret;
}
-#define VM_NO_THP (VM_SPECIAL|VM_MIXEDMAP|VM_HUGETLB|VM_SHARED|VM_MAYSHARE)
+#define VM_NO_THP (VM_SPECIAL | VM_HUGETLB | VM_SHARED | VM_MAYSHARE)
int hugepage_madvise(struct vm_area_struct *vma,
unsigned long *vm_flags, int advice)
diff --git a/mm/ksm.c b/mm/ksm.c
index aa4c7c7250c1..68710e80994a 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -444,7 +444,7 @@ static void break_cow(struct rmap_item *rmap_item)
static struct page *page_trans_compound_anon(struct page *page)
{
if (PageTransCompound(page)) {
- struct page *head = compound_trans_head(page);
+ struct page *head = compound_head(page);
/*
* head may actually be splitted and freed from under
* us but it's ok here.
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 53385cd4e6f0..5b6b0039f725 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1127,8 +1127,8 @@ skip_node:
* skipping css reference should be safe.
*/
if (next_css) {
- if ((next_css->flags & CSS_ONLINE) &&
- (next_css == &root->css || css_tryget(next_css)))
+ if ((next_css == &root->css) ||
+ ((next_css->flags & CSS_ONLINE) && css_tryget(next_css)))
return mem_cgroup_from_css(next_css);
prev_css = next_css;
@@ -1687,7 +1687,7 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
* protects memcg_name and makes sure that parallel ooms do not
* interleave
*/
- static DEFINE_SPINLOCK(oom_info_lock);
+ static DEFINE_MUTEX(oom_info_lock);
struct cgroup *task_cgrp;
struct cgroup *mem_cgrp;
static char memcg_name[PATH_MAX];
@@ -1698,7 +1698,7 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
if (!p)
return;
- spin_lock(&oom_info_lock);
+ mutex_lock(&oom_info_lock);
rcu_read_lock();
mem_cgrp = memcg->css.cgroup;
@@ -1767,7 +1767,7 @@ done:
pr_cont("\n");
}
- spin_unlock(&oom_info_lock);
+ mutex_unlock(&oom_info_lock);
}
/*
@@ -6595,6 +6595,7 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
struct mem_cgroup_event *event, *tmp;
+ struct cgroup_subsys_state *iter;
/*
* Unregister events and notify userspace.
@@ -6611,7 +6612,14 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
kmem_cgroup_css_offline(memcg);
mem_cgroup_invalidate_reclaim_iterators(memcg);
- mem_cgroup_reparent_charges(memcg);
+
+ /*
+ * This requires that offlining is serialized. Right now that is
+ * guaranteed because css_killed_work_fn() holds the cgroup_mutex.
+ */
+ css_for_each_descendant_post(iter, css)
+ mem_cgroup_reparent_charges(mem_cgroup_from_css(iter));
+
mem_cgroup_destroy_all_caches(memcg);
vmpressure_cleanup(&memcg->vmpressure);
}
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 2f2f34a4e77d..90002ea43638 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1651,7 +1651,7 @@ int soft_offline_page(struct page *page, int flags)
{
int ret;
unsigned long pfn = page_to_pfn(page);
- struct page *hpage = compound_trans_head(page);
+ struct page *hpage = compound_head(page);
if (PageHWPoison(page)) {
pr_info("soft offline: %#lx page already poisoned\n", pfn);
diff --git a/mm/memory.c b/mm/memory.c
index be6a0c0d4ae0..22dfa617bddb 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3348,6 +3348,7 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
if (ret & VM_FAULT_LOCKED)
unlock_page(vmf.page);
ret = VM_FAULT_HWPOISON;
+ page_cache_release(vmf.page);
goto uncharge_out;
}
@@ -3703,7 +3704,6 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
if (unlikely(is_vm_hugetlb_page(vma)))
return hugetlb_fault(mm, vma, address, flags);
-retry:
pgd = pgd_offset(mm, address);
pud = pud_alloc(mm, pgd, address);
if (!pud)
@@ -3741,20 +3741,13 @@ retry:
if (dirty && !pmd_write(orig_pmd)) {
ret = do_huge_pmd_wp_page(mm, vma, address, pmd,
orig_pmd);
- /*
- * If COW results in an oom, the huge pmd will
- * have been split, so retry the fault on the
- * pte for a smaller charge.
- */
- if (unlikely(ret & VM_FAULT_OOM))
- goto retry;
- return ret;
+ if (!(ret & VM_FAULT_FALLBACK))
+ return ret;
} else {
huge_pmd_set_accessed(mm, vma, address, pmd,
orig_pmd, dirty);
+ return 0;
}
-
- return 0;
}
}
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index ae3c8f3595d4..4755c8576942 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1556,10 +1556,10 @@ SYSCALL_DEFINE5(get_mempolicy, int __user *, policy,
#ifdef CONFIG_COMPAT
-asmlinkage long compat_sys_get_mempolicy(int __user *policy,
- compat_ulong_t __user *nmask,
- compat_ulong_t maxnode,
- compat_ulong_t addr, compat_ulong_t flags)
+COMPAT_SYSCALL_DEFINE5(get_mempolicy, int __user *, policy,
+ compat_ulong_t __user *, nmask,
+ compat_ulong_t, maxnode,
+ compat_ulong_t, addr, compat_ulong_t, flags)
{
long err;
unsigned long __user *nm = NULL;
@@ -1586,8 +1586,8 @@ asmlinkage long compat_sys_get_mempolicy(int __user *policy,
return err;
}
-asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask,
- compat_ulong_t maxnode)
+COMPAT_SYSCALL_DEFINE3(set_mempolicy, int, mode, compat_ulong_t __user *, nmask,
+ compat_ulong_t, maxnode)
{
long err = 0;
unsigned long __user *nm = NULL;
@@ -1609,9 +1609,9 @@ asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask,
return sys_set_mempolicy(mode, nm, nr_bits+1);
}
-asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
- compat_ulong_t mode, compat_ulong_t __user *nmask,
- compat_ulong_t maxnode, compat_ulong_t flags)
+COMPAT_SYSCALL_DEFINE6(mbind, compat_ulong_t, start, compat_ulong_t, len,
+ compat_ulong_t, mode, compat_ulong_t __user *, nmask,
+ compat_ulong_t, maxnode, compat_ulong_t, flags)
{
long err = 0;
unsigned long __user *nm = NULL;
@@ -2301,35 +2301,6 @@ static void sp_free(struct sp_node *n)
kmem_cache_free(sn_cache, n);
}
-#ifdef CONFIG_NUMA_BALANCING
-static bool numa_migrate_deferred(struct task_struct *p, int last_cpupid)
-{
- /* Never defer a private fault */
- if (cpupid_match_pid(p, last_cpupid))
- return false;
-
- if (p->numa_migrate_deferred) {
- p->numa_migrate_deferred--;
- return true;
- }
- return false;
-}
-
-static inline void defer_numa_migrate(struct task_struct *p)
-{
- p->numa_migrate_deferred = sysctl_numa_balancing_migrate_deferred;
-}
-#else
-static inline bool numa_migrate_deferred(struct task_struct *p, int last_cpupid)
-{
- return false;
-}
-
-static inline void defer_numa_migrate(struct task_struct *p)
-{
-}
-#endif /* CONFIG_NUMA_BALANCING */
-
/**
* mpol_misplaced - check whether current page node is valid in policy
*
@@ -2403,52 +2374,9 @@ int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long
/* Migrate the page towards the node whose CPU is referencing it */
if (pol->flags & MPOL_F_MORON) {
- int last_cpupid;
- int this_cpupid;
-
polnid = thisnid;
- this_cpupid = cpu_pid_to_cpupid(thiscpu, current->pid);
-
- /*
- * Multi-stage node selection is used in conjunction
- * with a periodic migration fault to build a temporal
- * task<->page relation. By using a two-stage filter we
- * remove short/unlikely relations.
- *
- * Using P(p) ~ n_p / n_t as per frequentist
- * probability, we can equate a task's usage of a
- * particular page (n_p) per total usage of this
- * page (n_t) (in a given time-span) to a probability.
- *
- * Our periodic faults will sample this probability and
- * getting the same result twice in a row, given these
- * samples are fully independent, is then given by
- * P(n)^2, provided our sample period is sufficiently
- * short compared to the usage pattern.
- *
- * This quadric squishes small probabilities, making
- * it less likely we act on an unlikely task<->page
- * relation.
- */
- last_cpupid = page_cpupid_xchg_last(page, this_cpupid);
- if (!cpupid_pid_unset(last_cpupid) && cpupid_to_nid(last_cpupid) != thisnid) {
- /* See sysctl_numa_balancing_migrate_deferred comment */
- if (!cpupid_match_pid(current, last_cpupid))
- defer_numa_migrate(current);
-
- goto out;
- }
-
- /*
- * The quadratic filter above reduces extraneous migration
- * of shared pages somewhat. This code reduces it even more,
- * reducing the overhead of page migrations of shared pages.
- * This makes workloads with shared pages rely more on
- * "move task near its memory", and less on "move memory
- * towards its task", which is exactly what we want.
- */
- if (numa_migrate_deferred(current, last_cpupid))
+ if (!should_numa_migrate_memory(current, page, curnid, thiscpu))
goto out;
}
diff --git a/mm/migrate.c b/mm/migrate.c
index 482a33d89134..bed48809e5d0 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -178,6 +178,37 @@ out:
}
/*
+ * Congratulations to trinity for discovering this bug.
+ * mm/fremap.c's remap_file_pages() accepts any range within a single vma to
+ * convert that vma to VM_NONLINEAR; and generic_file_remap_pages() will then
+ * replace the specified range by file ptes throughout (maybe populated after).
+ * If page migration finds a page within that range, while it's still located
+ * by vma_interval_tree rather than lost to i_mmap_nonlinear list, no problem:
+ * zap_pte() clears the temporary migration entry before mmap_sem is dropped.
+ * But if the migrating page is in a part of the vma outside the range to be
+ * remapped, then it will not be cleared, and remove_migration_ptes() needs to
+ * deal with it. Fortunately, this part of the vma is of course still linear,
+ * so we just need to use linear location on the nonlinear list.
+ */
+static int remove_linear_migration_ptes_from_nonlinear(struct page *page,
+ struct address_space *mapping, void *arg)
+{
+ struct vm_area_struct *vma;
+ /* hugetlbfs does not support remap_pages, so no huge pgoff worries */
+ pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
+ unsigned long addr;
+
+ list_for_each_entry(vma,
+ &mapping->i_mmap_nonlinear, shared.nonlinear) {
+
+ addr = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
+ if (addr >= vma->vm_start && addr < vma->vm_end)
+ remove_migration_pte(page, vma, addr, arg);
+ }
+ return SWAP_AGAIN;
+}
+
+/*
* Get rid of all migration entries and replace them by
* references to the indicated page.
*/
@@ -186,6 +217,7 @@ static void remove_migration_ptes(struct page *old, struct page *new)
struct rmap_walk_control rwc = {
.rmap_one = remove_migration_pte,
.arg = old,
+ .file_nonlinear = remove_linear_migration_ptes_from_nonlinear,
};
rmap_walk(new, &rwc);
@@ -1158,7 +1190,7 @@ static struct page *new_page_node(struct page *p, unsigned long private,
pm->node);
else
return alloc_pages_exact_node(pm->node,
- GFP_HIGHUSER_MOVABLE | GFP_THISNODE, 0);
+ GFP_HIGHUSER_MOVABLE | __GFP_THISNODE, 0);
}
/*
@@ -1544,9 +1576,9 @@ static struct page *alloc_misplaced_dst_page(struct page *page,
struct page *newpage;
newpage = alloc_pages_exact_node(nid,
- (GFP_HIGHUSER_MOVABLE | GFP_THISNODE |
- __GFP_NOMEMALLOC | __GFP_NORETRY |
- __GFP_NOWARN) &
+ (GFP_HIGHUSER_MOVABLE |
+ __GFP_THISNODE | __GFP_NOMEMALLOC |
+ __GFP_NORETRY | __GFP_NOWARN) &
~GFP_IOFS, 0);
return newpage;
@@ -1747,7 +1779,8 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
goto out_dropref;
new_page = alloc_pages_node(node,
- (GFP_TRANSHUGE | GFP_THISNODE) & ~__GFP_WAIT, HPAGE_PMD_ORDER);
+ (GFP_TRANSHUGE | __GFP_THISNODE) & ~__GFP_WAIT,
+ HPAGE_PMD_ORDER);
if (!new_page)
goto out_fail;
diff --git a/mm/mmap.c b/mm/mmap.c
index 20ff0c33274c..81ba54ff96c7 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2918,7 +2918,7 @@ static const struct vm_operations_struct special_mapping_vmops = {
* The array pointer and the pages it points to are assumed to stay alive
* for as long as this mapping might exist.
*/
-int install_special_mapping(struct mm_struct *mm,
+struct vm_area_struct *_install_special_mapping(struct mm_struct *mm,
unsigned long addr, unsigned long len,
unsigned long vm_flags, struct page **pages)
{
@@ -2927,7 +2927,7 @@ int install_special_mapping(struct mm_struct *mm,
vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
if (unlikely(vma == NULL))
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&vma->anon_vma_chain);
vma->vm_mm = mm;
@@ -2948,11 +2948,23 @@ int install_special_mapping(struct mm_struct *mm,
perf_event_mmap(vma);
- return 0;
+ return vma;
out:
kmem_cache_free(vm_area_cachep, vma);
- return ret;
+ return ERR_PTR(ret);
+}
+
+int install_special_mapping(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long vm_flags, struct page **pages)
+{
+ struct vm_area_struct *vma = _install_special_mapping(mm,
+ addr, len, vm_flags, pages);
+
+ if (IS_ERR(vma))
+ return PTR_ERR(vma);
+ return 0;
}
static DEFINE_MUTEX(mm_all_locks_mutex);
diff --git a/mm/mmu_context.c b/mm/mmu_context.c
index 8a8cd0265e52..f802c2d216a7 100644
--- a/mm/mmu_context.c
+++ b/mm/mmu_context.c
@@ -31,6 +31,9 @@ void use_mm(struct mm_struct *mm)
tsk->mm = mm;
switch_mm(active_mm, mm, tsk);
task_unlock(tsk);
+#ifdef finish_arch_post_lock_switch
+ finish_arch_post_lock_switch();
+#endif
if (active_mm != mm)
mmdrop(active_mm);
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 7332c1785744..769a67a15803 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -58,36 +58,27 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
if (pte_numa(ptent))
ptent = pte_mknonnuma(ptent);
ptent = pte_modify(ptent, newprot);
+ /*
+ * Avoid taking write faults for pages we
+ * know to be dirty.
+ */
+ if (dirty_accountable && pte_dirty(ptent))
+ ptent = pte_mkwrite(ptent);
+ ptep_modify_prot_commit(mm, addr, pte, ptent);
updated = true;
} else {
struct page *page;
- ptent = *pte;
page = vm_normal_page(vma, addr, oldpte);
if (page && !PageKsm(page)) {
if (!pte_numa(oldpte)) {
- ptent = pte_mknuma(ptent);
- set_pte_at(mm, addr, pte, ptent);
+ ptep_set_numa(mm, addr, pte);
updated = true;
}
}
}
-
- /*
- * Avoid taking write faults for pages we know to be
- * dirty.
- */
- if (dirty_accountable && pte_dirty(ptent)) {
- ptent = pte_mkwrite(ptent);
- updated = true;
- }
-
if (updated)
pages++;
-
- /* Only !prot_numa always clears the pte */
- if (!prot_numa)
- ptep_modify_prot_commit(mm, addr, pte, ptent);
} else if (IS_ENABLED(CONFIG_MIGRATION) && !pte_file(oldpte)) {
swp_entry_t entry = pte_to_swp_entry(oldpte);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index e3758a09a009..3bac76ae4b30 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -369,9 +369,11 @@ void prep_compound_page(struct page *page, unsigned long order)
__SetPageHead(page);
for (i = 1; i < nr_pages; i++) {
struct page *p = page + i;
- __SetPageTail(p);
set_page_count(p, 0);
p->first_page = page;
+ /* Make sure p->first_page is always valid for PageTail() */
+ smp_wmb();
+ __SetPageTail(p);
}
}
@@ -1236,6 +1238,15 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp)
}
local_irq_restore(flags);
}
+static bool gfp_thisnode_allocation(gfp_t gfp_mask)
+{
+ return (gfp_mask & GFP_THISNODE) == GFP_THISNODE;
+}
+#else
+static bool gfp_thisnode_allocation(gfp_t gfp_mask)
+{
+ return false;
+}
#endif
/*
@@ -1572,7 +1583,13 @@ again:
get_pageblock_migratetype(page));
}
- __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
+ /*
+ * NOTE: GFP_THISNODE allocations do not partake in the kswapd
+ * aging protocol, so they can't be fair.
+ */
+ if (!gfp_thisnode_allocation(gfp_flags))
+ __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
+
__count_zone_vm_events(PGALLOC, zone, 1 << order);
zone_statistics(preferred_zone, zone, gfp_flags);
local_irq_restore(flags);
@@ -1944,8 +1961,12 @@ zonelist_scan:
* ultimately fall back to remote zones that do not
* partake in the fairness round-robin cycle of this
* zonelist.
+ *
+ * NOTE: GFP_THISNODE allocations do not partake in
+ * the kswapd aging protocol, so they can't be fair.
*/
- if (alloc_flags & ALLOC_WMARK_LOW) {
+ if ((alloc_flags & ALLOC_WMARK_LOW) &&
+ !gfp_thisnode_allocation(gfp_mask)) {
if (zone_page_state(zone, NR_ALLOC_BATCH) <= 0)
continue;
if (!zone_local(preferred_zone, zone))
@@ -2501,8 +2522,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
* allowed per node queues are empty and that nodes are
* over allocated.
*/
- if (IS_ENABLED(CONFIG_NUMA) &&
- (gfp_mask & GFP_THISNODE) == GFP_THISNODE)
+ if (gfp_thisnode_allocation(gfp_mask))
goto nopage;
restart:
diff --git a/mm/percpu.c b/mm/percpu.c
index 036cfe07050f..63e24fb4387b 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -102,10 +102,11 @@ struct pcpu_chunk {
int free_size; /* free bytes in the chunk */
int contig_hint; /* max contiguous size hint */
void *base_addr; /* base address of this chunk */
- int map_used; /* # of map entries used */
+ int map_used; /* # of map entries used before the sentry */
int map_alloc; /* # of map entries allocated */
int *map; /* allocation map */
void *data; /* chunk data */
+ int first_free; /* no free below this */
bool immutable; /* no [de]population allowed */
unsigned long populated[]; /* populated bitmap */
};
@@ -356,11 +357,11 @@ static int pcpu_need_to_extend(struct pcpu_chunk *chunk)
{
int new_alloc;
- if (chunk->map_alloc >= chunk->map_used + 2)
+ if (chunk->map_alloc >= chunk->map_used + 3)
return 0;
new_alloc = PCPU_DFL_MAP_ALLOC;
- while (new_alloc < chunk->map_used + 2)
+ while (new_alloc < chunk->map_used + 3)
new_alloc *= 2;
return new_alloc;
@@ -418,48 +419,6 @@ out_unlock:
}
/**
- * pcpu_split_block - split a map block
- * @chunk: chunk of interest
- * @i: index of map block to split
- * @head: head size in bytes (can be 0)
- * @tail: tail size in bytes (can be 0)
- *
- * Split the @i'th map block into two or three blocks. If @head is
- * non-zero, @head bytes block is inserted before block @i moving it
- * to @i+1 and reducing its size by @head bytes.
- *
- * If @tail is non-zero, the target block, which can be @i or @i+1
- * depending on @head, is reduced by @tail bytes and @tail byte block
- * is inserted after the target block.
- *
- * @chunk->map must have enough free slots to accommodate the split.
- *
- * CONTEXT:
- * pcpu_lock.
- */
-static void pcpu_split_block(struct pcpu_chunk *chunk, int i,
- int head, int tail)
-{
- int nr_extra = !!head + !!tail;
-
- BUG_ON(chunk->map_alloc < chunk->map_used + nr_extra);
-
- /* insert new subblocks */
- memmove(&chunk->map[i + nr_extra], &chunk->map[i],
- sizeof(chunk->map[0]) * (chunk->map_used - i));
- chunk->map_used += nr_extra;
-
- if (head) {
- chunk->map[i + 1] = chunk->map[i] - head;
- chunk->map[i++] = head;
- }
- if (tail) {
- chunk->map[i++] -= tail;
- chunk->map[i] = tail;
- }
-}
-
-/**
* pcpu_alloc_area - allocate area from a pcpu_chunk
* @chunk: chunk of interest
* @size: wanted size in bytes
@@ -483,19 +442,27 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
int oslot = pcpu_chunk_slot(chunk);
int max_contig = 0;
int i, off;
+ bool seen_free = false;
+ int *p;
- for (i = 0, off = 0; i < chunk->map_used; off += abs(chunk->map[i++])) {
- bool is_last = i + 1 == chunk->map_used;
+ for (i = chunk->first_free, p = chunk->map + i; i < chunk->map_used; i++, p++) {
int head, tail;
+ int this_size;
+
+ off = *p;
+ if (off & 1)
+ continue;
/* extra for alignment requirement */
head = ALIGN(off, align) - off;
- BUG_ON(i == 0 && head != 0);
- if (chunk->map[i] < 0)
- continue;
- if (chunk->map[i] < head + size) {
- max_contig = max(chunk->map[i], max_contig);
+ this_size = (p[1] & ~1) - off;
+ if (this_size < head + size) {
+ if (!seen_free) {
+ chunk->first_free = i;
+ seen_free = true;
+ }
+ max_contig = max(this_size, max_contig);
continue;
}
@@ -505,44 +472,59 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
* than sizeof(int), which is very small but isn't too
* uncommon for percpu allocations.
*/
- if (head && (head < sizeof(int) || chunk->map[i - 1] > 0)) {
- if (chunk->map[i - 1] > 0)
- chunk->map[i - 1] += head;
- else {
- chunk->map[i - 1] -= head;
+ if (head && (head < sizeof(int) || !(p[-1] & 1))) {
+ *p = off += head;
+ if (p[-1] & 1)
chunk->free_size -= head;
- }
- chunk->map[i] -= head;
- off += head;
+ else
+ max_contig = max(*p - p[-1], max_contig);
+ this_size -= head;
head = 0;
}
/* if tail is small, just keep it around */
- tail = chunk->map[i] - head - size;
- if (tail < sizeof(int))
+ tail = this_size - head - size;
+ if (tail < sizeof(int)) {
tail = 0;
+ size = this_size - head;
+ }
/* split if warranted */
if (head || tail) {
- pcpu_split_block(chunk, i, head, tail);
+ int nr_extra = !!head + !!tail;
+
+ /* insert new subblocks */
+ memmove(p + nr_extra + 1, p + 1,
+ sizeof(chunk->map[0]) * (chunk->map_used - i));
+ chunk->map_used += nr_extra;
+
if (head) {
- i++;
- off += head;
- max_contig = max(chunk->map[i - 1], max_contig);
+ if (!seen_free) {
+ chunk->first_free = i;
+ seen_free = true;
+ }
+ *++p = off += head;
+ ++i;
+ max_contig = max(head, max_contig);
+ }
+ if (tail) {
+ p[1] = off + size;
+ max_contig = max(tail, max_contig);
}
- if (tail)
- max_contig = max(chunk->map[i + 1], max_contig);
}
+ if (!seen_free)
+ chunk->first_free = i + 1;
+
/* update hint and mark allocated */
- if (is_last)
+ if (i + 1 == chunk->map_used)
chunk->contig_hint = max_contig; /* fully scanned */
else
chunk->contig_hint = max(chunk->contig_hint,
max_contig);
- chunk->free_size -= chunk->map[i];
- chunk->map[i] = -chunk->map[i];
+ chunk->free_size -= size;
+ *p |= 1;
pcpu_chunk_relocate(chunk, oslot);
return off;
@@ -570,34 +552,50 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
static void pcpu_free_area(struct pcpu_chunk *chunk, int freeme)
{
int oslot = pcpu_chunk_slot(chunk);
- int i, off;
-
- for (i = 0, off = 0; i < chunk->map_used; off += abs(chunk->map[i++]))
- if (off == freeme)
- break;
+ int off = 0;
+ unsigned i, j;
+ int to_free = 0;
+ int *p;
+
+ freeme |= 1; /* we are searching for <given offset, in use> pair */
+
+ i = 0;
+ j = chunk->map_used;
+ while (i != j) {
+ unsigned k = (i + j) / 2;
+ off = chunk->map[k];
+ if (off < freeme)
+ i = k + 1;
+ else if (off > freeme)
+ j = k;
+ else
+ i = j = k;
+ }
BUG_ON(off != freeme);
- BUG_ON(chunk->map[i] > 0);
- chunk->map[i] = -chunk->map[i];
- chunk->free_size += chunk->map[i];
+ if (i < chunk->first_free)
+ chunk->first_free = i;
+ p = chunk->map + i;
+ *p = off &= ~1;
+ chunk->free_size += (p[1] & ~1) - off;
+
+ /* merge with next? */
+ if (!(p[1] & 1))
+ to_free++;
/* merge with previous? */
- if (i > 0 && chunk->map[i - 1] >= 0) {
- chunk->map[i - 1] += chunk->map[i];
- chunk->map_used--;
- memmove(&chunk->map[i], &chunk->map[i + 1],
- (chunk->map_used - i) * sizeof(chunk->map[0]));
+ if (i > 0 && !(p[-1] & 1)) {
+ to_free++;
i--;
+ p--;
}
- /* merge with next? */
- if (i + 1 < chunk->map_used && chunk->map[i + 1] >= 0) {
- chunk->map[i] += chunk->map[i + 1];
- chunk->map_used--;
- memmove(&chunk->map[i + 1], &chunk->map[i + 2],
- (chunk->map_used - (i + 1)) * sizeof(chunk->map[0]));
+ if (to_free) {
+ chunk->map_used -= to_free;
+ memmove(p + 1, p + 1 + to_free,
+ (chunk->map_used - i) * sizeof(chunk->map[0]));
}
- chunk->contig_hint = max(chunk->map[i], chunk->contig_hint);
+ chunk->contig_hint = max(chunk->map[i + 1] - chunk->map[i] - 1, chunk->contig_hint);
pcpu_chunk_relocate(chunk, oslot);
}
@@ -617,7 +615,9 @@ static struct pcpu_chunk *pcpu_alloc_chunk(void)
}
chunk->map_alloc = PCPU_DFL_MAP_ALLOC;
- chunk->map[chunk->map_used++] = pcpu_unit_size;
+ chunk->map[0] = 0;
+ chunk->map[1] = pcpu_unit_size | 1;
+ chunk->map_used = 1;
INIT_LIST_HEAD(&chunk->list);
chunk->free_size = pcpu_unit_size;
@@ -713,6 +713,16 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved)
unsigned long flags;
void __percpu *ptr;
+ /*
+ * We want the lowest bit of offset available for in-use/free
+ * indicator, so force >= 16bit alignment and make size even.
+ */
+ if (unlikely(align < 2))
+ align = 2;
+
+ if (unlikely(size & 1))
+ size++;
+
if (unlikely(!size || size > PCPU_MIN_UNIT_SIZE || align > PAGE_SIZE)) {
WARN(true, "illegal size (%zu) or align (%zu) for "
"percpu allocation\n", size, align);
@@ -1343,9 +1353,13 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
}
schunk->contig_hint = schunk->free_size;
- schunk->map[schunk->map_used++] = -ai->static_size;
+ schunk->map[0] = 1;
+ schunk->map[1] = ai->static_size;
+ schunk->map_used = 1;
if (schunk->free_size)
- schunk->map[schunk->map_used++] = schunk->free_size;
+ schunk->map[++schunk->map_used] = 1 | (ai->static_size + schunk->free_size);
+ else
+ schunk->map[1] |= 1;
/* init dynamic chunk if necessary */
if (dyn_size) {
@@ -1358,8 +1372,10 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
bitmap_fill(dchunk->populated, pcpu_unit_pages);
dchunk->contig_hint = dchunk->free_size = dyn_size;
- dchunk->map[dchunk->map_used++] = -pcpu_reserved_chunk_limit;
- dchunk->map[dchunk->map_used++] = dchunk->free_size;
+ dchunk->map[0] = 1;
+ dchunk->map[1] = pcpu_reserved_chunk_limit;
+ dchunk->map[2] = (pcpu_reserved_chunk_limit + dchunk->free_size) | 1;
+ dchunk->map_used = 2;
}
/* link the first chunk in */
diff --git a/mm/process_vm_access.c b/mm/process_vm_access.c
index fd26d0433509..3c5cf68566ec 100644
--- a/mm/process_vm_access.c
+++ b/mm/process_vm_access.c
@@ -456,25 +456,23 @@ free_iovecs:
return rc;
}
-asmlinkage ssize_t
-compat_sys_process_vm_readv(compat_pid_t pid,
- const struct compat_iovec __user *lvec,
- unsigned long liovcnt,
- const struct compat_iovec __user *rvec,
- unsigned long riovcnt,
- unsigned long flags)
+COMPAT_SYSCALL_DEFINE6(process_vm_readv, compat_pid_t, pid,
+ const struct compat_iovec __user *, lvec,
+ compat_ulong_t, liovcnt,
+ const struct compat_iovec __user *, rvec,
+ compat_ulong_t, riovcnt,
+ compat_ulong_t, flags)
{
return compat_process_vm_rw(pid, lvec, liovcnt, rvec,
riovcnt, flags, 0);
}
-asmlinkage ssize_t
-compat_sys_process_vm_writev(compat_pid_t pid,
- const struct compat_iovec __user *lvec,
- unsigned long liovcnt,
- const struct compat_iovec __user *rvec,
- unsigned long riovcnt,
- unsigned long flags)
+COMPAT_SYSCALL_DEFINE6(process_vm_writev, compat_pid_t, pid,
+ const struct compat_iovec __user *, lvec,
+ compat_ulong_t, liovcnt,
+ const struct compat_iovec __user *, rvec,
+ compat_ulong_t, riovcnt,
+ compat_ulong_t, flags)
{
return compat_process_vm_rw(pid, lvec, liovcnt, rvec,
riovcnt, flags, 1);
diff --git a/mm/rmap.c b/mm/rmap.c
index d9d42316a99a..11cf322f8133 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1165,6 +1165,16 @@ int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
}
set_pte_at(mm, address, pte,
swp_entry_to_pte(make_hwpoison_entry(page)));
+ } else if (pte_unused(pteval)) {
+ /*
+ * The guest indicated that the page content is of no
+ * interest anymore. Simply discard the pte, vmscan
+ * will take care of the rest.
+ */
+ if (PageAnon(page))
+ dec_mm_counter(mm, MM_ANONPAGES);
+ else
+ dec_mm_counter(mm, MM_FILEPAGES);
} else if (PageAnon(page)) {
swp_entry_t entry = { .val = page_private(page) };
pte_t swp_pte;
@@ -1360,8 +1370,9 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount,
}
static int try_to_unmap_nonlinear(struct page *page,
- struct address_space *mapping, struct vm_area_struct *vma)
+ struct address_space *mapping, void *arg)
{
+ struct vm_area_struct *vma;
int ret = SWAP_AGAIN;
unsigned long cursor;
unsigned long max_nl_cursor = 0;
@@ -1663,7 +1674,7 @@ static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc)
if (list_empty(&mapping->i_mmap_nonlinear))
goto done;
- ret = rwc->file_nonlinear(page, mapping, vma);
+ ret = rwc->file_nonlinear(page, mapping, rwc->arg);
done:
mutex_unlock(&mapping->i_mmap_mutex);
diff --git a/mm/swap.c b/mm/swap.c
index b31ba67d440a..0092097b3f4c 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -98,7 +98,7 @@ static void put_compound_page(struct page *page)
}
/* __split_huge_page_refcount can run under us */
- page_head = compound_trans_head(page);
+ page_head = compound_head(page);
/*
* THP can not break up slab pages so avoid taking
@@ -253,7 +253,7 @@ bool __get_page_tail(struct page *page)
*/
unsigned long flags;
bool got;
- struct page *page_head = compound_trans_head(page);
+ struct page *page_head = compound_head(page);
/* Ref to put_compound_page() comment. */
if (!__compound_tail_refcounted(page_head)) {
diff --git a/mm/vmpressure.c b/mm/vmpressure.c
index 196970a4541f..d4042e75f7c7 100644
--- a/mm/vmpressure.c
+++ b/mm/vmpressure.c
@@ -19,6 +19,7 @@
#include <linux/mm.h>
#include <linux/vmstat.h>
#include <linux/eventfd.h>
+#include <linux/slab.h>
#include <linux/swap.h>
#include <linux/printk.h>
#include <linux/vmpressure.h>
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index ec9909935fb6..175273f38cb1 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -307,9 +307,11 @@ static void vlan_sync_address(struct net_device *dev,
static void vlan_transfer_features(struct net_device *dev,
struct net_device *vlandev)
{
+ struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
+
vlandev->gso_max_size = dev->gso_max_size;
- if (dev->features & NETIF_F_HW_VLAN_CTAG_TX)
+ if (vlan_hw_offload_capable(dev->features, vlan->vlan_proto))
vlandev->hard_header_len = dev->hard_header_len;
else
vlandev->hard_header_len = dev->hard_header_len + VLAN_HLEN;
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index de51c48c4393..27bfe2f8e2de 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -538,6 +538,9 @@ static int vlan_passthru_hard_header(struct sk_buff *skb, struct net_device *dev
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
struct net_device *real_dev = vlan->real_dev;
+ if (saddr == NULL)
+ saddr = dev->dev_addr;
+
return dev_hard_header(skb, real_dev, type, daddr, saddr, len);
}
@@ -575,6 +578,9 @@ static int vlan_dev_init(struct net_device *dev)
dev->features |= real_dev->vlan_features | NETIF_F_LLTX;
dev->gso_max_size = real_dev->gso_max_size;
+ if (dev->features & NETIF_F_VLAN_FEATURES)
+ netdev_warn(real_dev, "VLAN features are set incorrectly. Q-in-Q configurations may not work correctly.\n");
+
/* ipv6 shared card related stuff */
dev->dev_id = real_dev->dev_id;
@@ -589,7 +595,8 @@ static int vlan_dev_init(struct net_device *dev)
#endif
dev->needed_headroom = real_dev->needed_headroom;
- if (real_dev->features & NETIF_F_HW_VLAN_CTAG_TX) {
+ if (vlan_hw_offload_capable(real_dev->features,
+ vlan_dev_priv(dev)->vlan_proto)) {
dev->header_ops = &vlan_passthru_header_ops;
dev->hard_header_len = real_dev->hard_header_len;
} else {
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 512159bf607f..8323bced8e5b 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -241,19 +241,19 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const uint8_t *addr)
size = bat_priv->num_ifaces * sizeof(uint8_t);
orig_node->bat_iv.bcast_own_sum = kzalloc(size, GFP_ATOMIC);
if (!orig_node->bat_iv.bcast_own_sum)
- goto free_bcast_own;
+ goto free_orig_node;
hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
batadv_choose_orig, orig_node,
&orig_node->hash_entry);
if (hash_added != 0)
- goto free_bcast_own;
+ goto free_orig_node;
return orig_node;
-free_bcast_own:
- kfree(orig_node->bat_iv.bcast_own);
free_orig_node:
+ /* free twice, as batadv_orig_node_new sets refcount to 2 */
+ batadv_orig_node_free_ref(orig_node);
batadv_orig_node_free_ref(orig_node);
return NULL;
@@ -266,7 +266,7 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface,
struct batadv_orig_node *orig_neigh)
{
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
- struct batadv_neigh_node *neigh_node;
+ struct batadv_neigh_node *neigh_node, *tmp_neigh_node;
neigh_node = batadv_neigh_node_new(hard_iface, neigh_addr, orig_node);
if (!neigh_node)
@@ -281,14 +281,24 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface,
neigh_node->orig_node = orig_neigh;
neigh_node->if_incoming = hard_iface;
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
- "Creating new neighbor %pM for orig_node %pM on interface %s\n",
- neigh_addr, orig_node->orig, hard_iface->net_dev->name);
-
spin_lock_bh(&orig_node->neigh_list_lock);
- hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
+ tmp_neigh_node = batadv_neigh_node_get(orig_node, hard_iface,
+ neigh_addr);
+ if (!tmp_neigh_node) {
+ hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
+ } else {
+ kfree(neigh_node);
+ batadv_hardif_free_ref(hard_iface);
+ neigh_node = tmp_neigh_node;
+ }
spin_unlock_bh(&orig_node->neigh_list_lock);
+ if (!tmp_neigh_node)
+ batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+ "Creating new neighbor %pM for orig_node %pM on interface %s\n",
+ neigh_addr, orig_node->orig,
+ hard_iface->net_dev->name);
+
out:
return neigh_node;
}
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 3d417d3641c6..b851cc580853 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -241,7 +241,7 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface)
{
struct batadv_priv *bat_priv = netdev_priv(soft_iface);
const struct batadv_hard_iface *hard_iface;
- int min_mtu = ETH_DATA_LEN;
+ int min_mtu = INT_MAX;
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
@@ -256,8 +256,6 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface)
}
rcu_read_unlock();
- atomic_set(&bat_priv->packet_size_max, min_mtu);
-
if (atomic_read(&bat_priv->fragmentation) == 0)
goto out;
@@ -268,13 +266,21 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface)
min_mtu = min_t(int, min_mtu, BATADV_FRAG_MAX_FRAG_SIZE);
min_mtu -= sizeof(struct batadv_frag_packet);
min_mtu *= BATADV_FRAG_MAX_FRAGMENTS;
- atomic_set(&bat_priv->packet_size_max, min_mtu);
-
- /* with fragmentation enabled we can fragment external packets easily */
- min_mtu = min_t(int, min_mtu, ETH_DATA_LEN);
out:
- return min_mtu - batadv_max_header_len();
+ /* report to the other components the maximum amount of bytes that
+ * batman-adv can send over the wire (without considering the payload
+ * overhead). For example, this value is used by TT to compute the
+ * maximum local table table size
+ */
+ atomic_set(&bat_priv->packet_size_max, min_mtu);
+
+ /* the real soft-interface MTU is computed by removing the payload
+ * overhead from the maximum amount of bytes that was just computed.
+ *
+ * However batman-adv does not support MTUs bigger than ETH_DATA_LEN
+ */
+ return min_t(int, min_mtu - batadv_max_header_len(), ETH_DATA_LEN);
}
/* adjusts the MTU if a new interface with a smaller MTU appeared. */
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 6df12a2e3605..853941629dc1 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -458,6 +458,42 @@ out:
}
/**
+ * batadv_neigh_node_get - retrieve a neighbour from the list
+ * @orig_node: originator which the neighbour belongs to
+ * @hard_iface: the interface where this neighbour is connected to
+ * @addr: the address of the neighbour
+ *
+ * Looks for and possibly returns a neighbour belonging to this originator list
+ * which is connected through the provided hard interface.
+ * Returns NULL if the neighbour is not found.
+ */
+struct batadv_neigh_node *
+batadv_neigh_node_get(const struct batadv_orig_node *orig_node,
+ const struct batadv_hard_iface *hard_iface,
+ const uint8_t *addr)
+{
+ struct batadv_neigh_node *tmp_neigh_node, *res = NULL;
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tmp_neigh_node, &orig_node->neigh_list, list) {
+ if (!batadv_compare_eth(tmp_neigh_node->addr, addr))
+ continue;
+
+ if (tmp_neigh_node->if_incoming != hard_iface)
+ continue;
+
+ if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
+ continue;
+
+ res = tmp_neigh_node;
+ break;
+ }
+ rcu_read_unlock();
+
+ return res;
+}
+
+/**
* batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object
* @rcu: rcu pointer of the orig_ifinfo object
*/
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index 37be290f63f6..db3a9ed734cb 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -29,6 +29,10 @@ void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node);
struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
const uint8_t *addr);
struct batadv_neigh_node *
+batadv_neigh_node_get(const struct batadv_orig_node *orig_node,
+ const struct batadv_hard_iface *hard_iface,
+ const uint8_t *addr);
+struct batadv_neigh_node *
batadv_neigh_node_new(struct batadv_hard_iface *hard_iface,
const uint8_t *neigh_addr,
struct batadv_orig_node *orig_node);
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 1ed9f7c9ecea..a953d5b196a3 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -688,7 +688,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
int is_old_ttvn;
/* check if there is enough data before accessing it */
- if (pskb_may_pull(skb, hdr_len + ETH_HLEN) < 0)
+ if (!pskb_may_pull(skb, hdr_len + ETH_HLEN))
return 0;
/* create a copy of the skb (in case of for re-routing) to modify it. */
@@ -918,6 +918,8 @@ int batadv_recv_unicast_tvlv(struct sk_buff *skb,
if (ret != NET_RX_SUCCESS)
ret = batadv_route_unicast_packet(skb, recv_if);
+ else
+ consume_skb(skb);
return ret;
}
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index 579f5f00a385..843febd1e519 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -254,9 +254,9 @@ static int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
unsigned short vid)
{
- struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
+ struct ethhdr *ethhdr;
struct batadv_unicast_packet *unicast_packet;
- int ret = NET_XMIT_DROP;
+ int ret = NET_XMIT_DROP, hdr_size;
if (!orig_node)
goto out;
@@ -265,12 +265,16 @@ static int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
case BATADV_UNICAST:
if (!batadv_send_skb_prepare_unicast(skb, orig_node))
goto out;
+
+ hdr_size = sizeof(*unicast_packet);
break;
case BATADV_UNICAST_4ADDR:
if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, skb,
orig_node,
packet_subtype))
goto out;
+
+ hdr_size = sizeof(struct batadv_unicast_4addr_packet);
break;
default:
/* this function supports UNICAST and UNICAST_4ADDR only. It
@@ -279,6 +283,7 @@ static int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
goto out;
}
+ ethhdr = (struct ethhdr *)(skb->data + hdr_size);
unicast_packet = (struct batadv_unicast_packet *)skb->data;
/* inform the destination node that we are still missing a correct route
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index b6071f675a3e..959dde721c46 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -1975,6 +1975,7 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
struct hlist_head *head;
uint32_t i, crc_tmp, crc = 0;
uint8_t flags;
+ __be16 tmp_vid;
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
@@ -2011,8 +2012,11 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
orig_node))
continue;
- crc_tmp = crc32c(0, &tt_common->vid,
- sizeof(tt_common->vid));
+ /* use network order to read the VID: this ensures that
+ * every node reads the bytes in the same order.
+ */
+ tmp_vid = htons(tt_common->vid);
+ crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
/* compute the CRC on flags that have to be kept in sync
* among nodes
@@ -2046,6 +2050,7 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv,
struct hlist_head *head;
uint32_t i, crc_tmp, crc = 0;
uint8_t flags;
+ __be16 tmp_vid;
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
@@ -2064,8 +2069,11 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv,
if (tt_common->flags & BATADV_TT_CLIENT_NEW)
continue;
- crc_tmp = crc32c(0, &tt_common->vid,
- sizeof(tt_common->vid));
+ /* use network order to read the VID: this ensures that
+ * every node reads the bytes in the same order.
+ */
+ tmp_vid = htons(tt_common->vid);
+ crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
/* compute the CRC on flags that have to be kept in sync
* among nodes
@@ -2262,6 +2270,7 @@ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node,
{
struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp;
struct batadv_orig_node_vlan *vlan;
+ uint32_t crc;
int i;
/* check if each received CRC matches the locally stored one */
@@ -2281,7 +2290,10 @@ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node,
if (!vlan)
return false;
- if (vlan->tt.crc != ntohl(tt_vlan_tmp->crc))
+ crc = vlan->tt.crc;
+ batadv_orig_node_vlan_free_ref(vlan);
+
+ if (crc != ntohl(tt_vlan_tmp->crc))
return false;
}
@@ -3218,7 +3230,6 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
spin_lock_bh(&orig_node->tt_lock);
- tt_change = (struct batadv_tvlv_tt_change *)tt_buff;
batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
ttvn, tt_change);
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 292e619db896..d9fb93451442 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -430,6 +430,16 @@ static void hidp_del_timer(struct hidp_session *session)
del_timer(&session->timer);
}
+static void hidp_process_report(struct hidp_session *session,
+ int type, const u8 *data, int len, int intr)
+{
+ if (len > HID_MAX_BUFFER_SIZE)
+ len = HID_MAX_BUFFER_SIZE;
+
+ memcpy(session->input_buf, data, len);
+ hid_input_report(session->hid, type, session->input_buf, len, intr);
+}
+
static void hidp_process_handshake(struct hidp_session *session,
unsigned char param)
{
@@ -502,7 +512,8 @@ static int hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
hidp_input_report(session, skb);
if (session->hid)
- hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
+ hidp_process_report(session, HID_INPUT_REPORT,
+ skb->data, skb->len, 0);
break;
case HIDP_DATA_RTYPE_OTHER:
@@ -584,7 +595,8 @@ static void hidp_recv_intr_frame(struct hidp_session *session,
hidp_input_report(session, skb);
if (session->hid) {
- hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
+ hidp_process_report(session, HID_INPUT_REPORT,
+ skb->data, skb->len, 1);
BT_DBG("report len %d", skb->len);
}
} else {
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index ab5241400cf7..8798492a6e99 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -24,6 +24,7 @@
#define __HIDP_H
#include <linux/types.h>
+#include <linux/hid.h>
#include <linux/kref.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/l2cap.h>
@@ -179,6 +180,9 @@ struct hidp_session {
/* Used in hidp_output_raw_report() */
int output_report_success; /* boolean */
+
+ /* temporary input buffer */
+ u8 input_buf[HID_MAX_BUFFER_SIZE];
};
/* HIDP init defines */
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 63f0455c0bc3..8fe8b71b487a 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -49,14 +49,14 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
brstats->tx_bytes += skb->len;
u64_stats_update_end(&brstats->syncp);
- if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
- goto out;
-
BR_INPUT_SKB_CB(skb)->brdev = dev;
skb_reset_mac_header(skb);
skb_pull(skb, ETH_HLEN);
+ if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
+ goto out;
+
if (is_broadcast_ether_addr(dest))
br_flood_deliver(br, skb, false);
else if (is_multicast_ether_addr(dest)) {
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 28d544627422..d0cca3c65f01 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -29,6 +29,7 @@ static int br_pass_frame_up(struct sk_buff *skb)
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
struct net_bridge *br = netdev_priv(brdev);
struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
+ struct net_port_vlans *pv;
u64_stats_update_begin(&brstats->syncp);
brstats->rx_packets++;
@@ -39,18 +40,18 @@ static int br_pass_frame_up(struct sk_buff *skb)
* packet is allowed except in promisc modue when someone
* may be running packet capture.
*/
+ pv = br_get_vlan_info(br);
if (!(brdev->flags & IFF_PROMISC) &&
- !br_allowed_egress(br, br_get_vlan_info(br), skb)) {
+ !br_allowed_egress(br, pv, skb)) {
kfree_skb(skb);
return NET_RX_DROP;
}
- skb = br_handle_vlan(br, br_get_vlan_info(br), skb);
- if (!skb)
- return NET_RX_DROP;
-
indev = skb->dev;
skb->dev = brdev;
+ skb = br_handle_vlan(br, pv, skb);
+ if (!skb)
+ return NET_RX_DROP;
return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
netif_receive_skb);
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index ef66365b7354..93067ecdb9a2 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1127,9 +1127,10 @@ static void br_multicast_query_received(struct net_bridge *br,
struct net_bridge_port *port,
struct bridge_mcast_querier *querier,
int saddr,
+ bool is_general_query,
unsigned long max_delay)
{
- if (saddr)
+ if (saddr && is_general_query)
br_multicast_update_querier_timer(br, querier, max_delay);
else if (timer_pending(&querier->timer))
return;
@@ -1181,8 +1182,16 @@ static int br_ip4_multicast_query(struct net_bridge *br,
IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
}
+ /* RFC2236+RFC3376 (IGMPv2+IGMPv3) require the multicast link layer
+ * all-systems destination addresses (224.0.0.1) for general queries
+ */
+ if (!group && iph->daddr != htonl(INADDR_ALLHOSTS_GROUP)) {
+ err = -EINVAL;
+ goto out;
+ }
+
br_multicast_query_received(br, port, &br->ip4_querier, !!iph->saddr,
- max_delay);
+ !group, max_delay);
if (!group)
goto out;
@@ -1228,6 +1237,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
unsigned long max_delay;
unsigned long now = jiffies;
const struct in6_addr *group = NULL;
+ bool is_general_query;
int err = 0;
spin_lock(&br->multicast_lock);
@@ -1235,6 +1245,12 @@ static int br_ip6_multicast_query(struct net_bridge *br,
(port && port->state == BR_STATE_DISABLED))
goto out;
+ /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
+ if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
+ err = -EINVAL;
+ goto out;
+ }
+
if (skb->len == sizeof(*mld)) {
if (!pskb_may_pull(skb, sizeof(*mld))) {
err = -EINVAL;
@@ -1256,8 +1272,19 @@ static int br_ip6_multicast_query(struct net_bridge *br,
max_delay = max(msecs_to_jiffies(mldv2_mrc(mld2q)), 1UL);
}
+ is_general_query = group && ipv6_addr_any(group);
+
+ /* RFC2710+RFC3810 (MLDv1+MLDv2) require the multicast link layer
+ * all-nodes destination address (ff02::1) for general queries
+ */
+ if (is_general_query && !ipv6_addr_is_ll_all_nodes(&ip6h->daddr)) {
+ err = -EINVAL;
+ goto out;
+ }
+
br_multicast_query_received(br, port, &br->ip6_querier,
- !ipv6_addr_any(&ip6h->saddr), max_delay);
+ !ipv6_addr_any(&ip6h->saddr),
+ is_general_query, max_delay);
if (!group)
goto out;
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 8249ca764c79..f23c74b3a953 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -119,22 +119,6 @@ static void __vlan_flush(struct net_port_vlans *v)
kfree_rcu(v, rcu);
}
-/* Strip the tag from the packet. Will return skb with tci set 0. */
-static struct sk_buff *br_vlan_untag(struct sk_buff *skb)
-{
- if (skb->protocol != htons(ETH_P_8021Q)) {
- skb->vlan_tci = 0;
- return skb;
- }
-
- skb->vlan_tci = 0;
- skb = vlan_untag(skb);
- if (skb)
- skb->vlan_tci = 0;
-
- return skb;
-}
-
struct sk_buff *br_handle_vlan(struct net_bridge *br,
const struct net_port_vlans *pv,
struct sk_buff *skb)
@@ -144,13 +128,27 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
if (!br->vlan_enabled)
goto out;
+ /* Vlan filter table must be configured at this point. The
+ * only exception is the bridge is set in promisc mode and the
+ * packet is destined for the bridge device. In this case
+ * pass the packet as is.
+ */
+ if (!pv) {
+ if ((br->dev->flags & IFF_PROMISC) && skb->dev == br->dev) {
+ goto out;
+ } else {
+ kfree_skb(skb);
+ return NULL;
+ }
+ }
+
/* At this point, we know that the frame was filtered and contains
* a valid vlan id. If the vlan id is set in the untagged bitmap,
* send untagged; otherwise, send tagged.
*/
br_vlan_get_tag(skb, &vid);
if (test_bit(vid, pv->untagged_bitmap))
- skb = br_vlan_untag(skb);
+ skb->vlan_tci = 0;
out:
return skb;
@@ -174,6 +172,18 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
if (!v)
return false;
+ /* If vlan tx offload is disabled on bridge device and frame was
+ * sent from vlan device on the bridge device, it does not have
+ * HW accelerated vlan tag.
+ */
+ if (unlikely(!vlan_tx_tag_present(skb) &&
+ (skb->protocol == htons(ETH_P_8021Q) ||
+ skb->protocol == htons(ETH_P_8021AD)))) {
+ skb = vlan_untag(skb);
+ if (unlikely(!skb))
+ return false;
+ }
+
err = br_vlan_get_tag(skb, vid);
if (!*vid) {
u16 pvid = br_get_pvid(v);
diff --git a/net/can/raw.c b/net/can/raw.c
index 8be757cca2ec..081e81fd017f 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -121,13 +121,9 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
if (!ro->recv_own_msgs && oskb->sk == sk)
return;
- /* do not pass frames with DLC > 8 to a legacy socket */
- if (!ro->fd_frames) {
- struct canfd_frame *cfd = (struct canfd_frame *)oskb->data;
-
- if (unlikely(cfd->len > CAN_MAX_DLEN))
- return;
- }
+ /* do not pass non-CAN2.0 frames to a legacy socket */
+ if (!ro->fd_frames && oskb->len != CAN_MTU)
+ return;
/* clone the given skb to be able to enqueue it into the rcv queue */
skb = skb_clone(oskb, GFP_ATOMIC);
@@ -738,9 +734,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size, int flags)
{
struct sock *sk = sock->sk;
- struct raw_sock *ro = raw_sk(sk);
struct sk_buff *skb;
- int rxmtu;
int err = 0;
int noblock;
@@ -751,20 +745,10 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
if (!skb)
return err;
- /*
- * when serving a legacy socket the DLC <= 8 is already checked inside
- * raw_rcv(). Now check if we need to pass a canfd_frame to a legacy
- * socket and cut the possible CANFD_MTU/CAN_MTU length to CAN_MTU
- */
- if (!ro->fd_frames)
- rxmtu = CAN_MTU;
- else
- rxmtu = skb->len;
-
- if (size < rxmtu)
+ if (size < skb->len)
msg->msg_flags |= MSG_TRUNC;
else
- size = rxmtu;
+ size = skb->len;
err = memcpy_toiovec(msg->msg_iov, skb->data, size);
if (err < 0) {
diff --git a/net/compat.c b/net/compat.c
index f50161fb812e..9a76eaf63184 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -384,8 +384,8 @@ static int compat_sock_setsockopt(struct socket *sock, int level, int optname,
return sock_setsockopt(sock, level, optname, optval, optlen);
}
-asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
- char __user *optval, unsigned int optlen)
+COMPAT_SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
+ char __user *, optval, unsigned int, optlen)
{
int err;
struct socket *sock = sockfd_lookup(fd, &err);
@@ -504,8 +504,8 @@ int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *usersta
}
EXPORT_SYMBOL(compat_sock_get_timestampns);
-asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
- char __user *optval, int __user *optlen)
+COMPAT_SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
+ char __user *, optval, int __user *, optlen)
{
int err;
struct socket *sock = sockfd_lookup(fd, &err);
@@ -735,15 +735,15 @@ static unsigned char nas[21] = {
};
#undef AL
-asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
+COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
{
if (flags & MSG_CMSG_COMPAT)
return -EINVAL;
return __sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
}
-asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
- unsigned int vlen, unsigned int flags)
+COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
+ unsigned int, vlen, unsigned int, flags)
{
if (flags & MSG_CMSG_COMPAT)
return -EINVAL;
@@ -751,28 +751,28 @@ asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
flags | MSG_CMSG_COMPAT);
}
-asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
+COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
{
if (flags & MSG_CMSG_COMPAT)
return -EINVAL;
return __sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
}
-asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned int flags)
+COMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags)
{
return sys_recv(fd, buf, len, flags | MSG_CMSG_COMPAT);
}
-asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
- unsigned int flags, struct sockaddr __user *addr,
- int __user *addrlen)
+COMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, buf, compat_size_t, len,
+ unsigned int, flags, struct sockaddr __user *, addr,
+ int __user *, addrlen)
{
return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen);
}
-asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
- unsigned int vlen, unsigned int flags,
- struct compat_timespec __user *timeout)
+COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
+ unsigned int, vlen, unsigned int, flags,
+ struct compat_timespec __user *, timeout)
{
int datagrams;
struct timespec ktspec;
@@ -795,7 +795,7 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
return datagrams;
}
-asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
+COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
{
int ret;
u32 a[6];
diff --git a/net/core/dev.c b/net/core/dev.c
index 9971ea1adc10..4a91591b30a6 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2286,7 +2286,7 @@ out:
}
EXPORT_SYMBOL(skb_checksum_help);
-__be16 skb_network_protocol(struct sk_buff *skb)
+__be16 skb_network_protocol(struct sk_buff *skb, int *depth)
{
__be16 type = skb->protocol;
int vlan_depth = ETH_HLEN;
@@ -2313,6 +2313,8 @@ __be16 skb_network_protocol(struct sk_buff *skb)
vlan_depth += VLAN_HLEN;
}
+ *depth = vlan_depth;
+
return type;
}
@@ -2326,12 +2328,13 @@ struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
{
struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
struct packet_offload *ptype;
- __be16 type = skb_network_protocol(skb);
+ int vlan_depth = skb->mac_len;
+ __be16 type = skb_network_protocol(skb, &vlan_depth);
if (unlikely(!type))
return ERR_PTR(-EINVAL);
- __skb_pull(skb, skb->mac_len);
+ __skb_pull(skb, vlan_depth);
rcu_read_lock();
list_for_each_entry_rcu(ptype, &offload_base, list) {
@@ -2420,7 +2423,7 @@ EXPORT_SYMBOL(netdev_rx_csum_fault);
* 2. No high memory really exists on this machine.
*/
-static int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
+static int illegal_highdma(const struct net_device *dev, struct sk_buff *skb)
{
#ifdef CONFIG_HIGHMEM
int i;
@@ -2495,34 +2498,38 @@ static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
}
static netdev_features_t harmonize_features(struct sk_buff *skb,
- netdev_features_t features)
+ const struct net_device *dev,
+ netdev_features_t features)
{
+ int tmp;
+
if (skb->ip_summed != CHECKSUM_NONE &&
- !can_checksum_protocol(features, skb_network_protocol(skb))) {
+ !can_checksum_protocol(features, skb_network_protocol(skb, &tmp))) {
features &= ~NETIF_F_ALL_CSUM;
- } else if (illegal_highdma(skb->dev, skb)) {
+ } else if (illegal_highdma(dev, skb)) {
features &= ~NETIF_F_SG;
}
return features;
}
-netdev_features_t netif_skb_features(struct sk_buff *skb)
+netdev_features_t netif_skb_dev_features(struct sk_buff *skb,
+ const struct net_device *dev)
{
__be16 protocol = skb->protocol;
- netdev_features_t features = skb->dev->features;
+ netdev_features_t features = dev->features;
- if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs)
+ if (skb_shinfo(skb)->gso_segs > dev->gso_max_segs)
features &= ~NETIF_F_GSO_MASK;
if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) {
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
protocol = veh->h_vlan_encapsulated_proto;
} else if (!vlan_tx_tag_present(skb)) {
- return harmonize_features(skb, features);
+ return harmonize_features(skb, dev, features);
}
- features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX |
+ features &= (dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_STAG_TX);
if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD))
@@ -2530,9 +2537,9 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_STAG_TX;
- return harmonize_features(skb, features);
+ return harmonize_features(skb, dev, features);
}
-EXPORT_SYMBOL(netif_skb_features);
+EXPORT_SYMBOL(netif_skb_dev_features);
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
struct netdev_queue *txq)
@@ -4128,8 +4135,8 @@ static void net_rps_action_and_irq_enable(struct softnet_data *sd)
struct softnet_data *next = remsd->rps_ipi_next;
if (cpu_online(remsd->cpu))
- __smp_call_function_single(remsd->cpu,
- &remsd->csd, 0);
+ smp_call_function_single_async(remsd->cpu,
+ &remsd->csd);
remsd = next;
}
} else
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 87577d447554..e29e810663d7 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -323,17 +323,6 @@ u32 __skb_get_poff(const struct sk_buff *skb)
return poff;
}
-static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index)
-{
- if (unlikely(queue_index >= dev->real_num_tx_queues)) {
- net_warn_ratelimited("%s selects TX queue %d, but real number of TX queues is %d\n",
- dev->name, queue_index,
- dev->real_num_tx_queues);
- return 0;
- }
- return queue_index;
-}
-
static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
{
#ifdef CONFIG_XPS
@@ -372,7 +361,7 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
#endif
}
-u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb)
+static u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb)
{
struct sock *sk = skb->sk;
int queue_index = sk_tx_queue_get(sk);
@@ -392,7 +381,6 @@ u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb)
return queue_index;
}
-EXPORT_SYMBOL(__netdev_pick_tx);
struct netdev_queue *netdev_pick_tx(struct net_device *dev,
struct sk_buff *skb,
@@ -403,13 +391,13 @@ struct netdev_queue *netdev_pick_tx(struct net_device *dev,
if (dev->real_num_tx_queues != 1) {
const struct net_device_ops *ops = dev->netdev_ops;
if (ops->ndo_select_queue)
- queue_index = ops->ndo_select_queue(dev, skb,
- accel_priv);
+ queue_index = ops->ndo_select_queue(dev, skb, accel_priv,
+ __netdev_pick_tx);
else
queue_index = __netdev_pick_tx(dev, skb);
if (!accel_priv)
- queue_index = dev_cap_txqueue(dev, queue_index);
+ queue_index = netdev_cap_txqueue(dev, queue_index);
}
skb_set_queue_mapping(skb, queue_index);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index b9e9e0d38672..e16129019c66 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -766,9 +766,6 @@ static void neigh_periodic_work(struct work_struct *work)
nht = rcu_dereference_protected(tbl->nht,
lockdep_is_held(&tbl->lock));
- if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
- goto out;
-
/*
* periodically recompute ReachableTime from random function
*/
@@ -781,6 +778,9 @@ static void neigh_periodic_work(struct work_struct *work)
neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
}
+ if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
+ goto out;
+
for (i = 0 ; i < (1 << nht->hash_shift); i++) {
np = &nht->hash_buckets[i];
@@ -3046,7 +3046,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
if (!t)
goto err;
- for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) {
+ for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
t->neigh_vars[i].data += (long) p;
t->neigh_vars[i].extra1 = dev;
t->neigh_vars[i].extra2 = p;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index a664f7829a6d..df9e6b1a9759 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -742,7 +742,7 @@ static bool pkt_is_ns(struct sk_buff *skb)
struct nd_msg *msg;
struct ipv6hdr *hdr;
- if (skb->protocol != htons(ETH_P_ARP))
+ if (skb->protocol != htons(ETH_P_IPV6))
return false;
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct nd_msg)))
return false;
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 048dc8d183aa..120eecc0f5a4 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1963,16 +1963,21 @@ replay:
dev->ifindex = ifm->ifi_index;
- if (ops->newlink)
+ if (ops->newlink) {
err = ops->newlink(net, dev, tb, data);
- else
+ /* Drivers should call free_netdev() in ->destructor
+ * and unregister it on failure so that device could be
+ * finally freed in rtnl_unlock.
+ */
+ if (err < 0)
+ goto out;
+ } else {
err = register_netdevice(dev);
-
- if (err < 0) {
- free_netdev(dev);
- goto out;
+ if (err < 0) {
+ free_netdev(dev);
+ goto out;
+ }
}
-
err = rtnl_configure_link(dev, ifm);
if (err < 0)
unregister_netdevice(dev);
@@ -2116,12 +2121,13 @@ EXPORT_SYMBOL(rtmsg_ifinfo);
static int nlmsg_populate_fdb_fill(struct sk_buff *skb,
struct net_device *dev,
u8 *addr, u32 pid, u32 seq,
- int type, unsigned int flags)
+ int type, unsigned int flags,
+ int nlflags)
{
struct nlmsghdr *nlh;
struct ndmsg *ndm;
- nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), NLM_F_MULTI);
+ nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), nlflags);
if (!nlh)
return -EMSGSIZE;
@@ -2159,7 +2165,7 @@ static void rtnl_fdb_notify(struct net_device *dev, u8 *addr, int type)
if (!skb)
goto errout;
- err = nlmsg_populate_fdb_fill(skb, dev, addr, 0, 0, type, NTF_SELF);
+ err = nlmsg_populate_fdb_fill(skb, dev, addr, 0, 0, type, NTF_SELF, 0);
if (err < 0) {
kfree_skb(skb);
goto errout;
@@ -2384,7 +2390,8 @@ static int nlmsg_populate_fdb(struct sk_buff *skb,
err = nlmsg_populate_fdb_fill(skb, dev, ha->addr,
portid, seq,
- RTM_NEWNEIGH, NTF_SELF);
+ RTM_NEWNEIGH, NTF_SELF,
+ NLM_F_MULTI);
if (err < 0)
return err;
skip:
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 5976ef0846bd..90b96a11b974 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -707,9 +707,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->mark = old->mark;
new->skb_iif = old->skb_iif;
__nf_copy(new, old);
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
- new->nf_trace = old->nf_trace;
-#endif
#ifdef CONFIG_NET_SCHED
new->tc_index = old->tc_index;
#ifdef CONFIG_NET_CLS_ACT
@@ -2130,25 +2127,31 @@ EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);
*
* The `hlen` as calculated by skb_zerocopy_headlen() specifies the
* headroom in the `to` buffer.
+ *
+ * Return value:
+ * 0: everything is OK
+ * -ENOMEM: couldn't orphan frags of @from due to lack of memory
+ * -EFAULT: skb_copy_bits() found some problem with skb geometry
*/
-void
-skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
+int
+skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
{
int i, j = 0;
int plen = 0; /* length of skb->head fragment */
+ int ret;
struct page *page;
unsigned int offset;
BUG_ON(!from->head_frag && !hlen);
/* dont bother with small payloads */
- if (len <= skb_tailroom(to)) {
- skb_copy_bits(from, 0, skb_put(to, len), len);
- return;
- }
+ if (len <= skb_tailroom(to))
+ return skb_copy_bits(from, 0, skb_put(to, len), len);
if (hlen) {
- skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
+ ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
+ if (unlikely(ret))
+ return ret;
len -= hlen;
} else {
plen = min_t(int, skb_headlen(from), len);
@@ -2166,6 +2169,11 @@ skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
to->len += len + plen;
to->data_len += len + plen;
+ if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) {
+ skb_tx_error(from);
+ return -ENOMEM;
+ }
+
for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
if (!len)
break;
@@ -2176,6 +2184,8 @@ skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
j++;
}
skb_shinfo(to)->nr_frags = j;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(skb_zerocopy);
@@ -2841,81 +2851,85 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum);
/**
* skb_segment - Perform protocol segmentation on skb.
- * @skb: buffer to segment
+ * @head_skb: buffer to segment
* @features: features for the output path (see dev->features)
*
* This function performs segmentation on the given skb. It returns
* a pointer to the first in a list of new skbs for the segments.
* In case of error it returns ERR_PTR(err).
*/
-struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
+struct sk_buff *skb_segment(struct sk_buff *head_skb,
+ netdev_features_t features)
{
struct sk_buff *segs = NULL;
struct sk_buff *tail = NULL;
- struct sk_buff *fskb = skb_shinfo(skb)->frag_list;
- skb_frag_t *skb_frag = skb_shinfo(skb)->frags;
- unsigned int mss = skb_shinfo(skb)->gso_size;
- unsigned int doffset = skb->data - skb_mac_header(skb);
+ struct sk_buff *list_skb = skb_shinfo(head_skb)->frag_list;
+ skb_frag_t *frag = skb_shinfo(head_skb)->frags;
+ unsigned int mss = skb_shinfo(head_skb)->gso_size;
+ unsigned int doffset = head_skb->data - skb_mac_header(head_skb);
+ struct sk_buff *frag_skb = head_skb;
unsigned int offset = doffset;
- unsigned int tnl_hlen = skb_tnl_header_len(skb);
+ unsigned int tnl_hlen = skb_tnl_header_len(head_skb);
unsigned int headroom;
unsigned int len;
__be16 proto;
bool csum;
int sg = !!(features & NETIF_F_SG);
- int nfrags = skb_shinfo(skb)->nr_frags;
+ int nfrags = skb_shinfo(head_skb)->nr_frags;
int err = -ENOMEM;
int i = 0;
int pos;
+ int dummy;
- proto = skb_network_protocol(skb);
+ proto = skb_network_protocol(head_skb, &dummy);
if (unlikely(!proto))
return ERR_PTR(-EINVAL);
csum = !!can_checksum_protocol(features, proto);
- __skb_push(skb, doffset);
- headroom = skb_headroom(skb);
- pos = skb_headlen(skb);
+ __skb_push(head_skb, doffset);
+ headroom = skb_headroom(head_skb);
+ pos = skb_headlen(head_skb);
do {
struct sk_buff *nskb;
- skb_frag_t *frag;
+ skb_frag_t *nskb_frag;
int hsize;
int size;
- len = skb->len - offset;
+ len = head_skb->len - offset;
if (len > mss)
len = mss;
- hsize = skb_headlen(skb) - offset;
+ hsize = skb_headlen(head_skb) - offset;
if (hsize < 0)
hsize = 0;
if (hsize > len || !sg)
hsize = len;
- if (!hsize && i >= nfrags && skb_headlen(fskb) &&
- (skb_headlen(fskb) == len || sg)) {
- BUG_ON(skb_headlen(fskb) > len);
+ if (!hsize && i >= nfrags && skb_headlen(list_skb) &&
+ (skb_headlen(list_skb) == len || sg)) {
+ BUG_ON(skb_headlen(list_skb) > len);
i = 0;
- nfrags = skb_shinfo(fskb)->nr_frags;
- skb_frag = skb_shinfo(fskb)->frags;
- pos += skb_headlen(fskb);
+ nfrags = skb_shinfo(list_skb)->nr_frags;
+ frag = skb_shinfo(list_skb)->frags;
+ frag_skb = list_skb;
+ pos += skb_headlen(list_skb);
while (pos < offset + len) {
BUG_ON(i >= nfrags);
- size = skb_frag_size(skb_frag);
+ size = skb_frag_size(frag);
if (pos + size > offset + len)
break;
i++;
pos += size;
- skb_frag++;
+ frag++;
}
- nskb = skb_clone(fskb, GFP_ATOMIC);
- fskb = fskb->next;
+ nskb = skb_clone(list_skb, GFP_ATOMIC);
+ list_skb = list_skb->next;
if (unlikely(!nskb))
goto err;
@@ -2936,7 +2950,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
__skb_push(nskb, doffset);
} else {
nskb = __alloc_skb(hsize + doffset + headroom,
- GFP_ATOMIC, skb_alloc_rx_flag(skb),
+ GFP_ATOMIC, skb_alloc_rx_flag(head_skb),
NUMA_NO_NODE);
if (unlikely(!nskb))
@@ -2952,12 +2966,12 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
segs = nskb;
tail = nskb;
- __copy_skb_header(nskb, skb);
- nskb->mac_len = skb->mac_len;
+ __copy_skb_header(nskb, head_skb);
+ nskb->mac_len = head_skb->mac_len;
skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom);
- skb_copy_from_linear_data_offset(skb, -tnl_hlen,
+ skb_copy_from_linear_data_offset(head_skb, -tnl_hlen,
nskb->data - tnl_hlen,
doffset + tnl_hlen);
@@ -2966,30 +2980,32 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
if (!sg) {
nskb->ip_summed = CHECKSUM_NONE;
- nskb->csum = skb_copy_and_csum_bits(skb, offset,
+ nskb->csum = skb_copy_and_csum_bits(head_skb, offset,
skb_put(nskb, len),
len, 0);
continue;
}
- frag = skb_shinfo(nskb)->frags;
+ nskb_frag = skb_shinfo(nskb)->frags;
- skb_copy_from_linear_data_offset(skb, offset,
+ skb_copy_from_linear_data_offset(head_skb, offset,
skb_put(nskb, hsize), hsize);
- skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG;
+ skb_shinfo(nskb)->tx_flags = skb_shinfo(head_skb)->tx_flags &
+ SKBTX_SHARED_FRAG;
while (pos < offset + len) {
if (i >= nfrags) {
- BUG_ON(skb_headlen(fskb));
+ BUG_ON(skb_headlen(list_skb));
i = 0;
- nfrags = skb_shinfo(fskb)->nr_frags;
- skb_frag = skb_shinfo(fskb)->frags;
+ nfrags = skb_shinfo(list_skb)->nr_frags;
+ frag = skb_shinfo(list_skb)->frags;
+ frag_skb = list_skb;
BUG_ON(!nfrags);
- fskb = fskb->next;
+ list_skb = list_skb->next;
}
if (unlikely(skb_shinfo(nskb)->nr_frags >=
@@ -3000,27 +3016,30 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
goto err;
}
- *frag = *skb_frag;
- __skb_frag_ref(frag);
- size = skb_frag_size(frag);
+ if (unlikely(skb_orphan_frags(frag_skb, GFP_ATOMIC)))
+ goto err;
+
+ *nskb_frag = *frag;
+ __skb_frag_ref(nskb_frag);
+ size = skb_frag_size(nskb_frag);
if (pos < offset) {
- frag->page_offset += offset - pos;
- skb_frag_size_sub(frag, offset - pos);
+ nskb_frag->page_offset += offset - pos;
+ skb_frag_size_sub(nskb_frag, offset - pos);
}
skb_shinfo(nskb)->nr_frags++;
if (pos + size <= offset + len) {
i++;
- skb_frag++;
+ frag++;
pos += size;
} else {
- skb_frag_size_sub(frag, pos + size - (offset + len));
+ skb_frag_size_sub(nskb_frag, pos + size - (offset + len));
goto skip_fraglist;
}
- frag++;
+ nskb_frag++;
}
skip_fraglist:
@@ -3034,7 +3053,7 @@ perform_csum_check:
nskb->len - doffset, 0);
nskb->ip_summed = CHECKSUM_NONE;
}
- } while ((offset += len) < skb->len);
+ } while ((offset += len) < head_skb->len);
return segs;
diff --git a/net/core/sock.c b/net/core/sock.c
index 5b6a9431b017..c0fc6bdad1e3 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -2357,10 +2357,13 @@ void release_sock(struct sock *sk)
if (sk->sk_backlog.tail)
__release_sock(sk);
+ /* Warning : release_cb() might need to release sk ownership,
+ * ie call sock_release_ownership(sk) before us.
+ */
if (sk->sk_prot->release_cb)
sk->sk_prot->release_cb(sk);
- sk->sk_lock.owned = 0;
+ sock_release_ownership(sk);
if (waitqueue_active(&sk->sk_lock.wq))
wake_up(&sk->sk_lock.wq);
spin_unlock_bh(&sk->sk_lock.slock);
diff --git a/net/dccp/ccids/lib/tfrc.c b/net/dccp/ccids/lib/tfrc.c
index c073b81a1f3e..62b5828acde0 100644
--- a/net/dccp/ccids/lib/tfrc.c
+++ b/net/dccp/ccids/lib/tfrc.c
@@ -8,7 +8,7 @@
#include "tfrc.h"
#ifdef CONFIG_IP_DCCP_TFRC_DEBUG
-static bool tfrc_debug;
+bool tfrc_debug;
module_param(tfrc_debug, bool, 0644);
MODULE_PARM_DESC(tfrc_debug, "Enable TFRC debug messages");
#endif
diff --git a/net/dccp/ccids/lib/tfrc.h b/net/dccp/ccids/lib/tfrc.h
index a3d8f7c76ae0..40ee7d62b652 100644
--- a/net/dccp/ccids/lib/tfrc.h
+++ b/net/dccp/ccids/lib/tfrc.h
@@ -21,6 +21,7 @@
#include "packet_history.h"
#ifdef CONFIG_IP_DCCP_TFRC_DEBUG
+extern bool tfrc_debug;
#define tfrc_pr_debug(format, a...) DCCP_PR_DEBUG(tfrc_debug, format, ##a)
#else
#define tfrc_pr_debug(format, a...)
diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c
index 327060c6c874..7ae0d7f6dbd0 100644
--- a/net/hsr/hsr_framereg.c
+++ b/net/hsr/hsr_framereg.c
@@ -297,7 +297,7 @@ static bool seq_nr_after(u16 a, u16 b)
void hsr_register_frame_in(struct node_entry *node, enum hsr_dev_idx dev_idx)
{
- if ((dev_idx < 0) || (dev_idx >= HSR_MAX_DEV)) {
+ if ((dev_idx < 0) || (dev_idx >= HSR_MAX_SLAVE)) {
WARN_ONCE(1, "%s: Invalid dev_idx (%d)\n", __func__, dev_idx);
return;
}
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index ecd2c3f245ce..19ab78aca547 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1296,8 +1296,11 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
segs = ERR_PTR(-EPROTONOSUPPORT);
- /* Note : following gso_segment() might change skb->encapsulation */
- udpfrag = !skb->encapsulation && proto == IPPROTO_UDP;
+ if (skb->encapsulation &&
+ skb_shinfo(skb)->gso_type & (SKB_GSO_SIT|SKB_GSO_IPIP))
+ udpfrag = proto == IPPROTO_UDP && encap;
+ else
+ udpfrag = proto == IPPROTO_UDP && !skb->encapsulation;
ops = rcu_dereference(inet_offloads[proto]);
if (likely(ops && ops->callbacks.gso_segment))
diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c
index 1863422fb7d5..250be7421ab3 100644
--- a/net/ipv4/gre_demux.c
+++ b/net/ipv4/gre_demux.c
@@ -182,6 +182,14 @@ static int gre_cisco_rcv(struct sk_buff *skb)
int i;
bool csum_err = false;
+#ifdef CONFIG_NET_IPGRE_BROADCAST
+ if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
+ /* Looped back packet, drop it! */
+ if (rt_is_output_route(skb_rtable(skb)))
+ goto drop;
+ }
+#endif
+
if (parse_gre_header(skb, &tpi, &csum_err) < 0)
goto drop;
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index bb075fc9a14f..3b01959bf4bb 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -208,7 +208,7 @@ int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force)
}
work = frag_mem_limit(nf) - nf->low_thresh;
- while (work > 0) {
+ while (work > 0 || force) {
spin_lock(&nf->lru_lock);
if (list_empty(&nf->lru_list)) {
@@ -278,9 +278,10 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
atomic_inc(&qp->refcnt);
hlist_add_head(&qp->list, &hb->chain);
+ inet_frag_lru_add(nf, qp);
spin_unlock(&hb->chain_lock);
read_unlock(&f->lock);
- inet_frag_lru_add(nf, qp);
+
return qp;
}
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index e9f1217a8afd..f3869c186d97 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -39,6 +39,71 @@
#include <net/route.h>
#include <net/xfrm.h>
+static bool ip_may_fragment(const struct sk_buff *skb)
+{
+ return unlikely((ip_hdr(skb)->frag_off & htons(IP_DF)) == 0) ||
+ !skb->local_df;
+}
+
+static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
+{
+ if (skb->len <= mtu || skb->local_df)
+ return false;
+
+ if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu)
+ return false;
+
+ return true;
+}
+
+static bool ip_gso_exceeds_dst_mtu(const struct sk_buff *skb)
+{
+ unsigned int mtu;
+
+ if (skb->local_df || !skb_is_gso(skb))
+ return false;
+
+ mtu = ip_dst_mtu_maybe_forward(skb_dst(skb), true);
+
+ /* if seglen > mtu, do software segmentation for IP fragmentation on
+ * output. DF bit cannot be set since ip_forward would have sent
+ * icmp error.
+ */
+ return skb_gso_network_seglen(skb) > mtu;
+}
+
+/* called if GSO skb needs to be fragmented on forward */
+static int ip_forward_finish_gso(struct sk_buff *skb)
+{
+ struct dst_entry *dst = skb_dst(skb);
+ netdev_features_t features;
+ struct sk_buff *segs;
+ int ret = 0;
+
+ features = netif_skb_dev_features(skb, dst->dev);
+ segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
+ if (IS_ERR(segs)) {
+ kfree_skb(skb);
+ return -ENOMEM;
+ }
+
+ consume_skb(skb);
+
+ do {
+ struct sk_buff *nskb = segs->next;
+ int err;
+
+ segs->next = NULL;
+ err = dst_output(segs);
+
+ if (err && ret == 0)
+ ret = err;
+ segs = nskb;
+ } while (segs);
+
+ return ret;
+}
+
static int ip_forward_finish(struct sk_buff *skb)
{
struct ip_options *opt = &(IPCB(skb)->opt);
@@ -49,6 +114,9 @@ static int ip_forward_finish(struct sk_buff *skb)
if (unlikely(opt->optlen))
ip_forward_options(skb);
+ if (ip_gso_exceeds_dst_mtu(skb))
+ return ip_forward_finish_gso(skb);
+
return dst_output(skb);
}
@@ -91,8 +159,7 @@ int ip_forward(struct sk_buff *skb)
IPCB(skb)->flags |= IPSKB_FORWARDED;
mtu = ip_dst_mtu_maybe_forward(&rt->dst, true);
- if (unlikely(skb->len > mtu && !skb_is_gso(skb) &&
- (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
+ if (!ip_may_fragment(skb) && ip_exceeds_mtu(skb, mtu)) {
IP_INC_STATS(dev_net(rt->dst.dev), IPSTATS_MIB_FRAGFAILS);
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
htonl(mtu));
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 8971780aec7c..73c6b63bba74 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -422,9 +422,6 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
to->tc_index = from->tc_index;
#endif
nf_copy(to, from);
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
- to->nf_trace = from->nf_trace;
-#endif
#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
to->ipvs_property = from->ipvs_property;
#endif
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 50228be5c17b..a82a22d8f77f 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -93,13 +93,14 @@ static void tunnel_dst_reset(struct ip_tunnel *t)
tunnel_dst_set(t, NULL);
}
-static void tunnel_dst_reset_all(struct ip_tunnel *t)
+void ip_tunnel_dst_reset_all(struct ip_tunnel *t)
{
int i;
for_each_possible_cpu(i)
__tunnel_dst_set(per_cpu_ptr(t->dst_cache, i), NULL);
}
+EXPORT_SYMBOL(ip_tunnel_dst_reset_all);
static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, u32 cookie)
{
@@ -119,52 +120,6 @@ static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, u32 cookie)
return (struct rtable *)dst;
}
-/* Often modified stats are per cpu, other are shared (netdev->stats) */
-struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *tot)
-{
- int i;
-
- for_each_possible_cpu(i) {
- const struct pcpu_sw_netstats *tstats =
- per_cpu_ptr(dev->tstats, i);
- u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
- unsigned int start;
-
- do {
- start = u64_stats_fetch_begin_bh(&tstats->syncp);
- rx_packets = tstats->rx_packets;
- tx_packets = tstats->tx_packets;
- rx_bytes = tstats->rx_bytes;
- tx_bytes = tstats->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
-
- tot->rx_packets += rx_packets;
- tot->tx_packets += tx_packets;
- tot->rx_bytes += rx_bytes;
- tot->tx_bytes += tx_bytes;
- }
-
- tot->multicast = dev->stats.multicast;
-
- tot->rx_crc_errors = dev->stats.rx_crc_errors;
- tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
- tot->rx_length_errors = dev->stats.rx_length_errors;
- tot->rx_frame_errors = dev->stats.rx_frame_errors;
- tot->rx_errors = dev->stats.rx_errors;
-
- tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
- tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
- tot->tx_dropped = dev->stats.tx_dropped;
- tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
- tot->tx_errors = dev->stats.tx_errors;
-
- tot->collisions = dev->stats.collisions;
-
- return tot;
-}
-EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64);
-
static bool ip_tunnel_key_match(const struct ip_tunnel_parm *p,
__be16 flags, __be32 key)
{
@@ -461,9 +416,6 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
#ifdef CONFIG_NET_IPGRE_BROADCAST
if (ipv4_is_multicast(iph->daddr)) {
- /* Looped back packet, drop it! */
- if (rt_is_output_route(skb_rtable(skb)))
- goto drop;
tunnel->dev->stats.multicast++;
skb->pkt_type = PACKET_BROADCAST;
}
@@ -759,7 +711,7 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn,
if (set_mtu)
dev->mtu = mtu;
}
- tunnel_dst_reset_all(t);
+ ip_tunnel_dst_reset_all(t);
netdev_state_change(dev);
}
@@ -1088,7 +1040,7 @@ void ip_tunnel_uninit(struct net_device *dev)
if (itn->fb_tunnel_dev != dev)
ip_tunnel_del(netdev_priv(dev));
- tunnel_dst_reset_all(tunnel);
+ ip_tunnel_dst_reset_all(tunnel);
}
EXPORT_SYMBOL_GPL(ip_tunnel_uninit);
diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c
index 6156f4ef5e91..8d69626f2206 100644
--- a/net/ipv4/ip_tunnel_core.c
+++ b/net/ipv4/ip_tunnel_core.c
@@ -148,3 +148,49 @@ error:
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(iptunnel_handle_offloads);
+
+/* Often modified stats are per cpu, other are shared (netdev->stats) */
+struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *tot)
+{
+ int i;
+
+ for_each_possible_cpu(i) {
+ const struct pcpu_sw_netstats *tstats =
+ per_cpu_ptr(dev->tstats, i);
+ u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin_bh(&tstats->syncp);
+ rx_packets = tstats->rx_packets;
+ tx_packets = tstats->tx_packets;
+ rx_bytes = tstats->rx_bytes;
+ tx_bytes = tstats->tx_bytes;
+ } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
+
+ tot->rx_packets += rx_packets;
+ tot->tx_packets += tx_packets;
+ tot->rx_bytes += rx_bytes;
+ tot->tx_bytes += tx_bytes;
+ }
+
+ tot->multicast = dev->stats.multicast;
+
+ tot->rx_crc_errors = dev->stats.rx_crc_errors;
+ tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
+ tot->rx_length_errors = dev->stats.rx_length_errors;
+ tot->rx_frame_errors = dev->stats.rx_frame_errors;
+ tot->rx_errors = dev->stats.rx_errors;
+
+ tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
+ tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
+ tot->tx_dropped = dev->stats.tx_dropped;
+ tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
+ tot->tx_errors = dev->stats.tx_errors;
+
+ tot->collisions = dev->stats.collisions;
+
+ return tot;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64);
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index efa1138fa523..b3e86ea7b71b 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -273,7 +273,7 @@ static int __init ic_open_devs(void)
msleep(1);
- if time_before(jiffies, next_msg)
+ if (time_before(jiffies, next_msg))
continue;
elapsed = jiffies_to_msecs(jiffies - start);
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index b9b3472975ba..28863570dd60 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -2255,13 +2255,14 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
}
static int ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
- u32 portid, u32 seq, struct mfc_cache *c, int cmd)
+ u32 portid, u32 seq, struct mfc_cache *c, int cmd,
+ int flags)
{
struct nlmsghdr *nlh;
struct rtmsg *rtm;
int err;
- nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), NLM_F_MULTI);
+ nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
if (nlh == NULL)
return -EMSGSIZE;
@@ -2329,7 +2330,7 @@ static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc,
if (skb == NULL)
goto errout;
- err = ipmr_fill_mroute(mrt, skb, 0, 0, mfc, cmd);
+ err = ipmr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
if (err < 0)
goto errout;
@@ -2368,7 +2369,8 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
if (ipmr_fill_mroute(mrt, skb,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
- mfc, RTM_NEWROUTE) < 0)
+ mfc, RTM_NEWROUTE,
+ NLM_F_MULTI) < 0)
goto done;
next_entry:
e++;
@@ -2382,7 +2384,8 @@ next_entry:
if (ipmr_fill_mroute(mrt, skb,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
- mfc, RTM_NEWROUTE) < 0) {
+ mfc, RTM_NEWROUTE,
+ NLM_F_MULTI) < 0) {
spin_unlock_bh(&mfc_unres_lock);
goto done;
}
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
index d551e31b416e..7c676671329d 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -1198,8 +1198,8 @@ static int snmp_translate(struct nf_conn *ct,
map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.ip);
} else {
/* DNAT replies */
- map.from = NOCT1(&ct->tuplehash[dir].tuple.src.u3.ip);
- map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.ip);
+ map.from = NOCT1(&ct->tuplehash[!dir].tuple.src.u3.ip);
+ map.to = NOCT1(&ct->tuplehash[dir].tuple.dst.u3.ip);
}
if (map.from == map.to)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 25071b48921c..4c011ec69ed4 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1597,6 +1597,7 @@ static int __mkroute_input(struct sk_buff *skb,
rth->rt_gateway = 0;
rth->rt_uses_gateway = 0;
INIT_LIST_HEAD(&rth->rt_uncached);
+ RT_CACHE_STAT_INC(in_slow_tot);
rth->dst.input = ip_forward;
rth->dst.output = ip_output;
@@ -1695,10 +1696,11 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
fl4.daddr = daddr;
fl4.saddr = saddr;
err = fib_lookup(net, &fl4, &res);
- if (err != 0)
+ if (err != 0) {
+ if (!IN_DEV_FORWARD(in_dev))
+ err = -EHOSTUNREACH;
goto no_route;
-
- RT_CACHE_STAT_INC(in_slow_tot);
+ }
if (res.type == RTN_BROADCAST)
goto brd_input;
@@ -1712,8 +1714,10 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
goto local_input;
}
- if (!IN_DEV_FORWARD(in_dev))
+ if (!IN_DEV_FORWARD(in_dev)) {
+ err = -EHOSTUNREACH;
goto no_route;
+ }
if (res.type != RTN_UNICAST)
goto martian_destination;
@@ -1768,6 +1772,7 @@ local_input:
rth->rt_gateway = 0;
rth->rt_uses_gateway = 0;
INIT_LIST_HEAD(&rth->rt_uncached);
+ RT_CACHE_STAT_INC(in_slow_tot);
if (res.type == RTN_UNREACHABLE) {
rth->dst.input= ip_error;
rth->dst.error= -err;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 9f3a2db9109e..97c8f5620c43 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1044,7 +1044,8 @@ void tcp_free_fastopen_req(struct tcp_sock *tp)
}
}
-static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *size)
+static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
+ int *copied, size_t size)
{
struct tcp_sock *tp = tcp_sk(sk);
int err, flags;
@@ -1059,11 +1060,12 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *size)
if (unlikely(tp->fastopen_req == NULL))
return -ENOBUFS;
tp->fastopen_req->data = msg;
+ tp->fastopen_req->size = size;
flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0;
err = __inet_stream_connect(sk->sk_socket, msg->msg_name,
msg->msg_namelen, flags);
- *size = tp->fastopen_req->copied;
+ *copied = tp->fastopen_req->copied;
tcp_free_fastopen_req(tp);
return err;
}
@@ -1083,7 +1085,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
flags = msg->msg_flags;
if (flags & MSG_FASTOPEN) {
- err = tcp_sendmsg_fastopen(sk, msg, &copied_syn);
+ err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
if (err == -EINPROGRESS && copied_syn > 0)
goto out;
else if (err)
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index ad37bf18ae4b..2388275adb9b 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -290,8 +290,7 @@ bool tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight)
left = tp->snd_cwnd - in_flight;
if (sk_can_gso(sk) &&
left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd &&
- left * tp->mss_cache < sk->sk_gso_max_size &&
- left < sk->sk_gso_max_segs)
+ left < tp->xmit_size_goal_segs)
return true;
return left <= tcp_max_tso_deferred_mss(tp);
}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 227cba79fa6b..eeaac399420d 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1945,8 +1945,9 @@ void tcp_enter_loss(struct sock *sk, int how)
if (skb == tcp_send_head(sk))
break;
- if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS)
+ if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
tp->undo_marker = 0;
+
TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED;
if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || how) {
TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 3cf976510497..1e4eac779f51 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2628,7 +2628,7 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
{
__be32 dest, src;
__u16 destp, srcp;
- long delta = tw->tw_ttd - jiffies;
+ s32 delta = tw->tw_ttd - inet_tw_time_stamp();
dest = tw->tw_daddr;
src = tw->tw_rcv_saddr;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 3be16727f058..17a11e65e57f 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -767,6 +767,17 @@ void tcp_release_cb(struct sock *sk)
if (flags & (1UL << TCP_TSQ_DEFERRED))
tcp_tsq_handler(sk);
+ /* Here begins the tricky part :
+ * We are called from release_sock() with :
+ * 1) BH disabled
+ * 2) sk_lock.slock spinlock held
+ * 3) socket owned by us (sk->sk_lock.owned == 1)
+ *
+ * But following code is meant to be called from BH handlers,
+ * so we should keep BH disabled, but early release socket ownership
+ */
+ sock_release_ownership(sk);
+
if (flags & (1UL << TCP_WRITE_TIMER_DEFERRED)) {
tcp_write_timer_handler(sk);
__sock_put(sk);
@@ -864,8 +875,8 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
if (unlikely(skb->fclone == SKB_FCLONE_ORIG &&
fclone->fclone == SKB_FCLONE_CLONE))
- NET_INC_STATS_BH(sock_net(sk),
- LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES);
+ NET_INC_STATS(sock_net(sk),
+ LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES);
if (unlikely(skb_cloned(skb)))
skb = pskb_copy(skb, gfp_mask);
@@ -2337,6 +2348,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
struct tcp_sock *tp = tcp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
unsigned int cur_mss;
+ int err;
/* Inconslusive MTU probe */
if (icsk->icsk_mtup.probe_size) {
@@ -2400,11 +2412,15 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
skb_headroom(skb) >= 0xFFFF)) {
struct sk_buff *nskb = __pskb_copy(skb, MAX_TCP_HEADER,
GFP_ATOMIC);
- return nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
- -ENOBUFS;
+ err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
+ -ENOBUFS;
} else {
- return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
+ err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
}
+
+ if (likely(!err))
+ TCP_SKB_CB(skb)->sacked |= TCPCB_EVER_RETRANS;
+ return err;
}
int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
@@ -2908,7 +2924,12 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
space = __tcp_mtu_to_mss(sk, inet_csk(sk)->icsk_pmtu_cookie) -
MAX_TCP_OPTION_SPACE;
- syn_data = skb_copy_expand(syn, skb_headroom(syn), space,
+ space = min_t(size_t, space, fo->size);
+
+ /* limit to order-0 allocations */
+ space = min_t(size_t, space, SKB_MAX_HEAD(MAX_TCP_HEADER));
+
+ syn_data = skb_copy_expand(syn, MAX_TCP_HEADER, space,
sk->sk_allocation);
if (syn_data == NULL)
goto fallback;
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index d92e5586783e..438a73aa777c 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -138,6 +138,7 @@ config INET6_XFRM_MODE_ROUTEOPTIMIZATION
config IPV6_VTI
tristate "Virtual (secure) IPv6: tunneling"
select IPV6_TUNNEL
+ select NET_IP_TUNNEL
depends on INET6_XFRM_MODE_TUNNEL
---help---
Tunneling means encapsulating data of one protocol type within
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index ad235690684c..6c7fa0853fc7 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -133,10 +133,12 @@ static int ipv6_count_addresses(struct inet6_dev *idev);
static struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE];
static DEFINE_SPINLOCK(addrconf_hash_lock);
-static void addrconf_verify(unsigned long);
+static void addrconf_verify(void);
+static void addrconf_verify_rtnl(void);
+static void addrconf_verify_work(struct work_struct *);
-static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0);
-static DEFINE_SPINLOCK(addrconf_verify_lock);
+static struct workqueue_struct *addrconf_wq;
+static DECLARE_DELAYED_WORK(addr_chk_work, addrconf_verify_work);
static void addrconf_join_anycast(struct inet6_ifaddr *ifp);
static void addrconf_leave_anycast(struct inet6_ifaddr *ifp);
@@ -151,7 +153,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
u32 flags, u32 noflags);
static void addrconf_dad_start(struct inet6_ifaddr *ifp);
-static void addrconf_dad_timer(unsigned long data);
+static void addrconf_dad_work(struct work_struct *w);
static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
static void addrconf_dad_run(struct inet6_dev *idev);
static void addrconf_rs_timer(unsigned long data);
@@ -247,9 +249,9 @@ static void addrconf_del_rs_timer(struct inet6_dev *idev)
__in6_dev_put(idev);
}
-static void addrconf_del_dad_timer(struct inet6_ifaddr *ifp)
+static void addrconf_del_dad_work(struct inet6_ifaddr *ifp)
{
- if (del_timer(&ifp->dad_timer))
+ if (cancel_delayed_work(&ifp->dad_work))
__in6_ifa_put(ifp);
}
@@ -261,12 +263,12 @@ static void addrconf_mod_rs_timer(struct inet6_dev *idev,
mod_timer(&idev->rs_timer, jiffies + when);
}
-static void addrconf_mod_dad_timer(struct inet6_ifaddr *ifp,
- unsigned long when)
+static void addrconf_mod_dad_work(struct inet6_ifaddr *ifp,
+ unsigned long delay)
{
- if (!timer_pending(&ifp->dad_timer))
+ if (!delayed_work_pending(&ifp->dad_work))
in6_ifa_hold(ifp);
- mod_timer(&ifp->dad_timer, jiffies + when);
+ mod_delayed_work(addrconf_wq, &ifp->dad_work, delay);
}
static int snmp6_alloc_dev(struct inet6_dev *idev)
@@ -751,8 +753,9 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
in6_dev_put(ifp->idev);
- if (del_timer(&ifp->dad_timer))
- pr_notice("Timer is still running, when freeing ifa=%p\n", ifp);
+ if (cancel_delayed_work(&ifp->dad_work))
+ pr_notice("delayed DAD work was pending while freeing ifa=%p\n",
+ ifp);
if (ifp->state != INET6_IFADDR_STATE_DEAD) {
pr_warn("Freeing alive inet6 address %p\n", ifp);
@@ -849,8 +852,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
spin_lock_init(&ifa->lock);
spin_lock_init(&ifa->state_lock);
- setup_timer(&ifa->dad_timer, addrconf_dad_timer,
- (unsigned long)ifa);
+ INIT_DELAYED_WORK(&ifa->dad_work, addrconf_dad_work);
INIT_HLIST_NODE(&ifa->addr_lst);
ifa->scope = scope;
ifa->prefix_len = pfxlen;
@@ -990,6 +992,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_NOP;
unsigned long expires;
+ ASSERT_RTNL();
+
spin_lock_bh(&ifp->state_lock);
state = ifp->state;
ifp->state = INET6_IFADDR_STATE_DEAD;
@@ -1021,7 +1025,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
write_unlock_bh(&ifp->idev->lock);
- addrconf_del_dad_timer(ifp);
+ addrconf_del_dad_work(ifp);
ipv6_ifa_notify(RTM_DELADDR, ifp);
@@ -1103,8 +1107,11 @@ retry:
* Lifetime is greater than REGEN_ADVANCE time units. In particular,
* an implementation must not create a temporary address with a zero
* Preferred Lifetime.
+ * Use age calculation as in addrconf_verify to avoid unnecessary
+ * temporary addresses being generated.
*/
- if (tmp_prefered_lft <= regen_advance) {
+ age = (now - tmp_tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
+ if (tmp_prefered_lft <= regen_advance + age) {
in6_ifa_put(ifp);
in6_dev_put(idev);
ret = -1;
@@ -1601,7 +1608,7 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
{
if (ifp->flags&IFA_F_PERMANENT) {
spin_lock_bh(&ifp->lock);
- addrconf_del_dad_timer(ifp);
+ addrconf_del_dad_work(ifp);
ifp->flags |= IFA_F_TENTATIVE;
if (dad_failed)
ifp->flags |= IFA_F_DADFAILED;
@@ -1622,20 +1629,21 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
spin_unlock_bh(&ifp->lock);
}
ipv6_del_addr(ifp);
- } else
+ } else {
ipv6_del_addr(ifp);
+ }
}
static int addrconf_dad_end(struct inet6_ifaddr *ifp)
{
int err = -ENOENT;
- spin_lock(&ifp->state_lock);
+ spin_lock_bh(&ifp->state_lock);
if (ifp->state == INET6_IFADDR_STATE_DAD) {
ifp->state = INET6_IFADDR_STATE_POSTDAD;
err = 0;
}
- spin_unlock(&ifp->state_lock);
+ spin_unlock_bh(&ifp->state_lock);
return err;
}
@@ -1668,7 +1676,12 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
}
}
- addrconf_dad_stop(ifp, 1);
+ spin_lock_bh(&ifp->state_lock);
+ /* transition from _POSTDAD to _ERRDAD */
+ ifp->state = INET6_IFADDR_STATE_ERRDAD;
+ spin_unlock_bh(&ifp->state_lock);
+
+ addrconf_mod_dad_work(ifp, 0);
}
/* Join to solicited addr multicast group. */
@@ -1677,6 +1690,8 @@ void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr)
{
struct in6_addr maddr;
+ ASSERT_RTNL();
+
if (dev->flags&(IFF_LOOPBACK|IFF_NOARP))
return;
@@ -1688,6 +1703,8 @@ void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr)
{
struct in6_addr maddr;
+ ASSERT_RTNL();
+
if (idev->dev->flags&(IFF_LOOPBACK|IFF_NOARP))
return;
@@ -1698,6 +1715,9 @@ void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr)
static void addrconf_join_anycast(struct inet6_ifaddr *ifp)
{
struct in6_addr addr;
+
+ ASSERT_RTNL();
+
if (ifp->prefix_len >= 127) /* RFC 6164 */
return;
ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
@@ -1709,6 +1729,9 @@ static void addrconf_join_anycast(struct inet6_ifaddr *ifp)
static void addrconf_leave_anycast(struct inet6_ifaddr *ifp)
{
struct in6_addr addr;
+
+ ASSERT_RTNL();
+
if (ifp->prefix_len >= 127) /* RFC 6164 */
return;
ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
@@ -2268,11 +2291,13 @@ ok:
return;
}
- ifp->flags |= IFA_F_MANAGETEMPADDR;
update_lft = 0;
create = 1;
+ spin_lock_bh(&ifp->lock);
+ ifp->flags |= IFA_F_MANAGETEMPADDR;
ifp->cstamp = jiffies;
ifp->tokenized = tokenized;
+ spin_unlock_bh(&ifp->lock);
addrconf_dad_start(ifp);
}
@@ -2323,7 +2348,7 @@ ok:
create, now);
in6_ifa_put(ifp);
- addrconf_verify(0);
+ addrconf_verify();
}
}
inet6_prefix_notify(RTM_NEWPREFIX, in6_dev, pinfo);
@@ -2472,7 +2497,7 @@ static int inet6_addr_add(struct net *net, int ifindex,
manage_tempaddrs(idev, ifp, valid_lft, prefered_lft,
true, jiffies);
in6_ifa_put(ifp);
- addrconf_verify(0);
+ addrconf_verify_rtnl();
return 0;
}
@@ -2783,6 +2808,8 @@ static void addrconf_gre_config(struct net_device *dev)
ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0);
if (!ipv6_generate_eui64(addr.s6_addr + 8, dev))
addrconf_add_linklocal(idev, &addr);
+ else
+ addrconf_prefix_route(&addr, 64, dev, 0, 0);
}
#endif
@@ -3006,7 +3033,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
hlist_for_each_entry_rcu(ifa, h, addr_lst) {
if (ifa->idev == idev) {
hlist_del_init_rcu(&ifa->addr_lst);
- addrconf_del_dad_timer(ifa);
+ addrconf_del_dad_work(ifa);
goto restart;
}
}
@@ -3044,7 +3071,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
while (!list_empty(&idev->addr_list)) {
ifa = list_first_entry(&idev->addr_list,
struct inet6_ifaddr, if_list);
- addrconf_del_dad_timer(ifa);
+ addrconf_del_dad_work(ifa);
list_del(&ifa->if_list);
@@ -3143,10 +3170,10 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp)
rand_num = prandom_u32() % (idev->cnf.rtr_solicit_delay ? : 1);
ifp->dad_probes = idev->cnf.dad_transmits;
- addrconf_mod_dad_timer(ifp, rand_num);
+ addrconf_mod_dad_work(ifp, rand_num);
}
-static void addrconf_dad_start(struct inet6_ifaddr *ifp)
+static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
{
struct inet6_dev *idev = ifp->idev;
struct net_device *dev = idev->dev;
@@ -3198,25 +3225,68 @@ out:
read_unlock_bh(&idev->lock);
}
-static void addrconf_dad_timer(unsigned long data)
+static void addrconf_dad_start(struct inet6_ifaddr *ifp)
+{
+ bool begin_dad = false;
+
+ spin_lock_bh(&ifp->state_lock);
+ if (ifp->state != INET6_IFADDR_STATE_DEAD) {
+ ifp->state = INET6_IFADDR_STATE_PREDAD;
+ begin_dad = true;
+ }
+ spin_unlock_bh(&ifp->state_lock);
+
+ if (begin_dad)
+ addrconf_mod_dad_work(ifp, 0);
+}
+
+static void addrconf_dad_work(struct work_struct *w)
{
- struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data;
+ struct inet6_ifaddr *ifp = container_of(to_delayed_work(w),
+ struct inet6_ifaddr,
+ dad_work);
struct inet6_dev *idev = ifp->idev;
struct in6_addr mcaddr;
+ enum {
+ DAD_PROCESS,
+ DAD_BEGIN,
+ DAD_ABORT,
+ } action = DAD_PROCESS;
+
+ rtnl_lock();
+
+ spin_lock_bh(&ifp->state_lock);
+ if (ifp->state == INET6_IFADDR_STATE_PREDAD) {
+ action = DAD_BEGIN;
+ ifp->state = INET6_IFADDR_STATE_DAD;
+ } else if (ifp->state == INET6_IFADDR_STATE_ERRDAD) {
+ action = DAD_ABORT;
+ ifp->state = INET6_IFADDR_STATE_POSTDAD;
+ }
+ spin_unlock_bh(&ifp->state_lock);
+
+ if (action == DAD_BEGIN) {
+ addrconf_dad_begin(ifp);
+ goto out;
+ } else if (action == DAD_ABORT) {
+ addrconf_dad_stop(ifp, 1);
+ goto out;
+ }
+
if (!ifp->dad_probes && addrconf_dad_end(ifp))
goto out;
- write_lock(&idev->lock);
+ write_lock_bh(&idev->lock);
if (idev->dead || !(idev->if_flags & IF_READY)) {
- write_unlock(&idev->lock);
+ write_unlock_bh(&idev->lock);
goto out;
}
spin_lock(&ifp->lock);
if (ifp->state == INET6_IFADDR_STATE_DEAD) {
spin_unlock(&ifp->lock);
- write_unlock(&idev->lock);
+ write_unlock_bh(&idev->lock);
goto out;
}
@@ -3227,7 +3297,7 @@ static void addrconf_dad_timer(unsigned long data)
ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
spin_unlock(&ifp->lock);
- write_unlock(&idev->lock);
+ write_unlock_bh(&idev->lock);
addrconf_dad_completed(ifp);
@@ -3235,16 +3305,17 @@ static void addrconf_dad_timer(unsigned long data)
}
ifp->dad_probes--;
- addrconf_mod_dad_timer(ifp,
- NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME));
+ addrconf_mod_dad_work(ifp,
+ NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME));
spin_unlock(&ifp->lock);
- write_unlock(&idev->lock);
+ write_unlock_bh(&idev->lock);
/* send a neighbour solicitation for our addr */
addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &in6addr_any);
out:
in6_ifa_put(ifp);
+ rtnl_unlock();
}
/* ifp->idev must be at least read locked */
@@ -3271,7 +3342,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
struct in6_addr lladdr;
bool send_rs, send_mld;
- addrconf_del_dad_timer(ifp);
+ addrconf_del_dad_work(ifp);
/*
* Configure the address for reception. Now it is valid.
@@ -3512,23 +3583,23 @@ int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr)
* Periodic address status verification
*/
-static void addrconf_verify(unsigned long foo)
+static void addrconf_verify_rtnl(void)
{
unsigned long now, next, next_sec, next_sched;
struct inet6_ifaddr *ifp;
int i;
+ ASSERT_RTNL();
+
rcu_read_lock_bh();
- spin_lock(&addrconf_verify_lock);
now = jiffies;
next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
- del_timer(&addr_chk_timer);
+ cancel_delayed_work(&addr_chk_work);
for (i = 0; i < IN6_ADDR_HSIZE; i++) {
restart:
- hlist_for_each_entry_rcu_bh(ifp,
- &inet6_addr_lst[i], addr_lst) {
+ hlist_for_each_entry_rcu_bh(ifp, &inet6_addr_lst[i], addr_lst) {
unsigned long age;
/* When setting preferred_lft to a value not zero or
@@ -3623,13 +3694,22 @@ restart:
ADBG(KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
now, next, next_sec, next_sched);
-
- addr_chk_timer.expires = next_sched;
- add_timer(&addr_chk_timer);
- spin_unlock(&addrconf_verify_lock);
+ mod_delayed_work(addrconf_wq, &addr_chk_work, next_sched - now);
rcu_read_unlock_bh();
}
+static void addrconf_verify_work(struct work_struct *w)
+{
+ rtnl_lock();
+ addrconf_verify_rtnl();
+ rtnl_unlock();
+}
+
+static void addrconf_verify(void)
+{
+ mod_delayed_work(addrconf_wq, &addr_chk_work, 0);
+}
+
static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local,
struct in6_addr **peer_pfx)
{
@@ -3686,6 +3766,8 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
bool was_managetempaddr;
bool had_prefixroute;
+ ASSERT_RTNL();
+
if (!valid_lft || (prefered_lft > valid_lft))
return -EINVAL;
@@ -3751,7 +3833,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
!was_managetempaddr, jiffies);
}
- addrconf_verify(0);
+ addrconf_verify_rtnl();
return 0;
}
@@ -4381,6 +4463,8 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
bool update_rs = false;
struct in6_addr ll_addr;
+ ASSERT_RTNL();
+
if (token == NULL)
return -EINVAL;
if (ipv6_addr_any(token))
@@ -4429,7 +4513,7 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
}
write_unlock_bh(&idev->lock);
- addrconf_verify(0);
+ addrconf_verify_rtnl();
return 0;
}
@@ -4631,6 +4715,9 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
{
struct net *net = dev_net(ifp->idev->dev);
+ if (event)
+ ASSERT_RTNL();
+
inet6_ifa_notify(event ? : RTM_NEWADDR, ifp);
switch (event) {
@@ -5239,6 +5326,12 @@ int __init addrconf_init(void)
if (err < 0)
goto out_addrlabel;
+ addrconf_wq = create_workqueue("ipv6_addrconf");
+ if (!addrconf_wq) {
+ err = -ENOMEM;
+ goto out_nowq;
+ }
+
/* The addrconf netdev notifier requires that loopback_dev
* has it's ipv6 private information allocated and setup
* before it can bring up and give link-local addresses
@@ -5269,7 +5362,7 @@ int __init addrconf_init(void)
register_netdevice_notifier(&ipv6_dev_notf);
- addrconf_verify(0);
+ addrconf_verify();
rtnl_af_register(&inet6_ops);
@@ -5297,6 +5390,8 @@ errout:
rtnl_af_unregister(&inet6_ops);
unregister_netdevice_notifier(&ipv6_dev_notf);
errlo:
+ destroy_workqueue(addrconf_wq);
+out_nowq:
unregister_pernet_subsys(&addrconf_ops);
out_addrlabel:
ipv6_addr_label_cleanup();
@@ -5332,7 +5427,8 @@ void addrconf_cleanup(void)
for (i = 0; i < IN6_ADDR_HSIZE; i++)
WARN_ON(!hlist_empty(&inet6_addr_lst[i]));
spin_unlock_bh(&addrconf_hash_lock);
-
- del_timer(&addr_chk_timer);
+ cancel_delayed_work(&addr_chk_work);
rtnl_unlock();
+
+ destroy_workqueue(addrconf_wq);
}
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c
index 140748debc4a..8af3eb57f438 100644
--- a/net/ipv6/exthdrs_core.c
+++ b/net/ipv6/exthdrs_core.c
@@ -212,7 +212,7 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
found = (nexthdr == target);
if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
- if (target < 0)
+ if (target < 0 || found)
break;
return -ENOENT;
}
diff --git a/net/ipv6/exthdrs_offload.c b/net/ipv6/exthdrs_offload.c
index cf77f3abfd06..447a7fbd1bb6 100644
--- a/net/ipv6/exthdrs_offload.c
+++ b/net/ipv6/exthdrs_offload.c
@@ -25,11 +25,11 @@ int __init ipv6_exthdrs_offload_init(void)
int ret;
ret = inet6_add_offload(&rthdr_offload, IPPROTO_ROUTING);
- if (!ret)
+ if (ret)
goto out;
ret = inet6_add_offload(&dstopt_offload, IPPROTO_DSTOPTS);
- if (!ret)
+ if (ret)
goto out_rt;
out:
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index 1e8683b135bb..59f95affceb0 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -89,7 +89,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
unsigned int unfrag_ip6hlen;
u8 *prevhdr;
int offset = 0;
- bool tunnel;
+ bool encap, udpfrag;
int nhoff;
if (unlikely(skb_shinfo(skb)->gso_type &
@@ -110,8 +110,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
goto out;
- tunnel = SKB_GSO_CB(skb)->encap_level > 0;
- if (tunnel)
+ encap = SKB_GSO_CB(skb)->encap_level > 0;
+ if (encap)
features = skb->dev->hw_enc_features & netif_skb_features(skb);
SKB_GSO_CB(skb)->encap_level += sizeof(*ipv6h);
@@ -121,6 +121,12 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
+ if (skb->encapsulation &&
+ skb_shinfo(skb)->gso_type & (SKB_GSO_SIT|SKB_GSO_IPIP))
+ udpfrag = proto == IPPROTO_UDP && encap;
+ else
+ udpfrag = proto == IPPROTO_UDP && !skb->encapsulation;
+
ops = rcu_dereference(inet6_offloads[proto]);
if (likely(ops && ops->callbacks.gso_segment)) {
skb_reset_transport_header(skb);
@@ -133,13 +139,9 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
for (skb = segs; skb; skb = skb->next) {
ipv6h = (struct ipv6hdr *)(skb_mac_header(skb) + nhoff);
ipv6h->payload_len = htons(skb->len - nhoff - sizeof(*ipv6h));
- if (tunnel) {
- skb_reset_inner_headers(skb);
- skb->encapsulation = 1;
- }
skb->network_header = (u8 *)ipv6h - skb->head;
- if (!tunnel && proto == IPPROTO_UDP) {
+ if (udpfrag) {
unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
fptr = (struct frag_hdr *)((u8 *)ipv6h + unfrag_ip6hlen);
fptr->frag_off = htons(offset);
@@ -148,6 +150,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
offset += (ntohs(ipv6h->payload_len) -
sizeof(struct frag_hdr));
}
+ if (encap)
+ skb_reset_inner_headers(skb);
}
out:
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index ef02b26ccf81..64d6073731d3 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -342,6 +342,20 @@ static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
return mtu;
}
+static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
+{
+ if (skb->len <= mtu || skb->local_df)
+ return false;
+
+ if (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)
+ return true;
+
+ if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu)
+ return false;
+
+ return true;
+}
+
int ip6_forward(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
@@ -466,8 +480,7 @@ int ip6_forward(struct sk_buff *skb)
if (mtu < IPV6_MIN_MTU)
mtu = IPV6_MIN_MTU;
- if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) ||
- (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) {
+ if (ip6_pkt_too_big(skb, mtu)) {
/* Again, force OUTPUT device used as source address */
skb->dev = dst->dev;
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
@@ -517,9 +530,6 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
to->tc_index = from->tc_index;
#endif
nf_copy(to, from);
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
- to->nf_trace = from->nf_trace;
-#endif
skb_copy_secmark(to, from);
}
@@ -1091,21 +1101,19 @@ static void ip6_append_data_mtu(unsigned int *mtu,
unsigned int fragheaderlen,
struct sk_buff *skb,
struct rt6_info *rt,
- bool pmtuprobe)
+ unsigned int orig_mtu)
{
if (!(rt->dst.flags & DST_XFRM_TUNNEL)) {
if (skb == NULL) {
/* first fragment, reserve header_len */
- *mtu = *mtu - rt->dst.header_len;
+ *mtu = orig_mtu - rt->dst.header_len;
} else {
/*
* this fragment is not first, the headers
* space is regarded as data space.
*/
- *mtu = min(*mtu, pmtuprobe ?
- rt->dst.dev->mtu :
- dst_mtu(rt->dst.path));
+ *mtu = orig_mtu;
}
*maxfraglen = ((*mtu - fragheaderlen) & ~7)
+ fragheaderlen - sizeof(struct frag_hdr);
@@ -1122,7 +1130,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
struct ipv6_pinfo *np = inet6_sk(sk);
struct inet_cork *cork;
struct sk_buff *skb, *skb_prev = NULL;
- unsigned int maxfraglen, fragheaderlen, mtu;
+ unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
int exthdrlen;
int dst_exthdrlen;
int hh_len;
@@ -1204,6 +1212,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
dst_exthdrlen = 0;
mtu = cork->fragsize;
}
+ orig_mtu = mtu;
hh_len = LL_RESERVED_SPACE(rt->dst.dev);
@@ -1301,8 +1310,7 @@ alloc_new_skb:
if (skb == NULL || skb_prev == NULL)
ip6_append_data_mtu(&mtu, &maxfraglen,
fragheaderlen, skb, rt,
- np->pmtudisc >=
- IPV6_PMTUDISC_PROBE);
+ orig_mtu);
skb_prev = skb;
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 0eb4038a4d63..8737400af0a0 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -2349,13 +2349,14 @@ int ip6mr_get_route(struct net *net,
}
static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
- u32 portid, u32 seq, struct mfc6_cache *c, int cmd)
+ u32 portid, u32 seq, struct mfc6_cache *c, int cmd,
+ int flags)
{
struct nlmsghdr *nlh;
struct rtmsg *rtm;
int err;
- nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), NLM_F_MULTI);
+ nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
if (nlh == NULL)
return -EMSGSIZE;
@@ -2423,7 +2424,7 @@ static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc,
if (skb == NULL)
goto errout;
- err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd);
+ err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
if (err < 0)
goto errout;
@@ -2462,7 +2463,8 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
if (ip6mr_fill_mroute(mrt, skb,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
- mfc, RTM_NEWROUTE) < 0)
+ mfc, RTM_NEWROUTE,
+ NLM_F_MULTI) < 0)
goto done;
next_entry:
e++;
@@ -2476,7 +2478,8 @@ next_entry:
if (ip6mr_fill_mroute(mrt, skb,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
- mfc, RTM_NEWROUTE) < 0) {
+ mfc, RTM_NEWROUTE,
+ NLM_F_MULTI) < 0) {
spin_unlock_bh(&mfc_unres_lock);
goto done;
}
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
index fb9beb78f00b..587bbdcb22b4 100644
--- a/net/ipv6/ping.c
+++ b/net/ipv6/ping.c
@@ -135,6 +135,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
fl6.flowi6_proto = IPPROTO_ICMPV6;
fl6.saddr = np->saddr;
fl6.daddr = *daddr;
+ fl6.flowi6_mark = sk->sk_mark;
fl6.fl6_icmp_type = user_icmph.icmp6_type;
fl6.fl6_icmp_code = user_icmph.icmp6_code;
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 11dac21e6586..fba54a407bb2 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1513,7 +1513,7 @@ int ip6_route_add(struct fib6_config *cfg)
if (!table)
goto out;
- rt = ip6_dst_alloc(net, NULL, DST_NOCOUNT, table);
+ rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table);
if (!rt) {
err = -ENOMEM;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 3dfbcf1dcb1c..b4d74c86586c 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -475,6 +475,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev)
ipip6_tunnel_unlink(sitn, tunnel);
ipip6_tunnel_del_prl(tunnel, NULL);
}
+ ip_tunnel_dst_reset_all(tunnel);
dev_put(dev);
}
@@ -1082,6 +1083,7 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
t->parms.link = p->link;
ipip6_tunnel_bind_dev(t->dev);
}
+ ip_tunnel_dst_reset_all(t);
netdev_state_change(t->dev);
}
@@ -1112,6 +1114,7 @@ static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
t->ip6rd.relay_prefix = relay_prefix;
t->ip6rd.prefixlen = ip6rd->prefixlen;
t->ip6rd.relay_prefixlen = ip6rd->relay_prefixlen;
+ ip_tunnel_dst_reset_all(t);
netdev_state_change(t->dev);
return 0;
}
@@ -1271,6 +1274,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL);
break;
}
+ ip_tunnel_dst_reset_all(t);
netdev_state_change(dev);
break;
@@ -1326,6 +1330,9 @@ static const struct net_device_ops ipip6_netdev_ops = {
static void ipip6_dev_free(struct net_device *dev)
{
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+
+ free_percpu(tunnel->dst_cache);
free_percpu(dev->tstats);
free_netdev(dev);
}
@@ -1375,6 +1382,12 @@ static int ipip6_tunnel_init(struct net_device *dev)
u64_stats_init(&ipip6_tunnel_stats->syncp);
}
+ tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst);
+ if (!tunnel->dst_cache) {
+ free_percpu(dev->tstats);
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -1405,6 +1418,12 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)
u64_stats_init(&ipip6_fb_stats->syncp);
}
+ tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst);
+ if (!tunnel->dst_cache) {
+ free_percpu(dev->tstats);
+ return -ENOMEM;
+ }
+
dev_hold(dev);
rcu_assign_pointer(sitn->tunnels_wc[0], tunnel);
return 0;
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index e7359f9eaa8d..b261ee8b83fc 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -113,7 +113,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
fptr->nexthdr = nexthdr;
fptr->reserved = 0;
- ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb));
+ fptr->identification = skb_shinfo(skb)->ip6_frag_id;
/* Fragment the skb. ipv6 header and the remaining fields of the
* fragment header are updated in ipv6_gso_segment()
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 1a04c1329362..79326978517a 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -433,12 +433,13 @@ static inline int verify_sec_ctx_len(const void *p)
return 0;
}
-static inline struct xfrm_user_sec_ctx *pfkey_sadb2xfrm_user_sec_ctx(const struct sadb_x_sec_ctx *sec_ctx)
+static inline struct xfrm_user_sec_ctx *pfkey_sadb2xfrm_user_sec_ctx(const struct sadb_x_sec_ctx *sec_ctx,
+ gfp_t gfp)
{
struct xfrm_user_sec_ctx *uctx = NULL;
int ctx_size = sec_ctx->sadb_x_ctx_len;
- uctx = kmalloc((sizeof(*uctx)+ctx_size), GFP_KERNEL);
+ uctx = kmalloc((sizeof(*uctx)+ctx_size), gfp);
if (!uctx)
return NULL;
@@ -1124,7 +1125,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
sec_ctx = ext_hdrs[SADB_X_EXT_SEC_CTX - 1];
if (sec_ctx != NULL) {
- struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
+ struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_KERNEL);
if (!uctx)
goto out;
@@ -2231,14 +2232,14 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, const struct sadb_
sec_ctx = ext_hdrs[SADB_X_EXT_SEC_CTX - 1];
if (sec_ctx != NULL) {
- struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
+ struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_KERNEL);
if (!uctx) {
err = -ENOBUFS;
goto out;
}
- err = security_xfrm_policy_alloc(&xp->security, uctx);
+ err = security_xfrm_policy_alloc(&xp->security, uctx, GFP_KERNEL);
kfree(uctx);
if (err)
@@ -2335,12 +2336,12 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, const struct sa
sec_ctx = ext_hdrs[SADB_X_EXT_SEC_CTX - 1];
if (sec_ctx != NULL) {
- struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
+ struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_KERNEL);
if (!uctx)
return -ENOMEM;
- err = security_xfrm_policy_alloc(&pol_ctx, uctx);
+ err = security_xfrm_policy_alloc(&pol_ctx, uctx, GFP_KERNEL);
kfree(uctx);
if (err)
return err;
@@ -3239,8 +3240,8 @@ static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,
}
if ((*dir = verify_sec_ctx_len(p)))
goto out;
- uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
- *dir = security_xfrm_policy_alloc(&xp->security, uctx);
+ uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_ATOMIC);
+ *dir = security_xfrm_policy_alloc(&xp->security, uctx, GFP_ATOMIC);
kfree(uctx);
if (*dir)
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 735d0f60c83a..c83827e7c324 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -112,7 +112,6 @@ struct l2tp_net {
spinlock_t l2tp_session_hlist_lock;
};
-static void l2tp_session_set_header_len(struct l2tp_session *session, int version);
static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk)
@@ -1863,7 +1862,7 @@ EXPORT_SYMBOL_GPL(l2tp_session_delete);
/* We come here whenever a session's send_seq, cookie_len or
* l2specific_len parameters are set.
*/
-static void l2tp_session_set_header_len(struct l2tp_session *session, int version)
+void l2tp_session_set_header_len(struct l2tp_session *session, int version)
{
if (version == L2TP_HDR_VER_2) {
session->hdr_len = 6;
@@ -1876,6 +1875,7 @@ static void l2tp_session_set_header_len(struct l2tp_session *session, int versio
}
}
+EXPORT_SYMBOL_GPL(l2tp_session_set_header_len);
struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
{
@@ -2016,7 +2016,7 @@ static int __init l2tp_init(void)
if (rc)
goto out;
- l2tp_wq = alloc_workqueue("l2tp", WQ_NON_REENTRANT | WQ_UNBOUND, 0);
+ l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0);
if (!l2tp_wq) {
pr_err("alloc_workqueue failed\n");
rc = -ENOMEM;
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 1f01ba3435bc..3f93ccd6ba97 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -263,6 +263,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
int length, int (*payload_hook)(struct sk_buff *skb));
int l2tp_session_queue_purge(struct l2tp_session *session);
int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb);
+void l2tp_session_set_header_len(struct l2tp_session *session, int version);
int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb,
int hdr_len);
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index 4cfd722e9153..bd7387adea9e 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -578,8 +578,10 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf
if (info->attrs[L2TP_ATTR_RECV_SEQ])
session->recv_seq = nla_get_u8(info->attrs[L2TP_ATTR_RECV_SEQ]);
- if (info->attrs[L2TP_ATTR_SEND_SEQ])
+ if (info->attrs[L2TP_ATTR_SEND_SEQ]) {
session->send_seq = nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]);
+ l2tp_session_set_header_len(session, session->tunnel->version);
+ }
if (info->attrs[L2TP_ATTR_LNS_MODE])
session->lns_mode = nla_get_u8(info->attrs[L2TP_ATTR_LNS_MODE]);
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index be5fadf34739..5990919356a5 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -254,12 +254,14 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int
po = pppox_sk(sk);
ppp_input(&po->chan, skb);
} else {
- l2tp_info(session, PPPOL2TP_MSG_DATA, "%s: socket not bound\n",
- session->name);
+ l2tp_dbg(session, PPPOL2TP_MSG_DATA,
+ "%s: recv %d byte data frame, passing to L2TP socket\n",
+ session->name, data_len);
- /* Not bound. Nothing we can do, so discard. */
- atomic_long_inc(&session->stats.rx_errors);
- kfree_skb(skb);
+ if (sock_queue_rcv_skb(sk, skb) < 0) {
+ atomic_long_inc(&session->stats.rx_errors);
+ kfree_skb(skb);
+ }
}
return;
@@ -1312,6 +1314,7 @@ static int pppol2tp_session_setsockopt(struct sock *sk,
po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ :
PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
}
+ l2tp_session_set_header_len(session, session->tunnel->version);
l2tp_info(session, PPPOL2TP_MSG_CONTROL,
"%s: set send_seq=%d\n",
session->name, session->send_seq);
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index f43613a97dd6..0c1ecfdf9a12 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -100,6 +100,12 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
}
max_bw = max(max_bw, width);
}
+
+ /* use the configured bandwidth in case of monitor interface */
+ sdata = rcu_dereference(local->monitor_sdata);
+ if (sdata && rcu_access_pointer(sdata->vif.chanctx_conf) == conf)
+ max_bw = max(max_bw, conf->def.width);
+
rcu_read_unlock();
return max_bw;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3701930c6649..5e44e3179e02 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1692,14 +1692,8 @@ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue);
void ieee80211_add_pending_skb(struct ieee80211_local *local,
struct sk_buff *skb);
-void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
- struct sk_buff_head *skbs,
- void (*fn)(void *data), void *data);
-static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
- struct sk_buff_head *skbs)
-{
- ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
-}
+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+ struct sk_buff_head *skbs);
void ieee80211_flush_queues(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index d6d1f1df9119..ce1c44370610 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1057,7 +1057,8 @@ static void ieee80211_uninit(struct net_device *dev)
static u16 ieee80211_netdev_select_queue(struct net_device *dev,
struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv,
+ select_queue_fallback_t fallback)
{
return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
}
@@ -1075,7 +1076,8 @@ static const struct net_device_ops ieee80211_dataif_ops = {
static u16 ieee80211_monitor_select_queue(struct net_device *dev,
struct sk_buff *skb,
- void *accel_priv)
+ void *accel_priv,
+ select_queue_fallback_t fallback)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c
index 2802f9d9279d..ad8b377b4b9f 100644
--- a/net/mac80211/mesh_ps.c
+++ b/net/mac80211/mesh_ps.c
@@ -36,6 +36,7 @@ static struct sk_buff *mps_qos_null_get(struct sta_info *sta)
sdata->vif.addr);
nullfunc->frame_control = fc;
nullfunc->duration_id = 0;
+ nullfunc->seq_ctrl = 0;
/* no address resolution for this frame -> set addr 1 immediately */
memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
memset(skb_put(skb, 2), 0, 2); /* append QoS control field */
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index fc1d82465b3c..245dce969b31 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -222,6 +222,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
switch (vht_oper->chan_width) {
case IEEE80211_VHT_CHANWIDTH_USE_HT:
vht_chandef.width = chandef->width;
+ vht_chandef.center_freq1 = chandef->center_freq1;
break;
case IEEE80211_VHT_CHANWIDTH_80MHZ:
vht_chandef.width = NL80211_CHAN_WIDTH_80;
@@ -271,6 +272,28 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
ret = 0;
out:
+ /*
+ * When tracking the current AP, don't do any further checks if the
+ * new chandef is identical to the one we're currently using for the
+ * connection. This keeps us from playing ping-pong with regulatory,
+ * without it the following can happen (for example):
+ * - connect to an AP with 80 MHz, world regdom allows 80 MHz
+ * - AP advertises regdom US
+ * - CRDA loads regdom US with 80 MHz prohibited (old database)
+ * - the code below detects an unsupported channel, downgrades, and
+ * we disconnect from the AP in the caller
+ * - disconnect causes CRDA to reload world regdomain and the game
+ * starts anew.
+ * (see https://bugzilla.kernel.org/show_bug.cgi?id=70881)
+ *
+ * It seems possible that there are still scenarios with CSA or real
+ * bandwidth changes where a this could happen, but those cases are
+ * less common and wouldn't completely prevent using the AP.
+ */
+ if (tracking &&
+ cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef))
+ return ret;
+
/* don't print the message below for VHT mismatch if VHT is disabled */
if (ret & IEEE80211_STA_DISABLE_VHT)
vht_chandef = *chandef;
@@ -3753,6 +3776,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
+ sta_info_free(local, new_sta);
return -EINVAL;
}
rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index c24ca0d0f469..3e57f96c9666 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1128,6 +1128,13 @@ static void sta_ps_end(struct sta_info *sta)
sta->sta.addr, sta->sta.aid);
if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
+ /*
+ * Clear the flag only if the other one is still set
+ * so that the TX path won't start TX'ing new frames
+ * directly ... In the case that the driver flag isn't
+ * set ieee80211_sta_ps_deliver_wakeup() will clear it.
+ */
+ clear_sta_flag(sta, WLAN_STA_PS_STA);
ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n",
sta->sta.addr, sta->sta.aid);
return;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index decd30c1e290..137a192e64bc 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -91,7 +91,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
return -ENOENT;
}
-static void cleanup_single_sta(struct sta_info *sta)
+static void __cleanup_single_sta(struct sta_info *sta)
{
int ac, i;
struct tid_ampdu_tx *tid_tx;
@@ -99,7 +99,8 @@ static void cleanup_single_sta(struct sta_info *sta)
struct ieee80211_local *local = sdata->local;
struct ps_data *ps;
- if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
+ if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
+ test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ps = &sdata->bss->ps;
@@ -109,6 +110,7 @@ static void cleanup_single_sta(struct sta_info *sta)
return;
clear_sta_flag(sta, WLAN_STA_PS_STA);
+ clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
atomic_dec(&ps->num_sta_ps);
sta_info_recalc_tim(sta);
@@ -139,7 +141,14 @@ static void cleanup_single_sta(struct sta_info *sta)
ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
kfree(tid_tx);
}
+}
+static void cleanup_single_sta(struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct ieee80211_local *local = sdata->local;
+
+ __cleanup_single_sta(sta);
sta_info_free(local, sta);
}
@@ -330,6 +339,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
spin_lock_init(&sta->lock);
+ spin_lock_init(&sta->ps_lock);
INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
mutex_init(&sta->ampdu_mlme.mtx);
@@ -487,21 +497,26 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
goto out_err;
}
- /* notify driver */
- err = sta_info_insert_drv_state(local, sdata, sta);
- if (err)
- goto out_err;
-
local->num_sta++;
local->sta_generation++;
smp_mb();
+ /* simplify things and don't accept BA sessions yet */
+ set_sta_flag(sta, WLAN_STA_BLOCK_BA);
+
/* make the station visible */
sta_info_hash_add(local, sta);
list_add_rcu(&sta->list, &local->sta_list);
+ /* notify driver */
+ err = sta_info_insert_drv_state(local, sdata, sta);
+ if (err)
+ goto out_remove;
+
set_sta_flag(sta, WLAN_STA_INSERTED);
+ /* accept BA sessions now */
+ clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
ieee80211_recalc_min_chandef(sdata);
ieee80211_sta_debugfs_add(sta);
@@ -522,6 +537,12 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
mesh_accept_plinks_update(sdata);
return 0;
+ out_remove:
+ sta_info_hash_del(local, sta);
+ list_del_rcu(&sta->list);
+ local->num_sta--;
+ synchronize_net();
+ __cleanup_single_sta(sta);
out_err:
mutex_unlock(&local->sta_mtx);
rcu_read_lock();
@@ -1071,10 +1092,14 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
}
EXPORT_SYMBOL(ieee80211_find_sta);
-static void clear_sta_ps_flags(void *_sta)
+/* powersave support code */
+void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
{
- struct sta_info *sta = _sta;
struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct ieee80211_local *local = sdata->local;
+ struct sk_buff_head pending;
+ int filtered = 0, buffered = 0, ac;
+ unsigned long flags;
struct ps_data *ps;
if (sdata->vif.type == NL80211_IFTYPE_AP ||
@@ -1085,20 +1110,6 @@ static void clear_sta_ps_flags(void *_sta)
else
return;
- clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
- if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA))
- atomic_dec(&ps->num_sta_ps);
-}
-
-/* powersave support code */
-void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
-{
- struct ieee80211_sub_if_data *sdata = sta->sdata;
- struct ieee80211_local *local = sdata->local;
- struct sk_buff_head pending;
- int filtered = 0, buffered = 0, ac;
- unsigned long flags;
-
clear_sta_flag(sta, WLAN_STA_SP);
BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1);
@@ -1109,6 +1120,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
skb_queue_head_init(&pending);
+ /* sync with ieee80211_tx_h_unicast_ps_buf */
+ spin_lock(&sta->ps_lock);
/* Send all buffered frames to the station */
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
int count = skb_queue_len(&pending), tmp;
@@ -1127,7 +1140,12 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
buffered += tmp - count;
}
- ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
+ ieee80211_add_pending_skbs(local, &pending);
+ clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+ clear_sta_flag(sta, WLAN_STA_PS_STA);
+ spin_unlock(&sta->ps_lock);
+
+ atomic_dec(&ps->num_sta_ps);
/* This station just woke up and isn't aware of our SMPS state */
if (!ieee80211_smps_is_restrictive(sta->known_smps_mode,
@@ -1188,6 +1206,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
+ nullfunc->seq_ctrl = 0;
skb->priority = tid;
skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index d77ff7090630..d3a6d8208f2f 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -267,6 +267,7 @@ struct ieee80211_tx_latency_stat {
* @drv_unblock_wk: used for driver PS unblocking
* @listen_interval: listen interval of this station, when we're acting as AP
* @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
+ * @ps_lock: used for powersave (when mac80211 is the AP) related locking
* @ps_tx_buf: buffers (per AC) of frames to transmit to this station
* when it leaves power saving state or polls
* @tx_filtered: buffers (per AC) of frames we already tried to
@@ -356,10 +357,8 @@ struct sta_info {
/* use the accessors defined below */
unsigned long _flags;
- /*
- * STA powersave frame queues, no more than the internal
- * locking required.
- */
+ /* STA powersave lock and frame queues */
+ spinlock_t ps_lock;
struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
unsigned long driver_buffered_tids;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 97a02d3f7d87..4080c615636f 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -478,6 +478,20 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
sta->sta.addr, sta->sta.aid, ac);
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
purge_old_ps_buffers(tx->local);
+
+ /* sync with ieee80211_sta_ps_deliver_wakeup */
+ spin_lock(&sta->ps_lock);
+ /*
+ * STA woke up the meantime and all the frames on ps_tx_buf have
+ * been queued to pending queue. No reordering can happen, go
+ * ahead and Tx the packet.
+ */
+ if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
+ !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
+ spin_unlock(&sta->ps_lock);
+ return TX_CONTINUE;
+ }
+
if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
ps_dbg(tx->sdata,
@@ -492,6 +506,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
+ spin_unlock(&sta->ps_lock);
if (!timer_pending(&local->sta_cleanup))
mod_timer(&local->sta_cleanup,
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 676dc0967f37..b8700d417a9c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}
-void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
- struct sk_buff_head *skbs,
- void (*fn)(void *data), void *data)
+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+ struct sk_buff_head *skbs)
{
struct ieee80211_hw *hw = &local->hw;
struct sk_buff *skb;
@@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
__skb_queue_tail(&local->pending[queue], skb);
}
- if (fn)
- fn(data);
-
for (i = 0; i < hw->queues; i++)
__ieee80211_wake_queue(hw, i,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
@@ -1741,6 +1737,26 @@ int ieee80211_reconfig(struct ieee80211_local *local)
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
/*
+ * Reconfigure sched scan if it was interrupted by FW restart or
+ * suspend.
+ */
+ mutex_lock(&local->mtx);
+ sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
+ lockdep_is_held(&local->mtx));
+ if (sched_scan_sdata && local->sched_scan_req)
+ /*
+ * Sched scan stopped, but we don't want to report it. Instead,
+ * we're trying to reschedule.
+ */
+ if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
+ local->sched_scan_req))
+ sched_scan_stopped = true;
+ mutex_unlock(&local->mtx);
+
+ if (sched_scan_stopped)
+ cfg80211_sched_scan_stopped(local->hw.wiphy);
+
+ /*
* If this is for hw restart things are still running.
* We may want to change that later, however.
*/
@@ -1768,26 +1784,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
WARN_ON(1);
#endif
- /*
- * Reconfigure sched scan if it was interrupted by FW restart or
- * suspend.
- */
- mutex_lock(&local->mtx);
- sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
- lockdep_is_held(&local->mtx));
- if (sched_scan_sdata && local->sched_scan_req)
- /*
- * Sched scan stopped, but we don't want to report it. Instead,
- * we're trying to reschedule.
- */
- if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
- local->sched_scan_req))
- sched_scan_stopped = true;
- mutex_unlock(&local->mtx);
-
- if (sched_scan_stopped)
- cfg80211_sched_scan_stopped(local->hw.wiphy);
-
return 0;
}
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 21211c60ca98..d51422c778de 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -154,6 +154,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
return IEEE80211_AC_BE;
}
+ if (skb->protocol == sdata->control_port_protocol) {
+ skb->priority = 7;
+ return ieee80211_downgrade_queue(sdata, skb);
+ }
+
/* use the data classifier to determine what 802.1d tag the
* data frame has */
rcu_read_lock();
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index bb322d0beb48..b9f0e0374322 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1310,27 +1310,22 @@ ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[])
}
static int
-ctnetlink_change_nat(struct nf_conn *ct, const struct nlattr * const cda[])
+ctnetlink_setup_nat(struct nf_conn *ct, const struct nlattr * const cda[])
{
#ifdef CONFIG_NF_NAT_NEEDED
int ret;
- if (cda[CTA_NAT_DST]) {
- ret = ctnetlink_parse_nat_setup(ct,
- NF_NAT_MANIP_DST,
- cda[CTA_NAT_DST]);
- if (ret < 0)
- return ret;
- }
- if (cda[CTA_NAT_SRC]) {
- ret = ctnetlink_parse_nat_setup(ct,
- NF_NAT_MANIP_SRC,
- cda[CTA_NAT_SRC]);
- if (ret < 0)
- return ret;
- }
- return 0;
+ ret = ctnetlink_parse_nat_setup(ct, NF_NAT_MANIP_DST,
+ cda[CTA_NAT_DST]);
+ if (ret < 0)
+ return ret;
+
+ ret = ctnetlink_parse_nat_setup(ct, NF_NAT_MANIP_SRC,
+ cda[CTA_NAT_SRC]);
+ return ret;
#else
+ if (!cda[CTA_NAT_DST] && !cda[CTA_NAT_SRC])
+ return 0;
return -EOPNOTSUPP;
#endif
}
@@ -1659,11 +1654,9 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
goto err2;
}
- if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
- err = ctnetlink_change_nat(ct, cda);
- if (err < 0)
- goto err2;
- }
+ err = ctnetlink_setup_nat(ct, cda);
+ if (err < 0)
+ goto err2;
nf_ct_acct_ext_add(ct, GFP_ATOMIC);
nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index d3f5cd6dd962..52ca952b802c 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -432,15 +432,15 @@ nf_nat_setup_info(struct nf_conn *ct,
}
EXPORT_SYMBOL(nf_nat_setup_info);
-unsigned int
-nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
+static unsigned int
+__nf_nat_alloc_null_binding(struct nf_conn *ct, enum nf_nat_manip_type manip)
{
/* Force range to this IP; let proto decide mapping for
* per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
* Use reply in case it's already been mangled (eg local packet).
*/
union nf_inet_addr ip =
- (HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ?
+ (manip == NF_NAT_MANIP_SRC ?
ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3 :
ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3);
struct nf_nat_range range = {
@@ -448,7 +448,13 @@ nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
.min_addr = ip,
.max_addr = ip,
};
- return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
+ return nf_nat_setup_info(ct, &range, manip);
+}
+
+unsigned int
+nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
+{
+ return __nf_nat_alloc_null_binding(ct, HOOK2MANIP(hooknum));
}
EXPORT_SYMBOL_GPL(nf_nat_alloc_null_binding);
@@ -702,9 +708,9 @@ static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
static int
nfnetlink_parse_nat(const struct nlattr *nat,
- const struct nf_conn *ct, struct nf_nat_range *range)
+ const struct nf_conn *ct, struct nf_nat_range *range,
+ const struct nf_nat_l3proto *l3proto)
{
- const struct nf_nat_l3proto *l3proto;
struct nlattr *tb[CTA_NAT_MAX+1];
int err;
@@ -714,38 +720,46 @@ nfnetlink_parse_nat(const struct nlattr *nat,
if (err < 0)
return err;
- rcu_read_lock();
- l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
- if (l3proto == NULL) {
- err = -EAGAIN;
- goto out;
- }
err = l3proto->nlattr_to_range(tb, range);
if (err < 0)
- goto out;
+ return err;
if (!tb[CTA_NAT_PROTO])
- goto out;
+ return 0;
- err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
-out:
- rcu_read_unlock();
- return err;
+ return nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
}
+/* This function is called under rcu_read_lock() */
static int
nfnetlink_parse_nat_setup(struct nf_conn *ct,
enum nf_nat_manip_type manip,
const struct nlattr *attr)
{
struct nf_nat_range range;
+ const struct nf_nat_l3proto *l3proto;
int err;
- err = nfnetlink_parse_nat(attr, ct, &range);
+ /* Should not happen, restricted to creating new conntracks
+ * via ctnetlink.
+ */
+ if (WARN_ON_ONCE(nf_nat_initialized(ct, manip)))
+ return -EEXIST;
+
+ /* Make sure that L3 NAT is there by when we call nf_nat_setup_info to
+ * attach the null binding, otherwise this may oops.
+ */
+ l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
+ if (l3proto == NULL)
+ return -EAGAIN;
+
+ /* No NAT information has been passed, allocate the null-binding */
+ if (attr == NULL)
+ return __nf_nat_alloc_null_binding(ct, manip);
+
+ err = nfnetlink_parse_nat(attr, ct, &range, l3proto);
if (err < 0)
return err;
- if (nf_nat_initialized(ct, manip))
- return -EEXIST;
return nf_nat_setup_info(ct, &range, manip);
}
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
index f072fe803510..108120f216b1 100644
--- a/net/netfilter/nfnetlink_queue_core.c
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -354,13 +354,16 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
skb = nfnetlink_alloc_skb(net, size, queue->peer_portid,
GFP_ATOMIC);
- if (!skb)
+ if (!skb) {
+ skb_tx_error(entskb);
return NULL;
+ }
nlh = nlmsg_put(skb, 0, 0,
NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
sizeof(struct nfgenmsg), 0);
if (!nlh) {
+ skb_tx_error(entskb);
kfree_skb(skb);
return NULL;
}
@@ -488,13 +491,15 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
nla->nla_type = NFQA_PAYLOAD;
nla->nla_len = nla_attr_size(data_len);
- skb_zerocopy(skb, entskb, data_len, hlen);
+ if (skb_zerocopy(skb, entskb, data_len, hlen))
+ goto nla_put_failure;
}
nlh->nlmsg_len = skb->len;
return skb;
nla_put_failure:
+ skb_tx_error(entskb);
kfree_skb(skb);
net_err_ratelimited("nf_queue: error creating packet message\n");
return NULL;
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index e8254ad2e5a9..425cf39af890 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -116,7 +116,7 @@ static void nft_meta_get_eval(const struct nft_expr *expr,
skb->sk->sk_socket->file->f_cred->fsgid);
read_unlock_bh(&skb->sk->sk_callback_lock);
break;
-#ifdef CONFIG_NET_CLS_ROUTE
+#ifdef CONFIG_IP_ROUTE_CLASSID
case NFT_META_RTCLASSID: {
const struct dst_entry *dst = skb_dst(skb);
@@ -199,7 +199,7 @@ static int nft_meta_init_validate_get(uint32_t key)
case NFT_META_OIFTYPE:
case NFT_META_SKUID:
case NFT_META_SKGID:
-#ifdef CONFIG_NET_CLS_ROUTE
+#ifdef CONFIG_IP_ROUTE_CLASSID
case NFT_META_RTCLASSID:
#endif
#ifdef CONFIG_NETWORK_SECMARK
diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
index a2aeb318678f..85daa84bfdfe 100644
--- a/net/netfilter/nft_payload.c
+++ b/net/netfilter/nft_payload.c
@@ -135,7 +135,8 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
if (len == 0 || len > FIELD_SIZEOF(struct nft_data, data))
return ERR_PTR(-EINVAL);
- if (len <= 4 && IS_ALIGNED(offset, len) && base != NFT_PAYLOAD_LL_HEADER)
+ if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) &&
+ base != NFT_PAYLOAD_LL_HEADER)
return &nft_payload_fast_ops;
else
return &nft_payload_ops;
diff --git a/net/netfilter/nft_reject_inet.c b/net/netfilter/nft_reject_inet.c
index 8a310f239c93..b718a52a4654 100644
--- a/net/netfilter/nft_reject_inet.c
+++ b/net/netfilter/nft_reject_inet.c
@@ -21,9 +21,9 @@ static void nft_reject_inet_eval(const struct nft_expr *expr,
{
switch (pkt->ops->pf) {
case NFPROTO_IPV4:
- nft_reject_ipv4_eval(expr, data, pkt);
+ return nft_reject_ipv4_eval(expr, data, pkt);
case NFPROTO_IPV6:
- nft_reject_ipv6_eval(expr, data, pkt);
+ return nft_reject_ipv6_eval(expr, data, pkt);
}
}
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index fdf51353cf78..04748ab649c2 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1489,8 +1489,8 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
if (addr->sa_family != AF_NETLINK)
return -EINVAL;
- /* Only superuser is allowed to send multicasts */
- if (nladdr->nl_groups && !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
+ if ((nladdr->nl_groups || nladdr->nl_pid) &&
+ !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
return -EPERM;
if (!nlk->portid)
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 46bda010bf11..56db888b1cd5 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -301,7 +301,7 @@ static int nci_open_device(struct nci_dev *ndev)
rc = __nci_request(ndev, nci_reset_req, 0,
msecs_to_jiffies(NCI_RESET_TIMEOUT));
- if (ndev->ops->setup(ndev))
+ if (ndev->ops->setup)
ndev->ops->setup(ndev);
if (!rc) {
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index e9a48baf8551..270b77dfac30 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -464,7 +464,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
}
nla->nla_len = nla_attr_size(skb->len);
- skb_zerocopy(user_skb, skb, skb->len, hlen);
+ err = skb_zerocopy(user_skb, skb, skb->len, hlen);
+ if (err)
+ goto out;
/* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */
if (!(dp->user_features & OVS_DP_F_UNALIGNED)) {
@@ -478,6 +480,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid);
out:
+ if (err)
+ skb_tx_error(skb);
kfree_skb(nskb);
return err;
}
@@ -1174,7 +1178,7 @@ static void ovs_dp_reset_user_features(struct sk_buff *skb, struct genl_info *in
struct datapath *dp;
dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
- if (!dp)
+ if (IS_ERR(dp))
return;
WARN(dp->user_features, "Dropping previously announced user features\n");
@@ -1762,11 +1766,12 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
int bucket = cb->args[0], skip = cb->args[1];
int i, j = 0;
+ rcu_read_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
- if (!dp)
+ if (!dp) {
+ rcu_read_unlock();
return -ENODEV;
-
- rcu_read_lock();
+ }
for (i = bucket; i < DP_VPORT_HASH_BUCKETS; i++) {
struct vport *vport;
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index 16f4b46161d4..2998989e76db 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -73,6 +73,7 @@ void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb)
if ((flow->key.eth.type == htons(ETH_P_IP) ||
flow->key.eth.type == htons(ETH_P_IPV6)) &&
+ flow->key.ip.frag != OVS_FRAG_TYPE_LATER &&
flow->key.ip.proto == IPPROTO_TCP &&
likely(skb->len >= skb_transport_offset(skb) + sizeof(struct tcphdr))) {
tcp_flags = TCP_FLAGS_BE16(tcp_hdr(skb));
@@ -91,7 +92,7 @@ static void stats_read(struct flow_stats *stats,
unsigned long *used, __be16 *tcp_flags)
{
spin_lock(&stats->lock);
- if (time_after(stats->used, *used))
+ if (!*used || time_after(stats->used, *used))
*used = stats->used;
*tcp_flags |= stats->tcp_flags;
ovs_stats->n_packets += stats->packet_count;
@@ -102,30 +103,24 @@ static void stats_read(struct flow_stats *stats,
void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
unsigned long *used, __be16 *tcp_flags)
{
- int cpu, cur_cpu;
+ int cpu;
*used = 0;
*tcp_flags = 0;
memset(ovs_stats, 0, sizeof(*ovs_stats));
+ local_bh_disable();
if (!flow->stats.is_percpu) {
stats_read(flow->stats.stat, ovs_stats, used, tcp_flags);
} else {
- cur_cpu = get_cpu();
for_each_possible_cpu(cpu) {
struct flow_stats *stats;
- if (cpu == cur_cpu)
- local_bh_disable();
-
stats = per_cpu_ptr(flow->stats.cpu_stats, cpu);
stats_read(stats, ovs_stats, used, tcp_flags);
-
- if (cpu == cur_cpu)
- local_bh_enable();
}
- put_cpu();
}
+ local_bh_enable();
}
static void stats_reset(struct flow_stats *stats)
@@ -140,25 +135,17 @@ static void stats_reset(struct flow_stats *stats)
void ovs_flow_stats_clear(struct sw_flow *flow)
{
- int cpu, cur_cpu;
+ int cpu;
+ local_bh_disable();
if (!flow->stats.is_percpu) {
stats_reset(flow->stats.stat);
} else {
- cur_cpu = get_cpu();
-
for_each_possible_cpu(cpu) {
-
- if (cpu == cur_cpu)
- local_bh_disable();
-
stats_reset(per_cpu_ptr(flow->stats.cpu_stats, cpu));
-
- if (cpu == cur_cpu)
- local_bh_enable();
}
- put_cpu();
}
+ local_bh_enable();
}
static int check_header(struct sk_buff *skb, int len)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 6a2bb37506c5..48a6a93db296 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -308,11 +308,27 @@ static bool packet_use_direct_xmit(const struct packet_sock *po)
return po->xmit == packet_direct_xmit;
}
-static u16 packet_pick_tx_queue(struct net_device *dev)
+static u16 __packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb)
{
return (u16) raw_smp_processor_id() % dev->real_num_tx_queues;
}
+static void packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb)
+{
+ const struct net_device_ops *ops = dev->netdev_ops;
+ u16 queue_index;
+
+ if (ops->ndo_select_queue) {
+ queue_index = ops->ndo_select_queue(dev, skb, NULL,
+ __packet_pick_tx_queue);
+ queue_index = netdev_cap_txqueue(dev, queue_index);
+ } else {
+ queue_index = __packet_pick_tx_queue(dev, skb);
+ }
+
+ skb_set_queue_mapping(skb, queue_index);
+}
+
/* register_prot_hook must be invoked with the po->bind_lock held,
* or from a context in which asynchronous accesses to the packet
* socket is not possible (packet_create()).
@@ -2285,7 +2301,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
}
}
- skb_set_queue_mapping(skb, packet_pick_tx_queue(dev));
+ packet_pick_tx_queue(dev, skb);
+
skb->destructor = tpacket_destruct_skb;
__packet_set_status(po, ph, TP_STATUS_SENDING);
packet_inc_pending(&po->tx_ring);
@@ -2499,7 +2516,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
skb->dev = dev;
skb->priority = sk->sk_priority;
skb->mark = sk->sk_mark;
- skb_set_queue_mapping(skb, packet_pick_tx_queue(dev));
+
+ packet_pick_tx_queue(dev, skb);
if (po->has_vnet_hdr) {
if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
@@ -3786,7 +3804,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
*/
if (!tx_ring)
init_prb_bdqc(po, rb, pg_vec, req_u, tx_ring);
- break;
+ break;
default:
break;
}
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 1313145e3b86..a07d55e75698 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -273,11 +273,12 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
void qdisc_list_add(struct Qdisc *q)
{
- struct Qdisc *root = qdisc_dev(q)->qdisc;
+ if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
+ struct Qdisc *root = qdisc_dev(q)->qdisc;
- WARN_ON_ONCE(root == &noop_qdisc);
- if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
+ WARN_ON_ONCE(root == &noop_qdisc);
list_add_tail(&q->list, &root->list);
+ }
}
EXPORT_SYMBOL(qdisc_list_add);
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
index 08ef7a42c0e4..21e251766eb1 100644
--- a/net/sched/sch_fq.c
+++ b/net/sched/sch_fq.c
@@ -601,6 +601,7 @@ static int fq_resize(struct Qdisc *sch, u32 log)
{
struct fq_sched_data *q = qdisc_priv(sch);
struct rb_root *array;
+ void *old_fq_root;
u32 idx;
if (q->fq_root && log == q->fq_trees_log)
@@ -615,13 +616,19 @@ static int fq_resize(struct Qdisc *sch, u32 log)
for (idx = 0; idx < (1U << log); idx++)
array[idx] = RB_ROOT;
- if (q->fq_root) {
- fq_rehash(q, q->fq_root, q->fq_trees_log, array, log);
- fq_free(q->fq_root);
- }
+ sch_tree_lock(sch);
+
+ old_fq_root = q->fq_root;
+ if (old_fq_root)
+ fq_rehash(q, old_fq_root, q->fq_trees_log, array, log);
+
q->fq_root = array;
q->fq_trees_log = log;
+ sch_tree_unlock(sch);
+
+ fq_free(old_fq_root);
+
return 0;
}
@@ -697,9 +704,11 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
q->flow_refill_delay = usecs_to_jiffies(usecs_delay);
}
- if (!err)
+ if (!err) {
+ sch_tree_unlock(sch);
err = fq_resize(sch, fq_log);
-
+ sch_tree_lock(sch);
+ }
while (sch->q.qlen > sch->limit) {
struct sk_buff *skb = fq_dequeue(sch);
diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c
index a255d0200a59..fefeeb73f15f 100644
--- a/net/sched/sch_pie.c
+++ b/net/sched/sch_pie.c
@@ -15,6 +15,11 @@
*
* ECN support is added by Naeem Khademi <naeemk@ifi.uio.no>
* University of Oslo, Norway.
+ *
+ * References:
+ * IETF draft submission: http://tools.ietf.org/html/draft-pan-aqm-pie-00
+ * IEEE Conference on High Performance Switching and Routing 2013 :
+ * "PIE: A * Lightweight Control Scheme to Address the Bufferbloat Problem"
*/
#include <linux/module.h>
@@ -36,7 +41,7 @@ struct pie_params {
psched_time_t target; /* user specified target delay in pschedtime */
u32 tupdate; /* timer frequency (in jiffies) */
u32 limit; /* number of packets that can be enqueued */
- u32 alpha; /* alpha and beta are between -4 and 4 */
+ u32 alpha; /* alpha and beta are between 0 and 32 */
u32 beta; /* and are used for shift relative to 1 */
bool ecn; /* true if ecn is enabled */
bool bytemode; /* to scale drop early prob based on pkt size */
@@ -326,10 +331,16 @@ static void calculate_probability(struct Qdisc *sch)
if (qdelay == 0 && qlen != 0)
update_prob = false;
- /* Add ranges for alpha and beta, more aggressive for high dropping
- * mode and gentle steps for light dropping mode
- * In light dropping mode, take gentle steps; in medium dropping mode,
- * take medium steps; in high dropping mode, take big steps.
+ /* In the algorithm, alpha and beta are between 0 and 2 with typical
+ * value for alpha as 0.125. In this implementation, we use values 0-32
+ * passed from user space to represent this. Also, alpha and beta have
+ * unit of HZ and need to be scaled before they can used to update
+ * probability. alpha/beta are updated locally below by 1) scaling them
+ * appropriately 2) scaling down by 16 to come to 0-2 range.
+ * Please see paper for details.
+ *
+ * We scale alpha and beta differently depending on whether we are in
+ * light, medium or high dropping mode.
*/
if (q->vars.prob < MAX_PROB / 100) {
alpha =
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 1cb413fead89..4f505a006896 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -334,18 +334,6 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
qdisc_put_rtab(qdisc_get_rtab(&qopt->peakrate,
tb[TCA_TBF_PTAB]));
- if (q->qdisc != &noop_qdisc) {
- err = fifo_set_limit(q->qdisc, qopt->limit);
- if (err)
- goto done;
- } else if (qopt->limit > 0) {
- child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
- if (IS_ERR(child)) {
- err = PTR_ERR(child);
- goto done;
- }
- }
-
buffer = min_t(u64, PSCHED_TICKS2NS(qopt->buffer), ~0U);
mtu = min_t(u64, PSCHED_TICKS2NS(qopt->mtu), ~0U);
@@ -390,6 +378,18 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
goto done;
}
+ if (q->qdisc != &noop_qdisc) {
+ err = fifo_set_limit(q->qdisc, qopt->limit);
+ if (err)
+ goto done;
+ } else if (qopt->limit > 0) {
+ child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
+ if (IS_ERR(child)) {
+ err = PTR_ERR(child);
+ goto done;
+ }
+ }
+
sch_tree_lock(sch);
if (child) {
qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5ae609200674..ee13d28d39d1 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -1239,78 +1239,107 @@ void sctp_assoc_update(struct sctp_association *asoc,
}
/* Update the retran path for sending a retransmitted packet.
- * Round-robin through the active transports, else round-robin
- * through the inactive transports as this is the next best thing
- * we can try.
+ * See also RFC4960, 6.4. Multi-Homed SCTP Endpoints:
+ *
+ * When there is outbound data to send and the primary path
+ * becomes inactive (e.g., due to failures), or where the
+ * SCTP user explicitly requests to send data to an
+ * inactive destination transport address, before reporting
+ * an error to its ULP, the SCTP endpoint should try to send
+ * the data to an alternate active destination transport
+ * address if one exists.
+ *
+ * When retransmitting data that timed out, if the endpoint
+ * is multihomed, it should consider each source-destination
+ * address pair in its retransmission selection policy.
+ * When retransmitting timed-out data, the endpoint should
+ * attempt to pick the most divergent source-destination
+ * pair from the original source-destination pair to which
+ * the packet was transmitted.
+ *
+ * Note: Rules for picking the most divergent source-destination
+ * pair are an implementation decision and are not specified
+ * within this document.
+ *
+ * Our basic strategy is to round-robin transports in priorities
+ * according to sctp_state_prio_map[] e.g., if no such
+ * transport with state SCTP_ACTIVE exists, round-robin through
+ * SCTP_UNKNOWN, etc. You get the picture.
*/
-void sctp_assoc_update_retran_path(struct sctp_association *asoc)
+static const u8 sctp_trans_state_to_prio_map[] = {
+ [SCTP_ACTIVE] = 3, /* best case */
+ [SCTP_UNKNOWN] = 2,
+ [SCTP_PF] = 1,
+ [SCTP_INACTIVE] = 0, /* worst case */
+};
+
+static u8 sctp_trans_score(const struct sctp_transport *trans)
{
- struct sctp_transport *t, *next;
- struct list_head *head = &asoc->peer.transport_addr_list;
- struct list_head *pos;
+ return sctp_trans_state_to_prio_map[trans->state];
+}
- if (asoc->peer.transport_count == 1)
- return;
+static struct sctp_transport *sctp_trans_elect_best(struct sctp_transport *curr,
+ struct sctp_transport *best)
+{
+ if (best == NULL)
+ return curr;
- /* Find the next transport in a round-robin fashion. */
- t = asoc->peer.retran_path;
- pos = &t->transports;
- next = NULL;
+ return sctp_trans_score(curr) > sctp_trans_score(best) ? curr : best;
+}
- while (1) {
- /* Skip the head. */
- if (pos->next == head)
- pos = head->next;
- else
- pos = pos->next;
+void sctp_assoc_update_retran_path(struct sctp_association *asoc)
+{
+ struct sctp_transport *trans = asoc->peer.retran_path;
+ struct sctp_transport *trans_next = NULL;
- t = list_entry(pos, struct sctp_transport, transports);
+ /* We're done as we only have the one and only path. */
+ if (asoc->peer.transport_count == 1)
+ return;
+ /* If active_path and retran_path are the same and active,
+ * then this is the only active path. Use it.
+ */
+ if (asoc->peer.active_path == asoc->peer.retran_path &&
+ asoc->peer.active_path->state == SCTP_ACTIVE)
+ return;
- /* We have exhausted the list, but didn't find any
- * other active transports. If so, use the next
- * transport.
- */
- if (t == asoc->peer.retran_path) {
- t = next;
+ /* Iterate from retran_path's successor back to retran_path. */
+ for (trans = list_next_entry(trans, transports); 1;
+ trans = list_next_entry(trans, transports)) {
+ /* Manually skip the head element. */
+ if (&trans->transports == &asoc->peer.transport_addr_list)
+ continue;
+ if (trans->state == SCTP_UNCONFIRMED)
+ continue;
+ trans_next = sctp_trans_elect_best(trans, trans_next);
+ /* Active is good enough for immediate return. */
+ if (trans_next->state == SCTP_ACTIVE)
break;
- }
-
- /* Try to find an active transport. */
-
- if ((t->state == SCTP_ACTIVE) ||
- (t->state == SCTP_UNKNOWN)) {
+ /* We've reached the end, time to update path. */
+ if (trans == asoc->peer.retran_path)
break;
- } else {
- /* Keep track of the next transport in case
- * we don't find any active transport.
- */
- if (t->state != SCTP_UNCONFIRMED && !next)
- next = t;
- }
}
- if (t)
- asoc->peer.retran_path = t;
- else
- t = asoc->peer.retran_path;
+ if (trans_next != NULL)
+ asoc->peer.retran_path = trans_next;
- pr_debug("%s: association:%p addr:%pISpc\n", __func__, asoc,
- &t->ipaddr.sa);
+ pr_debug("%s: association:%p updated new path to addr:%pISpc\n",
+ __func__, asoc, &asoc->peer.retran_path->ipaddr.sa);
}
-/* Choose the transport for sending retransmit packet. */
-struct sctp_transport *sctp_assoc_choose_alter_transport(
- struct sctp_association *asoc, struct sctp_transport *last_sent_to)
+struct sctp_transport *
+sctp_assoc_choose_alter_transport(struct sctp_association *asoc,
+ struct sctp_transport *last_sent_to)
{
/* If this is the first time packet is sent, use the active path,
* else use the retran path. If the last packet was sent over the
* retran path, update the retran path and use it.
*/
- if (!last_sent_to)
+ if (last_sent_to == NULL) {
return asoc->peer.active_path;
- else {
+ } else {
if (last_sent_to == asoc->peer.retran_path)
sctp_assoc_update_retran_path(asoc);
+
return asoc->peer.retran_path;
}
}
@@ -1367,44 +1396,35 @@ static inline bool sctp_peer_needs_update(struct sctp_association *asoc)
return false;
}
-/* Increase asoc's rwnd by len and send any window update SACK if needed. */
-void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len)
+/* Update asoc's rwnd for the approximated state in the buffer,
+ * and check whether SACK needs to be sent.
+ */
+void sctp_assoc_rwnd_update(struct sctp_association *asoc, bool update_peer)
{
+ int rx_count;
struct sctp_chunk *sack;
struct timer_list *timer;
- if (asoc->rwnd_over) {
- if (asoc->rwnd_over >= len) {
- asoc->rwnd_over -= len;
- } else {
- asoc->rwnd += (len - asoc->rwnd_over);
- asoc->rwnd_over = 0;
- }
- } else {
- asoc->rwnd += len;
- }
+ if (asoc->ep->rcvbuf_policy)
+ rx_count = atomic_read(&asoc->rmem_alloc);
+ else
+ rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc);
- /* If we had window pressure, start recovering it
- * once our rwnd had reached the accumulated pressure
- * threshold. The idea is to recover slowly, but up
- * to the initial advertised window.
- */
- if (asoc->rwnd_press && asoc->rwnd >= asoc->rwnd_press) {
- int change = min(asoc->pathmtu, asoc->rwnd_press);
- asoc->rwnd += change;
- asoc->rwnd_press -= change;
- }
+ if ((asoc->base.sk->sk_rcvbuf - rx_count) > 0)
+ asoc->rwnd = (asoc->base.sk->sk_rcvbuf - rx_count) >> 1;
+ else
+ asoc->rwnd = 0;
- pr_debug("%s: asoc:%p rwnd increased by %d to (%u, %u) - %u\n",
- __func__, asoc, len, asoc->rwnd, asoc->rwnd_over,
- asoc->a_rwnd);
+ pr_debug("%s: asoc:%p rwnd=%u, rx_count=%d, sk_rcvbuf=%d\n",
+ __func__, asoc, asoc->rwnd, rx_count,
+ asoc->base.sk->sk_rcvbuf);
/* Send a window update SACK if the rwnd has increased by at least the
* minimum of the association's PMTU and half of the receive buffer.
* The algorithm used is similar to the one described in
* Section 4.2.3.3 of RFC 1122.
*/
- if (sctp_peer_needs_update(asoc)) {
+ if (update_peer && sctp_peer_needs_update(asoc)) {
asoc->a_rwnd = asoc->rwnd;
pr_debug("%s: sending window update SACK- asoc:%p rwnd:%u "
@@ -1426,45 +1446,6 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len)
}
}
-/* Decrease asoc's rwnd by len. */
-void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned int len)
-{
- int rx_count;
- int over = 0;
-
- if (unlikely(!asoc->rwnd || asoc->rwnd_over))
- pr_debug("%s: association:%p has asoc->rwnd:%u, "
- "asoc->rwnd_over:%u!\n", __func__, asoc,
- asoc->rwnd, asoc->rwnd_over);
-
- if (asoc->ep->rcvbuf_policy)
- rx_count = atomic_read(&asoc->rmem_alloc);
- else
- rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc);
-
- /* If we've reached or overflowed our receive buffer, announce
- * a 0 rwnd if rwnd would still be positive. Store the
- * the potential pressure overflow so that the window can be restored
- * back to original value.
- */
- if (rx_count >= asoc->base.sk->sk_rcvbuf)
- over = 1;
-
- if (asoc->rwnd >= len) {
- asoc->rwnd -= len;
- if (over) {
- asoc->rwnd_press += asoc->rwnd;
- asoc->rwnd = 0;
- }
- } else {
- asoc->rwnd_over = len - asoc->rwnd;
- asoc->rwnd = 0;
- }
-
- pr_debug("%s: asoc:%p rwnd decreased by %d to (%u, %u, %u)\n",
- __func__, asoc, len, asoc->rwnd, asoc->rwnd_over,
- asoc->rwnd_press);
-}
/* Build the bind address list for the association based on info from the
* local endpoint and the remote peer.
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 632090b961c3..3a1767ef3201 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1421,8 +1421,8 @@ static void sctp_chunk_destroy(struct sctp_chunk *chunk)
BUG_ON(!list_empty(&chunk->list));
list_del_init(&chunk->transmitted_list);
- /* Free the chunk skb data and the SCTP_chunk stub itself. */
- dev_kfree_skb(chunk->skb);
+ consume_skb(chunk->skb);
+ consume_skb(chunk->auth_chunk);
SCTP_DBG_OBJCNT_DEC(chunk);
kmem_cache_free(sctp_chunk_cachep, chunk);
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index bd859154000e..5d6883ff00c3 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -495,11 +495,12 @@ static void sctp_do_8_2_transport_strike(sctp_cmd_seq_t *commands,
}
/* If the transport error count is greater than the pf_retrans
- * threshold, and less than pathmaxrtx, then mark this transport
- * as Partially Failed, ee SCTP Quick Failover Draft, secon 5.1,
- * point 1
+ * threshold, and less than pathmaxrtx, and if the current state
+ * is not SCTP_UNCONFIRMED, then mark this transport as Partially
+ * Failed, see SCTP Quick Failover Draft, section 5.1
*/
if ((transport->state != SCTP_PF) &&
+ (transport->state != SCTP_UNCONFIRMED) &&
(asoc->pf_retrans < transport->pathmaxrxt) &&
(transport->error_count > asoc->pf_retrans)) {
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 483dcd71b3c5..01e002430c85 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -758,6 +758,12 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
struct sctp_chunk auth;
sctp_ierror_t ret;
+ /* Make sure that we and the peer are AUTH capable */
+ if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) {
+ sctp_association_free(new_asoc);
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+ }
+
/* set-up our fake chunk so that we can process it */
auth.skb = chunk->auth_chunk;
auth.asoc = chunk->asoc;
@@ -768,10 +774,6 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
auth.transport = chunk->transport;
ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth);
-
- /* We can now safely free the auth_chunk clone */
- kfree_skb(chunk->auth_chunk);
-
if (ret != SCTP_IERROR_NO_ERROR) {
sctp_association_free(new_asoc);
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
@@ -6176,7 +6178,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
* PMTU. In cases, such as loopback, this might be a rather
* large spill over.
*/
- if ((!chunk->data_accepted) && (!asoc->rwnd || asoc->rwnd_over ||
+ if ((!chunk->data_accepted) && (!asoc->rwnd ||
(datalen > asoc->rwnd + asoc->frag_point))) {
/* If this is the next TSN, consider reneging to make
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 9e91d6e5df63..981aaf8b6ace 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -64,6 +64,7 @@
#include <linux/crypto.h>
#include <linux/slab.h>
#include <linux/file.h>
+#include <linux/compat.h>
#include <net/ip.h>
#include <net/icmp.h>
@@ -1368,11 +1369,19 @@ static int sctp_setsockopt_connectx(struct sock *sk,
/*
* New (hopefully final) interface for the API.
* We use the sctp_getaddrs_old structure so that use-space library
- * can avoid any unnecessary allocations. The only defferent part
+ * can avoid any unnecessary allocations. The only different part
* is that we store the actual length of the address buffer into the
- * addrs_num structure member. That way we can re-use the existing
+ * addrs_num structure member. That way we can re-use the existing
* code.
*/
+#ifdef CONFIG_COMPAT
+struct compat_sctp_getaddrs_old {
+ sctp_assoc_t assoc_id;
+ s32 addr_num;
+ compat_uptr_t addrs; /* struct sockaddr * */
+};
+#endif
+
static int sctp_getsockopt_connectx3(struct sock *sk, int len,
char __user *optval,
int __user *optlen)
@@ -1381,16 +1390,30 @@ static int sctp_getsockopt_connectx3(struct sock *sk, int len,
sctp_assoc_t assoc_id = 0;
int err = 0;
- if (len < sizeof(param))
- return -EINVAL;
+#ifdef CONFIG_COMPAT
+ if (is_compat_task()) {
+ struct compat_sctp_getaddrs_old param32;
- if (copy_from_user(&param, optval, sizeof(param)))
- return -EFAULT;
+ if (len < sizeof(param32))
+ return -EINVAL;
+ if (copy_from_user(&param32, optval, sizeof(param32)))
+ return -EFAULT;
- err = __sctp_setsockopt_connectx(sk,
- (struct sockaddr __user *)param.addrs,
- param.addr_num, &assoc_id);
+ param.assoc_id = param32.assoc_id;
+ param.addr_num = param32.addr_num;
+ param.addrs = compat_ptr(param32.addrs);
+ } else
+#endif
+ {
+ if (len < sizeof(param))
+ return -EINVAL;
+ if (copy_from_user(&param, optval, sizeof(param)))
+ return -EFAULT;
+ }
+ err = __sctp_setsockopt_connectx(sk, (struct sockaddr __user *)
+ param.addrs, param.addr_num,
+ &assoc_id);
if (err == 0 || err == -EINPROGRESS) {
if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
return -EFAULT;
@@ -2092,12 +2115,6 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
sctp_skb_pull(skb, copied);
skb_queue_head(&sk->sk_receive_queue, skb);
- /* When only partial message is copied to the user, increase
- * rwnd by that amount. If all the data in the skb is read,
- * rwnd is updated when the event is freed.
- */
- if (!sctp_ulpevent_is_notification(event))
- sctp_assoc_rwnd_increase(event->asoc, copied);
goto out;
} else if ((event->msg_flags & MSG_NOTIFICATION) ||
(event->msg_flags & MSG_EOR))
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index 7135e617ab0f..35c8923b5554 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -151,6 +151,7 @@ static struct ctl_table sctp_net_table[] = {
},
{
.procname = "cookie_hmac_alg",
+ .data = &init_net.sctp.sctp_hmac_alg,
.maxlen = 8,
.mode = 0644,
.proc_handler = proc_sctp_do_hmac_alg,
@@ -401,15 +402,18 @@ static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write,
int sctp_sysctl_net_register(struct net *net)
{
- struct ctl_table *table;
- int i;
+ struct ctl_table *table = sctp_net_table;
+
+ if (!net_eq(net, &init_net)) {
+ int i;
- table = kmemdup(sctp_net_table, sizeof(sctp_net_table), GFP_KERNEL);
- if (!table)
- return -ENOMEM;
+ table = kmemdup(sctp_net_table, sizeof(sctp_net_table), GFP_KERNEL);
+ if (!table)
+ return -ENOMEM;
- for (i = 0; table[i].data; i++)
- table[i].data += (char *)(&net->sctp) - (char *)&init_net.sctp;
+ for (i = 0; table[i].data; i++)
+ table[i].data += (char *)(&net->sctp) - (char *)&init_net.sctp;
+ }
net->sctp.sysctl_header = register_net_sysctl(net, "net/sctp", table);
return 0;
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 85c64658bd0b..8d198ae03606 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -989,7 +989,7 @@ static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,
skb = sctp_event2skb(event);
/* Set the owner and charge rwnd for bytes received. */
sctp_ulpevent_set_owner(event, asoc);
- sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb));
+ sctp_assoc_rwnd_update(asoc, false);
if (!skb->data_len)
return;
@@ -1011,6 +1011,7 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event)
{
struct sk_buff *skb, *frag;
unsigned int len;
+ struct sctp_association *asoc;
/* Current stack structures assume that the rcv buffer is
* per socket. For UDP style sockets this is not true as
@@ -1035,8 +1036,11 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event)
}
done:
- sctp_assoc_rwnd_increase(event->asoc, len);
+ asoc = event->asoc;
+ sctp_association_hold(asoc);
sctp_ulpevent_release_owner(event);
+ sctp_assoc_rwnd_update(asoc, true);
+ sctp_association_put(asoc);
}
static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event)
diff --git a/net/socket.c b/net/socket.c
index 879933aaed4c..a19ae1968d37 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -450,16 +450,17 @@ EXPORT_SYMBOL(sockfd_lookup);
static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
{
- struct file *file;
+ struct fd f = fdget(fd);
struct socket *sock;
*err = -EBADF;
- file = fget_light(fd, fput_needed);
- if (file) {
- sock = sock_from_file(file, err);
- if (sock)
+ if (f.file) {
+ sock = sock_from_file(f.file, err);
+ if (likely(sock)) {
+ *fput_needed = f.flags;
return sock;
- fput_light(file, *fput_needed);
+ }
+ fdput(f);
}
return NULL;
}
@@ -1985,6 +1986,10 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
{
if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
return -EFAULT;
+
+ if (kmsg->msg_namelen < 0)
+ return -EINVAL;
+
if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
kmsg->msg_namelen = sizeof(struct sockaddr_storage);
return 0;
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 6c0513a7f992..36e431ee1c90 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -108,6 +108,7 @@ struct gss_auth {
static DEFINE_SPINLOCK(pipe_version_lock);
static struct rpc_wait_queue pipe_version_rpc_waitqueue;
static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
+static void gss_put_auth(struct gss_auth *gss_auth);
static void gss_free_ctx(struct gss_cl_ctx *);
static const struct rpc_pipe_ops gss_upcall_ops_v0;
@@ -320,6 +321,7 @@ gss_release_msg(struct gss_upcall_msg *gss_msg)
if (gss_msg->ctx != NULL)
gss_put_ctx(gss_msg->ctx);
rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
+ gss_put_auth(gss_msg->auth);
kfree(gss_msg);
}
@@ -498,9 +500,12 @@ gss_alloc_msg(struct gss_auth *gss_auth,
default:
err = gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name);
if (err)
- goto err_free_msg;
+ goto err_put_pipe_version;
};
+ kref_get(&gss_auth->kref);
return gss_msg;
+err_put_pipe_version:
+ put_pipe_version(gss_auth->net);
err_free_msg:
kfree(gss_msg);
err:
@@ -991,6 +996,8 @@ gss_create_new(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
if (gss_auth->service == 0)
goto err_put_mech;
+ if (!gssd_running(gss_auth->net))
+ goto err_put_mech;
auth = &gss_auth->rpc_auth;
auth->au_cslack = GSS_CRED_SLACK >> 2;
auth->au_rslack = GSS_VERF_SLACK >> 2;
@@ -1062,6 +1069,12 @@ gss_free_callback(struct kref *kref)
}
static void
+gss_put_auth(struct gss_auth *gss_auth)
+{
+ kref_put(&gss_auth->kref, gss_free_callback);
+}
+
+static void
gss_destroy(struct rpc_auth *auth)
{
struct gss_auth *gss_auth = container_of(auth,
@@ -1082,7 +1095,7 @@ gss_destroy(struct rpc_auth *auth)
gss_auth->gss_pipe[1] = NULL;
rpcauth_destroy_credcache(auth);
- kref_put(&gss_auth->kref, gss_free_callback);
+ gss_put_auth(gss_auth);
}
/*
@@ -1253,7 +1266,7 @@ gss_destroy_nullcred(struct rpc_cred *cred)
call_rcu(&cred->cr_rcu, gss_free_cred_callback);
if (ctx)
gss_put_ctx(ctx);
- kref_put(&gss_auth->kref, gss_free_callback);
+ gss_put_auth(gss_auth);
}
static void
diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c
index 890a29912d5a..e860d4f7ed2a 100644
--- a/net/sunrpc/backchannel_rqst.c
+++ b/net/sunrpc/backchannel_rqst.c
@@ -64,7 +64,6 @@ static void xprt_free_allocation(struct rpc_rqst *req)
free_page((unsigned long)xbufp->head[0].iov_base);
xbufp = &req->rq_snd_buf;
free_page((unsigned long)xbufp->head[0].iov_base);
- list_del(&req->rq_bc_pa_list);
kfree(req);
}
@@ -168,8 +167,10 @@ out_free:
/*
* Memory allocation failed, free the temporary list
*/
- list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list)
+ list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list) {
+ list_del(&req->rq_bc_pa_list);
xprt_free_allocation(req);
+ }
dprintk("RPC: setup backchannel transport failed\n");
return -ENOMEM;
@@ -198,6 +199,7 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs)
xprt_dec_alloc_count(xprt, max_reqs);
list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) {
dprintk("RPC: req=%p\n", req);
+ list_del(&req->rq_bc_pa_list);
xprt_free_allocation(req);
if (--max_reqs == 0)
break;
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 817a1e523969..0addefca8e77 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -510,6 +510,7 @@ static int xs_nospace(struct rpc_task *task)
struct rpc_rqst *req = task->tk_rqstp;
struct rpc_xprt *xprt = req->rq_xprt;
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+ struct sock *sk = transport->inet;
int ret = -EAGAIN;
dprintk("RPC: %5u xmit incomplete (%u left of %u)\n",
@@ -527,7 +528,7 @@ static int xs_nospace(struct rpc_task *task)
* window size
*/
set_bit(SOCK_NOSPACE, &transport->sock->flags);
- transport->inet->sk_write_pending++;
+ sk->sk_write_pending++;
/* ...and wait for more buffer space */
xprt_wait_for_buffer_space(task, xs_nospace_callback);
}
@@ -537,6 +538,9 @@ static int xs_nospace(struct rpc_task *task)
}
spin_unlock_bh(&xprt->transport_lock);
+
+ /* Race breaker in case memory is freed before above code is called */
+ sk->sk_write_space(sk);
return ret;
}
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index a38c89969c68..574b86193b15 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -610,8 +610,13 @@ static struct notifier_block notifier = {
int tipc_bearer_setup(void)
{
+ int err;
+
+ err = register_netdevice_notifier(&notifier);
+ if (err)
+ return err;
dev_add_pack(&tipc_packet_type);
- return register_netdevice_notifier(&notifier);
+ return 0;
}
void tipc_bearer_cleanup(void)
diff --git a/net/tipc/config.c b/net/tipc/config.c
index c301a9a592d8..e6d721692ae0 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -181,7 +181,7 @@ static struct sk_buff *cfg_set_own_addr(void)
if (tipc_own_addr)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change node address once assigned)");
- tipc_core_start_net(addr);
+ tipc_net_start(addr);
return tipc_cfg_reply_none();
}
@@ -376,7 +376,6 @@ static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr,
struct tipc_cfg_msg_hdr *req_hdr;
struct tipc_cfg_msg_hdr *rep_hdr;
struct sk_buff *rep_buf;
- int ret;
/* Validate configuration message header (ignore invalid message) */
req_hdr = (struct tipc_cfg_msg_hdr *)buf;
@@ -398,12 +397,8 @@ static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr,
memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
rep_hdr->tcm_len = htonl(rep_buf->len);
rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
-
- ret = tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data,
- rep_buf->len);
- if (ret < 0)
- pr_err("Sending cfg reply message failed, no memory\n");
-
+ tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data,
+ rep_buf->len);
kfree_skb(rep_buf);
}
}
diff --git a/net/tipc/core.c b/net/tipc/core.c
index f9e88d8b04ca..80c20647b3d2 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -77,37 +77,13 @@ struct sk_buff *tipc_buf_acquire(u32 size)
}
/**
- * tipc_core_stop_net - shut down TIPC networking sub-systems
- */
-static void tipc_core_stop_net(void)
-{
- tipc_net_stop();
- tipc_bearer_cleanup();
-}
-
-/**
- * start_net - start TIPC networking sub-systems
- */
-int tipc_core_start_net(unsigned long addr)
-{
- int res;
-
- tipc_net_start(addr);
- res = tipc_bearer_setup();
- if (res < 0)
- goto err;
- return res;
-
-err:
- tipc_core_stop_net();
- return res;
-}
-
-/**
* tipc_core_stop - switch TIPC from SINGLE NODE to NOT RUNNING mode
*/
static void tipc_core_stop(void)
{
+ tipc_handler_stop();
+ tipc_net_stop();
+ tipc_bearer_cleanup();
tipc_netlink_stop();
tipc_cfg_stop();
tipc_subscr_stop();
@@ -122,30 +98,65 @@ static void tipc_core_stop(void)
*/
static int tipc_core_start(void)
{
- int res;
+ int err;
get_random_bytes(&tipc_random, sizeof(tipc_random));
- res = tipc_handler_start();
- if (!res)
- res = tipc_ref_table_init(tipc_max_ports, tipc_random);
- if (!res)
- res = tipc_nametbl_init();
- if (!res)
- res = tipc_netlink_start();
- if (!res)
- res = tipc_socket_init();
- if (!res)
- res = tipc_register_sysctl();
- if (!res)
- res = tipc_subscr_start();
- if (!res)
- res = tipc_cfg_init();
- if (res) {
- tipc_handler_stop();
- tipc_core_stop();
- }
- return res;
+ err = tipc_handler_start();
+ if (err)
+ goto out_handler;
+
+ err = tipc_ref_table_init(tipc_max_ports, tipc_random);
+ if (err)
+ goto out_reftbl;
+
+ err = tipc_nametbl_init();
+ if (err)
+ goto out_nametbl;
+
+ err = tipc_netlink_start();
+ if (err)
+ goto out_netlink;
+
+ err = tipc_socket_init();
+ if (err)
+ goto out_socket;
+
+ err = tipc_register_sysctl();
+ if (err)
+ goto out_sysctl;
+
+ err = tipc_subscr_start();
+ if (err)
+ goto out_subscr;
+
+ err = tipc_cfg_init();
+ if (err)
+ goto out_cfg;
+
+ err = tipc_bearer_setup();
+ if (err)
+ goto out_bearer;
+
+ return 0;
+out_bearer:
+ tipc_cfg_stop();
+out_cfg:
+ tipc_subscr_stop();
+out_subscr:
+ tipc_unregister_sysctl();
+out_sysctl:
+ tipc_socket_stop();
+out_socket:
+ tipc_netlink_stop();
+out_netlink:
+ tipc_nametbl_stop();
+out_nametbl:
+ tipc_ref_table_stop();
+out_reftbl:
+ tipc_handler_stop();
+out_handler:
+ return err;
}
static int __init tipc_init(void)
@@ -174,8 +185,6 @@ static int __init tipc_init(void)
static void __exit tipc_exit(void)
{
- tipc_handler_stop();
- tipc_core_stop_net();
tipc_core_stop();
pr_info("Deactivated\n");
}
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 1ff477b0450d..4dfe137587bb 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -90,7 +90,6 @@ extern int tipc_random __read_mostly;
/*
* Routines available to privileged subsystems
*/
-int tipc_core_start_net(unsigned long);
int tipc_handler_start(void);
void tipc_handler_stop(void);
int tipc_netlink_start(void);
@@ -192,6 +191,7 @@ static inline void k_term_timer(struct timer_list *timer)
struct tipc_skb_cb {
void *handle;
+ bool deferred;
};
#define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
diff --git a/net/tipc/handler.c b/net/tipc/handler.c
index e4bc8a296744..1fabf160501f 100644
--- a/net/tipc/handler.c
+++ b/net/tipc/handler.c
@@ -58,7 +58,6 @@ unsigned int tipc_k_signal(Handler routine, unsigned long argument)
spin_lock_bh(&qitem_lock);
if (!handler_enabled) {
- pr_err("Signal request ignored by handler\n");
spin_unlock_bh(&qitem_lock);
return -ENOPROTOOPT;
}
diff --git a/net/tipc/link.c b/net/tipc/link.c
index d4b5de41b682..da6018beb6eb 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -1391,6 +1391,12 @@ static int link_recv_buf_validate(struct sk_buff *buf)
u32 hdr_size;
u32 min_hdr_size;
+ /* If this packet comes from the defer queue, the skb has already
+ * been validated
+ */
+ if (unlikely(TIPC_SKB_CB(buf)->deferred))
+ return 1;
+
if (unlikely(buf->len < MIN_H_SIZE))
return 0;
@@ -1703,6 +1709,7 @@ static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr,
&l_ptr->newest_deferred_in, buf)) {
l_ptr->deferred_inqueue_sz++;
l_ptr->stats.deferred_recv++;
+ TIPC_SKB_CB(buf)->deferred = true;
if ((l_ptr->deferred_inqueue_sz % 16) == 1)
tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
} else
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index 92a1533af4e0..042e8e3cabc0 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -941,20 +941,48 @@ int tipc_nametbl_init(void)
return 0;
}
-void tipc_nametbl_stop(void)
+/**
+ * tipc_purge_publications - remove all publications for a given type
+ *
+ * tipc_nametbl_lock must be held when calling this function
+ */
+static void tipc_purge_publications(struct name_seq *seq)
{
- u32 i;
+ struct publication *publ, *safe;
+ struct sub_seq *sseq;
+ struct name_info *info;
- if (!table.types)
+ if (!seq->sseqs) {
+ nameseq_delete_empty(seq);
return;
+ }
+ sseq = seq->sseqs;
+ info = sseq->info;
+ list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) {
+ tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node,
+ publ->ref, publ->key);
+ }
+}
+
+void tipc_nametbl_stop(void)
+{
+ u32 i;
+ struct name_seq *seq;
+ struct hlist_head *seq_head;
+ struct hlist_node *safe;
- /* Verify name table is empty, then release it */
+ /* Verify name table is empty and purge any lingering
+ * publications, then release the name table
+ */
write_lock_bh(&tipc_nametbl_lock);
for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
if (hlist_empty(&table.types[i]))
continue;
- pr_err("nametbl_stop(): orphaned hash chain detected\n");
- break;
+ seq_head = &table.types[i];
+ hlist_for_each_entry_safe(seq, safe, seq_head, ns_list) {
+ tipc_purge_publications(seq);
+ }
+ continue;
}
kfree(table.types);
table.types = NULL;
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index 9f72a6376362..3aaf73de9e2d 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -83,8 +83,6 @@ static struct genl_ops tipc_genl_ops[] = {
},
};
-static int tipc_genl_family_registered;
-
int tipc_netlink_start(void)
{
int res;
@@ -94,16 +92,10 @@ int tipc_netlink_start(void)
pr_err("Failed to register netlink interface\n");
return res;
}
-
- tipc_genl_family_registered = 1;
return 0;
}
void tipc_netlink_stop(void)
{
- if (!tipc_genl_family_registered)
- return;
-
genl_unregister_family(&tipc_genl_family);
- tipc_genl_family_registered = 0;
}
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
index 2a2a938dc22c..de3d593e2fee 100644
--- a/net/tipc/ref.c
+++ b/net/tipc/ref.c
@@ -126,9 +126,6 @@ int tipc_ref_table_init(u32 requested_size, u32 start)
*/
void tipc_ref_table_stop(void)
{
- if (!tipc_ref_table.entries)
- return;
-
vfree(tipc_ref_table.entries);
tipc_ref_table.entries = NULL;
}
diff --git a/net/tipc/server.c b/net/tipc/server.c
index b635ca347a87..646a930eefbf 100644
--- a/net/tipc/server.c
+++ b/net/tipc/server.c
@@ -87,7 +87,6 @@ static void tipc_clean_outqueues(struct tipc_conn *con);
static void tipc_conn_kref_release(struct kref *kref)
{
struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
- struct tipc_server *s = con->server;
if (con->sock) {
tipc_sock_release_local(con->sock);
@@ -95,10 +94,6 @@ static void tipc_conn_kref_release(struct kref *kref)
}
tipc_clean_outqueues(con);
-
- if (con->conid)
- s->tipc_conn_shutdown(con->conid, con->usr_data);
-
kfree(con);
}
@@ -181,6 +176,9 @@ static void tipc_close_conn(struct tipc_conn *con)
struct tipc_server *s = con->server;
if (test_and_clear_bit(CF_CONNECTED, &con->flags)) {
+ if (con->conid)
+ s->tipc_conn_shutdown(con->conid, con->usr_data);
+
spin_lock_bh(&s->idr_lock);
idr_remove(&s->conn_idr, con->conid);
s->idr_in_use--;
@@ -429,10 +427,12 @@ int tipc_conn_sendmsg(struct tipc_server *s, int conid,
list_add_tail(&e->list, &con->outqueue);
spin_unlock_bh(&con->outqueue_lock);
- if (test_bit(CF_CONNECTED, &con->flags))
+ if (test_bit(CF_CONNECTED, &con->flags)) {
if (!queue_work(s->send_wq, &con->swork))
conn_put(con);
-
+ } else {
+ conn_put(con);
+ }
return 0;
}
@@ -573,7 +573,6 @@ int tipc_server_start(struct tipc_server *s)
kmem_cache_destroy(s->rcvbuf_cache);
return ret;
}
- s->enabled = 1;
return ret;
}
@@ -583,10 +582,6 @@ void tipc_server_stop(struct tipc_server *s)
int total = 0;
int id;
- if (!s->enabled)
- return;
-
- s->enabled = 0;
spin_lock_bh(&s->idr_lock);
for (id = 0; total < s->idr_in_use; id++) {
con = idr_find(&s->conn_idr, id);
diff --git a/net/tipc/server.h b/net/tipc/server.h
index 98b23f20bc0f..be817b0b547e 100644
--- a/net/tipc/server.h
+++ b/net/tipc/server.h
@@ -56,7 +56,6 @@
* @name: server name
* @imp: message importance
* @type: socket type
- * @enabled: identify whether server is launched or not
*/
struct tipc_server {
struct idr conn_idr;
@@ -74,7 +73,6 @@ struct tipc_server {
const char name[TIPC_SERVER_NAME_LEN];
int imp;
int type;
- int enabled;
};
int tipc_conn_sendmsg(struct tipc_server *s, int conid,
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index aab4948f0aff..0ed0eaa62f29 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -70,8 +70,6 @@ static const struct proto_ops msg_ops;
static struct proto tipc_proto;
static struct proto tipc_proto_kern;
-static int sockets_enabled;
-
/*
* Revised TIPC socket locking policy:
*
@@ -999,7 +997,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long timeo)
for (;;) {
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
- if (skb_queue_empty(&sk->sk_receive_queue)) {
+ if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
if (sock->state == SS_DISCONNECTING) {
err = -ENOTCONN;
break;
@@ -1625,7 +1623,7 @@ static int tipc_wait_for_accept(struct socket *sock, long timeo)
for (;;) {
prepare_to_wait_exclusive(sk_sleep(sk), &wait,
TASK_INTERRUPTIBLE);
- if (skb_queue_empty(&sk->sk_receive_queue)) {
+ if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
@@ -2027,8 +2025,6 @@ int tipc_socket_init(void)
proto_unregister(&tipc_proto);
goto out;
}
-
- sockets_enabled = 1;
out:
return res;
}
@@ -2038,10 +2034,6 @@ int tipc_socket_init(void)
*/
void tipc_socket_stop(void)
{
- if (!sockets_enabled)
- return;
-
- sockets_enabled = 0;
sock_unregister(tipc_family_ops.family);
proto_unregister(&tipc_proto);
}
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index 7cb0bd5b1176..642437231ad5 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -96,20 +96,16 @@ static void subscr_send_event(struct tipc_subscription *sub, u32 found_lower,
{
struct tipc_subscriber *subscriber = sub->subscriber;
struct kvec msg_sect;
- int ret;
msg_sect.iov_base = (void *)&sub->evt;
msg_sect.iov_len = sizeof(struct tipc_event);
-
sub->evt.event = htohl(event, sub->swap);
sub->evt.found_lower = htohl(found_lower, sub->swap);
sub->evt.found_upper = htohl(found_upper, sub->swap);
sub->evt.port.ref = htohl(port_ref, sub->swap);
sub->evt.port.node = htohl(node, sub->swap);
- ret = tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL,
- msg_sect.iov_base, msg_sect.iov_len);
- if (ret < 0)
- pr_err("Sending subscription event failed, no memory\n");
+ tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL, msg_sect.iov_base,
+ msg_sect.iov_len);
}
/**
@@ -153,14 +149,6 @@ static void subscr_timeout(struct tipc_subscription *sub)
/* The spin lock per subscriber is used to protect its members */
spin_lock_bh(&subscriber->lock);
- /* Validate if the connection related to the subscriber is
- * closed (in case subscriber is terminating)
- */
- if (subscriber->conid == 0) {
- spin_unlock_bh(&subscriber->lock);
- return;
- }
-
/* Validate timeout (in case subscription is being cancelled) */
if (sub->timeout == TIPC_WAIT_FOREVER) {
spin_unlock_bh(&subscriber->lock);
@@ -215,9 +203,6 @@ static void subscr_release(struct tipc_subscriber *subscriber)
spin_lock_bh(&subscriber->lock);
- /* Invalidate subscriber reference */
- subscriber->conid = 0;
-
/* Destroy any existing subscriptions for subscriber */
list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
subscription_list) {
@@ -278,9 +263,9 @@ static void subscr_cancel(struct tipc_subscr *s,
*
* Called with subscriber lock held.
*/
-static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s,
- struct tipc_subscriber *subscriber)
-{
+static int subscr_subscribe(struct tipc_subscr *s,
+ struct tipc_subscriber *subscriber,
+ struct tipc_subscription **sub_p) {
struct tipc_subscription *sub;
int swap;
@@ -291,23 +276,21 @@ static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s,
if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
subscr_cancel(s, subscriber);
- return NULL;
+ return 0;
}
/* Refuse subscription if global limit exceeded */
if (atomic_read(&subscription_count) >= TIPC_MAX_SUBSCRIPTIONS) {
pr_warn("Subscription rejected, limit reached (%u)\n",
TIPC_MAX_SUBSCRIPTIONS);
- subscr_terminate(subscriber);
- return NULL;
+ return -EINVAL;
}
/* Allocate subscription object */
sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
if (!sub) {
pr_warn("Subscription rejected, no memory\n");
- subscr_terminate(subscriber);
- return NULL;
+ return -ENOMEM;
}
/* Initialize subscription object */
@@ -321,8 +304,7 @@ static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s,
(sub->seq.lower > sub->seq.upper)) {
pr_warn("Subscription rejected, illegal request\n");
kfree(sub);
- subscr_terminate(subscriber);
- return NULL;
+ return -EINVAL;
}
INIT_LIST_HEAD(&sub->nameseq_list);
list_add(&sub->subscription_list, &subscriber->subscription_list);
@@ -335,8 +317,8 @@ static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s,
(Handler)subscr_timeout, (unsigned long)sub);
k_start_timer(&sub->timer, sub->timeout);
}
-
- return sub;
+ *sub_p = sub;
+ return 0;
}
/* Handle one termination request for the subscriber */
@@ -350,10 +332,14 @@ static void subscr_conn_msg_event(int conid, struct sockaddr_tipc *addr,
void *usr_data, void *buf, size_t len)
{
struct tipc_subscriber *subscriber = usr_data;
- struct tipc_subscription *sub;
+ struct tipc_subscription *sub = NULL;
spin_lock_bh(&subscriber->lock);
- sub = subscr_subscribe((struct tipc_subscr *)buf, subscriber);
+ if (subscr_subscribe((struct tipc_subscr *)buf, subscriber, &sub) < 0) {
+ spin_unlock_bh(&subscriber->lock);
+ subscr_terminate(subscriber);
+ return;
+ }
if (sub)
tipc_nametbl_subscribe(sub);
spin_unlock_bh(&subscriber->lock);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 29fc8bee9702..94404f19f9de 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -163,9 +163,8 @@ static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
static inline unsigned int unix_hash_fold(__wsum n)
{
- unsigned int hash = (__force unsigned int)n;
+ unsigned int hash = (__force unsigned int)csum_fold(n);
- hash ^= hash>>16;
hash ^= hash>>8;
return hash&(UNIX_HASH_SIZE-1);
}
@@ -1788,8 +1787,11 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
goto out;
err = mutex_lock_interruptible(&u->readlock);
- if (err) {
- err = sock_intr_errno(sock_rcvtimeo(sk, noblock));
+ if (unlikely(err)) {
+ /* recvmsg() in non blocking mode is supposed to return -EAGAIN
+ * sk_rcvtimeo is not honored by mutex_lock_interruptible()
+ */
+ err = noblock ? -EAGAIN : -ERESTARTSYS;
goto out;
}
@@ -1914,6 +1916,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
struct unix_sock *u = unix_sk(sk);
DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, msg->msg_name);
int copied = 0;
+ int noblock = flags & MSG_DONTWAIT;
int check_creds = 0;
int target;
int err = 0;
@@ -1929,7 +1932,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
goto out;
target = sock_rcvlowat(sk, flags&MSG_WAITALL, size);
- timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT);
+ timeo = sock_rcvtimeo(sk, noblock);
/* Lock the socket to prevent queue disordering
* while sleeps in memcpy_tomsg
@@ -1941,8 +1944,11 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
}
err = mutex_lock_interruptible(&u->readlock);
- if (err) {
- err = sock_intr_errno(timeo);
+ if (unlikely(err)) {
+ /* recvmsg() in non blocking mode is supposed to return -EAGAIN
+ * sk_rcvtimeo is not honored by mutex_lock_interruptible()
+ */
+ err = noblock ? -EAGAIN : -ERESTARTSYS;
goto out;
}
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 010892b81a06..a3bf18d11609 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -788,8 +788,6 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
default:
break;
}
-
- wdev->beacon_interval = 0;
}
static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 9b897fca7487..f0541370e68e 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1700,7 +1700,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
return;
case NL80211_REGDOM_SET_BY_USER:
treatment = reg_process_hint_user(reg_request);
- if (treatment == REG_REQ_OK ||
+ if (treatment == REG_REQ_IGNORE ||
treatment == REG_REQ_ALREADY_SET)
return;
schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
@@ -2373,6 +2373,7 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
int set_regdom(const struct ieee80211_regdomain *rd)
{
struct regulatory_request *lr;
+ bool user_reset = false;
int r;
if (!reg_is_valid_request(rd->alpha2)) {
@@ -2389,6 +2390,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
break;
case NL80211_REGDOM_SET_BY_USER:
r = reg_set_rd_user(rd, lr);
+ user_reset = true;
break;
case NL80211_REGDOM_SET_BY_DRIVER:
r = reg_set_rd_driver(rd, lr);
@@ -2402,8 +2404,14 @@ int set_regdom(const struct ieee80211_regdomain *rd)
}
if (r) {
- if (r == -EALREADY)
+ switch (r) {
+ case -EALREADY:
reg_set_request_processed();
+ break;
+ default:
+ /* Back to world regulatory in case of errors */
+ restore_regulatory_settings(user_reset);
+ }
kfree(rd);
return r;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 4b98b25793c5..1d5c7bf29938 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1158,7 +1158,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
if (hlist_unhashed(&pol->bydst))
return NULL;
- hlist_del(&pol->bydst);
+ hlist_del_init(&pol->bydst);
hlist_del(&pol->byidx);
list_del(&pol->walk.all);
net->xfrm.policy_count[dir]--;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index a26b7aa79475..40f1b3e92e78 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1159,6 +1159,11 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
}
x->props.aalgo = orig->props.aalgo;
+ if (orig->aead) {
+ x->aead = xfrm_algo_aead_clone(orig->aead);
+ if (!x->aead)
+ goto error;
+ }
if (orig->ealg) {
x->ealg = xfrm_algo_clone(orig->ealg);
if (!x->ealg)
@@ -1201,6 +1206,9 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
x->props.flags = orig->props.flags;
x->props.extra_flags = orig->props.extra_flags;
+ x->tfcpad = orig->tfcpad;
+ x->replay_maxdiff = orig->replay_maxdiff;
+ x->replay_maxage = orig->replay_maxage;
x->curlft.add_time = orig->curlft.add_time;
x->km.state = orig->km.state;
x->km.seq = orig->km.seq;
@@ -1215,11 +1223,12 @@ out:
return NULL;
}
-/* net->xfrm.xfrm_state_lock is held */
struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net)
{
unsigned int h;
- struct xfrm_state *x;
+ struct xfrm_state *x = NULL;
+
+ spin_lock_bh(&net->xfrm.xfrm_state_lock);
if (m->reqid) {
h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr,
@@ -1236,7 +1245,7 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
m->old_family))
continue;
xfrm_state_hold(x);
- return x;
+ break;
}
} else {
h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr,
@@ -1251,11 +1260,13 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
m->old_family))
continue;
xfrm_state_hold(x);
- return x;
+ break;
}
}
- return NULL;
+ spin_unlock_bh(&net->xfrm.xfrm_state_lock);
+
+ return x;
}
EXPORT_SYMBOL(xfrm_migrate_state_find);
@@ -1451,7 +1462,7 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
{
int err = 0;
struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
- struct net *net = xs_net(*dst);
+ struct net *net = xs_net(*src);
if (!afinfo)
return -EAFNOSUPPORT;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 1ae3ec7c18b0..2f7ddc3a59b4 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -32,11 +32,6 @@
#include <linux/in6.h>
#endif
-static inline int aead_len(struct xfrm_algo_aead *alg)
-{
- return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
-}
-
static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
{
struct nlattr *rt = attrs[type];
@@ -1226,7 +1221,7 @@ static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs
return 0;
uctx = nla_data(rt);
- return security_xfrm_policy_alloc(&pol->security, uctx);
+ return security_xfrm_policy_alloc(&pol->security, uctx, GFP_KERNEL);
}
static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,
@@ -1631,7 +1626,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
if (rt) {
struct xfrm_user_sec_ctx *uctx = nla_data(rt);
- err = security_xfrm_policy_alloc(&ctx, uctx);
+ err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL);
if (err)
return err;
}
@@ -1933,7 +1928,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
if (rt) {
struct xfrm_user_sec_ctx *uctx = nla_data(rt);
- err = security_xfrm_policy_alloc(&ctx, uctx);
+ err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL);
if (err)
return err;
}
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 547e15daf03d..93a0da26582b 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -155,6 +155,15 @@ ld-option = $(call try-run,\
# Important: no spaces around options
ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2))
+# ld-version
+# Usage: $(call ld-version)
+# Note this is mainly for HJ Lu's 3 number binutil versions
+ld-version = $(shell $(LD) --version | $(srctree)/scripts/ld-version.sh)
+
+# ld-ifversion
+# Usage: $(call ld-ifversion, -ge, 22252, y)
+ld-ifversion = $(shell [ $(call ld-version) $(1) $(2) ] && echo $(3))
+
######
###
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index d5d859c80729..9f0ee22b914f 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -198,7 +198,7 @@ $(multi-objs-y:.o=.s) : modname = $(modname-multi)
$(multi-objs-y:.o=.lst) : modname = $(modname-multi)
quiet_cmd_cc_s_c = CC $(quiet_modtag) $@
-cmd_cc_s_c = $(CC) $(c_flags) -fverbose-asm -S -o $@ $<
+cmd_cc_s_c = $(CC) $(c_flags) $(DISABLE_LTO) -fverbose-asm -S -o $@ $<
$(obj)/%.s: $(src)/%.c FORCE
$(call if_changed_dep,cc_s_c)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 49392ecbef17..72105d104357 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -152,6 +152,7 @@ ld_flags = $(LDFLAGS) $(ldflags-y)
dtc_cpp_flags = -Wp,-MD,$(depfile).pre.tmp -nostdinc \
-I$(srctree)/arch/$(SRCARCH)/boot/dts \
-I$(srctree)/arch/$(SRCARCH)/boot/dts/include \
+ -I$(srctree)/drivers/of/testcase-data \
-undef -D__DTS__
# Finds the multi-part object the current object will be linked into
@@ -273,6 +274,18 @@ $(obj)/%.dtb: $(src)/%.dts FORCE
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
+# Helper targets for Installing DTBs into the boot directory
+quiet_cmd_dtb_install = INSTALL $<
+ cmd_dtb_install = cp $< $(2)
+
+_dtbinst_pre_:
+ $(Q)if [ -d $(INSTALL_DTBS_PATH).old ]; then rm -rf $(INSTALL_DTBS_PATH).old; fi
+ $(Q)if [ -d $(INSTALL_DTBS_PATH) ]; then mv $(INSTALL_DTBS_PATH) $(INSTALL_DTBS_PATH).old; fi
+ $(Q)mkdir -p $(INSTALL_DTBS_PATH)
+
+%.dtb_dtbinst_: $(obj)/%.dtb _dtbinst_pre_
+ $(call cmd,dtb_install,$(INSTALL_DTBS_PATH))
+
# Bzip2
# ---------------------------------------------------------------------------
diff --git a/scripts/dtc/dtc-parser.tab.c_shipped b/scripts/dtc/dtc-parser.tab.c_shipped
index ee1d8c3042fb..c8769d550cfb 100644
--- a/scripts/dtc/dtc-parser.tab.c_shipped
+++ b/scripts/dtc/dtc-parser.tab.c_shipped
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.5. */
+/* A Bison parser, made by GNU Bison 2.7.12-4996. */
/* Bison implementation for Yacc-like parsers in C
- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -44,7 +44,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "2.5"
+#define YYBISON_VERSION "2.7.12-4996"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -58,14 +58,11 @@
/* Pull parsers. */
#define YYPULL 1
-/* Using locations. */
-#define YYLSP_NEEDED 0
/* Copy the first part of user declarations. */
-
-/* Line 268 of yacc.c */
+/* Line 371 of yacc.c */
#line 21 "dtc-parser.y"
#include <stdio.h>
@@ -85,14 +82,16 @@ extern int treesource_error;
static unsigned long long eval_literal(const char *s, int base, int bits);
static unsigned char eval_char_literal(const char *s);
+/* Line 371 of yacc.c */
+#line 87 "dtc-parser.tab.c"
-/* Line 268 of yacc.c */
-#line 91 "dtc-parser.tab.c"
-
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
/* Enabling verbose error messages. */
#ifdef YYERROR_VERBOSE
@@ -102,11 +101,17 @@ static unsigned char eval_char_literal(const char *s);
# define YYERROR_VERBOSE 0
#endif
-/* Enabling the token table. */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
+/* In a future release of Bison, this section will be replaced
+ by #include "dtc-parser.tab.h". */
+#ifndef YY_YY_DTC_PARSER_TAB_H_INCLUDED
+# define YY_YY_DTC_PARSER_TAB_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
#endif
-
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -140,12 +145,10 @@ static unsigned char eval_char_literal(const char *s);
#endif
-
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
{
-
-/* Line 293 of yacc.c */
+/* Line 387 of yacc.c */
#line 40 "dtc-parser.y"
char *propnodename;
@@ -168,21 +171,36 @@ typedef union YYSTYPE
uint64_t integer;
-
-/* Line 293 of yacc.c */
-#line 174 "dtc-parser.tab.c"
+/* Line 387 of yacc.c */
+#line 176 "dtc-parser.tab.c"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
#endif
+extern YYSTYPE yylval;
-/* Copy the second part of user declarations. */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+#endif /* !YY_YY_DTC_PARSER_TAB_H_INCLUDED */
-/* Line 343 of yacc.c */
-#line 186 "dtc-parser.tab.c"
+/* Copy the second part of user declarations. */
+
+/* Line 390 of yacc.c */
+#line 204 "dtc-parser.tab.c"
#ifdef short
# undef short
@@ -235,24 +253,33 @@ typedef short int yytype_int16;
# if defined YYENABLE_NLS && YYENABLE_NLS
# if ENABLE_NLS
# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
# endif
# endif
# ifndef YY_
-# define YY_(msgid) msgid
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if (! defined __GNUC__ || __GNUC__ < 2 \
+ || (__GNUC__ == 2 && __GNUC_MINOR__ < 5))
+# define __attribute__(Spec) /* empty */
# endif
#endif
/* Suppress unused-variable warnings by "using" E. */
#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
+# define YYUSE(E) ((void) (E))
#else
-# define YYUSE(e) /* empty */
+# define YYUSE(E) /* empty */
#endif
+
/* Identity function, used to suppress warnings about constant conditions. */
#ifndef lint
-# define YYID(n) (n)
+# define YYID(N) (N)
#else
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
@@ -288,6 +315,7 @@ YYID (yyi)
# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
# ifndef EXIT_SUCCESS
# define EXIT_SUCCESS 0
# endif
@@ -379,20 +407,20 @@ union yyalloc
#endif
#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
-/* Copy COUNT objects from FROM to TO. The source and destination do
+/* Copy COUNT objects from SRC to DST. The source and destination do
not overlap. */
# ifndef YYCOPY
# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
while (YYID (0))
# endif
# endif
@@ -513,7 +541,7 @@ static const yytype_uint16 yyrline[] =
};
#endif
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+#if YYDEBUG || YYERROR_VERBOSE || 0
/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
@@ -530,7 +558,7 @@ static const char *const yytname[] =
"integer_expr", "integer_trinary", "integer_or", "integer_and",
"integer_bitor", "integer_bitxor", "integer_bitand", "integer_eq",
"integer_rela", "integer_shift", "integer_add", "integer_mul",
- "integer_unary", "bytestring", "subnodes", "subnode", 0
+ "integer_unary", "bytestring", "subnodes", "subnode", YY_NULL
};
#endif
@@ -655,10 +683,10 @@ static const yytype_uint8 yytable[] =
137, 0, 73, 139
};
-#define yypact_value_is_default(yystate) \
- ((yystate) == (-78))
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-78)))
-#define yytable_value_is_error(yytable_value) \
+#define yytable_value_is_error(Yytable_value) \
YYID (0)
static const yytype_int16 yycheck[] =
@@ -727,62 +755,35 @@ static const yytype_uint8 yystos[] =
#define YYRECOVERING() (!!yyerrstatus)
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- YYPOPSTACK (1); \
- goto yybackup; \
- } \
- else \
- { \
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
yyerror (YY_("syntax error: cannot back up")); \
YYERROR; \
} \
while (YYID (0))
-
+/* Error token number */
#define YYTERROR 1
#define YYERRCODE 256
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
- If N is 0, then set CURRENT to the empty location which ends
- the previous symbol: RHS[0] (always defined). */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- do \
- if (YYID (N)) \
- { \
- (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
- (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- } \
- else \
- { \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC (Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC (Rhs, 0).last_column; \
- } \
- while (YYID (0))
-#endif
-
-
/* This macro is provided for backward compatibility. */
-
#ifndef YY_LOCATION_PRINT
# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
#endif
/* YYLEX -- calling `yylex' with the right arguments. */
-
#ifdef YYLEX_PARAM
# define YYLEX yylex (YYLEX_PARAM)
#else
@@ -832,6 +833,8 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
YYSTYPE const * const yyvaluep;
#endif
{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
if (!yyvaluep)
return;
# ifdef YYPRINT
@@ -840,11 +843,7 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
# else
YYUSE (yyoutput);
# endif
- switch (yytype)
- {
- default:
- break;
- }
+ YYUSE (yytype);
}
@@ -1083,12 +1082,11 @@ static int
yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
yytype_int16 *yyssp, int yytoken)
{
- YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
/* Internationalized format string. */
- const char *yyformat = 0;
+ const char *yyformat = YY_NULL;
/* Arguments of yyformat. */
char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
/* Number of reported tokens (one for the "unexpected", one per
@@ -1148,11 +1146,13 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
break;
}
yyarg[yycount++] = yytname[yyx];
- yysize1 = yysize + yytnamerr (0, yytname[yyx]);
- if (! (yysize <= yysize1
- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
}
}
}
@@ -1172,10 +1172,12 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
# undef YYCASE_
}
- yysize1 = yysize + yystrlen (yyformat);
- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
if (*yymsg_alloc < yysize)
{
@@ -1231,36 +1233,26 @@ yydestruct (yymsg, yytype, yyvaluep)
yymsg = "Deleting";
YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
- switch (yytype)
- {
-
- default:
- break;
- }
+ YYUSE (yytype);
}
-/* Prevent warnings from -Wmissing-prototypes. */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
/* The lookahead symbol. */
int yychar;
+
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
/* The semantic value of the lookahead symbol. */
-YYSTYPE yylval;
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
/* Number of syntax errors so far. */
int yynerrs;
@@ -1300,7 +1292,7 @@ yyparse ()
`yyss': related to states.
`yyvs': related to semantic values.
- Refer to the stacks thru separate pointers, to allow yyoverflow
+ Refer to the stacks through separate pointers, to allow yyoverflow
to reallocate them elsewhere. */
/* The state stack. */
@@ -1318,7 +1310,7 @@ yyparse ()
int yyn;
int yyresult;
/* Lookahead token as an internal (translated) token number. */
- int yytoken;
+ int yytoken = 0;
/* The variables used to return semantic value and location from the
action routines. */
YYSTYPE yyval;
@@ -1336,9 +1328,8 @@ yyparse ()
Keep to zero when no symbol should be popped. */
int yylen = 0;
- yytoken = 0;
- yyss = yyssa;
- yyvs = yyvsa;
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
yystacksize = YYINITDEPTH;
YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1347,14 +1338,6 @@ yyparse ()
yyerrstatus = 0;
yynerrs = 0;
yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
- yyssp = yyss;
- yyvsp = yyvs;
-
goto yysetstate;
/*------------------------------------------------------------.
@@ -1495,7 +1478,9 @@ yybackup:
yychar = YYEMPTY;
yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
goto yynewstate;
@@ -1532,8 +1517,7 @@ yyreduce:
switch (yyn)
{
case 2:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 110 "dtc-parser.y"
{
the_boot_info = build_boot_info((yyvsp[(3) - (4)].re), (yyvsp[(4) - (4)].node),
@@ -1542,8 +1526,7 @@ yyreduce:
break;
case 3:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 118 "dtc-parser.y"
{
(yyval.re) = NULL;
@@ -1551,8 +1534,7 @@ yyreduce:
break;
case 4:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 122 "dtc-parser.y"
{
(yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re));
@@ -1560,8 +1542,7 @@ yyreduce:
break;
case 5:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 129 "dtc-parser.y"
{
(yyval.re) = build_reserve_entry((yyvsp[(2) - (4)].integer), (yyvsp[(3) - (4)].integer));
@@ -1569,8 +1550,7 @@ yyreduce:
break;
case 6:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 133 "dtc-parser.y"
{
add_label(&(yyvsp[(2) - (2)].re)->labels, (yyvsp[(1) - (2)].labelref));
@@ -1579,8 +1559,7 @@ yyreduce:
break;
case 7:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 141 "dtc-parser.y"
{
(yyval.node) = name_node((yyvsp[(2) - (2)].node), "");
@@ -1588,8 +1567,7 @@ yyreduce:
break;
case 8:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 145 "dtc-parser.y"
{
(yyval.node) = merge_nodes((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
@@ -1597,8 +1575,7 @@ yyreduce:
break;
case 9:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 149 "dtc-parser.y"
{
struct node *target = get_node_by_ref((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].labelref));
@@ -1612,8 +1589,7 @@ yyreduce:
break;
case 10:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 159 "dtc-parser.y"
{
struct node *target = get_node_by_ref((yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].labelref));
@@ -1628,8 +1604,7 @@ yyreduce:
break;
case 11:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 173 "dtc-parser.y"
{
(yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist));
@@ -1637,8 +1612,7 @@ yyreduce:
break;
case 12:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 180 "dtc-parser.y"
{
(yyval.proplist) = NULL;
@@ -1646,8 +1620,7 @@ yyreduce:
break;
case 13:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 184 "dtc-parser.y"
{
(yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist));
@@ -1655,8 +1628,7 @@ yyreduce:
break;
case 14:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 191 "dtc-parser.y"
{
(yyval.prop) = build_property((yyvsp[(1) - (4)].propnodename), (yyvsp[(3) - (4)].data));
@@ -1664,8 +1636,7 @@ yyreduce:
break;
case 15:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 195 "dtc-parser.y"
{
(yyval.prop) = build_property((yyvsp[(1) - (2)].propnodename), empty_data);
@@ -1673,8 +1644,7 @@ yyreduce:
break;
case 16:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 199 "dtc-parser.y"
{
(yyval.prop) = build_property_delete((yyvsp[(2) - (3)].propnodename));
@@ -1682,8 +1652,7 @@ yyreduce:
break;
case 17:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 203 "dtc-parser.y"
{
add_label(&(yyvsp[(2) - (2)].prop)->labels, (yyvsp[(1) - (2)].labelref));
@@ -1692,8 +1661,7 @@ yyreduce:
break;
case 18:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 211 "dtc-parser.y"
{
(yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data));
@@ -1701,8 +1669,7 @@ yyreduce:
break;
case 19:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 215 "dtc-parser.y"
{
(yyval.data) = data_merge((yyvsp[(1) - (3)].data), (yyvsp[(2) - (3)].array).data);
@@ -1710,8 +1677,7 @@ yyreduce:
break;
case 20:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 219 "dtc-parser.y"
{
(yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data));
@@ -1719,8 +1685,7 @@ yyreduce:
break;
case 21:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 223 "dtc-parser.y"
{
(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref));
@@ -1728,8 +1693,7 @@ yyreduce:
break;
case 22:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 227 "dtc-parser.y"
{
FILE *f = srcfile_relative_open((yyvsp[(4) - (9)].data).val, NULL);
@@ -1750,8 +1714,7 @@ yyreduce:
break;
case 23:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 244 "dtc-parser.y"
{
FILE *f = srcfile_relative_open((yyvsp[(4) - (5)].data).val, NULL);
@@ -1765,8 +1728,7 @@ yyreduce:
break;
case 24:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 254 "dtc-parser.y"
{
(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
@@ -1774,8 +1736,7 @@ yyreduce:
break;
case 25:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 261 "dtc-parser.y"
{
(yyval.data) = empty_data;
@@ -1783,8 +1744,7 @@ yyreduce:
break;
case 26:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 265 "dtc-parser.y"
{
(yyval.data) = (yyvsp[(1) - (2)].data);
@@ -1792,8 +1752,7 @@ yyreduce:
break;
case 27:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 269 "dtc-parser.y"
{
(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
@@ -1801,8 +1760,7 @@ yyreduce:
break;
case 28:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 276 "dtc-parser.y"
{
(yyval.array).data = empty_data;
@@ -1821,8 +1779,7 @@ yyreduce:
break;
case 29:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 291 "dtc-parser.y"
{
(yyval.array).data = empty_data;
@@ -1831,8 +1788,7 @@ yyreduce:
break;
case 30:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 296 "dtc-parser.y"
{
if ((yyvsp[(1) - (2)].array).bits < 64) {
@@ -1856,8 +1812,7 @@ yyreduce:
break;
case 31:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 316 "dtc-parser.y"
{
uint64_t val = ~0ULL >> (64 - (yyvsp[(1) - (2)].array).bits);
@@ -1875,8 +1830,7 @@ yyreduce:
break;
case 32:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 330 "dtc-parser.y"
{
(yyval.array).data = data_add_marker((yyvsp[(1) - (2)].array).data, LABEL, (yyvsp[(2) - (2)].labelref));
@@ -1884,8 +1838,7 @@ yyreduce:
break;
case 33:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 337 "dtc-parser.y"
{
(yyval.integer) = eval_literal((yyvsp[(1) - (1)].literal), 0, 64);
@@ -1893,8 +1846,7 @@ yyreduce:
break;
case 34:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 341 "dtc-parser.y"
{
(yyval.integer) = eval_char_literal((yyvsp[(1) - (1)].literal));
@@ -1902,8 +1854,7 @@ yyreduce:
break;
case 35:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 345 "dtc-parser.y"
{
(yyval.integer) = (yyvsp[(2) - (3)].integer);
@@ -1911,162 +1862,139 @@ yyreduce:
break;
case 38:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 356 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (5)].integer) ? (yyvsp[(3) - (5)].integer) : (yyvsp[(5) - (5)].integer); }
break;
case 40:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 361 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) || (yyvsp[(3) - (3)].integer); }
break;
case 42:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 366 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) && (yyvsp[(3) - (3)].integer); }
break;
case 44:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 371 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) | (yyvsp[(3) - (3)].integer); }
break;
case 46:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 376 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) ^ (yyvsp[(3) - (3)].integer); }
break;
case 48:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 381 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) & (yyvsp[(3) - (3)].integer); }
break;
case 50:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 386 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) == (yyvsp[(3) - (3)].integer); }
break;
case 51:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 387 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) != (yyvsp[(3) - (3)].integer); }
break;
case 53:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 392 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) < (yyvsp[(3) - (3)].integer); }
break;
case 54:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 393 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) > (yyvsp[(3) - (3)].integer); }
break;
case 55:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 394 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) <= (yyvsp[(3) - (3)].integer); }
break;
case 56:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 395 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) >= (yyvsp[(3) - (3)].integer); }
break;
case 57:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 399 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) << (yyvsp[(3) - (3)].integer); }
break;
case 58:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 400 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) >> (yyvsp[(3) - (3)].integer); }
break;
case 60:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 405 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) + (yyvsp[(3) - (3)].integer); }
break;
case 61:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 406 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) - (yyvsp[(3) - (3)].integer); }
break;
case 63:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 411 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) * (yyvsp[(3) - (3)].integer); }
break;
case 64:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 412 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) / (yyvsp[(3) - (3)].integer); }
break;
case 65:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 413 "dtc-parser.y"
{ (yyval.integer) = (yyvsp[(1) - (3)].integer) % (yyvsp[(3) - (3)].integer); }
break;
case 68:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 419 "dtc-parser.y"
{ (yyval.integer) = -(yyvsp[(2) - (2)].integer); }
break;
case 69:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 420 "dtc-parser.y"
{ (yyval.integer) = ~(yyvsp[(2) - (2)].integer); }
break;
case 70:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 421 "dtc-parser.y"
{ (yyval.integer) = !(yyvsp[(2) - (2)].integer); }
break;
case 71:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 426 "dtc-parser.y"
{
(yyval.data) = empty_data;
@@ -2074,8 +2002,7 @@ yyreduce:
break;
case 72:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 430 "dtc-parser.y"
{
(yyval.data) = data_append_byte((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].byte));
@@ -2083,8 +2010,7 @@ yyreduce:
break;
case 73:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 434 "dtc-parser.y"
{
(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
@@ -2092,8 +2018,7 @@ yyreduce:
break;
case 74:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 441 "dtc-parser.y"
{
(yyval.nodelist) = NULL;
@@ -2101,8 +2026,7 @@ yyreduce:
break;
case 75:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 445 "dtc-parser.y"
{
(yyval.nodelist) = chain_node((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].nodelist));
@@ -2110,8 +2034,7 @@ yyreduce:
break;
case 76:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 449 "dtc-parser.y"
{
print_error("syntax error: properties must precede subnodes");
@@ -2120,8 +2043,7 @@ yyreduce:
break;
case 77:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 457 "dtc-parser.y"
{
(yyval.node) = name_node((yyvsp[(2) - (2)].node), (yyvsp[(1) - (2)].propnodename));
@@ -2129,8 +2051,7 @@ yyreduce:
break;
case 78:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 461 "dtc-parser.y"
{
(yyval.node) = name_node(build_node_delete(), (yyvsp[(2) - (3)].propnodename));
@@ -2138,8 +2059,7 @@ yyreduce:
break;
case 79:
-
-/* Line 1806 of yacc.c */
+/* Line 1787 of yacc.c */
#line 465 "dtc-parser.y"
{
add_label(&(yyvsp[(2) - (2)].node)->labels, (yyvsp[(1) - (2)].labelref));
@@ -2148,9 +2068,8 @@ yyreduce:
break;
-
-/* Line 1806 of yacc.c */
-#line 2154 "dtc-parser.tab.c"
+/* Line 1787 of yacc.c */
+#line 2073 "dtc-parser.tab.c"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -2313,7 +2232,9 @@ yyerrlab1:
YY_STACK_PRINT (yyss, yyssp);
}
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
/* Shift the error token. */
@@ -2337,7 +2258,7 @@ yyabortlab:
yyresult = 1;
goto yyreturn;
-#if !defined(yyoverflow) || YYERROR_VERBOSE
+#if !defined yyoverflow || YYERROR_VERBOSE
/*-------------------------------------------------.
| yyexhaustedlab -- memory exhaustion comes here. |
`-------------------------------------------------*/
@@ -2379,8 +2300,7 @@ yyreturn:
}
-
-/* Line 2067 of yacc.c */
+/* Line 2050 of yacc.c */
#line 471 "dtc-parser.y"
@@ -2444,4 +2364,3 @@ static unsigned char eval_char_literal(const char *s)
return c;
}
-
diff --git a/scripts/dtc/dtc-parser.tab.h_shipped b/scripts/dtc/dtc-parser.tab.h_shipped
index 25d3b88c6132..b2e7a86cd85e 100644
--- a/scripts/dtc/dtc-parser.tab.h_shipped
+++ b/scripts/dtc/dtc-parser.tab.h_shipped
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.5. */
+/* A Bison parser, made by GNU Bison 2.7.12-4996. */
/* Bison interface for Yacc-like parsers in C
- Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,6 +30,15 @@
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
+#ifndef YY_YY_DTC_PARSER_TAB_H_INCLUDED
+# define YY_YY_DTC_PARSER_TAB_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -63,12 +72,10 @@
#endif
-
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
{
-
-/* Line 2068 of yacc.c */
+/* Line 2053 of yacc.c */
#line 40 "dtc-parser.y"
char *propnodename;
@@ -91,9 +98,8 @@ typedef union YYSTYPE
uint64_t integer;
-
-/* Line 2068 of yacc.c */
-#line 97 "dtc-parser.tab.h"
+/* Line 2053 of yacc.c */
+#line 103 "dtc-parser.tab.h"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -102,4 +108,18 @@ typedef union YYSTYPE
extern YYSTYPE yylval;
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+#endif /* !YY_YY_DTC_PARSER_TAB_H_INCLUDED */
diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
index a375683c1534..e3c96536fd9d 100644
--- a/scripts/dtc/dtc.c
+++ b/scripts/dtc/dtc.c
@@ -21,8 +21,6 @@
#include "dtc.h"
#include "srcpos.h"
-#include "version_gen.h"
-
/*
* Command line options
*/
@@ -49,55 +47,60 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
fill_fullpaths(child, tree->fullpath);
}
-static void __attribute__ ((noreturn)) usage(void)
-{
- fprintf(stderr, "Usage:\n");
- fprintf(stderr, "\tdtc [options] <input file>\n");
- fprintf(stderr, "\nOptions:\n");
- fprintf(stderr, "\t-h\n");
- fprintf(stderr, "\t\tThis help text\n");
- fprintf(stderr, "\t-q\n");
- fprintf(stderr, "\t\tQuiet: -q suppress warnings, -qq errors, -qqq all\n");
- fprintf(stderr, "\t-I <input format>\n");
- fprintf(stderr, "\t\tInput formats are:\n");
- fprintf(stderr, "\t\t\tdts - device tree source text\n");
- fprintf(stderr, "\t\t\tdtb - device tree blob\n");
- fprintf(stderr, "\t\t\tfs - /proc/device-tree style directory\n");
- fprintf(stderr, "\t-o <output file>\n");
- fprintf(stderr, "\t-O <output format>\n");
- fprintf(stderr, "\t\tOutput formats are:\n");
- fprintf(stderr, "\t\t\tdts - device tree source text\n");
- fprintf(stderr, "\t\t\tdtb - device tree blob\n");
- fprintf(stderr, "\t\t\tasm - assembler source\n");
- fprintf(stderr, "\t-V <output version>\n");
- fprintf(stderr, "\t\tBlob version to produce, defaults to %d (relevant for dtb\n\t\tand asm output only)\n", DEFAULT_FDT_VERSION);
- fprintf(stderr, "\t-d <output dependency file>\n");
- fprintf(stderr, "\t-R <number>\n");
- fprintf(stderr, "\t\tMake space for <number> reserve map entries (relevant for \n\t\tdtb and asm output only)\n");
- fprintf(stderr, "\t-S <bytes>\n");
- fprintf(stderr, "\t\tMake the blob at least <bytes> long (extra space)\n");
- fprintf(stderr, "\t-p <bytes>\n");
- fprintf(stderr, "\t\tAdd padding to the blob of <bytes> long (extra space)\n");
- fprintf(stderr, "\t-b <number>\n");
- fprintf(stderr, "\t\tSet the physical boot cpu\n");
- fprintf(stderr, "\t-f\n");
- fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
- fprintf(stderr, "\t-i\n");
- fprintf(stderr, "\t\tAdd a path to search for include files\n");
- fprintf(stderr, "\t-s\n");
- fprintf(stderr, "\t\tSort nodes and properties before outputting (only useful for\n\t\tcomparing trees)\n");
- fprintf(stderr, "\t-v\n");
- fprintf(stderr, "\t\tPrint DTC version and exit\n");
- fprintf(stderr, "\t-H <phandle format>\n");
- fprintf(stderr, "\t\tphandle formats are:\n");
- fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n");
- fprintf(stderr, "\t\t\tepapr - \"phandle\" properties only\n");
- fprintf(stderr, "\t\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n");
- fprintf(stderr, "\t-W [no-]<checkname>\n");
- fprintf(stderr, "\t-E [no-]<checkname>\n");
- fprintf(stderr, "\t\t\tenable or disable warnings and errors\n");
- exit(3);
-}
+/* Usage related data. */
+static const char usage_synopsis[] = "dtc [options] <input file>";
+static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
+static struct option const usage_long_opts[] = {
+ {"quiet", no_argument, NULL, 'q'},
+ {"in-format", a_argument, NULL, 'I'},
+ {"out", a_argument, NULL, 'o'},
+ {"out-format", a_argument, NULL, 'O'},
+ {"out-version", a_argument, NULL, 'V'},
+ {"out-dependency", a_argument, NULL, 'd'},
+ {"reserve", a_argument, NULL, 'R'},
+ {"space", a_argument, NULL, 'S'},
+ {"pad", a_argument, NULL, 'p'},
+ {"boot-cpu", a_argument, NULL, 'b'},
+ {"force", no_argument, NULL, 'f'},
+ {"include", a_argument, NULL, 'i'},
+ {"sort", no_argument, NULL, 's'},
+ {"phandle", a_argument, NULL, 'H'},
+ {"warning", a_argument, NULL, 'W'},
+ {"error", a_argument, NULL, 'E'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'v'},
+ {NULL, no_argument, NULL, 0x0},
+};
+static const char * const usage_opts_help[] = {
+ "\n\tQuiet: -q suppress warnings, -qq errors, -qqq all",
+ "\n\tInput formats are:\n"
+ "\t\tdts - device tree source text\n"
+ "\t\tdtb - device tree blob\n"
+ "\t\tfs - /proc/device-tree style directory",
+ "\n\tOutput file",
+ "\n\tOutput formats are:\n"
+ "\t\tdts - device tree source text\n"
+ "\t\tdtb - device tree blob\n"
+ "\t\tasm - assembler source",
+ "\n\tBlob version to produce, defaults to %d (for dtb and asm output)", //, DEFAULT_FDT_VERSION);
+ "\n\tOutput dependency file",
+ "\n\ttMake space for <number> reserve map entries (for dtb and asm output)",
+ "\n\tMake the blob at least <bytes> long (extra space)",
+ "\n\tAdd padding to the blob of <bytes> long (extra space)",
+ "\n\tSet the physical boot cpu",
+ "\n\tTry to produce output even if the input tree has errors",
+ "\n\tAdd a path to search for include files",
+ "\n\tSort nodes and properties before outputting (useful for comparing trees)",
+ "\n\tValid phandle formats are:\n"
+ "\t\tlegacy - \"linux,phandle\" properties only\n"
+ "\t\tepapr - \"phandle\" properties only\n"
+ "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
+ "\n\tEnable/disable warnings (prefix with \"no-\")",
+ "\n\tEnable/disable errors (prefix with \"no-\")",
+ "\n\tPrint this help and exit",
+ "\n\tPrint version and exit",
+ NULL,
+};
int main(int argc, char *argv[])
{
@@ -118,8 +121,7 @@ int main(int argc, char *argv[])
minsize = 0;
padsize = 0;
- while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fqb:i:vH:sW:E:"))
- != EOF) {
+ while ((opt = util_getopt_long()) != EOF) {
switch (opt) {
case 'I':
inform = optarg;
@@ -158,8 +160,7 @@ int main(int argc, char *argv[])
srcfile_add_search_path(optarg);
break;
case 'v':
- printf("Version: %s\n", DTC_VERSION);
- exit(0);
+ util_version();
case 'H':
if (streq(optarg, "legacy"))
phandle_format = PHANDLE_LEGACY;
@@ -185,13 +186,14 @@ int main(int argc, char *argv[])
break;
case 'h':
+ usage(NULL);
default:
- usage();
+ usage("unknown option");
}
}
if (argc > (optind+1))
- usage();
+ usage("missing files");
else if (argc < (optind+1))
arg = "-";
else
@@ -201,9 +203,6 @@ int main(int argc, char *argv[])
if (minsize && padsize)
die("Can't set both -p and -S\n");
- if (minsize)
- fprintf(stderr, "DTC: Use of \"-S\" is deprecated; it will be removed soon, use \"-p\" instead\n");
-
if (depname) {
depfile = fopen(depname, "w");
if (!depfile)
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index 3e42a071070e..264a20cf66a8 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -66,7 +66,6 @@ typedef uint32_t cell_t;
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/* Data blobs */
enum markertype {
diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c
index 246ab4bc0d9d..c20bc5315bc1 100644
--- a/scripts/dtc/srcpos.c
+++ b/scripts/dtc/srcpos.c
@@ -297,9 +297,9 @@ srcpos_verror(struct srcpos *pos, char const *fmt, va_list va)
srcstr = srcpos_string(pos);
- fprintf(stdout, "Error: %s ", srcstr);
- vfprintf(stdout, fmt, va);
- fprintf(stdout, "\n");
+ fprintf(stderr, "Error: %s ", srcstr);
+ vfprintf(stderr, fmt, va);
+ fprintf(stderr, "\n");
}
void
diff --git a/scripts/dtc/update-dtc-source.sh b/scripts/dtc/update-dtc-source.sh
new file mode 100755
index 000000000000..feb01ef26be4
--- /dev/null
+++ b/scripts/dtc/update-dtc-source.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+# Simple script to update the version of DTC carried by the Linux kernel
+#
+# This script assumes that the dtc and the linux git trees are in the
+# same directory. After building dtc in the dtc directory, it copies the
+# source files and generated source files into the scripts/dtc directory
+# in the kernel and creates a git commit updating them to the new
+# version.
+#
+# Usage: from the top level Linux source tree, run:
+# $ ./scripts/dtc/update-dtc-source.sh
+#
+# The script will change into the dtc tree, build and test dtc, copy the
+# relevant files into the kernel tree and create a git commit. The commit
+# message will need to be modified to reflect the version of DTC being
+# imported
+#
+# TODO:
+# This script is pretty basic, but it is seldom used so a few manual tasks
+# aren't a big deal. If anyone is interested in making it more robust, the
+# the following would be nice:
+# * Actually fail to complete if any testcase fails.
+# - The dtc "make check" target needs to return a failure
+# * Extract the version number from the dtc repo for the commit message
+# * Build dtc in the kernel tree
+# * run 'make check" on dtc built from the kernel tree
+
+set -ev
+
+DTC_UPSTREAM_PATH=`pwd`/../dtc
+DTC_LINUX_PATH=`pwd`/scripts/dtc
+
+DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \
+ srcpos.h treesource.c util.c util.h version_gen.h Makefile.dtc \
+ dtc-lexer.l dtc-parser.y"
+DTC_GENERATED="dtc-lexer.lex.c dtc-parser.tab.c dtc-parser.tab.h"
+
+# Build DTC
+cd $DTC_UPSTREAM_PATH
+make clean
+make check
+
+# Copy the files into the Linux tree
+cd $DTC_LINUX_PATH
+for f in $DTC_SOURCE; do
+ cp ${DTC_UPSTREAM_PATH}/${f} ${f}
+ git add ${f}
+done
+for f in $DTC_GENERATED; do
+ cp ${DTC_UPSTREAM_PATH}/$f ${f}_shipped
+ git add ${f}_shipped
+done
+
+git commit -e -v -m "scripts/dtc: Update to upstream version [CHANGEME]"
diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c
index 2422c34e11df..3055c16e980d 100644
--- a/scripts/dtc/util.c
+++ b/scripts/dtc/util.c
@@ -34,6 +34,7 @@
#include "libfdt.h"
#include "util.h"
+#include "version_gen.h"
char *xstrdup(const char *s)
{
@@ -72,7 +73,7 @@ char *join_path(const char *path, const char *name)
int util_is_printable_string(const void *data, int len)
{
const char *s = data;
- const char *ss;
+ const char *ss, *se;
/* zero length is not */
if (len == 0)
@@ -82,13 +83,19 @@ int util_is_printable_string(const void *data, int len)
if (s[len - 1] != '\0')
return 0;
- ss = s;
- while (*s && isprint(*s))
- s++;
+ se = s + len;
- /* not zero, or not done yet */
- if (*s != '\0' || (s + 1 - ss) < len)
- return 0;
+ while (s < se) {
+ ss = s;
+ while (s < se && *s && isprint(*s))
+ s++;
+
+ /* not zero, or not done yet */
+ if (*s != '\0' || s == ss)
+ return 0;
+
+ s++;
+ }
return 1;
}
@@ -191,7 +198,7 @@ char get_escape_char(const char *s, int *i)
return val;
}
-int utilfdt_read_err(const char *filename, char **buffp)
+int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
{
int fd = 0; /* assume stdin */
char *buf = NULL;
@@ -206,12 +213,12 @@ int utilfdt_read_err(const char *filename, char **buffp)
}
/* Loop until we have read everything */
- buf = malloc(bufsize);
+ buf = xmalloc(bufsize);
do {
/* Expand the buffer to hold the next chunk */
if (offset == bufsize) {
bufsize *= 2;
- buf = realloc(buf, bufsize);
+ buf = xrealloc(buf, bufsize);
if (!buf) {
ret = ENOMEM;
break;
@@ -232,13 +239,20 @@ int utilfdt_read_err(const char *filename, char **buffp)
free(buf);
else
*buffp = buf;
+ *len = bufsize;
return ret;
}
-char *utilfdt_read(const char *filename)
+int utilfdt_read_err(const char *filename, char **buffp)
+{
+ off_t len;
+ return utilfdt_read_err_len(filename, buffp, &len);
+}
+
+char *utilfdt_read_len(const char *filename, off_t *len)
{
char *buff;
- int ret = utilfdt_read_err(filename, &buff);
+ int ret = utilfdt_read_err_len(filename, &buff, len);
if (ret) {
fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
@@ -249,6 +263,12 @@ char *utilfdt_read(const char *filename)
return buff;
}
+char *utilfdt_read(const char *filename)
+{
+ off_t len;
+ return utilfdt_read_len(filename, &len);
+}
+
int utilfdt_write_err(const char *filename, const void *blob)
{
int fd = 1; /* assume stdout */
@@ -329,3 +349,100 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size)
return -1;
return 0;
}
+
+void utilfdt_print_data(const char *data, int len)
+{
+ int i;
+ const char *p = data;
+ const char *s;
+
+ /* no data, don't print */
+ if (len == 0)
+ return;
+
+ if (util_is_printable_string(data, len)) {
+ printf(" = ");
+
+ s = data;
+ do {
+ printf("\"%s\"", s);
+ s += strlen(s) + 1;
+ if (s < data + len)
+ printf(", ");
+ } while (s < data + len);
+
+ } else if ((len % 4) == 0) {
+ const uint32_t *cell = (const uint32_t *)data;
+
+ printf(" = <");
+ for (i = 0; i < len; i += 4)
+ printf("0x%08x%s", fdt32_to_cpu(cell[i]),
+ i < (len - 4) ? " " : "");
+ printf(">");
+ } else {
+ printf(" = [");
+ for (i = 0; i < len; i++)
+ printf("%02x%s", *p++, i < len - 1 ? " " : "");
+ printf("]");
+ }
+}
+
+void util_version(void)
+{
+ printf("Version: %s\n", DTC_VERSION);
+ exit(0);
+}
+
+void util_usage(const char *errmsg, const char *synopsis,
+ const char *short_opts, struct option const long_opts[],
+ const char * const opts_help[])
+{
+ FILE *fp = errmsg ? stderr : stdout;
+ const char a_arg[] = "<arg>";
+ size_t a_arg_len = strlen(a_arg) + 1;
+ size_t i;
+ int optlen;
+
+ fprintf(fp,
+ "Usage: %s\n"
+ "\n"
+ "Options: -[%s]\n", synopsis, short_opts);
+
+ /* prescan the --long opt length to auto-align */
+ optlen = 0;
+ for (i = 0; long_opts[i].name; ++i) {
+ /* +1 is for space between --opt and help text */
+ int l = strlen(long_opts[i].name) + 1;
+ if (long_opts[i].has_arg == a_argument)
+ l += a_arg_len;
+ if (optlen < l)
+ optlen = l;
+ }
+
+ for (i = 0; long_opts[i].name; ++i) {
+ /* helps when adding new applets or options */
+ assert(opts_help[i] != NULL);
+
+ /* first output the short flag if it has one */
+ if (long_opts[i].val > '~')
+ fprintf(fp, " ");
+ else
+ fprintf(fp, " -%c, ", long_opts[i].val);
+
+ /* then the long flag */
+ if (long_opts[i].has_arg == no_argument)
+ fprintf(fp, "--%-*s", optlen, long_opts[i].name);
+ else
+ fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
+ (int)(optlen - strlen(long_opts[i].name) - a_arg_len), "");
+
+ /* finally the help text */
+ fprintf(fp, "%s\n", opts_help[i]);
+ }
+
+ if (errmsg) {
+ fprintf(fp, "\nError: %s\n", errmsg);
+ exit(EXIT_FAILURE);
+ } else
+ exit(EXIT_SUCCESS);
+}
diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h
index c8eb45d9f04b..8f40b4499359 100644
--- a/scripts/dtc/util.h
+++ b/scripts/dtc/util.h
@@ -2,6 +2,7 @@
#define _UTIL_H
#include <stdarg.h>
+#include <getopt.h>
/*
* Copyright 2011 The Chromium Authors, All Rights Reserved.
@@ -23,7 +24,9 @@
* USA
*/
-static inline void __attribute__((noreturn)) die(char * str, ...)
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static inline void __attribute__((noreturn)) die(const char *str, ...)
{
va_list ap;
@@ -57,12 +60,14 @@ extern char *xstrdup(const char *s);
extern char *join_path(const char *path, const char *name);
/**
- * Check a string of a given length to see if it is all printable and
- * has a valid terminator.
+ * Check a property of a given length to see if it is all printable and
+ * has a valid terminator. The property can contain either a single string,
+ * or multiple strings each of non-zero length.
*
* @param data The string to check
* @param len The string length including terminator
- * @return 1 if a valid printable string, 0 if not */
+ * @return 1 if a valid printable string, 0 if not
+ */
int util_is_printable_string(const void *data, int len);
/*
@@ -83,6 +88,13 @@ char get_escape_char(const char *s, int *i);
char *utilfdt_read(const char *filename);
/**
+ * Like utilfdt_read(), but also passes back the size of the file read.
+ *
+ * @param len If non-NULL, the amount of data we managed to read
+ */
+char *utilfdt_read_len(const char *filename, off_t *len);
+
+/**
* Read a device tree file into a buffer. Does not report errors, but only
* returns them. The value returned can be passed to strerror() to obtain
* an error message for the user.
@@ -93,6 +105,12 @@ char *utilfdt_read(const char *filename);
*/
int utilfdt_read_err(const char *filename, char **buffp);
+/**
+ * Like utilfdt_read_err(), but also passes back the size of the file read.
+ *
+ * @param len If non-NULL, the amount of data we managed to read
+ */
+int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len);
/**
* Write a device tree buffer to a file. This will report any errors on
@@ -148,6 +166,85 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size);
#define USAGE_TYPE_MSG \
"<type>\ts=string, i=int, u=unsigned, x=hex\n" \
"\tOptional modifier prefix:\n" \
- "\t\thh or b=byte, h=2 byte, l=4 byte (default)\n";
+ "\t\thh or b=byte, h=2 byte, l=4 byte (default)";
+
+/**
+ * Print property data in a readable format to stdout
+ *
+ * Properties that look like strings will be printed as strings. Otherwise
+ * the data will be displayed either as cells (if len is a multiple of 4
+ * bytes) or bytes.
+ *
+ * If len is 0 then this function does nothing.
+ *
+ * @param data Pointers to property data
+ * @param len Length of property data
+ */
+void utilfdt_print_data(const char *data, int len);
+
+/**
+ * Show source version and exit
+ */
+void util_version(void) __attribute__((noreturn));
+
+/**
+ * Show usage and exit
+ *
+ * This helps standardize the output of various utils. You most likely want
+ * to use the usage() helper below rather than call this.
+ *
+ * @param errmsg If non-NULL, an error message to display
+ * @param synopsis The initial example usage text (and possible examples)
+ * @param short_opts The string of short options
+ * @param long_opts The structure of long options
+ * @param opts_help An array of help strings (should align with long_opts)
+ */
+void util_usage(const char *errmsg, const char *synopsis,
+ const char *short_opts, struct option const long_opts[],
+ const char * const opts_help[]) __attribute__((noreturn));
+
+/**
+ * Show usage and exit
+ *
+ * If you name all your usage variables with usage_xxx, then you can call this
+ * help macro rather than expanding all arguments yourself.
+ *
+ * @param errmsg If non-NULL, an error message to display
+ */
+#define usage(errmsg) \
+ util_usage(errmsg, usage_synopsis, usage_short_opts, \
+ usage_long_opts, usage_opts_help)
+
+/**
+ * Call getopt_long() with standard options
+ *
+ * Since all util code runs getopt in the same way, provide a helper.
+ */
+#define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
+ usage_long_opts, NULL)
+
+/* Helper for aligning long_opts array */
+#define a_argument required_argument
+
+/* Helper for usage_short_opts string constant */
+#define USAGE_COMMON_SHORT_OPTS "hV"
+
+/* Helper for usage_long_opts option array */
+#define USAGE_COMMON_LONG_OPTS \
+ {"help", no_argument, NULL, 'h'}, \
+ {"version", no_argument, NULL, 'V'}, \
+ {NULL, no_argument, NULL, 0x0}
+
+/* Helper for usage_opts_help array */
+#define USAGE_COMMON_OPTS_HELP \
+ "Print this help and exit", \
+ "Print version and exit", \
+ NULL
+
+/* Helper for getopt case statements */
+#define case_USAGE_COMMON_FLAGS \
+ case 'h': usage(NULL); \
+ case 'V': util_version(); \
+ case '?': usage("unknown option");
#endif /* _UTIL_H */
diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h
index 6158b867df99..54d4e904433a 100644
--- a/scripts/dtc/version_gen.h
+++ b/scripts/dtc/version_gen.h
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.2.0-g37c0b6a0"
+#define DTC_VERSION "DTC 1.4.0-dirty"
diff --git a/scripts/gcc-ld b/scripts/gcc-ld
new file mode 100644
index 000000000000..cadab9a13ed7
--- /dev/null
+++ b/scripts/gcc-ld
@@ -0,0 +1,29 @@
+#!/bin/sh
+# run gcc with ld options
+# used as a wrapper to execute link time optimizations
+# yes virginia, this is not pretty
+
+ARGS="-nostdlib"
+
+while [ "$1" != "" ] ; do
+ case "$1" in
+ -save-temps|-m32|-m64) N="$1" ;;
+ -r) N="$1" ;;
+ -[Wg]*) N="$1" ;;
+ -[olv]|-[Ofd]*|-nostdlib) N="$1" ;;
+ --end-group|--start-group)
+ N="-Wl,$1" ;;
+ -[RTFGhIezcbyYu]*|\
+--script|--defsym|-init|-Map|--oformat|-rpath|\
+-rpath-link|--sort-section|--section-start|-Tbss|-Tdata|-Ttext|\
+--version-script|--dynamic-list|--version-exports-symbol|--wrap|-m)
+ A="$1" ; shift ; N="-Wl,$A,$1" ;;
+ -[m]*) N="$1" ;;
+ -*) N="-Wl,$1" ;;
+ *) N="$1" ;;
+ esac
+ ARGS="$ARGS $N"
+ shift
+done
+
+exec $CC $ARGS
diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh
index ef474098d9f1..17fa901418ae 100644
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -257,7 +257,7 @@ case "$arg" in
&& compr="lzop -9 -f"
echo "$output_file" | grep -q "\.lz4$" \
&& [ -x "`which lz4 2> /dev/null`" ] \
- && compr="lz4 -9 -f"
+ && compr="lz4 -l -9 -f"
echo "$output_file" | grep -q "\.cpio$" && compr="cat"
shift
;;
diff --git a/scripts/ld-version.sh b/scripts/ld-version.sh
new file mode 100755
index 000000000000..198580d245e0
--- /dev/null
+++ b/scripts/ld-version.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/awk -f
+# extract linker version number from stdin and turn into single number
+ {
+ gsub(".*)", "");
+ split($1,a, ".");
+ print a[1]*10000000 + a[2]*100000 + a[3]*10000 + a[4]*100 + a[5];
+ exit
+ }
diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c
index bb5d115ca671..f282516acc7b 100644
--- a/scripts/mod/devicetable-offsets.c
+++ b/scripts/mod/devicetable-offsets.c
@@ -174,6 +174,9 @@ int main(void)
DEVID_FIELD(x86_cpu_id, model);
DEVID_FIELD(x86_cpu_id, vendor);
+ DEVID(cpu_feature);
+ DEVID_FIELD(cpu_feature, feature);
+
DEVID(mei_cl_device_id);
DEVID_FIELD(mei_cl_device_id, name);
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 25e5cb0aaef6..25f6f5970552 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -1110,7 +1110,7 @@ static int do_amba_entry(const char *filename,
}
ADD_TO_DEVTABLE("amba", amba_id, do_amba_entry);
-/* LOOKS like x86cpu:vendor:VVVV:family:FFFF:model:MMMM:feature:*,FEAT,*
+/* LOOKS like cpu:type:x86,venVVVVfamFFFFmodMMMM:feature:*,FEAT,*
* All fields are numbers. It would be nicer to use strings for vendor
* and feature, but getting those out of the build system here is too
* complicated.
@@ -1124,10 +1124,10 @@ static int do_x86cpu_entry(const char *filename, void *symval,
DEF_FIELD(symval, x86_cpu_id, model);
DEF_FIELD(symval, x86_cpu_id, vendor);
- strcpy(alias, "x86cpu:");
- ADD(alias, "vendor:", vendor != X86_VENDOR_ANY, vendor);
- ADD(alias, ":family:", family != X86_FAMILY_ANY, family);
- ADD(alias, ":model:", model != X86_MODEL_ANY, model);
+ strcpy(alias, "cpu:type:x86,");
+ ADD(alias, "ven", vendor != X86_VENDOR_ANY, vendor);
+ ADD(alias, "fam", family != X86_FAMILY_ANY, family);
+ ADD(alias, "mod", model != X86_MODEL_ANY, model);
strcat(alias, ":feature:*");
if (feature != X86_FEATURE_ANY)
sprintf(alias + strlen(alias), "%04X*", feature);
@@ -1135,6 +1135,16 @@ static int do_x86cpu_entry(const char *filename, void *symval,
}
ADD_TO_DEVTABLE("x86cpu", x86_cpu_id, do_x86cpu_entry);
+/* LOOKS like cpu:type:*:feature:*FEAT* */
+static int do_cpu_entry(const char *filename, void *symval, char *alias)
+{
+ DEF_FIELD(symval, cpu_feature, feature);
+
+ sprintf(alias, "cpu:type:*:feature:*%04X*", feature);
+ return 1;
+}
+ADD_TO_DEVTABLE("cpu", cpu_feature, do_cpu_entry);
+
/* Looks like: mei:S */
static int do_mei_entry(const char *filename, void *symval,
char *alias)
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 40610984a1b5..066355673930 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -623,7 +623,10 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
switch (sym->st_shndx) {
case SHN_COMMON:
- warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
+ if (!strncmp(symname, "__gnu_lto_", sizeof("__gnu_lto_")-1)) {
+ /* Should warn here, but modpost runs before the linker */
+ } else
+ warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
break;
case SHN_UNDEF:
/* undefined symbol */
@@ -849,6 +852,7 @@ static const char *section_white_list[] =
".xt.lit", /* xtensa */
".arcextmap*", /* arc */
".gnu.linkonce.arcext*", /* arc : modules */
+ ".gnu.lto*",
NULL
};
@@ -1455,6 +1459,10 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf,
to = find_elf_symbol(elf, r->r_addend, sym);
tosym = sym_name(elf, to);
+ if (!strncmp(fromsym, "reference___initcall",
+ sizeof("reference___initcall")-1))
+ return;
+
/* check whitelist - we may ignore it */
if (secref_whitelist(mismatch,
fromsec, fromsym, tosec, tosym)) {
@@ -1502,6 +1510,16 @@ static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
#define R_ARM_JUMP24 29
#endif
+#ifndef R_ARM_THM_CALL
+#define R_ARM_THM_CALL 10
+#endif
+#ifndef R_ARM_THM_JUMP24
+#define R_ARM_THM_JUMP24 30
+#endif
+#ifndef R_ARM_THM_JUMP19
+#define R_ARM_THM_JUMP19 51
+#endif
+
static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
{
unsigned int r_typ = ELF_R_TYPE(r->r_info);
@@ -1515,6 +1533,9 @@ static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
case R_ARM_PC24:
case R_ARM_CALL:
case R_ARM_JUMP24:
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_JUMP19:
/* From ARM ABI: ((S + A) | T) - P */
r->r_addend = (int)(long)(elf->hdr +
sechdr->sh_offset +
@@ -1680,6 +1701,19 @@ static void check_sec_ref(struct module *mod, const char *modname,
}
}
+static char *remove_dot(char *s)
+{
+ char *end;
+ int n = strcspn(s, ".");
+
+ if (n > 0 && s[n] != 0) {
+ strtoul(s + n + 1, &end, 10);
+ if (end > s + n + 1 && (*end == '.' || *end == 0))
+ s[n] = 0;
+ }
+ return s;
+}
+
static void read_symbols(char *modname)
{
const char *symname;
@@ -1718,7 +1752,7 @@ static void read_symbols(char *modname)
}
for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
- symname = info.strtab + sym->st_name;
+ symname = remove_dot(info.strtab + sym->st_name);
handle_modversions(mod, &info, sym, symname);
handle_moddevtable(mod, &info, sym, symname);
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index 51207e4d5f8b..168b43dc0a59 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -127,7 +127,7 @@ struct elf_info {
Elf_Section export_gpl_sec;
Elf_Section export_unused_gpl_sec;
Elf_Section export_gpl_future_sec;
- const char *strtab;
+ char *strtab;
char *modinfo;
unsigned int modinfo_len;
diff --git a/security/capability.c b/security/capability.c
index 8b4f24ae4338..21e2b9cae685 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -757,7 +757,8 @@ static void cap_skb_owned_by(struct sk_buff *skb, struct sock *sk)
#ifdef CONFIG_SECURITY_NETWORK_XFRM
static int cap_xfrm_policy_alloc_security(struct xfrm_sec_ctx **ctxp,
- struct xfrm_user_sec_ctx *sec_ctx)
+ struct xfrm_user_sec_ctx *sec_ctx,
+ gfp_t gfp)
{
return 0;
}
diff --git a/security/keys/compat.c b/security/keys/compat.c
index bbd32c729dbb..347896548ad3 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -65,8 +65,8 @@ no_payload:
* taking a 32-bit syscall are zero. If you can, you should call sys_keyctl()
* directly.
*/
-asmlinkage long compat_sys_keyctl(u32 option,
- u32 arg2, u32 arg3, u32 arg4, u32 arg5)
+COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
+ u32, arg2, u32, arg3, u32, arg4, u32, arg5)
{
switch (option) {
case KEYCTL_GET_KEYRING_ID:
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index d46cbc5e335e..2fb2576dc644 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -1000,7 +1000,11 @@ static int keyring_detect_cycle_iterator(const void *object,
kenter("{%d}", key->serial);
- BUG_ON(key != ctx->match_data);
+ /* We might get a keyring with matching index-key that is nonetheless a
+ * different keyring. */
+ if (key != ctx->match_data)
+ return 0;
+
ctx->result = ERR_PTR(-EDEADLK);
return 1;
}
diff --git a/security/security.c b/security/security.c
index 15b6928592ef..919cad93ac82 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1317,9 +1317,11 @@ void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
#ifdef CONFIG_SECURITY_NETWORK_XFRM
-int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx)
+int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
+ struct xfrm_user_sec_ctx *sec_ctx,
+ gfp_t gfp)
{
- return security_ops->xfrm_policy_alloc_security(ctxp, sec_ctx);
+ return security_ops->xfrm_policy_alloc_security(ctxp, sec_ctx, gfp);
}
EXPORT_SYMBOL(security_xfrm_policy_alloc);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4b34847208cc..b332e2cc0954 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -668,7 +668,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
if (flags[i] == SBLABEL_MNT)
continue;
rc = security_context_to_sid(mount_options[i],
- strlen(mount_options[i]), &sid);
+ strlen(mount_options[i]), &sid, GFP_KERNEL);
if (rc) {
printk(KERN_WARNING "SELinux: security_context_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n",
@@ -2489,7 +2489,8 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
if (flags[i] == SBLABEL_MNT)
continue;
len = strlen(mount_options[i]);
- rc = security_context_to_sid(mount_options[i], len, &sid);
+ rc = security_context_to_sid(mount_options[i], len, &sid,
+ GFP_KERNEL);
if (rc) {
printk(KERN_WARNING "SELinux: security_context_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n",
@@ -2893,7 +2894,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
if (rc)
return rc;
- rc = security_context_to_sid(value, size, &newsid);
+ rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL);
if (rc == -EINVAL) {
if (!capable(CAP_MAC_ADMIN)) {
struct audit_buffer *ab;
@@ -3050,7 +3051,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
if (!value || !size)
return -EACCES;
- rc = security_context_to_sid((void *)value, size, &newsid);
+ rc = security_context_to_sid((void *)value, size, &newsid, GFP_KERNEL);
if (rc)
return rc;
@@ -5529,7 +5530,7 @@ static int selinux_setprocattr(struct task_struct *p,
str[size-1] = 0;
size--;
}
- error = security_context_to_sid(value, size, &sid);
+ error = security_context_to_sid(value, size, &sid, GFP_KERNEL);
if (error == -EINVAL && !strcmp(name, "fscreate")) {
if (!capable(CAP_MAC_ADMIN)) {
struct audit_buffer *ab;
@@ -5638,7 +5639,7 @@ static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
- return security_context_to_sid(secdata, seclen, secid);
+ return security_context_to_sid(secdata, seclen, secid, GFP_KERNEL);
}
static void selinux_release_secctx(char *secdata, u32 seclen)
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 8ed8daf7f1ee..ce7852cf526b 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -134,7 +134,7 @@ int security_sid_to_context(u32 sid, char **scontext,
int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len);
int security_context_to_sid(const char *scontext, u32 scontext_len,
- u32 *out_sid);
+ u32 *out_sid, gfp_t gfp);
int security_context_to_sid_default(const char *scontext, u32 scontext_len,
u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index 48c3cc94c168..9f0584710c85 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -10,7 +10,8 @@
#include <net/flow.h>
int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
- struct xfrm_user_sec_ctx *uctx);
+ struct xfrm_user_sec_ctx *uctx,
+ gfp_t gfp);
int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
struct xfrm_sec_ctx **new_ctxp);
void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 5122affe06a8..d60c0ee66387 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -576,7 +576,7 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
if (length)
goto out;
- length = security_context_to_sid(buf, size, &sid);
+ length = security_context_to_sid(buf, size, &sid, GFP_KERNEL);
if (length)
goto out;
@@ -731,11 +731,13 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
- length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
+ length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
+ GFP_KERNEL);
if (length)
goto out;
- length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
+ length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
+ GFP_KERNEL);
if (length)
goto out;
@@ -817,11 +819,13 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
objname = namebuf;
}
- length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
+ length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
+ GFP_KERNEL);
if (length)
goto out;
- length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
+ length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
+ GFP_KERNEL);
if (length)
goto out;
@@ -878,11 +882,13 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
- length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
+ length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
+ GFP_KERNEL);
if (length)
goto out;
- length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
+ length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
+ GFP_KERNEL);
if (length)
goto out;
@@ -934,7 +940,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s", con, user) != 2)
goto out;
- length = security_context_to_sid(con, strlen(con) + 1, &sid);
+ length = security_context_to_sid(con, strlen(con) + 1, &sid, GFP_KERNEL);
if (length)
goto out;
@@ -994,11 +1000,13 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
- length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
+ length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
+ GFP_KERNEL);
if (length)
goto out;
- length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
+ length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
+ GFP_KERNEL);
if (length)
goto out;
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index c0f498842129..9c5cdc2caaef 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -3338,10 +3338,10 @@ static int filename_write_helper(void *key, void *data, void *ptr)
if (rc)
return rc;
- buf[0] = ft->stype;
- buf[1] = ft->ttype;
- buf[2] = ft->tclass;
- buf[3] = otype->otype;
+ buf[0] = cpu_to_le32(ft->stype);
+ buf[1] = cpu_to_le32(ft->ttype);
+ buf[2] = cpu_to_le32(ft->tclass);
+ buf[3] = cpu_to_le32(otype->otype);
rc = put_entry(buf, sizeof(u32), 4, fp);
if (rc)
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 5d0144ee8ed6..4bca49414a40 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1289,16 +1289,18 @@ out:
* @scontext: security context
* @scontext_len: length in bytes
* @sid: security identifier, SID
+ * @gfp: context for the allocation
*
* Obtains a SID associated with the security context that
* has the string representation specified by @scontext.
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success.
*/
-int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
+int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
+ gfp_t gfp)
{
return security_context_to_sid_core(scontext, scontext_len,
- sid, SECSID_NULL, GFP_KERNEL, 0);
+ sid, SECSID_NULL, gfp, 0);
}
/**
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 0462cb3ff0a7..98b042630a9e 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -78,7 +78,8 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
* xfrm_user_sec_ctx context.
*/
static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
- struct xfrm_user_sec_ctx *uctx)
+ struct xfrm_user_sec_ctx *uctx,
+ gfp_t gfp)
{
int rc;
const struct task_security_struct *tsec = current_security();
@@ -94,7 +95,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
if (str_len >= PAGE_SIZE)
return -ENOMEM;
- ctx = kmalloc(sizeof(*ctx) + str_len + 1, GFP_KERNEL);
+ ctx = kmalloc(sizeof(*ctx) + str_len + 1, gfp);
if (!ctx)
return -ENOMEM;
@@ -103,7 +104,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
ctx->ctx_len = str_len;
memcpy(ctx->ctx_str, &uctx[1], str_len);
ctx->ctx_str[str_len] = '\0';
- rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid);
+ rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid, gfp);
if (rc)
goto err;
@@ -282,9 +283,10 @@ int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid)
* LSM hook implementation that allocs and transfers uctx spec to xfrm_policy.
*/
int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
- struct xfrm_user_sec_ctx *uctx)
+ struct xfrm_user_sec_ctx *uctx,
+ gfp_t gfp)
{
- return selinux_xfrm_alloc_user(ctxp, uctx);
+ return selinux_xfrm_alloc_user(ctxp, uctx, gfp);
}
/*
@@ -332,7 +334,7 @@ int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
int selinux_xfrm_state_alloc(struct xfrm_state *x,
struct xfrm_user_sec_ctx *uctx)
{
- return selinux_xfrm_alloc_user(&x->security, uctx);
+ return selinux_xfrm_alloc_user(&x->security, uctx, GFP_KERNEL);
}
/*
diff --git a/sound/aoa/aoa.h b/sound/aoa/aoa.h
index e08789484e30..34c668f27798 100644
--- a/sound/aoa/aoa.h
+++ b/sound/aoa/aoa.h
@@ -116,7 +116,7 @@ struct aoa_card {
struct snd_card *alsa_card;
};
-extern int aoa_snd_device_new(snd_device_type_t type,
+extern int aoa_snd_device_new(enum snd_device_type type,
void * device_data, struct snd_device_ops * ops);
extern struct snd_card *aoa_get_card(void);
extern int aoa_snd_ctl_add(struct snd_kcontrol* control);
diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c
index 4cedc6950d72..f01bffb702bc 100644
--- a/sound/aoa/codecs/onyx.c
+++ b/sound/aoa/codecs/onyx.c
@@ -889,7 +889,7 @@ static int onyx_init_codec(struct aoa_codec *codec)
return -ENODEV;
}
- if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, onyx, &ops)) {
+ if (aoa_snd_device_new(SNDRV_DEV_CODEC, onyx, &ops)) {
printk(KERN_ERR PFX "failed to create onyx snd device!\n");
return -ENODEV;
}
diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c
index c491ae0f749c..cf3c6303b7e3 100644
--- a/sound/aoa/codecs/tas.c
+++ b/sound/aoa/codecs/tas.c
@@ -826,7 +826,7 @@ static int tas_init_codec(struct aoa_codec *codec)
return -ENODEV;
}
- if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, tas, &ops)) {
+ if (aoa_snd_device_new(SNDRV_DEV_CODEC, tas, &ops)) {
printk(KERN_ERR PFX "failed to create tas snd device!\n");
return -ENODEV;
}
diff --git a/sound/aoa/codecs/toonie.c b/sound/aoa/codecs/toonie.c
index 69d2cb601f2a..7e8c3417cd85 100644
--- a/sound/aoa/codecs/toonie.c
+++ b/sound/aoa/codecs/toonie.c
@@ -92,7 +92,7 @@ static int toonie_init_codec(struct aoa_codec *codec)
if (toonie->codec.connected != 1)
return -ENOTCONN;
- if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, toonie, &ops)) {
+ if (aoa_snd_device_new(SNDRV_DEV_CODEC, toonie, &ops)) {
printk(KERN_ERR PFX "failed to create toonie snd device!\n");
return -ENODEV;
}
diff --git a/sound/aoa/core/alsa.c b/sound/aoa/core/alsa.c
index 0fa3855b4790..4a7e4e6b746f 100644
--- a/sound/aoa/core/alsa.c
+++ b/sound/aoa/core/alsa.c
@@ -23,13 +23,12 @@ int aoa_alsa_init(char *name, struct module *mod, struct device *dev)
/* cannot be EEXIST due to usage in aoa_fabric_register */
return -EBUSY;
- err = snd_card_create(index, name, mod, sizeof(struct aoa_card),
- &alsa_card);
+ err = snd_card_new(dev, index, name, mod, sizeof(struct aoa_card),
+ &alsa_card);
if (err < 0)
return err;
aoa_card = alsa_card->private_data;
aoa_card->alsa_card = alsa_card;
- alsa_card->dev = dev;
strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver));
strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname));
strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname));
@@ -60,7 +59,7 @@ void aoa_alsa_cleanup(void)
}
}
-int aoa_snd_device_new(snd_device_type_t type,
+int aoa_snd_device_new(enum snd_device_type type,
void * device_data, struct snd_device_ops * ops)
{
struct snd_card *card = aoa_get_card();
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index c421fdb3c7a1..0e83a73efb16 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -899,8 +899,8 @@ static struct aaci *aaci_init_card(struct amba_device *dev)
struct snd_card *card;
int err;
- err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- THIS_MODULE, sizeof(struct aaci), &card);
+ err = snd_card_new(&dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, sizeof(struct aaci), &card);
if (err < 0)
return NULL;
@@ -1055,8 +1055,6 @@ static int aaci_probe(struct amba_device *dev,
if (ret)
goto out;
- snd_card_set_dev(aaci->card, &dev->dev);
-
ret = snd_card_register(aaci->card);
if (ret == 0) {
dev_info(&dev->dev, "%s\n", aaci->card->longname);
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index 9a2ac1e0f77a..3a10df6688ee 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -179,12 +179,11 @@ static int pxa2xx_ac97_probe(struct platform_device *dev)
goto err_dev;
}
- ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- THIS_MODULE, 0, &card);
+ ret = snd_card_new(&dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &card);
if (ret < 0)
goto err;
- card->dev = &dev->dev;
strlcpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
ret = pxa2xx_pcm_new(card, &pxa2xx_ac97_pcm_client, &pxa2xx_ac97_pcm);
@@ -210,7 +209,6 @@ static int pxa2xx_ac97_probe(struct platform_device *dev)
if (pdata && pdata->codec_pdata[0])
snd_ac97_dev_add_pdata(ac97_bus->codec[0], pdata->codec_pdata[0]);
- snd_card_set_dev(card, &dev->dev);
ret = snd_card_register(card);
if (ret == 0) {
platform_set_drvdata(dev, card);
diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c
index 3519518e25a0..edf2ca72d518 100644
--- a/sound/atmel/abdac.c
+++ b/sound/atmel/abdac.c
@@ -429,8 +429,9 @@ static int atmel_abdac_probe(struct platform_device *pdev)
}
clk_enable(pclk);
- retval = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- THIS_MODULE, sizeof(struct atmel_abdac), &card);
+ retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
+ SNDRV_DEFAULT_STR1, THIS_MODULE,
+ sizeof(struct atmel_abdac), &card);
if (retval) {
dev_dbg(&pdev->dev, "could not create sound card device\n");
goto out_put_sample_clk;
@@ -467,8 +468,6 @@ static int atmel_abdac_probe(struct platform_device *pdev)
goto out_unmap_regs;
}
- snd_card_set_dev(card, &pdev->dev);
-
if (pdata->dws.dma_dev) {
dma_cap_mask_t mask;
@@ -492,7 +491,7 @@ static int atmel_abdac_probe(struct platform_device *pdev)
if (!pdata->dws.dma_dev || !dac->dma.chan) {
dev_dbg(&pdev->dev, "DMA not available\n");
retval = -ENODEV;
- goto out_unset_card_dev;
+ goto out_unmap_regs;
}
strcpy(card->driver, "Atmel ABDAC");
@@ -521,9 +520,6 @@ static int atmel_abdac_probe(struct platform_device *pdev)
out_release_dma:
dma_release_channel(dac->dma.chan);
dac->dma.chan = NULL;
-out_unset_card_dev:
- snd_card_set_dev(card, NULL);
- free_irq(irq, dac);
out_unmap_regs:
iounmap(dac->regs);
out_free_card:
@@ -579,7 +575,6 @@ static int atmel_abdac_remove(struct platform_device *pdev)
dma_release_channel(dac->dma.chan);
dac->dma.chan = NULL;
- snd_card_set_dev(card, NULL);
iounmap(dac->regs);
free_irq(dac->irq, dac);
snd_card_free(card);
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index c5f0ddd729b3..05ec049c9faf 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -945,8 +945,9 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
}
clk_enable(pclk);
- retval = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- THIS_MODULE, sizeof(struct atmel_ac97c), &card);
+ retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
+ SNDRV_DEFAULT_STR1, THIS_MODULE,
+ sizeof(struct atmel_ac97c), &card);
if (retval) {
dev_dbg(&pdev->dev, "could not create sound card device\n");
goto err_snd_card_new;
@@ -990,8 +991,6 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
chip->reset_pin = -EINVAL;
}
- snd_card_set_dev(card, &pdev->dev);
-
atmel_ac97c_reset(chip);
/* Enable overrun interrupt from codec channel */
@@ -1113,8 +1112,6 @@ err_dma:
chip->dma.tx_chan = NULL;
}
err_ac97_bus:
- snd_card_set_dev(card, NULL);
-
if (gpio_is_valid(chip->reset_pin))
gpio_free(chip->reset_pin);
@@ -1195,7 +1192,6 @@ static int atmel_ac97c_remove(struct platform_device *pdev)
chip->dma.tx_chan = NULL;
}
- snd_card_set_dev(card, NULL);
snd_card_free(card);
return 0;
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 7a20897d33db..7403f348ed14 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -133,7 +133,7 @@ static int snd_compr_open(struct inode *inode, struct file *f)
kfree(data);
}
snd_card_unref(compr->card);
- return 0;
+ return ret;
}
static int snd_compr_free(struct inode *inode, struct file *f)
diff --git a/sound/core/control.c b/sound/core/control.c
index d8aa206e8bde..f038f5afafe2 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -151,7 +151,7 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
if (snd_BUG_ON(!card || !id))
return;
read_lock(&card->ctl_files_rwlock);
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
card->mixer_oss_change_count++;
#endif
list_for_each_entry(ctl, &card->ctl_files, list) {
@@ -170,7 +170,7 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
ev->mask = mask;
list_add_tail(&ev->list, &ctl->events);
} else {
- snd_printk(KERN_ERR "No memory available to allocate event\n");
+ dev_err(card->dev, "No memory available to allocate event\n");
}
_found:
wake_up(&ctl->change_sleep);
@@ -206,7 +206,7 @@ static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL);
if (kctl == NULL) {
- snd_printk(KERN_ERR "Cannot allocate control instance\n");
+ pr_err("ALSA: Cannot allocate control instance\n");
return NULL;
}
*kctl = *control;
@@ -241,9 +241,8 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
if (ncontrol->name) {
strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name));
if (strcmp(ncontrol->name, kctl.id.name) != 0)
- snd_printk(KERN_WARNING
- "Control name '%s' truncated to '%s'\n",
- ncontrol->name, kctl.id.name);
+ pr_warn("ALSA: Control name '%s' truncated to '%s'\n",
+ ncontrol->name, kctl.id.name);
}
kctl.id.index = ncontrol->index;
kctl.count = ncontrol->count ? ncontrol->count : 1;
@@ -306,7 +305,7 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
while (snd_ctl_remove_numid_conflict(card, count)) {
if (--iter == 0) {
/* this situation is very unlikely */
- snd_printk(KERN_ERR "unable to allocate new control numid\n");
+ dev_err(card->dev, "unable to allocate new control numid\n");
return -ENOMEM;
}
}
@@ -341,7 +340,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
down_write(&card->controls_rwsem);
if (snd_ctl_find_id(card, &id)) {
up_write(&card->controls_rwsem);
- snd_printd(KERN_ERR "control %i:%i:%i:%s:%i is already present\n",
+ dev_err(card->dev, "control %i:%i:%i:%s:%i is already present\n",
id.iface,
id.device,
id.subdevice,
@@ -1406,7 +1405,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
}
}
up_read(&snd_ioctl_rwsem);
- snd_printdd("unknown ioctl = 0x%x\n", cmd);
+ dev_dbg(card->dev, "unknown ioctl = 0x%x\n", cmd);
return -ENOTTY;
}
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index 2bb95a7a8809..b9c0910fb8c4 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -247,7 +247,7 @@ static int copy_ctl_value_from_user(struct snd_card *card,
} else {
size = get_elem_size(type, count);
if (size < 0) {
- printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
+ dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
return -EINVAL;
}
if (copy_from_user(data->value.bytes.data,
diff --git a/sound/core/device.c b/sound/core/device.c
index df88defed176..41bec3075ae5 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -41,29 +41,73 @@
*
* Return: Zero if successful, or a negative error code on failure.
*/
-int snd_device_new(struct snd_card *card, snd_device_type_t type,
+int snd_device_new(struct snd_card *card, enum snd_device_type type,
void *device_data, struct snd_device_ops *ops)
{
struct snd_device *dev;
+ struct list_head *p;
if (snd_BUG_ON(!card || !device_data || !ops))
return -ENXIO;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
- snd_printk(KERN_ERR "Cannot allocate device\n");
+ dev_err(card->dev, "Cannot allocate device, type=%d\n", type);
return -ENOMEM;
}
+ INIT_LIST_HEAD(&dev->list);
dev->card = card;
dev->type = type;
dev->state = SNDRV_DEV_BUILD;
dev->device_data = device_data;
dev->ops = ops;
- list_add(&dev->list, &card->devices); /* add to the head of list */
+
+ /* insert the entry in an incrementally sorted list */
+ list_for_each_prev(p, &card->devices) {
+ struct snd_device *pdev = list_entry(p, struct snd_device, list);
+ if ((unsigned int)pdev->type <= (unsigned int)type)
+ break;
+ }
+
+ list_add(&dev->list, p);
return 0;
}
-
EXPORT_SYMBOL(snd_device_new);
+static int __snd_device_disconnect(struct snd_device *dev)
+{
+ if (dev->state == SNDRV_DEV_REGISTERED) {
+ if (dev->ops->dev_disconnect &&
+ dev->ops->dev_disconnect(dev))
+ dev_err(dev->card->dev, "device disconnect failure\n");
+ dev->state = SNDRV_DEV_DISCONNECTED;
+ }
+ return 0;
+}
+
+static void __snd_device_free(struct snd_device *dev)
+{
+ /* unlink */
+ list_del(&dev->list);
+
+ __snd_device_disconnect(dev);
+ if (dev->ops->dev_free) {
+ if (dev->ops->dev_free(dev))
+ dev_err(dev->card->dev, "device free failure\n");
+ }
+ kfree(dev);
+}
+
+static struct snd_device *look_for_dev(struct snd_card *card, void *device_data)
+{
+ struct snd_device *dev;
+
+ list_for_each_entry(dev, &card->devices, list)
+ if (dev->device_data == device_data)
+ return dev;
+
+ return NULL;
+}
+
/**
* snd_device_free - release the device from the card
* @card: the card instance
@@ -72,73 +116,33 @@ EXPORT_SYMBOL(snd_device_new);
* Removes the device from the list on the card and invokes the
* callbacks, dev_disconnect and dev_free, corresponding to the state.
* Then release the device.
- *
- * Return: Zero if successful, or a negative error code on failure or if the
- * device not found.
*/
-int snd_device_free(struct snd_card *card, void *device_data)
+void snd_device_free(struct snd_card *card, void *device_data)
{
struct snd_device *dev;
if (snd_BUG_ON(!card || !device_data))
- return -ENXIO;
- list_for_each_entry(dev, &card->devices, list) {
- if (dev->device_data != device_data)
- continue;
- /* unlink */
- list_del(&dev->list);
- if (dev->state == SNDRV_DEV_REGISTERED &&
- dev->ops->dev_disconnect)
- if (dev->ops->dev_disconnect(dev))
- snd_printk(KERN_ERR
- "device disconnect failure\n");
- if (dev->ops->dev_free) {
- if (dev->ops->dev_free(dev))
- snd_printk(KERN_ERR "device free failure\n");
- }
- kfree(dev);
- return 0;
- }
- snd_printd("device free %p (from %pF), not found\n", device_data,
- __builtin_return_address(0));
- return -ENXIO;
+ return;
+ dev = look_for_dev(card, device_data);
+ if (dev)
+ __snd_device_free(dev);
+ else
+ dev_dbg(card->dev, "device free %p (from %pF), not found\n",
+ device_data, __builtin_return_address(0));
}
-
EXPORT_SYMBOL(snd_device_free);
-/**
- * snd_device_disconnect - disconnect the device
- * @card: the card instance
- * @device_data: the data pointer to disconnect
- *
- * Turns the device into the disconnection state, invoking
- * dev_disconnect callback, if the device was already registered.
- *
- * Usually called from snd_card_disconnect().
- *
- * Return: Zero if successful, or a negative error code on failure or if the
- * device not found.
- */
-int snd_device_disconnect(struct snd_card *card, void *device_data)
+static int __snd_device_register(struct snd_device *dev)
{
- struct snd_device *dev;
-
- if (snd_BUG_ON(!card || !device_data))
- return -ENXIO;
- list_for_each_entry(dev, &card->devices, list) {
- if (dev->device_data != device_data)
- continue;
- if (dev->state == SNDRV_DEV_REGISTERED &&
- dev->ops->dev_disconnect) {
- if (dev->ops->dev_disconnect(dev))
- snd_printk(KERN_ERR "device disconnect failure\n");
- dev->state = SNDRV_DEV_DISCONNECTED;
+ if (dev->state == SNDRV_DEV_BUILD) {
+ if (dev->ops->dev_register) {
+ int err = dev->ops->dev_register(dev);
+ if (err < 0)
+ return err;
}
- return 0;
+ dev->state = SNDRV_DEV_REGISTERED;
}
- snd_printd("device disconnect %p (from %pF), not found\n", device_data,
- __builtin_return_address(0));
- return -ENXIO;
+ return 0;
}
/**
@@ -157,26 +161,15 @@ int snd_device_disconnect(struct snd_card *card, void *device_data)
int snd_device_register(struct snd_card *card, void *device_data)
{
struct snd_device *dev;
- int err;
if (snd_BUG_ON(!card || !device_data))
return -ENXIO;
- list_for_each_entry(dev, &card->devices, list) {
- if (dev->device_data != device_data)
- continue;
- if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
- if ((err = dev->ops->dev_register(dev)) < 0)
- return err;
- dev->state = SNDRV_DEV_REGISTERED;
- return 0;
- }
- snd_printd("snd_device_register busy\n");
- return -EBUSY;
- }
+ dev = look_for_dev(card, device_data);
+ if (dev)
+ return __snd_device_register(dev);
snd_BUG();
return -ENXIO;
}
-
EXPORT_SYMBOL(snd_device_register);
/*
@@ -191,11 +184,9 @@ int snd_device_register_all(struct snd_card *card)
if (snd_BUG_ON(!card))
return -ENXIO;
list_for_each_entry(dev, &card->devices, list) {
- if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
- if ((err = dev->ops->dev_register(dev)) < 0)
- return err;
- dev->state = SNDRV_DEV_REGISTERED;
- }
+ err = __snd_device_register(dev);
+ if (err < 0)
+ return err;
}
return 0;
}
@@ -211,8 +202,8 @@ int snd_device_disconnect_all(struct snd_card *card)
if (snd_BUG_ON(!card))
return -ENXIO;
- list_for_each_entry(dev, &card->devices, list) {
- if (snd_device_disconnect(card, dev->device_data) < 0)
+ list_for_each_entry_reverse(dev, &card->devices, list) {
+ if (__snd_device_disconnect(dev) < 0)
err = -ENXIO;
}
return err;
@@ -222,24 +213,12 @@ int snd_device_disconnect_all(struct snd_card *card)
* release all the devices on the card.
* called from init.c
*/
-int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd)
+void snd_device_free_all(struct snd_card *card)
{
- struct snd_device *dev;
- int err;
- unsigned int range_low, range_high, type;
+ struct snd_device *dev, *next;
if (snd_BUG_ON(!card))
- return -ENXIO;
- range_low = (__force unsigned int)cmd * SNDRV_DEV_TYPE_RANGE_SIZE;
- range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1;
- __again:
- list_for_each_entry(dev, &card->devices, list) {
- type = (__force unsigned int)dev->type;
- if (type >= range_low && type <= range_high) {
- if ((err = snd_device_free(card, dev->device_data)) < 0)
- return err;
- goto __again;
- }
- }
- return 0;
+ return;
+ list_for_each_entry_safe_reverse(dev, next, &card->devices, list)
+ __snd_device_free(dev);
}
diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c
index b8b31c433d64..886be7da989d 100644
--- a/sound/core/hrtimer.c
+++ b/sound/core/hrtimer.c
@@ -126,8 +126,7 @@ static int __init snd_hrtimer_init(void)
hrtimer_get_res(CLOCK_MONOTONIC, &tp);
if (tp.tv_sec > 0 || !tp.tv_nsec) {
- snd_printk(KERN_ERR
- "snd-hrtimer: Invalid resolution %u.%09u",
+ pr_err("snd-hrtimer: Invalid resolution %u.%09u",
(unsigned)tp.tv_sec, (unsigned)tp.tv_nsec);
return -EINVAL;
}
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index d105073298cb..69459e5f712e 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -375,7 +375,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
*rhwdep = NULL;
hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL);
if (hwdep == NULL) {
- snd_printk(KERN_ERR "hwdep: cannot allocate\n");
+ dev_err(card->dev, "hwdep: cannot allocate\n");
return -ENOMEM;
}
hwdep->card = card;
@@ -395,6 +395,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
*rhwdep = hwdep;
return 0;
}
+EXPORT_SYMBOL(snd_hwdep_new);
static int snd_hwdep_free(struct snd_hwdep *hwdep)
{
@@ -415,37 +416,61 @@ static int snd_hwdep_dev_free(struct snd_device *device)
static int snd_hwdep_dev_register(struct snd_device *device)
{
struct snd_hwdep *hwdep = device->device_data;
+ struct snd_card *card = hwdep->card;
+ struct device *dev;
int err;
char name[32];
mutex_lock(&register_mutex);
- if (snd_hwdep_search(hwdep->card, hwdep->device)) {
+ if (snd_hwdep_search(card, hwdep->device)) {
mutex_unlock(&register_mutex);
return -EBUSY;
}
list_add_tail(&hwdep->list, &snd_hwdep_devices);
sprintf(name, "hwC%iD%i", hwdep->card->number, hwdep->device);
- if ((err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP,
- hwdep->card, hwdep->device,
- &snd_hwdep_f_ops, hwdep, name)) < 0) {
- snd_printk(KERN_ERR "unable to register hardware dependent device %i:%i\n",
- hwdep->card->number, hwdep->device);
+ dev = hwdep->dev;
+ if (!dev)
+ dev = snd_card_get_device_link(hwdep->card);
+ err = snd_register_device_for_dev(SNDRV_DEVICE_TYPE_HWDEP,
+ hwdep->card, hwdep->device,
+ &snd_hwdep_f_ops, hwdep, name, dev);
+ if (err < 0) {
+ dev_err(dev,
+ "unable to register hardware dependent device %i:%i\n",
+ card->number, hwdep->device);
list_del(&hwdep->list);
mutex_unlock(&register_mutex);
return err;
}
+
+ if (hwdep->groups) {
+ struct device *d = snd_get_device(SNDRV_DEVICE_TYPE_HWDEP,
+ hwdep->card, hwdep->device);
+ if (d) {
+ if (hwdep->private_data)
+ dev_set_drvdata(d, hwdep->private_data);
+ err = sysfs_create_groups(&d->kobj, hwdep->groups);
+ if (err < 0)
+ dev_warn(dev,
+ "hwdep %d:%d: cannot create sysfs groups\n",
+ card->number, hwdep->device);
+ put_device(d);
+ }
+ }
+
#ifdef CONFIG_SND_OSSEMUL
hwdep->ossreg = 0;
if (hwdep->oss_type >= 0) {
if ((hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM) && (hwdep->device != 0)) {
- snd_printk (KERN_WARNING "only hwdep device 0 can be registered as OSS direct FM device!\n");
+ dev_warn(dev,
+ "only hwdep device 0 can be registered as OSS direct FM device!\n");
} else {
if (snd_register_oss_device(hwdep->oss_type,
- hwdep->card, hwdep->device,
- &snd_hwdep_f_ops, hwdep,
- hwdep->oss_dev) < 0) {
- snd_printk(KERN_ERR "unable to register OSS compatibility device %i:%i\n",
- hwdep->card->number, hwdep->device);
+ card, hwdep->device,
+ &snd_hwdep_f_ops, hwdep) < 0) {
+ dev_err(dev,
+ "unable to register OSS compatibility device %i:%i\n",
+ card->number, hwdep->device);
} else
hwdep->ossreg = 1;
}
@@ -543,5 +568,3 @@ static void __exit alsa_hwdep_exit(void)
module_init(alsa_hwdep_init)
module_exit(alsa_hwdep_exit)
-
-EXPORT_SYMBOL(snd_hwdep_new);
diff --git a/sound/core/info.c b/sound/core/info.c
index e79baa11b60e..051d55b05521 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -418,9 +418,14 @@ static int snd_info_entry_release(struct inode *inode, struct file *file)
if (entry->c.text.write) {
entry->c.text.write(entry, data->wbuffer);
if (data->wbuffer->error) {
- snd_printk(KERN_WARNING "data write error to %s (%i)\n",
- entry->name,
- data->wbuffer->error);
+ if (entry->card)
+ dev_warn(entry->card->dev, "info: data write error to %s (%i)\n",
+ entry->name,
+ data->wbuffer->error);
+ else
+ pr_warn("ALSA: info: data write error to %s (%i)\n",
+ entry->name,
+ data->wbuffer->error);
}
}
kfree(data->wbuffer->buffer);
@@ -540,7 +545,7 @@ int __init snd_info_init(void)
snd_oss_root = entry;
}
#endif
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
{
struct snd_info_entry *entry;
if ((entry = snd_info_create_module_entry(THIS_MODULE, "seq", NULL)) == NULL)
@@ -567,7 +572,7 @@ int __exit snd_info_done(void)
snd_minor_info_done();
snd_info_version_done();
if (snd_proc_root) {
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
snd_info_free_entry(snd_seq_root);
#endif
#ifdef CONFIG_SND_OSSEMUL
diff --git a/sound/core/init.c b/sound/core/init.c
index 0d42fcda0de2..5ee83845c5de 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -28,6 +28,7 @@
#include <linux/time.h>
#include <linux/ctype.h>
#include <linux/pm.h>
+#include <linux/completion.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -94,7 +95,7 @@ static int module_slot_match(struct module *module, int idx)
return match;
}
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag);
EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
#endif
@@ -112,11 +113,11 @@ static inline int init_info_for_card(struct snd_card *card)
struct snd_info_entry *entry;
if ((err = snd_info_card_register(card)) < 0) {
- snd_printd("unable to create card info\n");
+ dev_dbg(card->dev, "unable to create card info\n");
return err;
}
if ((entry = snd_info_create_card_entry(card, "id", card->proc_root)) == NULL) {
- snd_printd("unable to create card entry\n");
+ dev_dbg(card->dev, "unable to create card entry\n");
return err;
}
entry->c.text.read = snd_card_id_read;
@@ -156,8 +157,17 @@ static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
return mask; /* unchanged */
}
+static int snd_card_do_free(struct snd_card *card);
+static const struct attribute_group *card_dev_attr_groups[];
+
+static void release_card_device(struct device *dev)
+{
+ snd_card_do_free(dev_to_snd_card(dev));
+}
+
/**
- * snd_card_create - create and initialize a soundcard structure
+ * snd_card_new - create and initialize a soundcard structure
+ * @parent: the parent device object
* @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
* @xid: card identification (ASCII string)
* @module: top level module for locking
@@ -172,7 +182,7 @@ static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
*
* Return: Zero if successful or a negative error code.
*/
-int snd_card_create(int idx, const char *xid,
+int snd_card_new(struct device *parent, int idx, const char *xid,
struct module *module, int extra_size,
struct snd_card **card_ret)
{
@@ -188,6 +198,8 @@ int snd_card_create(int idx, const char *xid,
card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
if (!card)
return -ENOMEM;
+ if (extra_size > 0)
+ card->private_data = (char *)card + sizeof(struct snd_card);
if (xid)
strlcpy(card->id, xid, sizeof(card->id));
err = 0;
@@ -205,14 +217,16 @@ int snd_card_create(int idx, const char *xid,
err = -ENODEV;
if (err < 0) {
mutex_unlock(&snd_card_mutex);
- snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n",
+ dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n",
idx, snd_ecards_limit - 1, err);
- goto __error;
+ kfree(card);
+ return err;
}
set_bit(idx, snd_cards_lock); /* lock it */
if (idx >= snd_ecards_limit)
snd_ecards_limit = idx + 1; /* increase the limit */
mutex_unlock(&snd_card_mutex);
+ card->dev = parent;
card->number = idx;
card->module = module;
INIT_LIST_HEAD(&card->devices);
@@ -222,36 +236,42 @@ int snd_card_create(int idx, const char *xid,
INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock);
INIT_LIST_HEAD(&card->files_list);
- init_waitqueue_head(&card->shutdown_sleep);
- atomic_set(&card->refcount, 0);
#ifdef CONFIG_PM
mutex_init(&card->power_lock);
init_waitqueue_head(&card->power_sleep);
#endif
+
+ device_initialize(&card->card_dev);
+ card->card_dev.parent = parent;
+ card->card_dev.class = sound_class;
+ card->card_dev.release = release_card_device;
+ card->card_dev.groups = card_dev_attr_groups;
+ err = kobject_set_name(&card->card_dev.kobj, "card%d", idx);
+ if (err < 0)
+ goto __error;
+
/* the control interface cannot be accessed from the user space until */
/* snd_cards_bitmask and snd_cards are set with snd_card_register */
err = snd_ctl_create(card);
if (err < 0) {
- snd_printk(KERN_ERR "unable to register control minors\n");
+ dev_err(parent, "unable to register control minors\n");
goto __error;
}
err = snd_info_card_create(card);
if (err < 0) {
- snd_printk(KERN_ERR "unable to create card info\n");
+ dev_err(parent, "unable to create card info\n");
goto __error_ctl;
}
- if (extra_size > 0)
- card->private_data = (char *)card + sizeof(struct snd_card);
*card_ret = card;
return 0;
__error_ctl:
- snd_device_free_all(card, SNDRV_DEV_CMD_PRE);
+ snd_device_free_all(card);
__error:
- kfree(card);
+ put_device(&card->card_dev);
return err;
}
-EXPORT_SYMBOL(snd_card_create);
+EXPORT_SYMBOL(snd_card_new);
/* return non-zero if a card is already locked */
int snd_card_locked(int card)
@@ -394,7 +414,7 @@ int snd_card_disconnect(struct snd_card *card)
/* phase 3: notify all connected devices about disconnection */
/* at this point, they cannot respond to any calls except release() */
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_DISCONNECT);
#endif
@@ -402,12 +422,12 @@ int snd_card_disconnect(struct snd_card *card)
/* notify all devices that we are disconnected */
err = snd_device_disconnect_all(card);
if (err < 0)
- snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
+ dev_err(card->dev, "not all devices for card %i can be disconnected\n", card->number);
snd_info_card_disconnect(card);
- if (card->card_dev) {
- device_unregister(card->card_dev);
- card->card_dev = NULL;
+ if (card->registered) {
+ device_del(&card->card_dev);
+ card->registered = false;
}
#ifdef CONFIG_PM
wake_up(&card->power_sleep);
@@ -430,81 +450,48 @@ EXPORT_SYMBOL(snd_card_disconnect);
*/
static int snd_card_do_free(struct snd_card *card)
{
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
#endif
- if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) {
- snd_printk(KERN_ERR "unable to free all devices (pre)\n");
- /* Fatal, but this situation should never occur */
- }
- if (snd_device_free_all(card, SNDRV_DEV_CMD_NORMAL) < 0) {
- snd_printk(KERN_ERR "unable to free all devices (normal)\n");
- /* Fatal, but this situation should never occur */
- }
- if (snd_device_free_all(card, SNDRV_DEV_CMD_POST) < 0) {
- snd_printk(KERN_ERR "unable to free all devices (post)\n");
- /* Fatal, but this situation should never occur */
- }
+ snd_device_free_all(card);
if (card->private_free)
card->private_free(card);
snd_info_free_entry(card->proc_id);
if (snd_info_card_free(card) < 0) {
- snd_printk(KERN_WARNING "unable to free card info\n");
+ dev_warn(card->dev, "unable to free card info\n");
/* Not fatal error */
}
+ if (card->release_completion)
+ complete(card->release_completion);
kfree(card);
return 0;
}
-/**
- * snd_card_unref - release the reference counter
- * @card: the card instance
- *
- * Decrements the reference counter. When it reaches to zero, wake up
- * the sleeper and call the destructor if needed.
- */
-void snd_card_unref(struct snd_card *card)
-{
- if (atomic_dec_and_test(&card->refcount)) {
- wake_up(&card->shutdown_sleep);
- if (card->free_on_last_close)
- snd_card_do_free(card);
- }
-}
-EXPORT_SYMBOL(snd_card_unref);
-
int snd_card_free_when_closed(struct snd_card *card)
{
- int ret;
-
- atomic_inc(&card->refcount);
- ret = snd_card_disconnect(card);
- if (ret) {
- atomic_dec(&card->refcount);
+ int ret = snd_card_disconnect(card);
+ if (ret)
return ret;
- }
-
- card->free_on_last_close = 1;
- if (atomic_dec_and_test(&card->refcount))
- snd_card_do_free(card);
+ put_device(&card->card_dev);
return 0;
}
-
EXPORT_SYMBOL(snd_card_free_when_closed);
int snd_card_free(struct snd_card *card)
{
- int ret = snd_card_disconnect(card);
+ struct completion released;
+ int ret;
+
+ init_completion(&released);
+ card->release_completion = &released;
+ ret = snd_card_free_when_closed(card);
if (ret)
return ret;
-
/* wait, until all devices are ready for the free operation */
- wait_event(card->shutdown_sleep, !atomic_read(&card->refcount));
- snd_card_do_free(card);
+ wait_for_completion(&released);
return 0;
}
-
EXPORT_SYMBOL(snd_card_free);
/* retrieve the last word of shortname or longname */
@@ -598,7 +585,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
goto again;
}
/* last resort... */
- snd_printk(KERN_ERR "unable to set card id (%s)\n", id);
+ dev_err(card->dev, "unable to set card id (%s)\n", id);
if (card->proc_root->name)
strlcpy(card->id, card->proc_root->name, sizeof(card->id));
}
@@ -626,15 +613,15 @@ static ssize_t
card_id_show_attr(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct snd_card *card = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n", card ? card->id : "(null)");
+ struct snd_card *card = container_of(dev, struct snd_card, card_dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n", card->id);
}
static ssize_t
card_id_store_attr(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct snd_card *card = dev_get_drvdata(dev);
+ struct snd_card *card = container_of(dev, struct snd_card, card_dev);
char buf1[sizeof(card->id)];
size_t copy = count > sizeof(card->id) - 1 ?
sizeof(card->id) - 1 : count;
@@ -660,19 +647,32 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct device_attribute card_id_attrs =
- __ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr);
+static DEVICE_ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr);
static ssize_t
card_number_show_attr(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct snd_card *card = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%i\n", card ? card->number : -1);
+ struct snd_card *card = container_of(dev, struct snd_card, card_dev);
+ return snprintf(buf, PAGE_SIZE, "%i\n", card->number);
}
-static struct device_attribute card_number_attrs =
- __ATTR(number, S_IRUGO, card_number_show_attr, NULL);
+static DEVICE_ATTR(number, S_IRUGO, card_number_show_attr, NULL);
+
+static struct attribute *card_dev_attrs[] = {
+ &dev_attr_id.attr,
+ &dev_attr_number.attr,
+ NULL
+};
+
+static struct attribute_group card_dev_attr_group = {
+ .attrs = card_dev_attrs,
+};
+
+static const struct attribute_group *card_dev_attr_groups[] = {
+ &card_dev_attr_group,
+ NULL
+};
/**
* snd_card_register - register the soundcard
@@ -692,12 +692,11 @@ int snd_card_register(struct snd_card *card)
if (snd_BUG_ON(!card))
return -EINVAL;
- if (!card->card_dev) {
- card->card_dev = device_create(sound_class, card->dev,
- MKDEV(0, 0), card,
- "card%i", card->number);
- if (IS_ERR(card->card_dev))
- card->card_dev = NULL;
+ if (!card->registered) {
+ err = device_add(&card->card_dev);
+ if (err < 0)
+ return err;
+ card->registered = true;
}
if ((err = snd_device_register_all(card)) < 0)
@@ -723,19 +722,10 @@ int snd_card_register(struct snd_card *card)
snd_cards[card->number] = card;
mutex_unlock(&snd_card_mutex);
init_info_for_card(card);
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER);
#endif
- if (card->card_dev) {
- err = device_create_file(card->card_dev, &card_id_attrs);
- if (err < 0)
- return err;
- err = device_create_file(card->card_dev, &card_number_attrs);
- if (err < 0)
- return err;
- }
-
return 0;
}
@@ -908,7 +898,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
return -ENODEV;
}
list_add(&mfile->list, &card->files_list);
- atomic_inc(&card->refcount);
+ get_device(&card->card_dev);
spin_unlock(&card->files_lock);
return 0;
}
@@ -947,11 +937,11 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
}
spin_unlock(&card->files_lock);
if (!found) {
- snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
+ dev_err(card->dev, "card file remove problem (%p)\n", file);
return -ENOENT;
}
kfree(found);
- snd_card_unref(card);
+ put_device(&card->card_dev);
return 0;
}
diff --git a/sound/core/isadma.c b/sound/core/isadma.c
index e2b386156a4c..31e8544d7f2d 100644
--- a/sound/core/isadma.c
+++ b/sound/core/isadma.c
@@ -106,7 +106,7 @@ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
result = result1;
#ifdef CONFIG_SND_DEBUG
if (result > size)
- snd_printk(KERN_ERR "pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
+ pr_err("ALSA: pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
#endif
if (result >= size || result == 0)
return 0;
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 4595f93d151e..082509eb805d 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -207,7 +207,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
break;
#endif
default:
- printk(KERN_ERR "snd-malloc: invalid device type %d\n", type);
+ pr_err("snd-malloc: invalid device type %d\n", type);
dmab->area = NULL;
dmab->addr = 0;
return -ENXIO;
@@ -284,7 +284,7 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
break;
#endif
default:
- printk(KERN_ERR "snd-malloc: invalid device type %d\n", dmab->dev.type);
+ pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type);
}
}
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index e8a1d18774b2..5e6349f00ecd 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1187,7 +1187,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0)
break;
if (ch >= SNDRV_OSS_MAX_MIXERS) {
- snd_printk(KERN_ERR "mixer_oss: invalid OSS volume '%s'\n", str);
+ pr_err("ALSA: mixer_oss: invalid OSS volume '%s'\n",
+ str);
continue;
}
cptr = snd_info_get_str(str, cptr, sizeof(str));
@@ -1201,7 +1202,7 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
snd_info_get_str(idxstr, cptr, sizeof(idxstr));
idx = simple_strtoul(idxstr, NULL, 10);
if (idx >= 0x4000) { /* too big */
- snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx);
+ pr_err("ALSA: mixer_oss: invalid index %d\n", idx);
continue;
}
mutex_lock(&mixer->reg_mutex);
@@ -1212,7 +1213,7 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
goto __unlock;
tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
if (! tbl) {
- snd_printk(KERN_ERR "mixer_oss: no memory\n");
+ pr_err("ALSA: mixer_oss: no memory\n");
goto __unlock;
}
tbl->oss_id = ch;
@@ -1343,20 +1344,18 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
struct snd_mixer_oss *mixer;
if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) {
- char name[128];
int idx, err;
mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL);
if (mixer == NULL)
return -ENOMEM;
mutex_init(&mixer->reg_mutex);
- sprintf(name, "mixer%i%i", card->number, 0);
if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
card, 0,
- &snd_mixer_oss_f_ops, card,
- name)) < 0) {
- snd_printk(KERN_ERR "unable to register OSS mixer device %i:%i\n",
- card->number, 0);
+ &snd_mixer_oss_f_ops, card)) < 0) {
+ dev_err(card->dev,
+ "unable to register OSS mixer device %i:%i\n",
+ card->number, 0);
kfree(mixer);
return err;
}
@@ -1365,7 +1364,8 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
if (*card->mixername)
strlcpy(mixer->name, card->mixername, sizeof(mixer->name));
else
- strlcpy(mixer->name, name, sizeof(mixer->name));
+ snprintf(mixer->name, sizeof(mixer->name),
+ "mixer%i", card->number);
#ifdef SNDRV_OSS_INFO_DEV_MIXERS
snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
card->number,
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 4c1cc51772e6..ada69d7a8d70 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -854,7 +854,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
params = kmalloc(sizeof(*params), GFP_KERNEL);
sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
if (!sw_params || !params || !sparams) {
- snd_printd("No memory\n");
+ pcm_dbg(substream->pcm, "No memory\n");
err = -ENOMEM;
goto failure;
}
@@ -877,7 +877,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
}
err = snd_pcm_hw_param_mask(substream, sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);
if (err < 0) {
- snd_printd("No usable accesses\n");
+ pcm_dbg(substream->pcm, "No usable accesses\n");
err = -EINVAL;
goto failure;
}
@@ -902,7 +902,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
break;
}
if ((__force int)sformat > (__force int)SNDRV_PCM_FORMAT_LAST) {
- snd_printd("Cannot find a format!!!\n");
+ pcm_dbg(substream->pcm, "Cannot find a format!!!\n");
err = -EINVAL;
goto failure;
}
@@ -942,14 +942,16 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
if ((err = snd_pcm_plug_format_plugins(substream,
params,
sparams)) < 0) {
- snd_printd("snd_pcm_plug_format_plugins failed: %i\n", err);
+ pcm_dbg(substream->pcm,
+ "snd_pcm_plug_format_plugins failed: %i\n", err);
snd_pcm_oss_plugin_clear(substream);
goto failure;
}
if (runtime->oss.plugin_first) {
struct snd_pcm_plugin *plugin;
if ((err = snd_pcm_plugin_build_io(substream, sparams, &plugin)) < 0) {
- snd_printd("snd_pcm_plugin_build_io failed: %i\n", err);
+ pcm_dbg(substream->pcm,
+ "snd_pcm_plugin_build_io failed: %i\n", err);
snd_pcm_oss_plugin_clear(substream);
goto failure;
}
@@ -983,7 +985,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams)) < 0) {
- snd_printd("HW_PARAMS failed: %i\n", err);
+ pcm_dbg(substream->pcm, "HW_PARAMS failed: %i\n", err);
goto failure;
}
@@ -1016,7 +1018,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
}
if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) {
- snd_printd("SW_PARAMS failed: %i\n", err);
+ pcm_dbg(substream->pcm, "SW_PARAMS failed: %i\n", err);
goto failure;
}
@@ -1110,7 +1112,8 @@ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
if (err < 0) {
- snd_printd("snd_pcm_oss_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n");
+ pcm_dbg(substream->pcm,
+ "snd_pcm_oss_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n");
return err;
}
runtime->oss.prepare = 0;
@@ -1175,12 +1178,10 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const
if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk(KERN_DEBUG "pcm_oss: write: "
- "recovering from XRUN\n");
- else
- printk(KERN_DEBUG "pcm_oss: write: "
- "recovering from SUSPEND\n");
+ pcm_dbg(substream->pcm,
+ "pcm_oss: write: recovering from %s\n",
+ runtime->status->state == SNDRV_PCM_STATE_XRUN ?
+ "XRUN" : "SUSPEND");
#endif
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
@@ -1213,12 +1214,10 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk(KERN_DEBUG "pcm_oss: read: "
- "recovering from XRUN\n");
- else
- printk(KERN_DEBUG "pcm_oss: read: "
- "recovering from SUSPEND\n");
+ pcm_dbg(substream->pcm,
+ "pcm_oss: read: recovering from %s\n",
+ runtime->status->state == SNDRV_PCM_STATE_XRUN ?
+ "XRUN" : "SUSPEND");
#endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
if (ret < 0)
@@ -1261,12 +1260,10 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void
if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk(KERN_DEBUG "pcm_oss: writev: "
- "recovering from XRUN\n");
- else
- printk(KERN_DEBUG "pcm_oss: writev: "
- "recovering from SUSPEND\n");
+ pcm_dbg(substream->pcm,
+ "pcm_oss: writev: recovering from %s\n",
+ runtime->status->state == SNDRV_PCM_STATE_XRUN ?
+ "XRUN" : "SUSPEND");
#endif
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
@@ -1299,12 +1296,10 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void *
if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
- if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk(KERN_DEBUG "pcm_oss: readv: "
- "recovering from XRUN\n");
- else
- printk(KERN_DEBUG "pcm_oss: readv: "
- "recovering from SUSPEND\n");
+ pcm_dbg(substream->pcm,
+ "pcm_oss: readv: recovering from %s\n",
+ runtime->status->state == SNDRV_PCM_STATE_XRUN ?
+ "XRUN" : "SUSPEND");
#endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
if (ret < 0)
@@ -1561,7 +1556,7 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
init_waitqueue_entry(&wait, current);
add_wait_queue(&runtime->sleep, &wait);
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "sync1: size = %li\n", size);
+ pcm_dbg(substream->pcm, "sync1: size = %li\n", size);
#endif
while (1) {
result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1);
@@ -1587,7 +1582,8 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
break;
}
if (res == 0) {
- snd_printk(KERN_ERR "OSS sync error - DMA timeout\n");
+ pcm_err(substream->pcm,
+ "OSS sync error - DMA timeout\n");
result = -EIO;
break;
}
@@ -1618,7 +1614,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
mutex_lock(&runtime->oss.params_lock);
if (runtime->oss.buffer_used > 0) {
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "sync: buffer_used\n");
+ pcm_dbg(substream->pcm, "sync: buffer_used\n");
#endif
size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width;
snd_pcm_format_set_silence(format,
@@ -1631,7 +1627,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
}
} else if (runtime->oss.period_ptr > 0) {
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "sync: period_ptr\n");
+ pcm_dbg(substream->pcm, "sync: period_ptr\n");
#endif
size = runtime->oss.period_bytes - runtime->oss.period_ptr;
snd_pcm_format_set_silence(format,
@@ -1983,7 +1979,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
int err, cmd;
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "pcm_oss: trigger = 0x%x\n", trigger);
+ pcm_dbg(substream->pcm, "pcm_oss: trigger = 0x%x\n", trigger);
#endif
psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
@@ -2203,9 +2199,9 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre
}
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "pcm_oss: space: bytes = %i, fragments = %i, "
- "fragstotal = %i, fragsize = %i\n",
- info.bytes, info.fragments, info.fragstotal, info.fragsize);
+ pcm_dbg(substream->pcm,
+ "pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n",
+ info.bytes, info.fragments, info.fragstotal, info.fragsize);
#endif
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
@@ -2215,7 +2211,7 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre
static int snd_pcm_oss_get_mapbuf(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct buffmem_desc __user * _info)
{
// it won't be probably implemented
- // snd_printd("TODO: snd_pcm_oss_get_mapbuf\n");
+ // pr_debug("TODO: snd_pcm_oss_get_mapbuf\n");
return -EINVAL;
}
@@ -2519,7 +2515,7 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
if (((cmd >> 8) & 0xff) != 'P')
return -EINVAL;
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "pcm_oss: ioctl = 0x%x\n", cmd);
+ pr_debug("pcm_oss: ioctl = 0x%x\n", cmd);
#endif
switch (cmd) {
case SNDCTL_DSP_RESET:
@@ -2646,7 +2642,7 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
case SNDCTL_DSP_PROFILE:
return 0; /* silently ignore */
default:
- snd_printd("pcm_oss: unknown command = 0x%x\n", cmd);
+ pr_debug("pcm_oss: unknown command = 0x%x\n", cmd);
}
return -EINVAL;
}
@@ -2673,8 +2669,9 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun
#else
{
ssize_t res = snd_pcm_oss_read1(substream, buf, count);
- printk(KERN_DEBUG "pcm_oss: read %li bytes "
- "(returned %li bytes)\n", (long)count, (long)res);
+ pcm_dbg(substream->pcm,
+ "pcm_oss: read %li bytes (returned %li bytes)\n",
+ (long)count, (long)res);
return res;
}
#endif
@@ -2693,7 +2690,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size
substream->f_flags = file->f_flags & O_NONBLOCK;
result = snd_pcm_oss_write1(substream, buf, count);
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "pcm_oss: write %li bytes (wrote %li bytes)\n",
+ pcm_dbg(substream->pcm, "pcm_oss: write %li bytes (wrote %li bytes)\n",
(long)count, (long)result);
#endif
return result;
@@ -2772,7 +2769,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
int err;
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "pcm_oss: mmap begin\n");
+ pr_debug("pcm_oss: mmap begin\n");
#endif
pcm_oss_file = file->private_data;
switch ((area->vm_flags & (VM_READ | VM_WRITE))) {
@@ -2822,7 +2819,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
runtime->silence_threshold = 0;
runtime->silence_size = 0;
#ifdef OSS_DEBUG
- printk(KERN_DEBUG "pcm_oss: mmap ok, bytes = 0x%x\n",
+ pr_debug("pcm_oss: mmap ok, bytes = 0x%x\n",
runtime->oss.mmap_bytes);
#endif
/* In mmap mode we never stop */
@@ -3007,12 +3004,10 @@ static const struct file_operations snd_pcm_oss_f_reg =
static void register_oss_dsp(struct snd_pcm *pcm, int index)
{
- char name[128];
- sprintf(name, "dsp%i%i", pcm->card->number, pcm->device);
if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
pcm->card, index, &snd_pcm_oss_f_reg,
- pcm, name) < 0) {
- snd_printk(KERN_ERR "unable to register OSS PCM device %i:%i\n",
+ pcm) < 0) {
+ pcm_err(pcm, "unable to register OSS PCM device %i:%i\n",
pcm->card->number, pcm->device);
}
}
@@ -3093,12 +3088,12 @@ static int __init alsa_pcm_oss_init(void)
/* check device map table */
for (i = 0; i < SNDRV_CARDS; i++) {
if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) {
- snd_printk(KERN_ERR "invalid dsp_map[%d] = %d\n",
+ pr_err("ALSA: pcm_oss: invalid dsp_map[%d] = %d\n",
i, dsp_map[i]);
dsp_map[i] = 0;
}
if (adsp_map[i] < 0 || adsp_map[i] >= SNDRV_PCM_DEVICES) {
- snd_printk(KERN_ERR "invalid adsp_map[%d] = %d\n",
+ pr_err("ALSA: pcm_oss: invalid adsp_map[%d] = %d\n",
i, adsp_map[i]);
adsp_map[i] = 1;
}
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index e1e9e0c999fe..43932e8dce66 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -295,7 +295,7 @@ static const char *snd_pcm_state_name(snd_pcm_state_t state)
return snd_pcm_state_names[(__force int)state];
}
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
#include <linux/soundcard.h>
static const char *snd_pcm_oss_format_name(int format)
@@ -338,7 +338,8 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (! info) {
- printk(KERN_DEBUG "snd_pcm_proc_info_read: cannot malloc\n");
+ pcm_dbg(substream->pcm,
+ "snd_pcm_proc_info_read: cannot malloc\n");
return;
}
@@ -398,7 +399,7 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "rate: %u (%u/%u)\n", runtime->rate, runtime->rate_num, runtime->rate_den);
snd_iprintf(buffer, "period_size: %lu\n", runtime->period_size);
snd_iprintf(buffer, "buffer_size: %lu\n", runtime->buffer_size);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
if (substream->oss.oss) {
snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format));
snd_iprintf(buffer, "OSS channels: %u\n", runtime->oss.channels);
@@ -651,7 +652,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
struct snd_pcm_str *pstr = &pcm->streams[stream];
struct snd_pcm_substream *substream, *prev;
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
mutex_init(&pstr->oss.setup_mutex);
#endif
pstr->stream = stream;
@@ -660,7 +661,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
if (substream_count > 0 && !pcm->internal) {
err = snd_pcm_stream_proc_init(pstr);
if (err < 0) {
- snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n");
+ pcm_err(pcm, "Error in snd_pcm_stream_proc_init\n");
return err;
}
}
@@ -668,7 +669,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
for (idx = 0, prev = NULL; idx < substream_count; idx++) {
substream = kzalloc(sizeof(*substream), GFP_KERNEL);
if (substream == NULL) {
- snd_printk(KERN_ERR "Cannot allocate PCM substream\n");
+ pcm_err(pcm, "Cannot allocate PCM substream\n");
return -ENOMEM;
}
substream->pcm = pcm;
@@ -685,7 +686,8 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
if (!pcm->internal) {
err = snd_pcm_substream_proc_init(substream);
if (err < 0) {
- snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n");
+ pcm_err(pcm,
+ "Error in snd_pcm_stream_proc_init\n");
if (prev == NULL)
pstr->substream = NULL;
else
@@ -724,7 +726,7 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
*rpcm = NULL;
pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
if (pcm == NULL) {
- snd_printk(KERN_ERR "Cannot allocate PCM\n");
+ dev_err(card->dev, "Cannot allocate PCM\n");
return -ENOMEM;
}
pcm->card = card;
@@ -807,7 +809,7 @@ EXPORT_SYMBOL(snd_pcm_new_internal);
static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
{
struct snd_pcm_substream *substream, *substream_next;
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
struct snd_pcm_oss_setup *setup, *setupn;
#endif
substream = pstr->substream;
@@ -819,7 +821,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
substream = substream_next;
}
snd_pcm_stream_proc_done(pstr);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
for (setup = pstr->oss.setup_list; setup; setup = setupn) {
setupn = setup->next;
kfree(setup->task_name);
@@ -1016,8 +1018,20 @@ static ssize_t show_pcm_class(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%s\n", str);
}
-static struct device_attribute pcm_attrs =
- __ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL);
+static DEVICE_ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL);
+static struct attribute *pcm_dev_attrs[] = {
+ &dev_attr_pcm_class.attr,
+ NULL
+};
+
+static struct attribute_group pcm_dev_attr_group = {
+ .attrs = pcm_dev_attrs,
+};
+
+static const struct attribute_group *pcm_dev_attr_groups[] = {
+ &pcm_dev_attr_group,
+ NULL
+};
static int snd_pcm_dev_register(struct snd_device *device)
{
@@ -1067,8 +1081,18 @@ static int snd_pcm_dev_register(struct snd_device *device)
mutex_unlock(&register_mutex);
return err;
}
- snd_add_device_sysfs_file(devtype, pcm->card, pcm->device,
- &pcm_attrs);
+
+ dev = snd_get_device(devtype, pcm->card, pcm->device);
+ if (dev) {
+ err = sysfs_create_groups(&dev->kobj,
+ pcm_dev_attr_groups);
+ if (err < 0)
+ dev_warn(dev,
+ "pcm %d:%d: cannot create sysfs groups\n",
+ pcm->card->number, pcm->device);
+ put_device(dev);
+ }
+
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
snd_pcm_timer_init(substream);
}
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index a2104671f51d..ce83def9f43b 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -174,7 +174,7 @@ static void xrun(struct snd_pcm_substream *substream)
if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
char name[16];
snd_pcm_debug_name(substream, name, sizeof(name));
- snd_printd(KERN_DEBUG "XRUN: %s\n", name);
+ pcm_warn(substream->pcm, "XRUN: %s\n", name);
dump_stack_on_xrun(substream);
}
}
@@ -184,9 +184,7 @@ static void xrun(struct snd_pcm_substream *substream)
do { \
if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \
xrun_log_show(substream); \
- if (snd_printd_ratelimit()) { \
- snd_printd("PCM: " fmt, ##args); \
- } \
+ pr_err_ratelimited("ALSA: PCM: " fmt, ##args); \
dump_stack_on_xrun(substream); \
} \
} while (0)
@@ -253,7 +251,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
entry = &log->entries[idx];
if (entry->period_size == 0)
break;
- snd_printd("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, "
+ pr_info("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, "
"hwptr=%ld/%ld\n",
name, entry->in_interrupt ? "[Q] " : "",
entry->jiffies,
@@ -342,14 +340,14 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
return -EPIPE;
}
if (pos >= runtime->buffer_size) {
- if (snd_printd_ratelimit()) {
+ if (printk_ratelimit()) {
char name[16];
snd_pcm_debug_name(substream, name, sizeof(name));
xrun_log_show(substream);
- snd_printd(KERN_ERR "BUG: %s, pos = %ld, "
- "buffer size = %ld, period size = %ld\n",
- name, pos, runtime->buffer_size,
- runtime->period_size);
+ pcm_err(substream->pcm,
+ "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
+ name, pos, runtime->buffer_size,
+ runtime->period_size);
}
pos = 0;
}
@@ -394,8 +392,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
char name[16];
snd_pcm_debug_name(substream, name, sizeof(name));
- snd_printd("%s_update: %s: pos=%u/%u/%u, "
- "hwptr=%ld/%ld/%ld/%ld\n",
+ pcm_dbg(substream->pcm,
+ "%s_update: %s: pos=%u/%u/%u, hwptr=%ld/%ld/%ld/%ld\n",
in_interrupt ? "period" : "hwptr",
name,
(unsigned int)pos,
@@ -1242,6 +1240,7 @@ int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_par
return -EINVAL;
return 0;
}
+EXPORT_SYMBOL(snd_pcm_hw_constraint_mask64);
/**
* snd_pcm_hw_constraint_integer - apply an integer constraint to an interval
@@ -1941,8 +1940,9 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
continue;
}
if (!tout) {
- snd_printd("%s write error (DMA or IRQ trouble?)\n",
- is_playback ? "playback" : "capture");
+ pcm_dbg(substream->pcm,
+ "%s write error (DMA or IRQ trouble?)\n",
+ is_playback ? "playback" : "capture");
err = -EIO;
break;
}
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 01a5e05ede95..b653ab001fba 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -190,12 +190,12 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (!(params->rmask & (1 << k)))
continue;
#ifdef RULES_DEBUG
- printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
- printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
+ pr_debug("%s = ", snd_pcm_hw_param_names[k]);
+ pr_cont("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
#endif
changed = snd_mask_refine(m, constrs_mask(constrs, k));
#ifdef RULES_DEBUG
- printk("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
+ pr_cont("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
#endif
if (changed)
params->cmask |= 1 << k;
@@ -210,21 +210,21 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (!(params->rmask & (1 << k)))
continue;
#ifdef RULES_DEBUG
- printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
+ pr_debug("%s = ", snd_pcm_hw_param_names[k]);
if (i->empty)
- printk("empty");
+ pr_cont("empty");
else
- printk("%c%u %u%c",
+ pr_cont("%c%u %u%c",
i->openmin ? '(' : '[', i->min,
i->max, i->openmax ? ')' : ']');
- printk(" -> ");
+ pr_cont(" -> ");
#endif
changed = snd_interval_refine(i, constrs_interval(constrs, k));
#ifdef RULES_DEBUG
if (i->empty)
- printk("empty\n");
+ pr_cont("empty\n");
else
- printk("%c%u %u%c\n",
+ pr_cont("%c%u %u%c\n",
i->openmin ? '(' : '[', i->min,
i->max, i->openmax ? ')' : ']');
#endif
@@ -255,18 +255,18 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (!doit)
continue;
#ifdef RULES_DEBUG
- printk(KERN_DEBUG "Rule %d [%p]: ", k, r->func);
+ pr_debug("Rule %d [%p]: ", k, r->func);
if (r->var >= 0) {
- printk("%s = ", snd_pcm_hw_param_names[r->var]);
+ pr_cont("%s = ", snd_pcm_hw_param_names[r->var]);
if (hw_is_mask(r->var)) {
m = hw_param_mask(params, r->var);
- printk("%x", *m->bits);
+ pr_cont("%x", *m->bits);
} else {
i = hw_param_interval(params, r->var);
if (i->empty)
- printk("empty");
+ pr_cont("empty");
else
- printk("%c%u %u%c",
+ pr_cont("%c%u %u%c",
i->openmin ? '(' : '[', i->min,
i->max, i->openmax ? ')' : ']');
}
@@ -275,19 +275,19 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
changed = r->func(params, r);
#ifdef RULES_DEBUG
if (r->var >= 0) {
- printk(" -> ");
+ pr_cont(" -> ");
if (hw_is_mask(r->var))
- printk("%x", *m->bits);
+ pr_cont("%x", *m->bits);
else {
if (i->empty)
- printk("empty");
+ pr_cont("empty");
else
- printk("%c%u %u%c",
+ pr_cont("%c%u %u%c",
i->openmin ? '(' : '[', i->min,
i->max, i->openmax ? ')' : ']');
}
}
- printk("\n");
+ pr_cont("\n");
#endif
rstamps[k] = stamp;
if (changed && r->var >= 0) {
@@ -399,7 +399,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
return -EBADFD;
}
snd_pcm_stream_unlock_irq(substream);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
if (!substream->oss.oss)
#endif
if (atomic_read(&substream->mmap_count))
@@ -954,7 +954,7 @@ static struct action_ops snd_pcm_action_stop = {
*
* The state of each stream is then changed to the given state unconditionally.
*
- * Return: Zero if succesful, or a negative error code.
+ * Return: Zero if successful, or a negative error code.
*/
int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
@@ -1541,7 +1541,8 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
result = -ESTRPIPE;
else {
- snd_printd("playback drain error (DMA or IRQ trouble?)\n");
+ dev_dbg(substream->pcm->card->dev,
+ "playback drain error (DMA or IRQ trouble?)\n");
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
result = -EIO;
}
@@ -2066,7 +2067,7 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
err = snd_pcm_hw_constraints_init(substream);
if (err < 0) {
- snd_printd("snd_pcm_hw_constraints_init failed\n");
+ pcm_dbg(pcm, "snd_pcm_hw_constraints_init failed\n");
goto error;
}
@@ -2077,7 +2078,7 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
err = snd_pcm_hw_constraints_complete(substream);
if (err < 0) {
- snd_printd("snd_pcm_hw_constraints_complete failed\n");
+ pcm_dbg(pcm, "snd_pcm_hw_constraints_complete failed\n");
goto error;
}
@@ -2609,7 +2610,7 @@ static int snd_pcm_common_ioctl1(struct file *file,
return res;
}
}
- snd_printd("unknown ioctl = 0x%x\n", cmd);
+ pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);
return -ENOTTY;
}
diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c
index b01d9481d632..20ecd8f18080 100644
--- a/sound/core/pcm_timer.c
+++ b/sound/core/pcm_timer.c
@@ -53,7 +53,9 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream)
post *= 2;
}
if (rate == 0) {
- snd_printk(KERN_ERR "pcm timer resolution out of range (rate = %u, period_size = %lu)\n", runtime->rate, runtime->period_size);
+ pcm_err(substream->pcm,
+ "pcm timer resolution out of range (rate = %u, period_size = %lu)\n",
+ runtime->rate, runtime->period_size);
runtime->timer_resolution = -1;
return;
}
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 7b596b5751db..6fc71a4c8a51 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -56,6 +56,13 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device);
static LIST_HEAD(snd_rawmidi_devices);
static DEFINE_MUTEX(register_mutex);
+#define rmidi_err(rmidi, fmt, args...) \
+ dev_err((rmidi)->card->dev, fmt, ##args)
+#define rmidi_warn(rmidi, fmt, args...) \
+ dev_warn((rmidi)->card->dev, fmt, ##args)
+#define rmidi_dbg(rmidi, fmt, args...) \
+ dev_dbg((rmidi)->card->dev, fmt, ##args)
+
static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
{
struct snd_rawmidi *rawmidi;
@@ -165,6 +172,7 @@ int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
spin_unlock_irqrestore(&runtime->lock, flags);
return 0;
}
+EXPORT_SYMBOL(snd_rawmidi_drop_output);
int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
{
@@ -180,7 +188,9 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
if (signal_pending(current))
err = -ERESTARTSYS;
if (runtime->avail < runtime->buffer_size && !timeout) {
- snd_printk(KERN_WARNING "rawmidi drain error (avail = %li, buffer_size = %li)\n", (long)runtime->avail, (long)runtime->buffer_size);
+ rmidi_warn(substream->rmidi,
+ "rawmidi drain error (avail = %li, buffer_size = %li)\n",
+ (long)runtime->avail, (long)runtime->buffer_size);
err = -EIO;
}
runtime->drain = 0;
@@ -194,6 +204,7 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
}
return err;
}
+EXPORT_SYMBOL(snd_rawmidi_drain_output);
int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream)
{
@@ -208,6 +219,7 @@ int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream)
spin_unlock_irqrestore(&runtime->lock, flags);
return 0;
}
+EXPORT_SYMBOL(snd_rawmidi_drain_input);
/* look for an available substream for the given stream direction;
* if a specific subdevice is given, try to assign it
@@ -345,6 +357,7 @@ int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice,
module_put(rmidi->card->module);
return err;
}
+EXPORT_SYMBOL(snd_rawmidi_kernel_open);
static int snd_rawmidi_open(struct inode *inode, struct file *file)
{
@@ -523,6 +536,7 @@ int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile)
module_put(rmidi->card->module);
return 0;
}
+EXPORT_SYMBOL(snd_rawmidi_kernel_release);
static int snd_rawmidi_release(struct inode *inode, struct file *file)
{
@@ -599,6 +613,7 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info
}
return -ENXIO;
}
+EXPORT_SYMBOL(snd_rawmidi_info_select);
static int snd_rawmidi_info_select_user(struct snd_card *card,
struct snd_rawmidi_info __user *_info)
@@ -646,6 +661,7 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
substream->active_sensing = !params->no_active_sensing;
return 0;
}
+EXPORT_SYMBOL(snd_rawmidi_output_params);
int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_params * params)
@@ -671,6 +687,7 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
runtime->avail_min = params->avail_min;
return 0;
}
+EXPORT_SYMBOL(snd_rawmidi_input_params);
static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_status * status)
@@ -802,10 +819,9 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
return -EINVAL;
}
}
-#ifdef CONFIG_SND_DEBUG
default:
- snd_printk(KERN_WARNING "rawmidi: unknown command = 0x%x\n", cmd);
-#endif
+ rmidi_dbg(rfile->rmidi,
+ "rawmidi: unknown command = 0x%x\n", cmd);
}
return -ENOTTY;
}
@@ -875,7 +891,8 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
if (!substream->opened)
return -EBADFD;
if (runtime->buffer == NULL) {
- snd_printd("snd_rawmidi_receive: input is not active!!!\n");
+ rmidi_dbg(substream->rmidi,
+ "snd_rawmidi_receive: input is not active!!!\n");
return -EINVAL;
}
spin_lock_irqsave(&runtime->lock, flags);
@@ -926,6 +943,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
spin_unlock_irqrestore(&runtime->lock, flags);
return result;
}
+EXPORT_SYMBOL(snd_rawmidi_receive);
static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
unsigned char __user *userbuf,
@@ -968,6 +986,7 @@ long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream,
snd_rawmidi_input_trigger(substream, 1);
return snd_rawmidi_kernel_read1(substream, NULL/*userbuf*/, buf, count);
}
+EXPORT_SYMBOL(snd_rawmidi_kernel_read);
static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count,
loff_t *offset)
@@ -1034,7 +1053,8 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
unsigned long flags;
if (runtime->buffer == NULL) {
- snd_printd("snd_rawmidi_transmit_empty: output is not active!!!\n");
+ rmidi_dbg(substream->rmidi,
+ "snd_rawmidi_transmit_empty: output is not active!!!\n");
return 1;
}
spin_lock_irqsave(&runtime->lock, flags);
@@ -1042,6 +1062,7 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
spin_unlock_irqrestore(&runtime->lock, flags);
return result;
}
+EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
/**
* snd_rawmidi_transmit_peek - copy data from the internal buffer
@@ -1065,7 +1086,8 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_runtime *runtime = substream->runtime;
if (runtime->buffer == NULL) {
- snd_printd("snd_rawmidi_transmit_peek: output is not active!!!\n");
+ rmidi_dbg(substream->rmidi,
+ "snd_rawmidi_transmit_peek: output is not active!!!\n");
return -EINVAL;
}
result = 0;
@@ -1097,11 +1119,12 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
spin_unlock_irqrestore(&runtime->lock, flags);
return result;
}
+EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
/**
* snd_rawmidi_transmit_ack - acknowledge the transmission
* @substream: the rawmidi substream
- * @count: the tranferred count
+ * @count: the transferred count
*
* Advances the hardware pointer for the internal output buffer with
* the given size and updates the condition.
@@ -1115,7 +1138,8 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
struct snd_rawmidi_runtime *runtime = substream->runtime;
if (runtime->buffer == NULL) {
- snd_printd("snd_rawmidi_transmit_ack: output is not active!!!\n");
+ rmidi_dbg(substream->rmidi,
+ "snd_rawmidi_transmit_ack: output is not active!!!\n");
return -EINVAL;
}
spin_lock_irqsave(&runtime->lock, flags);
@@ -1131,6 +1155,7 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
spin_unlock_irqrestore(&runtime->lock, flags);
return count;
}
+EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
/**
* snd_rawmidi_transmit - copy from the buffer to the device
@@ -1152,6 +1177,7 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
return count;
return snd_rawmidi_transmit_ack(substream, count);
}
+EXPORT_SYMBOL(snd_rawmidi_transmit);
static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
const unsigned char __user *userbuf,
@@ -1213,6 +1239,7 @@ long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream,
{
return snd_rawmidi_kernel_write1(substream, NULL, buf, count);
}
+EXPORT_SYMBOL(snd_rawmidi_kernel_write);
static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
size_t count, loff_t *offset)
@@ -1413,7 +1440,7 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
for (idx = 0; idx < count; idx++) {
substream = kzalloc(sizeof(*substream), GFP_KERNEL);
if (substream == NULL) {
- snd_printk(KERN_ERR "rawmidi: cannot allocate substream\n");
+ rmidi_err(rmidi, "rawmidi: cannot allocate substream\n");
return -ENOMEM;
}
substream->stream = direction;
@@ -1458,7 +1485,7 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
*rrawmidi = NULL;
rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL);
if (rmidi == NULL) {
- snd_printk(KERN_ERR "rawmidi: cannot allocate\n");
+ dev_err(card->dev, "rawmidi: cannot allocate\n");
return -ENOMEM;
}
rmidi->card = card;
@@ -1492,6 +1519,7 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
*rrawmidi = rmidi;
return 0;
}
+EXPORT_SYMBOL(snd_rawmidi_new);
static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream)
{
@@ -1557,7 +1585,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
if ((err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
rmidi->card, rmidi->device,
&snd_rawmidi_f_ops, rmidi, name)) < 0) {
- snd_printk(KERN_ERR "unable to register rawmidi device %i:%i\n", rmidi->card->number, rmidi->device);
+ rmidi_err(rmidi, "unable to register rawmidi device %i:%i\n",
+ rmidi->card->number, rmidi->device);
list_del(&rmidi->list);
mutex_unlock(&register_mutex);
return err;
@@ -1574,8 +1603,10 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
if ((int)rmidi->device == midi_map[rmidi->card->number]) {
if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
rmidi->card, 0, &snd_rawmidi_f_ops,
- rmidi, name) < 0) {
- snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 0);
+ rmidi) < 0) {
+ rmidi_err(rmidi,
+ "unable to register OSS rawmidi device %i:%i\n",
+ rmidi->card->number, 0);
} else {
rmidi->ossreg++;
#ifdef SNDRV_OSS_INFO_DEV_MIDI
@@ -1586,8 +1617,10 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
if ((int)rmidi->device == amidi_map[rmidi->card->number]) {
if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
rmidi->card, 1, &snd_rawmidi_f_ops,
- rmidi, name) < 0) {
- snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 1);
+ rmidi) < 0) {
+ rmidi_err(rmidi,
+ "unable to register OSS rawmidi device %i:%i\n",
+ rmidi->card->number, 1);
} else {
rmidi->ossreg++;
}
@@ -1670,6 +1703,7 @@ void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
list_for_each_entry(substream, &rmidi->streams[stream].substreams, list)
substream->ops = ops;
}
+EXPORT_SYMBOL(snd_rawmidi_set_ops);
/*
* ENTRY functions
@@ -1685,11 +1719,13 @@ static int __init alsa_rawmidi_init(void)
/* check device map table */
for (i = 0; i < SNDRV_CARDS; i++) {
if (midi_map[i] < 0 || midi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
- snd_printk(KERN_ERR "invalid midi_map[%d] = %d\n", i, midi_map[i]);
+ pr_err("ALSA: rawmidi: invalid midi_map[%d] = %d\n",
+ i, midi_map[i]);
midi_map[i] = 0;
}
if (amidi_map[i] < 0 || amidi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
- snd_printk(KERN_ERR "invalid amidi_map[%d] = %d\n", i, amidi_map[i]);
+ pr_err("ALSA: rawmidi: invalid amidi_map[%d] = %d\n",
+ i, amidi_map[i]);
amidi_map[i] = 1;
}
}
@@ -1706,21 +1742,3 @@ static void __exit alsa_rawmidi_exit(void)
module_init(alsa_rawmidi_init)
module_exit(alsa_rawmidi_exit)
-
-EXPORT_SYMBOL(snd_rawmidi_output_params);
-EXPORT_SYMBOL(snd_rawmidi_input_params);
-EXPORT_SYMBOL(snd_rawmidi_drop_output);
-EXPORT_SYMBOL(snd_rawmidi_drain_output);
-EXPORT_SYMBOL(snd_rawmidi_drain_input);
-EXPORT_SYMBOL(snd_rawmidi_receive);
-EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
-EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
-EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
-EXPORT_SYMBOL(snd_rawmidi_transmit);
-EXPORT_SYMBOL(snd_rawmidi_new);
-EXPORT_SYMBOL(snd_rawmidi_set_ops);
-EXPORT_SYMBOL(snd_rawmidi_info_select);
-EXPORT_SYMBOL(snd_rawmidi_kernel_open);
-EXPORT_SYMBOL(snd_rawmidi_kernel_release);
-EXPORT_SYMBOL(snd_rawmidi_kernel_read);
-EXPORT_SYMBOL(snd_rawmidi_kernel_write);
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
index e85e72baff9e..f3420d11a12f 100644
--- a/sound/core/rtctimer.c
+++ b/sound/core/rtctimer.c
@@ -27,7 +27,7 @@
#include <sound/core.h>
#include <sound/timer.h>
-#if defined(CONFIG_RTC) || defined(CONFIG_RTC_MODULE)
+#if IS_ENABLED(CONFIG_RTC)
#include <linux/mc146818rtc.h>
@@ -132,8 +132,7 @@ static int __init rtctimer_init(void)
if (rtctimer_freq < 2 || rtctimer_freq > 8192 ||
!is_power_of_2(rtctimer_freq)) {
- snd_printk(KERN_ERR "rtctimer: invalid frequency %d\n",
- rtctimer_freq);
+ pr_err("ALSA: rtctimer: invalid frequency %d\n", rtctimer_freq);
return -EINVAL;
}
@@ -185,4 +184,4 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_RTC));
-#endif /* CONFIG_RTC || CONFIG_RTC_MODULE */
+#endif /* IS_ENABLED(CONFIG_RTC) */
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index 8d4d5e853efe..16d42679e43f 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -39,12 +39,6 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_SEQUENCER);
MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MUSIC);
-#ifdef SNDRV_SEQ_OSS_DEBUG
-module_param(seq_oss_debug, int, 0644);
-MODULE_PARM_DESC(seq_oss_debug, "debug option");
-int seq_oss_debug = 0;
-#endif
-
/*
* prototypes
@@ -231,22 +225,19 @@ register_device(void)
mutex_lock(&register_mutex);
if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
NULL, 0,
- &seq_oss_f_ops, NULL,
- SNDRV_SEQ_OSS_DEVNAME)) < 0) {
- snd_printk(KERN_ERR "can't register device seq\n");
+ &seq_oss_f_ops, NULL)) < 0) {
+ pr_err("ALSA: seq_oss: can't register device seq\n");
mutex_unlock(&register_mutex);
return rc;
}
if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
NULL, 0,
- &seq_oss_f_ops, NULL,
- SNDRV_SEQ_OSS_DEVNAME)) < 0) {
- snd_printk(KERN_ERR "can't register device music\n");
+ &seq_oss_f_ops, NULL)) < 0) {
+ pr_err("ALSA: seq_oss: can't register device music\n");
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0);
mutex_unlock(&register_mutex);
return rc;
}
- debug_printk(("device registered\n"));
mutex_unlock(&register_mutex);
return 0;
}
@@ -255,11 +246,10 @@ static void
unregister_device(void)
{
mutex_lock(&register_mutex);
- debug_printk(("device unregistered\n"));
if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0)
- snd_printk(KERN_ERR "error unregister device music\n");
+ pr_err("ALSA: seq_oss: error unregister device music\n");
if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0) < 0)
- snd_printk(KERN_ERR "error unregister device seq\n");
+ pr_err("ALSA: seq_oss: error unregister device seq\n");
mutex_unlock(&register_mutex);
}
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h
index c0154a959d55..b43924325249 100644
--- a/sound/core/seq/oss/seq_oss_device.h
+++ b/sound/core/seq/oss/seq_oss_device.h
@@ -31,9 +31,6 @@
#include <sound/seq_kernel.h>
#include <sound/info.h>
-/* enable debug print */
-#define SNDRV_SEQ_OSS_DEBUG
-
/* max. applications */
#define SNDRV_SEQ_OSS_MAX_CLIENTS 16
#define SNDRV_SEQ_OSS_MAX_SYNTH_DEVS 16
@@ -46,7 +43,6 @@
#define SNDRV_SEQ_OSS_VERSION_STR "0.1.8"
/* device and proc interface name */
-#define SNDRV_SEQ_OSS_DEVNAME "seq_oss"
#define SNDRV_SEQ_OSS_PROCNAME "oss"
@@ -177,13 +173,4 @@ snd_seq_oss_fill_addr(struct seq_oss_devinfo *dp, struct snd_seq_event *ev,
/* misc. functions for proc interface */
char *enabled_str(int bool);
-
-/* for debug */
-#ifdef SNDRV_SEQ_OSS_DEBUG
-extern int seq_oss_debug;
-#define debug_printk(x) do { if (seq_oss_debug > 0) snd_printd x; } while (0)
-#else
-#define debug_printk(x) /**/
-#endif
-
#endif /* __SEQ_OSS_DEVICE_H */
diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c
index b3f39b5ed742..b9184d20c39f 100644
--- a/sound/core/seq/oss/seq_oss_init.c
+++ b/sound/core/seq/oss/seq_oss_init.c
@@ -92,7 +92,6 @@ snd_seq_oss_create_client(void)
goto __error;
system_client = rc;
- debug_printk(("new client = %d\n", rc));
/* create annoucement receiver port */
memset(port, 0, sizeof(*port));
@@ -190,10 +189,9 @@ snd_seq_oss_open(struct file *file, int level)
dp = kzalloc(sizeof(*dp), GFP_KERNEL);
if (!dp) {
- snd_printk(KERN_ERR "can't malloc device info\n");
+ pr_err("ALSA: seq_oss: can't malloc device info\n");
return -ENOMEM;
}
- debug_printk(("oss_open: dp = %p\n", dp));
dp->cseq = system_client;
dp->port = -1;
@@ -206,7 +204,7 @@ snd_seq_oss_open(struct file *file, int level)
dp->index = i;
if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) {
- snd_printk(KERN_ERR "too many applications\n");
+ pr_err("ALSA: seq_oss: too many applications\n");
rc = -ENOMEM;
goto _error;
}
@@ -216,21 +214,19 @@ snd_seq_oss_open(struct file *file, int level)
snd_seq_oss_midi_setup(dp);
if (dp->synth_opened == 0 && dp->max_mididev == 0) {
- /* snd_printk(KERN_ERR "no device found\n"); */
+ /* pr_err("ALSA: seq_oss: no device found\n"); */
rc = -ENODEV;
goto _error;
}
/* create port */
- debug_printk(("create new port\n"));
rc = create_port(dp);
if (rc < 0) {
- snd_printk(KERN_ERR "can't create port\n");
+ pr_err("ALSA: seq_oss: can't create port\n");
goto _error;
}
/* allocate queue */
- debug_printk(("allocate queue\n"));
rc = alloc_seq_queue(dp);
if (rc < 0)
goto _error;
@@ -247,7 +243,6 @@ snd_seq_oss_open(struct file *file, int level)
dp->file_mode = translate_mode(file);
/* initialize read queue */
- debug_printk(("initialize read queue\n"));
if (is_read_mode(dp->file_mode)) {
dp->readq = snd_seq_oss_readq_new(dp, maxqlen);
if (!dp->readq) {
@@ -257,7 +252,6 @@ snd_seq_oss_open(struct file *file, int level)
}
/* initialize write queue */
- debug_printk(("initialize write queue\n"));
if (is_write_mode(dp->file_mode)) {
dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen);
if (!dp->writeq) {
@@ -267,14 +261,12 @@ snd_seq_oss_open(struct file *file, int level)
}
/* initialize timer */
- debug_printk(("initialize timer\n"));
dp->timer = snd_seq_oss_timer_new(dp);
if (!dp->timer) {
- snd_printk(KERN_ERR "can't alloc timer\n");
+ pr_err("ALSA: seq_oss: can't alloc timer\n");
rc = -ENOMEM;
goto _error;
}
- debug_printk(("timer initialized\n"));
/* set private data pointer */
file->private_data = dp;
@@ -288,7 +280,6 @@ snd_seq_oss_open(struct file *file, int level)
client_table[dp->index] = dp;
num_clients++;
- debug_printk(("open done\n"));
return 0;
_error:
@@ -347,7 +338,6 @@ create_port(struct seq_oss_devinfo *dp)
return rc;
dp->port = port.addr.port;
- debug_printk(("new port = %d\n", port.addr.port));
return 0;
}
@@ -363,7 +353,6 @@ delete_port(struct seq_oss_devinfo *dp)
return 0;
}
- debug_printk(("delete_port %i\n", dp->port));
return snd_seq_event_port_detach(dp->cseq, dp->port);
}
@@ -401,7 +390,7 @@ delete_seq_queue(int queue)
qinfo.queue = queue;
rc = call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo);
if (rc < 0)
- printk(KERN_ERR "seq-oss: unable to delete queue %d (%d)\n", queue, rc);
+ pr_err("ALSA: seq_oss: unable to delete queue %d (%d)\n", queue, rc);
return rc;
}
@@ -438,21 +427,16 @@ snd_seq_oss_release(struct seq_oss_devinfo *dp)
client_table[dp->index] = NULL;
num_clients--;
- debug_printk(("resetting..\n"));
snd_seq_oss_reset(dp);
- debug_printk(("cleaning up..\n"));
snd_seq_oss_synth_cleanup(dp);
snd_seq_oss_midi_cleanup(dp);
/* clear slot */
- debug_printk(("releasing resource..\n"));
queue = dp->queue;
if (dp->port >= 0)
delete_port(dp);
delete_seq_queue(queue);
-
- debug_printk(("release done\n"));
}
@@ -466,7 +450,6 @@ snd_seq_oss_drain_write(struct seq_oss_devinfo *dp)
return;
if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) &&
dp->writeq) {
- debug_printk(("syncing..\n"));
while (snd_seq_oss_writeq_sync(dp->writeq))
;
}
diff --git a/sound/core/seq/oss/seq_oss_ioctl.c b/sound/core/seq/oss/seq_oss_ioctl.c
index 5ac701c903c1..5b8520177b0e 100644
--- a/sound/core/seq/oss/seq_oss_ioctl.c
+++ b/sound/core/seq/oss/seq_oss_ioctl.c
@@ -90,12 +90,10 @@ snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long ca
return snd_seq_oss_timer_ioctl(dp->timer, cmd, arg);
case SNDCTL_SEQ_PANIC:
- debug_printk(("panic\n"));
snd_seq_oss_reset(dp);
return -EINVAL;
case SNDCTL_SEQ_SYNC:
- debug_printk(("sync\n"));
if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
return 0;
while (snd_seq_oss_writeq_sync(dp->writeq))
@@ -105,55 +103,45 @@ snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long ca
return 0;
case SNDCTL_SEQ_RESET:
- debug_printk(("reset\n"));
snd_seq_oss_reset(dp);
return 0;
case SNDCTL_SEQ_TESTMIDI:
- debug_printk(("test midi\n"));
if (get_user(dev, p))
return -EFAULT;
return snd_seq_oss_midi_open(dp, dev, dp->file_mode);
case SNDCTL_SEQ_GETINCOUNT:
- debug_printk(("get in count\n"));
if (dp->readq == NULL || ! is_read_mode(dp->file_mode))
return 0;
return put_user(dp->readq->qlen, p) ? -EFAULT : 0;
case SNDCTL_SEQ_GETOUTCOUNT:
- debug_printk(("get out count\n"));
if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
return 0;
return put_user(snd_seq_oss_writeq_get_free_size(dp->writeq), p) ? -EFAULT : 0;
case SNDCTL_SEQ_GETTIME:
- debug_printk(("get time\n"));
return put_user(snd_seq_oss_timer_cur_tick(dp->timer), p) ? -EFAULT : 0;
case SNDCTL_SEQ_RESETSAMPLES:
- debug_printk(("reset samples\n"));
if (get_user(dev, p))
return -EFAULT;
return snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
case SNDCTL_SEQ_NRSYNTHS:
- debug_printk(("nr synths\n"));
return put_user(dp->max_synthdev, p) ? -EFAULT : 0;
case SNDCTL_SEQ_NRMIDIS:
- debug_printk(("nr midis\n"));
return put_user(dp->max_mididev, p) ? -EFAULT : 0;
case SNDCTL_SYNTH_MEMAVL:
- debug_printk(("mem avail\n"));
if (get_user(dev, p))
return -EFAULT;
val = snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
return put_user(val, p) ? -EFAULT : 0;
case SNDCTL_FM_4OP_ENABLE:
- debug_printk(("4op\n"));
if (get_user(dev, p))
return -EFAULT;
snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
@@ -161,19 +149,15 @@ snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long ca
case SNDCTL_SYNTH_INFO:
case SNDCTL_SYNTH_ID:
- debug_printk(("synth info\n"));
return snd_seq_oss_synth_info_user(dp, arg);
case SNDCTL_SEQ_OUTOFBAND:
- debug_printk(("out of band\n"));
return snd_seq_oss_oob_user(dp, arg);
case SNDCTL_MIDI_INFO:
- debug_printk(("midi info\n"));
return snd_seq_oss_midi_info_user(dp, arg);
case SNDCTL_SEQ_THRESHOLD:
- debug_printk(("threshold\n"));
if (! is_write_mode(dp->file_mode))
return 0;
if (get_user(val, p))
@@ -186,7 +170,6 @@ snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long ca
return 0;
case SNDCTL_MIDI_PRETIME:
- debug_printk(("pretime\n"));
if (dp->readq == NULL || !is_read_mode(dp->file_mode))
return 0;
if (get_user(val, p))
@@ -199,7 +182,6 @@ snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long ca
return put_user(val, p) ? -EFAULT : 0;
default:
- debug_printk(("others\n"));
if (! is_write_mode(dp->file_mode))
return -EIO;
return snd_seq_oss_synth_ioctl(dp, 0, cmd, carg);
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
index 862d84893ee8..3a4569669efa 100644
--- a/sound/core/seq/oss/seq_oss_midi.c
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -153,7 +153,6 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
struct seq_oss_midi *mdev;
unsigned long flags;
- debug_printk(("check for MIDI client %d port %d\n", pinfo->addr.client, pinfo->addr.port));
/* the port must include generic midi */
if (! (pinfo->type & SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC))
return 0;
@@ -175,7 +174,7 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
* allocate midi info record
*/
if ((mdev = kzalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) {
- snd_printk(KERN_ERR "can't malloc midi info\n");
+ pr_err("ALSA: seq_oss: can't malloc midi info\n");
return -ENOMEM;
}
@@ -191,7 +190,7 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
/* create MIDI coder */
if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) {
- snd_printk(KERN_ERR "can't malloc midi coder\n");
+ pr_err("ALSA: seq_oss: can't malloc midi coder\n");
kfree(mdev);
return -ENOMEM;
}
@@ -406,7 +405,6 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
return 0;
}
- debug_printk(("closing client %d port %d mode %d\n", mdev->client, mdev->port, mdev->opened));
memset(&subs, 0, sizeof(subs));
if (mdev->opened & PERM_WRITE) {
subs.sender = dp->addr;
@@ -470,7 +468,6 @@ snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev)
struct snd_seq_event ev;
int c;
- debug_printk(("resetting client %d port %d\n", mdev->client, mdev->port));
memset(&ev, 0, sizeof(ev));
ev.dest.client = mdev->client;
ev.dest.port = mdev->port;
diff --git a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c
index 73661c4ab82a..654d17a5023c 100644
--- a/sound/core/seq/oss/seq_oss_readq.c
+++ b/sound/core/seq/oss/seq_oss_readq.c
@@ -48,12 +48,12 @@ snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen)
struct seq_oss_readq *q;
if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) {
- snd_printk(KERN_ERR "can't malloc read queue\n");
+ pr_err("ALSA: seq_oss: can't malloc read queue\n");
return NULL;
}
if ((q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL)) == NULL) {
- snd_printk(KERN_ERR "can't malloc read queue buffer\n");
+ pr_err("ALSA: seq_oss: can't malloc read queue buffer\n");
kfree(q);
return NULL;
}
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
index c5b773a1eea9..701feb71b700 100644
--- a/sound/core/seq/oss/seq_oss_synth.c
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -106,7 +106,7 @@ snd_seq_oss_synth_register(struct snd_seq_device *dev)
unsigned long flags;
if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL) {
- snd_printk(KERN_ERR "can't malloc synth info\n");
+ pr_err("ALSA: seq_oss: can't malloc synth info\n");
return -ENOMEM;
}
rec->seq_device = -1;
@@ -130,7 +130,7 @@ snd_seq_oss_synth_register(struct snd_seq_device *dev)
if (i >= max_synth_devs) {
if (max_synth_devs >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS) {
spin_unlock_irqrestore(&register_lock, flags);
- snd_printk(KERN_ERR "no more synth slot\n");
+ pr_err("ALSA: seq_oss: no more synth slot\n");
kfree(rec);
return -ENOMEM;
}
@@ -138,7 +138,6 @@ snd_seq_oss_synth_register(struct snd_seq_device *dev)
}
rec->seq_device = i;
synth_devs[i] = rec;
- debug_printk(("synth %s registered %d\n", rec->name, i));
spin_unlock_irqrestore(&register_lock, flags);
dev->driver_data = rec;
#ifdef SNDRV_OSS_INFO_DEV_SYNTH
@@ -163,7 +162,7 @@ snd_seq_oss_synth_unregister(struct snd_seq_device *dev)
}
if (index >= max_synth_devs) {
spin_unlock_irqrestore(&register_lock, flags);
- snd_printk(KERN_ERR "can't unregister synth\n");
+ pr_err("ALSA: seq_oss: can't unregister synth\n");
return -EINVAL;
}
synth_devs[index] = NULL;
@@ -248,7 +247,7 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp)
if (info->nr_voices > 0) {
info->ch = kcalloc(info->nr_voices, sizeof(struct seq_oss_chinfo), GFP_KERNEL);
if (!info->ch) {
- snd_printk(KERN_ERR "Cannot malloc\n");
+ pr_err("ALSA: seq_oss: Cannot malloc voices\n");
rec->oper.close(&info->arg);
module_put(rec->oper.owner);
snd_use_lock_free(&rec->use_lock);
@@ -256,7 +255,6 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp)
}
reset_channels(info);
}
- debug_printk(("synth %d assigned\n", i));
info->opened++;
rec->opened++;
dp->synth_opened++;
@@ -326,7 +324,6 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp)
if (rec == NULL)
continue;
if (rec->opened > 0) {
- debug_printk(("synth %d closed\n", i));
rec->oper.close(&info->arg);
module_put(rec->oper.owner);
rec->opened = 0;
diff --git a/sound/core/seq/oss/seq_oss_timer.c b/sound/core/seq/oss/seq_oss_timer.c
index ab59cbfbcaf2..4f24ea9fad93 100644
--- a/sound/core/seq/oss/seq_oss_timer.c
+++ b/sound/core/seq/oss/seq_oss_timer.c
@@ -233,7 +233,6 @@ snd_seq_oss_timer_ioctl(struct seq_oss_timer *timer, unsigned int cmd, int __use
int value;
if (cmd == SNDCTL_SEQ_CTRLRATE) {
- debug_printk(("ctrl rate\n"));
/* if *arg == 0, just return the current rate */
if (get_user(value, arg))
return -EFAULT;
@@ -248,21 +247,16 @@ snd_seq_oss_timer_ioctl(struct seq_oss_timer *timer, unsigned int cmd, int __use
switch (cmd) {
case SNDCTL_TMR_START:
- debug_printk(("timer start\n"));
return snd_seq_oss_timer_start(timer);
case SNDCTL_TMR_STOP:
- debug_printk(("timer stop\n"));
return snd_seq_oss_timer_stop(timer);
case SNDCTL_TMR_CONTINUE:
- debug_printk(("timer continue\n"));
return snd_seq_oss_timer_continue(timer);
case SNDCTL_TMR_TEMPO:
- debug_printk(("timer tempo\n"));
if (get_user(value, arg))
return -EFAULT;
return snd_seq_oss_timer_tempo(timer, value);
case SNDCTL_TMR_TIMEBASE:
- debug_printk(("timer timebase\n"));
if (get_user(value, arg))
return -EFAULT;
if (value < MIN_OSS_TIMEBASE)
@@ -276,7 +270,6 @@ snd_seq_oss_timer_ioctl(struct seq_oss_timer *timer, unsigned int cmd, int __use
case SNDCTL_TMR_METRONOME:
case SNDCTL_TMR_SELECT:
case SNDCTL_TMR_SOURCE:
- debug_printk(("timer XXX\n"));
/* not supported */
return 0;
}
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 4dc6bae80e15..9ca5e647e54b 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -123,7 +123,7 @@ static inline int snd_seq_write_pool_allocated(struct snd_seq_client *client)
static struct snd_seq_client *clientptr(int clientid)
{
if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
- snd_printd("Seq: oops. Trying to get pointer to client %d\n",
+ pr_debug("ALSA: seq: oops. Trying to get pointer to client %d\n",
clientid);
return NULL;
}
@@ -136,7 +136,7 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
struct snd_seq_client *client;
if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
- snd_printd("Seq: oops. Trying to get pointer to client %d\n",
+ pr_debug("ALSA: seq: oops. Trying to get pointer to client %d\n",
clientid);
return NULL;
}
@@ -291,8 +291,8 @@ static void seq_free_client(struct snd_seq_client * client)
mutex_lock(&register_mutex);
switch (client->type) {
case NO_CLIENT:
- snd_printk(KERN_WARNING "Seq: Trying to free unused client %d\n",
- client->number);
+ pr_warn("ALSA: seq: Trying to free unused client %d\n",
+ client->number);
break;
case USER_CLIENT:
case KERNEL_CLIENT:
@@ -301,7 +301,7 @@ static void seq_free_client(struct snd_seq_client * client)
break;
default:
- snd_printk(KERN_ERR "Seq: Trying to free client %d with undefined type = %d\n",
+ pr_err("ALSA: seq: Trying to free client %d with undefined type = %d\n",
client->number, client->type);
}
mutex_unlock(&register_mutex);
@@ -773,7 +773,7 @@ static int broadcast_event(struct snd_seq_client *client,
static int multicast_event(struct snd_seq_client *client, struct snd_seq_event *event,
int atomic, int hop)
{
- snd_printd("seq: multicast not supported yet.\n");
+ pr_debug("ALSA: seq: multicast not supported yet.\n");
return 0; /* ignored */
}
#endif /* SUPPORT_BROADCAST */
@@ -794,7 +794,7 @@ static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_e
hop++;
if (hop >= SNDRV_SEQ_MAX_HOPS) {
- snd_printd("too long delivery path (%d:%d->%d:%d)\n",
+ pr_debug("ALSA: seq: too long delivery path (%d:%d->%d:%d)\n",
event->source.client, event->source.port,
event->dest.client, event->dest.port);
return -EMLINK;
@@ -2196,7 +2196,7 @@ static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd,
if (p->cmd == cmd)
return p->func(client, arg);
}
- snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
+ pr_debug("ALSA: seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
return -ENOTTY;
}
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 040c60e1da28..91a786a783e1 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -168,7 +168,7 @@ void snd_seq_device_load_drivers(void)
/*
* register a sequencer device
- * card = card info (NULL allowed)
+ * card = card info
* device = device number (if any)
* id = id of driver
* result = return pointer (NULL allowed if unnecessary)
@@ -325,7 +325,7 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
return -ENOMEM;
}
if (ops->driver & DRIVER_LOADED) {
- snd_printk(KERN_WARNING "driver_register: driver '%s' already exists\n", id);
+ pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id);
unlock_driver(ops);
snd_seq_autoload_unlock();
return -EBUSY;
@@ -398,7 +398,7 @@ int snd_seq_device_unregister_driver(char *id)
return -ENXIO;
if (! (ops->driver & DRIVER_LOADED) ||
(ops->driver & DRIVER_LOCKED)) {
- snd_printk(KERN_ERR "driver_unregister: cannot unload driver '%s': status=%x\n",
+ pr_err("ALSA: seq: driver_unregister: cannot unload driver '%s': status=%x\n",
id, ops->driver);
unlock_driver(ops);
return -EBUSY;
@@ -413,7 +413,7 @@ int snd_seq_device_unregister_driver(char *id)
ops->driver = 0;
if (ops->num_init_devices > 0)
- snd_printk(KERN_ERR "free_driver: init_devices > 0!! (%d)\n",
+ pr_err("ALSA: seq: free_driver: init_devices > 0!! (%d)\n",
ops->num_init_devices);
mutex_unlock(&ops->reg_mutex);
@@ -459,7 +459,7 @@ static int init_device(struct snd_seq_device *dev, struct ops_list *ops)
if (dev->status != SNDRV_SEQ_DEVICE_FREE)
return 0; /* already initialized */
if (ops->argsize != dev->argsize) {
- snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n",
+ pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
dev->name, ops->id, ops->argsize, dev->argsize);
return -EINVAL;
}
@@ -467,7 +467,7 @@ static int init_device(struct snd_seq_device *dev, struct ops_list *ops)
dev->status = SNDRV_SEQ_DEVICE_REGISTERED;
ops->num_init_devices++;
} else {
- snd_printk(KERN_ERR "init_device failed: %s: %s\n",
+ pr_err("ALSA: seq: init_device failed: %s: %s\n",
dev->name, dev->id);
}
@@ -486,7 +486,7 @@ static int free_device(struct snd_seq_device *dev, struct ops_list *ops)
if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED)
return 0; /* not registered */
if (ops->argsize != dev->argsize) {
- snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n",
+ pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
dev->name, ops->id, ops->argsize, dev->argsize);
return -EINVAL;
}
@@ -495,7 +495,7 @@ static int free_device(struct snd_seq_device *dev, struct ops_list *ops)
dev->driver_data = NULL;
ops->num_init_devices--;
} else {
- snd_printk(KERN_ERR "free_device failed: %s: %s\n",
+ pr_err("ALSA: seq: free_device failed: %s: %s\n",
dev->name, dev->id);
}
@@ -559,7 +559,7 @@ static void __exit alsa_seq_device_exit(void)
snd_info_free_entry(info_entry);
#endif
if (num_ops)
- snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops);
+ pr_err("ALSA: seq: drivers not released (%d)\n", num_ops);
}
module_init(alsa_seq_device_init)
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c
index dbc550716790..ec667f158f19 100644
--- a/sound/core/seq/seq_dummy.c
+++ b/sound/core/seq/seq_dummy.c
@@ -198,7 +198,7 @@ register_client(void)
int i;
if (ports < 1) {
- snd_printk(KERN_ERR "invalid number of ports %d\n", ports);
+ pr_err("ALSA: seq_dummy: invalid number of ports %d\n", ports);
return -EINVAL;
}
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index 0d75afa786bc..559989992bef 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -34,7 +34,7 @@ struct snd_seq_fifo *snd_seq_fifo_new(int poolsize)
f = kzalloc(sizeof(*f), GFP_KERNEL);
if (f == NULL) {
- snd_printd("malloc failed for snd_seq_fifo_new() \n");
+ pr_debug("ALSA: seq: malloc failed for snd_seq_fifo_new() \n");
return NULL;
}
diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c
index 2cfe50c71a9d..3b693e924db7 100644
--- a/sound/core/seq/seq_lock.c
+++ b/sound/core/seq/seq_lock.c
@@ -31,12 +31,12 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
int max_count = 5 * HZ;
if (atomic_read(lockp) < 0) {
- printk(KERN_WARNING "seq_lock: lock trouble [counter = %d] in %s:%d\n", atomic_read(lockp), file, line);
+ pr_warn("ALSA: seq_lock: lock trouble [counter = %d] in %s:%d\n", atomic_read(lockp), file, line);
return;
}
while (atomic_read(lockp) > 0) {
if (max_count == 0) {
- snd_printk(KERN_WARNING "seq_lock: timeout [%d left] in %s:%d\n", atomic_read(lockp), file, line);
+ pr_warn("ALSA: seq_lock: timeout [%d left] in %s:%d\n", atomic_read(lockp), file, line);
break;
}
schedule_timeout_uninterruptible(1);
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index f478f770bf52..1e206de0c2dd 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -236,7 +236,7 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool,
init_waitqueue_entry(&wait, current);
spin_lock_irqsave(&pool->lock, flags);
if (pool->ptr == NULL) { /* not initialized */
- snd_printd("seq: pool is not initialized\n");
+ pr_debug("ALSA: seq: pool is not initialized\n");
err = -EINVAL;
goto __error;
}
@@ -388,7 +388,7 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size);
if (pool->ptr == NULL) {
- snd_printd("seq: malloc for sequencer events failed\n");
+ pr_debug("ALSA: seq: malloc for sequencer events failed\n");
return -ENOMEM;
}
@@ -431,7 +431,7 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
while (atomic_read(&pool->counter) > 0) {
if (max_count == 0) {
- snd_printk(KERN_WARNING "snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter));
+ pr_warn("ALSA: snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter));
break;
}
schedule_timeout_uninterruptible(1);
@@ -464,7 +464,7 @@ struct snd_seq_pool *snd_seq_pool_new(int poolsize)
/* create pool block */
pool = kzalloc(sizeof(*pool), GFP_KERNEL);
if (pool == NULL) {
- snd_printd("seq: malloc failed for pool\n");
+ pr_debug("ALSA: seq: malloc failed for pool\n");
return NULL;
}
spin_lock_init(&pool->lock);
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index 64069dbf89ca..3e05c55a2880 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -121,7 +121,7 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i
runtime = substream->runtime;
if ((tmp = runtime->avail) < count) {
if (printk_ratelimit())
- snd_printk(KERN_ERR "MIDI output buffer overrun\n");
+ pr_err("ALSA: seq_midi: MIDI output buffer overrun\n");
return -ENOMEM;
}
if (snd_rawmidi_kernel_write(substream, buf, count) < count)
@@ -145,7 +145,7 @@ static int event_process_midi(struct snd_seq_event *ev, int direct,
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { /* special case, to save space */
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) {
/* invalid event */
- snd_printd("seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
+ pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
return 0;
}
snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
@@ -189,7 +189,7 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe
msynth->subdevice,
SNDRV_RAWMIDI_LFLG_INPUT,
&msynth->input_rfile)) < 0) {
- snd_printd("midi input open failed!!!\n");
+ pr_debug("ALSA: seq_midi: midi input open failed!!!\n");
return err;
}
runtime = msynth->input_rfile.input->runtime;
@@ -231,7 +231,7 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
msynth->subdevice,
SNDRV_RAWMIDI_LFLG_OUTPUT,
&msynth->output_rfile)) < 0) {
- snd_printd("midi output open failed!!!\n");
+ pr_debug("ALSA: seq_midi: midi output open failed!!!\n");
return err;
}
memset(&params, 0, sizeof(params));
diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c
index 6f64471ddde3..9b6470cdcf24 100644
--- a/sound/core/seq/seq_midi_emul.c
+++ b/sound/core/seq/seq_midi_emul.c
@@ -89,7 +89,7 @@ snd_midi_process_event(struct snd_midi_op *ops,
int dest_channel = 0;
if (ev == NULL || chanset == NULL) {
- snd_printd("ev or chanbase NULL (snd_midi_process_event)\n");
+ pr_debug("ALSA: seq_midi_emul: ev or chanbase NULL (snd_midi_process_event)\n");
return;
}
if (chanset->channels == NULL)
@@ -98,7 +98,7 @@ snd_midi_process_event(struct snd_midi_op *ops,
if (snd_seq_ev_is_channel_type(ev)) {
dest_channel = ev->data.note.channel;
if (dest_channel >= chanset->max_channels) {
- snd_printd("dest channel is %d, max is %d\n",
+ pr_debug("ALSA: seq_midi_emul: dest channel is %d, max is %d\n",
dest_channel, chanset->max_channels);
return;
}
@@ -232,7 +232,7 @@ snd_midi_process_event(struct snd_midi_op *ops,
case SNDRV_SEQ_EVENT_ECHO:
not_yet:
default:
- /*snd_printd("Unimplemented event %d\n", ev->type);*/
+ /*pr_debug("ALSA: seq_midi_emul: Unimplemented event %d\n", ev->type);*/
break;
}
}
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 9516e5ce3aad..794a341bf0e5 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -135,14 +135,14 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
return NULL;
if (client->num_ports >= SNDRV_SEQ_MAX_PORTS - 1) {
- snd_printk(KERN_WARNING "too many ports for client %d\n", client->number);
+ pr_warn("ALSA: seq: too many ports for client %d\n", client->number);
return NULL;
}
/* create a new port */
new_port = kzalloc(sizeof(*new_port), GFP_KERNEL);
if (! new_port) {
- snd_printd("malloc failed for registering client port\n");
+ pr_debug("ALSA: seq: malloc failed for registering client port\n");
return NULL; /* failure, out of memory */
}
/* init port data */
diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c
index 29896ab23403..021b02bc9330 100644
--- a/sound/core/seq/seq_prioq.c
+++ b/sound/core/seq/seq_prioq.c
@@ -60,7 +60,7 @@ struct snd_seq_prioq *snd_seq_prioq_new(void)
f = kzalloc(sizeof(*f), GFP_KERNEL);
if (f == NULL) {
- snd_printd("oops: malloc failed for snd_seq_prioq_new()\n");
+ pr_debug("ALSA: seq: malloc failed for snd_seq_prioq_new()\n");
return NULL;
}
@@ -79,7 +79,7 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo)
*fifo = NULL;
if (f == NULL) {
- snd_printd("oops: snd_seq_prioq_delete() called with NULL prioq\n");
+ pr_debug("ALSA: seq: snd_seq_prioq_delete() called with NULL prioq\n");
return;
}
@@ -197,7 +197,7 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
cur = cur->next;
if (! --count) {
spin_unlock_irqrestore(&f->lock, flags);
- snd_printk(KERN_ERR "cannot find a pointer.. infinite loop?\n");
+ pr_err("ALSA: seq: cannot find a pointer.. infinite loop?\n");
return -EINVAL;
}
}
@@ -223,7 +223,7 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)
unsigned long flags;
if (f == NULL) {
- snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
+ pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
return NULL;
}
spin_lock_irqsave(&f->lock, flags);
@@ -248,7 +248,7 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)
int snd_seq_prioq_avail(struct snd_seq_prioq * f)
{
if (f == NULL) {
- snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
+ pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
return 0;
}
return f->cells;
@@ -259,7 +259,7 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)
struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq * f)
{
if (f == NULL) {
- snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
+ pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
return NULL;
}
return f->head;
@@ -321,7 +321,7 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
freeprev = cell;
} else {
#if 0
- printk(KERN_DEBUG "type = %i, source = %i, dest = %i, "
+ pr_debug("ALSA: seq: type = %i, source = %i, dest = %i, "
"client = %i\n",
cell->event.type,
cell->event.source.client,
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index f9077361c119..aad4878cee55 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -112,7 +112,7 @@ static struct snd_seq_queue *queue_new(int owner, int locked)
q = kzalloc(sizeof(*q), GFP_KERNEL);
if (q == NULL) {
- snd_printd("malloc failed for snd_seq_queue_new()\n");
+ pr_debug("ALSA: seq: malloc failed for snd_seq_queue_new()\n");
return NULL;
}
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
index 24d44b2f61ac..e73605393eee 100644
--- a/sound/core/seq/seq_timer.c
+++ b/sound/core/seq/seq_timer.c
@@ -57,7 +57,7 @@ struct snd_seq_timer *snd_seq_timer_new(void)
tmr = kzalloc(sizeof(*tmr), GFP_KERNEL);
if (tmr == NULL) {
- snd_printd("malloc failed for snd_seq_timer_new() \n");
+ pr_debug("ALSA: seq: malloc failed for snd_seq_timer_new() \n");
return NULL;
}
spin_lock_init(&tmr->lock);
@@ -78,7 +78,7 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr)
*tmr = NULL;
if (t == NULL) {
- snd_printd("oops: snd_seq_timer_delete() called with NULL timer\n");
+ pr_debug("ALSA: seq: snd_seq_timer_delete() called with NULL timer\n");
return;
}
t->running = 0;
@@ -199,7 +199,7 @@ int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq)
/* refuse to change ppq on running timers */
/* because it will upset the song position (ticks) */
spin_unlock_irqrestore(&tmr->lock, flags);
- snd_printd("seq: cannot change ppq of a running timer\n");
+ pr_debug("ALSA: seq: cannot change ppq of a running timer\n");
return -EBUSY;
}
@@ -252,7 +252,7 @@ int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
/* FIXME */
if (base != SKEW_BASE) {
- snd_printd("invalid skew base 0x%x\n", base);
+ pr_debug("ALSA: seq: invalid skew base 0x%x\n", base);
return -EINVAL;
}
spin_lock_irqsave(&tmr->lock, flags);
@@ -292,7 +292,7 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
}
}
if (err < 0) {
- snd_printk(KERN_ERR "seq fatal error: cannot create timer (%i)\n", err);
+ pr_err("ALSA: seq fatal error: cannot create timer (%i)\n", err);
return err;
}
t->callback = snd_seq_timer_interrupt;
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index 4b50e604276d..56e0f4cd3f82 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -446,7 +446,7 @@ static int snd_virmidi_dev_register(struct snd_rawmidi *rmidi)
/* should check presence of port more strictly.. */
break;
default:
- snd_printk(KERN_ERR "seq_mode is not set: %d\n", rdev->seq_mode);
+ pr_err("ALSA: seq_virmidi: seq_mode is not set: %d\n", rdev->seq_mode);
return -EINVAL;
}
return 0;
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 437c25ea6403..38ad1a0dd3f7 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -118,7 +118,7 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
if (mreg && mreg->type == type) {
private_data = mreg->private_data;
if (private_data && mreg->card_ptr)
- atomic_inc(&mreg->card_ptr->refcount);
+ get_device(&mreg->card_ptr->card_dev);
} else
private_data = NULL;
mutex_unlock(&sound_mutex);
@@ -355,22 +355,25 @@ int snd_unregister_device(int type, struct snd_card *card, int dev)
EXPORT_SYMBOL(snd_unregister_device);
-int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
- struct device_attribute *attr)
+/* get the assigned device to the given type and device number;
+ * the caller needs to release it via put_device() after using it
+ */
+struct device *snd_get_device(int type, struct snd_card *card, int dev)
{
- int minor, ret = -EINVAL;
- struct device *d;
+ int minor;
+ struct device *d = NULL;
mutex_lock(&sound_mutex);
minor = find_snd_minor(type, card, dev);
- if (minor >= 0 && (d = snd_minors[minor]->dev) != NULL)
- ret = device_create_file(d, attr);
+ if (minor >= 0) {
+ d = snd_minors[minor]->dev;
+ if (d)
+ get_device(d);
+ }
mutex_unlock(&sound_mutex);
- return ret;
-
+ return d;
}
-
-EXPORT_SYMBOL(snd_add_device_sysfs_file);
+EXPORT_SYMBOL(snd_get_device);
#ifdef CONFIG_PROC_FS
/*
@@ -458,7 +461,7 @@ static int __init alsa_sound_init(void)
snd_major = major;
snd_ecards_limit = cards_limit;
if (register_chrdev(major, "alsa", &snd_fops)) {
- snd_printk(KERN_ERR "unable to register native major device number %d\n", major);
+ pr_err("ALSA core: unable to register native major device number %d\n", major);
return -EIO;
}
if (snd_info_init() < 0) {
@@ -467,7 +470,7 @@ static int __init alsa_sound_init(void)
}
snd_info_minor_register();
#ifndef MODULE
- printk(KERN_INFO "Advanced Linux Sound Architecture Driver Initialized.\n");
+ pr_info("Advanced Linux Sound Architecture Driver Initialized.\n");
#endif
return 0;
}
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index 726a49ac9725..573a65eb2b79 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -21,7 +21,7 @@
#ifdef CONFIG_SND_OSSEMUL
-#if !defined(CONFIG_SOUND) && !(defined(MODULE) && defined(CONFIG_SOUND_MODULE))
+#if !IS_ENABLED(CONFIG_SOUND)
#error "Enable the OSS soundcore multiplexer (CONFIG_SOUND) in the kernel."
#endif
@@ -55,7 +55,7 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
if (mreg && mreg->type == type) {
private_data = mreg->private_data;
if (private_data && mreg->card_ptr)
- atomic_inc(&mreg->card_ptr->refcount);
+ get_device(&mreg->card_ptr->card_dev);
} else
private_data = NULL;
mutex_unlock(&sound_oss_mutex);
@@ -105,8 +105,7 @@ static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev)
}
int snd_register_oss_device(int type, struct snd_card *card, int dev,
- const struct file_operations *f_ops, void *private_data,
- const char *name)
+ const struct file_operations *f_ops, void *private_data)
{
int minor = snd_oss_kernel_minor(type, card, dev);
int minor_unit;
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 6ddcf06f52f9..cfd455a8ac1a 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -35,9 +35,9 @@
#include <sound/initval.h>
#include <linux/kmod.h>
-#if defined(CONFIG_SND_HRTIMER) || defined(CONFIG_SND_HRTIMER_MODULE)
+#if IS_ENABLED(CONFIG_SND_HRTIMER)
#define DEFAULT_TIMER_LIMIT 4
-#elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE)
+#elif IS_ENABLED(CONFIG_SND_RTCTIMER)
#define DEFAULT_TIMER_LIMIT 2
#else
#define DEFAULT_TIMER_LIMIT 1
@@ -240,7 +240,8 @@ int snd_timer_open(struct snd_timer_instance **ti,
/* open a slave instance */
if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE ||
tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) {
- snd_printd("invalid slave class %i\n", tid->dev_sclass);
+ pr_debug("ALSA: timer: invalid slave class %i\n",
+ tid->dev_sclass);
return -EINVAL;
}
mutex_lock(&register_mutex);
@@ -774,7 +775,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
*rtimer = NULL;
timer = kzalloc(sizeof(*timer), GFP_KERNEL);
if (timer == NULL) {
- snd_printk(KERN_ERR "timer: cannot allocate\n");
+ pr_err("ALSA: timer: cannot allocate\n");
return -ENOMEM;
}
timer->tmr_class = tid->dev_class;
@@ -813,7 +814,7 @@ static int snd_timer_free(struct snd_timer *timer)
if (! list_empty(&timer->open_list_head)) {
struct list_head *p, *n;
struct snd_timer_instance *ti;
- snd_printk(KERN_WARNING "timer %p is busy?\n", timer);
+ pr_warn("ALSA: timer %p is busy?\n", timer);
list_for_each_safe(p, n, &timer->open_list_head) {
list_del_init(p);
ti = list_entry(p, struct snd_timer_instance, open_list);
@@ -1955,12 +1956,10 @@ static int __init alsa_timer_init(void)
#endif
if ((err = snd_timer_register_system()) < 0)
- snd_printk(KERN_ERR "unable to register system timer (%i)\n",
- err);
+ pr_err("ALSA: unable to register system timer (%i)\n", err);
if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,
&snd_timer_f_ops, NULL, "timer")) < 0)
- snd_printk(KERN_ERR "unable to register timer device (%i)\n",
- err);
+ pr_err("ALSA: unable to register timer device (%i)\n", err);
snd_timer_proc_init();
return 0;
}
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index 842a97d5fc3a..6c58e6f73a01 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -101,7 +101,7 @@ static int slave_init(struct link_slave *slave)
if (slave->info.count > 2 ||
(slave->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
slave->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) {
- snd_printk(KERN_ERR "invalid slave element\n");
+ pr_err("ALSA: vmaster: invalid slave element\n");
kfree(uinfo);
return -EINVAL;
}
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index f7589923effa..2a16c86a60b3 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -1142,8 +1142,8 @@ static int loopback_probe(struct platform_device *devptr)
int dev = devptr->id;
int err;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct loopback), &card);
+ err = snd_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct loopback), &card);
if (err < 0)
return err;
loopback = card->private_data;
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 915b4d7fbb23..fab90bd2bd51 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -1054,8 +1054,8 @@ static int snd_dummy_probe(struct platform_device *devptr)
int idx, err;
int dev = devptr->id;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_dummy), &card);
+ err = snd_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_dummy), &card);
if (err < 0)
return err;
dummy = card->private_data;
@@ -1114,8 +1114,6 @@ static int snd_dummy_probe(struct platform_device *devptr)
dummy_proc_init(dummy);
- snd_card_set_dev(card, &devptr->dev);
-
err = snd_card_register(card);
if (err == 0) {
platform_set_drvdata(devptr, card);
diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c
index 95ea4a153ea4..33ed76530d0b 100644
--- a/sound/drivers/ml403-ac97cr.c
+++ b/sound/drivers/ml403-ac97cr.c
@@ -1280,7 +1280,8 @@ static int snd_ml403_ac97cr_probe(struct platform_device *pfdev)
if (!enable[dev])
return -ENOENT;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pfdev->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
err = snd_ml403_ac97cr_create(card, pfdev, &ml403_ac97cr);
@@ -1310,8 +1311,6 @@ static int snd_ml403_ac97cr_probe(struct platform_device *pfdev)
(unsigned long)ml403_ac97cr->port, ml403_ac97cr->irq,
ml403_ac97cr->capture_irq, dev + 1);
- snd_card_set_dev(card, &pfdev->dev);
-
err = snd_card_register(card);
if (err < 0) {
snd_card_free(card);
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
index 90a3a7b38a2a..83014b83a44e 100644
--- a/sound/drivers/mpu401/mpu401.c
+++ b/sound/drivers/mpu401/mpu401.c
@@ -64,7 +64,8 @@ static struct platform_device *platform_devices[SNDRV_CARDS];
static int pnp_registered;
static unsigned int snd_mpu401_devices;
-static int snd_mpu401_create(int dev, struct snd_card **rcard)
+static int snd_mpu401_create(struct device *devptr, int dev,
+ struct snd_card **rcard)
{
struct snd_card *card;
int err;
@@ -73,7 +74,8 @@ static int snd_mpu401_create(int dev, struct snd_card **rcard)
snd_printk(KERN_ERR "the uart_enter option is obsolete; remove it\n");
*rcard = NULL;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
strcpy(card->driver, "MPU-401 UART");
@@ -114,10 +116,9 @@ static int snd_mpu401_probe(struct platform_device *devptr)
snd_printk(KERN_ERR "specify or disable IRQ\n");
return -EINVAL;
}
- err = snd_mpu401_create(dev, &card);
+ err = snd_mpu401_create(&devptr->dev, dev, &card);
if (err < 0)
return err;
- snd_card_set_dev(card, &devptr->dev);
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
return err;
@@ -194,14 +195,13 @@ static int snd_mpu401_pnp_probe(struct pnp_dev *pnp_dev,
err = snd_mpu401_pnp(dev, pnp_dev, id);
if (err < 0)
return err;
- err = snd_mpu401_create(dev, &card);
+ err = snd_mpu401_create(&pnp_dev->dev, dev, &card);
if (err < 0)
return err;
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
return err;
}
- snd_card_set_dev(card, &pnp_dev->dev);
pnp_set_drvdata(pnp_dev, card);
snd_mpu401_devices++;
++dev;
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index e5ec7eb27dec..4b66c7f22af7 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -697,7 +697,8 @@ static int snd_mtpav_probe(struct platform_device *dev)
int err;
struct mtpav *mtp_card;
- err = snd_card_create(index, id, THIS_MODULE, sizeof(*mtp_card), &card);
+ err = snd_card_new(&dev->dev, index, id, THIS_MODULE,
+ sizeof(*mtp_card), &card);
if (err < 0)
return err;
@@ -732,7 +733,6 @@ static int snd_mtpav_probe(struct platform_device *dev)
snd_mtpav_portscan(mtp_card);
- snd_card_set_dev(card, &dev->dev);
err = snd_card_register(mtp_card->card);
if (err < 0)
goto __error;
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c
index 4e0dd22ba08e..f5fd448dbc57 100644
--- a/sound/drivers/mts64.c
+++ b/sound/drivers/mts64.c
@@ -959,7 +959,8 @@ static int snd_mts64_probe(struct platform_device *pdev)
if ((err = snd_mts64_probe_port(p)) < 0)
return err;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pdev->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0) {
snd_printd("Cannot create card\n");
return err;
@@ -1009,8 +1010,6 @@ static int snd_mts64_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, card);
- snd_card_set_dev(card, &pdev->dev);
-
/* At this point card will be usable */
if ((err = snd_card_register(card)) < 0) {
snd_printd("Cannot register card\n");
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
index 33d9a857a262..f66af5884c40 100644
--- a/sound/drivers/opl3/opl3_lib.c
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -501,10 +501,8 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
hw->private_data = opl3;
hw->exclusive = 1;
#ifdef CONFIG_SND_OSSEMUL
- if (device == 0) {
+ if (device == 0)
hw->oss_type = SNDRV_OSS_DEVICE_TYPE_DMFM;
- sprintf(hw->oss_dev, "dmfm%i", card->number);
- }
#endif
strcpy(hw->name, hw->id);
switch (opl3->hardware & OPL3_HW_MASK) {
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c
index 742a4b642fd9..ddcc1a325a61 100644
--- a/sound/drivers/opl3/opl3_synth.c
+++ b/sound/drivers/opl3/opl3_synth.c
@@ -24,7 +24,7 @@
#include <sound/opl3.h>
#include <sound/asound_fm.h>
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
#define OPL3_SUPPORT_SYNTH
#endif
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c
index 328bd29264ce..36808cdab06f 100644
--- a/sound/drivers/pcsp/pcsp.c
+++ b/sound/drivers/pcsp/pcsp.c
@@ -105,7 +105,7 @@ static int snd_card_pcsp_probe(int devnum, struct device *dev)
hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
pcsp_chip.timer.function = pcsp_do_timer;
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -127,8 +127,6 @@ static int snd_card_pcsp_probe(int devnum, struct device *dev)
return err;
}
- snd_card_set_dev(pcsp_chip.card, dev);
-
strcpy(card->driver, "PC-Speaker");
strcpy(card->shortname, "pcsp");
sprintf(card->longname, "Internal PC-Speaker at port 0x%x",
diff --git a/sound/drivers/pcsp/pcsp_input.c b/sound/drivers/pcsp/pcsp_input.c
index b874b0ad99cd..0ecf8a453e01 100644
--- a/sound/drivers/pcsp/pcsp_input.c
+++ b/sound/drivers/pcsp/pcsp_input.c
@@ -16,6 +16,7 @@
#include <linux/input.h>
#include <asm/io.h>
#include "pcsp.h"
+#include "pcsp_input.h"
static void pcspkr_do_sound(unsigned int count)
{
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c
index 991018df7131..78ccfa455527 100644
--- a/sound/drivers/portman2x4.c
+++ b/sound/drivers/portman2x4.c
@@ -748,7 +748,8 @@ static int snd_portman_probe(struct platform_device *pdev)
if ((err = snd_portman_probe_port(p)) < 0)
return err;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pdev->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0) {
snd_printd("Cannot create card\n");
return err;
@@ -798,8 +799,6 @@ static int snd_portman_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, card);
- snd_card_set_dev(card, &pdev->dev);
-
/* At this point card will be usable */
if ((err = snd_card_register(card)) < 0) {
snd_printd("Cannot register card\n");
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index e0bf5e77b43a..9ad4414fa25c 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -942,7 +942,8 @@ static int snd_serial_probe(struct platform_device *devptr)
return -ENODEV;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -969,8 +970,6 @@ static int snd_serial_probe(struct platform_device *devptr)
uart->base,
uart->irq);
- snd_card_set_dev(card, &devptr->dev);
-
if ((err = snd_card_register(card)) < 0)
goto _err;
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index ace3879e8d96..b178724295f3 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -90,8 +90,8 @@ static int snd_virmidi_probe(struct platform_device *devptr)
int idx, err;
int dev = devptr->id;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_virmidi), &card);
+ err = snd_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_virmidi), &card);
if (err < 0)
return err;
vmidi = card->private_data;
@@ -118,8 +118,6 @@ static int snd_virmidi_probe(struct platform_device *devptr)
strcpy(card->shortname, "VirMIDI");
sprintf(card->longname, "Virtual MIDI Card %i", dev + 1);
- snd_card_set_dev(card, &devptr->dev);
-
if ((err = snd_card_register(card)) == 0) {
platform_set_drvdata(devptr, card);
return 0;
diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c
index c0aa64941cee..0c3948630cf7 100644
--- a/sound/firewire/dice.c
+++ b/sound/firewire/dice.c
@@ -1326,10 +1326,10 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
if (err < 0)
return err;
- err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*dice), &card);
+ err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
+ sizeof(*dice), &card);
if (err < 0)
return err;
- snd_card_set_dev(card, &unit->device);
dice = card->private_data;
dice->card = card;
diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c
index fd42e6b315e6..7ac94439e758 100644
--- a/sound/firewire/isight.c
+++ b/sound/firewire/isight.c
@@ -631,10 +631,10 @@ static int isight_probe(struct fw_unit *unit,
struct isight *isight;
int err;
- err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card);
+ err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
+ sizeof(*isight), &card);
if (err < 0)
return err;
- snd_card_set_dev(card, &unit->device);
isight = card->private_data;
isight->card = card;
diff --git a/sound/firewire/scs1x.c b/sound/firewire/scs1x.c
index 858023cf4298..2dba848a781f 100644
--- a/sound/firewire/scs1x.c
+++ b/sound/firewire/scs1x.c
@@ -391,10 +391,10 @@ static int scs_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
struct scs *scs;
int err;
- err = snd_card_create(-16, NULL, THIS_MODULE, sizeof(*scs), &card);
+ err = snd_card_new(&unit->device, -16, NULL, THIS_MODULE,
+ sizeof(*scs), &card);
if (err < 0)
return err;
- snd_card_set_dev(card, &unit->device);
scs = card->private_data;
scs->card = card;
diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c
index cc8bc3a51bc1..9f7ef219b109 100644
--- a/sound/firewire/speakers.c
+++ b/sound/firewire/speakers.c
@@ -668,10 +668,10 @@ static int fwspk_probe(struct fw_unit *unit,
u32 firmware;
int err;
- err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*fwspk), &card);
+ err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
+ sizeof(*fwspk), &card);
if (err < 0)
return err;
- snd_card_set_dev(card, &unit->device);
fwspk = card->private_data;
fwspk->card = card;
diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c
index e04e750a77ed..1a3a6fa27158 100644
--- a/sound/i2c/other/ak4113.c
+++ b/sound/i2c/other/ak4113.c
@@ -98,7 +98,7 @@ int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read,
AK4113_CINT | AK4113_STC);
chip->rcs1 = reg_read(chip, AK4113_REG_RCS1);
chip->rcs2 = reg_read(chip, AK4113_REG_RCS2);
- err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+ err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops);
if (err < 0)
goto __fail;
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
index 15ae0250eace..c7f56339415d 100644
--- a/sound/i2c/other/ak4114.c
+++ b/sound/i2c/other/ak4114.c
@@ -111,7 +111,7 @@ int snd_ak4114_create(struct snd_card *card,
chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT);
chip->rcs1 = reg_read(chip, AK4114_REG_RCS1);
- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
+ if ((err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops)) < 0)
goto __fail;
if (r_ak4114)
diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c
index 40e33c9f2b09..88452e899bd9 100644
--- a/sound/i2c/other/ak4117.c
+++ b/sound/i2c/other/ak4117.c
@@ -62,7 +62,7 @@ static void reg_dump(struct ak4117 *ak4117)
static void snd_ak4117_free(struct ak4117 *chip)
{
- del_timer(&chip->timer);
+ del_timer_sync(&chip->timer);
kfree(chip);
}
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index 26ce26a5884d..f481a41e027e 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -144,8 +144,9 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
struct snd_opl3 *opl3;
struct snd_timer *timer;
- error = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_ad1816a), &card);
+ error = snd_card_new(&pcard->card->dev,
+ index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_ad1816a), &card);
if (error < 0)
return error;
chip = card->private_data;
@@ -154,7 +155,6 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
snd_card_free(card);
return error;
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((error = snd_ad1816a_create(card, port[dev],
irq[dev],
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c
index e3f455bd85cd..093f22a464d7 100644
--- a/sound/isa/ad1848/ad1848.c
+++ b/sound/isa/ad1848/ad1848.c
@@ -91,7 +91,7 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n)
struct snd_pcm *pcm;
int error;
- error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
if (error < 0)
return error;
@@ -119,8 +119,6 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n)
if (thinkpad[n])
strcat(card->longname, " [Thinkpad]");
- snd_card_set_dev(card, dev);
-
error = snd_card_register(card);
if (error < 0)
goto out;
diff --git a/sound/isa/adlib.c b/sound/isa/adlib.c
index 35659218710f..120c524bb2a0 100644
--- a/sound/isa/adlib.c
+++ b/sound/isa/adlib.c
@@ -53,7 +53,7 @@ static int snd_adlib_probe(struct device *dev, unsigned int n)
struct snd_opl3 *opl3;
int error;
- error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
if (error < 0) {
dev_err(dev, "could not create card\n");
return error;
@@ -83,8 +83,6 @@ static int snd_adlib_probe(struct device *dev, unsigned int n)
goto out;
}
- snd_card_set_dev(card, dev);
-
error = snd_card_register(card);
if (error < 0) {
dev_err(dev, "could not register card\n");
diff --git a/sound/isa/als100.c b/sound/isa/als100.c
index 10f08a18fe3b..32d01525211d 100644
--- a/sound/isa/als100.c
+++ b/sound/isa/als100.c
@@ -193,8 +193,9 @@ static int snd_card_als100_probe(int dev,
struct snd_card_als100 *acard;
struct snd_opl3 *opl3;
- error = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_als100), &card);
+ error = snd_card_new(&pcard->card->dev,
+ index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_als100), &card);
if (error < 0)
return error;
acard = card->private_data;
@@ -203,7 +204,6 @@ static int snd_card_als100_probe(int dev,
snd_card_free(card);
return error;
}
- snd_card_set_dev(card, &pcard->card->dev);
if (pid->driver_data == SB_HW_DT019X)
dma16[dev] = -1;
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c
index db301ff94ec2..0ea75fc62072 100644
--- a/sound/isa/azt2320.c
+++ b/sound/isa/azt2320.c
@@ -184,8 +184,9 @@ static int snd_card_azt2320_probe(int dev,
struct snd_wss *chip;
struct snd_opl3 *opl3;
- error = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_azt2320), &card);
+ error = snd_card_new(&pcard->card->dev,
+ index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_azt2320), &card);
if (error < 0)
return error;
acard = card->private_data;
@@ -194,7 +195,6 @@ static int snd_card_azt2320_probe(int dev,
snd_card_free(card);
return error;
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((error = snd_card_azt2320_enable_wss(port[dev]))) {
snd_card_free(card);
diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c
index ab6b2dc043f1..4778852a1201 100644
--- a/sound/isa/cmi8328.c
+++ b/sound/isa/cmi8328.c
@@ -293,15 +293,14 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
}
outb(val, port);
- err = snd_card_create(index[ndev], id[ndev], THIS_MODULE,
- sizeof(struct snd_cmi8328), &card);
+ err = snd_card_new(pdev, index[ndev], id[ndev], THIS_MODULE,
+ sizeof(struct snd_cmi8328), &card);
if (err < 0)
return err;
cmi = card->private_data;
cmi->card = card;
cmi->port = port;
cmi->wss_cfg = val;
- snd_card_set_dev(card, pdev);
err = snd_wss_create(card, port + 4, -1, irq[ndev], dma1[ndev],
dma2[ndev], WSS_HW_DETECT, 0, &cmi->wss);
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index 270b9659ef7f..dfedfd85f205 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -514,14 +514,15 @@ static int snd_cmi8330_resume(struct snd_card *card)
#define PFX "cmi8330: "
-static int snd_cmi8330_card_new(int dev, struct snd_card **cardp)
+static int snd_cmi8330_card_new(struct device *pdev, int dev,
+ struct snd_card **cardp)
{
struct snd_card *card;
struct snd_cmi8330 *acard;
int err;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_cmi8330), &card);
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_cmi8330), &card);
if (err < 0) {
snd_printk(KERN_ERR PFX "could not get a new card\n");
return err;
@@ -635,10 +636,9 @@ static int snd_cmi8330_isa_probe(struct device *pdev,
struct snd_card *card;
int err;
- err = snd_cmi8330_card_new(dev, &card);
+ err = snd_cmi8330_card_new(pdev, dev, &card);
if (err < 0)
return err;
- snd_card_set_dev(card, pdev);
if ((err = snd_cmi8330_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
@@ -698,7 +698,7 @@ static int snd_cmi8330_pnp_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- res = snd_cmi8330_card_new(dev, &card);
+ res = snd_cmi8330_card_new(&pcard->card->dev, dev, &card);
if (res < 0)
return res;
if ((res = snd_cmi8330_pnp(dev, card->private_data, pcard, pid)) < 0) {
@@ -706,7 +706,6 @@ static int snd_cmi8330_pnp_detect(struct pnp_card_link *pcard,
snd_card_free(card);
return res;
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((res = snd_cmi8330_probe(card, dev)) < 0) {
snd_card_free(card);
return res;
diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c
index ba9a74eff3e0..7dba07a4343a 100644
--- a/sound/isa/cs423x/cs4231.c
+++ b/sound/isa/cs423x/cs4231.c
@@ -95,7 +95,7 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n)
struct snd_pcm *pcm;
int error;
- error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
if (error < 0)
return error;
@@ -135,8 +135,6 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n)
dev_warn(dev, "MPU401 not detected\n");
}
- snd_card_set_dev(card, dev);
-
error = snd_card_register(card);
if (error < 0)
goto out;
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index 69614acb2052..750f51c904fc 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -364,13 +364,14 @@ static void snd_card_cs4236_free(struct snd_card *card)
release_and_free_resource(acard->res_sb_port);
}
-static int snd_cs423x_card_new(int dev, struct snd_card **cardp)
+static int snd_cs423x_card_new(struct device *pdev, int dev,
+ struct snd_card **cardp)
{
struct snd_card *card;
int err;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_cs4236), &card);
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_cs4236), &card);
if (err < 0)
return err;
card->private_free = snd_card_cs4236_free;
@@ -487,10 +488,9 @@ static int snd_cs423x_isa_probe(struct device *pdev,
struct snd_card *card;
int err;
- err = snd_cs423x_card_new(dev, &card);
+ err = snd_cs423x_card_new(pdev, dev, &card);
if (err < 0)
return err;
- snd_card_set_dev(card, pdev);
if ((err = snd_cs423x_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
@@ -577,7 +577,7 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
if (!strcmp(cdev->id[0].id, cid))
break;
}
- err = snd_cs423x_card_new(dev, &card);
+ err = snd_cs423x_card_new(&pdev->dev, dev, &card);
if (err < 0)
return err;
err = snd_card_cs423x_pnp(dev, card->private_data, pdev, cdev);
@@ -586,7 +586,6 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
snd_card_free(card);
return err;
}
- snd_card_set_dev(card, &pdev->dev);
if ((err = snd_cs423x_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
@@ -638,7 +637,7 @@ static int snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- res = snd_cs423x_card_new(dev, &card);
+ res = snd_cs423x_card_new(&pcard->card->dev, dev, &card);
if (res < 0)
return res;
if ((res = snd_card_cs423x_pnpc(dev, card->private_data, pcard, pid)) < 0) {
@@ -647,7 +646,6 @@ static int snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
snd_card_free(card);
return res;
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((res = snd_cs423x_probe(card, dev)) < 0) {
snd_card_free(card);
return res;
diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c
index cdcfb57f1f0a..76001fe0579d 100644
--- a/sound/isa/es1688/es1688.c
+++ b/sound/isa/es1688/es1688.c
@@ -187,8 +187,8 @@ static int snd_es1688_isa_probe(struct device *dev, unsigned int n)
struct snd_card *card;
int error;
- error = snd_card_create(index[n], id[n], THIS_MODULE,
- sizeof(struct snd_es1688), &card);
+ error = snd_card_new(dev, index[n], id[n], THIS_MODULE,
+ sizeof(struct snd_es1688), &card);
if (error < 0)
return error;
@@ -196,8 +196,6 @@ static int snd_es1688_isa_probe(struct device *dev, unsigned int n)
if (error < 0)
goto out;
- snd_card_set_dev(card, dev);
-
error = snd_es1688_probe(card, n);
if (error < 0)
goto out;
@@ -274,8 +272,9 @@ static int snd_es968_pnp_detect(struct pnp_card_link *pcard,
if (dev == SNDRV_CARDS)
return -ENODEV;
- error = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_es1688), &card);
+ error = snd_card_new(&pcard->card->dev,
+ index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_es1688), &card);
if (error < 0)
return error;
chip = card->private_data;
@@ -285,7 +284,6 @@ static int snd_es968_pnp_detect(struct pnp_card_link *pcard,
snd_card_free(card);
return error;
}
- snd_card_set_dev(card, &pcard->card->dev);
error = snd_es1688_probe(card, dev);
if (error < 0)
return error;
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 12978b864c3a..1c16830af3d8 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -2105,10 +2105,11 @@ static int snd_audiodrive_pnpc(int dev, struct snd_es18xx *chip,
#define is_isapnp_selected(dev) 0
#endif
-static int snd_es18xx_card_new(int dev, struct snd_card **cardp)
+static int snd_es18xx_card_new(struct device *pdev, int dev,
+ struct snd_card **cardp)
{
- return snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_es18xx), cardp);
+ return snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_es18xx), cardp);
}
static int snd_audiodrive_probe(struct snd_card *card, int dev)
@@ -2179,10 +2180,9 @@ static int snd_es18xx_isa_probe1(int dev, struct device *devptr)
struct snd_card *card;
int err;
- err = snd_es18xx_card_new(dev, &card);
+ err = snd_es18xx_card_new(devptr, dev, &card);
if (err < 0)
return err;
- snd_card_set_dev(card, devptr);
if ((err = snd_audiodrive_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
@@ -2284,14 +2284,13 @@ static int snd_audiodrive_pnp_detect(struct pnp_dev *pdev,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- err = snd_es18xx_card_new(dev, &card);
+ err = snd_es18xx_card_new(&pdev->dev, dev, &card);
if (err < 0)
return err;
if ((err = snd_audiodrive_pnp(dev, card->private_data, pdev)) < 0) {
snd_card_free(card);
return err;
}
- snd_card_set_dev(card, &pdev->dev);
if ((err = snd_audiodrive_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
@@ -2342,7 +2341,7 @@ static int snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- res = snd_es18xx_card_new(dev, &card);
+ res = snd_es18xx_card_new(&pcard->card->dev, dev, &card);
if (res < 0)
return res;
@@ -2350,7 +2349,6 @@ static int snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard,
snd_card_free(card);
return res;
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((res = snd_audiodrive_probe(card, dev)) < 0) {
snd_card_free(card);
return res;
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c
index 81244e7cea5b..1eb2b1ec0fd9 100644
--- a/sound/isa/galaxy/galaxy.c
+++ b/sound/isa/galaxy/galaxy.c
@@ -506,13 +506,11 @@ static int snd_galaxy_probe(struct device *dev, unsigned int n)
u8 type;
int err;
- err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy,
- &card);
+ err = snd_card_new(dev, index[n], id[n], THIS_MODULE,
+ sizeof(*galaxy), &card);
if (err < 0)
return err;
- snd_card_set_dev(card, dev);
-
card->private_free = snd_galaxy_free;
galaxy = card->private_data;
diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c
index 1adc1b924f39..7ce29ffa1af9 100644
--- a/sound/isa/gus/gusclassic.c
+++ b/sound/isa/gus/gusclassic.c
@@ -149,7 +149,7 @@ static int snd_gusclassic_probe(struct device *dev, unsigned int n)
struct snd_gus_card *gus;
int error;
- error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
if (error < 0)
return error;
@@ -199,8 +199,6 @@ static int snd_gusclassic_probe(struct device *dev, unsigned int n)
sprintf(card->longname + strlen(card->longname),
"&%d", gus->gf1.dma2);
- snd_card_set_dev(card, dev);
-
error = snd_card_register(card);
if (error < 0)
goto out;
diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c
index 38e1e3260c24..28a16936a397 100644
--- a/sound/isa/gus/gusextreme.c
+++ b/sound/isa/gus/gusextreme.c
@@ -242,8 +242,8 @@ static int snd_gusextreme_probe(struct device *dev, unsigned int n)
struct snd_opl3 *opl3;
int error;
- error = snd_card_create(index[n], id[n], THIS_MODULE,
- sizeof(struct snd_es1688), &card);
+ error = snd_card_new(dev, index[n], id[n], THIS_MODULE,
+ sizeof(struct snd_es1688), &card);
if (error < 0)
return error;
@@ -328,8 +328,6 @@ static int snd_gusextreme_probe(struct device *dev, unsigned int n)
"irq %i&%i, dma %i&%i", es1688->port,
gus->gf1.irq, es1688->irq, gus->gf1.dma1, es1688->dma8);
- snd_card_set_dev(card, dev);
-
error = snd_card_register(card);
if (error < 0)
goto out;
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index 652d5d834620..39df36ca3acb 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -214,8 +214,8 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
struct snd_wss *wss;
struct snd_gusmax *maxcard;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_gusmax), &card);
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_gusmax), &card);
if (err < 0)
return err;
card->private_free = snd_gusmax_free;
@@ -337,8 +337,6 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
if (xdma2 >= 0)
sprintf(card->longname + strlen(card->longname), "&%i", xdma2);
- snd_card_set_dev(card, pdev);
-
err = snd_card_register(card);
if (err < 0)
goto _err;
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index afef0d738078..5abbbe477d16 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -625,14 +625,15 @@ static void snd_interwave_free(struct snd_card *card)
free_irq(iwcard->irq, (void *)iwcard);
}
-static int snd_interwave_card_new(int dev, struct snd_card **cardp)
+static int snd_interwave_card_new(struct device *pdev, int dev,
+ struct snd_card **cardp)
{
struct snd_card *card;
struct snd_interwave *iwcard;
int err;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_interwave), &card);
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_interwave), &card);
if (err < 0)
return err;
iwcard = card->private_data;
@@ -779,11 +780,10 @@ static int snd_interwave_isa_probe1(int dev, struct device *devptr)
struct snd_card *card;
int err;
- err = snd_interwave_card_new(dev, &card);
+ err = snd_interwave_card_new(devptr, dev, &card);
if (err < 0)
return err;
- snd_card_set_dev(card, devptr);
if ((err = snd_interwave_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
@@ -876,7 +876,7 @@ static int snd_interwave_pnp_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- res = snd_interwave_card_new(dev, &card);
+ res = snd_interwave_card_new(&pcard->card->dev, dev, &card);
if (res < 0)
return res;
@@ -884,7 +884,6 @@ static int snd_interwave_pnp_detect(struct pnp_card_link *pcard,
snd_card_free(card);
return res;
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((res = snd_interwave_probe(card, dev)) < 0) {
snd_card_free(card);
return res;
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
index 0a90bd6ae232..5016bf957f51 100644
--- a/sound/isa/msnd/msnd_pinnacle.c
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -905,12 +905,11 @@ static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
return -ENODEV;
}
- err = snd_card_create(index[idx], id[idx], THIS_MODULE,
- sizeof(struct snd_msnd), &card);
+ err = snd_card_new(pdev, index[idx], id[idx], THIS_MODULE,
+ sizeof(struct snd_msnd), &card);
if (err < 0)
return err;
- snd_card_set_dev(card, pdev);
chip = card->private_data;
chip->card = card;
@@ -1122,14 +1121,14 @@ static int snd_msnd_pnp_detect(struct pnp_card_link *pcard,
* Create a new ALSA sound card entry, in anticipation
* of detecting our hardware ...
*/
- ret = snd_card_create(index[idx], id[idx], THIS_MODULE,
- sizeof(struct snd_msnd), &card);
+ ret = snd_card_new(&pcard->card->dev,
+ index[idx], id[idx], THIS_MODULE,
+ sizeof(struct snd_msnd), &card);
if (ret < 0)
return ret;
chip = card->private_data;
chip->card = card;
- snd_card_set_dev(card, &pcard->card->dev);
/*
* Read the correct parameters off the ISA PnP bus ...
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index cc01c419b7e9..a219bc37816b 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -627,14 +627,15 @@ static void snd_opl3sa2_free(struct snd_card *card)
release_and_free_resource(chip->res_port);
}
-static int snd_opl3sa2_card_new(int dev, struct snd_card **cardp)
+static int snd_opl3sa2_card_new(struct device *pdev, int dev,
+ struct snd_card **cardp)
{
struct snd_card *card;
struct snd_opl3sa2 *chip;
int err;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_opl3sa2), &card);
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_opl3sa2), &card);
if (err < 0)
return err;
strcpy(card->driver, "OPL3SA2");
@@ -737,14 +738,13 @@ static int snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- err = snd_opl3sa2_card_new(dev, &card);
+ err = snd_opl3sa2_card_new(&pdev->dev, dev, &card);
if (err < 0)
return err;
if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) {
snd_card_free(card);
return err;
}
- snd_card_set_dev(card, &pdev->dev);
if ((err = snd_opl3sa2_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
@@ -802,14 +802,13 @@ static int snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- err = snd_opl3sa2_card_new(dev, &card);
+ err = snd_opl3sa2_card_new(&pdev->dev, dev, &card);
if (err < 0)
return err;
if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) {
snd_card_free(card);
return err;
}
- snd_card_set_dev(card, &pdev->dev);
if ((err = snd_opl3sa2_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
@@ -883,10 +882,9 @@ static int snd_opl3sa2_isa_probe(struct device *pdev,
struct snd_card *card;
int err;
- err = snd_opl3sa2_card_new(dev, &card);
+ err = snd_opl3sa2_card_new(pdev, dev, &card);
if (err < 0)
return err;
- snd_card_set_dev(card, pdev);
if ((err = snd_opl3sa2_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index 619753d96ca5..c2ca681ac51b 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -1411,8 +1411,8 @@ static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
struct snd_miro *miro;
struct snd_card *card;
- error = snd_card_create(index, id, THIS_MODULE,
- sizeof(struct snd_miro), &card);
+ error = snd_card_new(devptr, index, id, THIS_MODULE,
+ sizeof(struct snd_miro), &card);
if (error < 0)
return error;
@@ -1479,8 +1479,6 @@ static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
}
}
- snd_card_set_dev(card, devptr);
-
error = snd_miro_probe(card);
if (error < 0) {
snd_card_free(card);
@@ -1584,8 +1582,8 @@ static int snd_miro_pnp_probe(struct pnp_card_link *pcard,
return -EBUSY;
if (!isapnp)
return -ENODEV;
- err = snd_card_create(index, id, THIS_MODULE,
- sizeof(struct snd_miro), &card);
+ err = snd_card_new(&pcard->card->dev, index, id, THIS_MODULE,
+ sizeof(struct snd_miro), &card);
if (err < 0)
return err;
@@ -1612,7 +1610,6 @@ static int snd_miro_pnp_probe(struct pnp_card_link *pcard,
return err;
}
- snd_card_set_dev(card, &pcard->card->dev);
err = snd_miro_probe(card);
if (err < 0) {
snd_card_free(card);
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 6effe99bbb9c..c9b582848603 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -934,13 +934,13 @@ static int snd_opti9xx_probe(struct snd_card *card)
return snd_card_register(card);
}
-static int snd_opti9xx_card_new(struct snd_card **cardp)
+static int snd_opti9xx_card_new(struct device *pdev, struct snd_card **cardp)
{
struct snd_card *card;
int err;
- err = snd_card_create(index, id, THIS_MODULE,
- sizeof(struct snd_opti9xx), &card);
+ err = snd_card_new(pdev, index, id, THIS_MODULE,
+ sizeof(struct snd_opti9xx), &card);
if (err < 0)
return err;
card->private_free = snd_card_opti9xx_free;
@@ -1010,7 +1010,7 @@ static int snd_opti9xx_isa_probe(struct device *devptr,
}
#endif
- error = snd_opti9xx_card_new(&card);
+ error = snd_opti9xx_card_new(devptr, &card);
if (error < 0)
return error;
@@ -1018,7 +1018,6 @@ static int snd_opti9xx_isa_probe(struct device *devptr,
snd_card_free(card);
return error;
}
- snd_card_set_dev(card, devptr);
if ((error = snd_opti9xx_probe(card)) < 0) {
snd_card_free(card);
return error;
@@ -1100,7 +1099,7 @@ static int snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
return -EBUSY;
if (! isapnp)
return -ENODEV;
- error = snd_opti9xx_card_new(&card);
+ error = snd_opti9xx_card_new(&pcard->card->dev, &card);
if (error < 0)
return error;
chip = card->private_data;
@@ -1131,7 +1130,6 @@ static int snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
snd_card_free(card);
return error;
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((error = snd_opti9xx_probe(card)) < 0) {
snd_card_free(card);
return error;
diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c
index 356a6308392f..90d2eba549e9 100644
--- a/sound/isa/sb/jazz16.c
+++ b/sound/isa/sb/jazz16.c
@@ -229,8 +229,8 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
static int possible_dmas16[] = {5, 7, -1};
int err, xirq, xdma8, xdma16, xmpu_port, xmpu_irq;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_jazz16), &card);
+ err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_jazz16), &card);
if (err < 0)
return err;
@@ -327,8 +327,6 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
mpu_port[dev]);
}
- snd_card_set_dev(card, devptr);
-
err = snd_card_register(card);
if (err < 0)
goto err_free;
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
index a4130993955f..3f694543a7ea 100644
--- a/sound/isa/sb/sb16.c
+++ b/sound/isa/sb/sb16.c
@@ -323,13 +323,14 @@ static void snd_sb16_free(struct snd_card *card)
#define is_isapnp_selected(dev) 0
#endif
-static int snd_sb16_card_new(int dev, struct snd_card **cardp)
+static int snd_sb16_card_new(struct device *devptr, int dev,
+ struct snd_card **cardp)
{
struct snd_card *card;
int err;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_sb16), &card);
+ err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_sb16), &card);
if (err < 0)
return err;
card->private_free = snd_sb16_free;
@@ -493,7 +494,7 @@ static int snd_sb16_isa_probe1(int dev, struct device *pdev)
struct snd_card *card;
int err;
- err = snd_sb16_card_new(dev, &card);
+ err = snd_sb16_card_new(pdev, dev, &card);
if (err < 0)
return err;
@@ -507,7 +508,6 @@ static int snd_sb16_isa_probe1(int dev, struct device *pdev)
awe_port[dev] = port[dev] + 0x400;
#endif
- snd_card_set_dev(card, pdev);
if ((err = snd_sb16_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
@@ -613,10 +613,9 @@ static int snd_sb16_pnp_detect(struct pnp_card_link *pcard,
for ( ; dev < SNDRV_CARDS; dev++) {
if (!enable[dev] || !isapnp[dev])
continue;
- res = snd_sb16_card_new(dev, &card);
+ res = snd_sb16_card_new(&pcard->card->dev, dev, &card);
if (res < 0)
return res;
- snd_card_set_dev(card, &pcard->card->dev);
if ((res = snd_card_sb16_pnp(dev, card->private_data, pcard, pid)) < 0 ||
(res = snd_sb16_probe(card, dev)) < 0) {
snd_card_free(card);
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index a806ae90a944..6c32b3aa34af 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -102,8 +102,8 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
struct snd_opl3 *opl3;
int err;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_sb8), &card);
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_sb8), &card);
if (err < 0)
return err;
acard = card->private_data;
@@ -192,8 +192,6 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
chip->port,
irq[dev], dma8[dev]);
- snd_card_set_dev(card, pdev);
-
if ((err = snd_card_register(card)) < 0)
goto _err;
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
index 09d481b3ba7f..15a152eaa2e8 100644
--- a/sound/isa/sc6000.c
+++ b/sound/isa/sc6000.c
@@ -559,8 +559,8 @@ static int snd_sc6000_probe(struct device *devptr, unsigned int dev)
char __iomem *vmss_port;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, sizeof(vport),
- &card);
+ err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE,
+ sizeof(vport), &card);
if (err < 0)
return err;
@@ -668,8 +668,6 @@ static int snd_sc6000_probe(struct device *devptr, unsigned int dev)
sprintf(card->longname, "Gallant SC-6000 at 0x%lx, irq %d, dma %d",
mss_port[dev], xirq, xdma);
- snd_card_set_dev(card, devptr);
-
err = snd_card_register(card);
if (err < 0)
goto err_unmap2;
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 57b338973ede..44405df7d4be 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -1169,8 +1169,8 @@ static int snd_sscape_probe(struct device *pdev, unsigned int dev)
struct soundscape *sscape;
int ret;
- ret = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct soundscape), &card);
+ ret = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct soundscape), &card);
if (ret < 0)
return ret;
@@ -1178,7 +1178,6 @@ static int snd_sscape_probe(struct device *pdev, unsigned int dev)
sscape->type = SSCAPE;
dma[dev] &= 0x03;
- snd_card_set_dev(card, pdev);
ret = create_sscape(dev, card);
if (ret < 0)
@@ -1259,8 +1258,9 @@ static int sscape_pnp_detect(struct pnp_card_link *pcard,
* Create a new ALSA sound card entry, in anticipation
* of detecting our hardware ...
*/
- ret = snd_card_create(index[idx], id[idx], THIS_MODULE,
- sizeof(struct soundscape), &card);
+ ret = snd_card_new(&pcard->card->dev,
+ index[idx], id[idx], THIS_MODULE,
+ sizeof(struct soundscape), &card);
if (ret < 0)
return ret;
@@ -1288,7 +1288,6 @@ static int sscape_pnp_detect(struct pnp_card_link *pcard,
wss_port[idx] = pnp_port_start(dev, 1);
dma2[idx] = pnp_dma(dev, 1);
}
- snd_card_set_dev(card, &pcard->card->dev);
ret = create_sscape(idx, card);
if (ret < 0)
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index 82dd76939fa0..bfbf38cf9841 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -334,14 +334,15 @@ snd_wavefront_free(struct snd_card *card)
}
}
-static int snd_wavefront_card_new(int dev, struct snd_card **cardp)
+static int snd_wavefront_card_new(struct device *pdev, int dev,
+ struct snd_card **cardp)
{
struct snd_card *card;
snd_wavefront_card_t *acard;
int err;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(snd_wavefront_card_t), &card);
+ err = snd_card_new(pdev, index[dev], id[dev], THIS_MODULE,
+ sizeof(snd_wavefront_card_t), &card);
if (err < 0)
return err;
@@ -564,10 +565,9 @@ static int snd_wavefront_isa_probe(struct device *pdev,
struct snd_card *card;
int err;
- err = snd_wavefront_card_new(dev, &card);
+ err = snd_wavefront_card_new(pdev, dev, &card);
if (err < 0)
return err;
- snd_card_set_dev(card, pdev);
if ((err = snd_wavefront_probe(card, dev)) < 0) {
snd_card_free(card);
return err;
@@ -612,7 +612,7 @@ static int snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- res = snd_wavefront_card_new(dev, &card);
+ res = snd_wavefront_card_new(&pcard->card->dev, dev, &card);
if (res < 0)
return res;
@@ -623,7 +623,6 @@ static int snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
return -ENODEV;
}
}
- snd_card_set_dev(card, &pcard->card->dev);
if ((res = snd_wavefront_probe(card, dev)) < 0)
return res;
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c
index 224f54be15a6..a7cc49e96068 100644
--- a/sound/mips/au1x00.c
+++ b/sound/mips/au1x00.c
@@ -37,6 +37,7 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
@@ -98,6 +99,7 @@ struct snd_au1000 {
struct snd_pcm *pcm;
struct audio_stream *stream[2]; /* playback & capture */
+ int dmaid[2]; /* tx(0)/rx(1) DMA ids */
};
/*--------------------------- Local Functions --------------------------------*/
@@ -465,15 +467,17 @@ snd_au1000_pcm_new(struct snd_au1000 *au1000)
spin_lock_init(&au1000->stream[CAPTURE]->dma_lock);
flags = claim_dma_lock();
- if ((au1000->stream[PLAYBACK]->dma = request_au1000_dma(DMA_ID_AC97C_TX,
+ au1000->stream[PLAYBACK]->dma = request_au1000_dma(au1000->dmaid[0],
"AC97 TX", au1000_dma_interrupt, 0,
- au1000->stream[PLAYBACK])) < 0) {
+ au1000->stream[PLAYBACK]);
+ if (au1000->stream[PLAYBACK]->dma < 0) {
release_dma_lock(flags);
return -EBUSY;
}
- if ((au1000->stream[CAPTURE]->dma = request_au1000_dma(DMA_ID_AC97C_RX,
+ au1000->stream[CAPTURE]->dma = request_au1000_dma(au1000->dmaid[1],
"AC97 RX", au1000_dma_interrupt, 0,
- au1000->stream[CAPTURE])) < 0){
+ au1000->stream[CAPTURE]);
+ if (au1000->stream[CAPTURE]->dma < 0){
release_dma_lock(flags);
return -EBUSY;
}
@@ -552,69 +556,12 @@ get the interrupt driven case to work efficiently */
spin_unlock(&au1000->ac97_lock);
}
-static int
-snd_au1000_ac97_new(struct snd_au1000 *au1000)
-{
- int err;
- struct snd_ac97_bus *pbus;
- struct snd_ac97_template ac97;
- static struct snd_ac97_bus_ops ops = {
- .write = snd_au1000_ac97_write,
- .read = snd_au1000_ac97_read,
- };
-
- if ((au1000->ac97_res_port = request_mem_region(CPHYSADDR(AC97C_CONFIG),
- 0x100000, "Au1x00 AC97")) == NULL) {
- snd_printk(KERN_ERR "ALSA AC97: can't grap AC97 port\n");
- return -EBUSY;
- }
- au1000->ac97_ioport = (struct au1000_ac97_reg *)
- KSEG1ADDR(au1000->ac97_res_port->start);
-
- spin_lock_init(&au1000->ac97_lock);
-
- /* configure pins for AC'97
- TODO: move to board_setup.c */
- au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC);
-
- /* Initialise Au1000's AC'97 Control Block */
- au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE;
- udelay(10);
- au1000->ac97_ioport->cntrl = AC97C_CE;
- udelay(10);
-
- /* Initialise External CODEC -- cold reset */
- au1000->ac97_ioport->config = AC97C_RESET;
- udelay(10);
- au1000->ac97_ioport->config = 0x0;
- mdelay(5);
-
- /* Initialise AC97 middle-layer */
- if ((err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus)) < 0)
- return err;
-
- memset(&ac97, 0, sizeof(ac97));
- ac97.private_data = au1000;
- if ((err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97)) < 0)
- return err;
-
- return 0;
-}
-
/*------------------------------ Setup / Destroy ----------------------------*/
-void
-snd_au1000_free(struct snd_card *card)
+static void snd_au1000_free(struct snd_card *card)
{
struct snd_au1000 *au1000 = card->private_data;
- if (au1000->ac97_res_port) {
- /* put internal AC97 block into reset */
- au1000->ac97_ioport->cntrl = AC97C_RS;
- au1000->ac97_ioport = NULL;
- release_and_free_resource(au1000->ac97_res_port);
- }
-
if (au1000->stream[PLAYBACK]) {
if (au1000->stream[PLAYBACK]->dma >= 0)
free_au1000_dma(au1000->stream[PLAYBACK]->dma);
@@ -626,71 +573,167 @@ snd_au1000_free(struct snd_card *card)
free_au1000_dma(au1000->stream[CAPTURE]->dma);
kfree(au1000->stream[CAPTURE]);
}
-}
+ if (au1000->ac97_res_port) {
+ /* put internal AC97 block into reset */
+ if (au1000->ac97_ioport) {
+ au1000->ac97_ioport->cntrl = AC97C_RS;
+ iounmap(au1000->ac97_ioport);
+ au1000->ac97_ioport = NULL;
+ }
+ release_and_free_resource(au1000->ac97_res_port);
+ au1000->ac97_res_port = NULL;
+ }
+}
-static struct snd_card *au1000_card;
+static struct snd_ac97_bus_ops ops = {
+ .write = snd_au1000_ac97_write,
+ .read = snd_au1000_ac97_read,
+};
-static int __init
-au1000_init(void)
+static int au1000_ac97_probe(struct platform_device *pdev)
{
int err;
+ void __iomem *io;
+ struct resource *r;
struct snd_card *card;
struct snd_au1000 *au1000;
+ struct snd_ac97_bus *pbus;
+ struct snd_ac97_template ac97;
- err = snd_card_create(-1, "AC97", THIS_MODULE,
- sizeof(struct snd_au1000), &card);
+ err = snd_card_new(&pdev->dev, -1, "AC97", THIS_MODULE,
+ sizeof(struct snd_au1000), &card);
if (err < 0)
return err;
- card->private_free = snd_au1000_free;
au1000 = card->private_data;
au1000->card = card;
+ spin_lock_init(&au1000->ac97_lock);
- au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL);
- au1000->stream[CAPTURE ] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL);
- /* so that snd_au1000_free will work as intended */
- au1000->ac97_res_port = NULL;
- if (au1000->stream[PLAYBACK])
- au1000->stream[PLAYBACK]->dma = -1;
- if (au1000->stream[CAPTURE ])
- au1000->stream[CAPTURE ]->dma = -1;
-
- if (au1000->stream[PLAYBACK] == NULL ||
- au1000->stream[CAPTURE ] == NULL) {
- snd_card_free(card);
- return -ENOMEM;
- }
+ /* from here on let ALSA call the special freeing function */
+ card->private_free = snd_au1000_free;
- if ((err = snd_au1000_ac97_new(au1000)) < 0 ) {
- snd_card_free(card);
- return err;
+ /* TX DMA ID */
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!r) {
+ err = -ENODEV;
+ snd_printk(KERN_INFO "no TX DMA platform resource!\n");
+ goto out;
}
-
- if ((err = snd_au1000_pcm_new(au1000)) < 0) {
- snd_card_free(card);
- return err;
+ au1000->dmaid[0] = r->start;
+
+ /* RX DMA ID */
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!r) {
+ err = -ENODEV;
+ snd_printk(KERN_INFO "no RX DMA platform resource!\n");
+ goto out;
+ }
+ au1000->dmaid[1] = r->start;
+
+ au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream),
+ GFP_KERNEL);
+ if (!au1000->stream[PLAYBACK])
+ goto out;
+ au1000->stream[PLAYBACK]->dma = -1;
+
+ au1000->stream[CAPTURE] = kmalloc(sizeof(struct audio_stream),
+ GFP_KERNEL);
+ if (!au1000->stream[CAPTURE])
+ goto out;
+ au1000->stream[CAPTURE]->dma = -1;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r)
+ goto out;
+
+ err = -EBUSY;
+ au1000->ac97_res_port = request_mem_region(r->start,
+ r->end - r->start + 1, pdev->name);
+ if (!au1000->ac97_res_port) {
+ snd_printk(KERN_ERR "ALSA AC97: can't grab AC97 port\n");
+ goto out;
}
+ io = ioremap(r->start, r->end - r->start + 1);
+ if (!io)
+ goto out;
+
+ au1000->ac97_ioport = (struct au1000_ac97_reg *)io;
+
+ /* configure pins for AC'97
+ TODO: move to board_setup.c */
+ au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC);
+
+ /* Initialise Au1000's AC'97 Control Block */
+ au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE;
+ udelay(10);
+ au1000->ac97_ioport->cntrl = AC97C_CE;
+ udelay(10);
+
+ /* Initialise External CODEC -- cold reset */
+ au1000->ac97_ioport->config = AC97C_RESET;
+ udelay(10);
+ au1000->ac97_ioport->config = 0x0;
+ mdelay(5);
+
+ /* Initialise AC97 middle-layer */
+ err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus);
+ if (err < 0)
+ goto out;
+
+ memset(&ac97, 0, sizeof(ac97));
+ ac97.private_data = au1000;
+ err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97);
+ if (err < 0)
+ goto out;
+
+ err = snd_au1000_pcm_new(au1000);
+ if (err < 0)
+ goto out;
+
strcpy(card->driver, "Au1000-AC97");
strcpy(card->shortname, "AMD Au1000-AC97");
sprintf(card->longname, "AMD Au1000--AC97 ALSA Driver");
- if ((err = snd_card_register(card)) < 0) {
- snd_card_free(card);
- return err;
- }
+ err = snd_card_register(card);
+ if (err < 0)
+ goto out;
printk(KERN_INFO "ALSA AC97: Driver Initialized\n");
- au1000_card = card;
+
+ platform_set_drvdata(pdev, card);
+
return 0;
+
+ out:
+ snd_card_free(card);
+ return err;
+}
+
+static int au1000_ac97_remove(struct platform_device *pdev)
+{
+ return snd_card_free(platform_get_drvdata(pdev));
}
-static void __exit au1000_exit(void)
+struct platform_driver au1000_ac97c_driver = {
+ .driver = {
+ .name = "au1000-ac97c",
+ .owner = THIS_MODULE,
+ },
+ .probe = au1000_ac97_probe,
+ .remove = au1000_ac97_remove,
+};
+
+static int __init au1000_ac97_load(void)
{
- snd_card_free(au1000_card);
+ return platform_driver_register(&au1000_ac97c_driver);
}
-module_init(au1000_init);
-module_exit(au1000_exit);
+static void __exit au1000_ac97_unload(void)
+{
+ platform_driver_unregister(&au1000_ac97c_driver);
+}
+module_init(au1000_ac97_load);
+module_exit(au1000_ac97_unload);
diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c
index 2b7f6e8bdd24..23441b9e6148 100644
--- a/sound/mips/hal2.c
+++ b/sound/mips/hal2.c
@@ -880,7 +880,7 @@ static int hal2_probe(struct platform_device *pdev)
struct snd_hal2 *chip;
int err;
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pdev->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -889,7 +889,6 @@ static int hal2_probe(struct platform_device *pdev)
snd_card_free(card);
return err;
}
- snd_card_set_dev(card, &pdev->dev);
err = hal2_pcm_create(chip);
if (err < 0) {
diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c
index cfe99ae149fe..04bb06c03ec8 100644
--- a/sound/mips/sgio2audio.c
+++ b/sound/mips/sgio2audio.c
@@ -920,7 +920,7 @@ static int snd_sgio2audio_probe(struct platform_device *pdev)
struct snd_sgio2audio *chip;
int err;
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pdev->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -929,7 +929,6 @@ static int snd_sgio2audio_probe(struct platform_device *pdev)
snd_card_free(card);
return err;
}
- snd_card_set_dev(card, &pdev->dev);
err = snd_sgio2audio_new_pcm(chip);
if (err < 0) {
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 1a9640254433..48568fdf847f 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -13,15 +13,6 @@ config SOUND_BCM_CS4297A
note that CONFIG_KGDB should not be enabled at the same
time, since it also attempts to use this UART port.
-config SOUND_VWSND
- tristate "SGI Visual Workstation Sound"
- depends on X86_VISWS
- help
- Say Y or M if you have an SGI Visual Workstation and you want to be
- able to use its on-board audio. Read
- <file:Documentation/sound/oss/vwsnd> for more info on this driver's
- capabilities.
-
config SOUND_MSNDCLAS
tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
depends on (m || !STANDALONE) && ISA
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index 77f21b68bf0f..9bdbbde2173e 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -24,7 +24,6 @@ obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o
obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o
obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
-obj-$(CONFIG_SOUND_VWSND) += vwsnd.o
obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o
obj-$(CONFIG_DMASOUND) += dmasound/
diff --git a/sound/oss/pas2.h b/sound/oss/pas2.h
index fa12c55f560e..d19f757dbd79 100644
--- a/sound/oss/pas2.h
+++ b/sound/oss/pas2.h
@@ -15,3 +15,6 @@ int pas_init_mixer(void);
/* From pas_midi.c */
void pas_midi_init(void);
void pas_midi_interrupt(void);
+
+/* From pas2_mixer.c*/
+void mix_write(unsigned char data, int ioaddr);
diff --git a/sound/oss/pas2_card.c b/sound/oss/pas2_card.c
index 7004e24d209f..b07954a79536 100644
--- a/sound/oss/pas2_card.c
+++ b/sound/oss/pas2_card.c
@@ -74,8 +74,6 @@ static char *pas_model_names[] = {
* to support other than the default base address
*/
-extern void mix_write(unsigned char data, int ioaddr);
-
unsigned char pas_read(int ioaddr)
{
return inb(ioaddr + pas_translate_code);
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c
deleted file mode 100644
index a077e9c69a5e..000000000000
--- a/sound/oss/vwsnd.c
+++ /dev/null
@@ -1,3506 +0,0 @@
-/*
- * Sound driver for Silicon Graphics 320 and 540 Visual Workstations'
- * onboard audio. See notes in Documentation/sound/oss/vwsnd .
- *
- * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#undef VWSND_DEBUG /* define for debugging */
-
-/*
- * XXX to do -
- *
- * External sync.
- * Rename swbuf, hwbuf, u&i, hwptr&swptr to something rational.
- * Bug - if select() called before read(), pcm_setup() not called.
- * Bug - output doesn't stop soon enough if process killed.
- */
-
-/*
- * Things to test -
- *
- * Will readv/writev work? Write a test.
- *
- * insmod/rmmod 100 million times.
- *
- * Run I/O until int ptrs wrap around (roughly 6.2 hours @ DAT
- * rate).
- *
- * Concurrent threads banging on mixer simultaneously, both UP
- * and SMP kernels. Especially, watch for thread A changing
- * OUTSRC while thread B changes gain -- both write to the same
- * ad1843 register.
- *
- * What happens if a client opens /dev/audio then forks?
- * Do two procs have /dev/audio open? Test.
- *
- * Pump audio through the CD, MIC and line inputs and verify that
- * they mix/mute into the output.
- *
- * Apps:
- * amp
- * mpg123
- * x11amp
- * mxv
- * kmedia
- * esound
- * need more input apps
- *
- * Run tests while bombarding with signals. setitimer(2) will do it... */
-
-/*
- * This driver is organized in nine sections.
- * The nine sections are:
- *
- * debug stuff
- * low level lithium access
- * high level lithium access
- * AD1843 access
- * PCM I/O
- * audio driver
- * mixer driver
- * probe/attach/unload
- * initialization and loadable kernel module interface
- *
- * That is roughly the order of increasing abstraction, so forward
- * dependencies are minimal.
- */
-
-/*
- * Locking Notes
- *
- * INC_USE_COUNT and DEC_USE_COUNT keep track of the number of
- * open descriptors to this driver. They store it in vwsnd_use_count.
- * The global device list, vwsnd_dev_list, is immutable when the IN_USE
- * is true.
- *
- * devc->open_lock is a semaphore that is used to enforce the
- * single reader/single writer rule for /dev/audio. The rule is
- * that each device may have at most one reader and one writer.
- * Open will block until the previous client has closed the
- * device, unless O_NONBLOCK is specified.
- *
- * The semaphore devc->io_mutex serializes PCM I/O syscalls. This
- * is unnecessary in Linux 2.2, because the kernel lock
- * serializes read, write, and ioctl globally, but it's there,
- * ready for the brave, new post-kernel-lock world.
- *
- * Locking between interrupt and baselevel is handled by the
- * "lock" spinlock in vwsnd_port (one lock each for read and
- * write). Each half holds the lock just long enough to see what
- * area it owns and update its pointers. See pcm_output() and
- * pcm_input() for most of the gory stuff.
- *
- * devc->mix_mutex serializes all mixer ioctls. This is also
- * redundant because of the kernel lock.
- *
- * The lowest level lock is lith->lithium_lock. It is a
- * spinlock which is held during the two-register tango of
- * reading/writing an AD1843 register. See
- * li_{read,write}_ad1843_reg().
- */
-
-/*
- * Sample Format Notes
- *
- * Lithium's DMA engine has two formats: 16-bit 2's complement
- * and 8-bit unsigned . 16-bit transfers the data unmodified, 2
- * bytes per sample. 8-bit unsigned transfers 1 byte per sample
- * and XORs each byte with 0x80. Lithium can input or output
- * either mono or stereo in either format.
- *
- * The AD1843 has four formats: 16-bit 2's complement, 8-bit
- * unsigned, 8-bit mu-Law and 8-bit A-Law.
- *
- * This driver supports five formats: AFMT_S8, AFMT_U8,
- * AFMT_MU_LAW, AFMT_A_LAW, and AFMT_S16_LE.
- *
- * For AFMT_U8 output, we keep the AD1843 in 16-bit mode, and
- * rely on Lithium's XOR to translate between U8 and S8.
- *
- * For AFMT_S8, AFMT_MU_LAW and AFMT_A_LAW output, we have to XOR
- * the 0x80 bit in software to compensate for Lithium's XOR.
- * This happens in pcm_copy_{in,out}().
- *
- * Changes:
- * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- * Added some __init/__exit
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/spinlock.h>
-#include <linux/wait.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-
-#include <asm/visws/cobalt.h>
-
-#include "sound_config.h"
-
-static DEFINE_MUTEX(vwsnd_mutex);
-
-/*****************************************************************************/
-/* debug stuff */
-
-#ifdef VWSND_DEBUG
-
-static int shut_up = 1;
-
-/*
- * dbgassert - called when an assertion fails.
- */
-
-static void dbgassert(const char *fcn, int line, const char *expr)
-{
- if (in_interrupt())
- panic("ASSERTION FAILED IN INTERRUPT, %s:%s:%d %s\n",
- __FILE__, fcn, line, expr);
- else {
- int x;
- printk(KERN_ERR "ASSERTION FAILED, %s:%s:%d %s\n",
- __FILE__, fcn, line, expr);
- x = * (volatile int *) 0; /* force proc to exit */
- }
-}
-
-/*
- * Bunch of useful debug macros:
- *
- * ASSERT - print unless e nonzero (panic if in interrupt)
- * DBGDO - include arbitrary code if debugging
- * DBGX - debug print raw (w/o function name)
- * DBGP - debug print w/ function name
- * DBGE - debug print function entry
- * DBGC - debug print function call
- * DBGR - debug print function return
- * DBGXV - debug print raw when verbose
- * DBGPV - debug print when verbose
- * DBGEV - debug print function entry when verbose
- * DBGRV - debug print function return when verbose
- */
-
-#define ASSERT(e) ((e) ? (void) 0 : dbgassert(__func__, __LINE__, #e))
-#define DBGDO(x) x
-#define DBGX(fmt, args...) (in_interrupt() ? 0 : printk(KERN_ERR fmt, ##args))
-#define DBGP(fmt, args...) (DBGX("%s: " fmt, __func__ , ##args))
-#define DBGE(fmt, args...) (DBGX("%s" fmt, __func__ , ##args))
-#define DBGC(rtn) (DBGP("calling %s\n", rtn))
-#define DBGR() (DBGP("returning\n"))
-#define DBGXV(fmt, args...) (shut_up ? 0 : DBGX(fmt, ##args))
-#define DBGPV(fmt, args...) (shut_up ? 0 : DBGP(fmt, ##args))
-#define DBGEV(fmt, args...) (shut_up ? 0 : DBGE(fmt, ##args))
-#define DBGCV(rtn) (shut_up ? 0 : DBGC(rtn))
-#define DBGRV() (shut_up ? 0 : DBGR())
-
-#else /* !VWSND_DEBUG */
-
-#define ASSERT(e) ((void) 0)
-#define DBGDO(x) /* don't */
-#define DBGX(fmt, args...) ((void) 0)
-#define DBGP(fmt, args...) ((void) 0)
-#define DBGE(fmt, args...) ((void) 0)
-#define DBGC(rtn) ((void) 0)
-#define DBGR() ((void) 0)
-#define DBGPV(fmt, args...) ((void) 0)
-#define DBGXV(fmt, args...) ((void) 0)
-#define DBGEV(fmt, args...) ((void) 0)
-#define DBGCV(rtn) ((void) 0)
-#define DBGRV() ((void) 0)
-
-#endif /* !VWSND_DEBUG */
-
-/*****************************************************************************/
-/* low level lithium access */
-
-/*
- * We need to talk to Lithium registers on three pages. Here are
- * the pages' offsets from the base address (0xFF001000).
- */
-
-enum {
- LI_PAGE0_OFFSET = 0x01000 - 0x1000, /* FF001000 */
- LI_PAGE1_OFFSET = 0x0F000 - 0x1000, /* FF00F000 */
- LI_PAGE2_OFFSET = 0x10000 - 0x1000, /* FF010000 */
-};
-
-/* low-level lithium data */
-
-typedef struct lithium {
- void * page0; /* virtual addresses */
- void * page1;
- void * page2;
- spinlock_t lock; /* protects codec and UST/MSC access */
-} lithium_t;
-
-/*
- * li_destroy destroys the lithium_t structure and vm mappings.
- */
-
-static void li_destroy(lithium_t *lith)
-{
- if (lith->page0) {
- iounmap(lith->page0);
- lith->page0 = NULL;
- }
- if (lith->page1) {
- iounmap(lith->page1);
- lith->page1 = NULL;
- }
- if (lith->page2) {
- iounmap(lith->page2);
- lith->page2 = NULL;
- }
-}
-
-/*
- * li_create initializes the lithium_t structure and sets up vm mappings
- * to access the registers.
- * Returns 0 on success, -errno on failure.
- */
-
-static int __init li_create(lithium_t *lith, unsigned long baseaddr)
-{
- spin_lock_init(&lith->lock);
- lith->page0 = ioremap_nocache(baseaddr + LI_PAGE0_OFFSET, PAGE_SIZE);
- lith->page1 = ioremap_nocache(baseaddr + LI_PAGE1_OFFSET, PAGE_SIZE);
- lith->page2 = ioremap_nocache(baseaddr + LI_PAGE2_OFFSET, PAGE_SIZE);
- if (!lith->page0 || !lith->page1 || !lith->page2) {
- li_destroy(lith);
- return -ENOMEM;
- }
- return 0;
-}
-
-/*
- * basic register accessors - read/write long/byte
- */
-
-static __inline__ unsigned long li_readl(lithium_t *lith, int off)
-{
- return * (volatile unsigned long *) (lith->page0 + off);
-}
-
-static __inline__ unsigned char li_readb(lithium_t *lith, int off)
-{
- return * (volatile unsigned char *) (lith->page0 + off);
-}
-
-static __inline__ void li_writel(lithium_t *lith, int off, unsigned long val)
-{
- * (volatile unsigned long *) (lith->page0 + off) = val;
-}
-
-static __inline__ void li_writeb(lithium_t *lith, int off, unsigned char val)
-{
- * (volatile unsigned char *) (lith->page0 + off) = val;
-}
-
-/*****************************************************************************/
-/* High Level Lithium Access */
-
-/*
- * Lithium DMA Notes
- *
- * Lithium has two dedicated DMA channels for audio. They are known
- * as comm1 and comm2 (communication areas 1 and 2). Comm1 is for
- * input, and comm2 is for output. Each is controlled by three
- * registers: BASE (base address), CFG (config) and CCTL
- * (config/control).
- *
- * Each DMA channel points to a physically contiguous ring buffer in
- * main memory of up to 8 Kbytes. (This driver always uses 8 Kb.)
- * There are three pointers into the ring buffer: read, write, and
- * trigger. The pointers are 8 bits each. Each pointer points to
- * 32-byte "chunks" of data. The DMA engine moves 32 bytes at a time,
- * so there is no finer-granularity control.
- *
- * In comm1, the hardware updates the write ptr, and software updates
- * the read ptr. In comm2, it's the opposite: hardware updates the
- * read ptr, and software updates the write ptr. I designate the
- * hardware-updated ptr as the hwptr, and the software-updated ptr as
- * the swptr.
- *
- * The trigger ptr and trigger mask are used to trigger interrupts.
- * From the Lithium spec, section 5.6.8, revision of 12/15/1998:
- *
- * Trigger Mask Value
- *
- * A three bit wide field that represents a power of two mask
- * that is used whenever the trigger pointer is compared to its
- * respective read or write pointer. A value of zero here
- * implies a mask of 0xFF and a value of seven implies a mask
- * 0x01. This value can be used to sub-divide the ring buffer
- * into pie sections so that interrupts monitor the progress of
- * hardware from section to section.
- *
- * My interpretation of that is, whenever the hw ptr is updated, it is
- * compared with the trigger ptr, and the result is masked by the
- * trigger mask. (Actually, by the complement of the trigger mask.)
- * If the result is zero, an interrupt is triggered. I.e., interrupt
- * if ((hwptr & ~mask) == (trptr & ~mask)). The mask is formed from
- * the trigger register value as mask = (1 << (8 - tmreg)) - 1.
- *
- * In yet different words, setting tmreg to 0 causes an interrupt after
- * every 256 DMA chunks (8192 bytes) or once per traversal of the
- * ring buffer. Setting it to 7 caues an interrupt every 2 DMA chunks
- * (64 bytes) or 128 times per traversal of the ring buffer.
- */
-
-/* Lithium register offsets and bit definitions */
-
-#define LI_HOST_CONTROLLER 0x000
-# define LI_HC_RESET 0x00008000
-# define LI_HC_LINK_ENABLE 0x00004000
-# define LI_HC_LINK_FAILURE 0x00000004
-# define LI_HC_LINK_CODEC 0x00000002
-# define LI_HC_LINK_READY 0x00000001
-
-#define LI_INTR_STATUS 0x010
-#define LI_INTR_MASK 0x014
-# define LI_INTR_LINK_ERR 0x00008000
-# define LI_INTR_COMM2_TRIG 0x00000008
-# define LI_INTR_COMM2_UNDERFLOW 0x00000004
-# define LI_INTR_COMM1_TRIG 0x00000002
-# define LI_INTR_COMM1_OVERFLOW 0x00000001
-
-#define LI_CODEC_COMMAND 0x018
-# define LI_CC_BUSY 0x00008000
-# define LI_CC_DIR 0x00000080
-# define LI_CC_DIR_RD LI_CC_DIR
-# define LI_CC_DIR_WR (!LI_CC_DIR)
-# define LI_CC_ADDR_MASK 0x0000007F
-
-#define LI_CODEC_DATA 0x01C
-
-#define LI_COMM1_BASE 0x100
-#define LI_COMM1_CTL 0x104
-# define LI_CCTL_RESET 0x80000000
-# define LI_CCTL_SIZE 0x70000000
-# define LI_CCTL_DMA_ENABLE 0x08000000
-# define LI_CCTL_TMASK 0x07000000 /* trigger mask */
-# define LI_CCTL_TPTR 0x00FF0000 /* trigger pointer */
-# define LI_CCTL_RPTR 0x0000FF00
-# define LI_CCTL_WPTR 0x000000FF
-#define LI_COMM1_CFG 0x108
-# define LI_CCFG_LOCK 0x00008000
-# define LI_CCFG_SLOT 0x00000070
-# define LI_CCFG_DIRECTION 0x00000008
-# define LI_CCFG_DIR_IN (!LI_CCFG_DIRECTION)
-# define LI_CCFG_DIR_OUT LI_CCFG_DIRECTION
-# define LI_CCFG_MODE 0x00000004
-# define LI_CCFG_MODE_MONO (!LI_CCFG_MODE)
-# define LI_CCFG_MODE_STEREO LI_CCFG_MODE
-# define LI_CCFG_FORMAT 0x00000003
-# define LI_CCFG_FMT_8BIT 0x00000000
-# define LI_CCFG_FMT_16BIT 0x00000001
-#define LI_COMM2_BASE 0x10C
-#define LI_COMM2_CTL 0x110
- /* bit definitions are the same as LI_COMM1_CTL */
-#define LI_COMM2_CFG 0x114
- /* bit definitions are the same as LI_COMM1_CFG */
-
-#define LI_UST_LOW 0x200 /* 64-bit Unadjusted System Time is */
-#define LI_UST_HIGH 0x204 /* microseconds since boot */
-
-#define LI_AUDIO1_UST 0x300 /* UST-MSC pairs */
-#define LI_AUDIO1_MSC 0x304 /* MSC (Media Stream Counter) */
-#define LI_AUDIO2_UST 0x308 /* counts samples actually */
-#define LI_AUDIO2_MSC 0x30C /* processed as of time UST */
-
-/*
- * Lithium's DMA engine operates on chunks of 32 bytes. We call that
- * a DMACHUNK.
- */
-
-#define DMACHUNK_SHIFT 5
-#define DMACHUNK_SIZE (1 << DMACHUNK_SHIFT)
-#define BYTES_TO_CHUNKS(bytes) ((bytes) >> DMACHUNK_SHIFT)
-#define CHUNKS_TO_BYTES(chunks) ((chunks) << DMACHUNK_SHIFT)
-
-/*
- * Two convenient macros to shift bitfields into/out of position.
- *
- * Observe that (mask & -mask) is (1 << low_set_bit_of(mask)).
- * As long as mask is constant, we trust the compiler will change the
- * multiply and divide into shifts.
- */
-
-#define SHIFT_FIELD(val, mask) (((val) * ((mask) & -(mask))) & (mask))
-#define UNSHIFT_FIELD(val, mask) (((val) & (mask)) / ((mask) & -(mask)))
-
-/*
- * dma_chan_desc is invariant information about a Lithium
- * DMA channel. There are two instances, li_comm1 and li_comm2.
- *
- * Note that the CCTL register fields are write ptr and read ptr, but what
- * we care about are which pointer is updated by software and which by
- * hardware.
- */
-
-typedef struct dma_chan_desc {
- int basereg;
- int cfgreg;
- int ctlreg;
- int hwptrreg;
- int swptrreg;
- int ustreg;
- int mscreg;
- unsigned long swptrmask;
- int ad1843_slot;
- int direction; /* LI_CCTL_DIR_IN/OUT */
-} dma_chan_desc_t;
-
-static const dma_chan_desc_t li_comm1 = {
- LI_COMM1_BASE, /* base register offset */
- LI_COMM1_CFG, /* config register offset */
- LI_COMM1_CTL, /* control register offset */
- LI_COMM1_CTL + 0, /* hw ptr reg offset (write ptr) */
- LI_COMM1_CTL + 1, /* sw ptr reg offset (read ptr) */
- LI_AUDIO1_UST, /* ust reg offset */
- LI_AUDIO1_MSC, /* msc reg offset */
- LI_CCTL_RPTR, /* sw ptr bitmask in ctlval */
- 2, /* ad1843 serial slot */
- LI_CCFG_DIR_IN /* direction */
-};
-
-static const dma_chan_desc_t li_comm2 = {
- LI_COMM2_BASE, /* base register offset */
- LI_COMM2_CFG, /* config register offset */
- LI_COMM2_CTL, /* control register offset */
- LI_COMM2_CTL + 1, /* hw ptr reg offset (read ptr) */
- LI_COMM2_CTL + 0, /* sw ptr reg offset (writr ptr) */
- LI_AUDIO2_UST, /* ust reg offset */
- LI_AUDIO2_MSC, /* msc reg offset */
- LI_CCTL_WPTR, /* sw ptr bitmask in ctlval */
- 2, /* ad1843 serial slot */
- LI_CCFG_DIR_OUT /* direction */
-};
-
-/*
- * dma_chan is variable information about a Lithium DMA channel.
- *
- * The desc field points to invariant information.
- * The lith field points to a lithium_t which is passed
- * to li_read* and li_write* to access the registers.
- * The *val fields shadow the lithium registers' contents.
- */
-
-typedef struct dma_chan {
- const dma_chan_desc_t *desc;
- lithium_t *lith;
- unsigned long baseval;
- unsigned long cfgval;
- unsigned long ctlval;
-} dma_chan_t;
-
-/*
- * ustmsc is a UST/MSC pair (Unadjusted System Time/Media Stream Counter).
- * UST is time in microseconds since the system booted, and MSC is a
- * counter that increments with every audio sample.
- */
-
-typedef struct ustmsc {
- unsigned long long ust;
- unsigned long msc;
-} ustmsc_t;
-
-/*
- * li_ad1843_wait waits until lithium says the AD1843 register
- * exchange is not busy. Returns 0 on success, -EBUSY on timeout.
- *
- * Locking: must be called with lithium_lock held.
- */
-
-static int li_ad1843_wait(lithium_t *lith)
-{
- unsigned long later = jiffies + 2;
- while (li_readl(lith, LI_CODEC_COMMAND) & LI_CC_BUSY)
- if (time_after_eq(jiffies, later))
- return -EBUSY;
- return 0;
-}
-
-/*
- * li_read_ad1843_reg returns the current contents of a 16 bit AD1843 register.
- *
- * Returns unsigned register value on success, -errno on failure.
- */
-
-static int li_read_ad1843_reg(lithium_t *lith, int reg)
-{
- int val;
-
- ASSERT(!in_interrupt());
- spin_lock(&lith->lock);
- {
- val = li_ad1843_wait(lith);
- if (val == 0) {
- li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_RD | reg);
- val = li_ad1843_wait(lith);
- }
- if (val == 0)
- val = li_readl(lith, LI_CODEC_DATA);
- }
- spin_unlock(&lith->lock);
-
- DBGXV("li_read_ad1843_reg(lith=0x%p, reg=%d) returns 0x%04x\n",
- lith, reg, val);
-
- return val;
-}
-
-/*
- * li_write_ad1843_reg writes the specified value to a 16 bit AD1843 register.
- */
-
-static void li_write_ad1843_reg(lithium_t *lith, int reg, int newval)
-{
- spin_lock(&lith->lock);
- {
- if (li_ad1843_wait(lith) == 0) {
- li_writel(lith, LI_CODEC_DATA, newval);
- li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_WR | reg);
- }
- }
- spin_unlock(&lith->lock);
-}
-
-/*
- * li_setup_dma calculates all the register settings for DMA in a particular
- * mode. It takes too many arguments.
- */
-
-static void li_setup_dma(dma_chan_t *chan,
- const dma_chan_desc_t *desc,
- lithium_t *lith,
- unsigned long buffer_paddr,
- int bufshift,
- int fragshift,
- int channels,
- int sampsize)
-{
- unsigned long mode, format;
- unsigned long size, tmask;
-
- DBGEV("(chan=0x%p, desc=0x%p, lith=0x%p, buffer_paddr=0x%lx, "
- "bufshift=%d, fragshift=%d, channels=%d, sampsize=%d)\n",
- chan, desc, lith, buffer_paddr,
- bufshift, fragshift, channels, sampsize);
-
- /* Reset the channel first. */
-
- li_writel(lith, desc->ctlreg, LI_CCTL_RESET);
-
- ASSERT(channels == 1 || channels == 2);
- if (channels == 2)
- mode = LI_CCFG_MODE_STEREO;
- else
- mode = LI_CCFG_MODE_MONO;
- ASSERT(sampsize == 1 || sampsize == 2);
- if (sampsize == 2)
- format = LI_CCFG_FMT_16BIT;
- else
- format = LI_CCFG_FMT_8BIT;
- chan->desc = desc;
- chan->lith = lith;
-
- /*
- * Lithium DMA address register takes a 40-bit physical
- * address, right-shifted by 8 so it fits in 32 bits. Bit 37
- * must be set -- it enables cache coherence.
- */
-
- ASSERT(!(buffer_paddr & 0xFF));
- chan->baseval = (buffer_paddr >> 8) | 1 << (37 - 8);
-
- chan->cfgval = ((chan->cfgval & ~LI_CCFG_LOCK) |
- SHIFT_FIELD(desc->ad1843_slot, LI_CCFG_SLOT) |
- desc->direction |
- mode |
- format);
-
- size = bufshift - 6;
- tmask = 13 - fragshift; /* See Lithium DMA Notes above. */
- ASSERT(size >= 2 && size <= 7);
- ASSERT(tmask >= 1 && tmask <= 7);
- chan->ctlval = ((chan->ctlval & ~LI_CCTL_RESET) |
- SHIFT_FIELD(size, LI_CCTL_SIZE) |
- (chan->ctlval & ~LI_CCTL_DMA_ENABLE) |
- SHIFT_FIELD(tmask, LI_CCTL_TMASK) |
- SHIFT_FIELD(0, LI_CCTL_TPTR));
-
- DBGPV("basereg 0x%x = 0x%lx\n", desc->basereg, chan->baseval);
- DBGPV("cfgreg 0x%x = 0x%lx\n", desc->cfgreg, chan->cfgval);
- DBGPV("ctlreg 0x%x = 0x%lx\n", desc->ctlreg, chan->ctlval);
-
- li_writel(lith, desc->basereg, chan->baseval);
- li_writel(lith, desc->cfgreg, chan->cfgval);
- li_writel(lith, desc->ctlreg, chan->ctlval);
-
- DBGRV();
-}
-
-static void li_shutdown_dma(dma_chan_t *chan)
-{
- lithium_t *lith = chan->lith;
- void * lith1 = lith->page1;
-
- DBGEV("(chan=0x%p)\n", chan);
-
- chan->ctlval &= ~LI_CCTL_DMA_ENABLE;
- DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval);
- li_writel(lith, chan->desc->ctlreg, chan->ctlval);
-
- /*
- * Offset 0x500 on Lithium page 1 is an undocumented,
- * unsupported register that holds the zero sample value.
- * Lithium is supposed to output zero samples when DMA is
- * inactive, and repeat the last sample when DMA underflows.
- * But it has a bug, where, after underflow occurs, the zero
- * sample is not reset.
- *
- * I expect this to break in a future rev of Lithium.
- */
-
- if (lith1 && chan->desc->direction == LI_CCFG_DIR_OUT)
- * (volatile unsigned long *) (lith1 + 0x500) = 0;
-}
-
-/*
- * li_activate_dma always starts dma at the beginning of the buffer.
- *
- * N.B., these may be called from interrupt.
- */
-
-static __inline__ void li_activate_dma(dma_chan_t *chan)
-{
- chan->ctlval |= LI_CCTL_DMA_ENABLE;
- DBGPV("ctlval = 0x%lx\n", chan->ctlval);
- li_writel(chan->lith, chan->desc->ctlreg, chan->ctlval);
-}
-
-static void li_deactivate_dma(dma_chan_t *chan)
-{
- lithium_t *lith = chan->lith;
- void * lith2 = lith->page2;
-
- chan->ctlval &= ~(LI_CCTL_DMA_ENABLE | LI_CCTL_RPTR | LI_CCTL_WPTR);
- DBGPV("ctlval = 0x%lx\n", chan->ctlval);
- DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval);
- li_writel(lith, chan->desc->ctlreg, chan->ctlval);
-
- /*
- * Offsets 0x98 and 0x9C on Lithium page 2 are undocumented,
- * unsupported registers that are internal copies of the DMA
- * read and write pointers. Because of a Lithium bug, these
- * registers aren't zeroed correctly when DMA is shut off. So
- * we whack them directly.
- *
- * I expect this to break in a future rev of Lithium.
- */
-
- if (lith2 && chan->desc->direction == LI_CCFG_DIR_OUT) {
- * (volatile unsigned long *) (lith2 + 0x98) = 0;
- * (volatile unsigned long *) (lith2 + 0x9C) = 0;
- }
-}
-
-/*
- * read/write the ring buffer pointers. These routines' arguments and results
- * are byte offsets from the beginning of the ring buffer.
- */
-
-static __inline__ int li_read_swptr(dma_chan_t *chan)
-{
- const unsigned long mask = chan->desc->swptrmask;
-
- return CHUNKS_TO_BYTES(UNSHIFT_FIELD(chan->ctlval, mask));
-}
-
-static __inline__ int li_read_hwptr(dma_chan_t *chan)
-{
- return CHUNKS_TO_BYTES(li_readb(chan->lith, chan->desc->hwptrreg));
-}
-
-static __inline__ void li_write_swptr(dma_chan_t *chan, int val)
-{
- const unsigned long mask = chan->desc->swptrmask;
-
- ASSERT(!(val & ~CHUNKS_TO_BYTES(0xFF)));
- val = BYTES_TO_CHUNKS(val);
- chan->ctlval = (chan->ctlval & ~mask) | SHIFT_FIELD(val, mask);
- li_writeb(chan->lith, chan->desc->swptrreg, val);
-}
-
-/* li_read_USTMSC() returns a UST/MSC pair for the given channel. */
-
-static void li_read_USTMSC(dma_chan_t *chan, ustmsc_t *ustmsc)
-{
- lithium_t *lith = chan->lith;
- const dma_chan_desc_t *desc = chan->desc;
- unsigned long now_low, now_high0, now_high1, chan_ust;
-
- spin_lock(&lith->lock);
- {
- /*
- * retry until we do all five reads without the
- * high word changing. (High word increments
- * every 2^32 microseconds, i.e., not often)
- */
- do {
- now_high0 = li_readl(lith, LI_UST_HIGH);
- now_low = li_readl(lith, LI_UST_LOW);
-
- /*
- * Lithium guarantees these two reads will be
- * atomic -- ust will not increment after msc
- * is read.
- */
-
- ustmsc->msc = li_readl(lith, desc->mscreg);
- chan_ust = li_readl(lith, desc->ustreg);
-
- now_high1 = li_readl(lith, LI_UST_HIGH);
- } while (now_high0 != now_high1);
- }
- spin_unlock(&lith->lock);
- ustmsc->ust = ((unsigned long long) now_high0 << 32 | chan_ust);
-}
-
-static void li_enable_interrupts(lithium_t *lith, unsigned int mask)
-{
- DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask);
-
- /* clear any already-pending interrupts. */
-
- li_writel(lith, LI_INTR_STATUS, mask);
-
- /* enable the interrupts. */
-
- mask |= li_readl(lith, LI_INTR_MASK);
- li_writel(lith, LI_INTR_MASK, mask);
-}
-
-static void li_disable_interrupts(lithium_t *lith, unsigned int mask)
-{
- unsigned int keepmask;
-
- DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask);
-
- /* disable the interrupts */
-
- keepmask = li_readl(lith, LI_INTR_MASK) & ~mask;
- li_writel(lith, LI_INTR_MASK, keepmask);
-
- /* clear any pending interrupts. */
-
- li_writel(lith, LI_INTR_STATUS, mask);
-}
-
-/* Get the interrupt status and clear all pending interrupts. */
-
-static unsigned int li_get_clear_intr_status(lithium_t *lith)
-{
- unsigned int status;
-
- status = li_readl(lith, LI_INTR_STATUS);
- li_writel(lith, LI_INTR_STATUS, ~0);
- return status & li_readl(lith, LI_INTR_MASK);
-}
-
-static int li_init(lithium_t *lith)
-{
- /* 1. System power supplies stabilize. */
-
- /* 2. Assert the ~RESET signal. */
-
- li_writel(lith, LI_HOST_CONTROLLER, LI_HC_RESET);
- udelay(1);
-
- /* 3. Deassert the ~RESET signal and enter a wait period to allow
- the AD1843 internal clocks and the external crystal oscillator
- to stabilize. */
-
- li_writel(lith, LI_HOST_CONTROLLER, LI_HC_LINK_ENABLE);
- udelay(1);
-
- return 0;
-}
-
-/*****************************************************************************/
-/* AD1843 access */
-
-/*
- * AD1843 bitfield definitions. All are named as in the AD1843 data
- * sheet, with ad1843_ prepended and individual bit numbers removed.
- *
- * E.g., bits LSS0 through LSS2 become ad1843_LSS.
- *
- * Only the bitfields we need are defined.
- */
-
-typedef struct ad1843_bitfield {
- char reg;
- char lo_bit;
- char nbits;
-} ad1843_bitfield_t;
-
-static const ad1843_bitfield_t
- ad1843_PDNO = { 0, 14, 1 }, /* Converter Power-Down Flag */
- ad1843_INIT = { 0, 15, 1 }, /* Clock Initialization Flag */
- ad1843_RIG = { 2, 0, 4 }, /* Right ADC Input Gain */
- ad1843_RMGE = { 2, 4, 1 }, /* Right ADC Mic Gain Enable */
- ad1843_RSS = { 2, 5, 3 }, /* Right ADC Source Select */
- ad1843_LIG = { 2, 8, 4 }, /* Left ADC Input Gain */
- ad1843_LMGE = { 2, 12, 1 }, /* Left ADC Mic Gain Enable */
- ad1843_LSS = { 2, 13, 3 }, /* Left ADC Source Select */
- ad1843_RX1M = { 4, 0, 5 }, /* Right Aux 1 Mix Gain/Atten */
- ad1843_RX1MM = { 4, 7, 1 }, /* Right Aux 1 Mix Mute */
- ad1843_LX1M = { 4, 8, 5 }, /* Left Aux 1 Mix Gain/Atten */
- ad1843_LX1MM = { 4, 15, 1 }, /* Left Aux 1 Mix Mute */
- ad1843_RX2M = { 5, 0, 5 }, /* Right Aux 2 Mix Gain/Atten */
- ad1843_RX2MM = { 5, 7, 1 }, /* Right Aux 2 Mix Mute */
- ad1843_LX2M = { 5, 8, 5 }, /* Left Aux 2 Mix Gain/Atten */
- ad1843_LX2MM = { 5, 15, 1 }, /* Left Aux 2 Mix Mute */
- ad1843_RMCM = { 7, 0, 5 }, /* Right Mic Mix Gain/Atten */
- ad1843_RMCMM = { 7, 7, 1 }, /* Right Mic Mix Mute */
- ad1843_LMCM = { 7, 8, 5 }, /* Left Mic Mix Gain/Atten */
- ad1843_LMCMM = { 7, 15, 1 }, /* Left Mic Mix Mute */
- ad1843_HPOS = { 8, 4, 1 }, /* Headphone Output Voltage Swing */
- ad1843_HPOM = { 8, 5, 1 }, /* Headphone Output Mute */
- ad1843_RDA1G = { 9, 0, 6 }, /* Right DAC1 Analog/Digital Gain */
- ad1843_RDA1GM = { 9, 7, 1 }, /* Right DAC1 Analog Mute */
- ad1843_LDA1G = { 9, 8, 6 }, /* Left DAC1 Analog/Digital Gain */
- ad1843_LDA1GM = { 9, 15, 1 }, /* Left DAC1 Analog Mute */
- ad1843_RDA1AM = { 11, 7, 1 }, /* Right DAC1 Digital Mute */
- ad1843_LDA1AM = { 11, 15, 1 }, /* Left DAC1 Digital Mute */
- ad1843_ADLC = { 15, 0, 2 }, /* ADC Left Sample Rate Source */
- ad1843_ADRC = { 15, 2, 2 }, /* ADC Right Sample Rate Source */
- ad1843_DA1C = { 15, 8, 2 }, /* DAC1 Sample Rate Source */
- ad1843_C1C = { 17, 0, 16 }, /* Clock 1 Sample Rate Select */
- ad1843_C2C = { 20, 0, 16 }, /* Clock 1 Sample Rate Select */
- ad1843_DAADL = { 25, 4, 2 }, /* Digital ADC Left Source Select */
- ad1843_DAADR = { 25, 6, 2 }, /* Digital ADC Right Source Select */
- ad1843_DRSFLT = { 25, 15, 1 }, /* Digital Reampler Filter Mode */
- ad1843_ADLF = { 26, 0, 2 }, /* ADC Left Channel Data Format */
- ad1843_ADRF = { 26, 2, 2 }, /* ADC Right Channel Data Format */
- ad1843_ADTLK = { 26, 4, 1 }, /* ADC Transmit Lock Mode Select */
- ad1843_SCF = { 26, 7, 1 }, /* SCLK Frequency Select */
- ad1843_DA1F = { 26, 8, 2 }, /* DAC1 Data Format Select */
- ad1843_DA1SM = { 26, 14, 1 }, /* DAC1 Stereo/Mono Mode Select */
- ad1843_ADLEN = { 27, 0, 1 }, /* ADC Left Channel Enable */
- ad1843_ADREN = { 27, 1, 1 }, /* ADC Right Channel Enable */
- ad1843_AAMEN = { 27, 4, 1 }, /* Analog to Analog Mix Enable */
- ad1843_ANAEN = { 27, 7, 1 }, /* Analog Channel Enable */
- ad1843_DA1EN = { 27, 8, 1 }, /* DAC1 Enable */
- ad1843_DA2EN = { 27, 9, 1 }, /* DAC2 Enable */
- ad1843_C1EN = { 28, 11, 1 }, /* Clock Generator 1 Enable */
- ad1843_C2EN = { 28, 12, 1 }, /* Clock Generator 2 Enable */
- ad1843_PDNI = { 28, 15, 1 }; /* Converter Power Down */
-
-/*
- * The various registers of the AD1843 use three different formats for
- * specifying gain. The ad1843_gain structure parameterizes the
- * formats.
- */
-
-typedef struct ad1843_gain {
-
- int negative; /* nonzero if gain is negative. */
- const ad1843_bitfield_t *lfield;
- const ad1843_bitfield_t *rfield;
-
-} ad1843_gain_t;
-
-static const ad1843_gain_t ad1843_gain_RECLEV
- = { 0, &ad1843_LIG, &ad1843_RIG };
-static const ad1843_gain_t ad1843_gain_LINE
- = { 1, &ad1843_LX1M, &ad1843_RX1M };
-static const ad1843_gain_t ad1843_gain_CD
- = { 1, &ad1843_LX2M, &ad1843_RX2M };
-static const ad1843_gain_t ad1843_gain_MIC
- = { 1, &ad1843_LMCM, &ad1843_RMCM };
-static const ad1843_gain_t ad1843_gain_PCM
- = { 1, &ad1843_LDA1G, &ad1843_RDA1G };
-
-/* read the current value of an AD1843 bitfield. */
-
-static int ad1843_read_bits(lithium_t *lith, const ad1843_bitfield_t *field)
-{
- int w = li_read_ad1843_reg(lith, field->reg);
- int val = w >> field->lo_bit & ((1 << field->nbits) - 1);
-
- DBGXV("ad1843_read_bits(lith=0x%p, field->{%d %d %d}) returns 0x%x\n",
- lith, field->reg, field->lo_bit, field->nbits, val);
-
- return val;
-}
-
-/*
- * write a new value to an AD1843 bitfield and return the old value.
- */
-
-static int ad1843_write_bits(lithium_t *lith,
- const ad1843_bitfield_t *field,
- int newval)
-{
- int w = li_read_ad1843_reg(lith, field->reg);
- int mask = ((1 << field->nbits) - 1) << field->lo_bit;
- int oldval = (w & mask) >> field->lo_bit;
- int newbits = (newval << field->lo_bit) & mask;
- w = (w & ~mask) | newbits;
- (void) li_write_ad1843_reg(lith, field->reg, w);
-
- DBGXV("ad1843_write_bits(lith=0x%p, field->{%d %d %d}, val=0x%x) "
- "returns 0x%x\n",
- lith, field->reg, field->lo_bit, field->nbits, newval,
- oldval);
-
- return oldval;
-}
-
-/*
- * ad1843_read_multi reads multiple bitfields from the same AD1843
- * register. It uses a single read cycle to do it. (Reading the
- * ad1843 requires 256 bit times at 12.288 MHz, or nearly 20
- * microseconds.)
- *
- * Called ike this.
- *
- * ad1843_read_multi(lith, nfields,
- * &ad1843_FIELD1, &val1,
- * &ad1843_FIELD2, &val2, ...);
- */
-
-static void ad1843_read_multi(lithium_t *lith, int argcount, ...)
-{
- va_list ap;
- const ad1843_bitfield_t *fp;
- int w = 0, mask, *value, reg = -1;
-
- va_start(ap, argcount);
- while (--argcount >= 0) {
- fp = va_arg(ap, const ad1843_bitfield_t *);
- value = va_arg(ap, int *);
- if (reg == -1) {
- reg = fp->reg;
- w = li_read_ad1843_reg(lith, reg);
- }
- ASSERT(reg == fp->reg);
- mask = (1 << fp->nbits) - 1;
- *value = w >> fp->lo_bit & mask;
- }
- va_end(ap);
-}
-
-/*
- * ad1843_write_multi stores multiple bitfields into the same AD1843
- * register. It uses one read and one write cycle to do it.
- *
- * Called like this.
- *
- * ad1843_write_multi(lith, nfields,
- * &ad1843_FIELD1, val1,
- * &ad1843_FIELF2, val2, ...);
- */
-
-static void ad1843_write_multi(lithium_t *lith, int argcount, ...)
-{
- va_list ap;
- int reg;
- const ad1843_bitfield_t *fp;
- int value;
- int w, m, mask, bits;
-
- mask = 0;
- bits = 0;
- reg = -1;
-
- va_start(ap, argcount);
- while (--argcount >= 0) {
- fp = va_arg(ap, const ad1843_bitfield_t *);
- value = va_arg(ap, int);
- if (reg == -1)
- reg = fp->reg;
- ASSERT(fp->reg == reg);
- m = ((1 << fp->nbits) - 1) << fp->lo_bit;
- mask |= m;
- bits |= (value << fp->lo_bit) & m;
- }
- va_end(ap);
- ASSERT(!(bits & ~mask));
- if (~mask & 0xFFFF)
- w = li_read_ad1843_reg(lith, reg);
- else
- w = 0;
- w = (w & ~mask) | bits;
- (void) li_write_ad1843_reg(lith, reg, w);
-}
-
-/*
- * ad1843_get_gain reads the specified register and extracts the gain value
- * using the supplied gain type. It returns the gain in OSS format.
- */
-
-static int ad1843_get_gain(lithium_t *lith, const ad1843_gain_t *gp)
-{
- int lg, rg;
- unsigned short mask = (1 << gp->lfield->nbits) - 1;
-
- ad1843_read_multi(lith, 2, gp->lfield, &lg, gp->rfield, &rg);
- if (gp->negative) {
- lg = mask - lg;
- rg = mask - rg;
- }
- lg = (lg * 100 + (mask >> 1)) / mask;
- rg = (rg * 100 + (mask >> 1)) / mask;
- return lg << 0 | rg << 8;
-}
-
-/*
- * Set an audio channel's gain. Converts from OSS format to AD1843's
- * format.
- *
- * Returns the new gain, which may be lower than the old gain.
- */
-
-static int ad1843_set_gain(lithium_t *lith,
- const ad1843_gain_t *gp,
- int newval)
-{
- unsigned short mask = (1 << gp->lfield->nbits) - 1;
-
- int lg = newval >> 0 & 0xFF;
- int rg = newval >> 8;
- if (lg < 0 || lg > 100 || rg < 0 || rg > 100)
- return -EINVAL;
- lg = (lg * mask + (mask >> 1)) / 100;
- rg = (rg * mask + (mask >> 1)) / 100;
- if (gp->negative) {
- lg = mask - lg;
- rg = mask - rg;
- }
- ad1843_write_multi(lith, 2, gp->lfield, lg, gp->rfield, rg);
- return ad1843_get_gain(lith, gp);
-}
-
-/* Returns the current recording source, in OSS format. */
-
-static int ad1843_get_recsrc(lithium_t *lith)
-{
- int ls = ad1843_read_bits(lith, &ad1843_LSS);
-
- switch (ls) {
- case 1:
- return SOUND_MASK_MIC;
- case 2:
- return SOUND_MASK_LINE;
- case 3:
- return SOUND_MASK_CD;
- case 6:
- return SOUND_MASK_PCM;
- default:
- ASSERT(0);
- return -1;
- }
-}
-
-/*
- * Enable/disable digital resample mode in the AD1843.
- *
- * The AD1843 requires that ADL, ADR, DA1 and DA2 be powered down
- * while switching modes. So we save DA1's state (DA2's state is not
- * interesting), power them down, switch into/out of resample mode,
- * power them up, and restore state.
- *
- * This will cause audible glitches if D/A or A/D is going on, so the
- * driver disallows that (in mixer_write_ioctl()).
- *
- * The open question is, is this worth doing? I'm leaving it in,
- * because it's written, but...
- */
-
-static void ad1843_set_resample_mode(lithium_t *lith, int onoff)
-{
- /* Save DA1 mute and gain (addr 9 is DA1 analog gain/attenuation) */
- int save_da1 = li_read_ad1843_reg(lith, 9);
-
- /* Power down A/D and D/A. */
- ad1843_write_multi(lith, 4,
- &ad1843_DA1EN, 0,
- &ad1843_DA2EN, 0,
- &ad1843_ADLEN, 0,
- &ad1843_ADREN, 0);
-
- /* Switch mode */
- ASSERT(onoff == 0 || onoff == 1);
- ad1843_write_bits(lith, &ad1843_DRSFLT, onoff);
-
- /* Power up A/D and D/A. */
- ad1843_write_multi(lith, 3,
- &ad1843_DA1EN, 1,
- &ad1843_ADLEN, 1,
- &ad1843_ADREN, 1);
-
- /* Restore DA1 mute and gain. */
- li_write_ad1843_reg(lith, 9, save_da1);
-}
-
-/*
- * Set recording source. Arg newsrc specifies an OSS channel mask.
- *
- * The complication is that when we switch into/out of loopback mode
- * (i.e., src = SOUND_MASK_PCM), we change the AD1843 into/out of
- * digital resampling mode.
- *
- * Returns newsrc on success, -errno on failure.
- */
-
-static int ad1843_set_recsrc(lithium_t *lith, int newsrc)
-{
- int bits;
- int oldbits;
-
- switch (newsrc) {
- case SOUND_MASK_PCM:
- bits = 6;
- break;
-
- case SOUND_MASK_MIC:
- bits = 1;
- break;
-
- case SOUND_MASK_LINE:
- bits = 2;
- break;
-
- case SOUND_MASK_CD:
- bits = 3;
- break;
-
- default:
- return -EINVAL;
- }
- oldbits = ad1843_read_bits(lith, &ad1843_LSS);
- if (newsrc == SOUND_MASK_PCM && oldbits != 6) {
- DBGP("enabling digital resample mode\n");
- ad1843_set_resample_mode(lith, 1);
- ad1843_write_multi(lith, 2,
- &ad1843_DAADL, 2,
- &ad1843_DAADR, 2);
- } else if (newsrc != SOUND_MASK_PCM && oldbits == 6) {
- DBGP("disabling digital resample mode\n");
- ad1843_set_resample_mode(lith, 0);
- ad1843_write_multi(lith, 2,
- &ad1843_DAADL, 0,
- &ad1843_DAADR, 0);
- }
- ad1843_write_multi(lith, 2, &ad1843_LSS, bits, &ad1843_RSS, bits);
- return newsrc;
-}
-
-/*
- * Return current output sources, in OSS format.
- */
-
-static int ad1843_get_outsrc(lithium_t *lith)
-{
- int pcm, line, mic, cd;
-
- pcm = ad1843_read_bits(lith, &ad1843_LDA1GM) ? 0 : SOUND_MASK_PCM;
- line = ad1843_read_bits(lith, &ad1843_LX1MM) ? 0 : SOUND_MASK_LINE;
- cd = ad1843_read_bits(lith, &ad1843_LX2MM) ? 0 : SOUND_MASK_CD;
- mic = ad1843_read_bits(lith, &ad1843_LMCMM) ? 0 : SOUND_MASK_MIC;
-
- return pcm | line | cd | mic;
-}
-
-/*
- * Set output sources. Arg is a mask of active sources in OSS format.
- *
- * Returns source mask on success, -errno on failure.
- */
-
-static int ad1843_set_outsrc(lithium_t *lith, int mask)
-{
- int pcm, line, mic, cd;
-
- if (mask & ~(SOUND_MASK_PCM | SOUND_MASK_LINE |
- SOUND_MASK_CD | SOUND_MASK_MIC))
- return -EINVAL;
- pcm = (mask & SOUND_MASK_PCM) ? 0 : 1;
- line = (mask & SOUND_MASK_LINE) ? 0 : 1;
- mic = (mask & SOUND_MASK_MIC) ? 0 : 1;
- cd = (mask & SOUND_MASK_CD) ? 0 : 1;
-
- ad1843_write_multi(lith, 2, &ad1843_LDA1GM, pcm, &ad1843_RDA1GM, pcm);
- ad1843_write_multi(lith, 2, &ad1843_LX1MM, line, &ad1843_RX1MM, line);
- ad1843_write_multi(lith, 2, &ad1843_LX2MM, cd, &ad1843_RX2MM, cd);
- ad1843_write_multi(lith, 2, &ad1843_LMCMM, mic, &ad1843_RMCMM, mic);
-
- return mask;
-}
-
-/* Setup ad1843 for D/A conversion. */
-
-static void ad1843_setup_dac(lithium_t *lith,
- int framerate,
- int fmt,
- int channels)
-{
- int ad_fmt = 0, ad_mode = 0;
-
- DBGEV("(lith=0x%p, framerate=%d, fmt=%d, channels=%d)\n",
- lith, framerate, fmt, channels);
-
- switch (fmt) {
- case AFMT_S8: ad_fmt = 1; break;
- case AFMT_U8: ad_fmt = 1; break;
- case AFMT_S16_LE: ad_fmt = 1; break;
- case AFMT_MU_LAW: ad_fmt = 2; break;
- case AFMT_A_LAW: ad_fmt = 3; break;
- default: ASSERT(0);
- }
-
- switch (channels) {
- case 2: ad_mode = 0; break;
- case 1: ad_mode = 1; break;
- default: ASSERT(0);
- }
-
- DBGPV("ad_mode = %d, ad_fmt = %d\n", ad_mode, ad_fmt);
- ASSERT(framerate >= 4000 && framerate <= 49000);
- ad1843_write_bits(lith, &ad1843_C1C, framerate);
- ad1843_write_multi(lith, 2,
- &ad1843_DA1SM, ad_mode, &ad1843_DA1F, ad_fmt);
-}
-
-static void ad1843_shutdown_dac(lithium_t *lith)
-{
- ad1843_write_bits(lith, &ad1843_DA1F, 1);
-}
-
-static void ad1843_setup_adc(lithium_t *lith, int framerate, int fmt, int channels)
-{
- int da_fmt = 0;
-
- DBGEV("(lith=0x%p, framerate=%d, fmt=%d, channels=%d)\n",
- lith, framerate, fmt, channels);
-
- switch (fmt) {
- case AFMT_S8: da_fmt = 1; break;
- case AFMT_U8: da_fmt = 1; break;
- case AFMT_S16_LE: da_fmt = 1; break;
- case AFMT_MU_LAW: da_fmt = 2; break;
- case AFMT_A_LAW: da_fmt = 3; break;
- default: ASSERT(0);
- }
-
- DBGPV("da_fmt = %d\n", da_fmt);
- ASSERT(framerate >= 4000 && framerate <= 49000);
- ad1843_write_bits(lith, &ad1843_C2C, framerate);
- ad1843_write_multi(lith, 2,
- &ad1843_ADLF, da_fmt, &ad1843_ADRF, da_fmt);
-}
-
-static void ad1843_shutdown_adc(lithium_t *lith)
-{
- /* nothing to do */
-}
-
-/*
- * Fully initialize the ad1843. As described in the AD1843 data
- * sheet, section "START-UP SEQUENCE". The numbered comments are
- * subsection headings from the data sheet. See the data sheet, pages
- * 52-54, for more info.
- *
- * return 0 on success, -errno on failure. */
-
-static int __init ad1843_init(lithium_t *lith)
-{
- unsigned long later;
- int err;
-
- err = li_init(lith);
- if (err)
- return err;
-
- if (ad1843_read_bits(lith, &ad1843_INIT) != 0) {
- printk(KERN_ERR "vwsnd sound: AD1843 won't initialize\n");
- return -EIO;
- }
-
- ad1843_write_bits(lith, &ad1843_SCF, 1);
-
- /* 4. Put the conversion resources into standby. */
-
- ad1843_write_bits(lith, &ad1843_PDNI, 0);
- later = jiffies + HZ / 2; /* roughly half a second */
- DBGDO(shut_up++);
- while (ad1843_read_bits(lith, &ad1843_PDNO)) {
- if (time_after(jiffies, later)) {
- printk(KERN_ERR
- "vwsnd audio: AD1843 won't power up\n");
- return -EIO;
- }
- schedule();
- }
- DBGDO(shut_up--);
-
- /* 5. Power up the clock generators and enable clock output pins. */
-
- ad1843_write_multi(lith, 2, &ad1843_C1EN, 1, &ad1843_C2EN, 1);
-
- /* 6. Configure conversion resources while they are in standby. */
-
- /* DAC1 uses clock 1 as source, ADC uses clock 2. Always. */
-
- ad1843_write_multi(lith, 3,
- &ad1843_DA1C, 1,
- &ad1843_ADLC, 2,
- &ad1843_ADRC, 2);
-
- /* 7. Enable conversion resources. */
-
- ad1843_write_bits(lith, &ad1843_ADTLK, 1);
- ad1843_write_multi(lith, 5,
- &ad1843_ANAEN, 1,
- &ad1843_AAMEN, 1,
- &ad1843_DA1EN, 1,
- &ad1843_ADLEN, 1,
- &ad1843_ADREN, 1);
-
- /* 8. Configure conversion resources while they are enabled. */
-
- ad1843_write_bits(lith, &ad1843_DA1C, 1);
-
- /* Unmute all channels. */
-
- ad1843_set_outsrc(lith,
- (SOUND_MASK_PCM | SOUND_MASK_LINE |
- SOUND_MASK_MIC | SOUND_MASK_CD));
- ad1843_write_multi(lith, 2, &ad1843_LDA1AM, 0, &ad1843_RDA1AM, 0);
-
- /* Set default recording source to Line In and set
- * mic gain to +20 dB.
- */
-
- ad1843_set_recsrc(lith, SOUND_MASK_LINE);
- ad1843_write_multi(lith, 2, &ad1843_LMGE, 1, &ad1843_RMGE, 1);
-
- /* Set Speaker Out level to +/- 4V and unmute it. */
-
- ad1843_write_multi(lith, 2, &ad1843_HPOS, 1, &ad1843_HPOM, 0);
-
- return 0;
-}
-
-/*****************************************************************************/
-/* PCM I/O */
-
-#define READ_INTR_MASK (LI_INTR_COMM1_TRIG | LI_INTR_COMM1_OVERFLOW)
-#define WRITE_INTR_MASK (LI_INTR_COMM2_TRIG | LI_INTR_COMM2_UNDERFLOW)
-
-typedef enum vwsnd_port_swstate { /* software state */
- SW_OFF,
- SW_INITIAL,
- SW_RUN,
- SW_DRAIN,
-} vwsnd_port_swstate_t;
-
-typedef enum vwsnd_port_hwstate { /* hardware state */
- HW_STOPPED,
- HW_RUNNING,
-} vwsnd_port_hwstate_t;
-
-/*
- * These flags are read by ISR, but only written at baseline.
- */
-
-typedef enum vwsnd_port_flags {
- DISABLED = 1 << 0,
- ERFLOWN = 1 << 1, /* overflown or underflown */
- HW_BUSY = 1 << 2,
-} vwsnd_port_flags_t;
-
-/*
- * vwsnd_port is the per-port data structure. Each device has two
- * ports, one for input and one for output.
- *
- * Locking:
- *
- * port->lock protects: hwstate, flags, swb_[iu]_avail.
- *
- * devc->io_mutex protects: swstate, sw_*, swb_[iu]_idx.
- *
- * everything else is only written by open/release or
- * pcm_{setup,shutdown}(), which are serialized by a
- * combination of devc->open_mutex and devc->io_mutex.
- */
-
-typedef struct vwsnd_port {
-
- spinlock_t lock;
- wait_queue_head_t queue;
- vwsnd_port_swstate_t swstate;
- vwsnd_port_hwstate_t hwstate;
- vwsnd_port_flags_t flags;
-
- int sw_channels;
- int sw_samplefmt;
- int sw_framerate;
- int sample_size;
- int frame_size;
- unsigned int zero_word; /* zero for the sample format */
-
- int sw_fragshift;
- int sw_fragcount;
- int sw_subdivshift;
-
- unsigned int hw_fragshift;
- unsigned int hw_fragsize;
- unsigned int hw_fragcount;
-
- int hwbuf_size;
- unsigned long hwbuf_paddr;
- unsigned long hwbuf_vaddr;
- void * hwbuf; /* hwbuf == hwbuf_vaddr */
- int hwbuf_max; /* max bytes to preload */
-
- void * swbuf;
- unsigned int swbuf_size; /* size in bytes */
- unsigned int swb_u_idx; /* index of next user byte */
- unsigned int swb_i_idx; /* index of next intr byte */
- unsigned int swb_u_avail; /* # bytes avail to user */
- unsigned int swb_i_avail; /* # bytes avail to intr */
-
- dma_chan_t chan;
-
- /* Accounting */
-
- int byte_count;
- int frag_count;
- int MSC_offset;
-
-} vwsnd_port_t;
-
-/* vwsnd_dev is the per-device data structure. */
-
-typedef struct vwsnd_dev {
- struct vwsnd_dev *next_dev;
- int audio_minor; /* minor number of audio device */
- int mixer_minor; /* minor number of mixer device */
-
- struct mutex open_mutex;
- struct mutex io_mutex;
- struct mutex mix_mutex;
- fmode_t open_mode;
- wait_queue_head_t open_wait;
-
- lithium_t lith;
-
- vwsnd_port_t rport;
- vwsnd_port_t wport;
-} vwsnd_dev_t;
-
-static vwsnd_dev_t *vwsnd_dev_list; /* linked list of all devices */
-
-static atomic_t vwsnd_use_count = ATOMIC_INIT(0);
-
-# define INC_USE_COUNT (atomic_inc(&vwsnd_use_count))
-# define DEC_USE_COUNT (atomic_dec(&vwsnd_use_count))
-# define IN_USE (atomic_read(&vwsnd_use_count) != 0)
-
-/*
- * Lithium can only DMA multiples of 32 bytes. Its DMA buffer may
- * be up to 8 Kb. This driver always uses 8 Kb.
- *
- * Memory bug workaround -- I'm not sure what's going on here, but
- * somehow pcm_copy_out() was triggering segv's going on to the next
- * page of the hw buffer. So, I make the hw buffer one size bigger
- * than we actually use. That way, the following page is allocated
- * and mapped, and no error. I suspect that something is broken
- * in Cobalt, but haven't really investigated. HBO is the actual
- * size of the buffer, and HWBUF_ORDER is what we allocate.
- */
-
-#define HWBUF_SHIFT 13
-#define HWBUF_SIZE (1 << HWBUF_SHIFT)
-# define HBO (HWBUF_SHIFT > PAGE_SHIFT ? HWBUF_SHIFT - PAGE_SHIFT : 0)
-# define HWBUF_ORDER (HBO + 1) /* next size bigger */
-#define MIN_SPEED 4000
-#define MAX_SPEED 49000
-
-#define MIN_FRAGSHIFT (DMACHUNK_SHIFT + 1)
-#define MAX_FRAGSHIFT (PAGE_SHIFT)
-#define MIN_FRAGSIZE (1 << MIN_FRAGSHIFT)
-#define MAX_FRAGSIZE (1 << MAX_FRAGSHIFT)
-#define MIN_FRAGCOUNT(fragsize) 3
-#define MAX_FRAGCOUNT(fragsize) (32 * PAGE_SIZE / (fragsize))
-#define DEFAULT_FRAGSHIFT 12
-#define DEFAULT_FRAGCOUNT 16
-#define DEFAULT_SUBDIVSHIFT 0
-
-/*
- * The software buffer (swbuf) is a ring buffer shared between user
- * level and interrupt level. Each level owns some of the bytes in
- * the buffer, and may give bytes away by calling swb_inc_{u,i}().
- * User level calls _u for user, and interrupt level calls _i for
- * interrupt.
- *
- * port->swb_{u,i}_avail is the number of bytes available to that level.
- *
- * port->swb_{u,i}_idx is the index of the first available byte in the
- * buffer.
- *
- * Each level calls swb_inc_{u,i}() to atomically increment its index,
- * recalculate the number of bytes available for both sides, and
- * return the number of bytes available. Since each side can only
- * give away bytes, the other side can only increase the number of
- * bytes available to this side. Each side updates its own index
- * variable, swb_{u,i}_idx, so no lock is needed to read it.
- *
- * To query the number of bytes available, call swb_inc_{u,i} with an
- * increment of zero.
- */
-
-static __inline__ unsigned int __swb_inc_u(vwsnd_port_t *port, int inc)
-{
- if (inc) {
- port->swb_u_idx += inc;
- port->swb_u_idx %= port->swbuf_size;
- port->swb_u_avail -= inc;
- port->swb_i_avail += inc;
- }
- return port->swb_u_avail;
-}
-
-static __inline__ unsigned int swb_inc_u(vwsnd_port_t *port, int inc)
-{
- unsigned long flags;
- unsigned int ret;
-
- spin_lock_irqsave(&port->lock, flags);
- {
- ret = __swb_inc_u(port, inc);
- }
- spin_unlock_irqrestore(&port->lock, flags);
- return ret;
-}
-
-static __inline__ unsigned int __swb_inc_i(vwsnd_port_t *port, int inc)
-{
- if (inc) {
- port->swb_i_idx += inc;
- port->swb_i_idx %= port->swbuf_size;
- port->swb_i_avail -= inc;
- port->swb_u_avail += inc;
- }
- return port->swb_i_avail;
-}
-
-static __inline__ unsigned int swb_inc_i(vwsnd_port_t *port, int inc)
-{
- unsigned long flags;
- unsigned int ret;
-
- spin_lock_irqsave(&port->lock, flags);
- {
- ret = __swb_inc_i(port, inc);
- }
- spin_unlock_irqrestore(&port->lock, flags);
- return ret;
-}
-
-/*
- * pcm_setup - this routine initializes all port state after
- * mode-setting ioctls have been done, but before the first I/O is
- * done.
- *
- * Locking: called with devc->io_mutex held.
- *
- * Returns 0 on success, -errno on failure.
- */
-
-static int pcm_setup(vwsnd_dev_t *devc,
- vwsnd_port_t *rport,
- vwsnd_port_t *wport)
-{
- vwsnd_port_t *aport = rport ? rport : wport;
- int sample_size;
- unsigned int zero_word;
-
- DBGEV("(devc=0x%p, rport=0x%p, wport=0x%p)\n", devc, rport, wport);
-
- ASSERT(aport != NULL);
- if (aport->swbuf != NULL)
- return 0;
- switch (aport->sw_samplefmt) {
- case AFMT_MU_LAW:
- sample_size = 1;
- zero_word = 0xFFFFFFFF ^ 0x80808080;
- break;
-
- case AFMT_A_LAW:
- sample_size = 1;
- zero_word = 0xD5D5D5D5 ^ 0x80808080;
- break;
-
- case AFMT_U8:
- sample_size = 1;
- zero_word = 0x80808080;
- break;
-
- case AFMT_S8:
- sample_size = 1;
- zero_word = 0x00000000;
- break;
-
- case AFMT_S16_LE:
- sample_size = 2;
- zero_word = 0x00000000;
- break;
-
- default:
- sample_size = 0; /* prevent compiler warning */
- zero_word = 0;
- ASSERT(0);
- }
- aport->sample_size = sample_size;
- aport->zero_word = zero_word;
- aport->frame_size = aport->sw_channels * aport->sample_size;
- aport->hw_fragshift = aport->sw_fragshift - aport->sw_subdivshift;
- aport->hw_fragsize = 1 << aport->hw_fragshift;
- aport->hw_fragcount = aport->sw_fragcount << aport->sw_subdivshift;
- ASSERT(aport->hw_fragsize >= MIN_FRAGSIZE);
- ASSERT(aport->hw_fragsize <= MAX_FRAGSIZE);
- ASSERT(aport->hw_fragcount >= MIN_FRAGCOUNT(aport->hw_fragsize));
- ASSERT(aport->hw_fragcount <= MAX_FRAGCOUNT(aport->hw_fragsize));
- if (rport) {
- int hwfrags, swfrags;
- rport->hwbuf_max = aport->hwbuf_size - DMACHUNK_SIZE;
- hwfrags = rport->hwbuf_max >> aport->hw_fragshift;
- swfrags = aport->hw_fragcount - hwfrags;
- if (swfrags < 2)
- swfrags = 2;
- rport->swbuf_size = swfrags * aport->hw_fragsize;
- DBGPV("hwfrags = %d, swfrags = %d\n", hwfrags, swfrags);
- DBGPV("read hwbuf_max = %d, swbuf_size = %d\n",
- rport->hwbuf_max, rport->swbuf_size);
- }
- if (wport) {
- int hwfrags, swfrags;
- int total_bytes = aport->hw_fragcount * aport->hw_fragsize;
- wport->hwbuf_max = aport->hwbuf_size - DMACHUNK_SIZE;
- if (wport->hwbuf_max > total_bytes)
- wport->hwbuf_max = total_bytes;
- hwfrags = wport->hwbuf_max >> aport->hw_fragshift;
- DBGPV("hwfrags = %d\n", hwfrags);
- swfrags = aport->hw_fragcount - hwfrags;
- if (swfrags < 2)
- swfrags = 2;
- wport->swbuf_size = swfrags * aport->hw_fragsize;
- DBGPV("hwfrags = %d, swfrags = %d\n", hwfrags, swfrags);
- DBGPV("write hwbuf_max = %d, swbuf_size = %d\n",
- wport->hwbuf_max, wport->swbuf_size);
- }
-
- aport->swb_u_idx = 0;
- aport->swb_i_idx = 0;
- aport->byte_count = 0;
-
- /*
- * Is this a Cobalt bug? We need to make this buffer extend
- * one page further than we actually use -- somehow memcpy
- * causes an exceptoin otherwise. I suspect there's a bug in
- * Cobalt (or somewhere) where it's generating a fault on a
- * speculative load or something. Obviously, I haven't taken
- * the time to track it down.
- */
-
- aport->swbuf = vmalloc(aport->swbuf_size + PAGE_SIZE);
- if (!aport->swbuf)
- return -ENOMEM;
- if (rport && wport) {
- ASSERT(aport == rport);
- ASSERT(wport->swbuf == NULL);
- /* One extra page - see comment above. */
- wport->swbuf = vmalloc(aport->swbuf_size + PAGE_SIZE);
- if (!wport->swbuf) {
- vfree(aport->swbuf);
- aport->swbuf = NULL;
- return -ENOMEM;
- }
- wport->sample_size = rport->sample_size;
- wport->zero_word = rport->zero_word;
- wport->frame_size = rport->frame_size;
- wport->hw_fragshift = rport->hw_fragshift;
- wport->hw_fragsize = rport->hw_fragsize;
- wport->hw_fragcount = rport->hw_fragcount;
- wport->swbuf_size = rport->swbuf_size;
- wport->hwbuf_max = rport->hwbuf_max;
- wport->swb_u_idx = rport->swb_u_idx;
- wport->swb_i_idx = rport->swb_i_idx;
- wport->byte_count = rport->byte_count;
- }
- if (rport) {
- rport->swb_u_avail = 0;
- rport->swb_i_avail = rport->swbuf_size;
- rport->swstate = SW_RUN;
- li_setup_dma(&rport->chan,
- &li_comm1,
- &devc->lith,
- rport->hwbuf_paddr,
- HWBUF_SHIFT,
- rport->hw_fragshift,
- rport->sw_channels,
- rport->sample_size);
- ad1843_setup_adc(&devc->lith,
- rport->sw_framerate,
- rport->sw_samplefmt,
- rport->sw_channels);
- li_enable_interrupts(&devc->lith, READ_INTR_MASK);
- if (!(rport->flags & DISABLED)) {
- ustmsc_t ustmsc;
- rport->hwstate = HW_RUNNING;
- li_activate_dma(&rport->chan);
- li_read_USTMSC(&rport->chan, &ustmsc);
- rport->MSC_offset = ustmsc.msc;
- }
- }
- if (wport) {
- if (wport->hwbuf_max > wport->swbuf_size)
- wport->hwbuf_max = wport->swbuf_size;
- wport->flags &= ~ERFLOWN;
- wport->swb_u_avail = wport->swbuf_size;
- wport->swb_i_avail = 0;
- wport->swstate = SW_RUN;
- li_setup_dma(&wport->chan,
- &li_comm2,
- &devc->lith,
- wport->hwbuf_paddr,
- HWBUF_SHIFT,
- wport->hw_fragshift,
- wport->sw_channels,
- wport->sample_size);
- ad1843_setup_dac(&devc->lith,
- wport->sw_framerate,
- wport->sw_samplefmt,
- wport->sw_channels);
- li_enable_interrupts(&devc->lith, WRITE_INTR_MASK);
- }
- DBGRV();
- return 0;
-}
-
-/*
- * pcm_shutdown_port - shut down one port (direction) for PCM I/O.
- * Only called from pcm_shutdown.
- */
-
-static void pcm_shutdown_port(vwsnd_dev_t *devc,
- vwsnd_port_t *aport,
- unsigned int mask)
-{
- unsigned long flags;
- vwsnd_port_hwstate_t hwstate;
- DECLARE_WAITQUEUE(wait, current);
-
- aport->swstate = SW_INITIAL;
- add_wait_queue(&aport->queue, &wait);
- while (1) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- spin_lock_irqsave(&aport->lock, flags);
- {
- hwstate = aport->hwstate;
- }
- spin_unlock_irqrestore(&aport->lock, flags);
- if (hwstate == HW_STOPPED)
- break;
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&aport->queue, &wait);
- li_disable_interrupts(&devc->lith, mask);
- if (aport == &devc->rport)
- ad1843_shutdown_adc(&devc->lith);
- else /* aport == &devc->wport) */
- ad1843_shutdown_dac(&devc->lith);
- li_shutdown_dma(&aport->chan);
- vfree(aport->swbuf);
- aport->swbuf = NULL;
- aport->byte_count = 0;
-}
-
-/*
- * pcm_shutdown undoes what pcm_setup did.
- * Also sets the ports' swstate to newstate.
- */
-
-static void pcm_shutdown(vwsnd_dev_t *devc,
- vwsnd_port_t *rport,
- vwsnd_port_t *wport)
-{
- DBGEV("(devc=0x%p, rport=0x%p, wport=0x%p)\n", devc, rport, wport);
-
- if (rport && rport->swbuf) {
- DBGPV("shutting down rport\n");
- pcm_shutdown_port(devc, rport, READ_INTR_MASK);
- }
- if (wport && wport->swbuf) {
- DBGPV("shutting down wport\n");
- pcm_shutdown_port(devc, wport, WRITE_INTR_MASK);
- }
- DBGRV();
-}
-
-static void pcm_copy_in(vwsnd_port_t *rport, int swidx, int hwidx, int nb)
-{
- char *src = rport->hwbuf + hwidx;
- char *dst = rport->swbuf + swidx;
- int fmt = rport->sw_samplefmt;
-
- DBGPV("swidx = %d, hwidx = %d\n", swidx, hwidx);
- ASSERT(rport->hwbuf != NULL);
- ASSERT(rport->swbuf != NULL);
- ASSERT(nb > 0 && (nb % 32) == 0);
- ASSERT(swidx % 32 == 0 && hwidx % 32 == 0);
- ASSERT(swidx >= 0 && swidx + nb <= rport->swbuf_size);
- ASSERT(hwidx >= 0 && hwidx + nb <= rport->hwbuf_size);
-
- if (fmt == AFMT_MU_LAW || fmt == AFMT_A_LAW || fmt == AFMT_S8) {
-
- /* See Sample Format Notes above. */
-
- char *end = src + nb;
- while (src < end)
- *dst++ = *src++ ^ 0x80;
- } else
- memcpy(dst, src, nb);
-}
-
-static void pcm_copy_out(vwsnd_port_t *wport, int swidx, int hwidx, int nb)
-{
- char *src = wport->swbuf + swidx;
- char *dst = wport->hwbuf + hwidx;
- int fmt = wport->sw_samplefmt;
-
- ASSERT(nb > 0 && (nb % 32) == 0);
- ASSERT(wport->hwbuf != NULL);
- ASSERT(wport->swbuf != NULL);
- ASSERT(swidx % 32 == 0 && hwidx % 32 == 0);
- ASSERT(swidx >= 0 && swidx + nb <= wport->swbuf_size);
- ASSERT(hwidx >= 0 && hwidx + nb <= wport->hwbuf_size);
- if (fmt == AFMT_MU_LAW || fmt == AFMT_A_LAW || fmt == AFMT_S8) {
-
- /* See Sample Format Notes above. */
-
- char *end = src + nb;
- while (src < end)
- *dst++ = *src++ ^ 0x80;
- } else
- memcpy(dst, src, nb);
-}
-
-/*
- * pcm_output() is called both from baselevel and from interrupt level.
- * This is where audio frames are copied into the hardware-accessible
- * ring buffer.
- *
- * Locking note: The part of this routine that figures out what to do
- * holds wport->lock. The longer part releases wport->lock, but sets
- * wport->flags & HW_BUSY. Afterward, it reacquires wport->lock, and
- * checks for more work to do.
- *
- * If another thread calls pcm_output() while HW_BUSY is set, it
- * returns immediately, knowing that the thread that set HW_BUSY will
- * look for more work to do before returning.
- *
- * This has the advantage that port->lock is held for several short
- * periods instead of one long period. Also, when pcm_output is
- * called from base level, it reenables interrupts.
- */
-
-static void pcm_output(vwsnd_dev_t *devc, int erflown, int nb)
-{
- vwsnd_port_t *wport = &devc->wport;
- const int hwmax = wport->hwbuf_max;
- const int hwsize = wport->hwbuf_size;
- const int swsize = wport->swbuf_size;
- const int fragsize = wport->hw_fragsize;
- unsigned long iflags;
-
- DBGEV("(devc=0x%p, erflown=%d, nb=%d)\n", devc, erflown, nb);
- spin_lock_irqsave(&wport->lock, iflags);
- if (erflown)
- wport->flags |= ERFLOWN;
- (void) __swb_inc_u(wport, nb);
- if (wport->flags & HW_BUSY) {
- spin_unlock_irqrestore(&wport->lock, iflags);
- DBGPV("returning: HW BUSY\n");
- return;
- }
- if (wport->flags & DISABLED) {
- spin_unlock_irqrestore(&wport->lock, iflags);
- DBGPV("returning: DISABLED\n");
- return;
- }
- wport->flags |= HW_BUSY;
- while (1) {
- int swptr, hwptr, hw_avail, sw_avail, swidx;
- vwsnd_port_hwstate_t hwstate = wport->hwstate;
- vwsnd_port_swstate_t swstate = wport->swstate;
- int hw_unavail;
- ustmsc_t ustmsc;
-
- hwptr = li_read_hwptr(&wport->chan);
- swptr = li_read_swptr(&wport->chan);
- hw_unavail = (swptr - hwptr + hwsize) % hwsize;
- hw_avail = (hwmax - hw_unavail) & -fragsize;
- sw_avail = wport->swb_i_avail & -fragsize;
- if (sw_avail && swstate == SW_RUN) {
- if (wport->flags & ERFLOWN) {
- wport->flags &= ~ERFLOWN;
- }
- } else if (swstate == SW_INITIAL ||
- swstate == SW_OFF ||
- (swstate == SW_DRAIN &&
- !sw_avail &&
- (wport->flags & ERFLOWN))) {
- DBGP("stopping. hwstate = %d\n", hwstate);
- if (hwstate != HW_STOPPED) {
- li_deactivate_dma(&wport->chan);
- wport->hwstate = HW_STOPPED;
- }
- wake_up(&wport->queue);
- break;
- }
- if (!sw_avail || !hw_avail)
- break;
- spin_unlock_irqrestore(&wport->lock, iflags);
-
- /*
- * We gave up the port lock, but we have the HW_BUSY flag.
- * Proceed without accessing any nonlocal state.
- * Do not exit the loop -- must check for more work.
- */
-
- swidx = wport->swb_i_idx;
- nb = hw_avail;
- if (nb > sw_avail)
- nb = sw_avail;
- if (nb > hwsize - swptr)
- nb = hwsize - swptr; /* don't overflow hwbuf */
- if (nb > swsize - swidx)
- nb = swsize - swidx; /* don't overflow swbuf */
- ASSERT(nb > 0);
- if (nb % fragsize) {
- DBGP("nb = %d, fragsize = %d\n", nb, fragsize);
- DBGP("hw_avail = %d\n", hw_avail);
- DBGP("sw_avail = %d\n", sw_avail);
- DBGP("hwsize = %d, swptr = %d\n", hwsize, swptr);
- DBGP("swsize = %d, swidx = %d\n", swsize, swidx);
- }
- ASSERT(!(nb % fragsize));
- DBGPV("copying swb[%d..%d] to hwb[%d..%d]\n",
- swidx, swidx + nb, swptr, swptr + nb);
- pcm_copy_out(wport, swidx, swptr, nb);
- li_write_swptr(&wport->chan, (swptr + nb) % hwsize);
- spin_lock_irqsave(&wport->lock, iflags);
- if (hwstate == HW_STOPPED) {
- DBGPV("starting\n");
- li_activate_dma(&wport->chan);
- wport->hwstate = HW_RUNNING;
- li_read_USTMSC(&wport->chan, &ustmsc);
- ASSERT(wport->byte_count % wport->frame_size == 0);
- wport->MSC_offset = ustmsc.msc - wport->byte_count / wport->frame_size;
- }
- __swb_inc_i(wport, nb);
- wport->byte_count += nb;
- wport->frag_count += nb / fragsize;
- ASSERT(nb % fragsize == 0);
- wake_up(&wport->queue);
- }
- wport->flags &= ~HW_BUSY;
- spin_unlock_irqrestore(&wport->lock, iflags);
- DBGRV();
-}
-
-/*
- * pcm_input() is called both from baselevel and from interrupt level.
- * This is where audio frames are copied out of the hardware-accessible
- * ring buffer.
- *
- * Locking note: The part of this routine that figures out what to do
- * holds rport->lock. The longer part releases rport->lock, but sets
- * rport->flags & HW_BUSY. Afterward, it reacquires rport->lock, and
- * checks for more work to do.
- *
- * If another thread calls pcm_input() while HW_BUSY is set, it
- * returns immediately, knowing that the thread that set HW_BUSY will
- * look for more work to do before returning.
- *
- * This has the advantage that port->lock is held for several short
- * periods instead of one long period. Also, when pcm_input is
- * called from base level, it reenables interrupts.
- */
-
-static void pcm_input(vwsnd_dev_t *devc, int erflown, int nb)
-{
- vwsnd_port_t *rport = &devc->rport;
- const int hwmax = rport->hwbuf_max;
- const int hwsize = rport->hwbuf_size;
- const int swsize = rport->swbuf_size;
- const int fragsize = rport->hw_fragsize;
- unsigned long iflags;
-
- DBGEV("(devc=0x%p, erflown=%d, nb=%d)\n", devc, erflown, nb);
-
- spin_lock_irqsave(&rport->lock, iflags);
- if (erflown)
- rport->flags |= ERFLOWN;
- (void) __swb_inc_u(rport, nb);
- if (rport->flags & HW_BUSY || !rport->swbuf) {
- spin_unlock_irqrestore(&rport->lock, iflags);
- DBGPV("returning: HW BUSY or !swbuf\n");
- return;
- }
- if (rport->flags & DISABLED) {
- spin_unlock_irqrestore(&rport->lock, iflags);
- DBGPV("returning: DISABLED\n");
- return;
- }
- rport->flags |= HW_BUSY;
- while (1) {
- int swptr, hwptr, hw_avail, sw_avail, swidx;
- vwsnd_port_hwstate_t hwstate = rport->hwstate;
- vwsnd_port_swstate_t swstate = rport->swstate;
-
- hwptr = li_read_hwptr(&rport->chan);
- swptr = li_read_swptr(&rport->chan);
- hw_avail = (hwptr - swptr + hwsize) % hwsize & -fragsize;
- if (hw_avail > hwmax)
- hw_avail = hwmax;
- sw_avail = rport->swb_i_avail & -fragsize;
- if (swstate != SW_RUN) {
- DBGP("stopping. hwstate = %d\n", hwstate);
- if (hwstate != HW_STOPPED) {
- li_deactivate_dma(&rport->chan);
- rport->hwstate = HW_STOPPED;
- }
- wake_up(&rport->queue);
- break;
- }
- if (!sw_avail || !hw_avail)
- break;
- spin_unlock_irqrestore(&rport->lock, iflags);
-
- /*
- * We gave up the port lock, but we have the HW_BUSY flag.
- * Proceed without accessing any nonlocal state.
- * Do not exit the loop -- must check for more work.
- */
-
- swidx = rport->swb_i_idx;
- nb = hw_avail;
- if (nb > sw_avail)
- nb = sw_avail;
- if (nb > hwsize - swptr)
- nb = hwsize - swptr; /* don't overflow hwbuf */
- if (nb > swsize - swidx)
- nb = swsize - swidx; /* don't overflow swbuf */
- ASSERT(nb > 0);
- if (nb % fragsize) {
- DBGP("nb = %d, fragsize = %d\n", nb, fragsize);
- DBGP("hw_avail = %d\n", hw_avail);
- DBGP("sw_avail = %d\n", sw_avail);
- DBGP("hwsize = %d, swptr = %d\n", hwsize, swptr);
- DBGP("swsize = %d, swidx = %d\n", swsize, swidx);
- }
- ASSERT(!(nb % fragsize));
- DBGPV("copying hwb[%d..%d] to swb[%d..%d]\n",
- swptr, swptr + nb, swidx, swidx + nb);
- pcm_copy_in(rport, swidx, swptr, nb);
- li_write_swptr(&rport->chan, (swptr + nb) % hwsize);
- spin_lock_irqsave(&rport->lock, iflags);
- __swb_inc_i(rport, nb);
- rport->byte_count += nb;
- rport->frag_count += nb / fragsize;
- ASSERT(nb % fragsize == 0);
- wake_up(&rport->queue);
- }
- rport->flags &= ~HW_BUSY;
- spin_unlock_irqrestore(&rport->lock, iflags);
- DBGRV();
-}
-
-/*
- * pcm_flush_frag() writes zero samples to fill the current fragment,
- * then flushes it to the hardware.
- *
- * It is only meaningful to flush output, not input.
- */
-
-static void pcm_flush_frag(vwsnd_dev_t *devc)
-{
- vwsnd_port_t *wport = &devc->wport;
-
- DBGPV("swstate = %d\n", wport->swstate);
- if (wport->swstate == SW_RUN) {
- int idx = wport->swb_u_idx;
- int end = (idx + wport->hw_fragsize - 1)
- >> wport->hw_fragshift
- << wport->hw_fragshift;
- int nb = end - idx;
- DBGPV("clearing %d bytes\n", nb);
- if (nb)
- memset(wport->swbuf + idx,
- (char) wport->zero_word,
- nb);
- wport->swstate = SW_DRAIN;
- pcm_output(devc, 0, nb);
- }
- DBGRV();
-}
-
-/*
- * Wait for output to drain. This sleeps uninterruptibly because
- * there is nothing intelligent we can do if interrupted. This
- * means the process will be delayed in responding to the signal.
- */
-
-static void pcm_write_sync(vwsnd_dev_t *devc)
-{
- vwsnd_port_t *wport = &devc->wport;
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- vwsnd_port_hwstate_t hwstate;
-
- DBGEV("(devc=0x%p)\n", devc);
- add_wait_queue(&wport->queue, &wait);
- while (1) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- spin_lock_irqsave(&wport->lock, flags);
- {
- hwstate = wport->hwstate;
- }
- spin_unlock_irqrestore(&wport->lock, flags);
- if (hwstate == HW_STOPPED)
- break;
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&wport->queue, &wait);
- DBGPV("swstate = %d, hwstate = %d\n", wport->swstate, wport->hwstate);
- DBGRV();
-}
-
-/*****************************************************************************/
-/* audio driver */
-
-/*
- * seek on an audio device always fails.
- */
-
-static void vwsnd_audio_read_intr(vwsnd_dev_t *devc, unsigned int status)
-{
- int overflown = status & LI_INTR_COMM1_OVERFLOW;
-
- if (status & READ_INTR_MASK)
- pcm_input(devc, overflown, 0);
-}
-
-static void vwsnd_audio_write_intr(vwsnd_dev_t *devc, unsigned int status)
-{
- int underflown = status & LI_INTR_COMM2_UNDERFLOW;
-
- if (status & WRITE_INTR_MASK)
- pcm_output(devc, underflown, 0);
-}
-
-static irqreturn_t vwsnd_audio_intr(int irq, void *dev_id)
-{
- vwsnd_dev_t *devc = dev_id;
- unsigned int status;
-
- DBGEV("(irq=%d, dev_id=0x%p)\n", irq, dev_id);
-
- status = li_get_clear_intr_status(&devc->lith);
- vwsnd_audio_read_intr(devc, status);
- vwsnd_audio_write_intr(devc, status);
- return IRQ_HANDLED;
-}
-
-static ssize_t vwsnd_audio_do_read(struct file *file,
- char *buffer,
- size_t count,
- loff_t *ppos)
-{
- vwsnd_dev_t *devc = file->private_data;
- vwsnd_port_t *rport = ((file->f_mode & FMODE_READ) ?
- &devc->rport : NULL);
- int ret, nb;
-
- DBGEV("(file=0x%p, buffer=0x%p, count=%d, ppos=0x%p)\n",
- file, buffer, count, ppos);
-
- if (!rport)
- return -EINVAL;
-
- if (rport->swbuf == NULL) {
- vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ?
- &devc->wport : NULL;
- ret = pcm_setup(devc, rport, wport);
- if (ret < 0)
- return ret;
- }
-
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
- while (count) {
- DECLARE_WAITQUEUE(wait, current);
- add_wait_queue(&rport->queue, &wait);
- while ((nb = swb_inc_u(rport, 0)) == 0) {
- DBGPV("blocking\n");
- set_current_state(TASK_INTERRUPTIBLE);
- if (rport->flags & DISABLED ||
- file->f_flags & O_NONBLOCK) {
- current->state = TASK_RUNNING;
- remove_wait_queue(&rport->queue, &wait);
- return ret ? ret : -EAGAIN;
- }
- schedule();
- if (signal_pending(current)) {
- current->state = TASK_RUNNING;
- remove_wait_queue(&rport->queue, &wait);
- return ret ? ret : -ERESTARTSYS;
- }
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&rport->queue, &wait);
- pcm_input(devc, 0, 0);
- /* nb bytes are available in userbuf. */
- if (nb > count)
- nb = count;
- DBGPV("nb = %d\n", nb);
- if (copy_to_user(buffer, rport->swbuf + rport->swb_u_idx, nb))
- return -EFAULT;
- (void) swb_inc_u(rport, nb);
- buffer += nb;
- count -= nb;
- ret += nb;
- }
- DBGPV("returning %d\n", ret);
- return ret;
-}
-
-static ssize_t vwsnd_audio_read(struct file *file,
- char *buffer,
- size_t count,
- loff_t *ppos)
-{
- vwsnd_dev_t *devc = file->private_data;
- ssize_t ret;
-
- mutex_lock(&devc->io_mutex);
- ret = vwsnd_audio_do_read(file, buffer, count, ppos);
- mutex_unlock(&devc->io_mutex);
- return ret;
-}
-
-static ssize_t vwsnd_audio_do_write(struct file *file,
- const char *buffer,
- size_t count,
- loff_t *ppos)
-{
- vwsnd_dev_t *devc = file->private_data;
- vwsnd_port_t *wport = ((file->f_mode & FMODE_WRITE) ?
- &devc->wport : NULL);
- int ret, nb;
-
- DBGEV("(file=0x%p, buffer=0x%p, count=%d, ppos=0x%p)\n",
- file, buffer, count, ppos);
-
- if (!wport)
- return -EINVAL;
-
- if (wport->swbuf == NULL) {
- vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ?
- &devc->rport : NULL;
- ret = pcm_setup(devc, rport, wport);
- if (ret < 0)
- return ret;
- }
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
- while (count) {
- DECLARE_WAITQUEUE(wait, current);
- add_wait_queue(&wport->queue, &wait);
- while ((nb = swb_inc_u(wport, 0)) == 0) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (wport->flags & DISABLED ||
- file->f_flags & O_NONBLOCK) {
- current->state = TASK_RUNNING;
- remove_wait_queue(&wport->queue, &wait);
- return ret ? ret : -EAGAIN;
- }
- schedule();
- if (signal_pending(current)) {
- current->state = TASK_RUNNING;
- remove_wait_queue(&wport->queue, &wait);
- return ret ? ret : -ERESTARTSYS;
- }
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&wport->queue, &wait);
- /* nb bytes are available in userbuf. */
- if (nb > count)
- nb = count;
- DBGPV("nb = %d\n", nb);
- if (copy_from_user(wport->swbuf + wport->swb_u_idx, buffer, nb))
- return -EFAULT;
- pcm_output(devc, 0, nb);
- buffer += nb;
- count -= nb;
- ret += nb;
- }
- DBGPV("returning %d\n", ret);
- return ret;
-}
-
-static ssize_t vwsnd_audio_write(struct file *file,
- const char *buffer,
- size_t count,
- loff_t *ppos)
-{
- vwsnd_dev_t *devc = file->private_data;
- ssize_t ret;
-
- mutex_lock(&devc->io_mutex);
- ret = vwsnd_audio_do_write(file, buffer, count, ppos);
- mutex_unlock(&devc->io_mutex);
- return ret;
-}
-
-/* No kernel lock - fine */
-static unsigned int vwsnd_audio_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
- vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ?
- &devc->rport : NULL;
- vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ?
- &devc->wport : NULL;
- unsigned int mask = 0;
-
- DBGEV("(file=0x%p, wait=0x%p)\n", file, wait);
-
- ASSERT(rport || wport);
- if (rport) {
- poll_wait(file, &rport->queue, wait);
- if (swb_inc_u(rport, 0))
- mask |= (POLLIN | POLLRDNORM);
- }
- if (wport) {
- poll_wait(file, &wport->queue, wait);
- if (wport->swbuf == NULL || swb_inc_u(wport, 0))
- mask |= (POLLOUT | POLLWRNORM);
- }
-
- DBGPV("returning 0x%x\n", mask);
- return mask;
-}
-
-static int vwsnd_audio_do_ioctl(struct file *file,
- unsigned int cmd,
- unsigned long arg)
-{
- vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
- vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ?
- &devc->rport : NULL;
- vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ?
- &devc->wport : NULL;
- vwsnd_port_t *aport = rport ? rport : wport;
- struct audio_buf_info buf_info;
- struct count_info info;
- unsigned long flags;
- int ival;
-
-
- DBGEV("(file=0x%p, cmd=0x%x, arg=0x%lx)\n",
- file, cmd, arg);
- switch (cmd) {
- case OSS_GETVERSION: /* _SIOR ('M', 118, int) */
- DBGX("OSS_GETVERSION\n");
- ival = SOUND_VERSION;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_GETCAPS: /* _SIOR ('P',15, int) */
- DBGX("SNDCTL_DSP_GETCAPS\n");
- ival = DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_GETFMTS: /* _SIOR ('P',11, int) */
- DBGX("SNDCTL_DSP_GETFMTS\n");
- ival = (AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW |
- AFMT_U8 | AFMT_S8);
- return put_user(ival, (int *) arg);
- break;
-
- case SOUND_PCM_READ_RATE: /* _SIOR ('P', 2, int) */
- DBGX("SOUND_PCM_READ_RATE\n");
- ival = aport->sw_framerate;
- return put_user(ival, (int *) arg);
-
- case SOUND_PCM_READ_CHANNELS: /* _SIOR ('P', 6, int) */
- DBGX("SOUND_PCM_READ_CHANNELS\n");
- ival = aport->sw_channels;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_SPEED: /* _SIOWR('P', 2, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_SPEED %d\n", ival);
- if (ival) {
- if (aport->swstate != SW_INITIAL) {
- DBGX("SNDCTL_DSP_SPEED failed: swstate = %d\n",
- aport->swstate);
- return -EINVAL;
- }
- if (ival < MIN_SPEED)
- ival = MIN_SPEED;
- if (ival > MAX_SPEED)
- ival = MAX_SPEED;
- if (rport)
- rport->sw_framerate = ival;
- if (wport)
- wport->sw_framerate = ival;
- } else
- ival = aport->sw_framerate;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_STEREO: /* _SIOWR('P', 3, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_STEREO %d\n", ival);
- if (ival != 0 && ival != 1)
- return -EINVAL;
- if (aport->swstate != SW_INITIAL)
- return -EINVAL;
- if (rport)
- rport->sw_channels = ival + 1;
- if (wport)
- wport->sw_channels = ival + 1;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_CHANNELS: /* _SIOWR('P', 6, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_CHANNELS %d\n", ival);
- if (ival != 1 && ival != 2)
- return -EINVAL;
- if (aport->swstate != SW_INITIAL)
- return -EINVAL;
- if (rport)
- rport->sw_channels = ival;
- if (wport)
- wport->sw_channels = ival;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_GETBLKSIZE: /* _SIOWR('P', 4, int) */
- ival = pcm_setup(devc, rport, wport);
- if (ival < 0) {
- DBGX("SNDCTL_DSP_GETBLKSIZE failed, errno %d\n", ival);
- return ival;
- }
- ival = 1 << aport->sw_fragshift;
- DBGX("SNDCTL_DSP_GETBLKSIZE returning %d\n", ival);
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_SETFRAGMENT: /* _SIOWR('P',10, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_SETFRAGMENT %d:%d\n",
- ival >> 16, ival & 0xFFFF);
- if (aport->swstate != SW_INITIAL)
- return -EINVAL;
- {
- int sw_fragshift = ival & 0xFFFF;
- int sw_subdivshift = aport->sw_subdivshift;
- int hw_fragshift = sw_fragshift - sw_subdivshift;
- int sw_fragcount = (ival >> 16) & 0xFFFF;
- int hw_fragsize;
- if (hw_fragshift < MIN_FRAGSHIFT)
- hw_fragshift = MIN_FRAGSHIFT;
- if (hw_fragshift > MAX_FRAGSHIFT)
- hw_fragshift = MAX_FRAGSHIFT;
- sw_fragshift = hw_fragshift + aport->sw_subdivshift;
- hw_fragsize = 1 << hw_fragshift;
- if (sw_fragcount < MIN_FRAGCOUNT(hw_fragsize))
- sw_fragcount = MIN_FRAGCOUNT(hw_fragsize);
- if (sw_fragcount > MAX_FRAGCOUNT(hw_fragsize))
- sw_fragcount = MAX_FRAGCOUNT(hw_fragsize);
- DBGPV("sw_fragshift = %d\n", sw_fragshift);
- DBGPV("rport = 0x%p, wport = 0x%p\n", rport, wport);
- if (rport) {
- rport->sw_fragshift = sw_fragshift;
- rport->sw_fragcount = sw_fragcount;
- }
- if (wport) {
- wport->sw_fragshift = sw_fragshift;
- wport->sw_fragcount = sw_fragcount;
- }
- ival = sw_fragcount << 16 | sw_fragshift;
- }
- DBGX("SNDCTL_DSP_SETFRAGMENT returns %d:%d\n",
- ival >> 16, ival & 0xFFFF);
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_SUBDIVIDE: /* _SIOWR('P', 9, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_SUBDIVIDE %d\n", ival);
- if (aport->swstate != SW_INITIAL)
- return -EINVAL;
- {
- int subdivshift;
- int hw_fragshift, hw_fragsize, hw_fragcount;
- switch (ival) {
- case 1: subdivshift = 0; break;
- case 2: subdivshift = 1; break;
- case 4: subdivshift = 2; break;
- default: return -EINVAL;
- }
- hw_fragshift = aport->sw_fragshift - subdivshift;
- if (hw_fragshift < MIN_FRAGSHIFT ||
- hw_fragshift > MAX_FRAGSHIFT)
- return -EINVAL;
- hw_fragsize = 1 << hw_fragshift;
- hw_fragcount = aport->sw_fragcount >> subdivshift;
- if (hw_fragcount < MIN_FRAGCOUNT(hw_fragsize) ||
- hw_fragcount > MAX_FRAGCOUNT(hw_fragsize))
- return -EINVAL;
- if (rport)
- rport->sw_subdivshift = subdivshift;
- if (wport)
- wport->sw_subdivshift = subdivshift;
- }
- return 0;
-
- case SNDCTL_DSP_SETFMT: /* _SIOWR('P',5, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_SETFMT %d\n", ival);
- if (ival != AFMT_QUERY) {
- if (aport->swstate != SW_INITIAL) {
- DBGP("SETFMT failed, swstate = %d\n",
- aport->swstate);
- return -EINVAL;
- }
- switch (ival) {
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_U8:
- case AFMT_S8:
- case AFMT_S16_LE:
- if (rport)
- rport->sw_samplefmt = ival;
- if (wport)
- wport->sw_samplefmt = ival;
- break;
- default:
- return -EINVAL;
- }
- }
- ival = aport->sw_samplefmt;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_GETOSPACE: /* _SIOR ('P',12, audio_buf_info) */
- DBGXV("SNDCTL_DSP_GETOSPACE\n");
- if (!wport)
- return -EINVAL;
- ival = pcm_setup(devc, rport, wport);
- if (ival < 0)
- return ival;
- ival = swb_inc_u(wport, 0);
- buf_info.fragments = ival >> wport->sw_fragshift;
- buf_info.fragstotal = wport->sw_fragcount;
- buf_info.fragsize = 1 << wport->sw_fragshift;
- buf_info.bytes = ival;
- DBGXV("SNDCTL_DSP_GETOSPACE returns { %d %d %d %d }\n",
- buf_info.fragments, buf_info.fragstotal,
- buf_info.fragsize, buf_info.bytes);
- if (copy_to_user((void *) arg, &buf_info, sizeof buf_info))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETISPACE: /* _SIOR ('P',13, audio_buf_info) */
- DBGX("SNDCTL_DSP_GETISPACE\n");
- if (!rport)
- return -EINVAL;
- ival = pcm_setup(devc, rport, wport);
- if (ival < 0)
- return ival;
- ival = swb_inc_u(rport, 0);
- buf_info.fragments = ival >> rport->sw_fragshift;
- buf_info.fragstotal = rport->sw_fragcount;
- buf_info.fragsize = 1 << rport->sw_fragshift;
- buf_info.bytes = ival;
- DBGX("SNDCTL_DSP_GETISPACE returns { %d %d %d %d }\n",
- buf_info.fragments, buf_info.fragstotal,
- buf_info.fragsize, buf_info.bytes);
- if (copy_to_user((void *) arg, &buf_info, sizeof buf_info))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_NONBLOCK: /* _SIO ('P',14) */
- DBGX("SNDCTL_DSP_NONBLOCK\n");
- spin_lock(&file->f_lock);
- file->f_flags |= O_NONBLOCK;
- spin_unlock(&file->f_lock);
- return 0;
-
- case SNDCTL_DSP_RESET: /* _SIO ('P', 0) */
- DBGX("SNDCTL_DSP_RESET\n");
- /*
- * Nothing special needs to be done for input. Input
- * samples sit in swbuf, but it will be reinitialized
- * to empty when pcm_setup() is called.
- */
- if (wport && wport->swbuf) {
- wport->swstate = SW_INITIAL;
- pcm_output(devc, 0, 0);
- pcm_write_sync(devc);
- }
- pcm_shutdown(devc, rport, wport);
- return 0;
-
- case SNDCTL_DSP_SYNC: /* _SIO ('P', 1) */
- DBGX("SNDCTL_DSP_SYNC\n");
- if (wport) {
- pcm_flush_frag(devc);
- pcm_write_sync(devc);
- }
- pcm_shutdown(devc, rport, wport);
- return 0;
-
- case SNDCTL_DSP_POST: /* _SIO ('P', 8) */
- DBGX("SNDCTL_DSP_POST\n");
- if (!wport)
- return -EINVAL;
- pcm_flush_frag(devc);
- return 0;
-
- case SNDCTL_DSP_GETIPTR: /* _SIOR ('P', 17, count_info) */
- DBGX("SNDCTL_DSP_GETIPTR\n");
- if (!rport)
- return -EINVAL;
- spin_lock_irqsave(&rport->lock, flags);
- {
- ustmsc_t ustmsc;
- if (rport->hwstate == HW_RUNNING) {
- ASSERT(rport->swstate == SW_RUN);
- li_read_USTMSC(&rport->chan, &ustmsc);
- info.bytes = ustmsc.msc - rport->MSC_offset;
- info.bytes *= rport->frame_size;
- } else {
- info.bytes = rport->byte_count;
- }
- info.blocks = rport->frag_count;
- info.ptr = 0; /* not implemented */
- rport->frag_count = 0;
- }
- spin_unlock_irqrestore(&rport->lock, flags);
- if (copy_to_user((void *) arg, &info, sizeof info))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETOPTR: /* _SIOR ('P',18, count_info) */
- DBGX("SNDCTL_DSP_GETOPTR\n");
- if (!wport)
- return -EINVAL;
- spin_lock_irqsave(&wport->lock, flags);
- {
- ustmsc_t ustmsc;
- if (wport->hwstate == HW_RUNNING) {
- ASSERT(wport->swstate == SW_RUN);
- li_read_USTMSC(&wport->chan, &ustmsc);
- info.bytes = ustmsc.msc - wport->MSC_offset;
- info.bytes *= wport->frame_size;
- } else {
- info.bytes = wport->byte_count;
- }
- info.blocks = wport->frag_count;
- info.ptr = 0; /* not implemented */
- wport->frag_count = 0;
- }
- spin_unlock_irqrestore(&wport->lock, flags);
- if (copy_to_user((void *) arg, &info, sizeof info))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETODELAY: /* _SIOR ('P', 23, int) */
- DBGX("SNDCTL_DSP_GETODELAY\n");
- if (!wport)
- return -EINVAL;
- spin_lock_irqsave(&wport->lock, flags);
- {
- int fsize = wport->frame_size;
- ival = wport->swb_i_avail / fsize;
- if (wport->hwstate == HW_RUNNING) {
- int swptr, hwptr, hwframes, hwbytes, hwsize;
- int totalhwbytes;
- ustmsc_t ustmsc;
-
- hwsize = wport->hwbuf_size;
- swptr = li_read_swptr(&wport->chan);
- li_read_USTMSC(&wport->chan, &ustmsc);
- hwframes = ustmsc.msc - wport->MSC_offset;
- totalhwbytes = hwframes * fsize;
- hwptr = totalhwbytes % hwsize;
- hwbytes = (swptr - hwptr + hwsize) % hwsize;
- ival += hwbytes / fsize;
- }
- }
- spin_unlock_irqrestore(&wport->lock, flags);
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_PROFILE: /* _SIOW ('P', 23, int) */
- DBGX("SNDCTL_DSP_PROFILE\n");
-
- /*
- * Thomas Sailer explains SNDCTL_DSP_PROFILE
- * (private email, March 24, 1999):
- *
- * This gives the sound driver a hint on what it
- * should do with partial fragments
- * (i.e. fragments partially filled with write).
- * This can direct the driver to zero them or
- * leave them alone. But don't ask me what this
- * is good for, my driver just zeroes the last
- * fragment before the receiver stops, no idea
- * what good for any other behaviour could
- * be. Implementing it as NOP seems safe.
- */
-
- break;
-
- case SNDCTL_DSP_GETTRIGGER: /* _SIOR ('P',16, int) */
- DBGX("SNDCTL_DSP_GETTRIGGER\n");
- ival = 0;
- if (rport) {
- spin_lock_irqsave(&rport->lock, flags);
- {
- if (!(rport->flags & DISABLED))
- ival |= PCM_ENABLE_INPUT;
- }
- spin_unlock_irqrestore(&rport->lock, flags);
- }
- if (wport) {
- spin_lock_irqsave(&wport->lock, flags);
- {
- if (!(wport->flags & DISABLED))
- ival |= PCM_ENABLE_OUTPUT;
- }
- spin_unlock_irqrestore(&wport->lock, flags);
- }
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_SETTRIGGER: /* _SIOW ('P',16, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_SETTRIGGER %d\n", ival);
-
- /*
- * If user is disabling I/O and port is not in initial
- * state, fail with EINVAL.
- */
-
- if (((rport && !(ival & PCM_ENABLE_INPUT)) ||
- (wport && !(ival & PCM_ENABLE_OUTPUT))) &&
- aport->swstate != SW_INITIAL)
- return -EINVAL;
-
- if (rport) {
- vwsnd_port_hwstate_t hwstate;
- spin_lock_irqsave(&rport->lock, flags);
- {
- hwstate = rport->hwstate;
- if (ival & PCM_ENABLE_INPUT)
- rport->flags &= ~DISABLED;
- else
- rport->flags |= DISABLED;
- }
- spin_unlock_irqrestore(&rport->lock, flags);
- if (hwstate != HW_RUNNING && ival & PCM_ENABLE_INPUT) {
-
- if (rport->swstate == SW_INITIAL)
- pcm_setup(devc, rport, wport);
- else
- li_activate_dma(&rport->chan);
- }
- }
- if (wport) {
- vwsnd_port_flags_t pflags;
- spin_lock_irqsave(&wport->lock, flags);
- {
- pflags = wport->flags;
- if (ival & PCM_ENABLE_OUTPUT)
- wport->flags &= ~DISABLED;
- else
- wport->flags |= DISABLED;
- }
- spin_unlock_irqrestore(&wport->lock, flags);
- if (pflags & DISABLED && ival & PCM_ENABLE_OUTPUT) {
- if (wport->swstate == SW_RUN)
- pcm_output(devc, 0, 0);
- }
- }
- return 0;
-
- default:
- DBGP("unknown ioctl 0x%x\n", cmd);
- return -EINVAL;
- }
- DBGP("unimplemented ioctl 0x%x\n", cmd);
- return -EINVAL;
-}
-
-static long vwsnd_audio_ioctl(struct file *file,
- unsigned int cmd,
- unsigned long arg)
-{
- vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
- int ret;
-
- mutex_lock(&vwsnd_mutex);
- mutex_lock(&devc->io_mutex);
- ret = vwsnd_audio_do_ioctl(file, cmd, arg);
- mutex_unlock(&devc->io_mutex);
- mutex_unlock(&vwsnd_mutex);
-
- return ret;
-}
-
-/* No mmap. */
-
-static int vwsnd_audio_mmap(struct file *file, struct vm_area_struct *vma)
-{
- DBGE("(file=0x%p, vma=0x%p)\n", file, vma);
- return -ENODEV;
-}
-
-/*
- * Open the audio device for read and/or write.
- *
- * Returns 0 on success, -errno on failure.
- */
-
-static int vwsnd_audio_open(struct inode *inode, struct file *file)
-{
- vwsnd_dev_t *devc;
- int minor = iminor(inode);
- int sw_samplefmt;
- DEFINE_WAIT(wait);
-
- DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
-
- mutex_lock(&vwsnd_mutex);
- INC_USE_COUNT;
- for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
- if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F))
- break;
-
- if (devc == NULL) {
- DEC_USE_COUNT;
- mutex_unlock(&vwsnd_mutex);
- return -ENODEV;
- }
-
- mutex_lock(&devc->open_mutex);
- while (1) {
- prepare_to_wait(&devc->open_wait, &wait, TASK_INTERRUPTIBLE);
- if (!(devc->open_mode & file->f_mode))
- break;
-
- mutex_unlock(&devc->open_mutex);
- mutex_unlock(&vwsnd_mutex);
- if (file->f_flags & O_NONBLOCK) {
- DEC_USE_COUNT;
- return -EBUSY;
- }
- schedule();
- if (signal_pending(current)) {
- DEC_USE_COUNT;
- return -ERESTARTSYS;
- }
- mutex_lock(&vwsnd_mutex);
- mutex_lock(&devc->open_mutex);
- }
- finish_wait(&devc->open_wait, &wait);
- devc->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&devc->open_mutex);
-
- /* get default sample format from minor number. */
-
- sw_samplefmt = 0;
- if ((minor & 0xF) == SND_DEV_DSP)
- sw_samplefmt = AFMT_U8;
- else if ((minor & 0xF) == SND_DEV_AUDIO)
- sw_samplefmt = AFMT_MU_LAW;
- else if ((minor & 0xF) == SND_DEV_DSP16)
- sw_samplefmt = AFMT_S16_LE;
- else
- ASSERT(0);
-
- /* Initialize vwsnd_ports. */
-
- mutex_lock(&devc->io_mutex);
- {
- if (file->f_mode & FMODE_READ) {
- devc->rport.swstate = SW_INITIAL;
- devc->rport.flags = 0;
- devc->rport.sw_channels = 1;
- devc->rport.sw_samplefmt = sw_samplefmt;
- devc->rport.sw_framerate = 8000;
- devc->rport.sw_fragshift = DEFAULT_FRAGSHIFT;
- devc->rport.sw_fragcount = DEFAULT_FRAGCOUNT;
- devc->rport.sw_subdivshift = DEFAULT_SUBDIVSHIFT;
- devc->rport.byte_count = 0;
- devc->rport.frag_count = 0;
- }
- if (file->f_mode & FMODE_WRITE) {
- devc->wport.swstate = SW_INITIAL;
- devc->wport.flags = 0;
- devc->wport.sw_channels = 1;
- devc->wport.sw_samplefmt = sw_samplefmt;
- devc->wport.sw_framerate = 8000;
- devc->wport.sw_fragshift = DEFAULT_FRAGSHIFT;
- devc->wport.sw_fragcount = DEFAULT_FRAGCOUNT;
- devc->wport.sw_subdivshift = DEFAULT_SUBDIVSHIFT;
- devc->wport.byte_count = 0;
- devc->wport.frag_count = 0;
- }
- }
- mutex_unlock(&devc->io_mutex);
-
- file->private_data = devc;
- DBGRV();
- mutex_unlock(&vwsnd_mutex);
- return 0;
-}
-
-/*
- * Release (close) the audio device.
- */
-
-static int vwsnd_audio_release(struct inode *inode, struct file *file)
-{
- vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
- vwsnd_port_t *wport = NULL, *rport = NULL;
- int err = 0;
-
- mutex_lock(&vwsnd_mutex);
- mutex_lock(&devc->io_mutex);
- {
- DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
-
- if (file->f_mode & FMODE_READ)
- rport = &devc->rport;
- if (file->f_mode & FMODE_WRITE) {
- wport = &devc->wport;
- pcm_flush_frag(devc);
- pcm_write_sync(devc);
- }
- pcm_shutdown(devc, rport, wport);
- if (rport)
- rport->swstate = SW_OFF;
- if (wport)
- wport->swstate = SW_OFF;
- }
- mutex_unlock(&devc->io_mutex);
-
- mutex_lock(&devc->open_mutex);
- {
- devc->open_mode &= ~file->f_mode;
- }
- mutex_unlock(&devc->open_mutex);
- wake_up(&devc->open_wait);
- DEC_USE_COUNT;
- DBGR();
- mutex_unlock(&vwsnd_mutex);
- return err;
-}
-
-static const struct file_operations vwsnd_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = vwsnd_audio_read,
- .write = vwsnd_audio_write,
- .poll = vwsnd_audio_poll,
- .unlocked_ioctl = vwsnd_audio_ioctl,
- .mmap = vwsnd_audio_mmap,
- .open = vwsnd_audio_open,
- .release = vwsnd_audio_release,
-};
-
-/*****************************************************************************/
-/* mixer driver */
-
-/* open the mixer device. */
-
-static int vwsnd_mixer_open(struct inode *inode, struct file *file)
-{
- vwsnd_dev_t *devc;
-
- DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
-
- INC_USE_COUNT;
- mutex_lock(&vwsnd_mutex);
- for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
- if (devc->mixer_minor == iminor(inode))
- break;
-
- if (devc == NULL) {
- DEC_USE_COUNT;
- mutex_unlock(&vwsnd_mutex);
- return -ENODEV;
- }
- file->private_data = devc;
- mutex_unlock(&vwsnd_mutex);
- return 0;
-}
-
-/* release (close) the mixer device. */
-
-static int vwsnd_mixer_release(struct inode *inode, struct file *file)
-{
- DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
- DEC_USE_COUNT;
- return 0;
-}
-
-/* mixer_read_ioctl handles all read ioctls on the mixer device. */
-
-static int mixer_read_ioctl(vwsnd_dev_t *devc, unsigned int nr, void __user *arg)
-{
- int val = -1;
-
- DBGEV("(devc=0x%p, nr=0x%x, arg=0x%p)\n", devc, nr, arg);
-
- switch (nr) {
- case SOUND_MIXER_CAPS:
- val = SOUND_CAP_EXCL_INPUT;
- break;
-
- case SOUND_MIXER_DEVMASK:
- val = (SOUND_MASK_PCM | SOUND_MASK_LINE |
- SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_RECLEV);
- break;
-
- case SOUND_MIXER_STEREODEVS:
- val = (SOUND_MASK_PCM | SOUND_MASK_LINE |
- SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_RECLEV);
- break;
-
- case SOUND_MIXER_OUTMASK:
- val = (SOUND_MASK_PCM | SOUND_MASK_LINE |
- SOUND_MASK_MIC | SOUND_MASK_CD);
- break;
-
- case SOUND_MIXER_RECMASK:
- val = (SOUND_MASK_PCM | SOUND_MASK_LINE |
- SOUND_MASK_MIC | SOUND_MASK_CD);
- break;
-
- case SOUND_MIXER_PCM:
- val = ad1843_get_gain(&devc->lith, &ad1843_gain_PCM);
- break;
-
- case SOUND_MIXER_LINE:
- val = ad1843_get_gain(&devc->lith, &ad1843_gain_LINE);
- break;
-
- case SOUND_MIXER_MIC:
- val = ad1843_get_gain(&devc->lith, &ad1843_gain_MIC);
- break;
-
- case SOUND_MIXER_CD:
- val = ad1843_get_gain(&devc->lith, &ad1843_gain_CD);
- break;
-
- case SOUND_MIXER_RECLEV:
- val = ad1843_get_gain(&devc->lith, &ad1843_gain_RECLEV);
- break;
-
- case SOUND_MIXER_RECSRC:
- val = ad1843_get_recsrc(&devc->lith);
- break;
-
- case SOUND_MIXER_OUTSRC:
- val = ad1843_get_outsrc(&devc->lith);
- break;
-
- default:
- return -EINVAL;
- }
- return put_user(val, (int __user *) arg);
-}
-
-/* mixer_write_ioctl handles all write ioctls on the mixer device. */
-
-static int mixer_write_ioctl(vwsnd_dev_t *devc, unsigned int nr, void __user *arg)
-{
- int val;
- int err;
-
- DBGEV("(devc=0x%p, nr=0x%x, arg=0x%p)\n", devc, nr, arg);
-
- err = get_user(val, (int __user *) arg);
- if (err)
- return -EFAULT;
- switch (nr) {
- case SOUND_MIXER_PCM:
- val = ad1843_set_gain(&devc->lith, &ad1843_gain_PCM, val);
- break;
-
- case SOUND_MIXER_LINE:
- val = ad1843_set_gain(&devc->lith, &ad1843_gain_LINE, val);
- break;
-
- case SOUND_MIXER_MIC:
- val = ad1843_set_gain(&devc->lith, &ad1843_gain_MIC, val);
- break;
-
- case SOUND_MIXER_CD:
- val = ad1843_set_gain(&devc->lith, &ad1843_gain_CD, val);
- break;
-
- case SOUND_MIXER_RECLEV:
- val = ad1843_set_gain(&devc->lith, &ad1843_gain_RECLEV, val);
- break;
-
- case SOUND_MIXER_RECSRC:
- if (devc->rport.swbuf || devc->wport.swbuf)
- return -EBUSY; /* can't change recsrc while running */
- val = ad1843_set_recsrc(&devc->lith, val);
- break;
-
- case SOUND_MIXER_OUTSRC:
- val = ad1843_set_outsrc(&devc->lith, val);
- break;
-
- default:
- return -EINVAL;
- }
- if (val < 0)
- return val;
- return put_user(val, (int __user *) arg);
-}
-
-/* This is the ioctl entry to the mixer driver. */
-
-static long vwsnd_mixer_ioctl(struct file *file,
- unsigned int cmd,
- unsigned long arg)
-{
- vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
- const unsigned int nrmask = _IOC_NRMASK << _IOC_NRSHIFT;
- const unsigned int nr = (cmd & nrmask) >> _IOC_NRSHIFT;
- int retval;
-
- DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
-
- mutex_lock(&vwsnd_mutex);
- mutex_lock(&devc->mix_mutex);
- {
- if ((cmd & ~nrmask) == MIXER_READ(0))
- retval = mixer_read_ioctl(devc, nr, (void __user *) arg);
- else if ((cmd & ~nrmask) == MIXER_WRITE(0))
- retval = mixer_write_ioctl(devc, nr, (void __user *) arg);
- else
- retval = -EINVAL;
- }
- mutex_unlock(&devc->mix_mutex);
- mutex_unlock(&vwsnd_mutex);
- return retval;
-}
-
-static const struct file_operations vwsnd_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .unlocked_ioctl = vwsnd_mixer_ioctl,
- .open = vwsnd_mixer_open,
- .release = vwsnd_mixer_release,
-};
-
-/*****************************************************************************/
-/* probe/attach/unload */
-
-/* driver probe routine. Return nonzero if hardware is found. */
-
-static int __init probe_vwsnd(struct address_info *hw_config)
-{
- lithium_t lith;
- int w;
- unsigned long later;
-
- DBGEV("(hw_config=0x%p)\n", hw_config);
-
- /* XXX verify lithium present (to prevent crash on non-vw) */
-
- if (li_create(&lith, hw_config->io_base) != 0) {
- printk(KERN_WARNING "probe_vwsnd: can't map lithium\n");
- return 0;
- }
- later = jiffies + 2;
- li_writel(&lith, LI_HOST_CONTROLLER, LI_HC_LINK_ENABLE);
- do {
- w = li_readl(&lith, LI_HOST_CONTROLLER);
- } while (w == LI_HC_LINK_ENABLE && time_before(jiffies, later));
-
- li_destroy(&lith);
-
- DBGPV("HC = 0x%04x\n", w);
-
- if ((w == LI_HC_LINK_ENABLE) || (w & LI_HC_LINK_CODEC)) {
-
- /* This may indicate a beta machine with no audio,
- * or a future machine with different audio.
- * On beta-release 320 w/ no audio, HC == 0x4000 */
-
- printk(KERN_WARNING "probe_vwsnd: audio codec not found\n");
- return 0;
- }
-
- if (w & LI_HC_LINK_FAILURE) {
- printk(KERN_WARNING "probe_vwsnd: can't init audio codec\n");
- return 0;
- }
-
- printk(KERN_INFO "vwsnd: lithium audio at mmio %#x irq %d\n",
- hw_config->io_base, hw_config->irq);
-
- return 1;
-}
-
-/*
- * driver attach routine. Initialize driver data structures and
- * initialize hardware. A new vwsnd_dev_t is allocated and put
- * onto the global list, vwsnd_dev_list.
- *
- * Return +minor_dev on success, -errno on failure.
- */
-
-static int __init attach_vwsnd(struct address_info *hw_config)
-{
- vwsnd_dev_t *devc = NULL;
- int err = -ENOMEM;
-
- DBGEV("(hw_config=0x%p)\n", hw_config);
-
- devc = kmalloc(sizeof (vwsnd_dev_t), GFP_KERNEL);
- if (devc == NULL)
- goto fail0;
-
- err = li_create(&devc->lith, hw_config->io_base);
- if (err)
- goto fail1;
-
- init_waitqueue_head(&devc->open_wait);
-
- devc->rport.hwbuf_size = HWBUF_SIZE;
- devc->rport.hwbuf_vaddr = __get_free_pages(GFP_KERNEL, HWBUF_ORDER);
- if (!devc->rport.hwbuf_vaddr)
- goto fail2;
- devc->rport.hwbuf = (void *) devc->rport.hwbuf_vaddr;
- devc->rport.hwbuf_paddr = virt_to_phys(devc->rport.hwbuf);
-
- /*
- * Quote from the NT driver:
- *
- * // WARNING!!! HACK to setup output dma!!!
- * // This is required because even on output there is some data
- * // trickling into the input DMA channel. This is a bug in the
- * // Lithium microcode.
- * // --sde
- *
- * We set the input side's DMA base address here. It will remain
- * valid until the driver is unloaded.
- */
-
- li_writel(&devc->lith, LI_COMM1_BASE,
- devc->rport.hwbuf_paddr >> 8 | 1 << (37 - 8));
-
- devc->wport.hwbuf_size = HWBUF_SIZE;
- devc->wport.hwbuf_vaddr = __get_free_pages(GFP_KERNEL, HWBUF_ORDER);
- if (!devc->wport.hwbuf_vaddr)
- goto fail3;
- devc->wport.hwbuf = (void *) devc->wport.hwbuf_vaddr;
- devc->wport.hwbuf_paddr = virt_to_phys(devc->wport.hwbuf);
- DBGP("wport hwbuf = 0x%p\n", devc->wport.hwbuf);
-
- DBGDO(shut_up++);
- err = ad1843_init(&devc->lith);
- DBGDO(shut_up--);
- if (err)
- goto fail4;
-
- /* install interrupt handler */
-
- err = request_irq(hw_config->irq, vwsnd_audio_intr, 0, "vwsnd", devc);
- if (err)
- goto fail5;
-
- /* register this device's drivers. */
-
- devc->audio_minor = register_sound_dsp(&vwsnd_audio_fops, -1);
- if ((err = devc->audio_minor) < 0) {
- DBGDO(printk(KERN_WARNING
- "attach_vwsnd: register_sound_dsp error %d\n",
- err));
- goto fail6;
- }
- devc->mixer_minor = register_sound_mixer(&vwsnd_mixer_fops,
- devc->audio_minor >> 4);
- if ((err = devc->mixer_minor) < 0) {
- DBGDO(printk(KERN_WARNING
- "attach_vwsnd: register_sound_mixer error %d\n",
- err));
- goto fail7;
- }
-
- /* Squirrel away device indices for unload routine. */
-
- hw_config->slots[0] = devc->audio_minor;
-
- /* Initialize as much of *devc as possible */
-
- mutex_init(&devc->open_mutex);
- mutex_init(&devc->io_mutex);
- mutex_init(&devc->mix_mutex);
- devc->open_mode = 0;
- spin_lock_init(&devc->rport.lock);
- init_waitqueue_head(&devc->rport.queue);
- devc->rport.swstate = SW_OFF;
- devc->rport.hwstate = HW_STOPPED;
- devc->rport.flags = 0;
- devc->rport.swbuf = NULL;
- spin_lock_init(&devc->wport.lock);
- init_waitqueue_head(&devc->wport.queue);
- devc->wport.swstate = SW_OFF;
- devc->wport.hwstate = HW_STOPPED;
- devc->wport.flags = 0;
- devc->wport.swbuf = NULL;
-
- /* Success. Link us onto the local device list. */
-
- devc->next_dev = vwsnd_dev_list;
- vwsnd_dev_list = devc;
- return devc->audio_minor;
-
- /* So many ways to fail. Undo what we did. */
-
- fail7:
- unregister_sound_dsp(devc->audio_minor);
- fail6:
- free_irq(hw_config->irq, devc);
- fail5:
- fail4:
- free_pages(devc->wport.hwbuf_vaddr, HWBUF_ORDER);
- fail3:
- free_pages(devc->rport.hwbuf_vaddr, HWBUF_ORDER);
- fail2:
- li_destroy(&devc->lith);
- fail1:
- kfree(devc);
- fail0:
- return err;
-}
-
-static int __exit unload_vwsnd(struct address_info *hw_config)
-{
- vwsnd_dev_t *devc, **devcp;
-
- DBGE("()\n");
-
- devcp = &vwsnd_dev_list;
- while ((devc = *devcp)) {
- if (devc->audio_minor == hw_config->slots[0]) {
- *devcp = devc->next_dev;
- break;
- }
- devcp = &devc->next_dev;
- }
-
- if (!devc)
- return -ENODEV;
-
- unregister_sound_mixer(devc->mixer_minor);
- unregister_sound_dsp(devc->audio_minor);
- free_irq(hw_config->irq, devc);
- free_pages(devc->wport.hwbuf_vaddr, HWBUF_ORDER);
- free_pages(devc->rport.hwbuf_vaddr, HWBUF_ORDER);
- li_destroy(&devc->lith);
- kfree(devc);
-
- return 0;
-}
-
-/*****************************************************************************/
-/* initialization and loadable kernel module interface */
-
-static struct address_info the_hw_config = {
- 0xFF001000, /* lithium phys addr */
- CO_IRQ(CO_APIC_LI_AUDIO) /* irq */
-};
-
-MODULE_DESCRIPTION("SGI Visual Workstation sound module");
-MODULE_AUTHOR("Bob Miller <kbob@sgi.com>");
-MODULE_LICENSE("GPL");
-
-static int __init init_vwsnd(void)
-{
- int err;
-
- DBGXV("\n");
- DBGXV("sound::vwsnd::init_module()\n");
-
- if (!probe_vwsnd(&the_hw_config))
- return -ENODEV;
-
- err = attach_vwsnd(&the_hw_config);
- if (err < 0)
- return err;
- return 0;
-}
-
-static void __exit cleanup_vwsnd(void)
-{
- DBGX("sound::vwsnd::cleanup_module()\n");
-
- unload_vwsnd(&the_hw_config);
-}
-
-module_init(init_vwsnd);
-module_exit(cleanup_vwsnd);
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index 67f56a2cee6a..4b20be79c1dd 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -959,8 +959,6 @@ snd_harmony_create(struct snd_card *card,
goto free_and_ret;
}
- snd_card_set_dev(card, &padev->dev);
-
*rchip = h;
return 0;
@@ -977,7 +975,7 @@ snd_harmony_probe(struct parisc_device *padev)
struct snd_card *card;
struct snd_harmony *h;
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&padev->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 8756c8e32922..0b0c0cf13f74 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -276,7 +276,7 @@ config SND_CS46XX_NEW_DSP
config SND_CS5530
tristate "CS5530 Audio"
- depends on ISA_DMA_API
+ depends on ISA_DMA_API && (X86_32 || COMPILE_TEST)
select SND_SB16_DSP
help
Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips.
@@ -286,6 +286,7 @@ config SND_CS5530
config SND_CS5535AUDIO
tristate "CS5535/CS5536 Audio"
+ depends on X86_32 || MIPS || COMPILE_TEST
select SND_PCM
select SND_AC97_CODEC
help
@@ -578,8 +579,6 @@ config SND_FM801_TEA575X_BOOL
FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and
SF64-PCR) into the snd-fm801 driver.
-source "sound/pci/hda/Kconfig"
-
config SND_HDSP
tristate "RME Hammerfall DSP Audio"
select FW_LOADER
@@ -796,7 +795,7 @@ config SND_RME9652
config SND_SIS7019
tristate "SiS 7019 Audio Accelerator"
- depends on X86 && !X86_64
+ depends on X86_32
select SND_AC97_CODEC
select ZONE_DMA
help
@@ -889,3 +888,5 @@ config SND_YMFPCI
will be called snd-ymfpci.
endif # SND_PCI
+
+source "sound/pci/hda/Kconfig"
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index bf578ba2677e..14ad54b7928c 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -214,6 +214,12 @@ static void update_power_regs(struct snd_ac97 *ac97);
#define ac97_is_power_save_mode(ac97) 0
#endif
+#define ac97_err(ac97, fmt, args...) \
+ dev_err((ac97)->bus->card->dev, fmt, ##args)
+#define ac97_warn(ac97, fmt, args...) \
+ dev_warn((ac97)->bus->card->dev, fmt, ##args)
+#define ac97_dbg(ac97, fmt, args...) \
+ dev_dbg((ac97)->bus->card->dev, fmt, ##args)
/*
* I/O routines
@@ -1673,7 +1679,7 @@ static int snd_ac97_modem_build(struct snd_card *card, struct snd_ac97 * ac97)
int err, idx;
/*
- printk(KERN_DEBUG "AC97_GPIO_CFG = %x\n",
+ ac97_dbg(ac97, "AC97_GPIO_CFG = %x\n",
snd_ac97_read(ac97,AC97_GPIO_CFG));
*/
snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH));
@@ -1963,7 +1969,7 @@ static int snd_ac97_dev_register(struct snd_device *device)
ac97->bus->card->number, ac97->num,
snd_ac97_get_short_name(ac97));
if ((err = device_register(&ac97->dev)) < 0) {
- snd_printk(KERN_ERR "Can't register ac97 bus\n");
+ ac97_err(ac97, "Can't register ac97 bus\n");
ac97->dev.bus = NULL;
return err;
}
@@ -2089,7 +2095,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
msecs_to_jiffies(500), 1);
}
if (err < 0) {
- snd_printk(KERN_WARNING "AC'97 %d does not respond - RESET\n", ac97->num);
+ ac97_warn(ac97, "AC'97 %d does not respond - RESET\n",
+ ac97->num);
/* proceed anyway - it's often non-critical */
}
}
@@ -2098,7 +2105,9 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);
if (! (ac97->scaps & AC97_SCAP_DETECT_BY_VENDOR) &&
(ac97->id == 0x00000000 || ac97->id == 0xffffffff)) {
- snd_printk(KERN_ERR "AC'97 %d access is not valid [0x%x], removing mixer.\n", ac97->num, ac97->id);
+ ac97_err(ac97,
+ "AC'97 %d access is not valid [0x%x], removing mixer.\n",
+ ac97->num, ac97->id);
snd_ac97_free(ac97);
return -EIO;
}
@@ -2131,7 +2140,9 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
if (!ac97_is_audio(ac97) && !ac97_is_modem(ac97)) {
if (!(ac97->scaps & (AC97_SCAP_SKIP_AUDIO|AC97_SCAP_SKIP_MODEM)))
- snd_printk(KERN_ERR "AC'97 %d access error (not audio or modem codec)\n", ac97->num);
+ ac97_err(ac97,
+ "AC'97 %d access error (not audio or modem codec)\n",
+ ac97->num);
snd_ac97_free(ac97);
return -EACCES;
}
@@ -2156,7 +2167,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
goto __ready_ok;
schedule_timeout_uninterruptible(1);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_WARNING "AC'97 %d analog subsections not ready\n", ac97->num);
+ ac97_warn(ac97,
+ "AC'97 %d analog subsections not ready\n", ac97->num);
}
/* FIXME: add powerdown control */
@@ -2188,7 +2200,10 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
goto __ready_ok;
schedule_timeout_uninterruptible(1);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_WARNING "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS));
+ ac97_warn(ac97,
+ "MC'97 %d converters and GPIO not ready (0x%x)\n",
+ ac97->num,
+ snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS));
}
__ready_ok:
@@ -2723,7 +2738,7 @@ static int tune_ad_sharing(struct snd_ac97 *ac97)
{
unsigned short scfg;
if ((ac97->id & 0xffffff00) != 0x41445300) {
- snd_printk(KERN_ERR "ac97_quirk AD_SHARING is only for AD codecs\n");
+ ac97_err(ac97, "ac97_quirk AD_SHARING is only for AD codecs\n");
return -EINVAL;
}
/* Turn on OMS bit to route microphone to back panel */
@@ -2739,7 +2754,8 @@ AC97_SINGLE("Jack Detect", AC97_ALC650_CLOCK, 5, 1, 0);
static int tune_alc_jack(struct snd_ac97 *ac97)
{
if ((ac97->id & 0xffffff00) != 0x414c4700) {
- snd_printk(KERN_ERR "ac97_quirk ALC_JACK is only for Realtek codecs\n");
+ ac97_err(ac97,
+ "ac97_quirk ALC_JACK is only for Realtek codecs\n");
return -EINVAL;
}
snd_ac97_update_bits(ac97, 0x7a, 0x20, 0x20); /* select jack detect function */
@@ -2899,7 +2915,8 @@ int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, cons
if (override && strcmp(override, "-1") && strcmp(override, "default")) {
result = apply_quirk_str(ac97, override);
if (result < 0)
- snd_printk(KERN_ERR "applying quirk type %s failed (%d)\n", override, result);
+ ac97_err(ac97, "applying quirk type %s failed (%d)\n",
+ override, result);
return result;
}
@@ -2913,10 +2930,14 @@ int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, cons
quirk->subdevice == (quirk->mask & ac97->subsystem_device)) {
if (quirk->codec_id && quirk->codec_id != ac97->id)
continue;
- snd_printdd("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, ac97->subsystem_device);
+ ac97_dbg(ac97, "ac97 quirk for %s (%04x:%04x)\n",
+ quirk->name, ac97->subsystem_vendor,
+ ac97->subsystem_device);
result = apply_quirk(ac97, quirk->type);
if (result < 0)
- snd_printk(KERN_ERR "applying quirk type %d for %s failed (%d)\n", quirk->type, quirk->name, result);
+ ac97_err(ac97,
+ "applying quirk type %d for %s failed (%d)\n",
+ quirk->type, quirk->name, result);
return result;
}
}
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 66a3bc95fb84..991762215417 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -3477,7 +3477,8 @@ static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name,
sctl = snd_ac97_find_mixer_ctl(ac97, *s);
if (!sctl) {
- snd_printdd("Cannot find slave %s, skipped\n", *s);
+ dev_dbg(ac97->bus->card->dev,
+ "Cannot find slave %s, skipped\n", *s);
continue;
}
err = snd_ctl_add_slave(kctl, sctl);
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c
index eab0fc9ff2e0..d15297a68801 100644
--- a/sound/pci/ac97/ac97_pcm.c
+++ b/sound/pci/ac97/ac97_pcm.c
@@ -604,7 +604,9 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate,
}
if (!ok_flag) {
spin_unlock_irq(&pcm->bus->bus_lock);
- snd_printk(KERN_ERR "cannot find configuration for AC97 slot %i\n", i);
+ dev_err(bus->card->dev,
+ "cannot find configuration for AC97 slot %i\n",
+ i);
err = -EAGAIN;
goto error;
}
@@ -618,15 +620,20 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate,
if (pcm->r[r].rslots[cidx] & (1 << i)) {
reg = get_slot_reg(pcm, cidx, i, r);
if (reg == 0xff) {
- snd_printk(KERN_ERR "invalid AC97 slot %i?\n", i);
+ dev_err(bus->card->dev,
+ "invalid AC97 slot %i?\n", i);
continue;
}
if (reg_ok[cidx] & (1 << (reg - AC97_PCM_FRONT_DAC_RATE)))
continue;
- //printk(KERN_DEBUG "setting ac97 reg 0x%x to rate %d\n", reg, rate);
+ dev_dbg(bus->card->dev,
+ "setting ac97 reg 0x%x to rate %d\n",
+ reg, rate);
err = snd_ac97_set_rate(pcm->r[r].codec[cidx], reg, rate);
if (err < 0)
- snd_printk(KERN_ERR "error in snd_ac97_set_rate: cidx=%d, reg=0x%x, rate=%d, err=%d\n", cidx, reg, rate, err);
+ dev_err(bus->card->dev,
+ "error in snd_ac97_set_rate: cidx=%d, reg=0x%x, rate=%d, err=%d\n",
+ cidx, reg, rate, err);
else
reg_ok[cidx] |= (1 << (reg - AC97_PCM_FRONT_DAC_RATE));
}
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index b680d03e2419..488f966adde3 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -77,9 +77,6 @@ MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
#define DEVNAME "ad1889"
#define PFX DEVNAME ": "
-/* let's use the global sound debug interfaces */
-#define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg)
-
/* keep track of some hw registers */
struct ad1889_register_state {
u16 reg; /* reg setup */
@@ -264,11 +261,11 @@ snd_ad1889_ac97_ready(struct snd_ad1889 *chip)
&& --retry)
mdelay(1);
if (!retry) {
- snd_printk(KERN_ERR PFX "[%s] Link is not ready.\n",
- __func__);
+ dev_err(chip->card->dev, "[%s] Link is not ready.\n",
+ __func__);
return -EIO;
}
- ad1889_debug("[%s] ready after %d ms\n", __func__, 400 - retry);
+ dev_dbg(chip->card->dev, "[%s] ready after %d ms\n", __func__, 400 - retry);
return 0;
}
@@ -405,9 +402,9 @@ snd_ad1889_playback_prepare(struct snd_pcm_substream *ss)
spin_unlock_irq(&chip->lock);
- ad1889_debug("prepare playback: addr = 0x%x, count = %u, "
- "size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr,
- count, size, reg, rt->rate);
+ dev_dbg(chip->card->dev,
+ "prepare playback: addr = 0x%x, count = %u, size = %u, reg = 0x%x, rate = %u\n",
+ chip->wave.addr, count, size, reg, rt->rate);
return 0;
}
@@ -452,9 +449,9 @@ snd_ad1889_capture_prepare(struct snd_pcm_substream *ss)
spin_unlock_irq(&chip->lock);
- ad1889_debug("prepare capture: addr = 0x%x, count = %u, "
- "size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr,
- count, size, reg, rt->rate);
+ dev_dbg(chip->card->dev,
+ "prepare capture: addr = 0x%x, count = %u, size = %u, reg = 0x%x, rate = %u\n",
+ chip->ramc.addr, count, size, reg, rt->rate);
return 0;
}
@@ -614,7 +611,8 @@ snd_ad1889_interrupt(int irq, void *dev_id)
return IRQ_NONE;
if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI))
- ad1889_debug("Unexpected master or target abort interrupt!\n");
+ dev_dbg(chip->card->dev,
+ "Unexpected master or target abort interrupt!\n");
if ((st & AD_DMA_DISR_WAVI) && chip->psubs)
snd_pcm_period_elapsed(chip->psubs);
@@ -656,7 +654,7 @@ snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm)
BUFFER_BYTES_MAX);
if (err < 0) {
- snd_printk(KERN_ERR PFX "buffer allocation error: %d\n", err);
+ dev_err(chip->card->dev, "buffer allocation error: %d\n", err);
return err;
}
@@ -912,7 +910,7 @@ snd_ad1889_create(struct snd_card *card,
/* check PCI availability (32bit DMA) */
if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
- printk(KERN_ERR PFX "error setting 32-bit DMA mask.\n");
+ dev_err(card->dev, "error setting 32-bit DMA mask.\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -935,7 +933,7 @@ snd_ad1889_create(struct snd_card *card,
chip->bar = pci_resource_start(pci, 0);
chip->iobase = pci_ioremap_bar(pci, 0);
if (chip->iobase == NULL) {
- printk(KERN_ERR PFX "unable to reserve region.\n");
+ dev_err(card->dev, "unable to reserve region.\n");
err = -EBUSY;
goto free_and_ret;
}
@@ -946,7 +944,7 @@ snd_ad1889_create(struct snd_card *card,
if (request_irq(pci->irq, snd_ad1889_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
- printk(KERN_ERR PFX "cannot obtain IRQ %d\n", pci->irq);
+ dev_err(card->dev, "cannot obtain IRQ %d\n", pci->irq);
snd_ad1889_free(chip);
return -EBUSY;
}
@@ -965,8 +963,6 @@ snd_ad1889_create(struct snd_card *card,
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
return 0;
@@ -996,7 +992,8 @@ snd_ad1889_probe(struct pci_dev *pci,
}
/* (2) */
- err = snd_card_create(index[devno], id[devno], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[devno], id[devno], THIS_MODULE,
+ 0, &card);
/* XXX REVISIT: we can probably allocate chip in this call */
if (err < 0)
return err;
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index c6835a3d64fb..feb29c24cab1 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -65,18 +65,6 @@ module_param(enable, bool, 0444);
/*
- * Debug part definitions
- */
-
-/* #define ALI_DEBUG */
-
-#ifdef ALI_DEBUG
-#define snd_ali_printk(format, args...) printk(KERN_DEBUG format, ##args);
-#else
-#define snd_ali_printk(format, args...)
-#endif
-
-/*
* Constants definition
*/
@@ -321,7 +309,7 @@ static int snd_ali_codec_ready(struct snd_ali *codec,
}
snd_ali_5451_poke(codec, port, res & ~0x8000);
- snd_printdd("ali_codec_ready: codec is not ready.\n ");
+ dev_dbg(codec->card->dev, "ali_codec_ready: codec is not ready.\n ");
return -EIO;
}
@@ -342,7 +330,7 @@ static int snd_ali_stimer_ready(struct snd_ali *codec)
schedule_timeout_uninterruptible(1);
}
- snd_printk(KERN_ERR "ali_stimer_read: stimer is not ready.\n");
+ dev_err(codec->card->dev, "ali_stimer_read: stimer is not ready.\n");
return -EIO;
}
@@ -354,7 +342,8 @@ static void snd_ali_codec_poke(struct snd_ali *codec,int secondary,
unsigned int port;
if (reg >= 0x80) {
- snd_printk(KERN_ERR "ali_codec_poke: reg(%xh) invalid.\n", reg);
+ dev_err(codec->card->dev,
+ "ali_codec_poke: reg(%xh) invalid.\n", reg);
return;
}
@@ -385,7 +374,8 @@ static unsigned short snd_ali_codec_peek(struct snd_ali *codec,
unsigned int port;
if (reg >= 0x80) {
- snd_printk(KERN_ERR "ali_codec_peek: reg(%xh) invalid.\n", reg);
+ dev_err(codec->card->dev,
+ "ali_codec_peek: reg(%xh) invalid.\n", reg);
return ~0;
}
@@ -417,7 +407,7 @@ static void snd_ali_codec_write(struct snd_ac97 *ac97,
{
struct snd_ali *codec = ac97->private_data;
- snd_ali_printk("codec_write: reg=%xh data=%xh.\n", reg, val);
+ dev_dbg(codec->card->dev, "codec_write: reg=%xh data=%xh.\n", reg, val);
if (reg == AC97_GPIO_STATUS) {
outl((val << ALI_AC97_GPIO_DATA_SHIFT) | ALI_AC97_GPIO_ENABLE,
ALI_REG(codec, ALI_AC97_GPIO));
@@ -433,7 +423,7 @@ static unsigned short snd_ali_codec_read(struct snd_ac97 *ac97,
{
struct snd_ali *codec = ac97->private_data;
- snd_ali_printk("codec_read reg=%xh.\n", reg);
+ dev_dbg(codec->card->dev, "codec_read reg=%xh.\n", reg);
return snd_ali_codec_peek(codec, ac97->num, reg);
}
@@ -474,7 +464,7 @@ static int snd_ali_reset_5451(struct snd_ali *codec)
}
/* non-fatal if you have a non PM capable codec */
- /* snd_printk(KERN_WARNING "ali5451: reset time out\n"); */
+ /* dev_warn(codec->card->dev, "ali5451: reset time out\n"); */
return 0;
}
@@ -528,7 +518,7 @@ static void snd_ali_disable_voice_irq(struct snd_ali *codec,
unsigned int mask;
struct snd_ali_channel_control *pchregs = &(codec->chregs);
- snd_ali_printk("disable_voice_irq channel=%d\n",channel);
+ dev_dbg(codec->card->dev, "disable_voice_irq channel=%d\n", channel);
mask = 1 << (channel & 0x1f);
pchregs->data.ainten = inl(ALI_REG(codec, pchregs->regs.ainten));
@@ -541,7 +531,7 @@ static int snd_ali_alloc_pcm_channel(struct snd_ali *codec, int channel)
unsigned int idx = channel & 0x1f;
if (codec->synth.chcnt >= ALI_CHANNELS){
- snd_printk(KERN_ERR
+ dev_err(codec->card->dev,
"ali_alloc_pcm_channel: no free channels.\n");
return -1;
}
@@ -549,7 +539,7 @@ static int snd_ali_alloc_pcm_channel(struct snd_ali *codec, int channel)
if (!(codec->synth.chmap & (1 << idx))) {
codec->synth.chmap |= 1 << idx;
codec->synth.chcnt++;
- snd_ali_printk("alloc_pcm_channel no. %d.\n",idx);
+ dev_dbg(codec->card->dev, "alloc_pcm_channel no. %d.\n", idx);
return idx;
}
return -1;
@@ -560,7 +550,8 @@ static int snd_ali_find_free_channel(struct snd_ali * codec, int rec)
int idx;
int result = -1;
- snd_ali_printk("find_free_channel: for %s\n",rec ? "rec" : "pcm");
+ dev_dbg(codec->card->dev,
+ "find_free_channel: for %s\n", rec ? "rec" : "pcm");
/* recording */
if (rec) {
@@ -575,8 +566,8 @@ static int snd_ali_find_free_channel(struct snd_ali * codec, int rec)
if (result >= 0)
return result;
else {
- snd_printk(KERN_ERR "ali_find_free_channel: "
- "record channel is busy now.\n");
+ dev_err(codec->card->dev,
+ "ali_find_free_channel: record channel is busy now.\n");
return -1;
}
}
@@ -590,8 +581,8 @@ static int snd_ali_find_free_channel(struct snd_ali * codec, int rec)
if (result >= 0)
return result;
else
- snd_printk(KERN_ERR "ali_find_free_channel: "
- "S/PDIF out channel is in busy now.\n");
+ dev_err(codec->card->dev,
+ "ali_find_free_channel: S/PDIF out channel is in busy now.\n");
}
for (idx = 0; idx < ALI_CHANNELS; idx++) {
@@ -599,7 +590,7 @@ static int snd_ali_find_free_channel(struct snd_ali * codec, int rec)
if (result >= 0)
return result;
}
- snd_printk(KERN_ERR "ali_find_free_channel: no free channels.\n");
+ dev_err(codec->card->dev, "ali_find_free_channel: no free channels.\n");
return -1;
}
@@ -607,14 +598,15 @@ static void snd_ali_free_channel_pcm(struct snd_ali *codec, int channel)
{
unsigned int idx = channel & 0x0000001f;
- snd_ali_printk("free_channel_pcm channel=%d\n",channel);
+ dev_dbg(codec->card->dev, "free_channel_pcm channel=%d\n", channel);
if (channel < 0 || channel >= ALI_CHANNELS)
return;
if (!(codec->synth.chmap & (1 << idx))) {
- snd_printk(KERN_ERR "ali_free_channel_pcm: "
- "channel %d is not in use.\n", channel);
+ dev_err(codec->card->dev,
+ "ali_free_channel_pcm: channel %d is not in use.\n",
+ channel);
return;
} else {
codec->synth.chmap &= ~(1 << idx);
@@ -626,7 +618,7 @@ static void snd_ali_stop_voice(struct snd_ali *codec, unsigned int channel)
{
unsigned int mask = 1 << (channel & 0x1f);
- snd_ali_printk("stop_voice: channel=%d\n",channel);
+ dev_dbg(codec->card->dev, "stop_voice: channel=%d\n", channel);
outl(mask, ALI_REG(codec, codec->chregs.regs.stop));
}
@@ -667,7 +659,7 @@ static void snd_ali_detect_spdif_rate(struct snd_ali *codec)
}
if (count > 50000) {
- snd_printk(KERN_ERR "ali_detect_spdif_rate: timeout!\n");
+ dev_err(codec->card->dev, "ali_detect_spdif_rate: timeout!\n");
return;
}
@@ -682,7 +674,7 @@ static void snd_ali_detect_spdif_rate(struct snd_ali *codec)
}
if (count > 50000) {
- snd_printk(KERN_ERR "ali_detect_spdif_rate: timeout!\n");
+ dev_err(codec->card->dev, "ali_detect_spdif_rate: timeout!\n");
return;
}
@@ -857,9 +849,6 @@ static void snd_ali_update_ptr(struct snd_ali *codec, int channel)
struct snd_ali_voice *pvoice;
struct snd_ali_channel_control *pchregs;
unsigned int old, mask;
-#ifdef ALI_DEBUG
- unsigned int temp, cspf;
-#endif
pchregs = &(codec->chregs);
@@ -877,14 +866,11 @@ static void snd_ali_update_ptr(struct snd_ali *codec, int channel)
if (pvoice->pcm && pvoice->substream) {
/* pcm interrupt */
-#ifdef ALI_DEBUG
- outb((u8)(pvoice->number), ALI_REG(codec, ALI_GC_CIR));
- temp = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));
- cspf = (inl(ALI_REG(codec, ALI_CSPF)) & mask) == mask;
-#endif
if (pvoice->running) {
- snd_ali_printk("update_ptr: cso=%4.4x cspf=%d.\n",
- (u16)temp, cspf);
+ dev_dbg(codec->card->dev,
+ "update_ptr: cso=%4.4x cspf=%d.\n",
+ inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2)),
+ (inl(ALI_REG(codec, ALI_CSPF)) & mask) == mask);
spin_unlock(&codec->reg_lock);
snd_pcm_period_elapsed(pvoice->substream);
spin_lock(&codec->reg_lock);
@@ -940,14 +926,14 @@ static struct snd_ali_voice *snd_ali_alloc_voice(struct snd_ali * codec,
struct snd_ali_voice *pvoice;
int idx;
- snd_ali_printk("alloc_voice: type=%d rec=%d\n", type, rec);
+ dev_dbg(codec->card->dev, "alloc_voice: type=%d rec=%d\n", type, rec);
spin_lock_irq(&codec->voice_alloc);
if (type == SNDRV_ALI_VOICE_TYPE_PCM) {
idx = channel > 0 ? snd_ali_alloc_pcm_channel(codec, channel) :
snd_ali_find_free_channel(codec,rec);
if (idx < 0) {
- snd_printk(KERN_ERR "ali_alloc_voice: err.\n");
+ dev_err(codec->card->dev, "ali_alloc_voice: err.\n");
spin_unlock_irq(&codec->voice_alloc);
return NULL;
}
@@ -970,7 +956,7 @@ static void snd_ali_free_voice(struct snd_ali * codec,
void (*private_free)(void *);
void *private_data;
- snd_ali_printk("free_voice: channel=%d\n",pvoice->number);
+ dev_dbg(codec->card->dev, "free_voice: channel=%d\n", pvoice->number);
if (!pvoice->use)
return;
snd_ali_clear_voices(codec, pvoice->number, pvoice->number);
@@ -1153,7 +1139,7 @@ static int snd_ali_trigger(struct snd_pcm_substream *substream,
outl(val, ALI_REG(codec, ALI_AINTEN));
if (do_start)
outl(what, ALI_REG(codec, ALI_START));
- snd_ali_printk("trigger: what=%xh whati=%xh\n", what, whati);
+ dev_dbg(codec->card->dev, "trigger: what=%xh whati=%xh\n", what, whati);
spin_unlock(&codec->reg_lock);
return 0;
@@ -1239,7 +1225,7 @@ static int snd_ali_playback_prepare(struct snd_pcm_substream *substream)
unsigned int VOL;
unsigned int EC;
- snd_ali_printk("playback_prepare ...\n");
+ dev_dbg(codec->card->dev, "playback_prepare ...\n");
spin_lock_irq(&codec->reg_lock);
@@ -1266,7 +1252,7 @@ static int snd_ali_playback_prepare(struct snd_pcm_substream *substream)
/* set target ESO for channel */
pvoice->eso = runtime->buffer_size;
- snd_ali_printk("playback_prepare: eso=%xh count=%xh\n",
+ dev_dbg(codec->card->dev, "playback_prepare: eso=%xh count=%xh\n",
pvoice->eso, pvoice->count);
/* set ESO to capture first MIDLP interrupt */
@@ -1278,8 +1264,9 @@ static int snd_ali_playback_prepare(struct snd_pcm_substream *substream)
PAN = 0;
VOL = 0;
EC = 0;
- snd_ali_printk("playback_prepare:\n");
- snd_ali_printk("ch=%d, Rate=%d Delta=%xh,GVSEL=%xh,PAN=%xh,CTRL=%xh\n",
+ dev_dbg(codec->card->dev, "playback_prepare:\n");
+ dev_dbg(codec->card->dev,
+ "ch=%d, Rate=%d Delta=%xh,GVSEL=%xh,PAN=%xh,CTRL=%xh\n",
pvoice->number,runtime->rate,Delta,GVSEL,PAN,CTRL);
snd_ali_write_voice_regs(codec,
pvoice->number,
@@ -1332,7 +1319,7 @@ static int snd_ali_prepare(struct snd_pcm_substream *substream)
spin_lock_irq(&codec->reg_lock);
- snd_ali_printk("ali_prepare...\n");
+ dev_dbg(codec->card->dev, "ali_prepare...\n");
snd_ali_enable_special_channel(codec,pvoice->number);
@@ -1351,15 +1338,16 @@ static int snd_ali_prepare(struct snd_pcm_substream *substream)
rate = snd_ali_get_spdif_in_rate(codec);
if (rate == 0) {
- snd_printk(KERN_WARNING "ali_capture_preapre: "
- "spdif rate detect err!\n");
+ dev_warn(codec->card->dev,
+ "ali_capture_preapre: spdif rate detect err!\n");
rate = 48000;
}
spin_lock_irq(&codec->reg_lock);
bValue = inb(ALI_REG(codec,ALI_SPDIF_CTRL));
if (bValue & 0x10) {
outb(bValue,ALI_REG(codec,ALI_SPDIF_CTRL));
- printk(KERN_WARNING "clear SPDIF parity error flag.\n");
+ dev_warn(codec->card->dev,
+ "clear SPDIF parity error flag.\n");
}
if (rate != 48000)
@@ -1418,7 +1406,7 @@ snd_ali_playback_pointer(struct snd_pcm_substream *substream)
outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR));
cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));
spin_unlock(&codec->reg_lock);
- snd_ali_printk("playback pointer returned cso=%xh.\n", cso);
+ dev_dbg(codec->card->dev, "playback pointer returned cso=%xh.\n", cso);
return cso;
}
@@ -1685,7 +1673,8 @@ static int snd_ali_pcm(struct snd_ali *codec, int device,
err = snd_pcm_new(codec->card, desc->name, device,
desc->playback_num, desc->capture_num, &pcm);
if (err < 0) {
- snd_printk(KERN_ERR "snd_ali_pcm: err called snd_pcm_new.\n");
+ dev_err(codec->card->dev,
+ "snd_ali_pcm: err called snd_pcm_new.\n");
return err;
}
pcm->private_data = codec;
@@ -1861,7 +1850,7 @@ static int snd_ali_mixer(struct snd_ali *codec)
ac97.num = i;
err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97[i]);
if (err < 0) {
- snd_printk(KERN_ERR
+ dev_err(codec->card->dev,
"ali mixer %d creating error.\n", i);
if (i == 0)
return err;
@@ -1947,8 +1936,7 @@ static int ali_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "ali5451: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -2013,10 +2001,10 @@ static int snd_ali_chip_init(struct snd_ali *codec)
unsigned char temp;
struct pci_dev *pci_dev;
- snd_ali_printk("chip initializing ... \n");
+ dev_dbg(codec->card->dev, "chip initializing ...\n");
if (snd_ali_reset_5451(codec)) {
- snd_printk(KERN_ERR "ali_chip_init: reset 5451 error.\n");
+ dev_err(codec->card->dev, "ali_chip_init: reset 5451 error.\n");
return -1;
}
@@ -2062,7 +2050,7 @@ static int snd_ali_chip_init(struct snd_ali *codec)
ALI_REG(codec, ALI_SCTRL));
}
- snd_ali_printk("chip initialize succeed.\n");
+ dev_dbg(codec->card->dev, "chip initialize succeed.\n");
return 0;
}
@@ -2088,7 +2076,7 @@ static int snd_ali_resources(struct snd_ali *codec)
{
int err;
- snd_ali_printk("resources allocation ...\n");
+ dev_dbg(codec->card->dev, "resources allocation ...\n");
err = pci_request_regions(codec->pci, "ALI 5451");
if (err < 0)
return err;
@@ -2096,11 +2084,11 @@ static int snd_ali_resources(struct snd_ali *codec)
if (request_irq(codec->pci->irq, snd_ali_card_interrupt,
IRQF_SHARED, KBUILD_MODNAME, codec)) {
- snd_printk(KERN_ERR "Unable to request irq.\n");
+ dev_err(codec->card->dev, "Unable to request irq.\n");
return -EBUSY;
}
codec->irq = codec->pci->irq;
- snd_ali_printk("resources allocated.\n");
+ dev_dbg(codec->card->dev, "resources allocated.\n");
return 0;
}
static int snd_ali_dev_free(struct snd_device *device)
@@ -2125,7 +2113,7 @@ static int snd_ali_create(struct snd_card *card,
*r_ali = NULL;
- snd_ali_printk("creating ...\n");
+ dev_dbg(card->dev, "creating ...\n");
/* enable PCI device */
err = pci_enable_device(pci);
@@ -2134,8 +2122,8 @@ static int snd_ali_create(struct snd_card *card,
/* check, if we can restrict PCI DMA transfers to 31 bits */
if (pci_set_dma_mask(pci, DMA_BIT_MASK(31)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(31)) < 0) {
- snd_printk(KERN_ERR "architecture does not support "
- "31bit PCI busmaster DMA\n");
+ dev_err(card->dev,
+ "architecture does not support 31bit PCI busmaster DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -2199,48 +2187,46 @@ static int snd_ali_create(struct snd_card *card,
/* M1533: southbridge */
codec->pci_m1533 = pci_get_device(0x10b9, 0x1533, NULL);
if (!codec->pci_m1533) {
- snd_printk(KERN_ERR "ali5451: cannot find ALi 1533 chip.\n");
+ dev_err(card->dev, "cannot find ALi 1533 chip.\n");
snd_ali_free(codec);
return -ENODEV;
}
/* M7101: power management */
codec->pci_m7101 = pci_get_device(0x10b9, 0x7101, NULL);
if (!codec->pci_m7101 && codec->revision == ALI_5451_V02) {
- snd_printk(KERN_ERR "ali5451: cannot find ALi 7101 chip.\n");
+ dev_err(card->dev, "cannot find ALi 7101 chip.\n");
snd_ali_free(codec);
return -ENODEV;
}
- snd_ali_printk("snd_device_new is called.\n");
+ dev_dbg(card->dev, "snd_device_new is called.\n");
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops);
if (err < 0) {
snd_ali_free(codec);
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
/* initialise synth voices*/
for (i = 0; i < ALI_CHANNELS; i++)
codec->synth.voices[i].number = i;
err = snd_ali_chip_init(codec);
if (err < 0) {
- snd_printk(KERN_ERR "ali create: chip init error.\n");
+ dev_err(card->dev, "ali create: chip init error.\n");
return err;
}
#ifdef CONFIG_PM_SLEEP
codec->image = kmalloc(sizeof(*codec->image), GFP_KERNEL);
if (!codec->image)
- snd_printk(KERN_WARNING "can't allocate apm buffer\n");
+ dev_warn(card->dev, "can't allocate apm buffer\n");
#endif
snd_ali_enable_address_interrupt(codec);
codec->hw_initialized = 1;
*r_ali = codec;
- snd_ali_printk("created.\n");
+ dev_dbg(card->dev, "created.\n");
return 0;
}
@@ -2251,9 +2237,9 @@ static int snd_ali_probe(struct pci_dev *pci,
struct snd_ali *codec;
int err;
- snd_ali_printk("probe ...\n");
+ dev_dbg(&pci->dev, "probe ...\n");
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -2262,12 +2248,12 @@ static int snd_ali_probe(struct pci_dev *pci,
goto error;
card->private_data = codec;
- snd_ali_printk("mixer building ...\n");
+ dev_dbg(&pci->dev, "mixer building ...\n");
err = snd_ali_mixer(codec);
if (err < 0)
goto error;
- snd_ali_printk("pcm building ...\n");
+ dev_dbg(&pci->dev, "pcm building ...\n");
err = snd_ali_build_pcms(codec);
if (err < 0)
goto error;
@@ -2280,7 +2266,7 @@ static int snd_ali_probe(struct pci_dev *pci,
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, codec->port, codec->irq);
- snd_ali_printk("register card.\n");
+ dev_dbg(&pci->dev, "register card.\n");
err = snd_card_register(card);
if (err < 0)
goto error;
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 591efb6eef05..cc9a15a1304b 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -87,19 +87,8 @@
#define PLAYBACK_BLOCK_COUNTER 0x9A
#define RECORD_BLOCK_COUNTER 0x9B
-#define DEBUG_CALLS 0
#define DEBUG_PLAY_REC 0
-#if DEBUG_CALLS
-#define snd_als300_dbgcalls(format, args...) printk(KERN_DEBUG format, ##args)
-#define snd_als300_dbgcallenter() printk(KERN_ERR "--> %s\n", __func__)
-#define snd_als300_dbgcallleave() printk(KERN_ERR "<-- %s\n", __func__)
-#else
-#define snd_als300_dbgcalls(format, args...)
-#define snd_als300_dbgcallenter()
-#define snd_als300_dbgcallleave()
-#endif
-
#if DEBUG_PLAY_REC
#define snd_als300_dbgplay(format, args...) printk(KERN_ERR format, ##args)
#else
@@ -177,7 +166,6 @@ static inline void snd_als300_gcr_write(unsigned long port,
static void snd_als300_set_irq_flag(struct snd_als300 *chip, int cmd)
{
u32 tmp = snd_als300_gcr_read(chip->port, MISC_CONTROL);
- snd_als300_dbgcallenter();
/* boolean XOR check, since old vs. new hardware have
directly reversed bit setting for ENABLE and DISABLE.
@@ -188,19 +176,16 @@ static void snd_als300_set_irq_flag(struct snd_als300 *chip, int cmd)
else
tmp &= ~IRQ_SET_BIT;
snd_als300_gcr_write(chip->port, MISC_CONTROL, tmp);
- snd_als300_dbgcallleave();
}
static int snd_als300_free(struct snd_als300 *chip)
{
- snd_als300_dbgcallenter();
snd_als300_set_irq_flag(chip, IRQ_DISABLE);
if (chip->irq >= 0)
free_irq(chip->irq, chip);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip);
- snd_als300_dbgcallleave();
return 0;
}
@@ -280,9 +265,7 @@ static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id)
static void snd_als300_remove(struct pci_dev *pci)
{
- snd_als300_dbgcallenter();
snd_card_free(pci_get_drvdata(pci));
- snd_als300_dbgcallleave();
}
static unsigned short snd_als300_ac97_read(struct snd_ac97 *ac97,
@@ -330,14 +313,12 @@ static int snd_als300_ac97(struct snd_als300 *chip)
.read = snd_als300_ac97_read,
};
- snd_als300_dbgcallenter();
if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus)) < 0)
return err;
memset(&ac97, 0, sizeof(ac97));
ac97.private_data = chip;
- snd_als300_dbgcallleave();
return snd_ac97_mixer(bus, &ac97, &chip->ac97);
}
@@ -395,13 +376,11 @@ static int snd_als300_playback_open(struct snd_pcm_substream *substream)
if (!data)
return -ENOMEM;
- snd_als300_dbgcallenter();
chip->playback_substream = substream;
runtime->hw = snd_als300_playback_hw;
runtime->private_data = data;
data->control_register = PLAYBACK_CONTROL;
data->block_counter_register = PLAYBACK_BLOCK_COUNTER;
- snd_als300_dbgcallleave();
return 0;
}
@@ -411,11 +390,9 @@ static int snd_als300_playback_close(struct snd_pcm_substream *substream)
struct snd_als300_substream_data *data;
data = substream->runtime->private_data;
- snd_als300_dbgcallenter();
kfree(data);
chip->playback_substream = NULL;
snd_pcm_lib_free_pages(substream);
- snd_als300_dbgcallleave();
return 0;
}
@@ -428,13 +405,11 @@ static int snd_als300_capture_open(struct snd_pcm_substream *substream)
if (!data)
return -ENOMEM;
- snd_als300_dbgcallenter();
chip->capture_substream = substream;
runtime->hw = snd_als300_capture_hw;
runtime->private_data = data;
data->control_register = RECORD_CONTROL;
data->block_counter_register = RECORD_BLOCK_COUNTER;
- snd_als300_dbgcallleave();
return 0;
}
@@ -444,11 +419,9 @@ static int snd_als300_capture_close(struct snd_pcm_substream *substream)
struct snd_als300_substream_data *data;
data = substream->runtime->private_data;
- snd_als300_dbgcallenter();
kfree(data);
chip->capture_substream = NULL;
snd_pcm_lib_free_pages(substream);
- snd_als300_dbgcallleave();
return 0;
}
@@ -472,7 +445,6 @@ static int snd_als300_playback_prepare(struct snd_pcm_substream *substream)
unsigned short period_bytes = snd_pcm_lib_period_bytes(substream);
unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
- snd_als300_dbgcallenter();
spin_lock_irq(&chip->reg_lock);
tmp = snd_als300_gcr_read(chip->port, PLAYBACK_CONTROL);
tmp &= ~TRANSFER_START;
@@ -491,7 +463,6 @@ static int snd_als300_playback_prepare(struct snd_pcm_substream *substream)
snd_als300_gcr_write(chip->port, PLAYBACK_END,
runtime->dma_addr + buffer_bytes - 1);
spin_unlock_irq(&chip->reg_lock);
- snd_als300_dbgcallleave();
return 0;
}
@@ -503,7 +474,6 @@ static int snd_als300_capture_prepare(struct snd_pcm_substream *substream)
unsigned short period_bytes = snd_pcm_lib_period_bytes(substream);
unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
- snd_als300_dbgcallenter();
spin_lock_irq(&chip->reg_lock);
tmp = snd_als300_gcr_read(chip->port, RECORD_CONTROL);
tmp &= ~TRANSFER_START;
@@ -522,7 +492,6 @@ static int snd_als300_capture_prepare(struct snd_pcm_substream *substream)
snd_als300_gcr_write(chip->port, RECORD_END,
runtime->dma_addr + buffer_bytes - 1);
spin_unlock_irq(&chip->reg_lock);
- snd_als300_dbgcallleave();
return 0;
}
@@ -537,7 +506,6 @@ static int snd_als300_trigger(struct snd_pcm_substream *substream, int cmd)
data = substream->runtime->private_data;
reg = data->control_register;
- snd_als300_dbgcallenter();
spin_lock(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -568,7 +536,6 @@ static int snd_als300_trigger(struct snd_pcm_substream *substream, int cmd)
ret = -EINVAL;
}
spin_unlock(&chip->reg_lock);
- snd_als300_dbgcallleave();
return ret;
}
@@ -582,7 +549,6 @@ static snd_pcm_uframes_t snd_als300_pointer(struct snd_pcm_substream *substream)
data = substream->runtime->private_data;
period_bytes = snd_pcm_lib_period_bytes(substream);
- snd_als300_dbgcallenter();
spin_lock(&chip->reg_lock);
current_ptr = (u16) snd_als300_gcr_read(chip->port,
data->block_counter_register) + 4;
@@ -595,7 +561,6 @@ static snd_pcm_uframes_t snd_als300_pointer(struct snd_pcm_substream *substream)
if (data->period_flipflop == 0)
current_ptr += period_bytes;
snd_als300_dbgplay("Pointer (bytes): %d\n", current_ptr);
- snd_als300_dbgcallleave();
return bytes_to_frames(substream->runtime, current_ptr);
}
@@ -626,7 +591,6 @@ static int snd_als300_new_pcm(struct snd_als300 *chip)
struct snd_pcm *pcm;
int err;
- snd_als300_dbgcallenter();
err = snd_pcm_new(chip->card, "ALS300", 0, 1, 1, &pcm);
if (err < 0)
return err;
@@ -643,7 +607,6 @@ static int snd_als300_new_pcm(struct snd_als300 *chip)
/* pre-allocation of buffers */
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 64*1024);
- snd_als300_dbgcallleave();
return 0;
}
@@ -652,7 +615,6 @@ static void snd_als300_init(struct snd_als300 *chip)
unsigned long flags;
u32 tmp;
- snd_als300_dbgcallenter();
spin_lock_irqsave(&chip->reg_lock, flags);
chip->revision = (snd_als300_gcr_read(chip->port, MISC_CONTROL) >> 16)
& 0x0000000F;
@@ -679,7 +641,6 @@ static void snd_als300_init(struct snd_als300 *chip)
snd_als300_gcr_write(chip->port, PLAYBACK_CONTROL,
tmp & ~TRANSFER_START);
spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_als300_dbgcallleave();
}
static int snd_als300_create(struct snd_card *card,
@@ -695,13 +656,12 @@ static int snd_als300_create(struct snd_card *card,
};
*rchip = NULL;
- snd_als300_dbgcallenter();
if ((err = pci_enable_device(pci)) < 0)
return err;
if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) {
- printk(KERN_ERR "error setting 28bit DMA mask\n");
+ dev_err(card->dev, "error setting 28bit DMA mask\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -733,7 +693,7 @@ static int snd_als300_create(struct snd_card *card,
if (request_irq(pci->irq, irq_handler, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_als300_free(chip);
return -EBUSY;
}
@@ -744,13 +704,13 @@ static int snd_als300_create(struct snd_card *card,
err = snd_als300_ac97(chip);
if (err < 0) {
- snd_printk(KERN_WARNING "Could not create ac97\n");
+ dev_err(card->dev, "Could not create ac97\n");
snd_als300_free(chip);
return err;
}
if ((err = snd_als300_new_pcm(chip)) < 0) {
- snd_printk(KERN_WARNING "Could not create PCM\n");
+ dev_err(card->dev, "Could not create PCM\n");
snd_als300_free(chip);
return err;
}
@@ -761,10 +721,7 @@ static int snd_als300_create(struct snd_card *card,
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
- snd_als300_dbgcallleave();
return 0;
}
@@ -794,8 +751,7 @@ static int snd_als300_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "als300: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -829,7 +785,8 @@ static int snd_als300_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index ffc821b0139e..b751c381d25e 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -578,7 +578,7 @@ static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id)
snd_als4k_iobase_readb(chip->alt_port,
ALS4K_IOB_16_ACK_FOR_CR1E);
- /* printk(KERN_INFO "als4000: irq 0x%04x 0x%04x\n",
+ /* dev_dbg(chip->card->dev, "als4000: irq 0x%04x 0x%04x\n",
pci_irqstatus, sb_irqstatus); */
/* only ack the things we actually handled above */
@@ -791,13 +791,13 @@ static int snd_als4000_create_gameport(struct snd_card_als4000 *acard, int dev)
}
if (!r) {
- printk(KERN_WARNING "als4000: cannot reserve joystick ports\n");
+ dev_warn(&acard->pci->dev, "cannot reserve joystick ports\n");
return -EBUSY;
}
acard->gameport = gp = gameport_allocate_port();
if (!gp) {
- printk(KERN_ERR "als4000: cannot allocate memory for gameport\n");
+ dev_err(&acard->pci->dev, "cannot allocate memory for gameport\n");
release_and_free_resource(r);
return -ENOMEM;
}
@@ -873,7 +873,7 @@ static int snd_card_als4000_probe(struct pci_dev *pci,
/* check, if we can restrict PCI DMA transfers to 24 bits */
if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) {
- snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n");
+ dev_err(&pci->dev, "architecture does not support 24bit PCI busmaster DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -888,9 +888,9 @@ static int snd_card_als4000_probe(struct pci_dev *pci,
pci_write_config_word(pci, PCI_COMMAND, word | PCI_COMMAND_IO);
pci_set_master(pci);
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(*acard) /* private_data: acard */,
- &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(*acard) /* private_data: acard */,
+ &card);
if (err < 0) {
pci_release_regions(pci);
pci_disable_device(pci);
@@ -920,7 +920,6 @@ static int snd_card_als4000_probe(struct pci_dev *pci,
chip->pci = pci;
chip->alt_port = iobase;
- snd_card_set_dev(card, &pci->dev);
snd_als4000_configure(chip);
@@ -934,7 +933,7 @@ static int snd_card_als4000_probe(struct pci_dev *pci,
MPU401_INFO_INTEGRATED |
MPU401_INFO_IRQ_HOOK,
-1, &chip->rmidi)) < 0) {
- printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n",
+ dev_err(&pci->dev, "no MPU-401 device at 0x%lx?\n",
iobase + ALS4K_IOB_30_MIDI_DATA);
goto out_err;
}
@@ -955,7 +954,7 @@ static int snd_card_als4000_probe(struct pci_dev *pci,
iobase + ALS4K_IOB_10_ADLIB_ADDR0,
iobase + ALS4K_IOB_12_ADLIB_ADDR2,
OPL3_HW_AUTO, 1, &opl3) < 0) {
- printk(KERN_ERR "als4000: no OPL device at 0x%lx-0x%lx?\n",
+ dev_err(&pci->dev, "no OPL device at 0x%lx-0x%lx?\n",
iobase + ALS4K_IOB_10_ADLIB_ADDR0,
iobase + ALS4K_IOB_12_ADLIB_ADDR2);
} else {
@@ -1015,8 +1014,7 @@ static int snd_als4000_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "als4000: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index 5f2acd35dcb9..901c9490398a 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -1253,11 +1253,12 @@ static int snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, int device)
num_outstreams, num_instreams, &pcm);
if (err < 0)
return err;
+
/* pointer to ops struct is stored, dont change ops afterwards! */
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- &snd_card_asihpi_playback_mmap_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
- &snd_card_asihpi_capture_mmap_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_card_asihpi_playback_mmap_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &snd_card_asihpi_capture_mmap_ops);
pcm->private_data = asihpi;
pcm->info_flags = 0;
@@ -2827,17 +2828,13 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
hpi = pci_get_drvdata(pci_dev);
adapter_index = hpi->adapter->index;
/* first try to give the card the same index as its hardware index */
- err = snd_card_create(adapter_index,
- id[adapter_index], THIS_MODULE,
- sizeof(struct snd_card_asihpi),
- &card);
+ err = snd_card_new(&pci_dev->dev, adapter_index, id[adapter_index],
+ THIS_MODULE, sizeof(struct snd_card_asihpi), &card);
if (err < 0) {
/* if that fails, try the default index==next available */
- err =
- snd_card_create(index[dev], id[dev],
- THIS_MODULE,
- sizeof(struct snd_card_asihpi),
- &card);
+ err = snd_card_new(&pci_dev->dev, index[dev], id[dev],
+ THIS_MODULE, sizeof(struct snd_card_asihpi),
+ &card);
if (err < 0)
return err;
snd_printk(KERN_WARNING
@@ -2845,8 +2842,6 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
adapter_index, card->number);
}
- snd_card_set_dev(card, &pci_dev->dev);
-
asihpi = card->private_data;
asihpi->card = card;
asihpi->pci = pci_dev;
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index f6dec3ea371f..ae07b4926dc2 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -432,7 +432,7 @@ static int snd_atiixp_acquire_codec(struct atiixp *chip)
while (atiixp_read(chip, PHYS_OUT_ADDR) & ATI_REG_PHYS_OUT_ADDR_EN) {
if (! timeout--) {
- snd_printk(KERN_WARNING "atiixp: codec acquire timeout\n");
+ dev_warn(chip->card->dev, "codec acquire timeout\n");
return -EBUSY;
}
udelay(1);
@@ -463,7 +463,7 @@ static unsigned short snd_atiixp_codec_read(struct atiixp *chip, unsigned short
} while (--timeout);
/* time out may happen during reset */
if (reg < 0x7c)
- snd_printk(KERN_WARNING "atiixp: codec read timeout (reg %x)\n", reg);
+ dev_warn(chip->card->dev, "codec read timeout (reg %x)\n", reg);
return 0xffff;
}
@@ -523,7 +523,7 @@ static int snd_atiixp_aclink_reset(struct atiixp *chip)
mdelay(1);
atiixp_update(chip, CMD, ATI_REG_CMD_AC_RESET, ATI_REG_CMD_AC_RESET);
if (!--timeout) {
- snd_printk(KERN_ERR "atiixp: codec reset timeout\n");
+ dev_err(chip->card->dev, "codec reset timeout\n");
break;
}
}
@@ -567,9 +567,8 @@ static int ac97_probing_bugs(struct pci_dev *pci)
q = snd_pci_quirk_lookup(pci, atiixp_quirks);
if (q) {
- snd_printdd(KERN_INFO
- "Atiixp quirk for %s. Forcing codec %d\n",
- snd_pci_quirk_name(q), q->value);
+ dev_dbg(&pci->dev, "atiixp quirk for %s. Forcing codec %d\n",
+ snd_pci_quirk_name(q), q->value);
return q->value;
}
/* this hardware doesn't need workarounds. Probe for codec */
@@ -600,7 +599,7 @@ static int snd_atiixp_codec_detect(struct atiixp *chip)
atiixp_write(chip, IER, 0); /* disable irqs */
if ((chip->codec_not_ready_bits & ALL_CODEC_NOT_READY) == ALL_CODEC_NOT_READY) {
- snd_printk(KERN_ERR "atiixp: no codec detected!\n");
+ dev_err(chip->card->dev, "no codec detected!\n");
return -ENXIO;
}
return 0;
@@ -676,7 +675,7 @@ static snd_pcm_uframes_t snd_atiixp_pcm_pointer(struct snd_pcm_substream *substr
continue;
return bytes_to_frames(runtime, curptr);
}
- snd_printd("atiixp: invalid DMA pointer read 0x%x (buf=%x)\n",
+ dev_dbg(chip->card->dev, "invalid DMA pointer read 0x%x (buf=%x)\n",
readl(chip->remap_addr + dma->ops->dt_cur), dma->buf_addr);
return 0;
}
@@ -688,7 +687,7 @@ static void snd_atiixp_xrun_dma(struct atiixp *chip, struct atiixp_dma *dma)
{
if (! dma->substream || ! dma->running)
return;
- snd_printdd("atiixp: XRUN detected (DMA %d)\n", dma->ops->type);
+ dev_dbg(chip->card->dev, "XRUN detected (DMA %d)\n", dma->ops->type);
snd_pcm_stream_lock(dma->substream);
snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
snd_pcm_stream_unlock(dma->substream);
@@ -1453,14 +1452,15 @@ static int snd_atiixp_mixer_new(struct atiixp *chip, int clock,
ac97.scaps |= AC97_SCAP_NO_SPDIF;
if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
chip->ac97[i] = NULL; /* to be sure */
- snd_printdd("atiixp: codec %d not available for audio\n", i);
+ dev_dbg(chip->card->dev,
+ "codec %d not available for audio\n", i);
continue;
}
codec_count++;
}
if (! codec_count) {
- snd_printk(KERN_ERR "atiixp: no codec available\n");
+ dev_err(chip->card->dev, "no codec available\n");
return -ENODEV;
}
@@ -1511,8 +1511,7 @@ static int snd_atiixp_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "atiixp: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -1637,14 +1636,14 @@ static int snd_atiixp_create(struct snd_card *card,
chip->addr = pci_resource_start(pci, 0);
chip->remap_addr = pci_ioremap_bar(pci, 0);
if (chip->remap_addr == NULL) {
- snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+ dev_err(card->dev, "AC'97 space ioremap problem\n");
snd_atiixp_free(chip);
return -EIO;
}
if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_atiixp_free(chip);
return -EBUSY;
}
@@ -1657,8 +1656,6 @@ static int snd_atiixp_create(struct snd_card *card,
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*r_chip = chip;
return 0;
}
@@ -1671,7 +1668,7 @@ static int snd_atiixp_probe(struct pci_dev *pci,
struct atiixp *chip;
int err;
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 289563ecb6dd..b9dc96c5d21e 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -400,7 +400,7 @@ static int snd_atiixp_acquire_codec(struct atiixp_modem *chip)
while (atiixp_read(chip, PHYS_OUT_ADDR) & ATI_REG_PHYS_OUT_ADDR_EN) {
if (! timeout--) {
- snd_printk(KERN_WARNING "atiixp-modem: codec acquire timeout\n");
+ dev_warn(chip->card->dev, "codec acquire timeout\n");
return -EBUSY;
}
udelay(1);
@@ -433,7 +433,7 @@ static unsigned short snd_atiixp_codec_read(struct atiixp_modem *chip,
} while (--timeout);
/* time out may happen during reset */
if (reg < 0x7c)
- snd_printk(KERN_WARNING "atiixp-modem: codec read timeout (reg %x)\n", reg);
+ dev_warn(chip->card->dev, "codec read timeout (reg %x)\n", reg);
return 0xffff;
}
@@ -499,7 +499,7 @@ static int snd_atiixp_aclink_reset(struct atiixp_modem *chip)
msleep(1);
atiixp_update(chip, CMD, ATI_REG_CMD_AC_RESET, ATI_REG_CMD_AC_RESET);
if (!--timeout) {
- snd_printk(KERN_ERR "atiixp-modem: codec reset timeout\n");
+ dev_err(chip->card->dev, "codec reset timeout\n");
break;
}
}
@@ -553,7 +553,7 @@ static int snd_atiixp_codec_detect(struct atiixp_modem *chip)
atiixp_write(chip, IER, 0); /* disable irqs */
if ((chip->codec_not_ready_bits & ALL_CODEC_NOT_READY) == ALL_CODEC_NOT_READY) {
- snd_printk(KERN_ERR "atiixp-modem: no codec detected!\n");
+ dev_err(chip->card->dev, "no codec detected!\n");
return -ENXIO;
}
return 0;
@@ -624,7 +624,7 @@ static snd_pcm_uframes_t snd_atiixp_pcm_pointer(struct snd_pcm_substream *substr
continue;
return bytes_to_frames(runtime, curptr);
}
- snd_printd("atiixp-modem: invalid DMA pointer read 0x%x (buf=%x)\n",
+ dev_dbg(chip->card->dev, "invalid DMA pointer read 0x%x (buf=%x)\n",
readl(chip->remap_addr + dma->ops->dt_cur), dma->buf_addr);
return 0;
}
@@ -637,7 +637,7 @@ static void snd_atiixp_xrun_dma(struct atiixp_modem *chip,
{
if (! dma->substream || ! dma->running)
return;
- snd_printdd("atiixp-modem: XRUN detected (DMA %d)\n", dma->ops->type);
+ dev_dbg(chip->card->dev, "XRUN detected (DMA %d)\n", dma->ops->type);
snd_pcm_stream_lock(dma->substream);
snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
snd_pcm_stream_unlock(dma->substream);
@@ -1098,14 +1098,15 @@ static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
chip->ac97[i] = NULL; /* to be sure */
- snd_printdd("atiixp-modem: codec %d not available for modem\n", i);
+ dev_dbg(chip->card->dev,
+ "codec %d not available for modem\n", i);
continue;
}
codec_count++;
}
if (! codec_count) {
- snd_printk(KERN_ERR "atiixp-modem: no codec available\n");
+ dev_err(chip->card->dev, "no codec available\n");
return -ENODEV;
}
@@ -1150,8 +1151,7 @@ static int snd_atiixp_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "atiixp-modem: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -1262,14 +1262,14 @@ static int snd_atiixp_create(struct snd_card *card,
chip->addr = pci_resource_start(pci, 0);
chip->remap_addr = pci_ioremap_bar(pci, 0);
if (chip->remap_addr == NULL) {
- snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+ dev_err(card->dev, "AC'97 space ioremap problem\n");
snd_atiixp_free(chip);
return -EIO;
}
if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_atiixp_free(chip);
return -EBUSY;
}
@@ -1282,8 +1282,6 @@ static int snd_atiixp_create(struct snd_card *card,
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*r_chip = chip;
return 0;
}
@@ -1296,7 +1294,7 @@ static int snd_atiixp_probe(struct pci_dev *pci,
struct atiixp_modem *chip;
int err;
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index 7059dd69e5e6..afb1b44b741e 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -211,8 +211,6 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
goto alloc_out;
}
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
return 0;
@@ -250,7 +248,8 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return -ENOENT;
}
// (2)
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index 2925220d3fcf..120d0d320a60 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -262,7 +262,7 @@ static int snd_aw2_create(struct snd_card *card,
/* check PCI availability (32bit DMA) */
if ((pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0) ||
(pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0)) {
- printk(KERN_ERR "aw2: Impossible to set 32bit mask DMA\n");
+ dev_err(card->dev, "Impossible to set 32bit mask DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -290,7 +290,7 @@ static int snd_aw2_create(struct snd_card *card,
pci_resource_len(pci, 0));
if (chip->iobase_virt == NULL) {
- printk(KERN_ERR "aw2: unable to remap memory region");
+ dev_err(card->dev, "unable to remap memory region");
pci_release_regions(pci);
pci_disable_device(pci);
kfree(chip);
@@ -302,7 +302,7 @@ static int snd_aw2_create(struct snd_card *card,
if (request_irq(pci->irq, snd_aw2_saa7146_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
- printk(KERN_ERR "aw2: Cannot grab irq %d\n", pci->irq);
+ dev_err(card->dev, "Cannot grab irq %d\n", pci->irq);
iounmap(chip->iobase_virt);
pci_release_regions(chip->pci);
@@ -322,12 +322,10 @@ static int snd_aw2_create(struct snd_card *card,
return err;
}
- snd_card_set_dev(card, &pci->dev);
*rchip = chip;
- printk(KERN_INFO
- "Audiowerk 2 sound card (saa7146 chipset) detected and "
- "managed\n");
+ dev_info(card->dev,
+ "Audiowerk 2 sound card (saa7146 chipset) detected and managed\n");
return 0;
}
@@ -349,7 +347,8 @@ static int snd_aw2_probe(struct pci_dev *pci,
}
/* (2) Create card instance */
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -399,7 +398,7 @@ static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- snd_printdd(KERN_DEBUG "aw2: Playback_open\n");
+ dev_dbg(substream->pcm->card->dev, "Playback_open\n");
runtime->hw = snd_aw2_playback_hw;
return 0;
}
@@ -415,7 +414,7 @@ static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- snd_printdd(KERN_DEBUG "aw2: Capture_open\n");
+ dev_dbg(substream->pcm->card->dev, "Capture_open\n");
runtime->hw = snd_aw2_capture_hw;
return 0;
}
@@ -603,7 +602,7 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
err = snd_pcm_new(chip->card, "Audiowerk2 analog playback", 0, 1, 0,
&pcm_playback_ana);
if (err < 0) {
- printk(KERN_ERR "aw2: snd_pcm_new error (0x%X)\n", err);
+ dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err);
return err;
}
@@ -633,14 +632,15 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
(chip->pci),
64 * 1024, 64 * 1024);
if (err)
- printk(KERN_ERR "aw2: snd_pcm_lib_preallocate_pages_for_all "
- "error (0x%X)\n", err);
+ dev_err(chip->card->dev,
+ "snd_pcm_lib_preallocate_pages_for_all error (0x%X)\n",
+ err);
err = snd_pcm_new(chip->card, "Audiowerk2 digital playback", 1, 1, 0,
&pcm_playback_num);
if (err < 0) {
- printk(KERN_ERR "aw2: snd_pcm_new error (0x%X)\n", err);
+ dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err);
return err;
}
/* Creation ok */
@@ -669,17 +669,15 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
(chip->pci),
64 * 1024, 64 * 1024);
if (err)
- printk(KERN_ERR
- "aw2: snd_pcm_lib_preallocate_pages_for_all error "
- "(0x%X)\n", err);
-
-
+ dev_err(chip->card->dev,
+ "snd_pcm_lib_preallocate_pages_for_all error (0x%X)\n",
+ err);
err = snd_pcm_new(chip->card, "Audiowerk2 capture", 2, 0, 1,
&pcm_capture);
if (err < 0) {
- printk(KERN_ERR "aw2: snd_pcm_new error (0x%X)\n", err);
+ dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err);
return err;
}
@@ -709,15 +707,15 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
(chip->pci),
64 * 1024, 64 * 1024);
if (err)
- printk(KERN_ERR
- "aw2: snd_pcm_lib_preallocate_pages_for_all error "
- "(0x%X)\n", err);
+ dev_err(chip->card->dev,
+ "snd_pcm_lib_preallocate_pages_for_all error (0x%X)\n",
+ err);
/* Create control */
err = snd_ctl_add(chip->card, snd_ctl_new1(&aw2_control, chip));
if (err < 0) {
- printk(KERN_ERR "aw2: snd_ctl_add error (0x%X)\n", err);
+ dev_err(chip->card->dev, "snd_ctl_add error (0x%X)\n", err);
return err;
}
diff --git a/sound/pci/aw2/aw2-saa7146.c b/sound/pci/aw2/aw2-saa7146.c
index 4439636971eb..6d24e9536777 100644
--- a/sound/pci/aw2/aw2-saa7146.c
+++ b/sound/pci/aw2/aw2-saa7146.c
@@ -204,8 +204,7 @@ void snd_aw2_saa7146_pcm_init_playback(struct snd_aw2_saa7146 *chip,
/* Define upper limit for DMA access */
WRITEREG(dma_addr + buffer_size, ProtA1_out);
} else {
- printk(KERN_ERR
- "aw2: snd_aw2_saa7146_pcm_init_playback: "
+ pr_err("aw2: snd_aw2_saa7146_pcm_init_playback: "
"Substream number is not 0 or 1 -> not managed\n");
}
}
@@ -251,8 +250,7 @@ void snd_aw2_saa7146_pcm_init_capture(struct snd_aw2_saa7146 *chip,
/* Define upper limit for DMA access */
WRITEREG(dma_addr + buffer_size, ProtA1_in);
} else {
- printk(KERN_ERR
- "aw2: snd_aw2_saa7146_pcm_init_capture: "
+ pr_err("aw2: snd_aw2_saa7146_pcm_init_capture: "
"Substream number is not 0 -> not managed\n");
}
}
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 1aef7128f7ca..c9216c0a9c8b 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -238,61 +238,6 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
2>/dev/null
*/
-#define DEBUG_MISC 0
-#define DEBUG_CALLS 0
-#define DEBUG_MIXER 0
-#define DEBUG_CODEC 0
-#define DEBUG_TIMER 0
-#define DEBUG_GAME 0
-#define DEBUG_PM 0
-#define MIXER_TESTING 0
-
-#if DEBUG_MISC
-#define snd_azf3328_dbgmisc(format, args...) printk(KERN_DEBUG format, ##args)
-#else
-#define snd_azf3328_dbgmisc(format, args...)
-#endif
-
-#if DEBUG_CALLS
-#define snd_azf3328_dbgcalls(format, args...) printk(format, ##args)
-#define snd_azf3328_dbgcallenter() printk(KERN_DEBUG "--> %s\n", __func__)
-#define snd_azf3328_dbgcallleave() printk(KERN_DEBUG "<-- %s\n", __func__)
-#else
-#define snd_azf3328_dbgcalls(format, args...)
-#define snd_azf3328_dbgcallenter()
-#define snd_azf3328_dbgcallleave()
-#endif
-
-#if DEBUG_MIXER
-#define snd_azf3328_dbgmixer(format, args...) printk(KERN_DEBUG format, ##args)
-#else
-#define snd_azf3328_dbgmixer(format, args...)
-#endif
-
-#if DEBUG_CODEC
-#define snd_azf3328_dbgcodec(format, args...) printk(KERN_DEBUG format, ##args)
-#else
-#define snd_azf3328_dbgcodec(format, args...)
-#endif
-
-#if DEBUG_MISC
-#define snd_azf3328_dbgtimer(format, args...) printk(KERN_DEBUG format, ##args)
-#else
-#define snd_azf3328_dbgtimer(format, args...)
-#endif
-
-#if DEBUG_GAME
-#define snd_azf3328_dbggame(format, args...) printk(KERN_DEBUG format, ##args)
-#else
-#define snd_azf3328_dbggame(format, args...)
-#endif
-
-#if DEBUG_PM
-#define snd_azf3328_dbgpm(format, args...) printk(KERN_DEBUG format, ##args)
-#else
-#define snd_azf3328_dbgpm(format, args...)
-#endif
-
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard.");
@@ -475,6 +420,12 @@ snd_azf3328_ctrl_inb(const struct snd_azf3328 *chip, unsigned reg)
return inb(chip->ctrl_io + reg);
}
+static inline u16
+snd_azf3328_ctrl_inw(const struct snd_azf3328 *chip, unsigned reg)
+{
+ return inw(chip->ctrl_io + reg);
+}
+
static inline void
snd_azf3328_ctrl_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value)
{
@@ -578,11 +529,12 @@ snd_azf3328_mixer_reset(const struct snd_azf3328 *chip)
#ifdef AZF_USE_AC97_LAYER
static inline void
-snd_azf3328_mixer_ac97_map_unsupported(unsigned short reg, const char *mode)
+snd_azf3328_mixer_ac97_map_unsupported(const struct snd_azf3328 *chip,
+ unsigned short reg, const char *mode)
{
/* need to add some more or less clever emulation? */
- printk(KERN_WARNING
- "azt3328: missing %s emulation for AC97 register 0x%02x!\n",
+ dev_warn(chip->card->dev,
+ "missing %s emulation for AC97 register 0x%02x!\n",
mode, reg);
}
@@ -717,10 +669,8 @@ snd_azf3328_mixer_ac97_read(struct snd_ac97 *ac97, unsigned short reg_ac97)
unsigned short reg_val = 0;
bool unsupported = false;
- snd_azf3328_dbgmixer(
- "snd_azf3328_mixer_ac97_read reg_ac97 %u\n",
- reg_ac97
- );
+ dev_dbg(chip->card->dev, "snd_azf3328_mixer_ac97_read reg_ac97 %u\n",
+ reg_ac97);
if (reg_azf & AZF_AC97_REG_UNSUPPORTED)
unsupported = true;
else {
@@ -765,7 +715,7 @@ snd_azf3328_mixer_ac97_read(struct snd_ac97 *ac97, unsigned short reg_ac97)
}
}
if (unsupported)
- snd_azf3328_mixer_ac97_map_unsupported(reg_ac97, "read");
+ snd_azf3328_mixer_ac97_map_unsupported(chip, reg_ac97, "read");
return reg_val;
}
@@ -778,10 +728,9 @@ snd_azf3328_mixer_ac97_write(struct snd_ac97 *ac97,
unsigned short reg_azf = snd_azf3328_mixer_ac97_map_reg_idx(reg_ac97);
bool unsupported = false;
- snd_azf3328_dbgmixer(
+ dev_dbg(chip->card->dev,
"snd_azf3328_mixer_ac97_write reg_ac97 %u val %u\n",
- reg_ac97, val
- );
+ reg_ac97, val);
if (reg_azf & AZF_AC97_REG_UNSUPPORTED)
unsupported = true;
else {
@@ -814,7 +763,7 @@ snd_azf3328_mixer_ac97_write(struct snd_ac97 *ac97,
}
}
if (unsupported)
- snd_azf3328_mixer_ac97_map_unsupported(reg_ac97, "write");
+ snd_azf3328_mixer_ac97_map_unsupported(chip, reg_ac97, "write");
}
static int
@@ -850,7 +799,7 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip)
* due to this card being a very quirky AC97 "lookalike".
*/
if (rc)
- printk(KERN_ERR "azt3328: AC97 init failed, err %d!\n", rc);
+ dev_err(chip->card->dev, "AC97 init failed, err %d!\n", rc);
/* If we return an error here, then snd_card_free() should
* free up any ac97 codecs that got created, as well as the bus.
@@ -870,8 +819,6 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip,
unsigned char curr_vol_left = 0, curr_vol_right = 0;
int left_change = 0, right_change = 0;
- snd_azf3328_dbgcallenter();
-
if (chan_sel & SET_CHAN_LEFT) {
curr_vol_left = inb(portbase + 1);
@@ -912,7 +859,6 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip,
if (delay)
mdelay(delay);
} while ((left_change) || (right_change));
- snd_azf3328_dbgcallleave();
}
/*
@@ -990,14 +936,12 @@ snd_azf3328_info_mixer(struct snd_kcontrol *kcontrol,
{
struct azf3328_mixer_reg reg;
- snd_azf3328_dbgcallenter();
snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
uinfo->type = reg.mask == 1 ?
SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = reg.stereo + 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = reg.mask;
- snd_azf3328_dbgcallleave();
return 0;
}
@@ -1009,7 +953,6 @@ snd_azf3328_get_mixer(struct snd_kcontrol *kcontrol,
struct azf3328_mixer_reg reg;
u16 oreg, val;
- snd_azf3328_dbgcallenter();
snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
oreg = snd_azf3328_mixer_inw(chip, reg.reg);
@@ -1023,12 +966,11 @@ snd_azf3328_get_mixer(struct snd_kcontrol *kcontrol,
val = reg.mask - val;
ucontrol->value.integer.value[1] = val;
}
- snd_azf3328_dbgmixer("get: %02x is %04x -> vol %02lx|%02lx "
- "(shift %02d|%02d, mask %02x, inv. %d, stereo %d)\n",
+ dev_dbg(chip->card->dev,
+ "get: %02x is %04x -> vol %02lx|%02lx (shift %02d|%02d, mask %02x, inv. %d, stereo %d)\n",
reg.reg, oreg,
ucontrol->value.integer.value[0], ucontrol->value.integer.value[1],
reg.lchan_shift, reg.rchan_shift, reg.mask, reg.invert, reg.stereo);
- snd_azf3328_dbgcallleave();
return 0;
}
@@ -1040,7 +982,6 @@ snd_azf3328_put_mixer(struct snd_kcontrol *kcontrol,
struct azf3328_mixer_reg reg;
u16 oreg, nreg, val;
- snd_azf3328_dbgcallenter();
snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
oreg = snd_azf3328_mixer_inw(chip, reg.reg);
val = ucontrol->value.integer.value[0] & reg.mask;
@@ -1064,12 +1005,11 @@ snd_azf3328_put_mixer(struct snd_kcontrol *kcontrol,
else
snd_azf3328_mixer_outw(chip, reg.reg, nreg);
- snd_azf3328_dbgmixer("put: %02x to %02lx|%02lx, "
- "oreg %04x; shift %02d|%02d -> nreg %04x; after: %04x\n",
+ dev_dbg(chip->card->dev,
+ "put: %02x to %02lx|%02lx, oreg %04x; shift %02d|%02d -> nreg %04x; after: %04x\n",
reg.reg, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1],
oreg, reg.lchan_shift, reg.rchan_shift,
nreg, snd_azf3328_mixer_inw(chip, reg.reg));
- snd_azf3328_dbgcallleave();
return (nreg != oreg);
}
@@ -1135,7 +1075,8 @@ snd_azf3328_get_mixer_enum(struct snd_kcontrol *kcontrol,
} else
ucontrol->value.enumerated.item[0] = (val >> reg.lchan_shift) & (reg.enum_c - 1);
- snd_azf3328_dbgmixer("get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n",
+ dev_dbg(chip->card->dev,
+ "get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n",
reg.reg, val, ucontrol->value.enumerated.item[0], ucontrol->value.enumerated.item[1],
reg.lchan_shift, reg.enum_c);
return 0;
@@ -1167,7 +1108,8 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol,
snd_azf3328_mixer_outw(chip, reg.reg, val);
nreg = val;
- snd_azf3328_dbgmixer("put_enum: %02x to %04x, oreg %04x\n", reg.reg, val, oreg);
+ dev_dbg(chip->card->dev,
+ "put_enum: %02x to %04x, oreg %04x\n", reg.reg, val, oreg);
return (nreg != oreg);
}
@@ -1253,7 +1195,6 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip)
unsigned int idx;
int err;
- snd_azf3328_dbgcallenter();
if (snd_BUG_ON(!chip || !chip->card))
return -EINVAL;
@@ -1279,7 +1220,6 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip)
snd_component_add(card, "AZF3328 mixer");
strcpy(card->mixername, "AZF3328 mixer");
- snd_azf3328_dbgcallleave();
return 0;
}
#endif /* AZF_USE_AC97_LAYER */
@@ -1288,19 +1228,13 @@ static int
snd_azf3328_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
- int res;
- snd_azf3328_dbgcallenter();
- res = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
- snd_azf3328_dbgcallleave();
- return res;
+ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
}
static int
snd_azf3328_hw_free(struct snd_pcm_substream *substream)
{
- snd_azf3328_dbgcallenter();
snd_pcm_lib_free_pages(substream);
- snd_azf3328_dbgcallleave();
return 0;
}
@@ -1315,7 +1249,6 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec,
u16 val = 0xff00;
u8 freq = 0;
- snd_azf3328_dbgcallenter();
switch (bitrate) {
case AZF_FREQ_4000: freq = SOUNDFORMAT_FREQ_SUSPECTED_4000; break;
case AZF_FREQ_4800: freq = SOUNDFORMAT_FREQ_SUSPECTED_4800; break;
@@ -1379,7 +1312,6 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec,
);
spin_unlock_irqrestore(codec->lock, flags);
- snd_azf3328_dbgcallleave();
}
static inline void
@@ -1404,15 +1336,16 @@ snd_azf3328_ctrl_reg_6AH_update(struct snd_azf3328 *chip,
chip->shadow_reg_ctrl_6AH |= bitmask;
else
chip->shadow_reg_ctrl_6AH &= ~bitmask;
- snd_azf3328_dbgcodec("6AH_update mask 0x%04x do_mask %d: val 0x%04x\n",
- bitmask, do_mask, chip->shadow_reg_ctrl_6AH);
+ dev_dbg(chip->card->dev,
+ "6AH_update mask 0x%04x do_mask %d: val 0x%04x\n",
+ bitmask, do_mask, chip->shadow_reg_ctrl_6AH);
snd_azf3328_ctrl_outw(chip, IDX_IO_6AH, chip->shadow_reg_ctrl_6AH);
}
static inline void
snd_azf3328_ctrl_enable_codecs(struct snd_azf3328 *chip, bool enable)
{
- snd_azf3328_dbgcodec("codec_enable %d\n", enable);
+ dev_dbg(chip->card->dev, "codec_enable %d\n", enable);
/* no idea what exactly is being done here, but I strongly assume it's
* PM related */
snd_azf3328_ctrl_reg_6AH_update(
@@ -1429,7 +1362,7 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip,
struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
bool need_change = (codec->running != enable);
- snd_azf3328_dbgcodec(
+ dev_dbg(chip->card->dev,
"codec_activity: %s codec, enable %d, need_change %d\n",
codec->name, enable, need_change
);
@@ -1470,13 +1403,13 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip,
}
static void
-snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec,
- unsigned long addr,
- unsigned int period_bytes,
- unsigned int buffer_bytes
+snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip,
+ struct snd_azf3328_codec_data *codec,
+ unsigned long addr,
+ unsigned int period_bytes,
+ unsigned int buffer_bytes
)
{
- snd_azf3328_dbgcallenter();
WARN_ONCE(period_bytes & 1, "odd period length!?\n");
WARN_ONCE(buffer_bytes != 2 * period_bytes,
"missed our input expectations! %u vs. %u\n",
@@ -1499,7 +1432,7 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec,
setup_io.dma_start_1 = addr;
setup_io.dma_start_2 = addr+area_length;
- snd_azf3328_dbgcodec(
+ dev_dbg(chip->card->dev,
"setdma: buffers %08x[%u] / %08x[%u], %u, %u\n",
setup_io.dma_start_1, area_length,
setup_io.dma_start_2, area_length,
@@ -1522,7 +1455,6 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec,
);
spin_unlock_irqrestore(codec->lock, flags);
}
- snd_azf3328_dbgcallleave();
}
static int
@@ -1535,8 +1467,6 @@ snd_azf3328_pcm_prepare(struct snd_pcm_substream *substream)
unsigned int count = snd_pcm_lib_period_bytes(substream);
#endif
- snd_azf3328_dbgcallenter();
-
codec->dma_base = runtime->dma_addr;
#if 0
@@ -1544,10 +1474,9 @@ snd_azf3328_pcm_prepare(struct snd_pcm_substream *substream)
runtime->rate,
snd_pcm_format_width(runtime->format),
runtime->channels);
- snd_azf3328_codec_setdmaa(codec,
+ snd_azf3328_codec_setdmaa(chip, codec,
runtime->dma_addr, count, size);
#endif
- snd_azf3328_dbgcallleave();
return 0;
}
@@ -1562,11 +1491,9 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
bool previously_muted = false;
bool is_main_mixer_playback_codec = (AZF_CODEC_PLAYBACK == codec->type);
- snd_azf3328_dbgcalls("snd_azf3328_pcm_trigger cmd %d\n", cmd);
-
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- snd_azf3328_dbgcodec("START %s\n", codec->name);
+ dev_dbg(chip->card->dev, "START PCM %s\n", codec->name);
if (is_main_mixer_playback_codec) {
/* mute WaveOut (avoid clicking during setup) */
@@ -1593,7 +1520,7 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff);
spin_unlock(codec->lock);
- snd_azf3328_codec_setdmaa(codec, runtime->dma_addr,
+ snd_azf3328_codec_setdmaa(chip, codec, runtime->dma_addr,
snd_pcm_lib_period_bytes(substream),
snd_pcm_lib_buffer_bytes(substream)
);
@@ -1633,10 +1560,10 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
);
}
- snd_azf3328_dbgcodec("STARTED %s\n", codec->name);
+ dev_dbg(chip->card->dev, "PCM STARTED %s\n", codec->name);
break;
case SNDRV_PCM_TRIGGER_RESUME:
- snd_azf3328_dbgcodec("RESUME %s\n", codec->name);
+ dev_dbg(chip->card->dev, "PCM RESUME %s\n", codec->name);
/* resume codec if we were active */
spin_lock(codec->lock);
if (codec->running)
@@ -1648,7 +1575,7 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
spin_unlock(codec->lock);
break;
case SNDRV_PCM_TRIGGER_STOP:
- snd_azf3328_dbgcodec("STOP %s\n", codec->name);
+ dev_dbg(chip->card->dev, "PCM STOP %s\n", codec->name);
if (is_main_mixer_playback_codec) {
/* mute WaveOut (avoid clicking during setup) */
@@ -1684,10 +1611,10 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
);
}
- snd_azf3328_dbgcodec("STOPPED %s\n", codec->name);
+ dev_dbg(chip->card->dev, "PCM STOPPED %s\n", codec->name);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
- snd_azf3328_dbgcodec("SUSPEND %s\n", codec->name);
+ dev_dbg(chip->card->dev, "PCM SUSPEND %s\n", codec->name);
/* make sure codec is stopped */
snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
snd_azf3328_codec_inw(
@@ -1696,17 +1623,16 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
+ WARN(1, "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
+ WARN(1, "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
break;
default:
- snd_printk(KERN_ERR "FIXME: unknown trigger mode!\n");
+ WARN(1, "FIXME: unknown trigger mode!\n");
return -EINVAL;
}
- snd_azf3328_dbgcallleave();
return result;
}
@@ -1728,8 +1654,8 @@ snd_azf3328_pcm_pointer(struct snd_pcm_substream *substream
result -= codec->dma_base;
#endif
frmres = bytes_to_frames( substream->runtime, result);
- snd_azf3328_dbgcodec("%08li %s @ 0x%8lx, frames %8ld\n",
- jiffies, codec->name, result, frmres);
+ dev_dbg(substream->pcm->card->dev, "%08li %s @ 0x%8lx, frames %8ld\n",
+ jiffies, codec->name, result, frmres);
return frmres;
}
@@ -1792,7 +1718,7 @@ snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip)
* skeleton handler only
* (we do not want axis reading in interrupt handler - too much load!)
*/
- snd_azf3328_dbggame("gameport irq\n");
+ dev_dbg(chip->card->dev, "gameport irq\n");
/* this should ACK the gameport IRQ properly, hopefully. */
snd_azf3328_game_inw(chip, IDX_GAME_AXIS_VALUE);
@@ -1804,7 +1730,7 @@ snd_azf3328_gameport_open(struct gameport *gameport, int mode)
struct snd_azf3328 *chip = gameport_get_port_data(gameport);
int res;
- snd_azf3328_dbggame("gameport_open, mode %d\n", mode);
+ dev_dbg(chip->card->dev, "gameport_open, mode %d\n", mode);
switch (mode) {
case GAMEPORT_MODE_COOKED:
case GAMEPORT_MODE_RAW:
@@ -1827,7 +1753,7 @@ snd_azf3328_gameport_close(struct gameport *gameport)
{
struct snd_azf3328 *chip = gameport_get_port_data(gameport);
- snd_azf3328_dbggame("gameport_close\n");
+ dev_dbg(chip->card->dev, "gameport_close\n");
snd_azf3328_gameport_set_counter_frequency(chip,
GAME_HWCFG_ADC_COUNTER_FREQ_1_200);
snd_azf3328_gameport_axis_circuit_enable(chip, 0);
@@ -1892,9 +1818,8 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport,
axes[i] = -1;
}
- snd_azf3328_dbggame("cooked_read: axes %d %d %d %d buttons %d\n",
- axes[0], axes[1], axes[2], axes[3], *buttons
- );
+ dev_dbg(chip->card->dev, "cooked_read: axes %d %d %d %d buttons %d\n",
+ axes[0], axes[1], axes[2], axes[3], *buttons);
return 0;
}
@@ -1906,7 +1831,7 @@ snd_azf3328_gameport(struct snd_azf3328 *chip, int dev)
chip->gameport = gp = gameport_allocate_port();
if (!gp) {
- printk(KERN_ERR "azt3328: cannot alloc memory for gameport\n");
+ dev_err(chip->card->dev, "cannot alloc memory for gameport\n");
return -ENOMEM;
}
@@ -1950,23 +1875,23 @@ snd_azf3328_gameport_free(struct snd_azf3328 *chip) { }
static inline void
snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip)
{
- printk(KERN_WARNING "huh, game port IRQ occurred!?\n");
+ dev_warn(chip->card->dev, "huh, game port IRQ occurred!?\n");
}
#endif /* SUPPORT_GAMEPORT */
/******************************************************************/
static inline void
-snd_azf3328_irq_log_unknown_type(u8 which)
+snd_azf3328_irq_log_unknown_type(struct snd_azf3328 *chip, u8 which)
{
- snd_azf3328_dbgcodec(
- "azt3328: unknown IRQ type (%x) occurred, please report!\n",
- which
- );
+ dev_dbg(chip->card->dev,
+ "unknown IRQ type (%x) occurred, please report!\n",
+ which);
}
static inline void
-snd_azf3328_pcm_interrupt(const struct snd_azf3328_codec_data *first_codec,
+snd_azf3328_pcm_interrupt(struct snd_azf3328 *chip,
+ const struct snd_azf3328_codec_data *first_codec,
u8 status
)
{
@@ -1990,17 +1915,15 @@ snd_azf3328_pcm_interrupt(const struct snd_azf3328_codec_data *first_codec,
if (codec->substream) {
snd_pcm_period_elapsed(codec->substream);
- snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n",
+ dev_dbg(chip->card->dev, "%s period done (#%x), @ %x\n",
codec->name,
which,
snd_azf3328_codec_inl(
- codec, IDX_IO_CODEC_DMA_CURRPOS
- )
- );
+ codec, IDX_IO_CODEC_DMA_CURRPOS));
} else
- printk(KERN_WARNING "azt3328: irq handler problem!\n");
+ dev_warn(chip->card->dev, "irq handler problem!\n");
if (which & IRQ_SOMETHING)
- snd_azf3328_irq_log_unknown_type(which);
+ snd_azf3328_irq_log_unknown_type(chip, which);
}
}
@@ -2009,9 +1932,7 @@ snd_azf3328_interrupt(int irq, void *dev_id)
{
struct snd_azf3328 *chip = dev_id;
u8 status;
-#if DEBUG_CODEC
static unsigned long irq_count;
-#endif
status = snd_azf3328_ctrl_inb(chip, IDX_IO_IRQSTATUS);
@@ -2022,14 +1943,13 @@ snd_azf3328_interrupt(int irq, void *dev_id)
))
return IRQ_NONE; /* must be interrupt for another device */
- snd_azf3328_dbgcodec(
+ dev_dbg(chip->card->dev,
"irq_count %ld! IDX_IO_IRQSTATUS %04x\n",
irq_count++ /* debug-only */,
- status
- );
+ status);
if (status & IRQ_TIMER) {
- /* snd_azf3328_dbgcodec("timer %ld\n",
+ /* dev_dbg(chip->card->dev, "timer %ld\n",
snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE)
& TIMER_VALUE_MASK
); */
@@ -2039,11 +1959,11 @@ snd_azf3328_interrupt(int irq, void *dev_id)
spin_lock(&chip->reg_lock);
snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07);
spin_unlock(&chip->reg_lock);
- snd_azf3328_dbgcodec("azt3328: timer IRQ\n");
+ dev_dbg(chip->card->dev, "timer IRQ\n");
}
if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT))
- snd_azf3328_pcm_interrupt(chip->codecs, status);
+ snd_azf3328_pcm_interrupt(chip, chip->codecs, status);
if (status & IRQ_GAMEPORT)
snd_azf3328_gameport_interrupt(chip);
@@ -2055,7 +1975,7 @@ snd_azf3328_interrupt(int irq, void *dev_id)
/* hmm, do we have to ack the IRQ here somehow?
* If so, then I don't know how yet... */
- snd_azf3328_dbgcodec("azt3328: MPU401 IRQ\n");
+ dev_dbg(chip->card->dev, "MPU401 IRQ\n");
}
return IRQ_HANDLED;
}
@@ -2133,7 +2053,6 @@ snd_azf3328_pcm_open(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
- snd_azf3328_dbgcallenter();
codec->substream = substream;
/* same parameters for all our codecs - at least we think so... */
@@ -2142,7 +2061,6 @@ snd_azf3328_pcm_open(struct snd_pcm_substream *substream,
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&snd_azf3328_hw_constraints_rates);
runtime->private_data = codec;
- snd_azf3328_dbgcallleave();
return 0;
}
@@ -2171,9 +2089,7 @@ snd_azf3328_pcm_close(struct snd_pcm_substream *substream
struct snd_azf3328_codec_data *codec =
substream->runtime->private_data;
- snd_azf3328_dbgcallenter();
codec->substream = NULL;
- snd_azf3328_dbgcallleave();
return 0;
}
@@ -2220,8 +2136,6 @@ enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */
struct snd_pcm *pcm;
int err;
- snd_azf3328_dbgcallenter();
-
err = snd_pcm_new(chip->card, "AZF3328 DSP", AZF_PCMDEV_STD,
1, 1, &pcm);
if (err < 0)
@@ -2258,7 +2172,6 @@ enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */
snd_dma_pci_data(chip->pci),
64*1024, 64*1024);
- snd_azf3328_dbgcallleave();
return 0;
}
@@ -2281,7 +2194,6 @@ snd_azf3328_timer_start(struct snd_timer *timer)
unsigned long flags;
unsigned int delay;
- snd_azf3328_dbgcallenter();
chip = snd_timer_chip(timer);
delay = ((timer->sticks * seqtimer_scaling) - 1) & TIMER_VALUE_MASK;
if (delay < 49) {
@@ -2289,15 +2201,14 @@ snd_azf3328_timer_start(struct snd_timer *timer)
* this timing tweak
* (we need to do it to avoid a lockup, though) */
- snd_azf3328_dbgtimer("delay was too low (%d)!\n", delay);
+ dev_dbg(chip->card->dev, "delay was too low (%d)!\n", delay);
delay = 49; /* minimum time is 49 ticks */
}
- snd_azf3328_dbgtimer("setting timer countdown value %d\n", delay);
+ dev_dbg(chip->card->dev, "setting timer countdown value %d\n", delay);
delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE;
spin_lock_irqsave(&chip->reg_lock, flags);
snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay);
spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_azf3328_dbgcallleave();
return 0;
}
@@ -2307,7 +2218,6 @@ snd_azf3328_timer_stop(struct snd_timer *timer)
struct snd_azf3328 *chip;
unsigned long flags;
- snd_azf3328_dbgcallenter();
chip = snd_timer_chip(timer);
spin_lock_irqsave(&chip->reg_lock, flags);
/* disable timer countdown and interrupt */
@@ -2319,7 +2229,6 @@ snd_azf3328_timer_stop(struct snd_timer *timer)
the hardware/ALSA interrupt activity. */
snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x04);
spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_azf3328_dbgcallleave();
return 0;
}
@@ -2328,10 +2237,8 @@ static int
snd_azf3328_timer_precise_resolution(struct snd_timer *timer,
unsigned long *num, unsigned long *den)
{
- snd_azf3328_dbgcallenter();
*num = 1;
*den = 1024000 / seqtimer_scaling;
- snd_azf3328_dbgcallleave();
return 0;
}
@@ -2351,7 +2258,6 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device)
struct snd_timer_id tid;
int err;
- snd_azf3328_dbgcallenter();
tid.dev_class = SNDRV_TIMER_CLASS_CARD;
tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
tid.card = chip->card->number;
@@ -2376,7 +2282,6 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device)
err = 0;
out:
- snd_azf3328_dbgcallleave();
return err;
}
@@ -2438,34 +2343,34 @@ snd_azf3328_test_bit(unsigned unsigned reg, int bit)
static inline void
snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip)
{
-#if DEBUG_MISC
u16 tmp;
- snd_azf3328_dbgmisc(
+ dev_dbg(chip->card->dev,
"ctrl_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, "
"opl3_io 0x%lx, mixer_io 0x%lx, irq %d\n",
chip->ctrl_io, chip->game_io, chip->mpu_io,
- chip->opl3_io, chip->mixer_io, chip->irq
- );
+ chip->opl3_io, chip->mixer_io, chip->irq);
- snd_azf3328_dbgmisc("game %02x %02x %02x %02x %02x %02x\n",
+ dev_dbg(chip->card->dev,
+ "game %02x %02x %02x %02x %02x %02x\n",
snd_azf3328_game_inb(chip, 0),
snd_azf3328_game_inb(chip, 1),
snd_azf3328_game_inb(chip, 2),
snd_azf3328_game_inb(chip, 3),
snd_azf3328_game_inb(chip, 4),
- snd_azf3328_game_inb(chip, 5)
- );
+ snd_azf3328_game_inb(chip, 5));
for (tmp = 0; tmp < 0x07; tmp += 1)
- snd_azf3328_dbgmisc("mpu_io 0x%04x\n", inb(chip->mpu_io + tmp));
+ dev_dbg(chip->card->dev,
+ "mpu_io 0x%04x\n", inb(chip->mpu_io + tmp));
for (tmp = 0; tmp <= 0x07; tmp += 1)
- snd_azf3328_dbgmisc("0x%02x: game200 0x%04x, game208 0x%04x\n",
+ dev_dbg(chip->card->dev,
+ "0x%02x: game200 0x%04x, game208 0x%04x\n",
tmp, inb(0x200 + tmp), inb(0x208 + tmp));
for (tmp = 0; tmp <= 0x01; tmp += 1)
- snd_azf3328_dbgmisc(
+ dev_dbg(chip->card->dev,
"0x%02x: mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, "
"mpu330 0x%04x opl388 0x%04x opl38c 0x%04x\n",
tmp,
@@ -2474,19 +2379,17 @@ snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip)
inb(0x320 + tmp),
inb(0x330 + tmp),
inb(0x388 + tmp),
- inb(0x38c + tmp)
- );
+ inb(0x38c + tmp));
for (tmp = 0; tmp < AZF_IO_SIZE_CTRL; tmp += 2)
- snd_azf3328_dbgmisc("ctrl 0x%02x: 0x%04x\n",
- tmp, snd_azf3328_ctrl_inw(chip, tmp)
- );
+ dev_dbg(chip->card->dev,
+ "ctrl 0x%02x: 0x%04x\n",
+ tmp, snd_azf3328_ctrl_inw(chip, tmp));
for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2)
- snd_azf3328_dbgmisc("mixer 0x%02x: 0x%04x\n",
- tmp, snd_azf3328_mixer_inw(chip, tmp)
- );
-#endif /* DEBUG_MISC */
+ dev_dbg(chip->card->dev,
+ "mixer 0x%02x: 0x%04x\n",
+ tmp, snd_azf3328_mixer_inw(chip, tmp));
}
static int
@@ -2523,8 +2426,8 @@ snd_azf3328_create(struct snd_card *card,
/* check if we can restrict PCI DMA transfers to 24 bits */
if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) {
- snd_printk(KERN_ERR "architecture does not support "
- "24bit PCI busmaster DMA\n"
+ dev_err(card->dev,
+ "architecture does not support 24bit PCI busmaster DMA\n"
);
err = -ENXIO;
goto out_err;
@@ -2560,7 +2463,7 @@ snd_azf3328_create(struct snd_card *card,
if (request_irq(pci->irq, snd_azf3328_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
err = -EBUSY;
goto out_err;
}
@@ -2599,8 +2502,6 @@ snd_azf3328_create(struct snd_card *card,
spin_unlock_irq(codec->lock);
}
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
err = 0;
@@ -2624,7 +2525,6 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
struct snd_opl3 *opl3;
int err;
- snd_azf3328_dbgcallenter();
if (dev >= SNDRV_CARDS) {
err = -ENODEV;
goto out;
@@ -2635,7 +2535,8 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
goto out;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
goto out;
@@ -2657,7 +2558,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
-1, &chip->rmidi
);
if (err < 0) {
- snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n",
+ dev_err(card->dev, "no MPU-401 device at 0x%lx?\n",
chip->mpu_io
);
goto out_err;
@@ -2673,7 +2574,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
if (snd_opl3_create(card, chip->opl3_io, chip->opl3_io+2,
OPL3_HW_AUTO, 1, &opl3) < 0) {
- snd_printk(KERN_ERR "azf3328: no OPL3 device at 0x%lx-0x%lx?\n",
+ dev_err(card->dev, "no OPL3 device at 0x%lx-0x%lx?\n",
chip->opl3_io, chip->opl3_io+2
);
} else {
@@ -2695,12 +2596,15 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
goto out_err;
#ifdef MODULE
- printk(KERN_INFO
-"azt3328: Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n"
-"azt3328: Hardware was completely undocumented, unfortunately.\n"
-"azt3328: Feel free to contact andi AT lisas.de for bug reports etc.!\n"
-"azt3328: User-scalable sequencer timer set to %dHz (1024000Hz / %d).\n",
- 1024000 / seqtimer_scaling, seqtimer_scaling);
+ dev_info(card->dev,
+ "Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n");
+ dev_info(card->dev,
+ "Hardware was completely undocumented, unfortunately.\n");
+ dev_info(card->dev,
+ "Feel free to contact andi AT lisas.de for bug reports etc.!\n");
+ dev_info(card->dev,
+ "User-scalable sequencer timer set to %dHz (1024000Hz / %d).\n",
+ 1024000 / seqtimer_scaling, seqtimer_scaling);
#endif
snd_azf3328_gameport(chip, dev);
@@ -2712,31 +2616,29 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
goto out;
out_err:
- snd_printk(KERN_ERR "azf3328: something failed, exiting\n");
+ dev_err(card->dev, "something failed, exiting\n");
snd_card_free(card);
out:
- snd_azf3328_dbgcallleave();
return err;
}
static void
snd_azf3328_remove(struct pci_dev *pci)
{
- snd_azf3328_dbgcallenter();
snd_card_free(pci_get_drvdata(pci));
- snd_azf3328_dbgcallleave();
}
#ifdef CONFIG_PM_SLEEP
static inline void
-snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs)
+snd_azf3328_suspend_regs(const struct snd_azf3328 *chip,
+ unsigned long io_addr, unsigned count, u32 *saved_regs)
{
unsigned reg;
for (reg = 0; reg < count; ++reg) {
*saved_regs = inl(io_addr);
- snd_azf3328_dbgpm("suspend: io 0x%04lx: 0x%08x\n",
+ dev_dbg(chip->card->dev, "suspend: io 0x%04lx: 0x%08x\n",
io_addr, *saved_regs);
++saved_regs;
io_addr += sizeof(*saved_regs);
@@ -2744,7 +2646,8 @@ snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs)
}
static inline void
-snd_azf3328_resume_regs(const u32 *saved_regs,
+snd_azf3328_resume_regs(const struct snd_azf3328 *chip,
+ const u32 *saved_regs,
unsigned long io_addr,
unsigned count
)
@@ -2753,7 +2656,8 @@ snd_azf3328_resume_regs(const u32 *saved_regs,
for (reg = 0; reg < count; ++reg) {
outl(*saved_regs, io_addr);
- snd_azf3328_dbgpm("resume: io 0x%04lx: 0x%08x --> 0x%08x\n",
+ dev_dbg(chip->card->dev,
+ "resume: io 0x%04lx: 0x%08x --> 0x%08x\n",
io_addr, *saved_regs, inl(io_addr));
++saved_regs;
io_addr += sizeof(*saved_regs);
@@ -2766,7 +2670,7 @@ snd_azf3328_suspend_ac97(struct snd_azf3328 *chip)
#ifdef AZF_USE_AC97_LAYER
snd_ac97_suspend(chip->ac97);
#else
- snd_azf3328_suspend_regs(chip->mixer_io,
+ snd_azf3328_suspend_regs(chip, chip->mixer_io,
ARRAY_SIZE(chip->saved_regs_mixer), chip->saved_regs_mixer);
/* make sure to disable master volume etc. to prevent looping sound */
@@ -2781,7 +2685,7 @@ snd_azf3328_resume_ac97(const struct snd_azf3328 *chip)
#ifdef AZF_USE_AC97_LAYER
snd_ac97_resume(chip->ac97);
#else
- snd_azf3328_resume_regs(chip->saved_regs_mixer, chip->mixer_io,
+ snd_azf3328_resume_regs(chip, chip->saved_regs_mixer, chip->mixer_io,
ARRAY_SIZE(chip->saved_regs_mixer));
/* unfortunately with 32bit transfers, IDX_MIXER_PLAY_MASTER (0x02)
@@ -2808,18 +2712,18 @@ snd_azf3328_suspend(struct device *dev)
snd_azf3328_suspend_ac97(chip);
- snd_azf3328_suspend_regs(chip->ctrl_io,
+ snd_azf3328_suspend_regs(chip, chip->ctrl_io,
ARRAY_SIZE(chip->saved_regs_ctrl), chip->saved_regs_ctrl);
/* manually store the one currently relevant write-only reg, too */
saved_regs_ctrl_u16 = (u16 *)chip->saved_regs_ctrl;
saved_regs_ctrl_u16[IDX_IO_6AH / 2] = chip->shadow_reg_ctrl_6AH;
- snd_azf3328_suspend_regs(chip->game_io,
+ snd_azf3328_suspend_regs(chip, chip->game_io,
ARRAY_SIZE(chip->saved_regs_game), chip->saved_regs_game);
- snd_azf3328_suspend_regs(chip->mpu_io,
+ snd_azf3328_suspend_regs(chip, chip->mpu_io,
ARRAY_SIZE(chip->saved_regs_mpu), chip->saved_regs_mpu);
- snd_azf3328_suspend_regs(chip->opl3_io,
+ snd_azf3328_suspend_regs(chip, chip->opl3_io,
ARRAY_SIZE(chip->saved_regs_opl3), chip->saved_regs_opl3);
pci_disable_device(pci);
@@ -2838,23 +2742,22 @@ snd_azf3328_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "azt3328: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
pci_set_master(pci);
- snd_azf3328_resume_regs(chip->saved_regs_game, chip->game_io,
+ snd_azf3328_resume_regs(chip, chip->saved_regs_game, chip->game_io,
ARRAY_SIZE(chip->saved_regs_game));
- snd_azf3328_resume_regs(chip->saved_regs_mpu, chip->mpu_io,
+ snd_azf3328_resume_regs(chip, chip->saved_regs_mpu, chip->mpu_io,
ARRAY_SIZE(chip->saved_regs_mpu));
- snd_azf3328_resume_regs(chip->saved_regs_opl3, chip->opl3_io,
+ snd_azf3328_resume_regs(chip, chip->saved_regs_opl3, chip->opl3_io,
ARRAY_SIZE(chip->saved_regs_opl3));
snd_azf3328_resume_ac97(chip);
- snd_azf3328_resume_regs(chip->saved_regs_ctrl, chip->ctrl_io,
+ snd_azf3328_resume_regs(chip, chip->saved_regs_ctrl, chip->ctrl_io,
ARRAY_SIZE(chip->saved_regs_ctrl));
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 18802039497a..8546711d12f9 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -293,17 +293,23 @@ static void snd_bt87x_pci_error(struct snd_bt87x *chip, unsigned int status)
PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY;
pci_write_config_word(chip->pci, PCI_STATUS, pci_status);
if (pci_status != PCI_STATUS_DETECTED_PARITY)
- snd_printk(KERN_ERR "Aieee - PCI error! status %#08x, PCI status %#04x\n",
+ dev_err(chip->card->dev,
+ "Aieee - PCI error! status %#08x, PCI status %#04x\n",
status & ERROR_INTERRUPTS, pci_status);
else {
- snd_printk(KERN_ERR "Aieee - PCI parity error detected!\n");
+ dev_err(chip->card->dev,
+ "Aieee - PCI parity error detected!\n");
/* error 'handling' similar to aic7xxx_pci.c: */
chip->pci_parity_errors++;
if (chip->pci_parity_errors > 20) {
- snd_printk(KERN_ERR "Too many PCI parity errors observed.\n");
- snd_printk(KERN_ERR "Some device on this bus is generating bad parity.\n");
- snd_printk(KERN_ERR "This is an error *observed by*, not *generated by*, this card.\n");
- snd_printk(KERN_ERR "PCI parity error checking has been disabled.\n");
+ dev_err(chip->card->dev,
+ "Too many PCI parity errors observed.\n");
+ dev_err(chip->card->dev,
+ "Some device on this bus is generating bad parity.\n");
+ dev_err(chip->card->dev,
+ "This is an error *observed by*, not *generated by*, this card.\n");
+ dev_err(chip->card->dev,
+ "PCI parity error checking has been disabled.\n");
chip->interrupt_mask &= ~(INT_PPERR | INT_RIPERR);
snd_bt87x_writel(chip, REG_INT_MASK, chip->interrupt_mask);
}
@@ -323,9 +329,11 @@ static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id)
if (irq_status & ERROR_INTERRUPTS) {
if (irq_status & (INT_FBUS | INT_FTRGT))
- snd_printk(KERN_WARNING "FIFO overrun, status %#08x\n", status);
+ dev_warn(chip->card->dev,
+ "FIFO overrun, status %#08x\n", status);
if (irq_status & INT_OCERR)
- snd_printk(KERN_ERR "internal RISC error, status %#08x\n", status);
+ dev_err(chip->card->dev,
+ "internal RISC error, status %#08x\n", status);
if (irq_status & (INT_PPERR | INT_RIPERR | INT_PABORT))
snd_bt87x_pci_error(chip, irq_status);
}
@@ -747,7 +755,7 @@ static int snd_bt87x_create(struct snd_card *card,
}
chip->mmio = pci_ioremap_bar(pci, 0);
if (!chip->mmio) {
- snd_printk(KERN_ERR "cannot remap io memory\n");
+ dev_err(card->dev, "cannot remap io memory\n");
err = -ENOMEM;
goto fail;
}
@@ -762,7 +770,7 @@ static int snd_bt87x_create(struct snd_card *card,
err = request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip);
if (err < 0) {
- snd_printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
+ dev_err(card->dev, "cannot grab irq %d\n", pci->irq);
goto fail;
}
chip->irq = pci->irq;
@@ -773,7 +781,6 @@ static int snd_bt87x_create(struct snd_card *card,
if (err < 0)
goto fail;
- snd_card_set_dev(card, &pci->dev);
*rchip = chip;
return 0;
@@ -851,14 +858,15 @@ static int snd_bt87x_detect_card(struct pci_dev *pci)
for (i = 0; i < ARRAY_SIZE(blacklist); ++i)
if (blacklist[i].subvendor == pci->subsystem_vendor &&
blacklist[i].subdevice == pci->subsystem_device) {
- snd_printdd(KERN_INFO "card %#04x-%#04x:%#04x has no audio\n",
+ dev_dbg(&pci->dev,
+ "card %#04x-%#04x:%#04x has no audio\n",
pci->device, pci->subsystem_vendor, pci->subsystem_device);
return -EBUSY;
}
- snd_printk(KERN_INFO "unknown card %#04x-%#04x:%#04x\n",
+ dev_info(&pci->dev, "unknown card %#04x-%#04x:%#04x\n",
pci->device, pci->subsystem_vendor, pci->subsystem_device);
- snd_printk(KERN_DEBUG "please mail id, board name, and, "
+ dev_info(&pci->dev, "please mail id, board name, and, "
"if it works, the correct digital_rate option to "
"<alsa-devel@alsa-project.org>\n");
return SND_BT87X_BOARD_UNKNOWN;
@@ -888,7 +896,8 @@ static int snd_bt87x_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -925,7 +934,7 @@ static int snd_bt87x_probe(struct pci_dev *pci,
if (err < 0)
goto _error;
}
- snd_printk(KERN_INFO "bt87x%d: Using board %d, %sanalog, %sdigital "
+ dev_info(card->dev, "bt87x%d: Using board %d, %sanalog, %sdigital "
"(rate %d Hz)\n", dev, boardid,
chip->board.no_analog ? "no " : "",
chip->board.no_digital ? "no " : "", chip->board.dig_rate);
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index f4db5587e86e..f94cc6e97d4a 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -417,13 +417,13 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
int status;
int retry;
if ((reg > 0x7f) || (value > 0x1ff)) {
- snd_printk(KERN_ERR "i2c_write: invalid values.\n");
+ dev_err(emu->card->dev, "i2c_write: invalid values.\n");
return -EINVAL;
}
tmp = reg << 25 | value << 16;
/*
- snd_printk(KERN_DEBUG "I2C-write:reg=0x%x, value=0x%x\n", reg, value);
+ dev_dbg(emu->card->dev, "I2C-write:reg=0x%x, value=0x%x\n", reg, value);
*/
/* Not sure what this I2C channel controls. */
/* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */
@@ -442,7 +442,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
/* Wait till the transaction ends */
while (1) {
status = snd_ca0106_ptr_read(emu, I2C_A, 0);
- /*snd_printk(KERN_DEBUG "I2C:status=0x%x\n", status);*/
+ /*dev_dbg(emu->card->dev, "I2C:status=0x%x\n", status);*/
timeout++;
if ((status & I2C_A_ADC_START) == 0)
break;
@@ -456,7 +456,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
}
if (retry == 10) {
- snd_printk(KERN_ERR "Writing to ADC failed!\n");
+ dev_err(emu->card->dev, "Writing to ADC failed!\n");
return -EINVAL;
}
@@ -516,7 +516,8 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
}
}
-static int snd_ca0106_channel_dac(struct snd_ca0106_details *details,
+static int snd_ca0106_channel_dac(struct snd_ca0106 *chip,
+ struct snd_ca0106_details *details,
int channel_id)
{
switch (channel_id) {
@@ -529,7 +530,7 @@ static int snd_ca0106_channel_dac(struct snd_ca0106_details *details,
case PCM_UNKNOWN_CHANNEL:
return (details->spi_dac & 0x000f) >> (4 * 0);
default:
- snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n",
+ dev_dbg(chip->card->dev, "ca0106: unknown channel_id %d\n",
channel_id);
}
return 0;
@@ -539,7 +540,7 @@ static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id,
int power)
{
if (chip->details->spi_dac) {
- const int dac = snd_ca0106_channel_dac(chip->details,
+ const int dac = snd_ca0106_channel_dac(chip, chip->details,
channel_id);
const int reg = spi_dacd_reg[dac];
const int bit = spi_dacd_bit[dac];
@@ -583,7 +584,7 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr
channel->use = 1;
/*
- printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+ dev_dbg(chip->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n",
channel_id, chip, channel);
*/
//channel->interrupt = snd_ca0106_pcm_channel_interrupt;
@@ -660,7 +661,8 @@ static int snd_ca0106_pcm_open_capture_channel(struct snd_pcm_substream *substre
epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
if (epcm == NULL) {
- snd_printk(KERN_ERR "open_capture_channel: failed epcm alloc\n");
+ dev_err(chip->card->dev,
+ "open_capture_channel: failed epcm alloc\n");
return -ENOMEM;
}
epcm->emu = chip;
@@ -677,7 +679,7 @@ static int snd_ca0106_pcm_open_capture_channel(struct snd_pcm_substream *substre
channel->use = 1;
/*
- printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+ dev_dbg(chip->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n",
channel_id, chip, channel);
*/
//channel->interrupt = snd_ca0106_pcm_channel_interrupt;
@@ -771,7 +773,7 @@ static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream)
int i;
#if 0 /* debug */
- snd_printk(KERN_DEBUG
+ dev_dbg(emu->card->dev,
"prepare:channel_number=%d, rate=%d, format=0x%x, "
"channels=%d, buffer_size=%ld, period_size=%ld, "
"periods=%u, frames_to_bytes=%d\n",
@@ -779,9 +781,11 @@ static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream)
runtime->channels, runtime->buffer_size,
runtime->period_size, runtime->periods,
frames_to_bytes(runtime, 1));
- snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n",
+ dev_dbg(emu->card->dev,
+ "dma_addr=%x, dma_area=%p, table_base=%p\n",
runtime->dma_addr, runtime->dma_area, table_base);
- snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
+ dev_dbg(emu->card->dev,
+ "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
#endif /* debug */
/* Rate can be set per channel. */
@@ -876,7 +880,7 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream)
u32 reg71;
#if 0 /* debug */
- snd_printk(KERN_DEBUG
+ dev_dbg(emu->card->dev,
"prepare:channel_number=%d, rate=%d, format=0x%x, "
"channels=%d, buffer_size=%ld, period_size=%ld, "
"periods=%u, frames_to_bytes=%d\n",
@@ -884,9 +888,11 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream)
runtime->channels, runtime->buffer_size,
runtime->period_size, runtime->periods,
frames_to_bytes(runtime, 1));
- snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n",
+ dev_dbg(emu->card->dev,
+ "dma_addr=%x, dma_area=%p, table_base=%p\n",
runtime->dma_addr, runtime->dma_area, table_base);
- snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
+ dev_dbg(emu->card->dev,
+ "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
#endif /* debug */
/* reg71 controls ADC rate. */
@@ -934,7 +940,7 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream)
/*
- printk(KERN_DEBUG
+ dev_dbg(emu->card->dev,
"prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, "
"buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",
channel, runtime->rate, runtime->format, runtime->channels,
@@ -982,13 +988,13 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream,
runtime = s->runtime;
epcm = runtime->private_data;
channel = epcm->channel_id;
- /* snd_printk(KERN_DEBUG "channel=%d\n", channel); */
+ /* dev_dbg(emu->card->dev, "channel=%d\n", channel); */
epcm->running = running;
basic |= (0x1 << channel);
extended |= (0x10 << channel);
snd_pcm_trigger_done(s, substream);
}
- /* snd_printk(KERN_DEBUG "basic=0x%x, extended=0x%x\n",basic, extended); */
+ /* dev_dbg(emu->card->dev, "basic=0x%x, extended=0x%x\n",basic, extended); */
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -1070,7 +1076,7 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
return ptr;
prev_ptr = ptr;
} while (--timeout);
- snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n");
+ dev_warn(emu->card->dev, "ca0106: unstable DMA pointer!\n");
return 0;
}
@@ -1093,7 +1099,7 @@ snd_ca0106_pcm_pointer_capture(struct snd_pcm_substream *substream)
if (ptr >= runtime->buffer_size)
ptr -= runtime->buffer_size;
/*
- printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
+ dev_dbg(emu->card->dev, "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
"buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
ptr1, ptr2, ptr, (int)runtime->buffer_size,
(int)runtime->period_size, (int)runtime->frame_bits,
@@ -1284,9 +1290,9 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
stat76 = snd_ca0106_ptr_read(chip, EXTENDED_INT, 0);
/*
- snd_printk(KERN_DEBUG "interrupt status = 0x%08x, stat76=0x%08x\n",
+ dev_dbg(emu->card->dev, "interrupt status = 0x%08x, stat76=0x%08x\n",
status, stat76);
- snd_printk(KERN_DEBUG "ptr=0x%08x\n",
+ dev_dbg(emu->card->dev, "ptr=0x%08x\n",
snd_ca0106_ptr_read(chip, PLAYBACK_POINTER, 0));
*/
mask = 0x11; /* 0x1 for one half, 0x10 for the other half period. */
@@ -1296,11 +1302,13 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
/* FIXME: Select the correct substream for period elapsed */
if(pchannel->use) {
snd_pcm_period_elapsed(pchannel->epcm->substream);
- //printk(KERN_INFO "interrupt [%d] used\n", i);
+ /* dev_dbg(emu->card->dev, "interrupt [%d] used\n", i); */
}
}
- //printk(KERN_INFO "channel=%p\n",pchannel);
- //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number);
+ /*
+ dev_dbg(emu->card->dev, "channel=%p\n", pchannel);
+ dev_dbg(emu->card->dev, "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number);
+ */
mask <<= 1;
}
mask = 0x110000; /* 0x1 for one half, 0x10 for the other half period. */
@@ -1310,11 +1318,13 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
/* FIXME: Select the correct substream for period elapsed */
if(pchannel->use) {
snd_pcm_period_elapsed(pchannel->epcm->substream);
- //printk(KERN_INFO "interrupt [%d] used\n", i);
+ /* dev_dbg(emu->card->dev, "interrupt [%d] used\n", i); */
}
}
- //printk(KERN_INFO "channel=%p\n",pchannel);
- //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number);
+ /*
+ dev_dbg(emu->card->dev, "channel=%p\n", pchannel);
+ dev_dbg(emu->card->dev, "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number);
+ */
mask <<= 1;
}
@@ -1603,7 +1613,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
int size, n;
size = ARRAY_SIZE(i2c_adc_init);
- /* snd_printk(KERN_DEBUG "I2C:array size=0x%x\n", size); */
+ /* dev_dbg(emu->card->dev, "I2C:array size=0x%x\n", size); */
for (n = 0; n < size; n++)
snd_ca0106_i2c_write(chip, i2c_adc_init[n][0],
i2c_adc_init[n][1]);
@@ -1668,7 +1678,7 @@ static int snd_ca0106_create(int dev, struct snd_card *card,
return err;
if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
- printk(KERN_ERR "error to set 32bit mask DMA\n");
+ dev_err(card->dev, "error to set 32bit mask DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -1689,14 +1699,14 @@ static int snd_ca0106_create(int dev, struct snd_card *card,
chip->res_port = request_region(chip->port, 0x20, "snd_ca0106");
if (!chip->res_port) {
snd_ca0106_free(chip);
- printk(KERN_ERR "cannot allocate the port\n");
+ dev_err(card->dev, "cannot allocate the port\n");
return -EBUSY;
}
if (request_irq(pci->irq, snd_ca0106_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
snd_ca0106_free(chip);
- printk(KERN_ERR "cannot grab irq\n");
+ dev_err(card->dev, "cannot grab irq\n");
return -EBUSY;
}
chip->irq = pci->irq;
@@ -1712,7 +1722,7 @@ static int snd_ca0106_create(int dev, struct snd_card *card,
/* read serial */
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
- printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n",
+ dev_info(card->dev, "Model %04x Rev %08x Serial %08x\n",
chip->model, pci->revision, chip->serial);
strcpy(card->driver, "CA0106");
strcpy(card->shortname, "CA0106");
@@ -1726,7 +1736,7 @@ static int snd_ca0106_create(int dev, struct snd_card *card,
}
chip->details = c;
if (subsystem[dev]) {
- printk(KERN_INFO "snd-ca0106: Sound card name=%s, "
+ dev_info(card->dev, "Sound card name=%s, "
"subsystem=0x%x. Forced to subsystem=0x%x\n",
c->name, chip->serial, subsystem[dev]);
}
@@ -1843,7 +1853,8 @@ static int snd_ca0106_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -1868,18 +1879,16 @@ static int snd_ca0106_probe(struct pci_dev *pci,
if (err < 0)
goto error;
- snd_printdd("ca0106: probe for MIDI channel A ...");
+ dev_dbg(card->dev, "probe for MIDI channel A ...");
err = snd_ca0106_midi(chip, CA0106_MIDI_CHAN_A);
if (err < 0)
goto error;
- snd_printdd(" done.\n");
+ dev_dbg(card->dev, " done.\n");
#ifdef CONFIG_PROC_FS
snd_ca0106_proc_init(chip);
#endif
- snd_card_set_dev(card, &pci->dev);
-
err = snd_card_register(card);
if (err < 0)
goto error;
diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c
index 8bbdf265d11d..b91c7f6d19f9 100644
--- a/sound/pci/ca0106/ca_midi.c
+++ b/sound/pci/ca0106/ca_midi.c
@@ -46,7 +46,7 @@ static void ca_midi_clear_rx(struct snd_ca_midi *midi)
ca_midi_read_data(midi);
#ifdef CONFIG_SND_DEBUG
if (timeout <= 0)
- snd_printk(KERN_ERR "ca_midi_clear_rx: timeout (status = 0x%x)\n",
+ pr_err("ca_midi_clear_rx: timeout (status = 0x%x)\n",
ca_midi_read_stat(midi));
#endif
}
@@ -113,7 +113,7 @@ static void ca_midi_cmd(struct snd_ca_midi *midi, unsigned char cmd, int ack)
}
spin_unlock_irqrestore(&midi->input_lock, flags);
if (!ok)
- snd_printk(KERN_ERR "ca_midi_cmd: 0x%x failed at 0x%x (status = 0x%x, data = 0x%x)!!!\n",
+ pr_err("ca_midi_cmd: 0x%x failed at 0x%x (status = 0x%x, data = 0x%x)!!!\n",
cmd,
midi->get_dev_id_port(midi->dev_id),
ca_midi_read_stat(midi),
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 2755ec5bcc25..12c318e175f4 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -796,7 +796,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
if (runtime->channels > 1)
rec->fmt |= 0x01;
if (rec->is_dac && set_dac_channels(cm, rec, runtime->channels) < 0) {
- snd_printd("cannot set dac channels\n");
+ dev_dbg(cm->card->dev, "cannot set dac channels\n");
return -EINVAL;
}
@@ -827,7 +827,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
else
cm->ctrl |= val;
snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);
- //snd_printd("cmipci: functrl0 = %08x\n", cm->ctrl);
+ /* dev_dbg(cm->card->dev, "functrl0 = %08x\n", cm->ctrl); */
/* set sample rate */
freq = 0;
@@ -850,7 +850,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
val |= (freq << CM_ASFC_SHIFT) & CM_ASFC_MASK;
}
snd_cmipci_write(cm, CM_REG_FUNCTRL1, val);
- //snd_printd("cmipci: functrl1 = %08x\n", val);
+ dev_dbg(cm->card->dev, "functrl1 = %08x\n", val);
/* set format */
val = snd_cmipci_read(cm, CM_REG_CHFORMAT);
@@ -866,7 +866,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
val |= freq_ext << (rec->ch * 2);
}
snd_cmipci_write(cm, CM_REG_CHFORMAT, val);
- //snd_printd("cmipci: chformat = %08x\n", val);
+ dev_dbg(cm->card->dev, "chformat = %08x\n", val);
if (!rec->is_dac && cm->chip_version) {
if (runtime->rate > 44100)
@@ -904,7 +904,7 @@ static int snd_cmipci_pcm_trigger(struct cmipci *cm, struct cmipci_pcm *rec,
cm->ctrl |= chen;
/* enable channel */
snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl);
- //snd_printd("cmipci: functrl0 = %08x\n", cm->ctrl);
+ dev_dbg(cm->card->dev, "functrl0 = %08x\n", cm->ctrl);
break;
case SNDRV_PCM_TRIGGER_STOP:
rec->running = 0;
@@ -952,7 +952,7 @@ static snd_pcm_uframes_t snd_cmipci_pcm_pointer(struct cmipci *cm, struct cmipci
if (rem < rec->dma_size)
goto ok;
}
- printk(KERN_ERR "cmipci: invalid PCM pointer: %#x\n", rem);
+ dev_err(cm->card->dev, "invalid PCM pointer: %#x\n", rem);
return SNDRV_PCM_POS_XRUN;
ok:
ptr = (rec->dma_size - (rem + 1)) >> rec->shift;
@@ -2889,13 +2889,13 @@ static int snd_cmipci_create_gameport(struct cmipci *cm, int dev)
}
if (!r) {
- printk(KERN_WARNING "cmipci: cannot reserve joystick ports\n");
+ dev_warn(cm->card->dev, "cannot reserve joystick ports\n");
return -EBUSY;
}
cm->gameport = gp = gameport_allocate_port();
if (!gp) {
- printk(KERN_ERR "cmipci: cannot allocate memory for gameport\n");
+ dev_err(cm->card->dev, "cannot allocate memory for gameport\n");
release_and_free_resource(r);
return -ENOMEM;
}
@@ -2995,13 +2995,14 @@ static int snd_cmipci_create_fm(struct cmipci *cm, long fm_port)
if (snd_opl3_create(cm->card, iosynth, iosynth + 2,
OPL3_HW_OPL3, 0, &opl3) < 0) {
- printk(KERN_ERR "cmipci: no OPL device at %#lx, "
- "skipping...\n", iosynth);
+ dev_err(cm->card->dev,
+ "no OPL device at %#lx, skipping...\n",
+ iosynth);
goto disable_fm;
}
}
if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
- printk(KERN_ERR "cmipci: cannot create OPL3 hwdep\n");
+ dev_err(cm->card->dev, "cannot create OPL3 hwdep\n");
return err;
}
return 0;
@@ -3060,7 +3061,7 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci,
if (request_irq(pci->irq, snd_cmipci_interrupt,
IRQF_SHARED, KBUILD_MODNAME, cm)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_cmipci_free(cm);
return -EBUSY;
}
@@ -3192,8 +3193,9 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci,
/* enable UART */
snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_UART_EN);
if (inb(iomidi + 1) == 0xff) {
- snd_printk(KERN_ERR "cannot enable MPU-401 port"
- " at %#lx\n", iomidi);
+ dev_err(cm->card->dev,
+ "cannot enable MPU-401 port at %#lx\n",
+ iomidi);
snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1,
CM_UART_EN);
iomidi = 0;
@@ -3237,7 +3239,8 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci,
MPU401_INFO_INTEGRATED : 0) |
MPU401_INFO_IRQ_HOOK,
-1, &cm->rmidi)) < 0) {
- printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi);
+ dev_err(cm->card->dev,
+ "no UART401 device at 0x%lx\n", iomidi);
}
}
@@ -3254,8 +3257,6 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci,
if (snd_cmipci_create_gameport(cm, dev) < 0)
snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
- snd_card_set_dev(card, &pci->dev);
-
*rcmipci = cm;
return 0;
}
@@ -3280,7 +3281,8 @@ static int snd_cmipci_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -3381,8 +3383,7 @@ static int snd_cmipci_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "cmipci: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 1dc793e742d7..43d1f912c641 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -564,7 +564,8 @@ static void snd_cs4281_ac97_write(struct snd_ac97 *ac97,
return;
}
}
- snd_printk(KERN_ERR "AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val);
+ dev_err(chip->card->dev,
+ "AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val);
}
static unsigned short snd_cs4281_ac97_read(struct snd_ac97 *ac97,
@@ -624,7 +625,8 @@ static unsigned short snd_cs4281_ac97_read(struct snd_ac97 *ac97,
goto __ok1;
}
- snd_printk(KERN_ERR "AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg);
+ dev_err(chip->card->dev,
+ "AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg);
result = 0xffff;
goto __end;
@@ -643,7 +645,8 @@ static unsigned short snd_cs4281_ac97_read(struct snd_ac97 *ac97,
udelay(10);
}
- snd_printk(KERN_ERR "AC'97 read problem (ACSTS_VSTS), reg = 0x%x\n", reg);
+ dev_err(chip->card->dev,
+ "AC'97 read problem (ACSTS_VSTS), reg = 0x%x\n", reg);
result = 0xffff;
goto __end;
@@ -835,8 +838,9 @@ static snd_pcm_uframes_t snd_cs4281_pointer(struct snd_pcm_substream *substream)
struct cs4281 *chip = snd_pcm_substream_chip(substream);
/*
- printk(KERN_DEBUG "DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n",
- snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size,
+ dev_dbg(chip->card->dev,
+ "DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n",
+ snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size,
jiffies);
*/
return runtime->buffer_size -
@@ -1265,7 +1269,8 @@ static int snd_cs4281_create_gameport(struct cs4281 *chip)
chip->gameport = gp = gameport_allocate_port();
if (!gp) {
- printk(KERN_ERR "cs4281: cannot allocate memory for gameport\n");
+ dev_err(chip->card->dev,
+ "cannot allocate memory for gameport\n");
return -ENOMEM;
}
@@ -1361,7 +1366,7 @@ static int snd_cs4281_create(struct snd_card *card,
chip->irq = -1;
pci_set_master(pci);
if (dual_codec < 0 || dual_codec > 3) {
- snd_printk(KERN_ERR "invalid dual_codec option %d\n", dual_codec);
+ dev_err(card->dev, "invalid dual_codec option %d\n", dual_codec);
dual_codec = 0;
}
chip->dual_codec = dual_codec;
@@ -1383,7 +1388,7 @@ static int snd_cs4281_create(struct snd_card *card,
if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_cs4281_free(chip);
return -ENOMEM;
}
@@ -1402,8 +1407,6 @@ static int snd_cs4281_create(struct snd_card *card,
snd_cs4281_proc_init(chip);
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
return 0;
}
@@ -1425,7 +1428,8 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
snd_cs4281_pokeBA0(chip, BA0_CFLR, BA0_CFLR_DEFAULT);
tmp = snd_cs4281_peekBA0(chip, BA0_CFLR);
if (tmp != BA0_CFLR_DEFAULT) {
- snd_printk(KERN_ERR "CFLR setup failed (0x%x)\n", tmp);
+ dev_err(chip->card->dev,
+ "CFLR setup failed (0x%x)\n", tmp);
return -EIO;
}
}
@@ -1436,11 +1440,13 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
snd_cs4281_pokeBA0(chip, BA0_CWPR, 0x4281);
if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC1)) != (BA0_SERC1_SO1EN | BA0_SERC1_AC97)) {
- snd_printk(KERN_ERR "SERC1 AC'97 check failed (0x%x)\n", tmp);
+ dev_err(chip->card->dev,
+ "SERC1 AC'97 check failed (0x%x)\n", tmp);
return -EIO;
}
if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC2)) != (BA0_SERC2_SI1EN | BA0_SERC2_AC97)) {
- snd_printk(KERN_ERR "SERC2 AC'97 check failed (0x%x)\n", tmp);
+ dev_err(chip->card->dev,
+ "SERC2 AC'97 check failed (0x%x)\n", tmp);
return -EIO;
}
@@ -1502,7 +1508,7 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
schedule_timeout_uninterruptible(1);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_ERR "DLLRDY not seen\n");
+ dev_err(chip->card->dev, "DLLRDY not seen\n");
return -EIO;
__ok0:
@@ -1528,7 +1534,9 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
schedule_timeout_uninterruptible(1);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_ERR "never read codec ready from AC'97 (0x%x)\n", snd_cs4281_peekBA0(chip, BA0_ACSTS));
+ dev_err(chip->card->dev,
+ "never read codec ready from AC'97 (0x%x)\n",
+ snd_cs4281_peekBA0(chip, BA0_ACSTS));
return -EIO;
__ok1:
@@ -1539,7 +1547,8 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
goto __codec2_ok;
schedule_timeout_uninterruptible(1);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_INFO "secondary codec doesn't respond. disable it...\n");
+ dev_info(chip->card->dev,
+ "secondary codec doesn't respond. disable it...\n");
chip->dual_codec = 0;
__codec2_ok: ;
}
@@ -1569,7 +1578,7 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
if (--retry_count > 0)
goto __retry;
- snd_printk(KERN_ERR "never read ISV3 and ISV4 from AC'97\n");
+ dev_err(chip->card->dev, "never read ISV3 and ISV4 from AC'97\n");
return -EIO;
__ok2:
@@ -1917,7 +1926,8 @@ static int snd_cs4281_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -2055,8 +2065,7 @@ static int cs4281_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "cs4281: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index b03498325d66..af0eacbc8bd2 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -88,7 +88,8 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
if ((err = snd_cs46xx_create(card, pci,
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 062398ec5335..32b44f25b5c8 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -116,7 +116,7 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
tmp = snd_cs46xx_peekBA0(chip, BA0_ACCTL);
if ((tmp & ACCTL_VFRM) == 0) {
- snd_printk(KERN_WARNING "cs46xx: ACCTL_VFRM not set 0x%x\n",tmp);
+ dev_warn(chip->card->dev, "ACCTL_VFRM not set 0x%x\n", tmp);
snd_cs46xx_pokeBA0(chip, BA0_ACCTL, (tmp & (~ACCTL_ESYN)) | ACCTL_VFRM );
msleep(50);
tmp = snd_cs46xx_peekBA0(chip, BA0_ACCTL + offset);
@@ -168,7 +168,8 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
goto ok1;
}
- snd_printk(KERN_ERR "AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg);
+ dev_err(chip->card->dev,
+ "AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg);
result = 0xffff;
goto end;
@@ -187,7 +188,9 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
udelay(10);
}
- snd_printk(KERN_ERR "AC'97 read problem (ACSTS_VSTS), codec_index %d, reg = 0x%x\n", codec_index, reg);
+ dev_err(chip->card->dev,
+ "AC'97 read problem (ACSTS_VSTS), codec_index %d, reg = 0x%x\n",
+ codec_index, reg);
result = 0xffff;
goto end;
@@ -197,7 +200,8 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
* ACSDA = Status Data Register = 474h
*/
#if 0
- printk(KERN_DEBUG "e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg,
+ dev_dbg(chip->card->dev,
+ "e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg,
snd_cs46xx_peekBA0(chip, BA0_ACSDA),
snd_cs46xx_peekBA0(chip, BA0_ACCAD));
#endif
@@ -286,7 +290,9 @@ static void snd_cs46xx_codec_write(struct snd_cs46xx *chip,
goto end;
}
}
- snd_printk(KERN_ERR "AC'97 write problem, codec_index = %d, reg = 0x%x, val = 0x%x\n", codec_index, reg, val);
+ dev_err(chip->card->dev,
+ "AC'97 write problem, codec_index = %d, reg = 0x%x, val = 0x%x\n",
+ codec_index, reg, val);
end:
chip->active_ctrl(chip, -1);
}
@@ -608,8 +614,8 @@ static int cs46xx_wait_for_fifo(struct snd_cs46xx * chip,int retry_timeout)
}
if(status & SERBST_WBSY) {
- snd_printk(KERN_ERR "cs46xx: failure waiting for "
- "FIFO command to complete\n");
+ dev_err(chip->card->dev,
+ "failure waiting for FIFO command to complete\n");
return -EINVAL;
}
@@ -646,7 +652,9 @@ static void snd_cs46xx_clear_serial_FIFOs(struct snd_cs46xx *chip)
* Make sure the previous FIFO write operation has completed.
*/
if (cs46xx_wait_for_fifo(chip,1)) {
- snd_printdd ("failed waiting for FIFO at addr (%02X)\n",idx);
+ dev_dbg(chip->card->dev,
+ "failed waiting for FIFO at addr (%02X)\n",
+ idx);
if (powerdown)
snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp);
@@ -694,7 +702,7 @@ static void snd_cs46xx_proc_start(struct snd_cs46xx *chip)
}
if (snd_cs46xx_peek(chip, BA1_SPCR) & SPCR_RUNFR)
- snd_printk(KERN_ERR "SPCR_RUNFR never reset\n");
+ dev_err(chip->card->dev, "SPCR_RUNFR never reset\n");
}
static void snd_cs46xx_proc_stop(struct snd_cs46xx *chip)
@@ -1054,7 +1062,8 @@ static int _cs46xx_adjust_sample_rate (struct snd_cs46xx *chip, struct snd_cs46x
cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate,
cpcm, cpcm->hw_buf.addr,cpcm->pcm_channel_id);
if (cpcm->pcm_channel == NULL) {
- snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n");
+ dev_err(chip->card->dev,
+ "failed to create virtual PCM channel\n");
return -ENOMEM;
}
cpcm->pcm_channel->sample_rate = sample_rate;
@@ -1067,7 +1076,8 @@ static int _cs46xx_adjust_sample_rate (struct snd_cs46xx *chip, struct snd_cs46x
if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm,
cpcm->hw_buf.addr,
cpcm->pcm_channel_id)) == NULL) {
- snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n");
+ dev_err(chip->card->dev,
+ "failed to re-create virtual PCM channel\n");
return -ENOMEM;
}
@@ -1116,7 +1126,8 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- snd_printdd ("period_size (%d), periods (%d) buffer_size(%d)\n",
+ dev_dbg(chip->card->dev,
+ "period_size (%d), periods (%d) buffer_size(%d)\n",
period_size, params_periods(hw_params),
params_buffer_bytes(hw_params));
#endif
@@ -1531,22 +1542,20 @@ static int _cs46xx_playback_open_channel (struct snd_pcm_substream *substream,in
static int snd_cs46xx_playback_open(struct snd_pcm_substream *substream)
{
- snd_printdd("open front channel\n");
+ dev_dbg(substream->pcm->card->dev, "open front channel\n");
return _cs46xx_playback_open_channel(substream,DSP_PCM_MAIN_CHANNEL);
}
#ifdef CONFIG_SND_CS46XX_NEW_DSP
static int snd_cs46xx_playback_open_rear(struct snd_pcm_substream *substream)
{
- snd_printdd("open rear channel\n");
-
+ dev_dbg(substream->pcm->card->dev, "open rear channel\n");
return _cs46xx_playback_open_channel(substream,DSP_PCM_REAR_CHANNEL);
}
static int snd_cs46xx_playback_open_clfe(struct snd_pcm_substream *substream)
{
- snd_printdd("open center - LFE channel\n");
-
+ dev_dbg(substream->pcm->card->dev, "open center - LFE channel\n");
return _cs46xx_playback_open_channel(substream,DSP_PCM_CENTER_LFE_CHANNEL);
}
@@ -1554,7 +1563,7 @@ static int snd_cs46xx_playback_open_iec958(struct snd_pcm_substream *substream)
{
struct snd_cs46xx *chip = snd_pcm_substream_chip(substream);
- snd_printdd("open raw iec958 channel\n");
+ dev_dbg(chip->card->dev, "open raw iec958 channel\n");
mutex_lock(&chip->spos_mutex);
cs46xx_iec958_pre_open (chip);
@@ -1570,7 +1579,7 @@ static int snd_cs46xx_playback_close_iec958(struct snd_pcm_substream *substream)
int err;
struct snd_cs46xx *chip = snd_pcm_substream_chip(substream);
- snd_printdd("close raw iec958 channel\n");
+ dev_dbg(chip->card->dev, "close raw iec958 channel\n");
err = snd_cs46xx_playback_close(substream);
@@ -2421,10 +2430,10 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97)
/* set the desired CODEC mode */
if (ac97->num == CS46XX_PRIMARY_CODEC_INDEX) {
- snd_printdd("cs46xx: CODEC1 mode %04x\n", 0x0);
+ dev_dbg(ac97->bus->card->dev, "CODEC1 mode %04x\n", 0x0);
snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x0);
} else if (ac97->num == CS46XX_SECONDARY_CODEC_INDEX) {
- snd_printdd("cs46xx: CODEC2 mode %04x\n", 0x3);
+ dev_dbg(ac97->bus->card->dev, "CODEC2 mode %04x\n", 0x3);
snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x3);
} else {
snd_BUG(); /* should never happen ... */
@@ -2456,7 +2465,8 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97)
msleep(10);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_ERR "CS46xx secondary codec doesn't respond!\n");
+ dev_err(ac97->bus->card->dev,
+ "CS46xx secondary codec doesn't respond!\n");
}
#endif
@@ -2476,7 +2486,8 @@ static int cs46xx_detect_codec(struct snd_cs46xx *chip, int codec)
snd_cs46xx_codec_write(chip, AC97_RESET, 0, codec);
udelay(10);
if (snd_cs46xx_codec_read(chip, AC97_RESET, codec) & 0x8000) {
- snd_printdd("snd_cs46xx: seconadry codec not present\n");
+ dev_dbg(chip->card->dev,
+ "seconadry codec not present\n");
return -ENXIO;
}
}
@@ -2489,7 +2500,7 @@ static int cs46xx_detect_codec(struct snd_cs46xx *chip, int codec)
}
msleep(10);
}
- snd_printdd("snd_cs46xx: codec %d detection timeout\n", codec);
+ dev_dbg(chip->card->dev, "codec %d detection timeout\n", codec);
return -ENXIO;
}
@@ -2509,7 +2520,7 @@ int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device)
/* detect primary codec */
chip->nr_ac97_codecs = 0;
- snd_printdd("snd_cs46xx: detecting primary codec\n");
+ dev_dbg(chip->card->dev, "detecting primary codec\n");
if ((err = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus)) < 0)
return err;
chip->ac97_bus->private_free = snd_cs46xx_mixer_free_ac97_bus;
@@ -2519,7 +2530,7 @@ int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device)
chip->nr_ac97_codecs = 1;
#ifdef CONFIG_SND_CS46XX_NEW_DSP
- snd_printdd("snd_cs46xx: detecting seconadry codec\n");
+ dev_dbg(chip->card->dev, "detecting seconadry codec\n");
/* try detect a secondary codec */
if (! cs46xx_detect_codec(chip, CS46XX_SECONDARY_CODEC_INDEX))
chip->nr_ac97_codecs = 2;
@@ -2554,7 +2565,7 @@ int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device)
}
/* do soundcard specific mixer setup */
if (chip->mixer_init) {
- snd_printdd ("calling chip->mixer_init(chip);\n");
+ dev_dbg(chip->card->dev, "calling chip->mixer_init(chip);\n");
chip->mixer_init(chip);
}
#endif
@@ -2801,7 +2812,8 @@ int snd_cs46xx_gameport(struct snd_cs46xx *chip)
chip->gameport = gp = gameport_allocate_port();
if (!gp) {
- printk(KERN_ERR "cs46xx: cannot allocate memory for gameport\n");
+ dev_err(chip->card->dev,
+ "cannot allocate memory for gameport\n");
return -ENOMEM;
}
@@ -3138,8 +3150,10 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip)
}
- snd_printk(KERN_ERR "create - never read codec ready from AC'97\n");
- snd_printk(KERN_ERR "it is not probably bug, try to use CS4236 driver\n");
+ dev_err(chip->card->dev,
+ "create - never read codec ready from AC'97\n");
+ dev_err(chip->card->dev,
+ "it is not probably bug, try to use CS4236 driver\n");
return -EIO;
ok1:
#ifdef CONFIG_SND_CS46XX_NEW_DSP
@@ -3157,7 +3171,8 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip)
* Make sure CODEC is READY.
*/
if (!(snd_cs46xx_peekBA0(chip, BA0_ACSTS2) & ACSTS_CRDY))
- snd_printdd("cs46xx: never read card ready from secondary AC'97\n");
+ dev_dbg(chip->card->dev,
+ "never read card ready from secondary AC'97\n");
}
#endif
@@ -3187,17 +3202,21 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip)
}
#ifndef CONFIG_SND_CS46XX_NEW_DSP
- snd_printk(KERN_ERR "create - never read ISV3 & ISV4 from AC'97\n");
+ dev_err(chip->card->dev,
+ "create - never read ISV3 & ISV4 from AC'97\n");
return -EIO;
#else
/* This may happen on a cold boot with a Terratec SiXPack 5.1.
Reloading the driver may help, if there's other soundcards
with the same problem I would like to know. (Benny) */
- snd_printk(KERN_ERR "ERROR: snd-cs46xx: never read ISV3 & ISV4 from AC'97\n");
- snd_printk(KERN_ERR " Try reloading the ALSA driver, if you find something\n");
- snd_printk(KERN_ERR " broken or not working on your soundcard upon\n");
- snd_printk(KERN_ERR " this message please report to alsa-devel@alsa-project.org\n");
+ dev_err(chip->card->dev, "never read ISV3 & ISV4 from AC'97\n");
+ dev_err(chip->card->dev,
+ "Try reloading the ALSA driver, if you find something\n");
+ dev_err(chip->card->dev,
+ "broken or not working on your soundcard upon\n");
+ dev_err(chip->card->dev,
+ "this message please report to alsa-devel@alsa-project.org\n");
return -EIO;
#endif
@@ -3266,13 +3285,13 @@ int snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
for (i = 0; i < CS46XX_DSP_MODULES; i++) {
err = load_firmware(chip, &chip->modules[i], module_names[i]);
if (err < 0) {
- snd_printk(KERN_ERR "firmware load error [%s]\n",
+ dev_err(chip->card->dev, "firmware load error [%s]\n",
module_names[i]);
return err;
}
err = cs46xx_dsp_load_module(chip, chip->modules[i]);
if (err < 0) {
- snd_printk(KERN_ERR "image download error [%s]\n",
+ dev_err(chip->card->dev, "image download error [%s]\n",
module_names[i]);
return err;
}
@@ -3288,7 +3307,7 @@ int snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
/* old image */
err = snd_cs46xx_download_image(chip);
if (err < 0) {
- snd_printk(KERN_ERR "image download error\n");
+ dev_err(chip->card->dev, "image download error\n");
return err;
}
@@ -3341,7 +3360,7 @@ static int voyetra_setup_eapd_slot(struct snd_cs46xx *chip)
u32 idx, valid_slots,tmp,powerdown = 0;
u16 modem_power,pin_config,logic_type;
- snd_printdd ("cs46xx: cs46xx_setup_eapd_slot()+\n");
+ dev_dbg(chip->card->dev, "cs46xx_setup_eapd_slot()+\n");
/*
* See if the devices are powered down. If so, we must power them up first
@@ -3359,7 +3378,8 @@ static int voyetra_setup_eapd_slot(struct snd_cs46xx *chip)
* stuff.
*/
if(chip->nr_ac97_codecs != 2) {
- snd_printk (KERN_ERR "cs46xx: cs46xx_setup_eapd_slot() - no secondary codec configured\n");
+ dev_err(chip->card->dev,
+ "cs46xx_setup_eapd_slot() - no secondary codec configured\n");
return -EINVAL;
}
@@ -3400,7 +3420,7 @@ static int voyetra_setup_eapd_slot(struct snd_cs46xx *chip)
snd_cs46xx_pokeBA0(chip, BA0_ACOSV, valid_slots);
if ( cs46xx_wait_for_fifo(chip,1) ) {
- snd_printdd("FIFO is busy\n");
+ dev_dbg(chip->card->dev, "FIFO is busy\n");
return -EINVAL;
}
@@ -3421,7 +3441,9 @@ static int voyetra_setup_eapd_slot(struct snd_cs46xx *chip)
* Wait for command to complete
*/
if ( cs46xx_wait_for_fifo(chip,200) ) {
- snd_printdd("failed waiting for FIFO at addr (%02X)\n",idx);
+ dev_dbg(chip->card->dev,
+ "failed waiting for FIFO at addr (%02X)\n",
+ idx);
return -EINVAL;
}
@@ -3510,14 +3532,14 @@ static void amp_hercules(struct snd_cs46xx *chip, int change)
chip->amplifier += change;
if (chip->amplifier && !old) {
- snd_printdd ("Hercules amplifier ON\n");
+ dev_dbg(chip->card->dev, "Hercules amplifier ON\n");
snd_cs46xx_pokeBA0(chip, BA0_EGPIODR,
EGPIODR_GPOE2 | val1); /* enable EGPIO2 output */
snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR,
EGPIOPTR_GPPT2 | val2); /* open-drain on output */
} else if (old && !chip->amplifier) {
- snd_printdd ("Hercules amplifier OFF\n");
+ dev_dbg(chip->card->dev, "Hercules amplifier OFF\n");
snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, val1 & ~EGPIODR_GPOE2); /* disable */
snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, val2 & ~EGPIOPTR_GPPT2); /* disable */
}
@@ -3525,7 +3547,7 @@ static void amp_hercules(struct snd_cs46xx *chip, int change)
static void voyetra_mixer_init (struct snd_cs46xx *chip)
{
- snd_printdd ("initializing Voyetra mixer\n");
+ dev_dbg(chip->card->dev, "initializing Voyetra mixer\n");
/* Enable SPDIF out */
snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, EGPIODR_GPOE0);
@@ -3543,7 +3565,7 @@ static void hercules_mixer_init (struct snd_cs46xx *chip)
/* set EGPIO to default */
hercules_init(chip);
- snd_printdd ("initializing Hercules mixer\n");
+ dev_dbg(chip->card->dev, "initializing Hercules mixer\n");
#ifdef CONFIG_SND_CS46XX_NEW_DSP
if (chip->in_suspend)
@@ -3554,7 +3576,9 @@ static void hercules_mixer_init (struct snd_cs46xx *chip)
kctl = snd_ctl_new1(&snd_hercules_controls[idx], chip);
if ((err = snd_ctl_add(card, kctl)) < 0) {
- printk (KERN_ERR "cs46xx: failed to initialize Hercules mixer (%d)\n",err);
+ dev_err(card->dev,
+ "failed to initialize Hercules mixer (%d)\n",
+ err);
break;
}
}
@@ -3826,8 +3850,7 @@ static int snd_cs46xx_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "cs46xx: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -3932,7 +3955,8 @@ int snd_cs46xx_create(struct snd_card *card,
chip->ba1_addr = pci_resource_start(pci, 1);
if (chip->ba0_addr == 0 || chip->ba0_addr == (unsigned long)~0 ||
chip->ba1_addr == 0 || chip->ba1_addr == (unsigned long)~0) {
- snd_printk(KERN_ERR "wrong address(es) - ba0 = 0x%lx, ba1 = 0x%lx\n",
+ dev_err(chip->card->dev,
+ "wrong address(es) - ba0 = 0x%lx, ba1 = 0x%lx\n",
chip->ba0_addr, chip->ba1_addr);
snd_cs46xx_free(chip);
return -ENOMEM;
@@ -3969,7 +3993,8 @@ int snd_cs46xx_create(struct snd_card *card,
for (cp = &cards[0]; cp->name; cp++) {
if (cp->vendor == ss_vendor && cp->id == ss_card) {
- snd_printdd ("hack for %s enabled\n", cp->name);
+ dev_dbg(chip->card->dev, "hack for %s enabled\n",
+ cp->name);
chip->amplifier_ctrl = cp->amp;
chip->active_ctrl = cp->active;
@@ -3982,12 +4007,14 @@ int snd_cs46xx_create(struct snd_card *card,
}
if (external_amp) {
- snd_printk(KERN_INFO "Crystal EAPD support forced on.\n");
+ dev_info(chip->card->dev,
+ "Crystal EAPD support forced on.\n");
chip->amplifier_ctrl = amp_voyetra;
}
if (thinkpad) {
- snd_printk(KERN_INFO "Activating CLKRUN hack for Thinkpad.\n");
+ dev_info(chip->card->dev,
+ "Activating CLKRUN hack for Thinkpad.\n");
chip->active_ctrl = clkrun_hack;
clkrun_init(chip);
}
@@ -4005,14 +4032,16 @@ int snd_cs46xx_create(struct snd_card *card,
region = &chip->region.idx[idx];
if ((region->resource = request_mem_region(region->base, region->size,
region->name)) == NULL) {
- snd_printk(KERN_ERR "unable to request memory region 0x%lx-0x%lx\n",
+ dev_err(chip->card->dev,
+ "unable to request memory region 0x%lx-0x%lx\n",
region->base, region->base + region->size - 1);
snd_cs46xx_free(chip);
return -EBUSY;
}
region->remap_addr = ioremap_nocache(region->base, region->size);
if (region->remap_addr == NULL) {
- snd_printk(KERN_ERR "%s ioremap problem\n", region->name);
+ dev_err(chip->card->dev,
+ "%s ioremap problem\n", region->name);
snd_cs46xx_free(chip);
return -ENOMEM;
}
@@ -4020,7 +4049,7 @@ int snd_cs46xx_create(struct snd_card *card,
if (request_irq(pci->irq, snd_cs46xx_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(chip->card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_cs46xx_free(chip);
return -EBUSY;
}
@@ -4058,8 +4087,6 @@ int snd_cs46xx_create(struct snd_card *card,
chip->active_ctrl(chip, -1); /* disable CLKRUN */
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
return 0;
}
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index 1686b4f4c44f..1c4a0fb3ffef 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -85,12 +85,15 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32
address = (hival & 0x00FFF) << 5;
address |= loval >> 15;
- snd_printdd("handle_wideop[1]: %05x:%05x addr %04x\n",hival,loval,address);
+ dev_dbg(chip->card->dev,
+ "handle_wideop[1]: %05x:%05x addr %04x\n",
+ hival, loval, address);
if ( !(address & 0x8000) ) {
address += (ins->code.offset / 2) - overlay_begin_address;
} else {
- snd_printdd("handle_wideop[1]: ROM symbol not reallocated\n");
+ dev_dbg(chip->card->dev,
+ "handle_wideop[1]: ROM symbol not reallocated\n");
}
hival &= 0xFF000;
@@ -102,8 +105,9 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32
address = (hival & 0x00FFF) << 5;
address |= loval >> 15;
- snd_printdd("handle_wideop:[2] %05x:%05x addr %04x\n",hival,loval,address);
- nreallocated ++;
+ dev_dbg(chip->card->dev,
+ "handle_wideop:[2] %05x:%05x addr %04x\n",
+ hival, loval, address); nreallocated++;
} /* wide_opcodes[j] == wide_op */
} /* for */
} /* mod_type == 0 ... */
@@ -113,7 +117,8 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32
ins->code.data[ins->code.size++] = hival;
}
- snd_printdd("dsp_spos: %d instructions reallocated\n",nreallocated);
+ dev_dbg(chip->card->dev,
+ "dsp_spos: %d instructions reallocated\n", nreallocated);
return nreallocated;
}
@@ -157,7 +162,8 @@ static int add_symbols (struct snd_cs46xx * chip, struct dsp_module_desc * modul
for (i = 0;i < module->symbol_table.nsymbols; ++i) {
if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
- snd_printk(KERN_ERR "dsp_spos: symbol table is full\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: symbol table is full\n");
return -ENOMEM;
}
@@ -176,8 +182,11 @@ static int add_symbols (struct snd_cs46xx * chip, struct dsp_module_desc * modul
ins->symbol_table.nsymbols++;
} else {
- /* if (0) printk ("dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n",
- module->symbol_table.symbols[i].symbol_name); */
+#if 0
+ dev_dbg(chip->card->dev,
+ "dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n",
+ module->symbol_table.symbols[i].symbol_name); */
+#endif
}
}
@@ -192,14 +201,15 @@ add_symbol (struct snd_cs46xx * chip, char * symbol_name, u32 address, int type)
int index;
if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
- snd_printk(KERN_ERR "dsp_spos: symbol table is full\n");
+ dev_err(chip->card->dev, "dsp_spos: symbol table is full\n");
return NULL;
}
if (cs46xx_dsp_lookup_symbol(chip,
symbol_name,
type) != NULL) {
- snd_printk(KERN_ERR "dsp_spos: symbol <%s> duplicated\n", symbol_name);
+ dev_err(chip->card->dev,
+ "dsp_spos: symbol <%s> duplicated\n", symbol_name);
return NULL;
}
@@ -305,19 +315,20 @@ static int dsp_load_parameter(struct snd_cs46xx *chip,
u32 doffset, dsize;
if (!parameter) {
- snd_printdd("dsp_spos: module got no parameter segment\n");
+ dev_dbg(chip->card->dev,
+ "dsp_spos: module got no parameter segment\n");
return 0;
}
doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
dsize = parameter->size * 4;
- snd_printdd("dsp_spos: "
- "downloading parameter data to chip (%08x-%08x)\n",
+ dev_dbg(chip->card->dev,
+ "dsp_spos: downloading parameter data to chip (%08x-%08x)\n",
doffset,doffset + dsize);
if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
- snd_printk(KERN_ERR "dsp_spos: "
- "failed to download parameter data to DSP\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: failed to download parameter data to DSP\n");
return -EINVAL;
}
return 0;
@@ -329,18 +340,21 @@ static int dsp_load_sample(struct snd_cs46xx *chip,
u32 doffset, dsize;
if (!sample) {
- snd_printdd("dsp_spos: module got no sample segment\n");
+ dev_dbg(chip->card->dev,
+ "dsp_spos: module got no sample segment\n");
return 0;
}
doffset = (sample->offset * 4 + DSP_SAMPLE_BYTE_OFFSET);
dsize = sample->size * 4;
- snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n",
+ dev_dbg(chip->card->dev,
+ "dsp_spos: downloading sample data to chip (%08x-%08x)\n",
doffset,doffset + dsize);
if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
- snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: failed to sample data to DSP\n");
return -EINVAL;
}
return 0;
@@ -354,14 +368,16 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m
int err;
if (ins->nmodules == DSP_MAX_MODULES - 1) {
- snd_printk(KERN_ERR "dsp_spos: to many modules loaded into DSP\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: to many modules loaded into DSP\n");
return -ENOMEM;
}
- snd_printdd("dsp_spos: loading module %s into DSP\n", module->module_name);
+ dev_dbg(chip->card->dev,
+ "dsp_spos: loading module %s into DSP\n", module->module_name);
if (ins->nmodules == 0) {
- snd_printdd("dsp_spos: clearing parameter area\n");
+ dev_dbg(chip->card->dev, "dsp_spos: clearing parameter area\n");
snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE);
}
@@ -371,7 +387,7 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m
return err;
if (ins->nmodules == 0) {
- snd_printdd("dsp_spos: clearing sample area\n");
+ dev_dbg(chip->card->dev, "dsp_spos: clearing sample area\n");
snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE);
}
@@ -381,15 +397,17 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m
return err;
if (ins->nmodules == 0) {
- snd_printdd("dsp_spos: clearing code area\n");
+ dev_dbg(chip->card->dev, "dsp_spos: clearing code area\n");
snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
}
if (code == NULL) {
- snd_printdd("dsp_spos: module got no code segment\n");
+ dev_dbg(chip->card->dev,
+ "dsp_spos: module got no code segment\n");
} else {
if (ins->code.offset + code->size > DSP_CODE_BYTE_SIZE) {
- snd_printk(KERN_ERR "dsp_spos: no space available in DSP\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: no space available in DSP\n");
return -ENOMEM;
}
@@ -401,19 +419,22 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m
if (snd_BUG_ON(!module->symbol_table.symbols))
return -ENOMEM;
if (add_symbols(chip,module)) {
- snd_printk(KERN_ERR "dsp_spos: failed to load symbol table\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: failed to load symbol table\n");
return -ENOMEM;
}
doffset = (code->offset * 4 + ins->code.offset * 4 + DSP_CODE_BYTE_OFFSET);
dsize = code->size * 4;
- snd_printdd("dsp_spos: downloading code to chip (%08x-%08x)\n",
+ dev_dbg(chip->card->dev,
+ "dsp_spos: downloading code to chip (%08x-%08x)\n",
doffset,doffset + dsize);
module->nfixups = shadow_and_reallocate_code(chip,code->data,code->size,module->overlay_begin_address);
if (snd_cs46xx_download (chip,(ins->code.data + ins->code.offset),doffset,dsize)) {
- snd_printk(KERN_ERR "dsp_spos: failed to download code to DSP\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: failed to download code to DSP\n");
return -EINVAL;
}
@@ -447,7 +468,7 @@ cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name, int symb
}
#if 0
- printk ("dsp_spos: symbol <%s> type %02x not found\n",
+ dev_err(chip->card->dev, "dsp_spos: symbol <%s> type %02x not found\n",
symbol_name,symbol_type);
#endif
@@ -910,7 +931,6 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip)
}
#endif /* CONFIG_PROC_FS */
-static int debug_tree;
static void _dsp_create_task_tree (struct snd_cs46xx *chip, u32 * task_data,
u32 dest, int size)
{
@@ -919,13 +939,13 @@ static void _dsp_create_task_tree (struct snd_cs46xx *chip, u32 * task_data,
int i;
for (i = 0; i < size; ++i) {
- if (debug_tree) printk ("addr %p, val %08x\n",spdst,task_data[i]);
+ dev_dbg(chip->card->dev, "addr %p, val %08x\n",
+ spdst, task_data[i]);
writel(task_data[i],spdst);
spdst += sizeof(u32);
}
}
-static int debug_scb;
static void _dsp_create_scb (struct snd_cs46xx *chip, u32 * scb_data, u32 dest)
{
void __iomem *spdst = chip->region.idx[1].remap_addr +
@@ -933,7 +953,8 @@ static void _dsp_create_scb (struct snd_cs46xx *chip, u32 * scb_data, u32 dest)
int i;
for (i = 0; i < 0x10; ++i) {
- if (debug_scb) printk ("addr %p, val %08x\n",spdst,scb_data[i]);
+ dev_dbg(chip->card->dev, "addr %p, val %08x\n",
+ spdst, scb_data[i]);
writel(scb_data[i],spdst);
spdst += sizeof(u32);
}
@@ -960,7 +981,8 @@ static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * nam
int index;
if (ins->nscb == DSP_MAX_SCB_DESC - 1) {
- snd_printk(KERN_ERR "dsp_spos: got no place for other SCB\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: got no place for other SCB\n");
return NULL;
}
@@ -991,7 +1013,8 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
struct dsp_task_descriptor * desc = NULL;
if (ins->ntask == DSP_MAX_TASK_DESC - 1) {
- snd_printk(KERN_ERR "dsp_spos: got no place for other TASK\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: got no place for other TASK\n");
return NULL;
}
@@ -1031,7 +1054,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32
desc->data = scb_data;
_dsp_create_scb(chip,scb_data,dest);
} else {
- snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
+ dev_err(chip->card->dev, "dsp_spos: failed to map SCB\n");
#ifdef CONFIG_PM_SLEEP
kfree(scb_data);
#endif
@@ -1052,7 +1075,7 @@ cs46xx_dsp_create_task_tree (struct snd_cs46xx *chip, char * name, u32 * task_da
desc->data = task_data;
_dsp_create_task_tree(chip,task_data,dest,size);
} else {
- snd_printk(KERN_ERR "dsp_spos: failed to map TASK\n");
+ dev_err(chip->card->dev, "dsp_spos: failed to map TASK\n");
}
return desc;
@@ -1105,31 +1128,36 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip)
null_algorithm = cs46xx_dsp_lookup_symbol(chip, "NULLALGORITHM", SYMBOL_CODE);
if (null_algorithm == NULL) {
- snd_printk(KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: symbol NULLALGORITHM not found\n");
return -EIO;
}
fg_task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "FGTASKTREEHEADERCODE", SYMBOL_CODE);
if (fg_task_tree_header_code == NULL) {
- snd_printk(KERN_ERR "dsp_spos: symbol FGTASKTREEHEADERCODE not found\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: symbol FGTASKTREEHEADERCODE not found\n");
return -EIO;
}
task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "TASKTREEHEADERCODE", SYMBOL_CODE);
if (task_tree_header_code == NULL) {
- snd_printk(KERN_ERR "dsp_spos: symbol TASKTREEHEADERCODE not found\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: symbol TASKTREEHEADERCODE not found\n");
return -EIO;
}
task_tree_thread = cs46xx_dsp_lookup_symbol(chip, "TASKTREETHREAD", SYMBOL_CODE);
if (task_tree_thread == NULL) {
- snd_printk(KERN_ERR "dsp_spos: symbol TASKTREETHREAD not found\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: symbol TASKTREETHREAD not found\n");
return -EIO;
}
magic_snoop_task = cs46xx_dsp_lookup_symbol(chip, "MAGICSNOOPTASK", SYMBOL_CODE);
if (magic_snoop_task == NULL) {
- snd_printk(KERN_ERR "dsp_spos: symbol MAGICSNOOPTASK not found\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: symbol MAGICSNOOPTASK not found\n");
return -EIO;
}
@@ -1476,7 +1504,7 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip)
return 0;
_fail_end:
- snd_printk(KERN_ERR "dsp_spos: failed to setup SCB's in DSP\n");
+ dev_err(chip->card->dev, "dsp_spos: failed to setup SCB's in DSP\n");
return -EINVAL;
}
@@ -1491,18 +1519,21 @@ static int cs46xx_dsp_async_init (struct snd_cs46xx *chip,
s16_async_codec_input_task = cs46xx_dsp_lookup_symbol(chip, "S16_ASYNCCODECINPUTTASK", SYMBOL_CODE);
if (s16_async_codec_input_task == NULL) {
- snd_printk(KERN_ERR "dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n");
return -EIO;
}
spdifo_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFOTASK", SYMBOL_CODE);
if (spdifo_task == NULL) {
- snd_printk(KERN_ERR "dsp_spos: symbol SPDIFOTASK not found\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: symbol SPDIFOTASK not found\n");
return -EIO;
}
spdifi_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFITASK", SYMBOL_CODE);
if (spdifi_task == NULL) {
- snd_printk(KERN_ERR "dsp_spos: symbol SPDIFITASK not found\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: symbol SPDIFITASK not found\n");
return -EIO;
}
@@ -1883,7 +1914,8 @@ int cs46xx_poke_via_dsp (struct snd_cs46xx *chip, u32 address, u32 data)
}
if (i == 25) {
- snd_printk(KERN_ERR "dsp_spos: SPIOWriteTask not responding\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: SPIOWriteTask not responding\n");
return -EBUSY;
}
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
index 409e8764fbeb..8284bc9b5858 100644
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
@@ -233,8 +233,11 @@ void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
{
if (scb->proc_info) {
struct proc_scb_info * scb_info = scb->proc_info->private_data;
+ struct snd_cs46xx *chip = scb_info->chip;
- snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name);
+ dev_dbg(chip->card->dev,
+ "cs46xx_dsp_proc_free_scb_desc: freeing %s\n",
+ scb->scb_name);
snd_info_free_entry(scb->proc_info);
scb->proc_info = NULL;
@@ -305,7 +308,7 @@ _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u
scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
scb_data[SCBfuncEntryPtr] |= task_entry->address;
- snd_printdd("dsp_spos: creating SCB <%s>\n",name);
+ dev_dbg(chip->card->dev, "dsp_spos: creating SCB <%s>\n", name);
scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
@@ -320,9 +323,15 @@ _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u
/* update parent SCB */
if (scb->parent_scb_ptr) {
#if 0
- printk ("scb->parent_scb_ptr = %s\n",scb->parent_scb_ptr->scb_name);
- printk ("scb->parent_scb_ptr->next_scb_ptr = %s\n",scb->parent_scb_ptr->next_scb_ptr->scb_name);
- printk ("scb->parent_scb_ptr->sub_list_ptr = %s\n",scb->parent_scb_ptr->sub_list_ptr->scb_name);
+ dev_dbg(chip->card->dev,
+ "scb->parent_scb_ptr = %s\n",
+ scb->parent_scb_ptr->scb_name);
+ dev_dbg(chip->card->dev,
+ "scb->parent_scb_ptr->next_scb_ptr = %s\n",
+ scb->parent_scb_ptr->next_scb_ptr->scb_name);
+ dev_dbg(chip->card->dev,
+ "scb->parent_scb_ptr->sub_list_ptr = %s\n",
+ scb->parent_scb_ptr->sub_list_ptr->scb_name);
#endif
/* link to parent SCB */
if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
@@ -368,7 +377,8 @@ cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_d
SYMBOL_CODE);
if (task_entry == NULL) {
- snd_printk (KERN_ERR "dsp_spos: symbol %s not found\n",task_entry_name);
+ dev_err(chip->card->dev,
+ "dsp_spos: symbol %s not found\n", task_entry_name);
return NULL;
}
@@ -582,7 +592,8 @@ cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
SYMBOL_CODE);
if (ins->null_algorithm == NULL) {
- snd_printk (KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: symbol NULLALGORITHM not found\n");
return NULL;
}
}
@@ -612,7 +623,8 @@ cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
unsigned int phiIncr;
unsigned int correctionPerGOF, correctionPerSec;
- snd_printdd( "dsp_spos: setting %s rate to %u\n",scb_name,rate);
+ dev_dbg(chip->card->dev, "dsp_spos: setting %s rate to %u\n",
+ scb_name, rate);
/*
* Compute the values used to drive the actual sample rate conversion.
@@ -670,7 +682,8 @@ cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
SYMBOL_CODE);
if (ins->s16_up == NULL) {
- snd_printk (KERN_ERR "dsp_spos: symbol S16_UPSRC not found\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: symbol S16_UPSRC not found\n");
return NULL;
}
}
@@ -1265,7 +1278,7 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
the Sample Rate Converted (which could
alter the raw data stream ...) */
if (sample_rate == 48000) {
- snd_printdd ("IEC958 pass through\n");
+ dev_dbg(chip->card->dev, "IEC958 pass through\n");
/* Hack to bypass creating a new SRC */
pass_through = 1;
}
@@ -1299,13 +1312,14 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
}
if (pcm_index == -1) {
- snd_printk (KERN_ERR "dsp_spos: no free PCM channel\n");
+ dev_err(chip->card->dev, "dsp_spos: no free PCM channel\n");
return NULL;
}
if (src_scb == NULL) {
if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
- snd_printk(KERN_ERR "dsp_spos: to many SRC instances\n!");
+ dev_err(chip->card->dev,
+ "dsp_spos: to many SRC instances\n!");
return NULL;
}
@@ -1331,7 +1345,8 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
- snd_printdd( "dsp_spos: creating SRC \"%s\"\n",scb_name);
+ dev_dbg(chip->card->dev,
+ "dsp_spos: creating SRC \"%s\"\n", scb_name);
src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
sample_rate,
src_output_buffer_addr[src_index],
@@ -1343,7 +1358,8 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
pass_through);
if (!src_scb) {
- snd_printk (KERN_ERR "dsp_spos: failed to create SRCtaskSCB\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: failed to create SRCtaskSCB\n");
return NULL;
}
@@ -1355,8 +1371,8 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
- snd_printdd( "dsp_spos: creating PCM \"%s\" (%d)\n",scb_name,
- pcm_channel_id);
+ dev_dbg(chip->card->dev, "dsp_spos: creating PCM \"%s\" (%d)\n",
+ scb_name, pcm_channel_id);
pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
pcm_reader_buffer_addr[pcm_index],
@@ -1369,7 +1385,8 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
);
if (!pcm_scb) {
- snd_printk (KERN_ERR "dsp_spos: failed to create PCMreaderSCB\n");
+ dev_err(chip->card->dev,
+ "dsp_spos: failed to create PCMreaderSCB\n");
return NULL;
}
@@ -1419,7 +1436,8 @@ int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
temp |= DMA_RQ_C1_SOURCE_MOD16;
break;
default:
- snd_printdd ("period size (%d) not supported by HW\n", period_size);
+ dev_dbg(chip->card->dev,
+ "period size (%d) not supported by HW\n", period_size);
return -EINVAL;
}
@@ -1457,7 +1475,8 @@ int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
temp |= DMA_RQ_C1_DEST_MOD16;
break;
default:
- snd_printdd ("period size (%d) not supported by HW\n", period_size);
+ dev_dbg(chip->card->dev,
+ "period size (%d) not supported by HW\n", period_size);
return -EINVAL;
}
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
index c6b82c85e044..b4e0ff6a99a3 100644
--- a/sound/pci/cs5530.c
+++ b/sound/pci/cs5530.c
@@ -160,17 +160,17 @@ static int snd_cs5530_create(struct snd_card *card,
sb_base = 0x220 + 0x20 * (map & 3);
if (map & (1<<2))
- printk(KERN_INFO "CS5530: XpressAudio at 0x%lx\n", sb_base);
+ dev_info(card->dev, "XpressAudio at 0x%lx\n", sb_base);
else {
- printk(KERN_ERR "Could not find XpressAudio!\n");
+ dev_err(card->dev, "Could not find XpressAudio!\n");
snd_cs5530_free(chip);
return -ENODEV;
}
if (map & (1<<5))
- printk(KERN_INFO "CS5530: MPU at 0x300\n");
+ dev_info(card->dev, "MPU at 0x300\n");
else if (map & (1<<6))
- printk(KERN_INFO "CS5530: MPU at 0x330\n");
+ dev_info(card->dev, "MPU at 0x330\n");
irq = snd_cs5530_mixer_read(sb_base, 0x80) & 0x0F;
dma8 = snd_cs5530_mixer_read(sb_base, 0x81);
@@ -182,7 +182,7 @@ static int snd_cs5530_create(struct snd_card *card,
else if (dma8 & 0x80)
dma16 = 7;
else {
- printk(KERN_ERR "CS5530: No 16bit DMA enabled\n");
+ dev_err(card->dev, "No 16bit DMA enabled\n");
snd_cs5530_free(chip);
return -ENODEV;
}
@@ -194,7 +194,7 @@ static int snd_cs5530_create(struct snd_card *card,
else if (dma8 & 0x08)
dma8 = 3;
else {
- printk(KERN_ERR "CS5530: No 8bit DMA enabled\n");
+ dev_err(card->dev, "No 8bit DMA enabled\n");
snd_cs5530_free(chip);
return -ENODEV;
}
@@ -208,32 +208,31 @@ static int snd_cs5530_create(struct snd_card *card,
else if (irq & 8)
irq = 10;
else {
- printk(KERN_ERR "CS5530: SoundBlaster IRQ not set\n");
+ dev_err(card->dev, "SoundBlaster IRQ not set\n");
snd_cs5530_free(chip);
return -ENODEV;
}
- printk(KERN_INFO "CS5530: IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8,
- dma16);
+ dev_info(card->dev, "IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8, dma16);
err = snd_sbdsp_create(card, sb_base, irq, snd_sb16dsp_interrupt, dma8,
dma16, SB_HW_CS5530, &chip->sb);
if (err < 0) {
- printk(KERN_ERR "CS5530: Could not create SoundBlaster\n");
+ dev_err(card->dev, "Could not create SoundBlaster\n");
snd_cs5530_free(chip);
return err;
}
err = snd_sb16dsp_pcm(chip->sb, 0, &chip->sb->pcm);
if (err < 0) {
- printk(KERN_ERR "CS5530: Could not create PCM\n");
+ dev_err(card->dev, "Could not create PCM\n");
snd_cs5530_free(chip);
return err;
}
err = snd_sbmixer_new(chip->sb);
if (err < 0) {
- printk(KERN_ERR "CS5530: Could not create Mixer\n");
+ dev_err(card->dev, "Could not create Mixer\n");
snd_cs5530_free(chip);
return err;
}
@@ -244,7 +243,6 @@ static int snd_cs5530_create(struct snd_card *card,
return err;
}
- snd_card_set_dev(card, &pci->dev);
*rchip = chip;
return 0;
}
@@ -264,7 +262,8 @@ static int snd_cs5530_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index c0d2835344da..edcbbda5c488 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -84,7 +84,8 @@ static void wait_till_cmd_acked(struct cs5535audio *cs5535au, unsigned long time
udelay(1);
} while (--timeout);
if (!timeout)
- snd_printk(KERN_ERR "Failure writing to cs5535 codec\n");
+ dev_err(cs5535au->card->dev,
+ "Failure writing to cs5535 codec\n");
}
static unsigned short snd_cs5535audio_codec_read(struct cs5535audio *cs5535au,
@@ -109,8 +110,9 @@ static unsigned short snd_cs5535audio_codec_read(struct cs5535audio *cs5535au,
udelay(1);
} while (--timeout);
if (!timeout)
- snd_printk(KERN_ERR "Failure reading codec reg 0x%x,"
- "Last value=0x%x\n", reg, val);
+ dev_err(cs5535au->card->dev,
+ "Failure reading codec reg 0x%x, Last value=0x%x\n",
+ reg, val);
return (unsigned short) val;
}
@@ -168,7 +170,7 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
olpc_prequirks(card, &ac97);
if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) {
- snd_printk(KERN_ERR "mixer failed\n");
+ dev_err(card->dev, "mixer failed\n");
return err;
}
@@ -176,7 +178,7 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
err = olpc_quirks(card, cs5535au->ac97);
if (err < 0) {
- snd_printk(KERN_ERR "olpc quirks failed\n");
+ dev_err(card->dev, "olpc quirks failed\n");
return err;
}
@@ -194,8 +196,9 @@ static void process_bm0_irq(struct cs5535audio *cs5535au)
dma = cs5535au->playback_substream->runtime->private_data;
snd_pcm_period_elapsed(cs5535au->playback_substream);
} else {
- snd_printk(KERN_ERR "unexpected bm0 irq src, bm_stat=%x\n",
- bm_stat);
+ dev_err(cs5535au->card->dev,
+ "unexpected bm0 irq src, bm_stat=%x\n",
+ bm_stat);
}
}
@@ -241,8 +244,9 @@ static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id)
process_bm1_irq(cs5535au);
break;
default:
- snd_printk(KERN_ERR "Unexpected irq src: "
- "0x%x\n", acc_irq_stat);
+ dev_err(cs5535au->card->dev,
+ "Unexpected irq src: 0x%x\n",
+ acc_irq_stat);
break;
}
}
@@ -287,7 +291,7 @@ static int snd_cs5535audio_create(struct snd_card *card,
if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
- printk(KERN_WARNING "unable to get 32bit dma\n");
+ dev_warn(card->dev, "unable to get 32bit dma\n");
err = -ENXIO;
goto pcifail;
}
@@ -312,7 +316,7 @@ static int snd_cs5535audio_create(struct snd_card *card,
if (request_irq(pci->irq, snd_cs5535audio_interrupt,
IRQF_SHARED, KBUILD_MODNAME, cs5535au)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
err = -EBUSY;
goto sndfail;
}
@@ -324,8 +328,6 @@ static int snd_cs5535audio_create(struct snd_card *card,
cs5535au, &ops)) < 0)
goto sndfail;
- snd_card_set_dev(card, &pci->dev);
-
*rcs5535au = cs5535au;
return 0;
@@ -353,7 +355,8 @@ static int snd_cs5535audio_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c
index e6a44507d557..3b0fdaca8dc7 100644
--- a/sound/pci/cs5535audio/cs5535audio_olpc.c
+++ b/sound/pci/cs5535audio/cs5535audio_olpc.c
@@ -36,7 +36,8 @@ void olpc_analog_input(struct snd_ac97 *ac97, int on)
err = snd_ac97_update_bits(ac97, AC97_AD_TEST2,
1 << AC97_AD_HPFD_SHIFT, on << AC97_AD_HPFD_SHIFT);
if (err < 0) {
- snd_printk(KERN_ERR "setting High Pass Filter - %d\n", err);
+ dev_err(ac97->bus->card->dev,
+ "setting High Pass Filter - %d\n", err);
return;
}
@@ -58,7 +59,7 @@ void olpc_mic_bias(struct snd_ac97 *ac97, int on)
err = snd_ac97_update_bits(ac97, AC97_AD_MISC,
1 << AC97_AD_VREFD_SHIFT, on << AC97_AD_VREFD_SHIFT);
if (err < 0)
- snd_printk(KERN_ERR "setting MIC Bias - %d\n", err);
+ dev_err(ac97->bus->card->dev, "setting MIC Bias - %d\n", err);
}
static int olpc_dc_info(struct snd_kcontrol *kctl,
@@ -153,7 +154,7 @@ int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97)
return 0;
if (gpio_request(OLPC_GPIO_MIC_AC, DRV_NAME)) {
- printk(KERN_ERR DRV_NAME ": unable to allocate MIC GPIO\n");
+ dev_err(card->dev, "unable to allocate MIC GPIO\n");
return -EIO;
}
gpio_direction_output(OLPC_GPIO_MIC_AC, 0);
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c
index 9ab01a7047cf..9c2dc911d8d7 100644
--- a/sound/pci/cs5535audio/cs5535audio_pcm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pcm.c
@@ -317,7 +317,7 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd)
dma->ops->disable_dma(cs5535au);
break;
default:
- snd_printk(KERN_ERR "unhandled trigger\n");
+ dev_err(cs5535au->card->dev, "unhandled trigger\n");
err = -EINVAL;
break;
}
@@ -335,13 +335,13 @@ static snd_pcm_uframes_t snd_cs5535audio_pcm_pointer(struct snd_pcm_substream
dma = substream->runtime->private_data;
curdma = dma->ops->read_dma_pntr(cs5535au);
if (curdma < dma->buf_addr) {
- snd_printk(KERN_ERR "curdma=%x < %x bufaddr.\n",
+ dev_err(cs5535au->card->dev, "curdma=%x < %x bufaddr.\n",
curdma, dma->buf_addr);
return 0;
}
curdma -= dma->buf_addr;
if (curdma >= dma->buf_bytes) {
- snd_printk(KERN_ERR "diff=%x >= %x buf_bytes.\n",
+ dev_err(cs5535au->card->dev, "diff=%x >= %x buf_bytes.\n",
curdma, dma->buf_bytes);
return 0;
}
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c
index 6c34def5986d..34cc60057d0c 100644
--- a/sound/pci/cs5535audio/cs5535audio_pm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pm.c
@@ -74,7 +74,7 @@ static int snd_cs5535audio_suspend(struct device *dev)
snd_cs5535audio_stop_hardware(cs5535au);
if (pci_save_state(pci)) {
- printk(KERN_ERR "cs5535audio: pci_save_state failed!\n");
+ dev_err(dev, "pci_save_state failed!\n");
return -EIO;
}
pci_disable_device(pci);
@@ -94,8 +94,7 @@ static int snd_cs5535audio_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "cs5535audio: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -113,7 +112,7 @@ static int snd_cs5535audio_resume(struct device *dev)
} while (--timeout);
if (!timeout)
- snd_printk(KERN_ERR "Failure getting AC Link ready\n");
+ dev_err(cs5535au->card->dev, "Failure getting AC Link ready\n");
/* set up rate regs, dma. actual initiation is done in trig */
for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) {
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index eb86829529eb..af632bd08323 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -1739,8 +1739,6 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci,
if (err < 0)
goto error1;
- snd_card_set_dev(card, &pci->dev);
-
*ratc = atc;
return 0;
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c
index d464ad2fc7b7..98426d09c8bd 100644
--- a/sound/pci/ctxfi/xfi.c
+++ b/sound/pci/ctxfi/xfi.c
@@ -71,7 +71,8 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
dev++;
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err)
return err;
if ((reference_rate != 48000) && (reference_rate != 44100)) {
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 05cfe551ce42..9f10c9e0df5e 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -58,7 +58,8 @@ static int get_firmware(const struct firmware **fw_entry,
snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data);
err = request_firmware(fw_entry, name, pci_device(chip));
if (err < 0)
- snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err);
+ dev_err(chip->card->dev,
+ "get_firmware(): Firmware not available (%d)\n", err);
#ifdef CONFIG_PM_SLEEP
else
chip->fw_cache[fw_index] = *fw_entry;
@@ -563,7 +564,7 @@ static int init_engine(struct snd_pcm_substream *substream,
err = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
if (err < 0) {
- snd_printk(KERN_ERR "malloc_pages err=%d\n", err);
+ dev_err(chip->card->dev, "malloc_pages err=%d\n", err);
spin_lock_irq(&chip->lock);
free_pipes(chip, pipe);
spin_unlock_irq(&chip->lock);
@@ -1989,8 +1990,8 @@ static int snd_echo_create(struct snd_card *card,
if ((chip->iores = request_mem_region(chip->dsp_registers_phys, sz,
ECHOCARD_NAME)) == NULL) {
+ dev_err(chip->card->dev, "cannot get memory region\n");
snd_echo_free(chip);
- snd_printk(KERN_ERR "cannot get memory region\n");
return -EBUSY;
}
chip->dsp_registers = (volatile u32 __iomem *)
@@ -1998,8 +1999,8 @@ static int snd_echo_create(struct snd_card *card,
if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
+ dev_err(chip->card->dev, "cannot grab irq\n");
snd_echo_free(chip);
- snd_printk(KERN_ERR "cannot grab irq\n");
return -EBUSY;
}
chip->irq = pci->irq;
@@ -2011,8 +2012,8 @@ static int snd_echo_create(struct snd_card *card,
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
sizeof(struct comm_page),
&chip->commpage_dma_buf) < 0) {
+ dev_err(chip->card->dev, "cannot allocate the comm page\n");
snd_echo_free(chip);
- snd_printk(KERN_ERR "cannot allocate the comm page\n");
return -ENOMEM;
}
chip->comm_page_phys = chip->commpage_dma_buf.addr;
@@ -2058,12 +2059,11 @@ static int snd_echo_probe(struct pci_dev *pci,
DE_INIT(("Echoaudio driver starting...\n"));
i = 0;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
- snd_card_set_dev(card, &pci->dev);
-
chip = NULL; /* Tells snd_echo_create to allocate chip */
if ((err = snd_echo_create(card, pci, &chip)) < 0) {
snd_card_free(card);
@@ -2082,7 +2082,7 @@ static int snd_echo_probe(struct pci_dev *pci,
chip->dsp_registers_phys, chip->irq);
if ((err = snd_echo_new_pcm(chip)) < 0) {
- snd_printk(KERN_ERR "new pcm error %d\n", err);
+ dev_err(chip->card->dev, "new pcm error %d\n", err);
snd_card_free(card);
return err;
}
@@ -2090,7 +2090,7 @@ static int snd_echo_probe(struct pci_dev *pci,
#ifdef ECHOCARD_HAS_MIDI
if (chip->has_midi) { /* Some Mia's do not have midi */
if ((err = snd_echo_midi_create(card, chip)) < 0) {
- snd_printk(KERN_ERR "new midi error %d\n", err);
+ dev_err(chip->card->dev, "new midi error %d\n", err);
snd_card_free(card);
return err;
}
@@ -2189,14 +2189,14 @@ static int snd_echo_probe(struct pci_dev *pci,
err = snd_card_register(card);
if (err < 0)
goto ctl_error;
- snd_printk(KERN_INFO "Card registered: %s\n", card->longname);
+ dev_info(card->dev, "Card registered: %s\n", card->longname);
pci_set_drvdata(pci, chip);
dev++;
return 0;
ctl_error:
- snd_printk(KERN_ERR "new control error %d\n", err);
+ dev_err(card->dev, "new control error %d\n", err);
snd_card_free(card);
return err;
}
@@ -2291,8 +2291,8 @@ static int snd_echo_resume(struct device *dev)
if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
+ dev_err(chip->card->dev, "cannot grab irq\n");
snd_echo_free(chip);
- snd_printk(KERN_ERR "cannot grab irq\n");
return -EBUSY;
}
chip->irq = pci->irq;
diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c
index d8c670c9d62c..5a6a217b82e0 100644
--- a/sound/pci/echoaudio/echoaudio_dsp.c
+++ b/sound/pci/echoaudio/echoaudio_dsp.c
@@ -53,7 +53,7 @@ static int wait_handshake(struct echoaudio *chip)
udelay(1);
}
- snd_printk(KERN_ERR "wait_handshake(): Timeout waiting for DSP\n");
+ dev_err(chip->card->dev, "wait_handshake(): Timeout waiting for DSP\n");
return -EBUSY;
}
@@ -149,7 +149,8 @@ static int read_sn(struct echoaudio *chip)
for (i = 0; i < 5; i++) {
if (read_dsp(chip, &sn[i])) {
- snd_printk(KERN_ERR "Failed to read serial number\n");
+ dev_err(chip->card->dev,
+ "Failed to read serial number\n");
return -EIO;
}
}
@@ -184,7 +185,7 @@ static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic)
err = get_firmware(&fw, chip, asic);
if (err < 0) {
- snd_printk(KERN_WARNING "Firmware not found !\n");
+ dev_warn(chip->card->dev, "Firmware not found !\n");
return err;
}
@@ -247,7 +248,7 @@ static int install_resident_loader(struct echoaudio *chip)
i = get_firmware(&fw, chip, FW_361_LOADER);
if (i < 0) {
- snd_printk(KERN_WARNING "Firmware not found !\n");
+ dev_warn(chip->card->dev, "Firmware not found !\n");
return i;
}
diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c
index abfd51c2530e..7f4dfae0323a 100644
--- a/sound/pci/echoaudio/midi.c
+++ b/sound/pci/echoaudio/midi.c
@@ -221,7 +221,8 @@ static void snd_echo_midi_output_write(unsigned long data)
DE_MID(("Try to send %d bytes...\n", bytes));
sent = write_midi(chip, buf, bytes);
if (sent < 0) {
- snd_printk(KERN_ERR "write_midi() error %d\n", sent);
+ dev_err(chip->card->dev,
+ "write_midi() error %d\n", sent);
/* retry later */
sent = 9000;
chip->midi_full = 1;
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index 9e1bd0c39a8c..ad9d9f8b48ed 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -117,7 +117,8 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
if (max_buffer_size[dev] < 32)
@@ -169,7 +170,8 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH,
sizeof(struct snd_emu10k1_synth_arg), &wave) < 0 ||
wave == NULL) {
- snd_printk(KERN_WARNING "can't initialize Emu10k1 wavetable synth\n");
+ dev_warn(emu->card->dev,
+ "can't initialize Emu10k1 wavetable synth\n");
} else {
struct snd_emu10k1_synth_arg *arg;
arg = SNDRV_SEQ_DEVICE_ARGPTR(wave);
@@ -246,8 +248,7 @@ static int snd_emu10k1_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "emu10k1: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c
index cae36597aa71..3f3ef38d9b6e 100644
--- a/sound/pci/emu10k1/emu10k1_callback.c
+++ b/sound/pci/emu10k1/emu10k1_callback.c
@@ -105,7 +105,7 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw)
vp = &emu->voices[best[i].voice];
if ((ch = vp->ch) < 0) {
/*
- printk(KERN_WARNING
+ dev_warn(emu->card->dev,
"synth_get_voice: ch < 0 (%d) ??", i);
*/
continue;
@@ -339,7 +339,7 @@ start_voice(struct snd_emux_voice *vp)
return -EINVAL;
emem->map_locked++;
if (snd_emu10k1_memblk_map(hw, emem) < 0) {
- /* printk(KERN_ERR "emu: cannot map!\n"); */
+ /* dev_err(hw->card->devK, "emu: cannot map!\n"); */
return -ENOMEM;
}
mapped_offset = snd_emu10k1_memblk_offset(emem) >> 1;
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index bdd888ec9a84..229269788023 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -217,7 +217,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
}
if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */
/* Hacks for Alice3 to work independent of haP16V driver */
- snd_printk(KERN_INFO "Audigy2 value: Special config.\n");
+ dev_info(emu->card->dev, "Audigy2 value: Special config.\n");
/* Setup SRCMulti_I2S SamplingRate */
tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
tmp &= 0xfffff1ff;
@@ -723,7 +723,8 @@ static int emu1010_firmware_thread(void *data)
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
/* Audio Dock attached */
/* Return to Audio Dock programming mode */
- snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
+ dev_info(emu->card->dev,
+ "emu1010: Loading Audio Dock Firmware\n");
snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK);
if (!emu->dock_fw) {
@@ -756,19 +757,25 @@ static int emu1010_firmware_thread(void *data)
snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg);
- snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", reg);
+ dev_info(emu->card->dev,
+ "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n",
+ reg);
/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
- snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", reg);
+ dev_info(emu->card->dev,
+ "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", reg);
if ((reg & 0x1f) != 0x15) {
/* FPGA failed to be programmed */
- snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", reg);
+ dev_info(emu->card->dev,
+ "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n",
+ reg);
continue;
}
- snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n");
+ dev_info(emu->card->dev,
+ "emu1010: Audio Dock Firmware loaded\n");
snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
- snd_printk(KERN_INFO "Audio Dock ver: %u.%u\n",
+ dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n",
tmp, tmp2);
/* Sync clocking between 1010 and Dock */
/* Allow DLL to settle */
@@ -777,7 +784,7 @@ static int emu1010_firmware_thread(void *data)
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
}
}
- snd_printk(KERN_INFO "emu1010: firmware thread stopping\n");
+ dev_info(emu->card->dev, "emu1010: firmware thread stopping\n");
return 0;
}
@@ -818,7 +825,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
u32 tmp, tmp2, reg;
int err;
- snd_printk(KERN_INFO "emu1010: Special config.\n");
+ dev_info(emu->card->dev, "emu1010: Special config.\n");
/* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
* Lock Sound Memory Cache, Lock Tank Memory Cache,
* Mute all codecs.
@@ -843,7 +850,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
/* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
- snd_printdd("reg1 = 0x%x\n", reg);
+ dev_dbg(emu->card->dev, "reg1 = 0x%x\n", reg);
if ((reg & 0x3f) == 0x15) {
/* FPGA netlist already present so clear it */
/* Return to programming mode */
@@ -851,13 +858,14 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02);
}
snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
- snd_printdd("reg2 = 0x%x\n", reg);
+ dev_dbg(emu->card->dev, "reg2 = 0x%x\n", reg);
if ((reg & 0x3f) == 0x15) {
/* FPGA failed to return to programming mode */
- snd_printk(KERN_INFO "emu1010: FPGA failed to return to programming mode\n");
+ dev_info(emu->card->dev,
+ "emu1010: FPGA failed to return to programming mode\n");
return -ENODEV;
}
- snd_printk(KERN_INFO "emu1010: EMU_HANA_ID = 0x%x\n", reg);
+ dev_info(emu->card->dev, "emu1010: EMU_HANA_ID = 0x%x\n", reg);
if (!emu->firmware) {
const char *filename;
@@ -880,16 +888,19 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
err = request_firmware(&emu->firmware, filename, &emu->pci->dev);
if (err != 0) {
- snd_printk(KERN_ERR "emu1010: firmware: %s not found. Err = %d\n", filename, err);
+ dev_info(emu->card->dev,
+ "emu1010: firmware: %s not found. Err = %d\n",
+ filename, err);
return err;
}
- snd_printk(KERN_INFO "emu1010: firmware file = %s, size = 0x%zx\n",
+ dev_info(emu->card->dev,
+ "emu1010: firmware file = %s, size = 0x%zx\n",
filename, emu->firmware->size);
}
err = snd_emu1010_load_firmware(emu, emu->firmware);
if (err != 0) {
- snd_printk(KERN_INFO "emu1010: Loading Firmware failed\n");
+ dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n");
return err;
}
@@ -897,21 +908,23 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
if ((reg & 0x3f) != 0x15) {
/* FPGA failed to be programmed */
- snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n", reg);
+ dev_info(emu->card->dev,
+ "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n",
+ reg);
return -ENODEV;
}
- snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n");
+ dev_info(emu->card->dev, "emu1010: Hana Firmware loaded\n");
snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp);
snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2);
- snd_printk(KERN_INFO "emu1010: Hana version: %u.%u\n", tmp, tmp2);
+ dev_info(emu->card->dev, "emu1010: Hana version: %u.%u\n", tmp, tmp2);
/* Enable 48Volt power to Audio Dock */
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON);
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
- snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg);
+ dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg);
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
- snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg);
+ dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg);
snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp);
/* Optical -> ADAT I/O */
/* 0 : SPDIF
@@ -950,7 +963,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00);
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
- snd_printk(KERN_INFO "emu1010: Card options3 = 0x%x\n", reg);
+ dev_info(emu->card->dev, "emu1010: Card options3 = 0x%x\n", reg);
/* Default WCLK set to 48kHz. */
snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00);
/* Word Clock source, Internal 48kHz x1 */
@@ -1808,7 +1821,9 @@ int snd_emu10k1_create(struct snd_card *card,
emu->revision = pci->revision;
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model);
- snd_printdd("vendor = 0x%x, device = 0x%x, subsystem_vendor_id = 0x%x, subsystem_id = 0x%x\n", pci->vendor, pci->device, emu->serial, emu->model);
+ dev_dbg(card->dev,
+ "vendor = 0x%x, device = 0x%x, subsystem_vendor_id = 0x%x, subsystem_id = 0x%x\n",
+ pci->vendor, pci->device, emu->serial, emu->model);
for (c = emu_chip_details; c->vendor; c++) {
if (c->vendor == pci->vendor && c->device == pci->device) {
@@ -1827,21 +1842,21 @@ int snd_emu10k1_create(struct snd_card *card,
}
}
if (c->vendor == 0) {
- snd_printk(KERN_ERR "emu10k1: Card not recognised\n");
+ dev_err(card->dev, "emu10k1: Card not recognised\n");
kfree(emu);
pci_disable_device(pci);
return -ENOENT;
}
emu->card_capabilities = c;
if (c->subsystem && !subsystem)
- snd_printdd("Sound card name = %s\n", c->name);
+ dev_dbg(card->dev, "Sound card name = %s\n", c->name);
else if (subsystem)
- snd_printdd("Sound card name = %s, "
+ dev_dbg(card->dev, "Sound card name = %s, "
"vendor = 0x%x, device = 0x%x, subsystem = 0x%x. "
"Forced to subsystem = 0x%x\n", c->name,
pci->vendor, pci->device, emu->serial, c->subsystem);
else
- snd_printdd("Sound card name = %s, "
+ dev_dbg(card->dev, "Sound card name = %s, "
"vendor = 0x%x, device = 0x%x, subsystem = 0x%x.\n",
c->name, pci->vendor, pci->device,
emu->serial);
@@ -1869,7 +1884,9 @@ int snd_emu10k1_create(struct snd_card *card,
emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK;
if (pci_set_dma_mask(pci, emu->dma_mask) < 0 ||
pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) {
- snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask);
+ dev_err(card->dev,
+ "architecture does not support PCI busmaster DMA with mask 0x%lx\n",
+ emu->dma_mask);
kfree(emu);
pci_disable_device(pci);
return -ENXIO;
@@ -2021,7 +2038,6 @@ int snd_emu10k1_create(struct snd_card *card,
snd_emu10k1_proc_init(emu);
#endif
- snd_card_set_dev(card, &pci->dev);
*remu = emu;
return 0;
diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index 662a45876a8b..0e069aeab86d 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -50,7 +50,8 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
return -EINVAL;
if (sp->v.size == 0) {
- snd_printd("emu: rom font for sample %d\n", sp->v.sample);
+ dev_dbg(emu->card->dev,
+ "emu: rom font for sample %d\n", sp->v.sample);
return 0;
}
@@ -92,7 +93,8 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
blocksize *= 2;
sp->block = snd_emu10k1_synth_alloc(emu, blocksize);
if (sp->block == NULL) {
- snd_printd("emu10k1: synth malloc failed (size=%d)\n", blocksize);
+ dev_dbg(emu->card->dev,
+ "synth malloc failed (size=%d)\n", blocksize);
/* not ENOMEM (for compatibility with OSS) */
return -ENOSPC;
}
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 56ad9d6f200d..efe017526977 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -369,7 +369,8 @@ static void snd_emu10k1x_pcm_interrupt(struct emu10k1x *emu, struct emu10k1x_voi
if (epcm->substream == NULL)
return;
#if 0
- snd_printk(KERN_INFO "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
+ dev_info(emu->card->dev,
+ "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
epcm->substream->ops->pointer(epcm->substream),
snd_pcm_lib_period_bytes(epcm->substream),
snd_pcm_lib_buffer_bytes(epcm->substream));
@@ -487,7 +488,11 @@ static int snd_emu10k1x_pcm_trigger(struct snd_pcm_substream *substream,
int channel = epcm->voice->number;
int result = 0;
-// snd_printk(KERN_INFO "trigger - emu10k1x = 0x%x, cmd = %i, pointer = %d\n", (int)emu, cmd, (int)substream->ops->pointer(substream));
+ /*
+ dev_dbg(emu->card->dev,
+ "trigger - emu10k1x = 0x%x, cmd = %i, pointer = %d\n",
+ (int)emu, cmd, (int)substream->ops->pointer(substream));
+ */
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -826,7 +831,7 @@ static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id)
// acknowledge the interrupt if necessary
outl(status, chip->port + IPR);
- // snd_printk(KERN_INFO "interrupt %08x\n", status);
+ /* dev_dbg(chip->card->dev, "interrupt %08x\n", status); */
return IRQ_HANDLED;
}
@@ -919,7 +924,7 @@ static int snd_emu10k1x_create(struct snd_card *card,
return err;
if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) {
- snd_printk(KERN_ERR "error to set 28bit mask DMA\n");
+ dev_err(card->dev, "error to set 28bit mask DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -940,14 +945,15 @@ static int snd_emu10k1x_create(struct snd_card *card,
chip->port = pci_resource_start(pci, 0);
if ((chip->res_port = request_region(chip->port, 8,
"EMU10K1X")) == NULL) {
- snd_printk(KERN_ERR "emu10k1x: cannot allocate the port 0x%lx\n", chip->port);
+ dev_err(card->dev, "cannot allocate the port 0x%lx\n",
+ chip->port);
snd_emu10k1x_free(chip);
return -EBUSY;
}
if (request_irq(pci->irq, snd_emu10k1x_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "emu10k1x: cannot grab irq %d\n", pci->irq);
+ dev_err(card->dev, "cannot grab irq %d\n", pci->irq);
snd_emu10k1x_free(chip);
return -EBUSY;
}
@@ -964,7 +970,7 @@ static int snd_emu10k1x_create(struct snd_card *card,
chip->revision = pci->revision;
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
- snd_printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model,
+ dev_info(card->dev, "Model %04x Rev %08x Serial %08x\n", chip->model,
chip->revision, chip->serial);
outl(0, chip->port + INTE);
@@ -1248,7 +1254,9 @@ static void mpu401_clear_rx(struct emu10k1x *emu, struct emu10k1x_midi *mpu)
mpu401_read_data(emu, mpu);
#ifdef CONFIG_SND_DEBUG
if (timeout <= 0)
- snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu));
+ dev_err(emu->card->dev,
+ "cmd: clear rx timeout (status = 0x%x)\n",
+ mpu401_read_stat(emu, mpu));
#endif
}
@@ -1322,7 +1330,8 @@ static int snd_emu10k1x_midi_cmd(struct emu10k1x * emu,
}
spin_unlock_irqrestore(&midi->input_lock, flags);
if (!ok) {
- snd_printk(KERN_ERR "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
+ dev_err(emu->card->dev,
+ "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
cmd, emu->port,
mpu401_read_stat(emu, midi),
mpu401_read_data(emu, midi));
@@ -1564,7 +1573,8 @@ static int snd_emu10k1x_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -1608,8 +1618,6 @@ static int snd_emu10k1x_probe(struct pci_dev *pci,
sprintf(card->longname, "%s at 0x%lx irq %i",
card->shortname, chip->port, chip->irq);
- snd_card_set_dev(card, &pci->dev);
-
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
return err;
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 1f9c7c4bbcd8..745f0627c634 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -1547,7 +1547,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
/* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
if (emu->card_capabilities->emu_model) {
/* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
- snd_printk(KERN_INFO "EMU outputs on\n");
+ dev_info(emu->card->dev, "EMU outputs on\n");
for (z = 0; z < 8; z++) {
if (emu->card_capabilities->ca0108_chip) {
A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
@@ -1571,7 +1571,9 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
if ((z==1) && (emu->card_capabilities->spdif_bug)) {
/* Due to a SPDIF output bug on some Audigy cards, this code delays the Right channel by 1 sample */
- snd_printk(KERN_INFO "Installing spdif_bug patch: %s\n", emu->card_capabilities->name);
+ dev_info(emu->card->dev,
+ "Installing spdif_bug patch: %s\n",
+ emu->card_capabilities->name);
A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
} else {
@@ -1595,7 +1597,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
if (emu->card_capabilities->emu_model) {
if (emu->card_capabilities->ca0108_chip) {
- snd_printk(KERN_INFO "EMU2 inputs on\n");
+ dev_info(emu->card->dev, "EMU2 inputs on\n");
for (z = 0; z < 0x10; z++) {
snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp,
bit_shifter16,
@@ -1603,11 +1605,11 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
A_FXBUS2(z*2) );
}
} else {
- snd_printk(KERN_INFO "EMU inputs on\n");
+ dev_info(emu->card->dev, "EMU inputs on\n");
/* Capture 16 (originally 8) channels of S32_LE sound */
/*
- printk(KERN_DEBUG "emufx.c: gpr=0x%x, tmp=0x%x\n",
+ dev_dbg(emu->card->dev, "emufx.c: gpr=0x%x, tmp=0x%x\n",
gpr, tmp);
*/
/* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index f6c3da0d377d..c5ae2a24d8a5 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -1853,8 +1853,10 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) {
if (emu->card_capabilities->ac97_chip == 1)
return err;
- snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n");
- snd_printd(KERN_INFO" Proceeding without ac97 mixers...\n");
+ dev_info(emu->card->dev,
+ "AC97 is optional on this board\n");
+ dev_info(emu->card->dev,
+ "Proceeding without ac97 mixers...\n");
snd_device_free(emu->card, pbus);
goto no_ac97; /* FIXME: get rid of ugly gotos.. */
}
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c
index 1ec91246dfee..fdf2b0ada489 100644
--- a/sound/pci/emu10k1/emumpu401.c
+++ b/sound/pci/emu10k1/emumpu401.c
@@ -64,7 +64,9 @@ static void mpu401_clear_rx(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *mp
mpu401_read_data(emu, mpu);
#ifdef CONFIG_SND_DEBUG
if (timeout <= 0)
- snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu));
+ dev_err(emu->card->dev,
+ "cmd: clear rx timeout (status = 0x%x)\n",
+ mpu401_read_stat(emu, mpu));
#endif
}
@@ -141,7 +143,8 @@ static int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_mid
}
spin_unlock_irqrestore(&midi->input_lock, flags);
if (!ok) {
- snd_printk(KERN_ERR "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
+ dev_err(emu->card->dev,
+ "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
cmd, emu->port,
mpu401_read_stat(emu, midi),
mpu401_read_data(emu, midi));
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index 5ae1d045bdcb..f82481bd2542 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -44,7 +44,8 @@ static void snd_emu10k1_pcm_interrupt(struct snd_emu10k1 *emu,
if (epcm->substream == NULL)
return;
#if 0
- printk(KERN_DEBUG "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
+ dev_dbg(emu->card->dev,
+ "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
epcm->substream->runtime->hw->pointer(emu, epcm->substream),
snd_pcm_lib_period_bytes(epcm->substream),
snd_pcm_lib_buffer_bytes(epcm->substream));
@@ -147,7 +148,7 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voic
&epcm->extra);
if (err < 0) {
/*
- printk(KERN_DEBUG "pcm_channel_alloc: "
+ dev_dbg(emu->card->dev, "pcm_channel_alloc: "
"failed extra: voices=%d, frame=%d\n",
voices, frame);
*/
@@ -761,7 +762,8 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
int result = 0;
/*
- printk(KERN_DEBUG "trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n",
+ dev_dbg(emu->card->dev,
+ "trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n",
(int)emu, cmd, substream->ops->pointer(substream))
*/
spin_lock(&emu->reg_lock);
@@ -815,7 +817,7 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
outl(epcm->capture_ipr, emu->port + IPR);
snd_emu10k1_intr_enable(emu, epcm->capture_inte);
/*
- printk(KERN_DEBUG "adccr = 0x%x, adcbs = 0x%x\n",
+ dev_dbg(emu->card->dev, "adccr = 0x%x, adcbs = 0x%x\n",
epcm->adccr, epcm->adcbs);
*/
switch (epcm->type) {
@@ -826,7 +828,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream,
if (emu->audigy) {
snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val);
snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2);
- snd_printdd("cr_val=0x%x, cr_val2=0x%x\n", epcm->capture_cr_val, epcm->capture_cr_val2);
+ dev_dbg(emu->card->dev,
+ "cr_val=0x%x, cr_val2=0x%x\n",
+ epcm->capture_cr_val,
+ epcm->capture_cr_val2);
} else
snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val);
break;
@@ -889,7 +894,7 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *
}
#endif
/*
- printk(KERN_DEBUG
+ dev_dbg(emu->card->dev,
"ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n",
(long)ptr, (long)runtime->buffer_size,
(long)runtime->period_size);
@@ -1594,7 +1599,8 @@ static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left,
unsigned int tram_shift)
{
/*
- printk(KERN_DEBUG "tram_poke1: dst_left = 0x%p, dst_right = 0x%p, "
+ dev_dbg(emu->card->dev,
+ "tram_poke1: dst_left = 0x%p, dst_right = 0x%p, "
"src = 0x%p, count = 0x%x\n",
dst_left, dst_right, src, count);
*/
@@ -1675,7 +1681,7 @@ static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substre
unsigned int i;
/*
- printk(KERN_DEBUG "prepare: etram_pages = 0x%p, dma_area = 0x%x, "
+ dev_dbg(emu->card->dev, "prepare: etram_pages = 0x%p, dma_area = 0x%x, "
"buffer_size = 0x%x (0x%x)\n",
emu->fx8010.etram_pages, runtime->dma_area,
runtime->buffer_size, runtime->buffer_size << 2);
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index e4fba49fee4a..706b4f0c6806 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -71,11 +71,8 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
unsigned long flags;
unsigned int mask;
- if (!emu) {
- snd_printk(KERN_ERR "ptr_write: emu is null!\n");
- dump_stack();
+ if (snd_BUG_ON(!emu))
return;
- }
mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
@@ -199,7 +196,7 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
int err = 0;
if ((reg > 0x7f) || (value > 0x1ff)) {
- snd_printk(KERN_ERR "i2c_write: invalid values.\n");
+ dev_err(emu->card->dev, "i2c_write: invalid values.\n");
return -EINVAL;
}
@@ -227,7 +224,7 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
break;
if (timeout > 1000) {
- snd_printk(KERN_WARNING
+ dev_warn(emu->card->dev,
"emu10k1:I2C:timeout status=0x%x\n",
status);
break;
@@ -239,8 +236,8 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
}
if (retry == 10) {
- snd_printk(KERN_ERR "Writing to ADC failed!\n");
- snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n",
+ dev_err(emu->card->dev, "Writing to ADC failed!\n");
+ dev_err(emu->card->dev, "status=0x%x, reg=%d, value=%d\n",
status, reg, value);
/* dump_stack(); */
err = -EINVAL;
diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c
index 30bfed6f8339..3c5c5e3dc2d9 100644
--- a/sound/pci/emu10k1/irq.c
+++ b/sound/pci/emu10k1/irq.c
@@ -41,11 +41,12 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
orig_status = status;
handled = 1;
if ((status & 0xffffffff) == 0xffffffff) {
- snd_printk(KERN_INFO "snd-emu10k1: Suspected sound card removal\n");
+ dev_info(emu->card->dev,
+ "Suspected sound card removal\n");
break;
}
if (status & IPR_PCIERROR) {
- snd_printk(KERN_ERR "interrupt: PCI error\n");
+ dev_err(emu->card->dev, "interrupt: PCI error\n");
snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE);
status &= ~IPR_PCIERROR;
}
@@ -157,19 +158,22 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
struct snd_emu10k1_voice *pvoice = &(emu->p16v_voices[0]);
struct snd_emu10k1_voice *cvoice = &(emu->p16v_capture_voice);
- //printk(KERN_INFO "status2=0x%x\n", status2);
+ /* dev_dbg(emu->card->dev, "status2=0x%x\n", status2); */
orig_status2 = status2;
if(status2 & mask) {
if(pvoice->use) {
snd_pcm_period_elapsed(pvoice->epcm->substream);
} else {
- snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use);
+ dev_err(emu->card->dev,
+ "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n",
+ status2, mask, pvoice,
+ pvoice->use);
}
}
if(status2 & 0x110000) {
- //printk(KERN_INFO "capture int found\n");
+ /* dev_info(emu->card->dev, "capture int found\n"); */
if(cvoice->use) {
- //printk(KERN_INFO "capture period_elapsed\n");
+ /* dev_info(emu->card->dev, "capture period_elapsed\n"); */
snd_pcm_period_elapsed(cvoice->epcm->substream);
}
}
@@ -180,7 +184,8 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
if (status) {
unsigned int bits;
- snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status);
+ dev_err(emu->card->dev,
+ "unhandled interrupt: 0x%08x\n", status);
//make sure any interrupts we don't handle are disabled:
bits = INTE_FXDSPENABLE |
INTE_PCIERRORENABLE |
@@ -202,7 +207,7 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
outl(orig_status, emu->port + IPR); /* ack all */
}
if (timeout == 1000)
- snd_printk(KERN_INFO "emu10k1 irq routine failure\n");
+ dev_info(emu->card->dev, "emu10k1 irq routine failure\n");
return IRQ_RETVAL(handled);
}
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index ae709c1ab3a8..c68e6dd2fa67 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -236,11 +236,13 @@ __found_pages:
static int is_valid_page(struct snd_emu10k1 *emu, dma_addr_t addr)
{
if (addr & ~emu->dma_mask) {
- snd_printk(KERN_ERR "max memory size is 0x%lx (addr = 0x%lx)!!\n", emu->dma_mask, (unsigned long)addr);
+ dev_err(emu->card->dev,
+ "max memory size is 0x%lx (addr = 0x%lx)!!\n",
+ emu->dma_mask, (unsigned long)addr);
return 0;
}
if (addr & (EMUPAGESIZE-1)) {
- snd_printk(KERN_ERR "page is not aligned\n");
+ dev_err(emu->card->dev, "page is not aligned\n");
return 0;
}
return 1;
@@ -331,7 +333,8 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst
else
addr = snd_pcm_sgbuf_get_addr(substream, ofs);
if (! is_valid_page(emu, addr)) {
- printk(KERN_ERR "emu: failure page = %d\n", idx);
+ dev_err(emu->card->dev,
+ "emu: failure page = %d\n", idx);
mutex_unlock(&hdr->block_mutex);
return NULL;
}
@@ -507,7 +510,8 @@ static inline void *offset_ptr(struct snd_emu10k1 *emu, int page, int offset)
return NULL;
ptr = emu->page_ptr_table[page];
if (! ptr) {
- printk(KERN_ERR "emu10k1: access to NULL ptr: page = %d\n", page);
+ dev_err(emu->card->dev,
+ "access to NULL ptr: page = %d\n", page);
return NULL;
}
ptr += offset & (PAGE_SIZE - 1);
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index 7e2025cd6d9c..a4fe7f0c9458 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -168,7 +168,7 @@ static void snd_p16v_pcm_free_substream(struct snd_pcm_runtime *runtime)
struct snd_emu10k1_pcm *epcm = runtime->private_data;
if (epcm) {
- /* snd_printk(KERN_DEBUG "epcm free: %p\n", epcm); */
+ /* dev_dbg(emu->card->dev, "epcm free: %p\n", epcm); */
kfree(epcm);
}
}
@@ -183,14 +183,14 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea
int err;
epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
- /* snd_printk(KERN_DEBUG "epcm kcalloc: %p\n", epcm); */
+ /* dev_dbg(emu->card->dev, "epcm kcalloc: %p\n", epcm); */
if (epcm == NULL)
return -ENOMEM;
epcm->emu = emu;
epcm->substream = substream;
/*
- snd_printk(KERN_DEBUG "epcm device=%d, channel_id=%d\n",
+ dev_dbg(emu->card->dev, "epcm device=%d, channel_id=%d\n",
substream->pcm->device, channel_id);
*/
runtime->private_data = epcm;
@@ -203,10 +203,10 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea
channel->use=1;
#if 0 /* debug */
- snd_printk(KERN_DEBUG
+ dev_dbg(emu->card->dev,
"p16v: open channel_id=%d, channel=%p, use=0x%x\n",
channel_id, channel, channel->use);
- printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+ dev_dbg(emu->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n",
channel_id, chip, channel);
#endif /* debug */
/* channel->interrupt = snd_p16v_pcm_channel_interrupt; */
@@ -231,14 +231,14 @@ static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream
int err;
epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
- /* snd_printk(KERN_DEBUG "epcm kcalloc: %p\n", epcm); */
+ /* dev_dbg(emu->card->dev, "epcm kcalloc: %p\n", epcm); */
if (epcm == NULL)
return -ENOMEM;
epcm->emu = emu;
epcm->substream = substream;
/*
- snd_printk(KERN_DEBUG "epcm device=%d, channel_id=%d\n",
+ dev_dbg(emu->card->dev, "epcm device=%d, channel_id=%d\n",
substream->pcm->device, channel_id);
*/
runtime->private_data = epcm;
@@ -251,10 +251,10 @@ static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream
channel->use=1;
#if 0 /* debug */
- snd_printk(KERN_DEBUG
+ dev_dbg(emu->card->dev,
"p16v: open channel_id=%d, channel=%p, use=0x%x\n",
channel_id, channel, channel->use);
- printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+ dev_dbg(emu->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n",
channel_id, chip, channel);
#endif /* debug */
/* channel->interrupt = snd_p16v_pcm_channel_interrupt; */
@@ -349,15 +349,18 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream)
u32 tmp;
#if 0 /* debug */
- snd_printk(KERN_DEBUG "prepare:channel_number=%d, rate=%d, "
+ dev_dbg(emu->card->dev,
+ "prepare:channel_number=%d, rate=%d, "
"format=0x%x, channels=%d, buffer_size=%ld, "
"period_size=%ld, periods=%u, frames_to_bytes=%d\n",
channel, runtime->rate, runtime->format, runtime->channels,
runtime->buffer_size, runtime->period_size,
runtime->periods, frames_to_bytes(runtime, 1));
- snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n",
+ dev_dbg(emu->card->dev,
+ "dma_addr=%x, dma_area=%p, table_base=%p\n",
runtime->dma_addr, runtime->dma_area, table_base);
- snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
+ dev_dbg(emu->card->dev,
+ "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
emu->p16v_buffer.addr, emu->p16v_buffer.area,
emu->p16v_buffer.bytes);
#endif /* debug */
@@ -405,7 +408,7 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream)
u32 tmp;
/*
- printk(KERN_DEBUG "prepare capture:channel_number=%d, rate=%d, "
+ dev_dbg(emu->card->dev, "prepare capture:channel_number=%d, rate=%d, "
"format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, "
"frames_to_bytes=%d\n",
channel, runtime->rate, runtime->format, runtime->channels,
@@ -491,13 +494,13 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream,
runtime = s->runtime;
epcm = runtime->private_data;
channel = substream->pcm->device-emu->p16v_device_offset;
- /* snd_printk(KERN_DEBUG "p16v channel=%d\n", channel); */
+ /* dev_dbg(emu->card->dev, "p16v channel=%d\n", channel); */
epcm->running = running;
basic |= (0x1<<channel);
inte |= (INTE2_PLAYBACK_CH_0_LOOP<<channel);
snd_pcm_trigger_done(s, substream);
}
- /* snd_printk(KERN_DEBUG "basic=0x%x, inte=0x%x\n", basic, inte); */
+ /* dev_dbg(emu->card->dev, "basic=0x%x, inte=0x%x\n", basic, inte); */
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -588,10 +591,10 @@ snd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream)
ptr=ptr2;
if (ptr >= runtime->buffer_size) {
ptr -= runtime->buffer_size;
- printk(KERN_WARNING "buffer capture limited!\n");
+ dev_warn(emu->card->dev, "buffer capture limited!\n");
}
/*
- printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
+ dev_dbg(emu->card->dev, "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
"buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
ptr1, ptr2, ptr, (int)runtime->buffer_size,
(int)runtime->period_size, (int)runtime->frame_bits,
@@ -630,7 +633,7 @@ int snd_p16v_free(struct snd_emu10k1 *chip)
if (chip->p16v_buffer.area) {
snd_dma_free_pages(&chip->p16v_buffer);
/*
- snd_printk(KERN_DEBUG "period lables free: %p\n",
+ dev_dbg(chip->card->dev, "period lables free: %p\n",
&chip->p16v_buffer);
*/
}
@@ -644,7 +647,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
int err;
int capture=1;
- /* snd_printk(KERN_DEBUG "snd_p16v_pcm called. device=%d\n", device); */
+ /* dev_dbg(emu->card->dev, "snd_p16v_pcm called. device=%d\n", device); */
emu->p16v_device_offset = device;
if (rpcm)
*rpcm = NULL;
@@ -672,7 +675,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
((65536 - 64) * 8), ((65536 - 64) * 8))) < 0)
return err;
/*
- snd_printk(KERN_DEBUG
+ dev_dbg(emu->card->dev,
"preallocate playback substream: err=%d\n", err);
*/
}
@@ -686,7 +689,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
65536 - 64, 65536 - 64)) < 0)
return err;
/*
- snd_printk(KERN_DEBUG
+ dev_dbg(emu->card->dev,
"preallocate capture substream: err=%d\n", err);
*/
}
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c
index 101e7cb79cb2..f16fd5cfb7cd 100644
--- a/sound/pci/emu10k1/voice.c
+++ b/sound/pci/emu10k1/voice.c
@@ -55,7 +55,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
first_voice = last_voice = 0;
for (i = emu->next_free_voice, j = 0; j < NUM_G ; i += number, j += number) {
/*
- printk(KERN_DEBUG "i %d j %d next free %d!\n",
+ dev_dbg(emu->card->dev, "i %d j %d next free %d!\n",
i, j, emu->next_free_voice);
*/
i %= NUM_G;
@@ -75,7 +75,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
}
}
if (!skip) {
- /* printk(KERN_DEBUG "allocated voice %d\n", i); */
+ /* dev_dbg(emu->card->dev, "allocated voice %d\n", i); */
first_voice = i;
last_voice = (i + number) % NUM_G;
emu->next_free_voice = last_voice;
@@ -89,7 +89,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number,
for (i = 0; i < number; i++) {
voice = &emu->voices[(first_voice + i) % NUM_G];
/*
- printk(kERN_DEBUG "voice alloc - %i, %i of %i\n",
+ dev_dbg(emu->card->dev, "voice alloc - %i, %i of %i\n",
voice->number, idx-first_voice+1, number);
*/
voice->use = 1;
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 61262f396004..29cd339ffc37 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -525,7 +525,7 @@ static unsigned int snd_es1371_wait_src_ready(struct ensoniq * ensoniq)
return r;
cond_resched();
}
- snd_printk(KERN_ERR "wait src ready timeout 0x%lx [0x%x]\n",
+ dev_err(ensoniq->card->dev, "wait src ready timeout 0x%lx [0x%x]\n",
ES_REG(ensoniq, 1371_SMPRATE), r);
return 0;
}
@@ -587,7 +587,7 @@ static void snd_es1370_codec_write(struct snd_ak4531 *ak4531,
unsigned long end_time = jiffies + HZ / 10;
#if 0
- printk(KERN_DEBUG
+ dev_dbg(ensoniq->card->dev,
"CODEC WRITE: reg = 0x%x, val = 0x%x (0x%x), creg = 0x%x\n",
reg, val, ES_1370_CODEC_WRITE(reg, val), ES_REG(ensoniq, 1370_CODEC));
#endif
@@ -598,7 +598,7 @@ static void snd_es1370_codec_write(struct snd_ak4531 *ak4531,
}
schedule_timeout_uninterruptible(1);
} while (time_after(end_time, jiffies));
- snd_printk(KERN_ERR "codec write timeout, status = 0x%x\n",
+ dev_err(ensoniq->card->dev, "codec write timeout, status = 0x%x\n",
inl(ES_REG(ensoniq, STATUS)));
}
@@ -649,7 +649,7 @@ static void snd_es1371_codec_write(struct snd_ac97 *ac97,
}
}
mutex_unlock(&ensoniq->src_mutex);
- snd_printk(KERN_ERR "codec write timeout at 0x%lx [0x%x]\n",
+ dev_err(ensoniq->card->dev, "codec write timeout at 0x%lx [0x%x]\n",
ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC)));
}
@@ -706,8 +706,8 @@ static unsigned short snd_es1371_codec_read(struct snd_ac97 *ac97,
}
mutex_unlock(&ensoniq->src_mutex);
if (++fail > 10) {
- snd_printk(KERN_ERR "codec read timeout (final) "
- "at 0x%lx, reg = 0x%x [0x%x]\n",
+ dev_err(ensoniq->card->dev,
+ "codec read timeout (final) at 0x%lx, reg = 0x%x [0x%x]\n",
ES_REG(ensoniq, 1371_CODEC), reg,
inl(ES_REG(ensoniq, 1371_CODEC)));
return 0;
@@ -716,7 +716,7 @@ static unsigned short snd_es1371_codec_read(struct snd_ac97 *ac97,
}
}
mutex_unlock(&ensoniq->src_mutex);
- snd_printk(KERN_ERR "es1371: codec read timeout at 0x%lx [0x%x]\n",
+ dev_err(ensoniq->card->dev, "codec read timeout at 0x%lx [0x%x]\n",
ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC)));
return 0;
}
@@ -1796,7 +1796,7 @@ static int snd_ensoniq_1370_mixer(struct ensoniq *ensoniq)
#ifdef SUPPORT_JOYSTICK
#ifdef CHIP1371
-static int snd_ensoniq_get_joystick_port(int dev)
+static int snd_ensoniq_get_joystick_port(struct ensoniq *ensoniq, int dev)
{
switch (joystick_port[dev]) {
case 0: /* disabled */
@@ -1808,12 +1808,13 @@ static int snd_ensoniq_get_joystick_port(int dev)
return joystick_port[dev];
default:
- printk(KERN_ERR "ens1371: invalid joystick port %#x", joystick_port[dev]);
+ dev_err(ensoniq->card->dev,
+ "invalid joystick port %#x", joystick_port[dev]);
return 0;
}
}
#else
-static inline int snd_ensoniq_get_joystick_port(int dev)
+static int snd_ensoniq_get_joystick_port(struct ensoniq *ensoniq, int dev)
{
return joystick[dev] ? 0x200 : 0;
}
@@ -1824,7 +1825,7 @@ static int snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int dev)
struct gameport *gp;
int io_port;
- io_port = snd_ensoniq_get_joystick_port(dev);
+ io_port = snd_ensoniq_get_joystick_port(ensoniq, dev);
switch (io_port) {
case 0:
@@ -1835,14 +1836,16 @@ static int snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int dev)
if (request_region(io_port, 8, "ens137x: gameport"))
break;
if (io_port > 0x218) {
- printk(KERN_WARNING "ens137x: no gameport ports available\n");
+ dev_warn(ensoniq->card->dev,
+ "no gameport ports available\n");
return -EBUSY;
}
break;
default:
if (!request_region(io_port, 8, "ens137x: gameport")) {
- printk(KERN_WARNING "ens137x: gameport io port %#x in use\n",
+ dev_warn(ensoniq->card->dev,
+ "gameport io port %#x in use\n",
io_port);
return -EBUSY;
}
@@ -1851,7 +1854,8 @@ static int snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int dev)
ensoniq->gameport = gp = gameport_allocate_port();
if (!gp) {
- printk(KERN_ERR "ens137x: cannot allocate memory for gameport\n");
+ dev_err(ensoniq->card->dev,
+ "cannot allocate memory for gameport\n");
release_region(io_port, 8);
return -ENOMEM;
}
@@ -2082,8 +2086,7 @@ static int snd_ensoniq_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR DRIVER_NAME ": pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -2137,7 +2140,7 @@ static int snd_ensoniq_create(struct snd_card *card,
ensoniq->port = pci_resource_start(pci, 0);
if (request_irq(pci->irq, snd_audiopci_interrupt, IRQF_SHARED,
KBUILD_MODNAME, ensoniq)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_ensoniq_free(ensoniq);
return -EBUSY;
}
@@ -2145,7 +2148,7 @@ static int snd_ensoniq_create(struct snd_card *card,
#ifdef CHIP1370
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
16, &ensoniq->dma_bug) < 0) {
- snd_printk(KERN_ERR "unable to allocate space for phantom area - dma_bug\n");
+ dev_err(card->dev, "unable to allocate space for phantom area - dma_bug\n");
snd_ensoniq_free(ensoniq);
return -EBUSY;
}
@@ -2180,8 +2183,6 @@ static int snd_ensoniq_create(struct snd_card *card,
snd_ensoniq_proc_init(ensoniq);
- snd_card_set_dev(card, &pci->dev);
-
*rensoniq = ensoniq;
return 0;
}
@@ -2437,7 +2438,8 @@ static int snd_audiopci_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 9213fb38921c..34d95bf916b5 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -254,7 +254,6 @@ MODULE_DEVICE_TABLE(pci, snd_es1938_ids);
#define WRITE_LOOP_TIMEOUT 0x10000
#define GET_LOOP_TIMEOUT 0x01000
-#undef REG_DEBUG
/* -----------------------------------------------------------------
* Write to a mixer register
* -----------------------------------------------------------------*/
@@ -265,9 +264,7 @@ static void snd_es1938_mixer_write(struct es1938 *chip, unsigned char reg, unsig
outb(reg, SLSB_REG(chip, MIXERADDR));
outb(val, SLSB_REG(chip, MIXERDATA));
spin_unlock_irqrestore(&chip->mixer_lock, flags);
-#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Mixer reg %02x set to %02x\n", reg, val);
-#endif
+ dev_dbg(chip->card->dev, "Mixer reg %02x set to %02x\n", reg, val);
}
/* -----------------------------------------------------------------
@@ -281,9 +278,7 @@ static int snd_es1938_mixer_read(struct es1938 *chip, unsigned char reg)
outb(reg, SLSB_REG(chip, MIXERADDR));
data = inb(SLSB_REG(chip, MIXERDATA));
spin_unlock_irqrestore(&chip->mixer_lock, flags);
-#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Mixer reg %02x now is %02x\n", reg, data);
-#endif
+ dev_dbg(chip->card->dev, "Mixer reg %02x now is %02x\n", reg, data);
return data;
}
@@ -302,10 +297,9 @@ static int snd_es1938_mixer_bits(struct es1938 *chip, unsigned char reg,
if (val != oval) {
new = (old & ~mask) | (val & mask);
outb(new, SLSB_REG(chip, MIXERDATA));
-#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Mixer reg %02x was %02x, set to %02x\n",
+ dev_dbg(chip->card->dev,
+ "Mixer reg %02x was %02x, set to %02x\n",
reg, old, new);
-#endif
}
spin_unlock_irqrestore(&chip->mixer_lock, flags);
return oval;
@@ -324,7 +318,8 @@ static void snd_es1938_write_cmd(struct es1938 *chip, unsigned char cmd)
return;
}
}
- printk(KERN_ERR "snd_es1938_write_cmd timeout (0x02%x/0x02%x)\n", cmd, v);
+ dev_err(chip->card->dev,
+ "snd_es1938_write_cmd timeout (0x02%x/0x02%x)\n", cmd, v);
}
/* -----------------------------------------------------------------
@@ -337,7 +332,7 @@ static int snd_es1938_get_byte(struct es1938 *chip)
for (i = GET_LOOP_TIMEOUT; i; i--)
if ((v = inb(SLSB_REG(chip, STATUS))) & 0x80)
return inb(SLSB_REG(chip, READDATA));
- snd_printk(KERN_ERR "get_byte timeout: status 0x02%x\n", v);
+ dev_err(chip->card->dev, "get_byte timeout: status 0x02%x\n", v);
return -ENODEV;
}
@@ -351,9 +346,7 @@ static void snd_es1938_write(struct es1938 *chip, unsigned char reg, unsigned ch
snd_es1938_write_cmd(chip, reg);
snd_es1938_write_cmd(chip, val);
spin_unlock_irqrestore(&chip->reg_lock, flags);
-#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Reg %02x set to %02x\n", reg, val);
-#endif
+ dev_dbg(chip->card->dev, "Reg %02x set to %02x\n", reg, val);
}
/* -----------------------------------------------------------------
@@ -368,9 +361,7 @@ static unsigned char snd_es1938_read(struct es1938 *chip, unsigned char reg)
snd_es1938_write_cmd(chip, reg);
val = snd_es1938_get_byte(chip);
spin_unlock_irqrestore(&chip->reg_lock, flags);
-#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Reg %02x now is %02x\n", reg, val);
-#endif
+ dev_dbg(chip->card->dev, "Reg %02x now is %02x\n", reg, val);
return val;
}
@@ -391,10 +382,8 @@ static int snd_es1938_bits(struct es1938 *chip, unsigned char reg, unsigned char
snd_es1938_write_cmd(chip, reg);
new = (old & ~mask) | (val & mask);
snd_es1938_write_cmd(chip, new);
-#ifdef REG_DEBUG
- snd_printk(KERN_DEBUG "Reg %02x was %02x, set to %02x\n",
+ dev_dbg(chip->card->dev, "Reg %02x was %02x, set to %02x\n",
reg, old, new);
-#endif
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
return oval;
@@ -416,7 +405,7 @@ static void snd_es1938_reset(struct es1938 *chip)
goto __next;
}
}
- snd_printk(KERN_ERR "ESS Solo-1 reset failed\n");
+ dev_err(chip->card->dev, "ESS Solo-1 reset failed\n");
__next:
snd_es1938_write_cmd(chip, ESS_CMD_ENABLEEXT);
@@ -1504,16 +1493,15 @@ static int es1938_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "es1938: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
if (request_irq(pci->irq, snd_es1938_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
- printk(KERN_ERR "es1938: unable to grab IRQ %d, "
- "disabling device\n", pci->irq);
+ dev_err(dev, "unable to grab IRQ %d, disabling device\n",
+ pci->irq);
snd_card_disconnect(card);
return -EIO;
}
@@ -1545,7 +1533,8 @@ static int snd_es1938_create_gameport(struct es1938 *chip)
chip->gameport = gp = gameport_allocate_port();
if (!gp) {
- printk(KERN_ERR "es1938: cannot allocate memory for gameport\n");
+ dev_err(chip->card->dev,
+ "cannot allocate memory for gameport\n");
return -ENOMEM;
}
@@ -1612,7 +1601,8 @@ static int snd_es1938_create(struct snd_card *card,
/* check, if we can restrict PCI DMA transfers to 24 bits */
if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) {
- snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n");
+ dev_err(card->dev,
+ "architecture does not support 24bit PCI busmaster DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -1639,15 +1629,14 @@ static int snd_es1938_create(struct snd_card *card,
chip->game_port = pci_resource_start(pci, 4);
if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_es1938_free(chip);
return -EBUSY;
}
chip->irq = pci->irq;
-#ifdef ES1938_DDEBUG
- snd_printk(KERN_DEBUG "create: io: 0x%lx, sb: 0x%lx, vc: 0x%lx, mpu: 0x%lx, game: 0x%lx\n",
+ dev_dbg(card->dev,
+ "create: io: 0x%lx, sb: 0x%lx, vc: 0x%lx, mpu: 0x%lx, game: 0x%lx\n",
chip->io_port, chip->sb_port, chip->vc_port, chip->mpu_port, chip->game_port);
-#endif
chip->ddma_port = chip->vc_port + 0x00; /* fix from Thomas Sailer */
@@ -1658,8 +1647,6 @@ static int snd_es1938_create(struct snd_card *card,
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
return 0;
}
@@ -1675,21 +1662,22 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id)
status = inb(SLIO_REG(chip, IRQCONTROL));
#if 0
- printk(KERN_DEBUG "Es1938debug - interrupt status: =0x%x\n", status);
+ dev_dbg(chip->card->dev,
+ "Es1938debug - interrupt status: =0x%x\n", status);
#endif
/* AUDIO 1 */
if (status & 0x10) {
#if 0
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
"Es1938debug - AUDIO channel 1 interrupt\n");
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
"Es1938debug - AUDIO channel 1 DMAC DMA count: %u\n",
inw(SLDM_REG(chip, DMACOUNT)));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
"Es1938debug - AUDIO channel 1 DMAC DMA base: %u\n",
inl(SLDM_REG(chip, DMAADDR)));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
"Es1938debug - AUDIO channel 1 DMAC DMA status: 0x%x\n",
inl(SLDM_REG(chip, DMASTATUS)));
#endif
@@ -1705,12 +1693,12 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id)
/* AUDIO 2 */
if (status & 0x20) {
#if 0
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
"Es1938debug - AUDIO channel 2 interrupt\n");
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
"Es1938debug - AUDIO channel 2 DMAC DMA count: %u\n",
inw(SLIO_REG(chip, AUDIO2DMACOUNT)));
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
"Es1938debug - AUDIO channel 2 DMAC DMA base: %u\n",
inl(SLIO_REG(chip, AUDIO2DMAADDR)));
@@ -1808,7 +1796,8 @@ static int snd_es1938_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
for (idx = 0; idx < 5; idx++) {
@@ -1843,7 +1832,7 @@ static int snd_es1938_probe(struct pci_dev *pci,
SLSB_REG(chip, FMLOWADDR),
SLSB_REG(chip, FMHIGHADDR),
OPL3_HW_OPL3, 1, &opl3) < 0) {
- printk(KERN_ERR "es1938: OPL3 not detected at 0x%lx\n",
+ dev_err(card->dev, "OPL3 not detected at 0x%lx\n",
SLSB_REG(chip, FMLOWADDR));
} else {
if ((err = snd_opl3_timer_new(opl3, 0, 1)) < 0) {
@@ -1859,7 +1848,7 @@ static int snd_es1938_probe(struct pci_dev *pci,
chip->mpu_port,
MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
-1, &chip->rmidi) < 0) {
- printk(KERN_ERR "es1938: unable to initialize MPU-401\n");
+ dev_err(card->dev, "unable to initialize MPU-401\n");
} else {
// this line is vital for MIDI interrupt handling on ess-solo1
// andreas@flying-snail.de
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 772cc36f951d..5bb1cf603301 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -632,7 +632,7 @@ static int snd_es1968_ac97_wait(struct es1968 *chip)
return 0;
cond_resched();
}
- snd_printd("es1968: ac97 timeout\n");
+ dev_dbg(chip->card->dev, "ac97 timeout\n");
return 1; /* timeout */
}
@@ -644,7 +644,7 @@ static int snd_es1968_ac97_wait_poll(struct es1968 *chip)
if (!(inb(chip->io_port + ESM_AC97_INDEX) & 1))
return 0;
}
- snd_printd("es1968: ac97 timeout\n");
+ dev_dbg(chip->card->dev, "ac97 timeout\n");
return 1; /* timeout */
}
@@ -687,7 +687,7 @@ static void apu_index_set(struct es1968 *chip, u16 index)
for (i = 0; i < 1000; i++)
if (__maestro_read(chip, IDR1_CRAM_POINTER) == index)
return;
- snd_printd("es1968: APU register select failed. (Timeout)\n");
+ dev_dbg(chip->card->dev, "APU register select failed. (Timeout)\n");
}
/* no spinlock */
@@ -699,7 +699,7 @@ static void apu_data_set(struct es1968 *chip, u16 data)
return;
__maestro_write(chip, IDR0_DATA_PORT, data);
}
- snd_printd("es1968: APU register set probably failed (Timeout)!\n");
+ dev_dbg(chip->card->dev, "APU register set probably failed (Timeout)!\n");
}
/* no spinlock */
@@ -1442,13 +1442,14 @@ snd_es1968_init_dmabuf(struct es1968 *chip)
snd_dma_pci_data(chip->pci),
chip->total_bufsize, &chip->dma);
if (err < 0 || ! chip->dma.area) {
- snd_printk(KERN_ERR "es1968: can't allocate dma pages for size %d\n",
+ dev_err(chip->card->dev,
+ "can't allocate dma pages for size %d\n",
chip->total_bufsize);
return -ENOMEM;
}
if ((chip->dma.addr + chip->dma.bytes - 1) & ~((1 << 28) - 1)) {
snd_dma_free_pages(&chip->dma);
- snd_printk(KERN_ERR "es1968: DMA buffer beyond 256MB.\n");
+ dev_err(chip->card->dev, "DMA buffer beyond 256MB.\n");
return -ENOMEM;
}
@@ -1489,7 +1490,8 @@ static int snd_es1968_hw_params(struct snd_pcm_substream *substream,
}
chan->memory = snd_es1968_new_memory(chip, size);
if (chan->memory == NULL) {
- // snd_printd("cannot allocate dma buffer: size = %d\n", size);
+ dev_dbg(chip->card->dev,
+ "cannot allocate dma buffer: size = %d\n", size);
return -ENOMEM;
}
snd_pcm_set_runtime_buffer(substream, &chan->memory->buf);
@@ -1715,11 +1717,13 @@ static void es1968_measure_clock(struct es1968 *chip)
/* search 2 APUs (although one apu is enough) */
if ((apu = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_PLAY)) < 0) {
- snd_printk(KERN_ERR "Hmm, cannot find empty APU pair!?\n");
+ dev_err(chip->card->dev, "Hmm, cannot find empty APU pair!?\n");
return;
}
if ((memory = snd_es1968_new_memory(chip, CLOCK_MEASURE_BUFSIZE)) == NULL) {
- snd_printk(KERN_ERR "cannot allocate dma buffer - using default clock %d\n", chip->clock);
+ dev_warn(chip->card->dev,
+ "cannot allocate dma buffer - using default clock %d\n",
+ chip->clock);
snd_es1968_free_apu_pair(chip, apu);
return;
}
@@ -1780,7 +1784,7 @@ static void es1968_measure_clock(struct es1968 *chip)
else
t += stop_time.tv_usec - start_time.tv_usec;
if (t == 0) {
- snd_printk(KERN_ERR "?? calculation error..\n");
+ dev_err(chip->card->dev, "?? calculation error..\n");
} else {
offset *= 1000;
offset = (offset / t) * 1000 + ((offset % t) * 1000) / t;
@@ -1788,7 +1792,7 @@ static void es1968_measure_clock(struct es1968 *chip)
if (offset >= 40000 && offset <= 50000)
chip->clock = (chip->clock * offset) / 48000;
}
- printk(KERN_INFO "es1968: clocking to %d\n", chip->clock);
+ dev_info(chip->card->dev, "clocking to %d\n", chip->clock);
}
snd_es1968_free_memory(chip, memory);
snd_es1968_free_apu_pair(chip, apu);
@@ -2108,7 +2112,7 @@ static void snd_es1968_ac97_reset(struct es1968 *chip)
outw(inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
#if 0 /* the loop here needs to be much better if we want it.. */
- snd_printk(KERN_INFO "trying software reset\n");
+ dev_info(chip->card->dev, "trying software reset\n");
/* try and do a software reset */
outb(0x80 | 0x7c, ioaddr + 0x30);
for (w = 0;; w++) {
@@ -2416,8 +2420,7 @@ static int es1968_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "es1968: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -2479,7 +2482,8 @@ static int snd_es1968_create_gameport(struct es1968 *chip, int dev)
chip->gameport = gp = gameport_allocate_port();
if (!gp) {
- printk(KERN_ERR "es1968: cannot allocate memory for gameport\n");
+ dev_err(chip->card->dev,
+ "cannot allocate memory for gameport\n");
release_and_free_resource(r);
return -ENOMEM;
}
@@ -2706,7 +2710,8 @@ static int snd_es1968_create(struct snd_card *card,
/* check, if we can restrict PCI DMA transfers to 28 bits */
if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) {
- snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n");
+ dev_err(card->dev,
+ "architecture does not support 28bit PCI busmaster DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -2740,7 +2745,7 @@ static int snd_es1968_create(struct snd_card *card,
chip->io_port = pci_resource_start(pci, 0);
if (request_irq(pci->irq, snd_es1968_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_es1968_free(chip);
return -EBUSY;
}
@@ -2770,7 +2775,7 @@ static int snd_es1968_create(struct snd_card *card,
}
if (do_pm > 1) {
/* not matched; disabling pm */
- printk(KERN_INFO "es1968: not attempting power management.\n");
+ dev_info(card->dev, "not attempting power management.\n");
do_pm = 0;
}
}
@@ -2783,8 +2788,6 @@ static int snd_es1968_create(struct snd_card *card,
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
#ifdef CONFIG_SND_ES1968_RADIO
/* don't play with GPIOs on laptops */
if (chip->pci->subsystem_vendor != 0x125d)
@@ -2802,7 +2805,7 @@ static int snd_es1968_create(struct snd_card *card,
for (i = 0; i < ARRAY_SIZE(snd_es1968_tea575x_gpios); i++) {
chip->tea575x_tuner = i;
if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) {
- snd_printk(KERN_INFO "es1968: detected TEA575x radio type %s\n",
+ dev_info(card->dev, "detected TEA575x radio type %s\n",
get_tea575x_gpio(chip)->name);
strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name,
sizeof(chip->tea.card));
@@ -2836,7 +2839,8 @@ static int snd_es1968_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -2900,7 +2904,7 @@ static int snd_es1968_probe(struct pci_dev *pci,
MPU401_INFO_INTEGRATED |
MPU401_INFO_IRQ_HOOK,
-1, &chip->rmidi)) < 0) {
- printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n");
+ dev_warn(card->dev, "skipping MPU-401 MIDI support..\n");
}
}
@@ -2909,8 +2913,8 @@ static int snd_es1968_probe(struct pci_dev *pci,
#ifdef CONFIG_SND_ES1968_INPUT
err = snd_es1968_input_register(chip);
if (err)
- snd_printk(KERN_WARNING "Input device registration "
- "failed with error %i", err);
+ dev_warn(card->dev,
+ "Input device registration failed with error %i", err);
#endif
snd_es1968_start_irq(chip);
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 45bc8a95b7c4..db18ccabadd6 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -254,7 +254,7 @@ static void snd_fm801_codec_write(struct snd_ac97 *ac97,
goto ok1;
udelay(10);
}
- snd_printk(KERN_ERR "AC'97 interface is busy (1)\n");
+ dev_err(chip->card->dev, "AC'97 interface is busy (1)\n");
return;
ok1:
@@ -269,7 +269,7 @@ static void snd_fm801_codec_write(struct snd_ac97 *ac97,
return;
udelay(10);
}
- snd_printk(KERN_ERR "AC'97 interface #%d is busy (2)\n", ac97->num);
+ dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", ac97->num);
}
static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short reg)
@@ -285,7 +285,7 @@ static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short
goto ok1;
udelay(10);
}
- snd_printk(KERN_ERR "AC'97 interface is busy (1)\n");
+ dev_err(chip->card->dev, "AC'97 interface is busy (1)\n");
return 0;
ok1:
@@ -297,7 +297,7 @@ static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short
goto ok2;
udelay(10);
}
- snd_printk(KERN_ERR "AC'97 interface #%d is busy (2)\n", ac97->num);
+ dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", ac97->num);
return 0;
ok2:
@@ -306,7 +306,7 @@ static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short
goto ok3;
udelay(10);
}
- snd_printk(KERN_ERR "AC'97 interface #%d is not valid (2)\n", ac97->num);
+ dev_err(chip->card->dev, "AC'97 interface #%d is not valid (2)\n", ac97->num);
return 0;
ok3:
@@ -1100,8 +1100,8 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0)
if (!resume) {
- snd_printk(KERN_INFO "Primary AC'97 codec not found, "
- "assume SF64-PCR (tuner-only)\n");
+ dev_info(chip->card->dev,
+ "Primary AC'97 codec not found, assume SF64-PCR (tuner-only)\n");
chip->tea575x_tuner = 3 | TUNER_ONLY;
goto __ac97_ok;
}
@@ -1225,7 +1225,7 @@ static int snd_fm801_create(struct snd_card *card,
if ((tea575x_tuner & TUNER_ONLY) == 0) {
if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq);
snd_fm801_free(chip);
return -EBUSY;
}
@@ -1251,8 +1251,6 @@ static int snd_fm801_create(struct snd_card *card,
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
#ifdef CONFIG_SND_FM801_TEA575X_BOOL
err = v4l2_device_register(&pci->dev, &chip->v4l2_dev);
if (err < 0) {
@@ -1267,7 +1265,7 @@ static int snd_fm801_create(struct snd_card *card,
if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
(tea575x_tuner & TUNER_TYPE_MASK) < 4) {
if (snd_tea575x_init(&chip->tea, THIS_MODULE)) {
- snd_printk(KERN_ERR "TEA575x radio not found\n");
+ dev_err(card->dev, "TEA575x radio not found\n");
snd_fm801_free(chip);
return -ENODEV;
}
@@ -1276,13 +1274,14 @@ static int snd_fm801_create(struct snd_card *card,
for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) {
chip->tea575x_tuner = tea575x_tuner;
if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) {
- snd_printk(KERN_INFO "detected TEA575x radio type %s\n",
+ dev_info(card->dev,
+ "detected TEA575x radio type %s\n",
get_tea575x_gpio(chip)->name);
break;
}
}
if (tea575x_tuner == 4) {
- snd_printk(KERN_ERR "TEA575x radio not found\n");
+ dev_err(card->dev, "TEA575x radio not found\n");
chip->tea575x_tuner = TUNER_DISABLED;
}
}
@@ -1312,7 +1311,8 @@ static int snd_card_fm801_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], radio_nr[dev], &chip)) < 0) {
@@ -1411,8 +1411,7 @@ static int snd_fm801_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "fm801: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 0e53634dbbd8..ac17c3fc9388 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -1,8 +1,15 @@
-menuconfig SND_HDA_INTEL
- tristate "Intel HD Audio"
+menu "HD-Audio"
+
+config SND_HDA
+ tristate
select SND_PCM
select SND_VMASTER
select SND_KCTL_JACK
+
+config SND_HDA_INTEL
+ tristate "HD Audio PCI"
+ depends on SND_PCI
+ select SND_HDA
help
Say Y here to include support for Intel "High Definition
Audio" (Azalia) and its compatible devices.
@@ -13,7 +20,7 @@ menuconfig SND_HDA_INTEL
To compile this driver as a module, choose M here: the module
will be called snd-hda-intel.
-if SND_HDA_INTEL
+if SND_HDA
config SND_HDA_DSP_LOADER
bool
@@ -41,7 +48,6 @@ config SND_HDA_HWDEP
config SND_HDA_RECONFIG
bool "Allow dynamic codec reconfiguration"
- depends on SND_HDA_HWDEP
help
Say Y here to enable the HD-audio codec re-configuration feature.
This adds the sysfs interfaces to allow user to clear the whole
@@ -50,7 +56,7 @@ config SND_HDA_RECONFIG
config SND_HDA_INPUT_BEEP
bool "Support digital beep via input layer"
- depends on INPUT=y || INPUT=SND_HDA_INTEL
+ depends on INPUT=y || INPUT=SND_HDA
help
Say Y here to build a digital beep interface for HD-audio
driver. This interface is used to generate digital beeps.
@@ -76,7 +82,6 @@ config SND_HDA_INPUT_JACK
config SND_HDA_PATCH_LOADER
bool "Support initialization patch loading for HD-audio"
select FW_LOADER
- select SND_HDA_HWDEP
select SND_HDA_RECONFIG
help
Say Y here to allow the HD-audio driver to load a pseudo
@@ -84,8 +89,6 @@ config SND_HDA_PATCH_LOADER
start up. The "patch" file can be specified via patch module
option, such as patch=hda-init.
- This option turns on hwdep and reconfig features automatically.
-
config SND_HDA_CODEC_REALTEK
tristate "Build Realtek HD-audio codec support"
select SND_HDA_GENERIC
@@ -94,7 +97,7 @@ config SND_HDA_CODEC_REALTEK
snd-hda-intel driver, such as ALC880.
comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA_INTEL=y && SND_HDA_CODEC_REALTEK=m
+ depends on SND_HDA=y && SND_HDA_CODEC_REALTEK=m
config SND_HDA_CODEC_ANALOG
tristate "Build Analog Device HD-audio codec support"
@@ -104,7 +107,7 @@ config SND_HDA_CODEC_ANALOG
snd-hda-intel driver, such as AD1986A.
comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA_INTEL=y && SND_HDA_CODEC_ANALOG=m
+ depends on SND_HDA=y && SND_HDA_CODEC_ANALOG=m
config SND_HDA_CODEC_SIGMATEL
tristate "Build IDT/Sigmatel HD-audio codec support"
@@ -114,7 +117,7 @@ config SND_HDA_CODEC_SIGMATEL
snd-hda-intel driver, such as STAC9200.
comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA_INTEL=y && SND_HDA_CODEC_SIGMATEL=m
+ depends on SND_HDA=y && SND_HDA_CODEC_SIGMATEL=m
config SND_HDA_CODEC_VIA
tristate "Build VIA HD-audio codec support"
@@ -124,7 +127,7 @@ config SND_HDA_CODEC_VIA
snd-hda-intel driver, such as VT1708.
comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA_INTEL=y && SND_HDA_CODEC_VIA=m
+ depends on SND_HDA=y && SND_HDA_CODEC_VIA=m
config SND_HDA_CODEC_HDMI
tristate "Build HDMI/DisplayPort HD-audio codec support"
@@ -134,7 +137,7 @@ config SND_HDA_CODEC_HDMI
Intel and Nvidia HDMI/DisplayPort codecs.
comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA_INTEL=y && SND_HDA_CODEC_HDMI=m
+ depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m
config SND_HDA_I915
bool
@@ -149,7 +152,7 @@ config SND_HDA_CODEC_CIRRUS
snd-hda-intel driver, such as CS4206.
comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CIRRUS=m
+ depends on SND_HDA=y && SND_HDA_CODEC_CIRRUS=m
config SND_HDA_CODEC_CONEXANT
tristate "Build Conexant HD-audio codec support"
@@ -159,7 +162,7 @@ config SND_HDA_CODEC_CONEXANT
snd-hda-intel driver, such as CX20549.
comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CONEXANT=m
+ depends on SND_HDA=y && SND_HDA_CODEC_CONEXANT=m
config SND_HDA_CODEC_CA0110
tristate "Build Creative CA0110-IBG codec support"
@@ -169,7 +172,7 @@ config SND_HDA_CODEC_CA0110
snd-hda-intel driver, found on some Creative X-Fi cards.
comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CA0110=m
+ depends on SND_HDA=y && SND_HDA_CODEC_CA0110=m
config SND_HDA_CODEC_CA0132
tristate "Build Creative CA0132 codec support"
@@ -178,7 +181,7 @@ config SND_HDA_CODEC_CA0132
snd-hda-intel driver.
comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CA0132=m
+ depends on SND_HDA=y && SND_HDA_CODEC_CA0132=m
config SND_HDA_CODEC_CA0132_DSP
bool "Support new DSP code for CA0132 codec"
@@ -200,7 +203,7 @@ config SND_HDA_CODEC_CMEDIA
snd-hda-intel driver, such as CMI9880.
comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CMEDIA=m
+ depends on SND_HDA=y && SND_HDA_CODEC_CMEDIA=m
config SND_HDA_CODEC_SI3054
tristate "Build Silicon Labs 3054 HD-modem codec support"
@@ -209,7 +212,7 @@ config SND_HDA_CODEC_SI3054
(and compatibles) support in snd-hda-intel driver.
comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA_INTEL=y && SND_HDA_CODEC_SI3054=m
+ depends on SND_HDA=y && SND_HDA_CODEC_SI3054=m
config SND_HDA_GENERIC
tristate "Enable generic HD-audio codec parser"
@@ -218,7 +221,7 @@ config SND_HDA_GENERIC
in snd-hda-intel driver.
comment "Set to Y if you want auto-loading the codec driver"
- depends on SND_HDA_INTEL=y && SND_HDA_GENERIC=m
+ depends on SND_HDA=y && SND_HDA_GENERIC=m
config SND_HDA_POWER_SAVE_DEFAULT
int "Default time-out for HD-audio power-save mode"
@@ -229,3 +232,5 @@ config SND_HDA_POWER_SAVE_DEFAULT
power-save mode. 0 means to disable the power-save mode.
endif
+
+endmenu
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 1fcb118e480a..d0d0c19ddfc2 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,15 +1,16 @@
snd-hda-intel-objs := hda_intel.o
+snd-hda-controller-objs := hda_controller.o
# for haswell power well
snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o
-snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o
+snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o
snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
# for trace-points
CFLAGS_hda_codec.o := -I$(src)
-CFLAGS_hda_intel.o := -I$(src)
+CFLAGS_hda_controller.o := -I$(src)
snd-hda-codec-generic-objs := hda_generic.o
snd-hda-codec-realtek-objs := patch_realtek.o
@@ -25,7 +26,8 @@ snd-hda-codec-via-objs := patch_via.o
snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o
# common driver
-obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
+obj-$(CONFIG_SND_HDA) := snd-hda-codec.o
+obj-$(CONFIG_SND_HDA) += snd-hda-controller.o
# codec drivers
obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index 47ad31c6aa70..90d2fda6c8f9 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -227,10 +227,18 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
continue;
if (!assoc_line_out)
assoc_line_out = assoc;
- else if (assoc_line_out != assoc)
+ else if (assoc_line_out != assoc) {
+ codec_info(codec,
+ "ignore pin 0x%x with mismatching assoc# 0x%x vs 0x%x\n",
+ nid, assoc, assoc_line_out);
continue;
- if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins))
+ }
+ if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) {
+ codec_info(codec,
+ "ignore pin 0x%x, too many assigned pins\n",
+ nid);
continue;
+ }
line_out[cfg->line_outs].pin = nid;
line_out[cfg->line_outs].seq = seq;
cfg->line_outs++;
@@ -238,8 +246,12 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
case AC_JACK_SPEAKER:
seq = get_defcfg_sequence(def_conf);
assoc = get_defcfg_association(def_conf);
- if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))
+ if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) {
+ codec_info(codec,
+ "ignore pin 0x%x, too many assigned pins\n",
+ nid);
continue;
+ }
speaker_out[cfg->speaker_outs].pin = nid;
speaker_out[cfg->speaker_outs].seq = (assoc << 4) | seq;
cfg->speaker_outs++;
@@ -247,8 +259,12 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
case AC_JACK_HP_OUT:
seq = get_defcfg_sequence(def_conf);
assoc = get_defcfg_association(def_conf);
- if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
+ if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) {
+ codec_info(codec,
+ "ignore pin 0x%x, too many assigned pins\n",
+ nid);
continue;
+ }
hp_out[cfg->hp_outs].pin = nid;
hp_out[cfg->hp_outs].seq = (assoc << 4) | seq;
cfg->hp_outs++;
@@ -267,8 +283,12 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
break;
case AC_JACK_SPDIF_OUT:
case AC_JACK_DIG_OTHER_OUT:
- if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins))
+ if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins)) {
+ codec_info(codec,
+ "ignore pin 0x%x, too many assigned pins\n",
+ nid);
continue;
+ }
cfg->dig_out_pins[cfg->dig_outs] = nid;
cfg->dig_out_type[cfg->dig_outs] =
(loc == AC_JACK_LOC_HDMI) ?
@@ -313,9 +333,9 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
}
if (hsmic)
- snd_printdd("Told to look for a headset mic, but didn't find any.\n");
+ codec_dbg(codec, "Told to look for a headset mic, but didn't find any.\n");
if (hpmic)
- snd_printdd("Told to look for a headphone mic, but didn't find any.\n");
+ codec_dbg(codec, "Told to look for a headphone mic, but didn't find any.\n");
}
/* FIX-UP:
@@ -384,33 +404,33 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
/*
* debug prints of the parsed results
*/
- snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
+ codec_info(codec, "autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
cfg->line_out_pins[2], cfg->line_out_pins[3],
cfg->line_out_pins[4],
cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
(cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
"speaker" : "line"));
- snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+ codec_info(codec, " speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
cfg->speaker_outs, cfg->speaker_pins[0],
cfg->speaker_pins[1], cfg->speaker_pins[2],
cfg->speaker_pins[3], cfg->speaker_pins[4]);
- snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+ codec_info(codec, " hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
cfg->hp_outs, cfg->hp_pins[0],
cfg->hp_pins[1], cfg->hp_pins[2],
cfg->hp_pins[3], cfg->hp_pins[4]);
- snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin);
+ codec_info(codec, " mono: mono_out=0x%x\n", cfg->mono_out_pin);
if (cfg->dig_outs)
- snd_printd(" dig-out=0x%x/0x%x\n",
+ codec_info(codec, " dig-out=0x%x/0x%x\n",
cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
- snd_printd(" inputs:\n");
+ codec_info(codec, " inputs:\n");
for (i = 0; i < cfg->num_inputs; i++) {
- snd_printd(" %s=0x%x\n",
+ codec_info(codec, " %s=0x%x\n",
hda_get_autocfg_input_label(codec, cfg, i),
cfg->inputs[i].pin);
}
if (cfg->dig_in_pin)
- snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin);
+ codec_info(codec, " dig-in=0x%x\n", cfg->dig_in_pin);
return 0;
}
@@ -774,38 +794,33 @@ static void apply_fixup(struct hda_codec *codec, int id, int action, int depth)
case HDA_FIXUP_PINS:
if (action != HDA_FIXUP_ACT_PRE_PROBE || !fix->v.pins)
break;
- snd_printdd(KERN_INFO SFX
- "%s: Apply pincfg for %s\n",
+ codec_dbg(codec, "%s: Apply pincfg for %s\n",
codec->chip_name, modelname);
snd_hda_apply_pincfgs(codec, fix->v.pins);
break;
case HDA_FIXUP_VERBS:
if (action != HDA_FIXUP_ACT_PROBE || !fix->v.verbs)
break;
- snd_printdd(KERN_INFO SFX
- "%s: Apply fix-verbs for %s\n",
+ codec_dbg(codec, "%s: Apply fix-verbs for %s\n",
codec->chip_name, modelname);
snd_hda_add_verbs(codec, fix->v.verbs);
break;
case HDA_FIXUP_FUNC:
if (!fix->v.func)
break;
- snd_printdd(KERN_INFO SFX
- "%s: Apply fix-func for %s\n",
+ codec_dbg(codec, "%s: Apply fix-func for %s\n",
codec->chip_name, modelname);
fix->v.func(codec, fix, action);
break;
case HDA_FIXUP_PINCTLS:
if (action != HDA_FIXUP_ACT_PROBE || !fix->v.pins)
break;
- snd_printdd(KERN_INFO SFX
- "%s: Apply pinctl for %s\n",
+ codec_dbg(codec, "%s: Apply pinctl for %s\n",
codec->chip_name, modelname);
set_pin_targets(codec, fix->v.pins);
break;
default:
- snd_printk(KERN_ERR SFX
- "%s: Invalid fixup type %d\n",
+ codec_err(codec, "%s: Invalid fixup type %d\n",
codec->chip_name, fix->type);
break;
}
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 0589b39cda6e..8c6c50afc0b7 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -20,7 +20,6 @@
*/
#include <linux/input.h>
-#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/export.h>
@@ -140,7 +139,10 @@ static void turn_off_beep(struct hda_beep *beep)
static void snd_hda_do_detach(struct hda_beep *beep)
{
- input_unregister_device(beep->dev);
+ if (beep->registered)
+ input_unregister_device(beep->dev);
+ else
+ input_free_device(beep->dev);
beep->dev = NULL;
turn_off_beep(beep);
}
@@ -149,7 +151,6 @@ static int snd_hda_do_attach(struct hda_beep *beep)
{
struct input_dev *input_dev;
struct hda_codec *codec = beep->codec;
- int err;
input_dev = input_allocate_device();
if (!input_dev)
@@ -167,15 +168,9 @@ static int snd_hda_do_attach(struct hda_beep *beep)
input_dev->evbit[0] = BIT_MASK(EV_SND);
input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
input_dev->event = snd_hda_beep_event;
- input_dev->dev.parent = &codec->bus->pci->dev;
+ input_dev->dev.parent = &codec->dev;
input_set_drvdata(input_dev, beep);
- err = input_register_device(input_dev);
- if (err < 0) {
- input_free_device(input_dev);
- printk(KERN_INFO "hda_beep: unable to register input device\n");
- return err;
- }
beep->dev = input_dev;
return 0;
}
@@ -245,6 +240,27 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
}
EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device);
+int snd_hda_register_beep_device(struct hda_codec *codec)
+{
+ struct hda_beep *beep = codec->beep;
+ int err;
+
+ if (!beep || !beep->dev)
+ return 0;
+
+ err = input_register_device(beep->dev);
+ if (err < 0) {
+ codec_err(codec, "hda_beep: unable to register input device\n");
+ input_free_device(beep->dev);
+ codec->beep = NULL;
+ kfree(beep);
+ return err;
+ }
+ beep->registered = true;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_register_beep_device);
+
static bool ctl_has_mute(struct snd_kcontrol *kcontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
index cb88464676b6..a63b5e077332 100644
--- a/sound/pci/hda/hda_beep.h
+++ b/sound/pci/hda/hda_beep.h
@@ -34,6 +34,7 @@ struct hda_beep {
char phys[32];
int tone;
hda_nid_t nid;
+ unsigned int registered:1;
unsigned int enabled:1;
unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */
unsigned int playing:1;
@@ -45,6 +46,7 @@ struct hda_beep {
int snd_hda_enable_beep_device(struct hda_codec *codec, int enable);
int snd_hda_attach_beep_device(struct hda_codec *codec, int nid);
void snd_hda_detach_beep_device(struct hda_codec *codec);
+int snd_hda_register_beep_device(struct hda_codec *codec);
#else
static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
{
@@ -53,5 +55,9 @@ static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
static inline void snd_hda_detach_beep_device(struct hda_codec *codec)
{
}
+static inline int snd_hda_register_beep_device(struct hda_codec *codec)
+{
+ return 0;
+}
#endif
#endif
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index dafcf82139e2..4c20277a6835 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/async.h>
@@ -68,6 +67,7 @@ static struct hda_vendor_id hda_vendor_ids[] = {
{ 0x17e8, "Chrontel" },
{ 0x1854, "LG" },
{ 0x1aec, "Wolfson Microelectronics" },
+ { 0x1af4, "QEMU" },
{ 0x434d, "C-Media" },
{ 0x8086, "Intel" },
{ 0x8384, "SigmaTel" },
@@ -201,7 +201,7 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int flags,
if ((codec->addr & ~0xf) || (nid & ~0x7f) ||
(verb & ~0xfff) || (parm & ~0xffff)) {
- printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x\n",
+ codec_err(codec, "hda-codec: out of range cmd %x:%x:%x:%x\n",
codec->addr, nid, verb, parm);
return ~0;
}
@@ -249,8 +249,8 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
snd_hda_power_down(codec);
if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) {
if (bus->response_reset) {
- snd_printd("hda_codec: resetting BUS due to "
- "fatal communication error\n");
+ codec_dbg(codec,
+ "resetting BUS due to fatal communication error\n");
trace_hda_bus_reset(bus);
bus->ops.bus_reset(bus);
}
@@ -475,8 +475,7 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
if (len > 0 && conn_list) {
if (len > max_conns) {
- snd_printk(KERN_ERR "hda_codec: "
- "Too many connections %d for NID 0x%x\n",
+ codec_err(codec, "Too many connections %d for NID 0x%x\n",
len, nid);
return -EINVAL;
}
@@ -574,8 +573,8 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
range_val = !!(parm & (1 << (shift-1))); /* ranges */
val = parm & mask;
if (val == 0 && null_count++) { /* no second chance */
- snd_printdd("hda_codec: "
- "invalid CONNECT_LIST verb %x[%i]:%x\n",
+ codec_dbg(codec,
+ "invalid CONNECT_LIST verb %x[%i]:%x\n",
nid, i, parm);
return 0;
}
@@ -583,7 +582,7 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
if (range_val) {
/* ranges between the previous and this one */
if (!prev_nid || prev_nid >= val) {
- snd_printk(KERN_WARNING "hda_codec: "
+ codec_warn(codec,
"invalid dep_range_val %x:%x\n",
prev_nid, val);
continue;
@@ -660,7 +659,7 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
if (!recursive)
return -1;
if (recursive > 10) {
- snd_printd("hda_codec: too deep connection for 0x%x\n", nid);
+ codec_dbg(codec, "too deep connection for 0x%x\n", nid);
return -1;
}
recursive++;
@@ -808,8 +807,7 @@ static int init_unsol_queue(struct hda_bus *bus)
unsol = kzalloc(sizeof(*unsol), GFP_KERNEL);
if (!unsol) {
- snd_printk(KERN_ERR "hda_codec: "
- "can't allocate unsolicited queue\n");
+ dev_err(bus->card->dev, "can't allocate unsolicited queue\n");
return -ENOMEM;
}
INIT_WORK(&unsol->work, process_unsol_events);
@@ -821,51 +819,36 @@ static int init_unsol_queue(struct hda_bus *bus)
/*
* destructor
*/
-static void snd_hda_codec_free(struct hda_codec *codec);
-
-static int snd_hda_bus_free(struct hda_bus *bus)
+static void snd_hda_bus_free(struct hda_bus *bus)
{
- struct hda_codec *codec, *n;
-
if (!bus)
- return 0;
+ return;
+
+ WARN_ON(!list_empty(&bus->codec_list));
if (bus->workq)
flush_workqueue(bus->workq);
if (bus->unsol)
kfree(bus->unsol);
- list_for_each_entry_safe(codec, n, &bus->codec_list, list) {
- snd_hda_codec_free(codec);
- }
if (bus->ops.private_free)
bus->ops.private_free(bus);
if (bus->workq)
destroy_workqueue(bus->workq);
kfree(bus);
- return 0;
}
static int snd_hda_bus_dev_free(struct snd_device *device)
{
- struct hda_bus *bus = device->device_data;
- bus->shutdown = 1;
- return snd_hda_bus_free(bus);
+ snd_hda_bus_free(device->device_data);
+ return 0;
}
-#ifdef CONFIG_SND_HDA_HWDEP
-static int snd_hda_bus_dev_register(struct snd_device *device)
+static int snd_hda_bus_dev_disconnect(struct snd_device *device)
{
struct hda_bus *bus = device->device_data;
- struct hda_codec *codec;
- list_for_each_entry(codec, &bus->codec_list, list) {
- snd_hda_hwdep_add_sysfs(codec);
- snd_hda_hwdep_add_power_sysfs(codec);
- }
+ bus->shutdown = 1;
return 0;
}
-#else
-#define snd_hda_bus_dev_register NULL
-#endif
/**
* snd_hda_bus_new - create a HDA bus
@@ -882,7 +865,7 @@ int snd_hda_bus_new(struct snd_card *card,
struct hda_bus *bus;
int err;
static struct snd_device_ops dev_ops = {
- .dev_register = snd_hda_bus_dev_register,
+ .dev_disconnect = snd_hda_bus_dev_disconnect,
.dev_free = snd_hda_bus_dev_free,
};
@@ -896,7 +879,7 @@ int snd_hda_bus_new(struct snd_card *card,
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
if (bus == NULL) {
- snd_printk(KERN_ERR "can't allocate struct hda_bus\n");
+ dev_err(card->dev, "can't allocate struct hda_bus\n");
return -ENOMEM;
}
@@ -915,7 +898,7 @@ int snd_hda_bus_new(struct snd_card *card,
"hd-audio%d", card->number);
bus->workq = create_singlethread_workqueue(bus->workq_name);
if (!bus->workq) {
- snd_printk(KERN_ERR "cannot create workqueue %s\n",
+ dev_err(card->dev, "cannot create workqueue %s\n",
bus->workq_name);
kfree(bus);
return -ENOMEM;
@@ -959,7 +942,7 @@ find_codec_preset(struct hda_codec *codec)
mutex_lock(&preset_mutex);
list_for_each_entry(tbl, &hda_preset_tables, list) {
if (!try_module_get(tbl->owner)) {
- snd_printk(KERN_ERR "hda_codec: cannot module_get\n");
+ codec_err(codec, "cannot module_get\n");
continue;
}
for (preset = tbl->preset; preset->id; preset++) {
@@ -1185,7 +1168,7 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
{
struct hda_pincfg *pin;
-#ifdef CONFIG_SND_HDA_HWDEP
+#ifdef CONFIG_SND_HDA_RECONFIG
{
unsigned int cfg = 0;
mutex_lock(&codec->user_mutex);
@@ -1300,7 +1283,7 @@ static void free_hda_cache(struct hda_cache_rec *cache);
static void free_init_pincfgs(struct hda_codec *codec)
{
snd_array_free(&codec->driver_pins);
-#ifdef CONFIG_SND_HDA_HWDEP
+#ifdef CONFIG_SND_HDA_RECONFIG
snd_array_free(&codec->user_pins);
#endif
snd_array_free(&codec->init_pins);
@@ -1374,6 +1357,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
hda_call_pm_notify(codec, false); /* cancel leftover refcounts */
+ snd_hda_sysfs_clear(codec);
unload_parser(codec);
module_put(codec->owner);
free_hda_cache(&codec->amp_cache);
@@ -1383,7 +1367,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
kfree(codec->modelname);
kfree(codec->wcaps);
codec->bus->num_codecs--;
- kfree(codec);
+ put_device(&codec->dev);
}
static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
@@ -1392,6 +1376,38 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
static unsigned int hda_set_power_state(struct hda_codec *codec,
unsigned int power_state);
+static int snd_hda_codec_dev_register(struct snd_device *device)
+{
+ struct hda_codec *codec = device->device_data;
+ int err = device_add(&codec->dev);
+
+ if (err < 0)
+ return err;
+ snd_hda_register_beep_device(codec);
+ return 0;
+}
+
+static int snd_hda_codec_dev_disconnect(struct snd_device *device)
+{
+ struct hda_codec *codec = device->device_data;
+
+ snd_hda_detach_beep_device(codec);
+ device_del(&codec->dev);
+ return 0;
+}
+
+static int snd_hda_codec_dev_free(struct snd_device *device)
+{
+ snd_hda_codec_free(device->device_data);
+ return 0;
+}
+
+/* just free the container */
+static void snd_hda_codec_dev_release(struct device *dev)
+{
+ kfree(container_of(dev, struct hda_codec, dev));
+}
+
/**
* snd_hda_codec_new - create a HDA codec
* @bus: the bus to assign
@@ -1408,6 +1424,11 @@ int snd_hda_codec_new(struct hda_bus *bus,
char component[31];
hda_nid_t fg;
int err;
+ static struct snd_device_ops dev_ops = {
+ .dev_register = snd_hda_codec_dev_register,
+ .dev_disconnect = snd_hda_codec_dev_disconnect,
+ .dev_free = snd_hda_codec_dev_free,
+ };
if (snd_BUG_ON(!bus))
return -EINVAL;
@@ -1415,17 +1436,27 @@ int snd_hda_codec_new(struct hda_bus *bus,
return -EINVAL;
if (bus->caddr_tbl[codec_addr]) {
- snd_printk(KERN_ERR "hda_codec: "
- "address 0x%x is already occupied\n", codec_addr);
+ dev_err(bus->card->dev,
+ "address 0x%x is already occupied\n",
+ codec_addr);
return -EBUSY;
}
codec = kzalloc(sizeof(*codec), GFP_KERNEL);
if (codec == NULL) {
- snd_printk(KERN_ERR "can't allocate struct hda_codec\n");
+ dev_err(bus->card->dev, "can't allocate struct hda_codec\n");
return -ENOMEM;
}
+ device_initialize(&codec->dev);
+ codec->dev.parent = &bus->card->card_dev;
+ codec->dev.class = sound_class;
+ codec->dev.release = snd_hda_codec_dev_release;
+ codec->dev.groups = snd_hda_dev_attr_groups;
+ dev_set_name(&codec->dev, "hdaudioC%dD%d", bus->card->number,
+ codec_addr);
+ dev_set_drvdata(&codec->dev, codec); /* for sysfs */
+
codec->bus = bus;
codec->addr = codec_addr;
mutex_init(&codec->spdif_mutex);
@@ -1456,11 +1487,13 @@ int snd_hda_codec_new(struct hda_bus *bus,
hda_keep_power_on(codec);
#endif
+ snd_hda_sysfs_init(codec);
+
if (codec->bus->modelname) {
codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
if (!codec->modelname) {
- snd_hda_codec_free(codec);
- return -ENODEV;
+ err = -ENODEV;
+ goto error;
}
}
@@ -1484,7 +1517,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
setup_fg_nodes(codec);
if (!codec->afg && !codec->mfg) {
- snd_printdd("hda_codec: no AFG or MFG node found\n");
+ dev_err(bus->card->dev, "no AFG or MFG node found\n");
err = -ENODEV;
goto error;
}
@@ -1492,7 +1525,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
fg = codec->afg ? codec->afg : codec->mfg;
err = read_widget_caps(codec, fg);
if (err < 0) {
- snd_printk(KERN_ERR "hda_codec: cannot malloc\n");
+ dev_err(bus->card->dev, "cannot malloc\n");
goto error;
}
err = read_pin_defaults(codec);
@@ -1528,6 +1561,10 @@ int snd_hda_codec_new(struct hda_bus *bus,
codec->subsystem_id, codec->revision_id);
snd_component_add(codec->bus->card, component);
+ err = snd_device_new(bus->card, SNDRV_DEV_CODEC, codec, &dev_ops);
+ if (err < 0)
+ goto error;
+
if (codecp)
*codecp = codec;
return 0;
@@ -1550,7 +1587,7 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec)
fg = codec->afg ? codec->afg : codec->mfg;
err = read_widget_caps(codec, fg);
if (err < 0) {
- snd_printk(KERN_ERR "hda_codec: cannot malloc\n");
+ codec_err(codec, "cannot malloc\n");
return err;
}
@@ -1627,7 +1664,7 @@ int snd_hda_codec_configure(struct hda_codec *codec)
#endif
}
if (!patch) {
- printk(KERN_ERR "hda-codec: No codec parser is available\n");
+ codec_err(codec, "No codec parser is available\n");
return -ENODEV;
}
}
@@ -1711,9 +1748,9 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
if (!nid)
return;
- snd_printdd("hda_codec_setup_stream: "
- "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n",
- nid, stream_tag, channel_id, format);
+ codec_dbg(codec,
+ "hda_codec_setup_stream: NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n",
+ nid, stream_tag, channel_id, format);
p = get_hda_cvt_setup(codec, nid);
if (!p)
return;
@@ -1760,7 +1797,7 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
if (codec->no_sticky_stream)
do_now = 1;
- snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid);
+ codec_dbg(codec, "hda_codec_cleanup_stream: NID=0x%x\n", nid);
p = get_hda_cvt_setup(codec, nid);
if (p) {
/* here we just clear the active flag when do_now isn't set;
@@ -2282,9 +2319,9 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
uinfo->value.integer.min = 0;
uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs);
if (!uinfo->value.integer.max) {
- printk(KERN_WARNING "hda_codec: "
- "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid,
- kcontrol->id.name);
+ codec_warn(codec,
+ "num_steps = 0 for NID=0x%x (ctl = %s)\n",
+ nid, kcontrol->id.name);
return -EINVAL;
}
return 0;
@@ -2558,8 +2595,8 @@ int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
item->nid = nid;
return 0;
}
- printk(KERN_ERR "hda-codec: no NID for mapping control %s:%d:%d\n",
- kctl->id.name, kctl->id.index, index);
+ codec_err(codec, "no NID for mapping control %s:%d:%d\n",
+ kctl->id.name, kctl->id.index, index);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(snd_hda_add_nid);
@@ -2660,6 +2697,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
bus->pcm_dev_bits);
}
}
+ snd_hda_detach_beep_device(codec);
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
@@ -2751,7 +2789,7 @@ static int get_kctl_0dB_offset(struct snd_kcontrol *kctl, int *step_to_check)
return -1;
if (*step_to_check && *step_to_check != step) {
snd_printk(KERN_ERR "hda_codec: Mismatching dB step for vmaster slave (%d!=%d)\n",
- *step_to_check, step);
+- *step_to_check, step);
return -1;
}
*step_to_check = step;
@@ -2821,7 +2859,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
err = map_slaves(codec, slaves, suffix, check_slave_present, NULL);
if (err != 1) {
- snd_printdd("No slave found for %s\n", name);
+ codec_dbg(codec, "No slave found for %s\n", name);
return 0;
}
kctl = snd_ctl_make_virtual_master(name, tlv);
@@ -3487,7 +3525,7 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch", idx);
if (idx < 0) {
- printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
+ codec_err(codec, "too many IEC958 outputs\n");
return -EBUSY;
}
spdif = snd_array_new(&codec->spdif_out);
@@ -3691,7 +3729,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch", 0);
if (idx < 0) {
- printk(KERN_ERR "hda_codec: too many IEC958 inputs\n");
+ codec_err(codec, "too many IEC958 inputs\n");
return -EBUSY;
}
for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
@@ -4010,7 +4048,7 @@ static void sync_power_up_states(struct hda_codec *codec)
}
}
-#ifdef CONFIG_SND_HDA_HWDEP
+#ifdef CONFIG_SND_HDA_RECONFIG
/* execute additional init verbs */
static void hda_exec_init_verbs(struct hda_codec *codec)
{
@@ -4118,12 +4156,13 @@ int snd_hda_build_controls(struct hda_bus *bus)
list_for_each_entry(codec, &bus->codec_list, list) {
int err = snd_hda_codec_build_controls(codec);
if (err < 0) {
- printk(KERN_ERR "hda_codec: cannot build controls "
- "for #%d (error %d)\n", codec->addr, err);
+ codec_err(codec,
+ "cannot build controls for #%d (error %d)\n",
+ codec->addr, err);
err = snd_hda_codec_reset(codec);
if (err < 0) {
- printk(KERN_ERR
- "hda_codec: cannot revert codec\n");
+ codec_err(codec,
+ "cannot revert codec\n");
return err;
}
}
@@ -4294,7 +4333,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
break;
default:
snd_printdd("invalid format width %d\n",
- snd_pcm_format_width(format));
+ snd_pcm_format_width(format));
return 0;
}
@@ -4370,10 +4409,10 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
rates |= rate_bits[i].alsa_bits;
}
if (rates == 0) {
- snd_printk(KERN_ERR "hda_codec: rates == 0 "
- "(nid=0x%x, val=0x%x, ovrd=%i)\n",
- nid, val,
- (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0);
+ codec_err(codec,
+ "rates == 0 (nid=0x%x, val=0x%x, ovrd=%i)\n",
+ nid, val,
+ (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0);
return -EIO;
}
*ratesp = rates;
@@ -4433,12 +4472,11 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
bps = 8;
}
if (formats == 0) {
- snd_printk(KERN_ERR "hda_codec: formats == 0 "
- "(nid=0x%x, val=0x%x, ovrd=%i, "
- "streams=0x%x)\n",
- nid, val,
- (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0,
- streams);
+ codec_err(codec,
+ "formats == 0 (nid=0x%x, val=0x%x, ovrd=%i, streams=0x%x)\n",
+ nid, val,
+ (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0,
+ streams);
return -EIO;
}
if (formatsp)
@@ -4629,7 +4667,7 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
int i;
if (type >= HDA_PCM_NTYPES) {
- snd_printk(KERN_WARNING "Invalid PCM type %d\n", type);
+ dev_err(bus->card->dev, "Invalid PCM type %d\n", type);
return -EINVAL;
}
@@ -4650,10 +4688,11 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
}
#endif
- snd_printk(KERN_WARNING "Too many %s devices\n",
+ dev_warn(bus->card->dev, "Too many %s devices\n",
snd_hda_pcm_type_name[type]);
#ifndef CONFIG_SND_DYNAMIC_MINORS
- snd_printk(KERN_WARNING "Consider building the kernel with CONFIG_SND_DYNAMIC_MINORS=y\n");
+ dev_warn(bus->card->dev,
+ "Consider building the kernel with CONFIG_SND_DYNAMIC_MINORS=y\n");
#endif
return -EAGAIN;
}
@@ -4691,12 +4730,13 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec)
return 0;
err = codec->patch_ops.build_pcms(codec);
if (err < 0) {
- printk(KERN_ERR "hda_codec: cannot build PCMs"
- "for #%d (error %d)\n", codec->addr, err);
+ codec_err(codec,
+ "cannot build PCMs for #%d (error %d)\n",
+ codec->addr, err);
err = snd_hda_codec_reset(codec);
if (err < 0) {
- printk(KERN_ERR
- "hda_codec: cannot revert codec\n");
+ codec_err(codec,
+ "cannot revert codec\n");
return err;
}
}
@@ -4715,9 +4755,9 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec)
cpcm->device = dev;
err = snd_hda_attach_pcm(codec, cpcm);
if (err < 0) {
- printk(KERN_ERR "hda_codec: cannot attach "
- "PCM stream %d for codec #%d\n",
- dev, codec->addr);
+ codec_err(codec,
+ "cannot attach PCM stream %d for codec #%d\n",
+ dev, codec->addr);
continue; /* no fatal error */
}
}
@@ -4786,8 +4826,8 @@ int snd_hda_check_board_config(struct hda_codec *codec,
for (i = 0; i < num_configs; i++) {
if (models[i] &&
!strcmp(codec->modelname, models[i])) {
- snd_printd(KERN_INFO "hda_codec: model '%s' is "
- "selected\n", models[i]);
+ codec_info(codec, "model '%s' is selected\n",
+ models[i]);
return i;
}
}
@@ -4809,10 +4849,9 @@ int snd_hda_check_board_config(struct hda_codec *codec,
sprintf(tmp, "#%d", tbl->value);
model = tmp;
}
- snd_printdd(KERN_INFO "hda_codec: model '%s' is selected "
- "for config %x:%x (%s)\n",
- model, tbl->subvendor, tbl->subdevice,
- (tbl->name ? tbl->name : "Unknown device"));
+ codec_info(codec, "model '%s' is selected for config %x:%x (%s)\n",
+ model, tbl->subvendor, tbl->subdevice,
+ (tbl->name ? tbl->name : "Unknown device"));
#endif
return tbl->value;
}
@@ -4870,10 +4909,9 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
sprintf(tmp, "#%d", tbl->value);
model = tmp;
}
- snd_printdd(KERN_INFO "hda_codec: model '%s' is selected "
- "for config %x:%x (%s)\n",
- model, tbl->subvendor, tbl->subdevice,
- (tbl->name ? tbl->name : "Unknown device"));
+ codec_info(codec, "model '%s' is selected for config %x:%x (%s)\n",
+ model, tbl->subvendor, tbl->subdevice,
+ (tbl->name ? tbl->name : "Unknown device"));
#endif
return tbl->value;
}
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index ab2a444ba501..a4233136cb93 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -271,6 +271,7 @@ struct hda_pcm {
/* codec information */
struct hda_codec {
+ struct device dev;
struct hda_bus *bus;
unsigned int addr; /* codec addr*/
struct list_head list; /* list point */
@@ -332,14 +333,17 @@ struct hda_codec {
struct snd_array driver_pins; /* pin configs set by codec parser */
struct snd_array cvt_setups; /* audio convert setups */
-#ifdef CONFIG_SND_HDA_HWDEP
struct mutex user_mutex;
- struct snd_hwdep *hwdep; /* assigned hwdep device */
+#ifdef CONFIG_SND_HDA_RECONFIG
struct snd_array init_verbs; /* additional init verbs */
struct snd_array hints; /* additional hints */
struct snd_array user_pins; /* default pin configs to override */
#endif
+#ifdef CONFIG_SND_HDA_HWDEP
+ struct snd_hwdep *hwdep; /* assigned hwdep device */
+#endif
+
/* misc flags */
unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
* status change
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
new file mode 100644
index 000000000000..97993e17f46a
--- /dev/null
+++ b/sound/pci/hda/hda_controller.c
@@ -0,0 +1,2031 @@
+/*
+ *
+ * Implementation of primary alsa driver code base for Intel HD Audio.
+ *
+ * Copyright(c) 2004 Intel Corporation. All rights reserved.
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ * PeiSen Hou <pshou@realtek.com.tw>
+ *
+ * This program is free software; 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/clocksource.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include "hda_priv.h"
+#include "hda_controller.h"
+
+#define CREATE_TRACE_POINTS
+#include "hda_intel_trace.h"
+
+/* DSP lock helpers */
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+#define dsp_lock_init(dev) mutex_init(&(dev)->dsp_mutex)
+#define dsp_lock(dev) mutex_lock(&(dev)->dsp_mutex)
+#define dsp_unlock(dev) mutex_unlock(&(dev)->dsp_mutex)
+#define dsp_is_locked(dev) ((dev)->locked)
+#else
+#define dsp_lock_init(dev) do {} while (0)
+#define dsp_lock(dev) do {} while (0)
+#define dsp_unlock(dev) do {} while (0)
+#define dsp_is_locked(dev) 0
+#endif
+
+/*
+ * AZX stream operations.
+ */
+
+/* start a stream */
+static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
+{
+ /*
+ * Before stream start, initialize parameter
+ */
+ azx_dev->insufficient = 1;
+
+ /* enable SIE */
+ azx_writel(chip, INTCTL,
+ azx_readl(chip, INTCTL) | (1 << azx_dev->index));
+ /* set DMA start and interrupt mask */
+ azx_sd_writeb(chip, azx_dev, SD_CTL,
+ azx_sd_readb(chip, azx_dev, SD_CTL) |
+ SD_CTL_DMA_START | SD_INT_MASK);
+}
+
+/* stop DMA */
+static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev)
+{
+ azx_sd_writeb(chip, azx_dev, SD_CTL,
+ azx_sd_readb(chip, azx_dev, SD_CTL) &
+ ~(SD_CTL_DMA_START | SD_INT_MASK));
+ azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
+}
+
+/* stop a stream */
+void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
+{
+ azx_stream_clear(chip, azx_dev);
+ /* disable SIE */
+ azx_writel(chip, INTCTL,
+ azx_readl(chip, INTCTL) & ~(1 << azx_dev->index));
+}
+EXPORT_SYMBOL_GPL(azx_stream_stop);
+
+/* reset stream */
+static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
+{
+ unsigned char val;
+ int timeout;
+
+ azx_stream_clear(chip, azx_dev);
+
+ azx_sd_writeb(chip, azx_dev, SD_CTL,
+ azx_sd_readb(chip, azx_dev, SD_CTL) |
+ SD_CTL_STREAM_RESET);
+ udelay(3);
+ timeout = 300;
+ while (!((val = azx_sd_readb(chip, azx_dev, SD_CTL)) &
+ SD_CTL_STREAM_RESET) && --timeout)
+ ;
+ val &= ~SD_CTL_STREAM_RESET;
+ azx_sd_writeb(chip, azx_dev, SD_CTL, val);
+ udelay(3);
+
+ timeout = 300;
+ /* waiting for hardware to report that the stream is out of reset */
+ while (((val = azx_sd_readb(chip, azx_dev, SD_CTL)) &
+ SD_CTL_STREAM_RESET) && --timeout)
+ ;
+
+ /* reset first position - may not be synced with hw at this time */
+ *azx_dev->posbuf = 0;
+}
+
+/*
+ * set up the SD for streaming
+ */
+static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
+{
+ unsigned int val;
+ /* make sure the run bit is zero for SD */
+ azx_stream_clear(chip, azx_dev);
+ /* program the stream_tag */
+ val = azx_sd_readl(chip, azx_dev, SD_CTL);
+ val = (val & ~SD_CTL_STREAM_TAG_MASK) |
+ (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT);
+ if (!azx_snoop(chip))
+ val |= SD_CTL_TRAFFIC_PRIO;
+ azx_sd_writel(chip, azx_dev, SD_CTL, val);
+
+ /* program the length of samples in cyclic buffer */
+ azx_sd_writel(chip, azx_dev, SD_CBL, azx_dev->bufsize);
+
+ /* program the stream format */
+ /* this value needs to be the same as the one programmed */
+ azx_sd_writew(chip, azx_dev, SD_FORMAT, azx_dev->format_val);
+
+ /* program the stream LVI (last valid index) of the BDL */
+ azx_sd_writew(chip, azx_dev, SD_LVI, azx_dev->frags - 1);
+
+ /* program the BDL address */
+ /* lower BDL address */
+ azx_sd_writel(chip, azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
+ /* upper BDL address */
+ azx_sd_writel(chip, azx_dev, SD_BDLPU,
+ upper_32_bits(azx_dev->bdl.addr));
+
+ /* enable the position buffer */
+ if (chip->position_fix[0] != POS_FIX_LPIB ||
+ chip->position_fix[1] != POS_FIX_LPIB) {
+ if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
+ azx_writel(chip, DPLBASE,
+ (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
+ }
+
+ /* set the interrupt enable bits in the descriptor control register */
+ azx_sd_writel(chip, azx_dev, SD_CTL,
+ azx_sd_readl(chip, azx_dev, SD_CTL) | SD_INT_MASK);
+
+ return 0;
+}
+
+/* assign a stream for the PCM */
+static inline struct azx_dev *
+azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream)
+{
+ int dev, i, nums;
+ struct azx_dev *res = NULL;
+ /* make a non-zero unique key for the substream */
+ int key = (substream->pcm->device << 16) | (substream->number << 2) |
+ (substream->stream + 1);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dev = chip->playback_index_offset;
+ nums = chip->playback_streams;
+ } else {
+ dev = chip->capture_index_offset;
+ nums = chip->capture_streams;
+ }
+ for (i = 0; i < nums; i++, dev++) {
+ struct azx_dev *azx_dev = &chip->azx_dev[dev];
+ dsp_lock(azx_dev);
+ if (!azx_dev->opened && !dsp_is_locked(azx_dev)) {
+ res = azx_dev;
+ if (res->assigned_key == key) {
+ res->opened = 1;
+ res->assigned_key = key;
+ dsp_unlock(azx_dev);
+ return azx_dev;
+ }
+ }
+ dsp_unlock(azx_dev);
+ }
+ if (res) {
+ dsp_lock(res);
+ res->opened = 1;
+ res->assigned_key = key;
+ dsp_unlock(res);
+ }
+ return res;
+}
+
+/* release the assigned stream */
+static inline void azx_release_device(struct azx_dev *azx_dev)
+{
+ azx_dev->opened = 0;
+}
+
+static cycle_t azx_cc_read(const struct cyclecounter *cc)
+{
+ struct azx_dev *azx_dev = container_of(cc, struct azx_dev, azx_cc);
+ struct snd_pcm_substream *substream = azx_dev->substream;
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ struct azx *chip = apcm->chip;
+
+ return azx_readl(chip, WALLCLK);
+}
+
+static void azx_timecounter_init(struct snd_pcm_substream *substream,
+ bool force, cycle_t last)
+{
+ struct azx_dev *azx_dev = get_azx_dev(substream);
+ struct timecounter *tc = &azx_dev->azx_tc;
+ struct cyclecounter *cc = &azx_dev->azx_cc;
+ u64 nsec;
+
+ cc->read = azx_cc_read;
+ cc->mask = CLOCKSOURCE_MASK(32);
+
+ /*
+ * Converting from 24 MHz to ns means applying a 125/3 factor.
+ * To avoid any saturation issues in intermediate operations,
+ * the 125 factor is applied first. The division is applied
+ * last after reading the timecounter value.
+ * Applying the 1/3 factor as part of the multiplication
+ * requires at least 20 bits for a decent precision, however
+ * overflows occur after about 4 hours or less, not a option.
+ */
+
+ cc->mult = 125; /* saturation after 195 years */
+ cc->shift = 0;
+
+ nsec = 0; /* audio time is elapsed time since trigger */
+ timecounter_init(tc, cc, nsec);
+ if (force)
+ /*
+ * force timecounter to use predefined value,
+ * used for synchronized starts
+ */
+ tc->cycle_last = last;
+}
+
+static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream,
+ u64 nsec)
+{
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+ u64 codec_frames, codec_nsecs;
+
+ if (!hinfo->ops.get_delay)
+ return nsec;
+
+ codec_frames = hinfo->ops.get_delay(hinfo, apcm->codec, substream);
+ codec_nsecs = div_u64(codec_frames * 1000000000LL,
+ substream->runtime->rate);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ return nsec + codec_nsecs;
+
+ return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0;
+}
+
+/*
+ * set up a BDL entry
+ */
+static int setup_bdle(struct azx *chip,
+ struct snd_dma_buffer *dmab,
+ struct azx_dev *azx_dev, u32 **bdlp,
+ int ofs, int size, int with_ioc)
+{
+ u32 *bdl = *bdlp;
+
+ while (size > 0) {
+ dma_addr_t addr;
+ int chunk;
+
+ if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
+ return -EINVAL;
+
+ addr = snd_sgbuf_get_addr(dmab, ofs);
+ /* program the address field of the BDL entry */
+ bdl[0] = cpu_to_le32((u32)addr);
+ bdl[1] = cpu_to_le32(upper_32_bits(addr));
+ /* program the size field of the BDL entry */
+ chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size);
+ /* one BDLE cannot cross 4K boundary on CTHDA chips */
+ if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
+ u32 remain = 0x1000 - (ofs & 0xfff);
+ if (chunk > remain)
+ chunk = remain;
+ }
+ bdl[2] = cpu_to_le32(chunk);
+ /* program the IOC to enable interrupt
+ * only when the whole fragment is processed
+ */
+ size -= chunk;
+ bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
+ bdl += 4;
+ azx_dev->frags++;
+ ofs += chunk;
+ }
+ *bdlp = bdl;
+ return ofs;
+}
+
+/*
+ * set up BDL entries
+ */
+static int azx_setup_periods(struct azx *chip,
+ struct snd_pcm_substream *substream,
+ struct azx_dev *azx_dev)
+{
+ u32 *bdl;
+ int i, ofs, periods, period_bytes;
+ int pos_adj = 0;
+
+ /* reset BDL address */
+ azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
+ azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
+
+ period_bytes = azx_dev->period_bytes;
+ periods = azx_dev->bufsize / period_bytes;
+
+ /* program the initial BDL entries */
+ bdl = (u32 *)azx_dev->bdl.area;
+ ofs = 0;
+ azx_dev->frags = 0;
+
+ if (chip->bdl_pos_adj)
+ pos_adj = chip->bdl_pos_adj[chip->dev_index];
+ if (!azx_dev->no_period_wakeup && pos_adj > 0) {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int pos_align = pos_adj;
+ pos_adj = (pos_adj * runtime->rate + 47999) / 48000;
+ if (!pos_adj)
+ pos_adj = pos_align;
+ else
+ pos_adj = ((pos_adj + pos_align - 1) / pos_align) *
+ pos_align;
+ pos_adj = frames_to_bytes(runtime, pos_adj);
+ if (pos_adj >= period_bytes) {
+ dev_warn(chip->card->dev,"Too big adjustment %d\n",
+ pos_adj);
+ pos_adj = 0;
+ } else {
+ ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
+ azx_dev,
+ &bdl, ofs, pos_adj, true);
+ if (ofs < 0)
+ goto error;
+ }
+ } else
+ pos_adj = 0;
+
+ for (i = 0; i < periods; i++) {
+ if (i == periods - 1 && pos_adj)
+ ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
+ azx_dev, &bdl, ofs,
+ period_bytes - pos_adj, 0);
+ else
+ ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
+ azx_dev, &bdl, ofs,
+ period_bytes,
+ !azx_dev->no_period_wakeup);
+ if (ofs < 0)
+ goto error;
+ }
+ return 0;
+
+ error:
+ dev_err(chip->card->dev, "Too many BDL entries: buffer=%d, period=%d\n",
+ azx_dev->bufsize, period_bytes);
+ return -EINVAL;
+}
+
+/*
+ * PCM ops
+ */
+
+static int azx_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+ struct azx *chip = apcm->chip;
+ struct azx_dev *azx_dev = get_azx_dev(substream);
+ unsigned long flags;
+
+ mutex_lock(&chip->open_mutex);
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ azx_dev->substream = NULL;
+ azx_dev->running = 0;
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ azx_release_device(azx_dev);
+ hinfo->ops.close(hinfo, apcm->codec, substream);
+ snd_hda_power_down(apcm->codec);
+ mutex_unlock(&chip->open_mutex);
+ return 0;
+}
+
+static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ struct azx *chip = apcm->chip;
+ int ret;
+
+ dsp_lock(get_azx_dev(substream));
+ if (dsp_is_locked(get_azx_dev(substream))) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = chip->ops->substream_alloc_pages(chip, substream,
+ params_buffer_bytes(hw_params));
+unlock:
+ dsp_unlock(get_azx_dev(substream));
+ return ret;
+}
+
+static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ struct azx_dev *azx_dev = get_azx_dev(substream);
+ struct azx *chip = apcm->chip;
+ struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+ int err;
+
+ /* reset BDL address */
+ dsp_lock(azx_dev);
+ if (!dsp_is_locked(azx_dev)) {
+ azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
+ azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
+ azx_sd_writel(chip, azx_dev, SD_CTL, 0);
+ azx_dev->bufsize = 0;
+ azx_dev->period_bytes = 0;
+ azx_dev->format_val = 0;
+ }
+
+ snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
+
+ err = chip->ops->substream_free_pages(chip, substream);
+ azx_dev->prepared = 0;
+ dsp_unlock(azx_dev);
+ return err;
+}
+
+static int azx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ struct azx *chip = apcm->chip;
+ struct azx_dev *azx_dev = get_azx_dev(substream);
+ struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned int bufsize, period_bytes, format_val, stream_tag;
+ int err;
+ struct hda_spdif_out *spdif =
+ snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid);
+ unsigned short ctls = spdif ? spdif->ctls : 0;
+
+ dsp_lock(azx_dev);
+ if (dsp_is_locked(azx_dev)) {
+ err = -EBUSY;
+ goto unlock;
+ }
+
+ azx_stream_reset(chip, azx_dev);
+ format_val = snd_hda_calc_stream_format(runtime->rate,
+ runtime->channels,
+ runtime->format,
+ hinfo->maxbps,
+ ctls);
+ if (!format_val) {
+ dev_err(chip->card->dev,
+ "invalid format_val, rate=%d, ch=%d, format=%d\n",
+ runtime->rate, runtime->channels, runtime->format);
+ err = -EINVAL;
+ goto unlock;
+ }
+
+ bufsize = snd_pcm_lib_buffer_bytes(substream);
+ period_bytes = snd_pcm_lib_period_bytes(substream);
+
+ dev_dbg(chip->card->dev, "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
+ bufsize, format_val);
+
+ if (bufsize != azx_dev->bufsize ||
+ period_bytes != azx_dev->period_bytes ||
+ format_val != azx_dev->format_val ||
+ runtime->no_period_wakeup != azx_dev->no_period_wakeup) {
+ azx_dev->bufsize = bufsize;
+ azx_dev->period_bytes = period_bytes;
+ azx_dev->format_val = format_val;
+ azx_dev->no_period_wakeup = runtime->no_period_wakeup;
+ err = azx_setup_periods(chip, substream, azx_dev);
+ if (err < 0)
+ goto unlock;
+ }
+
+ /* when LPIB delay correction gives a small negative value,
+ * we ignore it; currently set the threshold statically to
+ * 64 frames
+ */
+ if (runtime->period_size > 64)
+ azx_dev->delay_negative_threshold = -frames_to_bytes(runtime, 64);
+ else
+ azx_dev->delay_negative_threshold = 0;
+
+ /* wallclk has 24Mhz clock source */
+ azx_dev->period_wallclk = (((runtime->period_size * 24000) /
+ runtime->rate) * 1000);
+ azx_setup_controller(chip, azx_dev);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ azx_dev->fifo_size =
+ azx_sd_readw(chip, azx_dev, SD_FIFOSIZE) + 1;
+ else
+ azx_dev->fifo_size = 0;
+
+ stream_tag = azx_dev->stream_tag;
+ /* CA-IBG chips need the playback stream starting from 1 */
+ if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) &&
+ stream_tag > chip->capture_streams)
+ stream_tag -= chip->capture_streams;
+ err = snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
+ azx_dev->format_val, substream);
+
+ unlock:
+ if (!err)
+ azx_dev->prepared = 1;
+ dsp_unlock(azx_dev);
+ return err;
+}
+
+static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ struct azx *chip = apcm->chip;
+ struct azx_dev *azx_dev;
+ struct snd_pcm_substream *s;
+ int rstart = 0, start, nsync = 0, sbits = 0;
+ int nwait, timeout;
+
+ azx_dev = get_azx_dev(substream);
+ trace_azx_pcm_trigger(chip, azx_dev, cmd);
+
+ if (dsp_is_locked(azx_dev) || !azx_dev->prepared)
+ return -EPIPE;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ rstart = 1;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ start = 1;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ start = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (s->pcm->card != substream->pcm->card)
+ continue;
+ azx_dev = get_azx_dev(s);
+ sbits |= 1 << azx_dev->index;
+ nsync++;
+ snd_pcm_trigger_done(s, substream);
+ }
+
+ spin_lock(&chip->reg_lock);
+
+ /* first, set SYNC bits of corresponding streams */
+ if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+ azx_writel(chip, OLD_SSYNC,
+ azx_readl(chip, OLD_SSYNC) | sbits);
+ else
+ azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits);
+
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (s->pcm->card != substream->pcm->card)
+ continue;
+ azx_dev = get_azx_dev(s);
+ if (start) {
+ azx_dev->start_wallclk = azx_readl(chip, WALLCLK);
+ if (!rstart)
+ azx_dev->start_wallclk -=
+ azx_dev->period_wallclk;
+ azx_stream_start(chip, azx_dev);
+ } else {
+ azx_stream_stop(chip, azx_dev);
+ }
+ azx_dev->running = start;
+ }
+ spin_unlock(&chip->reg_lock);
+ if (start) {
+ /* wait until all FIFOs get ready */
+ for (timeout = 5000; timeout; timeout--) {
+ nwait = 0;
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (s->pcm->card != substream->pcm->card)
+ continue;
+ azx_dev = get_azx_dev(s);
+ if (!(azx_sd_readb(chip, azx_dev, SD_STS) &
+ SD_STS_FIFO_READY))
+ nwait++;
+ }
+ if (!nwait)
+ break;
+ cpu_relax();
+ }
+ } else {
+ /* wait until all RUN bits are cleared */
+ for (timeout = 5000; timeout; timeout--) {
+ nwait = 0;
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (s->pcm->card != substream->pcm->card)
+ continue;
+ azx_dev = get_azx_dev(s);
+ if (azx_sd_readb(chip, azx_dev, SD_CTL) &
+ SD_CTL_DMA_START)
+ nwait++;
+ }
+ if (!nwait)
+ break;
+ cpu_relax();
+ }
+ }
+ spin_lock(&chip->reg_lock);
+ /* reset SYNC bits */
+ if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+ azx_writel(chip, OLD_SSYNC,
+ azx_readl(chip, OLD_SSYNC) & ~sbits);
+ else
+ azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
+ if (start) {
+ azx_timecounter_init(substream, 0, 0);
+ if (nsync > 1) {
+ cycle_t cycle_last;
+
+ /* same start cycle for master and group */
+ azx_dev = get_azx_dev(substream);
+ cycle_last = azx_dev->azx_tc.cycle_last;
+
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (s->pcm->card != substream->pcm->card)
+ continue;
+ azx_timecounter_init(s, 1, cycle_last);
+ }
+ }
+ }
+ spin_unlock(&chip->reg_lock);
+ return 0;
+}
+
+/* get the current DMA position with correction on VIA chips */
+static unsigned int azx_via_get_position(struct azx *chip,
+ struct azx_dev *azx_dev)
+{
+ unsigned int link_pos, mini_pos, bound_pos;
+ unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos;
+ unsigned int fifo_size;
+
+ link_pos = azx_sd_readl(chip, azx_dev, SD_LPIB);
+ if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* Playback, no problem using link position */
+ return link_pos;
+ }
+
+ /* Capture */
+ /* For new chipset,
+ * use mod to get the DMA position just like old chipset
+ */
+ mod_dma_pos = le32_to_cpu(*azx_dev->posbuf);
+ mod_dma_pos %= azx_dev->period_bytes;
+
+ /* azx_dev->fifo_size can't get FIFO size of in stream.
+ * Get from base address + offset.
+ */
+ fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET);
+
+ if (azx_dev->insufficient) {
+ /* Link position never gather than FIFO size */
+ if (link_pos <= fifo_size)
+ return 0;
+
+ azx_dev->insufficient = 0;
+ }
+
+ if (link_pos <= fifo_size)
+ mini_pos = azx_dev->bufsize + link_pos - fifo_size;
+ else
+ mini_pos = link_pos - fifo_size;
+
+ /* Find nearest previous boudary */
+ mod_mini_pos = mini_pos % azx_dev->period_bytes;
+ mod_link_pos = link_pos % azx_dev->period_bytes;
+ if (mod_link_pos >= fifo_size)
+ bound_pos = link_pos - mod_link_pos;
+ else if (mod_dma_pos >= mod_mini_pos)
+ bound_pos = mini_pos - mod_mini_pos;
+ else {
+ bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes;
+ if (bound_pos >= azx_dev->bufsize)
+ bound_pos = 0;
+ }
+
+ /* Calculate real DMA position we want */
+ return bound_pos + mod_dma_pos;
+}
+
+unsigned int azx_get_position(struct azx *chip,
+ struct azx_dev *azx_dev,
+ bool with_check)
+{
+ struct snd_pcm_substream *substream = azx_dev->substream;
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ unsigned int pos;
+ int stream = substream->stream;
+ struct hda_pcm_stream *hinfo = apcm->hinfo[stream];
+ int delay = 0;
+
+ switch (chip->position_fix[stream]) {
+ case POS_FIX_LPIB:
+ /* read LPIB */
+ pos = azx_sd_readl(chip, azx_dev, SD_LPIB);
+ break;
+ case POS_FIX_VIACOMBO:
+ pos = azx_via_get_position(chip, azx_dev);
+ break;
+ default:
+ /* use the position buffer */
+ pos = le32_to_cpu(*azx_dev->posbuf);
+ if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) {
+ if (!pos || pos == (u32)-1) {
+ dev_info(chip->card->dev,
+ "Invalid position buffer, using LPIB read method instead.\n");
+ chip->position_fix[stream] = POS_FIX_LPIB;
+ pos = azx_sd_readl(chip, azx_dev, SD_LPIB);
+ } else
+ chip->position_fix[stream] = POS_FIX_POSBUF;
+ }
+ break;
+ }
+
+ if (pos >= azx_dev->bufsize)
+ pos = 0;
+
+ /* calculate runtime delay from LPIB */
+ if (substream->runtime &&
+ chip->position_fix[stream] == POS_FIX_POSBUF &&
+ (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
+ unsigned int lpib_pos = azx_sd_readl(chip, azx_dev, SD_LPIB);
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ delay = pos - lpib_pos;
+ else
+ delay = lpib_pos - pos;
+ if (delay < 0) {
+ if (delay >= azx_dev->delay_negative_threshold)
+ delay = 0;
+ else
+ delay += azx_dev->bufsize;
+ }
+ if (delay >= azx_dev->period_bytes) {
+ dev_info(chip->card->dev,
+ "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n",
+ delay, azx_dev->period_bytes);
+ delay = 0;
+ chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY;
+ }
+ delay = bytes_to_frames(substream->runtime, delay);
+ }
+
+ if (substream->runtime) {
+ if (hinfo->ops.get_delay)
+ delay += hinfo->ops.get_delay(hinfo, apcm->codec,
+ substream);
+ substream->runtime->delay = delay;
+ }
+
+ trace_azx_get_position(chip, azx_dev, pos, delay);
+ return pos;
+}
+EXPORT_SYMBOL_GPL(azx_get_position);
+
+static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ struct azx *chip = apcm->chip;
+ struct azx_dev *azx_dev = get_azx_dev(substream);
+ return bytes_to_frames(substream->runtime,
+ azx_get_position(chip, azx_dev, false));
+}
+
+static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream,
+ struct timespec *ts)
+{
+ struct azx_dev *azx_dev = get_azx_dev(substream);
+ u64 nsec;
+
+ nsec = timecounter_read(&azx_dev->azx_tc);
+ nsec = div_u64(nsec, 3); /* can be optimized */
+ nsec = azx_adjust_codec_delay(substream, nsec);
+
+ *ts = ns_to_timespec(nsec);
+
+ return 0;
+}
+
+static struct snd_pcm_hardware azx_pcm_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ /* No full-resume yet implemented */
+ /* SNDRV_PCM_INFO_RESUME |*/
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_SYNC_START |
+ SNDRV_PCM_INFO_HAS_WALL_CLOCK |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = AZX_MAX_BUF_SIZE,
+ .period_bytes_min = 128,
+ .period_bytes_max = AZX_MAX_BUF_SIZE / 2,
+ .periods_min = 2,
+ .periods_max = AZX_MAX_FRAG,
+ .fifo_size = 0,
+};
+
+static int azx_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+ struct azx *chip = apcm->chip;
+ struct azx_dev *azx_dev;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned long flags;
+ int err;
+ int buff_step;
+
+ mutex_lock(&chip->open_mutex);
+ azx_dev = azx_assign_device(chip, substream);
+ if (azx_dev == NULL) {
+ mutex_unlock(&chip->open_mutex);
+ return -EBUSY;
+ }
+ runtime->hw = azx_pcm_hw;
+ runtime->hw.channels_min = hinfo->channels_min;
+ runtime->hw.channels_max = hinfo->channels_max;
+ runtime->hw.formats = hinfo->formats;
+ runtime->hw.rates = hinfo->rates;
+ snd_pcm_limit_hw_rates(runtime);
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+ /* avoid wrap-around with wall-clock */
+ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME,
+ 20,
+ 178000000);
+
+ if (chip->align_buffer_size)
+ /* constrain buffer sizes to be multiple of 128
+ bytes. This is more efficient in terms of memory
+ access but isn't required by the HDA spec and
+ prevents users from specifying exact period/buffer
+ sizes. For example for 44.1kHz, a period size set
+ to 20ms will be rounded to 19.59ms. */
+ buff_step = 128;
+ else
+ /* Don't enforce steps on buffer sizes, still need to
+ be multiple of 4 bytes (HDA spec). Tested on Intel
+ HDA controllers, may not work on all devices where
+ option needs to be disabled */
+ buff_step = 4;
+
+ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ buff_step);
+ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ buff_step);
+ snd_hda_power_up_d3wait(apcm->codec);
+ err = hinfo->ops.open(hinfo, apcm->codec, substream);
+ if (err < 0) {
+ azx_release_device(azx_dev);
+ snd_hda_power_down(apcm->codec);
+ mutex_unlock(&chip->open_mutex);
+ return err;
+ }
+ snd_pcm_limit_hw_rates(runtime);
+ /* sanity check */
+ if (snd_BUG_ON(!runtime->hw.channels_min) ||
+ snd_BUG_ON(!runtime->hw.channels_max) ||
+ snd_BUG_ON(!runtime->hw.formats) ||
+ snd_BUG_ON(!runtime->hw.rates)) {
+ azx_release_device(azx_dev);
+ hinfo->ops.close(hinfo, apcm->codec, substream);
+ snd_hda_power_down(apcm->codec);
+ mutex_unlock(&chip->open_mutex);
+ return -EINVAL;
+ }
+
+ /* disable WALLCLOCK timestamps for capture streams
+ until we figure out how to handle digital inputs */
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK;
+
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ azx_dev->substream = substream;
+ azx_dev->running = 0;
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+ runtime->private_data = azx_dev;
+ snd_pcm_set_sync(substream);
+ mutex_unlock(&chip->open_mutex);
+ return 0;
+}
+
+static int azx_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *area)
+{
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ struct azx *chip = apcm->chip;
+ if (chip->ops->pcm_mmap_prepare)
+ chip->ops->pcm_mmap_prepare(substream, area);
+ return snd_pcm_lib_default_mmap(substream, area);
+}
+
+static struct snd_pcm_ops azx_pcm_ops = {
+ .open = azx_pcm_open,
+ .close = azx_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = azx_pcm_hw_params,
+ .hw_free = azx_pcm_hw_free,
+ .prepare = azx_pcm_prepare,
+ .trigger = azx_pcm_trigger,
+ .pointer = azx_pcm_pointer,
+ .wall_clock = azx_get_wallclock_tstamp,
+ .mmap = azx_pcm_mmap,
+ .page = snd_pcm_sgbuf_ops_page,
+};
+
+static void azx_pcm_free(struct snd_pcm *pcm)
+{
+ struct azx_pcm *apcm = pcm->private_data;
+ if (apcm) {
+ list_del(&apcm->list);
+ kfree(apcm);
+ }
+}
+
+#define MAX_PREALLOC_SIZE (32 * 1024 * 1024)
+
+static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
+ struct hda_pcm *cpcm)
+{
+ struct azx *chip = bus->private_data;
+ struct snd_pcm *pcm;
+ struct azx_pcm *apcm;
+ int pcm_dev = cpcm->device;
+ unsigned int size;
+ int s, err;
+
+ list_for_each_entry(apcm, &chip->pcm_list, list) {
+ if (apcm->pcm->device == pcm_dev) {
+ dev_err(chip->card->dev, "PCM %d already exists\n",
+ pcm_dev);
+ return -EBUSY;
+ }
+ }
+ err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
+ cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
+ cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams,
+ &pcm);
+ if (err < 0)
+ return err;
+ strlcpy(pcm->name, cpcm->name, sizeof(pcm->name));
+ apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
+ if (apcm == NULL)
+ return -ENOMEM;
+ apcm->chip = chip;
+ apcm->pcm = pcm;
+ apcm->codec = codec;
+ pcm->private_data = apcm;
+ pcm->private_free = azx_pcm_free;
+ if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
+ pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
+ list_add_tail(&apcm->list, &chip->pcm_list);
+ cpcm->pcm = pcm;
+ for (s = 0; s < 2; s++) {
+ apcm->hinfo[s] = &cpcm->stream[s];
+ if (cpcm->stream[s].substreams)
+ snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
+ }
+ /* buffer pre-allocation */
+ size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
+ if (size > MAX_PREALLOC_SIZE)
+ size = MAX_PREALLOC_SIZE;
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+ chip->card->dev,
+ size, MAX_PREALLOC_SIZE);
+ /* link to codec */
+ pcm->dev = &codec->dev;
+ return 0;
+}
+
+/*
+ * CORB / RIRB interface
+ */
+static int azx_alloc_cmd_io(struct azx *chip)
+{
+ int err;
+
+ /* single page (at least 4096 bytes) must suffice for both ringbuffes */
+ err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
+ PAGE_SIZE, &chip->rb);
+ if (err < 0)
+ dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n");
+ return err;
+}
+EXPORT_SYMBOL_GPL(azx_alloc_cmd_io);
+
+static void azx_init_cmd_io(struct azx *chip)
+{
+ int timeout;
+
+ spin_lock_irq(&chip->reg_lock);
+ /* CORB set up */
+ chip->corb.addr = chip->rb.addr;
+ chip->corb.buf = (u32 *)chip->rb.area;
+ azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
+ azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr));
+
+ /* set the corb size to 256 entries (ULI requires explicitly) */
+ azx_writeb(chip, CORBSIZE, 0x02);
+ /* set the corb write pointer to 0 */
+ azx_writew(chip, CORBWP, 0);
+
+ /* reset the corb hw read pointer */
+ azx_writew(chip, CORBRP, ICH6_CORBRP_RST);
+ for (timeout = 1000; timeout > 0; timeout--) {
+ if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST)
+ break;
+ udelay(1);
+ }
+ if (timeout <= 0)
+ dev_err(chip->card->dev, "CORB reset timeout#1, CORBRP = %d\n",
+ azx_readw(chip, CORBRP));
+
+ azx_writew(chip, CORBRP, 0);
+ for (timeout = 1000; timeout > 0; timeout--) {
+ if (azx_readw(chip, CORBRP) == 0)
+ break;
+ udelay(1);
+ }
+ if (timeout <= 0)
+ dev_err(chip->card->dev, "CORB reset timeout#2, CORBRP = %d\n",
+ azx_readw(chip, CORBRP));
+
+ /* enable corb dma */
+ azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN);
+
+ /* RIRB set up */
+ chip->rirb.addr = chip->rb.addr + 2048;
+ chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
+ chip->rirb.wp = chip->rirb.rp = 0;
+ memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds));
+ azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
+ azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
+
+ /* set the rirb size to 256 entries (ULI requires explicitly) */
+ azx_writeb(chip, RIRBSIZE, 0x02);
+ /* reset the rirb hw write pointer */
+ azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
+ /* set N=1, get RIRB response interrupt for new entry */
+ if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
+ azx_writew(chip, RINTCNT, 0xc0);
+ else
+ azx_writew(chip, RINTCNT, 1);
+ /* enable rirb dma and response irq */
+ azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
+ spin_unlock_irq(&chip->reg_lock);
+}
+EXPORT_SYMBOL_GPL(azx_init_cmd_io);
+
+static void azx_free_cmd_io(struct azx *chip)
+{
+ spin_lock_irq(&chip->reg_lock);
+ /* disable ringbuffer DMAs */
+ azx_writeb(chip, RIRBCTL, 0);
+ azx_writeb(chip, CORBCTL, 0);
+ spin_unlock_irq(&chip->reg_lock);
+}
+EXPORT_SYMBOL_GPL(azx_free_cmd_io);
+
+static unsigned int azx_command_addr(u32 cmd)
+{
+ unsigned int addr = cmd >> 28;
+
+ if (addr >= AZX_MAX_CODECS) {
+ snd_BUG();
+ addr = 0;
+ }
+
+ return addr;
+}
+
+/* send a command */
+static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
+{
+ struct azx *chip = bus->private_data;
+ unsigned int addr = azx_command_addr(val);
+ unsigned int wp, rp;
+
+ spin_lock_irq(&chip->reg_lock);
+
+ /* add command to corb */
+ wp = azx_readw(chip, CORBWP);
+ if (wp == 0xffff) {
+ /* something wrong, controller likely turned to D3 */
+ spin_unlock_irq(&chip->reg_lock);
+ return -EIO;
+ }
+ wp++;
+ wp %= ICH6_MAX_CORB_ENTRIES;
+
+ rp = azx_readw(chip, CORBRP);
+ if (wp == rp) {
+ /* oops, it's full */
+ spin_unlock_irq(&chip->reg_lock);
+ return -EAGAIN;
+ }
+
+ chip->rirb.cmds[addr]++;
+ chip->corb.buf[wp] = cpu_to_le32(val);
+ azx_writew(chip, CORBWP, wp);
+
+ spin_unlock_irq(&chip->reg_lock);
+
+ return 0;
+}
+
+#define ICH6_RIRB_EX_UNSOL_EV (1<<4)
+
+/* retrieve RIRB entry - called from interrupt handler */
+static void azx_update_rirb(struct azx *chip)
+{
+ unsigned int rp, wp;
+ unsigned int addr;
+ u32 res, res_ex;
+
+ wp = azx_readw(chip, RIRBWP);
+ if (wp == 0xffff) {
+ /* something wrong, controller likely turned to D3 */
+ return;
+ }
+
+ if (wp == chip->rirb.wp)
+ return;
+ chip->rirb.wp = wp;
+
+ while (chip->rirb.rp != wp) {
+ chip->rirb.rp++;
+ chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES;
+
+ rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */
+ res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
+ res = le32_to_cpu(chip->rirb.buf[rp]);
+ addr = res_ex & 0xf;
+ if ((addr >= AZX_MAX_CODECS) || !(chip->codec_mask & (1 << addr))) {
+ dev_err(chip->card->dev, "spurious response %#x:%#x, rp = %d, wp = %d",
+ res, res_ex,
+ chip->rirb.rp, wp);
+ snd_BUG();
+ }
+ else if (res_ex & ICH6_RIRB_EX_UNSOL_EV)
+ snd_hda_queue_unsol_event(chip->bus, res, res_ex);
+ else if (chip->rirb.cmds[addr]) {
+ chip->rirb.res[addr] = res;
+ smp_wmb();
+ chip->rirb.cmds[addr]--;
+ } else if (printk_ratelimit()) {
+ dev_err(chip->card->dev, "spurious response %#x:%#x, last cmd=%#08x\n",
+ res, res_ex,
+ chip->last_cmd[addr]);
+ }
+ }
+}
+
+/* receive a response */
+static unsigned int azx_rirb_get_response(struct hda_bus *bus,
+ unsigned int addr)
+{
+ struct azx *chip = bus->private_data;
+ unsigned long timeout;
+ unsigned long loopcounter;
+ int do_poll = 0;
+
+ again:
+ timeout = jiffies + msecs_to_jiffies(1000);
+
+ for (loopcounter = 0;; loopcounter++) {
+ if (chip->polling_mode || do_poll) {
+ spin_lock_irq(&chip->reg_lock);
+ azx_update_rirb(chip);
+ spin_unlock_irq(&chip->reg_lock);
+ }
+ if (!chip->rirb.cmds[addr]) {
+ smp_rmb();
+ bus->rirb_error = 0;
+
+ if (!do_poll)
+ chip->poll_count = 0;
+ return chip->rirb.res[addr]; /* the last value */
+ }
+ if (time_after(jiffies, timeout))
+ break;
+ if (bus->needs_damn_long_delay || loopcounter > 3000)
+ msleep(2); /* temporary workaround */
+ else {
+ udelay(10);
+ cond_resched();
+ }
+ }
+
+ if (!bus->no_response_fallback)
+ return -1;
+
+ if (!chip->polling_mode && chip->poll_count < 2) {
+ dev_dbg(chip->card->dev,
+ "azx_get_response timeout, polling the codec once: last cmd=0x%08x\n",
+ chip->last_cmd[addr]);
+ do_poll = 1;
+ chip->poll_count++;
+ goto again;
+ }
+
+
+ if (!chip->polling_mode) {
+ dev_warn(chip->card->dev,
+ "azx_get_response timeout, switching to polling mode: last cmd=0x%08x\n",
+ chip->last_cmd[addr]);
+ chip->polling_mode = 1;
+ goto again;
+ }
+
+ if (chip->msi) {
+ dev_warn(chip->card->dev,
+ "No response from codec, disabling MSI: last cmd=0x%08x\n",
+ chip->last_cmd[addr]);
+ if (chip->ops->disable_msi_reset_irq(chip) &&
+ chip->ops->disable_msi_reset_irq(chip) < 0) {
+ bus->rirb_error = 1;
+ return -1;
+ }
+ goto again;
+ }
+
+ if (chip->probing) {
+ /* If this critical timeout happens during the codec probing
+ * phase, this is likely an access to a non-existing codec
+ * slot. Better to return an error and reset the system.
+ */
+ return -1;
+ }
+
+ /* a fatal communication error; need either to reset or to fallback
+ * to the single_cmd mode
+ */
+ bus->rirb_error = 1;
+ if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) {
+ bus->response_reset = 1;
+ return -1; /* give a chance to retry */
+ }
+
+ dev_err(chip->card->dev,
+ "azx_get_response timeout, switching to single_cmd mode: last cmd=0x%08x\n",
+ chip->last_cmd[addr]);
+ chip->single_cmd = 1;
+ bus->response_reset = 0;
+ /* release CORB/RIRB */
+ azx_free_cmd_io(chip);
+ /* disable unsolicited responses */
+ azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_UNSOL);
+ return -1;
+}
+
+/*
+ * Use the single immediate command instead of CORB/RIRB for simplicity
+ *
+ * Note: according to Intel, this is not preferred use. The command was
+ * intended for the BIOS only, and may get confused with unsolicited
+ * responses. So, we shouldn't use it for normal operation from the
+ * driver.
+ * I left the codes, however, for debugging/testing purposes.
+ */
+
+/* receive a response */
+static int azx_single_wait_for_response(struct azx *chip, unsigned int addr)
+{
+ int timeout = 50;
+
+ while (timeout--) {
+ /* check IRV busy bit */
+ if (azx_readw(chip, IRS) & ICH6_IRS_VALID) {
+ /* reuse rirb.res as the response return value */
+ chip->rirb.res[addr] = azx_readl(chip, IR);
+ return 0;
+ }
+ udelay(1);
+ }
+ if (printk_ratelimit())
+ dev_dbg(chip->card->dev, "get_response timeout: IRS=0x%x\n",
+ azx_readw(chip, IRS));
+ chip->rirb.res[addr] = -1;
+ return -EIO;
+}
+
+/* send a command */
+static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
+{
+ struct azx *chip = bus->private_data;
+ unsigned int addr = azx_command_addr(val);
+ int timeout = 50;
+
+ bus->rirb_error = 0;
+ while (timeout--) {
+ /* check ICB busy bit */
+ if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) {
+ /* Clear IRV valid bit */
+ azx_writew(chip, IRS, azx_readw(chip, IRS) |
+ ICH6_IRS_VALID);
+ azx_writel(chip, IC, val);
+ azx_writew(chip, IRS, azx_readw(chip, IRS) |
+ ICH6_IRS_BUSY);
+ return azx_single_wait_for_response(chip, addr);
+ }
+ udelay(1);
+ }
+ if (printk_ratelimit())
+ dev_dbg(chip->card->dev,
+ "send_cmd timeout: IRS=0x%x, val=0x%x\n",
+ azx_readw(chip, IRS), val);
+ return -EIO;
+}
+
+/* receive a response */
+static unsigned int azx_single_get_response(struct hda_bus *bus,
+ unsigned int addr)
+{
+ struct azx *chip = bus->private_data;
+ return chip->rirb.res[addr];
+}
+
+/*
+ * The below are the main callbacks from hda_codec.
+ *
+ * They are just the skeleton to call sub-callbacks according to the
+ * current setting of chip->single_cmd.
+ */
+
+/* send a command */
+static int azx_send_cmd(struct hda_bus *bus, unsigned int val)
+{
+ struct azx *chip = bus->private_data;
+
+ if (chip->disabled)
+ return 0;
+ chip->last_cmd[azx_command_addr(val)] = val;
+ if (chip->single_cmd)
+ return azx_single_send_cmd(bus, val);
+ else
+ return azx_corb_send_cmd(bus, val);
+}
+EXPORT_SYMBOL_GPL(azx_send_cmd);
+
+/* get a response */
+static unsigned int azx_get_response(struct hda_bus *bus,
+ unsigned int addr)
+{
+ struct azx *chip = bus->private_data;
+ if (chip->disabled)
+ return 0;
+ if (chip->single_cmd)
+ return azx_single_get_response(bus, addr);
+ else
+ return azx_rirb_get_response(bus, addr);
+}
+EXPORT_SYMBOL_GPL(azx_get_response);
+
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+/*
+ * DSP loading code (e.g. for CA0132)
+ */
+
+/* use the first stream for loading DSP */
+static struct azx_dev *
+azx_get_dsp_loader_dev(struct azx *chip)
+{
+ return &chip->azx_dev[chip->playback_index_offset];
+}
+
+static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
+ unsigned int byte_size,
+ struct snd_dma_buffer *bufp)
+{
+ u32 *bdl;
+ struct azx *chip = bus->private_data;
+ struct azx_dev *azx_dev;
+ int err;
+
+ azx_dev = azx_get_dsp_loader_dev(chip);
+
+ dsp_lock(azx_dev);
+ spin_lock_irq(&chip->reg_lock);
+ if (azx_dev->running || azx_dev->locked) {
+ spin_unlock_irq(&chip->reg_lock);
+ err = -EBUSY;
+ goto unlock;
+ }
+ azx_dev->prepared = 0;
+ chip->saved_azx_dev = *azx_dev;
+ azx_dev->locked = 1;
+ spin_unlock_irq(&chip->reg_lock);
+
+ err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV_SG,
+ byte_size, bufp);
+ if (err < 0)
+ goto err_alloc;
+
+ azx_dev->bufsize = byte_size;
+ azx_dev->period_bytes = byte_size;
+ azx_dev->format_val = format;
+
+ azx_stream_reset(chip, azx_dev);
+
+ /* reset BDL address */
+ azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
+ azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
+
+ azx_dev->frags = 0;
+ bdl = (u32 *)azx_dev->bdl.area;
+ err = setup_bdle(chip, bufp, azx_dev, &bdl, 0, byte_size, 0);
+ if (err < 0)
+ goto error;
+
+ azx_setup_controller(chip, azx_dev);
+ dsp_unlock(azx_dev);
+ return azx_dev->stream_tag;
+
+ error:
+ chip->ops->dma_free_pages(chip, bufp);
+ err_alloc:
+ spin_lock_irq(&chip->reg_lock);
+ if (azx_dev->opened)
+ *azx_dev = chip->saved_azx_dev;
+ azx_dev->locked = 0;
+ spin_unlock_irq(&chip->reg_lock);
+ unlock:
+ dsp_unlock(azx_dev);
+ return err;
+}
+
+static void azx_load_dsp_trigger(struct hda_bus *bus, bool start)
+{
+ struct azx *chip = bus->private_data;
+ struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
+
+ if (start)
+ azx_stream_start(chip, azx_dev);
+ else
+ azx_stream_stop(chip, azx_dev);
+ azx_dev->running = start;
+}
+
+static void azx_load_dsp_cleanup(struct hda_bus *bus,
+ struct snd_dma_buffer *dmab)
+{
+ struct azx *chip = bus->private_data;
+ struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
+
+ if (!dmab->area || !azx_dev->locked)
+ return;
+
+ dsp_lock(azx_dev);
+ /* reset BDL address */
+ azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
+ azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
+ azx_sd_writel(chip, azx_dev, SD_CTL, 0);
+ azx_dev->bufsize = 0;
+ azx_dev->period_bytes = 0;
+ azx_dev->format_val = 0;
+
+ chip->ops->dma_free_pages(chip, dmab);
+ dmab->area = NULL;
+
+ spin_lock_irq(&chip->reg_lock);
+ if (azx_dev->opened)
+ *azx_dev = chip->saved_azx_dev;
+ azx_dev->locked = 0;
+ spin_unlock_irq(&chip->reg_lock);
+ dsp_unlock(azx_dev);
+}
+#endif /* CONFIG_SND_HDA_DSP_LOADER */
+
+int azx_alloc_stream_pages(struct azx *chip)
+{
+ int i, err;
+ struct snd_card *card = chip->card;
+
+ for (i = 0; i < chip->num_streams; i++) {
+ dsp_lock_init(&chip->azx_dev[i]);
+ /* allocate memory for the BDL for each stream */
+ err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
+ BDL_SIZE,
+ &chip->azx_dev[i].bdl);
+ if (err < 0) {
+ dev_err(card->dev, "cannot allocate BDL\n");
+ return -ENOMEM;
+ }
+ }
+ /* allocate memory for the position buffer */
+ err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
+ chip->num_streams * 8, &chip->posbuf);
+ if (err < 0) {
+ dev_err(card->dev, "cannot allocate posbuf\n");
+ return -ENOMEM;
+ }
+
+ /* allocate CORB/RIRB */
+ err = azx_alloc_cmd_io(chip);
+ if (err < 0)
+ return err;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(azx_alloc_stream_pages);
+
+void azx_free_stream_pages(struct azx *chip)
+{
+ int i;
+ if (chip->azx_dev) {
+ for (i = 0; i < chip->num_streams; i++)
+ if (chip->azx_dev[i].bdl.area)
+ chip->ops->dma_free_pages(
+ chip, &chip->azx_dev[i].bdl);
+ }
+ if (chip->rb.area)
+ chip->ops->dma_free_pages(chip, &chip->rb);
+ if (chip->posbuf.area)
+ chip->ops->dma_free_pages(chip, &chip->posbuf);
+}
+EXPORT_SYMBOL_GPL(azx_free_stream_pages);
+
+/*
+ * Lowlevel interface
+ */
+
+/* enter link reset */
+void azx_enter_link_reset(struct azx *chip)
+{
+ unsigned long timeout;
+
+ /* reset controller */
+ azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET);
+
+ timeout = jiffies + msecs_to_jiffies(100);
+ while ((azx_readb(chip, GCTL) & ICH6_GCTL_RESET) &&
+ time_before(jiffies, timeout))
+ usleep_range(500, 1000);
+}
+EXPORT_SYMBOL_GPL(azx_enter_link_reset);
+
+/* exit link reset */
+static void azx_exit_link_reset(struct azx *chip)
+{
+ unsigned long timeout;
+
+ azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET);
+
+ timeout = jiffies + msecs_to_jiffies(100);
+ while (!azx_readb(chip, GCTL) &&
+ time_before(jiffies, timeout))
+ usleep_range(500, 1000);
+}
+
+/* reset codec link */
+static int azx_reset(struct azx *chip, int full_reset)
+{
+ if (!full_reset)
+ goto __skip;
+
+ /* clear STATESTS */
+ azx_writew(chip, STATESTS, STATESTS_INT_MASK);
+
+ /* reset controller */
+ azx_enter_link_reset(chip);
+
+ /* delay for >= 100us for codec PLL to settle per spec
+ * Rev 0.9 section 5.5.1
+ */
+ usleep_range(500, 1000);
+
+ /* Bring controller out of reset */
+ azx_exit_link_reset(chip);
+
+ /* Brent Chartrand said to wait >= 540us for codecs to initialize */
+ usleep_range(1000, 1200);
+
+ __skip:
+ /* check to see if controller is ready */
+ if (!azx_readb(chip, GCTL)) {
+ dev_dbg(chip->card->dev, "azx_reset: controller not ready!\n");
+ return -EBUSY;
+ }
+
+ /* Accept unsolicited responses */
+ if (!chip->single_cmd)
+ azx_writel(chip, GCTL, azx_readl(chip, GCTL) |
+ ICH6_GCTL_UNSOL);
+
+ /* detect codecs */
+ if (!chip->codec_mask) {
+ chip->codec_mask = azx_readw(chip, STATESTS);
+ dev_dbg(chip->card->dev, "codec_mask = 0x%x\n",
+ chip->codec_mask);
+ }
+
+ return 0;
+}
+
+/* enable interrupts */
+static void azx_int_enable(struct azx *chip)
+{
+ /* enable controller CIE and GIE */
+ azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) |
+ ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN);
+}
+
+/* disable interrupts */
+static void azx_int_disable(struct azx *chip)
+{
+ int i;
+
+ /* disable interrupts in stream descriptor */
+ for (i = 0; i < chip->num_streams; i++) {
+ struct azx_dev *azx_dev = &chip->azx_dev[i];
+ azx_sd_writeb(chip, azx_dev, SD_CTL,
+ azx_sd_readb(chip, azx_dev, SD_CTL) &
+ ~SD_INT_MASK);
+ }
+
+ /* disable SIE for all streams */
+ azx_writeb(chip, INTCTL, 0);
+
+ /* disable controller CIE and GIE */
+ azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) &
+ ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN));
+}
+
+/* clear interrupts */
+static void azx_int_clear(struct azx *chip)
+{
+ int i;
+
+ /* clear stream status */
+ for (i = 0; i < chip->num_streams; i++) {
+ struct azx_dev *azx_dev = &chip->azx_dev[i];
+ azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK);
+ }
+
+ /* clear STATESTS */
+ azx_writew(chip, STATESTS, STATESTS_INT_MASK);
+
+ /* clear rirb status */
+ azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
+
+ /* clear int status */
+ azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM);
+}
+
+/*
+ * reset and start the controller registers
+ */
+void azx_init_chip(struct azx *chip, int full_reset)
+{
+ if (chip->initialized)
+ return;
+
+ /* reset controller */
+ azx_reset(chip, full_reset);
+
+ /* initialize interrupts */
+ azx_int_clear(chip);
+ azx_int_enable(chip);
+
+ /* initialize the codec command I/O */
+ if (!chip->single_cmd)
+ azx_init_cmd_io(chip);
+
+ /* program the position buffer */
+ azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
+ azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr));
+
+ chip->initialized = 1;
+}
+EXPORT_SYMBOL_GPL(azx_init_chip);
+
+void azx_stop_chip(struct azx *chip)
+{
+ if (!chip->initialized)
+ return;
+
+ /* disable interrupts */
+ azx_int_disable(chip);
+ azx_int_clear(chip);
+
+ /* disable CORB/RIRB */
+ azx_free_cmd_io(chip);
+
+ /* disable position buffer */
+ azx_writel(chip, DPLBASE, 0);
+ azx_writel(chip, DPUBASE, 0);
+
+ chip->initialized = 0;
+}
+EXPORT_SYMBOL_GPL(azx_stop_chip);
+
+/*
+ * interrupt handler
+ */
+irqreturn_t azx_interrupt(int irq, void *dev_id)
+{
+ struct azx *chip = dev_id;
+ struct azx_dev *azx_dev;
+ u32 status;
+ u8 sd_status;
+ int i;
+
+#ifdef CONFIG_PM_RUNTIME
+ if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
+ if (chip->card->dev->power.runtime_status != RPM_ACTIVE)
+ return IRQ_NONE;
+#endif
+
+ spin_lock(&chip->reg_lock);
+
+ if (chip->disabled) {
+ spin_unlock(&chip->reg_lock);
+ return IRQ_NONE;
+ }
+
+ status = azx_readl(chip, INTSTS);
+ if (status == 0 || status == 0xffffffff) {
+ spin_unlock(&chip->reg_lock);
+ return IRQ_NONE;
+ }
+
+ for (i = 0; i < chip->num_streams; i++) {
+ azx_dev = &chip->azx_dev[i];
+ if (status & azx_dev->sd_int_sta_mask) {
+ sd_status = azx_sd_readb(chip, azx_dev, SD_STS);
+ azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK);
+ if (!azx_dev->substream || !azx_dev->running ||
+ !(sd_status & SD_INT_COMPLETE))
+ continue;
+ /* check whether this IRQ is really acceptable */
+ if (!chip->ops->position_check ||
+ chip->ops->position_check(chip, azx_dev)) {
+ spin_unlock(&chip->reg_lock);
+ snd_pcm_period_elapsed(azx_dev->substream);
+ spin_lock(&chip->reg_lock);
+ }
+ }
+ }
+
+ /* clear rirb int */
+ status = azx_readb(chip, RIRBSTS);
+ if (status & RIRB_INT_MASK) {
+ if (status & RIRB_INT_RESPONSE) {
+ if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY)
+ udelay(80);
+ azx_update_rirb(chip);
+ }
+ azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
+ }
+
+ spin_unlock(&chip->reg_lock);
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(azx_interrupt);
+
+/*
+ * Codec initerface
+ */
+
+/*
+ * Probe the given codec address
+ */
+static int probe_codec(struct azx *chip, int addr)
+{
+ unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
+ (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
+ unsigned int res;
+
+ mutex_lock(&chip->bus->cmd_mutex);
+ chip->probing = 1;
+ azx_send_cmd(chip->bus, cmd);
+ res = azx_get_response(chip->bus, addr);
+ chip->probing = 0;
+ mutex_unlock(&chip->bus->cmd_mutex);
+ if (res == -1)
+ return -EIO;
+ dev_dbg(chip->card->dev, "codec #%d probed OK\n", addr);
+ return 0;
+}
+
+static void azx_bus_reset(struct hda_bus *bus)
+{
+ struct azx *chip = bus->private_data;
+
+ bus->in_reset = 1;
+ azx_stop_chip(chip);
+ azx_init_chip(chip, 1);
+#ifdef CONFIG_PM
+ if (chip->initialized) {
+ struct azx_pcm *p;
+ list_for_each_entry(p, &chip->pcm_list, list)
+ snd_pcm_suspend_all(p->pcm);
+ snd_hda_suspend(chip->bus);
+ snd_hda_resume(chip->bus);
+ }
+#endif
+ bus->in_reset = 0;
+}
+
+#ifdef CONFIG_PM
+/* power-up/down the controller */
+static void azx_power_notify(struct hda_bus *bus, bool power_up)
+{
+ struct azx *chip = bus->private_data;
+
+ if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
+ return;
+
+ if (power_up)
+ pm_runtime_get_sync(chip->card->dev);
+ else
+ pm_runtime_put_sync(chip->card->dev);
+}
+#endif
+
+static int get_jackpoll_interval(struct azx *chip)
+{
+ int i;
+ unsigned int j;
+
+ if (!chip->jackpoll_ms)
+ return 0;
+
+ i = chip->jackpoll_ms[chip->dev_index];
+ if (i == 0)
+ return 0;
+ if (i < 50 || i > 60000)
+ j = 0;
+ else
+ j = msecs_to_jiffies(i);
+ if (j == 0)
+ dev_warn(chip->card->dev,
+ "jackpoll_ms value out of range: %d\n", i);
+ return j;
+}
+
+/* Codec initialization */
+int azx_codec_create(struct azx *chip, const char *model,
+ unsigned int max_slots,
+ int *power_save_to)
+{
+ struct hda_bus_template bus_temp;
+ int c, codecs, err;
+
+ memset(&bus_temp, 0, sizeof(bus_temp));
+ bus_temp.private_data = chip;
+ bus_temp.modelname = model;
+ bus_temp.pci = chip->pci;
+ bus_temp.ops.command = azx_send_cmd;
+ bus_temp.ops.get_response = azx_get_response;
+ bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
+ bus_temp.ops.bus_reset = azx_bus_reset;
+#ifdef CONFIG_PM
+ bus_temp.power_save = power_save_to;
+ bus_temp.ops.pm_notify = azx_power_notify;
+#endif
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+ bus_temp.ops.load_dsp_prepare = azx_load_dsp_prepare;
+ bus_temp.ops.load_dsp_trigger = azx_load_dsp_trigger;
+ bus_temp.ops.load_dsp_cleanup = azx_load_dsp_cleanup;
+#endif
+
+ err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);
+ if (err < 0)
+ return err;
+
+ if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
+ dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
+ chip->bus->needs_damn_long_delay = 1;
+ }
+
+ codecs = 0;
+ if (!max_slots)
+ max_slots = AZX_DEFAULT_CODECS;
+
+ /* First try to probe all given codec slots */
+ for (c = 0; c < max_slots; c++) {
+ if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
+ if (probe_codec(chip, c) < 0) {
+ /* Some BIOSen give you wrong codec addresses
+ * that don't exist
+ */
+ dev_warn(chip->card->dev,
+ "Codec #%d probe error; disabling it...\n", c);
+ chip->codec_mask &= ~(1 << c);
+ /* More badly, accessing to a non-existing
+ * codec often screws up the controller chip,
+ * and disturbs the further communications.
+ * Thus if an error occurs during probing,
+ * better to reset the controller chip to
+ * get back to the sanity state.
+ */
+ azx_stop_chip(chip);
+ azx_init_chip(chip, 1);
+ }
+ }
+ }
+
+ /* AMD chipsets often cause the communication stalls upon certain
+ * sequence like the pin-detection. It seems that forcing the synced
+ * access works around the stall. Grrr...
+ */
+ if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
+ dev_dbg(chip->card->dev, "Enable sync_write for stable communication\n");
+ chip->bus->sync_write = 1;
+ chip->bus->allow_bus_reset = 1;
+ }
+
+ /* Then create codec instances */
+ for (c = 0; c < max_slots; c++) {
+ if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
+ struct hda_codec *codec;
+ err = snd_hda_codec_new(chip->bus, c, &codec);
+ if (err < 0)
+ continue;
+ codec->jackpoll_interval = get_jackpoll_interval(chip);
+ codec->beep_mode = chip->beep_mode;
+ codecs++;
+ }
+ }
+ if (!codecs) {
+ dev_err(chip->card->dev, "no codecs initialized\n");
+ return -ENXIO;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(azx_codec_create);
+
+/* configure each codec instance */
+int azx_codec_configure(struct azx *chip)
+{
+ struct hda_codec *codec;
+ list_for_each_entry(codec, &chip->bus->codec_list, list) {
+ snd_hda_codec_configure(codec);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(azx_codec_configure);
+
+/* mixer creation - all stuff is implemented in hda module */
+int azx_mixer_create(struct azx *chip)
+{
+ return snd_hda_build_controls(chip->bus);
+}
+EXPORT_SYMBOL_GPL(azx_mixer_create);
+
+
+/* initialize SD streams */
+int azx_init_stream(struct azx *chip)
+{
+ int i;
+
+ /* initialize each stream (aka device)
+ * assign the starting bdl address to each stream (device)
+ * and initialize
+ */
+ for (i = 0; i < chip->num_streams; i++) {
+ struct azx_dev *azx_dev = &chip->azx_dev[i];
+ azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
+ /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
+ /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
+ azx_dev->sd_int_sta_mask = 1 << i;
+ /* stream tag: must be non-zero and unique */
+ azx_dev->index = i;
+ azx_dev->stream_tag = i + 1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(azx_init_stream);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Common HDA driver funcitons");
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
new file mode 100644
index 000000000000..1d2e3be2bae6
--- /dev/null
+++ b/sound/pci/hda/hda_controller.h
@@ -0,0 +1,53 @@
+/*
+ * Common functionality for the alsa driver code base for HD Audio.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __SOUND_HDA_CONTROLLER_H
+#define __SOUND_HDA_CONTROLLER_H
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include "hda_codec.h"
+#include "hda_priv.h"
+
+/* PCM setup */
+static inline struct azx_dev *get_azx_dev(struct snd_pcm_substream *substream)
+{
+ return substream->runtime->private_data;
+}
+unsigned int azx_get_position(struct azx *chip,
+ struct azx_dev *azx_dev,
+ bool with_check);
+
+/* Stream control. */
+void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev);
+
+/* Allocation functions. */
+int azx_alloc_stream_pages(struct azx *chip);
+void azx_free_stream_pages(struct azx *chip);
+
+/* Low level azx interface */
+void azx_init_chip(struct azx *chip, int full_reset);
+void azx_stop_chip(struct azx *chip);
+void azx_enter_link_reset(struct azx *chip);
+irqreturn_t azx_interrupt(int irq, void *dev_id);
+
+/* Codec interface */
+int azx_codec_create(struct azx *chip, const char *model,
+ unsigned int max_slots,
+ int *power_save_to);
+int azx_codec_configure(struct azx *chip);
+int azx_mixer_create(struct azx *chip);
+int azx_init_stream(struct azx *chip);
+
+#endif /* __SOUND_HDA_CONTROLLER_H */
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index 79ca80f6c77a..46690a7f48f6 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -153,7 +153,7 @@ static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid,
val = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_HDMI_ELDD, byte_index);
#ifdef BE_PARANOID
- printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
+ codec_info(codec, "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
#endif
return val;
}
@@ -332,11 +332,11 @@ int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
size = snd_hdmi_get_eld_size(codec, nid);
if (size == 0) {
/* wfg: workaround for ASUS P5E-VM HDMI board */
- snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n");
+ codec_info(codec, "HDMI: ELD buf size is 0, force 128\n");
size = 128;
}
if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
- snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size);
+ codec_info(codec, "HDMI: invalid ELD buf size %d\n", size);
return -ERANGE;
}
@@ -348,8 +348,7 @@ int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
* Just abort. The caller will repoll after a while.
*/
if (!(val & AC_ELDD_ELD_VALID)) {
- snd_printd(KERN_INFO
- "HDMI: invalid ELD data byte %d\n", i);
+ codec_info(codec, "HDMI: invalid ELD data byte %d\n", i);
ret = -EINVAL;
goto error;
}
@@ -361,7 +360,7 @@ int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
* correctly writes ELD content before setting ELD_valid bit.
*/
if (!val && !i) {
- snd_printdd(KERN_INFO "HDMI: 0 ELD data\n");
+ codec_dbg(codec, "HDMI: 0 ELD data\n");
ret = -EINVAL;
goto error;
}
@@ -681,7 +680,7 @@ int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0);
if (spkalloc <= 0) {
- snd_printd(KERN_INFO "HDMI ATI/AMD: no speaker allocation for ELD\n");
+ codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n");
return -EINVAL;
}
@@ -722,7 +721,7 @@ int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
if (sink_desc_len > ELD_MAX_MNL) {
- snd_printd(KERN_INFO "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n",
+ codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n",
sink_desc_len);
sink_desc_len = ELD_MAX_MNL;
}
@@ -764,7 +763,7 @@ int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
}
if (pos == ELD_FIXED_BYTES + sink_desc_len) {
- snd_printd(KERN_INFO "HDMI ATI/AMD: no audio descriptors for ELD\n");
+ codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n");
return -EINVAL;
}
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index d9a09bdd09db..16133881e967 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -79,7 +79,7 @@ static void free_kctls(struct hda_gen_spec *spec)
snd_array_free(&spec->kctls);
}
-void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
+static void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
{
if (!spec)
return;
@@ -87,7 +87,6 @@ void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
snd_array_free(&spec->paths);
snd_array_free(&spec->loopback_list);
}
-EXPORT_SYMBOL_GPL(snd_hda_gen_spec_free);
/*
* store user hints
@@ -347,7 +346,8 @@ static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid,
return is_ctl_used(codec, val, type);
}
-static void print_nid_path(const char *pfx, struct nid_path *path)
+static void print_nid_path(struct hda_codec *codec,
+ const char *pfx, struct nid_path *path)
{
char buf[40];
int i;
@@ -359,7 +359,7 @@ static void print_nid_path(const char *pfx, struct nid_path *path)
sprintf(tmp, ":%02x", path->path[i]);
strlcat(buf, tmp, sizeof(buf));
}
- snd_printdd("%s path: depth=%d %s\n", pfx, path->depth, buf);
+ codec_dbg(codec, "%s path: depth=%d %s\n", pfx, path->depth, buf);
}
/* called recursively */
@@ -762,7 +762,7 @@ void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
AC_PWRST_D0);
}
if (enable && path->multi[i])
- snd_hda_codec_write_cache(codec, nid, 0,
+ snd_hda_codec_update_cache(codec, nid, 0,
AC_VERB_SET_CONNECT_SEL,
path->idx[i]);
if (has_amp_in(codec, path, i))
@@ -1261,7 +1261,7 @@ static int try_assign_dacs(struct hda_codec *codec, int num_outs,
dac = dacs[i] = 0;
badness += bad->no_dac;
} else {
- /* print_nid_path("output", path); */
+ /* print_nid_path(codec, "output", path); */
path->active = true;
path_idx[i] = snd_hda_get_path_idx(codec, path);
badness += assign_out_path_ctls(codec, path);
@@ -1388,7 +1388,7 @@ static int fill_multi_ios(struct hda_codec *codec,
badness++;
continue;
}
- /* print_nid_path("multiio", path); */
+ /* print_nid_path(codec, "multiio", path); */
spec->multi_io[spec->multi_ios].pin = nid;
spec->multi_io[spec->multi_ios].dac = dac;
spec->out_paths[cfg->line_outs + spec->multi_ios] =
@@ -1445,7 +1445,7 @@ static bool map_singles(struct hda_codec *codec, int outs,
if (path) {
dacs[i] = dac;
found = true;
- /* print_nid_path("output", path); */
+ /* print_nid_path(codec, "output", path); */
path->active = true;
path_idx[i] = snd_hda_get_path_idx(codec, path);
}
@@ -1483,7 +1483,7 @@ static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
}
if (!path)
return 0;
- /* print_nid_path("output-aamix", path); */
+ /* print_nid_path(codec, "output-aamix", path); */
path->active = false; /* unused as default */
return snd_hda_get_path_idx(codec, path);
}
@@ -1700,7 +1700,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
#define DEBUG_BADNESS
#ifdef DEBUG_BADNESS
-#define debug_badness snd_printdd
+#define debug_badness(fmt, args...) codec_dbg(codec, fmt, ##args)
#else
#define debug_badness(...)
#endif
@@ -1713,7 +1713,7 @@ static inline void print_nid_path_idx(struct hda_codec *codec,
path = snd_hda_get_path_from_idx(codec, idx);
if (path)
- print_nid_path(pfx, path);
+ print_nid_path(codec, pfx, path);
}
static void debug_show_configs(struct hda_codec *codec,
@@ -1781,7 +1781,7 @@ static void fill_all_dac_nids(struct hda_codec *codec)
if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT)
continue;
if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) {
- snd_printk(KERN_ERR "hda: Too many DACs!\n");
+ codec_err(codec, "Too many DACs!\n");
break;
}
spec->all_dacs[spec->num_all_dacs++] = nid;
@@ -2430,7 +2430,7 @@ static int create_hp_mic(struct hda_codec *codec)
spec->hp_mic_pin = nid;
/* we can't handle auto-mic together with HP-mic */
spec->suppress_auto_mic = 1;
- snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid);
+ codec_dbg(codec, "Enable shared I/O jack on NID 0x%x\n", nid);
return 0;
}
@@ -2884,7 +2884,7 @@ static int new_analog_input(struct hda_codec *codec, int input_idx,
path = snd_hda_add_new_path(codec, pin, mix_nid, 0);
if (!path)
return -EINVAL;
- print_nid_path("loopback", path);
+ print_nid_path(codec, "loopback", path);
spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path);
idx = path->idx[path->depth - 1];
@@ -2912,7 +2912,7 @@ static int new_analog_input(struct hda_codec *codec, int input_idx,
path = snd_hda_add_new_path(codec, spec->mixer_nid,
spec->mixer_merge_nid, 0);
if (path) {
- print_nid_path("loopback-merge", path);
+ print_nid_path(codec, "loopback-merge", path);
path->active = true;
spec->loopback_merge_path =
snd_hda_get_path_idx(codec, path);
@@ -2991,7 +2991,7 @@ static int check_dyn_adc_switch(struct hda_codec *codec)
}
}
- snd_printdd("hda-codec: enabling ADC switching\n");
+ codec_dbg(codec, "enabling ADC switching\n");
spec->dyn_adc_switch = 1;
} else if (nums != spec->num_adc_nids) {
/* shrink the invalid adcs and input paths */
@@ -3015,7 +3015,7 @@ static int check_dyn_adc_switch(struct hda_codec *codec)
if (imux->num_items == 1 ||
(imux->num_items == 2 && spec->hp_mic)) {
- snd_printdd("hda-codec: reducing to a single ADC\n");
+ codec_dbg(codec, "reducing to a single ADC\n");
spec->num_adc_nids = 1; /* reduce to a single ADC */
}
@@ -3046,7 +3046,7 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
path = snd_hda_add_new_path(codec, pin, adc, anchor);
if (!path)
continue;
- print_nid_path("input", path);
+ print_nid_path(codec, "input", path);
spec->input_paths[imux_idx][c] =
snd_hda_get_path_idx(codec, path);
@@ -3712,7 +3712,7 @@ static void parse_digital(struct hda_codec *codec)
path = snd_hda_add_new_path(codec, dig_nid, pin, 0);
if (!path)
continue;
- print_nid_path("digout", path);
+ print_nid_path(codec, "digout", path);
path->active = true;
spec->digout_paths[i] = snd_hda_get_path_idx(codec, path);
set_pin_target(codec, pin, PIN_OUT, false);
@@ -3739,7 +3739,7 @@ static void parse_digital(struct hda_codec *codec)
continue;
path = snd_hda_add_new_path(codec, pin, dig_nid, 0);
if (path) {
- print_nid_path("digin", path);
+ print_nid_path(codec, "digin", path);
path->active = true;
spec->dig_in_nid = dig_nid;
spec->digin_path = snd_hda_get_path_idx(codec, path);
@@ -4170,8 +4170,7 @@ static int check_auto_mute_availability(struct hda_codec *codec)
hda_nid_t nid = cfg->hp_pins[i];
if (!is_jack_detectable(codec, nid))
continue;
- snd_printdd("hda-codec: Enable HP auto-muting on NID 0x%x\n",
- nid);
+ codec_dbg(codec, "Enable HP auto-muting on NID 0x%x\n", nid);
snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT,
call_hp_automute);
spec->detect_hp = 1;
@@ -4183,7 +4182,7 @@ static int check_auto_mute_availability(struct hda_codec *codec)
hda_nid_t nid = cfg->line_out_pins[i];
if (!is_jack_detectable(codec, nid))
continue;
- snd_printdd("hda-codec: Enable Line-Out auto-muting on NID 0x%x\n", nid);
+ codec_dbg(codec, "Enable Line-Out auto-muting on NID 0x%x\n", nid);
snd_hda_jack_detect_enable_callback(codec, nid,
HDA_GEN_FRONT_EVENT,
call_line_automute);
@@ -4303,7 +4302,7 @@ static int check_auto_mic_availability(struct hda_codec *codec)
spec->auto_mic = 1;
spec->num_adc_nids = 1;
spec->cur_mux[0] = spec->am_entry[0].idx;
- snd_printdd("hda-codec: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
+ codec_dbg(codec, "Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
spec->am_entry[0].pin,
spec->am_entry[1].pin,
spec->am_entry[2].pin);
@@ -5350,7 +5349,7 @@ EXPORT_SYMBOL_GPL(snd_hda_gen_init);
*/
void snd_hda_gen_free(struct hda_codec *codec)
{
- snd_hda_detach_beep_device(codec);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
snd_hda_gen_spec_free(codec->spec);
kfree(codec->spec);
codec->spec = NULL;
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index c908afbe4d94..bb2dea743986 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -297,7 +297,6 @@ struct hda_gen_spec {
};
int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
-void snd_hda_gen_spec_free(struct hda_gen_spec *spec);
int snd_hda_gen_init(struct hda_codec *codec);
void snd_hda_gen_free(struct hda_codec *codec);
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 72d8389fb399..014a7849e8fd 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -20,24 +20,13 @@
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/compat.h>
-#include <linux/mutex.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/export.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
#include <sound/hda_hwdep.h>
#include <sound/minors.h>
-/* hint string pair */
-struct hda_hint {
- const char *key;
- const char *val; /* contained in the same alloc as key */
-};
-
/*
* write/read an out-of-bound verb
*/
@@ -105,26 +94,6 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
return 0;
}
-static void clear_hwdep_elements(struct hda_codec *codec)
-{
- int i;
-
- /* clear init verbs */
- snd_array_free(&codec->init_verbs);
- /* clear hints */
- for (i = 0; i < codec->hints.used; i++) {
- struct hda_hint *hint = snd_array_elem(&codec->hints, i);
- kfree(hint->key); /* we don't need to free hint->val */
- }
- snd_array_free(&codec->hints);
- snd_array_free(&codec->user_pins);
-}
-
-static void hwdep_free(struct snd_hwdep *hwdep)
-{
- clear_hwdep_elements(hwdep->private_data);
-}
-
int snd_hda_create_hwdep(struct hda_codec *codec)
{
char hwname[16];
@@ -139,8 +108,8 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
sprintf(hwdep->name, "HDA Codec %d", codec->addr);
hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
hwdep->private_data = codec;
- hwdep->private_free = hwdep_free;
hwdep->exclusive = 1;
+ hwdep->groups = snd_hda_dev_attr_groups;
hwdep->ops.open = hda_hwdep_open;
hwdep->ops.ioctl = hda_hwdep_ioctl;
@@ -148,740 +117,8 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
#endif
- mutex_init(&codec->user_mutex);
- snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
- snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
- snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static ssize_t power_on_acct_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
- struct hda_codec *codec = hwdep->private_data;
- snd_hda_update_power_acct(codec);
- return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
-}
-
-static ssize_t power_off_acct_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
- struct hda_codec *codec = hwdep->private_data;
- snd_hda_update_power_acct(codec);
- return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
-}
-
-static struct device_attribute power_attrs[] = {
- __ATTR_RO(power_on_acct),
- __ATTR_RO(power_off_acct),
-};
-
-int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
-{
- struct snd_hwdep *hwdep = codec->hwdep;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(power_attrs); i++)
- snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
- hwdep->device, &power_attrs[i]);
- return 0;
-}
-#endif /* CONFIG_PM */
-
-#ifdef CONFIG_SND_HDA_RECONFIG
-
-/*
- * sysfs interface
- */
-
-static int clear_codec(struct hda_codec *codec)
-{
- int err;
-
- err = snd_hda_codec_reset(codec);
- if (err < 0) {
- snd_printk(KERN_ERR "The codec is being used, can't free.\n");
- return err;
- }
- clear_hwdep_elements(codec);
- return 0;
-}
-
-static int reconfig_codec(struct hda_codec *codec)
-{
- int err;
-
- snd_hda_power_up(codec);
- snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
- err = snd_hda_codec_reset(codec);
- if (err < 0) {
- snd_printk(KERN_ERR
- "The codec is being used, can't reconfigure.\n");
- goto error;
- }
- err = snd_hda_codec_configure(codec);
- if (err < 0)
- goto error;
- /* rebuild PCMs */
- err = snd_hda_codec_build_pcms(codec);
- if (err < 0)
- goto error;
- /* rebuild mixers */
- err = snd_hda_codec_build_controls(codec);
- if (err < 0)
- goto error;
- err = snd_card_register(codec->bus->card);
- error:
- snd_hda_power_down(codec);
- return err;
-}
-
-/*
- * allocate a string at most len chars, and remove the trailing EOL
- */
-static char *kstrndup_noeol(const char *src, size_t len)
-{
- char *s = kstrndup(src, len, GFP_KERNEL);
- char *p;
- if (!s)
- return NULL;
- p = strchr(s, '\n');
- if (p)
- *p = 0;
- return s;
-}
-
-#define CODEC_INFO_SHOW(type) \
-static ssize_t type##_show(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
- struct hda_codec *codec = hwdep->private_data; \
- return sprintf(buf, "0x%x\n", codec->type); \
-}
-
-#define CODEC_INFO_STR_SHOW(type) \
-static ssize_t type##_show(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
- struct hda_codec *codec = hwdep->private_data; \
- return sprintf(buf, "%s\n", \
- codec->type ? codec->type : ""); \
-}
-
-CODEC_INFO_SHOW(vendor_id);
-CODEC_INFO_SHOW(subsystem_id);
-CODEC_INFO_SHOW(revision_id);
-CODEC_INFO_SHOW(afg);
-CODEC_INFO_SHOW(mfg);
-CODEC_INFO_STR_SHOW(vendor_name);
-CODEC_INFO_STR_SHOW(chip_name);
-CODEC_INFO_STR_SHOW(modelname);
-
-#define CODEC_INFO_STORE(type) \
-static ssize_t type##_store(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
- struct hda_codec *codec = hwdep->private_data; \
- unsigned long val; \
- int err = kstrtoul(buf, 0, &val); \
- if (err < 0) \
- return err; \
- codec->type = val; \
- return count; \
-}
-
-#define CODEC_INFO_STR_STORE(type) \
-static ssize_t type##_store(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
- struct hda_codec *codec = hwdep->private_data; \
- char *s = kstrndup_noeol(buf, 64); \
- if (!s) \
- return -ENOMEM; \
- kfree(codec->type); \
- codec->type = s; \
- return count; \
-}
-
-CODEC_INFO_STORE(vendor_id);
-CODEC_INFO_STORE(subsystem_id);
-CODEC_INFO_STORE(revision_id);
-CODEC_INFO_STR_STORE(vendor_name);
-CODEC_INFO_STR_STORE(chip_name);
-CODEC_INFO_STR_STORE(modelname);
-
-#define CODEC_ACTION_STORE(type) \
-static ssize_t type##_store(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
- struct hda_codec *codec = hwdep->private_data; \
- int err = 0; \
- if (*buf) \
- err = type##_codec(codec); \
- return err < 0 ? err : count; \
-}
-
-CODEC_ACTION_STORE(reconfig);
-CODEC_ACTION_STORE(clear);
-
-static ssize_t init_verbs_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
- struct hda_codec *codec = hwdep->private_data;
- int i, len = 0;
- mutex_lock(&codec->user_mutex);
- for (i = 0; i < codec->init_verbs.used; i++) {
- struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
- len += snprintf(buf + len, PAGE_SIZE - len,
- "0x%02x 0x%03x 0x%04x\n",
- v->nid, v->verb, v->param);
- }
- mutex_unlock(&codec->user_mutex);
- return len;
-}
-
-static int parse_init_verbs(struct hda_codec *codec, const char *buf)
-{
- struct hda_verb *v;
- int nid, verb, param;
-
- if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
- return -EINVAL;
- if (!nid || !verb)
- return -EINVAL;
- mutex_lock(&codec->user_mutex);
- v = snd_array_new(&codec->init_verbs);
- if (!v) {
- mutex_unlock(&codec->user_mutex);
- return -ENOMEM;
- }
- v->nid = nid;
- v->verb = verb;
- v->param = param;
- mutex_unlock(&codec->user_mutex);
- return 0;
-}
-
-static ssize_t init_verbs_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
- struct hda_codec *codec = hwdep->private_data;
- int err = parse_init_verbs(codec, buf);
- if (err < 0)
- return err;
- return count;
-}
-
-static ssize_t hints_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
- struct hda_codec *codec = hwdep->private_data;
- int i, len = 0;
- mutex_lock(&codec->user_mutex);
- for (i = 0; i < codec->hints.used; i++) {
- struct hda_hint *hint = snd_array_elem(&codec->hints, i);
- len += snprintf(buf + len, PAGE_SIZE - len,
- "%s = %s\n", hint->key, hint->val);
- }
- mutex_unlock(&codec->user_mutex);
- return len;
-}
-
-static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
-{
- int i;
-
- for (i = 0; i < codec->hints.used; i++) {
- struct hda_hint *hint = snd_array_elem(&codec->hints, i);
- if (!strcmp(hint->key, key))
- return hint;
- }
- return NULL;
-}
-
-static void remove_trail_spaces(char *str)
-{
- char *p;
- if (!*str)
- return;
- p = str + strlen(str) - 1;
- for (; isspace(*p); p--) {
- *p = 0;
- if (p == str)
- return;
- }
-}
-
-#define MAX_HINTS 1024
-
-static int parse_hints(struct hda_codec *codec, const char *buf)
-{
- char *key, *val;
- struct hda_hint *hint;
- int err = 0;
-
- buf = skip_spaces(buf);
- if (!*buf || *buf == '#' || *buf == '\n')
- return 0;
- if (*buf == '=')
- return -EINVAL;
- key = kstrndup_noeol(buf, 1024);
- if (!key)
- return -ENOMEM;
- /* extract key and val */
- val = strchr(key, '=');
- if (!val) {
- kfree(key);
- return -EINVAL;
- }
- *val++ = 0;
- val = skip_spaces(val);
- remove_trail_spaces(key);
- remove_trail_spaces(val);
- mutex_lock(&codec->user_mutex);
- hint = get_hint(codec, key);
- if (hint) {
- /* replace */
- kfree(hint->key);
- hint->key = key;
- hint->val = val;
- goto unlock;
- }
- /* allocate a new hint entry */
- if (codec->hints.used >= MAX_HINTS)
- hint = NULL;
- else
- hint = snd_array_new(&codec->hints);
- if (hint) {
- hint->key = key;
- hint->val = val;
- } else {
- err = -ENOMEM;
- }
- unlock:
- mutex_unlock(&codec->user_mutex);
- if (err)
- kfree(key);
- return err;
-}
-
-static ssize_t hints_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
- struct hda_codec *codec = hwdep->private_data;
- int err = parse_hints(codec, buf);
- if (err < 0)
- return err;
- return count;
-}
-
-static ssize_t pin_configs_show(struct hda_codec *codec,
- struct snd_array *list,
- char *buf)
-{
- int i, len = 0;
- mutex_lock(&codec->user_mutex);
- for (i = 0; i < list->used; i++) {
- struct hda_pincfg *pin = snd_array_elem(list, i);
- len += sprintf(buf + len, "0x%02x 0x%08x\n",
- pin->nid, pin->cfg);
- }
- mutex_unlock(&codec->user_mutex);
- return len;
-}
-
-static ssize_t init_pin_configs_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
- struct hda_codec *codec = hwdep->private_data;
- return pin_configs_show(codec, &codec->init_pins, buf);
-}
-
-static ssize_t user_pin_configs_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
- struct hda_codec *codec = hwdep->private_data;
- return pin_configs_show(codec, &codec->user_pins, buf);
-}
-
-static ssize_t driver_pin_configs_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
- struct hda_codec *codec = hwdep->private_data;
- return pin_configs_show(codec, &codec->driver_pins, buf);
-}
-
-#define MAX_PIN_CONFIGS 32
-
-static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
-{
- int nid, cfg, err;
-
- if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
- return -EINVAL;
- if (!nid)
- return -EINVAL;
- mutex_lock(&codec->user_mutex);
- err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
- mutex_unlock(&codec->user_mutex);
- return err;
-}
-
-static ssize_t user_pin_configs_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct snd_hwdep *hwdep = dev_get_drvdata(dev);
- struct hda_codec *codec = hwdep->private_data;
- int err = parse_user_pin_configs(codec, buf);
- if (err < 0)
- return err;
- return count;
-}
-
-#define CODEC_ATTR_RW(type) \
- __ATTR(type, 0644, type##_show, type##_store)
-#define CODEC_ATTR_RO(type) \
- __ATTR_RO(type)
-#define CODEC_ATTR_WO(type) \
- __ATTR(type, 0200, NULL, type##_store)
-
-static struct device_attribute codec_attrs[] = {
- CODEC_ATTR_RW(vendor_id),
- CODEC_ATTR_RW(subsystem_id),
- CODEC_ATTR_RW(revision_id),
- CODEC_ATTR_RO(afg),
- CODEC_ATTR_RO(mfg),
- CODEC_ATTR_RW(vendor_name),
- CODEC_ATTR_RW(chip_name),
- CODEC_ATTR_RW(modelname),
- CODEC_ATTR_RW(init_verbs),
- CODEC_ATTR_RW(hints),
- CODEC_ATTR_RO(init_pin_configs),
- CODEC_ATTR_RW(user_pin_configs),
- CODEC_ATTR_RO(driver_pin_configs),
- CODEC_ATTR_WO(reconfig),
- CODEC_ATTR_WO(clear),
-};
-
-/*
- * create sysfs files on hwdep directory
- */
-int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
-{
- struct snd_hwdep *hwdep = codec->hwdep;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(codec_attrs); i++)
- snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
- hwdep->device, &codec_attrs[i]);
- return 0;
-}
-
-/*
- * Look for hint string
- */
-const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
-{
- struct hda_hint *hint = get_hint(codec, key);
- return hint ? hint->val : NULL;
-}
-EXPORT_SYMBOL_GPL(snd_hda_get_hint);
-
-int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
-{
- const char *p;
- int ret;
-
- mutex_lock(&codec->user_mutex);
- p = snd_hda_get_hint(codec, key);
- if (!p || !*p)
- ret = -ENOENT;
- else {
- switch (toupper(*p)) {
- case 'T': /* true */
- case 'Y': /* yes */
- case '1':
- ret = 1;
- break;
- default:
- ret = 0;
- break;
- }
- }
- mutex_unlock(&codec->user_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
-
-int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
-{
- const char *p;
- unsigned long val;
- int ret;
-
- mutex_lock(&codec->user_mutex);
- p = snd_hda_get_hint(codec, key);
- if (!p)
- ret = -ENOENT;
- else if (kstrtoul(p, 0, &val))
- ret = -EINVAL;
- else {
- *valp = val;
- ret = 0;
- }
- mutex_unlock(&codec->user_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
-#endif /* CONFIG_SND_HDA_RECONFIG */
-
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
+ /* link to codec */
+ hwdep->dev = &codec->dev;
-/* parser mode */
-enum {
- LINE_MODE_NONE,
- LINE_MODE_CODEC,
- LINE_MODE_MODEL,
- LINE_MODE_PINCFG,
- LINE_MODE_VERB,
- LINE_MODE_HINT,
- LINE_MODE_VENDOR_ID,
- LINE_MODE_SUBSYSTEM_ID,
- LINE_MODE_REVISION_ID,
- LINE_MODE_CHIP_NAME,
- NUM_LINE_MODES,
-};
-
-static inline int strmatch(const char *a, const char *b)
-{
- return strnicmp(a, b, strlen(b)) == 0;
-}
-
-/* parse the contents after the line "[codec]"
- * accept only the line with three numbers, and assign the current codec
- */
-static void parse_codec_mode(char *buf, struct hda_bus *bus,
- struct hda_codec **codecp)
-{
- int vendorid, subid, caddr;
- struct hda_codec *codec;
-
- *codecp = NULL;
- if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
- list_for_each_entry(codec, &bus->codec_list, list) {
- if ((vendorid <= 0 || codec->vendor_id == vendorid) &&
- (subid <= 0 || codec->subsystem_id == subid) &&
- codec->addr == caddr) {
- *codecp = codec;
- break;
- }
- }
- }
-}
-
-/* parse the contents after the other command tags, [pincfg], [verb],
- * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
- * just pass to the sysfs helper (only when any codec was specified)
- */
-static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
- struct hda_codec **codecp)
-{
- parse_user_pin_configs(*codecp, buf);
-}
-
-static void parse_verb_mode(char *buf, struct hda_bus *bus,
- struct hda_codec **codecp)
-{
- parse_init_verbs(*codecp, buf);
-}
-
-static void parse_hint_mode(char *buf, struct hda_bus *bus,
- struct hda_codec **codecp)
-{
- parse_hints(*codecp, buf);
-}
-
-static void parse_model_mode(char *buf, struct hda_bus *bus,
- struct hda_codec **codecp)
-{
- kfree((*codecp)->modelname);
- (*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
-}
-
-static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
- struct hda_codec **codecp)
-{
- kfree((*codecp)->chip_name);
- (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
-}
-
-#define DEFINE_PARSE_ID_MODE(name) \
-static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
- struct hda_codec **codecp) \
-{ \
- unsigned long val; \
- if (!kstrtoul(buf, 0, &val)) \
- (*codecp)->name = val; \
-}
-
-DEFINE_PARSE_ID_MODE(vendor_id);
-DEFINE_PARSE_ID_MODE(subsystem_id);
-DEFINE_PARSE_ID_MODE(revision_id);
-
-
-struct hda_patch_item {
- const char *tag;
- const char *alias;
- void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
-};
-
-static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
- [LINE_MODE_CODEC] = {
- .tag = "[codec]",
- .parser = parse_codec_mode,
- },
- [LINE_MODE_MODEL] = {
- .tag = "[model]",
- .parser = parse_model_mode,
- },
- [LINE_MODE_VERB] = {
- .tag = "[verb]",
- .alias = "[init_verbs]",
- .parser = parse_verb_mode,
- },
- [LINE_MODE_PINCFG] = {
- .tag = "[pincfg]",
- .alias = "[user_pin_configs]",
- .parser = parse_pincfg_mode,
- },
- [LINE_MODE_HINT] = {
- .tag = "[hint]",
- .alias = "[hints]",
- .parser = parse_hint_mode
- },
- [LINE_MODE_VENDOR_ID] = {
- .tag = "[vendor_id]",
- .parser = parse_vendor_id_mode,
- },
- [LINE_MODE_SUBSYSTEM_ID] = {
- .tag = "[subsystem_id]",
- .parser = parse_subsystem_id_mode,
- },
- [LINE_MODE_REVISION_ID] = {
- .tag = "[revision_id]",
- .parser = parse_revision_id_mode,
- },
- [LINE_MODE_CHIP_NAME] = {
- .tag = "[chip_name]",
- .parser = parse_chip_name_mode,
- },
-};
-
-/* check the line starting with '[' -- change the parser mode accodingly */
-static int parse_line_mode(char *buf, struct hda_bus *bus)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
- if (!patch_items[i].tag)
- continue;
- if (strmatch(buf, patch_items[i].tag))
- return i;
- if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
- return i;
- }
- return LINE_MODE_NONE;
-}
-
-/* copy one line from the buffer in fw, and update the fields in fw
- * return zero if it reaches to the end of the buffer, or non-zero
- * if successfully copied a line
- *
- * the spaces at the beginning and the end of the line are stripped
- */
-static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
- const void **fw_data_p)
-{
- int len;
- size_t fw_size = *fw_size_p;
- const char *p = *fw_data_p;
-
- while (isspace(*p) && fw_size) {
- p++;
- fw_size--;
- }
- if (!fw_size)
- return 0;
-
- for (len = 0; len < fw_size; len++) {
- if (!*p)
- break;
- if (*p == '\n') {
- p++;
- len++;
- break;
- }
- if (len < size)
- *buf++ = *p++;
- }
- *buf = 0;
- *fw_size_p = fw_size - len;
- *fw_data_p = p;
- remove_trail_spaces(buf);
- return 1;
-}
-
-/*
- * load a "patch" firmware file and parse it
- */
-int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
-{
- char buf[128];
- struct hda_codec *codec;
- int line_mode;
-
- line_mode = LINE_MODE_NONE;
- codec = NULL;
- while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
- if (!*buf || *buf == '#' || *buf == '\n')
- continue;
- if (*buf == '[')
- line_mode = parse_line_mode(buf, bus);
- else if (patch_items[line_mode].parser &&
- (codec || line_mode <= LINE_MODE_CODEC))
- patch_items[line_mode].parser(buf, bus, &codec);
- }
return 0;
}
-EXPORT_SYMBOL_GPL(snd_hda_load_patch);
-#endif /* CONFIG_SND_HDA_PATCH_LOADER */
diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c
index 76c13d5b3ca0..9d07e4edacdb 100644
--- a/sound/pci/hda/hda_i915.c
+++ b/sound/pci/hda/hda_i915.c
@@ -30,7 +30,7 @@ void hda_display_power(bool enable)
if (!get_power || !put_power)
return;
- snd_printdd("HDA display power %s \n",
+ pr_debug("HDA display power %s \n",
enable ? "Enable" : "Disable");
if (enable)
get_power();
@@ -44,7 +44,7 @@ int hda_i915_init(void)
get_power = symbol_request(i915_request_power_well);
if (!get_power) {
- snd_printk(KERN_WARNING "hda-i915: get_power symbol get fail\n");
+ pr_warn("hda-i915: get_power symbol get fail\n");
return -ENODEV;
}
@@ -55,7 +55,7 @@ int hda_i915_init(void)
return -ENODEV;
}
- snd_printd("HDA driver get symbol successfully from i915 module\n");
+ pr_debug("HDA driver get symbol successfully from i915 module\n");
return err;
}
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index e354ab1ec20f..77ca894f8284 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -63,6 +63,8 @@
#include <linux/firmware.h>
#include "hda_codec.h"
#include "hda_i915.h"
+#include "hda_controller.h"
+#include "hda_priv.h"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
@@ -127,6 +129,7 @@ static struct kernel_param_ops param_ops_xint = {
#define param_check_xint param_check_int
static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
+static int *power_save_addr = &power_save;
module_param(power_save, xint, 0644);
MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
"(in second, 0 = disable).");
@@ -138,6 +141,8 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
static bool power_save_controller = 1;
module_param(power_save_controller, bool, 0644);
MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
+#else
+static int *power_save_addr;
#endif /* CONFIG_PM */
static int align_buffer_size = -1;
@@ -149,10 +154,8 @@ MODULE_PARM_DESC(align_buffer_size,
static bool hda_snoop = true;
module_param_named(snoop, hda_snoop, bool, 0444);
MODULE_PARM_DESC(snoop, "Enable/disable snooping");
-#define azx_snoop(chip) (chip)->snoop
#else
#define hda_snoop true
-#define azx_snoop(chip) true
#endif
@@ -191,12 +194,6 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{ULI, M5461}}");
MODULE_DESCRIPTION("Intel HDA driver");
-#ifdef CONFIG_SND_VERBOSE_PRINTK
-#define SFX /* nop */
-#else
-#define SFX "hda-intel "
-#endif
-
#if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO)
#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
#define SUPPORT_VGA_SWITCHEROO
@@ -205,365 +202,8 @@ MODULE_DESCRIPTION("Intel HDA driver");
/*
- * registers
- */
-#define ICH6_REG_GCAP 0x00
-#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */
-#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */
-#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */
-#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */
-#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */
-#define ICH6_REG_VMIN 0x02
-#define ICH6_REG_VMAJ 0x03
-#define ICH6_REG_OUTPAY 0x04
-#define ICH6_REG_INPAY 0x06
-#define ICH6_REG_GCTL 0x08
-#define ICH6_GCTL_RESET (1 << 0) /* controller reset */
-#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */
-#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */
-#define ICH6_REG_WAKEEN 0x0c
-#define ICH6_REG_STATESTS 0x0e
-#define ICH6_REG_GSTS 0x10
-#define ICH6_GSTS_FSTS (1 << 1) /* flush status */
-#define ICH6_REG_INTCTL 0x20
-#define ICH6_REG_INTSTS 0x24
-#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */
-#define ICH6_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */
-#define ICH6_REG_SSYNC 0x38
-#define ICH6_REG_CORBLBASE 0x40
-#define ICH6_REG_CORBUBASE 0x44
-#define ICH6_REG_CORBWP 0x48
-#define ICH6_REG_CORBRP 0x4a
-#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */
-#define ICH6_REG_CORBCTL 0x4c
-#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */
-#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */
-#define ICH6_REG_CORBSTS 0x4d
-#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */
-#define ICH6_REG_CORBSIZE 0x4e
-
-#define ICH6_REG_RIRBLBASE 0x50
-#define ICH6_REG_RIRBUBASE 0x54
-#define ICH6_REG_RIRBWP 0x58
-#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */
-#define ICH6_REG_RINTCNT 0x5a
-#define ICH6_REG_RIRBCTL 0x5c
-#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */
-#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */
-#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */
-#define ICH6_REG_RIRBSTS 0x5d
-#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */
-#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */
-#define ICH6_REG_RIRBSIZE 0x5e
-
-#define ICH6_REG_IC 0x60
-#define ICH6_REG_IR 0x64
-#define ICH6_REG_IRS 0x68
-#define ICH6_IRS_VALID (1<<1)
-#define ICH6_IRS_BUSY (1<<0)
-
-#define ICH6_REG_DPLBASE 0x70
-#define ICH6_REG_DPUBASE 0x74
-#define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */
-
-/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
-enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
-
-/* stream register offsets from stream base */
-#define ICH6_REG_SD_CTL 0x00
-#define ICH6_REG_SD_STS 0x03
-#define ICH6_REG_SD_LPIB 0x04
-#define ICH6_REG_SD_CBL 0x08
-#define ICH6_REG_SD_LVI 0x0c
-#define ICH6_REG_SD_FIFOW 0x0e
-#define ICH6_REG_SD_FIFOSIZE 0x10
-#define ICH6_REG_SD_FORMAT 0x12
-#define ICH6_REG_SD_BDLPL 0x18
-#define ICH6_REG_SD_BDLPU 0x1c
-
-/* PCI space */
-#define ICH6_PCIREG_TCSEL 0x44
-
-/*
- * other constants
*/
-/* max number of SDs */
-/* ICH, ATI and VIA have 4 playback and 4 capture */
-#define ICH6_NUM_CAPTURE 4
-#define ICH6_NUM_PLAYBACK 4
-
-/* ULI has 6 playback and 5 capture */
-#define ULI_NUM_CAPTURE 5
-#define ULI_NUM_PLAYBACK 6
-
-/* ATI HDMI may have up to 8 playbacks and 0 capture */
-#define ATIHDMI_NUM_CAPTURE 0
-#define ATIHDMI_NUM_PLAYBACK 8
-
-/* TERA has 4 playback and 3 capture */
-#define TERA_NUM_CAPTURE 3
-#define TERA_NUM_PLAYBACK 4
-
-/* this number is statically defined for simplicity */
-#define MAX_AZX_DEV 16
-
-/* max number of fragments - we may use more if allocating more pages for BDL */
-#define BDL_SIZE 4096
-#define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16)
-#define AZX_MAX_FRAG 32
-/* max buffer size - no h/w limit, you can increase as you like */
-#define AZX_MAX_BUF_SIZE (1024*1024*1024)
-
-/* RIRB int mask: overrun[2], response[0] */
-#define RIRB_INT_RESPONSE 0x01
-#define RIRB_INT_OVERRUN 0x04
-#define RIRB_INT_MASK 0x05
-
-/* STATESTS int mask: S3,SD2,SD1,SD0 */
-#define AZX_MAX_CODECS 8
-#define AZX_DEFAULT_CODECS 4
-#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1)
-
-/* SD_CTL bits */
-#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
-#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */
-#define SD_CTL_STRIPE (3 << 16) /* stripe control */
-#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */
-#define SD_CTL_DIR (1 << 19) /* bi-directional stream */
-#define SD_CTL_STREAM_TAG_MASK (0xf << 20)
-#define SD_CTL_STREAM_TAG_SHIFT 20
-
-/* SD_CTL and SD_STS */
-#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */
-#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */
-#define SD_INT_COMPLETE 0x04 /* completion interrupt */
-#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
- SD_INT_COMPLETE)
-
-/* SD_STS */
-#define SD_STS_FIFO_READY 0x20 /* FIFO ready */
-
-/* INTCTL and INTSTS */
-#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */
-#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */
-#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */
-
-/* below are so far hardcoded - should read registers in future */
-#define ICH6_MAX_CORB_ENTRIES 256
-#define ICH6_MAX_RIRB_ENTRIES 256
-
-/* position fix mode */
-enum {
- POS_FIX_AUTO,
- POS_FIX_LPIB,
- POS_FIX_POSBUF,
- POS_FIX_VIACOMBO,
- POS_FIX_COMBO,
-};
-
-/* Defines for ATI HD Audio support in SB450 south bridge */
-#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42
-#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02
-
-/* Defines for Nvidia HDA support */
-#define NVIDIA_HDA_TRANSREG_ADDR 0x4e
-#define NVIDIA_HDA_ENABLE_COHBITS 0x0f
-#define NVIDIA_HDA_ISTRM_COH 0x4d
-#define NVIDIA_HDA_OSTRM_COH 0x4c
-#define NVIDIA_HDA_ENABLE_COHBIT 0x01
-
-/* Defines for Intel SCH HDA snoop control */
-#define INTEL_SCH_HDA_DEVC 0x78
-#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11)
-
-/* Define IN stream 0 FIFO size offset in VIA controller */
-#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90
-/* Define VIA HD Audio Device ID*/
-#define VIA_HDAC_DEVICE_ID 0x3288
-
-/* HD Audio class code */
-#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
-
-/*
- */
-
-struct azx_dev {
- struct snd_dma_buffer bdl; /* BDL buffer */
- u32 *posbuf; /* position buffer pointer */
-
- unsigned int bufsize; /* size of the play buffer in bytes */
- unsigned int period_bytes; /* size of the period in bytes */
- unsigned int frags; /* number for period in the play buffer */
- unsigned int fifo_size; /* FIFO size */
- unsigned long start_wallclk; /* start + minimum wallclk */
- unsigned long period_wallclk; /* wallclk for period */
-
- void __iomem *sd_addr; /* stream descriptor pointer */
-
- u32 sd_int_sta_mask; /* stream int status mask */
-
- /* pcm support */
- struct snd_pcm_substream *substream; /* assigned substream,
- * set in PCM open
- */
- unsigned int format_val; /* format value to be set in the
- * controller and the codec
- */
- unsigned char stream_tag; /* assigned stream */
- unsigned char index; /* stream index */
- int assigned_key; /* last device# key assigned to */
-
- unsigned int opened :1;
- unsigned int running :1;
- unsigned int irq_pending :1;
- unsigned int prepared:1;
- unsigned int locked:1;
- /*
- * For VIA:
- * A flag to ensure DMA position is 0
- * when link position is not greater than FIFO size
- */
- unsigned int insufficient :1;
- unsigned int wc_marked:1;
- unsigned int no_period_wakeup:1;
-
- struct timecounter azx_tc;
- struct cyclecounter azx_cc;
-
- int delay_negative_threshold;
-
-#ifdef CONFIG_SND_HDA_DSP_LOADER
- struct mutex dsp_mutex;
-#endif
-};
-
-/* DSP lock helpers */
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-#define dsp_lock_init(dev) mutex_init(&(dev)->dsp_mutex)
-#define dsp_lock(dev) mutex_lock(&(dev)->dsp_mutex)
-#define dsp_unlock(dev) mutex_unlock(&(dev)->dsp_mutex)
-#define dsp_is_locked(dev) ((dev)->locked)
-#else
-#define dsp_lock_init(dev) do {} while (0)
-#define dsp_lock(dev) do {} while (0)
-#define dsp_unlock(dev) do {} while (0)
-#define dsp_is_locked(dev) 0
-#endif
-
-/* CORB/RIRB */
-struct azx_rb {
- u32 *buf; /* CORB/RIRB buffer
- * Each CORB entry is 4byte, RIRB is 8byte
- */
- dma_addr_t addr; /* physical address of CORB/RIRB buffer */
- /* for RIRB */
- unsigned short rp, wp; /* read/write pointers */
- int cmds[AZX_MAX_CODECS]; /* number of pending requests */
- u32 res[AZX_MAX_CODECS]; /* last read value */
-};
-
-struct azx_pcm {
- struct azx *chip;
- struct snd_pcm *pcm;
- struct hda_codec *codec;
- struct hda_pcm_stream *hinfo[2];
- struct list_head list;
-};
-
-struct azx {
- struct snd_card *card;
- struct pci_dev *pci;
- int dev_index;
-
- /* chip type specific */
- int driver_type;
- unsigned int driver_caps;
- int playback_streams;
- int playback_index_offset;
- int capture_streams;
- int capture_index_offset;
- int num_streams;
-
- /* pci resources */
- unsigned long addr;
- void __iomem *remap_addr;
- int irq;
-
- /* locks */
- spinlock_t reg_lock;
- struct mutex open_mutex;
- struct completion probe_wait;
-
- /* streams (x num_streams) */
- struct azx_dev *azx_dev;
-
- /* PCM */
- struct list_head pcm_list; /* azx_pcm list */
-
- /* HD codec */
- unsigned short codec_mask;
- int codec_probe_mask; /* copied from probe_mask option */
- struct hda_bus *bus;
- unsigned int beep_mode;
-
- /* CORB/RIRB */
- struct azx_rb corb;
- struct azx_rb rirb;
-
- /* CORB/RIRB and position buffers */
- struct snd_dma_buffer rb;
- struct snd_dma_buffer posbuf;
-
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
- const struct firmware *fw;
-#endif
-
- /* flags */
- int position_fix[2]; /* for both playback/capture streams */
- int poll_count;
- unsigned int running :1;
- unsigned int initialized :1;
- unsigned int single_cmd :1;
- unsigned int polling_mode :1;
- unsigned int msi :1;
- unsigned int irq_pending_warned :1;
- unsigned int probing :1; /* codec probing phase */
- unsigned int snoop:1;
- unsigned int align_buffer_size:1;
- unsigned int region_requested:1;
-
- /* VGA-switcheroo setup */
- unsigned int use_vga_switcheroo:1;
- unsigned int vga_switcheroo_registered:1;
- unsigned int init_failed:1; /* delayed init failed */
- unsigned int disabled:1; /* disabled by VGA-switcher */
-
- /* for debugging */
- unsigned int last_cmd[AZX_MAX_CODECS];
-
- /* for pending irqs */
- struct work_struct irq_pending_work;
-
- struct work_struct probe_work;
-
- /* reboot notifier (for mysterious hangup problem at power-down) */
- struct notifier_block reboot_notifier;
-
- /* card list (for power_save trigger) */
- struct list_head list;
-
-#ifdef CONFIG_SND_HDA_DSP_LOADER
- struct azx_dev saved_azx_dev;
-#endif
-
- /* secondary power domain for hdmi audio under vga device */
- struct dev_pm_domain hdmi_pm_domain;
-};
-
-#define CREATE_TRACE_POINTS
-#include "hda_intel_trace.h"
-
/* driver types */
enum {
AZX_DRIVER_ICH,
@@ -584,28 +224,6 @@ enum {
AZX_NUM_DRIVERS, /* keep this as last entry */
};
-/* driver quirks (capabilities) */
-/* bits 0-7 are used for indicating driver type */
-#define AZX_DCAPS_NO_TCSEL (1 << 8) /* No Intel TCSEL bit */
-#define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */
-#define AZX_DCAPS_ATI_SNOOP (1 << 10) /* ATI snoop enable */
-#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11) /* Nvidia snoop enable */
-#define AZX_DCAPS_SCH_SNOOP (1 << 12) /* SCH/PCH snoop enable */
-#define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */
-#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */
-#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */
-#define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */
-#define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */
-#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */
-#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */
-#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */
-#define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */
-#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */
-#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */
-#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
-#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */
-#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 power well support */
-
/* quirks for Intel PCH */
#define AZX_DCAPS_INTEL_PCH_NOPM \
(AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \
@@ -663,38 +281,6 @@ static char *driver_short_names[] = {
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
};
-/*
- * macros for easy use
- */
-#define azx_writel(chip,reg,value) \
- writel(value, (chip)->remap_addr + ICH6_REG_##reg)
-#define azx_readl(chip,reg) \
- readl((chip)->remap_addr + ICH6_REG_##reg)
-#define azx_writew(chip,reg,value) \
- writew(value, (chip)->remap_addr + ICH6_REG_##reg)
-#define azx_readw(chip,reg) \
- readw((chip)->remap_addr + ICH6_REG_##reg)
-#define azx_writeb(chip,reg,value) \
- writeb(value, (chip)->remap_addr + ICH6_REG_##reg)
-#define azx_readb(chip,reg) \
- readb((chip)->remap_addr + ICH6_REG_##reg)
-
-#define azx_sd_writel(dev,reg,value) \
- writel(value, (dev)->sd_addr + ICH6_REG_##reg)
-#define azx_sd_readl(dev,reg) \
- readl((dev)->sd_addr + ICH6_REG_##reg)
-#define azx_sd_writew(dev,reg,value) \
- writew(value, (dev)->sd_addr + ICH6_REG_##reg)
-#define azx_sd_readw(dev,reg) \
- readw((dev)->sd_addr + ICH6_REG_##reg)
-#define azx_sd_writeb(dev,reg,value) \
- writeb(value, (dev)->sd_addr + ICH6_REG_##reg)
-#define azx_sd_readb(dev,reg) \
- readb((dev)->sd_addr + ICH6_REG_##reg)
-
-/* for pcm support */
-#define get_azx_dev(substream) (substream->runtime->private_data)
-
#ifdef CONFIG_X86
static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
{
@@ -749,578 +335,6 @@ static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
#endif
static int azx_acquire_irq(struct azx *chip, int do_disconnect);
-static int azx_send_cmd(struct hda_bus *bus, unsigned int val);
-/*
- * Interface for HD codec
- */
-
-/*
- * CORB / RIRB interface
- */
-static int azx_alloc_cmd_io(struct azx *chip)
-{
- int err;
-
- /* single page (at least 4096 bytes) must suffice for both ringbuffes */
- err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
- snd_dma_pci_data(chip->pci),
- PAGE_SIZE, &chip->rb);
- if (err < 0) {
- snd_printk(KERN_ERR SFX "%s: cannot allocate CORB/RIRB\n", pci_name(chip->pci));
- return err;
- }
- mark_pages_wc(chip, &chip->rb, true);
- return 0;
-}
-
-static void azx_init_cmd_io(struct azx *chip)
-{
- spin_lock_irq(&chip->reg_lock);
- /* CORB set up */
- chip->corb.addr = chip->rb.addr;
- chip->corb.buf = (u32 *)chip->rb.area;
- azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
- azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr));
-
- /* set the corb size to 256 entries (ULI requires explicitly) */
- azx_writeb(chip, CORBSIZE, 0x02);
- /* set the corb write pointer to 0 */
- azx_writew(chip, CORBWP, 0);
- /* reset the corb hw read pointer */
- azx_writew(chip, CORBRP, ICH6_CORBRP_RST);
- /* enable corb dma */
- azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN);
-
- /* RIRB set up */
- chip->rirb.addr = chip->rb.addr + 2048;
- chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
- chip->rirb.wp = chip->rirb.rp = 0;
- memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds));
- azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
- azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
-
- /* set the rirb size to 256 entries (ULI requires explicitly) */
- azx_writeb(chip, RIRBSIZE, 0x02);
- /* reset the rirb hw write pointer */
- azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
- /* set N=1, get RIRB response interrupt for new entry */
- if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
- azx_writew(chip, RINTCNT, 0xc0);
- else
- azx_writew(chip, RINTCNT, 1);
- /* enable rirb dma and response irq */
- azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
- spin_unlock_irq(&chip->reg_lock);
-}
-
-static void azx_free_cmd_io(struct azx *chip)
-{
- spin_lock_irq(&chip->reg_lock);
- /* disable ringbuffer DMAs */
- azx_writeb(chip, RIRBCTL, 0);
- azx_writeb(chip, CORBCTL, 0);
- spin_unlock_irq(&chip->reg_lock);
-}
-
-static unsigned int azx_command_addr(u32 cmd)
-{
- unsigned int addr = cmd >> 28;
-
- if (addr >= AZX_MAX_CODECS) {
- snd_BUG();
- addr = 0;
- }
-
- return addr;
-}
-
-static unsigned int azx_response_addr(u32 res)
-{
- unsigned int addr = res & 0xf;
-
- if (addr >= AZX_MAX_CODECS) {
- snd_BUG();
- addr = 0;
- }
-
- return addr;
-}
-
-/* send a command */
-static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
-{
- struct azx *chip = bus->private_data;
- unsigned int addr = azx_command_addr(val);
- unsigned int wp, rp;
-
- spin_lock_irq(&chip->reg_lock);
-
- /* add command to corb */
- wp = azx_readw(chip, CORBWP);
- if (wp == 0xffff) {
- /* something wrong, controller likely turned to D3 */
- spin_unlock_irq(&chip->reg_lock);
- return -EIO;
- }
- wp++;
- wp %= ICH6_MAX_CORB_ENTRIES;
-
- rp = azx_readw(chip, CORBRP);
- if (wp == rp) {
- /* oops, it's full */
- spin_unlock_irq(&chip->reg_lock);
- return -EAGAIN;
- }
-
- chip->rirb.cmds[addr]++;
- chip->corb.buf[wp] = cpu_to_le32(val);
- azx_writel(chip, CORBWP, wp);
-
- spin_unlock_irq(&chip->reg_lock);
-
- return 0;
-}
-
-#define ICH6_RIRB_EX_UNSOL_EV (1<<4)
-
-/* retrieve RIRB entry - called from interrupt handler */
-static void azx_update_rirb(struct azx *chip)
-{
- unsigned int rp, wp;
- unsigned int addr;
- u32 res, res_ex;
-
- wp = azx_readw(chip, RIRBWP);
- if (wp == 0xffff) {
- /* something wrong, controller likely turned to D3 */
- return;
- }
-
- if (wp == chip->rirb.wp)
- return;
- chip->rirb.wp = wp;
-
- while (chip->rirb.rp != wp) {
- chip->rirb.rp++;
- chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES;
-
- rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */
- res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
- res = le32_to_cpu(chip->rirb.buf[rp]);
- addr = azx_response_addr(res_ex);
- if (res_ex & ICH6_RIRB_EX_UNSOL_EV)
- snd_hda_queue_unsol_event(chip->bus, res, res_ex);
- else if (chip->rirb.cmds[addr]) {
- chip->rirb.res[addr] = res;
- smp_wmb();
- chip->rirb.cmds[addr]--;
- } else if (printk_ratelimit()) {
- snd_printk(KERN_ERR SFX "%s: spurious response %#x:%#x, last cmd=%#08x\n",
- pci_name(chip->pci),
- res, res_ex,
- chip->last_cmd[addr]);
- }
- }
-}
-
-/* receive a response */
-static unsigned int azx_rirb_get_response(struct hda_bus *bus,
- unsigned int addr)
-{
- struct azx *chip = bus->private_data;
- unsigned long timeout;
- unsigned long loopcounter;
- int do_poll = 0;
-
- again:
- timeout = jiffies + msecs_to_jiffies(1000);
-
- for (loopcounter = 0;; loopcounter++) {
- if (chip->polling_mode || do_poll) {
- spin_lock_irq(&chip->reg_lock);
- azx_update_rirb(chip);
- spin_unlock_irq(&chip->reg_lock);
- }
- if (!chip->rirb.cmds[addr]) {
- smp_rmb();
- bus->rirb_error = 0;
-
- if (!do_poll)
- chip->poll_count = 0;
- return chip->rirb.res[addr]; /* the last value */
- }
- if (time_after(jiffies, timeout))
- break;
- if (bus->needs_damn_long_delay || loopcounter > 3000)
- msleep(2); /* temporary workaround */
- else {
- udelay(10);
- cond_resched();
- }
- }
-
- if (!bus->no_response_fallback)
- return -1;
-
- if (!chip->polling_mode && chip->poll_count < 2) {
- snd_printdd(SFX "%s: azx_get_response timeout, "
- "polling the codec once: last cmd=0x%08x\n",
- pci_name(chip->pci), chip->last_cmd[addr]);
- do_poll = 1;
- chip->poll_count++;
- goto again;
- }
-
-
- if (!chip->polling_mode) {
- snd_printk(KERN_WARNING SFX "%s: azx_get_response timeout, "
- "switching to polling mode: last cmd=0x%08x\n",
- pci_name(chip->pci), chip->last_cmd[addr]);
- chip->polling_mode = 1;
- goto again;
- }
-
- if (chip->msi) {
- snd_printk(KERN_WARNING SFX "%s: No response from codec, "
- "disabling MSI: last cmd=0x%08x\n",
- pci_name(chip->pci), chip->last_cmd[addr]);
- free_irq(chip->irq, chip);
- chip->irq = -1;
- pci_disable_msi(chip->pci);
- chip->msi = 0;
- if (azx_acquire_irq(chip, 1) < 0) {
- bus->rirb_error = 1;
- return -1;
- }
- goto again;
- }
-
- if (chip->probing) {
- /* If this critical timeout happens during the codec probing
- * phase, this is likely an access to a non-existing codec
- * slot. Better to return an error and reset the system.
- */
- return -1;
- }
-
- /* a fatal communication error; need either to reset or to fallback
- * to the single_cmd mode
- */
- bus->rirb_error = 1;
- if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) {
- bus->response_reset = 1;
- return -1; /* give a chance to retry */
- }
-
- snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
- "switching to single_cmd mode: last cmd=0x%08x\n",
- chip->last_cmd[addr]);
- chip->single_cmd = 1;
- bus->response_reset = 0;
- /* release CORB/RIRB */
- azx_free_cmd_io(chip);
- /* disable unsolicited responses */
- azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_UNSOL);
- return -1;
-}
-
-/*
- * Use the single immediate command instead of CORB/RIRB for simplicity
- *
- * Note: according to Intel, this is not preferred use. The command was
- * intended for the BIOS only, and may get confused with unsolicited
- * responses. So, we shouldn't use it for normal operation from the
- * driver.
- * I left the codes, however, for debugging/testing purposes.
- */
-
-/* receive a response */
-static int azx_single_wait_for_response(struct azx *chip, unsigned int addr)
-{
- int timeout = 50;
-
- while (timeout--) {
- /* check IRV busy bit */
- if (azx_readw(chip, IRS) & ICH6_IRS_VALID) {
- /* reuse rirb.res as the response return value */
- chip->rirb.res[addr] = azx_readl(chip, IR);
- return 0;
- }
- udelay(1);
- }
- if (printk_ratelimit())
- snd_printd(SFX "%s: get_response timeout: IRS=0x%x\n",
- pci_name(chip->pci), azx_readw(chip, IRS));
- chip->rirb.res[addr] = -1;
- return -EIO;
-}
-
-/* send a command */
-static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
-{
- struct azx *chip = bus->private_data;
- unsigned int addr = azx_command_addr(val);
- int timeout = 50;
-
- bus->rirb_error = 0;
- while (timeout--) {
- /* check ICB busy bit */
- if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) {
- /* Clear IRV valid bit */
- azx_writew(chip, IRS, azx_readw(chip, IRS) |
- ICH6_IRS_VALID);
- azx_writel(chip, IC, val);
- azx_writew(chip, IRS, azx_readw(chip, IRS) |
- ICH6_IRS_BUSY);
- return azx_single_wait_for_response(chip, addr);
- }
- udelay(1);
- }
- if (printk_ratelimit())
- snd_printd(SFX "%s: send_cmd timeout: IRS=0x%x, val=0x%x\n",
- pci_name(chip->pci), azx_readw(chip, IRS), val);
- return -EIO;
-}
-
-/* receive a response */
-static unsigned int azx_single_get_response(struct hda_bus *bus,
- unsigned int addr)
-{
- struct azx *chip = bus->private_data;
- return chip->rirb.res[addr];
-}
-
-/*
- * The below are the main callbacks from hda_codec.
- *
- * They are just the skeleton to call sub-callbacks according to the
- * current setting of chip->single_cmd.
- */
-
-/* send a command */
-static int azx_send_cmd(struct hda_bus *bus, unsigned int val)
-{
- struct azx *chip = bus->private_data;
-
- if (chip->disabled)
- return 0;
- chip->last_cmd[azx_command_addr(val)] = val;
- if (chip->single_cmd)
- return azx_single_send_cmd(bus, val);
- else
- return azx_corb_send_cmd(bus, val);
-}
-
-/* get a response */
-static unsigned int azx_get_response(struct hda_bus *bus,
- unsigned int addr)
-{
- struct azx *chip = bus->private_data;
- if (chip->disabled)
- return 0;
- if (chip->single_cmd)
- return azx_single_get_response(bus, addr);
- else
- return azx_rirb_get_response(bus, addr);
-}
-
-#ifdef CONFIG_PM
-static void azx_power_notify(struct hda_bus *bus, bool power_up);
-#endif
-
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
- unsigned int byte_size,
- struct snd_dma_buffer *bufp);
-static void azx_load_dsp_trigger(struct hda_bus *bus, bool start);
-static void azx_load_dsp_cleanup(struct hda_bus *bus,
- struct snd_dma_buffer *dmab);
-#endif
-
-/* enter link reset */
-static void azx_enter_link_reset(struct azx *chip)
-{
- unsigned long timeout;
-
- /* reset controller */
- azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET);
-
- timeout = jiffies + msecs_to_jiffies(100);
- while ((azx_readb(chip, GCTL) & ICH6_GCTL_RESET) &&
- time_before(jiffies, timeout))
- usleep_range(500, 1000);
-}
-
-/* exit link reset */
-static void azx_exit_link_reset(struct azx *chip)
-{
- unsigned long timeout;
-
- azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET);
-
- timeout = jiffies + msecs_to_jiffies(100);
- while (!azx_readb(chip, GCTL) &&
- time_before(jiffies, timeout))
- usleep_range(500, 1000);
-}
-
-/* reset codec link */
-static int azx_reset(struct azx *chip, int full_reset)
-{
- if (!full_reset)
- goto __skip;
-
- /* clear STATESTS */
- azx_writew(chip, STATESTS, STATESTS_INT_MASK);
-
- /* reset controller */
- azx_enter_link_reset(chip);
-
- /* delay for >= 100us for codec PLL to settle per spec
- * Rev 0.9 section 5.5.1
- */
- usleep_range(500, 1000);
-
- /* Bring controller out of reset */
- azx_exit_link_reset(chip);
-
- /* Brent Chartrand said to wait >= 540us for codecs to initialize */
- usleep_range(1000, 1200);
-
- __skip:
- /* check to see if controller is ready */
- if (!azx_readb(chip, GCTL)) {
- snd_printd(SFX "%s: azx_reset: controller not ready!\n", pci_name(chip->pci));
- return -EBUSY;
- }
-
- /* Accept unsolicited responses */
- if (!chip->single_cmd)
- azx_writel(chip, GCTL, azx_readl(chip, GCTL) |
- ICH6_GCTL_UNSOL);
-
- /* detect codecs */
- if (!chip->codec_mask) {
- chip->codec_mask = azx_readw(chip, STATESTS);
- snd_printdd(SFX "%s: codec_mask = 0x%x\n", pci_name(chip->pci), chip->codec_mask);
- }
-
- return 0;
-}
-
-
-/*
- * Lowlevel interface
- */
-
-/* enable interrupts */
-static void azx_int_enable(struct azx *chip)
-{
- /* enable controller CIE and GIE */
- azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) |
- ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN);
-}
-
-/* disable interrupts */
-static void azx_int_disable(struct azx *chip)
-{
- int i;
-
- /* disable interrupts in stream descriptor */
- for (i = 0; i < chip->num_streams; i++) {
- struct azx_dev *azx_dev = &chip->azx_dev[i];
- azx_sd_writeb(azx_dev, SD_CTL,
- azx_sd_readb(azx_dev, SD_CTL) & ~SD_INT_MASK);
- }
-
- /* disable SIE for all streams */
- azx_writeb(chip, INTCTL, 0);
-
- /* disable controller CIE and GIE */
- azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) &
- ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN));
-}
-
-/* clear interrupts */
-static void azx_int_clear(struct azx *chip)
-{
- int i;
-
- /* clear stream status */
- for (i = 0; i < chip->num_streams; i++) {
- struct azx_dev *azx_dev = &chip->azx_dev[i];
- azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
- }
-
- /* clear STATESTS */
- azx_writew(chip, STATESTS, STATESTS_INT_MASK);
-
- /* clear rirb status */
- azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
-
- /* clear int status */
- azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM);
-}
-
-/* start a stream */
-static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
-{
- /*
- * Before stream start, initialize parameter
- */
- azx_dev->insufficient = 1;
-
- /* enable SIE */
- azx_writel(chip, INTCTL,
- azx_readl(chip, INTCTL) | (1 << azx_dev->index));
- /* set DMA start and interrupt mask */
- azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
- SD_CTL_DMA_START | SD_INT_MASK);
-}
-
-/* stop DMA */
-static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev)
-{
- azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &
- ~(SD_CTL_DMA_START | SD_INT_MASK));
- azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
-}
-
-/* stop a stream */
-static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
-{
- azx_stream_clear(chip, azx_dev);
- /* disable SIE */
- azx_writel(chip, INTCTL,
- azx_readl(chip, INTCTL) & ~(1 << azx_dev->index));
-}
-
-
-/*
- * reset and start the controller registers
- */
-static void azx_init_chip(struct azx *chip, int full_reset)
-{
- if (chip->initialized)
- return;
-
- /* reset controller */
- azx_reset(chip, full_reset);
-
- /* initialize interrupts */
- azx_int_clear(chip);
- azx_int_enable(chip);
-
- /* initialize the codec command I/O */
- if (!chip->single_cmd)
- azx_init_cmd_io(chip);
-
- /* program the position buffer */
- azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
- azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr));
-
- chip->initialized = 1;
-}
/*
* initialize the PCI registers
@@ -1346,7 +360,7 @@ static void azx_init_pci(struct azx *chip)
* The PCI register TCSEL is defined in the Intel manuals.
*/
if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) {
- snd_printdd(SFX "%s: Clearing TCSEL\n", pci_name(chip->pci));
+ dev_dbg(chip->card->dev, "Clearing TCSEL\n");
update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0);
}
@@ -1354,7 +368,8 @@ static void azx_init_pci(struct azx *chip)
* we need to enable snoop.
*/
if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) {
- snd_printdd(SFX "%s: Setting ATI snoop: %d\n", pci_name(chip->pci), azx_snoop(chip));
+ dev_dbg(chip->card->dev, "Setting ATI snoop: %d\n",
+ azx_snoop(chip));
update_pci_byte(chip->pci,
ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07,
azx_snoop(chip) ? ATI_SB450_HDAUDIO_ENABLE_SNOOP : 0);
@@ -1362,7 +377,8 @@ static void azx_init_pci(struct azx *chip)
/* For NVIDIA HDA, enable snoop */
if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) {
- snd_printdd(SFX "%s: Setting Nvidia snoop: %d\n", pci_name(chip->pci), azx_snoop(chip));
+ dev_dbg(chip->card->dev, "Setting Nvidia snoop: %d\n",
+ azx_snoop(chip));
update_pci_byte(chip->pci,
NVIDIA_HDA_TRANSREG_ADDR,
0x0f, NVIDIA_HDA_ENABLE_COHBITS);
@@ -1387,1114 +403,31 @@ static void azx_init_pci(struct azx *chip)
pci_read_config_word(chip->pci,
INTEL_SCH_HDA_DEVC, &snoop);
}
- snd_printdd(SFX "%s: SCH snoop: %s\n",
- pci_name(chip->pci), (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)
- ? "Disabled" : "Enabled");
+ dev_dbg(chip->card->dev, "SCH snoop: %s\n",
+ (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) ?
+ "Disabled" : "Enabled");
}
}
-
static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev);
-/*
- * interrupt handler
- */
-static irqreturn_t azx_interrupt(int irq, void *dev_id)
-{
- struct azx *chip = dev_id;
- struct azx_dev *azx_dev;
- u32 status;
- u8 sd_status;
- int i, ok;
-
-#ifdef CONFIG_PM_RUNTIME
- if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
- if (chip->pci->dev.power.runtime_status != RPM_ACTIVE)
- return IRQ_NONE;
-#endif
-
- spin_lock(&chip->reg_lock);
-
- if (chip->disabled) {
- spin_unlock(&chip->reg_lock);
- return IRQ_NONE;
- }
-
- status = azx_readl(chip, INTSTS);
- if (status == 0 || status == 0xffffffff) {
- spin_unlock(&chip->reg_lock);
- return IRQ_NONE;
- }
-
- for (i = 0; i < chip->num_streams; i++) {
- azx_dev = &chip->azx_dev[i];
- if (status & azx_dev->sd_int_sta_mask) {
- sd_status = azx_sd_readb(azx_dev, SD_STS);
- azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
- if (!azx_dev->substream || !azx_dev->running ||
- !(sd_status & SD_INT_COMPLETE))
- continue;
- /* check whether this IRQ is really acceptable */
- ok = azx_position_ok(chip, azx_dev);
- if (ok == 1) {
- azx_dev->irq_pending = 0;
- spin_unlock(&chip->reg_lock);
- snd_pcm_period_elapsed(azx_dev->substream);
- spin_lock(&chip->reg_lock);
- } else if (ok == 0 && chip->bus && chip->bus->workq) {
- /* bogus IRQ, process it later */
- azx_dev->irq_pending = 1;
- queue_work(chip->bus->workq,
- &chip->irq_pending_work);
- }
- }
- }
-
- /* clear rirb int */
- status = azx_readb(chip, RIRBSTS);
- if (status & RIRB_INT_MASK) {
- if (status & RIRB_INT_RESPONSE) {
- if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY)
- udelay(80);
- azx_update_rirb(chip);
- }
- azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
- }
-
-#if 0
- /* clear state status int */
- if (azx_readw(chip, STATESTS) & 0x04)
- azx_writew(chip, STATESTS, 0x04);
-#endif
- spin_unlock(&chip->reg_lock);
-
- return IRQ_HANDLED;
-}
-
-
-/*
- * set up a BDL entry
- */
-static int setup_bdle(struct azx *chip,
- struct snd_dma_buffer *dmab,
- struct azx_dev *azx_dev, u32 **bdlp,
- int ofs, int size, int with_ioc)
-{
- u32 *bdl = *bdlp;
-
- while (size > 0) {
- dma_addr_t addr;
- int chunk;
-
- if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
- return -EINVAL;
-
- addr = snd_sgbuf_get_addr(dmab, ofs);
- /* program the address field of the BDL entry */
- bdl[0] = cpu_to_le32((u32)addr);
- bdl[1] = cpu_to_le32(upper_32_bits(addr));
- /* program the size field of the BDL entry */
- chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size);
- /* one BDLE cannot cross 4K boundary on CTHDA chips */
- if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
- u32 remain = 0x1000 - (ofs & 0xfff);
- if (chunk > remain)
- chunk = remain;
- }
- bdl[2] = cpu_to_le32(chunk);
- /* program the IOC to enable interrupt
- * only when the whole fragment is processed
- */
- size -= chunk;
- bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
- bdl += 4;
- azx_dev->frags++;
- ofs += chunk;
- }
- *bdlp = bdl;
- return ofs;
-}
-
-/*
- * set up BDL entries
- */
-static int azx_setup_periods(struct azx *chip,
- struct snd_pcm_substream *substream,
- struct azx_dev *azx_dev)
-{
- u32 *bdl;
- int i, ofs, periods, period_bytes;
- int pos_adj;
-
- /* reset BDL address */
- azx_sd_writel(azx_dev, SD_BDLPL, 0);
- azx_sd_writel(azx_dev, SD_BDLPU, 0);
-
- period_bytes = azx_dev->period_bytes;
- periods = azx_dev->bufsize / period_bytes;
-
- /* program the initial BDL entries */
- bdl = (u32 *)azx_dev->bdl.area;
- ofs = 0;
- azx_dev->frags = 0;
- pos_adj = bdl_pos_adj[chip->dev_index];
- if (!azx_dev->no_period_wakeup && pos_adj > 0) {
- struct snd_pcm_runtime *runtime = substream->runtime;
- int pos_align = pos_adj;
- pos_adj = (pos_adj * runtime->rate + 47999) / 48000;
- if (!pos_adj)
- pos_adj = pos_align;
- else
- pos_adj = ((pos_adj + pos_align - 1) / pos_align) *
- pos_align;
- pos_adj = frames_to_bytes(runtime, pos_adj);
- if (pos_adj >= period_bytes) {
- snd_printk(KERN_WARNING SFX "%s: Too big adjustment %d\n",
- pci_name(chip->pci), bdl_pos_adj[chip->dev_index]);
- pos_adj = 0;
- } else {
- ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
- azx_dev,
- &bdl, ofs, pos_adj, true);
- if (ofs < 0)
- goto error;
- }
- } else
- pos_adj = 0;
- for (i = 0; i < periods; i++) {
- if (i == periods - 1 && pos_adj)
- ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
- azx_dev, &bdl, ofs,
- period_bytes - pos_adj, 0);
- else
- ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
- azx_dev, &bdl, ofs,
- period_bytes,
- !azx_dev->no_period_wakeup);
- if (ofs < 0)
- goto error;
- }
- return 0;
-
- error:
- snd_printk(KERN_ERR SFX "%s: Too many BDL entries: buffer=%d, period=%d\n",
- pci_name(chip->pci), azx_dev->bufsize, period_bytes);
- return -EINVAL;
-}
-
-/* reset stream */
-static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
-{
- unsigned char val;
- int timeout;
-
- azx_stream_clear(chip, azx_dev);
-
- azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
- SD_CTL_STREAM_RESET);
- udelay(3);
- timeout = 300;
- while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
- --timeout)
- ;
- val &= ~SD_CTL_STREAM_RESET;
- azx_sd_writeb(azx_dev, SD_CTL, val);
- udelay(3);
-
- timeout = 300;
- /* waiting for hardware to report that the stream is out of reset */
- while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
- --timeout)
- ;
-
- /* reset first position - may not be synced with hw at this time */
- *azx_dev->posbuf = 0;
-}
-
-/*
- * set up the SD for streaming
- */
-static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
-{
- unsigned int val;
- /* make sure the run bit is zero for SD */
- azx_stream_clear(chip, azx_dev);
- /* program the stream_tag */
- val = azx_sd_readl(azx_dev, SD_CTL);
- val = (val & ~SD_CTL_STREAM_TAG_MASK) |
- (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT);
- if (!azx_snoop(chip))
- val |= SD_CTL_TRAFFIC_PRIO;
- azx_sd_writel(azx_dev, SD_CTL, val);
-
- /* program the length of samples in cyclic buffer */
- azx_sd_writel(azx_dev, SD_CBL, azx_dev->bufsize);
-
- /* program the stream format */
- /* this value needs to be the same as the one programmed */
- azx_sd_writew(azx_dev, SD_FORMAT, azx_dev->format_val);
-
- /* program the stream LVI (last valid index) of the BDL */
- azx_sd_writew(azx_dev, SD_LVI, azx_dev->frags - 1);
-
- /* program the BDL address */
- /* lower BDL address */
- azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
- /* upper BDL address */
- azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
-
- /* enable the position buffer */
- if (chip->position_fix[0] != POS_FIX_LPIB ||
- chip->position_fix[1] != POS_FIX_LPIB) {
- if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
- azx_writel(chip, DPLBASE,
- (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
- }
-
- /* set the interrupt enable bits in the descriptor control register */
- azx_sd_writel(azx_dev, SD_CTL,
- azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK);
-
- return 0;
-}
-
-/*
- * Probe the given codec address
- */
-static int probe_codec(struct azx *chip, int addr)
-{
- unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
- (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
- unsigned int res;
-
- mutex_lock(&chip->bus->cmd_mutex);
- chip->probing = 1;
- azx_send_cmd(chip->bus, cmd);
- res = azx_get_response(chip->bus, addr);
- chip->probing = 0;
- mutex_unlock(&chip->bus->cmd_mutex);
- if (res == -1)
- return -EIO;
- snd_printdd(SFX "%s: codec #%d probed OK\n", pci_name(chip->pci), addr);
- return 0;
-}
-
-static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
- struct hda_pcm *cpcm);
-static void azx_stop_chip(struct azx *chip);
-
-static void azx_bus_reset(struct hda_bus *bus)
-{
- struct azx *chip = bus->private_data;
-
- bus->in_reset = 1;
- azx_stop_chip(chip);
- azx_init_chip(chip, 1);
-#ifdef CONFIG_PM
- if (chip->initialized) {
- struct azx_pcm *p;
- list_for_each_entry(p, &chip->pcm_list, list)
- snd_pcm_suspend_all(p->pcm);
- snd_hda_suspend(chip->bus);
- snd_hda_resume(chip->bus);
- }
-#endif
- bus->in_reset = 0;
-}
-
-static int get_jackpoll_interval(struct azx *chip)
-{
- int i = jackpoll_ms[chip->dev_index];
- unsigned int j;
- if (i == 0)
- return 0;
- if (i < 50 || i > 60000)
- j = 0;
- else
- j = msecs_to_jiffies(i);
- if (j == 0)
- snd_printk(KERN_WARNING SFX
- "jackpoll_ms value out of range: %d\n", i);
- return j;
-}
-
-/*
- * Codec initialization
- */
-
-/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
-static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = {
- [AZX_DRIVER_NVIDIA] = 8,
- [AZX_DRIVER_TERA] = 1,
-};
-
-static int azx_codec_create(struct azx *chip, const char *model)
-{
- struct hda_bus_template bus_temp;
- int c, codecs, err;
- int max_slots;
-
- memset(&bus_temp, 0, sizeof(bus_temp));
- bus_temp.private_data = chip;
- bus_temp.modelname = model;
- bus_temp.pci = chip->pci;
- bus_temp.ops.command = azx_send_cmd;
- bus_temp.ops.get_response = azx_get_response;
- bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
- bus_temp.ops.bus_reset = azx_bus_reset;
-#ifdef CONFIG_PM
- bus_temp.power_save = &power_save;
- bus_temp.ops.pm_notify = azx_power_notify;
-#endif
-#ifdef CONFIG_SND_HDA_DSP_LOADER
- bus_temp.ops.load_dsp_prepare = azx_load_dsp_prepare;
- bus_temp.ops.load_dsp_trigger = azx_load_dsp_trigger;
- bus_temp.ops.load_dsp_cleanup = azx_load_dsp_cleanup;
-#endif
-
- err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);
- if (err < 0)
- return err;
-
- if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
- snd_printd(SFX "%s: Enable delay in RIRB handling\n", pci_name(chip->pci));
- chip->bus->needs_damn_long_delay = 1;
- }
-
- codecs = 0;
- max_slots = azx_max_codecs[chip->driver_type];
- if (!max_slots)
- max_slots = AZX_DEFAULT_CODECS;
-
- /* First try to probe all given codec slots */
- for (c = 0; c < max_slots; c++) {
- if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
- if (probe_codec(chip, c) < 0) {
- /* Some BIOSen give you wrong codec addresses
- * that don't exist
- */
- snd_printk(KERN_WARNING SFX
- "%s: Codec #%d probe error; "
- "disabling it...\n", pci_name(chip->pci), c);
- chip->codec_mask &= ~(1 << c);
- /* More badly, accessing to a non-existing
- * codec often screws up the controller chip,
- * and disturbs the further communications.
- * Thus if an error occurs during probing,
- * better to reset the controller chip to
- * get back to the sanity state.
- */
- azx_stop_chip(chip);
- azx_init_chip(chip, 1);
- }
- }
- }
-
- /* AMD chipsets often cause the communication stalls upon certain
- * sequence like the pin-detection. It seems that forcing the synced
- * access works around the stall. Grrr...
- */
- if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
- snd_printd(SFX "%s: Enable sync_write for stable communication\n",
- pci_name(chip->pci));
- chip->bus->sync_write = 1;
- chip->bus->allow_bus_reset = 1;
- }
-
- /* Then create codec instances */
- for (c = 0; c < max_slots; c++) {
- if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
- struct hda_codec *codec;
- err = snd_hda_codec_new(chip->bus, c, &codec);
- if (err < 0)
- continue;
- codec->jackpoll_interval = get_jackpoll_interval(chip);
- codec->beep_mode = chip->beep_mode;
- codecs++;
- }
- }
- if (!codecs) {
- snd_printk(KERN_ERR SFX "%s: no codecs initialized\n", pci_name(chip->pci));
- return -ENXIO;
- }
- return 0;
-}
-
-/* configure each codec instance */
-static int azx_codec_configure(struct azx *chip)
-{
- struct hda_codec *codec;
- list_for_each_entry(codec, &chip->bus->codec_list, list) {
- snd_hda_codec_configure(codec);
- }
- return 0;
-}
-
-
-/*
- * PCM support
- */
-
-/* assign a stream for the PCM */
-static inline struct azx_dev *
-azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream)
-{
- int dev, i, nums;
- struct azx_dev *res = NULL;
- /* make a non-zero unique key for the substream */
- int key = (substream->pcm->device << 16) | (substream->number << 2) |
- (substream->stream + 1);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- dev = chip->playback_index_offset;
- nums = chip->playback_streams;
- } else {
- dev = chip->capture_index_offset;
- nums = chip->capture_streams;
- }
- for (i = 0; i < nums; i++, dev++) {
- struct azx_dev *azx_dev = &chip->azx_dev[dev];
- dsp_lock(azx_dev);
- if (!azx_dev->opened && !dsp_is_locked(azx_dev)) {
- res = azx_dev;
- if (res->assigned_key == key) {
- res->opened = 1;
- res->assigned_key = key;
- dsp_unlock(azx_dev);
- return azx_dev;
- }
- }
- dsp_unlock(azx_dev);
- }
- if (res) {
- dsp_lock(res);
- res->opened = 1;
- res->assigned_key = key;
- dsp_unlock(res);
- }
- return res;
-}
-
-/* release the assigned stream */
-static inline void azx_release_device(struct azx_dev *azx_dev)
+/* called from IRQ */
+static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
{
- azx_dev->opened = 0;
-}
-
-static cycle_t azx_cc_read(const struct cyclecounter *cc)
-{
- struct azx_dev *azx_dev = container_of(cc, struct azx_dev, azx_cc);
- struct snd_pcm_substream *substream = azx_dev->substream;
- struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct azx *chip = apcm->chip;
-
- return azx_readl(chip, WALLCLK);
-}
-
-static void azx_timecounter_init(struct snd_pcm_substream *substream,
- bool force, cycle_t last)
-{
- struct azx_dev *azx_dev = get_azx_dev(substream);
- struct timecounter *tc = &azx_dev->azx_tc;
- struct cyclecounter *cc = &azx_dev->azx_cc;
- u64 nsec;
-
- cc->read = azx_cc_read;
- cc->mask = CLOCKSOURCE_MASK(32);
-
- /*
- * Converting from 24 MHz to ns means applying a 125/3 factor.
- * To avoid any saturation issues in intermediate operations,
- * the 125 factor is applied first. The division is applied
- * last after reading the timecounter value.
- * Applying the 1/3 factor as part of the multiplication
- * requires at least 20 bits for a decent precision, however
- * overflows occur after about 4 hours or less, not a option.
- */
-
- cc->mult = 125; /* saturation after 195 years */
- cc->shift = 0;
-
- nsec = 0; /* audio time is elapsed time since trigger */
- timecounter_init(tc, cc, nsec);
- if (force)
- /*
- * force timecounter to use predefined value,
- * used for synchronized starts
- */
- tc->cycle_last = last;
-}
-
-static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream,
- u64 nsec)
-{
- struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
- u64 codec_frames, codec_nsecs;
-
- if (!hinfo->ops.get_delay)
- return nsec;
-
- codec_frames = hinfo->ops.get_delay(hinfo, apcm->codec, substream);
- codec_nsecs = div_u64(codec_frames * 1000000000LL,
- substream->runtime->rate);
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- return nsec + codec_nsecs;
-
- return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0;
-}
-
-static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream,
- struct timespec *ts)
-{
- struct azx_dev *azx_dev = get_azx_dev(substream);
- u64 nsec;
-
- nsec = timecounter_read(&azx_dev->azx_tc);
- nsec = div_u64(nsec, 3); /* can be optimized */
- nsec = azx_adjust_codec_delay(substream, nsec);
-
- *ts = ns_to_timespec(nsec);
-
- return 0;
-}
-
-static struct snd_pcm_hardware azx_pcm_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- /* No full-resume yet implemented */
- /* SNDRV_PCM_INFO_RESUME |*/
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_SYNC_START |
- SNDRV_PCM_INFO_HAS_WALL_CLOCK |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_48000,
- .rate_min = 48000,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = AZX_MAX_BUF_SIZE,
- .period_bytes_min = 128,
- .period_bytes_max = AZX_MAX_BUF_SIZE / 2,
- .periods_min = 2,
- .periods_max = AZX_MAX_FRAG,
- .fifo_size = 0,
-};
-
-static int azx_pcm_open(struct snd_pcm_substream *substream)
-{
- struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
- struct azx *chip = apcm->chip;
- struct azx_dev *azx_dev;
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned long flags;
- int err;
- int buff_step;
+ int ok;
- mutex_lock(&chip->open_mutex);
- azx_dev = azx_assign_device(chip, substream);
- if (azx_dev == NULL) {
- mutex_unlock(&chip->open_mutex);
- return -EBUSY;
- }
- runtime->hw = azx_pcm_hw;
- runtime->hw.channels_min = hinfo->channels_min;
- runtime->hw.channels_max = hinfo->channels_max;
- runtime->hw.formats = hinfo->formats;
- runtime->hw.rates = hinfo->rates;
- snd_pcm_limit_hw_rates(runtime);
- snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-
- /* avoid wrap-around with wall-clock */
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME,
- 20,
- 178000000);
-
- if (chip->align_buffer_size)
- /* constrain buffer sizes to be multiple of 128
- bytes. This is more efficient in terms of memory
- access but isn't required by the HDA spec and
- prevents users from specifying exact period/buffer
- sizes. For example for 44.1kHz, a period size set
- to 20ms will be rounded to 19.59ms. */
- buff_step = 128;
- else
- /* Don't enforce steps on buffer sizes, still need to
- be multiple of 4 bytes (HDA spec). Tested on Intel
- HDA controllers, may not work on all devices where
- option needs to be disabled */
- buff_step = 4;
-
- snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
- buff_step);
- snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
- buff_step);
- snd_hda_power_up_d3wait(apcm->codec);
- err = hinfo->ops.open(hinfo, apcm->codec, substream);
- if (err < 0) {
- azx_release_device(azx_dev);
- snd_hda_power_down(apcm->codec);
- mutex_unlock(&chip->open_mutex);
- return err;
+ ok = azx_position_ok(chip, azx_dev);
+ if (ok == 1) {
+ azx_dev->irq_pending = 0;
+ return ok;
+ } else if (ok == 0 && chip->bus && chip->bus->workq) {
+ /* bogus IRQ, process it later */
+ azx_dev->irq_pending = 1;
+ queue_work(chip->bus->workq, &chip->irq_pending_work);
}
- snd_pcm_limit_hw_rates(runtime);
- /* sanity check */
- if (snd_BUG_ON(!runtime->hw.channels_min) ||
- snd_BUG_ON(!runtime->hw.channels_max) ||
- snd_BUG_ON(!runtime->hw.formats) ||
- snd_BUG_ON(!runtime->hw.rates)) {
- azx_release_device(azx_dev);
- hinfo->ops.close(hinfo, apcm->codec, substream);
- snd_hda_power_down(apcm->codec);
- mutex_unlock(&chip->open_mutex);
- return -EINVAL;
- }
-
- /* disable WALLCLOCK timestamps for capture streams
- until we figure out how to handle digital inputs */
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK;
-
- spin_lock_irqsave(&chip->reg_lock, flags);
- azx_dev->substream = substream;
- azx_dev->running = 0;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
-
- runtime->private_data = azx_dev;
- snd_pcm_set_sync(substream);
- mutex_unlock(&chip->open_mutex);
return 0;
}
-static int azx_pcm_close(struct snd_pcm_substream *substream)
-{
- struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
- struct azx *chip = apcm->chip;
- struct azx_dev *azx_dev = get_azx_dev(substream);
- unsigned long flags;
-
- mutex_lock(&chip->open_mutex);
- spin_lock_irqsave(&chip->reg_lock, flags);
- azx_dev->substream = NULL;
- azx_dev->running = 0;
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- azx_release_device(azx_dev);
- hinfo->ops.close(hinfo, apcm->codec, substream);
- snd_hda_power_down(apcm->codec);
- mutex_unlock(&chip->open_mutex);
- return 0;
-}
-
-static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct azx *chip = apcm->chip;
- struct azx_dev *azx_dev = get_azx_dev(substream);
- int ret;
-
- dsp_lock(azx_dev);
- if (dsp_is_locked(azx_dev)) {
- ret = -EBUSY;
- goto unlock;
- }
-
- mark_runtime_wc(chip, azx_dev, substream, false);
- azx_dev->bufsize = 0;
- azx_dev->period_bytes = 0;
- azx_dev->format_val = 0;
- ret = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
- if (ret < 0)
- goto unlock;
- mark_runtime_wc(chip, azx_dev, substream, true);
- unlock:
- dsp_unlock(azx_dev);
- return ret;
-}
-
-static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
-{
- struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct azx_dev *azx_dev = get_azx_dev(substream);
- struct azx *chip = apcm->chip;
- struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
-
- /* reset BDL address */
- dsp_lock(azx_dev);
- if (!dsp_is_locked(azx_dev)) {
- azx_sd_writel(azx_dev, SD_BDLPL, 0);
- azx_sd_writel(azx_dev, SD_BDLPU, 0);
- azx_sd_writel(azx_dev, SD_CTL, 0);
- azx_dev->bufsize = 0;
- azx_dev->period_bytes = 0;
- azx_dev->format_val = 0;
- }
-
- snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
-
- mark_runtime_wc(chip, azx_dev, substream, false);
- azx_dev->prepared = 0;
- dsp_unlock(azx_dev);
- return snd_pcm_lib_free_pages(substream);
-}
-
-static int azx_pcm_prepare(struct snd_pcm_substream *substream)
-{
- struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct azx *chip = apcm->chip;
- struct azx_dev *azx_dev = get_azx_dev(substream);
- struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned int bufsize, period_bytes, format_val, stream_tag;
- int err;
- struct hda_spdif_out *spdif =
- snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid);
- unsigned short ctls = spdif ? spdif->ctls : 0;
-
- dsp_lock(azx_dev);
- if (dsp_is_locked(azx_dev)) {
- err = -EBUSY;
- goto unlock;
- }
-
- azx_stream_reset(chip, azx_dev);
- format_val = snd_hda_calc_stream_format(runtime->rate,
- runtime->channels,
- runtime->format,
- hinfo->maxbps,
- ctls);
- if (!format_val) {
- snd_printk(KERN_ERR SFX
- "%s: invalid format_val, rate=%d, ch=%d, format=%d\n",
- pci_name(chip->pci), runtime->rate, runtime->channels, runtime->format);
- err = -EINVAL;
- goto unlock;
- }
-
- bufsize = snd_pcm_lib_buffer_bytes(substream);
- period_bytes = snd_pcm_lib_period_bytes(substream);
-
- snd_printdd(SFX "%s: azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
- pci_name(chip->pci), bufsize, format_val);
-
- if (bufsize != azx_dev->bufsize ||
- period_bytes != azx_dev->period_bytes ||
- format_val != azx_dev->format_val ||
- runtime->no_period_wakeup != azx_dev->no_period_wakeup) {
- azx_dev->bufsize = bufsize;
- azx_dev->period_bytes = period_bytes;
- azx_dev->format_val = format_val;
- azx_dev->no_period_wakeup = runtime->no_period_wakeup;
- err = azx_setup_periods(chip, substream, azx_dev);
- if (err < 0)
- goto unlock;
- }
-
- /* when LPIB delay correction gives a small negative value,
- * we ignore it; currently set the threshold statically to
- * 64 frames
- */
- if (runtime->period_size > 64)
- azx_dev->delay_negative_threshold = -frames_to_bytes(runtime, 64);
- else
- azx_dev->delay_negative_threshold = 0;
-
- /* wallclk has 24Mhz clock source */
- azx_dev->period_wallclk = (((runtime->period_size * 24000) /
- runtime->rate) * 1000);
- azx_setup_controller(chip, azx_dev);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
- else
- azx_dev->fifo_size = 0;
-
- stream_tag = azx_dev->stream_tag;
- /* CA-IBG chips need the playback stream starting from 1 */
- if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) &&
- stream_tag > chip->capture_streams)
- stream_tag -= chip->capture_streams;
- err = snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
- azx_dev->format_val, substream);
-
- unlock:
- if (!err)
- azx_dev->prepared = 1;
- dsp_unlock(azx_dev);
- return err;
-}
-
-static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct azx *chip = apcm->chip;
- struct azx_dev *azx_dev;
- struct snd_pcm_substream *s;
- int rstart = 0, start, nsync = 0, sbits = 0;
- int nwait, timeout;
-
- azx_dev = get_azx_dev(substream);
- trace_azx_pcm_trigger(chip, azx_dev, cmd);
-
- if (dsp_is_locked(azx_dev) || !azx_dev->prepared)
- return -EPIPE;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- rstart = 1;
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_RESUME:
- start = 1;
- break;
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_STOP:
- start = 0;
- break;
- default:
- return -EINVAL;
- }
-
- snd_pcm_group_for_each_entry(s, substream) {
- if (s->pcm->card != substream->pcm->card)
- continue;
- azx_dev = get_azx_dev(s);
- sbits |= 1 << azx_dev->index;
- nsync++;
- snd_pcm_trigger_done(s, substream);
- }
-
- spin_lock(&chip->reg_lock);
-
- /* first, set SYNC bits of corresponding streams */
- if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
- azx_writel(chip, OLD_SSYNC,
- azx_readl(chip, OLD_SSYNC) | sbits);
- else
- azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits);
-
- snd_pcm_group_for_each_entry(s, substream) {
- if (s->pcm->card != substream->pcm->card)
- continue;
- azx_dev = get_azx_dev(s);
- if (start) {
- azx_dev->start_wallclk = azx_readl(chip, WALLCLK);
- if (!rstart)
- azx_dev->start_wallclk -=
- azx_dev->period_wallclk;
- azx_stream_start(chip, azx_dev);
- } else {
- azx_stream_stop(chip, azx_dev);
- }
- azx_dev->running = start;
- }
- spin_unlock(&chip->reg_lock);
- if (start) {
- /* wait until all FIFOs get ready */
- for (timeout = 5000; timeout; timeout--) {
- nwait = 0;
- snd_pcm_group_for_each_entry(s, substream) {
- if (s->pcm->card != substream->pcm->card)
- continue;
- azx_dev = get_azx_dev(s);
- if (!(azx_sd_readb(azx_dev, SD_STS) &
- SD_STS_FIFO_READY))
- nwait++;
- }
- if (!nwait)
- break;
- cpu_relax();
- }
- } else {
- /* wait until all RUN bits are cleared */
- for (timeout = 5000; timeout; timeout--) {
- nwait = 0;
- snd_pcm_group_for_each_entry(s, substream) {
- if (s->pcm->card != substream->pcm->card)
- continue;
- azx_dev = get_azx_dev(s);
- if (azx_sd_readb(azx_dev, SD_CTL) &
- SD_CTL_DMA_START)
- nwait++;
- }
- if (!nwait)
- break;
- cpu_relax();
- }
- }
- spin_lock(&chip->reg_lock);
- /* reset SYNC bits */
- if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
- azx_writel(chip, OLD_SSYNC,
- azx_readl(chip, OLD_SSYNC) & ~sbits);
- else
- azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
- if (start) {
- azx_timecounter_init(substream, 0, 0);
- if (nsync > 1) {
- cycle_t cycle_last;
-
- /* same start cycle for master and group */
- azx_dev = get_azx_dev(substream);
- cycle_last = azx_dev->azx_tc.cycle_last;
-
- snd_pcm_group_for_each_entry(s, substream) {
- if (s->pcm->card != substream->pcm->card)
- continue;
- azx_timecounter_init(s, 1, cycle_last);
- }
- }
- }
- spin_unlock(&chip->reg_lock);
- return 0;
-}
-
-/* get the current DMA position with correction on VIA chips */
-static unsigned int azx_via_get_position(struct azx *chip,
- struct azx_dev *azx_dev)
-{
- unsigned int link_pos, mini_pos, bound_pos;
- unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos;
- unsigned int fifo_size;
-
- link_pos = azx_sd_readl(azx_dev, SD_LPIB);
- if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- /* Playback, no problem using link position */
- return link_pos;
- }
-
- /* Capture */
- /* For new chipset,
- * use mod to get the DMA position just like old chipset
- */
- mod_dma_pos = le32_to_cpu(*azx_dev->posbuf);
- mod_dma_pos %= azx_dev->period_bytes;
-
- /* azx_dev->fifo_size can't get FIFO size of in stream.
- * Get from base address + offset.
- */
- fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET);
-
- if (azx_dev->insufficient) {
- /* Link position never gather than FIFO size */
- if (link_pos <= fifo_size)
- return 0;
-
- azx_dev->insufficient = 0;
- }
-
- if (link_pos <= fifo_size)
- mini_pos = azx_dev->bufsize + link_pos - fifo_size;
- else
- mini_pos = link_pos - fifo_size;
-
- /* Find nearest previous boudary */
- mod_mini_pos = mini_pos % azx_dev->period_bytes;
- mod_link_pos = link_pos % azx_dev->period_bytes;
- if (mod_link_pos >= fifo_size)
- bound_pos = link_pos - mod_link_pos;
- else if (mod_dma_pos >= mod_mini_pos)
- bound_pos = mini_pos - mod_mini_pos;
- else {
- bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes;
- if (bound_pos >= azx_dev->bufsize)
- bound_pos = 0;
- }
-
- /* Calculate real DMA position we want */
- return bound_pos + mod_dma_pos;
-}
-
-static unsigned int azx_get_position(struct azx *chip,
- struct azx_dev *azx_dev,
- bool with_check)
-{
- struct snd_pcm_substream *substream = azx_dev->substream;
- struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- unsigned int pos;
- int stream = substream->stream;
- struct hda_pcm_stream *hinfo = apcm->hinfo[stream];
- int delay = 0;
-
- switch (chip->position_fix[stream]) {
- case POS_FIX_LPIB:
- /* read LPIB */
- pos = azx_sd_readl(azx_dev, SD_LPIB);
- break;
- case POS_FIX_VIACOMBO:
- pos = azx_via_get_position(chip, azx_dev);
- break;
- default:
- /* use the position buffer */
- pos = le32_to_cpu(*azx_dev->posbuf);
- if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) {
- if (!pos || pos == (u32)-1) {
- printk(KERN_WARNING
- "hda-intel: Invalid position buffer, "
- "using LPIB read method instead.\n");
- chip->position_fix[stream] = POS_FIX_LPIB;
- pos = azx_sd_readl(azx_dev, SD_LPIB);
- } else
- chip->position_fix[stream] = POS_FIX_POSBUF;
- }
- break;
- }
-
- if (pos >= azx_dev->bufsize)
- pos = 0;
-
- /* calculate runtime delay from LPIB */
- if (substream->runtime &&
- chip->position_fix[stream] == POS_FIX_POSBUF &&
- (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
- unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB);
- if (stream == SNDRV_PCM_STREAM_PLAYBACK)
- delay = pos - lpib_pos;
- else
- delay = lpib_pos - pos;
- if (delay < 0) {
- if (delay >= azx_dev->delay_negative_threshold)
- delay = 0;
- else
- delay += azx_dev->bufsize;
- }
- if (delay >= azx_dev->period_bytes) {
- snd_printk(KERN_WARNING SFX
- "%s: Unstable LPIB (%d >= %d); "
- "disabling LPIB delay counting\n",
- pci_name(chip->pci), delay, azx_dev->period_bytes);
- delay = 0;
- chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY;
- }
- delay = bytes_to_frames(substream->runtime, delay);
- }
-
- if (substream->runtime) {
- if (hinfo->ops.get_delay)
- delay += hinfo->ops.get_delay(hinfo, apcm->codec,
- substream);
- substream->runtime->delay = delay;
- }
-
- trace_azx_get_position(chip, azx_dev, pos, delay);
- return pos;
-}
-
-static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
-{
- struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct azx *chip = apcm->chip;
- struct azx_dev *azx_dev = get_azx_dev(substream);
- return bytes_to_frames(substream->runtime,
- azx_get_position(chip, azx_dev, false));
-}
-
/*
* Check whether the current DMA position is acceptable for updating
* periods. Returns non-zero if it's OK.
@@ -2521,7 +454,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
if (wallclk < (azx_dev->period_wallclk * 5) / 4 &&
pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
/* NG - it's below the first next period boundary */
- return bdl_pos_adj[chip->dev_index] ? 0 : -1;
+ return chip->bdl_pos_adj[chip->dev_index] ? 0 : -1;
azx_dev->start_wallclk += wallclk;
return 1; /* OK, it's fine */
}
@@ -2535,10 +468,9 @@ static void azx_irq_pending_work(struct work_struct *work)
int i, pending, ok;
if (!chip->irq_pending_warned) {
- printk(KERN_WARNING
- "hda-intel: IRQ timing workaround is activated "
- "for card #%d. Suggest a bigger bdl_pos_adj.\n",
- chip->card->number);
+ dev_info(chip->card->dev,
+ "IRQ timing workaround is activated for card #%d. Suggest a bigger bdl_pos_adj.\n",
+ chip->card->number);
chip->irq_pending_warned = 1;
}
@@ -2580,139 +512,14 @@ static void azx_clear_irq_pending(struct azx *chip)
spin_unlock_irq(&chip->reg_lock);
}
-#ifdef CONFIG_X86
-static int azx_pcm_mmap(struct snd_pcm_substream *substream,
- struct vm_area_struct *area)
-{
- struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct azx *chip = apcm->chip;
- if (!azx_snoop(chip))
- area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
- return snd_pcm_lib_default_mmap(substream, area);
-}
-#else
-#define azx_pcm_mmap NULL
-#endif
-
-static struct snd_pcm_ops azx_pcm_ops = {
- .open = azx_pcm_open,
- .close = azx_pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = azx_pcm_hw_params,
- .hw_free = azx_pcm_hw_free,
- .prepare = azx_pcm_prepare,
- .trigger = azx_pcm_trigger,
- .pointer = azx_pcm_pointer,
- .wall_clock = azx_get_wallclock_tstamp,
- .mmap = azx_pcm_mmap,
- .page = snd_pcm_sgbuf_ops_page,
-};
-
-static void azx_pcm_free(struct snd_pcm *pcm)
-{
- struct azx_pcm *apcm = pcm->private_data;
- if (apcm) {
- list_del(&apcm->list);
- kfree(apcm);
- }
-}
-
-#define MAX_PREALLOC_SIZE (32 * 1024 * 1024)
-
-static int
-azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
- struct hda_pcm *cpcm)
-{
- struct azx *chip = bus->private_data;
- struct snd_pcm *pcm;
- struct azx_pcm *apcm;
- int pcm_dev = cpcm->device;
- unsigned int size;
- int s, err;
-
- list_for_each_entry(apcm, &chip->pcm_list, list) {
- if (apcm->pcm->device == pcm_dev) {
- snd_printk(KERN_ERR SFX "%s: PCM %d already exists\n",
- pci_name(chip->pci), pcm_dev);
- return -EBUSY;
- }
- }
- err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
- cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
- cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams,
- &pcm);
- if (err < 0)
- return err;
- strlcpy(pcm->name, cpcm->name, sizeof(pcm->name));
- apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
- if (apcm == NULL)
- return -ENOMEM;
- apcm->chip = chip;
- apcm->pcm = pcm;
- apcm->codec = codec;
- pcm->private_data = apcm;
- pcm->private_free = azx_pcm_free;
- if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
- pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
- list_add_tail(&apcm->list, &chip->pcm_list);
- cpcm->pcm = pcm;
- for (s = 0; s < 2; s++) {
- apcm->hinfo[s] = &cpcm->stream[s];
- if (cpcm->stream[s].substreams)
- snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
- }
- /* buffer pre-allocation */
- size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
- if (size > MAX_PREALLOC_SIZE)
- size = MAX_PREALLOC_SIZE;
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
- snd_dma_pci_data(chip->pci),
- size, MAX_PREALLOC_SIZE);
- return 0;
-}
-
-/*
- * mixer creation - all stuff is implemented in hda module
- */
-static int azx_mixer_create(struct azx *chip)
-{
- return snd_hda_build_controls(chip->bus);
-}
-
-
-/*
- * initialize SD streams
- */
-static int azx_init_stream(struct azx *chip)
-{
- int i;
-
- /* initialize each stream (aka device)
- * assign the starting bdl address to each stream (device)
- * and initialize
- */
- for (i = 0; i < chip->num_streams; i++) {
- struct azx_dev *azx_dev = &chip->azx_dev[i];
- azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
- /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
- azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
- /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
- azx_dev->sd_int_sta_mask = 1 << i;
- /* stream tag: must be non-zero and unique */
- azx_dev->index = i;
- azx_dev->stream_tag = i + 1;
- }
-
- return 0;
-}
-
static int azx_acquire_irq(struct azx *chip, int do_disconnect)
{
if (request_irq(chip->pci->irq, azx_interrupt,
chip->msi ? 0 : IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "
- "disabling device\n", chip->pci->irq);
+ dev_err(chip->card->dev,
+ "unable to grab IRQ %d, disabling device\n",
+ chip->pci->irq);
if (do_disconnect)
snd_card_disconnect(chip->card);
return -1;
@@ -2722,160 +529,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect)
return 0;
}
-
-static void azx_stop_chip(struct azx *chip)
-{
- if (!chip->initialized)
- return;
-
- /* disable interrupts */
- azx_int_disable(chip);
- azx_int_clear(chip);
-
- /* disable CORB/RIRB */
- azx_free_cmd_io(chip);
-
- /* disable position buffer */
- azx_writel(chip, DPLBASE, 0);
- azx_writel(chip, DPUBASE, 0);
-
- chip->initialized = 0;
-}
-
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-/*
- * DSP loading code (e.g. for CA0132)
- */
-
-/* use the first stream for loading DSP */
-static struct azx_dev *
-azx_get_dsp_loader_dev(struct azx *chip)
-{
- return &chip->azx_dev[chip->playback_index_offset];
-}
-
-static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
- unsigned int byte_size,
- struct snd_dma_buffer *bufp)
-{
- u32 *bdl;
- struct azx *chip = bus->private_data;
- struct azx_dev *azx_dev;
- int err;
-
- azx_dev = azx_get_dsp_loader_dev(chip);
-
- dsp_lock(azx_dev);
- spin_lock_irq(&chip->reg_lock);
- if (azx_dev->running || azx_dev->locked) {
- spin_unlock_irq(&chip->reg_lock);
- err = -EBUSY;
- goto unlock;
- }
- azx_dev->prepared = 0;
- chip->saved_azx_dev = *azx_dev;
- azx_dev->locked = 1;
- spin_unlock_irq(&chip->reg_lock);
-
- err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG,
- snd_dma_pci_data(chip->pci),
- byte_size, bufp);
- if (err < 0)
- goto err_alloc;
-
- mark_pages_wc(chip, bufp, true);
- azx_dev->bufsize = byte_size;
- azx_dev->period_bytes = byte_size;
- azx_dev->format_val = format;
-
- azx_stream_reset(chip, azx_dev);
-
- /* reset BDL address */
- azx_sd_writel(azx_dev, SD_BDLPL, 0);
- azx_sd_writel(azx_dev, SD_BDLPU, 0);
-
- azx_dev->frags = 0;
- bdl = (u32 *)azx_dev->bdl.area;
- err = setup_bdle(chip, bufp, azx_dev, &bdl, 0, byte_size, 0);
- if (err < 0)
- goto error;
-
- azx_setup_controller(chip, azx_dev);
- dsp_unlock(azx_dev);
- return azx_dev->stream_tag;
-
- error:
- mark_pages_wc(chip, bufp, false);
- snd_dma_free_pages(bufp);
- err_alloc:
- spin_lock_irq(&chip->reg_lock);
- if (azx_dev->opened)
- *azx_dev = chip->saved_azx_dev;
- azx_dev->locked = 0;
- spin_unlock_irq(&chip->reg_lock);
- unlock:
- dsp_unlock(azx_dev);
- return err;
-}
-
-static void azx_load_dsp_trigger(struct hda_bus *bus, bool start)
-{
- struct azx *chip = bus->private_data;
- struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
-
- if (start)
- azx_stream_start(chip, azx_dev);
- else
- azx_stream_stop(chip, azx_dev);
- azx_dev->running = start;
-}
-
-static void azx_load_dsp_cleanup(struct hda_bus *bus,
- struct snd_dma_buffer *dmab)
-{
- struct azx *chip = bus->private_data;
- struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
-
- if (!dmab->area || !azx_dev->locked)
- return;
-
- dsp_lock(azx_dev);
- /* reset BDL address */
- azx_sd_writel(azx_dev, SD_BDLPL, 0);
- azx_sd_writel(azx_dev, SD_BDLPU, 0);
- azx_sd_writel(azx_dev, SD_CTL, 0);
- azx_dev->bufsize = 0;
- azx_dev->period_bytes = 0;
- azx_dev->format_val = 0;
-
- mark_pages_wc(chip, dmab, false);
- snd_dma_free_pages(dmab);
- dmab->area = NULL;
-
- spin_lock_irq(&chip->reg_lock);
- if (azx_dev->opened)
- *azx_dev = chip->saved_azx_dev;
- azx_dev->locked = 0;
- spin_unlock_irq(&chip->reg_lock);
- dsp_unlock(azx_dev);
-}
-#endif /* CONFIG_SND_HDA_DSP_LOADER */
-
#ifdef CONFIG_PM
-/* power-up/down the controller */
-static void azx_power_notify(struct hda_bus *bus, bool power_up)
-{
- struct azx *chip = bus->private_data;
-
- if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
- return;
-
- if (power_up)
- pm_runtime_get_sync(&chip->pci->dev);
- else
- pm_runtime_put_sync(&chip->pci->dev);
-}
-
static DEFINE_MUTEX(card_list_lock);
static LIST_HEAD(card_list);
@@ -2969,8 +623,8 @@ static int azx_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "hda-intel: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(chip->card->dev,
+ "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -3127,36 +781,32 @@ static void azx_vs_set_state(struct pci_dev *pci,
if (!chip->bus) {
chip->disabled = disabled;
if (!disabled) {
- snd_printk(KERN_INFO SFX
- "%s: Start delayed initialization\n",
- pci_name(chip->pci));
+ dev_info(chip->card->dev,
+ "Start delayed initialization\n");
if (azx_probe_continue(chip) < 0) {
- snd_printk(KERN_ERR SFX
- "%s: initialization error\n",
- pci_name(chip->pci));
+ dev_err(chip->card->dev, "initialization error\n");
chip->init_failed = true;
}
}
} else {
- snd_printk(KERN_INFO SFX
- "%s: %s via VGA-switcheroo\n", pci_name(chip->pci),
- disabled ? "Disabling" : "Enabling");
+ dev_info(chip->card->dev, "%s via VGA-switcheroo\n",
+ disabled ? "Disabling" : "Enabling");
if (disabled) {
- pm_runtime_put_sync_suspend(&pci->dev);
- azx_suspend(&pci->dev);
+ pm_runtime_put_sync_suspend(card->dev);
+ azx_suspend(card->dev);
/* when we get suspended by vga switcheroo we end up in D3cold,
* however we have no ACPI handle, so pci/acpi can't put us there,
* put ourselves there */
pci->current_state = PCI_D3cold;
chip->disabled = true;
if (snd_hda_lock_devices(chip->bus))
- snd_printk(KERN_WARNING SFX "%s: Cannot lock devices!\n",
- pci_name(chip->pci));
+ dev_warn(chip->card->dev,
+ "Cannot lock devices!\n");
} else {
snd_hda_unlock_devices(chip->bus);
- pm_runtime_get_noresume(&pci->dev);
+ pm_runtime_get_noresume(card->dev);
chip->disabled = false;
- azx_resume(&pci->dev);
+ azx_resume(card->dev);
}
}
}
@@ -3181,9 +831,8 @@ static void init_vga_switcheroo(struct azx *chip)
{
struct pci_dev *p = get_bound_vga(chip->pci);
if (p) {
- snd_printk(KERN_INFO SFX
- "%s: Handle VGA-switcheroo audio client\n",
- pci_name(chip->pci));
+ dev_info(chip->card->dev,
+ "Handle VGA-switcheroo audio client\n");
chip->use_vga_switcheroo = 1;
pci_dev_put(p);
}
@@ -3211,7 +860,8 @@ static int register_vga_switcheroo(struct azx *chip)
chip->vga_switcheroo_registered = 1;
/* register as an optimus hdmi audio power domain */
- vga_switcheroo_init_domain_pm_optimus_hdmi_audio(&chip->pci->dev, &chip->hdmi_pm_domain);
+ vga_switcheroo_init_domain_pm_optimus_hdmi_audio(chip->card->dev,
+ &chip->hdmi_pm_domain);
return 0;
}
#else
@@ -3260,21 +910,7 @@ static int azx_free(struct azx *chip)
if (chip->remap_addr)
iounmap(chip->remap_addr);
- if (chip->azx_dev) {
- for (i = 0; i < chip->num_streams; i++)
- if (chip->azx_dev[i].bdl.area) {
- mark_pages_wc(chip, &chip->azx_dev[i].bdl, false);
- snd_dma_free_pages(&chip->azx_dev[i].bdl);
- }
- }
- if (chip->rb.area) {
- mark_pages_wc(chip, &chip->rb, false);
- snd_dma_free_pages(&chip->rb);
- }
- if (chip->posbuf.area) {
- mark_pages_wc(chip, &chip->posbuf, false);
- snd_dma_free_pages(&chip->posbuf);
- }
+ azx_free_stream_pages(chip);
if (chip->region_requested)
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
@@ -3374,20 +1010,19 @@ static int check_position_fix(struct azx *chip, int fix)
q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
if (q) {
- printk(KERN_INFO
- "hda_intel: position_fix set to %d "
- "for device %04x:%04x\n",
- q->value, q->subvendor, q->subdevice);
+ dev_info(chip->card->dev,
+ "position_fix set to %d for device %04x:%04x\n",
+ q->value, q->subvendor, q->subdevice);
return q->value;
}
/* Check VIA/ATI HD Audio Controller exist */
if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) {
- snd_printd(SFX "%s: Using VIACOMBO position fix\n", pci_name(chip->pci));
+ dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n");
return POS_FIX_VIACOMBO;
}
if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) {
- snd_printd(SFX "%s: Using LPIB position fix\n", pci_name(chip->pci));
+ dev_dbg(chip->card->dev, "Using LPIB position fix\n");
return POS_FIX_LPIB;
}
return POS_FIX_AUTO;
@@ -3425,10 +1060,9 @@ static void check_probe_mask(struct azx *chip, int dev)
if (chip->codec_probe_mask == -1) {
q = snd_pci_quirk_lookup(chip->pci, probe_mask_list);
if (q) {
- printk(KERN_INFO
- "hda_intel: probe_mask set to 0x%x "
- "for device %04x:%04x\n",
- q->value, q->subvendor, q->subdevice);
+ dev_info(chip->card->dev,
+ "probe_mask set to 0x%x for device %04x:%04x\n",
+ q->value, q->subvendor, q->subdevice);
chip->codec_probe_mask = q->value;
}
}
@@ -3437,8 +1071,8 @@ static void check_probe_mask(struct azx *chip, int dev)
if (chip->codec_probe_mask != -1 &&
(chip->codec_probe_mask & AZX_FORCE_CODEC_MASK)) {
chip->codec_mask = chip->codec_probe_mask & 0xff;
- printk(KERN_INFO "hda_intel: codec_mask forced to 0x%x\n",
- chip->codec_mask);
+ dev_info(chip->card->dev, "codec_mask forced to 0x%x\n",
+ chip->codec_mask);
}
}
@@ -3470,16 +1104,16 @@ static void check_msi(struct azx *chip)
chip->msi = 1; /* enable MSI as default */
q = snd_pci_quirk_lookup(chip->pci, msi_black_list);
if (q) {
- printk(KERN_INFO
- "hda_intel: msi for device %04x:%04x set to %d\n",
- q->subvendor, q->subdevice, q->value);
+ dev_info(chip->card->dev,
+ "msi for device %04x:%04x set to %d\n",
+ q->subvendor, q->subdevice, q->value);
chip->msi = q->value;
return;
}
/* NVidia chipsets seem to cause troubles with MSI */
if (chip->driver_caps & AZX_DCAPS_NO_MSI) {
- printk(KERN_INFO "hda_intel: Disabling MSI\n");
+ dev_info(chip->card->dev, "Disabling MSI\n");
chip->msi = 0;
}
}
@@ -3511,8 +1145,8 @@ static void azx_check_snoop_available(struct azx *chip)
}
if (snoop != chip->snoop) {
- snd_printk(KERN_INFO SFX "%s: Force to %s mode\n",
- pci_name(chip->pci), snoop ? "snoop" : "non-snoop");
+ dev_info(chip->card->dev, "Force to %s mode\n",
+ snoop ? "snoop" : "non-snoop");
chip->snoop = snoop;
}
}
@@ -3527,6 +1161,7 @@ static void azx_probe_work(struct work_struct *work)
*/
static int azx_create(struct snd_card *card, struct pci_dev *pci,
int dev, unsigned int driver_caps,
+ const struct hda_controller_ops *hda_ops,
struct azx **rchip)
{
static struct snd_device_ops ops = {
@@ -3543,7 +1178,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip) {
- snd_printk(KERN_ERR SFX "%s: Cannot allocate chip\n", pci_name(pci));
+ dev_err(card->dev, "Cannot allocate chip\n");
pci_disable_device(pci);
return -ENOMEM;
}
@@ -3552,11 +1187,13 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
mutex_init(&chip->open_mutex);
chip->card = card;
chip->pci = pci;
+ chip->ops = hda_ops;
chip->irq = -1;
chip->driver_caps = driver_caps;
chip->driver_type = driver_caps & 0xff;
check_msi(chip);
chip->dev_index = dev;
+ chip->jackpoll_ms = jackpoll_ms;
INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
INIT_LIST_HEAD(&chip->pcm_list);
INIT_LIST_HEAD(&chip->list);
@@ -3588,11 +1225,11 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
break;
}
}
+ chip->bdl_pos_adj = bdl_pos_adj;
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
if (err < 0) {
- snd_printk(KERN_ERR SFX "%s: Error creating device [card]!\n",
- pci_name(chip->pci));
+ dev_err(card->dev, "Error creating device [card]!\n");
azx_free(chip);
return err;
}
@@ -3610,7 +1247,7 @@ static int azx_first_init(struct azx *chip)
int dev = chip->dev_index;
struct pci_dev *pci = chip->pci;
struct snd_card *card = chip->card;
- int i, err;
+ int err;
unsigned short gcap;
#if BITS_PER_LONG != 64
@@ -3631,7 +1268,7 @@ static int azx_first_init(struct azx *chip)
chip->addr = pci_resource_start(pci, 0);
chip->remap_addr = pci_ioremap_bar(pci, 0);
if (chip->remap_addr == NULL) {
- snd_printk(KERN_ERR SFX "%s: ioremap error\n", pci_name(chip->pci));
+ dev_err(card->dev, "ioremap error\n");
return -ENXIO;
}
@@ -3646,7 +1283,7 @@ static int azx_first_init(struct azx *chip)
synchronize_irq(chip->irq);
gcap = azx_readw(chip, GCAP);
- snd_printdd(SFX "%s: chipset global capabilities = 0x%x\n", pci_name(chip->pci), gcap);
+ dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap);
/* disable SB600 64bit support for safety */
if (chip->pci->vendor == PCI_VENDOR_ID_ATI) {
@@ -3663,7 +1300,7 @@ static int azx_first_init(struct azx *chip)
/* disable 64bit DMA address on some devices */
if (chip->driver_caps & AZX_DCAPS_NO_64BIT) {
- snd_printd(SFX "%s: Disabling 64bit DMA\n", pci_name(chip->pci));
+ dev_dbg(card->dev, "Disabling 64bit DMA\n");
gcap &= ~ICH6_GCAP_64OK;
}
@@ -3718,33 +1355,11 @@ static int azx_first_init(struct azx *chip)
chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev),
GFP_KERNEL);
if (!chip->azx_dev) {
- snd_printk(KERN_ERR SFX "%s: cannot malloc azx_dev\n", pci_name(chip->pci));
+ dev_err(card->dev, "cannot malloc azx_dev\n");
return -ENOMEM;
}
- for (i = 0; i < chip->num_streams; i++) {
- dsp_lock_init(&chip->azx_dev[i]);
- /* allocate memory for the BDL for each stream */
- err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
- snd_dma_pci_data(chip->pci),
- BDL_SIZE, &chip->azx_dev[i].bdl);
- if (err < 0) {
- snd_printk(KERN_ERR SFX "%s: cannot allocate BDL\n", pci_name(chip->pci));
- return -ENOMEM;
- }
- mark_pages_wc(chip, &chip->azx_dev[i].bdl, true);
- }
- /* allocate memory for the position buffer */
- err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
- snd_dma_pci_data(chip->pci),
- chip->num_streams * 8, &chip->posbuf);
- if (err < 0) {
- snd_printk(KERN_ERR SFX "%s: cannot allocate posbuf\n", pci_name(chip->pci));
- return -ENOMEM;
- }
- mark_pages_wc(chip, &chip->posbuf, true);
- /* allocate CORB/RIRB */
- err = azx_alloc_cmd_io(chip);
+ err = azx_alloc_stream_pages(chip);
if (err < 0)
return err;
@@ -3757,7 +1372,7 @@ static int azx_first_init(struct azx *chip)
/* codec detection */
if (!chip->codec_mask) {
- snd_printk(KERN_ERR SFX "%s: no codecs found!\n", pci_name(chip->pci));
+ dev_err(card->dev, "no codecs found!\n");
return -ENODEV;
}
@@ -3793,8 +1408,7 @@ static void azx_firmware_cb(const struct firmware *fw, void *context)
struct pci_dev *pci = chip->pci;
if (!fw) {
- snd_printk(KERN_ERR SFX "%s: Cannot load firmware, aborting\n",
- pci_name(chip->pci));
+ dev_err(card->dev, "Cannot load firmware, aborting\n");
goto error;
}
@@ -3812,6 +1426,132 @@ static void azx_firmware_cb(const struct firmware *fw, void *context)
}
#endif
+/*
+ * HDA controller ops.
+ */
+
+/* PCI register access. */
+static void pci_azx_writel(u32 value, u32 __iomem *addr)
+{
+ writel(value, addr);
+}
+
+static u32 pci_azx_readl(u32 __iomem *addr)
+{
+ return readl(addr);
+}
+
+static void pci_azx_writew(u16 value, u16 __iomem *addr)
+{
+ writew(value, addr);
+}
+
+static u16 pci_azx_readw(u16 __iomem *addr)
+{
+ return readw(addr);
+}
+
+static void pci_azx_writeb(u8 value, u8 __iomem *addr)
+{
+ writeb(value, addr);
+}
+
+static u8 pci_azx_readb(u8 __iomem *addr)
+{
+ return readb(addr);
+}
+
+static int disable_msi_reset_irq(struct azx *chip)
+{
+ int err;
+
+ free_irq(chip->irq, chip);
+ chip->irq = -1;
+ pci_disable_msi(chip->pci);
+ chip->msi = 0;
+ err = azx_acquire_irq(chip, 1);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/* DMA page allocation helpers. */
+static int dma_alloc_pages(struct azx *chip,
+ int type,
+ size_t size,
+ struct snd_dma_buffer *buf)
+{
+ int err;
+
+ err = snd_dma_alloc_pages(type,
+ chip->card->dev,
+ size, buf);
+ if (err < 0)
+ return err;
+ mark_pages_wc(chip, buf, true);
+ return 0;
+}
+
+static void dma_free_pages(struct azx *chip, struct snd_dma_buffer *buf)
+{
+ mark_pages_wc(chip, buf, false);
+ snd_dma_free_pages(buf);
+}
+
+static int substream_alloc_pages(struct azx *chip,
+ struct snd_pcm_substream *substream,
+ size_t size)
+{
+ struct azx_dev *azx_dev = get_azx_dev(substream);
+ int ret;
+
+ mark_runtime_wc(chip, azx_dev, substream, false);
+ azx_dev->bufsize = 0;
+ azx_dev->period_bytes = 0;
+ azx_dev->format_val = 0;
+ ret = snd_pcm_lib_malloc_pages(substream, size);
+ if (ret < 0)
+ return ret;
+ mark_runtime_wc(chip, azx_dev, substream, true);
+ return 0;
+}
+
+static int substream_free_pages(struct azx *chip,
+ struct snd_pcm_substream *substream)
+{
+ struct azx_dev *azx_dev = get_azx_dev(substream);
+ mark_runtime_wc(chip, azx_dev, substream, false);
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
+ struct vm_area_struct *area)
+{
+#ifdef CONFIG_X86
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ struct azx *chip = apcm->chip;
+ if (!azx_snoop(chip))
+ area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
+#endif
+}
+
+static const struct hda_controller_ops pci_hda_ops = {
+ .reg_writel = pci_azx_writel,
+ .reg_readl = pci_azx_readl,
+ .reg_writew = pci_azx_writew,
+ .reg_readw = pci_azx_readw,
+ .reg_writeb = pci_azx_writeb,
+ .reg_readb = pci_azx_readb,
+ .disable_msi_reset_irq = disable_msi_reset_irq,
+ .dma_alloc_pages = dma_alloc_pages,
+ .dma_free_pages = dma_free_pages,
+ .substream_alloc_pages = substream_alloc_pages,
+ .substream_free_pages = substream_free_pages,
+ .pcm_mmap_prepare = pcm_mmap_prepare,
+ .position_check = azx_position_check,
+};
+
static int azx_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
@@ -3828,15 +1568,15 @@ static int azx_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0) {
- snd_printk(KERN_ERR "hda-intel: Error creating card!\n");
+ dev_err(&pci->dev, "Error creating card!\n");
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
- err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
+ err = azx_create(card, pci, dev, pci_id->driver_data,
+ &pci_hda_ops, &chip);
if (err < 0)
goto out_free;
card->private_data = chip;
@@ -3845,15 +1585,13 @@ static int azx_probe(struct pci_dev *pci,
err = register_vga_switcheroo(chip);
if (err < 0) {
- snd_printk(KERN_ERR SFX
- "%s: Error registering VGA-switcheroo client\n", pci_name(pci));
+ dev_err(card->dev, "Error registering VGA-switcheroo client\n");
goto out_free;
}
if (check_hdmi_disabled(pci)) {
- snd_printk(KERN_INFO SFX "%s: VGA controller is disabled\n",
- pci_name(pci));
- snd_printk(KERN_INFO SFX "%s: Delaying initialization\n", pci_name(pci));
+ dev_info(card->dev, "VGA controller is disabled\n");
+ dev_info(card->dev, "Delaying initialization\n");
chip->disabled = true;
}
@@ -3861,8 +1599,8 @@ static int azx_probe(struct pci_dev *pci,
#ifdef CONFIG_SND_HDA_PATCH_LOADER
if (patch[dev] && *patch[dev]) {
- snd_printk(KERN_ERR SFX "%s: Applying patch firmware '%s'\n",
- pci_name(pci), patch[dev]);
+ dev_info(card->dev, "Applying patch firmware '%s'\n",
+ patch[dev]);
err = request_firmware_nowait(THIS_MODULE, true, patch[dev],
&pci->dev, GFP_KERNEL, card,
azx_firmware_cb);
@@ -3874,7 +1612,7 @@ static int azx_probe(struct pci_dev *pci,
#ifndef CONFIG_SND_HDA_I915
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- snd_printk(KERN_ERR SFX "Haswell must build in CONFIG_SND_HDA_I915\n");
+ dev_err(card->dev, "Haswell must build in CONFIG_SND_HDA_I915\n");
#endif
if (schedule_probe)
@@ -3890,6 +1628,12 @@ out_free:
return err;
}
+/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
+static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = {
+ [AZX_DRIVER_NVIDIA] = 8,
+ [AZX_DRIVER_TERA] = 1,
+};
+
static int azx_probe_continue(struct azx *chip)
{
struct pci_dev *pci = chip->pci;
@@ -3901,7 +1645,8 @@ static int azx_probe_continue(struct azx *chip)
#ifdef CONFIG_SND_HDA_I915
err = hda_i915_init();
if (err < 0) {
- snd_printk(KERN_ERR SFX "Error request power-well from i915\n");
+ dev_err(chip->card->dev,
+ "Error request power-well from i915\n");
goto out_free;
}
#endif
@@ -3917,7 +1662,10 @@ static int azx_probe_continue(struct azx *chip)
#endif
/* create codec instances */
- err = azx_codec_create(chip, model[dev]);
+ err = azx_codec_create(chip, model[dev],
+ azx_max_codecs[chip->driver_type],
+ power_save_addr);
+
if (err < 0)
goto out_free;
#ifdef CONFIG_SND_HDA_PATCH_LOADER
@@ -4142,7 +1890,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
.driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
{ PCI_DEVICE(0x1102, 0x0012),
.driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
-#if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE)
+#if !IS_ENABLED(CONFIG_SND_CTXFI)
/* the following entry conflicts with snd-ctxfi driver,
* as ctxfi driver mutates from HD-audio to native mode with
* a special command sequence.
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index da80c5bd7fd4..e51d15529215 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -597,23 +597,10 @@ int snd_hda_create_hwdep(struct hda_codec *codec);
static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
#endif
-#if defined(CONFIG_PM) && defined(CONFIG_SND_HDA_HWDEP)
-int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec);
-#else
-static inline int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
-{
- return 0;
-}
-#endif
+void snd_hda_sysfs_init(struct hda_codec *codec);
+void snd_hda_sysfs_clear(struct hda_codec *codec);
-#ifdef CONFIG_SND_HDA_RECONFIG
-int snd_hda_hwdep_add_sysfs(struct hda_codec *codec);
-#else
-static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
-{
- return 0;
-}
-#endif
+extern const struct attribute_group *snd_hda_dev_attr_groups[];
#ifdef CONFIG_SND_HDA_RECONFIG
const char *snd_hda_get_hint(struct hda_codec *codec, const char *key);
@@ -771,4 +758,11 @@ void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
+/*
+ */
+#define codec_err(codec, fmt, args...) dev_err(&(codec)->dev, fmt, ##args)
+#define codec_warn(codec, fmt, args...) dev_warn(&(codec)->dev, fmt, ##args)
+#define codec_info(codec, fmt, args...) dev_info(&(codec)->dev, fmt, ##args)
+#define codec_dbg(codec, fmt, args...) dev_dbg(&(codec)->dev, fmt, ##args)
+
#endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h
new file mode 100644
index 000000000000..ba38b819f984
--- /dev/null
+++ b/sound/pci/hda/hda_priv.h
@@ -0,0 +1,463 @@
+/*
+ * Common defines for the alsa driver code base for HD Audio.
+ *
+ * This program is free software; 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.
+ */
+
+#ifndef __SOUND_HDA_PRIV_H
+#define __SOUND_HDA_PRIV_H
+
+#include <linux/clocksource.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+/*
+ * registers
+ */
+#define ICH6_REG_GCAP 0x00
+#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */
+#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */
+#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */
+#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */
+#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */
+#define ICH6_REG_VMIN 0x02
+#define ICH6_REG_VMAJ 0x03
+#define ICH6_REG_OUTPAY 0x04
+#define ICH6_REG_INPAY 0x06
+#define ICH6_REG_GCTL 0x08
+#define ICH6_GCTL_RESET (1 << 0) /* controller reset */
+#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */
+#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */
+#define ICH6_REG_WAKEEN 0x0c
+#define ICH6_REG_STATESTS 0x0e
+#define ICH6_REG_GSTS 0x10
+#define ICH6_GSTS_FSTS (1 << 1) /* flush status */
+#define ICH6_REG_INTCTL 0x20
+#define ICH6_REG_INTSTS 0x24
+#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */
+#define ICH6_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */
+#define ICH6_REG_SSYNC 0x38
+#define ICH6_REG_CORBLBASE 0x40
+#define ICH6_REG_CORBUBASE 0x44
+#define ICH6_REG_CORBWP 0x48
+#define ICH6_REG_CORBRP 0x4a
+#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */
+#define ICH6_REG_CORBCTL 0x4c
+#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */
+#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */
+#define ICH6_REG_CORBSTS 0x4d
+#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */
+#define ICH6_REG_CORBSIZE 0x4e
+
+#define ICH6_REG_RIRBLBASE 0x50
+#define ICH6_REG_RIRBUBASE 0x54
+#define ICH6_REG_RIRBWP 0x58
+#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */
+#define ICH6_REG_RINTCNT 0x5a
+#define ICH6_REG_RIRBCTL 0x5c
+#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */
+#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */
+#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */
+#define ICH6_REG_RIRBSTS 0x5d
+#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */
+#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */
+#define ICH6_REG_RIRBSIZE 0x5e
+
+#define ICH6_REG_IC 0x60
+#define ICH6_REG_IR 0x64
+#define ICH6_REG_IRS 0x68
+#define ICH6_IRS_VALID (1<<1)
+#define ICH6_IRS_BUSY (1<<0)
+
+#define ICH6_REG_DPLBASE 0x70
+#define ICH6_REG_DPUBASE 0x74
+#define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */
+
+/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
+
+/* stream register offsets from stream base */
+#define ICH6_REG_SD_CTL 0x00
+#define ICH6_REG_SD_STS 0x03
+#define ICH6_REG_SD_LPIB 0x04
+#define ICH6_REG_SD_CBL 0x08
+#define ICH6_REG_SD_LVI 0x0c
+#define ICH6_REG_SD_FIFOW 0x0e
+#define ICH6_REG_SD_FIFOSIZE 0x10
+#define ICH6_REG_SD_FORMAT 0x12
+#define ICH6_REG_SD_BDLPL 0x18
+#define ICH6_REG_SD_BDLPU 0x1c
+
+/* PCI space */
+#define ICH6_PCIREG_TCSEL 0x44
+
+/*
+ * other constants
+ */
+
+/* max number of SDs */
+/* ICH, ATI and VIA have 4 playback and 4 capture */
+#define ICH6_NUM_CAPTURE 4
+#define ICH6_NUM_PLAYBACK 4
+
+/* ULI has 6 playback and 5 capture */
+#define ULI_NUM_CAPTURE 5
+#define ULI_NUM_PLAYBACK 6
+
+/* ATI HDMI may have up to 8 playbacks and 0 capture */
+#define ATIHDMI_NUM_CAPTURE 0
+#define ATIHDMI_NUM_PLAYBACK 8
+
+/* TERA has 4 playback and 3 capture */
+#define TERA_NUM_CAPTURE 3
+#define TERA_NUM_PLAYBACK 4
+
+/* this number is statically defined for simplicity */
+#define MAX_AZX_DEV 16
+
+/* max number of fragments - we may use more if allocating more pages for BDL */
+#define BDL_SIZE 4096
+#define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16)
+#define AZX_MAX_FRAG 32
+/* max buffer size - no h/w limit, you can increase as you like */
+#define AZX_MAX_BUF_SIZE (1024*1024*1024)
+
+/* RIRB int mask: overrun[2], response[0] */
+#define RIRB_INT_RESPONSE 0x01
+#define RIRB_INT_OVERRUN 0x04
+#define RIRB_INT_MASK 0x05
+
+/* STATESTS int mask: S3,SD2,SD1,SD0 */
+#define AZX_MAX_CODECS 8
+#define AZX_DEFAULT_CODECS 4
+#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1)
+
+/* SD_CTL bits */
+#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
+#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */
+#define SD_CTL_STRIPE (3 << 16) /* stripe control */
+#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */
+#define SD_CTL_DIR (1 << 19) /* bi-directional stream */
+#define SD_CTL_STREAM_TAG_MASK (0xf << 20)
+#define SD_CTL_STREAM_TAG_SHIFT 20
+
+/* SD_CTL and SD_STS */
+#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */
+#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */
+#define SD_INT_COMPLETE 0x04 /* completion interrupt */
+#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
+ SD_INT_COMPLETE)
+
+/* SD_STS */
+#define SD_STS_FIFO_READY 0x20 /* FIFO ready */
+
+/* INTCTL and INTSTS */
+#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */
+#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */
+#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */
+
+/* below are so far hardcoded - should read registers in future */
+#define ICH6_MAX_CORB_ENTRIES 256
+#define ICH6_MAX_RIRB_ENTRIES 256
+
+/* driver quirks (capabilities) */
+/* bits 0-7 are used for indicating driver type */
+#define AZX_DCAPS_NO_TCSEL (1 << 8) /* No Intel TCSEL bit */
+#define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */
+#define AZX_DCAPS_ATI_SNOOP (1 << 10) /* ATI snoop enable */
+#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11) /* Nvidia snoop enable */
+#define AZX_DCAPS_SCH_SNOOP (1 << 12) /* SCH/PCH snoop enable */
+#define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */
+#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */
+#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */
+#define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */
+#define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */
+#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */
+#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */
+#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */
+#define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */
+#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */
+#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */
+#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
+#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */
+#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */
+
+/* position fix mode */
+enum {
+ POS_FIX_AUTO,
+ POS_FIX_LPIB,
+ POS_FIX_POSBUF,
+ POS_FIX_VIACOMBO,
+ POS_FIX_COMBO,
+};
+
+/* Defines for ATI HD Audio support in SB450 south bridge */
+#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42
+#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02
+
+/* Defines for Nvidia HDA support */
+#define NVIDIA_HDA_TRANSREG_ADDR 0x4e
+#define NVIDIA_HDA_ENABLE_COHBITS 0x0f
+#define NVIDIA_HDA_ISTRM_COH 0x4d
+#define NVIDIA_HDA_OSTRM_COH 0x4c
+#define NVIDIA_HDA_ENABLE_COHBIT 0x01
+
+/* Defines for Intel SCH HDA snoop control */
+#define INTEL_SCH_HDA_DEVC 0x78
+#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11)
+
+/* Define IN stream 0 FIFO size offset in VIA controller */
+#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90
+/* Define VIA HD Audio Device ID*/
+#define VIA_HDAC_DEVICE_ID 0x3288
+
+/* HD Audio class code */
+#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
+
+struct azx_dev {
+ struct snd_dma_buffer bdl; /* BDL buffer */
+ u32 *posbuf; /* position buffer pointer */
+
+ unsigned int bufsize; /* size of the play buffer in bytes */
+ unsigned int period_bytes; /* size of the period in bytes */
+ unsigned int frags; /* number for period in the play buffer */
+ unsigned int fifo_size; /* FIFO size */
+ unsigned long start_wallclk; /* start + minimum wallclk */
+ unsigned long period_wallclk; /* wallclk for period */
+
+ void __iomem *sd_addr; /* stream descriptor pointer */
+
+ u32 sd_int_sta_mask; /* stream int status mask */
+
+ /* pcm support */
+ struct snd_pcm_substream *substream; /* assigned substream,
+ * set in PCM open
+ */
+ unsigned int format_val; /* format value to be set in the
+ * controller and the codec
+ */
+ unsigned char stream_tag; /* assigned stream */
+ unsigned char index; /* stream index */
+ int assigned_key; /* last device# key assigned to */
+
+ unsigned int opened:1;
+ unsigned int running:1;
+ unsigned int irq_pending:1;
+ unsigned int prepared:1;
+ unsigned int locked:1;
+ /*
+ * For VIA:
+ * A flag to ensure DMA position is 0
+ * when link position is not greater than FIFO size
+ */
+ unsigned int insufficient:1;
+ unsigned int wc_marked:1;
+ unsigned int no_period_wakeup:1;
+
+ struct timecounter azx_tc;
+ struct cyclecounter azx_cc;
+
+ int delay_negative_threshold;
+
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+ /* Allows dsp load to have sole access to the playback stream. */
+ struct mutex dsp_mutex;
+#endif
+};
+
+/* CORB/RIRB */
+struct azx_rb {
+ u32 *buf; /* CORB/RIRB buffer
+ * Each CORB entry is 4byte, RIRB is 8byte
+ */
+ dma_addr_t addr; /* physical address of CORB/RIRB buffer */
+ /* for RIRB */
+ unsigned short rp, wp; /* read/write pointers */
+ int cmds[AZX_MAX_CODECS]; /* number of pending requests */
+ u32 res[AZX_MAX_CODECS]; /* last read value */
+};
+
+struct azx;
+
+/* Functions to read/write to hda registers. */
+struct hda_controller_ops {
+ /* Register Access */
+ void (*reg_writel)(u32 value, u32 __iomem *addr);
+ u32 (*reg_readl)(u32 __iomem *addr);
+ void (*reg_writew)(u16 value, u16 __iomem *addr);
+ u16 (*reg_readw)(u16 __iomem *addr);
+ void (*reg_writeb)(u8 value, u8 __iomem *addr);
+ u8 (*reg_readb)(u8 __iomem *addr);
+ /* Disable msi if supported, PCI only */
+ int (*disable_msi_reset_irq)(struct azx *);
+ /* Allocation ops */
+ int (*dma_alloc_pages)(struct azx *chip,
+ int type,
+ size_t size,
+ struct snd_dma_buffer *buf);
+ void (*dma_free_pages)(struct azx *chip, struct snd_dma_buffer *buf);
+ int (*substream_alloc_pages)(struct azx *chip,
+ struct snd_pcm_substream *substream,
+ size_t size);
+ int (*substream_free_pages)(struct azx *chip,
+ struct snd_pcm_substream *substream);
+ void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
+ struct vm_area_struct *area);
+ /* Check if current position is acceptable */
+ int (*position_check)(struct azx *chip, struct azx_dev *azx_dev);
+};
+
+struct azx_pcm {
+ struct azx *chip;
+ struct snd_pcm *pcm;
+ struct hda_codec *codec;
+ struct hda_pcm_stream *hinfo[2];
+ struct list_head list;
+};
+
+struct azx {
+ struct snd_card *card;
+ struct pci_dev *pci;
+ int dev_index;
+
+ /* chip type specific */
+ int driver_type;
+ unsigned int driver_caps;
+ int playback_streams;
+ int playback_index_offset;
+ int capture_streams;
+ int capture_index_offset;
+ int num_streams;
+ const int *jackpoll_ms; /* per-card jack poll interval */
+
+ /* Register interaction. */
+ const struct hda_controller_ops *ops;
+
+ /* pci resources */
+ unsigned long addr;
+ void __iomem *remap_addr;
+ int irq;
+
+ /* locks */
+ spinlock_t reg_lock;
+ struct mutex open_mutex; /* Prevents concurrent open/close operations */
+ struct completion probe_wait;
+
+ /* streams (x num_streams) */
+ struct azx_dev *azx_dev;
+
+ /* PCM */
+ struct list_head pcm_list; /* azx_pcm list */
+
+ /* HD codec */
+ unsigned short codec_mask;
+ int codec_probe_mask; /* copied from probe_mask option */
+ struct hda_bus *bus;
+ unsigned int beep_mode;
+
+ /* CORB/RIRB */
+ struct azx_rb corb;
+ struct azx_rb rirb;
+
+ /* CORB/RIRB and position buffers */
+ struct snd_dma_buffer rb;
+ struct snd_dma_buffer posbuf;
+
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+ const struct firmware *fw;
+#endif
+
+ /* flags */
+ int position_fix[2]; /* for both playback/capture streams */
+ const int *bdl_pos_adj;
+ int poll_count;
+ unsigned int running:1;
+ unsigned int initialized:1;
+ unsigned int single_cmd:1;
+ unsigned int polling_mode:1;
+ unsigned int msi:1;
+ unsigned int irq_pending_warned:1;
+ unsigned int probing:1; /* codec probing phase */
+ unsigned int snoop:1;
+ unsigned int align_buffer_size:1;
+ unsigned int region_requested:1;
+
+ /* VGA-switcheroo setup */
+ unsigned int use_vga_switcheroo:1;
+ unsigned int vga_switcheroo_registered:1;
+ unsigned int init_failed:1; /* delayed init failed */
+ unsigned int disabled:1; /* disabled by VGA-switcher */
+
+ /* for debugging */
+ unsigned int last_cmd[AZX_MAX_CODECS];
+
+ /* for pending irqs */
+ struct work_struct irq_pending_work;
+
+ struct work_struct probe_work;
+
+ /* reboot notifier (for mysterious hangup problem at power-down) */
+ struct notifier_block reboot_notifier;
+
+ /* card list (for power_save trigger) */
+ struct list_head list;
+
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+ struct azx_dev saved_azx_dev;
+#endif
+
+ /* secondary power domain for hdmi audio under vga device */
+ struct dev_pm_domain hdmi_pm_domain;
+};
+
+#ifdef CONFIG_SND_VERBOSE_PRINTK
+#define SFX /* nop */
+#else
+#define SFX "hda-intel "
+#endif
+
+#ifdef CONFIG_X86
+#define azx_snoop(chip) ((chip)->snoop)
+#else
+#define azx_snoop(chip) true
+#endif
+
+/*
+ * macros for easy use
+ */
+
+#define azx_writel(chip, reg, value) \
+ ((chip)->ops->reg_writel(value, (chip)->remap_addr + ICH6_REG_##reg))
+#define azx_readl(chip, reg) \
+ ((chip)->ops->reg_readl((chip)->remap_addr + ICH6_REG_##reg))
+#define azx_writew(chip, reg, value) \
+ ((chip)->ops->reg_writew(value, (chip)->remap_addr + ICH6_REG_##reg))
+#define azx_readw(chip, reg) \
+ ((chip)->ops->reg_readw((chip)->remap_addr + ICH6_REG_##reg))
+#define azx_writeb(chip, reg, value) \
+ ((chip)->ops->reg_writeb(value, (chip)->remap_addr + ICH6_REG_##reg))
+#define azx_readb(chip, reg) \
+ ((chip)->ops->reg_readb((chip)->remap_addr + ICH6_REG_##reg))
+
+#define azx_sd_writel(chip, dev, reg, value) \
+ ((chip)->ops->reg_writel(value, (dev)->sd_addr + ICH6_REG_##reg))
+#define azx_sd_readl(chip, dev, reg) \
+ ((chip)->ops->reg_readl((dev)->sd_addr + ICH6_REG_##reg))
+#define azx_sd_writew(chip, dev, reg, value) \
+ ((chip)->ops->reg_writew(value, (dev)->sd_addr + ICH6_REG_##reg))
+#define azx_sd_readw(chip, dev, reg) \
+ ((chip)->ops->reg_readw((dev)->sd_addr + ICH6_REG_##reg))
+#define azx_sd_writeb(chip, dev, reg, value) \
+ ((chip)->ops->reg_writeb(value, (dev)->sd_addr + ICH6_REG_##reg))
+#define azx_sd_readb(chip, dev, reg) \
+ ((chip)->ops->reg_readb((dev)->sd_addr + ICH6_REG_##reg))
+
+#endif /* __SOUND_HDA_PRIV_H */
diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c
new file mode 100644
index 000000000000..e2079090ca6f
--- /dev/null
+++ b/sound/pci/hda/hda_sysfs.c
@@ -0,0 +1,780 @@
+/*
+ * sysfs interface for HD-audio codec
+ *
+ * Copyright (c) 2014 Takashi Iwai <tiwai@suse.de>
+ *
+ * split from hda_hwdep.c
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/compat.h>
+#include <linux/mutex.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+#include <sound/hda_hwdep.h>
+#include <sound/minors.h>
+
+/* hint string pair */
+struct hda_hint {
+ const char *key;
+ const char *val; /* contained in the same alloc as key */
+};
+
+#ifdef CONFIG_PM
+static ssize_t power_on_acct_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hda_codec *codec = dev_get_drvdata(dev);
+ snd_hda_update_power_acct(codec);
+ return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
+}
+
+static ssize_t power_off_acct_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hda_codec *codec = dev_get_drvdata(dev);
+ snd_hda_update_power_acct(codec);
+ return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
+}
+
+static DEVICE_ATTR_RO(power_on_acct);
+static DEVICE_ATTR_RO(power_off_acct);
+#endif /* CONFIG_PM */
+
+#define CODEC_INFO_SHOW(type) \
+static ssize_t type##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct hda_codec *codec = dev_get_drvdata(dev); \
+ return sprintf(buf, "0x%x\n", codec->type); \
+}
+
+#define CODEC_INFO_STR_SHOW(type) \
+static ssize_t type##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct hda_codec *codec = dev_get_drvdata(dev); \
+ return sprintf(buf, "%s\n", \
+ codec->type ? codec->type : ""); \
+}
+
+CODEC_INFO_SHOW(vendor_id);
+CODEC_INFO_SHOW(subsystem_id);
+CODEC_INFO_SHOW(revision_id);
+CODEC_INFO_SHOW(afg);
+CODEC_INFO_SHOW(mfg);
+CODEC_INFO_STR_SHOW(vendor_name);
+CODEC_INFO_STR_SHOW(chip_name);
+CODEC_INFO_STR_SHOW(modelname);
+
+static ssize_t pin_configs_show(struct hda_codec *codec,
+ struct snd_array *list,
+ char *buf)
+{
+ int i, len = 0;
+ mutex_lock(&codec->user_mutex);
+ for (i = 0; i < list->used; i++) {
+ struct hda_pincfg *pin = snd_array_elem(list, i);
+ len += sprintf(buf + len, "0x%02x 0x%08x\n",
+ pin->nid, pin->cfg);
+ }
+ mutex_unlock(&codec->user_mutex);
+ return len;
+}
+
+static ssize_t init_pin_configs_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hda_codec *codec = dev_get_drvdata(dev);
+ return pin_configs_show(codec, &codec->init_pins, buf);
+}
+
+static ssize_t driver_pin_configs_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hda_codec *codec = dev_get_drvdata(dev);
+ return pin_configs_show(codec, &codec->driver_pins, buf);
+}
+
+#ifdef CONFIG_SND_HDA_RECONFIG
+
+/*
+ * sysfs interface
+ */
+
+static int clear_codec(struct hda_codec *codec)
+{
+ int err;
+
+ err = snd_hda_codec_reset(codec);
+ if (err < 0) {
+ codec_err(codec, "The codec is being used, can't free.\n");
+ return err;
+ }
+ snd_hda_sysfs_clear(codec);
+ return 0;
+}
+
+static int reconfig_codec(struct hda_codec *codec)
+{
+ int err;
+
+ snd_hda_power_up(codec);
+ codec_info(codec, "hda-codec: reconfiguring\n");
+ err = snd_hda_codec_reset(codec);
+ if (err < 0) {
+ codec_err(codec,
+ "The codec is being used, can't reconfigure.\n");
+ goto error;
+ }
+ err = snd_hda_codec_configure(codec);
+ if (err < 0)
+ goto error;
+ /* rebuild PCMs */
+ err = snd_hda_codec_build_pcms(codec);
+ if (err < 0)
+ goto error;
+ /* rebuild mixers */
+ err = snd_hda_codec_build_controls(codec);
+ if (err < 0)
+ goto error;
+ err = snd_card_register(codec->bus->card);
+ error:
+ snd_hda_power_down(codec);
+ return err;
+}
+
+/*
+ * allocate a string at most len chars, and remove the trailing EOL
+ */
+static char *kstrndup_noeol(const char *src, size_t len)
+{
+ char *s = kstrndup(src, len, GFP_KERNEL);
+ char *p;
+ if (!s)
+ return NULL;
+ p = strchr(s, '\n');
+ if (p)
+ *p = 0;
+ return s;
+}
+
+#define CODEC_INFO_STORE(type) \
+static ssize_t type##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct hda_codec *codec = dev_get_drvdata(dev); \
+ unsigned long val; \
+ int err = kstrtoul(buf, 0, &val); \
+ if (err < 0) \
+ return err; \
+ codec->type = val; \
+ return count; \
+}
+
+#define CODEC_INFO_STR_STORE(type) \
+static ssize_t type##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct hda_codec *codec = dev_get_drvdata(dev); \
+ char *s = kstrndup_noeol(buf, 64); \
+ if (!s) \
+ return -ENOMEM; \
+ kfree(codec->type); \
+ codec->type = s; \
+ return count; \
+}
+
+CODEC_INFO_STORE(vendor_id);
+CODEC_INFO_STORE(subsystem_id);
+CODEC_INFO_STORE(revision_id);
+CODEC_INFO_STR_STORE(vendor_name);
+CODEC_INFO_STR_STORE(chip_name);
+CODEC_INFO_STR_STORE(modelname);
+
+#define CODEC_ACTION_STORE(type) \
+static ssize_t type##_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct hda_codec *codec = dev_get_drvdata(dev); \
+ int err = 0; \
+ if (*buf) \
+ err = type##_codec(codec); \
+ return err < 0 ? err : count; \
+}
+
+CODEC_ACTION_STORE(reconfig);
+CODEC_ACTION_STORE(clear);
+
+static ssize_t init_verbs_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hda_codec *codec = dev_get_drvdata(dev);
+ int i, len = 0;
+ mutex_lock(&codec->user_mutex);
+ for (i = 0; i < codec->init_verbs.used; i++) {
+ struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "0x%02x 0x%03x 0x%04x\n",
+ v->nid, v->verb, v->param);
+ }
+ mutex_unlock(&codec->user_mutex);
+ return len;
+}
+
+static int parse_init_verbs(struct hda_codec *codec, const char *buf)
+{
+ struct hda_verb *v;
+ int nid, verb, param;
+
+ if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
+ return -EINVAL;
+ if (!nid || !verb)
+ return -EINVAL;
+ mutex_lock(&codec->user_mutex);
+ v = snd_array_new(&codec->init_verbs);
+ if (!v) {
+ mutex_unlock(&codec->user_mutex);
+ return -ENOMEM;
+ }
+ v->nid = nid;
+ v->verb = verb;
+ v->param = param;
+ mutex_unlock(&codec->user_mutex);
+ return 0;
+}
+
+static ssize_t init_verbs_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hda_codec *codec = dev_get_drvdata(dev);
+ int err = parse_init_verbs(codec, buf);
+ if (err < 0)
+ return err;
+ return count;
+}
+
+static ssize_t hints_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hda_codec *codec = dev_get_drvdata(dev);
+ int i, len = 0;
+ mutex_lock(&codec->user_mutex);
+ for (i = 0; i < codec->hints.used; i++) {
+ struct hda_hint *hint = snd_array_elem(&codec->hints, i);
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "%s = %s\n", hint->key, hint->val);
+ }
+ mutex_unlock(&codec->user_mutex);
+ return len;
+}
+
+static struct hda_hint *get_hint(struct hda_codec *codec, const char *key)
+{
+ int i;
+
+ for (i = 0; i < codec->hints.used; i++) {
+ struct hda_hint *hint = snd_array_elem(&codec->hints, i);
+ if (!strcmp(hint->key, key))
+ return hint;
+ }
+ return NULL;
+}
+
+static void remove_trail_spaces(char *str)
+{
+ char *p;
+ if (!*str)
+ return;
+ p = str + strlen(str) - 1;
+ for (; isspace(*p); p--) {
+ *p = 0;
+ if (p == str)
+ return;
+ }
+}
+
+#define MAX_HINTS 1024
+
+static int parse_hints(struct hda_codec *codec, const char *buf)
+{
+ char *key, *val;
+ struct hda_hint *hint;
+ int err = 0;
+
+ buf = skip_spaces(buf);
+ if (!*buf || *buf == '#' || *buf == '\n')
+ return 0;
+ if (*buf == '=')
+ return -EINVAL;
+ key = kstrndup_noeol(buf, 1024);
+ if (!key)
+ return -ENOMEM;
+ /* extract key and val */
+ val = strchr(key, '=');
+ if (!val) {
+ kfree(key);
+ return -EINVAL;
+ }
+ *val++ = 0;
+ val = skip_spaces(val);
+ remove_trail_spaces(key);
+ remove_trail_spaces(val);
+ mutex_lock(&codec->user_mutex);
+ hint = get_hint(codec, key);
+ if (hint) {
+ /* replace */
+ kfree(hint->key);
+ hint->key = key;
+ hint->val = val;
+ goto unlock;
+ }
+ /* allocate a new hint entry */
+ if (codec->hints.used >= MAX_HINTS)
+ hint = NULL;
+ else
+ hint = snd_array_new(&codec->hints);
+ if (hint) {
+ hint->key = key;
+ hint->val = val;
+ } else {
+ err = -ENOMEM;
+ }
+ unlock:
+ mutex_unlock(&codec->user_mutex);
+ if (err)
+ kfree(key);
+ return err;
+}
+
+static ssize_t hints_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hda_codec *codec = dev_get_drvdata(dev);
+ int err = parse_hints(codec, buf);
+ if (err < 0)
+ return err;
+ return count;
+}
+
+static ssize_t user_pin_configs_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hda_codec *codec = dev_get_drvdata(dev);
+ return pin_configs_show(codec, &codec->user_pins, buf);
+}
+
+#define MAX_PIN_CONFIGS 32
+
+static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
+{
+ int nid, cfg, err;
+
+ if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
+ return -EINVAL;
+ if (!nid)
+ return -EINVAL;
+ mutex_lock(&codec->user_mutex);
+ err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
+ mutex_unlock(&codec->user_mutex);
+ return err;
+}
+
+static ssize_t user_pin_configs_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hda_codec *codec = dev_get_drvdata(dev);
+ int err = parse_user_pin_configs(codec, buf);
+ if (err < 0)
+ return err;
+ return count;
+}
+
+/* sysfs attributes exposed only when CONFIG_SND_HDA_RECONFIG=y */
+static DEVICE_ATTR_RW(init_verbs);
+static DEVICE_ATTR_RW(hints);
+static DEVICE_ATTR_RW(user_pin_configs);
+static DEVICE_ATTR_WO(reconfig);
+static DEVICE_ATTR_WO(clear);
+
+/*
+ * Look for hint string
+ */
+const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
+{
+ struct hda_hint *hint = get_hint(codec, key);
+ return hint ? hint->val : NULL;
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_hint);
+
+int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
+{
+ const char *p;
+ int ret;
+
+ mutex_lock(&codec->user_mutex);
+ p = snd_hda_get_hint(codec, key);
+ if (!p || !*p)
+ ret = -ENOENT;
+ else {
+ switch (toupper(*p)) {
+ case 'T': /* true */
+ case 'Y': /* yes */
+ case '1':
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&codec->user_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
+
+int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
+{
+ const char *p;
+ unsigned long val;
+ int ret;
+
+ mutex_lock(&codec->user_mutex);
+ p = snd_hda_get_hint(codec, key);
+ if (!p)
+ ret = -ENOENT;
+ else if (kstrtoul(p, 0, &val))
+ ret = -EINVAL;
+ else {
+ *valp = val;
+ ret = 0;
+ }
+ mutex_unlock(&codec->user_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
+#endif /* CONFIG_SND_HDA_RECONFIG */
+
+/*
+ * common sysfs attributes
+ */
+#ifdef CONFIG_SND_HDA_RECONFIG
+#define RECONFIG_DEVICE_ATTR(name) DEVICE_ATTR_RW(name)
+#else
+#define RECONFIG_DEVICE_ATTR(name) DEVICE_ATTR_RO(name)
+#endif
+static RECONFIG_DEVICE_ATTR(vendor_id);
+static RECONFIG_DEVICE_ATTR(subsystem_id);
+static RECONFIG_DEVICE_ATTR(revision_id);
+static DEVICE_ATTR_RO(afg);
+static DEVICE_ATTR_RO(mfg);
+static RECONFIG_DEVICE_ATTR(vendor_name);
+static RECONFIG_DEVICE_ATTR(chip_name);
+static RECONFIG_DEVICE_ATTR(modelname);
+static DEVICE_ATTR_RO(init_pin_configs);
+static DEVICE_ATTR_RO(driver_pin_configs);
+
+
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+
+/* parser mode */
+enum {
+ LINE_MODE_NONE,
+ LINE_MODE_CODEC,
+ LINE_MODE_MODEL,
+ LINE_MODE_PINCFG,
+ LINE_MODE_VERB,
+ LINE_MODE_HINT,
+ LINE_MODE_VENDOR_ID,
+ LINE_MODE_SUBSYSTEM_ID,
+ LINE_MODE_REVISION_ID,
+ LINE_MODE_CHIP_NAME,
+ NUM_LINE_MODES,
+};
+
+static inline int strmatch(const char *a, const char *b)
+{
+ return strnicmp(a, b, strlen(b)) == 0;
+}
+
+/* parse the contents after the line "[codec]"
+ * accept only the line with three numbers, and assign the current codec
+ */
+static void parse_codec_mode(char *buf, struct hda_bus *bus,
+ struct hda_codec **codecp)
+{
+ int vendorid, subid, caddr;
+ struct hda_codec *codec;
+
+ *codecp = NULL;
+ if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
+ list_for_each_entry(codec, &bus->codec_list, list) {
+ if ((vendorid <= 0 || codec->vendor_id == vendorid) &&
+ (subid <= 0 || codec->subsystem_id == subid) &&
+ codec->addr == caddr) {
+ *codecp = codec;
+ break;
+ }
+ }
+ }
+}
+
+/* parse the contents after the other command tags, [pincfg], [verb],
+ * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model]
+ * just pass to the sysfs helper (only when any codec was specified)
+ */
+static void parse_pincfg_mode(char *buf, struct hda_bus *bus,
+ struct hda_codec **codecp)
+{
+ parse_user_pin_configs(*codecp, buf);
+}
+
+static void parse_verb_mode(char *buf, struct hda_bus *bus,
+ struct hda_codec **codecp)
+{
+ parse_init_verbs(*codecp, buf);
+}
+
+static void parse_hint_mode(char *buf, struct hda_bus *bus,
+ struct hda_codec **codecp)
+{
+ parse_hints(*codecp, buf);
+}
+
+static void parse_model_mode(char *buf, struct hda_bus *bus,
+ struct hda_codec **codecp)
+{
+ kfree((*codecp)->modelname);
+ (*codecp)->modelname = kstrdup(buf, GFP_KERNEL);
+}
+
+static void parse_chip_name_mode(char *buf, struct hda_bus *bus,
+ struct hda_codec **codecp)
+{
+ kfree((*codecp)->chip_name);
+ (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL);
+}
+
+#define DEFINE_PARSE_ID_MODE(name) \
+static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
+ struct hda_codec **codecp) \
+{ \
+ unsigned long val; \
+ if (!kstrtoul(buf, 0, &val)) \
+ (*codecp)->name = val; \
+}
+
+DEFINE_PARSE_ID_MODE(vendor_id);
+DEFINE_PARSE_ID_MODE(subsystem_id);
+DEFINE_PARSE_ID_MODE(revision_id);
+
+
+struct hda_patch_item {
+ const char *tag;
+ const char *alias;
+ void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
+};
+
+static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
+ [LINE_MODE_CODEC] = {
+ .tag = "[codec]",
+ .parser = parse_codec_mode,
+ },
+ [LINE_MODE_MODEL] = {
+ .tag = "[model]",
+ .parser = parse_model_mode,
+ },
+ [LINE_MODE_VERB] = {
+ .tag = "[verb]",
+ .alias = "[init_verbs]",
+ .parser = parse_verb_mode,
+ },
+ [LINE_MODE_PINCFG] = {
+ .tag = "[pincfg]",
+ .alias = "[user_pin_configs]",
+ .parser = parse_pincfg_mode,
+ },
+ [LINE_MODE_HINT] = {
+ .tag = "[hint]",
+ .alias = "[hints]",
+ .parser = parse_hint_mode
+ },
+ [LINE_MODE_VENDOR_ID] = {
+ .tag = "[vendor_id]",
+ .parser = parse_vendor_id_mode,
+ },
+ [LINE_MODE_SUBSYSTEM_ID] = {
+ .tag = "[subsystem_id]",
+ .parser = parse_subsystem_id_mode,
+ },
+ [LINE_MODE_REVISION_ID] = {
+ .tag = "[revision_id]",
+ .parser = parse_revision_id_mode,
+ },
+ [LINE_MODE_CHIP_NAME] = {
+ .tag = "[chip_name]",
+ .parser = parse_chip_name_mode,
+ },
+};
+
+/* check the line starting with '[' -- change the parser mode accodingly */
+static int parse_line_mode(char *buf, struct hda_bus *bus)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(patch_items); i++) {
+ if (!patch_items[i].tag)
+ continue;
+ if (strmatch(buf, patch_items[i].tag))
+ return i;
+ if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
+ return i;
+ }
+ return LINE_MODE_NONE;
+}
+
+/* copy one line from the buffer in fw, and update the fields in fw
+ * return zero if it reaches to the end of the buffer, or non-zero
+ * if successfully copied a line
+ *
+ * the spaces at the beginning and the end of the line are stripped
+ */
+static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
+ const void **fw_data_p)
+{
+ int len;
+ size_t fw_size = *fw_size_p;
+ const char *p = *fw_data_p;
+
+ while (isspace(*p) && fw_size) {
+ p++;
+ fw_size--;
+ }
+ if (!fw_size)
+ return 0;
+
+ for (len = 0; len < fw_size; len++) {
+ if (!*p)
+ break;
+ if (*p == '\n') {
+ p++;
+ len++;
+ break;
+ }
+ if (len < size)
+ *buf++ = *p++;
+ }
+ *buf = 0;
+ *fw_size_p = fw_size - len;
+ *fw_data_p = p;
+ remove_trail_spaces(buf);
+ return 1;
+}
+
+/*
+ * load a "patch" firmware file and parse it
+ */
+int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
+{
+ char buf[128];
+ struct hda_codec *codec;
+ int line_mode;
+
+ line_mode = LINE_MODE_NONE;
+ codec = NULL;
+ while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
+ if (!*buf || *buf == '#' || *buf == '\n')
+ continue;
+ if (*buf == '[')
+ line_mode = parse_line_mode(buf, bus);
+ else if (patch_items[line_mode].parser &&
+ (codec || line_mode <= LINE_MODE_CODEC))
+ patch_items[line_mode].parser(buf, bus, &codec);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_load_patch);
+#endif /* CONFIG_SND_HDA_PATCH_LOADER */
+
+/*
+ * sysfs entries
+ */
+static struct attribute *hda_dev_attrs[] = {
+ &dev_attr_vendor_id.attr,
+ &dev_attr_subsystem_id.attr,
+ &dev_attr_revision_id.attr,
+ &dev_attr_afg.attr,
+ &dev_attr_mfg.attr,
+ &dev_attr_vendor_name.attr,
+ &dev_attr_chip_name.attr,
+ &dev_attr_modelname.attr,
+ &dev_attr_init_pin_configs.attr,
+ &dev_attr_driver_pin_configs.attr,
+#ifdef CONFIG_PM
+ &dev_attr_power_on_acct.attr,
+ &dev_attr_power_off_acct.attr,
+#endif
+#ifdef CONFIG_SND_HDA_RECONFIG
+ &dev_attr_init_verbs.attr,
+ &dev_attr_hints.attr,
+ &dev_attr_user_pin_configs.attr,
+ &dev_attr_reconfig.attr,
+ &dev_attr_clear.attr,
+#endif
+ NULL
+};
+
+static struct attribute_group hda_dev_attr_group = {
+ .attrs = hda_dev_attrs,
+};
+
+const struct attribute_group *snd_hda_dev_attr_groups[] = {
+ &hda_dev_attr_group,
+ NULL
+};
+
+void snd_hda_sysfs_init(struct hda_codec *codec)
+{
+ mutex_init(&codec->user_mutex);
+#ifdef CONFIG_SND_HDA_RECONFIG
+ snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
+ snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
+ snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
+#endif
+}
+
+void snd_hda_sysfs_clear(struct hda_codec *codec)
+{
+#ifdef CONFIG_SND_HDA_RECONFIG
+ int i;
+
+ /* clear init verbs */
+ snd_array_free(&codec->init_verbs);
+ /* clear hints */
+ for (i = 0; i < codec->hints.used; i++) {
+ struct hda_hint *hint = snd_array_elem(&codec->hints, i);
+ kfree(hint->key); /* we don't need to free hint->val */
+ }
+ snd_array_free(&codec->hints);
+ snd_array_free(&codec->user_pins);
+#endif
+}
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index df3652ad15ef..40ba06eb44af 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -21,7 +21,6 @@
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/module.h>
#include <sound/core.h>
@@ -1026,6 +1025,9 @@ static void ad1884_fixup_thinkpad(struct hda_codec *codec,
spec->gen.keep_eapd_on = 1;
spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
spec->eapd_nid = 0x12;
+ /* Analog PC Beeper - allow firmware/ACPI beeps */
+ spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT);
+ spec->gen.beep_nid = 0; /* no digital beep */
}
}
@@ -1092,6 +1094,7 @@ static int patch_ad1884(struct hda_codec *codec)
spec = codec->spec;
spec->gen.mixer_nid = 0x20;
+ spec->gen.mixer_merge_nid = 0x21;
spec->gen.beep_nid = 0x10;
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c
index 30b3a4bc06ee..5e65999e0d8e 100644
--- a/sound/pci/hda/patch_ca0110.c
+++ b/sound/pci/hda/patch_ca0110.c
@@ -20,7 +20,6 @@
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/module.h>
#include <sound/core.h>
#include "hda_codec.h"
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 54d14793725a..092f2bd030bd 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -24,7 +24,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/firmware.h>
@@ -868,7 +867,7 @@ static int chipio_write_data_multiple(struct hda_codec *codec,
int status = 0;
if (data == NULL) {
- snd_printdd(KERN_ERR "chipio_write_data null ptr\n");
+ codec_dbg(codec, "chipio_write_data null ptr\n");
return -EINVAL;
}
@@ -1407,12 +1406,12 @@ static int dspio_scp(struct hda_codec *codec,
return -EINVAL;
if (dir == SCP_GET && reply == NULL) {
- snd_printdd(KERN_ERR "dspio_scp get but has no buffer\n");
+ codec_dbg(codec, "dspio_scp get but has no buffer\n");
return -EINVAL;
}
if (reply != NULL && (reply_len == NULL || (*reply_len == 0))) {
- snd_printdd(KERN_ERR "dspio_scp bad resp buf len parms\n");
+ codec_dbg(codec, "dspio_scp bad resp buf len parms\n");
return -EINVAL;
}
@@ -1430,7 +1429,7 @@ static int dspio_scp(struct hda_codec *codec,
sizeof(scp_reply), &ret_bytes);
if (status < 0) {
- snd_printdd(KERN_ERR "dspio_scp: send scp msg failed\n");
+ codec_dbg(codec, "dspio_scp: send scp msg failed\n");
return status;
}
@@ -1449,17 +1448,17 @@ static int dspio_scp(struct hda_codec *codec,
/ sizeof(unsigned int);
if (*reply_len < ret_size*sizeof(unsigned int)) {
- snd_printdd(KERN_ERR "reply too long for buf\n");
+ codec_dbg(codec, "reply too long for buf\n");
return -EINVAL;
} else if (ret_size != reply_data_size) {
- snd_printdd(KERN_ERR "RetLen and HdrLen .NE.\n");
+ codec_dbg(codec, "RetLen and HdrLen .NE.\n");
return -EINVAL;
} else {
*reply_len = ret_size*sizeof(unsigned int);
memcpy(reply, scp_reply.data, *reply_len);
}
} else {
- snd_printdd(KERN_ERR "reply ill-formed or errflag set\n");
+ codec_dbg(codec, "reply ill-formed or errflag set\n");
return -EIO;
}
@@ -1489,22 +1488,22 @@ static int dspio_alloc_dma_chan(struct hda_codec *codec, unsigned int *dma_chan)
int status = 0;
unsigned int size = sizeof(dma_chan);
- snd_printdd(KERN_INFO " dspio_alloc_dma_chan() -- begin\n");
+ codec_dbg(codec, " dspio_alloc_dma_chan() -- begin\n");
status = dspio_scp(codec, MASTERCONTROL, MASTERCONTROL_ALLOC_DMA_CHAN,
SCP_GET, NULL, 0, dma_chan, &size);
if (status < 0) {
- snd_printdd(KERN_INFO "dspio_alloc_dma_chan: SCP Failed\n");
+ codec_dbg(codec, "dspio_alloc_dma_chan: SCP Failed\n");
return status;
}
if ((*dma_chan + 1) == 0) {
- snd_printdd(KERN_INFO "no free dma channels to allocate\n");
+ codec_dbg(codec, "no free dma channels to allocate\n");
return -EBUSY;
}
- snd_printdd("dspio_alloc_dma_chan: chan=%d\n", *dma_chan);
- snd_printdd(KERN_INFO " dspio_alloc_dma_chan() -- complete\n");
+ codec_dbg(codec, "dspio_alloc_dma_chan: chan=%d\n", *dma_chan);
+ codec_dbg(codec, " dspio_alloc_dma_chan() -- complete\n");
return status;
}
@@ -1517,18 +1516,18 @@ static int dspio_free_dma_chan(struct hda_codec *codec, unsigned int dma_chan)
int status = 0;
unsigned int dummy = 0;
- snd_printdd(KERN_INFO " dspio_free_dma_chan() -- begin\n");
- snd_printdd("dspio_free_dma_chan: chan=%d\n", dma_chan);
+ codec_dbg(codec, " dspio_free_dma_chan() -- begin\n");
+ codec_dbg(codec, "dspio_free_dma_chan: chan=%d\n", dma_chan);
status = dspio_scp(codec, MASTERCONTROL, MASTERCONTROL_ALLOC_DMA_CHAN,
SCP_SET, &dma_chan, sizeof(dma_chan), NULL, &dummy);
if (status < 0) {
- snd_printdd(KERN_INFO "dspio_free_dma_chan: SCP Failed\n");
+ codec_dbg(codec, "dspio_free_dma_chan: SCP Failed\n");
return status;
}
- snd_printdd(KERN_INFO " dspio_free_dma_chan() -- complete\n");
+ codec_dbg(codec, " dspio_free_dma_chan() -- complete\n");
return status;
}
@@ -1576,14 +1575,14 @@ static int dsp_reset(struct hda_codec *codec)
unsigned int res;
int retry = 20;
- snd_printdd("dsp_reset\n");
+ codec_dbg(codec, "dsp_reset\n");
do {
res = dspio_send(codec, VENDOR_DSPIO_DSP_INIT, 0);
retry--;
} while (res == -EIO && retry);
if (!retry) {
- snd_printdd("dsp_reset timeout\n");
+ codec_dbg(codec, "dsp_reset timeout\n");
return -EIO;
}
@@ -1636,39 +1635,39 @@ static int dsp_dma_setup_common(struct hda_codec *codec,
unsigned int active;
bool code, yram;
- snd_printdd(KERN_INFO "-- dsp_dma_setup_common() -- Begin ---------\n");
+ codec_dbg(codec, "-- dsp_dma_setup_common() -- Begin ---------\n");
if (dma_chan >= DSPDMAC_DMA_CFG_CHANNEL_COUNT) {
- snd_printdd(KERN_ERR "dma chan num invalid\n");
+ codec_dbg(codec, "dma chan num invalid\n");
return -EINVAL;
}
if (dsp_is_dma_active(codec, dma_chan)) {
- snd_printdd(KERN_ERR "dma already active\n");
+ codec_dbg(codec, "dma already active\n");
return -EBUSY;
}
dsp_addx = dsp_chip_to_dsp_addx(chip_addx, &code, &yram);
if (dsp_addx == INVALID_CHIP_ADDRESS) {
- snd_printdd(KERN_ERR "invalid chip addr\n");
+ codec_dbg(codec, "invalid chip addr\n");
return -ENXIO;
}
chnl_prop = DSPDMAC_CHNLPROP_AC_MASK;
active = 0;
- snd_printdd(KERN_INFO " dsp_dma_setup_common() start reg pgm\n");
+ codec_dbg(codec, " dsp_dma_setup_common() start reg pgm\n");
if (ovly) {
status = chipio_read(codec, DSPDMAC_CHNLPROP_INST_OFFSET,
&chnl_prop);
if (status < 0) {
- snd_printdd(KERN_ERR "read CHNLPROP Reg fail\n");
+ codec_dbg(codec, "read CHNLPROP Reg fail\n");
return status;
}
- snd_printdd(KERN_INFO "dsp_dma_setup_common() Read CHNLPROP\n");
+ codec_dbg(codec, "dsp_dma_setup_common() Read CHNLPROP\n");
}
if (!code)
@@ -1680,20 +1679,20 @@ static int dsp_dma_setup_common(struct hda_codec *codec,
status = chipio_write(codec, DSPDMAC_CHNLPROP_INST_OFFSET, chnl_prop);
if (status < 0) {
- snd_printdd(KERN_ERR "write CHNLPROP Reg fail\n");
+ codec_dbg(codec, "write CHNLPROP Reg fail\n");
return status;
}
- snd_printdd(KERN_INFO " dsp_dma_setup_common() Write CHNLPROP\n");
+ codec_dbg(codec, " dsp_dma_setup_common() Write CHNLPROP\n");
if (ovly) {
status = chipio_read(codec, DSPDMAC_ACTIVE_INST_OFFSET,
&active);
if (status < 0) {
- snd_printdd(KERN_ERR "read ACTIVE Reg fail\n");
+ codec_dbg(codec, "read ACTIVE Reg fail\n");
return status;
}
- snd_printdd(KERN_INFO "dsp_dma_setup_common() Read ACTIVE\n");
+ codec_dbg(codec, "dsp_dma_setup_common() Read ACTIVE\n");
}
active &= (~(1 << (DSPDMAC_ACTIVE_AAR_LOBIT + dma_chan))) &
@@ -1701,35 +1700,35 @@ static int dsp_dma_setup_common(struct hda_codec *codec,
status = chipio_write(codec, DSPDMAC_ACTIVE_INST_OFFSET, active);
if (status < 0) {
- snd_printdd(KERN_ERR "write ACTIVE Reg fail\n");
+ codec_dbg(codec, "write ACTIVE Reg fail\n");
return status;
}
- snd_printdd(KERN_INFO " dsp_dma_setup_common() Write ACTIVE\n");
+ codec_dbg(codec, " dsp_dma_setup_common() Write ACTIVE\n");
status = chipio_write(codec, DSPDMAC_AUDCHSEL_INST_OFFSET(dma_chan),
port_map_mask);
if (status < 0) {
- snd_printdd(KERN_ERR "write AUDCHSEL Reg fail\n");
+ codec_dbg(codec, "write AUDCHSEL Reg fail\n");
return status;
}
- snd_printdd(KERN_INFO " dsp_dma_setup_common() Write AUDCHSEL\n");
+ codec_dbg(codec, " dsp_dma_setup_common() Write AUDCHSEL\n");
status = chipio_write(codec, DSPDMAC_IRQCNT_INST_OFFSET(dma_chan),
DSPDMAC_IRQCNT_BICNT_MASK | DSPDMAC_IRQCNT_CICNT_MASK);
if (status < 0) {
- snd_printdd(KERN_ERR "write IRQCNT Reg fail\n");
+ codec_dbg(codec, "write IRQCNT Reg fail\n");
return status;
}
- snd_printdd(KERN_INFO " dsp_dma_setup_common() Write IRQCNT\n");
+ codec_dbg(codec, " dsp_dma_setup_common() Write IRQCNT\n");
- snd_printdd(
+ codec_dbg(codec,
"ChipA=0x%x,DspA=0x%x,dmaCh=%u, "
"CHSEL=0x%x,CHPROP=0x%x,Active=0x%x\n",
chip_addx, dsp_addx, dma_chan,
port_map_mask, chnl_prop, active);
- snd_printdd(KERN_INFO "-- dsp_dma_setup_common() -- Complete ------\n");
+ codec_dbg(codec, "-- dsp_dma_setup_common() -- Complete ------\n");
return 0;
}
@@ -1755,20 +1754,20 @@ static int dsp_dma_setup(struct hda_codec *codec,
const unsigned int max_dma_count = 1 << (DSPDMAC_XFRCNT_BCNT_HIBIT -
DSPDMAC_XFRCNT_BCNT_LOBIT + 1);
- snd_printdd(KERN_INFO "-- dsp_dma_setup() -- Begin ---------\n");
+ codec_dbg(codec, "-- dsp_dma_setup() -- Begin ---------\n");
if (count > max_dma_count) {
- snd_printdd(KERN_ERR "count too big\n");
+ codec_dbg(codec, "count too big\n");
return -EINVAL;
}
dsp_addx = dsp_chip_to_dsp_addx(chip_addx, &code, &yram);
if (dsp_addx == INVALID_CHIP_ADDRESS) {
- snd_printdd(KERN_ERR "invalid chip addr\n");
+ codec_dbg(codec, "invalid chip addr\n");
return -ENXIO;
}
- snd_printdd(KERN_INFO " dsp_dma_setup() start reg pgm\n");
+ codec_dbg(codec, " dsp_dma_setup() start reg pgm\n");
addr_field = dsp_addx << DSPDMAC_DMACFG_DBADR_LOBIT;
incr_field = 0;
@@ -1785,10 +1784,10 @@ static int dsp_dma_setup(struct hda_codec *codec,
status = chipio_write(codec, DSPDMAC_DMACFG_INST_OFFSET(dma_chan),
dma_cfg);
if (status < 0) {
- snd_printdd(KERN_ERR "write DMACFG Reg fail\n");
+ codec_dbg(codec, "write DMACFG Reg fail\n");
return status;
}
- snd_printdd(KERN_INFO " dsp_dma_setup() Write DMACFG\n");
+ codec_dbg(codec, " dsp_dma_setup() Write DMACFG\n");
adr_ofs = (count - 1) << (DSPDMAC_DSPADROFS_BOFS_LOBIT +
(code ? 0 : 1));
@@ -1796,10 +1795,10 @@ static int dsp_dma_setup(struct hda_codec *codec,
status = chipio_write(codec, DSPDMAC_DSPADROFS_INST_OFFSET(dma_chan),
adr_ofs);
if (status < 0) {
- snd_printdd(KERN_ERR "write DSPADROFS Reg fail\n");
+ codec_dbg(codec, "write DSPADROFS Reg fail\n");
return status;
}
- snd_printdd(KERN_INFO " dsp_dma_setup() Write DSPADROFS\n");
+ codec_dbg(codec, " dsp_dma_setup() Write DSPADROFS\n");
base_cnt = (count - 1) << DSPDMAC_XFRCNT_BCNT_LOBIT;
@@ -1810,17 +1809,17 @@ static int dsp_dma_setup(struct hda_codec *codec,
status = chipio_write(codec,
DSPDMAC_XFRCNT_INST_OFFSET(dma_chan), xfr_cnt);
if (status < 0) {
- snd_printdd(KERN_ERR "write XFRCNT Reg fail\n");
+ codec_dbg(codec, "write XFRCNT Reg fail\n");
return status;
}
- snd_printdd(KERN_INFO " dsp_dma_setup() Write XFRCNT\n");
+ codec_dbg(codec, " dsp_dma_setup() Write XFRCNT\n");
- snd_printdd(
+ codec_dbg(codec,
"ChipA=0x%x, cnt=0x%x, DMACFG=0x%x, "
"ADROFS=0x%x, XFRCNT=0x%x\n",
chip_addx, count, dma_cfg, adr_ofs, xfr_cnt);
- snd_printdd(KERN_INFO "-- dsp_dma_setup() -- Complete ---------\n");
+ codec_dbg(codec, "-- dsp_dma_setup() -- Complete ---------\n");
return 0;
}
@@ -1834,17 +1833,17 @@ static int dsp_dma_start(struct hda_codec *codec,
unsigned int reg = 0;
int status = 0;
- snd_printdd(KERN_INFO "-- dsp_dma_start() -- Begin ---------\n");
+ codec_dbg(codec, "-- dsp_dma_start() -- Begin ---------\n");
if (ovly) {
status = chipio_read(codec,
DSPDMAC_CHNLSTART_INST_OFFSET, &reg);
if (status < 0) {
- snd_printdd(KERN_ERR "read CHNLSTART reg fail\n");
+ codec_dbg(codec, "read CHNLSTART reg fail\n");
return status;
}
- snd_printdd(KERN_INFO "-- dsp_dma_start() Read CHNLSTART\n");
+ codec_dbg(codec, "-- dsp_dma_start() Read CHNLSTART\n");
reg &= ~(DSPDMAC_CHNLSTART_EN_MASK |
DSPDMAC_CHNLSTART_DIS_MASK);
@@ -1853,10 +1852,10 @@ static int dsp_dma_start(struct hda_codec *codec,
status = chipio_write(codec, DSPDMAC_CHNLSTART_INST_OFFSET,
reg | (1 << (dma_chan + DSPDMAC_CHNLSTART_EN_LOBIT)));
if (status < 0) {
- snd_printdd(KERN_ERR "write CHNLSTART reg fail\n");
+ codec_dbg(codec, "write CHNLSTART reg fail\n");
return status;
}
- snd_printdd(KERN_INFO "-- dsp_dma_start() -- Complete ---------\n");
+ codec_dbg(codec, "-- dsp_dma_start() -- Complete ---------\n");
return status;
}
@@ -1870,17 +1869,17 @@ static int dsp_dma_stop(struct hda_codec *codec,
unsigned int reg = 0;
int status = 0;
- snd_printdd(KERN_INFO "-- dsp_dma_stop() -- Begin ---------\n");
+ codec_dbg(codec, "-- dsp_dma_stop() -- Begin ---------\n");
if (ovly) {
status = chipio_read(codec,
DSPDMAC_CHNLSTART_INST_OFFSET, &reg);
if (status < 0) {
- snd_printdd(KERN_ERR "read CHNLSTART reg fail\n");
+ codec_dbg(codec, "read CHNLSTART reg fail\n");
return status;
}
- snd_printdd(KERN_INFO "-- dsp_dma_stop() Read CHNLSTART\n");
+ codec_dbg(codec, "-- dsp_dma_stop() Read CHNLSTART\n");
reg &= ~(DSPDMAC_CHNLSTART_EN_MASK |
DSPDMAC_CHNLSTART_DIS_MASK);
}
@@ -1888,10 +1887,10 @@ static int dsp_dma_stop(struct hda_codec *codec,
status = chipio_write(codec, DSPDMAC_CHNLSTART_INST_OFFSET,
reg | (1 << (dma_chan + DSPDMAC_CHNLSTART_DIS_LOBIT)));
if (status < 0) {
- snd_printdd(KERN_ERR "write CHNLSTART reg fail\n");
+ codec_dbg(codec, "write CHNLSTART reg fail\n");
return status;
}
- snd_printdd(KERN_INFO "-- dsp_dma_stop() -- Complete ---------\n");
+ codec_dbg(codec, "-- dsp_dma_stop() -- Complete ---------\n");
return status;
}
@@ -1974,17 +1973,17 @@ static int dsp_allocate_ports(struct hda_codec *codec,
{
int status;
- snd_printdd(KERN_INFO " dsp_allocate_ports() -- begin\n");
+ codec_dbg(codec, " dsp_allocate_ports() -- begin\n");
if ((rate_multi != 1) && (rate_multi != 2) && (rate_multi != 4)) {
- snd_printdd(KERN_ERR "bad rate multiple\n");
+ codec_dbg(codec, "bad rate multiple\n");
return -EINVAL;
}
status = dsp_allocate_router_ports(codec, num_chans,
rate_multi, 0, port_map);
- snd_printdd(KERN_INFO " dsp_allocate_ports() -- complete\n");
+ codec_dbg(codec, " dsp_allocate_ports() -- complete\n");
return status;
}
@@ -2001,7 +2000,7 @@ static int dsp_allocate_ports_format(struct hda_codec *codec,
unsigned int rate_multi = sample_rate_mul / sample_rate_div;
if ((rate_multi != 1) && (rate_multi != 2) && (rate_multi != 4)) {
- snd_printdd(KERN_ERR "bad rate multiple\n");
+ codec_dbg(codec, "bad rate multiple\n");
return -EINVAL;
}
@@ -2019,14 +2018,14 @@ static int dsp_free_ports(struct hda_codec *codec)
{
int status;
- snd_printdd(KERN_INFO " dsp_free_ports() -- begin\n");
+ codec_dbg(codec, " dsp_free_ports() -- begin\n");
status = dsp_free_router_ports(codec);
if (status < 0) {
- snd_printdd(KERN_ERR "free router ports fail\n");
+ codec_dbg(codec, "free router ports fail\n");
return status;
}
- snd_printdd(KERN_INFO " dsp_free_ports() -- complete\n");
+ codec_dbg(codec, " dsp_free_ports() -- complete\n");
return status;
}
@@ -2092,8 +2091,6 @@ static int dma_set_state(struct dma_engine *dma, enum dma_state state)
{
bool cmd;
- snd_printdd("dma_set_state state=%d\n", state);
-
switch (state) {
case DMA_STATE_STOP:
cmd = false;
@@ -2196,7 +2193,7 @@ static int dspxfr_hci_write(struct hda_codec *codec,
unsigned int count;
if (fls == NULL || fls->chip_addr != g_chip_addr_magic_value) {
- snd_printdd(KERN_ERR "hci_write invalid params\n");
+ codec_dbg(codec, "hci_write invalid params\n");
return -EINVAL;
}
@@ -2205,7 +2202,7 @@ static int dspxfr_hci_write(struct hda_codec *codec,
while (count >= 2) {
status = chipio_write(codec, data[0], data[1]);
if (status < 0) {
- snd_printdd(KERN_ERR "hci_write chipio failed\n");
+ codec_dbg(codec, "hci_write chipio failed\n");
return status;
}
count -= 2;
@@ -2265,12 +2262,12 @@ static int dspxfr_one_seg(struct hda_codec *codec,
}
if (hci_write && (!fls || is_last(fls))) {
- snd_printdd("hci_write\n");
+ codec_dbg(codec, "hci_write\n");
return dspxfr_hci_write(codec, hci_write);
}
if (fls == NULL || dma_engine == NULL || port_map_mask == 0) {
- snd_printdd("Invalid Params\n");
+ codec_dbg(codec, "Invalid Params\n");
return -EINVAL;
}
@@ -2286,7 +2283,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
if (!UC_RANGE(chip_addx, words_to_write) &&
!X_RANGE_ALL(chip_addx, words_to_write) &&
!Y_RANGE_ALL(chip_addx, words_to_write)) {
- snd_printdd("Invalid chip_addx Params\n");
+ codec_dbg(codec, "Invalid chip_addx Params\n");
return -EINVAL;
}
@@ -2296,7 +2293,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
buffer_addx = dma_get_buffer_addr(dma_engine);
if (buffer_addx == NULL) {
- snd_printdd(KERN_ERR "dma_engine buffer NULL\n");
+ codec_dbg(codec, "dma_engine buffer NULL\n");
return -EINVAL;
}
@@ -2309,7 +2306,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
(num_chans * sample_rate_mul / sample_rate_div));
if (hda_frame_size_words == 0) {
- snd_printdd(KERN_ERR "frmsz zero\n");
+ codec_dbg(codec, "frmsz zero\n");
return -EINVAL;
}
@@ -2317,14 +2314,14 @@ static int dspxfr_one_seg(struct hda_codec *codec,
(unsigned int)(UC_RANGE(chip_addx, 1) ?
65536 : 32768));
buffer_size_words -= buffer_size_words % hda_frame_size_words;
- snd_printdd(
+ codec_dbg(codec,
"chpadr=0x%08x frmsz=%u nchan=%u "
"rate_mul=%u div=%u bufsz=%u\n",
chip_addx, hda_frame_size_words, num_chans,
sample_rate_mul, sample_rate_div, buffer_size_words);
if (buffer_size_words < hda_frame_size_words) {
- snd_printdd(KERN_ERR "dspxfr_one_seg:failed\n");
+ codec_dbg(codec, "dspxfr_one_seg:failed\n");
return -EINVAL;
}
@@ -2338,7 +2335,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
while (words_to_write != 0) {
run_size_words = min(buffer_size_words, words_to_write);
- snd_printdd("dspxfr (seg loop)cnt=%u rs=%u remainder=%u\n",
+ codec_dbg(codec, "dspxfr (seg loop)cnt=%u rs=%u remainder=%u\n",
words_to_write, run_size_words, remainder_words);
dma_xfer(dma_engine, data, run_size_words*sizeof(u32));
if (!comm_dma_setup_done) {
@@ -2360,7 +2357,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
if (status < 0)
return status;
if (!dsp_is_dma_active(codec, dma_chan)) {
- snd_printdd(KERN_ERR "dspxfr:DMA did not start\n");
+ codec_dbg(codec, "dspxfr:DMA did not start\n");
return -EIO;
}
status = dma_set_state(dma_engine, DMA_STATE_RUN);
@@ -2392,7 +2389,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
if (dma_active)
break;
- snd_printdd(KERN_INFO "+++++ DMA complete\n");
+ codec_dbg(codec, "+++++ DMA complete\n");
dma_set_state(dma_engine, DMA_STATE_STOP);
status = dma_reset(dma_engine);
@@ -2466,7 +2463,7 @@ static int dspxfr_image(struct hda_codec *codec,
hda_format, &response);
if (status < 0) {
- snd_printdd(KERN_ERR "set converter format fail\n");
+ codec_dbg(codec, "set converter format fail\n");
goto exit;
}
@@ -2481,7 +2478,7 @@ static int dspxfr_image(struct hda_codec *codec,
if (ovly) {
status = dspio_alloc_dma_chan(codec, &dma_chan);
if (status < 0) {
- snd_printdd(KERN_ERR "alloc dmachan fail\n");
+ codec_dbg(codec, "alloc dmachan fail\n");
dma_chan = INVALID_DMA_CHANNEL;
goto exit;
}
@@ -2491,7 +2488,7 @@ static int dspxfr_image(struct hda_codec *codec,
status = dsp_allocate_ports_format(codec, hda_format,
&port_map_mask);
if (status < 0) {
- snd_printdd(KERN_ERR "alloc ports fail\n");
+ codec_dbg(codec, "alloc ports fail\n");
goto exit;
}
@@ -2499,13 +2496,13 @@ static int dspxfr_image(struct hda_codec *codec,
status = codec_set_converter_stream_channel(codec,
WIDGET_CHIP_CTRL, stream_id, 0, &response);
if (status < 0) {
- snd_printdd(KERN_ERR "set stream chan fail\n");
+ codec_dbg(codec, "set stream chan fail\n");
goto exit;
}
while ((fls_data != NULL) && !is_last(fls_data)) {
if (!is_valid(fls_data)) {
- snd_printdd(KERN_ERR "FLS check fail\n");
+ codec_dbg(codec, "FLS check fail\n");
status = -EINVAL;
goto exit;
}
@@ -2548,7 +2545,7 @@ exit:
*/
static void dspload_post_setup(struct hda_codec *codec)
{
- snd_printdd(KERN_INFO "---- dspload_post_setup ------\n");
+ codec_dbg(codec, "---- dspload_post_setup ------\n");
/*set DSP speaker to 2.0 configuration*/
chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x18), 0x08080080);
@@ -2586,7 +2583,7 @@ static int dspload_image(struct hda_codec *codec,
unsigned int sample_rate;
unsigned short channels;
- snd_printdd(KERN_INFO "---- dspload_image begin ------\n");
+ codec_dbg(codec, "---- dspload_image begin ------\n");
if (router_chans == 0) {
if (!ovly)
router_chans = DMA_TRANSFER_FRAME_SIZE_NWORDS;
@@ -2603,27 +2600,27 @@ static int dspload_image(struct hda_codec *codec,
}
do {
- snd_printdd(KERN_INFO "Ready to program DMA\n");
+ codec_dbg(codec, "Ready to program DMA\n");
if (!ovly)
status = dsp_reset(codec);
if (status < 0)
break;
- snd_printdd(KERN_INFO "dsp_reset() complete\n");
+ codec_dbg(codec, "dsp_reset() complete\n");
status = dspxfr_image(codec, fls, reloc, sample_rate, channels,
ovly);
if (status < 0)
break;
- snd_printdd(KERN_INFO "dspxfr_image() complete\n");
+ codec_dbg(codec, "dspxfr_image() complete\n");
if (autostart && !ovly) {
dspload_post_setup(codec);
status = dsp_set_run_state(codec);
}
- snd_printdd(KERN_INFO "LOAD FINISHED\n");
+ codec_dbg(codec, "LOAD FINISHED\n");
} while (0);
return status;
@@ -2662,60 +2659,6 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
}
/*
- * PCM stuffs
- */
-static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid,
- u32 stream_tag,
- int channel_id, int format)
-{
- unsigned int oldval, newval;
-
- if (!nid)
- return;
-
- snd_printdd(
- "ca0132_setup_stream: NID=0x%x, stream=0x%x, "
- "channel=%d, format=0x%x\n",
- nid, stream_tag, channel_id, format);
-
- /* update the format-id if changed */
- oldval = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_STREAM_FORMAT,
- 0);
- if (oldval != format) {
- msleep(20);
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_STREAM_FORMAT,
- format);
- }
-
- oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
- newval = (stream_tag << 4) | channel_id;
- if (oldval != newval) {
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_CHANNEL_STREAMID,
- newval);
- }
-}
-
-static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid)
-{
- unsigned int val;
-
- if (!nid)
- return;
-
- snd_printdd(KERN_INFO "ca0132_cleanup_stream: NID=0x%x\n", nid);
-
- val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
- if (!val)
- return;
-
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
-}
-
-/*
* PCM callbacks
*/
static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -2726,7 +2669,7 @@ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
{
struct ca0132_spec *spec = codec->spec;
- ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
+ snd_hda_codec_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
return 0;
}
@@ -2745,7 +2688,7 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
msleep(50);
- ca0132_cleanup_stream(codec, spec->dacs[0]);
+ snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
return 0;
}
@@ -2822,10 +2765,8 @@ static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
unsigned int format,
struct snd_pcm_substream *substream)
{
- struct ca0132_spec *spec = codec->spec;
-
- ca0132_setup_stream(codec, spec->adcs[substream->number],
- stream_tag, 0, format);
+ snd_hda_codec_setup_stream(codec, hinfo->nid,
+ stream_tag, 0, format);
return 0;
}
@@ -2839,7 +2780,7 @@ static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
if (spec->dsp_state == DSP_DOWNLOADING)
return 0;
- ca0132_cleanup_stream(codec, hinfo->nid);
+ snd_hda_codec_cleanup_stream(codec, hinfo->nid);
return 0;
}
@@ -3188,7 +3129,7 @@ static int ca0132_select_out(struct hda_codec *codec)
unsigned int tmp;
int err;
- snd_printdd(KERN_INFO "ca0132_select_out\n");
+ codec_dbg(codec, "ca0132_select_out\n");
snd_hda_power_up(codec);
@@ -3206,7 +3147,7 @@ static int ca0132_select_out(struct hda_codec *codec)
spec->cur_out_type = SPEAKER_OUT;
if (spec->cur_out_type == SPEAKER_OUT) {
- snd_printdd(KERN_INFO "ca0132_select_out speaker\n");
+ codec_dbg(codec, "ca0132_select_out speaker\n");
/*speaker out config*/
tmp = FLOAT_ONE;
err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
@@ -3239,7 +3180,7 @@ static int ca0132_select_out(struct hda_codec *codec)
snd_hda_set_pin_ctl(codec, spec->out_pins[0],
pin_ctl | PIN_OUT);
} else {
- snd_printdd(KERN_INFO "ca0132_select_out hp\n");
+ codec_dbg(codec, "ca0132_select_out hp\n");
/*headphone out config*/
tmp = FLOAT_ZERO;
err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
@@ -3344,7 +3285,7 @@ static int ca0132_select_mic(struct hda_codec *codec)
int jack_present;
int auto_jack;
- snd_printdd(KERN_INFO "ca0132_select_mic\n");
+ codec_dbg(codec, "ca0132_select_mic\n");
snd_hda_power_up(codec);
@@ -3466,7 +3407,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
val = 0;
}
- snd_printdd(KERN_INFO "ca0132_effect_set: nid=0x%x, val=%ld\n",
+ codec_dbg(codec, "ca0132_effect_set: nid=0x%x, val=%ld\n",
nid, val);
on = (val == 0) ? FLOAT_ZERO : FLOAT_ONE;
@@ -3488,7 +3429,7 @@ static int ca0132_pe_switch_set(struct hda_codec *codec)
hda_nid_t nid;
int i, ret = 0;
- snd_printdd(KERN_INFO "ca0132_pe_switch_set: val=%ld\n",
+ codec_dbg(codec, "ca0132_pe_switch_set: val=%ld\n",
spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]);
i = OUT_EFFECT_START_NID - EFFECT_START_NID;
@@ -3534,7 +3475,7 @@ static int ca0132_cvoice_switch_set(struct hda_codec *codec)
int i, ret = 0;
unsigned int oldval;
- snd_printdd(KERN_INFO "ca0132_cvoice_switch_set: val=%ld\n",
+ codec_dbg(codec, "ca0132_cvoice_switch_set: val=%ld\n",
spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID]);
i = IN_EFFECT_START_NID - EFFECT_START_NID;
@@ -3664,7 +3605,7 @@ static int ca0132_voicefx_put(struct snd_kcontrol *kcontrol,
if (sel >= items)
return 0;
- snd_printdd(KERN_INFO "ca0132_voicefx_put: sel=%d, preset=%s\n",
+ codec_dbg(codec, "ca0132_voicefx_put: sel=%d, preset=%s\n",
sel, ca0132_voicefx_presets[sel].name);
/*
@@ -3735,7 +3676,7 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
long *valp = ucontrol->value.integer.value;
int changed = 1;
- snd_printdd(KERN_INFO "ca0132_switch_put: nid=0x%x, val=%ld\n",
+ codec_dbg(codec, "ca0132_switch_put: nid=0x%x, val=%ld\n",
nid, *valp);
snd_hda_power_up(codec);
@@ -4198,7 +4139,7 @@ static void ca0132_set_dmic(struct hda_codec *codec, int enable)
u8 val;
unsigned int oldval;
- snd_printdd(KERN_INFO "ca0132_set_dmic: enable=%d\n", enable);
+ codec_dbg(codec, "ca0132_set_dmic: enable=%d\n", enable);
oldval = stop_mic1(codec);
ca0132_set_vipsource(codec, 0);
@@ -4306,7 +4247,7 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec)
int i;
hda_nid_t nid;
- snd_printdd(KERN_INFO "ca0132_refresh_widget_caps.\n");
+ codec_dbg(codec, "ca0132_refresh_widget_caps.\n");
nid = codec->start_nid;
for (i = 0; i < codec->num_nodes; i++, nid++)
codec->wcaps[i] = snd_hda_param_read(codec, nid,
@@ -4450,7 +4391,7 @@ static void ca0132_process_dsp_response(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- snd_printdd(KERN_INFO "ca0132_process_dsp_response\n");
+ codec_dbg(codec, "ca0132_process_dsp_response\n");
if (spec->wait_scp) {
if (dspio_get_response_data(codec) >= 0)
spec->wait_scp = 0;
@@ -4469,7 +4410,7 @@ static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res)
res = snd_hda_jack_get_action(codec,
(res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f);
- snd_printdd(KERN_INFO "snd_hda_jack_get_action: 0x%x\n", res);
+ codec_dbg(codec, "snd_hda_jack_get_action: 0x%x\n", res);
switch (res) {
case UNSOL_TAG_HP:
@@ -4714,7 +4655,7 @@ static int patch_ca0132(struct hda_codec *codec)
struct ca0132_spec *spec;
int err;
- snd_printdd("patch_ca0132\n");
+ codec_dbg(codec, "patch_ca0132\n");
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
@@ -4742,6 +4683,8 @@ static int patch_ca0132(struct hda_codec *codec)
return err;
codec->patch_ops = ca0132_patch_ops;
+ codec->pcm_format_first = 1;
+ codec->no_sticky_stream = 1;
return 0;
}
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index fc492ac24caa..387f0b551889 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -20,7 +20,6 @@
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/tlv.h>
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index 9c6ce73b03c5..061ea5965dd5 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/module.h>
#include <sound/core.h>
#include "hda_codec.h"
@@ -32,6 +31,9 @@
#include "hda_jack.h"
#include "hda_generic.h"
+#undef ENABLE_CMI_STATIC_QUIRKS
+
+#ifdef ENABLE_CMI_STATIC_QUIRKS
#define NUM_PINS 11
@@ -45,10 +47,12 @@ enum {
CMI_AUTO, /* let driver guess it */
CMI_MODELS
};
+#endif /* ENABLE_CMI_STATIC_QUIRKS */
struct cmi_spec {
struct hda_gen_spec gen;
+#ifdef ENABLE_CMI_STATIC_QUIRKS
/* below are only for static models */
int board_config;
@@ -81,8 +85,10 @@ struct cmi_spec {
/* multichannel pins */
struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */
+#endif /* ENABLE_CMI_STATIC_QUIRKS */
};
+#ifdef ENABLE_CMI_STATIC_QUIRKS
/*
* input MUX
*/
@@ -566,6 +572,7 @@ static const struct hda_codec_ops cmi9880_patch_ops = {
.init = cmi9880_init,
.free = cmi9880_free,
};
+#endif /* ENABLE_CMI_STATIC_QUIRKS */
/*
* stuff for auto-parser
@@ -588,15 +595,20 @@ static int cmi_parse_auto_config(struct hda_codec *codec)
err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
if (err < 0)
- return err;
+ goto error;
err = snd_hda_gen_parse_auto_config(codec, cfg);
if (err < 0)
- return err;
+ goto error;
codec->patch_ops = cmi_auto_patch_ops;
return 0;
+
+ error:
+ snd_hda_gen_free(codec);
+ return err;
}
+
static int patch_cmi9880(struct hda_codec *codec)
{
struct cmi_spec *spec;
@@ -606,23 +618,18 @@ static int patch_cmi9880(struct hda_codec *codec)
return -ENOMEM;
codec->spec = spec;
+#ifdef ENABLE_CMI_STATIC_QUIRKS
spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS,
cmi9880_models,
cmi9880_cfg_tbl);
if (spec->board_config < 0) {
- snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec_dbg(codec, "%s: BIOS auto-probing.\n",
codec->chip_name);
spec->board_config = CMI_AUTO; /* try everything */
}
- if (spec->board_config == CMI_AUTO) {
- int err = cmi_parse_auto_config(codec);
- if (err < 0) {
- snd_hda_gen_free(codec);
- return err;
- }
- return 0;
- }
+ if (spec->board_config == CMI_AUTO)
+ return cmi_parse_auto_config(codec);
/* copy default DAC NIDs */
memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids));
@@ -669,6 +676,9 @@ static int patch_cmi9880(struct hda_codec *codec)
codec->patch_ops = cmi9880_patch_ops;
return 0;
+#else
+ return cmi_parse_auto_config(codec);
+#endif
}
/*
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index bcf91bea3317..1dc7e974f3b1 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/jack.h>
@@ -35,7 +34,7 @@
#include "hda_jack.h"
#include "hda_generic.h"
-#define ENABLE_CXT_STATIC_QUIRKS
+#undef ENABLE_CXT_STATIC_QUIRKS
#define CXT_PIN_DIR_IN 0x00
#define CXT_PIN_DIR_OUT 0x01
@@ -68,6 +67,12 @@ struct conexant_spec {
unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
+ /* OPLC XO specific */
+ bool recording;
+ bool dc_enable;
+ unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */
+ struct nid_path *dc_mode_path;
+
#ifdef ENABLE_CXT_STATIC_QUIRKS
const struct snd_kcontrol_new *mixers[5];
int num_mixers;
@@ -123,19 +128,6 @@ struct conexant_spec {
unsigned int hp_laptop:1;
unsigned int asus:1;
- unsigned int ext_mic_present;
- unsigned int recording;
- void (*capture_prepare)(struct hda_codec *codec);
- void (*capture_cleanup)(struct hda_codec *codec);
-
- /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
- * through the microphone jack.
- * When the user enables this through a mixer switch, both internal and
- * external microphones are disabled. Gain is fixed at 0dB. In this mode,
- * we also allow the bias to be configured through a separate mixer
- * control. */
- unsigned int dc_enable;
- unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */
unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */
#endif /* ENABLE_CXT_STATIC_QUIRKS */
};
@@ -253,8 +245,6 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
{
struct conexant_spec *spec = codec->spec;
- if (spec->capture_prepare)
- spec->capture_prepare(codec);
snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
stream_tag, 0, format);
return 0;
@@ -266,8 +256,6 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
{
struct conexant_spec *spec = codec->spec;
snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
- if (spec->capture_cleanup)
- spec->capture_cleanup(codec);
return 0;
}
@@ -457,9 +445,7 @@ static int conexant_init(struct hda_codec *codec)
static void conexant_free(struct hda_codec *codec)
{
- struct conexant_spec *spec = codec->spec;
- snd_hda_detach_beep_device(codec);
- kfree(spec);
+ kfree(codec->spec);
}
static const struct snd_kcontrol_new cxt_capture_mixers[] = {
@@ -673,14 +659,6 @@ static const struct hda_input_mux cxt5045_capture_source_benq = {
}
};
-static const struct hda_input_mux cxt5045_capture_source_hp530 = {
- .num_items = 2,
- .items = {
- { "Mic", 0x1 },
- { "Internal Mic", 0x2 },
- }
-};
-
/* turn on/off EAPD (+ mute HP) as a master switch */
static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -796,28 +774,6 @@ static const struct snd_kcontrol_new cxt5045_benq_mixers[] = {
{}
};
-static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x00, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
- HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
- HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Switch",
- .info = cxt_eapd_info,
- .get = cxt_eapd_get,
- .put = cxt5045_hp_master_sw_put,
- .private_value = 0x10,
- },
-
- {}
-};
-
static const struct hda_verb cxt5045_init_verbs[] = {
/* Line in, Mic */
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
@@ -1000,7 +956,6 @@ enum {
CXT5045_LAPTOP_MICSENSE,
CXT5045_LAPTOP_HPMICSENSE,
CXT5045_BENQ,
- CXT5045_LAPTOP_HP530,
#ifdef CONFIG_SND_DEBUG
CXT5045_TEST,
#endif
@@ -1013,7 +968,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = {
[CXT5045_LAPTOP_MICSENSE] = "laptop-micsense",
[CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense",
[CXT5045_BENQ] = "benq",
- [CXT5045_LAPTOP_HP530] = "laptop-hp530",
#ifdef CONFIG_SND_DEBUG
[CXT5045_TEST] = "test",
#endif
@@ -1021,8 +975,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = {
};
static const struct snd_pci_quirk cxt5045_cfg_tbl[] = {
- SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
- SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE),
SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ),
SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE),
SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE),
@@ -1113,14 +1065,6 @@ static int patch_cxt5045(struct hda_codec *codec)
spec->num_mixers = 2;
codec->patch_ops.init = cxt5045_init;
break;
- case CXT5045_LAPTOP_HP530:
- codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
- spec->input_mux = &cxt5045_capture_source_hp530;
- spec->num_init_verbs = 2;
- spec->init_verbs[1] = cxt5045_hp_sense_init_verbs;
- spec->mixers[0] = cxt5045_mixers_hp530;
- codec->patch_ops.init = cxt5045_init;
- break;
#ifdef CONFIG_SND_DEBUG
case CXT5045_TEST:
spec->input_mux = &cxt5045_test_capture_source;
@@ -1940,11 +1884,6 @@ static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 };
-/* OLPC's microphone port is DC coupled for use with external sensors,
- * therefore we use a 50% mic bias in order to center the input signal with
- * the DC input range of the codec. */
-#define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50
-
static const struct hda_channel_mode cxt5066_modes[1] = {
{ 2, NULL },
};
@@ -1959,7 +1898,8 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
struct conexant_spec *spec = codec->spec;
unsigned int pinctl;
- snd_printdd("CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n",
+ codec_dbg(codec,
+ "CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n",
spec->hp_present, spec->cur_eapd);
/* Port A (HP) */
@@ -1997,88 +1937,6 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static const struct hda_input_mux cxt5066_olpc_dc_bias = {
- .num_items = 3,
- .items = {
- { "Off", PIN_IN },
- { "50%", PIN_VREF50 },
- { "80%", PIN_VREF80 },
- },
-};
-
-static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec)
-{
- struct conexant_spec *spec = codec->spec;
- /* Even though port F is the DC input, the bias is controlled on port B.
- * we also leave that port as an active input (but unselected) in DC mode
- * just in case that is necessary to make the bias setting take effect. */
- return snd_hda_set_pin_ctl_cache(codec, 0x1a,
- cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index);
-}
-
-/* OLPC defers mic widget control until when capture is started because the
- * microphone LED comes on as soon as these settings are put in place. if we
- * did this before recording, it would give the false indication that recording
- * is happening when it is not. */
-static void cxt5066_olpc_select_mic(struct hda_codec *codec)
-{
- struct conexant_spec *spec = codec->spec;
- if (!spec->recording)
- return;
-
- if (spec->dc_enable) {
- /* in DC mode we ignore presence detection and just use the jack
- * through our special DC port */
- const struct hda_verb enable_dc_mode[] = {
- /* disble internal mic, port C */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
- /* enable DC capture, port F */
- {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {},
- };
-
- snd_hda_sequence_write(codec, enable_dc_mode);
- /* port B input disabled (and bias set) through the following call */
- cxt5066_set_olpc_dc_bias(codec);
- return;
- }
-
- /* disable DC (port F) */
- snd_hda_set_pin_ctl(codec, 0x1e, 0);
-
- /* external mic, port B */
- snd_hda_set_pin_ctl(codec, 0x1a,
- spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0);
-
- /* internal mic, port C */
- snd_hda_set_pin_ctl(codec, 0x1b,
- spec->ext_mic_present ? 0 : PIN_VREF80);
-}
-
-/* toggle input of built-in and mic jack appropriately */
-static void cxt5066_olpc_automic(struct hda_codec *codec)
-{
- struct conexant_spec *spec = codec->spec;
- unsigned int present;
-
- if (spec->dc_enable) /* don't do presence detection in DC mode */
- return;
-
- present = snd_hda_codec_read(codec, 0x1a, 0,
- AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
- if (present)
- snd_printdd("CXT5066: external microphone detected\n");
- else
- snd_printdd("CXT5066: external microphone absent\n");
-
- snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
- present ? 0 : 1);
- spec->ext_mic_present = !!present;
-
- cxt5066_olpc_select_mic(codec);
-}
-
/* toggle input of built-in digital mic and mic jack appropriately */
static void cxt5066_vostro_automic(struct hda_codec *codec)
{
@@ -2110,10 +1968,10 @@ static void cxt5066_vostro_automic(struct hda_codec *codec)
present = snd_hda_jack_detect(codec, 0x1a);
if (present) {
- snd_printdd("CXT5066: external microphone detected\n");
+ codec_dbg(codec, "CXT5066: external microphone detected\n");
snd_hda_sequence_write(codec, ext_mic_present);
} else {
- snd_printdd("CXT5066: external microphone absent\n");
+ codec_dbg(codec, "CXT5066: external microphone absent\n");
snd_hda_sequence_write(codec, ext_mic_absent);
}
}
@@ -2138,10 +1996,10 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec)
present = snd_hda_jack_detect(codec, 0x1b);
if (present) {
- snd_printdd("CXT5066: external microphone detected\n");
+ codec_dbg(codec, "CXT5066: external microphone detected\n");
snd_hda_sequence_write(codec, ext_mic_present);
} else {
- snd_printdd("CXT5066: external microphone absent\n");
+ codec_dbg(codec, "CXT5066: external microphone absent\n");
snd_hda_sequence_write(codec, ext_mic_absent);
}
}
@@ -2153,7 +2011,7 @@ static void cxt5066_asus_automic(struct hda_codec *codec)
unsigned int present;
present = snd_hda_jack_detect(codec, 0x1b);
- snd_printdd("CXT5066: external microphone present=%d\n", present);
+ codec_dbg(codec, "CXT5066: external microphone present=%d\n", present);
snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
present ? 1 : 0);
}
@@ -2165,7 +2023,7 @@ static void cxt5066_hp_laptop_automic(struct hda_codec *codec)
unsigned int present;
present = snd_hda_jack_detect(codec, 0x1b);
- snd_printdd("CXT5066: external microphone present=%d\n", present);
+ codec_dbg(codec, "CXT5066: external microphone present=%d\n", present);
snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
present ? 1 : 3);
}
@@ -2204,13 +2062,13 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec)
ext_present = snd_hda_jack_detect(codec, 0x1b);
dock_present = snd_hda_jack_detect(codec, 0x1a);
if (ext_present) {
- snd_printdd("CXT5066: external microphone detected\n");
+ codec_dbg(codec, "CXT5066: external microphone detected\n");
snd_hda_sequence_write(codec, ext_mic_present);
} else if (dock_present) {
- snd_printdd("CXT5066: dock microphone detected\n");
+ codec_dbg(codec, "CXT5066: dock microphone detected\n");
snd_hda_sequence_write(codec, dock_mic_present);
} else {
- snd_printdd("CXT5066: external microphone absent\n");
+ codec_dbg(codec, "CXT5066: external microphone absent\n");
snd_hda_sequence_write(codec, ext_mic_absent);
}
}
@@ -2229,7 +2087,7 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
spec->hp_present = portA ? HP_PRESENT_PORT_A : 0;
spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0;
- snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
+ codec_dbg(codec, "CXT5066: hp automute portA=%x portD=%x present=%d\n",
portA, portD, spec->hp_present);
cxt5066_update_speaker(codec);
}
@@ -2252,26 +2110,9 @@ static void cxt5066_automic(struct hda_codec *codec)
}
/* unsolicited event for jack sensing */
-static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
-{
- struct conexant_spec *spec = codec->spec;
- snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
- switch (res >> 26) {
- case CONEXANT_HP_EVENT:
- cxt5066_hp_automute(codec);
- break;
- case CONEXANT_MIC_EVENT:
- /* ignore mic events in DC mode; we're always using the jack */
- if (!spec->dc_enable)
- cxt5066_olpc_automic(codec);
- break;
- }
-}
-
-/* unsolicited event for jack sensing */
static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
{
- snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
+ codec_dbg(codec, "CXT5066: unsol event %x (%x)\n", res, res >> 26);
switch (res >> 26) {
case CONEXANT_HP_EVENT:
cxt5066_hp_automute(codec);
@@ -2338,124 +2179,10 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol,
idx = imux->num_items - 1;
spec->mic_boost = idx;
- if (!spec->dc_enable)
- cxt5066_set_mic_boost(codec);
- return 1;
-}
-
-static void cxt5066_enable_dc(struct hda_codec *codec)
-{
- const struct hda_verb enable_dc_mode[] = {
- /* disable gain */
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* switch to DC input */
- {0x17, AC_VERB_SET_CONNECT_SEL, 3},
- {}
- };
-
- /* configure as input source */
- snd_hda_sequence_write(codec, enable_dc_mode);
- cxt5066_olpc_select_mic(codec); /* also sets configured bias */
-}
-
-static void cxt5066_disable_dc(struct hda_codec *codec)
-{
- /* reconfigure input source */
cxt5066_set_mic_boost(codec);
- /* automic also selects the right mic if we're recording */
- cxt5066_olpc_automic(codec);
-}
-
-static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct conexant_spec *spec = codec->spec;
- ucontrol->value.integer.value[0] = spec->dc_enable;
- return 0;
-}
-
-static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct conexant_spec *spec = codec->spec;
- int dc_enable = !!ucontrol->value.integer.value[0];
-
- if (dc_enable == spec->dc_enable)
- return 0;
-
- spec->dc_enable = dc_enable;
- if (dc_enable)
- cxt5066_enable_dc(codec);
- else
- cxt5066_disable_dc(codec);
-
- return 1;
-}
-
-static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo);
-}
-
-static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct conexant_spec *spec = codec->spec;
- ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
- return 0;
-}
-
-static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct conexant_spec *spec = codec->spec;
- const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
- unsigned int idx;
-
- idx = ucontrol->value.enumerated.item[0];
- if (idx >= imux->num_items)
- idx = imux->num_items - 1;
-
- spec->dc_input_bias = idx;
- if (spec->dc_enable)
- cxt5066_set_olpc_dc_bias(codec);
return 1;
}
-static void cxt5066_olpc_capture_prepare(struct hda_codec *codec)
-{
- struct conexant_spec *spec = codec->spec;
- /* mark as recording and configure the microphone widget so that the
- * recording LED comes on. */
- spec->recording = 1;
- cxt5066_olpc_select_mic(codec);
-}
-
-static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
-{
- struct conexant_spec *spec = codec->spec;
- const struct hda_verb disable_mics[] = {
- /* disable external mic, port B */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
- /* disble internal mic, port C */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
- /* disable DC capture, port F */
- {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {},
- };
-
- snd_hda_sequence_write(codec, disable_mics);
- spec->recording = 0;
-}
-
static void conexant_check_dig_outs(struct hda_codec *codec,
const hda_nid_t *dig_pins,
int num_pins)
@@ -2506,43 +2233,6 @@ static const struct snd_kcontrol_new cxt5066_mixer_master[] = {
{}
};
-static const struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Volume",
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
- SNDRV_CTL_ELEM_ACCESS_TLV_READ |
- SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
- .subdevice = HDA_SUBDEV_AMP_FLAG,
- .info = snd_hda_mixer_amp_volume_info,
- .get = snd_hda_mixer_amp_volume_get,
- .put = snd_hda_mixer_amp_volume_put,
- .tlv = { .c = snd_hda_mixer_amp_tlv },
- /* offset by 28 volume steps to limit minimum gain to -46dB */
- .private_value =
- HDA_COMPOSE_AMP_VAL_OFS(0x10, 3, 0, HDA_OUTPUT, 28),
- },
- {}
-};
-
-static const struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "DC Mode Enable Switch",
- .info = snd_ctl_boolean_mono_info,
- .get = cxt5066_olpc_dc_get,
- .put = cxt5066_olpc_dc_put,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "DC Input Bias Enum",
- .info = cxt5066_olpc_dc_bias_enum_info,
- .get = cxt5066_olpc_dc_bias_enum_get,
- .put = cxt5066_olpc_dc_bias_enum_put,
- },
- {}
-};
-
static const struct snd_kcontrol_new cxt5066_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -2633,67 +2323,6 @@ static const struct hda_verb cxt5066_init_verbs[] = {
{ } /* end */
};
-static const struct hda_verb cxt5066_init_verbs_olpc[] = {
- /* Port A: headphones */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
-
- /* Port B: external microphone */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
- /* Port C: internal microphone */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
- /* Port D: unused */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
- /* Port E: unused, but has primary EAPD */
- {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
-
- /* Port F: external DC input through microphone port */
- {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
- /* Port G: internal speakers */
- {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
-
- /* DAC1 */
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* DAC2: unused */
- {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-
- /* Disable digital microphone port */
- {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
- /* Audio input selectors */
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-
- /* Disable SPDIF */
- {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-
- /* enable unsolicited events for Port A and B */
- {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
- {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
- { } /* end */
-};
-
static const struct hda_verb cxt5066_init_verbs_vostro[] = {
/* Port A: headphones */
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
@@ -2879,7 +2508,7 @@ static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = {
/* initialize jack-sensing, too */
static int cxt5066_init(struct hda_codec *codec)
{
- snd_printdd("CXT5066: init\n");
+ codec_dbg(codec, "CXT5066: init\n");
conexant_init(codec);
if (codec->patch_ops.unsol_event) {
cxt5066_hp_automute(codec);
@@ -2889,25 +2518,9 @@ static int cxt5066_init(struct hda_codec *codec)
return 0;
}
-static int cxt5066_olpc_init(struct hda_codec *codec)
-{
- struct conexant_spec *spec = codec->spec;
- snd_printdd("CXT5066: init\n");
- conexant_init(codec);
- cxt5066_hp_automute(codec);
- if (!spec->dc_enable) {
- cxt5066_set_mic_boost(codec);
- cxt5066_olpc_automic(codec);
- } else {
- cxt5066_enable_dc(codec);
- }
- return 0;
-}
-
enum {
CXT5066_LAPTOP, /* Laptops w/ EAPD support */
CXT5066_DELL_LAPTOP, /* Dell Laptop */
- CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */
CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */
CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */
CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */
@@ -2920,7 +2533,6 @@ enum {
static const char * const cxt5066_models[CXT5066_MODELS] = {
[CXT5066_LAPTOP] = "laptop",
[CXT5066_DELL_LAPTOP] = "dell-laptop",
- [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5",
[CXT5066_DELL_VOSTRO] = "dell-vostro",
[CXT5066_IDEAPAD] = "ideapad",
[CXT5066_THINKPAD] = "thinkpad",
@@ -2941,10 +2553,8 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS),
SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS),
SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
- SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
CXT5066_LAPTOP),
- SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
@@ -3030,32 +2640,11 @@ static int patch_cxt5066(struct hda_codec *codec)
spec->mic_boost = 3; /* default 30dB gain */
break;
- case CXT5066_OLPC_XO_1_5:
- codec->patch_ops.init = cxt5066_olpc_init;
- codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event;
- spec->init_verbs[0] = cxt5066_init_verbs_olpc;
- spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
- spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc;
- spec->mixers[spec->num_mixers++] = cxt5066_mixers;
- spec->port_d_mode = 0;
- spec->mic_boost = 3; /* default 30dB gain */
-
- /* no S/PDIF out */
- spec->multiout.dig_out_nid = 0;
-
- /* input source automatically selected */
- spec->input_mux = NULL;
-
- /* our capture hooks which allow us to turn on the microphone LED
- * at the right time */
- spec->capture_prepare = cxt5066_olpc_capture_prepare;
- spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
- break;
case CXT5066_DELL_VOSTRO:
codec->patch_ops.init = cxt5066_init;
codec->patch_ops.unsol_event = cxt5066_unsol_event;
spec->init_verbs[0] = cxt5066_init_verbs_vostro;
- spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
+ spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers;
spec->port_d_mode = 0;
@@ -3207,11 +2796,7 @@ static int cx_auto_init(struct hda_codec *codec)
return 0;
}
-static void cx_auto_free(struct hda_codec *codec)
-{
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
- snd_hda_gen_free(codec);
-}
+#define cx_auto_free snd_hda_gen_free
static const struct hda_codec_ops cx_auto_patch_ops = {
.build_controls = cx_auto_build_controls,
@@ -3238,6 +2823,11 @@ enum {
CXT_FIXUP_HEADPHONE_MIC,
CXT_FIXUP_GPIO1,
CXT_FIXUP_THINKPAD_ACPI,
+ CXT_FIXUP_OLPC_XO,
+ CXT_FIXUP_CAP_MIX_AMP,
+ CXT_FIXUP_TOSHIBA_P105,
+ CXT_FIXUP_HP_530,
+ CXT_FIXUP_CAP_MIX_AMP_5047,
};
/* for hda_fixup_thinkpad_acpi() */
@@ -3316,6 +2906,288 @@ static void cxt_fixup_headphone_mic(struct hda_codec *codec,
}
}
+/* OPLC XO 1.5 fixup */
+
+/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
+ * through the microphone jack.
+ * When the user enables this through a mixer switch, both internal and
+ * external microphones are disabled. Gain is fixed at 0dB. In this mode,
+ * we also allow the bias to be configured through a separate mixer
+ * control. */
+
+#define update_mic_pin(codec, nid, val) \
+ snd_hda_codec_update_cache(codec, nid, 0, \
+ AC_VERB_SET_PIN_WIDGET_CONTROL, val)
+
+static const struct hda_input_mux olpc_xo_dc_bias = {
+ .num_items = 3,
+ .items = {
+ { "Off", PIN_IN },
+ { "50%", PIN_VREF50 },
+ { "80%", PIN_VREF80 },
+ },
+};
+
+static void olpc_xo_update_mic_boost(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ int ch, val;
+
+ for (ch = 0; ch < 2; ch++) {
+ val = AC_AMP_SET_OUTPUT |
+ (ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT);
+ if (!spec->dc_enable)
+ val |= snd_hda_codec_amp_read(codec, 0x17, ch, HDA_OUTPUT, 0);
+ snd_hda_codec_write(codec, 0x17, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, val);
+ }
+}
+
+static void olpc_xo_update_mic_pins(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ int cur_input, val;
+ struct nid_path *path;
+
+ cur_input = spec->gen.input_paths[0][spec->gen.cur_mux[0]];
+
+ /* Set up mic pins for port-B, C and F dynamically as the recording
+ * LED is turned on/off by these pin controls
+ */
+ if (!spec->dc_enable) {
+ /* disable DC bias path and pin for port F */
+ update_mic_pin(codec, 0x1e, 0);
+ snd_hda_activate_path(codec, spec->dc_mode_path, false, false);
+
+ /* update port B (ext mic) and C (int mic) */
+ /* OLPC defers mic widget control until when capture is
+ * started because the microphone LED comes on as soon as
+ * these settings are put in place. if we did this before
+ * recording, it would give the false indication that
+ * recording is happening when it is not.
+ */
+ update_mic_pin(codec, 0x1a, spec->recording ?
+ snd_hda_codec_get_pin_target(codec, 0x1a) : 0);
+ update_mic_pin(codec, 0x1b, spec->recording ?
+ snd_hda_codec_get_pin_target(codec, 0x1b) : 0);
+ /* enable normal mic path */
+ path = snd_hda_get_path_from_idx(codec, cur_input);
+ if (path)
+ snd_hda_activate_path(codec, path, true, false);
+ } else {
+ /* disable normal mic path */
+ path = snd_hda_get_path_from_idx(codec, cur_input);
+ if (path)
+ snd_hda_activate_path(codec, path, false, false);
+
+ /* Even though port F is the DC input, the bias is controlled
+ * on port B. We also leave that port as an active input (but
+ * unselected) in DC mode just in case that is necessary to
+ * make the bias setting take effect.
+ */
+ if (spec->recording)
+ val = olpc_xo_dc_bias.items[spec->dc_input_bias].index;
+ else
+ val = 0;
+ update_mic_pin(codec, 0x1a, val);
+ update_mic_pin(codec, 0x1b, 0);
+ /* enable DC bias path and pin */
+ update_mic_pin(codec, 0x1e, spec->recording ? PIN_IN : 0);
+ snd_hda_activate_path(codec, spec->dc_mode_path, true, false);
+ }
+}
+
+/* mic_autoswitch hook */
+static void olpc_xo_automic(struct hda_codec *codec, struct hda_jack_tbl *jack)
+{
+ struct conexant_spec *spec = codec->spec;
+ int saved_cached_write = codec->cached_write;
+
+ codec->cached_write = 1;
+ /* in DC mode, we don't handle automic */
+ if (!spec->dc_enable)
+ snd_hda_gen_mic_autoswitch(codec, jack);
+ olpc_xo_update_mic_pins(codec);
+ snd_hda_codec_flush_cache(codec);
+ codec->cached_write = saved_cached_write;
+ if (spec->dc_enable)
+ olpc_xo_update_mic_boost(codec);
+}
+
+/* pcm_capture hook */
+static void olpc_xo_capture_hook(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream,
+ int action)
+{
+ struct conexant_spec *spec = codec->spec;
+
+ /* toggle spec->recording flag and update mic pins accordingly
+ * for turning on/off LED
+ */
+ switch (action) {
+ case HDA_GEN_PCM_ACT_PREPARE:
+ spec->recording = 1;
+ olpc_xo_update_mic_pins(codec);
+ break;
+ case HDA_GEN_PCM_ACT_CLEANUP:
+ spec->recording = 0;
+ olpc_xo_update_mic_pins(codec);
+ break;
+ }
+}
+
+static int olpc_xo_dc_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ ucontrol->value.integer.value[0] = spec->dc_enable;
+ return 0;
+}
+
+static int olpc_xo_dc_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ int dc_enable = !!ucontrol->value.integer.value[0];
+
+ if (dc_enable == spec->dc_enable)
+ return 0;
+
+ spec->dc_enable = dc_enable;
+ olpc_xo_update_mic_pins(codec);
+ olpc_xo_update_mic_boost(codec);
+ return 1;
+}
+
+static int olpc_xo_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
+ return 0;
+}
+
+static int olpc_xo_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ return snd_hda_input_mux_info(&olpc_xo_dc_bias, uinfo);
+}
+
+static int olpc_xo_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ const struct hda_input_mux *imux = &olpc_xo_dc_bias;
+ unsigned int idx;
+
+ idx = ucontrol->value.enumerated.item[0];
+ if (idx >= imux->num_items)
+ idx = imux->num_items - 1;
+ if (spec->dc_input_bias == idx)
+ return 0;
+
+ spec->dc_input_bias = idx;
+ if (spec->dc_enable)
+ olpc_xo_update_mic_pins(codec);
+ return 1;
+}
+
+static const struct snd_kcontrol_new olpc_xo_mixers[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "DC Mode Enable Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = olpc_xo_dc_mode_get,
+ .put = olpc_xo_dc_mode_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "DC Input Bias Enum",
+ .info = olpc_xo_dc_bias_enum_info,
+ .get = olpc_xo_dc_bias_enum_get,
+ .put = olpc_xo_dc_bias_enum_put,
+ },
+ {}
+};
+
+/* overriding mic boost put callback; update mic boost volume only when
+ * DC mode is disabled
+ */
+static int olpc_xo_mic_boost_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct conexant_spec *spec = codec->spec;
+ int ret = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
+ if (ret > 0 && spec->dc_enable)
+ olpc_xo_update_mic_boost(codec);
+ return ret;
+}
+
+static void cxt_fixup_olpc_xo(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct conexant_spec *spec = codec->spec;
+ int i;
+
+ if (action != HDA_FIXUP_ACT_PROBE)
+ return;
+
+ spec->gen.mic_autoswitch_hook = olpc_xo_automic;
+ spec->gen.pcm_capture_hook = olpc_xo_capture_hook;
+ spec->dc_mode_path = snd_hda_add_new_path(codec, 0x1e, 0x14, 0);
+
+ snd_hda_add_new_ctls(codec, olpc_xo_mixers);
+
+ /* OLPC's microphone port is DC coupled for use with external sensors,
+ * therefore we use a 50% mic bias in order to center the input signal
+ * with the DC input range of the codec.
+ */
+ snd_hda_codec_set_pin_target(codec, 0x1a, PIN_VREF50);
+
+ /* override mic boost control */
+ for (i = 0; i < spec->gen.kctls.used; i++) {
+ struct snd_kcontrol_new *kctl =
+ snd_array_elem(&spec->gen.kctls, i);
+ if (!strcmp(kctl->name, "Mic Boost Volume")) {
+ kctl->put = olpc_xo_mic_boost_put;
+ break;
+ }
+ }
+}
+
+/*
+ * Fix max input level on mixer widget to 0dB
+ * (originally it has 0x2b steps with 0dB offset 0x14)
+ */
+static void cxt_fixup_cap_mix_amp(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
+ (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
+ (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+ (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+ (1 << AC_AMPCAP_MUTE_SHIFT));
+}
+
+/*
+ * Fix max input level on mixer widget to 0dB
+ * (originally it has 0x1e steps with 0 dB offset 0x17)
+ */
+static void cxt_fixup_cap_mix_amp_5047(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT,
+ (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
+ (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+ (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+ (1 << AC_AMPCAP_MUTE_SHIFT));
+}
/* ThinkPad X200 & co with cxt5051 */
static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
@@ -3401,6 +3273,68 @@ static const struct hda_fixup cxt_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = hda_fixup_thinkpad_acpi,
},
+ [CXT_FIXUP_OLPC_XO] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cxt_fixup_olpc_xo,
+ },
+ [CXT_FIXUP_CAP_MIX_AMP] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cxt_fixup_cap_mix_amp,
+ },
+ [CXT_FIXUP_TOSHIBA_P105] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x10, 0x961701f0 }, /* speaker/hp */
+ { 0x12, 0x02a1901e }, /* ext mic */
+ { 0x14, 0x95a70110 }, /* int mic */
+ {}
+ },
+ },
+ [CXT_FIXUP_HP_530] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x12, 0x90a60160 }, /* int mic */
+ {}
+ },
+ .chained = true,
+ .chain_id = CXT_FIXUP_CAP_MIX_AMP,
+ },
+ [CXT_FIXUP_CAP_MIX_AMP_5047] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cxt_fixup_cap_mix_amp_5047,
+ },
+};
+
+static const struct snd_pci_quirk cxt5045_fixups[] = {
+ SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT_FIXUP_HP_530),
+ SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT_FIXUP_TOSHIBA_P105),
+ /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have
+ * really bad sound over 0dB on NID 0x17.
+ */
+ SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP),
+ SND_PCI_QUIRK_VENDOR(0x1631, "Packard Bell", CXT_FIXUP_CAP_MIX_AMP),
+ SND_PCI_QUIRK_VENDOR(0x1734, "Fujitsu", CXT_FIXUP_CAP_MIX_AMP),
+ SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT_FIXUP_CAP_MIX_AMP),
+ {}
+};
+
+static const struct hda_model_fixup cxt5045_fixup_models[] = {
+ { .id = CXT_FIXUP_CAP_MIX_AMP, .name = "cap-mix-amp" },
+ { .id = CXT_FIXUP_TOSHIBA_P105, .name = "toshiba-p105" },
+ { .id = CXT_FIXUP_HP_530, .name = "hp-530" },
+ {}
+};
+
+static const struct snd_pci_quirk cxt5047_fixups[] = {
+ /* HP laptops have really bad sound over 0 dB on NID 0x10.
+ */
+ SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047),
+ {}
+};
+
+static const struct hda_model_fixup cxt5047_fixup_models[] = {
+ { .id = CXT_FIXUP_CAP_MIX_AMP_5047, .name = "cap-mix-amp" },
+ {}
};
static const struct snd_pci_quirk cxt5051_fixups[] = {
@@ -3408,10 +3342,16 @@ static const struct snd_pci_quirk cxt5051_fixups[] = {
{}
};
+static const struct hda_model_fixup cxt5051_fixup_models[] = {
+ { .id = CXT_PINCFG_LENOVO_X200, .name = "lenovo-x200" },
+ {}
+};
+
static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_GPIO1),
SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
+ SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
@@ -3428,6 +3368,17 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
{}
};
+static const struct hda_model_fixup cxt5066_fixup_models[] = {
+ { .id = CXT_FIXUP_STEREO_DMIC, .name = "stereo-dmic" },
+ { .id = CXT_FIXUP_GPIO1, .name = "gpio1" },
+ { .id = CXT_FIXUP_HEADPHONE_MIC_PIN, .name = "headphone-mic-pin" },
+ { .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" },
+ { .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" },
+ { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" },
+ { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" },
+ {}
+};
+
/* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches
* can be created (bko#42825)
*/
@@ -3449,8 +3400,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
struct conexant_spec *spec;
int err;
- printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
- codec->chip_name);
+ codec_info(codec, "%s: BIOS auto-probing.\n", codec->chip_name);
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
@@ -3467,19 +3417,28 @@ static int patch_conexant_auto(struct hda_codec *codec)
switch (codec->vendor_id) {
case 0x14f15045:
codec->single_adc_amp = 1;
+ spec->gen.mixer_nid = 0x17;
+ spec->gen.add_stereo_mix_input = 1;
+ snd_hda_pick_fixup(codec, cxt5045_fixup_models,
+ cxt5045_fixups, cxt_fixups);
break;
case 0x14f15047:
codec->pin_amp_workaround = 1;
spec->gen.mixer_nid = 0x19;
+ spec->gen.add_stereo_mix_input = 1;
+ snd_hda_pick_fixup(codec, cxt5047_fixup_models,
+ cxt5047_fixups, cxt_fixups);
break;
case 0x14f15051:
add_cx5051_fake_mutes(codec);
codec->pin_amp_workaround = 1;
- snd_hda_pick_fixup(codec, NULL, cxt5051_fixups, cxt_fixups);
+ snd_hda_pick_fixup(codec, cxt5051_fixup_models,
+ cxt5051_fixups, cxt_fixups);
break;
default:
codec->pin_amp_workaround = 1;
- snd_hda_pick_fixup(codec, NULL, cxt5066_fixups, cxt_fixups);
+ snd_hda_pick_fixup(codec, cxt5066_fixup_models,
+ cxt5066_fixups, cxt_fixups);
break;
}
@@ -3513,7 +3472,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
* Better to make reset, then.
*/
if (!codec->bus->sync_write) {
- snd_printd("hda_codec: "
+ codec_info(codec,
"Enable sync_write for stable communication\n");
codec->bus->sync_write = 1;
codec->bus->allow_bus_reset = 1;
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 5ef95034d041..0cb5b89cd0c8 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -68,6 +68,7 @@ struct hdmi_spec_per_pin {
hda_nid_t pin_nid;
int num_mux_nids;
hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+ int mux_idx;
hda_nid_t cvt_nid;
struct hda_codec *codec;
@@ -353,40 +354,43 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
#define get_pcm_rec(spec, idx) \
((struct hda_pcm *)snd_array_elem(&spec->pcm_rec, idx))
-static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid)
+static int pin_nid_to_pin_index(struct hda_codec *codec, hda_nid_t pin_nid)
{
+ struct hdmi_spec *spec = codec->spec;
int pin_idx;
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
if (get_pin(spec, pin_idx)->pin_nid == pin_nid)
return pin_idx;
- snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid);
+ codec_warn(codec, "HDMI: pin nid %d not registered\n", pin_nid);
return -EINVAL;
}
-static int hinfo_to_pin_index(struct hdmi_spec *spec,
+static int hinfo_to_pin_index(struct hda_codec *codec,
struct hda_pcm_stream *hinfo)
{
+ struct hdmi_spec *spec = codec->spec;
int pin_idx;
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
if (get_pcm_rec(spec, pin_idx)->stream == hinfo)
return pin_idx;
- snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo);
+ codec_warn(codec, "HDMI: hinfo %p not registered\n", hinfo);
return -EINVAL;
}
-static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid)
+static int cvt_nid_to_cvt_index(struct hda_codec *codec, hda_nid_t cvt_nid)
{
+ struct hdmi_spec *spec = codec->spec;
int cvt_idx;
for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++)
if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid)
return cvt_idx;
- snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid);
+ codec_warn(codec, "HDMI: cvt nid %d not registered\n", cvt_nid);
return -EINVAL;
}
@@ -706,7 +710,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec,
for (i = 0; i < 8; i++) {
channel = spec->ops.pin_get_slot_channel(codec, pin_nid, i);
- printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n",
+ codec_dbg(codec, "HDMI: ASP channel %d => slot %d\n",
channel, i);
}
#endif
@@ -755,8 +759,7 @@ static void hdmi_std_setup_channel_mapping(struct hda_codec *codec,
int channel = (slotsetup & 0xf0) >> 4;
err = spec->ops.pin_set_slot_channel(codec, pin_nid, hdmi_slot, channel);
if (err) {
- snd_printdd(KERN_NOTICE
- "HDMI: channel mapping failed\n");
+ codec_dbg(codec, "HDMI: channel mapping failed\n");
break;
}
}
@@ -967,12 +970,12 @@ static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid)
int size;
size = snd_hdmi_get_eld_size(codec, pin_nid);
- printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size);
+ codec_dbg(codec, "HDMI: ELD buf size is %d\n", size);
for (i = 0; i < 8; i++) {
size = snd_hda_codec_read(codec, pin_nid, 0,
AC_VERB_GET_HDMI_DIP_SIZE, i);
- printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size);
+ codec_dbg(codec, "HDMI: DIP GP[%d] buf size is %d\n", i, size);
}
#endif
}
@@ -994,12 +997,12 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
hdmi_write_dip_byte(codec, pin_nid, 0x0);
hdmi_get_dip_index(codec, pin_nid, &pi, &bi);
if (pi != i)
- snd_printd(KERN_INFO "dip index %d: %d != %d\n",
+ codec_dbg(codec, "dip index %d: %d != %d\n",
bi, pi, i);
if (bi == 0) /* byte index wrapped around */
break;
}
- snd_printd(KERN_INFO
+ codec_dbg(codec,
"HDMI: DIP GP[%d] buf reported size=%d, written=%d\n",
i, size, j);
}
@@ -1062,6 +1065,7 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
{
union audio_infoframe ai;
+ memset(&ai, 0, sizeof(ai));
if (conn_type == 0) { /* HDMI */
struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
@@ -1080,7 +1084,7 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
dp_ai->CC02_CT47 = active_channels - 1;
dp_ai->CA = ca;
} else {
- snd_printd("HDMI: unknown connection type at pin %d\n",
+ codec_dbg(codec, "HDMI: unknown connection type at pin %d\n",
pin_nid);
return;
}
@@ -1092,8 +1096,8 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
*/
if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
sizeof(ai))) {
- snd_printdd("hdmi_pin_setup_infoframe: "
- "pin=%d channels=%d ca=0x%02x\n",
+ codec_dbg(codec,
+ "hdmi_pin_setup_infoframe: pin=%d channels=%d ca=0x%02x\n",
pin_nid,
active_channels, ca);
hdmi_stop_infoframe_trans(codec, pin_nid);
@@ -1161,7 +1165,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
static void jack_callback(struct hda_codec *codec, struct hda_jack_tbl *jack)
{
struct hdmi_spec *spec = codec->spec;
- int pin_idx = pin_nid_to_pin_index(spec, jack->nid);
+ int pin_idx = pin_nid_to_pin_index(codec, jack->nid);
if (pin_idx < 0)
return;
@@ -1180,7 +1184,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
return;
jack->jack_dirty = 1;
- _snd_printd(SND_PR_VERBOSE,
+ codec_dbg(codec,
"HDMI hot plug event: Codec=%d Pin=%d Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n",
codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
!!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
@@ -1195,7 +1199,7 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
- printk(KERN_INFO
+ codec_info(codec,
"HDMI CP event: CODEC=%d TAG=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
codec->addr,
tag,
@@ -1217,7 +1221,7 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
if (!snd_hda_jack_tbl_get_from_tag(codec, tag)) {
- snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
+ codec_dbg(codec, "Unexpected HDMI event tag 0x%x\n", tag);
return;
}
@@ -1244,7 +1248,7 @@ static void haswell_verify_D0(struct hda_codec *codec,
msleep(40);
pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
- snd_printd("Haswell HDMI audio: Power for pin 0x%x is now D%d\n", nid, pwr);
+ codec_dbg(codec, "Haswell HDMI audio: Power for pin 0x%x is now D%d\n", nid, pwr);
}
}
@@ -1274,8 +1278,8 @@ static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
else
new_pinctl |= AC_PINCTL_EPT_NATIVE;
- snd_printdd("hdmi_pin_hbr_setup: "
- "NID=0x%x, %spinctl=0x%x\n",
+ codec_dbg(codec,
+ "hdmi_pin_hbr_setup: NID=0x%x, %spinctl=0x%x\n",
pin_nid,
pinctl == new_pinctl ? "" : "new-",
new_pinctl);
@@ -1302,7 +1306,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
err = spec->ops.pin_hbr_setup(codec, pin_nid, is_hbr_format(format));
if (err) {
- snd_printdd("hdmi_setup_stream: HBR is not supported\n");
+ codec_dbg(codec, "hdmi_setup_stream: HBR is not supported\n");
return err;
}
@@ -1341,6 +1345,8 @@ static int hdmi_choose_cvt(struct hda_codec *codec,
if (cvt_idx == spec->num_cvts)
return -ENODEV;
+ per_pin->mux_idx = mux_idx;
+
if (cvt_id)
*cvt_id = cvt_idx;
if (mux_id)
@@ -1349,6 +1355,22 @@ static int hdmi_choose_cvt(struct hda_codec *codec,
return 0;
}
+/* Assure the pin select the right convetor */
+static void intel_verify_pin_cvt_connect(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin)
+{
+ hda_nid_t pin_nid = per_pin->pin_nid;
+ int mux_idx, curr;
+
+ mux_idx = per_pin->mux_idx;
+ curr = snd_hda_codec_read(codec, pin_nid, 0,
+ AC_VERB_GET_CONNECT_SEL, 0);
+ if (curr != mux_idx)
+ snd_hda_codec_write_cache(codec, pin_nid, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ mux_idx);
+}
+
/* Intel HDMI workaround to fix audio routing issue:
* For some Intel display codecs, pins share the same connection list.
* So a conveter can be selected by multiple pins and playback on any of these
@@ -1389,7 +1411,8 @@ static void intel_not_share_assigned_cvt(struct hda_codec *codec,
for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
per_cvt = get_cvt(spec, cvt_idx);
if (!per_cvt->assigned) {
- snd_printdd("choose cvt %d for pin nid %d\n",
+ codec_dbg(codec,
+ "choose cvt %d for pin nid %d\n",
cvt_idx, nid);
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_CONNECT_SEL,
@@ -1416,7 +1439,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
int err;
/* Validate hinfo */
- pin_idx = hinfo_to_pin_index(spec, hinfo);
+ pin_idx = hinfo_to_pin_index(codec, hinfo);
if (snd_BUG_ON(pin_idx < 0))
return -EINVAL;
per_pin = get_pin(spec, pin_idx);
@@ -1482,9 +1505,8 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
hda_nid_t pin_nid = per_pin->pin_nid;
if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
- snd_printk(KERN_WARNING
- "HDMI: pin %d wcaps %#x "
- "does not support connection list\n",
+ codec_warn(codec,
+ "HDMI: pin %d wcaps %#x does not support connection list\n",
pin_nid, get_wcaps(codec, pin_nid));
return -EINVAL;
}
@@ -1527,7 +1549,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
else
eld->eld_valid = false;
- _snd_printd(SND_PR_VERBOSE,
+ codec_dbg(codec,
"HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
codec->addr, pin_nid, pin_eld->monitor_present, eld->eld_valid);
@@ -1690,7 +1712,7 @@ static int hdmi_parse_codec(struct hda_codec *codec)
nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
if (!nid || nodes < 0) {
- snd_printk(KERN_WARNING "HDMI: failed to get afg sub nodes\n");
+ codec_warn(codec, "HDMI: failed to get afg sub nodes\n");
return -EINVAL;
}
@@ -1744,12 +1766,25 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
{
hda_nid_t cvt_nid = hinfo->nid;
struct hdmi_spec *spec = codec->spec;
- int pin_idx = hinfo_to_pin_index(spec, hinfo);
+ int pin_idx = hinfo_to_pin_index(codec, hinfo);
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
hda_nid_t pin_nid = per_pin->pin_nid;
bool non_pcm;
int pinctl;
+ if (is_haswell_plus(codec) || is_valleyview(codec)) {
+ /* Verify pin:cvt selections to avoid silent audio after S3.
+ * After S3, the audio driver restores pin:cvt selections
+ * but this can happen before gfx is ready and such selection
+ * is overlooked by HW. Thus multiple pins can share a same
+ * default convertor and mute control will affect each other,
+ * which can cause a resumed audio playback become silent
+ * after S3.
+ */
+ intel_verify_pin_cvt_connect(codec, per_pin);
+ intel_not_share_assigned_cvt(codec, pin_nid, per_pin->mux_idx);
+ }
+
non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
mutex_lock(&per_pin->lock);
per_pin->channels = substream->runtime->channels;
@@ -1788,7 +1823,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
int pinctl;
if (hinfo->nid) {
- cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
+ cvt_idx = cvt_nid_to_cvt_index(codec, hinfo->nid);
if (snd_BUG_ON(cvt_idx < 0))
return -EINVAL;
per_cvt = get_cvt(spec, cvt_idx);
@@ -1797,7 +1832,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
per_cvt->assigned = 0;
hinfo->nid = 0;
- pin_idx = hinfo_to_pin_index(spec, hinfo);
+ pin_idx = hinfo_to_pin_index(codec, hinfo);
if (snd_BUG_ON(pin_idx < 0))
return -EINVAL;
per_pin = get_pin(spec, pin_idx);
@@ -2211,7 +2246,7 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
return;
/* override pins connection list */
- snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid);
+ codec_dbg(codec, "hdmi: haswell: override pin connection 0x%x\n", nid);
snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids);
}
@@ -3132,8 +3167,8 @@ static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
else
hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE;
- snd_printdd("atihdmi_pin_hbr_setup: "
- "NID=0x%x, %shbr-ctl=0x%x\n",
+ codec_dbg(codec,
+ "atihdmi_pin_hbr_setup: NID=0x%x, %shbr-ctl=0x%x\n",
pin_nid,
hbr_ctl == hbr_ctl_new ? "" : "new-",
hbr_ctl_new);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index a9a83b85517a..ea2351d119f0 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -395,6 +395,8 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec)
goto do_sku;
}
+ if (!codec->bus->pci)
+ return -1;
ass = codec->subsystem_id & 0xffff;
if (ass != codec->bus->pci->subsystem_device && (ass & 1))
goto do_sku;
@@ -405,8 +407,8 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec)
ass = snd_hda_codec_get_pincfg(codec, nid);
if (!(ass & 1)) {
- printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
- codec->chip_name, ass);
+ codec_info(codec, "%s: SKU not ready 0x%08x\n",
+ codec->chip_name, ass);
return -1;
}
@@ -430,17 +432,17 @@ do_sku:
spec->cdefine.swap = (ass & 0x2) >> 1;
spec->cdefine.override = ass & 0x1;
- snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
+ codec_dbg(codec, "SKU: Nid=0x%x sku_cfg=0x%08x\n",
nid, spec->cdefine.sku_cfg);
- snd_printd("SKU: port_connectivity=0x%x\n",
+ codec_dbg(codec, "SKU: port_connectivity=0x%x\n",
spec->cdefine.port_connectivity);
- snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
- snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
- snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
- snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
- snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
- snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
- snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
+ codec_dbg(codec, "SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
+ codec_dbg(codec, "SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
+ codec_dbg(codec, "SKU: customization=0x%08x\n", spec->cdefine.customization);
+ codec_dbg(codec, "SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
+ codec_dbg(codec, "SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
+ codec_dbg(codec, "SKU: swap=0x%x\n", spec->cdefine.swap);
+ codec_dbg(codec, "SKU: override=0x%x\n", spec->cdefine.override);
return 0;
}
@@ -483,7 +485,8 @@ static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
}
ass = codec->subsystem_id & 0xffff;
- if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
+ if (codec->bus->pci &&
+ ass != codec->bus->pci->subsystem_device && (ass & 1))
goto do_sku;
/* invalid SSID, check the special NID pin defcfg instead */
@@ -499,8 +502,8 @@ static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
if (codec->vendor_id == 0x10ec0260)
nid = 0x17;
ass = snd_hda_codec_get_pincfg(codec, nid);
- snd_printd("realtek: No valid SSID, "
- "checking pincfg 0x%08x for NID 0x%x\n",
+ codec_dbg(codec,
+ "realtek: No valid SSID, checking pincfg 0x%08x for NID 0x%x\n",
ass, nid);
if (!(ass & 1))
return 0;
@@ -516,7 +519,7 @@ static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
if (((ass >> 16) & 0xf) != tmp)
return 0;
do_sku:
- snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
+ codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
ass & 0xffff, codec->vendor_id);
/*
* 0 : override
@@ -574,8 +577,8 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
{
if (!alc_subsystem_id(codec, ports)) {
struct alc_spec *spec = codec->spec;
- snd_printd("realtek: "
- "Enable default setup for auto mode as fallback\n");
+ codec_dbg(codec,
+ "realtek: Enable default setup for auto mode as fallback\n");
spec->init_amp = ALC_INIT_DEFAULT;
}
}
@@ -845,11 +848,7 @@ static inline void alc_shutup(struct hda_codec *codec)
snd_hda_shutup_pins(codec);
}
-static void alc_free(struct hda_codec *codec)
-{
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
- snd_hda_gen_free(codec);
-}
+#define alc_free snd_hda_gen_free
#ifdef CONFIG_PM
static void alc_power_eapd(struct hda_codec *codec)
@@ -970,6 +969,8 @@ static int alc_codec_rename_from_preset(struct hda_codec *codec)
return alc_codec_rename(codec, p->name);
}
+ if (!codec->bus->pci)
+ return 0;
for (q = rename_pci_tbl; q->codec_vendor_id; q++) {
if (q->codec_vendor_id != codec->vendor_id)
continue;
@@ -993,6 +994,7 @@ static int alc_codec_rename_from_preset(struct hda_codec *codec)
static const struct snd_pci_quirk beep_white_list[] = {
SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
+ SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1),
SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
SND_PCI_QUIRK(0x1043, 0x8376, "EeePC", 1),
SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
@@ -2786,6 +2788,237 @@ static void alc269_shutup(struct hda_codec *codec)
snd_hda_shutup_pins(codec);
}
+static void alc282_restore_default_value(struct hda_codec *codec)
+{
+ int val;
+
+ /* Power Down Control */
+ alc_write_coef_idx(codec, 0x03, 0x0002);
+ /* FIFO and filter clock */
+ alc_write_coef_idx(codec, 0x05, 0x0700);
+ /* DMIC control */
+ alc_write_coef_idx(codec, 0x07, 0x0200);
+ /* Analog clock */
+ val = alc_read_coef_idx(codec, 0x06);
+ alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0);
+ /* JD */
+ val = alc_read_coef_idx(codec, 0x08);
+ alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c);
+ /* JD offset1 */
+ alc_write_coef_idx(codec, 0x0a, 0xcccc);
+ /* JD offset2 */
+ alc_write_coef_idx(codec, 0x0b, 0xcccc);
+ /* LDO1/2/3, DAC/ADC */
+ alc_write_coef_idx(codec, 0x0e, 0x6e00);
+ /* JD */
+ val = alc_read_coef_idx(codec, 0x0f);
+ alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000);
+ /* Capless */
+ val = alc_read_coef_idx(codec, 0x10);
+ alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00);
+ /* Class D test 4 */
+ alc_write_coef_idx(codec, 0x6f, 0x0);
+ /* IO power down directly */
+ val = alc_read_coef_idx(codec, 0x0c);
+ alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0);
+ /* ANC */
+ alc_write_coef_idx(codec, 0x34, 0xa0c0);
+ /* AGC MUX */
+ val = alc_read_coef_idx(codec, 0x16);
+ alc_write_coef_idx(codec, 0x16, (val & ~0x0008) | 0x0);
+ /* DAC simple content protection */
+ val = alc_read_coef_idx(codec, 0x1d);
+ alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0);
+ /* ADC simple content protection */
+ val = alc_read_coef_idx(codec, 0x1f);
+ alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0);
+ /* DAC ADC Zero Detection */
+ alc_write_coef_idx(codec, 0x21, 0x8804);
+ /* PLL */
+ alc_write_coef_idx(codec, 0x63, 0x2902);
+ /* capless control 2 */
+ alc_write_coef_idx(codec, 0x68, 0xa080);
+ /* capless control 3 */
+ alc_write_coef_idx(codec, 0x69, 0x3400);
+ /* capless control 4 */
+ alc_write_coef_idx(codec, 0x6a, 0x2f3e);
+ /* capless control 5 */
+ alc_write_coef_idx(codec, 0x6b, 0x0);
+ /* class D test 2 */
+ val = alc_read_coef_idx(codec, 0x6d);
+ alc_write_coef_idx(codec, 0x6d, (val & ~0x0fff) | 0x0900);
+ /* class D test 3 */
+ alc_write_coef_idx(codec, 0x6e, 0x110a);
+ /* class D test 5 */
+ val = alc_read_coef_idx(codec, 0x70);
+ alc_write_coef_idx(codec, 0x70, (val & ~0x00f8) | 0x00d8);
+ /* class D test 6 */
+ alc_write_coef_idx(codec, 0x71, 0x0014);
+ /* classD OCP */
+ alc_write_coef_idx(codec, 0x72, 0xc2ba);
+ /* classD pure DC test */
+ val = alc_read_coef_idx(codec, 0x77);
+ alc_write_coef_idx(codec, 0x77, (val & ~0x0f80) | 0x0);
+ /* Class D amp control */
+ alc_write_coef_idx(codec, 0x6c, 0xfc06);
+}
+
+static void alc282_init(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+ bool hp_pin_sense;
+ int coef78;
+
+ alc282_restore_default_value(codec);
+
+ if (!hp_pin)
+ return;
+ hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+ coef78 = alc_read_coef_idx(codec, 0x78);
+
+ /* Index 0x78 Direct Drive HP AMP LPM Control 1 */
+ /* Headphone capless set to high power mode */
+ alc_write_coef_idx(codec, 0x78, 0x9004);
+
+ if (hp_pin_sense)
+ msleep(2);
+
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+ if (hp_pin_sense)
+ msleep(85);
+
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+ if (hp_pin_sense)
+ msleep(100);
+
+ /* Headphone capless set to normal mode */
+ alc_write_coef_idx(codec, 0x78, coef78);
+}
+
+static void alc282_shutup(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+ bool hp_pin_sense;
+ int coef78;
+
+ if (!hp_pin) {
+ alc269_shutup(codec);
+ return;
+ }
+
+ hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+ coef78 = alc_read_coef_idx(codec, 0x78);
+ alc_write_coef_idx(codec, 0x78, 0x9004);
+
+ if (hp_pin_sense)
+ msleep(2);
+
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+ if (hp_pin_sense)
+ msleep(85);
+
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+ if (hp_pin_sense)
+ msleep(100);
+
+ alc_auto_setup_eapd(codec, false);
+ snd_hda_shutup_pins(codec);
+ alc_write_coef_idx(codec, 0x78, coef78);
+}
+
+static void alc283_restore_default_value(struct hda_codec *codec)
+{
+ int val;
+
+ /* Power Down Control */
+ alc_write_coef_idx(codec, 0x03, 0x0002);
+ /* FIFO and filter clock */
+ alc_write_coef_idx(codec, 0x05, 0x0700);
+ /* DMIC control */
+ alc_write_coef_idx(codec, 0x07, 0x0200);
+ /* Analog clock */
+ val = alc_read_coef_idx(codec, 0x06);
+ alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0);
+ /* JD */
+ val = alc_read_coef_idx(codec, 0x08);
+ alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c);
+ /* JD offset1 */
+ alc_write_coef_idx(codec, 0x0a, 0xcccc);
+ /* JD offset2 */
+ alc_write_coef_idx(codec, 0x0b, 0xcccc);
+ /* LDO1/2/3, DAC/ADC */
+ alc_write_coef_idx(codec, 0x0e, 0x6fc0);
+ /* JD */
+ val = alc_read_coef_idx(codec, 0x0f);
+ alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000);
+ /* Capless */
+ val = alc_read_coef_idx(codec, 0x10);
+ alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00);
+ /* Class D test 4 */
+ alc_write_coef_idx(codec, 0x3a, 0x0);
+ /* IO power down directly */
+ val = alc_read_coef_idx(codec, 0x0c);
+ alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0);
+ /* ANC */
+ alc_write_coef_idx(codec, 0x22, 0xa0c0);
+ /* AGC MUX */
+ val = alc_read_coefex_idx(codec, 0x53, 0x01);
+ alc_write_coefex_idx(codec, 0x53, 0x01, (val & ~0x000f) | 0x0008);
+ /* DAC simple content protection */
+ val = alc_read_coef_idx(codec, 0x1d);
+ alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0);
+ /* ADC simple content protection */
+ val = alc_read_coef_idx(codec, 0x1f);
+ alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0);
+ /* DAC ADC Zero Detection */
+ alc_write_coef_idx(codec, 0x21, 0x8804);
+ /* PLL */
+ alc_write_coef_idx(codec, 0x2e, 0x2902);
+ /* capless control 2 */
+ alc_write_coef_idx(codec, 0x33, 0xa080);
+ /* capless control 3 */
+ alc_write_coef_idx(codec, 0x34, 0x3400);
+ /* capless control 4 */
+ alc_write_coef_idx(codec, 0x35, 0x2f3e);
+ /* capless control 5 */
+ alc_write_coef_idx(codec, 0x36, 0x0);
+ /* class D test 2 */
+ val = alc_read_coef_idx(codec, 0x38);
+ alc_write_coef_idx(codec, 0x38, (val & ~0x0fff) | 0x0900);
+ /* class D test 3 */
+ alc_write_coef_idx(codec, 0x39, 0x110a);
+ /* class D test 5 */
+ val = alc_read_coef_idx(codec, 0x3b);
+ alc_write_coef_idx(codec, 0x3b, (val & ~0x00f8) | 0x00d8);
+ /* class D test 6 */
+ alc_write_coef_idx(codec, 0x3c, 0x0014);
+ /* classD OCP */
+ alc_write_coef_idx(codec, 0x3d, 0xc2ba);
+ /* classD pure DC test */
+ val = alc_read_coef_idx(codec, 0x42);
+ alc_write_coef_idx(codec, 0x42, (val & ~0x0f80) | 0x0);
+ /* test mode */
+ alc_write_coef_idx(codec, 0x49, 0x0);
+ /* Class D DC enable */
+ val = alc_read_coef_idx(codec, 0x40);
+ alc_write_coef_idx(codec, 0x40, (val & ~0xf800) | 0x9800);
+ /* DC offset */
+ val = alc_read_coef_idx(codec, 0x42);
+ alc_write_coef_idx(codec, 0x42, (val & ~0xf000) | 0x2000);
+ /* Class D amp control */
+ alc_write_coef_idx(codec, 0x37, 0xfc06);
+}
+
static void alc283_init(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -2793,6 +3026,8 @@ static void alc283_init(struct hda_codec *codec)
bool hp_pin_sense;
int val;
+ alc283_restore_default_value(codec);
+
if (!hp_pin)
return;
hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
@@ -3169,7 +3404,8 @@ static void alc269_fixup_hp_mute_led(struct hda_codec *codec,
spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook;
spec->gen.vmaster_mute_enum = 1;
codec->power_filter = led_power_filter;
- snd_printd("Detected mute LED for %x:%d\n", spec->mute_led_nid,
+ codec_dbg(codec,
+ "Detected mute LED for %x:%d\n", spec->mute_led_nid,
spec->mute_led_polarity);
break;
}
@@ -3295,7 +3531,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
alc_write_coef_idx(codec, 0xb7, 0x802b);
break;
}
- snd_printdd("Headset jack set to unplugged mode.\n");
+ codec_dbg(codec, "Headset jack set to unplugged mode.\n");
}
@@ -3338,7 +3574,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
break;
}
- snd_printdd("Headset jack set to mic-in mode.\n");
+ codec_dbg(codec, "Headset jack set to mic-in mode.\n");
}
static void alc_headset_mode_default(struct hda_codec *codec)
@@ -3366,7 +3602,7 @@ static void alc_headset_mode_default(struct hda_codec *codec)
alc_write_coef_idx(codec, 0xb7, 0x802b);
break;
}
- snd_printdd("Headset jack set to headphone (default) mode.\n");
+ codec_dbg(codec, "Headset jack set to headphone (default) mode.\n");
}
/* Iphone type */
@@ -3395,7 +3631,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
alc_write_coef_idx(codec, 0xc3, 0x0000);
break;
}
- snd_printdd("Headset jack set to iPhone-style headset mode.\n");
+ codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
}
/* Nokia type */
@@ -3424,7 +3660,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
alc_write_coef_idx(codec, 0xc3, 0x0000);
break;
}
- snd_printdd("Headset jack set to Nokia-style headset mode.\n");
+ codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n");
}
static void alc_determine_headset_type(struct hda_codec *codec)
@@ -3466,7 +3702,7 @@ static void alc_determine_headset_type(struct hda_codec *codec)
break;
}
- snd_printdd("Headset jack detected iPhone-style headset: %s\n",
+ codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n",
is_ctia ? "yes" : "no");
spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
}
@@ -3592,21 +3828,38 @@ static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
alc_fixup_headset_mode(codec, fix, action);
}
+static void alc255_set_default_jack_type(struct hda_codec *codec)
+{
+ /* Set to iphone type */
+ alc_write_coef_idx(codec, 0x1b, 0x880b);
+ alc_write_coef_idx(codec, 0x45, 0xd089);
+ alc_write_coef_idx(codec, 0x1b, 0x080b);
+ alc_write_coef_idx(codec, 0x46, 0x0004);
+ alc_write_coef_idx(codec, 0x1b, 0x0c0b);
+ msleep(30);
+}
+
static void alc_fixup_headset_mode_alc255(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- /* Set to iphone type */
- alc_write_coef_idx(codec, 0x1b, 0x880b);
- alc_write_coef_idx(codec, 0x45, 0xd089);
- alc_write_coef_idx(codec, 0x1b, 0x080b);
- alc_write_coef_idx(codec, 0x46, 0x0004);
- alc_write_coef_idx(codec, 0x1b, 0x0c0b);
- msleep(30);
+ alc255_set_default_jack_type(codec);
}
alc_fixup_headset_mode(codec, fix, action);
}
+static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ struct alc_spec *spec = codec->spec;
+ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+ alc255_set_default_jack_type(codec);
+ }
+ else
+ alc_fixup_headset_mode(codec, fix, action);
+}
+
static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -3616,6 +3869,19 @@ static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
}
}
+static void alc_no_shutup(struct hda_codec *codec)
+{
+}
+
+static void alc_fixup_no_shutup(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ struct alc_spec *spec = codec->spec;
+ spec->shutup = alc_no_shutup;
+ }
+}
+
static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -3844,6 +4110,7 @@ enum {
ALC269_FIXUP_HP_GPIO_LED,
ALC269_FIXUP_INV_DMIC,
ALC269_FIXUP_LENOVO_DOCK,
+ ALC269_FIXUP_NO_SHUTUP,
ALC286_FIXUP_SONY_MIC_NO_PRESENCE,
ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
@@ -3873,7 +4140,9 @@ enum {
ALC290_FIXUP_SUBWOOFER_HSJACK,
ALC269_FIXUP_THINKPAD_ACPI,
ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+ ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
ALC255_FIXUP_HEADSET_MODE,
+ ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -4020,6 +4289,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_inv_dmic_0x12,
},
+ [ALC269_FIXUP_NO_SHUTUP] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_no_shutup,
+ },
[ALC269_FIXUP_LENOVO_DOCK] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -4246,13 +4519,27 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC255_FIXUP_HEADSET_MODE
},
+ [ALC255_FIXUP_DELL2_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC
+ },
[ALC255_FIXUP_HEADSET_MODE] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_headset_mode_alc255,
},
+ [ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_mode_alc255_no_hp_mic,
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x0283, "Acer TravelMate 8371", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
@@ -4300,6 +4587,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0629, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x062c, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x062e, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0632, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
SND_PCI_QUIRK(0x1028, 0x063e, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -4308,8 +4598,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0652, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0657, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0658, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x065f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0662, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0669, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -4317,6 +4611,54 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
+ /* ALC282 */
+ SND_PCI_QUIRK(0x103c, 0x220f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2213, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2266, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2267, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2269, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x227a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x227b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22a0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22c0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22c1, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22c2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22cd, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22ce, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22d0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ /* ALC290 */
+ SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2261, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2262, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x227d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x227e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2280, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2281, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2289, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x228a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x228b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x228c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x228d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x228e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22c5, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22c6, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22c7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22c3, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -4354,6 +4696,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -4503,13 +4846,15 @@ static int patch_alc269(struct hda_codec *codec)
spec->codec_variant = ALC269_TYPE_ALC269VA;
switch (alc_get_coef0(codec) & 0x00f0) {
case 0x0010:
- if (codec->bus->pci->subsystem_vendor == 0x1025 &&
+ if (codec->bus->pci &&
+ codec->bus->pci->subsystem_vendor == 0x1025 &&
spec->cdefine.platform_type == 1)
err = alc_codec_rename(codec, "ALC271X");
spec->codec_variant = ALC269_TYPE_ALC269VB;
break;
case 0x0020:
- if (codec->bus->pci->subsystem_vendor == 0x17aa &&
+ if (codec->bus->pci &&
+ codec->bus->pci->subsystem_vendor == 0x17aa &&
codec->bus->pci->subsystem_device == 0x21f3)
err = alc_codec_rename(codec, "ALC3202");
spec->codec_variant = ALC269_TYPE_ALC269VC;
@@ -4532,6 +4877,8 @@ static int patch_alc269(struct hda_codec *codec)
break;
case 0x10ec0282:
spec->codec_variant = ALC269_TYPE_ALC282;
+ spec->shutup = alc282_shutup;
+ spec->init_hook = alc282_init;
break;
case 0x10ec0233:
case 0x10ec0283:
@@ -4849,8 +5196,7 @@ static void alc272_fixup_mario(struct hda_codec *codec,
(0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
(0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
(0 << AC_AMPCAP_MUTE_SHIFT)))
- printk(KERN_WARNING
- "hda_codec: failed to override amp caps for NID 0x2\n");
+ codec_warn(codec, "failed to override amp caps for NID 0x2\n");
}
static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = {
@@ -4872,8 +5218,54 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec,
}
}
+/* turn on/off mute LED per vmaster hook */
+static void alc662_led_gpio1_mute_hook(void *private_data, int enabled)
+{
+ struct hda_codec *codec = private_data;
+ struct alc_spec *spec = codec->spec;
+ unsigned int oldval = spec->gpio_led;
+
+ if (enabled)
+ spec->gpio_led &= ~0x01;
+ else
+ spec->gpio_led |= 0x01;
+ if (spec->gpio_led != oldval)
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+ spec->gpio_led);
+}
+
+/* avoid D3 for keeping GPIO up */
+static unsigned int gpio_led_power_filter(struct hda_codec *codec,
+ hda_nid_t nid,
+ unsigned int power_state)
+{
+ struct alc_spec *spec = codec->spec;
+ if (nid == codec->afg && power_state == AC_PWRST_D3 && spec->gpio_led)
+ return AC_PWRST_D0;
+ return power_state;
+}
+
+static void alc662_fixup_led_gpio1(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static const struct hda_verb gpio_init[] = {
+ { 0x01, AC_VERB_SET_GPIO_MASK, 0x01 },
+ { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 },
+ {}
+ };
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->gen.vmaster_mute.hook = alc662_led_gpio1_mute_hook;
+ spec->gpio_led = 0;
+ snd_hda_add_verbs(codec, gpio_init);
+ codec->power_filter = gpio_led_power_filter;
+ }
+}
+
enum {
ALC662_FIXUP_ASPIRE,
+ ALC662_FIXUP_LED_GPIO1,
ALC662_FIXUP_IDEAPAD,
ALC272_FIXUP_MARIO,
ALC662_FIXUP_CZC_P10T,
@@ -4892,9 +5284,10 @@ enum {
ALC662_FIXUP_INV_DMIC,
ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
ALC668_FIXUP_HEADSET_MODE,
- ALC662_FIXUP_BASS_CHMAP,
+ ALC662_FIXUP_BASS_MODE4_CHMAP,
+ ALC662_FIXUP_BASS_16,
ALC662_FIXUP_BASS_1A,
- ALC662_FIXUP_BASS_1A_CHMAP,
+ ALC662_FIXUP_BASS_CHMAP,
ALC668_FIXUP_AUTO_MUTE,
};
@@ -4906,12 +5299,18 @@ static const struct hda_fixup alc662_fixups[] = {
{ }
}
},
+ [ALC662_FIXUP_LED_GPIO1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc662_fixup_led_gpio1,
+ },
[ALC662_FIXUP_IDEAPAD] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
{ 0x17, 0x99130112 }, /* subwoofer */
{ }
- }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_LED_GPIO1,
},
[ALC272_FIXUP_MARIO] = {
.type = HDA_FIXUP_FUNC,
@@ -5076,24 +5475,33 @@ static const struct hda_fixup alc662_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_headset_mode_alc668,
},
- [ALC662_FIXUP_BASS_CHMAP] = {
+ [ALC662_FIXUP_BASS_MODE4_CHMAP] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_bass_chmap,
.chained = true,
.chain_id = ALC662_FIXUP_ASUS_MODE4
},
+ [ALC662_FIXUP_BASS_16] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ {0x16, 0x80106111}, /* bass speaker */
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_BASS_CHMAP,
+ },
[ALC662_FIXUP_BASS_1A] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
{0x1a, 0x80106111}, /* bass speaker */
{}
},
+ .chained = true,
+ .chain_id = ALC662_FIXUP_BASS_CHMAP,
},
- [ALC662_FIXUP_BASS_1A_CHMAP] = {
+ [ALC662_FIXUP_BASS_CHMAP] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_bass_chmap,
- .chained = true,
- .chain_id = ALC662_FIXUP_BASS_1A,
},
};
@@ -5113,11 +5521,13 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0628, "Dell", ALC668_FIXUP_AUTO_MUTE),
- SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_AUTO_MUTE),
SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
- SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A_CHMAP),
- SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_CHMAP),
- SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_CHMAP),
+ SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A),
+ SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
+ SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
+ SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
+ SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
@@ -5258,7 +5668,7 @@ static int patch_alc662(struct hda_codec *codec)
spec->gen.beep_nid = 0x01;
if ((alc_get_coef0(codec) & (1 << 14)) &&
- codec->bus->pci->subsystem_vendor == 0x1025 &&
+ codec->bus->pci && codec->bus->pci->subsystem_vendor == 0x1025 &&
spec->cdefine.platform_type == 1) {
err = alc_codec_rename(codec, "ALC272X");
if (err < 0)
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index 6679a5095e55..3208ad69583e 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -236,7 +236,7 @@ static int si3054_init(struct hda_codec *codec)
} while ((val & SI3054_MEI_READY) != SI3054_MEI_READY && wait_count--);
if((val&SI3054_MEI_READY) != SI3054_MEI_READY) {
- snd_printk(KERN_ERR "si3054: cannot initialize. EXT MID = %04x\n", val);
+ codec_err(codec, "si3054: cannot initialize. EXT MID = %04x\n", val);
/* let's pray that this is no fatal error */
/* return -EACCES; */
}
@@ -247,7 +247,8 @@ static int si3054_init(struct hda_codec *codec)
SET_REG(codec, SI3054_LINE_CFG1,0x200);
if((GET_REG(codec,SI3054_LINE_STATUS) & (1<<6)) == 0) {
- snd_printd("Link Frame Detect(FDT) is not ready (line status: %04x)\n",
+ codec_dbg(codec,
+ "Link Frame Detect(FDT) is not ready (line status: %04x)\n",
GET_REG(codec,SI3054_LINE_STATUS));
}
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 7311badf6a94..75515b494034 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -83,6 +83,7 @@ enum {
STAC_DELL_M6_BOTH,
STAC_DELL_EQ,
STAC_ALIENWARE_M17X,
+ STAC_92HD89XX_HP_FRONT_JACK,
STAC_92HD73XX_MODELS
};
@@ -97,6 +98,7 @@ enum {
STAC_92HD83XXX_HP_LED,
STAC_92HD83XXX_HP_INV_LED,
STAC_92HD83XXX_HP_MIC_LED,
+ STAC_HP_LED_GPIO10,
STAC_92HD83XXX_HEADSET_JACK,
STAC_92HD83XXX_HP,
STAC_HP_ENVY_BASS,
@@ -294,7 +296,7 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
{
unsigned int gpiostate, gpiomask, gpiodir;
- snd_printdd("%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data);
+ codec_dbg(codec, "%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data);
gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
AC_VERB_GET_GPIO_DATA, 0);
@@ -357,7 +359,7 @@ static int stac_vrefout_set(struct hda_codec *codec,
{
int error, pinctl;
- snd_printdd("%s, nid %x ctl %x\n", __func__, nid, new_vref);
+ codec_dbg(codec, "%s, nid %x ctl %x\n", __func__, nid, new_vref);
pinctl = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
@@ -1795,6 +1797,12 @@ static const struct hda_pintbl intel_dg45id_pin_configs[] = {
{}
};
+static const struct hda_pintbl stac92hd89xx_hp_front_jack_pin_configs[] = {
+ { 0x0a, 0x02214030 },
+ { 0x0b, 0x02A19010 },
+ {}
+};
+
static void stac92hd73xx_fixup_ref(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -1913,6 +1921,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = {
[STAC_92HD73XX_NO_JD] = {
.type = HDA_FIXUP_FUNC,
.v.func = stac92hd73xx_fixup_no_jd,
+ },
+ [STAC_92HD89XX_HP_FRONT_JACK] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = stac92hd89xx_hp_front_jack_pin_configs,
}
};
@@ -1973,6 +1985,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = {
"Alienware M17x", STAC_ALIENWARE_M17X),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
"Alienware M17x R3", STAC_DELL_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
+ "unknown HP", STAC_92HD89XX_HP_FRONT_JACK),
{} /* terminator */
};
@@ -2072,9 +2086,12 @@ static void stac92hd83xxx_fixup_hp(struct hda_codec *codec,
}
if (find_mute_led_cfg(codec, spec->default_polarity))
- snd_printd("mute LED gpio %d polarity %d\n",
+ codec_dbg(codec, "mute LED gpio %d polarity %d\n",
spec->gpio_led,
spec->gpio_led_polarity);
+
+ /* allow auto-switching of dock line-in */
+ spec->gen.line_in_auto_switch = true;
}
static void stac92hd83xxx_fixup_hp_zephyr(struct hda_codec *codec,
@@ -2117,6 +2134,17 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec,
}
}
+static void stac92hd83xxx_fixup_hp_led_gpio10(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct sigmatel_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->gpio_led = 0x10; /* GPIO4 */
+ spec->default_polarity = 0;
+ }
+}
+
static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -2611,6 +2639,12 @@ static const struct hda_fixup stac92hd83xxx_fixups[] = {
.chained = true,
.chain_id = STAC_92HD83XXX_HP,
},
+ [STAC_HP_LED_GPIO10] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = stac92hd83xxx_fixup_hp_led_gpio10,
+ .chained = true,
+ .chain_id = STAC_92HD83XXX_HP,
+ },
[STAC_92HD83XXX_HEADSET_JACK] = {
.type = HDA_FIXUP_FUNC,
.v.func = stac92hd83xxx_fixup_headset_jack,
@@ -2689,6 +2723,8 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = {
"HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1888,
"HP Envy Spectre", STAC_HP_ENVY_BASS),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1899,
+ "HP Folio 13", STAC_HP_LED_GPIO10),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df,
"HP Folio", STAC_HP_BNB13_EQ),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18F8,
@@ -3044,7 +3080,7 @@ static void stac92hd71bxx_fixup_hp(struct hda_codec *codec,
}
if (find_mute_led_cfg(codec, 1))
- snd_printd("mute LED gpio %d polarity %d\n",
+ codec_dbg(codec, "mute LED gpio %d polarity %d\n",
spec->gpio_led,
spec->gpio_led_polarity);
@@ -4389,8 +4425,8 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
num_dacs = snd_hda_get_num_conns(codec, 0x0a) - 1;
if (num_dacs < 3 || num_dacs > 5) {
- printk(KERN_WARNING "hda_codec: Could not determine "
- "number of channels defaulting to DAC count\n");
+ codec_warn(codec,
+ "Could not determine number of channels defaulting to DAC count\n");
num_dacs = 5;
}
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index f84195f3ea31..778166259b3e 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -465,14 +465,8 @@ static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,
static void via_free(struct hda_codec *codec)
{
- struct via_spec *spec = codec->spec;
-
- if (!spec)
- return;
-
vt1708_stop_hp_work(codec);
- snd_hda_gen_spec_free(&spec->gen);
- kfree(spec);
+ snd_hda_gen_free(codec);
}
#ifdef CONFIG_PM
diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/pci/hda/thinkpad_helper.c
index 8fe3b8c18ed4..6ba0b5517c40 100644
--- a/sound/pci/hda/thinkpad_helper.c
+++ b/sound/pci/hda/thinkpad_helper.c
@@ -63,7 +63,8 @@ static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
if (!led_set_func)
led_set_func = symbol_request(tpacpi_led_set);
if (!led_set_func) {
- snd_printk(KERN_WARNING "Failed to find thinkpad-acpi symbol tpacpi_led_set\n");
+ codec_warn(codec,
+ "Failed to find thinkpad-acpi symbol tpacpi_led_set\n");
return;
}
@@ -75,7 +76,8 @@ static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
}
if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0) {
if (spec->num_adc_nids > 1)
- snd_printdd("Skipping micmute LED control due to several ADCs");
+ codec_dbg(codec,
+ "Skipping micmute LED control due to several ADCs");
else {
spec->cap_sync_hook = update_tpacpi_micmute_led;
removefunc = false;
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 55902ec40344..3b3cf4ac9060 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -1937,9 +1937,12 @@ static int aureon_add_controls(struct snd_ice1712 *ice)
snd_ice1712_save_gpio_status(ice);
id = aureon_cs8415_get(ice, CS8415_ID);
if (id != 0x41)
- snd_printk(KERN_INFO "No CS8415 chip. Skipping CS8415 controls.\n");
+ dev_info(ice->card->dev,
+ "No CS8415 chip. Skipping CS8415 controls.\n");
else if ((id & 0x0F) != 0x01)
- snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1));
+ dev_info(ice->card->dev,
+ "Detected unsupported CS8415 rev. (%c)\n",
+ (char)((id & 0x0F) + 'A' - 1));
else {
for (i = 0; i < ARRAY_SIZE(cs8415_controls); i++) {
struct snd_kcontrol *kctl;
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index 9e28cc12969b..ed2144eee38a 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -425,7 +425,8 @@ static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kco
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
if (snd_i2c_sendbytes(ice->cs8427, &reg, 1) != 1)
- snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg);
+ dev_err(ice->card->dev,
+ "unable to send register 0x%x byte to CS8427\n", reg);
snd_i2c_readbytes(ice->cs8427, &reg, 1);
ucontrol->value.integer.value[0] = (reg & CS8427_UNLOCK) ? 1 : 0;
return 0;
@@ -575,6 +576,30 @@ static struct snd_ak4xxx_private akm_vx442_priv = {
.mask_flags = 0,
};
+#ifdef CONFIG_PM_SLEEP
+static int snd_ice1712_delta_resume(struct snd_ice1712 *ice)
+{
+ unsigned char akm_backup[AK4XXX_IMAGE_SIZE];
+ /* init codec and restore registers */
+ if (ice->akm_codecs) {
+ memcpy(akm_backup, ice->akm->images, sizeof(akm_backup));
+ snd_akm4xxx_init(ice->akm);
+ memcpy(ice->akm->images, akm_backup, sizeof(akm_backup));
+ snd_akm4xxx_reset(ice->akm, 0);
+ }
+
+ return 0;
+}
+
+static int snd_ice1712_delta_suspend(struct snd_ice1712 *ice)
+{
+ if (ice->akm_codecs) /* reset & mute codec */
+ snd_akm4xxx_reset(ice->akm, 1);
+
+ return 0;
+}
+#endif
+
static int snd_ice1712_delta_init(struct snd_ice1712 *ice)
{
int err;
@@ -621,7 +646,11 @@ static int snd_ice1712_delta_init(struct snd_ice1712 *ice)
ice->num_total_adcs = 4;
break;
}
-
+#ifdef CONFIG_PM_SLEEP
+ ice->pm_resume = snd_ice1712_delta_resume;
+ ice->pm_suspend = snd_ice1712_delta_suspend;
+ ice->pm_suspend_enabled = 1;
+#endif
/* initialize the SPI clock to high */
tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
tmp |= ICE1712_DELTA_AP_CCLK;
@@ -637,7 +666,7 @@ static int snd_ice1712_delta_init(struct snd_ice1712 *ice)
case ICE1712_SUBDEVICE_VX442:
case ICE1712_SUBDEVICE_DELTA66E:
if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) {
- snd_printk(KERN_ERR "unable to create I2C bus\n");
+ dev_err(ice->card->dev, "unable to create I2C bus\n");
return err;
}
ice->i2c->private_data = ice;
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
index bc2e7011c55d..817a1bc50a60 100644
--- a/sound/pci/ice1712/ews.c
+++ b/sound/pci/ice1712/ews.c
@@ -163,7 +163,8 @@ static int snd_ice1712_ews88mt_chip_select(struct snd_ice1712 *ice, int chip_mas
__error:
snd_i2c_unlock(ice->i2c);
- snd_printk(KERN_ERR "AK4524 chip select failed, check cable to the front module\n");
+ dev_err(ice->card->dev,
+ "AK4524 chip select failed, check cable to the front module\n");
return -EIO;
}
@@ -174,7 +175,7 @@ static void ews88mt_ak4524_lock(struct snd_akm4xxx *ak, int chip)
unsigned char tmp;
/* assert AK4524 CS */
if (snd_ice1712_ews88mt_chip_select(ice, ~(1 << chip) & 0x0f) < 0)
- snd_printk(KERN_ERR "fatal error (ews88mt chip select)\n");
+ dev_err(ice->card->dev, "fatal error (ews88mt chip select)\n");
snd_ice1712_save_gpio_status(ice);
tmp = ICE1712_EWS88_SERIAL_DATA |
ICE1712_EWS88_SERIAL_CLOCK |
@@ -456,7 +457,7 @@ static int snd_ice1712_ews_init(struct snd_ice1712 *ice)
/* create i2c */
if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) {
- snd_printk(KERN_ERR "unable to create I2C bus\n");
+ dev_err(ice->card->dev, "unable to create I2C bus\n");
return err;
}
ice->i2c->private_data = ice;
@@ -469,7 +470,8 @@ static int snd_ice1712_ews_init(struct snd_ice1712 *ice)
ICE1712_6FIRE_PCF9554_ADDR,
&spec->i2cdevs[EWS_I2C_6FIRE]);
if (err < 0) {
- snd_printk(KERN_ERR "PCF9554 initialization failed\n");
+ dev_err(ice->card->dev,
+ "PCF9554 initialization failed\n");
return err;
}
snd_ice1712_6fire_write_pca(ice, PCF9554_REG_CONFIG, 0x80);
@@ -834,7 +836,7 @@ static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg
byte = 0;
if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) {
snd_i2c_unlock(ice->i2c);
- printk(KERN_ERR "cannot read pca\n");
+ dev_err(ice->card->dev, "cannot read pca\n");
return -EIO;
}
snd_i2c_unlock(ice->i2c);
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 28ec872e54c0..291672fc4a99 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -394,7 +394,7 @@ int snd_ice1712_init_cs8427(struct snd_ice1712 *ice, int addr)
err = snd_cs8427_create(ice->i2c, addr,
(ice->cs8427_timeout * HZ) / 1000, &ice->cs8427);
if (err < 0) {
- snd_printk(KERN_ERR "CS8427 initialization failed\n");
+ dev_err(ice->card->dev, "CS8427 initialization failed\n");
return err;
}
ice->spdif.ops.open = open_cs8427;
@@ -467,7 +467,7 @@ static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id)
u16 pbkstatus;
struct snd_pcm_substream *substream;
pbkstatus = inw(ICEDS(ice, INTSTAT));
- /* printk(KERN_DEBUG "pbkstatus = 0x%x\n", pbkstatus); */
+ /* dev_dbg(ice->card->dev, "pbkstatus = 0x%x\n", pbkstatus); */
for (idx = 0; idx < 6; idx++) {
if ((pbkstatus & (3 << (idx * 2))) == 0)
continue;
@@ -903,7 +903,8 @@ static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm *
if (rpcm)
*rpcm = pcm;
- printk(KERN_WARNING "Consumer PCM code does not work well at the moment --jk\n");
+ dev_warn(ice->card->dev,
+ "Consumer PCM code does not work well at the moment --jk\n");
return 0;
}
@@ -1534,7 +1535,8 @@ static int snd_ice1712_ac97_mixer(struct snd_ice1712 *ice)
ac97.private_free = snd_ice1712_mixer_free_ac97;
err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
if (err < 0)
- printk(KERN_WARNING "ice1712: cannot initialize ac97 for consumer, skipped\n");
+ dev_warn(ice->card->dev,
+ "cannot initialize ac97 for consumer, skipped\n");
else {
err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice));
if (err < 0)
@@ -1552,7 +1554,8 @@ static int snd_ice1712_ac97_mixer(struct snd_ice1712 *ice)
ac97.private_free = snd_ice1712_mixer_free_ac97;
err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
if (err < 0)
- printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n");
+ dev_warn(ice->card->dev,
+ "cannot initialize pro ac97, skipped\n");
else
return 0;
}
@@ -2332,7 +2335,8 @@ static int snd_ice1712_read_eeprom(struct snd_ice1712 *ice,
pci_read_config_word(ice->pci, PCI_SUBSYSTEM_ID, &device);
ice->eeprom.subvendor = ((unsigned int)swab16(vendor) << 16) | swab16(device);
if (ice->eeprom.subvendor == 0 || ice->eeprom.subvendor == (unsigned int)-1) {
- printk(KERN_ERR "ice1712: No valid ID is found\n");
+ dev_err(ice->card->dev,
+ "No valid ID is found\n");
return -ENXIO;
}
}
@@ -2340,21 +2344,22 @@ static int snd_ice1712_read_eeprom(struct snd_ice1712 *ice,
for (tbl = card_tables; *tbl; tbl++) {
for (c = *tbl; c->subvendor; c++) {
if (modelname && c->model && !strcmp(modelname, c->model)) {
- printk(KERN_INFO "ice1712: Using board model %s\n", c->name);
+ dev_info(ice->card->dev,
+ "Using board model %s\n", c->name);
ice->eeprom.subvendor = c->subvendor;
} else if (c->subvendor != ice->eeprom.subvendor)
continue;
if (!c->eeprom_size || !c->eeprom_data)
goto found;
/* if the EEPROM is given by the driver, use it */
- snd_printdd("using the defined eeprom..\n");
+ dev_dbg(ice->card->dev, "using the defined eeprom..\n");
ice->eeprom.version = 1;
ice->eeprom.size = c->eeprom_size + 6;
memcpy(ice->eeprom.data, c->eeprom_data, c->eeprom_size);
goto read_skipped;
}
}
- printk(KERN_WARNING "ice1712: No matching model found for ID 0x%x\n",
+ dev_warn(ice->card->dev, "No matching model found for ID 0x%x\n",
ice->eeprom.subvendor);
found:
@@ -2362,12 +2367,13 @@ static int snd_ice1712_read_eeprom(struct snd_ice1712 *ice,
if (ice->eeprom.size < 6)
ice->eeprom.size = 32; /* FIXME: any cards without the correct size? */
else if (ice->eeprom.size > 32) {
- snd_printk(KERN_ERR "invalid EEPROM (size = %i)\n", ice->eeprom.size);
+ dev_err(ice->card->dev,
+ "invalid EEPROM (size = %i)\n", ice->eeprom.size);
return -EIO;
}
ice->eeprom.version = snd_ice1712_read_i2c(ice, dev, 0x05);
if (ice->eeprom.version != 1) {
- snd_printk(KERN_ERR "invalid EEPROM version %i\n",
+ dev_err(ice->card->dev, "invalid EEPROM version %i\n",
ice->eeprom.version);
/* return -EIO; */
}
@@ -2428,6 +2434,13 @@ static int snd_ice1712_chip_init(struct snd_ice1712 *ice)
snd_ice1712_write(ice, ICE1712_IREG_CONSUMER_POWERDOWN, 0);
}
snd_ice1712_set_pro_rate(ice, 48000, 1);
+ /* unmask used interrupts */
+ outb(((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) == 0 ?
+ ICE1712_IRQ_MPU2 : 0) |
+ ((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97) ?
+ ICE1712_IRQ_PBKDS | ICE1712_IRQ_CONCAP | ICE1712_IRQ_CONPBK : 0),
+ ICEREG(ice, IRQMASK));
+ outb(0x00, ICEMT(ice, IRQ));
return 0;
}
@@ -2553,7 +2566,8 @@ static int snd_ice1712_create(struct snd_card *card,
/* check, if we can restrict PCI DMA transfers to 28 bits */
if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) {
- snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n");
+ dev_err(card->dev,
+ "architecture does not support 28bit PCI busmaster DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -2589,6 +2603,7 @@ static int snd_ice1712_create(struct snd_card *card,
ice->pci = pci;
ice->irq = -1;
pci_set_master(pci);
+ /* disable legacy emulation */
pci_write_config_word(ice->pci, 0x40, 0x807f);
pci_write_config_word(ice->pci, 0x42, 0x0006);
snd_ice1712_proc_init(ice);
@@ -2609,7 +2624,7 @@ static int snd_ice1712_create(struct snd_card *card,
if (request_irq(pci->irq, snd_ice1712_interrupt, IRQF_SHARED,
KBUILD_MODNAME, ice)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_ice1712_free(ice);
return -EIO;
}
@@ -2625,22 +2640,12 @@ static int snd_ice1712_create(struct snd_card *card,
return -EIO;
}
- /* unmask used interrupts */
- outb(((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) == 0 ?
- ICE1712_IRQ_MPU2 : 0) |
- ((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97) ?
- ICE1712_IRQ_PBKDS | ICE1712_IRQ_CONCAP | ICE1712_IRQ_CONPBK : 0),
- ICEREG(ice, IRQMASK));
- outb(0x00, ICEMT(ice, IRQ));
-
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops);
if (err < 0) {
snd_ice1712_free(ice);
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*r_ice1712 = ice;
return 0;
}
@@ -2670,7 +2675,8 @@ static int snd_ice1712_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -2809,11 +2815,80 @@ static void snd_ice1712_remove(struct pci_dev *pci)
snd_card_free(card);
}
+#ifdef CONFIG_PM_SLEEP
+static int snd_ice1712_suspend(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct snd_ice1712 *ice = card->private_data;
+
+ if (!ice->pm_suspend_enabled)
+ return 0;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+ snd_pcm_suspend_all(ice->pcm);
+ snd_pcm_suspend_all(ice->pcm_pro);
+ snd_pcm_suspend_all(ice->pcm_ds);
+ snd_ac97_suspend(ice->ac97);
+
+ if (ice->pm_suspend)
+ ice->pm_suspend(ice);
+
+ pci_disable_device(pci);
+ pci_save_state(pci);
+ pci_set_power_state(pci, PCI_D3hot);
+ return 0;
+}
+
+static int snd_ice1712_resume(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct snd_ice1712 *ice = card->private_data;
+
+ if (!ice->pm_suspend_enabled)
+ return 0;
+
+ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+
+ if (pci_enable_device(pci) < 0) {
+ snd_card_disconnect(card);
+ return -EIO;
+ }
+
+ pci_set_master(pci);
+
+ if (snd_ice1712_chip_init(ice) < 0) {
+ snd_card_disconnect(card);
+ return -EIO;
+ }
+
+ if (ice->pm_resume)
+ ice->pm_resume(ice);
+
+ if (ice->ac97)
+ snd_ac97_resume(ice->ac97);
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(snd_ice1712_pm, snd_ice1712_suspend, snd_ice1712_resume);
+#define SND_VT1712_PM_OPS &snd_ice1712_pm
+#else
+#define SND_VT1712_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
static struct pci_driver ice1712_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_ice1712_ids,
.probe = snd_ice1712_probe,
.remove = snd_ice1712_remove,
+ .driver = {
+ .pm = SND_VT1712_PM_OPS,
+ },
};
module_pci_driver(ice1712_driver);
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 500471778291..5e7948f3efe9 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -146,7 +146,7 @@ static unsigned char snd_vt1724_ac97_ready(struct snd_ice1712 *ice)
continue;
return old_cmd;
}
- snd_printd(KERN_ERR "snd_vt1724_ac97_ready: timeout\n");
+ dev_dbg(ice->card->dev, "snd_vt1724_ac97_ready: timeout\n");
return old_cmd;
}
@@ -156,7 +156,7 @@ static int snd_vt1724_ac97_wait_bit(struct snd_ice1712 *ice, unsigned char bit)
for (tm = 0; tm < 0x10000; tm++)
if ((inb(ICEMT1724(ice, AC97_CMD)) & bit) == 0)
return 0;
- snd_printd(KERN_ERR "snd_vt1724_ac97_wait_bit: timeout\n");
+ dev_dbg(ice->card->dev, "snd_vt1724_ac97_wait_bit: timeout\n");
return -EIO;
}
@@ -430,10 +430,10 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
spin_lock(&ice->reg_lock);
if (++timeout > 10) {
status = inb(ICEREG1724(ice, IRQSTAT));
- printk(KERN_ERR "ice1724: Too long irq loop, "
- "status = 0x%x\n", status);
+ dev_err(ice->card->dev,
+ "Too long irq loop, status = 0x%x\n", status);
if (status & VT1724_IRQ_MPU_TX) {
- printk(KERN_ERR "ice1724: Disabling MPU_TX\n");
+ dev_err(ice->card->dev, "Disabling MPU_TX\n");
enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0);
}
spin_unlock(&ice->reg_lock);
@@ -801,7 +801,7 @@ static int snd_vt1724_playback_pro_prepare(struct snd_pcm_substream *substream)
spin_unlock_irq(&ice->reg_lock);
/*
- printk(KERN_DEBUG "pro prepare: ch = %d, addr = 0x%x, "
+ dev_dbg(ice->card->dev, "pro prepare: ch = %d, addr = 0x%x, "
"buffer = 0x%x, period = 0x%x\n",
substream->runtime->channels,
(unsigned int)substream->runtime->dma_addr,
@@ -821,13 +821,13 @@ static snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(struct snd_pcm_substrea
#if 0 /* read PLAYBACK_ADDR */
ptr = inl(ICEMT1724(ice, PLAYBACK_ADDR));
if (ptr < substream->runtime->dma_addr) {
- snd_printd("ice1724: invalid negative ptr\n");
+ dev_dbg(ice->card->dev, "invalid negative ptr\n");
return 0;
}
ptr -= substream->runtime->dma_addr;
ptr = bytes_to_frames(substream->runtime, ptr);
if (ptr >= substream->runtime->buffer_size) {
- snd_printd("ice1724: invalid ptr %d (size=%d)\n",
+ dev_dbg(ice->card->dev, "invalid ptr %d (size=%d)\n",
(int)ptr, (int)substream->runtime->period_size);
return 0;
}
@@ -840,7 +840,7 @@ static snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(struct snd_pcm_substrea
else if (ptr <= substream->runtime->buffer_size)
ptr = substream->runtime->buffer_size - ptr;
else {
- snd_printd("ice1724: invalid ptr %d (size=%d)\n",
+ dev_dbg(ice->card->dev, "invalid ptr %d (size=%d)\n",
(int)ptr, (int)substream->runtime->buffer_size);
ptr = 0;
}
@@ -884,7 +884,7 @@ static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substr
else if (ptr <= substream->runtime->buffer_size)
ptr = substream->runtime->buffer_size - ptr;
else {
- snd_printd("ice1724: invalid ptr %d (size=%d)\n",
+ dev_dbg(ice->card->dev, "invalid ptr %d (size=%d)\n",
(int)ptr, (int)substream->runtime->buffer_size);
ptr = 0;
}
@@ -1508,7 +1508,8 @@ static int snd_vt1724_ac97_mixer(struct snd_ice1712 *ice)
ac97.private_data = ice;
err = snd_ac97_mixer(pbus, &ac97, &ice->ac97);
if (err < 0)
- printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n");
+ dev_warn(ice->card->dev,
+ "cannot initialize pro ac97, skipped\n");
else
return 0;
}
@@ -2271,7 +2272,7 @@ static void wait_i2c_busy(struct snd_ice1712 *ice)
while ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_BUSY) && t--)
;
if (t == -1)
- printk(KERN_ERR "ice1724: i2c busy timeout\n");
+ dev_err(ice->card->dev, "i2c busy timeout\n");
}
unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice,
@@ -2287,7 +2288,7 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice,
val = inb(ICEREG1724(ice, I2C_DATA));
mutex_unlock(&ice->i2c_mutex);
/*
- printk(KERN_DEBUG "i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val);
+ dev_dbg(ice->card->dev, "i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val);
*/
return val;
}
@@ -2298,7 +2299,7 @@ void snd_vt1724_write_i2c(struct snd_ice1712 *ice,
mutex_lock(&ice->i2c_mutex);
wait_i2c_busy(ice);
/*
- printk(KERN_DEBUG "i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data);
+ dev_dbg(ice->card->dev, "i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data);
*/
outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
outb(data, ICEREG1724(ice, I2C_DATA));
@@ -2335,7 +2336,8 @@ static int snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
((unsigned int)swab16(vendor) << 16) | swab16(device);
if (ice->eeprom.subvendor == 0 ||
ice->eeprom.subvendor == (unsigned int)-1) {
- printk(KERN_ERR "ice1724: No valid ID is found\n");
+ dev_err(ice->card->dev,
+ "No valid ID is found\n");
return -ENXIO;
}
}
@@ -2344,7 +2346,8 @@ static int snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
for (c = *tbl; c->name; c++) {
if (modelname && c->model &&
!strcmp(modelname, c->model)) {
- printk(KERN_INFO "ice1724: Using board model %s\n",
+ dev_info(ice->card->dev,
+ "Using board model %s\n",
c->name);
ice->eeprom.subvendor = c->subvendor;
} else if (c->subvendor != ice->eeprom.subvendor)
@@ -2353,14 +2356,14 @@ static int snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
if (!c->eeprom_size || !c->eeprom_data)
goto found;
/* if the EEPROM is given by the driver, use it */
- snd_printdd("using the defined eeprom..\n");
+ dev_dbg(ice->card->dev, "using the defined eeprom..\n");
ice->eeprom.version = 2;
ice->eeprom.size = c->eeprom_size + 6;
memcpy(ice->eeprom.data, c->eeprom_data, c->eeprom_size);
goto read_skipped;
}
}
- printk(KERN_WARNING "ice1724: No matching model found for ID 0x%x\n",
+ dev_warn(ice->card->dev, "No matching model found for ID 0x%x\n",
ice->eeprom.subvendor);
#ifdef CONFIG_PM_SLEEP
/* assume AC97-only card which can suspend without additional code */
@@ -2372,13 +2375,13 @@ static int snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
if (ice->eeprom.size < 6)
ice->eeprom.size = 32;
else if (ice->eeprom.size > 32) {
- printk(KERN_ERR "ice1724: Invalid EEPROM (size = %i)\n",
+ dev_err(ice->card->dev, "Invalid EEPROM (size = %i)\n",
ice->eeprom.size);
return -EIO;
}
ice->eeprom.version = snd_vt1724_read_i2c(ice, dev, 0x05);
if (ice->eeprom.version != 1 && ice->eeprom.version != 2)
- printk(KERN_WARNING "ice1724: Invalid EEPROM version %i\n",
+ dev_warn(ice->card->dev, "Invalid EEPROM version %i\n",
ice->eeprom.version);
size = ice->eeprom.size - 6;
for (i = 0; i < size; i++)
@@ -2586,7 +2589,7 @@ static int snd_vt1724_create(struct snd_card *card,
if (request_irq(pci->irq, snd_vt1724_interrupt,
IRQF_SHARED, KBUILD_MODNAME, ice)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_vt1724_free(ice);
return -EIO;
}
@@ -2609,8 +2612,6 @@ static int snd_vt1724_create(struct snd_card *card,
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*r_ice1712 = ice;
return 0;
}
@@ -2638,7 +2639,8 @@ static int snd_vt1724_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index 8855933e710d..7a6c0786c55c 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -244,7 +244,7 @@ static void juli_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
/* AK5385 first, since it requires cold reset affecting both codecs */
old_gpio = ice->gpio.get_data(ice);
new_gpio = (old_gpio & ~GPIO_AK5385A_MASK) | ak5385_pins;
- /* printk(KERN_DEBUG "JULI - ak5385 set_rate_val: new gpio 0x%x\n",
+ /* dev_dbg(ice->card->dev, "JULI - ak5385 set_rate_val: new gpio 0x%x\n",
new_gpio); */
ice->gpio.set_data(ice, new_gpio);
@@ -344,7 +344,7 @@ static int juli_mute_put(struct snd_kcontrol *kcontrol,
new_gpio = old_gpio &
~((unsigned int) kcontrol->private_value);
}
- /* printk(KERN_DEBUG
+ /* dev_dbg(ice->card->dev,
"JULI - mute/unmute: control_value: 0x%x, old_gpio: 0x%x, "
"new_gpio 0x%x\n",
(unsigned int)ucontrol->value.integer.value[0], old_gpio,
@@ -439,9 +439,9 @@ static void add_slaves(struct snd_card *card,
{
for (; *list; list++) {
struct snd_kcontrol *slave = ctl_find(card, *list);
- /* printk(KERN_DEBUG "add_slaves - %s\n", *list); */
+ /* dev_dbg(card->dev, "add_slaves - %s\n", *list); */
if (slave) {
- /* printk(KERN_DEBUG "slave %s found\n", *list); */
+ /* dev_dbg(card->dev, "slave %s found\n", *list); */
snd_ctl_add_slave(master, slave);
}
}
@@ -536,7 +536,7 @@ static void juli_set_rate(struct snd_ice1712 *ice, unsigned int rate)
old = ice->gpio.get_data(ice);
new = (old & ~GPIO_RATE_MASK) | get_gpio_val(rate);
- /* printk(KERN_DEBUG "JULI - set_rate: old %x, new %x\n",
+ /* dev_dbg(ice->card->dev, "JULI - set_rate: old %x, new %x\n",
old & GPIO_RATE_MASK,
new & GPIO_RATE_MASK); */
@@ -573,7 +573,7 @@ static void juli_ak4114_change(struct ak4114 *ak4114, unsigned char c0,
if (ice->is_spdif_master(ice) && c1) {
/* only for SPDIF master mode, rate was changed */
rate = snd_ak4114_external_rate(ak4114);
- /* printk(KERN_DEBUG "ak4114 - input rate changed to %d\n",
+ /* dev_dbg(ice->card->dev, "ak4114 - input rate changed to %d\n",
rate); */
juli_akm_set_rate_val(ice->akm, rate);
}
@@ -628,7 +628,7 @@ static int juli_init(struct snd_ice1712 *ice)
#endif
if (spec->analog) {
- printk(KERN_INFO "juli@: analog I/O detected\n");
+ dev_info(ice->card->dev, "juli@: analog I/O detected\n");
ice->num_total_dacs = 2;
ice->num_total_adcs = 2;
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
index e610339f7601..f3b491aa3e22 100644
--- a/sound/pci/ice1712/prodigy192.c
+++ b/sound/pci/ice1712/prodigy192.c
@@ -98,7 +98,7 @@ static int stac9460_dac_mute(struct snd_ice1712 *ice, int idx,
new = (~mute << 7 & 0x80) | (old & ~0x80);
change = (new != old);
if (change)
- /*printk ("Volume register 0x%02x: 0x%02x\n", idx, new);*/
+ /* dev_dbg(ice->card->dev, "Volume register 0x%02x: 0x%02x\n", idx, new);*/
stac9460_put(ice, idx, new);
return change;
}
@@ -133,7 +133,7 @@ static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
/* due to possible conflicts with stac9460_set_rate_val, mutexing */
mutex_lock(&spec->mute_mutex);
/*
- printk(KERN_DEBUG "Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx,
+ dev_dbg(ice->card->dev, "Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx,
ucontrol->value.integer.value[0]);
*/
change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]);
@@ -187,7 +187,7 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
if (change) {
ovol = (0x7f - nvol) | (tmp & 0x80);
/*
- printk(KERN_DEBUG "DAC Volume: reg 0x%02x: 0x%02x\n",
+ dev_dbg(ice->card->dev, "DAC Volume: reg 0x%02x: 0x%02x\n",
idx, ovol);
*/
stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
@@ -348,7 +348,7 @@ static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate)
for (idx = 0; idx < 7 ; ++idx)
changed[idx] = stac9460_dac_mute(ice,
STAC946X_MASTER_VOLUME + idx, 0);
- /*printk(KERN_DEBUG "Rate change: %d, new MC: 0x%02x\n", rate, new);*/
+ /*dev_dbg(ice->card->dev, "Rate change: %d, new MC: 0x%02x\n", rate, new);*/
stac9460_put(ice, STAC946X_MASTER_CLOCKING, new);
udelay(10);
/* unmuting - only originally unmuted dacs -
@@ -768,9 +768,10 @@ static int prodigy192_init(struct snd_ice1712 *ice)
/* from this moment if err = 0 then
* spec->ak4114 should not be null
*/
- snd_printdd("AK4114 initialized with status %d\n", err);
+ dev_dbg(ice->card->dev,
+ "AK4114 initialized with status %d\n", err);
} else
- snd_printdd("AK4114 not found\n");
+ dev_dbg(ice->card->dev, "AK4114 not found\n");
if (err < 0)
return err;
diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c
index 71c6003ef338..2c2df4b74e01 100644
--- a/sound/pci/ice1712/quartet.c
+++ b/sound/pci/ice1712/quartet.c
@@ -280,7 +280,7 @@ static void qtet_akm_write(struct snd_akm4xxx *ak, int chip,
if (snd_BUG_ON(chip < 0 || chip >= 4))
return;
- /*printk(KERN_DEBUG "Writing to AK4620: chip=%d, addr=0x%x,
+ /*dev_dbg(ice->card->dev, "Writing to AK4620: chip=%d, addr=0x%x,
data=0x%x\n", chip, addr, data);*/
orig_dir = ice->gpio.get_dir(ice);
ice->gpio.set_dir(ice, orig_dir | GPIO_SPI_ALL);
@@ -898,7 +898,7 @@ static void qtet_set_rate(struct snd_ice1712 *ice, unsigned int rate)
new = (get_cpld(ice) & ~CPLD_CKS_MASK) | get_cks_val(rate);
/* switch to internal clock, drop CPLD_SYNC_SEL */
new &= ~CPLD_SYNC_SEL;
- /* printk(KERN_DEBUG "QT - set_rate: old %x, new %x\n",
+ /* dev_dbg(ice->card->dev, "QT - set_rate: old %x, new %x\n",
get_cpld(ice), new); */
set_cpld(ice, new);
}
@@ -978,7 +978,7 @@ static void qtet_ak4113_change(struct ak4113 *ak4113, unsigned char c0,
c1) {
/* only for SPDIF master mode, rate was changed */
rate = snd_ak4113_external_rate(ak4113);
- /* printk(KERN_DEBUG "ak4113 - input rate changed to %d\n",
+ /* dev_dbg(ice->card->dev, "ak4113 - input rate changed to %d\n",
rate); */
qtet_akm_set_rate_val(ice->akm, rate);
}
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 08d8733604a2..68340d7df76d 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -547,7 +547,8 @@ static int snd_intel8x0_codec_semaphore(struct intel8x0 *chip, unsigned int code
/* access to some forbidden (non existent) ac97 registers will not
* reset the semaphore. So even if you don't get the semaphore, still
* continue the access. We don't need the semaphore anyway. */
- snd_printk(KERN_ERR "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n",
+ dev_err(chip->card->dev,
+ "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n",
igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA)));
iagetword(chip, 0); /* clear semaphore flag */
/* I don't care about the semaphore */
@@ -562,7 +563,9 @@ static void snd_intel8x0_codec_write(struct snd_ac97 *ac97,
if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) {
if (! chip->in_ac97_init)
- snd_printk(KERN_ERR "codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
+ dev_err(chip->card->dev,
+ "codec_write %d: semaphore is not ready for register 0x%x\n",
+ ac97->num, reg);
}
iaputword(chip, reg + ac97->num * 0x80, val);
}
@@ -576,7 +579,9 @@ static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97,
if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) {
if (! chip->in_ac97_init)
- snd_printk(KERN_ERR "codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
+ dev_err(chip->card->dev,
+ "codec_read %d: semaphore is not ready for register 0x%x\n",
+ ac97->num, reg);
res = 0xffff;
} else {
res = iagetword(chip, reg + ac97->num * 0x80);
@@ -585,7 +590,9 @@ static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97,
iputdword(chip, ICHREG(GLOB_STA), tmp &
~(chip->codec_ready_bits | ICH_GSCI));
if (! chip->in_ac97_init)
- snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg);
+ dev_err(chip->card->dev,
+ "codec_read %d: read timeout for register 0x%x\n",
+ ac97->num, reg);
res = 0xffff;
}
}
@@ -619,7 +626,7 @@ static int snd_intel8x0_ali_codec_ready(struct intel8x0 *chip, int mask)
return 0;
}
if (! chip->in_ac97_init)
- snd_printd(KERN_WARNING "intel8x0: AC97 codec ready timeout.\n");
+ dev_warn(chip->card->dev, "AC97 codec ready timeout.\n");
return -EBUSY;
}
@@ -631,7 +638,7 @@ static int snd_intel8x0_ali_codec_semaphore(struct intel8x0 *chip)
while (--time && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY))
udelay(1);
if (! time && ! chip->in_ac97_init)
- snd_printk(KERN_WARNING "ali_codec_semaphore timeout\n");
+ dev_warn(chip->card->dev, "ali_codec_semaphore timeout\n");
return snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_CODEC_READY);
}
@@ -700,7 +707,7 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */
ichdev->fragsize >> ichdev->pos_shift);
#if 0
- printk(KERN_DEBUG "bdbar[%i] = 0x%x [0x%x]\n",
+ dev_dbg(chip->card->dev, "bdbar[%i] = 0x%x [0x%x]\n",
idx + 0, bdbar[idx + 0], bdbar[idx + 1]);
#endif
}
@@ -712,8 +719,8 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags;
ichdev->position = 0;
#if 0
- printk(KERN_DEBUG "lvi_frag = %i, frags = %i, period_size = 0x%x, "
- "period_size1 = 0x%x\n",
+ dev_dbg(chip->card->dev,
+ "lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n",
ichdev->lvi_frag, ichdev->frags, ichdev->fragsize,
ichdev->fragsize1);
#endif
@@ -781,8 +788,8 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich
ichdev->lvi_frag %= ichdev->frags;
ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1);
#if 0
- printk(KERN_DEBUG "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, "
- "all = 0x%x, 0x%x\n",
+ dev_dbg(chip->card->dev,
+ "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n",
ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2],
ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port),
inl(port + 4), inb(port + ICH_REG_OFF_CR));
@@ -2289,7 +2296,8 @@ static int snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
ac97.num = i;
if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
if (err != -EACCES)
- snd_printk(KERN_ERR "Unable to initialize codec #%d\n", i);
+ dev_err(chip->card->dev,
+ "Unable to initialize codec #%d\n", i);
if (i == 0)
goto __err;
}
@@ -2441,7 +2449,7 @@ static int snd_intel8x0_ich_chip_reset(struct intel8x0 *chip)
return 0;
schedule_timeout_uninterruptible(1);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n",
+ dev_err(chip->card->dev, "AC'97 warm reset still in progress? [0x%x]\n",
igetdword(chip, ICHREG(GLOB_CNT)));
return -EIO;
}
@@ -2483,7 +2491,8 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
} while (time_after_eq(end_time, jiffies));
if (! status) {
/* no codec is found */
- snd_printk(KERN_ERR "codec_ready: codec is not ready [0x%x]\n",
+ dev_err(chip->card->dev,
+ "codec_ready: codec is not ready [0x%x]\n",
igetdword(chip, ICHREG(GLOB_STA)));
return -EIO;
}
@@ -2547,7 +2556,7 @@ static int snd_intel8x0_ali_chip_init(struct intel8x0 *chip, int probing)
goto __ok;
schedule_timeout_uninterruptible(1);
}
- snd_printk(KERN_ERR "AC'97 reset failed.\n");
+ dev_err(chip->card->dev, "AC'97 reset failed.\n");
if (probing)
return -EIO;
@@ -2591,7 +2600,7 @@ static int snd_intel8x0_chip_init(struct intel8x0 *chip, int probing)
break;
}
if (timeout == 0)
- printk(KERN_ERR "intel8x0: reset of registers failed?\n");
+ dev_err(chip->card->dev, "reset of registers failed?\n");
}
/* initialize Buffer Descriptor Lists */
for (i = 0; i < chip->bdbars_count; i++)
@@ -2692,8 +2701,7 @@ static int intel8x0_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "intel8x0: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -2701,8 +2709,8 @@ static int intel8x0_resume(struct device *dev)
snd_intel8x0_chip_init(chip, 0);
if (request_irq(pci->irq, snd_intel8x0_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
- printk(KERN_ERR "intel8x0: unable to grab IRQ %d, "
- "disabling device\n", pci->irq);
+ dev_err(dev, "unable to grab IRQ %d, disabling device\n",
+ pci->irq);
snd_card_disconnect(card);
return -EIO;
}
@@ -2779,7 +2787,8 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
__again:
subs = chip->pcm[0]->streams[0].substream;
if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) {
- snd_printk(KERN_WARNING "no playback buffer allocated - aborting measure ac97 clock\n");
+ dev_warn(chip->card->dev,
+ "no playback buffer allocated - aborting measure ac97 clock\n");
return;
}
ichdev = &chip->ichd[ICHD_PCMOUT];
@@ -2789,7 +2798,8 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
/* set rate */
if (snd_ac97_set_rate(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 48000) < 0) {
- snd_printk(KERN_ERR "cannot set ac97 rate: clock = %d\n", chip->ac97_bus->clock);
+ dev_err(chip->card->dev, "cannot set ac97 rate: clock = %d\n",
+ chip->ac97_bus->clock);
return;
}
snd_intel8x0_setup_periods(chip, ichdev);
@@ -2843,7 +2853,8 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
spin_unlock_irq(&chip->reg_lock);
if (pos == 0) {
- snd_printk(KERN_ERR "intel8x0: measure - unreliable DMA position..\n");
+ dev_err(chip->card->dev,
+ "measure - unreliable DMA position..\n");
__retry:
if (attempt < 3) {
msleep(300);
@@ -2857,16 +2868,17 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
t = stop_time.tv_sec - start_time.tv_sec;
t *= 1000000;
t += (stop_time.tv_nsec - start_time.tv_nsec) / 1000;
- printk(KERN_INFO "%s: measured %lu usecs (%lu samples)\n", __func__, t, pos);
+ dev_info(chip->card->dev,
+ "%s: measured %lu usecs (%lu samples)\n", __func__, t, pos);
if (t == 0) {
- snd_printk(KERN_ERR "intel8x0: ?? calculation error..\n");
+ dev_err(chip->card->dev, "?? calculation error..\n");
goto __retry;
}
pos *= 1000;
pos = (pos / t) * 1000 + ((pos % t) * 1000) / t;
if (pos < 40000 || pos >= 60000) {
/* abnormal value. hw problem? */
- printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos);
+ dev_info(chip->card->dev, "measured clock %ld rejected\n", pos);
goto __retry;
} else if (pos > 40500 && pos < 41500)
/* first exception - 41000Hz reference clock */
@@ -2878,7 +2890,7 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
/* not 48000Hz, tuning the clock.. */
chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;
__end:
- printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock);
+ dev_info(chip->card->dev, "clocking to %d\n", chip->ac97_bus->clock);
snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0);
}
@@ -2899,7 +2911,7 @@ static int intel8x0_in_clock_list(struct intel8x0 *chip)
wl = snd_pci_quirk_lookup(pci, intel8x0_clock_list);
if (!wl)
return 0;
- printk(KERN_INFO "intel8x0: white list rate for %04x:%04x is %i\n",
+ dev_info(chip->card->dev, "white list rate for %04x:%04x is %i\n",
pci->subsystem_vendor, pci->subsystem_device, wl->value);
chip->ac97_bus->clock = wl->value;
return 1;
@@ -3003,7 +3015,7 @@ static int snd_intel8x0_inside_vm(struct pci_dev *pci)
fini:
if (msg != NULL)
- printk(KERN_INFO "intel8x0: %s optimization\n", msg);
+ dev_info(&pci->dev, "%s optimization\n", msg);
return result;
}
@@ -3098,7 +3110,7 @@ static int snd_intel8x0_create(struct snd_card *card,
else
chip->addr = pci_iomap(pci, 0, 0);
if (!chip->addr) {
- snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+ dev_err(card->dev, "AC'97 space ioremap problem\n");
snd_intel8x0_free(chip);
return -EIO;
}
@@ -3107,7 +3119,7 @@ static int snd_intel8x0_create(struct snd_card *card,
else
chip->bmaddr = pci_iomap(pci, 1, 0);
if (!chip->bmaddr) {
- snd_printk(KERN_ERR "Controller space ioremap problem\n");
+ dev_err(card->dev, "Controller space ioremap problem\n");
snd_intel8x0_free(chip);
return -EIO;
}
@@ -3152,7 +3164,7 @@ static int snd_intel8x0_create(struct snd_card *card,
chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2,
&chip->bdbars) < 0) {
snd_intel8x0_free(chip);
- snd_printk(KERN_ERR "intel8x0: cannot allocate buffer descriptors\n");
+ dev_err(card->dev, "cannot allocate buffer descriptors\n");
return -ENOMEM;
}
/* tables must be aligned to 8 bytes here, but the kernel pages
@@ -3206,7 +3218,7 @@ static int snd_intel8x0_create(struct snd_card *card,
/* request irq after initializaing int_sta_mask, etc */
if (request_irq(pci->irq, snd_intel8x0_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_intel8x0_free(chip);
return -EBUSY;
}
@@ -3217,8 +3229,6 @@ static int snd_intel8x0_create(struct snd_card *card,
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*r_intel8x0 = chip;
return 0;
}
@@ -3265,12 +3275,12 @@ static int check_default_spdif_aclink(struct pci_dev *pci)
w = snd_pci_quirk_lookup(pci, spdif_aclink_defaults);
if (w) {
if (w->value)
- snd_printdd(KERN_INFO
- "intel8x0: Using SPDIF over AC-Link for %s\n",
+ dev_dbg(&pci->dev,
+ "Using SPDIF over AC-Link for %s\n",
snd_pci_quirk_name(w));
else
- snd_printdd(KERN_INFO
- "intel8x0: Using integrated SPDIF DMA for %s\n",
+ dev_dbg(&pci->dev,
+ "Using integrated SPDIF DMA for %s\n",
snd_pci_quirk_name(w));
return w->value;
}
@@ -3285,7 +3295,7 @@ static int snd_intel8x0_probe(struct pci_dev *pci,
int err;
struct shortname_table *name;
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 3573c1193665..b54d3e93cab1 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -334,7 +334,8 @@ static int snd_intel8x0m_codec_semaphore(struct intel8x0m *chip, unsigned int co
/* access to some forbidden (non existent) ac97 registers will not
* reset the semaphore. So even if you don't get the semaphore, still
* continue the access. We don't need the semaphore anyway. */
- snd_printk(KERN_ERR "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n",
+ dev_err(chip->card->dev,
+ "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n",
igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA)));
iagetword(chip, 0); /* clear semaphore flag */
/* I don't care about the semaphore */
@@ -349,7 +350,9 @@ static void snd_intel8x0m_codec_write(struct snd_ac97 *ac97,
if (snd_intel8x0m_codec_semaphore(chip, ac97->num) < 0) {
if (! chip->in_ac97_init)
- snd_printk(KERN_ERR "codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
+ dev_err(chip->card->dev,
+ "codec_write %d: semaphore is not ready for register 0x%x\n",
+ ac97->num, reg);
}
iaputword(chip, reg + ac97->num * 0x80, val);
}
@@ -363,7 +366,9 @@ static unsigned short snd_intel8x0m_codec_read(struct snd_ac97 *ac97,
if (snd_intel8x0m_codec_semaphore(chip, ac97->num) < 0) {
if (! chip->in_ac97_init)
- snd_printk(KERN_ERR "codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
+ dev_err(chip->card->dev,
+ "codec_read %d: semaphore is not ready for register 0x%x\n",
+ ac97->num, reg);
res = 0xffff;
} else {
res = iagetword(chip, reg + ac97->num * 0x80);
@@ -372,7 +377,9 @@ static unsigned short snd_intel8x0m_codec_read(struct snd_ac97 *ac97,
iputdword(chip, ICHREG(GLOB_STA),
tmp & ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI));
if (! chip->in_ac97_init)
- snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg);
+ dev_err(chip->card->dev,
+ "codec_read %d: read timeout for register 0x%x\n",
+ ac97->num, reg);
res = 0xffff;
}
}
@@ -412,7 +419,7 @@ static void snd_intel8x0m_setup_periods(struct intel8x0m *chip, struct ichdev *i
bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */
ichdev->fragsize >> chip->pcm_pos_shift);
/*
- printk(KERN_DEBUG "bdbar[%i] = 0x%x [0x%x]\n",
+ dev_dbg(chip->card->dev, "bdbar[%i] = 0x%x [0x%x]\n",
idx + 0, bdbar[idx + 0], bdbar[idx + 1]);
*/
}
@@ -424,8 +431,8 @@ static void snd_intel8x0m_setup_periods(struct intel8x0m *chip, struct ichdev *i
ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags;
ichdev->position = 0;
#if 0
- printk(KERN_DEBUG "lvi_frag = %i, frags = %i, period_size = 0x%x, "
- "period_size1 = 0x%x\n",
+ dev_dbg(chip->card->dev,
+ "lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n",
ichdev->lvi_frag, ichdev->frags, ichdev->fragsize,
ichdev->fragsize1);
#endif
@@ -470,8 +477,8 @@ static inline void snd_intel8x0m_update(struct intel8x0m *chip, struct ichdev *i
ichdev->lvi_frag *
ichdev->fragsize1);
#if 0
- printk(KERN_DEBUG "new: bdbar[%i] = 0x%x [0x%x], "
- "prefetch = %i, all = 0x%x, 0x%x\n",
+ dev_dbg(chip->card->dev,
+ "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n",
ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2],
ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port),
inl(port + 4), inb(port + ICH_REG_OFF_CR));
@@ -850,7 +857,8 @@ static int snd_intel8x0m_mixer(struct intel8x0m *chip, int ac97_clock)
ac97.pci = chip->pci;
ac97.num = glob_sta & ICH_SCR ? 1 : 0;
if ((err = snd_ac97_mixer(pbus, &ac97, &x97)) < 0) {
- snd_printk(KERN_ERR "Unable to initialize codec #%d\n", ac97.num);
+ dev_err(chip->card->dev,
+ "Unable to initialize codec #%d\n", ac97.num);
if (ac97.num == 0)
goto __err;
return err;
@@ -901,7 +909,7 @@ static int snd_intel8x0m_ich_chip_init(struct intel8x0m *chip, int probing)
goto __ok;
schedule_timeout_uninterruptible(1);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n",
+ dev_err(chip->card->dev, "AC'97 warm reset still in progress? [0x%x]\n",
igetdword(chip, ICHREG(GLOB_CNT)));
return -EIO;
@@ -921,7 +929,8 @@ static int snd_intel8x0m_ich_chip_init(struct intel8x0m *chip, int probing)
} while (time_after_eq(end_time, jiffies));
if (! status) {
/* no codec is found */
- snd_printk(KERN_ERR "codec_ready: codec is not ready [0x%x]\n",
+ dev_err(chip->card->dev,
+ "codec_ready: codec is not ready [0x%x]\n",
igetdword(chip, ICHREG(GLOB_STA)));
return -EIO;
}
@@ -1042,16 +1051,15 @@ static int intel8x0m_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "intel8x0m: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
pci_set_master(pci);
if (request_irq(pci->irq, snd_intel8x0m_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
- printk(KERN_ERR "intel8x0m: unable to grab IRQ %d, "
- "disabling device\n", pci->irq);
+ dev_err(dev, "unable to grab IRQ %d, disabling device\n",
+ pci->irq);
snd_card_disconnect(card);
return -EIO;
}
@@ -1165,7 +1173,7 @@ static int snd_intel8x0m_create(struct snd_card *card,
else
chip->addr = pci_iomap(pci, 0, 0);
if (!chip->addr) {
- snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+ dev_err(card->dev, "AC'97 space ioremap problem\n");
snd_intel8x0m_free(chip);
return -EIO;
}
@@ -1174,7 +1182,7 @@ static int snd_intel8x0m_create(struct snd_card *card,
else
chip->bmaddr = pci_iomap(pci, 1, 0);
if (!chip->bmaddr) {
- snd_printk(KERN_ERR "Controller space ioremap problem\n");
+ dev_err(card->dev, "Controller space ioremap problem\n");
snd_intel8x0m_free(chip);
return -EIO;
}
@@ -1182,7 +1190,7 @@ static int snd_intel8x0m_create(struct snd_card *card,
port_inited:
if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_intel8x0m_free(chip);
return -EBUSY;
}
@@ -1243,8 +1251,6 @@ static int snd_intel8x0m_create(struct snd_card *card,
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*r_intel8x0m = chip;
return 0;
}
@@ -1283,7 +1289,7 @@ static int snd_intel8x0m_probe(struct pci_dev *pci,
int err;
struct shortname_table *name;
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 9cf9829555d4..8f36d77f01e5 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -2418,8 +2418,6 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci,
snd_korg1212_proc_init(korg1212);
- snd_card_set_dev(card, &pci->dev);
-
* rchip = korg1212;
return 0;
@@ -2445,7 +2443,8 @@ snd_korg1212_probe(struct pci_dev *pci,
dev++;
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
index 0568540dc8d3..68824cdd137d 100644
--- a/sound/pci/lola/lola.c
+++ b/sound/pci/lola/lola.c
@@ -75,7 +75,7 @@ MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
static int debug;
module_param(debug, int, 0644);
#define verbose_debug(fmt, args...) \
- do { if (debug > 1) printk(KERN_DEBUG SFX fmt, ##args); } while (0)
+ do { if (debug > 1) pr_debug(SFX fmt, ##args); } while (0)
#else
#define verbose_debug(fmt, args...)
#endif
@@ -168,7 +168,7 @@ static int rirb_get_response(struct lola *chip, unsigned int *val,
verbose_debug("get_response: %x, %x\n",
chip->res, chip->res_ex);
if (chip->res_ex & LOLA_RIRB_EX_ERROR) {
- printk(KERN_WARNING SFX "RIRB ERROR: "
+ dev_warn(chip->card->dev, "RIRB ERROR: "
"NID=%x, verb=%x, data=%x, ext=%x\n",
chip->last_cmd_nid,
chip->last_verb, chip->last_data,
@@ -182,9 +182,9 @@ static int rirb_get_response(struct lola *chip, unsigned int *val,
udelay(20);
cond_resched();
}
- printk(KERN_WARNING SFX "RIRB response error\n");
+ dev_warn(chip->card->dev, "RIRB response error\n");
if (!chip->polling_mode) {
- printk(KERN_WARNING SFX "switching to polling mode\n");
+ dev_warn(chip->card->dev, "switching to polling mode\n");
chip->polling_mode = 1;
goto again;
}
@@ -327,7 +327,7 @@ static int reset_controller(struct lola *chip)
break;
} while (time_before(jiffies, end_time));
if (!gctl) {
- printk(KERN_ERR SFX "cannot reset controller\n");
+ dev_err(chip->card->dev, "cannot reset controller\n");
return -EIO;
}
return 0;
@@ -452,40 +452,40 @@ static int lola_parse_tree(struct lola *chip)
err = lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val);
if (err < 0) {
- printk(KERN_ERR SFX "Can't read VENDOR_ID\n");
+ dev_err(chip->card->dev, "Can't read VENDOR_ID\n");
return err;
}
val >>= 16;
if (val != 0x1369) {
- printk(KERN_ERR SFX "Unknown codec vendor 0x%x\n", val);
+ dev_err(chip->card->dev, "Unknown codec vendor 0x%x\n", val);
return -EINVAL;
}
err = lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val);
if (err < 0) {
- printk(KERN_ERR SFX "Can't read FUNCTION_TYPE\n");
+ dev_err(chip->card->dev, "Can't read FUNCTION_TYPE\n");
return err;
}
if (val != 1) {
- printk(KERN_ERR SFX "Unknown function type %d\n", val);
+ dev_err(chip->card->dev, "Unknown function type %d\n", val);
return -EINVAL;
}
err = lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val);
if (err < 0) {
- printk(KERN_ERR SFX "Can't read SPECCAPS\n");
+ dev_err(chip->card->dev, "Can't read SPECCAPS\n");
return err;
}
chip->lola_caps = val;
chip->pin[CAPT].num_pins = LOLA_AFG_INPUT_PIN_COUNT(chip->lola_caps);
chip->pin[PLAY].num_pins = LOLA_AFG_OUTPUT_PIN_COUNT(chip->lola_caps);
- snd_printdd(SFX "speccaps=0x%x, pins in=%d, out=%d\n",
+ dev_dbg(chip->card->dev, "speccaps=0x%x, pins in=%d, out=%d\n",
chip->lola_caps,
chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins);
if (chip->pin[CAPT].num_pins > MAX_AUDIO_INOUT_COUNT ||
chip->pin[PLAY].num_pins > MAX_AUDIO_INOUT_COUNT) {
- printk(KERN_ERR SFX "Invalid Lola-spec caps 0x%x\n", val);
+ dev_err(chip->card->dev, "Invalid Lola-spec caps 0x%x\n", val);
return -EINVAL;
}
@@ -586,7 +586,6 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip) {
- snd_printk(KERN_ERR SFX "cannot allocate chip\n");
pci_disable_device(pci);
return -ENOMEM;
}
@@ -609,7 +608,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
chip->sample_rate_max = 192000;
break;
default:
- snd_printk(KERN_WARNING SFX
+ dev_warn(chip->card->dev,
"Invalid granularity %d, reset to %d\n",
chip->granularity, LOLA_GRANULARITY_MAX);
chip->granularity = LOLA_GRANULARITY_MAX;
@@ -618,7 +617,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
}
chip->sample_rate_min = sample_rate_min[dev];
if (chip->sample_rate_min > chip->sample_rate_max) {
- snd_printk(KERN_WARNING SFX
+ dev_warn(chip->card->dev,
"Invalid sample_rate_min %d, reset to 16000\n",
chip->sample_rate_min);
chip->sample_rate_min = 16000;
@@ -636,7 +635,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
chip->bar[1].addr = pci_resource_start(pci, 2);
chip->bar[1].remap_addr = pci_ioremap_bar(pci, 2);
if (!chip->bar[0].remap_addr || !chip->bar[1].remap_addr) {
- snd_printk(KERN_ERR SFX "ioremap error\n");
+ dev_err(chip->card->dev, "ioremap error\n");
err = -ENXIO;
goto errout;
}
@@ -649,7 +648,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
+ dev_err(chip->card->dev, "unable to grab IRQ %d\n", pci->irq);
err = -EBUSY;
goto errout;
}
@@ -660,7 +659,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
chip->pcm[CAPT].num_streams = (dever >> 0) & 0x3ff;
chip->pcm[PLAY].num_streams = (dever >> 10) & 0x3ff;
chip->version = (dever >> 24) & 0xff;
- snd_printdd(SFX "streams in=%d, out=%d, version=0x%x\n",
+ dev_dbg(chip->card->dev, "streams in=%d, out=%d, version=0x%x\n",
chip->pcm[CAPT].num_streams, chip->pcm[PLAY].num_streams,
chip->version);
@@ -669,7 +668,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
chip->pcm[PLAY].num_streams > MAX_STREAM_OUT_COUNT ||
(!chip->pcm[CAPT].num_streams &&
!chip->pcm[PLAY].num_streams)) {
- printk(KERN_ERR SFX "invalid DEVER = %x\n", dever);
+ dev_err(chip->card->dev, "invalid DEVER = %x\n", dever);
err = -EINVAL;
goto errout;
}
@@ -680,7 +679,7 @@ static int lola_create(struct snd_card *card, struct pci_dev *pci,
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
if (err < 0) {
- snd_printk(KERN_ERR SFX "Error creating device [card]!\n");
+ dev_err(chip->card->dev, "Error creating device [card]!\n");
goto errout;
}
@@ -717,14 +716,13 @@ static int lola_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0) {
- snd_printk(KERN_ERR SFX "Error creating card!\n");
+ dev_err(card->dev, "Error creating card!\n");
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
err = lola_create(card, pci, dev, &chip);
if (err < 0)
goto out_free;
diff --git a/sound/pci/lola/lola_clock.c b/sound/pci/lola/lola_clock.c
index eb1d6b97df16..2bef6b412aee 100644
--- a/sound/pci/lola/lola_clock.c
+++ b/sound/pci/lola/lola_clock.c
@@ -128,21 +128,21 @@ int lola_init_clock_widget(struct lola *chip, int nid)
err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
if (err < 0) {
- printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+ dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
return err;
}
if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */
- snd_printdd("No valid clock widget\n");
+ dev_dbg(chip->card->dev, "No valid clock widget\n");
return 0;
}
chip->clock.nid = nid;
chip->clock.items = val & 0xff;
- snd_printdd("clock_list nid=%x, entries=%d\n", nid,
+ dev_dbg(chip->card->dev, "clock_list nid=%x, entries=%d\n", nid,
chip->clock.items);
if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) {
- printk(KERN_ERR SFX "CLOCK_LIST too big: %d\n",
+ dev_err(chip->card->dev, "CLOCK_LIST too big: %d\n",
chip->clock.items);
return -EINVAL;
}
@@ -158,7 +158,7 @@ int lola_init_clock_widget(struct lola *chip, int nid)
err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
idx, 0, &val, &res_ex);
if (err < 0) {
- printk(KERN_ERR SFX "Can't read CLOCK_LIST\n");
+ dev_err(chip->card->dev, "Can't read CLOCK_LIST\n");
return -EINVAL;
}
@@ -223,7 +223,7 @@ int lola_enable_clock_events(struct lola *chip)
if (err < 0)
return err;
if (res) {
- printk(KERN_WARNING SFX "error in enable_clock_events %d\n",
+ dev_warn(chip->card->dev, "error in enable_clock_events %d\n",
res);
return -EINVAL;
}
@@ -242,7 +242,7 @@ int lola_set_clock_index(struct lola *chip, unsigned int idx)
if (err < 0)
return err;
if (res) {
- printk(KERN_WARNING SFX "error in set_clock %d\n", res);
+ dev_warn(chip->card->dev, "error in set_clock %d\n", res);
return -EINVAL;
}
return 0;
diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c
index 52c8d6b0f39b..782f4d8299ae 100644
--- a/sound/pci/lola/lola_mixer.c
+++ b/sound/pci/lola/lola_mixer.c
@@ -37,7 +37,7 @@ static int lola_init_pin(struct lola *chip, struct lola_pin *pin,
pin->nid = nid;
err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
if (err < 0) {
- printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+ dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
return err;
}
val &= 0x00f00fff; /* test TYPE and bits 0..11 */
@@ -48,7 +48,7 @@ static int lola_init_pin(struct lola *chip, struct lola_pin *pin,
else if (val == 0x0040000c && dir == PLAY) /* Dig=0, OutAmp/ovrd */
pin->is_analog = true;
else {
- printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", val, nid);
+ dev_err(chip->card->dev, "Invalid wcaps 0x%x for 0x%x\n", val, nid);
return -EINVAL;
}
@@ -62,7 +62,7 @@ static int lola_init_pin(struct lola *chip, struct lola_pin *pin,
else
err = lola_read_param(chip, nid, LOLA_PAR_AMP_IN_CAP, &val);
if (err < 0) {
- printk(KERN_ERR SFX "Can't read AMP-caps for 0x%x\n", nid);
+ dev_err(chip->card->dev, "Can't read AMP-caps for 0x%x\n", nid);
return err;
}
@@ -79,7 +79,7 @@ static int lola_init_pin(struct lola *chip, struct lola_pin *pin,
err = lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val,
NULL);
if (err < 0) {
- printk(KERN_ERR SFX "Can't get MAX_LEVEL 0x%x\n", nid);
+ dev_err(chip->card->dev, "Can't get MAX_LEVEL 0x%x\n", nid);
return err;
}
pin->max_level = val & 0x3ff; /* 10 bits */
@@ -119,12 +119,12 @@ int lola_init_mixer_widget(struct lola *chip, int nid)
err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
if (err < 0) {
- printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+ dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
return err;
}
if ((val & 0xfff00000) != 0x02f00000) { /* test SubType and Type */
- snd_printdd("No valid mixer widget\n");
+ dev_dbg(chip->card->dev, "No valid mixer widget\n");
return 0;
}
@@ -202,7 +202,7 @@ int lola_init_mixer_widget(struct lola *chip, int nid)
*/
if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT ||
chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) {
- printk(KERN_ERR SFX "Invalid mixer widget size\n");
+ dev_err(chip->card->dev, "Invalid mixer widget size\n");
return -EINVAL;
}
@@ -213,7 +213,7 @@ int lola_init_mixer_widget(struct lola *chip, int nid)
(((1U << chip->mixer.dest_phys_outs) - 1)
<< chip->mixer.dest_phys_out_ofs);
- snd_printdd("Mixer src_mask=%x, dest_mask=%x\n",
+ dev_dbg(chip->card->dev, "Mixer src_mask=%x, dest_mask=%x\n",
chip->mixer.src_mask, chip->mixer.dest_mask);
return 0;
@@ -236,7 +236,8 @@ static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id,
(gain == readw(&chip->mixer.array->src_gain[id])))
return 0;
- snd_printdd("lola_mixer_set_src_gain (id=%d, gain=%d) enable=%x\n",
+ dev_dbg(chip->card->dev,
+ "lola_mixer_set_src_gain (id=%d, gain=%d) enable=%x\n",
id, gain, val);
writew(gain, &chip->mixer.array->src_gain[id]);
writel(val, &chip->mixer.array->src_gain_enable);
@@ -409,7 +410,8 @@ static int set_analog_volume(struct lola *chip, int dir,
return 0;
if (external_call)
lola_codec_flush(chip);
- snd_printdd("set_analog_volume (dir=%d idx=%d, volume=%d)\n",
+ dev_dbg(chip->card->dev,
+ "set_analog_volume (dir=%d idx=%d, volume=%d)\n",
dir, idx, val);
err = lola_codec_write(chip, pin->nid,
LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0);
diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c
index 5ea85e8b83ab..3bd6985430e8 100644
--- a/sound/pci/lola/lola_pcm.c
+++ b/sound/pci/lola/lola_pcm.c
@@ -103,7 +103,7 @@ static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str)
return;
msleep(1);
}
- printk(KERN_WARNING SFX "SRST not clear (stream %d)\n", str->dsd);
+ dev_warn(chip->card->dev, "SRST not clear (stream %d)\n", str->dsd);
}
static int lola_stream_wait_for_fifo(struct lola *chip,
@@ -118,7 +118,7 @@ static int lola_stream_wait_for_fifo(struct lola *chip,
return 0;
msleep(1);
}
- printk(KERN_WARNING SFX "FIFO not ready (stream %d)\n", str->dsd);
+ dev_warn(chip->card->dev, "FIFO not ready (stream %d)\n", str->dsd);
return -EIO;
}
@@ -156,7 +156,7 @@ static int lola_sync_wait_for_fifo(struct lola *chip,
return 0;
msleep(1);
}
- printk(KERN_WARNING SFX "FIFO not ready (pending %d)\n", pending - 1);
+ dev_warn(chip->card->dev, "FIFO not ready (pending %d)\n", pending - 1);
return -EIO;
}
@@ -373,7 +373,7 @@ static int lola_setup_periods(struct lola *chip, struct lola_pcm *pcm,
return 0;
error:
- snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n",
+ dev_err(chip->card->dev, "Too many BDL entries: buffer=%d, period=%d\n",
str->bufsize, period_bytes);
return -EINVAL;
}
@@ -415,7 +415,7 @@ static int lola_set_stream_config(struct lola *chip,
err = lola_codec_read(chip, str->nid, LOLA_VERB_SET_STREAM_FORMAT,
str->format_verb, 0, &val, NULL);
if (err < 0) {
- printk(KERN_ERR SFX "Cannot set stream format 0x%x\n",
+ dev_err(chip->card->dev, "Cannot set stream format 0x%x\n",
str->format_verb);
return err;
}
@@ -427,7 +427,8 @@ static int lola_set_stream_config(struct lola *chip,
LOLA_VERB_SET_CHANNEL_STREAMID, 0, verb,
&val, NULL);
if (err < 0) {
- printk(KERN_ERR SFX "Cannot set stream channel %d\n", i);
+ dev_err(chip->card->dev,
+ "Cannot set stream channel %d\n", i);
return err;
}
}
@@ -651,13 +652,14 @@ static int lola_init_stream(struct lola *chip, struct lola_stream *str,
str->dsd += MAX_STREAM_IN_COUNT;
err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
if (err < 0) {
- printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
+ dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
return err;
}
if (dir == PLAY) {
/* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1) */
if ((val & 0x00f00dff) != 0x00000010) {
- printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n",
+ dev_err(chip->card->dev,
+ "Invalid wcaps 0x%x for 0x%x\n",
val, nid);
return -EINVAL;
}
@@ -666,7 +668,8 @@ static int lola_init_stream(struct lola *chip, struct lola_stream *str,
* (bug : ignore bit8: Conn list = 0/1)
*/
if ((val & 0x00f00cff) != 0x00100010) {
- printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n",
+ dev_err(chip->card->dev,
+ "Invalid wcaps 0x%x for 0x%x\n",
val, nid);
return -EINVAL;
}
@@ -677,14 +680,15 @@ static int lola_init_stream(struct lola *chip, struct lola_stream *str,
err = lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val);
if (err < 0) {
- printk(KERN_ERR SFX "Can't read FORMATS 0x%x\n", nid);
+ dev_err(chip->card->dev, "Can't read FORMATS 0x%x\n", nid);
return err;
}
val &= 3;
if (val == 3)
str->can_float = true;
if (!(val & 1)) {
- printk(KERN_ERR SFX "Invalid formats 0x%x for 0x%x", val, nid);
+ dev_err(chip->card->dev,
+ "Invalid formats 0x%x for 0x%x", val, nid);
return -EINVAL;
}
return 0;
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
index 5fcaaa6da4a8..27f60ce8a55c 100644
--- a/sound/pci/lx6464es/lx6464es.c
+++ b/sound/pci/lx6464es/lx6464es.c
@@ -112,16 +112,16 @@ static int lx_hardware_open(struct lx6464es *chip,
snd_pcm_uframes_t period_size = runtime->period_size;
- snd_printd(LXP "allocating pipe for %d channels\n", channels);
+ dev_dbg(chip->card->dev, "allocating pipe for %d channels\n", channels);
err = lx_pipe_allocate(chip, 0, is_capture, channels);
if (err < 0) {
- snd_printk(KERN_ERR LXP "allocating pipe failed\n");
+ dev_err(chip->card->dev, LXP "allocating pipe failed\n");
return err;
}
err = lx_set_granularity(chip, period_size);
if (err < 0) {
- snd_printk(KERN_ERR LXP "setting granularity to %ld failed\n",
+ dev_err(chip->card->dev, "setting granularity to %ld failed\n",
period_size);
return err;
}
@@ -136,24 +136,24 @@ static int lx_hardware_start(struct lx6464es *chip,
struct snd_pcm_runtime *runtime = substream->runtime;
int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
- snd_printd(LXP "setting stream format\n");
+ dev_dbg(chip->card->dev, "setting stream format\n");
err = lx_stream_set_format(chip, runtime, 0, is_capture);
if (err < 0) {
- snd_printk(KERN_ERR LXP "setting stream format failed\n");
+ dev_err(chip->card->dev, "setting stream format failed\n");
return err;
}
- snd_printd(LXP "starting pipe\n");
+ dev_dbg(chip->card->dev, "starting pipe\n");
err = lx_pipe_start(chip, 0, is_capture);
if (err < 0) {
- snd_printk(KERN_ERR LXP "starting pipe failed\n");
+ dev_err(chip->card->dev, "starting pipe failed\n");
return err;
}
- snd_printd(LXP "waiting for pipe to start\n");
+ dev_dbg(chip->card->dev, "waiting for pipe to start\n");
err = lx_pipe_wait_for_start(chip, 0, is_capture);
if (err < 0) {
- snd_printk(KERN_ERR LXP "waiting for pipe failed\n");
+ dev_err(chip->card->dev, "waiting for pipe failed\n");
return err;
}
@@ -167,24 +167,24 @@ static int lx_hardware_stop(struct lx6464es *chip,
int err = 0;
int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
- snd_printd(LXP "pausing pipe\n");
+ dev_dbg(chip->card->dev, "pausing pipe\n");
err = lx_pipe_pause(chip, 0, is_capture);
if (err < 0) {
- snd_printk(KERN_ERR LXP "pausing pipe failed\n");
+ dev_err(chip->card->dev, "pausing pipe failed\n");
return err;
}
- snd_printd(LXP "waiting for pipe to become idle\n");
+ dev_dbg(chip->card->dev, "waiting for pipe to become idle\n");
err = lx_pipe_wait_for_idle(chip, 0, is_capture);
if (err < 0) {
- snd_printk(KERN_ERR LXP "waiting for pipe failed\n");
+ dev_err(chip->card->dev, "waiting for pipe failed\n");
return err;
}
- snd_printd(LXP "stopping pipe\n");
+ dev_dbg(chip->card->dev, "stopping pipe\n");
err = lx_pipe_stop(chip, 0, is_capture);
if (err < 0) {
- snd_printk(LXP "stopping pipe failed\n");
+ dev_err(chip->card->dev, "stopping pipe failed\n");
return err;
}
@@ -198,10 +198,10 @@ static int lx_hardware_close(struct lx6464es *chip,
int err = 0;
int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
- snd_printd(LXP "releasing pipe\n");
+ dev_dbg(chip->card->dev, "releasing pipe\n");
err = lx_pipe_release(chip, 0, is_capture);
if (err < 0) {
- snd_printk(LXP "releasing pipe failed\n");
+ dev_err(chip->card->dev, "releasing pipe failed\n");
return err;
}
@@ -216,7 +216,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
int err = 0;
int board_rate;
- snd_printdd("->lx_pcm_open\n");
+ dev_dbg(chip->card->dev, "->lx_pcm_open\n");
mutex_lock(&chip->setup_mutex);
/* copy the struct snd_pcm_hardware struct */
@@ -227,7 +227,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
err = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (err < 0) {
- snd_printk(KERN_WARNING LXP "could not constrain periods\n");
+ dev_warn(chip->card->dev, "could not constrain periods\n");
goto exit;
}
#endif
@@ -238,7 +238,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
board_rate, board_rate);
if (err < 0) {
- snd_printk(KERN_WARNING LXP "could not constrain periods\n");
+ dev_warn(chip->card->dev, "could not constrain periods\n");
goto exit;
}
@@ -248,7 +248,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream)
MICROBLAZE_IBL_MIN,
MICROBLAZE_IBL_MAX);
if (err < 0) {
- snd_printk(KERN_WARNING LXP
+ dev_warn(chip->card->dev,
"could not constrain period size\n");
goto exit;
}
@@ -263,14 +263,14 @@ exit:
runtime->private_data = chip;
mutex_unlock(&chip->setup_mutex);
- snd_printdd("<-lx_pcm_open, %d\n", err);
+ dev_dbg(chip->card->dev, "<-lx_pcm_open, %d\n", err);
return err;
}
static int lx_pcm_close(struct snd_pcm_substream *substream)
{
int err = 0;
- snd_printdd("->lx_pcm_close\n");
+ dev_dbg(substream->pcm->card->dev, "->lx_pcm_close\n");
return err;
}
@@ -285,13 +285,13 @@ static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream
struct lx_stream *lx_stream = is_capture ? &chip->capture_stream :
&chip->playback_stream;
- snd_printdd("->lx_pcm_stream_pointer\n");
+ dev_dbg(chip->card->dev, "->lx_pcm_stream_pointer\n");
spin_lock_irqsave(&chip->lock, flags);
pos = lx_stream->frame_pos * substream->runtime->period_size;
spin_unlock_irqrestore(&chip->lock, flags);
- snd_printdd(LXP "stream_pointer at %ld\n", pos);
+ dev_dbg(chip->card->dev, "stream_pointer at %ld\n", pos);
return pos;
}
@@ -301,37 +301,37 @@ static int lx_pcm_prepare(struct snd_pcm_substream *substream)
int err = 0;
const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
- snd_printdd("->lx_pcm_prepare\n");
+ dev_dbg(chip->card->dev, "->lx_pcm_prepare\n");
mutex_lock(&chip->setup_mutex);
if (chip->hardware_running[is_capture]) {
err = lx_hardware_stop(chip, substream);
if (err < 0) {
- snd_printk(KERN_ERR LXP "failed to stop hardware. "
+ dev_err(chip->card->dev, "failed to stop hardware. "
"Error code %d\n", err);
goto exit;
}
err = lx_hardware_close(chip, substream);
if (err < 0) {
- snd_printk(KERN_ERR LXP "failed to close hardware. "
+ dev_err(chip->card->dev, "failed to close hardware. "
"Error code %d\n", err);
goto exit;
}
}
- snd_printd(LXP "opening hardware\n");
+ dev_dbg(chip->card->dev, "opening hardware\n");
err = lx_hardware_open(chip, substream);
if (err < 0) {
- snd_printk(KERN_ERR LXP "failed to open hardware. "
+ dev_err(chip->card->dev, "failed to open hardware. "
"Error code %d\n", err);
goto exit;
}
err = lx_hardware_start(chip, substream);
if (err < 0) {
- snd_printk(KERN_ERR LXP "failed to start hardware. "
+ dev_err(chip->card->dev, "failed to start hardware. "
"Error code %d\n", err);
goto exit;
}
@@ -354,7 +354,7 @@ static int lx_pcm_hw_params(struct snd_pcm_substream *substream,
struct lx6464es *chip = snd_pcm_substream_chip(substream);
int err = 0;
- snd_printdd("->lx_pcm_hw_params\n");
+ dev_dbg(chip->card->dev, "->lx_pcm_hw_params\n");
mutex_lock(&chip->setup_mutex);
@@ -389,20 +389,20 @@ static int lx_pcm_hw_free(struct snd_pcm_substream *substream)
int err = 0;
int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
- snd_printdd("->lx_pcm_hw_free\n");
+ dev_dbg(chip->card->dev, "->lx_pcm_hw_free\n");
mutex_lock(&chip->setup_mutex);
if (chip->hardware_running[is_capture]) {
err = lx_hardware_stop(chip, substream);
if (err < 0) {
- snd_printk(KERN_ERR LXP "failed to stop hardware. "
+ dev_err(chip->card->dev, "failed to stop hardware. "
"Error code %d\n", err);
goto exit;
}
err = lx_hardware_close(chip, substream);
if (err < 0) {
- snd_printk(KERN_ERR LXP "failed to close hardware. "
+ dev_err(chip->card->dev, "failed to close hardware. "
"Error code %d\n", err);
goto exit;
}
@@ -446,25 +446,25 @@ static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream)
err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed,
size_array);
- snd_printdd(LXP "starting: needed %d, freed %d\n",
+ dev_dbg(chip->card->dev, "starting: needed %d, freed %d\n",
needed, freed);
err = lx_buffer_give(chip, 0, is_capture, period_bytes,
lower_32_bits(buf), upper_32_bits(buf),
&buffer_index);
- snd_printdd(LXP "starting: buffer index %x on 0x%lx (%d bytes)\n",
+ dev_dbg(chip->card->dev, "starting: buffer index %x on 0x%lx (%d bytes)\n",
buffer_index, (unsigned long)buf, period_bytes);
buf += period_bytes;
}
err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array);
- snd_printdd(LXP "starting: needed %d, freed %d\n", needed, freed);
+ dev_dbg(chip->card->dev, "starting: needed %d, freed %d\n", needed, freed);
- snd_printd(LXP "starting: starting stream\n");
+ dev_dbg(chip->card->dev, "starting: starting stream\n");
err = lx_stream_start(chip, 0, is_capture);
if (err < 0)
- snd_printk(KERN_ERR LXP "couldn't start stream\n");
+ dev_err(chip->card->dev, "couldn't start stream\n");
else
lx_stream->status = LX_STREAM_STATUS_RUNNING;
@@ -476,10 +476,10 @@ static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream)
const unsigned int is_capture = lx_stream->is_capture;
int err;
- snd_printd(LXP "stopping: stopping stream\n");
+ dev_dbg(chip->card->dev, "stopping: stopping stream\n");
err = lx_stream_stop(chip, 0, is_capture);
if (err < 0)
- snd_printk(KERN_ERR LXP "couldn't stop stream\n");
+ dev_err(chip->card->dev, "couldn't stop stream\n");
else
lx_stream->status = LX_STREAM_STATUS_FREE;
@@ -507,7 +507,7 @@ static void lx_trigger_tasklet(unsigned long data)
struct lx6464es *chip = (struct lx6464es *)data;
unsigned long flags;
- snd_printdd("->lx_trigger_tasklet\n");
+ dev_dbg(chip->card->dev, "->lx_trigger_tasklet\n");
spin_lock_irqsave(&chip->lock, flags);
lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream);
@@ -547,14 +547,14 @@ static int lx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct lx_stream *stream = is_capture ? &chip->capture_stream :
&chip->playback_stream;
- snd_printdd("->lx_pcm_trigger\n");
+ dev_dbg(chip->card->dev, "->lx_pcm_trigger\n");
return lx_pcm_trigger_dispatch(chip, stream, cmd);
}
static int snd_lx6464es_free(struct lx6464es *chip)
{
- snd_printdd("->snd_lx6464es_free\n");
+ dev_dbg(chip->card->dev, "->snd_lx6464es_free\n");
lx_irq_disable(chip);
@@ -583,7 +583,7 @@ static int lx_init_xilinx_reset(struct lx6464es *chip)
int i;
u32 plx_reg = lx_plx_reg_read(chip, ePLX_CHIPSC);
- snd_printdd("->lx_init_xilinx_reset\n");
+ dev_dbg(chip->card->dev, "->lx_init_xilinx_reset\n");
/* activate reset of xilinx */
plx_reg &= ~CHIPSC_RESET_XILINX;
@@ -603,8 +603,8 @@ static int lx_init_xilinx_reset(struct lx6464es *chip)
msleep(10);
reg_mbox3 = lx_plx_reg_read(chip, ePLX_MBOX3);
if (reg_mbox3) {
- snd_printd(LXP "xilinx reset done\n");
- snd_printdd(LXP "xilinx took %d loops\n", i);
+ dev_dbg(chip->card->dev, "xilinx reset done\n");
+ dev_dbg(chip->card->dev, "xilinx took %d loops\n", i);
break;
}
}
@@ -624,7 +624,7 @@ static int lx_init_xilinx_test(struct lx6464es *chip)
{
u32 reg;
- snd_printdd("->lx_init_xilinx_test\n");
+ dev_dbg(chip->card->dev, "->lx_init_xilinx_test\n");
/* TEST if we have access to Xilinx/MicroBlaze */
lx_dsp_reg_write(chip, eReg_CSM, 0);
@@ -632,19 +632,19 @@ static int lx_init_xilinx_test(struct lx6464es *chip)
reg = lx_dsp_reg_read(chip, eReg_CSM);
if (reg) {
- snd_printk(KERN_ERR LXP "Problem: Reg_CSM %x.\n", reg);
+ dev_err(chip->card->dev, "Problem: Reg_CSM %x.\n", reg);
/* PCI9056_SPACE0_REMAP */
lx_plx_reg_write(chip, ePLX_PCICR, 1);
reg = lx_dsp_reg_read(chip, eReg_CSM);
if (reg) {
- snd_printk(KERN_ERR LXP "Error: Reg_CSM %x.\n", reg);
+ dev_err(chip->card->dev, "Error: Reg_CSM %x.\n", reg);
return -EAGAIN; /* seems to be appropriate */
}
}
- snd_printd(LXP "Xilinx/MicroBlaze access test successful\n");
+ dev_dbg(chip->card->dev, "Xilinx/MicroBlaze access test successful\n");
return 0;
}
@@ -661,7 +661,7 @@ static int lx_init_ethersound_config(struct lx6464es *chip)
(64 << IOCR_OUTPUTS_OFFSET) |
(FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET);
- snd_printdd("->lx_init_ethersound\n");
+ dev_dbg(chip->card->dev, "->lx_init_ethersound\n");
chip->freq_ratio = FREQ_RATIO_SINGLE_MODE;
@@ -675,18 +675,18 @@ static int lx_init_ethersound_config(struct lx6464es *chip)
for (i = 0; i != 1000; ++i) {
if (lx_dsp_reg_read(chip, eReg_CSES) & 4) {
- snd_printd(LXP "ethersound initialized after %dms\n",
+ dev_dbg(chip->card->dev, "ethersound initialized after %dms\n",
i);
goto ethersound_initialized;
}
msleep(1);
}
- snd_printk(KERN_WARNING LXP
+ dev_warn(chip->card->dev,
"ethersound could not be initialized after %dms\n", i);
return -ETIMEDOUT;
ethersound_initialized:
- snd_printd(LXP "ethersound initialized\n");
+ dev_dbg(chip->card->dev, "ethersound initialized\n");
return 0;
}
@@ -696,14 +696,14 @@ static int lx_init_get_version_features(struct lx6464es *chip)
int err;
- snd_printdd("->lx_init_get_version_features\n");
+ dev_dbg(chip->card->dev, "->lx_init_get_version_features\n");
err = lx_dsp_get_version(chip, &dsp_version);
if (err == 0) {
u32 freq;
- snd_printk(LXP "DSP version: V%02d.%02d #%d\n",
+ dev_info(chip->card->dev, "DSP version: V%02d.%02d #%d\n",
(dsp_version>>16) & 0xff, (dsp_version>>8) & 0xff,
dsp_version & 0xff);
@@ -718,9 +718,9 @@ static int lx_init_get_version_features(struct lx6464es *chip)
err = lx_dsp_get_clock_frequency(chip, &freq);
if (err == 0)
chip->board_sample_rate = freq;
- snd_printd(LXP "actual clock frequency %d\n", freq);
+ dev_dbg(chip->card->dev, "actual clock frequency %d\n", freq);
} else {
- snd_printk(KERN_ERR LXP "DSP corrupted \n");
+ dev_err(chip->card->dev, "DSP corrupted \n");
err = -EAGAIN;
}
@@ -732,7 +732,7 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran)
int err = 0;
u32 snapped_gran = MICROBLAZE_IBL_MIN;
- snd_printdd("->lx_set_granularity\n");
+ dev_dbg(chip->card->dev, "->lx_set_granularity\n");
/* blocksize is a power of 2 */
while ((snapped_gran < gran) &&
@@ -745,14 +745,14 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran)
err = lx_dsp_set_granularity(chip, snapped_gran);
if (err < 0) {
- snd_printk(KERN_WARNING LXP "could not set granularity\n");
+ dev_warn(chip->card->dev, "could not set granularity\n");
err = -EAGAIN;
}
if (snapped_gran != gran)
- snd_printk(LXP "snapped blocksize to %d\n", snapped_gran);
+ dev_err(chip->card->dev, "snapped blocksize to %d\n", snapped_gran);
- snd_printd(LXP "set blocksize on board %d\n", snapped_gran);
+ dev_dbg(chip->card->dev, "set blocksize on board %d\n", snapped_gran);
chip->pcm_granularity = snapped_gran;
return err;
@@ -764,19 +764,19 @@ static int lx_init_dsp(struct lx6464es *chip)
int err;
int i;
- snd_printdd("->lx_init_dsp\n");
+ dev_dbg(chip->card->dev, "->lx_init_dsp\n");
- snd_printd(LXP "initialize board\n");
+ dev_dbg(chip->card->dev, "initialize board\n");
err = lx_init_xilinx_reset(chip);
if (err)
return err;
- snd_printd(LXP "testing board\n");
+ dev_dbg(chip->card->dev, "testing board\n");
err = lx_init_xilinx_test(chip);
if (err)
return err;
- snd_printd(LXP "initialize ethersound configuration\n");
+ dev_dbg(chip->card->dev, "initialize ethersound configuration\n");
err = lx_init_ethersound_config(chip);
if (err)
return err;
@@ -797,8 +797,9 @@ static int lx_init_dsp(struct lx6464es *chip)
return -ETIMEDOUT;
mac_ready:
- snd_printd(LXP "mac address ready read after: %dms\n", i);
- snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n",
+ dev_dbg(chip->card->dev, "mac address ready read after: %dms\n", i);
+ dev_info(chip->card->dev,
+ "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n",
chip->mac_address[0], chip->mac_address[1], chip->mac_address[2],
chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]);
@@ -977,7 +978,7 @@ static int snd_lx6464es_create(struct snd_card *card,
.dev_free = snd_lx6464es_dev_free,
};
- snd_printdd("->snd_lx6464es_create\n");
+ dev_dbg(card->dev, "->snd_lx6464es_create\n");
*rchip = NULL;
@@ -991,8 +992,8 @@ static int snd_lx6464es_create(struct snd_card *card,
/* check if we can restrict PCI DMA transfers to 32 bits */
err = pci_set_dma_mask(pci, DMA_BIT_MASK(32));
if (err < 0) {
- snd_printk(KERN_ERR "architecture does not support "
- "32bit PCI busmaster DMA\n");
+ dev_err(card->dev,
+ "architecture does not support 32bit PCI busmaster DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -1034,7 +1035,7 @@ static int snd_lx6464es_create(struct snd_card *card,
err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip);
if (err) {
- snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
goto request_irq_failed;
}
chip->irq = pci->irq;
@@ -1045,7 +1046,7 @@ static int snd_lx6464es_create(struct snd_card *card,
err = lx_init_dsp(chip);
if (err < 0) {
- snd_printk(KERN_ERR LXP "error during DSP initialization\n");
+ dev_err(card->dev, "error during DSP initialization\n");
return err;
}
@@ -1062,8 +1063,6 @@ static int snd_lx6464es_create(struct snd_card *card,
if (err < 0)
return err;
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
return 0;
@@ -1090,7 +1089,7 @@ static int snd_lx6464es_probe(struct pci_dev *pci,
struct lx6464es *chip;
int err;
- snd_printdd("->snd_lx6464es_probe\n");
+ dev_dbg(&pci->dev, "->snd_lx6464es_probe\n");
if (dev >= SNDRV_CARDS)
return -ENODEV;
@@ -1099,13 +1098,14 @@ static int snd_lx6464es_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
err = snd_lx6464es_create(card, pci, &chip);
if (err < 0) {
- snd_printk(KERN_ERR LXP "error during snd_lx6464es_create\n");
+ dev_err(card->dev, "error during snd_lx6464es_create\n");
goto out_free;
}
@@ -1125,7 +1125,7 @@ static int snd_lx6464es_probe(struct pci_dev *pci,
if (err < 0)
goto out_free;
- snd_printdd(LXP "initialization successful\n");
+ dev_dbg(chip->card->dev, "initialization successful\n");
pci_set_drvdata(pci, card);
dev++;
return 0;
diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c
index 626ecad4dae7..2d8e95e9fbe5 100644
--- a/sound/pci/lx6464es/lx_core.c
+++ b/sound/pci/lx6464es/lx_core.c
@@ -141,63 +141,6 @@ void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data)
iowrite32(data, address);
}
-u32 lx_plx_mbox_read(struct lx6464es *chip, int mbox_nr)
-{
- int index;
-
- switch (mbox_nr) {
- case 1:
- index = ePLX_MBOX1; break;
- case 2:
- index = ePLX_MBOX2; break;
- case 3:
- index = ePLX_MBOX3; break;
- case 4:
- index = ePLX_MBOX4; break;
- case 5:
- index = ePLX_MBOX5; break;
- case 6:
- index = ePLX_MBOX6; break;
- case 7:
- index = ePLX_MBOX7; break;
- case 0: /* reserved for HF flags */
- snd_BUG();
- default:
- return 0xdeadbeef;
- }
-
- return lx_plx_reg_read(chip, index);
-}
-
-int lx_plx_mbox_write(struct lx6464es *chip, int mbox_nr, u32 value)
-{
- int index = -1;
-
- switch (mbox_nr) {
- case 1:
- index = ePLX_MBOX1; break;
- case 3:
- index = ePLX_MBOX3; break;
- case 4:
- index = ePLX_MBOX4; break;
- case 5:
- index = ePLX_MBOX5; break;
- case 6:
- index = ePLX_MBOX6; break;
- case 7:
- index = ePLX_MBOX7; break;
- case 0: /* reserved for HF flags */
- case 2: /* reserved for Pipe States
- * the DSP keeps an image of it */
- snd_BUG();
- return -EBADRQC;
- }
-
- lx_plx_reg_write(chip, index, value);
- return 0;
-}
-
-
/* rmh */
#ifdef CONFIG_SND_DEBUG
@@ -330,7 +273,7 @@ static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh)
int dwloop;
if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) {
- snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg);
+ dev_err(chip->card->dev, "PIOSendMessage eReg_CSM %x\n", reg);
return -EBUSY;
}
@@ -351,7 +294,7 @@ static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh)
} else
udelay(1);
}
- snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send_atomic! "
+ dev_warn(chip->card->dev, "TIMEOUT lx_message_send_atomic! "
"polling failed\n");
polling_successful:
@@ -363,18 +306,18 @@ polling_successful:
rmh->stat_len);
}
} else
- snd_printk(LXP "rmh error: %08x\n", reg);
+ dev_err(chip->card->dev, "rmh error: %08x\n", reg);
/* clear Reg_CSM_MR */
lx_dsp_reg_write(chip, eReg_CSM, 0);
switch (reg) {
case ED_DSP_TIMED_OUT:
- snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n");
+ dev_warn(chip->card->dev, "lx_message_send: dsp timeout\n");
return -ETIMEDOUT;
case ED_DSP_CRASHED:
- snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n");
+ dev_warn(chip->card->dev, "lx_message_send: dsp crashed\n");
return -EAGAIN;
}
@@ -491,33 +434,6 @@ int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data)
#define CSES_BROADCAST 0x0002
#define CSES_UPDATE_LDSV 0x0004
-int lx_dsp_es_check_pipeline(struct lx6464es *chip)
-{
- int i;
-
- for (i = 0; i != CSES_TIMEOUT; ++i) {
- /*
- * le bit CSES_UPDATE_LDSV est à 1 dés que le macprog
- * est pret. il re-passe à 0 lorsque le premier read a
- * été fait. pour l'instant on retire le test car ce bit
- * passe a 1 environ 200 à 400 ms aprés que le registre
- * confES à été écrit (kick du xilinx ES).
- *
- * On ne teste que le bit CE.
- * */
-
- u32 cses = lx_dsp_reg_read(chip, eReg_CSES);
-
- if ((cses & CSES_CE) == 0)
- return 0;
-
- udelay(1);
- }
-
- return -ETIMEDOUT;
-}
-
-
#define PIPE_INFO_TO_CMD(capture, pipe) \
((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET)
@@ -542,7 +458,7 @@ int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture,
spin_unlock_irqrestore(&chip->msg_lock, flags);
if (err != 0)
- snd_printk(KERN_ERR "lx6464es: could not allocate pipe\n");
+ dev_err(chip->card->dev, "could not allocate pipe\n");
return err;
}
@@ -604,11 +520,13 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
}
#if 0
- snd_printdd(LXP "CMD_08_ASK_BUFFERS: needed %d, freed %d\n",
+ dev_dbg(chip->card->dev,
+ "CMD_08_ASK_BUFFERS: needed %d, freed %d\n",
*r_needed, *r_freed);
for (i = 0; i < MAX_STREAM_BUFFER; ++i) {
for (i = 0; i != chip->rmh.stat_len; ++i)
- snd_printdd(" stat[%d]: %x, %x\n", i,
+ dev_dbg(chip->card->dev,
+ " stat[%d]: %x, %x\n", i,
chip->rmh.stat[i],
chip->rmh.stat[i] & MASK_DATA_SIZE);
}
@@ -701,8 +619,8 @@ int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture,
err = lx_message_send_atomic(chip, &chip->rmh); /* don't sleep! */
if (err != 0)
- snd_printk(KERN_ERR
- "lx6464es: could not query pipe's sample count\n");
+ dev_err(chip->card->dev,
+ "could not query pipe's sample count\n");
else {
*rsample_count = ((u64)(chip->rmh.stat[0] & MASK_SPL_COUNT_HI)
<< 24) /* hi part */
@@ -728,7 +646,7 @@ int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate)
err = lx_message_send_atomic(chip, &chip->rmh);
if (err != 0)
- snd_printk(KERN_ERR "lx6464es: could not query pipe's state\n");
+ dev_err(chip->card->dev, "could not query pipe's state\n");
else
*rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F;
@@ -801,7 +719,7 @@ int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime,
u32 channels = runtime->channels;
if (runtime->channels != channels)
- snd_printk(KERN_ERR LXP "channel count mismatch: %d vs %d",
+ dev_err(chip->card->dev, "channel count mismatch: %d vs %d",
runtime->channels, channels);
spin_lock_irqsave(&chip->msg_lock, flags);
@@ -904,13 +822,16 @@ int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture,
}
if (err == EB_RBUFFERS_TABLE_OVERFLOW)
- snd_printk(LXP "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n");
+ dev_err(chip->card->dev,
+ "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n");
if (err == EB_INVALID_STREAM)
- snd_printk(LXP "lx_buffer_give EB_INVALID_STREAM\n");
+ dev_err(chip->card->dev,
+ "lx_buffer_give EB_INVALID_STREAM\n");
if (err == EB_CMD_REFUSED)
- snd_printk(LXP "lx_buffer_give EB_CMD_REFUSED\n");
+ dev_err(chip->card->dev,
+ "lx_buffer_give EB_CMD_REFUSED\n");
done:
spin_unlock_irqrestore(&chip->msg_lock, flags);
@@ -983,7 +904,8 @@ int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute)
chip->rmh.cmd[1] = (u32)(mute_mask >> (u64)32); /* hi part */
chip->rmh.cmd[2] = (u32)(mute_mask & (u64)0xFFFFFFFF); /* lo part */
- snd_printk("mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1],
+ dev_dbg(chip->card->dev,
+ "mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1],
chip->rmh.cmd[2]);
err = lx_message_send_atomic(chip, &chip->rmh);
@@ -1093,7 +1015,7 @@ static int lx_interrupt_ack(struct lx6464es *chip, u32 *r_irqsrc,
}
if (irq_async) {
- /* snd_printd("interrupt: async event pending\n"); */
+ /* dev_dbg(chip->card->dev, "interrupt: async event pending\n"); */
*r_async_pending = 1;
}
@@ -1139,13 +1061,13 @@ static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc,
if (eb_pending_in) {
*r_notified_in_pipe_mask = ((u64)stat[3] << 32)
+ stat[4];
- snd_printdd(LXP "interrupt: EOBI pending %llx\n",
+ dev_dbg(chip->card->dev, "interrupt: EOBI pending %llx\n",
*r_notified_in_pipe_mask);
}
if (eb_pending_out) {
*r_notified_out_pipe_mask = ((u64)stat[1] << 32)
+ stat[2];
- snd_printdd(LXP "interrupt: EOBO pending %llx\n",
+ dev_dbg(chip->card->dev, "interrupt: EOBO pending %llx\n",
*r_notified_out_pipe_mask);
}
@@ -1181,17 +1103,19 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
u32 needed, freed;
u32 size_array[MAX_STREAM_BUFFER];
- snd_printdd("->lx_interrupt_request_new_buffer\n");
+ dev_dbg(chip->card->dev, "->lx_interrupt_request_new_buffer\n");
spin_lock_irqsave(&chip->lock, flags);
err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array);
- snd_printdd(LXP "interrupt: needed %d, freed %d\n", needed, freed);
+ dev_dbg(chip->card->dev,
+ "interrupt: needed %d, freed %d\n", needed, freed);
unpack_pointer(buf, &buf_lo, &buf_hi);
err = lx_buffer_give(chip, 0, is_capture, period_bytes, buf_lo, buf_hi,
&buffer_index);
- snd_printdd(LXP "interrupt: gave buffer index %x on 0x%lx (%d bytes)\n",
+ dev_dbg(chip->card->dev,
+ "interrupt: gave buffer index %x on 0x%lx (%d bytes)\n",
buffer_index, (unsigned long)buf, period_bytes);
lx_stream->frame_pos = next_pos;
@@ -1206,11 +1130,11 @@ void lx_tasklet_playback(unsigned long data)
struct lx_stream *lx_stream = &chip->playback_stream;
int err;
- snd_printdd("->lx_tasklet_playback\n");
+ dev_dbg(chip->card->dev, "->lx_tasklet_playback\n");
err = lx_interrupt_request_new_buffer(chip, lx_stream);
if (err < 0)
- snd_printk(KERN_ERR LXP
+ dev_err(chip->card->dev,
"cannot request new buffer for playback\n");
snd_pcm_period_elapsed(lx_stream->stream);
@@ -1222,10 +1146,10 @@ void lx_tasklet_capture(unsigned long data)
struct lx_stream *lx_stream = &chip->capture_stream;
int err;
- snd_printdd("->lx_tasklet_capture\n");
+ dev_dbg(chip->card->dev, "->lx_tasklet_capture\n");
err = lx_interrupt_request_new_buffer(chip, lx_stream);
if (err < 0)
- snd_printk(KERN_ERR LXP
+ dev_err(chip->card->dev,
"cannot request new buffer for capture\n");
snd_pcm_period_elapsed(lx_stream->stream);
@@ -1240,12 +1164,14 @@ static int lx_interrupt_handle_audio_transfer(struct lx6464es *chip,
int err = 0;
if (notified_in_pipe_mask) {
- snd_printdd(LXP "requesting audio transfer for capture\n");
+ dev_dbg(chip->card->dev,
+ "requesting audio transfer for capture\n");
tasklet_hi_schedule(&chip->tasklet_capture);
}
if (notified_out_pipe_mask) {
- snd_printdd(LXP "requesting audio transfer for playback\n");
+ dev_dbg(chip->card->dev,
+ "requesting audio transfer for playback\n");
tasklet_hi_schedule(&chip->tasklet_playback);
}
@@ -1261,11 +1187,12 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
spin_lock(&chip->lock);
- snd_printdd("**************************************************\n");
+ dev_dbg(chip->card->dev,
+ "**************************************************\n");
if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) {
spin_unlock(&chip->lock);
- snd_printdd("IRQ_NONE\n");
+ dev_dbg(chip->card->dev, "IRQ_NONE\n");
return IRQ_NONE; /* this device did not cause the interrupt */
}
@@ -1274,16 +1201,16 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
#if 0
if (irqsrc & MASK_SYS_STATUS_EOBI)
- snd_printdd(LXP "interrupt: EOBI\n");
+ dev_dgg(chip->card->dev, "interrupt: EOBI\n");
if (irqsrc & MASK_SYS_STATUS_EOBO)
- snd_printdd(LXP "interrupt: EOBO\n");
+ dev_dbg(chip->card->dev, "interrupt: EOBO\n");
if (irqsrc & MASK_SYS_STATUS_URUN)
- snd_printdd(LXP "interrupt: URUN\n");
+ dev_dbg(chip->card->dev, "interrupt: URUN\n");
if (irqsrc & MASK_SYS_STATUS_ORUN)
- snd_printdd(LXP "interrupt: ORUN\n");
+ dev_dbg(chip->card->dev, "interrupt: ORUN\n");
#endif
if (async_pending) {
@@ -1298,7 +1225,7 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
&notified_in_pipe_mask,
&notified_out_pipe_mask);
if (err)
- snd_printk(KERN_ERR LXP
+ dev_err(chip->card->dev,
"error handling async events\n");
err = lx_interrupt_handle_audio_transfer(chip,
@@ -1306,7 +1233,7 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
notified_out_pipe_mask
);
if (err)
- snd_printk(KERN_ERR LXP
+ dev_err(chip->card->dev,
"error during audio transfer\n");
}
@@ -1318,7 +1245,7 @@ irqreturn_t lx_interrupt(int irq, void *dev_id)
*
* */
- snd_printdd("lx6464es: interrupt requests escmd handling\n");
+ dev_dbg(chip->card->dev, "interrupt requests escmd handling\n");
#endif
}
@@ -1346,12 +1273,12 @@ static void lx_irq_set(struct lx6464es *chip, int enable)
void lx_irq_enable(struct lx6464es *chip)
{
- snd_printdd("->lx_irq_enable\n");
+ dev_dbg(chip->card->dev, "->lx_irq_enable\n");
lx_irq_set(chip, 1);
}
void lx_irq_disable(struct lx6464es *chip)
{
- snd_printdd("->lx_irq_disable\n");
+ dev_dbg(chip->card->dev, "->lx_irq_disable\n");
lx_irq_set(chip, 0);
}
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index d5417360f51f..0d3ea3e79952 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -1403,7 +1403,7 @@ static int snd_m3_pcm_hw_params(struct snd_pcm_substream *substream,
/* set buffer address */
s->buffer_addr = substream->runtime->dma_addr;
if (s->buffer_addr & 0x3) {
- snd_printk(KERN_ERR "oh my, not aligned\n");
+ dev_err(substream->pcm->card->dev, "oh my, not aligned\n");
s->buffer_addr = s->buffer_addr & ~0x3;
}
return 0;
@@ -1900,7 +1900,7 @@ static int snd_m3_ac97_wait(struct snd_m3 *chip)
cpu_relax();
} while (i-- > 0);
- snd_printk(KERN_ERR "ac97 serial bus busy\n");
+ dev_err(chip->card->dev, "ac97 serial bus busy\n");
return 1;
}
@@ -2015,7 +2015,8 @@ static void snd_m3_ac97_reset(struct snd_m3 *chip)
delay1 += 10;
delay2 += 100;
- snd_printd("maestro3: retrying codec reset with delays of %d and %d ms\n",
+ dev_dbg(chip->card->dev,
+ "retrying codec reset with delays of %d and %d ms\n",
delay1, delay2);
}
@@ -2194,7 +2195,8 @@ static int snd_m3_assp_client_init(struct snd_m3 *chip, struct m3_dma *s, int in
address = 0x1100 + ((data_bytes/2) * index);
if ((address + (data_bytes/2)) >= 0x1c00) {
- snd_printk(KERN_ERR "no memory for %d bytes at ind %d (addr 0x%x)\n",
+ dev_err(chip->card->dev,
+ "no memory for %d bytes at ind %d (addr 0x%x)\n",
data_bytes, index, address);
return -ENOMEM;
}
@@ -2439,8 +2441,7 @@ static int m3_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "maestor3: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -2553,7 +2554,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
/* check, if we can restrict PCI DMA transfers to 28 bits */
if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) {
- snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n");
+ dev_err(card->dev,
+ "architecture does not support 28bit PCI busmaster DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -2586,9 +2588,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
else {
quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list);
if (quirk) {
- snd_printdd(KERN_INFO
- "maestro3: set amp-gpio for '%s'\n",
- snd_pci_quirk_name(quirk));
+ dev_info(card->dev, "set amp-gpio for '%s'\n",
+ snd_pci_quirk_name(quirk));
chip->amp_gpio = quirk->value;
} else if (chip->allegro_flag)
chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
@@ -2598,9 +2599,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list);
if (quirk) {
- snd_printdd(KERN_INFO
- "maestro3: enabled irda workaround for '%s'\n",
- snd_pci_quirk_name(quirk));
+ dev_info(card->dev, "enabled irda workaround for '%s'\n",
+ snd_pci_quirk_name(quirk));
chip->irda_workaround = 1;
}
quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list);
@@ -2652,7 +2652,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_m3_free(chip);
return -ENOMEM;
}
@@ -2661,7 +2661,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
#ifdef CONFIG_PM_SLEEP
chip->suspend_mem = vmalloc(sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH));
if (chip->suspend_mem == NULL)
- snd_printk(KERN_WARNING "can't allocate apm buffer\n");
+ dev_warn(card->dev, "can't allocate apm buffer\n");
#endif
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
@@ -2685,16 +2685,15 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
if (chip->hv_config & HV_CTRL_ENABLE) {
err = snd_m3_input_register(chip);
if (err)
- snd_printk(KERN_WARNING "Input device registration "
- "failed with error %i", err);
+ dev_warn(card->dev,
+ "Input device registration failed with error %i",
+ err);
}
#endif
snd_m3_enable_ints(chip);
snd_m3_assp_continue(chip);
- snd_card_set_dev(card, &pci->dev);
-
*chip_ret = chip;
return 0;
@@ -2721,7 +2720,8 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -2764,7 +2764,7 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
-1, &chip->rmidi);
if (err < 0)
- printk(KERN_WARNING "maestro3: no MIDI support.\n");
+ dev_warn(card->dev, "no MIDI support.\n");
#endif
pci_set_drvdata(pci, card);
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 1e0f6ee193f0..a93e7af51eed 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -87,7 +87,8 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr,
if(!start) return 0; /* already stopped */
break;
default:
- snd_printk(KERN_ERR "error mixart_set_pipe_state called with wrong pipe->status!\n");
+ dev_err(&mgr->pci->dev,
+ "error mixart_set_pipe_state called with wrong pipe->status!\n");
return -EINVAL; /* function called with wrong pipe status */
}
@@ -102,7 +103,8 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr,
err = snd_mixart_send_msg_wait_notif(mgr, &request, system_msg_uid);
if(err) {
- snd_printk(KERN_ERR "error : MSG_SYSTEM_WAIT_SYNCHRO_CMD was not notified !\n");
+ dev_err(&mgr->pci->dev,
+ "error : MSG_SYSTEM_WAIT_SYNCHRO_CMD was not notified !\n");
return err;
}
@@ -123,7 +125,9 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr,
err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp);
if (err < 0 || group_state_resp.txx_status != 0) {
- snd_printk(KERN_ERR "error MSG_STREAM_ST***_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status);
+ dev_err(&mgr->pci->dev,
+ "error MSG_STREAM_ST***_STREAM_GRP_PACKET err=%x stat=%x !\n",
+ err, group_state_resp.txx_status);
return -EINVAL;
}
@@ -134,7 +138,9 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr,
err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp);
if (err < 0 || group_state_resp.txx_status != 0) {
- snd_printk(KERN_ERR "error MSG_STREAM_START_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status);
+ dev_err(&mgr->pci->dev,
+ "error MSG_STREAM_START_STREAM_GRP_PACKET err=%x stat=%x !\n",
+ err, group_state_resp.txx_status);
return -EINVAL;
}
@@ -147,7 +153,9 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr,
err = snd_mixart_send_msg(mgr, &request, sizeof(stat), &stat);
if (err < 0 || stat != 0) {
- snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD err=%x stat=%x !\n", err, stat);
+ dev_err(&mgr->pci->dev,
+ "error MSG_SYSTEM_SEND_SYNCHRO_CMD err=%x stat=%x !\n",
+ err, stat);
return -EINVAL;
}
@@ -178,7 +186,9 @@ static int mixart_set_clock(struct mixart_mgr *mgr,
if(rate == 0)
return 0; /* nothing to do */
else {
- snd_printk(KERN_ERR "error mixart_set_clock(%d) called with wrong pipe->status !\n", rate);
+ dev_err(&mgr->pci->dev,
+ "error mixart_set_clock(%d) called with wrong pipe->status !\n",
+ rate);
return -EINVAL;
}
}
@@ -190,7 +200,7 @@ static int mixart_set_clock(struct mixart_mgr *mgr,
clock_properties.nb_callers = 1; /* only one entry in uid_caller ! */
clock_properties.uid_caller[0] = pipe->group_uid;
- snd_printdd("mixart_set_clock to %d kHz\n", rate);
+ dev_dbg(&mgr->pci->dev, "mixart_set_clock to %d kHz\n", rate);
request.message_id = MSG_CLOCK_SET_PROPERTIES;
request.uid = mgr->uid_console_manager;
@@ -199,7 +209,9 @@ static int mixart_set_clock(struct mixart_mgr *mgr,
err = snd_mixart_send_msg(mgr, &request, sizeof(clock_prop_resp), &clock_prop_resp);
if (err < 0 || clock_prop_resp.status != 0 || clock_prop_resp.clock_mode != CM_STANDALONE) {
- snd_printk(KERN_ERR "error MSG_CLOCK_SET_PROPERTIES err=%x stat=%x mod=%x !\n", err, clock_prop_resp.status, clock_prop_resp.clock_mode);
+ dev_err(&mgr->pci->dev,
+ "error MSG_CLOCK_SET_PROPERTIES err=%x stat=%x mod=%x !\n",
+ err, clock_prop_resp.status, clock_prop_resp.clock_mode);
return -EINVAL;
}
@@ -252,7 +264,9 @@ snd_mixart_add_ref_pipe(struct snd_mixart *chip, int pcm_number, int capture,
struct mixart_streaming_group sgroup_resp;
} *buf;
- snd_printdd("add_ref_pipe audio chip(%d) pcm(%d)\n", chip->chip_idx, pcm_number);
+ dev_dbg(chip->card->dev,
+ "add_ref_pipe audio chip(%d) pcm(%d)\n",
+ chip->chip_idx, pcm_number);
buf = kmalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
@@ -302,7 +316,9 @@ snd_mixart_add_ref_pipe(struct snd_mixart *chip, int pcm_number, int capture,
err = snd_mixart_send_msg(chip->mgr, &request, sizeof(buf->sgroup_resp), &buf->sgroup_resp);
if((err < 0) || (buf->sgroup_resp.status != 0)) {
- snd_printk(KERN_ERR "error MSG_STREAM_ADD_**PUT_GROUP err=%x stat=%x !\n", err, buf->sgroup_resp.status);
+ dev_err(chip->card->dev,
+ "error MSG_STREAM_ADD_**PUT_GROUP err=%x stat=%x !\n",
+ err, buf->sgroup_resp.status);
kfree(buf);
return NULL;
}
@@ -343,13 +359,14 @@ int snd_mixart_kill_ref_pipe(struct mixart_mgr *mgr,
/* release the clock */
err = mixart_set_clock( mgr, pipe, 0);
if( err < 0 ) {
- snd_printk(KERN_ERR "mixart_set_clock(0) return error!\n");
+ dev_err(&mgr->pci->dev,
+ "mixart_set_clock(0) return error!\n");
}
/* stop the pipe */
err = mixart_set_pipe_state(mgr, pipe, 0);
if( err < 0 ) {
- snd_printk(KERN_ERR "error stopping pipe!\n");
+ dev_err(&mgr->pci->dev, "error stopping pipe!\n");
}
request.message_id = MSG_STREAM_DELETE_GROUP;
@@ -360,7 +377,9 @@ int snd_mixart_kill_ref_pipe(struct mixart_mgr *mgr,
/* delete the pipe */
err = snd_mixart_send_msg(mgr, &request, sizeof(delete_resp), &delete_resp);
if ((err < 0) || (delete_resp.status != 0)) {
- snd_printk(KERN_ERR "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n", err, delete_resp.status);
+ dev_err(&mgr->pci->dev,
+ "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n",
+ err, delete_resp.status);
}
pipe->group_uid = (struct mixart_uid){0,0};
@@ -414,7 +433,7 @@ static int snd_mixart_trigger(struct snd_pcm_substream *subs, int cmd)
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- snd_printdd("SNDRV_PCM_TRIGGER_START\n");
+ dev_dbg(subs->pcm->card->dev, "SNDRV_PCM_TRIGGER_START\n");
/* START_STREAM */
if( mixart_set_stream_state(stream, 1) )
@@ -431,19 +450,19 @@ static int snd_mixart_trigger(struct snd_pcm_substream *subs, int cmd)
stream->status = MIXART_STREAM_STATUS_OPEN;
- snd_printdd("SNDRV_PCM_TRIGGER_STOP\n");
+ dev_dbg(subs->pcm->card->dev, "SNDRV_PCM_TRIGGER_STOP\n");
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
/* TODO */
stream->status = MIXART_STREAM_STATUS_PAUSE;
- snd_printdd("SNDRV_PCM_PAUSE_PUSH\n");
+ dev_dbg(subs->pcm->card->dev, "SNDRV_PCM_PAUSE_PUSH\n");
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
/* TODO */
stream->status = MIXART_STREAM_STATUS_RUNNING;
- snd_printdd("SNDRV_PCM_PAUSE_RELEASE\n");
+ dev_dbg(subs->pcm->card->dev, "SNDRV_PCM_PAUSE_RELEASE\n");
break;
default:
return -EINVAL;
@@ -456,7 +475,8 @@ static int mixart_sync_nonblock_events(struct mixart_mgr *mgr)
unsigned long timeout = jiffies + HZ;
while (atomic_read(&mgr->msg_processed) > 0) {
if (time_after(jiffies, timeout)) {
- snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n");
+ dev_err(&mgr->pci->dev,
+ "mixart: cannot process nonblock events!\n");
return -EBUSY;
}
schedule_timeout_uninterruptible(1);
@@ -474,7 +494,7 @@ static int snd_mixart_prepare(struct snd_pcm_substream *subs)
/* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */
- snd_printdd("snd_mixart_prepare\n");
+ dev_dbg(chip->card->dev, "snd_mixart_prepare\n");
mixart_sync_nonblock_events(chip->mgr);
@@ -542,11 +562,13 @@ static int mixart_set_format(struct mixart_stream *stream, snd_pcm_format_t form
stream_param.sample_size = 32;
break;
default:
- snd_printk(KERN_ERR "error mixart_set_format() : unknown format\n");
+ dev_err(chip->card->dev,
+ "error mixart_set_format() : unknown format\n");
return -EINVAL;
}
- snd_printdd("set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n",
+ dev_dbg(chip->card->dev,
+ "set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n",
stream_param.sample_type, stream_param.sample_size, stream_param.sampling_freq, stream->channels);
/* TODO: what else to configure ? */
@@ -566,7 +588,9 @@ static int mixart_set_format(struct mixart_stream *stream, snd_pcm_format_t form
err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
if((err < 0) || resp.error_code) {
- snd_printk(KERN_ERR "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", err, resp.error_code);
+ dev_err(chip->card->dev,
+ "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n",
+ err, resp.error_code);
return -EINVAL;
}
return 0;
@@ -627,8 +651,9 @@ static int snd_mixart_hw_params(struct snd_pcm_substream *subs,
bufferinfo[i].available_length = subs->runtime->dma_bytes;
/* bufferinfo[i].buffer_id is already defined */
- snd_printdd("snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n", i,
- bufferinfo[i].buffer_address,
+ dev_dbg(chip->card->dev,
+ "snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n",
+ i, bufferinfo[i].buffer_address,
bufferinfo[i].available_length,
subs->number);
}
@@ -714,14 +739,18 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs)
pcm_number = MIXART_PCM_DIGITAL;
runtime->hw = snd_mixart_digital_caps;
}
- snd_printdd("snd_mixart_playback_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);
+ dev_dbg(chip->card->dev,
+ "snd_mixart_playback_open C%d/P%d/Sub%d\n",
+ chip->chip_idx, pcm_number, subs->number);
/* get stream info */
stream = &(chip->playback_stream[pcm_number][subs->number]);
if (stream->status != MIXART_STREAM_STATUS_FREE){
/* streams in use */
- snd_printk(KERN_ERR "snd_mixart_playback_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
+ dev_err(chip->card->dev,
+ "snd_mixart_playback_open C%d/P%d/Sub%d in use\n",
+ chip->chip_idx, pcm_number, subs->number);
err = -EBUSY;
goto _exit_open;
}
@@ -737,7 +766,7 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs)
/* start the pipe if necessary */
err = mixart_set_pipe_state(chip->mgr, pipe, 1);
if( err < 0 ) {
- snd_printk(KERN_ERR "error starting pipe!\n");
+ dev_err(chip->card->dev, "error starting pipe!\n");
snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
err = -EINVAL;
goto _exit_open;
@@ -792,14 +821,17 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs)
runtime->hw.channels_min = 2; /* for instance, no mono */
- snd_printdd("snd_mixart_capture_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);
+ dev_dbg(chip->card->dev, "snd_mixart_capture_open C%d/P%d/Sub%d\n",
+ chip->chip_idx, pcm_number, subs->number);
/* get stream info */
stream = &(chip->capture_stream[pcm_number]);
if (stream->status != MIXART_STREAM_STATUS_FREE){
/* streams in use */
- snd_printk(KERN_ERR "snd_mixart_capture_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
+ dev_err(chip->card->dev,
+ "snd_mixart_capture_open C%d/P%d/Sub%d in use\n",
+ chip->chip_idx, pcm_number, subs->number);
err = -EBUSY;
goto _exit_open;
}
@@ -815,7 +847,7 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs)
/* start the pipe if necessary */
err = mixart_set_pipe_state(chip->mgr, pipe, 1);
if( err < 0 ) {
- snd_printk(KERN_ERR "error starting pipe!\n");
+ dev_err(chip->card->dev, "error starting pipe!\n");
snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
err = -EINVAL;
goto _exit_open;
@@ -855,7 +887,8 @@ static int snd_mixart_close(struct snd_pcm_substream *subs)
mutex_lock(&mgr->setup_mutex);
- snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number);
+ dev_dbg(chip->card->dev, "snd_mixart_close C%d/P%d/Sub%d\n",
+ chip->chip_idx, stream->pcm_number, subs->number);
/* sample rate released */
if(--mgr->ref_count_rate == 0) {
@@ -865,7 +898,9 @@ static int snd_mixart_close(struct snd_pcm_substream *subs)
/* delete pipe */
if (snd_mixart_kill_ref_pipe(mgr, stream->pipe, 0 ) < 0) {
- snd_printk(KERN_ERR "error snd_mixart_kill_ref_pipe C%dP%d\n", chip->chip_idx, stream->pcm_number);
+ dev_err(chip->card->dev,
+ "error snd_mixart_kill_ref_pipe C%dP%d\n",
+ chip->chip_idx, stream->pcm_number);
}
stream->pipe = NULL;
@@ -940,7 +975,8 @@ static int snd_mixart_pcm_analog(struct snd_mixart *chip)
if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_ANALOG,
MIXART_PLAYBACK_STREAMS,
MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
- snd_printk(KERN_ERR "cannot create the analog pcm %d\n", chip->chip_idx);
+ dev_err(chip->card->dev,
+ "cannot create the analog pcm %d\n", chip->chip_idx);
return err;
}
@@ -971,7 +1007,8 @@ static int snd_mixart_pcm_digital(struct snd_mixart *chip)
if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL,
MIXART_PLAYBACK_STREAMS,
MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
- snd_printk(KERN_ERR "cannot create the digital pcm %d\n", chip->chip_idx);
+ dev_err(chip->card->dev,
+ "cannot create the digital pcm %d\n", chip->chip_idx);
return err;
}
@@ -1014,7 +1051,7 @@ static int snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *card, int
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (! chip) {
- snd_printk(KERN_ERR "cannot allocate chip\n");
+ dev_err(card->dev, "cannot allocate chip\n");
return -ENOMEM;
}
@@ -1028,8 +1065,6 @@ static int snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *card, int
}
mgr->chip[idx] = chip;
- snd_card_set_dev(card, &mgr->pci->dev);
-
return 0;
}
@@ -1073,7 +1108,7 @@ static int snd_mixart_free(struct mixart_mgr *mgr)
/* reset board if some firmware was loaded */
if(mgr->dsp_loaded) {
snd_mixart_reset_board(mgr);
- snd_printdd("reset miXart !\n");
+ dev_dbg(&mgr->pci->dev, "reset miXart !\n");
}
/* release the i/o ports */
@@ -1234,7 +1269,8 @@ static int snd_mixart_probe(struct pci_dev *pci,
/* check if we can restrict PCI DMA transfers to 32 bits */
if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
- snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n");
+ dev_err(&pci->dev,
+ "architecture does not support 32bit PCI busmaster DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -1260,7 +1296,7 @@ static int snd_mixart_probe(struct pci_dev *pci,
mgr->mem[i].phys = pci_resource_start(pci, i);
mgr->mem[i].virt = pci_ioremap_bar(pci, i);
if (!mgr->mem[i].virt) {
- printk(KERN_ERR "unable to remap resource 0x%lx\n",
+ dev_err(&pci->dev, "unable to remap resource 0x%lx\n",
mgr->mem[i].phys);
snd_mixart_free(mgr);
return -EBUSY;
@@ -1269,7 +1305,7 @@ static int snd_mixart_probe(struct pci_dev *pci,
if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED,
KBUILD_MODNAME, mgr)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq);
snd_mixart_free(mgr);
return -EBUSY;
}
@@ -1308,10 +1344,11 @@ static int snd_mixart_probe(struct pci_dev *pci,
else
idx = index[dev] + i;
snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : "MIXART", i);
- err = snd_card_create(idx, tmpid, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, idx, tmpid, THIS_MODULE,
+ 0, &card);
if (err < 0) {
- snd_printk(KERN_ERR "cannot allocate the card %d\n", i);
+ dev_err(&pci->dev, "cannot allocate the card %d\n", i);
snd_mixart_free(mgr);
return err;
}
diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
index 3df0f530f67c..71f4bdcc4055 100644
--- a/sound/pci/mixart/mixart_core.c
+++ b/sound/pci/mixart/mixart_core.c
@@ -22,6 +22,7 @@
#include <linux/interrupt.h>
#include <linux/mutex.h>
+#include <linux/pci.h>
#include <asm/io.h>
#include <sound/core.h>
@@ -94,7 +95,8 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp,
if( (size < MSG_DESCRIPTOR_SIZE) || (resp->size < (size - MSG_DESCRIPTOR_SIZE))) {
err = -EINVAL;
- snd_printk(KERN_ERR "problem with response size = %d\n", size);
+ dev_err(&mgr->pci->dev,
+ "problem with response size = %d\n", size);
goto _clean_exit;
}
size -= MSG_DESCRIPTOR_SIZE;
@@ -161,7 +163,7 @@ static int send_msg( struct mixart_mgr *mgr,
headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_HEAD));
if (tailptr == headptr) {
- snd_printk(KERN_ERR "error: no message frame available\n");
+ dev_err(&mgr->pci->dev, "error: no message frame available\n");
return -EBUSY;
}
@@ -265,7 +267,8 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int
if (! timeout) {
/* error - no ack */
mutex_unlock(&mgr->msg_mutex);
- snd_printk(KERN_ERR "error: no response on msg %x\n", msg_frame);
+ dev_err(&mgr->pci->dev,
+ "error: no response on msg %x\n", msg_frame);
return -EIO;
}
@@ -278,7 +281,7 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int
err = get_msg(mgr, &resp, msg_frame);
if( request->message_id != resp.message_id )
- snd_printk(KERN_ERR "RESPONSE ERROR!\n");
+ dev_err(&mgr->pci->dev, "RESPONSE ERROR!\n");
mutex_unlock(&mgr->msg_mutex);
return err;
@@ -321,7 +324,8 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr,
if (! timeout) {
/* error - no ack */
mutex_unlock(&mgr->msg_mutex);
- snd_printk(KERN_ERR "error: notification %x not received\n", notif_event);
+ dev_err(&mgr->pci->dev,
+ "error: notification %x not received\n", notif_event);
return -EIO;
}
@@ -378,7 +382,9 @@ void snd_mixart_msg_tasklet(unsigned long arg)
resp.size = sizeof(mixart_msg_data);
err = get_msg(mgr, &resp, addr);
if( err < 0 ) {
- snd_printk(KERN_ERR "tasklet: error(%d) reading mf %x\n", err, msg);
+ dev_err(&mgr->pci->dev,
+ "tasklet: error(%d) reading mf %x\n",
+ err, msg);
break;
}
@@ -388,10 +394,13 @@ void snd_mixart_msg_tasklet(unsigned long arg)
case MSG_STREAM_STOP_INPUT_STAGE_PACKET:
case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET:
if(mixart_msg_data[0])
- snd_printk(KERN_ERR "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", mixart_msg_data[0]);
+ dev_err(&mgr->pci->dev,
+ "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n",
+ mixart_msg_data[0]);
break;
default:
- snd_printdd("tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n",
+ dev_dbg(&mgr->pci->dev,
+ "tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n",
msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size);
break;
}
@@ -401,7 +410,9 @@ void snd_mixart_msg_tasklet(unsigned long arg)
case MSG_TYPE_COMMAND:
/* get_msg() necessary */
default:
- snd_printk(KERN_ERR "tasklet doesn't know what to do with message %x\n", msg);
+ dev_err(&mgr->pci->dev,
+ "tasklet doesn't know what to do with message %x\n",
+ msg);
} /* switch type */
/* decrement counter */
@@ -451,7 +462,9 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
resp.size = sizeof(mixart_msg_data);
err = get_msg(mgr, &resp, msg & ~MSG_TYPE_MASK);
if( err < 0 ) {
- snd_printk(KERN_ERR "interrupt: error(%d) reading mf %x\n", err, msg);
+ dev_err(&mgr->pci->dev,
+ "interrupt: error(%d) reading mf %x\n",
+ err, msg);
break;
}
@@ -472,7 +485,8 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
struct mixart_stream *stream;
if ((chip_number >= mgr->num_cards) || (pcm_number >= MIXART_PCM_TOTAL) || (sub_number >= MIXART_PLAYBACK_STREAMS)) {
- snd_printk(KERN_ERR "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n",
+ dev_err(&mgr->pci->dev,
+ "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n",
buffer_id, notify->streams[i].sample_pos_low_part);
break;
}
@@ -524,18 +538,22 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
}
#endif
((char*)mixart_msg_data)[resp.size - 1] = 0;
- snd_printdd("MIXART TRACE : %s\n", (char*)mixart_msg_data);
+ dev_dbg(&mgr->pci->dev,
+ "MIXART TRACE : %s\n",
+ (char *)mixart_msg_data);
}
break;
}
- snd_printdd("command %x not handled\n", resp.message_id);
+ dev_dbg(&mgr->pci->dev, "command %x not handled\n",
+ resp.message_id);
break;
case MSG_TYPE_NOTIFY:
if(msg & MSG_CANCEL_NOTIFY_MASK) {
msg &= ~MSG_CANCEL_NOTIFY_MASK;
- snd_printk(KERN_ERR "canceled notification %x !\n", msg);
+ dev_err(&mgr->pci->dev,
+ "canceled notification %x !\n", msg);
}
/* no break, continue ! */
case MSG_TYPE_ANSWER:
@@ -556,7 +574,8 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
break;
case MSG_TYPE_REQUEST:
default:
- snd_printdd("interrupt received request %x\n", msg);
+ dev_dbg(&mgr->pci->dev,
+ "interrupt received request %x\n", msg);
/* TODO : are there things to do here ? */
break;
} /* switch on msg type */
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
index ece1f831c16a..581e1e74863c 100644
--- a/sound/pci/mixart/mixart_hwdep.c
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -165,7 +165,8 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr)
err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
- snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");
+ dev_err(&mgr->pci->dev,
+ "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");
err = -EINVAL;
goto __error;
}
@@ -184,7 +185,7 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr)
pipe->uid_left_connector = connector->uid[k]; /* even */
}
- /* snd_printk(KERN_DEBUG "playback connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
+ /* dev_dbg(&mgr->pci->dev, "playback connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
@@ -194,10 +195,11 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr)
err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
if( err < 0 ) {
- snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
+ dev_err(&mgr->pci->dev,
+ "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
goto __error;
}
- /*snd_printk(KERN_DEBUG "play analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
+ /*dev_dbg(&mgr->pci->dev, "play analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
}
request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR;
@@ -207,7 +209,8 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr)
err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
- snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");
+ dev_err(&mgr->pci->dev,
+ "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");
err = -EINVAL;
goto __error;
}
@@ -226,7 +229,7 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr)
pipe->uid_left_connector = connector->uid[k]; /* even */
}
- /* snd_printk(KERN_DEBUG "capture connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
+ /* dev_dbg(&mgr->pci->dev, "capture connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
@@ -236,10 +239,11 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr)
err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
if( err < 0 ) {
- snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
+ dev_err(&mgr->pci->dev,
+ "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
goto __error;
}
- /*snd_printk(KERN_DEBUG "rec analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
+ /*dev_dbg(&mgr->pci->dev, "rec analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
}
err = 0;
@@ -272,7 +276,9 @@ static int mixart_enum_physio(struct mixart_mgr *mgr)
err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr);
if( (err < 0) || (console_mgr.error_code != 0) ) {
- snd_printk(KERN_DEBUG "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n", console_mgr.error_code);
+ dev_dbg(&mgr->pci->dev,
+ "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n",
+ console_mgr.error_code);
return -EINVAL;
}
@@ -286,7 +292,9 @@ static int mixart_enum_physio(struct mixart_mgr *mgr)
err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io);
if( (err < 0) || ( phys_io.error_code != 0 ) ) {
- snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n", err, phys_io.error_code );
+ dev_err(&mgr->pci->dev,
+ "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n",
+ err, phys_io.error_code);
return -EINVAL;
}
@@ -322,7 +330,7 @@ static int mixart_first_init(struct mixart_mgr *mgr)
/* this command has no data. response is a 32 bit status */
err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k);
if( (err < 0) || (k != 0) ) {
- snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n");
+ dev_err(&mgr->pci->dev, "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n");
return err == 0 ? -EINVAL : err;
}
@@ -348,7 +356,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* motherboard xilinx status 5 will say that the board is performing a reset */
if (status_xilinx == 5) {
- snd_printk(KERN_ERR "miXart is resetting !\n");
+ dev_err(&mgr->pci->dev, "miXart is resetting !\n");
return -EAGAIN; /* try again later */
}
@@ -357,12 +365,13 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* xilinx already loaded ? */
if (status_xilinx == 4) {
- snd_printk(KERN_DEBUG "xilinx is already loaded !\n");
+ dev_dbg(&mgr->pci->dev, "xilinx is already loaded !\n");
return 0;
}
/* the status should be 0 == "idle" */
if (status_xilinx != 0) {
- snd_printk(KERN_ERR "xilinx load error ! status = %d\n",
+ dev_err(&mgr->pci->dev,
+ "xilinx load error ! status = %d\n",
status_xilinx);
return -EIO; /* modprob -r may help ? */
}
@@ -393,13 +402,14 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
case MIXART_MOTHERBOARD_ELF_INDEX:
if (status_elf == 4) {
- snd_printk(KERN_DEBUG "elf file already loaded !\n");
+ dev_dbg(&mgr->pci->dev, "elf file already loaded !\n");
return 0;
}
/* the status should be 0 == "idle" */
if (status_elf != 0) {
- snd_printk(KERN_ERR "elf load error ! status = %d\n",
+ dev_err(&mgr->pci->dev,
+ "elf load error ! status = %d\n",
status_elf);
return -EIO; /* modprob -r may help ? */
}
@@ -407,7 +417,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* wait for xilinx status == 4 */
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */
if (err < 0) {
- snd_printk(KERN_ERR "xilinx was not loaded or "
+ dev_err(&mgr->pci->dev, "xilinx was not loaded or "
"could not be started\n");
return err;
}
@@ -429,7 +439,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* wait for elf status == 4 */
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */
if (err < 0) {
- snd_printk(KERN_ERR "elf could not be started\n");
+ dev_err(&mgr->pci->dev, "elf could not be started\n");
return err;
}
@@ -443,7 +453,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* elf and xilinx should be loaded */
if (status_elf != 4 || status_xilinx != 4) {
- printk(KERN_ERR "xilinx or elf not "
+ dev_err(&mgr->pci->dev, "xilinx or elf not "
"successfully loaded\n");
return -EIO; /* modprob -r may help ? */
}
@@ -451,7 +461,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* wait for daughter detection != 0 */
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */
if (err < 0) {
- snd_printk(KERN_ERR "error starting elf file\n");
+ dev_err(&mgr->pci->dev, "error starting elf file\n");
return err;
}
@@ -467,7 +477,8 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* daughter should be idle */
if (status_daught != 0) {
- printk(KERN_ERR "daughter load error ! status = %d\n",
+ dev_err(&mgr->pci->dev,
+ "daughter load error ! status = %d\n",
status_daught);
return -EIO; /* modprob -r may help ? */
}
@@ -487,7 +498,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* wait for status == 2 */
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */
if (err < 0) {
- snd_printk(KERN_ERR "daughter board load error\n");
+ dev_err(&mgr->pci->dev, "daughter board load error\n");
return err;
}
@@ -509,7 +520,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* wait for daughter status == 3 */
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */
if (err < 0) {
- snd_printk(KERN_ERR
+ dev_err(&mgr->pci->dev,
"daughter board could not be initialised\n");
return err;
}
@@ -520,7 +531,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* first communication with embedded */
err = mixart_first_init(mgr);
if (err < 0) {
- snd_printk(KERN_ERR "miXart could not be set up\n");
+ dev_err(&mgr->pci->dev, "miXart could not be set up\n");
return err;
}
@@ -540,7 +551,8 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
return err;
}
- snd_printdd("miXart firmware downloaded and successfully set up\n");
+ dev_dbg(&mgr->pci->dev,
+ "miXart firmware downloaded and successfully set up\n");
return 0;
}
@@ -559,7 +571,8 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
for (i = 0; i < 3; i++) {
sprintf(path, "mixart/%s", fw_files[i]);
if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
- snd_printk(KERN_ERR "miXart: can't load firmware %s\n", path);
+ dev_err(&mgr->pci->dev,
+ "miXart: can't load firmware %s\n", path);
return -ENOENT;
}
/* fake hwdep dsp record */
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c
index 3ba6174c3df1..24a1955b8c29 100644
--- a/sound/pci/mixart/mixart_mixer.c
+++ b/sound/pci/mixart/mixart_mixer.c
@@ -329,7 +329,9 @@ static int mixart_update_analog_audio_level(struct snd_mixart* chip, int is_capt
err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
if((err<0) || (resp.error_code)) {
- snd_printk(KERN_DEBUG "error MSG_PHYSICALIO_SET_LEVEL card(%d) is_capture(%d) error_code(%x)\n", chip->chip_idx, is_capture, resp.error_code);
+ dev_dbg(chip->card->dev,
+ "error MSG_PHYSICALIO_SET_LEVEL card(%d) is_capture(%d) error_code(%x)\n",
+ chip->chip_idx, is_capture, resp.error_code);
return -EINVAL;
}
return 0;
@@ -762,7 +764,9 @@ int mixart_update_playback_stream_level(struct snd_mixart* chip, int is_aes, int
err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status);
if((err<0) || status) {
- snd_printk(KERN_DEBUG "error MSG_STREAM_SET_OUT_STREAM_LEVEL card(%d) status(%x)\n", chip->chip_idx, status);
+ dev_dbg(chip->card->dev,
+ "error MSG_STREAM_SET_OUT_STREAM_LEVEL card(%d) status(%x)\n",
+ chip->chip_idx, status);
return -EINVAL;
}
return 0;
@@ -805,7 +809,9 @@ int mixart_update_capture_stream_level(struct snd_mixart* chip, int is_aes)
err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status);
if((err<0) || status) {
- snd_printk(KERN_DEBUG "error MSG_STREAM_SET_IN_AUDIO_LEVEL card(%d) status(%x)\n", chip->chip_idx, status);
+ dev_dbg(chip->card->dev,
+ "error MSG_STREAM_SET_IN_AUDIO_LEVEL card(%d) status(%x)\n",
+ chip->chip_idx, status);
return -EINVAL;
}
return 0;
@@ -977,7 +983,9 @@ static int mixart_update_monitoring(struct snd_mixart* chip, int channel)
err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
if((err<0) || resp) {
- snd_printk(KERN_DEBUG "error MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL card(%d) resp(%x)\n", chip->chip_idx, resp);
+ dev_dbg(chip->card->dev,
+ "error MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL card(%d) resp(%x)\n",
+ chip->chip_idx, resp);
return -EINVAL;
}
return 0;
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index fe79fff4c6dc..ddc60215cc10 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -318,7 +318,8 @@ snd_nm256_write_buffer(struct nm256 *chip, void *src, int offset, int size)
offset -= chip->buffer_start;
#ifdef CONFIG_SND_DEBUG
if (offset < 0 || offset >= chip->buffer_size) {
- snd_printk(KERN_ERR "write_buffer invalid offset = %d size = %d\n",
+ dev_err(chip->card->dev,
+ "write_buffer invalid offset = %d size = %d\n",
offset, size);
return;
}
@@ -366,7 +367,8 @@ snd_nm256_load_coefficient(struct nm256 *chip, int stream, int number)
NM_RECORD_REG_OFFSET : NM_PLAYBACK_REG_OFFSET);
if (snd_nm256_readb(chip, poffset) & 1) {
- snd_printd("NM256: Engine was enabled while loading coefficients!\n");
+ dev_dbg(chip->card->dev,
+ "NM256: Engine was enabled while loading coefficients!\n");
return;
}
@@ -466,7 +468,8 @@ static int snd_nm256_acquire_irq(struct nm256 *chip)
if (chip->irq < 0) {
if (request_irq(chip->pci->irq, chip->interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq);
+ dev_err(chip->card->dev,
+ "unable to grab IRQ %d\n", chip->pci->irq);
mutex_unlock(&chip->irq_mutex);
return -EBUSY;
}
@@ -1039,7 +1042,7 @@ snd_nm256_interrupt(int irq, void *dev_id)
if (status & NM_MISC_INT_1) {
status &= ~NM_MISC_INT_1;
NM_ACK_INT(chip, NM_MISC_INT_1);
- snd_printd("NM256: Got misc interrupt #1\n");
+ dev_dbg(chip->card->dev, "NM256: Got misc interrupt #1\n");
snd_nm256_writew(chip, NM_INT_REG, 0x8000);
cbyte = snd_nm256_readb(chip, 0x400);
snd_nm256_writeb(chip, 0x400, cbyte | 2);
@@ -1048,14 +1051,15 @@ snd_nm256_interrupt(int irq, void *dev_id)
if (status & NM_MISC_INT_2) {
status &= ~NM_MISC_INT_2;
NM_ACK_INT(chip, NM_MISC_INT_2);
- snd_printd("NM256: Got misc interrupt #2\n");
+ dev_dbg(chip->card->dev, "NM256: Got misc interrupt #2\n");
cbyte = snd_nm256_readb(chip, 0x400);
snd_nm256_writeb(chip, 0x400, cbyte & ~2);
}
/* Unknown interrupt. */
if (status) {
- snd_printd("NM256: Fire in the hole! Unknown status 0x%x\n",
+ dev_dbg(chip->card->dev,
+ "NM256: Fire in the hole! Unknown status 0x%x\n",
status);
/* Pray. */
NM_ACK_INT(chip, status);
@@ -1104,7 +1108,7 @@ snd_nm256_interrupt_zx(int irq, void *dev_id)
if (status & NM2_MISC_INT_1) {
status &= ~NM2_MISC_INT_1;
NM2_ACK_INT(chip, NM2_MISC_INT_1);
- snd_printd("NM256: Got misc interrupt #1\n");
+ dev_dbg(chip->card->dev, "NM256: Got misc interrupt #1\n");
cbyte = snd_nm256_readb(chip, 0x400);
snd_nm256_writeb(chip, 0x400, cbyte | 2);
}
@@ -1112,14 +1116,15 @@ snd_nm256_interrupt_zx(int irq, void *dev_id)
if (status & NM2_MISC_INT_2) {
status &= ~NM2_MISC_INT_2;
NM2_ACK_INT(chip, NM2_MISC_INT_2);
- snd_printd("NM256: Got misc interrupt #2\n");
+ dev_dbg(chip->card->dev, "NM256: Got misc interrupt #2\n");
cbyte = snd_nm256_readb(chip, 0x400);
snd_nm256_writeb(chip, 0x400, cbyte & ~2);
}
/* Unknown interrupt. */
if (status) {
- snd_printd("NM256: Fire in the hole! Unknown status 0x%x\n",
+ dev_dbg(chip->card->dev,
+ "NM256: Fire in the hole! Unknown status 0x%x\n",
status);
/* Pray. */
NM2_ACK_INT(chip, status);
@@ -1245,7 +1250,7 @@ snd_nm256_ac97_write(struct snd_ac97 *ac97,
return;
}
}
- snd_printd("nm256: ac97 codec not ready..\n");
+ dev_dbg(chip->card->dev, "nm256: ac97 codec not ready..\n");
}
/* static resolution table */
@@ -1347,7 +1352,8 @@ snd_nm256_peek_for_sig(struct nm256 *chip)
temp = ioremap_nocache(chip->buffer_addr + chip->buffer_end - 0x400, 16);
if (temp == NULL) {
- snd_printk(KERN_ERR "Unable to scan for card signature in video RAM\n");
+ dev_err(chip->card->dev,
+ "Unable to scan for card signature in video RAM\n");
return -EBUSY;
}
@@ -1361,12 +1367,14 @@ snd_nm256_peek_for_sig(struct nm256 *chip)
if (pointer == 0xffffffff ||
pointer < chip->buffer_size ||
pointer > chip->buffer_end) {
- snd_printk(KERN_ERR "invalid signature found: 0x%x\n", pointer);
+ dev_err(chip->card->dev,
+ "invalid signature found: 0x%x\n", pointer);
iounmap(temp);
return -ENODEV;
} else {
pointer_found = pointer;
- printk(KERN_INFO "nm256: found card signature in video RAM: 0x%x\n",
+ dev_info(chip->card->dev,
+ "found card signature in video RAM: 0x%x\n",
pointer);
}
}
@@ -1411,8 +1419,7 @@ static int nm256_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "nm256: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -1520,14 +1527,15 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
chip->res_cport = request_mem_region(chip->cport_addr, NM_PORT2_SIZE,
card->driver);
if (chip->res_cport == NULL) {
- snd_printk(KERN_ERR "memory region 0x%lx (size 0x%x) busy\n",
+ dev_err(card->dev, "memory region 0x%lx (size 0x%x) busy\n",
chip->cport_addr, NM_PORT2_SIZE);
err = -EBUSY;
goto __error;
}
chip->cport = ioremap_nocache(chip->cport_addr, NM_PORT2_SIZE);
if (chip->cport == NULL) {
- snd_printk(KERN_ERR "unable to map control port %lx\n", chip->cport_addr);
+ dev_err(card->dev, "unable to map control port %lx\n",
+ chip->cport_addr);
err = -ENOMEM;
goto __error;
}
@@ -1537,12 +1545,14 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
pval = snd_nm256_readw(chip, NM_MIXER_PRESENCE);
if ((pval & NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) {
if (! force_ac97) {
- printk(KERN_ERR "nm256: no ac97 is found!\n");
- printk(KERN_ERR " force the driver to load by "
- "passing in the module parameter\n");
- printk(KERN_ERR " force_ac97=1\n");
- printk(KERN_ERR " or try sb16, opl3sa2, or "
- "cs423x drivers instead.\n");
+ dev_err(card->dev,
+ "no ac97 is found!\n");
+ dev_err(card->dev,
+ "force the driver to load by passing in the module parameter\n");
+ dev_err(card->dev,
+ " force_ac97=1\n");
+ dev_err(card->dev,
+ "or try sb16, opl3sa2, or cs423x drivers instead.\n");
err = -ENXIO;
goto __error;
}
@@ -1581,14 +1591,14 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
chip->buffer_start = chip->buffer_end - chip->buffer_size;
chip->buffer_addr += chip->buffer_start;
- printk(KERN_INFO "nm256: Mapping port 1 from 0x%x - 0x%x\n",
+ dev_info(card->dev, "Mapping port 1 from 0x%x - 0x%x\n",
chip->buffer_start, chip->buffer_end);
chip->res_buffer = request_mem_region(chip->buffer_addr,
chip->buffer_size,
card->driver);
if (chip->res_buffer == NULL) {
- snd_printk(KERN_ERR "nm256: buffer 0x%lx (size 0x%x) busy\n",
+ dev_err(card->dev, "buffer 0x%lx (size 0x%x) busy\n",
chip->buffer_addr, chip->buffer_size);
err = -EBUSY;
goto __error;
@@ -1596,7 +1606,8 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
chip->buffer = ioremap_nocache(chip->buffer_addr, chip->buffer_size);
if (chip->buffer == NULL) {
err = -ENOMEM;
- snd_printk(KERN_ERR "unable to map ring buffer at %lx\n", chip->buffer_addr);
+ dev_err(card->dev, "unable to map ring buffer at %lx\n",
+ chip->buffer_addr);
goto __error;
}
@@ -1626,8 +1637,6 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
goto __error;
- snd_card_set_dev(card, &pci->dev);
-
*chip_ret = chip;
return 0;
@@ -1660,12 +1669,12 @@ static int snd_nm256_probe(struct pci_dev *pci,
q = snd_pci_quirk_lookup(pci, nm256_quirks);
if (q) {
- snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n",
+ dev_dbg(&pci->dev, "Enabled quirk for %s.\n",
snd_pci_quirk_name(q));
switch (q->value) {
case NM_BLACKLISTED:
- printk(KERN_INFO "nm256: The device is blacklisted. "
- "Loading stopped\n");
+ dev_info(&pci->dev,
+ "The device is blacklisted. Loading stopped\n");
return -ENODEV;
case NM_RESET_WORKAROUND_2:
reset_workaround_2 = 1;
@@ -1676,7 +1685,7 @@ static int snd_nm256_probe(struct pci_dev *pci,
}
}
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -1691,7 +1700,7 @@ static int snd_nm256_probe(struct pci_dev *pci,
strcpy(card->driver, "NM256XL+");
break;
default:
- snd_printk(KERN_ERR "invalid device id 0x%x\n", pci->device);
+ dev_err(&pci->dev, "invalid device id 0x%x\n", pci->device);
snd_card_free(card);
return -EINVAL;
}
@@ -1714,12 +1723,12 @@ static int snd_nm256_probe(struct pci_dev *pci,
card->private_data = chip;
if (reset_workaround) {
- snd_printdd(KERN_INFO "nm256: reset_workaround activated\n");
+ dev_dbg(&pci->dev, "reset_workaround activated\n");
chip->reset_workaround = 1;
}
if (reset_workaround_2) {
- snd_printdd(KERN_INFO "nm256: reset_workaround_2 activated\n");
+ dev_dbg(&pci->dev, "reset_workaround_2 activated\n");
chip->reset_workaround_2 = 1;
}
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c
index 3274907189fe..4b8a32c37e31 100644
--- a/sound/pci/oxygen/oxygen_io.c
+++ b/sound/pci/oxygen/oxygen_io.c
@@ -147,7 +147,7 @@ void oxygen_write_ac97(struct oxygen *chip, unsigned int codec,
return;
}
}
- snd_printk(KERN_ERR "AC'97 write timeout\n");
+ dev_err(chip->card->dev, "AC'97 write timeout\n");
}
EXPORT_SYMBOL(oxygen_write_ac97);
@@ -179,7 +179,7 @@ u16 oxygen_read_ac97(struct oxygen *chip, unsigned int codec,
reg ^= 0xffff;
}
}
- snd_printk(KERN_ERR "AC'97 read timeout on codec %u\n", codec);
+ dev_err(chip->card->dev, "AC'97 read timeout on codec %u\n", codec);
return 0;
}
EXPORT_SYMBOL(oxygen_read_ac97);
@@ -208,7 +208,7 @@ static int oxygen_wait_spi(struct oxygen *chip)
OXYGEN_SPI_BUSY) == 0)
return 0;
}
- snd_printk(KERN_ERR "oxygen: SPI wait timeout\n");
+ dev_err(chip->card->dev, "oxygen: SPI wait timeout\n");
return -EIO;
}
@@ -288,5 +288,5 @@ void oxygen_write_eeprom(struct oxygen *chip, unsigned int index, u16 value)
& OXYGEN_EEPROM_BUSY))
return;
}
- snd_printk(KERN_ERR "EEPROM write timeout\n");
+ dev_err(chip->card->dev, "EEPROM write timeout\n");
}
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index b0cb48adddc7..b67e30602473 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -313,7 +313,7 @@ static void oxygen_restore_eeprom(struct oxygen *chip,
oxygen_clear_bits8(chip, OXYGEN_MISC,
OXYGEN_MISC_WRITE_PCI_SUBID);
- snd_printk(KERN_INFO "EEPROM ID restored\n");
+ dev_info(chip->card->dev, "EEPROM ID restored\n");
}
}
@@ -595,7 +595,8 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
const struct pci_device_id *pci_id;
int err;
- err = snd_card_create(index, id, owner, sizeof(*chip), &card);
+ err = snd_card_new(&pci->dev, index, id, owner,
+ sizeof(*chip), &card);
if (err < 0)
return err;
@@ -616,13 +617,13 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
err = pci_request_regions(pci, DRIVER);
if (err < 0) {
- snd_printk(KERN_ERR "cannot reserve PCI resources\n");
+ dev_err(card->dev, "cannot reserve PCI resources\n");
goto err_pci_enable;
}
if (!(pci_resource_flags(pci, 0) & IORESOURCE_IO) ||
pci_resource_len(pci, 0) < OXYGEN_IO_SIZE) {
- snd_printk(KERN_ERR "invalid PCI I/O range\n");
+ dev_err(card->dev, "invalid PCI I/O range\n");
err = -ENXIO;
goto err_pci_regions;
}
@@ -648,7 +649,6 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
}
pci_set_master(pci);
- snd_card_set_dev(card, &pci->dev);
card->private_free = oxygen_card_free;
configure_pcie_bridge(pci);
@@ -658,7 +658,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip);
if (err < 0) {
- snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq);
+ dev_err(card->dev, "cannot grab interrupt %d\n", pci->irq);
goto err_card;
}
chip->irq = pci->irq;
@@ -796,7 +796,7 @@ static int oxygen_pci_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- snd_printk(KERN_ERR "cannot reenable device");
+ dev_err(dev, "cannot reenable device");
snd_card_disconnect(card);
return -EIO;
}
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index ed6f199f8a38..4cf3200e988b 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -238,11 +238,21 @@ void set_cs4245_adc_params(struct oxygen *chip,
cs4245_write_spi(chip, CS4245_MCLK_FREQ);
}
+static inline unsigned int shift_bits(unsigned int value,
+ unsigned int shift_from,
+ unsigned int shift_to,
+ unsigned int mask)
+{
+ if (shift_from < shift_to)
+ return (value << (shift_to - shift_from)) & mask;
+ else
+ return (value >> (shift_from - shift_to)) & mask;
+}
+
unsigned int adjust_dg_dac_routing(struct oxygen *chip,
unsigned int play_routing)
{
struct dg *data = chip->model_data;
- unsigned int routing = 0;
switch (data->output_sel) {
case PLAYBACK_DST_HP:
@@ -252,15 +262,23 @@ unsigned int adjust_dg_dac_routing(struct oxygen *chip,
OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK);
break;
case PLAYBACK_DST_MULTICH:
- routing = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
- (2 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
- (1 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
- (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK);
break;
}
- return routing;
+ return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
+ shift_bits(play_routing,
+ OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
+ OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
+ OXYGEN_PLAY_DAC1_SOURCE_MASK) |
+ shift_bits(play_routing,
+ OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
+ OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
+ OXYGEN_PLAY_DAC2_SOURCE_MASK) |
+ shift_bits(play_routing,
+ OXYGEN_PLAY_DAC0_SOURCE_SHIFT,
+ OXYGEN_PLAY_DAC3_SOURCE_SHIFT,
+ OXYGEN_PLAY_DAC3_SOURCE_MASK);
}
void dump_cs4245_registers(struct oxygen *chip,
diff --git a/sound/pci/oxygen/xonar_hdmi.c b/sound/pci/oxygen/xonar_hdmi.c
index 136dac6a3964..91d92bc32b75 100644
--- a/sound/pci/oxygen/xonar_hdmi.c
+++ b/sound/pci/oxygen/xonar_hdmi.c
@@ -120,7 +120,7 @@ void xonar_hdmi_uart_input(struct oxygen *chip)
if (chip->uart_input_count >= 2 &&
chip->uart_input[chip->uart_input_count - 2] == 'O' &&
chip->uart_input[chip->uart_input_count - 1] == 'K') {
- printk(KERN_DEBUG "message from HDMI chip received:\n");
+ dev_dbg(chip->card->dev, "message from HDMI chip received:\n");
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
chip->uart_input, chip->uart_input_count);
chip->uart_input_count = 0;
diff --git a/sound/pci/oxygen/xonar_lib.c b/sound/pci/oxygen/xonar_lib.c
index 0ebe7f5916f9..706b1a42163f 100644
--- a/sound/pci/oxygen/xonar_lib.c
+++ b/sound/pci/oxygen/xonar_lib.c
@@ -56,9 +56,9 @@ static void xonar_ext_power_gpio_changed(struct oxygen *chip)
if (has_power != data->has_power) {
data->has_power = has_power;
if (has_power) {
- snd_printk(KERN_NOTICE "power restored\n");
+ dev_notice(chip->card->dev, "power restored\n");
} else {
- snd_printk(KERN_CRIT
+ dev_crit(chip->card->dev,
"Hey! Don't unplug the power cable!\n");
/* TODO: stop PCMs */
}
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index d379b284955b..8d09444ff88b 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -284,7 +284,7 @@ static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate,
rmh.cmd_len = 3;
err = pcxhr_send_msg(mgr, &rmh);
if (err < 0) {
- snd_printk(KERN_ERR
+ dev_err(&mgr->pci->dev,
"error CMD_ACCESS_IO_WRITE "
"for PLL register : %x!\n", err);
return err;
@@ -357,7 +357,7 @@ static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr,
return err;
}
/* set the new frequency */
- snd_printdd("clock register : set %x\n", val);
+ dev_dbg(&mgr->pci->dev, "clock register : set %x\n", val);
err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK,
val, changed);
if (err)
@@ -380,7 +380,7 @@ static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr,
mgr->codec_speed = speed; /* save new codec speed */
}
- snd_printdd("pcxhr_sub_set_clock to %dHz (realfreq=%d)\n",
+ dev_dbg(&mgr->pci->dev, "pcxhr_sub_set_clock to %dHz (realfreq=%d)\n",
rate, realfreq);
return 0;
}
@@ -480,7 +480,7 @@ static int pcxhr_sub_get_external_clock(struct pcxhr_mgr *mgr,
case REG_STATUS_SYNC_192000 : rate = 192000; break;
default: rate = 0;
}
- snd_printdd("External clock is at %d Hz\n", rate);
+ dev_dbg(&mgr->pci->dev, "External clock is at %d Hz\n", rate);
*sample_rate = rate;
return 0;
}
@@ -537,8 +537,8 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream)
err = pcxhr_send_msg(chip->mgr, &rmh);
if (err)
- snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n",
- err);
+ dev_err(chip->card->dev,
+ "ERROR pcxhr_set_stream_state err=%x;\n", err);
stream->status =
start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED;
return err;
@@ -628,7 +628,8 @@ static int pcxhr_set_format(struct pcxhr_stream *stream)
rmh.cmd[rmh.cmd_len++] = (header & 0xff) << 16;
err = pcxhr_send_msg(chip->mgr, &rmh);
if (err)
- snd_printk(KERN_ERR "ERROR pcxhr_set_format err=%x;\n", err);
+ dev_err(chip->card->dev,
+ "ERROR pcxhr_set_format err=%x;\n", err);
return err;
}
@@ -665,7 +666,7 @@ static int pcxhr_update_r_buffer(struct pcxhr_stream *stream)
rmh.cmd_len = 4;
err = pcxhr_send_msg(chip->mgr, &rmh);
if (err)
- snd_printk(KERN_ERR
+ dev_err(chip->card->dev,
"ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err);
return err;
}
@@ -735,11 +736,11 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
}
if (capture_mask == 0 && playback_mask == 0) {
mutex_unlock(&mgr->setup_mutex);
- snd_printk(KERN_ERR "pcxhr_trigger_tasklet : no pipes\n");
+ dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : no pipes\n");
return;
}
- snd_printdd("pcxhr_trigger_tasklet : "
+ dev_dbg(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
"playback_mask=%x capture_mask=%x\n",
playback_mask, capture_mask);
@@ -747,7 +748,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0);
if (err) {
mutex_unlock(&mgr->setup_mutex);
- snd_printk(KERN_ERR "pcxhr_trigger_tasklet : "
+ dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
"error stop pipes (P%x C%x)\n",
playback_mask, capture_mask);
return;
@@ -792,7 +793,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
if (err) {
mutex_unlock(&mgr->setup_mutex);
- snd_printk(KERN_ERR "pcxhr_trigger_tasklet : "
+ dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
"error start pipes (P%x C%x)\n",
playback_mask, capture_mask);
return;
@@ -825,7 +826,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
#ifdef CONFIG_SND_DEBUG_VERBOSE
do_gettimeofday(&my_tv2);
- snd_printdd("***TRIGGER TASKLET*** TIME = %ld (err = %x)\n",
+ dev_dbg(&mgr->pci->dev, "***TRIGGER TASKLET*** TIME = %ld (err = %x)\n",
(long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
#endif
}
@@ -902,7 +903,7 @@ static int pcxhr_hardware_timer(struct pcxhr_mgr *mgr, int start)
}
err = pcxhr_send_msg(mgr, &rmh);
if (err < 0)
- snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n",
+ dev_err(&mgr->pci->dev, "error pcxhr_hardware_timer err(%x)\n",
err);
return err;
}
@@ -916,7 +917,8 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs)
struct pcxhr_mgr *mgr = chip->mgr;
int err = 0;
- snd_printdd("pcxhr_prepare : period_size(%lx) periods(%x) buffer_size(%lx)\n",
+ dev_dbg(chip->card->dev,
+ "pcxhr_prepare : period_size(%lx) periods(%x) buffer_size(%lx)\n",
subs->runtime->period_size, subs->runtime->periods,
subs->runtime->buffer_size);
@@ -1025,11 +1027,11 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
runtime->hw = pcxhr_caps;
if( subs->stream == SNDRV_PCM_STREAM_PLAYBACK ) {
- snd_printdd("pcxhr_open playback chip%d subs%d\n",
+ dev_dbg(chip->card->dev, "pcxhr_open playback chip%d subs%d\n",
chip->chip_idx, subs->number);
stream = &chip->playback_stream[subs->number];
} else {
- snd_printdd("pcxhr_open capture chip%d subs%d\n",
+ dev_dbg(chip->card->dev, "pcxhr_open capture chip%d subs%d\n",
chip->chip_idx, subs->number);
if (mgr->mono_capture)
runtime->hw.channels_max = 1;
@@ -1039,7 +1041,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
}
if (stream->status != PCXHR_STREAM_STATUS_FREE){
/* streams in use */
- snd_printk(KERN_ERR "pcxhr_open chip%d subs%d in use\n",
+ dev_err(chip->card->dev, "pcxhr_open chip%d subs%d in use\n",
chip->chip_idx, subs->number);
mutex_unlock(&mgr->setup_mutex);
return -EBUSY;
@@ -1105,7 +1107,7 @@ static int pcxhr_close(struct snd_pcm_substream *subs)
mutex_lock(&mgr->setup_mutex);
- snd_printdd("pcxhr_close chip%d subs%d\n",
+ dev_dbg(chip->card->dev, "pcxhr_close chip%d subs%d\n",
chip->chip_idx, subs->number);
/* sample rate released */
@@ -1168,7 +1170,7 @@ int pcxhr_create_pcm(struct snd_pcxhr *chip)
if ((err = snd_pcm_new(chip->card, name, 0,
chip->nb_streams_play,
chip->nb_streams_capt, &pcm)) < 0) {
- snd_printk(KERN_ERR "cannot create pcm %s\n", name);
+ dev_err(chip->card->dev, "cannot create pcm %s\n", name);
return err;
}
pcm->private_data = chip;
@@ -1214,7 +1216,7 @@ static int pcxhr_create(struct pcxhr_mgr *mgr,
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (! chip) {
- snd_printk(KERN_ERR "cannot allocate chip\n");
+ dev_err(card->dev, "cannot allocate chip\n");
return -ENOMEM;
}
@@ -1239,7 +1241,6 @@ static int pcxhr_create(struct pcxhr_mgr *mgr,
}
mgr->chip[idx] = chip;
- snd_card_set_dev(card, &mgr->pci->dev);
return 0;
}
@@ -1488,7 +1489,7 @@ static int pcxhr_free(struct pcxhr_mgr *mgr)
/* reset board if some firmware was loaded */
if(mgr->dsp_loaded) {
pcxhr_reset_board(mgr);
- snd_printdd("reset pcxhr !\n");
+ dev_dbg(&mgr->pci->dev, "reset pcxhr !\n");
}
/* release irq */
@@ -1537,8 +1538,8 @@ static int pcxhr_probe(struct pci_dev *pci,
/* check if we can restrict PCI DMA transfers to 32 bits */
if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
- snd_printk(KERN_ERR "architecture does not support "
- "32bit PCI busmaster DMA\n");
+ dev_err(&pci->dev,
+ "architecture does not support 32bit PCI busmaster DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -1589,7 +1590,7 @@ static int pcxhr_probe(struct pci_dev *pci,
if (request_irq(pci->irq, pcxhr_interrupt, IRQF_SHARED,
KBUILD_MODNAME, mgr)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq);
pcxhr_free(mgr);
return -EBUSY;
}
@@ -1638,10 +1639,11 @@ static int pcxhr_probe(struct pci_dev *pci,
snprintf(tmpid, sizeof(tmpid), "%s-%d",
id[dev] ? id[dev] : card_name, i);
- err = snd_card_create(idx, tmpid, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, idx, tmpid, THIS_MODULE,
+ 0, &card);
if (err < 0) {
- snd_printk(KERN_ERR "cannot allocate the card %d\n", i);
+ dev_err(card->dev, "cannot allocate the card %d\n", i);
pcxhr_free(mgr);
return err;
}
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index 37b431b9b69d..df9371918601 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/interrupt.h>
+#include <linux/pci.h>
#include <asm/io.h>
#include <sound/core.h>
#include "pcxhr.h"
@@ -132,14 +133,14 @@ static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg,
*read = PCXHR_INPB(mgr, reg);
if ((*read & mask) == bit) {
if (i > 100)
- snd_printdd("ATTENTION! check_reg(%x) "
- "loopcount=%d\n",
+ dev_dbg(&mgr->pci->dev,
+ "ATTENTION! check_reg(%x) loopcount=%d\n",
reg, i);
return 0;
}
i++;
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_ERR
+ dev_err(&mgr->pci->dev,
"pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=%x\n",
reg, mask, *read);
return -EIO;
@@ -216,7 +217,7 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr,
err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_CVR, PCXHR_CVR_HI08_HC, 0,
PCXHR_TIMEOUT_DSP, &reg);
if (err) {
- snd_printk(KERN_ERR "pcxhr_send_it_dsp : TIMEOUT CVR\n");
+ dev_err(&mgr->pci->dev, "pcxhr_send_it_dsp : TIMEOUT CVR\n");
return err;
}
if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {
@@ -227,7 +228,7 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr,
PCXHR_TIMEOUT_DSP,
&reg);
if (err) {
- snd_printk(KERN_ERR
+ dev_err(&mgr->pci->dev,
"pcxhr_send_it_dsp : TIMEOUT HF5\n");
return err;
}
@@ -294,7 +295,7 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr,
*/
if(second) {
if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) {
- snd_printk(KERN_ERR "error loading first xilinx\n");
+ dev_err(&mgr->pci->dev, "error loading first xilinx\n");
return -EINVAL;
}
/* activate second xilinx */
@@ -360,7 +361,7 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp)
PCXHR_ISR_HI08_TRDY,
PCXHR_TIMEOUT_DSP, &dummy);
if (err) {
- snd_printk(KERN_ERR
+ dev_err(&mgr->pci->dev,
"dsp loading error at position %d\n", i);
return err;
}
@@ -396,7 +397,7 @@ int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr,
msleep(PCXHR_WAIT_DEFAULT);
PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
msleep(PCXHR_WAIT_DEFAULT);
- snd_printdd("no need to load eeprom boot\n");
+ dev_dbg(&mgr->pci->dev, "no need to load eeprom boot\n");
return 0;
}
PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);
@@ -561,9 +562,9 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
PCXHR_ISR_HI08_RXDF,
PCXHR_TIMEOUT_DSP, &reg);
if (err) {
- snd_printk(KERN_ERR "ERROR RMH stat: "
- "ISR:RXDF=1 (ISR = %x; i=%d )\n",
- reg, i);
+ dev_err(&mgr->pci->dev,
+ "ERROR RMH stat: ISR:RXDF=1 (ISR = %x; i=%d )\n",
+ reg, i);
return err;
}
/* read data */
@@ -591,13 +592,13 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
}
#ifdef CONFIG_SND_DEBUG_VERBOSE
if (rmh->cmd_idx < CMD_LAST_INDEX)
- snd_printdd(" stat[%d]=%x\n", i, data);
+ dev_dbg(&mgr->pci->dev, " stat[%d]=%x\n", i, data);
#endif
if (i < max_stat_len)
rmh->stat[i] = data;
}
if (rmh->stat_len > max_stat_len) {
- snd_printdd("PCXHR : rmh->stat_len=%x too big\n",
+ dev_dbg(&mgr->pci->dev, "PCXHR : rmh->stat_len=%x too big\n",
rmh->stat_len);
rmh->stat_len = max_stat_len;
}
@@ -615,7 +616,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
return -EINVAL;
err = pcxhr_send_it_dsp(mgr, PCXHR_IT_MESSAGE, 1);
if (err) {
- snd_printk(KERN_ERR "pcxhr_send_message : ED_DSP_CRASHED\n");
+ dev_err(&mgr->pci->dev,
+ "pcxhr_send_message : ED_DSP_CRASHED\n");
return err;
}
/* wait for chk bit */
@@ -641,7 +643,7 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
data &= 0xff7fff; /* MASK_1_WORD_COMMAND */
#ifdef CONFIG_SND_DEBUG_VERBOSE
if (rmh->cmd_idx < CMD_LAST_INDEX)
- snd_printdd("MSG cmd[0]=%x (%s)\n",
+ dev_dbg(&mgr->pci->dev, "MSG cmd[0]=%x (%s)\n",
data, cmd_names[rmh->cmd_idx]);
#endif
@@ -671,7 +673,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
data = rmh->cmd[i];
#ifdef CONFIG_SND_DEBUG_VERBOSE
if (rmh->cmd_idx < CMD_LAST_INDEX)
- snd_printdd(" cmd[%d]=%x\n", i, data);
+ dev_dbg(&mgr->pci->dev,
+ " cmd[%d]=%x\n", i, data);
#endif
err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR,
PCXHR_ISR_HI08_TRDY,
@@ -697,14 +700,15 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
PCXHR_ISR_HI08_RXDF,
PCXHR_TIMEOUT_DSP, &reg);
if (err) {
- snd_printk(KERN_ERR "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg);
+ dev_err(&mgr->pci->dev,
+ "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg);
return err;
}
/* read error code */
data = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16;
data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8;
data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL);
- snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n",
+ dev_err(&mgr->pci->dev, "ERROR RMH(%d): 0x%x\n",
rmh->cmd_idx, data);
err = -EINVAL;
} else {
@@ -780,7 +784,7 @@ static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr)
* (PCXHR_PIPE_STATE_CAPTURE_OFFSET)
*/
start_mask &= 0xffffff;
- snd_printdd("CMD_PIPE_STATE MBOX2=0x%06x\n", start_mask);
+ dev_dbg(&mgr->pci->dev, "CMD_PIPE_STATE MBOX2=0x%06x\n", start_mask);
return start_mask;
}
@@ -809,7 +813,7 @@ static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr,
}
err = pcxhr_send_msg(mgr, &rmh);
if (err) {
- snd_printk(KERN_ERR
+ dev_err(&mgr->pci->dev,
"error pipe start "
"(CMD_CAN_START_PIPE) err=%x!\n",
err);
@@ -847,7 +851,7 @@ static int pcxhr_stop_pipes(struct pcxhr_mgr *mgr, int audio_mask)
}
err = pcxhr_send_msg(mgr, &rmh);
if (err) {
- snd_printk(KERN_ERR
+ dev_err(&mgr->pci->dev,
"error pipe stop "
"(CMD_STOP_PIPE) err=%x!\n", err);
return err;
@@ -876,7 +880,7 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask)
1 << (audio - PCXHR_PIPE_STATE_CAPTURE_OFFSET));
err = pcxhr_send_msg(mgr, &rmh);
if (err) {
- snd_printk(KERN_ERR
+ dev_err(&mgr->pci->dev,
"error pipe start "
"(CMD_CONF_PIPE) err=%x!\n", err);
return err;
@@ -889,7 +893,7 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask)
pcxhr_init_rmh(&rmh, CMD_SEND_IRQA);
err = pcxhr_send_msg(mgr, &rmh);
if (err) {
- snd_printk(KERN_ERR
+ dev_err(&mgr->pci->dev,
"error pipe start (CMD_SEND_IRQA) err=%x!\n",
err);
return err;
@@ -913,7 +917,8 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
(capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET));
/* current pipe state (playback + record) */
state = pcxhr_pipes_running(mgr);
- snd_printdd("pcxhr_set_pipe_state %s (mask %x current %x)\n",
+ dev_dbg(&mgr->pci->dev,
+ "pcxhr_set_pipe_state %s (mask %x current %x)\n",
start ? "START" : "STOP", audio_mask, state);
if (start) {
/* start only pipes that are not yet started */
@@ -944,7 +949,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
if ((state & audio_mask) == (start ? audio_mask : 0))
break;
if (++i >= MAX_WAIT_FOR_DSP * 100) {
- snd_printk(KERN_ERR "error pipe start/stop\n");
+ dev_err(&mgr->pci->dev, "error pipe start/stop\n");
return -EBUSY;
}
udelay(10); /* wait 10 microseconds */
@@ -956,7 +961,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
}
#ifdef CONFIG_SND_DEBUG_VERBOSE
do_gettimeofday(&my_tv2);
- snd_printdd("***SET PIPE STATE*** TIME = %ld (err = %x)\n",
+ dev_dbg(&mgr->pci->dev, "***SET PIPE STATE*** TIME = %ld (err = %x)\n",
(long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
#endif
return 0;
@@ -971,7 +976,8 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
spin_lock_irqsave(&mgr->msg_lock, flags);
if ((mgr->io_num_reg_cont & mask) == value) {
- snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n",
+ dev_dbg(&mgr->pci->dev,
+ "IO_NUM_REG_CONT mask %x already is set to %x\n",
mask, value);
if (changed)
*changed = 0;
@@ -1024,7 +1030,7 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err,
err = ((err >> 12) & 0xfff);
if (!err)
return 0;
- snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n",
+ dev_dbg(&mgr->pci->dev, "CMD_ASYNC : Error %s %s Pipe %d err=%x\n",
err_src_name[err_src],
is_capture ? "Record" : "Play", pipe, err);
if (err == 0xe01)
@@ -1045,20 +1051,24 @@ void pcxhr_msg_tasklet(unsigned long arg)
int i, j;
if (mgr->src_it_dsp & PCXHR_IRQ_FREQ_CHANGE)
- snd_printdd("TASKLET : PCXHR_IRQ_FREQ_CHANGE event occurred\n");
+ dev_dbg(&mgr->pci->dev,
+ "TASKLET : PCXHR_IRQ_FREQ_CHANGE event occurred\n");
if (mgr->src_it_dsp & PCXHR_IRQ_TIME_CODE)
- snd_printdd("TASKLET : PCXHR_IRQ_TIME_CODE event occurred\n");
+ dev_dbg(&mgr->pci->dev,
+ "TASKLET : PCXHR_IRQ_TIME_CODE event occurred\n");
if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY)
- snd_printdd("TASKLET : PCXHR_IRQ_NOTIFY event occurred\n");
+ dev_dbg(&mgr->pci->dev,
+ "TASKLET : PCXHR_IRQ_NOTIFY event occurred\n");
if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) {
/* clear events FREQ_CHANGE and TIME_CODE */
pcxhr_init_rmh(prmh, CMD_TEST_IT);
err = pcxhr_send_msg(mgr, prmh);
- snd_printdd("CMD_TEST_IT : err=%x, stat=%x\n",
+ dev_dbg(&mgr->pci->dev, "CMD_TEST_IT : err=%x, stat=%x\n",
err, prmh->stat[0]);
}
if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) {
- snd_printdd("TASKLET : PCXHR_IRQ_ASYNC event occurred\n");
+ dev_dbg(&mgr->pci->dev,
+ "TASKLET : PCXHR_IRQ_ASYNC event occurred\n");
pcxhr_init_rmh(prmh, CMD_ASYNC);
prmh->cmd[0] |= 1; /* add SEL_ASYNC_EVENTS */
@@ -1066,7 +1076,7 @@ void pcxhr_msg_tasklet(unsigned long arg)
prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS;
err = pcxhr_send_msg(mgr, prmh);
if (err)
- snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n",
+ dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_tasklet=%x;\n",
err);
i = 1;
while (i < prmh->stat_len) {
@@ -1079,7 +1089,8 @@ void pcxhr_msg_tasklet(unsigned long arg)
u32 err2;
if (prmh->stat[i] & 0x800000) { /* if BIT_END */
- snd_printdd("TASKLET : End%sPipe %d\n",
+ dev_dbg(&mgr->pci->dev,
+ "TASKLET : End%sPipe %d\n",
is_capture ? "Record" : "Play",
pipe);
}
@@ -1136,7 +1147,8 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr,
hw_sample_count = ((u_int64_t)rmh.stat[0]) << 24;
hw_sample_count += (u_int64_t)rmh.stat[1];
- snd_printdd("stream %c%d : abs samples real(%llu) timer(%llu)\n",
+ dev_dbg(&mgr->pci->dev,
+ "stream %c%d : abs samples real(%llu) timer(%llu)\n",
stream->pipe->is_capture ? 'C' : 'P',
stream->substream->number,
hw_sample_count,
@@ -1202,7 +1214,7 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
(u_int32_t)(new_sample_count -
stream->timer_abs_periods);
} else {
- snd_printk(KERN_ERR
+ dev_err(&mgr->pci->dev,
"ERROR new_sample_count too small ??? %ld\n",
(long unsigned int)new_sample_count);
}
@@ -1247,33 +1259,39 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
(mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID)) {
/* handle dsp counter wraparound without resync */
int tmp_diff = dsp_time_diff + PCXHR_DSP_TIME_MASK + 1;
- snd_printdd("WARNING DSP timestamp old(%d) new(%d)",
+ dev_dbg(&mgr->pci->dev,
+ "WARNING DSP timestamp old(%d) new(%d)",
mgr->dsp_time_last, dsp_time_new);
if (tmp_diff > 0 && tmp_diff <= (2*mgr->granularity)) {
- snd_printdd("-> timestamp wraparound OK: "
+ dev_dbg(&mgr->pci->dev,
+ "-> timestamp wraparound OK: "
"diff=%d\n", tmp_diff);
dsp_time_diff = tmp_diff;
} else {
- snd_printdd("-> resynchronize all streams\n");
+ dev_dbg(&mgr->pci->dev,
+ "-> resynchronize all streams\n");
mgr->dsp_time_err++;
}
}
#ifdef CONFIG_SND_DEBUG_VERBOSE
if (dsp_time_diff == 0)
- snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n",
+ dev_dbg(&mgr->pci->dev,
+ "ERROR DSP TIME NO DIFF time(%d)\n",
dsp_time_new);
else if (dsp_time_diff >= (2*mgr->granularity))
- snd_printdd("ERROR DSP TIME TOO BIG old(%d) add(%d)\n",
+ dev_dbg(&mgr->pci->dev,
+ "ERROR DSP TIME TOO BIG old(%d) add(%d)\n",
mgr->dsp_time_last,
dsp_time_new - mgr->dsp_time_last);
else if (dsp_time_diff % mgr->granularity)
- snd_printdd("ERROR DSP TIME increased by %d\n",
+ dev_dbg(&mgr->pci->dev,
+ "ERROR DSP TIME increased by %d\n",
dsp_time_diff);
#endif
mgr->dsp_time_last = dsp_time_new;
if (timer_toggle == mgr->timer_toggle) {
- snd_printdd("ERROR TIMER TOGGLE\n");
+ dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n");
mgr->dsp_time_err++;
}
mgr->timer_toggle = timer_toggle;
@@ -1308,7 +1326,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
}
#ifdef CONFIG_SND_DEBUG_VERBOSE
if (reg & PCXHR_FATAL_DSP_ERR)
- snd_printdd("FATAL DSP ERROR : %x\n", reg);
+ dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg);
#endif
spin_unlock(&mgr->lock);
return IRQ_HANDLED; /* this device caused the interrupt */
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
index d995175c1c48..15a8ce5f1f48 100644
--- a/sound/pci/pcxhr/pcxhr_hwdep.c
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -72,7 +72,8 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr)
/* test max nb substream per pipe */
if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS)
return -EINVAL;
- snd_printdd("supported formats : playback=%x capture=%x\n",
+ dev_dbg(&mgr->pci->dev,
+ "supported formats : playback=%x capture=%x\n",
rmh.stat[2], rmh.stat[3]);
pcxhr_init_rmh(&rmh, CMD_VERSION);
@@ -84,7 +85,8 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr)
err = pcxhr_send_msg(mgr, &rmh);
if (err)
return err;
- snd_printdd("PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff,
+ dev_dbg(&mgr->pci->dev,
+ "PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff,
(rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff);
mgr->dsp_version = rmh.stat[0];
@@ -179,7 +181,7 @@ static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr,
stream_count = PCXHR_PLAYBACK_STREAMS;
audio_count = 2; /* always stereo */
}
- snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n",
+ dev_dbg(&mgr->pci->dev, "snd_add_ref_pipe pin(%d) pcm%c0\n",
pin, is_capture ? 'c' : 'p');
pipe->is_capture = is_capture;
pipe->first_audio = pin;
@@ -194,7 +196,7 @@ static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr,
}
err = pcxhr_send_msg(mgr, &rmh);
if (err < 0) {
- snd_printk(KERN_ERR "error pipe allocation "
+ dev_err(&mgr->pci->dev, "error pipe allocation "
"(CMD_RES_PIPE) err=%x!\n", err);
return err;
}
@@ -222,14 +224,14 @@ static int pcxhr_dsp_free_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe)
/* stop one pipe */
err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0);
if (err < 0)
- snd_printk(KERN_ERR "error stopping pipe!\n");
+ dev_err(&mgr->pci->dev, "error stopping pipe!\n");
/* release the pipe */
pcxhr_init_rmh(&rmh, CMD_FREE_PIPE);
pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio,
0, 0);
err = pcxhr_send_msg(mgr, &rmh);
if (err < 0)
- snd_printk(KERN_ERR "error pipe release "
+ dev_err(&mgr->pci->dev, "error pipe release "
"(CMD_FREE_PIPE) err(%x)\n", err);
pipe->status = PCXHR_PIPE_UNDEFINED;
return err;
@@ -289,7 +291,8 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index,
{
int err, card_index;
- snd_printdd("loading dsp [%d] size = %Zd\n", index, dsp->size);
+ dev_dbg(&mgr->pci->dev,
+ "loading dsp [%d] size = %Zd\n", index, dsp->size);
switch (index) {
case PCXHR_FIRMWARE_XLX_INT_INDEX:
@@ -313,19 +316,19 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index,
return err;
break; /* continue with first init */
default:
- snd_printk(KERN_ERR "wrong file index\n");
+ dev_err(&mgr->pci->dev, "wrong file index\n");
return -EFAULT;
} /* end of switch file index*/
/* first communication with embedded */
err = pcxhr_init_board(mgr);
if (err < 0) {
- snd_printk(KERN_ERR "pcxhr could not be set up\n");
+ dev_err(&mgr->pci->dev, "pcxhr could not be set up\n");
return err;
}
err = pcxhr_config_pipes(mgr);
if (err < 0) {
- snd_printk(KERN_ERR "pcxhr pipes could not be set up\n");
+ dev_err(&mgr->pci->dev, "pcxhr pipes could not be set up\n");
return err;
}
/* create devices and mixer in accordance with HW options*/
@@ -344,10 +347,11 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index,
}
err = pcxhr_start_pipes(mgr);
if (err < 0) {
- snd_printk(KERN_ERR "pcxhr pipes could not be started\n");
+ dev_err(&mgr->pci->dev, "pcxhr pipes could not be started\n");
return err;
}
- snd_printdd("pcxhr firmware downloaded and successfully set up\n");
+ dev_dbg(&mgr->pci->dev,
+ "pcxhr firmware downloaded and successfully set up\n");
return 0;
}
@@ -382,7 +386,8 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
continue;
sprintf(path, "pcxhr/%s", fw_files[fw_set][i]);
if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
- snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n",
+ dev_err(&mgr->pci->dev,
+ "pcxhr: can't load firmware %s\n",
path);
return -ENOENT;
}
diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c
index 84fe57626eba..6a56e5306a65 100644
--- a/sound/pci/pcxhr/pcxhr_mix22.c
+++ b/sound/pci/pcxhr/pcxhr_mix22.c
@@ -22,6 +22,7 @@
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/pci.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/tlv.h>
@@ -290,7 +291,8 @@ int hr222_sub_init(struct pcxhr_mgr *mgr)
reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS);
if (reg & PCXHR_STAT_MIC_CAPS)
mgr->board_has_mic = 1; /* microphone available */
- snd_printdd("MIC input available = %d\n", mgr->board_has_mic);
+ dev_dbg(&mgr->pci->dev,
+ "MIC input available = %d\n", mgr->board_has_mic);
/* reset codec */
PCXHR_OUTPB(mgr, PCXHR_DSP_RESET,
@@ -405,7 +407,7 @@ int hr222_sub_set_clock(struct pcxhr_mgr *mgr,
hr222_config_akm(mgr, AKM_UNMUTE_CMD);
- snd_printdd("set_clock to %dHz (realfreq=%d pllreg=%x)\n",
+ dev_dbg(&mgr->pci->dev, "set_clock to %dHz (realfreq=%d pllreg=%x)\n",
rate, realfreq, pllreg);
return 0;
}
@@ -431,13 +433,15 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr,
reg = PCXHR_STAT_FREQ_UER1_MASK;
} else {
- snd_printdd("get_external_clock : type %d not supported\n",
+ dev_dbg(&mgr->pci->dev,
+ "get_external_clock : type %d not supported\n",
clock_type);
return -EINVAL; /* other clocks not supported */
}
if ((PCXHR_INPB(mgr, PCXHR_XLX_CSUER) & mask) != mask) {
- snd_printdd("get_external_clock(%d) = 0 Hz\n", clock_type);
+ dev_dbg(&mgr->pci->dev,
+ "get_external_clock(%d) = 0 Hz\n", clock_type);
*sample_rate = 0;
return 0; /* no external clock locked */
}
@@ -495,7 +499,7 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr,
else
rate = 0;
- snd_printdd("External clock is at %d Hz (measured %d Hz)\n",
+ dev_dbg(&mgr->pci->dev, "External clock is at %d Hz (measured %d Hz)\n",
rate, calc_rate);
*sample_rate = rate;
return 0;
@@ -542,7 +546,8 @@ int hr222_manage_timecode(struct pcxhr_mgr *mgr, int enable)
int hr222_update_analog_audio_level(struct snd_pcxhr *chip,
int is_capture, int channel)
{
- snd_printdd("hr222_update_analog_audio_level(%s chan=%d)\n",
+ dev_dbg(chip->card->dev,
+ "hr222_update_analog_audio_level(%s chan=%d)\n",
is_capture ? "capture" : "playback", channel);
if (is_capture) {
int level_l, level_r, level_mic;
@@ -642,7 +647,7 @@ int hr222_iec958_capture_byte(struct snd_pcxhr *chip,
if (PCXHR_INPB(chip->mgr, PCXHR_XLX_CSUER) & mask)
temp |= 1;
}
- snd_printdd("read iec958 AES %d byte %d = 0x%x\n",
+ dev_dbg(chip->card->dev, "read iec958 AES %d byte %d = 0x%x\n",
chip->chip_idx, aes_idx, temp);
*aes_bits = temp;
return 0;
@@ -684,7 +689,7 @@ static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level)
PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic);
- snd_printdd("hr222_micro_boost : set %x\n", boost_mask);
+ dev_dbg(&mgr->pci->dev, "hr222_micro_boost : set %x\n", boost_mask);
}
static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power)
@@ -696,7 +701,7 @@ static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power)
PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic);
- snd_printdd("hr222_phantom_power : set %d\n", power);
+ dev_dbg(&mgr->pci->dev, "hr222_phantom_power : set %d\n", power);
}
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c
index fec049344621..95c9571780d8 100644
--- a/sound/pci/pcxhr/pcxhr_mixer.c
+++ b/sound/pci/pcxhr/pcxhr_mixer.c
@@ -72,7 +72,8 @@ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip,
rmh.cmd_len = 3;
err = pcxhr_send_msg(chip->mgr, &rmh);
if (err < 0) {
- snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d)"
+ dev_dbg(chip->card->dev,
+ "error update_analog_audio_level card(%d)"
" is_capture(%d) err(%x)\n",
chip->chip_idx, is_capture, err);
return -EINVAL;
@@ -284,7 +285,7 @@ static int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx)
err = pcxhr_send_msg(chip->mgr, &rmh);
if (err < 0) {
- snd_printk(KERN_DEBUG "error update_playback_stream_level "
+ dev_dbg(chip->card->dev, "error update_playback_stream_level "
"card(%d) err(%x)\n", chip->chip_idx, err);
return -EINVAL;
}
@@ -335,7 +336,8 @@ static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip,
err = pcxhr_send_msg(chip->mgr, &rmh);
if (err < 0) {
- snd_printk(KERN_DEBUG "error update_audio_level(%d) err=%x\n",
+ dev_dbg(chip->card->dev,
+ "error update_audio_level(%d) err=%x\n",
chip->chip_idx, err);
return -EINVAL;
}
@@ -930,7 +932,7 @@ static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip,
temp |= 1;
}
}
- snd_printdd("read iec958 AES %d byte %d = 0x%x\n",
+ dev_dbg(chip->card->dev, "read iec958 AES %d byte %d = 0x%x\n",
chip->chip_idx, aes_idx, temp);
*aes_bits = temp;
return 0;
@@ -992,7 +994,8 @@ static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip,
rmh.cmd[0] |= IO_NUM_REG_CUER;
rmh.cmd[1] = cmd;
rmh.cmd_len = 2;
- snd_printdd("write iec958 AES %d byte %d bit %d (cmd %x)\n",
+ dev_dbg(chip->card->dev,
+ "write iec958 AES %d byte %d bit %d (cmd %x)\n",
chip->chip_idx, aes_idx, i, cmd);
err = pcxhr_send_msg(chip->mgr, &rmh);
if (err)
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 56cc891e395e..b4a8278241b1 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -1916,8 +1916,6 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci,
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
return 0;
}
@@ -2086,7 +2084,8 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
err = snd_riptide_create(card, pci, &chip);
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index cc26346ae66b..cc2f0c1b6484 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -1349,14 +1349,15 @@ static int snd_rme32_create(struct rme32 *rme32)
rme32->iobase = ioremap_nocache(rme32->port, RME32_IO_SIZE);
if (!rme32->iobase) {
- snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n",
+ dev_err(rme32->card->dev,
+ "unable to remap memory region 0x%lx-0x%lx\n",
rme32->port, rme32->port + RME32_IO_SIZE - 1);
return -ENOMEM;
}
if (request_irq(pci->irq, snd_rme32_interrupt, IRQF_SHARED,
KBUILD_MODNAME, rme32)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(rme32->card->dev, "unable to grab IRQ %d\n", pci->irq);
return -EBUSY;
}
rme32->irq = pci->irq;
@@ -1938,15 +1939,14 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct rme32), &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct rme32), &card);
if (err < 0)
return err;
card->private_free = snd_rme32_card_free;
rme32 = (struct rme32 *) card->private_data;
rme32->card = card;
rme32->pci = pci;
- snd_card_set_dev(card, &pci->dev);
if (fullduplex[dev])
rme32->fullduplex_mode = 1;
if ((err = snd_rme32_create(rme32)) < 0) {
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 0236363c301f..76169929770d 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -240,7 +240,7 @@ struct rme96 {
u8 rev; /* card revision number */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
u32 playback_pointer;
u32 capture_pointer;
void *playback_suspend_buffer;
@@ -1570,7 +1570,7 @@ snd_rme96_free(void *private_data)
pci_release_regions(rme96->pci);
rme96->port = 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
vfree(rme96->playback_suspend_buffer);
vfree(rme96->capture_suspend_buffer);
#endif
@@ -1609,13 +1609,15 @@ snd_rme96_create(struct rme96 *rme96)
rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE);
if (!rme96->iobase) {
- snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme96->port, rme96->port + RME96_IO_SIZE - 1);
+ dev_err(rme96->card->dev,
+ "unable to remap memory region 0x%lx-0x%lx\n",
+ rme96->port, rme96->port + RME96_IO_SIZE - 1);
return -ENOMEM;
}
if (request_irq(pci->irq, snd_rme96_interrupt, IRQF_SHARED,
KBUILD_MODNAME, rme96)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(rme96->card->dev, "unable to grab IRQ %d\n", pci->irq);
return -EBUSY;
}
rme96->irq = pci->irq;
@@ -2372,13 +2374,12 @@ snd_rme96_create_switches(struct snd_card *card,
* Card initialisation
*/
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
-static int
-snd_rme96_suspend(struct pci_dev *pci,
- pm_message_t state)
+static int rme96_suspend(struct device *dev)
{
- struct snd_card *card = pci_get_drvdata(pci);
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
struct rme96 *rme96 = card->private_data;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
@@ -2407,15 +2408,15 @@ snd_rme96_suspend(struct pci_dev *pci,
return 0;
}
-static int
-snd_rme96_resume(struct pci_dev *pci)
+static int rme96_resume(struct device *dev)
{
- struct snd_card *card = pci_get_drvdata(pci);
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
struct rme96 *rme96 = card->private_data;
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "rme96: pci_enable_device failed, disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -2451,7 +2452,11 @@ snd_rme96_resume(struct pci_dev *pci)
return 0;
}
-#endif
+static SIMPLE_DEV_PM_OPS(rme96_pm, rme96_suspend, rme96_resume);
+#define RME96_PM_OPS &rme96_pm
+#else
+#define RME96_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
static void snd_rme96_card_free(struct snd_card *card)
{
@@ -2475,31 +2480,30 @@ snd_rme96_probe(struct pci_dev *pci,
dev++;
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct rme96), &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct rme96), &card);
if (err < 0)
return err;
card->private_free = snd_rme96_card_free;
rme96 = card->private_data;
rme96->card = card;
rme96->pci = pci;
- snd_card_set_dev(card, &pci->dev);
if ((err = snd_rme96_create(rme96)) < 0) {
snd_card_free(card);
return err;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
if (!rme96->playback_suspend_buffer) {
- snd_printk(KERN_ERR
+ dev_err(card->dev,
"Failed to allocate playback suspend buffer!\n");
snd_card_free(card);
return -ENOMEM;
}
rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
if (!rme96->capture_suspend_buffer) {
- snd_printk(KERN_ERR
+ dev_err(card->dev,
"Failed to allocate capture suspend buffer!\n");
snd_card_free(card);
return -ENOMEM;
@@ -2548,10 +2552,9 @@ static struct pci_driver rme96_driver = {
.id_table = snd_rme96_ids,
.probe = snd_rme96_probe,
.remove = snd_rme96_remove,
-#ifdef CONFIG_PM
- .suspend = snd_rme96_suspend,
- .resume = snd_rme96_resume,
-#endif
+ .driver = {
+ .pm = RME96_PM_OPS,
+ },
};
module_pci_driver(rme96_driver);
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index bd90c80bb494..4c6f5d1c9882 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -675,14 +675,15 @@ static int hdsp_check_for_iobox (struct hdsp *hdsp)
if (0 == (hdsp_read(hdsp, HDSP_statusRegister) &
HDSP_ConfigError)) {
if (i) {
- snd_printd("Hammerfall-DSP: IO box found after %d ms\n",
+ dev_dbg(hdsp->card->dev,
+ "IO box found after %d ms\n",
(20 * i));
}
return 0;
}
msleep(20);
}
- snd_printk(KERN_ERR "Hammerfall-DSP: no IO box connected!\n");
+ dev_err(hdsp->card->dev, "no IO box connected!\n");
hdsp->state &= ~HDSP_FirmwareLoaded;
return -EIO;
}
@@ -699,13 +700,13 @@ static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops,
if (hdsp_read(hdsp, HDSP_statusRegister) & HDSP_ConfigError)
msleep(delay);
else {
- snd_printd("Hammerfall-DSP: iobox found after %ums!\n",
+ dev_dbg(hdsp->card->dev, "iobox found after %ums!\n",
i * delay);
return 0;
}
}
- snd_printk("Hammerfall-DSP: no IO box connected!\n");
+ dev_info(hdsp->card->dev, "no IO box connected!\n");
hdsp->state &= ~HDSP_FirmwareLoaded;
return -EIO;
}
@@ -728,13 +729,14 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
- snd_printk ("Hammerfall-DSP: loading firmware\n");
+ dev_info(hdsp->card->dev, "loading firmware\n");
hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_PROGRAM);
hdsp_write (hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
- snd_printk ("Hammerfall-DSP: timeout waiting for download preparation\n");
+ dev_info(hdsp->card->dev,
+ "timeout waiting for download preparation\n");
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
return -EIO;
}
@@ -744,7 +746,8 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
for (i = 0; i < HDSP_FIRMWARE_SIZE / 4; ++i) {
hdsp_write(hdsp, HDSP_fifoData, cache[i]);
if (hdsp_fifo_wait (hdsp, 127, HDSP_LONG_WAIT)) {
- snd_printk ("Hammerfall-DSP: timeout during firmware loading\n");
+ dev_info(hdsp->card->dev,
+ "timeout during firmware loading\n");
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
return -EIO;
}
@@ -760,11 +763,12 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
hdsp->control2_register = 0;
#endif
hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register);
- snd_printk ("Hammerfall-DSP: finished firmware loading\n");
+ dev_info(hdsp->card->dev, "finished firmware loading\n");
}
if (hdsp->state & HDSP_InitializationComplete) {
- snd_printk(KERN_INFO "Hammerfall-DSP: firmware loaded from cache, restoring defaults\n");
+ dev_info(hdsp->card->dev,
+ "firmware loaded from cache, restoring defaults\n");
spin_lock_irqsave(&hdsp->lock, flags);
snd_hdsp_set_defaults(hdsp);
spin_unlock_irqrestore(&hdsp->lock, flags);
@@ -791,7 +795,7 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
hdsp_write (hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
hdsp->io_type = Multiface;
- snd_printk("Hammerfall-DSP: Multiface found\n");
+ dev_info(hdsp->card->dev, "Multiface found\n");
return 0;
}
@@ -799,7 +803,7 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
hdsp_write(hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) {
hdsp->io_type = Digiface;
- snd_printk("Hammerfall-DSP: Digiface found\n");
+ dev_info(hdsp->card->dev, "Digiface found\n");
return 0;
}
@@ -808,7 +812,7 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
hdsp_write(hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) {
hdsp->io_type = Multiface;
- snd_printk("Hammerfall-DSP: Multiface found\n");
+ dev_info(hdsp->card->dev, "Multiface found\n");
return 0;
}
@@ -817,12 +821,12 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
hdsp_write(hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
hdsp->io_type = Multiface;
- snd_printk("Hammerfall-DSP: Multiface found\n");
+ dev_info(hdsp->card->dev, "Multiface found\n");
return 0;
}
hdsp->io_type = RPM;
- snd_printk("Hammerfall-DSP: RPM found\n");
+ dev_info(hdsp->card->dev, "RPM found\n");
return 0;
} else {
/* firmware was already loaded, get iobox type */
@@ -847,20 +851,18 @@ static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand)
hdsp->state &= ~HDSP_FirmwareLoaded;
if (! load_on_demand)
return -EIO;
- snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n");
+ dev_err(hdsp->card->dev, "firmware not present.\n");
/* try to load firmware */
if (! (hdsp->state & HDSP_FirmwareCached)) {
if (! hdsp_request_fw_loader(hdsp))
return 0;
- snd_printk(KERN_ERR
- "Hammerfall-DSP: No firmware loaded nor "
- "cached, please upload firmware.\n");
+ dev_err(hdsp->card->dev,
+ "No firmware loaded nor cached, please upload firmware.\n");
return -EIO;
}
if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) {
- snd_printk(KERN_ERR
- "Hammerfall-DSP: Firmware loading from "
- "cache failed, please upload manually.\n");
+ dev_err(hdsp->card->dev,
+ "Firmware loading from cache failed, please upload manually.\n");
return -EIO;
}
}
@@ -888,7 +890,8 @@ static int hdsp_fifo_wait(struct hdsp *hdsp, int count, int timeout)
udelay (100);
}
- snd_printk ("Hammerfall-DSP: wait for FIFO status <= %d failed after %d iterations\n",
+ dev_warn(hdsp->card->dev,
+ "wait for FIFO status <= %d failed after %d iterations\n",
count, timeout);
return -1;
}
@@ -1005,7 +1008,9 @@ static int hdsp_spdif_sample_rate(struct hdsp *hdsp)
default:
break;
}
- snd_printk ("Hammerfall-DSP: unknown spdif frequency status; bits = 0x%x, status = 0x%x\n", rate_bits, status);
+ dev_warn(hdsp->card->dev,
+ "unknown spdif frequency status; bits = 0x%x, status = 0x%x\n",
+ rate_bits, status);
return 0;
}
@@ -1139,7 +1144,8 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
if (!(hdsp->control_register & HDSP_ClockModeMaster)) {
if (called_internally) {
/* request from ctl or card initialization */
- snd_printk(KERN_ERR "Hammerfall-DSP: device is not running as a clock master: cannot set sample rate.\n");
+ dev_err(hdsp->card->dev,
+ "device is not running as a clock master: cannot set sample rate.\n");
return -1;
} else {
/* hw_param request while in AutoSync mode */
@@ -1147,11 +1153,14 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
int spdif_freq = hdsp_spdif_sample_rate(hdsp);
if ((spdif_freq == external_freq*2) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1))
- snd_printk(KERN_INFO "Hammerfall-DSP: Detected ADAT in double speed mode\n");
+ dev_info(hdsp->card->dev,
+ "Detected ADAT in double speed mode\n");
else if (hdsp->io_type == H9632 && (spdif_freq == external_freq*4) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1))
- snd_printk(KERN_INFO "Hammerfall-DSP: Detected ADAT in quad speed mode\n");
+ dev_info(hdsp->card->dev,
+ "Detected ADAT in quad speed mode\n");
else if (rate != external_freq) {
- snd_printk(KERN_INFO "Hammerfall-DSP: No AutoSync source for requested rate\n");
+ dev_info(hdsp->card->dev,
+ "No AutoSync source for requested rate\n");
return -1;
}
}
@@ -1223,7 +1232,8 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
}
if (reject_if_open && (hdsp->capture_pid >= 0 || hdsp->playback_pid >= 0)) {
- snd_printk ("Hammerfall-DSP: cannot change speed mode (capture PID = %d, playback PID = %d)\n",
+ dev_warn(hdsp->card->dev,
+ "cannot change speed mode (capture PID = %d, playback PID = %d)\n",
hdsp->capture_pid,
hdsp->playback_pid);
return -EBUSY;
@@ -3785,7 +3795,8 @@ static int snd_hdsp_initialize_memory(struct hdsp *hdsp)
snd_hammerfall_get_buffer(hdsp->pci, &hdsp->playback_dma_buf, HDSP_DMA_AREA_BYTES) < 0) {
if (hdsp->capture_dma_buf.area)
snd_dma_free_pages(&hdsp->capture_dma_buf);
- printk(KERN_ERR "%s: no buffers available\n", hdsp->card_name);
+ dev_err(hdsp->card->dev,
+ "%s: no buffers available\n", hdsp->card_name);
return -ENOMEM;
}
@@ -4747,7 +4758,8 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
return err;
if (!(hdsp->state & HDSP_FirmwareLoaded)) {
- snd_printk(KERN_ERR "Hammerfall-DSP: firmware needs to be uploaded to the card.\n");
+ dev_err(hdsp->card->dev,
+ "firmware needs to be uploaded to the card.\n");
return -EINVAL;
}
@@ -4858,7 +4870,8 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
if (hdsp->state & (HDSP_FirmwareCached | HDSP_FirmwareLoaded))
return -EBUSY;
- snd_printk(KERN_INFO "Hammerfall-DSP: initializing firmware upload\n");
+ dev_info(hdsp->card->dev,
+ "initializing firmware upload\n");
firmware = (struct hdsp_firmware __user *)argp;
if (get_user(firmware_data, &firmware->firmware_data))
@@ -4893,7 +4906,8 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
snd_hdsp_initialize_midi_flush(hdsp);
if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) {
- snd_printk(KERN_ERR "Hammerfall-DSP: error creating alsa devices\n");
+ dev_err(hdsp->card->dev,
+ "error creating alsa devices\n");
return err;
}
}
@@ -4983,7 +4997,8 @@ static int snd_hdsp_enable_io (struct hdsp *hdsp)
int i;
if (hdsp_fifo_wait (hdsp, 0, 100)) {
- snd_printk(KERN_ERR "Hammerfall-DSP: enable_io fifo_wait failed\n");
+ dev_err(hdsp->card->dev,
+ "enable_io fifo_wait failed\n");
return -EIO;
}
@@ -5057,25 +5072,29 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp
int err;
if ((err = snd_hdsp_create_pcm(card, hdsp)) < 0) {
- snd_printk(KERN_ERR "Hammerfall-DSP: Error creating pcm interface\n");
+ dev_err(card->dev,
+ "Error creating pcm interface\n");
return err;
}
if ((err = snd_hdsp_create_midi(card, hdsp, 0)) < 0) {
- snd_printk(KERN_ERR "Hammerfall-DSP: Error creating first midi interface\n");
+ dev_err(card->dev,
+ "Error creating first midi interface\n");
return err;
}
if (hdsp->io_type == Digiface || hdsp->io_type == H9652) {
if ((err = snd_hdsp_create_midi(card, hdsp, 1)) < 0) {
- snd_printk(KERN_ERR "Hammerfall-DSP: Error creating second midi interface\n");
+ dev_err(card->dev,
+ "Error creating second midi interface\n");
return err;
}
}
if ((err = snd_hdsp_create_controls(card, hdsp)) < 0) {
- snd_printk(KERN_ERR "Hammerfall-DSP: Error creating ctl interface\n");
+ dev_err(card->dev,
+ "Error creating ctl interface\n");
return err;
}
@@ -5088,7 +5107,8 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp
hdsp->playback_substream = NULL;
if ((err = snd_hdsp_set_defaults(hdsp)) < 0) {
- snd_printk(KERN_ERR "Hammerfall-DSP: Error setting default values\n");
+ dev_err(card->dev,
+ "Error setting default values\n");
return err;
}
@@ -5098,7 +5118,8 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp
hdsp->port, hdsp->irq);
if ((err = snd_card_register(card)) < 0) {
- snd_printk(KERN_ERR "Hammerfall-DSP: error registering card\n");
+ dev_err(card->dev,
+ "error registering card\n");
return err;
}
hdsp->state |= HDSP_InitializationComplete;
@@ -5141,16 +5162,19 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp)
fwfile = "digiface_firmware_rev11.bin";
break;
default:
- snd_printk(KERN_ERR "Hammerfall-DSP: invalid io_type %d\n", hdsp->io_type);
+ dev_err(hdsp->card->dev,
+ "invalid io_type %d\n", hdsp->io_type);
return -EINVAL;
}
if (request_firmware(&fw, fwfile, &hdsp->pci->dev)) {
- snd_printk(KERN_ERR "Hammerfall-DSP: cannot load firmware %s\n", fwfile);
+ dev_err(hdsp->card->dev,
+ "cannot load firmware %s\n", fwfile);
return -ENOENT;
}
if (fw->size < HDSP_FIRMWARE_SIZE) {
- snd_printk(KERN_ERR "Hammerfall-DSP: too short firmware size %d (expected %d)\n",
+ dev_err(hdsp->card->dev,
+ "too short firmware size %d (expected %d)\n",
(int)fw->size, HDSP_FIRMWARE_SIZE);
return -EINVAL;
}
@@ -5167,13 +5191,15 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp)
return err;
if ((err = snd_hdsp_create_hwdep(hdsp->card, hdsp)) < 0) {
- snd_printk(KERN_ERR "Hammerfall-DSP: error creating hwdep device\n");
+ dev_err(hdsp->card->dev,
+ "error creating hwdep device\n");
return err;
}
snd_hdsp_initialize_channels(hdsp);
snd_hdsp_initialize_midi_flush(hdsp);
if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) {
- snd_printk(KERN_ERR "Hammerfall-DSP: error creating alsa devices\n");
+ dev_err(hdsp->card->dev,
+ "error creating alsa devices\n");
return err;
}
}
@@ -5249,13 +5275,14 @@ static int snd_hdsp_create(struct snd_card *card,
return err;
hdsp->port = pci_resource_start(pci, 0);
if ((hdsp->iobase = ioremap_nocache(hdsp->port, HDSP_IO_EXTENT)) == NULL) {
- snd_printk(KERN_ERR "Hammerfall-DSP: unable to remap region 0x%lx-0x%lx\n", hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1);
+ dev_err(hdsp->card->dev, "unable to remap region 0x%lx-0x%lx\n",
+ hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1);
return -EBUSY;
}
if (request_irq(pci->irq, snd_hdsp_interrupt, IRQF_SHARED,
KBUILD_MODNAME, hdsp)) {
- snd_printk(KERN_ERR "Hammerfall-DSP: unable to use IRQ %d\n", pci->irq);
+ dev_err(hdsp->card->dev, "unable to use IRQ %d\n", pci->irq);
return -EBUSY;
}
@@ -5281,17 +5308,20 @@ static int snd_hdsp_create(struct snd_card *card,
if userspace is not ready for
firmware upload
*/
- snd_printk(KERN_ERR "Hammerfall-DSP: couldn't get firmware from userspace. try using hdsploader\n");
+ dev_err(hdsp->card->dev,
+ "couldn't get firmware from userspace. try using hdsploader\n");
else
/* init is complete, we return */
return 0;
/* we defer initialization */
- snd_printk(KERN_INFO "Hammerfall-DSP: card initialization pending : waiting for firmware\n");
+ dev_info(hdsp->card->dev,
+ "card initialization pending : waiting for firmware\n");
if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0)
return err;
return 0;
} else {
- snd_printk(KERN_INFO "Hammerfall-DSP: Firmware already present, initializing card.\n");
+ dev_info(hdsp->card->dev,
+ "Firmware already present, initializing card.\n");
if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
hdsp->io_type = RPM;
else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
@@ -5375,8 +5405,8 @@ static int snd_hdsp_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct hdsp), &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct hdsp), &card);
if (err < 0)
return err;
@@ -5384,7 +5414,6 @@ static int snd_hdsp_probe(struct pci_dev *pci,
card->private_free = snd_hdsp_card_free;
hdsp->dev = dev;
hdsp->pci = pci;
- snd_card_set_dev(card, &pci->dev);
if ((err = snd_hdsp_create(card, hdsp)) < 0) {
snd_card_free(card);
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index e98dc008de0b..cb82b593473a 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -1651,9 +1651,8 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
just make a warning an remember setting
for future master mode switching */
- snd_printk(KERN_WARNING "HDSPM: "
- "Warning: device is not running "
- "as a clock master.\n");
+ dev_warn(hdspm->card->dev,
+ "Warning: device is not running as a clock master.\n");
not_set = 1;
} else {
@@ -1664,15 +1663,14 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
if (hdspm_autosync_ref(hdspm) ==
HDSPM_AUTOSYNC_FROM_NONE) {
- snd_printk(KERN_WARNING "HDSPM: "
- "Detected no Externel Sync \n");
+ dev_warn(hdspm->card->dev,
+ "Detected no Externel Sync\n");
not_set = 1;
} else if (rate != external_freq) {
- snd_printk(KERN_WARNING "HDSPM: "
- "Warning: No AutoSync source for "
- "requested rate\n");
+ dev_warn(hdspm->card->dev,
+ "Warning: No AutoSync source for requested rate\n");
not_set = 1;
}
}
@@ -1738,13 +1736,11 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
if (current_speed != target_speed
&& (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) {
- snd_printk
- (KERN_ERR "HDSPM: "
- "cannot change from %s speed to %s speed mode "
- "(capture PID = %d, playback PID = %d)\n",
- hdspm_speed_names[current_speed],
- hdspm_speed_names[target_speed],
- hdspm->capture_pid, hdspm->playback_pid);
+ dev_err(hdspm->card->dev,
+ "cannot change from %s speed to %s speed mode (capture PID = %d, playback PID = %d)\n",
+ hdspm_speed_names[current_speed],
+ hdspm_speed_names[target_speed],
+ hdspm->capture_pid, hdspm->playback_pid);
return -EBUSY;
}
@@ -5446,7 +5442,7 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
* 0 64 ~3998231 ~8191558
**/
/*
- snd_printk(KERN_INFO "snd_hdspm_interrupt %llu @ %llx\n",
+ dev_info(hdspm->card->dev, "snd_hdspm_interrupt %llu @ %llx\n",
now-hdspm->last_interrupt, status & 0xFFC0);
hdspm->last_interrupt = now;
*/
@@ -5583,7 +5579,7 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
spin_lock_irq(&hdspm->lock);
err = hdspm_set_rate(hdspm, params_rate(params), 0);
if (err < 0) {
- snd_printk(KERN_INFO "err on hdspm_set_rate: %d\n", err);
+ dev_info(hdspm->card->dev, "err on hdspm_set_rate: %d\n", err);
spin_unlock_irq(&hdspm->lock);
_snd_pcm_hw_param_setempty(params,
SNDRV_PCM_HW_PARAM_RATE);
@@ -5594,7 +5590,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
err = hdspm_set_interrupt_interval(hdspm,
params_period_size(params));
if (err < 0) {
- snd_printk(KERN_INFO "err on hdspm_set_interrupt_interval: %d\n", err);
+ dev_info(hdspm->card->dev,
+ "err on hdspm_set_interrupt_interval: %d\n", err);
_snd_pcm_hw_param_setempty(params,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
return err;
@@ -5610,7 +5607,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
err =
snd_pcm_lib_malloc_pages(substream, HDSPM_DMA_AREA_BYTES);
if (err < 0) {
- snd_printk(KERN_INFO "err on snd_pcm_lib_malloc_pages: %d\n", err);
+ dev_info(hdspm->card->dev,
+ "err on snd_pcm_lib_malloc_pages: %d\n", err);
return err;
}
@@ -5624,7 +5622,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
hdspm->playback_buffer =
(unsigned char *) substream->runtime->dma_area;
- snd_printdd("Allocated sample buffer for playback at %p\n",
+ dev_dbg(hdspm->card->dev,
+ "Allocated sample buffer for playback at %p\n",
hdspm->playback_buffer);
} else {
hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferIn,
@@ -5635,18 +5634,21 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
hdspm->capture_buffer =
(unsigned char *) substream->runtime->dma_area;
- snd_printdd("Allocated sample buffer for capture at %p\n",
+ dev_dbg(hdspm->card->dev,
+ "Allocated sample buffer for capture at %p\n",
hdspm->capture_buffer);
}
/*
- snd_printdd("Allocated sample buffer for %s at 0x%08X\n",
+ dev_dbg(hdspm->card->dev,
+ "Allocated sample buffer for %s at 0x%08X\n",
substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
"playback" : "capture",
snd_pcm_sgbuf_get_addr(substream, 0));
*/
/*
- snd_printdd("set_hwparams: %s %d Hz, %d channels, bs = %d\n",
+ dev_dbg(hdspm->card->dev,
+ "set_hwparams: %s %d Hz, %d channels, bs = %d\n",
substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
"playback" : "capture",
params_rate(params), params_channels(params),
@@ -5667,12 +5669,14 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
/* Switch to native float format if requested */
if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) {
if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT))
- snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE float format.\n");
+ dev_info(hdspm->card->dev,
+ "Switching to native 32bit LE float format.\n");
hdspm->control_register |= HDSPe_FLOAT_FORMAT;
} else if (SNDRV_PCM_FORMAT_S32_LE == params_format(params)) {
if (hdspm->control_register & HDSPe_FLOAT_FORMAT)
- snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE integer format.\n");
+ dev_info(hdspm->card->dev,
+ "Switching to native 32bit LE integer format.\n");
hdspm->control_register &= ~HDSPe_FLOAT_FORMAT;
}
@@ -5715,12 +5719,16 @@ static int snd_hdspm_channel_info(struct snd_pcm_substream *substream,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (snd_BUG_ON(info->channel >= hdspm->max_channels_out)) {
- snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel out of range (%d)\n", info->channel);
+ dev_info(hdspm->card->dev,
+ "snd_hdspm_channel_info: output channel out of range (%d)\n",
+ info->channel);
return -EINVAL;
}
if (hdspm->channel_map_out[info->channel] < 0) {
- snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel %d mapped out\n", info->channel);
+ dev_info(hdspm->card->dev,
+ "snd_hdspm_channel_info: output channel %d mapped out\n",
+ info->channel);
return -EINVAL;
}
@@ -5728,12 +5736,16 @@ static int snd_hdspm_channel_info(struct snd_pcm_substream *substream,
HDSPM_CHANNEL_BUFFER_BYTES;
} else {
if (snd_BUG_ON(info->channel >= hdspm->max_channels_in)) {
- snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel out of range (%d)\n", info->channel);
+ dev_info(hdspm->card->dev,
+ "snd_hdspm_channel_info: input channel out of range (%d)\n",
+ info->channel);
return -EINVAL;
}
if (hdspm->channel_map_in[info->channel] < 0) {
- snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel %d mapped out\n", info->channel);
+ dev_info(hdspm->card->dev,
+ "snd_hdspm_channel_info: input channel %d mapped out\n",
+ info->channel);
return -EINVAL;
}
@@ -6283,7 +6295,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
s = copy_to_user(argp, levels, sizeof(struct hdspm_peak_rms));
if (0 != s) {
- /* snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu
+ /* dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu
[Levels]\n", sizeof(struct hdspm_peak_rms), s);
*/
return -EFAULT;
@@ -6329,7 +6341,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
s = copy_to_user(argp, &ltc, sizeof(struct hdspm_ltc));
if (0 != s) {
/*
- snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */
+ dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */
return -EFAULT;
}
@@ -6494,11 +6506,13 @@ static int snd_hdspm_preallocate_memory(struct hdspm *hdspm)
wanted,
wanted);
if (err < 0) {
- snd_printdd("Could not preallocate %zd Bytes\n", wanted);
+ dev_dbg(hdspm->card->dev,
+ "Could not preallocate %zd Bytes\n", wanted);
return err;
} else
- snd_printdd(" Preallocated %zd Bytes\n", wanted);
+ dev_dbg(hdspm->card->dev,
+ " Preallocated %zd Bytes\n", wanted);
return 0;
}
@@ -6559,7 +6573,7 @@ static int snd_hdspm_create_alsa_devices(struct snd_card *card,
{
int err, i;
- snd_printdd("Create card...\n");
+ dev_dbg(card->dev, "Create card...\n");
err = snd_hdspm_create_pcm(card, hdspm);
if (err < 0)
return err;
@@ -6581,7 +6595,7 @@ static int snd_hdspm_create_alsa_devices(struct snd_card *card,
if (err < 0)
return err;
- snd_printdd("proc init...\n");
+ dev_dbg(card->dev, "proc init...\n");
snd_hdspm_proc_init(hdspm);
hdspm->system_sample_rate = -1;
@@ -6592,23 +6606,23 @@ static int snd_hdspm_create_alsa_devices(struct snd_card *card,
hdspm->capture_substream = NULL;
hdspm->playback_substream = NULL;
- snd_printdd("Set defaults...\n");
+ dev_dbg(card->dev, "Set defaults...\n");
err = snd_hdspm_set_defaults(hdspm);
if (err < 0)
return err;
- snd_printdd("Update mixer controls...\n");
+ dev_dbg(card->dev, "Update mixer controls...\n");
hdspm_update_simple_mixer_controls(hdspm);
- snd_printdd("Initializeing complete ???\n");
+ dev_dbg(card->dev, "Initializeing complete ???\n");
err = snd_card_register(card);
if (err < 0) {
- snd_printk(KERN_ERR "HDSPM: error registering card\n");
+ dev_err(card->dev, "error registering card\n");
return err;
}
- snd_printdd("... yes now\n");
+ dev_dbg(card->dev, "... yes now\n");
return 0;
}
@@ -6662,8 +6676,8 @@ static int snd_hdspm_create(struct snd_card *card,
hdspm->card_name = "RME MADI";
hdspm->midiPorts = 3;
} else {
- snd_printk(KERN_ERR
- "HDSPM: unknown firmware revision %x\n",
+ dev_err(card->dev,
+ "unknown firmware revision %x\n",
hdspm->firmware_rev);
return -ENODEV;
}
@@ -6682,36 +6696,35 @@ static int snd_hdspm_create(struct snd_card *card,
hdspm->port = pci_resource_start(pci, 0);
io_extent = pci_resource_len(pci, 0);
- snd_printdd("grabbed memory region 0x%lx-0x%lx\n",
+ dev_dbg(card->dev, "grabbed memory region 0x%lx-0x%lx\n",
hdspm->port, hdspm->port + io_extent - 1);
hdspm->iobase = ioremap_nocache(hdspm->port, io_extent);
if (!hdspm->iobase) {
- snd_printk(KERN_ERR "HDSPM: "
- "unable to remap region 0x%lx-0x%lx\n",
+ dev_err(card->dev, "unable to remap region 0x%lx-0x%lx\n",
hdspm->port, hdspm->port + io_extent - 1);
return -EBUSY;
}
- snd_printdd("remapped region (0x%lx) 0x%lx-0x%lx\n",
+ dev_dbg(card->dev, "remapped region (0x%lx) 0x%lx-0x%lx\n",
(unsigned long)hdspm->iobase, hdspm->port,
hdspm->port + io_extent - 1);
if (request_irq(pci->irq, snd_hdspm_interrupt,
IRQF_SHARED, KBUILD_MODNAME, hdspm)) {
- snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to use IRQ %d\n", pci->irq);
return -EBUSY;
}
- snd_printdd("use IRQ %d\n", pci->irq);
+ dev_dbg(card->dev, "use IRQ %d\n", pci->irq);
hdspm->irq = pci->irq;
- snd_printdd("kmalloc Mixer memory of %zd Bytes\n",
+ dev_dbg(card->dev, "kmalloc Mixer memory of %zd Bytes\n",
sizeof(struct hdspm_mixer));
hdspm->mixer = kzalloc(sizeof(struct hdspm_mixer), GFP_KERNEL);
if (!hdspm->mixer) {
- snd_printk(KERN_ERR "HDSPM: "
- "unable to kmalloc Mixer memory of %d Bytes\n",
+ dev_err(card->dev,
+ "unable to kmalloc Mixer memory of %d Bytes\n",
(int)sizeof(struct hdspm_mixer));
return -ENOMEM;
}
@@ -6780,14 +6793,14 @@ static int snd_hdspm_create(struct snd_card *card,
hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS;
if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) {
- snd_printk(KERN_INFO "HDSPM: AEB input board found\n");
+ dev_info(card->dev, "AEB input board found\n");
hdspm->ss_in_channels += 4;
hdspm->ds_in_channels += 4;
hdspm->qs_in_channels += 4;
}
if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) {
- snd_printk(KERN_INFO "HDSPM: AEB output board found\n");
+ dev_info(card->dev, "AEB output board found\n");
hdspm->ss_out_channels += 4;
hdspm->ds_out_channels += 4;
hdspm->qs_out_channels += 4;
@@ -6854,7 +6867,7 @@ static int snd_hdspm_create(struct snd_card *card,
if (NULL != hdspm->tco) {
hdspm_tco_write(hdspm);
}
- snd_printk(KERN_INFO "HDSPM: AIO/RayDAT TCO module found\n");
+ dev_info(card->dev, "AIO/RayDAT TCO module found\n");
} else {
hdspm->tco = NULL;
}
@@ -6869,7 +6882,7 @@ static int snd_hdspm_create(struct snd_card *card,
if (NULL != hdspm->tco) {
hdspm_tco_write(hdspm);
}
- snd_printk(KERN_INFO "HDSPM: MADI/AES TCO module found\n");
+ dev_info(card->dev, "MADI/AES TCO module found\n");
} else {
hdspm->tco = NULL;
}
@@ -6951,7 +6964,7 @@ static int snd_hdspm_create(struct snd_card *card,
}
}
- snd_printdd("create alsa devices.\n");
+ dev_dbg(card->dev, "create alsa devices.\n");
err = snd_hdspm_create_alsa_devices(card, hdspm);
if (err < 0)
return err;
@@ -7016,8 +7029,8 @@ static int snd_hdspm_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev],
- THIS_MODULE, sizeof(struct hdspm), &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev],
+ THIS_MODULE, sizeof(struct hdspm), &card);
if (err < 0)
return err;
@@ -7026,8 +7039,6 @@ static int snd_hdspm_probe(struct pci_dev *pci,
hdspm->dev = dev;
hdspm->pci = pci;
- snd_card_set_dev(card, &pci->dev);
-
err = snd_hdspm_create(card, hdspm);
if (err < 0) {
snd_card_free(card);
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index 1503ee3585fd..1d9be90f7748 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -394,7 +394,9 @@ static snd_pcm_uframes_t rme9652_hw_pointer(struct snd_rme9652 *rme9652)
if (offset < period_size) {
if (offset > rme9652->max_jitter) {
if (frag)
- printk(KERN_ERR "Unexpected hw_pointer position (bufid == 0): status: %x offset: %d\n", status, offset);
+ dev_err(rme9652->card->dev,
+ "Unexpected hw_pointer position (bufid == 0): status: %x offset: %d\n",
+ status, offset);
} else if (!frag)
return 0;
offset -= rme9652->max_jitter;
@@ -403,7 +405,9 @@ static snd_pcm_uframes_t rme9652_hw_pointer(struct snd_rme9652 *rme9652)
} else {
if (offset > period_size + rme9652->max_jitter) {
if (!frag)
- printk(KERN_ERR "Unexpected hw_pointer position (bufid == 1): status: %x offset: %d\n", status, offset);
+ dev_err(rme9652->card->dev,
+ "Unexpected hw_pointer position (bufid == 1): status: %x offset: %d\n",
+ status, offset);
} else if (frag)
return period_size;
offset -= rme9652->max_jitter;
@@ -769,7 +773,8 @@ static inline int rme9652_spdif_sample_rate(struct snd_rme9652 *s)
break;
default:
- snd_printk(KERN_ERR "%s: unknown S/PDIF input rate (bits = 0x%x)\n",
+ dev_err(s->card->dev,
+ "%s: unknown S/PDIF input rate (bits = 0x%x)\n",
s->card_name, rate_bits);
return 0;
break;
@@ -1790,7 +1795,8 @@ static int snd_rme9652_initialize_memory(struct snd_rme9652 *rme9652)
snd_hammerfall_get_buffer(rme9652->pci, &rme9652->playback_dma_buf, RME9652_DMA_AREA_BYTES) < 0) {
if (rme9652->capture_dma_buf.area)
snd_dma_free_pages(&rme9652->capture_dma_buf);
- printk(KERN_ERR "%s: no buffers available\n", rme9652->card_name);
+ dev_err(rme9652->card->dev,
+ "%s: no buffers available\n", rme9652->card_name);
return -ENOMEM;
}
@@ -2468,13 +2474,14 @@ static int snd_rme9652_create(struct snd_card *card,
rme9652->port = pci_resource_start(pci, 0);
rme9652->iobase = ioremap_nocache(rme9652->port, RME9652_IO_EXTENT);
if (rme9652->iobase == NULL) {
- snd_printk(KERN_ERR "unable to remap region 0x%lx-0x%lx\n", rme9652->port, rme9652->port + RME9652_IO_EXTENT - 1);
+ dev_err(card->dev, "unable to remap region 0x%lx-0x%lx\n",
+ rme9652->port, rme9652->port + RME9652_IO_EXTENT - 1);
return -EBUSY;
}
if (request_irq(pci->irq, snd_rme9652_interrupt, IRQF_SHARED,
KBUILD_MODNAME, rme9652)) {
- snd_printk(KERN_ERR "unable to request IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to request IRQ %d\n", pci->irq);
return -EBUSY;
}
rme9652->irq = pci->irq;
@@ -2587,8 +2594,8 @@ static int snd_rme9652_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_rme9652), &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_rme9652), &card);
if (err < 0)
return err;
@@ -2597,7 +2604,6 @@ static int snd_rme9652_probe(struct pci_dev *pci,
card->private_free = snd_rme9652_card_free;
rme9652->dev = dev;
rme9652->pci = pci;
- snd_card_set_dev(card, &pci->dev);
if ((err = snd_rme9652_create(card, rme9652, precise_ptr[dev])) < 0) {
snd_card_free(card);
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index e413b4e2c819..6b26b93e001d 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -1404,8 +1404,6 @@ static int sis_chip_create(struct snd_card *card,
if (rc)
goto error_out_cleanup;
- snd_card_set_dev(card, &pci->dev);
-
return 0;
error_out_cleanup:
@@ -1440,7 +1438,8 @@ static int snd_sis7019_probe(struct pci_dev *pci,
if (!codecs)
codecs = SIS_PRIMARY_CODEC_PRESENT;
- rc = snd_card_create(index, id, THIS_MODULE, sizeof(*sis), &card);
+ rc = snd_card_new(&pci->dev, index, id, THIS_MODULE,
+ sizeof(*sis), &card);
if (rc < 0)
goto error_out;
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 2a46bf98af30..2044dc742071 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -273,7 +273,7 @@ static inline void snd_sonicvibes_setdmaa(struct sonicvibes * sonic,
outl(count, sonic->dmaa_port + SV_DMA_COUNT0);
outb(0x18, sonic->dmaa_port + SV_DMA_MODE);
#if 0
- printk(KERN_DEBUG "program dmaa: addr = 0x%x, paddr = 0x%x\n",
+ dev_dbg(sonic->card->dev, "program dmaa: addr = 0x%x, paddr = 0x%x\n",
addr, inl(sonic->dmaa_port + SV_DMA_ADDR0));
#endif
}
@@ -289,7 +289,7 @@ static inline void snd_sonicvibes_setdmac(struct sonicvibes * sonic,
outl(count, sonic->dmac_port + SV_DMA_COUNT0);
outb(0x14, sonic->dmac_port + SV_DMA_MODE);
#if 0
- printk(KERN_DEBUG "program dmac: addr = 0x%x, paddr = 0x%x\n",
+ dev_dbg(sonic->card->dev, "program dmac: addr = 0x%x, paddr = 0x%x\n",
addr, inl(sonic->dmac_port + SV_DMA_ADDR0));
#endif
}
@@ -357,105 +357,105 @@ static unsigned char snd_sonicvibes_in(struct sonicvibes * sonic, unsigned char
#if 0
static void snd_sonicvibes_debug(struct sonicvibes * sonic)
{
- printk(KERN_DEBUG
- "SV REGS: INDEX = 0x%02x ", inb(SV_REG(sonic, INDEX)));
- printk(" STATUS = 0x%02x\n", inb(SV_REG(sonic, STATUS)));
- printk(KERN_DEBUG
- " 0x00: left input = 0x%02x ", snd_sonicvibes_in(sonic, 0x00));
- printk(" 0x20: synth rate low = 0x%02x\n", snd_sonicvibes_in(sonic, 0x20));
- printk(KERN_DEBUG
- " 0x01: right input = 0x%02x ", snd_sonicvibes_in(sonic, 0x01));
- printk(" 0x21: synth rate high = 0x%02x\n", snd_sonicvibes_in(sonic, 0x21));
- printk(KERN_DEBUG
- " 0x02: left AUX1 = 0x%02x ", snd_sonicvibes_in(sonic, 0x02));
- printk(" 0x22: ADC clock = 0x%02x\n", snd_sonicvibes_in(sonic, 0x22));
- printk(KERN_DEBUG
- " 0x03: right AUX1 = 0x%02x ", snd_sonicvibes_in(sonic, 0x03));
- printk(" 0x23: ADC alt rate = 0x%02x\n", snd_sonicvibes_in(sonic, 0x23));
- printk(KERN_DEBUG
- " 0x04: left CD = 0x%02x ", snd_sonicvibes_in(sonic, 0x04));
- printk(" 0x24: ADC pll M = 0x%02x\n", snd_sonicvibes_in(sonic, 0x24));
- printk(KERN_DEBUG
- " 0x05: right CD = 0x%02x ", snd_sonicvibes_in(sonic, 0x05));
- printk(" 0x25: ADC pll N = 0x%02x\n", snd_sonicvibes_in(sonic, 0x25));
- printk(KERN_DEBUG
- " 0x06: left line = 0x%02x ", snd_sonicvibes_in(sonic, 0x06));
- printk(" 0x26: Synth pll M = 0x%02x\n", snd_sonicvibes_in(sonic, 0x26));
- printk(KERN_DEBUG
- " 0x07: right line = 0x%02x ", snd_sonicvibes_in(sonic, 0x07));
- printk(" 0x27: Synth pll N = 0x%02x\n", snd_sonicvibes_in(sonic, 0x27));
- printk(KERN_DEBUG
- " 0x08: MIC = 0x%02x ", snd_sonicvibes_in(sonic, 0x08));
- printk(" 0x28: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x28));
- printk(KERN_DEBUG
- " 0x09: Game port = 0x%02x ", snd_sonicvibes_in(sonic, 0x09));
- printk(" 0x29: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x29));
- printk(KERN_DEBUG
- " 0x0a: left synth = 0x%02x ", snd_sonicvibes_in(sonic, 0x0a));
- printk(" 0x2a: MPU401 = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2a));
- printk(KERN_DEBUG
- " 0x0b: right synth = 0x%02x ", snd_sonicvibes_in(sonic, 0x0b));
- printk(" 0x2b: drive ctrl = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2b));
- printk(KERN_DEBUG
- " 0x0c: left AUX2 = 0x%02x ", snd_sonicvibes_in(sonic, 0x0c));
- printk(" 0x2c: SRS space = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2c));
- printk(KERN_DEBUG
- " 0x0d: right AUX2 = 0x%02x ", snd_sonicvibes_in(sonic, 0x0d));
- printk(" 0x2d: SRS center = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2d));
- printk(KERN_DEBUG
- " 0x0e: left analog = 0x%02x ", snd_sonicvibes_in(sonic, 0x0e));
- printk(" 0x2e: wave source = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2e));
- printk(KERN_DEBUG
- " 0x0f: right analog = 0x%02x ", snd_sonicvibes_in(sonic, 0x0f));
- printk(" 0x2f: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2f));
- printk(KERN_DEBUG
- " 0x10: left PCM = 0x%02x ", snd_sonicvibes_in(sonic, 0x10));
- printk(" 0x30: analog power = 0x%02x\n", snd_sonicvibes_in(sonic, 0x30));
- printk(KERN_DEBUG
- " 0x11: right PCM = 0x%02x ", snd_sonicvibes_in(sonic, 0x11));
- printk(" 0x31: analog power = 0x%02x\n", snd_sonicvibes_in(sonic, 0x31));
- printk(KERN_DEBUG
- " 0x12: DMA data format = 0x%02x ", snd_sonicvibes_in(sonic, 0x12));
- printk(" 0x32: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x32));
- printk(KERN_DEBUG
- " 0x13: P/C enable = 0x%02x ", snd_sonicvibes_in(sonic, 0x13));
- printk(" 0x33: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x33));
- printk(KERN_DEBUG
- " 0x14: U/D button = 0x%02x ", snd_sonicvibes_in(sonic, 0x14));
- printk(" 0x34: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x34));
- printk(KERN_DEBUG
- " 0x15: revision = 0x%02x ", snd_sonicvibes_in(sonic, 0x15));
- printk(" 0x35: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x35));
- printk(KERN_DEBUG
- " 0x16: ADC output ctrl = 0x%02x ", snd_sonicvibes_in(sonic, 0x16));
- printk(" 0x36: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x36));
- printk(KERN_DEBUG
- " 0x17: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x17));
- printk(" 0x37: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x37));
- printk(KERN_DEBUG
- " 0x18: DMA A upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x18));
- printk(" 0x38: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x38));
- printk(KERN_DEBUG
- " 0x19: DMA A lower cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x19));
- printk(" 0x39: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x39));
- printk(KERN_DEBUG
- " 0x1a: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x1a));
- printk(" 0x3a: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3a));
- printk(KERN_DEBUG
- " 0x1b: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x1b));
- printk(" 0x3b: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3b));
- printk(KERN_DEBUG
- " 0x1c: DMA C upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x1c));
- printk(" 0x3c: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3c));
- printk(KERN_DEBUG
- " 0x1d: DMA C upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x1d));
- printk(" 0x3d: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3d));
- printk(KERN_DEBUG
- " 0x1e: PCM rate low = 0x%02x ", snd_sonicvibes_in(sonic, 0x1e));
- printk(" 0x3e: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3e));
- printk(KERN_DEBUG
- " 0x1f: PCM rate high = 0x%02x ", snd_sonicvibes_in(sonic, 0x1f));
- printk(" 0x3f: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3f));
+ dev_dbg(sonic->card->dev,
+ "SV REGS: INDEX = 0x%02x STATUS = 0x%02x\n",
+ inb(SV_REG(sonic, INDEX)), inb(SV_REG(sonic, STATUS)));
+ dev_dbg(sonic->card->dev,
+ " 0x00: left input = 0x%02x 0x20: synth rate low = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x00), snd_sonicvibes_in(sonic, 0x20));
+ dev_dbg(sonic->card->dev,
+ " 0x01: right input = 0x%02x 0x21: synth rate high = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x01), snd_sonicvibes_in(sonic, 0x21));
+ dev_dbg(sonic->card->dev,
+ " 0x02: left AUX1 = 0x%02x 0x22: ADC clock = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x02), snd_sonicvibes_in(sonic, 0x22));
+ dev_dbg(sonic->card->dev,
+ " 0x03: right AUX1 = 0x%02x 0x23: ADC alt rate = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x03), snd_sonicvibes_in(sonic, 0x23));
+ dev_dbg(sonic->card->dev,
+ " 0x04: left CD = 0x%02x 0x24: ADC pll M = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x04), snd_sonicvibes_in(sonic, 0x24));
+ dev_dbg(sonic->card->dev,
+ " 0x05: right CD = 0x%02x 0x25: ADC pll N = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x05), snd_sonicvibes_in(sonic, 0x25));
+ dev_dbg(sonic->card->dev,
+ " 0x06: left line = 0x%02x 0x26: Synth pll M = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x06), snd_sonicvibes_in(sonic, 0x26));
+ dev_dbg(sonic->card->dev,
+ " 0x07: right line = 0x%02x 0x27: Synth pll N = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x07), snd_sonicvibes_in(sonic, 0x27));
+ dev_dbg(sonic->card->dev,
+ " 0x08: MIC = 0x%02x 0x28: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x08), snd_sonicvibes_in(sonic, 0x28));
+ dev_dbg(sonic->card->dev,
+ " 0x09: Game port = 0x%02x 0x29: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x09), snd_sonicvibes_in(sonic, 0x29));
+ dev_dbg(sonic->card->dev,
+ " 0x0a: left synth = 0x%02x 0x2a: MPU401 = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x0a), snd_sonicvibes_in(sonic, 0x2a));
+ dev_dbg(sonic->card->dev,
+ " 0x0b: right synth = 0x%02x 0x2b: drive ctrl = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x0b), snd_sonicvibes_in(sonic, 0x2b));
+ dev_dbg(sonic->card->dev,
+ " 0x0c: left AUX2 = 0x%02x 0x2c: SRS space = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x0c), snd_sonicvibes_in(sonic, 0x2c));
+ dev_dbg(sonic->card->dev,
+ " 0x0d: right AUX2 = 0x%02x 0x2d: SRS center = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x0d), snd_sonicvibes_in(sonic, 0x2d));
+ dev_dbg(sonic->card->dev,
+ " 0x0e: left analog = 0x%02x 0x2e: wave source = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x0e), snd_sonicvibes_in(sonic, 0x2e));
+ dev_dbg(sonic->card->dev,
+ " 0x0f: right analog = 0x%02x 0x2f: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x0f), snd_sonicvibes_in(sonic, 0x2f));
+ dev_dbg(sonic->card->dev,
+ " 0x10: left PCM = 0x%02x 0x30: analog power = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x10), snd_sonicvibes_in(sonic, 0x30));
+ dev_dbg(sonic->card->dev,
+ " 0x11: right PCM = 0x%02x 0x31: analog power = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x11), snd_sonicvibes_in(sonic, 0x31));
+ dev_dbg(sonic->card->dev,
+ " 0x12: DMA data format = 0x%02x 0x32: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x12), snd_sonicvibes_in(sonic, 0x32));
+ dev_dbg(sonic->card->dev,
+ " 0x13: P/C enable = 0x%02x 0x33: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x13), snd_sonicvibes_in(sonic, 0x33));
+ dev_dbg(sonic->card->dev,
+ " 0x14: U/D button = 0x%02x 0x34: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x14), snd_sonicvibes_in(sonic, 0x34));
+ dev_dbg(sonic->card->dev,
+ " 0x15: revision = 0x%02x 0x35: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x15), snd_sonicvibes_in(sonic, 0x35));
+ dev_dbg(sonic->card->dev,
+ " 0x16: ADC output ctrl = 0x%02x 0x36: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x16), snd_sonicvibes_in(sonic, 0x36));
+ dev_dbg(sonic->card->dev,
+ " 0x17: --- = 0x%02x 0x37: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x17), snd_sonicvibes_in(sonic, 0x37));
+ dev_dbg(sonic->card->dev,
+ " 0x18: DMA A upper cnt = 0x%02x 0x38: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x18), snd_sonicvibes_in(sonic, 0x38));
+ dev_dbg(sonic->card->dev,
+ " 0x19: DMA A lower cnt = 0x%02x 0x39: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x19), snd_sonicvibes_in(sonic, 0x39));
+ dev_dbg(sonic->card->dev,
+ " 0x1a: --- = 0x%02x 0x3a: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x1a), snd_sonicvibes_in(sonic, 0x3a));
+ dev_dbg(sonic->card->dev,
+ " 0x1b: --- = 0x%02x 0x3b: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x1b), snd_sonicvibes_in(sonic, 0x3b));
+ dev_dbg(sonic->card->dev,
+ " 0x1c: DMA C upper cnt = 0x%02x 0x3c: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x1c), snd_sonicvibes_in(sonic, 0x3c));
+ dev_dbg(sonic->card->dev,
+ " 0x1d: DMA C upper cnt = 0x%02x 0x3d: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x1d), snd_sonicvibes_in(sonic, 0x3d));
+ dev_dbg(sonic->card->dev,
+ " 0x1e: PCM rate low = 0x%02x 0x3e: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x1e), snd_sonicvibes_in(sonic, 0x3e));
+ dev_dbg(sonic->card->dev,
+ " 0x1f: PCM rate high = 0x%02x 0x3f: --- = 0x%02x\n",
+ snd_sonicvibes_in(sonic, 0x1f), snd_sonicvibes_in(sonic, 0x3f));
}
#endif
@@ -511,8 +511,10 @@ static void snd_sonicvibes_pll(unsigned int rate,
*res_m = m;
*res_n = n;
#if 0
- printk(KERN_DEBUG "metric = %i, xm = %i, xn = %i\n", metric, xm, xn);
- printk(KERN_DEBUG "pll: m = 0x%x, r = 0x%x, n = 0x%x\n", reg, m, r, n);
+ dev_dbg(sonic->card->dev,
+ "metric = %i, xm = %i, xn = %i\n", metric, xm, xn);
+ dev_dbg(sonic->card->dev,
+ "pll: m = 0x%x, r = 0x%x, n = 0x%x\n", reg, m, r, n);
#endif
}
@@ -624,7 +626,8 @@ static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id)
return IRQ_NONE;
if (status == 0xff) { /* failure */
outb(sonic->irqmask = ~0, SV_REG(sonic, IRQMASK));
- snd_printk(KERN_ERR "IRQ failure - interrupts disabled!!\n");
+ dev_err(sonic->card->dev,
+ "IRQ failure - interrupts disabled!!\n");
return IRQ_HANDLED;
}
if (sonic->pcm) {
@@ -1198,7 +1201,8 @@ static int snd_sonicvibes_create_gameport(struct sonicvibes *sonic)
sonic->gameport = gp = gameport_allocate_port();
if (!gp) {
- printk(KERN_ERR "sonicvibes: cannot allocate memory for gameport\n");
+ dev_err(sonic->card->dev,
+ "sonicvibes: cannot allocate memory for gameport\n");
return -ENOMEM;
}
@@ -1267,7 +1271,8 @@ static int snd_sonicvibes_create(struct snd_card *card,
/* check, if we can restrict PCI DMA transfers to 24 bits */
if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) {
- snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n");
+ dev_err(card->dev,
+ "architecture does not support 24bit PCI busmaster DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -1296,7 +1301,7 @@ static int snd_sonicvibes_create(struct snd_card *card,
if (request_irq(pci->irq, snd_sonicvibes_interrupt, IRQF_SHARED,
KBUILD_MODNAME, sonic)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_sonicvibes_free(sonic);
return -EBUSY;
}
@@ -1310,24 +1315,32 @@ static int snd_sonicvibes_create(struct snd_card *card,
if (!dmaa) {
dmaa = dmaio;
dmaio += 0x10;
- snd_printk(KERN_INFO "BIOS did not allocate DDMA channel A i/o, allocated at 0x%x\n", dmaa);
+ dev_info(card->dev,
+ "BIOS did not allocate DDMA channel A i/o, allocated at 0x%x\n",
+ dmaa);
}
if (!dmac) {
dmac = dmaio;
dmaio += 0x10;
- snd_printk(KERN_INFO "BIOS did not allocate DDMA channel C i/o, allocated at 0x%x\n", dmac);
+ dev_info(card->dev,
+ "BIOS did not allocate DDMA channel C i/o, allocated at 0x%x\n",
+ dmac);
}
pci_write_config_dword(pci, 0x40, dmaa);
pci_write_config_dword(pci, 0x48, dmac);
if ((sonic->res_dmaa = request_region(dmaa, 0x10, "S3 SonicVibes DDMA-A")) == NULL) {
snd_sonicvibes_free(sonic);
- snd_printk(KERN_ERR "unable to grab DDMA-A port at 0x%x-0x%x\n", dmaa, dmaa + 0x10 - 1);
+ dev_err(card->dev,
+ "unable to grab DDMA-A port at 0x%x-0x%x\n",
+ dmaa, dmaa + 0x10 - 1);
return -EBUSY;
}
if ((sonic->res_dmac = request_region(dmac, 0x10, "S3 SonicVibes DDMA-C")) == NULL) {
snd_sonicvibes_free(sonic);
- snd_printk(KERN_ERR "unable to grab DDMA-C port at 0x%x-0x%x\n", dmac, dmac + 0x10 - 1);
+ dev_err(card->dev,
+ "unable to grab DDMA-C port at 0x%x-0x%x\n",
+ dmac, dmac + 0x10 - 1);
return -EBUSY;
}
@@ -1392,8 +1405,6 @@ static int snd_sonicvibes_create(struct snd_card *card,
snd_sonicvibes_proc_init(sonic);
- snd_card_set_dev(card, &pci->dev);
-
*rsonic = sonic;
return 0;
}
@@ -1459,7 +1470,8 @@ static int snd_sonic_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
for (idx = 0; idx < 5; idx++) {
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index b3b588bc94c3..d852458caf38 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -89,7 +89,8 @@ static int snd_trident_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index fb0e1586a6f8..1272c18a2544 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -69,40 +69,40 @@ static void snd_trident_print_voice_regs(struct snd_trident *trident, int voice)
{
unsigned int val, tmp;
- printk(KERN_DEBUG "Trident voice %i:\n", voice);
+ dev_dbg(trident->card->dev, "Trident voice %i:\n", voice);
outb(voice, TRID_REG(trident, T4D_LFO_GC_CIR));
val = inl(TRID_REG(trident, CH_LBA));
- printk(KERN_DEBUG "LBA: 0x%x\n", val);
+ dev_dbg(trident->card->dev, "LBA: 0x%x\n", val);
val = inl(TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC));
- printk(KERN_DEBUG "GVSel: %i\n", val >> 31);
- printk(KERN_DEBUG "Pan: 0x%x\n", (val >> 24) & 0x7f);
- printk(KERN_DEBUG "Vol: 0x%x\n", (val >> 16) & 0xff);
- printk(KERN_DEBUG "CTRL: 0x%x\n", (val >> 12) & 0x0f);
- printk(KERN_DEBUG "EC: 0x%x\n", val & 0x0fff);
+ dev_dbg(trident->card->dev, "GVSel: %i\n", val >> 31);
+ dev_dbg(trident->card->dev, "Pan: 0x%x\n", (val >> 24) & 0x7f);
+ dev_dbg(trident->card->dev, "Vol: 0x%x\n", (val >> 16) & 0xff);
+ dev_dbg(trident->card->dev, "CTRL: 0x%x\n", (val >> 12) & 0x0f);
+ dev_dbg(trident->card->dev, "EC: 0x%x\n", val & 0x0fff);
if (trident->device != TRIDENT_DEVICE_ID_NX) {
val = inl(TRID_REG(trident, CH_DX_CSO_ALPHA_FMS));
- printk(KERN_DEBUG "CSO: 0x%x\n", val >> 16);
- printk("Alpha: 0x%x\n", (val >> 4) & 0x0fff);
- printk(KERN_DEBUG "FMS: 0x%x\n", val & 0x0f);
+ dev_dbg(trident->card->dev, "CSO: 0x%x\n", val >> 16);
+ dev_dbg(trident->card->dev, "Alpha: 0x%x\n", (val >> 4) & 0x0fff);
+ dev_dbg(trident->card->dev, "FMS: 0x%x\n", val & 0x0f);
val = inl(TRID_REG(trident, CH_DX_ESO_DELTA));
- printk(KERN_DEBUG "ESO: 0x%x\n", val >> 16);
- printk(KERN_DEBUG "Delta: 0x%x\n", val & 0xffff);
+ dev_dbg(trident->card->dev, "ESO: 0x%x\n", val >> 16);
+ dev_dbg(trident->card->dev, "Delta: 0x%x\n", val & 0xffff);
val = inl(TRID_REG(trident, CH_DX_FMC_RVOL_CVOL));
} else { // TRIDENT_DEVICE_ID_NX
val = inl(TRID_REG(trident, CH_NX_DELTA_CSO));
tmp = (val >> 24) & 0xff;
- printk(KERN_DEBUG "CSO: 0x%x\n", val & 0x00ffffff);
+ dev_dbg(trident->card->dev, "CSO: 0x%x\n", val & 0x00ffffff);
val = inl(TRID_REG(trident, CH_NX_DELTA_ESO));
tmp |= (val >> 16) & 0xff00;
- printk(KERN_DEBUG "Delta: 0x%x\n", tmp);
- printk(KERN_DEBUG "ESO: 0x%x\n", val & 0x00ffffff);
+ dev_dbg(trident->card->dev, "Delta: 0x%x\n", tmp);
+ dev_dbg(trident->card->dev, "ESO: 0x%x\n", val & 0x00ffffff);
val = inl(TRID_REG(trident, CH_NX_ALPHA_FMS_FMC_RVOL_CVOL));
- printk(KERN_DEBUG "Alpha: 0x%x\n", val >> 20);
- printk(KERN_DEBUG "FMS: 0x%x\n", (val >> 16) & 0x0f);
+ dev_dbg(trident->card->dev, "Alpha: 0x%x\n", val >> 20);
+ dev_dbg(trident->card->dev, "FMS: 0x%x\n", (val >> 16) & 0x0f);
}
- printk(KERN_DEBUG "FMC: 0x%x\n", (val >> 14) & 3);
- printk(KERN_DEBUG "RVol: 0x%x\n", (val >> 7) & 0x7f);
- printk(KERN_DEBUG "CVol: 0x%x\n", val & 0x7f);
+ dev_dbg(trident->card->dev, "FMC: 0x%x\n", (val >> 14) & 3);
+ dev_dbg(trident->card->dev, "RVol: 0x%x\n", (val >> 7) & 0x7f);
+ dev_dbg(trident->card->dev, "CVol: 0x%x\n", val & 0x7f);
}
#endif
@@ -156,7 +156,8 @@ static unsigned short snd_trident_codec_read(struct snd_ac97 *ac97, unsigned sho
}
if (count == 0 && !trident->ac97_detect) {
- snd_printk(KERN_ERR "ac97 codec read TIMEOUT [0x%x/0x%x]!!!\n",
+ dev_err(trident->card->dev,
+ "ac97 codec read TIMEOUT [0x%x/0x%x]!!!\n",
reg, data);
data = 0;
}
@@ -497,16 +498,16 @@ void snd_trident_write_voice_regs(struct snd_trident * trident,
outl(regs[4], TRID_REG(trident, CH_START + 16));
#if 0
- printk(KERN_DEBUG "written %i channel:\n", voice->number);
- printk(KERN_DEBUG " regs[0] = 0x%x/0x%x\n",
+ dev_dbg(trident->card->dev, "written %i channel:\n", voice->number);
+ dev_dbg(trident->card->dev, " regs[0] = 0x%x/0x%x\n",
regs[0], inl(TRID_REG(trident, CH_START + 0)));
- printk(KERN_DEBUG " regs[1] = 0x%x/0x%x\n",
+ dev_dbg(trident->card->dev, " regs[1] = 0x%x/0x%x\n",
regs[1], inl(TRID_REG(trident, CH_START + 4)));
- printk(KERN_DEBUG " regs[2] = 0x%x/0x%x\n",
+ dev_dbg(trident->card->dev, " regs[2] = 0x%x/0x%x\n",
regs[2], inl(TRID_REG(trident, CH_START + 8)));
- printk(KERN_DEBUG " regs[3] = 0x%x/0x%x\n",
+ dev_dbg(trident->card->dev, " regs[3] = 0x%x/0x%x\n",
regs[3], inl(TRID_REG(trident, CH_START + 12)));
- printk(KERN_DEBUG " regs[4] = 0x%x/0x%x\n",
+ dev_dbg(trident->card->dev, " regs[4] = 0x%x/0x%x\n",
regs[4], inl(TRID_REG(trident, CH_START + 16)));
#endif
}
@@ -589,7 +590,7 @@ static void snd_trident_write_vol_reg(struct snd_trident * trident,
outb(voice->Vol >> 2, TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC + 2));
break;
case TRIDENT_DEVICE_ID_SI7018:
- /* printk(KERN_DEBUG "voice->Vol = 0x%x\n", voice->Vol); */
+ /* dev_dbg(trident->card->dev, "voice->Vol = 0x%x\n", voice->Vol); */
outw((voice->CTRL << 12) | voice->Vol,
TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC));
break;
@@ -3013,13 +3014,15 @@ static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device)
_ac97.num = 1;
err = snd_ac97_mixer(trident->ac97_bus, &_ac97, &trident->ac97_sec);
if (err < 0)
- snd_printk(KERN_ERR "SI7018: the secondary codec - invalid access\n");
+ dev_err(trident->card->dev,
+ "SI7018: the secondary codec - invalid access\n");
#if 0 // only for my testing purpose --jk
{
struct snd_ac97 *mc97;
err = snd_ac97_modem(trident->card, &_ac97, &mc97);
if (err < 0)
- snd_printk(KERN_ERR "snd_ac97_modem returned error %i\n", err);
+ dev_err(trident->card->dev,
+ "snd_ac97_modem returned error %i\n", err);
}
#endif
}
@@ -3197,7 +3200,8 @@ int snd_trident_create_gameport(struct snd_trident *chip)
chip->gameport = gp = gameport_allocate_port();
if (!gp) {
- printk(KERN_ERR "trident: cannot allocate memory for gameport\n");
+ dev_err(chip->card->dev,
+ "cannot allocate memory for gameport\n");
return -ENOMEM;
}
@@ -3270,7 +3274,8 @@ static int snd_trident_sis_reset(struct snd_trident *trident)
goto __si7018_ok;
do_delay(trident);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_ERR "AC'97 codec ready error [0x%x]\n", inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)));
+ dev_err(trident->card->dev, "AC'97 codec ready error [0x%x]\n",
+ inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)));
if (r-- > 0) {
end_time = jiffies + HZ;
do {
@@ -3367,7 +3372,7 @@ static int snd_trident_tlb_alloc(struct snd_trident *trident)
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci),
2 * SNDRV_TRIDENT_MAX_PAGES * 4, &trident->tlb.buffer) < 0) {
- snd_printk(KERN_ERR "trident: unable to allocate TLB buffer\n");
+ dev_err(trident->card->dev, "unable to allocate TLB buffer\n");
return -ENOMEM;
}
trident->tlb.entries = (unsigned int*)ALIGN((unsigned long)trident->tlb.buffer.area, SNDRV_TRIDENT_MAX_PAGES * 4);
@@ -3375,13 +3380,14 @@ static int snd_trident_tlb_alloc(struct snd_trident *trident)
/* allocate shadow TLB page table (virtual addresses) */
trident->tlb.shadow_entries = vmalloc(SNDRV_TRIDENT_MAX_PAGES*sizeof(unsigned long));
if (trident->tlb.shadow_entries == NULL) {
- snd_printk(KERN_ERR "trident: unable to allocate shadow TLB entries\n");
+ dev_err(trident->card->dev,
+ "unable to allocate shadow TLB entries\n");
return -ENOMEM;
}
/* allocate and setup silent page and initialise TLB entries */
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci),
SNDRV_TRIDENT_PAGE_SIZE, &trident->tlb.silent_page) < 0) {
- snd_printk(KERN_ERR "trident: unable to allocate silent page\n");
+ dev_err(trident->card->dev, "unable to allocate silent page\n");
return -ENOMEM;
}
memset(trident->tlb.silent_page.area, 0, SNDRV_TRIDENT_PAGE_SIZE);
@@ -3439,7 +3445,7 @@ static int snd_trident_4d_dx_init(struct snd_trident *trident)
goto __dx_ok;
do_delay(trident);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_ERR "AC'97 codec ready error\n");
+ dev_err(trident->card->dev, "AC'97 codec ready error\n");
return -EIO;
__dx_ok:
@@ -3477,7 +3483,8 @@ static int snd_trident_4d_nx_init(struct snd_trident *trident)
goto __nx_ok;
do_delay(trident);
} while (time_after_eq(end_time, jiffies));
- snd_printk(KERN_ERR "AC'97 codec ready error [0x%x]\n", inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT)));
+ dev_err(trident->card->dev, "AC'97 codec ready error [0x%x]\n",
+ inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT)));
return -EIO;
__nx_ok:
@@ -3562,7 +3569,8 @@ int snd_trident_create(struct snd_card *card,
/* check, if we can restrict PCI DMA transfers to 30 bits */
if (pci_set_dma_mask(pci, DMA_BIT_MASK(30)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(30)) < 0) {
- snd_printk(KERN_ERR "architecture does not support 30bit PCI busmaster DMA\n");
+ dev_err(card->dev,
+ "architecture does not support 30bit PCI busmaster DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -3600,7 +3608,7 @@ int snd_trident_create(struct snd_card *card,
if (request_irq(pci->irq, snd_trident_interrupt, IRQF_SHARED,
KBUILD_MODNAME, trident)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_trident_free(trident);
return -EBUSY;
}
@@ -3664,7 +3672,6 @@ int snd_trident_create(struct snd_card *card,
snd_trident_enable_eso(trident);
snd_trident_proc_init(trident);
- snd_card_set_dev(card, &pci->dev);
*rtrident = trident;
return 0;
}
@@ -3950,8 +3957,7 @@ static int snd_trident_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "trident: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 5ae6f042c586..95b98f537b67 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -459,7 +459,7 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
unsigned int addr;
if (idx >= VIA_TABLE_SIZE) {
- snd_printk(KERN_ERR "via82xx: too much table size!\n");
+ dev_err(&pci->dev, "too much table size!\n");
return -EINVAL;
}
addr = snd_pcm_sgbuf_get_addr(substream, ofs);
@@ -474,8 +474,9 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
} else
flag = 0; /* period continues to the next */
/*
- printk(KERN_DEBUG "via: tbl %d: at %d size %d "
- "(rest %d)\n", idx, ofs, r, rest);
+ dev_dbg(&pci->dev,
+ "tbl %d: at %d size %d (rest %d)\n",
+ idx, ofs, r, rest);
*/
((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag);
dev->idx_table[idx].offset = ofs;
@@ -528,7 +529,7 @@ static int snd_via82xx_codec_ready(struct via82xx *chip, int secondary)
if (!((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY))
return val & 0xffff;
}
- snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n",
+ dev_err(chip->card->dev, "codec_ready: codec %i is not ready [0x%x]\n",
secondary, snd_via82xx_codec_xread(chip));
return -EIO;
}
@@ -587,7 +588,8 @@ static unsigned short snd_via82xx_codec_read(struct snd_ac97 *ac97, unsigned sho
xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
while (1) {
if (again++ > 3) {
- snd_printk(KERN_ERR "codec_read: codec %i is not valid [0x%x]\n",
+ dev_err(chip->card->dev,
+ "codec_read: codec %i is not valid [0x%x]\n",
ac97->num, snd_via82xx_codec_xread(chip));
return 0xffff;
}
@@ -777,7 +779,9 @@ static int snd_via82xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
((pos) < viadev->lastpos && ((pos) >= viadev->bufsize2 ||\
viadev->lastpos < viadev->bufsize2))
-static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int idx,
+static inline unsigned int calc_linear_pos(struct via82xx *chip,
+ struct viadev *viadev,
+ unsigned int idx,
unsigned int count)
{
unsigned int size, base, res;
@@ -790,7 +794,8 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i
/* check the validity of the calculated position */
if (size < count) {
- snd_printd(KERN_ERR "invalid via82xx_cur_ptr (size = %d, count = %d)\n",
+ dev_dbg(chip->card->dev,
+ "invalid via82xx_cur_ptr (size = %d, count = %d)\n",
(int)size, (int)count);
res = viadev->lastpos;
} else {
@@ -807,9 +812,9 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i
}
if (check_invalid_pos(viadev, res)) {
#ifdef POINTER_DEBUG
- printk(KERN_DEBUG "fail: idx = %i/%i, lastpos = 0x%x, "
- "bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, "
- "count = 0x%x\n", idx, viadev->tbl_entries,
+ dev_dbg(chip->card->dev,
+ "fail: idx = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x\n",
+ idx, viadev->tbl_entries,
viadev->lastpos, viadev->bufsize2,
viadev->idx_table[idx].offset,
viadev->idx_table[idx].size, count);
@@ -817,8 +822,8 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i
/* count register returns full size when end of buffer is reached */
res = base + size;
if (check_invalid_pos(viadev, res)) {
- snd_printd(KERN_ERR "invalid via82xx_cur_ptr (2), "
- "using last valid pointer\n");
+ dev_dbg(chip->card->dev,
+ "invalid via82xx_cur_ptr (2), using last valid pointer\n");
res = viadev->lastpos;
}
}
@@ -850,7 +855,7 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr
idx = 0;
else /* CURR_PTR holds the address + 8 */
idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) % viadev->tbl_entries;
- res = calc_linear_pos(viadev, idx, count);
+ res = calc_linear_pos(chip, viadev, idx, count);
viadev->lastpos = res; /* remember the last position */
spin_unlock(&chip->reg_lock);
@@ -889,13 +894,14 @@ static snd_pcm_uframes_t snd_via8233_pcm_pointer(struct snd_pcm_substream *subst
idx = count >> 24;
if (idx >= viadev->tbl_entries) {
#ifdef POINTER_DEBUG
- printk(KERN_DEBUG "fail: invalid idx = %i/%i\n", idx,
+ dev_dbg(chip->card->dev,
+ "fail: invalid idx = %i/%i\n", idx,
viadev->tbl_entries);
#endif
res = viadev->lastpos;
} else {
count &= 0xffffff;
- res = calc_linear_pos(viadev, idx, count);
+ res = calc_linear_pos(chip, viadev, idx, count);
}
} else {
res = viadev->hwptr_done;
@@ -1940,14 +1946,15 @@ static int snd_via686_create_gameport(struct via82xx *chip, unsigned char *legac
r = request_region(JOYSTICK_ADDR, 8, "VIA686 gameport");
if (!r) {
- printk(KERN_WARNING "via82xx: cannot reserve joystick port %#x\n",
+ dev_warn(chip->card->dev, "cannot reserve joystick port %#x\n",
JOYSTICK_ADDR);
return -EBUSY;
}
chip->gameport = gp = gameport_allocate_port();
if (!gp) {
- printk(KERN_ERR "via82xx: cannot allocate memory for gameport\n");
+ dev_err(chip->card->dev,
+ "cannot allocate memory for gameport\n");
release_and_free_resource(r);
return -ENOMEM;
}
@@ -2016,7 +2023,8 @@ static int snd_via8233_init_misc(struct via82xx *chip)
strcpy(sid.name, "PCM Playback Volume");
sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
if (! snd_ctl_find_id(chip->card, &sid)) {
- snd_printd(KERN_INFO "Using DXS as PCM Playback\n");
+ dev_info(chip->card->dev,
+ "Using DXS as PCM Playback\n");
err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_pcmdxs_volume_control, chip));
if (err < 0)
return err;
@@ -2102,8 +2110,9 @@ static int snd_via686_init_misc(struct via82xx *chip)
mpu_port, MPU401_INFO_INTEGRATED |
MPU401_INFO_IRQ_HOOK, -1,
&chip->rmidi) < 0) {
- printk(KERN_WARNING "unable to initialize MPU-401"
- " at 0x%lx, skipping\n", mpu_port);
+ dev_warn(chip->card->dev,
+ "unable to initialize MPU-401 at 0x%lx, skipping\n",
+ mpu_port);
legacy &= ~VIA_FUNC_ENABLE_MIDI;
} else {
legacy &= ~VIA_FUNC_MIDI_IRQMASK; /* enable MIDI interrupt */
@@ -2203,7 +2212,8 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
} while (time_before(jiffies, end_time));
if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
- snd_printk(KERN_ERR "AC'97 codec is not ready [0x%x]\n", val);
+ dev_err(chip->card->dev,
+ "AC'97 codec is not ready [0x%x]\n", val);
#if 0 /* FIXME: we don't support the second codec yet so skip the detection now.. */
snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
@@ -2303,8 +2313,7 @@ static int snd_via82xx_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "via82xx: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -2417,7 +2426,7 @@ static int snd_via82xx_create(struct snd_card *card,
snd_via8233_interrupt : snd_via686_interrupt,
IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_via82xx_free(chip);
return -EBUSY;
}
@@ -2441,8 +2450,6 @@ static int snd_via82xx_create(struct snd_card *card,
* We call pci_set_master here because it does not hurt. */
pci_set_master(pci);
- snd_card_set_dev(card, &pci->dev);
-
*r_via = chip;
return 0;
}
@@ -2516,7 +2523,7 @@ static int check_dxs_list(struct pci_dev *pci, int revision)
w = snd_pci_quirk_lookup(pci, dxs_whitelist);
if (w) {
- snd_printdd(KERN_INFO "via82xx: DXS white list for %s found\n",
+ dev_dbg(&pci->dev, "DXS white list for %s found\n",
snd_pci_quirk_name(w));
return w->value;
}
@@ -2528,10 +2535,10 @@ static int check_dxs_list(struct pci_dev *pci, int revision)
/*
* not detected, try 48k rate only to be sure.
*/
- printk(KERN_INFO "via82xx: Assuming DXS channels with 48k fixed sample rate.\n");
- printk(KERN_INFO " Please try dxs_support=5 option\n");
- printk(KERN_INFO " and report if it works on your machine.\n");
- printk(KERN_INFO " For more details, read ALSA-Configuration.txt.\n");
+ dev_info(&pci->dev, "Assuming DXS channels with 48k fixed sample rate.\n");
+ dev_info(&pci->dev, " Please try dxs_support=5 option\n");
+ dev_info(&pci->dev, " and report if it works on your machine.\n");
+ dev_info(&pci->dev, " For more details, read ALSA-Configuration.txt.\n");
return VIA_DXS_48K;
};
@@ -2544,7 +2551,7 @@ static int snd_via82xx_probe(struct pci_dev *pci,
unsigned int i;
int err;
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -2584,7 +2591,7 @@ static int snd_via82xx_probe(struct pci_dev *pci,
strcpy(card->driver, "VIA8233");
break;
default:
- snd_printk(KERN_ERR "invalid card type %d\n", card_type);
+ dev_err(card->dev, "invalid card type %d\n", card_type);
err = -EINVAL;
goto __error;
}
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index ca190283cbd7..46a0526b1d79 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -312,7 +312,7 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
unsigned int addr;
if (idx >= VIA_TABLE_SIZE) {
- snd_printk(KERN_ERR "via82xx: too much table size!\n");
+ dev_err(&pci->dev, "too much table size!\n");
return -EINVAL;
}
addr = snd_pcm_sgbuf_get_addr(substream, ofs);
@@ -329,8 +329,9 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
} else
flag = 0; /* period continues to the next */
/*
- printk(KERN_DEBUG "via: tbl %d: at %d size %d "
- "(rest %d)\n", idx, ofs, r, rest);
+ dev_dbg(&pci->dev,
+ "tbl %d: at %d size %d (rest %d)\n",
+ idx, ofs, r, rest);
*/
((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag);
dev->idx_table[idx].offset = ofs;
@@ -382,7 +383,7 @@ static int snd_via82xx_codec_ready(struct via82xx_modem *chip, int secondary)
if (!((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY))
return val & 0xffff;
}
- snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n",
+ dev_err(chip->card->dev, "codec_ready: codec %i is not ready [0x%x]\n",
secondary, snd_via82xx_codec_xread(chip));
return -EIO;
}
@@ -443,7 +444,8 @@ static unsigned short snd_via82xx_codec_read(struct snd_ac97 *ac97, unsigned sho
xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
while (1) {
if (again++ > 3) {
- snd_printk(KERN_ERR "codec_read: codec %i is not valid [0x%x]\n",
+ dev_err(chip->card->dev,
+ "codec_read: codec %i is not valid [0x%x]\n",
ac97->num, snd_via82xx_codec_xread(chip));
return 0xffff;
}
@@ -560,7 +562,9 @@ static int snd_via82xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
((pos) < viadev->lastpos && ((pos) >= viadev->bufsize2 ||\
viadev->lastpos < viadev->bufsize2))
-static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int idx,
+static inline unsigned int calc_linear_pos(struct via82xx_modem *chip,
+ struct viadev *viadev,
+ unsigned int idx,
unsigned int count)
{
unsigned int size, res;
@@ -570,20 +574,21 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i
/* check the validity of the calculated position */
if (size < count) {
- snd_printd(KERN_ERR "invalid via82xx_cur_ptr (size = %d, count = %d)\n",
+ dev_err(chip->card->dev,
+ "invalid via82xx_cur_ptr (size = %d, count = %d)\n",
(int)size, (int)count);
res = viadev->lastpos;
} else if (check_invalid_pos(viadev, res)) {
#ifdef POINTER_DEBUG
- printk(KERN_DEBUG "fail: idx = %i/%i, lastpos = 0x%x, "
- "bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, "
- "count = 0x%x\n", idx, viadev->tbl_entries, viadev->lastpos,
+ dev_dbg(chip->card->dev,
+ "fail: idx = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x\n",
+ idx, viadev->tbl_entries, viadev->lastpos,
viadev->bufsize2, viadev->idx_table[idx].offset,
viadev->idx_table[idx].size, count);
#endif
if (count && size < count) {
- snd_printd(KERN_ERR "invalid via82xx_cur_ptr, "
- "using last valid pointer\n");
+ dev_dbg(chip->card->dev,
+ "invalid via82xx_cur_ptr, using last valid pointer\n");
res = viadev->lastpos;
} else {
if (! count)
@@ -595,8 +600,8 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i
*/
res = viadev->idx_table[idx].offset + size;
if (check_invalid_pos(viadev, res)) {
- snd_printd(KERN_ERR "invalid via82xx_cur_ptr (2), "
- "using last valid pointer\n");
+ dev_dbg(chip->card->dev,
+ "invalid via82xx_cur_ptr (2), using last valid pointer\n");
res = viadev->lastpos;
}
}
@@ -632,7 +637,7 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr
else /* CURR_PTR holds the address + 8 */
idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) %
viadev->tbl_entries;
- res = calc_linear_pos(viadev, idx, count);
+ res = calc_linear_pos(chip, viadev, idx, count);
spin_unlock(&chip->reg_lock);
return bytes_to_frames(substream->runtime, res);
@@ -991,7 +996,8 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
} while (time_before(jiffies, end_time));
if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
- snd_printk(KERN_ERR "AC'97 codec is not ready [0x%x]\n", val);
+ dev_err(chip->card->dev,
+ "AC'97 codec is not ready [0x%x]\n", val);
snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
VIA_REG_AC97_SECONDARY_VALID |
@@ -1054,8 +1060,7 @@ static int snd_via82xx_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "via82xx-modem: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -1137,7 +1142,7 @@ static int snd_via82xx_create(struct snd_card *card,
chip->port = pci_resource_start(pci, 0);
if (request_irq(pci->irq, snd_via82xx_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_via82xx_free(chip);
return -EBUSY;
}
@@ -1161,8 +1166,6 @@ static int snd_via82xx_create(struct snd_card *card,
* We call pci_set_master here because it does not hurt. */
pci_set_master(pci);
- snd_card_set_dev(card, &pci->dev);
-
*r_via = chip;
return 0;
}
@@ -1177,7 +1180,7 @@ static int snd_via82xx_probe(struct pci_dev *pci,
unsigned int i;
int err;
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -1188,7 +1191,7 @@ static int snd_via82xx_probe(struct pci_dev *pci,
sprintf(card->shortname, "VIA 82XX modem");
break;
default:
- snd_printk(KERN_ERR "invalid card type %d\n", card_type);
+ dev_err(card->dev, "invalid card type %d\n", card_type);
err = -EINVAL;
goto __error;
}
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index ab8a9b1bfb8e..ff9074d22607 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -170,7 +170,7 @@ static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci,
if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_vx222_free(chip);
return -EBUSY;
}
@@ -181,8 +181,6 @@ static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci,
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*rchip = vx;
return 0;
}
@@ -204,7 +202,8 @@ static int snd_vx222_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -229,7 +228,7 @@ static int snd_vx222_probe(struct pci_dev *pci,
sprintf(card->longname, "%s at 0x%lx & 0x%lx, irq %i",
card->shortname, vx->port[0], vx->port[1], vx->core.irq);
- snd_printdd("%s at 0x%lx & 0x%lx, irq %i\n",
+ dev_dbg(card->dev, "%s at 0x%lx & 0x%lx, irq %i\n",
card->shortname, vx->port[0], vx->port[1], vx->core.irq);
#ifdef SND_VX_FW_LOADER
@@ -280,8 +279,7 @@ static int snd_vx222_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "vx222: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index a69e774d0b13..2d1570273e99 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -108,7 +108,7 @@ static void vx2_outb(struct vx_core *chip, int offset, unsigned char val)
{
outb(val, vx2_reg_addr(chip, offset));
/*
- printk(KERN_DEBUG "outb: %x -> %x\n", val, vx2_reg_addr(chip, offset));
+ dev_dbg(chip->card->dev, "outb: %x -> %x\n", val, vx2_reg_addr(chip, offset));
*/
}
@@ -129,7 +129,7 @@ static unsigned int vx2_inl(struct vx_core *chip, int offset)
static void vx2_outl(struct vx_core *chip, int offset, unsigned int val)
{
/*
- printk(KERN_DEBUG "outl: %x -> %x\n", val, vx2_reg_addr(chip, offset));
+ dev_dbg(chip->card->dev, "outl: %x -> %x\n", val, vx2_reg_addr(chip, offset));
*/
outl(val, vx2_reg_addr(chip, offset));
}
@@ -173,7 +173,7 @@ static int vx2_test_xilinx(struct vx_core *_chip)
struct snd_vx222 *chip = (struct snd_vx222 *)_chip;
unsigned int data;
- snd_printdd("testing xilinx...\n");
+ dev_dbg(_chip->card->dev, "testing xilinx...\n");
/* This test uses several write/read sequences on TEST0 and TEST1 bits
* to figure out whever or not the xilinx was correctly loaded
*/
@@ -183,7 +183,7 @@ static int vx2_test_xilinx(struct vx_core *_chip)
vx_inl(chip, ISR);
data = vx_inl(chip, STATUS);
if ((data & VX_STATUS_VAL_TEST0_MASK) == VX_STATUS_VAL_TEST0_MASK) {
- snd_printdd("bad!\n");
+ dev_dbg(_chip->card->dev, "bad!\n");
return -ENODEV;
}
@@ -192,7 +192,7 @@ static int vx2_test_xilinx(struct vx_core *_chip)
vx_inl(chip, ISR);
data = vx_inl(chip, STATUS);
if (! (data & VX_STATUS_VAL_TEST0_MASK)) {
- snd_printdd("bad! #2\n");
+ dev_dbg(_chip->card->dev, "bad! #2\n");
return -ENODEV;
}
@@ -203,7 +203,7 @@ static int vx2_test_xilinx(struct vx_core *_chip)
vx_inl(chip, ISR);
data = vx_inl(chip, STATUS);
if ((data & VX_STATUS_VAL_TEST1_MASK) == VX_STATUS_VAL_TEST1_MASK) {
- snd_printdd("bad! #3\n");
+ dev_dbg(_chip->card->dev, "bad! #3\n");
return -ENODEV;
}
@@ -212,11 +212,11 @@ static int vx2_test_xilinx(struct vx_core *_chip)
vx_inl(chip, ISR);
data = vx_inl(chip, STATUS);
if (! (data & VX_STATUS_VAL_TEST1_MASK)) {
- snd_printdd("bad! #4\n");
+ dev_dbg(_chip->card->dev, "bad! #4\n");
return -ENODEV;
}
}
- snd_printdd("ok, xilinx fine.\n");
+ dev_dbg(_chip->card->dev, "ok, xilinx fine.\n");
return 0;
}
@@ -397,7 +397,8 @@ static int vx2_load_xilinx_binary(struct vx_core *chip, const struct firmware *x
i = vx_inl(chip, GPIOC);
if (i & 0x0100)
return 0;
- snd_printk(KERN_ERR "vx222: xilinx test failed after load, GPIOC=0x%x\n", i);
+ dev_err(chip->card->dev,
+ "xilinx test failed after load, GPIOC=0x%x\n", i);
return -EINVAL;
}
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index e8932b2e4a5d..82eed164b275 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -106,7 +106,8 @@ static int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev,
break;
}
if (!r) {
- printk(KERN_ERR "ymfpci: no gameport ports available\n");
+ dev_err(chip->card->dev,
+ "no gameport ports available\n");
return -EBUSY;
}
}
@@ -116,19 +117,22 @@ static int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev,
case 0x204: legacy_ctrl2 |= 2 << 6; break;
case 0x205: legacy_ctrl2 |= 3 << 6; break;
default:
- printk(KERN_ERR "ymfpci: invalid joystick port %#x", io_port);
+ dev_err(chip->card->dev,
+ "invalid joystick port %#x", io_port);
return -EINVAL;
}
}
if (!r && !(r = request_region(io_port, 1, "YMFPCI gameport"))) {
- printk(KERN_ERR "ymfpci: joystick port %#x is in use.\n", io_port);
+ dev_err(chip->card->dev,
+ "joystick port %#x is in use.\n", io_port);
return -EBUSY;
}
chip->gameport = gp = gameport_allocate_port();
if (!gp) {
- printk(KERN_ERR "ymfpci: cannot allocate memory for gameport\n");
+ dev_err(chip->card->dev,
+ "cannot allocate memory for gameport\n");
release_and_free_resource(r);
return -ENOMEM;
}
@@ -187,7 +191,8 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ 0, &card);
if (err < 0)
return err;
@@ -313,7 +318,9 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
MPU401_INFO_INTEGRATED |
MPU401_INFO_IRQ_HOOK,
-1, &chip->rawmidi)) < 0) {
- printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]);
+ dev_warn(card->dev,
+ "cannot initialize MPU401 at 0x%lx, skipping...\n",
+ mpu_port[dev]);
legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */
pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl);
}
@@ -323,12 +330,14 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
fm_port[dev],
fm_port[dev] + 2,
OPL3_HW_OPL3, 1, &opl3)) < 0) {
- printk(KERN_WARNING "ymfpci: cannot initialize FM OPL3 at 0x%lx, skipping...\n", fm_port[dev]);
+ dev_warn(card->dev,
+ "cannot initialize FM OPL3 at 0x%lx, skipping...\n",
+ fm_port[dev]);
legacy_ctrl &= ~YMFPCI_LEGACY_FMEN;
pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl);
} else if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
snd_card_free(card);
- snd_printk(KERN_ERR "cannot create opl3 hwdep\n");
+ dev_err(card->dev, "cannot create opl3 hwdep\n");
return err;
}
}
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index d591c154fc58..81c916a5eb96 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -86,7 +86,9 @@ static int snd_ymfpci_codec_ready(struct snd_ymfpci *chip, int secondary)
return 0;
schedule_timeout_uninterruptible(1);
} while (time_before(jiffies, end_time));
- snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_ymfpci_readw(chip, reg));
+ dev_err(chip->card->dev,
+ "codec_ready: codec %i is not ready [0x%x]\n",
+ secondary, snd_ymfpci_readw(chip, reg));
return -EBUSY;
}
@@ -319,7 +321,7 @@ static void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_
ypcm->last_pos = pos;
if (ypcm->period_pos >= ypcm->period_size) {
/*
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
"done - active_bank = 0x%x, start = 0x%x\n",
chip->active_bank,
voice->bank[chip->active_bank].start);
@@ -372,7 +374,7 @@ static void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream
if (ypcm->period_pos >= ypcm->period_size) {
ypcm->period_pos %= ypcm->period_size;
/*
- printk(KERN_DEBUG
+ dev_dbg(chip->card->dev,
"done - active_bank = 0x%x, start = 0x%x\n",
chip->active_bank,
voice->bank[chip->active_bank].start);
@@ -2067,7 +2069,8 @@ static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip)
&chip->pci->dev);
if (err >= 0) {
if (chip->dsp_microcode->size != YDSXG_DSPLENGTH) {
- snd_printk(KERN_ERR "DSP microcode has wrong size\n");
+ dev_err(chip->card->dev,
+ "DSP microcode has wrong size\n");
err = -EINVAL;
}
}
@@ -2082,8 +2085,8 @@ static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip)
&chip->pci->dev);
if (err >= 0) {
if (chip->controller_microcode->size != YDSXG_CTRLLENGTH) {
- snd_printk(KERN_ERR "controller microcode"
- " has wrong size\n");
+ dev_err(chip->card->dev,
+ "controller microcode has wrong size\n");
err = -EINVAL;
}
}
@@ -2360,8 +2363,7 @@ static int snd_ymfpci_resume(struct device *dev)
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "ymfpci: pci_enable_device failed, "
- "disabling device\n");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
@@ -2433,13 +2435,15 @@ int snd_ymfpci_create(struct snd_card *card,
chip->src441_used = -1;
if ((chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI")) == NULL) {
- snd_printk(KERN_ERR "unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1);
+ dev_err(chip->card->dev,
+ "unable to grab memory region 0x%lx-0x%lx\n",
+ chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1);
snd_ymfpci_free(chip);
return -EBUSY;
}
if (request_irq(pci->irq, snd_ymfpci_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+ dev_err(chip->card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_ymfpci_free(chip);
return -EBUSY;
}
@@ -2453,7 +2457,7 @@ int snd_ymfpci_create(struct snd_card *card,
err = snd_ymfpci_request_firmware(chip);
if (err < 0) {
- snd_printk(KERN_ERR "firmware request failed: %d\n", err);
+ dev_err(chip->card->dev, "firmware request failed: %d\n", err);
snd_ymfpci_free(chip);
return err;
}
@@ -2487,8 +2491,6 @@ int snd_ymfpci_create(struct snd_card *card,
snd_ymfpci_proc_init(card, chip);
- snd_card_set_dev(card, &pci->dev);
-
*rchip = chip;
return 0;
}
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index 8f489de5c4c6..56bda124cd4a 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -112,7 +112,8 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
return -ENODEV; /* disabled explicitly */
/* ok, create a card instance */
- err = snd_card_create(index[i], id[i], THIS_MODULE, 0, &card);
+ err = snd_card_new(&link->dev, index[i], id[i], THIS_MODULE,
+ 0, &card);
if (err < 0) {
snd_printk(KERN_ERR "pdacf: cannot create a card instance\n");
return err;
@@ -131,8 +132,6 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
return err;
}
- snd_card_set_dev(card, &link->dev);
-
pdacf->index = i;
card_list[i] = card;
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index d4db7ecaa6bf..786e7e139c9e 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -238,7 +238,6 @@ static int vxpocket_config(struct pcmcia_device *link)
goto failed;
chip->dev = &link->dev;
- snd_card_set_dev(chip->card, chip->dev);
if (snd_vxpocket_assign_resources(chip, link->resource[0]->start,
link->irq) < 0)
@@ -307,7 +306,8 @@ static int vxpocket_probe(struct pcmcia_device *p_dev)
return -ENODEV; /* disabled explicitly */
/* ok, create a card instance */
- err = snd_card_create(index[i], id[i], THIS_MODULE, 0, &card);
+ err = snd_card_new(&p_dev->dev, index[i], id[i], THIS_MODULE,
+ 0, &card);
if (err < 0) {
snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n");
return err;
diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c
index 8abb521b4814..350a7c8f86dd 100644
--- a/sound/ppc/powermac.c
+++ b/sound/ppc/powermac.c
@@ -58,7 +58,7 @@ static int snd_pmac_probe(struct platform_device *devptr)
char *name_ext;
int err;
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&devptr->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -122,8 +122,6 @@ static int snd_pmac_probe(struct platform_device *devptr)
if (enable_beep)
snd_pmac_attach_beep(chip);
- snd_card_set_dev(card, &devptr->dev);
-
if ((err = snd_card_register(card)) < 0)
goto __error;
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index ebb76f2d90d7..58f292a87f98 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -984,7 +984,8 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
}
/* create card instance */
- ret = snd_card_create(index, id, THIS_MODULE, 0, &the_card.card);
+ ret = snd_card_new(&dev->core, index, id, THIS_MODULE,
+ 0, &the_card.card);
if (ret < 0)
goto clean_irq;
@@ -1052,7 +1053,6 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
snd_ps3_init_avsetting(&the_card);
/* register the card */
- snd_card_set_dev(the_card.card, &dev->core);
ret = snd_card_register(the_card.card);
if (ret < 0)
goto clean_dma_map;
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
index 78a369785a9e..47849eaf266d 100644
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -608,8 +608,8 @@ static int snd_aica_probe(struct platform_device *devptr)
dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL);
if (unlikely(!dreamcastcard))
return -ENOMEM;
- err = snd_card_create(index, SND_AICA_DRIVER, THIS_MODULE, 0,
- &dreamcastcard->card);
+ err = snd_card_new(&devptr->dev, index, SND_AICA_DRIVER,
+ THIS_MODULE, 0, &dreamcastcard->card);
if (unlikely(err < 0)) {
kfree(dreamcastcard);
return err;
@@ -624,7 +624,6 @@ static int snd_aica_probe(struct platform_device *devptr)
err = snd_aicapcmchip(dreamcastcard, 0);
if (unlikely(err < 0))
goto freedreamcast;
- snd_card_set_dev(dreamcastcard->card, &devptr->dev);
dreamcastcard->timer.data = 0;
dreamcastcard->channel = NULL;
/* Add basic controls */
diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c
index 7c9422c4fc0f..d1fb74dabbd1 100644
--- a/sound/sh/sh_dac_audio.c
+++ b/sound/sh/sh_dac_audio.c
@@ -396,7 +396,7 @@ static int snd_sh_dac_probe(struct platform_device *devptr)
struct snd_card *card;
int err;
- err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ err = snd_card_new(&devptr->dev, index, id, THIS_MODULE, 0, &card);
if (err < 0) {
snd_printk(KERN_ERR "cannot allocate the card\n");
return err;
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index d62ce483a443..0060b31cc3f3 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -50,6 +50,7 @@ source "sound/soc/pxa/Kconfig"
source "sound/soc/samsung/Kconfig"
source "sound/soc/s6000/Kconfig"
source "sound/soc/sh/Kconfig"
+source "sound/soc/sirf/Kconfig"
source "sound/soc/spear/Kconfig"
source "sound/soc/tegra/Kconfig"
source "sound/soc/txx9/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 62a1822e77bf..5f1df02984f8 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += samsung/
obj-$(CONFIG_SND_SOC) += s6000/
obj-$(CONFIG_SND_SOC) += sh/
+obj-$(CONFIG_SND_SOC) += sirf/
obj-$(CONFIG_SND_SOC) += spear/
obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += txx9/
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index e634eb78ed03..4789619a52d8 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -58,6 +58,6 @@ config SND_AT91_SOC_AFEB9260
depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
select SND_ATMEL_SOC_PDC
select SND_ATMEL_SOC_SSC
- select SND_SOC_TLV320AIC23
+ select SND_SOC_TLV320AIC23_I2C
help
Say Y here to support sound on AFEB9260 board.
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 1ead3c977a51..de433cfd044c 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -341,6 +341,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
{
int id = dai->id;
struct atmel_ssc_info *ssc_p = &ssc_info[id];
+ struct ssc_device *ssc = ssc_p->ssc;
struct atmel_pcm_dma_params *dma_params;
int dir, channels, bits;
u32 tfmr, rfmr, tcmr, rcmr;
@@ -466,7 +467,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
| SSC_BF(RCMR_START, start_event)
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
- | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK);
+ | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
+ SSC_CKS_PIN : SSC_CKS_CLOCK);
rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
| SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
@@ -481,7 +483,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
| SSC_BF(TCMR_START, start_event)
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
| SSC_BF(TCMR_CKO, SSC_CKO_NONE)
- | SSC_BF(TCMR_CKS, SSC_CKS_PIN);
+ | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ?
+ SSC_CKS_CLOCK : SSC_CKS_PIN);
tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
| SSC_BF(TFMR_FSDEN, 0)
@@ -550,7 +553,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
| SSC_BF(RCMR_START, SSC_START_RISING_RF)
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
- | SSC_BF(RCMR_CKS, SSC_CKS_PIN);
+ | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
+ SSC_CKS_PIN : SSC_CKS_CLOCK);
rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
| SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
@@ -565,7 +569,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
| SSC_BF(TCMR_START, SSC_START_RISING_RF)
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
| SSC_BF(TCMR_CKO, SSC_CKO_NONE)
- | SSC_BF(TCMR_CKS, SSC_CKS_PIN);
+ | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
+ SSC_CKS_CLOCK : SSC_CKS_PIN);
tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
| SSC_BF(TFMR_FSDEN, 0)
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index f15bff1548f8..174bd546c08b 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -155,25 +155,14 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- /* Add specific widgets */
- snd_soc_dapm_new_controls(dapm, at91sam9g20ek_dapm_widgets,
- ARRAY_SIZE(at91sam9g20ek_dapm_widgets));
- /* Set up specific audio path interconnects */
- snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
/* not connected */
snd_soc_dapm_nc_pin(dapm, "RLINEIN");
snd_soc_dapm_nc_pin(dapm, "LLINEIN");
-#ifdef ENABLE_MIC_INPUT
- snd_soc_dapm_enable_pin(dapm, "Int Mic");
-#else
- snd_soc_dapm_nc_pin(dapm, "Int Mic");
+#ifndef ENABLE_MIC_INPUT
+ snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic");
#endif
- /* always connected */
- snd_soc_dapm_enable_pin(dapm, "Ext Spk");
-
return 0;
}
@@ -194,6 +183,11 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
.dai_link = &at91sam9g20ek_dai,
.num_links = 1,
.set_bias_level = at91sam9g20ek_set_bias_level,
+
+ .dapm_widgets = at91sam9g20ek_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets),
+ .dapm_routes = intercon,
+ .num_dapm_routes = ARRAY_SIZE(intercon),
};
static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index 54f74f8cbb75..6347d5910138 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -11,20 +11,20 @@ config SND_BF5XX_I2S
config SND_BF5XX_SOC_SSM2602
tristate "SoC SSM2602 Audio Codec Add-On Card support"
- depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
+ depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
select SND_BF5XX_SOC_I2S if !BF60x
select SND_BF6XX_SOC_I2S if BF60x
- select SND_SOC_SSM2602
+ select SND_SOC_SSM2602_SPI if SPI_MASTER
+ select SND_SOC_SSM2602_I2C if I2C
help
Say Y if you want to add support for the Analog Devices
SSM2602 Audio Codec Add-On Card.
config SND_SOC_BFIN_EVAL_ADAU1701
tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards"
- depends on SND_BF5XX_I2S
+ depends on SND_BF5XX_I2S && I2C
select SND_BF5XX_SOC_I2S
select SND_SOC_ADAU1701
- select I2C
help
Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ
board connected to one of the Blackfin evaluation boards like the
@@ -45,9 +45,10 @@ config SND_SOC_BFIN_EVAL_ADAU1373
config SND_SOC_BFIN_EVAL_ADAV80X
tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
- depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
+ depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
select SND_BF5XX_SOC_I2S
- select SND_SOC_ADAV80X
+ select SND_SOC_ADAV801 if SPI_MASTER
+ select SND_SOC_ADAV803 if I2C
help
Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or
EVAL-ADAV803 board connected to one of the Blackfin evaluation boards
@@ -58,7 +59,7 @@ config SND_SOC_BFIN_EVAL_ADAV80X
config SND_BF5XX_SOC_AD1836
tristate "SoC AD1836 Audio support for BF5xx"
- depends on SND_BF5XX_I2S
+ depends on SND_BF5XX_I2S && SPI_MASTER
select SND_BF5XX_SOC_I2S
select SND_SOC_AD1836
help
@@ -66,9 +67,10 @@ config SND_BF5XX_SOC_AD1836
config SND_BF5XX_SOC_AD193X
tristate "SoC AD193X Audio support for Blackfin"
- depends on SND_BF5XX_I2S
+ depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
select SND_BF5XX_SOC_I2S
- select SND_SOC_AD193X
+ select SND_SOC_AD193X_I2C if I2C
+ select SND_SOC_AD193X_SPI if SPI_MASTER
help
Say Y if you want to add support for AD193X codec on Blackfin.
This driver supports AD1936, AD1937, AD1938 and AD1939.
diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig
index 06f938deda15..5477c5475923 100644
--- a/sound/soc/cirrus/Kconfig
+++ b/sound/soc/cirrus/Kconfig
@@ -1,6 +1,6 @@
config SND_EP93XX_SOC
tristate "SoC Audio support for the Cirrus Logic EP93xx series"
- depends on (ARCH_EP93XX || COMPILE_TEST) && SND_SOC
+ depends on ARCH_EP93XX || COMPILE_TEST
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for codecs attached to
@@ -18,7 +18,7 @@ config SND_EP93XX_SOC_SNAPPERCL15
tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
select SND_EP93XX_SOC_I2S
- select SND_SOC_TLV320AIC23
+ select SND_SOC_TLV320AIC23_I2C
help
Say Y or M here if you want to add support for I2S audio on the
Bluewater Systems Snapper CL15 module.
diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c
index 29238a7476dd..5b68b106cfc2 100644
--- a/sound/soc/cirrus/snappercl15.c
+++ b/sound/soc/cirrus/snappercl15.c
@@ -65,18 +65,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"MICIN", NULL, "Mic Jack"},
};
-static int snappercl15_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
- ARRAY_SIZE(tlv320aic23_dapm_widgets));
-
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
- return 0;
-}
-
static struct snd_soc_dai_link snappercl15_dai = {
.name = "tlv320aic23",
.stream_name = "AIC23",
@@ -84,7 +72,6 @@ static struct snd_soc_dai_link snappercl15_dai = {
.codec_dai_name = "tlv320aic23-hifi",
.codec_name = "tlv320aic23-codec.0-001a",
.platform_name = "ep93xx-i2s",
- .init = snappercl15_tlv320aic23_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
SND_SOC_DAIFMT_CBS_CFS,
.ops = &snappercl15_ops,
@@ -95,6 +82,11 @@ static struct snd_soc_card snd_soc_snappercl15 = {
.owner = THIS_MODULE,
.dai_link = &snappercl15_dai,
.num_links = 1,
+
+ .dapm_widgets = tlv320aic23_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static int snappercl15_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index 75d0ad5d2dcb..b07e17160f94 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -448,38 +448,38 @@ static const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"};
static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"};
-static const struct soc_enum pm860x_hs1_opamp_enum =
- SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 5, 4, pm860x_opamp_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_hs1_opamp_enum,
+ PM860X_HS1_CTRL, 5, pm860x_opamp_texts);
-static const struct soc_enum pm860x_hs2_opamp_enum =
- SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 5, 4, pm860x_opamp_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_hs2_opamp_enum,
+ PM860X_HS2_CTRL, 5, pm860x_opamp_texts);
-static const struct soc_enum pm860x_hs1_pa_enum =
- SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 3, 4, pm860x_pa_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_hs1_pa_enum,
+ PM860X_HS1_CTRL, 3, pm860x_pa_texts);
-static const struct soc_enum pm860x_hs2_pa_enum =
- SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 3, 4, pm860x_pa_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_hs2_pa_enum,
+ PM860X_HS2_CTRL, 3, pm860x_pa_texts);
-static const struct soc_enum pm860x_lo1_opamp_enum =
- SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 5, 4, pm860x_opamp_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_lo1_opamp_enum,
+ PM860X_LO1_CTRL, 5, pm860x_opamp_texts);
-static const struct soc_enum pm860x_lo2_opamp_enum =
- SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 5, 4, pm860x_opamp_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_lo2_opamp_enum,
+ PM860X_LO2_CTRL, 5, pm860x_opamp_texts);
-static const struct soc_enum pm860x_lo1_pa_enum =
- SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 3, 4, pm860x_pa_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_lo1_pa_enum,
+ PM860X_LO1_CTRL, 3, pm860x_pa_texts);
-static const struct soc_enum pm860x_lo2_pa_enum =
- SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 3, 4, pm860x_pa_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_lo2_pa_enum,
+ PM860X_LO2_CTRL, 3, pm860x_pa_texts);
-static const struct soc_enum pm860x_spk_pa_enum =
- SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 5, 4, pm860x_pa_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_spk_pa_enum,
+ PM860X_EAR_CTRL_1, 5, pm860x_pa_texts);
-static const struct soc_enum pm860x_ear_pa_enum =
- SOC_ENUM_SINGLE(PM860X_EAR_CTRL_2, 0, 4, pm860x_pa_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_ear_pa_enum,
+ PM860X_EAR_CTRL_2, 0, pm860x_pa_texts);
-static const struct soc_enum pm860x_spk_ear_opamp_enum =
- SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 3, 4, pm860x_opamp_texts);
+static SOC_ENUM_SINGLE_DECL(pm860x_spk_ear_opamp_enum,
+ PM860X_EAR_CTRL_1, 3, pm860x_opamp_texts);
static const struct snd_kcontrol_new pm860x_snd_controls[] = {
SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2,
@@ -561,8 +561,8 @@ static const char *aif1_text[] = {
"PCM L", "PCM R",
};
-static const struct soc_enum aif1_enum =
- SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 6, 2, aif1_text);
+static SOC_ENUM_SINGLE_DECL(aif1_enum,
+ PM860X_PCM_IFACE_3, 6, aif1_text);
static const struct snd_kcontrol_new aif1_mux =
SOC_DAPM_ENUM("PCM Mux", aif1_enum);
@@ -572,8 +572,8 @@ static const char *i2s_din_text[] = {
"DIN", "DIN1",
};
-static const struct soc_enum i2s_din_enum =
- SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 1, 2, i2s_din_text);
+static SOC_ENUM_SINGLE_DECL(i2s_din_enum,
+ PM860X_I2S_IFACE_3, 1, i2s_din_text);
static const struct snd_kcontrol_new i2s_din_mux =
SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum);
@@ -583,8 +583,8 @@ static const char *i2s_mic_text[] = {
"Ex PA", "ADC",
};
-static const struct soc_enum i2s_mic_enum =
- SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 4, 2, i2s_mic_text);
+static SOC_ENUM_SINGLE_DECL(i2s_mic_enum,
+ PM860X_I2S_IFACE_3, 4, i2s_mic_text);
static const struct snd_kcontrol_new i2s_mic_mux =
SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum);
@@ -594,8 +594,8 @@ static const char *adcl_text[] = {
"ADCR", "ADCL",
};
-static const struct soc_enum adcl_enum =
- SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 4, 2, adcl_text);
+static SOC_ENUM_SINGLE_DECL(adcl_enum,
+ PM860X_PCM_IFACE_3, 4, adcl_text);
static const struct snd_kcontrol_new adcl_mux =
SOC_DAPM_ENUM("ADC Left Mux", adcl_enum);
@@ -605,8 +605,8 @@ static const char *adcr_text[] = {
"ADCL", "ADCR",
};
-static const struct soc_enum adcr_enum =
- SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 2, 2, adcr_text);
+static SOC_ENUM_SINGLE_DECL(adcr_enum,
+ PM860X_PCM_IFACE_3, 2, adcr_text);
static const struct snd_kcontrol_new adcr_mux =
SOC_DAPM_ENUM("ADC Right Mux", adcr_enum);
@@ -616,8 +616,8 @@ static const char *adcr_ec_text[] = {
"ADCR", "EC",
};
-static const struct soc_enum adcr_ec_enum =
- SOC_ENUM_SINGLE(PM860X_ADC_EN_2, 3, 2, adcr_ec_text);
+static SOC_ENUM_SINGLE_DECL(adcr_ec_enum,
+ PM860X_ADC_EN_2, 3, adcr_ec_text);
static const struct snd_kcontrol_new adcr_ec_mux =
SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum);
@@ -627,8 +627,8 @@ static const char *ec_text[] = {
"Left", "Right", "Left + Right",
};
-static const struct soc_enum ec_enum =
- SOC_ENUM_SINGLE(PM860X_EC_PATH, 1, 3, ec_text);
+static SOC_ENUM_SINGLE_DECL(ec_enum,
+ PM860X_EC_PATH, 1, ec_text);
static const struct snd_kcontrol_new ec_mux =
SOC_DAPM_ENUM("EC Mux", ec_enum);
@@ -638,36 +638,36 @@ static const char *dac_text[] = {
};
/* DAC Headset 1 Mux / Mux10 */
-static const struct soc_enum dac_hs1_enum =
- SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 0, 4, dac_text);
+static SOC_ENUM_SINGLE_DECL(dac_hs1_enum,
+ PM860X_ANA_INPUT_SEL_1, 0, dac_text);
static const struct snd_kcontrol_new dac_hs1_mux =
SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum);
/* DAC Headset 2 Mux / Mux11 */
-static const struct soc_enum dac_hs2_enum =
- SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 2, 4, dac_text);
+static SOC_ENUM_SINGLE_DECL(dac_hs2_enum,
+ PM860X_ANA_INPUT_SEL_1, 2, dac_text);
static const struct snd_kcontrol_new dac_hs2_mux =
SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum);
/* DAC Lineout 1 Mux / Mux12 */
-static const struct soc_enum dac_lo1_enum =
- SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 4, 4, dac_text);
+static SOC_ENUM_SINGLE_DECL(dac_lo1_enum,
+ PM860X_ANA_INPUT_SEL_1, 4, dac_text);
static const struct snd_kcontrol_new dac_lo1_mux =
SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum);
/* DAC Lineout 2 Mux / Mux13 */
-static const struct soc_enum dac_lo2_enum =
- SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 6, 4, dac_text);
+static SOC_ENUM_SINGLE_DECL(dac_lo2_enum,
+ PM860X_ANA_INPUT_SEL_1, 6, dac_text);
static const struct snd_kcontrol_new dac_lo2_mux =
SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum);
/* DAC Spearker Earphone Mux / Mux14 */
-static const struct soc_enum dac_spk_ear_enum =
- SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_2, 0, 4, dac_text);
+static SOC_ENUM_SINGLE_DECL(dac_spk_ear_enum,
+ PM860X_ANA_INPUT_SEL_2, 0, dac_text);
static const struct snd_kcontrol_new dac_spk_ear_mux =
SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum);
@@ -677,29 +677,29 @@ static const char *in_text[] = {
"Digital", "Analog",
};
-static const struct soc_enum hs1_enum =
- SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 0, 2, in_text);
+static SOC_ENUM_SINGLE_DECL(hs1_enum,
+ PM860X_ANA_TO_ANA, 0, in_text);
static const struct snd_kcontrol_new hs1_mux =
SOC_DAPM_ENUM("Headset1 Mux", hs1_enum);
/* Headset 2 Mux / Mux16 */
-static const struct soc_enum hs2_enum =
- SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 1, 2, in_text);
+static SOC_ENUM_SINGLE_DECL(hs2_enum,
+ PM860X_ANA_TO_ANA, 1, in_text);
static const struct snd_kcontrol_new hs2_mux =
SOC_DAPM_ENUM("Headset2 Mux", hs2_enum);
/* Lineout 1 Mux / Mux17 */
-static const struct soc_enum lo1_enum =
- SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 2, 2, in_text);
+static SOC_ENUM_SINGLE_DECL(lo1_enum,
+ PM860X_ANA_TO_ANA, 2, in_text);
static const struct snd_kcontrol_new lo1_mux =
SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum);
/* Lineout 2 Mux / Mux18 */
-static const struct soc_enum lo2_enum =
- SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 3, 2, in_text);
+static SOC_ENUM_SINGLE_DECL(lo2_enum,
+ PM860X_ANA_TO_ANA, 3, in_text);
static const struct snd_kcontrol_new lo2_mux =
SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum);
@@ -709,8 +709,8 @@ static const char *spk_text[] = {
"Earpiece", "Speaker",
};
-static const struct soc_enum spk_enum =
- SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 6, 2, spk_text);
+static SOC_ENUM_SINGLE_DECL(spk_enum,
+ PM860X_ANA_TO_ANA, 6, spk_text);
static const struct snd_kcontrol_new spk_demux =
SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum);
@@ -720,8 +720,8 @@ static const char *mic_text[] = {
"Mic 1", "Mic 2",
};
-static const struct soc_enum mic_enum =
- SOC_ENUM_SINGLE(PM860X_ADC_ANA_4, 4, 2, mic_text);
+static SOC_ENUM_SINGLE_DECL(mic_enum,
+ PM860X_ADC_ANA_4, 4, mic_text);
static const struct snd_kcontrol_new mic_mux =
SOC_DAPM_ENUM("MIC Mux", mic_enum);
@@ -1327,7 +1327,9 @@ static int pm860x_probe(struct snd_soc_codec *codec)
pm860x->codec = codec;
- codec->control_data = pm860x->regmap;
+ ret = snd_soc_codec_set_cache_io(codec, pm860x->regmap);
+ if (ret)
+ return ret;
for (i = 0; i < 4; i++) {
ret = request_threaded_irq(pm860x->irq[i], NULL,
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 983d087aa92a..f0e840137887 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -8,6 +8,8 @@ config SND_SOC_I2C_AND_SPI
default y if I2C=y
default y if SPI_MASTER=y
+menu "CODEC drivers"
+
config SND_SOC_ALL_CODECS
tristate "Build all ASoC CODEC drivers"
depends on COMPILE_TEST
@@ -16,15 +18,20 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AB8500_CODEC if ABX500_CORE
select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
select SND_SOC_AD1836 if SPI_MASTER
- select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
+ select SND_SOC_AD193X_SPI if SPI_MASTER
+ select SND_SOC_AD193X_I2C if I2C
select SND_SOC_AD1980 if SND_SOC_AC97_BUS
select SND_SOC_AD73311
select SND_SOC_ADAU1373 if I2C
- select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
+ select SND_SOC_ADAV801 if SPI_MASTER
+ select SND_SOC_ADAV803 if I2C
+ select SND_SOC_ADAU1977_SPI if SPI_MASTER
+ select SND_SOC_ADAU1977_I2C if I2C
select SND_SOC_ADAU1701 if I2C
select SND_SOC_ADS117X
select SND_SOC_AK4104 if SPI_MASTER
select SND_SOC_AK4535 if I2C
+ select SND_SOC_AK4554
select SND_SOC_AK4641 if I2C
select SND_SOC_AK4642 if I2C
select SND_SOC_AK4671 if I2C
@@ -37,6 +44,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS42L73 if I2C
select SND_SOC_CS4270 if I2C
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
+ select SND_SOC_CS42XX8_I2C if I2C
select SND_SOC_CX20442 if TTY
select SND_SOC_DA7210 if I2C
select SND_SOC_DA7213 if I2C
@@ -59,20 +67,26 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM1681 if I2C
select SND_SOC_PCM1792A if SPI_MASTER
select SND_SOC_PCM3008
+ select SND_SOC_PCM512x_I2C if I2C
+ select SND_SOC_PCM512x_SPI if SPI_MASTER
select SND_SOC_RT5631 if I2C
select SND_SOC_RT5640 if I2C
select SND_SOC_SGTL5000 if I2C
select SND_SOC_SI476X if MFD_SI476X_CORE
+ select SND_SOC_SIRF_AUDIO_CODEC
select SND_SOC_SN95031 if INTEL_SCU_IPC
select SND_SOC_SPDIF
select SND_SOC_SSM2518 if I2C
- select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI
+ select SND_SOC_SSM2602_SPI if SPI_MASTER
+ select SND_SOC_SSM2602_I2C if I2C
select SND_SOC_STA32X if I2C
select SND_SOC_STA529 if I2C
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
select SND_SOC_TAS5086 if I2C
- select SND_SOC_TLV320AIC23 if I2C
+ select SND_SOC_TLV320AIC23_I2C if I2C
+ select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
select SND_SOC_TLV320AIC26 if SPI_MASTER
+ select SND_SOC_TLV320AIC31XX if I2C
select SND_SOC_TLV320AIC32X4 if I2C
select SND_SOC_TLV320AIC3X if I2C
select SND_SOC_TPA6130A2 if I2C
@@ -182,6 +196,14 @@ config SND_SOC_AD1836
config SND_SOC_AD193X
tristate
+config SND_SOC_AD193X_SPI
+ tristate
+ select SND_SOC_AD193X
+
+config SND_SOC_AD193X_I2C
+ tristate
+ select SND_SOC_AD193X
+
config SND_SOC_AD1980
tristate
@@ -189,41 +211,66 @@ config SND_SOC_AD73311
tristate
config SND_SOC_ADAU1701
+ tristate "Analog Devices ADAU1701 CODEC"
+ depends on I2C
select SND_SOC_SIGMADSP
- tristate
config SND_SOC_ADAU1373
tristate
+config SND_SOC_ADAU1977
+ tristate
+
+config SND_SOC_ADAU1977_SPI
+ tristate
+ select SND_SOC_ADAU1977
+ select REGMAP_SPI
+
+config SND_SOC_ADAU1977_I2C
+ tristate
+ select SND_SOC_ADAU1977
+ select REGMAP_I2C
+
config SND_SOC_ADAV80X
tristate
+config SND_SOC_ADAV801
+ tristate
+ select SND_SOC_ADAV80X
+
+config SND_SOC_ADAV803
+ tristate
+ select SND_SOC_ADAV80X
+
config SND_SOC_ADS117X
tristate
config SND_SOC_AK4104
- tristate
+ tristate "AKM AK4104 CODEC"
+ depends on SPI_MASTER
config SND_SOC_AK4535
tristate
config SND_SOC_AK4554
- tristate
+ tristate "AKM AK4554 CODEC"
config SND_SOC_AK4641
tristate
config SND_SOC_AK4642
- tristate
+ tristate "AKM AK4642 CODEC"
+ depends on I2C
config SND_SOC_AK4671
tristate
config SND_SOC_AK5386
- tristate
+ tristate "AKM AK5638 CODEC"
config SND_SOC_ALC5623
tristate
+
config SND_SOC_ALC5632
tristate
@@ -234,14 +281,17 @@ config SND_SOC_CS42L51
tristate
config SND_SOC_CS42L52
- tristate
+ tristate "Cirrus Logic CS42L52 CODEC"
+ depends on I2C
config SND_SOC_CS42L73
- tristate
+ tristate "Cirrus Logic CS42L73 CODEC"
+ depends on I2C
# Cirrus Logic CS4270 Codec
config SND_SOC_CS4270
- tristate
+ tristate "Cirrus Logic CS4270 CODEC"
+ depends on I2C
# Cirrus Logic CS4270 Codec VD = 3.3V Errata
# Select if you are affected by the errata where the part will not function
@@ -252,8 +302,18 @@ config SND_SOC_CS4270_VD33_ERRATA
depends on SND_SOC_CS4270
config SND_SOC_CS4271
+ tristate "Cirrus Logic CS4271 CODEC"
+ depends on SND_SOC_I2C_AND_SPI
+
+config SND_SOC_CS42XX8
tristate
+config SND_SOC_CS42XX8_I2C
+ tristate "Cirrus Logic CS42448/CS42888 CODEC (I2C)"
+ depends on I2C
+ select SND_SOC_CS42XX8
+ select REGMAP_I2C
+
config SND_SOC_CX20442
tristate
depends on TTY
@@ -283,6 +343,9 @@ config SND_SOC_BT_SCO
config SND_SOC_DMIC
tristate
+config SND_SOC_HDMI_CODEC
+ tristate "HDMI stub CODEC"
+
config SND_SOC_ISABELLE
tristate
@@ -301,18 +364,32 @@ config SND_SOC_MAX98095
config SND_SOC_MAX9850
tristate
-config SND_SOC_HDMI_CODEC
- tristate
-
config SND_SOC_PCM1681
- tristate
+ tristate "Texas Instruments PCM1681 CODEC"
+ depends on I2C
config SND_SOC_PCM1792A
- tristate
+ tristate "Texas Instruments PCM1792A CODEC"
+ depends on SPI_MASTER
config SND_SOC_PCM3008
tristate
+config SND_SOC_PCM512x
+ tristate
+
+config SND_SOC_PCM512x_I2C
+ tristate "Texas Instruments PCM512x CODECs - I2C"
+ depends on I2C
+ select SND_SOC_PCM512x
+ select REGMAP_I2C
+
+config SND_SOC_PCM512x_SPI
+ tristate "Texas Instruments PCM512x CODECs - SPI"
+ depends on SPI_MASTER
+ select SND_SOC_PCM512x
+ select REGMAP_SPI
+
config SND_SOC_RT5631
tristate
@@ -321,7 +398,8 @@ config SND_SOC_RT5640
#Freescale sgtl5000 codec
config SND_SOC_SGTL5000
- tristate
+ tristate "Freescale SGTL5000 CODEC"
+ depends on I2C
config SND_SOC_SI476X
tristate
@@ -330,11 +408,15 @@ config SND_SOC_SIGMADSP
tristate
select CRC32
+config SND_SOC_SIRF_AUDIO_CODEC
+ tristate "SiRF SoC internal audio codec"
+ select REGMAP_MMIO
+
config SND_SOC_SN95031
tristate
config SND_SOC_SPDIF
- tristate
+ tristate "S/PDIF CODEC"
config SND_SOC_SSM2518
tristate
@@ -342,6 +424,14 @@ config SND_SOC_SSM2518
config SND_SOC_SSM2602
tristate
+config SND_SOC_SSM2602_SPI
+ select SND_SOC_SSM2602
+ tristate
+
+config SND_SOC_SSM2602_I2C
+ select SND_SOC_SSM2602
+ tristate
+
config SND_SOC_STA32X
tristate
@@ -352,20 +442,33 @@ config SND_SOC_STAC9766
tristate
config SND_SOC_TAS5086
- tristate
+ tristate "Texas Instruments TAS5086 speaker amplifier"
+ depends on I2C
config SND_SOC_TLV320AIC23
tristate
+config SND_SOC_TLV320AIC23_I2C
+ tristate
+ select SND_SOC_TLV320AIC23
+
+config SND_SOC_TLV320AIC23_SPI
+ tristate
+ select SND_SOC_TLV320AIC23
+
config SND_SOC_TLV320AIC26
tristate
depends on SPI
+config SND_SOC_TLV320AIC31XX
+ tristate
+
config SND_SOC_TLV320AIC32X4
tristate
config SND_SOC_TLV320AIC3X
- tristate
+ tristate "Texas Instruments TLV320AIC3x CODECs"
+ depends on I2C
config SND_SOC_TLV320DAC33
tristate
@@ -414,55 +517,69 @@ config SND_SOC_WM8400
tristate
config SND_SOC_WM8510
- tristate
+ tristate "Wolfson Microelectronics WM8510 CODEC"
+ depends on SND_SOC_I2C_AND_SPI
config SND_SOC_WM8523
- tristate
+ tristate "Wolfson Microelectronics WM8523 DAC"
+ depends on I2C
config SND_SOC_WM8580
- tristate
+ tristate "Wolfson Microelectronics WM8523 CODEC"
+ depends on I2C
config SND_SOC_WM8711
- tristate
+ tristate "Wolfson Microelectronics WM8711 CODEC"
+ depends on SND_SOC_I2C_AND_SPI
config SND_SOC_WM8727
tristate
config SND_SOC_WM8728
- tristate
+ tristate "Wolfson Microelectronics WM8728 DAC"
+ depends on SND_SOC_I2C_AND_SPI
config SND_SOC_WM8731
- tristate
+ tristate "Wolfson Microelectronics WM8731 CODEC"
+ depends on SND_SOC_I2C_AND_SPI
config SND_SOC_WM8737
- tristate
+ tristate "Wolfson Microelectronics WM8737 ADC"
+ depends on SND_SOC_I2C_AND_SPI
config SND_SOC_WM8741
- tristate
+ tristate "Wolfson Microelectronics WM8737 DAC"
+ depends on SND_SOC_I2C_AND_SPI
config SND_SOC_WM8750
- tristate
+ tristate "Wolfson Microelectronics WM8750 CODEC"
+ depends on SND_SOC_I2C_AND_SPI
config SND_SOC_WM8753
- tristate
+ tristate "Wolfson Microelectronics WM8753 CODEC"
+ depends on SND_SOC_I2C_AND_SPI
config SND_SOC_WM8770
- tristate
+ tristate "Wolfson Microelectronics WM8770 CODEC"
+ depends on SPI_MASTER
config SND_SOC_WM8776
- tristate
+ tristate "Wolfson Microelectronics WM8776 CODEC"
+ depends on SND_SOC_I2C_AND_SPI
config SND_SOC_WM8782
tristate
config SND_SOC_WM8804
- tristate
+ tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver"
+ depends on SND_SOC_I2C_AND_SPI
config SND_SOC_WM8900
tristate
config SND_SOC_WM8903
- tristate
+ tristate "Wolfson Microelectronics WM8903 CODEC"
+ depends on I2C
config SND_SOC_WM8904
tristate
@@ -480,7 +597,8 @@ config SND_SOC_WM8961
tristate
config SND_SOC_WM8962
- tristate
+ tristate "Wolfson Microelectronics WM8962 CODEC"
+ depends on I2C
config SND_SOC_WM8971
tristate
@@ -553,4 +671,7 @@ config SND_SOC_ML26124
tristate
config SND_SOC_TPA6130A2
- tristate
+ tristate "Texas Instruments TPA6130A2 headphone amplifier"
+ depends on I2C
+
+endmenu
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index bc126764a44d..3c4d275d064b 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -3,11 +3,18 @@ snd-soc-ab8500-codec-objs := ab8500-codec.o
snd-soc-ac97-objs := ac97.o
snd-soc-ad1836-objs := ad1836.o
snd-soc-ad193x-objs := ad193x.o
+snd-soc-ad193x-spi-objs := ad193x-spi.o
+snd-soc-ad193x-i2c-objs := ad193x-i2c.o
snd-soc-ad1980-objs := ad1980.o
snd-soc-ad73311-objs := ad73311.o
snd-soc-adau1701-objs := adau1701.o
snd-soc-adau1373-objs := adau1373.o
+snd-soc-adau1977-objs := adau1977.o
+snd-soc-adau1977-spi-objs := adau1977-spi.o
+snd-soc-adau1977-i2c-objs := adau1977-i2c.o
snd-soc-adav80x-objs := adav80x.o
+snd-soc-adav801-objs := adav801.o
+snd-soc-adav803-objs := adav803.o
snd-soc-ads117x-objs := ads117x.o
snd-soc-ak4104-objs := ak4104.o
snd-soc-ak4535-objs := ak4535.o
@@ -23,6 +30,8 @@ snd-soc-cs42l52-objs := cs42l52.o
snd-soc-cs42l73-objs := cs42l73.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cs4271-objs := cs4271.o
+snd-soc-cs42xx8-objs := cs42xx8.o
+snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
snd-soc-da7213-objs := da7213.o
@@ -46,6 +55,9 @@ snd-soc-hdmi-codec-objs := hdmi.o
snd-soc-pcm1681-objs := pcm1681.o
snd-soc-pcm1792a-codec-objs := pcm1792a.o
snd-soc-pcm3008-objs := pcm3008.o
+snd-soc-pcm512x-objs := pcm512x.o
+snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
+snd-soc-pcm512x-spi-objs := pcm512x-spi.o
snd-soc-rt5631-objs := rt5631.o
snd-soc-rt5640-objs := rt5640.o
snd-soc-sgtl5000-objs := sgtl5000.o
@@ -53,19 +65,25 @@ snd-soc-alc5623-objs := alc5623.o
snd-soc-alc5632-objs := alc5632.o
snd-soc-sigmadsp-objs := sigmadsp.o
snd-soc-si476x-objs := si476x.o
+snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
snd-soc-sn95031-objs := sn95031.o
snd-soc-spdif-tx-objs := spdif_transmitter.o
snd-soc-spdif-rx-objs := spdif_receiver.o
snd-soc-ssm2518-objs := ssm2518.o
snd-soc-ssm2602-objs := ssm2602.o
+snd-soc-ssm2602-spi-objs := ssm2602-spi.o
+snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o
snd-soc-sta32x-objs := sta32x.o
snd-soc-sta529-objs := sta529.o
snd-soc-stac9766-objs := stac9766.o
snd-soc-tas5086-objs := tas5086.o
snd-soc-tlv320aic23-objs := tlv320aic23.o
+snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
+snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
snd-soc-tlv320aic26-objs := tlv320aic26.o
-snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
+snd-soc-tlv320aic3x-objs := tlv320aic3x.o
snd-soc-tlv320dac33-objs := tlv320dac33.o
snd-soc-twl4030-objs := twl4030.o
snd-soc-twl6040-objs := twl6040.o
@@ -134,11 +152,18 @@ obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
+obj-$(CONFIG_SND_SOC_AD193X_SPI) += snd-soc-ad193x-spi.o
+obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o
+obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o
+obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o
+obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o
obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o
obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
+obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
+obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o
obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o
obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
@@ -156,6 +181,8 @@ obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
+obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o
+obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o
@@ -179,6 +206,9 @@ obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
+obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o
+obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
+obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
@@ -188,14 +218,19 @@ obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
+obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o
+obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o
obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o
obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
+obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
+obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o
obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
-obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
+obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o
obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o
+obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 77f459868579..685998dd086e 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -40,8 +40,8 @@ struct ad1836_priv {
*/
static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"};
-static const struct soc_enum ad1836_deemp_enum =
- SOC_ENUM_SINGLE(AD1836_DAC_CTRL1, 8, 4, ad1836_deemp);
+static SOC_ENUM_SINGLE_DECL(ad1836_deemp_enum,
+ AD1836_DAC_CTRL1, 8, ad1836_deemp);
#define AD1836_DAC_VOLUME(x) \
SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \
diff --git a/sound/soc/codecs/ad193x-i2c.c b/sound/soc/codecs/ad193x-i2c.c
new file mode 100644
index 000000000000..df3a1a415825
--- /dev/null
+++ b/sound/soc/codecs/ad193x-i2c.c
@@ -0,0 +1,54 @@
+/*
+ * AD1936/AD1937 audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "ad193x.h"
+
+static const struct i2c_device_id ad193x_id[] = {
+ { "ad1936", 0 },
+ { "ad1937", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ad193x_id);
+
+static int ad193x_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct regmap_config config;
+
+ config = ad193x_regmap_config;
+ config.val_bits = 8;
+ config.reg_bits = 8;
+
+ return ad193x_probe(&client->dev, devm_regmap_init_i2c(client, &config));
+}
+
+static int ad193x_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static struct i2c_driver ad193x_i2c_driver = {
+ .driver = {
+ .name = "ad193x",
+ },
+ .probe = ad193x_i2c_probe,
+ .remove = ad193x_i2c_remove,
+ .id_table = ad193x_id,
+};
+module_i2c_driver(ad193x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC AD1936/AD1937 audio CODEC driver");
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad193x-spi.c b/sound/soc/codecs/ad193x-spi.c
new file mode 100644
index 000000000000..390cef9b9dc2
--- /dev/null
+++ b/sound/soc/codecs/ad193x-spi.c
@@ -0,0 +1,48 @@
+/*
+ * AD1938/AD1939 audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "ad193x.h"
+
+static int ad193x_spi_probe(struct spi_device *spi)
+{
+ struct regmap_config config;
+
+ config = ad193x_regmap_config;
+ config.val_bits = 8;
+ config.reg_bits = 16;
+ config.read_flag_mask = 0x09;
+ config.write_flag_mask = 0x08;
+
+ return ad193x_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
+}
+
+static int ad193x_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ return 0;
+}
+
+static struct spi_driver ad193x_spi_driver = {
+ .driver = {
+ .name = "ad193x",
+ .owner = THIS_MODULE,
+ },
+ .probe = ad193x_spi_probe,
+ .remove = ad193x_spi_remove,
+};
+module_spi_driver(ad193x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC AD1938/AD1939 audio CODEC driver");
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index 5a42dca535b7..6844d0b2af68 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -6,12 +6,10 @@
* Licensed under the GPL-2 or later.
*/
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
-#include <linux/i2c.h>
-#include <linux/spi/spi.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -19,6 +17,7 @@
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/tlv.h>
+
#include "ad193x.h"
/* codec private data */
@@ -32,8 +31,8 @@ struct ad193x_priv {
*/
static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};
-static const struct soc_enum ad193x_deemp_enum =
- SOC_ENUM_SINGLE(AD193X_DAC_CTRL2, 1, 4, ad193x_deemp);
+static SOC_ENUM_SINGLE_DECL(ad193x_deemp_enum, AD193X_DAC_CTRL2, 1,
+ ad193x_deemp);
static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0);
@@ -320,17 +319,9 @@ static struct snd_soc_dai_driver ad193x_dai = {
.ops = &ad193x_dai_ops,
};
-static int ad193x_probe(struct snd_soc_codec *codec)
+static int ad193x_codec_probe(struct snd_soc_codec *codec)
{
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- codec->control_data = ad193x->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
- return ret;
- }
/* default setting for ad193x */
@@ -348,11 +339,11 @@ static int ad193x_probe(struct snd_soc_codec *codec)
regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL1, 0x04);
- return ret;
+ return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
- .probe = ad193x_probe,
+ .probe = ad193x_codec_probe,
.controls = ad193x_snd_controls,
.num_controls = ARRAY_SIZE(ad193x_snd_controls),
.dapm_widgets = ad193x_dapm_widgets,
@@ -366,140 +357,31 @@ static bool adau193x_reg_volatile(struct device *dev, unsigned int reg)
return false;
}
-#if defined(CONFIG_SPI_MASTER)
-
-static const struct regmap_config ad193x_spi_regmap_config = {
- .val_bits = 8,
- .reg_bits = 16,
- .read_flag_mask = 0x09,
- .write_flag_mask = 0x08,
-
+const struct regmap_config ad193x_regmap_config = {
.max_register = AD193X_NUM_REGS - 1,
.volatile_reg = adau193x_reg_volatile,
};
+EXPORT_SYMBOL_GPL(ad193x_regmap_config);
-static int ad193x_spi_probe(struct spi_device *spi)
+int ad193x_probe(struct device *dev, struct regmap *regmap)
{
struct ad193x_priv *ad193x;
- ad193x = devm_kzalloc(&spi->dev, sizeof(struct ad193x_priv),
- GFP_KERNEL);
- if (ad193x == NULL)
- return -ENOMEM;
-
- ad193x->regmap = devm_regmap_init_spi(spi, &ad193x_spi_regmap_config);
- if (IS_ERR(ad193x->regmap))
- return PTR_ERR(ad193x->regmap);
-
- spi_set_drvdata(spi, ad193x);
-
- return snd_soc_register_codec(&spi->dev, &soc_codec_dev_ad193x,
- &ad193x_dai, 1);
-}
-
-static int ad193x_spi_remove(struct spi_device *spi)
-{
- snd_soc_unregister_codec(&spi->dev);
- return 0;
-}
-
-static struct spi_driver ad193x_spi_driver = {
- .driver = {
- .name = "ad193x",
- .owner = THIS_MODULE,
- },
- .probe = ad193x_spi_probe,
- .remove = ad193x_spi_remove,
-};
-#endif
-
-#if IS_ENABLED(CONFIG_I2C)
-
-static const struct regmap_config ad193x_i2c_regmap_config = {
- .val_bits = 8,
- .reg_bits = 8,
-
- .max_register = AD193X_NUM_REGS - 1,
- .volatile_reg = adau193x_reg_volatile,
-};
-
-static const struct i2c_device_id ad193x_id[] = {
- { "ad1936", 0 },
- { "ad1937", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ad193x_id);
-
-static int ad193x_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct ad193x_priv *ad193x;
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
- ad193x = devm_kzalloc(&client->dev, sizeof(struct ad193x_priv),
- GFP_KERNEL);
+ ad193x = devm_kzalloc(dev, sizeof(*ad193x), GFP_KERNEL);
if (ad193x == NULL)
return -ENOMEM;
- ad193x->regmap = devm_regmap_init_i2c(client, &ad193x_i2c_regmap_config);
- if (IS_ERR(ad193x->regmap))
- return PTR_ERR(ad193x->regmap);
-
- i2c_set_clientdata(client, ad193x);
-
- return snd_soc_register_codec(&client->dev, &soc_codec_dev_ad193x,
- &ad193x_dai, 1);
-}
-
-static int ad193x_i2c_remove(struct i2c_client *client)
-{
- snd_soc_unregister_codec(&client->dev);
- return 0;
-}
-
-static struct i2c_driver ad193x_i2c_driver = {
- .driver = {
- .name = "ad193x",
- },
- .probe = ad193x_i2c_probe,
- .remove = ad193x_i2c_remove,
- .id_table = ad193x_id,
-};
-#endif
-
-static int __init ad193x_modinit(void)
-{
- int ret;
-
-#if IS_ENABLED(CONFIG_I2C)
- ret = i2c_add_driver(&ad193x_i2c_driver);
- if (ret != 0) {
- printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n",
- ret);
- }
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
- ret = spi_register_driver(&ad193x_spi_driver);
- if (ret != 0) {
- printk(KERN_ERR "Failed to register AD193X SPI driver: %d\n",
- ret);
- }
-#endif
- return ret;
-}
-module_init(ad193x_modinit);
+ ad193x->regmap = regmap;
-static void __exit ad193x_modexit(void)
-{
-#if defined(CONFIG_SPI_MASTER)
- spi_unregister_driver(&ad193x_spi_driver);
-#endif
+ dev_set_drvdata(dev, ad193x);
-#if IS_ENABLED(CONFIG_I2C)
- i2c_del_driver(&ad193x_i2c_driver);
-#endif
+ return snd_soc_register_codec(dev, &soc_codec_dev_ad193x,
+ &ad193x_dai, 1);
}
-module_exit(ad193x_modexit);
+EXPORT_SYMBOL_GPL(ad193x_probe);
MODULE_DESCRIPTION("ASoC ad193x driver");
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h
index 473388049992..ab9a998f15be 100644
--- a/sound/soc/codecs/ad193x.h
+++ b/sound/soc/codecs/ad193x.h
@@ -9,6 +9,13 @@
#ifndef __AD193X_H__
#define __AD193X_H__
+#include <linux/regmap.h>
+
+struct device;
+
+extern const struct regmap_config ad193x_regmap_config;
+int ad193x_probe(struct device *dev, struct regmap *regmap);
+
#define AD193X_PLL_CLK_CTRL0 0x00
#define AD193X_PLL_POWERDOWN 0x01
#define AD193X_PLL_INPUT_MASK 0x6
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 7257a8885f42..34d965a4a040 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -57,8 +57,8 @@ static const u16 ad1980_reg[] = {
static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line",
"Stereo Mix", "Mono Mix", "Phone"};
-static const struct soc_enum ad1980_cap_src =
- SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 7, ad1980_rec_sel);
+static SOC_ENUM_DOUBLE_DECL(ad1980_cap_src,
+ AC97_REC_SEL, 8, 0, ad1980_rec_sel);
static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = {
SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1),
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index eb836ed5271f..877f5737bb6b 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -345,15 +345,15 @@ static const char *adau1373_fdsp_sel_text[] = {
"Channel 5",
};
-static const SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum,
ADAU1373_FDSP_SEL1, 4, adau1373_fdsp_sel_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum,
ADAU1373_FDSP_SEL1, 0, adau1373_fdsp_sel_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum,
ADAU1373_FDSP_SEL2, 0, adau1373_fdsp_sel_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum,
ADAU1373_FDSP_SEL3, 0, adau1373_fdsp_sel_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum,
ADAU1373_FDSP_SEL4, 4, adau1373_fdsp_sel_text);
static const char *adau1373_hpf_cutoff_text[] = {
@@ -362,7 +362,7 @@ static const char *adau1373_hpf_cutoff_text[] = {
"800Hz",
};
-static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum,
ADAU1373_HPF_CTRL, 3, adau1373_hpf_cutoff_text);
static const char *adau1373_bass_lpf_cutoff_text[] = {
@@ -388,14 +388,14 @@ static const unsigned int adau1373_bass_tlv[] = {
5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0),
};
-static const SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum,
ADAU1373_BASS1, 5, adau1373_bass_lpf_cutoff_text);
-static const SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum,
+static SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum,
ADAU1373_BASS1, 2, 7, adau1373_bass_clip_level_text,
adau1373_bass_clip_level_values);
-static const SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum,
ADAU1373_BASS1, 0, adau1373_bass_hpf_cutoff_text);
static const char *adau1373_3d_level_text[] = {
@@ -409,9 +409,9 @@ static const char *adau1373_3d_cutoff_text[] = {
"0.16875 fs", "0.27083 fs"
};
-static const SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum,
ADAU1373_3D_CTRL1, 4, adau1373_3d_level_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum,
ADAU1373_3D_CTRL1, 0, adau1373_3d_cutoff_text);
static const unsigned int adau1373_3d_tlv[] = {
@@ -427,11 +427,11 @@ static const char *adau1373_lr_mux_text[] = {
"Stereo",
};
-static const SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum,
ADAU1373_OUTPUT_CTRL, 4, adau1373_lr_mux_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum,
ADAU1373_OUTPUT_CTRL, 6, adau1373_lr_mux_text);
-static const SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum,
+static SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum,
ADAU1373_LS_CTRL, 4, adau1373_lr_mux_text);
static const struct snd_kcontrol_new adau1373_controls[] = {
@@ -576,8 +576,8 @@ static const char *adau1373_decimator_text[] = {
"DMIC1",
};
-static const struct soc_enum adau1373_decimator_enum =
- SOC_ENUM_SINGLE(0, 0, 2, adau1373_decimator_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(adau1373_decimator_enum,
+ adau1373_decimator_text);
static const struct snd_kcontrol_new adau1373_decimator_mux =
SOC_DAPM_ENUM_VIRT("Decimator Mux", adau1373_decimator_enum);
@@ -1376,15 +1376,8 @@ static int adau1373_probe(struct snd_soc_codec *codec)
struct adau1373_platform_data *pdata = codec->dev->platform_data;
bool lineout_differential = false;
unsigned int val;
- int ret;
int i;
- ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
- if (ret) {
- dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
if (pdata) {
if (pdata->num_drc > ARRAY_SIZE(pdata->drc_setting))
return -EINVAL;
diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c
new file mode 100644
index 000000000000..9700e8c838c9
--- /dev/null
+++ b/sound/soc/codecs/adau1977-i2c.c
@@ -0,0 +1,59 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "adau1977.h"
+
+static int adau1977_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct regmap_config config;
+
+ config = adau1977_regmap_config;
+ config.val_bits = 8;
+ config.reg_bits = 8;
+
+ return adau1977_probe(&client->dev,
+ devm_regmap_init_i2c(client, &config),
+ id->driver_data, NULL);
+}
+
+static int adau1977_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id adau1977_i2c_ids[] = {
+ { "adau1977", ADAU1977 },
+ { "adau1978", ADAU1978 },
+ { "adau1979", ADAU1978 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids);
+
+static struct i2c_driver adau1977_i2c_driver = {
+ .driver = {
+ .name = "adau1977",
+ .owner = THIS_MODULE,
+ },
+ .probe = adau1977_i2c_probe,
+ .remove = adau1977_i2c_remove,
+ .id_table = adau1977_i2c_ids,
+};
+module_i2c_driver(adau1977_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1977-spi.c b/sound/soc/codecs/adau1977-spi.c
new file mode 100644
index 000000000000..b05cf5da3a94
--- /dev/null
+++ b/sound/soc/codecs/adau1977-spi.c
@@ -0,0 +1,76 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "adau1977.h"
+
+static void adau1977_spi_switch_mode(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+
+ /*
+ * To get the device into SPI mode CLATCH has to be pulled low three
+ * times. Do this by issuing three dummy reads.
+ */
+ spi_w8r8(spi, 0x00);
+ spi_w8r8(spi, 0x00);
+ spi_w8r8(spi, 0x00);
+}
+
+static int adau1977_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct regmap_config config;
+
+ if (!id)
+ return -EINVAL;
+
+ config = adau1977_regmap_config;
+ config.val_bits = 8;
+ config.reg_bits = 16;
+ config.read_flag_mask = 0x1;
+
+ return adau1977_probe(&spi->dev,
+ devm_regmap_init_spi(spi, &config),
+ id->driver_data, adau1977_spi_switch_mode);
+}
+
+static int adau1977_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ return 0;
+}
+
+static const struct spi_device_id adau1977_spi_ids[] = {
+ { "adau1977", ADAU1977 },
+ { "adau1978", ADAU1978 },
+ { "adau1979", ADAU1978 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, adau1977_spi_ids);
+
+static struct spi_driver adau1977_spi_driver = {
+ .driver = {
+ .name = "adau1977",
+ .owner = THIS_MODULE,
+ },
+ .probe = adau1977_spi_probe,
+ .remove = adau1977_spi_remove,
+ .id_table = adau1977_spi_ids,
+};
+module_spi_driver(adau1977_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
new file mode 100644
index 000000000000..fd55da7cb9d4
--- /dev/null
+++ b/sound/soc/codecs/adau1977.c
@@ -0,0 +1,1018 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_data/adau1977.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "adau1977.h"
+
+#define ADAU1977_REG_POWER 0x00
+#define ADAU1977_REG_PLL 0x01
+#define ADAU1977_REG_BOOST 0x02
+#define ADAU1977_REG_MICBIAS 0x03
+#define ADAU1977_REG_BLOCK_POWER_SAI 0x04
+#define ADAU1977_REG_SAI_CTRL0 0x05
+#define ADAU1977_REG_SAI_CTRL1 0x06
+#define ADAU1977_REG_CMAP12 0x07
+#define ADAU1977_REG_CMAP34 0x08
+#define ADAU1977_REG_SAI_OVERTEMP 0x09
+#define ADAU1977_REG_POST_ADC_GAIN(x) (0x0a + (x))
+#define ADAU1977_REG_MISC_CONTROL 0x0e
+#define ADAU1977_REG_DIAG_CONTROL 0x10
+#define ADAU1977_REG_STATUS(x) (0x11 + (x))
+#define ADAU1977_REG_DIAG_IRQ1 0x15
+#define ADAU1977_REG_DIAG_IRQ2 0x16
+#define ADAU1977_REG_ADJUST1 0x17
+#define ADAU1977_REG_ADJUST2 0x18
+#define ADAU1977_REG_ADC_CLIP 0x19
+#define ADAU1977_REG_DC_HPF_CAL 0x1a
+
+#define ADAU1977_POWER_RESET BIT(7)
+#define ADAU1977_POWER_PWUP BIT(0)
+
+#define ADAU1977_PLL_CLK_S BIT(4)
+#define ADAU1977_PLL_MCS_MASK 0x7
+
+#define ADAU1977_MICBIAS_MB_VOLTS_MASK 0xf0
+#define ADAU1977_MICBIAS_MB_VOLTS_OFFSET 4
+
+#define ADAU1977_BLOCK_POWER_SAI_LR_POL BIT(7)
+#define ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE BIT(6)
+#define ADAU1977_BLOCK_POWER_SAI_LDO_EN BIT(5)
+
+#define ADAU1977_SAI_CTRL0_FMT_MASK (0x3 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_I2S (0x0 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_LJ (0x1 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_RJ_24BIT (0x2 << 6)
+#define ADAU1977_SAI_CTRL0_FMT_RJ_16BIT (0x3 << 6)
+
+#define ADAU1977_SAI_CTRL0_SAI_MASK (0x7 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_I2S (0x0 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_2 (0x1 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_4 (0x2 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_8 (0x3 << 3)
+#define ADAU1977_SAI_CTRL0_SAI_TDM_16 (0x4 << 3)
+
+#define ADAU1977_SAI_CTRL0_FS_MASK (0x7)
+#define ADAU1977_SAI_CTRL0_FS_8000_12000 (0x0)
+#define ADAU1977_SAI_CTRL0_FS_16000_24000 (0x1)
+#define ADAU1977_SAI_CTRL0_FS_32000_48000 (0x2)
+#define ADAU1977_SAI_CTRL0_FS_64000_96000 (0x3)
+#define ADAU1977_SAI_CTRL0_FS_128000_192000 (0x4)
+
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK (0x3 << 5)
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_32 (0x0 << 5)
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_24 (0x1 << 5)
+#define ADAU1977_SAI_CTRL1_SLOT_WIDTH_16 (0x2 << 5)
+#define ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK (0x1 << 4)
+#define ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT (0x1 << 4)
+#define ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT (0x0 << 4)
+#define ADAU1977_SAI_CTRL1_LRCLK_PULSE BIT(3)
+#define ADAU1977_SAI_CTRL1_MSB BIT(2)
+#define ADAU1977_SAI_CTRL1_BCLKRATE_16 (0x1 << 1)
+#define ADAU1977_SAI_CTRL1_BCLKRATE_32 (0x0 << 1)
+#define ADAU1977_SAI_CTRL1_BCLKRATE_MASK (0x1 << 1)
+#define ADAU1977_SAI_CTRL1_MASTER BIT(0)
+
+#define ADAU1977_SAI_OVERTEMP_DRV_C(x) BIT(4 + (x))
+#define ADAU1977_SAI_OVERTEMP_DRV_HIZ BIT(3)
+
+#define ADAU1977_MISC_CONTROL_SUM_MODE_MASK (0x3 << 6)
+#define ADAU1977_MISC_CONTROL_SUM_MODE_1CH (0x2 << 6)
+#define ADAU1977_MISC_CONTROL_SUM_MODE_2CH (0x1 << 6)
+#define ADAU1977_MISC_CONTROL_SUM_MODE_4CH (0x0 << 6)
+#define ADAU1977_MISC_CONTROL_MMUTE BIT(4)
+#define ADAU1977_MISC_CONTROL_DC_CAL BIT(0)
+
+#define ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET 4
+#define ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET 0
+
+struct adau1977 {
+ struct regmap *regmap;
+ bool right_j;
+ unsigned int sysclk;
+ enum adau1977_sysclk_src sysclk_src;
+ struct gpio_desc *reset_gpio;
+ enum adau1977_type type;
+
+ struct regulator *avdd_reg;
+ struct regulator *dvdd_reg;
+
+ struct snd_pcm_hw_constraint_list constraints;
+
+ struct device *dev;
+ void (*switch_mode)(struct device *dev);
+
+ unsigned int max_master_fs;
+ unsigned int slot_width;
+ bool enabled;
+ bool master;
+};
+
+static const struct reg_default adau1977_reg_defaults[] = {
+ { 0x00, 0x00 },
+ { 0x01, 0x41 },
+ { 0x02, 0x4a },
+ { 0x03, 0x7d },
+ { 0x04, 0x3d },
+ { 0x05, 0x02 },
+ { 0x06, 0x00 },
+ { 0x07, 0x10 },
+ { 0x08, 0x32 },
+ { 0x09, 0xf0 },
+ { 0x0a, 0xa0 },
+ { 0x0b, 0xa0 },
+ { 0x0c, 0xa0 },
+ { 0x0d, 0xa0 },
+ { 0x0e, 0x02 },
+ { 0x10, 0x0f },
+ { 0x15, 0x20 },
+ { 0x16, 0x00 },
+ { 0x17, 0x00 },
+ { 0x18, 0x00 },
+ { 0x1a, 0x00 },
+};
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(adau1977_adc_gain, -3562, 6000);
+
+static const struct snd_soc_dapm_widget adau1977_micbias_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU1977_REG_MICBIAS,
+ 3, 0, NULL, 0)
+};
+
+static const struct snd_soc_dapm_widget adau1977_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("Vref", ADAU1977_REG_BLOCK_POWER_SAI,
+ 4, 0, NULL, 0),
+
+ SND_SOC_DAPM_ADC("ADC1", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 0, 0),
+ SND_SOC_DAPM_ADC("ADC2", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 1, 0),
+ SND_SOC_DAPM_ADC("ADC3", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 2, 0),
+ SND_SOC_DAPM_ADC("ADC4", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 3, 0),
+
+ SND_SOC_DAPM_INPUT("AIN1"),
+ SND_SOC_DAPM_INPUT("AIN2"),
+ SND_SOC_DAPM_INPUT("AIN3"),
+ SND_SOC_DAPM_INPUT("AIN4"),
+
+ SND_SOC_DAPM_OUTPUT("VREF"),
+};
+
+static const struct snd_soc_dapm_route adau1977_dapm_routes[] = {
+ { "ADC1", NULL, "AIN1" },
+ { "ADC2", NULL, "AIN2" },
+ { "ADC3", NULL, "AIN3" },
+ { "ADC4", NULL, "AIN4" },
+
+ { "ADC1", NULL, "Vref" },
+ { "ADC2", NULL, "Vref" },
+ { "ADC3", NULL, "Vref" },
+ { "ADC4", NULL, "Vref" },
+
+ { "VREF", NULL, "Vref" },
+};
+
+#define ADAU1977_VOLUME(x) \
+ SOC_SINGLE_TLV("ADC" #x " Capture Volume", \
+ ADAU1977_REG_POST_ADC_GAIN((x) - 1), \
+ 0, 255, 1, adau1977_adc_gain)
+
+#define ADAU1977_HPF_SWITCH(x) \
+ SOC_SINGLE("ADC" #x " Highpass-Filter Capture Switch", \
+ ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0)
+
+#define ADAU1977_DC_SUB_SWITCH(x) \
+ SOC_SINGLE("ADC" #x " DC Substraction Capture Switch", \
+ ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0)
+
+static const struct snd_kcontrol_new adau1977_snd_controls[] = {
+ ADAU1977_VOLUME(1),
+ ADAU1977_VOLUME(2),
+ ADAU1977_VOLUME(3),
+ ADAU1977_VOLUME(4),
+
+ ADAU1977_HPF_SWITCH(1),
+ ADAU1977_HPF_SWITCH(2),
+ ADAU1977_HPF_SWITCH(3),
+ ADAU1977_HPF_SWITCH(4),
+
+ ADAU1977_DC_SUB_SWITCH(1),
+ ADAU1977_DC_SUB_SWITCH(2),
+ ADAU1977_DC_SUB_SWITCH(3),
+ ADAU1977_DC_SUB_SWITCH(4),
+};
+
+static int adau1977_reset(struct adau1977 *adau1977)
+{
+ int ret;
+
+ /*
+ * The reset bit is obviously volatile, but we need to be able to cache
+ * the other bits in the register, so we can't just mark the whole
+ * register as volatile. Since this is the only place where we'll ever
+ * touch the reset bit just bypass the cache for this operation.
+ */
+ regcache_cache_bypass(adau1977->regmap, true);
+ ret = regmap_write(adau1977->regmap, ADAU1977_REG_POWER,
+ ADAU1977_POWER_RESET);
+ regcache_cache_bypass(adau1977->regmap, false);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+/*
+ * Returns the appropriate setting for ths FS field in the CTRL0 register
+ * depending on the rate.
+ */
+static int adau1977_lookup_fs(unsigned int rate)
+{
+ if (rate >= 8000 && rate <= 12000)
+ return ADAU1977_SAI_CTRL0_FS_8000_12000;
+ else if (rate >= 16000 && rate <= 24000)
+ return ADAU1977_SAI_CTRL0_FS_16000_24000;
+ else if (rate >= 32000 && rate <= 48000)
+ return ADAU1977_SAI_CTRL0_FS_32000_48000;
+ else if (rate >= 64000 && rate <= 96000)
+ return ADAU1977_SAI_CTRL0_FS_64000_96000;
+ else if (rate >= 128000 && rate <= 192000)
+ return ADAU1977_SAI_CTRL0_FS_128000_192000;
+ else
+ return -EINVAL;
+}
+
+static int adau1977_lookup_mcs(struct adau1977 *adau1977, unsigned int rate,
+ unsigned int fs)
+{
+ unsigned int mcs;
+
+ /*
+ * rate = sysclk / (512 * mcs_lut[mcs]) * 2**fs
+ * => mcs_lut[mcs] = sysclk / (512 * rate) * 2**fs
+ * => mcs_lut[mcs] = sysclk / ((512 / 2**fs) * rate)
+ */
+
+ rate *= 512 >> fs;
+
+ if (adau1977->sysclk % rate != 0)
+ return -EINVAL;
+
+ mcs = adau1977->sysclk / rate;
+
+ /* The factors configured by MCS are 1, 2, 3, 4, 6 */
+ if (mcs < 1 || mcs > 6 || mcs == 5)
+ return -EINVAL;
+
+ mcs = mcs - 1;
+ if (mcs == 5)
+ mcs = 4;
+
+ return mcs;
+}
+
+static int adau1977_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+ unsigned int rate = params_rate(params);
+ unsigned int slot_width;
+ unsigned int ctrl0, ctrl0_mask;
+ unsigned int ctrl1;
+ int mcs, fs;
+ int ret;
+
+ fs = adau1977_lookup_fs(rate);
+ if (fs < 0)
+ return fs;
+
+ if (adau1977->sysclk_src == ADAU1977_SYSCLK_SRC_MCLK) {
+ mcs = adau1977_lookup_mcs(adau1977, rate, fs);
+ if (mcs < 0)
+ return mcs;
+ } else {
+ mcs = 0;
+ }
+
+ ctrl0_mask = ADAU1977_SAI_CTRL0_FS_MASK;
+ ctrl0 = fs;
+
+ if (adau1977->right_j) {
+ switch (params_width(params)) {
+ case 16:
+ ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_16BIT;
+ break;
+ case 24:
+ ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT;
+ break;
+ default:
+ return -EINVAL;
+ }
+ ctrl0_mask |= ADAU1977_SAI_CTRL0_FMT_MASK;
+ }
+
+ if (adau1977->master) {
+ switch (params_width(params)) {
+ case 16:
+ ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT;
+ slot_width = 16;
+ break;
+ case 24:
+ case 32:
+ ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT;
+ slot_width = 32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* In TDM mode there is a fixed slot width */
+ if (adau1977->slot_width)
+ slot_width = adau1977->slot_width;
+
+ if (slot_width == 16)
+ ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_16;
+ else
+ ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_32;
+
+ ret = regmap_update_bits(adau1977->regmap,
+ ADAU1977_REG_SAI_CTRL1,
+ ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK |
+ ADAU1977_SAI_CTRL1_BCLKRATE_MASK,
+ ctrl1);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
+ ctrl0_mask, ctrl0);
+ if (ret < 0)
+ return ret;
+
+ return regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL,
+ ADAU1977_PLL_MCS_MASK, mcs);
+}
+
+static int adau1977_power_disable(struct adau1977 *adau1977)
+{
+ int ret = 0;
+
+ if (!adau1977->enabled)
+ return 0;
+
+ ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER,
+ ADAU1977_POWER_PWUP, 0);
+ if (ret)
+ return ret;
+
+ regcache_mark_dirty(adau1977->regmap);
+
+ if (adau1977->reset_gpio)
+ gpiod_set_value_cansleep(adau1977->reset_gpio, 0);
+
+ regcache_cache_only(adau1977->regmap, true);
+
+ regulator_disable(adau1977->avdd_reg);
+ if (adau1977->dvdd_reg)
+ regulator_disable(adau1977->dvdd_reg);
+
+ adau1977->enabled = false;
+
+ return 0;
+}
+
+static int adau1977_power_enable(struct adau1977 *adau1977)
+{
+ unsigned int val;
+ int ret = 0;
+
+ if (adau1977->enabled)
+ return 0;
+
+ ret = regulator_enable(adau1977->avdd_reg);
+ if (ret)
+ return ret;
+
+ if (adau1977->dvdd_reg) {
+ ret = regulator_enable(adau1977->dvdd_reg);
+ if (ret)
+ goto err_disable_avdd;
+ }
+
+ if (adau1977->reset_gpio)
+ gpiod_set_value_cansleep(adau1977->reset_gpio, 1);
+
+ regcache_cache_only(adau1977->regmap, false);
+
+ if (adau1977->switch_mode)
+ adau1977->switch_mode(adau1977->dev);
+
+ ret = adau1977_reset(adau1977);
+ if (ret)
+ goto err_disable_dvdd;
+
+ ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER,
+ ADAU1977_POWER_PWUP, ADAU1977_POWER_PWUP);
+ if (ret)
+ goto err_disable_dvdd;
+
+ ret = regcache_sync(adau1977->regmap);
+ if (ret)
+ goto err_disable_dvdd;
+
+ /*
+ * The PLL register is not affected by the software reset. It is
+ * possible that the value of the register was changed to the
+ * default value while we were in cache only mode. In this case
+ * regcache_sync will skip over it and we have to manually sync
+ * it.
+ */
+ ret = regmap_read(adau1977->regmap, ADAU1977_REG_PLL, &val);
+ if (ret)
+ goto err_disable_dvdd;
+
+ if (val == 0x41) {
+ regcache_cache_bypass(adau1977->regmap, true);
+ ret = regmap_write(adau1977->regmap, ADAU1977_REG_PLL,
+ 0x41);
+ if (ret)
+ goto err_disable_dvdd;
+ regcache_cache_bypass(adau1977->regmap, false);
+ }
+
+ adau1977->enabled = true;
+
+ return ret;
+
+err_disable_dvdd:
+ if (adau1977->dvdd_reg)
+ regulator_disable(adau1977->dvdd_reg);
+err_disable_avdd:
+ regulator_disable(adau1977->avdd_reg);
+ return ret;
+}
+
+static int adau1977_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+ ret = adau1977_power_enable(adau1977);
+ break;
+ case SND_SOC_BIAS_OFF:
+ ret = adau1977_power_disable(adau1977);
+ break;
+ }
+
+ if (ret)
+ return ret;
+
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
+
+static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int width)
+{
+ struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+ unsigned int ctrl0, ctrl1, drv;
+ unsigned int slot[4];
+ unsigned int i;
+ int ret;
+
+ if (slots == 0) {
+ /* 0 = No fixed slot width */
+ adau1977->slot_width = 0;
+ adau1977->max_master_fs = 192000;
+ return regmap_update_bits(adau1977->regmap,
+ ADAU1977_REG_SAI_CTRL0, ADAU1977_SAI_CTRL0_SAI_MASK,
+ ADAU1977_SAI_CTRL0_SAI_I2S);
+ }
+
+ if (rx_mask == 0 || tx_mask != 0)
+ return -EINVAL;
+
+ drv = 0;
+ for (i = 0; i < 4; i++) {
+ slot[i] = __ffs(rx_mask);
+ drv |= ADAU1977_SAI_OVERTEMP_DRV_C(i);
+ rx_mask &= ~(1 << slot[i]);
+ if (slot[i] >= slots)
+ return -EINVAL;
+ if (rx_mask == 0)
+ break;
+ }
+
+ if (rx_mask != 0)
+ return -EINVAL;
+
+ switch (width) {
+ case 16:
+ ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_16;
+ break;
+ case 24:
+ /* We can only generate 16 bit or 32 bit wide slots */
+ if (adau1977->master)
+ return -EINVAL;
+ ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_24;
+ break;
+ case 32:
+ ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (slots) {
+ case 2:
+ ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_2;
+ break;
+ case 4:
+ ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_4;
+ break;
+ case 8:
+ ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_8;
+ break;
+ case 16:
+ ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_16;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP,
+ ADAU1977_SAI_OVERTEMP_DRV_C(0) |
+ ADAU1977_SAI_OVERTEMP_DRV_C(1) |
+ ADAU1977_SAI_OVERTEMP_DRV_C(2) |
+ ADAU1977_SAI_OVERTEMP_DRV_C(3), drv);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP12,
+ (slot[1] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) |
+ (slot[0] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP34,
+ (slot[3] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) |
+ (slot[2] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
+ ADAU1977_SAI_CTRL0_SAI_MASK, ctrl0);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1,
+ ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK, ctrl1);
+ if (ret)
+ return ret;
+
+ adau1977->slot_width = width;
+
+ /* In master mode the maximum bitclock is 24.576 MHz */
+ adau1977->max_master_fs = min(192000, 24576000 / width / slots);
+
+ return 0;
+}
+
+static int adau1977_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+ struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+ unsigned int val;
+
+ if (mute)
+ val = ADAU1977_MISC_CONTROL_MMUTE;
+ else
+ val = 0;
+
+ return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MISC_CONTROL,
+ ADAU1977_MISC_CONTROL_MMUTE, val);
+}
+
+static int adau1977_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+ unsigned int ctrl0 = 0, ctrl1 = 0, block_power = 0;
+ bool invert_lrclk;
+ int ret;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ adau1977->master = false;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ ctrl1 |= ADAU1977_SAI_CTRL1_MASTER;
+ adau1977->master = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ invert_lrclk = false;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE;
+ invert_lrclk = false;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ invert_lrclk = true;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE;
+ invert_lrclk = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ adau1977->right_j = false;
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ;
+ invert_lrclk = !invert_lrclk;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT;
+ adau1977->right_j = true;
+ invert_lrclk = !invert_lrclk;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE;
+ ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S;
+ invert_lrclk = false;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE;
+ ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ;
+ invert_lrclk = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (invert_lrclk)
+ block_power |= ADAU1977_BLOCK_POWER_SAI_LR_POL;
+
+ ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI,
+ ADAU1977_BLOCK_POWER_SAI_LR_POL |
+ ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE, block_power);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
+ ADAU1977_SAI_CTRL0_FMT_MASK,
+ ctrl0);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1,
+ ADAU1977_SAI_CTRL1_MASTER | ADAU1977_SAI_CTRL1_LRCLK_PULSE,
+ ctrl1);
+}
+
+static int adau1977_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+ u64 formats = 0;
+
+ if (adau1977->slot_width == 16)
+ formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE;
+ else if (adau1977->right_j || adau1977->slot_width == 24)
+ formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE;
+
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &adau1977->constraints);
+
+ if (adau1977->master)
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE, 8000, adau1977->max_master_fs);
+
+ if (formats != 0)
+ snd_pcm_hw_constraint_mask64(substream->runtime,
+ SNDRV_PCM_HW_PARAM_FORMAT, formats);
+
+ return 0;
+}
+
+static int adau1977_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+ struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec);
+ unsigned int val;
+
+ if (tristate)
+ val = ADAU1977_SAI_OVERTEMP_DRV_HIZ;
+ else
+ val = 0;
+
+ return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP,
+ ADAU1977_SAI_OVERTEMP_DRV_HIZ, val);
+}
+
+static const struct snd_soc_dai_ops adau1977_dai_ops = {
+ .startup = adau1977_startup,
+ .hw_params = adau1977_hw_params,
+ .mute_stream = adau1977_mute,
+ .set_fmt = adau1977_set_dai_fmt,
+ .set_tdm_slot = adau1977_set_tdm_slot,
+ .set_tristate = adau1977_set_tristate,
+};
+
+static struct snd_soc_dai_driver adau1977_dai = {
+ .name = "adau1977-hifi",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .sig_bits = 24,
+ },
+ .ops = &adau1977_dai_ops,
+};
+
+static const unsigned int adau1977_rates[] = {
+ 8000, 16000, 32000, 64000, 128000,
+ 11025, 22050, 44100, 88200, 172400,
+ 12000, 24000, 48000, 96000, 192000,
+};
+
+#define ADAU1977_RATE_CONSTRAINT_MASK_32000 0x001f
+#define ADAU1977_RATE_CONSTRAINT_MASK_44100 0x03e0
+#define ADAU1977_RATE_CONSTRAINT_MASK_48000 0x7c00
+/* All rates >= 32000 */
+#define ADAU1977_RATE_CONSTRAINT_MASK_LRCLK 0x739c
+
+static bool adau1977_check_sysclk(unsigned int mclk, unsigned int base_freq)
+{
+ unsigned int mcs;
+
+ if (mclk % (base_freq * 128) != 0)
+ return false;
+
+ mcs = mclk / (128 * base_freq);
+ if (mcs < 1 || mcs > 6 || mcs == 5)
+ return false;
+
+ return true;
+}
+
+static int adau1977_set_sysclk(struct snd_soc_codec *codec,
+ int clk_id, int source, unsigned int freq, int dir)
+{
+ struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+ unsigned int mask = 0;
+ unsigned int clk_src;
+ unsigned int ret;
+
+ if (dir != SND_SOC_CLOCK_IN)
+ return -EINVAL;
+
+ if (clk_id != ADAU1977_SYSCLK)
+ return -EINVAL;
+
+ switch (source) {
+ case ADAU1977_SYSCLK_SRC_MCLK:
+ clk_src = 0;
+ break;
+ case ADAU1977_SYSCLK_SRC_LRCLK:
+ clk_src = ADAU1977_PLL_CLK_S;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (freq != 0 && source == ADAU1977_SYSCLK_SRC_MCLK) {
+ if (freq < 4000000 || freq > 36864000)
+ return -EINVAL;
+
+ if (adau1977_check_sysclk(freq, 32000))
+ mask |= ADAU1977_RATE_CONSTRAINT_MASK_32000;
+ if (adau1977_check_sysclk(freq, 44100))
+ mask |= ADAU1977_RATE_CONSTRAINT_MASK_44100;
+ if (adau1977_check_sysclk(freq, 48000))
+ mask |= ADAU1977_RATE_CONSTRAINT_MASK_48000;
+
+ if (mask == 0)
+ return -EINVAL;
+ } else if (source == ADAU1977_SYSCLK_SRC_LRCLK) {
+ mask = ADAU1977_RATE_CONSTRAINT_MASK_LRCLK;
+ }
+
+ ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL,
+ ADAU1977_PLL_CLK_S, clk_src);
+ if (ret)
+ return ret;
+
+ adau1977->constraints.mask = mask;
+ adau1977->sysclk_src = source;
+ adau1977->sysclk = freq;
+
+ return 0;
+}
+
+static int adau1977_codec_probe(struct snd_soc_codec *codec)
+{
+ struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ switch (adau1977->type) {
+ case ADAU1977:
+ ret = snd_soc_dapm_new_controls(&codec->dapm,
+ adau1977_micbias_dapm_widgets,
+ ARRAY_SIZE(adau1977_micbias_dapm_widgets));
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver adau1977_codec_driver = {
+ .probe = adau1977_codec_probe,
+ .set_bias_level = adau1977_set_bias_level,
+ .set_sysclk = adau1977_set_sysclk,
+ .idle_bias_off = true,
+
+ .controls = adau1977_snd_controls,
+ .num_controls = ARRAY_SIZE(adau1977_snd_controls),
+ .dapm_widgets = adau1977_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(adau1977_dapm_widgets),
+ .dapm_routes = adau1977_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes),
+};
+
+static int adau1977_setup_micbias(struct adau1977 *adau1977)
+{
+ struct adau1977_platform_data *pdata = adau1977->dev->platform_data;
+ unsigned int micbias;
+
+ if (pdata) {
+ micbias = pdata->micbias;
+ if (micbias > ADAU1977_MICBIAS_9V0)
+ return -EINVAL;
+
+ } else {
+ micbias = ADAU1977_MICBIAS_8V5;
+ }
+
+ return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MICBIAS,
+ ADAU1977_MICBIAS_MB_VOLTS_MASK,
+ micbias << ADAU1977_MICBIAS_MB_VOLTS_OFFSET);
+}
+
+int adau1977_probe(struct device *dev, struct regmap *regmap,
+ enum adau1977_type type, void (*switch_mode)(struct device *dev))
+{
+ unsigned int power_off_mask;
+ struct adau1977 *adau1977;
+ int ret;
+
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ adau1977 = devm_kzalloc(dev, sizeof(*adau1977), GFP_KERNEL);
+ if (adau1977 == NULL)
+ return -ENOMEM;
+
+ adau1977->dev = dev;
+ adau1977->type = type;
+ adau1977->regmap = regmap;
+ adau1977->switch_mode = switch_mode;
+ adau1977->max_master_fs = 192000;
+
+ adau1977->constraints.list = adau1977_rates;
+ adau1977->constraints.count = ARRAY_SIZE(adau1977_rates);
+
+ adau1977->avdd_reg = devm_regulator_get(dev, "AVDD");
+ if (IS_ERR(adau1977->avdd_reg))
+ return PTR_ERR(adau1977->avdd_reg);
+
+ adau1977->dvdd_reg = devm_regulator_get_optional(dev, "DVDD");
+ if (IS_ERR(adau1977->dvdd_reg)) {
+ if (PTR_ERR(adau1977->dvdd_reg) != -ENODEV)
+ return PTR_ERR(adau1977->dvdd_reg);
+ adau1977->dvdd_reg = NULL;
+ }
+
+ adau1977->reset_gpio = devm_gpiod_get(dev, "reset");
+ if (IS_ERR(adau1977->reset_gpio)) {
+ ret = PTR_ERR(adau1977->reset_gpio);
+ if (ret != -ENOENT && ret != -ENOSYS)
+ return PTR_ERR(adau1977->reset_gpio);
+ adau1977->reset_gpio = NULL;
+ }
+
+ dev_set_drvdata(dev, adau1977);
+
+ if (adau1977->reset_gpio) {
+ ret = gpiod_direction_output(adau1977->reset_gpio, 0);
+ if (ret)
+ return ret;
+ ndelay(100);
+ }
+
+ ret = adau1977_power_enable(adau1977);
+ if (ret)
+ return ret;
+
+ if (type == ADAU1977) {
+ ret = adau1977_setup_micbias(adau1977);
+ if (ret)
+ goto err_poweroff;
+ }
+
+ if (adau1977->dvdd_reg)
+ power_off_mask = ~0;
+ else
+ power_off_mask = ~ADAU1977_BLOCK_POWER_SAI_LDO_EN;
+
+ ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI,
+ power_off_mask, 0x00);
+ if (ret)
+ goto err_poweroff;
+
+ ret = adau1977_power_disable(adau1977);
+ if (ret)
+ return ret;
+
+ return snd_soc_register_codec(dev, &adau1977_codec_driver,
+ &adau1977_dai, 1);
+
+err_poweroff:
+ adau1977_power_disable(adau1977);
+ return ret;
+
+}
+EXPORT_SYMBOL_GPL(adau1977_probe);
+
+static bool adau1977_register_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ADAU1977_REG_STATUS(0):
+ case ADAU1977_REG_STATUS(1):
+ case ADAU1977_REG_STATUS(2):
+ case ADAU1977_REG_STATUS(3):
+ case ADAU1977_REG_ADC_CLIP:
+ return true;
+ }
+
+ return false;
+}
+
+const struct regmap_config adau1977_regmap_config = {
+ .max_register = ADAU1977_REG_DC_HPF_CAL,
+ .volatile_reg = adau1977_register_volatile,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = adau1977_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults),
+};
+EXPORT_SYMBOL_GPL(adau1977_regmap_config);
+
+MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adau1977.h b/sound/soc/codecs/adau1977.h
new file mode 100644
index 000000000000..95e714345a86
--- /dev/null
+++ b/sound/soc/codecs/adau1977.h
@@ -0,0 +1,37 @@
+/*
+ * ADAU1977/ADAU1978/ADAU1979 driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __SOUND_SOC_CODECS_ADAU1977_H__
+#define __SOUND_SOC_CODECS_ADAU1977_H__
+
+#include <linux/regmap.h>
+
+struct device;
+
+enum adau1977_type {
+ ADAU1977,
+ ADAU1978,
+ ADAU1979,
+};
+
+int adau1977_probe(struct device *dev, struct regmap *regmap,
+ enum adau1977_type type, void (*switch_mode)(struct device *dev));
+
+extern const struct regmap_config adau1977_regmap_config;
+
+enum adau1977_clk_id {
+ ADAU1977_SYSCLK,
+};
+
+enum adau1977_sysclk_src {
+ ADAU1977_SYSCLK_SRC_MCLK,
+ ADAU1977_SYSCLK_SRC_LRCLK,
+};
+
+#endif
diff --git a/sound/soc/codecs/adav801.c b/sound/soc/codecs/adav801.c
new file mode 100644
index 000000000000..790fce33ab10
--- /dev/null
+++ b/sound/soc/codecs/adav801.c
@@ -0,0 +1,53 @@
+/*
+ * ADAV801 audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "adav80x.h"
+
+static const struct spi_device_id adav80x_spi_id[] = {
+ { "adav801", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, adav80x_spi_id);
+
+static int adav80x_spi_probe(struct spi_device *spi)
+{
+ struct regmap_config config;
+
+ config = adav80x_regmap_config;
+ config.read_flag_mask = 0x01;
+
+ return adav80x_bus_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
+}
+
+static int adav80x_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ return 0;
+}
+
+static struct spi_driver adav80x_spi_driver = {
+ .driver = {
+ .name = "adav801",
+ .owner = THIS_MODULE,
+ },
+ .probe = adav80x_spi_probe,
+ .remove = adav80x_spi_remove,
+ .id_table = adav80x_spi_id,
+};
+module_spi_driver(adav80x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC ADAV801 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_AUTHOR("Yi Li <yi.li@analog.com>>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c
new file mode 100644
index 000000000000..66d9fce34e62
--- /dev/null
+++ b/sound/soc/codecs/adav803.c
@@ -0,0 +1,50 @@
+/*
+ * ADAV803 audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "adav80x.h"
+
+static const struct i2c_device_id adav803_id[] = {
+ { "adav803", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adav803_id);
+
+static int adav803_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return adav80x_bus_probe(&client->dev,
+ devm_regmap_init_i2c(client, &adav80x_regmap_config));
+}
+
+static int adav803_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static struct i2c_driver adav803_driver = {
+ .driver = {
+ .name = "adav803",
+ .owner = THIS_MODULE,
+ },
+ .probe = adav803_probe,
+ .remove = adav803_remove,
+ .id_table = adav803_id,
+};
+module_i2c_driver(adav803_driver);
+
+MODULE_DESCRIPTION("ASoC ADAV803 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_AUTHOR("Yi Li <yi.li@analog.com>>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index f78b27a7c461..5062e34ee8dc 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -8,17 +8,15 @@
* Licensed under the GPL-2 or later.
*/
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/spi/spi.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
-#include <sound/core.h>
+
#include <sound/pcm.h>
#include <sound/pcm_params.h>
-#include <sound/tlv.h>
#include <sound/soc.h>
+#include <sound/tlv.h>
#include "adav80x.h"
@@ -541,6 +539,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
unsigned int freq, int dir)
{
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
if (dir == SND_SOC_CLOCK_IN) {
switch (clk_id) {
@@ -573,7 +572,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2,
iclk_ctrl2);
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_sync(dapm);
}
} else {
unsigned int mask;
@@ -600,17 +599,21 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
adav80x->sysclk_pd[clk_id] = false;
}
+ snd_soc_dapm_mutex_lock(dapm);
+
if (adav80x->sysclk_pd[0])
- snd_soc_dapm_disable_pin(&codec->dapm, "PLL1");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "PLL1");
else
- snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
+ snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL1");
if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2])
- snd_soc_dapm_disable_pin(&codec->dapm, "PLL2");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "PLL2");
else
- snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2");
+ snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL2");
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_sync_unlocked(dapm);
+
+ snd_soc_dapm_mutex_unlock(dapm);
}
return 0;
@@ -722,7 +725,7 @@ static int adav80x_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
- if (!codec->active || !adav80x->rate)
+ if (!snd_soc_codec_is_active(codec) || !adav80x->rate)
return 0;
return snd_pcm_hw_constraint_minmax(substream->runtime,
@@ -735,7 +738,7 @@ static void adav80x_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
- if (!codec->active)
+ if (!snd_soc_codec_is_active(codec))
adav80x->rate = 0;
}
@@ -798,15 +801,8 @@ static struct snd_soc_dai_driver adav80x_dais[] = {
static int adav80x_probe(struct snd_soc_codec *codec)
{
- int ret;
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
- ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
- if (ret) {
- dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* Force PLLs on for SYSCLK output */
snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2");
@@ -864,39 +860,26 @@ static struct snd_soc_codec_driver adav80x_codec_driver = {
.num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes),
};
-static int adav80x_bus_probe(struct device *dev, struct regmap *regmap)
+int adav80x_bus_probe(struct device *dev, struct regmap *regmap)
{
struct adav80x *adav80x;
- int ret;
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL);
+ adav80x = devm_kzalloc(dev, sizeof(*adav80x), GFP_KERNEL);
if (!adav80x)
return -ENOMEM;
-
dev_set_drvdata(dev, adav80x);
adav80x->regmap = regmap;
- ret = snd_soc_register_codec(dev, &adav80x_codec_driver,
+ return snd_soc_register_codec(dev, &adav80x_codec_driver,
adav80x_dais, ARRAY_SIZE(adav80x_dais));
- if (ret)
- kfree(adav80x);
-
- return ret;
-}
-
-static int adav80x_bus_remove(struct device *dev)
-{
- snd_soc_unregister_codec(dev);
- kfree(dev_get_drvdata(dev));
- return 0;
}
+EXPORT_SYMBOL_GPL(adav80x_bus_probe);
-#if defined(CONFIG_SPI_MASTER)
-static const struct regmap_config adav80x_spi_regmap_config = {
+const struct regmap_config adav80x_regmap_config = {
.val_bits = 8,
.pad_bits = 1,
.reg_bits = 7,
@@ -908,105 +891,7 @@ static const struct regmap_config adav80x_spi_regmap_config = {
.reg_defaults = adav80x_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults),
};
-
-static const struct spi_device_id adav80x_spi_id[] = {
- { "adav801", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(spi, adav80x_spi_id);
-
-static int adav80x_spi_probe(struct spi_device *spi)
-{
- return adav80x_bus_probe(&spi->dev,
- devm_regmap_init_spi(spi, &adav80x_spi_regmap_config));
-}
-
-static int adav80x_spi_remove(struct spi_device *spi)
-{
- return adav80x_bus_remove(&spi->dev);
-}
-
-static struct spi_driver adav80x_spi_driver = {
- .driver = {
- .name = "adav801",
- .owner = THIS_MODULE,
- },
- .probe = adav80x_spi_probe,
- .remove = adav80x_spi_remove,
- .id_table = adav80x_spi_id,
-};
-#endif
-
-#if IS_ENABLED(CONFIG_I2C)
-static const struct regmap_config adav80x_i2c_regmap_config = {
- .val_bits = 8,
- .pad_bits = 1,
- .reg_bits = 7,
-
- .max_register = ADAV80X_PLL_OUTE,
-
- .cache_type = REGCACHE_RBTREE,
- .reg_defaults = adav80x_reg_defaults,
- .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults),
-};
-
-static const struct i2c_device_id adav80x_i2c_id[] = {
- { "adav803", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id);
-
-static int adav80x_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- return adav80x_bus_probe(&client->dev,
- devm_regmap_init_i2c(client, &adav80x_i2c_regmap_config));
-}
-
-static int adav80x_i2c_remove(struct i2c_client *client)
-{
- return adav80x_bus_remove(&client->dev);
-}
-
-static struct i2c_driver adav80x_i2c_driver = {
- .driver = {
- .name = "adav803",
- .owner = THIS_MODULE,
- },
- .probe = adav80x_i2c_probe,
- .remove = adav80x_i2c_remove,
- .id_table = adav80x_i2c_id,
-};
-#endif
-
-static int __init adav80x_init(void)
-{
- int ret = 0;
-
-#if IS_ENABLED(CONFIG_I2C)
- ret = i2c_add_driver(&adav80x_i2c_driver);
- if (ret)
- return ret;
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
- ret = spi_register_driver(&adav80x_spi_driver);
-#endif
-
- return ret;
-}
-module_init(adav80x_init);
-
-static void __exit adav80x_exit(void)
-{
-#if IS_ENABLED(CONFIG_I2C)
- i2c_del_driver(&adav80x_i2c_driver);
-#endif
-#if defined(CONFIG_SPI_MASTER)
- spi_unregister_driver(&adav80x_spi_driver);
-#endif
-}
-module_exit(adav80x_exit);
+EXPORT_SYMBOL_GPL(adav80x_regmap_config);
MODULE_DESCRIPTION("ASoC ADAV80x driver");
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
diff --git a/sound/soc/codecs/adav80x.h b/sound/soc/codecs/adav80x.h
index adb0fc76d4e3..8a1d7c09dca5 100644
--- a/sound/soc/codecs/adav80x.h
+++ b/sound/soc/codecs/adav80x.h
@@ -9,6 +9,13 @@
#ifndef _ADAV80X_H
#define _ADAV80X_H
+#include <linux/regmap.h>
+
+struct device;
+
+extern const struct regmap_config adav80x_regmap_config;
+int adav80x_bus_probe(struct device *dev, struct regmap *regmap);
+
enum adav80x_pll_src {
ADAV80X_PLL_SRC_XIN,
ADAV80X_PLL_SRC_XTAL,
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index b4819dcd4f4d..10adf25d4c14 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -174,8 +174,6 @@ static int ak4104_probe(struct snd_soc_codec *codec)
struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
int ret;
- codec->control_data = ak4104->regmap;
-
/* set power-up and non-reset bits */
ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 684fe910669f..30e297890fec 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -388,15 +388,6 @@ static int ak4535_resume(struct snd_soc_codec *codec)
static int ak4535_probe(struct snd_soc_codec *codec)
{
- struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- codec->control_data = ak4535->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
/* power on device */
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index 94cbe508dd37..868c0e2da1ec 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -113,14 +113,14 @@ static const DECLARE_TLV_DB_SCALE(alc_tlv, -800, 50, 0);
static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0);
-static const struct soc_enum ak4641_mono_out_enum =
- SOC_ENUM_SINGLE(AK4641_SIG1, 6, 2, ak4641_mono_out);
-static const struct soc_enum ak4641_hp_out_enum =
- SOC_ENUM_SINGLE(AK4641_MODE2, 2, 2, ak4641_hp_out);
-static const struct soc_enum ak4641_mic_select_enum =
- SOC_ENUM_SINGLE(AK4641_MIC, 1, 2, ak4641_mic_select);
-static const struct soc_enum ak4641_mic_or_dac_enum =
- SOC_ENUM_SINGLE(AK4641_BTIF, 4, 2, ak4641_mic_or_dac);
+static SOC_ENUM_SINGLE_DECL(ak4641_mono_out_enum,
+ AK4641_SIG1, 6, ak4641_mono_out);
+static SOC_ENUM_SINGLE_DECL(ak4641_hp_out_enum,
+ AK4641_MODE2, 2, ak4641_hp_out);
+static SOC_ENUM_SINGLE_DECL(ak4641_mic_select_enum,
+ AK4641_MIC, 1, ak4641_mic_select);
+static SOC_ENUM_SINGLE_DECL(ak4641_mic_or_dac_enum,
+ AK4641_BTIF, 4, ak4641_mic_or_dac);
static const struct snd_kcontrol_new ak4641_snd_controls[] = {
SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum),
@@ -519,14 +519,6 @@ static int ak4641_resume(struct snd_soc_codec *codec)
static int ak4641_probe(struct snd_soc_codec *codec)
{
- int ret;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* power on device */
ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 1f646c6e90c6..92655cc189ae 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -465,14 +465,6 @@ static int ak4642_resume(struct snd_soc_codec *codec)
static int ak4642_probe(struct snd_soc_codec *codec)
{
- int ret;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index 25bdf6ad4a54..998fa0c5a0b9 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/delay.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/initval.h>
@@ -23,104 +24,99 @@
#include "ak4671.h"
-/* codec private data */
-struct ak4671_priv {
- enum snd_soc_control_type control_type;
-};
-
/* ak4671 register cache & default register settings */
-static const u8 ak4671_reg[AK4671_CACHEREGNUM] = {
- 0x00, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */
- 0xf6, /* AK4671_PLL_MODE_SELECT0 (0x01) */
- 0x00, /* AK4671_PLL_MODE_SELECT1 (0x02) */
- 0x02, /* AK4671_FORMAT_SELECT (0x03) */
- 0x00, /* AK4671_MIC_SIGNAL_SELECT (0x04) */
- 0x55, /* AK4671_MIC_AMP_GAIN (0x05) */
- 0x00, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */
- 0x00, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */
- 0xb5, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */
- 0x00, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */
- 0x00, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */
- 0x00, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */
- 0x00, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */
- 0x00, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */
- 0x00, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */
- 0x00, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */
- 0x00, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */
- 0x80, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */
- 0x91, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */
- 0x91, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */
- 0xe1, /* AK4671_ALC_REFERENCE_SELECT (0x14) */
- 0x00, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */
- 0x00, /* AK4671_ALC_TIMER_SELECT (0x16) */
- 0x00, /* AK4671_ALC_MODE_CONTROL (0x17) */
- 0x02, /* AK4671_MODE_CONTROL1 (0x18) */
- 0x01, /* AK4671_MODE_CONTROL2 (0x19) */
- 0x18, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */
- 0x18, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */
- 0x00, /* AK4671_SIDETONE_A_CONTROL (0x1c) */
- 0x02, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */
- 0x00, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */
- 0x00, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */
- 0x00, /* AK4671_FIL3_COEFFICIENT2 (0x20) */
- 0x00, /* AK4671_FIL3_COEFFICIENT3 (0x21) */
- 0x00, /* AK4671_EQ_COEFFICIENT0 (0x22) */
- 0x00, /* AK4671_EQ_COEFFICIENT1 (0x23) */
- 0x00, /* AK4671_EQ_COEFFICIENT2 (0x24) */
- 0x00, /* AK4671_EQ_COEFFICIENT3 (0x25) */
- 0x00, /* AK4671_EQ_COEFFICIENT4 (0x26) */
- 0x00, /* AK4671_EQ_COEFFICIENT5 (0x27) */
- 0xa9, /* AK4671_FIL1_COEFFICIENT0 (0x28) */
- 0x1f, /* AK4671_FIL1_COEFFICIENT1 (0x29) */
- 0xad, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */
- 0x20, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */
- 0x00, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */
- 0x00, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */
- 0x00, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */
- 0x00, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */
- 0x00, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */
- 0x00, /* this register not used */
- 0x00, /* AK4671_E1_COEFFICIENT0 (0x32) */
- 0x00, /* AK4671_E1_COEFFICIENT1 (0x33) */
- 0x00, /* AK4671_E1_COEFFICIENT2 (0x34) */
- 0x00, /* AK4671_E1_COEFFICIENT3 (0x35) */
- 0x00, /* AK4671_E1_COEFFICIENT4 (0x36) */
- 0x00, /* AK4671_E1_COEFFICIENT5 (0x37) */
- 0x00, /* AK4671_E2_COEFFICIENT0 (0x38) */
- 0x00, /* AK4671_E2_COEFFICIENT1 (0x39) */
- 0x00, /* AK4671_E2_COEFFICIENT2 (0x3a) */
- 0x00, /* AK4671_E2_COEFFICIENT3 (0x3b) */
- 0x00, /* AK4671_E2_COEFFICIENT4 (0x3c) */
- 0x00, /* AK4671_E2_COEFFICIENT5 (0x3d) */
- 0x00, /* AK4671_E3_COEFFICIENT0 (0x3e) */
- 0x00, /* AK4671_E3_COEFFICIENT1 (0x3f) */
- 0x00, /* AK4671_E3_COEFFICIENT2 (0x40) */
- 0x00, /* AK4671_E3_COEFFICIENT3 (0x41) */
- 0x00, /* AK4671_E3_COEFFICIENT4 (0x42) */
- 0x00, /* AK4671_E3_COEFFICIENT5 (0x43) */
- 0x00, /* AK4671_E4_COEFFICIENT0 (0x44) */
- 0x00, /* AK4671_E4_COEFFICIENT1 (0x45) */
- 0x00, /* AK4671_E4_COEFFICIENT2 (0x46) */
- 0x00, /* AK4671_E4_COEFFICIENT3 (0x47) */
- 0x00, /* AK4671_E4_COEFFICIENT4 (0x48) */
- 0x00, /* AK4671_E4_COEFFICIENT5 (0x49) */
- 0x00, /* AK4671_E5_COEFFICIENT0 (0x4a) */
- 0x00, /* AK4671_E5_COEFFICIENT1 (0x4b) */
- 0x00, /* AK4671_E5_COEFFICIENT2 (0x4c) */
- 0x00, /* AK4671_E5_COEFFICIENT3 (0x4d) */
- 0x00, /* AK4671_E5_COEFFICIENT4 (0x4e) */
- 0x00, /* AK4671_E5_COEFFICIENT5 (0x4f) */
- 0x88, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */
- 0x88, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */
- 0x08, /* AK4671_EQ_CONTRO_10KHZ (0x52) */
- 0x00, /* AK4671_PCM_IF_CONTROL0 (0x53) */
- 0x00, /* AK4671_PCM_IF_CONTROL1 (0x54) */
- 0x00, /* AK4671_PCM_IF_CONTROL2 (0x55) */
- 0x18, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */
- 0x18, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */
- 0x00, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */
- 0x00, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */
- 0x00, /* AK4671_SAR_ADC_CONTROL (0x5a) */
+static const struct reg_default ak4671_reg_defaults[] = {
+ { 0x00, 0x00 }, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */
+ { 0x01, 0xf6 }, /* AK4671_PLL_MODE_SELECT0 (0x01) */
+ { 0x02, 0x00 }, /* AK4671_PLL_MODE_SELECT1 (0x02) */
+ { 0x03, 0x02 }, /* AK4671_FORMAT_SELECT (0x03) */
+ { 0x04, 0x00 }, /* AK4671_MIC_SIGNAL_SELECT (0x04) */
+ { 0x05, 0x55 }, /* AK4671_MIC_AMP_GAIN (0x05) */
+ { 0x06, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */
+ { 0x07, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */
+ { 0x08, 0xb5 }, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */
+ { 0x09, 0x00 }, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */
+ { 0x0a, 0x00 }, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */
+ { 0x0b, 0x00 }, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */
+ { 0x0c, 0x00 }, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */
+ { 0x0d, 0x00 }, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */
+ { 0x0e, 0x00 }, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */
+ { 0x0f, 0x00 }, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */
+ { 0x10, 0x00 }, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */
+ { 0x11, 0x80 }, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */
+ { 0x12, 0x91 }, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */
+ { 0x13, 0x91 }, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */
+ { 0x14, 0xe1 }, /* AK4671_ALC_REFERENCE_SELECT (0x14) */
+ { 0x15, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */
+ { 0x16, 0x00 }, /* AK4671_ALC_TIMER_SELECT (0x16) */
+ { 0x17, 0x00 }, /* AK4671_ALC_MODE_CONTROL (0x17) */
+ { 0x18, 0x02 }, /* AK4671_MODE_CONTROL1 (0x18) */
+ { 0x19, 0x01 }, /* AK4671_MODE_CONTROL2 (0x19) */
+ { 0x1a, 0x18 }, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */
+ { 0x1b, 0x18 }, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */
+ { 0x1c, 0x00 }, /* AK4671_SIDETONE_A_CONTROL (0x1c) */
+ { 0x1d, 0x02 }, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */
+ { 0x1e, 0x00 }, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */
+ { 0x1f, 0x00 }, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */
+ { 0x20, 0x00 }, /* AK4671_FIL3_COEFFICIENT2 (0x20) */
+ { 0x21, 0x00 }, /* AK4671_FIL3_COEFFICIENT3 (0x21) */
+ { 0x22, 0x00 }, /* AK4671_EQ_COEFFICIENT0 (0x22) */
+ { 0x23, 0x00 }, /* AK4671_EQ_COEFFICIENT1 (0x23) */
+ { 0x24, 0x00 }, /* AK4671_EQ_COEFFICIENT2 (0x24) */
+ { 0x25, 0x00 }, /* AK4671_EQ_COEFFICIENT3 (0x25) */
+ { 0x26, 0x00 }, /* AK4671_EQ_COEFFICIENT4 (0x26) */
+ { 0x27, 0x00 }, /* AK4671_EQ_COEFFICIENT5 (0x27) */
+ { 0x28, 0xa9 }, /* AK4671_FIL1_COEFFICIENT0 (0x28) */
+ { 0x29, 0x1f }, /* AK4671_FIL1_COEFFICIENT1 (0x29) */
+ { 0x2a, 0xad }, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */
+ { 0x2b, 0x20 }, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */
+ { 0x2c, 0x00 }, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */
+ { 0x2d, 0x00 }, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */
+ { 0x2e, 0x00 }, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */
+ { 0x2f, 0x00 }, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */
+ { 0x30, 0x00 }, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */
+
+ { 0x32, 0x00 }, /* AK4671_E1_COEFFICIENT0 (0x32) */
+ { 0x33, 0x00 }, /* AK4671_E1_COEFFICIENT1 (0x33) */
+ { 0x34, 0x00 }, /* AK4671_E1_COEFFICIENT2 (0x34) */
+ { 0x35, 0x00 }, /* AK4671_E1_COEFFICIENT3 (0x35) */
+ { 0x36, 0x00 }, /* AK4671_E1_COEFFICIENT4 (0x36) */
+ { 0x37, 0x00 }, /* AK4671_E1_COEFFICIENT5 (0x37) */
+ { 0x38, 0x00 }, /* AK4671_E2_COEFFICIENT0 (0x38) */
+ { 0x39, 0x00 }, /* AK4671_E2_COEFFICIENT1 (0x39) */
+ { 0x3a, 0x00 }, /* AK4671_E2_COEFFICIENT2 (0x3a) */
+ { 0x3b, 0x00 }, /* AK4671_E2_COEFFICIENT3 (0x3b) */
+ { 0x3c, 0x00 }, /* AK4671_E2_COEFFICIENT4 (0x3c) */
+ { 0x3d, 0x00 }, /* AK4671_E2_COEFFICIENT5 (0x3d) */
+ { 0x3e, 0x00 }, /* AK4671_E3_COEFFICIENT0 (0x3e) */
+ { 0x3f, 0x00 }, /* AK4671_E3_COEFFICIENT1 (0x3f) */
+ { 0x40, 0x00 }, /* AK4671_E3_COEFFICIENT2 (0x40) */
+ { 0x41, 0x00 }, /* AK4671_E3_COEFFICIENT3 (0x41) */
+ { 0x42, 0x00 }, /* AK4671_E3_COEFFICIENT4 (0x42) */
+ { 0x43, 0x00 }, /* AK4671_E3_COEFFICIENT5 (0x43) */
+ { 0x44, 0x00 }, /* AK4671_E4_COEFFICIENT0 (0x44) */
+ { 0x45, 0x00 }, /* AK4671_E4_COEFFICIENT1 (0x45) */
+ { 0x46, 0x00 }, /* AK4671_E4_COEFFICIENT2 (0x46) */
+ { 0x47, 0x00 }, /* AK4671_E4_COEFFICIENT3 (0x47) */
+ { 0x48, 0x00 }, /* AK4671_E4_COEFFICIENT4 (0x48) */
+ { 0x49, 0x00 }, /* AK4671_E4_COEFFICIENT5 (0x49) */
+ { 0x4a, 0x00 }, /* AK4671_E5_COEFFICIENT0 (0x4a) */
+ { 0x4b, 0x00 }, /* AK4671_E5_COEFFICIENT1 (0x4b) */
+ { 0x4c, 0x00 }, /* AK4671_E5_COEFFICIENT2 (0x4c) */
+ { 0x4d, 0x00 }, /* AK4671_E5_COEFFICIENT3 (0x4d) */
+ { 0x4e, 0x00 }, /* AK4671_E5_COEFFICIENT4 (0x4e) */
+ { 0x4f, 0x00 }, /* AK4671_E5_COEFFICIENT5 (0x4f) */
+ { 0x50, 0x88 }, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */
+ { 0x51, 0x88 }, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */
+ { 0x52, 0x08 }, /* AK4671_EQ_CONTRO_10KHZ (0x52) */
+ { 0x53, 0x00 }, /* AK4671_PCM_IF_CONTROL0 (0x53) */
+ { 0x54, 0x00 }, /* AK4671_PCM_IF_CONTROL1 (0x54) */
+ { 0x55, 0x00 }, /* AK4671_PCM_IF_CONTROL2 (0x55) */
+ { 0x56, 0x18 }, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */
+ { 0x57, 0x18 }, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */
+ { 0x58, 0x00 }, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */
+ { 0x59, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */
+ { 0x5a, 0x00 }, /* AK4671_SAR_ADC_CONTROL (0x5a) */
};
/*
@@ -241,19 +237,17 @@ static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = {
/* Input MUXs */
static const char *ak4671_lin_mux_texts[] =
{"LIN1", "LIN2", "LIN3", "LIN4"};
-static const struct soc_enum ak4671_lin_mux_enum =
- SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 0,
- ARRAY_SIZE(ak4671_lin_mux_texts),
- ak4671_lin_mux_texts);
+static SOC_ENUM_SINGLE_DECL(ak4671_lin_mux_enum,
+ AK4671_MIC_SIGNAL_SELECT, 0,
+ ak4671_lin_mux_texts);
static const struct snd_kcontrol_new ak4671_lin_mux_control =
SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum);
static const char *ak4671_rin_mux_texts[] =
{"RIN1", "RIN2", "RIN3", "RIN4"};
-static const struct soc_enum ak4671_rin_mux_enum =
- SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 2,
- ARRAY_SIZE(ak4671_rin_mux_texts),
- ak4671_rin_mux_texts);
+static SOC_ENUM_SINGLE_DECL(ak4671_rin_mux_enum,
+ AK4671_MIC_SIGNAL_SELECT, 2,
+ ak4671_rin_mux_texts);
static const struct snd_kcontrol_new ak4671_rin_mux_control =
SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum);
@@ -619,21 +613,7 @@ static struct snd_soc_dai_driver ak4671_dai = {
static int ak4671_probe(struct snd_soc_codec *codec)
{
- struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
- snd_soc_add_codec_controls(codec, ak4671_snd_controls,
- ARRAY_SIZE(ak4671_snd_controls));
-
- ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return ret;
+ return ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
}
static int ak4671_remove(struct snd_soc_codec *codec)
@@ -646,28 +626,36 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
.probe = ak4671_probe,
.remove = ak4671_remove,
.set_bias_level = ak4671_set_bias_level,
- .reg_cache_size = AK4671_CACHEREGNUM,
- .reg_word_size = sizeof(u8),
- .reg_cache_default = ak4671_reg,
+ .controls = ak4671_snd_controls,
+ .num_controls = ARRAY_SIZE(ak4671_snd_controls),
.dapm_widgets = ak4671_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets),
.dapm_routes = ak4671_intercon,
.num_dapm_routes = ARRAY_SIZE(ak4671_intercon),
};
+static const struct regmap_config ak4671_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = AK4671_SAR_ADC_CONTROL,
+ .reg_defaults = ak4671_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(ak4671_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+};
+
static int ak4671_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct ak4671_priv *ak4671;
+ struct regmap *regmap;
int ret;
- ak4671 = devm_kzalloc(&client->dev, sizeof(struct ak4671_priv),
- GFP_KERNEL);
- if (ak4671 == NULL)
- return -ENOMEM;
-
- i2c_set_clientdata(client, ak4671);
- ak4671->control_type = SND_SOC_I2C;
+ regmap = devm_regmap_init_i2c(client, &ak4671_regmap);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ dev_err(&client->dev, "Failed to create regmap: %d\n", ret);
+ return ret;
+ }
ret = snd_soc_register_codec(&client->dev,
&soc_codec_dev_ak4671, &ak4671_dai, 1);
diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h
index 61cb7ab7552c..394a34d3f50a 100644
--- a/sound/soc/codecs/ak4671.h
+++ b/sound/soc/codecs/ak4671.h
@@ -105,8 +105,6 @@
#define AK4671_DIGITAL_MIXING_CONTROL2 0x59
#define AK4671_SAR_ADC_CONTROL 0x5a
-#define AK4671_CACHEREGNUM (AK4671_SAR_ADC_CONTROL + 1)
-
/* Bitfield Definitions */
/* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index d3036283482a..09f7e773bafb 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -21,6 +21,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -38,26 +39,13 @@ MODULE_PARM_DESC(caps_charge, "ALC5623 cap charge time (msecs)");
/* codec private data */
struct alc5623_priv {
- enum snd_soc_control_type control_type;
+ struct regmap *regmap;
u8 id;
unsigned int sysclk;
- u16 reg_cache[ALC5623_VENDOR_ID2+2];
unsigned int add_ctrl;
unsigned int jack_det_ctrl;
};
-static void alc5623_fill_cache(struct snd_soc_codec *codec)
-{
- int i, step = codec->driver->reg_cache_step;
- u16 *cache = codec->reg_cache;
-
- /* not really efficient ... */
- codec->cache_bypass = 1;
- for (i = 0 ; i < codec->driver->reg_cache_size ; i += step)
- cache[i] = snd_soc_read(codec, i);
- codec->cache_bypass = 0;
-}
-
static inline int alc5623_reset(struct snd_soc_codec *codec)
{
return snd_soc_write(codec, ALC5623_RESET, 0);
@@ -228,32 +216,37 @@ static const char *alc5623_aux_out_input_sel[] = {
"Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"};
/* auxout output mux */
-static const struct soc_enum alc5623_aux_out_input_enum =
-SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 6, 4, alc5623_aux_out_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5623_aux_out_input_enum,
+ ALC5623_OUTPUT_MIXER_CTRL, 6,
+ alc5623_aux_out_input_sel);
static const struct snd_kcontrol_new alc5623_auxout_mux_controls =
SOC_DAPM_ENUM("Route", alc5623_aux_out_input_enum);
/* speaker output mux */
-static const struct soc_enum alc5623_spkout_input_enum =
-SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 10, 4, alc5623_spkout_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5623_spkout_input_enum,
+ ALC5623_OUTPUT_MIXER_CTRL, 10,
+ alc5623_spkout_input_sel);
static const struct snd_kcontrol_new alc5623_spkout_mux_controls =
SOC_DAPM_ENUM("Route", alc5623_spkout_input_enum);
/* headphone left output mux */
-static const struct soc_enum alc5623_hpl_out_input_enum =
-SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 9, 2, alc5623_hpl_out_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5623_hpl_out_input_enum,
+ ALC5623_OUTPUT_MIXER_CTRL, 9,
+ alc5623_hpl_out_input_sel);
static const struct snd_kcontrol_new alc5623_hpl_out_mux_controls =
SOC_DAPM_ENUM("Route", alc5623_hpl_out_input_enum);
/* headphone right output mux */
-static const struct soc_enum alc5623_hpr_out_input_enum =
-SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 8, 2, alc5623_hpr_out_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5623_hpr_out_input_enum,
+ ALC5623_OUTPUT_MIXER_CTRL, 8,
+ alc5623_hpr_out_input_sel);
static const struct snd_kcontrol_new alc5623_hpr_out_mux_controls =
SOC_DAPM_ENUM("Route", alc5623_hpr_out_input_enum);
/* speaker output N select */
-static const struct soc_enum alc5623_spk_n_sour_enum =
-SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 14, 4, alc5623_spk_n_sour_sel);
+static SOC_ENUM_SINGLE_DECL(alc5623_spk_n_sour_enum,
+ ALC5623_OUTPUT_MIXER_CTRL, 14,
+ alc5623_spk_n_sour_sel);
static const struct snd_kcontrol_new alc5623_spkoutn_mux_controls =
SOC_DAPM_ENUM("Route", alc5623_spk_n_sour_enum);
@@ -338,8 +331,9 @@ SND_SOC_DAPM_VMID("Vmid"),
};
static const char *alc5623_amp_names[] = {"AB Amp", "D Amp"};
-static const struct soc_enum alc5623_amp_enum =
- SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 13, 2, alc5623_amp_names);
+static SOC_ENUM_SINGLE_DECL(alc5623_amp_enum,
+ ALC5623_OUTPUT_MIXER_CTRL, 13,
+ alc5623_amp_names);
static const struct snd_kcontrol_new alc5623_amp_mux_controls =
SOC_DAPM_ENUM("Route", alc5623_amp_enum);
@@ -869,18 +863,28 @@ static struct snd_soc_dai_driver alc5623_dai = {
static int alc5623_suspend(struct snd_soc_codec *codec)
{
+ struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+
alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ regcache_cache_only(alc5623->regmap, true);
+
return 0;
}
static int alc5623_resume(struct snd_soc_codec *codec)
{
- int i, step = codec->driver->reg_cache_step;
- u16 *cache = codec->reg_cache;
+ struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+ int ret;
/* Sync reg_cache with the hardware */
- for (i = 2 ; i < codec->driver->reg_cache_size ; i += step)
- snd_soc_write(codec, i, cache[i]);
+ regcache_cache_only(alc5623->regmap, false);
+ ret = regcache_sync(alc5623->regmap);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to sync register cache: %d\n",
+ ret);
+ regcache_cache_only(alc5623->regmap, true);
+ return ret;
+ }
alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -900,14 +904,7 @@ static int alc5623_probe(struct snd_soc_codec *codec)
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, alc5623->control_type);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
alc5623_reset(codec);
- alc5623_fill_cache(codec);
/* power on device */
alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -980,9 +977,15 @@ static struct snd_soc_codec_driver soc_codec_device_alc5623 = {
.suspend = alc5623_suspend,
.resume = alc5623_resume,
.set_bias_level = alc5623_set_bias_level,
- .reg_cache_size = ALC5623_VENDOR_ID2+2,
- .reg_word_size = sizeof(u16),
- .reg_cache_step = 2,
+};
+
+static const struct regmap_config alc5623_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .reg_stride = 2,
+
+ .max_register = ALC5623_VENDOR_ID2,
+ .cache_type = REGCACHE_RBTREE,
};
/*
@@ -996,19 +999,32 @@ static int alc5623_i2c_probe(struct i2c_client *client,
{
struct alc5623_platform_data *pdata;
struct alc5623_priv *alc5623;
- int ret, vid1, vid2;
+ unsigned int vid1, vid2;
+ int ret;
- vid1 = i2c_smbus_read_word_data(client, ALC5623_VENDOR_ID1);
- if (vid1 < 0) {
- dev_err(&client->dev, "failed to read I2C\n");
- return -EIO;
+ alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv),
+ GFP_KERNEL);
+ if (alc5623 == NULL)
+ return -ENOMEM;
+
+ alc5623->regmap = devm_regmap_init_i2c(client, &alc5623_regmap);
+ if (IS_ERR(alc5623->regmap)) {
+ ret = PTR_ERR(alc5623->regmap);
+ dev_err(&client->dev, "Failed to initialise I/O: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID1, &vid1);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to read vendor ID1: %d\n", ret);
+ return ret;
}
vid1 = ((vid1 & 0xff) << 8) | (vid1 >> 8);
- vid2 = i2c_smbus_read_byte_data(client, ALC5623_VENDOR_ID2);
- if (vid2 < 0) {
- dev_err(&client->dev, "failed to read I2C\n");
- return -EIO;
+ ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID2, &vid2);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to read vendor ID2: %d\n", ret);
+ return ret;
}
if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) {
@@ -1021,11 +1037,6 @@ static int alc5623_i2c_probe(struct i2c_client *client,
dev_dbg(&client->dev, "Found codec id : alc56%02x\n", vid2);
- alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv),
- GFP_KERNEL);
- if (alc5623 == NULL)
- return -ENOMEM;
-
pdata = client->dev.platform_data;
if (pdata) {
alc5623->add_ctrl = pdata->add_ctrl;
@@ -1048,7 +1059,6 @@ static int alc5623_i2c_probe(struct i2c_client *client,
}
i2c_set_clientdata(client, alc5623);
- alc5623->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&client->dev,
&soc_codec_device_alc5623, &alc5623_dai, 1);
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index fb001c56cf8d..ec071a6306ef 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -293,51 +293,59 @@ static const char * const alc5632_i2s_out_sel[] = {
"ADC LR", "Voice Stereo Digital"};
/* auxout output mux */
-static const struct soc_enum alc5632_aux_out_input_enum =
-SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 6, 4, alc5632_aux_out_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_aux_out_input_enum,
+ ALC5632_OUTPUT_MIXER_CTRL, 6,
+ alc5632_aux_out_input_sel);
static const struct snd_kcontrol_new alc5632_auxout_mux_controls =
SOC_DAPM_ENUM("AuxOut Mux", alc5632_aux_out_input_enum);
/* speaker output mux */
-static const struct soc_enum alc5632_spkout_input_enum =
-SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 10, 4, alc5632_spkout_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_spkout_input_enum,
+ ALC5632_OUTPUT_MIXER_CTRL, 10,
+ alc5632_spkout_input_sel);
static const struct snd_kcontrol_new alc5632_spkout_mux_controls =
SOC_DAPM_ENUM("SpeakerOut Mux", alc5632_spkout_input_enum);
/* headphone left output mux */
-static const struct soc_enum alc5632_hpl_out_input_enum =
-SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 9, 2, alc5632_hpl_out_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_hpl_out_input_enum,
+ ALC5632_OUTPUT_MIXER_CTRL, 9,
+ alc5632_hpl_out_input_sel);
static const struct snd_kcontrol_new alc5632_hpl_out_mux_controls =
SOC_DAPM_ENUM("Left Headphone Mux", alc5632_hpl_out_input_enum);
/* headphone right output mux */
-static const struct soc_enum alc5632_hpr_out_input_enum =
-SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 8, 2, alc5632_hpr_out_input_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_hpr_out_input_enum,
+ ALC5632_OUTPUT_MIXER_CTRL, 8,
+ alc5632_hpr_out_input_sel);
static const struct snd_kcontrol_new alc5632_hpr_out_mux_controls =
SOC_DAPM_ENUM("Right Headphone Mux", alc5632_hpr_out_input_enum);
/* speaker output N select */
-static const struct soc_enum alc5632_spk_n_sour_enum =
-SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 14, 4, alc5632_spk_n_sour_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_spk_n_sour_enum,
+ ALC5632_OUTPUT_MIXER_CTRL, 14,
+ alc5632_spk_n_sour_sel);
static const struct snd_kcontrol_new alc5632_spkoutn_mux_controls =
SOC_DAPM_ENUM("SpeakerOut N Mux", alc5632_spk_n_sour_enum);
/* speaker amplifier */
static const char *alc5632_amp_names[] = {"AB Amp", "D Amp"};
-static const struct soc_enum alc5632_amp_enum =
- SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 13, 2, alc5632_amp_names);
+static SOC_ENUM_SINGLE_DECL(alc5632_amp_enum,
+ ALC5632_OUTPUT_MIXER_CTRL, 13,
+ alc5632_amp_names);
static const struct snd_kcontrol_new alc5632_amp_mux_controls =
SOC_DAPM_ENUM("AB-D Amp Mux", alc5632_amp_enum);
/* ADC output select */
-static const struct soc_enum alc5632_adcr_func_enum =
- SOC_ENUM_SINGLE(ALC5632_DAC_FUNC_SELECT, 5, 2, alc5632_adcr_func_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_adcr_func_enum,
+ ALC5632_DAC_FUNC_SELECT, 5,
+ alc5632_adcr_func_sel);
static const struct snd_kcontrol_new alc5632_adcr_func_controls =
SOC_DAPM_ENUM("ADCR Mux", alc5632_adcr_func_enum);
/* I2S out select */
-static const struct soc_enum alc5632_i2s_out_enum =
- SOC_ENUM_SINGLE(ALC5632_I2S_OUT_CTL, 5, 2, alc5632_i2s_out_sel);
+static SOC_ENUM_SINGLE_DECL(alc5632_i2s_out_enum,
+ ALC5632_I2S_OUT_CTL, 5,
+ alc5632_i2s_out_sel);
static const struct snd_kcontrol_new alc5632_i2s_out_controls =
SOC_DAPM_ENUM("I2SOut Mux", alc5632_i2s_out_enum);
@@ -1055,14 +1063,6 @@ static int alc5632_probe(struct snd_soc_codec *codec)
struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
int ret;
- codec->control_data = alc5632->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* power on device */
alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index e4295fee8f13..29e198f57d4c 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -53,6 +53,14 @@
#define ARIZONA_AIF_RX_ENABLES 0x1A
#define ARIZONA_AIF_FORCE_WRITE 0x1B
+#define ARIZONA_FLL_VCO_CORNER 141900000
+#define ARIZONA_FLL_MAX_FREF 13500000
+#define ARIZONA_FLL_MIN_FVCO 90000000
+#define ARIZONA_FLL_MAX_FRATIO 16
+#define ARIZONA_FLL_MAX_REFDIV 8
+#define ARIZONA_FLL_MIN_OUTDIV 2
+#define ARIZONA_FLL_MAX_OUTDIV 7
+
#define arizona_fll_err(_fll, fmt, ...) \
dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_fll_warn(_fll, fmt, ...) \
@@ -542,67 +550,76 @@ static const char *arizona_vol_ramp_text[] = {
"15ms/6dB", "30ms/6dB",
};
-const struct soc_enum arizona_in_vd_ramp =
- SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
- ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
+SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
+ ARIZONA_INPUT_VOLUME_RAMP,
+ ARIZONA_IN_VD_RAMP_SHIFT,
+ arizona_vol_ramp_text);
EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
-const struct soc_enum arizona_in_vi_ramp =
- SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
- ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
+SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
+ ARIZONA_INPUT_VOLUME_RAMP,
+ ARIZONA_IN_VI_RAMP_SHIFT,
+ arizona_vol_ramp_text);
EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
-const struct soc_enum arizona_out_vd_ramp =
- SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
- ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
+SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
+ ARIZONA_OUTPUT_VOLUME_RAMP,
+ ARIZONA_OUT_VD_RAMP_SHIFT,
+ arizona_vol_ramp_text);
EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
-const struct soc_enum arizona_out_vi_ramp =
- SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
- ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
+SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
+ ARIZONA_OUTPUT_VOLUME_RAMP,
+ ARIZONA_OUT_VI_RAMP_SHIFT,
+ arizona_vol_ramp_text);
EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
static const char *arizona_lhpf_mode_text[] = {
"Low-pass", "High-pass"
};
-const struct soc_enum arizona_lhpf1_mode =
- SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
- arizona_lhpf_mode_text);
+SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
+ ARIZONA_HPLPF1_1,
+ ARIZONA_LHPF1_MODE_SHIFT,
+ arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
-const struct soc_enum arizona_lhpf2_mode =
- SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
- arizona_lhpf_mode_text);
+SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
+ ARIZONA_HPLPF2_1,
+ ARIZONA_LHPF2_MODE_SHIFT,
+ arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
-const struct soc_enum arizona_lhpf3_mode =
- SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
- arizona_lhpf_mode_text);
+SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
+ ARIZONA_HPLPF3_1,
+ ARIZONA_LHPF3_MODE_SHIFT,
+ arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
-const struct soc_enum arizona_lhpf4_mode =
- SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
- arizona_lhpf_mode_text);
+SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
+ ARIZONA_HPLPF4_1,
+ ARIZONA_LHPF4_MODE_SHIFT,
+ arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
static const char *arizona_ng_hold_text[] = {
"30ms", "120ms", "250ms", "500ms",
};
-const struct soc_enum arizona_ng_hold =
- SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
- 4, arizona_ng_hold_text);
+SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
+ ARIZONA_NOISE_GATE_CONTROL,
+ ARIZONA_NGATE_HOLD_SHIFT,
+ arizona_ng_hold_text);
EXPORT_SYMBOL_GPL(arizona_ng_hold);
static const char * const arizona_in_hpf_cut_text[] = {
"2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
};
-const struct soc_enum arizona_in_hpf_cut_enum =
- SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT,
- ARRAY_SIZE(arizona_in_hpf_cut_text),
- arizona_in_hpf_cut_text);
+SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
+ ARIZONA_HPF_CONTROL,
+ ARIZONA_IN_HPF_CUT_SHIFT,
+ arizona_in_hpf_cut_text);
EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
static const char * const arizona_in_dmic_osr_text[] = {
@@ -1377,74 +1394,147 @@ struct arizona_fll_cfg {
int gain;
};
-static int arizona_calc_fll(struct arizona_fll *fll,
- struct arizona_fll_cfg *cfg,
- unsigned int Fref,
- unsigned int Fout)
+static int arizona_validate_fll(struct arizona_fll *fll,
+ unsigned int Fref,
+ unsigned int Fout)
{
- unsigned int target, div, gcd_fll;
- int i, ratio;
+ unsigned int Fvco_min;
+
+ if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
+ arizona_fll_err(fll,
+ "Can't scale %dMHz in to <=13.5MHz\n",
+ Fref);
+ return -EINVAL;
+ }
- arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
+ Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
+ if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
+ arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
+ Fout);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int arizona_find_fratio(unsigned int Fref, int *fratio)
+{
+ int i;
+
+ /* Find an appropriate FLL_FRATIO */
+ for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+ if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+ if (fratio)
+ *fratio = fll_fratios[i].fratio;
+ return fll_fratios[i].ratio;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int arizona_calc_fratio(struct arizona_fll *fll,
+ struct arizona_fll_cfg *cfg,
+ unsigned int target,
+ unsigned int Fref, bool sync)
+{
+ int init_ratio, ratio;
+ int refdiv, div;
- /* Fref must be <=13.5MHz */
+ /* Fref must be <=13.5MHz, find initial refdiv */
div = 1;
cfg->refdiv = 0;
- while ((Fref / div) > 13500000) {
+ while (Fref > ARIZONA_FLL_MAX_FREF) {
div *= 2;
+ Fref /= 2;
cfg->refdiv++;
- if (div > 8) {
- arizona_fll_err(fll,
- "Can't scale %dMHz in to <=13.5MHz\n",
- Fref);
+ if (div > ARIZONA_FLL_MAX_REFDIV)
return -EINVAL;
+ }
+
+ /* Find an appropriate FLL_FRATIO */
+ init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
+ if (init_ratio < 0) {
+ arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
+ Fref);
+ return init_ratio;
+ }
+
+ switch (fll->arizona->type) {
+ case WM5110:
+ if (fll->arizona->rev < 3 || sync)
+ return init_ratio;
+ break;
+ default:
+ return init_ratio;
+ }
+
+ cfg->fratio = init_ratio - 1;
+
+ /* Adjust FRATIO/refdiv to avoid integer mode if possible */
+ refdiv = cfg->refdiv;
+
+ while (div <= ARIZONA_FLL_MAX_REFDIV) {
+ for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
+ ratio++) {
+ if (target % (ratio * Fref)) {
+ cfg->refdiv = refdiv;
+ cfg->fratio = ratio - 1;
+ return ratio;
+ }
}
+
+ for (ratio = init_ratio - 1; ratio >= 0; ratio--) {
+ if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) <
+ Fref)
+ break;
+
+ if (target % (ratio * Fref)) {
+ cfg->refdiv = refdiv;
+ cfg->fratio = ratio - 1;
+ return ratio;
+ }
+ }
+
+ div *= 2;
+ Fref /= 2;
+ refdiv++;
+ init_ratio = arizona_find_fratio(Fref, NULL);
}
- /* Apply the division for our remaining calculations */
- Fref /= div;
+ arizona_fll_warn(fll, "Falling back to integer mode operation\n");
+ return cfg->fratio + 1;
+}
+
+static int arizona_calc_fll(struct arizona_fll *fll,
+ struct arizona_fll_cfg *cfg,
+ unsigned int Fref, bool sync)
+{
+ unsigned int target, div, gcd_fll;
+ int i, ratio;
+
+ arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
/* Fvco should be over the targt; don't check the upper bound */
- div = 1;
- while (Fout * div < 90000000 * fll->vco_mult) {
+ div = ARIZONA_FLL_MIN_OUTDIV;
+ while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
div++;
- if (div > 7) {
- arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
- Fout);
+ if (div > ARIZONA_FLL_MAX_OUTDIV)
return -EINVAL;
- }
}
- target = Fout * div / fll->vco_mult;
+ target = fll->fout * div / fll->vco_mult;
cfg->outdiv = div;
arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
- /* Find an appropraite FLL_FRATIO and factor it out of the target */
- for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
- if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
- cfg->fratio = fll_fratios[i].fratio;
- ratio = fll_fratios[i].ratio;
- break;
- }
- }
- if (i == ARRAY_SIZE(fll_fratios)) {
- arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
- Fref);
- return -EINVAL;
- }
+ /* Find an appropriate FLL_FRATIO and refdiv */
+ ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
+ if (ratio < 0)
+ return ratio;
- for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
- if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
- cfg->gain = fll_gains[i].gain;
- break;
- }
- }
- if (i == ARRAY_SIZE(fll_gains)) {
- arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
- Fref);
- return -EINVAL;
- }
+ /* Apply the division for our remaining calculations */
+ Fref = Fref / (1 << cfg->refdiv);
cfg->n = target / (ratio * Fref);
@@ -1469,6 +1559,18 @@ static int arizona_calc_fll(struct arizona_fll *fll,
cfg->lambda >>= 1;
}
+ for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
+ if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
+ cfg->gain = fll_gains[i].gain;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(fll_gains)) {
+ arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
+ Fref);
+ return -EINVAL;
+ }
+
arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
cfg->n, cfg->theta, cfg->lambda);
arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
@@ -1496,14 +1598,18 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
- if (sync)
- regmap_update_bits_async(arizona->regmap, base + 0x7,
- ARIZONA_FLL1_GAIN_MASK,
- cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
- else
- regmap_update_bits_async(arizona->regmap, base + 0x9,
- ARIZONA_FLL1_GAIN_MASK,
- cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+ if (sync) {
+ regmap_update_bits(arizona->regmap, base + 0x7,
+ ARIZONA_FLL1_GAIN_MASK,
+ cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+ } else {
+ regmap_update_bits(arizona->regmap, base + 0x5,
+ ARIZONA_FLL1_OUTDIV_MASK,
+ cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+ regmap_update_bits(arizona->regmap, base + 0x9,
+ ARIZONA_FLL1_GAIN_MASK,
+ cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+ }
regmap_update_bits_async(arizona->regmap, base + 2,
ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
@@ -1526,13 +1632,12 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll)
return reg & ARIZONA_FLL1_ENA;
}
-static void arizona_enable_fll(struct arizona_fll *fll,
- struct arizona_fll_cfg *ref,
- struct arizona_fll_cfg *sync)
+static void arizona_enable_fll(struct arizona_fll *fll)
{
struct arizona *arizona = fll->arizona;
int ret;
bool use_sync = false;
+ struct arizona_fll_cfg cfg;
/*
* If we have both REFCLK and SYNCCLK then enable both,
@@ -1540,23 +1645,21 @@ static void arizona_enable_fll(struct arizona_fll *fll,
*/
if (fll->ref_src >= 0 && fll->ref_freq &&
fll->ref_src != fll->sync_src) {
- regmap_update_bits_async(arizona->regmap, fll->base + 5,
- ARIZONA_FLL1_OUTDIV_MASK,
- ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+ arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
- arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
+ arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
false);
if (fll->sync_src >= 0) {
- arizona_apply_fll(arizona, fll->base + 0x10, sync,
+ arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
+
+ arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
fll->sync_src, true);
use_sync = true;
}
} else if (fll->sync_src >= 0) {
- regmap_update_bits_async(arizona->regmap, fll->base + 5,
- ARIZONA_FLL1_OUTDIV_MASK,
- sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+ arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
- arizona_apply_fll(arizona, fll->base, sync,
+ arizona_apply_fll(arizona, fll->base, &cfg,
fll->sync_src, false);
regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
@@ -1618,32 +1721,22 @@ static void arizona_disable_fll(struct arizona_fll *fll)
int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
unsigned int Fref, unsigned int Fout)
{
- struct arizona_fll_cfg ref, sync;
int ret;
if (fll->ref_src == source && fll->ref_freq == Fref)
return 0;
- if (fll->fout) {
- if (Fref > 0) {
- ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
- if (ret != 0)
- return ret;
- }
-
- if (fll->sync_src >= 0) {
- ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
- fll->fout);
- if (ret != 0)
- return ret;
- }
+ if (fll->fout && Fref > 0) {
+ ret = arizona_validate_fll(fll, Fref, fll->fout);
+ if (ret != 0)
+ return ret;
}
fll->ref_src = source;
fll->ref_freq = Fref;
if (fll->fout && Fref > 0) {
- arizona_enable_fll(fll, &ref, &sync);
+ arizona_enable_fll(fll);
}
return 0;
@@ -1653,7 +1746,6 @@ EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
int arizona_set_fll(struct arizona_fll *fll, int source,
unsigned int Fref, unsigned int Fout)
{
- struct arizona_fll_cfg ref, sync;
int ret;
if (fll->sync_src == source &&
@@ -1662,13 +1754,12 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
if (Fout) {
if (fll->ref_src >= 0) {
- ret = arizona_calc_fll(fll, &ref, fll->ref_freq,
- Fout);
+ ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
if (ret != 0)
return ret;
}
- ret = arizona_calc_fll(fll, &sync, Fref, Fout);
+ ret = arizona_validate_fll(fll, Fref, Fout);
if (ret != 0)
return ret;
}
@@ -1678,7 +1769,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
fll->fout = Fout;
if (Fout) {
- arizona_enable_fll(fll, &ref, &sync);
+ arizona_enable_fll(fll);
} else {
arizona_disable_fll(fll);
}
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index 43737a27d79c..1e25c7af853b 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -138,9 +138,8 @@ static int cq93vc_probe(struct snd_soc_codec *codec)
struct davinci_vc *davinci_vc = codec->dev->platform_data;
davinci_vc->cq93vc.codec = codec;
- codec->control_data = davinci_vc->regmap;
- snd_soc_codec_set_cache_io(codec, 32, 32, SND_SOC_REGMAP);
+ snd_soc_codec_set_cache_io(codec, davinci_vc->regmap);
/* Off, with power on */
cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 83c835d9fd88..3920e6264948 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -506,15 +506,6 @@ static int cs4270_probe(struct snd_soc_codec *codec)
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int ret;
- /* Tell ASoC what kind of I/O to use to read the registers. ASoC will
- * then do the I2C transactions itself.
- */
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret);
- return ret;
- }
-
/* Disable auto-mute. This feature appears to be buggy. In some
* situations, auto-mute will not deactivate when it should, so we want
* this feature disabled by default. An application (e.g. alsactl) can
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index ce05fd93dc74..aef4965750c7 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -159,7 +159,6 @@ static bool cs4271_volatile_reg(struct device *dev, unsigned int reg)
}
struct cs4271_private {
- /* SND_SOC_I2C or SND_SOC_SPI */
unsigned int mclk;
bool master;
bool deemph;
@@ -540,14 +539,10 @@ static int cs4271_probe(struct snd_soc_codec *codec)
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
struct cs4271_platform_data *cs4271plat = codec->dev->platform_data;
int ret;
- int gpio_nreset = -EINVAL;
bool amutec_eq_bmutec = false;
#ifdef CONFIG_OF
if (of_match_device(cs4271_dt_ids, codec->dev)) {
- gpio_nreset = of_get_named_gpio(codec->dev->of_node,
- "reset-gpio", 0);
-
if (of_get_property(codec->dev->of_node,
"cirrus,amutec-eq-bmutec", NULL))
amutec_eq_bmutec = true;
@@ -559,27 +554,19 @@ static int cs4271_probe(struct snd_soc_codec *codec)
#endif
if (cs4271plat) {
- if (gpio_is_valid(cs4271plat->gpio_nreset))
- gpio_nreset = cs4271plat->gpio_nreset;
-
amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
}
- if (gpio_nreset >= 0)
- if (devm_gpio_request(codec->dev, gpio_nreset, "CS4271 Reset"))
- gpio_nreset = -EINVAL;
- if (gpio_nreset >= 0) {
+ if (gpio_is_valid(cs4271->gpio_nreset)) {
/* Reset codec */
- gpio_direction_output(gpio_nreset, 0);
+ gpio_direction_output(cs4271->gpio_nreset, 0);
udelay(1);
- gpio_set_value(gpio_nreset, 1);
+ gpio_set_value(cs4271->gpio_nreset, 1);
/* Give the codec time to wake up */
udelay(1);
}
- cs4271->gpio_nreset = gpio_nreset;
-
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
@@ -625,6 +612,36 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
.num_dapm_routes = ARRAY_SIZE(cs4271_dapm_routes),
};
+static int cs4271_common_probe(struct device *dev,
+ struct cs4271_private **c)
+{
+ struct cs4271_platform_data *cs4271plat = dev->platform_data;
+ struct cs4271_private *cs4271;
+
+ cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL);
+ if (!cs4271)
+ return -ENOMEM;
+
+ if (of_match_device(cs4271_dt_ids, dev))
+ cs4271->gpio_nreset =
+ of_get_named_gpio(dev->of_node, "reset-gpio", 0);
+
+ if (cs4271plat)
+ cs4271->gpio_nreset = cs4271plat->gpio_nreset;
+
+ if (gpio_is_valid(cs4271->gpio_nreset)) {
+ int ret;
+
+ ret = devm_gpio_request(dev, cs4271->gpio_nreset,
+ "CS4271 Reset");
+ if (ret < 0)
+ return ret;
+ }
+
+ *c = cs4271;
+ return 0;
+}
+
#if defined(CONFIG_SPI_MASTER)
static const struct regmap_config cs4271_spi_regmap = {
@@ -644,10 +661,11 @@ static const struct regmap_config cs4271_spi_regmap = {
static int cs4271_spi_probe(struct spi_device *spi)
{
struct cs4271_private *cs4271;
+ int ret;
- cs4271 = devm_kzalloc(&spi->dev, sizeof(*cs4271), GFP_KERNEL);
- if (!cs4271)
- return -ENOMEM;
+ ret = cs4271_common_probe(&spi->dev, &cs4271);
+ if (ret < 0)
+ return ret;
spi_set_drvdata(spi, cs4271);
cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap);
@@ -698,10 +716,11 @@ static int cs4271_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct cs4271_private *cs4271;
+ int ret;
- cs4271 = devm_kzalloc(&client->dev, sizeof(*cs4271), GFP_KERNEL);
- if (!cs4271)
- return -ENOMEM;
+ ret = cs4271_common_probe(&client->dev, &cs4271);
+ if (ret < 0)
+ return ret;
i2c_set_clientdata(client, cs4271);
cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap);
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 6e9ea8379a91..6c0da2baa154 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -30,6 +30,7 @@
#include <sound/pcm_params.h>
#include <sound/pcm.h>
#include <linux/i2c.h>
+#include <linux/regmap.h>
#include "cs42l51.h"
@@ -40,7 +41,6 @@ enum master_slave_mode {
};
struct cs42l51_private {
- enum snd_soc_control_type control_type;
unsigned int mclk;
unsigned int audio_mode; /* The mode (I2S or left-justified) */
enum master_slave_mode func;
@@ -52,24 +52,6 @@ struct cs42l51_private {
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE)
-static int cs42l51_fill_cache(struct snd_soc_codec *codec)
-{
- u8 *cache = codec->reg_cache + 1;
- struct i2c_client *i2c_client = to_i2c_client(codec->dev);
- s32 length;
-
- length = i2c_smbus_read_i2c_block_data(i2c_client,
- CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache);
- if (length != CS42L51_NUMREGS) {
- dev_err(&i2c_client->dev,
- "I2C read failure, addr=0x%x (ret=%d vs %d)\n",
- i2c_client->addr, length, CS42L51_NUMREGS);
- return -EIO;
- }
-
- return 0;
-}
-
static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -124,9 +106,8 @@ static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
-/* This is a lie. after -102 db, it stays at -102 */
-/* maybe a range would be better */
-static const DECLARE_TLV_DB_SCALE(aout_tlv, -11550, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0);
static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
static const char *chan_mix[] = {
@@ -135,13 +116,12 @@ static const char *chan_mix[] = {
"R L",
};
-static const struct soc_enum cs42l51_chan_mix =
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(chan_mix), chan_mix);
+static SOC_ENUM_SINGLE_EXT_DECL(cs42l51_chan_mix, chan_mix);
static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
- 6, 0x19, 0x7F, adc_pcm_tlv),
+ 0, 0x19, 0x7F, adc_pcm_tlv),
SOC_DOUBLE_R("PCM Playback Switch",
CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
@@ -149,7 +129,7 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
0, 0x34, 0xE4, aout_tlv),
SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
- 6, 0x19, 0x7F, adc_pcm_tlv),
+ 0, 0x19, 0x7F, adc_pcm_tlv),
SOC_DOUBLE_R("ADC Mixer Switch",
CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
@@ -192,22 +172,22 @@ static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
static const char *cs42l51_dac_names[] = {"Direct PCM",
"DSP PCM", "ADC"};
-static const struct soc_enum cs42l51_dac_mux_enum =
- SOC_ENUM_SINGLE(CS42L51_DAC_CTL, 6, 3, cs42l51_dac_names);
+static SOC_ENUM_SINGLE_DECL(cs42l51_dac_mux_enum,
+ CS42L51_DAC_CTL, 6, cs42l51_dac_names);
static const struct snd_kcontrol_new cs42l51_dac_mux_controls =
SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);
static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",
"MIC Left", "MIC+preamp Left"};
-static const struct soc_enum cs42l51_adcl_mux_enum =
- SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 4, 4, cs42l51_adcl_names);
+static SOC_ENUM_SINGLE_DECL(cs42l51_adcl_mux_enum,
+ CS42L51_ADC_INPUT, 4, cs42l51_adcl_names);
static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =
SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);
static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",
"MIC Right", "MIC+preamp Right"};
-static const struct soc_enum cs42l51_adcr_mux_enum =
- SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 6, 4, cs42l51_adcr_names);
+static SOC_ENUM_SINGLE_DECL(cs42l51_adcr_mux_enum,
+ CS42L51_ADC_INPUT, 6, cs42l51_adcr_names);
static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
@@ -505,21 +485,8 @@ static struct snd_soc_dai_driver cs42l51_dai = {
static int cs42l51_probe(struct snd_soc_codec *codec)
{
- struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
int ret, reg;
- ret = cs42l51_fill_cache(codec);
- if (ret < 0) {
- dev_err(codec->dev, "failed to fill register cache\n");
- return ret;
- }
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs42l51->control_type);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/*
* DAC configuration
* - Use signal processor
@@ -538,8 +505,6 @@ static int cs42l51_probe(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
.probe = cs42l51_probe,
- .reg_cache_size = CS42L51_NUMREGS + 1,
- .reg_word_size = sizeof(u8),
.controls = cs42l51_snd_controls,
.num_controls = ARRAY_SIZE(cs42l51_snd_controls),
@@ -549,38 +514,53 @@ static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
.num_dapm_routes = ARRAY_SIZE(cs42l51_routes),
};
+static const struct regmap_config cs42l51_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = CS42L51_CHARGE_FREQ,
+ .cache_type = REGCACHE_RBTREE,
+};
+
static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct cs42l51_private *cs42l51;
+ struct regmap *regmap;
+ unsigned int val;
int ret;
+ regmap = devm_regmap_init_i2c(i2c_client, &cs42l51_regmap);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ dev_err(&i2c_client->dev, "Failed to create regmap: %d\n",
+ ret);
+ return ret;
+ }
+
/* Verify that we have a CS42L51 */
- ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
+ ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);
if (ret < 0) {
dev_err(&i2c_client->dev, "failed to read I2C\n");
goto error;
}
- if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
- (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
- dev_err(&i2c_client->dev, "Invalid chip id\n");
+ if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
+ (val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
+ dev_err(&i2c_client->dev, "Invalid chip id: %x\n", val);
ret = -ENODEV;
goto error;
}
dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
- ret & 7);
+ val & 7);
cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private),
GFP_KERNEL);
- if (!cs42l51) {
- dev_err(&i2c_client->dev, "could not allocate codec\n");
+ if (!cs42l51)
return -ENOMEM;
- }
i2c_set_clientdata(i2c_client, cs42l51);
- cs42l51->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c_client->dev,
&soc_codec_device_cs42l51, &cs42l51_dai, 1);
@@ -600,10 +580,17 @@ static const struct i2c_device_id cs42l51_id[] = {
};
MODULE_DEVICE_TABLE(i2c, cs42l51_id);
+static const struct of_device_id cs42l51_of_match[] = {
+ { .compatible = "cirrus,cs42l51", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cs42l51_of_match);
+
static struct i2c_driver cs42l51_i2c_driver = {
.driver = {
.name = "cs42l51-codec",
.owner = THIS_MODULE,
+ .of_match_table = cs42l51_of_match,
},
.id_table = cs42l51_id,
.probe = cs42l51_i2c_probe,
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 0bac6d5a4ac8..f0ca6bee6771 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -210,13 +210,11 @@ static const char * const cs42l52_adca_text[] = {
static const char * const cs42l52_adcb_text[] = {
"Input1B", "Input2B", "Input3B", "Input4B", "PGA Input Right"};
-static const struct soc_enum adca_enum =
- SOC_ENUM_SINGLE(CS42L52_ADC_PGA_A, 5,
- ARRAY_SIZE(cs42l52_adca_text), cs42l52_adca_text);
+static SOC_ENUM_SINGLE_DECL(adca_enum,
+ CS42L52_ADC_PGA_A, 5, cs42l52_adca_text);
-static const struct soc_enum adcb_enum =
- SOC_ENUM_SINGLE(CS42L52_ADC_PGA_B, 5,
- ARRAY_SIZE(cs42l52_adcb_text), cs42l52_adcb_text);
+static SOC_ENUM_SINGLE_DECL(adcb_enum,
+ CS42L52_ADC_PGA_B, 5, cs42l52_adcb_text);
static const struct snd_kcontrol_new adca_mux =
SOC_DAPM_ENUM("Left ADC Input Capture Mux", adca_enum);
@@ -229,26 +227,22 @@ static const char * const mic_bias_level_text[] = {
"0.8 +VA", "0.83 +VA", "0.91 +VA"
};
-static const struct soc_enum mic_bias_level_enum =
- SOC_ENUM_SINGLE(CS42L52_IFACE_CTL2, 0,
- ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text);
+static SOC_ENUM_SINGLE_DECL(mic_bias_level_enum,
+ CS42L52_IFACE_CTL2, 0, mic_bias_level_text);
static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" };
-static const struct soc_enum mica_enum =
- SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5,
- ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text);
+static SOC_ENUM_SINGLE_DECL(mica_enum,
+ CS42L52_MICA_CTL, 5, cs42l52_mic_text);
-static const struct soc_enum micb_enum =
- SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5,
- ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text);
+static SOC_ENUM_SINGLE_DECL(micb_enum,
+ CS42L52_MICB_CTL, 5, cs42l52_mic_text);
static const char * const digital_output_mux_text[] = {"ADC", "DSP"};
-static const struct soc_enum digital_output_mux_enum =
- SOC_ENUM_SINGLE(CS42L52_ADC_MISC_CTL, 6,
- ARRAY_SIZE(digital_output_mux_text),
- digital_output_mux_text);
+static SOC_ENUM_SINGLE_DECL(digital_output_mux_enum,
+ CS42L52_ADC_MISC_CTL, 6,
+ digital_output_mux_text);
static const struct snd_kcontrol_new digital_output_mux =
SOC_DAPM_ENUM("Digital Output Mux", digital_output_mux_enum);
@@ -258,18 +252,18 @@ static const char * const hp_gain_num_text[] = {
"0.7099", "0.8399", "1.000", "1.1430"
};
-static const struct soc_enum hp_gain_enum =
- SOC_ENUM_SINGLE(CS42L52_PB_CTL1, 5,
- ARRAY_SIZE(hp_gain_num_text), hp_gain_num_text);
+static SOC_ENUM_SINGLE_DECL(hp_gain_enum,
+ CS42L52_PB_CTL1, 5,
+ hp_gain_num_text);
static const char * const beep_pitch_text[] = {
"C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
"C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
};
-static const struct soc_enum beep_pitch_enum =
- SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 4,
- ARRAY_SIZE(beep_pitch_text), beep_pitch_text);
+static SOC_ENUM_SINGLE_DECL(beep_pitch_enum,
+ CS42L52_BEEP_FREQ, 4,
+ beep_pitch_text);
static const char * const beep_ontime_text[] = {
"86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
@@ -277,66 +271,66 @@ static const char * const beep_ontime_text[] = {
"3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
};
-static const struct soc_enum beep_ontime_enum =
- SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 0,
- ARRAY_SIZE(beep_ontime_text), beep_ontime_text);
+static SOC_ENUM_SINGLE_DECL(beep_ontime_enum,
+ CS42L52_BEEP_FREQ, 0,
+ beep_ontime_text);
static const char * const beep_offtime_text[] = {
"1.23 s", "2.58 s", "3.90 s", "5.20 s",
"6.60 s", "8.05 s", "9.35 s", "10.80 s"
};
-static const struct soc_enum beep_offtime_enum =
- SOC_ENUM_SINGLE(CS42L52_BEEP_VOL, 5,
- ARRAY_SIZE(beep_offtime_text), beep_offtime_text);
+static SOC_ENUM_SINGLE_DECL(beep_offtime_enum,
+ CS42L52_BEEP_VOL, 5,
+ beep_offtime_text);
static const char * const beep_config_text[] = {
"Off", "Single", "Multiple", "Continuous"
};
-static const struct soc_enum beep_config_enum =
- SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 6,
- ARRAY_SIZE(beep_config_text), beep_config_text);
+static SOC_ENUM_SINGLE_DECL(beep_config_enum,
+ CS42L52_BEEP_TONE_CTL, 6,
+ beep_config_text);
static const char * const beep_bass_text[] = {
"50 Hz", "100 Hz", "200 Hz", "250 Hz"
};
-static const struct soc_enum beep_bass_enum =
- SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 1,
- ARRAY_SIZE(beep_bass_text), beep_bass_text);
+static SOC_ENUM_SINGLE_DECL(beep_bass_enum,
+ CS42L52_BEEP_TONE_CTL, 1,
+ beep_bass_text);
static const char * const beep_treble_text[] = {
"5 kHz", "7 kHz", "10 kHz", " 15 kHz"
};
-static const struct soc_enum beep_treble_enum =
- SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 3,
- ARRAY_SIZE(beep_treble_text), beep_treble_text);
+static SOC_ENUM_SINGLE_DECL(beep_treble_enum,
+ CS42L52_BEEP_TONE_CTL, 3,
+ beep_treble_text);
static const char * const ng_threshold_text[] = {
"-34dB", "-37dB", "-40dB", "-43dB",
"-46dB", "-52dB", "-58dB", "-64dB"
};
-static const struct soc_enum ng_threshold_enum =
- SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 2,
- ARRAY_SIZE(ng_threshold_text), ng_threshold_text);
+static SOC_ENUM_SINGLE_DECL(ng_threshold_enum,
+ CS42L52_NOISE_GATE_CTL, 2,
+ ng_threshold_text);
static const char * const cs42l52_ng_delay_text[] = {
"50ms", "100ms", "150ms", "200ms"};
-static const struct soc_enum ng_delay_enum =
- SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 0,
- ARRAY_SIZE(cs42l52_ng_delay_text), cs42l52_ng_delay_text);
+static SOC_ENUM_SINGLE_DECL(ng_delay_enum,
+ CS42L52_NOISE_GATE_CTL, 0,
+ cs42l52_ng_delay_text);
static const char * const cs42l52_ng_type_text[] = {
"Apply Specific", "Apply All"
};
-static const struct soc_enum ng_type_enum =
- SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 6,
- ARRAY_SIZE(cs42l52_ng_type_text), cs42l52_ng_type_text);
+static SOC_ENUM_SINGLE_DECL(ng_type_enum,
+ CS42L52_NOISE_GATE_CTL, 6,
+ cs42l52_ng_type_text);
static const char * const left_swap_text[] = {
"Left", "LR 2", "Right"};
@@ -347,7 +341,7 @@ static const char * const right_swap_text[] = {
static const unsigned int swap_values[] = { 0, 1, 3 };
static const struct soc_enum adca_swap_enum =
- SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 2, 1,
+ SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 2, 3,
ARRAY_SIZE(left_swap_text),
left_swap_text,
swap_values);
@@ -356,7 +350,7 @@ static const struct snd_kcontrol_new adca_mixer =
SOC_DAPM_ENUM("Route", adca_swap_enum);
static const struct soc_enum pcma_swap_enum =
- SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 6, 1,
+ SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 6, 3,
ARRAY_SIZE(left_swap_text),
left_swap_text,
swap_values);
@@ -365,7 +359,7 @@ static const struct snd_kcontrol_new pcma_mixer =
SOC_DAPM_ENUM("Route", pcma_swap_enum);
static const struct soc_enum adcb_swap_enum =
- SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 0, 1,
+ SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 0, 3,
ARRAY_SIZE(right_swap_text),
right_swap_text,
swap_values);
@@ -374,7 +368,7 @@ static const struct snd_kcontrol_new adcb_mixer =
SOC_DAPM_ENUM("Route", adcb_swap_enum);
static const struct soc_enum pcmb_swap_enum =
- SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 4, 1,
+ SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 4, 3,
ARRAY_SIZE(right_swap_text),
right_swap_text,
swap_values);
@@ -1115,14 +1109,7 @@ static void cs42l52_free_beep(struct snd_soc_codec *codec)
static int cs42l52_probe(struct snd_soc_codec *codec)
{
struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
- int ret;
- codec->control_data = cs42l52->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
regcache_cache_only(cs42l52->regmap, true);
cs42l52_add_mic_controls(codec);
@@ -1134,7 +1121,7 @@ static int cs42l52_probe(struct snd_soc_codec *codec)
cs42l52->sysclk = CS42L52_DEFAULT_CLK;
cs42l52->config.format = CS42L52_DEFAULT_FORMAT;
- return ret;
+ return 0;
}
static int cs42l52_remove(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 549d5d6a3fef..0ee60a19a263 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -278,13 +278,13 @@ static const DECLARE_TLV_DB_SCALE(attn_tlv, -6300, 100, 1);
static const char * const cs42l73_pgaa_text[] = { "Line A", "Mic 1" };
static const char * const cs42l73_pgab_text[] = { "Line B", "Mic 2" };
-static const struct soc_enum pgaa_enum =
- SOC_ENUM_SINGLE(CS42L73_ADCIPC, 3,
- ARRAY_SIZE(cs42l73_pgaa_text), cs42l73_pgaa_text);
+static SOC_ENUM_SINGLE_DECL(pgaa_enum,
+ CS42L73_ADCIPC, 3,
+ cs42l73_pgaa_text);
-static const struct soc_enum pgab_enum =
- SOC_ENUM_SINGLE(CS42L73_ADCIPC, 7,
- ARRAY_SIZE(cs42l73_pgab_text), cs42l73_pgab_text);
+static SOC_ENUM_SINGLE_DECL(pgab_enum,
+ CS42L73_ADCIPC, 7,
+ cs42l73_pgab_text);
static const struct snd_kcontrol_new pgaa_mux =
SOC_DAPM_ENUM("Left Analog Input Capture Mux", pgaa_enum);
@@ -309,9 +309,9 @@ static const struct snd_kcontrol_new input_right_mixer[] = {
static const char * const cs42l73_ng_delay_text[] = {
"50ms", "100ms", "150ms", "200ms" };
-static const struct soc_enum ng_delay_enum =
- SOC_ENUM_SINGLE(CS42L73_NGCAB, 0,
- ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text);
+static SOC_ENUM_SINGLE_DECL(ng_delay_enum,
+ CS42L73_NGCAB, 0,
+ cs42l73_ng_delay_text);
static const char * const cs42l73_mono_mix_texts[] = {
"Left", "Right", "Mono Mix"};
@@ -319,7 +319,7 @@ static const char * const cs42l73_mono_mix_texts[] = {
static const unsigned int cs42l73_mono_mix_values[] = { 0, 1, 2 };
static const struct soc_enum spk_asp_enum =
- SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 6, 1,
+ SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 6, 3,
ARRAY_SIZE(cs42l73_mono_mix_texts),
cs42l73_mono_mix_texts,
cs42l73_mono_mix_values);
@@ -337,7 +337,7 @@ static const struct snd_kcontrol_new spk_xsp_mixer =
SOC_DAPM_ENUM("Route", spk_xsp_enum);
static const struct soc_enum esl_asp_enum =
- SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 2, 5,
+ SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 2, 3,
ARRAY_SIZE(cs42l73_mono_mix_texts),
cs42l73_mono_mix_texts,
cs42l73_mono_mix_values);
@@ -346,7 +346,7 @@ static const struct snd_kcontrol_new esl_asp_mixer =
SOC_DAPM_ENUM("Route", esl_asp_enum);
static const struct soc_enum esl_xsp_enum =
- SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 0, 7,
+ SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 0, 3,
ARRAY_SIZE(cs42l73_mono_mix_texts),
cs42l73_mono_mix_texts,
cs42l73_mono_mix_values);
@@ -357,19 +357,19 @@ static const struct snd_kcontrol_new esl_xsp_mixer =
static const char * const cs42l73_ip_swap_text[] = {
"Stereo", "Mono A", "Mono B", "Swap A-B"};
-static const struct soc_enum ip_swap_enum =
- SOC_ENUM_SINGLE(CS42L73_MIOPC, 6,
- ARRAY_SIZE(cs42l73_ip_swap_text), cs42l73_ip_swap_text);
+static SOC_ENUM_SINGLE_DECL(ip_swap_enum,
+ CS42L73_MIOPC, 6,
+ cs42l73_ip_swap_text);
static const char * const cs42l73_spo_mixer_text[] = {"Mono", "Stereo"};
-static const struct soc_enum vsp_output_mux_enum =
- SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 5,
- ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text);
+static SOC_ENUM_SINGLE_DECL(vsp_output_mux_enum,
+ CS42L73_MIXERCTL, 5,
+ cs42l73_spo_mixer_text);
-static const struct soc_enum xsp_output_mux_enum =
- SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 4,
- ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text);
+static SOC_ENUM_SINGLE_DECL(xsp_output_mux_enum,
+ CS42L73_MIXERCTL, 4,
+ cs42l73_spo_mixer_text);
static const struct snd_kcontrol_new vsp_output_mux =
SOC_DAPM_ENUM("Route", vsp_output_mux_enum);
@@ -1108,7 +1108,7 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return 0;
}
-static u32 cs42l73_asrc_rates[] = {
+static const unsigned int cs42l73_asrc_rates[] = {
8000, 11025, 12000, 16000, 22050,
24000, 32000, 44100, 48000
};
@@ -1241,7 +1241,7 @@ static int cs42l73_set_tristate(struct snd_soc_dai *dai, int tristate)
0x7F, tristate << 7);
}
-static struct snd_pcm_hw_constraint_list constraints_12_24 = {
+static const struct snd_pcm_hw_constraint_list constraints_12_24 = {
.count = ARRAY_SIZE(cs42l73_asrc_rates),
.list = cs42l73_asrc_rates,
};
@@ -1255,9 +1255,6 @@ static int cs42l73_pcm_startup(struct snd_pcm_substream *substream,
return 0;
}
-/* SNDRV_PCM_RATE_KNOT -> 12000, 24000 Hz, limit with constraint list */
-#define CS42L73_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
-
#define CS42L73_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
@@ -1278,14 +1275,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
.stream_name = "XSP Playback",
.channels_min = 1,
.channels_max = 2,
- .rates = CS42L73_RATES,
+ .rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L73_FORMATS,
},
.capture = {
.stream_name = "XSP Capture",
.channels_min = 1,
.channels_max = 2,
- .rates = CS42L73_RATES,
+ .rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L73_FORMATS,
},
.ops = &cs42l73_ops,
@@ -1298,14 +1295,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
.stream_name = "ASP Playback",
.channels_min = 2,
.channels_max = 2,
- .rates = CS42L73_RATES,
+ .rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L73_FORMATS,
},
.capture = {
.stream_name = "ASP Capture",
.channels_min = 2,
.channels_max = 2,
- .rates = CS42L73_RATES,
+ .rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L73_FORMATS,
},
.ops = &cs42l73_ops,
@@ -1318,14 +1315,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = {
.stream_name = "VSP Playback",
.channels_min = 1,
.channels_max = 2,
- .rates = CS42L73_RATES,
+ .rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L73_FORMATS,
},
.capture = {
.stream_name = "VSP Capture",
.channels_min = 1,
.channels_max = 2,
- .rates = CS42L73_RATES,
+ .rates = SNDRV_PCM_RATE_KNOT,
.formats = CS42L73_FORMATS,
},
.ops = &cs42l73_ops,
@@ -1348,17 +1345,8 @@ static int cs42l73_resume(struct snd_soc_codec *codec)
static int cs42l73_probe(struct snd_soc_codec *codec)
{
- int ret;
struct cs42l73_private *cs42l73 = snd_soc_codec_get_drvdata(codec);
- codec->control_data = cs42l73->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Set Charge Pump Frequency */
@@ -1371,7 +1359,7 @@ static int cs42l73_probe(struct snd_soc_codec *codec)
cs42l73->mclksel = CS42L73_CLKID_MCLK1;
cs42l73->mclk = 0;
- return ret;
+ return 0;
}
static int cs42l73_remove(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c
new file mode 100644
index 000000000000..657dce27eade
--- /dev/null
+++ b/sound/soc/codecs/cs42xx8-i2c.c
@@ -0,0 +1,64 @@
+/*
+ * Cirrus Logic CS42448/CS42888 Audio CODEC DAI I2C driver
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.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/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+
+#include "cs42xx8.h"
+
+static int cs42xx8_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ u32 ret = cs42xx8_probe(&i2c->dev,
+ devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config));
+ if (ret)
+ return ret;
+
+ pm_runtime_enable(&i2c->dev);
+ pm_request_idle(&i2c->dev);
+
+ return 0;
+}
+
+static int cs42xx8_i2c_remove(struct i2c_client *i2c)
+{
+ snd_soc_unregister_codec(&i2c->dev);
+ pm_runtime_disable(&i2c->dev);
+
+ return 0;
+}
+
+static struct i2c_device_id cs42xx8_i2c_id[] = {
+ {"cs42448", (kernel_ulong_t)&cs42448_data},
+ {"cs42888", (kernel_ulong_t)&cs42888_data},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id);
+
+static struct i2c_driver cs42xx8_i2c_driver = {
+ .driver = {
+ .name = "cs42xx8",
+ .owner = THIS_MODULE,
+ .pm = &cs42xx8_pm,
+ },
+ .probe = cs42xx8_i2c_probe,
+ .remove = cs42xx8_i2c_remove,
+ .id_table = cs42xx8_i2c_id,
+};
+
+module_i2c_driver(cs42xx8_i2c_driver);
+
+MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec I2C Driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
new file mode 100644
index 000000000000..082299a4e2fa
--- /dev/null
+++ b/sound/soc/codecs/cs42xx8.c
@@ -0,0 +1,602 @@
+/*
+ * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.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/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "cs42xx8.h"
+
+#define CS42XX8_NUM_SUPPLIES 4
+static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = {
+ "VA",
+ "VD",
+ "VLS",
+ "VLC",
+};
+
+#define CS42XX8_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+/* codec private data */
+struct cs42xx8_priv {
+ struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES];
+ const struct cs42xx8_driver_data *drvdata;
+ struct regmap *regmap;
+ struct clk *clk;
+
+ bool slave_mode;
+ unsigned long sysclk;
+};
+
+/* -127.5dB to 0dB with step of 0.5dB */
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+/* -64dB to 24dB with step of 0.5dB */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);
+
+static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" };
+static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross",
+ "Soft Ramp", "Soft Ramp on Zero Cross" };
+
+static const struct soc_enum adc1_single_enum =
+ SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single);
+static const struct soc_enum adc2_single_enum =
+ SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single);
+static const struct soc_enum adc3_single_enum =
+ SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single);
+static const struct soc_enum dac_szc_enum =
+ SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc);
+static const struct soc_enum adc_szc_enum =
+ SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc);
+
+static const struct snd_kcontrol_new cs42xx8_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1,
+ CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv),
+ SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3,
+ CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv),
+ SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5,
+ CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv),
+ SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7,
+ CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv),
+ SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1,
+ CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),
+ SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3,
+ CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),
+ SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0),
+ SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0),
+ SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0),
+ SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0),
+ SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0),
+ SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0),
+ SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1),
+ SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0),
+ SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum),
+ SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum),
+ SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0),
+ SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),
+ SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0),
+ SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0),
+ SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0),
+ SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum),
+};
+
+static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = {
+ SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5,
+ CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv),
+ SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0),
+ SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum),
+};
+
+static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1),
+ SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1),
+ SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1),
+ SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1),
+
+ SND_SOC_DAPM_OUTPUT("AOUT1L"),
+ SND_SOC_DAPM_OUTPUT("AOUT1R"),
+ SND_SOC_DAPM_OUTPUT("AOUT2L"),
+ SND_SOC_DAPM_OUTPUT("AOUT2R"),
+ SND_SOC_DAPM_OUTPUT("AOUT3L"),
+ SND_SOC_DAPM_OUTPUT("AOUT3R"),
+ SND_SOC_DAPM_OUTPUT("AOUT4L"),
+ SND_SOC_DAPM_OUTPUT("AOUT4R"),
+
+ SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1),
+ SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1),
+
+ SND_SOC_DAPM_INPUT("AIN1L"),
+ SND_SOC_DAPM_INPUT("AIN1R"),
+ SND_SOC_DAPM_INPUT("AIN2L"),
+ SND_SOC_DAPM_INPUT("AIN2R"),
+
+ SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = {
+ SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1),
+
+ SND_SOC_DAPM_INPUT("AIN3L"),
+ SND_SOC_DAPM_INPUT("AIN3R"),
+};
+
+static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = {
+ /* Playback */
+ { "AOUT1L", NULL, "DAC1" },
+ { "AOUT1R", NULL, "DAC1" },
+ { "DAC1", NULL, "PWR" },
+
+ { "AOUT2L", NULL, "DAC2" },
+ { "AOUT2R", NULL, "DAC2" },
+ { "DAC2", NULL, "PWR" },
+
+ { "AOUT3L", NULL, "DAC3" },
+ { "AOUT3R", NULL, "DAC3" },
+ { "DAC3", NULL, "PWR" },
+
+ { "AOUT4L", NULL, "DAC4" },
+ { "AOUT4R", NULL, "DAC4" },
+ { "DAC4", NULL, "PWR" },
+
+ /* Capture */
+ { "ADC1", NULL, "AIN1L" },
+ { "ADC1", NULL, "AIN1R" },
+ { "ADC1", NULL, "PWR" },
+
+ { "ADC2", NULL, "AIN2L" },
+ { "ADC2", NULL, "AIN2R" },
+ { "ADC2", NULL, "PWR" },
+};
+
+static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {
+ /* Capture */
+ { "ADC3", NULL, "AIN3L" },
+ { "ADC3", NULL, "AIN3R" },
+ { "ADC3", NULL, "PWR" },
+};
+
+struct cs42xx8_ratios {
+ unsigned int ratio;
+ unsigned char speed;
+ unsigned char mclk;
+};
+
+static const struct cs42xx8_ratios cs42xx8_ratios[] = {
+ { 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) },
+ { 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) },
+ { 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) },
+ { 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) },
+ { 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) },
+ { 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) },
+ { 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) },
+ { 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) },
+ { 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) }
+};
+
+static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+
+ cs42xx8->sysclk = freq;
+
+ return 0;
+}
+
+static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int format)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+ u32 val;
+
+ /* Set DAI format */
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_LEFT_J:
+ val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;
+ break;
+ default:
+ dev_err(codec->dev, "unsupported dai format\n");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF,
+ CS42XX8_INTF_DAC_DIF_MASK |
+ CS42XX8_INTF_ADC_DIF_MASK, val);
+
+ /* Set master/slave audio interface */
+ switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ cs42xx8->slave_mode = true;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ cs42xx8->slave_mode = false;
+ break;
+ default:
+ dev_err(codec->dev, "unsupported master/slave mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ u32 ratio = cs42xx8->sysclk / params_rate(params);
+ u32 i, fm, val, mask;
+
+ for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
+ if (cs42xx8_ratios[i].ratio == ratio)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(cs42xx8_ratios)) {
+ dev_err(codec->dev, "unsupported sysclk ratio\n");
+ return -EINVAL;
+ }
+
+ mask = CS42XX8_FUNCMOD_MFREQ_MASK;
+ val = cs42xx8_ratios[i].mclk;
+
+ fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed;
+
+ regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
+ CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,
+ CS42XX8_FUNCMOD_xC_FM(tx, fm) | val);
+
+ return 0;
+}
+
+static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+
+ regmap_update_bits(cs42xx8->regmap, CS42XX8_DACMUTE,
+ CS42XX8_DACMUTE_ALL, mute ? CS42XX8_DACMUTE_ALL : 0);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
+ .set_fmt = cs42xx8_set_dai_fmt,
+ .set_sysclk = cs42xx8_set_dai_sysclk,
+ .hw_params = cs42xx8_hw_params,
+ .digital_mute = cs42xx8_digital_mute,
+};
+
+static struct snd_soc_dai_driver cs42xx8_dai = {
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = CS42XX8_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = CS42XX8_FORMATS,
+ },
+ .ops = &cs42xx8_dai_ops,
+};
+
+static const struct reg_default cs42xx8_reg[] = {
+ { 0x01, 0x01 }, /* Chip I.D. and Revision Register */
+ { 0x02, 0x00 }, /* Power Control */
+ { 0x03, 0xF0 }, /* Functional Mode */
+ { 0x04, 0x46 }, /* Interface Formats */
+ { 0x05, 0x00 }, /* ADC Control & DAC De-Emphasis */
+ { 0x06, 0x10 }, /* Transition Control */
+ { 0x07, 0x00 }, /* DAC Channel Mute */
+ { 0x08, 0x00 }, /* Volume Control AOUT1 */
+ { 0x09, 0x00 }, /* Volume Control AOUT2 */
+ { 0x0a, 0x00 }, /* Volume Control AOUT3 */
+ { 0x0b, 0x00 }, /* Volume Control AOUT4 */
+ { 0x0c, 0x00 }, /* Volume Control AOUT5 */
+ { 0x0d, 0x00 }, /* Volume Control AOUT6 */
+ { 0x0e, 0x00 }, /* Volume Control AOUT7 */
+ { 0x0f, 0x00 }, /* Volume Control AOUT8 */
+ { 0x10, 0x00 }, /* DAC Channel Invert */
+ { 0x11, 0x00 }, /* Volume Control AIN1 */
+ { 0x12, 0x00 }, /* Volume Control AIN2 */
+ { 0x13, 0x00 }, /* Volume Control AIN3 */
+ { 0x14, 0x00 }, /* Volume Control AIN4 */
+ { 0x15, 0x00 }, /* Volume Control AIN5 */
+ { 0x16, 0x00 }, /* Volume Control AIN6 */
+ { 0x17, 0x00 }, /* ADC Channel Invert */
+ { 0x18, 0x00 }, /* Status Control */
+ { 0x1a, 0x00 }, /* Status Mask */
+ { 0x1b, 0x00 }, /* MUTEC Pin Control */
+};
+
+static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42XX8_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42XX8_CHIPID:
+ case CS42XX8_STATUS:
+ return false;
+ default:
+ return true;
+ }
+}
+
+const struct regmap_config cs42xx8_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = CS42XX8_LASTREG,
+ .reg_defaults = cs42xx8_reg,
+ .num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),
+ .volatile_reg = cs42xx8_volatile_register,
+ .writeable_reg = cs42xx8_writeable_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
+
+static int cs42xx8_codec_probe(struct snd_soc_codec *codec)
+{
+ struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ switch (cs42xx8->drvdata->num_adcs) {
+ case 3:
+ snd_soc_add_codec_controls(codec, cs42xx8_adc3_snd_controls,
+ ARRAY_SIZE(cs42xx8_adc3_snd_controls));
+ snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets,
+ ARRAY_SIZE(cs42xx8_adc3_dapm_widgets));
+ snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes,
+ ARRAY_SIZE(cs42xx8_adc3_dapm_routes));
+ break;
+ default:
+ break;
+ }
+
+ /* Mute all DAC channels */
+ regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL);
+
+ return 0;
+}
+
+static const struct snd_soc_codec_driver cs42xx8_driver = {
+ .probe = cs42xx8_codec_probe,
+ .idle_bias_off = true,
+
+ .controls = cs42xx8_snd_controls,
+ .num_controls = ARRAY_SIZE(cs42xx8_snd_controls),
+ .dapm_widgets = cs42xx8_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs42xx8_dapm_widgets),
+ .dapm_routes = cs42xx8_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes),
+};
+
+const struct cs42xx8_driver_data cs42448_data = {
+ .name = "cs42448",
+ .num_adcs = 3,
+};
+EXPORT_SYMBOL_GPL(cs42448_data);
+
+const struct cs42xx8_driver_data cs42888_data = {
+ .name = "cs42888",
+ .num_adcs = 2,
+};
+EXPORT_SYMBOL_GPL(cs42888_data);
+
+const struct of_device_id cs42xx8_of_match[] = {
+ { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
+ { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
+EXPORT_SYMBOL_GPL(cs42xx8_of_match);
+
+int cs42xx8_probe(struct device *dev, struct regmap *regmap)
+{
+ const struct of_device_id *of_id = of_match_device(cs42xx8_of_match, dev);
+ struct cs42xx8_priv *cs42xx8;
+ int ret, val, i;
+
+ cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);
+ if (cs42xx8 == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, cs42xx8);
+
+ if (of_id)
+ cs42xx8->drvdata = of_id->data;
+
+ if (!cs42xx8->drvdata) {
+ dev_err(dev, "failed to find driver data\n");
+ return -EINVAL;
+ }
+
+ cs42xx8->clk = devm_clk_get(dev, "mclk");
+ if (IS_ERR(cs42xx8->clk)) {
+ dev_err(dev, "failed to get the clock: %ld\n",
+ PTR_ERR(cs42xx8->clk));
+ return -EINVAL;
+ }
+
+ cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);
+
+ for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++)
+ cs42xx8->supplies[i].supply = cs42xx8_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev,
+ ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies);
+ if (ret) {
+ dev_err(dev, "failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
+ cs42xx8->supplies);
+ if (ret) {
+ dev_err(dev, "failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ /* Make sure hardware reset done */
+ msleep(5);
+
+ cs42xx8->regmap = regmap;
+ if (IS_ERR(cs42xx8->regmap)) {
+ ret = PTR_ERR(cs42xx8->regmap);
+ dev_err(dev, "failed to allocate regmap: %d\n", ret);
+ goto err_enable;
+ }
+
+ /*
+ * We haven't marked the chip revision as volatile due to
+ * sharing a register with the right input volume; explicitly
+ * bypass the cache to read it.
+ */
+ regcache_cache_bypass(cs42xx8->regmap, true);
+
+ /* Validate the chip ID */
+ regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
+ if (val < 0) {
+ dev_err(dev, "failed to get device ID: %x", val);
+ ret = -EINVAL;
+ goto err_enable;
+ }
+
+ /* The top four bits of the chip ID should be 0000 */
+ if ((val & CS42XX8_CHIPID_CHIP_ID_MASK) != 0x00) {
+ dev_err(dev, "unmatched chip ID: %d\n",
+ val & CS42XX8_CHIPID_CHIP_ID_MASK);
+ ret = -EINVAL;
+ goto err_enable;
+ }
+
+ dev_info(dev, "found device, revision %X\n",
+ val & CS42XX8_CHIPID_REV_ID_MASK);
+
+ regcache_cache_bypass(cs42xx8->regmap, false);
+
+ cs42xx8_dai.name = cs42xx8->drvdata->name;
+
+ /* Each adc supports stereo input */
+ cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;
+
+ ret = snd_soc_register_codec(dev, &cs42xx8_driver, &cs42xx8_dai, 1);
+ if (ret) {
+ dev_err(dev, "failed to register codec:%d\n", ret);
+ goto err_enable;
+ }
+
+ regcache_cache_only(cs42xx8->regmap, true);
+
+err_enable:
+ regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
+ cs42xx8->supplies);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cs42xx8_probe);
+
+#ifdef CONFIG_PM_RUNTIME
+static int cs42xx8_runtime_resume(struct device *dev)
+{
+ struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(cs42xx8->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable mclk: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
+ cs42xx8->supplies);
+ if (ret) {
+ dev_err(dev, "failed to enable supplies: %d\n", ret);
+ goto err_clk;
+ }
+
+ /* Make sure hardware reset done */
+ msleep(5);
+
+ regcache_cache_only(cs42xx8->regmap, false);
+
+ ret = regcache_sync(cs42xx8->regmap);
+ if (ret) {
+ dev_err(dev, "failed to sync regmap: %d\n", ret);
+ goto err_bulk;
+ }
+
+ return 0;
+
+err_bulk:
+ regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
+ cs42xx8->supplies);
+err_clk:
+ clk_disable_unprepare(cs42xx8->clk);
+
+ return ret;
+}
+
+static int cs42xx8_runtime_suspend(struct device *dev)
+{
+ struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
+
+ regcache_cache_only(cs42xx8->regmap, true);
+
+ regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
+ cs42xx8->supplies);
+
+ clk_disable_unprepare(cs42xx8->clk);
+
+ return 0;
+}
+#endif
+
+const struct dev_pm_ops cs42xx8_pm = {
+ SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(cs42xx8_pm);
+
+MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h
new file mode 100644
index 000000000000..da0b94aee419
--- /dev/null
+++ b/sound/soc/codecs/cs42xx8.h
@@ -0,0 +1,238 @@
+/*
+ * cs42xx8.h - Cirrus Logic CS42448/CS42888 Audio CODEC driver header file
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _CS42XX8_H
+#define _CS42XX8_H
+
+struct cs42xx8_driver_data {
+ char name[32];
+ int num_adcs;
+};
+
+extern const struct dev_pm_ops cs42xx8_pm;
+extern const struct cs42xx8_driver_data cs42448_data;
+extern const struct cs42xx8_driver_data cs42888_data;
+extern const struct regmap_config cs42xx8_regmap_config;
+int cs42xx8_probe(struct device *dev, struct regmap *regmap);
+
+/* CS42888 register map */
+#define CS42XX8_CHIPID 0x01 /* Chip ID */
+#define CS42XX8_PWRCTL 0x02 /* Power Control */
+#define CS42XX8_FUNCMOD 0x03 /* Functional Mode */
+#define CS42XX8_INTF 0x04 /* Interface Formats */
+#define CS42XX8_ADCCTL 0x05 /* ADC Control */
+#define CS42XX8_TXCTL 0x06 /* Transition Control */
+#define CS42XX8_DACMUTE 0x07 /* DAC Mute Control */
+#define CS42XX8_VOLAOUT1 0x08 /* Volume Control AOUT1 */
+#define CS42XX8_VOLAOUT2 0x09 /* Volume Control AOUT2 */
+#define CS42XX8_VOLAOUT3 0x0A /* Volume Control AOUT3 */
+#define CS42XX8_VOLAOUT4 0x0B /* Volume Control AOUT4 */
+#define CS42XX8_VOLAOUT5 0x0C /* Volume Control AOUT5 */
+#define CS42XX8_VOLAOUT6 0x0D /* Volume Control AOUT6 */
+#define CS42XX8_VOLAOUT7 0x0E /* Volume Control AOUT7 */
+#define CS42XX8_VOLAOUT8 0x0F /* Volume Control AOUT8 */
+#define CS42XX8_DACINV 0x10 /* DAC Channel Invert */
+#define CS42XX8_VOLAIN1 0x11 /* Volume Control AIN1 */
+#define CS42XX8_VOLAIN2 0x12 /* Volume Control AIN2 */
+#define CS42XX8_VOLAIN3 0x13 /* Volume Control AIN3 */
+#define CS42XX8_VOLAIN4 0x14 /* Volume Control AIN4 */
+#define CS42XX8_VOLAIN5 0x15 /* Volume Control AIN5 */
+#define CS42XX8_VOLAIN6 0x16 /* Volume Control AIN6 */
+#define CS42XX8_ADCINV 0x17 /* ADC Channel Invert */
+#define CS42XX8_STATUSCTL 0x18 /* Status Control */
+#define CS42XX8_STATUS 0x19 /* Status */
+#define CS42XX8_STATUSM 0x1A /* Status Mask */
+#define CS42XX8_MUTEC 0x1B /* MUTEC Pin Control */
+
+#define CS42XX8_FIRSTREG CS42XX8_CHIPID
+#define CS42XX8_LASTREG CS42XX8_MUTEC
+#define CS42XX8_NUMREGS (CS42XX8_LASTREG - CS42XX8_FIRSTREG + 1)
+#define CS42XX8_I2C_INCR 0x80
+
+/* Chip I.D. and Revision Register (Address 01h) */
+#define CS42XX8_CHIPID_CHIP_ID_MASK 0xF0
+#define CS42XX8_CHIPID_REV_ID_MASK 0x0F
+
+/* Power Control (Address 02h) */
+#define CS42XX8_PWRCTL_PDN_ADC3_SHIFT 7
+#define CS42XX8_PWRCTL_PDN_ADC3_MASK (1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC3 (1 << CS42XX8_PWRCTL_PDN_ADC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC2_SHIFT 6
+#define CS42XX8_PWRCTL_PDN_ADC2_MASK (1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC2 (1 << CS42XX8_PWRCTL_PDN_ADC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC1_SHIFT 5
+#define CS42XX8_PWRCTL_PDN_ADC1_MASK (1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_ADC1 (1 << CS42XX8_PWRCTL_PDN_ADC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC4_SHIFT 4
+#define CS42XX8_PWRCTL_PDN_DAC4_MASK (1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC4 (1 << CS42XX8_PWRCTL_PDN_DAC4_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC3_SHIFT 3
+#define CS42XX8_PWRCTL_PDN_DAC3_MASK (1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC3 (1 << CS42XX8_PWRCTL_PDN_DAC3_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC2_SHIFT 2
+#define CS42XX8_PWRCTL_PDN_DAC2_MASK (1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC2 (1 << CS42XX8_PWRCTL_PDN_DAC2_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC1_SHIFT 1
+#define CS42XX8_PWRCTL_PDN_DAC1_MASK (1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_DAC1 (1 << CS42XX8_PWRCTL_PDN_DAC1_SHIFT)
+#define CS42XX8_PWRCTL_PDN_SHIFT 0
+#define CS42XX8_PWRCTL_PDN_MASK (1 << CS42XX8_PWRCTL_PDN_SHIFT)
+#define CS42XX8_PWRCTL_PDN (1 << CS42XX8_PWRCTL_PDN_SHIFT)
+
+/* Functional Mode (Address 03h) */
+#define CS42XX8_FUNCMOD_DAC_FM_SHIFT 6
+#define CS42XX8_FUNCMOD_DAC_FM_WIDTH 2
+#define CS42XX8_FUNCMOD_DAC_FM_MASK (((1 << CS42XX8_FUNCMOD_DAC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_DAC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_DAC_FM(v) ((v) << CS42XX8_FUNCMOD_DAC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_ADC_FM_SHIFT 4
+#define CS42XX8_FUNCMOD_ADC_FM_WIDTH 2
+#define CS42XX8_FUNCMOD_ADC_FM_MASK (((1 << CS42XX8_FUNCMOD_ADC_FM_WIDTH) - 1) << CS42XX8_FUNCMOD_ADC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_ADC_FM(v) ((v) << CS42XX8_FUNCMOD_ADC_FM_SHIFT)
+#define CS42XX8_FUNCMOD_xC_FM_MASK(x) ((x) ? CS42XX8_FUNCMOD_DAC_FM_MASK : CS42XX8_FUNCMOD_ADC_FM_MASK)
+#define CS42XX8_FUNCMOD_xC_FM(x, v) ((x) ? CS42XX8_FUNCMOD_DAC_FM(v) : CS42XX8_FUNCMOD_ADC_FM(v))
+#define CS42XX8_FUNCMOD_MFREQ_SHIFT 1
+#define CS42XX8_FUNCMOD_MFREQ_WIDTH 3
+#define CS42XX8_FUNCMOD_MFREQ_MASK (((1 << CS42XX8_FUNCMOD_MFREQ_WIDTH) - 1) << CS42XX8_FUNCMOD_MFREQ_SHIFT)
+#define CS42XX8_FUNCMOD_MFREQ_256(s) ((0 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_384(s) ((1 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_512(s) ((2 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_768(s) ((3 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42XX8_FUNCMOD_MFREQ_1024(s) ((4 << CS42XX8_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+
+#define CS42XX8_FM_SINGLE 0
+#define CS42XX8_FM_DOUBLE 1
+#define CS42XX8_FM_QUAD 2
+#define CS42XX8_FM_AUTO 3
+
+/* Interface Formats (Address 04h) */
+#define CS42XX8_INTF_FREEZE_SHIFT 7
+#define CS42XX8_INTF_FREEZE_MASK (1 << CS42XX8_INTF_FREEZE_SHIFT)
+#define CS42XX8_INTF_FREEZE (1 << CS42XX8_INTF_FREEZE_SHIFT)
+#define CS42XX8_INTF_AUX_DIF_SHIFT 6
+#define CS42XX8_INTF_AUX_DIF_MASK (1 << CS42XX8_INTF_AUX_DIF_SHIFT)
+#define CS42XX8_INTF_AUX_DIF (1 << CS42XX8_INTF_AUX_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_SHIFT 3
+#define CS42XX8_INTF_DAC_DIF_WIDTH 3
+#define CS42XX8_INTF_DAC_DIF_MASK (((1 << CS42XX8_INTF_DAC_DIF_WIDTH) - 1) << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_LEFTJ (0 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_I2S (1 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_RIGHTJ (2 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_ONELINE_20 (4 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_ONELINE_24 (6 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_DAC_DIF_TDM (7 << CS42XX8_INTF_DAC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_SHIFT 0
+#define CS42XX8_INTF_ADC_DIF_WIDTH 3
+#define CS42XX8_INTF_ADC_DIF_MASK (((1 << CS42XX8_INTF_ADC_DIF_WIDTH) - 1) << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_LEFTJ (0 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_I2S (1 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_RIGHTJ (2 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_ONELINE_20 (4 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_ONELINE_24 (6 << CS42XX8_INTF_ADC_DIF_SHIFT)
+#define CS42XX8_INTF_ADC_DIF_TDM (7 << CS42XX8_INTF_ADC_DIF_SHIFT)
+
+/* ADC Control & DAC De-Emphasis (Address 05h) */
+#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT 7
+#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_MASK (1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT)
+#define CS42XX8_ADCCTL_ADC_HPF_FREEZE (1 << CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT)
+#define CS42XX8_ADCCTL_DAC_DEM_SHIFT 5
+#define CS42XX8_ADCCTL_DAC_DEM_MASK (1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT)
+#define CS42XX8_ADCCTL_DAC_DEM (1 << CS42XX8_ADCCTL_DAC_DEM_SHIFT)
+#define CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT 4
+#define CS42XX8_ADCCTL_ADC1_SINGLE_MASK (1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC1_SINGLE (1 << CS42XX8_ADCCTL_ADC1_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT 3
+#define CS42XX8_ADCCTL_ADC2_SINGLE_MASK (1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC2_SINGLE (1 << CS42XX8_ADCCTL_ADC2_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT 2
+#define CS42XX8_ADCCTL_ADC3_SINGLE_MASK (1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_ADC3_SINGLE (1 << CS42XX8_ADCCTL_ADC3_SINGLE_SHIFT)
+#define CS42XX8_ADCCTL_AIN5_MUX_SHIFT 1
+#define CS42XX8_ADCCTL_AIN5_MUX_MASK (1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT)
+#define CS42XX8_ADCCTL_AIN5_MUX (1 << CS42XX8_ADCCTL_AIN5_MUX_SHIFT)
+#define CS42XX8_ADCCTL_AIN6_MUX_SHIFT 0
+#define CS42XX8_ADCCTL_AIN6_MUX_MASK (1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT)
+#define CS42XX8_ADCCTL_AIN6_MUX (1 << CS42XX8_ADCCTL_AIN6_MUX_SHIFT)
+
+/* Transition Control (Address 06h) */
+#define CS42XX8_TXCTL_DAC_SNGVOL_SHIFT 7
+#define CS42XX8_TXCTL_DAC_SNGVOL_MASK (1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_DAC_SNGVOL (1 << CS42XX8_TXCTL_DAC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_SHIFT 5
+#define CS42XX8_TXCTL_DAC_SZC_WIDTH 2
+#define CS42XX8_TXCTL_DAC_SZC_MASK (((1 << CS42XX8_TXCTL_DAC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_IC (0 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_ZC (1 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_SR (2 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_DAC_SZC_SRZC (3 << CS42XX8_TXCTL_DAC_SZC_SHIFT)
+#define CS42XX8_TXCTL_AMUTE_SHIFT 4
+#define CS42XX8_TXCTL_AMUTE_MASK (1 << CS42XX8_TXCTL_AMUTE_SHIFT)
+#define CS42XX8_TXCTL_AMUTE (1 << CS42XX8_TXCTL_AMUTE_SHIFT)
+#define CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT 3
+#define CS42XX8_TXCTL_MUTE_ADC_SP_MASK (1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT)
+#define CS42XX8_TXCTL_MUTE_ADC_SP (1 << CS42XX8_TXCTL_MUTE_ADC_SP_SHIFT)
+#define CS42XX8_TXCTL_ADC_SNGVOL_SHIFT 2
+#define CS42XX8_TXCTL_ADC_SNGVOL_MASK (1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_ADC_SNGVOL (1 << CS42XX8_TXCTL_ADC_SNGVOL_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_SHIFT 0
+#define CS42XX8_TXCTL_ADC_SZC_MASK (((1 << CS42XX8_TXCTL_ADC_SZC_WIDTH) - 1) << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_IC (0 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_ZC (1 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_SR (2 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+#define CS42XX8_TXCTL_ADC_SZC_SRZC (3 << CS42XX8_TXCTL_ADC_SZC_SHIFT)
+
+/* DAC Channel Mute (Address 07h) */
+#define CS42XX8_DACMUTE_AOUT(n) (0x1 << n)
+#define CS42XX8_DACMUTE_ALL 0xff
+
+/* Status Control (Address 18h)*/
+#define CS42XX8_STATUSCTL_INI_SHIFT 2
+#define CS42XX8_STATUSCTL_INI_WIDTH 2
+#define CS42XX8_STATUSCTL_INI_MASK (((1 << CS42XX8_STATUSCTL_INI_WIDTH) - 1) << CS42XX8_STATUSCTL_INI_SHIFT)
+#define CS42XX8_STATUSCTL_INT_ACTIVE_HIGH (0 << CS42XX8_STATUSCTL_INI_SHIFT)
+#define CS42XX8_STATUSCTL_INT_ACTIVE_LOW (1 << CS42XX8_STATUSCTL_INI_SHIFT)
+#define CS42XX8_STATUSCTL_INT_OPEN_DRAIN (2 << CS42XX8_STATUSCTL_INI_SHIFT)
+
+/* Status (Address 19h)*/
+#define CS42XX8_STATUS_DAC_CLK_ERR_SHIFT 4
+#define CS42XX8_STATUS_DAC_CLK_ERR_MASK (1 << CS42XX8_STATUS_DAC_CLK_ERR_SHIFT)
+#define CS42XX8_STATUS_ADC_CLK_ERR_SHIFT 3
+#define CS42XX8_STATUS_ADC_CLK_ERR_MASK (1 << CS42XX8_STATUS_ADC_CLK_ERR_SHIFT)
+#define CS42XX8_STATUS_ADC3_OVFL_SHIFT 2
+#define CS42XX8_STATUS_ADC3_OVFL_MASK (1 << CS42XX8_STATUS_ADC3_OVFL_SHIFT)
+#define CS42XX8_STATUS_ADC2_OVFL_SHIFT 1
+#define CS42XX8_STATUS_ADC2_OVFL_MASK (1 << CS42XX8_STATUS_ADC2_OVFL_SHIFT)
+#define CS42XX8_STATUS_ADC1_OVFL_SHIFT 0
+#define CS42XX8_STATUS_ADC1_OVFL_MASK (1 << CS42XX8_STATUS_ADC1_OVFL_SHIFT)
+
+/* Status Mask (Address 1Ah) */
+#define CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT 4
+#define CS42XX8_STATUS_DAC_CLK_ERR_M_MASK (1 << CS42XX8_STATUS_DAC_CLK_ERR_M_SHIFT)
+#define CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT 3
+#define CS42XX8_STATUS_ADC_CLK_ERR_M_MASK (1 << CS42XX8_STATUS_ADC_CLK_ERR_M_SHIFT)
+#define CS42XX8_STATUS_ADC3_OVFL_M_SHIFT 2
+#define CS42XX8_STATUS_ADC3_OVFL_M_MASK (1 << CS42XX8_STATUS_ADC3_OVFL_M_SHIFT)
+#define CS42XX8_STATUS_ADC2_OVFL_M_SHIFT 1
+#define CS42XX8_STATUS_ADC2_OVFL_M_MASK (1 << CS42XX8_STATUS_ADC2_OVFL_M_SHIFT)
+#define CS42XX8_STATUS_ADC1_OVFL_M_SHIFT 0
+#define CS42XX8_STATUS_ADC1_OVFL_M_MASK (1 << CS42XX8_STATUS_ADC1_OVFL_M_SHIFT)
+
+/* MUTEC Pin Control (Address 1Bh) */
+#define CS42XX8_MUTEC_MCPOLARITY_SHIFT 1
+#define CS42XX8_MUTEC_MCPOLARITY_MASK (1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
+#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_LOW (0 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
+#define CS42XX8_MUTEC_MCPOLARITY_ACTIVE_HIGH (1 << CS42XX8_MUTEC_MCPOLARITY_SHIFT)
+#define CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT 0
+#define CS42XX8_MUTEC_MUTEC_ACTIVE_MASK (1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT)
+#define CS42XX8_MUTEC_MUTEC_ACTIVE (1 << CS42XX8_MUTEC_MUTEC_ACTIVE_SHIFT)
+#endif /* _CS42XX8_H */
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index e62e294a8033..137e8ebc092c 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -307,29 +307,29 @@ static const char * const da7210_hpf_cutoff_txt[] = {
"Fs/8192*pi", "Fs/4096*pi", "Fs/2048*pi", "Fs/1024*pi"
};
-static const struct soc_enum da7210_dac_hpf_cutoff =
- SOC_ENUM_SINGLE(DA7210_DAC_HPF, 0, 4, da7210_hpf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da7210_dac_hpf_cutoff,
+ DA7210_DAC_HPF, 0, da7210_hpf_cutoff_txt);
-static const struct soc_enum da7210_adc_hpf_cutoff =
- SOC_ENUM_SINGLE(DA7210_ADC_HPF, 0, 4, da7210_hpf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da7210_adc_hpf_cutoff,
+ DA7210_ADC_HPF, 0, da7210_hpf_cutoff_txt);
/* ADC and DAC voice (8kHz) high pass cutoff value */
static const char * const da7210_vf_cutoff_txt[] = {
"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
};
-static const struct soc_enum da7210_dac_vf_cutoff =
- SOC_ENUM_SINGLE(DA7210_DAC_HPF, 4, 8, da7210_vf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da7210_dac_vf_cutoff,
+ DA7210_DAC_HPF, 4, da7210_vf_cutoff_txt);
-static const struct soc_enum da7210_adc_vf_cutoff =
- SOC_ENUM_SINGLE(DA7210_ADC_HPF, 4, 8, da7210_vf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da7210_adc_vf_cutoff,
+ DA7210_ADC_HPF, 4, da7210_vf_cutoff_txt);
static const char *da7210_hp_mode_txt[] = {
"Class H", "Class G"
};
-static const struct soc_enum da7210_hp_mode_sel =
- SOC_ENUM_SINGLE(DA7210_HP_CFG, 0, 2, da7210_hp_mode_txt);
+static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel,
+ DA7210_HP_CFG, 0, da7210_hp_mode_txt);
/* ALC can be enabled only if noise suppression is disabled */
static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,
@@ -1071,17 +1071,9 @@ static struct snd_soc_dai_driver da7210_dai = {
static int da7210_probe(struct snd_soc_codec *codec)
{
struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
- int ret;
dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
- codec->control_data = da7210->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
da7210->mclk_rate = 0; /* This will be set from set_sysclk() */
da7210->master = 0; /* This will be set from set_fmt() */
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 0c77e7ad7423..738fa18a50d2 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -63,30 +63,30 @@ static const char * const da7213_voice_hpf_corner_txt[] = {
"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
};
-static const struct soc_enum da7213_dac_voice_hpf_corner =
- SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT,
- DA7213_VOICE_HPF_CORNER_MAX,
- da7213_voice_hpf_corner_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_voice_hpf_corner,
+ DA7213_DAC_FILTERS1,
+ DA7213_VOICE_HPF_CORNER_SHIFT,
+ da7213_voice_hpf_corner_txt);
-static const struct soc_enum da7213_adc_voice_hpf_corner =
- SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT,
- DA7213_VOICE_HPF_CORNER_MAX,
- da7213_voice_hpf_corner_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_adc_voice_hpf_corner,
+ DA7213_ADC_FILTERS1,
+ DA7213_VOICE_HPF_CORNER_SHIFT,
+ da7213_voice_hpf_corner_txt);
/* ADC and DAC high pass filter cutoff value */
static const char * const da7213_audio_hpf_corner_txt[] = {
"Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000"
};
-static const struct soc_enum da7213_dac_audio_hpf_corner =
- SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT,
- DA7213_AUDIO_HPF_CORNER_MAX,
- da7213_audio_hpf_corner_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_audio_hpf_corner,
+ DA7213_DAC_FILTERS1
+ , DA7213_AUDIO_HPF_CORNER_SHIFT,
+ da7213_audio_hpf_corner_txt);
-static const struct soc_enum da7213_adc_audio_hpf_corner =
- SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT,
- DA7213_AUDIO_HPF_CORNER_MAX,
- da7213_audio_hpf_corner_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_adc_audio_hpf_corner,
+ DA7213_ADC_FILTERS1,
+ DA7213_AUDIO_HPF_CORNER_SHIFT,
+ da7213_audio_hpf_corner_txt);
/* Gain ramping rate value */
static const char * const da7213_gain_ramp_rate_txt[] = {
@@ -94,52 +94,50 @@ static const char * const da7213_gain_ramp_rate_txt[] = {
"nominal rate / 32"
};
-static const struct soc_enum da7213_gain_ramp_rate =
- SOC_ENUM_SINGLE(DA7213_GAIN_RAMP_CTRL, DA7213_GAIN_RAMP_RATE_SHIFT,
- DA7213_GAIN_RAMP_RATE_MAX, da7213_gain_ramp_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_gain_ramp_rate,
+ DA7213_GAIN_RAMP_CTRL,
+ DA7213_GAIN_RAMP_RATE_SHIFT,
+ da7213_gain_ramp_rate_txt);
/* DAC noise gate setup time value */
static const char * const da7213_dac_ng_setup_time_txt[] = {
"256 samples", "512 samples", "1024 samples", "2048 samples"
};
-static const struct soc_enum da7213_dac_ng_setup_time =
- SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME,
- DA7213_DAC_NG_SETUP_TIME_SHIFT,
- DA7213_DAC_NG_SETUP_TIME_MAX,
- da7213_dac_ng_setup_time_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_setup_time,
+ DA7213_DAC_NG_SETUP_TIME,
+ DA7213_DAC_NG_SETUP_TIME_SHIFT,
+ da7213_dac_ng_setup_time_txt);
/* DAC noise gate rampup rate value */
static const char * const da7213_dac_ng_rampup_txt[] = {
"0.02 ms/dB", "0.16 ms/dB"
};
-static const struct soc_enum da7213_dac_ng_rampup_rate =
- SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME,
- DA7213_DAC_NG_RAMPUP_RATE_SHIFT,
- DA7213_DAC_NG_RAMP_RATE_MAX,
- da7213_dac_ng_rampup_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampup_rate,
+ DA7213_DAC_NG_SETUP_TIME,
+ DA7213_DAC_NG_RAMPUP_RATE_SHIFT,
+ da7213_dac_ng_rampup_txt);
/* DAC noise gate rampdown rate value */
static const char * const da7213_dac_ng_rampdown_txt[] = {
"0.64 ms/dB", "20.48 ms/dB"
};
-static const struct soc_enum da7213_dac_ng_rampdown_rate =
- SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME,
- DA7213_DAC_NG_RAMPDN_RATE_SHIFT,
- DA7213_DAC_NG_RAMP_RATE_MAX,
- da7213_dac_ng_rampdown_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampdown_rate,
+ DA7213_DAC_NG_SETUP_TIME,
+ DA7213_DAC_NG_RAMPDN_RATE_SHIFT,
+ da7213_dac_ng_rampdown_txt);
/* DAC soft mute rate value */
static const char * const da7213_dac_soft_mute_rate_txt[] = {
"1", "2", "4", "8", "16", "32", "64"
};
-static const struct soc_enum da7213_dac_soft_mute_rate =
- SOC_ENUM_SINGLE(DA7213_DAC_FILTERS5, DA7213_DAC_SOFTMUTE_RATE_SHIFT,
- DA7213_DAC_SOFTMUTE_RATE_MAX,
- da7213_dac_soft_mute_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_soft_mute_rate,
+ DA7213_DAC_FILTERS5,
+ DA7213_DAC_SOFTMUTE_RATE_SHIFT,
+ da7213_dac_soft_mute_rate_txt);
/* ALC Attack Rate select */
static const char * const da7213_alc_attack_rate_txt[] = {
@@ -147,9 +145,10 @@ static const char * const da7213_alc_attack_rate_txt[] = {
"5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
};
-static const struct soc_enum da7213_alc_attack_rate =
- SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_ATTACK_SHIFT,
- DA7213_ALC_ATTACK_MAX, da7213_alc_attack_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_alc_attack_rate,
+ DA7213_ALC_CTRL2,
+ DA7213_ALC_ATTACK_SHIFT,
+ da7213_alc_attack_rate_txt);
/* ALC Release Rate select */
static const char * const da7213_alc_release_rate_txt[] = {
@@ -157,9 +156,10 @@ static const char * const da7213_alc_release_rate_txt[] = {
"11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
};
-static const struct soc_enum da7213_alc_release_rate =
- SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_RELEASE_SHIFT,
- DA7213_ALC_RELEASE_MAX, da7213_alc_release_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_alc_release_rate,
+ DA7213_ALC_CTRL2,
+ DA7213_ALC_RELEASE_SHIFT,
+ da7213_alc_release_rate_txt);
/* ALC Hold Time select */
static const char * const da7213_alc_hold_time_txt[] = {
@@ -168,22 +168,25 @@ static const char * const da7213_alc_hold_time_txt[] = {
"253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
};
-static const struct soc_enum da7213_alc_hold_time =
- SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_HOLD_SHIFT,
- DA7213_ALC_HOLD_MAX, da7213_alc_hold_time_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_alc_hold_time,
+ DA7213_ALC_CTRL3,
+ DA7213_ALC_HOLD_SHIFT,
+ da7213_alc_hold_time_txt);
/* ALC Input Signal Tracking rate select */
static const char * const da7213_alc_integ_rate_txt[] = {
"1/4", "1/16", "1/256", "1/65536"
};
-static const struct soc_enum da7213_alc_integ_attack_rate =
- SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_ATTACK_SHIFT,
- DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_attack_rate,
+ DA7213_ALC_CTRL3,
+ DA7213_ALC_INTEG_ATTACK_SHIFT,
+ da7213_alc_integ_rate_txt);
-static const struct soc_enum da7213_alc_integ_release_rate =
- SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_RELEASE_SHIFT,
- DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_release_rate,
+ DA7213_ALC_CTRL3,
+ DA7213_ALC_INTEG_RELEASE_SHIFT,
+ da7213_alc_integ_rate_txt);
/*
@@ -584,15 +587,17 @@ static const char * const da7213_mic_amp_in_sel_txt[] = {
"Differential", "MIC_P", "MIC_N"
};
-static const struct soc_enum da7213_mic_1_amp_in_sel =
- SOC_ENUM_SINGLE(DA7213_MIC_1_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT,
- DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_mic_1_amp_in_sel,
+ DA7213_MIC_1_CTRL,
+ DA7213_MIC_AMP_IN_SEL_SHIFT,
+ da7213_mic_amp_in_sel_txt);
static const struct snd_kcontrol_new da7213_mic_1_amp_in_sel_mux =
SOC_DAPM_ENUM("Mic 1 Amp Source MUX", da7213_mic_1_amp_in_sel);
-static const struct soc_enum da7213_mic_2_amp_in_sel =
- SOC_ENUM_SINGLE(DA7213_MIC_2_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT,
- DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_mic_2_amp_in_sel,
+ DA7213_MIC_2_CTRL,
+ DA7213_MIC_AMP_IN_SEL_SHIFT,
+ da7213_mic_amp_in_sel_txt);
static const struct snd_kcontrol_new da7213_mic_2_amp_in_sel_mux =
SOC_DAPM_ENUM("Mic 2 Amp Source MUX", da7213_mic_2_amp_in_sel);
@@ -601,15 +606,17 @@ static const char * const da7213_dai_src_txt[] = {
"ADC Left", "ADC Right", "DAI Input Left", "DAI Input Right"
};
-static const struct soc_enum da7213_dai_l_src =
- SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_L_SRC_SHIFT,
- DA7213_DAI_SRC_MAX, da7213_dai_src_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dai_l_src,
+ DA7213_DIG_ROUTING_DAI,
+ DA7213_DAI_L_SRC_SHIFT,
+ da7213_dai_src_txt);
static const struct snd_kcontrol_new da7213_dai_l_src_mux =
SOC_DAPM_ENUM("DAI Left Source MUX", da7213_dai_l_src);
-static const struct soc_enum da7213_dai_r_src =
- SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_R_SRC_SHIFT,
- DA7213_DAI_SRC_MAX, da7213_dai_src_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dai_r_src,
+ DA7213_DIG_ROUTING_DAI,
+ DA7213_DAI_R_SRC_SHIFT,
+ da7213_dai_src_txt);
static const struct snd_kcontrol_new da7213_dai_r_src_mux =
SOC_DAPM_ENUM("DAI Right Source MUX", da7213_dai_r_src);
@@ -619,15 +626,17 @@ static const char * const da7213_dac_src_txt[] = {
"DAI Input Right"
};
-static const struct soc_enum da7213_dac_l_src =
- SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_L_SRC_SHIFT,
- DA7213_DAC_SRC_MAX, da7213_dac_src_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_l_src,
+ DA7213_DIG_ROUTING_DAC,
+ DA7213_DAC_L_SRC_SHIFT,
+ da7213_dac_src_txt);
static const struct snd_kcontrol_new da7213_dac_l_src_mux =
SOC_DAPM_ENUM("DAC Left Source MUX", da7213_dac_l_src);
-static const struct soc_enum da7213_dac_r_src =
- SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_R_SRC_SHIFT,
- DA7213_DAC_SRC_MAX, da7213_dac_src_txt);
+static SOC_ENUM_SINGLE_DECL(da7213_dac_r_src,
+ DA7213_DIG_ROUTING_DAC,
+ DA7213_DAC_R_SRC_SHIFT,
+ da7213_dac_src_txt);
static const struct snd_kcontrol_new da7213_dac_r_src_mux =
SOC_DAPM_ENUM("DAC Right Source MUX", da7213_dac_r_src);
@@ -1384,17 +1393,9 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
static int da7213_probe(struct snd_soc_codec *codec)
{
- int ret;
struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec);
struct da7213_platform_data *pdata = da7213->pdata;
- codec->control_data = da7213->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* Default to using ALC auto offset calibration mode. */
snd_soc_update_bits(codec, DA7213_ALC_CTRL1,
DA7213_ALC_CALIB_MODE_MAN, 0);
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index f295b6569910..7d168ec71cd7 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -269,81 +269,65 @@ static const char *da732x_hpf_voice[] = {
"150Hz", "200Hz", "300Hz", "400Hz"
};
-static const struct soc_enum da732x_dac1_hpf_mode_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT,
- DA732X_HPF_MODE_MAX, da732x_hpf_mode)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac1_hpf_mode_enum,
+ DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT,
+ da732x_hpf_mode);
-static const struct soc_enum da732x_dac2_hpf_mode_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT,
- DA732X_HPF_MODE_MAX, da732x_hpf_mode)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac2_hpf_mode_enum,
+ DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT,
+ da732x_hpf_mode);
-static const struct soc_enum da732x_dac3_hpf_mode_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT,
- DA732X_HPF_MODE_MAX, da732x_hpf_mode)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac3_hpf_mode_enum,
+ DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT,
+ da732x_hpf_mode);
-static const struct soc_enum da732x_adc1_hpf_mode_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT,
- DA732X_HPF_MODE_MAX, da732x_hpf_mode)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_adc1_hpf_mode_enum,
+ DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT,
+ da732x_hpf_mode);
-static const struct soc_enum da732x_adc2_hpf_mode_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT,
- DA732X_HPF_MODE_MAX, da732x_hpf_mode)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_adc2_hpf_mode_enum,
+ DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT,
+ da732x_hpf_mode);
-static const struct soc_enum da732x_dac1_hp_filter_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT,
- DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac1_hp_filter_enum,
+ DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT,
+ da732x_hpf_music);
-static const struct soc_enum da732x_dac2_hp_filter_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT,
- DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac2_hp_filter_enum,
+ DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT,
+ da732x_hpf_music);
-static const struct soc_enum da732x_dac3_hp_filter_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT,
- DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac3_hp_filter_enum,
+ DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT,
+ da732x_hpf_music);
-static const struct soc_enum da732x_adc1_hp_filter_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT,
- DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_adc1_hp_filter_enum,
+ DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT,
+ da732x_hpf_music);
-static const struct soc_enum da732x_adc2_hp_filter_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT,
- DA732X_HPF_MUSIC_MAX, da732x_hpf_music)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_adc2_hp_filter_enum,
+ DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT,
+ da732x_hpf_music);
-static const struct soc_enum da732x_dac1_voice_filter_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT,
- DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac1_voice_filter_enum,
+ DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT,
+ da732x_hpf_voice);
-static const struct soc_enum da732x_dac2_voice_filter_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT,
- DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac2_voice_filter_enum,
+ DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT,
+ da732x_hpf_voice);
-static const struct soc_enum da732x_dac3_voice_filter_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT,
- DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_dac3_voice_filter_enum,
+ DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT,
+ da732x_hpf_voice);
-static const struct soc_enum da732x_adc1_voice_filter_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT,
- DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
-};
-
-static const struct soc_enum da732x_adc2_voice_filter_enum[] = {
- SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT,
- DA732X_HPF_VOICE_MAX, da732x_hpf_voice)
-};
+static SOC_ENUM_SINGLE_DECL(da732x_adc1_voice_filter_enum,
+ DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT,
+ da732x_hpf_voice);
+static SOC_ENUM_SINGLE_DECL(da732x_adc2_voice_filter_enum,
+ DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT,
+ da732x_hpf_voice);
static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -714,65 +698,65 @@ static const char *enable_text[] = {
};
/* ADC1LMUX */
-static const struct soc_enum adc1l_enum =
- SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT,
- DA732X_ADCL_MUX_MAX, adcl_text);
+static SOC_ENUM_SINGLE_DECL(adc1l_enum,
+ DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT,
+ adcl_text);
static const struct snd_kcontrol_new adc1l_mux =
SOC_DAPM_ENUM("ADC Route", adc1l_enum);
/* ADC1RMUX */
-static const struct soc_enum adc1r_enum =
- SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT,
- DA732X_ADCR_MUX_MAX, adcr_text);
+static SOC_ENUM_SINGLE_DECL(adc1r_enum,
+ DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT,
+ adcr_text);
static const struct snd_kcontrol_new adc1r_mux =
SOC_DAPM_ENUM("ADC Route", adc1r_enum);
/* ADC2LMUX */
-static const struct soc_enum adc2l_enum =
- SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT,
- DA732X_ADCL_MUX_MAX, adcl_text);
+static SOC_ENUM_SINGLE_DECL(adc2l_enum,
+ DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT,
+ adcl_text);
static const struct snd_kcontrol_new adc2l_mux =
SOC_DAPM_ENUM("ADC Route", adc2l_enum);
/* ADC2RMUX */
-static const struct soc_enum adc2r_enum =
- SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT,
- DA732X_ADCR_MUX_MAX, adcr_text);
+static SOC_ENUM_SINGLE_DECL(adc2r_enum,
+ DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT,
+ adcr_text);
static const struct snd_kcontrol_new adc2r_mux =
SOC_DAPM_ENUM("ADC Route", adc2r_enum);
-static const struct soc_enum da732x_hp_left_output =
- SOC_ENUM_SINGLE(DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT,
- DA732X_DAC_EN_MAX, enable_text);
+static SOC_ENUM_SINGLE_DECL(da732x_hp_left_output,
+ DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT,
+ enable_text);
static const struct snd_kcontrol_new hpl_mux =
SOC_DAPM_ENUM("HPL Switch", da732x_hp_left_output);
-static const struct soc_enum da732x_hp_right_output =
- SOC_ENUM_SINGLE(DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT,
- DA732X_DAC_EN_MAX, enable_text);
+static SOC_ENUM_SINGLE_DECL(da732x_hp_right_output,
+ DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT,
+ enable_text);
static const struct snd_kcontrol_new hpr_mux =
SOC_DAPM_ENUM("HPR Switch", da732x_hp_right_output);
-static const struct soc_enum da732x_speaker_output =
- SOC_ENUM_SINGLE(DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT,
- DA732X_DAC_EN_MAX, enable_text);
+static SOC_ENUM_SINGLE_DECL(da732x_speaker_output,
+ DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT,
+ enable_text);
static const struct snd_kcontrol_new spk_mux =
SOC_DAPM_ENUM("SPK Switch", da732x_speaker_output);
-static const struct soc_enum da732x_lout4_output =
- SOC_ENUM_SINGLE(DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT,
- DA732X_DAC_EN_MAX, enable_text);
+static SOC_ENUM_SINGLE_DECL(da732x_lout4_output,
+ DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT,
+ enable_text);
static const struct snd_kcontrol_new lout4_mux =
SOC_DAPM_ENUM("LOUT4 Switch", da732x_lout4_output);
-static const struct soc_enum da732x_lout2_output =
- SOC_ENUM_SINGLE(DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT,
- DA732X_DAC_EN_MAX, enable_text);
+static SOC_ENUM_SINGLE_DECL(da732x_lout2_output,
+ DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT,
+ enable_text);
static const struct snd_kcontrol_new lout2_mux =
SOC_DAPM_ENUM("LOUT2 Switch", da732x_lout2_output);
@@ -1268,11 +1252,23 @@ static struct snd_soc_dai_driver da732x_dai[] = {
},
};
+static bool da732x_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case DA732X_REG_HPL_DAC_OFF_CNTL:
+ case DA732X_REG_HPR_DAC_OFF_CNTL:
+ return true;
+ default:
+ return false;
+ }
+}
+
static const struct regmap_config da732x_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = DA732X_MAX_REG,
+ .volatile_reg = da732x_volatile,
.reg_defaults = da732x_reg_cache,
.num_reg_defaults = ARRAY_SIZE(da732x_reg_cache),
.cache_type = REGCACHE_RBTREE,
@@ -1301,9 +1297,9 @@ static void da732x_dac_offset_adjust(struct snd_soc_codec *codec)
msleep(DA732X_WAIT_FOR_STABILIZATION);
/* Check DAC offset sign */
- sign[DA732X_HPL_DAC] = (codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
+ sign[DA732X_HPL_DAC] = (snd_soc_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
DA732X_HP_DAC_OFF_CNTL_COMPO);
- sign[DA732X_HPR_DAC] = (codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
+ sign[DA732X_HPR_DAC] = (snd_soc_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
DA732X_HP_DAC_OFF_CNTL_COMPO);
/* Binary search DAC offset values (both channels at once) */
@@ -1320,10 +1316,10 @@ static void da732x_dac_offset_adjust(struct snd_soc_codec *codec)
msleep(DA732X_WAIT_FOR_STABILIZATION);
- if ((codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
+ if ((snd_soc_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) &
DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPL_DAC])
offset[DA732X_HPL_DAC] &= ~step;
- if ((codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
+ if ((snd_soc_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) &
DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPR_DAC])
offset[DA732X_HPR_DAC] &= ~step;
@@ -1364,9 +1360,9 @@ static void da732x_output_offset_adjust(struct snd_soc_codec *codec)
msleep(DA732X_WAIT_FOR_STABILIZATION);
/* Check output offset sign */
- sign[DA732X_HPL_AMP] = codec->hw_read(codec, DA732X_REG_HPL) &
+ sign[DA732X_HPL_AMP] = snd_soc_read(codec, DA732X_REG_HPL) &
DA732X_HP_OUT_COMPO;
- sign[DA732X_HPR_AMP] = codec->hw_read(codec, DA732X_REG_HPR) &
+ sign[DA732X_HPR_AMP] = snd_soc_read(codec, DA732X_REG_HPR) &
DA732X_HP_OUT_COMPO;
snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_OUT_COMP |
@@ -1387,10 +1383,10 @@ static void da732x_output_offset_adjust(struct snd_soc_codec *codec)
msleep(DA732X_WAIT_FOR_STABILIZATION);
- if ((codec->hw_read(codec, DA732X_REG_HPL) &
+ if ((snd_soc_read(codec, DA732X_REG_HPL) &
DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPL_AMP])
offset[DA732X_HPL_AMP] &= ~step;
- if ((codec->hw_read(codec, DA732X_REG_HPR) &
+ if ((snd_soc_read(codec, DA732X_REG_HPR) &
DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPR_AMP])
offset[DA732X_HPR_AMP] &= ~step;
@@ -1487,8 +1483,8 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
da732x_hp_dc_offset_cancellation(codec);
- regcache_cache_only(codec->control_data, false);
- regcache_sync(codec->control_data);
+ regcache_cache_only(da732x->regmap, false);
+ regcache_sync(da732x->regmap);
} else {
snd_soc_update_bits(codec, DA732X_REG_BIAS_EN,
DA732X_BIAS_BOOST_MASK,
@@ -1499,7 +1495,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
}
break;
case SND_SOC_BIAS_OFF:
- regcache_cache_only(codec->control_data, true);
+ regcache_cache_only(da732x->regmap, true);
da732x_set_charge_pump(codec, DA732X_DISABLE_CP);
snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_EN,
DA732X_BIAS_DIS);
@@ -1516,23 +1512,14 @@ static int da732x_probe(struct snd_soc_codec *codec)
{
struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret = 0;
da732x->codec = codec;
dapm->idle_bias_off = false;
- codec->control_data = da732x->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to register codec.\n");
- goto err;
- }
-
da732x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-err:
- return ret;
+
+ return 0;
}
static int da732x_remove(struct snd_soc_codec *codec)
@@ -1554,7 +1541,6 @@ static struct snd_soc_codec_driver soc_codec_dev_da732x = {
.dapm_routes = da732x_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(da732x_dapm_routes),
.set_pll = da732x_set_dai_pll,
- .reg_cache_size = ARRAY_SIZE(da732x_reg_cache),
};
static int da732x_i2c_probe(struct i2c_client *i2c,
diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h
index c8ce5475de22..1dceafeec415 100644
--- a/sound/soc/codecs/da732x.h
+++ b/sound/soc/codecs/da732x.h
@@ -113,9 +113,6 @@
#define DA732X_EQ_OVERALL_VOL_DB_MIN -1800
#define DA732X_EQ_OVERALL_VOL_DB_INC 600
-#define DA732X_SOC_ENUM_DOUBLE_R(xreg, xrreg, xmax, xtext) \
- {.reg = xreg, .reg2 = xrreg, .max = xmax, .texts = xtext}
-
enum da732x_sysctl {
DA732X_SR_8KHZ = 0x1,
DA732X_SR_11_025KHZ = 0x2,
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index 52b79a487ac7..4ff06b50fbba 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -18,6 +18,8 @@
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -321,22 +323,22 @@ static const char * const da9055_hpf_cutoff_txt[] = {
"Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000"
};
-static const struct soc_enum da9055_dac_hpf_cutoff =
- SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_hpf_cutoff,
+ DA9055_DAC_FILTERS1, 4, da9055_hpf_cutoff_txt);
-static const struct soc_enum da9055_adc_hpf_cutoff =
- SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_adc_hpf_cutoff,
+ DA9055_ADC_FILTERS1, 4, da9055_hpf_cutoff_txt);
/* ADC and DAC voice mode (8kHz) high pass cutoff value */
static const char * const da9055_vf_cutoff_txt[] = {
"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
};
-static const struct soc_enum da9055_dac_vf_cutoff =
- SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 0, 8, da9055_vf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_vf_cutoff,
+ DA9055_DAC_FILTERS1, 0, da9055_vf_cutoff_txt);
-static const struct soc_enum da9055_adc_vf_cutoff =
- SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 0, 8, da9055_vf_cutoff_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_adc_vf_cutoff,
+ DA9055_ADC_FILTERS1, 0, da9055_vf_cutoff_txt);
/* Gain ramping rate value */
static const char * const da9055_gain_ramping_txt[] = {
@@ -344,44 +346,44 @@ static const char * const da9055_gain_ramping_txt[] = {
"nominal rate / 8"
};
-static const struct soc_enum da9055_gain_ramping_rate =
- SOC_ENUM_SINGLE(DA9055_GAIN_RAMP_CTRL, 0, 4, da9055_gain_ramping_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_gain_ramping_rate,
+ DA9055_GAIN_RAMP_CTRL, 0, da9055_gain_ramping_txt);
/* DAC noise gate setup time value */
static const char * const da9055_dac_ng_setup_time_txt[] = {
"256 samples", "512 samples", "1024 samples", "2048 samples"
};
-static const struct soc_enum da9055_dac_ng_setup_time =
- SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 0, 4,
- da9055_dac_ng_setup_time_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_setup_time,
+ DA9055_DAC_NG_SETUP_TIME, 0,
+ da9055_dac_ng_setup_time_txt);
/* DAC noise gate rampup rate value */
static const char * const da9055_dac_ng_rampup_txt[] = {
"0.02 ms/dB", "0.16 ms/dB"
};
-static const struct soc_enum da9055_dac_ng_rampup_rate =
- SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 2, 2,
- da9055_dac_ng_rampup_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampup_rate,
+ DA9055_DAC_NG_SETUP_TIME, 2,
+ da9055_dac_ng_rampup_txt);
/* DAC noise gate rampdown rate value */
static const char * const da9055_dac_ng_rampdown_txt[] = {
"0.64 ms/dB", "20.48 ms/dB"
};
-static const struct soc_enum da9055_dac_ng_rampdown_rate =
- SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 3, 2,
- da9055_dac_ng_rampdown_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampdown_rate,
+ DA9055_DAC_NG_SETUP_TIME, 3,
+ da9055_dac_ng_rampdown_txt);
/* DAC soft mute rate value */
static const char * const da9055_dac_soft_mute_rate_txt[] = {
"1", "2", "4", "8", "16", "32", "64"
};
-static const struct soc_enum da9055_dac_soft_mute_rate =
- SOC_ENUM_SINGLE(DA9055_DAC_FILTERS5, 4, 7,
- da9055_dac_soft_mute_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_soft_mute_rate,
+ DA9055_DAC_FILTERS5, 4,
+ da9055_dac_soft_mute_rate_txt);
/* DAC routing select */
static const char * const da9055_dac_src_txt[] = {
@@ -389,40 +391,40 @@ static const char * const da9055_dac_src_txt[] = {
"AIF input right"
};
-static const struct soc_enum da9055_dac_l_src =
- SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 0, 4, da9055_dac_src_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_l_src,
+ DA9055_DIG_ROUTING_DAC, 0, da9055_dac_src_txt);
-static const struct soc_enum da9055_dac_r_src =
- SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 4, 4, da9055_dac_src_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_dac_r_src,
+ DA9055_DIG_ROUTING_DAC, 4, da9055_dac_src_txt);
/* MIC PGA Left source select */
static const char * const da9055_mic_l_src_txt[] = {
"MIC1_P_N", "MIC1_P", "MIC1_N", "MIC2_L"
};
-static const struct soc_enum da9055_mic_l_src =
- SOC_ENUM_SINGLE(DA9055_MIXIN_L_SELECT, 4, 4, da9055_mic_l_src_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_mic_l_src,
+ DA9055_MIXIN_L_SELECT, 4, da9055_mic_l_src_txt);
/* MIC PGA Right source select */
static const char * const da9055_mic_r_src_txt[] = {
"MIC2_R_L", "MIC2_R", "MIC2_L"
};
-static const struct soc_enum da9055_mic_r_src =
- SOC_ENUM_SINGLE(DA9055_MIXIN_R_SELECT, 4, 3, da9055_mic_r_src_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_mic_r_src,
+ DA9055_MIXIN_R_SELECT, 4, da9055_mic_r_src_txt);
/* ALC Input Signal Tracking rate select */
static const char * const da9055_signal_tracking_rate_txt[] = {
"1/4", "1/16", "1/256", "1/65536"
};
-static const struct soc_enum da9055_integ_attack_rate =
- SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 4, 4,
- da9055_signal_tracking_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_integ_attack_rate,
+ DA9055_ALC_CTRL3, 4,
+ da9055_signal_tracking_rate_txt);
-static const struct soc_enum da9055_integ_release_rate =
- SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 6, 4,
- da9055_signal_tracking_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_integ_release_rate,
+ DA9055_ALC_CTRL3, 6,
+ da9055_signal_tracking_rate_txt);
/* ALC Attack Rate select */
static const char * const da9055_attack_rate_txt[] = {
@@ -430,8 +432,8 @@ static const char * const da9055_attack_rate_txt[] = {
"5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
};
-static const struct soc_enum da9055_attack_rate =
- SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 0, 13, da9055_attack_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_attack_rate,
+ DA9055_ALC_CTRL2, 0, da9055_attack_rate_txt);
/* ALC Release Rate select */
static const char * const da9055_release_rate_txt[] = {
@@ -439,8 +441,8 @@ static const char * const da9055_release_rate_txt[] = {
"11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
};
-static const struct soc_enum da9055_release_rate =
- SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 4, 11, da9055_release_rate_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_release_rate,
+ DA9055_ALC_CTRL2, 4, da9055_release_rate_txt);
/* ALC Hold Time select */
static const char * const da9055_hold_time_txt[] = {
@@ -449,8 +451,8 @@ static const char * const da9055_hold_time_txt[] = {
"253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
};
-static const struct soc_enum da9055_hold_time =
- SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 0, 16, da9055_hold_time_txt);
+static SOC_ENUM_SINGLE_DECL(da9055_hold_time,
+ DA9055_ALC_CTRL3, 0, da9055_hold_time_txt);
static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)
{
@@ -1381,16 +1383,8 @@ static int da9055_set_bias_level(struct snd_soc_codec *codec,
static int da9055_probe(struct snd_soc_codec *codec)
{
- int ret;
struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
- codec->control_data = da9055->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* Enable all Gain Ramps */
snd_soc_update_bits(codec, DA9055_AUX_L_CTRL,
DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
@@ -1523,17 +1517,30 @@ static int da9055_remove(struct i2c_client *client)
return 0;
}
+/*
+ * DO NOT change the device Ids. The naming is intentionally specific as both
+ * the CODEC and PMIC parts of this chip are instantiated separately as I2C
+ * devices (both have configurable I2C addresses, and are to all intents and
+ * purposes separate). As a result there are specific DA9055 Ids for CODEC
+ * and PMIC, which must be different to operate together.
+ */
static const struct i2c_device_id da9055_i2c_id[] = {
- { "da9055", 0 },
+ { "da9055-codec", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
+static const struct of_device_id da9055_of_match[] = {
+ { .compatible = "dlg,da9055-codec", },
+ { }
+};
+
/* I2C codec control layer */
static struct i2c_driver da9055_i2c_driver = {
.driver = {
- .name = "da9055",
+ .name = "da9055-codec",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(da9055_of_match),
},
.probe = da9055_i2c_probe,
.remove = da9055_remove,
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index 5839048ec467..3a89ce66d51d 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -140,13 +140,17 @@ static const char *isabelle_rx1_texts[] = {"VRX1", "ARX1"};
static const char *isabelle_rx2_texts[] = {"VRX2", "ARX2"};
static const struct soc_enum isabelle_rx1_enum[] = {
- SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, 1, isabelle_rx1_texts),
- SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, 1, isabelle_rx1_texts),
+ SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3,
+ ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts),
+ SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5,
+ ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts),
};
static const struct soc_enum isabelle_rx2_enum[] = {
- SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, 1, isabelle_rx2_texts),
- SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, 1, isabelle_rx2_texts),
+ SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2,
+ ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts),
+ SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4,
+ ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts),
};
/* Headset DAC playback switches */
@@ -161,13 +165,17 @@ static const char *isabelle_atx_texts[] = {"AMIC1", "DMIC"};
static const char *isabelle_vtx_texts[] = {"AMIC2", "DMIC"};
static const struct soc_enum isabelle_atx_enum[] = {
- SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, 1, isabelle_atx_texts),
- SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_atx_texts),
+ SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7,
+ ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts),
+ SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0,
+ ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts),
};
static const struct soc_enum isabelle_vtx_enum[] = {
- SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, 1, isabelle_vtx_texts),
- SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_vtx_texts),
+ SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6,
+ ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts),
+ SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0,
+ ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts),
};
static const struct snd_kcontrol_new atx_mux_controls =
@@ -183,17 +191,13 @@ static const char *isabelle_amic1_texts[] = {
/* Left analog microphone selection */
static const char *isabelle_amic2_texts[] = {"Sub Mic", "Aux/FM Right"};
-static const struct soc_enum isabelle_amic1_enum[] = {
- SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 5,
- ARRAY_SIZE(isabelle_amic1_texts),
- isabelle_amic1_texts),
-};
+static SOC_ENUM_SINGLE_DECL(isabelle_amic1_enum,
+ ISABELLE_AMIC_CFG_REG, 5,
+ isabelle_amic1_texts);
-static const struct soc_enum isabelle_amic2_enum[] = {
- SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 4,
- ARRAY_SIZE(isabelle_amic2_texts),
- isabelle_amic2_texts),
-};
+static SOC_ENUM_SINGLE_DECL(isabelle_amic2_enum,
+ ISABELLE_AMIC_CFG_REG, 4,
+ isabelle_amic2_texts);
static const struct snd_kcontrol_new amic1_control =
SOC_DAPM_ENUM("Route", isabelle_amic1_enum);
@@ -206,16 +210,20 @@ static const char *isabelle_st_audio_texts[] = {"ATX1", "ATX2"};
static const char *isabelle_st_voice_texts[] = {"VTX1", "VTX2"};
static const struct soc_enum isabelle_st_audio_enum[] = {
- SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, 1,
+ SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7,
+ ARRAY_SIZE(isabelle_st_audio_texts),
isabelle_st_audio_texts),
- SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, 1,
+ SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7,
+ ARRAY_SIZE(isabelle_st_audio_texts),
isabelle_st_audio_texts),
};
static const struct soc_enum isabelle_st_voice_enum[] = {
- SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, 1,
+ SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7,
+ ARRAY_SIZE(isabelle_st_voice_texts),
isabelle_st_voice_texts),
- SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, 1,
+ SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7,
+ ARRAY_SIZE(isabelle_st_voice_texts),
isabelle_st_voice_texts),
};
@@ -910,8 +918,7 @@ static int isabelle_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
u16 aif = 0;
unsigned int fs_val = 0;
@@ -1082,23 +1089,7 @@ static struct snd_soc_dai_driver isabelle_dai[] = {
},
};
-static int isabelle_probe(struct snd_soc_codec *codec)
-{
- int ret = 0;
-
- codec->control_data = dev_get_regmap(codec->dev, NULL);
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_isabelle = {
- .probe = isabelle_probe,
.set_bias_level = isabelle_set_bias_level,
.controls = isabelle_snd_controls,
.num_controls = ARRAY_SIZE(isabelle_snd_controls),
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
index 0e5743ea79df..4f048db9f55f 100644
--- a/sound/soc/codecs/lm4857.c
+++ b/sound/soc/codecs/lm4857.c
@@ -101,8 +101,7 @@ static const char *lm4857_mode[] = {
"Headphone",
};
-static const struct soc_enum lm4857_mode_enum =
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode);
+static SOC_ENUM_SINGLE_EXT_DECL(lm4857_mode_enum, lm4857_mode);
static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("IN"),
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index e19490cfb3a8..275b3f72f3f4 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -195,33 +195,31 @@ struct lm49453_priv {
static const char *lm49453_mic2mode_text[] = {"Single Ended", "Differential"};
-static const SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5,
- lm49453_mic2mode_text);
+static SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5,
+ lm49453_mic2mode_text);
static const char *lm49453_dmic_cfg_text[] = {"DMICDAT1", "DMICDAT2"};
-static const SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum,
- LM49453_P0_DIGITAL_MIC1_CONFIG_REG,
- 7, lm49453_dmic_cfg_text);
+static SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum,
+ LM49453_P0_DIGITAL_MIC1_CONFIG_REG, 7,
+ lm49453_dmic_cfg_text);
-static const SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum,
- LM49453_P0_DIGITAL_MIC2_CONFIG_REG,
- 7, lm49453_dmic_cfg_text);
+static SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum,
+ LM49453_P0_DIGITAL_MIC2_CONFIG_REG, 7,
+ lm49453_dmic_cfg_text);
/* MUX Controls */
static const char *lm49453_adcl_mux_text[] = { "MIC1", "Aux_L" };
static const char *lm49453_adcr_mux_text[] = { "MIC2", "Aux_R" };
-static const struct soc_enum lm49453_adcl_enum =
- SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 0,
- ARRAY_SIZE(lm49453_adcl_mux_text),
- lm49453_adcl_mux_text);
+static SOC_ENUM_SINGLE_DECL(lm49453_adcl_enum,
+ LM49453_P0_ANALOG_MIXER_ADC_REG, 0,
+ lm49453_adcl_mux_text);
-static const struct soc_enum lm49453_adcr_enum =
- SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 1,
- ARRAY_SIZE(lm49453_adcr_mux_text),
- lm49453_adcr_mux_text);
+static SOC_ENUM_SINGLE_DECL(lm49453_adcr_enum,
+ LM49453_P0_ANALOG_MIXER_ADC_REG, 1,
+ lm49453_adcr_mux_text);
static const struct snd_kcontrol_new lm49453_adcl_mux_control =
SOC_DAPM_ENUM("ADC Left Mux", lm49453_adcl_enum);
@@ -1409,22 +1407,6 @@ static int lm49453_resume(struct snd_soc_codec *codec)
return 0;
}
-static int lm49453_probe(struct snd_soc_codec *codec)
-{
- struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
- int ret = 0;
-
- codec->control_data = lm49453->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
/* power down chip */
static int lm49453_remove(struct snd_soc_codec *codec)
{
@@ -1433,7 +1415,6 @@ static int lm49453_remove(struct snd_soc_codec *codec)
}
static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
- .probe = lm49453_probe,
.remove = lm49453_remove,
.suspend = lm49453_suspend,
.resume = lm49453_resume,
diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c
index 31f91560e9f6..ec481fc428c7 100644
--- a/sound/soc/codecs/max9768.c
+++ b/sound/soc/codecs/max9768.c
@@ -135,11 +135,6 @@ static int max9768_probe(struct snd_soc_codec *codec)
struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
int ret;
- codec->control_data = max9768->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 2, 6, SND_SOC_REGMAP);
- if (ret)
- return ret;
-
if (max9768->flags & MAX9768_FLAG_CLASSIC_PWM) {
ret = snd_soc_write(codec, MAX9768_CTRL, MAX9768_CTRL_PWM);
if (ret)
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index ee660e2d3df3..ef7cf89f5623 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -597,28 +597,27 @@ static const unsigned int max98088_exmode_values[] = {
0x00, 0x43, 0x10, 0x20, 0x30, 0x40, 0x11, 0x22, 0x32
};
-static const struct soc_enum max98088_exmode_enum =
- SOC_VALUE_ENUM_SINGLE(M98088_REG_41_SPKDHP, 0, 127,
- ARRAY_SIZE(max98088_exmode_texts),
- max98088_exmode_texts,
- max98088_exmode_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(max98088_exmode_enum,
+ M98088_REG_41_SPKDHP, 0, 127,
+ max98088_exmode_texts,
+ max98088_exmode_values);
static const char *max98088_ex_thresh[] = { /* volts PP */
"0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"};
-static const struct soc_enum max98088_ex_thresh_enum[] = {
- SOC_ENUM_SINGLE(M98088_REG_42_SPKDHP_THRESH, 0, 8,
- max98088_ex_thresh),
-};
+static SOC_ENUM_SINGLE_DECL(max98088_ex_thresh_enum,
+ M98088_REG_42_SPKDHP_THRESH, 0,
+ max98088_ex_thresh);
static const char *max98088_fltr_mode[] = {"Voice", "Music" };
-static const struct soc_enum max98088_filter_mode_enum[] = {
- SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 7, 2, max98088_fltr_mode),
-};
+static SOC_ENUM_SINGLE_DECL(max98088_filter_mode_enum,
+ M98088_REG_18_DAI1_FILTERS, 7,
+ max98088_fltr_mode);
static const char *max98088_extmic_text[] = { "None", "MIC1", "MIC2" };
-static const struct soc_enum max98088_extmic_enum =
- SOC_ENUM_SINGLE(M98088_REG_48_CFG_MIC, 0, 3, max98088_extmic_text);
+static SOC_ENUM_SINGLE_DECL(max98088_extmic_enum,
+ M98088_REG_48_CFG_MIC, 0,
+ max98088_extmic_text);
static const struct snd_kcontrol_new max98088_extmic_mux =
SOC_DAPM_ENUM("External MIC Mux", max98088_extmic_enum);
@@ -626,12 +625,12 @@ static const struct snd_kcontrol_new max98088_extmic_mux =
static const char *max98088_dai1_fltr[] = {
"Off", "fc=258/fs=16k", "fc=500/fs=16k",
"fc=258/fs=8k", "fc=500/fs=8k", "fc=200"};
-static const struct soc_enum max98088_dai1_dac_filter_enum[] = {
- SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 0, 6, max98088_dai1_fltr),
-};
-static const struct soc_enum max98088_dai1_adc_filter_enum[] = {
- SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 4, 6, max98088_dai1_fltr),
-};
+static SOC_ENUM_SINGLE_DECL(max98088_dai1_dac_filter_enum,
+ M98088_REG_18_DAI1_FILTERS, 0,
+ max98088_dai1_fltr);
+static SOC_ENUM_SINGLE_DECL(max98088_dai1_adc_filter_enum,
+ M98088_REG_18_DAI1_FILTERS, 4,
+ max98088_dai1_fltr);
static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -1849,7 +1848,7 @@ static void max98088_handle_eq_pdata(struct snd_soc_codec *codec)
/* Now point the soc_enum to .texts array items */
max98088->eq_enum.texts = max98088->eq_texts;
- max98088->eq_enum.max = max98088->eq_textcnt;
+ max98088->eq_enum.items = max98088->eq_textcnt;
ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
if (ret != 0)
@@ -1915,12 +1914,6 @@ static int max98088_probe(struct snd_soc_codec *codec)
regcache_mark_dirty(max98088->regmap);
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* initialize private data */
max98088->sysclk = (unsigned)-1;
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 51f9b3d16b41..98c6e104357c 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -336,6 +336,7 @@ static bool max98090_readable_register(struct device *dev, unsigned int reg)
case M98090_REG_RECORD_TDM_SLOT:
case M98090_REG_SAMPLE_RATE:
case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E:
+ case M98090_REG_REVISION_ID:
return true;
default:
return false;
@@ -512,65 +513,75 @@ static const char *max98090_perf_pwr_text[] =
static const char *max98090_pwr_perf_text[] =
{ "Low Power", "High Performance" };
-static const struct soc_enum max98090_vcmbandgap_enum =
- SOC_ENUM_SINGLE(M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_SHIFT,
- ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text);
+static SOC_ENUM_SINGLE_DECL(max98090_vcmbandgap_enum,
+ M98090_REG_BIAS_CONTROL,
+ M98090_VCM_MODE_SHIFT,
+ max98090_pwr_perf_text);
static const char *max98090_osr128_text[] = { "64*fs", "128*fs" };
-static const struct soc_enum max98090_osr128_enum =
- SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_OSR128_SHIFT,
- ARRAY_SIZE(max98090_osr128_text), max98090_osr128_text);
+static SOC_ENUM_SINGLE_DECL(max98090_osr128_enum,
+ M98090_REG_ADC_CONTROL,
+ M98090_OSR128_SHIFT,
+ max98090_osr128_text);
static const char *max98090_mode_text[] = { "Voice", "Music" };
-static const struct soc_enum max98090_mode_enum =
- SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG, M98090_MODE_SHIFT,
- ARRAY_SIZE(max98090_mode_text), max98090_mode_text);
+static SOC_ENUM_SINGLE_DECL(max98090_mode_enum,
+ M98090_REG_FILTER_CONFIG,
+ M98090_MODE_SHIFT,
+ max98090_mode_text);
-static const struct soc_enum max98090_filter_dmic34mode_enum =
- SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG,
- M98090_FLT_DMIC34MODE_SHIFT,
- ARRAY_SIZE(max98090_mode_text), max98090_mode_text);
+static SOC_ENUM_SINGLE_DECL(max98090_filter_dmic34mode_enum,
+ M98090_REG_FILTER_CONFIG,
+ M98090_FLT_DMIC34MODE_SHIFT,
+ max98090_mode_text);
static const char *max98090_drcatk_text[] =
{ "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" };
-static const struct soc_enum max98090_drcatk_enum =
- SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCATK_SHIFT,
- ARRAY_SIZE(max98090_drcatk_text), max98090_drcatk_text);
+static SOC_ENUM_SINGLE_DECL(max98090_drcatk_enum,
+ M98090_REG_DRC_TIMING,
+ M98090_DRCATK_SHIFT,
+ max98090_drcatk_text);
static const char *max98090_drcrls_text[] =
{ "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" };
-static const struct soc_enum max98090_drcrls_enum =
- SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCRLS_SHIFT,
- ARRAY_SIZE(max98090_drcrls_text), max98090_drcrls_text);
+static SOC_ENUM_SINGLE_DECL(max98090_drcrls_enum,
+ M98090_REG_DRC_TIMING,
+ M98090_DRCRLS_SHIFT,
+ max98090_drcrls_text);
static const char *max98090_alccmp_text[] =
{ "1:1", "1:1.5", "1:2", "1:4", "1:INF" };
-static const struct soc_enum max98090_alccmp_enum =
- SOC_ENUM_SINGLE(M98090_REG_DRC_COMPRESSOR, M98090_DRCCMP_SHIFT,
- ARRAY_SIZE(max98090_alccmp_text), max98090_alccmp_text);
+static SOC_ENUM_SINGLE_DECL(max98090_alccmp_enum,
+ M98090_REG_DRC_COMPRESSOR,
+ M98090_DRCCMP_SHIFT,
+ max98090_alccmp_text);
static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" };
-static const struct soc_enum max98090_drcexp_enum =
- SOC_ENUM_SINGLE(M98090_REG_DRC_EXPANDER, M98090_DRCEXP_SHIFT,
- ARRAY_SIZE(max98090_drcexp_text), max98090_drcexp_text);
+static SOC_ENUM_SINGLE_DECL(max98090_drcexp_enum,
+ M98090_REG_DRC_EXPANDER,
+ M98090_DRCEXP_SHIFT,
+ max98090_drcexp_text);
-static const struct soc_enum max98090_dac_perfmode_enum =
- SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_PERFMODE_SHIFT,
- ARRAY_SIZE(max98090_perf_pwr_text), max98090_perf_pwr_text);
+static SOC_ENUM_SINGLE_DECL(max98090_dac_perfmode_enum,
+ M98090_REG_DAC_CONTROL,
+ M98090_PERFMODE_SHIFT,
+ max98090_perf_pwr_text);
-static const struct soc_enum max98090_dachp_enum =
- SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_DACHP_SHIFT,
- ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text);
+static SOC_ENUM_SINGLE_DECL(max98090_dachp_enum,
+ M98090_REG_DAC_CONTROL,
+ M98090_DACHP_SHIFT,
+ max98090_pwr_perf_text);
-static const struct soc_enum max98090_adchp_enum =
- SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_ADCHP_SHIFT,
- ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text);
+static SOC_ENUM_SINGLE_DECL(max98090_adchp_enum,
+ M98090_REG_ADC_CONTROL,
+ M98090_ADCHP_SHIFT,
+ max98090_pwr_perf_text);
static const struct snd_kcontrol_new max98090_snd_controls[] = {
SOC_ENUM("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum),
@@ -841,39 +852,42 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
static const char *mic1_mux_text[] = { "IN12", "IN56" };
-static const struct soc_enum mic1_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC1_SHIFT,
- ARRAY_SIZE(mic1_mux_text), mic1_mux_text);
+static SOC_ENUM_SINGLE_DECL(mic1_mux_enum,
+ M98090_REG_INPUT_MODE,
+ M98090_EXTMIC1_SHIFT,
+ mic1_mux_text);
static const struct snd_kcontrol_new max98090_mic1_mux =
SOC_DAPM_ENUM("MIC1 Mux", mic1_mux_enum);
static const char *mic2_mux_text[] = { "IN34", "IN56" };
-static const struct soc_enum mic2_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC2_SHIFT,
- ARRAY_SIZE(mic2_mux_text), mic2_mux_text);
+static SOC_ENUM_SINGLE_DECL(mic2_mux_enum,
+ M98090_REG_INPUT_MODE,
+ M98090_EXTMIC2_SHIFT,
+ mic2_mux_text);
static const struct snd_kcontrol_new max98090_mic2_mux =
SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum);
static const char *dmic_mux_text[] = { "ADC", "DMIC" };
-static const struct soc_enum dmic_mux_enum =
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dmic_mux_text), dmic_mux_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text);
static const struct snd_kcontrol_new max98090_dmic_mux =
SOC_DAPM_ENUM_VIRT("DMIC Mux", dmic_mux_enum);
static const char *max98090_micpre_text[] = { "Off", "On" };
-static const struct soc_enum max98090_pa1en_enum =
- SOC_ENUM_SINGLE(M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT,
- ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text);
+static SOC_ENUM_SINGLE_DECL(max98090_pa1en_enum,
+ M98090_REG_MIC1_INPUT_LEVEL,
+ M98090_MIC_PA1EN_SHIFT,
+ max98090_micpre_text);
-static const struct soc_enum max98090_pa2en_enum =
- SOC_ENUM_SINGLE(M98090_REG_MIC2_INPUT_LEVEL, M98090_MIC_PA2EN_SHIFT,
- ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text);
+static SOC_ENUM_SINGLE_DECL(max98090_pa2en_enum,
+ M98090_REG_MIC2_INPUT_LEVEL,
+ M98090_MIC_PA2EN_SHIFT,
+ max98090_micpre_text);
/* LINEA mixer switch */
static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = {
@@ -937,13 +951,15 @@ static const struct snd_kcontrol_new max98090_right_adc_mixer_controls[] = {
static const char *lten_mux_text[] = { "Normal", "Loopthrough" };
-static const struct soc_enum ltenl_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT,
- ARRAY_SIZE(lten_mux_text), lten_mux_text);
+static SOC_ENUM_SINGLE_DECL(ltenl_mux_enum,
+ M98090_REG_IO_CONFIGURATION,
+ M98090_LTEN_SHIFT,
+ lten_mux_text);
-static const struct soc_enum ltenr_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT,
- ARRAY_SIZE(lten_mux_text), lten_mux_text);
+static SOC_ENUM_SINGLE_DECL(ltenr_mux_enum,
+ M98090_REG_IO_CONFIGURATION,
+ M98090_LTEN_SHIFT,
+ lten_mux_text);
static const struct snd_kcontrol_new max98090_ltenl_mux =
SOC_DAPM_ENUM("LTENL Mux", ltenl_mux_enum);
@@ -953,13 +969,15 @@ static const struct snd_kcontrol_new max98090_ltenr_mux =
static const char *lben_mux_text[] = { "Normal", "Loopback" };
-static const struct soc_enum lbenl_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT,
- ARRAY_SIZE(lben_mux_text), lben_mux_text);
+static SOC_ENUM_SINGLE_DECL(lbenl_mux_enum,
+ M98090_REG_IO_CONFIGURATION,
+ M98090_LBEN_SHIFT,
+ lben_mux_text);
-static const struct soc_enum lbenr_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT,
- ARRAY_SIZE(lben_mux_text), lben_mux_text);
+static SOC_ENUM_SINGLE_DECL(lbenr_mux_enum,
+ M98090_REG_IO_CONFIGURATION,
+ M98090_LBEN_SHIFT,
+ lben_mux_text);
static const struct snd_kcontrol_new max98090_lbenl_mux =
SOC_DAPM_ENUM("LBENL Mux", lbenl_mux_enum);
@@ -971,13 +989,15 @@ static const char *stenl_mux_text[] = { "Normal", "Sidetone Left" };
static const char *stenr_mux_text[] = { "Normal", "Sidetone Right" };
-static const struct soc_enum stenl_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSL_SHIFT,
- ARRAY_SIZE(stenl_mux_text), stenl_mux_text);
+static SOC_ENUM_SINGLE_DECL(stenl_mux_enum,
+ M98090_REG_ADC_SIDETONE,
+ M98090_DSTSL_SHIFT,
+ stenl_mux_text);
-static const struct soc_enum stenr_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSR_SHIFT,
- ARRAY_SIZE(stenr_mux_text), stenr_mux_text);
+static SOC_ENUM_SINGLE_DECL(stenr_mux_enum,
+ M98090_REG_ADC_SIDETONE,
+ M98090_DSTSR_SHIFT,
+ stenr_mux_text);
static const struct snd_kcontrol_new max98090_stenl_mux =
SOC_DAPM_ENUM("STENL Mux", stenl_mux_enum);
@@ -1085,9 +1105,10 @@ static const struct snd_kcontrol_new max98090_right_rcv_mixer_controls[] = {
static const char *linmod_mux_text[] = { "Left Only", "Left and Right" };
-static const struct soc_enum linmod_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_LOUTR_MIXER, M98090_LINMOD_SHIFT,
- ARRAY_SIZE(linmod_mux_text), linmod_mux_text);
+static SOC_ENUM_SINGLE_DECL(linmod_mux_enum,
+ M98090_REG_LOUTR_MIXER,
+ M98090_LINMOD_SHIFT,
+ linmod_mux_text);
static const struct snd_kcontrol_new max98090_linmod_mux =
SOC_DAPM_ENUM("LINMOD Mux", linmod_mux_enum);
@@ -1097,16 +1118,18 @@ static const char *mixhpsel_mux_text[] = { "DAC Only", "HP Mixer" };
/*
* This is a mux as it selects the HP output, but to DAPM it is a Mixer enable
*/
-static const struct soc_enum mixhplsel_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPLSEL_SHIFT,
- ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text);
+static SOC_ENUM_SINGLE_DECL(mixhplsel_mux_enum,
+ M98090_REG_HP_CONTROL,
+ M98090_MIXHPLSEL_SHIFT,
+ mixhpsel_mux_text);
static const struct snd_kcontrol_new max98090_mixhplsel_mux =
SOC_DAPM_ENUM("MIXHPLSEL Mux", mixhplsel_mux_enum);
-static const struct soc_enum mixhprsel_mux_enum =
- SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPRSEL_SHIFT,
- ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text);
+static SOC_ENUM_SINGLE_DECL(mixhprsel_mux_enum,
+ M98090_REG_HP_CONTROL,
+ M98090_MIXHPRSEL_SHIFT,
+ mixhpsel_mux_text);
static const struct snd_kcontrol_new max98090_mixhprsel_mux =
SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum);
@@ -1769,16 +1792,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
- if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
- ret = regcache_sync(max98090->regmap);
-
- if (ret != 0) {
- dev_err(codec->dev,
- "Failed to sync cache: %d\n", ret);
- return ret;
- }
- }
-
if (max98090->jack_state == M98090_JACK_STATE_HEADSET) {
/*
* Set to normal bias level.
@@ -1792,6 +1805,16 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ ret = regcache_sync(max98090->regmap);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to sync cache: %d\n", ret);
+ return ret;
+ }
+ }
+ break;
+
case SND_SOC_BIAS_OFF:
/* Set internal pull-up to lowest power mode */
snd_soc_update_bits(codec, M98090_REG_JACK_DETECT,
@@ -2195,14 +2218,6 @@ static int max98090_probe(struct snd_soc_codec *codec)
max98090->codec = codec;
- codec->control_data = max98090->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* Reset the codec, the DSP core, and disable all interrupts */
max98090_reset(max98090);
@@ -2328,7 +2343,6 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
max98090->devtype = id->driver_data;
i2c_set_clientdata(i2c, max98090);
- max98090->control_data = i2c;
max98090->pdata = i2c->dev.platform_data;
max98090->irq = i2c->irq;
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h
index 7e103f249053..1a4e2334a7b2 100644
--- a/sound/soc/codecs/max98090.h
+++ b/sound/soc/codecs/max98090.h
@@ -1523,7 +1523,6 @@ struct max98090_priv {
struct regmap *regmap;
struct snd_soc_codec *codec;
enum max98090_type devtype;
- void *control_data;
struct max98090_pdata *pdata;
unsigned int sysclk;
unsigned int bclk;
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 3ba1170ebb53..03f0536e6f61 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -560,25 +560,27 @@ static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai,
}
static const char * const max98095_fltr_mode[] = { "Voice", "Music" };
-static const struct soc_enum max98095_dai1_filter_mode_enum[] = {
- SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 7, 2, max98095_fltr_mode),
-};
-static const struct soc_enum max98095_dai2_filter_mode_enum[] = {
- SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 7, 2, max98095_fltr_mode),
-};
+static SOC_ENUM_SINGLE_DECL(max98095_dai1_filter_mode_enum,
+ M98095_02E_DAI1_FILTERS, 7,
+ max98095_fltr_mode);
+static SOC_ENUM_SINGLE_DECL(max98095_dai2_filter_mode_enum,
+ M98095_038_DAI2_FILTERS, 7,
+ max98095_fltr_mode);
static const char * const max98095_extmic_text[] = { "None", "MIC1", "MIC2" };
-static const struct soc_enum max98095_extmic_enum =
- SOC_ENUM_SINGLE(M98095_087_CFG_MIC, 0, 3, max98095_extmic_text);
+static SOC_ENUM_SINGLE_DECL(max98095_extmic_enum,
+ M98095_087_CFG_MIC, 0,
+ max98095_extmic_text);
static const struct snd_kcontrol_new max98095_extmic_mux =
SOC_DAPM_ENUM("External MIC Mux", max98095_extmic_enum);
static const char * const max98095_linein_text[] = { "INA", "INB" };
-static const struct soc_enum max98095_linein_enum =
- SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 6, 2, max98095_linein_text);
+static SOC_ENUM_SINGLE_DECL(max98095_linein_enum,
+ M98095_086_CFG_LINE, 6,
+ max98095_linein_text);
static const struct snd_kcontrol_new max98095_linein_mux =
SOC_DAPM_ENUM("Linein Input Mux", max98095_linein_enum);
@@ -586,24 +588,26 @@ static const struct snd_kcontrol_new max98095_linein_mux =
static const char * const max98095_line_mode_text[] = {
"Stereo", "Differential"};
-static const struct soc_enum max98095_linein_mode_enum =
- SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 7, 2, max98095_line_mode_text);
+static SOC_ENUM_SINGLE_DECL(max98095_linein_mode_enum,
+ M98095_086_CFG_LINE, 7,
+ max98095_line_mode_text);
-static const struct soc_enum max98095_lineout_mode_enum =
- SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 4, 2, max98095_line_mode_text);
+static SOC_ENUM_SINGLE_DECL(max98095_lineout_mode_enum,
+ M98095_086_CFG_LINE, 4,
+ max98095_line_mode_text);
static const char * const max98095_dai_fltr[] = {
"Off", "Elliptical-HPF-16k", "Butterworth-HPF-16k",
"Elliptical-HPF-8k", "Butterworth-HPF-8k", "Butterworth-HPF-Fs/240"};
-static const struct soc_enum max98095_dai1_dac_filter_enum[] = {
- SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 0, 6, max98095_dai_fltr),
-};
-static const struct soc_enum max98095_dai2_dac_filter_enum[] = {
- SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 0, 6, max98095_dai_fltr),
-};
-static const struct soc_enum max98095_dai3_dac_filter_enum[] = {
- SOC_ENUM_SINGLE(M98095_042_DAI3_FILTERS, 0, 6, max98095_dai_fltr),
-};
+static SOC_ENUM_SINGLE_DECL(max98095_dai1_dac_filter_enum,
+ M98095_02E_DAI1_FILTERS, 0,
+ max98095_dai_fltr);
+static SOC_ENUM_SINGLE_DECL(max98095_dai2_dac_filter_enum,
+ M98095_038_DAI2_FILTERS, 0,
+ max98095_dai_fltr);
+static SOC_ENUM_SINGLE_DECL(max98095_dai3_dac_filter_enum,
+ M98095_042_DAI3_FILTERS, 0,
+ max98095_dai_fltr);
static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -1861,7 +1865,7 @@ static void max98095_handle_eq_pdata(struct snd_soc_codec *codec)
/* Now point the soc_enum to .texts array items */
max98095->eq_enum.texts = max98095->eq_texts;
- max98095->eq_enum.max = max98095->eq_textcnt;
+ max98095->eq_enum.items = max98095->eq_textcnt;
ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
if (ret != 0)
@@ -2016,7 +2020,7 @@ static void max98095_handle_bq_pdata(struct snd_soc_codec *codec)
/* Now point the soc_enum to .texts array items */
max98095->bq_enum.texts = max98095->bq_texts;
- max98095->bq_enum.max = max98095->bq_textcnt;
+ max98095->bq_enum.items = max98095->bq_textcnt;
ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
if (ret != 0)
@@ -2234,12 +2238,6 @@ static int max98095_probe(struct snd_soc_codec *codec)
struct i2c_client *client;
int ret = 0;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* reset the codec, the DSP core, and disable all interrupts */
max98095_reset(codec);
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index 82757ebf0301..4fdf5aaa236f 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -312,14 +312,6 @@ static int max9850_resume(struct snd_soc_codec *codec)
static int max9850_probe(struct snd_soc_codec *codec)
{
- int ret;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* enable zero-detect */
snd_soc_update_bits(codec, MAX9850_GENERAL_PURPOSE, 1, 1);
/* enable slew-rate control */
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index 582c2bbd42cb..2c59b1fb69dc 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -106,8 +106,7 @@ static int mc13783_pcm_hw_params_dac(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
unsigned int rate = params_rate(params);
int i;
@@ -126,8 +125,7 @@ static int mc13783_pcm_hw_params_codec(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
unsigned int rate = params_rate(params);
unsigned int val;
@@ -408,8 +406,7 @@ static const char * const adcl_enum_text[] = {
"MC1L", "RXINL",
};
-static const struct soc_enum adcl_enum =
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcl_enum_text), adcl_enum_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(adcl_enum, adcl_enum_text);
static const struct snd_kcontrol_new left_input_mux =
SOC_DAPM_ENUM_VIRT("Route", adcl_enum);
@@ -418,8 +415,7 @@ static const char * const adcr_enum_text[] = {
"MC1R", "MC2", "RXINR", "TXIN",
};
-static const struct soc_enum adcr_enum =
- SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcr_enum_text), adcr_enum_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(adcr_enum, adcr_enum_text);
static const struct snd_kcontrol_new right_input_mux =
SOC_DAPM_ENUM_VIRT("Route", adcr_enum);
@@ -430,8 +426,8 @@ static const struct snd_kcontrol_new samp_ctl =
static const char * const speaker_amp_source_text[] = {
"CODEC", "Right"
};
-static const SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4,
- speaker_amp_source_text);
+static SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4,
+ speaker_amp_source_text);
static const struct snd_kcontrol_new speaker_amp_source_mux =
SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source);
@@ -439,8 +435,8 @@ static const char * const headset_amp_source_text[] = {
"CODEC", "Mixer"
};
-static const SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11,
- headset_amp_source_text);
+static SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11,
+ headset_amp_source_text);
static const struct snd_kcontrol_new headset_amp_source_mux =
SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source);
@@ -580,9 +576,9 @@ static struct snd_soc_dapm_route mc13783_routes[] = {
static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix",
"Mono", "Mono Mix"};
-static const struct soc_enum mc13783_enum_3d_mixer =
- SOC_ENUM_SINGLE(MC13783_AUDIO_RX1, 16, ARRAY_SIZE(mc13783_3d_mixer),
- mc13783_3d_mixer);
+static SOC_ENUM_SINGLE_DECL(mc13783_enum_3d_mixer,
+ MC13783_AUDIO_RX1, 16,
+ mc13783_3d_mixer);
static struct snd_kcontrol_new mc13783_control_list[] = {
SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0),
@@ -614,8 +610,8 @@ static int mc13783_probe(struct snd_soc_codec *codec)
struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
int ret;
- codec->control_data = dev_get_regmap(codec->dev->parent, NULL);
- ret = snd_soc_codec_set_cache_io(codec, 8, 24, SND_SOC_REGMAP);
+ ret = snd_soc_codec_set_cache_io(codec,
+ dev_get_regmap(codec->dev->parent, NULL));
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index 185fa3bc3052..e661e8420e3d 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -73,11 +73,11 @@ static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0);
static const char * const ml26124_companding[] = {"16bit PCM", "u-law",
"A-law"};
-static const struct soc_enum ml26124_adc_companding_enum
- = SOC_ENUM_SINGLE(ML26124_SAI_TRANS_CTL, 6, 3, ml26124_companding);
+static SOC_ENUM_SINGLE_DECL(ml26124_adc_companding_enum,
+ ML26124_SAI_TRANS_CTL, 6, ml26124_companding);
-static const struct soc_enum ml26124_dac_companding_enum
- = SOC_ENUM_SINGLE(ML26124_SAI_RCV_CTL, 6, 3, ml26124_companding);
+static SOC_ENUM_SINGLE_DECL(ml26124_dac_companding_enum,
+ ML26124_SAI_RCV_CTL, 6, ml26124_companding);
static const struct snd_kcontrol_new ml26124_snd_controls[] = {
SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0,
@@ -136,8 +136,8 @@ static const struct snd_kcontrol_new ml26124_output_mixer_controls[] = {
static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in",
"Digital MIC in", "Analog MIC Differential in"};
-static const struct soc_enum ml26124_insel_enum =
- SOC_ENUM_SINGLE(ML26124_MIC_IF_CTL, 0, 3, ml26124_input_select);
+static SOC_ENUM_SINGLE_DECL(ml26124_insel_enum,
+ ML26124_MIC_IF_CTL, 0, ml26124_input_select);
static const struct snd_kcontrol_new ml26124_input_mux_controls =
SOC_DAPM_ENUM("Input Select", ml26124_insel_enum);
@@ -586,16 +586,6 @@ static int ml26124_resume(struct snd_soc_codec *codec)
static int ml26124_probe(struct snd_soc_codec *codec)
{
- int ret;
- struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
- codec->control_data = priv->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* Software Reset */
snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1);
snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0);
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index 73f9c3630e2c..e427544183d7 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -172,16 +172,21 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
int val = 0, ret;
- int pcm_format = params_format(params);
priv->rate = params_rate(params);
switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_RIGHT_J:
- if (pcm_format == SNDRV_PCM_FORMAT_S24_LE)
- val = 0x00;
- else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE)
- val = 0x03;
+ switch (params_width(params)) {
+ case 24:
+ val = 0;
+ break;
+ case 16:
+ val = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
break;
case SND_SOC_DAIFMT_I2S:
val = 0x04;
diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c
index 7146653a8e16..3a80ba4452df 100644
--- a/sound/soc/codecs/pcm1792a.c
+++ b/sound/soc/codecs/pcm1792a.c
@@ -107,24 +107,35 @@ static int pcm1792a_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
int val = 0, ret;
- int pcm_format = params_format(params);
priv->rate = params_rate(params);
switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_RIGHT_J:
- if (pcm_format == SNDRV_PCM_FORMAT_S24_LE ||
- pcm_format == SNDRV_PCM_FORMAT_S32_LE)
- val = 0x02;
- else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE)
- val = 0x00;
+ switch (params_width(params)) {
+ case 24:
+ case 32:
+ val = 2;
+ break;
+ case 16:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
break;
case SND_SOC_DAIFMT_I2S:
- if (pcm_format == SNDRV_PCM_FORMAT_S24_LE ||
- pcm_format == SNDRV_PCM_FORMAT_S32_LE)
- val = 0x05;
- else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE)
- val = 0x04;
+ switch (params_width(params)) {
+ case 24:
+ case 32:
+ val = 5;
+ break;
+ case 16:
+ val = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
break;
default:
dev_err(codec->dev, "Invalid DAI format\n");
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c
new file mode 100644
index 000000000000..4d62230bd378
--- /dev/null
+++ b/sound/soc/codecs/pcm512x-i2c.c
@@ -0,0 +1,71 @@
+/*
+ * Driver for the PCM512x CODECs
+ *
+ * Author: Mark Brown <broonie@linaro.org>
+ * Copyright 2014 Linaro 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include "pcm512x.h"
+
+static int pcm512x_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(i2c, &pcm512x_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return pcm512x_probe(&i2c->dev, regmap);
+}
+
+static int pcm512x_i2c_remove(struct i2c_client *i2c)
+{
+ pcm512x_remove(&i2c->dev);
+ return 0;
+}
+
+static const struct i2c_device_id pcm512x_i2c_id[] = {
+ { "pcm5121", },
+ { "pcm5122", },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
+
+static const struct of_device_id pcm512x_of_match[] = {
+ { .compatible = "ti,pcm5121", },
+ { .compatible = "ti,pcm5122", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcm512x_of_match);
+
+static struct i2c_driver pcm512x_i2c_driver = {
+ .probe = pcm512x_i2c_probe,
+ .remove = pcm512x_i2c_remove,
+ .id_table = pcm512x_i2c_id,
+ .driver = {
+ .name = "pcm512x",
+ .owner = THIS_MODULE,
+ .of_match_table = pcm512x_of_match,
+ .pm = &pcm512x_pm_ops,
+ },
+};
+
+module_i2c_driver(pcm512x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC PCM512x codec driver - I2C");
+MODULE_AUTHOR("Mark Brown <broonie@linaro.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c
new file mode 100644
index 000000000000..f297058c0038
--- /dev/null
+++ b/sound/soc/codecs/pcm512x-spi.c
@@ -0,0 +1,69 @@
+/*
+ * Driver for the PCM512x CODECs
+ *
+ * Author: Mark Brown <broonie@linaro.org>
+ * Copyright 2014 Linaro 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "pcm512x.h"
+
+static int pcm512x_spi_probe(struct spi_device *spi)
+{
+ struct regmap *regmap;
+ int ret;
+
+ regmap = devm_regmap_init_spi(spi, &pcm512x_regmap);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ return ret;
+ }
+
+ return pcm512x_probe(&spi->dev, regmap);
+}
+
+static int pcm512x_spi_remove(struct spi_device *spi)
+{
+ pcm512x_remove(&spi->dev);
+ return 0;
+}
+
+static const struct spi_device_id pcm512x_spi_id[] = {
+ { "pcm5121", },
+ { "pcm5122", },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, pcm512x_spi_id);
+
+static const struct of_device_id pcm512x_of_match[] = {
+ { .compatible = "ti,pcm5121", },
+ { .compatible = "ti,pcm5122", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcm512x_of_match);
+
+static struct spi_driver pcm512x_spi_driver = {
+ .probe = pcm512x_spi_probe,
+ .remove = pcm512x_spi_remove,
+ .id_table = pcm512x_spi_id,
+ .driver = {
+ .name = "pcm512x",
+ .owner = THIS_MODULE,
+ .of_match_table = pcm512x_of_match,
+ .pm = &pcm512x_pm_ops,
+ },
+};
+
+module_spi_driver(pcm512x_spi_driver);
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
new file mode 100644
index 000000000000..4b4c0c7bb918
--- /dev/null
+++ b/sound/soc/codecs/pcm512x.c
@@ -0,0 +1,589 @@
+/*
+ * Driver for the PCM512x CODECs
+ *
+ * Author: Mark Brown <broonie@linaro.org>
+ * Copyright 2014 Linaro 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.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "pcm512x.h"
+
+#define PCM512x_NUM_SUPPLIES 3
+static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = {
+ "AVDD",
+ "DVDD",
+ "CPVDD",
+};
+
+struct pcm512x_priv {
+ struct regmap *regmap;
+ struct clk *sclk;
+ struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES];
+ struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES];
+};
+
+/*
+ * We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define PCM512x_REGULATOR_EVENT(n) \
+static int pcm512x_regulator_event_##n(struct notifier_block *nb, \
+ unsigned long event, void *data) \
+{ \
+ struct pcm512x_priv *pcm512x = container_of(nb, struct pcm512x_priv, \
+ supply_nb[n]); \
+ if (event & REGULATOR_EVENT_DISABLE) { \
+ regcache_mark_dirty(pcm512x->regmap); \
+ regcache_cache_only(pcm512x->regmap, true); \
+ } \
+ return 0; \
+}
+
+PCM512x_REGULATOR_EVENT(0)
+PCM512x_REGULATOR_EVENT(1)
+PCM512x_REGULATOR_EVENT(2)
+
+static const struct reg_default pcm512x_reg_defaults[] = {
+ { PCM512x_RESET, 0x00 },
+ { PCM512x_POWER, 0x00 },
+ { PCM512x_MUTE, 0x00 },
+ { PCM512x_DSP, 0x00 },
+ { PCM512x_PLL_REF, 0x00 },
+ { PCM512x_DAC_ROUTING, 0x11 },
+ { PCM512x_DSP_PROGRAM, 0x01 },
+ { PCM512x_CLKDET, 0x00 },
+ { PCM512x_AUTO_MUTE, 0x00 },
+ { PCM512x_ERROR_DETECT, 0x00 },
+ { PCM512x_DIGITAL_VOLUME_1, 0x00 },
+ { PCM512x_DIGITAL_VOLUME_2, 0x30 },
+ { PCM512x_DIGITAL_VOLUME_3, 0x30 },
+ { PCM512x_DIGITAL_MUTE_1, 0x22 },
+ { PCM512x_DIGITAL_MUTE_2, 0x00 },
+ { PCM512x_DIGITAL_MUTE_3, 0x07 },
+ { PCM512x_OUTPUT_AMPLITUDE, 0x00 },
+ { PCM512x_ANALOG_GAIN_CTRL, 0x00 },
+ { PCM512x_UNDERVOLTAGE_PROT, 0x00 },
+ { PCM512x_ANALOG_MUTE_CTRL, 0x00 },
+ { PCM512x_ANALOG_GAIN_BOOST, 0x00 },
+ { PCM512x_VCOM_CTRL_1, 0x00 },
+ { PCM512x_VCOM_CTRL_2, 0x01 },
+};
+
+static bool pcm512x_readable(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case PCM512x_RESET:
+ case PCM512x_POWER:
+ case PCM512x_MUTE:
+ case PCM512x_PLL_EN:
+ case PCM512x_SPI_MISO_FUNCTION:
+ case PCM512x_DSP:
+ case PCM512x_GPIO_EN:
+ case PCM512x_BCLK_LRCLK_CFG:
+ case PCM512x_DSP_GPIO_INPUT:
+ case PCM512x_MASTER_MODE:
+ case PCM512x_PLL_REF:
+ case PCM512x_PLL_COEFF_0:
+ case PCM512x_PLL_COEFF_1:
+ case PCM512x_PLL_COEFF_2:
+ case PCM512x_PLL_COEFF_3:
+ case PCM512x_PLL_COEFF_4:
+ case PCM512x_DSP_CLKDIV:
+ case PCM512x_DAC_CLKDIV:
+ case PCM512x_NCP_CLKDIV:
+ case PCM512x_OSR_CLKDIV:
+ case PCM512x_MASTER_CLKDIV_1:
+ case PCM512x_MASTER_CLKDIV_2:
+ case PCM512x_FS_SPEED_MODE:
+ case PCM512x_IDAC_1:
+ case PCM512x_IDAC_2:
+ case PCM512x_ERROR_DETECT:
+ case PCM512x_I2S_1:
+ case PCM512x_I2S_2:
+ case PCM512x_DAC_ROUTING:
+ case PCM512x_DSP_PROGRAM:
+ case PCM512x_CLKDET:
+ case PCM512x_AUTO_MUTE:
+ case PCM512x_DIGITAL_VOLUME_1:
+ case PCM512x_DIGITAL_VOLUME_2:
+ case PCM512x_DIGITAL_VOLUME_3:
+ case PCM512x_DIGITAL_MUTE_1:
+ case PCM512x_DIGITAL_MUTE_2:
+ case PCM512x_DIGITAL_MUTE_3:
+ case PCM512x_GPIO_OUTPUT_1:
+ case PCM512x_GPIO_OUTPUT_2:
+ case PCM512x_GPIO_OUTPUT_3:
+ case PCM512x_GPIO_OUTPUT_4:
+ case PCM512x_GPIO_OUTPUT_5:
+ case PCM512x_GPIO_OUTPUT_6:
+ case PCM512x_GPIO_CONTROL_1:
+ case PCM512x_GPIO_CONTROL_2:
+ case PCM512x_OVERFLOW:
+ case PCM512x_RATE_DET_1:
+ case PCM512x_RATE_DET_2:
+ case PCM512x_RATE_DET_3:
+ case PCM512x_RATE_DET_4:
+ case PCM512x_ANALOG_MUTE_DET:
+ case PCM512x_GPIN:
+ case PCM512x_DIGITAL_MUTE_DET:
+ case PCM512x_OUTPUT_AMPLITUDE:
+ case PCM512x_ANALOG_GAIN_CTRL:
+ case PCM512x_UNDERVOLTAGE_PROT:
+ case PCM512x_ANALOG_MUTE_CTRL:
+ case PCM512x_ANALOG_GAIN_BOOST:
+ case PCM512x_VCOM_CTRL_1:
+ case PCM512x_VCOM_CTRL_2:
+ case PCM512x_CRAM_CTRL:
+ return true;
+ default:
+ /* There are 256 raw register addresses */
+ return reg < 0xff;
+ }
+}
+
+static bool pcm512x_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case PCM512x_PLL_EN:
+ case PCM512x_OVERFLOW:
+ case PCM512x_RATE_DET_1:
+ case PCM512x_RATE_DET_2:
+ case PCM512x_RATE_DET_3:
+ case PCM512x_RATE_DET_4:
+ case PCM512x_ANALOG_MUTE_DET:
+ case PCM512x_GPIN:
+ case PCM512x_DIGITAL_MUTE_DET:
+ case PCM512x_CRAM_CTRL:
+ return true;
+ default:
+ /* There are 256 raw register addresses */
+ return reg < 0xff;
+ }
+}
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
+
+static const char * const pcm512x_dsp_program_texts[] = {
+ "FIR interpolation with de-emphasis",
+ "Low latency IIR with de-emphasis",
+ "Fixed process flow",
+ "High attenuation with de-emphasis",
+ "Ringing-less low latency FIR",
+};
+
+static const unsigned int pcm512x_dsp_program_values[] = {
+ 1,
+ 2,
+ 3,
+ 5,
+ 7,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program,
+ PCM512x_DSP_PROGRAM, 0, 0x1f,
+ pcm512x_dsp_program_texts,
+ pcm512x_dsp_program_values);
+
+static const char * const pcm512x_clk_missing_text[] = {
+ "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s"
+};
+
+static const struct soc_enum pcm512x_clk_missing =
+ SOC_ENUM_SINGLE(PCM512x_CLKDET, 0, 8, pcm512x_clk_missing_text);
+
+static const char * const pcm512x_autom_text[] = {
+ "21ms", "106ms", "213ms", "533ms", "1.07s", "2.13s", "5.33s", "10.66s"
+};
+
+static const struct soc_enum pcm512x_autom_l =
+ SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATML_SHIFT, 8,
+ pcm512x_autom_text);
+
+static const struct soc_enum pcm512x_autom_r =
+ SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 8,
+ pcm512x_autom_text);
+
+static const char * const pcm512x_ramp_rate_text[] = {
+ "1 sample/update", "2 samples/update", "4 samples/update",
+ "Immediate"
+};
+
+static const struct soc_enum pcm512x_vndf =
+ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDF_SHIFT, 4,
+ pcm512x_ramp_rate_text);
+
+static const struct soc_enum pcm512x_vnuf =
+ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUF_SHIFT, 4,
+ pcm512x_ramp_rate_text);
+
+static const struct soc_enum pcm512x_vedf =
+ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDF_SHIFT, 4,
+ pcm512x_ramp_rate_text);
+
+static const char * const pcm512x_ramp_step_text[] = {
+ "4dB/step", "2dB/step", "1dB/step", "0.5dB/step"
+};
+
+static const struct soc_enum pcm512x_vnds =
+ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDS_SHIFT, 4,
+ pcm512x_ramp_step_text);
+
+static const struct soc_enum pcm512x_vnus =
+ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUS_SHIFT, 4,
+ pcm512x_ramp_step_text);
+
+static const struct soc_enum pcm512x_veds =
+ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4,
+ pcm512x_ramp_step_text);
+
+static const struct snd_kcontrol_new pcm512x_controls[] = {
+SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2,
+ PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL,
+ PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
+SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
+ PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
+SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
+ PCM512x_RQMR_SHIFT, 1, 1),
+
+SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
+SOC_VALUE_ENUM("DSP Program", pcm512x_dsp_program),
+
+SOC_ENUM("Clock Missing Period", pcm512x_clk_missing),
+SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l),
+SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r),
+SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3,
+ PCM512x_ACTL_SHIFT, 1, 0),
+SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT,
+ PCM512x_AMLR_SHIFT, 1, 0),
+
+SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf),
+SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds),
+SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf),
+SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus),
+SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf),
+SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds),
+};
+
+static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = {
+SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_OUTPUT("OUTL"),
+SND_SOC_DAPM_OUTPUT("OUTR"),
+};
+
+static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = {
+ { "DACL", NULL, "Playback" },
+ { "DACR", NULL, "Playback" },
+
+ { "OUTL", NULL, "DACL" },
+ { "OUTR", NULL, "DACR" },
+};
+
+static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct pcm512x_priv *pcm512x = dev_get_drvdata(codec->dev);
+ int ret;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+ PCM512x_RQST, 0);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to remove standby: %d\n",
+ ret);
+ return ret;
+ }
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+ PCM512x_RQST, PCM512x_RQST);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request standby: %d\n",
+ ret);
+ return ret;
+ }
+ break;
+ }
+
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver pcm512x_dai = {
+ .name = "pcm512x-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE
+ },
+};
+
+static struct snd_soc_codec_driver pcm512x_codec_driver = {
+ .set_bias_level = pcm512x_set_bias_level,
+ .idle_bias_off = true,
+
+ .controls = pcm512x_controls,
+ .num_controls = ARRAY_SIZE(pcm512x_controls),
+ .dapm_widgets = pcm512x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets),
+ .dapm_routes = pcm512x_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes),
+};
+
+static const struct regmap_range_cfg pcm512x_range = {
+ .name = "Pages", .range_min = PCM512x_VIRT_BASE,
+ .range_max = PCM512x_MAX_REGISTER,
+ .selector_reg = PCM512x_PAGE,
+ .selector_mask = 0xff,
+ .window_start = 0, .window_len = 0x100,
+};
+
+const struct regmap_config pcm512x_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .readable_reg = pcm512x_readable,
+ .volatile_reg = pcm512x_volatile,
+
+ .ranges = &pcm512x_range,
+ .num_ranges = 1,
+
+ .max_register = PCM512x_MAX_REGISTER,
+ .reg_defaults = pcm512x_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(pcm512x_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(pcm512x_regmap);
+
+int pcm512x_probe(struct device *dev, struct regmap *regmap)
+{
+ struct pcm512x_priv *pcm512x;
+ int i, ret;
+
+ pcm512x = devm_kzalloc(dev, sizeof(struct pcm512x_priv), GFP_KERNEL);
+ if (!pcm512x)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, pcm512x);
+ pcm512x->regmap = regmap;
+
+ for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++)
+ pcm512x->supplies[i].supply = pcm512x_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm512x->supplies),
+ pcm512x->supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to get supplies: %d\n", ret);
+ return ret;
+ }
+
+ pcm512x->supply_nb[0].notifier_call = pcm512x_regulator_event_0;
+ pcm512x->supply_nb[1].notifier_call = pcm512x_regulator_event_1;
+ pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2;
+
+ for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) {
+ ret = regulator_register_notifier(pcm512x->supplies[i].consumer,
+ &pcm512x->supply_nb[i]);
+ if (ret != 0) {
+ dev_err(dev,
+ "Failed to register regulator notifier: %d\n",
+ ret);
+ }
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies),
+ pcm512x->supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ /* Reset the device, verifying I/O in the process for I2C */
+ ret = regmap_write(regmap, PCM512x_RESET,
+ PCM512x_RSTM | PCM512x_RSTR);
+ if (ret != 0) {
+ dev_err(dev, "Failed to reset device: %d\n", ret);
+ goto err;
+ }
+
+ ret = regmap_write(regmap, PCM512x_RESET, 0);
+ if (ret != 0) {
+ dev_err(dev, "Failed to reset device: %d\n", ret);
+ goto err;
+ }
+
+ pcm512x->sclk = devm_clk_get(dev, NULL);
+ if (IS_ERR(pcm512x->sclk)) {
+ if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ dev_info(dev, "No SCLK, using BCLK: %ld\n",
+ PTR_ERR(pcm512x->sclk));
+
+ /* Disable reporting of missing SCLK as an error */
+ regmap_update_bits(regmap, PCM512x_ERROR_DETECT,
+ PCM512x_IDCH, PCM512x_IDCH);
+
+ /* Switch PLL input to BCLK */
+ regmap_update_bits(regmap, PCM512x_PLL_REF,
+ PCM512x_SREF, PCM512x_SREF);
+ } else {
+ ret = clk_prepare_enable(pcm512x->sclk);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+ return ret;
+ }
+ }
+
+ /* Default to standby mode */
+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+ PCM512x_RQST, PCM512x_RQST);
+ if (ret != 0) {
+ dev_err(dev, "Failed to request standby: %d\n",
+ ret);
+ goto err_clk;
+ }
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ ret = snd_soc_register_codec(dev, &pcm512x_codec_driver,
+ &pcm512x_dai, 1);
+ if (ret != 0) {
+ dev_err(dev, "Failed to register CODEC: %d\n", ret);
+ goto err_pm;
+ }
+
+ return 0;
+
+err_pm:
+ pm_runtime_disable(dev);
+err_clk:
+ if (!IS_ERR(pcm512x->sclk))
+ clk_disable_unprepare(pcm512x->sclk);
+err:
+ regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies),
+ pcm512x->supplies);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pcm512x_probe);
+
+void pcm512x_remove(struct device *dev)
+{
+ struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
+
+ snd_soc_unregister_codec(dev);
+ pm_runtime_disable(dev);
+ if (!IS_ERR(pcm512x->sclk))
+ clk_disable_unprepare(pcm512x->sclk);
+ regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies),
+ pcm512x->supplies);
+}
+EXPORT_SYMBOL_GPL(pcm512x_remove);
+
+static int pcm512x_suspend(struct device *dev)
+{
+ struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+ PCM512x_RQPD, PCM512x_RQPD);
+ if (ret != 0) {
+ dev_err(dev, "Failed to request power down: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies),
+ pcm512x->supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to disable supplies: %d\n", ret);
+ return ret;
+ }
+
+ if (!IS_ERR(pcm512x->sclk))
+ clk_disable_unprepare(pcm512x->sclk);
+
+ return 0;
+}
+
+static int pcm512x_resume(struct device *dev)
+{
+ struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
+ int ret;
+
+ if (!IS_ERR(pcm512x->sclk)) {
+ ret = clk_prepare_enable(pcm512x->sclk);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies),
+ pcm512x->supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ regcache_cache_only(pcm512x->regmap, false);
+ ret = regcache_sync(pcm512x->regmap);
+ if (ret != 0) {
+ dev_err(dev, "Failed to sync cache: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
+ PCM512x_RQPD, 0);
+ if (ret != 0) {
+ dev_err(dev, "Failed to remove power down: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+const struct dev_pm_ops pcm512x_pm_ops = {
+ SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(pcm512x_pm_ops);
+
+MODULE_DESCRIPTION("ASoC PCM512x codec driver");
+MODULE_AUTHOR("Mark Brown <broonie@linaro.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h
new file mode 100644
index 000000000000..6ee76aaca09a
--- /dev/null
+++ b/sound/soc/codecs/pcm512x.h
@@ -0,0 +1,171 @@
+/*
+ * Driver for the PCM512x CODECs
+ *
+ * Author: Mark Brown <broonie@linaro.org>
+ * Copyright 2014 Linaro 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.
+ */
+
+#ifndef _SND_SOC_PCM512X
+#define _SND_SOC_PCM512X
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define PCM512x_VIRT_BASE 0x100
+#define PCM512x_PAGE_LEN 0x100
+#define PCM512x_PAGE_BASE(n) (PCM512x_VIRT_BASE + (PCM512x_PAGE_LEN * n))
+
+#define PCM512x_PAGE 0
+
+#define PCM512x_RESET (PCM512x_PAGE_BASE(0) + 1)
+#define PCM512x_POWER (PCM512x_PAGE_BASE(0) + 2)
+#define PCM512x_MUTE (PCM512x_PAGE_BASE(0) + 3)
+#define PCM512x_PLL_EN (PCM512x_PAGE_BASE(0) + 4)
+#define PCM512x_SPI_MISO_FUNCTION (PCM512x_PAGE_BASE(0) + 6)
+#define PCM512x_DSP (PCM512x_PAGE_BASE(0) + 7)
+#define PCM512x_GPIO_EN (PCM512x_PAGE_BASE(0) + 8)
+#define PCM512x_BCLK_LRCLK_CFG (PCM512x_PAGE_BASE(0) + 9)
+#define PCM512x_DSP_GPIO_INPUT (PCM512x_PAGE_BASE(0) + 10)
+#define PCM512x_MASTER_MODE (PCM512x_PAGE_BASE(0) + 12)
+#define PCM512x_PLL_REF (PCM512x_PAGE_BASE(0) + 13)
+#define PCM512x_PLL_COEFF_0 (PCM512x_PAGE_BASE(0) + 20)
+#define PCM512x_PLL_COEFF_1 (PCM512x_PAGE_BASE(0) + 21)
+#define PCM512x_PLL_COEFF_2 (PCM512x_PAGE_BASE(0) + 22)
+#define PCM512x_PLL_COEFF_3 (PCM512x_PAGE_BASE(0) + 23)
+#define PCM512x_PLL_COEFF_4 (PCM512x_PAGE_BASE(0) + 24)
+#define PCM512x_DSP_CLKDIV (PCM512x_PAGE_BASE(0) + 27)
+#define PCM512x_DAC_CLKDIV (PCM512x_PAGE_BASE(0) + 28)
+#define PCM512x_NCP_CLKDIV (PCM512x_PAGE_BASE(0) + 29)
+#define PCM512x_OSR_CLKDIV (PCM512x_PAGE_BASE(0) + 30)
+#define PCM512x_MASTER_CLKDIV_1 (PCM512x_PAGE_BASE(0) + 32)
+#define PCM512x_MASTER_CLKDIV_2 (PCM512x_PAGE_BASE(0) + 33)
+#define PCM512x_FS_SPEED_MODE (PCM512x_PAGE_BASE(0) + 34)
+#define PCM512x_IDAC_1 (PCM512x_PAGE_BASE(0) + 35)
+#define PCM512x_IDAC_2 (PCM512x_PAGE_BASE(0) + 36)
+#define PCM512x_ERROR_DETECT (PCM512x_PAGE_BASE(0) + 37)
+#define PCM512x_I2S_1 (PCM512x_PAGE_BASE(0) + 40)
+#define PCM512x_I2S_2 (PCM512x_PAGE_BASE(0) + 41)
+#define PCM512x_DAC_ROUTING (PCM512x_PAGE_BASE(0) + 42)
+#define PCM512x_DSP_PROGRAM (PCM512x_PAGE_BASE(0) + 43)
+#define PCM512x_CLKDET (PCM512x_PAGE_BASE(0) + 44)
+#define PCM512x_AUTO_MUTE (PCM512x_PAGE_BASE(0) + 59)
+#define PCM512x_DIGITAL_VOLUME_1 (PCM512x_PAGE_BASE(0) + 60)
+#define PCM512x_DIGITAL_VOLUME_2 (PCM512x_PAGE_BASE(0) + 61)
+#define PCM512x_DIGITAL_VOLUME_3 (PCM512x_PAGE_BASE(0) + 62)
+#define PCM512x_DIGITAL_MUTE_1 (PCM512x_PAGE_BASE(0) + 63)
+#define PCM512x_DIGITAL_MUTE_2 (PCM512x_PAGE_BASE(0) + 64)
+#define PCM512x_DIGITAL_MUTE_3 (PCM512x_PAGE_BASE(0) + 65)
+#define PCM512x_GPIO_OUTPUT_1 (PCM512x_PAGE_BASE(0) + 80)
+#define PCM512x_GPIO_OUTPUT_2 (PCM512x_PAGE_BASE(0) + 81)
+#define PCM512x_GPIO_OUTPUT_3 (PCM512x_PAGE_BASE(0) + 82)
+#define PCM512x_GPIO_OUTPUT_4 (PCM512x_PAGE_BASE(0) + 83)
+#define PCM512x_GPIO_OUTPUT_5 (PCM512x_PAGE_BASE(0) + 84)
+#define PCM512x_GPIO_OUTPUT_6 (PCM512x_PAGE_BASE(0) + 85)
+#define PCM512x_GPIO_CONTROL_1 (PCM512x_PAGE_BASE(0) + 86)
+#define PCM512x_GPIO_CONTROL_2 (PCM512x_PAGE_BASE(0) + 87)
+#define PCM512x_OVERFLOW (PCM512x_PAGE_BASE(0) + 90)
+#define PCM512x_RATE_DET_1 (PCM512x_PAGE_BASE(0) + 91)
+#define PCM512x_RATE_DET_2 (PCM512x_PAGE_BASE(0) + 92)
+#define PCM512x_RATE_DET_3 (PCM512x_PAGE_BASE(0) + 93)
+#define PCM512x_RATE_DET_4 (PCM512x_PAGE_BASE(0) + 94)
+#define PCM512x_ANALOG_MUTE_DET (PCM512x_PAGE_BASE(0) + 108)
+#define PCM512x_GPIN (PCM512x_PAGE_BASE(0) + 119)
+#define PCM512x_DIGITAL_MUTE_DET (PCM512x_PAGE_BASE(0) + 120)
+
+#define PCM512x_OUTPUT_AMPLITUDE (PCM512x_PAGE_BASE(1) + 1)
+#define PCM512x_ANALOG_GAIN_CTRL (PCM512x_PAGE_BASE(1) + 2)
+#define PCM512x_UNDERVOLTAGE_PROT (PCM512x_PAGE_BASE(1) + 5)
+#define PCM512x_ANALOG_MUTE_CTRL (PCM512x_PAGE_BASE(1) + 6)
+#define PCM512x_ANALOG_GAIN_BOOST (PCM512x_PAGE_BASE(1) + 7)
+#define PCM512x_VCOM_CTRL_1 (PCM512x_PAGE_BASE(1) + 8)
+#define PCM512x_VCOM_CTRL_2 (PCM512x_PAGE_BASE(1) + 9)
+
+#define PCM512x_CRAM_CTRL (PCM512x_PAGE_BASE(44) + 1)
+
+#define PCM512x_MAX_REGISTER (PCM512x_PAGE_BASE(44) + 1)
+
+/* Page 0, Register 1 - reset */
+#define PCM512x_RSTR (1 << 0)
+#define PCM512x_RSTM (1 << 4)
+
+/* Page 0, Register 2 - power */
+#define PCM512x_RQPD (1 << 0)
+#define PCM512x_RQPD_SHIFT 0
+#define PCM512x_RQST (1 << 4)
+#define PCM512x_RQST_SHIFT 4
+
+/* Page 0, Register 3 - mute */
+#define PCM512x_RQMR_SHIFT 0
+#define PCM512x_RQML_SHIFT 4
+
+/* Page 0, Register 4 - PLL */
+#define PCM512x_PLCE (1 << 0)
+#define PCM512x_RLCE_SHIFT 0
+#define PCM512x_PLCK (1 << 4)
+#define PCM512x_PLCK_SHIFT 4
+
+/* Page 0, Register 7 - DSP */
+#define PCM512x_SDSL (1 << 0)
+#define PCM512x_SDSL_SHIFT 0
+#define PCM512x_DEMP (1 << 4)
+#define PCM512x_DEMP_SHIFT 4
+
+/* Page 0, Register 13 - PLL reference */
+#define PCM512x_SREF (1 << 4)
+
+/* Page 0, Register 37 - Error detection */
+#define PCM512x_IPLK (1 << 0)
+#define PCM512x_DCAS (1 << 1)
+#define PCM512x_IDCM (1 << 2)
+#define PCM512x_IDCH (1 << 3)
+#define PCM512x_IDSK (1 << 4)
+#define PCM512x_IDBK (1 << 5)
+#define PCM512x_IDFS (1 << 6)
+
+/* Page 0, Register 42 - DAC routing */
+#define PCM512x_AUPR_SHIFT 0
+#define PCM512x_AUPL_SHIFT 4
+
+/* Page 0, Register 59 - auto mute */
+#define PCM512x_ATMR_SHIFT 0
+#define PCM512x_ATML_SHIFT 4
+
+/* Page 0, Register 63 - ramp rates */
+#define PCM512x_VNDF_SHIFT 6
+#define PCM512x_VNDS_SHIFT 4
+#define PCM512x_VNUF_SHIFT 2
+#define PCM512x_VNUS_SHIFT 0
+
+/* Page 0, Register 64 - emergency ramp rates */
+#define PCM512x_VEDF_SHIFT 6
+#define PCM512x_VEDS_SHIFT 4
+
+/* Page 0, Register 65 - Digital mute enables */
+#define PCM512x_ACTL_SHIFT 2
+#define PCM512x_AMLE_SHIFT 1
+#define PCM512x_AMLR_SHIFT 0
+
+/* Page 1, Register 2 - analog volume control */
+#define PCM512x_RAGN_SHIFT 0
+#define PCM512x_LAGN_SHIFT 4
+
+/* Page 1, Register 7 - analog boost control */
+#define PCM512x_AGBR_SHIFT 0
+#define PCM512x_AGBL_SHIFT 4
+
+extern const struct dev_pm_ops pcm512x_pm_ops;
+extern const struct regmap_config pcm512x_regmap;
+
+int pcm512x_probe(struct device *dev, struct regmap *regmap);
+void pcm512x_remove(struct device *dev);
+
+#endif
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 912c9cbc2724..d4c229f0233f 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -210,26 +210,22 @@ static int rt5631_dmic_put(struct snd_kcontrol *kcontrol,
static const char *rt5631_input_mode[] = {
"Single ended", "Differential"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1,
- RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode);
+static SOC_ENUM_SINGLE_DECL(rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1,
+ RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode);
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1,
- RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode);
+static SOC_ENUM_SINGLE_DECL(rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1,
+ RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode);
/* MONO Input Type */
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL,
- RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode);
+static SOC_ENUM_SINGLE_DECL(rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL,
+ RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode);
/* SPK Ratio Gain Control */
static const char *rt5631_spk_ratio[] = {"1.00x", "1.09x", "1.27x", "1.44x",
"1.56x", "1.68x", "1.99x", "2.34x"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG,
- RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio);
+static SOC_ENUM_SINGLE_DECL(rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG,
+ RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio);
static const struct snd_kcontrol_new rt5631_snd_controls[] = {
/* MIC */
@@ -759,9 +755,8 @@ static const struct snd_kcontrol_new rt5631_monomix_mixer_controls[] = {
/* Left SPK Volume Input */
static const char *rt5631_spkvoll_sel[] = {"Vmid", "SPKMIXL"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL,
- RT5631_L_EN_SHIFT, rt5631_spkvoll_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL,
+ RT5631_L_EN_SHIFT, rt5631_spkvoll_sel);
static const struct snd_kcontrol_new rt5631_spkvoll_mux_control =
SOC_DAPM_ENUM("Left SPKVOL SRC", rt5631_spkvoll_enum);
@@ -769,9 +764,8 @@ static const struct snd_kcontrol_new rt5631_spkvoll_mux_control =
/* Left HP Volume Input */
static const char *rt5631_hpvoll_sel[] = {"Vmid", "OUTMIXL"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_hpvoll_enum, RT5631_HP_OUT_VOL,
- RT5631_L_EN_SHIFT, rt5631_hpvoll_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_hpvoll_enum, RT5631_HP_OUT_VOL,
+ RT5631_L_EN_SHIFT, rt5631_hpvoll_sel);
static const struct snd_kcontrol_new rt5631_hpvoll_mux_control =
SOC_DAPM_ENUM("Left HPVOL SRC", rt5631_hpvoll_enum);
@@ -779,9 +773,8 @@ static const struct snd_kcontrol_new rt5631_hpvoll_mux_control =
/* Left Out Volume Input */
static const char *rt5631_outvoll_sel[] = {"Vmid", "OUTMIXL"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL,
- RT5631_L_EN_SHIFT, rt5631_outvoll_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL,
+ RT5631_L_EN_SHIFT, rt5631_outvoll_sel);
static const struct snd_kcontrol_new rt5631_outvoll_mux_control =
SOC_DAPM_ENUM("Left OUTVOL SRC", rt5631_outvoll_enum);
@@ -789,9 +782,8 @@ static const struct snd_kcontrol_new rt5631_outvoll_mux_control =
/* Right Out Volume Input */
static const char *rt5631_outvolr_sel[] = {"Vmid", "OUTMIXR"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL,
- RT5631_R_EN_SHIFT, rt5631_outvolr_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL,
+ RT5631_R_EN_SHIFT, rt5631_outvolr_sel);
static const struct snd_kcontrol_new rt5631_outvolr_mux_control =
SOC_DAPM_ENUM("Right OUTVOL SRC", rt5631_outvolr_enum);
@@ -799,9 +791,8 @@ static const struct snd_kcontrol_new rt5631_outvolr_mux_control =
/* Right HP Volume Input */
static const char *rt5631_hpvolr_sel[] = {"Vmid", "OUTMIXR"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_hpvolr_enum, RT5631_HP_OUT_VOL,
- RT5631_R_EN_SHIFT, rt5631_hpvolr_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_hpvolr_enum, RT5631_HP_OUT_VOL,
+ RT5631_R_EN_SHIFT, rt5631_hpvolr_sel);
static const struct snd_kcontrol_new rt5631_hpvolr_mux_control =
SOC_DAPM_ENUM("Right HPVOL SRC", rt5631_hpvolr_enum);
@@ -809,9 +800,8 @@ static const struct snd_kcontrol_new rt5631_hpvolr_mux_control =
/* Right SPK Volume Input */
static const char *rt5631_spkvolr_sel[] = {"Vmid", "SPKMIXR"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL,
- RT5631_R_EN_SHIFT, rt5631_spkvolr_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL,
+ RT5631_R_EN_SHIFT, rt5631_spkvolr_sel);
static const struct snd_kcontrol_new rt5631_spkvolr_mux_control =
SOC_DAPM_ENUM("Right SPKVOL SRC", rt5631_spkvolr_enum);
@@ -820,9 +810,8 @@ static const struct snd_kcontrol_new rt5631_spkvolr_mux_control =
static const char *rt5631_spol_src_sel[] = {
"SPOLMIX", "MONOIN_RX", "VDAC", "DACL"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
- RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+ RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel);
static const struct snd_kcontrol_new rt5631_spol_mux_control =
SOC_DAPM_ENUM("SPOL SRC", rt5631_spol_src_enum);
@@ -831,9 +820,8 @@ static const struct snd_kcontrol_new rt5631_spol_mux_control =
static const char *rt5631_spor_src_sel[] = {
"SPORMIX", "MONOIN_RX", "VDAC", "DACR"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
- RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+ RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel);
static const struct snd_kcontrol_new rt5631_spor_mux_control =
SOC_DAPM_ENUM("SPOR SRC", rt5631_spor_src_enum);
@@ -841,9 +829,8 @@ static const struct snd_kcontrol_new rt5631_spor_mux_control =
/* MONO Input */
static const char *rt5631_mono_src_sel[] = {"MONOMIX", "MONOIN_RX", "VDAC"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
- RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+ RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel);
static const struct snd_kcontrol_new rt5631_mono_mux_control =
SOC_DAPM_ENUM("MONO SRC", rt5631_mono_src_enum);
@@ -851,9 +838,8 @@ static const struct snd_kcontrol_new rt5631_mono_mux_control =
/* Left HPO Input */
static const char *rt5631_hpl_src_sel[] = {"Left HPVOL", "Left DAC"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
- RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+ RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel);
static const struct snd_kcontrol_new rt5631_hpl_mux_control =
SOC_DAPM_ENUM("HPL SRC", rt5631_hpl_src_enum);
@@ -861,9 +847,8 @@ static const struct snd_kcontrol_new rt5631_hpl_mux_control =
/* Right HPO Input */
static const char *rt5631_hpr_src_sel[] = {"Right HPVOL", "Right DAC"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
- RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel);
+static SOC_ENUM_SINGLE_DECL(rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL,
+ RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel);
static const struct snd_kcontrol_new rt5631_hpr_mux_control =
SOC_DAPM_ENUM("HPR SRC", rt5631_hpr_src_enum);
@@ -1585,15 +1570,6 @@ static int rt5631_probe(struct snd_soc_codec *codec)
{
struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
unsigned int val;
- int ret;
-
- codec->control_data = rt5631->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
val = rt5631_read_index(codec, RT5631_ADDA_MIXER_INTL_REG3);
if (val & 0x0002)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index a3fb41179636..0061ae6b6716 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -361,25 +361,24 @@ static unsigned int bst_tlv[] = {
static const char * const rt5640_data_select[] = {
"Normal", "left copy to right", "right copy to left", "Swap"};
-static const SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA,
- RT5640_IF1_DAC_SEL_SFT, rt5640_data_select);
+static SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA,
+ RT5640_IF1_DAC_SEL_SFT, rt5640_data_select);
-static const SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA,
- RT5640_IF1_ADC_SEL_SFT, rt5640_data_select);
+static SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA,
+ RT5640_IF1_ADC_SEL_SFT, rt5640_data_select);
-static const SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA,
- RT5640_IF2_DAC_SEL_SFT, rt5640_data_select);
+static SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA,
+ RT5640_IF2_DAC_SEL_SFT, rt5640_data_select);
-static const SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA,
- RT5640_IF2_ADC_SEL_SFT, rt5640_data_select);
+static SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA,
+ RT5640_IF2_ADC_SEL_SFT, rt5640_data_select);
/* Class D speaker gain ratio */
static const char * const rt5640_clsd_spk_ratio[] = {"1.66x", "1.83x", "1.94x",
"2x", "2.11x", "2.22x", "2.33x", "2.44x", "2.55x", "2.66x", "2.77x"};
-static const SOC_ENUM_SINGLE_DECL(
- rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT,
- RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio);
+static SOC_ENUM_SINGLE_DECL(rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT,
+ RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio);
static const struct snd_kcontrol_new rt5640_snd_controls[] = {
/* Speaker Output Volume */
@@ -753,9 +752,8 @@ static const char * const rt5640_stereo_adc1_src[] = {
"DIG MIX", "ADC"
};
-static const SOC_ENUM_SINGLE_DECL(
- rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER,
- RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src);
+static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER,
+ RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src);
static const struct snd_kcontrol_new rt5640_sto_adc_1_mux =
SOC_DAPM_ENUM("Stereo ADC1 Mux", rt5640_stereo_adc1_enum);
@@ -764,9 +762,8 @@ static const char * const rt5640_stereo_adc2_src[] = {
"DMIC1", "DMIC2", "DIG MIX"
};
-static const SOC_ENUM_SINGLE_DECL(
- rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER,
- RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src);
+static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER,
+ RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src);
static const struct snd_kcontrol_new rt5640_sto_adc_2_mux =
SOC_DAPM_ENUM("Stereo ADC2 Mux", rt5640_stereo_adc2_enum);
@@ -776,9 +773,8 @@ static const char * const rt5640_mono_adc_l1_src[] = {
"Mono DAC MIXL", "ADCL"
};
-static const SOC_ENUM_SINGLE_DECL(
- rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER,
- RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src);
+static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER,
+ RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src);
static const struct snd_kcontrol_new rt5640_mono_adc_l1_mux =
SOC_DAPM_ENUM("Mono ADC1 left source", rt5640_mono_adc_l1_enum);
@@ -787,9 +783,8 @@ static const char * const rt5640_mono_adc_l2_src[] = {
"DMIC L1", "DMIC L2", "Mono DAC MIXL"
};
-static const SOC_ENUM_SINGLE_DECL(
- rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER,
- RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src);
+static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER,
+ RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src);
static const struct snd_kcontrol_new rt5640_mono_adc_l2_mux =
SOC_DAPM_ENUM("Mono ADC2 left source", rt5640_mono_adc_l2_enum);
@@ -798,9 +793,8 @@ static const char * const rt5640_mono_adc_r1_src[] = {
"Mono DAC MIXR", "ADCR"
};
-static const SOC_ENUM_SINGLE_DECL(
- rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER,
- RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src);
+static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER,
+ RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src);
static const struct snd_kcontrol_new rt5640_mono_adc_r1_mux =
SOC_DAPM_ENUM("Mono ADC1 right source", rt5640_mono_adc_r1_enum);
@@ -809,9 +803,8 @@ static const char * const rt5640_mono_adc_r2_src[] = {
"DMIC R1", "DMIC R2", "Mono DAC MIXR"
};
-static const SOC_ENUM_SINGLE_DECL(
- rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER,
- RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src);
+static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER,
+ RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src);
static const struct snd_kcontrol_new rt5640_mono_adc_r2_mux =
SOC_DAPM_ENUM("Mono ADC2 right source", rt5640_mono_adc_r2_enum);
@@ -826,9 +819,9 @@ static int rt5640_dac_l2_values[] = {
3,
};
-static const SOC_VALUE_ENUM_SINGLE_DECL(
- rt5640_dac_l2_enum, RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT,
- 0x3, rt5640_dac_l2_src, rt5640_dac_l2_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_l2_enum,
+ RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT,
+ 0x3, rt5640_dac_l2_src, rt5640_dac_l2_values);
static const struct snd_kcontrol_new rt5640_dac_l2_mux =
SOC_DAPM_VALUE_ENUM("DAC2 left channel source", rt5640_dac_l2_enum);
@@ -841,9 +834,9 @@ static int rt5640_dac_r2_values[] = {
0,
};
-static const SOC_VALUE_ENUM_SINGLE_DECL(
- rt5640_dac_r2_enum, RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT,
- 0x3, rt5640_dac_r2_src, rt5640_dac_r2_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_r2_enum,
+ RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT,
+ 0x3, rt5640_dac_r2_src, rt5640_dac_r2_values);
static const struct snd_kcontrol_new rt5640_dac_r2_mux =
SOC_DAPM_ENUM("DAC2 right channel source", rt5640_dac_r2_enum);
@@ -860,9 +853,10 @@ static int rt5640_dai_iis_map_values[] = {
7,
};
-static const SOC_VALUE_ENUM_SINGLE_DECL(
- rt5640_dai_iis_map_enum, RT5640_I2S1_SDP, RT5640_I2S_IF_SFT,
- 0x7, rt5640_dai_iis_map, rt5640_dai_iis_map_values);
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dai_iis_map_enum,
+ RT5640_I2S1_SDP, RT5640_I2S_IF_SFT,
+ 0x7, rt5640_dai_iis_map,
+ rt5640_dai_iis_map_values);
static const struct snd_kcontrol_new rt5640_dai_mux =
SOC_DAPM_VALUE_ENUM("DAI select", rt5640_dai_iis_map_enum);
@@ -872,9 +866,8 @@ static const char * const rt5640_sdi_sel[] = {
"IF1", "IF2"
};
-static const SOC_ENUM_SINGLE_DECL(
- rt5640_sdi_sel_enum, RT5640_I2S2_SDP,
- RT5640_I2S2_SDI_SFT, rt5640_sdi_sel);
+static SOC_ENUM_SINGLE_DECL(rt5640_sdi_sel_enum, RT5640_I2S2_SDP,
+ RT5640_I2S2_SDI_SFT, rt5640_sdi_sel);
static const struct snd_kcontrol_new rt5640_sdi_mux =
SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum);
@@ -1601,8 +1594,7 @@ static int get_clk_info(int sclk, int rate)
static int rt5640_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
unsigned int val_len = 0, val_clk, mask_clk;
int dai_sel, pre_div, bclk_ms, frame_size;
@@ -1943,16 +1935,8 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
static int rt5640_probe(struct snd_soc_codec *codec)
{
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- int ret;
rt5640->codec = codec;
- codec->control_data = rt5640->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
codec->dapm.idle_bias_off = 1;
rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -2093,6 +2077,7 @@ MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
#ifdef CONFIG_ACPI
static struct acpi_device_id rt5640_acpi_match[] = {
{ "INT33CA", 0 },
+ { "10EC5640", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 0fcbe90f3ef2..d3ed1be5a186 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -187,8 +187,9 @@ static const char *adc_mux_text[] = {
"MIC_IN", "LINE_IN"
};
-static const struct soc_enum adc_enum =
-SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 2, 2, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(adc_enum,
+ SGTL5000_CHIP_ANA_CTRL, 2,
+ adc_mux_text);
static const struct snd_kcontrol_new adc_mux =
SOC_DAPM_ENUM("Capture Mux", adc_enum);
@@ -198,8 +199,9 @@ static const char *dac_mux_text[] = {
"DAC", "LINE_IN"
};
-static const struct soc_enum dac_enum =
-SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 6, 2, dac_mux_text);
+static SOC_ENUM_SINGLE_DECL(dac_enum,
+ SGTL5000_CHIP_ANA_CTRL, 6,
+ dac_mux_text);
static const struct snd_kcontrol_new dac_mux =
SOC_DAPM_ENUM("Headphone Mux", dac_enum);
@@ -1350,14 +1352,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
int ret;
struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
- /* setup i2c data ops */
- codec->control_data = sgtl5000->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = sgtl5000_enable_regulators(codec);
if (ret)
return ret;
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index 52e7cb08434b..244c097cd905 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -21,6 +21,7 @@
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <linux/regmap.h>
#include <sound/soc.h>
#include <sound/initval.h>
@@ -209,8 +210,9 @@ out:
static int si476x_codec_probe(struct snd_soc_codec *codec)
{
- codec->control_data = dev_get_regmap(codec->dev->parent, NULL);
- return 0;
+ struct regmap *regmap = dev_get_regmap(codec->dev->parent, NULL);
+
+ return snd_soc_codec_set_cache_io(codec, regmap);
}
static struct snd_soc_dai_ops si476x_dai_ops = {
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
new file mode 100644
index 000000000000..58e7c1f23771
--- /dev/null
+++ b/sound/soc/codecs/sirf-audio-codec.c
@@ -0,0 +1,524 @@
+/*
+ * SiRF audio codec driver
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "sirf-audio-codec.h"
+
+struct sirf_audio_codec {
+ struct clk *clk;
+ struct regmap *regmap;
+ u32 reg_ctrl0, reg_ctrl1;
+};
+
+static const char * const input_mode_mux[] = {"Single-ended",
+ "Differential"};
+
+static const struct soc_enum input_mode_mux_enum =
+ SOC_ENUM_SINGLE(AUDIO_IC_CODEC_CTRL1, 4, 2, input_mode_mux);
+
+static const struct snd_kcontrol_new sirf_audio_codec_input_mode_control =
+ SOC_DAPM_ENUM("Route", input_mode_mux_enum);
+
+static const DECLARE_TLV_DB_SCALE(playback_vol_tlv, -12400, 100, 0);
+static const DECLARE_TLV_DB_SCALE(capture_vol_tlv_prima2, 500, 100, 0);
+static const DECLARE_TLV_DB_RANGE(capture_vol_tlv_atlas6,
+ 0, 7, TLV_DB_SCALE_ITEM(-100, 100, 0),
+ 0x22, 0x3F, TLV_DB_SCALE_ITEM(700, 100, 0),
+);
+
+static struct snd_kcontrol_new volume_controls_atlas6[] = {
+ SOC_DOUBLE_TLV("Playback Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
+ 0x7F, 0, playback_vol_tlv),
+ SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 16, 10,
+ 0x3F, 0, capture_vol_tlv_atlas6),
+};
+
+static struct snd_kcontrol_new volume_controls_prima2[] = {
+ SOC_DOUBLE_TLV("Speaker Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
+ 0x7F, 0, playback_vol_tlv),
+ SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 15, 10,
+ 0x1F, 0, capture_vol_tlv_prima2),
+};
+
+static struct snd_kcontrol_new left_input_path_controls[] = {
+ SOC_DAPM_SINGLE("Line Left Switch", AUDIO_IC_CODEC_CTRL1, 6, 1, 0),
+ SOC_DAPM_SINGLE("Mic Left Switch", AUDIO_IC_CODEC_CTRL1, 3, 1, 0),
+};
+
+static struct snd_kcontrol_new right_input_path_controls[] = {
+ SOC_DAPM_SINGLE("Line Right Switch", AUDIO_IC_CODEC_CTRL1, 5, 1, 0),
+ SOC_DAPM_SINGLE("Mic Right Switch", AUDIO_IC_CODEC_CTRL1, 2, 1, 0),
+};
+
+static struct snd_kcontrol_new left_dac_to_hp_left_amp_switch_control =
+ SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 9, 1, 0);
+
+static struct snd_kcontrol_new left_dac_to_hp_right_amp_switch_control =
+ SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 8, 1, 0);
+
+static struct snd_kcontrol_new right_dac_to_hp_left_amp_switch_control =
+ SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 7, 1, 0);
+
+static struct snd_kcontrol_new right_dac_to_hp_right_amp_switch_control =
+ SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 6, 1, 0);
+
+static struct snd_kcontrol_new left_dac_to_speaker_lineout_switch_control =
+ SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 11, 1, 0);
+
+static struct snd_kcontrol_new right_dac_to_speaker_lineout_switch_control =
+ SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 10, 1, 0);
+
+/* After enable adc, Delay 200ms to avoid pop noise */
+static int adc_enable_delay_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ msleep(200);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void enable_and_reset_codec(struct regmap *regmap,
+ u32 codec_enable_bits, u32 codec_reset_bits)
+{
+ regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
+ codec_enable_bits | codec_reset_bits,
+ codec_enable_bits | ~codec_reset_bits);
+ msleep(20);
+ regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
+ codec_reset_bits, codec_reset_bits);
+}
+
+static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+#define ATLAS6_CODEC_ENABLE_BITS (1 << 29)
+#define ATLAS6_CODEC_RESET_BITS (1 << 28)
+ struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ enable_and_reset_codec(sirf_audio_codec->regmap,
+ ATLAS6_CODEC_ENABLE_BITS, ATLAS6_CODEC_RESET_BITS);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(sirf_audio_codec->regmap,
+ AUDIO_IC_CODEC_CTRL1, ATLAS6_CODEC_ENABLE_BITS,
+ ~ATLAS6_CODEC_ENABLE_BITS);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+#define PRIMA2_CODEC_ENABLE_BITS (1 << 27)
+#define PRIMA2_CODEC_RESET_BITS (1 << 26)
+ struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ enable_and_reset_codec(sirf_audio_codec->regmap,
+ PRIMA2_CODEC_ENABLE_BITS, PRIMA2_CODEC_RESET_BITS);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(sirf_audio_codec->regmap,
+ AUDIO_IC_CODEC_CTRL1, PRIMA2_CODEC_ENABLE_BITS,
+ ~PRIMA2_CODEC_ENABLE_BITS);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget atlas6_output_driver_dapm_widgets[] = {
+ SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
+ 25, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
+ 26, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
+ 27, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget prima2_output_driver_dapm_widgets[] = {
+ SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
+ 23, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
+ 24, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
+ 25, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_widget atlas6_codec_clock_dapm_widget =
+ SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
+ atlas6_codec_enable_and_reset_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
+
+static const struct snd_soc_dapm_widget prima2_codec_clock_dapm_widget =
+ SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
+ prima2_codec_enable_and_reset_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
+
+static const struct snd_soc_dapm_widget sirf_audio_codec_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("DAC left", NULL, AUDIO_IC_CODEC_CTRL0, 1, 0),
+ SND_SOC_DAPM_DAC("DAC right", NULL, AUDIO_IC_CODEC_CTRL0, 0, 0),
+ SND_SOC_DAPM_SWITCH("Left dac to hp left amp", SND_SOC_NOPM, 0, 0,
+ &left_dac_to_hp_left_amp_switch_control),
+ SND_SOC_DAPM_SWITCH("Left dac to hp right amp", SND_SOC_NOPM, 0, 0,
+ &left_dac_to_hp_right_amp_switch_control),
+ SND_SOC_DAPM_SWITCH("Right dac to hp left amp", SND_SOC_NOPM, 0, 0,
+ &right_dac_to_hp_left_amp_switch_control),
+ SND_SOC_DAPM_SWITCH("Right dac to hp right amp", SND_SOC_NOPM, 0, 0,
+ &right_dac_to_hp_right_amp_switch_control),
+ SND_SOC_DAPM_OUT_DRV("HP amp left driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
+ NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("HP amp right driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_SWITCH("Left dac to speaker lineout", SND_SOC_NOPM, 0, 0,
+ &left_dac_to_speaker_lineout_switch_control),
+ SND_SOC_DAPM_SWITCH("Right dac to speaker lineout", SND_SOC_NOPM, 0, 0,
+ &right_dac_to_speaker_lineout_switch_control),
+ SND_SOC_DAPM_OUT_DRV("Speaker amp driver", AUDIO_IC_CODEC_CTRL0, 4, 0,
+ NULL, 0),
+
+ SND_SOC_DAPM_OUTPUT("HPOUTL"),
+ SND_SOC_DAPM_OUTPUT("HPOUTR"),
+ SND_SOC_DAPM_OUTPUT("SPKOUT"),
+
+ SND_SOC_DAPM_ADC_E("ADC left", NULL, AUDIO_IC_CODEC_CTRL1, 8, 0,
+ adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_ADC_E("ADC right", NULL, AUDIO_IC_CODEC_CTRL1, 7, 0,
+ adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER("Left PGA mixer", AUDIO_IC_CODEC_CTRL1, 1, 0,
+ &left_input_path_controls[0],
+ ARRAY_SIZE(left_input_path_controls)),
+ SND_SOC_DAPM_MIXER("Right PGA mixer", AUDIO_IC_CODEC_CTRL1, 0, 0,
+ &right_input_path_controls[0],
+ ARRAY_SIZE(right_input_path_controls)),
+
+ SND_SOC_DAPM_MUX("Mic input mode mux", SND_SOC_NOPM, 0, 0,
+ &sirf_audio_codec_input_mode_control),
+ SND_SOC_DAPM_MICBIAS("Mic Bias", AUDIO_IC_CODEC_PWR, 3, 0),
+ SND_SOC_DAPM_INPUT("MICIN1"),
+ SND_SOC_DAPM_INPUT("MICIN2"),
+ SND_SOC_DAPM_INPUT("LINEIN1"),
+ SND_SOC_DAPM_INPUT("LINEIN2"),
+
+ SND_SOC_DAPM_SUPPLY("HSL Phase Opposite", AUDIO_IC_CODEC_CTRL0,
+ 30, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route sirf_audio_codec_map[] = {
+ {"SPKOUT", NULL, "Speaker Driver"},
+ {"Speaker Driver", NULL, "Speaker amp driver"},
+ {"Speaker amp driver", NULL, "Left dac to speaker lineout"},
+ {"Speaker amp driver", NULL, "Right dac to speaker lineout"},
+ {"Left dac to speaker lineout", "Switch", "DAC left"},
+ {"Right dac to speaker lineout", "Switch", "DAC right"},
+ {"HPOUTL", NULL, "HP Left Driver"},
+ {"HPOUTR", NULL, "HP Right Driver"},
+ {"HP Left Driver", NULL, "HP amp left driver"},
+ {"HP Right Driver", NULL, "HP amp right driver"},
+ {"HP amp left driver", NULL, "Right dac to hp left amp"},
+ {"HP amp right driver", NULL , "Right dac to hp right amp"},
+ {"HP amp left driver", NULL, "Left dac to hp left amp"},
+ {"HP amp right driver", NULL , "Right dac to hp right amp"},
+ {"Right dac to hp left amp", "Switch", "DAC left"},
+ {"Right dac to hp right amp", "Switch", "DAC right"},
+ {"Left dac to hp left amp", "Switch", "DAC left"},
+ {"Left dac to hp right amp", "Switch", "DAC right"},
+ {"DAC left", NULL, "codecclk"},
+ {"DAC right", NULL, "codecclk"},
+ {"DAC left", NULL, "Playback"},
+ {"DAC right", NULL, "Playback"},
+ {"DAC left", NULL, "HSL Phase Opposite"},
+ {"DAC right", NULL, "HSL Phase Opposite"},
+
+ {"Capture", NULL, "ADC left"},
+ {"Capture", NULL, "ADC right"},
+ {"ADC left", NULL, "codecclk"},
+ {"ADC right", NULL, "codecclk"},
+ {"ADC left", NULL, "Left PGA mixer"},
+ {"ADC right", NULL, "Right PGA mixer"},
+ {"Left PGA mixer", "Line Left Switch", "LINEIN2"},
+ {"Right PGA mixer", "Line Right Switch", "LINEIN1"},
+ {"Left PGA mixer", "Mic Left Switch", "MICIN2"},
+ {"Right PGA mixer", "Mic Right Switch", "Mic input mode mux"},
+ {"Mic input mode mux", "Single-ended", "MICIN1"},
+ {"Mic input mode mux", "Differential", "MICIN1"},
+};
+
+static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
+ int cmd,
+ struct snd_soc_dai *dai)
+{
+ int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ struct snd_soc_codec *codec = dai->codec;
+ u32 val = 0;
+
+ /*
+ * This is a workaround, When stop playback,
+ * need disable HP amp, avoid the current noise.
+ */
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (playback)
+ val = IC_HSLEN | IC_HSREN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (playback)
+ snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0,
+ IC_HSLEN | IC_HSREN, val);
+ return 0;
+}
+
+struct snd_soc_dai_ops sirf_audio_codec_dai_ops = {
+ .trigger = sirf_audio_codec_trigger,
+};
+
+struct snd_soc_dai_driver sirf_audio_codec_dai = {
+ .name = "sirf-audio-codec",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &sirf_audio_codec_dai_ops,
+};
+
+static int sirf_audio_codec_probe(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ pm_runtime_enable(codec->dev);
+
+ if (of_device_is_compatible(codec->dev->of_node, "sirf,prima2-audio-codec")) {
+ snd_soc_dapm_new_controls(dapm,
+ prima2_output_driver_dapm_widgets,
+ ARRAY_SIZE(prima2_output_driver_dapm_widgets));
+ snd_soc_dapm_new_controls(dapm,
+ &prima2_codec_clock_dapm_widget, 1);
+ return snd_soc_add_codec_controls(codec,
+ volume_controls_prima2,
+ ARRAY_SIZE(volume_controls_prima2));
+ }
+ if (of_device_is_compatible(codec->dev->of_node, "sirf,atlas6-audio-codec")) {
+ snd_soc_dapm_new_controls(dapm,
+ atlas6_output_driver_dapm_widgets,
+ ARRAY_SIZE(atlas6_output_driver_dapm_widgets));
+ snd_soc_dapm_new_controls(dapm,
+ &atlas6_codec_clock_dapm_widget, 1);
+ return snd_soc_add_codec_controls(codec,
+ volume_controls_atlas6,
+ ARRAY_SIZE(volume_controls_atlas6));
+ }
+
+ return -EINVAL;
+}
+
+static int sirf_audio_codec_remove(struct snd_soc_codec *codec)
+{
+ pm_runtime_disable(codec->dev);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = {
+ .probe = sirf_audio_codec_probe,
+ .remove = sirf_audio_codec_remove,
+ .dapm_widgets = sirf_audio_codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
+ .dapm_routes = sirf_audio_codec_map,
+ .num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map),
+ .idle_bias_off = true,
+};
+
+static const struct of_device_id sirf_audio_codec_of_match[] = {
+ { .compatible = "sirf,prima2-audio-codec" },
+ { .compatible = "sirf,atlas6-audio-codec" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sirf_audio_codec_of_match);
+
+static const struct regmap_config sirf_audio_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = AUDIO_IC_CODEC_CTRL3,
+ .cache_type = REGCACHE_NONE,
+};
+
+static int sirf_audio_codec_driver_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct sirf_audio_codec *sirf_audio_codec;
+ void __iomem *base;
+ struct resource *mem_res;
+ const struct of_device_id *match;
+
+ match = of_match_node(sirf_audio_codec_of_match, pdev->dev.of_node);
+
+ sirf_audio_codec = devm_kzalloc(&pdev->dev,
+ sizeof(struct sirf_audio_codec), GFP_KERNEL);
+ if (!sirf_audio_codec)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, sirf_audio_codec);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, mem_res);
+ if (base == NULL)
+ return -ENOMEM;
+
+ sirf_audio_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &sirf_audio_codec_regmap_config);
+ if (IS_ERR(sirf_audio_codec->regmap))
+ return PTR_ERR(sirf_audio_codec->regmap);
+
+ sirf_audio_codec->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(sirf_audio_codec->clk)) {
+ dev_err(&pdev->dev, "Get clock failed.\n");
+ return PTR_ERR(sirf_audio_codec->clk);
+ }
+
+ ret = clk_prepare_enable(sirf_audio_codec->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Enable clock failed.\n");
+ return ret;
+ }
+
+ ret = snd_soc_register_codec(&(pdev->dev),
+ &soc_codec_device_sirf_audio_codec,
+ &sirf_audio_codec_dai, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "Register Audio Codec dai failed.\n");
+ goto err_clk_put;
+ }
+
+ /*
+ * Always open charge pump, if not, when the charge pump closed the
+ * adc will not stable
+ */
+ regmap_update_bits(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
+ IC_CPFREQ, IC_CPFREQ);
+
+ if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas6-audio-codec"))
+ regmap_update_bits(sirf_audio_codec->regmap,
+ AUDIO_IC_CODEC_CTRL0, IC_CPEN, IC_CPEN);
+ return 0;
+
+err_clk_put:
+ clk_disable_unprepare(sirf_audio_codec->clk);
+ return ret;
+}
+
+static int sirf_audio_codec_driver_remove(struct platform_device *pdev)
+{
+ struct sirf_audio_codec *sirf_audio_codec = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(sirf_audio_codec->clk);
+ snd_soc_unregister_codec(&(pdev->dev));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sirf_audio_codec_suspend(struct device *dev)
+{
+ struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
+
+ regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
+ &sirf_audio_codec->reg_ctrl0);
+ regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
+ &sirf_audio_codec->reg_ctrl1);
+ clk_disable_unprepare(sirf_audio_codec->clk);
+
+ return 0;
+}
+
+static int sirf_audio_codec_resume(struct device *dev)
+{
+ struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(sirf_audio_codec->clk);
+ if (ret)
+ return ret;
+
+ regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
+ sirf_audio_codec->reg_ctrl0);
+ regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
+ sirf_audio_codec->reg_ctrl1);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops sirf_audio_codec_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(sirf_audio_codec_suspend, sirf_audio_codec_resume)
+};
+
+static struct platform_driver sirf_audio_codec_driver = {
+ .driver = {
+ .name = "sirf-audio-codec",
+ .owner = THIS_MODULE,
+ .of_match_table = sirf_audio_codec_of_match,
+ .pm = &sirf_audio_codec_pm_ops,
+ },
+ .probe = sirf_audio_codec_driver_probe,
+ .remove = sirf_audio_codec_driver_remove,
+};
+
+module_platform_driver(sirf_audio_codec_driver);
+
+MODULE_DESCRIPTION("SiRF audio codec driver");
+MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/sirf-audio-codec.h b/sound/soc/codecs/sirf-audio-codec.h
new file mode 100644
index 000000000000..d4c187b8e54a
--- /dev/null
+++ b/sound/soc/codecs/sirf-audio-codec.h
@@ -0,0 +1,75 @@
+/*
+ * SiRF inner codec controllers define
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef _SIRF_AUDIO_CODEC_H
+#define _SIRF_AUDIO_CODEC_H
+
+
+#define AUDIO_IC_CODEC_PWR (0x00E0)
+#define AUDIO_IC_CODEC_CTRL0 (0x00E4)
+#define AUDIO_IC_CODEC_CTRL1 (0x00E8)
+#define AUDIO_IC_CODEC_CTRL2 (0x00EC)
+#define AUDIO_IC_CODEC_CTRL3 (0x00F0)
+
+#define MICBIASEN (1 << 3)
+
+#define IC_RDACEN (1 << 0)
+#define IC_LDACEN (1 << 1)
+#define IC_HSREN (1 << 2)
+#define IC_HSLEN (1 << 3)
+#define IC_SPEN (1 << 4)
+#define IC_CPEN (1 << 5)
+
+#define IC_HPRSELR (1 << 6)
+#define IC_HPLSELR (1 << 7)
+#define IC_HPRSELL (1 << 8)
+#define IC_HPLSELL (1 << 9)
+#define IC_SPSELR (1 << 10)
+#define IC_SPSELL (1 << 11)
+
+#define IC_MONOR (1 << 12)
+#define IC_MONOL (1 << 13)
+
+#define IC_RXOSRSEL (1 << 28)
+#define IC_CPFREQ (1 << 29)
+#define IC_HSINVEN (1 << 30)
+
+#define IC_MICINREN (1 << 0)
+#define IC_MICINLEN (1 << 1)
+#define IC_MICIN1SEL (1 << 2)
+#define IC_MICIN2SEL (1 << 3)
+#define IC_MICDIFSEL (1 << 4)
+#define IC_LINEIN1SEL (1 << 5)
+#define IC_LINEIN2SEL (1 << 6)
+#define IC_RADCEN (1 << 7)
+#define IC_LADCEN (1 << 8)
+#define IC_ALM (1 << 9)
+
+#define IC_DIGMICEN (1 << 22)
+#define IC_DIGMICFREQ (1 << 23)
+#define IC_ADC14B_12 (1 << 24)
+#define IC_FIRDAC_HSL_EN (1 << 25)
+#define IC_FIRDAC_HSR_EN (1 << 26)
+#define IC_FIRDAC_LOUT_EN (1 << 27)
+#define IC_POR (1 << 28)
+#define IC_CODEC_CLK_EN (1 << 29)
+#define IC_HP_3DB_BOOST (1 << 30)
+
+#define IC_ADC_LEFT_GAIN_SHIFT 16
+#define IC_ADC_RIGHT_GAIN_SHIFT 10
+#define IC_ADC_GAIN_MASK 0x3F
+#define IC_MIC_MAX_GAIN 0x39
+
+#define IC_RXPGAR_MASK 0x3F
+#define IC_RXPGAR_SHIFT 14
+#define IC_RXPGAL_MASK 0x3F
+#define IC_RXPGAL_SHIFT 21
+#define IC_RXPGAR 0x7B
+#define IC_RXPGAL 0x7B
+
+#endif /*__SIRF_AUDIO_CODEC_H*/
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c
index 13045f2af4d3..42dff26b3a2a 100644
--- a/sound/soc/codecs/sn95031.c
+++ b/sound/soc/codecs/sn95031.c
@@ -312,14 +312,14 @@ static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w,
/* mux controls */
static const char *sn95031_mic_texts[] = { "AMIC", "LineIn" };
-static const struct soc_enum sn95031_micl_enum =
- SOC_ENUM_SINGLE(SN95031_ADCCONFIG, 1, 2, sn95031_mic_texts);
+static SOC_ENUM_SINGLE_DECL(sn95031_micl_enum,
+ SN95031_ADCCONFIG, 1, sn95031_mic_texts);
static const struct snd_kcontrol_new sn95031_micl_mux_control =
SOC_DAPM_ENUM("Route", sn95031_micl_enum);
-static const struct soc_enum sn95031_micr_enum =
- SOC_ENUM_SINGLE(SN95031_ADCCONFIG, 3, 2, sn95031_mic_texts);
+static SOC_ENUM_SINGLE_DECL(sn95031_micr_enum,
+ SN95031_ADCCONFIG, 3, sn95031_mic_texts);
static const struct snd_kcontrol_new sn95031_micr_mux_control =
SOC_DAPM_ENUM("Route", sn95031_micr_enum);
@@ -328,26 +328,26 @@ static const char *sn95031_input_texts[] = { "DMIC1", "DMIC2", "DMIC3",
"DMIC4", "DMIC5", "DMIC6",
"ADC Left", "ADC Right" };
-static const struct soc_enum sn95031_input1_enum =
- SOC_ENUM_SINGLE(SN95031_AUDIOMUX12, 0, 8, sn95031_input_texts);
+static SOC_ENUM_SINGLE_DECL(sn95031_input1_enum,
+ SN95031_AUDIOMUX12, 0, sn95031_input_texts);
static const struct snd_kcontrol_new sn95031_input1_mux_control =
SOC_DAPM_ENUM("Route", sn95031_input1_enum);
-static const struct soc_enum sn95031_input2_enum =
- SOC_ENUM_SINGLE(SN95031_AUDIOMUX12, 4, 8, sn95031_input_texts);
+static SOC_ENUM_SINGLE_DECL(sn95031_input2_enum,
+ SN95031_AUDIOMUX12, 4, sn95031_input_texts);
static const struct snd_kcontrol_new sn95031_input2_mux_control =
SOC_DAPM_ENUM("Route", sn95031_input2_enum);
-static const struct soc_enum sn95031_input3_enum =
- SOC_ENUM_SINGLE(SN95031_AUDIOMUX34, 0, 8, sn95031_input_texts);
+static SOC_ENUM_SINGLE_DECL(sn95031_input3_enum,
+ SN95031_AUDIOMUX34, 0, sn95031_input_texts);
static const struct snd_kcontrol_new sn95031_input3_mux_control =
SOC_DAPM_ENUM("Route", sn95031_input3_enum);
-static const struct soc_enum sn95031_input4_enum =
- SOC_ENUM_SINGLE(SN95031_AUDIOMUX34, 4, 8, sn95031_input_texts);
+static SOC_ENUM_SINGLE_DECL(sn95031_input4_enum,
+ SN95031_AUDIOMUX34, 4, sn95031_input_texts);
static const struct snd_kcontrol_new sn95031_input4_mux_control =
SOC_DAPM_ENUM("Route", sn95031_input4_enum);
@@ -359,19 +359,19 @@ static const char *sn95031_micmode_text[] = {"Single Ended", "Differential"};
/* 0dB to 30dB in 10dB steps */
static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 10, 0);
-static const struct soc_enum sn95031_micmode1_enum =
- SOC_ENUM_SINGLE(SN95031_MICAMP1, 1, 2, sn95031_micmode_text);
-static const struct soc_enum sn95031_micmode2_enum =
- SOC_ENUM_SINGLE(SN95031_MICAMP2, 1, 2, sn95031_micmode_text);
+static SOC_ENUM_SINGLE_DECL(sn95031_micmode1_enum,
+ SN95031_MICAMP1, 1, sn95031_micmode_text);
+static SOC_ENUM_SINGLE_DECL(sn95031_micmode2_enum,
+ SN95031_MICAMP2, 1, sn95031_micmode_text);
static const char *sn95031_dmic_cfg_text[] = {"GPO", "DMIC"};
-static const struct soc_enum sn95031_dmic12_cfg_enum =
- SOC_ENUM_SINGLE(SN95031_DMICMUX, 0, 2, sn95031_dmic_cfg_text);
-static const struct soc_enum sn95031_dmic34_cfg_enum =
- SOC_ENUM_SINGLE(SN95031_DMICMUX, 1, 2, sn95031_dmic_cfg_text);
-static const struct soc_enum sn95031_dmic56_cfg_enum =
- SOC_ENUM_SINGLE(SN95031_DMICMUX, 2, 2, sn95031_dmic_cfg_text);
+static SOC_ENUM_SINGLE_DECL(sn95031_dmic12_cfg_enum,
+ SN95031_DMICMUX, 0, sn95031_dmic_cfg_text);
+static SOC_ENUM_SINGLE_DECL(sn95031_dmic34_cfg_enum,
+ SN95031_DMICMUX, 1, sn95031_dmic_cfg_text);
+static SOC_ENUM_SINGLE_DECL(sn95031_dmic56_cfg_enum,
+ SN95031_DMICMUX, 2, sn95031_dmic_cfg_text);
static const struct snd_kcontrol_new sn95031_snd_controls[] = {
SOC_ENUM("Mic1Mode Capture Route", sn95031_micmode1_enum),
@@ -825,8 +825,6 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
{
pr_debug("codec_probe called\n");
- snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
-
/* PCM interface config
* This sets the pcm rx slot conguration to max 6 slots
* for max 4 dais (2 stereo and 2 mono)
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index cc8debce752f..56adb3e2def9 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -169,19 +169,19 @@ static const char * const ssm2518_drc_hold_time_text[] = {
"682.24 ms", "1364 ms",
};
-static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum,
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum,
SSM2518_REG_DRC_2, 4, ssm2518_drc_peak_detector_attack_time_text);
-static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum,
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum,
SSM2518_REG_DRC_2, 0, ssm2518_drc_peak_detector_release_time_text);
-static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum,
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum,
SSM2518_REG_DRC_6, 4, ssm2518_drc_peak_detector_attack_time_text);
-static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum,
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum,
SSM2518_REG_DRC_6, 0, ssm2518_drc_peak_detector_release_time_text);
-static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum,
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum,
SSM2518_REG_DRC_7, 4, ssm2518_drc_hold_time_text);
-static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum,
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum,
SSM2518_REG_DRC_7, 0, ssm2518_drc_hold_time_text);
-static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum,
+static SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum,
SSM2518_REG_DRC_9, 0, ssm2518_drc_peak_detector_release_time_text);
static const struct snd_kcontrol_new ssm2518_snd_controls[] = {
@@ -648,16 +648,6 @@ static struct snd_soc_dai_driver ssm2518_dai = {
static int ssm2518_probe(struct snd_soc_codec *codec)
{
- struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- codec->control_data = ssm2518->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
return ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF);
}
diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c
new file mode 100644
index 000000000000..abd63d537173
--- /dev/null
+++ b/sound/soc/codecs/ssm2602-i2c.c
@@ -0,0 +1,57 @@
+/*
+ * SSM2602/SSM2603/SSM2604 I2C audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "ssm2602.h"
+
+/*
+ * ssm2602 2 wire address is determined by GPIO5
+ * state during powerup.
+ * low = 0x1a
+ * high = 0x1b
+ */
+static int ssm2602_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return ssm2602_probe(&client->dev, id->driver_data,
+ devm_regmap_init_i2c(client, &ssm2602_regmap_config));
+}
+
+static int ssm2602_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id ssm2602_i2c_id[] = {
+ { "ssm2602", SSM2602 },
+ { "ssm2603", SSM2602 },
+ { "ssm2604", SSM2604 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
+
+static struct i2c_driver ssm2602_i2c_driver = {
+ .driver = {
+ .name = "ssm2602",
+ .owner = THIS_MODULE,
+ },
+ .probe = ssm2602_i2c_probe,
+ .remove = ssm2602_i2c_remove,
+ .id_table = ssm2602_i2c_id,
+};
+module_i2c_driver(ssm2602_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 I2C driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2602-spi.c b/sound/soc/codecs/ssm2602-spi.c
new file mode 100644
index 000000000000..2bf55e24a7bb
--- /dev/null
+++ b/sound/soc/codecs/ssm2602-spi.c
@@ -0,0 +1,41 @@
+/*
+ * SSM2602 SPI audio driver
+ *
+ * Copyright 2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include <sound/soc.h>
+
+#include "ssm2602.h"
+
+static int ssm2602_spi_probe(struct spi_device *spi)
+{
+ return ssm2602_probe(&spi->dev, SSM2602,
+ devm_regmap_init_spi(spi, &ssm2602_regmap_config));
+}
+
+static int ssm2602_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ return 0;
+}
+
+static struct spi_driver ssm2602_spi_driver = {
+ .driver = {
+ .name = "ssm2602",
+ .owner = THIS_MODULE,
+ },
+ .probe = ssm2602_spi_probe,
+ .remove = ssm2602_spi_remove,
+};
+module_spi_driver(ssm2602_spi_driver);
+
+MODULE_DESCRIPTION("ASoC SSM2602 SPI driver");
+MODULE_AUTHOR("Cliff Cai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index af76bbd1b24f..97b0454eb346 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -27,32 +27,20 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/i2c.h>
-#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include <linux/slab.h>
-#include <sound/core.h>
+
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <sound/initval.h>
#include <sound/tlv.h>
#include "ssm2602.h"
-enum ssm2602_type {
- SSM2602,
- SSM2604,
-};
-
/* codec private data */
struct ssm2602_priv {
unsigned int sysclk;
- struct snd_pcm_hw_constraint_list *sysclk_constraints;
+ const struct snd_pcm_hw_constraint_list *sysclk_constraints;
struct regmap *regmap;
@@ -75,15 +63,16 @@ static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
/*Appending several "None"s just for OSS mixer use*/
static const char *ssm2602_input_select[] = {
- "Line", "Mic", "None", "None", "None",
- "None", "None", "None",
+ "Line", "Mic",
};
static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
static const struct soc_enum ssm2602_enum[] = {
- SOC_ENUM_SINGLE(SSM2602_APANA, 2, 2, ssm2602_input_select),
- SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph),
+ SOC_ENUM_SINGLE(SSM2602_APANA, 2, ARRAY_SIZE(ssm2602_input_select),
+ ssm2602_input_select),
+ SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, ARRAY_SIZE(ssm2602_deemph),
+ ssm2602_deemph),
};
static const unsigned int ssm260x_outmix_tlv[] = {
@@ -197,7 +186,7 @@ static const unsigned int ssm2602_rates_12288000[] = {
8000, 16000, 32000, 48000, 96000,
};
-static struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {
+static const struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {
.list = ssm2602_rates_12288000,
.count = ARRAY_SIZE(ssm2602_rates_12288000),
};
@@ -206,7 +195,7 @@ static const unsigned int ssm2602_rates_11289600[] = {
8000, 44100, 88200,
};
-static struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = {
+static const struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = {
.list = ssm2602_rates_11289600,
.count = ARRAY_SIZE(ssm2602_rates_11289600),
};
@@ -529,7 +518,7 @@ static int ssm2602_resume(struct snd_soc_codec *codec)
return 0;
}
-static int ssm2602_probe(struct snd_soc_codec *codec)
+static int ssm2602_codec_probe(struct snd_soc_codec *codec)
{
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
@@ -554,7 +543,7 @@ static int ssm2602_probe(struct snd_soc_codec *codec)
ARRAY_SIZE(ssm2602_routes));
}
-static int ssm2604_probe(struct snd_soc_codec *codec)
+static int ssm2604_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
@@ -568,18 +557,11 @@ static int ssm2604_probe(struct snd_soc_codec *codec)
ARRAY_SIZE(ssm2604_routes));
}
-static int ssm260x_probe(struct snd_soc_codec *codec)
+static int ssm260x_codec_probe(struct snd_soc_codec *codec)
{
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
int ret;
- codec->control_data = ssm2602->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = regmap_write(ssm2602->regmap, SSM2602_RESET, 0);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
@@ -597,10 +579,10 @@ static int ssm260x_probe(struct snd_soc_codec *codec)
switch (ssm2602->type) {
case SSM2602:
- ret = ssm2602_probe(codec);
+ ret = ssm2602_codec_probe(codec);
break;
case SSM2604:
- ret = ssm2604_probe(codec);
+ ret = ssm2604_codec_probe(codec);
break;
}
@@ -620,7 +602,7 @@ static int ssm2602_remove(struct snd_soc_codec *codec)
}
static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
- .probe = ssm260x_probe,
+ .probe = ssm260x_codec_probe,
.remove = ssm2602_remove,
.suspend = ssm2602_suspend,
.resume = ssm2602_resume,
@@ -639,7 +621,7 @@ static bool ssm2602_register_volatile(struct device *dev, unsigned int reg)
return reg == SSM2602_RESET;
}
-static const struct regmap_config ssm2602_regmap_config = {
+const struct regmap_config ssm2602_regmap_config = {
.val_bits = 9,
.reg_bits = 7,
@@ -650,134 +632,28 @@ static const struct regmap_config ssm2602_regmap_config = {
.reg_defaults_raw = ssm2602_reg,
.num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg),
};
+EXPORT_SYMBOL_GPL(ssm2602_regmap_config);
-#if defined(CONFIG_SPI_MASTER)
-static int ssm2602_spi_probe(struct spi_device *spi)
+int ssm2602_probe(struct device *dev, enum ssm2602_type type,
+ struct regmap *regmap)
{
struct ssm2602_priv *ssm2602;
- int ret;
-
- ssm2602 = devm_kzalloc(&spi->dev, sizeof(struct ssm2602_priv),
- GFP_KERNEL);
- if (ssm2602 == NULL)
- return -ENOMEM;
-
- spi_set_drvdata(spi, ssm2602);
- ssm2602->type = SSM2602;
- ssm2602->regmap = devm_regmap_init_spi(spi, &ssm2602_regmap_config);
- if (IS_ERR(ssm2602->regmap))
- return PTR_ERR(ssm2602->regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
- ret = snd_soc_register_codec(&spi->dev,
- &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
- return ret;
-}
-
-static int ssm2602_spi_remove(struct spi_device *spi)
-{
- snd_soc_unregister_codec(&spi->dev);
- return 0;
-}
-
-static struct spi_driver ssm2602_spi_driver = {
- .driver = {
- .name = "ssm2602",
- .owner = THIS_MODULE,
- },
- .probe = ssm2602_spi_probe,
- .remove = ssm2602_spi_remove,
-};
-#endif
-
-#if IS_ENABLED(CONFIG_I2C)
-/*
- * ssm2602 2 wire address is determined by GPIO5
- * state during powerup.
- * low = 0x1a
- * high = 0x1b
- */
-static int ssm2602_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
-{
- struct ssm2602_priv *ssm2602;
- int ret;
-
- ssm2602 = devm_kzalloc(&i2c->dev, sizeof(struct ssm2602_priv),
- GFP_KERNEL);
+ ssm2602 = devm_kzalloc(dev, sizeof(*ssm2602), GFP_KERNEL);
if (ssm2602 == NULL)
return -ENOMEM;
- i2c_set_clientdata(i2c, ssm2602);
- ssm2602->type = id->driver_data;
-
- ssm2602->regmap = devm_regmap_init_i2c(i2c, &ssm2602_regmap_config);
- if (IS_ERR(ssm2602->regmap))
- return PTR_ERR(ssm2602->regmap);
-
- ret = snd_soc_register_codec(&i2c->dev,
- &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
- return ret;
-}
-
-static int ssm2602_i2c_remove(struct i2c_client *client)
-{
- snd_soc_unregister_codec(&client->dev);
- return 0;
-}
-
-static const struct i2c_device_id ssm2602_i2c_id[] = {
- { "ssm2602", SSM2602 },
- { "ssm2603", SSM2602 },
- { "ssm2604", SSM2604 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
-
-/* corgi i2c codec control layer */
-static struct i2c_driver ssm2602_i2c_driver = {
- .driver = {
- .name = "ssm2602",
- .owner = THIS_MODULE,
- },
- .probe = ssm2602_i2c_probe,
- .remove = ssm2602_i2c_remove,
- .id_table = ssm2602_i2c_id,
-};
-#endif
-
-
-static int __init ssm2602_modinit(void)
-{
- int ret = 0;
-
-#if defined(CONFIG_SPI_MASTER)
- ret = spi_register_driver(&ssm2602_spi_driver);
- if (ret)
- return ret;
-#endif
-
-#if IS_ENABLED(CONFIG_I2C)
- ret = i2c_add_driver(&ssm2602_i2c_driver);
- if (ret)
- return ret;
-#endif
-
- return ret;
-}
-module_init(ssm2602_modinit);
-
-static void __exit ssm2602_exit(void)
-{
-#if defined(CONFIG_SPI_MASTER)
- spi_unregister_driver(&ssm2602_spi_driver);
-#endif
+ dev_set_drvdata(dev, ssm2602);
+ ssm2602->type = SSM2602;
+ ssm2602->regmap = regmap;
-#if IS_ENABLED(CONFIG_I2C)
- i2c_del_driver(&ssm2602_i2c_driver);
-#endif
+ return snd_soc_register_codec(dev, &soc_codec_dev_ssm2602,
+ &ssm2602_dai, 1);
}
-module_exit(ssm2602_exit);
+EXPORT_SYMBOL_GPL(ssm2602_probe);
MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver");
MODULE_AUTHOR("Cliff Cai");
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h
index fbd07d7b73ca..747538847689 100644
--- a/sound/soc/codecs/ssm2602.h
+++ b/sound/soc/codecs/ssm2602.h
@@ -28,6 +28,20 @@
#ifndef _SSM2602_H
#define _SSM2602_H
+#include <linux/regmap.h>
+
+struct device;
+
+enum ssm2602_type {
+ SSM2602,
+ SSM2604,
+};
+
+extern const struct regmap_config ssm2602_regmap_config;
+
+int ssm2602_probe(struct device *dev, enum ssm2602_type type,
+ struct regmap *regmap);
+
/* SSM2602 Codec Register definitions */
#define SSM2602_LINVOL 0x00
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 06edb396e733..12577749b17b 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -187,42 +187,42 @@ static const unsigned int sta32x_limiter_drc_release_tlv[] = {
13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
};
-static const struct soc_enum sta32x_drc_ac_enum =
- SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
- 2, sta32x_drc_ac);
-static const struct soc_enum sta32x_auto_eq_enum =
- SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
- 3, sta32x_auto_eq_mode);
-static const struct soc_enum sta32x_auto_gc_enum =
- SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
- 4, sta32x_auto_gc_mode);
-static const struct soc_enum sta32x_auto_xo_enum =
- SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
- 16, sta32x_auto_xo_mode);
-static const struct soc_enum sta32x_preset_eq_enum =
- SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
- 32, sta32x_preset_eq_mode);
-static const struct soc_enum sta32x_limiter_ch1_enum =
- SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
- 3, sta32x_limiter_select);
-static const struct soc_enum sta32x_limiter_ch2_enum =
- SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
- 3, sta32x_limiter_select);
-static const struct soc_enum sta32x_limiter_ch3_enum =
- SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
- 3, sta32x_limiter_select);
-static const struct soc_enum sta32x_limiter1_attack_rate_enum =
- SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT,
- 16, sta32x_limiter_attack_rate);
-static const struct soc_enum sta32x_limiter2_attack_rate_enum =
- SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT,
- 16, sta32x_limiter_attack_rate);
-static const struct soc_enum sta32x_limiter1_release_rate_enum =
- SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT,
- 16, sta32x_limiter_release_rate);
-static const struct soc_enum sta32x_limiter2_release_rate_enum =
- SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT,
- 16, sta32x_limiter_release_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum,
+ STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
+ sta32x_drc_ac);
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum,
+ STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
+ sta32x_auto_eq_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum,
+ STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
+ sta32x_auto_gc_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum,
+ STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
+ sta32x_auto_xo_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum,
+ STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
+ sta32x_preset_eq_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum,
+ STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
+ sta32x_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum,
+ STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
+ sta32x_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum,
+ STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
+ sta32x_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum,
+ STA32X_L1AR, STA32X_LxA_SHIFT,
+ sta32x_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum,
+ STA32X_L2AR, STA32X_LxA_SHIFT,
+ sta32x_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum,
+ STA32X_L1AR, STA32X_LxR_SHIFT,
+ sta32x_limiter_release_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum,
+ STA32X_L2AR, STA32X_LxR_SHIFT,
+ sta32x_limiter_release_rate);
/* byte array controls for setting biquad, mixer, scaling coefficients;
* for biquads all five coefficients need to be set in one go,
@@ -331,7 +331,7 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
static int sta32x_cache_sync(struct snd_soc_codec *codec)
{
- struct sta32x_priv *sta32x = codec->control_data;
+ struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
unsigned int mute;
int rc;
@@ -434,7 +434,7 @@ SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0,
SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum),
SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum),
SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
-SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
+SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum),
/* depending on mode, the attack/release thresholds have
* two different enum definitions; provide both
@@ -872,16 +872,6 @@ static int sta32x_probe(struct snd_soc_codec *codec)
return ret;
}
- /* Tell ASoC what kind of I/O to use to read the registers. ASoC will
- * then do the I2C transactions itself.
- */
- codec->control_data = sta32x->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret);
- goto err;
- }
-
/* Chip documentation explicitly requires that the reset values
* of reserved register bits are left untouched.
* Write the register default value to cache for reserved registers,
@@ -946,10 +936,6 @@ static int sta32x_probe(struct snd_soc_codec *codec)
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
return 0;
-
-err:
- regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
- return ret;
}
static int sta32x_remove(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index 40c07be9b581..a40c4b0196a3 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -141,7 +141,7 @@ static const char *pwm_mode_text[] = { "Binary", "Headphone", "Ternary",
static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -9150, 50, 0);
static const DECLARE_TLV_DB_SCALE(master_vol_tlv, -12750, 50, 0);
-static const SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text);
+static SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text);
static const struct snd_kcontrol_new sta529_snd_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", STA529_LVOL, STA529_RVOL, 0,
@@ -193,8 +193,7 @@ static int sta529_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
int pdata, play_freq_val, record_freq_val;
int bclk_to_fs_ratio;
@@ -322,16 +321,6 @@ static struct snd_soc_dai_driver sta529_dai = {
static int sta529_probe(struct snd_soc_codec *codec)
{
- struct sta529 *sta529 = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- codec->control_data = sta529->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index a5455c1aea42..53b810d23fea 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -62,25 +62,25 @@ static const char *stac9766_boost1[] = {"0dB", "10dB"};
static const char *stac9766_boost2[] = {"0dB", "20dB"};
static const char *stac9766_stereo_mic[] = {"Off", "On"};
-static const struct soc_enum stac9766_record_enum =
- SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, stac9766_record_mux);
-static const struct soc_enum stac9766_mono_enum =
- SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 9, 2, stac9766_mono_mux);
-static const struct soc_enum stac9766_mic_enum =
- SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, stac9766_mic_mux);
-static const struct soc_enum stac9766_SPDIF_enum =
- SOC_ENUM_SINGLE(AC97_STAC_DA_CONTROL, 1, 2, stac9766_SPDIF_mux);
-static const struct soc_enum stac9766_popbypass_enum =
- SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, stac9766_popbypass_mux);
-static const struct soc_enum stac9766_record_all_enum =
- SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 12, 2,
- stac9766_record_all_mux);
-static const struct soc_enum stac9766_boost1_enum =
- SOC_ENUM_SINGLE(AC97_MIC, 6, 2, stac9766_boost1); /* 0/10dB */
-static const struct soc_enum stac9766_boost2_enum =
- SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 2, 2, stac9766_boost2); /* 0/20dB */
-static const struct soc_enum stac9766_stereo_mic_enum =
- SOC_ENUM_SINGLE(AC97_STAC_STEREO_MIC, 2, 1, stac9766_stereo_mic);
+static SOC_ENUM_DOUBLE_DECL(stac9766_record_enum,
+ AC97_REC_SEL, 8, 0, stac9766_record_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_mono_enum,
+ AC97_GENERAL_PURPOSE, 9, stac9766_mono_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_mic_enum,
+ AC97_GENERAL_PURPOSE, 8, stac9766_mic_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_SPDIF_enum,
+ AC97_STAC_DA_CONTROL, 1, stac9766_SPDIF_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_popbypass_enum,
+ AC97_GENERAL_PURPOSE, 15, stac9766_popbypass_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_record_all_enum,
+ AC97_STAC_ANALOG_SPECIAL, 12,
+ stac9766_record_all_mux);
+static SOC_ENUM_SINGLE_DECL(stac9766_boost1_enum,
+ AC97_MIC, 6, stac9766_boost1); /* 0/10dB */
+static SOC_ENUM_SINGLE_DECL(stac9766_boost2_enum,
+ AC97_STAC_ANALOG_SPECIAL, 2, stac9766_boost2); /* 0/20dB */
+static SOC_ENUM_SINGLE_DECL(stac9766_stereo_mic_enum,
+ AC97_STAC_STEREO_MIC, 2, stac9766_stereo_mic);
static const DECLARE_TLV_DB_LINEAR(master_tlv, -4600, 0);
static const DECLARE_TLV_DB_LINEAR(record_tlv, 0, 2250);
diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c
new file mode 100644
index 000000000000..20fc46092c2c
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic23-i2c.c
@@ -0,0 +1,59 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver I2C interface
+ *
+ * Author: Arun KS, <arunks@mistralsolutions.com>
+ * Copyright: (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "tlv320aic23.h"
+
+static int tlv320aic23_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *i2c_id)
+{
+ struct regmap *regmap;
+
+ if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EINVAL;
+
+ regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap);
+ return tlv320aic23_probe(&i2c->dev, regmap);
+}
+
+static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
+{
+ snd_soc_unregister_codec(&i2c->dev);
+ return 0;
+}
+
+static const struct i2c_device_id tlv320aic23_id[] = {
+ {"tlv320aic23", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
+
+static struct i2c_driver tlv320aic23_i2c_driver = {
+ .driver = {
+ .name = "tlv320aic23-codec",
+ },
+ .probe = tlv320aic23_i2c_probe,
+ .remove = __exit_p(tlv320aic23_i2c_remove),
+ .id_table = tlv320aic23_id,
+};
+
+module_i2c_driver(tlv320aic23_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver I2C");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic23-spi.c b/sound/soc/codecs/tlv320aic23-spi.c
new file mode 100644
index 000000000000..3b387e41d75d
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic23-spi.c
@@ -0,0 +1,56 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver SPI interface
+ *
+ * Author: Arun KS, <arunks@mistralsolutions.com>
+ * Copyright: (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by Richard Purdie
+ *
+ * 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/regmap.h>
+#include <linux/spi/spi.h>
+#include <sound/soc.h>
+
+#include "tlv320aic23.h"
+
+static int aic23_spi_probe(struct spi_device *spi)
+{
+ int ret;
+ struct regmap *regmap;
+
+ dev_dbg(&spi->dev, "probing tlv320aic23 spi device\n");
+
+ spi->mode = SPI_MODE_0;
+ ret = spi_setup(spi);
+ if (ret < 0)
+ return ret;
+
+ regmap = devm_regmap_init_spi(spi, &tlv320aic23_regmap);
+ return tlv320aic23_probe(&spi->dev, regmap);
+}
+
+static int aic23_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ return 0;
+}
+
+static struct spi_driver aic23_spi = {
+ .driver = {
+ .name = "tlv320aic23",
+ .owner = THIS_MODULE,
+ },
+ .probe = aic23_spi_probe,
+ .remove = aic23_spi_remove,
+};
+
+module_spi_driver(aic23_spi);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver SPI");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 5d430cc56f51..20864ee8793b 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -51,7 +50,7 @@ static const struct reg_default tlv320aic23_reg[] = {
{ 9, 0x0000 },
};
-static const struct regmap_config tlv320aic23_regmap = {
+const struct regmap_config tlv320aic23_regmap = {
.reg_bits = 7,
.val_bits = 9,
@@ -60,20 +59,21 @@ static const struct regmap_config tlv320aic23_regmap = {
.num_reg_defaults = ARRAY_SIZE(tlv320aic23_reg),
.cache_type = REGCACHE_RBTREE,
};
+EXPORT_SYMBOL(tlv320aic23_regmap);
static const char *rec_src_text[] = { "Line", "Mic" };
static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"};
-static const struct soc_enum rec_src_enum =
- SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
+static SOC_ENUM_SINGLE_DECL(rec_src_enum,
+ TLV320AIC23_ANLG, 2, rec_src_text);
static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls =
SOC_DAPM_ENUM("Input Select", rec_src_enum);
-static const struct soc_enum tlv320aic23_rec_src =
- SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
-static const struct soc_enum tlv320aic23_deemph =
- SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text);
+static SOC_ENUM_SINGLE_DECL(tlv320aic23_rec_src,
+ TLV320AIC23_ANLG, 2, rec_src_text);
+static SOC_ENUM_SINGLE_DECL(tlv320aic23_deemph,
+ TLV320AIC23_DIGT, 1, deemph_text);
static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0);
static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0);
@@ -400,7 +400,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
/* deactivate */
- if (!codec->active) {
+ if (!snd_soc_codec_is_active(codec)) {
udelay(50);
snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0);
}
@@ -557,16 +557,8 @@ static int tlv320aic23_resume(struct snd_soc_codec *codec)
return 0;
}
-static int tlv320aic23_probe(struct snd_soc_codec *codec)
+static int tlv320aic23_codec_probe(struct snd_soc_codec *codec)
{
- int ret;
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* Reset codec */
snd_soc_write(codec, TLV320AIC23_RESET, 0);
@@ -604,7 +596,7 @@ static int tlv320aic23_remove(struct snd_soc_codec *codec)
}
static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
- .probe = tlv320aic23_probe,
+ .probe = tlv320aic23_codec_probe,
.remove = tlv320aic23_remove,
.suspend = tlv320aic23_suspend,
.resume = tlv320aic23_resume,
@@ -617,56 +609,25 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
.num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon),
};
-/*
- * If the i2c layer weren't so broken, we could pass this kind of data
- * around
- */
-static int tlv320aic23_codec_probe(struct i2c_client *i2c,
- const struct i2c_device_id *i2c_id)
+int tlv320aic23_probe(struct device *dev, struct regmap *regmap)
{
struct aic23 *aic23;
- int ret;
- if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -EINVAL;
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
- aic23 = devm_kzalloc(&i2c->dev, sizeof(struct aic23), GFP_KERNEL);
+ aic23 = devm_kzalloc(dev, sizeof(struct aic23), GFP_KERNEL);
if (aic23 == NULL)
return -ENOMEM;
- aic23->regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap);
- if (IS_ERR(aic23->regmap))
- return PTR_ERR(aic23->regmap);
+ aic23->regmap = regmap;
- i2c_set_clientdata(i2c, aic23);
+ dev_set_drvdata(dev, aic23);
- ret = snd_soc_register_codec(&i2c->dev,
- &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1);
- return ret;
+ return snd_soc_register_codec(dev, &soc_codec_dev_tlv320aic23,
+ &tlv320aic23_dai, 1);
}
-static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
-{
- snd_soc_unregister_codec(&i2c->dev);
- return 0;
-}
-
-static const struct i2c_device_id tlv320aic23_id[] = {
- {"tlv320aic23", 0},
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
-
-static struct i2c_driver tlv320aic23_i2c_driver = {
- .driver = {
- .name = "tlv320aic23-codec",
- },
- .probe = tlv320aic23_codec_probe,
- .remove = __exit_p(tlv320aic23_i2c_remove),
- .id_table = tlv320aic23_id,
-};
-
-module_i2c_driver(tlv320aic23_i2c_driver);
+EXPORT_SYMBOL(tlv320aic23_probe);
MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h
index e804120bd3da..3a7235a04a89 100644
--- a/sound/soc/codecs/tlv320aic23.h
+++ b/sound/soc/codecs/tlv320aic23.h
@@ -12,6 +12,12 @@
#ifndef _TLV320AIC23_H
#define _TLV320AIC23_H
+struct device;
+struct regmap_config;
+
+extern const struct regmap_config tlv320aic23_regmap;
+int tlv320aic23_probe(struct device *dev, struct regmap *regmap);
+
/* Codec TLV320AIC23 */
#define TLV320AIC23_LINVOL 0x00
#define TLV320AIC23_RINVOL 0x01
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 94a658fa6d97..43069de3d56a 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -238,8 +238,9 @@ static struct snd_soc_dai_driver aic26_dai = {
* ALSA controls
*/
static const char *aic26_capture_src_text[] = {"Mic", "Aux"};
-static const struct soc_enum aic26_capture_src_enum =
- SOC_ENUM_SINGLE(AIC26_REG_AUDIO_CTRL1, 12, 2, aic26_capture_src_text);
+static SOC_ENUM_SINGLE_DECL(aic26_capture_src_enum,
+ AIC26_REG_AUDIO_CTRL1, 12,
+ aic26_capture_src_text);
static const struct snd_kcontrol_new aic26_snd_controls[] = {
/* Output */
@@ -295,8 +296,6 @@ static int aic26_probe(struct snd_soc_codec *codec)
struct aic26 *aic26 = dev_get_drvdata(codec->dev);
int ret, reg;
- snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
-
aic26->codec = codec;
/* Reset the codec to power on defaults */
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
new file mode 100644
index 000000000000..fa158cfe9b32
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -0,0 +1,1280 @@
+/*
+ * ALSA SoC TLV320AIC31XX codec driver
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * Author: Jyri Sarha <jsarha@ti.com>
+ *
+ * Based on ground work by: Ajit Kulkarni <x0175765@ti.com>
+ *
+ * This package 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 PACKAGE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * The TLV320AIC31xx series of audio codec is a low-power, highly integrated
+ * high performance codec which provides a stereo DAC, a mono ADC,
+ * and mono/stereo Class-D speaker driver.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <dt-bindings/sound/tlv320aic31xx-micbias.h>
+
+#include "tlv320aic31xx.h"
+
+static const struct reg_default aic31xx_reg_defaults[] = {
+ { AIC31XX_CLKMUX, 0x00 },
+ { AIC31XX_PLLPR, 0x11 },
+ { AIC31XX_PLLJ, 0x04 },
+ { AIC31XX_PLLDMSB, 0x00 },
+ { AIC31XX_PLLDLSB, 0x00 },
+ { AIC31XX_NDAC, 0x01 },
+ { AIC31XX_MDAC, 0x01 },
+ { AIC31XX_DOSRMSB, 0x00 },
+ { AIC31XX_DOSRLSB, 0x80 },
+ { AIC31XX_NADC, 0x01 },
+ { AIC31XX_MADC, 0x01 },
+ { AIC31XX_AOSR, 0x80 },
+ { AIC31XX_IFACE1, 0x00 },
+ { AIC31XX_DATA_OFFSET, 0x00 },
+ { AIC31XX_IFACE2, 0x00 },
+ { AIC31XX_BCLKN, 0x01 },
+ { AIC31XX_DACSETUP, 0x14 },
+ { AIC31XX_DACMUTE, 0x0c },
+ { AIC31XX_LDACVOL, 0x00 },
+ { AIC31XX_RDACVOL, 0x00 },
+ { AIC31XX_ADCSETUP, 0x00 },
+ { AIC31XX_ADCFGA, 0x80 },
+ { AIC31XX_ADCVOL, 0x00 },
+ { AIC31XX_HPDRIVER, 0x04 },
+ { AIC31XX_SPKAMP, 0x06 },
+ { AIC31XX_DACMIXERROUTE, 0x00 },
+ { AIC31XX_LANALOGHPL, 0x7f },
+ { AIC31XX_RANALOGHPR, 0x7f },
+ { AIC31XX_LANALOGSPL, 0x7f },
+ { AIC31XX_RANALOGSPR, 0x7f },
+ { AIC31XX_HPLGAIN, 0x02 },
+ { AIC31XX_HPRGAIN, 0x02 },
+ { AIC31XX_SPLGAIN, 0x00 },
+ { AIC31XX_SPRGAIN, 0x00 },
+ { AIC31XX_MICBIAS, 0x00 },
+ { AIC31XX_MICPGA, 0x80 },
+ { AIC31XX_MICPGAPI, 0x00 },
+ { AIC31XX_MICPGAMI, 0x00 },
+};
+
+static bool aic31xx_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AIC31XX_PAGECTL: /* regmap implementation requires this */
+ case AIC31XX_RESET: /* always clears after write */
+ case AIC31XX_OT_FLAG:
+ case AIC31XX_ADCFLAG:
+ case AIC31XX_DACFLAG1:
+ case AIC31XX_DACFLAG2:
+ case AIC31XX_OFFLAG: /* Sticky interrupt flags */
+ case AIC31XX_INTRDACFLAG: /* Sticky interrupt flags */
+ case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
+ case AIC31XX_INTRDACFLAG2:
+ case AIC31XX_INTRADCFLAG2:
+ return true;
+ }
+ return false;
+}
+
+static bool aic31xx_writeable(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AIC31XX_OT_FLAG:
+ case AIC31XX_ADCFLAG:
+ case AIC31XX_DACFLAG1:
+ case AIC31XX_DACFLAG2:
+ case AIC31XX_OFFLAG: /* Sticky interrupt flags */
+ case AIC31XX_INTRDACFLAG: /* Sticky interrupt flags */
+ case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
+ case AIC31XX_INTRDACFLAG2:
+ case AIC31XX_INTRADCFLAG2:
+ return false;
+ }
+ return true;
+}
+
+static const struct regmap_range_cfg aic31xx_ranges[] = {
+ {
+ .range_min = 0,
+ .range_max = 12 * 128,
+ .selector_reg = AIC31XX_PAGECTL,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 128,
+ },
+};
+
+static const struct regmap_config aic31xx_i2c_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .writeable_reg = aic31xx_writeable,
+ .volatile_reg = aic31xx_volatile,
+ .reg_defaults = aic31xx_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(aic31xx_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .ranges = aic31xx_ranges,
+ .num_ranges = ARRAY_SIZE(aic31xx_ranges),
+ .max_register = 12 * 128,
+};
+
+#define AIC31XX_NUM_SUPPLIES 6
+static const char * const aic31xx_supply_names[AIC31XX_NUM_SUPPLIES] = {
+ "HPVDD",
+ "SPRVDD",
+ "SPLVDD",
+ "AVDD",
+ "IOVDD",
+ "DVDD",
+};
+
+struct aic31xx_disable_nb {
+ struct notifier_block nb;
+ struct aic31xx_priv *aic31xx;
+};
+
+struct aic31xx_priv {
+ struct snd_soc_codec *codec;
+ u8 i2c_regs_status;
+ struct device *dev;
+ struct regmap *regmap;
+ struct aic31xx_pdata pdata;
+ struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
+ struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
+ unsigned int sysclk;
+ int rate_div_line;
+};
+
+struct aic31xx_rate_divs {
+ u32 mclk;
+ u32 rate;
+ u8 p_val;
+ u8 pll_j;
+ u16 pll_d;
+ u16 dosr;
+ u8 ndac;
+ u8 mdac;
+ u8 aosr;
+ u8 nadc;
+ u8 madc;
+};
+
+/* ADC dividers can be disabled by cofiguring them to 0 */
+static const struct aic31xx_rate_divs aic31xx_divs[] = {
+ /* mclk rate pll: p j d dosr ndac mdac aors nadc madc */
+ /* 8k rate */
+ {12000000, 8000, 1, 8, 1920, 128, 48, 2, 128, 48, 2},
+ {24000000, 8000, 2, 8, 1920, 128, 48, 2, 128, 48, 2},
+ {25000000, 8000, 2, 7, 8643, 128, 48, 2, 128, 48, 2},
+ /* 11.025k rate */
+ {12000000, 11025, 1, 7, 5264, 128, 32, 2, 128, 32, 2},
+ {24000000, 11025, 2, 7, 5264, 128, 32, 2, 128, 32, 2},
+ {25000000, 11025, 2, 7, 2253, 128, 32, 2, 128, 32, 2},
+ /* 16k rate */
+ {12000000, 16000, 1, 8, 1920, 128, 24, 2, 128, 24, 2},
+ {24000000, 16000, 2, 8, 1920, 128, 24, 2, 128, 24, 2},
+ {25000000, 16000, 2, 7, 8643, 128, 24, 2, 128, 24, 2},
+ /* 22.05k rate */
+ {12000000, 22050, 1, 7, 5264, 128, 16, 2, 128, 16, 2},
+ {24000000, 22050, 2, 7, 5264, 128, 16, 2, 128, 16, 2},
+ {25000000, 22050, 2, 7, 2253, 128, 16, 2, 128, 16, 2},
+ /* 32k rate */
+ {12000000, 32000, 1, 8, 1920, 128, 12, 2, 128, 12, 2},
+ {24000000, 32000, 2, 8, 1920, 128, 12, 2, 128, 12, 2},
+ {25000000, 32000, 2, 7, 8643, 128, 12, 2, 128, 12, 2},
+ /* 44.1k rate */
+ {12000000, 44100, 1, 7, 5264, 128, 8, 2, 128, 8, 2},
+ {24000000, 44100, 2, 7, 5264, 128, 8, 2, 128, 8, 2},
+ {25000000, 44100, 2, 7, 2253, 128, 8, 2, 128, 8, 2},
+ /* 48k rate */
+ {12000000, 48000, 1, 8, 1920, 128, 8, 2, 128, 8, 2},
+ {24000000, 48000, 2, 8, 1920, 128, 8, 2, 128, 8, 2},
+ {25000000, 48000, 2, 7, 8643, 128, 8, 2, 128, 8, 2},
+ /* 88.2k rate */
+ {12000000, 88200, 1, 7, 5264, 64, 8, 2, 64, 8, 2},
+ {24000000, 88200, 2, 7, 5264, 64, 8, 2, 64, 8, 2},
+ {25000000, 88200, 2, 7, 2253, 64, 8, 2, 64, 8, 2},
+ /* 96k rate */
+ {12000000, 96000, 1, 8, 1920, 64, 8, 2, 64, 8, 2},
+ {24000000, 96000, 2, 8, 1920, 64, 8, 2, 64, 8, 2},
+ {25000000, 96000, 2, 7, 8643, 64, 8, 2, 64, 8, 2},
+ /* 176.4k rate */
+ {12000000, 176400, 1, 7, 5264, 32, 8, 2, 32, 8, 2},
+ {24000000, 176400, 2, 7, 5264, 32, 8, 2, 32, 8, 2},
+ {25000000, 176400, 2, 7, 2253, 32, 8, 2, 32, 8, 2},
+ /* 192k rate */
+ {12000000, 192000, 1, 8, 1920, 32, 8, 2, 32, 8, 2},
+ {24000000, 192000, 2, 8, 1920, 32, 8, 2, 32, 8, 2},
+ {25000000, 192000, 2, 7, 8643, 32, 8, 2, 32, 8, 2},
+};
+
+static const char * const ldac_in_text[] = {
+ "Off", "Left Data", "Right Data", "Mono"
+};
+
+static const char * const rdac_in_text[] = {
+ "Off", "Right Data", "Left Data", "Mono"
+};
+
+static SOC_ENUM_SINGLE_DECL(ldac_in_enum, AIC31XX_DACSETUP, 4, ldac_in_text);
+
+static SOC_ENUM_SINGLE_DECL(rdac_in_enum, AIC31XX_DACSETUP, 2, rdac_in_text);
+
+static const char * const mic_select_text[] = {
+ "Off", "FFR 10 Ohm", "FFR 20 Ohm", "FFR 40 Ohm"
+};
+
+static const
+SOC_ENUM_SINGLE_DECL(mic1lp_p_enum, AIC31XX_MICPGAPI, 6, mic_select_text);
+static const
+SOC_ENUM_SINGLE_DECL(mic1rp_p_enum, AIC31XX_MICPGAPI, 4, mic_select_text);
+static const
+SOC_ENUM_SINGLE_DECL(mic1lm_p_enum, AIC31XX_MICPGAPI, 2, mic_select_text);
+
+static const
+SOC_ENUM_SINGLE_DECL(cm_m_enum, AIC31XX_MICPGAMI, 6, mic_select_text);
+static const
+SOC_ENUM_SINGLE_DECL(mic1lm_m_enum, AIC31XX_MICPGAMI, 4, mic_select_text);
+
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(adc_fgain_tlv, 0, 10, 0);
+static const DECLARE_TLV_DB_SCALE(adc_cgain_tlv, -2000, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, 0, 50, 0);
+static const DECLARE_TLV_DB_SCALE(hp_drv_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(class_D_drv_tlv, 600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(sp_vol_tlv, -6350, 50, 0);
+
+/*
+ * controls to be exported to the user space
+ */
+static const struct snd_kcontrol_new aic31xx_snd_controls[] = {
+ SOC_DOUBLE_R_S_TLV("DAC Playback Volume", AIC31XX_LDACVOL,
+ AIC31XX_RDACVOL, 0, -127, 48, 7, 0, dac_vol_tlv),
+
+ SOC_SINGLE_TLV("ADC Fine Capture Volume", AIC31XX_ADCFGA, 4, 4, 1,
+ adc_fgain_tlv),
+
+ SOC_SINGLE("ADC Capture Switch", AIC31XX_ADCFGA, 7, 1, 1),
+ SOC_DOUBLE_R_S_TLV("ADC Capture Volume", AIC31XX_ADCVOL, AIC31XX_ADCVOL,
+ 0, -24, 40, 6, 0, adc_cgain_tlv),
+
+ SOC_SINGLE_TLV("Mic PGA Capture Volume", AIC31XX_MICPGA, 0,
+ 119, 0, mic_pga_tlv),
+
+ SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN,
+ AIC31XX_HPRGAIN, 2, 1, 0),
+ SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN,
+ AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv),
+
+ SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL,
+ AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv),
+};
+
+static const struct snd_kcontrol_new aic311x_snd_controls[] = {
+ SOC_DOUBLE_R("Speaker Driver Playback Switch", AIC31XX_SPLGAIN,
+ AIC31XX_SPRGAIN, 2, 1, 0),
+ SOC_DOUBLE_R_TLV("Speaker Driver Playback Volume", AIC31XX_SPLGAIN,
+ AIC31XX_SPRGAIN, 3, 3, 0, class_D_drv_tlv),
+
+ SOC_DOUBLE_R_TLV("Speaker Analog Playback Volume", AIC31XX_LANALOGSPL,
+ AIC31XX_RANALOGSPR, 0, 0x7F, 1, sp_vol_tlv),
+};
+
+static const struct snd_kcontrol_new aic310x_snd_controls[] = {
+ SOC_SINGLE("Speaker Driver Playback Switch", AIC31XX_SPLGAIN,
+ 2, 1, 0),
+ SOC_SINGLE_TLV("Speaker Driver Playback Volume", AIC31XX_SPLGAIN,
+ 3, 3, 0, class_D_drv_tlv),
+
+ SOC_SINGLE_TLV("Speaker Analog Playback Volume", AIC31XX_LANALOGSPL,
+ 0, 0x7F, 1, sp_vol_tlv),
+};
+
+static const struct snd_kcontrol_new ldac_in_control =
+ SOC_DAPM_ENUM("DAC Left Input", ldac_in_enum);
+
+static const struct snd_kcontrol_new rdac_in_control =
+ SOC_DAPM_ENUM("DAC Right Input", rdac_in_enum);
+
+static int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
+ unsigned int mask, unsigned int wbits, int sleep,
+ int count)
+{
+ unsigned int bits;
+ int counter = count;
+ int ret = regmap_read(aic31xx->regmap, reg, &bits);
+ while ((bits & mask) != wbits && counter && !ret) {
+ usleep_range(sleep, sleep * 2);
+ ret = regmap_read(aic31xx->regmap, reg, &bits);
+ counter--;
+ }
+ if ((bits & mask) != wbits) {
+ dev_err(aic31xx->dev,
+ "%s: Failed! 0x%x was 0x%x expected 0x%x (%d, 0x%x, %d us)\n",
+ __func__, reg, bits, wbits, ret, mask,
+ (count - counter) * sleep);
+ ret = -1;
+ }
+ return ret;
+}
+
+#define WIDGET_BIT(reg, shift) (((shift) << 8) | (reg))
+
+static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(w->codec);
+ unsigned int reg = AIC31XX_DACFLAG1;
+ unsigned int mask;
+
+ switch (WIDGET_BIT(w->reg, w->shift)) {
+ case WIDGET_BIT(AIC31XX_DACSETUP, 7):
+ mask = AIC31XX_LDACPWRSTATUS_MASK;
+ break;
+ case WIDGET_BIT(AIC31XX_DACSETUP, 6):
+ mask = AIC31XX_RDACPWRSTATUS_MASK;
+ break;
+ case WIDGET_BIT(AIC31XX_HPDRIVER, 7):
+ mask = AIC31XX_HPLDRVPWRSTATUS_MASK;
+ break;
+ case WIDGET_BIT(AIC31XX_HPDRIVER, 6):
+ mask = AIC31XX_HPRDRVPWRSTATUS_MASK;
+ break;
+ case WIDGET_BIT(AIC31XX_SPKAMP, 7):
+ mask = AIC31XX_SPLDRVPWRSTATUS_MASK;
+ break;
+ case WIDGET_BIT(AIC31XX_SPKAMP, 6):
+ mask = AIC31XX_SPRDRVPWRSTATUS_MASK;
+ break;
+ case WIDGET_BIT(AIC31XX_ADCSETUP, 7):
+ mask = AIC31XX_ADCPWRSTATUS_MASK;
+ reg = AIC31XX_ADCFLAG;
+ break;
+ default:
+ dev_err(w->codec->dev, "Unknown widget '%s' calling %s/n",
+ w->name, __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ return aic31xx_wait_bits(aic31xx, reg, mask, mask, 5000, 100);
+ case SND_SOC_DAPM_POST_PMD:
+ return aic31xx_wait_bits(aic31xx, reg, mask, 0, 5000, 100);
+ default:
+ dev_dbg(w->codec->dev,
+ "Unhandled dapm widget event %d from %s\n",
+ event, w->name);
+ }
+ return 0;
+}
+
+static const struct snd_kcontrol_new left_output_switches[] = {
+ SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0),
+ SOC_DAPM_SINGLE("From MIC1LP", AIC31XX_DACMIXERROUTE, 5, 1, 0),
+ SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_output_switches[] = {
+ SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0),
+ SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new p_term_mic1lp =
+ SOC_DAPM_ENUM("MIC1LP P-Terminal", mic1lp_p_enum);
+
+static const struct snd_kcontrol_new p_term_mic1rp =
+ SOC_DAPM_ENUM("MIC1RP P-Terminal", mic1rp_p_enum);
+
+static const struct snd_kcontrol_new p_term_mic1lm =
+ SOC_DAPM_ENUM("MIC1LM P-Terminal", mic1lm_p_enum);
+
+static const struct snd_kcontrol_new m_term_mic1lm =
+ SOC_DAPM_ENUM("MIC1LM M-Terminal", mic1lm_m_enum);
+
+static const struct snd_kcontrol_new aic31xx_dapm_hpl_switch =
+ SOC_DAPM_SINGLE("Switch", AIC31XX_LANALOGHPL, 7, 1, 0);
+
+static const struct snd_kcontrol_new aic31xx_dapm_hpr_switch =
+ SOC_DAPM_SINGLE("Switch", AIC31XX_RANALOGHPR, 7, 1, 0);
+
+static const struct snd_kcontrol_new aic31xx_dapm_spl_switch =
+ SOC_DAPM_SINGLE("Switch", AIC31XX_LANALOGSPL, 7, 1, 0);
+
+static const struct snd_kcontrol_new aic31xx_dapm_spr_switch =
+ SOC_DAPM_SINGLE("Switch", AIC31XX_RANALOGSPR, 7, 1, 0);
+
+static int mic_bias_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* change mic bias voltage to user defined */
+ snd_soc_update_bits(codec, AIC31XX_MICBIAS,
+ AIC31XX_MICBIAS_MASK,
+ aic31xx->pdata.micbias_vg <<
+ AIC31XX_MICBIAS_SHIFT);
+ dev_dbg(codec->dev, "%s: turned on\n", __func__);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* turn mic bias off */
+ snd_soc_update_bits(codec, AIC31XX_MICBIAS,
+ AIC31XX_MICBIAS_MASK, 0);
+ dev_dbg(codec->dev, "%s: turned off\n", __func__);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_MUX("DAC Left Input",
+ SND_SOC_NOPM, 0, 0, &ldac_in_control),
+ SND_SOC_DAPM_MUX("DAC Right Input",
+ SND_SOC_NOPM, 0, 0, &rdac_in_control),
+ /* DACs */
+ SND_SOC_DAPM_DAC_E("DAC Left", "Left Playback",
+ AIC31XX_DACSETUP, 7, 0, aic31xx_dapm_power_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("DAC Right", "Right Playback",
+ AIC31XX_DACSETUP, 6, 0, aic31xx_dapm_power_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* Output Mixers */
+ SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
+ left_output_switches,
+ ARRAY_SIZE(left_output_switches)),
+ SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
+ right_output_switches,
+ ARRAY_SIZE(right_output_switches)),
+
+ SND_SOC_DAPM_SWITCH("HP Left", SND_SOC_NOPM, 0, 0,
+ &aic31xx_dapm_hpl_switch),
+ SND_SOC_DAPM_SWITCH("HP Right", SND_SOC_NOPM, 0, 0,
+ &aic31xx_dapm_hpr_switch),
+
+ /* Output drivers */
+ SND_SOC_DAPM_OUT_DRV_E("HPL Driver", AIC31XX_HPDRIVER, 7, 0,
+ NULL, 0, aic31xx_dapm_power_event,
+ SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_OUT_DRV_E("HPR Driver", AIC31XX_HPDRIVER, 6, 0,
+ NULL, 0, aic31xx_dapm_power_event,
+ SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+
+ /* ADC */
+ SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0,
+ aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* Input Selection to MIC_PGA */
+ SND_SOC_DAPM_MUX("MIC1LP P-Terminal", SND_SOC_NOPM, 0, 0,
+ &p_term_mic1lp),
+ SND_SOC_DAPM_MUX("MIC1RP P-Terminal", SND_SOC_NOPM, 0, 0,
+ &p_term_mic1rp),
+ SND_SOC_DAPM_MUX("MIC1LM P-Terminal", SND_SOC_NOPM, 0, 0,
+ &p_term_mic1lm),
+
+ SND_SOC_DAPM_MUX("MIC1LM M-Terminal", SND_SOC_NOPM, 0, 0,
+ &m_term_mic1lm),
+ /* Enabling & Disabling MIC Gain Ctl */
+ SND_SOC_DAPM_PGA("MIC_GAIN_CTL", AIC31XX_MICPGA,
+ 7, 1, NULL, 0),
+
+ /* Mic Bias */
+ SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, mic_bias_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ /* Outputs */
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+
+ /* Inputs */
+ SND_SOC_DAPM_INPUT("MIC1LP"),
+ SND_SOC_DAPM_INPUT("MIC1RP"),
+ SND_SOC_DAPM_INPUT("MIC1LM"),
+};
+
+static const struct snd_soc_dapm_widget aic311x_dapm_widgets[] = {
+ /* AIC3111 and AIC3110 have stereo class-D amplifier */
+ SND_SOC_DAPM_OUT_DRV_E("SPL ClassD", AIC31XX_SPKAMP, 7, 0, NULL, 0,
+ aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUT_DRV_E("SPR ClassD", AIC31XX_SPKAMP, 6, 0, NULL, 0,
+ aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SWITCH("Speaker Left", SND_SOC_NOPM, 0, 0,
+ &aic31xx_dapm_spl_switch),
+ SND_SOC_DAPM_SWITCH("Speaker Right", SND_SOC_NOPM, 0, 0,
+ &aic31xx_dapm_spr_switch),
+ SND_SOC_DAPM_OUTPUT("SPL"),
+ SND_SOC_DAPM_OUTPUT("SPR"),
+};
+
+/* AIC3100 and AIC3120 have only mono class-D amplifier */
+static const struct snd_soc_dapm_widget aic310x_dapm_widgets[] = {
+ SND_SOC_DAPM_OUT_DRV_E("SPK ClassD", AIC31XX_SPKAMP, 7, 0, NULL, 0,
+ aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SWITCH("Speaker", SND_SOC_NOPM, 0, 0,
+ &aic31xx_dapm_spl_switch),
+ SND_SOC_DAPM_OUTPUT("SPK"),
+};
+
+static const struct snd_soc_dapm_route
+aic31xx_audio_map[] = {
+ /* DAC Input Routing */
+ {"DAC Left Input", "Left Data", "DAC IN"},
+ {"DAC Left Input", "Right Data", "DAC IN"},
+ {"DAC Left Input", "Mono", "DAC IN"},
+ {"DAC Right Input", "Left Data", "DAC IN"},
+ {"DAC Right Input", "Right Data", "DAC IN"},
+ {"DAC Right Input", "Mono", "DAC IN"},
+ {"DAC Left", NULL, "DAC Left Input"},
+ {"DAC Right", NULL, "DAC Right Input"},
+
+ /* Mic input */
+ {"MIC1LP P-Terminal", "FFR 10 Ohm", "MIC1LP"},
+ {"MIC1LP P-Terminal", "FFR 20 Ohm", "MIC1LP"},
+ {"MIC1LP P-Terminal", "FFR 40 Ohm", "MIC1LP"},
+ {"MIC1RP P-Terminal", "FFR 10 Ohm", "MIC1RP"},
+ {"MIC1RP P-Terminal", "FFR 20 Ohm", "MIC1RP"},
+ {"MIC1RP P-Terminal", "FFR 40 Ohm", "MIC1RP"},
+ {"MIC1LM P-Terminal", "FFR 10 Ohm", "MIC1LM"},
+ {"MIC1LM P-Terminal", "FFR 20 Ohm", "MIC1LM"},
+ {"MIC1LM P-Terminal", "FFR 40 Ohm", "MIC1LM"},
+
+ {"MIC1LM M-Terminal", "FFR 10 Ohm", "MIC1LM"},
+ {"MIC1LM M-Terminal", "FFR 20 Ohm", "MIC1LM"},
+ {"MIC1LM M-Terminal", "FFR 40 Ohm", "MIC1LM"},
+
+ {"MIC_GAIN_CTL", NULL, "MIC1LP P-Terminal"},
+ {"MIC_GAIN_CTL", NULL, "MIC1RP P-Terminal"},
+ {"MIC_GAIN_CTL", NULL, "MIC1LM P-Terminal"},
+ {"MIC_GAIN_CTL", NULL, "MIC1LM M-Terminal"},
+
+ {"ADC", NULL, "MIC_GAIN_CTL"},
+
+ /* Left Output */
+ {"Output Left", "From Left DAC", "DAC Left"},
+ {"Output Left", "From MIC1LP", "MIC1LP"},
+ {"Output Left", "From MIC1RP", "MIC1RP"},
+
+ /* Right Output */
+ {"Output Right", "From Right DAC", "DAC Right"},
+ {"Output Right", "From MIC1RP", "MIC1RP"},
+
+ /* HPL path */
+ {"HP Left", "Switch", "Output Left"},
+ {"HPL Driver", NULL, "HP Left"},
+ {"HPL", NULL, "HPL Driver"},
+
+ /* HPR path */
+ {"HP Right", "Switch", "Output Right"},
+ {"HPR Driver", NULL, "HP Right"},
+ {"HPR", NULL, "HPR Driver"},
+};
+
+static const struct snd_soc_dapm_route
+aic311x_audio_map[] = {
+ /* SP L path */
+ {"Speaker Left", "Switch", "Output Left"},
+ {"SPL ClassD", NULL, "Speaker Left"},
+ {"SPL", NULL, "SPL ClassD"},
+
+ /* SP R path */
+ {"Speaker Right", "Switch", "Output Right"},
+ {"SPR ClassD", NULL, "Speaker Right"},
+ {"SPR", NULL, "SPR ClassD"},
+};
+
+static const struct snd_soc_dapm_route
+aic310x_audio_map[] = {
+ /* SP L path */
+ {"Speaker", "Switch", "Output Left"},
+ {"SPK ClassD", NULL, "Speaker"},
+ {"SPK", NULL, "SPK ClassD"},
+};
+
+static int aic31xx_add_controls(struct snd_soc_codec *codec)
+{
+ int ret = 0;
+ struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+
+ if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT)
+ ret = snd_soc_add_codec_controls(
+ codec, aic311x_snd_controls,
+ ARRAY_SIZE(aic311x_snd_controls));
+ else
+ ret = snd_soc_add_codec_controls(
+ codec, aic310x_snd_controls,
+ ARRAY_SIZE(aic310x_snd_controls));
+
+ return ret;
+}
+
+static int aic31xx_add_widgets(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) {
+ ret = snd_soc_dapm_new_controls(
+ dapm, aic311x_dapm_widgets,
+ ARRAY_SIZE(aic311x_dapm_widgets));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, aic311x_audio_map,
+ ARRAY_SIZE(aic311x_audio_map));
+ if (ret)
+ return ret;
+ } else {
+ ret = snd_soc_dapm_new_controls(
+ dapm, aic310x_dapm_widgets,
+ ARRAY_SIZE(aic310x_dapm_widgets));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, aic310x_audio_map,
+ ARRAY_SIZE(aic310x_audio_map));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int aic31xx_setup_pll(struct snd_soc_codec *codec,
+ struct snd_pcm_hw_params *params)
+{
+ struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+ int bclk_n = 0;
+ int i;
+
+ /* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */
+ snd_soc_update_bits(codec, AIC31XX_CLKMUX,
+ AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL);
+ snd_soc_update_bits(codec, AIC31XX_IFACE2,
+ AIC31XX_BDIVCLK_MASK, AIC31XX_DAC2BCLK);
+
+ for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) {
+ if (aic31xx_divs[i].rate == params_rate(params) &&
+ aic31xx_divs[i].mclk == aic31xx->sysclk)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(aic31xx_divs)) {
+ dev_err(codec->dev, "%s: Sampling rate %u not supported\n",
+ __func__, params_rate(params));
+ return -EINVAL;
+ }
+
+ /* PLL configuration */
+ snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
+ (aic31xx_divs[i].p_val << 4) | 0x01);
+ snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j);
+
+ snd_soc_write(codec, AIC31XX_PLLDMSB,
+ aic31xx_divs[i].pll_d >> 8);
+ snd_soc_write(codec, AIC31XX_PLLDLSB,
+ aic31xx_divs[i].pll_d & 0xff);
+
+ /* DAC dividers configuration */
+ snd_soc_update_bits(codec, AIC31XX_NDAC, AIC31XX_PLL_MASK,
+ aic31xx_divs[i].ndac);
+ snd_soc_update_bits(codec, AIC31XX_MDAC, AIC31XX_PLL_MASK,
+ aic31xx_divs[i].mdac);
+
+ snd_soc_write(codec, AIC31XX_DOSRMSB, aic31xx_divs[i].dosr >> 8);
+ snd_soc_write(codec, AIC31XX_DOSRLSB, aic31xx_divs[i].dosr & 0xff);
+
+ /* ADC dividers configuration. Write reset value 1 if not used. */
+ snd_soc_update_bits(codec, AIC31XX_NADC, AIC31XX_PLL_MASK,
+ aic31xx_divs[i].nadc ? aic31xx_divs[i].nadc : 1);
+ snd_soc_update_bits(codec, AIC31XX_MADC, AIC31XX_PLL_MASK,
+ aic31xx_divs[i].madc ? aic31xx_divs[i].madc : 1);
+
+ snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr);
+
+ /* Bit clock divider configuration. */
+ bclk_n = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac)
+ / snd_soc_params_to_frame_size(params);
+ if (bclk_n == 0) {
+ dev_err(codec->dev, "%s: Not enough BLCK bandwidth\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, AIC31XX_BCLKN,
+ AIC31XX_PLL_MASK, bclk_n);
+
+ aic31xx->rate_div_line = i;
+
+ dev_dbg(codec->dev,
+ "pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n",
+ aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d,
+ aic31xx_divs[i].p_val, aic31xx_divs[i].dosr,
+ aic31xx_divs[i].ndac, aic31xx_divs[i].mdac,
+ aic31xx_divs[i].aosr, aic31xx_divs[i].nadc,
+ aic31xx_divs[i].madc, bclk_n);
+
+ return 0;
+}
+
+static int aic31xx_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 data = 0;
+
+ dev_dbg(codec->dev, "## %s: format %d width %d rate %d\n",
+ __func__, params_format(params), params_width(params),
+ params_rate(params));
+
+ switch (params_width(params)) {
+ case 16:
+ break;
+ case 20:
+ data = (AIC31XX_WORD_LEN_20BITS <<
+ AIC31XX_IFACE1_DATALEN_SHIFT);
+ break;
+ case 24:
+ data = (AIC31XX_WORD_LEN_24BITS <<
+ AIC31XX_IFACE1_DATALEN_SHIFT);
+ break;
+ case 32:
+ data = (AIC31XX_WORD_LEN_32BITS <<
+ AIC31XX_IFACE1_DATALEN_SHIFT);
+ break;
+ default:
+ dev_err(codec->dev, "%s: Unsupported format %d\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, AIC31XX_IFACE1,
+ AIC31XX_IFACE1_DATALEN_MASK,
+ data);
+
+ return aic31xx_setup_pll(codec, params);
+}
+
+static int aic31xx_dac_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+
+ if (mute) {
+ snd_soc_update_bits(codec, AIC31XX_DACMUTE,
+ AIC31XX_DACMUTE_MASK,
+ AIC31XX_DACMUTE_MASK);
+ } else {
+ snd_soc_update_bits(codec, AIC31XX_DACMUTE,
+ AIC31XX_DACMUTE_MASK, 0x0);
+ }
+
+ return 0;
+}
+
+static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u8 iface_reg1 = 0;
+ u8 iface_reg3 = 0;
+ u8 dsp_a_val = 0;
+
+ dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt);
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER;
+ break;
+ default:
+ dev_alert(codec->dev, "Invalid DAI master/slave interface\n");
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ dsp_a_val = 0x1;
+ case SND_SOC_DAIFMT_DSP_B:
+ /* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ iface_reg3 |= AIC31XX_BCLKINV_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ default:
+ return -EINVAL;
+ }
+ iface_reg1 |= (AIC31XX_DSP_MODE <<
+ AIC31XX_IFACE1_DATATYPE_SHIFT);
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ iface_reg1 |= (AIC31XX_RIGHT_JUSTIFIED_MODE <<
+ AIC31XX_IFACE1_DATATYPE_SHIFT);
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface_reg1 |= (AIC31XX_LEFT_JUSTIFIED_MODE <<
+ AIC31XX_IFACE1_DATATYPE_SHIFT);
+ break;
+ default:
+ dev_err(codec->dev, "Invalid DAI interface format\n");
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, AIC31XX_IFACE1,
+ AIC31XX_IFACE1_DATATYPE_MASK |
+ AIC31XX_IFACE1_MASTER_MASK,
+ iface_reg1);
+ snd_soc_update_bits(codec, AIC31XX_DATA_OFFSET,
+ AIC31XX_DATA_OFFSET_MASK,
+ dsp_a_val);
+ snd_soc_update_bits(codec, AIC31XX_IFACE2,
+ AIC31XX_BCLKINV_MASK,
+ iface_reg3);
+
+ return 0;
+}
+
+static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+ int i;
+
+ dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n",
+ __func__, clk_id, freq, dir);
+
+ for (i = 0; aic31xx_divs[i].mclk != freq; i++) {
+ if (i == ARRAY_SIZE(aic31xx_divs)) {
+ dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n",
+ __func__, freq);
+ return -EINVAL;
+ }
+ }
+
+ /* set clock on MCLK, BCLK, or GPIO1 as PLL input */
+ snd_soc_update_bits(codec, AIC31XX_CLKMUX, AIC31XX_PLL_CLKIN_MASK,
+ clk_id << AIC31XX_PLL_CLKIN_SHIFT);
+
+ aic31xx->sysclk = freq;
+ return 0;
+}
+
+static int aic31xx_regulator_event(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct aic31xx_disable_nb *disable_nb =
+ container_of(nb, struct aic31xx_disable_nb, nb);
+ struct aic31xx_priv *aic31xx = disable_nb->aic31xx;
+
+ if (event & REGULATOR_EVENT_DISABLE) {
+ /*
+ * Put codec to reset and as at least one of the
+ * supplies was disabled.
+ */
+ if (gpio_is_valid(aic31xx->pdata.gpio_reset))
+ gpio_set_value(aic31xx->pdata.gpio_reset, 0);
+
+ regcache_mark_dirty(aic31xx->regmap);
+ dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__);
+ }
+
+ return 0;
+}
+
+static void aic31xx_clk_on(struct snd_soc_codec *codec)
+{
+ struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+ u8 mask = AIC31XX_PM_MASK;
+ u8 on = AIC31XX_PM_MASK;
+
+ dev_dbg(codec->dev, "codec clock -> on (rate %d)\n",
+ aic31xx_divs[aic31xx->rate_div_line].rate);
+ snd_soc_update_bits(codec, AIC31XX_PLLPR, mask, on);
+ mdelay(10);
+ snd_soc_update_bits(codec, AIC31XX_NDAC, mask, on);
+ snd_soc_update_bits(codec, AIC31XX_MDAC, mask, on);
+ if (aic31xx_divs[aic31xx->rate_div_line].nadc)
+ snd_soc_update_bits(codec, AIC31XX_NADC, mask, on);
+ if (aic31xx_divs[aic31xx->rate_div_line].madc)
+ snd_soc_update_bits(codec, AIC31XX_MADC, mask, on);
+ snd_soc_update_bits(codec, AIC31XX_BCLKN, mask, on);
+}
+
+static void aic31xx_clk_off(struct snd_soc_codec *codec)
+{
+ u8 mask = AIC31XX_PM_MASK;
+ u8 off = 0;
+
+ dev_dbg(codec->dev, "codec clock -> off\n");
+ snd_soc_update_bits(codec, AIC31XX_BCLKN, mask, off);
+ snd_soc_update_bits(codec, AIC31XX_MADC, mask, off);
+ snd_soc_update_bits(codec, AIC31XX_NADC, mask, off);
+ snd_soc_update_bits(codec, AIC31XX_MDAC, mask, off);
+ snd_soc_update_bits(codec, AIC31XX_NDAC, mask, off);
+ snd_soc_update_bits(codec, AIC31XX_PLLPR, mask, off);
+}
+
+static int aic31xx_power_on(struct snd_soc_codec *codec)
+{
+ struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(aic31xx->supplies),
+ aic31xx->supplies);
+ if (ret)
+ return ret;
+
+ if (gpio_is_valid(aic31xx->pdata.gpio_reset)) {
+ gpio_set_value(aic31xx->pdata.gpio_reset, 1);
+ udelay(100);
+ }
+ regcache_cache_only(aic31xx->regmap, false);
+ ret = regcache_sync(aic31xx->regmap);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to restore cache: %d\n", ret);
+ regcache_cache_only(aic31xx->regmap, true);
+ regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
+ aic31xx->supplies);
+ return ret;
+ }
+ return 0;
+}
+
+static int aic31xx_power_off(struct snd_soc_codec *codec)
+{
+ struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ regcache_cache_only(aic31xx->regmap, true);
+ ret = regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
+ aic31xx->supplies);
+
+ return ret;
+}
+
+static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ dev_dbg(codec->dev, "## %s: %d -> %d\n", __func__,
+ codec->dapm.bias_level, level);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+ aic31xx_clk_on(codec);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ switch (codec->dapm.bias_level) {
+ case SND_SOC_BIAS_OFF:
+ aic31xx_power_on(codec);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ aic31xx_clk_off(codec);
+ break;
+ default:
+ BUG();
+ }
+ break;
+ case SND_SOC_BIAS_OFF:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+ aic31xx_power_off(codec);
+ break;
+ }
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
+
+static int aic31xx_suspend(struct snd_soc_codec *codec)
+{
+ aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int aic31xx_resume(struct snd_soc_codec *codec)
+{
+ aic31xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
+}
+
+static int aic31xx_codec_probe(struct snd_soc_codec *codec)
+{
+ int ret = 0;
+ struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+ int i;
+
+ dev_dbg(aic31xx->dev, "## %s\n", __func__);
+
+ aic31xx = snd_soc_codec_get_drvdata(codec);
+
+ aic31xx->codec = codec;
+
+ for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
+ aic31xx->disable_nb[i].nb.notifier_call =
+ aic31xx_regulator_event;
+ aic31xx->disable_nb[i].aic31xx = aic31xx;
+ ret = regulator_register_notifier(aic31xx->supplies[i].consumer,
+ &aic31xx->disable_nb[i].nb);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to request regulator notifier: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ regcache_cache_only(aic31xx->regmap, true);
+ regcache_mark_dirty(aic31xx->regmap);
+
+ ret = aic31xx_add_controls(codec);
+ if (ret)
+ return ret;
+
+ ret = aic31xx_add_widgets(codec);
+
+ return ret;
+}
+
+static int aic31xx_codec_remove(struct snd_soc_codec *codec)
+{
+ struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+ int i;
+ /* power down chip */
+ aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
+ regulator_unregister_notifier(aic31xx->supplies[i].consumer,
+ &aic31xx->disable_nb[i].nb);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
+ .probe = aic31xx_codec_probe,
+ .remove = aic31xx_codec_remove,
+ .suspend = aic31xx_suspend,
+ .resume = aic31xx_resume,
+ .set_bias_level = aic31xx_set_bias_level,
+ .controls = aic31xx_snd_controls,
+ .num_controls = ARRAY_SIZE(aic31xx_snd_controls),
+ .dapm_widgets = aic31xx_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(aic31xx_dapm_widgets),
+ .dapm_routes = aic31xx_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(aic31xx_audio_map),
+};
+
+static struct snd_soc_dai_ops aic31xx_dai_ops = {
+ .hw_params = aic31xx_hw_params,
+ .set_sysclk = aic31xx_set_dai_sysclk,
+ .set_fmt = aic31xx_set_dai_fmt,
+ .digital_mute = aic31xx_dac_mute,
+};
+
+static struct snd_soc_dai_driver aic31xx_dai_driver[] = {
+ {
+ .name = "tlv320aic31xx-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AIC31XX_RATES,
+ .formats = AIC31XX_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AIC31XX_RATES,
+ .formats = AIC31XX_FORMATS,
+ },
+ .ops = &aic31xx_dai_ops,
+ .symmetric_rates = 1,
+ }
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id tlv320aic31xx_of_match[] = {
+ { .compatible = "ti,tlv320aic310x" },
+ { .compatible = "ti,tlv320aic311x" },
+ { .compatible = "ti,tlv320aic3100" },
+ { .compatible = "ti,tlv320aic3110" },
+ { .compatible = "ti,tlv320aic3120" },
+ { .compatible = "ti,tlv320aic3111" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match);
+
+static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
+{
+ struct device_node *np = aic31xx->dev->of_node;
+ unsigned int value = MICBIAS_2_0V;
+ int ret;
+
+ of_property_read_u32(np, "ai31xx-micbias-vg", &value);
+ switch (value) {
+ case MICBIAS_2_0V:
+ case MICBIAS_2_5V:
+ case MICBIAS_AVDDV:
+ aic31xx->pdata.micbias_vg = value;
+ break;
+ default:
+ dev_err(aic31xx->dev,
+ "Bad ai31xx-micbias-vg value %d DT\n",
+ value);
+ aic31xx->pdata.micbias_vg = MICBIAS_2_0V;
+ }
+
+ ret = of_get_named_gpio(np, "gpio-reset", 0);
+ if (ret > 0)
+ aic31xx->pdata.gpio_reset = ret;
+}
+#else /* CONFIG_OF */
+static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
+{
+}
+#endif /* CONFIG_OF */
+
+static void aic31xx_device_init(struct aic31xx_priv *aic31xx)
+{
+ int ret, i;
+
+ dev_set_drvdata(aic31xx->dev, aic31xx);
+
+ if (dev_get_platdata(aic31xx->dev))
+ memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev),
+ sizeof(aic31xx->pdata));
+ else if (aic31xx->dev->of_node)
+ aic31xx_pdata_from_of(aic31xx);
+
+ if (aic31xx->pdata.gpio_reset) {
+ ret = devm_gpio_request_one(aic31xx->dev,
+ aic31xx->pdata.gpio_reset,
+ GPIOF_OUT_INIT_HIGH,
+ "aic31xx-reset-pin");
+ if (ret < 0) {
+ dev_err(aic31xx->dev, "not able to acquire gpio\n");
+ return;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
+ aic31xx->supplies[i].supply = aic31xx_supply_names[i];
+
+ ret = devm_regulator_bulk_get(aic31xx->dev,
+ ARRAY_SIZE(aic31xx->supplies),
+ aic31xx->supplies);
+ if (ret != 0)
+ dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret);
+
+}
+
+static int aic31xx_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct aic31xx_priv *aic31xx;
+ int ret;
+ const struct regmap_config *regmap_config;
+
+ dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__,
+ id->name, (int) id->driver_data);
+
+ regmap_config = &aic31xx_i2c_regmap;
+
+ aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL);
+ if (aic31xx == NULL)
+ return -ENOMEM;
+
+ aic31xx->regmap = devm_regmap_init_i2c(i2c, regmap_config);
+ if (IS_ERR(aic31xx->regmap)) {
+ ret = PTR_ERR(aic31xx->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+ aic31xx->dev = &i2c->dev;
+
+ aic31xx->pdata.codec_type = id->driver_data;
+
+ aic31xx_device_init(aic31xx);
+
+ return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx,
+ aic31xx_dai_driver,
+ ARRAY_SIZE(aic31xx_dai_driver));
+}
+
+static int aic31xx_i2c_remove(struct i2c_client *i2c)
+{
+ snd_soc_unregister_codec(&i2c->dev);
+ return 0;
+}
+
+static const struct i2c_device_id aic31xx_i2c_id[] = {
+ { "tlv320aic310x", AIC3100 },
+ { "tlv320aic311x", AIC3110 },
+ { "tlv320aic3100", AIC3100 },
+ { "tlv320aic3110", AIC3110 },
+ { "tlv320aic3120", AIC3120 },
+ { "tlv320aic3111", AIC3111 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
+
+static struct i2c_driver aic31xx_i2c_driver = {
+ .driver = {
+ .name = "tlv320aic31xx-codec",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(tlv320aic31xx_of_match),
+ },
+ .probe = aic31xx_i2c_probe,
+ .remove = aic31xx_i2c_remove,
+ .id_table = aic31xx_i2c_id,
+};
+
+module_i2c_driver(aic31xx_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC3111 codec driver");
+MODULE_AUTHOR("Jyri Sarha");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
new file mode 100644
index 000000000000..52ed57c69dfa
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -0,0 +1,258 @@
+/*
+ * ALSA SoC TLV320AIC31XX codec driver
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+#ifndef _TLV320AIC31XX_H
+#define _TLV320AIC31XX_H
+
+#define AIC31XX_RATES SNDRV_PCM_RATE_8000_192000
+
+#define AIC31XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+ | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+
+#define AIC31XX_STEREO_CLASS_D_BIT 0x1
+#define AIC31XX_MINIDSP_BIT 0x2
+
+enum aic31xx_type {
+ AIC3100 = 0,
+ AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
+ AIC3120 = AIC31XX_MINIDSP_BIT,
+ AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT),
+};
+
+struct aic31xx_pdata {
+ enum aic31xx_type codec_type;
+ unsigned int gpio_reset;
+ int micbias_vg;
+};
+
+/* Page Control Register */
+#define AIC31XX_PAGECTL 0x00
+
+/* Page 0 Registers */
+/* Software reset register */
+#define AIC31XX_RESET 0x01
+/* OT FLAG register */
+#define AIC31XX_OT_FLAG 0x03
+/* Clock clock Gen muxing, Multiplexers*/
+#define AIC31XX_CLKMUX 0x04
+/* PLL P and R-VAL register */
+#define AIC31XX_PLLPR 0x05
+/* PLL J-VAL register */
+#define AIC31XX_PLLJ 0x06
+/* PLL D-VAL MSB register */
+#define AIC31XX_PLLDMSB 0x07
+/* PLL D-VAL LSB register */
+#define AIC31XX_PLLDLSB 0x08
+/* DAC NDAC_VAL register*/
+#define AIC31XX_NDAC 0x0B
+/* DAC MDAC_VAL register */
+#define AIC31XX_MDAC 0x0C
+/* DAC OSR setting register 1, MSB value */
+#define AIC31XX_DOSRMSB 0x0D
+/* DAC OSR setting register 2, LSB value */
+#define AIC31XX_DOSRLSB 0x0E
+#define AIC31XX_MINI_DSP_INPOL 0x10
+/* Clock setting register 8, PLL */
+#define AIC31XX_NADC 0x12
+/* Clock setting register 9, PLL */
+#define AIC31XX_MADC 0x13
+/* ADC Oversampling (AOSR) Register */
+#define AIC31XX_AOSR 0x14
+/* Clock setting register 9, Multiplexers */
+#define AIC31XX_CLKOUTMUX 0x19
+/* Clock setting register 10, CLOCKOUT M divider value */
+#define AIC31XX_CLKOUTMVAL 0x1A
+/* Audio Interface Setting Register 1 */
+#define AIC31XX_IFACE1 0x1B
+/* Audio Data Slot Offset Programming */
+#define AIC31XX_DATA_OFFSET 0x1C
+/* Audio Interface Setting Register 2 */
+#define AIC31XX_IFACE2 0x1D
+/* Clock setting register 11, BCLK N Divider */
+#define AIC31XX_BCLKN 0x1E
+/* Audio Interface Setting Register 3, Secondary Audio Interface */
+#define AIC31XX_IFACESEC1 0x1F
+/* Audio Interface Setting Register 4 */
+#define AIC31XX_IFACESEC2 0x20
+/* Audio Interface Setting Register 5 */
+#define AIC31XX_IFACESEC3 0x21
+/* I2C Bus Condition */
+#define AIC31XX_I2C 0x22
+/* ADC FLAG */
+#define AIC31XX_ADCFLAG 0x24
+/* DAC Flag Registers */
+#define AIC31XX_DACFLAG1 0x25
+#define AIC31XX_DACFLAG2 0x26
+/* Sticky Interrupt flag (overflow) */
+#define AIC31XX_OFFLAG 0x27
+/* Sticy DAC Interrupt flags */
+#define AIC31XX_INTRDACFLAG 0x2C
+/* Sticy ADC Interrupt flags */
+#define AIC31XX_INTRADCFLAG 0x2D
+/* DAC Interrupt flags 2 */
+#define AIC31XX_INTRDACFLAG2 0x2E
+/* ADC Interrupt flags 2 */
+#define AIC31XX_INTRADCFLAG2 0x2F
+/* INT1 interrupt control */
+#define AIC31XX_INT1CTRL 0x30
+/* INT2 interrupt control */
+#define AIC31XX_INT2CTRL 0x31
+/* GPIO1 control */
+#define AIC31XX_GPIO1 0x33
+
+#define AIC31XX_DACPRB 0x3C
+/* ADC Instruction Set Register */
+#define AIC31XX_ADCPRB 0x3D
+/* DAC channel setup register */
+#define AIC31XX_DACSETUP 0x3F
+/* DAC Mute and volume control register */
+#define AIC31XX_DACMUTE 0x40
+/* Left DAC channel digital volume control */
+#define AIC31XX_LDACVOL 0x41
+/* Right DAC channel digital volume control */
+#define AIC31XX_RDACVOL 0x42
+/* Headset detection */
+#define AIC31XX_HSDETECT 0x43
+/* ADC Digital Mic */
+#define AIC31XX_ADCSETUP 0x51
+/* ADC Digital Volume Control Fine Adjust */
+#define AIC31XX_ADCFGA 0x52
+/* ADC Digital Volume Control Coarse Adjust */
+#define AIC31XX_ADCVOL 0x53
+
+
+/* Page 1 Registers */
+/* Headphone drivers */
+#define AIC31XX_HPDRIVER 0x9F
+/* Class-D Speakear Amplifier */
+#define AIC31XX_SPKAMP 0xA0
+/* HP Output Drivers POP Removal Settings */
+#define AIC31XX_HPPOP 0xA1
+/* Output Driver PGA Ramp-Down Period Control */
+#define AIC31XX_SPPGARAMP 0xA2
+/* DAC_L and DAC_R Output Mixer Routing */
+#define AIC31XX_DACMIXERROUTE 0xA3
+/* Left Analog Vol to HPL */
+#define AIC31XX_LANALOGHPL 0xA4
+/* Right Analog Vol to HPR */
+#define AIC31XX_RANALOGHPR 0xA5
+/* Left Analog Vol to SPL */
+#define AIC31XX_LANALOGSPL 0xA6
+/* Right Analog Vol to SPR */
+#define AIC31XX_RANALOGSPR 0xA7
+/* HPL Driver */
+#define AIC31XX_HPLGAIN 0xA8
+/* HPR Driver */
+#define AIC31XX_HPRGAIN 0xA9
+/* SPL Driver */
+#define AIC31XX_SPLGAIN 0xAA
+/* SPR Driver */
+#define AIC31XX_SPRGAIN 0xAB
+/* HP Driver Control */
+#define AIC31XX_HPCONTROL 0xAC
+/* MIC Bias Control */
+#define AIC31XX_MICBIAS 0xAE
+/* MIC PGA*/
+#define AIC31XX_MICPGA 0xAF
+/* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */
+#define AIC31XX_MICPGAPI 0xB0
+/* ADC Input Selection for M-Terminal */
+#define AIC31XX_MICPGAMI 0xB1
+/* Input CM Settings */
+#define AIC31XX_MICPGACM 0xB2
+
+/* Bits, masks and shifts */
+
+/* AIC31XX_CLKMUX */
+#define AIC31XX_PLL_CLKIN_MASK 0x0c
+#define AIC31XX_PLL_CLKIN_SHIFT 2
+#define AIC31XX_PLL_CLKIN_MCLK 0
+#define AIC31XX_CODEC_CLKIN_MASK 0x03
+#define AIC31XX_CODEC_CLKIN_SHIFT 0
+#define AIC31XX_CODEC_CLKIN_PLL 3
+#define AIC31XX_CODEC_CLKIN_BCLK 1
+
+/* AIC31XX_PLLPR, AIC31XX_NDAC, AIC31XX_MDAC, AIC31XX_NADC, AIC31XX_MADC,
+ AIC31XX_BCLKN */
+#define AIC31XX_PLL_MASK 0x7f
+#define AIC31XX_PM_MASK 0x80
+
+/* AIC31XX_IFACE1 */
+#define AIC31XX_WORD_LEN_16BITS 0x00
+#define AIC31XX_WORD_LEN_20BITS 0x01
+#define AIC31XX_WORD_LEN_24BITS 0x02
+#define AIC31XX_WORD_LEN_32BITS 0x03
+#define AIC31XX_IFACE1_DATALEN_MASK 0x30
+#define AIC31XX_IFACE1_DATALEN_SHIFT (4)
+#define AIC31XX_IFACE1_DATATYPE_MASK 0xC0
+#define AIC31XX_IFACE1_DATATYPE_SHIFT (6)
+#define AIC31XX_I2S_MODE 0x00
+#define AIC31XX_DSP_MODE 0x01
+#define AIC31XX_RIGHT_JUSTIFIED_MODE 0x02
+#define AIC31XX_LEFT_JUSTIFIED_MODE 0x03
+#define AIC31XX_IFACE1_MASTER_MASK 0x0C
+#define AIC31XX_BCLK_MASTER 0x08
+#define AIC31XX_WCLK_MASTER 0x04
+
+/* AIC31XX_DATA_OFFSET */
+#define AIC31XX_DATA_OFFSET_MASK 0xFF
+
+/* AIC31XX_IFACE2 */
+#define AIC31XX_BCLKINV_MASK 0x08
+#define AIC31XX_BDIVCLK_MASK 0x03
+#define AIC31XX_DAC2BCLK 0x00
+#define AIC31XX_DACMOD2BCLK 0x01
+#define AIC31XX_ADC2BCLK 0x02
+#define AIC31XX_ADCMOD2BCLK 0x03
+
+/* AIC31XX_ADCFLAG */
+#define AIC31XX_ADCPWRSTATUS_MASK 0x40
+
+/* AIC31XX_DACFLAG1 */
+#define AIC31XX_LDACPWRSTATUS_MASK 0x80
+#define AIC31XX_RDACPWRSTATUS_MASK 0x08
+#define AIC31XX_HPLDRVPWRSTATUS_MASK 0x20
+#define AIC31XX_HPRDRVPWRSTATUS_MASK 0x02
+#define AIC31XX_SPLDRVPWRSTATUS_MASK 0x10
+#define AIC31XX_SPRDRVPWRSTATUS_MASK 0x01
+
+/* AIC31XX_INTRDACFLAG */
+#define AIC31XX_HPSCDETECT_MASK 0x80
+#define AIC31XX_BUTTONPRESS_MASK 0x20
+#define AIC31XX_HSPLUG_MASK 0x10
+#define AIC31XX_LDRCTHRES_MASK 0x08
+#define AIC31XX_RDRCTHRES_MASK 0x04
+#define AIC31XX_DACSINT_MASK 0x02
+#define AIC31XX_DACAINT_MASK 0x01
+
+/* AIC31XX_INT1CTRL */
+#define AIC31XX_HSPLUGDET_MASK 0x80
+#define AIC31XX_BUTTONPRESSDET_MASK 0x40
+#define AIC31XX_DRCTHRES_MASK 0x20
+#define AIC31XX_AGCNOISE_MASK 0x10
+#define AIC31XX_OC_MASK 0x08
+#define AIC31XX_ENGINE_MASK 0x04
+
+/* AIC31XX_DACSETUP */
+#define AIC31XX_SOFTSTEP_MASK 0x03
+
+/* AIC31XX_DACMUTE */
+#define AIC31XX_DACMUTE_MASK 0x0C
+
+/* AIC31XX_MICBIAS */
+#define AIC31XX_MICBIAS_MASK 0x03
+#define AIC31XX_MICBIAS_SHIFT 0
+
+#endif /* _TLV320AIC31XX_H */
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 688151ba309a..1d9b117345a3 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -29,9 +29,12 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <linux/i2c.h>
#include <linux/cdev.h>
#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
#include <sound/tlv320aic32x4.h>
#include <sound/core.h>
@@ -66,20 +69,32 @@ struct aic32x4_priv {
u32 micpga_routing;
bool swapdacs;
int rstn_gpio;
+ struct clk *mclk;
+
+ struct regulator *supply_ldo;
+ struct regulator *supply_iov;
+ struct regulator *supply_dv;
+ struct regulator *supply_av;
};
-/* 0dB min, 1dB steps */
-static DECLARE_TLV_DB_SCALE(tlv_step_1, 0, 100, 0);
/* 0dB min, 0.5dB steps */
static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0);
+/* -63.5dB min, 0.5dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_pcm, -6350, 50, 0);
+/* -6dB min, 1dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0);
+/* -12dB min, 0.5dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);
static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
- SOC_DOUBLE_R_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
- AIC32X4_RDACVOL, 0, 0x30, 0, tlv_step_0_5),
- SOC_DOUBLE_R_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
- AIC32X4_HPRGAIN, 0, 0x1D, 0, tlv_step_1),
- SOC_DOUBLE_R_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
- AIC32X4_LORGAIN, 0, 0x1D, 0, tlv_step_1),
+ SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
+ AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
+ SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
+ AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0,
+ tlv_driver_gain),
+ SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
+ AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0,
+ tlv_driver_gain),
SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN,
AIC32X4_HPRGAIN, 6, 0x01, 1),
SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
@@ -90,8 +105,8 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0),
SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0),
- SOC_DOUBLE_R_TLV("ADC Level Volume", AIC32X4_LADCVOL,
- AIC32X4_RADCVOL, 0, 0x28, 0, tlv_step_0_5),
+ SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL,
+ AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol),
SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL,
AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
@@ -480,8 +495,18 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
switch (level) {
case SND_SOC_BIAS_ON:
+ /* Switch on master clock */
+ ret = clk_prepare_enable(aic32x4->mclk);
+ if (ret) {
+ dev_err(codec->dev, "Failed to enable master clock\n");
+ return ret;
+ }
+
/* Switch on PLL */
snd_soc_update_bits(codec, AIC32X4_PLLPR,
AIC32X4_PLLEN, AIC32X4_PLLEN);
@@ -509,29 +534,32 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- /* Switch off PLL */
- snd_soc_update_bits(codec, AIC32X4_PLLPR,
- AIC32X4_PLLEN, 0);
+ /* Switch off BCLK_N Divider */
+ snd_soc_update_bits(codec, AIC32X4_BCLKN,
+ AIC32X4_BCLKEN, 0);
- /* Switch off NDAC Divider */
- snd_soc_update_bits(codec, AIC32X4_NDAC,
- AIC32X4_NDACEN, 0);
+ /* Switch off MADC Divider */
+ snd_soc_update_bits(codec, AIC32X4_MADC,
+ AIC32X4_MADCEN, 0);
+
+ /* Switch off NADC Divider */
+ snd_soc_update_bits(codec, AIC32X4_NADC,
+ AIC32X4_NADCEN, 0);
/* Switch off MDAC Divider */
snd_soc_update_bits(codec, AIC32X4_MDAC,
AIC32X4_MDACEN, 0);
- /* Switch off NADC Divider */
- snd_soc_update_bits(codec, AIC32X4_NADC,
- AIC32X4_NADCEN, 0);
+ /* Switch off NDAC Divider */
+ snd_soc_update_bits(codec, AIC32X4_NDAC,
+ AIC32X4_NDACEN, 0);
- /* Switch off MADC Divider */
- snd_soc_update_bits(codec, AIC32X4_MADC,
- AIC32X4_MADCEN, 0);
+ /* Switch off PLL */
+ snd_soc_update_bits(codec, AIC32X4_PLLPR,
+ AIC32X4_PLLEN, 0);
- /* Switch off BCLK_N Divider */
- snd_soc_update_bits(codec, AIC32X4_BCLKN,
- AIC32X4_BCLKEN, 0);
+ /* Switch off master clock */
+ clk_disable_unprepare(aic32x4->mclk);
break;
case SND_SOC_BIAS_OFF:
break;
@@ -586,9 +614,7 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
u32 tmp_reg;
- snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-
- if (aic32x4->rstn_gpio >= 0) {
+ if (gpio_is_valid(aic32x4->rstn_gpio)) {
ndelay(10);
gpio_set_value(aic32x4->rstn_gpio, 1);
}
@@ -663,11 +689,122 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
.num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes),
};
+static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
+ struct device_node *np)
+{
+ aic32x4->swapdacs = false;
+ aic32x4->micpga_routing = 0;
+ aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
+
+ return 0;
+}
+
+static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4)
+{
+ regulator_disable(aic32x4->supply_iov);
+
+ if (!IS_ERR(aic32x4->supply_ldo))
+ regulator_disable(aic32x4->supply_ldo);
+
+ if (!IS_ERR(aic32x4->supply_dv))
+ regulator_disable(aic32x4->supply_dv);
+
+ if (!IS_ERR(aic32x4->supply_av))
+ regulator_disable(aic32x4->supply_av);
+}
+
+static int aic32x4_setup_regulators(struct device *dev,
+ struct aic32x4_priv *aic32x4)
+{
+ int ret = 0;
+
+ aic32x4->supply_ldo = devm_regulator_get_optional(dev, "ldoin");
+ aic32x4->supply_iov = devm_regulator_get(dev, "iov");
+ aic32x4->supply_dv = devm_regulator_get_optional(dev, "dv");
+ aic32x4->supply_av = devm_regulator_get_optional(dev, "av");
+
+ /* Check if the regulator requirements are fulfilled */
+
+ if (IS_ERR(aic32x4->supply_iov)) {
+ dev_err(dev, "Missing supply 'iov'\n");
+ return PTR_ERR(aic32x4->supply_iov);
+ }
+
+ if (IS_ERR(aic32x4->supply_ldo)) {
+ if (PTR_ERR(aic32x4->supply_ldo) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ if (IS_ERR(aic32x4->supply_dv)) {
+ dev_err(dev, "Missing supply 'dv' or 'ldoin'\n");
+ return PTR_ERR(aic32x4->supply_dv);
+ }
+ if (IS_ERR(aic32x4->supply_av)) {
+ dev_err(dev, "Missing supply 'av' or 'ldoin'\n");
+ return PTR_ERR(aic32x4->supply_av);
+ }
+ } else {
+ if (IS_ERR(aic32x4->supply_dv) &&
+ PTR_ERR(aic32x4->supply_dv) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ if (IS_ERR(aic32x4->supply_av) &&
+ PTR_ERR(aic32x4->supply_av) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ }
+
+ ret = regulator_enable(aic32x4->supply_iov);
+ if (ret) {
+ dev_err(dev, "Failed to enable regulator iov\n");
+ return ret;
+ }
+
+ if (!IS_ERR(aic32x4->supply_ldo)) {
+ ret = regulator_enable(aic32x4->supply_ldo);
+ if (ret) {
+ dev_err(dev, "Failed to enable regulator ldo\n");
+ goto error_ldo;
+ }
+ }
+
+ if (!IS_ERR(aic32x4->supply_dv)) {
+ ret = regulator_enable(aic32x4->supply_dv);
+ if (ret) {
+ dev_err(dev, "Failed to enable regulator dv\n");
+ goto error_dv;
+ }
+ }
+
+ if (!IS_ERR(aic32x4->supply_av)) {
+ ret = regulator_enable(aic32x4->supply_av);
+ if (ret) {
+ dev_err(dev, "Failed to enable regulator av\n");
+ goto error_av;
+ }
+ }
+
+ if (!IS_ERR(aic32x4->supply_ldo) && IS_ERR(aic32x4->supply_av))
+ aic32x4->power_cfg |= AIC32X4_PWR_AIC32X4_LDO_ENABLE;
+
+ return 0;
+
+error_av:
+ if (!IS_ERR(aic32x4->supply_dv))
+ regulator_disable(aic32x4->supply_dv);
+
+error_dv:
+ if (!IS_ERR(aic32x4->supply_ldo))
+ regulator_disable(aic32x4->supply_ldo);
+
+error_ldo:
+ regulator_disable(aic32x4->supply_iov);
+ return ret;
+}
+
static int aic32x4_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct aic32x4_pdata *pdata = i2c->dev.platform_data;
struct aic32x4_priv *aic32x4;
+ struct device_node *np = i2c->dev.of_node;
int ret;
aic32x4 = devm_kzalloc(&i2c->dev, sizeof(struct aic32x4_priv),
@@ -686,6 +823,12 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c,
aic32x4->swapdacs = pdata->swapdacs;
aic32x4->micpga_routing = pdata->micpga_routing;
aic32x4->rstn_gpio = pdata->rstn_gpio;
+ } else if (np) {
+ ret = aic32x4_parse_dt(aic32x4, np);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to parse DT node\n");
+ return ret;
+ }
} else {
aic32x4->power_cfg = 0;
aic32x4->swapdacs = false;
@@ -693,20 +836,44 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c,
aic32x4->rstn_gpio = -1;
}
- if (aic32x4->rstn_gpio >= 0) {
+ aic32x4->mclk = devm_clk_get(&i2c->dev, "mclk");
+ if (IS_ERR(aic32x4->mclk)) {
+ dev_err(&i2c->dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n");
+ return PTR_ERR(aic32x4->mclk);
+ }
+
+ if (gpio_is_valid(aic32x4->rstn_gpio)) {
ret = devm_gpio_request_one(&i2c->dev, aic32x4->rstn_gpio,
GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
if (ret != 0)
return ret;
}
+ ret = aic32x4_setup_regulators(&i2c->dev, aic32x4);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to setup regulators\n");
+ return ret;
+ }
+
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_aic32x4, &aic32x4_dai, 1);
- return ret;
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to register codec\n");
+ aic32x4_disable_regulators(aic32x4);
+ return ret;
+ }
+
+ i2c_set_clientdata(i2c, aic32x4);
+
+ return 0;
}
static int aic32x4_i2c_remove(struct i2c_client *client)
{
+ struct aic32x4_priv *aic32x4 = i2c_get_clientdata(client);
+
+ aic32x4_disable_regulators(aic32x4);
+
snd_soc_unregister_codec(&client->dev);
return 0;
}
@@ -717,10 +884,17 @@ static const struct i2c_device_id aic32x4_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id);
+static const struct of_device_id aic32x4_of_id[] = {
+ { .compatible = "ti,tlv320aic32x4", },
+ { /* senitel */ }
+};
+MODULE_DEVICE_TABLE(of, aic32x4_of_id);
+
static struct i2c_driver aic32x4_i2c_driver = {
.driver = {
.name = "tlv320aic32x4",
.owner = THIS_MODULE,
+ .of_match_table = aic32x4_of_id,
},
.probe = aic32x4_i2c_probe,
.remove = aic32x4_i2c_remove,
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 470fbfb4b386..b1835103e9b4 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1344,12 +1344,6 @@ static int aic3x_probe(struct snd_soc_codec *codec)
INIT_LIST_HEAD(&aic3x->list);
aic3x->codec = codec;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
aic3x->disable_nb[i].aic3x = aic3x;
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 4f358393d6d6..6bfc8a17331b 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -122,7 +122,6 @@ struct tlv320dac33_priv {
unsigned int uthr;
enum dac33_state state;
- enum snd_soc_control_type control_type;
void *control_data;
};
@@ -461,7 +460,7 @@ static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
if (dac33->fifo_mode == ucontrol->value.integer.value[0])
return 0;
/* Do not allow changes while stream is running*/
- if (codec->active)
+ if (snd_soc_codec_is_active(codec))
return -EPERM;
if (ucontrol->value.integer.value[0] < 0 ||
@@ -478,9 +477,7 @@ static const char *dac33_fifo_mode_texts[] = {
"Bypass", "Mode 1", "Mode 7"
};
-static const struct soc_enum dac33_fifo_mode_enum =
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts),
- dac33_fifo_mode_texts);
+static SOC_ENUM_SINGLE_EXT_DECL(dac33_fifo_mode_enum, dac33_fifo_mode_texts);
/* L/R Line Output Gain */
static const char *lr_lineout_gain_texts[] = {
@@ -488,15 +485,13 @@ static const char *lr_lineout_gain_texts[] = {
"Line 0dB DAC 12dB", "Line 6dB DAC 18dB",
};
-static const struct soc_enum l_lineout_gain_enum =
- SOC_ENUM_SINGLE(DAC33_LDAC_PWR_CTRL, 0,
- ARRAY_SIZE(lr_lineout_gain_texts),
- lr_lineout_gain_texts);
+static SOC_ENUM_SINGLE_DECL(l_lineout_gain_enum,
+ DAC33_LDAC_PWR_CTRL, 0,
+ lr_lineout_gain_texts);
-static const struct soc_enum r_lineout_gain_enum =
- SOC_ENUM_SINGLE(DAC33_RDAC_PWR_CTRL, 0,
- ARRAY_SIZE(lr_lineout_gain_texts),
- lr_lineout_gain_texts);
+static SOC_ENUM_SINGLE_DECL(r_lineout_gain_enum,
+ DAC33_RDAC_PWR_CTRL, 0,
+ lr_lineout_gain_texts);
/*
* DACL/R digital volume control:
@@ -534,18 +529,16 @@ static const struct snd_kcontrol_new dac33_dapm_abypassr_control =
/* LOP L/R invert selection */
static const char *dac33_lr_lom_texts[] = {"DAC", "LOP"};
-static const struct soc_enum dac33_left_lom_enum =
- SOC_ENUM_SINGLE(DAC33_OUT_AMP_CTRL, 3,
- ARRAY_SIZE(dac33_lr_lom_texts),
- dac33_lr_lom_texts);
+static SOC_ENUM_SINGLE_DECL(dac33_left_lom_enum,
+ DAC33_OUT_AMP_CTRL, 3,
+ dac33_lr_lom_texts);
static const struct snd_kcontrol_new dac33_dapm_left_lom_control =
SOC_DAPM_ENUM("Route", dac33_left_lom_enum);
-static const struct soc_enum dac33_right_lom_enum =
- SOC_ENUM_SINGLE(DAC33_OUT_AMP_CTRL, 2,
- ARRAY_SIZE(dac33_lr_lom_texts),
- dac33_lr_lom_texts);
+static SOC_ENUM_SINGLE_DECL(dac33_right_lom_enum,
+ DAC33_OUT_AMP_CTRL, 2,
+ dac33_lr_lom_texts);
static const struct snd_kcontrol_new dac33_dapm_right_lom_control =
SOC_DAPM_ENUM("Route", dac33_right_lom_enum);
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 00665ada23e2..975e0f760ac1 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -415,10 +415,9 @@ static const struct snd_kcontrol_new twl4030_dapm_carkitr_controls[] = {
static const char *twl4030_handsfreel_texts[] =
{"Voice", "AudioL1", "AudioL2", "AudioR2"};
-static const struct soc_enum twl4030_handsfreel_enum =
- SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0,
- ARRAY_SIZE(twl4030_handsfreel_texts),
- twl4030_handsfreel_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_handsfreel_enum,
+ TWL4030_REG_HFL_CTL, 0,
+ twl4030_handsfreel_texts);
static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control =
SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum);
@@ -431,10 +430,9 @@ static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control =
static const char *twl4030_handsfreer_texts[] =
{"Voice", "AudioR1", "AudioR2", "AudioL2"};
-static const struct soc_enum twl4030_handsfreer_enum =
- SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0,
- ARRAY_SIZE(twl4030_handsfreer_texts),
- twl4030_handsfreer_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_handsfreer_enum,
+ TWL4030_REG_HFR_CTL, 0,
+ twl4030_handsfreer_texts);
static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control =
SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);
@@ -448,10 +446,9 @@ static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control =
static const char *twl4030_vibra_texts[] =
{"AudioL1", "AudioR1", "AudioL2", "AudioR2"};
-static const struct soc_enum twl4030_vibra_enum =
- SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 2,
- ARRAY_SIZE(twl4030_vibra_texts),
- twl4030_vibra_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_vibra_enum,
+ TWL4030_REG_VIBRA_CTL, 2,
+ twl4030_vibra_texts);
static const struct snd_kcontrol_new twl4030_dapm_vibra_control =
SOC_DAPM_ENUM("Route", twl4030_vibra_enum);
@@ -460,10 +457,9 @@ SOC_DAPM_ENUM("Route", twl4030_vibra_enum);
static const char *twl4030_vibrapath_texts[] =
{"Local vibrator", "Audio"};
-static const struct soc_enum twl4030_vibrapath_enum =
- SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 4,
- ARRAY_SIZE(twl4030_vibrapath_texts),
- twl4030_vibrapath_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_vibrapath_enum,
+ TWL4030_REG_VIBRA_CTL, 4,
+ twl4030_vibrapath_texts);
static const struct snd_kcontrol_new twl4030_dapm_vibrapath_control =
SOC_DAPM_ENUM("Route", twl4030_vibrapath_enum);
@@ -490,10 +486,9 @@ static const struct snd_kcontrol_new twl4030_dapm_analogrmic_controls[] = {
static const char *twl4030_micpathtx1_texts[] =
{"Analog", "Digimic0"};
-static const struct soc_enum twl4030_micpathtx1_enum =
- SOC_ENUM_SINGLE(TWL4030_REG_ADCMICSEL, 0,
- ARRAY_SIZE(twl4030_micpathtx1_texts),
- twl4030_micpathtx1_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_micpathtx1_enum,
+ TWL4030_REG_ADCMICSEL, 0,
+ twl4030_micpathtx1_texts);
static const struct snd_kcontrol_new twl4030_dapm_micpathtx1_control =
SOC_DAPM_ENUM("Route", twl4030_micpathtx1_enum);
@@ -502,10 +497,9 @@ SOC_DAPM_ENUM("Route", twl4030_micpathtx1_enum);
static const char *twl4030_micpathtx2_texts[] =
{"Analog", "Digimic1"};
-static const struct soc_enum twl4030_micpathtx2_enum =
- SOC_ENUM_SINGLE(TWL4030_REG_ADCMICSEL, 2,
- ARRAY_SIZE(twl4030_micpathtx2_texts),
- twl4030_micpathtx2_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_micpathtx2_enum,
+ TWL4030_REG_ADCMICSEL, 2,
+ twl4030_micpathtx2_texts);
static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control =
SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum);
@@ -955,19 +949,15 @@ static const char *twl4030_op_modes_texts[] = {
"Option 2 (voice/audio)", "Option 1 (audio)"
};
-static const struct soc_enum twl4030_op_modes_enum =
- SOC_ENUM_SINGLE(TWL4030_REG_CODEC_MODE, 0,
- ARRAY_SIZE(twl4030_op_modes_texts),
- twl4030_op_modes_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_op_modes_enum,
+ TWL4030_REG_CODEC_MODE, 0,
+ twl4030_op_modes_texts);
static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned short val;
- unsigned short mask;
if (twl4030->configured) {
dev_err(codec->dev,
@@ -975,19 +965,7 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
return -EBUSY;
}
- if (ucontrol->value.enumerated.item[0] > e->max - 1)
- return -EINVAL;
-
- val = ucontrol->value.enumerated.item[0] << e->shift_l;
- mask = e->mask << e->shift_l;
- if (e->shift_l != e->shift_r) {
- if (ucontrol->value.enumerated.item[1] > e->max - 1)
- return -EINVAL;
- val |= ucontrol->value.enumerated.item[1] << e->shift_r;
- mask |= e->mask << e->shift_r;
- }
-
- return snd_soc_update_bits(codec, e->reg, mask, val);
+ return snd_soc_put_enum_double(kcontrol, ucontrol);
}
/*
@@ -1044,10 +1022,9 @@ static const char *twl4030_avadc_clk_priority_texts[] = {
"Voice high priority", "HiFi high priority"
};
-static const struct soc_enum twl4030_avadc_clk_priority_enum =
- SOC_ENUM_SINGLE(TWL4030_REG_AVADC_CTL, 2,
- ARRAY_SIZE(twl4030_avadc_clk_priority_texts),
- twl4030_avadc_clk_priority_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_avadc_clk_priority_enum,
+ TWL4030_REG_AVADC_CTL, 2,
+ twl4030_avadc_clk_priority_texts);
static const char *twl4030_rampdelay_texts[] = {
"27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms",
@@ -1055,40 +1032,36 @@ static const char *twl4030_rampdelay_texts[] = {
"3495/2581/1748 ms"
};
-static const struct soc_enum twl4030_rampdelay_enum =
- SOC_ENUM_SINGLE(TWL4030_REG_HS_POPN_SET, 2,
- ARRAY_SIZE(twl4030_rampdelay_texts),
- twl4030_rampdelay_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_rampdelay_enum,
+ TWL4030_REG_HS_POPN_SET, 2,
+ twl4030_rampdelay_texts);
/* Vibra H-bridge direction mode */
static const char *twl4030_vibradirmode_texts[] = {
"Vibra H-bridge direction", "Audio data MSB",
};
-static const struct soc_enum twl4030_vibradirmode_enum =
- SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 5,
- ARRAY_SIZE(twl4030_vibradirmode_texts),
- twl4030_vibradirmode_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_vibradirmode_enum,
+ TWL4030_REG_VIBRA_CTL, 5,
+ twl4030_vibradirmode_texts);
/* Vibra H-bridge direction */
static const char *twl4030_vibradir_texts[] = {
"Positive polarity", "Negative polarity",
};
-static const struct soc_enum twl4030_vibradir_enum =
- SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 1,
- ARRAY_SIZE(twl4030_vibradir_texts),
- twl4030_vibradir_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_vibradir_enum,
+ TWL4030_REG_VIBRA_CTL, 1,
+ twl4030_vibradir_texts);
/* Digimic Left and right swapping */
static const char *twl4030_digimicswap_texts[] = {
"Not swapped", "Swapped",
};
-static const struct soc_enum twl4030_digimicswap_enum =
- SOC_ENUM_SINGLE(TWL4030_REG_MISC_SET_1, 0,
- ARRAY_SIZE(twl4030_digimicswap_texts),
- twl4030_digimicswap_texts);
+static SOC_ENUM_SINGLE_DECL(twl4030_digimicswap_enum,
+ TWL4030_REG_MISC_SET_1, 0,
+ twl4030_digimicswap_texts);
static const struct snd_kcontrol_new twl4030_snd_controls[] = {
/* Codec operation mode control */
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 0afe8bef6765..bd3a20647fdf 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -81,7 +81,7 @@ struct twl6040_data {
};
/* set of rates for each pll: low-power and high-performance */
-static unsigned int lp_rates[] = {
+static const unsigned int lp_rates[] = {
8000,
11250,
16000,
@@ -93,7 +93,7 @@ static unsigned int lp_rates[] = {
96000,
};
-static unsigned int hp_rates[] = {
+static const unsigned int hp_rates[] = {
8000,
16000,
32000,
@@ -101,7 +101,7 @@ static unsigned int hp_rates[] = {
96000,
};
-static struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
+static const struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
{ .count = ARRAY_SIZE(lp_rates), .list = lp_rates, },
{ .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },
};
@@ -392,8 +392,10 @@ static const char *twl6040_amicr_texts[] =
{"Headset Mic", "Sub Mic", "Aux/FM Right", "Off"};
static const struct soc_enum twl6040_enum[] = {
- SOC_ENUM_SINGLE(TWL6040_REG_MICLCTL, 3, 4, twl6040_amicl_texts),
- SOC_ENUM_SINGLE(TWL6040_REG_MICRCTL, 3, 4, twl6040_amicr_texts),
+ SOC_ENUM_SINGLE(TWL6040_REG_MICLCTL, 3,
+ ARRAY_SIZE(twl6040_amicl_texts), twl6040_amicl_texts),
+ SOC_ENUM_SINGLE(TWL6040_REG_MICRCTL, 3,
+ ARRAY_SIZE(twl6040_amicr_texts), twl6040_amicr_texts),
};
static const char *twl6040_hs_texts[] = {
@@ -476,9 +478,8 @@ static const char *twl6040_power_mode_texts[] = {
"Low-Power", "High-Performance",
};
-static const struct soc_enum twl6040_power_mode_enum =
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl6040_power_mode_texts),
- twl6040_power_mode_texts);
+static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum,
+ twl6040_power_mode_texts);
static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index c94d4c1e3dac..edf27acc1d77 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -203,8 +203,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
u8 hw_params;
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 726df6d43c2b..e62e70781ec2 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -108,7 +108,7 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
/* the interpolator & decimator regs must only be written when the
* codec DAI is active.
*/
- if (!codec->active && (reg >= UDA1380_MVOL))
+ if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL))
return 0;
pr_debug("uda1380: hw write %x val %x\n", reg, value);
if (codec->hw_write(codec->control_data, data, 3) == 3) {
@@ -237,25 +237,27 @@ static const char *uda1380_os_setting[] = {
};
static const struct soc_enum uda1380_deemp_enum[] = {
- SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, 5, uda1380_deemp),
- SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, 5, uda1380_deemp),
+ SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, ARRAY_SIZE(uda1380_deemp),
+ uda1380_deemp),
+ SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, ARRAY_SIZE(uda1380_deemp),
+ uda1380_deemp),
};
-static const struct soc_enum uda1380_input_sel_enum =
- SOC_ENUM_SINGLE(UDA1380_ADC, 2, 4, uda1380_input_sel); /* SEL_MIC, SEL_LNA */
-static const struct soc_enum uda1380_output_sel_enum =
- SOC_ENUM_SINGLE(UDA1380_PM, 7, 2, uda1380_output_sel); /* R02_EN_AVC */
-static const struct soc_enum uda1380_spf_enum =
- SOC_ENUM_SINGLE(UDA1380_MODE, 14, 4, uda1380_spf_mode); /* M */
-static const struct soc_enum uda1380_capture_sel_enum =
- SOC_ENUM_SINGLE(UDA1380_IFACE, 6, 2, uda1380_capture_sel); /* SEL_SOURCE */
-static const struct soc_enum uda1380_sel_ns_enum =
- SOC_ENUM_SINGLE(UDA1380_MIXER, 14, 2, uda1380_sel_ns); /* SEL_NS */
-static const struct soc_enum uda1380_mix_enum =
- SOC_ENUM_SINGLE(UDA1380_MIXER, 12, 4, uda1380_mix_control); /* MIX, MIX_POS */
-static const struct soc_enum uda1380_sdet_enum =
- SOC_ENUM_SINGLE(UDA1380_MIXER, 4, 4, uda1380_sdet_setting); /* SD_VALUE */
-static const struct soc_enum uda1380_os_enum =
- SOC_ENUM_SINGLE(UDA1380_MIXER, 0, 3, uda1380_os_setting); /* OS */
+static SOC_ENUM_SINGLE_DECL(uda1380_input_sel_enum,
+ UDA1380_ADC, 2, uda1380_input_sel); /* SEL_MIC, SEL_LNA */
+static SOC_ENUM_SINGLE_DECL(uda1380_output_sel_enum,
+ UDA1380_PM, 7, uda1380_output_sel); /* R02_EN_AVC */
+static SOC_ENUM_SINGLE_DECL(uda1380_spf_enum,
+ UDA1380_MODE, 14, uda1380_spf_mode); /* M */
+static SOC_ENUM_SINGLE_DECL(uda1380_capture_sel_enum,
+ UDA1380_IFACE, 6, uda1380_capture_sel); /* SEL_SOURCE */
+static SOC_ENUM_SINGLE_DECL(uda1380_sel_ns_enum,
+ UDA1380_MIXER, 14, uda1380_sel_ns); /* SEL_NS */
+static SOC_ENUM_SINGLE_DECL(uda1380_mix_enum,
+ UDA1380_MIXER, 12, uda1380_mix_control); /* MIX, MIX_POS */
+static SOC_ENUM_SINGLE_DECL(uda1380_sdet_enum,
+ UDA1380_MIXER, 4, uda1380_sdet_setting); /* SD_VALUE */
+static SOC_ENUM_SINGLE_DECL(uda1380_os_enum,
+ UDA1380_MIXER, 0, uda1380_os_setting); /* OS */
/*
* from -48 dB in 1.5 dB steps (mute instead of -49.5 dB)
@@ -564,8 +566,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
/* shut down WSPLL power if running from this clock */
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index b7ab2ef567c8..6be5f80b65f1 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -197,7 +197,7 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
return 0;
/* Do not allow changes while stream is running */
- if (codec->active)
+ if (snd_soc_codec_is_active(codec))
return -EPERM;
if (ucontrol->value.integer.value[0] < 0 ||
@@ -209,8 +209,7 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
return 1;
}
-static const struct soc_enum wl1273_enum =
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_route), wl1273_audio_route);
+static SOC_ENUM_SINGLE_EXT_DECL(wl1273_enum, wl1273_audio_route);
static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -247,9 +246,7 @@ static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
static const char * const wl1273_audio_strings[] = { "Digital", "Analog" };
-static const struct soc_enum wl1273_audio_enum =
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_strings),
- wl1273_audio_strings);
+static SOC_ENUM_SINGLE_EXT_DECL(wl1273_audio_enum, wl1273_audio_strings);
static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 8ae50274ea8f..83a2c872925c 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -786,8 +786,6 @@ static int wm2000_probe(struct snd_soc_codec *codec)
{
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
- snd_soc_codec_set_cache_io(codec, 16, 8, SND_SOC_REGMAP);
-
/* This will trigger a transition to standby mode by default */
wm2000_anc_set_mode(wm2000);
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 57ba315d0c84..2e721e06671b 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -1113,11 +1113,10 @@ static const char *wm2200_rxanc_input_sel_texts[] = {
"None", "IN1", "IN2", "IN3",
};
-static const struct soc_enum wm2200_rxanc_input_sel =
- SOC_ENUM_SINGLE(WM2200_RXANC_SRC,
- WM2200_IN_RXANC_SEL_SHIFT,
- ARRAY_SIZE(wm2200_rxanc_input_sel_texts),
- wm2200_rxanc_input_sel_texts);
+static SOC_ENUM_SINGLE_DECL(wm2200_rxanc_input_sel,
+ WM2200_RXANC_SRC,
+ WM2200_IN_RXANC_SEL_SHIFT,
+ wm2200_rxanc_input_sel_texts);
static const struct snd_kcontrol_new wm2200_snd_controls[] = {
SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL,
@@ -1288,11 +1287,10 @@ static const char *wm2200_aec_loopback_texts[] = {
"OUT1L", "OUT1R", "OUT2L", "OUT2R",
};
-static const struct soc_enum wm2200_aec_loopback =
- SOC_ENUM_SINGLE(WM2200_DAC_AEC_CONTROL_1,
- WM2200_AEC_LOOPBACK_SRC_SHIFT,
- ARRAY_SIZE(wm2200_aec_loopback_texts),
- wm2200_aec_loopback_texts);
+static SOC_ENUM_SINGLE_DECL(wm2200_aec_loopback,
+ WM2200_DAC_AEC_CONTROL_1,
+ WM2200_AEC_LOOPBACK_SRC_SHIFT,
+ wm2200_aec_loopback_texts);
static const struct snd_kcontrol_new wm2200_aec_loopback_mux =
SOC_DAPM_ENUM("AEC Loopback", wm2200_aec_loopback);
@@ -1556,15 +1554,8 @@ static int wm2200_probe(struct snd_soc_codec *codec)
int ret;
wm2200->codec = codec;
- codec->control_data = wm2200->regmap;
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
- ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2);
if (ret != 0)
return ret;
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 4e3e31aaf509..eca983fad891 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -506,21 +506,21 @@ static const char *wm5100_lhpf_mode_text[] = {
"Low-pass", "High-pass"
};
-static const struct soc_enum wm5100_lhpf1_mode =
- SOC_ENUM_SINGLE(WM5100_HPLPF1_1, WM5100_LHPF1_MODE_SHIFT, 2,
- wm5100_lhpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(wm5100_lhpf1_mode,
+ WM5100_HPLPF1_1, WM5100_LHPF1_MODE_SHIFT,
+ wm5100_lhpf_mode_text);
-static const struct soc_enum wm5100_lhpf2_mode =
- SOC_ENUM_SINGLE(WM5100_HPLPF2_1, WM5100_LHPF2_MODE_SHIFT, 2,
- wm5100_lhpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(wm5100_lhpf2_mode,
+ WM5100_HPLPF2_1, WM5100_LHPF2_MODE_SHIFT,
+ wm5100_lhpf_mode_text);
-static const struct soc_enum wm5100_lhpf3_mode =
- SOC_ENUM_SINGLE(WM5100_HPLPF3_1, WM5100_LHPF3_MODE_SHIFT, 2,
- wm5100_lhpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(wm5100_lhpf3_mode,
+ WM5100_HPLPF3_1, WM5100_LHPF3_MODE_SHIFT,
+ wm5100_lhpf_mode_text);
-static const struct soc_enum wm5100_lhpf4_mode =
- SOC_ENUM_SINGLE(WM5100_HPLPF4_1, WM5100_LHPF4_MODE_SHIFT, 2,
- wm5100_lhpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(wm5100_lhpf4_mode,
+ WM5100_HPLPF4_1, WM5100_LHPF4_MODE_SHIFT,
+ wm5100_lhpf_mode_text);
static const struct snd_kcontrol_new wm5100_snd_controls[] = {
SOC_SINGLE("IN1 High Performance Switch", WM5100_IN1L_CONTROL,
@@ -2100,6 +2100,7 @@ static void wm5100_micd_irq(struct wm5100_priv *wm5100)
int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
if (jack) {
wm5100->jack = jack;
@@ -2117,9 +2118,14 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
WM5100_ACCDET_RATE_MASK);
/* We need the charge pump to power MICBIAS */
- snd_soc_dapm_force_enable_pin(&codec->dapm, "CP2");
- snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_mutex_lock(dapm);
+
+ snd_soc_dapm_force_enable_pin_unlocked(dapm, "CP2");
+ snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK");
+
+ snd_soc_dapm_sync_unlocked(dapm);
+
+ snd_soc_dapm_mutex_unlock(dapm);
/* We start off just enabling microphone detection - even a
* plain headphone will trigger detection.
@@ -2337,13 +2343,6 @@ static int wm5100_probe(struct snd_soc_codec *codec)
int ret, i;
wm5100->codec = codec;
- codec->control_data = wm5100->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++)
snd_soc_update_bits(codec, wm5100_dig_vu[i], WM5100_OUT_VU,
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index ce9c8e14d4bd..dcf1d12cfef8 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -582,7 +582,7 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = w->codec;
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
- struct regmap *regmap = codec->control_data;
+ struct regmap *regmap = arizona->regmap;
const struct reg_default *patch = NULL;
int i, patch_size;
@@ -622,13 +622,16 @@ static const unsigned int wm5102_osr_val[] = {
static const struct soc_enum wm5102_hpout_osr[] = {
SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
- ARIZONA_OUT1_OSR_SHIFT, 0x7, 3,
+ ARIZONA_OUT1_OSR_SHIFT, 0x7,
+ ARRAY_SIZE(wm5102_osr_text),
wm5102_osr_text, wm5102_osr_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
- ARIZONA_OUT2_OSR_SHIFT, 0x7, 3,
+ ARIZONA_OUT2_OSR_SHIFT, 0x7,
+ ARRAY_SIZE(wm5102_osr_text),
wm5102_osr_text, wm5102_osr_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
- ARIZONA_OUT3_OSR_SHIFT, 0x7, 3,
+ ARIZONA_OUT3_OSR_SHIFT, 0x7,
+ ARRAY_SIZE(wm5102_osr_text),
wm5102_osr_text, wm5102_osr_val),
};
@@ -685,15 +688,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
-SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21,
- ARIZONA_EQ1_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21,
- ARIZONA_EQ2_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21,
- ARIZONA_EQ3_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21,
- ARIZONA_EQ4_ENA_MASK),
-
+SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19),
+SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0),
SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
@@ -705,6 +701,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
24, 0, eq_tlv),
+SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19),
+SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0),
SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
@@ -716,6 +714,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
24, 0, eq_tlv),
+SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19),
+SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0),
SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
@@ -727,6 +727,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
24, 0, eq_tlv),
+SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19),
+SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0),
SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
@@ -1758,9 +1760,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
int ret;
- codec->control_data = priv->core.arizona->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP);
+ ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap);
if (ret != 0)
return ret;
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 2c3c962d9a85..df5a38dd8328 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -136,7 +136,7 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = w->codec;
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
- struct regmap *regmap = codec->control_data;
+ struct regmap *regmap = arizona->regmap;
const struct reg_default *patch = NULL;
int i, patch_size;
@@ -247,15 +247,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
-SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21,
- ARIZONA_EQ1_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21,
- ARIZONA_EQ2_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21,
- ARIZONA_EQ3_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21,
- ARIZONA_EQ4_ENA_MASK),
-
+SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19),
+SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0),
SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
@@ -267,6 +260,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
24, 0, eq_tlv),
+SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19),
+SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0),
SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
@@ -278,6 +273,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
24, 0, eq_tlv),
+SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19),
+SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0),
SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
@@ -289,6 +286,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
24, 0, eq_tlv),
+SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19),
+SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0),
SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
@@ -1588,10 +1587,9 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
int ret;
- codec->control_data = priv->core.arizona->regmap;
priv->core.arizona->dapm = &codec->dapm;
- ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP);
+ ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap);
if (ret != 0)
return ret;
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index a183dcf3d5c1..757256bf7672 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -1505,9 +1505,7 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec)
if (ret != 0)
return ret;
- codec->control_data = wm8350->regmap;
-
- snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
+ snd_soc_codec_set_cache_io(codec, wm8350->regmap);
/* Put the codec into reset if it wasn't already */
wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 48dc7d2fee36..146564feaea0 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -117,19 +117,23 @@ static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
static const char *wm8400_digital_sidetone[] =
{"None", "Left ADC", "Right ADC", "Reserved"};
-static const struct soc_enum wm8400_left_digital_sidetone_enum =
-SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE,
- WM8400_ADC_TO_DACL_SHIFT, 2, wm8400_digital_sidetone);
+static SOC_ENUM_SINGLE_DECL(wm8400_left_digital_sidetone_enum,
+ WM8400_DIGITAL_SIDE_TONE,
+ WM8400_ADC_TO_DACL_SHIFT,
+ wm8400_digital_sidetone);
-static const struct soc_enum wm8400_right_digital_sidetone_enum =
-SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE,
- WM8400_ADC_TO_DACR_SHIFT, 2, wm8400_digital_sidetone);
+static SOC_ENUM_SINGLE_DECL(wm8400_right_digital_sidetone_enum,
+ WM8400_DIGITAL_SIDE_TONE,
+ WM8400_ADC_TO_DACR_SHIFT,
+ wm8400_digital_sidetone);
static const char *wm8400_adcmode[] =
{"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
-static const struct soc_enum wm8400_right_adcmode_enum =
-SOC_ENUM_SINGLE(WM8400_ADC_CTRL, WM8400_ADC_HPF_CUT_SHIFT, 3, wm8400_adcmode);
+static SOC_ENUM_SINGLE_DECL(wm8400_right_adcmode_enum,
+ WM8400_ADC_CTRL,
+ WM8400_ADC_HPF_CUT_SHIFT,
+ wm8400_adcmode);
static const struct snd_kcontrol_new wm8400_snd_controls[] = {
/* INMIXL */
@@ -422,9 +426,10 @@ SOC_DAPM_SINGLE("RINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT,
static const char *wm8400_ainlmux[] =
{"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
-static const struct soc_enum wm8400_ainlmux_enum =
-SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINLMODE_SHIFT,
- ARRAY_SIZE(wm8400_ainlmux), wm8400_ainlmux);
+static SOC_ENUM_SINGLE_DECL(wm8400_ainlmux_enum,
+ WM8400_INPUT_MIXER1,
+ WM8400_AINLMODE_SHIFT,
+ wm8400_ainlmux);
static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls =
SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum);
@@ -435,9 +440,10 @@ SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum);
static const char *wm8400_ainrmux[] =
{"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
-static const struct soc_enum wm8400_ainrmux_enum =
-SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINRMODE_SHIFT,
- ARRAY_SIZE(wm8400_ainrmux), wm8400_ainrmux);
+static SOC_ENUM_SINGLE_DECL(wm8400_ainrmux_enum,
+ WM8400_INPUT_MIXER1,
+ WM8400_AINRMODE_SHIFT,
+ wm8400_ainrmux);
static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls =
SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum);
@@ -1310,10 +1316,9 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
snd_soc_codec_set_drvdata(codec, priv);
priv->wm8400 = wm8400;
- codec->control_data = wm8400->regmap;
priv->codec = codec;
- snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
+ snd_soc_codec_set_cache_io(codec, wm8400->regmap);
ret = devm_regulator_bulk_get(wm8400->dev,
ARRAY_SIZE(power), &power[0]);
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 7df7d4572755..1c1e328feeb8 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -589,20 +589,12 @@ static int wm8510_resume(struct snd_soc_codec *codec)
static int wm8510_probe(struct snd_soc_codec *codec)
{
- int ret;
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
wm8510_reset(codec);
/* power on device */
wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return ret;
+ return 0;
}
/* power down chip */
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 74d106dc7667..601ee8178af1 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -75,8 +75,8 @@ static const char *wm8523_zd_count_text[] = {
"2048",
};
-static const struct soc_enum wm8523_zc_count =
- SOC_ENUM_SINGLE(WM8523_ZERO_DETECT, 0, 2, wm8523_zd_count_text);
+static SOC_ENUM_SINGLE_DECL(wm8523_zc_count, WM8523_ZERO_DETECT, 0,
+ wm8523_zd_count_text);
static const struct snd_kcontrol_new wm8523_controls[] = {
SOC_DOUBLE_R_TLV("Playback Volume", WM8523_DAC_GAINL, WM8523_DAC_GAINR,
@@ -392,18 +392,11 @@ static int wm8523_resume(struct snd_soc_codec *codec)
static int wm8523_probe(struct snd_soc_codec *codec)
{
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
- int ret;
wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
wm8523->rate_constraint.count =
ARRAY_SIZE(wm8523->rate_constraint_list);
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* Change some default settings - latch VU and enable ZC */
snd_soc_update_bits(codec, WM8523_DAC_GAINR,
WM8523_DACR_VU, WM8523_DACR_VU);
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 318989acbbe5..af7ed8b5d4e1 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -504,8 +504,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
u16 paifa = 0;
u16 paifb = 0;
@@ -869,12 +868,6 @@ static int wm8580_probe(struct snd_soc_codec *codec)
struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),
wm8580->supplies);
if (ret != 0) {
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index d99f948c513c..b0fbcb377baf 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -201,7 +201,7 @@ static void wm8711_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
/* deactivate */
- if (!codec->active) {
+ if (!snd_soc_codec_is_active(codec)) {
udelay(50);
snd_soc_write(codec, WM8711_ACTIVE, 0x0);
}
@@ -367,12 +367,6 @@ static int wm8711_probe(struct snd_soc_codec *codec)
{
int ret;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = wm8711_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index cd89033e84c0..bac7fc28fe71 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -228,19 +228,10 @@ static int wm8728_resume(struct snd_soc_codec *codec)
static int wm8728_probe(struct snd_soc_codec *codec)
{
- int ret;
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n",
- ret);
- return ret;
- }
-
/* power on device */
wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return ret;
+ return 0;
}
static int wm8728_remove(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 029720366ff8..d74f43975b90 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -83,8 +83,8 @@ static bool wm8731_writeable(struct device *dev, unsigned int reg)
static const char *wm8731_input_select[] = {"Line In", "Mic"};
-static const struct soc_enum wm8731_insel_enum =
- SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select);
+static SOC_ENUM_SINGLE_DECL(wm8731_insel_enum,
+ WM8731_APANA, 2, wm8731_input_select);
static int wm8731_deemph[] = { 0, 32000, 44100, 48000 };
@@ -583,13 +583,6 @@ static int wm8731_probe(struct snd_soc_codec *codec)
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
int ret = 0, i;
- codec->control_data = wm8731->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
wm8731->supplies[i].supply = wm8731_supply_names[i];
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index 2f167a8ca01b..b27f26cdc049 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -99,29 +99,29 @@ static const char *micbias_enum_text[] = {
"100%",
};
-static const struct soc_enum micbias_enum =
- SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 0, 4, micbias_enum_text);
+static SOC_ENUM_SINGLE_DECL(micbias_enum,
+ WM8737_MIC_PREAMP_CONTROL, 0, micbias_enum_text);
static const char *low_cutoff_text[] = {
"Low", "High"
};
-static const struct soc_enum low_3d =
- SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 6, 2, low_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(low_3d,
+ WM8737_3D_ENHANCE, 6, low_cutoff_text);
static const char *high_cutoff_text[] = {
"High", "Low"
};
-static const struct soc_enum high_3d =
- SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 5, 2, high_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(high_3d,
+ WM8737_3D_ENHANCE, 5, high_cutoff_text);
static const char *alc_fn_text[] = {
"Disabled", "Right", "Left", "Stereo"
};
-static const struct soc_enum alc_fn =
- SOC_ENUM_SINGLE(WM8737_ALC1, 7, 4, alc_fn_text);
+static SOC_ENUM_SINGLE_DECL(alc_fn,
+ WM8737_ALC1, 7, alc_fn_text);
static const char *alc_hold_text[] = {
"0", "2.67ms", "5.33ms", "10.66ms", "21.32ms", "42.64ms", "85.28ms",
@@ -129,24 +129,24 @@ static const char *alc_hold_text[] = {
"10.916s", "21.832s", "43.691s"
};
-static const struct soc_enum alc_hold =
- SOC_ENUM_SINGLE(WM8737_ALC2, 0, 16, alc_hold_text);
+static SOC_ENUM_SINGLE_DECL(alc_hold,
+ WM8737_ALC2, 0, alc_hold_text);
static const char *alc_atk_text[] = {
"8.4ms", "16.8ms", "33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms",
"1.075s", "2.15s", "4.3s", "8.6s"
};
-static const struct soc_enum alc_atk =
- SOC_ENUM_SINGLE(WM8737_ALC3, 0, 11, alc_atk_text);
+static SOC_ENUM_SINGLE_DECL(alc_atk,
+ WM8737_ALC3, 0, alc_atk_text);
static const char *alc_dcy_text[] = {
"33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms", "1.075s", "2.15s",
"4.3s", "8.6s", "17.2s", "34.41s"
};
-static const struct soc_enum alc_dcy =
- SOC_ENUM_SINGLE(WM8737_ALC3, 4, 11, alc_dcy_text);
+static SOC_ENUM_SINGLE_DECL(alc_dcy,
+ WM8737_ALC3, 4, alc_dcy_text);
static const struct snd_kcontrol_new wm8737_snd_controls[] = {
SOC_DOUBLE_R_TLV("Mic Boost Volume", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
@@ -191,8 +191,8 @@ static const char *linsel_text[] = {
"LINPUT1", "LINPUT2", "LINPUT3", "LINPUT1 DC",
};
-static const struct soc_enum linsel_enum =
- SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_L, 7, 4, linsel_text);
+static SOC_ENUM_SINGLE_DECL(linsel_enum,
+ WM8737_AUDIO_PATH_L, 7, linsel_text);
static const struct snd_kcontrol_new linsel_mux =
SOC_DAPM_ENUM("LINSEL", linsel_enum);
@@ -202,8 +202,8 @@ static const char *rinsel_text[] = {
"RINPUT1", "RINPUT2", "RINPUT3", "RINPUT1 DC",
};
-static const struct soc_enum rinsel_enum =
- SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_R, 7, 4, rinsel_text);
+static SOC_ENUM_SINGLE_DECL(rinsel_enum,
+ WM8737_AUDIO_PATH_R, 7, rinsel_text);
static const struct snd_kcontrol_new rinsel_mux =
SOC_DAPM_ENUM("RINSEL", rinsel_enum);
@@ -212,15 +212,15 @@ static const char *bypass_text[] = {
"Direct", "Preamp"
};
-static const struct soc_enum lbypass_enum =
- SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 2, 2, bypass_text);
+static SOC_ENUM_SINGLE_DECL(lbypass_enum,
+ WM8737_MIC_PREAMP_CONTROL, 2, bypass_text);
static const struct snd_kcontrol_new lbypass_mux =
SOC_DAPM_ENUM("Left Bypass", lbypass_enum);
-static const struct soc_enum rbypass_enum =
- SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 3, 2, bypass_text);
+static SOC_ENUM_SINGLE_DECL(rbypass_enum,
+ WM8737_MIC_PREAMP_CONTROL, 3, bypass_text);
static const struct snd_kcontrol_new rbypass_mux =
SOC_DAPM_ENUM("Left Bypass", rbypass_enum);
@@ -570,12 +570,6 @@ static int wm8737_probe(struct snd_soc_codec *codec)
struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
int ret;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
wm8737->supplies);
if (ret != 0) {
@@ -644,7 +638,7 @@ static const struct regmap_config wm8737_regmap = {
.volatile_reg = wm8737_volatile,
};
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8737_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -758,7 +752,7 @@ static struct spi_driver wm8737_spi_driver = {
static int __init wm8737_modinit(void)
{
int ret;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8737_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register WM8737 I2C driver: %d\n",
@@ -781,7 +775,7 @@ static void __exit wm8737_exit(void)
#if defined(CONFIG_SPI_MASTER)
spi_unregister_driver(&wm8737_spi_driver);
#endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8737_i2c_driver);
#endif
}
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index 2895c8d3b5e4..b33542a04607 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -44,7 +44,7 @@ struct wm8741_priv {
struct regmap *regmap;
struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
unsigned int sysclk;
- struct snd_pcm_hw_constraint_list *sysclk_constraints;
+ const struct snd_pcm_hw_constraint_list *sysclk_constraints;
};
static const struct reg_default wm8741_reg_defaults[] = {
@@ -122,74 +122,74 @@ static struct {
{ 6, 768 },
};
-static unsigned int rates_11289[] = {
+static const unsigned int rates_11289[] = {
44100, 88235,
};
-static struct snd_pcm_hw_constraint_list constraints_11289 = {
+static const struct snd_pcm_hw_constraint_list constraints_11289 = {
.count = ARRAY_SIZE(rates_11289),
.list = rates_11289,
};
-static unsigned int rates_12288[] = {
+static const unsigned int rates_12288[] = {
32000, 48000, 96000,
};
-static struct snd_pcm_hw_constraint_list constraints_12288 = {
+static const struct snd_pcm_hw_constraint_list constraints_12288 = {
.count = ARRAY_SIZE(rates_12288),
.list = rates_12288,
};
-static unsigned int rates_16384[] = {
+static const unsigned int rates_16384[] = {
32000,
};
-static struct snd_pcm_hw_constraint_list constraints_16384 = {
+static const struct snd_pcm_hw_constraint_list constraints_16384 = {
.count = ARRAY_SIZE(rates_16384),
.list = rates_16384,
};
-static unsigned int rates_16934[] = {
+static const unsigned int rates_16934[] = {
44100, 88235,
};
-static struct snd_pcm_hw_constraint_list constraints_16934 = {
+static const struct snd_pcm_hw_constraint_list constraints_16934 = {
.count = ARRAY_SIZE(rates_16934),
.list = rates_16934,
};
-static unsigned int rates_18432[] = {
+static const unsigned int rates_18432[] = {
48000, 96000,
};
-static struct snd_pcm_hw_constraint_list constraints_18432 = {
+static const struct snd_pcm_hw_constraint_list constraints_18432 = {
.count = ARRAY_SIZE(rates_18432),
.list = rates_18432,
};
-static unsigned int rates_22579[] = {
+static const unsigned int rates_22579[] = {
44100, 88235, 1764000
};
-static struct snd_pcm_hw_constraint_list constraints_22579 = {
+static const struct snd_pcm_hw_constraint_list constraints_22579 = {
.count = ARRAY_SIZE(rates_22579),
.list = rates_22579,
};
-static unsigned int rates_24576[] = {
+static const unsigned int rates_24576[] = {
32000, 48000, 96000, 192000
};
-static struct snd_pcm_hw_constraint_list constraints_24576 = {
+static const struct snd_pcm_hw_constraint_list constraints_24576 = {
.count = ARRAY_SIZE(rates_24576),
.list = rates_24576,
};
-static unsigned int rates_36864[] = {
+static const unsigned int rates_36864[] = {
48000, 96000, 19200
};
-static struct snd_pcm_hw_constraint_list constraints_36864 = {
+static const struct snd_pcm_hw_constraint_list constraints_36864 = {
.count = ARRAY_SIZE(rates_36864),
.list = rates_36864,
};
@@ -429,12 +429,6 @@ static int wm8741_probe(struct snd_soc_codec *codec)
goto err_get;
}
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err_enable;
- }
-
ret = wm8741_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 78616a638a55..33990b63d214 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -702,12 +702,6 @@ static int wm8750_probe(struct snd_soc_codec *codec)
{
int ret;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = wm8750_reset(codec);
if (ret < 0) {
printk(KERN_ERR "wm8750: failed to reset: %d\n", ret);
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index be85da93a268..cbb8d55052a4 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -251,7 +251,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
if (wm8753->dai_func == ucontrol->value.integer.value[0])
return 0;
- if (codec->active)
+ if (snd_soc_codec_is_active(codec))
return -EBUSY;
ioctl = snd_soc_read(codec, WM8753_IOCTL);
@@ -1314,7 +1314,7 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute)
/* the digital mute covers the HiFi and Voice DAC's on the WM8753.
* make sure we check if they are not both active when we mute */
if (mute && wm8753->dai_func == 1) {
- if (!codec->active)
+ if (!snd_soc_codec_is_active(codec))
snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8);
} else {
if (mute)
@@ -1440,7 +1440,6 @@ static void wm8753_work(struct work_struct *work)
static int wm8753_suspend(struct snd_soc_codec *codec)
{
wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
- codec->cache_sync = 1;
return 0;
}
@@ -1471,13 +1470,6 @@ static int wm8753_probe(struct snd_soc_codec *codec)
INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8753_work);
- codec->control_data = wm8753->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = wm8753_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
index 89a18d82f303..c61aeb38efb8 100644
--- a/sound/soc/codecs/wm8770.c
+++ b/sound/soc/codecs/wm8770.c
@@ -196,8 +196,8 @@ static const char *ain_text[] = {
"AIN5", "AIN6", "AIN7", "AIN8"
};
-static const struct soc_enum ain_enum =
- SOC_ENUM_DOUBLE(WM8770_ADCMUX, 0, 4, 8, ain_text);
+static SOC_ENUM_DOUBLE_DECL(ain_enum,
+ WM8770_ADCMUX, 0, 4, ain_text);
static const struct snd_kcontrol_new ain_mux =
SOC_DAPM_ENUM("Capture Mux", ain_enum);
@@ -580,12 +580,6 @@ static int wm8770_probe(struct snd_soc_codec *codec)
wm8770 = snd_soc_codec_get_drvdata(codec);
wm8770->codec = codec;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
wm8770->supplies);
if (ret) {
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index ef8246725232..70952ceb278b 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -430,12 +430,6 @@ static int wm8776_probe(struct snd_soc_codec *codec)
{
int ret = 0;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = wm8776_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 9bc8206a6807..ee76f0fb4299 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -92,7 +92,7 @@ WM8804_REGULATOR_EVENT(0)
WM8804_REGULATOR_EVENT(1)
static const char *txsrc_text[] = { "S/PDIF RX", "AIF" };
-static const SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text);
+static SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text);
static const struct snd_kcontrol_new wm8804_snd_controls[] = {
SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put),
@@ -546,14 +546,6 @@ static int wm8804_probe(struct snd_soc_codec *codec)
wm8804 = snd_soc_codec_get_drvdata(codec);
- codec->control_data = wm8804->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
- return ret;
- }
-
for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
wm8804->supplies[i].supply = wm8804_supply_names[i];
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index e98bc7038a08..d09fdce57f5a 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -304,53 +304,53 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1);
static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" };
-static const struct soc_enum mic_bias_level =
-SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt);
+static SOC_ENUM_SINGLE_DECL(mic_bias_level,
+ WM8900_REG_INCTL, 8, mic_bias_level_txt);
static const char *dac_mute_rate_txt[] = { "Fast", "Slow" };
-static const struct soc_enum dac_mute_rate =
-SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt);
+static SOC_ENUM_SINGLE_DECL(dac_mute_rate,
+ WM8900_REG_DACCTRL, 7, dac_mute_rate_txt);
static const char *dac_deemphasis_txt[] = {
"Disabled", "32kHz", "44.1kHz", "48kHz"
};
-static const struct soc_enum dac_deemphasis =
-SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt);
+static SOC_ENUM_SINGLE_DECL(dac_deemphasis,
+ WM8900_REG_DACCTRL, 4, dac_deemphasis_txt);
static const char *adc_hpf_cut_txt[] = {
"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"
};
-static const struct soc_enum adc_hpf_cut =
-SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt);
+static SOC_ENUM_SINGLE_DECL(adc_hpf_cut,
+ WM8900_REG_ADCCTRL, 5, adc_hpf_cut_txt);
static const char *lr_txt[] = {
"Left", "Right"
};
-static const struct soc_enum aifl_src =
-SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt);
+static SOC_ENUM_SINGLE_DECL(aifl_src,
+ WM8900_REG_AUDIO1, 15, lr_txt);
-static const struct soc_enum aifr_src =
-SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt);
+static SOC_ENUM_SINGLE_DECL(aifr_src,
+ WM8900_REG_AUDIO1, 14, lr_txt);
-static const struct soc_enum dacl_src =
-SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt);
+static SOC_ENUM_SINGLE_DECL(dacl_src,
+ WM8900_REG_AUDIO2, 15, lr_txt);
-static const struct soc_enum dacr_src =
-SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt);
+static SOC_ENUM_SINGLE_DECL(dacr_src,
+ WM8900_REG_AUDIO2, 14, lr_txt);
static const char *sidetone_txt[] = {
"Disabled", "Left ADC", "Right ADC"
};
-static const struct soc_enum dacl_sidetone =
-SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt);
+static SOC_ENUM_SINGLE_DECL(dacl_sidetone,
+ WM8900_REG_SIDETONE, 2, sidetone_txt);
-static const struct soc_enum dacr_sidetone =
-SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt);
+static SOC_ENUM_SINGLE_DECL(dacr_sidetone,
+ WM8900_REG_SIDETONE, 0, sidetone_txt);
static const struct snd_kcontrol_new wm8900_snd_controls[] = {
SOC_ENUM("Mic Bias Level", mic_bias_level),
@@ -496,8 +496,8 @@ SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0),
static const char *wm8900_lp_mux[] = { "Disabled", "Enabled" };
-static const struct soc_enum wm8900_lineout2_lp_mux =
-SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm8900_lp_mux);
+static SOC_ENUM_SINGLE_DECL(wm8900_lineout2_lp_mux,
+ WM8900_REG_LOUTMIXCTL1, 1, wm8900_lp_mux);
static const struct snd_kcontrol_new wm8900_lineout2_lp =
SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux);
@@ -1178,13 +1178,7 @@ static int wm8900_resume(struct snd_soc_codec *codec)
static int wm8900_probe(struct snd_soc_codec *codec)
{
- int ret = 0, reg;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
+ int reg;
reg = snd_soc_read(codec, WM8900_REG_ID);
if (reg != 0x8900) {
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index eebcb1da3b7b..b0084a127d18 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -489,28 +489,28 @@ static const char *hpf_mode_text[] = {
"Hi-fi", "Voice 1", "Voice 2", "Voice 3"
};
-static const struct soc_enum hpf_mode =
- SOC_ENUM_SINGLE(WM8903_ADC_DIGITAL_0, 5, 4, hpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(hpf_mode,
+ WM8903_ADC_DIGITAL_0, 5, hpf_mode_text);
static const char *osr_text[] = {
"Low power", "High performance"
};
-static const struct soc_enum adc_osr =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_ADC_0, 0, 2, osr_text);
+static SOC_ENUM_SINGLE_DECL(adc_osr,
+ WM8903_ANALOGUE_ADC_0, 0, osr_text);
-static const struct soc_enum dac_osr =
- SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 0, 2, osr_text);
+static SOC_ENUM_SINGLE_DECL(dac_osr,
+ WM8903_DAC_DIGITAL_1, 0, osr_text);
static const char *drc_slope_text[] = {
"1", "1/2", "1/4", "1/8", "1/16", "0"
};
-static const struct soc_enum drc_slope_r0 =
- SOC_ENUM_SINGLE(WM8903_DRC_2, 3, 6, drc_slope_text);
+static SOC_ENUM_SINGLE_DECL(drc_slope_r0,
+ WM8903_DRC_2, 3, drc_slope_text);
-static const struct soc_enum drc_slope_r1 =
- SOC_ENUM_SINGLE(WM8903_DRC_2, 0, 6, drc_slope_text);
+static SOC_ENUM_SINGLE_DECL(drc_slope_r1,
+ WM8903_DRC_2, 0, drc_slope_text);
static const char *drc_attack_text[] = {
"instantaneous",
@@ -518,125 +518,125 @@ static const char *drc_attack_text[] = {
"46.4ms", "92.8ms", "185.6ms"
};
-static const struct soc_enum drc_attack =
- SOC_ENUM_SINGLE(WM8903_DRC_1, 12, 11, drc_attack_text);
+static SOC_ENUM_SINGLE_DECL(drc_attack,
+ WM8903_DRC_1, 12, drc_attack_text);
static const char *drc_decay_text[] = {
"186ms", "372ms", "743ms", "1.49s", "2.97s", "5.94s", "11.89s",
"23.87s", "47.56s"
};
-static const struct soc_enum drc_decay =
- SOC_ENUM_SINGLE(WM8903_DRC_1, 8, 9, drc_decay_text);
+static SOC_ENUM_SINGLE_DECL(drc_decay,
+ WM8903_DRC_1, 8, drc_decay_text);
static const char *drc_ff_delay_text[] = {
"5 samples", "9 samples"
};
-static const struct soc_enum drc_ff_delay =
- SOC_ENUM_SINGLE(WM8903_DRC_0, 5, 2, drc_ff_delay_text);
+static SOC_ENUM_SINGLE_DECL(drc_ff_delay,
+ WM8903_DRC_0, 5, drc_ff_delay_text);
static const char *drc_qr_decay_text[] = {
"0.725ms", "1.45ms", "5.8ms"
};
-static const struct soc_enum drc_qr_decay =
- SOC_ENUM_SINGLE(WM8903_DRC_1, 4, 3, drc_qr_decay_text);
+static SOC_ENUM_SINGLE_DECL(drc_qr_decay,
+ WM8903_DRC_1, 4, drc_qr_decay_text);
static const char *drc_smoothing_text[] = {
"Low", "Medium", "High"
};
-static const struct soc_enum drc_smoothing =
- SOC_ENUM_SINGLE(WM8903_DRC_0, 11, 3, drc_smoothing_text);
+static SOC_ENUM_SINGLE_DECL(drc_smoothing,
+ WM8903_DRC_0, 11, drc_smoothing_text);
static const char *soft_mute_text[] = {
"Fast (fs/2)", "Slow (fs/32)"
};
-static const struct soc_enum soft_mute =
- SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 10, 2, soft_mute_text);
+static SOC_ENUM_SINGLE_DECL(soft_mute,
+ WM8903_DAC_DIGITAL_1, 10, soft_mute_text);
static const char *mute_mode_text[] = {
"Hard", "Soft"
};
-static const struct soc_enum mute_mode =
- SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 9, 2, mute_mode_text);
+static SOC_ENUM_SINGLE_DECL(mute_mode,
+ WM8903_DAC_DIGITAL_1, 9, mute_mode_text);
static const char *companding_text[] = {
"ulaw", "alaw"
};
-static const struct soc_enum dac_companding =
- SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 0, 2, companding_text);
+static SOC_ENUM_SINGLE_DECL(dac_companding,
+ WM8903_AUDIO_INTERFACE_0, 0, companding_text);
-static const struct soc_enum adc_companding =
- SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 2, 2, companding_text);
+static SOC_ENUM_SINGLE_DECL(adc_companding,
+ WM8903_AUDIO_INTERFACE_0, 2, companding_text);
static const char *input_mode_text[] = {
"Single-Ended", "Differential Line", "Differential Mic"
};
-static const struct soc_enum linput_mode_enum =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text);
+static SOC_ENUM_SINGLE_DECL(linput_mode_enum,
+ WM8903_ANALOGUE_LEFT_INPUT_1, 0, input_mode_text);
-static const struct soc_enum rinput_mode_enum =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text);
+static SOC_ENUM_SINGLE_DECL(rinput_mode_enum,
+ WM8903_ANALOGUE_RIGHT_INPUT_1, 0, input_mode_text);
static const char *linput_mux_text[] = {
"IN1L", "IN2L", "IN3L"
};
-static const struct soc_enum linput_enum =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 2, 3, linput_mux_text);
+static SOC_ENUM_SINGLE_DECL(linput_enum,
+ WM8903_ANALOGUE_LEFT_INPUT_1, 2, linput_mux_text);
-static const struct soc_enum linput_inv_enum =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 4, 3, linput_mux_text);
+static SOC_ENUM_SINGLE_DECL(linput_inv_enum,
+ WM8903_ANALOGUE_LEFT_INPUT_1, 4, linput_mux_text);
static const char *rinput_mux_text[] = {
"IN1R", "IN2R", "IN3R"
};
-static const struct soc_enum rinput_enum =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 2, 3, rinput_mux_text);
+static SOC_ENUM_SINGLE_DECL(rinput_enum,
+ WM8903_ANALOGUE_RIGHT_INPUT_1, 2, rinput_mux_text);
-static const struct soc_enum rinput_inv_enum =
- SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text);
+static SOC_ENUM_SINGLE_DECL(rinput_inv_enum,
+ WM8903_ANALOGUE_RIGHT_INPUT_1, 4, rinput_mux_text);
static const char *sidetone_text[] = {
"None", "Left", "Right"
};
-static const struct soc_enum lsidetone_enum =
- SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 2, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(lsidetone_enum,
+ WM8903_DAC_DIGITAL_0, 2, sidetone_text);
-static const struct soc_enum rsidetone_enum =
- SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(rsidetone_enum,
+ WM8903_DAC_DIGITAL_0, 0, sidetone_text);
static const char *adcinput_text[] = {
"ADC", "DMIC"
};
-static const struct soc_enum adcinput_enum =
- SOC_ENUM_SINGLE(WM8903_CLOCK_RATE_TEST_4, 9, 2, adcinput_text);
+static SOC_ENUM_SINGLE_DECL(adcinput_enum,
+ WM8903_CLOCK_RATE_TEST_4, 9, adcinput_text);
static const char *aif_text[] = {
"Left", "Right"
};
-static const struct soc_enum lcapture_enum =
- SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 7, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(lcapture_enum,
+ WM8903_AUDIO_INTERFACE_0, 7, aif_text);
-static const struct soc_enum rcapture_enum =
- SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 6, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(rcapture_enum,
+ WM8903_AUDIO_INTERFACE_0, 6, aif_text);
-static const struct soc_enum lplay_enum =
- SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 5, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(lplay_enum,
+ WM8903_AUDIO_INTERFACE_0, 5, aif_text);
-static const struct soc_enum rplay_enum =
- SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 4, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(rplay_enum,
+ WM8903_AUDIO_INTERFACE_0, 4, aif_text);
static const struct snd_kcontrol_new wm8903_snd_controls[] = {
@@ -1897,21 +1897,13 @@ static void wm8903_free_gpio(struct wm8903_priv *wm8903)
static int wm8903_probe(struct snd_soc_codec *codec)
{
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
- int ret;
wm8903->codec = codec;
- codec->control_data = wm8903->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
/* power on device */
wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return ret;
+ return 0;
}
/* power down chip */
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 53bbfac6a83a..49c35c36935e 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -552,18 +552,20 @@ static const char *input_mode_text[] = {
"Single-Ended", "Differential Line", "Differential Mic"
};
-static const struct soc_enum lin_mode =
- SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text);
+static SOC_ENUM_SINGLE_DECL(lin_mode,
+ WM8904_ANALOGUE_LEFT_INPUT_1, 0,
+ input_mode_text);
-static const struct soc_enum rin_mode =
- SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text);
+static SOC_ENUM_SINGLE_DECL(rin_mode,
+ WM8904_ANALOGUE_RIGHT_INPUT_1, 0,
+ input_mode_text);
static const char *hpf_mode_text[] = {
"Hi-fi", "Voice 1", "Voice 2", "Voice 3"
};
-static const struct soc_enum hpf_mode =
- SOC_ENUM_SINGLE(WM8904_ADC_DIGITAL_0, 5, 4, hpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(hpf_mode, WM8904_ADC_DIGITAL_0, 5,
+ hpf_mode_text);
static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -611,8 +613,7 @@ static const char *drc_path_text[] = {
"ADC", "DAC"
};
-static const struct soc_enum drc_path =
- SOC_ENUM_SINGLE(WM8904_DRC_0, 14, 2, drc_path_text);
+static SOC_ENUM_SINGLE_DECL(drc_path, WM8904_DRC_0, 14, drc_path_text);
static const struct snd_kcontrol_new wm8904_dac_snd_controls[] = {
SOC_SINGLE_TLV("Digital Playback Boost Volume",
@@ -858,14 +859,14 @@ static const char *lin_text[] = {
"IN1L", "IN2L", "IN3L"
};
-static const struct soc_enum lin_enum =
- SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 2, 3, lin_text);
+static SOC_ENUM_SINGLE_DECL(lin_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 2,
+ lin_text);
static const struct snd_kcontrol_new lin_mux =
SOC_DAPM_ENUM("Left Capture Mux", lin_enum);
-static const struct soc_enum lin_inv_enum =
- SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 4, 3, lin_text);
+static SOC_ENUM_SINGLE_DECL(lin_inv_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 4,
+ lin_text);
static const struct snd_kcontrol_new lin_inv_mux =
SOC_DAPM_ENUM("Left Capture Inveting Mux", lin_inv_enum);
@@ -874,14 +875,14 @@ static const char *rin_text[] = {
"IN1R", "IN2R", "IN3R"
};
-static const struct soc_enum rin_enum =
- SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 2, 3, rin_text);
+static SOC_ENUM_SINGLE_DECL(rin_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 2,
+ rin_text);
static const struct snd_kcontrol_new rin_mux =
SOC_DAPM_ENUM("Right Capture Mux", rin_enum);
-static const struct soc_enum rin_inv_enum =
- SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 4, 3, rin_text);
+static SOC_ENUM_SINGLE_DECL(rin_inv_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 4,
+ rin_text);
static const struct snd_kcontrol_new rin_inv_mux =
SOC_DAPM_ENUM("Right Capture Inveting Mux", rin_inv_enum);
@@ -890,26 +891,26 @@ static const char *aif_text[] = {
"Left", "Right"
};
-static const struct soc_enum aifoutl_enum =
- SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 7, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifoutl_enum, WM8904_AUDIO_INTERFACE_0, 7,
+ aif_text);
static const struct snd_kcontrol_new aifoutl_mux =
SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum);
-static const struct soc_enum aifoutr_enum =
- SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 6, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifoutr_enum, WM8904_AUDIO_INTERFACE_0, 6,
+ aif_text);
static const struct snd_kcontrol_new aifoutr_mux =
SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum);
-static const struct soc_enum aifinl_enum =
- SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 5, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifinl_enum, WM8904_AUDIO_INTERFACE_0, 5,
+ aif_text);
static const struct snd_kcontrol_new aifinl_mux =
SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum);
-static const struct soc_enum aifinr_enum =
- SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 4, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifinr_enum, WM8904_AUDIO_INTERFACE_0, 4,
+ aif_text);
static const struct snd_kcontrol_new aifinr_mux =
SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum);
@@ -991,26 +992,26 @@ static const char *out_mux_text[] = {
"DAC", "Bypass"
};
-static const struct soc_enum hpl_enum =
- SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 3, 2, out_mux_text);
+static SOC_ENUM_SINGLE_DECL(hpl_enum, WM8904_ANALOGUE_OUT12_ZC, 3,
+ out_mux_text);
static const struct snd_kcontrol_new hpl_mux =
SOC_DAPM_ENUM("HPL Mux", hpl_enum);
-static const struct soc_enum hpr_enum =
- SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 2, 2, out_mux_text);
+static SOC_ENUM_SINGLE_DECL(hpr_enum, WM8904_ANALOGUE_OUT12_ZC, 2,
+ out_mux_text);
static const struct snd_kcontrol_new hpr_mux =
SOC_DAPM_ENUM("HPR Mux", hpr_enum);
-static const struct soc_enum linel_enum =
- SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 1, 2, out_mux_text);
+static SOC_ENUM_SINGLE_DECL(linel_enum, WM8904_ANALOGUE_OUT12_ZC, 1,
+ out_mux_text);
static const struct snd_kcontrol_new linel_mux =
SOC_DAPM_ENUM("LINEL Mux", linel_enum);
-static const struct soc_enum liner_enum =
- SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text);
+static SOC_ENUM_SINGLE_DECL(liner_enum, WM8904_ANALOGUE_OUT12_ZC, 0,
+ out_mux_text);
static const struct snd_kcontrol_new liner_mux =
SOC_DAPM_ENUM("LINER Mux", liner_enum);
@@ -1019,14 +1020,14 @@ static const char *sidetone_text[] = {
"None", "Left", "Right"
};
-static const struct soc_enum dacl_sidetone_enum =
- SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 2, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(dacl_sidetone_enum, WM8904_DAC_DIGITAL_0, 2,
+ sidetone_text);
static const struct snd_kcontrol_new dacl_sidetone_mux =
SOC_DAPM_ENUM("Left Sidetone Mux", dacl_sidetone_enum);
-static const struct soc_enum dacr_sidetone_enum =
- SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 0, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(dacr_sidetone_enum, WM8904_DAC_DIGITAL_0, 0,
+ sidetone_text);
static const struct snd_kcontrol_new dacr_sidetone_mux =
SOC_DAPM_ENUM("Right Sidetone Mux", dacr_sidetone_enum);
@@ -1981,7 +1982,7 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec)
dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
wm8904->num_retune_mobile_texts);
- wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts;
+ wm8904->retune_mobile_enum.items = wm8904->num_retune_mobile_texts;
wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts;
ret = snd_soc_add_codec_controls(codec, &control, 1);
@@ -2022,7 +2023,7 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec)
for (i = 0; i < pdata->num_drc_cfgs; i++)
wm8904->drc_texts[i] = pdata->drc_cfgs[i].name;
- wm8904->drc_enum.max = pdata->num_drc_cfgs;
+ wm8904->drc_enum.items = pdata->num_drc_cfgs;
wm8904->drc_enum.texts = wm8904->drc_texts;
ret = snd_soc_add_codec_controls(codec, &control, 1);
@@ -2047,9 +2048,6 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec)
static int wm8904_probe(struct snd_soc_codec *codec)
{
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- codec->control_data = wm8904->regmap;
switch (wm8904->devtype) {
case WM8904:
@@ -2063,12 +2061,6 @@ static int wm8904_probe(struct snd_soc_codec *codec)
return -EINVAL;
}
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
wm8904_handle_pdata(codec);
wm8904_add_widgets(codec);
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index b404c26c1753..fc6eec9ad66b 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -154,22 +154,22 @@ static const struct reg_default wm8940_reg_defaults[] = {
};
static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" };
-static const struct soc_enum wm8940_adc_companding_enum
-= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding);
-static const struct soc_enum wm8940_dac_companding_enum
-= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 3, 4, wm8940_companding);
+static SOC_ENUM_SINGLE_DECL(wm8940_adc_companding_enum,
+ WM8940_COMPANDINGCTL, 1, wm8940_companding);
+static SOC_ENUM_SINGLE_DECL(wm8940_dac_companding_enum,
+ WM8940_COMPANDINGCTL, 3, wm8940_companding);
static const char *wm8940_alc_mode_text[] = {"ALC", "Limiter"};
-static const struct soc_enum wm8940_alc_mode_enum
-= SOC_ENUM_SINGLE(WM8940_ALC3, 8, 2, wm8940_alc_mode_text);
+static SOC_ENUM_SINGLE_DECL(wm8940_alc_mode_enum,
+ WM8940_ALC3, 8, wm8940_alc_mode_text);
static const char *wm8940_mic_bias_level_text[] = {"0.9", "0.65"};
-static const struct soc_enum wm8940_mic_bias_level_enum
-= SOC_ENUM_SINGLE(WM8940_INPUTCTL, 8, 2, wm8940_mic_bias_level_text);
+static SOC_ENUM_SINGLE_DECL(wm8940_mic_bias_level_enum,
+ WM8940_INPUTCTL, 8, wm8940_mic_bias_level_text);
static const char *wm8940_filter_mode_text[] = {"Audio", "Application"};
-static const struct soc_enum wm8940_filter_mode_enum
-= SOC_ENUM_SINGLE(WM8940_ADC, 7, 2, wm8940_filter_mode_text);
+static SOC_ENUM_SINGLE_DECL(wm8940_filter_mode_enum,
+ WM8940_ADC, 7, wm8940_filter_mode_text);
static DECLARE_TLV_DB_SCALE(wm8940_spk_vol_tlv, -5700, 100, 1);
static DECLARE_TLV_DB_SCALE(wm8940_att_tlv, -1000, 1000, 0);
@@ -712,12 +712,6 @@ static int wm8940_probe(struct snd_soc_codec *codec)
int ret;
u16 reg;
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = wm8940_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 82c8ba975720..fecd4e4f4c57 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -416,22 +416,21 @@ static const char *bass_mode_text[] = {
"Linear", "Adaptive",
};
-static const struct soc_enum bass_mode =
- SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 7, 2, bass_mode_text);
+static SOC_ENUM_SINGLE_DECL(bass_mode, WM8955_BASS_CONTROL, 7, bass_mode_text);
static const char *bass_cutoff_text[] = {
"Low", "High"
};
-static const struct soc_enum bass_cutoff =
- SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 6, 2, bass_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(bass_cutoff, WM8955_BASS_CONTROL, 6,
+ bass_cutoff_text);
static const char *treble_cutoff_text[] = {
"High", "Low"
};
-static const struct soc_enum treble_cutoff =
- SOC_ENUM_SINGLE(WM8955_TREBLE_CONTROL, 6, 2, treble_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(treble_cutoff, WM8955_TREBLE_CONTROL, 2,
+ treble_cutoff_text);
static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
static const DECLARE_TLV_DB_SCALE(atten_tlv, -600, 600, 0);
@@ -896,14 +895,6 @@ static int wm8955_probe(struct snd_soc_codec *codec)
struct wm8955_pdata *pdata = dev_get_platdata(codec->dev);
int ret, i;
- codec->control_data = wm8955->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
wm8955->supplies[i].supply = wm8955_supply_names[i];
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
index b7488f190d2b..7ac2e511403c 100644
--- a/sound/soc/codecs/wm8958-dsp2.c
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -153,7 +153,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
data32 &= 0xffffff;
- wm8994_bulk_write(codec->control_data,
+ wm8994_bulk_write(wm8994->wm8994,
data32 & 0xffffff,
block_len / 2,
(void *)(data + 8));
@@ -944,7 +944,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
for (i = 0; i < pdata->num_mbc_cfgs; i++)
wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
- wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
+ wm8994->mbc_enum.items = pdata->num_mbc_cfgs;
wm8994->mbc_enum.texts = wm8994->mbc_texts;
ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
@@ -973,7 +973,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
for (i = 0; i < pdata->num_vss_cfgs; i++)
wm8994->vss_texts[i] = pdata->vss_cfgs[i].name;
- wm8994->vss_enum.max = pdata->num_vss_cfgs;
+ wm8994->vss_enum.items = pdata->num_vss_cfgs;
wm8994->vss_enum.texts = wm8994->vss_texts;
ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
@@ -1003,7 +1003,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
for (i = 0; i < pdata->num_vss_hpf_cfgs; i++)
wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name;
- wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs;
+ wm8994->vss_hpf_enum.items = pdata->num_vss_hpf_cfgs;
wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
@@ -1034,7 +1034,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
for (i = 0; i < pdata->num_enh_eq_cfgs; i++)
wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name;
- wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs;
+ wm8994->enh_eq_enum.items = pdata->num_enh_eq_cfgs;
wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index f156010e52bc..d04e9cad445c 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -976,12 +976,6 @@ static int wm8960_probe(struct snd_soc_codec *codec)
wm8960->set_bias_level = wm8960_set_bias_level_capless;
}
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = wm8960_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 900328e28a15..9c88f04442b3 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -317,15 +317,15 @@ static const char *adc_hpf_text[] = {
"Hi-fi", "Voice 1", "Voice 2", "Voice 3",
};
-static const struct soc_enum adc_hpf =
- SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_2, 7, 4, adc_hpf_text);
+static SOC_ENUM_SINGLE_DECL(adc_hpf,
+ WM8961_ADC_DAC_CONTROL_2, 7, adc_hpf_text);
static const char *dac_deemph_text[] = {
"None", "32kHz", "44.1kHz", "48kHz",
};
-static const struct soc_enum dac_deemph =
- SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_1, 1, 4, dac_deemph_text);
+static SOC_ENUM_SINGLE_DECL(dac_deemph,
+ WM8961_ADC_DAC_CONTROL_1, 1, dac_deemph_text);
static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
static const DECLARE_TLV_DB_SCALE(hp_sec_tlv, -700, 100, 0);
@@ -385,11 +385,11 @@ static const char *sidetone_text[] = {
"None", "Left", "Right"
};
-static const struct soc_enum dacl_sidetone =
- SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_0, 2, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(dacl_sidetone,
+ WM8961_DSP_SIDETONE_0, 2, sidetone_text);
-static const struct soc_enum dacr_sidetone =
- SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_1, 2, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(dacr_sidetone,
+ WM8961_DSP_SIDETONE_1, 2, sidetone_text);
static const struct snd_kcontrol_new dacl_mux =
SOC_DAPM_ENUM("DACL Sidetone", dacl_sidetone);
@@ -836,15 +836,8 @@ static struct snd_soc_dai_driver wm8961_dai = {
static int wm8961_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret = 0;
u16 reg;
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* Enable class W */
reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_B);
reg |= WM8961_CP_DYN_PWR_MASK;
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 97db3b45b411..5522d2566c67 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -1479,7 +1479,9 @@ static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static int wm8962_dsp2_write_config(struct snd_soc_codec *codec)
{
- return regcache_sync_region(codec->control_data,
+ struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+
+ return regcache_sync_region(wm8962->regmap,
WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER);
}
@@ -1658,16 +1660,16 @@ static const char *cap_hpf_mode_text[] = {
"Hi-fi", "Application"
};
-static const struct soc_enum cap_hpf_mode =
- SOC_ENUM_SINGLE(WM8962_ADC_DAC_CONTROL_2, 10, 2, cap_hpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(cap_hpf_mode,
+ WM8962_ADC_DAC_CONTROL_2, 10, cap_hpf_mode_text);
static const char *cap_lhpf_mode_text[] = {
"LPF", "HPF"
};
-static const struct soc_enum cap_lhpf_mode =
- SOC_ENUM_SINGLE(WM8962_LHPF1, 1, 2, cap_lhpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(cap_lhpf_mode,
+ WM8962_LHPF1, 1, cap_lhpf_mode_text);
static const struct snd_kcontrol_new wm8962_snd_controls[] = {
SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1),
@@ -2014,40 +2016,40 @@ static int dsp2_event(struct snd_soc_dapm_widget *w,
static const char *st_text[] = { "None", "Left", "Right" };
-static const struct soc_enum str_enum =
- SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_1, 2, 3, st_text);
+static SOC_ENUM_SINGLE_DECL(str_enum,
+ WM8962_DAC_DSP_MIXING_1, 2, st_text);
static const struct snd_kcontrol_new str_mux =
SOC_DAPM_ENUM("Right Sidetone", str_enum);
-static const struct soc_enum stl_enum =
- SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_2, 2, 3, st_text);
+static SOC_ENUM_SINGLE_DECL(stl_enum,
+ WM8962_DAC_DSP_MIXING_2, 2, st_text);
static const struct snd_kcontrol_new stl_mux =
SOC_DAPM_ENUM("Left Sidetone", stl_enum);
static const char *outmux_text[] = { "DAC", "Mixer" };
-static const struct soc_enum spkoutr_enum =
- SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_2, 7, 2, outmux_text);
+static SOC_ENUM_SINGLE_DECL(spkoutr_enum,
+ WM8962_SPEAKER_MIXER_2, 7, outmux_text);
static const struct snd_kcontrol_new spkoutr_mux =
SOC_DAPM_ENUM("SPKOUTR Mux", spkoutr_enum);
-static const struct soc_enum spkoutl_enum =
- SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_1, 7, 2, outmux_text);
+static SOC_ENUM_SINGLE_DECL(spkoutl_enum,
+ WM8962_SPEAKER_MIXER_1, 7, outmux_text);
static const struct snd_kcontrol_new spkoutl_mux =
SOC_DAPM_ENUM("SPKOUTL Mux", spkoutl_enum);
-static const struct soc_enum hpoutr_enum =
- SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_2, 7, 2, outmux_text);
+static SOC_ENUM_SINGLE_DECL(hpoutr_enum,
+ WM8962_HEADPHONE_MIXER_2, 7, outmux_text);
static const struct snd_kcontrol_new hpoutr_mux =
SOC_DAPM_ENUM("HPOUTR Mux", hpoutr_enum);
-static const struct soc_enum hpoutl_enum =
- SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_1, 7, 2, outmux_text);
+static SOC_ENUM_SINGLE_DECL(hpoutl_enum,
+ WM8962_HEADPHONE_MIXER_1, 7, outmux_text);
static const struct snd_kcontrol_new hpoutl_mux =
SOC_DAPM_ENUM("HPOUTL Mux", hpoutl_enum);
@@ -2884,9 +2886,13 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda);
snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n);
- try_wait_for_completion(&wm8962->fll_lock);
+ reinit_completion(&wm8962->fll_lock);
- pm_runtime_get_sync(codec->dev);
+ ret = pm_runtime_get_sync(codec->dev);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to resume device: %d\n", ret);
+ return ret;
+ }
snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
@@ -2894,8 +2900,6 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
- ret = 0;
-
/* This should be a massive overestimate but go even
* higher if we'll error out
*/
@@ -2909,14 +2913,17 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
if (timeout == 0 && wm8962->irq) {
dev_err(codec->dev, "FLL lock timed out");
- ret = -ETIMEDOUT;
+ snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+ WM8962_FLL_ENA, 0);
+ pm_runtime_put(codec->dev);
+ return -ETIMEDOUT;
}
wm8962->fll_fref = Fref;
wm8962->fll_fout = Fout;
wm8962->fll_src = source;
- return ret;
+ return 0;
}
static int wm8962_mute(struct snd_soc_dai *dai, int mute)
@@ -3003,9 +3010,16 @@ static irqreturn_t wm8962_irq(int irq, void *data)
unsigned int active;
int reg, ret;
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to resume: %d\n", ret);
+ return IRQ_NONE;
+ }
+
ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2_MASK,
&mask);
if (ret != 0) {
+ pm_runtime_put(dev);
dev_err(dev, "Failed to read interrupt mask: %d\n",
ret);
return IRQ_NONE;
@@ -3013,14 +3027,17 @@ static irqreturn_t wm8962_irq(int irq, void *data)
ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, &active);
if (ret != 0) {
+ pm_runtime_put(dev);
dev_err(dev, "Failed to read interrupt: %d\n", ret);
return IRQ_NONE;
}
active &= ~mask;
- if (!active)
+ if (!active) {
+ pm_runtime_put(dev);
return IRQ_NONE;
+ }
/* Acknowledge the interrupts */
ret = regmap_write(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, active);
@@ -3070,6 +3087,8 @@ static irqreturn_t wm8962_irq(int irq, void *data)
msecs_to_jiffies(250));
}
+ pm_runtime_put(dev);
+
return IRQ_HANDLED;
}
@@ -3089,6 +3108,7 @@ static irqreturn_t wm8962_irq(int irq, void *data)
int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
{
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
int irq_mask, enable;
wm8962->jack = jack;
@@ -3109,14 +3129,18 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
snd_soc_jack_report(wm8962->jack, 0,
SND_JACK_MICROPHONE | SND_JACK_BTN_0);
+ snd_soc_dapm_mutex_lock(dapm);
+
if (jack) {
- snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
- snd_soc_dapm_force_enable_pin(&codec->dapm, "MICBIAS");
+ snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK");
+ snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS");
} else {
- snd_soc_dapm_disable_pin(&codec->dapm, "SYSCLK");
- snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "SYSCLK");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS");
}
+ snd_soc_dapm_mutex_unlock(dapm);
+
return 0;
}
EXPORT_SYMBOL_GPL(wm8962_mic_detect);
@@ -3400,13 +3424,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)
bool dmicclk, dmicdat;
wm8962->codec = codec;
- codec->control_data = wm8962->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0;
wm8962->disable_nb[1].notifier_call = wm8962_regulator_event_1;
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 67aba78a7ca5..09b7b4200221 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -648,12 +648,6 @@ static int wm8971_probe(struct snd_soc_codec *codec)
int ret = 0;
u16 reg;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8971_work);
wm8971_workq = create_workqueue("wm8971");
if (wm8971_workq == NULL)
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 15f45c7bd833..0627c56fa44e 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -84,8 +84,8 @@ static const struct soc_enum wm8974_enum[] = {
static const char *wm8974_auxmode_text[] = { "Buffer", "Mixer" };
-static const struct soc_enum wm8974_auxmode =
- SOC_ENUM_SINGLE(WM8974_INPUT, 3, 2, wm8974_auxmode_text);
+static SOC_ENUM_SINGLE_DECL(wm8974_auxmode,
+ WM8974_INPUT, 3, wm8974_auxmode_text);
static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
@@ -593,12 +593,6 @@ static int wm8974_probe(struct snd_soc_codec *codec)
{
int ret = 0;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = wm8974_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index d8fc531c0e59..28ef46c91f62 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -117,21 +117,21 @@ static const char *wm8978_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"};
static const char *wm8978_alc3[] = {"ALC", "Limiter"};
static const char *wm8978_alc1[] = {"Off", "Right", "Left", "Both"};
-static const SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1,
- wm8978_companding);
-static const SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3,
- wm8978_companding);
-static const SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode);
-static const SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1);
-static const SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw);
-static const SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2);
-static const SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw);
-static const SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3);
-static const SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw);
-static const SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4);
-static const SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5);
-static const SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3);
-static const SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1);
+static SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1,
+ wm8978_companding);
+static SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3,
+ wm8978_companding);
+static SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode);
+static SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1);
+static SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw);
+static SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2);
+static SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw);
+static SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3);
+static SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw);
+static SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4);
+static SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5);
+static SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3);
+static SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1);
static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
@@ -975,19 +975,13 @@ static const int update_reg[] = {
static int wm8978_probe(struct snd_soc_codec *codec)
{
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
- int ret = 0, i;
+ int i;
/*
* Set default system clock to PLL, it is more precise, this is also the
* default hardware setting
*/
wm8978->sysclk = WM8978_PLL;
- codec->control_data = wm8978->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
/*
* Set the update bit in all registers, that have one. This way all
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index aa41ba0dfff4..2b9bfa53efbf 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -205,49 +205,44 @@ static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0);
static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" };
-static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7,
- alc_sel_text);
+static SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7, alc_sel_text);
static const char *alc_mode_text[] = { "ALC", "Limiter" };
-static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8,
- alc_mode_text);
+static SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8, alc_mode_text);
static const char *filter_mode_text[] = { "Audio", "Application" };
-static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7,
- filter_mode_text);
+static SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7,
+ filter_mode_text);
static const char *eq_bw_text[] = { "Narrow", "Wide" };
static const char *eqmode_text[] = { "Capture", "Playback" };
-static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
+static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
static const char *eq1_cutoff_text[] = {
"80Hz", "105Hz", "135Hz", "175Hz"
};
-static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5,
- eq1_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5,
+ eq1_cutoff_text);
static const char *eq2_cutoff_text[] = {
"230Hz", "300Hz", "385Hz", "500Hz"
};
-static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text);
-static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5,
- eq2_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5, eq2_cutoff_text);
static const char *eq3_cutoff_text[] = {
"650Hz", "850Hz", "1.1kHz", "1.4kHz"
};
-static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text);
-static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5,
- eq3_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5, eq3_cutoff_text);
static const char *eq4_cutoff_text[] = {
"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"
};
-static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text);
-static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5,
- eq4_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5, eq4_cutoff_text);
static const char *eq5_cutoff_text[] = {
"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"
};
-static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5,
- eq5_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5,
+ eq5_cutoff_text);
static const char *depth_3d_text[] = {
"Off",
@@ -267,8 +262,8 @@ static const char *depth_3d_text[] = {
"93.3%",
"100%"
};
-static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0,
- depth_3d_text);
+static SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0,
+ depth_3d_text);
static const struct snd_kcontrol_new wm8983_snd_controls[] = {
SOC_SINGLE("Digital Loopback Switch", WM8983_COMPANDING_CONTROL,
@@ -1000,12 +995,6 @@ static int wm8983_probe(struct snd_soc_codec *codec)
int ret;
int i;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
- return ret;
- }
-
ret = snd_soc_write(codec, WM8983_SOFTWARE_RESET, 0);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
@@ -1129,7 +1118,7 @@ static struct spi_driver wm8983_spi_driver = {
};
#endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8983_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1182,7 +1171,7 @@ static int __init wm8983_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8983_i2c_driver);
if (ret) {
printk(KERN_ERR "Failed to register wm8983 I2C driver: %d\n",
@@ -1202,7 +1191,7 @@ module_init(wm8983_modinit);
static void __exit wm8983_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8983_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 271b517911a4..5473dc969585 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -226,52 +226,48 @@ static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0);
static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" };
-static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7,
- alc_sel_text);
+static SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7, alc_sel_text);
static const char *alc_mode_text[] = { "ALC", "Limiter" };
-static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8,
- alc_mode_text);
+static SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8, alc_mode_text);
static const char *filter_mode_text[] = { "Audio", "Application" };
-static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7,
- filter_mode_text);
+static SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7,
+ filter_mode_text);
static const char *eq_bw_text[] = { "Narrow", "Wide" };
static const char *eqmode_text[] = { "Capture", "Playback" };
-static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
+static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
static const char *eq1_cutoff_text[] = {
"80Hz", "105Hz", "135Hz", "175Hz"
};
-static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5,
- eq1_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5,
+ eq1_cutoff_text);
static const char *eq2_cutoff_text[] = {
"230Hz", "300Hz", "385Hz", "500Hz"
};
-static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text);
-static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5,
- eq2_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5, eq2_cutoff_text);
static const char *eq3_cutoff_text[] = {
"650Hz", "850Hz", "1.1kHz", "1.4kHz"
};
-static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text);
-static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5,
- eq3_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5,
+ eq3_cutoff_text);
static const char *eq4_cutoff_text[] = {
"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"
};
-static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text);
-static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5,
- eq4_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text);
+static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5, eq4_cutoff_text);
static const char *eq5_cutoff_text[] = {
"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"
};
-static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5,
+static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5,
eq5_cutoff_text);
static const char *speaker_mode_text[] = { "Class A/B", "Class D" };
-static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text);
+static SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text);
static const char *depth_3d_text[] = {
"Off",
@@ -291,8 +287,7 @@ static const char *depth_3d_text[] = {
"93.3%",
"100%"
};
-static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0,
- depth_3d_text);
+static SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0, depth_3d_text);
static const struct snd_kcontrol_new wm8985_snd_controls[] = {
SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL,
@@ -1000,13 +995,6 @@ static int wm8985_probe(struct snd_soc_codec *codec)
int ret;
wm8985 = snd_soc_codec_get_drvdata(codec);
- codec->control_data = wm8985->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
- return ret;
- }
for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++)
wm8985->supplies[i].supply = wm8985_supply_names[i];
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index a55e1c2c382e..3a1ae4f5164d 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -116,7 +116,7 @@ static bool wm8988_writeable(struct device *dev, unsigned int reg)
struct wm8988_priv {
struct regmap *regmap;
unsigned int sysclk;
- struct snd_pcm_hw_constraint_list *sysclk_constraints;
+ const struct snd_pcm_hw_constraint_list *sysclk_constraints;
};
#define wm8988_reset(c) snd_soc_write(c, WM8988_RESET, 0)
@@ -126,46 +126,46 @@ struct wm8988_priv {
*/
static const char *bass_boost_txt[] = {"Linear Control", "Adaptive Boost"};
-static const struct soc_enum bass_boost =
- SOC_ENUM_SINGLE(WM8988_BASS, 7, 2, bass_boost_txt);
+static SOC_ENUM_SINGLE_DECL(bass_boost,
+ WM8988_BASS, 7, bass_boost_txt);
static const char *bass_filter_txt[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
-static const struct soc_enum bass_filter =
- SOC_ENUM_SINGLE(WM8988_BASS, 6, 2, bass_filter_txt);
+static SOC_ENUM_SINGLE_DECL(bass_filter,
+ WM8988_BASS, 6, bass_filter_txt);
static const char *treble_txt[] = {"8kHz", "4kHz"};
-static const struct soc_enum treble =
- SOC_ENUM_SINGLE(WM8988_TREBLE, 6, 2, treble_txt);
+static SOC_ENUM_SINGLE_DECL(treble,
+ WM8988_TREBLE, 6, treble_txt);
static const char *stereo_3d_lc_txt[] = {"200Hz", "500Hz"};
-static const struct soc_enum stereo_3d_lc =
- SOC_ENUM_SINGLE(WM8988_3D, 5, 2, stereo_3d_lc_txt);
+static SOC_ENUM_SINGLE_DECL(stereo_3d_lc,
+ WM8988_3D, 5, stereo_3d_lc_txt);
static const char *stereo_3d_uc_txt[] = {"2.2kHz", "1.5kHz"};
-static const struct soc_enum stereo_3d_uc =
- SOC_ENUM_SINGLE(WM8988_3D, 6, 2, stereo_3d_uc_txt);
+static SOC_ENUM_SINGLE_DECL(stereo_3d_uc,
+ WM8988_3D, 6, stereo_3d_uc_txt);
static const char *stereo_3d_func_txt[] = {"Capture", "Playback"};
-static const struct soc_enum stereo_3d_func =
- SOC_ENUM_SINGLE(WM8988_3D, 7, 2, stereo_3d_func_txt);
+static SOC_ENUM_SINGLE_DECL(stereo_3d_func,
+ WM8988_3D, 7, stereo_3d_func_txt);
static const char *alc_func_txt[] = {"Off", "Right", "Left", "Stereo"};
-static const struct soc_enum alc_func =
- SOC_ENUM_SINGLE(WM8988_ALC1, 7, 4, alc_func_txt);
+static SOC_ENUM_SINGLE_DECL(alc_func,
+ WM8988_ALC1, 7, alc_func_txt);
static const char *ng_type_txt[] = {"Constant PGA Gain",
"Mute ADC Output"};
-static const struct soc_enum ng_type =
- SOC_ENUM_SINGLE(WM8988_NGATE, 1, 2, ng_type_txt);
+static SOC_ENUM_SINGLE_DECL(ng_type,
+ WM8988_NGATE, 1, ng_type_txt);
static const char *deemph_txt[] = {"None", "32Khz", "44.1Khz", "48Khz"};
-static const struct soc_enum deemph =
- SOC_ENUM_SINGLE(WM8988_ADCDAC, 1, 4, deemph_txt);
+static SOC_ENUM_SINGLE_DECL(deemph,
+ WM8988_ADCDAC, 1, deemph_txt);
static const char *adcpol_txt[] = {"Normal", "L Invert", "R Invert",
"L + R Invert"};
-static const struct soc_enum adcpol =
- SOC_ENUM_SINGLE(WM8988_ADCDAC, 5, 4, adcpol_txt);
+static SOC_ENUM_SINGLE_DECL(adcpol,
+ WM8988_ADCDAC, 5, adcpol_txt);
static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);
static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
@@ -317,16 +317,16 @@ static const struct snd_kcontrol_new wm8988_right_pga_controls =
/* Differential Mux */
static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"};
-static const struct soc_enum diffmux =
- SOC_ENUM_SINGLE(WM8988_ADCIN, 8, 2, wm8988_diff_sel);
+static SOC_ENUM_SINGLE_DECL(diffmux,
+ WM8988_ADCIN, 8, wm8988_diff_sel);
static const struct snd_kcontrol_new wm8988_diffmux_controls =
SOC_DAPM_ENUM("Route", diffmux);
/* Mono ADC Mux */
static const char *wm8988_mono_mux[] = {"Stereo", "Mono (Left)",
"Mono (Right)", "Digital Mono"};
-static const struct soc_enum monomux =
- SOC_ENUM_SINGLE(WM8988_ADCIN, 6, 4, wm8988_mono_mux);
+static SOC_ENUM_SINGLE_DECL(monomux,
+ WM8988_ADCIN, 6, wm8988_mono_mux);
static const struct snd_kcontrol_new wm8988_monomux_controls =
SOC_DAPM_ENUM("Route", monomux);
@@ -521,30 +521,30 @@ static inline int get_coeff(int mclk, int rate)
/* The set of rates we can generate from the above for each SYSCLK */
-static unsigned int rates_12288[] = {
+static const unsigned int rates_12288[] = {
8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000,
};
-static struct snd_pcm_hw_constraint_list constraints_12288 = {
+static const struct snd_pcm_hw_constraint_list constraints_12288 = {
.count = ARRAY_SIZE(rates_12288),
.list = rates_12288,
};
-static unsigned int rates_112896[] = {
+static const unsigned int rates_112896[] = {
8000, 11025, 22050, 44100,
};
-static struct snd_pcm_hw_constraint_list constraints_112896 = {
+static const struct snd_pcm_hw_constraint_list constraints_112896 = {
.count = ARRAY_SIZE(rates_112896),
.list = rates_112896,
};
-static unsigned int rates_12[] = {
+static const unsigned int rates_12[] = {
8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000,
48000, 88235, 96000,
};
-static struct snd_pcm_hw_constraint_list constraints_12 = {
+static const struct snd_pcm_hw_constraint_list constraints_12 = {
.count = ARRAY_SIZE(rates_12),
.list = rates_12,
};
@@ -810,16 +810,8 @@ static int wm8988_resume(struct snd_soc_codec *codec)
static int wm8988_probe(struct snd_soc_codec *codec)
{
- struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- codec->control_data = wm8988->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
ret = wm8988_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 0ccd4d8d043b..c413c1991453 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -157,26 +157,23 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
static const char *wm8990_digital_sidetone[] =
{"None", "Left ADC", "Right ADC", "Reserved"};
-static const struct soc_enum wm8990_left_digital_sidetone_enum =
-SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE,
- WM8990_ADC_TO_DACL_SHIFT,
- WM8990_ADC_TO_DACL_MASK,
- wm8990_digital_sidetone);
-
-static const struct soc_enum wm8990_right_digital_sidetone_enum =
-SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE,
- WM8990_ADC_TO_DACR_SHIFT,
- WM8990_ADC_TO_DACR_MASK,
- wm8990_digital_sidetone);
+static SOC_ENUM_SINGLE_DECL(wm8990_left_digital_sidetone_enum,
+ WM8990_DIGITAL_SIDE_TONE,
+ WM8990_ADC_TO_DACL_SHIFT,
+ wm8990_digital_sidetone);
+
+static SOC_ENUM_SINGLE_DECL(wm8990_right_digital_sidetone_enum,
+ WM8990_DIGITAL_SIDE_TONE,
+ WM8990_ADC_TO_DACR_SHIFT,
+ wm8990_digital_sidetone);
static const char *wm8990_adcmode[] =
{"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
-static const struct soc_enum wm8990_right_adcmode_enum =
-SOC_ENUM_SINGLE(WM8990_ADC_CTRL,
- WM8990_ADC_HPF_CUT_SHIFT,
- WM8990_ADC_HPF_CUT_MASK,
- wm8990_adcmode);
+static SOC_ENUM_SINGLE_DECL(wm8990_right_adcmode_enum,
+ WM8990_ADC_CTRL,
+ WM8990_ADC_HPF_CUT_SHIFT,
+ wm8990_adcmode);
static const struct snd_kcontrol_new wm8990_snd_controls[] = {
/* INMIXL */
@@ -475,9 +472,9 @@ SOC_DAPM_SINGLE("RINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT,
static const char *wm8990_ainlmux[] =
{"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
-static const struct soc_enum wm8990_ainlmux_enum =
-SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT,
- ARRAY_SIZE(wm8990_ainlmux), wm8990_ainlmux);
+static SOC_ENUM_SINGLE_DECL(wm8990_ainlmux_enum,
+ WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT,
+ wm8990_ainlmux);
static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls =
SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum);
@@ -488,9 +485,9 @@ SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum);
static const char *wm8990_ainrmux[] =
{"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
-static const struct soc_enum wm8990_ainrmux_enum =
-SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT,
- ARRAY_SIZE(wm8990_ainrmux), wm8990_ainrmux);
+static SOC_ENUM_SINGLE_DECL(wm8990_ainrmux_enum,
+ WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT,
+ wm8990_ainrmux);
static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls =
SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum);
@@ -1292,14 +1289,6 @@ static int wm8990_resume(struct snd_soc_codec *codec)
*/
static int wm8990_probe(struct snd_soc_codec *codec)
{
- int ret;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret < 0) {
- printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
wm8990_reset(codec);
/* charge output caps */
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index dba0306c42a5..844cc4a60d66 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -171,26 +171,23 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
static const char *wm8991_digital_sidetone[] =
{"None", "Left ADC", "Right ADC", "Reserved"};
-static const struct soc_enum wm8991_left_digital_sidetone_enum =
- SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE,
- WM8991_ADC_TO_DACL_SHIFT,
- WM8991_ADC_TO_DACL_MASK,
- wm8991_digital_sidetone);
-
-static const struct soc_enum wm8991_right_digital_sidetone_enum =
- SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE,
- WM8991_ADC_TO_DACR_SHIFT,
- WM8991_ADC_TO_DACR_MASK,
- wm8991_digital_sidetone);
+static SOC_ENUM_SINGLE_DECL(wm8991_left_digital_sidetone_enum,
+ WM8991_DIGITAL_SIDE_TONE,
+ WM8991_ADC_TO_DACL_SHIFT,
+ wm8991_digital_sidetone);
+
+static SOC_ENUM_SINGLE_DECL(wm8991_right_digital_sidetone_enum,
+ WM8991_DIGITAL_SIDE_TONE,
+ WM8991_ADC_TO_DACR_SHIFT,
+ wm8991_digital_sidetone);
static const char *wm8991_adcmode[] =
{"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
-static const struct soc_enum wm8991_right_adcmode_enum =
- SOC_ENUM_SINGLE(WM8991_ADC_CTRL,
- WM8991_ADC_HPF_CUT_SHIFT,
- WM8991_ADC_HPF_CUT_MASK,
- wm8991_adcmode);
+static SOC_ENUM_SINGLE_DECL(wm8991_right_adcmode_enum,
+ WM8991_ADC_CTRL,
+ WM8991_ADC_HPF_CUT_SHIFT,
+ wm8991_adcmode);
static const struct snd_kcontrol_new wm8991_snd_controls[] = {
/* INMIXL */
@@ -486,9 +483,9 @@ static const struct snd_kcontrol_new wm8991_dapm_inmixr_controls[] = {
static const char *wm8991_ainlmux[] =
{"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
-static const struct soc_enum wm8991_ainlmux_enum =
- SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT,
- ARRAY_SIZE(wm8991_ainlmux), wm8991_ainlmux);
+static SOC_ENUM_SINGLE_DECL(wm8991_ainlmux_enum,
+ WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT,
+ wm8991_ainlmux);
static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls =
SOC_DAPM_ENUM("Route", wm8991_ainlmux_enum);
@@ -499,9 +496,9 @@ static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls =
static const char *wm8991_ainrmux[] =
{"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
-static const struct soc_enum wm8991_ainrmux_enum =
- SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT,
- ARRAY_SIZE(wm8991_ainrmux), wm8991_ainrmux);
+static SOC_ENUM_SINGLE_DECL(wm8991_ainrmux_enum,
+ WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT,
+ wm8991_ainrmux);
static const struct snd_kcontrol_new wm8991_dapm_ainrmux_controls =
SOC_DAPM_ENUM("Route", wm8991_ainrmux_enum);
@@ -1251,17 +1248,6 @@ static int wm8991_remove(struct snd_soc_codec *codec)
static int wm8991_probe(struct snd_soc_codec *codec)
{
- struct wm8991_priv *wm8991;
- int ret;
-
- wm8991 = snd_soc_codec_get_drvdata(codec);
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
- return ret;
- }
-
wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 433d59a0f3ef..f825dc04ebe1 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -646,8 +646,8 @@ static const char *dac_deemph_text[] = {
"48kHz",
};
-static const struct soc_enum dac_deemph =
- SOC_ENUM_SINGLE(WM8993_DAC_CTRL, 4, 4, dac_deemph_text);
+static SOC_ENUM_SINGLE_DECL(dac_deemph,
+ WM8993_DAC_CTRL, 4, dac_deemph_text);
static const char *adc_hpf_text[] = {
"Hi-Fi",
@@ -656,16 +656,16 @@ static const char *adc_hpf_text[] = {
"Voice 3",
};
-static const struct soc_enum adc_hpf =
- SOC_ENUM_SINGLE(WM8993_ADC_CTRL, 5, 4, adc_hpf_text);
+static SOC_ENUM_SINGLE_DECL(adc_hpf,
+ WM8993_ADC_CTRL, 5, adc_hpf_text);
static const char *drc_path_text[] = {
"ADC",
"DAC"
};
-static const struct soc_enum drc_path =
- SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 14, 2, drc_path_text);
+static SOC_ENUM_SINGLE_DECL(drc_path,
+ WM8993_DRC_CONTROL_1, 14, drc_path_text);
static const char *drc_r0_text[] = {
"1",
@@ -676,8 +676,8 @@ static const char *drc_r0_text[] = {
"0",
};
-static const struct soc_enum drc_r0 =
- SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 8, 6, drc_r0_text);
+static SOC_ENUM_SINGLE_DECL(drc_r0,
+ WM8993_DRC_CONTROL_3, 8, drc_r0_text);
static const char *drc_r1_text[] = {
"1",
@@ -687,8 +687,8 @@ static const char *drc_r1_text[] = {
"0",
};
-static const struct soc_enum drc_r1 =
- SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_4, 13, 5, drc_r1_text);
+static SOC_ENUM_SINGLE_DECL(drc_r1,
+ WM8993_DRC_CONTROL_4, 13, drc_r1_text);
static const char *drc_attack_text[] = {
"Reserved",
@@ -705,8 +705,8 @@ static const char *drc_attack_text[] = {
"185.6ms",
};
-static const struct soc_enum drc_attack =
- SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 12, 12, drc_attack_text);
+static SOC_ENUM_SINGLE_DECL(drc_attack,
+ WM8993_DRC_CONTROL_2, 12, drc_attack_text);
static const char *drc_decay_text[] = {
"186ms",
@@ -720,16 +720,16 @@ static const char *drc_decay_text[] = {
"47.56ms",
};
-static const struct soc_enum drc_decay =
- SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 8, 9, drc_decay_text);
+static SOC_ENUM_SINGLE_DECL(drc_decay,
+ WM8993_DRC_CONTROL_2, 8, drc_decay_text);
static const char *drc_ff_text[] = {
"5 samples",
"9 samples",
};
-static const struct soc_enum drc_ff =
- SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 7, 2, drc_ff_text);
+static SOC_ENUM_SINGLE_DECL(drc_ff,
+ WM8993_DRC_CONTROL_3, 7, drc_ff_text);
static const char *drc_qr_rate_text[] = {
"0.725ms",
@@ -737,8 +737,8 @@ static const char *drc_qr_rate_text[] = {
"5.8ms",
};
-static const struct soc_enum drc_qr_rate =
- SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 0, 3, drc_qr_rate_text);
+static SOC_ENUM_SINGLE_DECL(drc_qr_rate,
+ WM8993_DRC_CONTROL_3, 0, drc_qr_rate_text);
static const char *drc_smooth_text[] = {
"Low",
@@ -746,8 +746,8 @@ static const char *drc_smooth_text[] = {
"High",
};
-static const struct soc_enum drc_smooth =
- SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 4, 3, drc_smooth_text);
+static SOC_ENUM_SINGLE_DECL(drc_smooth,
+ WM8993_DRC_CONTROL_1, 4, drc_smooth_text);
static const struct snd_kcontrol_new wm8993_snd_controls[] = {
SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE,
@@ -841,26 +841,26 @@ static const char *aif_text[] = {
"Left", "Right"
};
-static const struct soc_enum aifoutl_enum =
- SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 15, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifoutl_enum,
+ WM8993_AUDIO_INTERFACE_1, 15, aif_text);
static const struct snd_kcontrol_new aifoutl_mux =
SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum);
-static const struct soc_enum aifoutr_enum =
- SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 14, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifoutr_enum,
+ WM8993_AUDIO_INTERFACE_1, 14, aif_text);
static const struct snd_kcontrol_new aifoutr_mux =
SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum);
-static const struct soc_enum aifinl_enum =
- SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 15, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifinl_enum,
+ WM8993_AUDIO_INTERFACE_2, 15, aif_text);
static const struct snd_kcontrol_new aifinl_mux =
SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum);
-static const struct soc_enum aifinr_enum =
- SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 14, 2, aif_text);
+static SOC_ENUM_SINGLE_DECL(aifinr_enum,
+ WM8993_AUDIO_INTERFACE_2, 14, aif_text);
static const struct snd_kcontrol_new aifinr_mux =
SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum);
@@ -869,14 +869,14 @@ static const char *sidetone_text[] = {
"None", "Left", "Right"
};
-static const struct soc_enum sidetonel_enum =
- SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 2, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetonel_enum,
+ WM8993_DIGITAL_SIDE_TONE, 2, sidetone_text);
static const struct snd_kcontrol_new sidetonel_mux =
SOC_DAPM_ENUM("Left Sidetone", sidetonel_enum);
-static const struct soc_enum sidetoner_enum =
- SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 0, 3, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetoner_enum,
+ WM8993_DIGITAL_SIDE_TONE, 0, sidetone_text);
static const struct snd_kcontrol_new sidetoner_mux =
SOC_DAPM_ENUM("Right Sidetone", sidetoner_enum);
@@ -1493,13 +1493,6 @@ static int wm8993_probe(struct snd_soc_codec *codec)
wm8993->hubs_data.dcs_codes_r = -2;
wm8993->hubs_data.series_startup = 1;
- codec->control_data = wm8993->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* Latch volume update bits and default ZC on */
snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
WM8993_DAC_VU, WM8993_DAC_VU);
@@ -1559,10 +1552,7 @@ static int wm8993_probe(struct snd_soc_codec *codec)
static int wm8993_remove(struct snd_soc_codec *codec)
{
- struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
-
wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
- regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
return 0;
}
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index b9be9cbc4603..6303537f54c6 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -265,21 +265,21 @@ static const char *sidetone_hpf_text[] = {
"2.7kHz", "1.35kHz", "675Hz", "370Hz", "180Hz", "90Hz", "45Hz"
};
-static const struct soc_enum sidetone_hpf =
- SOC_ENUM_SINGLE(WM8994_SIDETONE, 7, 7, sidetone_hpf_text);
+static SOC_ENUM_SINGLE_DECL(sidetone_hpf,
+ WM8994_SIDETONE, 7, sidetone_hpf_text);
static const char *adc_hpf_text[] = {
"HiFi", "Voice 1", "Voice 2", "Voice 3"
};
-static const struct soc_enum aif1adc1_hpf =
- SOC_ENUM_SINGLE(WM8994_AIF1_ADC1_FILTERS, 13, 4, adc_hpf_text);
+static SOC_ENUM_SINGLE_DECL(aif1adc1_hpf,
+ WM8994_AIF1_ADC1_FILTERS, 13, adc_hpf_text);
-static const struct soc_enum aif1adc2_hpf =
- SOC_ENUM_SINGLE(WM8994_AIF1_ADC2_FILTERS, 13, 4, adc_hpf_text);
+static SOC_ENUM_SINGLE_DECL(aif1adc2_hpf,
+ WM8994_AIF1_ADC2_FILTERS, 13, adc_hpf_text);
-static const struct soc_enum aif2adc_hpf =
- SOC_ENUM_SINGLE(WM8994_AIF2_ADC_FILTERS, 13, 4, adc_hpf_text);
+static SOC_ENUM_SINGLE_DECL(aif2adc_hpf,
+ WM8994_AIF2_ADC_FILTERS, 13, adc_hpf_text);
static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0);
static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
@@ -501,39 +501,39 @@ static const char *aif_chan_src_text[] = {
"Left", "Right"
};
-static const struct soc_enum aif1adcl_src =
- SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 15, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif1adcl_src,
+ WM8994_AIF1_CONTROL_1, 15, aif_chan_src_text);
-static const struct soc_enum aif1adcr_src =
- SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 14, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif1adcr_src,
+ WM8994_AIF1_CONTROL_1, 14, aif_chan_src_text);
-static const struct soc_enum aif2adcl_src =
- SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 15, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2adcl_src,
+ WM8994_AIF2_CONTROL_1, 15, aif_chan_src_text);
-static const struct soc_enum aif2adcr_src =
- SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 14, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2adcr_src,
+ WM8994_AIF2_CONTROL_1, 14, aif_chan_src_text);
-static const struct soc_enum aif1dacl_src =
- SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 15, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif1dacl_src,
+ WM8994_AIF1_CONTROL_2, 15, aif_chan_src_text);
-static const struct soc_enum aif1dacr_src =
- SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 14, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif1dacr_src,
+ WM8994_AIF1_CONTROL_2, 14, aif_chan_src_text);
-static const struct soc_enum aif2dacl_src =
- SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 15, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2dacl_src,
+ WM8994_AIF2_CONTROL_2, 15, aif_chan_src_text);
-static const struct soc_enum aif2dacr_src =
- SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 14, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2dacr_src,
+ WM8994_AIF2_CONTROL_2, 14, aif_chan_src_text);
static const char *osr_text[] = {
"Low Power", "High Performance",
};
-static const struct soc_enum dac_osr =
- SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 0, 2, osr_text);
+static SOC_ENUM_SINGLE_DECL(dac_osr,
+ WM8994_OVERSAMPLING, 0, osr_text);
-static const struct soc_enum adc_osr =
- SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text);
+static SOC_ENUM_SINGLE_DECL(adc_osr,
+ WM8994_OVERSAMPLING, 1, osr_text);
static const struct snd_kcontrol_new wm8994_snd_controls[] = {
SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
@@ -690,17 +690,20 @@ static const char *wm8958_ng_text[] = {
"30ms", "125ms", "250ms", "500ms",
};
-static const struct soc_enum wm8958_aif1dac1_ng_hold =
- SOC_ENUM_SINGLE(WM8958_AIF1_DAC1_NOISE_GATE,
- WM8958_AIF1DAC1_NG_THR_SHIFT, 4, wm8958_ng_text);
+static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac1_ng_hold,
+ WM8958_AIF1_DAC1_NOISE_GATE,
+ WM8958_AIF1DAC1_NG_THR_SHIFT,
+ wm8958_ng_text);
-static const struct soc_enum wm8958_aif1dac2_ng_hold =
- SOC_ENUM_SINGLE(WM8958_AIF1_DAC2_NOISE_GATE,
- WM8958_AIF1DAC2_NG_THR_SHIFT, 4, wm8958_ng_text);
+static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac2_ng_hold,
+ WM8958_AIF1_DAC2_NOISE_GATE,
+ WM8958_AIF1DAC2_NG_THR_SHIFT,
+ wm8958_ng_text);
-static const struct soc_enum wm8958_aif2dac_ng_hold =
- SOC_ENUM_SINGLE(WM8958_AIF2_DAC_NOISE_GATE,
- WM8958_AIF2DAC_NG_THR_SHIFT, 4, wm8958_ng_text);
+static SOC_ENUM_SINGLE_DECL(wm8958_aif2dac_ng_hold,
+ WM8958_AIF2_DAC_NOISE_GATE,
+ WM8958_AIF2DAC_NG_THR_SHIFT,
+ wm8958_ng_text);
static const struct snd_kcontrol_new wm8958_snd_controls[] = {
SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv),
@@ -1341,8 +1344,7 @@ static const char *adc_mux_text[] = {
"DMIC",
};
-static const struct soc_enum adc_enum =
- SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);
static const struct snd_kcontrol_new adcl_mux =
SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum);
@@ -1478,14 +1480,14 @@ static const char *sidetone_text[] = {
"ADC/DMIC1", "DMIC2",
};
-static const struct soc_enum sidetone1_enum =
- SOC_ENUM_SINGLE(WM8994_SIDETONE, 0, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetone1_enum,
+ WM8994_SIDETONE, 0, sidetone_text);
static const struct snd_kcontrol_new sidetone1_mux =
SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum);
-static const struct soc_enum sidetone2_enum =
- SOC_ENUM_SINGLE(WM8994_SIDETONE, 1, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetone2_enum,
+ WM8994_SIDETONE, 1, sidetone_text);
static const struct snd_kcontrol_new sidetone2_mux =
SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum);
@@ -1498,22 +1500,24 @@ static const char *loopback_text[] = {
"None", "ADCDAT",
};
-static const struct soc_enum aif1_loopback_enum =
- SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, WM8994_AIF1_LOOPBACK_SHIFT, 2,
- loopback_text);
+static SOC_ENUM_SINGLE_DECL(aif1_loopback_enum,
+ WM8994_AIF1_CONTROL_2,
+ WM8994_AIF1_LOOPBACK_SHIFT,
+ loopback_text);
static const struct snd_kcontrol_new aif1_loopback =
SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum);
-static const struct soc_enum aif2_loopback_enum =
- SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, WM8994_AIF2_LOOPBACK_SHIFT, 2,
- loopback_text);
+static SOC_ENUM_SINGLE_DECL(aif2_loopback_enum,
+ WM8994_AIF2_CONTROL_2,
+ WM8994_AIF2_LOOPBACK_SHIFT,
+ loopback_text);
static const struct snd_kcontrol_new aif2_loopback =
SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum);
-static const struct soc_enum aif1dac_enum =
- SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text);
+static SOC_ENUM_SINGLE_DECL(aif1dac_enum,
+ WM8994_POWER_MANAGEMENT_6, 0, aif1dac_text);
static const struct snd_kcontrol_new aif1dac_mux =
SOC_DAPM_ENUM("AIF1DAC Mux", aif1dac_enum);
@@ -1522,8 +1526,8 @@ static const char *aif2dac_text[] = {
"AIF2DACDAT", "AIF3DACDAT",
};
-static const struct soc_enum aif2dac_enum =
- SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 1, 2, aif2dac_text);
+static SOC_ENUM_SINGLE_DECL(aif2dac_enum,
+ WM8994_POWER_MANAGEMENT_6, 1, aif2dac_text);
static const struct snd_kcontrol_new aif2dac_mux =
SOC_DAPM_ENUM("AIF2DAC Mux", aif2dac_enum);
@@ -1532,8 +1536,8 @@ static const char *aif2adc_text[] = {
"AIF2ADCDAT", "AIF3DACDAT",
};
-static const struct soc_enum aif2adc_enum =
- SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 2, 2, aif2adc_text);
+static SOC_ENUM_SINGLE_DECL(aif2adc_enum,
+ WM8994_POWER_MANAGEMENT_6, 2, aif2adc_text);
static const struct snd_kcontrol_new aif2adc_mux =
SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum);
@@ -1542,14 +1546,14 @@ static const char *aif3adc_text[] = {
"AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT", "Mono PCM",
};
-static const struct soc_enum wm8994_aif3adc_enum =
- SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 3, aif3adc_text);
+static SOC_ENUM_SINGLE_DECL(wm8994_aif3adc_enum,
+ WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);
static const struct snd_kcontrol_new wm8994_aif3adc_mux =
SOC_DAPM_ENUM("AIF3ADC Mux", wm8994_aif3adc_enum);
-static const struct soc_enum wm8958_aif3adc_enum =
- SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 4, aif3adc_text);
+static SOC_ENUM_SINGLE_DECL(wm8958_aif3adc_enum,
+ WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);
static const struct snd_kcontrol_new wm8958_aif3adc_mux =
SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum);
@@ -1558,8 +1562,8 @@ static const char *mono_pcm_out_text[] = {
"None", "AIF2ADCL", "AIF2ADCR",
};
-static const struct soc_enum mono_pcm_out_enum =
- SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 9, 3, mono_pcm_out_text);
+static SOC_ENUM_SINGLE_DECL(mono_pcm_out_enum,
+ WM8994_POWER_MANAGEMENT_6, 9, mono_pcm_out_text);
static const struct snd_kcontrol_new mono_pcm_out_mux =
SOC_DAPM_ENUM("Mono PCM Out Mux", mono_pcm_out_enum);
@@ -1569,14 +1573,14 @@ static const char *aif2dac_src_text[] = {
};
/* Note that these two control shouldn't be simultaneously switched to AIF3 */
-static const struct soc_enum aif2dacl_src_enum =
- SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 7, 2, aif2dac_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2dacl_src_enum,
+ WM8994_POWER_MANAGEMENT_6, 7, aif2dac_src_text);
static const struct snd_kcontrol_new aif2dacl_src_mux =
SOC_DAPM_ENUM("AIF2DACL Mux", aif2dacl_src_enum);
-static const struct soc_enum aif2dacr_src_enum =
- SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 8, 2, aif2dac_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2dacr_src_enum,
+ WM8994_POWER_MANAGEMENT_6, 8, aif2dac_src_text);
static const struct snd_kcontrol_new aif2dacr_src_mux =
SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum);
@@ -2549,43 +2553,52 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode)
{
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
switch (mode) {
case WM8994_VMID_NORMAL:
+ snd_soc_dapm_mutex_lock(dapm);
+
if (wm8994->hubs.lineout1_se) {
- snd_soc_dapm_disable_pin(&codec->dapm,
- "LINEOUT1N Driver");
- snd_soc_dapm_disable_pin(&codec->dapm,
- "LINEOUT1P Driver");
+ snd_soc_dapm_disable_pin_unlocked(dapm,
+ "LINEOUT1N Driver");
+ snd_soc_dapm_disable_pin_unlocked(dapm,
+ "LINEOUT1P Driver");
}
if (wm8994->hubs.lineout2_se) {
- snd_soc_dapm_disable_pin(&codec->dapm,
- "LINEOUT2N Driver");
- snd_soc_dapm_disable_pin(&codec->dapm,
- "LINEOUT2P Driver");
+ snd_soc_dapm_disable_pin_unlocked(dapm,
+ "LINEOUT2N Driver");
+ snd_soc_dapm_disable_pin_unlocked(dapm,
+ "LINEOUT2P Driver");
}
/* Do the sync with the old mode to allow it to clean up */
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_sync_unlocked(dapm);
wm8994->vmid_mode = mode;
+
+ snd_soc_dapm_mutex_unlock(dapm);
break;
case WM8994_VMID_FORCE:
+ snd_soc_dapm_mutex_lock(dapm);
+
if (wm8994->hubs.lineout1_se) {
- snd_soc_dapm_force_enable_pin(&codec->dapm,
- "LINEOUT1N Driver");
- snd_soc_dapm_force_enable_pin(&codec->dapm,
- "LINEOUT1P Driver");
+ snd_soc_dapm_force_enable_pin_unlocked(dapm,
+ "LINEOUT1N Driver");
+ snd_soc_dapm_force_enable_pin_unlocked(dapm,
+ "LINEOUT1P Driver");
}
if (wm8994->hubs.lineout2_se) {
- snd_soc_dapm_force_enable_pin(&codec->dapm,
- "LINEOUT2N Driver");
- snd_soc_dapm_force_enable_pin(&codec->dapm,
- "LINEOUT2P Driver");
+ snd_soc_dapm_force_enable_pin_unlocked(dapm,
+ "LINEOUT2N Driver");
+ snd_soc_dapm_force_enable_pin_unlocked(dapm,
+ "LINEOUT2P Driver");
}
wm8994->vmid_mode = mode;
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_sync_unlocked(dapm);
+
+ snd_soc_dapm_mutex_unlock(dapm);
break;
default:
@@ -3237,7 +3250,7 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
wm8994->num_retune_mobile_texts);
- wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts;
+ wm8994->retune_mobile_enum.items = wm8994->num_retune_mobile_texts;
wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;
ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,
@@ -3293,7 +3306,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
for (i = 0; i < pdata->num_drc_cfgs; i++)
wm8994->drc_texts[i] = pdata->drc_cfgs[i].name;
- wm8994->drc_enum.max = pdata->num_drc_cfgs;
+ wm8994->drc_enum.items = pdata->num_drc_cfgs;
wm8994->drc_enum.texts = wm8994->drc_texts;
ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,
@@ -3985,9 +3998,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
int ret, i;
wm8994->hubs.codec = codec;
- codec->control_data = control->regmap;
- snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
+ snd_soc_codec_set_cache_io(codec, control->regmap);
mutex_init(&wm8994->accdet_lock);
INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap,
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 4300caff1783..d3152cf5bd56 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -423,24 +423,24 @@ static const char *in1l_text[] = {
"Differential", "Single-ended IN1LN", "Single-ended IN1LP"
};
-static const SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL,
- 2, in1l_text);
+static SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL,
+ 2, in1l_text);
static const char *in1r_text[] = {
"Differential", "Single-ended IN1RN", "Single-ended IN1RP"
};
-static const SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL,
- 0, in1r_text);
+static SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL,
+ 0, in1r_text);
static const char *dmic_src_text[] = {
"DMICDAT1", "DMICDAT2", "DMICDAT3"
};
-static const SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5,
- 8, dmic_src_text);
-static const SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5,
- 6, dmic_src_text);
+static SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5,
+ 8, dmic_src_text);
+static SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5,
+ 6, dmic_src_text);
static const struct snd_kcontrol_new wm8995_snd_controls[] = {
SOC_DOUBLE_R_TLV("DAC1 Volume", WM8995_DAC1_LEFT_VOLUME,
@@ -561,10 +561,8 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec;
- struct wm8995_priv *wm8995;
codec = w->codec;
- wm8995 = snd_soc_codec_get_drvdata(codec);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -783,14 +781,12 @@ static const char *sidetone_text[] = {
"ADC/DMIC1", "DMIC2",
};
-static const struct soc_enum sidetone1_enum =
- SOC_ENUM_SINGLE(WM8995_SIDETONE, 0, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetone1_enum, WM8995_SIDETONE, 0, sidetone_text);
static const struct snd_kcontrol_new sidetone1_mux =
SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum);
-static const struct soc_enum sidetone2_enum =
- SOC_ENUM_SINGLE(WM8995_SIDETONE, 1, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetone2_enum, WM8995_SIDETONE, 1, sidetone_text);
static const struct snd_kcontrol_new sidetone2_mux =
SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum);
@@ -886,8 +882,7 @@ static const char *adc_mux_text[] = {
"DMIC",
};
-static const struct soc_enum adc_enum =
- SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text);
static const struct snd_kcontrol_new adcl_mux =
SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum);
@@ -899,14 +894,14 @@ static const char *spk_src_text[] = {
"DAC1L", "DAC1R", "DAC2L", "DAC2R"
};
-static const SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1,
- 0, spk_src_text);
-static const SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1,
- 0, spk_src_text);
-static const SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2,
- 0, spk_src_text);
-static const SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2,
- 0, spk_src_text);
+static SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1,
+ 0, spk_src_text);
+static SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1,
+ 0, spk_src_text);
+static SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2,
+ 0, spk_src_text);
+static SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2,
+ 0, spk_src_text);
static const struct snd_kcontrol_new spk1l_mux =
SOC_DAPM_ENUM("SPK1L SRC", spk1l_src_enum);
@@ -2047,13 +2042,6 @@ static int wm8995_probe(struct snd_soc_codec *codec)
wm8995 = snd_soc_codec_get_drvdata(codec);
wm8995->codec = codec;
- codec->control_data = wm8995->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
- return ret;
- }
-
for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++)
wm8995->supplies[i].supply = wm8995_supply_names[i];
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 1a7655b0aa22..c6cbb3b8ace9 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -311,28 +311,28 @@ static const char *sidetone_hpf_text[] = {
"2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz"
};
-static const struct soc_enum sidetone_hpf =
- SOC_ENUM_SINGLE(WM8996_SIDETONE, 7, 7, sidetone_hpf_text);
+static SOC_ENUM_SINGLE_DECL(sidetone_hpf,
+ WM8996_SIDETONE, 7, sidetone_hpf_text);
static const char *hpf_mode_text[] = {
"HiFi", "Custom", "Voice"
};
-static const struct soc_enum dsp1tx_hpf_mode =
- SOC_ENUM_SINGLE(WM8996_DSP1_TX_FILTERS, 3, 3, hpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(dsp1tx_hpf_mode,
+ WM8996_DSP1_TX_FILTERS, 3, hpf_mode_text);
-static const struct soc_enum dsp2tx_hpf_mode =
- SOC_ENUM_SINGLE(WM8996_DSP2_TX_FILTERS, 3, 3, hpf_mode_text);
+static SOC_ENUM_SINGLE_DECL(dsp2tx_hpf_mode,
+ WM8996_DSP2_TX_FILTERS, 3, hpf_mode_text);
static const char *hpf_cutoff_text[] = {
"50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
};
-static const struct soc_enum dsp1tx_hpf_cutoff =
- SOC_ENUM_SINGLE(WM8996_DSP1_TX_FILTERS, 0, 7, hpf_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(dsp1tx_hpf_cutoff,
+ WM8996_DSP1_TX_FILTERS, 0, hpf_cutoff_text);
-static const struct soc_enum dsp2tx_hpf_cutoff =
- SOC_ENUM_SINGLE(WM8996_DSP2_TX_FILTERS, 0, 7, hpf_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(dsp2tx_hpf_cutoff,
+ WM8996_DSP2_TX_FILTERS, 0, hpf_cutoff_text);
static void wm8996_set_retune_mobile(struct snd_soc_codec *codec, int block)
{
@@ -780,14 +780,14 @@ static const char *sidetone_text[] = {
"IN1", "IN2",
};
-static const struct soc_enum left_sidetone_enum =
- SOC_ENUM_SINGLE(WM8996_SIDETONE, 0, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(left_sidetone_enum,
+ WM8996_SIDETONE, 0, sidetone_text);
static const struct snd_kcontrol_new left_sidetone =
SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum);
-static const struct soc_enum right_sidetone_enum =
- SOC_ENUM_SINGLE(WM8996_SIDETONE, 1, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(right_sidetone_enum,
+ WM8996_SIDETONE, 1, sidetone_text);
static const struct snd_kcontrol_new right_sidetone =
SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum);
@@ -796,14 +796,14 @@ static const char *spk_text[] = {
"DAC1L", "DAC1R", "DAC2L", "DAC2R"
};
-static const struct soc_enum spkl_enum =
- SOC_ENUM_SINGLE(WM8996_LEFT_PDM_SPEAKER, 0, 4, spk_text);
+static SOC_ENUM_SINGLE_DECL(spkl_enum,
+ WM8996_LEFT_PDM_SPEAKER, 0, spk_text);
static const struct snd_kcontrol_new spkl_mux =
SOC_DAPM_ENUM("SPKL", spkl_enum);
-static const struct soc_enum spkr_enum =
- SOC_ENUM_SINGLE(WM8996_RIGHT_PDM_SPEAKER, 0, 4, spk_text);
+static SOC_ENUM_SINGLE_DECL(spkr_enum,
+ WM8996_RIGHT_PDM_SPEAKER, 0, spk_text);
static const struct snd_kcontrol_new spkr_mux =
SOC_DAPM_ENUM("SPKR", spkr_enum);
@@ -812,8 +812,8 @@ static const char *dsp1rx_text[] = {
"AIF1", "AIF2"
};
-static const struct soc_enum dsp1rx_enum =
- SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 0, 2, dsp1rx_text);
+static SOC_ENUM_SINGLE_DECL(dsp1rx_enum,
+ WM8996_POWER_MANAGEMENT_8, 0, dsp1rx_text);
static const struct snd_kcontrol_new dsp1rx =
SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum);
@@ -822,8 +822,8 @@ static const char *dsp2rx_text[] = {
"AIF2", "AIF1"
};
-static const struct soc_enum dsp2rx_enum =
- SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 4, 2, dsp2rx_text);
+static SOC_ENUM_SINGLE_DECL(dsp2rx_enum,
+ WM8996_POWER_MANAGEMENT_8, 4, dsp2rx_text);
static const struct snd_kcontrol_new dsp2rx =
SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum);
@@ -832,8 +832,8 @@ static const char *aif2tx_text[] = {
"DSP2", "DSP1", "AIF1"
};
-static const struct soc_enum aif2tx_enum =
- SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 6, 3, aif2tx_text);
+static SOC_ENUM_SINGLE_DECL(aif2tx_enum,
+ WM8996_POWER_MANAGEMENT_8, 6, aif2tx_text);
static const struct snd_kcontrol_new aif2tx =
SOC_DAPM_ENUM("AIF2TX", aif2tx_enum);
@@ -842,14 +842,14 @@ static const char *inmux_text[] = {
"ADC", "DMIC1", "DMIC2"
};
-static const struct soc_enum in1_enum =
- SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_7, 0, 3, inmux_text);
+static SOC_ENUM_SINGLE_DECL(in1_enum,
+ WM8996_POWER_MANAGEMENT_7, 0, inmux_text);
static const struct snd_kcontrol_new in1_mux =
SOC_DAPM_ENUM("IN1 Mux", in1_enum);
-static const struct soc_enum in2_enum =
- SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_7, 4, 3, inmux_text);
+static SOC_ENUM_SINGLE_DECL(in2_enum,
+ WM8996_POWER_MANAGEMENT_7, 4, inmux_text);
static const struct snd_kcontrol_new in2_mux =
SOC_DAPM_ENUM("IN2 Mux", in2_enum);
@@ -1608,8 +1608,8 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
msleep(5);
}
- regcache_cache_only(codec->control_data, false);
- regcache_sync(codec->control_data);
+ regcache_cache_only(wm8996->regmap, false);
+ regcache_sync(wm8996->regmap);
}
/* Bypass the MICBIASes for lowest power */
@@ -1620,10 +1620,10 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_OFF:
- regcache_cache_only(codec->control_data, true);
+ regcache_cache_only(wm8996->regmap, true);
if (wm8996->pdata.ldo_ena >= 0) {
gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
- regcache_cache_only(codec->control_data, true);
+ regcache_cache_only(wm8996->regmap, true);
}
regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies),
wm8996->supplies);
@@ -2251,6 +2251,7 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
wm8996_polarity_fn polarity_cb)
{
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
wm8996->jack = jack;
wm8996->detecting = true;
@@ -2267,8 +2268,12 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
WM8996_MICB2_DISCH, 0);
/* LDO2 powers the microphones, SYSCLK clocks detection */
- snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
- snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
+ snd_soc_dapm_mutex_lock(dapm);
+
+ snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2");
+ snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK");
+
+ snd_soc_dapm_mutex_unlock(dapm);
/* We start off just enabling microphone detection - even a
* plain headphone will trigger detection.
@@ -2595,7 +2600,7 @@ static void wm8996_retune_mobile_pdata(struct snd_soc_codec *codec)
dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
wm8996->num_retune_mobile_texts);
- wm8996->retune_mobile_enum.max = wm8996->num_retune_mobile_texts;
+ wm8996->retune_mobile_enum.items = wm8996->num_retune_mobile_texts;
wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts;
ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls));
@@ -2628,14 +2633,6 @@ static int wm8996_probe(struct snd_soc_codec *codec)
init_completion(&wm8996->dcs_done);
init_completion(&wm8996->fll_lock);
- codec->control_data = wm8996->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err;
- }
-
if (wm8996->pdata.num_retune_mobile_cfgs)
wm8996_retune_mobile_pdata(codec);
else
@@ -2674,13 +2671,11 @@ static int wm8996_probe(struct snd_soc_codec *codec)
} else {
dev_err(codec->dev, "Failed to request IRQ: %d\n",
ret);
+ return ret;
}
}
return 0;
-
-err:
- return ret;
}
static int wm8996_remove(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index 555115ee2159..004186b6bd48 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -86,7 +86,7 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = w->codec;
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
- struct regmap *regmap = codec->control_data;
+ struct regmap *regmap = arizona->regmap;
const struct reg_default *patch = NULL;
int i, patch_size;
@@ -123,10 +123,12 @@ static const unsigned int wm8997_osr_val[] = {
static const struct soc_enum wm8997_hpout_osr[] = {
SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
- ARIZONA_OUT1_OSR_SHIFT, 0x7, 3,
+ ARIZONA_OUT1_OSR_SHIFT, 0x7,
+ ARRAY_SIZE(wm8997_osr_text),
wm8997_osr_text, wm8997_osr_val),
SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
- ARIZONA_OUT3_OSR_SHIFT, 0x7, 3,
+ ARIZONA_OUT3_OSR_SHIFT, 0x7,
+ ARRAY_SIZE(wm8997_osr_text),
wm8997_osr_text, wm8997_osr_val),
};
@@ -170,15 +172,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
-SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21,
- ARIZONA_EQ1_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21,
- ARIZONA_EQ2_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21,
- ARIZONA_EQ3_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21,
- ARIZONA_EQ4_ENA_MASK),
-
+SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19),
+SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0),
SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
@@ -190,6 +185,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
24, 0, eq_tlv),
+SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19),
+SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0),
SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
@@ -201,6 +198,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
24, 0, eq_tlv),
+SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19),
+SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0),
SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
@@ -212,6 +211,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
24, 0, eq_tlv),
+SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19),
+SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0),
SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
24, 0, eq_tlv),
SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
@@ -1052,9 +1053,7 @@ static int wm8997_codec_probe(struct snd_soc_codec *codec)
struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
int ret;
- codec->control_data = priv->core.arizona->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP);
+ ret = snd_soc_codec_set_cache_io(codec, priv->core.arizona->regmap);
if (ret != 0)
return ret;
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 0982c1d38ec4..d18eff31fbbc 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -268,8 +268,7 @@ static const char *drc_high_text[] = {
"0",
};
-static const struct soc_enum drc_high =
- SOC_ENUM_SINGLE(WM9081_DRC_3, 3, 6, drc_high_text);
+static SOC_ENUM_SINGLE_DECL(drc_high, WM9081_DRC_3, 3, drc_high_text);
static const char *drc_low_text[] = {
"1",
@@ -279,8 +278,7 @@ static const char *drc_low_text[] = {
"0",
};
-static const struct soc_enum drc_low =
- SOC_ENUM_SINGLE(WM9081_DRC_3, 0, 5, drc_low_text);
+static SOC_ENUM_SINGLE_DECL(drc_low, WM9081_DRC_3, 0, drc_low_text);
static const char *drc_atk_text[] = {
"181us",
@@ -297,8 +295,7 @@ static const char *drc_atk_text[] = {
"185.6ms",
};
-static const struct soc_enum drc_atk =
- SOC_ENUM_SINGLE(WM9081_DRC_2, 12, 12, drc_atk_text);
+static SOC_ENUM_SINGLE_DECL(drc_atk, WM9081_DRC_2, 12, drc_atk_text);
static const char *drc_dcy_text[] = {
"186ms",
@@ -312,8 +309,7 @@ static const char *drc_dcy_text[] = {
"47.56s",
};
-static const struct soc_enum drc_dcy =
- SOC_ENUM_SINGLE(WM9081_DRC_2, 8, 9, drc_dcy_text);
+static SOC_ENUM_SINGLE_DECL(drc_dcy, WM9081_DRC_2, 8, drc_dcy_text);
static const char *drc_qr_dcy_text[] = {
"0.725ms",
@@ -321,8 +317,7 @@ static const char *drc_qr_dcy_text[] = {
"5.8ms",
};
-static const struct soc_enum drc_qr_dcy =
- SOC_ENUM_SINGLE(WM9081_DRC_2, 4, 3, drc_qr_dcy_text);
+static SOC_ENUM_SINGLE_DECL(drc_qr_dcy, WM9081_DRC_2, 4, drc_qr_dcy_text);
static const char *dac_deemph_text[] = {
"None",
@@ -331,16 +326,16 @@ static const char *dac_deemph_text[] = {
"48kHz",
};
-static const struct soc_enum dac_deemph =
- SOC_ENUM_SINGLE(WM9081_DAC_DIGITAL_2, 1, 4, dac_deemph_text);
+static SOC_ENUM_SINGLE_DECL(dac_deemph, WM9081_DAC_DIGITAL_2, 1,
+ dac_deemph_text);
static const char *speaker_mode_text[] = {
"Class D",
"Class AB",
};
-static const struct soc_enum speaker_mode =
- SOC_ENUM_SINGLE(WM9081_ANALOGUE_SPEAKER_2, 6, 2, speaker_mode_text);
+static SOC_ENUM_SINGLE_DECL(speaker_mode, WM9081_ANALOGUE_SPEAKER_2, 6,
+ speaker_mode_text);
static int speaker_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -1265,15 +1260,6 @@ static struct snd_soc_dai_driver wm9081_dai = {
static int wm9081_probe(struct snd_soc_codec *codec)
{
struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- codec->control_data = wm9081->regmap;
-
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
/* Enable zero cross by default */
snd_soc_update_bits(codec, WM9081_ANALOGUE_LINEOUT,
@@ -1288,7 +1274,7 @@ static int wm9081_probe(struct snd_soc_codec *codec)
ARRAY_SIZE(wm9081_eq_controls));
}
- return ret;
+ return 0;
}
static int wm9081_remove(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index a07fe1618eec..87934171f063 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -522,16 +522,6 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
static int wm9090_probe(struct snd_soc_codec *codec)
{
- struct wm9090_priv *wm9090 = dev_get_drvdata(codec->dev);
- int ret;
-
- codec->control_data = wm9090->regmap;
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-
/* Configure some defaults; they will be written out when we
* bring the bias up.
*/
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index 70ce6793c5bd..c0b7f45dfa37 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -67,12 +67,12 @@ static const char *wm9705_mic[] = {"Mic 1", "Mic 2"};
static const char *wm9705_rec_sel[] = {"Mic", "CD", "NC", "NC",
"Line", "Stereo Mix", "Mono Mix", "Phone"};
-static const struct soc_enum wm9705_enum_mic =
- SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, wm9705_mic);
-static const struct soc_enum wm9705_enum_rec_l =
- SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9705_rec_sel);
-static const struct soc_enum wm9705_enum_rec_r =
- SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9705_rec_sel);
+static SOC_ENUM_SINGLE_DECL(wm9705_enum_mic,
+ AC97_GENERAL_PURPOSE, 8, wm9705_mic);
+static SOC_ENUM_SINGLE_DECL(wm9705_enum_rec_l,
+ AC97_REC_SEL, 8, wm9705_rec_sel);
+static SOC_ENUM_SINGLE_DECL(wm9705_enum_rec_r,
+ AC97_REC_SEL, 0, wm9705_rec_sel);
/* Headphone Mixer */
static const struct snd_kcontrol_new wm9705_hp_mixer_controls[] = {
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 444626fcab40..bb5f7b4e3ebb 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -684,24 +684,38 @@ static int wm_adsp_load(struct wm_adsp *dsp)
}
if (reg) {
- buf = wm_adsp_buf_alloc(region->data,
- le32_to_cpu(region->len),
- &buf_list);
- if (!buf) {
- adsp_err(dsp, "Out of memory\n");
- ret = -ENOMEM;
- goto out_fw;
- }
+ size_t to_write = PAGE_SIZE;
+ size_t remain = le32_to_cpu(region->len);
+ const u8 *data = region->data;
+
+ while (remain > 0) {
+ if (remain < PAGE_SIZE)
+ to_write = remain;
+
+ buf = wm_adsp_buf_alloc(data,
+ to_write,
+ &buf_list);
+ if (!buf) {
+ adsp_err(dsp, "Out of memory\n");
+ ret = -ENOMEM;
+ goto out_fw;
+ }
- ret = regmap_raw_write_async(regmap, reg, buf->buf,
- le32_to_cpu(region->len));
- if (ret != 0) {
- adsp_err(dsp,
- "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
- file, regions,
- le32_to_cpu(region->len), offset,
- region_name, ret);
- goto out_fw;
+ ret = regmap_raw_write_async(regmap, reg,
+ buf->buf,
+ to_write);
+ if (ret != 0) {
+ adsp_err(dsp,
+ "%s.%d: Failed to write %zd bytes at %d in %s: %d\n",
+ file, regions,
+ to_write, offset,
+ region_name, ret);
+ goto out_fw;
+ }
+
+ data += to_write;
+ reg += to_write / 2;
+ remain -= to_write;
}
}
@@ -1679,6 +1693,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
list_del(&alg_region->list);
kfree(alg_region);
}
+
+ adsp_dbg(dsp, "Shutdown complete\n");
break;
default:
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index b371066dd5bc..b6209662ab13 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -50,16 +50,16 @@ static const char *speaker_ref_text[] = {
"VMID",
};
-static const struct soc_enum speaker_ref =
- SOC_ENUM_SINGLE(WM8993_SPEAKER_MIXER, 8, 2, speaker_ref_text);
+static SOC_ENUM_SINGLE_DECL(speaker_ref,
+ WM8993_SPEAKER_MIXER, 8, speaker_ref_text);
static const char *speaker_mode_text[] = {
"Class D",
"Class AB",
};
-static const struct soc_enum speaker_mode =
- SOC_ENUM_SINGLE(WM8993_SPKMIXR_ATTENUATION, 8, 2, speaker_mode_text);
+static SOC_ENUM_SINGLE_DECL(speaker_mode,
+ WM8993_SPKMIXR_ATTENUATION, 8, speaker_mode_text);
static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
{
@@ -735,15 +735,15 @@ static const char *hp_mux_text[] = {
"DAC",
};
-static const struct soc_enum hpl_enum =
- SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER1, 8, 2, hp_mux_text);
+static SOC_ENUM_SINGLE_DECL(hpl_enum,
+ WM8993_OUTPUT_MIXER1, 8, hp_mux_text);
const struct snd_kcontrol_new wm_hubs_hpl_mux =
WM_HUBS_ENUM_W("Left Headphone Mux", hpl_enum);
EXPORT_SYMBOL_GPL(wm_hubs_hpl_mux);
-static const struct soc_enum hpr_enum =
- SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER2, 8, 2, hp_mux_text);
+static SOC_ENUM_SINGLE_DECL(hpr_enum,
+ WM8993_OUTPUT_MIXER2, 8, hp_mux_text);
const struct snd_kcontrol_new wm_hubs_hpr_mux =
WM_HUBS_ENUM_W("Right Headphone Mux", hpr_enum);
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 70ff3772079f..cab98a580053 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -17,6 +17,7 @@
#include <linux/platform_data/edma.h>
#include <linux/i2c.h>
#include <linux/of_platform.h>
+#include <linux/clk.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -30,9 +31,34 @@
#include "davinci-i2s.h"
struct snd_soc_card_drvdata_davinci {
+ struct clk *mclk;
unsigned sysclk;
};
+static int evm_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *soc_card = rtd->codec->card;
+ struct snd_soc_card_drvdata_davinci *drvdata =
+ snd_soc_card_get_drvdata(soc_card);
+
+ if (drvdata->mclk)
+ return clk_prepare_enable(drvdata->mclk);
+
+ return 0;
+}
+
+static void evm_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *soc_card = rtd->codec->card;
+ struct snd_soc_card_drvdata_davinci *drvdata =
+ snd_soc_card_get_drvdata(soc_card);
+
+ if (drvdata->mclk)
+ clk_disable_unprepare(drvdata->mclk);
+}
+
static int evm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -59,6 +85,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
}
static struct snd_soc_ops evm_ops = {
+ .startup = evm_startup,
+ .shutdown = evm_shutdown,
.hw_params = evm_hw_params,
};
@@ -95,35 +123,29 @@ static const struct snd_soc_dapm_route audio_map[] = {
/* Logic for a aic3x as connected on a davinci-evm */
static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_soc_card *card = rtd->card;
struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
struct device_node *np = codec->card->dev->of_node;
int ret;
/* Add davinci-evm specific widgets */
- snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
+ snd_soc_dapm_new_controls(&card->dapm, aic3x_dapm_widgets,
ARRAY_SIZE(aic3x_dapm_widgets));
if (np) {
- ret = snd_soc_of_parse_audio_routing(codec->card,
- "ti,audio-routing");
+ ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
if (ret)
return ret;
} else {
/* Set up davinci-evm specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+ snd_soc_dapm_add_routes(&card->dapm, audio_map,
+ ARRAY_SIZE(audio_map));
}
/* not connected */
- snd_soc_dapm_disable_pin(dapm, "MONO_LOUT");
- snd_soc_dapm_disable_pin(dapm, "HPLCOM");
- snd_soc_dapm_disable_pin(dapm, "HPRCOM");
-
- /* always connected */
- snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_enable_pin(dapm, "Line Out");
- snd_soc_dapm_enable_pin(dapm, "Mic Jack");
- snd_soc_dapm_enable_pin(dapm, "Line In");
+ snd_soc_dapm_nc_pin(&codec->dapm, "MONO_LOUT");
+ snd_soc_dapm_nc_pin(&codec->dapm, "HPLCOM");
+ snd_soc_dapm_nc_pin(&codec->dapm, "HPRCOM");
return 0;
}
@@ -348,6 +370,7 @@ static int davinci_evm_probe(struct platform_device *pdev)
of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data;
struct snd_soc_card_drvdata_davinci *drvdata = NULL;
+ struct clk *mclk;
int ret = 0;
evm_soc_card.dai_link = dai;
@@ -367,13 +390,38 @@ static int davinci_evm_probe(struct platform_device *pdev)
if (ret)
return ret;
+ mclk = devm_clk_get(&pdev->dev, "mclk");
+ if (PTR_ERR(mclk) == -EPROBE_DEFER) {
+ return -EPROBE_DEFER;
+ } else if (IS_ERR(mclk)) {
+ dev_dbg(&pdev->dev, "mclk not found.\n");
+ mclk = NULL;
+ }
+
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
+ drvdata->mclk = mclk;
+
ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk);
- if (ret < 0)
- return -EINVAL;
+
+ if (ret < 0) {
+ if (!drvdata->mclk) {
+ dev_err(&pdev->dev,
+ "No clock or clock rate defined.\n");
+ return -EINVAL;
+ }
+ drvdata->sysclk = clk_get_rate(drvdata->mclk);
+ } else if (drvdata->mclk) {
+ unsigned int requestd_rate = drvdata->sysclk;
+ clk_set_rate(drvdata->mclk, drvdata->sysclk);
+ drvdata->sysclk = clk_get_rate(drvdata->mclk);
+ if (drvdata->sysclk != requestd_rate)
+ dev_warn(&pdev->dev,
+ "Could not get requested rate %u using %u.\n",
+ requestd_rate, drvdata->sysclk);
+ }
snd_soc_card_set_drvdata(&evm_soc_card, drvdata);
ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card);
@@ -399,6 +447,7 @@ static struct platform_driver davinci_evm_driver = {
.driver = {
.name = "davinci_evm",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(davinci_evm_dt_ids),
},
};
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index b7858bfa0295..a01ae97c90aa 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -37,6 +37,16 @@
#include "davinci-pcm.h"
#include "davinci-mcasp.h"
+struct davinci_mcasp_context {
+ u32 txfmtctl;
+ u32 rxfmtctl;
+ u32 txfmt;
+ u32 rxfmt;
+ u32 aclkxctl;
+ u32 aclkrctl;
+ u32 pdir;
+};
+
struct davinci_mcasp {
struct davinci_pcm_dma_params dma_params[2];
struct snd_dmaengine_dai_dma_data dma_data[2];
@@ -53,6 +63,9 @@ struct davinci_mcasp {
u16 bclk_lrclk_ratio;
int streams;
+ int sysclk_freq;
+ bool bclk_master;
+
/* McASP FIFO related */
u8 txnumevt;
u8 rxnumevt;
@@ -60,15 +73,7 @@ struct davinci_mcasp {
bool dat_port;
#ifdef CONFIG_PM_SLEEP
- struct {
- u32 txfmtctl;
- u32 rxfmtctl;
- u32 txfmt;
- u32 rxfmt;
- u32 aclkxctl;
- u32 aclkrctl;
- u32 pdir;
- } context;
+ struct davinci_mcasp_context context;
#endif
};
@@ -263,7 +268,9 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret = 0;
+ pm_runtime_get_sync(mcasp->dev);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_B:
case SND_SOC_DAIFMT_AC97:
@@ -292,6 +299,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+ mcasp->bclk_master = 1;
break;
case SND_SOC_DAIFMT_CBM_CFS:
/* codec is clock master and frame slave */
@@ -303,6 +311,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+ mcasp->bclk_master = 0;
break;
case SND_SOC_DAIFMT_CBM_CFM:
/* codec is clock and frame master */
@@ -314,10 +323,12 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG,
ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
+ mcasp->bclk_master = 0;
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -354,10 +365,12 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
-
- return 0;
+out:
+ pm_runtime_put_sync(mcasp->dev);
+ return ret;
}
static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
@@ -405,6 +418,8 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
}
+ mcasp->sysclk_freq = freq;
+
return 0;
}
@@ -448,7 +463,7 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
return 0;
}
-static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream,
+static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
int channels)
{
int i;
@@ -524,12 +539,18 @@ static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream,
return 0;
}
-static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream)
+static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream)
{
int i, active_slots;
u32 mask = 0;
u32 busel = 0;
+ if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) {
+ dev_err(mcasp->dev, "tdm slot %d not supported\n",
+ mcasp->tdm_slots);
+ return -EINVAL;
+ }
+
active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots;
for (i = 0; i < active_slots; i++)
mask |= (1 << i);
@@ -539,35 +560,21 @@ static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream)
if (!mcasp->dat_port)
busel = TXSEL;
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- /* bit stream is MSB first with no delay */
- /* DSP_B mode */
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
-
- if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32))
- mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
- FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF));
- else
- printk(KERN_ERR "playback tdm slot %d not supported\n",
- mcasp->tdm_slots);
- } else {
- /* bit stream is MSB first with no delay */
- /* DSP_B mode */
- mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
-
- if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32))
- mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
- FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF));
- else
- printk(KERN_ERR "capture tdm slot %d not supported\n",
- mcasp->tdm_slots);
- }
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
+ FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF));
+
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
+ FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF));
+
+ return 0;
}
/* S/PDIF */
-static void davinci_hw_dit_param(struct davinci_mcasp *mcasp)
+static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp)
{
/* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
and LSB first */
@@ -589,6 +596,8 @@ static void davinci_hw_dit_param(struct davinci_mcasp *mcasp)
/* Enable the DIT */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
+
+ return 0;
}
static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
@@ -604,24 +613,31 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
u8 fifo_level;
u8 slots = mcasp->tdm_slots;
u8 active_serializers;
- int channels;
- struct snd_interval *pcm_channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- channels = pcm_channels->min;
+ int channels = params_channels(params);
+ int ret;
- active_serializers = (channels + slots - 1) / slots;
+ /* If mcasp is BCLK master we need to set BCLK divider */
+ if (mcasp->bclk_master) {
+ unsigned int bclk_freq = snd_soc_params_to_bclk(params);
+ if (mcasp->sysclk_freq % bclk_freq != 0) {
+ dev_err(mcasp->dev, "Can't produce requred BCLK\n");
+ return -EINVAL;
+ }
+ davinci_mcasp_set_clkdiv(
+ cpu_dai, 1, mcasp->sysclk_freq / bclk_freq);
+ }
- if (davinci_hw_common_param(mcasp, substream->stream, channels) == -EINVAL)
- return -EINVAL;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- fifo_level = mcasp->txnumevt * active_serializers;
- else
- fifo_level = mcasp->rxnumevt * active_serializers;
+ ret = mcasp_common_hw_param(mcasp, substream->stream, channels);
+ if (ret)
+ return ret;
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
- davinci_hw_dit_param(mcasp);
+ ret = mcasp_dit_hw_param(mcasp);
else
- davinci_hw_param(mcasp, substream->stream);
+ ret = mcasp_i2s_hw_param(mcasp, substream->stream);
+
+ if (ret)
+ return ret;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_U8:
@@ -655,6 +671,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ /* Calculate FIFO level */
+ active_serializers = (channels + slots - 1) / slots;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ fifo_level = mcasp->txnumevt * active_serializers;
+ else
+ fifo_level = mcasp->rxnumevt * active_serializers;
+
if (mcasp->version == MCASP_VERSION_2 && !fifo_level)
dma_params->acnt = 4;
else
@@ -678,19 +701,9 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- ret = pm_runtime_get_sync(mcasp->dev);
- if (IS_ERR_VALUE(ret))
- dev_err(mcasp->dev, "pm_runtime_get_sync() failed\n");
davinci_mcasp_start(mcasp, substream->stream);
break;
-
case SNDRV_PCM_TRIGGER_SUSPEND:
- davinci_mcasp_stop(mcasp, substream->stream);
- ret = pm_runtime_put_sync(mcasp->dev);
- if (IS_ERR_VALUE(ret))
- dev_err(mcasp->dev, "pm_runtime_put_sync() failed\n");
- break;
-
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
davinci_mcasp_stop(mcasp, substream->stream);
@@ -726,6 +739,43 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
.set_sysclk = davinci_mcasp_set_sysclk,
};
+#ifdef CONFIG_PM_SLEEP
+static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
+{
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+ struct davinci_mcasp_context *context = &mcasp->context;
+
+ context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG);
+ context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
+ context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG);
+ context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG);
+ context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
+ context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG);
+ context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
+
+ return 0;
+}
+
+static int davinci_mcasp_resume(struct snd_soc_dai *dai)
+{
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+ struct davinci_mcasp_context *context = &mcasp->context;
+
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir);
+
+ return 0;
+}
+#else
+#define davinci_mcasp_suspend NULL
+#define davinci_mcasp_resume NULL
+#endif
+
#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000
#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
@@ -742,6 +792,8 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
{
.name = "davinci-mcasp.0",
+ .suspend = davinci_mcasp_suspend,
+ .resume = davinci_mcasp_resume,
.playback = {
.channels_min = 2,
.channels_max = 32 * 16,
@@ -775,28 +827,28 @@ static const struct snd_soc_component_driver davinci_mcasp_component = {
};
/* Some HW specific values and defaults. The rest is filled in from DT. */
-static struct snd_platform_data dm646x_mcasp_pdata = {
+static struct davinci_mcasp_pdata dm646x_mcasp_pdata = {
.tx_dma_offset = 0x400,
.rx_dma_offset = 0x400,
.asp_chan_q = EVENTQ_0,
.version = MCASP_VERSION_1,
};
-static struct snd_platform_data da830_mcasp_pdata = {
+static struct davinci_mcasp_pdata da830_mcasp_pdata = {
.tx_dma_offset = 0x2000,
.rx_dma_offset = 0x2000,
.asp_chan_q = EVENTQ_0,
.version = MCASP_VERSION_2,
};
-static struct snd_platform_data am33xx_mcasp_pdata = {
+static struct davinci_mcasp_pdata am33xx_mcasp_pdata = {
.tx_dma_offset = 0,
.rx_dma_offset = 0,
.asp_chan_q = EVENTQ_0,
.version = MCASP_VERSION_3,
};
-static struct snd_platform_data dra7_mcasp_pdata = {
+static struct davinci_mcasp_pdata dra7_mcasp_pdata = {
.tx_dma_offset = 0x200,
.rx_dma_offset = 0x284,
.asp_chan_q = EVENTQ_0,
@@ -864,11 +916,11 @@ err1:
return ret;
}
-static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
+static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct snd_platform_data *pdata = NULL;
+ struct davinci_mcasp_pdata *pdata = NULL;
const struct of_device_id *match =
of_match_device(mcasp_dt_ids, &pdev->dev);
struct of_phandle_args dma_spec;
@@ -881,7 +933,7 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
pdata = pdev->dev.platform_data;
return pdata;
} else if (match) {
- pdata = (struct snd_platform_data *) match->data;
+ pdata = (struct davinci_mcasp_pdata*) match->data;
} else {
/* control shouldn't reach here. something is wrong */
ret = -EINVAL;
@@ -973,9 +1025,10 @@ nodata:
static int davinci_mcasp_probe(struct platform_device *pdev)
{
- struct davinci_pcm_dma_params *dma_data;
+ struct davinci_pcm_dma_params *dma_params;
+ struct snd_dmaengine_dai_dma_data *dma_data;
struct resource *mem, *ioarea, *res, *dat;
- struct snd_platform_data *pdata;
+ struct davinci_mcasp_pdata *pdata;
struct davinci_mcasp *mcasp;
int ret;
@@ -1042,41 +1095,49 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (dat)
mcasp->dat_port = true;
- dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
- dma_data->asp_chan_q = pdata->asp_chan_q;
- dma_data->ram_chan_q = pdata->ram_chan_q;
- dma_data->sram_pool = pdata->sram_pool;
- dma_data->sram_size = pdata->sram_size_playback;
+ dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
+ dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+ dma_params->asp_chan_q = pdata->asp_chan_q;
+ dma_params->ram_chan_q = pdata->ram_chan_q;
+ dma_params->sram_pool = pdata->sram_pool;
+ dma_params->sram_size = pdata->sram_size_playback;
if (dat)
- dma_data->dma_addr = dat->start;
+ dma_params->dma_addr = dat->start;
else
- dma_data->dma_addr = mem->start + pdata->tx_dma_offset;
+ dma_params->dma_addr = mem->start + pdata->tx_dma_offset;
/* Unconditional dmaengine stuff */
- mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_data->dma_addr;
+ dma_data->addr = dma_params->dma_addr;
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (res)
- dma_data->channel = res->start;
+ dma_params->channel = res->start;
else
- dma_data->channel = pdata->tx_dma_channel;
+ dma_params->channel = pdata->tx_dma_channel;
- dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
- dma_data->asp_chan_q = pdata->asp_chan_q;
- dma_data->ram_chan_q = pdata->ram_chan_q;
- dma_data->sram_pool = pdata->sram_pool;
- dma_data->sram_size = pdata->sram_size_capture;
+ /* dmaengine filter data for DT and non-DT boot */
+ if (pdev->dev.of_node)
+ dma_data->filter_data = "tx";
+ else
+ dma_data->filter_data = &dma_params->channel;
+
+ dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
+ dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+ dma_params->asp_chan_q = pdata->asp_chan_q;
+ dma_params->ram_chan_q = pdata->ram_chan_q;
+ dma_params->sram_pool = pdata->sram_pool;
+ dma_params->sram_size = pdata->sram_size_capture;
if (dat)
- dma_data->dma_addr = dat->start;
+ dma_params->dma_addr = dat->start;
else
- dma_data->dma_addr = mem->start + pdata->rx_dma_offset;
+ dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
/* Unconditional dmaengine stuff */
- mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_data->dma_addr;
+ dma_data->addr = dma_params->dma_addr;
if (mcasp->version < MCASP_VERSION_3) {
mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
- /* dma_data->dma_addr is pointing to the data port address */
+ /* dma_params->dma_addr is pointing to the data port address */
mcasp->dat_port = true;
} else {
mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
@@ -1084,13 +1145,15 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (res)
- dma_data->channel = res->start;
+ dma_params->channel = res->start;
else
- dma_data->channel = pdata->rx_dma_channel;
+ dma_params->channel = pdata->rx_dma_channel;
- /* Unconditional dmaengine stuff */
- mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx";
- mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = "rx";
+ /* dmaengine filter data for DT and non-DT boot */
+ if (pdev->dev.of_node)
+ dma_data->filter_data = "rx";
+ else
+ dma_data->filter_data = &dma_params->channel;
dev_set_drvdata(&pdev->dev, mcasp);
@@ -1134,49 +1197,12 @@ static int davinci_mcasp_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int davinci_mcasp_suspend(struct device *dev)
-{
- struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
-
- mcasp->context.txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG);
- mcasp->context.rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
- mcasp->context.txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG);
- mcasp->context.rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG);
- mcasp->context.aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
- mcasp->context.aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG);
- mcasp->context.pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
-
- return 0;
-}
-
-static int davinci_mcasp_resume(struct device *dev)
-{
- struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
-
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, mcasp->context.txfmtctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, mcasp->context.rxfmtctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, mcasp->context.txfmt);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, mcasp->context.rxfmt);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, mcasp->context.aclkxctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, mcasp->context.aclkrctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, mcasp->context.pdir);
-
- return 0;
-}
-#endif
-
-SIMPLE_DEV_PM_OPS(davinci_mcasp_pm_ops,
- davinci_mcasp_suspend,
- davinci_mcasp_resume);
-
static struct platform_driver davinci_mcasp_driver = {
.probe = davinci_mcasp_probe,
.remove = davinci_mcasp_remove,
.driver = {
.name = "davinci-mcasp",
.owner = THIS_MODULE,
- .pm = &davinci_mcasp_pm_ops,
.of_match_table = mcasp_dt_ids,
},
};
diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/davinci/edma-pcm.c
new file mode 100644
index 000000000000..d38afb1c61ae
--- /dev/null
+++ b/sound/soc/davinci/edma-pcm.c
@@ -0,0 +1,57 @@
+/*
+ * edma-pcm.c - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * Based on: sound/soc/tegra/tegra_pcm.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.
+ *
+ * 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 <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+#include <linux/edma.h>
+
+static const struct snd_pcm_hardware edma_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_INTERLEAVED,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 64 * 1024,
+ .periods_min = 2,
+ .periods_max = 19, /* Limit by edma dmaengine driver */
+};
+
+static const struct snd_dmaengine_pcm_config edma_dmaengine_pcm_config = {
+ .pcm_hardware = &edma_pcm_hardware,
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+ .compat_filter_fn = edma_filter_fn,
+ .prealloc_buffer_size = 128 * 1024,
+};
+
+int edma_pcm_platform_register(struct device *dev)
+{
+ return devm_snd_dmaengine_pcm_register(dev, &edma_dmaengine_pcm_config,
+ SND_DMAENGINE_PCM_FLAG_COMPAT);
+}
+EXPORT_SYMBOL_GPL(edma_pcm_platform_register);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("eDMA PCM ASoC platform driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/edma-pcm.h b/sound/soc/davinci/edma-pcm.h
new file mode 100644
index 000000000000..894c378c0f74
--- /dev/null
+++ b/sound/soc/davinci/edma-pcm.h
@@ -0,0 +1,25 @@
+/*
+ * edma-pcm.h - eDMA PCM driver using dmaengine for AM3xxx, AM4xxx
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc.
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * Based on: sound/soc/tegra/tegra_pcm.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 __EDMA_PCM_H__
+#define __EDMA_PCM_H__
+
+int edma_pcm_platform_register(struct device *dev);
+
+#endif /* __EDMA_PCM_H__ */
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 07f8f141727d..338a91642471 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,5 +1,6 @@
config SND_SOC_FSL_SAI
tristate
+ select REGMAP_MMIO
select SND_SOC_GENERIC_DMAENGINE_PCM
config SND_SOC_FSL_SSI
@@ -7,9 +8,12 @@ config SND_SOC_FSL_SSI
config SND_SOC_FSL_SPDIF
tristate
+ select REGMAP_MMIO
config SND_SOC_FSL_ESAI
tristate
+ select REGMAP_MMIO
+ select SND_SOC_FSL_UTILS
config SND_SOC_FSL_UTILS
tristate
@@ -117,6 +121,7 @@ if SND_IMX_SOC
config SND_SOC_IMX_SSI
tristate
+ select SND_SOC_FSL_UTILS
config SND_SOC_IMX_PCM_FIQ
tristate
@@ -168,12 +173,14 @@ config SND_SOC_EUKREA_TLV320
depends on MACH_EUKREA_MBIMX27_BASEBOARD \
|| MACH_EUKREA_MBIMXSD25_BASEBOARD \
|| MACH_EUKREA_MBIMXSD35_BASEBOARD \
- || MACH_EUKREA_MBIMXSD51_BASEBOARD
+ || MACH_EUKREA_MBIMXSD51_BASEBOARD \
+ || (OF && ARM)
depends on I2C
- select SND_SOC_TLV320AIC23
- select SND_SOC_IMX_PCM_FIQ
+ select SND_SOC_TLV320AIC23_I2C
select SND_SOC_IMX_AUDMUX
select SND_SOC_IMX_SSI
+ select SND_SOC_FSL_SSI
+ select SND_SOC_IMX_PCM_DMA
help
Enable I2S based access to the TLV320AIC23B codec attached
to the SSI interface
@@ -204,7 +211,6 @@ config SND_SOC_IMX_SPDIF
tristate "SoC Audio support for i.MX boards with S/PDIF"
select SND_SOC_IMX_PCM_DMA
select SND_SOC_FSL_SPDIF
- select REGMAP_MMIO
help
SoC Audio support for i.MX boards with S/PDIF
Say Y if you want to add support for SoC audio on an i.MX board with
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c
index 5983740be123..eb093d5b85c4 100644
--- a/sound/soc/fsl/eukrea-tlv320.c
+++ b/sound/soc/fsl/eukrea-tlv320.c
@@ -15,8 +15,11 @@
*
*/
+#include <linux/errno.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <sound/core.h>
@@ -26,6 +29,7 @@
#include "../codecs/tlv320aic23.h"
#include "imx-ssi.h"
+#include "fsl_ssi.h"
#include "imx-audmux.h"
#define CODEC_CLOCK 12000000
@@ -41,7 +45,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM);
- if (ret) {
+ /* fsl_ssi lacks the set_fmt ops. */
+ if (ret && ret != -ENOTSUPP) {
dev_err(cpu_dai->dev,
"Failed to set the cpu dai format.\n");
return ret;
@@ -63,11 +68,13 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
"Failed to set the codec sysclk.\n");
return ret;
}
+
snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
SND_SOC_CLOCK_IN);
- if (ret) {
+ /* fsl_ssi lacks the set_sysclk ops */
+ if (ret && ret != -EINVAL) {
dev_err(cpu_dai->dev,
"Can't set the IMX_SSP_SYS_CLK CPU system clock.\n");
return ret;
@@ -84,14 +91,10 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = {
.name = "tlv320aic23",
.stream_name = "TLV320AIC23",
.codec_dai_name = "tlv320aic23-hifi",
- .platform_name = "imx-ssi.0",
- .codec_name = "tlv320aic23-codec.0-001a",
- .cpu_dai_name = "imx-ssi.0",
.ops = &eukrea_tlv320_snd_ops,
};
static struct snd_soc_card eukrea_tlv320 = {
- .name = "cpuimx-audio",
.owner = THIS_MODULE,
.dai_link = &eukrea_tlv320_dai,
.num_links = 1,
@@ -101,8 +104,65 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
{
int ret;
int int_port = 0, ext_port;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *ssi_np, *codec_np;
- if (machine_is_eukrea_cpuimx27()) {
+ eukrea_tlv320.dev = &pdev->dev;
+ if (np) {
+ ret = snd_soc_of_parse_card_name(&eukrea_tlv320,
+ "eukrea,model");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "eukrea,model node missing or invalid.\n");
+ goto err;
+ }
+
+ ssi_np = of_parse_phandle(pdev->dev.of_node,
+ "ssi-controller", 0);
+ if (!ssi_np) {
+ dev_err(&pdev->dev,
+ "ssi-controller missing or invalid.\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ codec_np = of_parse_phandle(ssi_np, "codec-handle", 0);
+ if (codec_np)
+ eukrea_tlv320_dai.codec_of_node = codec_np;
+ else
+ dev_err(&pdev->dev, "codec-handle node missing or invalid.\n");
+
+ ret = of_property_read_u32(np, "fsl,mux-int-port", &int_port);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "fsl,mux-int-port node missing or invalid.\n");
+ return ret;
+ }
+ ret = of_property_read_u32(np, "fsl,mux-ext-port", &ext_port);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "fsl,mux-ext-port node missing or invalid.\n");
+ return ret;
+ }
+
+ /*
+ * The port numbering in the hardware manual starts at 1, while
+ * the audmux API expects it starts at 0.
+ */
+ int_port--;
+ ext_port--;
+
+ eukrea_tlv320_dai.cpu_of_node = ssi_np;
+ eukrea_tlv320_dai.platform_of_node = ssi_np;
+ } else {
+ eukrea_tlv320_dai.cpu_dai_name = "imx-ssi.0";
+ eukrea_tlv320_dai.platform_name = "imx-ssi.0";
+ eukrea_tlv320_dai.codec_name = "tlv320aic23-codec.0-001a";
+ eukrea_tlv320.name = "cpuimx-audio";
+ }
+
+ if (machine_is_eukrea_cpuimx27() ||
+ of_find_compatible_node(NULL, NULL, "fsl,imx21-audmux")) {
imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
IMX_AUDMUX_V1_PCR_SYN |
IMX_AUDMUX_V1_PCR_TFSDIR |
@@ -119,8 +179,12 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
);
} else if (machine_is_eukrea_cpuimx25sd() ||
machine_is_eukrea_cpuimx35sd() ||
- machine_is_eukrea_cpuimx51sd()) {
- ext_port = machine_is_eukrea_cpuimx25sd() ? 4 : 3;
+ machine_is_eukrea_cpuimx51sd() ||
+ of_find_compatible_node(NULL, NULL, "fsl,imx31-audmux")) {
+ if (!np)
+ ext_port = machine_is_eukrea_cpuimx25sd() ?
+ 4 : 3;
+
imx_audmux_v2_configure_port(int_port,
IMX_AUDMUX_V2_PTCR_SYN |
IMX_AUDMUX_V2_PTCR_TFSDIR |
@@ -134,14 +198,27 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)
);
} else {
- /* return happy. We might run on a totally different machine */
- return 0;
+ if (np) {
+ /* The eukrea,asoc-tlv320 driver was explicitely
+ * requested (through the device tree).
+ */
+ dev_err(&pdev->dev,
+ "Missing or invalid audmux DT node.\n");
+ return -ENODEV;
+ } else {
+ /* Return happy.
+ * We might run on a totally different machine.
+ */
+ return 0;
+ }
}
- eukrea_tlv320.dev = &pdev->dev;
ret = snd_soc_register_card(&eukrea_tlv320);
+err:
if (ret)
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+ if (np)
+ of_node_put(ssi_np);
return ret;
}
@@ -153,10 +230,17 @@ static int eukrea_tlv320_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id imx_tlv320_dt_ids[] = {
+ { .compatible = "eukrea,asoc-tlv320"},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_tlv320_dt_ids);
+
static struct platform_driver eukrea_tlv320_driver = {
.driver = {
.name = "eukrea_tlv320",
.owner = THIS_MODULE,
+ .of_match_table = imx_tlv320_dt_ids,
},
.probe = eukrea_tlv320_probe,
.remove = eukrea_tlv320_remove,
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index d0c72ed261e7..c8e5db1414d7 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -18,6 +18,7 @@
#include "fsl_esai.h"
#include "imx-pcm.h"
+#include "fsl_utils.h"
#define FSL_ESAI_RATES SNDRV_PCM_RATE_8000_192000
#define FSL_ESAI_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
@@ -326,7 +327,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA,
ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask));
regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB,
- ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(tx_mask));
+ ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(tx_mask));
regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
@@ -334,7 +335,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA,
ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask));
regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB,
- ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(rx_mask));
+ ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask));
esai_priv->slot_width = slot_width;
@@ -431,17 +432,26 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
static int fsl_esai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ int ret;
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
/*
* Some platforms might use the same bit to gate all three or two of
* clocks, so keep all clocks open/close at the same time for safety
*/
- clk_prepare_enable(esai_priv->coreclk);
- if (!IS_ERR(esai_priv->extalclk))
- clk_prepare_enable(esai_priv->extalclk);
- if (!IS_ERR(esai_priv->fsysclk))
- clk_prepare_enable(esai_priv->fsysclk);
+ ret = clk_prepare_enable(esai_priv->coreclk);
+ if (ret)
+ return ret;
+ if (!IS_ERR(esai_priv->extalclk)) {
+ ret = clk_prepare_enable(esai_priv->extalclk);
+ if (ret)
+ goto err_extalck;
+ }
+ if (!IS_ERR(esai_priv->fsysclk)) {
+ ret = clk_prepare_enable(esai_priv->fsysclk);
+ if (ret)
+ goto err_fsysclk;
+ }
if (!dai->active) {
/* Reset Port C */
@@ -463,6 +473,14 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
}
return 0;
+
+err_fsysclk:
+ if (!IS_ERR(esai_priv->extalclk))
+ clk_disable_unprepare(esai_priv->extalclk);
+err_extalck:
+ clk_disable_unprepare(esai_priv->coreclk);
+
+ return ret;
}
static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
@@ -564,6 +582,7 @@ static struct snd_soc_dai_ops fsl_esai_dai_ops = {
.hw_params = fsl_esai_hw_params,
.set_sysclk = fsl_esai_set_dai_sysclk,
.set_fmt = fsl_esai_set_dai_fmt,
+ .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask,
.set_tdm_slot = fsl_esai_set_dai_tdm_slot,
};
@@ -661,7 +680,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
}
}
-static const struct regmap_config fsl_esai_regmap_config = {
+static struct regmap_config fsl_esai_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
@@ -687,6 +706,9 @@ static int fsl_esai_probe(struct platform_device *pdev)
esai_priv->pdev = pdev;
strcpy(esai_priv->name, np->name);
+ if (of_property_read_bool(np, "big-endian"))
+ fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
+
/* Get the addresses and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&pdev->dev, res);
diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h
index 9c9f957fcae1..75e14033e8d8 100644
--- a/sound/soc/fsl/fsl_esai.h
+++ b/sound/soc/fsl/fsl_esai.h
@@ -322,7 +322,7 @@
#define ESAI_xSMB_xS_SHIFT 0
#define ESAI_xSMB_xS_WIDTH 16
#define ESAI_xSMB_xS_MASK (((1 << ESAI_xSMB_xS_WIDTH) - 1) << ESAI_xSMB_xS_SHIFT)
-#define ESAI_xSMB_xS(v) (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMA_xS_MASK)
+#define ESAI_xSMB_xS(v) (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMB_xS_MASK)
/* Port C Direction Register -- REG_ESAI_PRRC 0xF8 */
#define ESAI_PRRC_PDC_SHIFT 0
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index cdd3fa830704..c4a423111673 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -15,6 +15,7 @@
#include <linux/dmaengine.h>
#include <linux/module.h>
#include <linux/of_address.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/dmaengine_pcm.h>
@@ -22,34 +23,6 @@
#include "fsl_sai.h"
-static inline u32 sai_readl(struct fsl_sai *sai,
- const void __iomem *addr)
-{
- u32 val;
-
- val = __raw_readl(addr);
-
- if (likely(sai->big_endian_regs))
- val = be32_to_cpu(val);
- else
- val = le32_to_cpu(val);
- rmb();
-
- return val;
-}
-
-static inline void sai_writel(struct fsl_sai *sai,
- u32 val, void __iomem *addr)
-{
- wmb();
- if (likely(sai->big_endian_regs))
- val = cpu_to_be32(val);
- else
- val = cpu_to_le32(val);
-
- __raw_writel(val, addr);
-}
-
static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int fsl_dir)
{
@@ -61,7 +34,8 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
else
reg_cr2 = FSL_SAI_RCR2;
- val_cr2 = sai_readl(sai, sai->base + reg_cr2);
+ regmap_read(sai->regmap, reg_cr2, &val_cr2);
+
val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
switch (clk_id) {
@@ -81,7 +55,7 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
- sai_writel(sai, val_cr2, sai->base + reg_cr2);
+ regmap_write(sai->regmap, reg_cr2, val_cr2);
return 0;
}
@@ -89,32 +63,22 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
- struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
int ret;
if (dir == SND_SOC_CLOCK_IN)
return 0;
- ret = clk_prepare_enable(sai->clk);
- if (ret)
- return ret;
-
ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
FSL_FMT_TRANSMITTER);
if (ret) {
dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret);
- goto err_clk;
+ return ret;
}
ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
FSL_FMT_RECEIVER);
- if (ret) {
+ if (ret)
dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret);
- goto err_clk;
- }
-
-err_clk:
- clk_disable_unprepare(sai->clk);
return ret;
}
@@ -133,43 +97,84 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
reg_cr4 = FSL_SAI_RCR4;
}
- val_cr2 = sai_readl(sai, sai->base + reg_cr2);
- val_cr4 = sai_readl(sai, sai->base + reg_cr4);
+ regmap_read(sai->regmap, reg_cr2, &val_cr2);
+ regmap_read(sai->regmap, reg_cr4, &val_cr4);
if (sai->big_endian_data)
val_cr4 &= ~FSL_SAI_CR4_MF;
else
val_cr4 |= FSL_SAI_CR4_MF;
+ /* DAI mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
+ /*
+ * Frame low, 1clk before data, one word length for frame sync,
+ * frame sync starts one serial clock cycle earlier,
+ * that is, together with the last bit of the previous
+ * data word.
+ */
+ val_cr2 &= ~FSL_SAI_CR2_BCP;
+ val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ /*
+ * Frame high, one word length for frame sync,
+ * frame sync asserts with the first bit of the frame.
+ */
+ val_cr2 &= ~FSL_SAI_CR2_BCP;
+ val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ /*
+ * Frame high, 1clk before data, one bit for frame sync,
+ * frame sync starts one serial clock cycle earlier,
+ * that is, together with the last bit of the previous
+ * data word.
+ */
+ val_cr2 &= ~FSL_SAI_CR2_BCP;
+ val_cr4 &= ~FSL_SAI_CR4_FSP;
val_cr4 |= FSL_SAI_CR4_FSE;
+ sai->is_dsp_mode = true;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ /*
+ * Frame high, one bit for frame sync,
+ * frame sync asserts with the first bit of the frame.
+ */
+ val_cr2 &= ~FSL_SAI_CR2_BCP;
+ val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
+ sai->is_dsp_mode = true;
break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ /* To be done */
default:
return -EINVAL;
}
+ /* DAI clock inversion */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_IF:
- val_cr4 |= FSL_SAI_CR4_FSP;
- val_cr2 &= ~FSL_SAI_CR2_BCP;
+ /* Invert both clocks */
+ val_cr2 ^= FSL_SAI_CR2_BCP;
+ val_cr4 ^= FSL_SAI_CR4_FSP;
break;
case SND_SOC_DAIFMT_IB_NF:
- val_cr4 &= ~FSL_SAI_CR4_FSP;
- val_cr2 &= ~FSL_SAI_CR2_BCP;
+ /* Invert bit clock */
+ val_cr2 ^= FSL_SAI_CR2_BCP;
break;
case SND_SOC_DAIFMT_NB_IF:
- val_cr4 |= FSL_SAI_CR4_FSP;
- val_cr2 |= FSL_SAI_CR2_BCP;
+ /* Invert frame clock */
+ val_cr4 ^= FSL_SAI_CR4_FSP;
break;
case SND_SOC_DAIFMT_NB_NF:
- val_cr4 &= ~FSL_SAI_CR4_FSP;
- val_cr2 |= FSL_SAI_CR2_BCP;
+ /* Nothing to do for both normal cases */
break;
default:
return -EINVAL;
}
+ /* DAI clock master masks */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
@@ -179,39 +184,37 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
+ val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
+ val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
+ break;
default:
return -EINVAL;
}
- sai_writel(sai, val_cr2, sai->base + reg_cr2);
- sai_writel(sai, val_cr4, sai->base + reg_cr4);
+ regmap_write(sai->regmap, reg_cr2, val_cr2);
+ regmap_write(sai->regmap, reg_cr4, val_cr4);
return 0;
}
static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
- struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
int ret;
- ret = clk_prepare_enable(sai->clk);
- if (ret)
- return ret;
-
ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
if (ret) {
dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret);
- goto err_clk;
+ return ret;
}
ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
- if (ret) {
+ if (ret)
dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
- goto err_clk;
- }
-
-err_clk:
- clk_disable_unprepare(sai->clk);
return ret;
}
@@ -235,16 +238,19 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
reg_mr = FSL_SAI_RMR;
}
- val_cr4 = sai_readl(sai, sai->base + reg_cr4);
+ regmap_read(sai->regmap, reg_cr4, &val_cr4);
+ regmap_read(sai->regmap, reg_cr4, &val_cr5);
+
val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK;
val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK;
- val_cr5 = sai_readl(sai, sai->base + reg_cr5);
val_cr5 &= ~FSL_SAI_CR5_WNW_MASK;
val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
- val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
+ if (!sai->is_dsp_mode)
+ val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
+
val_cr5 |= FSL_SAI_CR5_WNW(word_width);
val_cr5 |= FSL_SAI_CR5_W0W(word_width);
@@ -257,9 +263,9 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
val_mr = ~0UL - ((1 << channels) - 1);
- sai_writel(sai, val_cr4, sai->base + reg_cr4);
- sai_writel(sai, val_cr5, sai->base + reg_cr5);
- sai_writel(sai, val_mr, sai->base + reg_mr);
+ regmap_write(sai->regmap, reg_cr4, val_cr4);
+ regmap_write(sai->regmap, reg_cr5, val_cr5);
+ regmap_write(sai->regmap, reg_mr, val_mr);
return 0;
}
@@ -268,44 +274,42 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- u32 tcsr, rcsr, val_cr2, val_cr3, reg_cr3;
-
- val_cr2 = sai_readl(sai, sai->base + FSL_SAI_TCR2);
- val_cr2 &= ~FSL_SAI_CR2_SYNC;
- sai_writel(sai, val_cr2, sai->base + FSL_SAI_TCR2);
+ u32 tcsr, rcsr;
- val_cr2 = sai_readl(sai, sai->base + FSL_SAI_RCR2);
- val_cr2 |= FSL_SAI_CR2_SYNC;
- sai_writel(sai, val_cr2, sai->base + FSL_SAI_RCR2);
+ /*
+ * The transmitter bit clock and frame sync are to be
+ * used by both the transmitter and receiver.
+ */
+ regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
+ ~FSL_SAI_CR2_SYNC);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
+ FSL_SAI_CR2_SYNC);
- tcsr = sai_readl(sai, sai->base + FSL_SAI_TCSR);
- rcsr = sai_readl(sai, sai->base + FSL_SAI_RCSR);
+ regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr);
+ regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
tcsr |= FSL_SAI_CSR_FRDE;
rcsr &= ~FSL_SAI_CSR_FRDE;
- reg_cr3 = FSL_SAI_TCR3;
} else {
rcsr |= FSL_SAI_CSR_FRDE;
tcsr &= ~FSL_SAI_CSR_FRDE;
- reg_cr3 = FSL_SAI_RCR3;
}
- val_cr3 = sai_readl(sai, sai->base + reg_cr3);
-
+ /*
+ * It is recommended that the transmitter is the last enabled
+ * and the first disabled.
+ */
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
tcsr |= FSL_SAI_CSR_TERE;
rcsr |= FSL_SAI_CSR_TERE;
- val_cr3 |= FSL_SAI_CR3_TRCE;
- sai_writel(sai, val_cr3, sai->base + reg_cr3);
- sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
- sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
+ regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
+ regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
break;
-
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -314,11 +318,8 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
rcsr &= ~FSL_SAI_CSR_TERE;
}
- val_cr3 &= ~FSL_SAI_CR3_TRCE;
-
- sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
- sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
- sai_writel(sai, val_cr3, sai->base + reg_cr3);
+ regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
+ regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
break;
default:
return -EINVAL;
@@ -331,16 +332,32 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 reg;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ reg = FSL_SAI_TCR3;
+ else
+ reg = FSL_SAI_RCR3;
+
+ regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
+ FSL_SAI_CR3_TRCE);
- return clk_prepare_enable(sai->clk);
+ return 0;
}
static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 reg;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ reg = FSL_SAI_TCR3;
+ else
+ reg = FSL_SAI_RCR3;
- clk_disable_unprepare(sai->clk);
+ regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
+ ~FSL_SAI_CR3_TRCE);
}
static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
@@ -355,18 +372,13 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
- int ret;
- ret = clk_prepare_enable(sai->clk);
- if (ret)
- return ret;
-
- sai_writel(sai, 0x0, sai->base + FSL_SAI_RCSR);
- sai_writel(sai, 0x0, sai->base + FSL_SAI_TCSR);
- sai_writel(sai, FSL_SAI_MAXBURST_TX * 2, sai->base + FSL_SAI_TCR1);
- sai_writel(sai, FSL_SAI_MAXBURST_RX - 1, sai->base + FSL_SAI_RCR1);
-
- clk_disable_unprepare(sai->clk);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
+ FSL_SAI_MAXBURST_TX * 2);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
+ FSL_SAI_MAXBURST_RX - 1);
snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
&sai->dma_params_rx);
@@ -397,26 +409,109 @@ static const struct snd_soc_component_driver fsl_component = {
.name = "fsl-sai",
};
+static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case FSL_SAI_TCSR:
+ case FSL_SAI_TCR1:
+ case FSL_SAI_TCR2:
+ case FSL_SAI_TCR3:
+ case FSL_SAI_TCR4:
+ case FSL_SAI_TCR5:
+ case FSL_SAI_TFR:
+ case FSL_SAI_TMR:
+ case FSL_SAI_RCSR:
+ case FSL_SAI_RCR1:
+ case FSL_SAI_RCR2:
+ case FSL_SAI_RCR3:
+ case FSL_SAI_RCR4:
+ case FSL_SAI_RCR5:
+ case FSL_SAI_RDR:
+ case FSL_SAI_RFR:
+ case FSL_SAI_RMR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case FSL_SAI_TFR:
+ case FSL_SAI_RFR:
+ case FSL_SAI_TDR:
+ case FSL_SAI_RDR:
+ return true;
+ default:
+ return false;
+ }
+
+}
+
+static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case FSL_SAI_TCSR:
+ case FSL_SAI_TCR1:
+ case FSL_SAI_TCR2:
+ case FSL_SAI_TCR3:
+ case FSL_SAI_TCR4:
+ case FSL_SAI_TCR5:
+ case FSL_SAI_TDR:
+ case FSL_SAI_TMR:
+ case FSL_SAI_RCSR:
+ case FSL_SAI_RCR1:
+ case FSL_SAI_RCR2:
+ case FSL_SAI_RCR3:
+ case FSL_SAI_RCR4:
+ case FSL_SAI_RCR5:
+ case FSL_SAI_RMR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct regmap_config fsl_sai_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+
+ .max_register = FSL_SAI_RMR,
+ .readable_reg = fsl_sai_readable_reg,
+ .volatile_reg = fsl_sai_volatile_reg,
+ .writeable_reg = fsl_sai_writeable_reg,
+};
+
static int fsl_sai_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct fsl_sai *sai;
struct resource *res;
+ void __iomem *base;
int ret;
sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
if (!sai)
return -ENOMEM;
+ sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
+ if (sai->big_endian_regs)
+ fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
+
+ sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- sai->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(sai->base))
- return PTR_ERR(sai->base);
-
- sai->clk = devm_clk_get(&pdev->dev, "sai");
- if (IS_ERR(sai->clk)) {
- dev_err(&pdev->dev, "Cannot get SAI's clock\n");
- return PTR_ERR(sai->clk);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+ "sai", base, &fsl_sai_regmap_config);
+ if (IS_ERR(sai->regmap)) {
+ dev_err(&pdev->dev, "regmap init failed\n");
+ return PTR_ERR(sai->regmap);
}
sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
@@ -424,9 +519,6 @@ static int fsl_sai_probe(struct platform_device *pdev)
sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
- sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
- sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
-
platform_set_drvdata(pdev, sai);
ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index 41bb62e69361..e432260be598 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -15,31 +15,36 @@
SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
+/* SAI Register Map Register */
+#define FSL_SAI_TCSR 0x00 /* SAI Transmit Control */
+#define FSL_SAI_TCR1 0x04 /* SAI Transmit Configuration 1 */
+#define FSL_SAI_TCR2 0x08 /* SAI Transmit Configuration 2 */
+#define FSL_SAI_TCR3 0x0c /* SAI Transmit Configuration 3 */
+#define FSL_SAI_TCR4 0x10 /* SAI Transmit Configuration 4 */
+#define FSL_SAI_TCR5 0x14 /* SAI Transmit Configuration 5 */
+#define FSL_SAI_TDR 0x20 /* SAI Transmit Data */
+#define FSL_SAI_TFR 0x40 /* SAI Transmit FIFO */
+#define FSL_SAI_TMR 0x60 /* SAI Transmit Mask */
+#define FSL_SAI_RCSR 0x80 /* SAI Receive Control */
+#define FSL_SAI_RCR1 0x84 /* SAI Receive Configuration 1 */
+#define FSL_SAI_RCR2 0x88 /* SAI Receive Configuration 2 */
+#define FSL_SAI_RCR3 0x8c /* SAI Receive Configuration 3 */
+#define FSL_SAI_RCR4 0x90 /* SAI Receive Configuration 4 */
+#define FSL_SAI_RCR5 0x94 /* SAI Receive Configuration 5 */
+#define FSL_SAI_RDR 0xa0 /* SAI Receive Data */
+#define FSL_SAI_RFR 0xc0 /* SAI Receive FIFO */
+#define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */
+
/* SAI Transmit/Recieve Control Register */
-#define FSL_SAI_TCSR 0x00
-#define FSL_SAI_RCSR 0x80
#define FSL_SAI_CSR_TERE BIT(31)
#define FSL_SAI_CSR_FWF BIT(17)
#define FSL_SAI_CSR_FRIE BIT(8)
#define FSL_SAI_CSR_FRDE BIT(0)
-/* SAI Transmit Data/FIFO/MASK Register */
-#define FSL_SAI_TDR 0x20
-#define FSL_SAI_TFR 0x40
-#define FSL_SAI_TMR 0x60
-
-/* SAI Recieve Data/FIFO/MASK Register */
-#define FSL_SAI_RDR 0xa0
-#define FSL_SAI_RFR 0xc0
-#define FSL_SAI_RMR 0xe0
-
/* SAI Transmit and Recieve Configuration 1 Register */
-#define FSL_SAI_TCR1 0x04
-#define FSL_SAI_RCR1 0x84
+#define FSL_SAI_CR1_RFW_MASK 0x1f
/* SAI Transmit and Recieve Configuration 2 Register */
-#define FSL_SAI_TCR2 0x08
-#define FSL_SAI_RCR2 0x88
#define FSL_SAI_CR2_SYNC BIT(30)
#define FSL_SAI_CR2_MSEL_MASK (0xff << 26)
#define FSL_SAI_CR2_MSEL_BUS 0
@@ -50,15 +55,11 @@
#define FSL_SAI_CR2_BCD_MSTR BIT(24)
/* SAI Transmit and Recieve Configuration 3 Register */
-#define FSL_SAI_TCR3 0x0c
-#define FSL_SAI_RCR3 0x8c
#define FSL_SAI_CR3_TRCE BIT(16)
#define FSL_SAI_CR3_WDFL(x) (x)
#define FSL_SAI_CR3_WDFL_MASK 0x1f
/* SAI Transmit and Recieve Configuration 4 Register */
-#define FSL_SAI_TCR4 0x10
-#define FSL_SAI_RCR4 0x90
#define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16)
#define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16)
#define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8)
@@ -69,8 +70,6 @@
#define FSL_SAI_CR4_FSD_MSTR BIT(0)
/* SAI Transmit and Recieve Configuration 5 Register */
-#define FSL_SAI_TCR5 0x14
-#define FSL_SAI_RCR5 0x94
#define FSL_SAI_CR5_WNW(x) (((x) - 1) << 24)
#define FSL_SAI_CR5_WNW_MASK (0x1f << 24)
#define FSL_SAI_CR5_W0W(x) (((x) - 1) << 16)
@@ -100,12 +99,11 @@
#define FSL_SAI_MAXBURST_RX 6
struct fsl_sai {
- struct clk *clk;
-
- void __iomem *base;
+ struct regmap *regmap;
bool big_endian_regs;
bool big_endian_data;
+ bool is_dsp_mode;
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx;
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 4d075f1abe78..6452ca83d889 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -911,8 +911,8 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
{
struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai);
- dai->playback_dma_data = &spdif_private->dma_params_tx;
- dai->capture_dma_data = &spdif_private->dma_params_rx;
+ snd_soc_dai_init_dma_data(dai, &spdif_private->dma_params_tx,
+ &spdif_private->dma_params_rx);
snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls));
@@ -985,7 +985,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
}
}
-static const struct regmap_config fsl_spdif_regmap_config = {
+static struct regmap_config fsl_spdif_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
@@ -1105,6 +1105,9 @@ static int fsl_spdif_probe(struct platform_device *pdev)
memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
spdif_priv->cpu_dai_drv.name = spdif_priv->name;
+ if (of_property_read_bool(np, "big-endian"))
+ fsl_spdif_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
+
/* Get the addresses and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&pdev->dev, res);
diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c
index b9e42b503a37..2ac7755da876 100644
--- a/sound/soc/fsl/fsl_utils.c
+++ b/sound/soc/fsl/fsl_utils.c
@@ -86,6 +86,33 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np,
}
EXPORT_SYMBOL(fsl_asoc_get_dma_channel);
+/**
+ * fsl_asoc_xlate_tdm_slot_mask - generate TDM slot TX/RX mask.
+ *
+ * @slots: Number of slots in use.
+ * @tx_mask: bitmask representing active TX slots.
+ * @rx_mask: bitmask representing active RX slots.
+ *
+ * This function used to generate the TDM slot TX/RX mask. And the TX/RX
+ * mask will use a 0 bit for an active slot as default, and the default
+ * active bits are at the LSB of the mask value.
+ */
+int fsl_asoc_xlate_tdm_slot_mask(unsigned int slots,
+ unsigned int *tx_mask,
+ unsigned int *rx_mask)
+{
+ if (!slots)
+ return -EINVAL;
+
+ if (tx_mask)
+ *tx_mask = ~((1 << slots) - 1);
+ if (rx_mask)
+ *rx_mask = ~((1 << slots) - 1);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_asoc_xlate_tdm_slot_mask);
+
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
MODULE_DESCRIPTION("Freescale ASoC utility code");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_utils.h b/sound/soc/fsl/fsl_utils.h
index b2951126527c..df535db40313 100644
--- a/sound/soc/fsl/fsl_utils.h
+++ b/sound/soc/fsl/fsl_utils.h
@@ -22,5 +22,7 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, const char *name,
struct snd_soc_dai_link *dai,
unsigned int *dma_channel_id,
unsigned int *dma_id);
-
+int fsl_asoc_xlate_tdm_slot_mask(unsigned int slots,
+ unsigned int *tx_mask,
+ unsigned int *rx_mask);
#endif /* _FSL_UTILS_H */
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c
index 79cee782dbbf..a2fd7321b5a9 100644
--- a/sound/soc/fsl/imx-mc13783.c
+++ b/sound/soc/fsl/imx-mc13783.c
@@ -160,7 +160,6 @@ static struct platform_driver imx_mc13783_audio_driver = {
.driver = {
.name = "imx_mc13783",
.owner = THIS_MODULE,
- .pm = &snd_soc_pm_ops,
},
.probe = imx_mc13783_probe,
.remove = imx_mc13783_remove
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 6553202dd48c..7abf6a079574 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -270,18 +270,17 @@ static int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
ret = imx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
- goto out;
+ return ret;
}
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
ret = imx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
- goto out;
+ return ret;
}
-out:
- return ret;
+ return 0;
}
static int ssi_irq = 0;
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
index f2beae78969f..1cb22dd034eb 100644
--- a/sound/soc/fsl/imx-sgtl5000.c
+++ b/sound/soc/fsl/imx-sgtl5000.c
@@ -33,8 +33,7 @@ struct imx_sgtl5000_data {
static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd)
{
- struct imx_sgtl5000_data *data = container_of(rtd->card,
- struct imx_sgtl5000_data, card);
+ struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(rtd->card);
struct device *dev = rtd->card->dev;
int ret;
@@ -159,13 +158,15 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
data->card.dapm_widgets = imx_sgtl5000_dapm_widgets;
data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets);
+ platform_set_drvdata(pdev, &data->card);
+ snd_soc_card_set_drvdata(&data->card, data);
+
ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
goto fail;
}
- platform_set_drvdata(pdev, data);
of_node_put(ssi_np);
of_node_put(codec_np);
@@ -184,7 +185,8 @@ fail:
static int imx_sgtl5000_remove(struct platform_device *pdev)
{
- struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(card);
clk_put(data->codec_clk);
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index df552fa1aa65..ab2fdd76b693 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -50,6 +50,7 @@
#include <linux/platform_data/asoc-imx-ssi.h>
#include "imx-ssi.h"
+#include "fsl_utils.h"
#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV)
@@ -339,6 +340,7 @@ static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
.set_fmt = imx_ssi_set_dai_fmt,
.set_clkdiv = imx_ssi_set_dai_clkdiv,
.set_sysclk = imx_ssi_set_dai_sysclk,
+ .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask,
.set_tdm_slot = imx_ssi_set_dai_tdm_slot,
.trigger = imx_ssi_trigger,
};
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c
index 3fd76bc391de..3a3d17ce6ba4 100644
--- a/sound/soc/fsl/imx-wm8962.c
+++ b/sound/soc/fsl/imx-wm8962.c
@@ -71,7 +71,7 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card,
{
struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
struct imx_priv *priv = &card_priv;
- struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev);
+ struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
struct device *dev = &priv->pdev->dev;
unsigned int pll_out;
int ret;
@@ -137,7 +137,7 @@ static int imx_wm8962_late_probe(struct snd_soc_card *card)
{
struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
struct imx_priv *priv = &card_priv;
- struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev);
+ struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
struct device *dev = &priv->pdev->dev;
int ret;
@@ -264,13 +264,15 @@ static int imx_wm8962_probe(struct platform_device *pdev)
data->card.late_probe = imx_wm8962_late_probe;
data->card.set_bias_level = imx_wm8962_set_bias_level;
+ platform_set_drvdata(pdev, &data->card);
+ snd_soc_card_set_drvdata(&data->card, data);
+
ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
goto clk_fail;
}
- platform_set_drvdata(pdev, data);
of_node_put(ssi_np);
of_node_put(codec_np);
@@ -289,7 +291,8 @@ fail:
static int imx_wm8962_remove(struct platform_device *pdev)
{
- struct imx_wm8962_data *data = platform_get_drvdata(pdev);
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
if (!IS_ERR(data->codec_clk))
clk_disable_unprepare(data->codec_clk);
diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c
index fce63252bdbb..804749a6c61e 100644
--- a/sound/soc/fsl/wm1133-ev1.c
+++ b/sound/soc/fsl/wm1133-ev1.c
@@ -214,12 +214,6 @@ static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- snd_soc_dapm_new_controls(dapm, wm1133_ev1_widgets,
- ARRAY_SIZE(wm1133_ev1_widgets));
-
- snd_soc_dapm_add_routes(dapm, wm1133_ev1_map,
- ARRAY_SIZE(wm1133_ev1_map));
-
/* Headphone jack detection */
snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
@@ -257,6 +251,11 @@ static struct snd_soc_card wm1133_ev1 = {
.owner = THIS_MODULE,
.dai_link = &wm1133_ev1_dai,
.num_links = 1,
+
+ .dapm_widgets = wm1133_ev1_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm1133_ev1_widgets),
+ .dapm_routes = wm1133_ev1_map,
+ .num_dapm_routes = ARRAY_SIZE(wm1133_ev1_map),
};
static struct platform_device *wm1133_ev1_snd_device;
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 2a1b1b5b5221..21f1ccbdf582 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -9,48 +9,77 @@
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
+#include <linux/device.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/string.h>
#include <sound/simple_card.h>
+#include <sound/soc-dai.h>
+#include <sound/soc.h>
+
+struct simple_card_data {
+ struct snd_soc_card snd_card;
+ struct simple_dai_props {
+ struct asoc_simple_dai cpu_dai;
+ struct asoc_simple_dai codec_dai;
+ } *dai_props;
+ struct snd_soc_dai_link dai_link[]; /* dynamically allocated */
+};
static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
- struct asoc_simple_dai *set,
- unsigned int daifmt)
+ struct asoc_simple_dai *set)
{
- int ret = 0;
+ int ret;
- daifmt |= set->fmt;
+ if (set->fmt) {
+ ret = snd_soc_dai_set_fmt(dai, set->fmt);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dai->dev, "simple-card: set_fmt error\n");
+ goto err;
+ }
+ }
- if (daifmt)
- ret = snd_soc_dai_set_fmt(dai, daifmt);
+ if (set->sysclk) {
+ ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dai->dev, "simple-card: set_sysclk error\n");
+ goto err;
+ }
+ }
- if (ret == -ENOTSUPP) {
- dev_dbg(dai->dev, "ASoC: set_fmt is not supported\n");
- ret = 0;
+ if (set->slots) {
+ ret = snd_soc_dai_set_tdm_slot(dai, 0, 0,
+ set->slots,
+ set->slot_width);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
+ goto err;
+ }
}
- if (!ret && set->sysclk)
- ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
+ ret = 0;
+err:
return ret;
}
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
- struct asoc_simple_card_info *info =
+ struct simple_card_data *priv =
snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *codec = rtd->codec_dai;
struct snd_soc_dai *cpu = rtd->cpu_dai;
- unsigned int daifmt = info->daifmt;
- int ret;
+ struct simple_dai_props *dai_props;
+ int num, ret;
- ret = __asoc_simple_card_dai_init(codec, &info->codec_dai, daifmt);
+ num = rtd - rtd->card->rtd;
+ dai_props = &priv->dai_props[num];
+ ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai);
if (ret < 0)
return ret;
- ret = __asoc_simple_card_dai_init(cpu, &info->cpu_dai, daifmt);
+ ret = __asoc_simple_card_dai_init(cpu, &dai_props->cpu_dai);
if (ret < 0)
return ret;
@@ -59,9 +88,12 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
static int
asoc_simple_card_sub_parse_of(struct device_node *np,
+ unsigned int daifmt,
struct asoc_simple_dai *dai,
- struct device_node **node)
+ const struct device_node **p_node,
+ const char **name)
{
+ struct device_node *node;
struct clk *clk;
int ret;
@@ -69,14 +101,20 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
* get node via "sound-dai = <&phandle port>"
* it will be used as xxx_of_node on soc_bind_dai_link()
*/
- *node = of_parse_phandle(np, "sound-dai", 0);
- if (!*node)
+ node = of_parse_phandle(np, "sound-dai", 0);
+ if (!node)
return -ENODEV;
+ *p_node = node;
/* get dai->name */
- ret = snd_soc_of_get_dai_name(np, &dai->name);
+ ret = snd_soc_of_get_dai_name(np, name);
if (ret < 0)
- goto parse_error;
+ return ret;
+
+ /* parse TDM slot */
+ ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
+ if (ret)
+ return ret;
/*
* bitclock-inversion, frame-inversion
@@ -84,6 +122,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
* and specific "format" if it has
*/
dai->fmt = snd_soc_of_parse_daifmt(np, NULL);
+ dai->fmt |= daifmt;
/*
* dai->sysclk come from
@@ -95,7 +134,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- goto parse_error;
+ return ret;
}
dai->sysclk = clk_get_rate(clk);
@@ -104,164 +143,278 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
"system-clock-frequency",
&dai->sysclk);
} else {
- clk = of_clk_get(*node, 0);
+ clk = of_clk_get(node, 0);
if (!IS_ERR(clk))
dai->sysclk = clk_get_rate(clk);
}
- ret = 0;
+ return 0;
+}
+
+static int simple_card_cpu_codec_of(struct device_node *node,
+ int daifmt,
+ struct snd_soc_dai_link *dai_link,
+ struct simple_dai_props *dai_props)
+{
+ struct device_node *np;
+ int ret;
-parse_error:
- of_node_put(*node);
+ /* CPU sub-node */
+ ret = -EINVAL;
+ np = of_get_child_by_name(node, "simple-audio-card,cpu");
+ if (np) {
+ ret = asoc_simple_card_sub_parse_of(np, daifmt,
+ &dai_props->cpu_dai,
+ &dai_link->cpu_of_node,
+ &dai_link->cpu_dai_name);
+ of_node_put(np);
+ }
+ if (ret < 0)
+ return ret;
+ /* CODEC sub-node */
+ ret = -EINVAL;
+ np = of_get_child_by_name(node, "simple-audio-card,codec");
+ if (np) {
+ ret = asoc_simple_card_sub_parse_of(np, daifmt,
+ &dai_props->codec_dai,
+ &dai_link->codec_of_node,
+ &dai_link->codec_dai_name);
+ of_node_put(np);
+ }
return ret;
}
static int asoc_simple_card_parse_of(struct device_node *node,
- struct asoc_simple_card_info *info,
+ struct simple_card_data *priv,
struct device *dev,
- struct device_node **of_cpu,
- struct device_node **of_codec,
- struct device_node **of_platform)
+ int multi)
{
+ struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
+ struct simple_dai_props *dai_props = priv->dai_props;
struct device_node *np;
char *name;
+ unsigned int daifmt;
int ret;
+ /* parsing the card name from DT */
+ snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
+
/* get CPU/CODEC common format via simple-audio-card,format */
- info->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
+ daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
(SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
+ /* off-codec widgets */
+ if (of_property_read_bool(node, "simple-audio-card,widgets")) {
+ ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
+ "simple-audio-card,widgets");
+ if (ret)
+ return ret;
+ }
+
/* DAPM routes */
if (of_property_read_bool(node, "simple-audio-card,routing")) {
- ret = snd_soc_of_parse_audio_routing(&info->snd_card,
+ ret = snd_soc_of_parse_audio_routing(&priv->snd_card,
"simple-audio-card,routing");
if (ret)
return ret;
}
- /* CPU sub-node */
- ret = -EINVAL;
- np = of_get_child_by_name(node, "simple-audio-card,cpu");
- if (np)
- ret = asoc_simple_card_sub_parse_of(np,
- &info->cpu_dai,
- of_cpu);
- if (ret < 0)
- return ret;
+ /* loop on the DAI links */
+ np = NULL;
+ for (;;) {
+ if (multi) {
+ np = of_get_next_child(node, np);
+ if (!np)
+ break;
+ }
- /* CODEC sub-node */
- ret = -EINVAL;
- np = of_get_child_by_name(node, "simple-audio-card,codec");
- if (np)
- ret = asoc_simple_card_sub_parse_of(np,
- &info->codec_dai,
- of_codec);
- if (ret < 0)
- return ret;
+ ret = simple_card_cpu_codec_of(multi ? np : node,
+ daifmt, dai_link, dai_props);
+ if (ret < 0)
+ goto err;
+
+ /*
+ * overwrite cpu_dai->fmt as its DAIFMT_MASTER bit is based on CODEC
+ * while the other bits should be identical unless buggy SW/HW design.
+ */
+ dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt;
+
+ if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* simple-card assumes platform == cpu */
+ dai_link->platform_of_node = dai_link->cpu_of_node;
+
+ name = devm_kzalloc(dev,
+ strlen(dai_link->cpu_dai_name) +
+ strlen(dai_link->codec_dai_name) + 2,
+ GFP_KERNEL);
+ sprintf(name, "%s-%s", dai_link->cpu_dai_name,
+ dai_link->codec_dai_name);
+ dai_link->name = dai_link->stream_name = name;
- if (!info->cpu_dai.name || !info->codec_dai.name)
- return -EINVAL;
+ if (!multi)
+ break;
+
+ dai_link++;
+ dai_props++;
+ }
/* card name is created from CPU/CODEC dai name */
- name = devm_kzalloc(dev,
- strlen(info->cpu_dai.name) +
- strlen(info->codec_dai.name) + 2,
- GFP_KERNEL);
- sprintf(name, "%s-%s", info->cpu_dai.name, info->codec_dai.name);
- info->name = info->card = name;
-
- /* simple-card assumes platform == cpu */
- *of_platform = *of_cpu;
-
- dev_dbg(dev, "card-name : %s\n", info->card);
- dev_dbg(dev, "platform : %04x\n", info->daifmt);
+ dai_link = priv->snd_card.dai_link;
+ if (!priv->snd_card.name)
+ priv->snd_card.name = dai_link->name;
+
+ dev_dbg(dev, "card-name : %s\n", priv->snd_card.name);
+ dev_dbg(dev, "platform : %04x\n", daifmt);
+ dai_props = priv->dai_props;
dev_dbg(dev, "cpu : %s / %04x / %d\n",
- info->cpu_dai.name,
- info->cpu_dai.fmt,
- info->cpu_dai.sysclk);
+ dai_link->cpu_dai_name,
+ dai_props->cpu_dai.fmt,
+ dai_props->cpu_dai.sysclk);
dev_dbg(dev, "codec : %s / %04x / %d\n",
- info->codec_dai.name,
- info->codec_dai.fmt,
- info->codec_dai.sysclk);
+ dai_link->codec_dai_name,
+ dai_props->codec_dai.fmt,
+ dai_props->codec_dai.sysclk);
return 0;
+
+err:
+ of_node_put(np);
+ return ret;
+}
+
+/* update the reference count of the devices nodes at end of probe */
+static int asoc_simple_card_unref(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct snd_soc_dai_link *dai_link;
+ struct device_node *np;
+ int num_links;
+
+ for (num_links = 0, dai_link = card->dai_link;
+ num_links < card->num_links;
+ num_links++, dai_link++) {
+ np = (struct device_node *) dai_link->cpu_of_node;
+ if (np)
+ of_node_put(np);
+ np = (struct device_node *) dai_link->codec_of_node;
+ if (np)
+ of_node_put(np);
+ }
+ return 0;
}
static int asoc_simple_card_probe(struct platform_device *pdev)
{
- struct asoc_simple_card_info *cinfo;
+ struct simple_card_data *priv;
+ struct snd_soc_dai_link *dai_link;
struct device_node *np = pdev->dev.of_node;
- struct device_node *of_cpu, *of_codec, *of_platform;
struct device *dev = &pdev->dev;
- int ret;
+ int num_links, multi, ret;
+
+ /* get the number of DAI links */
+ if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) {
+ num_links = of_get_child_count(np);
+ multi = 1;
+ } else {
+ num_links = 1;
+ multi = 0;
+ }
- cinfo = NULL;
- of_cpu = NULL;
- of_codec = NULL;
- of_platform = NULL;
+ /* allocate the private data and the DAI link array */
+ priv = devm_kzalloc(dev,
+ sizeof(*priv) + sizeof(*dai_link) * num_links,
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
- cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL);
- if (!cinfo)
+ /*
+ * init snd_soc_card
+ */
+ priv->snd_card.owner = THIS_MODULE;
+ priv->snd_card.dev = dev;
+ dai_link = priv->dai_link;
+ priv->snd_card.dai_link = dai_link;
+ priv->snd_card.num_links = num_links;
+
+ /* get room for the other properties */
+ priv->dai_props = devm_kzalloc(dev,
+ sizeof(*priv->dai_props) * num_links,
+ GFP_KERNEL);
+ if (!priv->dai_props)
return -ENOMEM;
if (np && of_device_is_available(np)) {
- cinfo->snd_card.dev = dev;
- ret = asoc_simple_card_parse_of(np, cinfo, dev,
- &of_cpu,
- &of_codec,
- &of_platform);
+ ret = asoc_simple_card_parse_of(np, priv, dev, multi);
if (ret < 0) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "parse error %d\n", ret);
- return ret;
+ goto err;
}
+
+ /*
+ * soc_bind_dai_link() will check cpu name
+ * after of_node matching if dai_link has cpu_dai_name.
+ * but, it will never match if name was created by fmt_single_name()
+ * remove cpu_dai_name to escape name matching.
+ * see
+ * fmt_single_name()
+ * fmt_multiple_name()
+ */
+ if (num_links == 1)
+ dai_link->cpu_dai_name = NULL;
+
} else {
- if (!dev->platform_data) {
+ struct asoc_simple_card_info *cinfo;
+
+ cinfo = dev->platform_data;
+ if (!cinfo) {
dev_err(dev, "no info for asoc-simple-card\n");
return -EINVAL;
}
- memcpy(cinfo, dev->platform_data, sizeof(*cinfo));
- cinfo->snd_card.dev = dev;
- }
+ if (!cinfo->name ||
+ !cinfo->codec_dai.name ||
+ !cinfo->codec ||
+ !cinfo->platform ||
+ !cinfo->cpu_dai.name) {
+ dev_err(dev, "insufficient asoc_simple_card_info settings\n");
+ return -EINVAL;
+ }
- if (!cinfo->name ||
- !cinfo->card ||
- !cinfo->codec_dai.name ||
- !(cinfo->codec || of_codec) ||
- !(cinfo->platform || of_platform) ||
- !(cinfo->cpu_dai.name || of_cpu)) {
- dev_err(dev, "insufficient asoc_simple_card_info settings\n");
- return -EINVAL;
+ priv->snd_card.name = (cinfo->card) ? cinfo->card : cinfo->name;
+ dai_link->name = cinfo->name;
+ dai_link->stream_name = cinfo->name;
+ dai_link->platform_name = cinfo->platform;
+ dai_link->codec_name = cinfo->codec;
+ dai_link->cpu_dai_name = cinfo->cpu_dai.name;
+ dai_link->codec_dai_name = cinfo->codec_dai.name;
+ memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
+ sizeof(priv->dai_props->cpu_dai));
+ memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
+ sizeof(priv->dai_props->codec_dai));
+
+ priv->dai_props->cpu_dai.fmt |= cinfo->daifmt;
+ priv->dai_props->codec_dai.fmt |= cinfo->daifmt;
}
/*
* init snd_soc_dai_link
*/
- cinfo->snd_link.name = cinfo->name;
- cinfo->snd_link.stream_name = cinfo->name;
- cinfo->snd_link.cpu_dai_name = cinfo->cpu_dai.name;
- cinfo->snd_link.platform_name = cinfo->platform;
- cinfo->snd_link.codec_name = cinfo->codec;
- cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name;
- cinfo->snd_link.cpu_of_node = of_cpu;
- cinfo->snd_link.codec_of_node = of_codec;
- cinfo->snd_link.platform_of_node = of_platform;
- cinfo->snd_link.init = asoc_simple_card_dai_init;
+ dai_link->init = asoc_simple_card_dai_init;
- /*
- * init snd_soc_card
- */
- cinfo->snd_card.name = cinfo->card;
- cinfo->snd_card.owner = THIS_MODULE;
- cinfo->snd_card.dai_link = &cinfo->snd_link;
- cinfo->snd_card.num_links = 1;
+ snd_soc_card_set_drvdata(&priv->snd_card, priv);
- snd_soc_card_set_drvdata(&cinfo->snd_card, cinfo);
+ ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
- return devm_snd_soc_register_card(&pdev->dev, &cinfo->snd_card);
+err:
+ asoc_simple_card_unref(pdev);
+ return ret;
}
static const struct of_device_id asoc_simple_of_match[] = {
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 61c10bf503d2..3c81b3891209 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -2,12 +2,50 @@ config SND_MFLD_MACHINE
tristate "SOC Machine Audio driver for Intel Medfield MID platform"
depends on INTEL_SCU_IPC
select SND_SOC_SN95031
- select SND_SST_PLATFORM
+ select SND_SST_MFLD_PLATFORM
help
This adds support for ASoC machine driver for Intel(R) MID Medfield platform
used as alsa device in audio substem in Intel(R) MID devices
Say Y if you have such a device
If unsure select "N".
-config SND_SST_PLATFORM
+config SND_SST_MFLD_PLATFORM
tristate
+
+config SND_SOC_INTEL_SST
+ tristate "ASoC support for Intel(R) Smart Sound Technology"
+ select SND_SOC_INTEL_SST_ACPI if ACPI
+ depends on (X86 || COMPILE_TEST)
+ help
+ This adds support for Intel(R) Smart Sound Technology (SST).
+ Say Y if you have such a device
+ If unsure select "N".
+
+config SND_SOC_INTEL_SST_ACPI
+ tristate
+
+config SND_SOC_INTEL_HASWELL
+ tristate
+
+config SND_SOC_INTEL_BAYTRAIL
+ tristate
+
+config SND_SOC_INTEL_HASWELL_MACH
+ tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
+ depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C
+ select SND_SOC_INTEL_HASWELL
+ select SND_SOC_RT5640
+ help
+ This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell
+ Ultrabook platforms.
+ Say Y if you have such a device
+ If unsure select "N".
+
+config SND_SOC_INTEL_BYT_RT5640_MACH
+ tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
+ depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C
+ select SND_SOC_INTEL_BAYTRAIL
+ select SND_SOC_RT5640
+ help
+ This adds audio driver for Intel Baytrail platform based boards
+ with the RT5640 audio codec.
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index 639883339465..edeb79ae3dff 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -1,5 +1,28 @@
-snd-soc-sst-platform-objs := sst_platform.o
+# Core support
+snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o
+snd-soc-sst-acpi-objs := sst-acpi.o
+
+snd-soc-sst-mfld-platform-objs := sst-mfld-platform.o
snd-soc-mfld-machine-objs := mfld_machine.o
-obj-$(CONFIG_SND_SST_PLATFORM) += snd-soc-sst-platform.o
+obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o
obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o
+
+obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o
+obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
+
+# Platform Support
+snd-soc-sst-haswell-pcm-objs := \
+ sst-haswell-ipc.o sst-haswell-pcm.o sst-haswell-dsp.o
+snd-soc-sst-baytrail-pcm-objs := \
+ sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o
+
+obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += snd-soc-sst-haswell-pcm.o
+obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o
+
+# Machine support
+snd-soc-sst-haswell-objs := haswell.o
+snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
+
+obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
+obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c
new file mode 100644
index 000000000000..eff97c8e5218
--- /dev/null
+++ b/sound/soc/intel/byt-rt5640.c
@@ -0,0 +1,187 @@
+/*
+ * Intel Baytrail SST RT5640 machine driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../codecs/rt5640.h"
+
+#include "sst-dsp.h"
+
+static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Internal Mic", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
+ {"IN2P", NULL, "Headset Mic"},
+ {"IN2N", NULL, "Headset Mic"},
+ {"DMIC1", NULL, "Internal Mic"},
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+ {"Speaker", NULL, "SPOLP"},
+ {"Speaker", NULL, "SPOLN"},
+ {"Speaker", NULL, "SPORP"},
+ {"Speaker", NULL, "SPORN"},
+};
+
+static const struct snd_kcontrol_new byt_rt5640_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Internal Mic"),
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static int byt_rt5640_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
+ params_rate(params) * 256,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "can't set codec clock %d\n", ret);
+ return ret;
+ }
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1,
+ params_rate(params) * 64,
+ params_rate(params) * 256);
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
+{
+ int ret;
+ struct snd_soc_codec *codec = runtime->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_card *card = runtime->card;
+
+ card->dapm.idle_bias_off = true;
+
+ ret = snd_soc_add_card_controls(card, byt_rt5640_controls,
+ ARRAY_SIZE(byt_rt5640_controls));
+ if (ret) {
+ dev_err(card->dev, "unable to add card controls\n");
+ return ret;
+ }
+
+ snd_soc_dapm_ignore_suspend(dapm, "HPOL");
+ snd_soc_dapm_ignore_suspend(dapm, "HPOR");
+
+ snd_soc_dapm_ignore_suspend(dapm, "SPOLP");
+ snd_soc_dapm_ignore_suspend(dapm, "SPOLN");
+ snd_soc_dapm_ignore_suspend(dapm, "SPORP");
+ snd_soc_dapm_ignore_suspend(dapm, "SPORN");
+
+ snd_soc_dapm_enable_pin(dapm, "Headset Mic");
+ snd_soc_dapm_enable_pin(dapm, "Headphone");
+ snd_soc_dapm_enable_pin(dapm, "Speaker");
+ snd_soc_dapm_enable_pin(dapm, "Internal Mic");
+
+ snd_soc_dapm_sync(dapm);
+ return ret;
+}
+
+static struct snd_soc_ops byt_rt5640_ops = {
+ .hw_params = byt_rt5640_hw_params,
+};
+
+static struct snd_soc_dai_link byt_rt5640_dais[] = {
+ {
+ .name = "Baytrail Audio",
+ .stream_name = "Audio",
+ .cpu_dai_name = "Front-cpu-dai",
+ .codec_dai_name = "rt5640-aif1",
+ .codec_name = "i2c-10EC5640:00",
+ .platform_name = "baytrail-pcm-audio",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .init = byt_rt5640_init,
+ .ignore_suspend = 1,
+ .ops = &byt_rt5640_ops,
+ },
+ {
+ .name = "Baytrail Voice",
+ .stream_name = "Voice",
+ .cpu_dai_name = "Mic1-cpu-dai",
+ .codec_dai_name = "rt5640-aif1",
+ .codec_name = "i2c-10EC5640:00",
+ .platform_name = "baytrail-pcm-audio",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .init = NULL,
+ .ignore_suspend = 1,
+ .ops = &byt_rt5640_ops,
+ },
+};
+
+static struct snd_soc_card byt_rt5640_card = {
+ .name = "byt-rt5640",
+ .dai_link = byt_rt5640_dais,
+ .num_links = ARRAY_SIZE(byt_rt5640_dais),
+ .dapm_widgets = byt_rt5640_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
+ .dapm_routes = byt_rt5640_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
+};
+
+static int byt_rt5640_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &byt_rt5640_card;
+ struct device *dev = &pdev->dev;
+
+ card->dev = &pdev->dev;
+ dev_set_drvdata(dev, card);
+ return snd_soc_register_card(card);
+}
+
+static int byt_rt5640_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_card(card);
+
+ return 0;
+}
+
+static struct platform_driver byt_rt5640_audio = {
+ .probe = byt_rt5640_probe,
+ .remove = byt_rt5640_remove,
+ .driver = {
+ .name = "byt-rt5640",
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver(byt_rt5640_audio)
+
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver");
+MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:byt-rt5640");
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c
new file mode 100644
index 000000000000..54345a2a7386
--- /dev/null
+++ b/sound/soc/intel/haswell.c
@@ -0,0 +1,235 @@
+/*
+ * Intel Haswell Lynxpoint SST Audio
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+#include "sst-dsp.h"
+#include "sst-haswell-ipc.h"
+
+#include "../codecs/rt5640.h"
+
+/* Haswell ULT platforms have a Headphone and Mic jack */
+static const struct snd_soc_dapm_widget haswell_widgets[] = {
+ SND_SOC_DAPM_HP("Headphones", NULL),
+ SND_SOC_DAPM_MIC("Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route haswell_rt5640_map[] = {
+
+ {"Headphones", NULL, "HPOR"},
+ {"Headphones", NULL, "HPOL"},
+ {"IN2P", NULL, "Mic"},
+
+ /* CODEC BE connections */
+ {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
+ {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
+};
+
+static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ /* The ADSP will covert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP0 to 16 bit */
+ snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
+ SNDRV_PCM_HW_PARAM_FIRST_MASK],
+ SNDRV_PCM_FORMAT_S16_LE);
+ return 0;
+}
+
+static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000,
+ SND_SOC_CLOCK_IN);
+
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec sysclk configuration\n");
+ return ret;
+ }
+
+ /* set correct codec filter for DAI format and clock config */
+ snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000);
+
+ return ret;
+}
+
+static struct snd_soc_ops haswell_rt5640_ops = {
+ .hw_params = haswell_rt5640_hw_params,
+};
+
+static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
+ struct sst_hsw *haswell = pdata->dsp;
+ int ret;
+
+ /* Set ADSP SSP port settings */
+ ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0,
+ SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
+ SST_HSW_DEVICE_CLOCK_MASTER, 9);
+ if (ret < 0) {
+ dev_err(rtd->dev, "failed to set device config\n");
+ return ret;
+ }
+
+ /* always connected */
+ snd_soc_dapm_enable_pin(dapm, "Headphones");
+ snd_soc_dapm_enable_pin(dapm, "Mic");
+
+ return 0;
+}
+
+static struct snd_soc_dai_link haswell_rt5640_dais[] = {
+ /* Front End DAI links */
+ {
+ .name = "System",
+ .stream_name = "System Playback",
+ .cpu_dai_name = "System Pin",
+ .platform_name = "haswell-pcm-audio",
+ .dynamic = 1,
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .init = haswell_rtd_init,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ },
+ {
+ .name = "Offload0",
+ .stream_name = "Offload0 Playback",
+ .cpu_dai_name = "Offload0 Pin",
+ .platform_name = "haswell-pcm-audio",
+ .dynamic = 1,
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ },
+ {
+ .name = "Offload1",
+ .stream_name = "Offload1 Playback",
+ .cpu_dai_name = "Offload1 Pin",
+ .platform_name = "haswell-pcm-audio",
+ .dynamic = 1,
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ },
+ {
+ .name = "Loopback",
+ .stream_name = "Loopback",
+ .cpu_dai_name = "Loopback Pin",
+ .platform_name = "haswell-pcm-audio",
+ .dynamic = 0,
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_capture = 1,
+ },
+ {
+ .name = "Capture",
+ .stream_name = "Capture",
+ .cpu_dai_name = "Capture Pin",
+ .platform_name = "haswell-pcm-audio",
+ .dynamic = 1,
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_capture = 1,
+ },
+
+ /* Back End DAI links */
+ {
+ /* SSP0 - Codec */
+ .name = "Codec",
+ .be_id = 0,
+ .cpu_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "snd-soc-dummy",
+ .no_pcm = 1,
+ .codec_name = "i2c-INT33CA:00",
+ .codec_dai_name = "rt5640-aif1",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = haswell_ssp0_fixup,
+ .ops = &haswell_rt5640_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ },
+};
+
+/* audio machine driver for Haswell Lynxpoint DSP + RT5640 */
+static struct snd_soc_card haswell_rt5640 = {
+ .name = "haswell-rt5640",
+ .owner = THIS_MODULE,
+ .dai_link = haswell_rt5640_dais,
+ .num_links = ARRAY_SIZE(haswell_rt5640_dais),
+ .dapm_widgets = haswell_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(haswell_widgets),
+ .dapm_routes = haswell_rt5640_map,
+ .num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map),
+ .fully_routed = true,
+};
+
+static int haswell_audio_probe(struct platform_device *pdev)
+{
+ haswell_rt5640.dev = &pdev->dev;
+
+ return snd_soc_register_card(&haswell_rt5640);
+}
+
+static int haswell_audio_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_card(&haswell_rt5640);
+ return 0;
+}
+
+static struct platform_driver haswell_audio = {
+ .probe = haswell_audio_probe,
+ .remove = haswell_audio_remove,
+ .driver = {
+ .name = "haswell-audio",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(haswell_audio)
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
+MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:haswell-audio");
diff --git a/sound/soc/intel/mfld_machine.c b/sound/soc/intel/mfld_machine.c
index d3d4c32434f7..031d78783fc8 100644
--- a/sound/soc/intel/mfld_machine.c
+++ b/sound/soc/intel/mfld_machine.c
@@ -53,6 +53,7 @@ enum soc_mic_bias_zones {
static unsigned int hs_switch;
static unsigned int lo_dac;
+static struct snd_soc_codec *mfld_codec;
struct mfld_mc_private {
void __iomem *int_base;
@@ -100,40 +101,47 @@ static int headset_get_switch(struct snd_kcontrol *kcontrol,
static int headset_set_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = &card->dapm;
if (ucontrol->value.integer.value[0] == hs_switch)
return 0;
+ snd_soc_dapm_mutex_lock(dapm);
+
if (ucontrol->value.integer.value[0]) {
pr_debug("hs_set HS path\n");
- snd_soc_dapm_enable_pin(&codec->dapm, "Headphones");
- snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
} else {
pr_debug("hs_set EP path\n");
- snd_soc_dapm_disable_pin(&codec->dapm, "Headphones");
- snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
}
- snd_soc_dapm_sync(&codec->dapm);
+
+ snd_soc_dapm_sync_unlocked(dapm);
+
+ snd_soc_dapm_mutex_unlock(dapm);
+
hs_switch = ucontrol->value.integer.value[0];
return 0;
}
-static void lo_enable_out_pins(struct snd_soc_codec *codec)
+static void lo_enable_out_pins(struct snd_soc_dapm_context *dapm)
{
- snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTL");
- snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTR");
- snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTL");
- snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTR");
- snd_soc_dapm_enable_pin(&codec->dapm, "VIB1OUT");
- snd_soc_dapm_enable_pin(&codec->dapm, "VIB2OUT");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTR");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "VIB1OUT");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "VIB2OUT");
if (hs_switch) {
- snd_soc_dapm_enable_pin(&codec->dapm, "Headphones");
- snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
} else {
- snd_soc_dapm_disable_pin(&codec->dapm, "Headphones");
- snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
}
}
@@ -147,45 +155,53 @@ static int lo_get_switch(struct snd_kcontrol *kcontrol,
static int lo_set_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_context *dapm = &card->dapm;
if (ucontrol->value.integer.value[0] == lo_dac)
return 0;
+ snd_soc_dapm_mutex_lock(dapm);
+
/* we dont want to work with last state of lineout so just enable all
* pins and then disable pins not required
*/
- lo_enable_out_pins(codec);
+ lo_enable_out_pins(dapm);
+
switch (ucontrol->value.integer.value[0]) {
case 0:
pr_debug("set vibra path\n");
- snd_soc_dapm_disable_pin(&codec->dapm, "VIB1OUT");
- snd_soc_dapm_disable_pin(&codec->dapm, "VIB2OUT");
- snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0);
+ snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT");
+ snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0);
break;
case 1:
pr_debug("set hs path\n");
- snd_soc_dapm_disable_pin(&codec->dapm, "Headphones");
- snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
- snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22);
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
+ snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x22);
break;
case 2:
pr_debug("set spkr path\n");
- snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTL");
- snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTR");
- snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44);
+ snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR");
+ snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x44);
break;
case 3:
pr_debug("set null path\n");
- snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTL");
- snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTR");
- snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66);
+ snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR");
+ snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x66);
break;
}
- snd_soc_dapm_sync(&codec->dapm);
+
+ snd_soc_dapm_sync_unlocked(dapm);
+
+ snd_soc_dapm_mutex_unlock(dapm);
+
lo_dac = ucontrol->value.integer.value[0];
return 0;
}
@@ -221,26 +237,11 @@ static void mfld_jack_check(unsigned int intr_status)
static int mfld_init(struct snd_soc_pcm_runtime *runtime)
{
- struct snd_soc_codec *codec = runtime->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
int ret_val;
- /* Add jack sense widgets */
- snd_soc_dapm_new_controls(dapm, mfld_widgets, ARRAY_SIZE(mfld_widgets));
-
- /* Set up the map */
- snd_soc_dapm_add_routes(dapm, mfld_map, ARRAY_SIZE(mfld_map));
+ mfld_codec = runtime->codec;
- /* always connected */
- snd_soc_dapm_enable_pin(dapm, "Headphones");
- snd_soc_dapm_enable_pin(dapm, "Mic");
-
- ret_val = snd_soc_add_codec_controls(codec, mfld_snd_controls,
- ARRAY_SIZE(mfld_snd_controls));
- if (ret_val) {
- pr_err("soc_add_controls failed %d", ret_val);
- return ret_val;
- }
/* default is earpiece pin, userspace sets it explcitly */
snd_soc_dapm_disable_pin(dapm, "Headphones");
/* default is lineout NC, userspace sets it explcitly */
@@ -253,7 +254,7 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
snd_soc_dapm_disable_pin(dapm, "LINEINR");
/* Headset and button jack detection */
- ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack",
+ ret_val = snd_soc_jack_new(mfld_codec, "Intel(R) MID Audio Jack",
SND_JACK_HEADSET | SND_JACK_BTN_0 |
SND_JACK_BTN_1, &mfld_jack);
if (ret_val) {
@@ -335,6 +336,13 @@ static struct snd_soc_card snd_soc_card_mfld = {
.owner = THIS_MODULE,
.dai_link = mfld_msic_dailink,
.num_links = ARRAY_SIZE(mfld_msic_dailink),
+
+ .controls = mfld_snd_controls,
+ .num_controls = ARRAY_SIZE(mfld_snd_controls),
+ .dapm_widgets = mfld_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mfld_widgets),
+ .dapm_routes = mfld_map,
+ .num_dapm_routes = ARRAY_SIZE(mfld_map),
};
static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c
new file mode 100644
index 000000000000..5d06eecb6198
--- /dev/null
+++ b/sound/soc/intel/sst-acpi.c
@@ -0,0 +1,284 @@
+/*
+ * Intel SST loader on ACPI systems
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 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/acpi.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "sst-dsp.h"
+
+#define SST_LPT_DSP_DMA_ADDR_OFFSET 0x0F0000
+#define SST_WPT_DSP_DMA_ADDR_OFFSET 0x0FE000
+#define SST_LPT_DSP_DMA_SIZE (1024 - 1)
+
+/* Descriptor for SST ASoC machine driver */
+struct sst_acpi_mach {
+ /* ACPI ID for the matching machine driver. Audio codec for instance */
+ const u8 id[ACPI_ID_LEN];
+ /* machine driver name */
+ const char *drv_name;
+ /* firmware file name */
+ const char *fw_filename;
+};
+
+/* Descriptor for setting up SST platform data */
+struct sst_acpi_desc {
+ const char *drv_name;
+ struct sst_acpi_mach *machines;
+ /* Platform resource indexes. Must set to -1 if not used */
+ int resindex_lpe_base;
+ int resindex_pcicfg_base;
+ int resindex_fw_base;
+ int irqindex_host_ipc;
+ int resindex_dma_base;
+ /* Unique number identifying the SST core on platform */
+ int sst_id;
+ /* DMA only valid when resindex_dma_base != -1*/
+ int dma_engine;
+ int dma_size;
+};
+
+struct sst_acpi_priv {
+ struct platform_device *pdev_mach;
+ struct platform_device *pdev_pcm;
+ struct sst_pdata sst_pdata;
+ struct sst_acpi_desc *desc;
+ struct sst_acpi_mach *mach;
+};
+
+static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
+{
+ struct platform_device *pdev = context;
+ struct device *dev = &pdev->dev;
+ struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
+ struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
+ struct sst_acpi_desc *desc = sst_acpi->desc;
+ struct sst_acpi_mach *mach = sst_acpi->mach;
+
+ sst_pdata->fw = fw;
+ if (!fw) {
+ dev_err(dev, "Cannot load firmware %s\n", mach->fw_filename);
+ return;
+ }
+
+ /* register PCM and DAI driver */
+ sst_acpi->pdev_pcm =
+ platform_device_register_data(dev, desc->drv_name, -1,
+ sst_pdata, sizeof(*sst_pdata));
+ if (IS_ERR(sst_acpi->pdev_pcm)) {
+ dev_err(dev, "Cannot register device %s. Error %d\n",
+ desc->drv_name, (int)PTR_ERR(sst_acpi->pdev_pcm));
+ }
+
+ return;
+}
+
+static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
+ void *context, void **ret)
+{
+ *(bool *)context = true;
+ return AE_OK;
+}
+
+static struct sst_acpi_mach *sst_acpi_find_machine(
+ struct sst_acpi_mach *machines)
+{
+ struct sst_acpi_mach *mach;
+ bool found = false;
+
+ for (mach = machines; mach->id[0]; mach++)
+ if (ACPI_SUCCESS(acpi_get_devices(mach->id,
+ sst_acpi_mach_match,
+ &found, NULL)) && found)
+ return mach;
+
+ return NULL;
+}
+
+static int sst_acpi_probe(struct platform_device *pdev)
+{
+ const struct acpi_device_id *id;
+ struct device *dev = &pdev->dev;
+ struct sst_acpi_priv *sst_acpi;
+ struct sst_pdata *sst_pdata;
+ struct sst_acpi_mach *mach;
+ struct sst_acpi_desc *desc;
+ struct resource *mmio;
+ int ret = 0;
+
+ sst_acpi = devm_kzalloc(dev, sizeof(*sst_acpi), GFP_KERNEL);
+ if (sst_acpi == NULL)
+ return -ENOMEM;
+
+ id = acpi_match_device(dev->driver->acpi_match_table, dev);
+ if (!id)
+ return -ENODEV;
+
+ desc = (struct sst_acpi_desc *)id->driver_data;
+ mach = sst_acpi_find_machine(desc->machines);
+ if (mach == NULL) {
+ dev_err(dev, "No matching ASoC machine driver found\n");
+ return -ENODEV;
+ }
+
+ sst_pdata = &sst_acpi->sst_pdata;
+ sst_pdata->id = desc->sst_id;
+ sst_acpi->desc = desc;
+ sst_acpi->mach = mach;
+
+ if (desc->resindex_dma_base >= 0) {
+ sst_pdata->dma_engine = desc->dma_engine;
+ sst_pdata->dma_base = desc->resindex_dma_base;
+ sst_pdata->dma_size = desc->dma_size;
+ }
+
+ if (desc->irqindex_host_ipc >= 0)
+ sst_pdata->irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
+
+ if (desc->resindex_lpe_base >= 0) {
+ mmio = platform_get_resource(pdev, IORESOURCE_MEM,
+ desc->resindex_lpe_base);
+ if (mmio) {
+ sst_pdata->lpe_base = mmio->start;
+ sst_pdata->lpe_size = resource_size(mmio);
+ }
+ }
+
+ if (desc->resindex_pcicfg_base >= 0) {
+ mmio = platform_get_resource(pdev, IORESOURCE_MEM,
+ desc->resindex_pcicfg_base);
+ if (mmio) {
+ sst_pdata->pcicfg_base = mmio->start;
+ sst_pdata->pcicfg_size = resource_size(mmio);
+ }
+ }
+
+ if (desc->resindex_fw_base >= 0) {
+ mmio = platform_get_resource(pdev, IORESOURCE_MEM,
+ desc->resindex_fw_base);
+ if (mmio) {
+ sst_pdata->fw_base = mmio->start;
+ sst_pdata->fw_size = resource_size(mmio);
+ }
+ }
+
+ platform_set_drvdata(pdev, sst_acpi);
+
+ /* register machine driver */
+ sst_acpi->pdev_mach =
+ platform_device_register_data(dev, mach->drv_name, -1,
+ sst_pdata, sizeof(*sst_pdata));
+ if (IS_ERR(sst_acpi->pdev_mach))
+ return PTR_ERR(sst_acpi->pdev_mach);
+
+ /* continue SST probing after firmware is loaded */
+ ret = request_firmware_nowait(THIS_MODULE, true, mach->fw_filename,
+ dev, GFP_KERNEL, pdev, sst_acpi_fw_cb);
+ if (ret)
+ platform_device_unregister(sst_acpi->pdev_mach);
+
+ return ret;
+}
+
+static int sst_acpi_remove(struct platform_device *pdev)
+{
+ struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
+ struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
+
+ platform_device_unregister(sst_acpi->pdev_mach);
+ if (!IS_ERR_OR_NULL(sst_acpi->pdev_pcm))
+ platform_device_unregister(sst_acpi->pdev_pcm);
+ release_firmware(sst_pdata->fw);
+
+ return 0;
+}
+
+static struct sst_acpi_mach haswell_machines[] = {
+ { "INT33CA", "haswell-audio", "intel/IntcSST1.bin" },
+ {}
+};
+
+static struct sst_acpi_desc sst_acpi_haswell_desc = {
+ .drv_name = "haswell-pcm-audio",
+ .machines = haswell_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = 1,
+ .resindex_fw_base = -1,
+ .irqindex_host_ipc = 0,
+ .sst_id = SST_DEV_ID_LYNX_POINT,
+ .dma_engine = SST_DMA_TYPE_DW,
+ .resindex_dma_base = SST_LPT_DSP_DMA_ADDR_OFFSET,
+ .dma_size = SST_LPT_DSP_DMA_SIZE,
+};
+
+static struct sst_acpi_mach broadwell_machines[] = {
+ { "INT343A", "broadwell-audio", "intel/IntcSST2.bin" },
+ {}
+};
+
+static struct sst_acpi_desc sst_acpi_broadwell_desc = {
+ .drv_name = "haswell-pcm-audio",
+ .machines = broadwell_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = 1,
+ .resindex_fw_base = -1,
+ .irqindex_host_ipc = 0,
+ .sst_id = SST_DEV_ID_WILDCAT_POINT,
+ .dma_engine = SST_DMA_TYPE_DW,
+ .resindex_dma_base = SST_WPT_DSP_DMA_ADDR_OFFSET,
+ .dma_size = SST_LPT_DSP_DMA_SIZE,
+};
+
+static struct sst_acpi_mach baytrail_machines[] = {
+ { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" },
+ {}
+};
+
+static struct sst_acpi_desc sst_acpi_baytrail_desc = {
+ .drv_name = "baytrail-pcm-audio",
+ .machines = baytrail_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = 1,
+ .resindex_fw_base = 2,
+ .irqindex_host_ipc = 5,
+ .sst_id = SST_DEV_ID_BYT,
+ .resindex_dma_base = -1,
+};
+
+static struct acpi_device_id sst_acpi_match[] = {
+ { "INT33C8", (unsigned long)&sst_acpi_haswell_desc },
+ { "INT3438", (unsigned long)&sst_acpi_broadwell_desc },
+ { "80860F28", (unsigned long)&sst_acpi_baytrail_desc },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, sst_acpi_match);
+
+static struct platform_driver sst_acpi_driver = {
+ .probe = sst_acpi_probe,
+ .remove = sst_acpi_remove,
+ .driver = {
+ .name = "sst-acpi",
+ .owner = THIS_MODULE,
+ .acpi_match_table = ACPI_PTR(sst_acpi_match),
+ },
+};
+module_platform_driver(sst_acpi_driver);
+
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
+MODULE_DESCRIPTION("Intel SST loader on ACPI systems");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c
new file mode 100644
index 000000000000..a50bf7fc0e3a
--- /dev/null
+++ b/sound/soc/intel/sst-baytrail-dsp.c
@@ -0,0 +1,372 @@
+/*
+ * Intel Baytrail SST DSP driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+#include "sst-baytrail-ipc.h"
+
+#define SST_BYT_FW_SIGNATURE_SIZE 4
+#define SST_BYT_FW_SIGN "$SST"
+
+#define SST_BYT_IRAM_OFFSET 0xC0000
+#define SST_BYT_DRAM_OFFSET 0x100000
+#define SST_BYT_SHIM_OFFSET 0x140000
+
+enum sst_ram_type {
+ SST_BYT_IRAM = 1,
+ SST_BYT_DRAM = 2,
+ SST_BYT_CACHE = 3,
+};
+
+struct dma_block_info {
+ enum sst_ram_type type; /* IRAM/DRAM */
+ u32 size; /* Bytes */
+ u32 ram_offset; /* Offset in I/DRAM */
+ u32 rsvd; /* Reserved field */
+};
+
+struct fw_header {
+ unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
+ u32 file_size; /* size of fw minus this header */
+ u32 modules; /* # of modules */
+ u32 file_format; /* version of header format */
+ u32 reserved[4];
+};
+
+struct sst_byt_fw_module_header {
+ unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
+ u32 mod_size; /* size of module */
+ u32 blocks; /* # of blocks */
+ u32 type; /* codec type, pp lib */
+ u32 entry_point;
+};
+
+static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
+ struct sst_byt_fw_module_header *module)
+{
+ struct dma_block_info *block;
+ struct sst_module *mod;
+ struct sst_module_data block_data;
+ struct sst_module_template template;
+ int count;
+
+ memset(&template, 0, sizeof(template));
+ template.id = module->type;
+ template.entry = module->entry_point;
+ template.p.type = SST_MEM_DRAM;
+ template.p.data_type = SST_DATA_P;
+ template.s.type = SST_MEM_DRAM;
+ template.s.data_type = SST_DATA_S;
+
+ mod = sst_module_new(fw, &template, NULL);
+ if (mod == NULL)
+ return -ENOMEM;
+
+ block = (void *)module + sizeof(*module);
+
+ for (count = 0; count < module->blocks; count++) {
+
+ if (block->size <= 0) {
+ dev_err(dsp->dev, "block %d size invalid\n", count);
+ return -EINVAL;
+ }
+
+ switch (block->type) {
+ case SST_BYT_IRAM:
+ block_data.offset = block->ram_offset +
+ dsp->addr.iram_offset;
+ block_data.type = SST_MEM_IRAM;
+ break;
+ case SST_BYT_DRAM:
+ block_data.offset = block->ram_offset +
+ dsp->addr.dram_offset;
+ block_data.type = SST_MEM_DRAM;
+ break;
+ case SST_BYT_CACHE:
+ block_data.offset = block->ram_offset +
+ (dsp->addr.fw_ext - dsp->addr.lpe);
+ block_data.type = SST_MEM_CACHE;
+ break;
+ default:
+ dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n",
+ block->type, count);
+ return -EINVAL;
+ }
+
+ block_data.size = block->size;
+ block_data.data_type = SST_DATA_M;
+ block_data.data = (void *)block + sizeof(*block);
+
+ sst_module_insert_fixed_block(mod, &block_data);
+
+ block = (void *)block + sizeof(*block) + block->size;
+ }
+ return 0;
+}
+
+static int sst_byt_parse_fw_image(struct sst_fw *sst_fw)
+{
+ struct fw_header *header;
+ struct sst_byt_fw_module_header *module;
+ struct sst_dsp *dsp = sst_fw->dsp;
+ int ret, count;
+
+ /* Read the header information from the data pointer */
+ header = (struct fw_header *)sst_fw->dma_buf;
+
+ /* verify FW */
+ if ((strncmp(header->signature, SST_BYT_FW_SIGN, 4) != 0) ||
+ (sst_fw->size != header->file_size + sizeof(*header))) {
+ /* Invalid FW signature */
+ dev_err(dsp->dev, "Invalid FW sign/filesize mismatch\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(dsp->dev,
+ "header sign=%4s size=0x%x modules=0x%x fmt=0x%x size=%zu\n",
+ header->signature, header->file_size, header->modules,
+ header->file_format, sizeof(*header));
+
+ module = (void *)sst_fw->dma_buf + sizeof(*header);
+ for (count = 0; count < header->modules; count++) {
+ /* module */
+ ret = sst_byt_parse_module(dsp, sst_fw, module);
+ if (ret < 0) {
+ dev_err(dsp->dev, "invalid module %d\n", count);
+ return ret;
+ }
+ module = (void *)module + sizeof(*module) + module->mod_size;
+ }
+
+ return 0;
+}
+
+static void sst_byt_dump_shim(struct sst_dsp *sst)
+{
+ int i;
+ u64 reg;
+
+ for (i = 0; i <= 0xF0; i += 8) {
+ reg = sst_dsp_shim_read64_unlocked(sst, i);
+ if (reg)
+ dev_dbg(sst->dev, "shim 0x%2.2x value 0x%16.16llx\n",
+ i, reg);
+ }
+
+ for (i = 0x00; i <= 0xff; i += 4) {
+ reg = readl(sst->addr.pci_cfg + i);
+ if (reg)
+ dev_dbg(sst->dev, "pci 0x%2.2x value 0x%8.8x\n",
+ i, (u32)reg);
+ }
+}
+
+static irqreturn_t sst_byt_irq(int irq, void *context)
+{
+ struct sst_dsp *sst = (struct sst_dsp *) context;
+ u64 isrx;
+ irqreturn_t ret = IRQ_NONE;
+
+ spin_lock(&sst->spinlock);
+
+ isrx = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
+ if (isrx & SST_ISRX_DONE) {
+ /* ADSP has processed the message request from IA */
+ sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCX,
+ SST_BYT_IPCX_DONE, 0);
+ ret = IRQ_WAKE_THREAD;
+ }
+ if (isrx & SST_BYT_ISRX_REQUEST) {
+ /* mask message request from ADSP and do processing later */
+ sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
+ SST_BYT_IMRX_REQUEST,
+ SST_BYT_IMRX_REQUEST);
+ ret = IRQ_WAKE_THREAD;
+ }
+
+ spin_unlock(&sst->spinlock);
+
+ return ret;
+}
+
+static void sst_byt_boot(struct sst_dsp *sst)
+{
+ int tries = 10;
+
+ /* release stall and wait to unstall */
+ sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_STALL, 0x0);
+ while (tries--) {
+ if (!(sst_dsp_shim_read64(sst, SST_CSR) &
+ SST_BYT_CSR_PWAITMODE))
+ break;
+ msleep(100);
+ }
+ if (tries < 0) {
+ dev_err(sst->dev, "unable to start DSP\n");
+ sst_byt_dump_shim(sst);
+ }
+}
+
+static void sst_byt_reset(struct sst_dsp *sst)
+{
+ /* put DSP into reset, set reset vector and stall */
+ sst_dsp_shim_update_bits64(sst, SST_CSR,
+ SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL,
+ SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL);
+
+ udelay(10);
+
+ /* take DSP out of reset and keep stalled for FW loading */
+ sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_RST, 0);
+}
+
+struct sst_adsp_memregion {
+ u32 start;
+ u32 end;
+ int blocks;
+ enum sst_mem_type type;
+};
+
+/* BYT test stuff */
+static const struct sst_adsp_memregion byt_region[] = {
+ {0xC0000, 0x100000, 8, SST_MEM_IRAM}, /* I-SRAM - 8 * 32kB */
+ {0x100000, 0x140000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
+};
+
+static int sst_byt_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+ sst->addr.lpe_base = pdata->lpe_base;
+ sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size);
+ if (!sst->addr.lpe)
+ return -ENODEV;
+
+ /* ADSP PCI MMIO config space */
+ sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size);
+ if (!sst->addr.pci_cfg) {
+ iounmap(sst->addr.lpe);
+ return -ENODEV;
+ }
+
+ /* SST Extended FW allocation */
+ sst->addr.fw_ext = ioremap(pdata->fw_base, pdata->fw_size);
+ if (!sst->addr.fw_ext) {
+ iounmap(sst->addr.pci_cfg);
+ iounmap(sst->addr.lpe);
+ return -ENODEV;
+ }
+
+ /* SST Shim */
+ sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset;
+
+ sst_dsp_mailbox_init(sst, SST_BYT_MAILBOX_OFFSET + 0x204,
+ SST_BYT_IPC_MAX_PAYLOAD_SIZE,
+ SST_BYT_MAILBOX_OFFSET,
+ SST_BYT_IPC_MAX_PAYLOAD_SIZE);
+
+ sst->irq = pdata->irq;
+
+ return 0;
+}
+
+static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+ const struct sst_adsp_memregion *region;
+ struct device *dev;
+ int ret = -ENODEV, i, j, region_count;
+ u32 offset, size;
+
+ dev = sst->dev;
+
+ switch (sst->id) {
+ case SST_DEV_ID_BYT:
+ region = byt_region;
+ region_count = ARRAY_SIZE(byt_region);
+ sst->addr.iram_offset = SST_BYT_IRAM_OFFSET;
+ sst->addr.dram_offset = SST_BYT_DRAM_OFFSET;
+ sst->addr.shim_offset = SST_BYT_SHIM_OFFSET;
+ break;
+ default:
+ dev_err(dev, "failed to get mem resources\n");
+ return ret;
+ }
+
+ ret = sst_byt_resource_map(sst, pdata);
+ if (ret < 0) {
+ dev_err(dev, "failed to map resources\n");
+ return ret;
+ }
+
+ /*
+ * save the physical address of extended firmware block in the first
+ * 4 bytes of the mailbox
+ */
+ memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
+ &pdata->fw_base, sizeof(u32));
+
+ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ /* enable Interrupt from both sides */
+ sst_dsp_shim_update_bits64(sst, SST_IMRX, 0x3, 0x0);
+ sst_dsp_shim_update_bits64(sst, SST_IMRD, 0x3, 0x0);
+
+ /* register DSP memory blocks - ideally we should get this from ACPI */
+ for (i = 0; i < region_count; i++) {
+ offset = region[i].start;
+ size = (region[i].end - region[i].start) / region[i].blocks;
+
+ /* register individual memory blocks */
+ for (j = 0; j < region[i].blocks; j++) {
+ sst_mem_block_register(sst, offset, size,
+ region[i].type, NULL, j, sst);
+ offset += size;
+ }
+ }
+
+ return 0;
+}
+
+static void sst_byt_free(struct sst_dsp *sst)
+{
+ sst_mem_block_unregister_all(sst);
+ iounmap(sst->addr.lpe);
+ iounmap(sst->addr.pci_cfg);
+ iounmap(sst->addr.fw_ext);
+}
+
+struct sst_ops sst_byt_ops = {
+ .reset = sst_byt_reset,
+ .boot = sst_byt_boot,
+ .write = sst_shim32_write,
+ .read = sst_shim32_read,
+ .write64 = sst_shim32_write64,
+ .read64 = sst_shim32_read64,
+ .ram_read = sst_memcpy_fromio_32,
+ .ram_write = sst_memcpy_toio_32,
+ .irq_handler = sst_byt_irq,
+ .init = sst_byt_init,
+ .free = sst_byt_free,
+ .parse_fw = sst_byt_parse_fw_image,
+};
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c
new file mode 100644
index 000000000000..d0eaeee21be4
--- /dev/null
+++ b/sound/soc/intel/sst-baytrail-ipc.c
@@ -0,0 +1,867 @@
+/*
+ * Intel Baytrail SST IPC Support
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/kthread.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+
+#include "sst-baytrail-ipc.h"
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+
+/* IPC message timeout */
+#define IPC_TIMEOUT_MSECS 300
+#define IPC_BOOT_MSECS 200
+
+#define IPC_EMPTY_LIST_SIZE 8
+
+/* IPC header bits */
+#define IPC_HEADER_MSG_ID_MASK 0xff
+#define IPC_HEADER_MSG_ID(x) ((x) & IPC_HEADER_MSG_ID_MASK)
+#define IPC_HEADER_STR_ID_SHIFT 8
+#define IPC_HEADER_STR_ID_MASK 0x1f
+#define IPC_HEADER_STR_ID(x) (((x) & 0x1f) << IPC_HEADER_STR_ID_SHIFT)
+#define IPC_HEADER_LARGE_SHIFT 13
+#define IPC_HEADER_LARGE(x) (((x) & 0x1) << IPC_HEADER_LARGE_SHIFT)
+#define IPC_HEADER_DATA_SHIFT 16
+#define IPC_HEADER_DATA_MASK 0x3fff
+#define IPC_HEADER_DATA(x) (((x) & 0x3fff) << IPC_HEADER_DATA_SHIFT)
+
+/* mask for differentiating between notification and reply message */
+#define IPC_NOTIFICATION (0x1 << 7)
+
+/* I2L Stream config/control msgs */
+#define IPC_IA_ALLOC_STREAM 0x20
+#define IPC_IA_FREE_STREAM 0x21
+#define IPC_IA_PAUSE_STREAM 0x24
+#define IPC_IA_RESUME_STREAM 0x25
+#define IPC_IA_DROP_STREAM 0x26
+#define IPC_IA_START_STREAM 0x30
+
+/* notification messages */
+#define IPC_IA_FW_INIT_CMPLT 0x81
+#define IPC_SST_PERIOD_ELAPSED 0x97
+
+/* IPC messages between host and ADSP */
+struct sst_byt_address_info {
+ u32 addr;
+ u32 size;
+} __packed;
+
+struct sst_byt_str_type {
+ u8 codec_type;
+ u8 str_type;
+ u8 operation;
+ u8 protected_str;
+ u8 time_slots;
+ u8 reserved;
+ u16 result;
+} __packed;
+
+struct sst_byt_pcm_params {
+ u8 num_chan;
+ u8 pcm_wd_sz;
+ u8 use_offload_path;
+ u8 reserved;
+ u32 sfreq;
+ u8 channel_map[8];
+} __packed;
+
+struct sst_byt_frames_info {
+ u16 num_entries;
+ u16 rsrvd;
+ u32 frag_size;
+ struct sst_byt_address_info ring_buf_info[8];
+} __packed;
+
+struct sst_byt_alloc_params {
+ struct sst_byt_str_type str_type;
+ struct sst_byt_pcm_params pcm_params;
+ struct sst_byt_frames_info frame_info;
+} __packed;
+
+struct sst_byt_alloc_response {
+ struct sst_byt_str_type str_type;
+ u8 reserved[88];
+} __packed;
+
+struct sst_byt_start_stream_params {
+ u32 byte_offset;
+} __packed;
+
+struct sst_byt_tstamp {
+ u64 ring_buffer_counter;
+ u64 hardware_counter;
+ u64 frames_decoded;
+ u64 bytes_decoded;
+ u64 bytes_copied;
+ u32 sampling_frequency;
+ u32 channel_peak[8];
+} __packed;
+
+/* driver internal IPC message structure */
+struct ipc_message {
+ struct list_head list;
+ u64 header;
+
+ /* direction wrt host CPU */
+ char tx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE];
+ size_t tx_size;
+ char rx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE];
+ size_t rx_size;
+
+ wait_queue_head_t waitq;
+ bool complete;
+ bool wait;
+ int errno;
+};
+
+struct sst_byt_stream;
+struct sst_byt;
+
+/* stream infomation */
+struct sst_byt_stream {
+ struct list_head node;
+
+ /* configuration */
+ struct sst_byt_alloc_params request;
+ struct sst_byt_alloc_response reply;
+
+ /* runtime info */
+ struct sst_byt *byt;
+ int str_id;
+ bool commited;
+ bool running;
+
+ /* driver callback */
+ u32 (*notify_position)(struct sst_byt_stream *stream, void *data);
+ void *pdata;
+};
+
+/* SST Baytrail IPC data */
+struct sst_byt {
+ struct device *dev;
+ struct sst_dsp *dsp;
+
+ /* stream */
+ struct list_head stream_list;
+
+ /* boot */
+ wait_queue_head_t boot_wait;
+ bool boot_complete;
+
+ /* IPC messaging */
+ struct list_head tx_list;
+ struct list_head rx_list;
+ struct list_head empty_list;
+ wait_queue_head_t wait_txq;
+ struct task_struct *tx_thread;
+ struct kthread_worker kworker;
+ struct kthread_work kwork;
+ struct ipc_message *msg;
+};
+
+static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id)
+{
+ u64 header;
+
+ header = IPC_HEADER_MSG_ID(msg_id) |
+ IPC_HEADER_STR_ID(str_id) |
+ IPC_HEADER_LARGE(large) |
+ IPC_HEADER_DATA(data) |
+ SST_BYT_IPCX_BUSY;
+
+ return header;
+}
+
+static inline u16 sst_byt_header_msg_id(u64 header)
+{
+ return header & IPC_HEADER_MSG_ID_MASK;
+}
+
+static inline u8 sst_byt_header_str_id(u64 header)
+{
+ return (header >> IPC_HEADER_STR_ID_SHIFT) & IPC_HEADER_STR_ID_MASK;
+}
+
+static inline u16 sst_byt_header_data(u64 header)
+{
+ return (header >> IPC_HEADER_DATA_SHIFT) & IPC_HEADER_DATA_MASK;
+}
+
+static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt,
+ int stream_id)
+{
+ struct sst_byt_stream *stream;
+
+ list_for_each_entry(stream, &byt->stream_list, node) {
+ if (stream->str_id == stream_id)
+ return stream;
+ }
+
+ return NULL;
+}
+
+static void sst_byt_ipc_shim_dbg(struct sst_byt *byt, const char *text)
+{
+ struct sst_dsp *sst = byt->dsp;
+ u64 isr, ipcd, imrx, ipcx;
+
+ ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX);
+ isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
+ ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
+ imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX);
+
+ dev_err(byt->dev,
+ "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n",
+ text, ipcx, isr, ipcd, imrx);
+}
+
+/* locks held by caller */
+static struct ipc_message *sst_byt_msg_get_empty(struct sst_byt *byt)
+{
+ struct ipc_message *msg = NULL;
+
+ if (!list_empty(&byt->empty_list)) {
+ msg = list_first_entry(&byt->empty_list,
+ struct ipc_message, list);
+ list_del(&msg->list);
+ }
+
+ return msg;
+}
+
+static void sst_byt_ipc_tx_msgs(struct kthread_work *work)
+{
+ struct sst_byt *byt =
+ container_of(work, struct sst_byt, kwork);
+ struct ipc_message *msg;
+ u64 ipcx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&byt->dsp->spinlock, flags);
+ if (list_empty(&byt->tx_list)) {
+ spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+ return;
+ }
+
+ /* if the DSP is busy we will TX messages after IRQ */
+ ipcx = sst_dsp_shim_read64_unlocked(byt->dsp, SST_IPCX);
+ if (ipcx & SST_BYT_IPCX_BUSY) {
+ spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+ return;
+ }
+
+ msg = list_first_entry(&byt->tx_list, struct ipc_message, list);
+
+ list_move(&msg->list, &byt->rx_list);
+
+ /* send the message */
+ if (msg->header & IPC_HEADER_LARGE(true))
+ sst_dsp_outbox_write(byt->dsp, msg->tx_data, msg->tx_size);
+ sst_dsp_shim_write64_unlocked(byt->dsp, SST_IPCX, msg->header);
+
+ spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+}
+
+static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt,
+ struct ipc_message *msg)
+{
+ msg->complete = true;
+
+ if (!msg->wait)
+ list_add_tail(&msg->list, &byt->empty_list);
+ else
+ wake_up(&msg->waitq);
+}
+
+static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg,
+ void *rx_data)
+{
+ unsigned long flags;
+ int ret;
+
+ /* wait for DSP completion */
+ ret = wait_event_timeout(msg->waitq, msg->complete,
+ msecs_to_jiffies(IPC_TIMEOUT_MSECS));
+
+ spin_lock_irqsave(&byt->dsp->spinlock, flags);
+ if (ret == 0) {
+ list_del(&msg->list);
+ sst_byt_ipc_shim_dbg(byt, "message timeout");
+
+ ret = -ETIMEDOUT;
+ } else {
+
+ /* copy the data returned from DSP */
+ if (msg->rx_size)
+ memcpy(rx_data, msg->rx_data, msg->rx_size);
+ ret = msg->errno;
+ }
+
+ list_add_tail(&msg->list, &byt->empty_list);
+ spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+ return ret;
+}
+
+static int sst_byt_ipc_tx_message(struct sst_byt *byt, u64 header,
+ void *tx_data, size_t tx_bytes,
+ void *rx_data, size_t rx_bytes, int wait)
+{
+ unsigned long flags;
+ struct ipc_message *msg;
+
+ spin_lock_irqsave(&byt->dsp->spinlock, flags);
+
+ msg = sst_byt_msg_get_empty(byt);
+ if (msg == NULL) {
+ spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+ return -EBUSY;
+ }
+
+ msg->header = header;
+ msg->tx_size = tx_bytes;
+ msg->rx_size = rx_bytes;
+ msg->wait = wait;
+ msg->errno = 0;
+ msg->complete = false;
+
+ if (tx_bytes) {
+ /* msg content = lower 32-bit of the header + data */
+ *(u32 *)msg->tx_data = (u32)(header & (u32)-1);
+ memcpy(msg->tx_data + sizeof(u32), tx_data, tx_bytes);
+ msg->tx_size += sizeof(u32);
+ }
+
+ list_add_tail(&msg->list, &byt->tx_list);
+ spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
+
+ queue_kthread_work(&byt->kworker, &byt->kwork);
+
+ if (wait)
+ return sst_byt_tx_wait_done(byt, msg, rx_data);
+ else
+ return 0;
+}
+
+static inline int sst_byt_ipc_tx_msg_wait(struct sst_byt *byt, u64 header,
+ void *tx_data, size_t tx_bytes,
+ void *rx_data, size_t rx_bytes)
+{
+ return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes,
+ rx_data, rx_bytes, 1);
+}
+
+static inline int sst_byt_ipc_tx_msg_nowait(struct sst_byt *byt, u64 header,
+ void *tx_data, size_t tx_bytes)
+{
+ return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes,
+ NULL, 0, 0);
+}
+
+static struct ipc_message *sst_byt_reply_find_msg(struct sst_byt *byt,
+ u64 header)
+{
+ struct ipc_message *msg = NULL, *_msg;
+ u64 mask;
+
+ /* match reply to message sent based on msg and stream IDs */
+ mask = IPC_HEADER_MSG_ID_MASK |
+ IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT;
+ header &= mask;
+
+ if (list_empty(&byt->rx_list)) {
+ dev_err(byt->dev,
+ "ipc: rx list is empty but received 0x%llx\n", header);
+ goto out;
+ }
+
+ list_for_each_entry(_msg, &byt->rx_list, list) {
+ if ((_msg->header & mask) == header) {
+ msg = _msg;
+ break;
+ }
+ }
+
+out:
+ return msg;
+}
+
+static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg)
+{
+ struct sst_byt_stream *stream;
+ u64 header = msg->header;
+ u8 stream_id = sst_byt_header_str_id(header);
+ u8 stream_msg = sst_byt_header_msg_id(header);
+
+ stream = sst_byt_get_stream(byt, stream_id);
+ if (stream == NULL)
+ return;
+
+ switch (stream_msg) {
+ case IPC_IA_DROP_STREAM:
+ case IPC_IA_PAUSE_STREAM:
+ case IPC_IA_FREE_STREAM:
+ stream->running = false;
+ break;
+ case IPC_IA_START_STREAM:
+ case IPC_IA_RESUME_STREAM:
+ stream->running = true;
+ break;
+ }
+}
+
+static int sst_byt_process_reply(struct sst_byt *byt, u64 header)
+{
+ struct ipc_message *msg;
+
+ msg = sst_byt_reply_find_msg(byt, header);
+ if (msg == NULL)
+ return 1;
+
+ if (header & IPC_HEADER_LARGE(true)) {
+ msg->rx_size = sst_byt_header_data(header);
+ sst_dsp_inbox_read(byt->dsp, msg->rx_data, msg->rx_size);
+ }
+
+ /* update any stream states */
+ sst_byt_stream_update(byt, msg);
+
+ list_del(&msg->list);
+ /* wake up */
+ sst_byt_tx_msg_reply_complete(byt, msg);
+
+ return 1;
+}
+
+static void sst_byt_fw_ready(struct sst_byt *byt, u64 header)
+{
+ dev_dbg(byt->dev, "ipc: DSP is ready 0x%llX\n", header);
+
+ byt->boot_complete = true;
+ wake_up(&byt->boot_wait);
+}
+
+static int sst_byt_process_notification(struct sst_byt *byt,
+ unsigned long *flags)
+{
+ struct sst_dsp *sst = byt->dsp;
+ struct sst_byt_stream *stream;
+ u64 header;
+ u8 msg_id, stream_id;
+ int handled = 1;
+
+ header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
+ msg_id = sst_byt_header_msg_id(header);
+
+ switch (msg_id) {
+ case IPC_SST_PERIOD_ELAPSED:
+ stream_id = sst_byt_header_str_id(header);
+ stream = sst_byt_get_stream(byt, stream_id);
+ if (stream && stream->running && stream->notify_position) {
+ spin_unlock_irqrestore(&sst->spinlock, *flags);
+ stream->notify_position(stream, stream->pdata);
+ spin_lock_irqsave(&sst->spinlock, *flags);
+ }
+ break;
+ case IPC_IA_FW_INIT_CMPLT:
+ sst_byt_fw_ready(byt, header);
+ break;
+ }
+
+ return handled;
+}
+
+static irqreturn_t sst_byt_irq_thread(int irq, void *context)
+{
+ struct sst_dsp *sst = (struct sst_dsp *) context;
+ struct sst_byt *byt = sst_dsp_get_thread_context(sst);
+ u64 header;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sst->spinlock, flags);
+
+ header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
+ if (header & SST_BYT_IPCD_BUSY) {
+ if (header & IPC_NOTIFICATION) {
+ /* message from ADSP */
+ sst_byt_process_notification(byt, &flags);
+ } else {
+ /* reply from ADSP */
+ sst_byt_process_reply(byt, header);
+ }
+ /*
+ * clear IPCD BUSY bit and set DONE bit. Tell DSP we have
+ * processed the message and can accept new. Clear data part
+ * of the header
+ */
+ sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCD,
+ SST_BYT_IPCD_DONE | SST_BYT_IPCD_BUSY |
+ IPC_HEADER_DATA(IPC_HEADER_DATA_MASK),
+ SST_BYT_IPCD_DONE);
+ /* unmask message request interrupts */
+ sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
+ SST_BYT_IMRX_REQUEST, 0);
+ }
+
+ spin_unlock_irqrestore(&sst->spinlock, flags);
+
+ /* continue to send any remaining messages... */
+ queue_kthread_work(&byt->kworker, &byt->kwork);
+
+ return IRQ_HANDLED;
+}
+
+/* stream API */
+struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
+ u32 (*notify_position)(struct sst_byt_stream *stream, void *data),
+ void *data)
+{
+ struct sst_byt_stream *stream;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (stream == NULL)
+ return NULL;
+
+ list_add(&stream->node, &byt->stream_list);
+ stream->notify_position = notify_position;
+ stream->pdata = data;
+ stream->byt = byt;
+ stream->str_id = id;
+
+ return stream;
+}
+
+int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
+ int bits)
+{
+ stream->request.pcm_params.pcm_wd_sz = bits;
+ return 0;
+}
+
+int sst_byt_stream_set_channels(struct sst_byt *byt,
+ struct sst_byt_stream *stream, u8 channels)
+{
+ stream->request.pcm_params.num_chan = channels;
+ return 0;
+}
+
+int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
+ unsigned int rate)
+{
+ stream->request.pcm_params.sfreq = rate;
+ return 0;
+}
+
+/* stream sonfiguration */
+int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
+ int codec_type, int stream_type, int operation)
+{
+ stream->request.str_type.codec_type = codec_type;
+ stream->request.str_type.str_type = stream_type;
+ stream->request.str_type.operation = operation;
+ stream->request.str_type.time_slots = 0xc;
+
+ return 0;
+}
+
+int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
+ uint32_t buffer_addr, uint32_t buffer_size)
+{
+ stream->request.frame_info.num_entries = 1;
+ stream->request.frame_info.ring_buf_info[0].addr = buffer_addr;
+ stream->request.frame_info.ring_buf_info[0].size = buffer_size;
+ /* calculate bytes per 4 ms fragment */
+ stream->request.frame_info.frag_size =
+ stream->request.pcm_params.sfreq *
+ stream->request.pcm_params.num_chan *
+ stream->request.pcm_params.pcm_wd_sz / 8 *
+ 4 / 1000;
+ return 0;
+}
+
+int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+ struct sst_byt_alloc_params *str_req = &stream->request;
+ struct sst_byt_alloc_response *reply = &stream->reply;
+ u64 header;
+ int ret;
+
+ header = sst_byt_header(IPC_IA_ALLOC_STREAM,
+ sizeof(*str_req) + sizeof(u32),
+ true, stream->str_id);
+ ret = sst_byt_ipc_tx_msg_wait(byt, header, str_req, sizeof(*str_req),
+ reply, sizeof(*reply));
+ if (ret < 0) {
+ dev_err(byt->dev, "ipc: error stream commit failed\n");
+ return ret;
+ }
+
+ stream->commited = true;
+
+ return 0;
+}
+
+int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+ u64 header;
+ int ret = 0;
+
+ if (!stream->commited)
+ goto out;
+
+ header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id);
+ ret = sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0);
+ if (ret < 0) {
+ dev_err(byt->dev, "ipc: free stream %d failed\n",
+ stream->str_id);
+ return -EAGAIN;
+ }
+
+ stream->commited = false;
+out:
+ list_del(&stream->node);
+ kfree(stream);
+
+ return ret;
+}
+
+static int sst_byt_stream_operations(struct sst_byt *byt, int type,
+ int stream_id, int wait)
+{
+ struct sst_byt_start_stream_params start_stream;
+ u64 header;
+ void *tx_msg = NULL;
+ size_t size = 0;
+
+ if (type != IPC_IA_START_STREAM) {
+ header = sst_byt_header(type, 0, false, stream_id);
+ } else {
+ start_stream.byte_offset = 0;
+ header = sst_byt_header(IPC_IA_START_STREAM,
+ sizeof(start_stream) + sizeof(u32),
+ true, stream_id);
+ tx_msg = &start_stream;
+ size = sizeof(start_stream);
+ }
+
+ if (wait)
+ return sst_byt_ipc_tx_msg_wait(byt, header,
+ tx_msg, size, NULL, 0);
+ else
+ return sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size);
+}
+
+/* stream ALSA trigger operations */
+int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+ int ret;
+
+ ret = sst_byt_stream_operations(byt, IPC_IA_START_STREAM,
+ stream->str_id, 0);
+ if (ret < 0)
+ dev_err(byt->dev, "ipc: error failed to start stream %d\n",
+ stream->str_id);
+
+ return ret;
+}
+
+int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+ int ret;
+
+ /* don't stop streams that are not commited */
+ if (!stream->commited)
+ return 0;
+
+ ret = sst_byt_stream_operations(byt, IPC_IA_DROP_STREAM,
+ stream->str_id, 0);
+ if (ret < 0)
+ dev_err(byt->dev, "ipc: error failed to stop stream %d\n",
+ stream->str_id);
+ return ret;
+}
+
+int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+ int ret;
+
+ ret = sst_byt_stream_operations(byt, IPC_IA_PAUSE_STREAM,
+ stream->str_id, 0);
+ if (ret < 0)
+ dev_err(byt->dev, "ipc: error failed to pause stream %d\n",
+ stream->str_id);
+
+ return ret;
+}
+
+int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream)
+{
+ int ret;
+
+ ret = sst_byt_stream_operations(byt, IPC_IA_RESUME_STREAM,
+ stream->str_id, 0);
+ if (ret < 0)
+ dev_err(byt->dev, "ipc: error failed to resume stream %d\n",
+ stream->str_id);
+
+ return ret;
+}
+
+int sst_byt_get_dsp_position(struct sst_byt *byt,
+ struct sst_byt_stream *stream, int buffer_size)
+{
+ struct sst_dsp *sst = byt->dsp;
+ struct sst_byt_tstamp fw_tstamp;
+ u8 str_id = stream->str_id;
+ u32 tstamp_offset;
+
+ tstamp_offset = SST_BYT_TIMESTAMP_OFFSET + str_id * sizeof(fw_tstamp);
+ memcpy_fromio(&fw_tstamp,
+ sst->addr.lpe + tstamp_offset, sizeof(fw_tstamp));
+
+ return do_div(fw_tstamp.ring_buffer_counter, buffer_size);
+}
+
+static int msg_empty_list_init(struct sst_byt *byt)
+{
+ struct ipc_message *msg;
+ int i;
+
+ byt->msg = kzalloc(sizeof(*msg) * IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
+ if (byt->msg == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
+ init_waitqueue_head(&byt->msg[i].waitq);
+ list_add(&byt->msg[i].list, &byt->empty_list);
+ }
+
+ return 0;
+}
+
+struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt)
+{
+ return byt->dsp;
+}
+
+static struct sst_dsp_device byt_dev = {
+ .thread = sst_byt_irq_thread,
+ .ops = &sst_byt_ops,
+};
+
+int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
+{
+ struct sst_byt *byt;
+ struct sst_fw *byt_sst_fw;
+ int err;
+
+ dev_dbg(dev, "initialising Byt DSP IPC\n");
+
+ byt = devm_kzalloc(dev, sizeof(*byt), GFP_KERNEL);
+ if (byt == NULL)
+ return -ENOMEM;
+
+ byt->dev = dev;
+ INIT_LIST_HEAD(&byt->stream_list);
+ INIT_LIST_HEAD(&byt->tx_list);
+ INIT_LIST_HEAD(&byt->rx_list);
+ INIT_LIST_HEAD(&byt->empty_list);
+ init_waitqueue_head(&byt->boot_wait);
+ init_waitqueue_head(&byt->wait_txq);
+
+ err = msg_empty_list_init(byt);
+ if (err < 0)
+ return -ENOMEM;
+
+ /* start the IPC message thread */
+ init_kthread_worker(&byt->kworker);
+ byt->tx_thread = kthread_run(kthread_worker_fn,
+ &byt->kworker,
+ dev_name(byt->dev));
+ if (IS_ERR(byt->tx_thread)) {
+ err = PTR_ERR(byt->tx_thread);
+ dev_err(byt->dev, "error failed to create message TX task\n");
+ goto err_free_msg;
+ }
+ init_kthread_work(&byt->kwork, sst_byt_ipc_tx_msgs);
+
+ byt_dev.thread_context = byt;
+
+ /* init SST shim */
+ byt->dsp = sst_dsp_new(dev, &byt_dev, pdata);
+ if (byt->dsp == NULL) {
+ err = -ENODEV;
+ goto err_free_msg;
+ }
+
+ /* keep the DSP in reset state for base FW loading */
+ sst_dsp_reset(byt->dsp);
+
+ byt_sst_fw = sst_fw_new(byt->dsp, pdata->fw, byt);
+ if (byt_sst_fw == NULL) {
+ err = -ENODEV;
+ dev_err(dev, "error: failed to load firmware\n");
+ goto fw_err;
+ }
+
+ /* wait for DSP boot completion */
+ sst_dsp_boot(byt->dsp);
+ err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
+ msecs_to_jiffies(IPC_BOOT_MSECS));
+ if (err == 0) {
+ err = -EIO;
+ dev_err(byt->dev, "ipc: error DSP boot timeout\n");
+ goto boot_err;
+ }
+
+ pdata->dsp = byt;
+
+ return 0;
+
+boot_err:
+ sst_dsp_reset(byt->dsp);
+ sst_fw_free(byt_sst_fw);
+fw_err:
+ sst_dsp_free(byt->dsp);
+err_free_msg:
+ kfree(byt->msg);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_init);
+
+void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata)
+{
+ struct sst_byt *byt = pdata->dsp;
+
+ sst_dsp_reset(byt->dsp);
+ sst_fw_free_all(byt->dsp);
+ sst_dsp_free(byt->dsp);
+ kfree(byt->msg);
+}
+EXPORT_SYMBOL_GPL(sst_byt_dsp_free);
diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/sst-baytrail-ipc.h
new file mode 100644
index 000000000000..f172b6440fa9
--- /dev/null
+++ b/sound/soc/intel/sst-baytrail-ipc.h
@@ -0,0 +1,69 @@
+/*
+ * Intel Baytrail SST IPC Support
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __SST_BYT_IPC_H
+#define __SST_BYT_IPC_H
+
+#include <linux/types.h>
+
+struct sst_byt;
+struct sst_byt_stream;
+struct sst_pdata;
+extern struct sst_ops sst_byt_ops;
+
+
+#define SST_BYT_MAILBOX_OFFSET 0x144000
+#define SST_BYT_TIMESTAMP_OFFSET (SST_BYT_MAILBOX_OFFSET + 0x800)
+
+/**
+ * Upfront defined maximum message size that is
+ * expected by the in/out communication pipes in FW.
+ */
+#define SST_BYT_IPC_MAX_PAYLOAD_SIZE 200
+
+/* stream API */
+struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
+ uint32_t (*get_write_position)(struct sst_byt_stream *stream,
+ void *data),
+ void *data);
+
+/* stream configuration */
+int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
+ int bits);
+int sst_byt_stream_set_channels(struct sst_byt *byt,
+ struct sst_byt_stream *stream, u8 channels);
+int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
+ unsigned int rate);
+int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
+ int codec_type, int stream_type, int operation);
+int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
+ uint32_t buffer_addr, uint32_t buffer_size);
+int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream);
+
+/* stream ALSA trigger operations */
+int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream);
+int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream);
+
+int sst_byt_get_dsp_position(struct sst_byt *byt,
+ struct sst_byt_stream *stream, int buffer_size);
+
+/* init */
+int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
+void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
+struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
+
+#endif
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c
new file mode 100644
index 000000000000..6d101f3813b4
--- /dev/null
+++ b/sound/soc/intel/sst-baytrail-pcm.c
@@ -0,0 +1,422 @@
+/*
+ * Intel Baytrail SST PCM Support
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "sst-baytrail-ipc.h"
+#include "sst-dsp-priv.h"
+#include "sst-dsp.h"
+
+#define BYT_PCM_COUNT 2
+
+static const struct snd_pcm_hardware sst_byt_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FORMAT_S24_LE,
+ .period_bytes_min = 384,
+ .period_bytes_max = 48000,
+ .periods_min = 2,
+ .periods_max = 250,
+ .buffer_bytes_max = 96000,
+};
+
+/* private data for each PCM DSP stream */
+struct sst_byt_pcm_data {
+ struct sst_byt_stream *stream;
+ struct snd_pcm_substream *substream;
+ struct mutex mutex;
+};
+
+/* private data for the driver */
+struct sst_byt_priv_data {
+ /* runtime DSP */
+ struct sst_byt *byt;
+
+ /* DAI data */
+ struct sst_byt_pcm_data pcm[BYT_PCM_COUNT];
+};
+
+/* this may get called several times by oss emulation */
+static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sst_byt_priv_data *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct sst_byt *byt = pdata->byt;
+ u32 rate, bits;
+ u8 channels;
+ int ret, playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+
+ dev_dbg(rtd->dev, "PCM: hw_params, pcm_data %p\n", pcm_data);
+
+ ret = sst_byt_stream_type(byt, pcm_data->stream,
+ 1, 1, !playback);
+ if (ret < 0) {
+ dev_err(rtd->dev, "failed to set stream format %d\n", ret);
+ return ret;
+ }
+
+ rate = params_rate(params);
+ ret = sst_byt_stream_set_rate(byt, pcm_data->stream, rate);
+ if (ret < 0) {
+ dev_err(rtd->dev, "could not set rate %d\n", rate);
+ return ret;
+ }
+
+ bits = snd_pcm_format_width(params_format(params));
+ ret = sst_byt_stream_set_bits(byt, pcm_data->stream, bits);
+ if (ret < 0) {
+ dev_err(rtd->dev, "could not set formats %d\n",
+ params_rate(params));
+ return ret;
+ }
+
+ channels = (u8)(params_channels(params) & 0xF);
+ ret = sst_byt_stream_set_channels(byt, pcm_data->stream, channels);
+ if (ret < 0) {
+ dev_err(rtd->dev, "could not set channels %d\n",
+ params_rate(params));
+ return ret;
+ }
+
+ snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+
+ ret = sst_byt_stream_buffer(byt, pcm_data->stream,
+ substream->dma_buffer.addr,
+ params_buffer_bytes(params));
+ if (ret < 0) {
+ dev_err(rtd->dev, "PCM: failed to set DMA buffer %d\n", ret);
+ return ret;
+ }
+
+ ret = sst_byt_stream_commit(byt, pcm_data->stream);
+ if (ret < 0) {
+ dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ dev_dbg(rtd->dev, "PCM: hw_free\n");
+ snd_pcm_lib_free_pages(substream);
+
+ return 0;
+}
+
+static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sst_byt_priv_data *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct sst_byt *byt = pdata->byt;
+
+ dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ sst_byt_stream_start(byt, pcm_data->stream);
+ break;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ sst_byt_stream_resume(byt, pcm_data->stream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ sst_byt_stream_stop(byt, pcm_data->stream);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ sst_byt_stream_pause(byt, pcm_data->stream);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
+{
+ struct sst_byt_pcm_data *pcm_data = data;
+ struct snd_pcm_substream *substream = pcm_data->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ u32 pos;
+
+ pos = frames_to_bytes(runtime,
+ (runtime->control->appl_ptr %
+ runtime->buffer_size));
+
+ dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
+
+ snd_pcm_period_elapsed(substream);
+ return pos;
+}
+
+static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct sst_byt_priv_data *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct sst_byt *byt = pdata->byt;
+ snd_pcm_uframes_t offset;
+ int pos;
+
+ pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
+ snd_pcm_lib_buffer_bytes(substream));
+ offset = bytes_to_frames(runtime, pos);
+
+ dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n",
+ frames_to_bytes(runtime, (u32)offset));
+ return offset;
+}
+
+static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sst_byt_priv_data *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct sst_byt *byt = pdata->byt;
+
+ dev_dbg(rtd->dev, "PCM: open\n");
+
+ pcm_data = &pdata->pcm[rtd->cpu_dai->id];
+ mutex_lock(&pcm_data->mutex);
+
+ snd_soc_pcm_set_drvdata(rtd, pcm_data);
+ pcm_data->substream = substream;
+
+ snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware);
+
+ pcm_data->stream = sst_byt_stream_new(byt, rtd->cpu_dai->id + 1,
+ byt_notify_pointer, pcm_data);
+ if (pcm_data->stream == NULL) {
+ dev_err(rtd->dev, "failed to create stream\n");
+ mutex_unlock(&pcm_data->mutex);
+ return -EINVAL;
+ }
+
+ mutex_unlock(&pcm_data->mutex);
+ return 0;
+}
+
+static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sst_byt_priv_data *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct sst_byt *byt = pdata->byt;
+ int ret;
+
+ dev_dbg(rtd->dev, "PCM: close\n");
+
+ mutex_lock(&pcm_data->mutex);
+ ret = sst_byt_stream_free(byt, pcm_data->stream);
+ if (ret < 0) {
+ dev_dbg(rtd->dev, "Free stream fail\n");
+ goto out;
+ }
+ pcm_data->stream = NULL;
+
+out:
+ mutex_unlock(&pcm_data->mutex);
+ return ret;
+}
+
+static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ dev_dbg(rtd->dev, "PCM: mmap\n");
+ return snd_pcm_lib_default_mmap(substream, vma);
+}
+
+static struct snd_pcm_ops sst_byt_pcm_ops = {
+ .open = sst_byt_pcm_open,
+ .close = sst_byt_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = sst_byt_pcm_hw_params,
+ .hw_free = sst_byt_pcm_hw_free,
+ .trigger = sst_byt_pcm_trigger,
+ .pointer = sst_byt_pcm_pointer,
+ .mmap = sst_byt_pcm_mmap,
+};
+
+static void sst_byt_pcm_free(struct snd_pcm *pcm)
+{
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm;
+ size_t size;
+ int ret = 0;
+
+ ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
+ pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+ size = sst_byt_pcm_hardware.buffer_bytes_max;
+ ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_DEV,
+ rtd->card->dev,
+ size, size);
+ if (ret) {
+ dev_err(rtd->dev, "dma buffer allocation failed %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static struct snd_soc_dai_driver byt_dais[] = {
+ {
+ .name = "Front-cpu-dai",
+ .playback = {
+ .stream_name = "System Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ },
+ {
+ .name = "Mic1-cpu-dai",
+ .capture = {
+ .stream_name = "Analog Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ },
+};
+
+static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
+{
+ struct sst_pdata *plat_data = dev_get_platdata(platform->dev);
+ struct sst_byt_priv_data *priv_data;
+ int i;
+
+ if (!plat_data)
+ return -ENODEV;
+
+ priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data),
+ GFP_KERNEL);
+ priv_data->byt = plat_data->dsp;
+ snd_soc_platform_set_drvdata(platform, priv_data);
+
+ for (i = 0; i < ARRAY_SIZE(byt_dais); i++)
+ mutex_init(&priv_data->pcm[i].mutex);
+
+ return 0;
+}
+
+static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
+{
+ return 0;
+}
+
+static struct snd_soc_platform_driver byt_soc_platform = {
+ .probe = sst_byt_pcm_probe,
+ .remove = sst_byt_pcm_remove,
+ .ops = &sst_byt_pcm_ops,
+ .pcm_new = sst_byt_pcm_new,
+ .pcm_free = sst_byt_pcm_free,
+};
+
+static const struct snd_soc_component_driver byt_dai_component = {
+ .name = "byt-dai",
+};
+
+static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
+{
+ struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+ int ret;
+
+ ret = sst_byt_dsp_init(&pdev->dev, sst_pdata);
+ if (ret < 0)
+ return -ENODEV;
+
+ ret = snd_soc_register_platform(&pdev->dev, &byt_soc_platform);
+ if (ret < 0)
+ goto err_plat;
+
+ ret = snd_soc_register_component(&pdev->dev, &byt_dai_component,
+ byt_dais, ARRAY_SIZE(byt_dais));
+ if (ret < 0)
+ goto err_comp;
+
+ return 0;
+
+err_comp:
+ snd_soc_unregister_platform(&pdev->dev);
+err_plat:
+ sst_byt_dsp_free(&pdev->dev, sst_pdata);
+ return ret;
+}
+
+static int sst_byt_pcm_dev_remove(struct platform_device *pdev)
+{
+ struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+
+ snd_soc_unregister_platform(&pdev->dev);
+ snd_soc_unregister_component(&pdev->dev);
+ sst_byt_dsp_free(&pdev->dev, sst_pdata);
+
+ return 0;
+}
+
+static struct platform_driver sst_byt_pcm_driver = {
+ .driver = {
+ .name = "baytrail-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = sst_byt_pcm_dev_probe,
+ .remove = sst_byt_pcm_dev_remove,
+};
+module_platform_driver(sst_byt_pcm_driver);
+
+MODULE_AUTHOR("Jarkko Nikula");
+MODULE_DESCRIPTION("Baytrail PCM");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:baytrail-pcm-audio");
diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h
new file mode 100644
index 000000000000..fe8e81aad646
--- /dev/null
+++ b/sound/soc/intel/sst-dsp-priv.h
@@ -0,0 +1,309 @@
+/*
+ * Intel Smart Sound Technology
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SOUND_SOC_SST_DSP_PRIV_H
+#define __SOUND_SOC_SST_DSP_PRIV_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+
+struct sst_mem_block;
+struct sst_module;
+struct sst_fw;
+
+/*
+ * DSP Operations exported by platform Audio DSP driver.
+ */
+struct sst_ops {
+ /* DSP core boot / reset */
+ void (*boot)(struct sst_dsp *);
+ void (*reset)(struct sst_dsp *);
+
+ /* Shim IO */
+ void (*write)(void __iomem *addr, u32 offset, u32 value);
+ u32 (*read)(void __iomem *addr, u32 offset);
+ void (*write64)(void __iomem *addr, u32 offset, u64 value);
+ u64 (*read64)(void __iomem *addr, u32 offset);
+
+ /* DSP I/DRAM IO */
+ void (*ram_read)(struct sst_dsp *sst, void *dest, void __iomem *src,
+ size_t bytes);
+ void (*ram_write)(struct sst_dsp *sst, void __iomem *dest, void *src,
+ size_t bytes);
+
+ void (*dump)(struct sst_dsp *);
+
+ /* IRQ handlers */
+ irqreturn_t (*irq_handler)(int irq, void *context);
+
+ /* SST init and free */
+ int (*init)(struct sst_dsp *sst, struct sst_pdata *pdata);
+ void (*free)(struct sst_dsp *sst);
+
+ /* FW module parser/loader */
+ int (*parse_fw)(struct sst_fw *sst_fw);
+};
+
+/*
+ * Audio DSP memory offsets and addresses.
+ */
+struct sst_addr {
+ u32 lpe_base;
+ u32 shim_offset;
+ u32 iram_offset;
+ u32 dram_offset;
+ void __iomem *lpe;
+ void __iomem *shim;
+ void __iomem *pci_cfg;
+ void __iomem *fw_ext;
+};
+
+/*
+ * Audio DSP Mailbox configuration.
+ */
+struct sst_mailbox {
+ void __iomem *in_base;
+ void __iomem *out_base;
+ size_t in_size;
+ size_t out_size;
+};
+
+/*
+ * Audio DSP Firmware data types.
+ */
+enum sst_data_type {
+ SST_DATA_M = 0, /* module block data */
+ SST_DATA_P = 1, /* peristant data (text, data) */
+ SST_DATA_S = 2, /* scratch data (usually buffers) */
+};
+
+/*
+ * Audio DSP memory block types.
+ */
+enum sst_mem_type {
+ SST_MEM_IRAM = 0,
+ SST_MEM_DRAM = 1,
+ SST_MEM_ANY = 2,
+ SST_MEM_CACHE= 3,
+};
+
+/*
+ * Audio DSP Generic Firmware File.
+ *
+ * SST Firmware files can consist of 1..N modules. This generic structure is
+ * used to manage each firmware file and it's modules regardless of SST firmware
+ * type. A SST driver may load multiple FW files.
+ */
+struct sst_fw {
+ struct sst_dsp *dsp;
+
+ /* base addresses of FW file data */
+ dma_addr_t dmable_fw_paddr; /* physical address of fw data */
+ void *dma_buf; /* virtual address of fw data */
+ u32 size; /* size of fw data */
+
+ /* lists */
+ struct list_head list; /* DSP list of FW */
+ struct list_head module_list; /* FW list of modules */
+
+ void *private; /* core doesn't touch this */
+};
+
+/*
+ * Audio DSP Generic Module data.
+ *
+ * This is used to dsecribe any sections of persistent (text and data) and
+ * scratch (buffers) of module data in ADSP memory space.
+ */
+struct sst_module_data {
+
+ enum sst_mem_type type; /* destination memory type */
+ enum sst_data_type data_type; /* type of module data */
+
+ u32 size; /* size in bytes */
+ u32 offset; /* offset in FW file */
+ u32 data_offset; /* offset in ADSP memory space */
+ void *data; /* module data */
+};
+
+/*
+ * Audio DSP Generic Module Template.
+ *
+ * Used to define and register a new FW module. This data is extracted from
+ * FW module header information.
+ */
+struct sst_module_template {
+ u32 id;
+ u32 entry; /* entry point */
+ struct sst_module_data s; /* scratch data */
+ struct sst_module_data p; /* peristant data */
+};
+
+/*
+ * Audio DSP Generic Module.
+ *
+ * Each Firmware file can consist of 1..N modules. A module can span multiple
+ * ADSP memory blocks. The simplest FW will be a file with 1 module.
+ */
+struct sst_module {
+ struct sst_dsp *dsp;
+ struct sst_fw *sst_fw; /* parent FW we belong too */
+
+ /* module configuration */
+ u32 id;
+ u32 entry; /* module entry point */
+ u32 offset; /* module offset in firmware file */
+ u32 size; /* module size */
+ struct sst_module_data s; /* scratch data */
+ struct sst_module_data p; /* peristant data */
+
+ /* runtime */
+ u32 usage_count; /* can be unloaded if count == 0 */
+ void *private; /* core doesn't touch this */
+
+ /* lists */
+ struct list_head block_list; /* Module list of blocks in use */
+ struct list_head list; /* DSP list of modules */
+ struct list_head list_fw; /* FW list of modules */
+};
+
+/*
+ * SST Memory Block operations.
+ */
+struct sst_block_ops {
+ int (*enable)(struct sst_mem_block *block);
+ int (*disable)(struct sst_mem_block *block);
+};
+
+/*
+ * SST Generic Memory Block.
+ *
+ * SST ADP memory has multiple IRAM and DRAM blocks. Some ADSP blocks can be
+ * power gated.
+ */
+struct sst_mem_block {
+ struct sst_dsp *dsp;
+ struct sst_module *module; /* module that uses this block */
+
+ /* block config */
+ u32 offset; /* offset from base */
+ u32 size; /* block size */
+ u32 index; /* block index 0..N */
+ enum sst_mem_type type; /* block memory type IRAM/DRAM */
+ struct sst_block_ops *ops; /* block operations, if any */
+
+ /* block status */
+ enum sst_data_type data_type; /* data type held in this block */
+ u32 bytes_used; /* bytes in use by modules */
+ void *private; /* generic core does not touch this */
+ int users; /* number of modules using this block */
+
+ /* block lists */
+ struct list_head module_list; /* Module list of blocks */
+ struct list_head list; /* Map list of free/used blocks */
+};
+
+/*
+ * Generic SST Shim Interface.
+ */
+struct sst_dsp {
+
+ /* runtime */
+ struct sst_dsp_device *sst_dev;
+ spinlock_t spinlock; /* IPC locking */
+ struct mutex mutex; /* DSP FW lock */
+ struct device *dev;
+ void *thread_context;
+ int irq;
+ u32 id;
+
+ /* list of free and used ADSP memory blocks */
+ struct list_head used_block_list;
+ struct list_head free_block_list;
+
+ /* operations */
+ struct sst_ops *ops;
+
+ /* debug FS */
+ struct dentry *debugfs_root;
+
+ /* base addresses */
+ struct sst_addr addr;
+
+ /* mailbox */
+ struct sst_mailbox mailbox;
+
+ /* SST FW files loaded and their modules */
+ struct list_head module_list;
+ struct list_head fw_list;
+
+ /* platform data */
+ struct sst_pdata *pdata;
+
+ /* DMA FW loading */
+ struct sst_dma *dma;
+ bool fw_use_dma;
+};
+
+/* Size optimised DRAM/IRAM memcpy */
+static inline void sst_dsp_write(struct sst_dsp *sst, void *src,
+ u32 dest_offset, size_t bytes)
+{
+ sst->ops->ram_write(sst, sst->addr.lpe + dest_offset, src, bytes);
+}
+
+static inline void sst_dsp_read(struct sst_dsp *sst, void *dest,
+ u32 src_offset, size_t bytes)
+{
+ sst->ops->ram_read(sst, dest, sst->addr.lpe + src_offset, bytes);
+}
+
+static inline void *sst_dsp_get_thread_context(struct sst_dsp *sst)
+{
+ return sst->thread_context;
+}
+
+/* Create/Free FW files - can contain multiple modules */
+struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
+ const struct firmware *fw, void *private);
+void sst_fw_free(struct sst_fw *sst_fw);
+void sst_fw_free_all(struct sst_dsp *dsp);
+
+/* Create/Free firmware modules */
+struct sst_module *sst_module_new(struct sst_fw *sst_fw,
+ struct sst_module_template *template, void *private);
+void sst_module_free(struct sst_module *sst_module);
+int sst_module_insert(struct sst_module *sst_module);
+int sst_module_remove(struct sst_module *sst_module);
+int sst_module_insert_fixed_block(struct sst_module *module,
+ struct sst_module_data *data);
+struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id);
+
+/* allocate/free pesistent/scratch memory regions managed by drv */
+struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp);
+void sst_mem_block_free_scratch(struct sst_dsp *dsp,
+ struct sst_module *scratch);
+int sst_block_module_remove(struct sst_module *module);
+
+/* Register the DSPs memory blocks - would be nice to read from ACPI */
+struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
+ u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
+ void *private);
+void sst_mem_block_unregister_all(struct sst_dsp *dsp);
+
+#endif
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c
new file mode 100644
index 000000000000..0c129fd85ecf
--- /dev/null
+++ b/sound/soc/intel/sst-dsp.c
@@ -0,0 +1,385 @@
+/*
+ * Intel Smart Sound Technology (SST) DSP Core Driver
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 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/slab.h>
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/intel-sst.h>
+
+/* Internal generic low-level SST IO functions - can be overidden */
+void sst_shim32_write(void __iomem *addr, u32 offset, u32 value)
+{
+ writel(value, addr + offset);
+}
+EXPORT_SYMBOL_GPL(sst_shim32_write);
+
+u32 sst_shim32_read(void __iomem *addr, u32 offset)
+{
+ return readl(addr + offset);
+}
+EXPORT_SYMBOL_GPL(sst_shim32_read);
+
+void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value)
+{
+ memcpy_toio(addr + offset, &value, sizeof(value));
+}
+EXPORT_SYMBOL_GPL(sst_shim32_write64);
+
+u64 sst_shim32_read64(void __iomem *addr, u32 offset)
+{
+ u64 val;
+
+ memcpy_fromio(&val, addr + offset, sizeof(val));
+ return val;
+}
+EXPORT_SYMBOL_GPL(sst_shim32_read64);
+
+static inline void _sst_memcpy_toio_32(volatile u32 __iomem *dest,
+ u32 *src, size_t bytes)
+{
+ int i, words = bytes >> 2;
+
+ for (i = 0; i < words; i++)
+ writel(src[i], dest + i);
+}
+
+static inline void _sst_memcpy_fromio_32(u32 *dest,
+ const volatile __iomem u32 *src, size_t bytes)
+{
+ int i, words = bytes >> 2;
+
+ for (i = 0; i < words; i++)
+ dest[i] = readl(src + i);
+}
+
+void sst_memcpy_toio_32(struct sst_dsp *sst,
+ void __iomem *dest, void *src, size_t bytes)
+{
+ _sst_memcpy_toio_32(dest, src, bytes);
+}
+EXPORT_SYMBOL_GPL(sst_memcpy_toio_32);
+
+void sst_memcpy_fromio_32(struct sst_dsp *sst, void *dest,
+ void __iomem *src, size_t bytes)
+{
+ _sst_memcpy_fromio_32(dest, src, bytes);
+}
+EXPORT_SYMBOL_GPL(sst_memcpy_fromio_32);
+
+/* Public API */
+void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sst->spinlock, flags);
+ sst->ops->write(sst->addr.shim, offset, value);
+ spin_unlock_irqrestore(&sst->spinlock, flags);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_write);
+
+u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset)
+{
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&sst->spinlock, flags);
+ val = sst->ops->read(sst->addr.shim, offset);
+ spin_unlock_irqrestore(&sst->spinlock, flags);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_read);
+
+void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sst->spinlock, flags);
+ sst->ops->write64(sst->addr.shim, offset, value);
+ spin_unlock_irqrestore(&sst->spinlock, flags);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_write64);
+
+u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset)
+{
+ unsigned long flags;
+ u64 val;
+
+ spin_lock_irqsave(&sst->spinlock, flags);
+ val = sst->ops->read64(sst->addr.shim, offset);
+ spin_unlock_irqrestore(&sst->spinlock, flags);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_read64);
+
+void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value)
+{
+ sst->ops->write(sst->addr.shim, offset, value);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked);
+
+u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset)
+{
+ return sst->ops->read(sst->addr.shim, offset);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked);
+
+void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value)
+{
+ sst->ops->write64(sst->addr.shim, offset, value);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_write64_unlocked);
+
+u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset)
+{
+ return sst->ops->read64(sst->addr.shim, offset);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_read64_unlocked);
+
+int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
+ u32 mask, u32 value)
+{
+ bool change;
+ unsigned int old, new;
+ u32 ret;
+
+ ret = sst_dsp_shim_read_unlocked(sst, offset);
+
+ old = ret;
+ new = (old & (~mask)) | (value & mask);
+
+ change = (old != new);
+ if (change)
+ sst_dsp_shim_write_unlocked(sst, offset, new);
+
+ return change;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked);
+
+int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
+ u64 mask, u64 value)
+{
+ bool change;
+ u64 old, new;
+
+ old = sst_dsp_shim_read64_unlocked(sst, offset);
+
+ new = (old & (~mask)) | (value & mask);
+
+ change = (old != new);
+ if (change)
+ sst_dsp_shim_write64_unlocked(sst, offset, new);
+
+ return change;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked);
+
+int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
+ u32 mask, u32 value)
+{
+ unsigned long flags;
+ bool change;
+
+ spin_lock_irqsave(&sst->spinlock, flags);
+ change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value);
+ spin_unlock_irqrestore(&sst->spinlock, flags);
+ return change;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits);
+
+int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
+ u64 mask, u64 value)
+{
+ unsigned long flags;
+ bool change;
+
+ spin_lock_irqsave(&sst->spinlock, flags);
+ change = sst_dsp_shim_update_bits64_unlocked(sst, offset, mask, value);
+ spin_unlock_irqrestore(&sst->spinlock, flags);
+ return change;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64);
+
+void sst_dsp_dump(struct sst_dsp *sst)
+{
+ sst->ops->dump(sst);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_dump);
+
+void sst_dsp_reset(struct sst_dsp *sst)
+{
+ sst->ops->reset(sst);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_reset);
+
+int sst_dsp_boot(struct sst_dsp *sst)
+{
+ sst->ops->boot(sst);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_boot);
+
+void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg)
+{
+ sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY);
+ trace_sst_ipc_msg_tx(msg);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_tx);
+
+u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp)
+{
+ u32 msg;
+
+ msg = sst_dsp_shim_read_unlocked(dsp, SST_IPCX);
+ trace_sst_ipc_msg_rx(msg);
+
+ return msg;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_rx);
+
+int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size,
+ u32 outbox_offset, size_t outbox_size)
+{
+ sst->mailbox.in_base = sst->addr.lpe + inbox_offset;
+ sst->mailbox.out_base = sst->addr.lpe + outbox_offset;
+ sst->mailbox.in_size = inbox_size;
+ sst->mailbox.out_size = outbox_size;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init);
+
+void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes)
+{
+ u32 i;
+
+ trace_sst_ipc_outbox_write(bytes);
+
+ memcpy_toio(sst->mailbox.out_base, message, bytes);
+
+ for (i = 0; i < bytes; i += 4)
+ trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i));
+}
+EXPORT_SYMBOL_GPL(sst_dsp_outbox_write);
+
+void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes)
+{
+ u32 i;
+
+ trace_sst_ipc_outbox_read(bytes);
+
+ memcpy_fromio(message, sst->mailbox.out_base, bytes);
+
+ for (i = 0; i < bytes; i += 4)
+ trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i));
+}
+EXPORT_SYMBOL_GPL(sst_dsp_outbox_read);
+
+void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes)
+{
+ u32 i;
+
+ trace_sst_ipc_inbox_write(bytes);
+
+ memcpy_toio(sst->mailbox.in_base, message, bytes);
+
+ for (i = 0; i < bytes; i += 4)
+ trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i));
+}
+EXPORT_SYMBOL_GPL(sst_dsp_inbox_write);
+
+void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
+{
+ u32 i;
+
+ trace_sst_ipc_inbox_read(bytes);
+
+ memcpy_fromio(message, sst->mailbox.in_base, bytes);
+
+ for (i = 0; i < bytes; i += 4)
+ trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i));
+}
+EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
+
+struct sst_dsp *sst_dsp_new(struct device *dev,
+ struct sst_dsp_device *sst_dev, struct sst_pdata *pdata)
+{
+ struct sst_dsp *sst;
+ int err;
+
+ dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id);
+
+ sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL);
+ if (sst == NULL)
+ return NULL;
+
+ spin_lock_init(&sst->spinlock);
+ mutex_init(&sst->mutex);
+ sst->dev = dev;
+ sst->thread_context = sst_dev->thread_context;
+ sst->sst_dev = sst_dev;
+ sst->id = pdata->id;
+ sst->irq = pdata->irq;
+ sst->ops = sst_dev->ops;
+ sst->pdata = pdata;
+ INIT_LIST_HEAD(&sst->used_block_list);
+ INIT_LIST_HEAD(&sst->free_block_list);
+ INIT_LIST_HEAD(&sst->module_list);
+ INIT_LIST_HEAD(&sst->fw_list);
+
+ /* Initialise SST Audio DSP */
+ if (sst->ops->init) {
+ err = sst->ops->init(sst, pdata);
+ if (err < 0)
+ return NULL;
+ }
+
+ /* Register the ISR */
+ err = request_threaded_irq(sst->irq, sst->ops->irq_handler,
+ sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
+ if (err)
+ goto irq_err;
+
+ return sst;
+
+irq_err:
+ if (sst->ops->free)
+ sst->ops->free(sst);
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_new);
+
+void sst_dsp_free(struct sst_dsp *sst)
+{
+ free_irq(sst->irq, sst);
+ if (sst->ops->free)
+ sst->ops->free(sst);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_free);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_DESCRIPTION("Intel SST Core");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h
new file mode 100644
index 000000000000..74052b59485c
--- /dev/null
+++ b/sound/soc/intel/sst-dsp.h
@@ -0,0 +1,233 @@
+/*
+ * Intel Smart Sound Technology (SST) Core
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SOUND_SOC_SST_DSP_H
+#define __SOUND_SOC_SST_DSP_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+
+/* SST Device IDs */
+#define SST_DEV_ID_LYNX_POINT 0x33C8
+#define SST_DEV_ID_WILDCAT_POINT 0x3438
+#define SST_DEV_ID_BYT 0x0F28
+
+/* Supported SST DMA Devices */
+#define SST_DMA_TYPE_DW 1
+#define SST_DMA_TYPE_MID 2
+
+/* SST Shim register map
+ * The register naming can differ between products. Some products also
+ * contain extra functionality.
+ */
+#define SST_CSR 0x00
+#define SST_PISR 0x08
+#define SST_PIMR 0x10
+#define SST_ISRX 0x18
+#define SST_ISRD 0x20
+#define SST_IMRX 0x28
+#define SST_IMRD 0x30
+#define SST_IPCX 0x38 /* IPC IA -> SST */
+#define SST_IPCD 0x40 /* IPC SST -> IA */
+#define SST_ISRSC 0x48
+#define SST_ISRLPESC 0x50
+#define SST_IMRSC 0x58
+#define SST_IMRLPESC 0x60
+#define SST_IPCSC 0x68
+#define SST_IPCLPESC 0x70
+#define SST_CLKCTL 0x78
+#define SST_CSR2 0x80
+#define SST_LTRC 0xE0
+#define SST_HDMC 0xE8
+#define SST_DBGO 0xF0
+
+#define SST_SHIM_SIZE 0x100
+#define SST_PWMCTRL 0x1000
+
+/* SST Shim Register bits
+ * The register bit naming can differ between products. Some products also
+ * contain extra functionality.
+ */
+
+/* CSR / CS */
+#define SST_CSR_RST (0x1 << 1)
+#define SST_CSR_SBCS0 (0x1 << 2)
+#define SST_CSR_SBCS1 (0x1 << 3)
+#define SST_CSR_DCS(x) (x << 4)
+#define SST_CSR_DCS_MASK (0x7 << 4)
+#define SST_CSR_STALL (0x1 << 10)
+#define SST_CSR_S0IOCS (0x1 << 21)
+#define SST_CSR_S1IOCS (0x1 << 23)
+#define SST_CSR_LPCS (0x1 << 31)
+#define SST_BYT_CSR_RST (0x1 << 0)
+#define SST_BYT_CSR_VECTOR_SEL (0x1 << 1)
+#define SST_BYT_CSR_STALL (0x1 << 2)
+#define SST_BYT_CSR_PWAITMODE (0x1 << 3)
+
+/* ISRX / ISC */
+#define SST_ISRX_BUSY (0x1 << 1)
+#define SST_ISRX_DONE (0x1 << 0)
+#define SST_BYT_ISRX_REQUEST (0x1 << 1)
+
+/* ISRD / ISD */
+#define SST_ISRD_BUSY (0x1 << 1)
+#define SST_ISRD_DONE (0x1 << 0)
+
+/* IMRX / IMC */
+#define SST_IMRX_BUSY (0x1 << 1)
+#define SST_IMRX_DONE (0x1 << 0)
+#define SST_BYT_IMRX_REQUEST (0x1 << 1)
+
+/* IPCX / IPCC */
+#define SST_IPCX_DONE (0x1 << 30)
+#define SST_IPCX_BUSY (0x1 << 31)
+#define SST_BYT_IPCX_DONE ((u64)0x1 << 62)
+#define SST_BYT_IPCX_BUSY ((u64)0x1 << 63)
+
+/* IPCD */
+#define SST_IPCD_DONE (0x1 << 30)
+#define SST_IPCD_BUSY (0x1 << 31)
+#define SST_BYT_IPCD_DONE ((u64)0x1 << 62)
+#define SST_BYT_IPCD_BUSY ((u64)0x1 << 63)
+
+/* CLKCTL */
+#define SST_CLKCTL_SMOS(x) (x << 24)
+#define SST_CLKCTL_MASK (3 << 24)
+#define SST_CLKCTL_DCPLCG (1 << 18)
+#define SST_CLKCTL_SCOE1 (1 << 17)
+#define SST_CLKCTL_SCOE0 (1 << 16)
+
+/* CSR2 / CS2 */
+#define SST_CSR2_SDFD_SSP0 (1 << 1)
+#define SST_CSR2_SDFD_SSP1 (1 << 2)
+
+/* LTRC */
+#define SST_LTRC_VAL(x) (x << 0)
+
+/* HDMC */
+#define SST_HDMC_HDDA0(x) (x << 0)
+#define SST_HDMC_HDDA1(x) (x << 7)
+
+
+/* SST Vendor Defined Registers and bits */
+#define SST_VDRTCTL0 0xa0
+#define SST_VDRTCTL1 0xa4
+#define SST_VDRTCTL2 0xa8
+#define SST_VDRTCTL3 0xaC
+
+/* VDRTCTL0 */
+#define SST_VDRTCL0_DSRAMPGE_SHIFT 16
+#define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT)
+#define SST_VDRTCL0_ISRAMPGE_SHIFT 6
+#define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT)
+
+struct sst_dsp;
+
+/*
+ * SST Device.
+ *
+ * This structure is populated by the SST core driver.
+ */
+struct sst_dsp_device {
+ /* Mandatory fields */
+ struct sst_ops *ops;
+ irqreturn_t (*thread)(int irq, void *context);
+ void *thread_context;
+};
+
+/*
+ * SST Platform Data.
+ */
+struct sst_pdata {
+ /* ACPI data */
+ u32 lpe_base;
+ u32 lpe_size;
+ u32 pcicfg_base;
+ u32 pcicfg_size;
+ u32 fw_base;
+ u32 fw_size;
+ int irq;
+
+ /* Firmware */
+ const struct firmware *fw;
+
+ /* DMA */
+ u32 dma_base;
+ u32 dma_size;
+ int dma_engine;
+
+ /* DSP */
+ u32 id;
+ void *dsp;
+};
+
+/* Initialization */
+struct sst_dsp *sst_dsp_new(struct device *dev,
+ struct sst_dsp_device *sst_dev, struct sst_pdata *pdata);
+void sst_dsp_free(struct sst_dsp *sst);
+
+/* SHIM Read / Write */
+void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value);
+u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset);
+int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
+ u32 mask, u32 value);
+void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value);
+u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset);
+int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
+ u64 mask, u64 value);
+
+/* SHIM Read / Write Unlocked for callers already holding sst lock */
+void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value);
+u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset);
+int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
+ u32 mask, u32 value);
+void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value);
+u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset);
+int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
+ u64 mask, u64 value);
+
+/* Internal generic low-level SST IO functions - can be overidden */
+void sst_shim32_write(void __iomem *addr, u32 offset, u32 value);
+u32 sst_shim32_read(void __iomem *addr, u32 offset);
+void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value);
+u64 sst_shim32_read64(void __iomem *addr, u32 offset);
+void sst_memcpy_toio_32(struct sst_dsp *sst,
+ void __iomem *dest, void *src, size_t bytes);
+void sst_memcpy_fromio_32(struct sst_dsp *sst,
+ void *dest, void __iomem *src, size_t bytes);
+
+/* DSP reset & boot */
+void sst_dsp_reset(struct sst_dsp *sst);
+int sst_dsp_boot(struct sst_dsp *sst);
+
+/* Msg IO */
+void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg);
+u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp);
+
+/* Mailbox management */
+int sst_dsp_mailbox_init(struct sst_dsp *dsp, u32 inbox_offset,
+ size_t inbox_size, u32 outbox_offset, size_t outbox_size);
+void sst_dsp_inbox_write(struct sst_dsp *dsp, void *message, size_t bytes);
+void sst_dsp_inbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
+void sst_dsp_outbox_write(struct sst_dsp *dsp, void *message, size_t bytes);
+void sst_dsp_outbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
+void sst_dsp_mailbox_dump(struct sst_dsp *dsp, size_t bytes);
+
+/* Debug */
+void sst_dsp_dump(struct sst_dsp *sst);
+
+#endif
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c
new file mode 100644
index 000000000000..f7687107cf7f
--- /dev/null
+++ b/sound/soc/intel/sst-firmware.c
@@ -0,0 +1,587 @@
+/*
+ * Intel SST Firmware Loader
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 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/kernel.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/firmware.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/pci.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+
+static void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes)
+{
+ u32 i;
+
+ /* copy one 32 bit word at a time as 64 bit access is not supported */
+ for (i = 0; i < bytes; i += 4)
+ memcpy_toio(dest + i, src + i, 4);
+}
+
+/* create new generic firmware object */
+struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
+ const struct firmware *fw, void *private)
+{
+ struct sst_fw *sst_fw;
+ int err;
+
+ if (!dsp->ops->parse_fw)
+ return NULL;
+
+ sst_fw = kzalloc(sizeof(*sst_fw), GFP_KERNEL);
+ if (sst_fw == NULL)
+ return NULL;
+
+ sst_fw->dsp = dsp;
+ sst_fw->private = private;
+ sst_fw->size = fw->size;
+
+ err = dma_coerce_mask_and_coherent(dsp->dev, DMA_BIT_MASK(32));
+ if (err < 0) {
+ kfree(sst_fw);
+ return NULL;
+ }
+
+ /* allocate DMA buffer to store FW data */
+ sst_fw->dma_buf = dma_alloc_coherent(dsp->dev, sst_fw->size,
+ &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL);
+ if (!sst_fw->dma_buf) {
+ dev_err(dsp->dev, "error: DMA alloc failed\n");
+ kfree(sst_fw);
+ return NULL;
+ }
+
+ /* copy FW data to DMA-able memory */
+ memcpy((void *)sst_fw->dma_buf, (void *)fw->data, fw->size);
+
+ /* call core specific FW paser to load FW data into DSP */
+ err = dsp->ops->parse_fw(sst_fw);
+ if (err < 0) {
+ dev_err(dsp->dev, "error: parse fw failed %d\n", err);
+ goto parse_err;
+ }
+
+ mutex_lock(&dsp->mutex);
+ list_add(&sst_fw->list, &dsp->fw_list);
+ mutex_unlock(&dsp->mutex);
+
+ return sst_fw;
+
+parse_err:
+ dma_free_coherent(dsp->dev, sst_fw->size,
+ sst_fw->dma_buf,
+ sst_fw->dmable_fw_paddr);
+ kfree(sst_fw);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_fw_new);
+
+/* free single firmware object */
+void sst_fw_free(struct sst_fw *sst_fw)
+{
+ struct sst_dsp *dsp = sst_fw->dsp;
+
+ mutex_lock(&dsp->mutex);
+ list_del(&sst_fw->list);
+ mutex_unlock(&dsp->mutex);
+
+ dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf,
+ sst_fw->dmable_fw_paddr);
+ kfree(sst_fw);
+}
+EXPORT_SYMBOL_GPL(sst_fw_free);
+
+/* free all firmware objects */
+void sst_fw_free_all(struct sst_dsp *dsp)
+{
+ struct sst_fw *sst_fw, *t;
+
+ mutex_lock(&dsp->mutex);
+ list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) {
+
+ list_del(&sst_fw->list);
+ dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf,
+ sst_fw->dmable_fw_paddr);
+ kfree(sst_fw);
+ }
+ mutex_unlock(&dsp->mutex);
+}
+EXPORT_SYMBOL_GPL(sst_fw_free_all);
+
+/* create a new SST generic module from FW template */
+struct sst_module *sst_module_new(struct sst_fw *sst_fw,
+ struct sst_module_template *template, void *private)
+{
+ struct sst_dsp *dsp = sst_fw->dsp;
+ struct sst_module *sst_module;
+
+ sst_module = kzalloc(sizeof(*sst_module), GFP_KERNEL);
+ if (sst_module == NULL)
+ return NULL;
+
+ sst_module->id = template->id;
+ sst_module->dsp = dsp;
+ sst_module->sst_fw = sst_fw;
+
+ memcpy(&sst_module->s, &template->s, sizeof(struct sst_module_data));
+ memcpy(&sst_module->p, &template->p, sizeof(struct sst_module_data));
+
+ INIT_LIST_HEAD(&sst_module->block_list);
+
+ mutex_lock(&dsp->mutex);
+ list_add(&sst_module->list, &dsp->module_list);
+ mutex_unlock(&dsp->mutex);
+
+ return sst_module;
+}
+EXPORT_SYMBOL_GPL(sst_module_new);
+
+/* free firmware module and remove from available list */
+void sst_module_free(struct sst_module *sst_module)
+{
+ struct sst_dsp *dsp = sst_module->dsp;
+
+ mutex_lock(&dsp->mutex);
+ list_del(&sst_module->list);
+ mutex_unlock(&dsp->mutex);
+
+ kfree(sst_module);
+}
+EXPORT_SYMBOL_GPL(sst_module_free);
+
+static struct sst_mem_block *find_block(struct sst_dsp *dsp, int type,
+ u32 offset)
+{
+ struct sst_mem_block *block;
+
+ list_for_each_entry(block, &dsp->free_block_list, list) {
+ if (block->type == type && block->offset == offset)
+ return block;
+ }
+
+ return NULL;
+}
+
+static int block_alloc_contiguous(struct sst_module *module,
+ struct sst_module_data *data, u32 offset, int size)
+{
+ struct list_head tmp = LIST_HEAD_INIT(tmp);
+ struct sst_dsp *dsp = module->dsp;
+ struct sst_mem_block *block;
+
+ while (size > 0) {
+ block = find_block(dsp, data->type, offset);
+ if (!block) {
+ list_splice(&tmp, &dsp->free_block_list);
+ return -ENOMEM;
+ }
+
+ list_move_tail(&block->list, &tmp);
+ offset += block->size;
+ size -= block->size;
+ }
+
+ list_splice(&tmp, &dsp->used_block_list);
+ return 0;
+}
+
+/* allocate free DSP blocks for module data - callers hold locks */
+static int block_alloc(struct sst_module *module,
+ struct sst_module_data *data)
+{
+ struct sst_dsp *dsp = module->dsp;
+ struct sst_mem_block *block, *tmp;
+ int ret = 0;
+
+ if (data->size == 0)
+ return 0;
+
+ /* find first free whole blocks that can hold module */
+ list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
+
+ /* ignore blocks with wrong type */
+ if (block->type != data->type)
+ continue;
+
+ if (data->size > block->size)
+ continue;
+
+ data->offset = block->offset;
+ block->data_type = data->data_type;
+ block->bytes_used = data->size % block->size;
+ list_add(&block->module_list, &module->block_list);
+ list_move(&block->list, &dsp->used_block_list);
+ dev_dbg(dsp->dev, " *module %d added block %d:%d\n",
+ module->id, block->type, block->index);
+ return 0;
+ }
+
+ /* then find free multiple blocks that can hold module */
+ list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
+
+ /* ignore blocks with wrong type */
+ if (block->type != data->type)
+ continue;
+
+ /* do we span > 1 blocks */
+ if (data->size > block->size) {
+ ret = block_alloc_contiguous(module, data,
+ block->offset + block->size,
+ data->size - block->size);
+ if (ret == 0)
+ return ret;
+ }
+ }
+
+ /* not enough free block space */
+ return -ENOMEM;
+}
+
+/* remove module from memory - callers hold locks */
+static void block_module_remove(struct sst_module *module)
+{
+ struct sst_mem_block *block, *tmp;
+ struct sst_dsp *dsp = module->dsp;
+ int err;
+
+ /* disable each block */
+ list_for_each_entry(block, &module->block_list, module_list) {
+
+ if (block->ops && block->ops->disable) {
+ err = block->ops->disable(block);
+ if (err < 0)
+ dev_err(dsp->dev,
+ "error: cant disable block %d:%d\n",
+ block->type, block->index);
+ }
+ }
+
+ /* mark each block as free */
+ list_for_each_entry_safe(block, tmp, &module->block_list, module_list) {
+ list_del(&block->module_list);
+ list_move(&block->list, &dsp->free_block_list);
+ }
+}
+
+/* prepare the memory block to receive data from host - callers hold locks */
+static int block_module_prepare(struct sst_module *module)
+{
+ struct sst_mem_block *block;
+ int ret = 0;
+
+ /* enable each block so that's it'e ready for module P/S data */
+ list_for_each_entry(block, &module->block_list, module_list) {
+
+ if (block->ops && block->ops->enable) {
+ ret = block->ops->enable(block);
+ if (ret < 0) {
+ dev_err(module->dsp->dev,
+ "error: cant disable block %d:%d\n",
+ block->type, block->index);
+ goto err;
+ }
+ }
+ }
+ return ret;
+
+err:
+ list_for_each_entry(block, &module->block_list, module_list) {
+ if (block->ops && block->ops->disable)
+ block->ops->disable(block);
+ }
+ return ret;
+}
+
+/* allocate memory blocks for static module addresses - callers hold locks */
+static int block_alloc_fixed(struct sst_module *module,
+ struct sst_module_data *data)
+{
+ struct sst_dsp *dsp = module->dsp;
+ struct sst_mem_block *block, *tmp;
+ u32 end = data->offset + data->size, block_end;
+ int err;
+
+ /* only IRAM/DRAM blocks are managed */
+ if (data->type != SST_MEM_IRAM && data->type != SST_MEM_DRAM)
+ return 0;
+
+ /* are blocks already attached to this module */
+ list_for_each_entry_safe(block, tmp, &module->block_list, module_list) {
+
+ /* force compacting mem blocks of the same data_type */
+ if (block->data_type != data->data_type)
+ continue;
+
+ block_end = block->offset + block->size;
+
+ /* find block that holds section */
+ if (data->offset >= block->offset && end < block_end)
+ return 0;
+
+ /* does block span more than 1 section */
+ if (data->offset >= block->offset && data->offset < block_end) {
+
+ err = block_alloc_contiguous(module, data,
+ block->offset + block->size,
+ data->size - block->size + data->offset - block->offset);
+ if (err < 0)
+ return -ENOMEM;
+
+ /* module already owns blocks */
+ return 0;
+ }
+ }
+
+ /* find first free blocks that can hold section in free list */
+ list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
+ block_end = block->offset + block->size;
+
+ /* find block that holds section */
+ if (data->offset >= block->offset && end < block_end) {
+
+ /* add block */
+ block->data_type = data->data_type;
+ list_move(&block->list, &dsp->used_block_list);
+ list_add(&block->module_list, &module->block_list);
+ return 0;
+ }
+
+ /* does block span more than 1 section */
+ if (data->offset >= block->offset && data->offset < block_end) {
+
+ err = block_alloc_contiguous(module, data,
+ block->offset + block->size,
+ data->size - block->size);
+ if (err < 0)
+ return -ENOMEM;
+
+ /* add block */
+ block->data_type = data->data_type;
+ list_move(&block->list, &dsp->used_block_list);
+ list_add(&block->module_list, &module->block_list);
+ return 0;
+ }
+
+ }
+
+ return -ENOMEM;
+}
+
+/* Load fixed module data into DSP memory blocks */
+int sst_module_insert_fixed_block(struct sst_module *module,
+ struct sst_module_data *data)
+{
+ struct sst_dsp *dsp = module->dsp;
+ int ret;
+
+ mutex_lock(&dsp->mutex);
+
+ /* alloc blocks that includes this section */
+ ret = block_alloc_fixed(module, data);
+ if (ret < 0) {
+ dev_err(dsp->dev,
+ "error: no free blocks for section at offset 0x%x size 0x%x\n",
+ data->offset, data->size);
+ mutex_unlock(&dsp->mutex);
+ return -ENOMEM;
+ }
+
+ /* prepare DSP blocks for module copy */
+ ret = block_module_prepare(module);
+ if (ret < 0) {
+ dev_err(dsp->dev, "error: fw module prepare failed\n");
+ goto err;
+ }
+
+ /* copy partial module data to blocks */
+ sst_memcpy32(dsp->addr.lpe + data->offset, data->data, data->size);
+
+ mutex_unlock(&dsp->mutex);
+ return ret;
+
+err:
+ block_module_remove(module);
+ mutex_unlock(&dsp->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sst_module_insert_fixed_block);
+
+/* Unload entire module from DSP memory */
+int sst_block_module_remove(struct sst_module *module)
+{
+ struct sst_dsp *dsp = module->dsp;
+
+ mutex_lock(&dsp->mutex);
+ block_module_remove(module);
+ mutex_unlock(&dsp->mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sst_block_module_remove);
+
+/* register a DSP memory block for use with FW based modules */
+struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
+ u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
+ void *private)
+{
+ struct sst_mem_block *block;
+
+ block = kzalloc(sizeof(*block), GFP_KERNEL);
+ if (block == NULL)
+ return NULL;
+
+ block->offset = offset;
+ block->size = size;
+ block->index = index;
+ block->type = type;
+ block->dsp = dsp;
+ block->private = private;
+ block->ops = ops;
+
+ mutex_lock(&dsp->mutex);
+ list_add(&block->list, &dsp->free_block_list);
+ mutex_unlock(&dsp->mutex);
+
+ return block;
+}
+EXPORT_SYMBOL_GPL(sst_mem_block_register);
+
+/* unregister all DSP memory blocks */
+void sst_mem_block_unregister_all(struct sst_dsp *dsp)
+{
+ struct sst_mem_block *block, *tmp;
+
+ mutex_lock(&dsp->mutex);
+
+ /* unregister used blocks */
+ list_for_each_entry_safe(block, tmp, &dsp->used_block_list, list) {
+ list_del(&block->list);
+ kfree(block);
+ }
+
+ /* unregister free blocks */
+ list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
+ list_del(&block->list);
+ kfree(block);
+ }
+
+ mutex_unlock(&dsp->mutex);
+}
+EXPORT_SYMBOL_GPL(sst_mem_block_unregister_all);
+
+/* allocate scratch buffer blocks */
+struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp)
+{
+ struct sst_module *sst_module, *scratch;
+ struct sst_mem_block *block, *tmp;
+ u32 block_size;
+ int ret = 0;
+
+ scratch = kzalloc(sizeof(struct sst_module), GFP_KERNEL);
+ if (scratch == NULL)
+ return NULL;
+
+ mutex_lock(&dsp->mutex);
+
+ /* calculate required scratch size */
+ list_for_each_entry(sst_module, &dsp->module_list, list) {
+ if (scratch->s.size > sst_module->s.size)
+ scratch->s.size = scratch->s.size;
+ else
+ scratch->s.size = sst_module->s.size;
+ }
+
+ dev_dbg(dsp->dev, "scratch buffer required is %d bytes\n",
+ scratch->s.size);
+
+ /* init scratch module */
+ scratch->dsp = dsp;
+ scratch->s.type = SST_MEM_DRAM;
+ scratch->s.data_type = SST_DATA_S;
+ INIT_LIST_HEAD(&scratch->block_list);
+
+ /* check free blocks before looking at used blocks for space */
+ if (!list_empty(&dsp->free_block_list))
+ block = list_first_entry(&dsp->free_block_list,
+ struct sst_mem_block, list);
+ else
+ block = list_first_entry(&dsp->used_block_list,
+ struct sst_mem_block, list);
+ block_size = block->size;
+
+ /* allocate blocks for module scratch buffers */
+ dev_dbg(dsp->dev, "allocating scratch blocks\n");
+ ret = block_alloc(scratch, &scratch->s);
+ if (ret < 0) {
+ dev_err(dsp->dev, "error: can't alloc scratch blocks\n");
+ goto err;
+ }
+
+ /* assign the same offset of scratch to each module */
+ list_for_each_entry(sst_module, &dsp->module_list, list)
+ sst_module->s.offset = scratch->s.offset;
+
+ mutex_unlock(&dsp->mutex);
+ return scratch;
+
+err:
+ list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list)
+ list_del(&block->module_list);
+ mutex_unlock(&dsp->mutex);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_mem_block_alloc_scratch);
+
+/* free all scratch blocks */
+void sst_mem_block_free_scratch(struct sst_dsp *dsp,
+ struct sst_module *scratch)
+{
+ struct sst_mem_block *block, *tmp;
+
+ mutex_lock(&dsp->mutex);
+
+ list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list)
+ list_del(&block->module_list);
+
+ mutex_unlock(&dsp->mutex);
+}
+EXPORT_SYMBOL_GPL(sst_mem_block_free_scratch);
+
+/* get a module from it's unique ID */
+struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id)
+{
+ struct sst_module *module;
+
+ mutex_lock(&dsp->mutex);
+
+ list_for_each_entry(module, &dsp->module_list, list) {
+ if (module->id == id) {
+ mutex_unlock(&dsp->mutex);
+ return module;
+ }
+ }
+
+ mutex_unlock(&dsp->mutex);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_module_get_from_id);
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c
new file mode 100644
index 000000000000..f5ebf36af889
--- /dev/null
+++ b/sound/soc/intel/sst-haswell-dsp.c
@@ -0,0 +1,517 @@
+/*
+ * Intel Haswell SST DSP driver
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+#include "sst-haswell-ipc.h"
+
+#include <trace/events/hswadsp.h>
+
+#define SST_HSW_FW_SIGNATURE_SIZE 4
+#define SST_HSW_FW_SIGN "$SST"
+#define SST_HSW_FW_LIB_SIGN "$LIB"
+
+#define SST_WPT_SHIM_OFFSET 0xFB000
+#define SST_LP_SHIM_OFFSET 0xE7000
+#define SST_WPT_IRAM_OFFSET 0xA0000
+#define SST_LP_IRAM_OFFSET 0x80000
+
+#define SST_SHIM_PM_REG 0x84
+
+#define SST_HSW_IRAM 1
+#define SST_HSW_DRAM 2
+#define SST_HSW_REGS 3
+
+struct dma_block_info {
+ __le32 type; /* IRAM/DRAM */
+ __le32 size; /* Bytes */
+ __le32 ram_offset; /* Offset in I/DRAM */
+ __le32 rsvd; /* Reserved field */
+} __attribute__((packed));
+
+struct fw_module_info {
+ __le32 persistent_size;
+ __le32 scratch_size;
+} __attribute__((packed));
+
+struct fw_header {
+ unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* FW signature */
+ __le32 file_size; /* size of fw minus this header */
+ __le32 modules; /* # of modules */
+ __le32 file_format; /* version of header format */
+ __le32 reserved[4];
+} __attribute__((packed));
+
+struct fw_module_header {
+ unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* module signature */
+ __le32 mod_size; /* size of module */
+ __le32 blocks; /* # of blocks */
+ __le16 padding;
+ __le16 type; /* codec type, pp lib */
+ __le32 entry_point;
+ struct fw_module_info info;
+} __attribute__((packed));
+
+static void hsw_free(struct sst_dsp *sst);
+
+static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
+ struct fw_module_header *module)
+{
+ struct dma_block_info *block;
+ struct sst_module *mod;
+ struct sst_module_data block_data;
+ struct sst_module_template template;
+ int count;
+ void __iomem *ram;
+
+ /* TODO: allowed module types need to be configurable */
+ if (module->type != SST_HSW_MODULE_BASE_FW
+ && module->type != SST_HSW_MODULE_PCM_SYSTEM
+ && module->type != SST_HSW_MODULE_PCM
+ && module->type != SST_HSW_MODULE_PCM_REFERENCE
+ && module->type != SST_HSW_MODULE_PCM_CAPTURE
+ && module->type != SST_HSW_MODULE_LPAL)
+ return 0;
+
+ dev_dbg(dsp->dev, "new module sign 0x%s size 0x%x blocks 0x%x type 0x%x\n",
+ module->signature, module->mod_size,
+ module->blocks, module->type);
+ dev_dbg(dsp->dev, " entrypoint 0x%x\n", module->entry_point);
+ dev_dbg(dsp->dev, " persistent 0x%x scratch 0x%x\n",
+ module->info.persistent_size, module->info.scratch_size);
+
+ memset(&template, 0, sizeof(template));
+ template.id = module->type;
+ template.entry = module->entry_point;
+ template.p.size = module->info.persistent_size;
+ template.p.type = SST_MEM_DRAM;
+ template.p.data_type = SST_DATA_P;
+ template.s.size = module->info.scratch_size;
+ template.s.type = SST_MEM_DRAM;
+ template.s.data_type = SST_DATA_S;
+
+ mod = sst_module_new(fw, &template, NULL);
+ if (mod == NULL)
+ return -ENOMEM;
+
+ block = (void *)module + sizeof(*module);
+
+ for (count = 0; count < module->blocks; count++) {
+
+ if (block->size <= 0) {
+ dev_err(dsp->dev,
+ "error: block %d size invalid\n", count);
+ sst_module_free(mod);
+ return -EINVAL;
+ }
+
+ switch (block->type) {
+ case SST_HSW_IRAM:
+ ram = dsp->addr.lpe;
+ block_data.offset =
+ block->ram_offset + dsp->addr.iram_offset;
+ block_data.type = SST_MEM_IRAM;
+ break;
+ case SST_HSW_DRAM:
+ ram = dsp->addr.lpe;
+ block_data.offset = block->ram_offset;
+ block_data.type = SST_MEM_DRAM;
+ break;
+ default:
+ dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n",
+ block->type, count);
+ sst_module_free(mod);
+ return -EINVAL;
+ }
+
+ block_data.size = block->size;
+ block_data.data_type = SST_DATA_M;
+ block_data.data = (void *)block + sizeof(*block);
+ block_data.data_offset = block_data.data - fw->dma_buf;
+
+ dev_dbg(dsp->dev, "copy firmware block %d type 0x%x "
+ "size 0x%x ==> ram %p offset 0x%x\n",
+ count, block->type, block->size, ram,
+ block->ram_offset);
+
+ sst_module_insert_fixed_block(mod, &block_data);
+
+ block = (void *)block + sizeof(*block) + block->size;
+ }
+ return 0;
+}
+
+static int hsw_parse_fw_image(struct sst_fw *sst_fw)
+{
+ struct fw_header *header;
+ struct sst_module *scratch;
+ struct fw_module_header *module;
+ struct sst_dsp *dsp = sst_fw->dsp;
+ struct sst_hsw *hsw = sst_fw->private;
+ int ret, count;
+
+ /* Read the header information from the data pointer */
+ header = (struct fw_header *)sst_fw->dma_buf;
+
+ /* verify FW */
+ if ((strncmp(header->signature, SST_HSW_FW_SIGN, 4) != 0) ||
+ (sst_fw->size != header->file_size + sizeof(*header))) {
+ dev_err(dsp->dev, "error: invalid fw sign/filesize mismatch\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(dsp->dev, "header size=0x%x modules=0x%x fmt=0x%x size=%zu\n",
+ header->file_size, header->modules,
+ header->file_format, sizeof(*header));
+
+ /* parse each module */
+ module = (void *)sst_fw->dma_buf + sizeof(*header);
+ for (count = 0; count < header->modules; count++) {
+
+ /* module */
+ ret = hsw_parse_module(dsp, sst_fw, module);
+ if (ret < 0) {
+ dev_err(dsp->dev, "error: invalid module %d\n", count);
+ return ret;
+ }
+ module = (void *)module + sizeof(*module) + module->mod_size;
+ }
+
+ /* allocate persistent/scratch mem regions */
+ scratch = sst_mem_block_alloc_scratch(dsp);
+ if (scratch == NULL)
+ return -ENOMEM;
+
+ sst_hsw_set_scratch_module(hsw, scratch);
+
+ return 0;
+}
+
+static irqreturn_t hsw_irq(int irq, void *context)
+{
+ struct sst_dsp *sst = (struct sst_dsp *) context;
+ u32 isr;
+ int ret = IRQ_NONE;
+
+ spin_lock(&sst->spinlock);
+
+ /* Interrupt arrived, check src */
+ isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX);
+ if (isr & SST_ISRX_DONE) {
+ trace_sst_irq_done(isr,
+ sst_dsp_shim_read_unlocked(sst, SST_IMRX));
+
+ /* Mask Done interrupt before return */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+ SST_IMRX_DONE, SST_IMRX_DONE);
+ ret = IRQ_WAKE_THREAD;
+ }
+
+ if (isr & SST_ISRX_BUSY) {
+ trace_sst_irq_busy(isr,
+ sst_dsp_shim_read_unlocked(sst, SST_IMRX));
+
+ /* Mask Busy interrupt before return */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+ SST_IMRX_BUSY, SST_IMRX_BUSY);
+ ret = IRQ_WAKE_THREAD;
+ }
+
+ spin_unlock(&sst->spinlock);
+ return ret;
+}
+
+static void hsw_boot(struct sst_dsp *sst)
+{
+ /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+ SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0);
+
+ /* stall DSP core, set clk to 192/96Mhz */
+ sst_dsp_shim_update_bits_unlocked(sst,
+ SST_CSR, SST_CSR_STALL | SST_CSR_DCS_MASK,
+ SST_CSR_STALL | SST_CSR_DCS(4));
+
+ /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
+ SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0,
+ SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0);
+
+ /* disable DMA finish function for SSP0 & SSP1 */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1,
+ SST_CSR2_SDFD_SSP1);
+
+ /* enable DMA engine 0,1 all channels to access host memory */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_HDMC,
+ SST_HDMC_HDDA1(0xff) | SST_HDMC_HDDA0(0xff),
+ SST_HDMC_HDDA1(0xff) | SST_HDMC_HDDA0(0xff));
+
+ /* disable all clock gating */
+ writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+ /* set DSP to RUN */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0);
+}
+
+static void hsw_reset(struct sst_dsp *sst)
+{
+ /* put DSP into reset and stall */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+ SST_CSR_RST | SST_CSR_STALL, SST_CSR_RST | SST_CSR_STALL);
+
+ /* keep in reset for 10ms */
+ mdelay(10);
+
+ /* take DSP out of reset and keep stalled for FW loading */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+ SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
+}
+
+struct sst_adsp_memregion {
+ u32 start;
+ u32 end;
+ int blocks;
+ enum sst_mem_type type;
+};
+
+/* lynx point ADSP mem regions */
+static const struct sst_adsp_memregion lp_region[] = {
+ {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
+ {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */
+ {0x80000, 0xE0000, 12, SST_MEM_IRAM}, /* I-SRAM - 12 * 32kB */
+};
+
+/* wild cat point ADSP mem regions */
+static const struct sst_adsp_memregion wpt_region[] = {
+ {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
+ {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */
+ {0x80000, 0xA0000, 4, SST_MEM_DRAM}, /* D-SRAM2 - 4 * 32kB */
+ {0xA0000, 0xF0000, 10, SST_MEM_IRAM}, /* I-SRAM - 10 * 32kB */
+};
+
+static int hsw_acpi_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+ /* ADSP DRAM & IRAM */
+ sst->addr.lpe_base = pdata->lpe_base;
+ sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size);
+ if (!sst->addr.lpe)
+ return -ENODEV;
+
+ /* ADSP PCI MMIO config space */
+ sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size);
+ if (!sst->addr.pci_cfg) {
+ iounmap(sst->addr.lpe);
+ return -ENODEV;
+ }
+
+ /* SST Shim */
+ sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset;
+ return 0;
+}
+
+static u32 hsw_block_get_bit(struct sst_mem_block *block)
+{
+ u32 bit = 0, shift = 0;
+
+ switch (block->type) {
+ case SST_MEM_DRAM:
+ shift = 16;
+ break;
+ case SST_MEM_IRAM:
+ shift = 6;
+ break;
+ default:
+ return 0;
+ }
+
+ bit = 1 << (block->index + shift);
+
+ return bit;
+}
+
+/* enable 32kB memory block - locks held by caller */
+static int hsw_block_enable(struct sst_mem_block *block)
+{
+ struct sst_dsp *sst = block->dsp;
+ u32 bit, val;
+
+ if (block->users++ > 0)
+ return 0;
+
+ dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n",
+ block->type, block->index, block->offset);
+
+ val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+ bit = hsw_block_get_bit(block);
+ writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+ /* wait 18 DSP clock ticks */
+ udelay(10);
+
+ return 0;
+}
+
+/* disable 32kB memory block - locks held by caller */
+static int hsw_block_disable(struct sst_mem_block *block)
+{
+ struct sst_dsp *sst = block->dsp;
+ u32 bit, val;
+
+ if (--block->users > 0)
+ return 0;
+
+ dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n",
+ block->type, block->index, block->offset);
+
+ val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+ bit = hsw_block_get_bit(block);
+ writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+ return 0;
+}
+
+static struct sst_block_ops sst_hsw_ops = {
+ .enable = hsw_block_enable,
+ .disable = hsw_block_disable,
+};
+
+static int hsw_enable_shim(struct sst_dsp *sst)
+{
+ int tries = 10;
+ u32 reg;
+
+ /* enable shim */
+ reg = readl(sst->addr.pci_cfg + SST_SHIM_PM_REG);
+ writel(reg & ~0x3, sst->addr.pci_cfg + SST_SHIM_PM_REG);
+
+ /* check that ADSP shim is enabled */
+ while (tries--) {
+ reg = sst_dsp_shim_read_unlocked(sst, SST_CSR);
+ if (reg != 0xffffffff)
+ return 0;
+
+ msleep(1);
+ }
+
+ return -ENODEV;
+}
+
+static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
+{
+ const struct sst_adsp_memregion *region;
+ struct device *dev;
+ int ret = -ENODEV, i, j, region_count;
+ u32 offset, size;
+
+ dev = sst->dev;
+
+ switch (sst->id) {
+ case SST_DEV_ID_LYNX_POINT:
+ region = lp_region;
+ region_count = ARRAY_SIZE(lp_region);
+ sst->addr.iram_offset = SST_LP_IRAM_OFFSET;
+ sst->addr.shim_offset = SST_LP_SHIM_OFFSET;
+ break;
+ case SST_DEV_ID_WILDCAT_POINT:
+ region = wpt_region;
+ region_count = ARRAY_SIZE(wpt_region);
+ sst->addr.iram_offset = SST_WPT_IRAM_OFFSET;
+ sst->addr.shim_offset = SST_WPT_SHIM_OFFSET;
+ break;
+ default:
+ dev_err(dev, "error: failed to get mem resources\n");
+ return ret;
+ }
+
+ ret = hsw_acpi_resource_map(sst, pdata);
+ if (ret < 0) {
+ dev_err(dev, "error: failed to map resources\n");
+ return ret;
+ }
+
+ /* enable the DSP SHIM */
+ ret = hsw_enable_shim(sst);
+ if (ret < 0) {
+ dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n");
+ return ret;
+ }
+
+ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ /* Enable Interrupt from both sides */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, 0x3, 0x0);
+ sst_dsp_shim_update_bits_unlocked(sst, SST_IMRD,
+ (0x3 | 0x1 << 16 | 0x3 << 21), 0x0);
+
+ /* register DSP memory blocks - ideally we should get this from ACPI */
+ for (i = 0; i < region_count; i++) {
+ offset = region[i].start;
+ size = (region[i].end - region[i].start) / region[i].blocks;
+
+ /* register individual memory blocks */
+ for (j = 0; j < region[i].blocks; j++) {
+ sst_mem_block_register(sst, offset, size,
+ region[i].type, &sst_hsw_ops, j, sst);
+ offset += size;
+ }
+ }
+
+ /* set default power gating mask */
+ writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+ return 0;
+}
+
+static void hsw_free(struct sst_dsp *sst)
+{
+ sst_mem_block_unregister_all(sst);
+ iounmap(sst->addr.lpe);
+ iounmap(sst->addr.pci_cfg);
+}
+
+struct sst_ops haswell_ops = {
+ .reset = hsw_reset,
+ .boot = hsw_boot,
+ .write = sst_shim32_write,
+ .read = sst_shim32_read,
+ .write64 = sst_shim32_write64,
+ .read64 = sst_shim32_read64,
+ .ram_read = sst_memcpy_fromio_32,
+ .ram_write = sst_memcpy_toio_32,
+ .irq_handler = hsw_irq,
+ .init = hsw_init,
+ .free = hsw_free,
+ .parse_fw = hsw_parse_fw_image,
+};
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
new file mode 100644
index 000000000000..f46bb4ddde6f
--- /dev/null
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -0,0 +1,1785 @@
+/*
+ * Intel SST Haswell/Broadwell IPC Support
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 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/types.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/kthread.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+
+#include "sst-haswell-ipc.h"
+#include "sst-dsp.h"
+#include "sst-dsp-priv.h"
+
+/* Global Message - Generic */
+#define IPC_GLB_TYPE_SHIFT 24
+#define IPC_GLB_TYPE_MASK (0x1f << IPC_GLB_TYPE_SHIFT)
+#define IPC_GLB_TYPE(x) (x << IPC_GLB_TYPE_SHIFT)
+
+/* Global Message - Reply */
+#define IPC_GLB_REPLY_SHIFT 0
+#define IPC_GLB_REPLY_MASK (0x1f << IPC_GLB_REPLY_SHIFT)
+#define IPC_GLB_REPLY_TYPE(x) (x << IPC_GLB_REPLY_TYPE_SHIFT)
+
+/* Stream Message - Generic */
+#define IPC_STR_TYPE_SHIFT 20
+#define IPC_STR_TYPE_MASK (0xf << IPC_STR_TYPE_SHIFT)
+#define IPC_STR_TYPE(x) (x << IPC_STR_TYPE_SHIFT)
+#define IPC_STR_ID_SHIFT 16
+#define IPC_STR_ID_MASK (0xf << IPC_STR_ID_SHIFT)
+#define IPC_STR_ID(x) (x << IPC_STR_ID_SHIFT)
+
+/* Stream Message - Reply */
+#define IPC_STR_REPLY_SHIFT 0
+#define IPC_STR_REPLY_MASK (0x1f << IPC_STR_REPLY_SHIFT)
+
+/* Stream Stage Message - Generic */
+#define IPC_STG_TYPE_SHIFT 12
+#define IPC_STG_TYPE_MASK (0xf << IPC_STG_TYPE_SHIFT)
+#define IPC_STG_TYPE(x) (x << IPC_STG_TYPE_SHIFT)
+#define IPC_STG_ID_SHIFT 10
+#define IPC_STG_ID_MASK (0x3 << IPC_STG_ID_SHIFT)
+#define IPC_STG_ID(x) (x << IPC_STG_ID_SHIFT)
+
+/* Stream Stage Message - Reply */
+#define IPC_STG_REPLY_SHIFT 0
+#define IPC_STG_REPLY_MASK (0x1f << IPC_STG_REPLY_SHIFT)
+
+/* Debug Log Message - Generic */
+#define IPC_LOG_OP_SHIFT 20
+#define IPC_LOG_OP_MASK (0xf << IPC_LOG_OP_SHIFT)
+#define IPC_LOG_OP_TYPE(x) (x << IPC_LOG_OP_SHIFT)
+#define IPC_LOG_ID_SHIFT 16
+#define IPC_LOG_ID_MASK (0xf << IPC_LOG_ID_SHIFT)
+#define IPC_LOG_ID(x) (x << IPC_LOG_ID_SHIFT)
+
+/* IPC message timeout (msecs) */
+#define IPC_TIMEOUT_MSECS 300
+#define IPC_BOOT_MSECS 200
+#define IPC_MSG_WAIT 0
+#define IPC_MSG_NOWAIT 1
+
+/* Firmware Ready Message */
+#define IPC_FW_READY (0x1 << 29)
+#define IPC_STATUS_MASK (0x3 << 30)
+
+#define IPC_EMPTY_LIST_SIZE 8
+#define IPC_MAX_STREAMS 4
+
+/* Mailbox */
+#define IPC_MAX_MAILBOX_BYTES 256
+
+/* Global Message - Types and Replies */
+enum ipc_glb_type {
+ IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */
+ IPC_GLB_PERFORMANCE_MONITOR = 1, /* Performance monitoring actions */
+ IPC_GLB_ALLOCATE_STREAM = 3, /* Request to allocate new stream */
+ IPC_GLB_FREE_STREAM = 4, /* Request to free stream */
+ IPC_GLB_GET_FW_CAPABILITIES = 5, /* Retrieves firmware capabilities */
+ IPC_GLB_STREAM_MESSAGE = 6, /* Message directed to stream or its stages */
+ /* Request to store firmware context during D0->D3 transition */
+ IPC_GLB_REQUEST_DUMP = 7,
+ /* Request to restore firmware context during D3->D0 transition */
+ IPC_GLB_RESTORE_CONTEXT = 8,
+ IPC_GLB_GET_DEVICE_FORMATS = 9, /* Set device format */
+ IPC_GLB_SET_DEVICE_FORMATS = 10, /* Get device format */
+ IPC_GLB_SHORT_REPLY = 11,
+ IPC_GLB_ENTER_DX_STATE = 12,
+ IPC_GLB_GET_MIXER_STREAM_INFO = 13, /* Request mixer stream params */
+ IPC_GLB_DEBUG_LOG_MESSAGE = 14, /* Message to or from the debug logger. */
+ IPC_GLB_REQUEST_TRANSFER = 16, /* < Request Transfer for host */
+ IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17, /* Maximum message number */
+};
+
+enum ipc_glb_reply {
+ IPC_GLB_REPLY_SUCCESS = 0, /* The operation was successful. */
+ IPC_GLB_REPLY_ERROR_INVALID_PARAM = 1, /* Invalid parameter was passed. */
+ IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE = 2, /* Uknown message type was resceived. */
+ IPC_GLB_REPLY_OUT_OF_RESOURCES = 3, /* No resources to satisfy the request. */
+ IPC_GLB_REPLY_BUSY = 4, /* The system or resource is busy. */
+ IPC_GLB_REPLY_PENDING = 5, /* The action was scheduled for processing. */
+ IPC_GLB_REPLY_FAILURE = 6, /* Critical error happened. */
+ IPC_GLB_REPLY_INVALID_REQUEST = 7, /* Request can not be completed. */
+ IPC_GLB_REPLY_STAGE_UNINITIALIZED = 8, /* Processing stage was uninitialized. */
+ IPC_GLB_REPLY_NOT_FOUND = 9, /* Required resource can not be found. */
+ IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10, /* Source was not started. */
+};
+
+/* Stream Message - Types */
+enum ipc_str_operation {
+ IPC_STR_RESET = 0,
+ IPC_STR_PAUSE = 1,
+ IPC_STR_RESUME = 2,
+ IPC_STR_STAGE_MESSAGE = 3,
+ IPC_STR_NOTIFICATION = 4,
+ IPC_STR_MAX_MESSAGE
+};
+
+/* Stream Stage Message Types */
+enum ipc_stg_operation {
+ IPC_STG_GET_VOLUME = 0,
+ IPC_STG_SET_VOLUME,
+ IPC_STG_SET_WRITE_POSITION,
+ IPC_STG_SET_FX_ENABLE,
+ IPC_STG_SET_FX_DISABLE,
+ IPC_STG_SET_FX_GET_PARAM,
+ IPC_STG_SET_FX_SET_PARAM,
+ IPC_STG_SET_FX_GET_INFO,
+ IPC_STG_MUTE_LOOPBACK,
+ IPC_STG_MAX_MESSAGE
+};
+
+/* Stream Stage Message Types For Notification*/
+enum ipc_stg_operation_notify {
+ IPC_POSITION_CHANGED = 0,
+ IPC_STG_GLITCH,
+ IPC_STG_MAX_NOTIFY
+};
+
+enum ipc_glitch_type {
+ IPC_GLITCH_UNDERRUN = 1,
+ IPC_GLITCH_DECODER_ERROR,
+ IPC_GLITCH_DOUBLED_WRITE_POS,
+ IPC_GLITCH_MAX
+};
+
+/* Debug Control */
+enum ipc_debug_operation {
+ IPC_DEBUG_ENABLE_LOG = 0,
+ IPC_DEBUG_DISABLE_LOG = 1,
+ IPC_DEBUG_REQUEST_LOG_DUMP = 2,
+ IPC_DEBUG_NOTIFY_LOG_DUMP = 3,
+ IPC_DEBUG_MAX_DEBUG_LOG
+};
+
+/* Firmware Ready */
+struct sst_hsw_ipc_fw_ready {
+ u32 inbox_offset;
+ u32 outbox_offset;
+ u32 inbox_size;
+ u32 outbox_size;
+ u32 fw_info_size;
+ u8 fw_info[1];
+} __attribute__((packed));
+
+struct ipc_message {
+ struct list_head list;
+ u32 header;
+
+ /* direction wrt host CPU */
+ char tx_data[IPC_MAX_MAILBOX_BYTES];
+ size_t tx_size;
+ char rx_data[IPC_MAX_MAILBOX_BYTES];
+ size_t rx_size;
+
+ wait_queue_head_t waitq;
+ bool pending;
+ bool complete;
+ bool wait;
+ int errno;
+};
+
+struct sst_hsw_stream;
+struct sst_hsw;
+
+/* Stream infomation */
+struct sst_hsw_stream {
+ /* configuration */
+ struct sst_hsw_ipc_stream_alloc_req request;
+ struct sst_hsw_ipc_stream_alloc_reply reply;
+ struct sst_hsw_ipc_stream_free_req free_req;
+
+ /* Mixer info */
+ u32 mute_volume[SST_HSW_NO_CHANNELS];
+ u32 mute[SST_HSW_NO_CHANNELS];
+
+ /* runtime info */
+ struct sst_hsw *hsw;
+ int host_id;
+ bool commited;
+ bool running;
+
+ /* Notification work */
+ struct work_struct notify_work;
+ u32 header;
+
+ /* Position info from DSP */
+ struct sst_hsw_ipc_stream_set_position wpos;
+ struct sst_hsw_ipc_stream_get_position rpos;
+ struct sst_hsw_ipc_stream_glitch_position glitch;
+
+ /* Volume info */
+ struct sst_hsw_ipc_volume_req vol_req;
+
+ /* driver callback */
+ u32 (*notify_position)(struct sst_hsw_stream *stream, void *data);
+ void *pdata;
+
+ struct list_head node;
+};
+
+/* FW log ring information */
+struct sst_hsw_log_stream {
+ dma_addr_t dma_addr;
+ unsigned char *dma_area;
+ unsigned char *ring_descr;
+ int pages;
+ int size;
+
+ /* Notification work */
+ struct work_struct notify_work;
+ wait_queue_head_t readers_wait_q;
+ struct mutex rw_mutex;
+
+ u32 last_pos;
+ u32 curr_pos;
+ u32 reader_pos;
+
+ /* fw log config */
+ u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS];
+
+ struct sst_hsw *hsw;
+};
+
+/* SST Haswell IPC data */
+struct sst_hsw {
+ struct device *dev;
+ struct sst_dsp *dsp;
+ struct platform_device *pdev_pcm;
+
+ /* FW config */
+ struct sst_hsw_ipc_fw_ready fw_ready;
+ struct sst_hsw_ipc_fw_version version;
+ struct sst_module *scratch;
+ bool fw_done;
+
+ /* stream */
+ struct list_head stream_list;
+
+ /* global mixer */
+ struct sst_hsw_ipc_stream_info_reply mixer_info;
+ enum sst_hsw_volume_curve curve_type;
+ u32 curve_duration;
+ u32 mute[SST_HSW_NO_CHANNELS];
+ u32 mute_volume[SST_HSW_NO_CHANNELS];
+
+ /* DX */
+ struct sst_hsw_ipc_dx_reply dx;
+
+ /* boot */
+ wait_queue_head_t boot_wait;
+ bool boot_complete;
+ bool shutdown;
+
+ /* IPC messaging */
+ struct list_head tx_list;
+ struct list_head rx_list;
+ struct list_head empty_list;
+ wait_queue_head_t wait_txq;
+ struct task_struct *tx_thread;
+ struct kthread_worker kworker;
+ struct kthread_work kwork;
+ bool pending;
+ struct ipc_message *msg;
+
+ /* FW log stream */
+ struct sst_hsw_log_stream log_stream;
+};
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/hswadsp.h>
+
+static inline u32 msg_get_global_type(u32 msg)
+{
+ return (msg & IPC_GLB_TYPE_MASK) >> IPC_GLB_TYPE_SHIFT;
+}
+
+static inline u32 msg_get_global_reply(u32 msg)
+{
+ return (msg & IPC_GLB_REPLY_MASK) >> IPC_GLB_REPLY_SHIFT;
+}
+
+static inline u32 msg_get_stream_type(u32 msg)
+{
+ return (msg & IPC_STR_TYPE_MASK) >> IPC_STR_TYPE_SHIFT;
+}
+
+static inline u32 msg_get_stage_type(u32 msg)
+{
+ return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT;
+}
+
+static inline u32 msg_set_stage_type(u32 msg, u32 type)
+{
+ return (msg & ~IPC_STG_TYPE_MASK) +
+ (type << IPC_STG_TYPE_SHIFT);
+}
+
+static inline u32 msg_get_stream_id(u32 msg)
+{
+ return (msg & IPC_STR_ID_MASK) >> IPC_STR_ID_SHIFT;
+}
+
+static inline u32 msg_get_notify_reason(u32 msg)
+{
+ return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT;
+}
+
+u32 create_channel_map(enum sst_hsw_channel_config config)
+{
+ switch (config) {
+ case SST_HSW_CHANNEL_CONFIG_MONO:
+ return (0xFFFFFFF0 | SST_HSW_CHANNEL_CENTER);
+ case SST_HSW_CHANNEL_CONFIG_STEREO:
+ return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT
+ | (SST_HSW_CHANNEL_RIGHT << 4));
+ case SST_HSW_CHANNEL_CONFIG_2_POINT_1:
+ return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT
+ | (SST_HSW_CHANNEL_RIGHT << 4)
+ | (SST_HSW_CHANNEL_LFE << 8 ));
+ case SST_HSW_CHANNEL_CONFIG_3_POINT_0:
+ return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT
+ | (SST_HSW_CHANNEL_CENTER << 4)
+ | (SST_HSW_CHANNEL_RIGHT << 8));
+ case SST_HSW_CHANNEL_CONFIG_3_POINT_1:
+ return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
+ | (SST_HSW_CHANNEL_CENTER << 4)
+ | (SST_HSW_CHANNEL_RIGHT << 8)
+ | (SST_HSW_CHANNEL_LFE << 12));
+ case SST_HSW_CHANNEL_CONFIG_QUATRO:
+ return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
+ | (SST_HSW_CHANNEL_RIGHT << 4)
+ | (SST_HSW_CHANNEL_LEFT_SURROUND << 8)
+ | (SST_HSW_CHANNEL_RIGHT_SURROUND << 12));
+ case SST_HSW_CHANNEL_CONFIG_4_POINT_0:
+ return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
+ | (SST_HSW_CHANNEL_CENTER << 4)
+ | (SST_HSW_CHANNEL_RIGHT << 8)
+ | (SST_HSW_CHANNEL_CENTER_SURROUND << 12));
+ case SST_HSW_CHANNEL_CONFIG_5_POINT_0:
+ return (0xFFF00000 | SST_HSW_CHANNEL_LEFT
+ | (SST_HSW_CHANNEL_CENTER << 4)
+ | (SST_HSW_CHANNEL_RIGHT << 8)
+ | (SST_HSW_CHANNEL_LEFT_SURROUND << 12)
+ | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16));
+ case SST_HSW_CHANNEL_CONFIG_5_POINT_1:
+ return (0xFF000000 | SST_HSW_CHANNEL_CENTER
+ | (SST_HSW_CHANNEL_LEFT << 4)
+ | (SST_HSW_CHANNEL_RIGHT << 8)
+ | (SST_HSW_CHANNEL_LEFT_SURROUND << 12)
+ | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16)
+ | (SST_HSW_CHANNEL_LFE << 20));
+ case SST_HSW_CHANNEL_CONFIG_DUAL_MONO:
+ return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT
+ | (SST_HSW_CHANNEL_LEFT << 4));
+ default:
+ return 0xFFFFFFFF;
+ }
+}
+
+static struct sst_hsw_stream *get_stream_by_id(struct sst_hsw *hsw,
+ int stream_id)
+{
+ struct sst_hsw_stream *stream;
+
+ list_for_each_entry(stream, &hsw->stream_list, node) {
+ if (stream->reply.stream_hw_id == stream_id)
+ return stream;
+ }
+
+ return NULL;
+}
+
+static void ipc_shim_dbg(struct sst_hsw *hsw, const char *text)
+{
+ struct sst_dsp *sst = hsw->dsp;
+ u32 isr, ipcd, imrx, ipcx;
+
+ ipcx = sst_dsp_shim_read_unlocked(sst, SST_IPCX);
+ isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX);
+ ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
+ imrx = sst_dsp_shim_read_unlocked(sst, SST_IMRX);
+
+ dev_err(hsw->dev, "ipc: --%s-- ipcx 0x%8.8x isr 0x%8.8x ipcd 0x%8.8x imrx 0x%8.8x\n",
+ text, ipcx, isr, ipcd, imrx);
+}
+
+/* locks held by caller */
+static struct ipc_message *msg_get_empty(struct sst_hsw *hsw)
+{
+ struct ipc_message *msg = NULL;
+
+ if (!list_empty(&hsw->empty_list)) {
+ msg = list_first_entry(&hsw->empty_list, struct ipc_message,
+ list);
+ list_del(&msg->list);
+ }
+
+ return msg;
+}
+
+static void ipc_tx_msgs(struct kthread_work *work)
+{
+ struct sst_hsw *hsw =
+ container_of(work, struct sst_hsw, kwork);
+ struct ipc_message *msg;
+ unsigned long flags;
+ u32 ipcx;
+
+ spin_lock_irqsave(&hsw->dsp->spinlock, flags);
+
+ if (list_empty(&hsw->tx_list) || hsw->pending) {
+ spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
+ return;
+ }
+
+ /* if the DSP is busy we will TX messages after IRQ */
+ ipcx = sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX);
+ if (ipcx & SST_IPCX_BUSY) {
+ spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
+ return;
+ }
+
+ msg = list_first_entry(&hsw->tx_list, struct ipc_message, list);
+
+ list_move(&msg->list, &hsw->rx_list);
+
+ /* send the message */
+ sst_dsp_outbox_write(hsw->dsp, msg->tx_data, msg->tx_size);
+ sst_dsp_ipc_msg_tx(hsw->dsp, msg->header | SST_IPCX_BUSY);
+
+ spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
+}
+
+/* locks held by caller */
+static void tx_msg_reply_complete(struct sst_hsw *hsw, struct ipc_message *msg)
+{
+ msg->complete = true;
+ trace_ipc_reply("completed", msg->header);
+
+ if (!msg->wait)
+ list_add_tail(&msg->list, &hsw->empty_list);
+ else
+ wake_up(&msg->waitq);
+}
+
+static int tx_wait_done(struct sst_hsw *hsw, struct ipc_message *msg,
+ void *rx_data)
+{
+ unsigned long flags;
+ int ret;
+
+ /* wait for DSP completion (in all cases atm inc pending) */
+ ret = wait_event_timeout(msg->waitq, msg->complete,
+ msecs_to_jiffies(IPC_TIMEOUT_MSECS));
+
+ spin_lock_irqsave(&hsw->dsp->spinlock, flags);
+ if (ret == 0) {
+ ipc_shim_dbg(hsw, "message timeout");
+
+ trace_ipc_error("error message timeout for", msg->header);
+ ret = -ETIMEDOUT;
+ } else {
+
+ /* copy the data returned from DSP */
+ if (msg->rx_size)
+ memcpy(rx_data, msg->rx_data, msg->rx_size);
+ ret = msg->errno;
+ }
+
+ list_add_tail(&msg->list, &hsw->empty_list);
+ spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
+ return ret;
+}
+
+static int ipc_tx_message(struct sst_hsw *hsw, u32 header, void *tx_data,
+ size_t tx_bytes, void *rx_data, size_t rx_bytes, int wait)
+{
+ struct ipc_message *msg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hsw->dsp->spinlock, flags);
+
+ msg = msg_get_empty(hsw);
+ if (msg == NULL) {
+ spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
+ return -EBUSY;
+ }
+
+ if (tx_bytes)
+ memcpy(msg->tx_data, tx_data, tx_bytes);
+
+ msg->header = header;
+ msg->tx_size = tx_bytes;
+ msg->rx_size = rx_bytes;
+ msg->wait = wait;
+ msg->errno = 0;
+ msg->pending = false;
+ msg->complete = false;
+
+ list_add_tail(&msg->list, &hsw->tx_list);
+ spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
+
+ queue_kthread_work(&hsw->kworker, &hsw->kwork);
+
+ if (wait)
+ return tx_wait_done(hsw, msg, rx_data);
+ else
+ return 0;
+}
+
+static inline int ipc_tx_message_wait(struct sst_hsw *hsw, u32 header,
+ void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes)
+{
+ return ipc_tx_message(hsw, header, tx_data, tx_bytes, rx_data,
+ rx_bytes, 1);
+}
+
+static inline int ipc_tx_message_nowait(struct sst_hsw *hsw, u32 header,
+ void *tx_data, size_t tx_bytes)
+{
+ return ipc_tx_message(hsw, header, tx_data, tx_bytes, NULL, 0, 0);
+}
+
+static void hsw_fw_ready(struct sst_hsw *hsw, u32 header)
+{
+ struct sst_hsw_ipc_fw_ready fw_ready;
+ u32 offset;
+
+ offset = (header & 0x1FFFFFFF) << 3;
+
+ dev_dbg(hsw->dev, "ipc: DSP is ready 0x%8.8x offset %d\n",
+ header, offset);
+
+ /* copy data from the DSP FW ready offset */
+ sst_dsp_read(hsw->dsp, &fw_ready, offset, sizeof(fw_ready));
+
+ sst_dsp_mailbox_init(hsw->dsp, fw_ready.inbox_offset,
+ fw_ready.inbox_size, fw_ready.outbox_offset,
+ fw_ready.outbox_size);
+
+ hsw->boot_complete = true;
+ wake_up(&hsw->boot_wait);
+
+ dev_dbg(hsw->dev, " mailbox upstream 0x%x - size 0x%x\n",
+ fw_ready.inbox_offset, fw_ready.inbox_size);
+ dev_dbg(hsw->dev, " mailbox downstream 0x%x - size 0x%x\n",
+ fw_ready.outbox_offset, fw_ready.outbox_size);
+}
+
+static void hsw_notification_work(struct work_struct *work)
+{
+ struct sst_hsw_stream *stream = container_of(work,
+ struct sst_hsw_stream, notify_work);
+ struct sst_hsw_ipc_stream_glitch_position *glitch = &stream->glitch;
+ struct sst_hsw_ipc_stream_get_position *pos = &stream->rpos;
+ struct sst_hsw *hsw = stream->hsw;
+ u32 reason;
+
+ reason = msg_get_notify_reason(stream->header);
+
+ switch (reason) {
+ case IPC_STG_GLITCH:
+ trace_ipc_notification("DSP stream under/overrun",
+ stream->reply.stream_hw_id);
+ sst_dsp_inbox_read(hsw->dsp, glitch, sizeof(*glitch));
+
+ dev_err(hsw->dev, "glitch %d pos 0x%x write pos 0x%x\n",
+ glitch->glitch_type, glitch->present_pos,
+ glitch->write_pos);
+ break;
+
+ case IPC_POSITION_CHANGED:
+ trace_ipc_notification("DSP stream position changed for",
+ stream->reply.stream_hw_id);
+ sst_dsp_inbox_read(hsw->dsp, pos, sizeof(pos));
+
+ if (stream->notify_position)
+ stream->notify_position(stream, stream->pdata);
+
+ break;
+ default:
+ dev_err(hsw->dev, "error: unknown notification 0x%x\n",
+ stream->header);
+ break;
+ }
+
+ /* tell DSP that notification has been handled */
+ sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IPCD,
+ SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
+
+ /* unmask busy interrupt */
+ sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0);
+}
+
+static struct ipc_message *reply_find_msg(struct sst_hsw *hsw, u32 header)
+{
+ struct ipc_message *msg;
+
+ /* clear reply bits & status bits */
+ header &= ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK);
+
+ if (list_empty(&hsw->rx_list)) {
+ dev_err(hsw->dev, "error: rx list empty but received 0x%x\n",
+ header);
+ return NULL;
+ }
+
+ list_for_each_entry(msg, &hsw->rx_list, list) {
+ if (msg->header == header)
+ return msg;
+ }
+
+ return NULL;
+}
+
+static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg)
+{
+ struct sst_hsw_stream *stream;
+ u32 header = msg->header & ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK);
+ u32 stream_id = msg_get_stream_id(header);
+ u32 stream_msg = msg_get_stream_type(header);
+
+ stream = get_stream_by_id(hsw, stream_id);
+ if (stream == NULL)
+ return;
+
+ switch (stream_msg) {
+ case IPC_STR_STAGE_MESSAGE:
+ case IPC_STR_NOTIFICATION:
+ case IPC_STR_RESET:
+ break;
+ case IPC_STR_PAUSE:
+ stream->running = false;
+ trace_ipc_notification("stream paused",
+ stream->reply.stream_hw_id);
+ break;
+ case IPC_STR_RESUME:
+ stream->running = true;
+ trace_ipc_notification("stream running",
+ stream->reply.stream_hw_id);
+ break;
+ }
+}
+
+static int hsw_process_reply(struct sst_hsw *hsw, u32 header)
+{
+ struct ipc_message *msg;
+ u32 reply = msg_get_global_reply(header);
+
+ trace_ipc_reply("processing -->", header);
+
+ msg = reply_find_msg(hsw, header);
+ if (msg == NULL) {
+ trace_ipc_error("error: can't find message header", header);
+ return -EIO;
+ }
+
+ /* first process the header */
+ switch (reply) {
+ case IPC_GLB_REPLY_PENDING:
+ trace_ipc_pending_reply("received", header);
+ msg->pending = true;
+ hsw->pending = true;
+ return 1;
+ case IPC_GLB_REPLY_SUCCESS:
+ if (msg->pending) {
+ trace_ipc_pending_reply("completed", header);
+ sst_dsp_inbox_read(hsw->dsp, msg->rx_data,
+ msg->rx_size);
+ hsw->pending = false;
+ } else {
+ /* copy data from the DSP */
+ sst_dsp_outbox_read(hsw->dsp, msg->rx_data,
+ msg->rx_size);
+ }
+ break;
+ /* these will be rare - but useful for debug */
+ case IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE:
+ trace_ipc_error("error: unknown message type", header);
+ msg->errno = -EBADMSG;
+ break;
+ case IPC_GLB_REPLY_OUT_OF_RESOURCES:
+ trace_ipc_error("error: out of resources", header);
+ msg->errno = -ENOMEM;
+ break;
+ case IPC_GLB_REPLY_BUSY:
+ trace_ipc_error("error: reply busy", header);
+ msg->errno = -EBUSY;
+ break;
+ case IPC_GLB_REPLY_FAILURE:
+ trace_ipc_error("error: reply failure", header);
+ msg->errno = -EINVAL;
+ break;
+ case IPC_GLB_REPLY_STAGE_UNINITIALIZED:
+ trace_ipc_error("error: stage uninitialized", header);
+ msg->errno = -EINVAL;
+ break;
+ case IPC_GLB_REPLY_NOT_FOUND:
+ trace_ipc_error("error: reply not found", header);
+ msg->errno = -EINVAL;
+ break;
+ case IPC_GLB_REPLY_SOURCE_NOT_STARTED:
+ trace_ipc_error("error: source not started", header);
+ msg->errno = -EINVAL;
+ break;
+ case IPC_GLB_REPLY_INVALID_REQUEST:
+ trace_ipc_error("error: invalid request", header);
+ msg->errno = -EINVAL;
+ break;
+ case IPC_GLB_REPLY_ERROR_INVALID_PARAM:
+ trace_ipc_error("error: invalid parameter", header);
+ msg->errno = -EINVAL;
+ break;
+ default:
+ trace_ipc_error("error: unknown reply", header);
+ msg->errno = -EINVAL;
+ break;
+ }
+
+ /* update any stream states */
+ hsw_stream_update(hsw, msg);
+
+ /* wake up and return the error if we have waiters on this message ? */
+ list_del(&msg->list);
+ tx_msg_reply_complete(hsw, msg);
+
+ return 1;
+}
+
+static int hsw_stream_message(struct sst_hsw *hsw, u32 header)
+{
+ u32 stream_msg, stream_id, stage_type;
+ struct sst_hsw_stream *stream;
+ int handled = 0;
+
+ stream_msg = msg_get_stream_type(header);
+ stream_id = msg_get_stream_id(header);
+ stage_type = msg_get_stage_type(header);
+
+ stream = get_stream_by_id(hsw, stream_id);
+ if (stream == NULL)
+ return handled;
+
+ stream->header = header;
+
+ switch (stream_msg) {
+ case IPC_STR_STAGE_MESSAGE:
+ dev_err(hsw->dev, "error: stage msg not implemented 0x%8.8x\n",
+ header);
+ break;
+ case IPC_STR_NOTIFICATION:
+ schedule_work(&stream->notify_work);
+ break;
+ default:
+ /* handle pending message complete request */
+ handled = hsw_process_reply(hsw, header);
+ break;
+ }
+
+ return handled;
+}
+
+static int hsw_log_message(struct sst_hsw *hsw, u32 header)
+{
+ u32 operation = (header & IPC_LOG_OP_MASK) >> IPC_LOG_OP_SHIFT;
+ struct sst_hsw_log_stream *stream = &hsw->log_stream;
+ int ret = 1;
+
+ if (operation != IPC_DEBUG_REQUEST_LOG_DUMP) {
+ dev_err(hsw->dev,
+ "error: log msg not implemented 0x%8.8x\n", header);
+ return 0;
+ }
+
+ mutex_lock(&stream->rw_mutex);
+ stream->last_pos = stream->curr_pos;
+ sst_dsp_inbox_read(
+ hsw->dsp, &stream->curr_pos, sizeof(stream->curr_pos));
+ mutex_unlock(&stream->rw_mutex);
+
+ schedule_work(&stream->notify_work);
+
+ return ret;
+}
+
+static int hsw_process_notification(struct sst_hsw *hsw)
+{
+ struct sst_dsp *sst = hsw->dsp;
+ u32 type, header;
+ int handled = 1;
+
+ header = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
+ type = msg_get_global_type(header);
+
+ trace_ipc_request("processing -->", header);
+
+ /* FW Ready is a special case */
+ if (!hsw->boot_complete && header & IPC_FW_READY) {
+ hsw_fw_ready(hsw, header);
+ return handled;
+ }
+
+ switch (type) {
+ case IPC_GLB_GET_FW_VERSION:
+ case IPC_GLB_ALLOCATE_STREAM:
+ case IPC_GLB_FREE_STREAM:
+ case IPC_GLB_GET_FW_CAPABILITIES:
+ case IPC_GLB_REQUEST_DUMP:
+ case IPC_GLB_GET_DEVICE_FORMATS:
+ case IPC_GLB_SET_DEVICE_FORMATS:
+ case IPC_GLB_ENTER_DX_STATE:
+ case IPC_GLB_GET_MIXER_STREAM_INFO:
+ case IPC_GLB_MAX_IPC_MESSAGE_TYPE:
+ case IPC_GLB_RESTORE_CONTEXT:
+ case IPC_GLB_SHORT_REPLY:
+ dev_err(hsw->dev, "error: message type %d header 0x%x\n",
+ type, header);
+ break;
+ case IPC_GLB_STREAM_MESSAGE:
+ handled = hsw_stream_message(hsw, header);
+ break;
+ case IPC_GLB_DEBUG_LOG_MESSAGE:
+ handled = hsw_log_message(hsw, header);
+ break;
+ default:
+ dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n",
+ type, header);
+ break;
+ }
+
+ return handled;
+}
+
+static irqreturn_t hsw_irq_thread(int irq, void *context)
+{
+ struct sst_dsp *sst = (struct sst_dsp *) context;
+ struct sst_hsw *hsw = sst_dsp_get_thread_context(sst);
+ u32 ipcx, ipcd;
+ int handled;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sst->spinlock, flags);
+
+ ipcx = sst_dsp_ipc_msg_rx(hsw->dsp);
+ ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
+
+ /* reply message from DSP */
+ if (ipcx & SST_IPCX_DONE) {
+
+ /* Handle Immediate reply from DSP Core */
+ handled = hsw_process_reply(hsw, ipcx);
+
+ if (handled > 0) {
+ /* clear DONE bit - tell DSP we have completed */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX,
+ SST_IPCX_DONE, 0);
+
+ /* unmask Done interrupt */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+ SST_IMRX_DONE, 0);
+ }
+ }
+
+ /* new message from DSP */
+ if (ipcd & SST_IPCD_BUSY) {
+
+ /* Handle Notification and Delayed reply from DSP Core */
+ handled = hsw_process_notification(hsw);
+
+ /* clear BUSY bit and set DONE bit - accept new messages */
+ if (handled > 0) {
+ sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD,
+ SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
+
+ /* unmask busy interrupt */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
+ SST_IMRX_BUSY, 0);
+ }
+ }
+
+ spin_unlock_irqrestore(&sst->spinlock, flags);
+
+ /* continue to send any remaining messages... */
+ queue_kthread_work(&hsw->kworker, &hsw->kwork);
+
+ return IRQ_HANDLED;
+}
+
+int sst_hsw_fw_get_version(struct sst_hsw *hsw,
+ struct sst_hsw_ipc_fw_version *version)
+{
+ int ret;
+
+ ret = ipc_tx_message_wait(hsw, IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION),
+ NULL, 0, version, sizeof(*version));
+ if (ret < 0)
+ dev_err(hsw->dev, "error: get version failed\n");
+
+ return ret;
+}
+
+/* Mixer Controls */
+int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ u32 stage_id, u32 channel)
+{
+ int ret;
+
+ ret = sst_hsw_stream_get_volume(hsw, stream, stage_id, channel,
+ &stream->mute_volume[channel]);
+ if (ret < 0)
+ return ret;
+
+ ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, 0);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n",
+ stream->reply.stream_hw_id, channel);
+ return ret;
+ }
+
+ stream->mute[channel] = 1;
+ return 0;
+}
+
+int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ u32 stage_id, u32 channel)
+
+{
+ int ret;
+
+ stream->mute[channel] = 0;
+ ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel,
+ stream->mute_volume[channel]);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n",
+ stream->reply.stream_hw_id, channel);
+ return ret;
+ }
+
+ return 0;
+}
+
+int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ u32 stage_id, u32 channel, u32 *volume)
+{
+ if (channel > 1)
+ return -EINVAL;
+
+ sst_dsp_read(hsw->dsp, volume,
+ stream->reply.volume_register_address[channel], sizeof(volume));
+
+ return 0;
+}
+
+int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u64 curve_duration,
+ enum sst_hsw_volume_curve curve)
+{
+ /* curve duration in steps of 100ns */
+ stream->vol_req.curve_duration = curve_duration;
+ stream->vol_req.curve_type = curve;
+
+ return 0;
+}
+
+/* stream volume */
+int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume)
+{
+ struct sst_hsw_ipc_volume_req *req;
+ u32 header;
+ int ret;
+
+ trace_ipc_request("set stream volume", stream->reply.stream_hw_id);
+
+ if (channel > 1)
+ return -EINVAL;
+
+ if (stream->mute[channel]) {
+ stream->mute_volume[channel] = volume;
+ return 0;
+ }
+
+ header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
+ IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
+ header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT);
+ header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT);
+ header |= (stage_id << IPC_STG_ID_SHIFT);
+
+ req = &stream->vol_req;
+ req->channel = channel;
+ req->target_volume = volume;
+
+ ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: set stream volume failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel)
+{
+ int ret;
+
+ ret = sst_hsw_mixer_get_volume(hsw, stage_id, channel,
+ &hsw->mute_volume[channel]);
+ if (ret < 0)
+ return ret;
+
+ ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, 0);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n",
+ channel);
+ return ret;
+ }
+
+ hsw->mute[channel] = 1;
+ return 0;
+}
+
+int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel)
+{
+ int ret;
+
+ ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel,
+ hsw->mixer_info.volume_register_address[channel]);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n",
+ channel);
+ return ret;
+ }
+
+ hsw->mute[channel] = 0;
+ return 0;
+}
+
+int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
+ u32 *volume)
+{
+ if (channel > 1)
+ return -EINVAL;
+
+ sst_dsp_read(hsw->dsp, volume,
+ hsw->mixer_info.volume_register_address[channel],
+ sizeof(*volume));
+
+ return 0;
+}
+
+int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw,
+ u64 curve_duration, enum sst_hsw_volume_curve curve)
+{
+ /* curve duration in steps of 100ns */
+ hsw->curve_duration = curve_duration;
+ hsw->curve_type = curve;
+
+ return 0;
+}
+
+/* global mixer volume */
+int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
+ u32 volume)
+{
+ struct sst_hsw_ipc_volume_req req;
+ u32 header;
+ int ret;
+
+ trace_ipc_request("set mixer volume", volume);
+
+ /* set both at same time ? */
+ if (channel == 2) {
+ if (hsw->mute[0] && hsw->mute[1]) {
+ hsw->mute_volume[0] = hsw->mute_volume[1] = volume;
+ return 0;
+ } else if (hsw->mute[0])
+ req.channel = 1;
+ else if (hsw->mute[1])
+ req.channel = 0;
+ else
+ req.channel = 0xffffffff;
+ } else {
+ /* set only 1 channel */
+ if (hsw->mute[channel]) {
+ hsw->mute_volume[channel] = volume;
+ return 0;
+ }
+ req.channel = channel;
+ }
+
+ header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
+ IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
+ header |= (hsw->mixer_info.mixer_hw_id << IPC_STR_ID_SHIFT);
+ header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT);
+ header |= (stage_id << IPC_STG_ID_SHIFT);
+
+ req.curve_duration = hsw->curve_duration;
+ req.curve_type = hsw->curve_type;
+ req.target_volume = volume;
+
+ ret = ipc_tx_message_wait(hsw, header, &req, sizeof(req), NULL, 0);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: set mixer volume failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Stream API */
+struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
+ u32 (*notify_position)(struct sst_hsw_stream *stream, void *data),
+ void *data)
+{
+ struct sst_hsw_stream *stream;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (stream == NULL)
+ return NULL;
+
+ list_add(&stream->node, &hsw->stream_list);
+ stream->notify_position = notify_position;
+ stream->pdata = data;
+ stream->hsw = hsw;
+ stream->host_id = id;
+
+ /* work to process notification messages */
+ INIT_WORK(&stream->notify_work, hsw_notification_work);
+
+ return stream;
+}
+
+int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
+{
+ u32 header;
+ int ret = 0;
+
+ /* dont free DSP streams that are not commited */
+ if (!stream->commited)
+ goto out;
+
+ trace_ipc_request("stream free", stream->host_id);
+
+ stream->free_req.stream_id = stream->reply.stream_hw_id;
+ header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM);
+
+ ret = ipc_tx_message_wait(hsw, header, &stream->free_req,
+ sizeof(stream->free_req), NULL, 0);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: free stream %d failed\n",
+ stream->free_req.stream_id);
+ return -EAGAIN;
+ }
+
+ trace_hsw_stream_free_req(stream, &stream->free_req);
+
+out:
+ list_del(&stream->node);
+ kfree(stream);
+
+ return ret;
+}
+
+int sst_hsw_stream_set_bits(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, enum sst_hsw_bitdepth bits)
+{
+ if (stream->commited) {
+ dev_err(hsw->dev, "error: stream committed for set bits\n");
+ return -EINVAL;
+ }
+
+ stream->request.format.bitdepth = bits;
+ return 0;
+}
+
+int sst_hsw_stream_set_channels(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, int channels)
+{
+ if (stream->commited) {
+ dev_err(hsw->dev, "error: stream committed for set channels\n");
+ return -EINVAL;
+ }
+
+ /* stereo is only supported atm */
+ if (channels != 2)
+ return -EINVAL;
+
+ stream->request.format.ch_num = channels;
+ return 0;
+}
+
+int sst_hsw_stream_set_rate(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, int rate)
+{
+ if (stream->commited) {
+ dev_err(hsw->dev, "error: stream committed for set rate\n");
+ return -EINVAL;
+ }
+
+ stream->request.format.frequency = rate;
+ return 0;
+}
+
+int sst_hsw_stream_set_map_config(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 map,
+ enum sst_hsw_channel_config config)
+{
+ if (stream->commited) {
+ dev_err(hsw->dev, "error: stream committed for set map\n");
+ return -EINVAL;
+ }
+
+ stream->request.format.map = map;
+ stream->request.format.config = config;
+ return 0;
+}
+
+int sst_hsw_stream_set_style(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, enum sst_hsw_interleaving style)
+{
+ if (stream->commited) {
+ dev_err(hsw->dev, "error: stream committed for set style\n");
+ return -EINVAL;
+ }
+
+ stream->request.format.style = style;
+ return 0;
+}
+
+int sst_hsw_stream_set_valid(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 bits)
+{
+ if (stream->commited) {
+ dev_err(hsw->dev, "error: stream committed for set valid bits\n");
+ return -EINVAL;
+ }
+
+ stream->request.format.valid_bit = bits;
+ return 0;
+}
+
+/* Stream Configuration */
+int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ enum sst_hsw_stream_path_id path_id,
+ enum sst_hsw_stream_type stream_type,
+ enum sst_hsw_stream_format format_id)
+{
+ if (stream->commited) {
+ dev_err(hsw->dev, "error: stream committed for set format\n");
+ return -EINVAL;
+ }
+
+ stream->request.path_id = path_id;
+ stream->request.stream_type = stream_type;
+ stream->request.format_id = format_id;
+
+ trace_hsw_stream_alloc_request(stream, &stream->request);
+
+ return 0;
+}
+
+int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ u32 ring_pt_address, u32 num_pages,
+ u32 ring_size, u32 ring_offset, u32 ring_first_pfn)
+{
+ if (stream->commited) {
+ dev_err(hsw->dev, "error: stream committed for buffer\n");
+ return -EINVAL;
+ }
+
+ stream->request.ringinfo.ring_pt_address = ring_pt_address;
+ stream->request.ringinfo.num_pages = num_pages;
+ stream->request.ringinfo.ring_size = ring_size;
+ stream->request.ringinfo.ring_offset = ring_offset;
+ stream->request.ringinfo.ring_first_pfn = ring_first_pfn;
+
+ trace_hsw_stream_buffer(stream);
+
+ return 0;
+}
+
+int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id,
+ u32 entry_point)
+{
+ struct sst_hsw_module_map *map = &stream->request.map;
+
+ if (stream->commited) {
+ dev_err(hsw->dev, "error: stream committed for set module\n");
+ return -EINVAL;
+ }
+
+ /* only support initial module atm */
+ map->module_entries_count = 1;
+ map->module_entries[0].module_id = module_id;
+ map->module_entries[0].entry_point = entry_point;
+
+ return 0;
+}
+
+int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 offset, u32 size)
+{
+ if (stream->commited) {
+ dev_err(hsw->dev, "error: stream committed for set pmem\n");
+ return -EINVAL;
+ }
+
+ stream->request.persistent_mem.offset = offset;
+ stream->request.persistent_mem.size = size;
+
+ return 0;
+}
+
+int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 offset, u32 size)
+{
+ if (stream->commited) {
+ dev_err(hsw->dev, "error: stream committed for set smem\n");
+ return -EINVAL;
+ }
+
+ stream->request.scratch_mem.offset = offset;
+ stream->request.scratch_mem.size = size;
+
+ return 0;
+}
+
+int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
+{
+ struct sst_hsw_ipc_stream_alloc_req *str_req = &stream->request;
+ struct sst_hsw_ipc_stream_alloc_reply *reply = &stream->reply;
+ u32 header;
+ int ret;
+
+ trace_ipc_request("stream alloc", stream->host_id);
+
+ header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM);
+
+ ret = ipc_tx_message_wait(hsw, header, str_req, sizeof(*str_req),
+ reply, sizeof(*reply));
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: stream commit failed\n");
+ return ret;
+ }
+
+ stream->commited = 1;
+ trace_hsw_stream_alloc_reply(stream);
+
+ return 0;
+}
+
+/* Stream Information - these calls could be inline but we want the IPC
+ ABI to be opaque to client PCM drivers to cope with any future ABI changes */
+int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream)
+{
+ return stream->reply.stream_hw_id;
+}
+
+int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream)
+{
+ return stream->reply.mixer_hw_id;
+}
+
+u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream)
+{
+ return stream->reply.read_position_register_address;
+}
+
+u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream)
+{
+ return stream->reply.presentation_position_register_address;
+}
+
+u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 channel)
+{
+ if (channel >= 2)
+ return 0;
+
+ return stream->reply.peak_meter_register_address[channel];
+}
+
+u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 channel)
+{
+ if (channel >= 2)
+ return 0;
+
+ return stream->reply.volume_register_address[channel];
+}
+
+int sst_hsw_mixer_get_info(struct sst_hsw *hsw)
+{
+ struct sst_hsw_ipc_stream_info_reply *reply;
+ u32 header;
+ int ret;
+
+ reply = &hsw->mixer_info;
+ header = IPC_GLB_TYPE(IPC_GLB_GET_MIXER_STREAM_INFO);
+
+ trace_ipc_request("get global mixer info", 0);
+
+ ret = ipc_tx_message_wait(hsw, header, NULL, 0, reply, sizeof(*reply));
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: get stream info failed\n");
+ return ret;
+ }
+
+ trace_hsw_mixer_info_reply(reply);
+
+ return 0;
+}
+
+/* Send stream command */
+static int sst_hsw_stream_operations(struct sst_hsw *hsw, int type,
+ int stream_id, int wait)
+{
+ u32 header;
+
+ header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | IPC_STR_TYPE(type);
+ header |= (stream_id << IPC_STR_ID_SHIFT);
+
+ if (wait)
+ return ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0);
+ else
+ return ipc_tx_message_nowait(hsw, header, NULL, 0);
+}
+
+/* Stream ALSA trigger operations */
+int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ int wait)
+{
+ int ret;
+
+ trace_ipc_request("stream pause", stream->reply.stream_hw_id);
+
+ ret = sst_hsw_stream_operations(hsw, IPC_STR_PAUSE,
+ stream->reply.stream_hw_id, wait);
+ if (ret < 0)
+ dev_err(hsw->dev, "error: failed to pause stream %d\n",
+ stream->reply.stream_hw_id);
+
+ return ret;
+}
+
+int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ int wait)
+{
+ int ret;
+
+ trace_ipc_request("stream resume", stream->reply.stream_hw_id);
+
+ ret = sst_hsw_stream_operations(hsw, IPC_STR_RESUME,
+ stream->reply.stream_hw_id, wait);
+ if (ret < 0)
+ dev_err(hsw->dev, "error: failed to resume stream %d\n",
+ stream->reply.stream_hw_id);
+
+ return ret;
+}
+
+int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
+{
+ int ret, tries = 10;
+
+ /* dont reset streams that are not commited */
+ if (!stream->commited)
+ return 0;
+
+ /* wait for pause to complete before we reset the stream */
+ while (stream->running && tries--)
+ msleep(1);
+ if (!tries) {
+ dev_err(hsw->dev, "error: reset stream %d still running\n",
+ stream->reply.stream_hw_id);
+ return -EINVAL;
+ }
+
+ trace_ipc_request("stream reset", stream->reply.stream_hw_id);
+
+ ret = sst_hsw_stream_operations(hsw, IPC_STR_RESET,
+ stream->reply.stream_hw_id, 1);
+ if (ret < 0)
+ dev_err(hsw->dev, "error: failed to reset stream %d\n",
+ stream->reply.stream_hw_id);
+ return ret;
+}
+
+/* Stream pointer positions */
+int sst_hsw_get_dsp_position(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream)
+{
+ return stream->rpos.position;
+}
+
+int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 stage_id, u32 position)
+{
+ u32 header;
+ int ret;
+
+ trace_stream_write_position(stream->reply.stream_hw_id, position);
+
+ header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
+ IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
+ header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT);
+ header |= (IPC_STG_SET_WRITE_POSITION << IPC_STG_TYPE_SHIFT);
+ header |= (stage_id << IPC_STG_ID_SHIFT);
+ stream->wpos.position = position;
+
+ ret = ipc_tx_message_nowait(hsw, header, &stream->wpos,
+ sizeof(stream->wpos));
+ if (ret < 0)
+ dev_err(hsw->dev, "error: stream %d set position %d failed\n",
+ stream->reply.stream_hw_id, position);
+
+ return ret;
+}
+
+/* physical BE config */
+int sst_hsw_device_set_config(struct sst_hsw *hsw,
+ enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk,
+ enum sst_hsw_device_mode mode, u32 clock_divider)
+{
+ struct sst_hsw_ipc_device_config_req config;
+ u32 header;
+ int ret;
+
+ trace_ipc_request("set device config", dev);
+
+ config.ssp_interface = dev;
+ config.clock_frequency = mclk;
+ config.mode = mode;
+ config.clock_divider = clock_divider;
+
+ trace_hsw_device_config_req(&config);
+
+ header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS);
+
+ ret = ipc_tx_message_wait(hsw, header, &config, sizeof(config),
+ NULL, 0);
+ if (ret < 0)
+ dev_err(hsw->dev, "error: set device formats failed\n");
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sst_hsw_device_set_config);
+
+/* DX Config */
+int sst_hsw_dx_set_state(struct sst_hsw *hsw,
+ enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx)
+{
+ u32 header, state_;
+ int ret;
+
+ header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE);
+ state_ = state;
+
+ trace_ipc_request("PM enter Dx state", state);
+
+ ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_),
+ dx, sizeof(dx));
+ if (ret < 0) {
+ dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state);
+ return ret;
+ }
+
+ dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n",
+ dx->entries_no, state);
+
+ memcpy(&hsw->dx, dx, sizeof(*dx));
+ return 0;
+}
+
+/* Used to save state into hsw->dx_reply */
+int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item,
+ u32 *offset, u32 *size, u32 *source)
+{
+ struct sst_hsw_ipc_dx_memory_item *dx_mem;
+ struct sst_hsw_ipc_dx_reply *dx_reply;
+ int entry_no;
+
+ dx_reply = &hsw->dx;
+ entry_no = dx_reply->entries_no;
+
+ trace_ipc_request("PM get Dx state", entry_no);
+
+ if (item >= entry_no)
+ return -EINVAL;
+
+ dx_mem = &dx_reply->mem_info[item];
+ *offset = dx_mem->offset;
+ *size = dx_mem->size;
+ *source = dx_mem->source;
+
+ return 0;
+}
+
+static int msg_empty_list_init(struct sst_hsw *hsw)
+{
+ int i;
+
+ hsw->msg = kzalloc(sizeof(struct ipc_message) *
+ IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
+ if (hsw->msg == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
+ init_waitqueue_head(&hsw->msg[i].waitq);
+ list_add(&hsw->msg[i].list, &hsw->empty_list);
+ }
+
+ return 0;
+}
+
+void sst_hsw_set_scratch_module(struct sst_hsw *hsw,
+ struct sst_module *scratch)
+{
+ hsw->scratch = scratch;
+}
+
+struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw)
+{
+ return hsw->dsp;
+}
+
+static struct sst_dsp_device hsw_dev = {
+ .thread = hsw_irq_thread,
+ .ops = &haswell_ops,
+};
+
+int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
+{
+ struct sst_hsw_ipc_fw_version version;
+ struct sst_hsw *hsw;
+ struct sst_fw *hsw_sst_fw;
+ int ret;
+
+ dev_dbg(dev, "initialising Audio DSP IPC\n");
+
+ hsw = devm_kzalloc(dev, sizeof(*hsw), GFP_KERNEL);
+ if (hsw == NULL)
+ return -ENOMEM;
+
+ hsw->dev = dev;
+ INIT_LIST_HEAD(&hsw->stream_list);
+ INIT_LIST_HEAD(&hsw->tx_list);
+ INIT_LIST_HEAD(&hsw->rx_list);
+ INIT_LIST_HEAD(&hsw->empty_list);
+ init_waitqueue_head(&hsw->boot_wait);
+ init_waitqueue_head(&hsw->wait_txq);
+
+ ret = msg_empty_list_init(hsw);
+ if (ret < 0)
+ goto list_err;
+
+ /* start the IPC message thread */
+ init_kthread_worker(&hsw->kworker);
+ hsw->tx_thread = kthread_run(kthread_worker_fn,
+ &hsw->kworker,
+ dev_name(hsw->dev));
+ if (IS_ERR(hsw->tx_thread)) {
+ ret = PTR_ERR(hsw->tx_thread);
+ dev_err(hsw->dev, "error: failed to create message TX task\n");
+ goto list_err;
+ }
+ init_kthread_work(&hsw->kwork, ipc_tx_msgs);
+
+ hsw_dev.thread_context = hsw;
+
+ /* init SST shim */
+ hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata);
+ if (hsw->dsp == NULL) {
+ ret = -ENODEV;
+ goto list_err;
+ }
+
+ /* keep the DSP in reset state for base FW loading */
+ sst_dsp_reset(hsw->dsp);
+
+ hsw_sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw);
+
+ if (hsw_sst_fw == NULL) {
+ ret = -ENODEV;
+ dev_err(dev, "error: failed to load firmware\n");
+ goto fw_err;
+ }
+
+ /* wait for DSP boot completion */
+ sst_dsp_boot(hsw->dsp);
+ ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
+ msecs_to_jiffies(IPC_BOOT_MSECS));
+ if (ret == 0) {
+ ret = -EIO;
+ dev_err(hsw->dev, "error: ADSP boot timeout\n");
+ goto boot_err;
+ }
+
+ /* get the FW version */
+ sst_hsw_fw_get_version(hsw, &version);
+ dev_info(hsw->dev, "FW loaded: type %d - version: %d.%d build %d\n",
+ version.type, version.major, version.minor, version.build);
+
+ /* get the globalmixer */
+ ret = sst_hsw_mixer_get_info(hsw);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: failed to get stream info\n");
+ goto boot_err;
+ }
+
+ pdata->dsp = hsw;
+ return 0;
+
+boot_err:
+ sst_dsp_reset(hsw->dsp);
+ sst_fw_free(hsw_sst_fw);
+fw_err:
+ sst_dsp_free(hsw->dsp);
+ kfree(hsw->msg);
+list_err:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sst_hsw_dsp_init);
+
+void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata)
+{
+ struct sst_hsw *hsw = pdata->dsp;
+
+ sst_dsp_reset(hsw->dsp);
+ sst_fw_free_all(hsw->dsp);
+ sst_dsp_free(hsw->dsp);
+ kfree(hsw->scratch);
+ kfree(hsw->msg);
+}
+EXPORT_SYMBOL_GPL(sst_hsw_dsp_free);
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
new file mode 100644
index 000000000000..d517929ccc38
--- /dev/null
+++ b/sound/soc/intel/sst-haswell-ipc.h
@@ -0,0 +1,488 @@
+/*
+ * Intel SST Haswell/Broadwell IPC Support
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SST_HASWELL_IPC_H
+#define __SST_HASWELL_IPC_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#define SST_HSW_NO_CHANNELS 2
+#define SST_HSW_MAX_DX_REGIONS 14
+
+#define SST_HSW_FW_LOG_CONFIG_DWORDS 12
+#define SST_HSW_GLOBAL_LOG 15
+
+/**
+ * Upfront defined maximum message size that is
+ * expected by the in/out communication pipes in FW.
+ */
+#define SST_HSW_IPC_MAX_PAYLOAD_SIZE 400
+#define SST_HSW_MAX_INFO_SIZE 64
+#define SST_HSW_BUILD_HASH_LENGTH 40
+
+struct sst_hsw;
+struct sst_hsw_stream;
+struct sst_hsw_log_stream;
+struct sst_pdata;
+struct sst_module;
+extern struct sst_ops haswell_ops;
+
+/* Stream Allocate Path ID */
+enum sst_hsw_stream_path_id {
+ SST_HSW_STREAM_PATH_SSP0_OUT = 0,
+ SST_HSW_STREAM_PATH_SSP0_IN = 1,
+ SST_HSW_STREAM_PATH_MAX_PATH_ID = 2,
+};
+
+/* Stream Allocate Stream Type */
+enum sst_hsw_stream_type {
+ SST_HSW_STREAM_TYPE_RENDER = 0,
+ SST_HSW_STREAM_TYPE_SYSTEM = 1,
+ SST_HSW_STREAM_TYPE_CAPTURE = 2,
+ SST_HSW_STREAM_TYPE_LOOPBACK = 3,
+ SST_HSW_STREAM_TYPE_MAX_STREAM_TYPE = 4,
+};
+
+/* Stream Allocate Stream Format */
+enum sst_hsw_stream_format {
+ SST_HSW_STREAM_FORMAT_PCM_FORMAT = 0,
+ SST_HSW_STREAM_FORMAT_MP3_FORMAT = 1,
+ SST_HSW_STREAM_FORMAT_AAC_FORMAT = 2,
+ SST_HSW_STREAM_FORMAT_MAX_FORMAT_ID = 3,
+};
+
+/* Device ID */
+enum sst_hsw_device_id {
+ SST_HSW_DEVICE_SSP_0 = 0,
+ SST_HSW_DEVICE_SSP_1 = 1,
+};
+
+/* Device Master Clock Frequency */
+enum sst_hsw_device_mclk {
+ SST_HSW_DEVICE_MCLK_OFF = 0,
+ SST_HSW_DEVICE_MCLK_FREQ_6_MHZ = 1,
+ SST_HSW_DEVICE_MCLK_FREQ_12_MHZ = 2,
+ SST_HSW_DEVICE_MCLK_FREQ_24_MHZ = 3,
+};
+
+/* Device Clock Master */
+enum sst_hsw_device_mode {
+ SST_HSW_DEVICE_CLOCK_SLAVE = 0,
+ SST_HSW_DEVICE_CLOCK_MASTER = 1,
+};
+
+/* DX Power State */
+enum sst_hsw_dx_state {
+ SST_HSW_DX_STATE_D0 = 0,
+ SST_HSW_DX_STATE_D1 = 1,
+ SST_HSW_DX_STATE_D3 = 3,
+ SST_HSW_DX_STATE_MAX = 3,
+};
+
+/* Audio stream stage IDs */
+enum sst_hsw_fx_stage_id {
+ SST_HSW_STAGE_ID_WAVES = 0,
+ SST_HSW_STAGE_ID_DTS = 1,
+ SST_HSW_STAGE_ID_DOLBY = 2,
+ SST_HSW_STAGE_ID_BOOST = 3,
+ SST_HSW_STAGE_ID_MAX_FX_ID
+};
+
+/* DX State Type */
+enum sst_hsw_dx_type {
+ SST_HSW_DX_TYPE_FW_IMAGE = 0,
+ SST_HSW_DX_TYPE_MEMORY_DUMP = 1
+};
+
+/* Volume Curve Type*/
+enum sst_hsw_volume_curve {
+ SST_HSW_VOLUME_CURVE_NONE = 0,
+ SST_HSW_VOLUME_CURVE_FADE = 1
+};
+
+/* Sample ordering */
+enum sst_hsw_interleaving {
+ SST_HSW_INTERLEAVING_PER_CHANNEL = 0,
+ SST_HSW_INTERLEAVING_PER_SAMPLE = 1,
+};
+
+/* Channel indices */
+enum sst_hsw_channel_index {
+ SST_HSW_CHANNEL_LEFT = 0,
+ SST_HSW_CHANNEL_CENTER = 1,
+ SST_HSW_CHANNEL_RIGHT = 2,
+ SST_HSW_CHANNEL_LEFT_SURROUND = 3,
+ SST_HSW_CHANNEL_CENTER_SURROUND = 3,
+ SST_HSW_CHANNEL_RIGHT_SURROUND = 4,
+ SST_HSW_CHANNEL_LFE = 7,
+ SST_HSW_CHANNEL_INVALID = 0xF,
+};
+
+/* List of supported channel maps. */
+enum sst_hsw_channel_config {
+ SST_HSW_CHANNEL_CONFIG_MONO = 0, /* mono only. */
+ SST_HSW_CHANNEL_CONFIG_STEREO = 1, /* L & R. */
+ SST_HSW_CHANNEL_CONFIG_2_POINT_1 = 2, /* L, R & LFE; PCM only. */
+ SST_HSW_CHANNEL_CONFIG_3_POINT_0 = 3, /* L, C & R; MP3 & AAC only. */
+ SST_HSW_CHANNEL_CONFIG_3_POINT_1 = 4, /* L, C, R & LFE; PCM only. */
+ SST_HSW_CHANNEL_CONFIG_QUATRO = 5, /* L, R, Ls & Rs; PCM only. */
+ SST_HSW_CHANNEL_CONFIG_4_POINT_0 = 6, /* L, C, R & Cs; MP3 & AAC only. */
+ SST_HSW_CHANNEL_CONFIG_5_POINT_0 = 7, /* L, C, R, Ls & Rs. */
+ SST_HSW_CHANNEL_CONFIG_5_POINT_1 = 8, /* L, C, R, Ls, Rs & LFE. */
+ SST_HSW_CHANNEL_CONFIG_DUAL_MONO = 9, /* One channel replicated in two. */
+ SST_HSW_CHANNEL_CONFIG_INVALID,
+};
+
+/* List of supported bit depths. */
+enum sst_hsw_bitdepth {
+ SST_HSW_DEPTH_8BIT = 8,
+ SST_HSW_DEPTH_16BIT = 16,
+ SST_HSW_DEPTH_24BIT = 24, /* Default. */
+ SST_HSW_DEPTH_32BIT = 32,
+ SST_HSW_DEPTH_INVALID = 33,
+};
+
+enum sst_hsw_module_id {
+ SST_HSW_MODULE_BASE_FW = 0x0,
+ SST_HSW_MODULE_MP3 = 0x1,
+ SST_HSW_MODULE_AAC_5_1 = 0x2,
+ SST_HSW_MODULE_AAC_2_0 = 0x3,
+ SST_HSW_MODULE_SRC = 0x4,
+ SST_HSW_MODULE_WAVES = 0x5,
+ SST_HSW_MODULE_DOLBY = 0x6,
+ SST_HSW_MODULE_BOOST = 0x7,
+ SST_HSW_MODULE_LPAL = 0x8,
+ SST_HSW_MODULE_DTS = 0x9,
+ SST_HSW_MODULE_PCM_CAPTURE = 0xA,
+ SST_HSW_MODULE_PCM_SYSTEM = 0xB,
+ SST_HSW_MODULE_PCM_REFERENCE = 0xC,
+ SST_HSW_MODULE_PCM = 0xD,
+ SST_HSW_MODULE_BLUETOOTH_RENDER_MODULE = 0xE,
+ SST_HSW_MODULE_BLUETOOTH_CAPTURE_MODULE = 0xF,
+ SST_HSW_MAX_MODULE_ID,
+};
+
+enum sst_hsw_performance_action {
+ SST_HSW_PERF_START = 0,
+ SST_HSW_PERF_STOP = 1,
+};
+
+/* SST firmware module info */
+struct sst_hsw_module_info {
+ u8 name[SST_HSW_MAX_INFO_SIZE];
+ u8 version[SST_HSW_MAX_INFO_SIZE];
+} __attribute__((packed));
+
+/* Module entry point */
+struct sst_hsw_module_entry {
+ enum sst_hsw_module_id module_id;
+ u32 entry_point;
+} __attribute__((packed));
+
+/* Module map - alignement matches DSP */
+struct sst_hsw_module_map {
+ u8 module_entries_count;
+ struct sst_hsw_module_entry module_entries[1];
+} __attribute__((packed));
+
+struct sst_hsw_memory_info {
+ u32 offset;
+ u32 size;
+} __attribute__((packed));
+
+struct sst_hsw_fx_enable {
+ struct sst_hsw_module_map module_map;
+ struct sst_hsw_memory_info persistent_mem;
+} __attribute__((packed));
+
+struct sst_hsw_get_fx_param {
+ u32 parameter_id;
+ u32 param_size;
+} __attribute__((packed));
+
+struct sst_hsw_perf_action {
+ u32 action;
+} __attribute__((packed));
+
+struct sst_hsw_perf_data {
+ u64 timestamp;
+ u64 cycles;
+ u64 datatime;
+} __attribute__((packed));
+
+/* FW version */
+struct sst_hsw_ipc_fw_version {
+ u8 build;
+ u8 minor;
+ u8 major;
+ u8 type;
+ u8 fw_build_hash[SST_HSW_BUILD_HASH_LENGTH];
+ u32 fw_log_providers_hash;
+} __attribute__((packed));
+
+/* Stream ring info */
+struct sst_hsw_ipc_stream_ring {
+ u32 ring_pt_address;
+ u32 num_pages;
+ u32 ring_size;
+ u32 ring_offset;
+ u32 ring_first_pfn;
+} __attribute__((packed));
+
+/* Debug Dump Log Enable Request */
+struct sst_hsw_ipc_debug_log_enable_req {
+ struct sst_hsw_ipc_stream_ring ringinfo;
+ u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS];
+} __attribute__((packed));
+
+/* Debug Dump Log Reply */
+struct sst_hsw_ipc_debug_log_reply {
+ u32 log_buffer_begining;
+ u32 log_buffer_size;
+} __attribute__((packed));
+
+/* Stream glitch position */
+struct sst_hsw_ipc_stream_glitch_position {
+ u32 glitch_type;
+ u32 present_pos;
+ u32 write_pos;
+} __attribute__((packed));
+
+/* Stream get position */
+struct sst_hsw_ipc_stream_get_position {
+ u32 position;
+ u32 fw_cycle_count;
+} __attribute__((packed));
+
+/* Stream set position */
+struct sst_hsw_ipc_stream_set_position {
+ u32 position;
+ u32 end_of_buffer;
+} __attribute__((packed));
+
+/* Stream Free Request */
+struct sst_hsw_ipc_stream_free_req {
+ u8 stream_id;
+ u8 reserved[3];
+} __attribute__((packed));
+
+/* Set Volume Request */
+struct sst_hsw_ipc_volume_req {
+ u32 channel;
+ u32 target_volume;
+ u64 curve_duration;
+ u32 curve_type;
+} __attribute__((packed));
+
+/* Device Configuration Request */
+struct sst_hsw_ipc_device_config_req {
+ u32 ssp_interface;
+ u32 clock_frequency;
+ u32 mode;
+ u16 clock_divider;
+ u16 reserved;
+} __attribute__((packed));
+
+/* Audio Data formats */
+struct sst_hsw_audio_data_format_ipc {
+ u32 frequency;
+ u32 bitdepth;
+ u32 map;
+ u32 config;
+ u32 style;
+ u8 ch_num;
+ u8 valid_bit;
+ u8 reserved[2];
+} __attribute__((packed));
+
+/* Stream Allocate Request */
+struct sst_hsw_ipc_stream_alloc_req {
+ u8 path_id;
+ u8 stream_type;
+ u8 format_id;
+ u8 reserved;
+ struct sst_hsw_audio_data_format_ipc format;
+ struct sst_hsw_ipc_stream_ring ringinfo;
+ struct sst_hsw_module_map map;
+ struct sst_hsw_memory_info persistent_mem;
+ struct sst_hsw_memory_info scratch_mem;
+ u32 number_of_notifications;
+} __attribute__((packed));
+
+/* Stream Allocate Reply */
+struct sst_hsw_ipc_stream_alloc_reply {
+ u32 stream_hw_id;
+ u32 mixer_hw_id; // returns rate ????
+ u32 read_position_register_address;
+ u32 presentation_position_register_address;
+ u32 peak_meter_register_address[SST_HSW_NO_CHANNELS];
+ u32 volume_register_address[SST_HSW_NO_CHANNELS];
+} __attribute__((packed));
+
+/* Get Mixer Stream Info */
+struct sst_hsw_ipc_stream_info_reply {
+ u32 mixer_hw_id;
+ u32 peak_meter_register_address[SST_HSW_NO_CHANNELS];
+ u32 volume_register_address[SST_HSW_NO_CHANNELS];
+} __attribute__((packed));
+
+/* DX State Request */
+struct sst_hsw_ipc_dx_req {
+ u8 state;
+ u8 reserved[3];
+} __attribute__((packed));
+
+/* DX State Reply Memory Info Item */
+struct sst_hsw_ipc_dx_memory_item {
+ u32 offset;
+ u32 size;
+ u32 source;
+} __attribute__((packed));
+
+/* DX State Reply */
+struct sst_hsw_ipc_dx_reply {
+ u32 entries_no;
+ struct sst_hsw_ipc_dx_memory_item mem_info[SST_HSW_MAX_DX_REGIONS];
+} __attribute__((packed));
+
+struct sst_hsw_ipc_fw_version;
+
+/* SST Init & Free */
+struct sst_hsw *sst_hsw_new(struct device *dev, const u8 *fw, size_t fw_length,
+ u32 fw_offset);
+void sst_hsw_free(struct sst_hsw *hsw);
+int sst_hsw_fw_get_version(struct sst_hsw *hsw,
+ struct sst_hsw_ipc_fw_version *version);
+u32 create_channel_map(enum sst_hsw_channel_config config);
+
+/* Stream Mixer Controls - */
+int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ u32 stage_id, u32 channel);
+int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ u32 stage_id, u32 channel);
+
+int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume);
+int sst_hsw_stream_get_volume(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume);
+
+int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u64 curve_duration,
+ enum sst_hsw_volume_curve curve);
+
+/* Global Mixer Controls - */
+int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel);
+int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel);
+
+int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
+ u32 volume);
+int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
+ u32 *volume);
+
+int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw,
+ u64 curve_duration, enum sst_hsw_volume_curve curve);
+
+/* Stream API */
+struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
+ u32 (*get_write_position)(struct sst_hsw_stream *stream, void *data),
+ void *data);
+
+int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
+
+/* Stream Configuration */
+int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ enum sst_hsw_stream_path_id path_id,
+ enum sst_hsw_stream_type stream_type,
+ enum sst_hsw_stream_format format_id);
+
+int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ u32 ring_pt_address, u32 num_pages,
+ u32 ring_size, u32 ring_offset, u32 ring_first_pfn);
+
+int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
+
+int sst_hsw_stream_set_valid(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ u32 bits);
+int sst_hsw_stream_set_rate(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ int rate);
+int sst_hsw_stream_set_bits(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ enum sst_hsw_bitdepth bits);
+int sst_hsw_stream_set_channels(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, int channels);
+int sst_hsw_stream_set_map_config(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 map,
+ enum sst_hsw_channel_config config);
+int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ enum sst_hsw_interleaving style);
+int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id,
+ u32 entry_point);
+int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 offset, u32 size);
+int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 offset, u32 size);
+int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream);
+int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream);
+u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream);
+u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream);
+u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 channel);
+u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 channel);
+int sst_hsw_mixer_get_info(struct sst_hsw *hsw);
+
+/* Stream ALSA trigger operations */
+int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ int wait);
+int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
+ int wait);
+int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
+
+/* Stream pointer positions */
+int sst_hsw_stream_get_read_pos(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 *position);
+int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 *position);
+int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, u32 stage_id, u32 position);
+int sst_hsw_get_dsp_position(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream);
+
+/* HW port config */
+int sst_hsw_device_set_config(struct sst_hsw *hsw,
+ enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk,
+ enum sst_hsw_device_mode mode, u32 clock_divider);
+
+/* DX Config */
+int sst_hsw_dx_set_state(struct sst_hsw *hsw,
+ enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx);
+int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item,
+ u32 *offset, u32 *size, u32 *source);
+
+/* init */
+int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata);
+void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata);
+struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw);
+void sst_hsw_set_scratch_module(struct sst_hsw *hsw,
+ struct sst_module *scratch);
+
+#endif
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
new file mode 100644
index 000000000000..0a32dd13a23d
--- /dev/null
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -0,0 +1,872 @@
+/*
+ * Intel SST Haswell/Broadwell PCM Support
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/compress_driver.h>
+
+#include "sst-haswell-ipc.h"
+#include "sst-dsp-priv.h"
+#include "sst-dsp.h"
+
+#define HSW_PCM_COUNT 6
+#define HSW_VOLUME_MAX 0x7FFFFFFF /* 0dB */
+
+/* simple volume table */
+static const u32 volume_map[] = {
+ HSW_VOLUME_MAX >> 30,
+ HSW_VOLUME_MAX >> 29,
+ HSW_VOLUME_MAX >> 28,
+ HSW_VOLUME_MAX >> 27,
+ HSW_VOLUME_MAX >> 26,
+ HSW_VOLUME_MAX >> 25,
+ HSW_VOLUME_MAX >> 24,
+ HSW_VOLUME_MAX >> 23,
+ HSW_VOLUME_MAX >> 22,
+ HSW_VOLUME_MAX >> 21,
+ HSW_VOLUME_MAX >> 20,
+ HSW_VOLUME_MAX >> 19,
+ HSW_VOLUME_MAX >> 18,
+ HSW_VOLUME_MAX >> 17,
+ HSW_VOLUME_MAX >> 16,
+ HSW_VOLUME_MAX >> 15,
+ HSW_VOLUME_MAX >> 14,
+ HSW_VOLUME_MAX >> 13,
+ HSW_VOLUME_MAX >> 12,
+ HSW_VOLUME_MAX >> 11,
+ HSW_VOLUME_MAX >> 10,
+ HSW_VOLUME_MAX >> 9,
+ HSW_VOLUME_MAX >> 8,
+ HSW_VOLUME_MAX >> 7,
+ HSW_VOLUME_MAX >> 6,
+ HSW_VOLUME_MAX >> 5,
+ HSW_VOLUME_MAX >> 4,
+ HSW_VOLUME_MAX >> 3,
+ HSW_VOLUME_MAX >> 2,
+ HSW_VOLUME_MAX >> 1,
+ HSW_VOLUME_MAX >> 0,
+};
+
+#define HSW_PCM_PERIODS_MAX 64
+#define HSW_PCM_PERIODS_MIN 2
+
+static const struct snd_pcm_hardware hsw_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .period_bytes_min = PAGE_SIZE,
+ .period_bytes_max = (HSW_PCM_PERIODS_MAX / HSW_PCM_PERIODS_MIN) * PAGE_SIZE,
+ .periods_min = HSW_PCM_PERIODS_MIN,
+ .periods_max = HSW_PCM_PERIODS_MAX,
+ .buffer_bytes_max = HSW_PCM_PERIODS_MAX * PAGE_SIZE,
+};
+
+/* private data for each PCM DSP stream */
+struct hsw_pcm_data {
+ int dai_id;
+ struct sst_hsw_stream *stream;
+ u32 volume[2];
+ struct snd_pcm_substream *substream;
+ struct snd_compr_stream *cstream;
+ unsigned int wpos;
+ struct mutex mutex;
+};
+
+/* private data for the driver */
+struct hsw_priv_data {
+ /* runtime DSP */
+ struct sst_hsw *hsw;
+
+ /* page tables */
+ unsigned char *pcm_pg[HSW_PCM_COUNT][2];
+
+ /* DAI data */
+ struct hsw_pcm_data pcm[HSW_PCM_COUNT];
+};
+
+static inline u32 hsw_mixer_to_ipc(unsigned int value)
+{
+ if (value >= ARRAY_SIZE(volume_map))
+ return volume_map[0];
+ else
+ return volume_map[value];
+}
+
+static inline unsigned int hsw_ipc_to_mixer(u32 value)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(volume_map); i++) {
+ if (volume_map[i] >= value)
+ return i;
+ }
+
+ return i - 1;
+}
+
+static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct hsw_priv_data *pdata =
+ snd_soc_platform_get_drvdata(platform);
+ struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
+ struct sst_hsw *hsw = pdata->hsw;
+ u32 volume;
+
+ mutex_lock(&pcm_data->mutex);
+
+ if (!pcm_data->stream) {
+ pcm_data->volume[0] =
+ hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+ pcm_data->volume[1] =
+ hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
+ mutex_unlock(&pcm_data->mutex);
+ return 0;
+ }
+
+ if (ucontrol->value.integer.value[0] ==
+ ucontrol->value.integer.value[1]) {
+ volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+ sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 2, volume);
+ } else {
+ volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+ sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 0, volume);
+ volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
+ sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume);
+ }
+
+ mutex_unlock(&pcm_data->mutex);
+ return 0;
+}
+
+static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct hsw_priv_data *pdata =
+ snd_soc_platform_get_drvdata(platform);
+ struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
+ struct sst_hsw *hsw = pdata->hsw;
+ u32 volume;
+
+ mutex_lock(&pcm_data->mutex);
+
+ if (!pcm_data->stream) {
+ ucontrol->value.integer.value[0] =
+ hsw_ipc_to_mixer(pcm_data->volume[0]);
+ ucontrol->value.integer.value[1] =
+ hsw_ipc_to_mixer(pcm_data->volume[1]);
+ mutex_unlock(&pcm_data->mutex);
+ return 0;
+ }
+
+ sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 0, &volume);
+ ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
+ sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume);
+ ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
+ mutex_unlock(&pcm_data->mutex);
+
+ return 0;
+}
+
+static int hsw_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+ struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+ struct sst_hsw *hsw = pdata->hsw;
+ u32 volume;
+
+ if (ucontrol->value.integer.value[0] ==
+ ucontrol->value.integer.value[1]) {
+
+ volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+ sst_hsw_mixer_set_volume(hsw, 0, 2, volume);
+
+ } else {
+ volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
+ sst_hsw_mixer_set_volume(hsw, 0, 0, volume);
+
+ volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
+ sst_hsw_mixer_set_volume(hsw, 0, 1, volume);
+ }
+
+ return 0;
+}
+
+static int hsw_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+ struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+ struct sst_hsw *hsw = pdata->hsw;
+ unsigned int volume = 0;
+
+ sst_hsw_mixer_get_volume(hsw, 0, 0, &volume);
+ ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
+
+ sst_hsw_mixer_get_volume(hsw, 0, 1, &volume);
+ ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
+
+ return 0;
+}
+
+/* TLV used by both global and stream volumes */
+static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1);
+
+/* System Pin has no volume control */
+static const struct snd_kcontrol_new hsw_volume_controls[] = {
+ /* Global DSP volume */
+ SOC_DOUBLE_EXT_TLV("Master Playback Volume", 0, 0, 8,
+ ARRAY_SIZE(volume_map) -1, 0,
+ hsw_volume_get, hsw_volume_put, hsw_vol_tlv),
+ /* Offload 0 volume */
+ SOC_DOUBLE_EXT_TLV("Media0 Playback Volume", 1, 0, 8,
+ ARRAY_SIZE(volume_map), 0,
+ hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
+ /* Offload 1 volume */
+ SOC_DOUBLE_EXT_TLV("Media1 Playback Volume", 2, 0, 8,
+ ARRAY_SIZE(volume_map), 0,
+ hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
+ /* Loopback volume */
+ SOC_DOUBLE_EXT_TLV("Loopback Capture Volume", 3, 0, 8,
+ ARRAY_SIZE(volume_map), 0,
+ hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
+ /* Mic Capture volume */
+ SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8,
+ ARRAY_SIZE(volume_map), 0,
+ hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
+};
+
+/* Create DMA buffer page table for DSP */
+static int create_adsp_page_table(struct hsw_priv_data *pdata,
+ struct snd_soc_pcm_runtime *rtd,
+ unsigned char *dma_area, size_t size, int pcm, int stream)
+{
+ int i, pages;
+
+ if (size % PAGE_SIZE)
+ pages = (size / PAGE_SIZE) + 1;
+ else
+ pages = size / PAGE_SIZE;
+
+ dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n",
+ dma_area, size, pages);
+
+ for (i = 0; i < pages; i++) {
+ u32 idx = (((i << 2) + i)) >> 1;
+ u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT;
+ u32 *pg_table;
+
+ dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
+
+ pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx);
+
+ if (i & 1)
+ *pg_table |= (pfn << 4);
+ else
+ *pg_table |= pfn;
+ }
+
+ return 0;
+}
+
+/* this may get called several times by oss emulation */
+static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct hsw_priv_data *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct sst_hsw *hsw = pdata->hsw;
+ struct sst_module *module_data;
+ struct sst_dsp *dsp;
+ enum sst_hsw_stream_type stream_type;
+ enum sst_hsw_stream_path_id path_id;
+ u32 rate, bits, map, pages, module_id;
+ u8 channels;
+ int ret;
+
+ /* stream direction */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
+ else
+ path_id = SST_HSW_STREAM_PATH_SSP0_IN;
+
+ /* DSP stream type depends on DAI ID */
+ switch (rtd->cpu_dai->id) {
+ case 0:
+ stream_type = SST_HSW_STREAM_TYPE_SYSTEM;
+ module_id = SST_HSW_MODULE_PCM_SYSTEM;
+ break;
+ case 1:
+ case 2:
+ stream_type = SST_HSW_STREAM_TYPE_RENDER;
+ module_id = SST_HSW_MODULE_PCM;
+ break;
+ case 3:
+ /* path ID needs to be OUT for loopback */
+ stream_type = SST_HSW_STREAM_TYPE_LOOPBACK;
+ path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
+ module_id = SST_HSW_MODULE_PCM_REFERENCE;
+ break;
+ case 4:
+ stream_type = SST_HSW_STREAM_TYPE_CAPTURE;
+ module_id = SST_HSW_MODULE_PCM_CAPTURE;
+ break;
+ default:
+ dev_err(rtd->dev, "error: invalid DAI ID %d\n",
+ rtd->cpu_dai->id);
+ return -EINVAL;
+ };
+
+ ret = sst_hsw_stream_format(hsw, pcm_data->stream,
+ path_id, stream_type, SST_HSW_STREAM_FORMAT_PCM_FORMAT);
+ if (ret < 0) {
+ dev_err(rtd->dev, "error: failed to set format %d\n", ret);
+ return ret;
+ }
+
+ rate = params_rate(params);
+ ret = sst_hsw_stream_set_rate(hsw, pcm_data->stream, rate);
+ if (ret < 0) {
+ dev_err(rtd->dev, "error: could not set rate %d\n", rate);
+ return ret;
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bits = SST_HSW_DEPTH_16BIT;
+ sst_hsw_stream_set_valid(hsw, pcm_data->stream, 16);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bits = SST_HSW_DEPTH_24BIT;
+ sst_hsw_stream_set_valid(hsw, pcm_data->stream, 32);
+ break;
+ default:
+ dev_err(rtd->dev, "error: invalid format %d\n",
+ params_format(params));
+ return -EINVAL;
+ }
+
+ ret = sst_hsw_stream_set_bits(hsw, pcm_data->stream, bits);
+ if (ret < 0) {
+ dev_err(rtd->dev, "error: could not set bits %d\n", bits);
+ return ret;
+ }
+
+ /* we only support stereo atm */
+ channels = params_channels(params);
+ if (channels != 2) {
+ dev_err(rtd->dev, "error: invalid channels %d\n", channels);
+ return -EINVAL;
+ }
+
+ map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO);
+ sst_hsw_stream_set_map_config(hsw, pcm_data->stream,
+ map, SST_HSW_CHANNEL_CONFIG_STEREO);
+
+ ret = sst_hsw_stream_set_channels(hsw, pcm_data->stream, channels);
+ if (ret < 0) {
+ dev_err(rtd->dev, "error: could not set channels %d\n",
+ channels);
+ return ret;
+ }
+
+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+ if (ret < 0) {
+ dev_err(rtd->dev, "error: could not allocate %d bytes for PCM %d\n",
+ params_buffer_bytes(params), ret);
+ return ret;
+ }
+
+ ret = create_adsp_page_table(pdata, rtd, runtime->dma_area,
+ runtime->dma_bytes, rtd->cpu_dai->id, substream->stream);
+ if (ret < 0)
+ return ret;
+
+ sst_hsw_stream_set_style(hsw, pcm_data->stream,
+ SST_HSW_INTERLEAVING_PER_CHANNEL);
+
+ if (runtime->dma_bytes % PAGE_SIZE)
+ pages = (runtime->dma_bytes / PAGE_SIZE) + 1;
+ else
+ pages = runtime->dma_bytes / PAGE_SIZE;
+
+ ret = sst_hsw_stream_buffer(hsw, pcm_data->stream,
+ virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]),
+ pages, runtime->dma_bytes, 0,
+ (u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT));
+ if (ret < 0) {
+ dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret);
+ return ret;
+ }
+
+ dsp = sst_hsw_get_dsp(hsw);
+
+ module_data = sst_module_get_from_id(dsp, module_id);
+ if (module_data == NULL) {
+ dev_err(rtd->dev, "error: failed to get module config\n");
+ return -EINVAL;
+ }
+
+ /* we use hardcoded memory offsets atm, will be updated for new FW */
+ if (stream_type == SST_HSW_STREAM_TYPE_CAPTURE) {
+ sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
+ SST_HSW_MODULE_PCM_CAPTURE, module_data->entry);
+ sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
+ 0x449400, 0x4000);
+ sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
+ 0x400000, 0);
+ } else { /* stream_type == SST_HSW_STREAM_TYPE_SYSTEM */
+ sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
+ SST_HSW_MODULE_PCM_SYSTEM, module_data->entry);
+
+ sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
+ module_data->offset, module_data->size);
+ sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
+ 0x44d400, 0x3800);
+
+ sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
+ module_data->offset, module_data->size);
+ sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
+ 0x400000, 0);
+ }
+
+ ret = sst_hsw_stream_commit(hsw, pcm_data->stream);
+ if (ret < 0) {
+ dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);
+ return ret;
+ }
+
+ ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);
+ if (ret < 0)
+ dev_err(rtd->dev, "error: failed to pause %d\n", ret);
+
+ return 0;
+}
+
+static int hsw_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_lib_free_pages(substream);
+ return 0;
+}
+
+static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct hsw_priv_data *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct sst_hsw *hsw = pdata->hsw;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ sst_hsw_stream_resume(hsw, pcm_data->stream, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ sst_hsw_stream_pause(hsw, pcm_data->stream, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data)
+{
+ struct hsw_pcm_data *pcm_data = data;
+ struct snd_pcm_substream *substream = pcm_data->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ u32 pos;
+
+ pos = frames_to_bytes(runtime,
+ (runtime->control->appl_ptr % runtime->buffer_size));
+
+ dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
+
+ /* let alsa know we have play a period */
+ snd_pcm_period_elapsed(substream);
+ return pos;
+}
+
+static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct hsw_priv_data *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct sst_hsw *hsw = pdata->hsw;
+ snd_pcm_uframes_t offset;
+
+ offset = bytes_to_frames(runtime,
+ sst_hsw_get_dsp_position(hsw, pcm_data->stream));
+
+ dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n",
+ frames_to_bytes(runtime, (u32)offset));
+ return offset;
+}
+
+static int hsw_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct hsw_priv_data *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ struct hsw_pcm_data *pcm_data;
+ struct sst_hsw *hsw = pdata->hsw;
+
+ pcm_data = &pdata->pcm[rtd->cpu_dai->id];
+
+ mutex_lock(&pcm_data->mutex);
+
+ snd_soc_pcm_set_drvdata(rtd, pcm_data);
+ pcm_data->substream = substream;
+
+ snd_soc_set_runtime_hwparams(substream, &hsw_pcm_hardware);
+
+ pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id,
+ hsw_notify_pointer, pcm_data);
+ if (pcm_data->stream == NULL) {
+ dev_err(rtd->dev, "error: failed to create stream\n");
+ mutex_unlock(&pcm_data->mutex);
+ return -EINVAL;
+ }
+
+ /* Set previous saved volume */
+ sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
+ 0, pcm_data->volume[0]);
+ sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
+ 1, pcm_data->volume[1]);
+
+ mutex_unlock(&pcm_data->mutex);
+ return 0;
+}
+
+static int hsw_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct hsw_priv_data *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+ struct sst_hsw *hsw = pdata->hsw;
+ int ret;
+
+ mutex_lock(&pcm_data->mutex);
+ ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
+ if (ret < 0) {
+ dev_dbg(rtd->dev, "error: reset stream failed %d\n", ret);
+ goto out;
+ }
+
+ ret = sst_hsw_stream_free(hsw, pcm_data->stream);
+ if (ret < 0) {
+ dev_dbg(rtd->dev, "error: free stream failed %d\n", ret);
+ goto out;
+ }
+ pcm_data->stream = NULL;
+
+out:
+ mutex_unlock(&pcm_data->mutex);
+ return ret;
+}
+
+static struct snd_pcm_ops hsw_pcm_ops = {
+ .open = hsw_pcm_open,
+ .close = hsw_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = hsw_pcm_hw_params,
+ .hw_free = hsw_pcm_hw_free,
+ .trigger = hsw_pcm_trigger,
+ .pointer = hsw_pcm_pointer,
+ .mmap = snd_pcm_lib_default_mmap,
+};
+
+static void hsw_pcm_free(struct snd_pcm *pcm)
+{
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm;
+ int ret = 0;
+
+ ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
+ pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+ ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_DEV,
+ rtd->card->dev,
+ hsw_pcm_hardware.buffer_bytes_max,
+ hsw_pcm_hardware.buffer_bytes_max);
+ if (ret) {
+ dev_err(rtd->dev, "dma buffer allocation failed %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+#define HSW_FORMATS \
+ (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver hsw_dais[] = {
+ {
+ .name = "System Pin",
+ .playback = {
+ .stream_name = "System Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ },
+ {
+ /* PCM */
+ .name = "Offload0 Pin",
+ .playback = {
+ .stream_name = "Offload0 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = HSW_FORMATS,
+ },
+ },
+ {
+ /* PCM */
+ .name = "Offload1 Pin",
+ .playback = {
+ .stream_name = "Offload1 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = HSW_FORMATS,
+ },
+ },
+ {
+ .name = "Loopback Pin",
+ .capture = {
+ .stream_name = "Loopback Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = HSW_FORMATS,
+ },
+ },
+ {
+ .name = "Capture Pin",
+ .capture = {
+ .stream_name = "Analog Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = HSW_FORMATS,
+ },
+ },
+};
+
+static const struct snd_soc_dapm_widget widgets[] = {
+
+ /* Backend DAIs */
+ SND_SOC_DAPM_AIF_IN("SSP0 CODEC IN", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SSP0 CODEC OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SSP1 BT IN", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SSP1 BT OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+ /* Global Playback Mixer */
+ SND_SOC_DAPM_MIXER("Playback VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route graph[] = {
+
+ /* Playback Mixer */
+ {"Playback VMixer", NULL, "System Playback"},
+ {"Playback VMixer", NULL, "Offload0 Playback"},
+ {"Playback VMixer", NULL, "Offload1 Playback"},
+
+ {"SSP0 CODEC OUT", NULL, "Playback VMixer"},
+
+ {"Analog Capture", NULL, "SSP0 CODEC IN"},
+};
+
+static int hsw_pcm_probe(struct snd_soc_platform *platform)
+{
+ struct sst_pdata *pdata = dev_get_platdata(platform->dev);
+ struct hsw_priv_data *priv_data;
+ int i;
+
+ if (!pdata)
+ return -ENODEV;
+
+ priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL);
+ priv_data->hsw = pdata->dsp;
+ snd_soc_platform_set_drvdata(platform, priv_data);
+
+ /* allocate DSP buffer page tables */
+ for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
+
+ mutex_init(&priv_data->pcm[i].mutex);
+
+ /* playback */
+ if (hsw_dais[i].playback.channels_min) {
+ priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA);
+ if (priv_data->pcm_pg[i][0] == NULL)
+ goto err;
+ }
+
+ /* capture */
+ if (hsw_dais[i].capture.channels_min) {
+ priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA);
+ if (priv_data->pcm_pg[i][1] == NULL)
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ for (;i >= 0; i--) {
+ if (hsw_dais[i].playback.channels_min)
+ kfree(priv_data->pcm_pg[i][0]);
+ if (hsw_dais[i].capture.channels_min)
+ kfree(priv_data->pcm_pg[i][1]);
+ }
+ return -ENOMEM;
+}
+
+static int hsw_pcm_remove(struct snd_soc_platform *platform)
+{
+ struct hsw_priv_data *priv_data =
+ snd_soc_platform_get_drvdata(platform);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
+ if (hsw_dais[i].playback.channels_min)
+ kfree(priv_data->pcm_pg[i][0]);
+ if (hsw_dais[i].capture.channels_min)
+ kfree(priv_data->pcm_pg[i][1]);
+ }
+
+ return 0;
+}
+
+static struct snd_soc_platform_driver hsw_soc_platform = {
+ .probe = hsw_pcm_probe,
+ .remove = hsw_pcm_remove,
+ .ops = &hsw_pcm_ops,
+ .pcm_new = hsw_pcm_new,
+ .pcm_free = hsw_pcm_free,
+ .controls = hsw_volume_controls,
+ .num_controls = ARRAY_SIZE(hsw_volume_controls),
+ .dapm_widgets = widgets,
+ .num_dapm_widgets = ARRAY_SIZE(widgets),
+ .dapm_routes = graph,
+ .num_dapm_routes = ARRAY_SIZE(graph),
+};
+
+static const struct snd_soc_component_driver hsw_dai_component = {
+ .name = "haswell-dai",
+};
+
+static int hsw_pcm_dev_probe(struct platform_device *pdev)
+{
+ struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+ int ret;
+
+ ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata);
+ if (ret < 0)
+ return -ENODEV;
+
+ ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform);
+ if (ret < 0)
+ goto err_plat;
+
+ ret = snd_soc_register_component(&pdev->dev, &hsw_dai_component,
+ hsw_dais, ARRAY_SIZE(hsw_dais));
+ if (ret < 0)
+ goto err_comp;
+
+ return 0;
+
+err_comp:
+ snd_soc_unregister_platform(&pdev->dev);
+err_plat:
+ sst_hsw_dsp_free(&pdev->dev, sst_pdata);
+ return 0;
+}
+
+static int hsw_pcm_dev_remove(struct platform_device *pdev)
+{
+ struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+
+ snd_soc_unregister_platform(&pdev->dev);
+ snd_soc_unregister_component(&pdev->dev);
+ sst_hsw_dsp_free(&pdev->dev, sst_pdata);
+
+ return 0;
+}
+
+static struct platform_driver hsw_pcm_driver = {
+ .driver = {
+ .name = "haswell-pcm-audio",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = hsw_pcm_dev_probe,
+ .remove = hsw_pcm_dev_remove,
+};
+module_platform_driver(hsw_pcm_driver);
+
+MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
+MODULE_DESCRIPTION("Haswell/Lynxpoint + Broadwell/Wildcatpoint PCM");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:haswell-pcm-audio");
diff --git a/sound/soc/intel/sst_dsp.h b/sound/soc/intel/sst-mfld-dsp.h
index 0fce1de284ff..3b63edc04b7f 100644
--- a/sound/soc/intel/sst_dsp.h
+++ b/sound/soc/intel/sst-mfld-dsp.h
@@ -1,7 +1,7 @@
-#ifndef __SST_DSP_H__
-#define __SST_DSP_H__
+#ifndef __SST_MFLD_DSP_H__
+#define __SST_MFLD_DSP_H__
/*
- * sst_dsp.h - Intel SST Driver for audio engine
+ * sst_mfld_dsp.h - Intel SST Driver for audio engine
*
* Copyright (C) 2008-12 Intel Corporation
* Authors: Vinod Koul <vinod.koul@linux.intel.com>
@@ -131,4 +131,4 @@ struct snd_sst_params {
struct snd_sst_alloc_params_ext aparams;
};
-#endif /* __SST_DSP_H__ */
+#endif /* __SST_MFLD_DSP_H__ */
diff --git a/sound/soc/intel/sst_platform.c b/sound/soc/intel/sst-mfld-platform.c
index f465a8180863..840306c2ef14 100644
--- a/sound/soc/intel/sst_platform.c
+++ b/sound/soc/intel/sst-mfld-platform.c
@@ -1,5 +1,5 @@
/*
- * sst_platform.c - Intel MID Platform driver
+ * sst_mfld_platform.c - Intel MID Platform driver
*
* Copyright (C) 2010-2013 Intel Corp
* Author: Vinod Koul <vinod.koul@intel.com>
@@ -33,7 +33,7 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/compress_driver.h>
-#include "sst_platform.h"
+#include "sst-mfld-platform.h"
static struct sst_device *sst;
static DEFINE_MUTEX(sst_lock);
@@ -709,7 +709,7 @@ static int sst_platform_remove(struct platform_device *pdev)
static struct platform_driver sst_platform_driver = {
.driver = {
- .name = "sst-platform",
+ .name = "sst-mfld-platform",
.owner = THIS_MODULE,
},
.probe = sst_platform_probe,
@@ -722,4 +722,4 @@ MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:sst-platform");
+MODULE_ALIAS("platform:sst-mfld-platform");
diff --git a/sound/soc/intel/sst_platform.h b/sound/soc/intel/sst-mfld-platform.h
index bee64fb7d2ef..0c4e2ddcecb1 100644
--- a/sound/soc/intel/sst_platform.h
+++ b/sound/soc/intel/sst-mfld-platform.h
@@ -1,5 +1,5 @@
/*
- * sst_platform.h - Intel MID Platform driver header file
+ * sst_mfld_platform.h - Intel MID Platform driver header file
*
* Copyright (C) 2010 Intel Corp
* Author: Vinod Koul <vinod.koul@intel.com>
@@ -27,7 +27,7 @@
#ifndef __SST_PLATFORMDRV_H__
#define __SST_PLATFORMDRV_H__
-#include "sst_dsp.h"
+#include "sst-mfld-dsp.h"
#define SST_MONO 1
#define SST_STEREO 2
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig
index 78ed4a42ad21..49f8437665de 100644
--- a/sound/soc/kirkwood/Kconfig
+++ b/sound/soc/kirkwood/Kconfig
@@ -1,11 +1,20 @@
config SND_KIRKWOOD_SOC
tristate "SoC Audio for the Marvell Kirkwood and Dove chips"
- depends on ARCH_KIRKWOOD || ARCH_DOVE || COMPILE_TEST
+ depends on ARCH_KIRKWOOD || ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST
help
Say Y or M if you want to add support for codecs attached to
the Kirkwood I2S interface. You will also need to select the
audio interfaces to support below.
+config SND_KIRKWOOD_SOC_ARMADA370_DB
+ tristate "SoC Audio support for Armada 370 DB"
+ depends on SND_KIRKWOOD_SOC && (ARCH_MVEBU || COMPILE_TEST) && I2C
+ select SND_SOC_CS42L51
+ select SND_SOC_SPDIF
+ help
+ Say Y if you want to add support for SoC audio on
+ the Armada 370 Development Board.
+
config SND_KIRKWOOD_SOC_OPENRD
tristate "SoC Audio support for Kirkwood Openrd Client"
depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE || COMPILE_TEST)
diff --git a/sound/soc/kirkwood/Makefile b/sound/soc/kirkwood/Makefile
index 9e781385cb88..7c1d8fe09e6b 100644
--- a/sound/soc/kirkwood/Makefile
+++ b/sound/soc/kirkwood/Makefile
@@ -4,6 +4,8 @@ obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
snd-soc-openrd-objs := kirkwood-openrd.o
snd-soc-t5325-objs := kirkwood-t5325.o
+snd-soc-armada-370-db-objs := armada-370-db.o
+obj-$(CONFIG_SND_KIRKWOOD_SOC_ARMADA370_DB) += snd-soc-armada-370-db.o
obj-$(CONFIG_SND_KIRKWOOD_SOC_OPENRD) += snd-soc-openrd.o
obj-$(CONFIG_SND_KIRKWOOD_SOC_T5325) += snd-soc-t5325.o
diff --git a/sound/soc/kirkwood/armada-370-db.c b/sound/soc/kirkwood/armada-370-db.c
new file mode 100644
index 000000000000..c44333849259
--- /dev/null
+++ b/sound/soc/kirkwood/armada-370-db.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <linux/of.h>
+#include <linux/platform_data/asoc-kirkwood.h>
+#include "../codecs/cs42l51.h"
+
+static int a370db_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int freq;
+
+ switch (params_rate(params)) {
+ default:
+ case 44100:
+ freq = 11289600;
+ break;
+ case 48000:
+ freq = 12288000;
+ break;
+ case 96000:
+ freq = 24576000;
+ break;
+ }
+
+ return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN);
+}
+
+static struct snd_soc_ops a370db_ops = {
+ .hw_params = a370db_hw_params,
+};
+
+static const struct snd_soc_dapm_widget a370db_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Out Jack", NULL),
+ SND_SOC_DAPM_LINE("In Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route a370db_route[] = {
+ { "Out Jack", NULL, "HPL" },
+ { "Out Jack", NULL, "HPR" },
+ { "AIN1L", NULL, "In Jack" },
+ { "AIN1L", NULL, "In Jack" },
+};
+
+static struct snd_soc_dai_link a370db_dai[] = {
+{
+ .name = "CS42L51",
+ .stream_name = "analog",
+ .cpu_dai_name = "i2s",
+ .codec_dai_name = "cs42l51-hifi",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+ .ops = &a370db_ops,
+},
+{
+ .name = "S/PDIF out",
+ .stream_name = "spdif-out",
+ .cpu_dai_name = "spdif",
+ .codec_dai_name = "dit-hifi",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+},
+{
+ .name = "S/PDIF in",
+ .stream_name = "spdif-in",
+ .cpu_dai_name = "spdif",
+ .codec_dai_name = "dir-hifi",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+},
+};
+
+static struct snd_soc_card a370db = {
+ .name = "a370db",
+ .owner = THIS_MODULE,
+ .dai_link = a370db_dai,
+ .num_links = ARRAY_SIZE(a370db_dai),
+ .dapm_widgets = a370db_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(a370db_dapm_widgets),
+ .dapm_routes = a370db_route,
+ .num_dapm_routes = ARRAY_SIZE(a370db_route),
+};
+
+static int a370db_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &a370db;
+
+ card->dev = &pdev->dev;
+
+ a370db_dai[0].cpu_of_node =
+ of_parse_phandle(pdev->dev.of_node,
+ "marvell,audio-controller", 0);
+ a370db_dai[0].platform_of_node = a370db_dai[0].cpu_of_node;
+
+ a370db_dai[0].codec_of_node =
+ of_parse_phandle(pdev->dev.of_node,
+ "marvell,audio-codec", 0);
+
+ a370db_dai[1].cpu_of_node = a370db_dai[0].cpu_of_node;
+ a370db_dai[1].platform_of_node = a370db_dai[0].cpu_of_node;
+
+ a370db_dai[1].codec_of_node =
+ of_parse_phandle(pdev->dev.of_node,
+ "marvell,audio-codec", 1);
+
+ a370db_dai[2].cpu_of_node = a370db_dai[0].cpu_of_node;
+ a370db_dai[2].platform_of_node = a370db_dai[0].cpu_of_node;
+
+ a370db_dai[2].codec_of_node =
+ of_parse_phandle(pdev->dev.of_node,
+ "marvell,audio-codec", 2);
+
+ return devm_snd_soc_register_card(card->dev, card);
+}
+
+static const struct of_device_id a370db_dt_ids[] = {
+ { .compatible = "marvell,a370db-audio" },
+ { },
+};
+
+static struct platform_driver a370db_driver = {
+ .driver = {
+ .name = "a370db-audio",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(a370db_dt_ids),
+ },
+ .probe = a370db_probe,
+};
+
+module_platform_driver(a370db_driver);
+
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
+MODULE_DESCRIPTION("ALSA SoC a370db audio client");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:a370db-audio");
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 3920a5e8125f..9f842222e798 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -633,6 +633,7 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
static struct of_device_id mvebu_audio_of_match[] = {
{ .compatible = "marvell,kirkwood-audio" },
{ .compatible = "marvell,dove-audio" },
+ { .compatible = "marvell,armada370-audio" },
{ }
};
MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 22ad9c5654b5..e00659351a4e 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -58,7 +58,7 @@ config SND_OMAP_SOC_OSK5912
tristate "SoC Audio support for omap osk5912"
depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C
select SND_OMAP_SOC_MCBSP
- select SND_SOC_TLV320AIC23
+ select SND_SOC_TLV320AIC23_I2C
help
Say Y if you want to add support for SoC audio on osk5912.
@@ -66,7 +66,7 @@ config SND_OMAP_SOC_AM3517EVM
tristate "SoC Audio support for OMAP3517 / AM3517 EVM"
depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C
select SND_OMAP_SOC_MCBSP
- select SND_SOC_TLV320AIC23
+ select SND_SOC_TLV320AIC23_I2C
help
Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517
EVM.
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 629446482a91..56a5219c0a00 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -103,60 +103,62 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
if (!codec->hw_write)
return -EUNATCH;
- if (ucontrol->value.enumerated.item[0] >= control->max)
+ if (ucontrol->value.enumerated.item[0] >= control->items)
return -EINVAL;
- mutex_lock(&codec->mutex);
+ snd_soc_dapm_mutex_lock(dapm);
/* Translate selection to bitmap */
pins = ams_delta_audio_mode_pins[ucontrol->value.enumerated.item[0]];
/* Setup pins after corresponding bits if changed */
pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE));
+
if (pin != snd_soc_dapm_get_pin_status(dapm, "Mouthpiece")) {
changed = 1;
if (pin)
- snd_soc_dapm_enable_pin(dapm, "Mouthpiece");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Mouthpiece");
else
- snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece");
}
pin = !!(pins & (1 << AMS_DELTA_EARPIECE));
if (pin != snd_soc_dapm_get_pin_status(dapm, "Earpiece")) {
changed = 1;
if (pin)
- snd_soc_dapm_enable_pin(dapm, "Earpiece");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece");
else
- snd_soc_dapm_disable_pin(dapm, "Earpiece");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Earpiece");
}
pin = !!(pins & (1 << AMS_DELTA_MICROPHONE));
if (pin != snd_soc_dapm_get_pin_status(dapm, "Microphone")) {
changed = 1;
if (pin)
- snd_soc_dapm_enable_pin(dapm, "Microphone");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone");
else
- snd_soc_dapm_disable_pin(dapm, "Microphone");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Microphone");
}
pin = !!(pins & (1 << AMS_DELTA_SPEAKER));
if (pin != snd_soc_dapm_get_pin_status(dapm, "Speaker")) {
changed = 1;
if (pin)
- snd_soc_dapm_enable_pin(dapm, "Speaker");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker");
else
- snd_soc_dapm_disable_pin(dapm, "Speaker");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
}
pin = !!(pins & (1 << AMS_DELTA_AGC));
if (pin != ams_delta_audio_agc) {
ams_delta_audio_agc = pin;
changed = 1;
if (pin)
- snd_soc_dapm_enable_pin(dapm, "AGCIN");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "AGCIN");
else
- snd_soc_dapm_disable_pin(dapm, "AGCIN");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN");
}
+
if (changed)
- snd_soc_dapm_sync(dapm);
+ snd_soc_dapm_sync_unlocked(dapm);
- mutex_unlock(&codec->mutex);
+ snd_soc_dapm_mutex_unlock(dapm);
return changed;
}
@@ -194,13 +196,11 @@ static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
return 0;
}
-static const struct soc_enum ams_delta_audio_enum[] = {
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ams_delta_audio_mode),
- ams_delta_audio_mode),
-};
+static const SOC_ENUM_SINGLE_EXT_DECL(ams_delta_audio_enum,
+ ams_delta_audio_mode);
static const struct snd_kcontrol_new ams_delta_audio_controls[] = {
- SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum[0],
+ SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum,
ams_delta_get_audio_mode, ams_delta_set_audio_mode),
};
@@ -315,12 +315,17 @@ static void cx81801_close(struct tty_struct *tty)
v253_ops.close(tty);
/* Revert back to default audio input/output constellation */
- snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
- snd_soc_dapm_enable_pin(dapm, "Earpiece");
- snd_soc_dapm_enable_pin(dapm, "Microphone");
- snd_soc_dapm_disable_pin(dapm, "Speaker");
- snd_soc_dapm_disable_pin(dapm, "AGCIN");
- snd_soc_dapm_sync(dapm);
+ snd_soc_dapm_mutex_lock(dapm);
+
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN");
+
+ snd_soc_dapm_sync_unlocked(dapm);
+
+ snd_soc_dapm_mutex_unlock(dapm);
}
/* Line discipline .hangup() */
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 3fde9e402710..fd4d9c809e50 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -68,26 +68,30 @@ static void n810_ext_control(struct snd_soc_dapm_context *dapm)
break;
}
+ snd_soc_dapm_mutex_lock(dapm);
+
if (n810_spk_func)
- snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
else
- snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
if (hp)
- snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
else
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
if (line1l)
- snd_soc_dapm_enable_pin(dapm, "LINE1L");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "LINE1L");
else
- snd_soc_dapm_disable_pin(dapm, "LINE1L");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "LINE1L");
if (n810_dmic_func)
- snd_soc_dapm_enable_pin(dapm, "DMic");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
else
- snd_soc_dapm_disable_pin(dapm, "DMic");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
+
+ snd_soc_dapm_sync_unlocked(dapm);
- snd_soc_dapm_sync(dapm);
+ snd_soc_dapm_mutex_unlock(dapm);
}
static int n810_startup(struct snd_pcm_substream *substream)
@@ -305,7 +309,9 @@ static int __init n810_soc_init(void)
int err;
struct device *dev;
- if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax()))
+ if (!of_have_populated_dt() ||
+ (!of_machine_is_compatible("nokia,n810") &&
+ !of_machine_is_compatible("nokia,n810-wimax")))
return -ENODEV;
n810_snd_device = platform_device_alloc("soc-audio", -1);
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
index ebb13906b3a0..024dafc3e298 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -203,8 +203,7 @@ static const struct snd_soc_dapm_route dmic_audio_map[] = {
static int omap_abe_dmic_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
ARRAY_SIZE(dmic_audio_map));
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 611179c3bca4..7fb3d4b10370 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -74,26 +74,30 @@ static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
break;
}
+ snd_soc_dapm_mutex_lock(dapm);
+
if (rx51_spk_func)
- snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
else
- snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
if (rx51_dmic_func)
- snd_soc_dapm_enable_pin(dapm, "DMic");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
else
- snd_soc_dapm_disable_pin(dapm, "DMic");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
if (hp)
- snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
else
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
if (hs)
- snd_soc_dapm_enable_pin(dapm, "HS Mic");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic");
else
- snd_soc_dapm_disable_pin(dapm, "HS Mic");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout);
- snd_soc_dapm_sync(dapm);
+ snd_soc_dapm_sync_unlocked(dapm);
+
+ snd_soc_dapm_mutex_unlock(dapm);
}
static int rx51_startup(struct snd_pcm_substream *substream)
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index 1853d41034bf..5a88136aa800 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -47,64 +47,63 @@ static int corgi_spk_func;
static void corgi_ext_control(struct snd_soc_dapm_context *dapm)
{
+ snd_soc_dapm_mutex_lock(dapm);
+
/* set up jack connection */
switch (corgi_jack_func) {
case CORGI_HP:
/* set = unmute headphone */
gpio_set_value(CORGI_GPIO_MUTE_L, 1);
gpio_set_value(CORGI_GPIO_MUTE_R, 1);
- snd_soc_dapm_disable_pin(dapm, "Mic Jack");
- snd_soc_dapm_disable_pin(dapm, "Line Jack");
- snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
break;
case CORGI_MIC:
/* reset = mute headphone */
gpio_set_value(CORGI_GPIO_MUTE_L, 0);
gpio_set_value(CORGI_GPIO_MUTE_R, 0);
- snd_soc_dapm_enable_pin(dapm, "Mic Jack");
- snd_soc_dapm_disable_pin(dapm, "Line Jack");
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
break;
case CORGI_LINE:
gpio_set_value(CORGI_GPIO_MUTE_L, 0);
gpio_set_value(CORGI_GPIO_MUTE_R, 0);
- snd_soc_dapm_disable_pin(dapm, "Mic Jack");
- snd_soc_dapm_enable_pin(dapm, "Line Jack");
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
break;
case CORGI_HEADSET:
gpio_set_value(CORGI_GPIO_MUTE_L, 0);
gpio_set_value(CORGI_GPIO_MUTE_R, 1);
- snd_soc_dapm_enable_pin(dapm, "Mic Jack");
- snd_soc_dapm_disable_pin(dapm, "Line Jack");
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_enable_pin(dapm, "Headset Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack");
break;
}
if (corgi_spk_func == CORGI_SPK_ON)
- snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
else
- snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
/* signal a DAPM event */
- snd_soc_dapm_sync(dapm);
+ snd_soc_dapm_sync_unlocked(dapm);
+
+ snd_soc_dapm_mutex_unlock(dapm);
}
static int corgi_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
-
- mutex_lock(&codec->mutex);
/* check the jack status at stream startup */
- corgi_ext_control(&codec->dapm);
-
- mutex_unlock(&codec->mutex);
+ corgi_ext_control(&rtd->card->dapm);
return 0;
}
diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c
index 44b5c09d296b..c29fedab2f49 100644
--- a/sound/soc/pxa/e740_wm9705.c
+++ b/sound/soc/pxa/e740_wm9705.c
@@ -103,11 +103,6 @@ static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "PCBEEP");
snd_soc_dapm_nc_pin(dapm, "MIC2");
- snd_soc_dapm_new_controls(dapm, e740_dapm_widgets,
- ARRAY_SIZE(e740_dapm_widgets));
-
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
return 0;
}
@@ -136,6 +131,11 @@ static struct snd_soc_card e740 = {
.owner = THIS_MODULE,
.dai_link = e740_dai,
.num_links = ARRAY_SIZE(e740_dai),
+
+ .dapm_widgets = e740_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(e740_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct gpio e740_audio_gpios[] = {
diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c
index c34e447eb991..ee36aba88063 100644
--- a/sound/soc/pxa/e750_wm9705.c
+++ b/sound/soc/pxa/e750_wm9705.c
@@ -85,11 +85,6 @@ static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "PCBEEP");
snd_soc_dapm_nc_pin(dapm, "MIC2");
- snd_soc_dapm_new_controls(dapm, e750_dapm_widgets,
- ARRAY_SIZE(e750_dapm_widgets));
-
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
return 0;
}
@@ -119,6 +114,11 @@ static struct snd_soc_card e750 = {
.owner = THIS_MODULE,
.dai_link = e750_dai,
.num_links = ARRAY_SIZE(e750_dai),
+
+ .dapm_widgets = e750_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(e750_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct gpio e750_audio_gpios[] = {
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c
index 3137f800b43f..24c2078ce70b 100644
--- a/sound/soc/pxa/e800_wm9712.c
+++ b/sound/soc/pxa/e800_wm9712.c
@@ -71,19 +71,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"MIC2", NULL, "Mic (Internal2)"},
};
-static int e800_ac97_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- snd_soc_dapm_new_controls(dapm, e800_dapm_widgets,
- ARRAY_SIZE(e800_dapm_widgets));
-
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- return 0;
-}
-
static struct snd_soc_dai_link e800_dai[] = {
{
.name = "AC97",
@@ -92,7 +79,6 @@ static struct snd_soc_dai_link e800_dai[] = {
.codec_dai_name = "wm9712-hifi",
.platform_name = "pxa-pcm-audio",
.codec_name = "wm9712-codec",
- .init = e800_ac97_init,
},
{
.name = "AC97 Aux",
@@ -109,6 +95,11 @@ static struct snd_soc_card e800 = {
.owner = THIS_MODULE,
.dai_link = e800_dai,
.num_links = ARRAY_SIZE(e800_dai),
+
+ .dapm_widgets = e800_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(e800_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct gpio e800_audio_gpios[] = {
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index aace19e0fe2c..259e048681c0 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -41,44 +41,42 @@ static int magician_hp_switch;
static int magician_spk_switch = 1;
static int magician_in_sel = MAGICIAN_MIC;
-static void magician_ext_control(struct snd_soc_codec *codec)
+static void magician_ext_control(struct snd_soc_dapm_context *dapm)
{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ snd_soc_dapm_mutex_lock(dapm);
if (magician_spk_switch)
- snd_soc_dapm_enable_pin(dapm, "Speaker");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker");
else
- snd_soc_dapm_disable_pin(dapm, "Speaker");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
if (magician_hp_switch)
- snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
else
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
switch (magician_in_sel) {
case MAGICIAN_MIC:
- snd_soc_dapm_disable_pin(dapm, "Headset Mic");
- snd_soc_dapm_enable_pin(dapm, "Call Mic");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Mic");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Call Mic");
break;
case MAGICIAN_MIC_EXT:
- snd_soc_dapm_disable_pin(dapm, "Call Mic");
- snd_soc_dapm_enable_pin(dapm, "Headset Mic");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Call Mic");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Mic");
break;
}
- snd_soc_dapm_sync(dapm);
+ snd_soc_dapm_sync_unlocked(dapm);
+
+ snd_soc_dapm_mutex_unlock(dapm);
}
static int magician_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
-
- mutex_lock(&codec->mutex);
/* check the jack status at stream startup */
- magician_ext_control(codec);
-
- mutex_unlock(&codec->mutex);
+ magician_ext_control(&rtd->card->dapm);
return 0;
}
@@ -277,13 +275,13 @@ static int magician_get_hp(struct snd_kcontrol *kcontrol,
static int magician_set_hp(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
if (magician_hp_switch == ucontrol->value.integer.value[0])
return 0;
magician_hp_switch = ucontrol->value.integer.value[0];
- magician_ext_control(codec);
+ magician_ext_control(&card->dapm);
return 1;
}
@@ -297,13 +295,13 @@ static int magician_get_spk(struct snd_kcontrol *kcontrol,
static int magician_set_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
if (magician_spk_switch == ucontrol->value.integer.value[0])
return 0;
magician_spk_switch = ucontrol->value.integer.value[0];
- magician_ext_control(codec);
+ magician_ext_control(&card->dapm);
return 1;
}
@@ -400,7 +398,6 @@ static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int err;
/* NC codec pins */
snd_soc_dapm_nc_pin(dapm, "VOUTLHP");
@@ -410,19 +407,6 @@ static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "VINL");
snd_soc_dapm_nc_pin(dapm, "VINR");
- /* Add magician specific controls */
- err = snd_soc_add_codec_controls(codec, uda1380_magician_controls,
- ARRAY_SIZE(uda1380_magician_controls));
- if (err < 0)
- return err;
-
- /* Add magician specific widgets */
- snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets,
- ARRAY_SIZE(uda1380_dapm_widgets));
-
- /* Set up magician specific audio path interconnects */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
return 0;
}
@@ -456,6 +440,12 @@ static struct snd_soc_card snd_soc_card_magician = {
.dai_link = magician_dai,
.num_links = ARRAY_SIZE(magician_dai),
+ .controls = uda1380_magician_controls,
+ .num_controls = ARRAY_SIZE(uda1380_magician_controls),
+ .dapm_widgets = uda1380_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *magician_snd_device;
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
index 160c5245448f..595eee341e90 100644
--- a/sound/soc/pxa/mioa701_wm9713.c
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -127,16 +127,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
unsigned short reg;
- /* Add mioa701 specific widgets */
- snd_soc_dapm_new_controls(dapm, mioa701_dapm_widgets,
- ARRAY_SIZE(mioa701_dapm_widgets));
-
- /* Set up mioa701 specific audio path audio_mapnects */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
/* Prepare GPIO8 for rear speaker amplifier */
reg = codec->driver->read(codec, AC97_GPIO_CFG);
codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100);
@@ -145,12 +137,6 @@ static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
reg = codec->driver->read(codec, AC97_3D_CONTROL);
codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000);
- snd_soc_dapm_enable_pin(dapm, "Front Speaker");
- snd_soc_dapm_enable_pin(dapm, "Rear Speaker");
- snd_soc_dapm_enable_pin(dapm, "Front Mic");
- snd_soc_dapm_enable_pin(dapm, "GSM Line In");
- snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
-
return 0;
}
@@ -183,6 +169,11 @@ static struct snd_soc_card mioa701 = {
.owner = THIS_MODULE,
.dai_link = mioa701_dai,
.num_links = ARRAY_SIZE(mioa701_dai),
+
+ .dapm_widgets = mioa701_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mioa701_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static int mioa701_wm9713_probe(struct platform_device *pdev)
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index c93e138d8dc3..c6bdc6c0eff6 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -74,14 +74,9 @@ static void poodle_ext_control(struct snd_soc_dapm_context *dapm)
static int poodle_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
-
- mutex_lock(&codec->mutex);
/* check the jack status at stream startup */
- poodle_ext_control(&codec->dapm);
-
- mutex_unlock(&codec->mutex);
+ poodle_ext_control(&rtd->card->dapm);
return 0;
}
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index fc052d8247ff..1373b017a951 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -46,74 +46,74 @@ static int spitz_mic_gpio;
static void spitz_ext_control(struct snd_soc_dapm_context *dapm)
{
+ snd_soc_dapm_mutex_lock(dapm);
+
if (spitz_spk_func == SPITZ_SPK_ON)
- snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
else
- snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
/* set up jack connection */
switch (spitz_jack_func) {
case SPITZ_HP:
/* enable and unmute hp jack, disable mic bias */
- snd_soc_dapm_disable_pin(dapm, "Headset Jack");
- snd_soc_dapm_disable_pin(dapm, "Mic Jack");
- snd_soc_dapm_disable_pin(dapm, "Line Jack");
- snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
gpio_set_value(SPITZ_GPIO_MUTE_L, 1);
gpio_set_value(SPITZ_GPIO_MUTE_R, 1);
break;
case SPITZ_MIC:
/* enable mic jack and bias, mute hp */
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_disable_pin(dapm, "Headset Jack");
- snd_soc_dapm_disable_pin(dapm, "Line Jack");
- snd_soc_dapm_enable_pin(dapm, "Mic Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
break;
case SPITZ_LINE:
/* enable line jack, disable mic bias and mute hp */
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_disable_pin(dapm, "Headset Jack");
- snd_soc_dapm_disable_pin(dapm, "Mic Jack");
- snd_soc_dapm_enable_pin(dapm, "Line Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack");
gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
break;
case SPITZ_HEADSET:
/* enable and unmute headset jack enable mic bias, mute L hp */
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_enable_pin(dapm, "Mic Jack");
- snd_soc_dapm_disable_pin(dapm, "Line Jack");
- snd_soc_dapm_enable_pin(dapm, "Headset Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack");
gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
gpio_set_value(SPITZ_GPIO_MUTE_R, 1);
break;
case SPITZ_HP_OFF:
/* jack removed, everything off */
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_disable_pin(dapm, "Headset Jack");
- snd_soc_dapm_disable_pin(dapm, "Mic Jack");
- snd_soc_dapm_disable_pin(dapm, "Line Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
break;
}
- snd_soc_dapm_sync(dapm);
+
+ snd_soc_dapm_sync_unlocked(dapm);
+
+ snd_soc_dapm_mutex_unlock(dapm);
}
static int spitz_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
-
- mutex_lock(&codec->mutex);
/* check the jack status at stream startup */
- spitz_ext_control(&codec->dapm);
-
- mutex_unlock(&codec->mutex);
+ spitz_ext_control(&rtd->card->dapm);
return 0;
}
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index 1d9c2ed223bc..4a956d1cb269 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -44,48 +44,46 @@
static int tosa_jack_func;
static int tosa_spk_func;
-static void tosa_ext_control(struct snd_soc_codec *codec)
+static void tosa_ext_control(struct snd_soc_dapm_context *dapm)
{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ snd_soc_dapm_mutex_lock(dapm);
/* set up jack connection */
switch (tosa_jack_func) {
case TOSA_HP:
- snd_soc_dapm_disable_pin(dapm, "Mic (Internal)");
- snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Mic (Internal)");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
break;
case TOSA_MIC_INT:
- snd_soc_dapm_enable_pin(dapm, "Mic (Internal)");
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Mic (Internal)");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
break;
case TOSA_HEADSET:
- snd_soc_dapm_disable_pin(dapm, "Mic (Internal)");
- snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_enable_pin(dapm, "Headset Jack");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Mic (Internal)");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack");
break;
}
if (tosa_spk_func == TOSA_SPK_ON)
- snd_soc_dapm_enable_pin(dapm, "Speaker");
+ snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker");
else
- snd_soc_dapm_disable_pin(dapm, "Speaker");
+ snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
+
+ snd_soc_dapm_sync_unlocked(dapm);
- snd_soc_dapm_sync(dapm);
+ snd_soc_dapm_mutex_unlock(dapm);
}
static int tosa_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
-
- mutex_lock(&codec->mutex);
/* check the jack status at stream startup */
- tosa_ext_control(codec);
-
- mutex_unlock(&codec->mutex);
+ tosa_ext_control(&rtd->card->dapm);
return 0;
}
@@ -104,13 +102,13 @@ static int tosa_get_jack(struct snd_kcontrol *kcontrol,
static int tosa_set_jack(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
if (tosa_jack_func == ucontrol->value.integer.value[0])
return 0;
tosa_jack_func = ucontrol->value.integer.value[0];
- tosa_ext_control(codec);
+ tosa_ext_control(&card->dapm);
return 1;
}
@@ -124,13 +122,13 @@ static int tosa_get_spk(struct snd_kcontrol *kcontrol,
static int tosa_set_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
if (tosa_spk_func == ucontrol->value.integer.value[0])
return 0;
tosa_spk_func = ucontrol->value.integer.value[0];
- tosa_ext_control(codec);
+ tosa_ext_control(&card->dapm);
return 1;
}
@@ -191,24 +189,10 @@ static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int err;
snd_soc_dapm_nc_pin(dapm, "OUT3");
snd_soc_dapm_nc_pin(dapm, "MONOOUT");
- /* add tosa specific controls */
- err = snd_soc_add_codec_controls(codec, tosa_controls,
- ARRAY_SIZE(tosa_controls));
- if (err < 0)
- return err;
-
- /* add tosa specific widgets */
- snd_soc_dapm_new_controls(dapm, tosa_dapm_widgets,
- ARRAY_SIZE(tosa_dapm_widgets));
-
- /* set up tosa specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
return 0;
}
@@ -239,6 +223,13 @@ static struct snd_soc_card tosa = {
.owner = THIS_MODULE,
.dai_link = tosa_dai,
.num_links = ARRAY_SIZE(tosa_dai),
+
+ .controls = tosa_controls,
+ .num_controls = ARRAY_SIZE(tosa_controls),
+ .dapm_widgets = tosa_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tosa_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static int tosa_probe(struct platform_device *pdev)
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c
index db8aadf8932d..23bf991e95d5 100644
--- a/sound/soc/pxa/zylonite.c
+++ b/sound/soc/pxa/zylonite.c
@@ -71,22 +71,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
if (clk_pout)
snd_soc_dai_set_pll(rtd->codec_dai, 0, 0,
clk_get_rate(pout), 0);
- snd_soc_dapm_new_controls(dapm, zylonite_dapm_widgets,
- ARRAY_SIZE(zylonite_dapm_widgets));
-
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- /* Static setup for now */
- snd_soc_dapm_enable_pin(dapm, "Headphone");
- snd_soc_dapm_enable_pin(dapm, "Headset Earpiece");
-
return 0;
}
@@ -256,6 +244,11 @@ static struct snd_soc_card zylonite = {
.resume_pre = &zylonite_resume_pre,
.dai_link = zylonite_dai,
.num_links = ARRAY_SIZE(zylonite_dai),
+
+ .dapm_widgets = zylonite_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(zylonite_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *zylonite_snd_ac97_device;
diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c
index 945e8abdc10f..0b21d1dc80c1 100644
--- a/sound/soc/s6000/s6105-ipcam.c
+++ b/sound/soc/s6000/s6105-ipcam.c
@@ -104,8 +104,8 @@ static int output_type_get(struct snd_kcontrol *kcontrol,
static int output_type_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = kcontrol->private_data;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_card *card = kcontrol->private_data;
+ struct snd_soc_dapm_context *dapm = &card->dapm;
unsigned int val = (ucontrol->value.enumerated.item[0] != 0);
char *differential = "Audio Out Differential";
char *stereo = "Audio Out Stereo";
@@ -137,13 +137,7 @@ static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- /* Add s6105 specific widgets */
- snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
- ARRAY_SIZE(aic3x_dapm_widgets));
-
- /* Set up s6105 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+ struct snd_soc_card *card = rtd->card;
/* not present */
snd_soc_dapm_nc_pin(dapm, "MONO_LOUT");
@@ -157,17 +151,10 @@ static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "RLOUT");
snd_soc_dapm_nc_pin(dapm, "HPRCOM");
- /* always connected */
- snd_soc_dapm_enable_pin(dapm, "Audio In");
-
/* must correspond to audio_out_mux.private_value initializer */
- snd_soc_dapm_disable_pin(dapm, "Audio Out Differential");
- snd_soc_dapm_sync(dapm);
- snd_soc_dapm_enable_pin(dapm, "Audio Out Stereo");
-
- snd_soc_dapm_sync(dapm);
+ snd_soc_dapm_disable_pin(&card->dapm, "Audio Out Differential");
- snd_ctl_add(codec->card->snd_card, snd_ctl_new1(&audio_out_mux, codec));
+ snd_ctl_add(card->snd_card, snd_ctl_new1(&audio_out_mux, card));
return 0;
}
@@ -190,6 +177,11 @@ static struct snd_soc_card snd_soc_card_s6105 = {
.owner = THIS_MODULE,
.dai_link = &s6105_dai,
.num_links = 1,
+
+ .dapm_widgets = aic3x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct s6000_snd_platform_data s6105_snd_data __initdata = {
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 454f41cfc828..f2e289180e46 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -59,7 +59,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
select SND_SOC_WM8750
select SND_S3C2412_SOC_I2S
help
- Sat Y if you want to add support for SoC audio on the Jive.
+ Say Y if you want to add support for SoC audio on the Jive.
config SND_SOC_SAMSUNG_SMDK_WM8580
tristate "SoC I2S Audio support for WM8580 on SMDK"
@@ -117,7 +117,7 @@ config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
select SND_S3C24XX_I2S
- select SND_SOC_TLV320AIC23
+ select SND_SOC_TLV320AIC23_I2C
select SND_SOC_SAMSUNG_SIMTEC
config SND_SOC_SAMSUNG_SIMTEC_HERMES
@@ -145,11 +145,11 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380
config SND_SOC_SAMSUNG_SMDK_WM9713
tristate "SoC AC97 Audio support for SMDK with WM9713"
- depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 || MACH_SMDKV310 || MACH_SMDKC210)
+ depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
select SND_SOC_WM9713
select SND_SAMSUNG_AC97
help
- Sat Y if you want to add support for SoC audio on the SMDK.
+ Say Y if you want to add support for SoC audio on the SMDK.
config SND_SOC_SMARTQ
tristate "SoC I2S Audio support for SmartQ board"
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
index fbced589d077..88b09e022503 100644
--- a/sound/soc/samsung/h1940_uda1380.c
+++ b/sound/soc/samsung/h1940_uda1380.c
@@ -66,10 +66,6 @@ static int h1940_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- runtime->hw.rate_min = hw_rates.list[0];
- runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
- runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
-
return snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&hw_rates);
@@ -94,7 +90,7 @@ static int h1940_hw_params(struct snd_pcm_substream *substream,
div++;
break;
default:
- dev_err(&rtd->dev, "%s: rate %d is not supported\n",
+ dev_err(rtd->dev, "%s: rate %d is not supported\n",
__func__, rate);
return -EINVAL;
}
@@ -181,7 +177,6 @@ static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int err;
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
snd_soc_dapm_enable_pin(dapm, "Speaker");
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index 98a04c11202d..b0800337b79e 100644
--- a/sound/soc/samsung/neo1973_wm8753.c
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -192,44 +192,6 @@ static struct snd_soc_ops neo1973_voice_ops = {
.hw_free = neo1973_voice_hw_free,
};
-/* Shared routes and controls */
-
-static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = {
- SND_SOC_DAPM_LINE("GSM Line Out", NULL),
- SND_SOC_DAPM_LINE("GSM Line In", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_MIC("Handset Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = {
- /* Connections to the GSM Module */
- {"GSM Line Out", NULL, "MONO1"},
- {"GSM Line Out", NULL, "MONO2"},
- {"RXP", NULL, "GSM Line In"},
- {"RXN", NULL, "GSM Line In"},
-
- /* Connections to Headset */
- {"MIC1", NULL, "Mic Bias"},
- {"Mic Bias", NULL, "Headset Mic"},
-
- /* Call Mic */
- {"MIC2", NULL, "Mic Bias"},
- {"MIC2N", NULL, "Mic Bias"},
- {"Mic Bias", NULL, "Handset Mic"},
-
- /* Connect the ALC pins */
- {"ACIN", NULL, "ACOP"},
-};
-
-static const struct snd_kcontrol_new neo1973_wm8753_controls[] = {
- SOC_DAPM_PIN_SWITCH("GSM Line Out"),
- SOC_DAPM_PIN_SWITCH("GSM Line In"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Handset Mic"),
-};
-
-/* GTA02 specific routes and controls */
-
static int gta02_speaker_enabled;
static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
@@ -257,7 +219,34 @@ static int lm4853_event(struct snd_soc_dapm_widget *w,
return 0;
}
-static const struct snd_soc_dapm_route neo1973_gta02_routes[] = {
+static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+ SND_SOC_DAPM_LINE("GSM Line In", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_SPK("Handset Spk", NULL),
+ SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
+};
+
+static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = {
+ /* Connections to the GSM Module */
+ {"GSM Line Out", NULL, "MONO1"},
+ {"GSM Line Out", NULL, "MONO2"},
+ {"RXP", NULL, "GSM Line In"},
+ {"RXN", NULL, "GSM Line In"},
+
+ /* Connections to Headset */
+ {"MIC1", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Headset Mic"},
+
+ /* Call Mic */
+ {"MIC2", NULL, "Mic Bias"},
+ {"MIC2N", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Handset Mic"},
+
+ /* Connect the ALC pins */
+ {"ACIN", NULL, "ACOP"},
+
/* Connections to the amp */
{"Stereo Out", NULL, "LOUT1"},
{"Stereo Out", NULL, "ROUT1"},
@@ -267,7 +256,11 @@ static const struct snd_soc_dapm_route neo1973_gta02_routes[] = {
{"Handset Spk", NULL, "ROUT2"},
};
-static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = {
+static const struct snd_kcontrol_new neo1973_wm8753_controls[] = {
+ SOC_DAPM_PIN_SWITCH("GSM Line Out"),
+ SOC_DAPM_PIN_SWITCH("GSM Line In"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Handset Mic"),
SOC_DAPM_PIN_SWITCH("Handset Spk"),
SOC_DAPM_PIN_SWITCH("Stereo Out"),
@@ -276,86 +269,32 @@ static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = {
lm4853_set_spk),
};
-static const struct snd_soc_dapm_widget neo1973_gta02_wm8753_dapm_widgets[] = {
- SND_SOC_DAPM_SPK("Handset Spk", NULL),
- SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
-};
-
-static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
-{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
-
- ret = snd_soc_dapm_new_controls(dapm, neo1973_gta02_wm8753_dapm_widgets,
- ARRAY_SIZE(neo1973_gta02_wm8753_dapm_widgets));
- if (ret)
- return ret;
-
- ret = snd_soc_dapm_add_routes(dapm, neo1973_gta02_routes,
- ARRAY_SIZE(neo1973_gta02_routes));
- if (ret)
- return ret;
-
- ret = snd_soc_add_card_controls(codec->card, neo1973_gta02_wm8753_controls,
- ARRAY_SIZE(neo1973_gta02_wm8753_controls));
- if (ret)
- return ret;
-
- snd_soc_dapm_disable_pin(dapm, "Stereo Out");
- snd_soc_dapm_disable_pin(dapm, "Handset Spk");
- snd_soc_dapm_ignore_suspend(dapm, "Stereo Out");
- snd_soc_dapm_ignore_suspend(dapm, "Handset Spk");
-
- return 0;
-}
-
static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
+ struct snd_soc_card *card = rtd->card;
/* set up NC codec pins */
- snd_soc_dapm_nc_pin(dapm, "OUT3");
- snd_soc_dapm_nc_pin(dapm, "OUT4");
- snd_soc_dapm_nc_pin(dapm, "LINE1");
- snd_soc_dapm_nc_pin(dapm, "LINE2");
-
- /* Add neo1973 specific widgets */
- ret = snd_soc_dapm_new_controls(dapm, neo1973_wm8753_dapm_widgets,
- ARRAY_SIZE(neo1973_wm8753_dapm_widgets));
- if (ret)
- return ret;
-
- /* add neo1973 specific controls */
- ret = snd_soc_add_card_controls(rtd->card, neo1973_wm8753_controls,
- ARRAY_SIZE(neo1973_wm8753_controls));
- if (ret)
- return ret;
-
- /* set up neo1973 specific audio routes */
- ret = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes,
- ARRAY_SIZE(neo1973_wm8753_routes));
- if (ret)
- return ret;
+ snd_soc_dapm_nc_pin(&codec->dapm, "OUT3");
+ snd_soc_dapm_nc_pin(&codec->dapm, "OUT4");
+ snd_soc_dapm_nc_pin(&codec->dapm, "LINE1");
+ snd_soc_dapm_nc_pin(&codec->dapm, "LINE2");
/* set endpoints to default off mode */
- snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line In");
- snd_soc_dapm_disable_pin(dapm, "Headset Mic");
- snd_soc_dapm_disable_pin(dapm, "Handset Mic");
+ snd_soc_dapm_disable_pin(&card->dapm, "GSM Line Out");
+ snd_soc_dapm_disable_pin(&card->dapm, "GSM Line In");
+ snd_soc_dapm_disable_pin(&card->dapm, "Headset Mic");
+ snd_soc_dapm_disable_pin(&card->dapm, "Handset Mic");
+ snd_soc_dapm_disable_pin(&card->dapm, "Stereo Out");
+ snd_soc_dapm_disable_pin(&card->dapm, "Handset Spk");
/* allow audio paths from the GSM modem to run during suspend */
- snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out");
- snd_soc_dapm_ignore_suspend(dapm, "GSM Line In");
- snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
- snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
-
- if (machine_is_neo1973_gta02()) {
- ret = neo1973_gta02_wm8753_init(codec);
- if (ret)
- return ret;
- }
+ snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line Out");
+ snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line In");
+ snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic");
+ snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Mic");
+ snd_soc_dapm_ignore_suspend(&card->dapm, "Stereo Out");
+ snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Spk");
return 0;
}
@@ -409,6 +348,13 @@ static struct snd_soc_card neo1973 = {
.num_aux_devs = ARRAY_SIZE(neo1973_aux_devs),
.codec_conf = neo1973_codec_conf,
.num_configs = ARRAY_SIZE(neo1973_codec_conf),
+
+ .controls = neo1973_wm8753_controls,
+ .num_controls = ARRAY_SIZE(neo1973_wm8753_controls),
+ .dapm_widgets = neo1973_wm8753_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(neo1973_wm8753_dapm_widgets),
+ .dapm_routes = neo1973_wm8753_routes,
+ .num_dapm_routes = ARRAY_SIZE(neo1973_wm8753_routes),
};
static struct platform_device *neo1973_snd_device;
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
index 06ebdc061770..2982d9e7f268 100644
--- a/sound/soc/samsung/rx1950_uda1380.c
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -131,10 +131,6 @@ static int rx1950_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- runtime->hw.rate_min = hw_rates.list[0];
- runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
- runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
-
return snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&hw_rates);
@@ -226,7 +222,6 @@ static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int err;
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
snd_soc_dapm_enable_pin(dapm, "Speaker");
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c
index d38ae98e2f32..682eb4f7ba0c 100644
--- a/sound/soc/samsung/smdk_wm8994.c
+++ b/sound/soc/samsung/smdk_wm8994.c
@@ -202,7 +202,7 @@ static int smdk_audio_probe(struct platform_device *pdev)
static struct platform_driver smdk_audio_driver = {
.driver = {
- .name = "smdk-audio-wm8894",
+ .name = "smdk-audio-wm8994",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(samsung_wm8994_of_match),
.pm = &snd_soc_pm_ops,
diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c
index f21ff608a819..1807b75ccc12 100644
--- a/sound/soc/samsung/tobermory.c
+++ b/sound/soc/samsung/tobermory.c
@@ -44,6 +44,8 @@ static int tobermory_set_bias_level(struct snd_soc_card *card,
SND_SOC_CLOCK_IN);
if (ret < 0) {
pr_err("Failed to set SYSCLK: %d\n", ret);
+ snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
+ 0, 0, 0);
return ret;
}
}
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 1967f44e7cd4..710a079a7377 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1711,9 +1711,9 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
- fsi->clk_master = 1;
break;
case SND_SOC_DAIFMT_CBS_CFS:
+ fsi->clk_master = 1; /* codec is slave, cpu is master */
break;
default:
return -EINVAL;
diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c
index 5014a884afee..c58c2529f103 100644
--- a/sound/soc/sh/migor.c
+++ b/sound/soc/sh/migor.c
@@ -136,19 +136,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{ "Mic Bias", NULL, "External Microphone" },
};
-static int migor_dai_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- snd_soc_dapm_new_controls(dapm, migor_dapm_widgets,
- ARRAY_SIZE(migor_dapm_widgets));
-
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- return 0;
-}
-
/* migor digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link migor_dai = {
.name = "wm8978",
@@ -158,7 +145,6 @@ static struct snd_soc_dai_link migor_dai = {
.platform_name = "siu-pcm-audio",
.codec_name = "wm8978.0-001a",
.ops = &migor_dai_ops,
- .init = migor_dai_init,
};
/* migor audio machine driver */
@@ -167,6 +153,11 @@ static struct snd_soc_card snd_soc_migor = {
.owner = THIS_MODULE,
.dai_link = &migor_dai,
.num_links = 1,
+
+ .dapm_widgets = migor_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(migor_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *migor_snd_device;
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
index 0ff492df7929..7d0051ced838 100644
--- a/sound/soc/sh/rcar/Makefile
+++ b/sound/soc/sh/rcar/Makefile
@@ -1,2 +1,2 @@
-snd-soc-rcar-objs := core.o gen.o scu.o adg.o ssi.o
+snd-soc-rcar-objs := core.o gen.o src.o adg.o ssi.o
obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index a53235c4d1b0..69c44269ebdb 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -25,15 +25,165 @@ struct rsnd_adg {
};
#define for_each_rsnd_clk(pos, adg, i) \
- for (i = 0, (pos) = adg->clk[i]; \
- i < CLKMAX; \
- i++, (pos) = adg->clk[i])
+ for (i = 0; \
+ (i < CLKMAX) && \
+ ((pos) = adg->clk[i]); \
+ i++)
#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
-static int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- unsigned int src_rate,
- unsigned int dst_rate)
+
+static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
+{
+ struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ int id = rsnd_mod_id(mod);
+ int ws = id;
+
+ if (rsnd_ssi_is_pin_sharing(rsnd_ssi_mod_get(priv, id))) {
+ switch (id) {
+ case 1:
+ case 2:
+ ws = 0;
+ break;
+ case 4:
+ ws = 3;
+ break;
+ case 8:
+ ws = 7;
+ break;
+ }
+ }
+
+ return (0x6 + ws) << 8;
+}
+
+static int rsnd_adg_set_src_timsel_gen2(struct rsnd_dai *rdai,
+ struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ u32 timsel)
+{
+ int is_play = rsnd_dai_is_play(rdai, io);
+ int id = rsnd_mod_id(mod);
+ int shift = (id % 2) ? 16 : 0;
+ u32 mask, ws;
+ u32 in, out;
+
+ ws = rsnd_adg_ssi_ws_timing_gen2(io);
+
+ in = (is_play) ? timsel : ws;
+ out = (is_play) ? ws : timsel;
+
+ in = in << shift;
+ out = out << shift;
+ mask = 0xffff << shift;
+
+ switch (id / 2) {
+ case 0:
+ rsnd_mod_bset(mod, SRCIN_TIMSEL0, mask, in);
+ rsnd_mod_bset(mod, SRCOUT_TIMSEL0, mask, out);
+ break;
+ case 1:
+ rsnd_mod_bset(mod, SRCIN_TIMSEL1, mask, in);
+ rsnd_mod_bset(mod, SRCOUT_TIMSEL1, mask, out);
+ break;
+ case 2:
+ rsnd_mod_bset(mod, SRCIN_TIMSEL2, mask, in);
+ rsnd_mod_bset(mod, SRCOUT_TIMSEL2, mask, out);
+ break;
+ case 3:
+ rsnd_mod_bset(mod, SRCIN_TIMSEL3, mask, in);
+ rsnd_mod_bset(mod, SRCOUT_TIMSEL3, mask, out);
+ break;
+ case 4:
+ rsnd_mod_bset(mod, SRCIN_TIMSEL4, mask, in);
+ rsnd_mod_bset(mod, SRCOUT_TIMSEL4, mask, out);
+ break;
+ }
+
+ return 0;
+}
+
+int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io,
+ unsigned int src_rate,
+ unsigned int dst_rate)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ int idx, sel, div, step, ret;
+ u32 val, en;
+ unsigned int min, diff;
+ unsigned int sel_rate [] = {
+ clk_get_rate(adg->clk[CLKA]), /* 0000: CLKA */
+ clk_get_rate(adg->clk[CLKB]), /* 0001: CLKB */
+ clk_get_rate(adg->clk[CLKC]), /* 0010: CLKC */
+ adg->rbga_rate_for_441khz_div_6,/* 0011: RBGA */
+ adg->rbgb_rate_for_48khz_div_6, /* 0100: RBGB */
+ };
+
+ min = ~0;
+ val = 0;
+ en = 0;
+ for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
+ idx = 0;
+ step = 2;
+
+ if (!sel_rate[sel])
+ continue;
+
+ for (div = 2; div <= 98304; div += step) {
+ diff = abs(src_rate - sel_rate[sel] / div);
+ if (min > diff) {
+ val = (sel << 8) | idx;
+ min = diff;
+ en = 1 << (sel + 1); /* fixme */
+ }
+
+ /*
+ * step of 0_0000 / 0_0001 / 0_1101
+ * are out of order
+ */
+ if ((idx > 2) && (idx % 2))
+ step *= 2;
+ if (idx == 0x1c) {
+ div += step;
+ step *= 2;
+ }
+ idx++;
+ }
+ }
+
+ if (min == ~0) {
+ dev_err(dev, "no Input clock\n");
+ return -EIO;
+ }
+
+ ret = rsnd_adg_set_src_timsel_gen2(rdai, mod, io, val);
+ if (ret < 0) {
+ dev_err(dev, "timsel error\n");
+ return ret;
+ }
+
+ rsnd_mod_bset(mod, DIV_EN, en, en);
+
+ return 0;
+}
+
+int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ u32 val = rsnd_adg_ssi_ws_timing_gen2(io);
+
+ return rsnd_adg_set_src_timsel_gen2(rdai, mod, io, val);
+}
+
+int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
+ struct rsnd_mod *mod,
+ unsigned int src_rate,
+ unsigned int dst_rate)
{
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct device *dev = rsnd_priv_to_dev(priv);
@@ -91,18 +241,6 @@ find_rate:
return 0;
}
-int rsnd_adg_set_convert_clk(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- unsigned int src_rate,
- unsigned int dst_rate)
-{
- if (rsnd_is_gen1(priv))
- return rsnd_adg_set_convert_clk_gen1(priv, mod,
- src_rate, dst_rate);
-
- return -EINVAL;
-}
-
static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val)
{
int id = rsnd_mod_id(mod);
@@ -254,13 +392,14 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
}
int rsnd_adg_probe(struct platform_device *pdev,
- struct rcar_snd_info *info,
+ const struct rsnd_of_data *of_data,
struct rsnd_priv *priv)
{
struct rsnd_adg *adg;
struct device *dev = rsnd_priv_to_dev(priv);
- struct clk *clk;
+ struct clk *clk, *clk_orig;
int i;
+ bool use_old_style = false;
adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
if (!adg) {
@@ -268,10 +407,39 @@ int rsnd_adg_probe(struct platform_device *pdev,
return -ENOMEM;
}
- adg->clk[CLKA] = clk_get(NULL, "audio_clk_a");
- adg->clk[CLKB] = clk_get(NULL, "audio_clk_b");
- adg->clk[CLKC] = clk_get(NULL, "audio_clk_c");
- adg->clk[CLKI] = clk_get(NULL, "audio_clk_internal");
+ clk_orig = devm_clk_get(dev, NULL);
+ adg->clk[CLKA] = devm_clk_get(dev, "clk_a");
+ adg->clk[CLKB] = devm_clk_get(dev, "clk_b");
+ adg->clk[CLKC] = devm_clk_get(dev, "clk_c");
+ adg->clk[CLKI] = devm_clk_get(dev, "clk_i");
+
+ /*
+ * It request device dependent audio clock.
+ * But above all clks will indicate rsnd module clock
+ * if platform doesn't it
+ */
+ for_each_rsnd_clk(clk, adg, i) {
+ if (clk_orig == clk) {
+ dev_warn(dev,
+ "doesn't have device dependent clock, use independent clock\n");
+ use_old_style = true;
+ break;
+ }
+ }
+
+ /*
+ * note:
+ * these exist in order to keep compatible with
+ * platform which has device independent audio clock,
+ * but will be removed soon
+ */
+ if (use_old_style) {
+ adg->clk[CLKA] = devm_clk_get(NULL, "audio_clk_a");
+ adg->clk[CLKB] = devm_clk_get(NULL, "audio_clk_b");
+ adg->clk[CLKC] = devm_clk_get(NULL, "audio_clk_c");
+ adg->clk[CLKI] = devm_clk_get(NULL, "audio_clk_internal");
+ }
+
for_each_rsnd_clk(clk, adg, i) {
if (IS_ERR(clk)) {
dev_err(dev, "Audio clock failed\n");
@@ -287,14 +455,3 @@ int rsnd_adg_probe(struct platform_device *pdev,
return 0;
}
-
-void rsnd_adg_remove(struct platform_device *pdev,
- struct rsnd_priv *priv)
-{
- struct rsnd_adg *adg = priv->adg;
- struct clk *clk;
- int i;
-
- for_each_rsnd_clk(clk, adg, i)
- clk_put(clk);
-}
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 743de5e3b1e1..215b668166be 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -73,13 +73,13 @@
* | +- ssi[2]
* | ...
* |
- * | ** these control scu
+ * | ** these control src
* |
- * +- scu
+ * +- src
* |
- * +- scu[0]
- * +- scu[1]
- * +- scu[2]
+ * +- src[0]
+ * +- src[1]
+ * +- src[2]
* ...
*
*
@@ -100,6 +100,21 @@
#define RSND_RATES SNDRV_PCM_RATE_8000_96000
#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
+static struct rsnd_of_data rsnd_of_data_gen1 = {
+ .flags = RSND_GEN1,
+};
+
+static struct rsnd_of_data rsnd_of_data_gen2 = {
+ .flags = RSND_GEN2,
+};
+
+static struct of_device_id rsnd_of_match[] = {
+ { .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 },
+ { .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rsnd_of_match);
+
/*
* rsnd_platform functions
*/
@@ -107,6 +122,11 @@
(!(priv->info->func) ? 0 : \
priv->info->func(param))
+#define rsnd_is_enable_path(io, name) \
+ ((io)->info ? (io)->info->name : NULL)
+#define rsnd_info_id(priv, io, name) \
+ ((io)->info->name - priv->info->name##_info)
+
/*
* rsnd_mod functions
*/
@@ -121,17 +141,19 @@ char *rsnd_mod_name(struct rsnd_mod *mod)
void rsnd_mod_init(struct rsnd_priv *priv,
struct rsnd_mod *mod,
struct rsnd_mod_ops *ops,
+ enum rsnd_mod_type type,
int id)
{
mod->priv = priv;
mod->id = id;
mod->ops = ops;
- INIT_LIST_HEAD(&mod->list);
+ mod->type = type;
}
/*
* rsnd_dma functions
*/
+static void __rsnd_dma_start(struct rsnd_dma *dma);
static void rsnd_dma_continue(struct rsnd_dma *dma)
{
/* push next A or B plane */
@@ -142,8 +164,9 @@ static void rsnd_dma_continue(struct rsnd_dma *dma)
void rsnd_dma_start(struct rsnd_dma *dma)
{
/* push both A and B plane*/
+ dma->offset = 0;
dma->submit_loop = 2;
- schedule_work(&dma->work);
+ __rsnd_dma_start(dma);
}
void rsnd_dma_stop(struct rsnd_dma *dma)
@@ -156,12 +179,26 @@ void rsnd_dma_stop(struct rsnd_dma *dma)
static void rsnd_dma_complete(void *data)
{
struct rsnd_dma *dma = (struct rsnd_dma *)data;
- struct rsnd_priv *priv = dma->priv;
+ struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(rsnd_dma_to_mod(dma));
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
unsigned long flags;
rsnd_lock(priv, flags);
- dma->complete(dma);
+ /*
+ * Renesas sound Gen1 needs 1 DMAC,
+ * Gen2 needs 2 DMAC.
+ * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri.
+ * But, Audio-DMAC-peri-peri doesn't have interrupt,
+ * and this driver is assuming that here.
+ *
+ * If Audio-DMAC-peri-peri has interrpt,
+ * rsnd_dai_pointer_update() will be called twice,
+ * ant it will breaks io->byte_pos
+ */
+
+ rsnd_dai_pointer_update(io, io->byte_per_period);
if (dma->submit_loop)
rsnd_dma_continue(dma);
@@ -169,20 +206,23 @@ static void rsnd_dma_complete(void *data)
rsnd_unlock(priv, flags);
}
-static void rsnd_dma_do_work(struct work_struct *work)
+static void __rsnd_dma_start(struct rsnd_dma *dma)
{
- struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work);
- struct rsnd_priv *priv = dma->priv;
+ struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct device *dev = rsnd_priv_to_dev(priv);
struct dma_async_tx_descriptor *desc;
dma_addr_t buf;
- size_t len;
+ size_t len = io->byte_per_period;
int i;
for (i = 0; i < dma->submit_loop; i++) {
- if (dma->inquiry(dma, &buf, &len) < 0)
- return;
+ buf = runtime->dma_addr +
+ rsnd_dai_pointer_offset(io, dma->offset + len);
+ dma->offset = len;
desc = dmaengine_prep_slave_single(
dma->chan, buf, len, dma->dir,
@@ -204,16 +244,20 @@ static void rsnd_dma_do_work(struct work_struct *work)
}
}
+static void rsnd_dma_do_work(struct work_struct *work)
+{
+ struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work);
+
+ __rsnd_dma_start(dma);
+}
+
int rsnd_dma_available(struct rsnd_dma *dma)
{
return !!dma->chan;
}
int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
- int is_play, int id,
- int (*inquiry)(struct rsnd_dma *dma,
- dma_addr_t *buf, int *len),
- int (*complete)(struct rsnd_dma *dma))
+ int is_play, int id)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct dma_slave_config cfg;
@@ -246,9 +290,6 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
goto rsnd_dma_init_err;
dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
- dma->priv = priv;
- dma->inquiry = inquiry;
- dma->complete = complete;
INIT_WORK(&dma->work, rsnd_dma_do_work);
return 0;
@@ -271,26 +312,42 @@ void rsnd_dma_quit(struct rsnd_priv *priv,
/*
* rsnd_dai functions
*/
-#define rsnd_dai_call(rdai, io, fn) \
-({ \
- struct rsnd_mod *mod, *n; \
- int ret = 0; \
- for_each_rsnd_mod(mod, n, io) { \
- ret = rsnd_mod_call(mod, fn, rdai, io); \
- if (ret < 0) \
- break; \
- } \
- ret; \
+#define __rsnd_mod_call(mod, func, rdai, io) \
+({ \
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \
+ struct device *dev = rsnd_priv_to_dev(priv); \
+ dev_dbg(dev, "%s [%d] %s\n", \
+ rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \
+ (mod)->ops->func(mod, rdai, io); \
+})
+
+#define rsnd_mod_call(mod, func, rdai, io) \
+ (!(mod) ? -ENODEV : \
+ !((mod)->ops->func) ? 0 : \
+ __rsnd_mod_call(mod, func, (rdai), (io)))
+
+#define rsnd_dai_call(rdai, io, fn) \
+({ \
+ struct rsnd_mod *mod; \
+ int ret = 0, i; \
+ for (i = 0; i < RSND_MOD_MAX; i++) { \
+ mod = (io)->mod[i]; \
+ if (!mod) \
+ continue; \
+ ret = rsnd_mod_call(mod, fn, (rdai), (io)); \
+ if (ret < 0) \
+ break; \
+ } \
+ ret; \
})
-int rsnd_dai_connect(struct rsnd_dai *rdai,
- struct rsnd_mod *mod,
- struct rsnd_dai_stream *io)
+static int rsnd_dai_connect(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io)
{
if (!mod)
return -EIO;
- if (!list_empty(&mod->list)) {
+ if (io->mod[mod->type]) {
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
@@ -300,14 +357,8 @@ int rsnd_dai_connect(struct rsnd_dai *rdai,
return -EIO;
}
- list_add_tail(&mod->list, &io->head);
-
- return 0;
-}
-
-int rsnd_dai_disconnect(struct rsnd_mod *mod)
-{
- list_del_init(&mod->list);
+ io->mod[mod->type] = mod;
+ mod->io = io;
return 0;
}
@@ -316,7 +367,7 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)
{
int id = rdai - priv->rdai;
- if ((id < 0) || (id >= rsnd_dai_nr(priv)))
+ if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
return -EINVAL;
return id;
@@ -324,7 +375,7 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)
struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id)
{
- if ((id < 0) || (id >= rsnd_dai_nr(priv)))
+ if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
return NULL;
return priv->rdai + id;
@@ -382,10 +433,6 @@ static int rsnd_dai_stream_init(struct rsnd_dai_stream *io,
{
struct snd_pcm_runtime *runtime = substream->runtime;
- if (!list_empty(&io->head))
- return -EIO;
-
- INIT_LIST_HEAD(&io->head);
io->substream = substream;
io->byte_pos = 0;
io->period_pos = 0;
@@ -440,10 +487,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
if (ret < 0)
goto dai_trigger_end;
- ret = rsnd_gen_path_init(priv, rdai, io);
- if (ret < 0)
- goto dai_trigger_end;
-
ret = rsnd_dai_call(rdai, io, init);
if (ret < 0)
goto dai_trigger_end;
@@ -461,10 +504,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
if (ret < 0)
goto dai_trigger_end;
- ret = rsnd_gen_path_exit(priv, rdai, io);
- if (ret < 0)
- goto dai_trigger_end;
-
ret = rsnd_platform_call(priv, dai, stop, ssi_id);
if (ret < 0)
goto dai_trigger_end;
@@ -486,10 +525,10 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
- rdai->clk_master = 1;
+ rdai->clk_master = 0;
break;
case SND_SOC_DAIFMT_CBS_CFS:
- rdai->clk_master = 0;
+ rdai->clk_master = 1; /* codec is slave, cpu is master */
break;
default:
return -EINVAL;
@@ -540,24 +579,174 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
.set_fmt = rsnd_soc_dai_set_fmt,
};
+static int rsnd_path_init(struct rsnd_priv *priv,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_mod *mod;
+ struct rsnd_dai_platform_info *dai_info = rdai->info;
+ int ret;
+ int ssi_id = -1;
+ int src_id = -1;
+
+ /*
+ * Gen1 is created by SRU/SSI, and this SRU is base module of
+ * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
+ *
+ * Easy image is..
+ * Gen1 SRU = Gen2 SCU + SSIU + etc
+ *
+ * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
+ * using fixed path.
+ */
+ if (dai_info) {
+ if (rsnd_is_enable_path(io, ssi))
+ ssi_id = rsnd_info_id(priv, io, ssi);
+ if (rsnd_is_enable_path(io, src))
+ src_id = rsnd_info_id(priv, io, src);
+ } else {
+ /* get SSI's ID */
+ mod = rsnd_ssi_mod_get_frm_dai(priv,
+ rsnd_dai_id(priv, rdai),
+ rsnd_dai_is_play(rdai, io));
+ if (!mod)
+ return 0;
+ ssi_id = src_id = rsnd_mod_id(mod);
+ }
+
+ ret = 0;
+
+ /* SRC */
+ if (src_id >= 0) {
+ mod = rsnd_src_mod_get(priv, src_id);
+ ret = rsnd_dai_connect(mod, io);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* SSI */
+ if (ssi_id >= 0) {
+ mod = rsnd_ssi_mod_get(priv, ssi_id);
+ ret = rsnd_dai_connect(mod, io);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+static void rsnd_of_parse_dai(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv)
+{
+ struct device_node *dai_node, *dai_np;
+ struct device_node *ssi_node, *ssi_np;
+ struct device_node *src_node, *src_np;
+ struct device_node *playback, *capture;
+ struct rsnd_dai_platform_info *dai_info;
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct device *dev = &pdev->dev;
+ int nr, i;
+ int dai_i, ssi_i, src_i;
+
+ if (!of_data)
+ return;
+
+ dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai");
+ if (!dai_node)
+ return;
+
+ nr = of_get_child_count(dai_node);
+ if (!nr)
+ return;
+
+ dai_info = devm_kzalloc(dev,
+ sizeof(struct rsnd_dai_platform_info) * nr,
+ GFP_KERNEL);
+ if (!dai_info) {
+ dev_err(dev, "dai info allocation error\n");
+ return;
+ }
+
+ info->dai_info_nr = nr;
+ info->dai_info = dai_info;
+
+ ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
+ src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
+
+#define mod_parse(name) \
+if (name##_node) { \
+ struct rsnd_##name##_platform_info *name##_info; \
+ \
+ name##_i = 0; \
+ for_each_child_of_node(name##_node, name##_np) { \
+ name##_info = info->name##_info + name##_i; \
+ \
+ if (name##_np == playback) \
+ dai_info->playback.name = name##_info; \
+ if (name##_np == capture) \
+ dai_info->capture.name = name##_info; \
+ \
+ name##_i++; \
+ } \
+}
+
+ /*
+ * parse all dai
+ */
+ dai_i = 0;
+ for_each_child_of_node(dai_node, dai_np) {
+ dai_info = info->dai_info + dai_i;
+
+ for (i = 0;; i++) {
+
+ playback = of_parse_phandle(dai_np, "playback", i);
+ capture = of_parse_phandle(dai_np, "capture", i);
+
+ if (!playback && !capture)
+ break;
+
+ mod_parse(ssi);
+ mod_parse(src);
+
+ if (playback)
+ of_node_put(playback);
+ if (capture)
+ of_node_put(capture);
+ }
+
+ dai_i++;
+ }
+}
+
static int rsnd_dai_probe(struct platform_device *pdev,
- struct rcar_snd_info *info,
+ const struct rsnd_of_data *of_data,
struct rsnd_priv *priv)
{
struct snd_soc_dai_driver *drv;
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
struct rsnd_dai *rdai;
struct rsnd_mod *pmod, *cmod;
struct device *dev = rsnd_priv_to_dev(priv);
int dai_nr;
int i;
- /* get max dai nr */
- for (dai_nr = 0; dai_nr < 32; dai_nr++) {
- pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1);
- cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0);
+ rsnd_of_parse_dai(pdev, of_data, priv);
- if (!pmod && !cmod)
- break;
+ /*
+ * dai_nr should be set via dai_info_nr,
+ * but allow it to keeping compatible
+ */
+ dai_nr = info->dai_info_nr;
+ if (!dai_nr) {
+ /* get max dai nr */
+ for (dai_nr = 0; dai_nr < 32; dai_nr++) {
+ pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1);
+ cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0);
+
+ if (!pmod && !cmod)
+ break;
+ }
}
if (!dai_nr) {
@@ -572,7 +761,13 @@ static int rsnd_dai_probe(struct platform_device *pdev,
return -ENOMEM;
}
+ priv->rdai_nr = dai_nr;
+ priv->daidrv = drv;
+ priv->rdai = rdai;
+
for (i = 0; i < dai_nr; i++) {
+ if (info->dai_info)
+ rdai[i].info = &info->dai_info[i];
pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1);
cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0);
@@ -580,9 +775,6 @@ static int rsnd_dai_probe(struct platform_device *pdev,
/*
* init rsnd_dai
*/
- INIT_LIST_HEAD(&rdai[i].playback.head);
- INIT_LIST_HEAD(&rdai[i].capture.head);
-
snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);
/*
@@ -595,12 +787,20 @@ static int rsnd_dai_probe(struct platform_device *pdev,
drv[i].playback.formats = RSND_FMTS;
drv[i].playback.channels_min = 2;
drv[i].playback.channels_max = 2;
+
+ if (info->dai_info)
+ rdai[i].playback.info = &info->dai_info[i].playback;
+ rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
}
if (cmod) {
drv[i].capture.rates = RSND_RATES;
drv[i].capture.formats = RSND_FMTS;
drv[i].capture.channels_min = 2;
drv[i].capture.channels_max = 2;
+
+ if (info->dai_info)
+ rdai[i].capture.info = &info->dai_info[i].capture;
+ rsnd_path_init(priv, &rdai[i], &rdai[i].capture);
}
dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name,
@@ -608,18 +808,9 @@ static int rsnd_dai_probe(struct platform_device *pdev,
cmod ? "capture" : " -- ");
}
- priv->dai_nr = dai_nr;
- priv->daidrv = drv;
- priv->rdai = rdai;
-
return 0;
}
-static void rsnd_dai_remove(struct platform_device *pdev,
- struct rsnd_priv *priv)
-{
-}
-
/*
* pcm ops
*/
@@ -713,9 +904,30 @@ static int rsnd_probe(struct platform_device *pdev)
struct rcar_snd_info *info;
struct rsnd_priv *priv;
struct device *dev = &pdev->dev;
- int ret;
+ struct rsnd_dai *rdai;
+ const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev);
+ const struct rsnd_of_data *of_data;
+ int (*probe_func[])(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv) = {
+ rsnd_gen_probe,
+ rsnd_ssi_probe,
+ rsnd_src_probe,
+ rsnd_adg_probe,
+ rsnd_dai_probe,
+ };
+ int ret, i;
+
+ info = NULL;
+ of_data = NULL;
+ if (of_id) {
+ info = devm_kzalloc(&pdev->dev,
+ sizeof(struct rcar_snd_info), GFP_KERNEL);
+ of_data = of_id->data;
+ } else {
+ info = pdev->dev.platform_data;
+ }
- info = pdev->dev.platform_data;
if (!info) {
dev_err(dev, "driver needs R-Car sound information\n");
return -ENODEV;
@@ -737,25 +949,21 @@ static int rsnd_probe(struct platform_device *pdev)
/*
* init each module
*/
- ret = rsnd_gen_probe(pdev, info, priv);
- if (ret < 0)
- return ret;
-
- ret = rsnd_scu_probe(pdev, info, priv);
- if (ret < 0)
- return ret;
+ for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
+ ret = probe_func[i](pdev, of_data, priv);
+ if (ret)
+ return ret;
+ }
- ret = rsnd_adg_probe(pdev, info, priv);
- if (ret < 0)
- return ret;
+ for_each_rsnd_dai(rdai, priv, i) {
+ ret = rsnd_dai_call(rdai, &rdai->playback, probe);
+ if (ret)
+ return ret;
- ret = rsnd_ssi_probe(pdev, info, priv);
- if (ret < 0)
- return ret;
-
- ret = rsnd_dai_probe(pdev, info, priv);
- if (ret < 0)
- return ret;
+ ret = rsnd_dai_call(rdai, &rdai->capture, probe);
+ if (ret)
+ return ret;
+ }
/*
* asoc register
@@ -767,7 +975,7 @@ static int rsnd_probe(struct platform_device *pdev)
}
ret = snd_soc_register_component(dev, &rsnd_soc_component,
- priv->daidrv, rsnd_dai_nr(priv));
+ priv->daidrv, rsnd_rdai_nr(priv));
if (ret < 0) {
dev_err(dev, "cannot snd dai register\n");
goto exit_snd_soc;
@@ -789,17 +997,20 @@ exit_snd_soc:
static int rsnd_remove(struct platform_device *pdev)
{
struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
+ struct rsnd_dai *rdai;
+ int ret, i;
pm_runtime_disable(&pdev->dev);
- /*
- * remove each module
- */
- rsnd_ssi_remove(pdev, priv);
- rsnd_adg_remove(pdev, priv);
- rsnd_scu_remove(pdev, priv);
- rsnd_dai_remove(pdev, priv);
- rsnd_gen_remove(pdev, priv);
+ for_each_rsnd_dai(rdai, priv, i) {
+ ret = rsnd_dai_call(rdai, &rdai->playback, remove);
+ if (ret)
+ return ret;
+
+ ret = rsnd_dai_call(rdai, &rdai->capture, remove);
+ if (ret)
+ return ret;
+ }
return 0;
}
@@ -807,6 +1018,7 @@ static int rsnd_remove(struct platform_device *pdev)
static struct platform_driver rsnd_driver = {
.driver = {
.name = "rcar_sound",
+ .of_match_table = rsnd_of_match,
},
.probe = rsnd_probe,
.remove = rsnd_remove,
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index add088bd4b2a..50a1ef3eb1c6 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -155,62 +155,6 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv,
return 0;
}
-int rsnd_gen_path_init(struct rsnd_priv *priv,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- struct rsnd_mod *mod;
- int ret;
- int id;
-
- /*
- * Gen1 is created by SRU/SSI, and this SRU is base module of
- * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
- *
- * Easy image is..
- * Gen1 SRU = Gen2 SCU + SSIU + etc
- *
- * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
- * using fixed path.
- *
- * Then, SSI id = SCU id here
- */
-
- /* get SSI's ID */
- mod = rsnd_ssi_mod_get_frm_dai(priv,
- rsnd_dai_id(priv, rdai),
- rsnd_dai_is_play(rdai, io));
- id = rsnd_mod_id(mod);
-
- /* SSI */
- mod = rsnd_ssi_mod_get(priv, id);
- ret = rsnd_dai_connect(rdai, mod, io);
- if (ret < 0)
- return ret;
-
- /* SCU */
- mod = rsnd_scu_mod_get(priv, id);
- ret = rsnd_dai_connect(rdai, mod, io);
-
- return ret;
-}
-
-int rsnd_gen_path_exit(struct rsnd_priv *priv,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- struct rsnd_mod *mod, *n;
- int ret = 0;
-
- /*
- * remove all mod from rdai
- */
- for_each_rsnd_mod(mod, n, io)
- ret |= rsnd_dai_disconnect(mod);
-
- return ret;
-}
-
/*
* Gen2
*/
@@ -229,14 +173,40 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
RSND_GEN2_S_REG(gen, SSIU, SSI_MODE0, 0x800),
RSND_GEN2_S_REG(gen, SSIU, SSI_MODE1, 0x804),
/* FIXME: it needs SSI_MODE2/3 in the future */
+ RSND_GEN2_M_REG(gen, SSIU, SSI_BUSIF_MODE, 0x0, 0x80),
+ RSND_GEN2_M_REG(gen, SSIU, SSI_BUSIF_ADINR,0x4, 0x80),
+ RSND_GEN2_M_REG(gen, SSIU, SSI_CTRL, 0x10, 0x80),
RSND_GEN2_M_REG(gen, SSIU, INT_ENABLE, 0x18, 0x80),
+ RSND_GEN2_M_REG(gen, SCU, SRC_BUSIF_MODE, 0x0, 0x20),
+ RSND_GEN2_M_REG(gen, SCU, SRC_ROUTE_MODE0,0xc, 0x20),
+ RSND_GEN2_M_REG(gen, SCU, SRC_CTRL, 0x10, 0x20),
+ RSND_GEN2_M_REG(gen, SCU, SRC_SWRSR, 0x200, 0x40),
+ RSND_GEN2_M_REG(gen, SCU, SRC_SRCIR, 0x204, 0x40),
+ RSND_GEN2_M_REG(gen, SCU, SRC_ADINR, 0x214, 0x40),
+ RSND_GEN2_M_REG(gen, SCU, SRC_IFSCR, 0x21c, 0x40),
+ RSND_GEN2_M_REG(gen, SCU, SRC_IFSVR, 0x220, 0x40),
+ RSND_GEN2_M_REG(gen, SCU, SRC_SRCCR, 0x224, 0x40),
+ RSND_GEN2_M_REG(gen, SCU, SRC_BSDSR, 0x22c, 0x40),
+ RSND_GEN2_M_REG(gen, SCU, SRC_BSISR, 0x238, 0x40),
+
RSND_GEN2_S_REG(gen, ADG, BRRA, 0x00),
RSND_GEN2_S_REG(gen, ADG, BRRB, 0x04),
RSND_GEN2_S_REG(gen, ADG, SSICKR, 0x08),
RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c),
RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10),
RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL2, 0x14),
+ RSND_GEN2_S_REG(gen, ADG, DIV_EN, 0x30),
+ RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL0, 0x34),
+ RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL1, 0x38),
+ RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL2, 0x3c),
+ RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL3, 0x40),
+ RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL4, 0x44),
+ RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL0, 0x48),
+ RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL1, 0x4c),
+ RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL2, 0x50),
+ RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL3, 0x54),
+ RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL4, 0x58),
RSND_GEN2_M_REG(gen, SSI, SSICR, 0x00, 0x40),
RSND_GEN2_M_REG(gen, SSI, SSISR, 0x04, 0x40),
@@ -249,7 +219,6 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
}
static int rsnd_gen2_probe(struct platform_device *pdev,
- struct rcar_snd_info *info,
struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
@@ -283,7 +252,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
return ret;
dev_dbg(dev, "Gen2 device probed\n");
- dev_dbg(dev, "SRU : %08x => %p\n", scu_res->start,
+ dev_dbg(dev, "SCU : %08x => %p\n", scu_res->start,
gen->base[RSND_GEN2_SCU]);
dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start,
gen->base[RSND_GEN2_ADG]);
@@ -317,7 +286,7 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_CTRL, 0xc0),
RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0),
RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4),
- RSND_GEN1_M_REG(gen, SRU, BUSIF_MODE, 0x20, 0x4),
+ RSND_GEN1_M_REG(gen, SRU, SRC_BUSIF_MODE, 0x20, 0x4),
RSND_GEN1_M_REG(gen, SRU, SRC_ROUTE_MODE0,0x50, 0x8),
RSND_GEN1_M_REG(gen, SRU, SRC_SWRSR, 0x200, 0x40),
RSND_GEN1_M_REG(gen, SRU, SRC_SRCIR, 0x204, 0x40),
@@ -347,7 +316,6 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
}
static int rsnd_gen1_probe(struct platform_device *pdev,
- struct rcar_snd_info *info,
struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
@@ -391,14 +359,28 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
/*
* Gen
*/
+static void rsnd_of_parse_gen(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv)
+{
+ struct rcar_snd_info *info = priv->info;
+
+ if (!of_data)
+ return;
+
+ info->flags = of_data->flags;
+}
+
int rsnd_gen_probe(struct platform_device *pdev,
- struct rcar_snd_info *info,
+ const struct rsnd_of_data *of_data,
struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen;
int ret;
+ rsnd_of_parse_gen(pdev, of_data, priv);
+
gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
if (!gen) {
dev_err(dev, "GEN allocate failed\n");
@@ -409,17 +391,12 @@ int rsnd_gen_probe(struct platform_device *pdev,
ret = -ENODEV;
if (rsnd_is_gen1(priv))
- ret = rsnd_gen1_probe(pdev, info, priv);
+ ret = rsnd_gen1_probe(pdev, priv);
else if (rsnd_is_gen2(priv))
- ret = rsnd_gen2_probe(pdev, info, priv);
+ ret = rsnd_gen2_probe(pdev, priv);
if (ret < 0)
dev_err(dev, "unknown generation R-Car sound device\n");
return ret;
}
-
-void rsnd_gen_remove(struct platform_device *pdev,
- struct rsnd_priv *priv)
-{
-}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 4ca66cd899c8..619d198c7d2e 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -17,6 +17,8 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <linux/sh_dma.h>
#include <linux/workqueue.h>
#include <sound/rcar_snd.h>
@@ -32,15 +34,9 @@
*/
enum rsnd_reg {
/* SRU/SCU/SSIU */
- RSND_REG_SRC_ROUTE_SEL, /* for Gen1 */
- RSND_REG_SRC_TMG_SEL0, /* for Gen1 */
- RSND_REG_SRC_TMG_SEL1, /* for Gen1 */
- RSND_REG_SRC_TMG_SEL2, /* for Gen1 */
- RSND_REG_SRC_ROUTE_CTRL, /* for Gen1 */
RSND_REG_SSI_MODE0,
RSND_REG_SSI_MODE1,
- RSND_REG_BUSIF_MODE,
- RSND_REG_INT_ENABLE, /* for Gen2 */
+ RSND_REG_SRC_BUSIF_MODE,
RSND_REG_SRC_ROUTE_MODE0,
RSND_REG_SRC_SWRSR,
RSND_REG_SRC_SRCIR,
@@ -48,7 +44,6 @@ enum rsnd_reg {
RSND_REG_SRC_IFSCR,
RSND_REG_SRC_IFSVR,
RSND_REG_SRC_SRCCR,
- RSND_REG_SRC_MNFSR,
/* ADG */
RSND_REG_BRRA,
@@ -56,10 +51,6 @@ enum rsnd_reg {
RSND_REG_SSICKR,
RSND_REG_AUDIO_CLK_SEL0,
RSND_REG_AUDIO_CLK_SEL1,
- RSND_REG_AUDIO_CLK_SEL2,
- RSND_REG_AUDIO_CLK_SEL3, /* for Gen1 */
- RSND_REG_AUDIO_CLK_SEL4, /* for Gen1 */
- RSND_REG_AUDIO_CLK_SEL5, /* for Gen1 */
/* SSI */
RSND_REG_SSICR,
@@ -68,9 +59,63 @@ enum rsnd_reg {
RSND_REG_SSIRDR,
RSND_REG_SSIWSR,
+ /* SHARE see below */
+ RSND_REG_SHARE01,
+ RSND_REG_SHARE02,
+ RSND_REG_SHARE03,
+ RSND_REG_SHARE04,
+ RSND_REG_SHARE05,
+ RSND_REG_SHARE06,
+ RSND_REG_SHARE07,
+ RSND_REG_SHARE08,
+ RSND_REG_SHARE09,
+ RSND_REG_SHARE10,
+ RSND_REG_SHARE11,
+ RSND_REG_SHARE12,
+ RSND_REG_SHARE13,
+ RSND_REG_SHARE14,
+ RSND_REG_SHARE15,
+ RSND_REG_SHARE16,
+ RSND_REG_SHARE17,
+ RSND_REG_SHARE18,
+ RSND_REG_SHARE19,
+
RSND_REG_MAX,
};
+/* Gen1 only */
+#define RSND_REG_SRC_ROUTE_SEL RSND_REG_SHARE01
+#define RSND_REG_SRC_TMG_SEL0 RSND_REG_SHARE02
+#define RSND_REG_SRC_TMG_SEL1 RSND_REG_SHARE03
+#define RSND_REG_SRC_TMG_SEL2 RSND_REG_SHARE04
+#define RSND_REG_SRC_ROUTE_CTRL RSND_REG_SHARE05
+#define RSND_REG_SRC_MNFSR RSND_REG_SHARE06
+#define RSND_REG_AUDIO_CLK_SEL3 RSND_REG_SHARE07
+#define RSND_REG_AUDIO_CLK_SEL4 RSND_REG_SHARE08
+#define RSND_REG_AUDIO_CLK_SEL5 RSND_REG_SHARE09
+
+/* Gen2 only */
+#define RSND_REG_SRC_CTRL RSND_REG_SHARE01
+#define RSND_REG_SSI_CTRL RSND_REG_SHARE02
+#define RSND_REG_SSI_BUSIF_MODE RSND_REG_SHARE03
+#define RSND_REG_SSI_BUSIF_ADINR RSND_REG_SHARE04
+#define RSND_REG_INT_ENABLE RSND_REG_SHARE05
+#define RSND_REG_SRC_BSDSR RSND_REG_SHARE06
+#define RSND_REG_SRC_BSISR RSND_REG_SHARE07
+#define RSND_REG_DIV_EN RSND_REG_SHARE08
+#define RSND_REG_SRCIN_TIMSEL0 RSND_REG_SHARE09
+#define RSND_REG_SRCIN_TIMSEL1 RSND_REG_SHARE10
+#define RSND_REG_SRCIN_TIMSEL2 RSND_REG_SHARE11
+#define RSND_REG_SRCIN_TIMSEL3 RSND_REG_SHARE12
+#define RSND_REG_SRCIN_TIMSEL4 RSND_REG_SHARE13
+#define RSND_REG_SRCOUT_TIMSEL0 RSND_REG_SHARE14
+#define RSND_REG_SRCOUT_TIMSEL1 RSND_REG_SHARE15
+#define RSND_REG_SRCOUT_TIMSEL2 RSND_REG_SHARE16
+#define RSND_REG_SRCOUT_TIMSEL3 RSND_REG_SHARE17
+#define RSND_REG_SRCOUT_TIMSEL4 RSND_REG_SHARE18
+#define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19
+
+struct rsnd_of_data;
struct rsnd_priv;
struct rsnd_mod;
struct rsnd_dai;
@@ -96,24 +141,20 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
* R-Car DMA
*/
struct rsnd_dma {
- struct rsnd_priv *priv;
struct sh_dmae_slave slave;
struct work_struct work;
struct dma_chan *chan;
enum dma_data_direction dir;
- int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len);
- int (*complete)(struct rsnd_dma *dma);
int submit_loop;
+ int offset; /* it cares A/B plane */
};
void rsnd_dma_start(struct rsnd_dma *dma);
void rsnd_dma_stop(struct rsnd_dma *dma);
int rsnd_dma_available(struct rsnd_dma *dma);
int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
- int is_play, int id,
- int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len),
- int (*complete)(struct rsnd_dma *dma));
+ int is_play, int id);
void rsnd_dma_quit(struct rsnd_priv *priv,
struct rsnd_dma *dma);
@@ -121,9 +162,20 @@ void rsnd_dma_quit(struct rsnd_priv *priv,
/*
* R-Car sound mod
*/
+enum rsnd_mod_type {
+ RSND_MOD_SRC = 0,
+ RSND_MOD_SSI,
+ RSND_MOD_MAX,
+};
struct rsnd_mod_ops {
char *name;
+ int (*probe)(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io);
+ int (*remove)(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io);
int (*init)(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io);
@@ -138,28 +190,26 @@ struct rsnd_mod_ops {
struct rsnd_dai_stream *io);
};
+struct rsnd_dai_stream;
struct rsnd_mod {
int id;
+ enum rsnd_mod_type type;
struct rsnd_priv *priv;
struct rsnd_mod_ops *ops;
- struct list_head list; /* connect to rsnd_dai playback/capture */
struct rsnd_dma dma;
+ struct rsnd_dai_stream *io;
};
#define rsnd_mod_to_priv(mod) ((mod)->priv)
#define rsnd_mod_to_dma(mod) (&(mod)->dma)
#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
+#define rsnd_mod_to_io(mod) ((mod)->io)
#define rsnd_mod_id(mod) ((mod)->id)
-#define for_each_rsnd_mod(pos, n, io) \
- list_for_each_entry_safe(pos, n, &(io)->head, list)
-#define rsnd_mod_call(mod, func, rdai, io) \
- (!(mod) ? -ENODEV : \
- !((mod)->ops->func) ? 0 : \
- (mod)->ops->func(mod, rdai, io))
void rsnd_mod_init(struct rsnd_priv *priv,
struct rsnd_mod *mod,
struct rsnd_mod_ops *ops,
+ enum rsnd_mod_type type,
int id);
char *rsnd_mod_name(struct rsnd_mod *mod);
@@ -168,13 +218,16 @@ char *rsnd_mod_name(struct rsnd_mod *mod);
*/
#define RSND_DAI_NAME_SIZE 16
struct rsnd_dai_stream {
- struct list_head head; /* head of rsnd_mod list */
struct snd_pcm_substream *substream;
+ struct rsnd_mod *mod[RSND_MOD_MAX];
+ struct rsnd_dai_path_info *info; /* rcar_snd.h */
int byte_pos;
int period_pos;
int byte_per_period;
int next_period_byte;
};
+#define rsnd_io_to_mod_ssi(io) ((io)->mod[RSND_MOD_SSI])
+#define rsnd_io_to_mod_src(io) ((io)->mod[RSND_MOD_SRC])
struct rsnd_dai {
char name[RSND_DAI_NAME_SIZE];
@@ -189,16 +242,14 @@ struct rsnd_dai {
unsigned int data_alignment:1;
};
-#define rsnd_dai_nr(priv) ((priv)->dai_nr)
+#define rsnd_rdai_nr(priv) ((priv)->rdai_nr)
#define for_each_rsnd_dai(rdai, priv, i) \
- for (i = 0, (rdai) = rsnd_dai_get(priv, i); \
- i < rsnd_dai_nr(priv); \
- i++, (rdai) = rsnd_dai_get(priv, i))
+ for (i = 0; \
+ (i < rsnd_rdai_nr(priv)) && \
+ ((rdai) = rsnd_dai_get(priv, i)); \
+ i++)
struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id);
-int rsnd_dai_disconnect(struct rsnd_mod *mod);
-int rsnd_dai_connect(struct rsnd_dai *rdai, struct rsnd_mod *mod,
- struct rsnd_dai_stream *io);
int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io);
int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai);
#define rsnd_dai_get_platform_info(rdai) ((rdai)->info)
@@ -206,21 +257,14 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai);
void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
+#define rsnd_dai_is_clk_master(rdai) ((rdai)->clk_master)
/*
* R-Car Gen1/Gen2
*/
int rsnd_gen_probe(struct platform_device *pdev,
- struct rcar_snd_info *info,
+ const struct rsnd_of_data *of_data,
struct rsnd_priv *priv);
-void rsnd_gen_remove(struct platform_device *pdev,
- struct rsnd_priv *priv);
-int rsnd_gen_path_init(struct rsnd_priv *priv,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io);
-int rsnd_gen_path_exit(struct rsnd_priv *priv,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io);
void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
struct rsnd_mod *mod,
enum rsnd_reg reg);
@@ -233,18 +277,28 @@ void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
int rsnd_adg_probe(struct platform_device *pdev,
- struct rcar_snd_info *info,
+ const struct rsnd_of_data *of_data,
struct rsnd_priv *priv);
-void rsnd_adg_remove(struct platform_device *pdev,
- struct rsnd_priv *priv);
-int rsnd_adg_set_convert_clk(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- unsigned int src_rate,
- unsigned int dst_rate);
+int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
+ struct rsnd_mod *mod,
+ unsigned int src_rate,
+ unsigned int dst_rate);
+int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io,
+ unsigned int src_rate,
+ unsigned int dst_rate);
+int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io);
/*
* R-Car sound priv
*/
+struct rsnd_of_data {
+ u32 flags;
+};
+
struct rsnd_priv {
struct device *dev;
@@ -257,10 +311,10 @@ struct rsnd_priv {
void *gen;
/*
- * below value will be filled on rsnd_scu_probe()
+ * below value will be filled on rsnd_src_probe()
*/
- void *scu;
- int scu_nr;
+ void *src;
+ int src_nr;
/*
* below value will be filled on rsnd_adg_probe()
@@ -270,46 +324,64 @@ struct rsnd_priv {
/*
* below value will be filled on rsnd_ssi_probe()
*/
- void *ssiu;
+ void *ssi;
+ int ssi_nr;
/*
* below value will be filled on rsnd_dai_probe()
*/
struct snd_soc_dai_driver *daidrv;
struct rsnd_dai *rdai;
- int dai_nr;
+ int rdai_nr;
};
#define rsnd_priv_to_dev(priv) ((priv)->dev)
+#define rsnd_priv_to_info(priv) ((priv)->info)
#define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
#define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
+#define rsnd_info_is_playback(priv, type) \
+({ \
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv); \
+ int i, is_play = 0; \
+ for (i = 0; i < info->dai_info_nr; i++) { \
+ if (info->dai_info[i].playback.type == (type)->info) { \
+ is_play = 1; \
+ break; \
+ } \
+ } \
+ is_play; \
+})
+
/*
- * R-Car SCU
+ * R-Car SRC
*/
-int rsnd_scu_probe(struct platform_device *pdev,
- struct rcar_snd_info *info,
+int rsnd_src_probe(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
struct rsnd_priv *priv);
-void rsnd_scu_remove(struct platform_device *pdev,
- struct rsnd_priv *priv);
-struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id);
-bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod);
-unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv,
- struct rsnd_mod *ssi_mod,
+struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
+unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
+ struct rsnd_dai_stream *io,
struct snd_pcm_runtime *runtime);
+int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io);
+int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io);
-#define rsnd_scu_nr(priv) ((priv)->scu_nr)
+#define rsnd_src_nr(priv) ((priv)->src_nr)
/*
* R-Car SSI
*/
int rsnd_ssi_probe(struct platform_device *pdev,
- struct rcar_snd_info *info,
- struct rsnd_priv *priv);
-void rsnd_ssi_remove(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
int dai_id, int is_play);
+int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
+int rsnd_ssi_is_play(struct rsnd_mod *mod);
#endif
diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c
deleted file mode 100644
index 9bb08bb1d455..000000000000
--- a/sound/soc/sh/rcar/scu.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Renesas R-Car SCU support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "rsnd.h"
-
-struct rsnd_scu {
- struct rsnd_scu_platform_info *info; /* rcar_snd.h */
- struct rsnd_mod mod;
- struct clk *clk;
-};
-
-#define rsnd_scu_mode_flags(p) ((p)->info->flags)
-#define rsnd_scu_convert_rate(p) ((p)->info->convert_rate)
-
-#define RSND_SCU_NAME_SIZE 16
-
-/*
- * ADINR
- */
-#define OTBL_24 (0 << 16)
-#define OTBL_22 (2 << 16)
-#define OTBL_20 (4 << 16)
-#define OTBL_18 (6 << 16)
-#define OTBL_16 (8 << 16)
-
-/*
- * image of SRC (Sampling Rate Converter)
- *
- * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+
- * 48kHz <-> | SRC | <------> | SSI | <-----> | codec |
- * 44.1kHz <-> +-----+ +-----+ +-------+
- * ...
- *
- */
-
-#define rsnd_mod_to_scu(_mod) \
- container_of((_mod), struct rsnd_scu, mod)
-
-#define for_each_rsnd_scu(pos, priv, i) \
- for ((i) = 0; \
- ((i) < rsnd_scu_nr(priv)) && \
- ((pos) = (struct rsnd_scu *)(priv)->scu + i); \
- i++)
-
-/* Gen1 only */
-static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- struct scu_route_config {
- u32 mask;
- int shift;
- } routes[] = {
- { 0xF, 0, }, /* 0 */
- { 0xF, 4, }, /* 1 */
- { 0xF, 8, }, /* 2 */
- { 0x7, 12, }, /* 3 */
- { 0x7, 16, }, /* 4 */
- { 0x7, 20, }, /* 5 */
- { 0x7, 24, }, /* 6 */
- { 0x3, 28, }, /* 7 */
- { 0x3, 30, }, /* 8 */
- };
- struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
- u32 mask;
- u32 val;
- int shift;
- int id;
-
- /*
- * Gen1 only
- */
- if (!rsnd_is_gen1(priv))
- return 0;
-
- id = rsnd_mod_id(mod);
- if (id < 0 || id >= ARRAY_SIZE(routes))
- return -EIO;
-
- /*
- * SRC_ROUTE_SELECT
- */
- val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2;
- val = val << routes[id].shift;
- mask = routes[id].mask << routes[id].shift;
-
- rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val);
-
- /*
- * SRC_TIMING_SELECT
- */
- shift = (id % 4) * 8;
- mask = 0x1F << shift;
-
- /*
- * ADG is used as source clock if SRC was used,
- * then, SSI WS is used as destination clock.
- * SSI WS is used as source clock if SRC is not used
- * (when playback, source/destination become reverse when capture)
- */
- if (rsnd_scu_convert_rate(scu)) /* use ADG */
- val = 0;
- else if (8 == id) /* use SSI WS, but SRU8 is special */
- val = id << shift;
- else /* use SSI WS */
- val = (id + 1) << shift;
-
- switch (id / 4) {
- case 0:
- rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val);
- break;
- case 1:
- rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val);
- break;
- case 2:
- rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val);
- break;
- }
-
- return 0;
-}
-
-unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv,
- struct rsnd_mod *ssi_mod,
- struct snd_pcm_runtime *runtime)
-{
- struct rsnd_scu *scu;
- unsigned int rate;
-
- /* this function is assuming SSI id = SCU id here */
- scu = rsnd_mod_to_scu(rsnd_scu_mod_get(priv, rsnd_mod_id(ssi_mod)));
-
- /*
- * return convert rate if SRC is used,
- * otherwise, return runtime->rate as usual
- */
- rate = rsnd_scu_convert_rate(scu);
- if (!rate)
- rate = runtime->rate;
-
- return rate;
-}
-
-static int rsnd_scu_convert_rate_ctrl(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
- u32 convert_rate = rsnd_scu_convert_rate(scu);
- u32 adinr = runtime->channels;
-
- /* set/clear soft reset */
- rsnd_mod_write(mod, SRC_SWRSR, 0);
- rsnd_mod_write(mod, SRC_SWRSR, 1);
-
- /* Initialize the operation of the SRC internal circuits */
- rsnd_mod_write(mod, SRC_SRCIR, 1);
-
- /* Set channel number and output bit length */
- switch (runtime->sample_bits) {
- case 16:
- adinr |= OTBL_16;
- break;
- case 32:
- adinr |= OTBL_24;
- break;
- default:
- return -EIO;
- }
- rsnd_mod_write(mod, SRC_ADINR, adinr);
-
- if (convert_rate) {
- u32 fsrate = 0x0400000 / convert_rate * runtime->rate;
- int ret;
-
- /* Enable the initial value of IFS */
- rsnd_mod_write(mod, SRC_IFSCR, 1);
-
- /* Set initial value of IFS */
- rsnd_mod_write(mod, SRC_IFSVR, fsrate);
-
- /* Select SRC mode (fixed value) */
- rsnd_mod_write(mod, SRC_SRCCR, 0x00010110);
-
- /* Set the restriction value of the FS ratio (98%) */
- rsnd_mod_write(mod, SRC_MNFSR, fsrate / 100 * 98);
-
- if (rsnd_is_gen1(priv)) {
- /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
- }
-
- /* set convert clock */
- ret = rsnd_adg_set_convert_clk(priv, mod,
- runtime->rate,
- convert_rate);
- if (ret < 0)
- return ret;
- }
-
- /* Cancel the initialization and operate the SRC function */
- rsnd_mod_write(mod, SRC_SRCIR, 0);
-
- /* use DMA transfer */
- rsnd_mod_write(mod, BUSIF_MODE, 1);
-
- return 0;
-}
-
-static int rsnd_scu_transfer_start(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
- int id = rsnd_mod_id(mod);
- u32 val;
-
- if (rsnd_is_gen1(priv)) {
- val = (1 << id);
- rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val);
- }
-
- if (rsnd_scu_convert_rate(scu))
- rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
-
- return 0;
-}
-
-static int rsnd_scu_transfer_stop(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
- int id = rsnd_mod_id(mod);
- u32 mask;
-
- if (rsnd_is_gen1(priv)) {
- mask = (1 << id);
- rsnd_mod_bset(mod, SRC_ROUTE_CTRL, mask, 0);
- }
-
- if (rsnd_scu_convert_rate(scu))
- rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0);
-
- return 0;
-}
-
-bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod)
-{
- struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
- u32 flags = rsnd_scu_mode_flags(scu);
-
- return !!(flags & RSND_SCU_USE_HPBIF);
-}
-
-static int rsnd_scu_start(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
- int ret;
-
- /*
- * SCU will be used if it has RSND_SCU_USE_HPBIF flags
- */
- if (!rsnd_scu_hpbif_is_enable(mod)) {
- /* it use PIO transter */
- dev_dbg(dev, "%s%d is not used\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
-
- return 0;
- }
-
- clk_enable(scu->clk);
-
- /* it use DMA transter */
-
- ret = rsnd_src_set_route_if_gen1(priv, mod, rdai, io);
- if (ret < 0)
- return ret;
-
- ret = rsnd_scu_convert_rate_ctrl(priv, mod, rdai, io);
- if (ret < 0)
- return ret;
-
- ret = rsnd_scu_transfer_start(priv, mod, rdai, io);
- if (ret < 0)
- return ret;
-
- dev_dbg(dev, "%s%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
-
- return 0;
-}
-
-static int rsnd_scu_stop(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
-
- if (!rsnd_scu_hpbif_is_enable(mod))
- return 0;
-
- rsnd_scu_transfer_stop(priv, mod, rdai, io);
-
- clk_disable(scu->clk);
-
- return 0;
-}
-
-static struct rsnd_mod_ops rsnd_scu_ops = {
- .name = "scu",
- .start = rsnd_scu_start,
- .stop = rsnd_scu_stop,
-};
-
-struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id)
-{
- if (WARN_ON(id < 0 || id >= rsnd_scu_nr(priv)))
- id = 0;
-
- return &((struct rsnd_scu *)(priv->scu) + id)->mod;
-}
-
-int rsnd_scu_probe(struct platform_device *pdev,
- struct rcar_snd_info *info,
- struct rsnd_priv *priv)
-{
- struct device *dev = rsnd_priv_to_dev(priv);
- struct rsnd_scu *scu;
- struct clk *clk;
- char name[RSND_SCU_NAME_SIZE];
- int i, nr;
-
- /*
- * init SCU
- */
- nr = info->scu_info_nr;
- scu = devm_kzalloc(dev, sizeof(*scu) * nr, GFP_KERNEL);
- if (!scu) {
- dev_err(dev, "SCU allocate failed\n");
- return -ENOMEM;
- }
-
- priv->scu_nr = nr;
- priv->scu = scu;
-
- for_each_rsnd_scu(scu, priv, i) {
- snprintf(name, RSND_SCU_NAME_SIZE, "scu.%d", i);
-
- clk = devm_clk_get(dev, name);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
- rsnd_mod_init(priv, &scu->mod,
- &rsnd_scu_ops, i);
- scu->info = &info->scu_info[i];
- scu->clk = clk;
-
- dev_dbg(dev, "SCU%d probed\n", i);
- }
- dev_dbg(dev, "scu probed\n");
-
- return 0;
-}
-
-void rsnd_scu_remove(struct platform_device *pdev,
- struct rsnd_priv *priv)
-{
-}
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
new file mode 100644
index 000000000000..6232b7d307aa
--- /dev/null
+++ b/sound/soc/sh/rcar/src.c
@@ -0,0 +1,727 @@
+/*
+ * Renesas R-Car SRC support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "rsnd.h"
+
+struct rsnd_src {
+ struct rsnd_src_platform_info *info; /* rcar_snd.h */
+ struct rsnd_mod mod;
+ struct clk *clk;
+};
+
+#define RSND_SRC_NAME_SIZE 16
+
+/*
+ * ADINR
+ */
+#define OTBL_24 (0 << 16)
+#define OTBL_22 (2 << 16)
+#define OTBL_20 (4 << 16)
+#define OTBL_18 (6 << 16)
+#define OTBL_16 (8 << 16)
+
+#define rsnd_src_mode_flags(p) ((p)->info->flags)
+#define rsnd_src_convert_rate(p) ((p)->info->convert_rate)
+#define rsnd_mod_to_src(_mod) \
+ container_of((_mod), struct rsnd_src, mod)
+#define rsnd_src_hpbif_is_enable(src) \
+ (rsnd_src_mode_flags(src) & RSND_SCU_USE_HPBIF)
+#define rsnd_src_dma_available(src) \
+ rsnd_dma_available(rsnd_mod_to_dma(&(src)->mod))
+
+#define for_each_rsnd_src(pos, priv, i) \
+ for ((i) = 0; \
+ ((i) < rsnd_src_nr(priv)) && \
+ ((pos) = (struct rsnd_src *)(priv)->src + i); \
+ i++)
+
+
+/*
+ * image of SRC (Sampling Rate Converter)
+ *
+ * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+
+ * 48kHz <-> | SRC | <------> | SSI | <-----> | codec |
+ * 44.1kHz <-> +-----+ +-----+ +-------+
+ * ...
+ *
+ */
+
+/*
+ * src.c is caring...
+ *
+ * Gen1
+ *
+ * [mem] -> [SRU] -> [SSI]
+ * |--------|
+ *
+ * Gen2
+ *
+ * [mem] -> [SRC] -> [SSIU] -> [SSI]
+ * |-----------------|
+ */
+
+/*
+ * How to use SRC bypass mode for debugging
+ *
+ * SRC has bypass mode, and it is useful for debugging.
+ * In Gen2 case,
+ * SRCm_MODE controls whether SRC is used or not
+ * SSI_MODE0 controls whether SSIU which receives SRC data
+ * is used or not.
+ * Both SRCm_MODE/SSI_MODE0 settings are needed if you use SRC,
+ * but SRC bypass mode needs SSI_MODE0 only.
+ *
+ * This driver request
+ * struct rsnd_src_platform_info {
+ * u32 flags;
+ * u32 convert_rate;
+ * }
+ *
+ * rsnd_src_hpbif_is_enable() will be true
+ * if flags had RSND_SRC_USE_HPBIF,
+ * and it controls whether SSIU is used or not.
+ *
+ * rsnd_src_convert_rate() indicates
+ * above convert_rate, and it controls
+ * whether SRC is used or not.
+ *
+ * ex) doesn't use SRC
+ * struct rsnd_src_platform_info info = {
+ * .flags = 0,
+ * .convert_rate = 0,
+ * };
+ *
+ * ex) uses SRC
+ * struct rsnd_src_platform_info info = {
+ * .flags = RSND_SRC_USE_HPBIF,
+ * .convert_rate = 48000,
+ * };
+ *
+ * ex) uses SRC bypass mode
+ * struct rsnd_src_platform_info info = {
+ * .flags = RSND_SRC_USE_HPBIF,
+ * .convert_rate = 0,
+ * };
+ *
+ */
+
+/*
+ * Gen1/Gen2 common functions
+ */
+int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+ struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ int ssi_id = rsnd_mod_id(ssi_mod);
+ int has_src = 0;
+
+ /*
+ * SSI_MODE0
+ */
+ if (info->dai_info) {
+ has_src = !!src_mod;
+ } else {
+ struct rsnd_src *src = rsnd_mod_to_src(src_mod);
+ has_src = rsnd_src_hpbif_is_enable(src);
+ }
+
+ rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id),
+ has_src ? 0 : (1 << ssi_id));
+
+ /*
+ * SSI_MODE1
+ */
+ if (rsnd_ssi_is_pin_sharing(ssi_mod)) {
+ int shift = -1;
+ switch (ssi_id) {
+ case 1:
+ shift = 0;
+ break;
+ case 2:
+ shift = 2;
+ break;
+ case 4:
+ shift = 16;
+ break;
+ }
+
+ if (shift >= 0)
+ rsnd_mod_bset(ssi_mod, SSI_MODE1,
+ 0x3 << shift,
+ rsnd_dai_is_clk_master(rdai) ?
+ 0x2 << shift : 0x1 << shift);
+ }
+
+ return 0;
+}
+
+int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+
+ /* enable PIO interrupt if Gen2 */
+ if (rsnd_is_gen2(priv))
+ rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000);
+
+ return 0;
+}
+
+unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
+ struct rsnd_dai_stream *io,
+ struct snd_pcm_runtime *runtime)
+{
+ struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
+ struct rsnd_src *src;
+ unsigned int rate = 0;
+
+ if (src_mod) {
+ src = rsnd_mod_to_src(src_mod);
+
+ /*
+ * return convert rate if SRC is used,
+ * otherwise, return runtime->rate as usual
+ */
+ rate = rsnd_src_convert_rate(src);
+ }
+
+ if (!rate)
+ rate = runtime->rate;
+
+ return rate;
+}
+
+static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+ u32 convert_rate = rsnd_src_convert_rate(src);
+ u32 adinr = runtime->channels;
+ u32 fsrate = 0;
+
+ if (convert_rate)
+ fsrate = 0x0400000 / convert_rate * runtime->rate;
+
+ /* set/clear soft reset */
+ rsnd_mod_write(mod, SRC_SWRSR, 0);
+ rsnd_mod_write(mod, SRC_SWRSR, 1);
+
+ /*
+ * Initialize the operation of the SRC internal circuits
+ * see rsnd_src_start()
+ */
+ rsnd_mod_write(mod, SRC_SRCIR, 1);
+
+ /* Set channel number and output bit length */
+ switch (runtime->sample_bits) {
+ case 16:
+ adinr |= OTBL_16;
+ break;
+ case 32:
+ adinr |= OTBL_24;
+ break;
+ default:
+ return -EIO;
+ }
+ rsnd_mod_write(mod, SRC_ADINR, adinr);
+
+ /* Enable the initial value of IFS */
+ if (fsrate) {
+ rsnd_mod_write(mod, SRC_IFSCR, 1);
+
+ /* Set initial value of IFS */
+ rsnd_mod_write(mod, SRC_IFSVR, fsrate);
+ }
+
+ /* use DMA transfer */
+ rsnd_mod_write(mod, SRC_BUSIF_MODE, 1);
+
+ return 0;
+}
+
+static int rsnd_src_init(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+ clk_enable(src->clk);
+
+ return 0;
+}
+
+static int rsnd_src_quit(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+ clk_disable(src->clk);
+
+ return 0;
+}
+
+static int rsnd_src_start(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+ /*
+ * Cancel the initialization and operate the SRC function
+ * see rsnd_src_set_convert_rate()
+ */
+ rsnd_mod_write(mod, SRC_SRCIR, 0);
+
+ if (rsnd_src_convert_rate(src))
+ rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
+
+ return 0;
+}
+
+
+static int rsnd_src_stop(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+ if (rsnd_src_convert_rate(src))
+ rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0);
+
+ return 0;
+}
+
+static struct rsnd_mod_ops rsnd_src_non_ops = {
+ .name = "src (non)",
+};
+
+/*
+ * Gen1 functions
+ */
+static int rsnd_src_set_route_gen1(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct src_route_config {
+ u32 mask;
+ int shift;
+ } routes[] = {
+ { 0xF, 0, }, /* 0 */
+ { 0xF, 4, }, /* 1 */
+ { 0xF, 8, }, /* 2 */
+ { 0x7, 12, }, /* 3 */
+ { 0x7, 16, }, /* 4 */
+ { 0x7, 20, }, /* 5 */
+ { 0x7, 24, }, /* 6 */
+ { 0x3, 28, }, /* 7 */
+ { 0x3, 30, }, /* 8 */
+ };
+ u32 mask;
+ u32 val;
+ int id;
+
+ id = rsnd_mod_id(mod);
+ if (id < 0 || id >= ARRAY_SIZE(routes))
+ return -EIO;
+
+ /*
+ * SRC_ROUTE_SELECT
+ */
+ val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2;
+ val = val << routes[id].shift;
+ mask = routes[id].mask << routes[id].shift;
+
+ rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val);
+
+ return 0;
+}
+
+static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ u32 convert_rate = rsnd_src_convert_rate(src);
+ u32 mask;
+ u32 val;
+ int shift;
+ int id = rsnd_mod_id(mod);
+ int ret;
+
+ /*
+ * SRC_TIMING_SELECT
+ */
+ shift = (id % 4) * 8;
+ mask = 0x1F << shift;
+
+ /*
+ * ADG is used as source clock if SRC was used,
+ * then, SSI WS is used as destination clock.
+ * SSI WS is used as source clock if SRC is not used
+ * (when playback, source/destination become reverse when capture)
+ */
+ ret = 0;
+ if (convert_rate) {
+ /* use ADG */
+ val = 0;
+ ret = rsnd_adg_set_convert_clk_gen1(priv, mod,
+ runtime->rate,
+ convert_rate);
+ } else if (8 == id) {
+ /* use SSI WS, but SRU8 is special */
+ val = id << shift;
+ } else {
+ /* use SSI WS */
+ val = (id + 1) << shift;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ switch (id / 4) {
+ case 0:
+ rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val);
+ break;
+ case 1:
+ rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val);
+ break;
+ case 2:
+ rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val);
+ break;
+ }
+
+ return 0;
+}
+
+static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ int ret;
+
+ ret = rsnd_src_set_convert_rate(mod, rdai, io);
+ if (ret < 0)
+ return ret;
+
+ /* Select SRC mode (fixed value) */
+ rsnd_mod_write(mod, SRC_SRCCR, 0x00010110);
+
+ /* Set the restriction value of the FS ratio (98%) */
+ rsnd_mod_write(mod, SRC_MNFSR,
+ rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98);
+
+ /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
+
+ return 0;
+}
+
+static int rsnd_src_init_gen1(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ int ret;
+
+ ret = rsnd_src_init(mod, rdai, io);
+ if (ret < 0)
+ return ret;
+
+ ret = rsnd_src_set_route_gen1(mod, rdai, io);
+ if (ret < 0)
+ return ret;
+
+ ret = rsnd_src_set_convert_rate_gen1(mod, rdai, io);
+ if (ret < 0)
+ return ret;
+
+ ret = rsnd_src_set_convert_timing_gen1(mod, rdai, io);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rsnd_src_start_gen1(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ int id = rsnd_mod_id(mod);
+
+ rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id));
+
+ return rsnd_src_start(mod, rdai, io);
+}
+
+static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ int id = rsnd_mod_id(mod);
+
+ rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0);
+
+ return rsnd_src_stop(mod, rdai, io);
+}
+
+static struct rsnd_mod_ops rsnd_src_gen1_ops = {
+ .name = "sru (gen1)",
+ .init = rsnd_src_init_gen1,
+ .quit = rsnd_src_quit,
+ .start = rsnd_src_start_gen1,
+ .stop = rsnd_src_stop_gen1,
+};
+
+/*
+ * Gen2 functions
+ */
+static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ int ret;
+
+ ret = rsnd_src_set_convert_rate(mod, rdai, io);
+ if (ret < 0)
+ return ret;
+
+ rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_mod_read(mod, SRC_ADINR));
+ rsnd_mod_write(mod, SSI_BUSIF_MODE, rsnd_mod_read(mod, SRC_BUSIF_MODE));
+
+ rsnd_mod_write(mod, SRC_SRCCR, 0x00011110);
+
+ rsnd_mod_write(mod, SRC_BSDSR, 0x01800000);
+ rsnd_mod_write(mod, SRC_BSISR, 0x00100060);
+
+ return 0;
+}
+
+static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+ u32 convert_rate = rsnd_src_convert_rate(src);
+ int ret;
+
+ if (convert_rate)
+ ret = rsnd_adg_set_convert_clk_gen2(mod, rdai, io,
+ runtime->rate,
+ convert_rate);
+ else
+ ret = rsnd_adg_set_convert_timing_gen2(mod, rdai, io);
+
+ return ret;
+}
+
+static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+ struct rsnd_mod *ssi = rsnd_ssi_mod_get(priv, rsnd_mod_id(mod));
+ struct device *dev = rsnd_priv_to_dev(priv);
+ int ret;
+ int is_play;
+
+ if (info->dai_info)
+ is_play = rsnd_info_is_playback(priv, src);
+ else
+ is_play = rsnd_ssi_is_play(ssi);
+
+ ret = rsnd_dma_init(priv,
+ rsnd_mod_to_dma(mod),
+ is_play,
+ src->info->dma_id);
+ if (ret < 0)
+ dev_err(dev, "SRC DMA failed\n");
+
+ return ret;
+}
+
+static int rsnd_src_remove_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod));
+
+ return 0;
+}
+
+static int rsnd_src_init_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ int ret;
+
+ ret = rsnd_src_init(mod, rdai, io);
+ if (ret < 0)
+ return ret;
+
+ ret = rsnd_src_set_convert_rate_gen2(mod, rdai, io);
+ if (ret < 0)
+ return ret;
+
+ ret = rsnd_src_set_convert_timing_gen2(mod, rdai, io);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rsnd_src_start_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+ rsnd_dma_start(rsnd_mod_to_dma(&src->mod));
+
+ rsnd_mod_write(mod, SSI_CTRL, 0x1);
+ rsnd_mod_write(mod, SRC_CTRL, 0x11);
+
+ return rsnd_src_start(mod, rdai, io);
+}
+
+static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+ rsnd_mod_write(mod, SSI_CTRL, 0);
+ rsnd_mod_write(mod, SRC_CTRL, 0);
+
+ rsnd_dma_stop(rsnd_mod_to_dma(&src->mod));
+
+ return rsnd_src_stop(mod, rdai, io);
+}
+
+static struct rsnd_mod_ops rsnd_src_gen2_ops = {
+ .name = "src (gen2)",
+ .probe = rsnd_src_probe_gen2,
+ .remove = rsnd_src_remove_gen2,
+ .init = rsnd_src_init_gen2,
+ .quit = rsnd_src_quit,
+ .start = rsnd_src_start_gen2,
+ .stop = rsnd_src_stop_gen2,
+};
+
+struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
+{
+ if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv)))
+ id = 0;
+
+ return &((struct rsnd_src *)(priv->src) + id)->mod;
+}
+
+static void rsnd_of_parse_src(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv)
+{
+ struct device_node *src_node;
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct rsnd_src_platform_info *src_info;
+ struct device *dev = &pdev->dev;
+ int nr;
+
+ if (!of_data)
+ return;
+
+ src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
+ if (!src_node)
+ return;
+
+ nr = of_get_child_count(src_node);
+ if (!nr)
+ return;
+
+ src_info = devm_kzalloc(dev,
+ sizeof(struct rsnd_src_platform_info) * nr,
+ GFP_KERNEL);
+ if (!src_info) {
+ dev_err(dev, "src info allocation error\n");
+ return;
+ }
+
+ info->src_info = src_info;
+ info->src_info_nr = nr;
+}
+
+int rsnd_src_probe(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv)
+{
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_src *src;
+ struct rsnd_mod_ops *ops;
+ struct clk *clk;
+ char name[RSND_SRC_NAME_SIZE];
+ int i, nr;
+
+ rsnd_of_parse_src(pdev, of_data, priv);
+
+ /*
+ * init SRC
+ */
+ nr = info->src_info_nr;
+ if (!nr)
+ return 0;
+
+ src = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL);
+ if (!src) {
+ dev_err(dev, "SRC allocate failed\n");
+ return -ENOMEM;
+ }
+
+ priv->src_nr = nr;
+ priv->src = src;
+
+ for_each_rsnd_src(src, priv, i) {
+ snprintf(name, RSND_SRC_NAME_SIZE, "src.%d", i);
+
+ clk = devm_clk_get(dev, name);
+ if (IS_ERR(clk)) {
+ snprintf(name, RSND_SRC_NAME_SIZE, "scu.%d", i);
+ clk = devm_clk_get(dev, name);
+ }
+
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ src->info = &info->src_info[i];
+ src->clk = clk;
+
+ ops = &rsnd_src_non_ops;
+ if (rsnd_src_hpbif_is_enable(src)) {
+ if (rsnd_is_gen1(priv))
+ ops = &rsnd_src_gen1_ops;
+ if (rsnd_is_gen2(priv))
+ ops = &rsnd_src_gen2_ops;
+ }
+
+ rsnd_mod_init(priv, &src->mod, ops, RSND_MOD_SRC, i);
+
+ dev_dbg(dev, "SRC%d probed\n", i);
+ }
+
+ return 0;
+}
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 4b8cf7ca9d19..4b7e20603dd7 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -64,108 +64,29 @@ struct rsnd_ssi {
struct rsnd_mod mod;
struct rsnd_dai *rdai;
- struct rsnd_dai_stream *io;
u32 cr_own;
u32 cr_clk;
u32 cr_etc;
int err;
- int dma_offset;
unsigned int usrcnt;
unsigned int rate;
};
-struct rsnd_ssiu {
- u32 ssi_mode0;
- u32 ssi_mode1;
-
- int ssi_nr;
- struct rsnd_ssi *ssi;
-};
-
#define for_each_rsnd_ssi(pos, priv, i) \
for (i = 0; \
(i < rsnd_ssi_nr(priv)) && \
- ((pos) = ((struct rsnd_ssiu *)((priv)->ssiu))->ssi + i); \
+ ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \
i++)
-#define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr)
+#define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
#define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma))
#define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0)
#define rsnd_ssi_dma_available(ssi) \
rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod))
#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
-#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master)
#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
-#define rsnd_ssi_to_ssiu(ssi)\
- (((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1)
-
-static void rsnd_ssi_mode_set(struct rsnd_priv *priv,
- struct rsnd_dai *rdai,
- struct rsnd_ssi *ssi)
-{
- struct device *dev = rsnd_priv_to_dev(priv);
- struct rsnd_mod *scu;
- struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi);
- int id = rsnd_mod_id(&ssi->mod);
- u32 flags;
- u32 val;
-
- scu = rsnd_scu_mod_get(priv, rsnd_mod_id(&ssi->mod));
-
- /*
- * SSI_MODE0
- */
-
- /* see also BUSIF_MODE */
- if (rsnd_scu_hpbif_is_enable(scu)) {
- ssiu->ssi_mode0 &= ~(1 << id);
- dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", id);
- } else {
- ssiu->ssi_mode0 |= (1 << id);
- dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", id);
- }
-
- /*
- * SSI_MODE1
- */
-#define ssi_parent_set(p, sync, adg, ext) \
- do { \
- ssi->parent = ssiu->ssi + p; \
- if (rsnd_rdai_is_clk_master(rdai)) \
- val = adg; \
- else \
- val = ext; \
- if (flags & RSND_SSI_SYNC) \
- val |= sync; \
- } while (0)
-
- flags = rsnd_ssi_mode_flags(ssi);
- if (flags & RSND_SSI_CLK_PIN_SHARE) {
-
- val = 0;
- switch (id) {
- case 1:
- ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0));
- break;
- case 2:
- ssi_parent_set(0, (1 << 4), (0x2 << 2), (0x1 << 2));
- break;
- case 4:
- ssi_parent_set(3, (1 << 20), (0x2 << 16), (0x1 << 16));
- break;
- case 8:
- ssi_parent_set(7, 0, 0, 0);
- break;
- }
-
- ssiu->ssi_mode1 |= val;
- }
-
- rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0);
- rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1);
-}
static void rsnd_ssi_status_check(struct rsnd_mod *mod,
u32 bit)
@@ -200,7 +121,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
1, 2, 4, 8, 16, 6, 12,
};
unsigned int main_rate;
- unsigned int rate = rsnd_scu_get_ssi_rate(priv, &ssi->mod, runtime);
+ unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime);
/*
* Find best clock, and try to start ADG
@@ -252,7 +173,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
if (0 == ssi->usrcnt) {
clk_enable(ssi->clk);
- if (rsnd_rdai_is_clk_master(rdai)) {
+ if (rsnd_dai_is_clk_master(rdai)) {
if (rsnd_ssi_clk_from_parent(ssi))
rsnd_ssi_hw_start(ssi->parent, rdai, io);
else
@@ -302,7 +223,7 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
rsnd_mod_write(&ssi->mod, SSICR, cr); /* disabled all */
rsnd_ssi_status_check(&ssi->mod, IIRQ);
- if (rsnd_rdai_is_clk_master(rdai)) {
+ if (rsnd_dai_is_clk_master(rdai)) {
if (rsnd_ssi_clk_from_parent(ssi))
rsnd_ssi_hw_stop(ssi->parent, rdai);
else
@@ -323,8 +244,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
u32 cr;
@@ -365,13 +284,10 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
* set ssi parameter
*/
ssi->rdai = rdai;
- ssi->io = io;
ssi->cr_own = cr;
ssi->err = -1; /* ignore 1st error */
- rsnd_ssi_mode_set(priv, rdai, ssi);
-
- dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+ rsnd_src_ssi_mode_init(mod, rdai, io);
return 0;
}
@@ -384,13 +300,10 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
- dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
-
if (ssi->err > 0)
dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err);
ssi->rdai = NULL;
- ssi->io = NULL;
ssi->cr_own = 0;
ssi->err = 0;
@@ -414,8 +327,9 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
{
struct rsnd_ssi *ssi = data;
- struct rsnd_dai_stream *io = ssi->io;
- u32 status = rsnd_mod_read(&ssi->mod, SSISR);
+ struct rsnd_mod *mod = &ssi->mod;
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+ u32 status = rsnd_mod_read(mod, SSISR);
irqreturn_t ret = IRQ_NONE;
if (io && (status & DIRQ)) {
@@ -432,9 +346,9 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
* see rsnd_ssi_init()
*/
if (rsnd_dai_is_play(rdai, io))
- rsnd_mod_write(&ssi->mod, SSITDR, *buf);
+ rsnd_mod_write(mod, SSITDR, *buf);
else
- *buf = rsnd_mod_read(&ssi->mod, SSIRDR);
+ *buf = rsnd_mod_read(mod, SSIRDR);
rsnd_dai_pointer_update(io, sizeof(*buf));
@@ -444,25 +358,39 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
return ret;
}
-static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
+static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ int irq = ssi->info->pio_irq;
+ int ret;
+
+ ret = devm_request_irq(dev, irq,
+ rsnd_ssi_pio_interrupt,
+ IRQF_SHARED,
+ dev_name(dev), ssi);
+ if (ret)
+ dev_err(dev, "SSI request interrupt failed\n");
+
+ return ret;
+}
+
+static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
/* enable PIO IRQ */
ssi->cr_etc = UIEN | OIEN | DIEN;
- /* enable PIO interrupt if gen2 */
- if (rsnd_is_gen2(priv))
- rsnd_mod_write(&ssi->mod, INT_ENABLE, 0x0f000000);
+ rsnd_src_enable_ssi_irq(mod, rdai, io);
rsnd_ssi_hw_start(ssi, rdai, io);
- dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
-
return 0;
}
@@ -470,12 +398,8 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io)
{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
-
ssi->cr_etc = 0;
rsnd_ssi_hw_stop(ssi, rdai);
@@ -485,35 +409,46 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
.name = "ssi (pio)",
+ .probe = rsnd_ssi_pio_probe,
.init = rsnd_ssi_init,
.quit = rsnd_ssi_quit,
.start = rsnd_ssi_pio_start,
.stop = rsnd_ssi_pio_stop,
};
-static int rsnd_ssi_dma_inquiry(struct rsnd_dma *dma, dma_addr_t *buf, int *len)
+static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
{
- struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma);
- struct rsnd_dai_stream *io = ssi->io;
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ int dma_id = ssi->info->dma_id;
+ int is_play;
+ int ret;
- *len = io->byte_per_period;
- *buf = runtime->dma_addr +
- rsnd_dai_pointer_offset(io, ssi->dma_offset + *len);
- ssi->dma_offset = *len; /* it cares A/B plane */
+ if (info->dai_info)
+ is_play = rsnd_info_is_playback(priv, ssi);
+ else
+ is_play = rsnd_ssi_is_play(&ssi->mod);
- return 0;
-}
+ ret = rsnd_dma_init(
+ priv, rsnd_mod_to_dma(mod),
+ is_play,
+ dma_id);
-static int rsnd_ssi_dma_complete(struct rsnd_dma *dma)
-{
- struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma);
- struct rsnd_dai_stream *io = ssi->io;
- u32 status = rsnd_mod_read(&ssi->mod, SSISR);
+ if (ret < 0)
+ dev_err(dev, "SSI DMA failed\n");
- rsnd_ssi_record_error(ssi, status);
+ return ret;
+}
- rsnd_dai_pointer_update(ssi->io, io->byte_per_period);
+static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod));
return 0;
}
@@ -527,14 +462,13 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
/* enable DMA transfer */
ssi->cr_etc = DMEN;
- ssi->dma_offset = 0;
rsnd_dma_start(dma);
rsnd_ssi_hw_start(ssi, ssi->rdai, io);
/* enable WS continue */
- if (rsnd_rdai_is_clk_master(rdai))
+ if (rsnd_dai_is_clk_master(rdai))
rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
return 0;
@@ -549,6 +483,8 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
ssi->cr_etc = 0;
+ rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR));
+
rsnd_ssi_hw_stop(ssi, rdai);
rsnd_dma_stop(dma);
@@ -558,6 +494,8 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
.name = "ssi (dma)",
+ .probe = rsnd_ssi_dma_probe,
+ .remove = rsnd_ssi_dma_remove,
.init = rsnd_ssi_init,
.quit = rsnd_ssi_quit,
.start = rsnd_ssi_dma_start,
@@ -567,24 +505,8 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
/*
* Non SSI
*/
-static int rsnd_ssi_non(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
-
- dev_dbg(dev, "%s\n", __func__);
-
- return 0;
-}
-
static struct rsnd_mod_ops rsnd_ssi_non_ops = {
.name = "ssi (non)",
- .init = rsnd_ssi_non,
- .quit = rsnd_ssi_non,
- .start = rsnd_ssi_non,
- .stop = rsnd_ssi_non,
};
/*
@@ -593,16 +515,30 @@ static struct rsnd_mod_ops rsnd_ssi_non_ops = {
struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
int dai_id, int is_play)
{
+ struct rsnd_dai_platform_info *dai_info = NULL;
+ struct rsnd_dai_path_info *path_info = NULL;
+ struct rsnd_ssi_platform_info *target_info = NULL;
struct rsnd_ssi *ssi;
int i, has_play;
+ if (priv->rdai)
+ dai_info = priv->rdai[dai_id].info;
+ if (dai_info)
+ path_info = (is_play) ? &dai_info->playback : &dai_info->capture;
+ if (path_info)
+ target_info = path_info->ssi;
+
is_play = !!is_play;
for_each_rsnd_ssi(ssi, priv, i) {
+ if (target_info == ssi->info)
+ return &ssi->mod;
+
+ /* for compatible */
if (rsnd_ssi_dai_id(ssi) != dai_id)
continue;
- has_play = !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY);
+ has_play = rsnd_ssi_is_play(&ssi->mod);
if (is_play == has_play)
return &ssi->mod;
@@ -616,36 +552,122 @@ struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
id = 0;
- return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod;
+ return &((struct rsnd_ssi *)(priv->ssi) + id)->mod;
+}
+
+int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
+{
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+ return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
+}
+
+int rsnd_ssi_is_play(struct rsnd_mod *mod)
+{
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+ return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY);
+}
+
+static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi)
+{
+ if (!rsnd_ssi_is_pin_sharing(&ssi->mod))
+ return;
+
+ switch (rsnd_mod_id(&ssi->mod)) {
+ case 1:
+ case 2:
+ ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0));
+ break;
+ case 4:
+ ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 3));
+ break;
+ case 8:
+ ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 7));
+ break;
+ }
+}
+
+
+static void rsnd_of_parse_ssi(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv)
+{
+ struct device_node *node;
+ struct device_node *np;
+ struct rsnd_ssi_platform_info *ssi_info;
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+ struct device *dev = &pdev->dev;
+ int nr, i;
+
+ if (!of_data)
+ return;
+
+ node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
+ if (!node)
+ return;
+
+ nr = of_get_child_count(node);
+ if (!nr)
+ return;
+
+ ssi_info = devm_kzalloc(dev,
+ sizeof(struct rsnd_ssi_platform_info) * nr,
+ GFP_KERNEL);
+ if (!ssi_info) {
+ dev_err(dev, "ssi info allocation error\n");
+ return;
+ }
+
+ info->ssi_info = ssi_info;
+ info->ssi_info_nr = nr;
+
+ i = -1;
+ for_each_child_of_node(node, np) {
+ i++;
+
+ ssi_info = info->ssi_info + i;
+
+ /*
+ * pin settings
+ */
+ if (of_get_property(np, "shared-pin", NULL))
+ ssi_info->flags |= RSND_SSI_CLK_PIN_SHARE;
+
+ /*
+ * irq
+ */
+ ssi_info->pio_irq = irq_of_parse_and_map(np, 0);
+ }
}
int rsnd_ssi_probe(struct platform_device *pdev,
- struct rcar_snd_info *info,
+ const struct rsnd_of_data *of_data,
struct rsnd_priv *priv)
{
+ struct rcar_snd_info *info = rsnd_priv_to_info(priv);
struct rsnd_ssi_platform_info *pinfo;
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_mod_ops *ops;
struct clk *clk;
- struct rsnd_ssiu *ssiu;
struct rsnd_ssi *ssi;
char name[RSND_SSI_NAME_SIZE];
- int i, nr, ret;
+ int i, nr;
+
+ rsnd_of_parse_ssi(pdev, of_data, priv);
/*
* init SSI
*/
nr = info->ssi_info_nr;
- ssiu = devm_kzalloc(dev, sizeof(*ssiu) + (sizeof(*ssi) * nr),
- GFP_KERNEL);
- if (!ssiu) {
+ ssi = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL);
+ if (!ssi) {
dev_err(dev, "SSI allocate failed\n");
return -ENOMEM;
}
- priv->ssiu = ssiu;
- ssiu->ssi = (struct rsnd_ssi *)(ssiu + 1);
- ssiu->ssi_nr = nr;
+ priv->ssi = ssi;
+ priv->ssi_nr = nr;
for_each_rsnd_ssi(ssi, priv, i) {
pinfo = &info->ssi_info[i];
@@ -660,61 +682,15 @@ int rsnd_ssi_probe(struct platform_device *pdev,
ssi->clk = clk;
ops = &rsnd_ssi_non_ops;
+ if (pinfo->dma_id > 0)
+ ops = &rsnd_ssi_dma_ops;
+ else if (rsnd_ssi_pio_available(ssi))
+ ops = &rsnd_ssi_pio_ops;
- /*
- * SSI DMA case
- */
- if (pinfo->dma_id > 0) {
- ret = rsnd_dma_init(
- priv, rsnd_mod_to_dma(&ssi->mod),
- (rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY),
- pinfo->dma_id,
- rsnd_ssi_dma_inquiry,
- rsnd_ssi_dma_complete);
- if (ret < 0)
- dev_info(dev, "SSI DMA failed. try PIO transter\n");
- else
- ops = &rsnd_ssi_dma_ops;
-
- dev_dbg(dev, "SSI%d use DMA transfer\n", i);
- }
-
- /*
- * SSI PIO case
- */
- if (!rsnd_ssi_dma_available(ssi) &&
- rsnd_ssi_pio_available(ssi)) {
- ret = devm_request_irq(dev, pinfo->pio_irq,
- &rsnd_ssi_pio_interrupt,
- IRQF_SHARED,
- dev_name(dev), ssi);
- if (ret) {
- dev_err(dev, "SSI request interrupt failed\n");
- return ret;
- }
-
- ops = &rsnd_ssi_pio_ops;
-
- dev_dbg(dev, "SSI%d use PIO transfer\n", i);
- }
+ rsnd_mod_init(priv, &ssi->mod, ops, RSND_MOD_SSI, i);
- rsnd_mod_init(priv, &ssi->mod, ops, i);
+ rsnd_ssi_parent_clk_setup(priv, ssi);
}
- dev_dbg(dev, "ssi probed\n");
-
return 0;
}
-
-void rsnd_ssi_remove(struct platform_device *pdev,
- struct rsnd_priv *priv)
-{
- struct rsnd_ssi *ssi;
- int i;
-
- for_each_rsnd_ssi(ssi, priv, i) {
- if (rsnd_ssi_dma_available(ssi))
- rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod));
- }
-
-}
diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig
new file mode 100644
index 000000000000..89e89429b04a
--- /dev/null
+++ b/sound/soc/sirf/Kconfig
@@ -0,0 +1,14 @@
+config SND_SOC_SIRF
+ tristate "SoC Audio for the SiRF SoC chips"
+ depends on ARCH_SIRF || COMPILE_TEST
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+
+config SND_SOC_SIRF_AUDIO
+ tristate "SoC Audio support for SiRF internal audio codec"
+ depends on SND_SOC_SIRF
+ select SND_SOC_SIRF_AUDIO_CODEC
+ select SND_SOC_SIRF_AUDIO_PORT
+
+config SND_SOC_SIRF_AUDIO_PORT
+ select REGMAP_MMIO
+ tristate
diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile
new file mode 100644
index 000000000000..913b93231d4e
--- /dev/null
+++ b/sound/soc/sirf/Makefile
@@ -0,0 +1,5 @@
+snd-soc-sirf-audio-objs := sirf-audio.o
+snd-soc-sirf-audio-port-objs := sirf-audio-port.o
+
+obj-$(CONFIG_SND_SOC_SIRF_AUDIO) += snd-soc-sirf-audio.o
+obj-$(CONFIG_SND_SOC_SIRF_AUDIO_PORT) += snd-soc-sirf-audio-port.o
diff --git a/sound/soc/sirf/sirf-audio-port.c b/sound/soc/sirf/sirf-audio-port.c
new file mode 100644
index 000000000000..b04a53f2b4f6
--- /dev/null
+++ b/sound/soc/sirf/sirf-audio-port.c
@@ -0,0 +1,194 @@
+/*
+ * SiRF Audio port driver
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "sirf-audio-port.h"
+
+struct sirf_audio_port {
+ struct regmap *regmap;
+ struct snd_dmaengine_dai_dma_data playback_dma_data;
+ struct snd_dmaengine_dai_dma_data capture_dma_data;
+};
+
+static void sirf_audio_port_tx_enable(struct sirf_audio_port *port)
+{
+ regmap_update_bits(port->regmap, AUDIO_PORT_IC_TXFIFO_OP,
+ AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
+ regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0);
+ regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
+ regmap_update_bits(port->regmap, AUDIO_PORT_IC_TXFIFO_OP,
+ AUDIO_FIFO_START, AUDIO_FIFO_START);
+ regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_TX_CTRL,
+ IC_TX_ENABLE, IC_TX_ENABLE);
+}
+
+static void sirf_audio_port_tx_disable(struct sirf_audio_port *port)
+{
+ regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
+ regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_TX_CTRL,
+ IC_TX_ENABLE, ~IC_TX_ENABLE);
+}
+
+static void sirf_audio_port_rx_enable(struct sirf_audio_port *port,
+ int channels)
+{
+ regmap_update_bits(port->regmap, AUDIO_PORT_IC_RXFIFO_OP,
+ AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
+ regmap_write(port->regmap, AUDIO_PORT_IC_RXFIFO_INT_MSK, 0);
+ regmap_write(port->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0);
+ regmap_update_bits(port->regmap, AUDIO_PORT_IC_RXFIFO_OP,
+ AUDIO_FIFO_START, AUDIO_FIFO_START);
+ if (channels == 1)
+ regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL,
+ IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO);
+ else
+ regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL,
+ IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO);
+}
+
+static void sirf_audio_port_rx_disable(struct sirf_audio_port *port)
+{
+ regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL,
+ IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO);
+}
+
+static int sirf_audio_port_dai_probe(struct snd_soc_dai *dai)
+{
+ struct sirf_audio_port *port = snd_soc_dai_get_drvdata(dai);
+ snd_soc_dai_init_dma_data(dai, &port->playback_dma_data,
+ &port->capture_dma_data);
+ return 0;
+}
+
+static int sirf_audio_port_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct sirf_audio_port *port = snd_soc_dai_get_drvdata(dai);
+ int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (playback)
+ sirf_audio_port_tx_disable(port);
+ else
+ sirf_audio_port_rx_disable(port);
+ break;
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (playback)
+ sirf_audio_port_tx_enable(port);
+ else
+ sirf_audio_port_rx_enable(port,
+ substream->runtime->channels);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops sirf_audio_port_dai_ops = {
+ .trigger = sirf_audio_port_trigger,
+};
+
+static struct snd_soc_dai_driver sirf_audio_port_dai = {
+ .probe = sirf_audio_port_dai_probe,
+ .name = "sirf-audio-port",
+ .id = 0,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &sirf_audio_port_dai_ops,
+};
+
+static const struct snd_soc_component_driver sirf_audio_port_component = {
+ .name = "sirf-audio-port",
+};
+
+static const struct regmap_config sirf_audio_port_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK,
+ .cache_type = REGCACHE_NONE,
+};
+
+static int sirf_audio_port_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct sirf_audio_port *port;
+ void __iomem *base;
+ struct resource *mem_res;
+
+ port = devm_kzalloc(&pdev->dev,
+ sizeof(struct sirf_audio_port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
+
+ base = devm_ioremap(&pdev->dev, mem_res->start,
+ resource_size(mem_res));
+ if (base == NULL)
+ return -ENOMEM;
+
+ port->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &sirf_audio_port_regmap_config);
+ if (IS_ERR(port->regmap))
+ return PTR_ERR(port->regmap);
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &sirf_audio_port_component, &sirf_audio_port_dai, 1);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, port);
+ return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+}
+
+static const struct of_device_id sirf_audio_port_of_match[] = {
+ { .compatible = "sirf,audio-port", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sirf_audio_port_of_match);
+
+static struct platform_driver sirf_audio_port_driver = {
+ .driver = {
+ .name = "sirf-audio-port",
+ .owner = THIS_MODULE,
+ .of_match_table = sirf_audio_port_of_match,
+ },
+ .probe = sirf_audio_port_probe,
+};
+
+module_platform_driver(sirf_audio_port_driver);
+
+MODULE_DESCRIPTION("SiRF Audio Port driver");
+MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sirf/sirf-audio-port.h b/sound/soc/sirf/sirf-audio-port.h
new file mode 100644
index 000000000000..f32dc54f4499
--- /dev/null
+++ b/sound/soc/sirf/sirf-audio-port.h
@@ -0,0 +1,62 @@
+/*
+ * SiRF Audio port controllers define
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef _SIRF_AUDIO_PORT_H
+#define _SIRF_AUDIO_PORT_H
+
+#define AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK 0x3F
+#define AUDIO_PORT_TX_FIFO_SC_OFFSET 0
+#define AUDIO_PORT_TX_FIFO_LC_OFFSET 10
+#define AUDIO_PORT_TX_FIFO_HC_OFFSET 20
+
+#define TX_FIFO_SC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+ << AUDIO_PORT_TX_FIFO_SC_OFFSET)
+#define TX_FIFO_LC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+ << AUDIO_PORT_TX_FIFO_LC_OFFSET)
+#define TX_FIFO_HC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
+ << AUDIO_PORT_TX_FIFO_HC_OFFSET)
+
+#define AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK 0x0F
+#define AUDIO_PORT_RX_FIFO_SC_OFFSET 0
+#define AUDIO_PORT_RX_FIFO_LC_OFFSET 10
+#define AUDIO_PORT_RX_FIFO_HC_OFFSET 20
+
+#define RX_FIFO_SC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+ << AUDIO_PORT_RX_FIFO_SC_OFFSET)
+#define RX_FIFO_LC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+ << AUDIO_PORT_RX_FIFO_LC_OFFSET)
+#define RX_FIFO_HC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
+ << AUDIO_PORT_RX_FIFO_HC_OFFSET)
+#define AUDIO_PORT_IC_CODEC_TX_CTRL (0x00F4)
+#define AUDIO_PORT_IC_CODEC_RX_CTRL (0x00F8)
+
+#define AUDIO_PORT_IC_TXFIFO_OP (0x00FC)
+#define AUDIO_PORT_IC_TXFIFO_LEV_CHK (0x0100)
+#define AUDIO_PORT_IC_TXFIFO_STS (0x0104)
+#define AUDIO_PORT_IC_TXFIFO_INT (0x0108)
+#define AUDIO_PORT_IC_TXFIFO_INT_MSK (0x010C)
+
+#define AUDIO_PORT_IC_RXFIFO_OP (0x0110)
+#define AUDIO_PORT_IC_RXFIFO_LEV_CHK (0x0114)
+#define AUDIO_PORT_IC_RXFIFO_STS (0x0118)
+#define AUDIO_PORT_IC_RXFIFO_INT (0x011C)
+#define AUDIO_PORT_IC_RXFIFO_INT_MSK (0x0120)
+
+#define AUDIO_FIFO_START (1 << 0)
+#define AUDIO_FIFO_RESET (1 << 1)
+
+#define AUDIO_FIFO_FULL (1 << 0)
+#define AUDIO_FIFO_EMPTY (1 << 1)
+#define AUDIO_FIFO_OFLOW (1 << 2)
+#define AUDIO_FIFO_UFLOW (1 << 3)
+
+#define IC_TX_ENABLE (0x03)
+#define IC_RX_ENABLE_MONO (0x01)
+#define IC_RX_ENABLE_STEREO (0x03)
+
+#endif /*__SIRF_AUDIO_PORT_H*/
diff --git a/sound/soc/sirf/sirf-audio.c b/sound/soc/sirf/sirf-audio.c
new file mode 100644
index 000000000000..ecef51021653
--- /dev/null
+++ b/sound/soc/sirf/sirf-audio.c
@@ -0,0 +1,156 @@
+/*
+ * SiRF audio card driver
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+struct sirf_audio_card {
+ unsigned int gpio_hp_pa;
+ unsigned int gpio_spk_pa;
+};
+
+static int sirf_audio_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *ctrl, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card);
+ int on = !SND_SOC_DAPM_EVENT_OFF(event);
+ if (gpio_is_valid(sirf_audio_card->gpio_hp_pa))
+ gpio_set_value(sirf_audio_card->gpio_hp_pa, on);
+ return 0;
+}
+
+static int sirf_audio_spk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *ctrl, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card);
+ int on = !SND_SOC_DAPM_EVENT_OFF(event);
+
+ if (gpio_is_valid(sirf_audio_card->gpio_spk_pa))
+ gpio_set_value(sirf_audio_card->gpio_spk_pa, on);
+
+ return 0;
+}
+static const struct snd_soc_dapm_widget sirf_audio_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Hp", sirf_audio_hp_event),
+ SND_SOC_DAPM_SPK("Ext Spk", sirf_audio_spk_event),
+ SND_SOC_DAPM_MIC("Ext Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+ {"Hp", NULL, "HPOUTL"},
+ {"Hp", NULL, "HPOUTR"},
+ {"Ext Spk", NULL, "SPKOUT"},
+ {"MICIN1", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Ext Mic"},
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link sirf_audio_dai_link[] = {
+ {
+ .name = "SiRF audio card",
+ .stream_name = "SiRF audio HiFi",
+ .codec_dai_name = "sirf-audio-codec",
+ },
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_sirf_audio_card = {
+ .name = "SiRF audio card",
+ .owner = THIS_MODULE,
+ .dai_link = sirf_audio_dai_link,
+ .num_links = ARRAY_SIZE(sirf_audio_dai_link),
+ .dapm_widgets = sirf_audio_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sirf_audio_dapm_widgets),
+ .dapm_routes = intercon,
+ .num_dapm_routes = ARRAY_SIZE(intercon),
+};
+
+static int sirf_audio_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &snd_soc_sirf_audio_card;
+ struct sirf_audio_card *sirf_audio_card;
+ int ret;
+
+ sirf_audio_card = devm_kzalloc(&pdev->dev, sizeof(struct sirf_audio_card),
+ GFP_KERNEL);
+ if (sirf_audio_card == NULL)
+ return -ENOMEM;
+
+ sirf_audio_dai_link[0].cpu_of_node =
+ of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0);
+ sirf_audio_dai_link[0].platform_of_node =
+ of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0);
+ sirf_audio_dai_link[0].codec_of_node =
+ of_parse_phandle(pdev->dev.of_node, "sirf,audio-codec", 0);
+ sirf_audio_card->gpio_spk_pa = of_get_named_gpio(pdev->dev.of_node,
+ "spk-pa-gpios", 0);
+ sirf_audio_card->gpio_hp_pa = of_get_named_gpio(pdev->dev.of_node,
+ "hp-pa-gpios", 0);
+ if (gpio_is_valid(sirf_audio_card->gpio_spk_pa)) {
+ ret = devm_gpio_request_one(&pdev->dev,
+ sirf_audio_card->gpio_spk_pa,
+ GPIOF_OUT_INIT_LOW, "SPA_PA_SD");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to request GPIO_%d for reset: %d\n",
+ sirf_audio_card->gpio_spk_pa, ret);
+ return ret;
+ }
+ }
+ if (gpio_is_valid(sirf_audio_card->gpio_hp_pa)) {
+ ret = devm_gpio_request_one(&pdev->dev,
+ sirf_audio_card->gpio_hp_pa,
+ GPIOF_OUT_INIT_LOW, "HP_PA_SD");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to request GPIO_%d for reset: %d\n",
+ sirf_audio_card->gpio_hp_pa, ret);
+ return ret;
+ }
+ }
+
+ card->dev = &pdev->dev;
+ snd_soc_card_set_drvdata(card, sirf_audio_card);
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret)
+ dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
+
+ return ret;
+}
+
+static const struct of_device_id sirf_audio_of_match[] = {
+ {.compatible = "sirf,sirf-audio-card", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sirf_audio_of_match);
+
+static struct platform_driver sirf_audio_driver = {
+ .driver = {
+ .name = "sirf-audio-card",
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = sirf_audio_of_match,
+ },
+ .probe = sirf_audio_probe,
+};
+module_platform_driver(sirf_audio_driver);
+
+MODULE_AUTHOR("RongJun Ying <RongJun.Ying@csr.com>");
+MODULE_DESCRIPTION("ALSA SoC SIRF audio card driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index 375dc6dfba4e..bfed3e4c45ff 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -96,8 +96,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec)
{
dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n",
codec->name);
- if (!codec->reg_cache)
- return 0;
+
kfree(codec->reg_cache);
codec->reg_cache = NULL;
return 0;
@@ -117,8 +116,9 @@ int snd_soc_cache_read(struct snd_soc_codec *codec,
return -EINVAL;
mutex_lock(&codec->cache_rw_mutex);
- *value = snd_soc_get_cache_val(codec->reg_cache, reg,
- codec->driver->reg_word_size);
+ if (!ZERO_OR_NULL_PTR(codec->reg_cache))
+ *value = snd_soc_get_cache_val(codec->reg_cache, reg,
+ codec->driver->reg_word_size);
mutex_unlock(&codec->cache_rw_mutex);
return 0;
@@ -136,8 +136,9 @@ int snd_soc_cache_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
mutex_lock(&codec->cache_rw_mutex);
- snd_soc_set_cache_val(codec->reg_cache, reg, value,
- codec->driver->reg_word_size);
+ if (!ZERO_OR_NULL_PTR(codec->reg_cache))
+ snd_soc_set_cache_val(codec->reg_cache, reg, value,
+ codec->driver->reg_word_size);
mutex_unlock(&codec->cache_rw_mutex);
return 0;
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 5e9690c85d8f..91083e6a6b38 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -30,8 +30,6 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret = 0;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
@@ -52,17 +50,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
}
}
- if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- cpu_dai->playback_active++;
- codec_dai->playback_active++;
- } else {
- cpu_dai->capture_active++;
- codec_dai->capture_active++;
- }
-
- cpu_dai->active++;
- codec_dai->active++;
- rtd->codec->active++;
+ snd_soc_runtime_activate(rtd, cstream->direction);
mutex_unlock(&rtd->pcm_mutex);
@@ -81,8 +69,6 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
struct snd_soc_pcm_runtime *fe = cstream->private_data;
struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
struct snd_soc_platform *platform = fe->platform;
- struct snd_soc_dai *cpu_dai = fe->cpu_dai;
- struct snd_soc_dai *codec_dai = fe->codec_dai;
struct snd_soc_dpcm *dpcm;
struct snd_soc_dapm_widget_list *list;
int stream;
@@ -140,17 +126,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
- if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- cpu_dai->playback_active++;
- codec_dai->playback_active++;
- } else {
- cpu_dai->capture_active++;
- codec_dai->capture_active++;
- }
-
- cpu_dai->active++;
- codec_dai->active++;
- fe->codec->active++;
+ snd_soc_runtime_activate(fe, stream);
mutex_unlock(&fe->card->mutex);
@@ -202,23 +178,18 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_codec *codec = rtd->codec;
+ int stream;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
- if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- cpu_dai->playback_active--;
- codec_dai->playback_active--;
- } else {
- cpu_dai->capture_active--;
- codec_dai->capture_active--;
- }
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ stream = SNDRV_PCM_STREAM_PLAYBACK;
+ else
+ stream = SNDRV_PCM_STREAM_CAPTURE;
- snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
+ snd_soc_runtime_deactivate(rtd, stream);
- cpu_dai->active--;
- codec_dai->active--;
- codec->active--;
+ snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
if (!cpu_dai->active)
cpu_dai->rate = 0;
@@ -235,8 +206,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
cpu_dai->runtime = NULL;
if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
- rtd->dai_link->ignore_pmdown_time) {
+ if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
snd_soc_dapm_stream_event(rtd,
SNDRV_PCM_STREAM_PLAYBACK,
SND_SOC_DAPM_STREAM_STOP);
@@ -261,26 +231,17 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
struct snd_soc_platform *platform = fe->platform;
- struct snd_soc_dai *cpu_dai = fe->cpu_dai;
- struct snd_soc_dai *codec_dai = fe->codec_dai;
struct snd_soc_dpcm *dpcm;
int stream, ret;
mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
- if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
stream = SNDRV_PCM_STREAM_PLAYBACK;
- cpu_dai->playback_active--;
- codec_dai->playback_active--;
- } else {
+ else
stream = SNDRV_PCM_STREAM_CAPTURE;
- cpu_dai->capture_active--;
- codec_dai->capture_active--;
- }
- cpu_dai->active--;
- codec_dai->active--;
- fe->codec->active--;
+ snd_soc_runtime_deactivate(fe, stream);
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index fe1df50805a3..051c006281f5 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -56,7 +56,6 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
#endif
static DEFINE_MUTEX(client_mutex);
-static LIST_HEAD(dai_list);
static LIST_HEAD(platform_list);
static LIST_HEAD(codec_list);
static LIST_HEAD(component_list);
@@ -370,18 +369,22 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
{
char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
ssize_t len, ret = 0;
+ struct snd_soc_component *component;
struct snd_soc_dai *dai;
if (!buf)
return -ENOMEM;
- list_for_each_entry(dai, &dai_list, list) {
- len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name);
- if (len >= 0)
- ret += len;
- if (ret > PAGE_SIZE) {
- ret = PAGE_SIZE;
- break;
+ list_for_each_entry(component, &component_list, list) {
+ list_for_each_entry(dai, &component->dai_list, list) {
+ len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+ dai->name);
+ if (len >= 0)
+ ret += len;
+ if (ret > PAGE_SIZE) {
+ ret = PAGE_SIZE;
+ break;
+ }
}
}
@@ -855,6 +858,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
{
struct snd_soc_dai_link *dai_link = &card->dai_link[num];
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+ struct snd_soc_component *component;
struct snd_soc_codec *codec;
struct snd_soc_platform *platform;
struct snd_soc_dai *codec_dai, *cpu_dai;
@@ -863,18 +867,20 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);
/* Find CPU DAI from registered DAIs*/
- list_for_each_entry(cpu_dai, &dai_list, list) {
+ list_for_each_entry(component, &component_list, list) {
if (dai_link->cpu_of_node &&
- (cpu_dai->dev->of_node != dai_link->cpu_of_node))
+ component->dev->of_node != dai_link->cpu_of_node)
continue;
if (dai_link->cpu_name &&
- strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name))
- continue;
- if (dai_link->cpu_dai_name &&
- strcmp(cpu_dai->name, dai_link->cpu_dai_name))
+ strcmp(dev_name(component->dev), dai_link->cpu_name))
continue;
+ list_for_each_entry(cpu_dai, &component->dai_list, list) {
+ if (dai_link->cpu_dai_name &&
+ strcmp(cpu_dai->name, dai_link->cpu_dai_name))
+ continue;
- rtd->cpu_dai = cpu_dai;
+ rtd->cpu_dai = cpu_dai;
+ }
}
if (!rtd->cpu_dai) {
@@ -899,12 +905,10 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
* CODEC found, so find CODEC DAI from registered DAIs from
* this CODEC
*/
- list_for_each_entry(codec_dai, &dai_list, list) {
- if (codec->dev == codec_dai->dev &&
- !strcmp(codec_dai->name,
- dai_link->codec_dai_name)) {
-
+ list_for_each_entry(codec_dai, &codec->component.dai_list, list) {
+ if (!strcmp(codec_dai->name, dai_link->codec_dai_name)) {
rtd->codec_dai = codec_dai;
+ break;
}
}
@@ -1128,15 +1132,21 @@ static int soc_probe_codec(struct snd_soc_card *card,
driver->num_dapm_widgets);
/* Create DAPM widgets for each DAI stream */
- list_for_each_entry(dai, &dai_list, list) {
- if (dai->dev != codec->dev)
- continue;
-
+ list_for_each_entry(dai, &codec->component.dai_list, list)
snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
- }
codec->dapm.idle_bias_off = driver->idle_bias_off;
+ if (!codec->write && dev_get_regmap(codec->dev, NULL)) {
+ /* Set the default I/O up try regmap */
+ ret = snd_soc_codec_set_cache_io(codec, NULL);
+ if (ret < 0) {
+ dev_err(codec->dev,
+ "Failed to set cache I/O: %d\n", ret);
+ goto err_probe;
+ }
+ }
+
if (driver->probe) {
ret = driver->probe(codec);
if (ret < 0) {
@@ -1150,10 +1160,6 @@ static int soc_probe_codec(struct snd_soc_card *card,
codec->name);
}
- /* If the driver didn't set I/O up try regmap */
- if (!codec->write && dev_get_regmap(codec->dev, NULL))
- snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
-
if (driver->controls)
snd_soc_add_codec_controls(codec, driver->controls,
driver->num_controls);
@@ -1180,6 +1186,7 @@ static int soc_probe_platform(struct snd_soc_card *card,
{
int ret = 0;
const struct snd_soc_platform_driver *driver = platform->driver;
+ struct snd_soc_component *component;
struct snd_soc_dai *dai;
platform->card = card;
@@ -1195,11 +1202,11 @@ static int soc_probe_platform(struct snd_soc_card *card,
driver->dapm_widgets, driver->num_dapm_widgets);
/* Create DAPM widgets for each DAI stream */
- list_for_each_entry(dai, &dai_list, list) {
- if (dai->dev != platform->dev)
+ list_for_each_entry(component, &component_list, list) {
+ if (component->dev != platform->dev)
continue;
-
- snd_soc_dapm_new_dai_widgets(&platform->dapm, dai);
+ list_for_each_entry(dai, &component->dai_list, list)
+ snd_soc_dapm_new_dai_widgets(&platform->dapm, dai);
}
platform->dapm.idle_bias_off = 1;
@@ -1246,7 +1253,7 @@ static int soc_post_component_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_link = NULL;
struct snd_soc_aux_dev *aux_dev = NULL;
struct snd_soc_pcm_runtime *rtd;
- const char *temp, *name;
+ const char *name;
int ret = 0;
if (!dailess) {
@@ -1260,10 +1267,6 @@ static int soc_post_component_init(struct snd_soc_card *card,
}
rtd->card = card;
- /* machine controls, routes and widgets are not prefixed */
- temp = codec->name_prefix;
- codec->name_prefix = NULL;
-
/* do machine specific initialization */
if (!dailess && dai_link->init)
ret = dai_link->init(rtd);
@@ -1273,7 +1276,6 @@ static int soc_post_component_init(struct snd_soc_card *card,
dev_err(card->dev, "ASoC: failed to init %s: %d\n", name, ret);
return ret;
}
- codec->name_prefix = temp;
/* register the rtd device */
rtd->codec = codec;
@@ -1654,7 +1656,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
}
/* card bind complete so register a sound card */
- ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
card->owner, 0, &card->snd_card);
if (ret < 0) {
dev_err(card->dev,
@@ -1662,7 +1664,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
card->name, ret);
goto base_error;
}
- card->snd_card->dev = card->dev;
card->dapm.bias_level = SND_SOC_BIAS_OFF;
card->dapm.dev = card->dev;
@@ -2571,10 +2572,10 @@ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
- uinfo->value.enumerated.items = e->max;
+ uinfo->value.enumerated.items = e->items;
- if (uinfo->value.enumerated.item > e->max - 1)
- uinfo->value.enumerated.item = e->max - 1;
+ if (uinfo->value.enumerated.item >= e->items)
+ uinfo->value.enumerated.item = e->items - 1;
strlcpy(uinfo->value.enumerated.name,
e->texts[uinfo->value.enumerated.item],
sizeof(uinfo->value.enumerated.name));
@@ -2596,14 +2597,18 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int val;
+ unsigned int val, item;
+ unsigned int reg_val;
- val = snd_soc_read(codec, e->reg);
- ucontrol->value.enumerated.item[0]
- = (val >> e->shift_l) & e->mask;
- if (e->shift_l != e->shift_r)
- ucontrol->value.enumerated.item[1] =
- (val >> e->shift_r) & e->mask;
+ reg_val = snd_soc_read(codec, e->reg);
+ val = (reg_val >> e->shift_l) & e->mask;
+ item = snd_soc_enum_val_to_item(e, val);
+ ucontrol->value.enumerated.item[0] = item;
+ if (e->shift_l != e->shift_r) {
+ val = (reg_val >> e->shift_l) & e->mask;
+ item = snd_soc_enum_val_to_item(e, val);
+ ucontrol->value.enumerated.item[1] = item;
+ }
return 0;
}
@@ -2623,17 +2628,18 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
unsigned int val;
unsigned int mask;
- if (ucontrol->value.enumerated.item[0] > e->max - 1)
+ if (item[0] >= e->items)
return -EINVAL;
- val = ucontrol->value.enumerated.item[0] << e->shift_l;
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
mask = e->mask << e->shift_l;
if (e->shift_l != e->shift_r) {
- if (ucontrol->value.enumerated.item[1] > e->max - 1)
+ if (item[1] >= e->items)
return -EINVAL;
- val |= ucontrol->value.enumerated.item[1] << e->shift_r;
+ val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
mask |= e->mask << e->shift_r;
}
@@ -2642,78 +2648,46 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
/**
- * snd_soc_get_value_enum_double - semi enumerated double mixer get callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to get the value of a double semi enumerated mixer.
+ * snd_soc_read_signed - Read a codec register and interprete as signed value
+ * @codec: codec
+ * @reg: Register to read
+ * @mask: Mask to use after shifting the register value
+ * @shift: Right shift of register value
+ * @sign_bit: Bit that describes if a number is negative or not.
*
- * Semi enumerated mixer: the enumerated items are referred as values. Can be
- * used for handling bitfield coded enumeration for example.
+ * This functions reads a codec register. The register value is shifted right
+ * by 'shift' bits and masked with the given 'mask'. Afterwards it translates
+ * the given registervalue into a signed integer if sign_bit is non-zero.
*
- * Returns 0 for success.
+ * Returns the register value as signed int.
*/
-int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int mask, unsigned int shift, unsigned int sign_bit)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int reg_val, val, mux;
+ int ret;
+ unsigned int val;
- reg_val = snd_soc_read(codec, e->reg);
- val = (reg_val >> e->shift_l) & e->mask;
- for (mux = 0; mux < e->max; mux++) {
- if (val == e->values[mux])
- break;
- }
- ucontrol->value.enumerated.item[0] = mux;
- if (e->shift_l != e->shift_r) {
- val = (reg_val >> e->shift_r) & e->mask;
- for (mux = 0; mux < e->max; mux++) {
- if (val == e->values[mux])
- break;
- }
- ucontrol->value.enumerated.item[1] = mux;
- }
+ val = (snd_soc_read(codec, reg) >> shift) & mask;
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double);
+ if (!sign_bit)
+ return val;
-/**
- * snd_soc_put_value_enum_double - semi enumerated double mixer put callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to set the value of a double semi enumerated mixer.
- *
- * Semi enumerated mixer: the enumerated items are referred as values. Can be
- * used for handling bitfield coded enumeration for example.
- *
- * Returns 0 for success.
- */
-int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int val;
- unsigned int mask;
+ /* non-negative number */
+ if (!(val & BIT(sign_bit)))
+ return val;
- if (ucontrol->value.enumerated.item[0] > e->max - 1)
- return -EINVAL;
- val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
- mask = e->mask << e->shift_l;
- if (e->shift_l != e->shift_r) {
- if (ucontrol->value.enumerated.item[1] > e->max - 1)
- return -EINVAL;
- val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
- mask |= e->mask << e->shift_r;
- }
+ ret = val;
- return snd_soc_update_bits_locked(codec, e->reg, mask, val);
+ /*
+ * The register most probably does not contain a full-sized int.
+ * Instead we have an arbitrary number of bits in a signed
+ * representation which has to be translated into a full-sized int.
+ * This is done by filling up all bits above the sign-bit.
+ */
+ ret |= ~((int)(BIT(sign_bit) - 1));
+
+ return ret;
}
-EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);
/**
* snd_soc_info_volsw - single mixer info callback
@@ -2743,7 +2717,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = platform_max;
+ uinfo->value.integer.max = platform_max - mc->min;
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
@@ -2769,11 +2743,16 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
unsigned int shift = mc->shift;
unsigned int rshift = mc->rshift;
int max = mc->max;
+ int min = mc->min;
+ int sign_bit = mc->sign_bit;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
- ucontrol->value.integer.value[0] =
- (snd_soc_read(codec, reg) >> shift) & mask;
+ if (sign_bit)
+ mask = BIT(sign_bit + 1) - 1;
+
+ ucontrol->value.integer.value[0] = snd_soc_read_signed(codec, reg, mask,
+ shift, sign_bit) - min;
if (invert)
ucontrol->value.integer.value[0] =
max - ucontrol->value.integer.value[0];
@@ -2781,10 +2760,12 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
if (snd_soc_volsw_is_stereo(mc)) {
if (reg == reg2)
ucontrol->value.integer.value[1] =
- (snd_soc_read(codec, reg) >> rshift) & mask;
+ snd_soc_read_signed(codec, reg, mask, rshift,
+ sign_bit) - min;
else
ucontrol->value.integer.value[1] =
- (snd_soc_read(codec, reg2) >> shift) & mask;
+ snd_soc_read_signed(codec, reg2, mask, shift,
+ sign_bit) - min;
if (invert)
ucontrol->value.integer.value[1] =
max - ucontrol->value.integer.value[1];
@@ -2815,20 +2796,25 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
unsigned int shift = mc->shift;
unsigned int rshift = mc->rshift;
int max = mc->max;
+ int min = mc->min;
+ unsigned int sign_bit = mc->sign_bit;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
int err;
- bool type_2r = 0;
+ bool type_2r = false;
unsigned int val2 = 0;
unsigned int val, val_mask;
- val = (ucontrol->value.integer.value[0] & mask);
+ if (sign_bit)
+ mask = BIT(sign_bit + 1) - 1;
+
+ val = ((ucontrol->value.integer.value[0] + min) & mask);
if (invert)
val = max - val;
val_mask = mask << shift;
val = val << shift;
if (snd_soc_volsw_is_stereo(mc)) {
- val2 = (ucontrol->value.integer.value[1] & mask);
+ val2 = ((ucontrol->value.integer.value[1] + min) & mask);
if (invert)
val2 = max - val2;
if (reg == reg2) {
@@ -2836,7 +2822,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
val |= val2 << rshift;
} else {
val2 = val2 << shift;
- type_2r = 1;
+ type_2r = true;
}
}
err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
@@ -3234,7 +3220,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
struct soc_bytes *params = (void *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int ret, len;
- unsigned int val;
+ unsigned int val, mask;
void *data;
if (!codec->using_regmap)
@@ -3264,12 +3250,36 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
((u8 *)data)[0] |= val;
break;
case 2:
- ((u16 *)data)[0] &= cpu_to_be16(~params->mask);
- ((u16 *)data)[0] |= cpu_to_be16(val);
+ mask = ~params->mask;
+ ret = regmap_parse_val(codec->control_data,
+ &mask, &mask);
+ if (ret != 0)
+ goto out;
+
+ ((u16 *)data)[0] &= mask;
+
+ ret = regmap_parse_val(codec->control_data,
+ &val, &val);
+ if (ret != 0)
+ goto out;
+
+ ((u16 *)data)[0] |= val;
break;
case 4:
- ((u32 *)data)[0] &= cpu_to_be32(~params->mask);
- ((u32 *)data)[0] |= cpu_to_be32(val);
+ mask = ~params->mask;
+ ret = regmap_parse_val(codec->control_data,
+ &mask, &mask);
+ if (ret != 0)
+ goto out;
+
+ ((u32 *)data)[0] &= mask;
+
+ ret = regmap_parse_val(codec->control_data,
+ &val, &val);
+ if (ret != 0)
+ goto out;
+
+ ((u32 *)data)[0] |= val;
break;
default:
ret = -EINVAL;
@@ -3609,6 +3619,30 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
/**
+ * snd_soc_xlate_tdm_slot - generate tx/rx slot mask.
+ * @slots: Number of slots in use.
+ * @tx_mask: bitmask representing active TX slots.
+ * @rx_mask: bitmask representing active RX slots.
+ *
+ * Generates the TDM tx and rx slot default masks for DAI.
+ */
+static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
+ unsigned int *tx_mask,
+ unsigned int *rx_mask)
+{
+ if (*tx_mask || *rx_mask)
+ return 0;
+
+ if (!slots)
+ return -EINVAL;
+
+ *tx_mask = (1 << slots) - 1;
+ *rx_mask = (1 << slots) - 1;
+
+ return 0;
+}
+
+/**
* snd_soc_dai_set_tdm_slot - configure DAI TDM.
* @dai: DAI
* @tx_mask: bitmask representing active TX slots.
@@ -3622,11 +3656,17 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
{
+ if (dai->driver && dai->driver->ops->xlate_tdm_slot_mask)
+ dai->driver->ops->xlate_tdm_slot_mask(slots,
+ &tx_mask, &rx_mask);
+ else
+ snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
+
if (dai->driver && dai->driver->ops->set_tdm_slot)
return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
slots, slot_width);
else
- return -EINVAL;
+ return -ENOTSUPP;
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
@@ -3882,95 +3922,42 @@ static inline char *fmt_multiple_name(struct device *dev,
}
/**
- * snd_soc_register_dai - Register a DAI with the ASoC core
+ * snd_soc_unregister_dai - Unregister DAIs from the ASoC core
*
- * @dai: DAI to register
+ * @component: The component for which the DAIs should be unregistered
*/
-static int snd_soc_register_dai(struct device *dev,
- struct snd_soc_dai_driver *dai_drv)
+static void snd_soc_unregister_dais(struct snd_soc_component *component)
{
- struct snd_soc_codec *codec;
- struct snd_soc_dai *dai;
+ struct snd_soc_dai *dai, *_dai;
- dev_dbg(dev, "ASoC: dai register %s\n", dev_name(dev));
-
- dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
- if (dai == NULL)
- return -ENOMEM;
-
- /* create DAI component name */
- dai->name = fmt_single_name(dev, &dai->id);
- if (dai->name == NULL) {
+ list_for_each_entry_safe(dai, _dai, &component->dai_list, list) {
+ dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n",
+ dai->name);
+ list_del(&dai->list);
+ kfree(dai->name);
kfree(dai);
- return -ENOMEM;
- }
-
- dai->dev = dev;
- dai->driver = dai_drv;
- dai->dapm.dev = dev;
- if (!dai->driver->ops)
- dai->driver->ops = &null_dai_ops;
-
- mutex_lock(&client_mutex);
-
- list_for_each_entry(codec, &codec_list, list) {
- if (codec->dev == dev) {
- dev_dbg(dev, "ASoC: Mapped DAI %s to CODEC %s\n",
- dai->name, codec->name);
- dai->codec = codec;
- break;
- }
- }
-
- if (!dai->codec)
- dai->dapm.idle_bias_off = 1;
-
- list_add(&dai->list, &dai_list);
-
- mutex_unlock(&client_mutex);
-
- dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
-
- return 0;
-}
-
-/**
- * snd_soc_unregister_dai - Unregister a DAI from the ASoC core
- *
- * @dai: DAI to unregister
- */
-static void snd_soc_unregister_dai(struct device *dev)
-{
- struct snd_soc_dai *dai;
-
- list_for_each_entry(dai, &dai_list, list) {
- if (dev == dai->dev)
- goto found;
}
- return;
-
-found:
- mutex_lock(&client_mutex);
- list_del(&dai->list);
- mutex_unlock(&client_mutex);
-
- dev_dbg(dev, "ASoC: Unregistered DAI '%s'\n", dai->name);
- kfree(dai->name);
- kfree(dai);
}
/**
- * snd_soc_register_dais - Register multiple DAIs with the ASoC core
+ * snd_soc_register_dais - Register a DAI with the ASoC core
*
- * @dai: Array of DAIs to register
+ * @component: The component the DAIs are registered for
+ * @codec: The CODEC that the DAIs are registered for, NULL if the component is
+ * not a CODEC.
+ * @dai_drv: DAI driver to use for the DAIs
* @count: Number of DAIs
+ * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the
+ * parent's name.
*/
-static int snd_soc_register_dais(struct device *dev,
- struct snd_soc_dai_driver *dai_drv, size_t count)
+static int snd_soc_register_dais(struct snd_soc_component *component,
+ struct snd_soc_codec *codec, struct snd_soc_dai_driver *dai_drv,
+ size_t count, bool legacy_dai_naming)
{
- struct snd_soc_codec *codec;
+ struct device *dev = component->dev;
struct snd_soc_dai *dai;
- int i, ret = 0;
+ unsigned int i;
+ int ret;
dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);
@@ -3982,70 +3969,54 @@ static int snd_soc_register_dais(struct device *dev,
goto err;
}
- /* create DAI component name */
- dai->name = fmt_multiple_name(dev, &dai_drv[i]);
+ /*
+ * Back in the old days when we still had component-less DAIs,
+ * instead of having a static name, component-less DAIs would
+ * inherit the name of the parent device so it is possible to
+ * register multiple instances of the DAI. We still need to keep
+ * the same naming style even though those DAIs are not
+ * component-less anymore.
+ */
+ if (count == 1 && legacy_dai_naming) {
+ dai->name = fmt_single_name(dev, &dai->id);
+ } else {
+ dai->name = fmt_multiple_name(dev, &dai_drv[i]);
+ if (dai_drv[i].id)
+ dai->id = dai_drv[i].id;
+ else
+ dai->id = i;
+ }
if (dai->name == NULL) {
kfree(dai);
- ret = -EINVAL;
+ ret = -ENOMEM;
goto err;
}
+ dai->component = component;
+ dai->codec = codec;
dai->dev = dev;
dai->driver = &dai_drv[i];
- if (dai->driver->id)
- dai->id = dai->driver->id;
- else
- dai->id = i;
dai->dapm.dev = dev;
if (!dai->driver->ops)
dai->driver->ops = &null_dai_ops;
- mutex_lock(&client_mutex);
-
- list_for_each_entry(codec, &codec_list, list) {
- if (codec->dev == dev) {
- dev_dbg(dev,
- "ASoC: Mapped DAI %s to CODEC %s\n",
- dai->name, codec->name);
- dai->codec = codec;
- break;
- }
- }
-
if (!dai->codec)
dai->dapm.idle_bias_off = 1;
- list_add(&dai->list, &dai_list);
-
- mutex_unlock(&client_mutex);
+ list_add(&dai->list, &component->dai_list);
- dev_dbg(dai->dev, "ASoC: Registered DAI '%s'\n", dai->name);
+ dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
}
return 0;
err:
- for (i--; i >= 0; i--)
- snd_soc_unregister_dai(dev);
+ snd_soc_unregister_dais(component);
return ret;
}
/**
- * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core
- *
- * @dai: Array of DAIs to unregister
- * @count: Number of DAIs
- */
-static void snd_soc_unregister_dais(struct device *dev, size_t count)
-{
- int i;
-
- for (i = 0; i < count; i++)
- snd_soc_unregister_dai(dev);
-}
-
-/**
* snd_soc_register_component - Register a component with the ASoC core
*
*/
@@ -4053,6 +4024,7 @@ static int
__snd_soc_register_component(struct device *dev,
struct snd_soc_component *cmpnt,
const struct snd_soc_component_driver *cmpnt_drv,
+ struct snd_soc_codec *codec,
struct snd_soc_dai_driver *dai_drv,
int num_dai, bool allow_single_dai)
{
@@ -4075,20 +4047,10 @@ __snd_soc_register_component(struct device *dev,
cmpnt->driver = cmpnt_drv;
cmpnt->dai_drv = dai_drv;
cmpnt->num_dai = num_dai;
+ INIT_LIST_HEAD(&cmpnt->dai_list);
- /*
- * snd_soc_register_dai() uses fmt_single_name(), and
- * snd_soc_register_dais() uses fmt_multiple_name()
- * for dai->name which is used for name based matching
- *
- * this function is used from cpu/codec.
- * allow_single_dai flag can ignore "codec" driver reworking
- * since it had been used snd_soc_register_dais(),
- */
- if ((1 == num_dai) && allow_single_dai)
- ret = snd_soc_register_dai(dev, dai_drv);
- else
- ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+ ret = snd_soc_register_dais(cmpnt, codec, dai_drv, num_dai,
+ allow_single_dai);
if (ret < 0) {
dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
goto error_component_name;
@@ -4121,7 +4083,9 @@ int snd_soc_register_component(struct device *dev,
return -ENOMEM;
}
- return __snd_soc_register_component(dev, cmpnt, cmpnt_drv,
+ cmpnt->ignore_pmdown_time = true;
+
+ return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL,
dai_drv, num_dai, true);
}
EXPORT_SYMBOL_GPL(snd_soc_register_component);
@@ -4141,7 +4105,7 @@ void snd_soc_unregister_component(struct device *dev)
return;
found:
- snd_soc_unregister_dais(dev, cmpnt->num_dai);
+ snd_soc_unregister_dais(cmpnt);
mutex_lock(&client_mutex);
list_del(&cmpnt->list);
@@ -4319,7 +4283,7 @@ int snd_soc_register_codec(struct device *dev,
codec->volatile_register = codec_drv->volatile_register;
codec->readable_register = codec_drv->readable_register;
codec->writable_register = codec_drv->writable_register;
- codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time;
+ codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
codec->dapm.dev = dev;
codec->dapm.codec = codec;
@@ -4342,7 +4306,7 @@ int snd_soc_register_codec(struct device *dev,
/* register component */
ret = __snd_soc_register_component(dev, &codec->component,
&codec_drv->component_driver,
- dai_drv, num_dai, false);
+ codec, dai_drv, num_dai, false);
if (ret < 0) {
dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret);
goto fail_codec_name;
@@ -4417,6 +4381,122 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name);
+static const struct snd_soc_dapm_widget simple_widgets[] = {
+ SND_SOC_DAPM_MIC("Microphone", NULL),
+ SND_SOC_DAPM_LINE("Line", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
+ const char *propname)
+{
+ struct device_node *np = card->dev->of_node;
+ struct snd_soc_dapm_widget *widgets;
+ const char *template, *wname;
+ int i, j, num_widgets, ret;
+
+ num_widgets = of_property_count_strings(np, propname);
+ if (num_widgets < 0) {
+ dev_err(card->dev,
+ "ASoC: Property '%s' does not exist\n", propname);
+ return -EINVAL;
+ }
+ if (num_widgets & 1) {
+ dev_err(card->dev,
+ "ASoC: Property '%s' length is not even\n", propname);
+ return -EINVAL;
+ }
+
+ num_widgets /= 2;
+ if (!num_widgets) {
+ dev_err(card->dev, "ASoC: Property '%s's length is zero\n",
+ propname);
+ return -EINVAL;
+ }
+
+ widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets),
+ GFP_KERNEL);
+ if (!widgets) {
+ dev_err(card->dev,
+ "ASoC: Could not allocate memory for widgets\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < num_widgets; i++) {
+ ret = of_property_read_string_index(np, propname,
+ 2 * i, &template);
+ if (ret) {
+ dev_err(card->dev,
+ "ASoC: Property '%s' index %d read error:%d\n",
+ propname, 2 * i, ret);
+ return -EINVAL;
+ }
+
+ for (j = 0; j < ARRAY_SIZE(simple_widgets); j++) {
+ if (!strncmp(template, simple_widgets[j].name,
+ strlen(simple_widgets[j].name))) {
+ widgets[i] = simple_widgets[j];
+ break;
+ }
+ }
+
+ if (j >= ARRAY_SIZE(simple_widgets)) {
+ dev_err(card->dev,
+ "ASoC: DAPM widget '%s' is not supported\n",
+ template);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_string_index(np, propname,
+ (2 * i) + 1,
+ &wname);
+ if (ret) {
+ dev_err(card->dev,
+ "ASoC: Property '%s' index %d read error:%d\n",
+ propname, (2 * i) + 1, ret);
+ return -EINVAL;
+ }
+
+ widgets[i].name = wname;
+ }
+
+ card->dapm_widgets = widgets;
+ card->num_dapm_widgets = num_widgets;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
+
+int snd_soc_of_parse_tdm_slot(struct device_node *np,
+ unsigned int *slots,
+ unsigned int *slot_width)
+{
+ u32 val;
+ int ret;
+
+ if (of_property_read_bool(np, "dai-tdm-slot-num")) {
+ ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
+ if (ret)
+ return ret;
+
+ if (slots)
+ *slots = val;
+ }
+
+ if (of_property_read_bool(np, "dai-tdm-slot-width")) {
+ ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
+ if (ret)
+ return ret;
+
+ if (slot_width)
+ *slot_width = val;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
+
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname)
{
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index dc8ff13187f7..c8a780d0d057 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -70,8 +70,6 @@ static int dapm_up_seq[] = {
[snd_soc_dapm_aif_out] = 4,
[snd_soc_dapm_mic] = 5,
[snd_soc_dapm_mux] = 6,
- [snd_soc_dapm_virt_mux] = 6,
- [snd_soc_dapm_value_mux] = 6,
[snd_soc_dapm_dac] = 7,
[snd_soc_dapm_switch] = 8,
[snd_soc_dapm_mixer] = 8,
@@ -102,8 +100,6 @@ static int dapm_down_seq[] = {
[snd_soc_dapm_mic] = 7,
[snd_soc_dapm_micbias] = 8,
[snd_soc_dapm_mux] = 9,
- [snd_soc_dapm_virt_mux] = 9,
- [snd_soc_dapm_value_mux] = 9,
[snd_soc_dapm_aif_in] = 10,
[snd_soc_dapm_aif_out] = 10,
[snd_soc_dapm_dai_in] = 10,
@@ -115,6 +111,12 @@ static int dapm_down_seq[] = {
[snd_soc_dapm_post] = 14,
};
+static void dapm_assert_locked(struct snd_soc_dapm_context *dapm)
+{
+ if (dapm->card && dapm->card->instantiated)
+ lockdep_assert_held(&dapm->card->dapm_mutex);
+}
+
static void pop_wait(u32 pop_time)
{
if (pop_time)
@@ -146,15 +148,16 @@ static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
return !list_empty(&w->dirty);
}
-void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
+static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
{
+ dapm_assert_locked(w->dapm);
+
if (!dapm_dirty_widget(w)) {
dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
w->name, reason);
list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
}
}
-EXPORT_SYMBOL_GPL(dapm_mark_dirty);
void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm)
{
@@ -361,6 +364,8 @@ static void dapm_reset(struct snd_soc_card *card)
{
struct snd_soc_dapm_widget *w;
+ lockdep_assert_held(&card->dapm_mutex);
+
memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
list_for_each_entry(w, &card->widgets, list) {
@@ -386,7 +391,8 @@ static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg,
return -1;
}
-static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val)
+static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg,
+ unsigned int val)
{
if (w->codec)
return snd_soc_write(w->codec, reg, val);
@@ -498,131 +504,40 @@ out:
return ret;
}
-/* set up initial codec paths */
-static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
- struct snd_soc_dapm_path *p, int i)
+/* connect mux widget to its interconnecting audio paths */
+static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
+ struct snd_soc_dapm_path *path, const char *control_name,
+ const struct snd_kcontrol_new *kcontrol)
{
- switch (w->id) {
- case snd_soc_dapm_switch:
- case snd_soc_dapm_mixer:
- case snd_soc_dapm_mixer_named_ctl: {
- int val;
- struct soc_mixer_control *mc = (struct soc_mixer_control *)
- w->kcontrol_news[i].private_value;
- int reg = mc->reg;
- unsigned int shift = mc->shift;
- int max = mc->max;
- unsigned int mask = (1 << fls(max)) - 1;
- unsigned int invert = mc->invert;
-
- if (reg != SND_SOC_NOPM) {
- soc_widget_read(w, reg, &val);
- val = (val >> shift) & mask;
- if (invert)
- val = max - val;
- p->connect = !!val;
- } else {
- p->connect = 0;
- }
-
- }
- break;
- case snd_soc_dapm_mux: {
- struct soc_enum *e = (struct soc_enum *)
- w->kcontrol_news[i].private_value;
- int val, item;
-
- soc_widget_read(w, e->reg, &val);
- item = (val >> e->shift_l) & e->mask;
-
- if (item < e->max && !strcmp(p->name, e->texts[item]))
- p->connect = 1;
- else
- p->connect = 0;
- }
- break;
- case snd_soc_dapm_virt_mux: {
- struct soc_enum *e = (struct soc_enum *)
- w->kcontrol_news[i].private_value;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int val, item;
+ int i;
- p->connect = 0;
+ if (e->reg != SND_SOC_NOPM) {
+ soc_widget_read(dest, e->reg, &val);
+ val = (val >> e->shift_l) & e->mask;
+ item = snd_soc_enum_val_to_item(e, val);
+ } else {
/* since a virtual mux has no backing registers to
* decide which path to connect, it will try to match
* with the first enumeration. This is to ensure
* that the default mux choice (the first) will be
* correctly powered up during initialization.
*/
- if (!strcmp(p->name, e->texts[0]))
- p->connect = 1;
- }
- break;
- case snd_soc_dapm_value_mux: {
- struct soc_enum *e = (struct soc_enum *)
- w->kcontrol_news[i].private_value;
- int val, item;
-
- soc_widget_read(w, e->reg, &val);
- val = (val >> e->shift_l) & e->mask;
- for (item = 0; item < e->max; item++) {
- if (val == e->values[item])
- break;
- }
-
- if (item < e->max && !strcmp(p->name, e->texts[item]))
- p->connect = 1;
- else
- p->connect = 0;
- }
- break;
- /* does not affect routing - always connected */
- case snd_soc_dapm_pga:
- case snd_soc_dapm_out_drv:
- case snd_soc_dapm_output:
- case snd_soc_dapm_adc:
- case snd_soc_dapm_input:
- case snd_soc_dapm_siggen:
- case snd_soc_dapm_dac:
- case snd_soc_dapm_micbias:
- case snd_soc_dapm_vmid:
- case snd_soc_dapm_supply:
- case snd_soc_dapm_regulator_supply:
- case snd_soc_dapm_clock_supply:
- case snd_soc_dapm_aif_in:
- case snd_soc_dapm_aif_out:
- case snd_soc_dapm_dai_in:
- case snd_soc_dapm_dai_out:
- case snd_soc_dapm_hp:
- case snd_soc_dapm_mic:
- case snd_soc_dapm_spk:
- case snd_soc_dapm_line:
- case snd_soc_dapm_dai_link:
- case snd_soc_dapm_kcontrol:
- p->connect = 1;
- break;
- /* does affect routing - dynamically connected */
- case snd_soc_dapm_pre:
- case snd_soc_dapm_post:
- p->connect = 0;
- break;
+ item = 0;
}
-}
-
-/* connect mux widget to its interconnecting audio paths */
-static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
- struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
- struct snd_soc_dapm_path *path, const char *control_name,
- const struct snd_kcontrol_new *kcontrol)
-{
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- int i;
- for (i = 0; i < e->max; i++) {
+ for (i = 0; i < e->items; i++) {
if (!(strcmp(control_name, e->texts[i]))) {
list_add(&path->list, &dapm->card->paths);
list_add(&path->list_sink, &dest->sources);
list_add(&path->list_source, &src->sinks);
path->name = (char*)e->texts[i];
- dapm_set_path_status(dest, path, 0);
+ if (i == item)
+ path->connect = 1;
+ else
+ path->connect = 0;
return 0;
}
}
@@ -630,6 +545,30 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
return -ENODEV;
}
+/* set up initial codec paths */
+static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w,
+ struct snd_soc_dapm_path *p, int i)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)
+ w->kcontrol_news[i].private_value;
+ unsigned int reg = mc->reg;
+ unsigned int shift = mc->shift;
+ unsigned int max = mc->max;
+ unsigned int mask = (1 << fls(max)) - 1;
+ unsigned int invert = mc->invert;
+ unsigned int val;
+
+ if (reg != SND_SOC_NOPM) {
+ soc_widget_read(w, reg, &val);
+ val = (val >> shift) & mask;
+ if (invert)
+ val = max - val;
+ p->connect = !!val;
+ } else {
+ p->connect = 0;
+ }
+}
+
/* connect mixer widget to its interconnecting audio paths */
static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
@@ -644,7 +583,7 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
list_add(&path->list_sink, &dest->sources);
list_add(&path->list_source, &src->sinks);
path->name = dest->kcontrol_news[i].name;
- dapm_set_path_status(dest, path, i);
+ dapm_set_mixer_path_status(dest, path, i);
return 0;
}
}
@@ -723,8 +662,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
kcname_in_long_name = true;
break;
case snd_soc_dapm_mux:
- case snd_soc_dapm_virt_mux:
- case snd_soc_dapm_value_mux:
wname_in_long_name = true;
kcname_in_long_name = false;
break;
@@ -1218,7 +1155,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
ret = regulator_allow_bypass(w->regulator, false);
if (ret != 0)
dev_warn(w->dapm->dev,
- "ASoC: Failed to bypass %s: %d\n",
+ "ASoC: Failed to unbypass %s: %d\n",
w->name, ret);
}
@@ -1228,7 +1165,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
ret = regulator_allow_bypass(w->regulator, true);
if (ret != 0)
dev_warn(w->dapm->dev,
- "ASoC: Failed to unbypass %s: %d\n",
+ "ASoC: Failed to bypass %s: %d\n",
w->name, ret);
}
@@ -1823,6 +1760,8 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
ASYNC_DOMAIN_EXCLUSIVE(async_domain);
enum snd_soc_bias_level bias;
+ lockdep_assert_held(&card->dapm_mutex);
+
trace_snd_soc_dapm_start(card);
list_for_each_entry(d, &card->dapm_list, list) {
@@ -1897,10 +1836,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
trace_snd_soc_dapm_walk_done(card);
- /* Run all the bias changes in parallel */
- list_for_each_entry(d, &card->dapm_list, list)
- async_schedule_domain(dapm_pre_sequence_async, d,
- &async_domain);
+ /* Run card bias changes at first */
+ dapm_pre_sequence_async(&card->dapm, 0);
+ /* Run other bias changes in parallel */
+ list_for_each_entry(d, &card->dapm_list, list) {
+ if (d != &card->dapm)
+ async_schedule_domain(dapm_pre_sequence_async, d,
+ &async_domain);
+ }
async_synchronize_full_domain(&async_domain);
list_for_each_entry(w, &down_list, power_list) {
@@ -1920,10 +1863,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
dapm_seq_run(card, &up_list, event, true);
/* Run all the bias changes in parallel */
- list_for_each_entry(d, &card->dapm_list, list)
- async_schedule_domain(dapm_post_sequence_async, d,
- &async_domain);
+ list_for_each_entry(d, &card->dapm_list, list) {
+ if (d != &card->dapm)
+ async_schedule_domain(dapm_post_sequence_async, d,
+ &async_domain);
+ }
async_synchronize_full_domain(&async_domain);
+ /* Run card bias changes at last */
+ dapm_post_sequence_async(&card->dapm, 0);
/* do we need to notify any clients that DAPM event is complete */
list_for_each_entry(d, &card->dapm_list, list) {
@@ -2110,6 +2057,8 @@ static int soc_dapm_mux_update_power(struct snd_soc_card *card,
struct snd_soc_dapm_path *path;
int found = 0;
+ lockdep_assert_held(&card->dapm_mutex);
+
/* find dapm widget path assoc with kcontrol */
dapm_kcontrol_for_each_path(path, kcontrol) {
if (!path->name || !e->texts[mux])
@@ -2160,6 +2109,8 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
struct snd_soc_dapm_path *path;
int found = 0;
+ lockdep_assert_held(&card->dapm_mutex);
+
/* find dapm widget path assoc with kcontrol */
dapm_kcontrol_for_each_path(path, kcontrol) {
found = 1;
@@ -2325,6 +2276,8 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
{
struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
+ dapm_assert_locked(dapm);
+
if (!w) {
dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
return -EINVAL;
@@ -2341,18 +2294,18 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
}
/**
- * snd_soc_dapm_sync - scan and power dapm paths
+ * snd_soc_dapm_sync_unlocked - scan and power dapm paths
* @dapm: DAPM context
*
* Walks all dapm audio paths and powers widgets according to their
* stream or path usage.
*
+ * Requires external locking.
+ *
* Returns 0 for success.
*/
-int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
+int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
{
- int ret;
-
/*
* Suppress early reports (eg, jacks syncing their state) to avoid
* silly DAPM runs during card startup.
@@ -2360,8 +2313,25 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
if (!dapm->card || !dapm->card->instantiated)
return 0;
+ return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
+
+/**
+ * snd_soc_dapm_sync - scan and power dapm paths
+ * @dapm: DAPM context
+ *
+ * Walks all dapm audio paths and powers widgets according to their
+ * stream or path usage.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
+{
+ int ret;
+
mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
- ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
+ ret = snd_soc_dapm_sync_unlocked(dapm);
mutex_unlock(&dapm->card->dapm_mutex);
return ret;
}
@@ -2444,8 +2414,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
path->connect = 1;
return 0;
case snd_soc_dapm_mux:
- case snd_soc_dapm_virt_mux:
- case snd_soc_dapm_value_mux:
ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
&wsink->kcontrol_news[0]);
if (ret != 0)
@@ -2772,8 +2740,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
dapm_new_mixer(w);
break;
case snd_soc_dapm_mux:
- case snd_soc_dapm_virt_mux:
- case snd_soc_dapm_value_mux:
dapm_new_mux(w);
break;
case snd_soc_dapm_pga:
@@ -2935,213 +2901,75 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int val;
-
- val = snd_soc_read(codec, e->reg);
- ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;
- if (e->shift_l != e->shift_r)
- ucontrol->value.enumerated.item[1] =
- (val >> e->shift_r) & e->mask;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
-
-/**
- * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to set the value of a dapm enumerated double mixer control.
- *
- * Returns 0 for success.
- */
-int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
- struct snd_soc_card *card = codec->card;
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int val, mux, change;
- unsigned int mask;
- struct snd_soc_dapm_update update;
- int ret = 0;
-
- if (ucontrol->value.enumerated.item[0] > e->max - 1)
- return -EINVAL;
- mux = ucontrol->value.enumerated.item[0];
- val = mux << e->shift_l;
- mask = e->mask << e->shift_l;
- if (e->shift_l != e->shift_r) {
- if (ucontrol->value.enumerated.item[1] > e->max - 1)
- return -EINVAL;
- val |= ucontrol->value.enumerated.item[1] << e->shift_r;
- mask |= e->mask << e->shift_r;
- }
-
- mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
- change = snd_soc_test_bits(codec, e->reg, mask, val);
- if (change) {
- update.kcontrol = kcontrol;
- update.reg = e->reg;
- update.mask = mask;
- update.val = val;
- card->update = &update;
-
- ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
-
- card->update = NULL;
- }
-
- mutex_unlock(&card->dapm_mutex);
+ unsigned int reg_val, val;
- if (ret > 0)
- soc_dpcm_runtime_update(card);
-
- return change;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
-
-/**
- * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.enumerated.item[0] = dapm_kcontrol_get_value(kcontrol);
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
-
-/**
- * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
- struct snd_soc_card *card = codec->card;
- unsigned int value;
- struct soc_enum *e =
- (struct soc_enum *)kcontrol->private_value;
- int change;
- int ret = 0;
-
- if (ucontrol->value.enumerated.item[0] >= e->max)
- return -EINVAL;
-
- mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
- value = ucontrol->value.enumerated.item[0];
- change = dapm_kcontrol_set_value(kcontrol, value);
- if (change)
- ret = soc_dapm_mux_update_power(card, kcontrol, value, e);
-
- mutex_unlock(&card->dapm_mutex);
-
- if (ret > 0)
- soc_dpcm_runtime_update(card);
-
- return change;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
-
-/**
- * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get
- * callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to get the value of a dapm semi enumerated double mixer control.
- *
- * Semi enumerated mixer: the enumerated items are referred as values. Can be
- * used for handling bitfield coded enumeration for example.
- *
- * Returns 0 for success.
- */
-int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int reg_val, val, mux;
+ if (e->reg != SND_SOC_NOPM)
+ reg_val = snd_soc_read(codec, e->reg);
+ else
+ reg_val = dapm_kcontrol_get_value(kcontrol);
- reg_val = snd_soc_read(codec, e->reg);
val = (reg_val >> e->shift_l) & e->mask;
- for (mux = 0; mux < e->max; mux++) {
- if (val == e->values[mux])
- break;
- }
- ucontrol->value.enumerated.item[0] = mux;
+ ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
if (e->shift_l != e->shift_r) {
val = (reg_val >> e->shift_r) & e->mask;
- for (mux = 0; mux < e->max; mux++) {
- if (val == e->values[mux])
- break;
- }
- ucontrol->value.enumerated.item[1] = mux;
+ val = snd_soc_enum_val_to_item(e, val);
+ ucontrol->value.enumerated.item[1] = val;
}
return 0;
}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
/**
- * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set
- * callback
+ * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
* @kcontrol: mixer control
* @ucontrol: control element information
*
- * Callback to set the value of a dapm semi enumerated double mixer control.
- *
- * Semi enumerated mixer: the enumerated items are referred as values. Can be
- * used for handling bitfield coded enumeration for example.
+ * Callback to set the value of a dapm enumerated double mixer control.
*
* Returns 0 for success.
*/
-int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
+int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_card *card = codec->card;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int val, mux, change;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ unsigned int val, change;
unsigned int mask;
struct snd_soc_dapm_update update;
int ret = 0;
- if (ucontrol->value.enumerated.item[0] > e->max - 1)
+ if (item[0] >= e->items)
return -EINVAL;
- mux = ucontrol->value.enumerated.item[0];
- val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
+
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
mask = e->mask << e->shift_l;
if (e->shift_l != e->shift_r) {
- if (ucontrol->value.enumerated.item[1] > e->max - 1)
+ if (item[1] > e->items)
return -EINVAL;
- val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
+ val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l;
mask |= e->mask << e->shift_r;
}
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
- change = snd_soc_test_bits(codec, e->reg, mask, val);
+ if (e->reg != SND_SOC_NOPM)
+ change = snd_soc_test_bits(codec, e->reg, mask, val);
+ else
+ change = dapm_kcontrol_set_value(kcontrol, val);
+
if (change) {
- update.kcontrol = kcontrol;
- update.reg = e->reg;
- update.mask = mask;
- update.val = val;
- card->update = &update;
+ if (e->reg != SND_SOC_NOPM) {
+ update.kcontrol = kcontrol;
+ update.reg = e->reg;
+ update.mask = mask;
+ update.val = val;
+ card->update = &update;
+ }
- ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
+ ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
card->update = NULL;
}
@@ -3153,7 +2981,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
return change;
}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
+EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
/**
* snd_soc_dapm_info_pin_switch - Info for a pin switch
@@ -3210,15 +3038,11 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
const char *pin = (const char *)kcontrol->private_value;
- mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
if (ucontrol->value.integer.value[0])
snd_soc_dapm_enable_pin(&card->dapm, pin);
else
snd_soc_dapm_disable_pin(&card->dapm, pin);
- mutex_unlock(&card->dapm_mutex);
-
snd_soc_dapm_sync(&card->dapm);
return 0;
}
@@ -3248,7 +3072,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
ret = regulator_allow_bypass(w->regulator, true);
if (ret != 0)
dev_warn(w->dapm->dev,
- "ASoC: Failed to unbypass %s: %d\n",
+ "ASoC: Failed to bypass %s: %d\n",
w->name, ret);
}
break;
@@ -3287,8 +3111,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
w->power_check = dapm_generic_check_power;
break;
case snd_soc_dapm_mux:
- case snd_soc_dapm_virt_mux:
- case snd_soc_dapm_value_mux:
w->power_check = dapm_generic_check_power;
break;
case snd_soc_dapm_dai_out:
@@ -3767,23 +3589,52 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
}
/**
+ * snd_soc_dapm_enable_pin_unlocked - enable pin.
+ * @dapm: DAPM context
+ * @pin: pin name
+ *
+ * Enables input/output pin and its parents or children widgets iff there is
+ * a valid audio route and active audio stream.
+ *
+ * Requires external locking.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+ const char *pin)
+{
+ return snd_soc_dapm_set_pin(dapm, pin, 1);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
+
+/**
* snd_soc_dapm_enable_pin - enable pin.
* @dapm: DAPM context
* @pin: pin name
*
* Enables input/output pin and its parents or children widgets iff there is
* a valid audio route and active audio stream.
+ *
* NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
* do any widget power switching.
*/
int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
{
- return snd_soc_dapm_set_pin(dapm, pin, 1);
+ int ret;
+
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+ ret = snd_soc_dapm_set_pin(dapm, pin, 1);
+
+ mutex_unlock(&dapm->card->dapm_mutex);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
/**
- * snd_soc_dapm_force_enable_pin - force a pin to be enabled
+ * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
* @dapm: DAPM context
* @pin: pin name
*
@@ -3791,11 +3642,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
* intended for use with microphone bias supplies used in microphone
* jack detection.
*
+ * Requires external locking.
+ *
* NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
* do any widget power switching.
*/
-int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
- const char *pin)
+int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+ const char *pin)
{
struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
@@ -3811,25 +3664,103 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
+
+/**
+ * snd_soc_dapm_force_enable_pin - force a pin to be enabled
+ * @dapm: DAPM context
+ * @pin: pin name
+ *
+ * Enables input/output pin regardless of any other state. This is
+ * intended for use with microphone bias supplies used in microphone
+ * jack detection.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
+ const char *pin)
+{
+ int ret;
+
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+ ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
+
+ mutex_unlock(&dapm->card->dapm_mutex);
+
+ return ret;
+}
EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
/**
+ * snd_soc_dapm_disable_pin_unlocked - disable pin.
+ * @dapm: DAPM context
+ * @pin: pin name
+ *
+ * Disables input/output pin and its parents or children widgets.
+ *
+ * Requires external locking.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+ const char *pin)
+{
+ return snd_soc_dapm_set_pin(dapm, pin, 0);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
+
+/**
* snd_soc_dapm_disable_pin - disable pin.
* @dapm: DAPM context
* @pin: pin name
*
* Disables input/output pin and its parents or children widgets.
+ *
* NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
* do any widget power switching.
*/
int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
const char *pin)
{
- return snd_soc_dapm_set_pin(dapm, pin, 0);
+ int ret;
+
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+ ret = snd_soc_dapm_set_pin(dapm, pin, 0);
+
+ mutex_unlock(&dapm->card->dapm_mutex);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
/**
+ * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
+ * @dapm: DAPM context
+ * @pin: pin name
+ *
+ * Marks the specified pin as being not connected, disabling it along
+ * any parent or child widgets. At present this is identical to
+ * snd_soc_dapm_disable_pin() but in future it will be extended to do
+ * additional things such as disabling controls which only affect
+ * paths through the pin.
+ *
+ * Requires external locking.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
+ const char *pin)
+{
+ return snd_soc_dapm_set_pin(dapm, pin, 0);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
+
+/**
* snd_soc_dapm_nc_pin - permanently disable pin.
* @dapm: DAPM context
* @pin: pin name
@@ -3845,7 +3776,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
*/
int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
{
- return snd_soc_dapm_set_pin(dapm, pin, 0);
+ int ret;
+
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+ ret = snd_soc_dapm_set_pin(dapm, pin, 0);
+
+ mutex_unlock(&dapm->card->dapm_mutex);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
@@ -3985,7 +3924,7 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
-static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
+static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
{
struct snd_soc_card *card = dapm->card;
struct snd_soc_dapm_widget *w;
@@ -4025,14 +3964,21 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
*/
void snd_soc_dapm_shutdown(struct snd_soc_card *card)
{
- struct snd_soc_codec *codec;
+ struct snd_soc_dapm_context *dapm;
- list_for_each_entry(codec, &card->codec_dev_list, card_list) {
- soc_dapm_shutdown_codec(&codec->dapm);
- if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
- snd_soc_dapm_set_bias_level(&codec->dapm,
- SND_SOC_BIAS_OFF);
+ list_for_each_entry(dapm, &card->dapm_list, list) {
+ if (dapm != &card->dapm) {
+ soc_dapm_shutdown_dapm(dapm);
+ if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
+ snd_soc_dapm_set_bias_level(dapm,
+ SND_SOC_BIAS_OFF);
+ }
}
+
+ soc_dapm_shutdown_dapm(&card->dapm);
+ if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+ snd_soc_dapm_set_bias_level(&card->dapm,
+ SND_SOC_BIAS_OFF);
}
/* Module information */
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index aa886cca3ecf..260efc8466fc 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -23,21 +23,6 @@
static int hw_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
- int ret;
-
- if (!snd_soc_codec_volatile_register(codec, reg) &&
- reg < codec->driver->reg_cache_size &&
- !codec->cache_bypass) {
- ret = snd_soc_cache_write(codec, reg, value);
- if (ret < 0)
- return -1;
- }
-
- if (codec->cache_only) {
- codec->cache_sync = 1;
- return 0;
- }
-
return regmap_write(codec->control_data, reg, value);
}
@@ -46,32 +31,18 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
int ret;
unsigned int val;
- if (reg >= codec->driver->reg_cache_size ||
- snd_soc_codec_volatile_register(codec, reg) ||
- codec->cache_bypass) {
- if (codec->cache_only)
- return -1;
-
- ret = regmap_read(codec->control_data, reg, &val);
- if (ret == 0)
- return val;
- else
- return -1;
- }
-
- ret = snd_soc_cache_read(codec, reg, &val);
- if (ret < 0)
+ ret = regmap_read(codec->control_data, reg, &val);
+ if (ret == 0)
+ return val;
+ else
return -1;
- return val;
}
/**
* snd_soc_codec_set_cache_io: Set up standard I/O functions.
*
* @codec: CODEC to configure.
- * @addr_bits: Number of bits of register address data.
- * @data_bits: Number of bits of data per register.
- * @control: Control bus used.
+ * @map: Register map to write to
*
* Register formats are frequently shared between many I2C and SPI
* devices. In order to promote code reuse the ASoC core provides
@@ -85,60 +56,36 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
* volatile registers.
*/
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
- int addr_bits, int data_bits,
- enum snd_soc_control_type control)
+ struct regmap *regmap)
{
- struct regmap_config config;
int ret;
- memset(&config, 0, sizeof(config));
- codec->write = hw_write;
- codec->read = hw_read;
-
- config.reg_bits = addr_bits;
- config.val_bits = data_bits;
+ /* Device has made its own regmap arrangements */
+ if (!regmap)
+ codec->control_data = dev_get_regmap(codec->dev, NULL);
+ else
+ codec->control_data = regmap;
- switch (control) {
-#if IS_ENABLED(CONFIG_REGMAP_I2C)
- case SND_SOC_I2C:
- codec->control_data = regmap_init_i2c(to_i2c_client(codec->dev),
- &config);
- break;
-#endif
+ if (IS_ERR(codec->control_data))
+ return PTR_ERR(codec->control_data);
-#if IS_ENABLED(CONFIG_REGMAP_SPI)
- case SND_SOC_SPI:
- codec->control_data = regmap_init_spi(to_spi_device(codec->dev),
- &config);
- break;
-#endif
-
- case SND_SOC_REGMAP:
- /* Device has made its own regmap arrangements */
- codec->using_regmap = true;
- if (!codec->control_data)
- codec->control_data = dev_get_regmap(codec->dev, NULL);
+ codec->write = hw_write;
+ codec->read = hw_read;
- if (codec->control_data) {
- ret = regmap_get_val_bytes(codec->control_data);
- /* Errors are legitimate for non-integer byte
- * multiples */
- if (ret > 0)
- codec->val_bytes = ret;
- }
- break;
+ ret = regmap_get_val_bytes(codec->control_data);
+ /* Errors are legitimate for non-integer byte
+ * multiples */
+ if (ret > 0)
+ codec->val_bytes = ret;
- default:
- return -EINVAL;
- }
+ codec->using_regmap = true;
- return PTR_ERR_OR_ZERO(codec->control_data);
+ return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
#else
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
- int addr_bits, int data_bits,
- enum snd_soc_control_type control)
+ struct regmap *regmap)
{
return -ENOTSUPP;
}
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 23d43dac91da..b903f822d1b2 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -250,7 +250,7 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
report = 0;
if (gpio->jack_status_check)
- report = gpio->jack_status_check();
+ report = gpio->jack_status_check(gpio->data);
snd_soc_jack_report(jack, report, gpio->report);
}
@@ -342,7 +342,8 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
gpio_export(gpios[i].gpio, false);
/* Update initial jack status */
- snd_soc_jack_gpio_detect(&gpios[i]);
+ schedule_delayed_work(&gpios[i].work,
+ msecs_to_jiffies(gpios[i].debounce_time));
}
return 0;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 47e1ce771e65..2cedf09f6d96 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -35,6 +35,86 @@
#define DPCM_MAX_BE_USERS 8
/**
+ * snd_soc_runtime_activate() - Increment active count for PCM runtime components
+ * @rtd: ASoC PCM runtime that is activated
+ * @stream: Direction of the PCM stream
+ *
+ * Increments the active count for all the DAIs and components attached to a PCM
+ * runtime. Should typically be called when a stream is opened.
+ *
+ * Must be called with the rtd->pcm_mutex being held
+ */
+void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ lockdep_assert_held(&rtd->pcm_mutex);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ cpu_dai->playback_active++;
+ codec_dai->playback_active++;
+ } else {
+ cpu_dai->capture_active++;
+ codec_dai->capture_active++;
+ }
+
+ cpu_dai->active++;
+ codec_dai->active++;
+ cpu_dai->component->active++;
+ codec_dai->component->active++;
+}
+
+/**
+ * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components
+ * @rtd: ASoC PCM runtime that is deactivated
+ * @stream: Direction of the PCM stream
+ *
+ * Decrements the active count for all the DAIs and components attached to a PCM
+ * runtime. Should typically be called when a stream is closed.
+ *
+ * Must be called with the rtd->pcm_mutex being held
+ */
+void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ lockdep_assert_held(&rtd->pcm_mutex);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ cpu_dai->playback_active--;
+ codec_dai->playback_active--;
+ } else {
+ cpu_dai->capture_active--;
+ codec_dai->capture_active--;
+ }
+
+ cpu_dai->active--;
+ codec_dai->active--;
+ cpu_dai->component->active--;
+ codec_dai->component->active--;
+}
+
+/**
+ * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
+ * @rtd: The ASoC PCM runtime that should be checked.
+ *
+ * This function checks whether the power down delay should be ignored for a
+ * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
+ * been configured to ignore the delay, or if none of the components benefits
+ * from having the delay.
+ */
+bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
+{
+ if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
+ return true;
+
+ return rtd->cpu_dai->component->ignore_pmdown_time &&
+ rtd->codec_dai->component->ignore_pmdown_time;
+}
+
+/**
* snd_soc_set_runtime_hwparams - set the runtime hardware parameters
* @substream: the pcm substream
* @hw: the hardware parameters
@@ -378,16 +458,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
runtime->hw.rate_max);
dynamic:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- cpu_dai->playback_active++;
- codec_dai->playback_active++;
- } else {
- cpu_dai->capture_active++;
- codec_dai->capture_active++;
- }
- cpu_dai->active++;
- codec_dai->active++;
- rtd->codec->active++;
+
+ snd_soc_runtime_activate(rtd, substream->stream);
+
mutex_unlock(&rtd->pcm_mutex);
return 0;
@@ -459,21 +532,10 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_codec *codec = rtd->codec;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- cpu_dai->playback_active--;
- codec_dai->playback_active--;
- } else {
- cpu_dai->capture_active--;
- codec_dai->capture_active--;
- }
-
- cpu_dai->active--;
- codec_dai->active--;
- codec->active--;
+ snd_soc_runtime_deactivate(rtd, substream->stream);
/* clear the corresponding DAIs rate when inactive */
if (!cpu_dai->active)
@@ -496,8 +558,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
cpu_dai->runtime = NULL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
- rtd->dai_link->ignore_pmdown_time) {
+ if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
/* powered down playback stream now */
snd_soc_dapm_stream_event(rtd,
SNDRV_PCM_STREAM_PLAYBACK,
diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c
index fe99f461aff0..19cca043e6e4 100644
--- a/sound/soc/spear/spdif_out.c
+++ b/sound/soc/spear/spdif_out.c
@@ -213,10 +213,7 @@ static int spdif_digital_mute(struct snd_soc_dai *dai, int mute)
static int spdif_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct snd_soc_card *card = codec->card;
- struct snd_soc_pcm_runtime *rtd = card->rtd;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
ucontrol->value.integer.value[0] = host->saved_params.mute;
@@ -226,10 +223,7 @@ static int spdif_mute_get(struct snd_kcontrol *kcontrol,
static int spdif_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct snd_soc_card *card = codec->card;
- struct snd_soc_pcm_runtime *rtd = card->rtd;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
if (host->saved_params.mute == ucontrol->value.integer.value[0])
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 9f9c1856f822..31198cf7f88d 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -105,7 +105,7 @@ config SND_SOC_TEGRA_TRIMSLICE
tristate "SoC Audio support for TrimSlice board"
depends on SND_SOC_TEGRA && I2C
select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
- select SND_SOC_TLV320AIC23
+ select SND_SOC_TLV320AIC23_I2C
help
Say Y or M here if you want to add support for SoC audio on the
TrimSlice platform.
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
index cf5e1cfe818d..3b0fa12dbff7 100644
--- a/sound/soc/tegra/tegra20_ac97.c
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -37,7 +37,6 @@
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
-#include "tegra_asoc_utils.h"
#include "tegra20_ac97.h"
#define DRV_NAME "tegra20-ac97"
@@ -306,7 +305,7 @@ static const struct regmap_config tegra20_ac97_regmap_config = {
.readable_reg = tegra20_ac97_wr_rd_reg,
.volatile_reg = tegra20_ac97_volatile_reg,
.precious_reg = tegra20_ac97_precious_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_FLAT,
};
static int tegra20_ac97_platform_probe(struct platform_device *pdev)
@@ -376,18 +375,10 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
ac97->playback_dma_data.maxburst = 4;
- ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev);
- if (ret)
- goto err_clk_put;
-
- ret = tegra_asoc_utils_set_ac97_rate(&ac97->util_data);
- if (ret)
- goto err_asoc_utils_fini;
-
ret = clk_prepare_enable(ac97->clk_ac97);
if (ret) {
dev_err(&pdev->dev, "clk_enable failed: %d\n", ret);
- goto err_asoc_utils_fini;
+ goto err;
}
ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
@@ -419,8 +410,6 @@ err_unregister_component:
snd_soc_unregister_component(&pdev->dev);
err_clk_disable_unprepare:
clk_disable_unprepare(ac97->clk_ac97);
-err_asoc_utils_fini:
- tegra_asoc_utils_fini(&ac97->util_data);
err_clk_put:
err:
snd_soc_set_ac97_ops(NULL);
@@ -434,8 +423,6 @@ static int tegra20_ac97_platform_remove(struct platform_device *pdev)
tegra_pcm_platform_unregister(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
- tegra_asoc_utils_fini(&ac97->util_data);
-
clk_disable_unprepare(ac97->clk_ac97);
snd_soc_set_ac97_ops(NULL);
diff --git a/sound/soc/tegra/tegra20_ac97.h b/sound/soc/tegra/tegra20_ac97.h
index 4acb3aaba29b..0a39d823edcb 100644
--- a/sound/soc/tegra/tegra20_ac97.h
+++ b/sound/soc/tegra/tegra20_ac97.h
@@ -90,6 +90,5 @@ struct tegra20_ac97 {
struct regmap *regmap;
int reset_gpio;
int sync_gpio;
- struct tegra_asoc_utils_data util_data;
};
#endif /* __TEGRA20_AC97_H__ */
diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c
index e72392927bd2..a634f13b3ffc 100644
--- a/sound/soc/tegra/tegra20_das.c
+++ b/sound/soc/tegra/tegra20_das.c
@@ -128,7 +128,7 @@ static const struct regmap_config tegra20_das_regmap_config = {
.max_register = LAST_REG(DAC_INPUT_DATA_CLK_SEL),
.writeable_reg = tegra20_das_wr_rd_reg,
.readable_reg = tegra20_das_wr_rd_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_FLAT,
};
static int tegra20_das_probe(struct platform_device *pdev)
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 42c1f6bfaf2e..79a9932ffe6e 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -333,7 +333,7 @@ static const struct regmap_config tegra20_i2s_regmap_config = {
.readable_reg = tegra20_i2s_wr_rd_reg,
.volatile_reg = tegra20_i2s_volatile_reg,
.precious_reg = tegra20_i2s_precious_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_FLAT,
};
static int tegra20_i2s_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index 8c7c1028e579..a0ce92400faf 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -259,7 +259,7 @@ static const struct regmap_config tegra20_spdif_regmap_config = {
.readable_reg = tegra20_spdif_wr_rd_reg,
.volatile_reg = tegra20_spdif_volatile_reg,
.precious_reg = tegra20_spdif_precious_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_FLAT,
};
static int tegra20_spdif_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index d6f4c9940e0c..0db68f49f4d9 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -471,7 +471,7 @@ static const struct regmap_config tegra30_ahub_apbif_regmap_config = {
.readable_reg = tegra30_ahub_apbif_wr_rd_reg,
.volatile_reg = tegra30_ahub_apbif_volatile_reg,
.precious_reg = tegra30_ahub_apbif_precious_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_FLAT,
};
static bool tegra30_ahub_ahub_wr_rd_reg(struct device *dev, unsigned int reg)
@@ -490,7 +490,7 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
.max_register = LAST_REG(AUDIO_RX),
.writeable_reg = tegra30_ahub_ahub_wr_rd_reg,
.readable_reg = tegra30_ahub_ahub_wr_rd_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_FLAT,
};
static struct tegra30_ahub_soc_data soc_data_tegra30 = {
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 49ad9366add8..f146c41dd3ec 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -357,7 +357,7 @@ static const struct regmap_config tegra30_i2s_regmap_config = {
.writeable_reg = tegra30_i2s_wr_rd_reg,
.readable_reg = tegra30_i2s_wr_rd_reg,
.volatile_reg = tegra30_i2s_volatile_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_FLAT,
};
static const struct tegra30_i2s_soc_data tegra30_i2s_config = {
diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c
index 45b57892b6a5..25a7f8211ecf 100644
--- a/sound/soc/tegra/tegra_wm9712.c
+++ b/sound/soc/tegra/tegra_wm9712.c
@@ -29,10 +29,13 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include "tegra_asoc_utils.h"
+
#define DRV_NAME "tegra-snd-wm9712"
struct tegra_wm9712 {
struct platform_device *codec;
+ struct tegra_asoc_utils_data util_data;
};
static const struct snd_soc_dapm_widget tegra_wm9712_dapm_widgets[] = {
@@ -118,15 +121,25 @@ static int tegra_wm9712_driver_probe(struct platform_device *pdev)
tegra_wm9712_dai.platform_of_node = tegra_wm9712_dai.cpu_of_node;
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ if (ret)
+ goto codec_unregister;
+
+ ret = tegra_asoc_utils_set_ac97_rate(&machine->util_data);
+ if (ret)
+ goto asoc_utils_fini;
+
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
ret);
- goto codec_unregister;
+ goto asoc_utils_fini;
}
return 0;
+asoc_utils_fini:
+ tegra_asoc_utils_fini(&machine->util_data);
codec_unregister:
platform_device_del(machine->codec);
codec_put:
@@ -141,6 +154,8 @@ static int tegra_wm9712_driver_remove(struct platform_device *pdev)
snd_soc_unregister_card(card);
+ tegra_asoc_utils_fini(&machine->util_data);
+
platform_device_unregister(machine->codec);
return 0;
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
index e0305a148568..9edd68db9f48 100644
--- a/sound/soc/txx9/txx9aclc-ac97.c
+++ b/sound/soc/txx9/txx9aclc-ac97.c
@@ -183,14 +183,16 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
+
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
drvdata->base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(drvdata->base))
return PTR_ERR(drvdata->base);
- drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
- if (!drvdata)
- return -ENOMEM;
platform_set_drvdata(pdev, drvdata);
drvdata->physbase = r->start;
if (sizeof(drvdata->physbase) > sizeof(r->start) &&
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
index 174d21fb56e2..4a85e1433472 100644
--- a/sound/sparc/amd7930.c
+++ b/sound/sparc/amd7930.c
@@ -1019,8 +1019,8 @@ static int amd7930_sbus_probe(struct platform_device *op)
return -ENOENT;
}
- err = snd_card_create(index[dev_num], id[dev_num], THIS_MODULE, 0,
- &card);
+ err = snd_card_new(&op->dev, index[dev_num], id[dev_num],
+ THIS_MODULE, 0, &card);
if (err < 0)
return err;
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index dbb1b625eb2f..4e91bcaa3664 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -1565,7 +1565,8 @@ static int snd_cs4231_mixer(struct snd_card *card)
static int dev;
-static int cs4231_attach_begin(struct snd_card **rcard)
+static int cs4231_attach_begin(struct platform_device *op,
+ struct snd_card **rcard)
{
struct snd_card *card;
struct snd_cs4231 *chip;
@@ -1581,8 +1582,8 @@ static int cs4231_attach_begin(struct snd_card **rcard)
return -ENOENT;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_cs4231), &card);
+ err = snd_card_new(&op->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_cs4231), &card);
if (err < 0)
return err;
@@ -1869,7 +1870,7 @@ static int cs4231_sbus_probe(struct platform_device *op)
struct snd_card *card;
int err;
- err = cs4231_attach_begin(&card);
+ err = cs4231_attach_begin(op, &card);
if (err)
return err;
@@ -2060,7 +2061,7 @@ static int cs4231_ebus_probe(struct platform_device *op)
struct snd_card *card;
int err;
- err = cs4231_attach_begin(&card);
+ err = cs4231_attach_begin(op, &card);
if (err)
return err;
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index eee7afcae375..be1b1aa96b7e 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -2615,8 +2615,8 @@ static int dbri_probe(struct platform_device *op)
return -ENODEV;
}
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_dbri), &card);
+ err = snd_card_new(&op->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_dbri), &card);
if (err < 0)
return err;
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c
index 25c38afaee49..39522367897c 100644
--- a/sound/spi/at73c213.c
+++ b/sound/spi/at73c213.c
@@ -927,8 +927,6 @@ static int snd_at73c213_dev_init(struct snd_card *card,
if (retval)
goto out_snd_dev;
- snd_card_set_dev(card, &spi->dev);
-
goto out;
out_snd_dev:
@@ -966,8 +964,8 @@ static int snd_at73c213_probe(struct spi_device *spi)
/* Allocate "card" using some unused identifiers. */
snprintf(id, sizeof id, "at73c213_%d", board->ssc_id);
- retval = snd_card_create(-1, id, THIS_MODULE,
- sizeof(struct snd_at73c213), &card);
+ retval = snd_card_new(&spi->dev, -1, id, THIS_MODULE,
+ sizeof(struct snd_at73c213), &card);
if (retval < 0)
goto out;
diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c
index 66edc4a7917f..dcddfc354ba6 100644
--- a/sound/usb/6fire/chip.c
+++ b/sound/usb/6fire/chip.c
@@ -106,7 +106,7 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
}
if (regidx < 0) {
mutex_unlock(&register_mutex);
- snd_printk(KERN_ERR PREFIX "too many cards registered.\n");
+ dev_err(&intf->dev, "too many cards registered.\n");
return -ENODEV;
}
devices[regidx] = device;
@@ -121,20 +121,19 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
/* if we are here, card can be registered in alsa. */
if (usb_set_interface(device, 0, 0) != 0) {
- snd_printk(KERN_ERR PREFIX "can't set first interface.\n");
+ dev_err(&intf->dev, "can't set first interface.\n");
return -EIO;
}
- ret = snd_card_create(index[regidx], id[regidx], THIS_MODULE,
- sizeof(struct sfire_chip), &card);
+ ret = snd_card_new(&intf->dev, index[regidx], id[regidx],
+ THIS_MODULE, sizeof(struct sfire_chip), &card);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "cannot create alsa card.\n");
+ dev_err(&intf->dev, "cannot create alsa card.\n");
return ret;
}
strcpy(card->driver, "6FireUSB");
strcpy(card->shortname, "TerraTec DMX6FireUSB");
sprintf(card->longname, "%s at %d:%d", card->shortname,
device->bus->busnum, device->devnum);
- snd_card_set_dev(card, &intf->dev);
chip = card->private_data;
chips[regidx] = chip;
@@ -169,7 +168,7 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
ret = snd_card_register(card);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "cannot register card.");
+ dev_err(&intf->dev, "cannot register card.");
usb6fire_chip_destroy(chip);
return ret;
}
diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c
index 23452ee617e1..161215d78d95 100644
--- a/sound/usb/6fire/comm.c
+++ b/sound/usb/6fire/comm.c
@@ -51,7 +51,7 @@ static void usb6fire_comm_receiver_handler(struct urb *urb)
urb->status = 0;
urb->actual_length = 0;
if (usb_submit_urb(urb, GFP_ATOMIC) < 0)
- snd_printk(KERN_WARNING PREFIX
+ dev_warn(&urb->dev->dev,
"comm data receiver aborted.\n");
}
}
@@ -179,7 +179,7 @@ int usb6fire_comm_init(struct sfire_chip *chip)
if (ret < 0) {
kfree(rt->receiver_buffer);
kfree(rt);
- snd_printk(KERN_ERR PREFIX "cannot create comm data receiver.");
+ dev_err(&chip->dev->dev, "cannot create comm data receiver.");
return ret;
}
chip->comm = rt;
diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
index f6434c245720..184e3987ac24 100644
--- a/sound/usb/6fire/control.c
+++ b/sound/usb/6fire/control.c
@@ -194,7 +194,8 @@ static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol,
int changed = 0;
if (ch > 4) {
- snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
+ dev_err(&rt->chip->dev->dev,
+ "Invalid channel in volume control.");
return -EINVAL;
}
@@ -222,7 +223,8 @@ static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol,
unsigned int ch = kcontrol->private_value;
if (ch > 4) {
- snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
+ dev_err(&rt->chip->dev->dev,
+ "Invalid channel in volume control.");
return -EINVAL;
}
@@ -240,7 +242,8 @@ static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol,
u8 value = 0;
if (ch > 4) {
- snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
+ dev_err(&rt->chip->dev->dev,
+ "Invalid channel in volume control.");
return -EINVAL;
}
@@ -265,7 +268,8 @@ static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol,
u8 value = rt->output_mute >> ch;
if (ch > 4) {
- snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
+ dev_err(&rt->chip->dev->dev,
+ "Invalid channel in volume control.");
return -EINVAL;
}
@@ -594,14 +598,14 @@ int usb6fire_control_init(struct sfire_chip *chip)
ret = usb6fire_control_add_virtual(rt, chip->card,
"Master Playback Volume", vol_elements);
if (ret) {
- snd_printk(KERN_ERR PREFIX "cannot add control.\n");
+ dev_err(&chip->dev->dev, "cannot add control.\n");
kfree(rt);
return ret;
}
ret = usb6fire_control_add_virtual(rt, chip->card,
"Master Playback Switch", mute_elements);
if (ret) {
- snd_printk(KERN_ERR PREFIX "cannot add control.\n");
+ dev_err(&chip->dev->dev, "cannot add control.\n");
kfree(rt);
return ret;
}
@@ -611,7 +615,7 @@ int usb6fire_control_init(struct sfire_chip *chip)
ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt));
if (ret < 0) {
kfree(rt);
- snd_printk(KERN_ERR PREFIX "cannot add control.\n");
+ dev_err(&chip->dev->dev, "cannot add control.\n");
return ret;
}
i++;
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
index 780bf3f62d28..3b02e54b8f6d 100644
--- a/sound/usb/6fire/firmware.c
+++ b/sound/usb/6fire/firmware.c
@@ -219,16 +219,16 @@ static int usb6fire_fw_ezusb_upload(
ret = request_firmware(&fw, fwname, &device->dev);
if (ret < 0) {
kfree(rec);
- snd_printk(KERN_ERR PREFIX "error requesting ezusb "
- "firmware %s.\n", fwname);
+ dev_err(&intf->dev,
+ "error requesting ezusb firmware %s.\n", fwname);
return ret;
}
ret = usb6fire_fw_ihex_init(fw, rec);
if (ret < 0) {
kfree(rec);
release_firmware(fw);
- snd_printk(KERN_ERR PREFIX "error validating ezusb "
- "firmware %s.\n", fwname);
+ dev_err(&intf->dev,
+ "error validating ezusb firmware %s.\n", fwname);
return ret;
}
/* upload firmware image */
@@ -237,8 +237,9 @@ static int usb6fire_fw_ezusb_upload(
if (ret < 0) {
kfree(rec);
release_firmware(fw);
- snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
- "firmware %s: begin message.\n", fwname);
+ dev_err(&intf->dev,
+ "unable to upload ezusb firmware %s: begin message.\n",
+ fwname);
return ret;
}
@@ -248,8 +249,9 @@ static int usb6fire_fw_ezusb_upload(
if (ret < 0) {
kfree(rec);
release_firmware(fw);
- snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
- "firmware %s: data urb.\n", fwname);
+ dev_err(&intf->dev,
+ "unable to upload ezusb firmware %s: data urb.\n",
+ fwname);
return ret;
}
}
@@ -260,8 +262,9 @@ static int usb6fire_fw_ezusb_upload(
ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr,
postdata, postlen);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
- "firmware %s: post urb.\n", fwname);
+ dev_err(&intf->dev,
+ "unable to upload ezusb firmware %s: post urb.\n",
+ fwname);
return ret;
}
}
@@ -269,8 +272,9 @@ static int usb6fire_fw_ezusb_upload(
data = 0x00; /* resume ezusb cpu */
ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
- "firmware %s: end message.\n", fwname);
+ dev_err(&intf->dev,
+ "unable to upload ezusb firmware %s: end message.\n",
+ fwname);
return ret;
}
return 0;
@@ -292,7 +296,7 @@ static int usb6fire_fw_fpga_upload(
ret = request_firmware(&fw, fwname, &device->dev);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "unable to get fpga firmware %s.\n",
+ dev_err(&intf->dev, "unable to get fpga firmware %s.\n",
fwname);
kfree(buffer);
return -EIO;
@@ -305,8 +309,8 @@ static int usb6fire_fw_fpga_upload(
if (ret < 0) {
kfree(buffer);
release_firmware(fw);
- snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: "
- "begin urb.\n");
+ dev_err(&intf->dev,
+ "unable to upload fpga firmware: begin urb.\n");
return ret;
}
@@ -318,8 +322,8 @@ static int usb6fire_fw_fpga_upload(
if (ret < 0) {
release_firmware(fw);
kfree(buffer);
- snd_printk(KERN_ERR PREFIX "unable to upload fpga "
- "firmware: fw urb.\n");
+ dev_err(&intf->dev,
+ "unable to upload fpga firmware: fw urb.\n");
return ret;
}
}
@@ -328,8 +332,8 @@ static int usb6fire_fw_fpga_upload(
ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: "
- "end urb.\n");
+ dev_err(&intf->dev,
+ "unable to upload fpga firmware: end urb.\n");
return ret;
}
return 0;
@@ -338,7 +342,7 @@ static int usb6fire_fw_fpga_upload(
/* check, if the firmware version the devices has currently loaded
* is known by this driver. 'version' needs to have 4 bytes version
* info data. */
-static int usb6fire_fw_check(u8 *version)
+static int usb6fire_fw_check(struct usb_interface *intf, const u8 *version)
{
int i;
@@ -346,7 +350,7 @@ static int usb6fire_fw_check(u8 *version)
if (!memcmp(version, known_fw_versions + i, 2))
return 0;
- snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %4ph. "
+ dev_err(&intf->dev, "invalid fimware version in device: %4ph. "
"please reconnect to power. if this failure "
"still happens, check your firmware installation.",
version);
@@ -364,16 +368,16 @@ int usb6fire_fw_init(struct usb_interface *intf)
ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "unable to receive device "
- "firmware state.\n");
+ dev_err(&intf->dev,
+ "unable to receive device firmware state.\n");
return ret;
}
if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
- snd_printk(KERN_ERR PREFIX "unknown device firmware state "
- "received from device: ");
+ dev_err(&intf->dev,
+ "unknown device firmware state received from device:");
for (i = 0; i < 8; i++)
- snd_printk("%02x ", buffer[i]);
- snd_printk("\n");
+ printk(KERN_CONT "%02x ", buffer[i]);
+ printk(KERN_CONT "\n");
return -EIO;
}
/* do we need fpga loader ezusb firmware? */
@@ -386,7 +390,7 @@ int usb6fire_fw_init(struct usb_interface *intf)
}
/* do we need fpga firmware and application ezusb firmware? */
else if (buffer[3] == 0x02) {
- ret = usb6fire_fw_check(buffer + 4);
+ ret = usb6fire_fw_check(intf, buffer + 4);
if (ret < 0)
return ret;
ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
@@ -402,14 +406,14 @@ int usb6fire_fw_init(struct usb_interface *intf)
}
/* all fw loaded? */
else if (buffer[3] == 0x03)
- return usb6fire_fw_check(buffer + 4);
+ return usb6fire_fw_check(intf, buffer + 4);
/* unknown data? */
else {
- snd_printk(KERN_ERR PREFIX "unknown device firmware state "
- "received from device: ");
+ dev_err(&intf->dev,
+ "unknown device firmware state received from device: ");
for (i = 0; i < 8; i++)
- snd_printk("%02x ", buffer[i]);
- snd_printk("\n");
+ printk(KERN_CONT "%02x ", buffer[i]);
+ printk(KERN_CONT "\n");
return -EIO;
}
return 0;
diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c
index f3dd7266c391..3d410969553e 100644
--- a/sound/usb/6fire/midi.c
+++ b/sound/usb/6fire/midi.c
@@ -41,8 +41,9 @@ static void usb6fire_midi_out_handler(struct urb *urb)
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0)
- snd_printk(KERN_ERR PREFIX "midi out urb "
- "submit failed: %d\n", ret);
+ dev_err(&urb->dev->dev,
+ "midi out urb submit failed: %d\n",
+ ret);
} else /* no more data to transmit */
rt->out = NULL;
}
@@ -94,8 +95,9 @@ static void usb6fire_midi_out_trigger(
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0)
- snd_printk(KERN_ERR PREFIX "midi out urb "
- "submit failed: %d\n", ret);
+ dev_err(&urb->dev->dev,
+ "midi out urb submit failed: %d\n",
+ ret);
else
rt->out = alsa_sub;
}
@@ -181,7 +183,7 @@ int usb6fire_midi_init(struct sfire_chip *chip)
if (ret < 0) {
kfree(rt->out_buffer);
kfree(rt);
- snd_printk(KERN_ERR PREFIX "unable to create midi.\n");
+ dev_err(&chip->dev->dev, "unable to create midi.\n");
return ret;
}
rt->instance->private_data = rt;
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
index b5eb97fdc842..ba40489b2de4 100644
--- a/sound/usb/6fire/pcm.c
+++ b/sound/usb/6fire/pcm.c
@@ -79,32 +79,35 @@ static int usb6fire_pcm_set_rate(struct pcm_runtime *rt)
ctrl_rt->usb_streaming = false;
ret = ctrl_rt->update_streaming(ctrl_rt);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "error stopping streaming while "
- "setting samplerate %d.\n", rates[rt->rate]);
+ dev_err(&rt->chip->dev->dev,
+ "error stopping streaming while setting samplerate %d.\n",
+ rates[rt->rate]);
return ret;
}
ret = ctrl_rt->set_rate(ctrl_rt, rt->rate);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n",
- rates[rt->rate]);
+ dev_err(&rt->chip->dev->dev,
+ "error setting samplerate %d.\n",
+ rates[rt->rate]);
return ret;
}
ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS,
false, false);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "error initializing channels "
- "while setting samplerate %d.\n",
- rates[rt->rate]);
+ dev_err(&rt->chip->dev->dev,
+ "error initializing channels while setting samplerate %d.\n",
+ rates[rt->rate]);
return ret;
}
ctrl_rt->usb_streaming = true;
ret = ctrl_rt->update_streaming(ctrl_rt);
if (ret < 0) {
- snd_printk(KERN_ERR PREFIX "error starting streaming while "
- "setting samplerate %d.\n", rates[rt->rate]);
+ dev_err(&rt->chip->dev->dev,
+ "error starting streaming while setting samplerate %d.\n",
+ rates[rt->rate]);
return ret;
}
@@ -124,7 +127,7 @@ static struct pcm_substream *usb6fire_pcm_get_substream(
return &rt->playback;
else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE)
return &rt->capture;
- snd_printk(KERN_ERR PREFIX "error getting pcm substream slot.\n");
+ dev_err(&rt->chip->dev->dev, "error getting pcm substream slot.\n");
return NULL;
}
@@ -257,7 +260,7 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub,
else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE)
dest = (u32 *) (urb->buffer);
else {
- snd_printk(KERN_ERR PREFIX "Unknown sample format.");
+ dev_err(&rt->chip->dev->dev, "Unknown sample format.");
return;
}
@@ -307,8 +310,8 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb)
}
if (rt->stream_state == STREAM_DISABLED) {
- snd_printk(KERN_ERR PREFIX "internal error: "
- "stream disabled in in-urb handler.\n");
+ dev_err(&rt->chip->dev->dev,
+ "internal error: stream disabled in in-urb handler.\n");
return;
}
@@ -410,7 +413,7 @@ static int usb6fire_pcm_open(struct snd_pcm_substream *alsa_sub)
if (!sub) {
mutex_unlock(&rt->stream_mutex);
- snd_printk(KERN_ERR PREFIX "invalid stream type.\n");
+ dev_err(&rt->chip->dev->dev, "invalid stream type.\n");
return -EINVAL;
}
@@ -481,8 +484,9 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
break;
if (rt->rate == ARRAY_SIZE(rates)) {
mutex_unlock(&rt->stream_mutex);
- snd_printk("invalid rate %d in prepare.\n",
- alsa_rt->rate);
+ dev_err(&rt->chip->dev->dev,
+ "invalid rate %d in prepare.\n",
+ alsa_rt->rate);
return -EINVAL;
}
@@ -494,8 +498,8 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
ret = usb6fire_pcm_stream_start(rt);
if (ret) {
mutex_unlock(&rt->stream_mutex);
- snd_printk(KERN_ERR PREFIX
- "could not start pcm stream.\n");
+ dev_err(&rt->chip->dev->dev,
+ "could not start pcm stream.\n");
return ret;
}
}
@@ -650,7 +654,7 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
if (ret < 0) {
usb6fire_pcm_buffers_destroy(rt);
kfree(rt);
- snd_printk(KERN_ERR PREFIX "cannot create pcm instance.\n");
+ dev_err(&chip->dev->dev, "cannot create pcm instance.\n");
return ret;
}
@@ -662,8 +666,8 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
if (ret) {
usb6fire_pcm_buffers_destroy(rt);
kfree(rt);
- snd_printk(KERN_ERR PREFIX
- "error preallocating pcm buffers.\n");
+ dev_err(&chip->dev->dev,
+ "error preallocating pcm buffers.\n");
return ret;
}
rt->instance = pcm;
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index bc55f708a696..b871ba407e4e 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -418,8 +418,9 @@ static int create_card(struct usb_device *usb_dev,
if (devnum >= SNDRV_CARDS)
return -ENODEV;
- err = snd_card_create(index[devnum], id[devnum], THIS_MODULE,
- sizeof(struct snd_usb_caiaqdev), &card);
+ err = snd_card_new(&intf->dev,
+ index[devnum], id[devnum], THIS_MODULE,
+ sizeof(struct snd_usb_caiaqdev), &card);
if (err < 0)
return err;
@@ -429,7 +430,6 @@ static int create_card(struct usb_device *usb_dev,
cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct));
spin_lock_init(&cdev->spinlock);
- snd_card_set_dev(card, &intf->dev);
*cardp = card;
return 0;
diff --git a/sound/usb/card.c b/sound/usb/card.c
index d979050e6a6a..893d5a1afc3c 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -139,8 +139,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
struct usb_interface *iface = usb_ifnum_to_if(dev, interface);
if (!iface) {
- snd_printk(KERN_ERR "%d:%u:%d : does not exist\n",
- dev->devnum, ctrlif, interface);
+ dev_err(&dev->dev, "%u:%d : does not exist\n",
+ ctrlif, interface);
return -EINVAL;
}
@@ -165,8 +165,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
}
if (usb_interface_claimed(iface)) {
- snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n",
- dev->devnum, ctrlif, interface);
+ dev_dbg(&dev->dev, "%d:%d: skipping, already claimed\n",
+ ctrlif, interface);
return -EINVAL;
}
@@ -176,8 +176,9 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
int err = snd_usbmidi_create(chip->card, iface,
&chip->midi_list, NULL);
if (err < 0) {
- snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n",
- dev->devnum, ctrlif, interface);
+ dev_err(&dev->dev,
+ "%u:%d: cannot create sequencer device\n",
+ ctrlif, interface);
return -EINVAL;
}
usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L);
@@ -188,14 +189,15 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING) {
- snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n",
- dev->devnum, ctrlif, interface, altsd->bInterfaceClass);
+ dev_dbg(&dev->dev,
+ "%u:%d: skipping non-supported interface %d\n",
+ ctrlif, interface, altsd->bInterfaceClass);
/* skip non-supported classes */
return -EINVAL;
}
if (snd_usb_get_speed(dev) == USB_SPEED_LOW) {
- snd_printk(KERN_ERR "low speed audio streaming not supported\n");
+ dev_err(&dev->dev, "low speed audio streaming not supported\n");
return -EINVAL;
}
@@ -228,26 +230,27 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
protocol = altsd->bInterfaceProtocol;
if (!control_header) {
- snd_printk(KERN_ERR "cannot find UAC_HEADER\n");
+ dev_err(&dev->dev, "cannot find UAC_HEADER\n");
return -EINVAL;
}
switch (protocol) {
default:
- snd_printdd(KERN_WARNING "unknown interface protocol %#02x, assuming v1\n",
- protocol);
+ dev_warn(&dev->dev,
+ "unknown interface protocol %#02x, assuming v1\n",
+ protocol);
/* fall through */
case UAC_VERSION_1: {
struct uac1_ac_header_descriptor *h1 = control_header;
if (!h1->bInCollection) {
- snd_printk(KERN_INFO "skipping empty audio interface (v1)\n");
+ dev_info(&dev->dev, "skipping empty audio interface (v1)\n");
return -EINVAL;
}
if (h1->bLength < sizeof(*h1) + h1->bInCollection) {
- snd_printk(KERN_ERR "invalid UAC_HEADER (v1)\n");
+ dev_err(&dev->dev, "invalid UAC_HEADER (v1)\n");
return -EINVAL;
}
@@ -277,7 +280,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
}
if (!assoc) {
- snd_printk(KERN_ERR "Audio class v2 interfaces need an interface association\n");
+ dev_err(&dev->dev, "Audio class v2 interfaces need an interface association\n");
return -EINVAL;
}
@@ -328,7 +331,8 @@ static void remove_trailing_spaces(char *str)
/*
* create a chip instance and set its names.
*/
-static int snd_usb_audio_create(struct usb_device *dev, int idx,
+static int snd_usb_audio_create(struct usb_interface *intf,
+ struct usb_device *dev, int idx,
const struct snd_usb_audio_quirk *quirk,
struct snd_usb_audio **rchip)
{
@@ -350,13 +354,14 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
case USB_SPEED_SUPER:
break;
default:
- snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev));
+ dev_err(&dev->dev, "unknown device speed %d\n", snd_usb_get_speed(dev));
return -ENXIO;
}
- err = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card);
+ err = snd_card_new(&intf->dev, index[idx], id[idx], THIS_MODULE,
+ 0, &card);
if (err < 0) {
- snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
+ dev_err(&dev->dev, "cannot create card instance %d\n", idx);
return err;
}
@@ -497,7 +502,7 @@ snd_usb_audio_probe(struct usb_device *dev,
for (i = 0; i < SNDRV_CARDS; i++) {
if (usb_chip[i] && usb_chip[i]->dev == dev) {
if (usb_chip[i]->shutdown) {
- snd_printk(KERN_ERR "USB device is in the shutdown state, cannot create a card instance\n");
+ dev_err(&dev->dev, "USB device is in the shutdown state, cannot create a card instance\n");
goto __error;
}
chip = usb_chip[i];
@@ -513,15 +518,15 @@ snd_usb_audio_probe(struct usb_device *dev,
if (enable[i] && ! usb_chip[i] &&
(vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) &&
(pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) {
- if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) {
+ if (snd_usb_audio_create(intf, dev, i, quirk,
+ &chip) < 0) {
goto __error;
}
- snd_card_set_dev(chip->card, &intf->dev);
chip->pm_intf = intf;
break;
}
if (!chip) {
- printk(KERN_ERR "no available usb audio device\n");
+ dev_err(&dev->dev, "no available usb audio device\n");
goto __error;
}
}
@@ -691,12 +696,12 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
}
list_for_each_entry(mixer, &chip->mixer_list, list)
- snd_usb_mixer_inactivate(mixer);
+ snd_usb_mixer_suspend(mixer);
return 0;
}
-static int usb_audio_resume(struct usb_interface *intf)
+static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
{
struct snd_usb_audio *chip = usb_get_intfdata(intf);
struct usb_mixer_interface *mixer;
@@ -711,7 +716,7 @@ static int usb_audio_resume(struct usb_interface *intf)
* we just notify and restart the mixers
*/
list_for_each_entry(mixer, &chip->mixer_list, list) {
- err = snd_usb_mixer_activate(mixer);
+ err = snd_usb_mixer_resume(mixer, reset_resume);
if (err < 0)
goto err_out;
}
@@ -723,9 +728,20 @@ static int usb_audio_resume(struct usb_interface *intf)
err_out:
return err;
}
+
+static int usb_audio_resume(struct usb_interface *intf)
+{
+ return __usb_audio_resume(intf, false);
+}
+
+static int usb_audio_reset_resume(struct usb_interface *intf)
+{
+ return __usb_audio_resume(intf, true);
+}
#else
#define usb_audio_suspend NULL
#define usb_audio_resume NULL
+#define usb_audio_reset_resume NULL
#endif /* CONFIG_PM */
static struct usb_device_id usb_audio_ids [] = {
@@ -747,6 +763,7 @@ static struct usb_driver usb_audio_driver = {
.disconnect = usb_audio_disconnect,
.suspend = usb_audio_suspend,
.resume = usb_audio_resume,
+ .reset_resume = usb_audio_reset_resume,
.id_table = usb_audio_ids,
.supports_autosuspend = 1,
};
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 86f80c60b21f..03fed6611d9e 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -115,9 +115,9 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i
return ret;
if (ret != sizeof(pin)) {
- snd_printk(KERN_ERR
- "usb-audio:%d: setting selector (id %d) unexpected length %d\n",
- chip->dev->devnum, selector_id, ret);
+ usb_audio_err(chip,
+ "setting selector (id %d) unexpected length %d\n",
+ selector_id, ret);
return -EINVAL;
}
@@ -126,9 +126,9 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i
return ret;
if (ret != pin) {
- snd_printk(KERN_ERR
- "usb-audio:%d: setting selector (id %d) to %x failed (current: %d)\n",
- chip->dev->devnum, selector_id, pin, ret);
+ usb_audio_err(chip,
+ "setting selector (id %d) to %x failed (current: %d)\n",
+ selector_id, pin, ret);
return -EINVAL;
}
@@ -158,7 +158,8 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
&data, sizeof(data));
if (err < 0) {
- snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n",
+ dev_warn(&dev->dev,
+ "%s(): cannot get clock validity for id %d\n",
__func__, source_id);
return 0;
}
@@ -177,9 +178,9 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
entity_id &= 0xff;
if (test_and_set_bit(entity_id, visited)) {
- snd_printk(KERN_WARNING
- "%s(): recursive clock topology detected, id %d.\n",
- __func__, entity_id);
+ usb_audio_warn(chip,
+ "%s(): recursive clock topology detected, id %d.\n",
+ __func__, entity_id);
return -EINVAL;
}
@@ -188,8 +189,9 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
if (source) {
entity_id = source->bClockID;
if (validate && !uac_clock_source_is_valid(chip, entity_id)) {
- snd_printk(KERN_ERR "usb-audio:%d: clock source %d is not valid, cannot use\n",
- chip->dev->devnum, entity_id);
+ usb_audio_err(chip,
+ "clock source %d is not valid, cannot use\n",
+ entity_id);
return -ENXIO;
}
return entity_id;
@@ -208,7 +210,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
/* Selector values are one-based */
if (ret > selector->bNrInPins || ret < 1) {
- snd_printk(KERN_ERR
+ usb_audio_err(chip,
"%s(): selector reported illegal value, id %d, ret %d\n",
__func__, selector->bClockID, ret);
@@ -237,9 +239,9 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
if (err < 0)
continue;
- snd_printk(KERN_INFO
- "usb-audio:%d: found and selected valid clock source %d\n",
- chip->dev->devnum, ret);
+ usb_audio_info(chip,
+ "found and selected valid clock source %d\n",
+ ret);
return ret;
}
@@ -296,8 +298,8 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
data, sizeof(data))) < 0) {
- snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
- dev->devnum, iface, fmt->altsetting, rate, ep);
+ dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n",
+ iface, fmt->altsetting, rate, ep);
return err;
}
@@ -305,14 +307,14 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
data, sizeof(data))) < 0) {
- snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
- dev->devnum, iface, fmt->altsetting, ep);
+ dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n",
+ iface, fmt->altsetting, ep);
return 0; /* some devices don't support reading */
}
crate = data[0] | (data[1] << 8) | (data[2] << 16);
if (crate != rate) {
- snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
+ dev_warn(&dev->dev, "current rate %d is different from the runtime rate %d\n", crate, rate);
// runtime->rate = crate;
}
@@ -332,8 +334,8 @@ static int get_sample_rate_v2(struct snd_usb_audio *chip, int iface,
snd_usb_ctrl_intf(chip) | (clock << 8),
&data, sizeof(data));
if (err < 0) {
- snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2): err %d\n",
- dev->devnum, iface, altsetting, err);
+ dev_warn(&dev->dev, "%d:%d: cannot get freq (v2): err %d\n",
+ iface, altsetting, err);
return 0;
}
@@ -369,8 +371,9 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
snd_usb_ctrl_intf(chip) | (clock << 8),
&data, sizeof(data));
if (err < 0) {
- snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2): err %d\n",
- dev->devnum, iface, fmt->altsetting, rate, err);
+ usb_audio_err(chip,
+ "%d:%d: cannot set freq %d (v2): err %d\n",
+ iface, fmt->altsetting, rate, err);
return err;
}
@@ -381,14 +384,14 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
if (cur_rate != rate) {
if (!writeable) {
- snd_printk(KERN_WARNING
- "%d:%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n",
- dev->devnum, iface, fmt->altsetting, rate, cur_rate);
+ usb_audio_warn(chip,
+ "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n",
+ iface, fmt->altsetting, rate, cur_rate);
return -ENXIO;
}
- snd_printd(KERN_WARNING
- "current rate %d is different from the runtime rate %d\n",
- cur_rate, rate);
+ usb_audio_dbg(chip,
+ "current rate %d is different from the runtime rate %d\n",
+ cur_rate, rate);
}
/* Some devices doesn't respond to sample rate changes while the
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 83aabea259d7..e70a87e0d9fe 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -333,8 +333,9 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)
err = usb_submit_urb(ctx->urb, GFP_ATOMIC);
if (err < 0)
- snd_printk(KERN_ERR "Unable to submit urb #%d: %d (urb %p)\n",
- ctx->index, err, ctx->urb);
+ usb_audio_err(ep->chip,
+ "Unable to submit urb #%d: %d (urb %p)\n",
+ ctx->index, err, ctx->urb);
else
set_bit(ctx->index, &ep->active_mask);
}
@@ -387,7 +388,7 @@ static void snd_complete_urb(struct urb *urb)
if (err == 0)
return;
- snd_printk(KERN_ERR "cannot submit urb (err = %d)\n", err);
+ usb_audio_err(ep->chip, "cannot submit urb (err = %d)\n", err);
//snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
exit_clear:
@@ -426,13 +427,14 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
if (ep->ep_num == ep_num &&
ep->iface == alts->desc.bInterfaceNumber &&
ep->altsetting == alts->desc.bAlternateSetting) {
- snd_printdd(KERN_DEBUG "Re-using EP %x in iface %d,%d @%p\n",
+ usb_audio_dbg(ep->chip,
+ "Re-using EP %x in iface %d,%d @%p\n",
ep_num, ep->iface, ep->altsetting, ep);
goto __exit_unlock;
}
}
- snd_printdd(KERN_DEBUG "Creating new %s %s endpoint #%x\n",
+ usb_audio_dbg(chip, "Creating new %s %s endpoint #%x\n",
is_playback ? "playback" : "capture",
type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync",
ep_num);
@@ -496,8 +498,9 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep)
} while (time_before(jiffies, end_time));
if (alive)
- snd_printk(KERN_ERR "timeout: still %d active urbs on EP #%x\n",
- alive, ep->ep_num);
+ usb_audio_err(ep->chip,
+ "timeout: still %d active urbs on EP #%x\n",
+ alive, ep->ep_num);
clear_bit(EP_FLAG_STOPPING, &ep->flags);
return 0;
@@ -794,8 +797,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
int err;
if (ep->use_count != 0) {
- snd_printk(KERN_WARNING "Unable to change format on ep #%x: already in use\n",
- ep->ep_num);
+ usb_audio_warn(ep->chip,
+ "Unable to change format on ep #%x: already in use\n",
+ ep->ep_num);
return -EBUSY;
}
@@ -830,8 +834,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
err = -EINVAL;
}
- snd_printdd(KERN_DEBUG "Setting params for ep #%x (type %d, %d urbs), ret=%d\n",
- ep->ep_num, ep->type, ep->nurbs, err);
+ usb_audio_dbg(ep->chip,
+ "Setting params for ep #%x (type %d, %d urbs), ret=%d\n",
+ ep->ep_num, ep->type, ep->nurbs, err);
return err;
}
@@ -906,8 +911,9 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep)
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- snd_printk(KERN_ERR "cannot submit urb %d, error %d: %s\n",
- i, err, usb_error_string(err));
+ usb_audio_err(ep->chip,
+ "cannot submit urb %d, error %d: %s\n",
+ i, err, usb_error_string(err));
goto __error;
}
set_bit(i, &ep->active_mask);
diff --git a/sound/usb/format.c b/sound/usb/format.c
index d244fd3703d8..8bcc87cf5667 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -74,8 +74,8 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
if ((pcm_formats == 0) &&
(format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED))) {
/* some devices don't define this correctly... */
- snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n",
- chip->dev->devnum, fp->iface, fp->altsetting);
+ usb_audio_info(chip, "%u:%d : format type 0 is detected, processed as PCM\n",
+ fp->iface, fp->altsetting);
format = 1 << UAC_FORMAT_TYPE_I_PCM;
}
if (format & (1 << UAC_FORMAT_TYPE_I_PCM)) {
@@ -83,9 +83,9 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
sample_width == 24 && sample_bytes == 2)
sample_bytes = 3;
else if (sample_width > sample_bytes * 8) {
- snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n",
- chip->dev->devnum, fp->iface, fp->altsetting,
- sample_width, sample_bytes);
+ usb_audio_info(chip, "%u:%d : sample bitwidth %d in over sample bytes %d\n",
+ fp->iface, fp->altsetting,
+ sample_width, sample_bytes);
}
/* check the format byte size */
switch (sample_bytes) {
@@ -108,9 +108,10 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
pcm_formats |= SNDRV_PCM_FMTBIT_S32_LE;
break;
default:
- snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n",
- chip->dev->devnum, fp->iface, fp->altsetting,
- sample_width, sample_bytes);
+ usb_audio_info(chip,
+ "%u:%d : unsupported sample bitwidth %d in %d bytes\n",
+ fp->iface, fp->altsetting,
+ sample_width, sample_bytes);
break;
}
}
@@ -132,8 +133,9 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
pcm_formats |= SNDRV_PCM_FMTBIT_MU_LAW;
}
if (format & ~0x3f) {
- snd_printk(KERN_INFO "%d:%u:%d : unsupported format bits %#x\n",
- chip->dev->devnum, fp->iface, fp->altsetting, format);
+ usb_audio_info(chip,
+ "%u:%d : unsupported format bits %#x\n",
+ fp->iface, fp->altsetting, format);
}
pcm_formats |= snd_usb_interface_dsd_format_quirks(chip, fp, sample_bytes);
@@ -158,8 +160,9 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
int nr_rates = fmt[offset];
if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) {
- snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
- chip->dev->devnum, fp->iface, fp->altsetting);
+ usb_audio_err(chip,
+ "%u:%d : invalid UAC_FORMAT_TYPE desc\n",
+ fp->iface, fp->altsetting);
return -EINVAL;
}
@@ -171,7 +174,7 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL);
if (fp->rate_table == NULL) {
- snd_printk(KERN_ERR "cannot malloc\n");
+ usb_audio_err(chip, "cannot malloc\n");
return -ENOMEM;
}
@@ -222,7 +225,8 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
* get to know how many sample rates we have to expect.
* Then fp->rate_table can be allocated and filled.
*/
-static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets,
+static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
+ struct audioformat *fp, int nr_triplets,
const unsigned char *data)
{
int i, nr_rates = 0;
@@ -261,7 +265,7 @@ static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets,
nr_rates++;
if (nr_rates >= MAX_NR_RATES) {
- snd_printk(KERN_ERR "invalid uac2 rates\n");
+ usb_audio_err(chip, "invalid uac2 rates\n");
break;
}
@@ -287,7 +291,8 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
int clock = snd_usb_clock_find_source(chip, fp->clock, false);
if (clock < 0) {
- snd_printk(KERN_ERR "%s(): unable to find clock source (clock %d)\n",
+ dev_err(&dev->dev,
+ "%s(): unable to find clock source (clock %d)\n",
__func__, clock);
goto err;
}
@@ -300,7 +305,8 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
tmp, sizeof(tmp));
if (ret < 0) {
- snd_printk(KERN_ERR "%s(): unable to retrieve number of sample rates (clock %d)\n",
+ dev_err(&dev->dev,
+ "%s(): unable to retrieve number of sample rates (clock %d)\n",
__func__, clock);
goto err;
}
@@ -321,7 +327,8 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
data, data_size);
if (ret < 0) {
- snd_printk(KERN_ERR "%s(): unable to retrieve sample rate range (clock %d)\n",
+ dev_err(&dev->dev,
+ "%s(): unable to retrieve sample rate range (clock %d)\n",
__func__, clock);
ret = -EINVAL;
goto err_free;
@@ -332,7 +339,7 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
* will have to deal with. */
kfree(fp->rate_table);
fp->rate_table = NULL;
- fp->nr_rates = parse_uac2_sample_rate_range(fp, nr_triplets, data);
+ fp->nr_rates = parse_uac2_sample_rate_range(chip, fp, nr_triplets, data);
if (fp->nr_rates == 0) {
/* SNDRV_PCM_RATE_CONTINUOUS */
@@ -348,7 +355,7 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
/* Call the triplet parser again, but this time, fp->rate_table is
* allocated, so the rates will be stored */
- parse_uac2_sample_rate_range(fp, nr_triplets, data);
+ parse_uac2_sample_rate_range(chip, fp, nr_triplets, data);
err_free:
kfree(data);
@@ -408,8 +415,9 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
}
if (fp->channels < 1) {
- snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n",
- chip->dev->devnum, fp->iface, fp->altsetting, fp->channels);
+ usb_audio_err(chip,
+ "%u:%d : invalid channels %d\n",
+ fp->iface, fp->altsetting, fp->channels);
return -EINVAL;
}
@@ -435,8 +443,9 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
fp->formats = SNDRV_PCM_FMTBIT_MPEG;
break;
default:
- snd_printd(KERN_INFO "%d:%u:%d : unknown format tag %#x is detected. processed as MPEG.\n",
- chip->dev->devnum, fp->iface, fp->altsetting, format);
+ usb_audio_info(chip,
+ "%u:%d : unknown format tag %#x is detected. processed as MPEG.\n",
+ fp->iface, fp->altsetting, format);
fp->formats = SNDRV_PCM_FMTBIT_MPEG;
break;
}
@@ -449,7 +458,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
struct uac_format_type_ii_discrete_descriptor *fmt = _fmt;
brate = le16_to_cpu(fmt->wMaxBitRate);
framesize = le16_to_cpu(fmt->wSamplesPerFrame);
- snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
+ usb_audio_info(chip, "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
fp->frame_size = framesize;
ret = parse_audio_format_rates_v1(chip, fp, _fmt, 8); /* fmt[8..] sample rates */
break;
@@ -458,7 +467,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
struct uac_format_type_ii_ext_descriptor *fmt = _fmt;
brate = le16_to_cpu(fmt->wMaxBitRate);
framesize = le16_to_cpu(fmt->wSamplesPerFrame);
- snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
+ usb_audio_info(chip, "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
fp->frame_size = framesize;
ret = parse_audio_format_rates_v2(chip, fp);
break;
@@ -484,9 +493,10 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
err = parse_audio_format_ii(chip, fp, format, fmt);
break;
default:
- snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n",
- chip->dev->devnum, fp->iface, fp->altsetting,
- fmt->bFormatType);
+ usb_audio_info(chip,
+ "%u:%d : format type %d is not supported yet\n",
+ fp->iface, fp->altsetting,
+ fmt->bFormatType);
return -ENOTSUPP;
}
fp->fmt_type = fmt->bFormatType;
diff --git a/sound/usb/hiface/chip.c b/sound/usb/hiface/chip.c
index b0dcb3924ce5..2670d646bda9 100644
--- a/sound/usb/hiface/chip.c
+++ b/sound/usb/hiface/chip.c
@@ -64,7 +64,8 @@ struct hiface_vendor_quirk {
u8 extra_freq;
};
-static int hiface_chip_create(struct usb_device *device, int idx,
+static int hiface_chip_create(struct usb_interface *intf,
+ struct usb_device *device, int idx,
const struct hiface_vendor_quirk *quirk,
struct hiface_chip **rchip)
{
@@ -76,7 +77,8 @@ static int hiface_chip_create(struct usb_device *device, int idx,
*rchip = NULL;
/* if we are here, card can be registered in alsa. */
- ret = snd_card_create(index[idx], id[idx], THIS_MODULE, sizeof(*chip), &card);
+ ret = snd_card_new(&intf->dev, index[idx], id[idx], THIS_MODULE,
+ sizeof(*chip), &card);
if (ret < 0) {
dev_err(&device->dev, "cannot create alsa card.\n");
return ret;
@@ -132,12 +134,10 @@ static int hiface_chip_probe(struct usb_interface *intf,
goto err;
}
- ret = hiface_chip_create(device, i, quirk, &chip);
+ ret = hiface_chip_create(intf, device, i, quirk, &chip);
if (ret < 0)
goto err;
- snd_card_set_dev(chip->card, &intf->dev);
-
ret = hiface_pcm_init(chip, quirk ? quirk->extra_freq : 0);
if (ret < 0)
goto err_chip_destroy;
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index b901f468b67a..9da74d2e8eee 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -191,16 +191,16 @@ static int snd_usbmidi_submit_urb(struct urb* urb, gfp_t flags)
{
int err = usb_submit_urb(urb, flags);
if (err < 0 && err != -ENODEV)
- snd_printk(KERN_ERR "usb_submit_urb: %d\n", err);
+ dev_err(&urb->dev->dev, "usb_submit_urb: %d\n", err);
return err;
}
/*
* Error handling for URB completion functions.
*/
-static int snd_usbmidi_urb_error(int status)
+static int snd_usbmidi_urb_error(const struct urb *urb)
{
- switch (status) {
+ switch (urb->status) {
/* manually unlinked, or device gone */
case -ENOENT:
case -ECONNRESET:
@@ -213,7 +213,7 @@ static int snd_usbmidi_urb_error(int status)
case -EILSEQ:
return -EIO;
default:
- snd_printk(KERN_ERR "urb status %d\n", status);
+ dev_err(&urb->dev->dev, "urb status %d\n", urb->status);
return 0; /* continue */
}
}
@@ -227,7 +227,7 @@ static void snd_usbmidi_input_data(struct snd_usb_midi_in_endpoint* ep, int port
struct usbmidi_in_port* port = &ep->ports[portidx];
if (!port->substream) {
- snd_printd("unexpected port %d!\n", portidx);
+ dev_dbg(&ep->umidi->dev->dev, "unexpected port %d!\n", portidx);
return;
}
if (!test_bit(port->substream->number, &ep->umidi->input_triggered))
@@ -259,7 +259,7 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb)
ep->umidi->usb_protocol_ops->input(ep, urb->transfer_buffer,
urb->actual_length);
} else {
- int err = snd_usbmidi_urb_error(urb->status);
+ int err = snd_usbmidi_urb_error(urb);
if (err < 0) {
if (err != -ENODEV) {
ep->error_resubmit = 1;
@@ -289,7 +289,7 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb)
}
spin_unlock(&ep->buffer_lock);
if (urb->status < 0) {
- int err = snd_usbmidi_urb_error(urb->status);
+ int err = snd_usbmidi_urb_error(urb);
if (err < 0) {
if (err != -ENODEV)
mod_timer(&ep->umidi->error_timer,
@@ -1668,7 +1668,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi,
struct snd_rawmidi_substream *substream = snd_usbmidi_find_substream(umidi, stream, number);
if (!substream) {
- snd_printd(KERN_ERR "substream %d:%d not found\n", stream, number);
+ dev_err(&umidi->dev->dev, "substream %d:%d not found\n", stream, number);
return;
}
@@ -1717,7 +1717,7 @@ static int snd_usbmidi_create_endpoints(struct snd_usb_midi* umidi,
}
}
}
- snd_printdd(KERN_INFO "created %d output and %d input ports\n",
+ dev_dbg(&umidi->dev->dev, "created %d output and %d input ports\n",
out_ports, in_ports);
return 0;
}
@@ -1747,10 +1747,11 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
ms_header->bLength >= 7 &&
ms_header->bDescriptorType == USB_DT_CS_INTERFACE &&
ms_header->bDescriptorSubtype == UAC_HEADER)
- snd_printdd(KERN_INFO "MIDIStreaming version %02x.%02x\n",
+ dev_dbg(&umidi->dev->dev, "MIDIStreaming version %02x.%02x\n",
ms_header->bcdMSC[1], ms_header->bcdMSC[0]);
else
- snd_printk(KERN_WARNING "MIDIStreaming interface descriptor not found\n");
+ dev_warn(&umidi->dev->dev,
+ "MIDIStreaming interface descriptor not found\n");
epidx = 0;
for (i = 0; i < intfd->bNumEndpoints; ++i) {
@@ -1767,7 +1768,8 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
if (usb_endpoint_dir_out(ep)) {
if (endpoints[epidx].out_ep) {
if (++epidx >= MIDI_MAX_ENDPOINTS) {
- snd_printk(KERN_WARNING "too many endpoints\n");
+ dev_warn(&umidi->dev->dev,
+ "too many endpoints\n");
break;
}
}
@@ -1782,12 +1784,13 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
*/
endpoints[epidx].out_interval = 1;
endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
- snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",
+ dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n",
ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
} else {
if (endpoints[epidx].in_ep) {
if (++epidx >= MIDI_MAX_ENDPOINTS) {
- snd_printk(KERN_WARNING "too many endpoints\n");
+ dev_warn(&umidi->dev->dev,
+ "too many endpoints\n");
break;
}
}
@@ -1797,7 +1800,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW)
endpoints[epidx].in_interval = 1;
endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
- snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",
+ dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n",
ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
}
}
@@ -1865,7 +1868,7 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi)
(get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
return;
- snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n",
+ dev_dbg(&umidi->dev->dev, "switching to altsetting %d with int ep\n",
intfd->bAlternateSetting);
usb_set_interface(umidi->dev, intfd->bInterfaceNumber,
intfd->bAlternateSetting);
@@ -2047,25 +2050,25 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi,
* input bulk endpoints (at indices 1 and 3) which aren't used.
*/
if (intfd->bNumEndpoints < (endpoint->out_cables > 0x0001 ? 5 : 3)) {
- snd_printdd(KERN_ERR "not enough endpoints\n");
+ dev_dbg(&umidi->dev->dev, "not enough endpoints\n");
return -ENOENT;
}
epd = get_endpoint(hostif, 0);
if (!usb_endpoint_dir_in(epd) || !usb_endpoint_xfer_int(epd)) {
- snd_printdd(KERN_ERR "endpoint[0] isn't interrupt\n");
+ dev_dbg(&umidi->dev->dev, "endpoint[0] isn't interrupt\n");
return -ENXIO;
}
epd = get_endpoint(hostif, 2);
if (!usb_endpoint_dir_out(epd) || !usb_endpoint_xfer_bulk(epd)) {
- snd_printdd(KERN_ERR "endpoint[2] isn't bulk output\n");
+ dev_dbg(&umidi->dev->dev, "endpoint[2] isn't bulk output\n");
return -ENXIO;
}
if (endpoint->out_cables > 0x0001) {
epd = get_endpoint(hostif, 4);
if (!usb_endpoint_dir_out(epd) ||
!usb_endpoint_xfer_bulk(epd)) {
- snd_printdd(KERN_ERR "endpoint[4] isn't bulk output\n");
+ dev_dbg(&umidi->dev->dev, "endpoint[4] isn't bulk output\n");
return -ENXIO;
}
}
@@ -2289,7 +2292,7 @@ int snd_usbmidi_create(struct snd_card *card,
err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
break;
default:
- snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
+ dev_err(&umidi->dev->dev, "invalid quirk type %d\n", quirk->type);
err = -ENXIO;
break;
}
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index 509315937f25..a1bab149df4d 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -1243,8 +1243,9 @@ static int ua101_probe(struct usb_interface *interface,
mutex_unlock(&devices_mutex);
return -ENOENT;
}
- err = snd_card_create(index[card_index], id[card_index], THIS_MODULE,
- sizeof(*ua), &card);
+ err = snd_card_new(&interface->dev,
+ index[card_index], id[card_index], THIS_MODULE,
+ sizeof(*ua), &card);
if (err < 0) {
mutex_unlock(&devices_mutex);
return err;
@@ -1283,8 +1284,6 @@ static int ua101_probe(struct usb_interface *interface,
}
}
- snd_card_set_dev(card, &interface->dev);
-
err = detect_usb_format(ua);
if (err < 0)
goto probe_error;
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 44b0ba4feab3..d40a2850e270 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -305,8 +305,9 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v
goto out;
}
}
- snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
- request, validx, idx, cval->val_type);
+ usb_audio_dbg(chip,
+ "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
+ request, validx, idx, cval->val_type);
err = -EINVAL;
out:
@@ -351,8 +352,9 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
if (ret < 0) {
error:
- snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
- request, validx, idx, cval->val_type);
+ usb_audio_err(chip,
+ "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
+ request, validx, idx, cval->val_type);
return ret;
}
@@ -413,7 +415,8 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
err = get_cur_mix_raw(cval, channel, value);
if (err < 0) {
if (!cval->mixer->ignore_ctl_error)
- snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n",
+ usb_audio_dbg(cval->mixer->chip,
+ "cannot get current value for control %d ch %d: err = %d\n",
cval->control, channel, err);
return err;
}
@@ -444,7 +447,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
/* FIXME */
if (request != UAC_SET_CUR) {
- snd_printdd(KERN_WARNING "RANGE setting not yet supported\n");
+ usb_audio_dbg(chip, "RANGE setting not yet supported\n");
return -EINVAL;
}
@@ -470,7 +473,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
goto out;
}
}
- snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
+ usb_audio_dbg(chip, "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
request, validx, idx, cval->val_type, buf[0], buf[1]);
err = -EINVAL;
@@ -494,7 +497,8 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
cval->ch_readonly & (1 << (channel - 1));
if (read_only) {
- snd_printdd(KERN_INFO "%s(): channel %d of control %d is read_only\n",
+ usb_audio_dbg(cval->mixer->chip,
+ "%s(): channel %d of control %d is read_only\n",
__func__, channel, cval->control);
return 0;
}
@@ -560,7 +564,7 @@ int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
while (snd_ctl_find_id(mixer->chip->card, &kctl->id))
kctl->id.index++;
if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) {
- snd_printd(KERN_ERR "cannot add control (err = %d)\n", err);
+ usb_audio_dbg(mixer->chip, "cannot add control (err = %d)\n", err);
return err;
}
cval->elem_id = &kctl->id;
@@ -807,7 +811,8 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
static void volume_control_quirks(struct usb_mixer_elem_info *cval,
struct snd_kcontrol *kctl)
{
- switch (cval->mixer->chip->usb_id) {
+ struct snd_usb_audio *chip = cval->mixer->chip;
+ switch (chip->usb_id) {
case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
if (strcmp(kctl->id.name, "Effect Duration") == 0) {
@@ -839,8 +844,8 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
if (strcmp(kctl->id.name, "Effect Duration") == 0) {
- snd_printk(KERN_INFO
- "usb-audio: set quirk for FTU Effect Duration\n");
+ usb_audio_info(chip,
+ "set quirk for FTU Effect Duration\n");
cval->min = 0x0000;
cval->max = 0x7f00;
cval->res = 0x0100;
@@ -848,8 +853,8 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
}
if (strcmp(kctl->id.name, "Effect Volume") == 0 ||
strcmp(kctl->id.name, "Effect Feedback Volume") == 0) {
- snd_printk(KERN_INFO
- "usb-audio: set quirks for FTU Effect Feedback/Volume\n");
+ usb_audio_info(chip,
+ "set quirks for FTU Effect Feedback/Volume\n");
cval->min = 0x00;
cval->max = 0x7f;
break;
@@ -867,7 +872,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
*/
if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
cval->min == -15616) {
- snd_printk(KERN_INFO
+ usb_audio_info(chip,
"set volume quirk for UDA1321/N101 chip\n");
cval->max = -256;
}
@@ -875,7 +880,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
case USB_ID(0x046d, 0x09a4):
if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
- snd_printk(KERN_INFO
+ usb_audio_info(chip,
"set volume quirk for QuickCam E3500\n");
cval->min = 6080;
cval->max = 8768;
@@ -883,6 +888,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
}
break;
+ case USB_ID(0x046d, 0x0807): /* Logitech Webcam C500 */
case USB_ID(0x046d, 0x0808):
case USB_ID(0x046d, 0x0809):
case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */
@@ -895,7 +901,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
* Proboly there is some logitech magic behind this number --fishor
*/
if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
- snd_printk(KERN_INFO
+ usb_audio_info(chip,
"set resolution quirk: cval->res = 384\n");
cval->res = 384;
}
@@ -931,7 +937,8 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
}
if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
- snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n",
+ usb_audio_err(cval->mixer->chip,
+ "%d:%d: cannot get min/max values for control %d (id %d)\n",
cval->id, snd_usb_ctrl_intf(cval->mixer->chip), cval->control, cval->id);
return -EINVAL;
}
@@ -1195,7 +1202,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
if (! cval) {
- snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+ usb_audio_err(state->chip, "cannot malloc kcontrol\n");
return;
}
cval->mixer = state->mixer;
@@ -1224,7 +1231,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
if (! kctl) {
- snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+ usb_audio_err(state->chip, "cannot malloc kcontrol\n");
kfree(cval);
return;
}
@@ -1298,16 +1305,16 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
* devices. It will definitively catch all buggy Logitech devices.
*/
if (range > 384) {
- snd_printk(KERN_WARNING "usb_audio: Warning! Unlikely big "
+ usb_audio_warn(state->chip, "Warning! Unlikely big "
"volume range (=%u), cval->res is probably wrong.",
range);
- snd_printk(KERN_WARNING "usb_audio: [%d] FU [%s] ch = %d, "
+ usb_audio_warn(state->chip, "[%d] FU [%s] ch = %d, "
"val = %d/%d/%d", cval->id,
kctl->id.name, cval->channels,
cval->min, cval->max, cval->res);
}
- snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
+ usb_audio_dbg(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res);
snd_usb_mixer_add_control(state->mixer, kctl);
}
@@ -1331,16 +1338,17 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
if (state->mixer->protocol == UAC_VERSION_1) {
csize = hdr->bControlSize;
if (!csize) {
- snd_printdd(KERN_ERR "usbaudio: unit %u: "
- "invalid bControlSize == 0\n", unitid);
+ usb_audio_dbg(state->chip,
+ "unit %u: invalid bControlSize == 0\n",
+ unitid);
return -EINVAL;
}
channels = (hdr->bLength - 7) / csize - 1;
bmaControls = hdr->bmaControls;
if (hdr->bLength < 7 + csize) {
- snd_printk(KERN_ERR "usbaudio: unit %u: "
- "invalid UAC_FEATURE_UNIT descriptor\n",
- unitid);
+ usb_audio_err(state->chip,
+ "unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
+ unitid);
return -EINVAL;
}
} else {
@@ -1349,9 +1357,9 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
channels = (hdr->bLength - 6) / 4 - 1;
bmaControls = ftr->bmaControls;
if (hdr->bLength < 6 + csize) {
- snd_printk(KERN_ERR "usbaudio: unit %u: "
- "invalid UAC_FEATURE_UNIT descriptor\n",
- unitid);
+ usb_audio_err(state->chip,
+ "unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
+ unitid);
return -EINVAL;
}
}
@@ -1369,14 +1377,14 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
/* master configuration quirks */
switch (state->chip->usb_id) {
case USB_ID(0x08bb, 0x2702):
- snd_printk(KERN_INFO
- "usbmixer: master volume quirk for PCM2702 chip\n");
+ usb_audio_info(state->chip,
+ "usbmixer: master volume quirk for PCM2702 chip\n");
/* disable non-functional volume control */
master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME);
break;
case USB_ID(0x1130, 0xf211):
- snd_printk(KERN_INFO
- "usbmixer: volume control quirk for Tenx TP6911 Audio Headset\n");
+ usb_audio_info(state->chip,
+ "usbmixer: volume control quirk for Tenx TP6911 Audio Headset\n");
/* disable non-functional volume control */
channels = 0;
break;
@@ -1478,7 +1486,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
if (! kctl) {
- snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+ usb_audio_err(state->chip, "cannot malloc kcontrol\n");
kfree(cval);
return;
}
@@ -1491,7 +1499,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1);
append_ctl_name(kctl, " Volume");
- snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
+ usb_audio_dbg(state->chip, "[%d] MU [%s] ch = %d, val = %d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
snd_usb_mixer_add_control(state->mixer, kctl);
}
@@ -1508,12 +1516,12 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, void *r
int pin, ich, err;
if (desc->bLength < 11 || ! (input_pins = desc->bNrInPins) || ! (num_outs = uac_mixer_unit_bNrChannels(desc))) {
- snd_printk(KERN_ERR "invalid MIXER UNIT descriptor %d\n", unitid);
+ usb_audio_err(state->chip, "invalid MIXER UNIT descriptor %d\n", unitid);
return -EINVAL;
}
/* no bmControls field (e.g. Maya44) -> ignore */
if (desc->bLength <= 10 + input_pins) {
- snd_printdd(KERN_INFO "MU %d has no bmControls field\n", unitid);
+ usb_audio_dbg(state->chip, "MU %d has no bmControls field\n", unitid);
return 0;
}
@@ -1712,7 +1720,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
if (desc->bLength < 13 || desc->bLength < 13 + num_ins ||
desc->bLength < num_ins + uac_processing_unit_bControlSize(desc, state->mixer->protocol)) {
- snd_printk(KERN_ERR "invalid %s descriptor (id %d)\n", name, unitid);
+ usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid);
return -EINVAL;
}
@@ -1738,7 +1746,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
continue;
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
if (! cval) {
- snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+ usb_audio_err(state->chip, "cannot malloc kcontrol\n");
return -ENOMEM;
}
cval->mixer = state->mixer;
@@ -1770,7 +1778,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
if (! kctl) {
- snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+ usb_audio_err(state->chip, "cannot malloc kcontrol\n");
kfree(cval);
return -ENOMEM;
}
@@ -1792,7 +1800,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
append_ctl_name(kctl, " ");
append_ctl_name(kctl, valinfo->suffix);
- snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n",
+ usb_audio_dbg(state->chip,
+ "[%d] PU [%s] ch = %d, val = %d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
return err;
@@ -1917,7 +1926,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
char **namelist;
if (!desc->bNrInPins || desc->bLength < 5 + desc->bNrInPins) {
- snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid);
+ usb_audio_err(state->chip,
+ "invalid SELECTOR UNIT descriptor %d\n", unitid);
return -EINVAL;
}
@@ -1935,7 +1945,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
if (! cval) {
- snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+ usb_audio_err(state->chip, "cannot malloc kcontrol\n");
return -ENOMEM;
}
cval->mixer = state->mixer;
@@ -1954,7 +1964,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL);
if (! namelist) {
- snd_printk(KERN_ERR "cannot malloc\n");
+ usb_audio_err(state->chip, "cannot malloc\n");
kfree(cval);
return -ENOMEM;
}
@@ -1964,7 +1974,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
len = 0;
namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL);
if (! namelist[i]) {
- snd_printk(KERN_ERR "cannot malloc\n");
+ usb_audio_err(state->chip, "cannot malloc\n");
while (i--)
kfree(namelist[i]);
kfree(namelist);
@@ -1981,7 +1991,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);
if (! kctl) {
- snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+ usb_audio_err(state->chip, "cannot malloc kcontrol\n");
kfree(namelist);
kfree(cval);
return -ENOMEM;
@@ -2009,7 +2019,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
append_ctl_name(kctl, " Playback Source");
}
- snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",
+ usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n",
cval->id, kctl->id.name, desc->bNrInPins);
if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
return err;
@@ -2031,7 +2041,7 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
p1 = find_audio_control_unit(state, unitid);
if (!p1) {
- snd_printk(KERN_ERR "usbaudio: unit %d not found!\n", unitid);
+ usb_audio_err(state->chip, "unit %d not found!\n", unitid);
return -EINVAL;
}
@@ -2061,7 +2071,8 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
case UAC2_EXTENSION_UNIT_V2:
return parse_audio_extension_unit(state, unitid, p1);
default:
- snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
+ usb_audio_err(state->chip,
+ "unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
return -EINVAL;
}
}
@@ -2209,8 +2220,9 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
__u8 channel = value & 0xff;
if (channel >= MAX_CHANNELS) {
- snd_printk(KERN_DEBUG "%s(): bogus channel number %d\n",
- __func__, channel);
+ usb_audio_dbg(mixer->chip,
+ "%s(): bogus channel number %d\n",
+ __func__, channel);
return;
}
@@ -2239,8 +2251,9 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
break;
default:
- snd_printk(KERN_DEBUG "unknown attribute %d in interrupt\n",
- attribute);
+ usb_audio_dbg(mixer->chip,
+ "unknown attribute %d in interrupt\n",
+ attribute);
break;
} /* switch */
}
@@ -2261,7 +2274,7 @@ static void snd_usb_mixer_interrupt(struct urb *urb)
for (status = urb->transfer_buffer;
len >= sizeof(*status);
len -= sizeof(*status), status++) {
- snd_printd(KERN_DEBUG "status interrupt: %02x %02x\n",
+ dev_dbg(&urb->dev->dev, "status interrupt: %02x %02x\n",
status->bStatusType,
status->bOriginator);
@@ -2299,26 +2312,6 @@ requeue:
}
}
-/* stop any bus activity of a mixer */
-void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer)
-{
- usb_kill_urb(mixer->urb);
- usb_kill_urb(mixer->rc_urb);
-}
-
-int snd_usb_mixer_activate(struct usb_mixer_interface *mixer)
-{
- int err;
-
- if (mixer->urb) {
- err = usb_submit_urb(mixer->urb, GFP_NOIO);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
/* create the handler for the optional status interrupt endpoint */
static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
{
@@ -2393,7 +2386,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
snd_usb_mixer_apply_create_quirk(mixer);
- err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops);
+ err = snd_device_new(chip->card, SNDRV_DEV_CODEC, mixer, &dev_ops);
if (err < 0)
goto _error;
@@ -2417,3 +2410,82 @@ void snd_usb_mixer_disconnect(struct list_head *p)
usb_kill_urb(mixer->urb);
usb_kill_urb(mixer->rc_urb);
}
+
+#ifdef CONFIG_PM
+/* stop any bus activity of a mixer */
+static void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer)
+{
+ usb_kill_urb(mixer->urb);
+ usb_kill_urb(mixer->rc_urb);
+}
+
+static int snd_usb_mixer_activate(struct usb_mixer_interface *mixer)
+{
+ int err;
+
+ if (mixer->urb) {
+ err = usb_submit_urb(mixer->urb, GFP_NOIO);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer)
+{
+ snd_usb_mixer_inactivate(mixer);
+ return 0;
+}
+
+static int restore_mixer_value(struct usb_mixer_elem_info *cval)
+{
+ int c, err, idx;
+
+ if (cval->cmask) {
+ idx = 0;
+ for (c = 0; c < MAX_CHANNELS; c++) {
+ if (!(cval->cmask & (1 << c)))
+ continue;
+ if (cval->cached & (1 << c)) {
+ err = set_cur_mix_value(cval, c + 1, idx,
+ cval->cache_val[idx]);
+ if (err < 0)
+ return err;
+ }
+ idx++;
+ }
+ } else {
+ /* master */
+ if (cval->cached) {
+ err = set_cur_mix_value(cval, 0, 0, *cval->cache_val);
+ if (err < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume)
+{
+ struct usb_mixer_elem_info *cval;
+ int id, err;
+
+ /* FIXME: any mixer quirks? */
+
+ if (reset_resume) {
+ /* restore cached mixer values */
+ for (id = 0; id < MAX_ID_ELEMS; id++) {
+ for (cval = mixer->id_elems[id]; cval;
+ cval = cval->next_id_elem) {
+ err = restore_mixer_value(cval);
+ if (err < 0)
+ return err;
+ }
+ }
+ }
+
+ return snd_usb_mixer_activate(mixer);
+}
+#endif
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index aab80df201bd..73b1f649447b 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -63,8 +63,6 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid);
int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
int request, int validx, int value_set);
-void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer);
-int snd_usb_mixer_activate(struct usb_mixer_interface *mixer);
int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
struct snd_kcontrol *kctl);
@@ -72,4 +70,9 @@ int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
unsigned int size, unsigned int __user *_tlv);
+#ifdef CONFIG_PM
+int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer);
+int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume);
+#endif
+
#endif /* __USBMIXER_H */
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index 32af6b741ef5..d1d72ff50347 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -328,6 +328,11 @@ static struct usbmix_name_map gamecom780_map[] = {
{}
};
+static const struct usbmix_name_map kef_x300a_map[] = {
+ { 10, NULL }, /* firmware locks up (?) when we try to access this FU */
+ { 0 }
+};
+
/*
* Control map entries
*/
@@ -419,6 +424,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
.id = USB_ID(0x200c, 0x1018),
.map = ebox44_map,
},
+ {
+ .id = USB_ID(0x27ac, 0x1000),
+ .map = kef_x300a_map,
+ },
{ 0 } /* terminator */
};
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index f4b12c216f1c..f119a41ed9a9 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -600,8 +600,8 @@ static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
up_read(&mixer->chip->shutdown_rwsem);
if (ret < 0) {
- snd_printk(KERN_ERR
- "unable to issue vendor read request (ret = %d)", ret);
+ dev_err(&dev->dev,
+ "unable to issue vendor read request (ret = %d)", ret);
return ret;
}
@@ -631,8 +631,8 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
up_read(&mixer->chip->shutdown_rwsem);
if (ret < 0) {
- snd_printk(KERN_ERR
- "unable to issue vendor write request (ret = %d)", ret);
+ dev_err(&dev->dev,
+ "unable to issue vendor write request (ret = %d)", ret);
return ret;
}
@@ -1699,7 +1699,7 @@ void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id);
break;
default:
- snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid);
+ usb_audio_dbg(mixer->chip, "memory change in unknown unit %d\n", unitid);
break;
}
}
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index ca3256d6fde3..49de5c1284f6 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -166,8 +166,8 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep,
data, sizeof(data))) < 0) {
- snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n",
- dev->devnum, iface, ep);
+ usb_audio_err(chip, "%d:%d: cannot set enable PITCH\n",
+ iface, ep);
return err;
}
@@ -187,8 +187,8 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
UAC2_EP_CS_PITCH << 8, 0,
data, sizeof(data))) < 0) {
- snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n",
- dev->devnum, iface, fmt->altsetting);
+ usb_audio_err(chip, "%d:%d: cannot set enable PITCH (v2)\n",
+ iface, fmt->altsetting);
return err;
}
@@ -226,7 +226,7 @@ static int start_endpoints(struct snd_usb_substream *subs, bool can_sleep)
if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) {
struct snd_usb_endpoint *ep = subs->data_endpoint;
- snd_printdd(KERN_DEBUG "Starting data EP @%p\n", ep);
+ dev_dbg(&subs->dev->dev, "Starting data EP @%p\n", ep);
ep->data_subs = subs;
err = snd_usb_endpoint_start(ep, can_sleep);
@@ -247,16 +247,15 @@ static int start_endpoints(struct snd_usb_substream *subs, bool can_sleep)
subs->sync_endpoint->altsetting);
if (err < 0) {
clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags);
- snd_printk(KERN_ERR
- "%d:%d:%d: cannot set interface (%d)\n",
- subs->dev->devnum,
+ dev_err(&subs->dev->dev,
+ "%d:%d: cannot set interface (%d)\n",
subs->sync_endpoint->iface,
subs->sync_endpoint->altsetting, err);
return -EIO;
}
}
- snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep);
+ dev_dbg(&subs->dev->dev, "Starting sync EP @%p\n", ep);
ep->sync_slave = subs->data_endpoint;
err = snd_usb_endpoint_start(ep, can_sleep);
@@ -410,8 +409,9 @@ static int set_sync_endpoint(struct snd_usb_substream *subs,
if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC ||
(get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
get_endpoint(alts, 1)->bSynchAddress != 0)) {
- snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n",
- dev->devnum, fmt->iface, fmt->altsetting,
+ dev_err(&dev->dev,
+ "%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n",
+ fmt->iface, fmt->altsetting,
get_endpoint(alts, 1)->bmAttributes,
get_endpoint(alts, 1)->bLength,
get_endpoint(alts, 1)->bSynchAddress);
@@ -421,8 +421,9 @@ static int set_sync_endpoint(struct snd_usb_substream *subs,
if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
((is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
(!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) {
- snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n",
- dev->devnum, fmt->iface, fmt->altsetting,
+ dev_err(&dev->dev,
+ "%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n",
+ fmt->iface, fmt->altsetting,
is_playback, ep, get_endpoint(alts, 0)->bSynchAddress);
return -EINVAL;
}
@@ -469,8 +470,9 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
if (subs->interface >= 0 && subs->interface != fmt->iface) {
err = usb_set_interface(subs->dev, subs->interface, 0);
if (err < 0) {
- snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed (%d)\n",
- dev->devnum, fmt->iface, fmt->altsetting, err);
+ dev_err(&dev->dev,
+ "%d:%d: return to setting 0 failed (%d)\n",
+ fmt->iface, fmt->altsetting, err);
return -EIO;
}
subs->interface = -1;
@@ -482,12 +484,13 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
subs->altset_idx != fmt->altset_idx) {
err = usb_set_interface(dev, fmt->iface, fmt->altsetting);
if (err < 0) {
- snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed (%d)\n",
- dev->devnum, fmt->iface, fmt->altsetting, err);
+ dev_err(&dev->dev,
+ "%d:%d: usb_set_interface failed (%d)\n",
+ fmt->iface, fmt->altsetting, err);
return -EIO;
}
- snd_printdd(KERN_INFO "setting usb interface %d:%d\n",
- fmt->iface, fmt->altsetting);
+ dev_dbg(&dev->dev, "setting usb interface %d:%d\n",
+ fmt->iface, fmt->altsetting);
subs->interface = fmt->iface;
subs->altset_idx = fmt->altset_idx;
@@ -523,20 +526,23 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
* - Requested PCM format is not supported.
* - Requested sample rate is not supported.
*/
-static int match_endpoint_audioformats(struct audioformat *fp,
- struct audioformat *match, int rate,
- snd_pcm_format_t pcm_format)
+static int match_endpoint_audioformats(struct snd_usb_substream *subs,
+ struct audioformat *fp,
+ struct audioformat *match, int rate,
+ snd_pcm_format_t pcm_format)
{
int i;
int score = 0;
if (fp->channels < 1) {
- snd_printdd("%s: (fmt @%p) no channels\n", __func__, fp);
+ dev_dbg(&subs->dev->dev,
+ "%s: (fmt @%p) no channels\n", __func__, fp);
return 0;
}
if (!(fp->formats & pcm_format_to_bits(pcm_format))) {
- snd_printdd("%s: (fmt @%p) no match for format %d\n", __func__,
+ dev_dbg(&subs->dev->dev,
+ "%s: (fmt @%p) no match for format %d\n", __func__,
fp, pcm_format);
return 0;
}
@@ -548,7 +554,8 @@ static int match_endpoint_audioformats(struct audioformat *fp,
}
}
if (!score) {
- snd_printdd("%s: (fmt @%p) no match for rate %d\n", __func__,
+ dev_dbg(&subs->dev->dev,
+ "%s: (fmt @%p) no match for rate %d\n", __func__,
fp, rate);
return 0;
}
@@ -556,7 +563,8 @@ static int match_endpoint_audioformats(struct audioformat *fp,
if (fp->channels == match->channels)
score++;
- snd_printdd("%s: (fmt @%p) score %d\n", __func__, fp, score);
+ dev_dbg(&subs->dev->dev,
+ "%s: (fmt @%p) score %d\n", __func__, fp, score);
return score;
}
@@ -587,7 +595,8 @@ static int configure_sync_endpoint(struct snd_usb_substream *subs)
/* Try to find the best matching audioformat. */
list_for_each_entry(fp, &sync_subs->fmt_list, list) {
- int score = match_endpoint_audioformats(fp, subs->cur_audiofmt,
+ int score = match_endpoint_audioformats(subs,
+ fp, subs->cur_audiofmt,
subs->cur_rate, subs->pcm_format);
if (score > cur_score) {
@@ -597,7 +606,8 @@ static int configure_sync_endpoint(struct snd_usb_substream *subs)
}
if (unlikely(sync_fp == NULL)) {
- snd_printk(KERN_ERR "%s: no valid audioformat for sync ep %x found\n",
+ dev_err(&subs->dev->dev,
+ "%s: no valid audioformat for sync ep %x found\n",
__func__, sync_subs->ep_num);
return -EINVAL;
}
@@ -609,7 +619,8 @@ static int configure_sync_endpoint(struct snd_usb_substream *subs)
if (sync_fp->channels != subs->channels) {
sync_period_bytes = (subs->period_bytes / subs->channels) *
sync_fp->channels;
- snd_printdd("%s: adjusted sync ep period bytes (%d -> %d)\n",
+ dev_dbg(&subs->dev->dev,
+ "%s: adjusted sync ep period bytes (%d -> %d)\n",
__func__, subs->period_bytes, sync_period_bytes);
}
@@ -685,7 +696,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
fmt = find_format(subs);
if (!fmt) {
- snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n",
+ dev_dbg(&subs->dev->dev,
+ "cannot set format: format = %#x, rate = %d, channels = %d\n",
subs->pcm_format, subs->cur_rate, subs->channels);
return -EINVAL;
}
@@ -742,7 +754,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
int ret;
if (! subs->cur_audiofmt) {
- snd_printk(KERN_ERR "usbaudio: no format is specified!\n");
+ dev_err(&subs->dev->dev, "no format is specified!\n");
return -ENXIO;
}
@@ -1235,7 +1247,8 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
for (i = 0; i < urb->number_of_packets; i++) {
cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset + subs->pkt_offset_adj;
if (urb->iso_frame_desc[i].status && printk_ratelimit()) {
- snd_printdd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
+ dev_dbg(&subs->dev->dev, "frame %d active: %d\n",
+ i, urb->iso_frame_desc[i].status);
// continue;
}
bytes = urb->iso_frame_desc[i].actual_length;
@@ -1245,7 +1258,8 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
if (bytes % (runtime->sample_bits >> 3) != 0) {
int oldbytes = bytes;
bytes = frames * stride;
- snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
+ dev_warn(&subs->dev->dev,
+ "Corrected urb data len. %d->%d\n",
oldbytes, bytes);
}
/* update the current pointer */
@@ -1488,7 +1502,8 @@ static void retire_playback_urb(struct snd_usb_substream *subs,
* on two reads of a counter updated every ms.
*/
if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
- snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n",
+ dev_dbg(&subs->dev->dev,
+ "delay: estimated %d, actual %d\n",
est_delay, subs->last_delay);
if (!subs->running) {
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 89730707614c..7c57f2268dd7 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -110,7 +110,7 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip,
altsd = get_iface_desc(alts);
err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber);
if (err < 0) {
- snd_printk(KERN_ERR "cannot setup if %d: error %d\n",
+ usb_audio_err(chip, "cannot setup if %d: error %d\n",
altsd->bInterfaceNumber, err);
return err;
}
@@ -135,7 +135,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
if (!fp) {
- snd_printk(KERN_ERR "cannot memdup\n");
+ usb_audio_err(chip, "cannot memdup\n");
return -ENOMEM;
}
if (fp->nr_rates > MAX_NR_RATES) {
@@ -464,7 +464,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
fp->rate_max = fp->rate_min = 96000;
break;
default:
- snd_printk(KERN_ERR "unknown sample rate\n");
+ usb_audio_err(chip, "unknown sample rate\n");
kfree(fp);
return -ENXIO;
}
@@ -536,7 +536,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
if (quirk->type < QUIRK_TYPE_COUNT) {
return quirk_funcs[quirk->type](chip, iface, driver, quirk);
} else {
- snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
+ usb_audio_err(chip, "invalid quirk type %d\n", quirk->type);
return -ENXIO;
}
}
@@ -555,18 +555,21 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac
if (le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_OLD ||
le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_NEW) {
- snd_printdd("sending Extigy boot sequence...\n");
+ dev_dbg(&dev->dev, "sending Extigy boot sequence...\n");
/* Send message to force it to reconnect with full interface. */
err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0),
0x10, 0x43, 0x0001, 0x000a, NULL, 0);
- if (err < 0) snd_printdd("error sending boot message: %d\n", err);
+ if (err < 0)
+ dev_dbg(&dev->dev, "error sending boot message: %d\n", err);
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
&dev->descriptor, sizeof(dev->descriptor));
config = dev->actconfig;
- if (err < 0) snd_printdd("error usb_get_descriptor: %d\n", err);
+ if (err < 0)
+ dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err);
err = usb_reset_configuration(dev);
- if (err < 0) snd_printdd("error usb_reset_configuration: %d\n", err);
- snd_printdd("extigy_boot: new boot length = %d\n",
+ if (err < 0)
+ dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err);
+ dev_dbg(&dev->dev, "extigy_boot: new boot length = %d\n",
le16_to_cpu(get_cfg_desc(config)->wTotalLength));
return -ENODEV; /* quit this anyway */
}
@@ -594,7 +597,7 @@ static int snd_usb_fasttrackpro_boot_quirk(struct usb_device *dev)
int err;
if (dev->actconfig->desc.bConfigurationValue == 1) {
- snd_printk(KERN_INFO "usb-audio: "
+ dev_info(&dev->dev,
"Fast Track Pro switching to config #2\n");
/* This function has to be available by the usb core module.
* if it is not avialable the boot quirk has to be left out
@@ -603,14 +606,15 @@ static int snd_usb_fasttrackpro_boot_quirk(struct usb_device *dev)
*/
err = usb_driver_set_configuration(dev, 2);
if (err < 0)
- snd_printdd("error usb_driver_set_configuration: %d\n",
- err);
+ dev_dbg(&dev->dev,
+ "error usb_driver_set_configuration: %d\n",
+ err);
/* Always return an error, so that we stop creating a device
that will just be destroyed and recreated with a new
configuration */
return -ENODEV;
} else
- snd_printk(KERN_INFO "usb-audio: Fast Track Pro config OK\n");
+ dev_info(&dev->dev, "Fast Track Pro config OK\n");
return 0;
}
@@ -779,11 +783,11 @@ static int snd_usb_mbox2_boot_quirk(struct usb_device *dev)
fwsize = le16_to_cpu(get_cfg_desc(config)->wTotalLength);
if (fwsize != MBOX2_FIRMWARE_SIZE) {
- snd_printk(KERN_ERR "usb-audio: Invalid firmware size=%d.\n", fwsize);
+ dev_err(&dev->dev, "Invalid firmware size=%d.\n", fwsize);
return -ENODEV;
}
- snd_printd("usb-audio: Sending Digidesign Mbox 2 boot sequence...\n");
+ dev_dbg(&dev->dev, "Sending Digidesign Mbox 2 boot sequence...\n");
count = 0;
bootresponse[0] = MBOX2_BOOT_LOADING;
@@ -794,32 +798,32 @@ static int snd_usb_mbox2_boot_quirk(struct usb_device *dev)
0x85, 0xc0, 0x0001, 0x0000, &bootresponse, 0x0012);
if (bootresponse[0] == MBOX2_BOOT_READY)
break;
- snd_printd("usb-audio: device not ready, resending boot sequence...\n");
+ dev_dbg(&dev->dev, "device not ready, resending boot sequence...\n");
count++;
}
if (bootresponse[0] != MBOX2_BOOT_READY) {
- snd_printk(KERN_ERR "usb-audio: Unknown bootresponse=%d, or timed out, ignoring device.\n", bootresponse[0]);
+ dev_err(&dev->dev, "Unknown bootresponse=%d, or timed out, ignoring device.\n", bootresponse[0]);
return -ENODEV;
}
- snd_printdd("usb-audio: device initialised!\n");
+ dev_dbg(&dev->dev, "device initialised!\n");
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
&dev->descriptor, sizeof(dev->descriptor));
config = dev->actconfig;
if (err < 0)
- snd_printd("error usb_get_descriptor: %d\n", err);
+ dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err);
err = usb_reset_configuration(dev);
if (err < 0)
- snd_printd("error usb_reset_configuration: %d\n", err);
- snd_printdd("mbox2_boot: new boot length = %d\n",
+ dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err);
+ dev_dbg(&dev->dev, "mbox2_boot: new boot length = %d\n",
le16_to_cpu(get_cfg_desc(config)->wTotalLength));
mbox2_setup_48_24_magic(dev);
- snd_printk(KERN_INFO "usb-audio: Digidesign Mbox 2: 24bit 48kHz");
+ dev_info(&dev->dev, "Digidesign Mbox 2: 24bit 48kHz");
return 0; /* Successful boot */
}
@@ -865,7 +869,7 @@ static int quattro_skip_setting_quirk(struct snd_usb_audio *chip,
return 1; /* skip this altsetting */
}
}
- snd_printdd(KERN_INFO
+ usb_audio_dbg(chip,
"using altsetting %d for interface %d config %d\n",
altno, iface, chip->setup);
return 0; /* keep this altsetting */
@@ -932,7 +936,7 @@ static int fasttrackpro_skip_setting_quirk(struct snd_usb_audio *chip,
return 1;
}
- snd_printdd(KERN_INFO
+ usb_audio_dbg(chip,
"using altsetting %d for interface %d config %d\n",
altno, iface, chip->setup);
return 0; /* keep this altsetting */
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 2fb71be5e100..310a3822d2b7 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -411,10 +411,9 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
if (!csep || csep->bLength < 7 ||
csep->bDescriptorSubtype != UAC_EP_GENERAL) {
- snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
- " class specific endpoint descriptor\n",
- chip->dev->devnum, iface_no,
- altsd->bAlternateSetting);
+ usb_audio_warn(chip,
+ "%u:%d : no or invalid class specific endpoint descriptor\n",
+ iface_no, altsd->bAlternateSetting);
return 0;
}
@@ -533,8 +532,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
/* get audio formats */
switch (protocol) {
default:
- snd_printdd(KERN_WARNING "%d:%u:%d: unknown interface protocol %#02x, assuming v1\n",
- dev->devnum, iface_no, altno, protocol);
+ dev_dbg(&dev->dev, "%u:%d: unknown interface protocol %#02x, assuming v1\n",
+ iface_no, altno, protocol);
protocol = UAC_VERSION_1;
/* fall through */
@@ -544,14 +543,16 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
struct uac_input_terminal_descriptor *iterm;
if (!as) {
- snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
- dev->devnum, iface_no, altno);
+ dev_err(&dev->dev,
+ "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+ iface_no, altno);
continue;
}
if (as->bLength < sizeof(*as)) {
- snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
- dev->devnum, iface_no, altno);
+ dev_err(&dev->dev,
+ "%u:%d : invalid UAC_AS_GENERAL desc\n",
+ iface_no, altno);
continue;
}
@@ -574,14 +575,16 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
if (!as) {
- snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
- dev->devnum, iface_no, altno);
+ dev_err(&dev->dev,
+ "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+ iface_no, altno);
continue;
}
if (as->bLength < sizeof(*as)) {
- snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
- dev->devnum, iface_no, altno);
+ dev_err(&dev->dev,
+ "%u:%d : invalid UAC_AS_GENERAL desc\n",
+ iface_no, altno);
continue;
}
@@ -607,8 +610,9 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
break;
}
- snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n",
- dev->devnum, iface_no, altno, as->bTerminalLink);
+ dev_err(&dev->dev,
+ "%u:%d : bogus bTerminalLink %d\n",
+ iface_no, altno, as->bTerminalLink);
continue;
}
}
@@ -616,14 +620,16 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
/* get format type */
fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE);
if (!fmt) {
- snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n",
- dev->devnum, iface_no, altno);
+ dev_err(&dev->dev,
+ "%u:%d : no UAC_FORMAT_TYPE desc\n",
+ iface_no, altno);
continue;
}
if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) ||
((protocol == UAC_VERSION_2) && (fmt->bLength < 6))) {
- snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
- dev->devnum, iface_no, altno);
+ dev_err(&dev->dev,
+ "%u:%d : invalid UAC_FORMAT_TYPE desc\n",
+ iface_no, altno);
continue;
}
@@ -644,7 +650,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
fp = kzalloc(sizeof(*fp), GFP_KERNEL);
if (! fp) {
- snd_printk(KERN_ERR "cannot malloc\n");
+ dev_err(&dev->dev, "cannot malloc\n");
return -ENOMEM;
}
@@ -707,7 +713,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
chconfig = 0;
fp->chmap = convert_chmap(fp->channels, chconfig, protocol);
- snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint);
+ dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
err = snd_usb_add_audio_stream(chip, stream, fp);
if (err < 0) {
kfree(fp->rate_table);
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 5d2fe0530745..25c4c7e217de 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -60,6 +60,15 @@ struct snd_usb_audio {
struct usb_host_interface *ctrl_intf; /* the audio control interface */
};
+#define usb_audio_err(chip, fmt, args...) \
+ dev_err(&(chip)->dev->dev, fmt, ##args)
+#define usb_audio_warn(chip, fmt, args...) \
+ dev_warn(&(chip)->dev->dev, fmt, ##args)
+#define usb_audio_info(chip, fmt, args...) \
+ dev_info(&(chip)->dev->dev, fmt, ##args)
+#define usb_audio_dbg(chip, fmt, args...) \
+ dev_dbg(&(chip)->dev->dev, fmt, ##args)
+
/*
* Information about devices with broken descriptors
*/
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c
index 999550bbad40..cf5dc33f4a6d 100644
--- a/sound/usb/usx2y/us122l.c
+++ b/sound/usb/usx2y/us122l.c
@@ -535,7 +535,9 @@ static void snd_us122l_free(struct snd_card *card)
snd_us122l_card_used[index] = 0;
}
-static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)
+static int usx2y_create_card(struct usb_device *device,
+ struct usb_interface *intf,
+ struct snd_card **cardp)
{
int dev;
struct snd_card *card;
@@ -546,8 +548,8 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)
break;
if (dev >= SNDRV_CARDS)
return -ENODEV;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct us122l), &card);
+ err = snd_card_new(&intf->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct us122l), &card);
if (err < 0)
return err;
snd_us122l_card_used[US122L(card)->card_index = dev] = 1;
@@ -578,11 +580,10 @@ static int us122l_usb_probe(struct usb_interface *intf,
struct snd_card *card;
int err;
- err = usx2y_create_card(device, &card);
+ err = usx2y_create_card(device, intf, &card);
if (err < 0)
return err;
- snd_card_set_dev(card, &intf->dev);
if (!us122l_create_card(card)) {
snd_card_free(card);
return -EINVAL;
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index 5a51b18c50fe..91e0e2a4808c 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -332,7 +332,9 @@ static struct usb_device_id snd_usX2Y_usb_id_table[] = {
{ /* terminator */ }
};
-static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp)
+static int usX2Y_create_card(struct usb_device *device,
+ struct usb_interface *intf,
+ struct snd_card **cardp)
{
int dev;
struct snd_card * card;
@@ -343,15 +345,15 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp)
break;
if (dev >= SNDRV_CARDS)
return -ENODEV;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct usX2Ydev), &card);
+ err = snd_card_new(&intf->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct usX2Ydev), &card);
if (err < 0)
return err;
snd_usX2Y_card_used[usX2Y(card)->card_index = dev] = 1;
card->private_free = snd_usX2Y_card_private_free;
usX2Y(card)->dev = device;
init_waitqueue_head(&usX2Y(card)->prepare_wait_queue);
- mutex_init(&usX2Y(card)->prepare_mutex);
+ mutex_init(&usX2Y(card)->pcm_mutex);
INIT_LIST_HEAD(&usX2Y(card)->midi_list);
strcpy(card->driver, "USB "NAME_ALLCAPS"");
sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
@@ -382,10 +384,9 @@ static int usX2Y_usb_probe(struct usb_device *device,
le16_to_cpu(device->descriptor.idProduct) != USB_ID_US428))
return -EINVAL;
- err = usX2Y_create_card(device, &card);
+ err = usX2Y_create_card(device, intf, &card);
if (err < 0)
return err;
- snd_card_set_dev(card, &intf->dev);
if ((err = usX2Y_hwdep_new(card, device)) < 0 ||
(err = snd_card_register(card)) < 0) {
snd_card_free(card);
diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h
index e43c0a86441a..6ae6b0806938 100644
--- a/sound/usb/usx2y/usbusx2y.h
+++ b/sound/usb/usx2y/usbusx2y.h
@@ -36,7 +36,7 @@ struct usX2Ydev {
unsigned int rate,
format;
int chip_status;
- struct mutex prepare_mutex;
+ struct mutex pcm_mutex;
struct us428ctls_sharedmem *us428ctls_sharedmem;
int wait_iso_frame;
wait_queue_head_t us428ctls_wait_queue_head;
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 6234a51625b1..a63330dd1407 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -752,36 +752,44 @@ static int snd_usX2Y_pcm_hw_params(struct snd_pcm_substream *substream,
unsigned int rate = params_rate(hw_params);
snd_pcm_format_t format = params_format(hw_params);
struct snd_card *card = substream->pstr->pcm->card;
- struct list_head *list;
+ struct usX2Ydev *dev = usX2Y(card);
+ int i;
+ mutex_lock(&usX2Y(card)->pcm_mutex);
snd_printdd("snd_usX2Y_hw_params(%p, %p)\n", substream, hw_params);
- // all pcm substreams off one usX2Y have to operate at the same rate & format
- list_for_each(list, &card->devices) {
- struct snd_device *dev;
- struct snd_pcm *pcm;
- int s;
- dev = snd_device(list);
- if (dev->type != SNDRV_DEV_PCM)
+ /* all pcm substreams off one usX2Y have to operate at the same
+ * rate & format
+ */
+ for (i = 0; i < dev->pcm_devs * 2; i++) {
+ struct snd_usX2Y_substream *subs = dev->subs[i];
+ struct snd_pcm_substream *test_substream;
+
+ if (!subs)
+ continue;
+ test_substream = subs->pcm_substream;
+ if (!test_substream || test_substream == substream ||
+ !test_substream->runtime)
continue;
- pcm = dev->device_data;
- for (s = 0; s < 2; ++s) {
- struct snd_pcm_substream *test_substream;
- test_substream = pcm->streams[s].substream;
- if (test_substream && test_substream != substream &&
- test_substream->runtime &&
- ((test_substream->runtime->format &&
- test_substream->runtime->format != format) ||
- (test_substream->runtime->rate &&
- test_substream->runtime->rate != rate)))
- return -EINVAL;
+ if ((test_substream->runtime->format &&
+ test_substream->runtime->format != format) ||
+ (test_substream->runtime->rate &&
+ test_substream->runtime->rate != rate)) {
+ err = -EINVAL;
+ goto error;
}
}
- if (0 > (err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)))) {
+
+ err = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ if (err < 0) {
snd_printk(KERN_ERR "snd_pcm_lib_malloc_pages(%p, %i) returned %i\n",
substream, params_buffer_bytes(hw_params), err);
- return err;
+ goto error;
}
- return 0;
+
+ error:
+ mutex_unlock(&usX2Y(card)->pcm_mutex);
+ return err;
}
/*
@@ -791,7 +799,7 @@ static int snd_usX2Y_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_usX2Y_substream *subs = runtime->private_data;
- mutex_lock(&subs->usX2Y->prepare_mutex);
+ mutex_lock(&subs->usX2Y->pcm_mutex);
snd_printdd("snd_usX2Y_hw_free(%p)\n", substream);
if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
@@ -812,7 +820,7 @@ static int snd_usX2Y_pcm_hw_free(struct snd_pcm_substream *substream)
usX2Y_urbs_release(subs);
}
}
- mutex_unlock(&subs->usX2Y->prepare_mutex);
+ mutex_unlock(&subs->usX2Y->pcm_mutex);
return snd_pcm_lib_free_pages(substream);
}
/*
@@ -829,7 +837,7 @@ static int snd_usX2Y_pcm_prepare(struct snd_pcm_substream *substream)
int err = 0;
snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
- mutex_lock(&usX2Y->prepare_mutex);
+ mutex_lock(&usX2Y->pcm_mutex);
usX2Y_subs_prepare(subs);
// Start hardware streams
// SyncStream first....
@@ -849,7 +857,7 @@ static int snd_usX2Y_pcm_prepare(struct snd_pcm_substream *substream)
err = usX2Y_urbs_start(subs);
up_prepare_mutex:
- mutex_unlock(&usX2Y->prepare_mutex);
+ mutex_unlock(&usX2Y->pcm_mutex);
return err;
}
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index 814d0e887c62..90766a92e7fd 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -358,7 +358,7 @@ static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_usX2Y_substream *subs = runtime->private_data,
*cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
- mutex_lock(&subs->usX2Y->prepare_mutex);
+ mutex_lock(&subs->usX2Y->pcm_mutex);
snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
@@ -387,7 +387,7 @@ static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
usX2Y_usbpcm_urbs_release(cap_subs2);
}
}
- mutex_unlock(&subs->usX2Y->prepare_mutex);
+ mutex_unlock(&subs->usX2Y->pcm_mutex);
return snd_pcm_lib_free_pages(substream);
}
@@ -493,7 +493,7 @@ static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
}
- mutex_lock(&usX2Y->prepare_mutex);
+ mutex_lock(&usX2Y->pcm_mutex);
usX2Y_subs_prepare(subs);
// Start hardware streams
// SyncStream first....
@@ -534,7 +534,7 @@ static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
up_prepare_mutex:
- mutex_unlock(&usX2Y->prepare_mutex);
+ mutex_unlock(&usX2Y->pcm_mutex);
return err;
}
@@ -600,59 +600,30 @@ static struct snd_pcm_ops snd_usX2Y_usbpcm_ops =
};
-static int usX2Y_pcms_lock_check(struct snd_card *card)
+static int usX2Y_pcms_busy_check(struct snd_card *card)
{
- struct list_head *list;
- struct snd_device *dev;
- struct snd_pcm *pcm;
- int err = 0;
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
- if (dev->type != SNDRV_DEV_PCM)
- continue;
- pcm = dev->device_data;
- mutex_lock(&pcm->open_mutex);
- }
- list_for_each(list, &card->devices) {
- int s;
- dev = snd_device(list);
- if (dev->type != SNDRV_DEV_PCM)
- continue;
- pcm = dev->device_data;
- for (s = 0; s < 2; ++s) {
- struct snd_pcm_substream *substream;
- substream = pcm->streams[s].substream;
- if (substream && SUBSTREAM_BUSY(substream))
- err = -EBUSY;
- }
- }
- return err;
-}
-
+ struct usX2Ydev *dev = usX2Y(card);
+ int i;
-static void usX2Y_pcms_unlock(struct snd_card *card)
-{
- struct list_head *list;
- struct snd_device *dev;
- struct snd_pcm *pcm;
- list_for_each(list, &card->devices) {
- dev = snd_device(list);
- if (dev->type != SNDRV_DEV_PCM)
- continue;
- pcm = dev->device_data;
- mutex_unlock(&pcm->open_mutex);
+ for (i = 0; i < dev->pcm_devs * 2; i++) {
+ struct snd_usX2Y_substream *subs = dev->subs[i];
+ if (subs && subs->pcm_substream &&
+ SUBSTREAM_BUSY(subs->pcm_substream))
+ return -EBUSY;
}
+ return 0;
}
-
static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
{
- // we need to be the first
struct snd_card *card = hw->card;
- int err = usX2Y_pcms_lock_check(card);
- if (0 == err)
+ int err;
+
+ mutex_lock(&usX2Y(card)->pcm_mutex);
+ err = usX2Y_pcms_busy_check(card);
+ if (!err)
usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
- usX2Y_pcms_unlock(card);
+ mutex_unlock(&usX2Y(card)->pcm_mutex);
return err;
}
@@ -660,10 +631,13 @@ static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
{
struct snd_card *card = hw->card;
- int err = usX2Y_pcms_lock_check(card);
- if (0 == err)
+ int err;
+
+ mutex_lock(&usX2Y(card)->pcm_mutex);
+ err = usX2Y_pcms_busy_check(card);
+ if (!err)
usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
- usX2Y_pcms_unlock(card);
+ mutex_unlock(&usX2Y(card)->pcm_mutex);
return err;
}
diff --git a/tools/Makefile b/tools/Makefile
index feec3ad5fd09..bcae806b0c39 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -7,6 +7,7 @@ help:
@echo ' cgroup - cgroup tools'
@echo ' cpupower - a tool for all things x86 CPU power'
@echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
+ @echo ' hv - tools used when in Hyper-V clients'
@echo ' lguest - a minimal 32-bit x86 hypervisor'
@echo ' perf - Linux performance measurement and analysis tool'
@echo ' selftests - various kernel selftests'
@@ -40,7 +41,7 @@ acpi: FORCE
cpupower: FORCE
$(call descend,power/$@)
-cgroup firewire guest usb virtio vm net: FORCE
+cgroup firewire hv guest usb virtio vm net: FORCE
$(call descend,$@)
libapikfs: FORCE
@@ -64,7 +65,7 @@ acpi_install:
cpupower_install:
$(call descend,power/$(@:_install=),install)
-cgroup_install firewire_install lguest_install perf_install usb_install virtio_install vm_install net_install:
+cgroup_install firewire_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install:
$(call descend,$(@:_install=),install)
selftests_install:
@@ -76,7 +77,7 @@ turbostat_install x86_energy_perf_policy_install:
tmon_install:
$(call descend,thermal/$(@:_install=),install)
-install: acpi_install cgroup_install cpupower_install firewire_install lguest_install \
+install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \
perf_install selftests_install turbostat_install usb_install \
virtio_install vm_install net_install x86_energy_perf_policy_install \
tmon
@@ -87,7 +88,7 @@ acpi_clean:
cpupower_clean:
$(call descend,power/cpupower,clean)
-cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean:
+cgroup_clean hv_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean:
$(call descend,$(@:_clean=),clean)
libapikfs_clean:
@@ -105,7 +106,7 @@ turbostat_clean x86_energy_perf_policy_clean:
tmon_clean:
$(call descend,thermal/tmon,clean)
-clean: acpi_clean cgroup_clean cpupower_clean firewire_clean lguest_clean \
+clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \
perf_clean selftests_clean turbostat_clean usb_clean virtio_clean \
vm_clean net_clean x86_energy_perf_policy_clean tmon_clean
diff --git a/tools/hv/Makefile b/tools/hv/Makefile
new file mode 100644
index 000000000000..bd22f786a60c
--- /dev/null
+++ b/tools/hv/Makefile
@@ -0,0 +1,13 @@
+# Makefile for Hyper-V tools
+
+CC = $(CROSS_COMPILE)gcc
+PTHREAD_LIBS = -lpthread
+WARNINGS = -Wall -Wextra
+CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS)
+
+all: hv_kvp_daemon hv_vss_daemon
+%: %.c
+ $(CC) $(CFLAGS) -o $@ $^
+
+clean:
+ $(RM) hv_kvp_daemon hv_vss_daemon
diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c
new file mode 100644
index 000000000000..4ecc4fd0bc1b
--- /dev/null
+++ b/tools/hv/hv_fcopy_daemon.c
@@ -0,0 +1,195 @@
+/*
+ * An implementation of host to guest copy functionality for Linux.
+ *
+ * Copyright (C) 2014, Microsoft, Inc.
+ *
+ * Author : K. Y. Srinivasan <kys@microsoft.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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <linux/hyperv.h>
+#include <syslog.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+static int target_fd;
+static char target_fname[W_MAX_PATH];
+
+static int hv_start_fcopy(struct hv_start_fcopy *smsg)
+{
+ int error = HV_E_FAIL;
+ char *q, *p;
+
+ /*
+ * If possile append a path seperator to the path.
+ */
+ if (strlen((char *)smsg->path_name) < (W_MAX_PATH - 2))
+ strcat((char *)smsg->path_name, "/");
+
+ p = (char *)smsg->path_name;
+ snprintf(target_fname, sizeof(target_fname), "%s/%s",
+ (char *)smsg->path_name, smsg->file_name);
+
+ syslog(LOG_INFO, "Target file name: %s", target_fname);
+ /*
+ * Check to see if the path is already in place; if not,
+ * create if required.
+ */
+ while ((q = strchr(p, '/')) != NULL) {
+ if (q == p) {
+ p++;
+ continue;
+ }
+ *q = '\0';
+ if (access((char *)smsg->path_name, F_OK)) {
+ if (smsg->copy_flags & CREATE_PATH) {
+ if (mkdir((char *)smsg->path_name, 0755)) {
+ syslog(LOG_ERR, "Failed to create %s",
+ (char *)smsg->path_name);
+ goto done;
+ }
+ } else {
+ syslog(LOG_ERR, "Invalid path: %s",
+ (char *)smsg->path_name);
+ goto done;
+ }
+ }
+ p = q + 1;
+ *q = '/';
+ }
+
+ if (!access(target_fname, F_OK)) {
+ syslog(LOG_INFO, "File: %s exists", target_fname);
+ if (!smsg->copy_flags & OVER_WRITE)
+ goto done;
+ }
+
+ target_fd = open(target_fname, O_RDWR | O_CREAT | O_CLOEXEC, 0744);
+ if (target_fd == -1) {
+ syslog(LOG_INFO, "Open Failed: %s", strerror(errno));
+ goto done;
+ }
+
+ error = 0;
+done:
+ return error;
+}
+
+static int hv_copy_data(struct hv_do_fcopy *cpmsg)
+{
+ ssize_t bytes_written;
+
+ bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
+ cpmsg->offset);
+
+ if (bytes_written != cpmsg->size)
+ return HV_E_FAIL;
+
+ return 0;
+}
+
+static int hv_copy_finished(void)
+{
+ close(target_fd);
+ return 0;
+}
+static int hv_copy_cancel(void)
+{
+ close(target_fd);
+ unlink(target_fname);
+ return 0;
+
+}
+
+int main(void)
+{
+ int fd, fcopy_fd, len;
+ int error;
+ int version = FCOPY_CURRENT_VERSION;
+ char *buffer[4096 * 2];
+ struct hv_fcopy_hdr *in_msg;
+
+ if (daemon(1, 0)) {
+ syslog(LOG_ERR, "daemon() failed; error: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ openlog("HV_FCOPY", 0, LOG_USER);
+ syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid());
+
+ fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR);
+
+ if (fcopy_fd < 0) {
+ syslog(LOG_ERR, "open /dev/vmbus/hv_fcopy failed; error: %d %s",
+ errno, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Register with the kernel.
+ */
+ if ((write(fcopy_fd, &version, sizeof(int))) != sizeof(int)) {
+ syslog(LOG_ERR, "Registration failed: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ while (1) {
+ /*
+ * In this loop we process fcopy messages after the
+ * handshake is complete.
+ */
+ len = pread(fcopy_fd, buffer, (4096 * 2), 0);
+ if (len < 0) {
+ syslog(LOG_ERR, "pread failed: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ in_msg = (struct hv_fcopy_hdr *)buffer;
+
+ switch (in_msg->operation) {
+ case START_FILE_COPY:
+ error = hv_start_fcopy((struct hv_start_fcopy *)in_msg);
+ break;
+ case WRITE_TO_FILE:
+ error = hv_copy_data((struct hv_do_fcopy *)in_msg);
+ break;
+ case COMPLETE_FCOPY:
+ error = hv_copy_finished();
+ break;
+ case CANCEL_FCOPY:
+ error = hv_copy_cancel();
+ break;
+
+ default:
+ syslog(LOG_ERR, "Unknown operation: %d",
+ in_msg->operation);
+
+ }
+
+ if (pwrite(fcopy_fd, &error, sizeof(int), 0) != sizeof(int)) {
+ syslog(LOG_ERR, "pwrite failed: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+}
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
index 520de3304571..6a213b8cd7b9 100644
--- a/tools/hv/hv_vss_daemon.c
+++ b/tools/hv/hv_vss_daemon.c
@@ -87,6 +87,8 @@ static int vss_operate(int operation)
continue;
if (strcmp(ent->mnt_type, "iso9660") == 0)
continue;
+ if (strcmp(ent->mnt_type, "vfat") == 0)
+ continue;
if (strcmp(ent->mnt_dir, "/") == 0) {
root_seen = 1;
continue;
diff --git a/tools/include/linux/hash.h b/tools/include/linux/hash.h
new file mode 100644
index 000000000000..d026c6573018
--- /dev/null
+++ b/tools/include/linux/hash.h
@@ -0,0 +1,5 @@
+#include "../../../include/linux/hash.h"
+
+#ifndef _TOOLS_LINUX_HASH_H
+#define _TOOLS_LINUX_HASH_H
+#endif
diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile
index ed2f51e11b80..ce00f7ee6455 100644
--- a/tools/lib/api/Makefile
+++ b/tools/lib/api/Makefile
@@ -9,8 +9,10 @@ LIB_H=
LIB_OBJS=
LIB_H += fs/debugfs.h
+LIB_H += fs/fs.h
LIB_OBJS += $(OUTPUT)fs/debugfs.o
+LIB_OBJS += $(OUTPUT)fs/fs.o
LIBFILE = libapikfs.a
diff --git a/tools/perf/util/fs.c b/tools/lib/api/fs/fs.c
index f5be1f26e724..5b5eb788996e 100644
--- a/tools/perf/util/fs.c
+++ b/tools/lib/api/fs/fs.c
@@ -1,8 +1,13 @@
+/* TODO merge/factor in debugfs.c here */
-/* TODO merge/factor into tools/lib/lk/debugfs.c */
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/vfs.h>
-#include "util.h"
-#include "util/fs.h"
+#include "debugfs.h"
+#include "fs.h"
static const char * const sysfs__fs_known_mountpoints[] = {
"/sys",
diff --git a/tools/perf/util/include/linux/magic.h b/tools/lib/api/fs/fs.h
index 07d63cf3e0f6..cb7049551f33 100644
--- a/tools/perf/util/include/linux/magic.h
+++ b/tools/lib/api/fs/fs.h
@@ -1,9 +1,5 @@
-#ifndef _PERF_LINUX_MAGIC_H_
-#define _PERF_LINUX_MAGIC_H_
-
-#ifndef DEBUGFS_MAGIC
-#define DEBUGFS_MAGIC 0x64626720
-#endif
+#ifndef __API_FS__
+#define __API_FS__
#ifndef SYSFS_MAGIC
#define SYSFS_MAGIC 0x62656572
@@ -13,4 +9,6 @@
#define PROC_SUPER_MAGIC 0x9fa0
#endif
-#endif
+const char *sysfs__mountpoint(void);
+const char *procfs__mountpoint(void);
+#endif /* __API_FS__ */
diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile
index da8b7aa3d351..07b0b7542511 100644
--- a/tools/lib/lockdep/Makefile
+++ b/tools/lib/lockdep/Makefile
@@ -87,8 +87,8 @@ endif # BUILD_SRC
# We process the rest of the Makefile if this is the final invocation of make
ifeq ($(skip-makefile),)
-srctree := $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))
-objtree := $(CURDIR)
+srctree := $(realpath $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR)))
+objtree := $(realpath $(CURDIR))
src := $(srctree)
obj := $(objtree)
@@ -112,7 +112,7 @@ export Q VERBOSE
LIBLOCKDEP_VERSION = $(LL_VERSION).$(LL_PATCHLEVEL).$(LL_EXTRAVERSION)
-INCLUDES = -I. -I/usr/local/include -I./uinclude $(CONFIG_INCLUDES)
+INCLUDES = -I. -I/usr/local/include -I./uinclude -I./include $(CONFIG_INCLUDES)
# Set compile option CFLAGS if not set elsewhere
CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g
diff --git a/tools/lib/lockdep/preload.c b/tools/lib/lockdep/preload.c
index f8465a811aa5..23bd69cb5ade 100644
--- a/tools/lib/lockdep/preload.c
+++ b/tools/lib/lockdep/preload.c
@@ -418,7 +418,7 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
__attribute__((constructor)) static void init_preload(void)
{
- if (__init_state != done)
+ if (__init_state == done)
return;
#ifndef __GLIBC__
diff --git a/tools/lib/lockdep/run_tests.sh b/tools/lib/lockdep/run_tests.sh
index 5334ad9d39b7..5334ad9d39b7 100644..100755
--- a/tools/lib/lockdep/run_tests.sh
+++ b/tools/lib/lockdep/run_tests.sh
diff --git a/tools/lib/lockdep/uinclude/asm/hash.h b/tools/lib/lockdep/uinclude/asm/hash.h
new file mode 100644
index 000000000000..d82b170bb216
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/asm/hash.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_GENERIC_HASH_H
+#define __ASM_GENERIC_HASH_H
+
+/* Stub */
+
+#endif /* __ASM_GENERIC_HASH_H */
diff --git a/tools/lib/lockdep/uinclude/linux/rcu.h b/tools/lib/lockdep/uinclude/linux/rcu.h
index 4c99fcb5da27..042ee8e463c9 100644
--- a/tools/lib/lockdep/uinclude/linux/rcu.h
+++ b/tools/lib/lockdep/uinclude/linux/rcu.h
@@ -13,4 +13,9 @@ static inline int rcu_is_cpu_idle(void)
return 1;
}
+static inline bool rcu_is_watching(void)
+{
+ return false;
+}
+
#endif
diff --git a/tools/net/Makefile b/tools/net/Makefile
index 004cd74734b6..ee577ea03ba5 100644
--- a/tools/net/Makefile
+++ b/tools/net/Makefile
@@ -12,7 +12,7 @@ YACC = bison
all : bpf_jit_disasm bpf_dbg bpf_asm
-bpf_jit_disasm : CFLAGS = -Wall -O2
+bpf_jit_disasm : CFLAGS = -Wall -O2 -DPACKAGE='bpf_jit_disasm'
bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl
bpf_jit_disasm : bpf_jit_disasm.o
diff --git a/tools/perf/Documentation/perf-mem.txt b/tools/perf/Documentation/perf-mem.txt
index 888d51137fbe..1d78a4064da4 100644
--- a/tools/perf/Documentation/perf-mem.txt
+++ b/tools/perf/Documentation/perf-mem.txt
@@ -18,6 +18,10 @@ from it, into perf.data. Perf record options are accepted and are passed through
"perf mem -t <TYPE> report" displays the result. It invokes perf report with the
right set of options to display a memory access profile.
+Note that on Intel systems the memory latency reported is the use-latency,
+not the pure load (or store latency). Use latency includes any pipeline
+queueing delays in addition to the memory subsystem latency.
+
OPTIONS
-------
<command>...::
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index b715cb71592b..1513935c399b 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -136,6 +136,8 @@ Each probe argument follows below syntax.
'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type.
+On x86 systems %REG is always the short form of the register: for example %AX. %RAX or %EAX is not valid.
+
LINE SYNTAX
-----------
Line range is described by following syntax.
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index f41572d0dd76..c0c87c87b60f 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -6,6 +6,7 @@ tools/lib/symbol/kallsyms.c
tools/lib/symbol/kallsyms.h
tools/include/asm/bug.h
tools/include/linux/compiler.h
+tools/include/linux/hash.h
include/linux/const.h
include/linux/perf_event.h
include/linux/rbtree.h
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 7257e7e9e38a..50d875d970c4 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -7,6 +7,8 @@ include config/utilities.mak
# Define V to have a more verbose compile.
#
+# Define VF to have a more verbose feature check output.
+#
# Define O to save output files in a separate directory.
#
# Define ARCH as name of target architecture if you want cross-builds.
@@ -55,6 +57,9 @@ include config/utilities.mak
# Define NO_LIBAUDIT if you do not want libaudit support
#
# Define NO_LIBBIONIC if you do not want bionic support
+#
+# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
+# for dwarf backtrace post unwind.
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -208,7 +213,7 @@ LIB_H += ../../include/uapi/linux/perf_event.h
LIB_H += ../../include/linux/rbtree.h
LIB_H += ../../include/linux/list.h
LIB_H += ../../include/uapi/linux/const.h
-LIB_H += ../../include/linux/hash.h
+LIB_H += ../include/linux/hash.h
LIB_H += ../../include/linux/stringify.h
LIB_H += util/include/linux/bitmap.h
LIB_H += util/include/linux/bitops.h
@@ -218,9 +223,7 @@ LIB_H += util/include/linux/ctype.h
LIB_H += util/include/linux/kernel.h
LIB_H += util/include/linux/list.h
LIB_H += util/include/linux/export.h
-LIB_H += util/include/linux/magic.h
LIB_H += util/include/linux/poison.h
-LIB_H += util/include/linux/prefetch.h
LIB_H += util/include/linux/rbtree.h
LIB_H += util/include/linux/rbtree_augmented.h
LIB_H += util/include/linux/string.h
@@ -244,7 +247,6 @@ LIB_H += util/cache.h
LIB_H += util/callchain.h
LIB_H += util/build-id.h
LIB_H += util/debug.h
-LIB_H += util/fs.h
LIB_H += util/pmu.h
LIB_H += util/event.h
LIB_H += util/evsel.h
@@ -306,7 +308,6 @@ LIB_OBJS += $(OUTPUT)util/annotate.o
LIB_OBJS += $(OUTPUT)util/build-id.o
LIB_OBJS += $(OUTPUT)util/config.o
LIB_OBJS += $(OUTPUT)util/ctype.o
-LIB_OBJS += $(OUTPUT)util/fs.o
LIB_OBJS += $(OUTPUT)util/pmu.o
LIB_OBJS += $(OUTPUT)util/environment.o
LIB_OBJS += $(OUTPUT)util/event.o
@@ -408,6 +409,11 @@ endif
LIB_OBJS += $(OUTPUT)tests/code-reading.o
LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
+ifndef NO_DWARF_UNWIND
+ifeq ($(ARCH),x86)
+LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o
+endif
+endif
BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -420,6 +426,9 @@ BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
endif
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
+BUILTIN_OBJS += $(OUTPUT)bench/futex-hash.o
+BUILTIN_OBJS += $(OUTPUT)bench/futex-wake.o
+BUILTIN_OBJS += $(OUTPUT)bench/futex-requeue.o
BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
@@ -475,8 +484,13 @@ ifndef NO_DWARF
endif # NO_DWARF
endif # NO_LIBELF
+ifndef NO_LIBDW_DWARF_UNWIND
+ LIB_OBJS += $(OUTPUT)util/unwind-libdw.o
+ LIB_H += util/unwind-libdw.h
+endif
+
ifndef NO_LIBUNWIND
- LIB_OBJS += $(OUTPUT)util/unwind.o
+ LIB_OBJS += $(OUTPUT)util/unwind-libunwind.o
endif
LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
@@ -533,6 +547,7 @@ ifeq ($(NO_PERF_REGS),0)
ifeq ($(ARCH),x86)
LIB_H += arch/x86/include/perf_regs.h
endif
+ LIB_OBJS += $(OUTPUT)util/perf_regs.o
endif
ifndef NO_LIBNUMA
@@ -655,6 +670,9 @@ $(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
-DPYTHON='"$(PYTHON_WORD)"' \
$<
+$(OUTPUT)tests/dwarf-unwind.o: tests/dwarf-unwind.c
+ $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -fno-optimize-sibling-calls $<
+
$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
@@ -707,9 +725,15 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
# we depend the various files onto their directories.
DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(GTK_OBJS)
DIRECTORY_DEPS += $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
-$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
+# no need to add flex objects, because they depend on bison ones
+DIRECTORY_DEPS += $(OUTPUT)util/parse-events-bison.c
+DIRECTORY_DEPS += $(OUTPUT)util/pmu-bison.c
+
+OUTPUT_DIRECTORIES := $(sort $(dir $(DIRECTORY_DEPS)))
+
+$(DIRECTORY_DEPS): | $(OUTPUT_DIRECTORIES)
# In the second step, we make a rule to actually create these directories
-$(sort $(dir $(DIRECTORY_DEPS))):
+$(OUTPUT_DIRECTORIES):
$(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
$(LIB_FILE): $(LIB_OBJS)
@@ -886,7 +910,7 @@ config-clean:
clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
$(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
- $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
+ $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
$(python-clean)
diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile
index fe9b61e322a5..67e9b3d38e89 100644
--- a/tools/perf/arch/arm/Makefile
+++ b/tools/perf/arch/arm/Makefile
@@ -3,5 +3,5 @@ PERF_HAVE_DWARF_REGS := 1
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
endif
ifndef NO_LIBUNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
endif
diff --git a/tools/perf/arch/arm/util/unwind.c b/tools/perf/arch/arm/util/unwind-libunwind.c
index da3dc950550c..729ed69a6664 100644
--- a/tools/perf/arch/arm/util/unwind.c
+++ b/tools/perf/arch/arm/util/unwind-libunwind.c
@@ -4,7 +4,7 @@
#include "perf_regs.h"
#include "../../util/unwind.h"
-int unwind__arch_reg_id(int regnum)
+int libunwind__arch_reg_id(int regnum)
{
switch (regnum) {
case UNW_ARM_R0:
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 8801fe02f206..1641542e3636 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -3,7 +3,14 @@ PERF_HAVE_DWARF_REGS := 1
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
endif
ifndef NO_LIBUNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
+endif
+ifndef NO_LIBDW_DWARF_UNWIND
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libdw.o
+endif
+ifndef NO_DWARF_UNWIND
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
endif
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
index e84ca76aae77..fc819ca34a7e 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -5,14 +5,20 @@
#include "../../util/types.h"
#include <asm/perf_regs.h>
+void perf_regs_load(u64 *regs);
+
#ifndef HAVE_ARCH_X86_64_SUPPORT
#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
+#define PERF_REGS_MAX PERF_REG_X86_32_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
#else
#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
(1ULL << PERF_REG_X86_ES) | \
(1ULL << PERF_REG_X86_FS) | \
(1ULL << PERF_REG_X86_GS))
#define PERF_REGS_MASK (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~REG_NOSUPPORT)
+#define PERF_REGS_MAX PERF_REG_X86_64_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
#endif
#define PERF_REG_IP PERF_REG_X86_IP
#define PERF_REG_SP PERF_REG_X86_SP
diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c
new file mode 100644
index 000000000000..b602ad93ce63
--- /dev/null
+++ b/tools/perf/arch/x86/tests/dwarf-unwind.c
@@ -0,0 +1,59 @@
+#include <string.h>
+#include "perf_regs.h"
+#include "thread.h"
+#include "map.h"
+#include "event.h"
+#include "tests/tests.h"
+
+#define STACK_SIZE 8192
+
+static int sample_ustack(struct perf_sample *sample,
+ struct thread *thread, u64 *regs)
+{
+ struct stack_dump *stack = &sample->user_stack;
+ struct map *map;
+ unsigned long sp;
+ u64 stack_size, *buf;
+
+ buf = malloc(STACK_SIZE);
+ if (!buf) {
+ pr_debug("failed to allocate sample uregs data\n");
+ return -1;
+ }
+
+ sp = (unsigned long) regs[PERF_REG_X86_SP];
+
+ map = map_groups__find(&thread->mg, MAP__FUNCTION, (u64) sp);
+ if (!map) {
+ pr_debug("failed to get stack map\n");
+ return -1;
+ }
+
+ stack_size = map->end - sp;
+ stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
+
+ memcpy(buf, (void *) sp, stack_size);
+ stack->data = (char *) buf;
+ stack->size = stack_size;
+ return 0;
+}
+
+int test__arch_unwind_sample(struct perf_sample *sample,
+ struct thread *thread)
+{
+ struct regs_dump *regs = &sample->user_regs;
+ u64 *buf;
+
+ buf = malloc(sizeof(u64) * PERF_REGS_MAX);
+ if (!buf) {
+ pr_debug("failed to allocate sample uregs data\n");
+ return -1;
+ }
+
+ perf_regs_load(buf);
+ regs->abi = PERF_SAMPLE_REGS_ABI;
+ regs->regs = buf;
+ regs->mask = PERF_REGS_MASK;
+
+ return sample_ustack(sample, thread, buf);
+}
diff --git a/tools/perf/arch/x86/tests/regs_load.S b/tools/perf/arch/x86/tests/regs_load.S
new file mode 100644
index 000000000000..99167bf644ea
--- /dev/null
+++ b/tools/perf/arch/x86/tests/regs_load.S
@@ -0,0 +1,92 @@
+
+#include <linux/linkage.h>
+
+#define AX 0
+#define BX 1 * 8
+#define CX 2 * 8
+#define DX 3 * 8
+#define SI 4 * 8
+#define DI 5 * 8
+#define BP 6 * 8
+#define SP 7 * 8
+#define IP 8 * 8
+#define FLAGS 9 * 8
+#define CS 10 * 8
+#define SS 11 * 8
+#define DS 12 * 8
+#define ES 13 * 8
+#define FS 14 * 8
+#define GS 15 * 8
+#define R8 16 * 8
+#define R9 17 * 8
+#define R10 18 * 8
+#define R11 19 * 8
+#define R12 20 * 8
+#define R13 21 * 8
+#define R14 22 * 8
+#define R15 23 * 8
+
+.text
+#ifdef HAVE_ARCH_X86_64_SUPPORT
+ENTRY(perf_regs_load)
+ movq %rax, AX(%rdi)
+ movq %rbx, BX(%rdi)
+ movq %rcx, CX(%rdi)
+ movq %rdx, DX(%rdi)
+ movq %rsi, SI(%rdi)
+ movq %rdi, DI(%rdi)
+ movq %rbp, BP(%rdi)
+
+ leaq 8(%rsp), %rax /* exclude this call. */
+ movq %rax, SP(%rdi)
+
+ movq 0(%rsp), %rax
+ movq %rax, IP(%rdi)
+
+ movq $0, FLAGS(%rdi)
+ movq $0, CS(%rdi)
+ movq $0, SS(%rdi)
+ movq $0, DS(%rdi)
+ movq $0, ES(%rdi)
+ movq $0, FS(%rdi)
+ movq $0, GS(%rdi)
+
+ movq %r8, R8(%rdi)
+ movq %r9, R9(%rdi)
+ movq %r10, R10(%rdi)
+ movq %r11, R11(%rdi)
+ movq %r12, R12(%rdi)
+ movq %r13, R13(%rdi)
+ movq %r14, R14(%rdi)
+ movq %r15, R15(%rdi)
+ ret
+ENDPROC(perf_regs_load)
+#else
+ENTRY(perf_regs_load)
+ push %edi
+ movl 8(%esp), %edi
+ movl %eax, AX(%edi)
+ movl %ebx, BX(%edi)
+ movl %ecx, CX(%edi)
+ movl %edx, DX(%edi)
+ movl %esi, SI(%edi)
+ pop %eax
+ movl %eax, DI(%edi)
+ movl %ebp, BP(%edi)
+
+ leal 4(%esp), %eax /* exclude this call. */
+ movl %eax, SP(%edi)
+
+ movl 0(%esp), %eax
+ movl %eax, IP(%edi)
+
+ movl $0, FLAGS(%edi)
+ movl $0, CS(%edi)
+ movl $0, SS(%edi)
+ movl $0, DS(%edi)
+ movl $0, ES(%edi)
+ movl $0, FS(%edi)
+ movl $0, GS(%edi)
+ ret
+ENDPROC(perf_regs_load)
+#endif
diff --git a/tools/perf/arch/x86/util/unwind-libdw.c b/tools/perf/arch/x86/util/unwind-libdw.c
new file mode 100644
index 000000000000..c4b72176ca83
--- /dev/null
+++ b/tools/perf/arch/x86/util/unwind-libdw.c
@@ -0,0 +1,51 @@
+#include <elfutils/libdwfl.h>
+#include "../../util/unwind-libdw.h"
+#include "../../util/perf_regs.h"
+
+bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+{
+ struct unwind_info *ui = arg;
+ struct regs_dump *user_regs = &ui->sample->user_regs;
+ Dwarf_Word dwarf_regs[17];
+ unsigned nregs;
+
+#define REG(r) ({ \
+ Dwarf_Word val = 0; \
+ perf_reg_value(&val, user_regs, PERF_REG_X86_##r); \
+ val; \
+})
+
+ if (user_regs->abi == PERF_SAMPLE_REGS_ABI_32) {
+ dwarf_regs[0] = REG(AX);
+ dwarf_regs[1] = REG(CX);
+ dwarf_regs[2] = REG(DX);
+ dwarf_regs[3] = REG(BX);
+ dwarf_regs[4] = REG(SP);
+ dwarf_regs[5] = REG(BP);
+ dwarf_regs[6] = REG(SI);
+ dwarf_regs[7] = REG(DI);
+ dwarf_regs[8] = REG(IP);
+ nregs = 9;
+ } else {
+ dwarf_regs[0] = REG(AX);
+ dwarf_regs[1] = REG(DX);
+ dwarf_regs[2] = REG(CX);
+ dwarf_regs[3] = REG(BX);
+ dwarf_regs[4] = REG(SI);
+ dwarf_regs[5] = REG(DI);
+ dwarf_regs[6] = REG(BP);
+ dwarf_regs[7] = REG(SP);
+ dwarf_regs[8] = REG(R8);
+ dwarf_regs[9] = REG(R9);
+ dwarf_regs[10] = REG(R10);
+ dwarf_regs[11] = REG(R11);
+ dwarf_regs[12] = REG(R12);
+ dwarf_regs[13] = REG(R13);
+ dwarf_regs[14] = REG(R14);
+ dwarf_regs[15] = REG(R15);
+ dwarf_regs[16] = REG(IP);
+ nregs = 17;
+ }
+
+ return dwfl_thread_state_registers(thread, 0, nregs, dwarf_regs);
+}
diff --git a/tools/perf/arch/x86/util/unwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c
index 456a88cf5b37..3261f68c6a7c 100644
--- a/tools/perf/arch/x86/util/unwind.c
+++ b/tools/perf/arch/x86/util/unwind-libunwind.c
@@ -5,7 +5,7 @@
#include "../../util/unwind.h"
#ifdef HAVE_ARCH_X86_64_SUPPORT
-int unwind__arch_reg_id(int regnum)
+int libunwind__arch_reg_id(int regnum)
{
int id;
@@ -69,7 +69,7 @@ int unwind__arch_reg_id(int regnum)
return id;
}
#else
-int unwind__arch_reg_id(int regnum)
+int libunwind__arch_reg_id(int regnum)
{
int id;
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index 0fdc85269c4d..eba46709b279 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -31,6 +31,9 @@ extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
extern int bench_mem_memcpy(int argc, const char **argv,
const char *prefix __maybe_unused);
extern int bench_mem_memset(int argc, const char **argv, const char *prefix);
+extern int bench_futex_hash(int argc, const char **argv, const char *prefix);
+extern int bench_futex_wake(int argc, const char **argv, const char *prefix);
+extern int bench_futex_requeue(int argc, const char **argv, const char *prefix);
#define BENCH_FORMAT_DEFAULT_STR "default"
#define BENCH_FORMAT_DEFAULT 0
diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c
new file mode 100644
index 000000000000..a84206e9c4aa
--- /dev/null
+++ b/tools/perf/bench/futex-hash.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2013 Davidlohr Bueso <davidlohr@hp.com>
+ *
+ * futex-hash: Stress the hell out of the Linux kernel futex uaddr hashing.
+ *
+ * This program is particularly useful for measuring the kernel's futex hash
+ * table/function implementation. In order for it to make sense, use with as
+ * many threads and futexes as possible.
+ */
+
+#include "../perf.h"
+#include "../util/util.h"
+#include "../util/stat.h"
+#include "../util/parse-options.h"
+#include "../util/header.h"
+#include "bench.h"
+#include "futex.h"
+
+#include <err.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+static unsigned int nthreads = 0;
+static unsigned int nsecs = 10;
+/* amount of futexes per thread */
+static unsigned int nfutexes = 1024;
+static bool fshared = false, done = false, silent = false;
+
+struct timeval start, end, runtime;
+static pthread_mutex_t thread_lock;
+static unsigned int threads_starting;
+static struct stats throughput_stats;
+static pthread_cond_t thread_parent, thread_worker;
+
+struct worker {
+ int tid;
+ u_int32_t *futex;
+ pthread_t thread;
+ unsigned long ops;
+};
+
+static const struct option options[] = {
+ OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
+ OPT_UINTEGER('r', "runtime", &nsecs, "Specify runtime (in seconds)"),
+ OPT_UINTEGER('f', "futexes", &nfutexes, "Specify amount of futexes per threads"),
+ OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"),
+ OPT_BOOLEAN( 'S', "shared", &fshared, "Use shared futexes instead of private ones"),
+ OPT_END()
+};
+
+static const char * const bench_futex_hash_usage[] = {
+ "perf bench futex hash <options>",
+ NULL
+};
+
+static void *workerfn(void *arg)
+{
+ int ret;
+ unsigned int i;
+ struct worker *w = (struct worker *) arg;
+
+ pthread_mutex_lock(&thread_lock);
+ threads_starting--;
+ if (!threads_starting)
+ pthread_cond_signal(&thread_parent);
+ pthread_cond_wait(&thread_worker, &thread_lock);
+ pthread_mutex_unlock(&thread_lock);
+
+ do {
+ for (i = 0; i < nfutexes; i++, w->ops++) {
+ /*
+ * We want the futex calls to fail in order to stress
+ * the hashing of uaddr and not measure other steps,
+ * such as internal waitqueue handling, thus enlarging
+ * the critical region protected by hb->lock.
+ */
+ ret = futex_wait(&w->futex[i], 1234, NULL,
+ fshared ? 0 : FUTEX_PRIVATE_FLAG);
+ if (!silent &&
+ (!ret || errno != EAGAIN || errno != EWOULDBLOCK))
+ warn("Non-expected futex return call");
+ }
+ } while (!done);
+
+ return NULL;
+}
+
+static void toggle_done(int sig __maybe_unused,
+ siginfo_t *info __maybe_unused,
+ void *uc __maybe_unused)
+{
+ /* inform all threads that we're done for the day */
+ done = true;
+ gettimeofday(&end, NULL);
+ timersub(&end, &start, &runtime);
+}
+
+static void print_summary(void)
+{
+ unsigned long avg = avg_stats(&throughput_stats);
+ double stddev = stddev_stats(&throughput_stats);
+
+ printf("%sAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n",
+ !silent ? "\n" : "", avg, rel_stddev_stats(stddev, avg),
+ (int) runtime.tv_sec);
+}
+
+int bench_futex_hash(int argc, const char **argv,
+ const char *prefix __maybe_unused)
+{
+ int ret = 0;
+ cpu_set_t cpu;
+ struct sigaction act;
+ unsigned int i, ncpus;
+ pthread_attr_t thread_attr;
+ struct worker *worker = NULL;
+
+ argc = parse_options(argc, argv, options, bench_futex_hash_usage, 0);
+ if (argc) {
+ usage_with_options(bench_futex_hash_usage, options);
+ exit(EXIT_FAILURE);
+ }
+
+ ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+ sigfillset(&act.sa_mask);
+ act.sa_sigaction = toggle_done;
+ sigaction(SIGINT, &act, NULL);
+
+ if (!nthreads) /* default to the number of CPUs */
+ nthreads = ncpus;
+
+ worker = calloc(nthreads, sizeof(*worker));
+ if (!worker)
+ goto errmem;
+
+ printf("Run summary [PID %d]: %d threads, each operating on %d [%s] futexes for %d secs.\n\n",
+ getpid(), nthreads, nfutexes, fshared ? "shared":"private", nsecs);
+
+ init_stats(&throughput_stats);
+ pthread_mutex_init(&thread_lock, NULL);
+ pthread_cond_init(&thread_parent, NULL);
+ pthread_cond_init(&thread_worker, NULL);
+
+ threads_starting = nthreads;
+ pthread_attr_init(&thread_attr);
+ gettimeofday(&start, NULL);
+ for (i = 0; i < nthreads; i++) {
+ worker[i].tid = i;
+ worker[i].futex = calloc(nfutexes, sizeof(*worker[i].futex));
+ if (!worker[i].futex)
+ goto errmem;
+
+ CPU_ZERO(&cpu);
+ CPU_SET(i % ncpus, &cpu);
+
+ ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpu);
+ if (ret)
+ err(EXIT_FAILURE, "pthread_attr_setaffinity_np");
+
+ ret = pthread_create(&worker[i].thread, &thread_attr, workerfn,
+ (void *)(struct worker *) &worker[i]);
+ if (ret)
+ err(EXIT_FAILURE, "pthread_create");
+
+ }
+ pthread_attr_destroy(&thread_attr);
+
+ pthread_mutex_lock(&thread_lock);
+ while (threads_starting)
+ pthread_cond_wait(&thread_parent, &thread_lock);
+ pthread_cond_broadcast(&thread_worker);
+ pthread_mutex_unlock(&thread_lock);
+
+ sleep(nsecs);
+ toggle_done(0, NULL, NULL);
+
+ for (i = 0; i < nthreads; i++) {
+ ret = pthread_join(worker[i].thread, NULL);
+ if (ret)
+ err(EXIT_FAILURE, "pthread_join");
+ }
+
+ /* cleanup & report results */
+ pthread_cond_destroy(&thread_parent);
+ pthread_cond_destroy(&thread_worker);
+ pthread_mutex_destroy(&thread_lock);
+
+ for (i = 0; i < nthreads; i++) {
+ unsigned long t = worker[i].ops/runtime.tv_sec;
+ update_stats(&throughput_stats, t);
+ if (!silent) {
+ if (nfutexes == 1)
+ printf("[thread %2d] futex: %p [ %ld ops/sec ]\n",
+ worker[i].tid, &worker[i].futex[0], t);
+ else
+ printf("[thread %2d] futexes: %p ... %p [ %ld ops/sec ]\n",
+ worker[i].tid, &worker[i].futex[0],
+ &worker[i].futex[nfutexes-1], t);
+ }
+
+ free(worker[i].futex);
+ }
+
+ print_summary();
+
+ free(worker);
+ return ret;
+errmem:
+ err(EXIT_FAILURE, "calloc");
+}
diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c
new file mode 100644
index 000000000000..a16255876f1d
--- /dev/null
+++ b/tools/perf/bench/futex-requeue.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2013 Davidlohr Bueso <davidlohr@hp.com>
+ *
+ * futex-requeue: Block a bunch of threads on futex1 and requeue them
+ * on futex2, N at a time.
+ *
+ * This program is particularly useful to measure the latency of nthread
+ * requeues without waking up any tasks -- thus mimicking a regular futex_wait.
+ */
+
+#include "../perf.h"
+#include "../util/util.h"
+#include "../util/stat.h"
+#include "../util/parse-options.h"
+#include "../util/header.h"
+#include "bench.h"
+#include "futex.h"
+
+#include <err.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+static u_int32_t futex1 = 0, futex2 = 0;
+
+/*
+ * How many tasks to requeue at a time.
+ * Default to 1 in order to make the kernel work more.
+ */
+static unsigned int nrequeue = 1;
+
+/*
+ * There can be significant variance from run to run,
+ * the more repeats, the more exact the overall avg and
+ * the better idea of the futex latency.
+ */
+static unsigned int repeat = 10;
+
+static pthread_t *worker;
+static bool done = 0, silent = 0;
+static pthread_mutex_t thread_lock;
+static pthread_cond_t thread_parent, thread_worker;
+static struct stats requeuetime_stats, requeued_stats;
+static unsigned int ncpus, threads_starting, nthreads = 0;
+
+static const struct option options[] = {
+ OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
+ OPT_UINTEGER('q', "nrequeue", &nrequeue, "Specify amount of threads to requeue at once"),
+ OPT_UINTEGER('r', "repeat", &repeat, "Specify amount of times to repeat the run"),
+ OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"),
+ OPT_END()
+};
+
+static const char * const bench_futex_requeue_usage[] = {
+ "perf bench futex requeue <options>",
+ NULL
+};
+
+static void print_summary(void)
+{
+ double requeuetime_avg = avg_stats(&requeuetime_stats);
+ double requeuetime_stddev = stddev_stats(&requeuetime_stats);
+ unsigned int requeued_avg = avg_stats(&requeued_stats);
+
+ printf("Requeued %d of %d threads in %.4f ms (+-%.2f%%)\n",
+ requeued_avg,
+ nthreads,
+ requeuetime_avg/1e3,
+ rel_stddev_stats(requeuetime_stddev, requeuetime_avg));
+}
+
+static void *workerfn(void *arg __maybe_unused)
+{
+ pthread_mutex_lock(&thread_lock);
+ threads_starting--;
+ if (!threads_starting)
+ pthread_cond_signal(&thread_parent);
+ pthread_cond_wait(&thread_worker, &thread_lock);
+ pthread_mutex_unlock(&thread_lock);
+
+ futex_wait(&futex1, 0, NULL, FUTEX_PRIVATE_FLAG);
+ return NULL;
+}
+
+static void block_threads(pthread_t *w,
+ pthread_attr_t thread_attr)
+{
+ cpu_set_t cpu;
+ unsigned int i;
+
+ threads_starting = nthreads;
+
+ /* create and block all threads */
+ for (i = 0; i < nthreads; i++) {
+ CPU_ZERO(&cpu);
+ CPU_SET(i % ncpus, &cpu);
+
+ if (pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpu))
+ err(EXIT_FAILURE, "pthread_attr_setaffinity_np");
+
+ if (pthread_create(&w[i], &thread_attr, workerfn, NULL))
+ err(EXIT_FAILURE, "pthread_create");
+ }
+}
+
+static void toggle_done(int sig __maybe_unused,
+ siginfo_t *info __maybe_unused,
+ void *uc __maybe_unused)
+{
+ done = true;
+}
+
+int bench_futex_requeue(int argc, const char **argv,
+ const char *prefix __maybe_unused)
+{
+ int ret = 0;
+ unsigned int i, j;
+ struct sigaction act;
+ pthread_attr_t thread_attr;
+
+ argc = parse_options(argc, argv, options, bench_futex_requeue_usage, 0);
+ if (argc)
+ goto err;
+
+ ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+ sigfillset(&act.sa_mask);
+ act.sa_sigaction = toggle_done;
+ sigaction(SIGINT, &act, NULL);
+
+ if (!nthreads)
+ nthreads = ncpus;
+
+ worker = calloc(nthreads, sizeof(*worker));
+ if (!worker)
+ err(EXIT_FAILURE, "calloc");
+
+ printf("Run summary [PID %d]: Requeuing %d threads (from %p to %p), "
+ "%d at a time.\n\n",
+ getpid(), nthreads, &futex1, &futex2, nrequeue);
+
+ init_stats(&requeued_stats);
+ init_stats(&requeuetime_stats);
+ pthread_attr_init(&thread_attr);
+ pthread_mutex_init(&thread_lock, NULL);
+ pthread_cond_init(&thread_parent, NULL);
+ pthread_cond_init(&thread_worker, NULL);
+
+ for (j = 0; j < repeat && !done; j++) {
+ unsigned int nrequeued = 0;
+ struct timeval start, end, runtime;
+
+ /* create, launch & block all threads */
+ block_threads(worker, thread_attr);
+
+ /* make sure all threads are already blocked */
+ pthread_mutex_lock(&thread_lock);
+ while (threads_starting)
+ pthread_cond_wait(&thread_parent, &thread_lock);
+ pthread_cond_broadcast(&thread_worker);
+ pthread_mutex_unlock(&thread_lock);
+
+ usleep(100000);
+
+ /* Ok, all threads are patiently blocked, start requeueing */
+ gettimeofday(&start, NULL);
+ for (nrequeued = 0; nrequeued < nthreads; nrequeued += nrequeue)
+ /*
+ * Do not wakeup any tasks blocked on futex1, allowing
+ * us to really measure futex_wait functionality.
+ */
+ futex_cmp_requeue(&futex1, 0, &futex2, 0, nrequeue,
+ FUTEX_PRIVATE_FLAG);
+ gettimeofday(&end, NULL);
+ timersub(&end, &start, &runtime);
+
+ update_stats(&requeued_stats, nrequeued);
+ update_stats(&requeuetime_stats, runtime.tv_usec);
+
+ if (!silent) {
+ printf("[Run %d]: Requeued %d of %d threads in %.4f ms\n",
+ j + 1, nrequeued, nthreads, runtime.tv_usec/1e3);
+ }
+
+ /* everybody should be blocked on futex2, wake'em up */
+ nrequeued = futex_wake(&futex2, nthreads, FUTEX_PRIVATE_FLAG);
+ if (nthreads != nrequeued)
+ warnx("couldn't wakeup all tasks (%d/%d)", nrequeued, nthreads);
+
+ for (i = 0; i < nthreads; i++) {
+ ret = pthread_join(worker[i], NULL);
+ if (ret)
+ err(EXIT_FAILURE, "pthread_join");
+ }
+
+ }
+
+ /* cleanup & report results */
+ pthread_cond_destroy(&thread_parent);
+ pthread_cond_destroy(&thread_worker);
+ pthread_mutex_destroy(&thread_lock);
+ pthread_attr_destroy(&thread_attr);
+
+ print_summary();
+
+ free(worker);
+ return ret;
+err:
+ usage_with_options(bench_futex_requeue_usage, options);
+ exit(EXIT_FAILURE);
+}
diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c
new file mode 100644
index 000000000000..d096169b161e
--- /dev/null
+++ b/tools/perf/bench/futex-wake.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2013 Davidlohr Bueso <davidlohr@hp.com>
+ *
+ * futex-wake: Block a bunch of threads on a futex and wake'em up, N at a time.
+ *
+ * This program is particularly useful to measure the latency of nthread wakeups
+ * in non-error situations: all waiters are queued and all wake calls wakeup
+ * one or more tasks, and thus the waitqueue is never empty.
+ */
+
+#include "../perf.h"
+#include "../util/util.h"
+#include "../util/stat.h"
+#include "../util/parse-options.h"
+#include "../util/header.h"
+#include "bench.h"
+#include "futex.h"
+
+#include <err.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+/* all threads will block on the same futex */
+static u_int32_t futex1 = 0;
+
+/*
+ * How many wakeups to do at a time.
+ * Default to 1 in order to make the kernel work more.
+ */
+static unsigned int nwakes = 1;
+
+/*
+ * There can be significant variance from run to run,
+ * the more repeats, the more exact the overall avg and
+ * the better idea of the futex latency.
+ */
+static unsigned int repeat = 10;
+
+pthread_t *worker;
+static bool done = 0, silent = 0;
+static pthread_mutex_t thread_lock;
+static pthread_cond_t thread_parent, thread_worker;
+static struct stats waketime_stats, wakeup_stats;
+static unsigned int ncpus, threads_starting, nthreads = 0;
+
+static const struct option options[] = {
+ OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
+ OPT_UINTEGER('w', "nwakes", &nwakes, "Specify amount of threads to wake at once"),
+ OPT_UINTEGER('r', "repeat", &repeat, "Specify amount of times to repeat the run"),
+ OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"),
+ OPT_END()
+};
+
+static const char * const bench_futex_wake_usage[] = {
+ "perf bench futex wake <options>",
+ NULL
+};
+
+static void *workerfn(void *arg __maybe_unused)
+{
+ pthread_mutex_lock(&thread_lock);
+ threads_starting--;
+ if (!threads_starting)
+ pthread_cond_signal(&thread_parent);
+ pthread_cond_wait(&thread_worker, &thread_lock);
+ pthread_mutex_unlock(&thread_lock);
+
+ futex_wait(&futex1, 0, NULL, FUTEX_PRIVATE_FLAG);
+ return NULL;
+}
+
+static void print_summary(void)
+{
+ double waketime_avg = avg_stats(&waketime_stats);
+ double waketime_stddev = stddev_stats(&waketime_stats);
+ unsigned int wakeup_avg = avg_stats(&wakeup_stats);
+
+ printf("Wokeup %d of %d threads in %.4f ms (+-%.2f%%)\n",
+ wakeup_avg,
+ nthreads,
+ waketime_avg/1e3,
+ rel_stddev_stats(waketime_stddev, waketime_avg));
+}
+
+static void block_threads(pthread_t *w,
+ pthread_attr_t thread_attr)
+{
+ cpu_set_t cpu;
+ unsigned int i;
+
+ threads_starting = nthreads;
+
+ /* create and block all threads */
+ for (i = 0; i < nthreads; i++) {
+ CPU_ZERO(&cpu);
+ CPU_SET(i % ncpus, &cpu);
+
+ if (pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpu))
+ err(EXIT_FAILURE, "pthread_attr_setaffinity_np");
+
+ if (pthread_create(&w[i], &thread_attr, workerfn, NULL))
+ err(EXIT_FAILURE, "pthread_create");
+ }
+}
+
+static void toggle_done(int sig __maybe_unused,
+ siginfo_t *info __maybe_unused,
+ void *uc __maybe_unused)
+{
+ done = true;
+}
+
+int bench_futex_wake(int argc, const char **argv,
+ const char *prefix __maybe_unused)
+{
+ int ret = 0;
+ unsigned int i, j;
+ struct sigaction act;
+ pthread_attr_t thread_attr;
+
+ argc = parse_options(argc, argv, options, bench_futex_wake_usage, 0);
+ if (argc) {
+ usage_with_options(bench_futex_wake_usage, options);
+ exit(EXIT_FAILURE);
+ }
+
+ ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+ sigfillset(&act.sa_mask);
+ act.sa_sigaction = toggle_done;
+ sigaction(SIGINT, &act, NULL);
+
+ if (!nthreads)
+ nthreads = ncpus;
+
+ worker = calloc(nthreads, sizeof(*worker));
+ if (!worker)
+ err(EXIT_FAILURE, "calloc");
+
+ printf("Run summary [PID %d]: blocking on %d threads (at futex %p), "
+ "waking up %d at a time.\n\n",
+ getpid(), nthreads, &futex1, nwakes);
+
+ init_stats(&wakeup_stats);
+ init_stats(&waketime_stats);
+ pthread_attr_init(&thread_attr);
+ pthread_mutex_init(&thread_lock, NULL);
+ pthread_cond_init(&thread_parent, NULL);
+ pthread_cond_init(&thread_worker, NULL);
+
+ for (j = 0; j < repeat && !done; j++) {
+ unsigned int nwoken = 0;
+ struct timeval start, end, runtime;
+
+ /* create, launch & block all threads */
+ block_threads(worker, thread_attr);
+
+ /* make sure all threads are already blocked */
+ pthread_mutex_lock(&thread_lock);
+ while (threads_starting)
+ pthread_cond_wait(&thread_parent, &thread_lock);
+ pthread_cond_broadcast(&thread_worker);
+ pthread_mutex_unlock(&thread_lock);
+
+ usleep(100000);
+
+ /* Ok, all threads are patiently blocked, start waking folks up */
+ gettimeofday(&start, NULL);
+ while (nwoken != nthreads)
+ nwoken += futex_wake(&futex1, nwakes, FUTEX_PRIVATE_FLAG);
+ gettimeofday(&end, NULL);
+ timersub(&end, &start, &runtime);
+
+ update_stats(&wakeup_stats, nwoken);
+ update_stats(&waketime_stats, runtime.tv_usec);
+
+ if (!silent) {
+ printf("[Run %d]: Wokeup %d of %d threads in %.4f ms\n",
+ j + 1, nwoken, nthreads, runtime.tv_usec/1e3);
+ }
+
+ for (i = 0; i < nthreads; i++) {
+ ret = pthread_join(worker[i], NULL);
+ if (ret)
+ err(EXIT_FAILURE, "pthread_join");
+ }
+
+ }
+
+ /* cleanup & report results */
+ pthread_cond_destroy(&thread_parent);
+ pthread_cond_destroy(&thread_worker);
+ pthread_mutex_destroy(&thread_lock);
+ pthread_attr_destroy(&thread_attr);
+
+ print_summary();
+
+ free(worker);
+ return ret;
+}
diff --git a/tools/perf/bench/futex.h b/tools/perf/bench/futex.h
new file mode 100644
index 000000000000..71f2844cf97f
--- /dev/null
+++ b/tools/perf/bench/futex.h
@@ -0,0 +1,71 @@
+/*
+ * Glibc independent futex library for testing kernel functionality.
+ * Shamelessly stolen from Darren Hart <dvhltc@us.ibm.com>
+ * http://git.kernel.org/cgit/linux/kernel/git/dvhart/futextest.git/
+ */
+
+#ifndef _FUTEX_H
+#define _FUTEX_H
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <linux/futex.h>
+
+/**
+ * futex() - SYS_futex syscall wrapper
+ * @uaddr: address of first futex
+ * @op: futex op code
+ * @val: typically expected value of uaddr, but varies by op
+ * @timeout: typically an absolute struct timespec (except where noted
+ * otherwise). Overloaded by some ops
+ * @uaddr2: address of second futex for some ops\
+ * @val3: varies by op
+ * @opflags: flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG
+ *
+ * futex() is used by all the following futex op wrappers. It can also be
+ * used for misuse and abuse testing. Generally, the specific op wrappers
+ * should be used instead. It is a macro instead of an static inline function as
+ * some of the types over overloaded (timeout is used for nr_requeue for
+ * example).
+ *
+ * These argument descriptions are the defaults for all
+ * like-named arguments in the following wrappers except where noted below.
+ */
+#define futex(uaddr, op, val, timeout, uaddr2, val3, opflags) \
+ syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3)
+
+/**
+ * futex_wait() - block on uaddr with optional timeout
+ * @timeout: relative timeout
+ */
+static inline int
+futex_wait(u_int32_t *uaddr, u_int32_t val, struct timespec *timeout, int opflags)
+{
+ return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
+}
+
+/**
+ * futex_wake() - wake one or more tasks blocked on uaddr
+ * @nr_wake: wake up to this many tasks
+ */
+static inline int
+futex_wake(u_int32_t *uaddr, int nr_wake, int opflags)
+{
+ return futex(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags);
+}
+
+/**
+* futex_cmp_requeue() - requeue tasks from uaddr to uaddr2
+* @nr_wake: wake up to this many tasks
+* @nr_requeue: requeue up to this many tasks
+*/
+static inline int
+futex_cmp_requeue(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2, int nr_wake,
+ int nr_requeue, int opflags)
+{
+ return futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2,
+ val, opflags);
+}
+
+#endif /* _FUTEX_H */
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
index d4c83c60b9b2..97d86d828190 100644
--- a/tools/perf/bench/numa.c
+++ b/tools/perf/bench/numa.c
@@ -1593,6 +1593,7 @@ static void init_params(struct params *p, const char *name, int argc, const char
p->data_rand_walk = true;
p->nr_loops = -1;
p->init_random = true;
+ p->run_all = argc == 1;
}
static int run_bench_numa(const char *name, const char **argv)
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index e47f90cc7b98..1e6e77710545 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -12,6 +12,7 @@
* sched ... scheduler and IPC performance
* mem ... memory access performance
* numa ... NUMA scheduling and MM performance
+ * futex ... Futex performance
*/
#include "perf.h"
#include "util/util.h"
@@ -54,6 +55,14 @@ static struct bench mem_benchmarks[] = {
{ NULL, NULL, NULL }
};
+static struct bench futex_benchmarks[] = {
+ { "hash", "Benchmark for futex hash table", bench_futex_hash },
+ { "wake", "Benchmark for futex wake calls", bench_futex_wake },
+ { "requeue", "Benchmark for futex requeue calls", bench_futex_requeue },
+ { "all", "Test all futex benchmarks", NULL },
+ { NULL, NULL, NULL }
+};
+
struct collection {
const char *name;
const char *summary;
@@ -61,11 +70,12 @@ struct collection {
};
static struct collection collections[] = {
- { "sched", "Scheduler and IPC benchmarks", sched_benchmarks },
+ { "sched", "Scheduler and IPC benchmarks", sched_benchmarks },
{ "mem", "Memory access benchmarks", mem_benchmarks },
#ifdef HAVE_LIBNUMA_SUPPORT
{ "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks },
#endif
+ {"futex", "Futex stressing benchmarks", futex_benchmarks },
{ "all", "All benchmarks", NULL },
{ NULL, NULL, NULL }
};
@@ -76,7 +86,7 @@ static struct collection collections[] = {
/* Iterate over all benchmarks within a collection: */
#define for_each_bench(coll, bench) \
- for (bench = coll->benchmarks; bench->name; bench++)
+ for (bench = coll->benchmarks; bench && bench->name; bench++)
static void dump_benchmarks(struct collection *coll)
{
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index a77e31246c00..204fffe22532 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -952,8 +952,8 @@ static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
dfmt->header_width, buf);
}
-static int hpp__header(struct perf_hpp_fmt *fmt,
- struct perf_hpp *hpp)
+static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+ struct perf_evsel *evsel __maybe_unused)
{
struct diff_hpp_fmt *dfmt =
container_of(fmt, struct diff_hpp_fmt, fmt);
@@ -963,7 +963,8 @@ static int hpp__header(struct perf_hpp_fmt *fmt,
}
static int hpp__width(struct perf_hpp_fmt *fmt,
- struct perf_hpp *hpp __maybe_unused)
+ struct perf_hpp *hpp __maybe_unused,
+ struct perf_evsel *evsel __maybe_unused)
{
struct diff_hpp_fmt *dfmt =
container_of(fmt, struct diff_hpp_fmt, fmt);
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index b3466018bbd7..3a7387551369 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -312,7 +312,6 @@ found:
sample_sw.period = sample->period;
sample_sw.time = sample->time;
perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
- evsel->attr.sample_regs_user,
evsel->attr.read_format, &sample_sw,
false);
build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index a7350519c63f..21c164b8f9db 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1691,17 +1691,15 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_END()
};
-
- const char * const kvm_usage[] = {
- "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}",
- NULL
- };
+ const char *const kvm_subcommands[] = { "top", "record", "report", "diff",
+ "buildid-list", "stat", NULL };
+ const char *kvm_usage[] = { NULL, NULL };
perf_host = 0;
perf_guest = 1;
- argc = parse_options(argc, argv, kvm_options, kvm_usage,
- PARSE_OPT_STOP_AT_NON_OPTION);
+ argc = parse_options_subcommand(argc, argv, kvm_options, kvm_subcommands, kvm_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc)
usage_with_options(kvm_usage, kvm_options);
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 78948882e3de..cdcd4eb3a57d 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -268,9 +268,9 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
return 0;
}
-static void init_params(void)
+static int init_params(void)
{
- line_range__init(&params.line_range);
+ return line_range__init(&params.line_range);
}
static void cleanup_params(void)
@@ -515,9 +515,11 @@ int cmd_probe(int argc, const char **argv, const char *prefix)
{
int ret;
- init_params();
- ret = __cmd_probe(argc, argv, prefix);
- cleanup_params();
+ ret = init_params();
+ if (!ret) {
+ ret = __cmd_probe(argc, argv, prefix);
+ cleanup_params();
+ }
return ret;
}
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index af47531b82ec..eb524f91bffe 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -649,7 +649,7 @@ error:
return ret;
}
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
static int get_stack_size(char *str, unsigned long *_size)
{
char *endptr;
@@ -675,7 +675,7 @@ static int get_stack_size(char *str, unsigned long *_size)
max_size, str);
return -1;
}
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
int record_parse_callchain(const char *arg, struct record_opts *opts)
{
@@ -704,7 +704,7 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
"needed for -g fp\n");
break;
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
/* Dwarf style */
} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
const unsigned long default_stack_dump_size = 8192;
@@ -720,7 +720,7 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
ret = get_stack_size(tok, &size);
opts->stack_dump_size = size;
}
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
} else {
pr_err("callchain: Unknown --call-graph option "
"value: %s\n", arg);
@@ -735,7 +735,9 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
static void callchain_debug(struct record_opts *opts)
{
- pr_debug("callchain: type %d\n", opts->call_graph);
+ static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
+
+ pr_debug("callchain: type %s\n", str[opts->call_graph]);
if (opts->call_graph == CALLCHAIN_DWARF)
pr_debug("callchain: stack dump size %d\n",
@@ -749,6 +751,8 @@ int record_parse_callchain_opt(const struct option *opt,
struct record_opts *opts = opt->value;
int ret;
+ opts->call_graph_enabled = !unset;
+
/* --no-call-graph */
if (unset) {
opts->call_graph = CALLCHAIN_NONE;
@@ -769,6 +773,8 @@ int record_callchain_opt(const struct option *opt,
{
struct record_opts *opts = opt->value;
+ opts->call_graph_enabled = !unset;
+
if (opts->call_graph == CALLCHAIN_NONE)
opts->call_graph = CALLCHAIN_FP;
@@ -776,6 +782,16 @@ int record_callchain_opt(const struct option *opt,
return 0;
}
+static int perf_record_config(const char *var, const char *value, void *cb)
+{
+ struct record *rec = cb;
+
+ if (!strcmp(var, "record.call-graph"))
+ return record_parse_callchain(value, &rec->opts);
+
+ return perf_default_config(var, value, cb);
+}
+
static const char * const record_usage[] = {
"perf record [<options>] [<command>]",
"perf record [<options>] -- <command> [<options>]",
@@ -807,7 +823,7 @@ static struct record record = {
#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
#else
const char record_callchain_help[] = CALLCHAIN_HELP "fp";
@@ -907,6 +923,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
if (rec->evlist == NULL)
return -ENOMEM;
+ perf_config(perf_record_config, rec);
+
argc = parse_options(argc, argv, record_options, record_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc && target__none(&rec->opts.target))
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 3c53ec268fbc..c8f21137dfd8 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -75,13 +75,10 @@ static int report__config(const char *var, const char *value, void *cb)
return perf_default_config(var, value, cb);
}
-static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_location *al,
- struct perf_sample *sample, struct perf_evsel *evsel,
- union perf_event *event)
+static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al,
+ struct perf_sample *sample, struct perf_evsel *evsel)
{
- struct report *rep = container_of(tool, struct report, tool);
struct symbol *parent = NULL;
- u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
struct hist_entry *he;
struct mem_info *mi, *mx;
uint64_t cost;
@@ -90,7 +87,7 @@ static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_locati
if (err)
return err;
- mi = machine__resolve_mem(al->machine, al->thread, sample, cpumode);
+ mi = sample__resolve_mem(sample, al);
if (!mi)
return -ENOMEM;
@@ -113,14 +110,16 @@ static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_locati
if (!he)
return -ENOMEM;
- err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
- if (err)
- goto out;
+ if (ui__has_annotation()) {
+ err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+ if (err)
+ goto out;
- mx = he->mem_info;
- err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
- if (err)
- goto out;
+ mx = he->mem_info;
+ err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
+ if (err)
+ goto out;
+ }
evsel->hists.stats.total_period += cost;
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
@@ -129,10 +128,9 @@ out:
return err;
}
-static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_location *al,
+static int report__add_branch_hist_entry(struct report *rep, struct addr_location *al,
struct perf_sample *sample, struct perf_evsel *evsel)
{
- struct report *rep = container_of(tool, struct report, tool);
struct symbol *parent = NULL;
unsigned i;
struct hist_entry *he;
@@ -142,8 +140,7 @@ static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_loc
if (err)
return err;
- bi = machine__resolve_bstack(al->machine, al->thread,
- sample->branch_stack);
+ bi = sample__resolve_bstack(sample, al);
if (!bi)
return -ENOMEM;
@@ -164,14 +161,18 @@ static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_loc
he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
1, 1, 0);
if (he) {
- bx = he->branch_info;
- err = addr_map_symbol__inc_samples(&bx->from, evsel->idx);
- if (err)
- goto out;
-
- err = addr_map_symbol__inc_samples(&bx->to, evsel->idx);
- if (err)
- goto out;
+ if (ui__has_annotation()) {
+ bx = he->branch_info;
+ err = addr_map_symbol__inc_samples(&bx->from,
+ evsel->idx);
+ if (err)
+ goto out;
+
+ err = addr_map_symbol__inc_samples(&bx->to,
+ evsel->idx);
+ if (err)
+ goto out;
+ }
evsel->hists.stats.total_period += 1;
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
@@ -184,10 +185,9 @@ out:
return err;
}
-static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evsel,
+static int report__add_hist_entry(struct report *rep, struct perf_evsel *evsel,
struct addr_location *al, struct perf_sample *sample)
{
- struct report *rep = container_of(tool, struct report, tool);
struct symbol *parent = NULL;
struct hist_entry *he;
int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
@@ -205,7 +205,9 @@ static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evs
if (err)
goto out;
- err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+ if (ui__has_annotation())
+ err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+
evsel->hists.stats.total_period += sample->period;
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
out:
@@ -229,25 +231,25 @@ static int process_sample_event(struct perf_tool *tool,
return -1;
}
- if (al.filtered || (rep->hide_unresolved && al.sym == NULL))
+ if (rep->hide_unresolved && al.sym == NULL)
return 0;
if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
return 0;
if (sort__mode == SORT_MODE__BRANCH) {
- ret = report__add_branch_hist_entry(tool, &al, sample, evsel);
+ ret = report__add_branch_hist_entry(rep, &al, sample, evsel);
if (ret < 0)
pr_debug("problem adding lbr entry, skipping event\n");
} else if (rep->mem_mode == 1) {
- ret = report__add_mem_hist_entry(tool, &al, sample, evsel, event);
+ ret = report__add_mem_hist_entry(rep, &al, sample, evsel);
if (ret < 0)
pr_debug("problem adding mem entry, skipping event\n");
} else {
if (al.map != NULL)
al.map->dso->hit = 1;
- ret = report__add_hist_entry(tool, evsel, &al, sample);
+ ret = report__add_hist_entry(rep, evsel, &al, sample);
if (ret < 0)
pr_debug("problem incrementing symbol period, skipping event\n");
}
@@ -926,7 +928,7 @@ repeat:
* so don't allocate extra space that won't be used in the stdio
* implementation.
*/
- if (use_browser == 1 && sort__has_sym) {
+ if (ui__has_annotation()) {
symbol_conf.priv_size = sizeof(struct annotation);
machines__set_symbol_filter(&session->machines,
symbol__annotate_init);
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 6a76a07b6789..9ac0a495c954 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1124,7 +1124,7 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
avg = work_list->total_lat / work_list->nb_atoms;
- printf("|%11.3f ms |%9" PRIu64 " | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n",
+ printf("|%11.3f ms |%9" PRIu64 " | avg:%9.3f ms | max:%9.3f ms | max at: %13.6f s\n",
(double)work_list->total_runtime / 1e6,
work_list->nb_atoms, (double)avg / 1e6,
(double)work_list->max_lat / 1e6,
@@ -1527,9 +1527,9 @@ static int perf_sched__lat(struct perf_sched *sched)
perf_sched__sort_lat(sched);
- printf("\n ---------------------------------------------------------------------------------------------------------------\n");
- printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n");
- printf(" ---------------------------------------------------------------------------------------------------------------\n");
+ printf("\n -----------------------------------------------------------------------------------------------------------------\n");
+ printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n");
+ printf(" -----------------------------------------------------------------------------------------------------------------\n");
next = rb_first(&sched->sorted_atom_root);
@@ -1541,7 +1541,7 @@ static int perf_sched__lat(struct perf_sched *sched)
next = rb_next(next);
}
- printf(" -----------------------------------------------------------------------------------------\n");
+ printf(" -----------------------------------------------------------------------------------------------------------------\n");
printf(" TOTAL: |%11.3f ms |%9" PRIu64 " |\n",
(double)sched->all_runtime / 1e6, sched->all_count);
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 25526d6eae59..74db2568b867 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -494,7 +494,7 @@ static const char *cat_backtrace(union perf_event *event,
continue;
}
- tal.filtered = false;
+ tal.filtered = 0;
thread__find_addr_location(al.thread, machine, cpumode,
MAP__FUNCTION, ip, &tal);
@@ -1238,7 +1238,7 @@ static int timechart__record(struct timechart *tchart, int argc, const char **ar
for (i = 0; i < old_power_args_nr; i++)
*p++ = strdup(old_power_args[i]);
- for (j = 1; j < (unsigned int)argc; j++)
+ for (j = 0; j < (unsigned int)argc; j++)
*p++ = argv[j];
return cmd_record(rec_argc, rec_argv, NULL);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 76cd510d34d0..65aaa5bbf7ec 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -176,7 +176,7 @@ static void perf_top__record_precise_ip(struct perf_top *top,
{
struct annotation *notes;
struct symbol *sym;
- int err;
+ int err = 0;
if (he == NULL || he->ms.sym == NULL ||
((top->sym_filter_entry == NULL ||
@@ -190,7 +190,9 @@ static void perf_top__record_precise_ip(struct perf_top *top,
return;
ip = he->ms.map->map_ip(he->ms.map, ip);
- err = hist_entry__inc_addr_samples(he, counter, ip);
+
+ if (ui__has_annotation())
+ err = hist_entry__inc_addr_samples(he, counter, ip);
pthread_mutex_unlock(&notes->lock);
@@ -991,6 +993,16 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
return record_parse_callchain_opt(opt, arg, unset);
}
+static int perf_top_config(const char *var, const char *value, void *cb)
+{
+ struct perf_top *top = cb;
+
+ if (!strcmp(var, "top.call-graph"))
+ return record_parse_callchain(value, &top->record_opts);
+
+ return perf_default_config(var, value, cb);
+}
+
static int
parse_percent_limit(const struct option *opt, const char *arg,
int unset __maybe_unused)
@@ -1115,6 +1127,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
if (top.evlist == NULL)
return -ENOMEM;
+ perf_config(perf_top_config, &top);
+
argc = parse_options(argc, argv, options, top_usage, 0);
if (argc)
usage_with_options(top_usage, options);
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 896f27047ed6..f954c26de231 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -37,6 +37,10 @@
# define MADV_UNMERGEABLE 13
#endif
+#ifndef EFD_SEMAPHORE
+# define EFD_SEMAPHORE 1
+#endif
+
struct tp_field {
int offset;
union {
@@ -279,6 +283,11 @@ static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
#define SCA_STRARRAY syscall_arg__scnprintf_strarray
+#if defined(__i386__) || defined(__x86_64__)
+/*
+ * FIXME: Make this available to all arches as soon as the ioctl beautifier
+ * gets rewritten to support all arches.
+ */
static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
struct syscall_arg *arg)
{
@@ -286,6 +295,7 @@ static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
}
#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
+#endif /* defined(__i386__) || defined(__x86_64__) */
static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
struct syscall_arg *arg);
@@ -815,7 +825,6 @@ static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscal
P_SIGNUM(PIPE);
P_SIGNUM(ALRM);
P_SIGNUM(TERM);
- P_SIGNUM(STKFLT);
P_SIGNUM(CHLD);
P_SIGNUM(CONT);
P_SIGNUM(STOP);
@@ -831,6 +840,15 @@ static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscal
P_SIGNUM(IO);
P_SIGNUM(PWR);
P_SIGNUM(SYS);
+#ifdef SIGEMT
+ P_SIGNUM(EMT);
+#endif
+#ifdef SIGSTKFLT
+ P_SIGNUM(STKFLT);
+#endif
+#ifdef SIGSWI
+ P_SIGNUM(SWI);
+#endif
default: break;
}
@@ -839,6 +857,10 @@ static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscal
#define SCA_SIGNUM syscall_arg__scnprintf_signum
+#if defined(__i386__) || defined(__x86_64__)
+/*
+ * FIXME: Make this available to all arches.
+ */
#define TCGETS 0x5401
static const char *tioctls[] = {
@@ -860,6 +882,7 @@ static const char *tioctls[] = {
};
static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
+#endif /* defined(__i386__) || defined(__x86_64__) */
#define STRARRAY(arg, name, array) \
.arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
@@ -941,9 +964,16 @@ static struct syscall_fmt {
{ .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
{ .name = "ioctl", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */
+#if defined(__i386__) || defined(__x86_64__)
+/*
+ * FIXME: Make this available to all arches.
+ */
[1] = SCA_STRHEXARRAY, /* cmd */
[2] = SCA_HEX, /* arg */ },
.arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
+#else
+ [2] = SCA_HEX, /* arg */ }, },
+#endif
{ .name = "kill", .errmsg = true,
.arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
{ .name = "linkat", .errmsg = true,
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index c48d44958172..c23418225c2c 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -59,6 +59,18 @@ ifeq ($(NO_PERF_REGS),0)
CFLAGS += -DHAVE_PERF_REGS_SUPPORT
endif
+ifndef NO_LIBELF
+ # for linking with debug library, run like:
+ # make DEBUG=1 LIBDW_DIR=/opt/libdw/
+ ifdef LIBDW_DIR
+ LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
+ LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
+
+ FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
+ FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw
+ endif
+endif
+
# include ARCH specific config
-include $(src-perf)/arch/$(ARCH)/Makefile
@@ -147,7 +159,35 @@ CORE_FEATURE_TESTS = \
libunwind \
on-exit \
stackprotector-all \
- timerfd
+ timerfd \
+ libdw-dwarf-unwind
+
+LIB_FEATURE_TESTS = \
+ dwarf \
+ glibc \
+ gtk2 \
+ libaudit \
+ libbfd \
+ libelf \
+ libnuma \
+ libperl \
+ libpython \
+ libslang \
+ libunwind \
+ libdw-dwarf-unwind
+
+VF_FEATURE_TESTS = \
+ backtrace \
+ fortify-source \
+ gtk2-infobar \
+ libelf-getphdrnum \
+ libelf-mmap \
+ libpython-version \
+ on-exit \
+ stackprotector-all \
+ timerfd \
+ libunwind-debug-frame \
+ bionic
# Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
# If in the future we need per-feature checks/flags for features not
@@ -161,17 +201,6 @@ endef
$(foreach feat,$(CORE_FEATURE_TESTS),$(call set_test_all_flags,$(feat)))
#
-# So here we detect whether test-all was rebuilt, to be able
-# to skip the print-out of the long features list if the file
-# existed before and after it was built:
-#
-ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all.bin),)
- test-all-failed := 1
-else
- test-all-failed := 0
-endif
-
-#
# Special fast-path for the 'all features are available' case:
#
$(call feature_check,all,$(MSG))
@@ -180,15 +209,6 @@ $(call feature_check,all,$(MSG))
# Just in case the build freshly failed, make sure we print the
# feature matrix:
#
-ifeq ($(feature-all), 0)
- test-all-failed := 1
-endif
-
-ifeq ($(test-all-failed),1)
- $(info )
- $(info Auto-detecting system features:)
-endif
-
ifeq ($(feature-all), 1)
#
# test-all.c passed - just set all the core feature flags to 1:
@@ -199,27 +219,6 @@ else
$(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat)))
endif
-#
-# Print the result of the feature test:
-#
-feature_print = $(eval $(feature_print_code)) $(info $(MSG))
-
-define feature_print_code
- ifeq ($(feature-$(1)), 1)
- MSG = $(shell printf '...%30s: [ \033[32mon\033[m ]' $(1))
- else
- MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(1))
- endif
-endef
-
-#
-# Only print out our features if we rebuilt the testcases or if a test failed:
-#
-ifeq ($(test-all-failed), 1)
- $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_print,$(feat)))
- $(info )
-endif
-
ifeq ($(feature-stackprotector-all), 1)
CFLAGS += -fstack-protector-all
endif
@@ -264,6 +263,7 @@ ifdef NO_LIBELF
NO_DWARF := 1
NO_DEMANGLE := 1
NO_LIBUNWIND := 1
+ NO_LIBDW_DWARF_UNWIND := 1
else
ifeq ($(feature-libelf), 0)
ifeq ($(feature-glibc), 1)
@@ -282,13 +282,12 @@ else
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
endif
else
- # for linking with debug library, run like:
- # make DEBUG=1 LIBDW_DIR=/opt/libdw/
- ifdef LIBDW_DIR
- LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
- LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
+ ifndef NO_LIBDW_DWARF_UNWIND
+ ifneq ($(feature-libdw-dwarf-unwind),1)
+ NO_LIBDW_DWARF_UNWIND := 1
+ msg := $(warning No libdw DWARF unwind found, Please install elfutils-devel/libdw-dev >= 0.158 and/or set LIBDW_DIR);
+ endif
endif
-
ifneq ($(feature-dwarf), 1)
msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
NO_DWARF := 1
@@ -324,25 +323,51 @@ endif # NO_LIBELF
ifndef NO_LIBUNWIND
ifneq ($(feature-libunwind), 1)
- msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1);
+ msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
NO_LIBUNWIND := 1
+ endif
+endif
+
+dwarf-post-unwind := 1
+dwarf-post-unwind-text := BUG
+
+# setup DWARF post unwinder
+ifdef NO_LIBUNWIND
+ ifdef NO_LIBDW_DWARF_UNWIND
+ msg := $(warning Disabling post unwind, no support found.);
+ dwarf-post-unwind := 0
else
- ifeq ($(ARCH),arm)
- $(call feature_check,libunwind-debug-frame)
- ifneq ($(feature-libunwind-debug-frame), 1)
- msg := $(warning No debug_frame support found in libunwind);
- CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
- endif
- else
- # non-ARM has no dwarf_find_debug_frame() function:
+ dwarf-post-unwind-text := libdw
+ endif
+else
+ dwarf-post-unwind-text := libunwind
+ # Enable libunwind support by default.
+ ifndef NO_LIBDW_DWARF_UNWIND
+ NO_LIBDW_DWARF_UNWIND := 1
+ endif
+endif
+
+ifeq ($(dwarf-post-unwind),1)
+ CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT
+else
+ NO_DWARF_UNWIND := 1
+endif
+
+ifndef NO_LIBUNWIND
+ ifeq ($(ARCH),arm)
+ $(call feature_check,libunwind-debug-frame)
+ ifneq ($(feature-libunwind-debug-frame), 1)
+ msg := $(warning No debug_frame support found in libunwind);
CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
endif
-
- CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
- EXTLIBS += $(LIBUNWIND_LIBS)
- CFLAGS += $(LIBUNWIND_CFLAGS)
- LDFLAGS += $(LIBUNWIND_LDFLAGS)
- endif # ifneq ($(feature-libunwind), 1)
+ else
+ # non-ARM has no dwarf_find_debug_frame() function:
+ CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
+ endif
+ CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
+ EXTLIBS += $(LIBUNWIND_LIBS)
+ CFLAGS += $(LIBUNWIND_CFLAGS)
+ LDFLAGS += $(LIBUNWIND_LDFLAGS)
endif
ifndef NO_LIBAUDIT
@@ -478,7 +503,7 @@ else
endif
ifeq ($(feature-libbfd), 1)
- EXTLIBS += -lbfd
+ EXTLIBS += -lbfd -lz -liberty
endif
ifdef NO_DEMANGLE
@@ -602,3 +627,84 @@ ifdef DESTDIR
plugindir=$(libdir)/traceevent/plugins
plugindir_SQ= $(subst ','\'',$(plugindir))
endif
+
+#
+# Print the result of the feature test:
+#
+feature_print_status = $(eval $(feature_print_status_code)) $(info $(MSG))
+
+define feature_print_status_code
+ ifeq ($(feature-$(1)), 1)
+ MSG = $(shell printf '...%30s: [ \033[32mon\033[m ]' $(1))
+ else
+ MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(1))
+ endif
+endef
+
+feature_print_var = $(eval $(feature_print_var_code)) $(info $(MSG))
+define feature_print_var_code
+ MSG = $(shell printf '...%30s: %s' $(1) $($(1)))
+endef
+
+feature_print_text = $(eval $(feature_print_text_code)) $(info $(MSG))
+define feature_print_text_code
+ MSG = $(shell printf '...%30s: %s' $(1) $(2))
+endef
+
+PERF_FEATURES := $(foreach feat,$(LIB_FEATURE_TESTS),feature-$(feat)($(feature-$(feat))))
+PERF_FEATURES_FILE := $(shell touch $(OUTPUT)PERF-FEATURES; cat $(OUTPUT)PERF-FEATURES)
+
+ifeq ($(dwarf-post-unwind),1)
+ PERF_FEATURES += dwarf-post-unwind($(dwarf-post-unwind-text))
+endif
+
+# The $(display_lib) controls the default detection message
+# output. It's set if:
+# - detected features differes from stored features from
+# last build (in PERF-FEATURES file)
+# - one of the $(LIB_FEATURE_TESTS) is not detected
+# - VF is enabled
+
+ifneq ("$(PERF_FEATURES)","$(PERF_FEATURES_FILE)")
+ $(shell echo "$(PERF_FEATURES)" > $(OUTPUT)PERF-FEATURES)
+ display_lib := 1
+endif
+
+feature_check = $(eval $(feature_check_code))
+define feature_check_code
+ ifneq ($(feature-$(1)), 1)
+ display_lib := 1
+ endif
+endef
+
+$(foreach feat,$(LIB_FEATURE_TESTS),$(call feature_check,$(feat)))
+
+ifeq ($(VF),1)
+ display_lib := 1
+ display_vf := 1
+endif
+
+ifeq ($(display_lib),1)
+ $(info )
+ $(info Auto-detecting system features:)
+ $(foreach feat,$(LIB_FEATURE_TESTS),$(call feature_print_status,$(feat),))
+
+ ifeq ($(dwarf-post-unwind),1)
+ $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
+ endif
+endif
+
+ifeq ($(display_vf),1)
+ $(foreach feat,$(VF_FEATURE_TESTS),$(call feature_print_status,$(feat),))
+ $(info )
+ $(call feature_print_var,prefix)
+ $(call feature_print_var,bindir)
+ $(call feature_print_var,libdir)
+ $(call feature_print_var,sysconfdir)
+ $(call feature_print_var,LIBUNWIND_DIR)
+ $(call feature_print_var,LIBDW_DIR)
+endif
+
+ifeq ($(display_lib),1)
+ $(info )
+endif
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 12e551346fa6..2da103c53f89 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -26,7 +26,8 @@ FILES= \
test-libunwind-debug-frame.bin \
test-on-exit.bin \
test-stackprotector-all.bin \
- test-timerfd.bin
+ test-timerfd.bin \
+ test-libdw-dwarf-unwind.bin
CC := $(CROSS_COMPILE)gcc -MD
PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -121,7 +122,7 @@ test-libpython-version.bin:
$(BUILD) $(FLAGS_PYTHON_EMBED)
test-libbfd.bin:
- $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
+ $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
test-liberty.bin:
$(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty
@@ -141,6 +142,9 @@ test-backtrace.bin:
test-timerfd.bin:
$(BUILD)
+test-libdw-dwarf-unwind.bin:
+ $(BUILD)
+
-include *.d
###############################
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index 9b8a544155bb..fc37eb3ca17b 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -89,6 +89,10 @@
# include "test-stackprotector-all.c"
#undef main
+#define main main_test_libdw_dwarf_unwind
+# include "test-libdw-dwarf-unwind.c"
+#undef main
+
int main(int argc, char *argv[])
{
main_test_libpython();
@@ -111,6 +115,7 @@ int main(int argc, char *argv[])
main_test_libnuma();
main_test_timerfd();
main_test_stackprotector_all();
+ main_test_libdw_dwarf_unwind();
return 0;
}
diff --git a/tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c b/tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
new file mode 100644
index 000000000000..f676a3ff442a
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-libdw-dwarf-unwind.c
@@ -0,0 +1,13 @@
+
+#include <elfutils/libdwfl.h>
+
+int main(void)
+{
+ /*
+ * This function is guarded via: __nonnull_attribute__ (1, 2).
+ * Passing '1' as arguments value. This code is never executed,
+ * only compiled.
+ */
+ dwfl_thread_getframes((void *) 1, (void *) 1, NULL);
+ return 0;
+}
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index 63a0e6f04a01..a28dca2582aa 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -18,7 +18,7 @@ underlying hardware counters.
Performance counters are accessed via special file descriptors.
There's one file descriptor per virtual counter used.
-The special file descriptor is opened via the perf_event_open()
+The special file descriptor is opened via the sys_perf_event_open()
system call:
int sys_perf_event_open(struct perf_event_attr *hw_event_uptr,
@@ -82,7 +82,7 @@ machine-specific.
If 'raw_type' is 0, then the 'type' field says what kind of counter
this is, with the following encoding:
-enum perf_event_types {
+enum perf_type_id {
PERF_TYPE_HARDWARE = 0,
PERF_TYPE_SOFTWARE = 1,
PERF_TYPE_TRACEPOINT = 2,
@@ -95,7 +95,7 @@ specified by 'event_id':
* Generalized performance counter event types, used by the hw_event.event_id
* parameter of the sys_perf_event_open() syscall:
*/
-enum hw_event_ids {
+enum perf_hw_id {
/*
* Common hardware events, generalized by the kernel:
*/
@@ -129,7 +129,7 @@ software events, selected by 'event_id':
* physical and sw events of the kernel (and allow the profiling of them as
* well):
*/
-enum sw_event_ids {
+enum perf_sw_ids {
PERF_COUNT_SW_CPU_CLOCK = 0,
PERF_COUNT_SW_TASK_CLOCK = 1,
PERF_COUNT_SW_PAGE_FAULTS = 2,
@@ -230,7 +230,7 @@ these events are recorded in the ring-buffer (see below).
The 'comm' bit allows tracking of process comm data on process creation.
This too is recorded in the ring-buffer (see below).
-The 'pid' parameter to the perf_event_open() system call allows the
+The 'pid' parameter to the sys_perf_event_open() system call allows the
counter to be specific to a task:
pid == 0: if the pid parameter is zero, the counter is attached to the
@@ -260,7 +260,7 @@ The 'flags' parameter is currently unused and must be zero.
The 'group_fd' parameter allows counter "groups" to be set up. A
counter group has one counter which is the group "leader". The leader
-is created first, with group_fd = -1 in the perf_event_open call
+is created first, with group_fd = -1 in the sys_perf_event_open call
that creates it. The rest of the group members are created
subsequently, with group_fd giving the fd of the group leader.
(A single counter on its own is created with group_fd = -1 and is
diff --git a/tools/perf/perf-completion.sh b/tools/perf/perf-completion.sh
index 496e2abb5482..ae3a57694b6b 100644
--- a/tools/perf/perf-completion.sh
+++ b/tools/perf/perf-completion.sh
@@ -123,7 +123,7 @@ __perf_main ()
__perfcomp_colon "$evts" "$cur"
# List subcommands for 'perf kvm'
elif [[ $prev == "kvm" ]]; then
- subcmds="top record report diff buildid-list stat"
+ subcmds=$($cmd $prev --list-cmds)
__perfcomp_colon "$subcmds" "$cur"
# List long option names
elif [[ $cur == --* ]]; then
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index e84fa26bc1be..e18a8b5e6953 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -12,6 +12,9 @@
#ifndef __NR_perf_event_open
# define __NR_perf_event_open 336
#endif
+#ifndef __NR_futex
+# define __NR_futex 240
+#endif
#endif
#if defined(__x86_64__)
@@ -23,6 +26,9 @@
#ifndef __NR_perf_event_open
# define __NR_perf_event_open 298
#endif
+#ifndef __NR_futex
+# define __NR_futex 202
+#endif
#endif
#ifdef __powerpc__
@@ -251,12 +257,14 @@ void pthread__unblock_sigwinch(void);
enum perf_call_graph_mode {
CALLCHAIN_NONE,
CALLCHAIN_FP,
- CALLCHAIN_DWARF
+ CALLCHAIN_DWARF,
+ CALLCHAIN_MAX
};
struct record_opts {
struct target target;
int call_graph;
+ bool call_graph_enabled;
bool group;
bool inherit_stat;
bool no_buffering;
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 1e67437fb4ca..b11bf8a08430 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -115,6 +115,14 @@ static struct test {
.desc = "Test parsing with no sample_id_all bit set",
.func = test__parse_no_sample_id_all,
},
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
+ {
+ .desc = "Test dwarf unwind",
+ .func = test__dwarf_unwind,
+ },
+#endif
+#endif
{
.func = NULL,
},
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
new file mode 100644
index 000000000000..c059ee81c038
--- /dev/null
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -0,0 +1,144 @@
+#include <linux/compiler.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "tests.h"
+#include "debug.h"
+#include "machine.h"
+#include "event.h"
+#include "unwind.h"
+#include "perf_regs.h"
+#include "map.h"
+#include "thread.h"
+
+static int mmap_handler(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine)
+{
+ return machine__process_mmap_event(machine, event, NULL);
+}
+
+static int init_live_machine(struct machine *machine)
+{
+ union perf_event event;
+ pid_t pid = getpid();
+
+ return perf_event__synthesize_mmap_events(NULL, &event, pid, pid,
+ mmap_handler, machine, true);
+}
+
+#define MAX_STACK 6
+
+static int unwind_entry(struct unwind_entry *entry, void *arg)
+{
+ unsigned long *cnt = (unsigned long *) arg;
+ char *symbol = entry->sym ? entry->sym->name : NULL;
+ static const char *funcs[MAX_STACK] = {
+ "test__arch_unwind_sample",
+ "unwind_thread",
+ "krava_3",
+ "krava_2",
+ "krava_1",
+ "test__dwarf_unwind"
+ };
+
+ if (*cnt >= MAX_STACK) {
+ pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
+ return -1;
+ }
+
+ if (!symbol) {
+ pr_debug("failed: got unresolved address 0x%" PRIx64 "\n",
+ entry->ip);
+ return -1;
+ }
+
+ pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip);
+ return strcmp((const char *) symbol, funcs[(*cnt)++]);
+}
+
+__attribute__ ((noinline))
+static int unwind_thread(struct thread *thread, struct machine *machine)
+{
+ struct perf_sample sample;
+ unsigned long cnt = 0;
+ int err = -1;
+
+ memset(&sample, 0, sizeof(sample));
+
+ if (test__arch_unwind_sample(&sample, thread)) {
+ pr_debug("failed to get unwind sample\n");
+ goto out;
+ }
+
+ err = unwind__get_entries(unwind_entry, &cnt, machine, thread,
+ &sample, MAX_STACK);
+ if (err)
+ pr_debug("unwind failed\n");
+ else if (cnt != MAX_STACK) {
+ pr_debug("got wrong number of stack entries %lu != %d\n",
+ cnt, MAX_STACK);
+ err = -1;
+ }
+
+ out:
+ free(sample.user_stack.data);
+ free(sample.user_regs.regs);
+ return err;
+}
+
+__attribute__ ((noinline))
+static int krava_3(struct thread *thread, struct machine *machine)
+{
+ return unwind_thread(thread, machine);
+}
+
+__attribute__ ((noinline))
+static int krava_2(struct thread *thread, struct machine *machine)
+{
+ return krava_3(thread, machine);
+}
+
+__attribute__ ((noinline))
+static int krava_1(struct thread *thread, struct machine *machine)
+{
+ return krava_2(thread, machine);
+}
+
+int test__dwarf_unwind(void)
+{
+ struct machines machines;
+ struct machine *machine;
+ struct thread *thread;
+ int err = -1;
+
+ machines__init(&machines);
+
+ machine = machines__find(&machines, HOST_KERNEL_ID);
+ if (!machine) {
+ pr_err("Could not get machine\n");
+ return -1;
+ }
+
+ if (init_live_machine(machine)) {
+ pr_err("Could not init machine\n");
+ goto out;
+ }
+
+ if (verbose > 1)
+ machine__fprintf(machine, stderr);
+
+ thread = machine__find_thread(machine, getpid(), getpid());
+ if (!thread) {
+ pr_err("Could not get thread\n");
+ goto out;
+ }
+
+ err = krava_1(thread, machine);
+
+ out:
+ machine__delete_threads(machine);
+ machine__exit(machine);
+ machines__exit(&machines);
+ return err;
+}
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 2b6519e0e36f..7ccbc7b6ae77 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -101,6 +101,7 @@ static struct machine *setup_fake_machine(struct machines *machines)
.mmap = {
.header = { .misc = PERF_RECORD_MISC_USER, },
.pid = fake_mmap_info[i].pid,
+ .tid = fake_mmap_info[i].pid,
.start = fake_mmap_info[i].start,
.len = 0x1000ULL,
.pgoff = 0ULL,
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 00544b8b644b..5daeae1cb4c0 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -27,6 +27,7 @@ make_no_ui := NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
make_no_demangle := NO_DEMANGLE=1
make_no_libelf := NO_LIBELF=1
make_no_libunwind := NO_LIBUNWIND=1
+make_no_libdw_dwarf_unwind := NO_LIBDW_DWARF_UNWIND=1
make_no_backtrace := NO_BACKTRACE=1
make_no_libnuma := NO_LIBNUMA=1
make_no_libaudit := NO_LIBAUDIT=1
@@ -35,8 +36,9 @@ make_tags := tags
make_cscope := cscope
make_help := help
make_doc := doc
-make_perf_o := perf.o
-make_util_map_o := util/map.o
+make_perf_o := perf.o
+make_util_map_o := util/map.o
+make_util_pmu_bison_o := util/pmu-bison.o
make_install := install
make_install_bin := install-bin
make_install_doc := install-doc
@@ -49,6 +51,7 @@ make_install_pdf := install-pdf
make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
+make_minimal += NO_LIBDW_DWARF_UNWIND=1
# $(run) contains all available tests
run := make_pure
@@ -65,6 +68,7 @@ run += make_no_ui
run += make_no_demangle
run += make_no_libelf
run += make_no_libunwind
+run += make_no_libdw_dwarf_unwind
run += make_no_backtrace
run += make_no_libnuma
run += make_no_libaudit
@@ -73,6 +77,7 @@ run += make_help
run += make_doc
run += make_perf_o
run += make_util_map_o
+run += make_util_pmu_bison_o
run += make_install
run += make_install_bin
# FIXME 'install-*' commented out till they're fixed
@@ -113,8 +118,9 @@ test_make_doc_O := $(test_ok)
test_make_python_perf_so := test -f $(PERF)/python/perf.so
-test_make_perf_o := test -f $(PERF)/perf.o
-test_make_util_map_o := test -f $(PERF)/util/map.o
+test_make_perf_o := test -f $(PERF)/perf.o
+test_make_util_map_o := test -f $(PERF)/util/map.o
+test_make_util_pmu_bison_o := test -f $(PERF)/util/pmu-bison.o
define test_dest_files
for file in $(1); do \
@@ -167,13 +173,10 @@ test_make_install_info_O := $(test_ok)
test_make_install_pdf := $(test_ok)
test_make_install_pdf_O := $(test_ok)
-# Kbuild tests only
-#test_make_python_perf_so_O := test -f $$TMP/tools/perf/python/perf.so
-#test_make_perf_o_O := test -f $$TMP/tools/perf/perf.o
-#test_make_util_map_o_O := test -f $$TMP/tools/perf/util/map.o
-
-test_make_perf_o_O := true
-test_make_util_map_o_O := true
+test_make_python_perf_so_O := test -f $$TMP_O/python/perf.so
+test_make_perf_o_O := test -f $$TMP_O/perf.o
+test_make_util_map_o_O := test -f $$TMP_O/util/map.o
+test_make_util_pmu_bison_o_O := test -f $$TMP_O/util/pmu-bison.o
test_default = test -x $(PERF)/perf
test = $(if $(test_$1),$(test_$1),$(test_default))
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 4db0ae617d70..8605ff5572ae 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -2,7 +2,7 @@
#include "parse-events.h"
#include "evsel.h"
#include "evlist.h"
-#include "fs.h"
+#include <api/fs/fs.h>
#include <api/fs/debugfs.h>
#include "tests.h"
#include <linux/hw_breakpoint.h>
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 1b677202638d..0014d3c8c21c 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -22,8 +22,8 @@
} while (0)
static bool samples_same(const struct perf_sample *s1,
- const struct perf_sample *s2, u64 type, u64 regs_user,
- u64 read_format)
+ const struct perf_sample *s2,
+ u64 type, u64 read_format)
{
size_t i;
@@ -95,8 +95,9 @@ static bool samples_same(const struct perf_sample *s1,
}
if (type & PERF_SAMPLE_REGS_USER) {
- size_t sz = hweight_long(regs_user) * sizeof(u64);
+ size_t sz = hweight_long(s1->user_regs.mask) * sizeof(u64);
+ COMP(user_regs.mask);
COMP(user_regs.abi);
if (s1->user_regs.abi &&
(!s1->user_regs.regs || !s2->user_regs.regs ||
@@ -174,6 +175,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
.branch_stack = &branch_stack.branch_stack,
.user_regs = {
.abi = PERF_SAMPLE_REGS_ABI_64,
+ .mask = sample_regs_user,
.regs = user_regs,
},
.user_stack = {
@@ -201,8 +203,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
sample.read.one.id = 99;
}
- sz = perf_event__sample_event_size(&sample, sample_type,
- sample_regs_user, read_format);
+ sz = perf_event__sample_event_size(&sample, sample_type, read_format);
bufsz = sz + 4096; /* Add a bit for overrun checking */
event = malloc(bufsz);
if (!event) {
@@ -215,8 +216,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
event->header.misc = 0;
event->header.size = sz;
- err = perf_event__synthesize_sample(event, sample_type,
- sample_regs_user, read_format,
+ err = perf_event__synthesize_sample(event, sample_type, read_format,
&sample, false);
if (err) {
pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
@@ -244,8 +244,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
goto out_free;
}
- if (!samples_same(&sample, &sample_out, sample_type,
- sample_regs_user, read_format)) {
+ if (!samples_same(&sample, &sample_out, sample_type, read_format)) {
pr_debug("parsing failed for sample_type %#"PRIx64"\n",
sample_type);
goto out_free;
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index e0ac713857ba..a24795ca002d 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -40,5 +40,14 @@ int test__code_reading(void);
int test__sample_parsing(void);
int test__keep_tracking(void);
int test__parse_no_sample_id_all(void);
+int test__dwarf_unwind(void);
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
+struct thread;
+struct perf_sample;
+int test__arch_unwind_sample(struct perf_sample *sample,
+ struct thread *thread);
+#endif
+#endif
#endif /* TESTS_H */
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index b720b92eba6e..7ec871af3f6f 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -587,95 +587,52 @@ struct hpp_arg {
bool current_entry;
};
-static int __hpp__color_callchain(struct hpp_arg *arg)
+static int __hpp__overhead_callback(struct perf_hpp *hpp, bool front)
{
- if (!symbol_conf.use_callchain)
- return 0;
-
- slsmg_printf("%c ", arg->folded_sign);
- return 2;
-}
-
-static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
- u64 (*get_field)(struct hist_entry *),
- int (*callchain_cb)(struct hpp_arg *))
-{
- int ret = 0;
- double percent = 0.0;
- struct hists *hists = he->hists;
struct hpp_arg *arg = hpp->ptr;
- if (hists->stats.total_period)
- percent = 100.0 * get_field(he) / hists->stats.total_period;
-
- ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
-
- if (callchain_cb)
- ret += callchain_cb(arg);
-
- ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
- slsmg_printf("%s", hpp->buf);
-
- if (symbol_conf.event_group) {
- int prev_idx, idx_delta;
- struct perf_evsel *evsel = hists_to_evsel(hists);
- struct hist_entry *pair;
- int nr_members = evsel->nr_members;
-
- if (nr_members <= 1)
- goto out;
+ if (arg->current_entry && arg->b->navkeypressed)
+ ui_browser__set_color(arg->b, HE_COLORSET_SELECTED);
+ else
+ ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
- prev_idx = perf_evsel__group_idx(evsel);
+ if (front) {
+ if (!symbol_conf.use_callchain)
+ return 0;
- list_for_each_entry(pair, &he->pairs.head, pairs.node) {
- u64 period = get_field(pair);
- u64 total = pair->hists->stats.total_period;
+ slsmg_printf("%c ", arg->folded_sign);
+ return 2;
+ }
- if (!total)
- continue;
+ return 0;
+}
- evsel = hists_to_evsel(pair->hists);
- idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
+static int __hpp__color_callback(struct perf_hpp *hpp, bool front __maybe_unused)
+{
+ struct hpp_arg *arg = hpp->ptr;
- while (idx_delta--) {
- /*
- * zero-fill group members in the middle which
- * have no sample
- */
- ui_browser__set_percent_color(arg->b, 0.0,
- arg->current_entry);
- ret += scnprintf(hpp->buf, hpp->size,
- " %6.2f%%", 0.0);
- slsmg_printf("%s", hpp->buf);
- }
+ if (!arg->current_entry || !arg->b->navkeypressed)
+ ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
+ return 0;
+}
- percent = 100.0 * period / total;
- ui_browser__set_percent_color(arg->b, percent,
- arg->current_entry);
- ret += scnprintf(hpp->buf, hpp->size,
- " %6.2f%%", percent);
- slsmg_printf("%s", hpp->buf);
+static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
+{
+ struct hpp_arg *arg = hpp->ptr;
+ int ret;
+ va_list args;
+ double percent;
- prev_idx = perf_evsel__group_idx(evsel);
- }
+ va_start(args, fmt);
+ percent = va_arg(args, double);
+ va_end(args);
- idx_delta = nr_members - prev_idx - 1;
+ ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
- while (idx_delta--) {
- /*
- * zero-fill group members at last which have no sample
- */
- ui_browser__set_percent_color(arg->b, 0.0,
- arg->current_entry);
- ret += scnprintf(hpp->buf, hpp->size,
- " %6.2f%%", 0.0);
- slsmg_printf("%s", hpp->buf);
- }
- }
-out:
- if (!arg->current_entry || !arg->b->navkeypressed)
- ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
+ ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
+ slsmg_printf("%s", hpp->buf);
+ advance_hpp(hpp, ret);
return ret;
}
@@ -690,14 +647,15 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
struct perf_hpp *hpp, \
struct hist_entry *he) \
{ \
- return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \
+ return __hpp__fmt(hpp, he, __hpp_get_##_field, _cb, " %6.2f%%", \
+ __hpp__slsmg_color_printf, true); \
}
-__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain)
-__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL)
-__HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL)
-__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL)
-__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
+__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__overhead_callback)
+__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, __hpp__color_callback)
+__HPP_COLOR_PERCENT_FN(overhead_us, period_us, __hpp__color_callback)
+__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, __hpp__color_callback)
+__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, __hpp__color_callback)
#undef __HPP_COLOR_PERCENT_FN
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 5b95c44f3435..e395ef9b0ae0 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -8,16 +8,24 @@
#define MAX_COLUMNS 32
-static int __percent_color_snprintf(char *buf, size_t size, double percent)
+static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
{
int ret = 0;
+ va_list args;
+ double percent;
const char *markup;
+ char *buf = hpp->buf;
+ size_t size = hpp->size;
+
+ va_start(args, fmt);
+ percent = va_arg(args, double);
+ va_end(args);
markup = perf_gtk__get_percent_color(percent);
if (markup)
ret += scnprintf(buf, size, markup);
- ret += scnprintf(buf + ret, size - ret, " %6.2f%%", percent);
+ ret += scnprintf(buf + ret, size - ret, fmt, percent);
if (markup)
ret += scnprintf(buf + ret, size - ret, "</span>");
@@ -25,66 +33,6 @@ static int __percent_color_snprintf(char *buf, size_t size, double percent)
return ret;
}
-
-static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
- u64 (*get_field)(struct hist_entry *))
-{
- int ret;
- double percent = 0.0;
- struct hists *hists = he->hists;
- struct perf_evsel *evsel = hists_to_evsel(hists);
-
- if (hists->stats.total_period)
- percent = 100.0 * get_field(he) / hists->stats.total_period;
-
- ret = __percent_color_snprintf(hpp->buf, hpp->size, percent);
-
- if (perf_evsel__is_group_event(evsel)) {
- int prev_idx, idx_delta;
- struct hist_entry *pair;
- int nr_members = evsel->nr_members;
-
- prev_idx = perf_evsel__group_idx(evsel);
-
- list_for_each_entry(pair, &he->pairs.head, pairs.node) {
- u64 period = get_field(pair);
- u64 total = pair->hists->stats.total_period;
-
- evsel = hists_to_evsel(pair->hists);
- idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
-
- while (idx_delta--) {
- /*
- * zero-fill group members in the middle which
- * have no sample
- */
- ret += __percent_color_snprintf(hpp->buf + ret,
- hpp->size - ret,
- 0.0);
- }
-
- percent = 100.0 * period / total;
- ret += __percent_color_snprintf(hpp->buf + ret,
- hpp->size - ret,
- percent);
-
- prev_idx = perf_evsel__group_idx(evsel);
- }
-
- idx_delta = nr_members - prev_idx - 1;
-
- while (idx_delta--) {
- /*
- * zero-fill group members at last which have no sample
- */
- ret += __percent_color_snprintf(hpp->buf + ret,
- hpp->size - ret,
- 0.0);
- }
- }
- return ret;
-}
-
#define __HPP_COLOR_PERCENT_FN(_type, _field) \
static u64 he_get_##_field(struct hist_entry *he) \
{ \
@@ -95,7 +43,8 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,
struct perf_hpp *hpp, \
struct hist_entry *he) \
{ \
- return __hpp__color_fmt(hpp, he, he_get_##_field); \
+ return __hpp__fmt(hpp, he, he_get_##_field, NULL, " %6.2f%%", \
+ __percent_color_snprintf, true); \
}
__HPP_COLOR_PERCENT_FN(overhead, period)
@@ -216,7 +165,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
struct perf_hpp hpp = {
.buf = s,
.size = sizeof(s),
- .ptr = hists_to_evsel(hists),
};
nr_cols = 0;
@@ -243,7 +191,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx = 0;
perf_hpp__for_each_format(fmt) {
- fmt->header(fmt, &hpp);
+ fmt->header(fmt, &hpp, hists_to_evsel(hists));
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-1, ltrim(s),
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 78f4c92e9b73..0f403b83e9d1 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -8,16 +8,27 @@
/* hist period print (hpp) functions */
-typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...);
-
-static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
- u64 (*get_field)(struct hist_entry *),
- const char *fmt, hpp_snprint_fn print_fn,
- bool fmt_percent)
+#define hpp__call_print_fn(hpp, fn, fmt, ...) \
+({ \
+ int __ret = fn(hpp, fmt, ##__VA_ARGS__); \
+ advance_hpp(hpp, __ret); \
+ __ret; \
+})
+
+int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
+ hpp_field_fn get_field, hpp_callback_fn callback,
+ const char *fmt, hpp_snprint_fn print_fn, bool fmt_percent)
{
- int ret;
+ int ret = 0;
struct hists *hists = he->hists;
struct perf_evsel *evsel = hists_to_evsel(hists);
+ char *buf = hpp->buf;
+ size_t size = hpp->size;
+
+ if (callback) {
+ ret = callback(hpp, true);
+ advance_hpp(hpp, ret);
+ }
if (fmt_percent) {
double percent = 0.0;
@@ -26,9 +37,9 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
percent = 100.0 * get_field(he) /
hists->stats.total_period;
- ret = print_fn(hpp->buf, hpp->size, fmt, percent);
+ ret += hpp__call_print_fn(hpp, print_fn, fmt, percent);
} else
- ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
+ ret += hpp__call_print_fn(hpp, print_fn, fmt, get_field(he));
if (perf_evsel__is_group_event(evsel)) {
int prev_idx, idx_delta;
@@ -52,16 +63,22 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
* zero-fill group members in the middle which
* have no sample
*/
- ret += print_fn(hpp->buf + ret, hpp->size - ret,
- fmt, 0);
+ if (fmt_percent) {
+ ret += hpp__call_print_fn(hpp, print_fn,
+ fmt, 0.0);
+ } else {
+ ret += hpp__call_print_fn(hpp, print_fn,
+ fmt, 0ULL);
+ }
}
- if (fmt_percent)
- ret += print_fn(hpp->buf + ret, hpp->size - ret,
- fmt, 100.0 * period / total);
- else
- ret += print_fn(hpp->buf + ret, hpp->size - ret,
- fmt, period);
+ if (fmt_percent) {
+ ret += hpp__call_print_fn(hpp, print_fn, fmt,
+ 100.0 * period / total);
+ } else {
+ ret += hpp__call_print_fn(hpp, print_fn, fmt,
+ period);
+ }
prev_idx = perf_evsel__group_idx(evsel);
}
@@ -72,41 +89,87 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
/*
* zero-fill group members at last which have no sample
*/
- ret += print_fn(hpp->buf + ret, hpp->size - ret,
- fmt, 0);
+ if (fmt_percent) {
+ ret += hpp__call_print_fn(hpp, print_fn,
+ fmt, 0.0);
+ } else {
+ ret += hpp__call_print_fn(hpp, print_fn,
+ fmt, 0ULL);
+ }
}
}
+
+ if (callback) {
+ int __ret = callback(hpp, false);
+
+ advance_hpp(hpp, __ret);
+ ret += __ret;
+ }
+
+ /*
+ * Restore original buf and size as it's where caller expects
+ * the result will be saved.
+ */
+ hpp->buf = buf;
+ hpp->size = size;
+
return ret;
}
#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
- struct perf_hpp *hpp) \
+ struct perf_hpp *hpp, \
+ struct perf_evsel *evsel) \
{ \
int len = _min_width; \
\
- if (symbol_conf.event_group) { \
- struct perf_evsel *evsel = hpp->ptr; \
- \
+ if (symbol_conf.event_group) \
len = max(len, evsel->nr_members * _unit_width); \
- } \
+ \
return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \
}
#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
- struct perf_hpp *hpp __maybe_unused) \
+ struct perf_hpp *hpp __maybe_unused, \
+ struct perf_evsel *evsel) \
{ \
int len = _min_width; \
\
- if (symbol_conf.event_group) { \
- struct perf_evsel *evsel = hpp->ptr; \
- \
+ if (symbol_conf.event_group) \
len = max(len, evsel->nr_members * _unit_width); \
- } \
+ \
return len; \
}
+static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
+{
+ va_list args;
+ ssize_t ssize = hpp->size;
+ double percent;
+ int ret;
+
+ va_start(args, fmt);
+ percent = va_arg(args, double);
+ ret = value_color_snprintf(hpp->buf, hpp->size, fmt, percent);
+ va_end(args);
+
+ return (ret >= ssize) ? (ssize - 1) : ret;
+}
+
+static int hpp_entry_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
+{
+ va_list args;
+ ssize_t ssize = hpp->size;
+ int ret;
+
+ va_start(args, fmt);
+ ret = vsnprintf(hpp->buf, hpp->size, fmt, args);
+ va_end(args);
+
+ return (ret >= ssize) ? (ssize - 1) : ret;
+}
+
#define __HPP_COLOR_PERCENT_FN(_type, _field) \
static u64 he_get_##_field(struct hist_entry *he) \
{ \
@@ -116,8 +179,8 @@ static u64 he_get_##_field(struct hist_entry *he) \
static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
struct perf_hpp *hpp, struct hist_entry *he) \
{ \
- return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
- percent_color_snprintf, true); \
+ return __hpp__fmt(hpp, he, he_get_##_field, NULL, " %6.2f%%", \
+ hpp_color_scnprintf, true); \
}
#define __HPP_ENTRY_PERCENT_FN(_type, _field) \
@@ -125,8 +188,8 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
struct perf_hpp *hpp, struct hist_entry *he) \
{ \
const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
- return __hpp__fmt(hpp, he, he_get_##_field, fmt, \
- scnprintf, true); \
+ return __hpp__fmt(hpp, he, he_get_##_field, NULL, fmt, \
+ hpp_entry_scnprintf, true); \
}
#define __HPP_ENTRY_RAW_FN(_type, _field) \
@@ -139,7 +202,8 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
struct perf_hpp *hpp, struct hist_entry *he) \
{ \
const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
- return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
+ return __hpp__fmt(hpp, he, he_get_raw_##_field, NULL, fmt, \
+ hpp_entry_scnprintf, false); \
}
#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \
@@ -263,15 +327,13 @@ unsigned int hists__sort_list_width(struct hists *hists)
struct perf_hpp_fmt *fmt;
struct sort_entry *se;
int i = 0, ret = 0;
- struct perf_hpp dummy_hpp = {
- .ptr = hists_to_evsel(hists),
- };
+ struct perf_hpp dummy_hpp;
perf_hpp__for_each_format(fmt) {
if (i)
ret += 2;
- ret += fmt->width(fmt, &dummy_hpp);
+ ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
}
list_for_each_entry(se, &hist_entry__sort_list, list)
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 831fbb77d1ff..d59893edf031 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -306,12 +306,6 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
}
-static inline void advance_hpp(struct perf_hpp *hpp, int inc)
-{
- hpp->buf += inc;
- hpp->size -= inc;
-}
-
static int hist_entry__period_snprintf(struct perf_hpp *hpp,
struct hist_entry *he)
{
@@ -385,7 +379,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
struct perf_hpp dummy_hpp = {
.buf = bf,
.size = sizeof(bf),
- .ptr = hists_to_evsel(hists),
};
bool first = true;
size_t linesz;
@@ -404,7 +397,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
else
first = false;
- fmt->header(fmt, &dummy_hpp);
+ fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
fprintf(fp, "%s", bf);
}
@@ -449,7 +442,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
else
first = false;
- width = fmt->width(fmt, &dummy_hpp);
+ width = fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
for (i = 0; i < width; i++)
fprintf(fp, ".");
}
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 469eb679fb9d..809b4c50beae 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -8,6 +8,8 @@
*/
#include "util.h"
+#include "ui/ui.h"
+#include "sort.h"
#include "build-id.h"
#include "color.h"
#include "cache.h"
@@ -489,7 +491,7 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
{
struct annotation *notes;
- if (sym == NULL || use_browser != 1 || !sort__has_sym)
+ if (sym == NULL)
return 0;
notes = symbol__annotation(sym);
@@ -1234,6 +1236,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
struct dso *dso = map->dso;
char *filename;
const char *d_filename;
+ const char *evsel_name = perf_evsel__name(evsel);
struct annotation *notes = symbol__annotation(sym);
struct disasm_line *pos, *queue = NULL;
u64 start = map__rip_2objdump(map, sym->start);
@@ -1241,7 +1244,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
int more = 0;
u64 len;
int width = 8;
- int namelen;
+ int namelen, evsel_name_len, graph_dotted_len;
filename = strdup(dso->long_name);
if (!filename)
@@ -1254,14 +1257,17 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
len = symbol__size(sym);
namelen = strlen(d_filename);
+ evsel_name_len = strlen(evsel_name);
if (perf_evsel__is_group_event(evsel))
width *= evsel->nr_members;
- printf(" %-*.*s| Source code & Disassembly of %s\n",
- width, width, "Percent", d_filename);
- printf("-%-*.*s-------------------------------------\n",
- width+namelen, width+namelen, graph_dotted_line);
+ printf(" %-*.*s| Source code & Disassembly of %s for %s\n",
+ width, width, "Percent", d_filename, evsel_name);
+
+ graph_dotted_len = width + namelen + evsel_name_len;
+ printf("-%-*.*s-----------------------------------------\n",
+ graph_dotted_len, graph_dotted_len, graph_dotted_line);
if (verbose)
symbol__annotate_hits(sym, evsel);
@@ -1399,3 +1405,8 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
{
return symbol__annotate(he->ms.sym, he->ms.map, privsize);
}
+
+bool ui__has_annotation(void)
+{
+ return use_browser == 1 && sort__has_sym;
+}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index b2aef59d6bb2..56ad4f5287de 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -151,6 +151,8 @@ void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
void disasm__purge(struct list_head *head);
+bool ui__has_annotation(void);
+
int symbol__tty_annotate(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, bool print_lines,
bool full_paths, int min_pcnt, int max_lines);
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index a9b48c42e81e..7fe4994eeb63 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -1,5 +1,5 @@
#include "util.h"
-#include "fs.h"
+#include <api/fs/fs.h>
#include "../perf.h"
#include "cpumap.h"
#include <assert.h>
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 4045d086d9d9..64453d63b971 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -45,8 +45,8 @@ int dso__read_binary_type_filename(const struct dso *dso,
debuglink--;
if (*debuglink == '/')
debuglink++;
- filename__read_debuglink(dso->long_name, debuglink,
- size - (debuglink - filename));
+ ret = filename__read_debuglink(dso->long_name, debuglink,
+ size - (debuglink - filename));
}
break;
case DSO_BINARY_TYPE__BUILD_ID_CACHE:
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index cd7d6f078cdd..ab06f1c03655 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -102,6 +102,16 @@ struct dso {
char name[0];
};
+/* dso__for_each_symbol - iterate over the symbols of given type
+ *
+ * @dso: the 'struct dso *' in which symbols itereated
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @n: the 'struct rb_node *' to use as a temporary storage
+ * @type: the 'enum map_type' type of symbols
+ */
+#define dso__for_each_symbol(dso, pos, n, type) \
+ symbols__for_each_entry(&(dso)->symbols[(type)], pos, n)
+
static inline void dso__set_loaded(struct dso *dso, enum map_type type)
{
dso->loaded |= (1 << type);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index b0f3ca850e9e..9d12aa6dd485 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,6 +1,7 @@
#include <linux/types.h>
#include "event.h"
#include "debug.h"
+#include "hist.h"
#include "machine.h"
#include "sort.h"
#include "string.h"
@@ -94,14 +95,10 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len)
static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
union perf_event *event, pid_t pid,
- int full,
perf_event__handler_t process,
struct machine *machine)
{
- char filename[PATH_MAX];
size_t size;
- DIR *tasks;
- struct dirent dirent, *next;
pid_t tgid;
memset(&event->comm, 0, sizeof(event->comm));
@@ -124,55 +121,35 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
event->comm.header.size = (sizeof(event->comm) -
(sizeof(event->comm.comm) - size) +
machine->id_hdr_size);
- if (!full) {
- event->comm.tid = pid;
+ event->comm.tid = pid;
- if (process(tool, event, &synth_sample, machine) != 0)
- return -1;
-
- goto out;
- }
-
- if (machine__is_default_guest(machine))
- return 0;
-
- snprintf(filename, sizeof(filename), "%s/proc/%d/task",
- machine->root_dir, pid);
-
- tasks = opendir(filename);
- if (tasks == NULL) {
- pr_debug("couldn't open %s\n", filename);
- return 0;
- }
+ if (process(tool, event, &synth_sample, machine) != 0)
+ return -1;
- while (!readdir_r(tasks, &dirent, &next) && next) {
- char *end;
- pid = strtol(dirent.d_name, &end, 10);
- if (*end)
- continue;
+out:
+ return tgid;
+}
- /* already have tgid; jut want to update the comm */
- (void) perf_event__get_comm_tgid(pid, event->comm.comm,
- sizeof(event->comm.comm));
+static int perf_event__synthesize_fork(struct perf_tool *tool,
+ union perf_event *event, pid_t pid,
+ pid_t tgid, perf_event__handler_t process,
+ struct machine *machine)
+{
+ memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size);
- size = strlen(event->comm.comm) + 1;
- size = PERF_ALIGN(size, sizeof(u64));
- memset(event->comm.comm + size, 0, machine->id_hdr_size);
- event->comm.header.size = (sizeof(event->comm) -
- (sizeof(event->comm.comm) - size) +
- machine->id_hdr_size);
+ /* this is really a clone event but we use fork to synthesize it */
+ event->fork.ppid = tgid;
+ event->fork.ptid = tgid;
+ event->fork.pid = tgid;
+ event->fork.tid = pid;
+ event->fork.header.type = PERF_RECORD_FORK;
- event->comm.tid = pid;
+ event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size);
- if (process(tool, event, &synth_sample, machine) != 0) {
- tgid = -1;
- break;
- }
- }
+ if (process(tool, event, &synth_sample, machine) != 0)
+ return -1;
- closedir(tasks);
-out:
- return tgid;
+ return 0;
}
int perf_event__synthesize_mmap_events(struct perf_tool *tool,
@@ -324,17 +301,71 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
static int __event__synthesize_thread(union perf_event *comm_event,
union perf_event *mmap_event,
+ union perf_event *fork_event,
pid_t pid, int full,
perf_event__handler_t process,
struct perf_tool *tool,
struct machine *machine, bool mmap_data)
{
- pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full,
+ char filename[PATH_MAX];
+ DIR *tasks;
+ struct dirent dirent, *next;
+ pid_t tgid;
+
+ /* special case: only send one comm event using passed in pid */
+ if (!full) {
+ tgid = perf_event__synthesize_comm(tool, comm_event, pid,
+ process, machine);
+
+ if (tgid == -1)
+ return -1;
+
+ return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
+ process, machine, mmap_data);
+ }
+
+ if (machine__is_default_guest(machine))
+ return 0;
+
+ snprintf(filename, sizeof(filename), "%s/proc/%d/task",
+ machine->root_dir, pid);
+
+ tasks = opendir(filename);
+ if (tasks == NULL) {
+ pr_debug("couldn't open %s\n", filename);
+ return 0;
+ }
+
+ while (!readdir_r(tasks, &dirent, &next) && next) {
+ char *end;
+ int rc = 0;
+ pid_t _pid;
+
+ _pid = strtol(dirent.d_name, &end, 10);
+ if (*end)
+ continue;
+
+ tgid = perf_event__synthesize_comm(tool, comm_event, _pid,
+ process, machine);
+ if (tgid == -1)
+ return -1;
+
+ if (_pid == pid) {
+ /* process the parent's maps too */
+ rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
+ process, machine, mmap_data);
+ } else {
+ /* only fork the tid's map, to save time */
+ rc = perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
process, machine);
- if (tgid == -1)
- return -1;
- return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
- process, machine, mmap_data);
+ }
+
+ if (rc)
+ return rc;
+ }
+
+ closedir(tasks);
+ return 0;
}
int perf_event__synthesize_thread_map(struct perf_tool *tool,
@@ -343,7 +374,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
struct machine *machine,
bool mmap_data)
{
- union perf_event *comm_event, *mmap_event;
+ union perf_event *comm_event, *mmap_event, *fork_event;
int err = -1, thread, j;
comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
@@ -354,9 +385,14 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
if (mmap_event == NULL)
goto out_free_comm;
+ fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size);
+ if (fork_event == NULL)
+ goto out_free_mmap;
+
err = 0;
for (thread = 0; thread < threads->nr; ++thread) {
if (__event__synthesize_thread(comm_event, mmap_event,
+ fork_event,
threads->map[thread], 0,
process, tool, machine,
mmap_data)) {
@@ -382,6 +418,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
/* if not, generate events for it */
if (need_leader &&
__event__synthesize_thread(comm_event, mmap_event,
+ fork_event,
comm_event->comm.pid, 0,
process, tool, machine,
mmap_data)) {
@@ -390,6 +427,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
}
}
}
+ free(fork_event);
+out_free_mmap:
free(mmap_event);
out_free_comm:
free(comm_event);
@@ -404,9 +443,12 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
DIR *proc;
char proc_path[PATH_MAX];
struct dirent dirent, *next;
- union perf_event *comm_event, *mmap_event;
+ union perf_event *comm_event, *mmap_event, *fork_event;
int err = -1;
+ if (machine__is_default_guest(machine))
+ return 0;
+
comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
if (comm_event == NULL)
goto out;
@@ -415,14 +457,15 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
if (mmap_event == NULL)
goto out_free_comm;
- if (machine__is_default_guest(machine))
- return 0;
+ fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size);
+ if (fork_event == NULL)
+ goto out_free_mmap;
snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
proc = opendir(proc_path);
if (proc == NULL)
- goto out_free_mmap;
+ goto out_free_fork;
while (!readdir_r(proc, &dirent, &next) && next) {
char *end;
@@ -434,12 +477,14 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
* We may race with exiting thread, so don't stop just because
* one thread couldn't be synthesized.
*/
- __event__synthesize_thread(comm_event, mmap_event, pid, 1,
- process, tool, machine, mmap_data);
+ __event__synthesize_thread(comm_event, mmap_event, fork_event, pid,
+ 1, process, tool, machine, mmap_data);
}
err = 0;
closedir(proc);
+out_free_fork:
+ free(fork_event);
out_free_mmap:
free(mmap_event);
out_free_comm:
@@ -661,7 +706,7 @@ void thread__find_addr_map(struct thread *thread,
al->thread = thread;
al->addr = addr;
al->cpumode = cpumode;
- al->filtered = false;
+ al->filtered = 0;
if (machine == NULL) {
al->map = NULL;
@@ -687,11 +732,11 @@ void thread__find_addr_map(struct thread *thread,
if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
!perf_guest)
- al->filtered = true;
+ al->filtered |= (1 << HIST_FILTER__GUEST);
if ((cpumode == PERF_RECORD_MISC_USER ||
cpumode == PERF_RECORD_MISC_KERNEL) &&
!perf_host)
- al->filtered = true;
+ al->filtered |= (1 << HIST_FILTER__HOST);
return;
}
@@ -748,9 +793,6 @@ int perf_event__preprocess_sample(const union perf_event *event,
if (thread == NULL)
return -1;
- if (thread__is_filtered(thread))
- goto out_filtered;
-
dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
/*
* Have we already created the kernel maps for this machine?
@@ -768,6 +810,10 @@ int perf_event__preprocess_sample(const union perf_event *event,
dump_printf(" ...... dso: %s\n",
al->map ? al->map->dso->long_name :
al->level == 'H' ? "[hypervisor]" : "<not found>");
+
+ if (thread__is_filtered(thread))
+ al->filtered |= (1 << HIST_FILTER__THREAD);
+
al->sym = NULL;
al->cpu = sample->cpu;
@@ -779,8 +825,9 @@ int perf_event__preprocess_sample(const union perf_event *event,
dso->short_name) ||
(dso->short_name != dso->long_name &&
strlist__has_entry(symbol_conf.dso_list,
- dso->long_name)))))
- goto out_filtered;
+ dso->long_name))))) {
+ al->filtered |= (1 << HIST_FILTER__DSO);
+ }
al->sym = map__find_symbol(al->map, al->addr,
machine->symbol_filter);
@@ -788,12 +835,9 @@ int perf_event__preprocess_sample(const union perf_event *event,
if (symbol_conf.sym_list &&
(!al->sym || !strlist__has_entry(symbol_conf.sym_list,
- al->sym->name)))
- goto out_filtered;
-
- return 0;
+ al->sym->name))) {
+ al->filtered |= (1 << HIST_FILTER__SYMBOL);
+ }
-out_filtered:
- al->filtered = true;
return 0;
}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 851fa06f4a42..38457d447a13 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -85,6 +85,7 @@ struct sample_event {
struct regs_dump {
u64 abi;
+ u64 mask;
u64 *regs;
};
@@ -259,9 +260,9 @@ int perf_event__preprocess_sample(const union perf_event *event,
const char *perf_event__name(unsigned int id);
size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
- u64 sample_regs_user, u64 read_format);
+ u64 read_format);
int perf_event__synthesize_sample(union perf_event *event, u64 type,
- u64 sample_regs_user, u64 read_format,
+ u64 read_format,
const struct perf_sample *sample,
bool swapped);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 55407c594b87..5c28d82b76c4 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -500,6 +500,34 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
return ret;
}
+static void
+perf_evsel__config_callgraph(struct perf_evsel *evsel,
+ struct record_opts *opts)
+{
+ bool function = perf_evsel__is_function_event(evsel);
+ struct perf_event_attr *attr = &evsel->attr;
+
+ perf_evsel__set_sample_bit(evsel, CALLCHAIN);
+
+ if (opts->call_graph == CALLCHAIN_DWARF) {
+ if (!function) {
+ perf_evsel__set_sample_bit(evsel, REGS_USER);
+ perf_evsel__set_sample_bit(evsel, STACK_USER);
+ attr->sample_regs_user = PERF_REGS_MASK;
+ attr->sample_stack_user = opts->stack_dump_size;
+ attr->exclude_callchain_user = 1;
+ } else {
+ pr_info("Cannot use DWARF unwind for function trace event,"
+ " falling back to framepointers.\n");
+ }
+ }
+
+ if (function) {
+ pr_info("Disabling user space callchains for function trace event.\n");
+ attr->exclude_callchain_user = 1;
+ }
+}
+
/*
* The enable_on_exec/disabled value strategy:
*
@@ -595,17 +623,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
attr->mmap_data = track;
}
- if (opts->call_graph) {
- perf_evsel__set_sample_bit(evsel, CALLCHAIN);
-
- if (opts->call_graph == CALLCHAIN_DWARF) {
- perf_evsel__set_sample_bit(evsel, REGS_USER);
- perf_evsel__set_sample_bit(evsel, STACK_USER);
- attr->sample_regs_user = PERF_REGS_MASK;
- attr->sample_stack_user = opts->stack_dump_size;
- attr->exclude_callchain_user = 1;
- }
- }
+ if (opts->call_graph_enabled)
+ perf_evsel__config_callgraph(evsel, opts);
if (target__has_cpu(&opts->target))
perf_evsel__set_sample_bit(evsel, CPU);
@@ -1004,7 +1023,7 @@ retry_sample_id:
group_fd = get_group_fd(evsel, cpu, thread);
retry_open:
- pr_debug2("perf_event_open: pid %d cpu %d group_fd %d flags %#lx\n",
+ pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx\n",
pid, cpus->map[cpu], group_fd, flags);
FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
@@ -1013,7 +1032,7 @@ retry_open:
group_fd, flags);
if (FD(evsel, cpu, thread) < 0) {
err = -errno;
- pr_debug2("perf_event_open failed, error %d\n",
+ pr_debug2("sys_perf_event_open failed, error %d\n",
err);
goto try_fallback;
}
@@ -1220,7 +1239,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
memset(data, 0, sizeof(*data));
data->cpu = data->pid = data->tid = -1;
data->stream_id = data->id = data->time = -1ULL;
- data->period = 1;
+ data->period = evsel->attr.sample_period;
data->weight = 0;
if (event->header.type != PERF_RECORD_SAMPLE) {
@@ -1396,10 +1415,11 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
array++;
if (data->user_regs.abi) {
- u64 regs_user = evsel->attr.sample_regs_user;
+ u64 mask = evsel->attr.sample_regs_user;
- sz = hweight_long(regs_user) * sizeof(u64);
+ sz = hweight_long(mask) * sizeof(u64);
OVERFLOW_CHECK(array, sz, max_size);
+ data->user_regs.mask = mask;
data->user_regs.regs = (u64 *)array;
array = (void *)array + sz;
}
@@ -1451,7 +1471,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
}
size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
- u64 sample_regs_user, u64 read_format)
+ u64 read_format)
{
size_t sz, result = sizeof(struct sample_event);
@@ -1517,7 +1537,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
if (type & PERF_SAMPLE_REGS_USER) {
if (sample->user_regs.abi) {
result += sizeof(u64);
- sz = hweight_long(sample_regs_user) * sizeof(u64);
+ sz = hweight_long(sample->user_regs.mask) * sizeof(u64);
result += sz;
} else {
result += sizeof(u64);
@@ -1546,7 +1566,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
}
int perf_event__synthesize_sample(union perf_event *event, u64 type,
- u64 sample_regs_user, u64 read_format,
+ u64 read_format,
const struct perf_sample *sample,
bool swapped)
{
@@ -1687,7 +1707,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
if (type & PERF_SAMPLE_REGS_USER) {
if (sample->user_regs.abi) {
*array++ = sample->user_regs.abi;
- sz = hweight_long(sample_regs_user) * sizeof(u64);
+ sz = hweight_long(sample->user_regs.mask) * sizeof(u64);
memcpy(array, sample->user_regs.regs, sz);
array = (void *)array + sz;
} else {
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index f1b325665aae..0c9926cfb292 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -315,6 +315,24 @@ static inline bool perf_evsel__is_group_event(struct perf_evsel *evsel)
return perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1;
}
+/**
+ * perf_evsel__is_function_event - Return whether given evsel is a function
+ * trace event
+ *
+ * @evsel - evsel selector to be tested
+ *
+ * Return %true if event is function trace event
+ */
+static inline bool perf_evsel__is_function_event(struct perf_evsel *evsel)
+{
+#define FUNCTION_EVENT "ftrace:function"
+
+ return evsel->name &&
+ !strncmp(FUNCTION_EVENT, evsel->name, sizeof(FUNCTION_EVENT));
+
+#undef FUNCTION_EVENT
+}
+
struct perf_attr_details {
bool freq;
bool verbose;
diff --git a/tools/perf/util/fs.h b/tools/perf/util/fs.h
deleted file mode 100644
index 5e09ce1bab0e..000000000000
--- a/tools/perf/util/fs.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __PERF_FS
-#define __PERF_FS
-
-const char *sysfs__mountpoint(void);
-const char *procfs__mountpoint(void);
-
-#endif /* __PERF_FS */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index e4e6249b87d4..f38590d7561b 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -13,13 +13,6 @@ static bool hists__filter_entry_by_thread(struct hists *hists,
static bool hists__filter_entry_by_symbol(struct hists *hists,
struct hist_entry *he);
-enum hist_filter {
- HIST_FILTER__DSO,
- HIST_FILTER__THREAD,
- HIST_FILTER__PARENT,
- HIST_FILTER__SYMBOL,
-};
-
struct callchain_param callchain_param = {
.mode = CHAIN_GRAPH_REL,
.min_percent = 0.5,
@@ -290,7 +283,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
if (he->branch_info) {
/*
* This branch info is (a part of) allocated from
- * machine__resolve_bstack() and will be freed after
+ * sample__resolve_bstack() and will be freed after
* adding new entries. So we need to save a copy.
*/
he->branch_info = malloc(sizeof(*he->branch_info));
@@ -369,7 +362,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
he_stat__add_period(&he->stat, period, weight);
/*
- * This mem info was allocated from machine__resolve_mem
+ * This mem info was allocated from sample__resolve_mem
* and will not be used anymore.
*/
zfree(&entry->mem_info);
@@ -429,7 +422,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
.weight = weight,
},
.parent = sym_parent,
- .filtered = symbol__parent_filter(sym_parent),
+ .filtered = symbol__parent_filter(sym_parent) | al->filtered,
.hists = hists,
.branch_info = bi,
.mem_info = mi,
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index a59743fa3ef7..1f1f513dfe7f 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -14,6 +14,15 @@ struct hist_entry;
struct addr_location;
struct symbol;
+enum hist_filter {
+ HIST_FILTER__DSO,
+ HIST_FILTER__THREAD,
+ HIST_FILTER__PARENT,
+ HIST_FILTER__SYMBOL,
+ HIST_FILTER__GUEST,
+ HIST_FILTER__HOST,
+};
+
/*
* The kernel collects the number of events it couldn't send in a stretch and
* when possible sends this number in a PERF_RECORD_LOST event. The number of
@@ -132,8 +141,10 @@ struct perf_hpp {
};
struct perf_hpp_fmt {
- int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
- int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
+ int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+ struct perf_evsel *evsel);
+ int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+ struct perf_evsel *evsel);
int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
struct hist_entry *he);
int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
@@ -166,6 +177,20 @@ void perf_hpp__init(void);
void perf_hpp__column_register(struct perf_hpp_fmt *format);
void perf_hpp__column_enable(unsigned col);
+typedef u64 (*hpp_field_fn)(struct hist_entry *he);
+typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front);
+typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
+
+int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
+ hpp_field_fn get_field, hpp_callback_fn callback,
+ const char *fmt, hpp_snprint_fn print_fn, bool fmt_percent);
+
+static inline void advance_hpp(struct perf_hpp *hpp, int inc)
+{
+ hpp->buf += inc;
+ hpp->size -= inc;
+}
+
static inline size_t perf_hpp__use_color(void)
{
return !symbol_conf.field_sep;
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index 45cf10a562bd..dadfa7e54287 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -87,13 +87,15 @@ static __always_inline unsigned long __ffs(unsigned long word)
return num;
}
+typedef const unsigned long __attribute__((__may_alias__)) long_alias_t;
+
/*
* Find the first set bit in a memory region.
*/
static inline unsigned long
find_first_bit(const unsigned long *addr, unsigned long size)
{
- const unsigned long *p = addr;
+ long_alias_t *p = (long_alias_t *) addr;
unsigned long result = 0;
unsigned long tmp;
diff --git a/tools/perf/util/include/linux/hash.h b/tools/perf/util/include/linux/hash.h
deleted file mode 100644
index 201f57397997..000000000000
--- a/tools/perf/util/include/linux/hash.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "../../../../include/linux/hash.h"
-
-#ifndef PERF_HASH_H
-#define PERF_HASH_H
-#endif
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index d8c927c868ee..9844c31b7c2b 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -94,12 +94,6 @@ static inline int scnprintf(char * buf, size_t size, const char * fmt, ...)
return (i >= ssize) ? (ssize - 1) : i;
}
-static inline unsigned long
-simple_strtoul(const char *nptr, char **endptr, int base)
-{
- return strtoul(nptr, endptr, base);
-}
-
int eprintf(int level,
const char *fmt, ...) __attribute__((format(printf, 2, 3)));
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
index 1d928a0ce997..bfe0a2afd0d2 100644
--- a/tools/perf/util/include/linux/list.h
+++ b/tools/perf/util/include/linux/list.h
@@ -1,5 +1,4 @@
#include <linux/kernel.h>
-#include <linux/prefetch.h>
#include "../../../../include/linux/list.h"
diff --git a/tools/perf/util/include/linux/prefetch.h b/tools/perf/util/include/linux/prefetch.h
deleted file mode 100644
index 7841e485d8c3..000000000000
--- a/tools/perf/util/include/linux/prefetch.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef PERF_LINUX_PREFETCH_H
-#define PERF_LINUX_PREFETCH_H
-
-static inline void prefetch(void *a __attribute__((unused))) { }
-
-#endif
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index c872991e0f65..a53cd0b8c151 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -327,9 +327,10 @@ struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
return __machine__findnew_thread(machine, pid, tid, true);
}
-struct thread *machine__find_thread(struct machine *machine, pid_t tid)
+struct thread *machine__find_thread(struct machine *machine, pid_t pid,
+ pid_t tid)
{
- return __machine__findnew_thread(machine, 0, tid, false);
+ return __machine__findnew_thread(machine, pid, tid, false);
}
int machine__process_comm_event(struct machine *machine, union perf_event *event,
@@ -1026,7 +1027,7 @@ int machine__process_mmap2_event(struct machine *machine,
}
thread = machine__findnew_thread(machine, event->mmap2.pid,
- event->mmap2.pid);
+ event->mmap2.tid);
if (thread == NULL)
goto out_problem;
@@ -1074,7 +1075,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
}
thread = machine__findnew_thread(machine, event->mmap.pid,
- event->mmap.pid);
+ event->mmap.tid);
if (thread == NULL)
goto out_problem;
@@ -1114,7 +1115,9 @@ static void machine__remove_thread(struct machine *machine, struct thread *th)
int machine__process_fork_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample)
{
- struct thread *thread = machine__find_thread(machine, event->fork.tid);
+ struct thread *thread = machine__find_thread(machine,
+ event->fork.pid,
+ event->fork.tid);
struct thread *parent = machine__findnew_thread(machine,
event->fork.ppid,
event->fork.ptid);
@@ -1140,7 +1143,9 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
int machine__process_exit_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample __maybe_unused)
{
- struct thread *thread = machine__find_thread(machine, event->fork.tid);
+ struct thread *thread = machine__find_thread(machine,
+ event->fork.pid,
+ event->fork.tid);
if (dump_trace)
perf_event__fprintf_task(event, stdout);
@@ -1184,39 +1189,22 @@ static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
return 0;
}
-static const u8 cpumodes[] = {
- PERF_RECORD_MISC_USER,
- PERF_RECORD_MISC_KERNEL,
- PERF_RECORD_MISC_GUEST_USER,
- PERF_RECORD_MISC_GUEST_KERNEL
-};
-#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
-
static void ip__resolve_ams(struct machine *machine, struct thread *thread,
struct addr_map_symbol *ams,
u64 ip)
{
struct addr_location al;
- size_t i;
- u8 m;
memset(&al, 0, sizeof(al));
+ /*
+ * We cannot use the header.misc hint to determine whether a
+ * branch stack address is user, kernel, guest, hypervisor.
+ * Branches may straddle the kernel/user/hypervisor boundaries.
+ * Thus, we have to try consecutively until we find a match
+ * or else, the symbol is unknown
+ */
+ thread__find_cpumode_addr_location(thread, machine, MAP__FUNCTION, ip, &al);
- for (i = 0; i < NCPUMODES; i++) {
- m = cpumodes[i];
- /*
- * We cannot use the header.misc hint to determine whether a
- * branch stack address is user, kernel, guest, hypervisor.
- * Branches may straddle the kernel/user/hypervisor boundaries.
- * Thus, we have to try consecutively until we find a match
- * or else, the symbol is unknown
- */
- thread__find_addr_location(thread, machine, m, MAP__FUNCTION,
- ip, &al);
- if (al.sym)
- goto found;
- }
-found:
ams->addr = ip;
ams->al_addr = al.addr;
ams->sym = al.sym;
@@ -1238,37 +1226,35 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread,
ams->map = al.map;
}
-struct mem_info *machine__resolve_mem(struct machine *machine,
- struct thread *thr,
- struct perf_sample *sample,
- u8 cpumode)
+struct mem_info *sample__resolve_mem(struct perf_sample *sample,
+ struct addr_location *al)
{
struct mem_info *mi = zalloc(sizeof(*mi));
if (!mi)
return NULL;
- ip__resolve_ams(machine, thr, &mi->iaddr, sample->ip);
- ip__resolve_data(machine, thr, cpumode, &mi->daddr, sample->addr);
+ ip__resolve_ams(al->machine, al->thread, &mi->iaddr, sample->ip);
+ ip__resolve_data(al->machine, al->thread, al->cpumode,
+ &mi->daddr, sample->addr);
mi->data_src.val = sample->data_src;
return mi;
}
-struct branch_info *machine__resolve_bstack(struct machine *machine,
- struct thread *thr,
- struct branch_stack *bs)
+struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
+ struct addr_location *al)
{
- struct branch_info *bi;
unsigned int i;
+ const struct branch_stack *bs = sample->branch_stack;
+ struct branch_info *bi = calloc(bs->nr, sizeof(struct branch_info));
- bi = calloc(bs->nr, sizeof(struct branch_info));
if (!bi)
return NULL;
for (i = 0; i < bs->nr; i++) {
- ip__resolve_ams(machine, thr, &bi[i].to, bs->entries[i].to);
- ip__resolve_ams(machine, thr, &bi[i].from, bs->entries[i].from);
+ ip__resolve_ams(al->machine, al->thread, &bi[i].to, bs->entries[i].to);
+ ip__resolve_ams(al->machine, al->thread, &bi[i].from, bs->entries[i].from);
bi[i].flags = bs->entries[i].flags;
}
return bi;
@@ -1326,7 +1312,7 @@ static int machine__resolve_callchain_sample(struct machine *machine,
continue;
}
- al.filtered = false;
+ al.filtered = 0;
thread__find_addr_location(thread, machine, cpumode,
MAP__FUNCTION, ip, &al);
if (al.sym != NULL) {
@@ -1385,8 +1371,7 @@ int machine__resolve_callchain(struct machine *machine,
return 0;
return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
- thread, evsel->attr.sample_regs_user,
- sample, max_stack);
+ thread, sample, max_stack);
}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index f77e91e483dc..c8c74a119398 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -41,7 +41,8 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
return machine->vmlinux_maps[type];
}
-struct thread *machine__find_thread(struct machine *machine, pid_t tid);
+struct thread *machine__find_thread(struct machine *machine, pid_t pid,
+ pid_t tid);
int machine__process_comm_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample);
@@ -91,12 +92,10 @@ void machine__delete_dead_threads(struct machine *machine);
void machine__delete_threads(struct machine *machine);
void machine__delete(struct machine *machine);
-struct branch_info *machine__resolve_bstack(struct machine *machine,
- struct thread *thread,
- struct branch_stack *bs);
-struct mem_info *machine__resolve_mem(struct machine *machine,
- struct thread *thread,
- struct perf_sample *sample, u8 cpumode);
+struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
+ struct addr_location *al);
+struct mem_info *sample__resolve_mem(struct perf_sample *sample,
+ struct addr_location *al);
int machine__resolve_callchain(struct machine *machine,
struct perf_evsel *evsel,
struct thread *thread,
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 257e513205ce..f00f058afb3b 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -90,6 +90,16 @@ u64 map__objdump_2mem(struct map *map, u64 ip);
struct symbol;
+/* map__for_each_symbol - iterate over the symbols in the given map
+ *
+ * @map: the 'struct map *' in which symbols itereated
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @n: the 'struct rb_node *' to use as a temporary storage
+ * Note: caller must ensure map->dso is not NULL (map is loaded).
+ */
+#define map__for_each_symbol(map, pos, n) \
+ dso__for_each_symbol(map->dso, pos, n, map->type)
+
typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
void map__init(struct map *map, enum map_type type,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index d248fca6d7ed..1e15df10a88c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1091,12 +1091,12 @@ int is_valid_tracepoint(const char *event_string)
static bool is_event_supported(u8 type, unsigned config)
{
bool ret = true;
+ int open_return;
struct perf_evsel *evsel;
struct perf_event_attr attr = {
.type = type,
.config = config,
.disabled = 1,
- .exclude_kernel = 1,
};
struct {
struct thread_map map;
@@ -1108,7 +1108,20 @@ static bool is_event_supported(u8 type, unsigned config)
evsel = perf_evsel__new(&attr);
if (evsel) {
- ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0;
+ open_return = perf_evsel__open(evsel, NULL, &tmap.map);
+ ret = open_return >= 0;
+
+ if (open_return == -EACCES) {
+ /*
+ * This happens if the paranoid value
+ * /proc/sys/kernel/perf_event_paranoid is set to 2
+ * Re-run with exclude_kernel set; we don't do that
+ * by default as some ARM machines do not support it.
+ *
+ */
+ evsel->attr.exclude_kernel = 1;
+ ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0;
+ }
perf_evsel__delete(evsel);
}
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index d22e3f8017dc..bf48092983c6 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -407,7 +407,9 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
if (internal_help && !strcmp(arg + 2, "help"))
return usage_with_options_internal(usagestr, options, 0);
if (!strcmp(arg + 2, "list-opts"))
- return PARSE_OPT_LIST;
+ return PARSE_OPT_LIST_OPTS;
+ if (!strcmp(arg + 2, "list-cmds"))
+ return PARSE_OPT_LIST_SUBCMDS;
switch (parse_long_opt(ctx, arg + 2, options)) {
case -1:
return parse_options_usage(usagestr, options, arg + 2, 0);
@@ -433,25 +435,45 @@ int parse_options_end(struct parse_opt_ctx_t *ctx)
return ctx->cpidx + ctx->argc;
}
-int parse_options(int argc, const char **argv, const struct option *options,
- const char * const usagestr[], int flags)
+int parse_options_subcommand(int argc, const char **argv, const struct option *options,
+ const char *const subcommands[], const char *usagestr[], int flags)
{
struct parse_opt_ctx_t ctx;
perf_header__set_cmdline(argc, argv);
+ /* build usage string if it's not provided */
+ if (subcommands && !usagestr[0]) {
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_addf(&buf, "perf %s [<options>] {", argv[0]);
+ for (int i = 0; subcommands[i]; i++) {
+ if (i)
+ strbuf_addstr(&buf, "|");
+ strbuf_addstr(&buf, subcommands[i]);
+ }
+ strbuf_addstr(&buf, "}");
+
+ usagestr[0] = strdup(buf.buf);
+ strbuf_release(&buf);
+ }
+
parse_options_start(&ctx, argc, argv, flags);
switch (parse_options_step(&ctx, options, usagestr)) {
case PARSE_OPT_HELP:
exit(129);
case PARSE_OPT_DONE:
break;
- case PARSE_OPT_LIST:
+ case PARSE_OPT_LIST_OPTS:
while (options->type != OPTION_END) {
printf("--%s ", options->long_name);
options++;
}
exit(130);
+ case PARSE_OPT_LIST_SUBCMDS:
+ for (int i = 0; subcommands[i]; i++)
+ printf("%s ", subcommands[i]);
+ exit(130);
default: /* PARSE_OPT_UNKNOWN */
if (ctx.argv[0][1] == '-') {
error("unknown option `%s'", ctx.argv[0] + 2);
@@ -464,6 +486,13 @@ int parse_options(int argc, const char **argv, const struct option *options,
return parse_options_end(&ctx);
}
+int parse_options(int argc, const char **argv, const struct option *options,
+ const char * const usagestr[], int flags)
+{
+ return parse_options_subcommand(argc, argv, options, NULL,
+ (const char **) usagestr, flags);
+}
+
#define USAGE_OPTS_WIDTH 24
#define USAGE_GAP 2
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index cbf0149cf221..d8dac8ac5f37 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -140,6 +140,11 @@ extern int parse_options(int argc, const char **argv,
const struct option *options,
const char * const usagestr[], int flags);
+extern int parse_options_subcommand(int argc, const char **argv,
+ const struct option *options,
+ const char *const subcommands[],
+ const char *usagestr[], int flags);
+
extern NORETURN void usage_with_options(const char * const *usagestr,
const struct option *options);
@@ -148,7 +153,8 @@ extern NORETURN void usage_with_options(const char * const *usagestr,
enum {
PARSE_OPT_HELP = -1,
PARSE_OPT_DONE,
- PARSE_OPT_LIST,
+ PARSE_OPT_LIST_OPTS,
+ PARSE_OPT_LIST_SUBCMDS,
PARSE_OPT_UNKNOWN,
};
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
new file mode 100644
index 000000000000..a3539ef30b15
--- /dev/null
+++ b/tools/perf/util/perf_regs.c
@@ -0,0 +1,19 @@
+#include <errno.h>
+#include "perf_regs.h"
+
+int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
+{
+ int i, idx = 0;
+ u64 mask = regs->mask;
+
+ if (!(mask & (1 << id)))
+ return -EINVAL;
+
+ for (i = 0; i < id; i++) {
+ if (mask & (1 << i))
+ idx++;
+ }
+
+ *valp = regs->regs[idx];
+ return 0;
+}
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index a3d42cd74919..d6e8b6a8d7f3 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -1,8 +1,14 @@
#ifndef __PERF_REGS_H
#define __PERF_REGS_H
+#include "types.h"
+#include "event.h"
+
#ifdef HAVE_PERF_REGS_SUPPORT
#include <perf_regs.h>
+
+int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
+
#else
#define PERF_REGS_MASK 0
@@ -10,5 +16,12 @@ static inline const char *perf_reg_name(int id __maybe_unused)
{
return NULL;
}
+
+static inline int perf_reg_value(u64 *valp __maybe_unused,
+ struct regs_dump *regs __maybe_unused,
+ int id __maybe_unused)
+{
+ return 0;
+}
#endif /* HAVE_PERF_REGS_SUPPORT */
#endif /* __PERF_REGS_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index b752ecb40d86..00a7dcb2f55c 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -3,7 +3,7 @@
#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
-#include "fs.h"
+#include <api/fs/fs.h>
#include <locale.h>
#include "util.h"
#include "pmu.h"
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index a8a9b6cd93a8..0d1542f33d87 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -70,34 +70,32 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
}
static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
-static int convert_name_to_addr(struct perf_probe_event *pev,
- const char *exec);
static void clear_probe_trace_event(struct probe_trace_event *tev);
-static struct machine machine;
+static struct machine *host_machine;
/* Initialize symbol maps and path of vmlinux/modules */
-static int init_vmlinux(void)
+static int init_symbol_maps(bool user_only)
{
int ret;
symbol_conf.sort_by_name = true;
- if (symbol_conf.vmlinux_name == NULL)
- symbol_conf.try_vmlinux_path = true;
- else
- pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
ret = symbol__init();
if (ret < 0) {
pr_debug("Failed to init symbol map.\n");
goto out;
}
- ret = machine__init(&machine, "", HOST_KERNEL_ID);
- if (ret < 0)
- goto out;
+ if (host_machine || user_only) /* already initialized */
+ return 0;
- if (machine__create_kernel_maps(&machine) < 0) {
- pr_debug("machine__create_kernel_maps() failed.\n");
- goto out;
+ if (symbol_conf.vmlinux_name)
+ pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
+
+ host_machine = machine__new_host();
+ if (!host_machine) {
+ pr_debug("machine__new_host() failed.\n");
+ symbol__exit();
+ ret = -1;
}
out:
if (ret < 0)
@@ -105,21 +103,66 @@ out:
return ret;
}
+static void exit_symbol_maps(void)
+{
+ if (host_machine) {
+ machine__delete(host_machine);
+ host_machine = NULL;
+ }
+ symbol__exit();
+}
+
static struct symbol *__find_kernel_function_by_name(const char *name,
struct map **mapp)
{
- return machine__find_kernel_function_by_name(&machine, name, mapp,
+ return machine__find_kernel_function_by_name(host_machine, name, mapp,
NULL);
}
+static struct symbol *__find_kernel_function(u64 addr, struct map **mapp)
+{
+ return machine__find_kernel_function(host_machine, addr, mapp, NULL);
+}
+
+static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void)
+{
+ /* kmap->ref_reloc_sym should be set if host_machine is initialized */
+ struct kmap *kmap;
+
+ if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0)
+ return NULL;
+
+ kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
+ return kmap->ref_reloc_sym;
+}
+
+static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc)
+{
+ struct ref_reloc_sym *reloc_sym;
+ struct symbol *sym;
+ struct map *map;
+
+ /* ref_reloc_sym is just a label. Need a special fix*/
+ reloc_sym = kernel_get_ref_reloc_sym();
+ if (reloc_sym && strcmp(name, reloc_sym->name) == 0)
+ return (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr;
+ else {
+ sym = __find_kernel_function_by_name(name, &map);
+ if (sym)
+ return map->unmap_ip(map, sym->start) -
+ (reloc) ? 0 : map->reloc;
+ }
+ return 0;
+}
+
static struct map *kernel_get_module_map(const char *module)
{
struct rb_node *nd;
- struct map_groups *grp = &machine.kmaps;
+ struct map_groups *grp = &host_machine->kmaps;
/* A file path -- this is an offline module */
if (module && strchr(module, '/'))
- return machine__new_module(&machine, 0, module);
+ return machine__new_module(host_machine, 0, module);
if (!module)
module = "kernel";
@@ -141,7 +184,7 @@ static struct dso *kernel_get_module_dso(const char *module)
const char *vmlinux_name;
if (module) {
- list_for_each_entry(dso, &machine.kernel_dsos, node) {
+ list_for_each_entry(dso, &host_machine->kernel_dsos, node) {
if (strncmp(dso->short_name + 1, module,
dso->short_name_len - 2) == 0)
goto found;
@@ -150,7 +193,7 @@ static struct dso *kernel_get_module_dso(const char *module)
return NULL;
}
- map = machine.vmlinux_maps[MAP__FUNCTION];
+ map = host_machine->vmlinux_maps[MAP__FUNCTION];
dso = map->dso;
vmlinux_name = symbol_conf.vmlinux_name;
@@ -173,20 +216,6 @@ const char *kernel_get_module_path(const char *module)
return (dso) ? dso->long_name : NULL;
}
-static int init_user_exec(void)
-{
- int ret = 0;
-
- symbol_conf.try_vmlinux_path = false;
- symbol_conf.sort_by_name = true;
- ret = symbol__init();
-
- if (ret < 0)
- pr_debug("Failed to init symbol map.\n");
-
- return ret;
-}
-
static int convert_exec_to_group(const char *exec, char **result)
{
char *ptr1, *ptr2, *exec_copy;
@@ -218,32 +247,23 @@ out:
return ret;
}
-static int convert_to_perf_probe_point(struct probe_trace_point *tp,
- struct perf_probe_point *pp)
+static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
{
- pp->function = strdup(tp->symbol);
-
- if (pp->function == NULL)
- return -ENOMEM;
-
- pp->offset = tp->offset;
- pp->retprobe = tp->retprobe;
+ int i;
- return 0;
+ for (i = 0; i < ntevs; i++)
+ clear_probe_trace_event(tevs + i);
}
#ifdef HAVE_DWARF_SUPPORT
+
/* Open new debuginfo of given module */
static struct debuginfo *open_debuginfo(const char *module)
{
- const char *path;
+ const char *path = module;
- /* A file path -- this is an offline module */
- if (module && strchr(module, '/'))
- path = module;
- else {
+ if (!module || !strchr(module, '/')) {
path = kernel_get_module_path(module);
-
if (!path) {
pr_err("Failed to find path of %s module.\n",
module ?: "kernel");
@@ -253,46 +273,6 @@ static struct debuginfo *open_debuginfo(const char *module)
return debuginfo__new(path);
}
-/*
- * Convert trace point to probe point with debuginfo
- * Currently only handles kprobes.
- */
-static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
- struct perf_probe_point *pp)
-{
- struct symbol *sym;
- struct map *map;
- u64 addr;
- int ret = -ENOENT;
- struct debuginfo *dinfo;
-
- sym = __find_kernel_function_by_name(tp->symbol, &map);
- if (sym) {
- addr = map->unmap_ip(map, sym->start + tp->offset);
- pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
- tp->offset, addr);
-
- dinfo = debuginfo__new_online_kernel(addr);
- if (dinfo) {
- ret = debuginfo__find_probe_point(dinfo,
- (unsigned long)addr, pp);
- debuginfo__delete(dinfo);
- } else {
- pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n",
- addr);
- ret = -ENOENT;
- }
- }
- if (ret <= 0) {
- pr_debug("Failed to find corresponding probes from "
- "debuginfo. Use kprobe event information.\n");
- return convert_to_perf_probe_point(tp, pp);
- }
- pp->retprobe = tp->retprobe;
-
- return 0;
-}
-
static int get_text_start_address(const char *exec, unsigned long *address)
{
Elf *elf;
@@ -321,12 +301,62 @@ out:
return ret;
}
+/*
+ * Convert trace point to probe point with debuginfo
+ */
+static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
+ struct perf_probe_point *pp,
+ bool is_kprobe)
+{
+ struct debuginfo *dinfo = NULL;
+ unsigned long stext = 0;
+ u64 addr = tp->address;
+ int ret = -ENOENT;
+
+ /* convert the address to dwarf address */
+ if (!is_kprobe) {
+ if (!addr) {
+ ret = -EINVAL;
+ goto error;
+ }
+ ret = get_text_start_address(tp->module, &stext);
+ if (ret < 0)
+ goto error;
+ addr += stext;
+ } else {
+ addr = kernel_get_symbol_address_by_name(tp->symbol, false);
+ if (addr == 0)
+ goto error;
+ addr += tp->offset;
+ }
+
+ pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
+ tp->module ? : "kernel");
+
+ dinfo = open_debuginfo(tp->module);
+ if (dinfo) {
+ ret = debuginfo__find_probe_point(dinfo,
+ (unsigned long)addr, pp);
+ debuginfo__delete(dinfo);
+ } else {
+ pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", addr);
+ ret = -ENOENT;
+ }
+
+ if (ret > 0) {
+ pp->retprobe = tp->retprobe;
+ return 0;
+ }
+error:
+ pr_debug("Failed to find corresponding probes from debuginfo.\n");
+ return ret ? : -ENOENT;
+}
+
static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
int ntevs, const char *exec)
{
int i, ret = 0;
- unsigned long offset, stext = 0;
- char buf[32];
+ unsigned long stext = 0;
if (!exec)
return 0;
@@ -336,16 +366,10 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
return ret;
for (i = 0; i < ntevs && ret >= 0; i++) {
- offset = tevs[i].point.address - stext;
- offset += tevs[i].point.offset;
- tevs[i].point.offset = 0;
- zfree(&tevs[i].point.symbol);
- ret = e_snprintf(buf, 32, "0x%lx", offset);
- if (ret < 0)
- break;
+ /* point.address is the addres of point.symbol + point.offset */
+ tevs[i].point.address -= stext;
tevs[i].point.module = strdup(exec);
- tevs[i].point.symbol = strdup(buf);
- if (!tevs[i].point.symbol || !tevs[i].point.module) {
+ if (!tevs[i].point.module) {
ret = -ENOMEM;
break;
}
@@ -388,12 +412,40 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
return ret;
}
-static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
+/* Post processing the probe events */
+static int post_process_probe_trace_events(struct probe_trace_event *tevs,
+ int ntevs, const char *module,
+ bool uprobe)
{
+ struct ref_reloc_sym *reloc_sym;
+ char *tmp;
int i;
- for (i = 0; i < ntevs; i++)
- clear_probe_trace_event(tevs + i);
+ if (uprobe)
+ return add_exec_to_probe_trace_events(tevs, ntevs, module);
+
+ /* Note that currently ref_reloc_sym based probe is not for drivers */
+ if (module)
+ return add_module_to_probe_trace_events(tevs, ntevs, module);
+
+ reloc_sym = kernel_get_ref_reloc_sym();
+ if (!reloc_sym) {
+ pr_warning("Relocated base symbol is not found!\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ntevs; i++) {
+ if (tevs[i].point.address) {
+ tmp = strdup(reloc_sym->name);
+ if (!tmp)
+ return -ENOMEM;
+ free(tevs[i].point.symbol);
+ tevs[i].point.symbol = tmp;
+ tevs[i].point.offset = tevs[i].point.address -
+ reloc_sym->unrelocated_addr;
+ }
+ }
+ return 0;
}
/* Try to find perf_probe_event with debuginfo */
@@ -416,21 +468,16 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
return 0;
}
+ pr_debug("Try to find probe point from debuginfo.\n");
/* Searching trace events corresponding to a probe event */
ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs);
debuginfo__delete(dinfo);
if (ntevs > 0) { /* Succeeded to find trace events */
- pr_debug("find %d probe_trace_events.\n", ntevs);
- if (target) {
- if (pev->uprobes)
- ret = add_exec_to_probe_trace_events(*tevs,
- ntevs, target);
- else
- ret = add_module_to_probe_trace_events(*tevs,
- ntevs, target);
- }
+ pr_debug("Found %d probe_trace_events.\n", ntevs);
+ ret = post_process_probe_trace_events(*tevs, ntevs,
+ target, pev->uprobes);
if (ret < 0) {
clear_probe_trace_events(*tevs, ntevs);
zfree(tevs);
@@ -563,20 +610,16 @@ static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
* Show line-range always requires debuginfo to find source file and
* line number.
*/
-int show_line_range(struct line_range *lr, const char *module)
+static int __show_line_range(struct line_range *lr, const char *module)
{
int l = 1;
- struct line_node *ln;
+ struct int_node *ln;
struct debuginfo *dinfo;
FILE *fp;
int ret;
char *tmp;
/* Search a line range */
- ret = init_vmlinux();
- if (ret < 0)
- return ret;
-
dinfo = open_debuginfo(module);
if (!dinfo) {
pr_warning("Failed to open debuginfo file.\n");
@@ -623,8 +666,8 @@ int show_line_range(struct line_range *lr, const char *module)
goto end;
}
- list_for_each_entry(ln, &lr->line_list, list) {
- for (; ln->line > l; l++) {
+ intlist__for_each(ln, lr->line_list) {
+ for (; ln->i > l; l++) {
ret = show_one_line(fp, l - lr->offset);
if (ret < 0)
goto end;
@@ -646,6 +689,19 @@ end:
return ret;
}
+int show_line_range(struct line_range *lr, const char *module)
+{
+ int ret;
+
+ ret = init_symbol_maps(false);
+ if (ret < 0)
+ return ret;
+ ret = __show_line_range(lr, module);
+ exit_symbol_maps();
+
+ return ret;
+}
+
static int show_available_vars_at(struct debuginfo *dinfo,
struct perf_probe_event *pev,
int max_vls, struct strfilter *_filter,
@@ -707,14 +763,15 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
int i, ret = 0;
struct debuginfo *dinfo;
- ret = init_vmlinux();
+ ret = init_symbol_maps(false);
if (ret < 0)
return ret;
dinfo = open_debuginfo(module);
if (!dinfo) {
pr_warning("Failed to open debuginfo file.\n");
- return -ENOENT;
+ ret = -ENOENT;
+ goto out;
}
setup_pager();
@@ -724,23 +781,19 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
externs);
debuginfo__delete(dinfo);
+out:
+ exit_symbol_maps();
return ret;
}
#else /* !HAVE_DWARF_SUPPORT */
-static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
- struct perf_probe_point *pp)
+static int
+find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused,
+ struct perf_probe_point *pp __maybe_unused,
+ bool is_kprobe __maybe_unused)
{
- struct symbol *sym;
-
- sym = __find_kernel_function_by_name(tp->symbol, NULL);
- if (!sym) {
- pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
- return -ENOENT;
- }
-
- return convert_to_perf_probe_point(tp, pp);
+ return -ENOSYS;
}
static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
@@ -776,24 +829,22 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
void line_range__clear(struct line_range *lr)
{
- struct line_node *ln;
-
free(lr->function);
free(lr->file);
free(lr->path);
free(lr->comp_dir);
- while (!list_empty(&lr->line_list)) {
- ln = list_first_entry(&lr->line_list, struct line_node, list);
- list_del(&ln->list);
- free(ln);
- }
+ intlist__delete(lr->line_list);
memset(lr, 0, sizeof(*lr));
}
-void line_range__init(struct line_range *lr)
+int line_range__init(struct line_range *lr)
{
memset(lr, 0, sizeof(*lr));
- INIT_LIST_HEAD(&lr->line_list);
+ lr->line_list = intlist__new(NULL);
+ if (!lr->line_list)
+ return -ENOMEM;
+ else
+ return 0;
}
static int parse_line_num(char **ptr, int *val, const char *what)
@@ -1267,16 +1318,21 @@ static int parse_probe_trace_command(const char *cmd,
} else
p = argv[1];
fmt1_str = strtok_r(p, "+", &fmt);
- tp->symbol = strdup(fmt1_str);
- if (tp->symbol == NULL) {
- ret = -ENOMEM;
- goto out;
+ if (fmt1_str[0] == '0') /* only the address started with 0x */
+ tp->address = strtoul(fmt1_str, NULL, 0);
+ else {
+ /* Only the symbol-based probe has offset */
+ tp->symbol = strdup(fmt1_str);
+ if (tp->symbol == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ fmt2_str = strtok_r(NULL, "", &fmt);
+ if (fmt2_str == NULL)
+ tp->offset = 0;
+ else
+ tp->offset = strtoul(fmt2_str, NULL, 10);
}
- fmt2_str = strtok_r(NULL, "", &fmt);
- if (fmt2_str == NULL)
- tp->offset = 0;
- else
- tp->offset = strtoul(fmt2_str, NULL, 10);
tev->nargs = argc - 2;
tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
@@ -1518,20 +1574,27 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
if (buf == NULL)
return NULL;
+ len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
+ tev->group, tev->event);
+ if (len <= 0)
+ goto error;
+
+ /* Uprobes must have tp->address and tp->module */
+ if (tev->uprobes && (!tp->address || !tp->module))
+ goto error;
+
+ /* Use the tp->address for uprobes */
if (tev->uprobes)
- len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
- tp->retprobe ? 'r' : 'p',
- tev->group, tev->event,
- tp->module, tp->symbol);
+ ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx",
+ tp->module, tp->address);
else
- len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
- tp->retprobe ? 'r' : 'p',
- tev->group, tev->event,
+ ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu",
tp->module ?: "", tp->module ? ":" : "",
tp->symbol, tp->offset);
- if (len <= 0)
+ if (ret <= 0)
goto error;
+ len += ret;
for (i = 0; i < tev->nargs; i++) {
ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
@@ -1547,6 +1610,79 @@ error:
return NULL;
}
+static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
+ struct perf_probe_point *pp,
+ bool is_kprobe)
+{
+ struct symbol *sym = NULL;
+ struct map *map;
+ u64 addr;
+ int ret = -ENOENT;
+
+ if (!is_kprobe) {
+ map = dso__new_map(tp->module);
+ if (!map)
+ goto out;
+ addr = tp->address;
+ sym = map__find_symbol(map, addr, NULL);
+ } else {
+ addr = kernel_get_symbol_address_by_name(tp->symbol, true);
+ if (addr) {
+ addr += tp->offset;
+ sym = __find_kernel_function(addr, &map);
+ }
+ }
+ if (!sym)
+ goto out;
+
+ pp->retprobe = tp->retprobe;
+ pp->offset = addr - map->unmap_ip(map, sym->start);
+ pp->function = strdup(sym->name);
+ ret = pp->function ? 0 : -ENOMEM;
+
+out:
+ if (map && !is_kprobe) {
+ dso__delete(map->dso);
+ map__delete(map);
+ }
+
+ return ret;
+}
+
+static int convert_to_perf_probe_point(struct probe_trace_point *tp,
+ struct perf_probe_point *pp,
+ bool is_kprobe)
+{
+ char buf[128];
+ int ret;
+
+ ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe);
+ if (!ret)
+ return 0;
+ ret = find_perf_probe_point_from_map(tp, pp, is_kprobe);
+ if (!ret)
+ return 0;
+
+ pr_debug("Failed to find probe point from both of dwarf and map.\n");
+
+ if (tp->symbol) {
+ pp->function = strdup(tp->symbol);
+ pp->offset = tp->offset;
+ } else if (!tp->module && !is_kprobe) {
+ ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address);
+ if (ret < 0)
+ return ret;
+ pp->function = strdup(buf);
+ pp->offset = 0;
+ }
+ if (pp->function == NULL)
+ return -ENOMEM;
+
+ pp->retprobe = tp->retprobe;
+
+ return 0;
+}
+
static int convert_to_perf_probe_event(struct probe_trace_event *tev,
struct perf_probe_event *pev, bool is_kprobe)
{
@@ -1560,11 +1696,7 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
return -ENOMEM;
/* Convert trace_point to probe_point */
- if (is_kprobe)
- ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
- else
- ret = convert_to_perf_probe_point(&tev->point, &pev->point);
-
+ ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe);
if (ret < 0)
return ret;
@@ -1731,7 +1863,8 @@ static struct strlist *get_probe_trace_command_rawlist(int fd)
}
/* Show an event */
-static int show_perf_probe_event(struct perf_probe_event *pev)
+static int show_perf_probe_event(struct perf_probe_event *pev,
+ const char *module)
{
int i, ret;
char buf[128];
@@ -1747,6 +1880,8 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
return ret;
printf(" %-20s (on %s", buf, place);
+ if (module)
+ printf(" in %s", module);
if (pev->nargs > 0) {
printf(" with");
@@ -1784,7 +1919,8 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
ret = convert_to_perf_probe_event(&tev, &pev,
is_kprobe);
if (ret >= 0)
- ret = show_perf_probe_event(&pev);
+ ret = show_perf_probe_event(&pev,
+ tev.point.module);
}
clear_perf_probe_event(&pev);
clear_probe_trace_event(&tev);
@@ -1807,7 +1943,7 @@ int show_perf_probe_events(void)
if (fd < 0)
return fd;
- ret = init_vmlinux();
+ ret = init_symbol_maps(false);
if (ret < 0)
return ret;
@@ -1820,6 +1956,7 @@ int show_perf_probe_events(void)
close(fd);
}
+ exit_symbol_maps();
return ret;
}
@@ -1982,7 +2119,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
group = pev->group;
pev->event = tev->event;
pev->group = tev->group;
- show_perf_probe_event(pev);
+ show_perf_probe_event(pev, tev->point.module);
/* Trick here - restore current event/group */
pev->event = (char *)event;
pev->group = (char *)group;
@@ -2008,113 +2145,175 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
return ret;
}
-static int convert_to_probe_trace_events(struct perf_probe_event *pev,
- struct probe_trace_event **tevs,
- int max_tevs, const char *target)
+static char *looking_function_name;
+static int num_matched_functions;
+
+static int probe_function_filter(struct map *map __maybe_unused,
+ struct symbol *sym)
{
+ if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
+ strcmp(looking_function_name, sym->name) == 0) {
+ num_matched_functions++;
+ return 0;
+ }
+ return 1;
+}
+
+#define strdup_or_goto(str, label) \
+ ({ char *__p = strdup(str); if (!__p) goto label; __p; })
+
+/*
+ * Find probe function addresses from map.
+ * Return an error or the number of found probe_trace_event
+ */
+static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
+ struct probe_trace_event **tevs,
+ int max_tevs, const char *target)
+{
+ struct map *map = NULL;
+ struct kmap *kmap = NULL;
+ struct ref_reloc_sym *reloc_sym = NULL;
struct symbol *sym;
- int ret, i;
+ struct rb_node *nd;
struct probe_trace_event *tev;
+ struct perf_probe_point *pp = &pev->point;
+ struct probe_trace_point *tp;
+ int ret, i;
- if (pev->uprobes && !pev->group) {
- /* Replace group name if not given */
- ret = convert_exec_to_group(target, &pev->group);
- if (ret != 0) {
- pr_warning("Failed to make a group name.\n");
- return ret;
- }
+ /* Init maps of given executable or kernel */
+ if (pev->uprobes)
+ map = dso__new_map(target);
+ else
+ map = kernel_get_module_map(target);
+ if (!map) {
+ ret = -EINVAL;
+ goto out;
}
- /* Convert perf_probe_event with debuginfo */
- ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
- if (ret != 0)
- return ret; /* Found in debuginfo or got an error */
-
- if (pev->uprobes) {
- ret = convert_name_to_addr(pev, target);
- if (ret < 0)
- return ret;
+ /*
+ * Load matched symbols: Since the different local symbols may have
+ * same name but different addresses, this lists all the symbols.
+ */
+ num_matched_functions = 0;
+ looking_function_name = pp->function;
+ ret = map__load(map, probe_function_filter);
+ if (ret || num_matched_functions == 0) {
+ pr_err("Failed to find symbol %s in %s\n", pp->function,
+ target ? : "kernel");
+ ret = -ENOENT;
+ goto out;
+ } else if (num_matched_functions > max_tevs) {
+ pr_err("Too many functions matched in %s\n",
+ target ? : "kernel");
+ ret = -E2BIG;
+ goto out;
}
- /* Allocate trace event buffer */
- tev = *tevs = zalloc(sizeof(struct probe_trace_event));
- if (tev == NULL)
- return -ENOMEM;
+ if (!pev->uprobes) {
+ kmap = map__kmap(map);
+ reloc_sym = kmap->ref_reloc_sym;
+ if (!reloc_sym) {
+ pr_warning("Relocated base symbol is not found!\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ }
- /* Copy parameters */
- tev->point.symbol = strdup(pev->point.function);
- if (tev->point.symbol == NULL) {
+ /* Setup result trace-probe-events */
+ *tevs = zalloc(sizeof(*tev) * num_matched_functions);
+ if (!*tevs) {
ret = -ENOMEM;
- goto error;
+ goto out;
}
- if (target) {
- tev->point.module = strdup(target);
- if (tev->point.module == NULL) {
- ret = -ENOMEM;
- goto error;
+ ret = 0;
+ map__for_each_symbol(map, sym, nd) {
+ tev = (*tevs) + ret;
+ tp = &tev->point;
+ if (ret == num_matched_functions) {
+ pr_warning("Too many symbols are listed. Skip it.\n");
+ break;
}
- }
-
- tev->point.offset = pev->point.offset;
- tev->point.retprobe = pev->point.retprobe;
- tev->nargs = pev->nargs;
- tev->uprobes = pev->uprobes;
+ ret++;
- if (tev->nargs) {
- tev->args = zalloc(sizeof(struct probe_trace_arg)
- * tev->nargs);
- if (tev->args == NULL) {
- ret = -ENOMEM;
- goto error;
+ if (pp->offset > sym->end - sym->start) {
+ pr_warning("Offset %ld is bigger than the size of %s\n",
+ pp->offset, sym->name);
+ ret = -ENOENT;
+ goto err_out;
+ }
+ /* Add one probe point */
+ tp->address = map->unmap_ip(map, sym->start) + pp->offset;
+ if (reloc_sym) {
+ tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out);
+ tp->offset = tp->address - reloc_sym->addr;
+ } else {
+ tp->symbol = strdup_or_goto(sym->name, nomem_out);
+ tp->offset = pp->offset;
+ }
+ tp->retprobe = pp->retprobe;
+ if (target)
+ tev->point.module = strdup_or_goto(target, nomem_out);
+ tev->uprobes = pev->uprobes;
+ tev->nargs = pev->nargs;
+ if (tev->nargs) {
+ tev->args = zalloc(sizeof(struct probe_trace_arg) *
+ tev->nargs);
+ if (tev->args == NULL)
+ goto nomem_out;
}
for (i = 0; i < tev->nargs; i++) {
- if (pev->args[i].name) {
- tev->args[i].name = strdup(pev->args[i].name);
- if (tev->args[i].name == NULL) {
- ret = -ENOMEM;
- goto error;
- }
- }
- tev->args[i].value = strdup(pev->args[i].var);
- if (tev->args[i].value == NULL) {
- ret = -ENOMEM;
- goto error;
- }
- if (pev->args[i].type) {
- tev->args[i].type = strdup(pev->args[i].type);
- if (tev->args[i].type == NULL) {
- ret = -ENOMEM;
- goto error;
- }
- }
+ if (pev->args[i].name)
+ tev->args[i].name =
+ strdup_or_goto(pev->args[i].name,
+ nomem_out);
+
+ tev->args[i].value = strdup_or_goto(pev->args[i].var,
+ nomem_out);
+ if (pev->args[i].type)
+ tev->args[i].type =
+ strdup_or_goto(pev->args[i].type,
+ nomem_out);
}
}
- if (pev->uprobes)
- return 1;
+out:
+ if (map && pev->uprobes) {
+ /* Only when using uprobe(exec) map needs to be released */
+ dso__delete(map->dso);
+ map__delete(map);
+ }
+ return ret;
- /* Currently just checking function name from symbol map */
- sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
- if (!sym) {
- pr_warning("Kernel symbol \'%s\' not found.\n",
- tev->point.symbol);
- ret = -ENOENT;
- goto error;
- } else if (tev->point.offset > sym->end - sym->start) {
- pr_warning("Offset specified is greater than size of %s\n",
- tev->point.symbol);
- ret = -ENOENT;
- goto error;
+nomem_out:
+ ret = -ENOMEM;
+err_out:
+ clear_probe_trace_events(*tevs, num_matched_functions);
+ zfree(tevs);
+ goto out;
+}
+
+static int convert_to_probe_trace_events(struct perf_probe_event *pev,
+ struct probe_trace_event **tevs,
+ int max_tevs, const char *target)
+{
+ int ret;
+ if (pev->uprobes && !pev->group) {
+ /* Replace group name if not given */
+ ret = convert_exec_to_group(target, &pev->group);
+ if (ret != 0) {
+ pr_warning("Failed to make a group name.\n");
+ return ret;
+ }
}
- return 1;
-error:
- clear_probe_trace_event(tev);
- free(tev);
- *tevs = NULL;
- return ret;
+ /* Convert perf_probe_event with debuginfo */
+ ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
+ if (ret != 0)
+ return ret; /* Found in debuginfo or got an error */
+
+ return find_probe_trace_events_from_map(pev, tevs, max_tevs, target);
}
struct __event_package {
@@ -2135,12 +2334,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
if (pkgs == NULL)
return -ENOMEM;
- if (!pevs->uprobes)
- /* Init vmlinux path */
- ret = init_vmlinux();
- else
- ret = init_user_exec();
-
+ ret = init_symbol_maps(pevs->uprobes);
if (ret < 0) {
free(pkgs);
return ret;
@@ -2174,6 +2368,7 @@ end:
zfree(&pkgs[i].tevs);
}
free(pkgs);
+ exit_symbol_maps();
return ret;
}
@@ -2323,159 +2518,51 @@ static struct strfilter *available_func_filter;
static int filter_available_functions(struct map *map __maybe_unused,
struct symbol *sym)
{
- if (sym->binding == STB_GLOBAL &&
+ if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
strfilter__compare(available_func_filter, sym->name))
return 0;
return 1;
}
-static int __show_available_funcs(struct map *map)
-{
- if (map__load(map, filter_available_functions)) {
- pr_err("Failed to load map.\n");
- return -EINVAL;
- }
- if (!dso__sorted_by_name(map->dso, map->type))
- dso__sort_by_name(map->dso, map->type);
-
- dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
- return 0;
-}
-
-static int available_kernel_funcs(const char *module)
+int show_available_funcs(const char *target, struct strfilter *_filter,
+ bool user)
{
struct map *map;
int ret;
- ret = init_vmlinux();
+ ret = init_symbol_maps(user);
if (ret < 0)
return ret;
- map = kernel_get_module_map(module);
+ /* Get a symbol map */
+ if (user)
+ map = dso__new_map(target);
+ else
+ map = kernel_get_module_map(target);
if (!map) {
- pr_err("Failed to find %s map.\n", (module) ? : "kernel");
+ pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
return -EINVAL;
}
- return __show_available_funcs(map);
-}
-
-static int available_user_funcs(const char *target)
-{
- struct map *map;
- int ret;
-
- ret = init_user_exec();
- if (ret < 0)
- return ret;
-
- map = dso__new_map(target);
- ret = __show_available_funcs(map);
- dso__delete(map->dso);
- map__delete(map);
- return ret;
-}
-int show_available_funcs(const char *target, struct strfilter *_filter,
- bool user)
-{
- setup_pager();
+ /* Load symbols with given filter */
available_func_filter = _filter;
-
- if (!user)
- return available_kernel_funcs(target);
-
- return available_user_funcs(target);
-}
-
-/*
- * uprobe_events only accepts address:
- * Convert function and any offset to address
- */
-static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
-{
- struct perf_probe_point *pp = &pev->point;
- struct symbol *sym;
- struct map *map = NULL;
- char *function = NULL;
- int ret = -EINVAL;
- unsigned long long vaddr = 0;
-
- if (!pp->function) {
- pr_warning("No function specified for uprobes");
- goto out;
- }
-
- function = strdup(pp->function);
- if (!function) {
- pr_warning("Failed to allocate memory by strdup.\n");
- ret = -ENOMEM;
- goto out;
- }
-
- map = dso__new_map(exec);
- if (!map) {
- pr_warning("Cannot find appropriate DSO for %s.\n", exec);
- goto out;
- }
- available_func_filter = strfilter__new(function, NULL);
if (map__load(map, filter_available_functions)) {
- pr_err("Failed to load map.\n");
- goto out;
- }
-
- sym = map__find_symbol_by_name(map, function, NULL);
- if (!sym) {
- pr_warning("Cannot find %s in DSO %s\n", function, exec);
- goto out;
- }
-
- if (map->start > sym->start)
- vaddr = map->start;
- vaddr += sym->start + pp->offset + map->pgoff;
- pp->offset = 0;
-
- if (!pev->event) {
- pev->event = function;
- function = NULL;
- }
- if (!pev->group) {
- char *ptr1, *ptr2, *exec_copy;
-
- pev->group = zalloc(sizeof(char *) * 64);
- exec_copy = strdup(exec);
- if (!exec_copy) {
- ret = -ENOMEM;
- pr_warning("Failed to copy exec string.\n");
- goto out;
- }
-
- ptr1 = strdup(basename(exec_copy));
- if (ptr1) {
- ptr2 = strpbrk(ptr1, "-._");
- if (ptr2)
- *ptr2 = '\0';
- e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
- ptr1);
- free(ptr1);
- }
- free(exec_copy);
- }
- free(pp->function);
- pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
- if (!pp->function) {
- ret = -ENOMEM;
- pr_warning("Failed to allocate memory by zalloc.\n");
- goto out;
+ pr_err("Failed to load symbols in %s\n", (target) ? : "kernel");
+ goto end;
}
- e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
- ret = 0;
+ if (!dso__sorted_by_name(map->dso, map->type))
+ dso__sort_by_name(map->dso, map->type);
-out:
- if (map) {
+ /* Show all (filtered) symbols */
+ setup_pager();
+ dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
+end:
+ if (user) {
dso__delete(map->dso);
map__delete(map);
}
- if (function)
- free(function);
+ exit_symbol_maps();
+
return ret;
}
+
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index fcaf7273e85a..776c9347a3b6 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -2,6 +2,7 @@
#define _PROBE_EVENT_H
#include <stdbool.h>
+#include "intlist.h"
#include "strlist.h"
#include "strfilter.h"
@@ -76,13 +77,6 @@ struct perf_probe_event {
struct perf_probe_arg *args; /* Arguments */
};
-
-/* Line number container */
-struct line_node {
- struct list_head list;
- int line;
-};
-
/* Line range */
struct line_range {
char *file; /* File name */
@@ -92,7 +86,7 @@ struct line_range {
int offset; /* Start line offset */
char *path; /* Real path name */
char *comp_dir; /* Compile directory */
- struct list_head line_list; /* Visible lines */
+ struct intlist *line_list; /* Visible lines */
};
/* List of variables */
@@ -124,7 +118,7 @@ extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
extern void line_range__clear(struct line_range *lr);
/* Initialize line range */
-extern void line_range__init(struct line_range *lr);
+extern int line_range__init(struct line_range *lr);
/* Internal use: Return kernel/module path */
extern const char *kernel_get_module_path(const char *module);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 061edb162b5b..df0238654698 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -34,7 +34,9 @@
#include <linux/bitops.h>
#include "event.h"
+#include "dso.h"
#include "debug.h"
+#include "intlist.h"
#include "util.h"
#include "symbol.h"
#include "probe-finder.h"
@@ -42,65 +44,6 @@
/* Kprobe tracer basic type is up to u64 */
#define MAX_BASIC_TYPE_BITS 64
-/* Line number list operations */
-
-/* Add a line to line number list */
-static int line_list__add_line(struct list_head *head, int line)
-{
- struct line_node *ln;
- struct list_head *p;
-
- /* Reverse search, because new line will be the last one */
- list_for_each_entry_reverse(ln, head, list) {
- if (ln->line < line) {
- p = &ln->list;
- goto found;
- } else if (ln->line == line) /* Already exist */
- return 1;
- }
- /* List is empty, or the smallest entry */
- p = head;
-found:
- pr_debug("line list: add a line %u\n", line);
- ln = zalloc(sizeof(struct line_node));
- if (ln == NULL)
- return -ENOMEM;
- ln->line = line;
- INIT_LIST_HEAD(&ln->list);
- list_add(&ln->list, p);
- return 0;
-}
-
-/* Check if the line in line number list */
-static int line_list__has_line(struct list_head *head, int line)
-{
- struct line_node *ln;
-
- /* Reverse search, because new line will be the last one */
- list_for_each_entry(ln, head, list)
- if (ln->line == line)
- return 1;
-
- return 0;
-}
-
-/* Init line number list */
-static void line_list__init(struct list_head *head)
-{
- INIT_LIST_HEAD(head);
-}
-
-/* Free line number list */
-static void line_list__free(struct list_head *head)
-{
- struct line_node *ln;
- while (!list_empty(head)) {
- ln = list_first_entry(head, struct line_node, list);
- list_del(&ln->list);
- free(ln);
- }
-}
-
/* Dwarf FL wrappers */
static char *debuginfo_path; /* Currently dummy */
@@ -147,80 +90,7 @@ error:
return -ENOENT;
}
-#if _ELFUTILS_PREREQ(0, 148)
-/* This method is buggy if elfutils is older than 0.148 */
-static int __linux_kernel_find_elf(Dwfl_Module *mod,
- void **userdata,
- const char *module_name,
- Dwarf_Addr base,
- char **file_name, Elf **elfp)
-{
- int fd;
- const char *path = kernel_get_module_path(module_name);
-
- pr_debug2("Use file %s for %s\n", path, module_name);
- if (path) {
- fd = open(path, O_RDONLY);
- if (fd >= 0) {
- *file_name = strdup(path);
- return fd;
- }
- }
- /* If failed, try to call standard method */
- return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
- file_name, elfp);
-}
-
-static const Dwfl_Callbacks kernel_callbacks = {
- .find_debuginfo = dwfl_standard_find_debuginfo,
- .debuginfo_path = &debuginfo_path,
-
- .find_elf = __linux_kernel_find_elf,
- .section_address = dwfl_linux_kernel_module_section_address,
-};
-
-/* Get a Dwarf from live kernel image */
-static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
- Dwarf_Addr addr)
-{
- dbg->dwfl = dwfl_begin(&kernel_callbacks);
- if (!dbg->dwfl)
- return -EINVAL;
-
- /* Load the kernel dwarves: Don't care the result here */
- dwfl_linux_kernel_report_kernel(dbg->dwfl);
- dwfl_linux_kernel_report_modules(dbg->dwfl);
-
- dbg->dbg = dwfl_addrdwarf(dbg->dwfl, addr, &dbg->bias);
- /* Here, check whether we could get a real dwarf */
- if (!dbg->dbg) {
- pr_debug("Failed to find kernel dwarf at %lx\n",
- (unsigned long)addr);
- dwfl_end(dbg->dwfl);
- memset(dbg, 0, sizeof(*dbg));
- return -ENOENT;
- }
-
- return 0;
-}
-#else
-/* With older elfutils, this just support kernel module... */
-static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
- Dwarf_Addr addr __maybe_unused)
-{
- const char *path = kernel_get_module_path("kernel");
-
- if (!path) {
- pr_err("Failed to find vmlinux path\n");
- return -ENOENT;
- }
-
- pr_debug2("Use file %s for debuginfo\n", path);
- return debuginfo__init_offline_dwarf(dbg, path);
-}
-#endif
-
-struct debuginfo *debuginfo__new(const char *path)
+static struct debuginfo *__debuginfo__new(const char *path)
{
struct debuginfo *dbg = zalloc(sizeof(*dbg));
if (!dbg)
@@ -228,21 +98,44 @@ struct debuginfo *debuginfo__new(const char *path)
if (debuginfo__init_offline_dwarf(dbg, path) < 0)
zfree(&dbg);
-
+ if (dbg)
+ pr_debug("Open Debuginfo file: %s\n", path);
return dbg;
}
-struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
-{
- struct debuginfo *dbg = zalloc(sizeof(*dbg));
+enum dso_binary_type distro_dwarf_types[] = {
+ DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
+ DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
+ DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
+ DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
+ DSO_BINARY_TYPE__NOT_FOUND,
+};
- if (!dbg)
- return NULL;
+struct debuginfo *debuginfo__new(const char *path)
+{
+ enum dso_binary_type *type;
+ char buf[PATH_MAX], nil = '\0';
+ struct dso *dso;
+ struct debuginfo *dinfo = NULL;
+
+ /* Try to open distro debuginfo files */
+ dso = dso__new(path);
+ if (!dso)
+ goto out;
- if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0)
- zfree(&dbg);
+ for (type = distro_dwarf_types;
+ !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;
+ type++) {
+ if (dso__read_binary_type_filename(dso, *type, &nil,
+ buf, PATH_MAX) < 0)
+ continue;
+ dinfo = __debuginfo__new(buf);
+ }
+ dso__delete(dso);
- return dbg;
+out:
+ /* if failed to open all distro debuginfo, open given binary */
+ return dinfo ? : __debuginfo__new(path);
}
void debuginfo__delete(struct debuginfo *dbg)
@@ -880,7 +773,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
}
/* Find lines which match lazy pattern */
-static int find_lazy_match_lines(struct list_head *head,
+static int find_lazy_match_lines(struct intlist *list,
const char *fname, const char *pat)
{
FILE *fp;
@@ -901,7 +794,7 @@ static int find_lazy_match_lines(struct list_head *head,
line[len - 1] = '\0';
if (strlazymatch(line, pat)) {
- line_list__add_line(head, linenum);
+ intlist__add(list, linenum);
count++;
}
linenum++;
@@ -924,7 +817,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
Dwarf_Die *sc_die, die_mem;
int ret;
- if (!line_list__has_line(&pf->lcache, lineno) ||
+ if (!intlist__has_entry(pf->lcache, lineno) ||
strtailcmp(fname, pf->fname) != 0)
return 0;
@@ -952,9 +845,9 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
{
int ret = 0;
- if (list_empty(&pf->lcache)) {
+ if (intlist__empty(pf->lcache)) {
/* Matching lazy line pattern */
- ret = find_lazy_match_lines(&pf->lcache, pf->fname,
+ ret = find_lazy_match_lines(pf->lcache, pf->fname,
pf->pev->point.lazy_line);
if (ret <= 0)
return ret;
@@ -1096,7 +989,9 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
#endif
off = 0;
- line_list__init(&pf->lcache);
+ pf->lcache = intlist__new(NULL);
+ if (!pf->lcache)
+ return -ENOMEM;
/* Fastpath: lookup by function name from .debug_pubnames section */
if (pp->function) {
@@ -1149,7 +1044,8 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
}
found:
- line_list__free(&pf->lcache);
+ intlist__delete(pf->lcache);
+ pf->lcache = NULL;
return ret;
}
@@ -1537,7 +1433,7 @@ static int line_range_add_line(const char *src, unsigned int lineno,
if (lr->path == NULL)
return -ENOMEM;
}
- return line_list__add_line(&lr->line_list, lineno);
+ return intlist__add(lr->line_list, lineno);
}
static int line_range_walk_cb(const char *fname, int lineno,
@@ -1565,7 +1461,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
/* Update status */
if (ret >= 0)
- if (!list_empty(&lf->lr->line_list))
+ if (!intlist__empty(lf->lr->line_list))
ret = lf->found = 1;
else
ret = 0; /* Lines are not found */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index ffc33cdd25cc..92590b2c7e1c 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -3,6 +3,7 @@
#include <stdbool.h>
#include "util.h"
+#include "intlist.h"
#include "probe-event.h"
#define MAX_PROBE_BUFFER 1024
@@ -29,8 +30,8 @@ struct debuginfo {
Dwarf_Addr bias;
};
+/* This also tries to open distro debuginfo */
extern struct debuginfo *debuginfo__new(const char *path);
-extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr);
extern void debuginfo__delete(struct debuginfo *dbg);
/* Find probe_trace_events specified by perf_probe_event from debuginfo */
@@ -66,7 +67,7 @@ struct probe_finder {
const char *fname; /* Real file name */
Dwarf_Die cu_die; /* Current CU */
Dwarf_Die sp_die;
- struct list_head lcache; /* Line cache for lazy match */
+ struct intlist *lcache; /* Line cache for lazy match */
/* For variable searching */
#if _ELFUTILS_PREREQ(0, 142)
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 595bfc73d2ed..16a475a7d492 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -17,6 +17,6 @@ util/xyarray.c
util/cgroup.c
util/rblist.c
util/strlist.c
-util/fs.c
+../lib/api/fs/fs.c
util/trace-event.c
../../lib/rbtree.c
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 373762501dad..049e0a09ccd3 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -2,7 +2,7 @@
#include "evsel.h"
#include "cpumap.h"
#include "parse-events.h"
-#include "fs.h"
+#include <api/fs/fs.h>
#include "util.h"
typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 0b39a48e5110..55960f22233c 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -702,11 +702,12 @@ static void regs_dump__printf(u64 mask, u64 *regs)
}
}
-static void regs_user__printf(struct perf_sample *sample, u64 mask)
+static void regs_user__printf(struct perf_sample *sample)
{
struct regs_dump *user_regs = &sample->user_regs;
if (user_regs->regs) {
+ u64 mask = user_regs->mask;
printf("... user regs: mask 0x%" PRIx64 "\n", mask);
regs_dump__printf(mask, user_regs->regs);
}
@@ -793,7 +794,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
if (!dump_trace)
return;
- printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n",
+ printf("(IP, 0x%x): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n",
event->header.misc, sample->pid, sample->tid, sample->ip,
sample->period, sample->addr);
@@ -806,7 +807,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
branch_stack__printf(sample);
if (sample_type & PERF_SAMPLE_REGS_USER)
- regs_user__printf(sample, evsel->attr.sample_regs_user);
+ regs_user__printf(sample);
if (sample_type & PERF_SAMPLE_STACK_USER)
stack_user__printf(&sample->user_stack);
@@ -1008,6 +1009,12 @@ static int perf_session__process_user_event(struct perf_session *session, union
if (err == 0)
perf_session__set_id_hdr_size(session);
return err;
+ case PERF_RECORD_HEADER_EVENT_TYPE:
+ /*
+ * Depreceated, but we need to handle it for sake
+ * of old data files create in pipe mode.
+ */
+ return 0;
case PERF_RECORD_HEADER_TRACING_DATA:
/* setup for reading amidst mmap */
lseek(fd, file_offset, SEEK_SET);
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 3e9f336740fa..3b7dbf51d4a9 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -151,15 +151,15 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
gelf_getshdr(sec, shp);
str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
- if (!strcmp(name, str)) {
+ if (str && !strcmp(name, str)) {
if (idx)
*idx = cnt;
- break;
+ return sec;
}
++cnt;
}
- return sec;
+ return NULL;
}
#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
@@ -506,6 +506,8 @@ int filename__read_debuglink(const char *filename, char *debuglink,
/* the start of this section is a zero-terminated string */
strncpy(debuglink, data->d_buf, size);
+ err = 0;
+
out_elf_end:
elf_end(elf);
out_close:
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index a9d758a3b371..95e249779931 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -410,7 +410,7 @@ struct symbol *dso__find_symbol(struct dso *dso,
return symbols__find(&dso->symbols[type], addr);
}
-struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
+static struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
{
return symbols__first(&dso->symbols[type]);
}
@@ -1251,6 +1251,46 @@ out_failure:
return -1;
}
+static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
+ enum dso_binary_type type)
+{
+ switch (type) {
+ case DSO_BINARY_TYPE__JAVA_JIT:
+ case DSO_BINARY_TYPE__DEBUGLINK:
+ case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
+ case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
+ case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
+ case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
+ case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
+ return !kmod && dso->kernel == DSO_TYPE_USER;
+
+ case DSO_BINARY_TYPE__KALLSYMS:
+ case DSO_BINARY_TYPE__VMLINUX:
+ case DSO_BINARY_TYPE__KCORE:
+ return dso->kernel == DSO_TYPE_KERNEL;
+
+ case DSO_BINARY_TYPE__GUEST_KALLSYMS:
+ case DSO_BINARY_TYPE__GUEST_VMLINUX:
+ case DSO_BINARY_TYPE__GUEST_KCORE:
+ return dso->kernel == DSO_TYPE_GUEST_KERNEL;
+
+ case DSO_BINARY_TYPE__GUEST_KMODULE:
+ case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+ /*
+ * kernel modules know their symtab type - it's set when
+ * creating a module dso in machine__new_module().
+ */
+ return kmod && dso->symtab_type == type;
+
+ case DSO_BINARY_TYPE__BUILD_ID_CACHE:
+ return true;
+
+ case DSO_BINARY_TYPE__NOT_FOUND:
+ default:
+ return false;
+ }
+}
+
int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
{
char *name;
@@ -1261,6 +1301,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
int ss_pos = 0;
struct symsrc ss_[2];
struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
+ bool kmod;
dso__set_loaded(dso, map->type);
@@ -1301,7 +1342,11 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
if (!name)
return -1;
- /* Iterate over candidate debug images.
+ kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
+ dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
+
+ /*
+ * Iterate over candidate debug images.
* Keep track of "interesting" ones (those which have a symtab, dynsym,
* and/or opd section) for processing.
*/
@@ -1311,6 +1356,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
enum dso_binary_type symtab_type = binary_type_symtab[i];
+ if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
+ continue;
+
if (dso__read_binary_type_filename(dso, symtab_type,
root_dir, name, PATH_MAX))
continue;
@@ -1336,6 +1384,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
if (syms_ss && runtime_ss)
break;
+ } else {
+ symsrc__destroy(ss);
}
}
@@ -1351,15 +1401,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
if (!runtime_ss && syms_ss)
runtime_ss = syms_ss;
- if (syms_ss) {
- int km;
-
- km = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
- dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
- ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, km);
- } else {
+ if (syms_ss)
+ ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
+ else
ret = -1;
- }
if (ret > 0) {
int nr_plt;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index fffe2888a1c7..501e4e722e8e 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -79,6 +79,17 @@ struct symbol {
void symbol__delete(struct symbol *sym);
void symbols__delete(struct rb_root *symbols);
+/* symbols__for_each_entry - iterate over symbols (rb_root)
+ *
+ * @symbols: the rb_root of symbols
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @nd: the 'struct rb_node *' to use as a temporary storage
+ */
+#define symbols__for_each_entry(symbols, pos, nd) \
+ for (nd = rb_first(symbols); \
+ nd && (pos = rb_entry(nd, struct symbol, rb_node)); \
+ nd = rb_next(nd))
+
static inline size_t symbol__size(const struct symbol *sym)
{
return sym->end - sym->start + 1;
@@ -175,7 +186,7 @@ struct addr_location {
struct symbol *sym;
u64 addr;
char level;
- bool filtered;
+ u8 filtered;
u8 cpumode;
s32 cpu;
};
@@ -223,7 +234,6 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
u64 addr);
struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
const char *name);
-struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
int filename__read_build_id(const char *filename, void *bf, size_t size);
int sysfs__read_build_id(const char *filename, void *bf, size_t size);
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 0358882c8910..3ce0498bdae6 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -142,3 +142,24 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
return 0;
}
+
+void thread__find_cpumode_addr_location(struct thread *thread,
+ struct machine *machine,
+ enum map_type type, u64 addr,
+ struct addr_location *al)
+{
+ size_t i;
+ const u8 const cpumodes[] = {
+ PERF_RECORD_MISC_USER,
+ PERF_RECORD_MISC_KERNEL,
+ PERF_RECORD_MISC_GUEST_USER,
+ PERF_RECORD_MISC_GUEST_KERNEL
+ };
+
+ for (i = 0; i < ARRAY_SIZE(cpumodes); i++) {
+ thread__find_addr_location(thread, machine, cpumodes[i], type,
+ addr, al);
+ if (al->map)
+ break;
+ }
+}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 5b856bf942e1..9b29f085aede 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -44,12 +44,6 @@ void thread__insert_map(struct thread *thread, struct map *map);
int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
size_t thread__fprintf(struct thread *thread, FILE *fp);
-static inline struct map *thread__find_map(struct thread *thread,
- enum map_type type, u64 addr)
-{
- return thread ? map_groups__find(&thread->mg, type, addr) : NULL;
-}
-
void thread__find_addr_map(struct thread *thread, struct machine *machine,
u8 cpumode, enum map_type type, u64 addr,
struct addr_location *al);
@@ -58,6 +52,11 @@ void thread__find_addr_location(struct thread *thread, struct machine *machine,
u8 cpumode, enum map_type type, u64 addr,
struct addr_location *al);
+void thread__find_cpumode_addr_location(struct thread *thread,
+ struct machine *machine,
+ enum map_type type, u64 addr,
+ struct addr_location *al);
+
static inline void *thread__priv(struct thread *thread)
{
return thread->priv;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index e0d6d07f6848..c36636fd825b 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -126,6 +126,7 @@ void event_format__print(struct event_format *event,
trace_seq_init(&s);
pevent_event_info(&s, event, &record);
trace_seq_do_printf(&s);
+ trace_seq_destroy(&s);
}
void parse_proc_kallsyms(struct pevent *pevent,
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
new file mode 100644
index 000000000000..67db73ec3dab
--- /dev/null
+++ b/tools/perf/util/unwind-libdw.c
@@ -0,0 +1,210 @@
+#include <linux/compiler.h>
+#include <elfutils/libdw.h>
+#include <elfutils/libdwfl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include "unwind.h"
+#include "unwind-libdw.h"
+#include "machine.h"
+#include "thread.h"
+#include "types.h"
+#include "event.h"
+#include "perf_regs.h"
+
+static char *debuginfo_path;
+
+static const Dwfl_Callbacks offline_callbacks = {
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .debuginfo_path = &debuginfo_path,
+ .section_address = dwfl_offline_section_address,
+};
+
+static int __report_module(struct addr_location *al, u64 ip,
+ struct unwind_info *ui)
+{
+ Dwfl_Module *mod;
+ struct dso *dso = NULL;
+
+ thread__find_addr_location(ui->thread, ui->machine,
+ PERF_RECORD_MISC_USER,
+ MAP__FUNCTION, ip, al);
+
+ if (al->map)
+ dso = al->map->dso;
+
+ if (!dso)
+ return 0;
+
+ mod = dwfl_addrmodule(ui->dwfl, ip);
+ if (!mod)
+ mod = dwfl_report_elf(ui->dwfl, dso->short_name,
+ dso->long_name, -1, al->map->start,
+ false);
+
+ return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1;
+}
+
+static int report_module(u64 ip, struct unwind_info *ui)
+{
+ struct addr_location al;
+
+ return __report_module(&al, ip, ui);
+}
+
+static int entry(u64 ip, struct unwind_info *ui)
+
+{
+ struct unwind_entry e;
+ struct addr_location al;
+
+ if (__report_module(&al, ip, ui))
+ return -1;
+
+ e.ip = ip;
+ e.map = al.map;
+ e.sym = al.sym;
+
+ pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
+ al.sym ? al.sym->name : "''",
+ ip,
+ al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
+
+ return ui->cb(&e, ui->arg);
+}
+
+static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
+{
+ /* We want only single thread to be processed. */
+ if (*thread_argp != NULL)
+ return 0;
+
+ *thread_argp = arg;
+ return dwfl_pid(dwfl);
+}
+
+static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
+ Dwarf_Word *data)
+{
+ struct addr_location al;
+ ssize_t size;
+
+ thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
+ MAP__FUNCTION, addr, &al);
+ if (!al.map) {
+ pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
+ return -1;
+ }
+
+ if (!al.map->dso)
+ return -1;
+
+ size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
+ addr, (u8 *) data, sizeof(*data));
+
+ return !(size == sizeof(*data));
+}
+
+static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *result,
+ void *arg)
+{
+ struct unwind_info *ui = arg;
+ struct stack_dump *stack = &ui->sample->user_stack;
+ u64 start, end;
+ int offset;
+ int ret;
+
+ ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
+ if (ret)
+ return false;
+
+ end = start + stack->size;
+
+ /* Check overflow. */
+ if (addr + sizeof(Dwarf_Word) < addr)
+ return false;
+
+ if (addr < start || addr + sizeof(Dwarf_Word) > end) {
+ ret = access_dso_mem(ui, addr, result);
+ if (ret) {
+ pr_debug("unwind: access_mem 0x%" PRIx64 " not inside range"
+ " 0x%" PRIx64 "-0x%" PRIx64 "\n",
+ addr, start, end);
+ return false;
+ }
+ return true;
+ }
+
+ offset = addr - start;
+ *result = *(Dwarf_Word *)&stack->data[offset];
+ pr_debug("unwind: access_mem addr 0x%" PRIx64 ", val %lx, offset %d\n",
+ addr, (unsigned long)*result, offset);
+ return true;
+}
+
+static const Dwfl_Thread_Callbacks callbacks = {
+ .next_thread = next_thread,
+ .memory_read = memory_read,
+ .set_initial_registers = libdw__arch_set_initial_registers,
+};
+
+static int
+frame_callback(Dwfl_Frame *state, void *arg)
+{
+ struct unwind_info *ui = arg;
+ Dwarf_Addr pc;
+
+ if (!dwfl_frame_pc(state, &pc, NULL)) {
+ pr_err("%s", dwfl_errmsg(-1));
+ return DWARF_CB_ABORT;
+ }
+
+ return entry(pc, ui) || !(--ui->max_stack) ?
+ DWARF_CB_ABORT : DWARF_CB_OK;
+}
+
+int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+ struct machine *machine, struct thread *thread,
+ struct perf_sample *data,
+ int max_stack)
+{
+ struct unwind_info ui = {
+ .sample = data,
+ .thread = thread,
+ .machine = machine,
+ .cb = cb,
+ .arg = arg,
+ .max_stack = max_stack,
+ };
+ Dwarf_Word ip;
+ int err = -EINVAL;
+
+ if (!data->user_regs.regs)
+ return -EINVAL;
+
+ ui.dwfl = dwfl_begin(&offline_callbacks);
+ if (!ui.dwfl)
+ goto out;
+
+ err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
+ if (err)
+ goto out;
+
+ err = report_module(ip, &ui);
+ if (err)
+ goto out;
+
+ if (!dwfl_attach_state(ui.dwfl, EM_NONE, thread->tid, &callbacks, &ui))
+ goto out;
+
+ err = dwfl_getthread_frames(ui.dwfl, thread->tid, frame_callback, &ui);
+
+ if (err && !ui.max_stack)
+ err = 0;
+
+ out:
+ if (err)
+ pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
+
+ dwfl_end(ui.dwfl);
+ return 0;
+}
diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
new file mode 100644
index 000000000000..417a1426f3ad
--- /dev/null
+++ b/tools/perf/util/unwind-libdw.h
@@ -0,0 +1,21 @@
+#ifndef __PERF_UNWIND_LIBDW_H
+#define __PERF_UNWIND_LIBDW_H
+
+#include <elfutils/libdwfl.h>
+#include "event.h"
+#include "thread.h"
+#include "unwind.h"
+
+bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg);
+
+struct unwind_info {
+ Dwfl *dwfl;
+ struct perf_sample *sample;
+ struct machine *machine;
+ struct thread *thread;
+ unwind_entry_cb_t cb;
+ void *arg;
+ int max_stack;
+};
+
+#endif /* __PERF_UNWIND_LIBDW_H */
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind-libunwind.c
index 742f23bf35ff..bd5768d74f01 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -86,7 +86,6 @@ struct unwind_info {
struct perf_sample *sample;
struct machine *machine;
struct thread *thread;
- u64 sample_uregs;
};
#define dw_read(ptr, type, end) ({ \
@@ -391,30 +390,13 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
return !(size == sizeof(*data));
}
-static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id,
- u64 sample_regs)
-{
- int i, idx = 0;
-
- if (!(sample_regs & (1 << id)))
- return -EINVAL;
-
- for (i = 0; i < id; i++) {
- if (sample_regs & (1 << i))
- idx++;
- }
-
- *valp = regs->regs[idx];
- return 0;
-}
-
static int access_mem(unw_addr_space_t __maybe_unused as,
unw_word_t addr, unw_word_t *valp,
int __write, void *arg)
{
struct unwind_info *ui = arg;
struct stack_dump *stack = &ui->sample->user_stack;
- unw_word_t start, end;
+ u64 start, end;
int offset;
int ret;
@@ -424,8 +406,7 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
return 0;
}
- ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP,
- ui->sample_uregs);
+ ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
if (ret)
return ret;
@@ -438,8 +419,9 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
if (addr < start || addr + sizeof(unw_word_t) >= end) {
ret = access_dso_mem(ui, addr, valp);
if (ret) {
- pr_debug("unwind: access_mem %p not inside range %p-%p\n",
- (void *)addr, (void *)start, (void *)end);
+ pr_debug("unwind: access_mem %p not inside range"
+ " 0x%" PRIx64 "-0x%" PRIx64 "\n",
+ (void *) addr, start, end);
*valp = 0;
return ret;
}
@@ -448,8 +430,8 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
offset = addr - start;
*valp = *(unw_word_t *)&stack->data[offset];
- pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n",
- (void *)addr, (unsigned long)*valp, offset);
+ pr_debug("unwind: access_mem addr %p val %lx, offset %d\n",
+ (void *) addr, (unsigned long)*valp, offset);
return 0;
}
@@ -459,6 +441,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
{
struct unwind_info *ui = arg;
int id, ret;
+ u64 val;
/* Don't support write, I suspect we don't need it. */
if (__write) {
@@ -471,16 +454,17 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
return 0;
}
- id = unwind__arch_reg_id(regnum);
+ id = libunwind__arch_reg_id(regnum);
if (id < 0)
return -EINVAL;
- ret = reg_value(valp, &ui->sample->user_regs, id, ui->sample_uregs);
+ ret = perf_reg_value(&val, &ui->sample->user_regs, id);
if (ret) {
pr_err("unwind: can't read reg %d\n", regnum);
return ret;
}
+ *valp = (unw_word_t) val;
pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
return 0;
}
@@ -563,7 +547,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
unw_word_t ip;
unw_get_reg(&c, UNW_REG_IP, &ip);
- ret = entry(ip, ui->thread, ui->machine, cb, arg);
+ ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0;
}
unw_destroy_addr_space(addr_space);
@@ -572,13 +556,11 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct machine *machine, struct thread *thread,
- u64 sample_uregs, struct perf_sample *data,
- int max_stack)
+ struct perf_sample *data, int max_stack)
{
- unw_word_t ip;
+ u64 ip;
struct unwind_info ui = {
.sample = data,
- .sample_uregs = sample_uregs,
.thread = thread,
.machine = machine,
};
@@ -587,7 +569,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
if (!data->user_regs.regs)
return -EINVAL;
- ret = reg_value(&ip, &data->user_regs, PERF_REG_IP, sample_uregs);
+ ret = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
if (ret)
return ret;
@@ -595,5 +577,5 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
if (ret)
return -ENOMEM;
- return get_entries(&ui, cb, arg, max_stack);
+ return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0;
}
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index d5966f49e22c..b031316f221a 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -13,24 +13,25 @@ struct unwind_entry {
typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct machine *machine,
struct thread *thread,
- u64 sample_uregs,
struct perf_sample *data, int max_stack);
-int unwind__arch_reg_id(int regnum);
+/* libunwind specific */
+#ifdef HAVE_LIBUNWIND_SUPPORT
+int libunwind__arch_reg_id(int regnum);
+#endif
#else
static inline int
unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
void *arg __maybe_unused,
struct machine *machine __maybe_unused,
struct thread *thread __maybe_unused,
- u64 sample_uregs __maybe_unused,
struct perf_sample *data __maybe_unused,
int max_stack __maybe_unused)
{
return 0;
}
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
#endif /* __UNWIND_H */
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 42ad667bb317..9f66549562bd 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -1,6 +1,6 @@
#include "../perf.h"
#include "util.h"
-#include "fs.h"
+#include <api/fs/fs.h>
#include <sys/mman.h>
#ifdef HAVE_BACKTRACE_SUPPORT
#include <execinfo.h>
diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c
index d66418237d21..aa290c0de6f5 100644
--- a/tools/testing/selftests/ipc/msgque.c
+++ b/tools/testing/selftests/ipc/msgque.c
@@ -201,6 +201,7 @@ int main(int argc, char **argv)
msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666);
if (msgque.msq_id == -1) {
+ err = -errno;
printf("Can't create queue\n");
goto err_out;
}
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
index bd24ae5aaeab..316194f26ff4 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -13,7 +13,7 @@ CFLAGS := -Wall -O2 -flto -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CUR
export CC CFLAGS
-TARGETS = pmu
+TARGETS = pmu copyloops
endif
diff --git a/tools/testing/selftests/powerpc/copyloops/Makefile b/tools/testing/selftests/powerpc/copyloops/Makefile
new file mode 100644
index 000000000000..6f2d3be227f9
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/Makefile
@@ -0,0 +1,29 @@
+# The loops are all 64-bit code
+CFLAGS += -m64
+CFLAGS += -I$(CURDIR)
+CFLAGS += -D SELFTEST
+
+# Use our CFLAGS for the implicit .S rule
+ASFLAGS = $(CFLAGS)
+
+PROGS := copyuser_64 copyuser_power7 memcpy_64 memcpy_power7
+EXTRA_SOURCES := validate.c ../harness.c
+
+all: $(PROGS)
+
+copyuser_64: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_base
+copyuser_power7: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_power7
+memcpy_64: CPPFLAGS += -D COPY_LOOP=test_memcpy
+memcpy_power7: CPPFLAGS += -D COPY_LOOP=test_memcpy_power7
+
+$(PROGS): $(EXTRA_SOURCES)
+
+run_tests: all
+ @-for PROG in $(PROGS); do \
+ ./$$PROG; \
+ done;
+
+clean:
+ rm -f $(PROGS) *.o
+
+.PHONY: all run_tests clean
diff --git a/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h
new file mode 100644
index 000000000000..ccd9c84c4e3f
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/asm/ppc_asm.h
@@ -0,0 +1,86 @@
+#include <ppc-asm.h>
+
+#define CONFIG_ALTIVEC
+
+#define r1 1
+
+#define vr0 0
+#define vr1 1
+#define vr2 2
+#define vr3 3
+#define vr4 4
+#define vr5 5
+#define vr6 6
+#define vr7 7
+#define vr8 8
+#define vr9 9
+#define vr10 10
+#define vr11 11
+#define vr12 12
+#define vr13 13
+#define vr14 14
+#define vr15 15
+#define vr16 16
+#define vr17 17
+#define vr18 18
+#define vr19 19
+#define vr20 20
+#define vr21 21
+#define vr22 22
+#define vr23 23
+#define vr24 24
+#define vr25 25
+#define vr26 26
+#define vr27 27
+#define vr28 28
+#define vr29 29
+#define vr30 30
+#define vr31 31
+
+#define R14 r14
+#define R15 r15
+#define R16 r16
+#define R17 r17
+#define R18 r18
+#define R19 r19
+#define R20 r20
+#define R21 r21
+#define R22 r22
+
+#define STACKFRAMESIZE 256
+#define STK_PARAM(i) (48 + ((i)-3)*8)
+#define STK_REG(i) (112 + ((i)-14)*8)
+
+#define _GLOBAL(A) FUNC_START(test_ ## A)
+
+#define PPC_MTOCRF(A, B) mtocrf A, B
+
+FUNC_START(enter_vmx_usercopy)
+ li r3,1
+ blr
+
+FUNC_START(exit_vmx_usercopy)
+ li r3,0
+ blr
+
+FUNC_START(enter_vmx_copy)
+ li r3,1
+ blr
+
+FUNC_START(exit_vmx_copy)
+ blr
+
+FUNC_START(memcpy_power7)
+ blr
+
+FUNC_START(__copy_tofrom_user_power7)
+ blr
+
+FUNC_START(__copy_tofrom_user_base)
+ blr
+
+#define BEGIN_FTR_SECTION
+#define FTR_SECTION_ELSE
+#define ALT_FTR_SECTION_END_IFCLR(x)
+#define ALT_FTR_SECTION_END(x, y)
+#define END_FTR_SECTION_IFCLR(x)
diff --git a/tools/testing/selftests/powerpc/copyloops/asm/processor.h b/tools/testing/selftests/powerpc/copyloops/asm/processor.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/asm/processor.h
diff --git a/tools/testing/selftests/powerpc/copyloops/copyuser_64.S b/tools/testing/selftests/powerpc/copyloops/copyuser_64.S
new file mode 120000
index 000000000000..f1c418a2521a
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/copyuser_64.S
@@ -0,0 +1 @@
+../../../../../arch/powerpc/lib/copyuser_64.S \ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/copyloops/copyuser_power7.S b/tools/testing/selftests/powerpc/copyloops/copyuser_power7.S
new file mode 120000
index 000000000000..478689598298
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/copyuser_power7.S
@@ -0,0 +1 @@
+../../../../../arch/powerpc/lib/copyuser_power7.S \ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/copyloops/memcpy_64.S b/tools/testing/selftests/powerpc/copyloops/memcpy_64.S
new file mode 120000
index 000000000000..cce33fb6f9d8
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/memcpy_64.S
@@ -0,0 +1 @@
+../../../../../arch/powerpc/lib/memcpy_64.S \ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/copyloops/memcpy_power7.S b/tools/testing/selftests/powerpc/copyloops/memcpy_power7.S
new file mode 120000
index 000000000000..0d6fbfaf3d59
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/memcpy_power7.S
@@ -0,0 +1 @@
+../../../../../arch/powerpc/lib/memcpy_power7.S \ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/copyloops/validate.c b/tools/testing/selftests/powerpc/copyloops/validate.c
new file mode 100644
index 000000000000..1750ff57ee58
--- /dev/null
+++ b/tools/testing/selftests/powerpc/copyloops/validate.c
@@ -0,0 +1,99 @@
+#include <malloc.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "../utils.h"
+
+#define MAX_LEN 8192
+#define MAX_OFFSET 16
+#define MIN_REDZONE 128
+#define BUFLEN (MAX_LEN+MAX_OFFSET+2*MIN_REDZONE)
+#define POISON 0xa5
+
+unsigned long COPY_LOOP(void *to, const void *from, unsigned long size);
+
+static void do_one(char *src, char *dst, unsigned long src_off,
+ unsigned long dst_off, unsigned long len, void *redzone,
+ void *fill)
+{
+ char *srcp, *dstp;
+ unsigned long ret;
+ unsigned long i;
+
+ srcp = src + MIN_REDZONE + src_off;
+ dstp = dst + MIN_REDZONE + dst_off;
+
+ memset(src, POISON, BUFLEN);
+ memset(dst, POISON, BUFLEN);
+ memcpy(srcp, fill, len);
+
+ ret = COPY_LOOP(dstp, srcp, len);
+ if (ret && ret != (unsigned long)dstp) {
+ printf("(%p,%p,%ld) returned %ld\n", dstp, srcp, len, ret);
+ abort();
+ }
+
+ if (memcmp(dstp, srcp, len)) {
+ printf("(%p,%p,%ld) miscompare\n", dstp, srcp, len);
+ printf("src: ");
+ for (i = 0; i < len; i++)
+ printf("%02x ", srcp[i]);
+ printf("\ndst: ");
+ for (i = 0; i < len; i++)
+ printf("%02x ", dstp[i]);
+ printf("\n");
+ abort();
+ }
+
+ if (memcmp(dst, redzone, dstp - dst)) {
+ printf("(%p,%p,%ld) redzone before corrupted\n",
+ dstp, srcp, len);
+ abort();
+ }
+
+ if (memcmp(dstp+len, redzone, dst+BUFLEN-(dstp+len))) {
+ printf("(%p,%p,%ld) redzone after corrupted\n",
+ dstp, srcp, len);
+ abort();
+ }
+}
+
+int test_copy_loop(void)
+{
+ char *src, *dst, *redzone, *fill;
+ unsigned long len, src_off, dst_off;
+ unsigned long i;
+
+ src = memalign(BUFLEN, BUFLEN);
+ dst = memalign(BUFLEN, BUFLEN);
+ redzone = malloc(BUFLEN);
+ fill = malloc(BUFLEN);
+
+ if (!src || !dst || !redzone || !fill) {
+ fprintf(stderr, "malloc failed\n");
+ exit(1);
+ }
+
+ memset(redzone, POISON, BUFLEN);
+
+ /* Fill with sequential bytes */
+ for (i = 0; i < BUFLEN; i++)
+ fill[i] = i & 0xff;
+
+ for (len = 1; len < MAX_LEN; len++) {
+ for (src_off = 0; src_off < MAX_OFFSET; src_off++) {
+ for (dst_off = 0; dst_off < MAX_OFFSET; dst_off++) {
+ do_one(src, dst, src_off, dst_off, len,
+ redzone, fill);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int main(void)
+{
+ return test_harness(test_copy_loop, str(COPY_LOOP));
+}
diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h
index 5851c4b0f553..0de064406dab 100644
--- a/tools/testing/selftests/powerpc/utils.h
+++ b/tools/testing/selftests/powerpc/utils.h
@@ -31,4 +31,7 @@ do { \
} \
} while (0)
+#define _str(s) #s
+#define str(s) _str(s)
+
#endif /* _SELFTESTS_POWERPC_UTILS_H */
diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh
index 587561d7c035..9b17e810ddc3 100644
--- a/tools/testing/selftests/rcutorture/bin/functions.sh
+++ b/tools/testing/selftests/rcutorture/bin/functions.sh
@@ -96,6 +96,7 @@ identify_qemu () {
echo qemu-system-ppc64
else
echo Cannot figure out what qemu command to use! 1>&2
+ echo file $1 output: $u
# Usually this will be one of /usr/bin/qemu-system-*
# Use RCU_QEMU_CMD environment variable or appropriate
# argument to top-level script.
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh
new file mode 100755
index 000000000000..829186e19eb1
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# Analyze a given results directory for locktorture progress.
+#
+# Usage: sh kvm-recheck-lock.sh resdir
+#
+# This program is free software; 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, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2014
+#
+# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+
+i="$1"
+if test -d $i
+then
+ :
+else
+ echo Unreadable results directory: $i
+ exit 1
+fi
+
+configfile=`echo $i | sed -e 's/^.*\///'`
+ncs=`grep "Writes: Total:" $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* Total: //' -e 's/ .*$//'`
+if test -z "$ncs"
+then
+ echo $configfile
+else
+ title="$configfile ------- $ncs acquisitions/releases"
+ dur=`sed -e 's/^.* locktorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null`
+ if test -z "$dur"
+ then
+ :
+ else
+ ncsps=`awk -v ncs=$ncs -v dur=$dur '
+ BEGIN { print ncs / dur }' < /dev/null`
+ title="$title ($ncsps per second)"
+ fi
+ echo $title
+fi
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh
new file mode 100755
index 000000000000..d75b1dc5ae53
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# Analyze a given results directory for rcutorture progress.
+#
+# Usage: sh kvm-recheck-rcu.sh resdir
+#
+# This program is free software; 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, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2014
+#
+# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+
+i="$1"
+if test -d $i
+then
+ :
+else
+ echo Unreadable results directory: $i
+ exit 1
+fi
+
+configfile=`echo $i | sed -e 's/^.*\///'`
+ngps=`grep ver: $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* ver: //' -e 's/ .*$//'`
+if test -z "$ngps"
+then
+ echo $configfile
+else
+ title="$configfile ------- $ngps grace periods"
+ dur=`sed -e 's/^.* rcutorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null`
+ if test -z "$dur"
+ then
+ :
+ else
+ ngpsps=`awk -v ngps=$ngps -v dur=$dur '
+ BEGIN { print ngps / dur }' < /dev/null`
+ title="$title ($ngpsps per second)"
+ fi
+ echo $title
+fi
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
index baef09f3469b..a44daaa259a9 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
@@ -1,6 +1,6 @@
#!/bin/bash
#
-# Given the results directories for previous KVM runs of rcutorture,
+# Given the results directories for previous KVM-based torture runs,
# check the build and console output for errors. Given a directory
# containing results directories, this recursively checks them all.
#
@@ -27,11 +27,18 @@
PATH=`pwd`/tools/testing/selftests/rcutorture/bin:$PATH; export PATH
for rd in "$@"
do
+ firsttime=1
dirs=`find $rd -name Make.defconfig.out -print | sort | sed -e 's,/[^/]*$,,' | sort -u`
for i in $dirs
do
- configfile=`echo $i | sed -e 's/^.*\///'`
- echo $configfile
+ if test -n "$firsttime"
+ then
+ firsttime=""
+ resdir=`echo $i | sed -e 's,/$,,' -e 's,/[^/]*$,,'`
+ head -1 $resdir/log
+ fi
+ TORTURE_SUITE="`cat $i/../TORTURE_SUITE`"
+ kvm-recheck-${TORTURE_SUITE}.sh $i
configcheck.sh $i/.config $i/ConfigFragment
parse-build.sh $i/Make.out $configfile
parse-rcutorture.sh $i/console.log $configfile
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
index 151b23788935..94b28bb37d36 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
@@ -6,15 +6,15 @@
# Execute this in the source tree. Do not run it as a background task
# because qemu does not seem to like that much.
#
-# Usage: sh kvm-test-1-rcu.sh config builddir resdir minutes qemu-args bootargs
+# Usage: sh kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args
#
-# qemu-args defaults to "" -- you will want "-nographic" if running headless.
-# bootargs defaults to "root=/dev/sda noapic selinux=0 console=ttyS0"
-# "initcall_debug debug rcutorture.stat_interval=15"
-# "rcutorture.shutdown_secs=$((minutes * 60))"
-# "rcutorture.rcutorture_runnable=1"
+# qemu-args defaults to "-nographic", along with arguments specifying the
+# number of CPUs and other options generated from
+# the underlying CPU architecture.
+# boot_args defaults to value returned by the per_version_boot_params
+# shell function.
#
-# Anything you specify for either qemu-args or bootargs is appended to
+# Anything you specify for either qemu-args or boot_args is appended to
# the default values. The "-smp" value is deduced from the contents of
# the config fragment.
#
@@ -40,32 +40,34 @@
grace=120
-T=/tmp/kvm-test-1-rcu.sh.$$
+T=/tmp/kvm-test-1-run.sh.$$
trap 'rm -rf $T' 0
. $KVM/bin/functions.sh
. $KVPATH/ver_functions.sh
config_template=${1}
+config_dir=`echo $config_template | sed -e 's,/[^/]*$,,'`
title=`echo $config_template | sed -e 's/^.*\///'`
builddir=${2}
if test -z "$builddir" -o ! -d "$builddir" -o ! -w "$builddir"
then
- echo "kvm-test-1-rcu.sh :$builddir: Not a writable directory, cannot build into it"
+ echo "kvm-test-1-run.sh :$builddir: Not a writable directory, cannot build into it"
exit 1
fi
resdir=${3}
if test -z "$resdir" -o ! -d "$resdir" -o ! -w "$resdir"
then
- echo "kvm-test-1-rcu.sh :$resdir: Not a writable directory, cannot build into it"
+ echo "kvm-test-1-run.sh :$resdir: Not a writable directory, cannot store results into it"
exit 1
fi
cp $config_template $resdir/ConfigFragment
echo ' ---' `date`: Starting build
echo ' ---' Kconfig fragment at: $config_template >> $resdir/log
-cat << '___EOF___' >> $T
-CONFIG_RCU_TORTURE_TEST=y
-___EOF___
+if test -r "$config_dir/CFcommon"
+then
+ cat < $config_dir/CFcommon >> $T
+fi
# Optimizations below this point
# CONFIG_USB=n
# CONFIG_SECURITY=n
@@ -96,11 +98,23 @@ then
cp $builddir/.config $resdir
cp $builddir/arch/x86/boot/bzImage $resdir
parse-build.sh $resdir/Make.out $title
+ if test -f $builddir.wait
+ then
+ mv $builddir.wait $builddir.ready
+ fi
else
cp $builddir/Make*.out $resdir
echo Build failed, not running KVM, see $resdir.
+ if test -f $builddir.wait
+ then
+ mv $builddir.wait $builddir.ready
+ fi
exit 1
fi
+while test -f $builddir.ready
+do
+ sleep 1
+done
minutes=$4
seconds=$(($minutes * 60))
qemu_args=$5
@@ -111,9 +125,10 @@ kstarttime=`awk 'BEGIN { print systime() }' < /dev/null`
echo ' ---' `date`: Starting kernel
# Determine the appropriate flavor of qemu command.
-QEMU="`identify_qemu $builddir/vmlinux.o`"
+QEMU="`identify_qemu $builddir/vmlinux`"
# Generate -smp qemu argument.
+qemu_args="-nographic $qemu_args"
cpu_count=`configNR_CPUS.sh $config_template`
vcpus=`identify_qemu_vcpus`
if test $cpu_count -gt $vcpus
@@ -133,12 +148,8 @@ qemu_append="`identify_qemu_append "$QEMU"`"
# Pull in Kconfig-fragment boot parameters
boot_args="`configfrag_boot_params "$boot_args" "$config_template"`"
-# Generate CPU-hotplug boot parameters
-boot_args="`rcutorture_param_onoff "$boot_args" $builddir/.config`"
-# Generate rcu_barrier() boot parameter
-boot_args="`rcutorture_param_n_barrier_cbs "$boot_args"`"
-# Pull in standard rcutorture boot arguments
-boot_args="$boot_args rcutorture.stat_interval=15 rcutorture.shutdown_secs=$seconds rcutorture.rcutorture_runnable=1"
+# Generate kernel-version-specific boot parameters
+boot_args="`per_version_boot_params "$boot_args" $builddir/.config $seconds`"
echo $QEMU $qemu_args -m 512 -kernel $builddir/arch/x86/boot/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
if test -n "$RCU_BUILDONLY"
@@ -188,5 +199,5 @@ then
fi
cp $builddir/console.log $resdir
-parse-rcutorture.sh $resdir/console.log $title
+parse-${TORTURE_SUITE}torture.sh $resdir/console.log $title
parse-console.sh $resdir/console.log $title
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh
index 1b7923bf6a70..5a78cbf55f06 100644
--- a/tools/testing/selftests/rcutorture/bin/kvm.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm.sh
@@ -30,14 +30,21 @@
scriptname=$0
args="$*"
+T=/tmp/kvm.sh.$$
+trap 'rm -rf $T' 0
+mkdir $T
+
dur=30
+dryrun=""
KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM
PATH=${KVM}/bin:$PATH; export PATH
builddir="${KVM}/b1"
RCU_INITRD="$KVM/initrd"; export RCU_INITRD
RCU_KMAKE_ARG=""; export RCU_KMAKE_ARG
+TORTURE_SUITE=rcu
resdir=""
configs=""
+cpus=0
ds=`date +%Y.%m.%d-%H:%M:%S`
kversion=""
@@ -49,7 +56,9 @@ usage () {
echo " --builddir absolute-pathname"
echo " --buildonly"
echo " --configs \"config-file list\""
+ echo " --cpus N"
echo " --datestamp string"
+ echo " --dryrun sched|script"
echo " --duration minutes"
echo " --interactive"
echo " --kmake-arg kernel-make-arguments"
@@ -58,8 +67,9 @@ usage () {
echo " --no-initrd"
echo " --qemu-args qemu-system-..."
echo " --qemu-cmd qemu-system-..."
- echo " --results absolute-pathname"
echo " --relbuilddir relative-pathname"
+ echo " --results absolute-pathname"
+ echo " --torture rcu"
exit 1
}
@@ -85,11 +95,21 @@ do
configs="$2"
shift
;;
+ --cpus)
+ checkarg --cpus "(number)" "$#" "$2" '^[0-9]*$' '^--'
+ cpus=$2
+ shift
+ ;;
--datestamp)
checkarg --datestamp "(relative pathname)" "$#" "$2" '^[^/]*$' '^--'
ds=$2
shift
;;
+ --dryrun)
+ checkarg --dryrun "sched|script" $# "$2" 'sched\|script' '^--'
+ dryrun=$2
+ shift
+ ;;
--duration)
checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error'
dur=$2
@@ -138,6 +158,11 @@ do
resdir=$2
shift
;;
+ --torture)
+ checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\)$' '^--'
+ TORTURE_SUITE=$2
+ shift
+ ;;
*)
echo Unknown argument $1
usage
@@ -146,7 +171,7 @@ do
shift
done
-CONFIGFRAG=${KVM}/configs; export CONFIGFRAG
+CONFIGFRAG=${KVM}/configs/${TORTURE_SUITE}; export CONFIGFRAG
KVPATH=${CONFIGFRAG}/$kversion; export KVPATH
if test -z "$configs"
@@ -157,54 +182,231 @@ fi
if test -z "$resdir"
then
resdir=$KVM/res
- if ! test -e $resdir
- then
- mkdir $resdir || :
- fi
-else
+fi
+
+if test "$dryrun" = ""
+then
if ! test -e $resdir
then
mkdir -p "$resdir" || :
fi
-fi
-mkdir $resdir/$ds
-touch $resdir/$ds/log
-echo $scriptname $args >> $resdir/$ds/log
+ mkdir $resdir/$ds
-pwd > $resdir/$ds/testid.txt
-if test -d .git
-then
- git status >> $resdir/$ds/testid.txt
- git rev-parse HEAD >> $resdir/$ds/testid.txt
-fi
-builddir=$KVM/b1
-if ! test -e $builddir
-then
- mkdir $builddir || :
+ # Be noisy only if running the script.
+ echo Results directory: $resdir/$ds
+ echo $scriptname $args
+
+ touch $resdir/$ds/log
+ echo $scriptname $args >> $resdir/$ds/log
+ echo ${TORTURE_SUITE} > $resdir/$ds/TORTURE_SUITE
+
+ pwd > $resdir/$ds/testid.txt
+ if test -d .git
+ then
+ git status >> $resdir/$ds/testid.txt
+ git rev-parse HEAD >> $resdir/$ds/testid.txt
+ fi
fi
+# Create a file of test-name/#cpus pairs, sorted by decreasing #cpus.
+touch $T/cfgcpu
for CF in $configs
do
- # Running TREE01 multiple times creates TREE01, TREE01.2, TREE01.3, ...
- rd=$resdir/$ds/$CF
- if test -d "${rd}"
+ if test -f "$CONFIGFRAG/$kversion/$CF"
then
- n="`ls -d "${rd}"* | grep '\.[0-9]\+$' |
- sed -e 's/^.*\.\([0-9]\+\)/\1/' |
- sort -k1n | tail -1`"
- if test -z "$n"
- then
- rd="${rd}.2"
- else
- n="`expr $n + 1`"
- rd="${rd}.${n}"
- fi
+ echo $CF `configNR_CPUS.sh $CONFIGFRAG/$kversion/$CF` >> $T/cfgcpu
+ else
+ echo "The --configs file $CF does not exist, terminating."
+ exit 1
fi
- mkdir "${rd}"
- echo Results directory: $rd
- kvm-test-1-rcu.sh $CONFIGFRAG/$kversion/$CF $builddir $rd $dur "-nographic $RCU_QEMU_ARG" "rcutorture.test_no_idle_hz=1 rcutorture.verbose=1 $RCU_BOOTARGS"
done
+sort -k2nr $T/cfgcpu > $T/cfgcpu.sort
+
+# Use a greedy bin-packing algorithm, sorting the list accordingly.
+awk < $T/cfgcpu.sort > $T/cfgcpu.pack -v ncpus=$cpus '
+BEGIN {
+ njobs = 0;
+}
+
+{
+ # Read file of tests and corresponding required numbers of CPUs.
+ cf[njobs] = $1;
+ cpus[njobs] = $2;
+ njobs++;
+}
+
+END {
+ alldone = 0;
+ batch = 0;
+ nc = -1;
+
+ # Each pass through the following loop creates on test batch
+ # that can be executed concurrently given ncpus. Note that a
+ # given test that requires more than the available CPUs will run in
+ # their own batch. Such tests just have to make do with what
+ # is available.
+ while (nc != ncpus) {
+ batch++;
+ nc = ncpus;
+
+ # Each pass through the following loop considers one
+ # test for inclusion in the current batch.
+ for (i = 0; i < njobs; i++) {
+ if (done[i])
+ continue; # Already part of a batch.
+ if (nc >= cpus[i] || nc == ncpus) {
+
+ # This test fits into the current batch.
+ done[i] = batch;
+ nc -= cpus[i];
+ if (nc <= 0)
+ break; # Too-big test in its own batch.
+ }
+ }
+ }
+
+ # Dump out the tests in batch order.
+ for (b = 1; b <= batch; b++)
+ for (i = 0; i < njobs; i++)
+ if (done[i] == b)
+ print cf[i], cpus[i];
+}'
+
+# Generate a script to execute the tests in appropriate batches.
+cat << ___EOF___ > $T/script
+TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE
+___EOF___
+awk < $T/cfgcpu.pack \
+ -v CONFIGDIR="$CONFIGFRAG/$kversion/" \
+ -v KVM="$KVM" \
+ -v ncpus=$cpus \
+ -v rd=$resdir/$ds/ \
+ -v dur=$dur \
+ -v RCU_QEMU_ARG=$RCU_QEMU_ARG \
+ -v RCU_BOOTARGS=$RCU_BOOTARGS \
+'BEGIN {
+ i = 0;
+}
+
+{
+ cf[i] = $1;
+ cpus[i] = $2;
+ i++;
+}
+
+# Dump out the scripting required to run one test batch.
+function dump(first, pastlast)
+{
+ print "echo ----Start batch: `date`";
+ print "echo ----Start batch: `date` >> " rd "/log";
+ jn=1
+ for (j = first; j < pastlast; j++) {
+ builddir=KVM "/b" jn
+ cpusr[jn] = cpus[j];
+ if (cfrep[cf[j]] == "") {
+ cfr[jn] = cf[j];
+ cfrep[cf[j]] = 1;
+ } else {
+ cfrep[cf[j]]++;
+ cfr[jn] = cf[j] "." cfrep[cf[j]];
+ }
+ if (cpusr[jn] > ncpus && ncpus != 0)
+ ovf = "(!)";
+ else
+ ovf = "";
+ print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date`";
+ print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date` >> " rd "/log";
+ print "rm -f " builddir ".*";
+ print "touch " builddir ".wait";
+ print "mkdir " builddir " > /dev/null 2>&1 || :";
+ print "mkdir " rd cfr[jn] " || :";
+ print "kvm-test-1-run.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" RCU_QEMU_ARG "\" \"" RCU_BOOTARGS "\" > " rd cfr[jn] "/kvm-test-1-run.sh.out 2>&1 &"
+ print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date`";
+ print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date` >> " rd "/log";
+ print "while test -f " builddir ".wait"
+ print "do"
+ print "\tsleep 1"
+ print "done"
+ print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date`";
+ print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date` >> " rd "/log";
+ jn++;
+ }
+ for (j = 1; j < jn; j++) {
+ builddir=KVM "/b" j
+ print "rm -f " builddir ".ready"
+ print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date`";
+ print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log";
+ }
+ print "wait"
+ print "echo ---- All kernel runs complete. `date`";
+ print "echo ---- All kernel runs complete. `date` >> " rd "/log";
+ for (j = 1; j < jn; j++) {
+ builddir=KVM "/b" j
+ print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results:";
+ print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results: >> " rd "/log";
+ print "cat " rd cfr[j] "/kvm-test-1-run.sh.out";
+ print "cat " rd cfr[j] "/kvm-test-1-run.sh.out >> " rd "/log";
+ }
+}
+
+END {
+ njobs = i;
+ nc = ncpus;
+ first = 0;
+
+ # Each pass through the following loop considers one test.
+ for (i = 0; i < njobs; i++) {
+ if (ncpus == 0) {
+ # Sequential test specified, each test its own batch.
+ dump(i, i + 1);
+ first = i;
+ } else if (nc < cpus[i] && i != 0) {
+ # Out of CPUs, dump out a batch.
+ dump(first, i);
+ first = i;
+ nc = ncpus;
+ }
+ # Account for the CPUs needed by the current test.
+ nc -= cpus[i];
+ }
+ # Dump the last batch.
+ if (ncpus != 0)
+ dump(first, i);
+}' >> $T/script
+
+if test "$dryrun" = script
+then
+ # Dump out the script, but define the environment variables that
+ # it needs to run standalone.
+ echo CONFIGFRAG="$CONFIGFRAG; export CONFIGFRAG"
+ echo KVM="$KVM; export KVM"
+ echo KVPATH="$KVPATH; export KVPATH"
+ echo PATH="$PATH; export PATH"
+ echo RCU_BUILDONLY="$RCU_BUILDONLY; export RCU_BUILDONLY"
+ echo RCU_INITRD="$RCU_INITRD; export RCU_INITRD"
+ echo RCU_KMAKE_ARG="$RCU_KMAKE_ARG; export RCU_KMAKE_ARG"
+ echo RCU_QEMU_CMD="$RCU_QEMU_CMD; export RCU_QEMU_CMD"
+ echo RCU_QEMU_INTERACTIVE="$RCU_QEMU_INTERACTIVE; export RCU_QEMU_INTERACTIVE"
+ echo RCU_QEMU_MAC="$RCU_QEMU_MAC; export RCU_QEMU_MAC"
+ echo "mkdir -p "$resdir" || :"
+ echo "mkdir $resdir/$ds"
+ cat $T/script
+ exit 0
+elif test "$dryrun" = sched
+then
+ # Extract the test run schedule from the script.
+ egrep 'start batch|Starting build\.' $T/script |
+ sed -e 's/:.*$//' -e 's/^echo //'
+ exit 0
+else
+ # Not a dryru, so run the script.
+ sh $T/script
+fi
+
# Tracing: trace_event=rcu:rcu_grace_period,rcu:rcu_future_grace_period,rcu:rcu_grace_period_init,rcu:rcu_nocb_wake,rcu:rcu_preempt_task,rcu:rcu_unlock_preempted_task,rcu:rcu_quiescent_state_report,rcu:rcu_fqs,rcu:rcu_callback,rcu:rcu_kfree_callback,rcu:rcu_batch_start,rcu:rcu_invoke_callback,rcu:rcu_invoke_kfree_callback,rcu:rcu_batch_end,rcu:rcu_torture_read,rcu:rcu_barrier
+echo
+echo
echo " --- `date` Test summary:"
+echo Results directory: $resdir/$ds
kvm-recheck.sh $resdir/$ds
diff --git a/tools/testing/selftests/rcutorture/configs/lock/BUSTED b/tools/testing/selftests/rcutorture/configs/lock/BUSTED
new file mode 100644
index 000000000000..1d1da1477fc3
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/BUSTED
@@ -0,0 +1,6 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/BUSTED.boot b/tools/testing/selftests/rcutorture/configs/lock/BUSTED.boot
new file mode 100644
index 000000000000..6386c15e9770
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/BUSTED.boot
@@ -0,0 +1 @@
+locktorture.torture_type=lock_busted
diff --git a/tools/testing/selftests/rcutorture/configs/lock/CFLIST b/tools/testing/selftests/rcutorture/configs/lock/CFLIST
new file mode 100644
index 000000000000..a061b22d1892
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/CFLIST
@@ -0,0 +1 @@
+LOCK01
diff --git a/tools/testing/selftests/rcutorture/configs/lock/CFcommon b/tools/testing/selftests/rcutorture/configs/lock/CFcommon
new file mode 100644
index 000000000000..e372dc269254
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/CFcommon
@@ -0,0 +1,2 @@
+CONFIG_LOCK_TORTURE_TEST=y
+CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK01 b/tools/testing/selftests/rcutorture/configs/lock/LOCK01
new file mode 100644
index 000000000000..a9625e3d6cd9
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK01
@@ -0,0 +1,6 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=8
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh
new file mode 100644
index 000000000000..9746ea1cd6c7
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# Kernel-version-dependent shell functions for the rest of the scripts.
+#
+# This program is free software; 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, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2014
+#
+# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+
+# locktorture_param_onoff bootparam-string config-file
+#
+# Adds onoff locktorture module parameters to kernels having it.
+locktorture_param_onoff () {
+ if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2"
+ then
+ echo CPU-hotplug kernel, adding locktorture onoff. 1>&2
+ echo locktorture.onoff_interval=3 locktorture.onoff_holdoff=30
+ fi
+}
+
+# per_version_boot_params bootparam-string config-file seconds
+#
+# Adds per-version torture-module parameters to kernels supporting them.
+per_version_boot_params () {
+ echo $1 `locktorture_param_onoff "$1" "$2"` \
+ locktorture.stat_interval=15 \
+ locktorture.shutdown_secs=$3 \
+ locktorture.locktorture_runnable=1 \
+ locktorture.verbose=1
+}
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/BUSTED b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED
new file mode 100644
index 000000000000..48d8a245c7fa
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED
@@ -0,0 +1,7 @@
+CONFIG_RCU_TRACE=n
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/BUSTED.boot b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED.boot
new file mode 100644
index 000000000000..6804f9dcfc1b
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED.boot
@@ -0,0 +1 @@
+rcutorture.torture_type=rcu_busted
diff --git a/tools/testing/selftests/rcutorture/configs/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
index cd3d29cb0a47..cd3d29cb0a47 100644
--- a/tools/testing/selftests/rcutorture/configs/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/CFcommon b/tools/testing/selftests/rcutorture/configs/rcu/CFcommon
new file mode 100644
index 000000000000..d2d2a86139db
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/CFcommon
@@ -0,0 +1,2 @@
+CONFIG_RCU_TORTURE_TEST=y
+CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-N b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N
index 10a0e27f4c75..9fbb41b9b314 100644
--- a/tools/testing/selftests/rcutorture/configs/SRCU-N
+++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N
@@ -1,8 +1,7 @@
CONFIG_RCU_TRACE=n
CONFIG_SMP=y
-CONFIG_NR_CPUS=8
+CONFIG_NR_CPUS=4
CONFIG_HOTPLUG_CPU=y
CONFIG_PREEMPT_NONE=y
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-N.boot b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N.boot
index 238bfe3bd0cc..238bfe3bd0cc 100644
--- a/tools/testing/selftests/rcutorture/configs/SRCU-N.boot
+++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N.boot
diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-P b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P
index 6650e00c6d91..4b6f272dba27 100644
--- a/tools/testing/selftests/rcutorture/configs/SRCU-P
+++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P
@@ -5,4 +5,3 @@ CONFIG_HOTPLUG_CPU=y
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-P.boot b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P.boot
index 238bfe3bd0cc..238bfe3bd0cc 100644
--- a/tools/testing/selftests/rcutorture/configs/SRCU-P.boot
+++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P.boot
diff --git a/tools/testing/selftests/rcutorture/configs/TINY01 b/tools/testing/selftests/rcutorture/configs/rcu/TINY01
index 0c2823f21712..0a63e073a00c 100644
--- a/tools/testing/selftests/rcutorture/configs/TINY01
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TINY01
@@ -10,4 +10,3 @@ CONFIG_RCU_TRACE=n
CONFIG_DEBUG_LOCK_ALLOC=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
CONFIG_PREEMPT_COUNT=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TINY02 b/tools/testing/selftests/rcutorture/configs/rcu/TINY02
index e5072d7528b6..f4feaee40776 100644
--- a/tools/testing/selftests/rcutorture/configs/TINY02
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TINY02
@@ -10,4 +10,3 @@ CONFIG_RCU_TRACE=y
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
CONFIG_PREEMPT_COUNT=y
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01
index 141119a00044..9c827ec59a97 100644
--- a/tools/testing/selftests/rcutorture/configs/TREE01
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01
@@ -20,4 +20,3 @@ CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE01.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot
index 0fc8a3428938..0fc8a3428938 100644
--- a/tools/testing/selftests/rcutorture/configs/TREE01.boot
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot
diff --git a/tools/testing/selftests/rcutorture/configs/TREE02 b/tools/testing/selftests/rcutorture/configs/rcu/TREE02
index 2d4d09608528..1a777b5f68b5 100644
--- a/tools/testing/selftests/rcutorture/configs/TREE02
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02
@@ -7,7 +7,7 @@ CONFIG_PREEMPT=y
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=y
CONFIG_NO_HZ_FULL=n
-CONFIG_RCU_FAST_NO_HZ=n
+CONFIG_RCU_FAST_NO_HZ=n
CONFIG_RCU_TRACE=n
CONFIG_HOTPLUG_CPU=n
CONFIG_SUSPEND=n
@@ -23,4 +23,3 @@ CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=y
CONFIG_RCU_BOOST=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE03 b/tools/testing/selftests/rcutorture/configs/rcu/TREE03
index a47de5be8a04..c1f111c1561b 100644
--- a/tools/testing/selftests/rcutorture/configs/TREE03
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03
@@ -20,4 +20,3 @@ CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=y
CONFIG_RCU_BOOST_PRIO=2
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
index 8d839b86a1d5..7dbd27ce17a4 100644
--- a/tools/testing/selftests/rcutorture/configs/TREE04
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
@@ -22,4 +22,3 @@ CONFIG_PROVE_RCU_DELAY=n
CONFIG_RCU_CPU_STALL_INFO=y
CONFIG_RCU_CPU_STALL_VERBOSE=y
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE04.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot
index 0fc8a3428938..0fc8a3428938 100644
--- a/tools/testing/selftests/rcutorture/configs/TREE04.boot
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot
diff --git a/tools/testing/selftests/rcutorture/configs/TREE05 b/tools/testing/selftests/rcutorture/configs/rcu/TREE05
index b5ba72ea25cb..d0f32e574743 100644
--- a/tools/testing/selftests/rcutorture/configs/TREE05
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE05
@@ -22,4 +22,3 @@ CONFIG_PROVE_RCU_DELAY=y
CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE05.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot
index 3b42b8b033cd..3b42b8b033cd 100644
--- a/tools/testing/selftests/rcutorture/configs/TREE05.boot
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot
diff --git a/tools/testing/selftests/rcutorture/configs/TREE06 b/tools/testing/selftests/rcutorture/configs/rcu/TREE06
index 7c95ab48d29f..2e477dfb9c57 100644
--- a/tools/testing/selftests/rcutorture/configs/TREE06
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE06
@@ -23,4 +23,3 @@ CONFIG_PROVE_RCU_DELAY=n
CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
index 1467404bdec1..042f86ef362a 100644
--- a/tools/testing/selftests/rcutorture/configs/TREE07
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
@@ -21,4 +21,3 @@ CONFIG_PROVE_RCU_DELAY=n
CONFIG_RCU_CPU_STALL_INFO=y
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE08 b/tools/testing/selftests/rcutorture/configs/rcu/TREE08
index 7d097a61ac2a..3438cee1e3c5 100644
--- a/tools/testing/selftests/rcutorture/configs/TREE08
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08
@@ -23,4 +23,3 @@ CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE08-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T
index 442c4e450ab3..bf4523d3e44c 100644
--- a/tools/testing/selftests/rcutorture/configs/TREE08-T
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T
@@ -23,4 +23,3 @@ CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/TREE09 b/tools/testing/selftests/rcutorture/configs/rcu/TREE09
index 0d1ec0d3dfee..81e4f7c0bf0b 100644
--- a/tools/testing/selftests/rcutorture/configs/TREE09
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE09
@@ -18,4 +18,3 @@ CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PRINTK_TIME=y
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/CFLIST
index 18223947bbcb..18223947bbcb 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/CFLIST
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP
index d3ef873eb6e7..d3ef873eb6e7 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/N1-S-T-NH-SD-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp
index 02e418572b1b..02e418572b1b 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/N2-2-t-nh-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp
index b3100f69c8cf..b3100f69c8cf 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/N3-3-T-nh-SD-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP
index c56b44530725..c56b44530725 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/N4-A-t-NH-sd-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp
index 90d924fea9e9..90d924fea9e9 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/N5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT1-nh
index 023f312a931c..023f312a931c 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/NT1-nh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT1-nh
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT3-NH
index 6fd0235dae73..6fd0235dae73 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/NT3-NH
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP
index f72402d7c13d..f72402d7c13d 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/P1-S-T-NH-SD-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp
index 0f3b667d2a9f..0f3b667d2a9f 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/P2-2-t-nh-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp
index b035e141bf2a..b035e141bf2a 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/P3-3-T-nh-SD-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP
index 3ccf6a9447f5..3ccf6a9447f5 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/P4-A-t-NH-sd-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp
index ef624ce73d8e..ef624ce73d8e 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/P5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT1-nh
index e3361c3894a1..e3361c3894a1 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/PT1-nh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT1-nh
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT2-NH
index 64abfc3b4d94..64abfc3b4d94 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/PT2-NH
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT2-NH
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/ver_functions.sh
index e8052539af54..5ace37a89780 100644
--- a/tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/ver_functions.sh
@@ -20,16 +20,14 @@
#
# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-# rcutorture_param_n_barrier_cbs bootparam-string
-#
-# Adds n_barrier_cbs rcutorture module parameter to kernels having it.
-rcutorture_param_n_barrier_cbs () {
- echo $1
-}
-
-# rcutorture_param_onoff bootparam-string config-file
-#
-# Adds onoff rcutorture module parameters to kernels having it.
-rcutorture_param_onoff () {
- echo $1
+# per_version_boot_params bootparam-string config-file seconds
+#
+# Adds per-version torture-module parameters to kernels supporting them.
+# Which old kernels do not.
+per_version_boot_params () {
+ echo rcutorture.stat_interval=15 \
+ rcutorture.shutdown_secs=$3 \
+ rcutorture.rcutorture_runnable=1 \
+ rcutorture.test_no_idle_hz=1 \
+ rcutorture.verbose=1
}
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/CFLIST
index da4cbc668f2a..da4cbc668f2a 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/CFLIST
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP
index d81e11d280aa..d81e11d280aa 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/N1-S-T-NH-SD-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp
index 02e418572b1b..02e418572b1b 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/N2-2-t-nh-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp
index b3100f69c8cf..b3100f69c8cf 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/N3-3-T-nh-SD-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP
index c56b44530725..c56b44530725 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/N4-A-t-NH-sd-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp
index 90d924fea9e9..90d924fea9e9 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/N5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N6---t-nh-SD-smp-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp
index 0ccc36d72738..0ccc36d72738 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/N6---t-nh-SD-smp-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N7-4-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP
index 3f640cf84973..3f640cf84973 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/N7-4-T-NH-SD-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N8-2-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP
index 285da2dd8ac3..285da2dd8ac3 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/N8-2-T-NH-SD-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT1-nh
index 023f312a931c..023f312a931c 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/NT1-nh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT1-nh
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT3-NH
index 6fd0235dae73..6fd0235dae73 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/NT3-NH
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP
index 9647c44cf4b7..9647c44cf4b7 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/P1-S-T-NH-SD-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp
index 0f3b667d2a9f..0f3b667d2a9f 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/P2-2-t-nh-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp
index b035e141bf2a..b035e141bf2a 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/P3-3-T-nh-SD-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP
index 3ccf6a9447f5..3ccf6a9447f5 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/P4-A-t-NH-sd-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp
index ef624ce73d8e..ef624ce73d8e 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/P5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P6---t-nh-SD-smp-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp
index f4c9175828bf..f4c9175828bf 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/P6---t-nh-SD-smp-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP
index 77a8c5b75763..77a8c5b75763 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-all b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all
index 0eecebc6e95f..0eecebc6e95f 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-all
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-none b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none
index 0eecebc6e95f..0eecebc6e95f 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-none
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp
index 588bc70420cd..588bc70420cd 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT1-nh
index e3361c3894a1..e3361c3894a1 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/PT1-nh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT1-nh
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT2-NH
index 64abfc3b4d94..64abfc3b4d94 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.12/PT2-NH
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT2-NH
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/CFLIST
index 18223947bbcb..18223947bbcb 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/CFLIST
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP
index d81e11d280aa..d81e11d280aa 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/N1-S-T-NH-SD-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp
index 02e418572b1b..02e418572b1b 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/N2-2-t-nh-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp
index b3100f69c8cf..b3100f69c8cf 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/N3-3-T-nh-SD-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP
index c56b44530725..c56b44530725 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/N4-A-t-NH-sd-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp
index 90d924fea9e9..90d924fea9e9 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/N5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT1-nh
index 023f312a931c..023f312a931c 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/NT1-nh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT1-nh
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT3-NH
index 6fd0235dae73..6fd0235dae73 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/NT3-NH
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP
index 9647c44cf4b7..9647c44cf4b7 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/P1-S-T-NH-SD-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp
index 0f3b667d2a9f..0f3b667d2a9f 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/P2-2-t-nh-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp
index b035e141bf2a..b035e141bf2a 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/P3-3-T-nh-SD-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP
index 3ccf6a9447f5..3ccf6a9447f5 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/P4-A-t-NH-sd-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp
index ef624ce73d8e..ef624ce73d8e 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/P5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT1-nh
index e3361c3894a1..e3361c3894a1 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/PT1-nh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT1-nh
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT2-NH
index 64abfc3b4d94..64abfc3b4d94 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/PT2-NH
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT2-NH
diff --git a/tools/testing/selftests/rcutorture/configs/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/ver_functions.sh
index 5e40eadea777..bae55692ce6e 100644
--- a/tools/testing/selftests/rcutorture/configs/ver_functions.sh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/ver_functions.sh
@@ -20,18 +20,6 @@
#
# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-# rcutorture_param_n_barrier_cbs bootparam-string
-#
-# Adds n_barrier_cbs rcutorture module parameter to kernels having it.
-rcutorture_param_n_barrier_cbs () {
- if echo $1 | grep -q "rcutorture\.n_barrier_cbs"
- then
- echo $1
- else
- echo $1 rcutorture.n_barrier_cbs=4
- fi
-}
-
# rcutorture_param_onoff bootparam-string config-file
#
# Adds onoff rcutorture module parameters to kernels having it.
@@ -39,8 +27,18 @@ rcutorture_param_onoff () {
if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2"
then
echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2
- echo $1 rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
- else
- echo $1
+ echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
fi
}
+
+# per_version_boot_params bootparam-string config-file seconds
+#
+# Adds per-version torture-module parameters to kernels supporting them.
+per_version_boot_params () {
+ echo $1 `rcutorture_param_onoff "$1" "$2"` \
+ rcutorture.stat_interval=15 \
+ rcutorture.shutdown_secs=$3 \
+ rcutorture.rcutorture_runnable=1 \
+ rcutorture.test_no_idle_hz=1 \
+ rcutorture.verbose=1
+}
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/CFLIST
index 18223947bbcb..18223947bbcb 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/CFLIST
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP
index d81e11d280aa..d81e11d280aa 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/N1-S-T-NH-SD-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp
index 02e418572b1b..02e418572b1b 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/N2-2-t-nh-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp
index b3100f69c8cf..b3100f69c8cf 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/N3-3-T-nh-SD-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP
index c56b44530725..c56b44530725 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/N4-A-t-NH-sd-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp
index 90d924fea9e9..90d924fea9e9 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/N5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT1-nh
index 023f312a931c..023f312a931c 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/NT1-nh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT1-nh
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT3-NH
index 6fd0235dae73..6fd0235dae73 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/NT3-NH
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP
index 9647c44cf4b7..9647c44cf4b7 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/P1-S-T-NH-SD-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp
index 0f3b667d2a9f..0f3b667d2a9f 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/P2-2-t-nh-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp
index b035e141bf2a..b035e141bf2a 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/P3-3-T-nh-SD-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP
index 3ccf6a9447f5..3ccf6a9447f5 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/P4-A-t-NH-sd-SMP-HP
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp
index ef624ce73d8e..ef624ce73d8e 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/P5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT1-nh
index e3361c3894a1..e3361c3894a1 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/PT1-nh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT1-nh
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT2-NH
index 64abfc3b4d94..64abfc3b4d94 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/PT2-NH
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT2-NH
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/ver_functions.sh
index 6a5f13aab44d..8977d8d31b19 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/ver_functions.sh
@@ -26,9 +26,9 @@
rcutorture_param_n_barrier_cbs () {
if echo $1 | grep -q "rcutorture\.n_barrier_cbs"
then
- echo $1
+ :
else
- echo $1 rcutorture.n_barrier_cbs=4
+ echo rcutorture.n_barrier_cbs=4
fi
}
@@ -38,9 +38,20 @@ rcutorture_param_n_barrier_cbs () {
rcutorture_param_onoff () {
if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2"
then
- echo CPU-hotplug kernel, adding rcutorture onoff.
- echo $1 rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
- else
- echo $1
+ echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2
+ echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
fi
}
+
+# per_version_boot_params bootparam-string config-file seconds
+#
+# Adds per-version torture-module parameters to kernels supporting them.
+per_version_boot_params () {
+ echo $1 `rcutorture_param_onoff "$1" "$2"` \
+ `rcutorture_param_n_barrier_cbs "$1"` \
+ rcutorture.stat_interval=15 \
+ rcutorture.shutdown_secs=$3 \
+ rcutorture.rcutorture_runnable=1 \
+ rcutorture.test_no_idle_hz=1 \
+ rcutorture.verbose=1
+}
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh
index c37432f3572c..8977d8d31b19 100644
--- a/tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh
@@ -24,7 +24,12 @@
#
# Adds n_barrier_cbs rcutorture module parameter to kernels having it.
rcutorture_param_n_barrier_cbs () {
- echo $1
+ if echo $1 | grep -q "rcutorture\.n_barrier_cbs"
+ then
+ :
+ else
+ echo rcutorture.n_barrier_cbs=4
+ fi
}
# rcutorture_param_onoff bootparam-string config-file
@@ -33,9 +38,20 @@ rcutorture_param_n_barrier_cbs () {
rcutorture_param_onoff () {
if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2"
then
- echo CPU-hotplug kernel, adding rcutorture onoff.
- echo $1 rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
- else
- echo $1
+ echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2
+ echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
fi
}
+
+# per_version_boot_params bootparam-string config-file seconds
+#
+# Adds per-version torture-module parameters to kernels supporting them.
+per_version_boot_params () {
+ echo $1 `rcutorture_param_onoff "$1" "$2"` \
+ `rcutorture_param_n_barrier_cbs "$1"` \
+ rcutorture.stat_interval=15 \
+ rcutorture.shutdown_secs=$3 \
+ rcutorture.rcutorture_runnable=1 \
+ rcutorture.test_no_idle_hz=1 \
+ rcutorture.verbose=1
+}
diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-Kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
index adbb76cffb49..adbb76cffb49 100644
--- a/tools/testing/selftests/rcutorture/doc/TREE_RCU-Kconfig.txt
+++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
diff --git a/tools/virtio/linux/kmemleak.h b/tools/virtio/linux/kmemleak.h
new file mode 100644
index 000000000000..c07072270e2f
--- /dev/null
+++ b/tools/virtio/linux/kmemleak.h
@@ -0,0 +1,3 @@
+static inline void kmemleak_ignore(const void *ptr)
+{
+}
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h
index 844783040703..5a2d1f0f6bc7 100644
--- a/tools/virtio/linux/virtio.h
+++ b/tools/virtio/linux/virtio.h
@@ -63,7 +63,7 @@ int virtqueue_add_inbuf(struct virtqueue *vq,
void *data,
gfp_t gfp);
-void virtqueue_kick(struct virtqueue *vq);
+bool virtqueue_kick(struct virtqueue *vq);
void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
@@ -79,7 +79,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
struct virtio_device *vdev,
bool weak_barriers,
void *pages,
- void (*notify)(struct virtqueue *vq),
+ bool (*notify)(struct virtqueue *vq),
void (*callback)(struct virtqueue *vq),
const char *name);
void vring_del_virtqueue(struct virtqueue *vq);
diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
index bdb71a26ae35..00ea679b3826 100644
--- a/tools/virtio/virtio_test.c
+++ b/tools/virtio/virtio_test.c
@@ -172,7 +172,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
GFP_ATOMIC);
if (likely(r == 0)) {
++started;
- if (unlikely(!virtqueue_kick(vq->vq))
+ if (unlikely(!virtqueue_kick(vq->vq)))
r = -1;
}
} else
diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig
index fbe1a48bd629..13f2d19793e3 100644
--- a/virt/kvm/Kconfig
+++ b/virt/kvm/Kconfig
@@ -22,6 +22,10 @@ config KVM_MMIO
config KVM_ASYNC_PF
bool
+# Toggle to switch between direct notification and batch job
+config KVM_ASYNC_PF_SYNC
+ bool
+
config HAVE_KVM_MSI
bool
diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c
index 8631d9c14320..10df100c4514 100644
--- a/virt/kvm/async_pf.c
+++ b/virt/kvm/async_pf.c
@@ -28,6 +28,21 @@
#include "async_pf.h"
#include <trace/events/kvm.h>
+static inline void kvm_async_page_present_sync(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+#ifdef CONFIG_KVM_ASYNC_PF_SYNC
+ kvm_arch_async_page_present(vcpu, work);
+#endif
+}
+static inline void kvm_async_page_present_async(struct kvm_vcpu *vcpu,
+ struct kvm_async_pf *work)
+{
+#ifndef CONFIG_KVM_ASYNC_PF_SYNC
+ kvm_arch_async_page_present(vcpu, work);
+#endif
+}
+
static struct kmem_cache *async_pf_cache;
int kvm_async_pf_init(void)
@@ -69,6 +84,7 @@ static void async_pf_execute(struct work_struct *work)
down_read(&mm->mmap_sem);
get_user_pages(current, mm, addr, 1, 1, 0, NULL, NULL);
up_read(&mm->mmap_sem);
+ kvm_async_page_present_sync(vcpu, apf);
unuse_mm(mm);
spin_lock(&vcpu->async_pf.lock);
@@ -97,11 +113,16 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu)
list_entry(vcpu->async_pf.queue.next,
typeof(*work), queue);
list_del(&work->queue);
+
+#ifdef CONFIG_KVM_ASYNC_PF_SYNC
+ flush_work(&work->work);
+#else
if (cancel_work_sync(&work->work)) {
mmdrop(work->mm);
kvm_put_kvm(vcpu->kvm); /* == work->vcpu->kvm */
kmem_cache_free(async_pf_cache, work);
}
+#endif
}
spin_lock(&vcpu->async_pf.lock);
@@ -130,7 +151,7 @@ void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu)
spin_unlock(&vcpu->async_pf.lock);
kvm_arch_async_page_ready(vcpu, work);
- kvm_arch_async_page_present(vcpu, work);
+ kvm_async_page_present_async(vcpu, work);
list_del(&work->queue);
vcpu->async_pf.queued--;
@@ -138,7 +159,7 @@ void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu)
}
}
-int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn,
+int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva,
struct kvm_arch_async_pf *arch)
{
struct kvm_async_pf *work;
@@ -159,7 +180,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn,
work->wakeup_all = false;
work->vcpu = vcpu;
work->gva = gva;
- work->addr = gfn_to_hva(vcpu->kvm, gfn);
+ work->addr = hva;
work->arch = *arch;
work->mm = current->mm;
atomic_inc(&work->mm->mm_count);
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
index abe4d6043b36..29c2a04e036e 100644
--- a/virt/kvm/eventfd.c
+++ b/virt/kvm/eventfd.c
@@ -391,19 +391,19 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
lockdep_is_held(&kvm->irqfds.lock));
irqfd_update(kvm, irqfd, irq_rt);
- events = f.file->f_op->poll(f.file, &irqfd->pt);
-
list_add_tail(&irqfd->list, &kvm->irqfds.items);
+ spin_unlock_irq(&kvm->irqfds.lock);
+
/*
* Check if there was an event already pending on the eventfd
* before we registered, and trigger it as if we didn't miss it.
*/
+ events = f.file->f_op->poll(f.file, &irqfd->pt);
+
if (events & POLLIN)
schedule_work(&irqfd->inject);
- spin_unlock_irq(&kvm->irqfds.lock);
-
/*
* do not drop the file until the irqfd is fully initialized, otherwise
* we might race against the POLLHUP
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index ce9ed99ad7dc..d4b601547f1f 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -50,7 +50,7 @@
#else
#define ioapic_debug(fmt, arg...)
#endif
-static int ioapic_deliver(struct kvm_ioapic *vioapic, int irq,
+static int ioapic_service(struct kvm_ioapic *vioapic, int irq,
bool line_status);
static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
@@ -163,23 +163,67 @@ static bool rtc_irq_check_coalesced(struct kvm_ioapic *ioapic)
return false;
}
-static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx,
- bool line_status)
+static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
+ int irq_level, bool line_status)
{
- union kvm_ioapic_redirect_entry *pent;
- int injected = -1;
+ union kvm_ioapic_redirect_entry entry;
+ u32 mask = 1 << irq;
+ u32 old_irr;
+ int edge, ret;
- pent = &ioapic->redirtbl[idx];
+ entry = ioapic->redirtbl[irq];
+ edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG);
- if (!pent->fields.mask) {
- injected = ioapic_deliver(ioapic, idx, line_status);
- if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG)
- pent->fields.remote_irr = 1;
+ if (!irq_level) {
+ ioapic->irr &= ~mask;
+ ret = 1;
+ goto out;
+ }
+
+ /*
+ * Return 0 for coalesced interrupts; for edge-triggered interrupts,
+ * this only happens if a previous edge has not been delivered due
+ * do masking. For level interrupts, the remote_irr field tells
+ * us if the interrupt is waiting for an EOI.
+ *
+ * RTC is special: it is edge-triggered, but userspace likes to know
+ * if it has been already ack-ed via EOI because coalesced RTC
+ * interrupts lead to time drift in Windows guests. So we track
+ * EOI manually for the RTC interrupt.
+ */
+ if (irq == RTC_GSI && line_status &&
+ rtc_irq_check_coalesced(ioapic)) {
+ ret = 0;
+ goto out;
}
- return injected;
+ old_irr = ioapic->irr;
+ ioapic->irr |= mask;
+ if ((edge && old_irr == ioapic->irr) ||
+ (!edge && entry.fields.remote_irr)) {
+ ret = 0;
+ goto out;
+ }
+
+ ret = ioapic_service(ioapic, irq, line_status);
+
+out:
+ trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0);
+ return ret;
+}
+
+static void kvm_ioapic_inject_all(struct kvm_ioapic *ioapic, unsigned long irr)
+{
+ u32 idx;
+
+ rtc_irq_eoi_tracking_reset(ioapic);
+ for_each_set_bit(idx, &irr, IOAPIC_NUM_PINS)
+ ioapic_set_irq(ioapic, idx, 1, true);
+
+ kvm_rtc_eoi_tracking_restore_all(ioapic);
}
+
static void update_handled_vectors(struct kvm_ioapic *ioapic)
{
DECLARE_BITMAP(handled_vectors, 256);
@@ -282,12 +326,15 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
}
}
-static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq, bool line_status)
+static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
{
union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq];
struct kvm_lapic_irq irqe;
int ret;
+ if (entry->fields.mask)
+ return -1;
+
ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
"vector=%x trig_mode=%x\n",
entry->fields.dest_id, entry->fields.dest_mode,
@@ -302,6 +349,9 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq, bool line_status)
irqe.level = 1;
irqe.shorthand = 0;
+ if (irqe.trig_mode == IOAPIC_EDGE_TRIG)
+ ioapic->irr &= ~(1 << irq);
+
if (irq == RTC_GSI && line_status) {
BUG_ON(ioapic->rtc_status.pending_eoi != 0);
ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe,
@@ -310,45 +360,24 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq, bool line_status)
} else
ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, NULL);
+ if (ret && irqe.trig_mode == IOAPIC_LEVEL_TRIG)
+ entry->fields.remote_irr = 1;
+
return ret;
}
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id,
int level, bool line_status)
{
- u32 old_irr;
- u32 mask = 1 << irq;
- union kvm_ioapic_redirect_entry entry;
int ret, irq_level;
BUG_ON(irq < 0 || irq >= IOAPIC_NUM_PINS);
spin_lock(&ioapic->lock);
- old_irr = ioapic->irr;
irq_level = __kvm_irq_line_state(&ioapic->irq_states[irq],
irq_source_id, level);
- entry = ioapic->redirtbl[irq];
- irq_level ^= entry.fields.polarity;
- if (!irq_level) {
- ioapic->irr &= ~mask;
- ret = 1;
- } else {
- int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG);
+ ret = ioapic_set_irq(ioapic, irq, irq_level, line_status);
- if (irq == RTC_GSI && line_status &&
- rtc_irq_check_coalesced(ioapic)) {
- ret = 0; /* coalesced */
- goto out;
- }
- ioapic->irr |= mask;
- if ((edge && old_irr != ioapic->irr) ||
- (!edge && !entry.fields.remote_irr))
- ret = ioapic_service(ioapic, irq, line_status);
- else
- ret = 0; /* report coalesced interrupt */
- }
-out:
- trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0);
spin_unlock(&ioapic->lock);
return ret;
@@ -394,7 +423,7 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
ent->fields.remote_irr = 0;
- if (!ent->fields.mask && (ioapic->irr & (1 << i)))
+ if (ioapic->irr & (1 << i))
ioapic_service(ioapic, i, false);
}
}
@@ -595,9 +624,10 @@ int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
spin_lock(&ioapic->lock);
memcpy(ioapic, state, sizeof(struct kvm_ioapic_state));
+ ioapic->irr = 0;
update_handled_vectors(ioapic);
kvm_vcpu_request_scan_ioapic(kvm);
- kvm_rtc_eoi_tracking_restore_all(ioapic);
+ kvm_ioapic_inject_all(ioapic, state->irr);
spin_unlock(&ioapic->lock);
return 0;
}
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 03a0381b1cb7..56baae8c2f56 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -102,7 +102,7 @@ static void kvm_release_pfn_dirty(pfn_t pfn);
static void mark_page_dirty_in_slot(struct kvm *kvm,
struct kvm_memory_slot *memslot, gfn_t gfn);
-bool kvm_rebooting;
+__visible bool kvm_rebooting;
EXPORT_SYMBOL_GPL(kvm_rebooting);
static bool largepages_enabled = true;
@@ -186,12 +186,9 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
void kvm_flush_remote_tlbs(struct kvm *kvm)
{
- long dirty_count = kvm->tlbs_dirty;
-
- smp_mb();
if (make_all_cpus_request(kvm, KVM_REQ_TLB_FLUSH))
++kvm->stat.remote_tlb_flush;
- cmpxchg(&kvm->tlbs_dirty, dirty_count, 0);
+ kvm->tlbs_dirty = false;
}
EXPORT_SYMBOL_GPL(kvm_flush_remote_tlbs);
@@ -1804,7 +1801,7 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
continue;
if (vcpu == me)
continue;
- if (waitqueue_active(&vcpu->wq))
+ if (waitqueue_active(&vcpu->wq) && !kvm_arch_vcpu_runnable(vcpu))
continue;
if (!kvm_vcpu_eligible_for_directed_yield(vcpu))
continue;
@@ -2284,6 +2281,11 @@ static int kvm_ioctl_create_device(struct kvm *kvm,
ops = &kvm_arm_vgic_v2_ops;
break;
#endif
+#ifdef CONFIG_S390
+ case KVM_DEV_TYPE_FLIC:
+ ops = &kvm_flic_ops;
+ break;
+#endif
default:
return -ENODEV;
}